summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/ui/cheatopt.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/ui/cheatopt.h')
-rw-r--r--src/emu/ui/cheatopt.h25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/emu/ui/cheatopt.h b/src/emu/ui/cheatopt.h
index 0358af493ab..a9321df7304 100644
--- a/src/emu/ui/cheatopt.h
+++ b/src/emu/ui/cheatopt.h
@@ -13,6 +13,12 @@
#ifndef __UI_CHEATOPT_H__
#define __UI_CHEATOPT_H__
+// itemrefs for key menu items
+#define ITEMREF_CHEATS_RESET_ALL ((void *) 0x0001)
+#define ITEMREF_CHEATS_RELOAD_ALL ((void *) 0x0002)
+#define ITEMREF_CHEATS_AUTOFIRE_SETTINGS ((void *) 0x0003)
+#define ITEMREF_CHEATS_FIRST_ITEM ((void *) 0x0004)
+
class ui_menu_cheat : public ui_menu {
public:
ui_menu_cheat(running_machine &machine, render_container *container);
@@ -21,4 +27,23 @@ public:
virtual void handle() override;
};
+
+// itemrefs for key menu items
+#define ITEMREF_AUTOFIRE_STATUS ((void *) 0x0001)
+#define ITEMREF_AUTOFIRE_DELAY ((void *) 0x0002)
+#define ITEMREF_AUTOFIRE_FIRST_BUTTON ((void *) 0x0003)
+
+class ui_menu_autofire : public ui_menu {
+public:
+ ui_menu_autofire(running_machine &machine, render_container *container);
+ virtual ~ui_menu_autofire();
+ virtual void populate() override;
+ virtual void handle() override;
+
+private:
+ float refresh;
+ bool last_toggle;
+};
+
+
#endif /* __UI_CHEATOPT_H__ */
3cad7bb8bb314c600b7171a83&id2=22083b0ed95ae695daeb06951cab04095a2016c6'>3rdparty/expat/Makefile.am154
-rw-r--r--3rdparty/expat/Makefile.in1140
-rw-r--r--3rdparty/expat/README139
-rw-r--r--3rdparty/expat/README.md194
-rw-r--r--3rdparty/expat/acinclude.m412
-rw-r--r--3rdparty/expat/aclocal.m41188
-rw-r--r--3rdparty/expat/amiga/Makefile336
-rw-r--r--3rdparty/expat/amiga/README.txt98
-rw-r--r--3rdparty/expat/amiga/expat.xml264
-rw-r--r--3rdparty/expat/amiga/expat_68k.c939
-rw-r--r--3rdparty/expat/amiga/expat_68k.h94
-rw-r--r--3rdparty/expat/amiga/expat_68k_handler_stubs.c185
-rw-r--r--3rdparty/expat/amiga/expat_base.h40
-rw-r--r--3rdparty/expat/amiga/expat_lib.c247
-rw-r--r--3rdparty/expat/amiga/expat_vectors.c505
-rw-r--r--3rdparty/expat/amiga/include/inline4/expat.h94
-rw-r--r--3rdparty/expat/amiga/include/interfaces/expat.h98
-rw-r--r--3rdparty/expat/amiga/include/libraries/expat.h566
-rw-r--r--3rdparty/expat/amiga/include/proto/expat.h52
-rw-r--r--3rdparty/expat/amiga/launch.c57
-rw-r--r--3rdparty/expat/bcb5/README.txt87
-rw-r--r--3rdparty/expat/bcb5/all_projects.bpg49
-rw-r--r--3rdparty/expat/bcb5/elements.bpf4
-rw-r--r--3rdparty/expat/bcb5/elements.bpr149
-rw-r--r--3rdparty/expat/bcb5/elements.mak186
-rw-r--r--3rdparty/expat/bcb5/expat.bpf6
-rw-r--r--3rdparty/expat/bcb5/expat.bpr140
-rw-r--r--3rdparty/expat/bcb5/expat.mak187
-rw-r--r--3rdparty/expat/bcb5/expat_static.bpf5
-rw-r--r--3rdparty/expat/bcb5/expat_static.bpr143
-rw-r--r--3rdparty/expat/bcb5/expat_static.mak189
-rw-r--r--3rdparty/expat/bcb5/expatw.bpf6
-rw-r--r--3rdparty/expat/bcb5/expatw.bpr146
-rw-r--r--3rdparty/expat/bcb5/expatw.mak187
-rw-r--r--3rdparty/expat/bcb5/expatw_static.bpf5
-rw-r--r--3rdparty/expat/bcb5/expatw_static.bpr152
-rw-r--r--3rdparty/expat/bcb5/expatw_static.mak190
-rw-r--r--3rdparty/expat/bcb5/libexpat_mtd.def141
-rw-r--r--3rdparty/expat/bcb5/libexpatw_mtd.def140
-rw-r--r--3rdparty/expat/bcb5/makefile.mak37
-rw-r--r--3rdparty/expat/bcb5/outline.bpf4
-rw-r--r--3rdparty/expat/bcb5/outline.bpr132
-rw-r--r--3rdparty/expat/bcb5/outline.mak186
-rw-r--r--3rdparty/expat/bcb5/setup.bat9
-rw-r--r--3rdparty/expat/bcb5/xmlwf.bpf7
-rw-r--r--3rdparty/expat/bcb5/xmlwf.bpr136
-rw-r--r--3rdparty/expat/bcb5/xmlwf.mak187
-rw-r--r--3rdparty/expat/cmake/expat-config.cmake.in75
-rw-r--r--3rdparty/expat/cmake/mingw-toolchain.cmake36
-rwxr-xr-x3rdparty/expat/configure7628
-rw-r--r--3rdparty/expat/configure.ac352
-rw-r--r--3rdparty/expat/conftools/ac_c_bigendian_cross.m481
-rwxr-xr-x3rdparty/expat/conftools/ar-lib271
-rw-r--r--3rdparty/expat/conftools/ax-append-compile-flags.m446
-rw-r--r--3rdparty/expat/conftools/ax-append-flag.m450
-rw-r--r--3rdparty/expat/conftools/ax-append-link-flags.m444
-rw-r--r--3rdparty/expat/conftools/ax-check-compile-flag.m477
-rw-r--r--3rdparty/expat/conftools/ax-check-link-flag.m453
-rw-r--r--3rdparty/expat/conftools/ax-require-defined.m437
-rwxr-xr-x3rdparty/expat/conftools/compile348
-rwxr-xr-x3rdparty/expat/conftools/config.guess986
-rwxr-xr-x3rdparty/expat/conftools/config.sub2525
-rwxr-xr-x3rdparty/expat/conftools/depcomp791
-rw-r--r--3rdparty/expat/conftools/expatcfg-compiler-supports-visibility.m439
-rwxr-xr-x3rdparty/expat/conftools/get-version.sh19
-rwxr-xr-x3rdparty/expat/conftools/install-sh410
-rw-r--r--3rdparty/expat/conftools/ltmain.sh5515
-rwxr-xr-x3rdparty/expat/conftools/missing215
-rwxr-xr-x3rdparty/expat/conftools/mkinstalldirs40
-rwxr-xr-x3rdparty/expat/conftools/test-driver148
-rw-r--r--3rdparty/expat/doc/Makefile.am59
-rw-r--r--3rdparty/expat/doc/Makefile.in602
-rw-r--r--3rdparty/expat/doc/expat.pngbin1029 -> 920 bytes-rw-r--r--3rdparty/expat/doc/reference.html30
-rw-r--r--3rdparty/expat/doc/valid-xhtml10.pngbin2370 -> 1981 bytes-rw-r--r--3rdparty/expat/doc/xmlwf.139
-rw-r--r--3rdparty/expat/doc/xmlwf.xml (renamed from 3rdparty/expat/doc/xmlwf.sgml)84
-rw-r--r--3rdparty/expat/examples/Makefile.am39
-rw-r--r--3rdparty/expat/examples/Makefile.in660
-rw-r--r--3rdparty/expat/examples/elements.c72
-rw-r--r--3rdparty/expat/examples/elements.dsp103
-rw-r--r--3rdparty/expat/examples/outline.c95
-rw-r--r--3rdparty/expat/examples/outline.dsp103
-rw-r--r--3rdparty/expat/expat.dsw110
-rw-r--r--3rdparty/expat/expat.pc.in4
-rw-r--r--3rdparty/expat/expat_config.h.cmake46
-rw-r--r--3rdparty/expat/expat_config.h.in54
-rwxr-xr-x3rdparty/expat/fix-xmltest-log.sh48
-rw-r--r--3rdparty/expat/lib/Makefile.MPW206
-rw-r--r--3rdparty/expat/lib/Makefile.am76
-rw-r--r--3rdparty/expat/lib/Makefile.in810
-rw-r--r--3rdparty/expat/lib/amigaconfig.h29
-rw-r--r--3rdparty/expat/lib/ascii.h32
-rw-r--r--3rdparty/expat/lib/asciitab.h94
-rw-r--r--3rdparty/expat/lib/expat.dsp185
-rw-r--r--3rdparty/expat/lib/expat.h347
-rw-r--r--3rdparty/expat/lib/expat_external.h113
-rw-r--r--3rdparty/expat/lib/expat_static.dsp162
-rw-r--r--3rdparty/expat/lib/expatw.dsp185
-rw-r--r--3rdparty/expat/lib/expatw_static.dsp162
-rw-r--r--3rdparty/expat/lib/iasciitab.h94
-rw-r--r--3rdparty/expat/lib/internal.h78
-rw-r--r--3rdparty/expat/lib/latin1tab.h94
-rw-r--r--3rdparty/expat/lib/libexpat.def4
-rw-r--r--3rdparty/expat/lib/libexpatw.def4
-rw-r--r--3rdparty/expat/lib/macconfig.h53
-rw-r--r--3rdparty/expat/lib/nametab.h274
-rw-r--r--3rdparty/expat/lib/siphash.h398
-rw-r--r--3rdparty/expat/lib/utf8tab.h95
-rw-r--r--3rdparty/expat/lib/winconfig.h52
-rw-r--r--3rdparty/expat/lib/xmlparse.c6262
-rw-r--r--3rdparty/expat/lib/xmlrole.c821
-rw-r--r--3rdparty/expat/lib/xmlrole.h45
-rw-r--r--3rdparty/expat/lib/xmltok.c1515
-rw-r--r--3rdparty/expat/lib/xmltok.h253
-rw-r--r--3rdparty/expat/lib/xmltok_impl.c1286
-rw-r--r--3rdparty/expat/lib/xmltok_impl.h103
-rw-r--r--3rdparty/expat/lib/xmltok_ns.c117
-rw-r--r--3rdparty/expat/m4/libtool.m42568
-rw-r--r--3rdparty/expat/m4/ltoptions.m4127
-rw-r--r--3rdparty/expat/m4/ltsugar.m47
-rw-r--r--3rdparty/expat/m4/ltversion.m412
-rw-r--r--3rdparty/expat/m4/lt~obsolete.m47
-rw-r--r--3rdparty/expat/run.sh.in12
-rwxr-xr-x3rdparty/expat/test-driver-wrapper.sh43
-rw-r--r--3rdparty/expat/tests/Makefile.am66
-rw-r--r--3rdparty/expat/tests/Makefile.in1254
-rw-r--r--3rdparty/expat/tests/benchmark/Makefile.am40
-rw-r--r--3rdparty/expat/tests/benchmark/Makefile.in651
-rw-r--r--3rdparty/expat/tests/benchmark/benchmark.c133
-rw-r--r--3rdparty/expat/tests/benchmark/benchmark.dsp88
-rw-r--r--3rdparty/expat/tests/benchmark/benchmark.dsw44
-rw-r--r--3rdparty/expat/tests/chardata.c179
-rw-r--r--3rdparty/expat/tests/chardata.h54
-rw-r--r--3rdparty/expat/tests/memcheck.c190
-rw-r--r--3rdparty/expat/tests/memcheck.h57
-rw-r--r--3rdparty/expat/tests/minicheck.c307
-rw-r--r--3rdparty/expat/tests/minicheck.h105
-rw-r--r--3rdparty/expat/tests/runtests.c12234
-rw-r--r--3rdparty/expat/tests/runtestspp.cpp40
-rw-r--r--3rdparty/expat/tests/structdata.c155
-rw-r--r--3rdparty/expat/tests/structdata.h70
-rwxr-xr-x3rdparty/expat/tests/udiffer.py62
-rw-r--r--3rdparty/expat/tests/xmltest.log.expected10
-rwxr-xr-x3rdparty/expat/tests/xmltest.sh32
-rw-r--r--3rdparty/expat/vms/README.vms23
-rw-r--r--3rdparty/expat/vms/descrip.mms70
-rw-r--r--3rdparty/expat/vms/expat_config.h52
-rw-r--r--3rdparty/expat/win32/MANIFEST.txt4
-rw-r--r--3rdparty/expat/win32/README.txt52
-rw-r--r--3rdparty/expat/win32/build_expat_iss.bat84
-rw-r--r--3rdparty/expat/win32/expat.iss34
-rw-r--r--3rdparty/expat/xmlwf/Makefile.am60
-rw-r--r--3rdparty/expat/xmlwf/Makefile.in783
-rw-r--r--3rdparty/expat/xmlwf/codepage.c98
-rw-r--r--3rdparty/expat/xmlwf/codepage.h32
-rw-r--r--3rdparty/expat/xmlwf/ct.c58
-rw-r--r--3rdparty/expat/xmlwf/filemap.h48
-rw-r--r--3rdparty/expat/xmlwf/readfilemap.c116
-rw-r--r--3rdparty/expat/xmlwf/unixfilemap.c68
-rw-r--r--3rdparty/expat/xmlwf/win32filemap.c72
-rw-r--r--3rdparty/expat/xmlwf/xmlfile.c203
-rw-r--r--3rdparty/expat/xmlwf/xmlfile.h43
-rw-r--r--3rdparty/expat/xmlwf/xmlmime.c70
-rw-r--r--3rdparty/expat/xmlwf/xmlmime.h32
-rw-r--r--3rdparty/expat/xmlwf/xmltchar.h104
-rw-r--r--3rdparty/expat/xmlwf/xmlurl.h13
-rw-r--r--3rdparty/expat/xmlwf/xmlwf.c688
-rw-r--r--3rdparty/expat/xmlwf/xmlwf.dsp139
-rwxr-xr-x3rdparty/expat/xmlwf/xmlwf_helpgen.py69
-rwxr-xr-x3rdparty/expat/xmlwf/xmlwf_helpgen.sh35
-rw-r--r--3rdparty/expat/xmlwf/xmlwin32url.cxx395
-rw-r--r--3rdparty/nanosvg/README.md8
-rw-r--r--3rdparty/nanosvg/example/example2.c2
-rw-r--r--3rdparty/nanosvg/premake4.lua2
-rw-r--r--3rdparty/nanosvg/src/nanosvg.h331
-rw-r--r--3rdparty/nanosvg/src/nanosvgrast.h43
-rw-r--r--3rdparty/sqlite3/shell.c17413
-rw-r--r--3rdparty/sqlite3/sqlite3.c87663
-rw-r--r--3rdparty/sqlite3/sqlite3.h4123
-rw-r--r--3rdparty/sqlite3/sqlite3ext.h109
-rw-r--r--COPYING6
-rw-r--r--android-project/app/src/main/AndroidManifest.xml4
-rw-r--r--docs/source/images/MAMElogo.svg71
-rw-r--r--docs/source/techspecs/layout_files.rst350
-rw-r--r--docs/source/usingmame/defaultkeys.rst375
-rw-r--r--docs/source/usingmame/images/mahjongpanel.svg215
-rw-r--r--hash/bbc_flop_hybrid.xml1107
-rw-r--r--hash/bbc_rom.xml256
-rw-r--r--hash/clipper_flop.xml2
-rw-r--r--hash/fmtowns_cd.xml299
-rw-r--r--hash/fmtowns_flop.xml158
-rw-r--r--hash/ibm5150.xml329
-rw-r--r--hash/ibm5170.xml216
-rw-r--r--hash/kaypro.xml (renamed from hash/kayproii.xml)99
-rw-r--r--hash/kaypro484.xml32
-rw-r--r--hash/laser2001_flop.xml20
-rw-r--r--hash/megadriv.xml16
-rw-r--r--hash/pc98_cd.xml2
-rw-r--r--hash/sgi_mips.xml134
-rw-r--r--hash/sorcerer_cass.xml213
-rw-r--r--hash/vgmplay.xml6167
-rw-r--r--hash/videopac.xml171
-rw-r--r--hash/vsmile_cart.xml29
-rw-r--r--hash/vtech_storio_cart.xml109
-rw-r--r--makefile8
-rw-r--r--plugins/cheat/init.lua3
-rw-r--r--plugins/hiscore/hiscore.dat24
-rwxr-xr-xscripts/build/complay.py157
-rw-r--r--scripts/genie.lua2
-rw-r--r--scripts/src/3rdparty.lua29
-rw-r--r--scripts/src/bus.lua22
-rw-r--r--scripts/src/cpu.lua13
-rw-r--r--scripts/src/emu.lua1
-rw-r--r--scripts/src/lib.lua3
-rw-r--r--scripts/src/machine.lua33
-rw-r--r--scripts/src/main.lua8
-rw-r--r--scripts/src/mame/frontend.lua2
-rw-r--r--scripts/src/netlist.lua19
-rw-r--r--scripts/src/sound.lua4
-rw-r--r--scripts/target/mame/arcade.lua10
-rw-r--r--scripts/target/mame/ci.lua8
-rw-r--r--scripts/target/mame/mess.lua17
-rw-r--r--scripts/target/mame/nl.lua22
-rw-r--r--scripts/target/mame/tiny.lua10
-rw-r--r--scripts/target/zexall/zexall.lua2
-rw-r--r--src/devices/bus/a2bus/a2bus.cpp4
-rw-r--r--src/devices/bus/a2bus/a2hsscsi.cpp95
-rw-r--r--src/devices/bus/a2bus/a2hsscsi.h5
-rw-r--r--src/devices/bus/a2bus/a2mcms.cpp21
-rw-r--r--src/devices/bus/a2bus/a2mcms.h2
-rw-r--r--src/devices/bus/a2bus/a2mockingboard.cpp33
-rw-r--r--src/devices/bus/a2bus/a2mockingboard.h2
-rw-r--r--src/devices/bus/a2bus/a2ultraterm.cpp5
-rw-r--r--src/devices/bus/a2bus/a2videoterm.cpp2
-rw-r--r--src/devices/bus/a2bus/computereyes2.cpp18
-rw-r--r--src/devices/bus/a2bus/computereyes2.h1
-rw-r--r--src/devices/bus/a2bus/mouse.cpp10
-rw-r--r--src/devices/bus/a2bus/sider.cpp296
-rw-r--r--src/devices/bus/a2bus/sider.h71
-rw-r--r--src/devices/bus/a2gameio/computereyes.cpp19
-rw-r--r--src/devices/bus/a2gameio/computereyes.h1
-rw-r--r--src/devices/bus/acorn/system/vdu40.cpp2
-rw-r--r--src/devices/bus/acorn/system/vdu80.cpp2
-rw-r--r--src/devices/bus/adamnet/adamnet.cpp2
-rw-r--r--src/devices/bus/adamnet/ddp.cpp2
-rw-r--r--src/devices/bus/adamnet/kb.cpp2
-rw-r--r--src/devices/bus/bbc/1mhzbus/1mhzbus.cpp16
-rw-r--r--src/devices/bus/bbc/1mhzbus/m5000.cpp435
-rw-r--r--src/devices/bus/bbc/1mhzbus/m5000.h158
-rw-r--r--src/devices/bus/bbc/joyport/joyport.cpp35
-rw-r--r--src/devices/bus/bbc/joyport/joyport.h6
-rw-r--r--src/devices/bus/bbc/tube/tube_32016.cpp85
-rw-r--r--src/devices/bus/bbc/tube/tube_32016.h7
-rw-r--r--src/devices/bus/bbc/userport/lcd.cpp2
-rw-r--r--src/devices/bus/bbc/userport/m4000.cpp170
-rw-r--r--src/devices/bus/bbc/userport/m4000.h58
-rw-r--r--src/devices/bus/bbc/userport/userport.cpp37
-rw-r--r--src/devices/bus/bbc/userport/userport.h6
-rw-r--r--src/devices/bus/bbc/userport/usersplit.cpp11
-rw-r--r--src/devices/bus/bbc/userport/usersplit.h2
-rw-r--r--src/devices/bus/bw2/ramcard.cpp23
-rw-r--r--src/devices/bus/c64/xl80.cpp12
-rw-r--r--src/devices/bus/cbmiec/cbmiec.cpp2
-rw-r--r--src/devices/bus/centronics/epson_lx810l.cpp4
-rw-r--r--src/devices/bus/coco/coco_ssc.cpp22
-rw-r--r--src/devices/bus/compis/hrg.cpp16
-rw-r--r--src/devices/bus/comx35/clm.cpp8
-rw-r--r--src/devices/bus/ecbbus/grip.cpp30
-rw-r--r--src/devices/bus/econet/econet.cpp2
-rw-r--r--src/devices/bus/einstein/pipe/tk02.cpp16
-rw-r--r--src/devices/bus/electron/cart/ap5.cpp2
-rw-r--r--src/devices/bus/electron/mode7.cpp2
-rw-r--r--src/devices/bus/electron/plus2.cpp2
-rw-r--r--src/devices/bus/fmt_scsi/fmt121.cpp150
-rw-r--r--src/devices/bus/fmt_scsi/fmt121.h50
-rw-r--r--src/devices/bus/fmt_scsi/fmt_scsi.cpp158
-rw-r--r--src/devices/bus/fmt_scsi/fmt_scsi.h98
-rw-r--r--src/devices/bus/gio64/newport.cpp2
-rw-r--r--src/devices/bus/hexbus/hexbus.cpp8
-rw-r--r--src/devices/bus/hexbus/hexbus.h2
-rw-r--r--src/devices/bus/hexbus/hx5102.cpp192
-rw-r--r--src/devices/bus/hexbus/hx5102.h14
-rw-r--r--src/devices/bus/hp_dio/hp98543.cpp2
-rw-r--r--src/devices/bus/hp_dio/hp98544.cpp12
-rw-r--r--src/devices/bus/hp_dio/hp98550.cpp2
-rw-r--r--src/devices/bus/ieee488/ieee488.cpp2
-rw-r--r--src/devices/bus/iq151/grafik.cpp2
-rw-r--r--src/devices/bus/iq151/minigraf.cpp2
-rw-r--r--src/devices/bus/iq151/ms151a.cpp2
-rw-r--r--src/devices/bus/iq151/video32.cpp2
-rw-r--r--src/devices/bus/iq151/video64.cpp2
-rw-r--r--src/devices/bus/isa/aga.cpp20
-rw-r--r--src/devices/bus/isa/cga.cpp690
-rw-r--r--src/devices/bus/isa/ega.cpp13
-rw-r--r--src/devices/bus/isa/eis_hgb107x.cpp21
-rw-r--r--src/devices/bus/isa/ex1280.cpp8
-rw-r--r--src/devices/bus/isa/fdc.cpp18
-rw-r--r--src/devices/bus/isa/fdc.h4
-rw-r--r--src/devices/bus/isa/gus.cpp25
-rw-r--r--src/devices/bus/isa/gus.h2
-rw-r--r--src/devices/bus/isa/isa_cards.cpp2
-rw-r--r--src/devices/bus/isa/mach32.cpp17
-rw-r--r--src/devices/bus/isa/mda.cpp280
-rw-r--r--src/devices/bus/isa/num9rev.cpp4
-rw-r--r--src/devices/bus/isa/omti8621.cpp21
-rw-r--r--src/devices/bus/isa/omti8621.h2
-rw-r--r--src/devices/bus/isa/pgc.cpp7
-rw-r--r--src/devices/bus/isa/trident.cpp27
-rw-r--r--src/devices/bus/macpds/pds_tpdfpd.cpp32
-rw-r--r--src/devices/bus/mtx/sdx.cpp2
-rw-r--r--src/devices/bus/nasbus/avc.cpp2
-rw-r--r--src/devices/bus/neogeo/prot_fatfury2.cpp16
-rw-r--r--src/devices/bus/nscsi/hd.cpp22
-rw-r--r--src/devices/bus/nubus/laserview.cpp30
-rw-r--r--src/devices/bus/nubus/nubus_48gc.cpp72
-rw-r--r--src/devices/bus/nubus/nubus_cb264.cpp52
-rw-r--r--src/devices/bus/nubus/nubus_m2hires.cpp56
-rw-r--r--src/devices/bus/nubus/nubus_m2video.cpp40
-rw-r--r--src/devices/bus/nubus/nubus_radiustpd.cpp32
-rw-r--r--src/devices/bus/nubus/nubus_spec8.cpp40
-rw-r--r--src/devices/bus/nubus/nubus_specpdq.cpp40
-rw-r--r--src/devices/bus/nubus/nubus_vikbw.cpp30
-rw-r--r--src/devices/bus/nubus/nubus_wsportrait.cpp49
-rw-r--r--src/devices/bus/nubus/pds30_30hr.cpp58
-rw-r--r--src/devices/bus/nubus/pds30_cb264.cpp55
-rw-r--r--src/devices/bus/nubus/pds30_mc30.cpp71
-rw-r--r--src/devices/bus/nubus/pds30_procolor816.cpp53
-rw-r--r--src/devices/bus/nubus/pds30_sigmalview.cpp14
-rw-r--r--src/devices/bus/odyssey2/4in1.cpp2
-rw-r--r--src/devices/bus/odyssey2/4in1.h2
-rw-r--r--src/devices/bus/odyssey2/chess.cpp2
-rw-r--r--src/devices/bus/odyssey2/chess.h2
-rw-r--r--src/devices/bus/odyssey2/homecomp.cpp2
-rw-r--r--src/devices/bus/odyssey2/homecomp.h2
-rw-r--r--src/devices/bus/odyssey2/ktaa.cpp2
-rw-r--r--src/devices/bus/odyssey2/ktaa.h2
-rw-r--r--src/devices/bus/odyssey2/rally.cpp2
-rw-r--r--src/devices/bus/odyssey2/rally.h2
-rw-r--r--src/devices/bus/odyssey2/rom.cpp2
-rw-r--r--src/devices/bus/odyssey2/rom.h2
-rw-r--r--src/devices/bus/odyssey2/slot.cpp14
-rw-r--r--src/devices/bus/odyssey2/slot.h40
-rw-r--r--src/devices/bus/odyssey2/voice.cpp2
-rw-r--r--src/devices/bus/odyssey2/voice.h2
-rw-r--r--src/devices/bus/s100/dg640.cpp24
-rw-r--r--src/devices/bus/s100/polyvti.cpp20
-rw-r--r--src/devices/bus/sbus/bwtwo.cpp9
-rw-r--r--src/devices/bus/sbus/cgsix.cpp6
-rw-r--r--src/devices/bus/sbus/cgthree.cpp6
-rw-r--r--src/devices/bus/scsi/omti5100.cpp2
-rw-r--r--src/devices/bus/svi3x8/slot/sv806.cpp18
-rw-r--r--src/devices/bus/tanbus/mpvdu.cpp10
-rw-r--r--src/devices/bus/tanbus/ravdu.cpp10
-rw-r--r--src/devices/bus/tanbus/tanhrg.cpp21
-rw-r--r--src/devices/bus/tanbus/tug8082.cpp14
-rw-r--r--src/devices/bus/ti99/gromport/cartridges.cpp36
-rw-r--r--src/devices/bus/ti99/gromport/cartridges.h10
-rw-r--r--src/devices/bus/ti99/internal/992board.cpp2
-rw-r--r--src/devices/bus/ti99/peb/horizon.cpp18
-rw-r--r--src/devices/bus/vic20/videopak.cpp2
-rw-r--r--src/devices/bus/vsmile/mat.cpp198
-rw-r--r--src/devices/bus/vsmile/mat.h69
-rw-r--r--src/devices/bus/vsmile/pad.cpp34
-rw-r--r--src/devices/bus/vsmile/pad.h36
-rw-r--r--src/devices/bus/vsmile/rom.cpp2
-rw-r--r--src/devices/bus/vsmile/rom.h2
-rw-r--r--src/devices/bus/vsmile/vsmile_ctrl.cpp2
-rw-r--r--src/devices/bus/wangpc/lvc.cpp10
-rw-r--r--src/devices/bus/wangpc/mvc.cpp22
-rw-r--r--src/devices/cpu/bcp/dp8344.cpp170
-rw-r--r--src/devices/cpu/bcp/dp8344.h7
-rw-r--r--src/devices/cpu/e0c6200/e0c6s46.cpp2
-rw-r--r--src/devices/cpu/f8/f8dasm.cpp181
-rw-r--r--src/devices/cpu/lc58/lc58d.cpp160
-rw-r--r--src/devices/cpu/lc58/lc58d.h30
-rw-r--r--src/devices/cpu/m6502/n2a03.cpp19
-rw-r--r--src/devices/cpu/m6502/n2a03.h29
-rw-r--r--src/devices/cpu/mcs48/mcs48.cpp24
-rw-r--r--src/devices/cpu/mcs48/mcs48.h3
-rw-r--r--src/devices/cpu/ns32000/ns32000.cpp1659
-rw-r--r--src/devices/cpu/ns32000/ns32000.h60
-rw-r--r--src/devices/cpu/ns32000/ns32000dasm.cpp47
-rw-r--r--src/devices/cpu/ns32000/ns32000dasm.h3
-rw-r--r--src/devices/cpu/ns32000/slave.h45
-rw-r--r--src/devices/cpu/pdp1/pdp1.cpp7
-rw-r--r--src/devices/cpu/pdp1/pdp1.h3
-rw-r--r--src/devices/cpu/pic16c5x/pic16c5x.cpp2
-rw-r--r--src/devices/cpu/t11/t11dasm.cpp49
-rw-r--r--src/devices/cpu/tms34010/tms34010.cpp4
-rw-r--r--src/devices/cpu/tms57002/tms57002.cpp9
-rw-r--r--src/devices/cpu/tms9900/tms9995.cpp6
-rw-r--r--src/devices/cpu/unsp/unsp.cpp10
-rw-r--r--src/devices/cpu/unsp/unspdasm_extended.cpp2
-rw-r--r--src/devices/cpu/vt50/vt50.cpp2
-rw-r--r--src/devices/cpu/x86log.cpp4
-rw-r--r--src/devices/cpu/x86log.h34
-rw-r--r--src/devices/imagedev/cassette.cpp53
-rw-r--r--src/devices/imagedev/cassette.h15
-rw-r--r--src/devices/imagedev/floppy.cpp34
-rw-r--r--src/devices/imagedev/floppy.h4
-rw-r--r--src/devices/imagedev/mfmhd.cpp23
-rw-r--r--src/devices/imagedev/mfmhd.h4
-rw-r--r--src/devices/imagedev/midiin.cpp18
-rw-r--r--src/devices/imagedev/midiin.h2
-rw-r--r--src/devices/imagedev/midiout.cpp14
-rw-r--r--src/devices/imagedev/midiout.h2
-rw-r--r--src/devices/imagedev/picture.cpp41
-rw-r--r--src/devices/imagedev/picture.h4
-rw-r--r--src/devices/machine/6840ptm.cpp5
-rw-r--r--src/devices/machine/6840ptm.h1
-rw-r--r--src/devices/machine/8364_paula.cpp14
-rw-r--r--src/devices/machine/8364_paula.h2
-rw-r--r--src/devices/machine/acorn_vidc.cpp4
-rw-r--r--src/devices/machine/alpha_8921.h2
-rw-r--r--src/devices/machine/am9519.h2
-rw-r--r--src/devices/machine/bl_handhelds_menucontrol.cpp214
-rw-r--r--src/devices/machine/bl_handhelds_menucontrol.h64
-rw-r--r--src/devices/machine/bq4847.cpp2
-rw-r--r--src/devices/machine/cs8900a.cpp428
-rw-r--r--src/devices/machine/cs8900a.h26
-rw-r--r--src/devices/machine/exorterm.cpp4
-rw-r--r--src/devices/machine/generalplus_gpl16250soc.cpp12
-rw-r--r--src/devices/machine/generalplus_gpl16250soc.h2
-rw-r--r--src/devices/machine/generalplus_gpl16250soc_video.cpp34
-rw-r--r--src/devices/machine/ie15.cpp3
-rw-r--r--src/devices/machine/laserdsc.cpp54
-rw-r--r--src/devices/machine/laserdsc.h23
-rw-r--r--src/devices/machine/ldpr8210.cpp12
-rw-r--r--src/devices/machine/m3002.cpp4
-rw-r--r--src/devices/machine/m3002.h2
-rw-r--r--src/devices/machine/mc68328.cpp19
-rw-r--r--src/devices/machine/mm58167.cpp5
-rw-r--r--src/devices/machine/netlist.cpp1
-rw-r--r--src/devices/machine/ns32081.cpp637
-rw-r--r--src/devices/machine/ns32081.h60
-rw-r--r--src/devices/machine/ns32202.cpp698
-rw-r--r--src/devices/machine/ns32202.h137
-rw-r--r--src/devices/machine/pxa255.cpp2
-rw-r--r--src/devices/machine/s2636.cpp15
-rw-r--r--src/devices/machine/s2636.h2
-rw-r--r--src/devices/machine/s3c24xx.hxx58
-rw-r--r--src/devices/machine/s3c44b0.cpp9
-rw-r--r--src/devices/machine/spg110_video.cpp9
-rw-r--r--src/devices/machine/spg290_ppu.cpp8
-rw-r--r--src/devices/machine/spg2xx.h2
-rw-r--r--src/devices/machine/spg2xx_audio.cpp14
-rw-r--r--src/devices/machine/spg2xx_audio.h2
-rw-r--r--src/devices/machine/spg_renderer.cpp2
-rw-r--r--src/devices/machine/swtpc8212.cpp2
-rw-r--r--src/devices/machine/tc009xlvc.cpp4
-rw-r--r--src/devices/machine/terminal.cpp2
-rw-r--r--src/devices/machine/upd765.cpp98
-rw-r--r--src/devices/machine/upd765.h8
-rw-r--r--src/devices/machine/wd1010.cpp222
-rw-r--r--src/devices/machine/wd1010.h20
-rw-r--r--src/devices/machine/z80scc.cpp1
-rw-r--r--src/devices/sound/2203intf.cpp9
-rw-r--r--src/devices/sound/2203intf.h2
-rw-r--r--src/devices/sound/2608intf.cpp8
-rw-r--r--src/devices/sound/2608intf.h2
-rw-r--r--src/devices/sound/2610intf.cpp14
-rw-r--r--src/devices/sound/2610intf.h4
-rw-r--r--src/devices/sound/2612intf.cpp10
-rw-r--r--src/devices/sound/2612intf.h2
-rw-r--r--src/devices/sound/262intf.cpp8
-rw-r--r--src/devices/sound/262intf.h2
-rw-r--r--src/devices/sound/3526intf.cpp8
-rw-r--r--src/devices/sound/3526intf.h2
-rw-r--r--src/devices/sound/3812intf.cpp8
-rw-r--r--src/devices/sound/3812intf.h2
-rw-r--r--src/devices/sound/8950intf.cpp8
-rw-r--r--src/devices/sound/8950intf.h2
-rw-r--r--src/devices/sound/aica.cpp5
-rw-r--r--src/devices/sound/asc.cpp10
-rw-r--r--src/devices/sound/astrocde.cpp4
-rw-r--r--src/devices/sound/awacs.cpp5
-rw-r--r--src/devices/sound/ay8910.cpp22
-rw-r--r--src/devices/sound/ay8910.h2
-rw-r--r--src/devices/sound/c140.cpp24
-rw-r--r--src/devices/sound/c352.cpp9
-rw-r--r--src/devices/sound/c6280.cpp17
-rw-r--r--src/devices/sound/cdda.cpp5
-rw-r--r--src/devices/sound/cdp1864.cpp2
-rw-r--r--src/devices/sound/cdp1869.cpp13
-rw-r--r--src/devices/sound/cem3394.cpp130
-rw-r--r--src/devices/sound/dac76.cpp2
-rw-r--r--src/devices/sound/dave.cpp5
-rw-r--r--src/devices/sound/digitalk.cpp5
-rw-r--r--src/devices/sound/discrete.cpp323
-rw-r--r--src/devices/sound/discrete.h192
-rw-r--r--src/devices/sound/dmadac.cpp2
-rw-r--r--src/devices/sound/dspv.cpp1
-rw-r--r--src/devices/sound/es1373.cpp61
-rw-r--r--src/devices/sound/es1373.h4
-rw-r--r--src/devices/sound/es5503.cpp46
-rw-r--r--src/devices/sound/es5503.h4
-rw-r--r--src/devices/sound/es5506.cpp144
-rw-r--r--src/devices/sound/es5506.h19
-rw-r--r--src/devices/sound/esqpump.cpp129
-rw-r--r--src/devices/sound/esqpump.h12
-rw-r--r--src/devices/sound/flt_biquad.cpp487
-rw-r--r--src/devices/sound/flt_biquad.h80
-rw-r--r--src/devices/sound/flt_rc.cpp47
-rw-r--r--src/devices/sound/flt_rc.h9
-rw-r--r--src/devices/sound/flt_vol.cpp16
-rw-r--r--src/devices/sound/flt_vol.h4
-rw-r--r--src/devices/sound/fm.cpp65
-rw-r--r--src/devices/sound/fm.h12
-rw-r--r--src/devices/sound/fm2612.cpp13
-rw-r--r--src/devices/sound/fmopl.cpp40
-rw-r--r--src/devices/sound/fmopl.h8
-rw-r--r--src/devices/sound/gaelco.cpp14
-rw-r--r--src/devices/sound/gaelco.h2
-rw-r--r--src/devices/sound/gb.cpp26
-rw-r--r--src/devices/sound/gb.h2
-rw-r--r--src/devices/sound/hc55516.cpp584
-rw-r--r--src/devices/sound/hc55516.h165
-rw-r--r--src/devices/sound/huc6230.cpp17
-rw-r--r--src/devices/sound/huc6230.h2
-rw-r--r--src/devices/sound/i5000.cpp10
-rw-r--r--src/devices/sound/i5000.h2
-rw-r--r--src/devices/sound/ics2115.cpp31
-rw-r--r--src/devices/sound/ics2115.h6
-rw-r--r--src/devices/sound/iopspu.cpp3
-rw-r--r--src/devices/sound/iopspu.h2
-rw-r--r--src/devices/sound/iremga20.cpp21
-rw-r--r--src/devices/sound/iremga20.h2
-rw-r--r--src/devices/sound/k005289.cpp43
-rw-r--r--src/devices/sound/k005289.h8
-rw-r--r--src/devices/sound/k007232.cpp18
-rw-r--r--src/devices/sound/k007232.h2
-rw-r--r--src/devices/sound/k051649.cpp24
-rw-r--r--src/devices/sound/k051649.h6
-rw-r--r--src/devices/sound/k053260.cpp30
-rw-r--r--src/devices/sound/k053260.h4
-rw-r--r--src/devices/sound/k054539.cpp15
-rw-r--r--src/devices/sound/k054539.h2
-rw-r--r--src/devices/sound/ks0164.cpp10
-rw-r--r--src/devices/sound/ks0164.h2
-rw-r--r--src/devices/sound/l7a1045_l6028_dsp_a.cpp16
-rw-r--r--src/devices/sound/l7a1045_l6028_dsp_a.h2
-rw-r--r--src/devices/sound/lmc1992.cpp5
-rw-r--r--src/devices/sound/lmc1992.h2
-rw-r--r--src/devices/sound/mas3507d.cpp25
-rw-r--r--src/devices/sound/mas3507d.h4
-rw-r--r--src/devices/sound/mea8000.cpp9
-rw-r--r--src/devices/sound/mea8000.h4
-rw-r--r--src/devices/sound/mm5837.cpp68
-rw-r--r--src/devices/sound/mm5837.h104
-rw-r--r--src/devices/sound/mos6560.cpp127
-rw-r--r--src/devices/sound/mos6560.h6
-rw-r--r--src/devices/sound/mos6581.cpp8
-rw-r--r--src/devices/sound/mos6581.h2
-rw-r--r--src/devices/sound/mos7360.cpp171
-rw-r--r--src/devices/sound/mos7360.h2
-rw-r--r--src/devices/sound/msm5232.cpp52
-rw-r--r--src/devices/sound/msm5232.h2
-rw-r--r--src/devices/sound/multipcm.cpp38
-rw-r--r--src/devices/sound/multipcm.h70
-rw-r--r--src/devices/sound/n63701x.cpp19
-rw-r--r--src/devices/sound/n63701x.h2
-rw-r--r--src/devices/sound/namco.cpp131
-rw-r--r--src/devices/sound/namco.h19
-rw-r--r--src/devices/sound/namco_163.cpp21
-rw-r--r--src/devices/sound/namco_163.h4
-rw-r--r--src/devices/sound/nes_apu.cpp28
-rw-r--r--src/devices/sound/nes_apu.h4
-rw-r--r--src/devices/sound/nes_apu_vt.cpp28
-rw-r--r--src/devices/sound/nes_apu_vt.h26
-rw-r--r--src/devices/sound/nile.cpp19
-rw-r--r--src/devices/sound/nile.h2
-rw-r--r--src/devices/sound/okim6258.cpp19
-rw-r--r--src/devices/sound/okim6258.h2
-rw-r--r--src/devices/sound/okim6295.cpp3
-rw-r--r--src/devices/sound/okim6376.cpp25
-rw-r--r--src/devices/sound/okim6376.h2
-rw-r--r--src/devices/sound/okim9810.cpp27
-rw-r--r--src/devices/sound/okim9810.h7
-rw-r--r--src/devices/sound/pcd3311.cpp5
-rw-r--r--src/devices/sound/pcd3311.h2
-rw-r--r--src/devices/sound/qs1000.cpp22
-rw-r--r--src/devices/sound/qs1000.h2
-rw-r--r--src/devices/sound/qsound.cpp10
-rw-r--r--src/devices/sound/qsound.h2
-rw-r--r--src/devices/sound/qsoundhle.cpp16
-rw-r--r--src/devices/sound/qsoundhle.h2
-rw-r--r--src/devices/sound/rf5c400.cpp20
-rw-r--r--src/devices/sound/rf5c400.h2
-rw-r--r--src/devices/sound/rf5c68.cpp51
-rw-r--r--src/devices/sound/rf5c68.h4
-rw-r--r--src/devices/sound/rolandpcm.cpp20
-rw-r--r--src/devices/sound/rolandpcm.h2
-rw-r--r--src/devices/sound/rp2c33_snd.cpp10
-rw-r--r--src/devices/sound/rp2c33_snd.h2
-rw-r--r--src/devices/sound/s14001a.cpp10
-rw-r--r--src/devices/sound/s14001a.h2
-rw-r--r--src/devices/sound/s_dsp.cpp12
-rw-r--r--src/devices/sound/s_dsp.h2
-rw-r--r--src/devices/sound/saa1099.cpp16
-rw-r--r--src/devices/sound/saa1099.h2
-rw-r--r--src/devices/sound/scsp.cpp47
-rw-r--r--src/devices/sound/scsp.h11
-rw-r--r--src/devices/sound/segapcm.cpp16
-rw-r--r--src/devices/sound/segapcm.h2
-rw-r--r--src/devices/sound/sid.cpp42
-rw-r--r--src/devices/sound/sid.h2
-rw-r--r--src/devices/sound/sn76477.cpp14
-rw-r--r--src/devices/sound/sn76477.h2
-rw-r--r--src/devices/sound/sn76496.cpp5
-rw-r--r--src/devices/sound/snkwave.cpp18
-rw-r--r--src/devices/sound/snkwave.h2
-rw-r--r--src/devices/sound/sp0250.cpp3
-rw-r--r--src/devices/sound/sp0256.cpp18
-rw-r--r--src/devices/sound/sp0256.h2
-rw-r--r--src/devices/sound/spkrdev.cpp32
-rw-r--r--src/devices/sound/spkrdev.h10
-rw-r--r--src/devices/sound/spu.cpp130
-rw-r--r--src/devices/sound/spu.h8
-rw-r--r--src/devices/sound/spureverb.cpp20
-rw-r--r--src/devices/sound/spureverb.h12
-rw-r--r--src/devices/sound/st0016.cpp16
-rw-r--r--src/devices/sound/st0016.h2
-rw-r--r--src/devices/sound/swp00.cpp6
-rw-r--r--src/devices/sound/swp00.h2
-rw-r--r--src/devices/sound/swp20.cpp3
-rw-r--r--src/devices/sound/swp20.h2
-rw-r--r--src/devices/sound/swp30.cpp18
-rw-r--r--src/devices/sound/swp30.h2
-rw-r--r--src/devices/sound/t6721a.cpp7
-rw-r--r--src/devices/sound/t6721a.h2
-rw-r--r--src/devices/sound/t6w28.cpp20
-rw-r--r--src/devices/sound/t6w28.h2
-rw-r--r--src/devices/sound/tc8830f.cpp8
-rw-r--r--src/devices/sound/tc8830f.h2
-rw-r--r--src/devices/sound/tiaintf.cpp8
-rw-r--r--src/devices/sound/tiaintf.h2
-rw-r--r--src/devices/sound/tiasound.cpp336
-rw-r--r--src/devices/sound/tiasound.h2
-rw-r--r--src/devices/sound/tms3615.cpp2
-rw-r--r--src/devices/sound/tms36xx.cpp15
-rw-r--r--src/devices/sound/tms36xx.h2
-rw-r--r--src/devices/sound/tms5110.cpp22
-rw-r--r--src/devices/sound/tms5110.h2
-rw-r--r--src/devices/sound/tms5220.cpp3
-rw-r--r--src/devices/sound/upd1771.cpp29
-rw-r--r--src/devices/sound/upd1771.h2
-rw-r--r--src/devices/sound/upd7752.cpp7
-rw-r--r--src/devices/sound/upd7752.h2
-rw-r--r--src/devices/sound/upd934g.cpp15
-rw-r--r--src/devices/sound/upd934g.h2
-rw-r--r--src/devices/sound/vgm_visualizer.cpp65
-rw-r--r--src/devices/sound/vlm5030.cpp35
-rw-r--r--src/devices/sound/vlm5030.h2
-rw-r--r--src/devices/sound/votrax.cpp9
-rw-r--r--src/devices/sound/vrc6.cpp16
-rw-r--r--src/devices/sound/vrc6.h2
-rw-r--r--src/devices/sound/vrender0.cpp16
-rw-r--r--src/devices/sound/vrender0.h4
-rw-r--r--src/devices/sound/wave.cpp39
-rw-r--r--src/devices/sound/wave.h3
-rw-r--r--src/devices/sound/x1_010.cpp26
-rw-r--r--src/devices/sound/x1_010.h2
-rw-r--r--src/devices/sound/ym2151.cpp13
-rw-r--r--src/devices/sound/ym2413.cpp12
-rw-r--r--src/devices/sound/ym2413.h2
-rw-r--r--src/devices/sound/ymf262.cpp33
-rw-r--r--src/devices/sound/ymf262.h4
-rw-r--r--src/devices/sound/ymf271.cpp147
-rw-r--r--src/devices/sound/ymf271.h2
-rw-r--r--src/devices/sound/ymf278b.cpp30
-rw-r--r--src/devices/sound/ymf278b.h2
-rw-r--r--src/devices/sound/ymz280b.cpp35
-rw-r--r--src/devices/sound/ymz280b.h2
-rw-r--r--src/devices/sound/ymz770.cpp18
-rw-r--r--src/devices/sound/ymz770.h2
-rw-r--r--src/devices/sound/zsg2.cpp11
-rw-r--r--src/devices/sound/zsg2.h2
-rw-r--r--src/devices/video/315_5124.cpp8
-rw-r--r--src/devices/video/315_5313.cpp2
-rw-r--r--src/devices/video/cdp1861.cpp5
-rw-r--r--src/devices/video/cdp1862.cpp5
-rw-r--r--src/devices/video/cesblit.cpp34
-rw-r--r--src/devices/video/clgd542x.cpp25
-rw-r--r--src/devices/video/ef9340_1.cpp123
-rw-r--r--src/devices/video/ef9340_1.h32
-rw-r--r--src/devices/video/ef9345.cpp4
-rw-r--r--src/devices/video/ef9364.cpp19
-rw-r--r--src/devices/video/ef9365.cpp15
-rw-r--r--src/devices/video/fixfreq.cpp5
-rw-r--r--src/devices/video/gb_lcd.cpp2
-rw-r--r--src/devices/video/gba_lcd.cpp2
-rw-r--r--src/devices/video/gf4500.cpp9
-rw-r--r--src/devices/video/hd44102.cpp2
-rw-r--r--src/devices/video/hd44352.cpp4
-rw-r--r--src/devices/video/hd44780.cpp4
-rw-r--r--src/devices/video/hd61830.cpp6
-rw-r--r--src/devices/video/hd63484.cpp2
-rw-r--r--src/devices/video/hd66421.cpp2
-rw-r--r--src/devices/video/hp1ll3.cpp4
-rw-r--r--src/devices/video/huc6260.cpp4
-rw-r--r--src/devices/video/huc6261.cpp4
-rw-r--r--src/devices/video/i8244.cpp162
-rw-r--r--src/devices/video/i8244.h68
-rw-r--r--src/devices/video/imagetek_i4100.cpp18
-rw-r--r--src/devices/video/m50458.cpp66
-rw-r--r--src/devices/video/mb88303.cpp2
-rw-r--r--src/devices/video/mb90082.cpp39
-rw-r--r--src/devices/video/mb_vcu.cpp19
-rw-r--r--src/devices/video/mc6845.cpp16
-rw-r--r--src/devices/video/mc6847.h6
-rw-r--r--src/devices/video/mos6566.cpp124
-rw-r--r--src/devices/video/msm6255.cpp8
-rw-r--r--src/devices/video/nt7534.cpp2
-rw-r--r--src/devices/video/pc_vga.cpp348
-rw-r--r--src/devices/video/ppu2c0x.cpp298
-rw-r--r--src/devices/video/ppu2c0x.h25
-rw-r--r--src/devices/video/ppu2c0x_sh6578.cpp65
-rw-r--r--src/devices/video/ppu2c0x_sh6578.h2
-rw-r--r--src/devices/video/ppu2c0x_vt.cpp366
-rw-r--r--src/devices/video/ppu2c0x_vt.h19
-rw-r--r--src/devices/video/psx.cpp8
-rw-r--r--src/devices/video/saa5050.cpp4
-rw-r--r--src/devices/video/scn2674.cpp2
-rw-r--r--src/devices/video/sed1330.cpp4
-rw-r--r--src/devices/video/snes_ppu.cpp14
-rw-r--r--src/devices/video/stvvdp2.cpp261
-rw-r--r--src/devices/video/t6963c.cpp8
-rw-r--r--src/devices/video/t6963c.h2
-rw-r--r--src/devices/video/t6a04.cpp2
-rw-r--r--src/devices/video/tms3556.cpp6
-rw-r--r--src/devices/video/tms9928a.cpp2
-rw-r--r--src/devices/video/v9938.cpp6
-rw-r--r--src/devices/video/vector.cpp7
-rw-r--r--src/devices/video/vic4567.cpp339
-rw-r--r--src/devices/video/voodoo.cpp8
-rw-r--r--src/devices/video/vrender0.cpp2
-rw-r--r--src/devices/video/zeus2.cpp10
-rw-r--r--src/emu/addrmap.cpp2
-rw-r--r--src/emu/crsshair.cpp46
-rw-r--r--src/emu/debug/debugcmd.cpp80
-rw-r--r--src/emu/debug/debugcmd.h5
-rw-r--r--src/emu/debug/debugcon.cpp98
-rw-r--r--src/emu/debug/debugcon.h93
-rw-r--r--src/emu/debug/debugvw.cpp18
-rw-r--r--src/emu/debug/dvtext.cpp39
-rw-r--r--src/emu/debug/dvtext.h13
-rw-r--r--src/emu/debug/express.h2
-rw-r--r--src/emu/debug/textbuf.cpp154
-rw-r--r--src/emu/debug/textbuf.h61
-rw-r--r--src/emu/device.h4
-rw-r--r--src/emu/disound.cpp18
-rw-r--r--src/emu/disound.h4
-rw-r--r--src/emu/distate.cpp6
-rw-r--r--src/emu/distate.h1
-rw-r--r--src/emu/emualloc.cpp2
-rw-r--r--src/emu/emualloc.h8
-rw-r--r--src/emu/emucore.h3
-rw-r--r--src/emu/fileio.cpp16
-rw-r--r--src/emu/ioport.cpp88
-rw-r--r--src/emu/machine.cpp6
-rw-r--r--src/emu/natkeyboard.cpp230
-rw-r--r--src/emu/natkeyboard.h42
-rw-r--r--src/emu/recording.cpp16
-rw-r--r--src/emu/render.cpp292
-rw-r--r--src/emu/render.h182
-rw-r--r--src/emu/rendertypes.h153
-rw-r--r--src/emu/rendfont.cpp6
-rw-r--r--src/emu/rendfont.h3
-rw-r--r--src/emu/rendlay.cpp1810
-rw-r--r--src/emu/rendutil.cpp331
-rw-r--r--src/emu/rendutil.h83
-rw-r--r--src/emu/romload.cpp17
-rw-r--r--src/emu/romload.h1
-rw-r--r--src/emu/screen.cpp84
-rw-r--r--src/emu/sound.cpp105
-rw-r--r--src/emu/sound.h140
-rw-r--r--src/emu/tilemap.cpp34
-rw-r--r--src/emu/uiinput.cpp51
-rw-r--r--src/emu/uiinput.h27
-rw-r--r--src/emu/video.cpp12
-rw-r--r--src/frontend/mame/audit.cpp215
-rw-r--r--src/frontend/mame/audit.h23
-rw-r--r--src/frontend/mame/clifront.cpp2
-rw-r--r--src/frontend/mame/luaengine.cpp2
-rw-r--r--src/frontend/mame/mame.cpp40
-rw-r--r--src/frontend/mame/mame.h6
-rw-r--r--src/frontend/mame/ui/icorender.cpp508
-rw-r--r--src/frontend/mame/ui/inputmap.cpp17
-rw-r--r--src/frontend/mame/ui/inputmap.h2
-rw-r--r--src/frontend/mame/ui/keyboard.cpp98
-rw-r--r--src/frontend/mame/ui/keyboard.h33
-rw-r--r--src/frontend/mame/ui/mainmenu.cpp3
-rw-r--r--src/frontend/mame/ui/menu.cpp177
-rw-r--r--src/frontend/mame/ui/menu.h4
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp37
-rw-r--r--src/frontend/mame/ui/miscmenu.h12
-rw-r--r--src/frontend/mame/ui/selgame.cpp65
-rw-r--r--src/frontend/mame/ui/selgame.h4
-rw-r--r--src/frontend/mame/ui/selmenu.cpp194
-rw-r--r--src/frontend/mame/ui/selmenu.h3
-rw-r--r--src/frontend/mame/ui/selsoft.cpp26
-rw-r--r--src/frontend/mame/ui/slider.h12
-rw-r--r--src/frontend/mame/ui/text.cpp4
-rw-r--r--src/frontend/mame/ui/text.h5
-rw-r--r--src/frontend/mame/ui/ui.cpp18
-rw-r--r--src/frontend/mame/ui/ui.h2
-rw-r--r--src/frontend/mame/ui/videoopt.cpp2
-rw-r--r--src/frontend/mame/ui/viewgfx.cpp10
-rw-r--r--src/frontend/mame/ui/widgets.cpp23
-rw-r--r--src/lib/formats/a26_cas.cpp16
-rw-r--r--src/lib/formats/ace_tap.cpp14
-rw-r--r--src/lib/formats/adam_cas.cpp27
-rw-r--r--src/lib/formats/apf_apt.cpp24
-rw-r--r--src/lib/formats/apridisk.cpp4
-rw-r--r--src/lib/formats/atom_tap.cpp21
-rw-r--r--src/lib/formats/camplynx_cas.cpp20
-rw-r--r--src/lib/formats/cassimg.cpp848
-rw-r--r--src/lib/formats/cassimg.h330
-rw-r--r--src/lib/formats/cbm_tap.cpp10
-rw-r--r--src/lib/formats/cgen_cas.cpp12
-rw-r--r--src/lib/formats/coco_cas.cpp36
-rw-r--r--src/lib/formats/csw_cas.cpp420
-rw-r--r--src/lib/formats/csw_cas.h2
-rw-r--r--src/lib/formats/fc100_cas.cpp16
-rw-r--r--src/lib/formats/fm7_cas.cpp16
-rw-r--r--src/lib/formats/fmsx_cas.cpp10
-rw-r--r--src/lib/formats/gtp_cas.cpp16
-rw-r--r--src/lib/formats/h8_cas.cpp16
-rw-r--r--src/lib/formats/hect_tap.cpp22
-rw-r--r--src/lib/formats/imd_dsk.cpp20
-rw-r--r--src/lib/formats/ioprocs.h24
-rw-r--r--src/lib/formats/ipf_dsk.cpp35
-rw-r--r--src/lib/formats/ipf_dsk.h22
-rw-r--r--src/lib/formats/kc_cas.cpp36
-rw-r--r--src/lib/formats/kim1_cas.cpp16
-rw-r--r--src/lib/formats/lviv_lvt.cpp33
-rw-r--r--src/lib/formats/mbee_cas.cpp10
-rw-r--r--src/lib/formats/mfi_dsk.cpp15
-rw-r--r--src/lib/formats/mz_cas.cpp13
-rw-r--r--src/lib/formats/orao_cas.cpp16
-rw-r--r--src/lib/formats/oric_tap.cpp13
-rw-r--r--src/lib/formats/p2000t_cas.cpp82
-rw-r--r--src/lib/formats/p6001_cas.cpp19
-rw-r--r--src/lib/formats/phc25_cas.cpp16
-rw-r--r--src/lib/formats/pmd_cas.cpp16
-rw-r--r--src/lib/formats/primoptp.cpp17
-rw-r--r--src/lib/formats/rk_cas.cpp59
-rw-r--r--src/lib/formats/sc3000_bit.cpp20
-rw-r--r--src/lib/formats/sol_cas.cpp14
-rw-r--r--src/lib/formats/sorc_cas.cpp12
-rw-r--r--src/lib/formats/sord_cas.cpp36
-rw-r--r--src/lib/formats/spc1000_cas.cpp24
-rw-r--r--src/lib/formats/svi_cas.cpp16
-rw-r--r--src/lib/formats/thom_cas.cpp117
-rw-r--r--src/lib/formats/trs_cas.cpp14
-rw-r--r--src/lib/formats/tvc_cas.cpp14
-rw-r--r--src/lib/formats/tzx_cas.cpp32
-rw-r--r--src/lib/formats/tzx_cas.h2
-rw-r--r--src/lib/formats/uef_cas.cpp22
-rw-r--r--src/lib/formats/uef_cas.h2
-rw-r--r--src/lib/formats/vg5k_cas.cpp18
-rw-r--r--src/lib/formats/vt_cas.cpp38
-rw-r--r--src/lib/formats/wavfile.cpp39
-rw-r--r--src/lib/formats/wavfile.h2
-rw-r--r--src/lib/formats/x07_cas.cpp16
-rw-r--r--src/lib/formats/x1_tap.cpp14
-rw-r--r--src/lib/formats/zx81_p.cpp30
-rw-r--r--src/lib/netlist/analog/nlid_fourterm.h15
-rw-r--r--src/lib/netlist/analog/nlid_twoterm.h2
-rwxr-xr-xsrc/lib/netlist/buildVS/netlistlib.vcxproj13
-rwxr-xr-xsrc/lib/netlist/buildVS/netlistlib.vcxproj.filters35
-rw-r--r--src/lib/netlist/core/analog.h3
-rw-r--r--src/lib/netlist/core/base_objects.h10
-rw-r--r--src/lib/netlist/core/core_device.h16
-rw-r--r--src/lib/netlist/core/exec.h25
-rw-r--r--src/lib/netlist/core/logic.h12
-rw-r--r--src/lib/netlist/core/netlist_state.h35
-rw-r--r--src/lib/netlist/core/nets.h158
-rw-r--r--src/lib/netlist/core/object_array.h6
-rw-r--r--src/lib/netlist/core/param.h4
-rw-r--r--src/lib/netlist/core/queue.h3
-rw-r--r--src/lib/netlist/core/setup.h22
-rw-r--r--src/lib/netlist/core/state_var.h7
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/devices/nld_2102a.cpp (renamed from src/lib/netlist/devices/nld_2102A.cpp)0
-rw-r--r--src/lib/netlist/devices/nld_4029.cpp272
-rw-r--r--src/lib/netlist/devices/nld_4042.cpp120
-rw-r--r--src/lib/netlist/devices/nld_4076.cpp132
-rw-r--r--src/lib/netlist/devices/nld_7448.cpp2
-rw-r--r--src/lib/netlist/devices/nld_7493.cpp34
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/devices/nld_82s115.cpp (renamed from src/lib/netlist/devices/nld_82S115.cpp)0
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/devices/nld_82s16.cpp (renamed from src/lib/netlist/devices/nld_82S16.cpp)0
-rw-r--r--src/lib/netlist/devices/nld_9316_base.hxx20
-rw-r--r--src/lib/netlist/devices/nld_9321.cpp2
-rw-r--r--src/lib/netlist/devices/nld_log.cpp4
-rw-r--r--src/lib/netlist/devices/nld_roms.cpp77
-rw-r--r--src/lib/netlist/devices/nld_system.cpp2
-rw-r--r--src/lib/netlist/devices/nlid_proxy.cpp18
-rw-r--r--src/lib/netlist/devices/nlid_system.h51
-rw-r--r--src/lib/netlist/devices/nlid_truthtable.cpp26
-rw-r--r--src/lib/netlist/examples/2n6027.cpp (renamed from src/lib/netlist/examples/2N6027.cpp)0
-rw-r--r--src/lib/netlist/examples/lm3900_test.cpp (renamed from src/lib/netlist/examples/LM3900_test.cpp)0
-rwxr-xr-xsrc/lib/netlist/generated/lib_entries.hxx4
-rwxr-xr-xsrc/lib/netlist/generated/nld_devinc.h90
-rwxr-xr-xsrc/lib/netlist/generated/nlm_modules_lib.cpp2
-rw-r--r--src/lib/netlist/generated/static_solvers.cpp13574
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/macro/modules/nlmod_icl8038_dip.cpp (renamed from src/lib/netlist/macro/modules/nlmod_ICL8038_DIP.cpp)0
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/macro/modules/nlmod_ne556_dip.cpp (renamed from src/lib/netlist/macro/modules/nlmod_NE556_DIP.cpp)0
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/macro/modules/nlmod_rtest.cpp (renamed from src/lib/netlist/macro/modules/nlmod_RTEST.cpp)0
-rw-r--r--src/lib/netlist/macro/nlm_cd4xxx_lib.cpp398
-rw-r--r--src/lib/netlist/macro/nlm_opamp_lib.cpp11
-rw-r--r--src/lib/netlist/macro/nlm_roms_lib.cpp34
-rw-r--r--src/lib/netlist/nl_base.cpp54
-rw-r--r--src/lib/netlist/nl_config.h60
-rw-r--r--src/lib/netlist/nl_errstr.h11
-rw-r--r--src/lib/netlist/nl_parser.h2
-rw-r--r--src/lib/netlist/nl_setup.cpp58
-rw-r--r--src/lib/netlist/nl_setup.h6
-rw-r--r--src/lib/netlist/nltypes.h18
-rw-r--r--src/lib/netlist/plib/gmres.h189
-rw-r--r--src/lib/netlist/plib/palloc.h7
-rw-r--r--src/lib/netlist/plib/parray.h17
-rwxr-xr-x[-rw-r--r--]src/lib/netlist/plib/pchrono.h42
-rw-r--r--src/lib/netlist/plib/pconfig.h7
-rw-r--r--src/lib/netlist/plib/pexception.cpp6
-rw-r--r--src/lib/netlist/plib/pexception.h4
-rw-r--r--src/lib/netlist/plib/pfmtlog.cpp7
-rw-r--r--src/lib/netlist/plib/pfmtlog.h27
-rw-r--r--src/lib/netlist/plib/pfunction.cpp133
-rw-r--r--src/lib/netlist/plib/pfunction.h25
-rw-r--r--src/lib/netlist/plib/pgsl.h35
-rwxr-xr-xsrc/lib/netlist/plib/plists.h43
-rw-r--r--src/lib/netlist/plib/pmath.h104
-rwxr-xr-xsrc/lib/netlist/plib/pmatrix2d.h11
-rw-r--r--src/lib/netlist/plib/pmatrix_cr.h (renamed from src/lib/netlist/plib/mat_cr.h)208
-rw-r--r--src/lib/netlist/plib/pmempool.h5
-rw-r--r--src/lib/netlist/plib/pmulti_threading.h11
-rw-r--r--src/lib/netlist/plib/poptions.h10
-rw-r--r--src/lib/netlist/plib/ppmf.h2
-rw-r--r--src/lib/netlist/plib/ppreprocessor.cpp6
-rw-r--r--src/lib/netlist/plib/prandom.h8
-rw-r--r--src/lib/netlist/plib/pstream.h10
-rw-r--r--src/lib/netlist/plib/pstring.h24
-rw-r--r--src/lib/netlist/plib/ptests.h8
-rw-r--r--src/lib/netlist/plib/ptime.h22
-rw-r--r--src/lib/netlist/plib/ptimed_queue.h85
-rw-r--r--src/lib/netlist/plib/vector_ops.h73
-rw-r--r--src/lib/netlist/prg/nltool.cpp8
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.cpp16
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.h4
-rw-r--r--src/lib/netlist/solver/nld_ms_gcr.h13
-rw-r--r--src/lib/netlist/solver/nld_ms_gmres.h4
-rw-r--r--src/lib/netlist/solver/nld_solver.cpp91
-rw-r--r--src/lib/netlist/tests/test_pfunction.cpp7
-rw-r--r--src/lib/util/avhuff.cpp23
-rw-r--r--src/lib/util/avhuff.h64
-rw-r--r--src/lib/util/aviio.cpp16
-rw-r--r--src/lib/util/bitmap.cpp104
-rw-r--r--src/lib/util/bitmap.h79
-rw-r--r--src/lib/util/chdcodec.cpp2
-rw-r--r--src/lib/util/corealloc.h40
-rw-r--r--src/lib/util/coretmpl.h6
-rw-r--r--src/lib/util/msdib.cpp642
-rw-r--r--src/lib/util/msdib.h46
-rw-r--r--src/lib/util/nanosvg.cpp6
-rw-r--r--src/lib/util/nanosvg.h33
-rw-r--r--src/lib/util/png.cpp271
-rw-r--r--src/lib/util/png.h42
-rw-r--r--src/lib/util/xmlfile.cpp9
-rw-r--r--src/mame/arcade.flt1
-rw-r--r--src/mame/audio/arcadia.cpp19
-rw-r--r--src/mame/audio/arcadia.h2
-rw-r--r--src/mame/audio/channelf.cpp17
-rw-r--r--src/mame/audio/channelf.h2
-rw-r--r--src/mame/audio/cinemat.cpp76
-rw-r--r--src/mame/audio/cinemat.h13
-rw-r--r--src/mame/audio/cmi01a.cpp16
-rw-r--r--src/mame/audio/cmi01a.h2
-rw-r--r--src/mame/audio/cps3.cpp16
-rw-r--r--src/mame/audio/cps3.h2
-rw-r--r--src/mame/audio/dai_snd.cpp16
-rw-r--r--src/mame/audio/dai_snd.h2
-rw-r--r--src/mame/audio/dsbz80.cpp32
-rw-r--r--src/mame/audio/dsbz80.h2
-rw-r--r--src/mame/audio/elan_eu3a05.cpp11
-rw-r--r--src/mame/audio/elan_eu3a05.h2
-rw-r--r--src/mame/audio/exidy.cpp66
-rw-r--r--src/mame/audio/exidy.h16
-rw-r--r--src/mame/audio/exidy440.cpp45
-rw-r--r--src/mame/audio/exidy440.h8
-rw-r--r--src/mame/audio/flower.cpp26
-rw-r--r--src/mame/audio/flower.h6
-rw-r--r--src/mame/audio/geebee.cpp14
-rw-r--r--src/mame/audio/geebee.h2
-rw-r--r--src/mame/audio/gomoku.cpp59
-rw-r--r--src/mame/audio/gomoku.h7
-rw-r--r--src/mame/audio/gottlieb.cpp2
-rw-r--r--src/mame/audio/gridlee.cpp12
-rw-r--r--src/mame/audio/hyprolyb.cpp11
-rw-r--r--src/mame/audio/hyprolyb.h5
-rw-r--r--src/mame/audio/lynx.cpp40
-rw-r--r--src/mame/audio/lynx.h4
-rw-r--r--src/mame/audio/micro3d.cpp38
-rw-r--r--src/mame/audio/micro3d.h6
-rw-r--r--src/mame/audio/nl_armora.cpp2
-rw-r--r--src/mame/audio/nl_astrob.cpp113
-rw-r--r--src/mame/audio/nl_barrier.cpp6
-rw-r--r--src/mame/audio/nl_boxingb.cpp16
-rw-r--r--src/mame/audio/nl_brdrline.cpp1721
-rw-r--r--src/mame/audio/nl_brdrline.h11
-rw-r--r--src/mame/audio/nl_frogs.cpp567
-rw-r--r--src/mame/audio/nl_frogs.h10
-rw-r--r--src/mame/audio/nl_ripoff.cpp6
-rw-r--r--src/mame/audio/nl_solarq.cpp2
-rw-r--r--src/mame/audio/nl_spacewar.cpp6
-rw-r--r--src/mame/audio/nl_starcas.cpp4
-rw-r--r--src/mame/audio/nl_tailg.cpp4
-rw-r--r--src/mame/audio/nl_warrior.cpp2
-rw-r--r--src/mame/audio/phoenix.cpp15
-rw-r--r--src/mame/audio/phoenix.h4
-rw-r--r--src/mame/audio/pleiads.cpp22
-rw-r--r--src/mame/audio/pleiads.h6
-rw-r--r--src/mame/audio/polepos.cpp16
-rw-r--r--src/mame/audio/polepos.h2
-rw-r--r--src/mame/audio/redbaron.cpp12
-rw-r--r--src/mame/audio/redbaron.h2
-rw-r--r--src/mame/audio/s11c_bg.cpp67
-rw-r--r--src/mame/audio/s11c_bg.h4
-rw-r--r--src/mame/audio/segag80r.cpp10
-rw-r--r--src/mame/audio/segausb.cpp12
-rw-r--r--src/mame/audio/segausb.h2
-rw-r--r--src/mame/audio/seibu.cpp20
-rw-r--r--src/mame/audio/seibu.h2
-rw-r--r--src/mame/audio/sente6vb.cpp54
-rw-r--r--src/mame/audio/snk6502.cpp12
-rw-r--r--src/mame/audio/snk6502.h2
-rw-r--r--src/mame/audio/socrates.cpp10
-rw-r--r--src/mame/audio/socrates.h2
-rw-r--r--src/mame/audio/special.cpp35
-rw-r--r--src/mame/audio/special.h2
-rw-r--r--src/mame/audio/svis_snd.cpp29
-rw-r--r--src/mame/audio/svis_snd.h2
-rw-r--r--src/mame/audio/tiamc1.cpp10
-rw-r--r--src/mame/audio/tiamc1.h2
-rw-r--r--src/mame/audio/timeplt.cpp11
-rw-r--r--src/mame/audio/timeplt.h5
-rw-r--r--src/mame/audio/trackfld.cpp11
-rw-r--r--src/mame/audio/trackfld.h5
-rw-r--r--src/mame/audio/tranqgun.cpp150
-rw-r--r--src/mame/audio/turrett.cpp19
-rw-r--r--src/mame/audio/tvc.cpp16
-rw-r--r--src/mame/audio/tvc.h2
-rw-r--r--src/mame/audio/tx1.cpp42
-rw-r--r--src/mame/audio/tx1.h10
-rw-r--r--src/mame/audio/vboy.cpp21
-rw-r--r--src/mame/audio/vboy.h2
-rw-r--r--src/mame/audio/vc4000.cpp16
-rw-r--r--src/mame/audio/vc4000.h2
-rw-r--r--src/mame/audio/vicdual.cpp387
-rw-r--r--src/mame/audio/vicdual.h49
-rw-r--r--src/mame/audio/warpwarp.cpp14
-rw-r--r--src/mame/audio/warpwarp.h2
-rw-r--r--src/mame/audio/williams.cpp8
-rw-r--r--src/mame/audio/williams.h1
-rw-r--r--src/mame/audio/wiping.cpp54
-rw-r--r--src/mame/audio/wiping.h7
-rw-r--r--src/mame/audio/wswan.cpp21
-rw-r--r--src/mame/audio/wswan.h2
-rw-r--r--src/mame/audio/xavix.cpp11
-rw-r--r--src/mame/drivers/1945kiii.cpp4
-rw-r--r--src/mame/drivers/5clown.cpp2
-rw-r--r--src/mame/drivers/8080bw.cpp8
-rw-r--r--src/mame/drivers/a5105.cpp4
-rw-r--r--src/mame/drivers/a7150.cpp9
-rw-r--r--src/mame/drivers/abc1600.cpp28
-rw-r--r--src/mame/drivers/ac1.cpp4
-rw-r--r--src/mame/drivers/accomm.cpp2
-rw-r--r--src/mame/drivers/acefruit.cpp23
-rw-r--r--src/mame/drivers/adacp150.cpp229
-rw-r--r--src/mame/drivers/adm11.cpp2
-rw-r--r--src/mame/drivers/aleck64.cpp28
-rw-r--r--src/mame/drivers/alesis.cpp2
-rw-r--r--src/mame/drivers/alfaskop41xx.cpp8
-rw-r--r--src/mame/drivers/alg.cpp1
-rw-r--r--src/mame/drivers/alinvade.cpp14
-rw-r--r--src/mame/drivers/alphajuno.cpp2
-rw-r--r--src/mame/drivers/alphatpx.cpp52
-rw-r--r--src/mame/drivers/alphatro.cpp23
-rw-r--r--src/mame/drivers/amust.cpp39
-rw-r--r--src/mame/drivers/apc.cpp61
-rw-r--r--src/mame/drivers/apf.cpp10
-rw-r--r--src/mame/drivers/apogee.cpp4
-rw-r--r--src/mame/drivers/apple1.cpp17
-rw-r--r--src/mame/drivers/apple2.cpp26
-rw-r--r--src/mame/drivers/apple2e.cpp130
-rw-r--r--src/mame/drivers/apple2gs.cpp31
-rw-r--r--src/mame/drivers/apple3.cpp7
-rw-r--r--src/mame/drivers/applix.cpp98
-rw-r--r--src/mame/drivers/apricot.cpp4
-rw-r--r--src/mame/drivers/apricotf.cpp6
-rw-r--r--src/mame/drivers/apricotp.cpp2
-rw-r--r--src/mame/drivers/argo.cpp2
-rw-r--r--src/mame/drivers/aristmk4.cpp38
-rw-r--r--src/mame/drivers/aristmk6.cpp8
-rw-r--r--src/mame/drivers/astinvad.cpp16
-rw-r--r--src/mame/drivers/astrof.cpp121
-rw-r--r--src/mame/drivers/at.cpp2
-rw-r--r--src/mame/drivers/atarisy4.cpp12
-rw-r--r--src/mame/drivers/atom.cpp58
-rw-r--r--src/mame/drivers/atronic.cpp4
-rw-r--r--src/mame/drivers/att4425.cpp27
-rw-r--r--src/mame/drivers/att630.cpp2
-rw-r--r--src/mame/drivers/attache.cpp68
-rw-r--r--src/mame/drivers/avalnche.cpp16
-rw-r--r--src/mame/drivers/b16.cpp9
-rw-r--r--src/mame/drivers/bagman.cpp251
-rw-r--r--src/mame/drivers/banctec.cpp14
-rw-r--r--src/mame/drivers/bbc.cpp171
-rw-r--r--src/mame/drivers/bcs3.cpp42
-rw-r--r--src/mame/drivers/beaminv.cpp14
-rw-r--r--src/mame/drivers/beezer.cpp6
-rw-r--r--src/mame/drivers/berzerk.cpp16
-rw-r--r--src/mame/drivers/bfcobra.cpp47
-rw-r--r--src/mame/drivers/bigbord2.cpp16
-rw-r--r--src/mame/drivers/bingor.cpp21
-rw-r--r--src/mame/drivers/bitgraph.cpp11
-rw-r--r--src/mame/drivers/blitz68k.cpp55
-rw-r--r--src/mame/drivers/blw700i.cpp33
-rw-r--r--src/mame/drivers/bmcbowl.cpp25
-rw-r--r--src/mame/drivers/bmcpokr.cpp24
-rw-r--r--src/mame/drivers/bmjr.cpp18
-rw-r--r--src/mame/drivers/bml3.cpp199
-rw-r--r--src/mame/drivers/bw12.cpp17
-rw-r--r--src/mame/drivers/bw2.cpp4
-rw-r--r--src/mame/drivers/by17.cpp5
-rw-r--r--src/mame/drivers/by35.cpp5
-rw-r--r--src/mame/drivers/c10.cpp17
-rw-r--r--src/mame/drivers/c128.cpp2
-rw-r--r--src/mame/drivers/c65.cpp2
-rw-r--r--src/mame/drivers/calcune.cpp2
-rw-r--r--src/mame/drivers/camplynx.cpp31
-rw-r--r--src/mame/drivers/candela.cpp2
-rw-r--r--src/mame/drivers/canon_s80.cpp2
-rw-r--r--src/mame/drivers/cardline.cpp4
-rw-r--r--src/mame/drivers/casloopy.cpp15
-rw-r--r--src/mame/drivers/cat.cpp4
-rw-r--r--src/mame/drivers/cave.cpp107
-rw-r--r--src/mame/drivers/cbm2.cpp14
-rw-r--r--src/mame/drivers/cc40.cpp2
-rw-r--r--src/mame/drivers/cd2650.cpp17
-rw-r--r--src/mame/drivers/cdc721.cpp19
-rw-r--r--src/mame/drivers/cdi.cpp2
-rw-r--r--src/mame/drivers/ceres.cpp283
-rw-r--r--src/mame/drivers/cesclass.cpp20
-rw-r--r--src/mame/drivers/cfx9850.cpp2
-rw-r--r--src/mame/drivers/cgang.cpp12
-rw-r--r--src/mame/drivers/cgenie.cpp10
-rw-r--r--src/mame/drivers/champbas.cpp38
-rw-r--r--src/mame/drivers/chihiro.cpp2
-rw-r--r--src/mame/drivers/cinemat.cpp89
-rw-r--r--src/mame/drivers/cit101.cpp2
-rw-r--r--src/mame/drivers/cit220.cpp2
-rw-r--r--src/mame/drivers/clayshoo.cpp2
-rw-r--r--src/mame/drivers/clcd.cpp94
-rw-r--r--src/mame/drivers/clickstart.cpp2
-rw-r--r--src/mame/drivers/cliffhgr.cpp1
-rw-r--r--src/mame/drivers/cmi.cpp18
-rw-r--r--src/mame/drivers/cobra.cpp34
-rw-r--r--src/mame/drivers/cocoloco.cpp2
-rw-r--r--src/mame/drivers/compucolor.cpp6
-rw-r--r--src/mame/drivers/comx35.cpp14
-rw-r--r--src/mame/drivers/consola_emt.cpp2
-rw-r--r--src/mame/drivers/coolpool.cpp18
-rw-r--r--src/mame/drivers/coolridr.cpp37
-rw-r--r--src/mame/drivers/corona.cpp16
-rw-r--r--src/mame/drivers/cowtipping.cpp113
-rw-r--r--src/mame/drivers/cps1bl_5205.cpp6
-rw-r--r--src/mame/drivers/cps1bl_pic.cpp2
-rw-r--r--src/mame/drivers/cps3.cpp24
-rw-r--r--src/mame/drivers/crvision.cpp1
-rw-r--r--src/mame/drivers/cubeqst.cpp17
-rw-r--r--src/mame/drivers/cupidon.cpp20
-rw-r--r--src/mame/drivers/cxhumax.cpp19
-rw-r--r--src/mame/drivers/cybertnk.cpp2
-rw-r--r--src/mame/drivers/cz101.cpp2
-rw-r--r--src/mame/drivers/d6800.cpp107
-rw-r--r--src/mame/drivers/dai.cpp2
-rw-r--r--src/mame/drivers/dai3wksi.cpp4
-rw-r--r--src/mame/drivers/darius.cpp4
-rw-r--r--src/mame/drivers/ddenlovr.cpp17
-rw-r--r--src/mame/drivers/dec0.cpp19
-rw-r--r--src/mame/drivers/dec8.cpp8
-rw-r--r--src/mame/drivers/deco_mlc.cpp162
-rw-r--r--src/mame/drivers/decstation.cpp13
-rw-r--r--src/mame/drivers/decwritr.cpp2
-rw-r--r--src/mame/drivers/destroyr.cpp2
-rw-r--r--src/mame/drivers/dgpix.cpp4
-rw-r--r--src/mame/drivers/dim68k.cpp10
-rw-r--r--src/mame/drivers/dkmb.cpp4
-rw-r--r--src/mame/drivers/dlair.cpp1
-rw-r--r--src/mame/drivers/dmv.cpp19
-rw-r--r--src/mame/drivers/dolphunk.cpp130
-rw-r--r--src/mame/drivers/dooyong.cpp6
-rw-r--r--src/mame/drivers/dorachan.cpp5
-rw-r--r--src/mame/drivers/dotrikun.cpp2
-rw-r--r--src/mame/drivers/dpb7000.cpp22
-rw-r--r--src/mame/drivers/dragon.cpp9
-rw-r--r--src/mame/drivers/drdmania.cpp125
-rw-r--r--src/mame/drivers/duet16.cpp7
-rw-r--r--src/mame/drivers/dvk_kcgd.cpp6
-rw-r--r--src/mame/drivers/dvk_ksm.cpp4
-rw-r--r--src/mame/drivers/dwarfd.cpp18
-rw-r--r--src/mame/drivers/e100.cpp2
-rw-r--r--src/mame/drivers/ec65.cpp16
-rw-r--r--src/mame/drivers/elan_eu3a05.cpp4
-rw-r--r--src/mame/drivers/electron.cpp2
-rw-r--r--src/mame/drivers/elekscmp.cpp7
-rw-r--r--src/mame/drivers/elwro800.cpp48
-rw-r--r--src/mame/drivers/embargo.cpp16
-rw-r--r--src/mame/drivers/emu3.cpp13
-rw-r--r--src/mame/drivers/emu68k.cpp2
-rw-r--r--src/mame/drivers/enigma2.cpp4
-rw-r--r--src/mame/drivers/eolith16.cpp2
-rw-r--r--src/mame/drivers/epic14e.cpp2
-rw-r--r--src/mame/drivers/esh.cpp2
-rw-r--r--src/mame/drivers/esprit.cpp4
-rw-r--r--src/mame/drivers/esq1.cpp14
-rw-r--r--src/mame/drivers/eurit.cpp2
-rw-r--r--src/mame/drivers/eurocom2.cpp15
-rw-r--r--src/mame/drivers/excali64.cpp21
-rw-r--r--src/mame/drivers/expro02.cpp4
-rw-r--r--src/mame/drivers/f-32.cpp8
-rw-r--r--src/mame/drivers/facit4440.cpp2
-rw-r--r--src/mame/drivers/falco5220.cpp2
-rw-r--r--src/mame/drivers/fanucspmg.cpp46
-rw-r--r--src/mame/drivers/fb01.cpp2
-rw-r--r--src/mame/drivers/fc100.cpp70
-rw-r--r--src/mame/drivers/fk1.cpp14
-rw-r--r--src/mame/drivers/flipjack.cpp4
-rw-r--r--src/mame/drivers/flyball.cpp2
-rw-r--r--src/mame/drivers/fm7.cpp4
-rw-r--r--src/mame/drivers/fmtowns.cpp176
-rw-r--r--src/mame/drivers/fp1100.cpp2
-rw-r--r--src/mame/drivers/fp200.cpp32
-rw-r--r--src/mame/drivers/fp6000.cpp30
-rw-r--r--src/mame/drivers/fs3216.cpp4
-rw-r--r--src/mame/drivers/gaelco.cpp204
-rw-r--r--src/mame/drivers/gaelco2.cpp158
-rw-r--r--src/mame/drivers/galaga.cpp8
-rw-r--r--src/mame/drivers/galaxian.cpp73
-rw-r--r--src/mame/drivers/galgame.cpp2
-rw-r--r--src/mame/drivers/galpani3.cpp207
-rw-r--r--src/mame/drivers/galpanic_ms.cpp4
-rw-r--r--src/mame/drivers/gamecstl.cpp17
-rw-r--r--src/mame/drivers/gameking.cpp42
-rw-r--r--src/mame/drivers/gei.cpp2
-rw-r--r--src/mame/drivers/generalplus_gpl16250_rom.cpp11
-rw-r--r--src/mame/drivers/generalplus_gpl162xx_lcdtype.cpp886
-rw-r--r--src/mame/drivers/generalplus_gpl32612.cpp93
-rw-r--r--src/mame/drivers/generalplus_gpl_unknown.cpp1116
-rw-r--r--src/mame/drivers/geniusiq.cpp4
-rw-r--r--src/mame/drivers/gigatron.cpp6
-rw-r--r--src/mame/drivers/ginganin.cpp8
-rw-r--r--src/mame/drivers/gkigt.cpp12
-rw-r--r--src/mame/drivers/gmaster.cpp34
-rw-r--r--src/mame/drivers/goldart.cpp6
-rw-r--r--src/mame/drivers/goldngam.cpp4
-rw-r--r--src/mame/drivers/goupil.cpp2
-rw-r--r--src/mame/drivers/gp2x.cpp11
-rw-r--r--src/mame/drivers/gp32.cpp55
-rw-r--r--src/mame/drivers/gpworld.cpp2
-rw-r--r--src/mame/drivers/grfd2301.cpp15
-rw-r--r--src/mame/drivers/gridcomp.cpp13
-rw-r--r--src/mame/drivers/gstream.cpp18
-rw-r--r--src/mame/drivers/gsword.cpp16
-rw-r--r--src/mame/drivers/gticlub.cpp2
-rw-r--r--src/mame/drivers/gts1.cpp10
-rw-r--r--src/mame/drivers/gts3a.cpp9
-rw-r--r--src/mame/drivers/gts80a.cpp8
-rw-r--r--src/mame/drivers/guab.cpp6
-rw-r--r--src/mame/drivers/gunpey.cpp54
-rw-r--r--src/mame/drivers/h01x.cpp2
-rw-r--r--src/mame/drivers/h19.cpp13
-rw-r--r--src/mame/drivers/halleys.cpp14
-rw-r--r--src/mame/drivers/hazeltin.cpp5
-rw-r--r--src/mame/drivers/hec2hrp.cpp106
-rw-r--r--src/mame/drivers/hektor.cpp16
-rw-r--r--src/mame/drivers/hh_amis2k.cpp8
-rw-r--r--src/mame/drivers/hh_cop400.cpp14
-rw-r--r--src/mame/drivers/hh_hmcs40.cpp10
-rw-r--r--src/mame/drivers/hh_pic16.cpp6
-rw-r--r--src/mame/drivers/hh_sm510.cpp2
-rw-r--r--src/mame/drivers/hh_tms1k.cpp27
-rw-r--r--src/mame/drivers/hh_ucom4.cpp6
-rw-r--r--src/mame/drivers/hhtiger.cpp16
-rw-r--r--src/mame/drivers/highvdeo.cpp24
-rw-r--r--src/mame/drivers/hitme.cpp10
-rw-r--r--src/mame/drivers/homelab.cpp15
-rw-r--r--src/mame/drivers/homez80.cpp15
-rw-r--r--src/mame/drivers/hotblock.cpp2
-rw-r--r--src/mame/drivers/hotstuff.cpp11
-rw-r--r--src/mame/drivers/hp16500.cpp16
-rw-r--r--src/mame/drivers/hp2640.cpp4
-rw-r--r--src/mame/drivers/hp64k.cpp16
-rw-r--r--src/mame/drivers/hp80.cpp36
-rw-r--r--src/mame/drivers/hp95lx.cpp28
-rw-r--r--src/mame/drivers/hp9845.cpp36
-rw-r--r--src/mame/drivers/hp9k.cpp5
-rw-r--r--src/mame/drivers/hprot1.cpp4
-rw-r--r--src/mame/drivers/huebler.cpp21
-rw-r--r--src/mame/drivers/hunter16.cpp6
-rw-r--r--src/mame/drivers/husky.cpp14
-rw-r--r--src/mame/drivers/ibm6580.cpp38
-rw-r--r--src/mame/drivers/ibmpcjr.cpp3
-rw-r--r--src/mame/drivers/icatel.cpp4
-rw-r--r--src/mame/drivers/if800.cpp13
-rw-r--r--src/mame/drivers/igs011.cpp4
-rw-r--r--src/mame/drivers/igs017.cpp350
-rw-r--r--src/mame/drivers/imolagp.cpp2
-rw-r--r--src/mame/drivers/informer_207_100.cpp49
-rw-r--r--src/mame/drivers/informer_207_376.cpp30
-rw-r--r--src/mame/drivers/informer_213.cpp307
-rw-r--r--src/mame/drivers/instruct.cpp20
-rw-r--r--src/mame/drivers/invqix.cpp36
-rw-r--r--src/mame/drivers/ipds.cpp7
-rw-r--r--src/mame/drivers/irisha.cpp12
-rw-r--r--src/mame/drivers/istellar.cpp1
-rw-r--r--src/mame/drivers/istrebiteli.cpp12
-rw-r--r--src/mame/drivers/itgambl2.cpp2
-rw-r--r--src/mame/drivers/itgambl3.cpp15
-rw-r--r--src/mame/drivers/itt1700.cpp2
-rw-r--r--src/mame/drivers/jangou.cpp2
-rw-r--r--src/mame/drivers/jantotsu.cpp19
-rw-r--r--src/mame/drivers/jchan.cpp8
-rw-r--r--src/mame/drivers/jollyjgr.cpp10
-rw-r--r--src/mame/drivers/jongkyo.cpp25
-rw-r--r--src/mame/drivers/jonos.cpp16
-rw-r--r--src/mame/drivers/joystand.cpp4
-rw-r--r--src/mame/drivers/jpmsys5.cpp12
-rw-r--r--src/mame/drivers/jr100.cpp25
-rw-r--r--src/mame/drivers/jr200.cpp15
-rw-r--r--src/mame/drivers/jtc.cpp26
-rw-r--r--src/mame/drivers/juku.cpp2
-rw-r--r--src/mame/drivers/jupace.cpp16
-rw-r--r--src/mame/drivers/jupiter.cpp15
-rw-r--r--src/mame/drivers/k8915.cpp15
-rw-r--r--src/mame/drivers/karnov.cpp211
-rw-r--r--src/mame/drivers/kaypro.cpp46
-rw-r--r--src/mame/drivers/kdt6.cpp6
-rw-r--r--src/mame/drivers/kim1.cpp13
-rw-r--r--src/mame/drivers/kinst.cpp8
-rw-r--r--src/mame/drivers/konamigs.cpp2
-rw-r--r--src/mame/drivers/konamigv.cpp57
-rw-r--r--src/mame/drivers/konmedal68k.cpp10
-rw-r--r--src/mame/drivers/kontest.cpp29
-rw-r--r--src/mame/drivers/korgds8.cpp4
-rw-r--r--src/mame/drivers/korgdss1.cpp11
-rw-r--r--src/mame/drivers/korgm1.cpp2
-rw-r--r--src/mame/drivers/krokha.cpp17
-rw-r--r--src/mame/drivers/kron.cpp16
-rw-r--r--src/mame/drivers/laser3k.cpp101
-rw-r--r--src/mame/drivers/laserbas.cpp4
-rw-r--r--src/mame/drivers/lastfght.cpp23
-rw-r--r--src/mame/drivers/lbeach.cpp4
-rw-r--r--src/mame/drivers/lcmate2.cpp19
-rw-r--r--src/mame/drivers/lft_craft.cpp2
-rw-r--r--src/mame/drivers/lft_phasor.cpp2
-rw-r--r--src/mame/drivers/lgp.cpp1
-rw-r--r--src/mame/drivers/limenko.cpp14
-rw-r--r--src/mame/drivers/llc1.cpp17
-rw-r--r--src/mame/drivers/llc2.cpp21
-rw-r--r--src/mame/drivers/lola8a.cpp12
-rw-r--r--src/mame/drivers/lviv.cpp4
-rw-r--r--src/mame/drivers/m14.cpp22
-rw-r--r--src/mame/drivers/m20.cpp9
-rw-r--r--src/mame/drivers/m3.cpp16
-rw-r--r--src/mame/drivers/m5.cpp2
-rw-r--r--src/mame/drivers/m72.cpp16
-rw-r--r--src/mame/drivers/m79152pc.cpp6
-rw-r--r--src/mame/drivers/m79amb.cpp10
-rw-r--r--src/mame/drivers/m92.cpp90
-rw-r--r--src/mame/drivers/mac.cpp88
-rw-r--r--src/mame/drivers/mac128.cpp291
-rw-r--r--src/mame/drivers/macquadra700.cpp936
-rw-r--r--src/mame/drivers/macrossp.cpp1
-rw-r--r--src/mame/drivers/magicard.cpp25
-rw-r--r--src/mame/drivers/marinedt.cpp12
-rw-r--r--src/mame/drivers/maygayv1.cpp14
-rw-r--r--src/mame/drivers/mbc200.cpp12
-rw-r--r--src/mame/drivers/mbee.cpp20
-rw-r--r--src/mame/drivers/mc8020.cpp46
-rw-r--r--src/mame/drivers/mc8030.cpp33
-rw-r--r--src/mame/drivers/mdt60.cpp2
-rw-r--r--src/mame/drivers/mediagx.cpp76
-rw-r--r--src/mame/drivers/megadriv_rad.cpp8
-rw-r--r--src/mame/drivers/megaplay.cpp6
-rw-r--r--src/mame/drivers/megatech.cpp4
-rw-r--r--src/mame/drivers/meijinsn.cpp2
-rw-r--r--src/mame/drivers/mekd2.cpp23
-rw-r--r--src/mame/drivers/mekd3.cpp55
-rw-r--r--src/mame/drivers/mekd4.cpp48
-rw-r--r--src/mame/drivers/merit.cpp15
-rw-r--r--src/mame/drivers/meritum.cpp52
-rw-r--r--src/mame/drivers/mes.cpp15
-rw-r--r--src/mame/drivers/metalmx.cpp2
-rw-r--r--src/mame/drivers/meyc8080.cpp18
-rw-r--r--src/mame/drivers/meyc8088.cpp2
-rw-r--r--src/mame/drivers/micral.cpp15
-rw-r--r--src/mame/drivers/microb.cpp12
-rw-r--r--src/mame/drivers/microtan.cpp4
-rw-r--r--src/mame/drivers/microterm_f8.cpp2
-rw-r--r--src/mame/drivers/microvsn.cpp2
-rw-r--r--src/mame/drivers/mikro80.cpp2
-rw-r--r--src/mame/drivers/mikromik.cpp2
-rw-r--r--src/mame/drivers/mikrosha.cpp2
-rw-r--r--src/mame/drivers/milton6805.cpp23
-rw-r--r--src/mame/drivers/mindset.cpp44
-rw-r--r--src/mame/drivers/miniboy7.cpp6
-rw-r--r--src/mame/drivers/minivadr.cpp16
-rw-r--r--src/mame/drivers/missile.cpp17
-rw-r--r--src/mame/drivers/mjsenpu.cpp26
-rw-r--r--src/mame/drivers/mjsister.cpp8
-rw-r--r--src/mame/drivers/ml20.cpp2
-rw-r--r--src/mame/drivers/mlanding.cpp6
-rw-r--r--src/mame/drivers/mmagic.cpp18
-rw-r--r--src/mame/drivers/modellot.cpp16
-rw-r--r--src/mame/drivers/monty.cpp2
-rw-r--r--src/mame/drivers/monzagp.cpp4
-rw-r--r--src/mame/drivers/mpu4plasma.cpp26
-rw-r--r--src/mame/drivers/mpu4vid.cpp43
-rw-r--r--src/mame/drivers/ms0515.cpp21
-rw-r--r--src/mame/drivers/ms6102.cpp4
-rw-r--r--src/mame/drivers/msisaac.cpp10
-rw-r--r--src/mame/drivers/mstation.cpp4
-rw-r--r--src/mame/drivers/mtd1256.cpp4
-rw-r--r--src/mame/drivers/multi16.cpp4
-rw-r--r--src/mame/drivers/multi8.cpp31
-rw-r--r--src/mame/drivers/mx2178.cpp14
-rw-r--r--src/mame/drivers/myb3k.cpp10
-rw-r--r--src/mame/drivers/mycom.cpp27
-rw-r--r--src/mame/drivers/mz2000.cpp22
-rw-r--r--src/mame/drivers/mz2500.cpp157
-rw-r--r--src/mame/drivers/mz3500.cpp42
-rw-r--r--src/mame/drivers/mz6500.cpp15
-rw-r--r--src/mame/drivers/nakajies.cpp2
-rw-r--r--src/mame/drivers/namcos10.cpp78
-rw-r--r--src/mame/drivers/namcos12.cpp12
-rw-r--r--src/mame/drivers/namcos21.cpp19
-rw-r--r--src/mame/drivers/namcos23.cpp14
-rw-r--r--src/mame/drivers/nanos.cpp10
-rw-r--r--src/mame/drivers/naomi.cpp26
-rw-r--r--src/mame/drivers/nc.cpp11
-rw-r--r--src/mame/drivers/ncd68k.cpp6
-rw-r--r--src/mame/drivers/nes_sh6578.cpp37
-rw-r--r--src/mame/drivers/nes_vt.cpp465
-rw-r--r--src/mame/drivers/newton.cpp15
-rw-r--r--src/mame/drivers/nexus3d.cpp8
-rw-r--r--src/mame/drivers/nforcepc.cpp26
-rw-r--r--src/mame/drivers/ngen.cpp4
-rw-r--r--src/mame/drivers/nightgal.cpp8
-rw-r--r--src/mame/drivers/nightmare.cpp10
-rw-r--r--src/mame/drivers/ninjaw.cpp8
-rw-r--r--src/mame/drivers/nmg5.cpp6
-rw-r--r--src/mame/drivers/nmk16.cpp58
-rw-r--r--src/mame/drivers/nokia_3310.cpp2
-rw-r--r--src/mame/drivers/notetaker.cpp41
-rw-r--r--src/mame/drivers/novag_diablo.cpp2
-rw-r--r--src/mame/drivers/novag_sexpert.cpp2
-rw-r--r--src/mame/drivers/nyny.cpp6
-rw-r--r--src/mame/drivers/octopus.cpp2
-rw-r--r--src/mame/drivers/odyssey.cpp4
-rw-r--r--src/mame/drivers/odyssey2.cpp202
-rw-r--r--src/mame/drivers/okean240.cpp13
-rw-r--r--src/mame/drivers/olyboss.cpp7
-rw-r--r--src/mame/drivers/ondra.cpp13
-rw-r--r--src/mame/drivers/orao.cpp2
-rw-r--r--src/mame/drivers/oric.cpp2
-rw-r--r--src/mame/drivers/osbexec.cpp2
-rw-r--r--src/mame/drivers/osi.cpp71
-rw-r--r--src/mame/drivers/othello.cpp6
-rw-r--r--src/mame/drivers/p2000t.cpp16
-rw-r--r--src/mame/drivers/pacman.cpp136
-rw-r--r--src/mame/drivers/panicr.cpp14
-rw-r--r--src/mame/drivers/partner.cpp12
-rw-r--r--src/mame/drivers/pasha2.cpp21
-rw-r--r--src/mame/drivers/paso1600.cpp40
-rw-r--r--src/mame/drivers/pasogo.cpp29
-rw-r--r--src/mame/drivers/pasopia.cpp4
-rw-r--r--src/mame/drivers/pasopia7.cpp32
-rw-r--r--src/mame/drivers/pc100.cpp27
-rw-r--r--src/mame/drivers/pc1500.cpp4
-rw-r--r--src/mame/drivers/pc1512.cpp8
-rw-r--r--src/mame/drivers/pc2000.cpp8
-rw-r--r--src/mame/drivers/pc4.cpp31
-rw-r--r--src/mame/drivers/pc8001.cpp41
-rw-r--r--src/mame/drivers/pc8801.cpp169
-rw-r--r--src/mame/drivers/pc88va.cpp108
-rw-r--r--src/mame/drivers/pc9801.cpp7
-rw-r--r--src/mame/drivers/pce220.cpp6
-rw-r--r--src/mame/drivers/pcm.cpp15
-rw-r--r--src/mame/drivers/pcw.cpp8
-rw-r--r--src/mame/drivers/pcxt.cpp21
-rw-r--r--src/mame/drivers/pda600.cpp2
-rw-r--r--src/mame/drivers/pdp1.cpp7
-rw-r--r--src/mame/drivers/pdp11.cpp14
-rw-r--r--src/mame/drivers/pegasus.cpp19
-rw-r--r--src/mame/drivers/peoplepc.cpp13
-rw-r--r--src/mame/drivers/pet.cpp36
-rw-r--r--src/mame/drivers/pg685.cpp50
-rw-r--r--src/mame/drivers/pgm2.cpp2
-rw-r--r--src/mame/drivers/phc25.cpp4
-rw-r--r--src/mame/drivers/photon2.cpp54
-rw-r--r--src/mame/drivers/photoply.cpp2
-rw-r--r--src/mame/drivers/phunsy.cpp14
-rw-r--r--src/mame/drivers/piggypas.cpp2
-rw-r--r--src/mame/drivers/pinball2k.cpp52
-rw-r--r--src/mame/drivers/plan80.cpp19
-rw-r--r--src/mame/drivers/pmd85.cpp12
-rw-r--r--src/mame/drivers/pmi80.cpp53
-rw-r--r--src/mame/drivers/pockstat.cpp2
-rw-r--r--src/mame/drivers/poisk1.cpp40
-rw-r--r--src/mame/drivers/pokemini.cpp46
-rw-r--r--src/mame/drivers/popobear.cpp2
-rw-r--r--src/mame/drivers/pp.cpp4
-rw-r--r--src/mame/drivers/prestige.cpp2
-rw-r--r--src/mame/drivers/primo.cpp2
-rw-r--r--src/mame/drivers/prof80.cpp14
-rw-r--r--src/mame/drivers/progolf.cpp26
-rw-r--r--src/mame/drivers/proteus3.cpp18
-rw-r--r--src/mame/drivers/ps2sony.cpp6
-rw-r--r--src/mame/drivers/psikyo.cpp12
-rw-r--r--src/mame/drivers/psion.cpp4
-rw-r--r--src/mame/drivers/psion5.cpp54
-rw-r--r--src/mame/drivers/ptcsol.cpp29
-rw-r--r--src/mame/drivers/pv1000.cpp19
-rw-r--r--src/mame/drivers/px4.cpp24
-rw-r--r--src/mame/drivers/pyl601.cpp47
-rw-r--r--src/mame/drivers/pzletime.cpp35
-rw-r--r--src/mame/drivers/quickpick5.cpp464
-rw-r--r--src/mame/drivers/quizo.cpp8
-rw-r--r--src/mame/drivers/qvt102.cpp2
-rw-r--r--src/mame/drivers/qvt103.cpp2
-rw-r--r--src/mame/drivers/qvt190.cpp2
-rw-r--r--src/mame/drivers/qvt70.cpp2
-rw-r--r--src/mame/drivers/qx10.cpp12
-rw-r--r--src/mame/drivers/r2dtank.cpp20
-rw-r--r--src/mame/drivers/rabbit.cpp42
-rw-r--r--src/mame/drivers/radio86.cpp4
-rw-r--r--src/mame/drivers/rainbow.cpp4
-rw-r--r--src/mame/drivers/rastersp.cpp2
-rw-r--r--src/mame/drivers/rc702.cpp14
-rw-r--r--src/mame/drivers/rc759.cpp2
-rw-r--r--src/mame/drivers/rd100.cpp2
-rw-r--r--src/mame/drivers/rex6000.cpp8
-rw-r--r--src/mame/drivers/rltennis.cpp60
-rw-r--r--src/mame/drivers/roland_cm32p.cpp15
-rw-r--r--src/mame/drivers/roland_d10.cpp15
-rw-r--r--src/mame/drivers/roland_mt32.cpp2
-rw-r--r--src/mame/drivers/roland_s10.cpp4
-rw-r--r--src/mame/drivers/rollext.cpp4
-rw-r--r--src/mame/drivers/rotaryf.cpp20
-rw-r--r--src/mame/drivers/roul.cpp7
-rw-r--r--src/mame/drivers/royalmah.cpp2
-rw-r--r--src/mame/drivers/rt1715.cpp4
-rw-r--r--src/mame/drivers/rx78.cpp4
-rw-r--r--src/mame/drivers/rz1.cpp2
-rw-r--r--src/mame/drivers/s11.cpp47
-rw-r--r--src/mame/drivers/s11a.cpp31
-rw-r--r--src/mame/drivers/s11b.cpp33
-rw-r--r--src/mame/drivers/s11c.cpp2
-rw-r--r--src/mame/drivers/saitek_intchess.cpp2
-rw-r--r--src/mame/drivers/saitek_risc2500.cpp2
-rw-r--r--src/mame/drivers/samcoupe.cpp24
-rw-r--r--src/mame/drivers/sapi1.cpp70
-rw-r--r--src/mame/drivers/sbc6510.cpp62
-rw-r--r--src/mame/drivers/sbowling.cpp2
-rw-r--r--src/mame/drivers/sbrain.cpp15
-rw-r--r--src/mame/drivers/scopus.cpp11
-rw-r--r--src/mame/drivers/scv.cpp82
-rw-r--r--src/mame/drivers/scyclone.cpp8
-rw-r--r--src/mame/drivers/sdk86.cpp44
-rw-r--r--src/mame/drivers/seabattl.cpp22
-rw-r--r--src/mame/drivers/segac2.cpp6
-rw-r--r--src/mame/drivers/segae.cpp14
-rw-r--r--src/mame/drivers/segahang.cpp102
-rw-r--r--src/mame/drivers/segas16b.cpp8
-rw-r--r--src/mame/drivers/segasp.cpp6
-rw-r--r--src/mame/drivers/seibucats.cpp14
-rw-r--r--src/mame/drivers/seibuspi.cpp6
-rw-r--r--src/mame/drivers/sfbonus.cpp32
-rw-r--r--src/mame/drivers/shine.cpp4
-rw-r--r--src/mame/drivers/shougi.cpp2
-rw-r--r--src/mame/drivers/sidepckt.cpp187
-rw-r--r--src/mame/drivers/sigmab98.cpp4
-rw-r--r--src/mame/drivers/sk101bl.cpp2
-rw-r--r--src/mame/drivers/skeetsht.cpp7
-rw-r--r--src/mame/drivers/skimaxx.cpp6
-rw-r--r--src/mame/drivers/sliver.cpp12
-rw-r--r--src/mame/drivers/slotcarn.cpp15
-rw-r--r--src/mame/drivers/sm1800.cpp9
-rw-r--r--src/mame/drivers/sm7238.cpp30
-rw-r--r--src/mame/drivers/smc777.cpp61
-rw-r--r--src/mame/drivers/smotor.cpp2
-rw-r--r--src/mame/drivers/smsmcorp.cpp7
-rw-r--r--src/mame/drivers/snesb.cpp21
-rw-r--r--src/mame/drivers/snk68.cpp113
-rw-r--r--src/mame/drivers/socrates.cpp25
-rw-r--r--src/mame/drivers/sorcerer.cpp16
-rw-r--r--src/mame/drivers/spaceg.cpp9
-rw-r--r--src/mame/drivers/spc1000.cpp12
-rw-r--r--src/mame/drivers/spc1500.cpp49
-rw-r--r--src/mame/drivers/special.cpp2
-rw-r--r--src/mame/drivers/special_gambl.cpp4
-rw-r--r--src/mame/drivers/speglsht.cpp16
-rw-r--r--src/mame/drivers/spg29x.cpp4
-rw-r--r--src/mame/drivers/spg2xx.cpp22
-rw-r--r--src/mame/drivers/spg2xx_lexibook.cpp16
-rw-r--r--src/mame/drivers/spg2xx_wiwi.cpp14
-rw-r--r--src/mame/drivers/spg2xx_zone_32bit.cpp6
-rw-r--r--src/mame/drivers/spiders.cpp26
-rw-r--r--src/mame/drivers/spinb.cpp4
-rw-r--r--src/mame/drivers/splash_ms.cpp4
-rw-r--r--src/mame/drivers/srmp5.cpp37
-rw-r--r--src/mame/drivers/ssem.cpp5
-rw-r--r--src/mame/drivers/ssingles.cpp26
-rw-r--r--src/mame/drivers/sstrangr.cpp16
-rw-r--r--src/mame/drivers/startouch.cpp20
-rw-r--r--src/mame/drivers/studio2.cpp2
-rw-r--r--src/mame/drivers/sun2.cpp31
-rw-r--r--src/mame/drivers/sun3.cpp99
-rw-r--r--src/mame/drivers/sun3x.cpp31
-rw-r--r--src/mame/drivers/supertnk.cpp18
-rw-r--r--src/mame/drivers/supracan.cpp36
-rw-r--r--src/mame/drivers/suprgolf.cpp38
-rw-r--r--src/mame/drivers/svision.cpp4
-rw-r--r--src/mame/drivers/swyft.cpp13
-rw-r--r--src/mame/drivers/sys9002.cpp14
-rw-r--r--src/mame/drivers/systel1.cpp2
-rw-r--r--src/mame/drivers/taitotz.cpp26
-rw-r--r--src/mame/drivers/taitowlf.cpp14
-rw-r--r--src/mame/drivers/tamag1.cpp2
-rw-r--r--src/mame/drivers/tandy2k.cpp11
-rw-r--r--src/mame/drivers/tapatune.cpp4
-rw-r--r--src/mame/drivers/tasc.cpp2
-rw-r--r--src/mame/drivers/tattack.cpp22
-rw-r--r--src/mame/drivers/tavernie.cpp18
-rw-r--r--src/mame/drivers/tek440x.cpp19
-rw-r--r--src/mame/drivers/teleray10.cpp2
-rw-r--r--src/mame/drivers/terak.cpp3
-rw-r--r--src/mame/drivers/tgtpanic.cpp24
-rw-r--r--src/mame/drivers/ti74.cpp6
-rw-r--r--src/mame/drivers/ti85.cpp2
-rw-r--r--src/mame/drivers/ti89.cpp13
-rw-r--r--src/mame/drivers/ti931.cpp4
-rw-r--r--src/mame/drivers/ti99_4x.cpp2
-rw-r--r--src/mame/drivers/ti99_8.cpp8
-rw-r--r--src/mame/drivers/tickee.cpp20
-rw-r--r--src/mame/drivers/tiki100.cpp6
-rw-r--r--src/mame/drivers/tim100.cpp17
-rw-r--r--src/mame/drivers/tk635.cpp4
-rw-r--r--src/mame/drivers/tmaster.cpp4
-rw-r--r--src/mame/drivers/tmc600.cpp14
-rw-r--r--src/mame/drivers/tmmjprd.cpp18
-rw-r--r--src/mame/drivers/toaplan2.cpp152
-rw-r--r--src/mame/drivers/toratora.cpp10
-rw-r--r--src/mame/drivers/toypop.cpp10
-rw-r--r--src/mame/drivers/trs80dt1.cpp4
-rw-r--r--src/mame/drivers/trs80m2.cpp4
-rw-r--r--src/mame/drivers/trs80m3.cpp2
-rw-r--r--src/mame/drivers/ts803.cpp17
-rw-r--r--src/mame/drivers/ttchamp.cpp42
-rw-r--r--src/mame/drivers/tulip1.cpp4
-rw-r--r--src/mame/drivers/tv910.cpp18
-rw-r--r--src/mame/drivers/tv950.cpp2
-rw-r--r--src/mame/drivers/tv955.cpp2
-rw-r--r--src/mame/drivers/tv990.cpp73
-rw-r--r--src/mame/drivers/tvc.cpp25
-rw-r--r--src/mame/drivers/tvgame.cpp11
-rw-r--r--src/mame/drivers/twins.cpp4
-rw-r--r--src/mame/drivers/ultrsprt.cpp6
-rw-r--r--src/mame/drivers/unior.cpp4
-rw-r--r--src/mame/drivers/unistar.cpp4
-rw-r--r--src/mame/drivers/univac.cpp2
-rw-r--r--src/mame/drivers/unixpc.cpp2
-rw-r--r--src/mame/drivers/unkhorse.cpp2
-rw-r--r--src/mame/drivers/unkpoker.cpp2
-rw-r--r--src/mame/drivers/ut88.cpp44
-rw-r--r--src/mame/drivers/uzebox.cpp4
-rw-r--r--src/mame/drivers/v6809.cpp14
-rw-r--r--src/mame/drivers/vboy.cpp47
-rw-r--r--src/mame/drivers/vcombat.cpp8
-rw-r--r--src/mame/drivers/vector06.cpp8
-rw-r--r--src/mame/drivers/vegaeo.cpp2
-rw-r--r--src/mame/drivers/vg5k.cpp50
-rw-r--r--src/mame/drivers/vicdual.cpp32
-rw-r--r--src/mame/drivers/victor9k.cpp2
-rw-r--r--src/mame/drivers/vidbrain.cpp23
-rw-r--r--src/mame/drivers/video21.cpp15
-rw-r--r--src/mame/drivers/videopkr.cpp4
-rw-r--r--src/mame/drivers/vis.cpp17
-rw-r--r--src/mame/drivers/vixen.cpp62
-rw-r--r--src/mame/drivers/vk100.cpp2
-rw-r--r--src/mame/drivers/votrhv.cpp80
-rw-r--r--src/mame/drivers/vp101.cpp4
-rw-r--r--src/mame/drivers/vt1682.cpp26
-rw-r--r--src/mame/drivers/vt240.cpp17
-rw-r--r--src/mame/drivers/vta2000.cpp23
-rw-r--r--src/mame/drivers/vtech1.cpp2
-rw-r--r--src/mame/drivers/warpsped.cpp2
-rw-r--r--src/mame/drivers/warriorb.cpp1
-rw-r--r--src/mame/drivers/wheelfir.cpp244
-rw-r--r--src/mame/drivers/wicat.cpp4
-rw-r--r--src/mame/drivers/williams.cpp45
-rw-r--r--src/mame/drivers/wpc_dot.cpp11
-rw-r--r--src/mame/drivers/wrally.cpp137
-rw-r--r--src/mame/drivers/wswan.cpp802
-rw-r--r--src/mame/drivers/wy100.cpp2
-rw-r--r--src/mame/drivers/wy50.cpp4
-rw-r--r--src/mame/drivers/x07.cpp4
-rw-r--r--src/mame/drivers/x1.cpp303
-rw-r--r--src/mame/drivers/xerox820.cpp37
-rw-r--r--src/mame/drivers/xtheball.cpp15
-rw-r--r--src/mame/drivers/xyonix.cpp8
-rw-r--r--src/mame/drivers/ymdx11.cpp2
-rw-r--r--src/mame/drivers/ymtx81z.cpp2
-rw-r--r--src/mame/drivers/z100.cpp2
-rw-r--r--src/mame/drivers/z1013.cpp15
-rw-r--r--src/mame/drivers/z22.cpp2
-rw-r--r--src/mame/drivers/z80ne.cpp10
-rw-r--r--src/mame/drivers/z9001.cpp21
-rw-r--r--src/mame/drivers/zeebo_qualcomm_adreno130.cpp2
-rw-r--r--src/mame/drivers/zorba.cpp7
-rw-r--r--src/mame/drivers/zrt80.cpp47
-rw-r--r--src/mame/includes/apollo.h6
-rw-r--r--src/mame/includes/apple3.h3
-rw-r--r--src/mame/includes/astrof.h41
-rw-r--r--src/mame/includes/bagman.h2
-rw-r--r--src/mame/includes/bbc.h1
-rw-r--r--src/mame/includes/cave.h2
-rw-r--r--src/mame/includes/champbas.h2
-rw-r--r--src/mame/includes/dai.h10
-rw-r--r--src/mame/includes/deco_mlc.h14
-rw-r--r--src/mame/includes/fmtowns.h7
-rw-r--r--src/mame/includes/gridlee.h2
-rw-r--r--src/mame/includes/karnov.h29
-rw-r--r--src/mame/includes/kaypro.h12
-rw-r--r--src/mame/includes/mac.h15
-rw-r--r--src/mame/includes/mbee.h9
-rw-r--r--src/mame/includes/model1.h6
-rw-r--r--src/mame/includes/model2.h162
-rw-r--r--src/mame/includes/nforcepc.h5
-rw-r--r--src/mame/includes/nmk16.h1
-rw-r--r--src/mame/includes/osi.h10
-rw-r--r--src/mame/includes/p2000t.h9
-rw-r--r--src/mame/includes/pacman.h24
-rw-r--r--src/mame/includes/pc1512.h2
-rw-r--r--src/mame/includes/prof80.h1
-rw-r--r--src/mame/includes/s11.h9
-rw-r--r--src/mame/includes/segag80r.h2
-rw-r--r--src/mame/includes/segas32.h2
-rw-r--r--src/mame/includes/seibuspi.h8
-rw-r--r--src/mame/includes/sidepckt.h30
-rw-r--r--src/mame/includes/snk68.h6
-rw-r--r--src/mame/includes/special.h12
-rw-r--r--src/mame/includes/taito_f2.h12
-rw-r--r--src/mame/includes/toaplan2.h2
-rw-r--r--src/mame/includes/turrett.h2
-rw-r--r--src/mame/includes/ut88.h8
-rw-r--r--src/mame/includes/vicdual.h14
-rw-r--r--src/mame/includes/williams.h7
-rw-r--r--src/mame/includes/wswan.h120
-rw-r--r--src/mame/includes/xavix.h2
-rw-r--r--src/mame/includes/xbox_pci.h29
-rw-r--r--src/mame/includes/xerox820.h5
-rw-r--r--src/mame/layout/allied.lay101
-rw-r--r--src/mame/layout/amerihok.lay2
-rw-r--r--src/mame/layout/babypkr.lay126
-rw-r--r--src/mame/layout/brkball.lay13
-rw-r--r--src/mame/layout/cgang.lay267
-rw-r--r--src/mame/layout/eacc.lay2
-rw-r--r--src/mame/layout/emma2.lay2
-rw-r--r--src/mame/layout/epc.lay2
-rw-r--r--src/mame/layout/esq2by16.lay136
-rw-r--r--src/mame/layout/fireball.lay2
-rw-r--r--src/mame/layout/gp_1.lay4
-rw-r--r--src/mame/layout/gp_2.lay4
-rw-r--r--src/mame/layout/hankin.lay101
-rw-r--r--src/mame/layout/hp9825.lay42
-rw-r--r--src/mame/layout/instruct.lay10
-rw-r--r--src/mame/layout/mmd1.lay2
-rw-r--r--src/mame/layout/mmd2.lay6
-rw-r--r--src/mame/layout/model1io2.lay37
-rw-r--r--src/mame/layout/outrun.lay4
-rw-r--r--src/mame/layout/play_1.lay103
-rw-r--r--src/mame/layout/play_2.lay99
-rw-r--r--src/mame/layout/play_3.lay111
-rw-r--r--src/mame/layout/s11.lay111
-rw-r--r--src/mame/layout/s11a.lay113
-rw-r--r--src/mame/layout/s11b.lay124
-rw-r--r--src/mame/layout/s11c.lay124
-rw-r--r--src/mame/layout/s3.lay103
-rw-r--r--src/mame/layout/s4.lay103
-rw-r--r--src/mame/layout/s6.lay103
-rw-r--r--src/mame/layout/s6a.lay111
-rw-r--r--src/mame/layout/s9.lay111
-rw-r--r--src/mame/layout/saitek_ssystem3.lay6
-rw-r--r--src/mame/layout/sc1_vfd.lay900
-rw-r--r--src/mame/layout/sc1_vid.lay4
-rw-r--r--src/mame/layout/sc2_dmd.lay12
-rw-r--r--src/mame/layout/sc2copcl7.lay12
-rw-r--r--src/mame/layout/sc2cpe.lay12
-rw-r--r--src/mame/layout/sc2prem2.lay12
-rw-r--r--src/mame/layout/sc2prom.lay12
-rw-r--r--src/mame/layout/sc2ptytm1.lay12
-rw-r--r--src/mame/layout/sc2town2.lay12
-rw-r--r--src/mame/layout/sc4_dmd.lay11
-rw-r--r--src/mame/layout/sdk86.lay12
-rw-r--r--src/mame/layout/sentx6p.lay76
-rw-r--r--src/mame/layout/st_mp100.lay103
-rw-r--r--src/mame/layout/st_mp200.lay115
-rw-r--r--src/mame/layout/tecnbras.lay348
-rw-r--r--src/mame/layout/tm990189.lay2
-rw-r--r--src/mame/layout/tm990189v.lay2
-rw-r--r--src/mame/layout/tmtennis.lay63
-rw-r--r--src/mame/layout/touchme.lay2
-rw-r--r--src/mame/layout/unkeinv.lay204
-rw-r--r--src/mame/layout/v4dbltak.lay8
-rw-r--r--src/mame/layout/videocba.lay19
-rw-r--r--src/mame/layout/videopkr.lay122
-rw-r--r--src/mame/layout/wpc_an.lay2
-rw-r--r--src/mame/machine/3do.cpp4
-rw-r--r--src/mame/machine/3dom2.cpp6
-rw-r--r--src/mame/machine/abc1600mac.cpp8
-rw-r--r--src/mame/machine/aim65.cpp5
-rw-r--r--src/mame/machine/amstrad.cpp6
-rw-r--r--src/mame/machine/apple3.cpp68
-rw-r--r--src/mame/machine/b2m.cpp19
-rw-r--r--src/mame/machine/bacta_datalogger.cpp2
-rw-r--r--src/mame/machine/bk.cpp6
-rw-r--r--src/mame/machine/cedar_magnet_plane.cpp2
-rw-r--r--src/mame/machine/cedar_magnet_sprite.cpp2
-rw-r--r--src/mame/machine/concept.cpp2
-rw-r--r--src/mame/machine/dai.cpp15
-rw-r--r--src/mame/machine/dragon.cpp2
-rw-r--r--src/mame/machine/egret.cpp16
-rw-r--r--src/mame/machine/fp6000_kbd.cpp6
-rw-r--r--src/mame/machine/gamepock.cpp64
-rw-r--r--src/mame/machine/ibm6580_fdc.cpp2
-rw-r--r--src/mame/machine/imds2ioc.cpp9
-rw-r--r--src/mame/machine/inder_vid.cpp9
-rw-r--r--src/mame/machine/informer_207_376_kbd.cpp2
-rw-r--r--src/mame/machine/informer_207_376_kbd.h4
-rw-r--r--src/mame/machine/informer_213_kbd.cpp304
-rw-r--r--src/mame/machine/informer_213_kbd.h58
-rw-r--r--src/mame/machine/kaypro.cpp49
-rw-r--r--src/mame/machine/lynx.cpp4
-rw-r--r--src/mame/machine/m6502_swap_op_d5_d6.cpp62
-rw-r--r--src/mame/machine/m6502_swap_op_d5_d6.h40
-rw-r--r--src/mame/machine/mac.cpp20
-rw-r--r--src/mame/machine/macadb.cpp24
-rw-r--r--src/mame/machine/macadb.h2
-rw-r--r--src/mame/machine/mbee.cpp24
-rw-r--r--src/mame/machine/mega32x.cpp11
-rw-r--r--src/mame/machine/mega32x.h2
-rw-r--r--src/mame/machine/megacd.cpp2
-rw-r--r--src/mame/machine/megadriv.cpp6
-rw-r--r--src/mame/machine/model1io2.cpp2
-rw-r--r--src/mame/machine/namcos21_dsp_c67.cpp2
-rw-r--r--src/mame/machine/namcos21_dsp_c67.h30
-rw-r--r--src/mame/machine/nes_vt_soc.cpp79
-rw-r--r--src/mame/machine/nes_vt_soc.h9
-rw-r--r--src/mame/machine/news_hid.cpp4
-rw-r--r--src/mame/machine/nl_tank.cpp17
-rw-r--r--src/mame/machine/osborne1.cpp4
-rw-r--r--src/mame/machine/p2000t.cpp80
-rw-r--r--src/mame/machine/p2000t_mdcr.cpp18
-rw-r--r--src/mame/machine/partner.cpp9
-rw-r--r--src/mame/machine/pc1512kb.cpp6
-rw-r--r--src/mame/machine/pcd_kbd.cpp6
-rw-r--r--src/mame/machine/primo.cpp2
-rw-r--r--src/mame/machine/psxcd.cpp14
-rw-r--r--src/mame/machine/radio86.cpp2
-rw-r--r--src/mame/machine/sms.cpp16
-rw-r--r--src/mame/machine/special.cpp17
-rw-r--r--src/mame/machine/st0016.cpp4
-rw-r--r--src/mame/machine/teleprinter.cpp15
-rw-r--r--src/mame/machine/thomson.cpp4
-rw-r--r--src/mame/machine/trs80.cpp2
-rw-r--r--src/mame/machine/ut88.cpp13
-rw-r--r--src/mame/machine/victor9k_kb.cpp2
-rw-r--r--src/mame/machine/wangpckb.cpp6
-rw-r--r--src/mame/machine/williams.cpp6
-rw-r--r--src/mame/machine/wswan.cpp664
-rw-r--r--src/mame/machine/x820kb.cpp10
-rw-r--r--src/mame/machine/xbox.cpp12
-rw-r--r--src/mame/machine/xbox_pci.cpp71
-rw-r--r--src/mame/machine/zx.cpp8
-rw-r--r--src/mame/mame.lst69
-rw-r--r--src/mame/mess.flt4
-rw-r--r--src/mame/nl.lst9
-rw-r--r--src/mame/video/1943.cpp8
-rw-r--r--src/mame/video/20pacgal.cpp8
-rw-r--r--src/mame/video/40love.cpp27
-rw-r--r--src/mame/video/733_asr.cpp2
-rw-r--r--src/mame/video/8080bw.cpp18
-rw-r--r--src/mame/video/abc1600.cpp2
-rw-r--r--src/mame/video/abc80.cpp2
-rw-r--r--src/mame/video/abc800.cpp16
-rw-r--r--src/mame/video/abc802.cpp6
-rw-r--r--src/mame/video/abc806.cpp8
-rw-r--r--src/mame/video/advision.cpp4
-rw-r--r--src/mame/video/aeroboto.cpp39
-rw-r--r--src/mame/video/aerofgt.cpp16
-rw-r--r--src/mame/video/agat7.cpp72
-rw-r--r--src/mame/video/agat9.cpp164
-rw-r--r--src/mame/video/airraid_dev.cpp4
-rw-r--r--src/mame/video/amiga.cpp6
-rw-r--r--src/mame/video/amigaaga.cpp6
-rw-r--r--src/mame/video/ams40041.cpp8
-rw-r--r--src/mame/video/apexc.cpp4
-rw-r--r--src/mame/video/apollo.cpp68
-rw-r--r--src/mame/video/apple2.cpp848
-rw-r--r--src/mame/video/apple2.h12
-rw-r--r--src/mame/video/apple3.cpp187
-rw-r--r--src/mame/video/arcadecl.cpp8
-rw-r--r--src/mame/video/arcadia.cpp6
-rw-r--r--src/mame/video/argus.cpp96
-rw-r--r--src/mame/video/armedf.cpp30
-rw-r--r--src/mame/video/artmagic.cpp9
-rw-r--r--src/mame/video/astrocde.cpp28
-rw-r--r--src/mame/video/atarig42.cpp23
-rw-r--r--src/mame/video/atarigt.cpp45
-rw-r--r--src/mame/video/atarigx2.cpp19
-rw-r--r--src/mame/video/atarimo.cpp2
-rw-r--r--src/mame/video/atarimo.h2
-rw-r--r--src/mame/video/atarirle.cpp24
-rw-r--r--src/mame/video/atarist.cpp4
-rw-r--r--src/mame/video/atarisy1.cpp4
-rw-r--r--src/mame/video/atarisy2.cpp8
-rw-r--r--src/mame/video/aussiebyte.cpp15
-rw-r--r--src/mame/video/avigo.cpp22
-rw-r--r--src/mame/video/badlands.cpp7
-rw-r--r--src/mame/video/balsente.cpp22
-rw-r--r--src/mame/video/batman.cpp18
-rw-r--r--src/mame/video/battlane.cpp23
-rw-r--r--src/mame/video/bbc.cpp4
-rw-r--r--src/mame/video/bbusters.cpp13
-rw-r--r--src/mame/video/bigevglf.cpp9
-rw-r--r--src/mame/video/bking.cpp6
-rw-r--r--src/mame/video/blockout.cpp4
-rw-r--r--src/mame/video/blstroid.cpp6
-rw-r--r--src/mame/video/boogwing.cpp23
-rw-r--r--src/mame/video/bosco.cpp8
-rw-r--r--src/mame/video/btoads.cpp14
-rw-r--r--src/mame/video/buggychl.cpp48
-rw-r--r--src/mame/video/busicom.cpp4
-rw-r--r--src/mame/video/capbowl.cpp4
-rw-r--r--src/mame/video/carpolo.cpp48
-rw-r--r--src/mame/video/ccastles.cpp40
-rw-r--r--src/mame/video/cclimber.cpp10
-rw-r--r--src/mame/video/cgc7900.cpp6
-rw-r--r--src/mame/video/chaknpop.cpp11
-rw-r--r--src/mame/video/changela.cpp194
-rw-r--r--src/mame/video/channelf.cpp14
-rw-r--r--src/mame/video/cheekyms.cpp13
-rw-r--r--src/mame/video/circus.cpp21
-rw-r--r--src/mame/video/cloak.cpp10
-rw-r--r--src/mame/video/cloud9.cpp41
-rw-r--r--src/mame/video/copsnrob.cpp28
-rw-r--r--src/mame/video/cosmic.cpp25
-rw-r--r--src/mame/video/cps1.cpp11
-rw-r--r--src/mame/video/crbaloon.cpp4
-rw-r--r--src/mame/video/crgolf.cpp10
-rw-r--r--src/mame/video/crt.cpp11
-rw-r--r--src/mame/video/cvs.cpp75
-rw-r--r--src/mame/video/cyberbal.cpp7
-rw-r--r--src/mame/video/cybstorm.cpp16
-rw-r--r--src/mame/video/dai.cpp397
-rw-r--r--src/mame/video/darkmist.cpp8
-rw-r--r--src/mame/video/dassault.cpp16
-rw-r--r--src/mame/video/dcheese.cpp11
-rw-r--r--src/mame/video/dday.cpp12
-rw-r--r--src/mame/video/decbac06.cpp8
-rw-r--r--src/mame/video/decmxc06.cpp2
-rw-r--r--src/mame/video/decmxc06.h10
-rw-r--r--src/mame/video/deco16ic.cpp12
-rw-r--r--src/mame/video/deco32.cpp20
-rw-r--r--src/mame/video/deco_mlc.cpp4
-rw-r--r--src/mame/video/deco_zoomspr.cpp33
-rw-r--r--src/mame/video/decocass.cpp42
-rw-r--r--src/mame/video/decodmd1.cpp22
-rw-r--r--src/mame/video/decodmd2.cpp7
-rw-r--r--src/mame/video/decodmd3.cpp4
-rw-r--r--src/mame/video/decospr.cpp28
-rw-r--r--src/mame/video/deniam.cpp24
-rw-r--r--src/mame/video/dgn_beta.cpp6
-rw-r--r--src/mame/video/dkong.cpp27
-rw-r--r--src/mame/video/dogfgt.cpp4
-rw-r--r--src/mame/video/dpb_combiner.cpp2
-rw-r--r--src/mame/video/dribling.cpp2
-rw-r--r--src/mame/video/dynax.cpp46
-rw-r--r--src/mame/video/dynduke.cpp15
-rw-r--r--src/mame/video/elan_eu3a05vid.cpp6
-rw-r--r--src/mame/video/elan_eu3a14vid.cpp8
-rw-r--r--src/mame/video/electron.cpp2
-rw-r--r--src/mame/video/eolith.cpp2
-rw-r--r--src/mame/video/epos.cpp8
-rw-r--r--src/mame/video/eprom.cpp33
-rw-r--r--src/mame/video/equites.cpp8
-rw-r--r--src/mame/video/esripsys.cpp15
-rw-r--r--src/mame/video/exidy.cpp50
-rw-r--r--src/mame/video/exidy440.cpp11
-rw-r--r--src/mame/video/exterm.cpp6
-rw-r--r--src/mame/video/fgoal.cpp24
-rw-r--r--src/mame/video/firetrk.cpp10
-rw-r--r--src/mame/video/fm7.cpp21
-rw-r--r--src/mame/video/fmtowns.cpp94
-rw-r--r--src/mame/video/gaelco2.cpp4
-rw-r--r--src/mame/video/gaelco3d.cpp14
-rw-r--r--src/mame/video/gaelco_wrally_sprites.cpp8
-rw-r--r--src/mame/video/galastrm.cpp12
-rw-r--r--src/mame/video/galaxia.cpp50
-rw-r--r--src/mame/video/galaxian.cpp12
-rw-r--r--src/mame/video/galaxold.cpp35
-rw-r--r--src/mame/video/galaxy.cpp43
-rw-r--r--src/mame/video/galpani2.cpp8
-rw-r--r--src/mame/video/galpanic.cpp10
-rw-r--r--src/mame/video/galspnbl.cpp6
-rw-r--r--src/mame/video/gamate.cpp2
-rw-r--r--src/mame/video/gamecom.cpp13
-rw-r--r--src/mame/video/gameplan.cpp10
-rw-r--r--src/mame/video/gaplus.cpp2
-rw-r--r--src/mame/video/gauntlet.cpp4
-rw-r--r--src/mame/video/gic.cpp23
-rw-r--r--src/mame/video/gic.h2
-rw-r--r--src/mame/video/gladiatr.cpp4
-rw-r--r--src/mame/video/glass.cpp12
-rw-r--r--src/mame/video/gomoku.cpp6
-rw-r--r--src/mame/video/gp9001.cpp10
-rw-r--r--src/mame/video/grchamp.cpp106
-rw-r--r--src/mame/video/gridlee.cpp26
-rw-r--r--src/mame/video/h01x.cpp21
-rw-r--r--src/mame/video/harddriv.cpp20
-rw-r--r--src/mame/video/hec2hrp.cpp4
-rw-r--r--src/mame/video/hnayayoi.cpp2
-rw-r--r--src/mame/video/hng64.cpp197
-rw-r--r--src/mame/video/hng64_3d.hxx4
-rw-r--r--src/mame/video/hp48.cpp2
-rw-r--r--src/mame/video/hyhoo.cpp70
-rw-r--r--src/mame/video/igs017_igs031.cpp4
-rw-r--r--src/mame/video/ikki.cpp4
-rw-r--r--src/mame/video/itech8.cpp88
-rw-r--r--src/mame/video/jaguar.cpp2
-rw-r--r--src/mame/video/jedi.cpp8
-rw-r--r--src/mame/video/jpmimpct.cpp9
-rw-r--r--src/mame/video/k001005.cpp33
-rw-r--r--src/mame/video/k001604.cpp4
-rw-r--r--src/mame/video/k053246_k053247_k055673.cpp2
-rw-r--r--src/mame/video/k053250.cpp8
-rw-r--r--src/mame/video/k053250_ps.cpp8
-rw-r--r--src/mame/video/k053936.cpp4
-rw-r--r--src/mame/video/k054156_k054157_k056832.cpp8
-rw-r--r--src/mame/video/k054338.cpp2
-rw-r--r--src/mame/video/k057714.cpp2
-rw-r--r--src/mame/video/k1ge.cpp22
-rw-r--r--src/mame/video/kaneko16.cpp13
-rw-r--r--src/mame/video/kaneko_spr.cpp19
-rw-r--r--src/mame/video/kangaroo.cpp7
-rw-r--r--src/mame/video/kaypro.cpp52
-rw-r--r--src/mame/video/kc.cpp25
-rw-r--r--src/mame/video/klax.cpp4
-rw-r--r--src/mame/video/konamigx.cpp33
-rw-r--r--src/mame/video/ladybug.cpp2
-rw-r--r--src/mame/video/laserbat.cpp12
-rw-r--r--src/mame/video/lasso.cpp20
-rw-r--r--src/mame/video/lazercmd.cpp10
-rw-r--r--src/mame/video/leland.cpp2
-rw-r--r--src/mame/video/lemmings.cpp25
-rw-r--r--src/mame/video/lethalj.cpp18
-rw-r--r--src/mame/video/liberatr.cpp34
-rw-r--r--src/mame/video/light.cpp6
-rw-r--r--src/mame/video/lockon.cpp76
-rw-r--r--src/mame/video/lordgun.cpp19
-rw-r--r--src/mame/video/lviv.cpp11
-rw-r--r--src/mame/video/m10.cpp6
-rw-r--r--src/mame/video/m57.cpp25
-rw-r--r--src/mame/video/m58.cpp4
-rw-r--r--src/mame/video/mac.cpp624
-rw-r--r--src/mame/video/madalien.cpp6
-rw-r--r--src/mame/video/magmax.cpp2
-rw-r--r--src/mame/video/malzak.cpp16
-rw-r--r--src/mame/video/mappy.cpp9
-rw-r--r--src/mame/video/maria.cpp3
-rw-r--r--src/mame/video/mbc55x.cpp47
-rw-r--r--src/mame/video/mbee.cpp13
-rw-r--r--src/mame/video/mcatadv.cpp4
-rw-r--r--src/mame/video/mcd212.cpp5
-rw-r--r--src/mame/video/mcr.cpp12
-rw-r--r--src/mame/video/megasys1.cpp20
-rw-r--r--src/mame/video/mermaid.cpp16
-rw-r--r--src/mame/video/micro3d.cpp11
-rw-r--r--src/mame/video/midtunit.cpp10
-rw-r--r--src/mame/video/midtview.ipp2
-rw-r--r--src/mame/video/midvunit.cpp8
-rw-r--r--src/mame/video/midyunit.cpp7
-rw-r--r--src/mame/video/midzeus.cpp6
-rw-r--r--src/mame/video/mikromik.cpp19
-rw-r--r--src/mame/video/mmdisplay2.cpp2
-rw-r--r--src/mame/video/model1.cpp14
-rw-r--r--src/mame/video/model2.cpp17
-rw-r--r--src/mame/video/model2rd.hxx6
-rw-r--r--src/mame/video/model3.cpp49
-rw-r--r--src/mame/video/momoko.cpp14
-rw-r--r--src/mame/video/ms32.cpp43
-rw-r--r--src/mame/video/mw8080bw.cpp20
-rw-r--r--src/mame/video/mz700.cpp40
-rw-r--r--src/mame/video/mz80.cpp45
-rw-r--r--src/mame/video/n64.cpp4
-rw-r--r--src/mame/video/n8080.cpp54
-rw-r--r--src/mame/video/namco_c355spr.cpp24
-rw-r--r--src/mame/video/namcona1.cpp12
-rw-r--r--src/mame/video/namcos21_3d.cpp12
-rw-r--r--src/mame/video/namcos22.cpp32
-rw-r--r--src/mame/video/namcos2_roz.cpp6
-rw-r--r--src/mame/video/namcos2_sprite.cpp6
-rw-r--r--src/mame/video/nbmj8688.cpp2
-rw-r--r--src/mame/video/nbmj8891.cpp4
-rw-r--r--src/mame/video/nbmj8900.cpp4
-rw-r--r--src/mame/video/nbmj8991.cpp12
-rw-r--r--src/mame/video/nbmj9195.cpp2
-rw-r--r--src/mame/video/nc.cpp2
-rw-r--r--src/mame/video/neogeo_spr.cpp6
-rw-r--r--src/mame/video/newbrain.cpp4
-rw-r--r--src/mame/video/nick.cpp2
-rw-r--r--src/mame/video/ninjakd2.cpp2
-rw-r--r--src/mame/video/nitedrvr.cpp2
-rw-r--r--src/mame/video/niyanpai.cpp2
-rw-r--r--src/mame/video/nmk16spr.cpp4
-rw-r--r--src/mame/video/nmk16spr.h10
-rw-r--r--src/mame/video/offtwall.cpp7
-rw-r--r--src/mame/video/ojankohs.cpp24
-rw-r--r--src/mame/video/orion.cpp2
-rw-r--r--src/mame/video/osi.cpp8
-rw-r--r--src/mame/video/p2000t.cpp16
-rw-r--r--src/mame/video/pacland.cpp10
-rw-r--r--src/mame/video/paradise.cpp10
-rw-r--r--src/mame/video/pastelg.cpp2
-rw-r--r--src/mame/video/pc080sn.cpp29
-rw-r--r--src/mame/video/pc4.cpp8
-rw-r--r--src/mame/video/pc6001.cpp207
-rw-r--r--src/mame/video/pc9801.cpp98
-rw-r--r--src/mame/video/pc_t1t.cpp246
-rw-r--r--src/mame/video/pcd.cpp8
-rw-r--r--src/mame/video/pcw.cpp16
-rw-r--r--src/mame/video/pcw16.cpp2
-rw-r--r--src/mame/video/pdp1.cpp7
-rw-r--r--src/mame/video/pgm.cpp16
-rw-r--r--src/mame/video/pgm2.cpp10
-rw-r--r--src/mame/video/pitnrun.cpp2
-rw-r--r--src/mame/video/pk8000.cpp31
-rw-r--r--src/mame/video/pk8020.cpp10
-rw-r--r--src/mame/video/playmark.cpp20
-rw-r--r--src/mame/video/pocketc.cpp2
-rw-r--r--src/mame/video/polepos.cpp2
-rw-r--r--src/mame/video/policetr.cpp16
-rw-r--r--src/mame/video/popeye.cpp12
-rw-r--r--src/mame/video/powervr2.cpp348
-rw-r--r--src/mame/video/powervr2.h45
-rw-r--r--src/mame/video/pp01.cpp2
-rw-r--r--src/mame/video/psikyosh.cpp56
-rw-r--r--src/mame/video/qix.cpp4
-rw-r--r--src/mame/video/quasar.cpp18
-rw-r--r--src/mame/video/raiden2.cpp6
-rw-r--r--src/mame/video/rallyx.cpp4
-rw-r--r--src/mame/video/rampart.cpp10
-rw-r--r--src/mame/video/redalert.cpp77
-rw-r--r--src/mame/video/redclash.cpp2
-rw-r--r--src/mame/video/relief.cpp10
-rw-r--r--src/mame/video/rltennis.cpp10
-rw-r--r--src/mame/video/rm380z.cpp53
-rw-r--r--src/mame/video/rmnimbus.cpp10
-rw-r--r--src/mame/video/rockrage.cpp2
-rw-r--r--src/mame/video/rohga.cpp12
-rw-r--r--src/mame/video/route16.cpp20
-rw-r--r--src/mame/video/rpunch.cpp10
-rw-r--r--src/mame/video/segag80r.cpp27
-rw-r--r--src/mame/video/segaic16.cpp11
-rw-r--r--src/mame/video/segaic16_road.cpp4
-rw-r--r--src/mame/video/segaic24.cpp72
-rw-r--r--src/mame/video/segas32.cpp270
-rw-r--r--src/mame/video/seibuspi.cpp10
-rw-r--r--src/mame/video/senjyo.cpp6
-rw-r--r--src/mame/video/seta.cpp8
-rw-r--r--src/mame/video/seta2.cpp4
-rw-r--r--src/mame/video/shuuz.cpp8
-rw-r--r--src/mame/video/sidearms.cpp23
-rw-r--r--src/mame/video/sidepckt.cpp2
-rw-r--r--src/mame/video/sknsspr.cpp43
-rw-r--r--src/mame/video/skullxbo.cpp14
-rw-r--r--src/mame/video/skyfox.cpp2
-rw-r--r--src/mame/video/skyraid.cpp17
-rw-r--r--src/mame/video/spacefb.cpp67
-rw-r--r--src/mame/video/special.cpp30
-rw-r--r--src/mame/video/spectrum.cpp6
-rw-r--r--src/mame/video/splash.cpp2
-rw-r--r--src/mame/video/sprint2.cpp9
-rw-r--r--src/mame/video/sprint4.cpp2
-rw-r--r--src/mame/video/sprint8.cpp4
-rw-r--r--src/mame/video/sspeedr.cpp10
-rw-r--r--src/mame/video/ssv.cpp3
-rw-r--r--src/mame/video/st0020.cpp4
-rw-r--r--src/mame/video/stactics.cpp17
-rw-r--r--src/mame/video/starcrus.cpp16
-rw-r--r--src/mame/video/starfield_05xx.cpp2
-rw-r--r--src/mame/video/starfire.cpp16
-rw-r--r--src/mame/video/starshp1.cpp29
-rw-r--r--src/mame/video/stfight_dev.cpp4
-rw-r--r--src/mame/video/stic.cpp10
-rw-r--r--src/mame/video/super80.cpp10
-rw-r--r--src/mame/video/superqix.cpp8
-rw-r--r--src/mame/video/suprloco.cpp2
-rw-r--r--src/mame/video/suprnova.cpp127
-rw-r--r--src/mame/video/system1.cpp12
-rw-r--r--src/mame/video/taito_b.cpp42
-rw-r--r--src/mame/video/taito_f2.cpp16
-rw-r--r--src/mame/video/taito_f3.cpp24
-rw-r--r--src/mame/video/taito_helper.cpp4
-rw-r--r--src/mame/video/taitoair.cpp3
-rw-r--r--src/mame/video/taitojc.cpp19
-rw-r--r--src/mame/video/taitosj.cpp27
-rw-r--r--src/mame/video/tank8.cpp15
-rw-r--r--src/mame/video/tatsumi.cpp419
-rw-r--r--src/mame/video/taxidriv.cpp76
-rw-r--r--src/mame/video/tc0080vco.cpp4
-rw-r--r--src/mame/video/tc0100scn.cpp12
-rw-r--r--src/mame/video/tc0180vcu.cpp43
-rw-r--r--src/mame/video/tc0480scp.cpp41
-rw-r--r--src/mame/video/tc0780fpa.cpp12
-rw-r--r--src/mame/video/tceptor.cpp10
-rw-r--r--src/mame/video/tecmo_mix.cpp21
-rw-r--r--src/mame/video/tecmosys.cpp23
-rw-r--r--src/mame/video/thief.cpp15
-rw-r--r--src/mame/video/thunderj.cpp18
-rw-r--r--src/mame/video/ti85.cpp27
-rw-r--r--src/mame/video/tia.cpp24
-rw-r--r--src/mame/video/timex.cpp2
-rw-r--r--src/mame/video/tmnt.cpp6
-rw-r--r--src/mame/video/toaplan1.cpp6
-rw-r--r--src/mame/video/toaplan2.cpp4
-rw-r--r--src/mame/video/toaplan_scu.cpp6
-rw-r--r--src/mame/video/toobin.cpp10
-rw-r--r--src/mame/video/triplhnt.cpp28
-rw-r--r--src/mame/video/trs80.cpp111
-rw-r--r--src/mame/video/trs80m3.cpp20
-rw-r--r--src/mame/video/truco.cpp2
-rw-r--r--src/mame/video/tubep.cpp24
-rw-r--r--src/mame/video/tunhunt.cpp6
-rw-r--r--src/mame/video/turbo.cpp161
-rw-r--r--src/mame/video/turrett.cpp2
-rw-r--r--src/mame/video/tutankhm.cpp16
-rw-r--r--src/mame/video/twin16.cpp9
-rw-r--r--src/mame/video/tx0.cpp7
-rw-r--r--src/mame/video/tx1.cpp24
-rw-r--r--src/mame/video/ultratnk.cpp2
-rw-r--r--src/mame/video/usgames.cpp2
-rw-r--r--src/mame/video/uv201.cpp2
-rw-r--r--src/mame/video/v1050.cpp8
-rw-r--r--src/mame/video/vc4000.cpp27
-rw-r--r--src/mame/video/vector06.cpp31
-rw-r--r--src/mame/video/vicdual.cpp27
-rw-r--r--src/mame/video/victory.cpp7
-rw-r--r--src/mame/video/vindictr.cpp10
-rw-r--r--src/mame/video/volfied.cpp2
-rw-r--r--src/mame/video/vtvideo.cpp30
-rw-r--r--src/mame/video/warpwarp.cpp2
-rw-r--r--src/mame/video/wecleman.cpp109
-rw-r--r--src/mame/video/welltris.cpp13
-rw-r--r--src/mame/video/wgp.cpp8
-rw-r--r--src/mame/video/williams.cpp31
-rw-r--r--src/mame/video/wolfpack.cpp23
-rw-r--r--src/mame/video/wswan.cpp49
-rw-r--r--src/mame/video/wswan.h23
-rw-r--r--src/mame/video/x1.cpp18
-rw-r--r--src/mame/video/x68k.cpp78
-rw-r--r--src/mame/video/xavix.cpp8
-rw-r--r--src/mame/video/xmen.cpp8
-rw-r--r--src/mame/video/xybots.cpp10
-rw-r--r--src/mame/video/ygv608.cpp10
-rw-r--r--src/mame/video/z88.cpp2
-rw-r--r--src/mame/video/zac2650.cpp23
-rw-r--r--src/mame/video/zaxxon.cpp17
-rw-r--r--src/mame/video/zx.cpp2
-rw-r--r--src/mame/video/zx8301.cpp6
-rw-r--r--src/osd/modules/debugger/debuggdbstub.cpp2
-rw-r--r--src/osd/modules/debugger/debugimgui.cpp10
-rw-r--r--src/osd/modules/debugger/win/consolewininfo.cpp4
-rw-r--r--src/osd/modules/debugger/win/disasmbasewininfo.cpp2
-rw-r--r--src/osd/modules/debugger/win/logwininfo.cpp2
-rw-r--r--src/osd/modules/debugger/win/memorywininfo.cpp2
-rw-r--r--src/osd/modules/debugger/win/pointswininfo.cpp6
-rw-r--r--src/osd/modules/file/posixptty.cpp2
-rw-r--r--src/osd/modules/font/font_dwrite.cpp4
-rw-r--r--src/osd/modules/font/font_sdl.cpp2
-rw-r--r--src/osd/modules/font/font_windows.cpp3
-rw-r--r--src/osd/modules/lib/osdobj_common.cpp20
-rw-r--r--src/osd/modules/lib/osdobj_common.h6
-rw-r--r--src/osd/modules/midi/midi_module.h15
-rw-r--r--src/osd/modules/midi/none.cpp9
-rw-r--r--src/osd/modules/midi/portmidi.cpp6
-rw-r--r--src/osd/modules/netdev/pcap.cpp2
-rw-r--r--src/osd/modules/netdev/taptun.cpp2
-rw-r--r--src/osd/modules/opengl/osd_opengl.h2
-rw-r--r--src/osd/modules/osdmodule.cpp60
-rw-r--r--src/osd/modules/osdmodule.h45
-rw-r--r--src/osd/modules/output/win32_output.cpp6
-rw-r--r--src/osd/modules/render/bgfx/chain.cpp2
-rw-r--r--src/osd/modules/render/bgfx/chainmanager.cpp2
-rw-r--r--src/osd/modules/render/bgfx/inputpair.cpp2
-rw-r--r--src/osd/modules/render/bgfx/slider.cpp2
-rw-r--r--src/osd/modules/render/bgfx/texturemanager.cpp6
-rw-r--r--src/osd/modules/render/d3d/d3dhlsl.cpp38
-rw-r--r--src/osd/modules/render/draw13.cpp6
-rw-r--r--src/osd/modules/render/draw13.h8
-rw-r--r--src/osd/modules/render/drawbgfx.cpp2
-rw-r--r--src/osd/modules/render/drawd3d.cpp28
-rw-r--r--src/osd/modules/render/drawd3d.h10
-rw-r--r--src/osd/modules/render/drawgdi.cpp16
-rw-r--r--src/osd/modules/render/drawgdi.h12
-rw-r--r--src/osd/modules/render/drawogl.cpp18
-rw-r--r--src/osd/modules/render/drawogl.h7
-rw-r--r--src/osd/modules/render/drawsdl.cpp33
-rw-r--r--src/osd/modules/render/drawsdl.h16
-rw-r--r--src/osd/osdepend.h2
-rw-r--r--src/osd/osdnet.cpp2
-rw-r--r--src/osd/osdnet.h12
-rw-r--r--src/osd/sdl/window.cpp3
-rw-r--r--src/osd/sdl/window.h8
-rw-r--r--src/osd/windows/window.cpp287
-rw-r--r--src/osd/windows/window.h34
-rw-r--r--src/tools/castool.cpp31
-rw-r--r--src/tools/chdman.cpp8
-rw-r--r--src/tools/imgtool/modules/hp85_tape.cpp4
-rw-r--r--src/tools/imgtool/modules/hp9845_tape.cpp4
-rw-r--r--src/tools/ldresample.cpp4
-rw-r--r--src/tools/ldverify.cpp14
-rw-r--r--src/tools/pngcmp.cpp44
-rw-r--r--src/tools/regrep.cpp52
-rw-r--r--src/tools/unidasm.cpp2
-rw-r--r--src/zexall/main.cpp2
-rw-r--r--src/zexall/zexall.cpp12
2357 files changed, 187955 insertions, 91190 deletions
diff --git a/3rdparty/expat/AUTHORS b/3rdparty/expat/AUTHORS
new file mode 100644
index 00000000000..99475bb1b2e
--- /dev/null
+++ b/3rdparty/expat/AUTHORS
@@ -0,0 +1,10 @@
+Expat is brought to you by:
+
+Clark Cooper
+Fred L. Drake, Jr.
+Greg Stein
+James Clark
+Karl Waclawek
+Rhodri James
+Sebastian Pipping
+Steven Solie
diff --git a/3rdparty/expat/CMake.README b/3rdparty/expat/CMake.README
index 0198e615640..aa098b4f942 100644
--- a/3rdparty/expat/CMake.README
+++ b/3rdparty/expat/CMake.README
@@ -1,27 +1,27 @@
== How to build expat with cmake (experimental) ==
-The cmake based buildsystem for expat works on Windows (cygwin, mingw, Visual
+The cmake based buildsystem for expat works on Windows (cygwin, mingw, Visual
Studio) and should work on all other platform cmake supports.
-Assuming ~/expat-2.1.1 is the source directory of expat, add a subdirectory
+Assuming ~/expat-2.2.10 is the source directory of expat, add a subdirectory
build and change into that directory:
-~/expat-2.1.1$ mkdir build && cd build
-~/expat-2.1.1/build$
+~/expat-2.2.10$ mkdir build && cd build
+~/expat-2.2.10/build$
-From that directory, call cmake first, then call make, make test and
+From that directory, call cmake first, then call make, make test and
make install in the usual way:
-~/expat-2.1.1/build$ cmake ..
+~/expat-2.2.10/build$ cmake ..
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
....
-- Configuring done
-- Generating done
--- Build files have been written to: /home/patrick/expat-2.1.1/build
+-- Build files have been written to: /home/patrick/expat-2.2.10/build
-If you want to specify the install location for your files, append
+If you want to specify the install location for your files, append
-DCMAKE_INSTALL_PREFIX=/your/install/path to the cmake call.
-~/expat-2.1.1/build$ make && make test && make install
+~/expat-2.2.10/build$ make && make test && make install
Scanning dependencies of target expat
[ 5%] Building C object CMakeFiles/expat.dir/lib/xmlparse.c.o
[ 11%] Building C object CMakeFiles/expat.dir/lib/xmlrole.c.o
@@ -30,13 +30,13 @@ Scanning dependencies of target expat
-- Installing: /usr/local/bin/xmlwf
-- Installing: /usr/local/share/man/man1/xmlwf.1
-For Windows builds, you must make sure to call cmake from an environment where
-your compiler is reachable, that means either you call it from the
+For Windows builds, you must make sure to call cmake from an environment where
+your compiler is reachable, that means either you call it from the
Visual Studio Command Prompt or when using mingw, you must open a cmd.exe and
-make sure that gcc can be called. On Windows, you also might want to specify a
+make sure that gcc can be called. On Windows, you also might want to specify a
special Generator for CMake:
-for Visual Studio builds do:
-cmake .. -G "Visual Studio 10" && vcexpress expat.sln
-for mingw builds do:
-cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=D:\expat-install
+for Visual Studio builds do:
+cmake .. -G "Visual Studio 15 2017" && msbuild /m expat.sln
+for mingw builds do:
+cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=D:\expat-install
&& gmake && gmake install
diff --git a/3rdparty/expat/CMakeLists.txt b/3rdparty/expat/CMakeLists.txt
index 9e07a5e1b50..dfbd0c5943b 100644
--- a/3rdparty/expat/CMakeLists.txt
+++ b/3rdparty/expat/CMakeLists.txt
@@ -1,83 +1,378 @@
# This file is copyrighted under the BSD-license for buildsystem files of KDE
# copyright 2010, Patrick Spendrin <ps_ml@gmx.de>
-project(expat)
+cmake_minimum_required(VERSION 3.1.3)
+
+# This allows controlling documented build time switches
+# when Expat is pulled in using the add_subdirectory function, e.g.
+#
+# set(EXPAT_BUILD_DOCS OFF)
+# set(EXPAT_BUILD_TOOLS OFF)
+# add_subdirectory(${expat_SOURCE_DIR}/expat ${expat_BINARY_DIR})
+#
+# would disable compilation of the xmlwf CLI and its man page.
+# Without activating behaviour NEW for policy CMP0077 here,
+# a user with -Wdev enabled would see warning
+#
+# Policy CMP0077 is not set: option() honors normal variables. Run "cmake
+# --help-policy CMP0077" for policy details. Use the cmake_policy command to
+# set the policy and suppress this warning.
+#
+# For compatibility with older versions of CMake, option is clearing the
+# normal variable 'EXPAT_BUILD_DOCS'.
+#
+# and effectively not be able to adjust option EXPAT_BUILD_DOCS.
+#
+# For more details please see:
+# - https://cmake.org/cmake/help/latest/policy/CMP0077.html
+# - https://github.com/libexpat/libexpat/pull/419
+#
+if(POLICY CMP0077)
+ cmake_policy(SET CMP0077 NEW)
+endif()
+
+project(expat
+ VERSION
+ 2.2.10
+ LANGUAGES
+ C
+)
-cmake_minimum_required(VERSION 2.6)
set(PACKAGE_BUGREPORT "expat-bugs@libexpat.org")
set(PACKAGE_NAME "expat")
-set(PACKAGE_VERSION "2.1.1")
+set(PACKAGE_VERSION "${PROJECT_VERSION}")
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME "${PACKAGE_NAME}")
-option(BUILD_tools "build the xmlwf tool for expat library" ON)
-option(BUILD_examples "build the examples for expat library" ON)
-option(BUILD_tests "build the tests for expat library" ON)
-option(BUILD_shared "build a shared expat library" ON)
-
-# configuration options
-set(XML_CONTEXT_BYTES 1024 CACHE STRING "Define to specify how much context to retain around the current parse point")
-option(XML_DTD "Define to make parameter entity parsing functionality available" ON)
-option(XML_NS "Define to make XML Namespaces functionality available" ON)
-
-if(XML_DTD)
- set(XML_DTD 1)
-else(XML_DTD)
- set(XML_DTD 0)
-endif(XML_DTD)
-if(XML_NS)
- set(XML_NS 1)
-else(XML_NS)
- set(XML_NS 0)
-endif(XML_NS)
-
-if(BUILD_tests)
- enable_testing()
-endif(BUILD_tests)
+include(CMakePackageConfigHelpers)
+include(GNUInstallDirs)
+
+#
+# Detect use by means of add_subdirectory
+#
+get_directory_property(_EXPAT_PARENT_DIRECTORY PARENT_DIRECTORY)
+
+#
+# Configuration defaults
+#
+if(WINCE)
+ set(_EXPAT_BUILD_TOOLS_DEFAULT OFF)
+else()
+ set(_EXPAT_BUILD_TOOLS_DEFAULT ON)
+endif()
+if(MSVC OR NOT _EXPAT_BUILD_TOOLS_DEFAULT)
+ set(_EXPAT_BUILD_DOCS_DEFAULT OFF)
+else()
+ find_program(DOCBOOK_TO_MAN NAMES docbook2x-man db2x_docbook2man docbook2man docbook-to-man)
+ if(DOCBOOK_TO_MAN)
+ set(_EXPAT_BUILD_DOCS_DEFAULT ON)
+ else()
+ set(_EXPAT_BUILD_DOCS_DEFAULT OFF)
+ endif()
+endif()
+if(MSVC)
+ set(_EXPAT_BUILD_PKGCONFIG_DEFAULT OFF)
+else()
+ set(_EXPAT_BUILD_PKGCONFIG_DEFAULT ON)
+endif()
+
+#
+# Configuration
+#
+option(EXPAT_BUILD_TOOLS "build the xmlwf tool for expat library" ${_EXPAT_BUILD_TOOLS_DEFAULT})
+option(EXPAT_BUILD_EXAMPLES "build the examples for expat library" ON)
+option(EXPAT_BUILD_TESTS "build the tests for expat library" ON)
+option(EXPAT_SHARED_LIBS "build a shared expat library" ON)
+option(EXPAT_BUILD_DOCS "build man page for xmlwf" ${_EXPAT_BUILD_DOCS_DEFAULT})
+option(EXPAT_BUILD_FUZZERS "build fuzzers for the expat library" OFF)
+option(EXPAT_BUILD_PKGCONFIG "build pkg-config file" ${_EXPAT_BUILD_PKGCONFIG_DEFAULT})
+option(EXPAT_OSSFUZZ_BUILD "build fuzzers via ossfuzz for the expat library" OFF)
+if(UNIX OR _EXPAT_HELP)
+ option(EXPAT_WITH_LIBBSD "utilize libbsd (for arc4random_buf)" OFF)
+endif()
+option(EXPAT_ENABLE_INSTALL "install expat files in cmake install target" ON)
+set(EXPAT_CONTEXT_BYTES 1024 CACHE STRING "Define to specify how much context to retain around the current parse point")
+mark_as_advanced(EXPAT_CONTEXT_BYTES)
+option(EXPAT_DTD "Define to make parameter entity parsing functionality available" ON)
+mark_as_advanced(EXPAT_DTD)
+option(EXPAT_NS "Define to make XML Namespaces functionality available" ON)
+mark_as_advanced(EXPAT_NS)
+option(EXPAT_WARNINGS_AS_ERRORS "Treat all compiler warnings as errors" OFF)
+if(UNIX OR _EXPAT_HELP)
+ option(EXPAT_DEV_URANDOM "Define to include code reading entropy from `/dev/urandom'." ON)
+ set(EXPAT_WITH_GETRANDOM "AUTO" CACHE STRING
+ "Make use of getrandom function (ON|OFF|AUTO) [default=AUTO]")
+ set(EXPAT_WITH_SYS_GETRANDOM "AUTO" CACHE STRING
+ "Make use of syscall SYS_getrandom (ON|OFF|AUTO) [default=AUTO]")
+ mark_as_advanced(EXPAT_DEV_URANDOM)
+endif()
+set(EXPAT_CHAR_TYPE "char" CACHE STRING "Character type to use (char|ushort|wchar_t) [default=char]")
+option(EXPAT_ATTR_INFO "Define to allow retrieving the byte offsets for attribute names and values" OFF)
+mark_as_advanced(EXPAT_ATTR_INFO)
+option(EXPAT_LARGE_SIZE "Make XML_GetCurrent* functions return <(unsigned) long long> rather than <(unsigned) long>" OFF)
+mark_as_advanced(EXPAT_LARGE_SIZE)
+option(EXPAT_MIN_SIZE "Get a smaller (but slower) parser (in particular avoid multiple copies of the tokenizer)" OFF)
+mark_as_advanced(EXPAT_MIN_SIZE)
+if(MSVC OR _EXPAT_HELP)
+ set(EXPAT_MSVC_STATIC_CRT OFF CACHE BOOL "Use /MT flag (static CRT) when compiling in MSVC")
+endif()
+
+#
+# Environment checks
+#
+if(EXPAT_WITH_LIBBSD)
+ find_library(LIB_BSD NAMES bsd)
+ if(NOT LIB_BSD)
+ message(SEND_ERROR "EXPAT_WITH_LIBBSD option is enabled, but libbsd was not found")
+ else()
+ set(HAVE_LIBBSD TRUE)
+ endif()
+endif()
+
+macro(_expat_copy_bool_int source_ref dest_ref)
+ if(${source_ref})
+ set(${dest_ref} 1)
+ else()
+ set(${dest_ref} 0)
+ endif()
+endmacro()
+
+if(EXPAT_LARGE_SIZE)
+ add_definitions(-DXML_LARGE_SIZE)
+endif()
+
+if(EXPAT_MIN_SIZE)
+ add_definitions(-DXML_MIN_SIZE)
+endif()
+
+if(EXPAT_CHAR_TYPE STREQUAL "char")
+ set(_EXPAT_UNICODE OFF)
+ set(_EXPAT_UNICODE_WCHAR_T OFF)
+elseif(EXPAT_CHAR_TYPE STREQUAL "ushort")
+ set(_EXPAT_UNICODE ON)
+ set(_EXPAT_UNICODE_WCHAR_T OFF)
+ if(EXPAT_BUILD_EXAMPLES)
+ message(SEND_ERROR "Examples can not be built with option -DEXPAT_CHAR_TYPE=ushort. Please pass -DEXPAT_CHAR_TYPE=(char|wchar_t) or -DEXPAT_BUILD_EXAMPLES=OFF.")
+ endif()
+ if(EXPAT_BUILD_TESTS)
+ message(SEND_ERROR "The testsuite can not be built with option -DEXPAT_CHAR_TYPE=ushort. Please pass -DEXPAT_CHAR_TYPE=(char|wchar_t) or -DEXPAT_BUILD_TESTS=OFF.")
+ endif()
+ if(EXPAT_BUILD_TOOLS)
+ message(SEND_ERROR "The xmlwf tool can not be built with option -DEXPAT_CHAR_TYPE=ushort. Please pass -DEXPAT_CHAR_TYPE=(char|wchar_t) or -DEXPAT_BUILD_TOOLS=OFF.")
+ endif()
+elseif(EXPAT_CHAR_TYPE STREQUAL "wchar_t")
+ set(_EXPAT_UNICODE ON)
+ set(_EXPAT_UNICODE_WCHAR_T ON)
+ if(NOT WIN32)
+ string(FIND "${CMAKE_C_FLAGS}" "-fshort-wchar" _expat_short_wchar_found)
+ if(${_expat_short_wchar_found} EQUAL "-1")
+ message(SEND_ERROR "Configuration -DEXPAT_CHAR_TYPE=wchar_t requires -DCMAKE_{C,CXX}_FLAGS=-fshort-wchar (which was not found) and libc compiled with -fshort-wchar, too.")
+ endif()
+ if (EXPAT_BUILD_TOOLS)
+ message(SEND_ERROR "The xmlwf tool can not be built with option -DEXPAT_CHAR_TYPE=wchar_t outside of Windows. Please pass -DEXPAT_CHAR_TYPE=char or -DEXPAT_BUILD_TOOLS=OFF.")
+ endif()
+ endif()
+else()
+ message(SEND_ERROR "Option -DEXPAT_CHAR_TYPE=(char|ushort|wchar_t) cannot be \"${EXPAT_CHAR_TYPE}\".")
+endif()
+
+if(_EXPAT_UNICODE)
+ add_definitions(-DXML_UNICODE) # for unsigned short
+ if(_EXPAT_UNICODE_WCHAR_T)
+ add_definitions(-DXML_UNICODE_WCHAR_T) # for wchar_t
+ endif()
+endif()
+
+include(${CMAKE_CURRENT_LIST_DIR}/ConfigureChecks.cmake)
+
+macro(evaluate_detection_results use_ref have_ref thing_lower thing_title)
+ if(${use_ref} AND NOT (${use_ref} STREQUAL "AUTO") AND NOT ${have_ref})
+ message(SEND_ERROR
+ "Use of ${thing_lower} was enforced by ${use_ref}=ON but it could not be found.")
+ elseif(NOT ${use_ref} AND ${have_ref})
+ message("${thing_title} was found but it will not be used due to ${use_ref}=OFF.")
+ set(${have_ref} 0)
+ endif()
+endmacro()
-include(ConfigureChecks.cmake)
+if(NOT WIN32)
+ evaluate_detection_results(EXPAT_WITH_GETRANDOM HAVE_GETRANDOM "function getrandom" "Function getrandom")
+ evaluate_detection_results(EXPAT_WITH_SYS_GETRANDOM HAVE_SYSCALL_GETRANDOM "syscall SYS_getrandom" "Syscall SYS_getrandom")
+endif()
-include_directories(${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/lib)
+_expat_copy_bool_int(EXPAT_ATTR_INFO XML_ATTR_INFO)
+_expat_copy_bool_int(EXPAT_DTD XML_DTD)
+_expat_copy_bool_int(EXPAT_LARGE_SIZE XML_LARGE_SIZE)
+_expat_copy_bool_int(EXPAT_MIN_SIZE XML_MIN_SIZE)
+_expat_copy_bool_int(EXPAT_NS XML_NS)
+if(NOT WIN32)
+ _expat_copy_bool_int(EXPAT_DEV_URANDOM XML_DEV_URANDOM)
+endif()
+set(XML_CONTEXT_BYTES ${EXPAT_CONTEXT_BYTES})
+
+macro(expat_install)
+ if(EXPAT_ENABLE_INSTALL)
+ install(${ARGN})
+ endif()
+endmacro()
+
+configure_file(expat_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/expat_config.h")
+add_definitions(-DHAVE_EXPAT_CONFIG_H)
+expat_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/expat_config.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+
+set(EXTRA_COMPILE_FLAGS)
+if(FLAG_NO_STRICT_ALIASING)
+ set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -fno-strict-aliasing")
+endif()
+if(FLAG_VISIBILITY)
+ add_definitions(-DXML_ENABLE_VISIBILITY=1)
+ set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -fvisibility=hidden")
+endif()
+if (EXPAT_WARNINGS_AS_ERRORS)
+ if(MSVC)
+ add_definitions(/WX)
+ else()
+ set(EXTRA_COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -Werror")
+ endif()
+endif()
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_COMPILE_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_COMPILE_FLAGS}")
+
+if (MSVC)
+ if (EXPAT_MSVC_STATIC_CRT)
+ message("-- Using static CRT ${EXPAT_MSVC_STATIC_CRT}")
+ foreach(flag_var
+ CMAKE_CXX_FLAGS_DEBUG
+ CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL
+ CMAKE_CXX_FLAGS_RELWITHDEBINFO
+ CMAKE_C_FLAGS_DEBUG
+ CMAKE_C_FLAGS_RELEASE
+ CMAKE_C_FLAGS_MINSIZEREL
+ CMAKE_C_FLAGS_RELWITHDEBINFO
+ )
+ string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endforeach()
+ endif()
+endif()
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -wd4996)
-endif(MSVC)
+endif()
+if(WIN32)
+ if(_EXPAT_UNICODE_WCHAR_T)
+ set(_POSTFIX_WIDE "w")
+ endif()
+
+ if(MSVC AND NOT EXPAT_SHARED_LIBS)
+ if(EXPAT_MSVC_STATIC_CRT)
+ set(_POSTFIX_CRT "MT")
+ else()
+ set(_POSTFIX_CRT "MD")
+ endif()
+ endif()
+
+ foreach(postfix_var
+ CMAKE_DEBUG_POSTFIX
+ CMAKE_RELEASE_POSTFIX
+ CMAKE_MINSIZEREL_POSTFIX
+ CMAKE_RELWITHDEBINFO_POSTFIX
+ )
+ if(postfix_var STREQUAL "CMAKE_DEBUG_POSTFIX")
+ set(_POSTFIX_DEBUG "d")
+ else()
+ set(_POSTFIX_DEBUG "")
+ endif()
+ set(${postfix_var} "${_POSTFIX_WIDE}${_POSTFIX_DEBUG}${_POSTFIX_CRT}" CACHE STRING "Windows binary postfix, e.g. libexpat<postfix=[w][d][MD|MT]>.lib")
+ endforeach()
+endif()
+
+#
+# C library
+#
set(expat_SRCS
lib/xmlparse.c
lib/xmlrole.c
- lib/xmltok.c
- lib/xmltok_impl.c
- lib/xmltok_ns.c
+ lib/xmltok.c
+# NOTE: ISO C forbids an empty translation unit
+# lib/xmltok_impl.c
+# lib/xmltok_ns.c
)
-if(WIN32 AND BUILD_shared)
- set(expat_SRCS ${expat_SRCS} lib/libexpat.def)
-endif(WIN32 AND BUILD_shared)
-
-if(BUILD_shared)
+if(EXPAT_SHARED_LIBS)
set(_SHARED SHARED)
-else(BUILD_shared)
+ if(MSVC)
+ set(expat_SRCS ${expat_SRCS} lib/libexpat.def)
+ endif()
+else()
set(_SHARED STATIC)
-endif(BUILD_shared)
+endif()
+
+# Avoid colliding with Expat.dll of Perl's XML::Parser::Expat
+if(WIN32 AND NOT MINGW)
+ set(_EXPAT_OUTPUT_NAME libexpat) # CMAKE_*_POSTFIX applies, see above
+else()
+ if(_EXPAT_UNICODE)
+ set(_EXPAT_OUTPUT_NAME expatw)
+ else()
+ set(_EXPAT_OUTPUT_NAME expat)
+ endif()
+endif()
add_library(expat ${_SHARED} ${expat_SRCS})
+if(EXPAT_WITH_LIBBSD)
+ target_link_libraries(expat ${LIB_BSD})
+endif()
+
+set(LIBCURRENT 7) # sync
+set(LIBREVISION 12) # with
+set(LIBAGE 6) # configure.ac!
+math(EXPR LIBCURRENT_MINUS_AGE "${LIBCURRENT} - ${LIBAGE}")
-install(TARGETS expat RUNTIME DESTINATION bin
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib)
+set_property(TARGET expat PROPERTY OUTPUT_NAME "${_EXPAT_OUTPUT_NAME}")
+if(NOT WIN32)
+ set_property(TARGET expat PROPERTY VERSION ${LIBCURRENT_MINUS_AGE}.${LIBAGE}.${LIBREVISION})
+ set_property(TARGET expat PROPERTY SOVERSION ${LIBCURRENT_MINUS_AGE})
+ set_property(TARGET expat PROPERTY NO_SONAME ${NO_SONAME})
+endif()
-set(prefix ${CMAKE_INSTALL_PREFIX})
-set(exec_prefix "\${prefix}/bin")
-set(libdir "\${prefix}/lib")
-set(includedir "\${prefix}/include")
-configure_file(expat.pc.in ${CMAKE_CURRENT_BINARY_DIR}/expat.pc)
+target_include_directories(expat
+ INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+if(NOT EXPAT_SHARED_LIBS AND WIN32)
+ target_compile_definitions(expat PUBLIC -DXML_STATIC)
+endif()
-install(FILES lib/expat.h lib/expat_external.h DESTINATION include)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/expat.pc DESTINATION lib/pkgconfig)
+expat_install(TARGETS expat EXPORT expat
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+expat_install(FILES lib/expat.h lib/expat_external.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+#
+# pkg-config file
+#
+if(EXPAT_BUILD_PKGCONFIG)
+ set(prefix ${CMAKE_INSTALL_PREFIX})
+ set(exec_prefix "\${prefix}")
+ set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+ set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+ configure_file(expat.pc.in ${CMAKE_CURRENT_BINARY_DIR}/expat.pc @ONLY)
+ expat_install(FILES ${CMAKE_CURRENT_BINARY_DIR}/expat.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+endif()
-if(BUILD_tools AND NOT WINCE)
+#
+# C command line tool xmlwf
+#
+if(EXPAT_BUILD_TOOLS)
set(xmlwf_SRCS
xmlwf/xmlwf.c
xmlwf/xmlfile.c
@@ -88,11 +383,32 @@ if(BUILD_tools AND NOT WINCE)
add_executable(xmlwf ${xmlwf_SRCS})
set_property(TARGET xmlwf PROPERTY RUNTIME_OUTPUT_DIRECTORY xmlwf)
target_link_libraries(xmlwf expat)
- install(TARGETS xmlwf DESTINATION bin)
- install(FILES doc/xmlwf.1 DESTINATION share/man/man1)
-endif(BUILD_tools AND NOT WINCE)
+ expat_install(TARGETS xmlwf DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+ if(MINGW AND _EXPAT_UNICODE_WCHAR_T)
+ # https://gcc.gnu.org/onlinedocs/gcc/x86-Windows-Options.html
+ set_target_properties(xmlwf PROPERTIES LINK_FLAGS -municode)
+ endif()
+
+ if(EXPAT_BUILD_DOCS)
+ file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc)
+ add_custom_target(
+ xmlwf-manpage
+ COMMAND
+ "${DOCBOOK_TO_MAN}" "${PROJECT_SOURCE_DIR}/doc/xmlwf.xml" && mv "XMLWF.1" "${PROJECT_BINARY_DIR}/doc/xmlwf.1"
+ BYPRODUCTS
+ doc/xmlwf.1)
+ add_dependencies(expat xmlwf-manpage)
+ expat_install(FILES "${PROJECT_BINARY_DIR}/doc/xmlwf.1" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+ elseif(EXISTS ${PROJECT_SOURCE_DIR}/doc/xmlwf.1)
+ expat_install(FILES "${PROJECT_SOURCE_DIR}/doc/xmlwf.1" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+ endif()
+endif()
-if(BUILD_examples)
+#
+# C code examples
+#
+if(EXPAT_BUILD_EXAMPLES)
add_executable(elements examples/elements.c)
set_property(TARGET elements PROPERTY RUNTIME_OUTPUT_DIRECTORY examples)
target_link_libraries(elements expat)
@@ -100,17 +416,298 @@ if(BUILD_examples)
add_executable(outline examples/outline.c)
set_property(TARGET outline PROPERTY RUNTIME_OUTPUT_DIRECTORY examples)
target_link_libraries(outline expat)
-endif(BUILD_examples)
+endif()
-if(BUILD_tests)
+#
+# C/C++ test runners
+#
+if(EXPAT_BUILD_TESTS)
## these are unittests that can be run on any platform
- add_executable(runtests tests/runtests.c tests/chardata.c tests/minicheck.c)
+ enable_language(CXX)
+ enable_testing()
+
+ set(test_SRCS
+ tests/chardata.c
+ tests/memcheck.c
+ tests/minicheck.c
+ tests/structdata.c
+ )
+
+ if(NOT MSVC)
+ if(MINGW)
+ set(host whatever-mingw32) # for nothing but run.sh
+ endif()
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run.sh.in run.sh @ONLY)
+ endif()
+
+ function(expat_add_test _name _file)
+ if(MSVC)
+ add_test(NAME ${_name} COMMAND ${_file})
+ else()
+ add_test(NAME ${_name} COMMAND bash run.sh ${_file})
+ endif()
+ endfunction()
+
+ add_executable(runtests tests/runtests.c ${test_SRCS})
set_property(TARGET runtests PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
target_link_libraries(runtests expat)
- add_test(runtests tests/runtests)
+ expat_add_test(runtests $<TARGET_FILE:runtests>)
- add_executable(runtestspp tests/runtestspp.cpp tests/chardata.c tests/minicheck.c)
+ add_executable(runtestspp tests/runtestspp.cpp ${test_SRCS})
set_property(TARGET runtestspp PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
target_link_libraries(runtestspp expat)
- add_test(runtestspp tests/runtestspp)
-endif(BUILD_tests)
+ expat_add_test(runtestspp $<TARGET_FILE:runtestspp>)
+endif()
+
+if(EXPAT_BUILD_FUZZERS)
+ if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
+ message(SEND_ERROR
+ "Building fuzz targets without Clang (but ${CMAKE_C_COMPILER_ID}) "
+ "is not supported. Please set "
+ "-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++.")
+ endif()
+
+ string(FIND "${CMAKE_C_FLAGS}" "-fsanitize" sanitizer_present)
+ if(${sanitizer_present} EQUAL "-1")
+ message(WARNING
+ "There was no sanitizer present when building the fuzz targets. "
+ "This is likely in error - consider adding "
+ "-DCMAKE_C_FLAGS='-fsanitize=<sanitizer>' and "
+ "-DCMAKE_CXX_FLAGS='-fsanitize=<sanitizer>' and "
+ "-DCMAKE_EXE_LINKER_FLAGS='-fsanitize=<sanitizer>' and "
+ "-DCMAKE_MODULE_LINKER_FLAGS='-fsanitize=<sanitizer>' and "
+ "-DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=<sanitizer>' to your cmake "
+ "execution.")
+ endif()
+
+ if(EXPAT_OSSFUZZ_BUILD AND NOT DEFINED ENV{LIB_FUZZING_ENGINE})
+ message(SEND_ERROR
+ "OSS-Fuzz builds require the environment variable "
+ "LIB_FUZZING_ENGINE to be set. If you are seeing this "
+ "warning, it points to a deeper problem in the ossfuzz "
+ "build setup.")
+ endif()
+
+ set(encoding_types UTF-16 UTF-8 ISO-8859-1 US-ASCII UTF-16BE UTF-16LE)
+ set(fuzz_targets xml_parse_fuzzer xml_parsebuffer_fuzzer)
+
+ add_library(fuzzpat STATIC ${expat_SRCS})
+ if(NOT EXPAT_OSSFUZZ_BUILD)
+ target_compile_options(fuzzpat PRIVATE -fsanitize=fuzzer-no-link)
+ endif()
+
+ foreach(fuzz_target ${fuzz_targets})
+ foreach(encoding_type ${encoding_types})
+ set(target_name ${fuzz_target}_${encoding_type})
+ add_executable(${target_name} fuzz/${fuzz_target}.c)
+ target_link_libraries(${target_name} fuzzpat)
+ target_compile_definitions(${target_name}
+ PRIVATE ENCODING_FOR_FUZZING=${encoding_type})
+ if(NOT EXPAT_OSSFUZZ_BUILD)
+ target_compile_options(${target_name} PRIVATE -fsanitize=fuzzer-no-link)
+ endif()
+ # NOTE: Avoiding target_link_options here only because it needs CMake >=3.13
+ if(EXPAT_OSSFUZZ_BUILD)
+ set_target_properties(${target_name} PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})
+ set_target_properties(${target_name} PROPERTIES LINKER_LANGUAGE "CXX")
+ else()
+ set_target_properties(${target_name} PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
+ endif()
+ set_property(
+ TARGET ${target_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY fuzz)
+ endforeach()
+ endforeach()
+else()
+ if(EXPAT_OSSFUZZ_BUILD)
+ message(SEND_ERROR
+ "Attempting to perform an ossfuzz build without turning on the fuzzer build. "
+ "This is likely in error - consider adding "
+ "-DEXPAT_BUILD_FUZZERS=ON to your cmake execution.")
+ endif()
+endif()
+
+#
+# Custom target "run-xmltest"
+#
+if(EXPAT_BUILD_TOOLS AND NOT MSVC)
+ add_custom_target(
+ xmlts-zip-downloaded
+ COMMAND
+ sh -c 'test -f xmlts.zip || wget --output-document=xmlts.zip https://www.w3.org/XML/Test/xmlts20080827.zip'
+ BYPRODUCTS
+ tests/xmlts.zip
+ WORKING_DIRECTORY
+ tests/)
+
+ add_custom_target(
+ xmlts-zip-extracted
+ COMMAND
+ sh -c 'test -d xmlconf || unzip -q xmlts.zip'
+ BYPRODUCTS
+ tests/xmlconf
+ WORKING_DIRECTORY
+ tests/)
+ add_dependencies(xmlts-zip-extracted xmlts-zip-downloaded)
+
+ add_custom_target(
+ xmltest-sh-been-run
+ COMMAND
+ sh -c '${CMAKE_CURRENT_SOURCE_DIR}/tests/xmltest.sh "bash ${CMAKE_CURRENT_BINARY_DIR}/run.sh $<TARGET_FILE:xmlwf>" 2>&1 | tee tests/xmltest.log'
+ BYPRODUCTS
+ tests/xmltest.log)
+ add_dependencies(xmltest-sh-been-run xmlts-zip-extracted xmlwf)
+
+ add_custom_target(
+ xmltest-log-fixed
+ COMMAND
+ ${CMAKE_CURRENT_SOURCE_DIR}/fix-xmltest-log.sh tests/xmltest.log
+ DEPENDS
+ tests/xmltest.log)
+ add_dependencies(xmltest-log-fixed xmltest-sh-been-run)
+
+ add_custom_target(
+ xmltest-log-verified
+ COMMAND
+ diff -u ${CMAKE_CURRENT_SOURCE_DIR}/tests/xmltest.log.expected tests/xmltest.log)
+ add_dependencies(xmltest-log-verified xmltest-log-fixed)
+
+ add_custom_target(run-xmltest)
+ add_dependencies(run-xmltest xmltest-log-verified)
+endif()
+
+#
+# Documentation
+#
+configure_file(Changes changelog COPYONLY)
+expat_install(
+ FILES
+ AUTHORS
+ ${CMAKE_CURRENT_BINARY_DIR}/changelog
+ DESTINATION
+ ${CMAKE_INSTALL_DOCDIR})
+
+#
+# CMake files for find_package(expat [..] CONFIG [..])
+#
+configure_package_config_file(
+ cmake/expat-config.cmake.in
+ cmake/expat-config.cmake
+ INSTALL_DESTINATION
+ ${CMAKE_INSTALL_LIBDIR}/cmake/expat-${PROJECT_VERSION}/
+)
+write_basic_package_version_file(
+ cmake/expat-config-version.cmake
+ COMPATIBILITY SameMajorVersion # i.e. semver
+)
+export(
+ TARGETS
+ expat
+ FILE
+ cmake/expat-targets.cmake # not going to be installed
+)
+expat_install(
+ FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/cmake/expat-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/cmake/expat-config-version.cmake
+ DESTINATION
+ ${CMAKE_INSTALL_LIBDIR}/cmake/expat-${PROJECT_VERSION}/
+)
+expat_install(
+ EXPORT
+ expat
+ DESTINATION
+ ${CMAKE_INSTALL_LIBDIR}/cmake/expat-${PROJECT_VERSION}/
+ NAMESPACE
+ expat::
+)
+
+#
+# CPack
+#
+
+# This effectively disables target "package_source".
+# That is done due to CPack's unfortunate choice of an exclusion list
+# rather than inclusion list. An exclusion list does not protect against
+# unwanted files ending up in the resulting archive in a way that's
+# safe to run from an Expat developer's machine.
+set(CPACK_SOURCE_GENERATOR '')
+
+if(WIN32)
+ set(CPACK_GENERATOR ZIP)
+else()
+ set(CPACK_GENERATOR TGZ)
+endif()
+
+include(CPack)
+
+#
+# Summary
+#
+if(EXPAT_CHAR_TYPE STREQUAL "char")
+ set(_EXPAT_CHAR_TYPE_SUMMARY "char (UTF-8)")
+elseif(EXPAT_CHAR_TYPE STREQUAL "ushort")
+ set(_EXPAT_CHAR_TYPE_SUMMARY "ushort (unsigned short, UTF-16)")
+elseif(EXPAT_CHAR_TYPE STREQUAL "wchar_t")
+ if(WIN32)
+ set(_EXPAT_CHAR_TYPE_SUMMARY "wchar_t (UTF-16)")
+ else()
+ set(_EXPAT_CHAR_TYPE_SUMMARY "wchar_t (UTF-32) // not implemented")
+ endif()
+else()
+ set(_EXPAT_CHAR_TYPE_SUMMARY "ERROR")
+endif()
+string(TOUPPER "${CMAKE_BUILD_TYPE}" _EXPAT_BUILD_TYPE_UPPER)
+
+message(STATUS "===========================================================================")
+message(STATUS "")
+message(STATUS "Configuration")
+message(STATUS " Prefix ..................... ${CMAKE_INSTALL_PREFIX}")
+message(STATUS " Build type ................. ${CMAKE_BUILD_TYPE}")
+message(STATUS " Shared libraries ........... ${EXPAT_SHARED_LIBS}")
+if(MSVC)
+ message(STATUS " Static CRT ................. ${EXPAT_MSVC_STATIC_CRT}")
+endif()
+message(STATUS " Character type ............. ${_EXPAT_CHAR_TYPE_SUMMARY}")
+if(WIN32)
+ message(STATUS " Binary postfix ............. ${CMAKE_${_EXPAT_BUILD_TYPE_UPPER}_POSTFIX}")
+endif()
+message(STATUS "")
+message(STATUS " Build documentation ........ ${EXPAT_BUILD_DOCS}")
+message(STATUS " Build examples ............. ${EXPAT_BUILD_EXAMPLES}")
+message(STATUS " Build fuzzers .............. ${EXPAT_BUILD_FUZZERS}")
+message(STATUS " Build tests ................ ${EXPAT_BUILD_TESTS}")
+message(STATUS " Build tools (xmlwf) ........ ${EXPAT_BUILD_TOOLS}")
+message(STATUS " Build pkg-config file ...... ${EXPAT_BUILD_PKGCONFIG}")
+message(STATUS " Install files .............. ${EXPAT_ENABLE_INSTALL}")
+message(STATUS "")
+message(STATUS " Features")
+message(STATUS " // Advanced options, changes not advised")
+message(STATUS " Attributes info .......... ${EXPAT_ATTR_INFO}")
+message(STATUS " Context bytes ............ ${EXPAT_CONTEXT_BYTES}")
+message(STATUS " DTD support .............. ${EXPAT_DTD}")
+message(STATUS " Large size ............... ${EXPAT_LARGE_SIZE}")
+message(STATUS " Minimum size ............. ${EXPAT_MIN_SIZE}")
+message(STATUS " Namespace support ........ ${EXPAT_NS}")
+message(STATUS "")
+message(STATUS " Entropy sources")
+if(WIN32)
+ message(STATUS " rand_s ................... ON")
+else()
+ message(STATUS " getrandom ................ ${HAVE_GETRANDOM}")
+ message(STATUS " syscall SYS_getrandom .... ${HAVE_SYSCALL_GETRANDOM}")
+ message(STATUS " libbsd ................... ${EXPAT_WITH_LIBBSD}")
+ message(STATUS " /dev/random .............. ${EXPAT_DEV_URANDOM}")
+endif()
+message(STATUS "")
+if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
+ message(STATUS "Continue with")
+ message(STATUS " make")
+ if(EXPAT_BUILD_TESTS)
+ message(STATUS " make test")
+ endif()
+ if(EXPAT_ENABLE_INSTALL)
+ message(STATUS " sudo make install")
+ endif()
+ message(STATUS "")
+endif()
+message(STATUS "===========================================================================")
diff --git a/3rdparty/expat/COPYING b/3rdparty/expat/COPYING
index dcb45064296..3c0142e71c8 100644
--- a/3rdparty/expat/COPYING
+++ b/3rdparty/expat/COPYING
@@ -1,6 +1,5 @@
-Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- and Clark Cooper
-Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
+Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
+Copyright (c) 2001-2019 Expat maintainers
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/3rdparty/expat/Changes b/3rdparty/expat/Changes
index db5f7f32eb4..b74a7c56a96 100644
--- a/3rdparty/expat/Changes
+++ b/3rdparty/expat/Changes
@@ -1,3 +1,599 @@
+NOTE: We are looking for help with a few things:
+ https://github.com/libexpat/libexpat/labels/help%20wanted
+ If you can help, please get in touch. Thanks!
+
+Release 2.2.10 Sat October 3 2020
+ Bug fixes:
+ #390 #395 #398 Fix undefined behavior during parsing caused by
+ pointer arithmetic with NULL pointers
+ #404 #405 Fix reading uninitialized variable during parsing
+ #406 xmlwf: Add missing check for malloc NULL return
+
+ Other changes:
+ #396 Windows: Drop support for Visual Studio <=8.0/2005
+ #409 Windows: Add missing file "Changes" to the installer
+ to fix compilation with CMake from installed sources
+ #403 xmlwf: Document exit codes in xmlwf manpage and
+ exit with code 3 (rather than code 1) for output errors
+ when used with "-d DIRECTORY"
+ #356 #359 MinGW: Provide declaration of rand_s for mingwrt <5.3.0
+ #383 #392 Autotools: Use -Werror while configure tests the compiler
+ for supported compile flags to avoid false positives
+ #383 #393 #394 Autotools: Improve handling of user (C|CPP|CXX|LD)FLAGS,
+ e.g. ensure that they have the last word over flags added
+ while running ./configure
+ #360 CMake: Create libexpatw.{dll,so} and expatw.pc (with emphasis
+ on suffix "w") with -DEXPAT_CHAR_TYPE=(ushort|wchar_t)
+ #360 CMake: Detect and deny unsupported build combinations
+ involving -DEXPAT_CHAR_TYPE=(ushort|wchar_t)
+ #360 CMake: Install pre-compiled shipped xmlwf.1 manpage in case
+ of -DEXPAT_BUILD_DOCS=OFF
+ #375 #380 #419 CMake: Fix use of Expat by means of add_subdirectory
+ #407 #408 CMake: Keep expat target name constant at "expat"
+ (i.e. refrain from using the target name to control
+ build artifact filenames)
+ #385 CMake: Fix compilation with -DEXPAT_SHARED_LIBS=OFF for
+ Windows
+ CMake: Expose man page compilation as target "xmlwf-manpage"
+ #413 #414 CMake: Introduce option EXPAT_BUILD_PKGCONFIG
+ to control generation of pkg-config file "expat.pc"
+ #424 CMake: Add minimalistic support for building binary packages
+ with CMake target "package"; based on CPack
+ #366 CMake: Add option -DEXPAT_OSSFUZZ_BUILD=(ON|OFF) with
+ default OFF to build fuzzer code against OSS-Fuzz and
+ related environment variable LIB_FUZZING_ENGINE
+ #354 Fix testsuite for -DEXPAT_DTD=OFF and -DEXPAT_NS=OFF, each
+ #354 #355 ..
+ #356 #412 Address compiler warnings
+ #368 #369 Address pngcheck warnings with doc/*.png images
+ Version info bumped from 7:11:6 to 7:12:6
+
+ Special thanks to:
+ asavah
+ Ben Wagner
+ Bhargava Shastry
+ Frank Landgraf
+ Jeffrey Walton
+ Joe Orton
+ Kleber Tarcísio
+ Ma Lin
+ Maciej Sroczyński
+ Mohammed Khajapasha
+ Vadim Zeitlin
+ and
+ Cppcheck 2.0 and the Cppcheck team
+
+Release 2.2.9 Wed September 25 2019
+ Other changes:
+ examples: Drop executable bits from elements.c
+ #349 Windows: Change the name of the Windows DLLs from expat*.dll
+ to libexpat*.dll once more (regression from 2.2.8, first
+ fixed in 1.95.3, issue #61 on SourceForge today,
+ was issue #432456 back then); needs a fix due
+ case-insensitive file systems on Windows and the fact that
+ Perl's XML::Parser::Expat compiles into Expat.dll.
+ #347 Windows: Only define _CRT_RAND_S if not defined
+ Version info bumped from 7:10:6 to 7:11:6
+
+ Special thanks to:
+ Ben Wagner
+
+Release 2.2.8 Fri September 13 2019
+ Security fixes:
+ #317 #318 CVE-2019-15903 -- Fix heap overflow triggered by
+ XML_GetCurrentLineNumber (or XML_GetCurrentColumnNumber),
+ and deny internal entities closing the doctype;
+ fixed in commit c20b758c332d9a13afbbb276d30db1d183a85d43
+
+ Bug fixes:
+ #240 Fix cases where XML_StopParser did not have any effect
+ when called from inside of an end element handler
+ #341 xmlwf: Fix exit code for operation without "-d DIRECTORY";
+ previously, only "-d DIRECTORY" would give you a proper
+ exit code:
+ # xmlwf -d . <<<'<not well-formed>' 2>/dev/null ; echo $?
+ 2
+ # xmlwf <<<'<not well-formed>' 2>/dev/null ; echo $?
+ 0
+ Now both cases return exit code 2.
+
+ Other changes:
+ #299 #302 Windows: Replace LoadLibrary hack to access
+ unofficial API function SystemFunction036 (RtlGenRandom)
+ by using official API function rand_s (needs WinXP+)
+ #325 Windows: Drop support for Visual Studio <=7.1/2003
+ and document supported compilers in README.md
+ #286 Windows: Remove COM code from xmlwf; in case it turns
+ out needed later, there will be a dedicated repository
+ below https://github.com/libexpat/ for that code
+ #322 Windows: Remove explicit MSVC solution and project files.
+ You can generate Visual Studio solution files through
+ CMake, e.g.: cmake -G"Visual Studio 15 2017" .
+ #338 xmlwf: Make "xmlwf -h" help output more friendly
+ #339 examples: Improve elements.c
+ #244 #264 Autotools: Add argument --enable-xml-attr-info
+ #239 #301 Autotools: Add arguments
+ --with-getrandom
+ --without-getrandom
+ --with-sys-getrandom
+ --without-sys-getrandom
+ #312 #343 Autotools: Fix linking issues with "./configure LD=clang"
+ Autotools: Fix "make run-xmltest" for out-of-source builds
+ #329 #336 CMake: Pull all options from Expat <=2.2.7 into namespace
+ prefix EXPAT_ with the exception of DOCBOOK_TO_MAN:
+ - BUILD_doc -> EXPAT_BUILD_DOCS (plural)
+ - BUILD_examples -> EXPAT_BUILD_EXAMPLES
+ - BUILD_shared -> EXPAT_SHARED_LIBS
+ - BUILD_tests -> EXPAT_BUILD_TESTS
+ - BUILD_tools -> EXPAT_BUILD_TOOLS
+ - DOCBOOK_TO_MAN -> DOCBOOK_TO_MAN (unchanged)
+ - INSTALL -> EXPAT_ENABLE_INSTALL
+ - MSVC_USE_STATIC_CRT -> EXPAT_MSVC_STATIC_CRT
+ - USE_libbsd -> EXPAT_WITH_LIBBSD
+ - WARNINGS_AS_ERRORS -> EXPAT_WARNINGS_AS_ERRORS
+ - XML_CONTEXT_BYTES -> EXPAT_CONTEXT_BYTES
+ - XML_DEV_URANDOM -> EXPAT_DEV_URANDOM
+ - XML_DTD -> EXPAT_DTD
+ - XML_NS -> EXPAT_NS
+ - XML_UNICODE -> EXPAT_CHAR_TYPE=ushort (!)
+ - XML_UNICODE_WCHAR_T -> EXPAT_CHAR_TYPE=wchar_t (!)
+ #244 #264 CMake: Add argument -DEXPAT_ATTR_INFO=(ON|OFF),
+ default OFF
+ #326 CMake: Add argument -DEXPAT_LARGE_SIZE=(ON|OFF),
+ default OFF
+ #328 CMake: Add argument -DEXPAT_MIN_SIZE=(ON|OFF),
+ default OFF
+ #239 #277 CMake: Add arguments
+ -DEXPAT_WITH_GETRANDOM=(ON|OFF|AUTO), default AUTO
+ -DEXPAT_WITH_SYS_GETRANDOM=(ON|OFF|AUTO), default AUTO
+ #326 CMake: Install expat_config.h to include directory
+ #326 CMake: Generate and install configuration files for
+ future find_package(expat [..] CONFIG [..])
+ CMake: Now produces a summary of applied configuration
+ CMake: Require C++ compiler only when tests are enabled
+ #330 CMake: Fix compilation for 16bit character types,
+ i.e. ex -DXML_UNICODE=ON (and ex -DXML_UNICODE_WCHAR_T=ON)
+ #265 CMake: Fix linking with MinGW
+ #330 CMake: Add full support for MinGW; to enable, use
+ -DCMAKE_TOOLCHAIN_FILE=[expat]/cmake/mingw-toolchain.cmake
+ #330 CMake: Port "make run-xmltest" from GNU Autotools to CMake
+ #316 CMake: Windows: Make binary postfix match MSVC
+ Old: expat[d].lib
+ New: expat[w][d][MD|MT].lib
+ CMake: Migrate files from Windows to Unix line endings
+ #308 CMake: Integrate OSS-Fuzz fuzzers, option
+ -DEXPAT_BUILD_FUZZERS=(ON|OFF), default OFF
+ #14 Drop an OpenVMS support leftover
+ #235 #268 ..
+ #270 #310 ..
+ #313 #331 #333 Address compiler warnings
+ #282 #283 ..
+ #284 #285 Address cppcheck warnings
+ #294 #295 Address Clang Static Analyzer warnings
+ #24 #293 Mass-apply clang-format 9 (and ensure conformance during CI)
+ Version info bumped from 7:9:6 to 7:10:6
+
+ Special thanks to:
+ David Loffredo
+ Joonun Jang
+ Kishore Kunche
+ Marco Maggi
+ Mitch Phillips
+ Mohammed Khajapasha
+ Rolf Ade
+ xantares
+ Zhongyuan Zhou
+
+Release 2.2.7 Wed June 19 2019
+ Security fixes:
+ #186 #262 CVE-2018-20843 -- Fix extraction of namespace prefixes from
+ XML names; XML names with multiple colons could end up in
+ the wrong namespace, and take a high amount of RAM and CPU
+ resources while processing, opening the door to
+ use for denial-of-service attacks
+
+ Other changes:
+ #195 #197 Autotools/CMake: Utilize -fvisibility=hidden to stop
+ exporting non-API symbols
+ #227 Autotools: Add --without-examples and --without-tests
+ #228 Autotools: Modernize configure.ac
+ #245 #246 Autotools: Fix check for -fvisibility=hidden for Clang
+ #247 #248 Autotools: Fix compilation for lack of docbook2x-man
+ #236 #258 Autotools: Produce .tar.{gz,lz,xz} release archives
+ #212 CMake: Make libdir of pkgconfig expat.pc support multilib
+ #158 #263 CMake: Build man page in PROJECT_BINARY_DIR not _SOURCE_DIR
+ #219 Remove fallback to bcopy, assume that memmove(3) exists
+ #257 Use portable "/usr/bin/env bash" shebang (e.g. for OpenBSD)
+ #243 Windows: Fix syntax of .def module definition files
+ Version info bumped from 7:8:6 to 7:9:6
+
+ Special thanks to:
+ Benjamin Peterson
+ Caolán McNamara
+ Hanno Böck
+ KangLin
+ Kishore Kunche
+ Marco Maggi
+ Rhodri James
+ Sebastian Dröge
+ userwithuid
+ Yury Gribov
+
+Release 2.2.6 Sun August 12 2018
+ Bug fixes:
+ #170 #206 Avoid doing arithmetic with NULL pointers in XML_GetBuffer
+ #204 #205 Fix 2.2.5 regression with suspend-resume while parsing
+ a document like '<root/>'
+
+ Other changes:
+ #165 #168 Autotools: Fix docbook-related configure syntax error
+ #166 Autotools: Avoid grep option `-q` for Solaris
+ #167 Autotools: Support
+ ./configure DOCBOOK_TO_MAN="xmlto man --skip-validation"
+ #159 #167 Autotools: Support DOCBOOK_TO_MAN command which produces
+ xmlwf.1 rather than XMLWF.1; also covers case insensitive
+ file systems
+ #181 Autotools: Drop -rpath option passed to libtool
+ #188 Autotools: Detect and deny SGML docbook2man as ours is XML
+ #188 Autotools/CMake: Support command db2x_docbook2man as well
+ #174 CMake: Introduce option WARNINGS_AS_ERRORS, defaults to OFF
+ #184 #185 CMake: Introduce option MSVC_USE_STATIC_CRT, defaults to OFF
+ #207 #208 CMake: Introduce option XML_UNICODE and XML_UNICODE_WCHAR_T,
+ both defaulting to OFF
+ #175 CMake: Prefer check_symbol_exists over check_function_exists
+ #176 CMake: Create the same pkg-config file as with GNU Autotools
+ #178 #179 CMake: Use GNUInstallDirs module to set proper defaults for
+ install directories
+ #208 CMake: Utilize expat_config.h.cmake for XML_DEV_URANDOM
+ #180 Windows: Fix compilation of test suite for Visual Studio 2008
+ #131 #173 #202 Address compiler warnings
+ #187 #190 #200 Fix miscellaneous typos
+ Version info bumped from 7:7:6 to 7:8:6
+
+ Special thanks to:
+ Anton Maklakov
+ Benjamin Peterson
+ Brad King
+ Franek Korta
+ Frank Rast
+ Joe Orton
+ luzpaz
+ Pedro Vicente
+ Rainer Jung
+ Rhodri James
+ Rolf Ade
+ Rolf Eike Beer
+ Thomas Beutlich
+ Tomasz Kłoczko
+
+Release 2.2.5 Tue October 31 2017
+ Bug fixes:
+ #8 If the parser runs out of memory, make sure its internal
+ state reflects the memory it actually has, not the memory
+ it wanted to have.
+ #11 The default handler wasn't being called when it should for
+ a SYSTEM or PUBLIC doctype if an entity declaration handler
+ was registered.
+ #137 #138 Fix a case of mistakenly reported parsing success where
+ XML_StopParser was called from an element handler
+ #162 Function XML_ErrorString was returning NULL rather than
+ a message for code XML_ERROR_INVALID_ARGUMENT
+ introduced with release 2.2.1
+
+ Other changes:
+ #106 xmlwf: Add argument -N adding notation declarations
+ #75 #106 Test suite: Resolve expected failure cases where xmlwf
+ output was incomplete
+ #127 Windows: Fix test suite compilation
+ #126 #127 Windows: Fix compilation for Visual Studio 2012
+ Windows: Upgrade shipped project files to Visual Studio 2017
+ #33 #132 tests: Mass-fix compilation for XML_UNICODE_WCHAR_T
+ #129 examples: Fix compilation for XML_UNICODE_WCHAR_T
+ #130 benchmark: Fix compilation for XML_UNICODE_WCHAR_T
+ #144 xmlwf: Fix compilation for XML_UNICODE_WCHAR_T; still needs
+ Windows or MinGW for 2-byte wchar_t
+ #9 Address two Clang Static Analyzer false positives
+ #59 Resolve troublesome macros hiding parser struct membership
+ and dereferencing that pointer
+ #6 Resolve superfluous internal malloc/realloc switch
+ #153 #155 Improve docbook2x-man detection
+ #160 Undefine NDEBUG in the test suite (rather than rejecting it)
+ #161 Address compiler warnings
+ Version info bumped from 7:6:6 to 7:7:6
+
+ Special thanks to:
+ Benbuck Nason
+ Hans Wennborg
+ José Gutiérrez de la Concha
+ Pedro Monreal Gonzalez
+ Rhodri James
+ Rolf Ade
+ Stephen Groat
+ and
+ Core Infrastructure Initiative
+
+Release 2.2.4 Sat August 19 2017
+ Bug fixes:
+ #115 Fix copying of partial characters for UTF-8 input
+
+ Other changes:
+ #109 Fix "make check" for non-x86 architectures that default
+ to unsigned type char (-128..127 rather than 0..255)
+ #109 coverage.sh: Cover -funsigned-char
+ Autotools: Introduce --without-xmlwf argument
+ #65 Autotools: Replace handwritten Makefile with GNU Automake
+ #43 CMake: Auto-detect high quality entropy extractors, add new
+ option USE_libbsd=ON to use arc4random_buf of libbsd
+ #74 CMake: Add -fno-strict-aliasing only where supported
+ #114 CMake: Always honor manually set BUILD_* options
+ #114 CMake: Compile man page if docbook2x-man is available, only
+ #117 Include file tests/xmltest.log.expected in source tarball
+ (required for "make run-xmltest")
+ #117 Include (existing) Visual Studio 2013 files in source tarball
+ Improve test suite error output
+ #111 Fix some typos in documentation
+ Version info bumped from 7:5:6 to 7:6:6
+
+ Special thanks to:
+ Jakub Wilk
+ Joe Orton
+ Lin Tian
+ Rolf Eike Beer
+
+Release 2.2.3 Wed August 2 2017
+ Security fixes:
+ #82 CVE-2017-11742 -- Windows: Fix DLL hijacking vulnerability
+ using Steve Holme's LoadLibrary wrapper for/of cURL
+
+ Bug fixes:
+ #85 Fix a dangling pointer issue related to realloc
+
+ Other changes:
+ Increase code coverage
+ #91 Linux: Allow getrandom to fail if nonblocking pool has not
+ yet been initialized and read /dev/urandom then, instead.
+ This is in line with what recent Python does.
+ #81 Pre-10.7/Lion macOS: Support entropy from arc4random
+ #86 Check that a UTF-16 encoding in an XML declaration has the
+ right endianness
+ #4 #5 #7 Recover correctly when some reallocations fail
+ Repair "./configure && make" for systems without any
+ provider of high quality entropy
+ and try reading /dev/urandom on those
+ Ensure that user-defined character encodings have converter
+ functions when they are needed
+ Fix mis-leading description of argument -c in xmlwf.1
+ Rely on macro HAVE_ARC4RANDOM_BUF (rather than __CloudABI__)
+ for CloudABI
+ #100 Fix use of SIPHASH_MAIN in siphash.h
+ #23 Test suite: Fix memory leaks
+ Version info bumped from 7:4:6 to 7:5:6
+
+ Special thanks to:
+ Chanho Park
+ Joe Orton
+ Pascal Cuoq
+ Rhodri James
+ Simon McVittie
+ Vadim Zeitlin
+ Viktor Szakats
+ and
+ Core Infrastructure Initiative
+
+Release 2.2.2 Wed July 12 2017
+ Security fixes:
+ #43 Protect against compilation without any source of high
+ quality entropy enabled, e.g. with CMake build system;
+ commit ff0207e6076e9828e536b8d9cd45c9c92069b895
+ #60 Windows with _UNICODE:
+ Unintended use of LoadLibraryW with a non-wide string
+ resulted in failure to load advapi32.dll and degradation
+ in quality of used entropy when compiled with _UNICODE for
+ Windows; you can launch existing binaries with
+ EXPAT_ENTROPY_DEBUG=1 in the environment to inspect the
+ quality of entropy used during runtime; commits
+ * 95b95032f907ef1cd17ee7a9a1768010a825d61d
+ * 73a5a2e9c081f49f2d775cf7ced864158b68dc80
+ [MOX-006] Fix non-NULL parser parameter validation in XML_Parse;
+ resulted in NULL dereference, previously;
+ commit ac256dafdffc9622ab0dc2c62fcecb0dfcfa71fe
+
+ Bug fixes:
+ #69 Fix improper use of unsigned long long integer literals
+
+ Other changes:
+ #73 Start requiring a C99 compiler
+ #49 Fix "==" Bashism in configure script
+ #50 Fix too eager getrandom detection for Debian GNU/kFreeBSD
+ #52 and macOS
+ #51 Address lack of stdint.h in Visual Studio 2003 to 2008
+ #58 Address compile warnings
+ #68 Fix "./buildconf.sh && ./configure" for some versions
+ of Dash for /bin/sh
+ #72 CMake: Ease use of Expat in context of a parent project
+ with multiple CMakeLists.txt files
+ #72 CMake: Resolve mistaken executable permissions
+ #76 Address compile warning with -DNDEBUG (not recommended!)
+ #77 Address compile warning about macro redefinition
+
+ Special thanks to:
+ Alexander Bluhm
+ Ben Boeckel
+ Cătălin Răceanu
+ Kerin Millar
+ László Böszörményi
+ S. P. Zeidler
+ Segev Finer
+ Václav Slavík
+ Victor Stinner
+ Viktor Szakats
+ and
+ Radically Open Security
+
+Release 2.2.1 Sat June 17 2017
+ Security fixes:
+ CVE-2017-9233 -- External entity infinite loop DoS
+ Details: https://libexpat.github.io/doc/cve-2017-9233/
+ Commit c4bf96bb51dd2a1b0e185374362ee136fe2c9d7f
+ [MOX-002] CVE-2016-9063 -- Detect integer overflow; commit
+ d4f735b88d9932bd5039df2335eefdd0723dbe20
+ (Fixed version of existing downstream patches!)
+ (SF.net) #539 Fix regression from fix to CVE-2016-0718 cutting off
+ longer tag names; commits
+ * 896b6c1fd3b842f377d1b62135dccf0a579cf65d
+ * af507cef2c93cb8d40062a0abe43a4f4e9158fb2
+ #16 * 0dbbf43fdb20f593ddf4fa1ff67288000dd4a7fd
+ #25 More integer overflow detection (function poolGrow); commits
+ * 810b74e4703dcfdd8f404e3cb177d44684775143
+ * 44178553f3539ce69d34abee77a05e879a7982ac
+ [MOX-002] Detect overflow from len=INT_MAX call to XML_Parse; commits
+ * 4be2cb5afcc018d996f34bbbce6374b7befad47f
+ * 7e5b71b748491b6e459e5c9a1d090820f94544d8
+ [MOX-005] #30 Use high quality entropy for hash initialization:
+ * arc4random_buf on BSD, systems with libbsd
+ (when configured with --with-libbsd), CloudABI
+ * RtlGenRandom on Windows XP / Server 2003 and later
+ * getrandom on Linux 3.17+
+ In a way, that's still part of CVE-2016-5300.
+ https://github.com/libexpat/libexpat/pull/30/commits
+ [MOX-005] For the low quality entropy extraction fallback code,
+ the parser instance address can no longer leak, commit
+ 04ad658bd3079dd15cb60fc67087900f0ff4b083
+ [MOX-003] Prevent use of uninitialised variable; commit
+ [MOX-004] a4dc944f37b664a3ca7199c624a98ee37babdb4b
+ Add missing parameter validation to public API functions
+ and dedicated error code XML_ERROR_INVALID_ARGUMENT:
+ [MOX-006] * NULL checks; commits
+ * d37f74b2b7149a3a95a680c4c4cd2a451a51d60a (merge/many)
+ * 9ed727064b675b7180c98cb3d4f75efba6966681
+ * 6a747c837c50114dfa413994e07c0ba477be4534
+ * Negative length (XML_Parse); commit
+ [MOX-002] 70db8d2538a10f4c022655d6895e4c3e78692e7f
+ [MOX-001] #35 Change hash algorithm to William Ahern's version of SipHash
+ to go further with fixing CVE-2012-0876.
+ https://github.com/libexpat/libexpat/pull/39/commits
+
+ Bug fixes:
+ #32 Fix sharing of hash salt across parsers;
+ relevant where XML_ExternalEntityParserCreate is called
+ prior to XML_Parse, in particular (e.g. FBReader)
+ #28 xmlwf: Auto-disable use of memory-mapping (and parsing
+ as a single chunk) for files larger than ~1 GB (2^30 bytes)
+ rather than failing with error "out of memory"
+ #3 Fix double free after malloc failure in DTD code; commit
+ 7ae9c3d3af433cd4defe95234eae7dc8ed15637f
+ #17 Fix memory leak on parser error for unbound XML attribute
+ prefix with new namespaces defined in the same tag;
+ found by Google's OSS-Fuzz; commits
+ * 16f87daae5a16132e479e4f71862128c7a915c73
+ * b47dbc9745932c160893d433220e462bd605f8cd
+ xmlwf on Windows: Add missing calls to CloseHandle
+
+ New features:
+ #30 Introduced environment switch EXPAT_ENTROPY_DEBUG=1
+ for runtime debugging of entropy extraction
+
+ Other changes:
+ Increase code coverage
+ #33 Reject use of XML_UNICODE_WCHAR_T with sizeof(wchar_t) != 2;
+ XML_UNICODE_WCHAR_T was never meant to be used outside
+ of Windows; 4-byte wchar_t is common on Linux
+ (SF.net) #538 Start using -fno-strict-aliasing
+ (SF.net) #540 Support compilation against cloudlibc of CloudABI
+ Allow MinGW cross-compilation
+ (SF.net) #534 CMake: Introduce option "BUILD_doc" (enabled by default)
+ to bypass compilation of the xmlwf.1 man page
+ (SF.net) pr2 CMake: Introduce option "INSTALL" (enabled by default)
+ to bypass installation of expat files
+ CMake: Fix ninja support
+ Autotools: Add parameters --enable-xml-context [COUNT]
+ and --disable-xml-context; default of context of 1024
+ bytes enabled unchanged
+ #14 Drop AmigaOS 4.x code and includes
+ #14 Drop ancient build systems:
+ * Borland C++ Builder
+ * OpenVMS
+ * Open Watcom
+ * Visual Studio 6.0
+ * Pre-X Mac OS (MPW Makefile)
+ If you happen to rely on some of these, please get in
+ touch for joining with maintenance.
+ #10 Move from WIN32 to _WIN32
+ #13 Fix "make run-xmltest" order instability
+ Address compile warnings
+ Bump version info from 7:2:6 to 7:3:6
+ Add AUTHORS file
+
+ Infrastructure:
+ #1 Migrate from SourceForge to GitHub (except downloads):
+ https://github.com/libexpat/
+ #1 Re-create http://libexpat.org/ project website
+ Start utilizing Travis CI
+
+ Special thanks to:
+ Andy Wang
+ Don Lewis
+ Ed Schouten
+ Karl Waclawek
+ Pascal Cuoq
+ Rhodri James
+ Sergei Nikulov
+ Tobias Taschner
+ Viktor Szakats
+ and
+ Core Infrastructure Initiative
+ Mozilla Foundation (MOSS Track 3: Secure Open Source)
+ Radically Open Security
+
+Release 2.2.0 Tue June 21 2016
+ Security fixes:
+ #537 CVE-2016-0718 -- Fix crash on malformed input
+ CVE-2016-4472 -- Improve insufficient fix to CVE-2015-1283 /
+ CVE-2015-2716 introduced with Expat 2.1.1
+ #499 CVE-2016-5300 -- Use more entropy for hash initialization
+ than the original fix to CVE-2012-0876
+ #519 CVE-2012-6702 -- Resolve troublesome internal call to srand
+ that was introduced with Expat 2.1.0
+ when addressing CVE-2012-0876 (issue #496)
+
+ Bug fixes:
+ Fix uninitialized reads of size 1
+ (e.g. in little2_updatePosition)
+ Fix detection of UTF-8 character boundaries
+
+ Other changes:
+ #532 Fix compilation for Visual Studio 2010 (keyword "C99")
+ Autotools: Resolve use of "$<" to better support bmake
+ Autotools: Add QA script "qa.sh" (and make target "qa")
+ Autotools: Respect CXXFLAGS if given
+ Autotools: Fix "make run-xmltest"
+ Autotools: Have "make run-xmltest" check for expected output
+ p90 CMake: Fix static build (BUILD_shared=OFF) on Windows
+ #536 CMake: Add soversion, support -DNO_SONAME=yes to bypass
+ #323 CMake: Add suffix "d" to differentiate debug from release
+ CMake: Define WIN32 with CMake on Windows
+ Annotate memory allocators for GCC
+ Address all currently known compile warnings
+ Make sure that API symbols remain visible despite
+ -fvisibility=hidden
+ Remove executable flag from source files
+ Resolve COMPILED_FROM_DSP in favor of WIN32
+
+ Special thanks to:
+ Björn Lindahl
+ Christian Heimes
+ Cristian Rodríguez
+ Daniel Krügler
+ Gustavo Grieco
+ Karl Waclawek
+ László Böszörményi
+ Marco Grassi
+ Pascal Cuoq
+ Sergei Nikulov
+ Thomas Beutlich
+ Warren Young
+ Yann Droneaud
+
Release 2.1.1 Sat March 12 2016
Security fixes:
#582: CVE-2015-1283 - Multiple integer overflows in XML_GetBuffer
@@ -7,31 +603,32 @@ Release 2.1.1 Sat March 12 2016
#520: Symbol XML_SetHashSalt was not exported
Output of "xmlwf -h" was incomplete
- Other changes
+ Other changes:
#503: Document behavior of calling XML_SetHashSalt with salt 0
Minor improvements to man page xmlwf(1)
Improvements to the experimental CMake build system
libtool now invoked with --verbose
Release 2.1.0 Sat March 24 2012
+ - Security fixes:
+ #2958794: CVE-2012-1148 - Memory leak in poolGrow.
+ #2895533: CVE-2012-1147 - Resource leak in readfilemap.c.
+ #3496608: CVE-2012-0876 - Hash DOS attack.
+ #2894085: CVE-2009-3560 - Buffer over-read and crash in big2_toUtf8().
+ #1990430: CVE-2009-3720 - Parser crash with special UTF-8 sequences.
- Bug Fixes:
#1742315: Harmful XML_ParserCreateNS suggestion.
- #2895533: CVE-2012-1147 - Resource leak in readfilemap.c.
#1785430: Expat build fails on linux-amd64 with gcc version>=4.1 -O3.
#1983953, 2517952, 2517962, 2649838:
Build modifications using autoreconf instead of buildconf.sh.
#2815947, #2884086: OBJEXT and EXEEXT support while building.
- #1990430: CVE-2009-3720 - Parser crash with special UTF-8 sequences.
#2517938: xmlwf should return non-zero exit status if not well-formed.
#2517946: Wrong statement about XMLDecl in xmlwf.1 and xmlwf.sgml.
#2855609: Dangling positionPtr after error.
- #2894085: CVE-2009-3560 - Buffer over-read and crash in big2_toUtf8().
- #2958794: CVE-2012-1148 - Memory leak in poolGrow.
#2990652: CMake support.
#3010819: UNEXPECTED_STATE with a trailing "%" in entity value.
- #3206497: Unitialized memory returned from XML_Parse.
+ #3206497: Uninitialized memory returned from XML_Parse.
#3287849: make check fails on mingw-w64.
- #3496608: CVE-2012-0876 - Hash DOS attack.
- Patches:
#1749198: pkg-config support.
#3010222: Fix for bug #3010819.
diff --git a/3rdparty/expat/ConfigureChecks.cmake b/3rdparty/expat/ConfigureChecks.cmake
index f03faa637d0..d85e48c972d 100644
--- a/3rdparty/expat/ConfigureChecks.cmake
+++ b/3rdparty/expat/ConfigureChecks.cmake
@@ -1,6 +1,7 @@
+include(CheckCCompilerFlag)
+include(CheckCSourceCompiles)
include(CheckIncludeFile)
include(CheckIncludeFiles)
-include(CheckFunctionExists)
include(CheckSymbolExists)
include(TestBigEndian)
@@ -16,10 +17,21 @@ check_include_file("sys/stat.h" HAVE_SYS_STAT_H)
check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
check_include_file("unistd.h" HAVE_UNISTD_H)
-check_function_exists("getpagesize" HAVE_GETPAGESIZE)
-check_function_exists("bcopy" HAVE_BCOPY)
-check_symbol_exists("memmove" "string.h" HAVE_MEMMOVE)
-check_function_exists("mmap" HAVE_MMAP)
+check_symbol_exists("getpagesize" "unistd.h" HAVE_GETPAGESIZE)
+check_symbol_exists("mmap" "sys/mman.h" HAVE_MMAP)
+check_symbol_exists("getrandom" "sys/random.h" HAVE_GETRANDOM)
+
+if(EXPAT_WITH_LIBBSD)
+ set(CMAKE_REQUIRED_LIBRARIES "${LIB_BSD}")
+ set(_bsd "bsd/")
+else()
+ set(_bsd "")
+endif()
+check_symbol_exists("arc4random_buf" "${_bsd}stdlib.h" HAVE_ARC4RANDOM_BUF)
+if(NOT HAVE_ARC4RANDOM_BUF)
+ check_symbol_exists("arc4random" "${_bsd}stdlib.h" HAVE_ARC4RANDOM)
+endif()
+set(CMAKE_REQUIRED_LIBRARIES)
#/* Define to 1 if you have the ANSI C header files. */
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
@@ -40,5 +52,15 @@ else(HAVE_SYS_TYPES_H)
set(SIZE_T "unsigned")
endif(HAVE_SYS_TYPES_H)
-configure_file(expat_config.h.cmake expat_config.h)
-add_definitions(-DHAVE_EXPAT_CONFIG_H)
+check_c_source_compiles("
+ #include <stdlib.h> /* for NULL */
+ #include <unistd.h> /* for syscall */
+ #include <sys/syscall.h> /* for SYS_getrandom */
+ int main() {
+ syscall(SYS_getrandom, NULL, 0, 0);
+ return 0;
+ }"
+ HAVE_SYSCALL_GETRANDOM)
+
+check_c_compiler_flag("-fno-strict-aliasing" FLAG_NO_STRICT_ALIASING)
+check_c_compiler_flag("-fvisibility=hidden" FLAG_VISIBILITY)
diff --git a/3rdparty/expat/MANIFEST b/3rdparty/expat/MANIFEST
deleted file mode 100644
index 209152706ef..00000000000
--- a/3rdparty/expat/MANIFEST
+++ /dev/null
@@ -1,141 +0,0 @@
-amiga/launch.c
-amiga/expat_68k.c
-amiga/expat_68k.h
-amiga/expat_68k_handler_stubs.c
-amiga/expat_base.h
-amiga/expat_vectors.c
-amiga/expat_lib.c
-amiga/expat.xml
-amiga/README.txt
-amiga/Makefile
-amiga/include/proto/expat.h
-amiga/include/libraries/expat.h
-amiga/include/interfaces/expat.h
-amiga/include/inline4/expat.h
-bcb5/README.txt
-bcb5/all_projects.bpg
-bcb5/elements.bpf
-bcb5/elements.bpr
-bcb5/elements.mak
-bcb5/expat.bpf
-bcb5/expat.bpr
-bcb5/expat.mak
-bcb5/expat_static.bpf
-bcb5/expat_static.bpr
-bcb5/expat_static.mak
-bcb5/expatw.bpf
-bcb5/expatw.bpr
-bcb5/expatw.mak
-bcb5/expatw_static.bpf
-bcb5/expatw_static.bpr
-bcb5/expatw_static.mak
-bcb5/libexpat_mtd.def
-bcb5/libexpatw_mtd.def
-bcb5/makefile.mak
-bcb5/outline.bpf
-bcb5/outline.bpr
-bcb5/outline.mak
-bcb5/setup.bat
-bcb5/xmlwf.bpf
-bcb5/xmlwf.bpr
-bcb5/xmlwf.mak
-doc/expat.png
-doc/reference.html
-doc/style.css
-doc/valid-xhtml10.png
-doc/xmlwf.1
-doc/xmlwf.sgml
-CMakeLists.txt
-CMake.README
-COPYING
-Changes
-ConfigureChecks.cmake
-MANIFEST
-Makefile.in
-README
-configure
-configure.ac
-expat_config.h.in
-expat_config.h.cmake
-expat.pc.in
-expat.dsw
-aclocal.m4
-conftools/PrintPath
-conftools/ac_c_bigendian_cross.m4
-conftools/expat.m4
-conftools/get-version.sh
-conftools/mkinstalldirs
-conftools/config.guess
-conftools/config.sub
-conftools/install-sh
-conftools/ltmain.sh
-m4/libtool.m4
-m4/ltversion.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/lt~obsolete.m4
-examples/elements.c
-examples/elements.dsp
-examples/outline.c
-examples/outline.dsp
-lib/Makefile.MPW
-lib/amigaconfig.h
-lib/ascii.h
-lib/asciitab.h
-lib/expat.dsp
-lib/expat.h
-lib/expat_external.h
-lib/expat_static.dsp
-lib/expatw.dsp
-lib/expatw_static.dsp
-lib/iasciitab.h
-lib/internal.h
-lib/latin1tab.h
-lib/libexpat.def
-lib/libexpatw.def
-lib/macconfig.h
-lib/nametab.h
-lib/utf8tab.h
-lib/winconfig.h
-lib/xmlparse.c
-lib/xmlrole.c
-lib/xmlrole.h
-lib/xmltok.c
-lib/xmltok.h
-lib/xmltok_impl.c
-lib/xmltok_impl.h
-lib/xmltok_ns.c
-tests/benchmark/README.txt
-tests/benchmark/benchmark.c
-tests/benchmark/benchmark.dsp
-tests/benchmark/benchmark.dsw
-tests/README.txt
-tests/chardata.c
-tests/chardata.h
-tests/minicheck.c
-tests/minicheck.h
-tests/runtests.c
-tests/runtestspp.cpp
-tests/xmltest.sh
-vms/README.vms
-vms/descrip.mms
-vms/expat_config.h
-win32/MANIFEST.txt
-win32/README.txt
-win32/expat.iss
-xmlwf/codepage.c
-xmlwf/codepage.h
-xmlwf/ct.c
-xmlwf/filemap.h
-xmlwf/readfilemap.c
-xmlwf/unixfilemap.c
-xmlwf/win32filemap.c
-xmlwf/xmlfile.c
-xmlwf/xmlfile.h
-xmlwf/xmlmime.c
-xmlwf/xmlmime.h
-xmlwf/xmltchar.h
-xmlwf/xmlurl.h
-xmlwf/xmlwf.c
-xmlwf/xmlwf.dsp
-xmlwf/xmlwin32url.cxx
diff --git a/3rdparty/expat/Makefile.am b/3rdparty/expat/Makefile.am
new file mode 100644
index 00000000000..5e1d37dd1a8
--- /dev/null
+++ b/3rdparty/expat/Makefile.am
@@ -0,0 +1,154 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+AUTOMAKE_OPTIONS = \
+ dist-bzip2 \
+ dist-lzip \
+ dist-xz \
+ foreign \
+ subdir-objects
+
+ACLOCAL_AMFLAGS = -I m4
+LIBTOOLFLAGS = --verbose
+
+SUBDIRS = lib # lib goes first to build first
+if WITH_EXAMPLES
+SUBDIRS += examples
+endif
+if WITH_TESTS
+SUBDIRS += tests
+endif
+if WITH_XMLWF
+SUBDIRS += xmlwf doc
+endif
+
+pkgconfig_DATA = expat.pc
+pkgconfigdir = $(libdir)/pkgconfig
+
+
+_EXTRA_DIST_CMAKE = \
+ cmake/expat-config.cmake.in \
+ cmake/mingw-toolchain.cmake \
+ \
+ CMakeLists.txt \
+ CMake.README \
+ ConfigureChecks.cmake \
+ expat_config.h.cmake
+
+_EXTRA_DIST_WINDOWS = \
+ win32/build_expat_iss.bat \
+ win32/expat.iss \
+ win32/MANIFEST.txt \
+ win32/README.txt
+
+EXTRA_DIST = \
+ $(_EXTRA_DIST_CMAKE) \
+ $(_EXTRA_DIST_WINDOWS) \
+ \
+ conftools/expat.m4 \
+ conftools/get-version.sh \
+ conftools/PrintPath \
+ \
+ xmlwf/xmlwf_helpgen.py \
+ xmlwf/xmlwf_helpgen.sh \
+ \
+ Changes \
+ README.md \
+ \
+ fix-xmltest-log.sh \
+ test-driver-wrapper.sh
+
+
+.PHONY: buildlib
+buildlib:
+ @echo 'ERROR: Running "make buildlib LIBRARY=libexpatw.la"' >&2
+ @echo 'ERROR: is no longer supported. INSTEAD please:' >&2
+ @echo 'ERROR:' >&2
+ @echo 'ERROR: * Mass-patch Makefile.am, e.g.' >&2
+ @echo 'ERROR: # find -name Makefile.am -exec sed \' >&2
+ @echo 'ERROR: -e "s,libexpat\.la,libexpatw.la," \' >&2
+ @echo 'ERROR: -e "s,libexpat_la,libexpatw_la," \' >&2
+ @echo 'ERROR: -i {} +' >&2
+ @echo 'ERROR:' >&2
+ @echo 'ERROR: * Run automake to re-generate Makefile.in files' >&2
+ @echo 'ERROR:' >&2
+ @echo 'ERROR: * Use "./configure --without-xmlwf" and/or' >&2
+ @echo 'ERROR: "make -C lib all install" to bypass compilation' >&2
+ @echo 'ERROR: of xmlwf (e.g. with -DXML_UNICODE)' >&2
+ @echo 'ERROR:' >&2
+ @false
+
+
+.PHONY: run-benchmark
+run-benchmark:
+ $(MAKE) -C tests/benchmark
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/recset.xml 65535 3
+
+.PHONY: download-xmlts-zip
+download-xmlts-zip:
+ if test "$(XMLTS_ZIP)" = ""; then \
+ wget --output-document=tests/xmlts.zip \
+ https://www.w3.org/XML/Test/xmlts20080827.zip; \
+ else \
+ cp $(XMLTS_ZIP) tests/xmlts.zip; \
+ fi
+
+tests/xmlts.zip:
+ $(MAKE) download-xmlts-zip
+
+.PHONY: extract-xmlts-zip
+extract-xmlts-zip: tests/xmlts.zip
+ [ -f $(builddir)/tests/xmlts.zip ] || $(MAKE) download-xmlts-zip # vpath workaround
+ cd tests && unzip -q xmlts.zip
+
+tests/xmlconf: tests/xmlts.zip
+ $(MAKE) extract-xmlts-zip
+
+.PHONY: run-xmltest
+run-xmltest: tests/xmlconf
+if WITH_XMLWF
+ [ -d $(builddir)/tests/xmlconf ] || $(MAKE) extract-xmlts-zip # vpath workaround
+ $(MAKE) -C lib
+ $(MAKE) -C xmlwf
+ $(srcdir)/tests/xmltest.sh "$(abs_builddir)/run.sh $(abs_builddir)/xmlwf/xmlwf@EXEEXT@" 2>&1 | tee $(builddir)/tests/xmltest.log
+ $(srcdir)/fix-xmltest-log.sh $(builddir)/tests/xmltest.log
+ diff -u $(srcdir)/tests/xmltest.log.expected $(builddir)/tests/xmltest.log
+else
+ @echo 'ERROR: xmlwf is needed for "make run-xmltest".' >&2
+ @echo 'ERROR: Please re-configure without --without-xmlwf.' >&2
+ @false
+endif
+
+.PHONY: qa
+qa:
+ QA_COMPILER=clang QA_SANITIZER=address ./qa.sh
+ QA_COMPILER=clang QA_SANITIZER=memory ./qa.sh
+ QA_COMPILER=clang QA_SANITIZER=undefined ./qa.sh
+ QA_COMPILER=gcc QA_PROCESSOR=gcov ./qa.sh
diff --git a/3rdparty/expat/Makefile.in b/3rdparty/expat/Makefile.in
index 6863b092bc1..ab846398cb7 100644
--- a/3rdparty/expat/Makefile.in
+++ b/3rdparty/expat/Makefile.in
@@ -1,201 +1,1047 @@
-################################################################
-# Process this file with top-level configure script to produce Makefile
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
#
-# Copyright 2000 Clark Cooper
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
#
-# This file is part of EXPAT.
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
#
-# EXPAT is free software; you can redistribute it and/or modify it
-# under the terms of the License (based on the MIT/X license) contained
-# in the file COPYING that comes with this distribution.
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
#
-# EXPAT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-# SOFTWARE OR THE USE OR OTHER DEALINGS IN EXPAT.
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WITH_EXAMPLES_TRUE@am__append_1 = examples
+@WITH_TESTS_TRUE@am__append_2 = tests
+@WITH_XMLWF_TRUE@am__append_3 = xmlwf doc
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+ $(am__configure_deps) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = expat_config.h
+CONFIG_CLEAN_FILES = expat.pc run.sh
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+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 = 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__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
+DATA = $(pkgconfig_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope distdir distdir-am dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ expat_config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = lib examples tests xmlwf doc
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/expat.pc.in \
+ $(srcdir)/expat_config.h.in $(srcdir)/run.sh.in \
+ $(top_srcdir)/conftools/ar-lib $(top_srcdir)/conftools/compile \
+ $(top_srcdir)/conftools/config.guess \
+ $(top_srcdir)/conftools/config.sub \
+ $(top_srcdir)/conftools/install-sh \
+ $(top_srcdir)/conftools/ltmain.sh \
+ $(top_srcdir)/conftools/missing AUTHORS COPYING \
+ conftools/ar-lib conftools/compile conftools/config.guess \
+ conftools/config.sub conftools/depcomp conftools/install-sh \
+ conftools/ltmain.sh conftools/missing
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).tar.lz \
+ $(distdir).tar.xz
+GZIP_ENV = --best
+DIST_TARGETS = dist-lzip dist-xz dist-bzip2 dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
-
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
-VPATH = @srcdir@
-
-prefix = @prefix@
-exec_prefix = @exec_prefix@
+AUTOMAKE_OPTIONS = \
+ dist-bzip2 \
+ dist-lzip \
+ dist-xz \
+ foreign \
+ subdir-objects
-bindir = @bindir@
-libdir = @libdir@
-includedir = @includedir@
-man1dir = @mandir@/man1
+ACLOCAL_AMFLAGS = -I m4
+LIBTOOLFLAGS = --verbose
+SUBDIRS = lib $(am__append_1) $(am__append_2) $(am__append_3)
+pkgconfig_DATA = expat.pc
pkgconfigdir = $(libdir)/pkgconfig
+_EXTRA_DIST_CMAKE = \
+ cmake/expat-config.cmake.in \
+ cmake/mingw-toolchain.cmake \
+ \
+ CMakeLists.txt \
+ CMake.README \
+ ConfigureChecks.cmake \
+ expat_config.h.cmake
-top_builddir = .
+_EXTRA_DIST_WINDOWS = \
+ win32/build_expat_iss.bat \
+ win32/expat.iss \
+ win32/MANIFEST.txt \
+ win32/README.txt
+EXTRA_DIST = \
+ $(_EXTRA_DIST_CMAKE) \
+ $(_EXTRA_DIST_WINDOWS) \
+ \
+ conftools/expat.m4 \
+ conftools/get-version.sh \
+ conftools/PrintPath \
+ \
+ xmlwf/xmlwf_helpgen.py \
+ xmlwf/xmlwf_helpgen.sh \
+ \
+ Changes \
+ README.md \
+ \
+ fix-xmltest-log.sh \
+ test-driver-wrapper.sh
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_DATA = @INSTALL_DATA@
-mkinstalldirs = $(SHELL) $(top_srcdir)/conftools/mkinstalldirs
+all: expat_config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+expat_config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
-MANFILE = $(srcdir)/doc/xmlwf.1
-APIHEADER = $(srcdir)/lib/expat.h $(srcdir)/lib/expat_external.h expat_config.h
-LIBRARY = libexpat.la
+stamp-h1: $(srcdir)/expat_config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status expat_config.h
+$(srcdir)/expat_config.h.in: $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
-DESTDIR = $(INSTALL_ROOT)
+distclean-hdr:
+ -rm -f expat_config.h stamp-h1
+expat.pc: $(top_builddir)/config.status $(srcdir)/expat.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+run.sh: $(top_builddir)/config.status $(srcdir)/run.sh.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
-default: buildlib xmlwf/xmlwf@EXEEXT@
+mostlyclean-libtool:
+ -rm -f *.lo
-buildlib: $(LIBRARY) expat.pc
+clean-libtool:
+ -rm -rf .libs _libs
-all: $(LIBRARY) expat.pc xmlwf/xmlwf@EXEEXT@ examples/elements examples/outline
+distclean-libtool:
+ -rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
-clean:
- cd lib && rm -f $(LIBRARY) *.@OBJEXT@ *.lo && rm -rf .libs _libs
- cd xmlwf && rm -f xmlwf *.@OBJEXT@ *.lo && rm -rf .libs _libs
- cd examples && rm -f elements outline *.@OBJEXT@ *.lo && rm -rf .libs _libs
- cd tests && rm -rf .libs runtests runtests.@OBJEXT@ runtestspp runtestspp.@OBJEXT@
- cd tests && rm -f chardata.@OBJEXT@ minicheck.@OBJEXT@
- rm -rf .libs libexpat.la
- rm -f examples/core tests/core xmlwf/core
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
-clobber: clean
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
-distclean: clean
- rm -f expat_config.h config.status config.log config.cache libtool
- rm -f Makefile expat.pc
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
-extraclean: distclean
- rm -f expat_config.h.in configure
- rm -f aclocal.m4 m4/*
- rm -f conftools/ltmain.sh conftools/install-sh conftools/config.guess conftools/config.sub
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
-check: tests/runtests tests/runtestspp
- tests/runtests
- tests/runtestspp
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
-install: xmlwf/xmlwf@EXEEXT@ installlib
- $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir)
- $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) xmlwf/xmlwf@EXEEXT@ $(DESTDIR)$(bindir)/xmlwf
- $(INSTALL_DATA) $(MANFILE) $(DESTDIR)$(man1dir)
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
-installlib: $(LIBRARY) $(APIHEADER) expat.pc
- $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir) $(DESTDIR)$(pkgconfigdir)
- $(LIBTOOL) --mode=install $(INSTALL) $(LIBRARY) $(DESTDIR)$(libdir)/$(LIBRARY)
- for FN in $(APIHEADER) ; do $(INSTALL_DATA) $$FN $(DESTDIR)$(includedir) ; done
- $(INSTALL_DATA) expat.pc $(DESTDIR)$(pkgconfigdir)/expat.pc
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
-uninstall: uninstalllib
- $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/xmlwf@EXEEXT@
- rm -f $(DESTDIR)$(man1dir)/xmlwf.1
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
-uninstalllib:
- $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(LIBRARY)
- rm -f $(DESTDIR)$(includedir)/expat.h
- rm -f $(DESTDIR)$(includedir)/expat_external.h
- rm -f $(DESTDIR)$(pkgconfigdir)/expat.pc
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
-# for VPATH builds (invoked by configure)
-mkdir-init:
- @for d in lib xmlwf examples tests ; do \
- (mkdir $$d 2> /dev/null || test 1) ; \
+distdir-am: $(DISTFILES)
+ $(am__remove_distdir)
+ 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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -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 $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
-CC = @CC@
-CXX = @CXX@
-LIBTOOL = @LIBTOOL@
+dist-zstd: distdir
+ tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
+ $(am__post_remove_distdir)
-INCLUDES = -I$(srcdir)/lib -I.
-LDFLAGS = @LDFLAGS@
-CPPFLAGS = @CPPFLAGS@ -DHAVE_EXPAT_CONFIG_H
-CFLAGS = @CFLAGS@
-CXXFLAGS = @CXXFLAGS@
-VSNFLAG = -version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
+dist-tarZ: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
-### autoconf this?
-LTFLAGS = --verbose
+dist-shar: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
-COMPILE = $(CC) $(INCLUDES) $(CFLAGS) $(DEFS) $(CPPFLAGS)
-CXXCOMPILE = $(CXX) $(INCLUDES) $(CXXFLAGS) $(DEFS) $(CPPFLAGS)
-LTCOMPILE = $(LIBTOOL) $(LTFLAGS) --mode=compile $(COMPILE)
-LINK_LIB = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) -no-undefined $(VSNFLAG) -rpath $(libdir) $(LDFLAGS) -o $@
-LINK_EXE = $(LIBTOOL) $(LTFLAGS) --mode=link $(COMPILE) $(LDFLAGS) -o $@
-LINK_CXX_EXE = $(LIBTOOL) $(LTFLAGS) --mode=link $(CXXCOMPILE) $(LDFLAGS) -o $@
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
-LIB_OBJS = lib/xmlparse.lo lib/xmltok.lo lib/xmlrole.lo
-$(LIBRARY): $(LIB_OBJS)
- $(LINK_LIB) $(LIB_OBJS)
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
-expat.pc: $(top_builddir)/config.status
- cd $(top_builddir) && $(SHELL) ./config.status $@
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ *.tar.zst*) \
+ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_build/sub $(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-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build/sub \
+ && ../../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=../.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA) expat_config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkgconfigDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
-lib/xmlparse.lo: lib/xmlparse.c lib/expat.h lib/xmlrole.h lib/xmltok.h \
- $(top_builddir)/expat_config.h lib/expat_external.h lib/internal.h
+ps: ps-recursive
-lib/xmlrole.lo: lib/xmlrole.c lib/ascii.h lib/xmlrole.h \
- $(top_builddir)/expat_config.h lib/expat_external.h lib/internal.h
+ps-am:
-lib/xmltok.lo: lib/xmltok.c lib/xmltok_impl.c lib/xmltok_ns.c \
- lib/ascii.h lib/asciitab.h lib/iasciitab.h lib/latin1tab.h \
- lib/nametab.h lib/utf8tab.h lib/xmltok.h lib/xmltok_impl.h \
- $(top_builddir)/expat_config.h lib/expat_external.h lib/internal.h
+uninstall-am: uninstall-pkgconfigDATA
+.MAKE: $(am__recursive_targets) all install-am install-strip
-XMLWF_OBJS = xmlwf/xmlwf.@OBJEXT@ xmlwf/xmlfile.@OBJEXT@ xmlwf/codepage.@OBJEXT@ xmlwf/@FILEMAP@.@OBJEXT@
-xmlwf/xmlwf.@OBJEXT@: xmlwf/xmlwf.c
-xmlwf/xmlfile.@OBJEXT@: xmlwf/xmlfile.c
-xmlwf/codepage.@OBJEXT@: xmlwf/codepage.c
-xmlwf/@FILEMAP@.@OBJEXT@: xmlwf/@FILEMAP@.c
-xmlwf/xmlwf@EXEEXT@: $(XMLWF_OBJS) $(LIBRARY)
- $(LINK_EXE) $(XMLWF_OBJS) $(LIBRARY)
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--refresh check check-am clean clean-cscope clean-generic \
+ clean-libtool cscope cscopelist-am ctags ctags-am dist \
+ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \
+ dist-xz dist-zip dist-zstd distcheck distclean \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkgconfigDATA
-examples/elements.@OBJEXT@: examples/elements.c
-examples/elements: examples/elements.@OBJEXT@ $(LIBRARY)
- $(LINK_EXE) $< $(LIBRARY)
+.PRECIOUS: Makefile
-examples/outline.@OBJEXT@: examples/outline.c
-examples/outline: examples/outline.@OBJEXT@ $(LIBRARY)
- $(LINK_EXE) $< $(LIBRARY)
-tests/chardata.@OBJEXT@: tests/chardata.c tests/chardata.h
-tests/minicheck.@OBJEXT@: tests/minicheck.c tests/minicheck.h
-tests/runtests.@OBJEXT@: tests/runtests.c tests/chardata.h
-tests/runtests: tests/runtests.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY)
- $(LINK_EXE) tests/runtests.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY)
-tests/runtestspp.@OBJEXT@: tests/runtestspp.cpp tests/runtests.c tests/chardata.h
-tests/runtestspp: tests/runtestspp.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY)
- $(LINK_CXX_EXE) tests/runtestspp.@OBJEXT@ tests/chardata.@OBJEXT@ tests/minicheck.@OBJEXT@ $(LIBRARY)
+.PHONY: buildlib
+buildlib:
+ @echo 'ERROR: Running "make buildlib LIBRARY=libexpatw.la"' >&2
+ @echo 'ERROR: is no longer supported. INSTEAD please:' >&2
+ @echo 'ERROR:' >&2
+ @echo 'ERROR: * Mass-patch Makefile.am, e.g.' >&2
+ @echo 'ERROR: # find -name Makefile.am -exec sed \' >&2
+ @echo 'ERROR: -e "s,libexpat\.la,libexpatw.la," \' >&2
+ @echo 'ERROR: -e "s,libexpat_la,libexpatw_la," \' >&2
+ @echo 'ERROR: -i {} +' >&2
+ @echo 'ERROR:' >&2
+ @echo 'ERROR: * Run automake to re-generate Makefile.in files' >&2
+ @echo 'ERROR:' >&2
+ @echo 'ERROR: * Use "./configure --without-xmlwf" and/or' >&2
+ @echo 'ERROR: "make -C lib all install" to bypass compilation' >&2
+ @echo 'ERROR: of xmlwf (e.g. with -DXML_UNICODE)' >&2
+ @echo 'ERROR:' >&2
+ @false
-tests/benchmark/benchmark.@OBJEXT@: tests/benchmark/benchmark.c
-tests/benchmark/benchmark: tests/benchmark/benchmark.@OBJEXT@ $(LIBRARY)
- $(LINK_EXE) tests/benchmark/benchmark.@OBJEXT@ $(LIBRARY)
+.PHONY: run-benchmark
+run-benchmark:
+ $(MAKE) -C tests/benchmark
+ ./run.sh tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/recset.xml 65535 3
-run-benchmark: tests/benchmark/benchmark
- tests/benchmark/benchmark@EXEEXT@ -n $(top_srcdir)/../testdata/largefiles/recset.xml 65535 3
+.PHONY: download-xmlts-zip
+download-xmlts-zip:
+ if test "$(XMLTS_ZIP)" = ""; then \
+ wget --output-document=tests/xmlts.zip \
+ https://www.w3.org/XML/Test/xmlts20080827.zip; \
+ else \
+ cp $(XMLTS_ZIP) tests/xmlts.zip; \
+ fi
tests/xmlts.zip:
- wget --output-document=tests/xmlts.zip \
- http://www.w3.org/XML/Test/xmlts20080827.zip
+ $(MAKE) download-xmlts-zip
-tests/XML-Test-Suite: tests/xmlts.zip
+.PHONY: extract-xmlts-zip
+extract-xmlts-zip: tests/xmlts.zip
+ [ -f $(builddir)/tests/xmlts.zip ] || $(MAKE) download-xmlts-zip # vpath workaround
cd tests && unzip -q xmlts.zip
-run-xmltest: xmlwf/xmlwf@EXEEXT@ tests/XML-Test-Suite
- tests/xmltest.sh
+tests/xmlconf: tests/xmlts.zip
+ $(MAKE) extract-xmlts-zip
-.SUFFIXES: .c .cpp .lo .@OBJEXT@
+.PHONY: run-xmltest
+run-xmltest: tests/xmlconf
+@WITH_XMLWF_TRUE@ [ -d $(builddir)/tests/xmlconf ] || $(MAKE) extract-xmlts-zip # vpath workaround
+@WITH_XMLWF_TRUE@ $(MAKE) -C lib
+@WITH_XMLWF_TRUE@ $(MAKE) -C xmlwf
+@WITH_XMLWF_TRUE@ $(srcdir)/tests/xmltest.sh "$(abs_builddir)/run.sh $(abs_builddir)/xmlwf/xmlwf@EXEEXT@" 2>&1 | tee $(builddir)/tests/xmltest.log
+@WITH_XMLWF_TRUE@ $(srcdir)/fix-xmltest-log.sh $(builddir)/tests/xmltest.log
+@WITH_XMLWF_TRUE@ diff -u $(srcdir)/tests/xmltest.log.expected $(builddir)/tests/xmltest.log
+@WITH_XMLWF_FALSE@ @echo 'ERROR: xmlwf is needed for "make run-xmltest".' >&2
+@WITH_XMLWF_FALSE@ @echo 'ERROR: Please re-configure without --without-xmlwf.' >&2
+@WITH_XMLWF_FALSE@ @false
-.cpp.@OBJEXT@:
- $(CXXCOMPILE) -o $@ -c $<
-.c.@OBJEXT@:
- $(COMPILE) -o $@ -c $<
-.c.lo:
- $(LTCOMPILE) -o $@ -c $<
+.PHONY: qa
+qa:
+ QA_COMPILER=clang QA_SANITIZER=address ./qa.sh
+ QA_COMPILER=clang QA_SANITIZER=memory ./qa.sh
+ QA_COMPILER=clang QA_SANITIZER=undefined ./qa.sh
+ QA_COMPILER=gcc QA_PROCESSOR=gcov ./qa.sh
-.PHONY: buildlib all \
- clean distclean extraclean maintainer-clean \
- dist distdir \
- install uninstall
+# 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:
diff --git a/3rdparty/expat/README b/3rdparty/expat/README
deleted file mode 100644
index 9ec8d0c6ade..00000000000
--- a/3rdparty/expat/README
+++ /dev/null
@@ -1,139 +0,0 @@
-
- Expat, Release 2.1.1
-
-This is Expat, a C library for parsing XML, written by James Clark.
-Expat is a stream-oriented XML parser. This means that you register
-handlers with the parser before starting the parse. These handlers
-are called when the parser discovers the associated structures in the
-document being parsed. A start tag is an example of the kind of
-structures for which you may register handlers.
-
-Windows users should use the expat_win32bin package, which includes
-both precompiled libraries and executables, and source code for
-developers.
-
-Expat is free software. You may copy, distribute, and modify it under
-the terms of the License contained in the file COPYING distributed
-with this package. This license is the same as the MIT/X Consortium
-license.
-
-Versions of Expat that have an odd minor version (the middle number in
-the release above), are development releases and should be considered
-as beta software. Releases with even minor version numbers are
-intended to be production grade software.
-
-If you are building Expat from a check-out from the CVS repository,
-you need to run a script that generates the configure script using the
-GNU autoconf and libtool tools. To do this, you need to have
-autoconf 2.58 or newer. Run the script like this:
-
- ./buildconf.sh
-
-Once this has been done, follow the same instructions as for building
-from a source distribution.
-
-To build Expat from a source distribution, you first run the
-configuration shell script in the top level distribution directory:
-
- ./configure
-
-There are many options which you may provide to configure (which you
-can discover by running configure with the --help option). But the
-one of most interest is the one that sets the installation directory.
-By default, the configure script will set things up to install
-libexpat into /usr/local/lib, expat.h into /usr/local/include, and
-xmlwf into /usr/local/bin. If, for example, you'd prefer to install
-into /home/me/mystuff/lib, /home/me/mystuff/include, and
-/home/me/mystuff/bin, you can tell configure about that with:
-
- ./configure --prefix=/home/me/mystuff
-
-Another interesting option is to enable 64-bit integer support for
-line and column numbers and the over-all byte index:
-
- ./configure CPPFLAGS=-DXML_LARGE_SIZE
-
-However, such a modification would be a breaking change to the ABI
-and is therefore not recommended for general use - e.g. as part of
-a Linux distribution - but rather for builds with special requirements.
-
-After running the configure script, the "make" command will build
-things and "make install" will install things into their proper
-location. Have a look at the "Makefile" to learn about additional
-"make" options. Note that you need to have write permission into
-the directories into which things will be installed.
-
-If you are interested in building Expat to provide document
-information in UTF-16 encoding rather than the default UTF-8, follow
-these instructions (after having run "make distclean"):
-
- 1. For UTF-16 output as unsigned short (and version/error
- strings as char), run:
-
- ./configure CPPFLAGS=-DXML_UNICODE
-
- For UTF-16 output as wchar_t (incl. version/error strings),
- run:
-
- ./configure CFLAGS="-g -O2 -fshort-wchar" \
- CPPFLAGS=-DXML_UNICODE_WCHAR_T
-
- 2. Edit the MakeFile, changing:
-
- LIBRARY = libexpat.la
-
- to:
-
- LIBRARY = libexpatw.la
-
- (Note the additional "w" in the library name.)
-
- 3. Run "make buildlib" (which builds the library only).
- Or, to save step 2, run "make buildlib LIBRARY=libexpatw.la".
-
- 4. Run "make installlib" (which installs the library only).
- Or, if step 2 was omitted, run "make installlib LIBRARY=libexpatw.la".
-
-Using DESTDIR or INSTALL_ROOT is enabled, with INSTALL_ROOT being the default
-value for DESTDIR, and the rest of the make file using only DESTDIR.
-It works as follows:
- $ make install DESTDIR=/path/to/image
-overrides the in-makefile set DESTDIR, while both
- $ INSTALL_ROOT=/path/to/image make install
- $ make install INSTALL_ROOT=/path/to/image
-use DESTDIR=$(INSTALL_ROOT), even if DESTDIR eventually is defined in the
-environment, because variable-setting priority is
-1) commandline
-2) in-makefile
-3) environment
-
-Note: This only applies to the Expat library itself, building UTF-16 versions
-of xmlwf and the tests is currently not supported.
-
-Note for Solaris users: The "ar" command is usually located in
-"/usr/ccs/bin", which is not in the default PATH. You will need to
-add this to your path for the "make" command, and probably also switch
-to GNU make (the "make" found in /usr/ccs/bin does not seem to work
-properly -- appearantly it does not understand .PHONY directives). If
-you're using ksh or bash, use this command to build:
-
- PATH=/usr/ccs/bin:$PATH make
-
-When using Expat with a project using autoconf for configuration, you
-can use the probing macro in conftools/expat.m4 to determine how to
-include Expat. See the comments at the top of that file for more
-information.
-
-A reference manual is available in the file doc/reference.html in this
-distribution.
-
-The homepage for this project is http://www.libexpat.org/. There
-are links there to connect you to the bug reports page. If you need
-to report a bug when you don't have access to a browser, you may also
-send a bug report by email to expat-bugs@mail.libexpat.org.
-
-Discussion related to the direction of future expat development takes
-place on expat-discuss@mail.libexpat.org. Archives of this list and
-other Expat-related lists may be found at:
-
- http://mail.libexpat.org/mailman/listinfo/
diff --git a/3rdparty/expat/README.md b/3rdparty/expat/README.md
new file mode 100644
index 00000000000..428a11ab245
--- /dev/null
+++ b/3rdparty/expat/README.md
@@ -0,0 +1,194 @@
+[![Travis CI Build Status](https://travis-ci.org/libexpat/libexpat.svg?branch=master)](https://travis-ci.org/libexpat/libexpat)
+[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/libexpat/libexpat?svg=true)](https://ci.appveyor.com/project/libexpat/libexpat)
+[![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions)
+
+
+# Expat, Release 2.2.10
+
+This is Expat, a C library for parsing XML, started by
+[James Clark](https://en.wikipedia.org/wiki/James_Clark_(programmer)) in 1997.
+Expat is a stream-oriented XML parser. This means that you register
+handlers with the parser before starting the parse. These handlers
+are called when the parser discovers the associated structures in the
+document being parsed. A start tag is an example of the kind of
+structures for which you may register handlers.
+
+Expat supports the following compilers:
+- GNU GCC >=4.5
+- LLVM Clang >=3.5
+- Microsoft Visual Studio >=9.0/2008
+
+Windows users can use the
+[`expat_win32` package](https://sourceforge.net/projects/expat/files/expat_win32/),
+which includes both precompiled libraries and executables, and source code for
+developers.
+
+Expat is [free software](https://www.gnu.org/philosophy/free-sw.en.html).
+You may copy, distribute, and modify it under the terms of the License
+contained in the file
+[`COPYING`](https://github.com/libexpat/libexpat/blob/master/expat/COPYING)
+distributed with this package.
+This license is the same as the MIT/X Consortium license.
+
+If you are building Expat from a check-out from the
+[Git repository](https://github.com/libexpat/libexpat/),
+you need to run a script that generates the configure script using the
+GNU autoconf and libtool tools. To do this, you need to have
+autoconf 2.58 or newer. Run the script like this:
+
+```console
+./buildconf.sh
+```
+
+Once this has been done, follow the same instructions as for building
+from a source distribution.
+
+To build Expat from a source distribution, you first run the
+configuration shell script in the top level distribution directory:
+
+```console
+./configure
+```
+
+There are many options which you may provide to configure (which you
+can discover by running configure with the `--help` option). But the
+one of most interest is the one that sets the installation directory.
+By default, the configure script will set things up to install
+libexpat into `/usr/local/lib`, `expat.h` into `/usr/local/include`, and
+`xmlwf` into `/usr/local/bin`. If, for example, you'd prefer to install
+into `/home/me/mystuff/lib`, `/home/me/mystuff/include`, and
+`/home/me/mystuff/bin`, you can tell `configure` about that with:
+
+```console
+./configure --prefix=/home/me/mystuff
+```
+
+Another interesting option is to enable 64-bit integer support for
+line and column numbers and the over-all byte index:
+
+```console
+./configure CPPFLAGS=-DXML_LARGE_SIZE
+```
+
+However, such a modification would be a breaking change to the ABI
+and is therefore not recommended for general use &mdash; e.g. as part of
+a Linux distribution &mdash; but rather for builds with special requirements.
+
+After running the configure script, the `make` command will build
+things and `make install` will install things into their proper
+location. Have a look at the `Makefile` to learn about additional
+`make` options. Note that you need to have write permission into
+the directories into which things will be installed.
+
+If you are interested in building Expat to provide document
+information in UTF-16 encoding rather than the default UTF-8, follow
+these instructions (after having run `make distclean`).
+Please note that we configure with `--without-xmlwf` as xmlwf does not
+support this mode of compilation (yet):
+
+1. Mass-patch `Makefile.am` files to use `libexpatw.la` for a library name:
+ <br/>
+ `find -name Makefile.am -exec sed
+ -e 's,libexpat\.la,libexpatw.la,'
+ -e 's,libexpat_la,libexpatw_la,'
+ -i {} +`
+
+1. Run `automake` to re-write `Makefile.in` files:<br/>
+ `automake`
+
+1. For UTF-16 output as unsigned short (and version/error strings as char),
+ run:<br/>
+ `./configure CPPFLAGS=-DXML_UNICODE --without-xmlwf`<br/>
+ For UTF-16 output as `wchar_t` (incl. version/error strings), run:<br/>
+ `./configure CFLAGS="-g -O2 -fshort-wchar" CPPFLAGS=-DXML_UNICODE_WCHAR_T
+ --without-xmlwf`
+ <br/>Note: The latter requires libc compiled with `-fshort-wchar`, as well.
+
+1. Run `make` (which excludes xmlwf).
+
+1. Run `make install` (again, excludes xmlwf).
+
+Using `DESTDIR` is supported. It works as follows:
+
+```console
+make install DESTDIR=/path/to/image
+```
+
+overrides the in-makefile set `DESTDIR`, because variable-setting priority is
+
+1. commandline
+1. in-makefile
+1. environment
+
+Note: This only applies to the Expat library itself, building UTF-16 versions
+of xmlwf and the tests is currently not supported.
+
+When using Expat with a project using autoconf for configuration, you
+can use the probing macro in `conftools/expat.m4` to determine how to
+include Expat. See the comments at the top of that file for more
+information.
+
+A reference manual is available in the file `doc/reference.html` in this
+distribution.
+
+
+The CMake build system is still *experimental* and will replace the primary
+build system based on GNU Autotools at some point when it is ready.
+For an idea of the available (non-advanced) options for building with CMake:
+
+```console
+# rm -f CMakeCache.txt ; cmake -D_EXPAT_HELP=ON -LH . | grep -B1 ':.*=' | sed 's,^--$,,'
+// Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ...
+CMAKE_BUILD_TYPE:STRING=
+
+// Install path prefix, prepended onto install directories.
+CMAKE_INSTALL_PREFIX:PATH=/usr/local
+
+// Path to a program.
+DOCBOOK_TO_MAN:FILEPATH=/usr/bin/docbook2x-man
+
+// build man page for xmlwf
+EXPAT_BUILD_DOCS:BOOL=ON
+
+// build the examples for expat library
+EXPAT_BUILD_EXAMPLES:BOOL=ON
+
+// build fuzzers for the expat library
+EXPAT_BUILD_FUZZERS:BOOL=OFF
+
+// build pkg-config file
+EXPAT_BUILD_PKGCONFIG:BOOL=ON
+
+// build the tests for expat library
+EXPAT_BUILD_TESTS:BOOL=ON
+
+// build the xmlwf tool for expat library
+EXPAT_BUILD_TOOLS:BOOL=ON
+
+// Character type to use (char|ushort|wchar_t) [default=char]
+EXPAT_CHAR_TYPE:STRING=char
+
+// install expat files in cmake install target
+EXPAT_ENABLE_INSTALL:BOOL=ON
+
+// Use /MT flag (static CRT) when compiling in MSVC
+EXPAT_MSVC_STATIC_CRT:BOOL=OFF
+
+// build fuzzers via ossfuzz for the expat library
+EXPAT_OSSFUZZ_BUILD:BOOL=OFF
+
+// build a shared expat library
+EXPAT_SHARED_LIBS:BOOL=ON
+
+// Treat all compiler warnings as errors
+EXPAT_WARNINGS_AS_ERRORS:BOOL=OFF
+
+// Make use of getrandom function (ON|OFF|AUTO) [default=AUTO]
+EXPAT_WITH_GETRANDOM:STRING=AUTO
+
+// utilize libbsd (for arc4random_buf)
+EXPAT_WITH_LIBBSD:BOOL=OFF
+
+// Make use of syscall SYS_getrandom (ON|OFF|AUTO) [default=AUTO]
+EXPAT_WITH_SYS_GETRANDOM:STRING=AUTO
+```
diff --git a/3rdparty/expat/acinclude.m4 b/3rdparty/expat/acinclude.m4
new file mode 100644
index 00000000000..7277ab29bbb
--- /dev/null
+++ b/3rdparty/expat/acinclude.m4
@@ -0,0 +1,12 @@
+# acinclude.m4 --
+#
+
+m4_include(conftools/ax-require-defined.m4)
+m4_include(conftools/ax-check-compile-flag.m4)
+m4_include(conftools/ax-check-link-flag.m4)
+m4_include(conftools/ax-append-flag.m4)
+m4_include(conftools/ax-append-compile-flags.m4)
+m4_include(conftools/ax-append-link-flags.m4)
+m4_include(conftools/expatcfg-compiler-supports-visibility.m4)
+
+### end of file
diff --git a/3rdparty/expat/aclocal.m4 b/3rdparty/expat/aclocal.m4
index f70f488482b..b8cb1fc8ca0 100644
--- a/3rdparty/expat/aclocal.m4
+++ b/3rdparty/expat/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -12,8 +12,1192 @@
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.16'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.16.2], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.16.2])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed. If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+ [AC_LANG_PUSH([C])
+ am_cv_ar_interface=ar
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+ [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([am_ar_try])
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=ar
+ else
+ am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([am_ar_try])
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=lib
+ else
+ am_cv_ar_interface=unknown
+ fi
+ fi
+ rm -f conftest.lib libconftest.a
+ ])
+ AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+ ;;
+lib)
+ # Microsoft lib, so override with the ar-lib wrapper script.
+ # FIXME: It is wrong to rewrite AR.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__AR in this case,
+ # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+ # similar.
+ AR="$am_aux_dir/ar-lib $AR"
+ ;;
+unknown)
+ m4_default([$1],
+ [AC_MSG_ERROR([could not determine $AR interface])])
+ ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ AS_CASE([$CONFIG_FILES],
+ [*\'*], [eval set x "$CONFIG_FILES"],
+ [*], [set x $CONFIG_FILES])
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`AS_DIRNAME(["$am_mf"])`
+ am_filepart=`AS_BASENAME(["$am_mf"])`
+ AM_RUN_LOG([cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles]) || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. If GNU make was not used, consider
+ re-running the configure script with MAKE="gmake" (or whatever is
+ necessary). You can also try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).])
+ fi
+ AS_UNSET([am_dirpart])
+ AS_UNSET([am_filepart])
+ AS_UNSET([am_mf])
+ AS_UNSET([am_rc])
+ rm -f conftest-deps.mk
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking is enabled.
+# This creates each '.Po' and '.Plo' makefile fragment that we'll need in
+# order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check whether make has an 'include' directive that can support all
+# the idioms we need for our automatic dependency tracking code.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive])
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out])
+ AS_CASE([$?:`cat confinc.out 2>/dev/null`],
+ ['0:this is the am__doit target'],
+ [AS_CASE([$s],
+ [BSD], [am__include='.include' am__quote='"'],
+ [am__include='include' am__quote=''])])
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+AC_MSG_RESULT([${_am_result}])
+AC_SUBST([am__include])])
+AC_SUBST([am__quote])])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # 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".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2020 Free Software Foundation, Inc.
+#
+# This file 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.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
m4_include([m4/libtool.m4])
m4_include([m4/ltoptions.m4])
m4_include([m4/ltsugar.m4])
m4_include([m4/ltversion.m4])
m4_include([m4/lt~obsolete.m4])
+m4_include([acinclude.m4])
diff --git a/3rdparty/expat/amiga/Makefile b/3rdparty/expat/amiga/Makefile
deleted file mode 100644
index c6d12619981..00000000000
--- a/3rdparty/expat/amiga/Makefile
+++ /dev/null
@@ -1,336 +0,0 @@
-#
-# Makefile for AmigaOS
-#
-
-.PHONY: help all check clean package
-.PHONY: clib2 newlib library so
-
-vpath %.c ../lib ../examples ../xmlwf ../tests ../tests/benchmark
-vpath %.h ../lib ../tests
-
-#############################################################################
-
-help:
- @echo "Requires:"
- @echo " AmigaOS 4.x"
- @echo " SDK 53.13"
- @echo ""
- @echo "Targets:"
- @echo " all - make libraries, xmlwf, examples and runs tests"
- @echo " install - install expat libraries and tools into SDK"
- @echo " clean - clean object files"
- @echo " check - run all the tests"
- @echo " package - prepare distribution archive"
-
-all: clib2 newlib library so check
-
-clib2: clib2/libexpat.a clib2/xmlwf clib2/elements clib2/outline clib2/runtests clib2/benchmark
-
-newlib: newlib/libexpat.a newlib/xmlwf newlib/elements newlib/outline newlib/runtests newlib/benchmark
-
-library: libs/expat.library libs/xmlwf libs/elements libs/outline libs/runtests libs/benchmark
-
-so: so/libexpat.so so/xmlwf so/elements so/outline so/runtests so/benchmark
-
-check: clib2/runtests newlib/runtests libs/runtests so/runtests
- clib2/runtests
- newlib/runtests
- libs/runtests
- so/runtests
-
-clean:
- -delete clib2/#?.o quiet
- -delete newlib/#?.o quiet
- -delete libs/#?.o quiet
- -delete so/#?.o quiet
-
-package:
- $(MAKE) all
- -delete T:expat all force quiet
- makedir all T:expat/Workbench/Libs
- copy clone libs/expat.library T:expat/Workbench/Libs
- makedir all T:expat/Workbench/SObjs
- copy clone so/libexpat.so T:expat/Workbench/SObjs
- makedir all T:expat/SDK/Local/C
- copy clone libs/xmlwf T:expat/SDK/Local/C
- makedir all T:expat/SDK/Local/clib2/lib
- copy clone clib2/libexpat.a T:expat/SDK/Local/clib2/lib
- makedir all T:expat/SDK/Local/newlib/lib
- copy clone newlib/libexpat.a T:expat/SDK/Local/newlib/lib
- makedir all T:expat/SDK/Local/common/include
- copy clone /lib/expat.h /lib/expat_external.h T:expat/SDK/Local/common/include
- makedir all T:expat/SDK/Include/include_h/inline4
- copy clone include/inline4/expat.h T:expat/SDK/Include/include_h/inline4
- makedir all T:expat/SDK/Include/include_h/interfaces
- copy clone include/interfaces/expat.h T:expat/SDK/Include/include_h/interfaces
- makedir all T:expat/SDK/Include/include_h/libraries
- copy clone include/libraries/expat.h T:expat/SDK/Include/include_h/libraries
- makedir all T:expat/SDK/Include/include_h/proto
- copy clone include/proto/expat.h T:expat/SDK/Include/include_h/proto
- makedir all T:expat/SDK/Documentation/Libs/Expat
- copy clone /COPYING T:expat/SDK/Documentation/Libs/Expat
- copy clone /README T:expat/SDK/Documentation/Libs/Expat
- copy clone README.txt T:expat/SDK/Documentation/Libs/Expat/README.AmigaOS
- -delete expat.lha
- lha -r a expat.lha T:expat
-
-#############################################################################
-
-CC := gcc
-LIBTOOL := ar
-STRIP := strip
-
-CFLAGS := -DNDEBUG -O3
-LTFLAGS := -crs
-STRIPFLAGS := -R.comment
-
-#############################################################################
-
-clib2/libexpat.a: clib2/xmlparse.o clib2/xmltok.o clib2/xmlrole.o
- $(LIBTOOL) $(LTFLAGS) $@ $^
- protect $@ -e
-
-clib2/xmlparse.o: xmlparse.c expat.h xmlrole.h xmltok.h \
- expat_external.h internal.h amigaconfig.h
-
-clib2/xmlrole.o: xmlrole.c ascii.h xmlrole.h expat_external.h \
- internal.h amigaconfig.h
-
-clib2/xmltok.o: xmltok.c xmltok_impl.c xmltok_ns.c ascii.h asciitab.h \
- iasciitab.h latin1tab.h nametab.h utf8tab.h xmltok.h xmltok_impl.h \
- expat_external.h internal.h amigaconfig.h
-
-#############################################################################
-
-clib2/xmlwf: clib2/xmlwf.o clib2/xmlfile.o clib2/codepage.o clib2/readfilemap.o
- $(CC) -mcrt=clib2 $^ -o $@ clib2/libexpat.a
- $(STRIP) $(STRIPFLAGS) $@
-
-clib2/xmlwf.o: xmlwf.c
-
-clib2/xmlfile.o: xmlfile.c
-
-clib2/codepage.o: codepage.c
-
-clib2/readfilemap.o: readfilemap.c
-
-#############################################################################
-
-clib2/elements: clib2/elements.o
- $(CC) -mcrt=clib2 $^ -o $@ clib2/libexpat.a
- $(STRIP) $(STRIPFLAGS) $@
-
-clib2/elements.o: elements.c
-
-#############################################################################
-
-clib2/outline: clib2/outline.o
- $(CC) -mcrt=clib2 $^ -o $@ clib2/libexpat.a
- $(STRIP) $(STRIPFLAGS) $@
-
-clib2/outline.o: outline.c
-
-#############################################################################
-
-clib2/runtests: clib2/runtests.o clib2/chardata.o clib2/minicheck.o
- $(CC) -mcrt=clib2 $^ -o $@ clib2/libexpat.a
-
-clib2/chardata.o: chardata.c chardata.h
-
-clib2/minicheck.o: minicheck.c minicheck.h
-
-clib2/runtests.o: runtests.c chardata.h
-
-#############################################################################
-
-clib2/benchmark: clib2/benchmark.o
- $(CC) -mcrt=clib2 $^ -o $@ clib2/libexpat.a -lm
-
-clib2/benchmark.o: benchmark.c
-
-#############################################################################
-
-newlib/libexpat.a: newlib/xmlparse.o newlib/xmltok.o newlib/xmlrole.o
- $(LIBTOOL) $(LTFLAGS) $@ $^
- protect $@ -e
-
-newlib/xmlparse.o: xmlparse.c expat.h xmlrole.h xmltok.h \
- expat_external.h internal.h amigaconfig.h
-
-newlib/xmlrole.o: xmlrole.c ascii.h xmlrole.h expat_external.h \
- internal.h amigaconfig.h
-
-newlib/xmltok.o: xmltok.c xmltok_impl.c xmltok_ns.c ascii.h asciitab.h \
- iasciitab.h latin1tab.h nametab.h utf8tab.h xmltok.h xmltok_impl.h \
- expat_external.h internal.h amigaconfig.h
-
-#############################################################################
-
-newlib/xmlwf: newlib/xmlwf.o newlib/xmlfile.o newlib/codepage.o newlib/readfilemap.o
- $(CC) -mcrt=newlib $^ -o $@ newlib/libexpat.a
- $(STRIP) $(STRIPFLAGS) $@
-
-newlib/xmlwf.o: xmlwf.c
-
-newlib/xmlfile.o: xmlfile.c
-
-newlib/codepage.o: codepage.c
-
-newlib/readfilemap.o: readfilemap.c
-
-#############################################################################
-
-newlib/elements: newlib/elements.o
- $(CC) -mcrt=newlib $^ -o $@ newlib/libexpat.a
- $(STRIP) $(STRIPFLAGS) $@
-
-newlib/elements.o: elements.c
-
-#############################################################################
-
-newlib/outline: newlib/outline.o
- $(CC) -mcrt=newlib $^ -o $@ newlib/libexpat.a
- $(STRIP) $(STRIPFLAGS) $@
-
-newlib/outline.o: outline.c
-
-#############################################################################
-
-newlib/runtests: newlib/runtests.o newlib/chardata.o newlib/minicheck.o
- $(CC) -mcrt=newlib $^ -o $@ newlib/libexpat.a
-
-newlib/chardata.o: chardata.c chardata.h
-
-newlib/minicheck.o: minicheck.c minicheck.h
-
-newlib/runtests.o: runtests.c chardata.h
-
-#############################################################################
-
-newlib/benchmark: newlib/benchmark.o
- $(CC) -mcrt=newlib $^ -o $@ newlib/libexpat.a
-
-newlib/benchmark.o: benchmark.c
-
-#############################################################################
-
-libs/expat.library: libs/expat_lib.o libs/expat_68k.o libs/expat_68k_handler_stubs.o libs/expat_vectors.o newlib/libexpat.a
- $(CC) -mcrt=newlib -nostartfiles $^ -o $@ newlib/libexpat.a -Wl,--cref,-M,-Map=$@.map
- protect $@ -e
- $(STRIP) $(STRIPFLAGS) $@
-
-libs/expat_lib.o: expat_lib.c expat_base.h
-
-libs/expat_68k.o: expat_68k.c expat_68k.h expat_base.h
-
-libs/expat_68k_handler_stubs.o: expat_68k_handler_stubs.c expat_68k.h
-
-libs/expat_vectors.o: expat_vectors.c
-
-libs/launch.o: launch.c
-
-#############################################################################
-
-libs/xmlwf: libs/xmlwf.o libs/xmlfile.o libs/codepage.o libs/readfilemap.o libs/launch.o
- $(CC) -mcrt=newlib $^ -o $@
- $(STRIP) $(STRIPFLAGS) $@
-
-libs/xmlwf.o: xmlwf.c
-
-libs/xmlfile.o: xmlfile.c
-
-libs/codepage.o: codepage.c
-
-libs/readfilemap.o: readfilemap.c
-
-#############################################################################
-
-libs/elements: libs/elements.o libs/launch.o
- $(CC) -mcrt=newlib $^ -o $@
- $(STRIP) $(STRIPFLAGS) $@
-
-libs/elements.o: elements.c
-
-#############################################################################
-
-libs/outline: libs/outline.o libs/launch.o
- $(CC) -mcrt=newlib $^ -o $@
- $(STRIP) $(STRIPFLAGS) $@
-
-libs/outline.o: outline.c
-
-#############################################################################
-
-libs/runtests: libs/runtests.o libs/chardata.o libs/minicheck.o libs/launch.o
- $(CC) -mcrt=newlib $^ -o $@
-
-libs/chardata.o: chardata.c chardata.h
-
-libs/minicheck.o: minicheck.c minicheck.h
-
-libs/runtests.o: runtests.c chardata.h
-
-#############################################################################
-
-libs/benchmark: libs/benchmark.o libs/launch.o
- $(CC) -mcrt=newlib $^ -o $@
-
-libs/benchmark.o: benchmark.c
-
-#############################################################################
-
-so/libexpat.so: so/xmlparse.o so/xmltok.o so/xmlrole.o
- $(CC) -mcrt=newlib -shared -o $@ $^
- protect $@ -e
-
-so/xmlparse.o: xmlparse.c expat.h xmlrole.h xmltok.h \
- expat_external.h internal.h amigaconfig.h
-
-so/xmlrole.o: xmlrole.c ascii.h xmlrole.h expat_external.h \
- internal.h amigaconfig.h
-
-so/xmltok.o: xmltok.c xmltok_impl.c xmltok_ns.c ascii.h asciitab.h \
- iasciitab.h latin1tab.h nametab.h utf8tab.h xmltok.h xmltok_impl.h \
- expat_external.h internal.h amigaconfig.h
-
-#############################################################################
-
-so/xmlwf: newlib/xmlwf.o newlib/xmlfile.o newlib/codepage.o newlib/readfilemap.o
- $(CC) -mcrt=newlib -use-dynld $^ -o $@ -Lso -lexpat
- $(STRIP) $(STRIPFLAGS) $@
-
-#############################################################################
-
-so/elements: newlib/elements.o
- $(CC) -mcrt=newlib -use-dynld $^ -o $@ -Lso -lexpat
- $(STRIP) $(STRIPFLAGS) $@
-
-#############################################################################
-
-so/outline: newlib/outline.o
- $(CC) -mcrt=newlib -use-dynld $^ -o $@ -Lso -lexpat
- $(STRIP) $(STRIPFLAGS) $@
-
-#############################################################################
-
-so/runtests: newlib/runtests.o newlib/chardata.o newlib/minicheck.o
- $(CC) -mcrt=newlib -use-dynld $^ -o $@ -Lso -lexpat
-
-#############################################################################
-
-so/benchmark: newlib/benchmark.o
- $(CC) -mcrt=newlib -use-dynld $^ -o $@ -Lso -lexpat
-
-#############################################################################
-
-clib2/%.o: %.c
- $(CC) -mcrt=clib2 $(CFLAGS) -I../lib -c $< -o $@
-
-newlib/%.o: %.c
- $(CC) -mcrt=newlib $(CFLAGS) -I../lib -c $< -o $@
-
-libs/%.o: %.c
- $(CC) -mcrt=newlib $(CFLAGS) -D__USE_INLINE__ -I. -Iinclude -Iinclude/libraries -I../lib -c $< -o $@
-
-so/%.o: %.c
- $(CC) -mcrt=newlib $(CFLAGS) -fPIC -I../lib -c $< -o $@
diff --git a/3rdparty/expat/amiga/README.txt b/3rdparty/expat/amiga/README.txt
deleted file mode 100644
index 3ba9267ef84..00000000000
--- a/3rdparty/expat/amiga/README.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-SUMMARY
-=======
-This is a port of expat for AmigaOS 4.x which includes the
-SDK, some XML tools and the libraries.
-
-Four library flavours are supported:
-1. static clib2 (libexpat.a)
-2. static newlib (libexpat.a)
-3. AmigaOS library (expat.library)
-4. AmigaOS shared object library (libexpat.so)
-
-The AmigaOS library version is based on the work of Fredrik Wikstrom.
-
-
-BUILDING
-========
-To build all the library flavours, all the tools, examples and run the
-test suite, simply type 'make all' in the amiga subdirectory.
-
-
-INSTALLATION
-============
-To install expat into the standard AmigaOS SDK type 'make install'
-in the amiga subdirectory.
-
-
-CONFIGURATION
-=============
-You may want to edit the lib/amigaconfig.h file to remove
-DTD and/or XML namespace support if they are not required by your
-specific application for a smaller and faster implementation.
-
-
-SOURCE CODE
-===========
-The source code is actively maintained and merged with the official
-Expat repository available at http://expat.sourceforge.net/
-
-
-HISTORY
-=======
-53.1 - bumped version to match AmigaOS streaming
- - modified to remove all global variables (except INewLib)
- - removed replacements for malloc(), etc. which are now
- handled by the respective C library
- - compiled with the latest binutils which bumps the
- AMIGAOS_DYNVERSION to 2 for the libexpat.so target
- - now strips the expat.library binary
-
-5.2 - fixed XML_Parse 68k stub which enables xmlviewer to work
- without crashing
- - added some new functions to the 68k jump table available
- in the latest expat.library for AmigaOS 3.x
- - patches provided by Fredrik Wikstrom
-
-5.1 - fixed package archive which was missing libexpat.so
- - fixed library protection bits
- - fixed up copyright notices
-
-5.0 - integrated 68k patches from Fredrik Wikstrom which means
- expat.library is now callable from 68k code
- - bumped version for the addition of the 68k interface so
- executables can explicitly ask for version 5 and know
- it includes the 68k interface
- - refactored Makefile to avoid recursive make calls and
- build all the library flavours
- - added static newlib version
- - added shared objects version
- - added package target to Makefile
- - compiled with SDK 53.13 (GCC 4.2.4) at -O3
-
-4.2 - updated to correspond to Expat 2.0.1 release
- - bumped copyright banners and versions
- - simplified amigaconfig.h
- - updated include/libraries/expat.h file
- - modified launch.c to use contructor/deconstructor
- - removed need for amiga_main() from expat utilities
-
-4.1 - fixed memory freeing bug in shared library version
- - now allocates shared memory
-
-4.0 - updated for corresponding Expat 2.0 release
- - some minor CVS related changes
-
-3.1 - removed obsolete sfd file
- - added library description xml file
- - refactored Makefile
- - removed extraneous VARARGS68K keywords
- - reworked default memory handling functions in shared lib
- - updated amigaconfig.h
-
-3.0 - initial release
- - based on expat 1.95.8
-
-
-TO DO
-=====
-- wide character support (UTF-16)
diff --git a/3rdparty/expat/amiga/expat.xml b/3rdparty/expat/amiga/expat.xml
deleted file mode 100644
index d6aeae2e3ab..00000000000
--- a/3rdparty/expat/amiga/expat.xml
+++ /dev/null
@@ -1,264 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE library SYSTEM "library.dtd">
-<!-- autogenerated by fdtrans v51.16 -->
-<library name="expat" basename="ExpatBase" basetype="Library" openname="expat.library">
- <include>libraries/expat.h</include>
- <interface name="main" version="1.0" struct="ExpatIFace" prefix="_Expat_" asmprefix="IExpat" global="IExpat">
- <method name="Obtain" result="uint32"/>
- <method name="Release" result="uint32"/>
- <method name="Expunge" result="void" status="unimplemented"/>
- <method name="Clone" result="struct Interface *" status="unimplemented"/>
- <method name="XML_ParserCreate" result="XML_Parser">
- <arg name="encodingName" type="const XML_Char *"/>
- </method>
- <method name="XML_ParserCreateNS" result="XML_Parser">
- <arg name="encodingName" type="const XML_Char *"/>
- <arg name="nsSep" type="XML_Char"/>
- </method>
- <method name="XML_ParserCreate_MM" result="XML_Parser">
- <arg name="encoding" type="const XML_Char *"/>
- <arg name="memsuite" type="const XML_Memory_Handling_Suite *"/>
- <arg name="namespaceSeparator" type="const XML_Char *"/>
- </method>
- <method name="XML_ExternalEntityParserCreate" result="XML_Parser">
- <arg name="parser" type="XML_Parser"/>
- <arg name="context" type="const XML_Char *"/>
- <arg name="encoding" type="const XML_Char *"/>
- </method>
- <method name="XML_ParserFree" result="void">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_Parse" result="enum XML_Status">
- <arg name="parser" type="XML_Parser"/>
- <arg name="s" type="const char *"/>
- <arg name="len" type="int"/>
- <arg name="isFinal" type="int"/>
- </method>
- <method name="XML_ParseBuffer" result="enum XML_Status">
- <arg name="parser" type="XML_Parser"/>
- <arg name="len" type="int"/>
- <arg name="isFinal" type="int"/>
- </method>
- <method name="XML_GetBuffer" result="void *">
- <arg name="parser" type="XML_Parser"/>
- <arg name="len" type="int"/>
- </method>
- <method name="XML_SetStartElementHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartElementHandler"/>
- </method>
- <method name="XML_SetEndElementHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="end" type="XML_EndElementHandler"/>
- </method>
- <method name="XML_SetElementHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartElementHandler"/>
- <arg name="end" type="XML_EndElementHandler"/>
- </method>
- <method name="XML_SetCharacterDataHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_CharacterDataHandler"/>
- </method>
- <method name="XML_SetProcessingInstructionHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_ProcessingInstructionHandler"/>
- </method>
- <method name="XML_SetCommentHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_CommentHandler"/>
- </method>
- <method name="XML_SetStartCdataSectionHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartCdataSectionHandler"/>
- </method>
- <method name="XML_SetEndCdataSectionHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="end" type="XML_EndCdataSectionHandler"/>
- </method>
- <method name="XML_SetCdataSectionHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartCdataSectionHandler"/>
- <arg name="end" type="XML_EndCdataSectionHandler"/>
- </method>
- <method name="XML_SetDefaultHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_DefaultHandler"/>
- </method>
- <method name="XML_SetDefaultHandlerExpand" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_DefaultHandler"/>
- </method>
- <method name="XML_SetExternalEntityRefHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_ExternalEntityRefHandler"/>
- </method>
- <method name="XML_SetExternalEntityRefHandlerArg" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="arg" type="void *"/>
- </method>
- <method name="XML_SetUnknownEncodingHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_UnknownEncodingHandler"/>
- <arg name="data" type="void *"/>
- </method>
- <method name="XML_SetStartNamespaceDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartNamespaceDeclHandler"/>
- </method>
- <method name="XML_SetEndNamespaceDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="end" type="XML_EndNamespaceDeclHandler"/>
- </method>
- <method name="XML_SetNamespaceDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartNamespaceDeclHandler"/>
- <arg name="end" type="XML_EndNamespaceDeclHandler"/>
- </method>
- <method name="XML_SetXmlDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_XmlDeclHandler"/>
- </method>
- <method name="XML_SetStartDoctypeDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartDoctypeDeclHandler"/>
- </method>
- <method name="XML_SetEndDoctypeDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="end" type="XML_EndDoctypeDeclHandler"/>
- </method>
- <method name="XML_SetDoctypeDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="start" type="XML_StartDoctypeDeclHandler"/>
- <arg name="end" type="XML_EndDoctypeDeclHandler"/>
- </method>
- <method name="XML_SetElementDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="eldecl" type="XML_ElementDeclHandler"/>
- </method>
- <method name="XML_SetAttlistDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="attdecl" type="XML_AttlistDeclHandler"/>
- </method>
- <method name="XML_SetEntityDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_EntityDeclHandler"/>
- </method>
- <method name="XML_SetUnparsedEntityDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_UnparsedEntityDeclHandler"/>
- </method>
- <method name="XML_SetNotationDeclHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_NotationDeclHandler"/>
- </method>
- <method name="XML_SetNotStandaloneHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_NotStandaloneHandler"/>
- </method>
- <method name="XML_GetErrorCode" result="enum XML_Error">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_ErrorString" result="const XML_LChar *">
- <arg name="code" type="enum XML_Error"/>
- </method>
- <method name="XML_GetCurrentByteIndex" result="long">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetCurrentLineNumber" result="int">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetCurrentColumnNumber" result="int">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetCurrentByteCount" result="int">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetInputContext" result="const char *">
- <arg name="parser" type="XML_Parser"/>
- <arg name="offset" type="int *"/>
- <arg name="size" type="int *"/>
- </method>
- <method name="XML_SetUserData" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="userData" type="void *"/>
- </method>
- <method name="XML_DefaultCurrent" result="void">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_UseParserAsHandlerArg" result="void">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_SetBase" result="enum XML_Status">
- <arg name="parser" type="XML_Parser"/>
- <arg name="base" type="const XML_Char *"/>
- </method>
- <method name="XML_GetBase" result="const XML_Char *">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetSpecifiedAttributeCount" result="int">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetIdAttributeIndex" result="int">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_SetEncoding" result="enum XML_Status">
- <arg name="parser" type="XML_Parser"/>
- <arg name="encoding" type="const XML_Char *"/>
- </method>
- <method name="XML_SetParamEntityParsing" result="int">
- <arg name="parser" type="XML_Parser"/>
- <arg name="parsing" type="enum XML_ParamEntityParsing"/>
- </method>
- <method name="XML_SetReturnNSTriplet" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="do_nst" type="int"/>
- </method>
- <method name="XML_ExpatVersion" result="const XML_LChar *">
- </method>
- <method name="XML_ExpatVersionInfo" result="XML_Expat_Version">
- </method>
- <method name="XML_ParserReset" result="XML_Bool">
- <arg name="parser" type="XML_Parser"/>
- <arg name="encoding" type="const XML_Char *"/>
- </method>
- <method name="XML_SetSkippedEntityHandler" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="handler" type="XML_SkippedEntityHandler"/>
- </method>
- <method name="XML_UseForeignDTD" result="enum XML_Error">
- <arg name="parser" type="XML_Parser"/>
- <arg name="useDTD" type="XML_Bool"/>
- </method>
- <method name="XML_GetFeatureList" result="const XML_Feature *">
- </method>
- <method name="XML_StopParser" result="enum XML_Status">
- <arg name="parser" type="XML_Parser"/>
- <arg name="resumable" type="XML_Bool"/>
- </method>
- <method name="XML_ResumeParser" result="enum XML_Status">
- <arg name="parser" type="XML_Parser"/>
- </method>
- <method name="XML_GetParsingStatus" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="status" type="XML_ParsingStatus *"/>
- </method>
- <method name="XML_FreeContentModel" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="model" type="XML_Content *"/>
- </method>
- <method name="XML_MemMalloc" result="void *">
- <arg name="parser" type="XML_Parser"/>
- <arg name="size" type="size_t"/>
- </method>
- <method name="XML_MemRealloc" result="void *">
- <arg name="parser" type="XML_Parser"/>
- <arg name="ptr" type="void *"/>
- <arg name="size" type="size_t"/>
- </method>
- <method name="XML_MemFree" result="void">
- <arg name="parser" type="XML_Parser"/>
- <arg name="ptr" type="void *"/>
- </method>
- </interface>
-</library>
diff --git a/3rdparty/expat/amiga/expat_68k.c b/3rdparty/expat/amiga/expat_68k.c
deleted file mode 100644
index aa4c6e2706e..00000000000
--- a/3rdparty/expat/amiga/expat_68k.c
+++ /dev/null
@@ -1,939 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-/*
-** Note: This file was originally automatically generated by fdtrans.
-*/
-
-#ifdef __USE_INLINE__
-#undef __USE_INLINE__
-#endif
-
-#include <exec/interfaces.h>
-#include <exec/libraries.h>
-#include <exec/emulation.h>
-#include <proto/exec.h>
-#include <interfaces/expat.h>
-#include "expat_68k.h"
-#include "expat_base.h"
-
-
-STATIC ULONG stub_OpenPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct LibraryManagerInterface *Self = (struct LibraryManagerInterface *) ExtLib->ILibrary;
-
- return (ULONG) Self->Open(0);
-}
-struct EmuTrap stub_Open = { TRAPINST, TRAPTYPE, stub_OpenPPC };
-
-STATIC ULONG stub_ClosePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct LibraryManagerInterface *Self = (struct LibraryManagerInterface *) ExtLib->ILibrary;
-
- return (ULONG) Self->Close();
-}
-struct EmuTrap stub_Close = { TRAPINST, TRAPTYPE, stub_ClosePPC };
-
-STATIC ULONG stub_ExpungePPC(ULONG *regarray)
-{
- return 0UL;
-}
-struct EmuTrap stub_Expunge = { TRAPINST, TRAPTYPE, stub_ExpungePPC };
-
-STATIC ULONG stub_ReservedPPC(ULONG *regarray)
-{
- return 0UL;
-}
-struct EmuTrap stub_Reserved = { TRAPINST, TRAPTYPE, stub_ReservedPPC };
-
-static M68kXML_Parser stub_XML_ParserCreatePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
- struct ExecIFace *IExec = ((struct ExpatBase *)Self->Data.LibBase)->IExec;
-
- M68kXML_Parser p;
- p = IExec->AllocVec(sizeof(*p), MEMF_SHARED|MEMF_CLEAR);
- if (p) {
- p->p = Self->XML_ParserCreate((const XML_Char *)regarray[8]);
- if (p->p) {
- p->IExec = IExec;
- Self->XML_SetUserData(p->p, p);
- return p;
- }
- IExec->FreeVec(p);
- }
- return NULL;
-}
-struct EmuTrap stub_XML_ParserCreate = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParserCreatePPC };
-
-static M68kXML_Parser stub_XML_ParserCreateNSPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
- struct ExecIFace *IExec = ((struct ExpatBase *)Self->Data.LibBase)->IExec;
-
- M68kXML_Parser p;
- p = IExec->AllocVec(sizeof(*p), MEMF_SHARED|MEMF_CLEAR);
- if (p) {
- p->p = Self->XML_ParserCreateNS((const XML_Char *)regarray[8], (XML_Char)regarray[0]);
- if (p->p) {
- p->IExec = IExec;
- Self->XML_SetUserData(p->p, p);
- return p;
- }
- IExec->FreeVec(p);
- }
- return NULL;
-}
-struct EmuTrap stub_XML_ParserCreateNS = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParserCreateNSPPC };
-
-static M68kXML_Parser stub_XML_ParserCreate_MMPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
- struct ExecIFace *IExec = ((struct ExpatBase *)Self->Data.LibBase)->IExec;
-
- M68kXML_Parser p;
- p = IExec->AllocVec(sizeof(*p), MEMF_SHARED|MEMF_CLEAR);
- if (p) {
- p->p = Self->XML_ParserCreate_MM((const XML_Char *)regarray[8],
- (const XML_Memory_Handling_Suite *)regarray[9],
- (const XML_Char *)regarray[10]);
- if (p->p) {
- p->IExec = IExec;
- Self->XML_SetUserData(p->p, p);
- return p;
- }
- IExec->FreeVec(p);
- }
- return NULL;
-}
-struct EmuTrap stub_XML_ParserCreate_MM = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParserCreate_MMPPC };
-
-static M68kXML_Parser stub_XML_ExternalEntityParserCreatePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
- struct ExecIFace *IExec = ((struct ExpatBase *)Self->Data.LibBase)->IExec;
-
- M68kXML_Parser p;
- p = IExec->AllocVec(sizeof(*p), MEMF_SHARED|MEMF_CLEAR);
- if (p) {
- p->p = Self->XML_ExternalEntityParserCreate((XML_Parser)regarray[8],
- (const XML_Char *)regarray[9], (const XML_Char *)regarray[10]);
- if (p->p) {
- p->IExec = IExec;
- Self->XML_SetUserData(p->p, p);
- return p;
- }
- IExec->FreeVec(p);
- }
- return NULL;
-}
-struct EmuTrap stub_XML_ExternalEntityParserCreate = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ExternalEntityParserCreatePPC };
-
-static void stub_XML_ParserFreePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
- struct ExecIFace *IExec = ((struct ExpatBase *)Self->Data.LibBase)->IExec;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- if (p) {
- Self->XML_ParserFree(p->p);
- IExec->FreeVec(p);
- }
-}
-struct EmuTrap stub_XML_ParserFree = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParserFreePPC };
-
-static int stub_XML_ParsePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- Self->XML_SetUserData(p->p, p);
- return Self->XML_Parse(p->p, (const char *)regarray[9], (int)regarray[0], (int)regarray[1]);
-}
-struct EmuTrap stub_XML_Parse = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParsePPC };
-
-static int stub_XML_ParseBufferPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_ParseBuffer(p->p, (int)regarray[0], (int)regarray[1]);
-}
-struct EmuTrap stub_XML_ParseBuffer = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParseBufferPPC };
-
-static void * stub_XML_GetBufferPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetBuffer(p->p, (int)regarray[0]);
-}
-struct EmuTrap stub_XML_GetBuffer = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetBufferPPC };
-
-static void stub_XML_SetStartElementHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startelementhandler = (void *)regarray[9];
- Self->XML_SetStartElementHandler(p->p, _68k_startelementhandler);
-}
-struct EmuTrap stub_XML_SetStartElementHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetStartElementHandlerPPC };
-
-static void stub_XML_SetEndElementHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->endelementhandler = (void *)regarray[9];
- Self->XML_SetEndElementHandler(p->p, _68k_endelementhandler);
-}
-struct EmuTrap stub_XML_SetEndElementHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetEndElementHandlerPPC };
-
-static void stub_XML_SetElementHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startelementhandler = (void *)regarray[9];
- p->endelementhandler = (void *)regarray[10];
- Self->XML_SetElementHandler(p->p, _68k_startelementhandler, _68k_endelementhandler);
-}
-struct EmuTrap stub_XML_SetElementHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetElementHandlerPPC };
-
-static void stub_XML_SetCharacterDataHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->chardatahandler = (void *)regarray[9];
- Self->XML_SetCharacterDataHandler(p->p, _68k_chardatahandler);
-}
-struct EmuTrap stub_XML_SetCharacterDataHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetCharacterDataHandlerPPC };
-
-static void stub_XML_SetProcessingInstructionHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->procinsthandler = (void *)regarray[9];
- Self->XML_SetProcessingInstructionHandler(p->p, _68k_procinsthandler);
-}
-struct EmuTrap stub_XML_SetProcessingInstructionHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetProcessingInstructionHandlerPPC };
-
-static void stub_XML_SetCommentHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->commenthandler = (void *)regarray[9];
- Self->XML_SetCommentHandler(p->p, _68k_commenthandler);
-}
-struct EmuTrap stub_XML_SetCommentHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetCommentHandlerPPC };
-
-static void stub_XML_SetStartCdataSectionHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startcdatahandler = (void *)regarray[9];
- Self->XML_SetStartCdataSectionHandler(p->p, _68k_startcdatahandler);
-}
-struct EmuTrap stub_XML_SetStartCdataSectionHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetStartCdataSectionHandlerPPC };
-
-static void stub_XML_SetEndCdataSectionHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->endcdatahandler = (void *)regarray[9];
- Self->XML_SetEndCdataSectionHandler(p->p, _68k_endcdatahandler);
-}
-struct EmuTrap stub_XML_SetEndCdataSectionHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetEndCdataSectionHandlerPPC };
-
-static void stub_XML_SetCdataSectionHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startcdatahandler = (void *)regarray[9];
- p->endcdatahandler = (void *)regarray[10];
- Self->XML_SetCdataSectionHandler(p->p, _68k_startcdatahandler, _68k_endcdatahandler);
-}
-struct EmuTrap stub_XML_SetCdataSectionHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetCdataSectionHandlerPPC };
-
-static void stub_XML_SetDefaultHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->defaulthandler = (void *)regarray[9];
- Self->XML_SetDefaultHandler(p->p, _68k_defaulthandler);
-}
-struct EmuTrap stub_XML_SetDefaultHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetDefaultHandlerPPC };
-
-static void stub_XML_SetDefaultHandlerExpandPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->defaulthandlerexp = (void *)regarray[9];
- Self->XML_SetDefaultHandlerExpand(p->p, _68k_defaulthandlerexp);
-}
-struct EmuTrap stub_XML_SetDefaultHandlerExpand = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetDefaultHandlerExpandPPC };
-
-static void stub_XML_SetExternalEntityRefHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->extentrefhandler = (void *)regarray[9];
- Self->XML_SetExternalEntityRefHandler(p->p, _68k_extentrefhandler);
-}
-struct EmuTrap stub_XML_SetExternalEntityRefHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetExternalEntityRefHandlerPPC };
-
-static void stub_XML_SetExternalEntityRefHandlerArgPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->extenthandlerarg = (void *)regarray[9];
-}
-struct EmuTrap stub_XML_SetExternalEntityRefHandlerArg = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetExternalEntityRefHandlerArgPPC };
-
-static void stub_XML_SetUnknownEncodingHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->unknownenchandler = (void *)regarray[9];
- p->enchandlerarg = (void *)regarray[10];
- Self->XML_SetUnknownEncodingHandler(p->p, _68k_unknownenchandler, p);
-}
-struct EmuTrap stub_XML_SetUnknownEncodingHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetUnknownEncodingHandlerPPC };
-
-static void stub_XML_SetStartNamespaceDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startnamespacehandler = (void *)regarray[9];
- Self->XML_SetStartNamespaceDeclHandler(p->p, _68k_startnamespacehandler);
-}
-struct EmuTrap stub_XML_SetStartNamespaceDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetStartNamespaceDeclHandlerPPC };
-
-static void stub_XML_SetEndNamespaceDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->endnamespacehandler = (void *)regarray[9];
- Self->XML_SetEndNamespaceDeclHandler(p->p, _68k_endnamespacehandler);
-}
-struct EmuTrap stub_XML_SetEndNamespaceDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetEndNamespaceDeclHandlerPPC };
-
-static void stub_XML_SetNamespaceDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startnamespacehandler = (void *)regarray[9];
- p->endnamespacehandler = (void *)regarray[10];
- Self->XML_SetNamespaceDeclHandler(p->p, _68k_startnamespacehandler, _68k_endnamespacehandler);
-}
-struct EmuTrap stub_XML_SetNamespaceDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetNamespaceDeclHandlerPPC };
-
-static void stub_XML_SetXmlDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->xmldeclhandler = (void *)regarray[9];
- Self->XML_SetXmlDeclHandler(p->p, _68k_xmldeclhandler);
-}
-struct EmuTrap stub_XML_SetXmlDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetXmlDeclHandlerPPC };
-
-static void stub_XML_SetStartDoctypeDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startdoctypehandler = (void *)regarray[9];
- Self->XML_SetStartDoctypeDeclHandler(p->p, _68k_startdoctypehandler);
-}
-struct EmuTrap stub_XML_SetStartDoctypeDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetStartDoctypeDeclHandlerPPC };
-
-static void stub_XML_SetEndDoctypeDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->enddoctypehandler = (void *)regarray[9];
- Self->XML_SetEndDoctypeDeclHandler(p->p, _68k_enddoctypehandler);
-}
-struct EmuTrap stub_XML_SetEndDoctypeDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetEndDoctypeDeclHandlerPPC };
-
-static void stub_XML_SetDoctypeDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->startdoctypehandler = (void *)regarray[9];
- p->enddoctypehandler = (void *)regarray[10];
- Self->XML_SetDoctypeDeclHandler(p->p, _68k_startdoctypehandler, _68k_enddoctypehandler);
-}
-struct EmuTrap stub_XML_SetDoctypeDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetDoctypeDeclHandlerPPC };
-
-static void stub_XML_SetElementDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->elementdeclhandler = (void *)regarray[9];
- Self->XML_SetElementDeclHandler(p->p, _68k_elementdeclhandler);
-}
-struct EmuTrap stub_XML_SetElementDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetElementDeclHandlerPPC };
-
-static void stub_XML_SetAttlistDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->attlistdeclhandler = (void *)regarray[9];
- Self->XML_SetAttlistDeclHandler(p->p, _68k_attlistdeclhandler);
-}
-struct EmuTrap stub_XML_SetAttlistDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetAttlistDeclHandlerPPC };
-
-static void stub_XML_SetEntityDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->entitydeclhandler = (void *)regarray[9];
- Self->XML_SetEntityDeclHandler(p->p, _68k_entitydeclhandler);
-}
-struct EmuTrap stub_XML_SetEntityDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetEntityDeclHandlerPPC };
-
-static void stub_XML_SetUnparsedEntityDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->unparseddeclhandler = (void *)regarray[9];
- Self->XML_SetUnparsedEntityDeclHandler(p->p, _68k_unparseddeclhandler);
-}
-struct EmuTrap stub_XML_SetUnparsedEntityDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetUnparsedEntityDeclHandlerPPC };
-
-static void stub_XML_SetNotationDeclHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->notationdeclhandler = (void *)regarray[9];
- Self->XML_SetNotationDeclHandler(p->p, _68k_notationdeclhandler);
-}
-struct EmuTrap stub_XML_SetNotationDeclHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetNotationDeclHandlerPPC };
-
-static void stub_XML_SetNotStandaloneHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->notstandalonehandler = (void *)regarray[9];
- Self->XML_SetNotStandaloneHandler(p->p, _68k_notstandalonehandler);
-}
-struct EmuTrap stub_XML_SetNotStandaloneHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetNotStandaloneHandlerPPC };
-
-static int stub_XML_GetErrorCodePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetErrorCode(p->p);
-}
-struct EmuTrap stub_XML_GetErrorCode = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetErrorCodePPC };
-
-static const XML_LChar * stub_XML_ErrorStringPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- return Self->XML_ErrorString((int)regarray[0]);
-}
-struct EmuTrap stub_XML_ErrorString = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ErrorStringPPC };
-
-static long stub_XML_GetCurrentByteIndexPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetCurrentByteIndex(p->p);
-}
-struct EmuTrap stub_XML_GetCurrentByteIndex = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetCurrentByteIndexPPC };
-
-static int stub_XML_GetCurrentLineNumberPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetCurrentLineNumber(p->p);
-}
-struct EmuTrap stub_XML_GetCurrentLineNumber = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetCurrentLineNumberPPC };
-
-static int stub_XML_GetCurrentColumnNumberPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetCurrentColumnNumber(p->p);
-}
-struct EmuTrap stub_XML_GetCurrentColumnNumber = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetCurrentColumnNumberPPC };
-
-static int stub_XML_GetCurrentByteCountPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetCurrentByteCount(p->p);
-}
-struct EmuTrap stub_XML_GetCurrentByteCount = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetCurrentByteCountPPC };
-
-static const char * stub_XML_GetInputContextPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetInputContext(p->p, (int *)regarray[9], (int *)regarray[10]);
-}
-struct EmuTrap stub_XML_GetInputContext = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetInputContextPPC };
-
-static void stub_XML_SetUserDataPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->handlerarg = (void *)regarray[9];
-}
-struct EmuTrap stub_XML_SetUserData = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetUserDataPPC };
-
-static void stub_XML_DefaultCurrentPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- Self->XML_DefaultCurrent(p->p);
-}
-struct EmuTrap stub_XML_DefaultCurrent = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_DefaultCurrentPPC };
-
-static void stub_XML_UseParserAsHandlerArgPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->handlerarg = p;
-}
-struct EmuTrap stub_XML_UseParserAsHandlerArg = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_UseParserAsHandlerArgPPC };
-
-static int stub_XML_SetBasePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_SetBase(p->p, (const XML_Char *)regarray[9]);
-}
-struct EmuTrap stub_XML_SetBase = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetBasePPC };
-
-static const XML_Char * stub_XML_GetBasePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetBase(p->p);
-}
-struct EmuTrap stub_XML_GetBase = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetBasePPC };
-
-static int stub_XML_GetSpecifiedAttributeCountPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetSpecifiedAttributeCount(p->p);
-}
-struct EmuTrap stub_XML_GetSpecifiedAttributeCount = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetSpecifiedAttributeCountPPC };
-
-static int stub_XML_GetIdAttributeIndexPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_GetIdAttributeIndex(p->p);
-}
-struct EmuTrap stub_XML_GetIdAttributeIndex = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetIdAttributeIndexPPC };
-
-static int stub_XML_SetEncodingPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_SetEncoding(p->p, (const XML_Char *)regarray[9]);
-}
-struct EmuTrap stub_XML_SetEncoding = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetEncodingPPC };
-
-static int stub_XML_SetParamEntityParsingPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_SetParamEntityParsing(p->p, (enum XML_ParamEntityParsing)regarray[9]);
-}
-struct EmuTrap stub_XML_SetParamEntityParsing = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetParamEntityParsingPPC };
-
-static void stub_XML_SetReturnNSTripletPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- Self->XML_SetReturnNSTriplet(p->p, (int)regarray[0]);
-}
-struct EmuTrap stub_XML_SetReturnNSTriplet = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetReturnNSTripletPPC };
-
-static const XML_LChar * stub_XML_ExpatVersionPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- return Self->XML_ExpatVersion();
-}
-struct EmuTrap stub_XML_ExpatVersion = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ExpatVersionPPC };
-
-static XML_Expat_Version stub_XML_ExpatVersionInfoPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- return Self->XML_ExpatVersionInfo();
-}
-struct EmuTrap stub_XML_ExpatVersionInfo = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ExpatVersionInfoPPC };
-
-static int stub_XML_ParserResetPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_ParserReset(p->p, (const XML_Char *)regarray[9]);
-}
-struct EmuTrap stub_XML_ParserReset = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ParserResetPPC };
-
-static void stub_XML_SetSkippedEntityHandlerPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- p->skippedentityhandler = (void *)regarray[9];
- Self->XML_SetSkippedEntityHandler(p->p, _68k_skippedentityhandler);
-}
-struct EmuTrap stub_XML_SetSkippedEntityHandler = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_SetSkippedEntityHandlerPPC };
-
-static int stub_XML_UseForeignDTDPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_UseForeignDTD(p->p, (XML_Bool)regarray[0]);
-}
-struct EmuTrap stub_XML_UseForeignDTD = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_UseForeignDTDPPC };
-
-static const XML_Feature * stub_XML_GetFeatureListPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- return Self->XML_GetFeatureList();
-}
-struct EmuTrap stub_XML_GetFeatureList = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetFeatureListPPC };
-
-static int stub_XML_StopParserPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_StopParser(p->p, (XML_Bool)regarray[0]);
-}
-struct EmuTrap stub_XML_StopParser = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_StopParserPPC };
-
-static int stub_XML_ResumeParserPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_ResumeParser(p->p);
-}
-struct EmuTrap stub_XML_ResumeParser = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_ResumeParserPPC };
-
-static void stub_XML_GetParsingStatusPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- Self->XML_GetParsingStatus(p->p, (XML_ParsingStatus *)regarray[9]);
-}
-struct EmuTrap stub_XML_GetParsingStatus = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_GetParsingStatusPPC };
-
-static void stub_XML_FreeContentModelPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- Self->XML_FreeContentModel(p->p, (XML_Content *)regarray[9]);
-}
-struct EmuTrap stub_XML_FreeContentModel = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_FreeContentModelPPC };
-
-static void *stub_XML_MemMallocPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_MemMalloc(p->p, (size_t)regarray[0]);
-}
-struct EmuTrap stub_XML_MemMalloc = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_MemMallocPPC };
-
-static void *stub_XML_MemReallocPPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- return Self->XML_MemRealloc(p->p, (void *)regarray[9], (size_t)regarray[0]);
-}
-struct EmuTrap stub_XML_MemRealloc = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_MemReallocPPC };
-
-static void stub_XML_MemFreePPC(ULONG *regarray)
-{
- struct Library *Base = (struct Library *) regarray[REG68K_A6/4];
- struct ExtendedLibrary *ExtLib = (struct ExtendedLibrary *) ((ULONG)Base + Base->lib_PosSize);
- struct ExpatIFace *Self = (struct ExpatIFace *) ExtLib->MainIFace;
-
- M68kXML_Parser p = (M68kXML_Parser)regarray[8];
- Self->XML_MemFree(p->p, (void *)regarray[9]);
-}
-struct EmuTrap stub_XML_MemFree = { TRAPINST, TRAPTYPE, (ULONG (*)(ULONG *))stub_XML_MemFreePPC };
-
-ULONG VecTable68K[] = {
- (ULONG)&stub_Open,
- (ULONG)&stub_Close,
- (ULONG)&stub_Expunge,
- (ULONG)&stub_Reserved,
- (ULONG)&stub_XML_ParserCreate,
- (ULONG)&stub_XML_ParserCreateNS,
- (ULONG)&stub_XML_ParserCreate_MM,
- (ULONG)&stub_XML_ExternalEntityParserCreate,
- (ULONG)&stub_XML_ParserFree,
- (ULONG)&stub_XML_Parse,
- (ULONG)&stub_XML_ParseBuffer,
- (ULONG)&stub_XML_GetBuffer,
- (ULONG)&stub_XML_SetStartElementHandler,
- (ULONG)&stub_XML_SetEndElementHandler,
- (ULONG)&stub_XML_SetElementHandler,
- (ULONG)&stub_XML_SetCharacterDataHandler,
- (ULONG)&stub_XML_SetProcessingInstructionHandler,
- (ULONG)&stub_XML_SetCommentHandler,
- (ULONG)&stub_XML_SetStartCdataSectionHandler,
- (ULONG)&stub_XML_SetEndCdataSectionHandler,
- (ULONG)&stub_XML_SetCdataSectionHandler,
- (ULONG)&stub_XML_SetDefaultHandler,
- (ULONG)&stub_XML_SetDefaultHandlerExpand,
- (ULONG)&stub_XML_SetExternalEntityRefHandler,
- (ULONG)&stub_XML_SetExternalEntityRefHandlerArg,
- (ULONG)&stub_XML_SetUnknownEncodingHandler,
- (ULONG)&stub_XML_SetStartNamespaceDeclHandler,
- (ULONG)&stub_XML_SetEndNamespaceDeclHandler,
- (ULONG)&stub_XML_SetNamespaceDeclHandler,
- (ULONG)&stub_XML_SetXmlDeclHandler,
- (ULONG)&stub_XML_SetStartDoctypeDeclHandler,
- (ULONG)&stub_XML_SetEndDoctypeDeclHandler,
- (ULONG)&stub_XML_SetDoctypeDeclHandler,
- (ULONG)&stub_XML_SetElementDeclHandler,
- (ULONG)&stub_XML_SetAttlistDeclHandler,
- (ULONG)&stub_XML_SetEntityDeclHandler,
- (ULONG)&stub_XML_SetUnparsedEntityDeclHandler,
- (ULONG)&stub_XML_SetNotationDeclHandler,
- (ULONG)&stub_XML_SetNotStandaloneHandler,
- (ULONG)&stub_XML_GetErrorCode,
- (ULONG)&stub_XML_ErrorString,
- (ULONG)&stub_XML_GetCurrentByteIndex,
- (ULONG)&stub_XML_GetCurrentLineNumber,
- (ULONG)&stub_XML_GetCurrentColumnNumber,
- (ULONG)&stub_XML_GetCurrentByteCount,
- (ULONG)&stub_XML_GetInputContext,
- (ULONG)&stub_XML_SetUserData,
- (ULONG)&stub_XML_DefaultCurrent,
- (ULONG)&stub_XML_UseParserAsHandlerArg,
- (ULONG)&stub_XML_SetBase,
- (ULONG)&stub_XML_GetBase,
- (ULONG)&stub_XML_GetSpecifiedAttributeCount,
- (ULONG)&stub_XML_GetIdAttributeIndex,
- (ULONG)&stub_XML_SetEncoding,
- (ULONG)&stub_XML_SetParamEntityParsing,
- (ULONG)&stub_XML_SetReturnNSTriplet,
- (ULONG)&stub_XML_ExpatVersion,
- (ULONG)&stub_XML_ExpatVersionInfo,
- (ULONG)&stub_XML_ParserReset,
- (ULONG)&stub_XML_SetSkippedEntityHandler,
- (ULONG)&stub_XML_UseForeignDTD,
- (ULONG)&stub_XML_GetFeatureList,
- (ULONG)&stub_XML_StopParser,
- (ULONG)&stub_XML_ResumeParser,
- (ULONG)&stub_XML_GetParsingStatus,
- (ULONG)&stub_XML_FreeContentModel,
- (ULONG)&stub_XML_MemMalloc,
- (ULONG)&stub_XML_MemRealloc,
- (ULONG)&stub_XML_MemFree,
- (ULONG)-1
-};
diff --git a/3rdparty/expat/amiga/expat_68k.h b/3rdparty/expat/amiga/expat_68k.h
deleted file mode 100644
index 6f1aac59b89..00000000000
--- a/3rdparty/expat/amiga/expat_68k.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#ifndef EXPAT_68K_H
-#define EXPAT_68K_H
-
-#ifndef LIBRARIES_EXPAT_H
-#include <libraries/expat.h>
-#endif
-
-typedef struct M68kXML_ParserStruct {
- XML_Parser p;
- struct ExecIFace *IExec;
- void *handlerarg;
- void *extenthandlerarg;
- void *enchandlerarg;
- void *startelementhandler;
- void *endelementhandler;
- void *chardatahandler;
- void *procinsthandler;
- void *commenthandler;
- void *startcdatahandler;
- void *endcdatahandler;
- void *defaulthandler;
- void *defaulthandlerexp;
- void *extentrefhandler;
- void *unknownenchandler;
- void *startnamespacehandler;
- void *endnamespacehandler;
- void *xmldeclhandler;
- void *startdoctypehandler;
- void *enddoctypehandler;
- void *elementdeclhandler;
- void *attlistdeclhandler;
- void *entitydeclhandler;
- void *unparseddeclhandler;
- void *notationdeclhandler;
- void *notstandalonehandler;
- void *skippedentityhandler;
-} *M68kXML_Parser;
-
-/* expat_68k_handler_stubs.c */
-void _68k_startelementhandler(void *userdata, const char *name, const char **attrs);
-void _68k_endelementhandler(void *userdata, const char *name);
-void _68k_chardatahandler(void *userdata, const char *s, int len);
-void _68k_procinsthandler(void *userdata, const char *target, const char *data);
-void _68k_commenthandler(void *userdata, const char *data);
-void _68k_startcdatahandler(void *userdata);
-void _68k_endcdatahandler(void *userdata);
-void _68k_defaulthandler(void *userdata, const char *s, int len);
-void _68k_defaulthandlerexp(void *userdata, const char *s, int len);
-int _68k_extentrefhandler(XML_Parser parser, const char *context, const char *base,
- const char *sysid, const char *pubid);
-int _68k_unknownenchandler(void *enchandlerdata, const char *name, XML_Encoding *info);
-void _68k_startnamespacehandler(void *userdata, const char *prefix, const char *uri);
-void _68k_endnamespacehandler(void *userdata, const char *prefix);
-void _68k_xmldeclhandler(void *userdata, const char *version, const char *encoding, int standalone);
-void _68k_startdoctypehandler(void *userdata, const char *doctypename,
- const char *sysid, const char *pubid, int has_internal_subset);
-void _68k_enddoctypehandler(void *userdata);
-void _68k_elementdeclhandler(void *userdata, const char *name, XML_Content *model);
-void _68k_attlistdeclhandler(void *userdata, const char *elname, const char *attname,
- const char *att_type, const char *dflt, int isrequired);
-void _68k_entitydeclhandler(void *userdata, const char *entityname, int is_param_entity,
- const char *value, int value_length, const char *base, const char *sysid, const char *pubid,
- const char *notationname);
-void _68k_unparseddeclhandler(void *userdata, const char *entityname, const char *base,
- const char *sysid, const char *pubid, const char *notationname);
-void _68k_notationdeclhandler(void *userdata, const char *notationname, const char *base,
- const char *sysid, const char *pubid);
-int _68k_notstandalonehandler(void *userdata);
-void _68k_skippedentityhandler(void *userdata, const char *entityname, int is_param_entity);
-
-#endif
diff --git a/3rdparty/expat/amiga/expat_68k_handler_stubs.c b/3rdparty/expat/amiga/expat_68k_handler_stubs.c
deleted file mode 100644
index aca33c6ecd9..00000000000
--- a/3rdparty/expat/amiga/expat_68k_handler_stubs.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#ifdef __USE_INLINE__
-#undef __USE_INLINE__
-#endif
-
-#include "expat_68k.h"
-#include <exec/emulation.h>
-#include <proto/exec.h>
-#include <stdarg.h>
-
-static uint32 VARARGS68K call_68k_code (struct ExecIFace *IExec, void *code, int num_args, ...) {
- uint32 res = 0;
-
- va_list vargs;
- va_startlinear(vargs, num_args);
- uint32 *args = va_getlinearva(vargs, uint32 *);
-
- uint8 *stack = IExec->AllocVec(4096, MEMF_SHARED);
- if (stack) {
- uint32 *sp = (uint32 *)(stack + 4096);
- args += num_args;
- while (num_args--) {
- *--sp = *--args;
- }
-
- res = IExec->EmulateTags(code, ET_StackPtr, sp, TAG_END);
- IExec->FreeVec(stack);
- }
-
- va_end(vargs);
-
- return res;
-}
-
-void _68k_startelementhandler(void *userdata, const char *name, const char **attrs) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->startelementhandler, 3, p->handlerarg, name, attrs);
-}
-
-void _68k_endelementhandler(void *userdata, const char *name) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->endelementhandler, 2, p->handlerarg, name);
-}
-
-void _68k_chardatahandler(void *userdata, const char *s, int len) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->chardatahandler, 3, p->handlerarg, s, len);
-}
-
-void _68k_procinsthandler(void *userdata, const char *target, const char *data) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->procinsthandler, 3, p->handlerarg, target, data);
-}
-
-void _68k_commenthandler(void *userdata, const char *data) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->commenthandler, 2, p->handlerarg, data);
-}
-
-void _68k_startcdatahandler(void *userdata) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->startcdatahandler, 1, p->handlerarg);
-}
-
-void _68k_endcdatahandler(void *userdata) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->endcdatahandler, 1, p->handlerarg);
-}
-
-void _68k_defaulthandler(void *userdata, const char *s, int len) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->defaulthandler, 3, p->handlerarg, s, len);
-}
-
-void _68k_defaulthandlerexp(void *userdata, const char *s, int len) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->defaulthandlerexp, 3, p->handlerarg, s, len);
-}
-
-int _68k_extentrefhandler(XML_Parser parser, const char *context, const char *base,
- const char *sysid, const char *pubid)
-{
- M68kXML_Parser p = XML_GetUserData(parser);
- void *arg = p->extenthandlerarg;
- return (int)call_68k_code(p->IExec, p->extentrefhandler, 5, arg ? arg : p, context, base, sysid, pubid);
-}
-
-int _68k_unknownenchandler(void *enchandlerdata, const char *name, XML_Encoding *info) {
- M68kXML_Parser p = enchandlerdata;
- return (int)call_68k_code(p->IExec, p->unknownenchandler, 3, p->enchandlerarg, name, info);
-}
-
-void _68k_startnamespacehandler(void *userdata, const char *prefix, const char *uri) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->startnamespacehandler, 3, p->handlerarg, prefix, uri);
-}
-
-void _68k_endnamespacehandler(void *userdata, const char *prefix) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->endnamespacehandler, 2, p->handlerarg, prefix);
-}
-
-void _68k_xmldeclhandler(void *userdata, const char *version, const char *encoding, int standalone) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->xmldeclhandler, 4, p->handlerarg, version, encoding, standalone);
-}
-
-void _68k_startdoctypehandler(void *userdata, const char *doctypename,
- const char *sysid, const char *pubid, int has_internal_subset)
-{
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->startdoctypehandler, 5, p->handlerarg, doctypename, sysid, pubid, has_internal_subset);
-}
-
-void _68k_enddoctypehandler(void *userdata) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->enddoctypehandler, 1, p->handlerarg);
-}
-
-void _68k_elementdeclhandler(void *userdata, const char *name, XML_Content *model) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->elementdeclhandler, 3, p->handlerarg, name, model);
-}
-
-void _68k_attlistdeclhandler(void *userdata, const char *elname, const char *attname,
- const char *att_type, const char *dflt, int isrequired)
-{
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->attlistdeclhandler, 6, p->handlerarg, elname, attname, att_type, dflt, isrequired);
-}
-
-void _68k_entitydeclhandler(void *userdata, const char *entityname, int is_param_entity,
- const char *value, int value_length, const char *base, const char *sysid, const char *pubid,
- const char *notationname)
-{
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->entitydeclhandler, 9, p->handlerarg, entityname, is_param_entity,
- value, value_length, base, sysid, pubid, notationname);
-}
-
-void _68k_unparseddeclhandler(void *userdata, const char *entityname, const char *base,
- const char *sysid, const char *pubid, const char *notationname)
-{
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->unparseddeclhandler, 6, p->handlerarg, entityname, base, sysid, pubid, notationname);
-}
-
-void _68k_notationdeclhandler(void *userdata, const char *notationname, const char *base,
- const char *sysid, const char *pubid)
-{
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->notationdeclhandler, 5, p->handlerarg, notationname, base, sysid, pubid);
-}
-
-int _68k_notstandalonehandler(void *userdata) {
- M68kXML_Parser p = userdata;
- return (int)call_68k_code(p->IExec, p->notstandalonehandler, 1, p->handlerarg);
-}
-
-void _68k_skippedentityhandler(void *userdata, const char *entityname, int is_param_entity) {
- M68kXML_Parser p = userdata;
- call_68k_code(p->IExec, p->skippedentityhandler, 3, p->handlerarg, entityname, is_param_entity);
-}
diff --git a/3rdparty/expat/amiga/expat_base.h b/3rdparty/expat/amiga/expat_base.h
deleted file mode 100644
index 26636398502..00000000000
--- a/3rdparty/expat/amiga/expat_base.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#ifndef EXPAT_BASE_H
-#define EXPAT_BASE_H
-
-#include <exec/libraries.h>
-#include <dos/dos.h>
-#include <interfaces/exec.h>
-#include <interfaces/utility.h>
-
-
-struct ExpatBase {
- struct Library libNode;
- uint16 pad;
- BPTR SegList;
- struct ExecIFace *IExec;
-};
-
-#endif
diff --git a/3rdparty/expat/amiga/expat_lib.c b/3rdparty/expat/amiga/expat_lib.c
deleted file mode 100644
index 70e91b101aa..00000000000
--- a/3rdparty/expat/amiga/expat_lib.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#ifdef __USE_INLINE__
-#undef __USE_INLINE__
-#endif
-
-#define __NOLIBBASE__
-#define __NOGLOBALIFACE__
-
-#include <dos/dos.h>
-#include <proto/exec.h>
-
-#include "expat_base.h"
-
-
-#define LIBNAME "expat.library"
-#define LIBPRI 0
-#define VERSION 53
-#define REVISION 1
-#define VSTRING "expat.library 53.1 (7.8.2009)" /* dd.mm.yyyy */
-
-
-static const char* __attribute__((used)) verstag = "\0$VER: " VSTRING;
-
-
-struct Interface *INewlib = 0;
-
-
-struct ExpatBase * libInit(struct ExpatBase *libBase, BPTR seglist, struct ExecIFace *ISys);
-uint32 libObtain (struct LibraryManagerInterface *Self);
-uint32 libRelease (struct LibraryManagerInterface *Self);
-struct ExpatBase *libOpen (struct LibraryManagerInterface *Self, uint32 version);
-BPTR libClose (struct LibraryManagerInterface *Self);
-BPTR libExpunge (struct LibraryManagerInterface *Self);
-struct Interface *openInterface(struct ExecIFace *IExec, CONST_STRPTR libName, uint32 libVer);
-void closeInterface(struct ExecIFace *IExec, struct Interface *iface);
-
-
-static APTR lib_manager_vectors[] = {
- libObtain,
- libRelease,
- NULL,
- NULL,
- libOpen,
- libClose,
- libExpunge,
- NULL,
- (APTR)-1,
-};
-
-
-static struct TagItem lib_managerTags[] = {
- { MIT_Name, (uint32)"__library" },
- { MIT_VectorTable, (uint32)lib_manager_vectors },
- { MIT_Version, 1 },
- { TAG_END, 0 }
-};
-
-
-extern void *main_vectors[];
-
-static struct TagItem lib_mainTags[] = {
- { MIT_Name, (uint32)"main" },
- { MIT_VectorTable, (uint32)main_vectors },
- { MIT_Version, 1 },
- { TAG_END, 0 }
-};
-
-
-static APTR libInterfaces[] = {
- lib_managerTags,
- lib_mainTags,
- NULL
-};
-
-
-extern void *VecTable68K[];
-
-static struct TagItem libCreateTags[] = {
- { CLT_DataSize, sizeof(struct ExpatBase) },
- { CLT_InitFunc, (uint32)libInit },
- { CLT_Interfaces, (uint32)libInterfaces },
- { CLT_Vector68K, (uint32)VecTable68K },
- { TAG_END, 0 }
-};
-
-
-static struct Resident __attribute__((used)) lib_res = {
- RTC_MATCHWORD, // rt_MatchWord
- &lib_res, // rt_MatchTag
- &lib_res+1, // rt_EndSkip
- RTF_NATIVE | RTF_AUTOINIT, // rt_Flags
- VERSION, // rt_Version
- NT_LIBRARY, // rt_Type
- LIBPRI, // rt_Pri
- LIBNAME, // rt_Name
- VSTRING, // rt_IdString
- libCreateTags // rt_Init
-};
-
-
-int32 _start()
-{
- return RETURN_FAIL;
-}
-
-
-struct ExpatBase *libInit(struct ExpatBase *libBase, BPTR seglist, struct ExecIFace *iexec)
-{
- libBase->libNode.lib_Node.ln_Type = NT_LIBRARY;
- libBase->libNode.lib_Node.ln_Pri = LIBPRI;
- libBase->libNode.lib_Node.ln_Name = LIBNAME;
- libBase->libNode.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED;
- libBase->libNode.lib_Version = VERSION;
- libBase->libNode.lib_Revision = REVISION;
- libBase->libNode.lib_IdString = VSTRING;
-
- libBase->SegList = seglist;
-
- libBase->IExec = iexec;
- INewlib = openInterface(iexec, "newlib.library", 0);
-
- if ( INewlib != 0 ) {
- return libBase;
- }
-
- closeInterface(iexec, INewlib);
- INewlib = 0;
-
- iexec->DeleteLibrary(&libBase->libNode);
-
- return NULL;
-}
-
-
-uint32 libObtain( struct LibraryManagerInterface *Self )
-{
- ++Self->Data.RefCount;
- return Self->Data.RefCount;
-}
-
-
-uint32 libRelease( struct LibraryManagerInterface *Self )
-{
- --Self->Data.RefCount;
- return Self->Data.RefCount;
-}
-
-
-struct ExpatBase *libOpen( struct LibraryManagerInterface *Self, uint32 version )
-{
- struct ExpatBase *libBase;
-
- libBase = (struct ExpatBase *)Self->Data.LibBase;
-
- ++libBase->libNode.lib_OpenCnt;
- libBase->libNode.lib_Flags &= ~LIBF_DELEXP;
-
- return libBase;
-}
-
-
-BPTR libClose( struct LibraryManagerInterface *Self )
-{
- struct ExpatBase *libBase;
-
- libBase = (struct ExpatBase *)Self->Data.LibBase;
-
- --libBase->libNode.lib_OpenCnt;
- if ( libBase->libNode.lib_OpenCnt ) {
- return 0;
- }
-
- if ( libBase->libNode.lib_Flags & LIBF_DELEXP ) {
- return (BPTR)Self->LibExpunge();
- }
- else {
- return ZERO;
- }
-}
-
-
-BPTR libExpunge( struct LibraryManagerInterface *Self )
-{
- struct ExpatBase *libBase = (struct ExpatBase *)Self->Data.LibBase;
- BPTR result = ZERO;
-
- if (libBase->libNode.lib_OpenCnt == 0) {
- libBase->IExec->Remove(&libBase->libNode.lib_Node);
-
- result = libBase->SegList;
-
- closeInterface(libBase->IExec, INewlib);
- INewlib = 0;
-
- libBase->IExec->DeleteLibrary(&libBase->libNode);
- }
- else {
- libBase->libNode.lib_Flags |= LIBF_DELEXP;
- }
-
- return result;
-}
-
-
-struct Interface *openInterface(struct ExecIFace *IExec, CONST_STRPTR libName, uint32 libVer)
-{
- struct Library *base = IExec->OpenLibrary(libName, libVer);
- struct Interface *iface = IExec->GetInterface(base, "main", 1, 0);
- if (iface == 0) {
- IExec->CloseLibrary(base);
- }
-
- return iface;
-}
-
-
-void closeInterface(struct ExecIFace *IExec, struct Interface *iface)
-{
- if (iface != 0)
- {
- struct Library *base = iface->Data.LibBase;
- IExec->DropInterface(iface);
- IExec->CloseLibrary(base);
- }
-}
diff --git a/3rdparty/expat/amiga/expat_vectors.c b/3rdparty/expat/amiga/expat_vectors.c
deleted file mode 100644
index cf489509cd1..00000000000
--- a/3rdparty/expat/amiga/expat_vectors.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#include <exec/types.h>
-#include <exec/exec.h>
-#include <exec/interfaces.h>
-#include <interfaces/expat.h>
-
-extern uint32 _Expat_Obtain(struct ExpatIFace *);
-extern uint32 _Expat_Release(struct ExpatIFace *);
-extern XML_Parser _Expat_XML_ParserCreate(struct ExpatIFace *, const XML_Char * encodingName);
-extern XML_Parser _Expat_XML_ParserCreateNS(struct ExpatIFace *, const XML_Char * encodingName, XML_Char nsSep);
-extern XML_Parser _Expat_XML_ParserCreate_MM(struct ExpatIFace *, const XML_Char * encoding, const XML_Memory_Handling_Suite * memsuite, const XML_Char * namespaceSeparator);
-extern XML_Parser _Expat_XML_ExternalEntityParserCreate(struct ExpatIFace *, XML_Parser parser, const XML_Char * context, const XML_Char * encoding);
-extern void _Expat_XML_ParserFree(struct ExpatIFace *, XML_Parser parser);
-extern enum XML_Status _Expat_XML_Parse(struct ExpatIFace *, XML_Parser parser, const char * s, int len, int isFinal);
-extern enum XML_Status _Expat_XML_ParseBuffer(struct ExpatIFace *, XML_Parser parser, int len, int isFinal);
-extern void * _Expat_XML_GetBuffer(struct ExpatIFace *, XML_Parser parser, int len);
-extern void _Expat_XML_SetStartElementHandler(struct ExpatIFace *, XML_Parser parser, XML_StartElementHandler start);
-extern void _Expat_XML_SetEndElementHandler(struct ExpatIFace *, XML_Parser parser, XML_EndElementHandler end);
-extern void _Expat_XML_SetElementHandler(struct ExpatIFace *, XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end);
-extern void _Expat_XML_SetCharacterDataHandler(struct ExpatIFace *, XML_Parser parser, XML_CharacterDataHandler handler);
-extern void _Expat_XML_SetProcessingInstructionHandler(struct ExpatIFace *, XML_Parser parser, XML_ProcessingInstructionHandler handler);
-extern void _Expat_XML_SetCommentHandler(struct ExpatIFace *, XML_Parser parser, XML_CommentHandler handler);
-extern void _Expat_XML_SetStartCdataSectionHandler(struct ExpatIFace *, XML_Parser parser, XML_StartCdataSectionHandler start);
-extern void _Expat_XML_SetEndCdataSectionHandler(struct ExpatIFace *, XML_Parser parser, XML_EndCdataSectionHandler end);
-extern void _Expat_XML_SetCdataSectionHandler(struct ExpatIFace *, XML_Parser parser, XML_StartCdataSectionHandler start, XML_EndCdataSectionHandler end);
-extern void _Expat_XML_SetDefaultHandler(struct ExpatIFace *, XML_Parser parser, XML_DefaultHandler handler);
-extern void _Expat_XML_SetDefaultHandlerExpand(struct ExpatIFace *, XML_Parser parser, XML_DefaultHandler handler);
-extern void _Expat_XML_SetExternalEntityRefHandler(struct ExpatIFace *, XML_Parser parser, XML_ExternalEntityRefHandler handler);
-extern void _Expat_XML_SetExternalEntityRefHandlerArg(struct ExpatIFace *, XML_Parser parser, void * arg);
-extern void _Expat_XML_SetUnknownEncodingHandler(struct ExpatIFace *, XML_Parser parser, XML_UnknownEncodingHandler handler, void * data);
-extern void _Expat_XML_SetStartNamespaceDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_StartNamespaceDeclHandler start);
-extern void _Expat_XML_SetEndNamespaceDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_EndNamespaceDeclHandler end);
-extern void _Expat_XML_SetNamespaceDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_StartNamespaceDeclHandler start, XML_EndNamespaceDeclHandler end);
-extern void _Expat_XML_SetXmlDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_XmlDeclHandler handler);
-extern void _Expat_XML_SetStartDoctypeDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_StartDoctypeDeclHandler start);
-extern void _Expat_XML_SetEndDoctypeDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_EndDoctypeDeclHandler end);
-extern void _Expat_XML_SetDoctypeDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_StartDoctypeDeclHandler start, XML_EndDoctypeDeclHandler end);
-extern void _Expat_XML_SetElementDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_ElementDeclHandler eldecl);
-extern void _Expat_XML_SetAttlistDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_AttlistDeclHandler attdecl);
-extern void _Expat_XML_SetEntityDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_EntityDeclHandler handler);
-extern void _Expat_XML_SetUnparsedEntityDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_UnparsedEntityDeclHandler handler);
-extern void _Expat_XML_SetNotationDeclHandler(struct ExpatIFace *, XML_Parser parser, XML_NotationDeclHandler handler);
-extern void _Expat_XML_SetNotStandaloneHandler(struct ExpatIFace *, XML_Parser parser, XML_NotStandaloneHandler handler);
-extern enum XML_Error _Expat_XML_GetErrorCode(struct ExpatIFace *, XML_Parser parser);
-extern const XML_LChar * _Expat_XML_ErrorString(struct ExpatIFace *, enum XML_Error code);
-extern long _Expat_XML_GetCurrentByteIndex(struct ExpatIFace *, XML_Parser parser);
-extern int _Expat_XML_GetCurrentLineNumber(struct ExpatIFace *, XML_Parser parser);
-extern int _Expat_XML_GetCurrentColumnNumber(struct ExpatIFace *, XML_Parser parser);
-extern int _Expat_XML_GetCurrentByteCount(struct ExpatIFace *, XML_Parser parser);
-extern const char * _Expat_XML_GetInputContext(struct ExpatIFace *, XML_Parser parser, int * offset, int * size);
-extern void _Expat_XML_SetUserData(struct ExpatIFace *, XML_Parser parser, void * userData);
-extern void _Expat_XML_DefaultCurrent(struct ExpatIFace *, XML_Parser parser);
-extern void _Expat_XML_UseParserAsHandlerArg(struct ExpatIFace *, XML_Parser parser);
-extern enum XML_Status _Expat_XML_SetBase(struct ExpatIFace *, XML_Parser parser, const XML_Char * base);
-extern const XML_Char * _Expat_XML_GetBase(struct ExpatIFace *, XML_Parser parser);
-extern int _Expat_XML_GetSpecifiedAttributeCount(struct ExpatIFace *, XML_Parser parser);
-extern int _Expat_XML_GetIdAttributeIndex(struct ExpatIFace *, XML_Parser parser);
-extern enum XML_Status _Expat_XML_SetEncoding(struct ExpatIFace *, XML_Parser parser, const XML_Char * encoding);
-extern int _Expat_XML_SetParamEntityParsing(struct ExpatIFace *, XML_Parser parser, enum XML_ParamEntityParsing parsing);
-extern void _Expat_XML_SetReturnNSTriplet(struct ExpatIFace *, XML_Parser parser, int do_nst);
-extern const XML_LChar * _Expat_XML_ExpatVersion(struct ExpatIFace *);
-extern XML_Expat_Version _Expat_XML_ExpatVersionInfo(struct ExpatIFace *);
-extern XML_Bool _Expat_XML_ParserReset(struct ExpatIFace *, XML_Parser parser, const XML_Char * encoding);
-extern void _Expat_XML_SetSkippedEntityHandler(struct ExpatIFace *, XML_Parser parser, XML_SkippedEntityHandler handler);
-extern enum XML_Error _Expat_XML_UseForeignDTD(struct ExpatIFace *, XML_Parser parser, XML_Bool useDTD);
-extern const XML_Feature * _Expat_XML_GetFeatureList(struct ExpatIFace *);
-extern enum XML_Status _Expat_XML_StopParser(struct ExpatIFace *, XML_Parser parser, XML_Bool resumable);
-extern enum XML_Status _Expat_XML_ResumeParser(struct ExpatIFace *, XML_Parser parser);
-extern void _Expat_XML_GetParsingStatus(struct ExpatIFace *, XML_Parser parser, XML_ParsingStatus * status);
-extern void _Expat_XML_FreeContentModel(struct ExpatIFace *, XML_Parser parser, XML_Content * model);
-extern void * _Expat_XML_MemMalloc(struct ExpatIFace *, XML_Parser parser, size_t size);
-extern void * _Expat_XML_MemRealloc(struct ExpatIFace *, XML_Parser parser, void * ptr, size_t size);
-extern void _Expat_XML_MemFree(struct ExpatIFace *, XML_Parser parser, void * ptr);
-
-
-CONST APTR main_vectors[] =
-{
- _Expat_Obtain,
- _Expat_Release,
- NULL,
- NULL,
- _Expat_XML_ParserCreate,
- _Expat_XML_ParserCreateNS,
- _Expat_XML_ParserCreate_MM,
- _Expat_XML_ExternalEntityParserCreate,
- _Expat_XML_ParserFree,
- _Expat_XML_Parse,
- _Expat_XML_ParseBuffer,
- _Expat_XML_GetBuffer,
- _Expat_XML_SetStartElementHandler,
- _Expat_XML_SetEndElementHandler,
- _Expat_XML_SetElementHandler,
- _Expat_XML_SetCharacterDataHandler,
- _Expat_XML_SetProcessingInstructionHandler,
- _Expat_XML_SetCommentHandler,
- _Expat_XML_SetStartCdataSectionHandler,
- _Expat_XML_SetEndCdataSectionHandler,
- _Expat_XML_SetCdataSectionHandler,
- _Expat_XML_SetDefaultHandler,
- _Expat_XML_SetDefaultHandlerExpand,
- _Expat_XML_SetExternalEntityRefHandler,
- _Expat_XML_SetExternalEntityRefHandlerArg,
- _Expat_XML_SetUnknownEncodingHandler,
- _Expat_XML_SetStartNamespaceDeclHandler,
- _Expat_XML_SetEndNamespaceDeclHandler,
- _Expat_XML_SetNamespaceDeclHandler,
- _Expat_XML_SetXmlDeclHandler,
- _Expat_XML_SetStartDoctypeDeclHandler,
- _Expat_XML_SetEndDoctypeDeclHandler,
- _Expat_XML_SetDoctypeDeclHandler,
- _Expat_XML_SetElementDeclHandler,
- _Expat_XML_SetAttlistDeclHandler,
- _Expat_XML_SetEntityDeclHandler,
- _Expat_XML_SetUnparsedEntityDeclHandler,
- _Expat_XML_SetNotationDeclHandler,
- _Expat_XML_SetNotStandaloneHandler,
- _Expat_XML_GetErrorCode,
- _Expat_XML_ErrorString,
- _Expat_XML_GetCurrentByteIndex,
- _Expat_XML_GetCurrentLineNumber,
- _Expat_XML_GetCurrentColumnNumber,
- _Expat_XML_GetCurrentByteCount,
- _Expat_XML_GetInputContext,
- _Expat_XML_SetUserData,
- _Expat_XML_DefaultCurrent,
- _Expat_XML_UseParserAsHandlerArg,
- _Expat_XML_SetBase,
- _Expat_XML_GetBase,
- _Expat_XML_GetSpecifiedAttributeCount,
- _Expat_XML_GetIdAttributeIndex,
- _Expat_XML_SetEncoding,
- _Expat_XML_SetParamEntityParsing,
- _Expat_XML_SetReturnNSTriplet,
- _Expat_XML_ExpatVersion,
- _Expat_XML_ExpatVersionInfo,
- _Expat_XML_ParserReset,
- _Expat_XML_SetSkippedEntityHandler,
- _Expat_XML_UseForeignDTD,
- _Expat_XML_GetFeatureList,
- _Expat_XML_StopParser,
- _Expat_XML_ResumeParser,
- _Expat_XML_GetParsingStatus,
- _Expat_XML_FreeContentModel,
- _Expat_XML_MemMalloc,
- _Expat_XML_MemRealloc,
- _Expat_XML_MemFree,
- (APTR)-1
-};
-
-uint32 _Expat_Obtain(struct ExpatIFace *Self)
-{
- return ++Self->Data.RefCount;
-}
-
-uint32 _Expat_Release(struct ExpatIFace *Self)
-{
- return --Self->Data.RefCount;
-}
-
-XML_Parser _Expat_XML_ParserCreate(struct ExpatIFace * Self, const XML_Char *encoding)
-{
- return XML_ParserCreate(encoding);
-}
-
-XML_Parser _Expat_XML_ParserCreateNS(struct ExpatIFace * Self, const XML_Char *encoding, XML_Char nsSep)
-{
- return XML_ParserCreateNS(encoding, nsSep);
-}
-
-XML_Parser _Expat_XML_ParserCreate_MM(struct ExpatIFace * Self, const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, const XML_Char *namespaceSeparator)
-{
- return XML_ParserCreate_MM(encoding, memsuite, namespaceSeparator);
-}
-
-XML_Parser _Expat_XML_ExternalEntityParserCreate(struct ExpatIFace * Self, XML_Parser parser, const XML_Char *context, const XML_Char *encoding)
-{
- return XML_ExternalEntityParserCreate(parser, context, encoding);
-}
-
-void _Expat_XML_ParserFree(struct ExpatIFace *Self, XML_Parser parser)
-{
- XML_ParserFree(parser);
-}
-
-enum XML_Status _Expat_XML_Parse(struct ExpatIFace * Self, XML_Parser parser, const char * s, int len, int isFinal)
-{
- return XML_Parse(parser, s, len, isFinal);
-}
-
-enum XML_Status _Expat_XML_ParseBuffer(struct ExpatIFace * Self, XML_Parser parser, int len, int isFinal)
-{
- return XML_ParseBuffer(parser, len, isFinal);
-}
-
-void * _Expat_XML_GetBuffer(struct ExpatIFace * Self, XML_Parser parser, int len)
-{
- return XML_GetBuffer(parser, len);
-}
-
-void _Expat_XML_SetStartElementHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartElementHandler start)
-{
- XML_SetStartElementHandler(parser, start);
-}
-
-void _Expat_XML_SetEndElementHandler(struct ExpatIFace * Self, XML_Parser parser, XML_EndElementHandler end)
-{
- XML_SetEndElementHandler(parser, end);
-}
-
-void _Expat_XML_SetElementHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end)
-{
- XML_SetElementHandler(parser, start, end);
-}
-
-void _Expat_XML_SetCharacterDataHandler(struct ExpatIFace * Self, XML_Parser parser, XML_CharacterDataHandler handler)
-{
- XML_SetCharacterDataHandler(parser, handler);
-}
-
-void _Expat_XML_SetProcessingInstructionHandler(struct ExpatIFace * Self, XML_Parser parser, XML_ProcessingInstructionHandler handler)
-{
- XML_SetProcessingInstructionHandler(parser, handler);
-}
-
-void _Expat_XML_SetCommentHandler(struct ExpatIFace * Self, XML_Parser parser, XML_CommentHandler handler)
-{
- XML_SetCommentHandler(parser, handler);
-}
-
-void _Expat_XML_SetStartCdataSectionHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartCdataSectionHandler start)
-{
- XML_SetStartCdataSectionHandler(parser, start);
-}
-
-void _Expat_XML_SetEndCdataSectionHandler(struct ExpatIFace * Self, XML_Parser parser, XML_EndCdataSectionHandler end)
-{
- XML_SetEndCdataSectionHandler(parser, end);
-}
-
-void _Expat_XML_SetCdataSectionHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartCdataSectionHandler start, XML_EndCdataSectionHandler end)
-{
- XML_SetCdataSectionHandler(parser, start, end);
-}
-
-void _Expat_XML_SetDefaultHandler(struct ExpatIFace * Self, XML_Parser parser, XML_DefaultHandler handler)
-{
- XML_SetDefaultHandler(parser, handler);
-}
-
-void _Expat_XML_SetDefaultHandlerExpand(struct ExpatIFace * Self, XML_Parser parser, XML_DefaultHandler handler)
-{
- XML_SetDefaultHandlerExpand(parser, handler);
-}
-
-void _Expat_XML_SetExternalEntityRefHandler(struct ExpatIFace * Self, XML_Parser parser, XML_ExternalEntityRefHandler handler)
-{
- XML_SetExternalEntityRefHandler(parser, handler);
-}
-
-void _Expat_XML_SetExternalEntityRefHandlerArg(struct ExpatIFace * Self, XML_Parser parser, void * arg)
-{
- XML_SetExternalEntityRefHandlerArg(parser, arg);
-}
-
-void _Expat_XML_SetUnknownEncodingHandler(struct ExpatIFace * Self, XML_Parser parser, XML_UnknownEncodingHandler handler, void * data)
-{
- XML_SetUnknownEncodingHandler(parser, handler, data);
-}
-
-void _Expat_XML_SetStartNamespaceDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartNamespaceDeclHandler start)
-{
- XML_SetStartNamespaceDeclHandler(parser, start);
-}
-
-void _Expat_XML_SetEndNamespaceDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_EndNamespaceDeclHandler end)
-{
- XML_SetEndNamespaceDeclHandler(parser, end);
-}
-
-void _Expat_XML_SetNamespaceDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartNamespaceDeclHandler start, XML_EndNamespaceDeclHandler end)
-{
- XML_SetNamespaceDeclHandler(parser, start, end);
-}
-
-void _Expat_XML_SetXmlDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_XmlDeclHandler handler)
-{
- XML_SetXmlDeclHandler(parser, handler);
-}
-
-void _Expat_XML_SetStartDoctypeDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartDoctypeDeclHandler start)
-{
- XML_SetStartDoctypeDeclHandler(parser, start);
-}
-
-void _Expat_XML_SetEndDoctypeDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_EndDoctypeDeclHandler end)
-{
- XML_SetEndDoctypeDeclHandler(parser, end);
-}
-
-void _Expat_XML_SetDoctypeDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_StartDoctypeDeclHandler start, XML_EndDoctypeDeclHandler end)
-{
- XML_SetDoctypeDeclHandler(parser, start, end);
-}
-
-void _Expat_XML_SetElementDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_ElementDeclHandler eldecl)
-{
- XML_SetElementDeclHandler(parser, eldecl);
-}
-
-void _Expat_XML_SetAttlistDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_AttlistDeclHandler attdecl)
-{
- XML_SetAttlistDeclHandler(parser, attdecl);
-}
-
-void _Expat_XML_SetEntityDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_EntityDeclHandler handler)
-{
- XML_SetEntityDeclHandler(parser, handler);
-}
-
-void _Expat_XML_SetUnparsedEntityDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_UnparsedEntityDeclHandler handler)
-{
- XML_SetUnparsedEntityDeclHandler(parser, handler);
-}
-
-void _Expat_XML_SetNotationDeclHandler(struct ExpatIFace * Self, XML_Parser parser, XML_NotationDeclHandler handler)
-{
- XML_SetNotationDeclHandler(parser, handler);
-}
-
-void _Expat_XML_SetNotStandaloneHandler(struct ExpatIFace * Self, XML_Parser parser, XML_NotStandaloneHandler handler)
-{
- XML_SetNotStandaloneHandler(parser, handler);
-}
-
-enum XML_Error _Expat_XML_GetErrorCode(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetErrorCode(parser);
-}
-
-const XML_LChar * _Expat_XML_ErrorString(struct ExpatIFace * Self, enum XML_Error code)
-{
- return XML_ErrorString(code);
-}
-
-long _Expat_XML_GetCurrentByteIndex(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetCurrentByteIndex(parser);
-}
-
-int _Expat_XML_GetCurrentLineNumber(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetCurrentLineNumber(parser);
-}
-
-int _Expat_XML_GetCurrentColumnNumber(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetCurrentColumnNumber(parser);
-}
-
-int _Expat_XML_GetCurrentByteCount(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetCurrentByteCount(parser);
-}
-
-const char * _Expat_XML_GetInputContext(struct ExpatIFace * Self, XML_Parser parser, int * offset, int * size)
-{
- return XML_GetInputContext(parser, offset, size);
-}
-
-void _Expat_XML_SetUserData(struct ExpatIFace * Self, XML_Parser parser, void * userData)
-{
- XML_SetUserData(parser, userData);
-}
-
-void _Expat_XML_DefaultCurrent(struct ExpatIFace * Self, XML_Parser parser)
-{
- XML_DefaultCurrent(parser);
-}
-
-void _Expat_XML_UseParserAsHandlerArg(struct ExpatIFace * Self, XML_Parser parser)
-{
- XML_UseParserAsHandlerArg(parser);
-}
-
-enum XML_Status _Expat_XML_SetBase(struct ExpatIFace * Self, XML_Parser parser, const XML_Char *p)
-{
- return XML_SetBase(parser, p);
-}
-
-const XML_Char * _Expat_XML_GetBase(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetBase(parser);
-}
-
-int _Expat_XML_GetSpecifiedAttributeCount(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetSpecifiedAttributeCount(parser);
-}
-
-int _Expat_XML_GetIdAttributeIndex(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_GetIdAttributeIndex(parser);
-}
-
-enum XML_Status _Expat_XML_SetEncoding(struct ExpatIFace * Self, XML_Parser parser, const XML_Char *encoding)
-{
- return XML_SetEncoding(parser, encoding);
-}
-
-int _Expat_XML_SetParamEntityParsing(struct ExpatIFace * Self, XML_Parser parser, enum XML_ParamEntityParsing parsing)
-{
- return XML_SetParamEntityParsing(parser, parsing);
-}
-
-void _Expat_XML_SetReturnNSTriplet(struct ExpatIFace * Self, XML_Parser parser, int do_nst)
-{
- XML_SetReturnNSTriplet(parser, do_nst);
-}
-
-const XML_LChar * _Expat_XML_ExpatVersion(struct ExpatIFace * Self)
-{
- return XML_ExpatVersion();
-}
-
-XML_Expat_Version _Expat_XML_ExpatVersionInfo(struct ExpatIFace * Self)
-{
- return XML_ExpatVersionInfo();
-}
-
-XML_Bool _Expat_XML_ParserReset(struct ExpatIFace * Self, XML_Parser parser, const XML_Char *encoding)
-{
- return XML_ParserReset(parser, encoding);
-}
-
-void _Expat_XML_SetSkippedEntityHandler(struct ExpatIFace * Self, XML_Parser parser, XML_SkippedEntityHandler handler)
-{
- XML_SetSkippedEntityHandler(parser, handler);
-}
-
-enum XML_Error _Expat_XML_UseForeignDTD(struct ExpatIFace * Self, XML_Parser parser, XML_Bool useDTD)
-{
- return XML_UseForeignDTD(parser, useDTD);
-}
-
-const XML_Feature * _Expat_XML_GetFeatureList(struct ExpatIFace * Self)
-{
- return XML_GetFeatureList();
-}
-
-enum XML_Status _Expat_XML_StopParser(struct ExpatIFace * Self, XML_Parser parser, XML_Bool resumable)
-{
- return XML_StopParser(parser, resumable);
-}
-
-enum XML_Status _Expat_XML_ResumeParser(struct ExpatIFace * Self, XML_Parser parser)
-{
- return XML_ResumeParser(parser);
-}
-
-void _Expat_XML_GetParsingStatus(struct ExpatIFace * Self, XML_Parser parser, XML_ParsingStatus * status)
-{
- XML_GetParsingStatus(parser, status);
-}
-
-void _Expat_XML_FreeContentModel(struct ExpatIFace * Self, XML_Parser parser, XML_Content * model)
-{
- XML_FreeContentModel(parser, model);
-}
-
-void * _Expat_XML_MemMalloc(struct ExpatIFace * Self, XML_Parser parser, size_t size)
-{
- return XML_MemMalloc(parser, size);
-}
-
-void * _Expat_XML_MemRealloc(struct ExpatIFace * Self, XML_Parser parser, void * ptr, size_t size)
-{
- XML_MemRealloc(parser, ptr, size);
-}
-
-void _Expat_XML_MemFree(struct ExpatIFace * Self, XML_Parser parser, void * ptr)
-{
- XML_MemFree(parser, ptr);
-}
diff --git a/3rdparty/expat/amiga/include/inline4/expat.h b/3rdparty/expat/amiga/include/inline4/expat.h
deleted file mode 100644
index 1e3105d94eb..00000000000
--- a/3rdparty/expat/amiga/include/inline4/expat.h
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef INLINE4_EXPAT_H
-#define INLINE4_EXPAT_H
-
-/*
-** This file was auto generated by idltool 51.6.
-**
-** It provides compatibility to OS3 style library
-** calls by substituting functions.
-**
-** Do not edit manually.
-*/
-
-#ifndef EXEC_TYPES_H
-#include <exec/types.h>
-#endif
-#ifndef EXEC_EXEC_H
-#include <exec/exec.h>
-#endif
-#ifndef EXEC_INTERFACES_H
-#include <exec/interfaces.h>
-#endif
-
-#ifndef LIBRARIES_EXPAT_H
-#include <libraries/expat.h>
-#endif
-
-/* Inline macros for Interface "main" */
-#define XML_ParserCreate(encodingName) IExpat->XML_ParserCreate(encodingName)
-#define XML_ParserCreateNS(encodingName, nsSep) IExpat->XML_ParserCreateNS(encodingName, nsSep)
-#define XML_ParserCreate_MM(encoding, memsuite, namespaceSeparator) IExpat->XML_ParserCreate_MM(encoding, memsuite, namespaceSeparator)
-#define XML_ExternalEntityParserCreate(parser, context, encoding) IExpat->XML_ExternalEntityParserCreate(parser, context, encoding)
-#define XML_ParserFree(parser) IExpat->XML_ParserFree(parser)
-#define XML_Parse(parser, s, len, isFinal) IExpat->XML_Parse(parser, s, len, isFinal)
-#define XML_ParseBuffer(parser, len, isFinal) IExpat->XML_ParseBuffer(parser, len, isFinal)
-#define XML_GetBuffer(parser, len) IExpat->XML_GetBuffer(parser, len)
-#define XML_SetStartElementHandler(parser, start) IExpat->XML_SetStartElementHandler(parser, start)
-#define XML_SetEndElementHandler(parser, end) IExpat->XML_SetEndElementHandler(parser, end)
-#define XML_SetElementHandler(parser, start, end) IExpat->XML_SetElementHandler(parser, start, end)
-#define XML_SetCharacterDataHandler(parser, handler) IExpat->XML_SetCharacterDataHandler(parser, handler)
-#define XML_SetProcessingInstructionHandler(parser, handler) IExpat->XML_SetProcessingInstructionHandler(parser, handler)
-#define XML_SetCommentHandler(parser, handler) IExpat->XML_SetCommentHandler(parser, handler)
-#define XML_SetStartCdataSectionHandler(parser, start) IExpat->XML_SetStartCdataSectionHandler(parser, start)
-#define XML_SetEndCdataSectionHandler(parser, end) IExpat->XML_SetEndCdataSectionHandler(parser, end)
-#define XML_SetCdataSectionHandler(parser, start, end) IExpat->XML_SetCdataSectionHandler(parser, start, end)
-#define XML_SetDefaultHandler(parser, handler) IExpat->XML_SetDefaultHandler(parser, handler)
-#define XML_SetDefaultHandlerExpand(parser, handler) IExpat->XML_SetDefaultHandlerExpand(parser, handler)
-#define XML_SetExternalEntityRefHandler(parser, handler) IExpat->XML_SetExternalEntityRefHandler(parser, handler)
-#define XML_SetExternalEntityRefHandlerArg(parser, arg) IExpat->XML_SetExternalEntityRefHandlerArg(parser, arg)
-#define XML_SetUnknownEncodingHandler(parser, handler, data) IExpat->XML_SetUnknownEncodingHandler(parser, handler, data)
-#define XML_SetStartNamespaceDeclHandler(parser, start) IExpat->XML_SetStartNamespaceDeclHandler(parser, start)
-#define XML_SetEndNamespaceDeclHandler(parser, end) IExpat->XML_SetEndNamespaceDeclHandler(parser, end)
-#define XML_SetNamespaceDeclHandler(parser, start, end) IExpat->XML_SetNamespaceDeclHandler(parser, start, end)
-#define XML_SetXmlDeclHandler(parser, handler) IExpat->XML_SetXmlDeclHandler(parser, handler)
-#define XML_SetStartDoctypeDeclHandler(parser, start) IExpat->XML_SetStartDoctypeDeclHandler(parser, start)
-#define XML_SetEndDoctypeDeclHandler(parser, end) IExpat->XML_SetEndDoctypeDeclHandler(parser, end)
-#define XML_SetDoctypeDeclHandler(parser, start, end) IExpat->XML_SetDoctypeDeclHandler(parser, start, end)
-#define XML_SetElementDeclHandler(parser, eldecl) IExpat->XML_SetElementDeclHandler(parser, eldecl)
-#define XML_SetAttlistDeclHandler(parser, attdecl) IExpat->XML_SetAttlistDeclHandler(parser, attdecl)
-#define XML_SetEntityDeclHandler(parser, handler) IExpat->XML_SetEntityDeclHandler(parser, handler)
-#define XML_SetUnparsedEntityDeclHandler(parser, handler) IExpat->XML_SetUnparsedEntityDeclHandler(parser, handler)
-#define XML_SetNotationDeclHandler(parser, handler) IExpat->XML_SetNotationDeclHandler(parser, handler)
-#define XML_SetNotStandaloneHandler(parser, handler) IExpat->XML_SetNotStandaloneHandler(parser, handler)
-#define XML_GetErrorCode(parser) IExpat->XML_GetErrorCode(parser)
-#define XML_ErrorString(code) IExpat->XML_ErrorString(code)
-#define XML_GetCurrentByteIndex(parser) IExpat->XML_GetCurrentByteIndex(parser)
-#define XML_GetCurrentLineNumber(parser) IExpat->XML_GetCurrentLineNumber(parser)
-#define XML_GetCurrentColumnNumber(parser) IExpat->XML_GetCurrentColumnNumber(parser)
-#define XML_GetCurrentByteCount(parser) IExpat->XML_GetCurrentByteCount(parser)
-#define XML_GetInputContext(parser, offset, size) IExpat->XML_GetInputContext(parser, offset, size)
-#define XML_SetUserData(parser, userData) IExpat->XML_SetUserData(parser, userData)
-#define XML_DefaultCurrent(parser) IExpat->XML_DefaultCurrent(parser)
-#define XML_UseParserAsHandlerArg(parser) IExpat->XML_UseParserAsHandlerArg(parser)
-#define XML_SetBase(parser, base) IExpat->XML_SetBase(parser, base)
-#define XML_GetBase(parser) IExpat->XML_GetBase(parser)
-#define XML_GetSpecifiedAttributeCount(parser) IExpat->XML_GetSpecifiedAttributeCount(parser)
-#define XML_GetIdAttributeIndex(parser) IExpat->XML_GetIdAttributeIndex(parser)
-#define XML_SetEncoding(parser, encoding) IExpat->XML_SetEncoding(parser, encoding)
-#define XML_SetParamEntityParsing(parser, parsing) IExpat->XML_SetParamEntityParsing(parser, parsing)
-#define XML_SetReturnNSTriplet(parser, do_nst) IExpat->XML_SetReturnNSTriplet(parser, do_nst)
-#define XML_ExpatVersion() IExpat->XML_ExpatVersion()
-#define XML_ExpatVersionInfo() IExpat->XML_ExpatVersionInfo()
-#define XML_ParserReset(parser, encoding) IExpat->XML_ParserReset(parser, encoding)
-#define XML_SetSkippedEntityHandler(parser, handler) IExpat->XML_SetSkippedEntityHandler(parser, handler)
-#define XML_UseForeignDTD(parser, useDTD) IExpat->XML_UseForeignDTD(parser, useDTD)
-#define XML_GetFeatureList() IExpat->XML_GetFeatureList()
-#define XML_StopParser(parser, resumable) IExpat->XML_StopParser(parser, resumable)
-#define XML_ResumeParser(parser) IExpat->XML_ResumeParser(parser)
-#define XML_GetParsingStatus(parser, status) IExpat->XML_GetParsingStatus(parser, status)
-#define XML_FreeContentModel(parser, model) IExpat->XML_FreeContentModel(parser, model)
-#define XML_MemMalloc(parser, size) IExpat->XML_MemMalloc(parser, size)
-#define XML_MemRealloc(parser, ptr, size) IExpat->XML_MemRealloc(parser, ptr, size)
-#define XML_MemFree(parser, ptr) IExpat->XML_MemFree(parser, ptr)
-
-#endif /* INLINE4_EXPAT_H */
diff --git a/3rdparty/expat/amiga/include/interfaces/expat.h b/3rdparty/expat/amiga/include/interfaces/expat.h
deleted file mode 100644
index e9bdf4aa12a..00000000000
--- a/3rdparty/expat/amiga/include/interfaces/expat.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef EXPAT_INTERFACE_DEF_H
-#define EXPAT_INTERFACE_DEF_H
-
-/*
-** This file was machine generated by idltool 51.6.
-** Do not edit
-*/
-
-#ifndef EXEC_TYPES_H
-#include <exec/types.h>
-#endif
-#ifndef EXEC_EXEC_H
-#include <exec/exec.h>
-#endif
-#ifndef EXEC_INTERFACES_H
-#include <exec/interfaces.h>
-#endif
-
-#ifndef LIBRARIES_EXPAT_H
-#include <libraries/expat.h>
-#endif
-
-struct ExpatIFace
-{
- struct InterfaceData Data;
-
- uint32 APICALL (*Obtain)(struct ExpatIFace *Self);
- uint32 APICALL (*Release)(struct ExpatIFace *Self);
- void APICALL (*Expunge)(struct ExpatIFace *Self);
- struct Interface * APICALL (*Clone)(struct ExpatIFace *Self);
- XML_Parser APICALL (*XML_ParserCreate)(struct ExpatIFace *Self, const XML_Char * encodingName);
- XML_Parser APICALL (*XML_ParserCreateNS)(struct ExpatIFace *Self, const XML_Char * encodingName, XML_Char nsSep);
- XML_Parser APICALL (*XML_ParserCreate_MM)(struct ExpatIFace *Self, const XML_Char * encoding, const XML_Memory_Handling_Suite * memsuite, const XML_Char * namespaceSeparator);
- XML_Parser APICALL (*XML_ExternalEntityParserCreate)(struct ExpatIFace *Self, XML_Parser parser, const XML_Char * context, const XML_Char * encoding);
- void APICALL (*XML_ParserFree)(struct ExpatIFace *Self, XML_Parser parser);
- enum XML_Status APICALL (*XML_Parse)(struct ExpatIFace *Self, XML_Parser parser, const char * s, int len, int isFinal);
- enum XML_Status APICALL (*XML_ParseBuffer)(struct ExpatIFace *Self, XML_Parser parser, int len, int isFinal);
- void * APICALL (*XML_GetBuffer)(struct ExpatIFace *Self, XML_Parser parser, int len);
- void APICALL (*XML_SetStartElementHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartElementHandler start);
- void APICALL (*XML_SetEndElementHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_EndElementHandler end);
- void APICALL (*XML_SetElementHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end);
- void APICALL (*XML_SetCharacterDataHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_CharacterDataHandler handler);
- void APICALL (*XML_SetProcessingInstructionHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_ProcessingInstructionHandler handler);
- void APICALL (*XML_SetCommentHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_CommentHandler handler);
- void APICALL (*XML_SetStartCdataSectionHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartCdataSectionHandler start);
- void APICALL (*XML_SetEndCdataSectionHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_EndCdataSectionHandler end);
- void APICALL (*XML_SetCdataSectionHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartCdataSectionHandler start, XML_EndCdataSectionHandler end);
- void APICALL (*XML_SetDefaultHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_DefaultHandler handler);
- void APICALL (*XML_SetDefaultHandlerExpand)(struct ExpatIFace *Self, XML_Parser parser, XML_DefaultHandler handler);
- void APICALL (*XML_SetExternalEntityRefHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_ExternalEntityRefHandler handler);
- void APICALL (*XML_SetExternalEntityRefHandlerArg)(struct ExpatIFace *Self, XML_Parser parser, void * arg);
- void APICALL (*XML_SetUnknownEncodingHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_UnknownEncodingHandler handler, void * data);
- void APICALL (*XML_SetStartNamespaceDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartNamespaceDeclHandler start);
- void APICALL (*XML_SetEndNamespaceDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_EndNamespaceDeclHandler end);
- void APICALL (*XML_SetNamespaceDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartNamespaceDeclHandler start, XML_EndNamespaceDeclHandler end);
- void APICALL (*XML_SetXmlDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_XmlDeclHandler handler);
- void APICALL (*XML_SetStartDoctypeDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartDoctypeDeclHandler start);
- void APICALL (*XML_SetEndDoctypeDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_EndDoctypeDeclHandler end);
- void APICALL (*XML_SetDoctypeDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_StartDoctypeDeclHandler start, XML_EndDoctypeDeclHandler end);
- void APICALL (*XML_SetElementDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_ElementDeclHandler eldecl);
- void APICALL (*XML_SetAttlistDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_AttlistDeclHandler attdecl);
- void APICALL (*XML_SetEntityDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_EntityDeclHandler handler);
- void APICALL (*XML_SetUnparsedEntityDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_UnparsedEntityDeclHandler handler);
- void APICALL (*XML_SetNotationDeclHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_NotationDeclHandler handler);
- void APICALL (*XML_SetNotStandaloneHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_NotStandaloneHandler handler);
- enum XML_Error APICALL (*XML_GetErrorCode)(struct ExpatIFace *Self, XML_Parser parser);
- const XML_LChar * APICALL (*XML_ErrorString)(struct ExpatIFace *Self, enum XML_Error code);
- long APICALL (*XML_GetCurrentByteIndex)(struct ExpatIFace *Self, XML_Parser parser);
- int APICALL (*XML_GetCurrentLineNumber)(struct ExpatIFace *Self, XML_Parser parser);
- int APICALL (*XML_GetCurrentColumnNumber)(struct ExpatIFace *Self, XML_Parser parser);
- int APICALL (*XML_GetCurrentByteCount)(struct ExpatIFace *Self, XML_Parser parser);
- const char * APICALL (*XML_GetInputContext)(struct ExpatIFace *Self, XML_Parser parser, int * offset, int * size);
- void APICALL (*XML_SetUserData)(struct ExpatIFace *Self, XML_Parser parser, void * userData);
- void APICALL (*XML_DefaultCurrent)(struct ExpatIFace *Self, XML_Parser parser);
- void APICALL (*XML_UseParserAsHandlerArg)(struct ExpatIFace *Self, XML_Parser parser);
- enum XML_Status APICALL (*XML_SetBase)(struct ExpatIFace *Self, XML_Parser parser, const XML_Char * base);
- const XML_Char * APICALL (*XML_GetBase)(struct ExpatIFace *Self, XML_Parser parser);
- int APICALL (*XML_GetSpecifiedAttributeCount)(struct ExpatIFace *Self, XML_Parser parser);
- int APICALL (*XML_GetIdAttributeIndex)(struct ExpatIFace *Self, XML_Parser parser);
- enum XML_Status APICALL (*XML_SetEncoding)(struct ExpatIFace *Self, XML_Parser parser, const XML_Char * encoding);
- int APICALL (*XML_SetParamEntityParsing)(struct ExpatIFace *Self, XML_Parser parser, enum XML_ParamEntityParsing parsing);
- void APICALL (*XML_SetReturnNSTriplet)(struct ExpatIFace *Self, XML_Parser parser, int do_nst);
- const XML_LChar * APICALL (*XML_ExpatVersion)(struct ExpatIFace *Self);
- XML_Expat_Version APICALL (*XML_ExpatVersionInfo)(struct ExpatIFace *Self);
- XML_Bool APICALL (*XML_ParserReset)(struct ExpatIFace *Self, XML_Parser parser, const XML_Char * encoding);
- void APICALL (*XML_SetSkippedEntityHandler)(struct ExpatIFace *Self, XML_Parser parser, XML_SkippedEntityHandler handler);
- enum XML_Error APICALL (*XML_UseForeignDTD)(struct ExpatIFace *Self, XML_Parser parser, XML_Bool useDTD);
- const XML_Feature * APICALL (*XML_GetFeatureList)(struct ExpatIFace *Self);
- enum XML_Status APICALL (*XML_StopParser)(struct ExpatIFace *Self, XML_Parser parser, XML_Bool resumable);
- enum XML_Status APICALL (*XML_ResumeParser)(struct ExpatIFace *Self, XML_Parser parser);
- void APICALL (*XML_GetParsingStatus)(struct ExpatIFace *Self, XML_Parser parser, XML_ParsingStatus * status);
- void APICALL (*XML_FreeContentModel)(struct ExpatIFace *Self, XML_Parser parser, XML_Content * model);
- void * APICALL (*XML_MemMalloc)(struct ExpatIFace *Self, XML_Parser parser, size_t size);
- void * APICALL (*XML_MemRealloc)(struct ExpatIFace *Self, XML_Parser parser, void * ptr, size_t size);
- void APICALL (*XML_MemFree)(struct ExpatIFace *Self, XML_Parser parser, void * ptr);
-};
-
-#endif /* EXPAT_INTERFACE_DEF_H */
diff --git a/3rdparty/expat/amiga/include/libraries/expat.h b/3rdparty/expat/amiga/include/libraries/expat.h
deleted file mode 100644
index 1b57387c7b1..00000000000
--- a/3rdparty/expat/amiga/include/libraries/expat.h
+++ /dev/null
@@ -1,566 +0,0 @@
-#ifndef LIBRARIES_EXPAT_H
-#define LIBRARIES_EXPAT_H
-
-/*
-** Copyright (c) 2001-2007 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-
-/****************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __GNUC__
- #ifdef __PPC__
- #pragma pack(2)
- #endif
-#elif defined(__VBCC__)
- #pragma amiga-align
-#endif
-
-/****************************************************************************/
-
-
-#include <stdlib.h>
-
-#ifndef XMLCALL
-#define XMLCALL
-#endif
-
-typedef char XML_Char;
-typedef char XML_LChar;
-typedef long XML_Index;
-typedef unsigned long XML_Size;
-
-struct XML_ParserStruct;
-typedef struct XML_ParserStruct *XML_Parser;
-
-typedef unsigned char XML_Bool;
-#define XML_TRUE ((XML_Bool) 1)
-#define XML_FALSE ((XML_Bool) 0)
-
-enum XML_Status {
- XML_STATUS_ERROR = 0,
-#define XML_STATUS_ERROR XML_STATUS_ERROR
- XML_STATUS_OK = 1,
-#define XML_STATUS_OK XML_STATUS_OK
- XML_STATUS_SUSPENDED = 2,
-#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
-};
-
-enum XML_Error {
- XML_ERROR_NONE,
- XML_ERROR_NO_MEMORY,
- XML_ERROR_SYNTAX,
- XML_ERROR_NO_ELEMENTS,
- XML_ERROR_INVALID_TOKEN,
- XML_ERROR_UNCLOSED_TOKEN,
- XML_ERROR_PARTIAL_CHAR,
- XML_ERROR_TAG_MISMATCH,
- XML_ERROR_DUPLICATE_ATTRIBUTE,
- XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
- XML_ERROR_PARAM_ENTITY_REF,
- XML_ERROR_UNDEFINED_ENTITY,
- XML_ERROR_RECURSIVE_ENTITY_REF,
- XML_ERROR_ASYNC_ENTITY,
- XML_ERROR_BAD_CHAR_REF,
- XML_ERROR_BINARY_ENTITY_REF,
- XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
- XML_ERROR_MISPLACED_XML_PI,
- XML_ERROR_UNKNOWN_ENCODING,
- XML_ERROR_INCORRECT_ENCODING,
- XML_ERROR_UNCLOSED_CDATA_SECTION,
- XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- XML_ERROR_NOT_STANDALONE,
- XML_ERROR_UNEXPECTED_STATE,
- XML_ERROR_ENTITY_DECLARED_IN_PE,
- XML_ERROR_FEATURE_REQUIRES_XML_DTD,
- XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,
- XML_ERROR_UNBOUND_PREFIX,
- XML_ERROR_UNDECLARING_PREFIX,
- XML_ERROR_INCOMPLETE_PE,
- XML_ERROR_XML_DECL,
- XML_ERROR_TEXT_DECL,
- XML_ERROR_PUBLICID,
- XML_ERROR_SUSPENDED,
- XML_ERROR_NOT_SUSPENDED,
- XML_ERROR_ABORTED,
- XML_ERROR_FINISHED,
- XML_ERROR_SUSPEND_PE,
- XML_ERROR_RESERVED_PREFIX_XML,
- XML_ERROR_RESERVED_PREFIX_XMLNS,
- XML_ERROR_RESERVED_NAMESPACE_URI
-};
-
-enum XML_Content_Type {
- XML_CTYPE_EMPTY = 1,
- XML_CTYPE_ANY,
- XML_CTYPE_MIXED,
- XML_CTYPE_NAME,
- XML_CTYPE_CHOICE,
- XML_CTYPE_SEQ
-};
-
-enum XML_Content_Quant {
- XML_CQUANT_NONE,
- XML_CQUANT_OPT,
- XML_CQUANT_REP,
- XML_CQUANT_PLUS
-};
-
-typedef struct XML_cp XML_Content;
-
-struct XML_cp {
- enum XML_Content_Type type;
- enum XML_Content_Quant quant;
- XML_Char * name;
- unsigned int numchildren;
- XML_Content * children;
-};
-
-
-typedef void (*XML_ElementDeclHandler) (void *userData,
- const XML_Char *name,
- XML_Content *model);
-
-void
-XML_SetElementDeclHandler(XML_Parser parser,
- XML_ElementDeclHandler eldecl);
-
-typedef void (*XML_AttlistDeclHandler) (
- void *userData,
- const XML_Char *elname,
- const XML_Char *attname,
- const XML_Char *att_type,
- const XML_Char *dflt,
- int isrequired);
-
-void
-XML_SetAttlistDeclHandler(XML_Parser parser,
- XML_AttlistDeclHandler attdecl);
-
-typedef void (*XML_XmlDeclHandler) (void *userData,
- const XML_Char *version,
- const XML_Char *encoding,
- int standalone);
-
-void
-XML_SetXmlDeclHandler(XML_Parser parser,
- XML_XmlDeclHandler xmldecl);
-
-
-typedef struct {
- void *(*malloc_fcn)(size_t size);
- void *(*realloc_fcn)(void *ptr, size_t size);
- void (*free_fcn)(void *ptr);
-} XML_Memory_Handling_Suite;
-
-XML_Parser
-XML_ParserCreate(const XML_Char *encoding);
-
-XML_Parser
-XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
-
-
-XML_Parser
-XML_ParserCreate_MM(const XML_Char *encoding,
- const XML_Memory_Handling_Suite *memsuite,
- const XML_Char *namespaceSeparator);
-
-XML_Bool
-XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
-
-typedef void (*XML_StartElementHandler) (void *userData,
- const XML_Char *name,
- const XML_Char **atts);
-
-typedef void (*XML_EndElementHandler) (void *userData,
- const XML_Char *name);
-
-
-typedef void (*XML_CharacterDataHandler) (void *userData,
- const XML_Char *s,
- int len);
-
-typedef void (*XML_ProcessingInstructionHandler) (
- void *userData,
- const XML_Char *target,
- const XML_Char *data);
-
-typedef void (*XML_CommentHandler) (void *userData,
- const XML_Char *data);
-
-typedef void (*XML_StartCdataSectionHandler) (void *userData);
-typedef void (*XML_EndCdataSectionHandler) (void *userData);
-
-typedef void (*XML_DefaultHandler) (void *userData,
- const XML_Char *s,
- int len);
-
-typedef void (*XML_StartDoctypeDeclHandler) (
- void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid,
- int has_internal_subset);
-
-typedef void (*XML_EndDoctypeDeclHandler)(void *userData);
-
-typedef void (*XML_EntityDeclHandler) (
- void *userData,
- const XML_Char *entityName,
- int is_parameter_entity,
- const XML_Char *value,
- int value_length,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName);
-
-void
-XML_SetEntityDeclHandler(XML_Parser parser,
- XML_EntityDeclHandler handler);
-
-typedef void (*XML_UnparsedEntityDeclHandler) (
- void *userData,
- const XML_Char *entityName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName);
-
-typedef void (*XML_NotationDeclHandler) (
- void *userData,
- const XML_Char *notationName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId);
-
-typedef void (*XML_StartNamespaceDeclHandler) (
- void *userData,
- const XML_Char *prefix,
- const XML_Char *uri);
-
-typedef void (*XML_EndNamespaceDeclHandler) (
- void *userData,
- const XML_Char *prefix);
-
-typedef int (*XML_NotStandaloneHandler) (void *userData);
-
-typedef int (*XML_ExternalEntityRefHandler) (
- XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId);
-
-typedef void (*XML_SkippedEntityHandler) (
- void *userData,
- const XML_Char *entityName,
- int is_parameter_entity);
-
-typedef struct {
- int map[256];
- void *data;
- int (*convert)(void *data, const char *s);
- void (*release)(void *data);
-} XML_Encoding;
-
-typedef int (*XML_UnknownEncodingHandler) (
- void *encodingHandlerData,
- const XML_Char *name,
- XML_Encoding *info);
-
-void
-XML_SetElementHandler(XML_Parser parser,
- XML_StartElementHandler start,
- XML_EndElementHandler end);
-
-void
-XML_SetStartElementHandler(XML_Parser parser,
- XML_StartElementHandler handler);
-
-void
-XML_SetEndElementHandler(XML_Parser parser,
- XML_EndElementHandler handler);
-
-void
-XML_SetCharacterDataHandler(XML_Parser parser,
- XML_CharacterDataHandler handler);
-
-void
-XML_SetProcessingInstructionHandler(XML_Parser parser,
- XML_ProcessingInstructionHandler handler);
-void
-XML_SetCommentHandler(XML_Parser parser,
- XML_CommentHandler handler);
-
-void
-XML_SetCdataSectionHandler(XML_Parser parser,
- XML_StartCdataSectionHandler start,
- XML_EndCdataSectionHandler end);
-
-void
-XML_SetStartCdataSectionHandler(XML_Parser parser,
- XML_StartCdataSectionHandler start);
-
-void
-XML_SetEndCdataSectionHandler(XML_Parser parser,
- XML_EndCdataSectionHandler end);
-
-void
-XML_SetDefaultHandler(XML_Parser parser,
- XML_DefaultHandler handler);
-
-void
-XML_SetDefaultHandlerExpand(XML_Parser parser,
- XML_DefaultHandler handler);
-
-void
-XML_SetDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start,
- XML_EndDoctypeDeclHandler end);
-
-void
-XML_SetStartDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start);
-
-void
-XML_SetEndDoctypeDeclHandler(XML_Parser parser,
- XML_EndDoctypeDeclHandler end);
-
-void
-XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
- XML_UnparsedEntityDeclHandler handler);
-
-void
-XML_SetNotationDeclHandler(XML_Parser parser,
- XML_NotationDeclHandler handler);
-
-void
-XML_SetNamespaceDeclHandler(XML_Parser parser,
- XML_StartNamespaceDeclHandler start,
- XML_EndNamespaceDeclHandler end);
-
-void
-XML_SetStartNamespaceDeclHandler(XML_Parser parser,
- XML_StartNamespaceDeclHandler start);
-
-void
-XML_SetEndNamespaceDeclHandler(XML_Parser parser,
- XML_EndNamespaceDeclHandler end);
-
-void
-XML_SetNotStandaloneHandler(XML_Parser parser,
- XML_NotStandaloneHandler handler);
-
-void
-XML_SetExternalEntityRefHandler(XML_Parser parser,
- XML_ExternalEntityRefHandler handler);
-
-void
-XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
- void *arg);
-
-void
-XML_SetSkippedEntityHandler(XML_Parser parser,
- XML_SkippedEntityHandler handler);
-
-void
-XML_SetUnknownEncodingHandler(XML_Parser parser,
- XML_UnknownEncodingHandler handler,
- void *encodingHandlerData);
-
-void
-XML_DefaultCurrent(XML_Parser parser);
-
-void
-XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
-
-void
-XML_SetUserData(XML_Parser parser, void *userData);
-
-#define XML_GetUserData(parser) (*(void **)(parser))
-
-enum XML_Status
-XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
-
-void
-XML_UseParserAsHandlerArg(XML_Parser parser);
-
-enum XML_Error
-XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
-
-
-enum XML_Status
-XML_SetBase(XML_Parser parser, const XML_Char *base);
-
-const XML_Char *
-XML_GetBase(XML_Parser parser);
-
-int
-XML_GetSpecifiedAttributeCount(XML_Parser parser);
-
-int
-XML_GetIdAttributeIndex(XML_Parser parser);
-
-enum XML_Status
-XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
-
-void *
-XML_GetBuffer(XML_Parser parser, int len);
-
-enum XML_Status
-XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
-
-enum XML_Status
-XML_StopParser(XML_Parser parser, XML_Bool resumable);
-
-enum XML_Status
-XML_ResumeParser(XML_Parser parser);
-
-enum XML_Parsing {
- XML_INITIALIZED,
- XML_PARSING,
- XML_FINISHED,
- XML_SUSPENDED
-};
-
-typedef struct {
- enum XML_Parsing parsing;
- XML_Bool finalBuffer;
-} XML_ParsingStatus;
-
-void
-XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
-
-XML_Parser
-XML_ExternalEntityParserCreate(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *encoding);
-
-enum XML_ParamEntityParsing {
- XML_PARAM_ENTITY_PARSING_NEVER,
- XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
- XML_PARAM_ENTITY_PARSING_ALWAYS
-};
-
-int
-XML_SetParamEntityParsing(XML_Parser parser,
- enum XML_ParamEntityParsing parsing);
-
-enum XML_Error
-XML_GetErrorCode(XML_Parser parser);
-
-int XML_GetCurrentLineNumber(XML_Parser parser);
-int XML_GetCurrentColumnNumber(XML_Parser parser);
-long XML_GetCurrentByteIndex(XML_Parser parser);
-
-int
-XML_GetCurrentByteCount(XML_Parser parser);
-
-const char *
-XML_GetInputContext(XML_Parser parser,
- int *offset,
- int *size);
-
-#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
-#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
-#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
-
-void
-XML_FreeContentModel(XML_Parser parser, XML_Content *model);
-
-void *
-XML_MemMalloc(XML_Parser parser, size_t size);
-
-void *
-XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
-
-void
-XML_MemFree(XML_Parser parser, void *ptr);
-
-void
-XML_ParserFree(XML_Parser parser);
-
-const XML_LChar *
-XML_ErrorString(enum XML_Error code);
-
-const XML_LChar *
-XML_ExpatVersion(void);
-
-typedef struct {
- int major;
- int minor;
- int micro;
-} XML_Expat_Version;
-
-XML_Expat_Version
-XML_ExpatVersionInfo(void);
-
-enum XML_FeatureEnum {
- XML_FEATURE_END = 0,
- XML_FEATURE_UNICODE,
- XML_FEATURE_UNICODE_WCHAR_T,
- XML_FEATURE_DTD,
- XML_FEATURE_CONTEXT_BYTES,
- XML_FEATURE_MIN_SIZE,
- XML_FEATURE_SIZEOF_XML_CHAR,
- XML_FEATURE_SIZEOF_XML_LCHAR,
- XML_FEATURE_NS,
- XML_FEATURE_LARGE_SIZE
-};
-
-typedef struct {
- enum XML_FeatureEnum feature;
- const XML_LChar *name;
- long int value;
-} XML_Feature;
-
-const XML_Feature *
-XML_GetFeatureList(void);
-
-
-#define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 0
-#define XML_MICRO_VERSION 1
-
-
-/****************************************************************************/
-
-#ifdef __GNUC__
- #ifdef __PPC__
- #pragma pack()
- #endif
-#elif defined(__VBCC__)
- #pragma default-align
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-/****************************************************************************/
-
-#endif /* EXPAT_EXPAT_H */
diff --git a/3rdparty/expat/amiga/include/proto/expat.h b/3rdparty/expat/amiga/include/proto/expat.h
deleted file mode 100644
index 90bf62c46ea..00000000000
--- a/3rdparty/expat/amiga/include/proto/expat.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef PROTO_EXPAT_H
-#define PROTO_EXPAT_H
-
-#ifndef LIBRARIES_EXPAT_H
-#include <libraries/expat.h>
-#endif
-
-/****************************************************************************/
-
-#ifndef __NOLIBBASE__
- #ifndef __USE_BASETYPE__
- extern struct Library * ExpatBase;
- #else
- extern struct Library * ExpatBase;
- #endif /* __USE_BASETYPE__ */
-#endif /* __NOLIBBASE__ */
-
-/****************************************************************************/
-
-#ifdef __amigaos4__
- #include <interfaces/expat.h>
- #ifdef __USE_INLINE__
- #include <inline4/expat.h>
- #endif /* __USE_INLINE__ */
- #ifndef CLIB_EXPAT_PROTOS_H
- #define CLIB_EXPAT_PROTOS_H 1
- #endif /* CLIB_EXPAT_PROTOS_H */
- #ifndef __NOGLOBALIFACE__
- extern struct ExpatIFace *IExpat;
- #endif /* __NOGLOBALIFACE__ */
-#else /* __amigaos4__ */
- #ifndef CLIB_EXPAT_PROTOS_H
- #include <clib/expat_protos.h>
- #endif /* CLIB_EXPAT_PROTOS_H */
- #if defined(__GNUC__)
- #ifndef __PPC__
- #include <inline/expat.h>
- #else
- #include <ppcinline/expat.h>
- #endif /* __PPC__ */
- #elif defined(__VBCC__)
- #ifndef __PPC__
- #include <inline/expat_protos.h>
- #endif /* __PPC__ */
- #else
- #include <pragmas/expat_pragmas.h>
- #endif /* __GNUC__ */
-#endif /* __amigaos4__ */
-
-/****************************************************************************/
-
-#endif /* PROTO_EXPAT_H */
diff --git a/3rdparty/expat/amiga/launch.c b/3rdparty/expat/amiga/launch.c
deleted file mode 100644
index 20b069c3f83..00000000000
--- a/3rdparty/expat/amiga/launch.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-** Copyright (c) 2001-2009 Expat maintainers.
-**
-** Permission is hereby granted, free of charge, to any person obtaining
-** a copy of this software and associated documentation files (the
-** "Software"), to deal in the Software without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Software, and to
-** permit persons to whom the Software is furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#ifdef __USE_INLINE__
-#undef __USE_INLINE__
-#endif
-
-#include <stdlib.h>
-#include <proto/exec.h>
-
-struct Library* ExpatBase = 0;
-struct ExpatIFace* IExpat = 0;
-
-
-void setup() __attribute__((constructor));
-void cleanup() __attribute__((destructor));
-
-
-void setup()
-{
- ExpatBase = IExec->OpenLibrary("expat.library", 53);
- IExpat = (struct ExpatIFace*)IExec->GetInterface(ExpatBase, "main", 1, NULL);
-
- if ( IExpat == 0 ) {
- IExec->DebugPrintF("Can't open expat.library\n");
- }
-}
-
-
-void cleanup()
-{
- IExec->DropInterface((struct Interface*)IExpat);
- IExpat = 0;
-
- IExec->CloseLibrary(ExpatBase);
- ExpatBase = 0;
-}
diff --git a/3rdparty/expat/bcb5/README.txt b/3rdparty/expat/bcb5/README.txt
deleted file mode 100644
index 486f1ca85d6..00000000000
--- a/3rdparty/expat/bcb5/README.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-
- Using a Borland compiler product
-
-The files in this directory support using both the free Borland command-line
-compiler tools and the Borland C++ Builder IDE. The project files have been
-tested with both versions 5 and 6 of the C++ Builder product.
-
- Using the free BCC32 command line compiler
-
-After downloading and installing the free C++ Builder commandline version,
-perform the following steps (assuming it was installed under C:\Borland\BCC55):
-
-1) Add "C:\Borland\BCC55\BIN" to your path
-2) Set the environment variable BCB to "C:\Borland\BCC55".
-3) edit makefile.mak: enable or comment out the appropriate commands under
- clean & distclean, depending on whether your OS can use deltree /y or
- del /s/f/q.
-
-After that, you should simply cd to the bcb5 directory in your Expat directory
-tree (same structure as CVS) and run "make all" or just "make".
-
- Naming
-
-The libraries have the base name "libexpat" followed optionally by an "s"
-(static) or a "w" (unicode version), then an underscore and optionally
-"mt" (multi-threaded) and "d" (dynamic RTL).
-
-To change the name of the library a project file produces, edit the project
-option source (see step 1 under Unicode below) and change the name contained in
-the PROJECT tag. In a make file, change the value assigned to the PROJECT
-variable. Also, the LIBRARY entry in the .def file has to be changed to
-correspond to the new executable name.
-
-
- Unicode Considerations
-
-There are no facilities in the BCB 5 GUI to create a unicode-enabled
-application. Fortunately, it is not hard to do by hand.
-
-1. The startup .obj system file must be changed to the unicode version.
- Go to Project|Edit Option Source, and scroll down to the ALLOBJ tag. Change
- c0x32.obj to c0x32w.obj. Editing this file can be quirky, but usually the
- following kludge will make the change stick. Close and save the file
- (CTRL-F4) then open the options dialog (CTRL-Shift-F11), then click OK on
- the dialog immediately without changing anything in it. If this doesn't work,
- you will have to close the project completely and edit the .bpr file by hand.
-
- If you are using a make file, just change the startup .obj file assigned
- to the ALLOBJ variable.
-
-2. Add the macro define XML_UNICODE_WCHAR_T. In the GUI that goes in the options
- dialog, Directories/Conditionals tab, in the Conditional define box. In a
- make file, put it in the USERDEFINES variable.
-
-3. Of course, your code has to be written for unicode. As a start, the "main"
- function is called "wmain". The tchar macros are an interesting way to
- write code that can easily switch between unicode and utf-8. If these macros
- are used, then simply adding the conditional define _UNICODE as well as
- XML_UNICODE_WCHAR_T will bring in the unicode versions of the tchar macros.
- Otherwise the utf-8 versions are used. xmlwf uses its own versions of the
- tchar macros which are switched on and off by the XML_UNICODE macro, which
- itself is set by the XML_UNICODE_WCHAR_T define.
-
- Threading
-
-The libexpat libraries are all built to link with the multi-threaded dynamic RTL's.
-That means they require CC32xxMT.DLL present on the installation target.
-To create single-threaded libs, do the following:
-
-1. The compiler option for multi-threading must be turned off. Following the
- instructions above to edit the option source, remove the -tWM option from
- the CFLAG1 tag. In a make file, remove it from the CFLAG1 variable.
-
-2. The single threaded RTL must be called. change the RTL in the ALLLIB tag or
- variable (GUI or makefile repectively) to the version without the "mt" in the
- name. For example, change cw32mti.lib to cw32i.lib.
-
- Static RTL's
-
-To build the libs with static RTL's do the following,
-
-1. For the static expatlibs, in the Tlib tab on the options dialog, uncheck the
- "Use dynamic RTL" box. For the dynamic expatlibs, in the Linker tab on the
- options dialog, uncheck "Use dynamic RTL". If you are using a make file,
- remove the _RTLDLL assignment to the SYSDEFINES variable, and change the RTL
- to the version without an "i" in the ALLLIB variable. For example,
- cw32mti.lib would become cw32mt.lib.
diff --git a/3rdparty/expat/bcb5/all_projects.bpg b/3rdparty/expat/bcb5/all_projects.bpg
deleted file mode 100644
index 27c9a1cba57..00000000000
--- a/3rdparty/expat/bcb5/all_projects.bpg
+++ /dev/null
@@ -1,49 +0,0 @@
-#------------------------------------------------------------------------------
-VERSION = BWS.01
-#------------------------------------------------------------------------------
-!ifndef ROOT
-ROOT = $(MAKEDIR)\..
-!endif
-#------------------------------------------------------------------------------
-MAKE = $(ROOT)\bin\make.exe -$(MAKEFLAGS) -f$**
-DCC = $(ROOT)\bin\dcc32.exe $**
-BRCC = $(ROOT)\bin\brcc32.exe $**
-#------------------------------------------------------------------------------
-PROJECTS = setup libexpat_mtd.dll libexpats_mtd.lib libexpatw_mtd.dll \
- libexpatws_mtd.lib elements.exe outline.exe xmlwf.exe
-#------------------------------------------------------------------------------
-default: $(PROJECTS)
-#------------------------------------------------------------------------------
-
-libexpat_mtd.dll: expat.bpr
- $(ROOT)\bin\bpr2mak $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-libexpats_mtd.lib: expat_static.bpr
- $(ROOT)\bin\bpr2mak -t$(ROOT)\bin\deflib.bmk $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-libexpatw_mtd.dll: expatw.bpr
- $(ROOT)\bin\bpr2mak $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-libexpatws_mtd.lib: expatw_static.bpr
- $(ROOT)\bin\bpr2mak -t$(ROOT)\bin\deflib.bmk $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-elements.exe: elements.bpr
- $(ROOT)\bin\bpr2mak $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-outline.exe: outline.bpr
- $(ROOT)\bin\bpr2mak $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-xmlwf.exe: xmlwf.bpr
- $(ROOT)\bin\bpr2mak $**
- $(ROOT)\bin\make -$(MAKEFLAGS) -f$*.mak
-
-setup: setup.bat
- call $**
-
-
diff --git a/3rdparty/expat/bcb5/elements.bpf b/3rdparty/expat/bcb5/elements.bpf
deleted file mode 100644
index 5c1e878d671..00000000000
--- a/3rdparty/expat/bcb5/elements.bpf
+++ /dev/null
@@ -1,4 +0,0 @@
-USEUNIT("..\examples\elements.c");
-USELIB("Release\libexpats_mtd.lib");
-//---------------------------------------------------------------------------
-main
diff --git a/3rdparty/expat/bcb5/elements.bpr b/3rdparty/expat/bcb5/elements.bpr
deleted file mode 100644
index e6e260f8a71..00000000000
--- a/3rdparty/expat/bcb5/elements.bpr
+++ /dev/null
@@ -1,149 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\elements.exe"/>
- <OBJFILES value="Release\obj\examples\elements.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value=""/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value="Release\libexpats_mtd.lib"/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value="VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi"/>
- <PATHCPP value=".;..\examples"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="ilink32"/>
- <USERDEFINES value="WIN32;NDEBUG;_CONSOLE;XML_STATIC"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="elements.bpf"/>
- <INCLUDEPATH value="..\examples;$(BCB)\include"/>
- <LIBPATH value="..\examples;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-par -w-8027 -w-8026"/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-O2 -X- -a8 -b -k- -vi -q -tWM -I..\lib -c"/>
- <PFLAGS value="-N2Release\obj\examples -N0Release\obj\examples -$Y- -$L- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value="-IRelease\obj\examples -D&quot;&quot; -ap -Tpe -x -Gn -q -L..\LIB\RELEASE_STATIC"/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="c0x32.obj $(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=4
-Item0=..\examples;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl
-Item3=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=8
-Item0=..\examples;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\examples;$(BCB)\lib;..\examples\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);..\lib\Release-w_static
-Item4=$(BCB)\lib;$(RELEASELIBPATH);..\lib\Release_static
-Item5=$(BCB)\lib;$(RELEASELIBPATH);C:\src\expat\lib\Release_static
-Item6=$(BCB)\lib;$(RELEASELIBPATH);$(BCB)\lib\psdk
-Item7=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=17
-Item0=WIN32;NDEBUG;_CONSOLE;XML_STATIC
-Item1=WIN32;NDEBUG;_CONSOLE;_DEBUG;XML_STATIC
-Item2=WIN32;NDEBUG;_CONSOLE;_DEBUG;XML_UNICODE_WCHAR_T;_UNICODE;XML_STATIC
-Item3=WIN32;NDEBUG;_CONSOLE;_DEBUG;XML_UNICODE_WCHAR_T;_UNICODE
-Item4=WIN32;NDEBUG;_CONSOLE;_DEBUG
-Item5=WIN32;NDEBUG;_CONSOLE;XML_STATIC;_DEBUG
-Item6=WIN32;NDEBUG;_CONSOLE;XML_STATIC;_DEBUG;_UNICODE
-Item7=WIN32;NDEBUG;_CONSOLE;XML_STATIC;_DEBUG;XML_UNICODE_WCHAR_T
-Item8=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC;_DEBUG;XML_UNICODE_WCHAR_T
-Item9=WIN32;NDEBUG;_CONSOLE;_UNICODE;XML_STATIC;_DEBUG;XML_UNICODE_WCHAR_T
-Item10=WIN32;NDEBUG;_CONSOLE;_UNICODE;XML_STATIC;_DEBUG;XML_UNICODE
-Item11=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC;_DEBUG;XML_UNICODE_WCHAR_T;__WCHAR_T
-Item12=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC;_DEBUG;XML_UNICODE_WCHAR_T;_UNICODE
-Item13=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC;_DEBUG;XML_UNICODE;_UNICODE
-Item14=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC;_DEBUG;XML_UNICODE
-Item15=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC;_DEBUG
-Item16=WIN32;NDEBUG;_CONSOLE;_MBCS;XML_STATIC
-
-[HistoryLists\hlIntOutputDir]
-Count=5
-Item0=Release\obj\examples
-Item1=Release\obj\elements
-Item2=Release\obj\mts
-Item3=..\examples\Release
-Item4=Release
-
-[HistoryLists\hlFinalOutputDir]
-Count=1
-Item0=Release\
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/elements.mak b/3rdparty/expat/bcb5/elements.mak
deleted file mode 100644
index d4427fd5129..00000000000
--- a/3rdparty/expat/bcb5/elements.mak
+++ /dev/null
@@ -1,186 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\elements.exe
-OBJFILES = Release\obj\examples\elements.obj
-RESFILES =
-MAINSOURCE = elements.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES = Release\libexpats_mtd.lib
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES = VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi \
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi \
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi \
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi
-SPARELIBS =
-DEFFILE =
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\examples
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = WIN32;NDEBUG;_CONSOLE;XML_STATIC
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\examples;$(BCB)\include
-LIBPATH = ..\examples;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS= -w-par -w-8027 -w-8026
-# ---------------------------------------------------------------------------
-CFLAG1 = -O2 -X- -a8 -b -k- -vi -q -I..\lib -c
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\examples -N0Release\obj\examples -$Y- -$L- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS = -IRelease\obj\examples -D"" -ap -Tpe -x -Gn -q -L..\LIB\RELEASE_STATIC
-# ---------------------------------------------------------------------------
-ALLOBJ = c0x32.obj $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = ilink32
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) @&&!
- $(LFLAGS) -L$(LIBPATH) +
- $(ALLOBJ), +
- $(PROJECT),, +
- $(ALLLIB), +
- $(DEFFILE), +
- $(ALLRES)
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/bcb5/expat.bpf b/3rdparty/expat/bcb5/expat.bpf
deleted file mode 100644
index 2c423283f10..00000000000
--- a/3rdparty/expat/bcb5/expat.bpf
+++ /dev/null
@@ -1,6 +0,0 @@
-USEUNIT("..\lib\xmlparse.c");
-USEUNIT("..\lib\xmlrole.c");
-USEUNIT("..\lib\xmltok.c");
-USEDEF("libexpat_mtd.def");
-//---------------------------------------------------------------------------
-#define DllEntryPoint
diff --git a/3rdparty/expat/bcb5/expat.bpr b/3rdparty/expat/bcb5/expat.bpr
deleted file mode 100644
index 7aff450b0ee..00000000000
--- a/3rdparty/expat/bcb5/expat.bpr
+++ /dev/null
@@ -1,140 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\libexpat_mtd.dll"/>
- <OBJFILES value="Release\obj\libexpat\xmlparse.obj Release\obj\libexpat\xmlrole.obj
- Release\obj\libexpat\xmltok.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value="libexpat_mtd.def"/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value=""/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value="VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi"/>
- <PATHCPP value=".;..\lib"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="ilink32"/>
- <USERDEFINES value="_WINDOWS;WIN32;NDEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="expat.bpf"/>
- <INCLUDEPATH value="..\lib;$(BCB)\include"/>
- <LIBPATH value="..\lib;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-rch -w-par -w-8027 -w-8026 -w-ccc"/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-WD -O2 -X- -a8 -b -k- -vi -q -tWM -c -tWD"/>
- <PFLAGS value="-N2Release\obj\libexpat -N0Release\obj\libexpat -$Y- -$L- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value="-IRelease\obj\libexpat -D&quot;&quot; -aa -Tpd -x -Gn -Gi -q"/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="c0d32.obj $(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=4
-Item0=..\lib;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl
-Item3=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=5
-Item0=..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\lib;$(BCB)\lib;..\lib\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);$(BCB)\lib\psdk
-Item4=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=8
-Item0=_WINDOWS;WIN32;NDEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS
-Item1=_WINDOWS;WIN32;NDEBUG;_DEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS
-Item2=WIN32;_WINDOWS;NDEBUG;_DEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS
-Item3=WIN32;_WINDOWS;NDEBUG;_DEBUG;_USRDLL;EXPAT_EXPORTS;COMPILED_FROM_DSP
-Item4=NDEBUG;WIN32;_WINDOWS;_USRDLL;_DEBUG;EXPAT_EXPORTS;COMPILED_FROM_DSP
-Item5=NDEBUG;WIN32;_WINDOWS;_USRDLL;EXPAT_EXPORTS;COMPILED_FROM_DSP;_DEBUG
-Item6=NDEBUG;WIN32;_WINDOWS;_MBCS;_USRDLL;EXPAT_EXPORTS;COMPILED_FROM_DSP;_DEBUG
-Item7=NDEBUG;WIN32;_WINDOWS;_MBCS;_USRDLL;EXPAT_EXPORTS;COMPILED_FROM_DSP
-
-[HistoryLists\hlIntOutputDir]
-Count=7
-Item0=Release\obj\libexpat
-Item1=Release\obj\libexpat_static
-Item2=Release\obj\mtd
-Item3=Release\obj\mt
-Item4=Release\obj
-Item5=Release
-Item6=..\lib\Release
-
-[HistoryLists\hlFinalOutputDir]
-Count=1
-Item0=Release\
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/expat.mak b/3rdparty/expat/bcb5/expat.mak
deleted file mode 100644
index 7c9c23f52b8..00000000000
--- a/3rdparty/expat/bcb5/expat.mak
+++ /dev/null
@@ -1,187 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\libexpat_mtd.dll
-OBJFILES = Release\obj\libexpat\xmlparse.obj Release\obj\libexpat\xmlrole.obj \
- Release\obj\libexpat\xmltok.obj
-RESFILES =
-MAINSOURCE = expat.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES =
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES = VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi \
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi \
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi \
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi
-SPARELIBS =
-DEFFILE = libexpat_mtd.def
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\lib
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = _WINDOWS;WIN32;NDEBUG;_USRDLL;COMPILED_FROM_DSP
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\lib;$(BCB)\include
-LIBPATH = ..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS= -w-rch -w-par -w-8027 -w-8026 -w-ccc
-# ---------------------------------------------------------------------------
-CFLAG1 = -WD -O2 -X- -a8 -b -k- -vi -q -tWM -c -tWD
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\libexpat -N0Release\obj\libexpat -$Y- -$L- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS = -IRelease\obj\libexpat -D"" -aa -Tpd -x -Gn -Gi -q
-# ---------------------------------------------------------------------------
-ALLOBJ = c0d32.obj $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = ilink32
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) @&&!
- $(LFLAGS) -L$(LIBPATH) +
- $(ALLOBJ), +
- $(PROJECT),, +
- $(ALLLIB), +
- $(DEFFILE), +
- $(ALLRES)
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/bcb5/expat_static.bpf b/3rdparty/expat/bcb5/expat_static.bpf
deleted file mode 100644
index 5ca458edcae..00000000000
--- a/3rdparty/expat/bcb5/expat_static.bpf
+++ /dev/null
@@ -1,5 +0,0 @@
-USEUNIT("..\lib\xmlparse.c");
-USEUNIT("..\lib\xmlrole.c");
-USEUNIT("..\lib\xmltok.c");
-//---------------------------------------------------------------------------
-#define Library
diff --git a/3rdparty/expat/bcb5/expat_static.bpr b/3rdparty/expat/bcb5/expat_static.bpr
deleted file mode 100644
index 0b78ec89128..00000000000
--- a/3rdparty/expat/bcb5/expat_static.bpr
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\libexpats_mtd.lib"/>
- <OBJFILES value="Release\obj\libexpat_static\xmlparse.obj
- Release\obj\libexpat_static\xmlrole.obj
- Release\obj\libexpat_static\xmltok.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value=""/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value=""/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value=""/>
- <PATHCPP value=".;..\lib"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="TLib"/>
- <USERDEFINES value="_WINDOWS;WIN32;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="expat_static.bpf"/>
- <INCLUDEPATH value="..\lib;$(BCB)\include"/>
- <LIBPATH value="..\lib;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-rch -w-par -w-8027 -w-8026 -w-ccc"/>
- <LISTFILE value=""/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-O2 -X- -a8 -b -k- -vi -q -tWM -c"/>
- <PFLAGS value="-N2Release\obj\libexpat_static -N0Release\obj\libexpat_static -$Y- -$L- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value=""/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="$(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES)"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=4
-Item0=..\lib;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl
-Item3=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=5
-Item0=..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\lib;$(BCB)\lib;..\lib\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);$(BCB)\lib\psdk
-Item4=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=7
-Item0=_WINDOWS;WIN32;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC
-Item1=_WINDOWS;WIN32;NDEBUG;_DEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC
-Item2=WIN32;_WINDOWS;NDEBUG;_DEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC
-Item3=WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP;_DEBUG
-Item4=WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP
-Item5=WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP;_MBCS
-Item6=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP
-
-[HistoryLists\hlIntOutputDir]
-Count=6
-Item0=Release\obj\libexpat_static
-Item1=Release\obj\mts
-Item2=Release\obj\mt
-Item3=Release
-Item4=..\lib\Release_static
-Item5=Release_static
-
-[HistoryLists\hlFinalOutputDir]
-Count=3
-Item0=Release\
-Item1=Release
-Item2=Release_static\
-
-[HistoryLists\hlTlibPageSize]
-Count=1
-Item0=0x0010
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/expat_static.mak b/3rdparty/expat/bcb5/expat_static.mak
deleted file mode 100644
index 9137d3b5346..00000000000
--- a/3rdparty/expat/bcb5/expat_static.mak
+++ /dev/null
@@ -1,189 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\libexpats_mtd.lib
-OBJFILES = Release\obj\libexpat_static\xmlparse.obj \
- Release\obj\libexpat_static\xmlrole.obj \
- Release\obj\libexpat_static\xmltok.obj
-RESFILES =
-MAINSOURCE = expat_static.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES =
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES =
-SPARELIBS =
-DEFFILE =
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\lib
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-LINKER = TLib
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = _WINDOWS;WIN32;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\lib;$(BCB)\include
-LIBPATH = ..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS = -w-rch -w-par -w-8027 -w-8026 -w-ccc
-LISTFILE =
-# ---------------------------------------------------------------------------
-CFLAG1 = -O2 -X- -a8 -b -k- -vi -q -tWM -c
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\libexpat_static -N0Release\obj\libexpat_static -$Y- -$L- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS =
-# ---------------------------------------------------------------------------
-ALLOBJ = $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES)
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = TLib
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-!if "$(LISTFILE)" == ""
-COMMA =
-!else
-COMMA = ,
-!endif
-
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) /u $@ @&&!
- $(LFLAGS) $? $(COMMA) $(LISTFILE)
-
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/bcb5/expatw.bpf b/3rdparty/expat/bcb5/expatw.bpf
deleted file mode 100644
index 188a6d54ead..00000000000
--- a/3rdparty/expat/bcb5/expatw.bpf
+++ /dev/null
@@ -1,6 +0,0 @@
-USEUNIT("..\lib\xmlparse.c");
-USEUNIT("..\lib\xmlrole.c");
-USEUNIT("..\lib\xmltok.c");
-USEDEF("libexpatw_mtd.def");
-//---------------------------------------------------------------------------
-#define DllEntryPoint
diff --git a/3rdparty/expat/bcb5/expatw.bpr b/3rdparty/expat/bcb5/expatw.bpr
deleted file mode 100644
index a9c9f75cf3f..00000000000
--- a/3rdparty/expat/bcb5/expatw.bpr
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\libexpatw_mtd.dll"/>
- <OBJFILES value="Release\obj\libexpatw\xmlparse.obj Release\obj\libexpatw\xmlrole.obj
- Release\obj\libexpatw\xmltok.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value="libexpatw_mtd.def"/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value=""/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value="VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi"/>
- <PATHCPP value=".;..\lib"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="ilink32"/>
- <USERDEFINES value="_WINDOWS;WIN32;NDEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="expatw.bpf"/>
- <INCLUDEPATH value="..\lib;$(BCB)\include"/>
- <LIBPATH value="..\lib;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-rch -w-par -w-8027 -w-8026 -w-ccc"/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-WD -O2 -X- -a8 -b -k- -vi -q -tWM -c -tWD"/>
- <PFLAGS value="-N2Release\obj\libexpatw -N0Release\obj\libexpatw -$Y- -$L- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value="-IRelease\obj\libexpatw -D&quot;&quot; -aa -Tpd -x -Gn -Gi -w -q"/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="c0d32w.obj $(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=4
-Item0=..\lib;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl
-Item3=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=5
-Item0=..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\lib;$(BCB)\lib;..\lib\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);$(BCB)\lib\psdk
-Item4=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=9
-Item0=_WINDOWS;WIN32;NDEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T
-Item1=_WINDOWS;WIN32;NDEBUG;_DEBUG;_USRDLL;COMPILED_FROM_DSP;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T
-Item2=_WINDOWS;WIN32;NDEBUG;_DEBUG;_USRDLL;EXPAT_EXPORTS;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T
-Item3=NDEBUG;COMPILED_FROM_DSP;WIN32;_WINDOWS;_USRDLL;EXPAT_EXPORTS;_DEBUG;XML_UNICODE_WCHAR_T
-Item4=NDEBUG;COMPILED_FROM_DSP;WIN32;_WINDOWS;_USRDLL;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T;_DEBUG
-Item5=NDEBUG;COMPILED_FROM_DSP;WIN32;_WINDOWS;_UNICODE;_USRDLL;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T;_DEBUG
-Item6=NDEBUG;COMPILED_FROM_DSP;WIN32;_WINDOWS;_UNICODE;_USRDLL;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T
-Item7=NDEBUG;COMPILED_FROM_DSP;WIN32;_WINDOWS;_MBCS;_USRDLL;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T;XML_UNICODE
-Item8=NDEBUG;COMPILED_FROM_DSP;WIN32;_WINDOWS;_MBCS;_USRDLL;EXPAT_EXPORTS;XML_UNICODE_WCHAR_T
-
-[HistoryLists\hlIntOutputDir]
-Count=8
-Item0=Release\obj\libexpatw
-Item1=Release\obj\libexpat
-Item2=Release\obj\mtd
-Item3=Release\obj\mt
-Item4=Release_w\obj
-Item5=Release-w\obj
-Item6=Release-w
-Item7=..\lib\Release-w
-
-[HistoryLists\hlFinalOutputDir]
-Count=5
-Item0=Release\
-Item1=Release
-Item2=Release_w\
-Item3=Release-w\
-Item4=Release-w
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/expatw.mak b/3rdparty/expat/bcb5/expatw.mak
deleted file mode 100644
index 08e17d003b8..00000000000
--- a/3rdparty/expat/bcb5/expatw.mak
+++ /dev/null
@@ -1,187 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\libexpatw_mtd.dll
-OBJFILES = Release\obj\libexpatw\xmlparse.obj Release\obj\libexpatw\xmlrole.obj \
- Release\obj\libexpatw\xmltok.obj
-RESFILES =
-MAINSOURCE = expatw.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES =
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES = VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi \
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi \
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi \
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi
-SPARELIBS =
-DEFFILE = libexpatw_mtd.def
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\lib
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = _WINDOWS;WIN32;NDEBUG;_USRDLL;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\lib;$(BCB)\include
-LIBPATH = ..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS= -w-rch -w-par -w-8027 -w-8026 -w-ccc
-# ---------------------------------------------------------------------------
-CFLAG1 = -WD -O2 -X- -a8 -b -k- -vi -q -tWM -c -tWD
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\libexpatw -N0Release\obj\libexpatw -$Y- -$L- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS = -IRelease\obj\libexpatw -D"" -aa -Tpd -x -Gn -Gi -w -q
-# ---------------------------------------------------------------------------
-ALLOBJ = c0d32w.obj $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = ilink32
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) @&&!
- $(LFLAGS) -L$(LIBPATH) +
- $(ALLOBJ), +
- $(PROJECT),, +
- $(ALLLIB), +
- $(DEFFILE), +
- $(ALLRES)
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/bcb5/expatw_static.bpf b/3rdparty/expat/bcb5/expatw_static.bpf
deleted file mode 100644
index 5ca458edcae..00000000000
--- a/3rdparty/expat/bcb5/expatw_static.bpf
+++ /dev/null
@@ -1,5 +0,0 @@
-USEUNIT("..\lib\xmlparse.c");
-USEUNIT("..\lib\xmlrole.c");
-USEUNIT("..\lib\xmltok.c");
-//---------------------------------------------------------------------------
-#define Library
diff --git a/3rdparty/expat/bcb5/expatw_static.bpr b/3rdparty/expat/bcb5/expatw_static.bpr
deleted file mode 100644
index 457acc7c1ad..00000000000
--- a/3rdparty/expat/bcb5/expatw_static.bpr
+++ /dev/null
@@ -1,152 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\libexpatws_mtd.lib"/>
- <OBJFILES value="Release\obj\libexpatw_static\xmlparse.obj
- Release\obj\libexpatw_static\xmlrole.obj
- Release\obj\libexpatw_static\xmltok.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value=""/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value=""/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value=""/>
- <PATHCPP value=".;..\lib"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="TLib"/>
- <USERDEFINES value="_WINDOWS;WIN32;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;XML_UNICODE_WCHAR_T"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="expatw_static.bpf"/>
- <INCLUDEPATH value="..\lib;$(BCB)\include"/>
- <LIBPATH value="..\lib;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-rch -w-par -w-8027 -w-8026 -w-ccc"/>
- <LISTFILE value=""/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-O2 -X- -a8 -b -k- -vi -q -tWM -c"/>
- <PFLAGS value="-N2Release\obj\libexpatw_static -N0Release\obj\libexpatw_static -$Y- -$L-
- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value=""/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="$(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES)"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=4
-Item0=..\lib;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl
-Item3=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=5
-Item0=..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\lib;$(BCB)\lib;..\lib\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);$(BCB)\lib\psdk
-Item4=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=15
-Item0=_WINDOWS;WIN32;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;XML_UNICODE_WCHAR_T
-Item1=_WINDOWS;WIN32;NDEBUG;_DEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;XML_UNICODE_WCHAR_T
-Item2=WIN32;_WINDOWS;NDEBUG;_DEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;XML_UNICODE_WCHAR_T
-Item3=WIN32;_WINDOWS;NDEBUG;_DEBUG;_LIB;XML_STATIC;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T
-Item4=WIN32;_WINDOWS;NDEBUG;_LIB;COMPILED_FROM_DSP;_DEBUG;XML_UNICODE_WCHAR_T
-Item5=WIN32;_WINDOWS;NDEBUG;_UNICODE;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T;_DEBUG
-Item6=WIN32;_WINDOWS;NDEBUG;_UNICODE;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T;_DEBUG;__cplusplus
-Item7=WIN32;_WINDOWS;NDEBUG;_UNICODE;_LIB;COMPILED_FROM_DSP;XML_UNICODE;_DEBUG
-Item8=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE;_DEBUG
-Item9=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T;_DEBUG;__WCHAR_T
-Item10=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T;_DEBUG;_UNICODE
-Item11=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE;_DEBUG;_UNICODE
-Item12=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T;_DEBUG
-Item13=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T
-Item14=WIN32;_WINDOWS;NDEBUG;_MBCS;_LIB;COMPILED_FROM_DSP;XML_UNICODE_WCHAR_T;XML_UNICODE
-
-[HistoryLists\hlIntOutputDir]
-Count=6
-Item0=Release\obj\libexpatw_static
-Item1=Release\obj\libexpat_static
-Item2=Release\obj\mts
-Item3=Release\obj\mt
-Item4=..\lib\Release-w_static
-Item5=Release-w_static
-
-[HistoryLists\hlFinalOutputDir]
-Count=3
-Item0=Release\
-Item1=Release
-Item2=Release-w_static\
-
-[HistoryLists\hlTlibPageSize]
-Count=1
-Item0=0x0010
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/expatw_static.mak b/3rdparty/expat/bcb5/expatw_static.mak
deleted file mode 100644
index 16b7e5b90ec..00000000000
--- a/3rdparty/expat/bcb5/expatw_static.mak
+++ /dev/null
@@ -1,190 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\libexpatws_mtd.lib
-OBJFILES = Release\obj\libexpatw_static\xmlparse.obj \
- Release\obj\libexpatw_static\xmlrole.obj \
- Release\obj\libexpatw_static\xmltok.obj
-RESFILES =
-MAINSOURCE = expatw_static.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES =
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES =
-SPARELIBS =
-DEFFILE =
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\lib
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-LINKER = TLib
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = _WINDOWS;WIN32;NDEBUG;_LIB;COMPILED_FROM_DSP;XML_STATIC;XML_UNICODE_WCHAR_T
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\lib;$(BCB)\include
-LIBPATH = ..\lib;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS = -w-rch -w-par -w-8027 -w-8026 -w-ccc
-LISTFILE =
-# ---------------------------------------------------------------------------
-CFLAG1 = -O2 -X- -a8 -b -k- -vi -q -tWM -c
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\libexpatw_static -N0Release\obj\libexpatw_static -$Y- -$L- \
- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS =
-# ---------------------------------------------------------------------------
-ALLOBJ = $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES)
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = TLib
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-!if "$(LISTFILE)" == ""
-COMMA =
-!else
-COMMA = ,
-!endif
-
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) /u $@ @&&!
- $(LFLAGS) $? $(COMMA) $(LISTFILE)
-
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/bcb5/libexpat_mtd.def b/3rdparty/expat/bcb5/libexpat_mtd.def
deleted file mode 100644
index fc1cb9554fa..00000000000
--- a/3rdparty/expat/bcb5/libexpat_mtd.def
+++ /dev/null
@@ -1,141 +0,0 @@
-; DEF file for BCB5
-LIBRARY LIBEXPAT_MTD
-DESCRIPTION "Implements an XML parser."
-EXPORTS
- _XML_DefaultCurrent @1
- _XML_ErrorString @2
- _XML_ExpatVersion @3
- _XML_ExpatVersionInfo @4
- _XML_ExternalEntityParserCreate @5
- _XML_GetBase @6
- _XML_GetBuffer @7
- _XML_GetCurrentByteCount @8
- _XML_GetCurrentByteIndex @9
- _XML_GetCurrentColumnNumber @10
- _XML_GetCurrentLineNumber @11
- _XML_GetErrorCode @12
- _XML_GetIdAttributeIndex @13
- _XML_GetInputContext @14
- _XML_GetSpecifiedAttributeCount @15
- _XML_Parse @16
- _XML_ParseBuffer @17
- _XML_ParserCreate @18
- _XML_ParserCreateNS @19
- _XML_ParserCreate_MM @20
- _XML_ParserFree @21
- _XML_SetAttlistDeclHandler @22
- _XML_SetBase @23
- _XML_SetCdataSectionHandler @24
- _XML_SetCharacterDataHandler @25
- _XML_SetCommentHandler @26
- _XML_SetDefaultHandler @27
- _XML_SetDefaultHandlerExpand @28
- _XML_SetDoctypeDeclHandler @29
- _XML_SetElementDeclHandler @30
- _XML_SetElementHandler @31
- _XML_SetEncoding @32
- _XML_SetEndCdataSectionHandler @33
- _XML_SetEndDoctypeDeclHandler @34
- _XML_SetEndElementHandler @35
- _XML_SetEndNamespaceDeclHandler @36
- _XML_SetEntityDeclHandler @37
- _XML_SetExternalEntityRefHandler @38
- _XML_SetExternalEntityRefHandlerArg @39
- _XML_SetNamespaceDeclHandler @40
- _XML_SetNotStandaloneHandler @41
- _XML_SetNotationDeclHandler @42
- _XML_SetParamEntityParsing @43
- _XML_SetProcessingInstructionHandler @44
- _XML_SetReturnNSTriplet @45
- _XML_SetStartCdataSectionHandler @46
- _XML_SetStartDoctypeDeclHandler @47
- _XML_SetStartElementHandler @48
- _XML_SetStartNamespaceDeclHandler @49
- _XML_SetUnknownEncodingHandler @50
- _XML_SetUnparsedEntityDeclHandler @51
- _XML_SetUserData @52
- _XML_SetXmlDeclHandler @53
- _XML_UseParserAsHandlerArg @54
-; added with version 1.95.3
- _XML_ParserReset @55
- _XML_SetSkippedEntityHandler @56
-; added with version 1.95.5
- _XML_GetFeatureList @57
- _XML_UseForeignDTD @58
-; added with version 1.95.6
- _XML_FreeContentModel @59
- _XML_MemMalloc @60
- _XML_MemRealloc @61
- _XML_MemFree @62
-; added with version 1.95.8
- _XML_StopParser @63
- _XML_ResumeParser @64
- _XML_GetParsingStatus @65
-
-; Aliases for MS compatible names
- XML_DefaultCurrent = _XML_DefaultCurrent
- XML_ErrorString = _XML_ErrorString
- XML_ExpatVersion = _XML_ExpatVersion
- XML_ExpatVersionInfo = _XML_ExpatVersionInfo
- XML_ExternalEntityParserCreate = _XML_ExternalEntityParserCreate
- XML_GetBase = _XML_GetBase
- XML_GetBuffer = _XML_GetBuffer
- XML_GetCurrentByteCount = _XML_GetCurrentByteCount
- XML_GetCurrentByteIndex = _XML_GetCurrentByteIndex
- XML_GetCurrentColumnNumber = _XML_GetCurrentColumnNumber
- XML_GetCurrentLineNumber = _XML_GetCurrentLineNumber
- XML_GetErrorCode = _XML_GetErrorCode
- XML_GetIdAttributeIndex = _XML_GetIdAttributeIndex
- XML_GetInputContext = _XML_GetInputContext
- XML_GetSpecifiedAttributeCount = _XML_GetSpecifiedAttributeCount
- XML_Parse = _XML_Parse
- XML_ParseBuffer = _XML_ParseBuffer
- XML_ParserCreate = _XML_ParserCreate
- XML_ParserCreateNS = _XML_ParserCreateNS
- XML_ParserCreate_MM = _XML_ParserCreate_MM
- XML_ParserFree = _XML_ParserFree
- XML_SetAttlistDeclHandler = _XML_SetAttlistDeclHandler
- XML_SetBase = _XML_SetBase
- XML_SetCdataSectionHandler = _XML_SetCdataSectionHandler
- XML_SetCharacterDataHandler = _XML_SetCharacterDataHandler
- XML_SetCommentHandler = _XML_SetCommentHandler
- XML_SetDefaultHandler = _XML_SetDefaultHandler
- XML_SetDefaultHandlerExpand = _XML_SetDefaultHandlerExpand
- XML_SetDoctypeDeclHandler = _XML_SetDoctypeDeclHandler
- XML_SetElementDeclHandler = _XML_SetElementDeclHandler
- XML_SetElementHandler = _XML_SetElementHandler
- XML_SetEncoding = _XML_SetEncoding
- XML_SetEndCdataSectionHandler = _XML_SetEndCdataSectionHandler
- XML_SetEndDoctypeDeclHandler = _XML_SetEndDoctypeDeclHandler
- XML_SetEndElementHandler = _XML_SetEndElementHandler
- XML_SetEndNamespaceDeclHandler = _XML_SetEndNamespaceDeclHandler
- XML_SetEntityDeclHandler = _XML_SetEntityDeclHandler
- XML_SetExternalEntityRefHandler = _XML_SetExternalEntityRefHandler
- XML_SetExternalEntityRefHandlerArg = _XML_SetExternalEntityRefHandlerArg
- XML_SetNamespaceDeclHandler = _XML_SetNamespaceDeclHandler
- XML_SetNotStandaloneHandler = _XML_SetNotStandaloneHandler
- XML_SetNotationDeclHandler = _XML_SetNotationDeclHandler
- XML_SetParamEntityParsing = _XML_SetParamEntityParsing
- XML_SetProcessingInstructionHandler = _XML_SetProcessingInstructionHandler
- XML_SetReturnNSTriplet = _XML_SetReturnNSTriplet
- XML_SetStartCdataSectionHandler = _XML_SetStartCdataSectionHandler
- XML_SetStartDoctypeDeclHandler = _XML_SetStartDoctypeDeclHandler
- XML_SetStartElementHandler = _XML_SetStartElementHandler
- XML_SetStartNamespaceDeclHandler = _XML_SetStartNamespaceDeclHandler
- XML_SetUnknownEncodingHandler = _XML_SetUnknownEncodingHandler
- XML_SetUnparsedEntityDeclHandler = _XML_SetUnparsedEntityDeclHandler
- XML_SetUserData = _XML_SetUserData
- XML_SetXmlDeclHandler = _XML_SetXmlDeclHandler
- XML_UseParserAsHandlerArg = _XML_UseParserAsHandlerArg
- XML_ParserReset = _XML_ParserReset
- XML_SetSkippedEntityHandler = _XML_SetSkippedEntityHandler
- XML_GetFeatureList = _XML_GetFeatureList
- XML_UseForeignDTD = _XML_UseForeignDTD
- XML_FreeContentModel = _XML_FreeContentModel
- XML_MemMalloc = _XML_MemMalloc
- XML_MemRealloc = _XML_MemRealloc
- XML_MemFree = _XML_MemFree
- XML_StopParser = _XML_StopParser
- XML_ResumeParser = _XML_ResumeParser
- XML_GetParsingStatus = _XML_GetParsingStatus
-
diff --git a/3rdparty/expat/bcb5/libexpatw_mtd.def b/3rdparty/expat/bcb5/libexpatw_mtd.def
deleted file mode 100644
index 418462df5a4..00000000000
--- a/3rdparty/expat/bcb5/libexpatw_mtd.def
+++ /dev/null
@@ -1,140 +0,0 @@
-; DEF file for BCB5
-LIBRARY LIBEXPATW_MTD
-DESCRIPTION "Implements an XML parser."
-EXPORTS
- _XML_DefaultCurrent @1
- _XML_ErrorString @2
- _XML_ExpatVersion @3
- _XML_ExpatVersionInfo @4
- _XML_ExternalEntityParserCreate @5
- _XML_GetBase @6
- _XML_GetBuffer @7
- _XML_GetCurrentByteCount @8
- _XML_GetCurrentByteIndex @9
- _XML_GetCurrentColumnNumber @10
- _XML_GetCurrentLineNumber @11
- _XML_GetErrorCode @12
- _XML_GetIdAttributeIndex @13
- _XML_GetInputContext @14
- _XML_GetSpecifiedAttributeCount @15
- _XML_Parse @16
- _XML_ParseBuffer @17
- _XML_ParserCreate @18
- _XML_ParserCreateNS @19
- _XML_ParserCreate_MM @20
- _XML_ParserFree @21
- _XML_SetAttlistDeclHandler @22
- _XML_SetBase @23
- _XML_SetCdataSectionHandler @24
- _XML_SetCharacterDataHandler @25
- _XML_SetCommentHandler @26
- _XML_SetDefaultHandler @27
- _XML_SetDefaultHandlerExpand @28
- _XML_SetDoctypeDeclHandler @29
- _XML_SetElementDeclHandler @30
- _XML_SetElementHandler @31
- _XML_SetEncoding @32
- _XML_SetEndCdataSectionHandler @33
- _XML_SetEndDoctypeDeclHandler @34
- _XML_SetEndElementHandler @35
- _XML_SetEndNamespaceDeclHandler @36
- _XML_SetEntityDeclHandler @37
- _XML_SetExternalEntityRefHandler @38
- _XML_SetExternalEntityRefHandlerArg @39
- _XML_SetNamespaceDeclHandler @40
- _XML_SetNotStandaloneHandler @41
- _XML_SetNotationDeclHandler @42
- _XML_SetParamEntityParsing @43
- _XML_SetProcessingInstructionHandler @44
- _XML_SetReturnNSTriplet @45
- _XML_SetStartCdataSectionHandler @46
- _XML_SetStartDoctypeDeclHandler @47
- _XML_SetStartElementHandler @48
- _XML_SetStartNamespaceDeclHandler @49
- _XML_SetUnknownEncodingHandler @50
- _XML_SetUnparsedEntityDeclHandler @51
- _XML_SetUserData @52
- _XML_SetXmlDeclHandler @53
- _XML_UseParserAsHandlerArg @54
-; added with version 1.95.3
- _XML_ParserReset @55
- _XML_SetSkippedEntityHandler @56
-; added with version 1.95.5
- _XML_GetFeatureList @57
- _XML_UseForeignDTD @58
-; added with version 1.95.6
- _XML_FreeContentModel @59
- _XML_MemMalloc @60
- _XML_MemRealloc @61
- _XML_MemFree @62
-; added with version 1.95.8
- _XML_StopParser @63
- _XML_ResumeParser @64
- _XML_GetParsingStatus @65
-
-; Aliases for MS compatible names
- XML_DefaultCurrent = _XML_DefaultCurrent
- XML_ErrorString = _XML_ErrorString
- XML_ExpatVersion = _XML_ExpatVersion
- XML_ExpatVersionInfo = _XML_ExpatVersionInfo
- XML_ExternalEntityParserCreate = _XML_ExternalEntityParserCreate
- XML_GetBase = _XML_GetBase
- XML_GetBuffer = _XML_GetBuffer
- XML_GetCurrentByteCount = _XML_GetCurrentByteCount
- XML_GetCurrentByteIndex = _XML_GetCurrentByteIndex
- XML_GetCurrentColumnNumber = _XML_GetCurrentColumnNumber
- XML_GetCurrentLineNumber = _XML_GetCurrentLineNumber
- XML_GetErrorCode = _XML_GetErrorCode
- XML_GetIdAttributeIndex = _XML_GetIdAttributeIndex
- XML_GetInputContext = _XML_GetInputContext
- XML_GetSpecifiedAttributeCount = _XML_GetSpecifiedAttributeCount
- XML_Parse = _XML_Parse
- XML_ParseBuffer = _XML_ParseBuffer
- XML_ParserCreate = _XML_ParserCreate
- XML_ParserCreateNS = _XML_ParserCreateNS
- XML_ParserCreate_MM = _XML_ParserCreate_MM
- XML_ParserFree = _XML_ParserFree
- XML_SetAttlistDeclHandler = _XML_SetAttlistDeclHandler
- XML_SetBase = _XML_SetBase
- XML_SetCdataSectionHandler = _XML_SetCdataSectionHandler
- XML_SetCharacterDataHandler = _XML_SetCharacterDataHandler
- XML_SetCommentHandler = _XML_SetCommentHandler
- XML_SetDefaultHandler = _XML_SetDefaultHandler
- XML_SetDefaultHandlerExpand = _XML_SetDefaultHandlerExpand
- XML_SetDoctypeDeclHandler = _XML_SetDoctypeDeclHandler
- XML_SetElementDeclHandler = _XML_SetElementDeclHandler
- XML_SetElementHandler = _XML_SetElementHandler
- XML_SetEncoding = _XML_SetEncoding
- XML_SetEndCdataSectionHandler = _XML_SetEndCdataSectionHandler
- XML_SetEndDoctypeDeclHandler = _XML_SetEndDoctypeDeclHandler
- XML_SetEndElementHandler = _XML_SetEndElementHandler
- XML_SetEndNamespaceDeclHandler = _XML_SetEndNamespaceDeclHandler
- XML_SetEntityDeclHandler = _XML_SetEntityDeclHandler
- XML_SetExternalEntityRefHandler = _XML_SetExternalEntityRefHandler
- XML_SetExternalEntityRefHandlerArg = _XML_SetExternalEntityRefHandlerArg
- XML_SetNamespaceDeclHandler = _XML_SetNamespaceDeclHandler
- XML_SetNotStandaloneHandler = _XML_SetNotStandaloneHandler
- XML_SetNotationDeclHandler = _XML_SetNotationDeclHandler
- XML_SetParamEntityParsing = _XML_SetParamEntityParsing
- XML_SetProcessingInstructionHandler = _XML_SetProcessingInstructionHandler
- XML_SetReturnNSTriplet = _XML_SetReturnNSTriplet
- XML_SetStartCdataSectionHandler = _XML_SetStartCdataSectionHandler
- XML_SetStartDoctypeDeclHandler = _XML_SetStartDoctypeDeclHandler
- XML_SetStartElementHandler = _XML_SetStartElementHandler
- XML_SetStartNamespaceDeclHandler = _XML_SetStartNamespaceDeclHandler
- XML_SetUnknownEncodingHandler = _XML_SetUnknownEncodingHandler
- XML_SetUnparsedEntityDeclHandler = _XML_SetUnparsedEntityDeclHandler
- XML_SetUserData = _XML_SetUserData
- XML_SetXmlDeclHandler = _XML_SetXmlDeclHandler
- XML_UseParserAsHandlerArg = _XML_UseParserAsHandlerArg
- XML_ParserReset = _XML_ParserReset
- XML_SetSkippedEntityHandler = _XML_SetSkippedEntityHandler
- XML_GetFeatureList = _XML_GetFeatureList
- XML_UseForeignDTD = _XML_UseForeignDTD
- XML_FreeContentModel = _XML_FreeContentModel
- XML_MemMalloc = _XML_MemMalloc
- XML_MemRealloc = _XML_MemRealloc
- XML_MemFree = _XML_MemFree
- XML_StopParser = _XML_StopParser
- XML_ResumeParser = _XML_ResumeParser
- XML_GetParsingStatus = _XML_GetParsingStatus
diff --git a/3rdparty/expat/bcb5/makefile.mak b/3rdparty/expat/bcb5/makefile.mak
deleted file mode 100644
index 548815eafe7..00000000000
--- a/3rdparty/expat/bcb5/makefile.mak
+++ /dev/null
@@ -1,37 +0,0 @@
-all: setup expat expatw expat_static expatw_static elements outline xmlwf
-
-setup:
- setup
-
-expat:
- make -l -fexpat.mak
-
-expatw:
- make -l -fexpatw.mak
-
-expat_static:
- make -l -fexpat_static.mak
-
-expatw_static:
- make -l -fexpatw_static.mak
-
-elements:
- make -l -felements.mak
-
-outline:
- make -l -foutline.mak
-
-xmlwf:
- make -l -fxmlwf.mak
-
-clean:
-# works on Win98/ME
-# deltree /y release\obj
-# works on WinNT/2000
- del /s/f/q release\obj
-
-distclean:
-# works on Win98/ME
-# deltree /y release\*.*
-# works on WinNT/2000
- del /s/f/q release\*
diff --git a/3rdparty/expat/bcb5/outline.bpf b/3rdparty/expat/bcb5/outline.bpf
deleted file mode 100644
index 52dce830163..00000000000
--- a/3rdparty/expat/bcb5/outline.bpf
+++ /dev/null
@@ -1,4 +0,0 @@
-USEUNIT("..\examples\outline.c");
-USELIB("Release\libexpat_mtd.lib");
-//---------------------------------------------------------------------------
-main
diff --git a/3rdparty/expat/bcb5/outline.bpr b/3rdparty/expat/bcb5/outline.bpr
deleted file mode 100644
index 9ad8bed2736..00000000000
--- a/3rdparty/expat/bcb5/outline.bpr
+++ /dev/null
@@ -1,132 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\outline.exe"/>
- <OBJFILES value="Release\obj\examples\outline.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value=""/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value="Release\libexpat_mtd.lib"/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value="VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi"/>
- <PATHCPP value=".;..\examples"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="ilink32"/>
- <USERDEFINES value="WIN32;NDEBUG;_CONSOLE"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="outline.bpf"/>
- <INCLUDEPATH value="..\examples;$(BCB)\include"/>
- <LIBPATH value="..\examples;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-par -w-8027 -w-8026"/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-O2 -X- -a8 -b -k- -vi -q -tWM -I..\lib -c"/>
- <PFLAGS value="-N2Release\obj\examples -N0Release\obj\examples -$Y- -$L- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value="-IRelease\obj\examples -D&quot;&quot; -ap -Tpe -x -Gn -q"/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="c0x32.obj $(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=3
-Item0=..\examples;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=4
-Item0=..\examples;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\examples;$(BCB)\lib;..\examples\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=6
-Item0=WIN32;NDEBUG;_CONSOLE
-Item1=WIN32;NDEBUG;_CONSOLE;XML_STATIC
-Item2=WIN32;NDEBUG;_CONSOLE;_DEBUG;XML_STATIC
-Item3=WIN32;NDEBUG;_CONSOLE;_DEBUG;XML_UNICODE_WCHAR_T;_UNICODE;XML_STATIC
-Item4=WIN32;NDEBUG;_CONSOLE;_DEBUG;XML_UNICODE_WCHAR_T;_UNICODE
-Item5=WIN32;NDEBUG;_CONSOLE;_DEBUG
-
-[HistoryLists\hlIntOutputDir]
-Count=4
-Item0=Release\obj\examples
-Item1=Release\obj\outline
-Item2=..\examples\Release
-Item3=Release
-
-[HistoryLists\hlFinalOutputDir]
-Count=1
-Item0=Release\
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/outline.mak b/3rdparty/expat/bcb5/outline.mak
deleted file mode 100644
index 510b541f647..00000000000
--- a/3rdparty/expat/bcb5/outline.mak
+++ /dev/null
@@ -1,186 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\outline.exe
-OBJFILES = Release\obj\examples\outline.obj
-RESFILES =
-MAINSOURCE = outline.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES = Release\libexpat_mtd.lib
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES = VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi \
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi \
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi \
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi
-SPARELIBS =
-DEFFILE =
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\examples
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = WIN32;NDEBUG;_CONSOLE
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\examples;$(BCB)\include
-LIBPATH = ..\examples;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS= -w-par -w-8027 -w-8026
-# ---------------------------------------------------------------------------
-CFLAG1 = -O2 -X- -a8 -b -k- -vi -q -tWM -I..\lib -c
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\examples -N0Release\obj\examples -$Y- -$L- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS = -IRelease\obj\examples -D"" -ap -Tpe -x -Gn -q
-# ---------------------------------------------------------------------------
-ALLOBJ = c0x32.obj $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = ilink32
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) @&&!
- $(LFLAGS) -L$(LIBPATH) +
- $(ALLOBJ), +
- $(PROJECT),, +
- $(ALLLIB), +
- $(DEFFILE), +
- $(ALLRES)
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/bcb5/setup.bat b/3rdparty/expat/bcb5/setup.bat
deleted file mode 100644
index 6f4b573179e..00000000000
--- a/3rdparty/expat/bcb5/setup.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-REM CommandInterpreter: $(COMSPEC)
-if not exist .\release\nul mkdir release
-if not exist .\release\obj\nul mkdir release\obj
-if not exist .\release\obj\libexpat\nul mkdir release\obj\libexpat
-if not exist .\release\obj\libexpatw\nul mkdir release\obj\libexpatw
-if not exist .\release\obj\libexpat_static\nul mkdir release\obj\libexpat_static
-if not exist .\release\obj\libexpatw_static\nul mkdir release\obj\libexpatw_static
-if not exist .\release\obj\examples\nul mkdir release\obj\examples
-if not exist .\release\obj\xmlwf\nul mkdir release\obj\xmlwf
diff --git a/3rdparty/expat/bcb5/xmlwf.bpf b/3rdparty/expat/bcb5/xmlwf.bpf
deleted file mode 100644
index d06208e811b..00000000000
--- a/3rdparty/expat/bcb5/xmlwf.bpf
+++ /dev/null
@@ -1,7 +0,0 @@
-USEUNIT("..\xmlwf\codepage.c");
-USEUNIT("..\xmlwf\win32filemap.c");
-USEUNIT("..\xmlwf\xmlfile.c");
-USEUNIT("..\xmlwf\xmlwf.c");
-USELIB("Release\libexpat_mtd.lib");
-//---------------------------------------------------------------------------
-main
diff --git a/3rdparty/expat/bcb5/xmlwf.bpr b/3rdparty/expat/bcb5/xmlwf.bpr
deleted file mode 100644
index bc765863d86..00000000000
--- a/3rdparty/expat/bcb5/xmlwf.bpr
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version='1.0' encoding='utf-8' ?>
-<!-- C++Builder XML Project -->
-<PROJECT>
- <MACROS>
- <VERSION value="BCB.05.03"/>
- <PROJECT value="Release\xmlwf.exe"/>
- <OBJFILES value="Release\obj\xmlwf\codepage.obj Release\obj\xmlwf\win32filemap.obj
- Release\obj\xmlwf\xmlfile.obj Release\obj\xmlwf\xmlwf.obj"/>
- <RESFILES value=""/>
- <IDLFILES value=""/>
- <IDLGENFILES value=""/>
- <DEFFILE value=""/>
- <RESDEPEN value="$(RESFILES)"/>
- <LIBFILES value="Release\libexpat_mtd.lib"/>
- <LIBRARIES value=""/>
- <SPARELIBS value=""/>
- <PACKAGES value="VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi"/>
- <PATHCPP value=".;..\xmlwf"/>
- <PATHPAS value=".;"/>
- <PATHRC value=".;"/>
- <PATHASM value=".;"/>
- <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
- <RELEASELIBPATH value="$(BCB)\lib\release"/>
- <LINKER value="ilink32"/>
- <USERDEFINES value="NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP"/>
- <SYSDEFINES value="_NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL"/>
- <MAINSOURCE value="xmlwf.bpf"/>
- <INCLUDEPATH value="..\xmlwf;$(BCB)\include"/>
- <LIBPATH value="..\xmlwf;$(BCB)\lib;$(RELEASELIBPATH)"/>
- <WARNINGS value="-w-8065 -w-par -w-8027 -w-8026"/>
- </MACROS>
- <OPTIONS>
- <IDLCFLAGS value="-I$(BCB)\include"/>
- <CFLAG1 value="-O2 -X- -a8 -b -k- -vi -q -tWM -I..\lib -c"/>
- <PFLAGS value="-N2Release\obj\xmlwf -N0Release\obj\xmlwf -$Y- -$L- -$D-"/>
- <RFLAGS value="/l 0x409 /d &quot;NDEBUG&quot; /i$(BCB)\include"/>
- <AFLAGS value="/mx /w2 /zn"/>
- <LFLAGS value="-IRelease\obj\xmlwf -D&quot;&quot; -ap -Tpe -x -Gn -q"/>
- </OPTIONS>
- <LINKER>
- <ALLOBJ value="c0x32.obj $(OBJFILES)"/>
- <ALLRES value="$(RESFILES)"/>
- <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib"/>
- </LINKER>
- <IDEOPTIONS>
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-Locale=1033
-CodePage=1252
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[HistoryLists\hlIncludePath]
-Count=4
-Item0=..\xmlwf;$(BCB)\include
-Item1=$(BCB)\include
-Item2=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl
-Item3=$(BCB)\include;$(BCB)\include\mfc;$(BCB)\include\atl;
-
-[HistoryLists\hlLibraryPath]
-Count=5
-Item0=..\xmlwf;$(BCB)\lib;$(RELEASELIBPATH)
-Item1=..\xmlwf;$(BCB)\lib;..\xmlwf\$(RELEASELIBPATH)
-Item2=$(BCB)\lib;$(RELEASELIBPATH)
-Item3=$(BCB)\lib;$(RELEASELIBPATH);$(BCB)\lib\psdk
-Item4=$(BCB)\lib;$(RELEASELIBPATH);;$(BCB)\lib\psdk;
-
-[HistoryLists\hlDebugSourcePath]
-Count=1
-Item0=$(BCB)\source\vcl
-
-[HistoryLists\hlConditionals]
-Count=6
-Item0=NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP
-Item1=NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP;_DEBUG;XML_UNICODE_WCHAR_T;_UNICODE
-Item2=NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP;_DEBUG;XML_UNICODE_WCHAR_T
-Item3=NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP;_DEBUG
-Item4=NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP;_DEBUG;_UNICODE;XML_UNICODE_WCHAR_T
-Item5=NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP;_DEBUG;_UNICODE
-
-[HistoryLists\hlIntOutputDir]
-Count=3
-Item0=Release\obj\xmlwf
-Item1=..\xmlwf\Release
-Item2=Release
-
-[HistoryLists\hlFinalOutputDir]
-Count=3
-Item0=Release\
-Item1=Release
-Item2=.\Release\
-
-[Debugging]
-DebugSourceDirs=
-
-[Parameters]
-RunParams=sample.xml
-HostApplication=
-RemoteHost=
-RemotePath=
-RemoteDebug=0
-
-[Compiler]
-ShowInfoMsgs=0
-LinkDebugVcl=0
-LinkCGLIB=0
-
-[Language]
-ActiveLang=
-ProjectLang=
-RootDir=
- </IDEOPTIONS>
-</PROJECT>@
diff --git a/3rdparty/expat/bcb5/xmlwf.mak b/3rdparty/expat/bcb5/xmlwf.mak
deleted file mode 100644
index f74126e454a..00000000000
--- a/3rdparty/expat/bcb5/xmlwf.mak
+++ /dev/null
@@ -1,187 +0,0 @@
-# ---------------------------------------------------------------------------
-!if !$d(BCB)
-BCB = $(MAKEDIR)\..
-!endif
-
-# ---------------------------------------------------------------------------
-# IDE SECTION
-# ---------------------------------------------------------------------------
-# The following section of the project makefile is managed by the BCB IDE.
-# It is recommended to use the IDE to change any of the values in this
-# section.
-# ---------------------------------------------------------------------------
-
-VERSION = BCB.05.03
-# ---------------------------------------------------------------------------
-PROJECT = Release\xmlwf.exe
-OBJFILES = Release\obj\xmlwf\codepage.obj Release\obj\xmlwf\win32filemap.obj \
- Release\obj\xmlwf\xmlfile.obj Release\obj\xmlwf\xmlwf.obj
-RESFILES =
-MAINSOURCE = xmlwf.bpf
-RESDEPEN = $(RESFILES)
-LIBFILES = Release\libexpat_mtd.lib
-IDLFILES =
-IDLGENFILES =
-LIBRARIES =
-PACKAGES = VCL50.bpi VCLX50.bpi bcbsmp50.bpi QRPT50.bpi VCLDB50.bpi VCLBDE50.bpi \
- ibsmp50.bpi VCLDBX50.bpi TEEUI50.bpi TEEDB50.bpi TEE50.bpi TEEQR50.bpi \
- VCLIB50.bpi bcbie50.bpi VCLIE50.bpi INETDB50.bpi INET50.bpi NMFAST50.bpi \
- dclocx50.bpi bcb2kaxserver50.bpi dclusr50.bpi
-SPARELIBS =
-DEFFILE =
-# ---------------------------------------------------------------------------
-PATHCPP = .;..\xmlwf
-PATHASM = .;
-PATHPAS = .;
-PATHRC = .;
-DEBUGLIBPATH = $(BCB)\lib\debug
-RELEASELIBPATH = $(BCB)\lib\release
-USERDEFINES = NDEBUG;WIN32;_CONSOLE;COMPILED_FROM_DSP
-SYSDEFINES = _NO_VCL;_ASSERTE;NO_STRICT;_RTLDLL
-INCLUDEPATH = ..\xmlwf;$(BCB)\include
-LIBPATH = ..\xmlwf;$(BCB)\lib;$(RELEASELIBPATH)
-WARNINGS= -w-8065 -w-par -w-8027 -w-8026
-# ---------------------------------------------------------------------------
-CFLAG1 = -O2 -X- -a8 -b -k- -vi -q -tWM -I..\lib -c
-IDLCFLAGS = -I$(BCB)\include
-PFLAGS = -N2Release\obj\xmlwf -N0Release\obj\xmlwf -$Y- -$L- -$D-
-RFLAGS = /l 0x409 /d "NDEBUG" /i$(BCB)\include
-AFLAGS = /mx /w2 /zn
-LFLAGS = -IRelease\obj\xmlwf -D"" -ap -Tpe -x -Gn -q
-# ---------------------------------------------------------------------------
-ALLOBJ = c0x32.obj $(OBJFILES)
-ALLRES = $(RESFILES)
-ALLLIB = $(LIBFILES) $(LIBRARIES) import32.lib cw32mti.lib
-# ---------------------------------------------------------------------------
-!ifdef IDEOPTIONS
-
-[Version Info]
-IncludeVerInfo=0
-AutoIncBuild=0
-MajorVer=1
-MinorVer=0
-Release=0
-Build=0
-Debug=0
-PreRelease=0
-Special=0
-Private=0
-DLL=0
-
-[Version Info Keys]
-CompanyName=
-FileDescription=
-FileVersion=1.0.0.0
-InternalName=
-LegalCopyright=
-LegalTrademarks=
-OriginalFilename=
-ProductName=
-ProductVersion=1.0.0.0
-Comments=
-
-[Debugging]
-DebugSourceDirs=$(BCB)\source\vcl
-
-!endif
-
-
-
-
-
-# ---------------------------------------------------------------------------
-# MAKE SECTION
-# ---------------------------------------------------------------------------
-# This section of the project file is not used by the BCB IDE. It is for
-# the benefit of building from the command-line using the MAKE utility.
-# ---------------------------------------------------------------------------
-
-.autodepend
-# ---------------------------------------------------------------------------
-!if "$(USERDEFINES)" != ""
-AUSERDEFINES = -d$(USERDEFINES:;= -d)
-!else
-AUSERDEFINES =
-!endif
-
-!if !$d(BCC32)
-BCC32 = bcc32
-!endif
-
-!if !$d(CPP32)
-CPP32 = cpp32
-!endif
-
-!if !$d(DCC32)
-DCC32 = dcc32
-!endif
-
-!if !$d(TASM32)
-TASM32 = tasm32
-!endif
-
-!if !$d(LINKER)
-LINKER = ilink32
-!endif
-
-!if !$d(BRCC32)
-BRCC32 = brcc32
-!endif
-
-
-# ---------------------------------------------------------------------------
-!if $d(PATHCPP)
-.PATH.CPP = $(PATHCPP)
-.PATH.C = $(PATHCPP)
-!endif
-
-!if $d(PATHPAS)
-.PATH.PAS = $(PATHPAS)
-!endif
-
-!if $d(PATHASM)
-.PATH.ASM = $(PATHASM)
-!endif
-
-!if $d(PATHRC)
-.PATH.RC = $(PATHRC)
-!endif
-# ---------------------------------------------------------------------------
-$(PROJECT): $(IDLGENFILES) $(OBJFILES) $(RESDEPEN) $(DEFFILE)
- $(BCB)\BIN\$(LINKER) @&&!
- $(LFLAGS) -L$(LIBPATH) +
- $(ALLOBJ), +
- $(PROJECT),, +
- $(ALLLIB), +
- $(DEFFILE), +
- $(ALLRES)
-!
-# ---------------------------------------------------------------------------
-.pas.hpp:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.pas.obj:
- $(BCB)\BIN\$(DCC32) $(PFLAGS) -U$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -O$(INCLUDEPATH) --BCB {$< }
-
-.cpp.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.obj:
- $(BCB)\BIN\$(BCC32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n$(@D) {$< }
-
-.c.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.cpp.i:
- $(BCB)\BIN\$(CPP32) $(CFLAG1) $(WARNINGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -n. {$< }
-
-.asm.obj:
- $(BCB)\BIN\$(TASM32) $(AFLAGS) -i$(INCLUDEPATH:;= -i) $(AUSERDEFINES) -d$(SYSDEFINES:;= -d) $<, $@
-
-.rc.res:
- $(BCB)\BIN\$(BRCC32) $(RFLAGS) -I$(INCLUDEPATH) -D$(USERDEFINES);$(SYSDEFINES) -fo$@ $<
-# ---------------------------------------------------------------------------
-
-
-
-
diff --git a/3rdparty/expat/cmake/expat-config.cmake.in b/3rdparty/expat/cmake/expat-config.cmake.in
new file mode 100644
index 00000000000..a4da61e0104
--- /dev/null
+++ b/3rdparty/expat/cmake/expat-config.cmake.in
@@ -0,0 +1,75 @@
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2019 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+if(NOT _expat_config_included)
+ # Protect against multiple inclusion
+ set(_expat_config_included TRUE)
+
+
+include("${CMAKE_CURRENT_LIST_DIR}/expat.cmake")
+
+@PACKAGE_INIT@
+
+#
+# Supported components
+#
+macro(expat_register_component _NAME _AVAILABE)
+ set(expat_${_NAME}_FOUND ${_AVAILABE})
+endmacro()
+
+expat_register_component(attr_info @EXPAT_ATTR_INFO@)
+expat_register_component(dtd @EXPAT_DTD@)
+expat_register_component(large_size @EXPAT_LARGE_SIZE@)
+expat_register_component(min_size @EXPAT_MIN_SIZE@)
+expat_register_component(ns @EXPAT_NS@)
+
+if(@EXPAT_CONTEXT_BYTES@)
+ expat_register_component(context_bytes ON)
+else()
+ expat_register_component(context_bytes OFF)
+endif()
+
+if("@EXPAT_CHAR_TYPE@" STREQUAL "char")
+ expat_register_component(char ON)
+ expat_register_component(ushort OFF)
+ expat_register_component(wchar_t OFF)
+elseif("@EXPAT_CHAR_TYPE@" STREQUAL "ushort")
+ expat_register_component(char OFF)
+ expat_register_component(ushort ON)
+ expat_register_component(wchar_t OFF)
+elseif("@EXPAT_CHAR_TYPE@" STREQUAL "wchar_t")
+ expat_register_component(char OFF)
+ expat_register_component(ushort OFF)
+ expat_register_component(wchar_t ON)
+endif()
+
+check_required_components(expat)
+
+
+endif(NOT _expat_config_included)
diff --git a/3rdparty/expat/cmake/mingw-toolchain.cmake b/3rdparty/expat/cmake/mingw-toolchain.cmake
new file mode 100644
index 00000000000..31a238b05ca
--- /dev/null
+++ b/3rdparty/expat/cmake/mingw-toolchain.cmake
@@ -0,0 +1,36 @@
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2019 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+set(CMAKE_SYSTEM_NAME Windows)
+
+set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
+set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
+
+set(WIN32 ON)
+set(MINGW ON)
diff --git a/3rdparty/expat/configure b/3rdparty/expat/configure
index d1486076c26..947bc0ebcde 100755
--- a/3rdparty/expat/configure
+++ b/3rdparty/expat/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for expat 2.1.1.
+# Generated by GNU Autoconf 2.69 for expat 2.2.10.
#
# Report bugs to <expat-bugs@libexpat.org>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='expat'
PACKAGE_TARNAME='expat'
-PACKAGE_VERSION='2.1.1'
-PACKAGE_STRING='expat 2.1.1'
+PACKAGE_VERSION='2.2.10'
+PACKAGE_STRING='expat 2.2.10'
PACKAGE_BUGREPORT='expat-bugs@libexpat.org'
PACKAGE_URL=''
@@ -633,13 +633,33 @@ ac_includes_default="\
#endif"
ac_header_list=
-ac_subst_vars='LTLIBOBJS
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
LIBOBJS
+_EXPAT_OUTPUT_NAME
+AM_LDFLAGS
+AM_CXXFLAGS
+AM_CFLAGS
+AM_CPPFLAGS
+WITH_DOCBOOK_FALSE
+WITH_DOCBOOK_TRUE
+DOCBOOK_TO_MAN
FILEMAP
-INSTALL_DATA
-INSTALL_SCRIPT
-INSTALL_PROGRAM
+UNICODE_FALSE
+UNICODE_TRUE
+MINGW_FALSE
+MINGW_TRUE
+WITH_TESTS_FALSE
+WITH_TESTS_TRUE
+WITH_EXAMPLES_FALSE
+WITH_EXAMPLES_TRUE
+WITH_XMLWF_FALSE
+WITH_XMLWF_TRUE
CXXCPP
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
ac_ct_CXX
CXXFLAGS
CXX
@@ -647,18 +667,14 @@ LIBAGE
LIBREVISION
LIBCURRENT
CPP
+LT_SYS_LIBRARY_PATH
OTOOL64
OTOOL
LIPO
NMEDIT
DSYMUTIL
MANIFEST_TOOL
-AWK
RANLIB
-STRIP
-ac_ct_AR
-AR
-LN_S
NM
ac_ct_DUMPBIN
DUMPBIN
@@ -667,6 +683,20 @@ FGREP
EGREP
GREP
SED
+LIBTOOL
+OBJDUMP
+DLLTOOL
+AS
+LN_S
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__include
+DEPDIR
OBJEXT
EXEEXT
ac_ct_CC
@@ -674,10 +704,35 @@ CPPFLAGS
LDFLAGS
CFLAGS
CC
-LIBTOOL
-OBJDUMP
-DLLTOOL
-AS
+ac_ct_AR
+AR
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
host_os
host_vendor
host_cpu
@@ -705,6 +760,7 @@ infodir
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -723,17 +779,30 @@ PACKAGE_VERSION
PACKAGE_TARNAME
PACKAGE_NAME
PATH_SEPARATOR
-SHELL'
+SHELL
+am__quote'
ac_subst_files=''
ac_user_opts='
enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
enable_shared
enable_static
with_pic
enable_fast_install
+with_aix_soname
with_gnu_ld
with_sysroot
enable_libtool_lock
+with_xmlwf
+with_examples
+with_tests
+with_libbsd
+with_getrandom
+with_sys_getrandom
+enable_xml_attr_info
+enable_xml_context
+with_docbook
'
ac_precious_vars='build_alias
host_alias
@@ -743,11 +812,13 @@ CFLAGS
LDFLAGS
LIBS
CPPFLAGS
+LT_SYS_LIBRARY_PATH
CPP
CXX
CXXFLAGS
CCC
-CXXCPP'
+CXXCPP
+DOCBOOK_TO_MAN'
# Initialize some variables set by options.
@@ -786,6 +857,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1038,6 +1110,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1175,7 +1256,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1288,7 +1369,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures expat 2.1.1 to adapt to many kinds of systems.
+\`configure' configures expat 2.2.10 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1328,6 +1409,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -1345,6 +1427,11 @@ _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]
@@ -1353,7 +1440,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of expat 2.1.1:";;
+ short | recursive ) echo "Configuration of expat 2.2.10:";;
esac
cat <<\_ACEOF
@@ -1361,20 +1448,48 @@ 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]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
--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-xml-attr-info Enable retrieving the byte offsets for attribute
+ names and values [default=no]
+ --enable-xml-context [COUNT]
+ Retain context around the current parse point;
+ default is enabled and a size of 1024 bytes
+ --disable-xml-context Do not retain context around the current parse point
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
both]
+ --with-aix-soname=aix|svr4|both
+ shared library versioning (aka "SONAME") variant to
+ provide on AIX, [default=aix].
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
- --with-sysroot=DIR Search for dependent libraries within DIR
- (or the compiler's sysroot if not specified).
+ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the
+ compiler's sysroot if not specified).
+ --without-xmlwf do not build xmlwf
+ --without-examples do not build examples [default=included]
+ --without-tests do not build tests [default=included]
+ --with-libbsd utilize libbsd (for arc4random_buf)
+ --with-getrandom enforce the use of getrandom function in the system
+ [default=check]
+ --without-getrandom skip auto detect of getrandom [default=check]
+ --with-sys-getrandom enforce the use of syscall SYS_getrandom function in
+ the system [default=check]
+ --without-sys-getrandom skip auto detect of syscall SYS_getrandom
+ [default=check]
+ --with-docbook enforce XML to man page compilation [default=check]
+ --without-docbook skip XML to man page compilation [default=check]
Some influential environment variables:
CC C compiler command
@@ -1384,10 +1499,14 @@ Some influential environment variables:
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>
+ LT_SYS_LIBRARY_PATH
+ User-defined run-time library search path.
CPP C preprocessor
CXX C++ compiler command
CXXFLAGS C++ compiler flags
CXXCPP C++ preprocessor
+ DOCBOOK_TO_MAN
+ docbook2x-man command
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -1455,7 +1574,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-expat configure 2.1.1
+expat configure 2.2.10
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1999,7 +2118,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by expat $as_me 2.1.1, which was
+It was created by expat $as_me 2.2.10, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2383,19 +2502,6 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
-
-
-
-LIBCURRENT=7
-LIBREVISION=0
-LIBAGE=6
-
-ac_config_headers="$ac_config_headers expat_config.h"
-
-
-
-
-
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
@@ -2467,112 +2573,222 @@ IFS=$ac_save_IFS
case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-enable_win32_dll=yes
+am__api_version='1.16'
-case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
-set dummy ${ac_tool_prefix}as; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AS+:} false; then :
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# 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:${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 ${ac_cv_path_install+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$AS"; then
- ac_cv_prog_AS="$AS" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_AS="${ac_tool_prefix}as"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
+ # 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[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
done
IFS=$as_save_IFS
+rm -rf conftest.one conftest.two conftest.dir
+
fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL 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.
+ INSTALL=$ac_install_sh
+ fi
fi
-AS=$ac_cv_prog_AS
-if test -n "$AS"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
-$as_echo "$AS" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
+{ $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}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-fi
-if test -z "$ac_cv_prog_AS"; then
- ac_ct_AS=$AS
- # Extract the first word of "as", so it can be a program name with args.
-set dummy as; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_AS+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_AS"; then
- ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_AS="as"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # 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_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
fi
-fi
-ac_ct_AS=$ac_cv_prog_ac_ct_AS
-if test -n "$ac_ct_AS"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
-$as_echo "$ac_ct_AS" >&6; }
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ am_missing_run=
+ { $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
- if test "x$ac_ct_AS" = x; then
- AS="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $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
- AS=$ac_ct_AS
- fi
-else
- AS="$ac_cv_prog_AS"
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
fi
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+ # 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:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DLLTOOL+:} false; then :
+if ${ac_cv_prog_STRIP+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$DLLTOOL"; then
- ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
@@ -2581,7 +2797,7 @@ do
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
@@ -2591,10 +2807,10 @@ IFS=$as_save_IFS
fi
fi
-DLLTOOL=$ac_cv_prog_DLLTOOL
-if test -n "$DLLTOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
-$as_echo "$DLLTOOL" >&6; }
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
@@ -2602,17 +2818,17 @@ fi
fi
-if test -z "$ac_cv_prog_DLLTOOL"; then
- ac_ct_DLLTOOL=$DLLTOOL
- # Extract the first word of "dlltool", so it can be a program name with args.
-set dummy dlltool; ac_word=$2
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$ac_ct_DLLTOOL"; then
- ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
@@ -2621,7 +2837,7 @@ do
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ ac_cv_prog_ac_ct_STRIP="strip"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
@@ -2631,17 +2847,17 @@ IFS=$as_save_IFS
fi
fi
-ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
-if test -n "$ac_ct_DLLTOOL"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
-$as_echo "$ac_ct_DLLTOOL" >&6; }
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
- if test "x$ac_ct_DLLTOOL" = x; then
- DLLTOOL="false"
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
else
case $cross_compiling:$ac_tool_warned in
yes:)
@@ -2649,62 +2865,68 @@ yes:)
$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
- DLLTOOL=$ac_ct_DLLTOOL
+ STRIP=$ac_ct_STRIP
fi
else
- DLLTOOL="$ac_cv_prog_DLLTOOL"
+ STRIP="$ac_cv_prog_STRIP"
fi
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
-set dummy ${ac_tool_prefix}objdump; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OBJDUMP+:} false; then :
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $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 ${ac_cv_path_mkdir+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$OBJDUMP"; then
- ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
done
IFS=$as_save_IFS
fi
-fi
-OBJDUMP=$ac_cv_prog_OBJDUMP
-if test -n "$OBJDUMP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
-$as_echo "$OBJDUMP" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # 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.
+ MKDIR_P="$ac_install_sh -d"
+ fi
fi
-if test -z "$ac_cv_prog_OBJDUMP"; then
- ac_ct_OBJDUMP=$OBJDUMP
- # Extract the first word of "objdump", so it can be a program name with args.
-set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+if ${ac_cv_prog_AWK+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$ac_ct_OBJDUMP"; then
- ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
@@ -2713,7 +2935,7 @@ do
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ ac_cv_prog_AWK="$ac_prog"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
@@ -2723,145 +2945,316 @@ IFS=$as_save_IFS
fi
fi
-ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
-if test -n "$ac_ct_OBJDUMP"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
-$as_echo "$ac_ct_OBJDUMP" >&6; }
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
- if test "x$ac_ct_OBJDUMP" = x; then
- OBJDUMP="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $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 ;;
+
+ test -n "$AWK" && break
+done
+
+{ $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 eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
esac
- OBJDUMP=$ac_ct_OBJDUMP
- fi
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
else
- OBJDUMP="$ac_cv_prog_OBJDUMP"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
fi
- ;;
-esac
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
-test -z "$AS" && AS=as
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
-test -z "$DLLTOOL" && DLLTOOL=dlltool
+# Define the identity of the package.
+ PACKAGE='expat'
+ VERSION='2.2.10'
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
-test -z "$OBJDUMP" && OBJDUMP=objdump
+# Some tools Automake needs.
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
-case `pwd` in
- *\ * | *\ *)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
-esac
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
-macro_version='2.4.2'
-macro_revision='1.3337'
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar pax cpio none'
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
-ltmain="$ac_aux_dir/ltmain.sh"
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
-# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+END
+ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+ fi
+fi
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
-$as_echo_n "checking how to print strings... " >&6; }
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
- test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
- ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
- ECHO='printf %s\n'
-else
- # Use this function as a fallback that always works.
- func_fallback_echo ()
- {
- eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
- }
- ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
- $ECHO ""
-}
-
-case "$ECHO" in
- printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
-$as_echo "printf" >&6; } ;;
- print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
-$as_echo "print -r" >&6; } ;;
- *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
-$as_echo "cat" >&6; } ;;
-esac
+LIBCURRENT=7 # sync
+LIBREVISION=12 # with
+LIBAGE=6 # CMakeLists.txt!
+if ${AM_CPPFLAGS+:} false; then :
+ case " $AM_CPPFLAGS " in #(
+ *" -DHAVE_EXPAT_CONFIG_H "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CPPFLAGS already contains -DHAVE_EXPAT_CONFIG_H"; } >&5
+ (: AM_CPPFLAGS already contains -DHAVE_EXPAT_CONFIG_H) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+ as_fn_append AM_CPPFLAGS " -DHAVE_EXPAT_CONFIG_H"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CPPFLAGS=\"\$AM_CPPFLAGS\""; } >&5
+ (: AM_CPPFLAGS="$AM_CPPFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+else
+ AM_CPPFLAGS=-DHAVE_EXPAT_CONFIG_H
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CPPFLAGS=\"\$AM_CPPFLAGS\""; } >&5
+ (: AM_CPPFLAGS="$AM_CPPFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+fi
+ac_config_headers="$ac_config_headers expat_config.h"
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
+$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; }
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5
+ (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ case $?:`cat confinc.out 2>/dev/null` in #(
+ '0:this is the am__doit target') :
+ case $s in #(
+ BSD) :
+ am__include='.include' am__quote='"' ;; #(
+ *) :
+ am__include='include' am__quote='' ;;
+esac ;; #(
+ *) :
+ ;;
+esac
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
+$as_echo "${_am_result}" >&6; }
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
ac_ext=c
@@ -3653,6 +4046,504 @@ 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
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $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 "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar lib "link -lib"
+ 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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar lib "link -lib"
+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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+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:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $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
+ fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ am_cv_ar_interface=ar
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+ (eval $am_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=ar
+ else
+ am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+ (eval $am_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=lib
+ else
+ am_cv_ar_interface=unknown
+ fi
+ fi
+ rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+ ;;
+lib)
+ # Microsoft lib, so override with the ar-lib wrapper script.
+ # FIXME: It is wrong to rewrite AR.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__AR in this case,
+ # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+ # similar.
+ AR="$am_aux_dir/ar-lib $AR"
+ ;;
+unknown)
+ as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+ ;;
+esac
+
+
+{ $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:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $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:${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 eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.6'
+macro_revision='2.4.6'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case $ECHO in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{ $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 ${ac_cv_path_SED+:} false; then :
@@ -3954,19 +4845,19 @@ test -z "$GREP" && GREP=grep
# Check whether --with-gnu-ld was given.
if test "${with_gnu_ld+set}" = set; then :
- withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+ withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
else
with_gnu_ld=no
fi
ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
# Check if gcc -print-prog-name=ld gives a path.
{ $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*)
- # gcc leaves a trailing carriage return which upsets mingw
+ # gcc leaves a trailing carriage return, which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -3980,7 +4871,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
done
- test -z "$LD" && LD="$ac_prog"
+ test -z "$LD" && LD=$ac_prog
;;
"")
# If it fails, then pretend we aren't using GCC.
@@ -3991,7 +4882,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
with_gnu_ld=unknown
;;
esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
$as_echo_n "checking for GNU ld... " >&6; }
else
@@ -4002,32 +4893,32 @@ if ${lt_cv_path_LD+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -z "$LD"; then
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
+ lt_cv_path_LD=$ac_dir/$ac_prog
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
- test "$with_gnu_ld" != no && break
+ test no != "$with_gnu_ld" && break
;;
*)
- test "$with_gnu_ld" != yes && break
+ test yes != "$with_gnu_ld" && break
;;
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
fi
fi
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
if test -n "$LD"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
$as_echo "$LD" >&6; }
@@ -4070,33 +4961,38 @@ if ${lt_cv_path_NM+:} false; then :
else
if test -n "$NM"; then
# Let the user override the test.
- lt_cv_path_NM="$NM"
+ lt_cv_path_NM=$NM
else
- lt_nm_to_check="${ac_tool_prefix}nm"
+ lt_nm_to_check=${ac_tool_prefix}nm
if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
lt_nm_to_check="$lt_nm_to_check nm"
fi
for lt_tmp_nm in $lt_nm_to_check; do
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- tmp_nm="$ac_dir/$lt_tmp_nm"
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
# Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
# Tru64's nm complains that /dev/null is an invalid object file
- case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
- */dev/null* | *'Invalid file or object type'*)
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
lt_cv_path_NM="$tmp_nm -B"
- break
+ break 2
;;
*)
case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
*/dev/null*)
lt_cv_path_NM="$tmp_nm -p"
- break
+ break 2
;;
*)
lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
@@ -4107,15 +5003,15 @@ else
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
done
: ${lt_cv_path_NM=no}
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
$as_echo "$lt_cv_path_NM" >&6; }
-if test "$lt_cv_path_NM" != "no"; then
- NM="$lt_cv_path_NM"
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
else
# Didn't find any BSD compatible name lister, look for dumpbin.
if test -n "$DUMPBIN"; then :
@@ -4221,9 +5117,9 @@ esac
fi
fi
- case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
*COFF*)
- DUMPBIN="$DUMPBIN -symbols"
+ DUMPBIN="$DUMPBIN -symbols -headers"
;;
*)
DUMPBIN=:
@@ -4231,8 +5127,8 @@ fi
esac
fi
- if test "$DUMPBIN" != ":"; then
- NM="$DUMPBIN"
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
fi
fi
test -z "$NM" && NM=nm
@@ -4265,17 +5161,6 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
$as_echo "$lt_cv_nm_interface" >&6; }
-{ $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:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
-$as_echo "no, using $LN_S" >&6; }
-fi
-
# find the maximum length of command line arguments
{ $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; }
@@ -4283,7 +5168,7 @@ if ${lt_cv_sys_max_cmd_len+:} false; then :
$as_echo_n "(cached) " >&6
else
i=0
- teststring="ABCD"
+ teststring=ABCD
case $build_os in
msdosdjgpp*)
@@ -4317,13 +5202,18 @@ else
lt_cv_sys_max_cmd_len=8192;
;;
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
amigaos*)
# On AmigaOS with pdksh, this test takes hours, literally.
# So we just punt and use a minimum line length of 8192.
lt_cv_sys_max_cmd_len=8192;
;;
- netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -4374,22 +5264,22 @@ else
*)
lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
if test -n "$lt_cv_sys_max_cmd_len" && \
- test undefined != "$lt_cv_sys_max_cmd_len"; then
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
else
# Make teststring a little bigger before we do anything with it.
# a 1K string should be a reasonable start.
- for i in 1 2 3 4 5 6 7 8 ; do
+ for i in 1 2 3 4 5 6 7 8; do
teststring=$teststring$teststring
done
SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
- while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
= "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test $i != 17 # 1/2 MB should be enough
+ test 17 != "$i" # 1/2 MB should be enough
do
i=`expr $i + 1`
teststring=$teststring$teststring
@@ -4407,7 +5297,7 @@ else
fi
-if test -n $lt_cv_sys_max_cmd_len ; then
+if test -n "$lt_cv_sys_max_cmd_len"; then
{ $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
@@ -4425,30 +5315,6 @@ max_cmd_len=$lt_cv_sys_max_cmd_len
: ${MV="mv -f"}
: ${RM="rm -f"}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
-$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
- test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
- = c,a/b,b/c, \
- && eval 'test $(( 1 + 1 )) -eq 2 \
- && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
- && xsi_shell=yes
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
-$as_echo "$xsi_shell" >&6; }
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
-$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
- >/dev/null 2>&1 \
- && lt_shell_append=yes
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
-$as_echo "$lt_shell_append" >&6; }
-
-
if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
lt_unset=unset
else
@@ -4571,13 +5437,13 @@ esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- if test "$GCC" != yes; then
+ if test yes != "$GCC"; then
reload_cmds=false
fi
;;
darwin*)
- if test "$GCC" = yes; then
- reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
else
reload_cmds='$LD$reload_flag -o $output$reload_objs'
fi
@@ -4702,13 +5568,13 @@ lt_cv_deplibs_check_method='unknown'
# Need to set the preceding variable on all platforms that support
# interlibrary dependencies.
# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
+# 'unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
# 'test_compile' -- check by making test program.
# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
case $host_os in
aix[4-9]*)
@@ -4735,8 +5601,7 @@ mingw* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
# func_win32_libid shell function, so use a weaker test based on 'objdump',
# unless we find 'file', for example because we are cross-compiling.
- # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
- if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ if ( file / ) >/dev/null 2>&1; then
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
lt_cv_file_magic_cmd='func_win32_libid'
else
@@ -4814,7 +5679,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
lt_cv_deplibs_check_method=pass_all
;;
-netbsd* | netbsdelf*-gnu)
+netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
else
@@ -4832,8 +5697,8 @@ newos6*)
lt_cv_deplibs_check_method=pass_all
;;
-openbsd*)
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
else
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
@@ -4886,6 +5751,9 @@ sysv4 | sysv4.3*)
tpf*)
lt_cv_deplibs_check_method=pass_all
;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
fi
@@ -5040,8 +5908,8 @@ else
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- # two different shell functions defined in ltmain.sh
- # decide which to use based on capabilities of $DLLTOOL
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
case `$DLLTOOL --help 2>&1` in
*--identify-strict*)
lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
@@ -5053,7 +5921,7 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
*)
# fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
;;
esac
@@ -5069,7 +5937,6 @@ test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
if test -n "$ac_tool_prefix"; then
for ac_prog in ar
do
@@ -5208,7 +6075,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
- if test "$ac_status" -eq 0; then
+ if test 0 -eq "$ac_status"; then
# Ensure the archiver fails upon bogus file names.
rm -f conftest.$ac_objext libconftest.a
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
@@ -5216,7 +6083,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
- if test "$ac_status" -ne 0; then
+ if test 0 -ne "$ac_status"; then
lt_cv_ar_at_file=@
fi
fi
@@ -5229,7 +6096,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
$as_echo "$lt_cv_ar_at_file" >&6; }
-if test "x$lt_cv_ar_at_file" = xno; then
+if test no = "$lt_cv_ar_at_file"; then
archiver_list_spec=
else
archiver_list_spec=$lt_cv_ar_at_file
@@ -5446,7 +6313,7 @@ old_postuninstall_cmds=
if test -n "$RANLIB"; then
case $host_os in
- openbsd*)
+ bitrig* | openbsd*)
old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
;;
*)
@@ -5483,48 +6350,6 @@ esac
-for ac_prog in gawk mawk nawk awk
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$AWK"; then
- ac_cv_prog_AWK="$AWK" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_AWK="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-AWK=$ac_cv_prog_AWK
-if test -n "$AWK"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-$as_echo "$AWK" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$AWK" && break
-done
-
@@ -5578,7 +6403,7 @@ cygwin* | mingw* | pw32* | cegcc*)
symcode='[ABCDGISTW]'
;;
hpux*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
symcode='[ABCDEGRST]'
fi
;;
@@ -5611,14 +6436,44 @@ case `$NM -V 2>&1` in
symcode='[ABCDGIRSTW]' ;;
esac
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
# Handle CRLF in mingw tool chain
opt_cr=
@@ -5636,21 +6491,24 @@ for ac_symprfx in "" "_"; do
# Write the raw and C identifiers.
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Fake it for dumpbin and say T for any non-static function
- # and D for any global variable.
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
# Also find C++ and __fastcall symbols from MSVC++,
# which start with @ or ?.
lt_cv_sys_global_symbol_pipe="$AWK '"\
" {last_section=section; section=\$ 3};"\
" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
" \$ 0!~/External *\|/{next};"\
" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
" {if(hide[section]) next};"\
-" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-" s[1]~/^[@?]/{print s[1], s[1]; next};"\
-" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
" ' prfx=^$ac_symprfx"
else
lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
@@ -5698,11 +6556,11 @@ _LT_EOF
if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
cat <<_LT_EOF > conftest.$ac_ext
/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
relocations are performed -- see ld's documentation on pseudo-relocs. */
# define LT_DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
/* This system does not cope well with relocations in const data. */
# define LT_DLSYM_CONST
#else
@@ -5728,7 +6586,7 @@ lt__PROGRAM__LTX_preloaded_symbols[] =
{
{ "@PROGRAM@", (void *) 0 },
_LT_EOF
- $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
cat <<\_LT_EOF >> conftest.$ac_ext
{0, (void *) 0}
};
@@ -5748,13 +6606,13 @@ _LT_EOF
mv conftest.$ac_objext conftstm.$ac_objext
lt_globsym_save_LIBS=$LIBS
lt_globsym_save_CFLAGS=$CFLAGS
- LIBS="conftstm.$ac_objext"
+ LIBS=conftstm.$ac_objext
CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
(eval $ac_link) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ test $ac_status = 0; } && test -s conftest$ac_exeext; then
pipe_works=yes
fi
LIBS=$lt_globsym_save_LIBS
@@ -5775,7 +6633,7 @@ _LT_EOF
rm -rf conftest* conftst*
# Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
+ if test yes = "$pipe_works"; then
break
else
lt_cv_sys_global_symbol_pipe=
@@ -5828,6 +6686,16 @@ fi
+
+
+
+
+
+
+
+
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
$as_echo_n "checking for sysroot... " >&6; }
@@ -5840,9 +6708,9 @@ fi
lt_sysroot=
-case ${with_sysroot} in #(
+case $with_sysroot in #(
yes)
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
lt_sysroot=`$CC --print-sysroot 2>/dev/null`
fi
;; #(
@@ -5852,8 +6720,8 @@ case ${with_sysroot} in #(
no|'')
;; #(
*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
-$as_echo "${with_sysroot}" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+$as_echo "$with_sysroot" >&6; }
as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
;;
esac
@@ -5865,18 +6733,99 @@ $as_echo "${lt_sysroot:-no}" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+$as_echo_n "checking for a working dd... " >&6; }
+if ${ac_cv_path_lt_DD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+if test -z "$lt_DD"; then
+ ac_path_lt_DD_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in dd; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_lt_DD" || continue
+if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi
+ $ac_path_lt_DD_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_lt_DD"; then
+ :
+ fi
+else
+ ac_cv_path_lt_DD=$lt_DD
+fi
+
+rm -f conftest.i conftest2.i conftest.out
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+$as_echo "$ac_cv_path_lt_DD" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+$as_echo_n "checking how to truncate binary pipes... " >&6; }
+if ${lt_cv_truncate_bin+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+$as_echo "$lt_cv_truncate_bin" >&6; }
+
+
+
+
+
+
+
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in $*""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
# Check whether --enable-libtool-lock was given.
if test "${enable_libtool_lock+set}" = set; then :
enableval=$enable_libtool_lock;
fi
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case $host in
ia64-*-hpux*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
echo 'int i;' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
@@ -5885,24 +6834,25 @@ ia64-*-hpux*)
test $ac_status = 0; }; then
case `/usr/bin/file conftest.$ac_objext` in
*ELF-32*)
- HPUX_IA64_MODE="32"
+ HPUX_IA64_MODE=32
;;
*ELF-64*)
- HPUX_IA64_MODE="64"
+ HPUX_IA64_MODE=64
;;
esac
fi
rm -rf conftest*
;;
*-*-irix6*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
echo '#line '$LINENO' "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:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
case `/usr/bin/file conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -melf32bsmip"
@@ -5931,9 +6881,50 @@ ia64-*-hpux*)
rm -rf conftest*
;;
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '#line '$LINENO' "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:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
echo 'int i;' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
@@ -5956,10 +6947,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
;;
esac
;;
- powerpc64le-*)
+ powerpc64le-*linux*)
LD="${LD-ld} -m elf32lppclinux"
;;
- powerpc64-*)
+ powerpc64-*linux*)
LD="${LD-ld} -m elf32ppclinux"
;;
s390x-*linux*)
@@ -5978,10 +6969,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
x86_64-*linux*)
LD="${LD-ld} -m elf_x86_64"
;;
- powerpcle-*)
+ powerpcle-*linux*|powerpc64le-*linux*)
LD="${LD-ld} -m elf64lppc"
;;
- powerpc-*)
+ powerpc-*linux*|powerpc64-*linux*)
LD="${LD-ld} -m elf64ppc"
;;
s390*-*linux*|s390*-*tpf*)
@@ -5999,7 +6990,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
+ SAVE_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -belf"
{ $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; }
@@ -6039,13 +7030,14 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
fi
{ $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
+ if test yes != "$lt_cv_cc_needs_belf"; then
# this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
+ CFLAGS=$SAVE_CFLAGS
fi
;;
*-*solaris*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
echo 'int i;' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
@@ -6057,7 +7049,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
case $lt_cv_prog_gnu_ld in
yes*)
case $host in
- i?86-*-solaris*)
+ i?86-*-solaris*|x86_64-*-solaris*)
LD="${LD-ld} -m elf_x86_64"
;;
sparc*-*-solaris*)
@@ -6066,7 +7058,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
esac
# GNU ld 2.21 introduced _sol2 emulations. Use them if available.
if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD="${LD-ld}_sol2"
+ LD=${LD-ld}_sol2
fi
;;
*)
@@ -6082,7 +7074,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; }
;;
esac
-need_locks="$enable_libtool_lock"
+need_locks=$enable_libtool_lock
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
@@ -6193,7 +7185,7 @@ else
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
$as_echo "$lt_cv_path_mainfest_tool" >&6; }
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
+if test yes != "$lt_cv_path_mainfest_tool"; then
MANIFEST_TOOL=:
fi
@@ -6696,7 +7688,7 @@ if ${lt_cv_apple_cc_single_mod+:} false; then :
$as_echo_n "(cached) " >&6
else
lt_cv_apple_cc_single_mod=no
- if test -z "${LT_MULTI_MODULE}"; then
+ if test -z "$LT_MULTI_MODULE"; then
# By default we will add the -single_module flag. You can override
# by either setting the environment variable LT_MULTI_MODULE
# non-empty at configure time, or by adding -multi_module to the
@@ -6714,7 +7706,7 @@ else
cat conftest.err >&5
# Otherwise, if the output was created with a 0 exit code from
# the compiler, it worked.
- elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
lt_cv_apple_cc_single_mod=yes
else
cat conftest.err >&5
@@ -6753,7 +7745,7 @@ else
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
@@ -6782,7 +7774,7 @@ _LT_EOF
_lt_result=$?
if test -s conftest.err && $GREP force_load conftest.err; then
cat conftest.err >&5
- elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
lt_cv_ld_force_load=yes
else
cat conftest.err >&5
@@ -6795,32 +7787,32 @@ fi
$as_echo "$lt_cv_ld_force_load" >&6; }
case $host_os in
rhapsody* | darwin1.[012])
- _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[91]*)
- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
- 10.[012]*)
- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[012][,.]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
10.*)
- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
- if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
_lt_dar_single_mod='$single_module'
fi
- if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
- _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
else
- _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
fi
- if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
_lt_dsymutil='~$DSYMUTIL $lib || :'
else
_lt_dsymutil=
@@ -6828,6 +7820,41 @@ $as_echo "$lt_cv_ld_force_load" >&6; }
;;
esac
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x$2 in
+ x)
+ ;;
+ *:)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+ ;;
+ x:*)
+ eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+ ;;
+ *)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -7113,6 +8140,306 @@ done
# Set options
+enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
+set dummy ${ac_tool_prefix}as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AS"; then
+ ac_cv_prog_AS="$AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AS="${ac_tool_prefix}as"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AS"; then
+ ac_ct_AS=$AS
+ # Extract the first word of "as", so it can be a program name with args.
+set dummy as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AS"; then
+ ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AS="as"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AS=$ac_cv_prog_ac_ct_AS
+if test -n "$ac_ct_AS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
+$as_echo "$ac_ct_AS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AS" = x; then
+ AS="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $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
+ AS=$ac_ct_AS
+ fi
+else
+ AS="$ac_cv_prog_AS"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $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
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $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
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+ ;;
+esac
+
+test -z "$AS" && AS=as
+
+
+
+
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
@@ -7129,14 +8456,14 @@ if test "${enable_shared+set}" = set; then :
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac
else
@@ -7160,14 +8487,14 @@ if test "${enable_static+set}" = set; then :
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac
else
@@ -7191,14 +8518,14 @@ if test "${with_pic+set}" = set; then :
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac
else
@@ -7206,8 +8533,6 @@ else
fi
-test -z "$pic_mode" && pic_mode=default
-
@@ -7223,14 +8548,14 @@ if test "${enable_fast_install+set}" = set; then :
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac
else
@@ -7244,11 +8569,63 @@ fi
+ shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[5-9]*,yes)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+
+# Check whether --with-aix-soname was given.
+if test "${with_aix_soname+set}" = set; then :
+ withval=$with_aix_soname; case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname
+else
+ if ${lt_cv_with_aix_soname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_with_aix_soname=aix
+fi
+
+ with_aix_soname=$lt_cv_with_aix_soname
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+$as_echo "$with_aix_soname" >&6; }
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+
+
+
+
+
+
# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ltmain"
+LIBTOOL_DEPS=$ltmain
# Always use our own libtool.
LIBTOOL='$(SHELL) $(top_builddir)/libtool'
@@ -7297,7 +8674,7 @@ test -z "$LN_S" && LN_S="ln -s"
-if test -n "${ZSH_VERSION+set}" ; then
+if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
@@ -7336,7 +8713,7 @@ aix3*)
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
- if test "X${COLLECT_NAMES+set}" != Xset; then
+ if test set != "${COLLECT_NAMES+set}"; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
@@ -7347,14 +8724,14 @@ esac
ofile=libtool
can_build_shared=yes
-# All known linkers require a `.a' archive for static linking (except MSVC,
+# All known linkers require a '.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
-with_gnu_ld="$lt_cv_prog_gnu_ld"
+with_gnu_ld=$lt_cv_prog_gnu_ld
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
+old_CC=$CC
+old_CFLAGS=$CFLAGS
# Set sane defaults for various variables
test -z "$CC" && CC=cc
@@ -7363,15 +8740,8 @@ test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
test -z "$LD" && LD=ld
test -z "$ac_objext" && ac_objext=o
-for cc_temp in $compiler""; do
- case $cc_temp in
- compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
- distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
- \-*) ;;
- *) break;;
- esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
# Only perform the check for file, if the check method requires it
@@ -7386,22 +8756,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then :
else
case $MAGIC_CMD in
[\\/*] | ?:[\\/]*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
;;
*)
- lt_save_MAGIC_CMD="$MAGIC_CMD"
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
for ac_dir in $ac_dummy; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/${ac_tool_prefix}file; then
- lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -f "$ac_dir/${ac_tool_prefix}file"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
:
@@ -7424,13 +8794,13 @@ _LT_EOF
break
fi
done
- IFS="$lt_save_ifs"
- MAGIC_CMD="$lt_save_MAGIC_CMD"
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
;;
esac
fi
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if test -n "$MAGIC_CMD"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
$as_echo "$MAGIC_CMD" >&6; }
@@ -7452,22 +8822,22 @@ if ${lt_cv_path_MAGIC_CMD+:} false; then :
else
case $MAGIC_CMD in
[\\/*] | ?:[\\/]*)
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
;;
*)
- lt_save_MAGIC_CMD="$MAGIC_CMD"
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
for ac_dir in $ac_dummy; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/file; then
- lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -f "$ac_dir/file"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"file"
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
:
@@ -7490,13 +8860,13 @@ _LT_EOF
break
fi
done
- IFS="$lt_save_ifs"
- MAGIC_CMD="$lt_save_MAGIC_CMD"
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
;;
esac
fi
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if test -n "$MAGIC_CMD"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
$as_echo "$MAGIC_CMD" >&6; }
@@ -7517,7 +8887,7 @@ esac
# Use C for the default configuration in the libtool script
-lt_save_CC="$CC"
+lt_save_CC=$CC
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -7579,7 +8949,7 @@ if test -n "$compiler"; then
lt_prog_compiler_no_builtin_flag=
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
case $cc_basename in
nvcc*)
lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
@@ -7595,7 +8965,7 @@ else
lt_cv_prog_compiler_rtti_exceptions=no
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="-fno-rtti -fno-exceptions"
+ lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
@@ -7625,7 +8995,7 @@ fi
{ $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
+if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
else
:
@@ -7643,17 +9013,18 @@ lt_prog_compiler_pic=
lt_prog_compiler_static=
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
lt_prog_compiler_wl='-Wl,'
lt_prog_compiler_static='-static'
case $host_os in
aix*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
lt_prog_compiler_static='-Bstatic'
fi
+ lt_prog_compiler_pic='-fPIC'
;;
amigaos*)
@@ -7664,8 +9035,8 @@ lt_prog_compiler_static=
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
;;
esac
@@ -7681,6 +9052,11 @@ lt_prog_compiler_static=
# Although the cygwin gcc ignores -fPIC, still need this for old-style
# (--disable-auto-import) libraries
lt_prog_compiler_pic='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static='$wl-static'
+ ;;
+ esac
;;
darwin* | rhapsody*)
@@ -7751,7 +9127,7 @@ lt_prog_compiler_static=
case $host_os in
aix*)
lt_prog_compiler_wl='-Wl,'
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
lt_prog_compiler_static='-Bstatic'
else
@@ -7759,10 +9135,29 @@ lt_prog_compiler_static=
fi
;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+
mingw* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
lt_prog_compiler_pic='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static='$wl-static'
+ ;;
+ esac
;;
hpux9* | hpux10* | hpux11*)
@@ -7778,7 +9173,7 @@ lt_prog_compiler_static=
;;
esac
# Is there a better lt_prog_compiler_static that works with the bundled CC?
- lt_prog_compiler_static='${wl}-a ${wl}archive'
+ lt_prog_compiler_static='$wl-a ${wl}archive'
;;
irix5* | irix6* | nonstopux*)
@@ -7789,7 +9184,7 @@ lt_prog_compiler_static=
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
case $cc_basename in
- # old Intel for x86_64 which still supported -KPIC.
+ # old Intel for x86_64, which still supported -KPIC.
ecc*)
lt_prog_compiler_wl='-Wl,'
lt_prog_compiler_pic='-KPIC'
@@ -7814,6 +9209,12 @@ lt_prog_compiler_static=
lt_prog_compiler_pic='-PIC'
lt_prog_compiler_static='-Bstatic'
;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group compilers (*not* the Pentium gcc compiler,
# which looks to be a dead project)
@@ -7911,7 +9312,7 @@ lt_prog_compiler_static=
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
lt_prog_compiler_pic='-Kconform_pic'
lt_prog_compiler_static='-Bstatic'
fi
@@ -7940,7 +9341,7 @@ lt_prog_compiler_static=
fi
case $host_os in
- # For platforms which do not support PIC, -DPIC is meaningless:
+ # For platforms that do not support PIC, -DPIC is meaningless:
*djgpp*)
lt_prog_compiler_pic=
;;
@@ -7972,7 +9373,7 @@ else
lt_cv_prog_compiler_pic_works=no
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
@@ -8002,7 +9403,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
-if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+if test yes = "$lt_cv_prog_compiler_pic_works"; then
case $lt_prog_compiler_pic in
"" | " "*) ;;
*) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
@@ -8034,7 +9435,7 @@ if ${lt_cv_prog_compiler_static_works+:} false; then :
$as_echo_n "(cached) " >&6
else
lt_cv_prog_compiler_static_works=no
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -8053,13 +9454,13 @@ else
fi
fi
$RM -r conftest*
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
-if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+if test yes = "$lt_cv_prog_compiler_static_works"; then
:
else
lt_prog_compiler_static=
@@ -8179,8 +9580,8 @@ $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
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
# do not overwrite the value of need_locks provided by the user
{ $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; }
@@ -8192,9 +9593,9 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
ln conftest.a conftest.b 2>/dev/null && hard_links=no
{ $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:${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;}
+ if test no = "$hard_links"; then
+ { $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
else
@@ -8237,9 +9638,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
# included in the symbol list
include_expsyms=
# exclude_expsyms can be an extended regexp of symbols to exclude
- # it will be wrapped by ` (' and `)$', so one must not match beginning or
- # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
- # as well as any symbol that contains `d'.
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
# platforms (ab)use it in PIC code, but their linkers get confused if
@@ -8254,7 +9655,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
- if test "$GCC" != yes; then
+ if test yes != "$GCC"; then
with_gnu_ld=no
fi
;;
@@ -8262,12 +9663,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
- openbsd*)
+ openbsd* | bitrig*)
with_gnu_ld=no
;;
- linux* | k*bsd*-gnu | gnu*)
- link_all_deplibs=no
- ;;
esac
ld_shlibs=yes
@@ -8275,7 +9673,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
# On some targets, GNU ld is compatible enough with the native linker
# that we're better off using the native interface for both.
lt_use_gnu_ld_interface=no
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
case $host_os in
aix*)
# The AIX port of GNU ld has always aspired to compatibility
@@ -8297,24 +9695,24 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
esac
fi
- if test "$lt_use_gnu_ld_interface" = yes; then
+ if test yes = "$lt_use_gnu_ld_interface"; then
# If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
+ wlarc='$wl'
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- export_dynamic_flag_spec='${wl}--export-dynamic'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ export_dynamic_flag_spec='$wl--export-dynamic'
# ancient GNU ld didn't support --whole-archive et. al.
if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
whole_archive_flag_spec=
fi
supports_anon_versioning=no
- case `$LD -v 2>&1` in
+ case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
*GNU\ gold*) supports_anon_versioning=yes ;;
*\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -8327,7 +9725,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
case $host_os in
aix[3-9]*)
# On AIX/PPC, the GNU linker is very broken
- if test "$host_cpu" != ia64; then
+ if test ia64 != "$host_cpu"; then
ld_shlibs=no
cat <<_LT_EOF 1>&2
@@ -8346,7 +9744,7 @@ _LT_EOF
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
archive_expsym_cmds=''
;;
m68k)
@@ -8362,7 +9760,7 @@ _LT_EOF
allow_undefined_flag=unsupported
# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
- archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
else
ld_shlibs=no
fi
@@ -8372,7 +9770,7 @@ _LT_EOF
# _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
# as there is no search path for DLLs.
hardcode_libdir_flag_spec='-L$libdir'
- export_dynamic_flag_spec='${wl}--export-all-symbols'
+ export_dynamic_flag_spec='$wl--export-all-symbols'
allow_undefined_flag=unsupported
always_export_symbols=no
enable_shared_with_static_runtimes=yes
@@ -8380,61 +9778,89 @@ _LT_EOF
exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is; otherwise, prepend...
- archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
ld_shlibs=no
fi
;;
haiku*)
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
link_all_deplibs=yes
;;
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ shrext_cmds=.dll
+ archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
interix[3-9]*)
hardcode_direct=no
hardcode_shlibpath_var=no
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- export_dynamic_flag_spec='${wl}-E'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ export_dynamic_flag_spec='$wl-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
tmp_diet=no
- if test "$host_os" = linux-dietlibc; then
+ if test linux-dietlibc = "$host_os"; then
case $cc_basename in
diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
esac
fi
if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
- && test "$tmp_diet" = no
+ && test no = "$tmp_diet"
then
tmp_addflag=' $pic_flag'
tmp_sharedflag='-shared'
case $cc_basename,$host_cpu in
pgcc*) # Portland Group C compiler
- whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
tmp_addflag=' $pic_flag'
;;
pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group f77 and f90 compilers
- whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
tmp_addflag=' $pic_flag -Mnomain' ;;
ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
tmp_addflag=' -i_dynamic' ;;
@@ -8445,42 +9871,47 @@ _LT_EOF
lf95*) # Lahey Fortran 8.1
whole_archive_flag_spec=
tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
tmp_sharedflag='-qmkshrobj'
tmp_addflag= ;;
nvcc*) # Cuda Compiler Driver 2.2
- whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
compiler_needs_object=yes
;;
esac
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*) # Sun C 5.9
- whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
compiler_needs_object=yes
tmp_sharedflag='-G' ;;
*Sun\ F*) # Sun Fortran 8.3
tmp_sharedflag='-G' ;;
esac
- archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ if test yes = "$supports_anon_versioning"; then
archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
case $cc_basename in
+ tcc*)
+ export_dynamic_flag_spec='-rdynamic'
+ ;;
xlf* | bgf* | bgxlf* | mpixlf*)
# IBM XL Fortran 10.1 on PPC cannot create shared libs itself
whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ if test yes = "$supports_anon_versioning"; then
archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
fi
;;
esac
@@ -8489,13 +9920,13 @@ _LT_EOF
fi
;;
- netbsd* | netbsdelf*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
else
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
fi
;;
@@ -8513,8 +9944,8 @@ _LT_EOF
_LT_EOF
elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
ld_shlibs=no
fi
@@ -8526,7 +9957,7 @@ _LT_EOF
ld_shlibs=no
cat <<_LT_EOF 1>&2
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
*** reliably create shared libraries on SCO systems. Therefore, libtool
*** is disabling shared libraries support. We urge you to upgrade GNU
*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
@@ -8541,9 +9972,9 @@ _LT_EOF
# DT_RUNPATH tag from executables and libraries. But doing so
# requires that you compile everything twice, which is a pain.
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
ld_shlibs=no
fi
@@ -8560,15 +9991,15 @@ _LT_EOF
*)
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
ld_shlibs=no
fi
;;
esac
- if test "$ld_shlibs" = no; then
+ if test no = "$ld_shlibs"; then
runpath_var=
hardcode_libdir_flag_spec=
export_dynamic_flag_spec=
@@ -8584,7 +10015,7 @@ _LT_EOF
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
hardcode_minus_L=yes
- if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
hardcode_direct=unsupported
@@ -8592,34 +10023,57 @@ _LT_EOF
;;
aix[4-9]*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
- no_entry_flag=""
+ no_entry_flag=
else
# If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to AIX nm, but means don't demangle with GNU nm
- # Also, AIX nm treats weak defined symbols like other global
- # defined symbols, whereas GNU nm marks them as "W".
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
aix_use_runtimelinking=yes
break
fi
done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
;;
esac
@@ -8638,13 +10092,21 @@ _LT_EOF
hardcode_direct_absolute=yes
hardcode_libdir_separator=':'
link_all_deplibs=yes
- file_list_spec='${wl}-f,'
+ file_list_spec='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ ;;
+ esac
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
case $host_os in aix4.[012]|aix4.[012].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
- collect2name=`${CC} -print-prog-name=collect2`
+ collect2name=`$CC -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
@@ -8663,36 +10125,42 @@ _LT_EOF
;;
esac
shared_flag='-shared'
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag="$shared_flag "'${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
fi
- link_all_deplibs=no
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
else
# not using gcc
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
else
- shared_flag='${wl}-bM:SRE'
+ shared_flag='$wl-bM:SRE'
fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
fi
fi
- export_dynamic_flag_spec='${wl}-bexpall'
+ export_dynamic_flag_spec='$wl-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to export.
always_export_symbols=yes
- if test "$aix_use_runtimelinking" = yes; then
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
# Warning - without using the other runtime loading flags (-brtl),
# -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.
- if test "${lt_cv_aix_libpath+set}" = set; then
+ if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
if ${lt_cv_aix_libpath_+:} false; then :
@@ -8727,7 +10195,7 @@ fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_="/usr/lib:/lib"
+ lt_cv_aix_libpath_=/usr/lib:/lib
fi
fi
@@ -8735,17 +10203,17 @@ fi
aix_libpath=$lt_cv_aix_libpath_
fi
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
else
- if test "$host_cpu" = ia64; then
- hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ if test ia64 = "$host_cpu"; then
+ hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
allow_undefined_flag="-z nodefs"
- 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"
+ 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.
- if test "${lt_cv_aix_libpath+set}" = set; then
+ if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
if ${lt_cv_aix_libpath_+:} false; then :
@@ -8780,7 +10248,7 @@ fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_="/usr/lib:/lib"
+ lt_cv_aix_libpath_=/usr/lib:/lib
fi
fi
@@ -8788,21 +10256,33 @@ fi
aix_libpath=$lt_cv_aix_libpath_
fi
- hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
- no_undefined_flag=' ${wl}-bernotok'
- allow_undefined_flag=' ${wl}-berok'
- if test "$with_gnu_ld" = yes; then
+ no_undefined_flag=' $wl-bernotok'
+ allow_undefined_flag=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
# We only use this code for GNU lds that support --whole-archive.
- whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
whole_archive_flag_spec='$convenience'
fi
archive_cmds_need_lc=yes
- # This is similar to how AIX traditionally builds its shared libraries.
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
fi
fi
;;
@@ -8811,7 +10291,7 @@ fi
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
archive_expsym_cmds=''
;;
m68k)
@@ -8841,16 +10321,17 @@ fi
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
- archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
- else
- sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
+ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
enable_shared_with_static_runtimes=yes
@@ -8859,18 +10340,18 @@ fi
# Don't use ranlib
old_postinstall_cmds='chmod 644 $oldlib'
postlink_cmds='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile="$lt_outputfile.exe"
- lt_tool_outputfile="$lt_tool_outputfile.exe"
- ;;
- esac~
- if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
;;
*)
# Assume MSVC wrapper
@@ -8879,7 +10360,7 @@ fi
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
@@ -8898,24 +10379,24 @@ fi
hardcode_direct=no
hardcode_automatic=yes
hardcode_shlibpath_var=unsupported
- if test "$lt_cv_ld_force_load" = "yes"; then
- whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ if test yes = "$lt_cv_ld_force_load"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
else
whole_archive_flag_spec=''
fi
link_all_deplibs=yes
- allow_undefined_flag="$_lt_dar_allow_undefined"
+ allow_undefined_flag=$_lt_dar_allow_undefined
case $cc_basename in
- ifort*) _lt_dar_can_shared=yes ;;
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
*) _lt_dar_can_shared=$GCC ;;
esac
- if test "$_lt_dar_can_shared" = "yes"; then
+ if test yes = "$_lt_dar_can_shared"; then
output_verbose_link_cmd=func_echo_all
- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
else
ld_shlibs=no
@@ -8957,33 +10438,33 @@ fi
;;
hpux9*)
- if test "$GCC" = yes; then
- archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ if test yes = "$GCC"; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
else
- archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
fi
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
- export_dynamic_flag_spec='${wl}-E'
+ export_dynamic_flag_spec='$wl-E'
;;
hpux10*)
- if test "$GCC" = yes && test "$with_gnu_ld" = no; then
- archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
else
archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
fi
- if test "$with_gnu_ld" = no; then
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
hardcode_libdir_separator=:
hardcode_direct=yes
hardcode_direct_absolute=yes
- export_dynamic_flag_spec='${wl}-E'
+ export_dynamic_flag_spec='$wl-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
hardcode_minus_L=yes
@@ -8991,25 +10472,25 @@ fi
;;
hpux11*)
- if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ if test yes,no = "$GCC,$with_gnu_ld"; then
case $host_cpu in
hppa*64*)
- archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
- archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
case $host_cpu in
hppa*64*)
- archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
- archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
@@ -9021,7 +10502,7 @@ if ${lt_cv_prog_compiler__b+:} false; then :
$as_echo_n "(cached) " >&6
else
lt_cv_prog_compiler__b=no
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS -b"
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -9040,14 +10521,14 @@ else
fi
fi
$RM -r conftest*
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
$as_echo "$lt_cv_prog_compiler__b" >&6; }
-if test x"$lt_cv_prog_compiler__b" = xyes; then
- archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+if test yes = "$lt_cv_prog_compiler__b"; then
+ archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
else
archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
fi
@@ -9055,8 +10536,8 @@ fi
;;
esac
fi
- if test "$with_gnu_ld" = no; then
- hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
hardcode_libdir_separator=:
case $host_cpu in
@@ -9067,7 +10548,7 @@ fi
*)
hardcode_direct=yes
hardcode_direct_absolute=yes
- export_dynamic_flag_spec='${wl}-E'
+ export_dynamic_flag_spec='$wl-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
@@ -9078,8 +10559,8 @@ fi
;;
irix5* | irix6* | nonstopux*)
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
# Try to use the -exported_symbol ld option, if it does not
# work, assume that -exports_file does not work either and
# implicitly export all symbols.
@@ -9089,8 +10570,8 @@ $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >
if ${lt_cv_irix_exported_symbol+:} false; then :
$as_echo_n "(cached) " >&6
else
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int foo (void) { return 0; }
@@ -9102,25 +10583,35 @@ else
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
$as_echo "$lt_cv_irix_exported_symbol" >&6; }
- if test "$lt_cv_irix_exported_symbol" = yes; then
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
fi
else
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
fi
archive_cmds_need_lc='no'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
hardcode_libdir_separator=:
inherit_rpath=yes
link_all_deplibs=yes
;;
- netbsd* | netbsdelf*-gnu)
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ ld_shlibs=yes
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
@@ -9134,7 +10625,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
newsos6)
archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
hardcode_direct=yes
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
hardcode_libdir_separator=:
hardcode_shlibpath_var=no
;;
@@ -9142,27 +10633,19 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
*nto* | *qnx*)
;;
- openbsd*)
+ openbsd* | bitrig*)
if test -f /usr/libexec/ld.so; then
hardcode_direct=yes
hardcode_shlibpath_var=no
hardcode_direct_absolute=yes
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- export_dynamic_flag_spec='${wl}-E'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ export_dynamic_flag_spec='$wl-E'
else
- case $host_os in
- openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- ;;
- *)
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
- ;;
- esac
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
fi
else
ld_shlibs=no
@@ -9173,33 +10656,53 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
hardcode_libdir_flag_spec='-L$libdir'
hardcode_minus_L=yes
allow_undefined_flag=unsupported
- archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
- old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ shrext_cmds=.dll
+ archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes=yes
;;
osf3*)
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GCC"; then
+ allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
else
allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
fi
archive_cmds_need_lc='no'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
hardcode_libdir_separator=:
;;
osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test "$GCC" = yes; then
- allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ if test yes = "$GCC"; then
+ allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+ archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
else
allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
- $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
# Both c and cxx compiler support -rpath directly
hardcode_libdir_flag_spec='-rpath $libdir'
@@ -9210,24 +10713,24 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
solaris*)
no_undefined_flag=' -z defs'
- if test "$GCC" = yes; then
- wlarc='${wl}'
- archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
else
case `$CC -V 2>&1` in
*"Compilers 5.0"*)
wlarc=''
- archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
;;
*)
- wlarc='${wl}'
- archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ wlarc='$wl'
+ archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
;;
esac
fi
@@ -9237,11 +10740,11 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
solaris2.[0-5] | solaris2.[0-5].*) ;;
*)
# The compiler driver will combine and reorder linker options,
- # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
# but is careful enough not to reorder.
# Supported since Solaris 2.6 (maybe 2.5.1?)
- if test "$GCC" = yes; then
- whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ if test yes = "$GCC"; then
+ whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
else
whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
fi
@@ -9251,10 +10754,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
;;
sunos4*)
- if test "x$host_vendor" = xsequent; then
+ if test sequent = "$host_vendor"; then
# Use $CC to link under sequent, because it throws in some extra .o
# files that make .init and .fini sections work.
- archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
else
archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
fi
@@ -9303,43 +10806,43 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
- no_undefined_flag='${wl}-z,text'
+ no_undefined_flag='$wl-z,text'
archive_cmds_need_lc=no
hardcode_shlibpath_var=no
runpath_var='LD_RUN_PATH'
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
sysv5* | sco3.2v5* | sco5v6*)
- # Note: We can NOT use -z defs as we might desire, because we do not
+ # Note: We CANNOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
- no_undefined_flag='${wl}-z,text'
- allow_undefined_flag='${wl}-z,nodefs'
+ no_undefined_flag='$wl-z,text'
+ allow_undefined_flag='$wl-z,nodefs'
archive_cmds_need_lc=no
hardcode_shlibpath_var=no
- hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_flag_spec='$wl-R,$libdir'
hardcode_libdir_separator=':'
link_all_deplibs=yes
- export_dynamic_flag_spec='${wl}-Bexport'
+ export_dynamic_flag_spec='$wl-Bexport'
runpath_var='LD_RUN_PATH'
- if test "$GCC" = yes; then
- archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
@@ -9354,10 +10857,10 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
;;
esac
- if test x$host_vendor = xsni; then
+ if test sni = "$host_vendor"; then
case $host in
sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- export_dynamic_flag_spec='${wl}-Blargedynsym'
+ export_dynamic_flag_spec='$wl-Blargedynsym'
;;
esac
fi
@@ -9365,7 +10868,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
{ $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 no = "$ld_shlibs" && can_build_shared=no
with_gnu_ld=$with_gnu_ld
@@ -9391,7 +10894,7 @@ x|xyes)
# Assume -lc should be added
archive_cmds_need_lc=yes
- if test "$enable_shared" = yes && test "$GCC" = yes; then
+ if test yes,yes = "$GCC,$enable_shared"; then
case $archive_cmds in
*'~'*)
# FIXME: we may have to deal with multi-command sequences.
@@ -9606,14 +11109,14 @@ esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
$as_echo_n "checking dynamic linker characteristics... " >&6; }
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
case $host_os in
- darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
- *) lt_awk_arg="/^libraries:/" ;;
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
esac
case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
- *) lt_sed_strip_eq="s,=/,/,g" ;;
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
case $lt_search_path_spec in
@@ -9629,28 +11132,35 @@ if test "$GCC" = yes; then
;;
esac
# Ok, now we have the path, separated by spaces, we can step through it
- # and add multilib dir if necessary.
+ # and add multilib dir if necessary...
lt_tmp_lt_search_path_spec=
- lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
for lt_sys_path in $lt_search_path_spec; do
- if test -d "$lt_sys_path/$lt_multi_os_dir"; then
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
- else
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
test -d "$lt_sys_path" && \
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
fi
done
lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
- lt_foo="";
- lt_count=0;
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
for (lt_i = NF; lt_i > 0; lt_i--) {
if ($lt_i != "" && $lt_i != ".") {
if ($lt_i == "..") {
lt_count++;
} else {
if (lt_count == 0) {
- lt_foo="/" $lt_i lt_foo;
+ lt_foo = "/" $lt_i lt_foo;
} else {
lt_count--;
}
@@ -9664,7 +11174,7 @@ BEGIN {RS=" "; FS="/|\n";} {
# for these hosts.
case $host_os in
mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
- $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
esac
sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
else
@@ -9673,7 +11183,7 @@ fi
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -9690,14 +11200,16 @@ hardcode_into_libs=no
# flags to be left without arguments
need_version=unknown
+
+
case $host_os in
aix3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
shlibpath_var=LIBPATH
# AIX 3 has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}${shared_ext}$major'
+ soname_spec='$libname$release$shared_ext$major'
;;
aix[4-9]*)
@@ -9705,41 +11217,91 @@ aix[4-9]*)
need_lib_prefix=no
need_version=no
hardcode_into_libs=yes
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 supports IA64
- library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
else
# With GCC up to 2.95.x, collect2 would create an import file
# for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
# development snapshots of GCC prior to 3.0.
case $host_os in
aix4 | aix4.[01] | aix4.[01].*)
if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
echo ' yes '
- echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
:
else
can_build_shared=no
fi
;;
esac
- # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
# soname into executable. Probably we can add versioning support to
# collect2, so additional links can be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
# If using run time linking (on AIX 4.2 or later) use lib<name>.so
# instead of lib<name>.a to let people know that these are not
# typical AIX shared libraries.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a(lib.so.V)'
# We preserve .a as extension for shared libraries through AIX4.2
# and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}${shared_ext}$major'
- fi
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
shlibpath_var=LIBPATH
fi
;;
@@ -9749,18 +11311,18 @@ amigaos*)
powerpc)
# Since July 2007 AmigaOS4 officially supports .so libraries.
# When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
;;
m68k)
library_names_spec='$libname.ixlibrary $libname.a'
# Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
;;
esac
;;
beos*)
- library_names_spec='${libname}${shared_ext}'
+ library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"
shlibpath_var=LIBRARY_PATH
;;
@@ -9768,8 +11330,8 @@ beos*)
bsdi[45]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -9781,7 +11343,7 @@ bsdi[45]*)
cygwin* | mingw* | pw32* | cegcc*)
version_type=windows
- shrext_cmds=".dll"
+ shrext_cmds=.dll
need_version=no
need_lib_prefix=no
@@ -9790,8 +11352,8 @@ cygwin* | mingw* | pw32* | cegcc*)
# gcc
library_names_spec='$libname.dll.a'
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname~
@@ -9807,17 +11369,17 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
;;
mingw* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
- soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
@@ -9826,8 +11388,8 @@ cygwin* | mingw* | pw32* | cegcc*)
*,cl*)
# Native MSVC
libname_spec='$name'
- soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
- library_names_spec='${libname}.dll.lib'
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
case $build_os in
mingw*)
@@ -9854,7 +11416,7 @@ cygwin* | mingw* | pw32* | cegcc*)
sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
;;
*)
- sys_lib_search_path_spec="$LIB"
+ sys_lib_search_path_spec=$LIB
if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
# It is most probably a Windows format PATH.
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -9867,8 +11429,8 @@ cygwin* | mingw* | pw32* | cegcc*)
esac
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname'
@@ -9881,7 +11443,7 @@ cygwin* | mingw* | pw32* | cegcc*)
*)
# Assume MSVC wrapper
- library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
esac
@@ -9894,11 +11456,11 @@ darwin* | rhapsody*)
version_type=darwin
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
- soname_spec='${libname}${release}${major}$shared_ext'
+ library_names_spec='$libname$release$versuffix$shared_ext $libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+ shrext_cmds='`test .$module = .yes && echo .bundle || echo .dylib`'
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
@@ -9908,8 +11470,8 @@ dgux*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -9924,17 +11486,31 @@ freebsd* | dragonfly*)
*) objformat=elf ;;
esac
fi
- version_type=freebsd-$objformat
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
need_version=no
need_lib_prefix=no
;;
freebsd-*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
@@ -9962,10 +11538,10 @@ haiku*)
need_lib_prefix=no
need_version=no
dynamic_linker="$host_os runtime_loader"
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=yes
+ shlibpath_overrides_runpath=no
sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
hardcode_into_libs=yes
;;
@@ -9983,14 +11559,15 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- if test "X$HPUX_IA64_MODE" = X32; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
else
sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
fi
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
shrext_cmds='.sl'
@@ -9998,8 +11575,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
@@ -10008,8 +11585,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
;;
esac
# HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -10022,8 +11599,8 @@ interix[3-9]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -10034,7 +11611,7 @@ irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
*)
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
version_type=linux # correct to gnu/linux during the next big refactor
else
version_type=irix
@@ -10042,8 +11619,8 @@ irix5* | irix6* | nonstopux*)
esac
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
case $host_os in
irix5* | nonstopux*)
libsuff= shlibsuff=
@@ -10062,8 +11639,8 @@ irix5* | irix6* | nonstopux*)
esac
shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
hardcode_into_libs=yes
;;
@@ -10072,13 +11649,33 @@ linux*oldld* | linux*aout* | linux*coff*)
dynamic_linker=no
;;
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -10122,7 +11719,12 @@ fi
# before this can be enabled.
hardcode_into_libs=yes
- # Append ld.so.conf contents to the search path
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -10137,29 +11739,17 @@ fi
dynamic_linker='GNU/Linux ld.so'
;;
-netbsdelf*-gnu)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='NetBSD ld.elf_so'
- ;;
-
netbsd*)
version_type=sunos
need_lib_prefix=no
need_version=no
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
dynamic_linker='NetBSD (a.out) ld.so'
else
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='NetBSD ld.elf_so'
fi
shlibpath_var=LD_LIBRARY_PATH
@@ -10169,7 +11759,7 @@ netbsd*)
newsos6)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
;;
@@ -10178,58 +11768,68 @@ newsos6)
version_type=qnx
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='ldqnx.so'
;;
-openbsd*)
+openbsd* | bitrig*)
version_type=sunos
- sys_lib_dlsearch_path_spec="/usr/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib
need_lib_prefix=no
- # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
- case $host_os in
- openbsd3.3 | openbsd3.3.*) need_version=yes ;;
- *) need_version=no ;;
- esac
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case $host_os in
- openbsd2.[89] | openbsd2.[89].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
else
- shlibpath_overrides_runpath=yes
+ need_version=yes
fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
;;
os2*)
libname_spec='$name'
- shrext_cmds=".dll"
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
need_lib_prefix=no
- library_names_spec='$libname${shared_ext} $libname.a'
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
;;
osf3* | osf4* | osf5*)
version_type=osf
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
rdos*)
@@ -10240,8 +11840,8 @@ solaris*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
@@ -10251,11 +11851,11 @@ solaris*)
sunos4*)
version_type=sunos
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
need_lib_prefix=no
fi
need_version=yes
@@ -10263,8 +11863,8 @@ sunos4*)
sysv4 | sysv4.3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
case $host_vendor in
sni)
@@ -10285,24 +11885,24 @@ sysv4 | sysv4.3*)
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
- soname_spec='$libname${shared_ext}.$major'
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
shlibpath_var=LD_LIBRARY_PATH
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- version_type=freebsd-elf
+ version_type=sco
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
else
sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -10320,7 +11920,7 @@ tpf*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
@@ -10328,8 +11928,8 @@ tpf*)
uts4*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -10339,20 +11939,35 @@ uts4*)
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
$as_echo "$dynamic_linker" >&6; }
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
- sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
- sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
fi
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
@@ -10449,15 +12064,15 @@ $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
hardcode_action=
if test -n "$hardcode_libdir_flag_spec" ||
test -n "$runpath_var" ||
- test "X$hardcode_automatic" = "Xyes" ; then
+ test yes = "$hardcode_automatic"; then
# We can hardcode non-existent directories.
- if test "$hardcode_direct" != no &&
+ if test no != "$hardcode_direct" &&
# If the only mechanism to avoid hardcoding is shlibpath_var, we
# have to relink, otherwise we might link with an installed library
# when we should be linking with a yet-to-be-installed one
- ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
- test "$hardcode_minus_L" != no; then
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
+ test no != "$hardcode_minus_L"; then
# Linking always hardcodes the temporary library directory.
hardcode_action=relink
else
@@ -10472,12 +12087,12 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
$as_echo "$hardcode_action" >&6; }
-if test "$hardcode_action" = relink ||
- test "$inherit_rpath" = yes; then
+if test relink = "$hardcode_action" ||
+ test yes = "$inherit_rpath"; then
# Fast installation is not supported
enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
# Fast installation is not necessary
enable_fast_install=needless
fi
@@ -10487,7 +12102,7 @@ fi
- if test "x$enable_dlopen" != xyes; then
+ if test yes != "$enable_dlopen"; then
enable_dlopen=unknown
enable_dlopen_self=unknown
enable_dlopen_self_static=unknown
@@ -10497,23 +12112,23 @@ else
case $host_os in
beos*)
- lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen=load_add_on
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
;;
mingw* | pw32* | cegcc*)
- lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen=LoadLibrary
lt_cv_dlopen_libs=
;;
cygwin*)
- lt_cv_dlopen="dlopen"
+ lt_cv_dlopen=dlopen
lt_cv_dlopen_libs=
;;
darwin*)
- # if libdl is installed we need to link against it
+ # if libdl is installed we need to link against it
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
if ${ac_cv_lib_dl_dlopen+:} false; then :
@@ -10551,10 +12166,10 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
else
- lt_cv_dlopen="dyld"
+ lt_cv_dlopen=dyld
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
@@ -10562,10 +12177,18 @@ fi
;;
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
*)
ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
if test "x$ac_cv_func_shl_load" = xyes; then :
- lt_cv_dlopen="shl_load"
+ lt_cv_dlopen=shl_load
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
$as_echo_n "checking for shl_load in -ldld... " >&6; }
@@ -10604,11 +12227,11 @@ fi
{ $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 "x$ac_cv_lib_dld_shl_load" = xyes; then :
- lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+ lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
else
ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
if test "x$ac_cv_func_dlopen" = xyes; then :
- lt_cv_dlopen="dlopen"
+ lt_cv_dlopen=dlopen
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
@@ -10647,7 +12270,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
$as_echo_n "checking for dlopen in -lsvld... " >&6; }
@@ -10686,7 +12309,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
- lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
$as_echo_n "checking for dld_link in -ldld... " >&6; }
@@ -10725,7 +12348,7 @@ fi
{ $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 "x$ac_cv_lib_dld_dld_link" = xyes; then :
- lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+ lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
fi
@@ -10746,21 +12369,21 @@ fi
;;
esac
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
+ if test no = "$lt_cv_dlopen"; then
enable_dlopen=no
+ else
+ enable_dlopen=yes
fi
case $lt_cv_dlopen in
dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
- save_LIBS="$LIBS"
+ save_LIBS=$LIBS
LIBS="$lt_cv_dlopen_libs $LIBS"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
@@ -10768,7 +12391,7 @@ $as_echo_n "checking whether a program can dlopen itself... " >&6; }
if ${lt_cv_dlopen_self+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test "$cross_compiling" = yes; then :
+ if test yes = "$cross_compiling"; then :
lt_cv_dlopen_self=cross
else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -10815,9 +12438,9 @@ else
# endif
#endif
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
correspondingly for the symbols needed. */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
int fnord () __attribute__((visibility("default")));
#endif
@@ -10847,7 +12470,7 @@ _LT_EOF
(eval $ac_link) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ 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
@@ -10867,14 +12490,14 @@ fi
{ $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
+ if test yes = "$lt_cv_dlopen_self"; then
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
{ $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 ${lt_cv_dlopen_self_static+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test "$cross_compiling" = yes; then :
+ if test yes = "$cross_compiling"; then :
lt_cv_dlopen_self_static=cross
else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -10921,9 +12544,9 @@ else
# endif
#endif
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
correspondingly for the symbols needed. */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
int fnord () __attribute__((visibility("default")));
#endif
@@ -10953,7 +12576,7 @@ _LT_EOF
(eval $ac_link) 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ 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
@@ -10974,9 +12597,9 @@ fi
$as_echo "$lt_cv_dlopen_self_static" >&6; }
fi
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
;;
esac
@@ -11020,7 +12643,7 @@ else
# FIXME - insert some real tests, host_os isn't really good enough
case $host_os in
darwin*)
- if test -n "$STRIP" ; then
+ if test -n "$STRIP"; then
striplib="$STRIP -x"
old_striplib="$STRIP -S"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
@@ -11048,7 +12671,7 @@ fi
- # Report which library types will actually be built
+ # Report what library types will actually be built
{ $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:${as_lineno-$LINENO}: result: $can_build_shared" >&5
@@ -11056,13 +12679,13 @@ $as_echo "$can_build_shared" >&6; }
{ $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
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
@@ -11070,8 +12693,12 @@ $as_echo_n "checking whether to build shared libraries... " >&6; }
;;
aix[4-9]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -11081,7 +12708,7 @@ $as_echo "$enable_shared" >&6; }
{ $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
+ test yes = "$enable_shared" || enable_static=yes
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
$as_echo "$enable_static" >&6; }
@@ -11095,7 +12722,7 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-CC="$lt_save_CC"
+CC=$lt_save_CC
@@ -11129,539 +12756,601 @@ ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-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:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
done
- done
-IFS=$as_save_IFS
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
fi
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+
+if test "$GCC" = yes; then :
+
+
+
+
+for flag in -Wall -Wextra; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-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:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $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 ;;
+if ${AM_CFLAGS+:} false; then :
+
+ case " $AM_CFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains \$flag"; } >&5
+ (: AM_CFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+
+ AM_CFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ :
fi
+done
- fi
-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:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+
+
+
+
+for flag in -fexceptions; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ eval "$as_CACHEVAR=no"
fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+if ${AM_CFLAGS+:} false; then :
+
+ case " $AM_CFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains \$flag"; } >&5
+ (: AM_CFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl.exe
- 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:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
+
+ AM_CFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ :
fi
+done
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl.exe
-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:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+
+
+
+
+for flag in -fno-strict-aliasing -Wmissing-prototypes -Wstrict-prototypes; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-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:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ eval "$as_CACHEVAR=no"
fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+if ${AM_CFLAGS+:} false; then :
- test -n "$ac_ct_CC" && break
-done
+ case " $AM_CFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains \$flag"; } >&5
+ (: AM_CFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $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 ;;
+ as_fn_append AM_CFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
+else
-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:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-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:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ AM_CFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
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; }
+
+fi
+
+else
+ :
+fi
+
done
-{ $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 ${ac_cv_c_compiler_gnu+:} false; then :
+
+
+
+
+for flag in -pedantic -Wduplicated-cond -Wduplicated-branches -Wlogical-op; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
+
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror $flag"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-
-int
-main ()
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
+int main(void) { return 0; }
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_compiler_gnu=yes
+ eval "$as_CACHEVAR=yes"
else
- ac_compiler_gnu=no
+ eval "$as_CACHEVAR=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
+ CFLAGS=$ax_check_save_flags
fi
-{ $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
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+
+if ${AM_CFLAGS+:} false; then :
+
+ case " $AM_CFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains \$flag"; } >&5
+ (: AM_CFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
else
- GCC=
+
+ AM_CFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; 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 confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ :
+fi
-int
-main ()
-{
+done
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-else
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int
-main ()
-{
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-else
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int
-main ()
-{
+for flag in -Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
- ;
- return 0;
-}
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+
+if ${AM_CFLAGS+:} false; then :
+
+ case " $AM_CFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains \$flag"; } >&5
+ (: AM_CFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_CFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
fi
-{ $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
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
+
else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
+ :
fi
-{ $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 ${ac_cv_prog_cc_c89+:} false; then :
+
+done
+
+
+
+
+
+for flag in -Wshadow -Wformat=2 -Wmisleading-indentation; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
+$as_echo_n "checking whether C compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+ ax_check_save_flags=$CFLAGS
+ CFLAGS="$CFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+if ${AM_CFLAGS+:} false; then :
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+ case " $AM_CFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains \$flag"; } >&5
+ (: AM_CFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_CFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
-}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
+else
+ :
fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $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:${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 :
+
+done
fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
@@ -11914,25 +13603,153 @@ else
CXXFLAGS=
fi
fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+depcc="$CXX" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $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
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
func_stripname_cnf ()
{
- case ${2} in
- .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
- *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ case $2 in
+ .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;;
+ *) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;;
esac
} # func_stripname_cnf
- if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
- ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
- (test "X$CXX" != "Xg++"))) ; then
+ if test -n "$CXX" && ( test no != "$CXX" &&
+ ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+ (test g++ != "$CXX"))); then
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -12060,11 +13877,11 @@ as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
See \`config.log' for more details" "$LINENO" 5; }
fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
else
_lt_caught_CXX_error=yes
@@ -12111,7 +13928,7 @@ objext_CXX=$objext
# the CXX compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
+if test yes != "$_lt_caught_CXX_error"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;"
@@ -12172,46 +13989,39 @@ $RM -r conftest*
CFLAGS=$CXXFLAGS
compiler=$CC
compiler_CXX=$CC
- for cc_temp in $compiler""; do
- case $cc_temp in
- compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
- distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
- \-*) ;;
- *) break;;
- esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+ func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
if test -n "$compiler"; then
# We don't want -fno-exception when compiling C++ code, so set the
# no_builtin_flag separately
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
else
lt_prog_compiler_no_builtin_flag_CXX=
fi
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
# Set up default GNU C++ configuration
# Check whether --with-gnu-ld was given.
if test "${with_gnu_ld+set}" = set; then :
- withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+ withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
else
with_gnu_ld=no
fi
ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
# Check if gcc -print-prog-name=ld gives a path.
{ $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*)
- # gcc leaves a trailing carriage return which upsets mingw
+ # gcc leaves a trailing carriage return, which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -12225,7 +14035,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
done
- test -z "$LD" && LD="$ac_prog"
+ test -z "$LD" && LD=$ac_prog
;;
"")
# If it fails, then pretend we aren't using GCC.
@@ -12236,7 +14046,7 @@ $as_echo_n "checking for ld used by $CC... " >&6; }
with_gnu_ld=unknown
;;
esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
$as_echo_n "checking for GNU ld... " >&6; }
else
@@ -12247,32 +14057,32 @@ if ${lt_cv_path_LD+:} false; then :
$as_echo_n "(cached) " >&6
else
if test -z "$LD"; then
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
+ lt_cv_path_LD=$ac_dir/$ac_prog
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
- test "$with_gnu_ld" != no && break
+ test no != "$with_gnu_ld" && break
;;
*)
- test "$with_gnu_ld" != yes && break
+ test yes != "$with_gnu_ld" && break
;;
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
fi
fi
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
if test -n "$LD"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
$as_echo "$LD" >&6; }
@@ -12308,22 +14118,22 @@ with_gnu_ld=$lt_cv_prog_gnu_ld
# Check if GNU C++ uses GNU ld as the underlying linker, since the
# archiving commands below assume that GNU ld is being used.
- if test "$with_gnu_ld" = yes; then
- archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ if test yes = "$with_gnu_ld"; then
+ archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
- export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+ export_dynamic_flag_spec_CXX='$wl--export-dynamic'
# If archive_cmds runs LD, not CC, wlarc should be empty
# XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
# investigate it a little bit more. (MM)
- wlarc='${wl}'
+ wlarc='$wl'
# ancient GNU ld didn't support --whole-archive et. al.
if eval "`$CC -print-prog-name=ld` --help 2>&1" |
$GREP 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
whole_archive_flag_spec_CXX=
fi
@@ -12360,18 +14170,30 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
ld_shlibs_CXX=no
;;
aix[4-9]*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
- no_entry_flag=""
+ no_entry_flag=
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
for ld_flag in $LDFLAGS; do
case $ld_flag in
@@ -12381,6 +14203,13 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
;;
esac
done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
;;
esac
@@ -12399,13 +14228,21 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
hardcode_direct_absolute_CXX=yes
hardcode_libdir_separator_CXX=':'
link_all_deplibs_CXX=yes
- file_list_spec_CXX='${wl}-f,'
+ file_list_spec_CXX='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ hardcode_direct_CXX=no
+ hardcode_direct_absolute_CXX=no
+ ;;
+ esac
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
case $host_os in aix4.[012]|aix4.[012].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
- collect2name=`${CC} -print-prog-name=collect2`
+ collect2name=`$CC -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
@@ -12423,36 +14260,44 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
fi
esac
shared_flag='-shared'
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag="$shared_flag "'${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag=$shared_flag' $wl-G'
fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
else
# not using gcc
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
else
- shared_flag='${wl}-bM:SRE'
+ shared_flag='$wl-bM:SRE'
fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
fi
fi
- export_dynamic_flag_spec_CXX='${wl}-bexpall'
+ export_dynamic_flag_spec_CXX='$wl-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to
# export.
always_export_symbols_CXX=yes
- if test "$aix_use_runtimelinking" = yes; then
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
- allow_undefined_flag_CXX='-berok'
+ # The "-G" linker flag allows undefined symbols.
+ no_undefined_flag_CXX='-bernotok'
# Determine the default libpath from the value encoded in an empty
# executable.
- if test "${lt_cv_aix_libpath+set}" = set; then
+ if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
if ${lt_cv_aix_libpath__CXX+:} false; then :
@@ -12487,7 +14332,7 @@ fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath__CXX"; then
- lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+ lt_cv_aix_libpath__CXX=/usr/lib:/lib
fi
fi
@@ -12495,18 +14340,18 @@ fi
aix_libpath=$lt_cv_aix_libpath__CXX
fi
- hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
else
- if test "$host_cpu" = ia64; then
- hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+ if test ia64 = "$host_cpu"; then
+ hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib'
allow_undefined_flag_CXX="-z nodefs"
- 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"
+ 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.
- if test "${lt_cv_aix_libpath+set}" = set; then
+ if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
if ${lt_cv_aix_libpath__CXX+:} false; then :
@@ -12541,7 +14386,7 @@ fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test -z "$lt_cv_aix_libpath__CXX"; then
- lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+ lt_cv_aix_libpath__CXX=/usr/lib:/lib
fi
fi
@@ -12549,22 +14394,34 @@ fi
aix_libpath=$lt_cv_aix_libpath__CXX
fi
- hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
- no_undefined_flag_CXX=' ${wl}-bernotok'
- allow_undefined_flag_CXX=' ${wl}-berok'
- if test "$with_gnu_ld" = yes; then
+ no_undefined_flag_CXX=' $wl-bernotok'
+ allow_undefined_flag_CXX=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
# We only use this code for GNU lds that support --whole-archive.
- whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
whole_archive_flag_spec_CXX='$convenience'
fi
archive_cmds_need_lc_CXX=yes
- # This is similar to how AIX traditionally builds its shared
- # libraries.
- archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared
+ # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+ archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d'
fi
fi
;;
@@ -12574,7 +14431,7 @@ fi
allow_undefined_flag_CXX=unsupported
# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
- archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
else
ld_shlibs_CXX=no
fi
@@ -12602,57 +14459,58 @@ fi
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
- archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
- else
- $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
+ archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true'
enable_shared_with_static_runtimes_CXX=yes
# Don't use ranlib
old_postinstall_cmds_CXX='chmod 644 $oldlib'
postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile="$lt_outputfile.exe"
- lt_tool_outputfile="$lt_tool_outputfile.exe"
- ;;
- esac~
- func_to_tool_file "$lt_outputfile"~
- if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
;;
*)
# g++
# _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
# as there is no search path for DLLs.
hardcode_libdir_flag_spec_CXX='-L$libdir'
- export_dynamic_flag_spec_CXX='${wl}--export-all-symbols'
+ export_dynamic_flag_spec_CXX='$wl--export-all-symbols'
allow_undefined_flag_CXX=unsupported
always_export_symbols_CXX=no
enable_shared_with_static_runtimes_CXX=yes
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is; otherwise, prepend...
- archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ archive_expsym_cmds_CXX='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
ld_shlibs_CXX=no
fi
@@ -12666,27 +14524,27 @@ fi
hardcode_direct_CXX=no
hardcode_automatic_CXX=yes
hardcode_shlibpath_var_CXX=unsupported
- if test "$lt_cv_ld_force_load" = "yes"; then
- whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ if test yes = "$lt_cv_ld_force_load"; then
+ whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
else
whole_archive_flag_spec_CXX=''
fi
link_all_deplibs_CXX=yes
- allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+ allow_undefined_flag_CXX=$_lt_dar_allow_undefined
case $cc_basename in
- ifort*) _lt_dar_can_shared=yes ;;
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
*) _lt_dar_can_shared=$GCC ;;
esac
- if test "$_lt_dar_can_shared" = "yes"; then
+ if test yes = "$_lt_dar_can_shared"; then
output_verbose_link_cmd=func_echo_all
- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
- if test "$lt_cv_apple_cc_single_mod" != "yes"; then
- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ if test yes != "$lt_cv_apple_cc_single_mod"; then
+ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+ archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
fi
else
@@ -12695,6 +14553,34 @@ fi
;;
+ os2*)
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ hardcode_minus_L_CXX=yes
+ allow_undefined_flag_CXX=unsupported
+ shrext_cmds=.dll
+ archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes_CXX=yes
+ ;;
+
dgux*)
case $cc_basename in
ec++*)
@@ -12730,14 +14616,14 @@ fi
;;
haiku*)
- archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
link_all_deplibs_CXX=yes
;;
hpux9*)
- hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
hardcode_libdir_separator_CXX=:
- export_dynamic_flag_spec_CXX='${wl}-E'
+ export_dynamic_flag_spec_CXX='$wl-E'
hardcode_direct_CXX=yes
hardcode_minus_L_CXX=yes # Not in the search PATH,
# but as the default
@@ -12749,7 +14635,7 @@ fi
ld_shlibs_CXX=no
;;
aCC*)
- archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
@@ -12758,11 +14644,11 @@ fi
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes; then
- archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ if test yes = "$GXX"; then
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
else
# FIXME: insert proper C++ library support
ld_shlibs_CXX=no
@@ -12772,15 +14658,15 @@ fi
;;
hpux10*|hpux11*)
- if test $with_gnu_ld = no; then
- hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
hardcode_libdir_separator_CXX=:
case $host_cpu in
hppa*64*|ia64*)
;;
*)
- export_dynamic_flag_spec_CXX='${wl}-E'
+ export_dynamic_flag_spec_CXX='$wl-E'
;;
esac
fi
@@ -12806,13 +14692,13 @@ fi
aCC*)
case $host_cpu in
hppa*64*)
- archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
- archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
- archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
# Commands to make compiler produce verbose output that lists
@@ -12823,20 +14709,20 @@ fi
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes; then
- if test $with_gnu_ld = no; then
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
case $host_cpu in
hppa*64*)
- archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
- archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
- archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
fi
@@ -12851,22 +14737,22 @@ fi
interix[3-9]*)
hardcode_direct_CXX=no
hardcode_shlibpath_var_CXX=no
- hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
- export_dynamic_flag_spec_CXX='${wl}-E'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='$wl-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
- archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
irix5* | irix6*)
case $cc_basename in
CC*)
# SGI C++
- archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
# Archives containing C++ object files must be created using
# "CC -ar", where "CC" is the IRIX C++ compiler. This is
@@ -12875,17 +14761,17 @@ fi
old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
;;
*)
- if test "$GXX" = yes; then
- if test "$with_gnu_ld" = no; then
- archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
else
- archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
fi
fi
link_all_deplibs_CXX=yes
;;
esac
- hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
hardcode_libdir_separator_CXX=:
inherit_rpath_CXX=yes
;;
@@ -12898,8 +14784,8 @@ fi
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
- archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
@@ -12908,10 +14794,10 @@ fi
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
- hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
- export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='$wl--export-dynamic'
# Archives containing C++ object files must be created using
# "CC -Bstatic", where "CC" is the KAI C++ compiler.
@@ -12925,59 +14811,59 @@ fi
# earlier do not add the objects themselves.
case `$CC -V 2>&1` in
*"Version 7."*)
- archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 8.0 or newer
tmp_idyn=
case $host_cpu in
ia64*) tmp_idyn=' -i_dynamic';;
esac
- archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
archive_cmds_need_lc_CXX=no
- hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
- export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
- whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+ whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
;;
pgCC* | pgcpp*)
# Portland Group C++ compiler
case `$CC -V` in
*pgCC\ [1-5].* | *pgcpp\ [1-5].*)
prelink_cmds_CXX='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
- compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
old_archive_cmds_CXX='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
- $RANLIB $oldlib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
archive_cmds_CXX='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
archive_expsym_cmds_CXX='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 6 and above use weak symbols
- archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
- archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
- hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
- export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
- whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir'
+ export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+ whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
;;
cxx*)
# Compaq C++
- archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
runpath_var=LD_RUN_PATH
hardcode_libdir_flag_spec_CXX='-rpath $libdir'
@@ -12991,18 +14877,18 @@ fi
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
;;
xl* | mpixl* | bgxl*)
# IBM XL 8.0 on PPC, with GNU ld
- hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
- export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
- archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+ export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+ archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
;;
*)
@@ -13010,10 +14896,10 @@ fi
*Sun\ C*)
# Sun C++ 5.9
no_undefined_flag_CXX=' -zdefs'
- archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
hardcode_libdir_flag_spec_CXX='-R$libdir'
- whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
compiler_needs_object_CXX=yes
# Not sure whether something based on
@@ -13071,22 +14957,17 @@ fi
ld_shlibs_CXX=yes
;;
- openbsd2*)
- # C++ shared libraries are fairly broken
- ld_shlibs_CXX=no
- ;;
-
- openbsd*)
+ openbsd* | bitrig*)
if test -f /usr/libexec/ld.so; then
hardcode_direct_CXX=yes
hardcode_shlibpath_var_CXX=no
hardcode_direct_absolute_CXX=yes
archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
- hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
- export_dynamic_flag_spec_CXX='${wl}-E'
- whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+ export_dynamic_flag_spec_CXX='$wl-E'
+ whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
fi
output_verbose_link_cmd=func_echo_all
else
@@ -13102,9 +14983,9 @@ fi
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
- archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
hardcode_libdir_separator_CXX=:
# Archives containing C++ object files must be created using
@@ -13122,17 +15003,17 @@ fi
cxx*)
case $host in
osf3*)
- allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
- archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
- hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
+ archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
;;
*)
allow_undefined_flag_CXX=' -expect_unresolved \*'
- archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
- echo "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
- $RM $lib.exp'
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+ $RM $lib.exp'
hardcode_libdir_flag_spec_CXX='-rpath $libdir'
;;
esac
@@ -13147,21 +15028,21 @@ fi
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes && test "$with_gnu_ld" = no; then
- allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
case $host in
osf3*)
- archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
;;
*)
- archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
;;
esac
- hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
hardcode_libdir_separator_CXX=:
# Commands to make compiler produce verbose output that lists
@@ -13207,9 +15088,9 @@ fi
# Sun C++ 4.2, 5.x and Centerline C++
archive_cmds_need_lc_CXX=yes
no_undefined_flag_CXX=' -zdefs'
- archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
hardcode_libdir_flag_spec_CXX='-R$libdir'
hardcode_shlibpath_var_CXX=no
@@ -13217,7 +15098,7 @@ fi
solaris2.[0-5] | solaris2.[0-5].*) ;;
*)
# The compiler driver will combine and reorder linker options,
- # but understands `-z linker_flag'.
+ # but understands '-z linker_flag'.
# Supported since Solaris 2.6 (maybe 2.5.1?)
whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
;;
@@ -13234,30 +15115,30 @@ fi
;;
gcx*)
# Green Hills C++ Compiler
- archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
# The C++ compiler must be used to create the archive.
old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
;;
*)
# GNU C++ compiler with Solaris linker
- if test "$GXX" = yes && test "$with_gnu_ld" = no; then
- no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ no_undefined_flag_CXX=' $wl-z ${wl}defs'
if $CC --version | $GREP -v '^2\.7' > /dev/null; then
- archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
else
- # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # g++ 2.7 appears to require '-G' NOT '-shared' on this
# platform.
- archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
@@ -13265,11 +15146,11 @@ fi
output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
fi
- hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+ hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir'
case $host_os in
solaris2.[0-5] | solaris2.[0-5].*) ;;
*)
- whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
;;
esac
fi
@@ -13278,52 +15159,52 @@ fi
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
- no_undefined_flag_CXX='${wl}-z,text'
+ no_undefined_flag_CXX='$wl-z,text'
archive_cmds_need_lc_CXX=no
hardcode_shlibpath_var_CXX=no
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
- archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
sysv5* | sco3.2v5* | sco5v6*)
- # Note: We can NOT use -z defs as we might desire, because we do not
+ # Note: We CANNOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
- no_undefined_flag_CXX='${wl}-z,text'
- allow_undefined_flag_CXX='${wl}-z,nodefs'
+ no_undefined_flag_CXX='$wl-z,text'
+ allow_undefined_flag_CXX='$wl-z,nodefs'
archive_cmds_need_lc_CXX=no
hardcode_shlibpath_var_CXX=no
- hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+ hardcode_libdir_flag_spec_CXX='$wl-R,$libdir'
hardcode_libdir_separator_CXX=':'
link_all_deplibs_CXX=yes
- export_dynamic_flag_spec_CXX='${wl}-Bexport'
+ export_dynamic_flag_spec_CXX='$wl-Bexport'
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
- archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
- '"$old_archive_cmds_CXX"
+ '"$old_archive_cmds_CXX"
reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
- '"$reload_cmds_CXX"
+ '"$reload_cmds_CXX"
;;
*)
- archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
@@ -13355,10 +15236,10 @@ fi
{ $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 no = "$ld_shlibs_CXX" && can_build_shared=no
- GCC_CXX="$GXX"
- LD_CXX="$LD"
+ GCC_CXX=$GXX
+ LD_CXX=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -13402,13 +15283,13 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
pre_test_object_deps_done=no
for p in `eval "$output_verbose_link_cmd"`; do
- case ${prev}${p} in
+ case $prev$p in
-L* | -R* | -l*)
# Some compilers place space between "-{L,R}" and the path.
# Remove the space.
- if test $p = "-L" ||
- test $p = "-R"; then
+ if test x-L = "$p" ||
+ test x-R = "$p"; then
prev=$p
continue
fi
@@ -13424,16 +15305,16 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
case $p in
=*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
esac
- if test "$pre_test_object_deps_done" = no; then
- case ${prev} in
+ if test no = "$pre_test_object_deps_done"; then
+ case $prev in
-L | -R)
# Internal compiler library paths should come after those
# provided the user. The postdeps already come after the
# user supplied libs so there is no need to process them.
if test -z "$compiler_lib_search_path_CXX"; then
- compiler_lib_search_path_CXX="${prev}${p}"
+ compiler_lib_search_path_CXX=$prev$p
else
- compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p"
fi
;;
# The "-l" case would never come before the object being
@@ -13441,9 +15322,9 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
esac
else
if test -z "$postdeps_CXX"; then
- postdeps_CXX="${prev}${p}"
+ postdeps_CXX=$prev$p
else
- postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+ postdeps_CXX="${postdeps_CXX} $prev$p"
fi
fi
prev=
@@ -13458,15 +15339,15 @@ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
continue
fi
- if test "$pre_test_object_deps_done" = no; then
+ if test no = "$pre_test_object_deps_done"; then
if test -z "$predep_objects_CXX"; then
- predep_objects_CXX="$p"
+ predep_objects_CXX=$p
else
predep_objects_CXX="$predep_objects_CXX $p"
fi
else
if test -z "$postdep_objects_CXX"; then
- postdep_objects_CXX="$p"
+ postdep_objects_CXX=$p
else
postdep_objects_CXX="$postdep_objects_CXX $p"
fi
@@ -13496,51 +15377,6 @@ interix[3-9]*)
postdep_objects_CXX=
postdeps_CXX=
;;
-
-linux*)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- # Sun C++ 5.9
-
- # The more standards-conforming stlport4 library is
- # incompatible with the Cstd library. Avoid specifying
- # it if it's in CXXFLAGS. Ignore libCrun as
- # -library=stlport4 depends on it.
- case " $CXX $CXXFLAGS " in
- *" -library=stlport4 "*)
- solaris_use_stlport4=yes
- ;;
- esac
-
- if test "$solaris_use_stlport4" != yes; then
- postdeps_CXX='-library=Cstd -library=Crun'
- fi
- ;;
- esac
- ;;
-
-solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # The more standards-conforming stlport4 library is
- # incompatible with the Cstd library. Avoid specifying
- # it if it's in CXXFLAGS. Ignore libCrun as
- # -library=stlport4 depends on it.
- case " $CXX $CXXFLAGS " in
- *" -library=stlport4 "*)
- solaris_use_stlport4=yes
- ;;
- esac
-
- # Adding this requires a known-good setup of shared libraries for
- # Sun compiler versions before 5.6, else PIC objects from an old
- # archive will be linked into the output, leading to subtle bugs.
- if test "$solaris_use_stlport4" != yes; then
- postdeps_CXX='-library=Cstd -library=Crun'
- fi
- ;;
- esac
- ;;
esac
@@ -13549,7 +15385,7 @@ case " $postdeps_CXX " in
esac
compiler_lib_search_dirs_CXX=
if test -n "${compiler_lib_search_path_CXX}"; then
- compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'`
fi
@@ -13588,17 +15424,18 @@ lt_prog_compiler_static_CXX=
# C++ specific cases for pic, static, wl, etc.
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
lt_prog_compiler_wl_CXX='-Wl,'
lt_prog_compiler_static_CXX='-static'
case $host_os in
aix*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
lt_prog_compiler_static_CXX='-Bstatic'
fi
+ lt_prog_compiler_pic_CXX='-fPIC'
;;
amigaos*)
@@ -13609,8 +15446,8 @@ lt_prog_compiler_static_CXX=
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
;;
esac
@@ -13625,6 +15462,11 @@ lt_prog_compiler_static_CXX=
# Although the cygwin gcc ignores -fPIC, still need this for old-style
# (--disable-auto-import) libraries
lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static_CXX='$wl-static'
+ ;;
+ esac
;;
darwin* | rhapsody*)
# PIC is the default on this platform
@@ -13674,7 +15516,7 @@ lt_prog_compiler_static_CXX=
case $host_os in
aix[4-9]*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
lt_prog_compiler_static_CXX='-Bstatic'
else
@@ -13714,14 +15556,14 @@ lt_prog_compiler_static_CXX=
case $cc_basename in
CC*)
lt_prog_compiler_wl_CXX='-Wl,'
- lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
- if test "$host_cpu" != ia64; then
+ lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
+ if test ia64 != "$host_cpu"; then
lt_prog_compiler_pic_CXX='+Z'
fi
;;
aCC*)
lt_prog_compiler_wl_CXX='-Wl,'
- lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
case $host_cpu in
hppa*64*|ia64*)
# +Z the default
@@ -13758,7 +15600,7 @@ lt_prog_compiler_static_CXX=
lt_prog_compiler_pic_CXX='-fPIC'
;;
ecpc* )
- # old Intel C++ for x86_64 which still supported -KPIC.
+ # old Intel C++ for x86_64, which still supported -KPIC.
lt_prog_compiler_wl_CXX='-Wl,'
lt_prog_compiler_pic_CXX='-KPIC'
lt_prog_compiler_static_CXX='-static'
@@ -13814,7 +15656,7 @@ lt_prog_compiler_static_CXX=
;;
esac
;;
- netbsd* | netbsdelf*-gnu)
+ netbsd*)
;;
*qnx* | *nto*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
@@ -13903,7 +15745,7 @@ lt_prog_compiler_static_CXX=
fi
case $host_os in
- # For platforms which do not support PIC, -DPIC is meaningless:
+ # For platforms that do not support PIC, -DPIC is meaningless:
*djgpp*)
lt_prog_compiler_pic_CXX=
;;
@@ -13935,7 +15777,7 @@ else
lt_cv_prog_compiler_pic_works_CXX=no
ac_outfile=conftest.$ac_objext
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" ## exclude from sc_useless_quotes_in_assignment
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
@@ -13965,7 +15807,7 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
-if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then
case $lt_prog_compiler_pic_CXX in
"" | " "*) ;;
*) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
@@ -13991,7 +15833,7 @@ if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
$as_echo_n "(cached) " >&6
else
lt_cv_prog_compiler_static_works_CXX=no
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -14010,13 +15852,13 @@ else
fi
fi
$RM -r conftest*
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
-if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then
:
else
lt_prog_compiler_static_CXX=
@@ -14130,8 +15972,8 @@ $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
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then
# do not overwrite the value of need_locks provided by the user
{ $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; }
@@ -14143,9 +15985,9 @@ $as_echo_n "checking if we can lock with hard links... " >&6; }
ln conftest.a conftest.b 2>/dev/null && hard_links=no
{ $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:${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;}
+ if test no = "$hard_links"; then
+ { $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
else
@@ -14162,17 +16004,21 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
case $host_os in
aix[4-9]*)
# If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to AIX nm, but means don't demangle with GNU nm
- # Also, AIX nm treats weak defined symbols like other global defined
- # symbols, whereas GNU nm marks them as "W".
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
;;
pw32*)
- export_symbols_cmds_CXX="$ltdll_cmds"
+ export_symbols_cmds_CXX=$ltdll_cmds
;;
cygwin* | mingw* | cegcc*)
case $cc_basename in
@@ -14185,9 +16031,6 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
;;
esac
;;
- linux* | k*bsd*-gnu | gnu*)
- link_all_deplibs_CXX=no
- ;;
*)
export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
;;
@@ -14195,7 +16038,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
{ $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 no = "$ld_shlibs_CXX" && can_build_shared=no
with_gnu_ld_CXX=$with_gnu_ld
@@ -14212,7 +16055,7 @@ x|xyes)
# Assume -lc should be added
archive_cmds_need_lc_CXX=yes
- if test "$enable_shared" = yes && test "$GCC" = yes; then
+ if test yes,yes = "$GCC,$enable_shared"; then
case $archive_cmds_CXX in
*'~'*)
# FIXME: we may have to deal with multi-command sequences.
@@ -14340,7 +16183,7 @@ $as_echo_n "checking dynamic linker characteristics... " >&6; }
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -14357,14 +16200,16 @@ hardcode_into_libs=no
# flags to be left without arguments
need_version=unknown
+
+
case $host_os in
aix3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
shlibpath_var=LIBPATH
# AIX 3 has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}${shared_ext}$major'
+ soname_spec='$libname$release$shared_ext$major'
;;
aix[4-9]*)
@@ -14372,41 +16217,91 @@ aix[4-9]*)
need_lib_prefix=no
need_version=no
hardcode_into_libs=yes
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 supports IA64
- library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
else
# With GCC up to 2.95.x, collect2 would create an import file
# for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
# development snapshots of GCC prior to 3.0.
case $host_os in
aix4 | aix4.[01] | aix4.[01].*)
if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
echo ' yes '
- echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
:
else
can_build_shared=no
fi
;;
esac
- # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
# soname into executable. Probably we can add versioning support to
# collect2, so additional links can be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
# If using run time linking (on AIX 4.2 or later) use lib<name>.so
# instead of lib<name>.a to let people know that these are not
# typical AIX shared libraries.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a(lib.so.V)'
# We preserve .a as extension for shared libraries through AIX4.2
# and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}${shared_ext}$major'
- fi
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
shlibpath_var=LIBPATH
fi
;;
@@ -14416,18 +16311,18 @@ amigaos*)
powerpc)
# Since July 2007 AmigaOS4 officially supports .so libraries.
# When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
;;
m68k)
library_names_spec='$libname.ixlibrary $libname.a'
# Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
;;
esac
;;
beos*)
- library_names_spec='${libname}${shared_ext}'
+ library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"
shlibpath_var=LIBRARY_PATH
;;
@@ -14435,8 +16330,8 @@ beos*)
bsdi[45]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -14448,7 +16343,7 @@ bsdi[45]*)
cygwin* | mingw* | pw32* | cegcc*)
version_type=windows
- shrext_cmds=".dll"
+ shrext_cmds=.dll
need_version=no
need_lib_prefix=no
@@ -14457,8 +16352,8 @@ cygwin* | mingw* | pw32* | cegcc*)
# gcc
library_names_spec='$libname.dll.a'
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname~
@@ -14474,16 +16369,16 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
mingw* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
- soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
@@ -14492,8 +16387,8 @@ cygwin* | mingw* | pw32* | cegcc*)
*,cl*)
# Native MSVC
libname_spec='$name'
- soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
- library_names_spec='${libname}.dll.lib'
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
case $build_os in
mingw*)
@@ -14520,7 +16415,7 @@ cygwin* | mingw* | pw32* | cegcc*)
sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
;;
*)
- sys_lib_search_path_spec="$LIB"
+ sys_lib_search_path_spec=$LIB
if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
# It is most probably a Windows format PATH.
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -14533,8 +16428,8 @@ cygwin* | mingw* | pw32* | cegcc*)
esac
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname'
@@ -14547,7 +16442,7 @@ cygwin* | mingw* | pw32* | cegcc*)
*)
# Assume MSVC wrapper
- library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
esac
@@ -14560,11 +16455,11 @@ darwin* | rhapsody*)
version_type=darwin
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
- soname_spec='${libname}${release}${major}$shared_ext'
+ library_names_spec='$libname$release$versuffix$shared_ext $libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+ shrext_cmds='`test .$module = .yes && echo .bundle || echo .dylib`'
sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
;;
@@ -14573,8 +16468,8 @@ dgux*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -14589,17 +16484,31 @@ freebsd* | dragonfly*)
*) objformat=elf ;;
esac
fi
- version_type=freebsd-$objformat
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
need_version=no
need_lib_prefix=no
;;
freebsd-*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
@@ -14627,10 +16536,10 @@ haiku*)
need_lib_prefix=no
need_version=no
dynamic_linker="$host_os runtime_loader"
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=yes
+ shlibpath_overrides_runpath=no
sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
hardcode_into_libs=yes
;;
@@ -14648,14 +16557,15 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- if test "X$HPUX_IA64_MODE" = X32; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
else
sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
fi
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
shrext_cmds='.sl'
@@ -14663,8 +16573,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
@@ -14673,8 +16583,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
;;
esac
# HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -14687,8 +16597,8 @@ interix[3-9]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -14699,7 +16609,7 @@ irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
*)
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
version_type=linux # correct to gnu/linux during the next big refactor
else
version_type=irix
@@ -14707,8 +16617,8 @@ irix5* | irix6* | nonstopux*)
esac
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
case $host_os in
irix5* | nonstopux*)
libsuff= shlibsuff=
@@ -14727,8 +16637,8 @@ irix5* | irix6* | nonstopux*)
esac
shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
hardcode_into_libs=yes
;;
@@ -14737,13 +16647,33 @@ linux*oldld* | linux*aout* | linux*coff*)
dynamic_linker=no
;;
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ ;;
+
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -14787,7 +16717,12 @@ fi
# before this can be enabled.
hardcode_into_libs=yes
- # Append ld.so.conf contents to the search path
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -14802,29 +16737,17 @@ fi
dynamic_linker='GNU/Linux ld.so'
;;
-netbsdelf*-gnu)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='NetBSD ld.elf_so'
- ;;
-
netbsd*)
version_type=sunos
need_lib_prefix=no
need_version=no
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
dynamic_linker='NetBSD (a.out) ld.so'
else
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='NetBSD ld.elf_so'
fi
shlibpath_var=LD_LIBRARY_PATH
@@ -14834,7 +16757,7 @@ netbsd*)
newsos6)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
;;
@@ -14843,58 +16766,68 @@ newsos6)
version_type=qnx
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='ldqnx.so'
;;
-openbsd*)
+openbsd* | bitrig*)
version_type=sunos
- sys_lib_dlsearch_path_spec="/usr/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib
need_lib_prefix=no
- # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
- case $host_os in
- openbsd3.3 | openbsd3.3.*) need_version=yes ;;
- *) need_version=no ;;
- esac
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case $host_os in
- openbsd2.[89] | openbsd2.[89].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
else
- shlibpath_overrides_runpath=yes
+ need_version=yes
fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
;;
os2*)
libname_spec='$name'
- shrext_cmds=".dll"
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
need_lib_prefix=no
- library_names_spec='$libname${shared_ext} $libname.a'
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
;;
osf3* | osf4* | osf5*)
version_type=osf
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
rdos*)
@@ -14905,8 +16838,8 @@ solaris*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
@@ -14916,11 +16849,11 @@ solaris*)
sunos4*)
version_type=sunos
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
need_lib_prefix=no
fi
need_version=yes
@@ -14928,8 +16861,8 @@ sunos4*)
sysv4 | sysv4.3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
case $host_vendor in
sni)
@@ -14950,24 +16883,24 @@ sysv4 | sysv4.3*)
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
- soname_spec='$libname${shared_ext}.$major'
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
shlibpath_var=LD_LIBRARY_PATH
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- version_type=freebsd-elf
+ version_type=sco
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
else
sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -14985,7 +16918,7 @@ tpf*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
@@ -14993,8 +16926,8 @@ tpf*)
uts4*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -15004,20 +16937,32 @@ uts4*)
esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
$as_echo "$dynamic_linker" >&6; }
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
- sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
- sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
fi
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
@@ -15060,15 +17005,15 @@ $as_echo_n "checking how to hardcode library paths into programs... " >&6; }
hardcode_action_CXX=
if test -n "$hardcode_libdir_flag_spec_CXX" ||
test -n "$runpath_var_CXX" ||
- test "X$hardcode_automatic_CXX" = "Xyes" ; then
+ test yes = "$hardcode_automatic_CXX"; then
# We can hardcode non-existent directories.
- if test "$hardcode_direct_CXX" != no &&
+ if test no != "$hardcode_direct_CXX" &&
# If the only mechanism to avoid hardcoding is shlibpath_var, we
# have to relink, otherwise we might link with an installed library
# when we should be linking with a yet-to-be-installed one
- ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
- test "$hardcode_minus_L_CXX" != no; then
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" &&
+ test no != "$hardcode_minus_L_CXX"; then
# Linking always hardcodes the temporary library directory.
hardcode_action_CXX=relink
else
@@ -15083,12 +17028,12 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
$as_echo "$hardcode_action_CXX" >&6; }
-if test "$hardcode_action_CXX" = relink ||
- test "$inherit_rpath_CXX" = yes; then
+if test relink = "$hardcode_action_CXX" ||
+ test yes = "$inherit_rpath_CXX"; then
# Fast installation is not supported
enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
# Fast installation is not necessary
enable_fast_install=needless
fi
@@ -15111,115 +17056,245 @@ fi
lt_cv_path_LD=$lt_save_path_LD
lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
+fi # test yes != "$_lt_caught_CXX_error"
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-# Find a good install program. We prefer a C program (faster),
-# so one script is as good as another. But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# 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:${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 ${ac_cv_path_install+:} false; then :
+
+if test "$GCC" = yes; then :
+
+
+
+
+for flag in -Wall -Wextra; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5
+$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
$as_echo_n "(cached) " >&6
else
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in #((
- ./ | .// | /[cC]/* | \
- /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
- ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
- /usr/ucb/* ) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
- if test $ac_prog = install &&
- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- elif test $ac_prog = install &&
- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # program-specific install script used by HP pwplus--don't use.
- :
- else
- rm -rf conftest.one conftest.two conftest.dir
- echo one > conftest.one
- echo two > conftest.two
- mkdir conftest.dir
- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
- test -s conftest.one && test -s conftest.two &&
- test -s conftest.dir/conftest.one &&
- test -s conftest.dir/conftest.two
- then
- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
- break 3
- fi
- fi
- fi
- done
- done
- ;;
+
+ ax_check_save_flags=$CXXFLAGS
+ CXXFLAGS="$CXXFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CXXFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+
+if ${AM_CXXFLAGS+:} false; then :
+
+ case " $AM_CXXFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS already contains \$flag"; } >&5
+ (: AM_CXXFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CXXFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS=\"\$AM_CXXFLAGS\""; } >&5
+ (: AM_CXXFLAGS="$AM_CXXFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
esac
- done
-IFS=$as_save_IFS
+else
-rm -rf conftest.one conftest.two conftest.dir
+ AM_CXXFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS=\"\$AM_CXXFLAGS\""; } >&5
+ (: AM_CXXFLAGS="$AM_CXXFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
fi
- if test "${ac_cv_path_install+set}" = set; then
- INSTALL=$ac_cv_path_install
- else
- # As a last resort, use the slow shell script. Don't cache a
- # value for INSTALL 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.
- INSTALL=$ac_install_sh
- fi
+
+else
+ :
fi
-{ $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}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+done
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-if test "$GCC" = yes ; then
- OLDCFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes"
- CFLAGS="$OLDCFLAGS -fexceptions"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -fexceptions" >&5
-$as_echo_n "checking whether $CC accepts -fexceptions... " >&6; }
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+for flag in -fexceptions; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5
+$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$CXXFLAGS
+ CXXFLAGS="$CXXFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CXXFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+
+if ${AM_CXXFLAGS+:} false; then :
+
+ case " $AM_CXXFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS already contains \$flag"; } >&5
+ (: AM_CXXFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CXXFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS=\"\$AM_CXXFLAGS\""; } >&5
+ (: AM_CXXFLAGS="$AM_CXXFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_CXXFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS=\"\$AM_CXXFLAGS\""; } >&5
+ (: AM_CXXFLAGS="$AM_CXXFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
+fi
+
+else
+ :
+fi
+
+done
+
+
+
+
+
+for flag in -fno-strict-aliasing; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_cxxflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $flag" >&5
+$as_echo_n "checking whether C++ compiler accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$CXXFLAGS
+ CXXFLAGS="$CXXFLAGS -Werror $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void) { return 0; }
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval "$as_CACHEVAR=yes"
+else
+ eval "$as_CACHEVAR=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CXXFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+
+if ${AM_CXXFLAGS+:} false; then :
+
+ case " $AM_CXXFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS already contains \$flag"; } >&5
+ (: AM_CXXFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CXXFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS=\"\$AM_CXXFLAGS\""; } >&5
+ (: AM_CXXFLAGS="$AM_CXXFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_CXXFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CXXFLAGS=\"\$AM_CXXFLAGS\""; } >&5
+ (: AM_CXXFLAGS="$AM_CXXFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
+fi
+
+else
+ :
+fi
+
+done
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+if test "$GCC" = yes; then :
+
+
+
+
+for flag in -fno-strict-aliasing; do
+ as_CACHEVAR=`$as_echo "ax_cv_check_ldflags__$flag" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts $flag" >&5
+$as_echo_n "checking whether the linker accepts $flag... " >&6; }
+if eval \${$as_CACHEVAR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $flag"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
@@ -15231,15 +17306,159 @@ main ()
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+ eval "$as_CACHEVAR=yes"
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }; CFLAGS="$OLDCFLAGS"
+ eval "$as_CACHEVAR=no"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
- CXXFLAGS=`echo "$CFLAGS" | sed 's/ -Wmissing-prototypes -Wstrict-prototypes//'`
+ LDFLAGS=$ax_check_save_flags
+fi
+eval ac_res=\$$as_CACHEVAR
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then :
+
+if ${AM_LDFLAGS+:} false; then :
+
+ case " $AM_LDFLAGS " in #(
+ *" $flag "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_LDFLAGS already contains \$flag"; } >&5
+ (: AM_LDFLAGS already contains $flag) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_LDFLAGS " $flag"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_LDFLAGS=\"\$AM_LDFLAGS\""; } >&5
+ (: AM_LDFLAGS="$AM_LDFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_LDFLAGS=$flag
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_LDFLAGS=\"\$AM_LDFLAGS\""; } >&5
+ (: AM_LDFLAGS="$AM_LDFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
+fi
+
+else
+ :
+fi
+
+done
+
+fi
+
+case "$LD" in #(
+ *clang*) :
+ case "${host_os}" in #(
+ *linux*) :
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' ;; #(
+ *) :
+ ;;
+esac ;; #(
+ *) :
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports visibility" >&5
+$as_echo_n "checking whether compiler supports visibility... " >&6; }
+if ${expatcfg_cv_compiler_supports_visibility+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ expatcfg_cv_compiler_supports_visibility=no
+ OLDFLAGS=$CFLAGS
+ as_fn_append CFLAGS " -fvisibility=hidden -Wall -Werror -Wno-unknown-warning-option"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ void __attribute__((visibility("default"))) foo(void);
+ void foo(void) {}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ expatcfg_cv_compiler_supports_visibility=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS=$OLDFLAGS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $expatcfg_cv_compiler_supports_visibility" >&5
+$as_echo "$expatcfg_cv_compiler_supports_visibility" >&6; }
+ if test "$expatcfg_cv_compiler_supports_visibility" = yes; then :
+
+
+if ${AM_CFLAGS+:} false; then :
+
+ case " $AM_CFLAGS " in #(
+ *" -fvisibility=hidden "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS already contains -fvisibility=hidden"; } >&5
+ (: AM_CFLAGS already contains -fvisibility=hidden) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CFLAGS " -fvisibility=hidden"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_CFLAGS=-fvisibility=hidden
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CFLAGS=\"\$AM_CFLAGS\""; } >&5
+ (: AM_CFLAGS="$AM_CFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
+fi
+
+
+if ${AM_CPPFLAGS+:} false; then :
+
+ case " $AM_CPPFLAGS " in #(
+ *" -DXML_ENABLE_VISIBILITY=1 "*) :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CPPFLAGS already contains -DXML_ENABLE_VISIBILITY=1"; } >&5
+ (: AM_CPPFLAGS already contains -DXML_ENABLE_VISIBILITY=1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } ;; #(
+ *) :
+
+ as_fn_append AM_CPPFLAGS " -DXML_ENABLE_VISIBILITY=1"
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CPPFLAGS=\"\$AM_CPPFLAGS\""; } >&5
+ (: AM_CPPFLAGS="$AM_CPPFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ ;;
+esac
+
+else
+
+ AM_CPPFLAGS=-DXML_ENABLE_VISIBILITY=1
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: : AM_CPPFLAGS=\"\$AM_CPPFLAGS\""; } >&5
+ (: AM_CPPFLAGS="$AM_CPPFLAGS") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+
+fi
+
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
@@ -15356,41 +17575,123 @@ fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
if ${ac_cv_c_bigendian+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_cv_c_bigendian=unknown
-# See if sys/param.h defines the BYTE_ORDER macro.
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
-#include <sys/param.h>
+ #include <sys/param.h>
+
int
main ()
{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
-#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
- bogus endian macros
-#endif
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
# It does; now see whether it defined to BIG_ENDIAN or not.
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/types.h>
-#include <sys/param.h>
+ #include <sys/param.h>
+
int
main ()
{
-
#if BYTE_ORDER != BIG_ENDIAN
- not big endian
-#endif
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+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
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
;
return 0;
}
@@ -15403,21 +17704,70 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-if test $ac_cv_c_bigendian = unknown; then
-if test "$cross_compiling" = yes; then :
- echo $ac_n "cross-compiling... " 2>&6
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-main () {
- /* Are we little or big endian? From Harbison&Steele. */
- union
- {
- long l;
- char c[sizeof (long)];
- } u;
- u.l = 1;
- exit (u.c[sizeof (long) - 1] == 1);
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
@@ -15429,60 +17779,32 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-fi
+ fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
$as_echo "$ac_cv_c_bigendian" >&6; }
-if test $ac_cv_c_bigendian = unknown; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to probe for byte ordering" >&5
-$as_echo_n "checking to probe for byte ordering... " >&6; }
-
-cat >conftest.c <<EOF
-short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
-short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
-void _ascii() { char* s = (char*) ascii_mm; s = (char*) ascii_ii; }
-short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
-short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
-void _ebcdic() { char* s = (char*) ebcdic_mm; s = (char*) ebcdic_ii; }
-int main() { _ascii (); _ebcdic (); return 0; }
-EOF
- if test -f conftest.c ; then
- if ${CC-cc} -c conftest.c -o conftest.o && test -f conftest.o ; then
- if test `grep -l BIGenDianSyS conftest.o` ; then
- echo $ac_n ' big endian probe OK, ' 1>&6
- ac_cv_c_bigendian=yes
- fi
- if test `grep -l LiTTleEnDian conftest.o` ; then
- echo $ac_n ' little endian probe OK, ' 1>&6
- if test $ac_cv_c_bigendian = yes ; then
- ac_cv_c_bigendian=unknown;
- else
- ac_cv_c_bigendian=no
- fi
- fi
- echo $ac_n 'guessing bigendian ... ' >&6
- fi
- fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
-$as_echo "$ac_cv_c_bigendian" >&6; }
-fi
-if test $ac_cv_c_bigendian = yes; then
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
-$as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+ BYTEORDER=4321;; #(
+ no)
+ BYTEORDER=1234 ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
- BYTEORDER=4321
-else
- BYTEORDER=1234
-fi
cat >>confdefs.h <<_ACEOF
#define BYTEORDER $BYTEORDER
_ACEOF
-if test $ac_cv_c_bigendian = unknown; then
- as_fn_error please pre-set ac_cv_c_bigendian "unknown endianess - sorry" "$LINENO" 5
-fi
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
@@ -15576,18 +17898,282 @@ _ACEOF
fi
-for ac_func in memmove bcopy
-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"
-if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+
+
+# Check whether --with-xmlwf was given.
+if test "${with_xmlwf+set}" = set; then :
+ withval=$with_xmlwf;
+else
+ with_xmlwf=yes
+fi
+
+ if test x${with_xmlwf} = xyes; then
+ WITH_XMLWF_TRUE=
+ WITH_XMLWF_FALSE='#'
+else
+ WITH_XMLWF_TRUE='#'
+ WITH_XMLWF_FALSE=
+fi
+
+
+
+# Check whether --with-examples was given.
+if test "${with_examples+set}" = set; then :
+ withval=$with_examples;
+else
+ with_examples=yes
+fi
+
+ if test x${with_examples} = xyes; then
+ WITH_EXAMPLES_TRUE=
+ WITH_EXAMPLES_FALSE='#'
+else
+ WITH_EXAMPLES_TRUE='#'
+ WITH_EXAMPLES_FALSE=
+fi
+
+
+
+# Check whether --with-tests was given.
+if test "${with_tests+set}" = set; then :
+ withval=$with_tests;
+else
+ with_tests=yes
+fi
+
+ if test x${with_tests} = xyes; then
+ WITH_TESTS_TRUE=
+ WITH_TESTS_FALSE='#'
+else
+ WITH_TESTS_TRUE='#'
+ WITH_TESTS_FALSE=
+fi
+
+
+
+EXPATCFG_ON_MINGW=no
+case "${host_os}" in #(
+ mingw*) :
+ EXPATCFG_ON_MINGW=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: detected OS: MinGW" >&5
+$as_echo "$as_me: detected OS: MinGW" >&6;} ;; #(
+ *) :
+ ;;
+esac
+ if test x${EXPATCFG_ON_MINGW} = xyes; then
+ MINGW_TRUE=
+ MINGW_FALSE='#'
+else
+ MINGW_TRUE='#'
+ MINGW_FALSE=
+fi
+
+
+ if echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_UNICODE >/dev/null; then
+ UNICODE_TRUE=
+ UNICODE_FALSE='#'
+else
+ UNICODE_TRUE='#'
+ UNICODE_FALSE=
+fi
+
+
+
+
+# Check whether --with-libbsd was given.
+if test "${with_libbsd+set}" = set; then :
+ withval=$with_libbsd;
+else
+ with_libbsd=no
+fi
+
+if test "x${with_libbsd}" != xno; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for arc4random_buf in -lbsd" >&5
+$as_echo_n "checking for arc4random_buf in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_arc4random_buf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* 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 arc4random_buf ();
+int
+main ()
+{
+return arc4random_buf ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bsd_arc4random_buf=yes
+else
+ ac_cv_lib_bsd_arc4random_buf=no
+fi
+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:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_arc4random_buf" >&5
+$as_echo "$ac_cv_lib_bsd_arc4random_buf" >&6; }
+if test "x$ac_cv_lib_bsd_arc4random_buf" = xyes; then :
cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+#define HAVE_LIBBSD 1
_ACEOF
+ LIBS="-lbsd $LIBS"
+
+else
+ if test "x${with_libbsd}" = xyes; then :
+ as_fn_error $? "Enforced use of libbsd cannot be satisfied." "$LINENO" 5
+fi
fi
-done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for arc4random_buf (BSD or libbsd)" >&5
+$as_echo_n "checking for arc4random_buf (BSD or libbsd)... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdlib.h> /* for arc4random_buf on BSD, for NULL */
+ #if defined(HAVE_LIBBSD)
+ # include <bsd/stdlib.h>
+ #endif
+ int main() {
+ arc4random_buf(NULL, 0U);
+ return 0;
+ }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_ARC4RANDOM_BUF 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for arc4random (BSD, macOS or libbsd)" >&5
+$as_echo_n "checking for arc4random (BSD, macOS or libbsd)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #if defined(HAVE_LIBBSD)
+ # include <bsd/stdlib.h>
+ #else
+ # include <stdlib.h>
+ #endif
+ int main() {
+ arc4random();
+ return 0;
+ }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_ARC4RANDOM 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+
+# Check whether --with-getrandom was given.
+if test "${with_getrandom+set}" = set; then :
+ withval=$with_getrandom;
+else
+ with_getrandom=check
+fi
+
+
+if test "x$with_getrandom" != xno; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getrandom (Linux 3.17+, glibc 2.25+)" >&5
+$as_echo_n "checking for getrandom (Linux 3.17+, glibc 2.25+)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdlib.h> /* for NULL */
+ #include <sys/random.h>
+ int main() {
+ return getrandom(NULL, 0U, 0U);
+ }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_GETRANDOM 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ if test "x$with_getrandom" = xyes; then :
+ as_fn_error $? "enforced the use of getrandom --with-getrandom, but not detected" "$LINENO" 5
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+# Check whether --with-sys_getrandom was given.
+if test "${with_sys_getrandom+set}" = set; then :
+ withval=$with_sys_getrandom;
+else
+ with_sys_getrandom=check
+fi
+
+
+if test "x$with_sys_getrandom" != xno; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syscall SYS_getrandom (Linux 3.17+)" >&5
+$as_echo_n "checking for syscall SYS_getrandom (Linux 3.17+)... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdlib.h> /* for NULL */
+ #include <unistd.h> /* for syscall */
+ #include <sys/syscall.h> /* for SYS_getrandom */
+ int main() {
+ syscall(SYS_getrandom, NULL, 0, 0);
+ return 0;
+ }
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_SYSCALL_GETRANDOM 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ if test "x$with_sys_getrandom" = xyes; then :
+ as_fn_error $? "enforced the use of syscall SYS_getrandom --with-sys-getrandom, but not detected" "$LINENO" 5
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
for ac_header in fcntl.h unistd.h
do :
@@ -15815,377 +18401,142 @@ fi
rm -f conftest.mmap conftest.txt
-if test "$ac_cv_func_mmap_fixed_mapped" = "yes"; then
- FILEMAP=unixfilemap
+if test "$ac_cv_func_mmap_fixed_mapped" = "yes"; then :
+ FILEMAP=unixfilemap
else
- FILEMAP=readfilemap
+ FILEMAP=readfilemap
fi
-# AC_CPP_FUNC
-# ------------------ #
-# Checks to see if ANSI C99 CPP variable __func__ works.
-# If not, perhaps __FUNCTION__ works instead.
-# If not, we'll just define __func__ to "".
-# AC_CPP_FUNC
-
- case $ac_cv_prog_cc_stdc in #(
- no) :
- ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #(
- *) :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
-$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
-if ${ac_cv_prog_cc_c99+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <wchar.h>
-#include <stdio.h>
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-#define debug(...) fprintf (stderr, __VA_ARGS__)
-#define showlist(...) puts (#__VA_ARGS__)
-#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
-static void
-test_varargs_macros (void)
-{
- int x = 1234;
- int y = 5678;
- debug ("Flag");
- debug ("X = %d\n", x);
- showlist (The first, second, and third items.);
- report (x>y, "x is %d but y is %d", x, y);
-}
+$as_echo "#define XML_NS 1" >>confdefs.h
-// Check long long types.
-#define BIG64 18446744073709551615ull
-#define BIG32 4294967295ul
-#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
-#if !BIG_OK
- your preprocessor is broken;
-#endif
-#if BIG_OK
-#else
- your preprocessor is broken;
-#endif
-static long long int bignum = -9223372036854775807LL;
-static unsigned long long int ubignum = BIG64;
-struct incomplete_array
-{
- int datasize;
- double data[];
-};
+$as_echo "#define XML_DTD 1" >>confdefs.h
-struct named_init {
- int number;
- const wchar_t *name;
- double average;
-};
-typedef const char *ccp;
+$as_echo "#define XML_DEV_URANDOM 1" >>confdefs.h
-static inline int
-test_restrict (ccp restrict text)
-{
- // See if C++-style comments work.
- // Iterate through items via the restricted pointer.
- // Also check for declarations in for loops.
- for (unsigned int i = 0; *(text+i) != '\0'; ++i)
- continue;
- return 0;
-}
-// Check varargs and va_copy.
-static void
-test_varargs (const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- va_list args_copy;
- va_copy (args_copy, args);
+# Check whether --enable-xml-attr-info was given.
+if test "${enable_xml_attr_info+set}" = set; then :
+ enableval=$enable_xml_attr_info;
+else
+ enable_xml_attr_info=no
+fi
- const char *str;
- int number;
- float fnumber;
+if test "x${enable_xml_attr_info}" = "xyes"; then :
- while (*format)
- {
- switch (*format++)
- {
- case 's': // string
- str = va_arg (args_copy, const char *);
- break;
- case 'd': // int
- number = va_arg (args_copy, int);
- break;
- case 'f': // float
- fnumber = va_arg (args_copy, double);
- break;
- default:
- break;
- }
- }
- va_end (args_copy);
- va_end (args);
-}
+$as_echo "#define XML_ATTR_INFO 1" >>confdefs.h
-int
-main ()
-{
+fi
- // Check bool.
- _Bool success = false;
+# Check whether --enable-xml-context was given.
+if test "${enable_xml_context+set}" = set; then :
+ enableval=$enable_xml_context; enable_xml_context=${enableval}
+fi
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
+if test "x${enable_xml_context}" != "xno"; then :
+ if test "x${enable_xml_context}" = "xyes" \
+ -o "x${enable_xml_context}" = "x"; then :
+ enable_xml_context=1024
+fi
- // Check varargs.
- test_varargs ("s, d' f .", "string", 65, 34.234);
- test_varargs_macros ();
+cat >>confdefs.h <<_ACEOF
+#define XML_CONTEXT_BYTES ${enable_xml_context}
+_ACEOF
- // Check flexible array members.
- struct incomplete_array *ia =
- malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
- ia->datasize = 10;
- for (int i = 0; i < ia->datasize; ++i)
- ia->data[i] = i * 1.234;
+fi
- // Check named initializers.
- struct named_init ni = {
- .number = 34,
- .name = L"Test wide string",
- .average = 543.34343,
- };
- ni.number = 58;
+# Check whether --with-docbook was given.
+if test "${with_docbook+set}" = set; then :
+ withval=$with_docbook;
+else
+ with_docbook=check
+fi
- int dynamic_array[ni.number];
- dynamic_array[ni.number - 1] = 543;
- // work around unused variable warnings
- return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
- || dynamic_array[ni.number - 1] != 543);
- ;
- return 0;
-}
-_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+if test "x$with_docbook" != xno; then :
+ for ac_prog in docbook2x-man db2x_docbook2man docbook2man docbook-to-man
do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c99=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c99" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
- *)
- CC="$CC $ac_cv_prog_cc_c99"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c99" != xno; then :
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
-else
- { $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 ${ac_cv_prog_cc_c89+:} false; then :
+ # 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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DOCBOOK_TO_MAN+:} false; then :
$as_echo_n "(cached) " >&6
else
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
-}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+ if test -n "$DOCBOOK_TO_MAN"; then
+ ac_cv_prog_DOCBOOK_TO_MAN="$DOCBOOK_TO_MAN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DOCBOOK_TO_MAN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
+ done
+IFS=$as_save_IFS
fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $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:${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 :
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
-else
- ac_cv_prog_cc_stdc=no
fi
-
-fi
- ;;
-esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5
-$as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; }
- if ${ac_cv_prog_cc_stdc+:} false; then :
- $as_echo_n "(cached) " >&6
+DOCBOOK_TO_MAN=$ac_cv_prog_DOCBOOK_TO_MAN
+if test -n "$DOCBOOK_TO_MAN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOCBOOK_TO_MAN" >&5
+$as_echo "$DOCBOOK_TO_MAN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
fi
- case $ac_cv_prog_cc_stdc in #(
- no) :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;; #(
- '') :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;; #(
- *) :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5
-$as_echo "$ac_cv_prog_cc_stdc" >&6; } ;;
-esac
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C99-conforming __func__" >&5
-$as_echo_n "checking for an ANSI C99-conforming __func__... " >&6; }
-if ${ac_cv_cpp_func+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int
-main ()
-{
-char *foo = __func__;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_cpp_func=yes
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ test -n "$DOCBOOK_TO_MAN" && break
+done
-int
-main ()
-{
-char *foo = __FUNCTION__;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_cpp_func=__FUNCTION__
-else
- ac_cv_cpp_func=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if test "x${DOCBOOK_TO_MAN}" = x -a "x$with_docbook" = xyes; then :
+ as_fn_error $? "Required program 'docbook2x-man' not found." "$LINENO" 5
+fi
+if test "x${DOCBOOK_TO_MAN}" != x -a "x$with_docbook" != xno; then :
+ if ${DOCBOOK_TO_MAN} --help | grep -i -q -F sgmlbase; then :
+ as_fn_error $? "Your local ${DOCBOOK_TO_MAN} was found to work with SGML rather
+ than XML. Please install docbook2X and use variable DOCBOOK_TO_MAN to point
+ configure to command docbook2x-man of docbook2X.
+ Or use DOCBOOK_TO_MAN=\"xmlto man --skip-validation\" if you have xmlto around.
+ You can also configure using --without-docbook if you can do without a man
+ page for xmlwf." "$LINENO" 5
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_func" >&5
-$as_echo "$ac_cv_cpp_func" >&6; }
-if test $ac_cv_cpp_func = __FUNCTION__; then
-
-$as_echo "#define __func__ __FUNCTION__" >>confdefs.h
-
-elif test $ac_cv_cpp_func = no; then
-
-$as_echo "#define __func__ \"\"" >>confdefs.h
+ if test "x${DOCBOOK_TO_MAN}" != x; then
+ WITH_DOCBOOK_TRUE=
+ WITH_DOCBOOK_FALSE='#'
+else
+ WITH_DOCBOOK_TRUE='#'
+ WITH_DOCBOOK_FALSE=
fi
-$as_echo "#define XML_NS 1" >>confdefs.h
-$as_echo "#define XML_DTD 1" >>confdefs.h
+_EXPAT_OUTPUT_NAME="$PACKAGE_NAME"
-$as_echo "#define XML_CONTEXT_BYTES 1024" >>confdefs.h
+ac_config_files="$ac_config_files Makefile expat.pc doc/Makefile examples/Makefile lib/Makefile tests/Makefile tests/benchmark/Makefile xmlwf/Makefile"
-ac_config_files="$ac_config_files Makefile expat.pc"
+ac_config_files="$ac_config_files run.sh"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -16296,6 +18647,59 @@ LIBOBJS=$ac_libobjs
LTLIBOBJS=$ac_ltlibobjs
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ 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_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_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+if test -z "${WITH_XMLWF_TRUE}" && test -z "${WITH_XMLWF_FALSE}"; then
+ as_fn_error $? "conditional \"WITH_XMLWF\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${WITH_EXAMPLES_TRUE}" && test -z "${WITH_EXAMPLES_FALSE}"; then
+ as_fn_error $? "conditional \"WITH_EXAMPLES\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${WITH_TESTS_TRUE}" && test -z "${WITH_TESTS_FALSE}"; then
+ as_fn_error $? "conditional \"WITH_TESTS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${MINGW_TRUE}" && test -z "${MINGW_FALSE}"; then
+ as_fn_error $? "conditional \"MINGW\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${UNICODE_TRUE}" && test -z "${UNICODE_FALSE}"; then
+ as_fn_error $? "conditional \"UNICODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${WITH_DOCBOOK_TRUE}" && test -z "${WITH_DOCBOOK_FALSE}"; then
+ as_fn_error $? "conditional \"WITH_DOCBOOK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
: "${CONFIG_STATUS=./config.status}"
ac_write_fail=0
@@ -16693,7 +19097,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by expat $as_me 2.1.1, which was
+This file was extended by expat $as_me 2.2.10, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -16759,7 +19163,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-expat config.status 2.1.1
+expat config.status 2.2.10
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -16770,6 +19174,7 @@ gives unlimited permission to copy, distribute and modify it."
ac_pwd='$ac_pwd'
srcdir='$srcdir'
INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
AWK='$AWK'
test -n "\$AWK" || AWK=awk
_ACEOF
@@ -16877,6 +19282,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
#
# INIT-COMMANDS
#
+AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"
# The HP-UX ksh and POSIX shell print the target directory to stdout
@@ -16886,15 +19292,16 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
sed_quote_subst='$sed_quote_subst'
double_quote_subst='$double_quote_subst'
delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`'
DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
-macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
-macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
@@ -16942,10 +19349,13 @@ compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
@@ -17010,7 +19420,8 @@ finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
-sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
+configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
@@ -17116,9 +19527,12 @@ CFLAGS \
compiler \
lt_cv_sys_global_symbol_pipe \
lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_import \
lt_cv_sys_global_symbol_to_c_name_address \
lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_cv_nm_interface \
nm_file_list_spec \
+lt_cv_truncate_bin \
lt_prog_compiler_no_builtin_flag \
lt_prog_compiler_pic \
lt_prog_compiler_wl \
@@ -17184,7 +19598,7 @@ postdeps_CXX \
compiler_lib_search_path_CXX; do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[\\\\\\\`\\"\\\$]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -17211,7 +19625,8 @@ postinstall_cmds \
postuninstall_cmds \
finish_cmds \
sys_lib_search_path_spec \
-sys_lib_dlsearch_path_spec \
+configure_time_dlsearch_path \
+configure_time_lt_sys_library_path \
reload_cmds_CXX \
old_archive_cmds_CXX \
old_archive_from_new_cmds_CXX \
@@ -17225,7 +19640,7 @@ prelink_cmds_CXX \
postlink_cmds_CXX; do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[\\\\\\\`\\"\\\$]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -17234,19 +19649,16 @@ postlink_cmds_CXX; do
done
ac_aux_dir='$ac_aux_dir'
-xsi_shell='$xsi_shell'
-lt_shell_append='$lt_shell_append'
-# See if we are running on zsh, and set the options which allow our
+# See if we are running on zsh, and set the options that allow our
# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
+if test -n "\${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
PACKAGE='$PACKAGE'
VERSION='$VERSION'
- TIMESTAMP='$TIMESTAMP'
RM='$RM'
ofile='$ofile'
@@ -17264,9 +19676,17 @@ for ac_config_target in $ac_config_targets
do
case $ac_config_target in
"expat_config.h") CONFIG_HEADERS="$CONFIG_HEADERS expat_config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
"libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"expat.pc") CONFIG_FILES="$CONFIG_FILES expat.pc" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
+ "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+ "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
+ "tests/benchmark/Makefile") CONFIG_FILES="$CONFIG_FILES tests/benchmark/Makefile" ;;
+ "xmlwf/Makefile") CONFIG_FILES="$CONFIG_FILES xmlwf/Makefile" ;;
+ "run.sh") CONFIG_FILES="$CONFIG_FILES run.sh" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac
@@ -17715,6 +20135,11 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
[\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
*) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
_ACEOF
cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
@@ -17769,6 +20194,7 @@ s&@builddir@&$ac_builddir&;t t
s&@abs_builddir@&$ac_abs_builddir&;t t
s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
$ac_datarootdir_hack
"
eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
@@ -17813,6 +20239,40 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;}
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
|| as_fn_error $? "could not create -" "$LINENO" 5
fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
;;
:C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
@@ -17822,60 +20282,158 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ case $CONFIG_FILES in #(
+ *\'*) :
+ eval set x "$CONFIG_FILES" ;; #(
+ *) :
+ set x $CONFIG_FILES ;; #(
+ *) :
+ ;;
+esac
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`$as_dirname -- "$am_mf" ||
+$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$am_mf" : 'X\(//\)[^/]' \| \
+ X"$am_mf" : 'X\(//\)$' \| \
+ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$am_mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ am_filepart=`$as_basename -- "$am_mf" ||
+$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$am_mf" : 'X\(//\)$' \| \
+ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$am_mf" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { echo "$as_me:$LINENO: cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles" >&5
+ (cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. If GNU make was not used, consider
+ re-running the configure script with MAKE=\"gmake\" (or whatever is
+ necessary). You can also try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ { am_dirpart=; unset am_dirpart;}
+ { am_filepart=; unset am_filepart;}
+ { am_mf=; unset am_mf;}
+ { am_rc=; unset am_rc;}
+ rm -f conftest-deps.mk
+}
+ ;;
"libtool":C)
- # See if we are running on zsh, and set the options which allow our
+ # See if we are running on zsh, and set the options that allow our
# commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}" ; then
+ if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
- cfgfile="${ofile}T"
+ cfgfile=${ofile}T
trap "$RM \"$cfgfile\"; exit 1" 1 2 15
$RM "$cfgfile"
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Generated automatically by $as_me ($PACKAGE) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-# Foundation, Inc.
-# Written by Gordon Matzigkeit, 1996
-#
-# This file is part of GNU Libtool.
-#
-# GNU Libtool is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
#
-# GNU Libtool is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING. If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
# The names of the tagged configurations supported by this script.
-available_tags="CXX "
+available_tags='CXX '
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
# ### BEGIN LIBTOOL CONFIG
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
# Assembler program.
AS=$lt_AS
@@ -17885,10 +20443,6 @@ DLLTOOL=$lt_DLLTOOL
# Object dumper program.
OBJDUMP=$lt_OBJDUMP
-# Which release of libtool.m4 was used?
-macro_version=$macro_version
-macro_revision=$macro_revision
-
# Whether or not to build shared libraries.
build_libtool_libs=$enable_shared
@@ -17901,6 +20455,9 @@ pic_mode=$pic_mode
# Whether or not to optimize for fast installation.
fast_install=$enable_fast_install
+# Shared archive member basename,for filename based shared library versioning on AIX.
+shared_archive_member_spec=$shared_archive_member_spec
+
# Shell to use when invoking shell scripts.
SHELL=$lt_SHELL
@@ -18012,18 +20569,27 @@ global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
# Transform the output of nm in a proper C declaration.
global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+# Transform the output of nm into a list of symbols to manually relocate.
+global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
+
# Transform the output of nm in a C name address pair.
global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
# Transform the output of nm in a C name address pair when lib prefix is needed.
global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+# The name lister interface.
+nm_interface=$lt_lt_cv_nm_interface
+
# Specify filename containing input files for \$NM.
nm_file_list_spec=$lt_nm_file_list_spec
-# The root where to search for dependent libraries,and in which our libraries should be installed.
+# The root where to search for dependent libraries,and where our libraries should be installed.
lt_sysroot=$lt_sysroot
+# Command to truncate a binary pipe.
+lt_truncate_bin=$lt_lt_cv_truncate_bin
+
# The name of the directory that contains temporary libtool files.
objdir=$objdir
@@ -18114,8 +20680,11 @@ hardcode_into_libs=$hardcode_into_libs
# Compile-time system search path for libraries.
sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
-# Run-time system search path for libraries.
-sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+# Detected run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
+
+# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
+configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
# Whether dlopen is supported.
dlopen_support=$enable_dlopen
@@ -18208,13 +20777,13 @@ hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
# Whether we need a single "-rpath" flag with a separated argument.
hardcode_libdir_separator=$lt_hardcode_libdir_separator
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
# DIR into the resulting binary.
hardcode_direct=$hardcode_direct
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
# DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
# library is relocated.
hardcode_direct_absolute=$hardcode_direct_absolute
@@ -18280,13 +20849,72 @@ compiler_lib_search_path=$lt_compiler_lib_search_path
_LT_EOF
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x$2 in
+ x)
+ ;;
+ *:)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+ ;;
+ x:*)
+ eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+ ;;
+ *)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+
+
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in $*""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
case $host_os in
aix3*)
cat <<\_LT_EOF >> "$cfgfile"
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
+if test set != "${COLLECT_NAMES+set}"; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
@@ -18295,7 +20923,7 @@ _LT_EOF
esac
-ltmain="$ac_aux_dir/ltmain.sh"
+ltmain=$ac_aux_dir/ltmain.sh
# We use sed instead of cat because bash on DJGPP gets confused if
@@ -18305,165 +20933,6 @@ ltmain="$ac_aux_dir/ltmain.sh"
sed '$q' "$ltmain" >> "$cfgfile" \
|| (rm -f "$cfgfile"; exit 1)
- if test x"$xsi_shell" = xyes; then
- sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
-func_dirname ()\
-{\
-\ case ${1} in\
-\ */*) func_dirname_result="${1%/*}${2}" ;;\
-\ * ) func_dirname_result="${3}" ;;\
-\ esac\
-} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_basename ()$/,/^} # func_basename /c\
-func_basename ()\
-{\
-\ func_basename_result="${1##*/}"\
-} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
-func_dirname_and_basename ()\
-{\
-\ case ${1} in\
-\ */*) func_dirname_result="${1%/*}${2}" ;;\
-\ * ) func_dirname_result="${3}" ;;\
-\ esac\
-\ func_basename_result="${1##*/}"\
-} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
-func_stripname ()\
-{\
-\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
-\ # positional parameters, so assign one to ordinary parameter first.\
-\ func_stripname_result=${3}\
-\ func_stripname_result=${func_stripname_result#"${1}"}\
-\ func_stripname_result=${func_stripname_result%"${2}"}\
-} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
-func_split_long_opt ()\
-{\
-\ func_split_long_opt_name=${1%%=*}\
-\ func_split_long_opt_arg=${1#*=}\
-} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
-func_split_short_opt ()\
-{\
-\ func_split_short_opt_arg=${1#??}\
-\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
-} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
-func_lo2o ()\
-{\
-\ case ${1} in\
-\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
-\ *) func_lo2o_result=${1} ;;\
-\ esac\
-} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_xform ()$/,/^} # func_xform /c\
-func_xform ()\
-{\
- func_xform_result=${1%.*}.lo\
-} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_arith ()$/,/^} # func_arith /c\
-func_arith ()\
-{\
- func_arith_result=$(( $* ))\
-} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_len ()$/,/^} # func_len /c\
-func_len ()\
-{\
- func_len_result=${#1}\
-} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-fi
-
-if test x"$lt_shell_append" = xyes; then
- sed -e '/^func_append ()$/,/^} # func_append /c\
-func_append ()\
-{\
- eval "${1}+=\\${2}"\
-} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
-func_append_quoted ()\
-{\
-\ func_quote_for_eval "${2}"\
-\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
-} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-
-
- # Save a `func_append' function call where possible by direct use of '+='
- sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
- test 0 -eq $? || _lt_function_replace_fail=:
-else
- # Save a `func_append' function call even when '+=' is not available
- sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
- test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
-$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
-fi
-
-
mv -f "$cfgfile" "$ofile" ||
(rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
chmod +x "$ofile"
@@ -18550,13 +21019,13 @@ hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
# Whether we need a single "-rpath" flag with a separated argument.
hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
# DIR into the resulting binary.
hardcode_direct=$hardcode_direct_CXX
-# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
# DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
# library is relocated.
hardcode_direct_absolute=$hardcode_direct_absolute_CXX
@@ -18622,6 +21091,7 @@ compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
_LT_EOF
;;
+ "run.sh":F) chmod +x run.sh ;;
esac
done # for ac_tag
@@ -18661,8 +21131,30 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi
-abs_srcdir="`cd $srcdir && pwd`"
-abs_builddir="`pwd`"
-if test "$abs_srcdir" != "$abs_builddir"; then
- make mkdir-init
-fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}:
+
+Automake flags (can be overridden by user flags):
+ AM_CPPFLAGS: ${AM_CPPFLAGS}
+ AM_CFLAGS: ${AM_CFLAGS}
+ AM_CXXFLAGS: ${AM_CXXFLAGS}
+ AM_LDFLAGS: ${AM_LDFLAGS}
+
+User flags (override Automake flags on conflict):
+ CPPFLAGS: ${CPPFLAGS}
+ CFLAGS: ${CFLAGS}
+ CXXFLAGS: ${CXXFLAGS}
+ LDFLAGS: ${LDFLAGS}" >&5
+$as_echo "$as_me:
+
+Automake flags (can be overridden by user flags):
+ AM_CPPFLAGS: ${AM_CPPFLAGS}
+ AM_CFLAGS: ${AM_CFLAGS}
+ AM_CXXFLAGS: ${AM_CXXFLAGS}
+ AM_LDFLAGS: ${AM_LDFLAGS}
+
+User flags (override Automake flags on conflict):
+ CPPFLAGS: ${CPPFLAGS}
+ CFLAGS: ${CFLAGS}
+ CXXFLAGS: ${CXXFLAGS}
+ LDFLAGS: ${LDFLAGS}" >&6;}
diff --git a/3rdparty/expat/configure.ac b/3rdparty/expat/configure.ac
index 7e968c46de3..82ec1fdd178 100644
--- a/3rdparty/expat/configure.ac
+++ b/3rdparty/expat/configure.ac
@@ -10,8 +10,8 @@ dnl under the terms of the License (based on the MIT/X license) contained
dnl in the file COPYING that comes with this distribution.
dnl
-dnl Ensure that Expat is configured with autoconf 2.58 or newer
-AC_PREREQ(2.58)
+dnl Ensure that Expat is configured with autoconf 2.69 or newer.
+AC_PREREQ(2.69)
dnl Get the version number of Expat, using m4's esyscmd() command to run
dnl the command at m4-generation time. This allows us to create an m4
@@ -23,15 +23,18 @@ dnl
dnl NOTE: esyscmd() is a GNU M4 extension. Thus, we wrap it in an appropriate
dnl test. I believe this test will work, but I don't have a place with non-
dnl GNU M4 to test it right now.
-define([expat_version], ifdef([__gnu__],
- [esyscmd(conftools/get-version.sh lib/expat.h)],
- [2.1.x]))
+m4_define([expat_version],
+ m4_ifdef([__gnu__],
+ [esyscmd(conftools/get-version.sh lib/expat.h)],
+ [2.2.x]))
AC_INIT(expat, expat_version, expat-bugs@libexpat.org)
-undefine([expat_version])
+m4_undefine([expat_version])
-AC_CONFIG_SRCDIR(Makefile.in)
-AC_CONFIG_AUX_DIR(conftools)
+AC_CONFIG_SRCDIR([Makefile.in])
+AC_CONFIG_AUX_DIR([conftools])
AC_CONFIG_MACRO_DIR([m4])
+AC_CANONICAL_HOST
+AM_INIT_AUTOMAKE
dnl
@@ -41,115 +44,302 @@ dnl If the API has changed, increment LIBCURRENT and set LIBREVISION to 0
dnl
dnl If the API changes compatibly (i.e. simply adding a new function
dnl without changing or removing earlier interfaces), then increment LIBAGE.
-dnl
+dnl
dnl If the API changes incompatibly set LIBAGE back to 0
dnl
-LIBCURRENT=7
-LIBREVISION=0
-LIBAGE=6
+LIBCURRENT=7 # sync
+LIBREVISION=12 # with
+LIBAGE=6 # CMakeLists.txt!
-AC_CONFIG_HEADER(expat_config.h)
+AX_APPEND_FLAG([-DHAVE_EXPAT_CONFIG_H], [AM_CPPFLAGS])
+AC_CONFIG_HEADER([expat_config.h])
-sinclude(conftools/ac_c_bigendian_cross.m4)
+AM_PROG_AR
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
-AC_LIBTOOL_WIN32_DLL
-AC_PROG_LIBTOOL
+LT_PREREQ([2.4])
+LT_INIT([win32-dll])
AC_SUBST(LIBCURRENT)
AC_SUBST(LIBREVISION)
AC_SUBST(LIBAGE)
-dnl Checks for programs.
-AC_PROG_CC
+AC_LANG([C])
+AC_PROG_CC_C99
+
+AS_IF([test "$GCC" = yes],
+ [AX_APPEND_COMPILE_FLAGS([-Wall -Wextra], [AM_CFLAGS])
+ dnl Be careful about adding the -fexceptions option; some versions of
+ dnl GCC don't support it and it causes extra warnings that are only
+ dnl distracting; avoid.
+ AX_APPEND_COMPILE_FLAGS([-fexceptions], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing -Wmissing-prototypes -Wstrict-prototypes], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-pedantic -Wduplicated-cond -Wduplicated-branches -Wlogical-op], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion], [AM_CFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-Wshadow -Wformat=2 -Wmisleading-indentation], [AM_CFLAGS])])
+
+AC_LANG_PUSH([C++])
AC_PROG_CXX
-AC_PROG_INSTALL
-if test "$GCC" = yes ; then
- dnl
- dnl Be careful about adding the -fexceptions option; some versions of
- dnl GCC don't support it and it causes extra warnings that are only
- dnl distracting; avoid.
- dnl
- OLDCFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes"
- CFLAGS="$OLDCFLAGS -fexceptions"
- AC_MSG_CHECKING(whether $CC accepts -fexceptions)
- AC_TRY_LINK( , ,
- AC_MSG_RESULT(yes),
- AC_MSG_RESULT(no); CFLAGS="$OLDCFLAGS")
- CXXFLAGS=`echo "$CFLAGS" | sed 's/ -Wmissing-prototypes -Wstrict-prototypes//'`
-fi
+AS_IF([test "$GCC" = yes],
+ [AX_APPEND_COMPILE_FLAGS([-Wall -Wextra], [AM_CXXFLAGS])
+ dnl Be careful about adding the -fexceptions option; some versions of
+ dnl GCC don't support it and it causes extra warnings that are only
+ dnl distracting; avoid.
+ AX_APPEND_COMPILE_FLAGS([-fexceptions], [AM_CXXFLAGS])
+ AX_APPEND_COMPILE_FLAGS([-fno-strict-aliasing], [AM_CXXFLAGS])])
+AC_LANG_POP([C++])
+
+AS_IF([test "$GCC" = yes],
+ [AX_APPEND_LINK_FLAGS([-fno-strict-aliasing],[AM_LDFLAGS])])
+
+dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang (issue #312)
+AS_CASE(["$LD"],[*clang*],
+ [AS_CASE(["${host_os}"],
+ [*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
+
+EXPATCFG_COMPILER_SUPPORTS_VISIBILITY([
+ AX_APPEND_FLAG([-fvisibility=hidden], [AM_CFLAGS])
+ AX_APPEND_FLAG([-DXML_ENABLE_VISIBILITY=1], [AM_CPPFLAGS])])
dnl Checks for header files.
AC_HEADER_STDC
dnl Checks for typedefs, structures, and compiler characteristics.
-dnl Note: Avoid using AC_C_BIGENDIAN because it does not
-dnl work in a cross compile.
-AC_C_BIGENDIAN_CROSS
+dnl We define BYTEORDER to 1234 when the platform is little endian; it
+dnl defines it to 4321 when the platform is big endian. We also define
+dnl WORDS_BIGENDIAN to 1 when the platform is big endian.
+dnl
+dnl A long time ago (early 2000 years) AC_C_BIGENDIAN was considered
+dnl wrong when cross compiling, now (2018, GNU Autoconf 2.69) we assume
+dnl it is fine.
+AC_C_BIGENDIAN([AC_DEFINE([WORDS_BIGENDIAN], 1)
+ AS_VAR_SET([BYTEORDER], 4321)],
+ [AS_VAR_SET([BYTEORDER], 1234)])
+AC_DEFINE_UNQUOTED([BYTEORDER], $BYTEORDER, [1234 = LILENDIAN, 4321 = BIGENDIAN])
AC_C_CONST
AC_TYPE_SIZE_T
-AC_CHECK_FUNCS(memmove bcopy)
+
+AC_ARG_WITH([xmlwf],
+ [AS_HELP_STRING([--without-xmlwf], [do not build xmlwf])],
+ [],
+ [with_xmlwf=yes])
+AM_CONDITIONAL([WITH_XMLWF], [test x${with_xmlwf} = xyes])
+
+AC_ARG_WITH([examples],
+ [AS_HELP_STRING([--without-examples], [do not build examples @<:@default=included@:>@])],
+ [],
+ [with_examples=yes])
+AM_CONDITIONAL([WITH_EXAMPLES], [test x${with_examples} = xyes])
+
+AC_ARG_WITH([tests],
+ [AS_HELP_STRING([--without-tests], [do not build tests @<:@default=included@:>@])],
+ [],
+ [with_tests=yes])
+AM_CONDITIONAL([WITH_TESTS], [test x${with_tests} = xyes])
+
+
+AS_VAR_SET([EXPATCFG_ON_MINGW],[no])
+AS_CASE("${host_os}",
+ [mingw*],
+ [AS_VAR_SET([EXPATCFG_ON_MINGW],[yes])
+ AC_MSG_NOTICE([detected OS: MinGW])])
+AM_CONDITIONAL([MINGW], [test x${EXPATCFG_ON_MINGW} = xyes])
+
+AM_CONDITIONAL([UNICODE], [echo -- "${CPPFLAGS}${CFLAGS}" | ${FGREP} XML_UNICODE >/dev/null])
+
+
+AC_ARG_WITH([libbsd],
+ [AS_HELP_STRING([--with-libbsd], [utilize libbsd (for arc4random_buf)])],
+ [],
+ [with_libbsd=no])
+AS_IF([test "x${with_libbsd}" != xno],
+ [AC_CHECK_LIB([bsd],
+ [arc4random_buf],
+ [],
+ [AS_IF([test "x${with_libbsd}" = xyes],
+ [AC_MSG_ERROR([Enforced use of libbsd cannot be satisfied.])])])])
+AC_MSG_CHECKING([for arc4random_buf (BSD or libbsd)])
+AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #include <stdlib.h> /* for arc4random_buf on BSD, for NULL */
+ #if defined(HAVE_LIBBSD)
+ # include <bsd/stdlib.h>
+ #endif
+ int main() {
+ arc4random_buf(NULL, 0U);
+ return 0;
+ }
+ ])],
+ [AC_DEFINE([HAVE_ARC4RANDOM_BUF], [1], [Define to 1 if you have the `arc4random_buf' function.])
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+
+ AC_MSG_CHECKING([for arc4random (BSD, macOS or libbsd)])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #if defined(HAVE_LIBBSD)
+ # include <bsd/stdlib.h>
+ #else
+ # include <stdlib.h>
+ #endif
+ int main() {
+ arc4random();
+ return 0;
+ }
+ ])],
+ [AC_DEFINE([HAVE_ARC4RANDOM], [1], [Define to 1 if you have the `arc4random' function.])
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])])])
+
+AC_ARG_WITH([getrandom],
+ [AS_HELP_STRING([--with-getrandom],
+ [enforce the use of getrandom function in the system @<:@default=check@:>@])
+AS_HELP_STRING([--without-getrandom],
+ [skip auto detect of getrandom @<:@default=check@:>@])],
+ [],
+ [with_getrandom=check])
+
+AS_IF([test "x$with_getrandom" != xno],
+ [AC_MSG_CHECKING([for getrandom (Linux 3.17+, glibc 2.25+)])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #include <stdlib.h> /* for NULL */
+ #include <sys/random.h>
+ int main() {
+ return getrandom(NULL, 0U, 0U);
+ }
+ ])],
+ [AC_DEFINE([HAVE_GETRANDOM], [1], [Define to 1 if you have the `getrandom' function.])
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AS_IF([test "x$with_getrandom" = xyes],
+ [AC_MSG_ERROR([enforced the use of getrandom --with-getrandom, but not detected])])])])
+
+AC_ARG_WITH([sys_getrandom],
+ [AS_HELP_STRING([--with-sys-getrandom],
+ [enforce the use of syscall SYS_getrandom function in the system @<:@default=check@:>@])
+AS_HELP_STRING([--without-sys-getrandom],
+ [skip auto detect of syscall SYS_getrandom @<:@default=check@:>@])],
+ [],
+ [with_sys_getrandom=check])
+
+AS_IF([test "x$with_sys_getrandom" != xno],
+ [AC_MSG_CHECKING([for syscall SYS_getrandom (Linux 3.17+)])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #include <stdlib.h> /* for NULL */
+ #include <unistd.h> /* for syscall */
+ #include <sys/syscall.h> /* for SYS_getrandom */
+ int main() {
+ syscall(SYS_getrandom, NULL, 0, 0);
+ return 0;
+ }
+ ])],
+ [AC_DEFINE([HAVE_SYSCALL_GETRANDOM], [1], [Define to 1 if you have `syscall' and `SYS_getrandom'.])
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AS_IF([test "x$with_sys_getrandom" = xyes],
+ [AC_MSG_ERROR([enforced the use of syscall SYS_getrandom --with-sys-getrandom, but not detected])])])])
dnl Only needed for xmlwf:
AC_CHECK_HEADERS(fcntl.h unistd.h)
AC_TYPE_OFF_T
AC_FUNC_MMAP
-if test "$ac_cv_func_mmap_fixed_mapped" = "yes"; then
- FILEMAP=unixfilemap
-else
- FILEMAP=readfilemap
-fi
+AS_IF([test "$ac_cv_func_mmap_fixed_mapped" = "yes"],
+ [AS_VAR_SET(FILEMAP,unixfilemap)],
+ [AS_VAR_SET(FILEMAP,readfilemap)])
AC_SUBST(FILEMAP)
-dnl Needed for the test support code; this was found at
-dnl http://lists.gnu.org/archive/html/bug-autoconf/2002-07/msg00028.html
-
-# AC_CPP_FUNC
-# ------------------ #
-# Checks to see if ANSI C99 CPP variable __func__ works.
-# If not, perhaps __FUNCTION__ works instead.
-# If not, we'll just define __func__ to "".
-AC_DEFUN([AC_CPP_FUNC],
-[AC_REQUIRE([AC_PROG_CC_STDC])dnl
-AC_CACHE_CHECK([for an ANSI C99-conforming __func__], ac_cv_cpp_func,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
-[[char *foo = __func__;]])],
- [ac_cv_cpp_func=yes],
- [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
-[[char *foo = __FUNCTION__;]])],
- [ac_cv_cpp_func=__FUNCTION__],
- [ac_cv_cpp_func=no])])])
-if test $ac_cv_cpp_func = __FUNCTION__; then
- AC_DEFINE(__func__,__FUNCTION__,
- [Define to __FUNCTION__ or "" if `__func__' does not conform to
-ANSI C.])
-elif test $ac_cv_cpp_func = no; then
- AC_DEFINE(__func__,"",
- [Define to __FUNCTION__ or "" if `__func__' does not conform to
-ANSI C.])
-fi
-])# AC_CPP_FUNC
-
-AC_CPP_FUNC
-
dnl Some basic configuration:
AC_DEFINE([XML_NS], 1,
[Define to make XML Namespaces functionality available.])
AC_DEFINE([XML_DTD], 1,
[Define to make parameter entity parsing functionality available.])
-AC_DEFINE([XML_CONTEXT_BYTES], 1024,
- [Define to specify how much context to retain around the current parse point.])
+AC_DEFINE([XML_DEV_URANDOM], 1,
+ [Define to include code reading entropy from `/dev/urandom'.])
+
+AC_ARG_ENABLE([xml-attr-info],
+ [AS_HELP_STRING([--enable-xml-attr-info],
+ [Enable retrieving the byte offsets for attribute names and values @<:@default=no@:>@])],
+ [],
+ [enable_xml_attr_info=no])
+AS_IF([test "x${enable_xml_attr_info}" = "xyes"],
+ [AC_DEFINE([XML_ATTR_INFO], 1,
+ [Define to allow retrieving the byte offsets for attribute names and values.])])
+
+AC_ARG_ENABLE([xml-context],
+ AS_HELP_STRING([--enable-xml-context @<:@COUNT@:>@],
+ [Retain context around the current parse point;
+ default is enabled and a size of 1024 bytes])
+AS_HELP_STRING([--disable-xml-context],
+ [Do not retain context around the current parse point]),
+ [enable_xml_context=${enableval}])
+AS_IF([test "x${enable_xml_context}" != "xno"],
+ [AS_IF([test "x${enable_xml_context}" = "xyes" \
+ -o "x${enable_xml_context}" = "x"],
+ [AS_VAR_SET(enable_xml_context,1024)])
+ AC_DEFINE_UNQUOTED([XML_CONTEXT_BYTES], [${enable_xml_context}],
+ [Define to specify how much context to retain around the current parse point.])])
-AC_CONFIG_FILES([Makefile expat.pc])
+AC_ARG_WITH([docbook],
+ [AS_HELP_STRING([--with-docbook],
+ [enforce XML to man page compilation @<:@default=check@:>@])
+AS_HELP_STRING([--without-docbook],
+ [skip XML to man page compilation @<:@default=check@:>@])],
+ [],
+ [with_docbook=check])
+
+AC_ARG_VAR([DOCBOOK_TO_MAN], [docbook2x-man command])
+AS_IF([test "x$with_docbook" != xno],
+ [AC_CHECK_PROGS([DOCBOOK_TO_MAN], [docbook2x-man db2x_docbook2man docbook2man docbook-to-man])])
+AS_IF([test "x${DOCBOOK_TO_MAN}" = x -a "x$with_docbook" = xyes],
+ [AC_MSG_ERROR([Required program 'docbook2x-man' not found.])])
+AS_IF([test "x${DOCBOOK_TO_MAN}" != x -a "x$with_docbook" != xno],
+ [AS_IF([${DOCBOOK_TO_MAN} --help | grep -i -q -F sgmlbase],
+ [AC_MSG_ERROR([Your local ${DOCBOOK_TO_MAN} was found to work with SGML rather
+ than XML. Please install docbook2X and use variable DOCBOOK_TO_MAN to point
+ configure to command docbook2x-man of docbook2X.
+ Or use DOCBOOK_TO_MAN="xmlto man --skip-validation" if you have xmlto around.
+ You can also configure using --without-docbook if you can do without a man
+ page for xmlwf.])])])
+
+AM_CONDITIONAL(WITH_DOCBOOK, [test "x${DOCBOOK_TO_MAN}" != x])
+
+dnl write the Automake flags we set
+AC_SUBST([AM_CPPFLAGS])
+AC_SUBST([AM_CFLAGS])
+AC_SUBST([AM_CXXFLAGS])
+AC_SUBST([AM_LDFLAGS])
+
+dnl updating _EXPAT_OUTPUT_NAME variable to effect the package name in expat.pc file (issue #361)
+AC_SUBST(_EXPAT_OUTPUT_NAME, ["$PACKAGE_NAME"])
+
+AC_CONFIG_FILES([Makefile]
+ [expat.pc]
+ [doc/Makefile]
+ [examples/Makefile]
+ [lib/Makefile]
+ [tests/Makefile]
+ [tests/benchmark/Makefile]
+ [xmlwf/Makefile])
+AC_CONFIG_FILES([run.sh], [chmod +x run.sh])
AC_OUTPUT
-abs_srcdir="`cd $srcdir && pwd`"
-abs_builddir="`pwd`"
-if test "$abs_srcdir" != "$abs_builddir"; then
- make mkdir-init
-fi
+
+AC_MSG_NOTICE([
+
+Automake flags (can be overridden by user flags):
+ [AM_CPPFLAGS]: ${AM_CPPFLAGS}
+ [AM_CFLAGS]: ${AM_CFLAGS}
+ [AM_CXXFLAGS]: ${AM_CXXFLAGS}
+ [AM_LDFLAGS]: ${AM_LDFLAGS}
+
+User flags (override Automake flags on conflict):
+ CPPFLAGS: ${CPPFLAGS}
+ CFLAGS: ${CFLAGS}
+ CXXFLAGS: ${CXXFLAGS}
+ LDFLAGS: ${LDFLAGS}])
diff --git a/3rdparty/expat/conftools/ac_c_bigendian_cross.m4 b/3rdparty/expat/conftools/ac_c_bigendian_cross.m4
deleted file mode 100644
index e95ffb6dcbe..00000000000
--- a/3rdparty/expat/conftools/ac_c_bigendian_cross.m4
+++ /dev/null
@@ -1,81 +0,0 @@
-dnl @synopsis AC_C_BIGENDIAN_CROSS
-dnl
-dnl Check endianess even when crosscompiling
-dnl (partially based on the original AC_C_BIGENDIAN).
-dnl
-dnl The implementation will create a binary, and instead of running
-dnl the binary it will be grep'ed for some symbols that will look
-dnl different for different endianess of the binary.
-dnl
-dnl @version $Id: ac_c_bigendian_cross.m4,v 1.1 2001/07/24 19:51:35 fdrake Exp $
-dnl @author Guido Draheim <guidod@gmx.de>
-dnl
-AC_DEFUN([AC_C_BIGENDIAN_CROSS],
-[AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian,
-[ac_cv_c_bigendian=unknown
-# See if sys/param.h defines the BYTE_ORDER macro.
-AC_TRY_COMPILE([#include <sys/types.h>
-#include <sys/param.h>], [
-#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
- bogus endian macros
-#endif], [# It does; now see whether it defined to BIG_ENDIAN or not.
-AC_TRY_COMPILE([#include <sys/types.h>
-#include <sys/param.h>], [
-#if BYTE_ORDER != BIG_ENDIAN
- not big endian
-#endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)])
-if test $ac_cv_c_bigendian = unknown; then
-AC_TRY_RUN([main () {
- /* Are we little or big endian? From Harbison&Steele. */
- union
- {
- long l;
- char c[sizeof (long)];
- } u;
- u.l = 1;
- exit (u.c[sizeof (long) - 1] == 1);
-}], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes,
-[ echo $ac_n "cross-compiling... " 2>&AC_FD_MSG ])
-fi])
-if test $ac_cv_c_bigendian = unknown; then
-AC_MSG_CHECKING(to probe for byte ordering)
-[
-cat >conftest.c <<EOF
-short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
-short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
-void _ascii() { char* s = (char*) ascii_mm; s = (char*) ascii_ii; }
-short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
-short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
-void _ebcdic() { char* s = (char*) ebcdic_mm; s = (char*) ebcdic_ii; }
-int main() { _ascii (); _ebcdic (); return 0; }
-EOF
-] if test -f conftest.c ; then
- if ${CC-cc} -c conftest.c -o conftest.o && test -f conftest.o ; then
- if test `grep -l BIGenDianSyS conftest.o` ; then
- echo $ac_n ' big endian probe OK, ' 1>&AC_FD_MSG
- ac_cv_c_bigendian=yes
- fi
- if test `grep -l LiTTleEnDian conftest.o` ; then
- echo $ac_n ' little endian probe OK, ' 1>&AC_FD_MSG
- if test $ac_cv_c_bigendian = yes ; then
- ac_cv_c_bigendian=unknown;
- else
- ac_cv_c_bigendian=no
- fi
- fi
- echo $ac_n 'guessing bigendian ... ' >&AC_FD_MSG
- fi
- fi
-AC_MSG_RESULT($ac_cv_c_bigendian)
-fi
-if test $ac_cv_c_bigendian = yes; then
- AC_DEFINE(WORDS_BIGENDIAN, 1, [whether byteorder is bigendian])
- BYTEORDER=4321
-else
- BYTEORDER=1234
-fi
-AC_DEFINE_UNQUOTED(BYTEORDER, $BYTEORDER, [1234 = LIL_ENDIAN, 4321 = BIGENDIAN])
-if test $ac_cv_c_bigendian = unknown; then
- AC_MSG_ERROR(unknown endianess - sorry, please pre-set ac_cv_c_bigendian)
-fi
-])
diff --git a/3rdparty/expat/conftools/ar-lib b/3rdparty/expat/conftools/ar-lib
new file mode 100755
index 00000000000..1e9388e2ae3
--- /dev/null
+++ b/3rdparty/expat/conftools/ar-lib
@@ -0,0 +1,271 @@
+#! /bin/sh
+# Wrapper for Microsoft lib.exe
+
+me=ar-lib
+scriptversion=2019-07-04.01; # UTC
+
+# Copyright (C) 2010-2020 Free Software Foundation, Inc.
+# Written by Peter Rosin <peda@lysator.liu.se>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+
+# func_error message
+func_error ()
+{
+ echo "$me: $1" 1>&2
+ exit 1
+}
+
+file_conv=
+
+# func_file_conv build_file
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN* | MSYS*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv in
+ mingw)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin | msys)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_at_file at_file operation archive
+# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
+# for each of them.
+# When interpreting the content of the @FILE, do NOT use func_file_conv,
+# since the user would need to supply preconverted file names to
+# binutils ar, at least for MinGW.
+func_at_file ()
+{
+ operation=$2
+ archive=$3
+ at_file_contents=`cat "$1"`
+ eval set x "$at_file_contents"
+ shift
+
+ for member
+ do
+ $AR -NOLOGO $operation:"$member" "$archive" || exit $?
+ done
+}
+
+case $1 in
+ '')
+ func_error "no command. Try '$0 --help' for more information."
+ ;;
+ -h | --h*)
+ cat <<EOF
+Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
+
+Members may be specified in a file named with @FILE.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "$me, version $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test $# -lt 3; then
+ func_error "you must specify a program, an action and an archive"
+fi
+
+AR=$1
+shift
+while :
+do
+ if test $# -lt 2; then
+ func_error "you must specify a program, an action and an archive"
+ fi
+ case $1 in
+ -lib | -LIB \
+ | -ltcg | -LTCG \
+ | -machine* | -MACHINE* \
+ | -subsystem* | -SUBSYSTEM* \
+ | -verbose | -VERBOSE \
+ | -wx* | -WX* )
+ AR="$AR $1"
+ shift
+ ;;
+ *)
+ action=$1
+ shift
+ break
+ ;;
+ esac
+done
+orig_archive=$1
+shift
+func_file_conv "$orig_archive"
+archive=$file
+
+# strip leading dash in $action
+action=${action#-}
+
+delete=
+extract=
+list=
+quick=
+replace=
+index=
+create=
+
+while test -n "$action"
+do
+ case $action in
+ d*) delete=yes ;;
+ x*) extract=yes ;;
+ t*) list=yes ;;
+ q*) quick=yes ;;
+ r*) replace=yes ;;
+ s*) index=yes ;;
+ S*) ;; # the index is always updated implicitly
+ c*) create=yes ;;
+ u*) ;; # TODO: don't ignore the update modifier
+ v*) ;; # TODO: don't ignore the verbose modifier
+ *)
+ func_error "unknown action specified"
+ ;;
+ esac
+ action=${action#?}
+done
+
+case $delete$extract$list$quick$replace,$index in
+ yes,* | ,yes)
+ ;;
+ yesyes*)
+ func_error "more than one action specified"
+ ;;
+ *)
+ func_error "no action specified"
+ ;;
+esac
+
+if test -n "$delete"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ for member
+ do
+ case $1 in
+ @*)
+ func_at_file "${1#@}" -REMOVE "$archive"
+ ;;
+ *)
+ func_file_conv "$1"
+ $AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
+ ;;
+ esac
+ done
+
+elif test -n "$extract"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ if test $# -gt 0; then
+ for member
+ do
+ case $1 in
+ @*)
+ func_at_file "${1#@}" -EXTRACT "$archive"
+ ;;
+ *)
+ func_file_conv "$1"
+ $AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
+ ;;
+ esac
+ done
+ else
+ $AR -NOLOGO -LIST "$archive" | tr -d '\r' | sed -e 's/\\/\\\\/g' \
+ | while read member
+ do
+ $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
+ done
+ fi
+
+elif test -n "$quick$replace"; then
+ if test ! -f "$orig_archive"; then
+ if test -z "$create"; then
+ echo "$me: creating $orig_archive"
+ fi
+ orig_archive=
+ else
+ orig_archive=$archive
+ fi
+
+ for member
+ do
+ case $1 in
+ @*)
+ func_file_conv "${1#@}"
+ set x "$@" "@$file"
+ ;;
+ *)
+ func_file_conv "$1"
+ set x "$@" "$file"
+ ;;
+ esac
+ shift
+ shift
+ done
+
+ if test -n "$orig_archive"; then
+ $AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
+ else
+ $AR -NOLOGO -OUT:"$archive" "$@" || exit $?
+ fi
+
+elif test -n "$list"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ $AR -NOLOGO -LIST "$archive" || exit $?
+fi
diff --git a/3rdparty/expat/conftools/ax-append-compile-flags.m4 b/3rdparty/expat/conftools/ax-append-compile-flags.m4
new file mode 100644
index 00000000000..9c856356c0c
--- /dev/null
+++ b/3rdparty/expat/conftools/ax-append-compile-flags.m4
@@ -0,0 +1,46 @@
+# ============================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# For every FLAG1, FLAG2 it is checked whether the compiler works with the
+# flag. If it does, the flag is added FLAGS-VARIABLE
+#
+# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+# CFLAGS) is used. During the check the flag is always added to the
+# current language's flags.
+#
+# If EXTRA-FLAGS is defined, it is added to the current language's default
+# flags (e.g. CFLAGS) when the check is done. The check is thus made with
+# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
+# force the compiler to issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+# NOTE: This macro depends on the AX_APPEND_FLAG and
+# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
+# AX_APPEND_LINK_FLAGS.
+#
+# LICENSE
+#
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 7
+
+AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
+[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
+AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
+for flag in $1; do
+ AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
+done
+])dnl AX_APPEND_COMPILE_FLAGS
diff --git a/3rdparty/expat/conftools/ax-append-flag.m4 b/3rdparty/expat/conftools/ax-append-flag.m4
new file mode 100644
index 00000000000..dd6d8b61406
--- /dev/null
+++ b/3rdparty/expat/conftools/ax-append-flag.m4
@@ -0,0 +1,50 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
+#
+# DESCRIPTION
+#
+# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
+# added in between.
+#
+# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
+# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
+# FLAG.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 8
+
+AC_DEFUN([AX_APPEND_FLAG],
+[dnl
+AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
+AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
+AS_VAR_SET_IF(FLAGS,[
+ AS_CASE([" AS_VAR_GET(FLAGS) "],
+ [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
+ [
+ AS_VAR_APPEND(FLAGS,[" $1"])
+ AC_RUN_LOG([: FLAGS="$FLAGS"])
+ ])
+ ],
+ [
+ AS_VAR_SET(FLAGS,[$1])
+ AC_RUN_LOG([: FLAGS="$FLAGS"])
+ ])
+AS_VAR_POPDEF([FLAGS])dnl
+])dnl AX_APPEND_FLAG
diff --git a/3rdparty/expat/conftools/ax-append-link-flags.m4 b/3rdparty/expat/conftools/ax-append-link-flags.m4
new file mode 100644
index 00000000000..99b9fa5b4e8
--- /dev/null
+++ b/3rdparty/expat/conftools/ax-append-link-flags.m4
@@ -0,0 +1,44 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# For every FLAG1, FLAG2 it is checked whether the linker works with the
+# flag. If it does, the flag is added FLAGS-VARIABLE
+#
+# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is
+# used. During the check the flag is always added to the linker's flags.
+#
+# If EXTRA-FLAGS is defined, it is added to the linker's default flags
+# when the check is done. The check is thus made with the flags: "LDFLAGS
+# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
+# issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG.
+# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS.
+#
+# LICENSE
+#
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 7
+
+AC_DEFUN([AX_APPEND_LINK_FLAGS],
+[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
+for flag in $1; do
+ AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4])
+done
+])dnl AX_APPEND_LINK_FLAGS
diff --git a/3rdparty/expat/conftools/ax-check-compile-flag.m4 b/3rdparty/expat/conftools/ax-check-compile-flag.m4
new file mode 100644
index 00000000000..172e29656f3
--- /dev/null
+++ b/3rdparty/expat/conftools/ax-check-compile-flag.m4
@@ -0,0 +1,77 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG plus -Werror works with the current
+# language's compiler — C or C++ — or gives an error.
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the current language's default
+# flags (e.g. CFLAGS) when the check is done. The check is thus made with
+# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
+# force the compiler to issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+# Copyright (c) 2020 Sebastian Pipping <sebastian@pipping.org>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+ _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 -Werror $1"
+ AC_COMPILE_IFELSE([m4_default([$5],
+ [AC_LANG_SOURCE(
+ [[int main(void) { return 0; }]])])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/3rdparty/expat/conftools/ax-check-link-flag.m4 b/3rdparty/expat/conftools/ax-check-link-flag.m4
new file mode 100644
index 00000000000..03a30ce4c73
--- /dev/null
+++ b/3rdparty/expat/conftools/ax-check-link-flag.m4
@@ -0,0 +1,53 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the linker or gives an error.
+# (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the linker's default flags
+# when the check is done. The check is thus made with the flags: "LDFLAGS
+# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
+# issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_LINK_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 6
+
+AC_DEFUN([AX_CHECK_LINK_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
+AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $4 $1"
+ AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ LDFLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_LINK_FLAGS
diff --git a/3rdparty/expat/conftools/ax-require-defined.m4 b/3rdparty/expat/conftools/ax-require-defined.m4
new file mode 100644
index 00000000000..17c3eab7daf
--- /dev/null
+++ b/3rdparty/expat/conftools/ax-require-defined.m4
@@ -0,0 +1,37 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_REQUIRE_DEFINED(MACRO)
+#
+# DESCRIPTION
+#
+# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
+# been defined and thus are available for use. This avoids random issues
+# where a macro isn't expanded. Instead the configure script emits a
+# non-fatal:
+#
+# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
+#
+# It's like AC_REQUIRE except it doesn't expand the required macro.
+#
+# Here's an example:
+#
+# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+#
+# LICENSE
+#
+# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 2
+
+AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
+ m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
+])dnl AX_REQUIRE_DEFINED
diff --git a/3rdparty/expat/conftools/compile b/3rdparty/expat/conftools/compile
new file mode 100755
index 00000000000..23fcba01132
--- /dev/null
+++ b/3rdparty/expat/conftools/compile
@@ -0,0 +1,348 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN* | MSYS*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/* | msys/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/3rdparty/expat/conftools/config.guess b/3rdparty/expat/conftools/config.guess
index 1f5c50c0d15..df895493ef7 100755
--- a/3rdparty/expat/conftools/config.guess
+++ b/3rdparty/expat/conftools/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2014 Free Software Foundation, Inc.
+# Copyright 1992-2019 Free Software Foundation, Inc.
-timestamp='2014-03-23'
+timestamp='2019-09-10'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@ timestamp='2014-03-23'
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -24,12 +24,12 @@ timestamp='2014-03-23'
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
-# Originally written by Per Bothner.
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
#
-# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+# Please send patches to <config-patches@gnu.org>.
me=`echo "$0" | sed -e 's,.*/,,'`
@@ -39,7 +39,7 @@ Usage: $0 [OPTION]
Output the configuration name of the system \`$me' is run on.
-Operation modes:
+Options:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -84,8 +84,6 @@ if test $# != 0; then
exit 1
fi
-trap 'exit 1' 1 2 15
-
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
@@ -96,34 +94,38 @@ trap 'exit 1' 1 2 15
# Portable tmp directory creation inspired by the Autoconf team.
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,) echo "int x;" > $dummy.c ;
- for c in cc gcc c89 c99 ; do
- if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+ : "${TMPDIR=/tmp}"
+ # shellcheck disable=SC2039
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+ dummy=$tmp/dummy
+ case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+ ,,) echo "int x;" > "$dummy.c"
+ for driver in cc gcc c89 c99 ; do
+ if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$driver"
+ break
+ fi
+ done
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+ esac
+}
# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+if test -f /.attbin/uname ; then
PATH=$PATH:/.attbin ; export PATH
fi
@@ -132,14 +134,14 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-case "${UNAME_SYSTEM}" in
+case "$UNAME_SYSTEM" in
Linux|GNU|GNU/*)
# If the system lacks a compiler, then just pick glibc.
# We could probably try harder.
LIBC=gnu
- eval $set_cc_for_build
- cat <<-EOF > $dummy.c
+ set_cc_for_build
+ cat <<-EOF > "$dummy.c"
#include <features.h>
#if defined(__UCLIBC__)
LIBC=uclibc
@@ -149,13 +151,20 @@ Linux|GNU|GNU/*)
LIBC=gnu
#endif
EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
+ # If ldd exists, use it to detect musl libc.
+ if command -v ldd >/dev/null && \
+ ldd --version 2>&1 | grep -q ^musl
+ then
+ LIBC=musl
+ fi
;;
esac
# Note: order is significant - the case branches are not exclusive.
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -168,21 +177,31 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
- case "${UNAME_MACHINE_ARCH}" in
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ "/sbin/$sysctl" 2>/dev/null || \
+ "/usr/sbin/$sysctl" 2>/dev/null || \
+ echo unknown)`
+ case "$UNAME_MACHINE_ARCH" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
- *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ earmv*)
+ arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine="${arch}${endian}"-unknown
+ ;;
+ *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
esac
# The Operating System including object format, if it has switched
- # to ELF recently, or will in the future.
- case "${UNAME_MACHINE_ARCH}" in
+ # to ELF recently (or will in the future) and ABI.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ os=netbsdelf
+ ;;
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval $set_cc_for_build
+ set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
then
@@ -197,43 +216,72 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd
;;
esac
+ # Determine ABI tags.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ ;;
+ esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
# kernel version information, so it can be replaced with a
# suitable tag, in the style of linux-gnu.
- case "${UNAME_VERSION}" in
+ case "$UNAME_VERSION" in
Debian*)
release='-gnu'
;;
*)
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}"
+ echo "$machine-${os}${release}${abi-}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
exit ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+ exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+ exit ;;
+ *:MidnightBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
exit ;;
*:ekkoBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
exit ;;
*:SolidBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
+ exit ;;
+ *:OS108:*:*)
+ echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
exit ;;
macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
exit ;;
*:MirBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:Sortix:*:*)
+ echo "$UNAME_MACHINE"-unknown-sortix
+ exit ;;
+ *:Twizzler:*:*)
+ echo "$UNAME_MACHINE"-unknown-twizzler
+ exit ;;
+ *:Redox:*:*)
+ echo "$UNAME_MACHINE"-unknown-redox
+ exit ;;
+ mips:OSF1:*.*)
+ echo mips-dec-osf1
exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
@@ -251,63 +299,54 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"EV4.5 (21064)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"LCA4 (21066/21068)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"EV5 (21164)")
- UNAME_MACHINE="alphaev5" ;;
+ UNAME_MACHINE=alphaev5 ;;
"EV5.6 (21164A)")
- UNAME_MACHINE="alphaev56" ;;
+ UNAME_MACHINE=alphaev56 ;;
"EV5.6 (21164PC)")
- UNAME_MACHINE="alphapca56" ;;
+ UNAME_MACHINE=alphapca56 ;;
"EV5.7 (21164PC)")
- UNAME_MACHINE="alphapca57" ;;
+ UNAME_MACHINE=alphapca57 ;;
"EV6 (21264)")
- UNAME_MACHINE="alphaev6" ;;
+ UNAME_MACHINE=alphaev6 ;;
"EV6.7 (21264A)")
- UNAME_MACHINE="alphaev67" ;;
+ UNAME_MACHINE=alphaev67 ;;
"EV6.8CB (21264C)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.8AL (21264B)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.8CX (21264D)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.9A (21264/EV69A)")
- UNAME_MACHINE="alphaev69" ;;
+ UNAME_MACHINE=alphaev69 ;;
"EV7 (21364)")
- UNAME_MACHINE="alphaev7" ;;
+ UNAME_MACHINE=alphaev7 ;;
"EV7.9 (21364A)")
- UNAME_MACHINE="alphaev79" ;;
+ UNAME_MACHINE=alphaev79 ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
exit $exitcode ;;
- Alpha\ *:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # Should we change UNAME_MACHINE based on the output of uname instead
- # of the specific Alpha model?
- echo alpha-pc-interix
- exit ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit ;;
Amiga*:UNIX_System_V:4.0:*)
echo m68k-unknown-sysv4
exit ;;
*:[Aa]miga[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-amigaos
+ echo "$UNAME_MACHINE"-unknown-amigaos
exit ;;
*:[Mm]orph[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-morphos
+ echo "$UNAME_MACHINE"-unknown-morphos
exit ;;
*:OS/390:*:*)
echo i370-ibm-openedition
@@ -319,7 +358,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
+ echo arm-acorn-riscix"$UNAME_RELEASE"
exit ;;
arm*:riscos:*:*|arm*:RISCOS:*:*)
echo arm-unknown-riscos
@@ -346,38 +385,38 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
s390x:SunOS:*:*)
- echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
exit ;;
sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
- echo i386-pc-auroraux${UNAME_RELEASE}
+ echo i386-pc-auroraux"$UNAME_RELEASE"
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
- eval $set_cc_for_build
- SUN_ARCH="i386"
+ set_cc_for_build
+ SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
- SUN_ARCH="x86_64"
+ SUN_ARCH=x86_64
fi
fi
- echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
exit ;;
sun4*:SunOS:*:*)
case "`/usr/bin/arch -k`" in
@@ -386,25 +425,25 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
;;
esac
# Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
exit ;;
sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
+ echo m68k-sun-sunos"$UNAME_RELEASE"
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
- echo m68k-sun-sunos${UNAME_RELEASE}
+ echo m68k-sun-sunos"$UNAME_RELEASE"
;;
sun4)
- echo sparc-sun-sunos${UNAME_RELEASE}
+ echo sparc-sun-sunos"$UNAME_RELEASE"
;;
esac
exit ;;
aushp:SunOS:*:*)
- echo sparc-auspex-sunos${UNAME_RELEASE}
+ echo sparc-auspex-sunos"$UNAME_RELEASE"
exit ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
@@ -415,44 +454,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint"$UNAME_RELEASE"
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint"$UNAME_RELEASE"
exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint"$UNAME_RELEASE"
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
+ echo m68k-milan-mint"$UNAME_RELEASE"
exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
+ echo m68k-hades-mint"$UNAME_RELEASE"
exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
+ echo m68k-unknown-mint"$UNAME_RELEASE"
exit ;;
m68k:machten:*:*)
- echo m68k-apple-machten${UNAME_RELEASE}
+ echo m68k-apple-machten"$UNAME_RELEASE"
exit ;;
powerpc:machten:*:*)
- echo powerpc-apple-machten${UNAME_RELEASE}
+ echo powerpc-apple-machten"$UNAME_RELEASE"
exit ;;
RISC*:Mach:*:*)
echo mips-dec-mach_bsd4.3
exit ;;
RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
+ echo mips-dec-ultrix"$UNAME_RELEASE"
exit ;;
VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
+ echo vax-dec-ultrix"$UNAME_RELEASE"
exit ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix${UNAME_RELEASE}
+ echo clipper-intergraph-clix"$UNAME_RELEASE"
exit ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
#ifdef __cplusplus
#include <stdio.h> /* for printf() prototype */
int main (int argc, char *argv[]) {
@@ -461,23 +500,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
#endif
#if defined (host_mips) && defined (MIPSEB)
#if defined (SYSTYPE_SYSV)
- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_SVR4)
- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
#endif
#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
#endif
#endif
exit (-1);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c &&
- dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`$dummy $dummyarg` &&
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+ dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos${UNAME_RELEASE}
+ echo mips-mips-riscos"$UNAME_RELEASE"
exit ;;
Motorola:PowerMAX_OS:*:*)
echo powerpc-motorola-powermax
@@ -503,17 +542,17 @@ EOF
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
then
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
- [ ${TARGET_BINARY_INTERFACE}x = x ]
+ if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
+ [ "$TARGET_BINARY_INTERFACE"x = x ]
then
- echo m88k-dg-dgux${UNAME_RELEASE}
+ echo m88k-dg-dgux"$UNAME_RELEASE"
else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ echo m88k-dg-dguxbcs"$UNAME_RELEASE"
fi
else
- echo i586-dg-dgux${UNAME_RELEASE}
+ echo i586-dg-dgux"$UNAME_RELEASE"
fi
exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
@@ -530,7 +569,7 @@ EOF
echo m68k-tektronix-bsd
exit ;;
*:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
exit ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
@@ -542,14 +581,14 @@ EOF
if [ -x /usr/bin/oslevel ] ; then
IBM_REV=`/usr/bin/oslevel`
else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
- echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
exit ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
main()
@@ -560,7 +599,7 @@ EOF
exit(0);
}
EOF
- if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
then
echo "$SYSTEM_NAME"
else
@@ -574,26 +613,27 @@ EOF
exit ;;
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
- if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
else
IBM_ARCH=powerpc
fi
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
+ if [ -x /usr/bin/lslpp ] ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
exit ;;
*:AIX:*:*)
echo rs6000-ibm-aix
exit ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
echo romp-ibm-bsd4.4
exit ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
exit ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
echo rs6000-bull-bosx
@@ -608,28 +648,28 @@ EOF
echo m68k-hp-bsd4.4
exit ;;
9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ case "$UNAME_MACHINE" in
+ 9000/31?) HP_ARCH=m68000 ;;
+ 9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ case "$sc_cpu_version" in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ case "$sc_kernel_bits" in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;;
esac
fi
- if [ "${HP_ARCH}" = "" ]; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ if [ "$HP_ARCH" = "" ]; then
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
#define _HPUX_SOURCE
#include <stdlib.h>
@@ -662,13 +702,13 @@ EOF
exit (0);
}
EOF
- (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ ${HP_ARCH} = "hppa2.0w" ]
+ if [ "$HP_ARCH" = hppa2.0w ]
then
- eval $set_cc_for_build
+ set_cc_for_build
# hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
# 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
@@ -679,23 +719,23 @@ EOF
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23
- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
- HP_ARCH="hppa2.0w"
+ HP_ARCH=hppa2.0w
else
- HP_ARCH="hppa64"
+ HP_ARCH=hppa64
fi
fi
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
exit ;;
ia64:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux${HPUX_REV}
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux"$HPUX_REV"
exit ;;
3050*:HI-UX:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ set_cc_for_build
+ sed 's/^ //' << EOF > "$dummy.c"
#include <unistd.h>
int
main ()
@@ -720,11 +760,11 @@ EOF
exit (0);
}
EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
{ echo "$SYSTEM_NAME"; exit; }
echo unknown-hitachi-hiuxwe2
exit ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
echo hppa1.1-hp-bsd
exit ;;
9000/8??:4.3bsd:*:*)
@@ -733,7 +773,7 @@ EOF
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
echo hppa1.0-hp-mpeix
exit ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
echo hppa1.1-hp-osf
exit ;;
hp8??:OSF1:*:*)
@@ -741,9 +781,9 @@ EOF
exit ;;
i*86:OSF1:*:*)
if [ -x /usr/sbin/sysversion ] ; then
- echo ${UNAME_MACHINE}-unknown-osf1mk
+ echo "$UNAME_MACHINE"-unknown-osf1mk
else
- echo ${UNAME_MACHINE}-unknown-osf1
+ echo "$UNAME_MACHINE"-unknown-osf1
fi
exit ;;
parisc*:Lites*:*:*)
@@ -768,127 +808,120 @@ EOF
echo c4-convex-bsd
exit ;;
CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*[A-Z]90:*:*:*)
- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
-e 's/\.[^.]*$/.X/'
exit ;;
CRAY*TS:*:*:*)
- echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
CRAY*SV1:*:*:*)
- echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
*:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
exit ;;
sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi${UNAME_RELEASE}
+ echo sparc-unknown-bsdi"$UNAME_RELEASE"
exit ;;
*:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ arm:FreeBSD:*:*)
+ UNAME_PROCESSOR=`uname -p`
+ set_cc_for_build
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+ else
+ echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+ fi
exit ;;
*:FreeBSD:*:*)
UNAME_PROCESSOR=`/usr/bin/uname -p`
- case ${UNAME_PROCESSOR} in
+ case "$UNAME_PROCESSOR" in
amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
esac
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
exit ;;
i*:CYGWIN*:*)
- echo ${UNAME_MACHINE}-pc-cygwin
+ echo "$UNAME_MACHINE"-pc-cygwin
exit ;;
*:MINGW64*:*)
- echo ${UNAME_MACHINE}-pc-mingw64
+ echo "$UNAME_MACHINE"-pc-mingw64
exit ;;
*:MINGW*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
+ echo "$UNAME_MACHINE"-pc-mingw32
exit ;;
*:MSYS*:*)
- echo ${UNAME_MACHINE}-pc-msys
- exit ;;
- i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
+ echo "$UNAME_MACHINE"-pc-msys
exit ;;
i*:PW*:*)
- echo ${UNAME_MACHINE}-pc-pw32
+ echo "$UNAME_MACHINE"-pc-pw32
exit ;;
*:Interix*:*)
- case ${UNAME_MACHINE} in
+ case "$UNAME_MACHINE" in
x86)
- echo i586-pc-interix${UNAME_RELEASE}
+ echo i586-pc-interix"$UNAME_RELEASE"
exit ;;
authenticamd | genuineintel | EM64T)
- echo x86_64-unknown-interix${UNAME_RELEASE}
+ echo x86_64-unknown-interix"$UNAME_RELEASE"
exit ;;
IA64)
- echo ia64-unknown-interix${UNAME_RELEASE}
+ echo ia64-unknown-interix"$UNAME_RELEASE"
exit ;;
esac ;;
- [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
- echo i${UNAME_MACHINE}-pc-mks
- exit ;;
- 8664:Windows_NT:*)
- echo x86_64-pc-mks
- exit ;;
- i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
- # UNAME_MACHINE based on the output of uname instead of i386?
- echo i586-pc-interix
- exit ;;
i*:UWIN*:*)
- echo ${UNAME_MACHINE}-pc-uwin
+ echo "$UNAME_MACHINE"-pc-uwin
exit ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
- exit ;;
- p*:CYGWIN*:*)
- echo powerpcle-unknown-cygwin
+ echo x86_64-pc-cygwin
exit ;;
prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
exit ;;
*:GNU:*:*)
# the GNU system
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
exit ;;
- i*86:Minix:*:*)
- echo ${UNAME_MACHINE}-pc-minix
+ *:Minix:*:*)
+ echo "$UNAME_MACHINE"-unknown-minix
exit ;;
aarch64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -901,129 +934,180 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
- if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
arm*:Linux:*:*)
- eval $set_cc_for_build
+ set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
else
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
fi
fi
exit ;;
avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
cris:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
exit ;;
crisv32:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ e2k:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
frv:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
hexagon:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
i*86:Linux:*:*)
- echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
exit ;;
ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ k1om:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ set_cc_for_build
+ IS_GLIBC=0
+ test x"${LIBC}" = xgnu && IS_GLIBC=1
+ sed 's/^ //' << EOF > "$dummy.c"
#undef CPU
- #undef ${UNAME_MACHINE}
- #undef ${UNAME_MACHINE}el
+ #undef mips
+ #undef mipsel
+ #undef mips64
+ #undef mips64el
+ #if ${IS_GLIBC} && defined(_ABI64)
+ LIBCABI=gnuabi64
+ #else
+ #if ${IS_GLIBC} && defined(_ABIN32)
+ LIBCABI=gnuabin32
+ #else
+ LIBCABI=${LIBC}
+ #endif
+ #endif
+
+ #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa64r6
+ #else
+ #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+ CPU=mipsisa32r6
+ #else
+ #if defined(__mips64)
+ CPU=mips64
+ #else
+ CPU=mips
+ #endif
+ #endif
+ #endif
+
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=${UNAME_MACHINE}el
+ MIPS_ENDIAN=el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=${UNAME_MACHINE}
+ MIPS_ENDIAN=
#else
- CPU=
+ MIPS_ENDIAN=
#endif
#endif
EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
+ test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
+ mips64el:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
openrisc*:Linux:*:*)
- echo or1k-unknown-linux-${LIBC}
+ echo or1k-unknown-linux-"$LIBC"
exit ;;
or32:Linux:*:* | or1k*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
padre:Linux:*:*)
- echo sparc-unknown-linux-${LIBC}
+ echo sparc-unknown-linux-"$LIBC"
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-${LIBC}
+ echo hppa64-unknown-linux-"$LIBC"
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
- PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
- *) echo hppa-unknown-linux-${LIBC} ;;
+ PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+ PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+ *) echo hppa-unknown-linux-"$LIBC" ;;
esac
exit ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-${LIBC}
+ echo powerpc64-unknown-linux-"$LIBC"
exit ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-${LIBC}
+ echo powerpc-unknown-linux-"$LIBC"
exit ;;
ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-${LIBC}
+ echo powerpc64le-unknown-linux-"$LIBC"
exit ;;
ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-${LIBC}
+ echo powerpcle-unknown-linux-"$LIBC"
+ exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
tile*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
exit ;;
x86_64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ set_cc_for_build
+ X86_64_ABI=
+ # If there is a compiler, see if it is configured for 32-bit objects.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_X32 >/dev/null
+ then
+ X86_64_ABI=x32
+ fi
+ fi
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC$X86_64_ABI"
exit ;;
xtensa*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
exit ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
@@ -1037,34 +1121,34 @@ EOF
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
exit ;;
i*86:OS/2:*:*)
# If we were able to find `uname', then EMX Unix compatibility
# is probably installed.
- echo ${UNAME_MACHINE}-pc-os2-emx
+ echo "$UNAME_MACHINE"-pc-os2-emx
exit ;;
i*86:XTS-300:*:STOP)
- echo ${UNAME_MACHINE}-unknown-stop
+ echo "$UNAME_MACHINE"-unknown-stop
exit ;;
i*86:atheos:*:*)
- echo ${UNAME_MACHINE}-unknown-atheos
+ echo "$UNAME_MACHINE"-unknown-atheos
exit ;;
i*86:syllable:*:*)
- echo ${UNAME_MACHINE}-pc-syllable
+ echo "$UNAME_MACHINE"-pc-syllable
exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
+ echo i386-unknown-lynxos"$UNAME_RELEASE"
exit ;;
i*86:*DOS:*:*)
- echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ echo "$UNAME_MACHINE"-pc-msdosdjgpp
exit ;;
- i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
- UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ i*86:*:4.*:*)
+ UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
fi
exit ;;
i*86:*:5:[678]*)
@@ -1074,12 +1158,12 @@ EOF
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
exit ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
elif /bin/uname -X 2>/dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
@@ -1089,9 +1173,9 @@ EOF
&& UNAME_MACHINE=i686
(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
else
- echo ${UNAME_MACHINE}-pc-sysv32
+ echo "$UNAME_MACHINE"-pc-sysv32
fi
exit ;;
pc:*:*:*)
@@ -1099,7 +1183,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
- # prints for the "djgpp" host, or else GDB configury will decide that
+ # prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
@@ -1111,9 +1195,9 @@ EOF
exit ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
fi
exit ;;
mini*:CTIX:SYS*5:*)
@@ -1133,9 +1217,9 @@ EOF
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;;
@@ -1144,28 +1228,28 @@ EOF
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos${UNAME_RELEASE}
+ echo m68k-unknown-lynxos"$UNAME_RELEASE"
exit ;;
mc68030:UNIX_System_V:4.*:*)
echo m68k-atari-sysv4
exit ;;
TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos${UNAME_RELEASE}
+ echo sparc-unknown-lynxos"$UNAME_RELEASE"
exit ;;
rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ echo rs6000-unknown-lynxos"$UNAME_RELEASE"
exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
- echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ echo powerpc-unknown-lynxos"$UNAME_RELEASE"
exit ;;
SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv${UNAME_RELEASE}
+ echo mips-dde-sysv"$UNAME_RELEASE"
exit ;;
RM*:ReliantUNIX-*:*:*)
echo mips-sni-sysv4
@@ -1176,7 +1260,7 @@ EOF
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
+ echo "$UNAME_MACHINE"-sni-sysv4
else
echo ns32k-sni-sysv
fi
@@ -1196,23 +1280,23 @@ EOF
exit ;;
i*86:VOS:*:*)
# From Paul.Green@stratus.com.
- echo ${UNAME_MACHINE}-stratus-vos
+ echo "$UNAME_MACHINE"-stratus-vos
exit ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
echo hppa1.1-stratus-vos
exit ;;
mc68*:A/UX:*:*)
- echo m68k-apple-aux${UNAME_RELEASE}
+ echo m68k-apple-aux"$UNAME_RELEASE"
exit ;;
news*:NEWS-OS:6*:*)
echo mips-sony-newsos6
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
+ echo mips-nec-sysv"$UNAME_RELEASE"
else
- echo mips-unknown-sysv${UNAME_RELEASE}
+ echo mips-unknown-sysv"$UNAME_RELEASE"
fi
exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
@@ -1231,77 +1315,94 @@ EOF
echo x86_64-unknown-haiku
exit ;;
SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux${UNAME_RELEASE}
+ echo sx4-nec-superux"$UNAME_RELEASE"
exit ;;
SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux${UNAME_RELEASE}
+ echo sx5-nec-superux"$UNAME_RELEASE"
exit ;;
SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux${UNAME_RELEASE}
+ echo sx6-nec-superux"$UNAME_RELEASE"
exit ;;
SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux${UNAME_RELEASE}
+ echo sx7-nec-superux"$UNAME_RELEASE"
exit ;;
SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux${UNAME_RELEASE}
+ echo sx8-nec-superux"$UNAME_RELEASE"
exit ;;
SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux${UNAME_RELEASE}
+ echo sx8r-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux"$UNAME_RELEASE"
exit ;;
Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ echo powerpc-apple-rhapsody"$UNAME_RELEASE"
exit ;;
*:Rhapsody:*:*)
- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
exit ;;
*:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval $set_cc_for_build
- if test "$UNAME_PROCESSOR" = unknown ; then
- UNAME_PROCESSOR=powerpc
+ UNAME_PROCESSOR=`uname -p`
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ if command -v xcode-select > /dev/null 2> /dev/null && \
+ ! xcode-select --print-path > /dev/null 2> /dev/null ; then
+ # Avoid executing cc if there is no toolchain installed as
+ # cc will be a stub that puts up a graphical alert
+ # prompting the user to install developer tools.
+ CC_FOR_BUILD=no_compiler_found
+ else
+ set_cc_for_build
fi
- if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- case $UNAME_PROCESSOR in
- i386) UNAME_PROCESSOR=x86_64 ;;
- powerpc) UNAME_PROCESSOR=powerpc64 ;;
- esac
- fi
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
fi
elif test "$UNAME_PROCESSOR" = i386 ; then
- # Avoid executing cc on OS X 10.9, as it ships with a stub
- # that puts up a graphical alert prompting to install
- # developer tools. Any system running Mac OS X 10.7 or
- # later (Darwin 11 and later) is required to have a 64-bit
- # processor. This is not true of the ARM version of Darwin
- # that Apple uses in portable devices.
- UNAME_PROCESSOR=x86_64
+ # uname -m returns i386 or x86_64
+ UNAME_PROCESSOR=$UNAME_MACHINE
fi
- echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = "x86"; then
+ if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
- echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
exit ;;
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
- NEO-?:NONSTOP_KERNEL:*:*)
- echo neo-tandem-nsk${UNAME_RELEASE}
+ NEO-*:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk"$UNAME_RELEASE"
exit ;;
NSE-*:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk${UNAME_RELEASE}
+ echo nse-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk"$UNAME_RELEASE"
exit ;;
- NSR-?:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk${UNAME_RELEASE}
+ NSV-*:NONSTOP_KERNEL:*:*)
+ echo nsv-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk"$UNAME_RELEASE"
exit ;;
*:NonStop-UX:*:*)
echo mips-compaq-nonstopux
@@ -1310,18 +1411,19 @@ EOF
echo bs2000-siemens-sysv
exit ;;
DS/*:UNIX_System_V:*:*)
- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
exit ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
- if test "$cputype" = "386"; then
+ # shellcheck disable=SC2154
+ if test "$cputype" = 386; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
fi
- echo ${UNAME_MACHINE}-unknown-plan9
+ echo "$UNAME_MACHINE"-unknown-plan9
exit ;;
*:TOPS-10:*:*)
echo pdp10-unknown-tops10
@@ -1342,14 +1444,14 @@ EOF
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
+ echo mips-sei-seiux"$UNAME_RELEASE"
exit ;;
*:DragonFly:*:*)
- echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
exit ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
- case "${UNAME_MACHINE}" in
+ case "$UNAME_MACHINE" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
V*) echo vax-dec-vms ; exit ;;
@@ -1358,34 +1460,188 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
exit ;;
i*86:rdos:*:*)
- echo ${UNAME_MACHINE}-pc-rdos
+ echo "$UNAME_MACHINE"-pc-rdos
exit ;;
i*86:AROS:*:*)
- echo ${UNAME_MACHINE}-pc-aros
+ echo "$UNAME_MACHINE"-pc-aros
exit ;;
x86_64:VMkernel:*:*)
- echo ${UNAME_MACHINE}-unknown-esx
+ echo "$UNAME_MACHINE"-unknown-esx
+ exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
exit ;;
+ *:Unleashed:*:*)
+ echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
+ exit ;;
+esac
+
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+ printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname un;
+ uname (&un);
+ printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+ struct utsname *un;
+ uname (&un);
+ printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+ printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
+echo "$0: unable to guess system type" >&2
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+ mips:Linux | mips64:Linux)
+ # If we got here on MIPS GNU/Linux, output extra information.
+ cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+ ;;
esac
cat >&2 <<EOF
-$0: unable to guess system type
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches@gnu.org> in order to provide the needed
-information to handle your system.
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
config.guess timestamp = $timestamp
@@ -1404,16 +1660,16 @@ hostinfo = `(hostinfo) 2>/dev/null`
/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
EOF
exit 1
# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
+# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
diff --git a/3rdparty/expat/conftools/config.sub b/3rdparty/expat/conftools/config.sub
index bba4efb8057..96fca060bde 100755
--- a/3rdparty/expat/conftools/config.sub
+++ b/3rdparty/expat/conftools/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2014 Free Software Foundation, Inc.
+# Copyright 1992-2019 Free Software Foundation, Inc.
-timestamp='2014-09-11'
+timestamp='2019-06-30'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@ timestamp='2014-09-11'
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
@@ -25,7 +25,7 @@ timestamp='2014-09-11'
# of the GNU General Public License, version 3 ("GPLv3").
-# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+# Please send patches to <config-patches@gnu.org>.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
@@ -33,7 +33,7 @@ timestamp='2014-09-11'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -53,12 +53,11 @@ timestamp='2014-09-11'
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
- $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
Canonicalize a configuration name.
-Operation modes:
+Options:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
@@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -90,12 +89,12 @@ while test $# -gt 0 ; do
- ) # Use stdin as input.
break ;;
-* )
- echo "$me: invalid option $1$help"
+ echo "$me: invalid option $1$help" >&2
exit 1 ;;
*local*)
# First pass through any local machine types.
- echo $1
+ echo "$1"
exit ;;
* )
@@ -111,1220 +110,1185 @@ case $# in
exit 1;;
esac
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
- linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | \
- kopensolaris*-gnu* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
- os=-$maybe_os
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- android-linux)
- os=-linux-android
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
- ;;
- *)
- basic_machine=`echo $1 | sed 's/-[^-]*$//'`
- if [ $basic_machine != $1 ]
- then os=`echo $1 | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
+# Split fields of configuration type
+# shellcheck disable=SC2162
+IFS="-" read field1 field2 field3 field4 <<EOF
+$1
+EOF
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray | -microblaze*)
- os=
- basic_machine=$1
- ;;
- -bluegene*)
- os=-cnk
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=-vxworks
- basic_machine=$1
- ;;
- -chorusos*)
- os=-chorusos
- basic_machine=$1
- ;;
- -chorusrdb)
- os=-chorusrdb
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*178)
- os=-lynxos178
- ;;
- -lynx*5)
- os=-lynxos5
- ;;
- -lynx*)
- os=-lynxos
+# Separate into logical components for further validation
+case $1 in
+ *-*-*-*-*)
+ echo Invalid configuration \`"$1"\': more than four components >&2
+ exit 1
;;
- -ptx*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ *-*-*-*)
+ basic_machine=$field1-$field2
+ os=$field3-$field4
;;
- -windowsnt*)
- os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ *-*-*)
+ # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+ # parts
+ maybe_os=$field2-$field3
+ case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
+ | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
+ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+ | storm-chaos* | os2-emx* | rtmk-nova*)
+ basic_machine=$field1
+ os=$maybe_os
+ ;;
+ android-linux)
+ basic_machine=$field1-unknown
+ os=linux-android
+ ;;
+ *)
+ basic_machine=$field1-$field2
+ os=$field3
+ ;;
+ esac
;;
- -psos*)
- os=-psos
+ *-*)
+ # A lone config we happen to match not fitting any pattern
+ case $field1-$field2 in
+ decstation-3100)
+ basic_machine=mips-dec
+ os=
+ ;;
+ *-*)
+ # Second component is usually, but not always the OS
+ case $field2 in
+ # Prevent following clause from handling this valid os
+ sun*os*)
+ basic_machine=$field1
+ os=$field2
+ ;;
+ # Manufacturers
+ dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+ | unicom* | ibm* | next | hp | isi* | apollo | altos* \
+ | convergent* | ncr* | news | 32* | 3600* | 3100* \
+ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+ | ultra | tti* | harris | dolphin | highlevel | gould \
+ | cbm | ns | masscomp | apple | axis | knuth | cray \
+ | microblaze* | sim | cisco \
+ | oki | wec | wrs | winbond)
+ basic_machine=$field1-$field2
+ os=
+ ;;
+ *)
+ basic_machine=$field1
+ os=$field2
+ ;;
+ esac
+ ;;
+ esac
;;
- -mint | -mint[0-9]*)
- basic_machine=m68k-atari
- os=-mint
+ *)
+ # Convert single-component short-hands not valid as part of
+ # multi-component configurations.
+ case $field1 in
+ 386bsd)
+ basic_machine=i386-pc
+ os=bsd
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=udi
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=scout
+ ;;
+ alliant)
+ basic_machine=fx80-alliant
+ os=
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ os=
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=sysv
+ ;;
+ amiga)
+ basic_machine=m68k-unknown
+ os=
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=linux
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=bsd
+ ;;
+ cray)
+ basic_machine=j90-cray
+ os=unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ os=
+ ;;
+ da30)
+ basic_machine=m68k-da30
+ os=
+ ;;
+ decstation | pmax | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ os=
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=msdosdjgpp
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=ebmon
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=ose
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=go32
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=sysv3
+ ;;
+ hp300 | hp300hpux)
+ basic_machine=m68k-hp
+ os=hpux
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=bsd
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=proelf
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=mach
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=sysv
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=mingw32ce
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=msdos
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-pc
+ os=netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=sysv
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=nonstopux
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=os68k
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=linux
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=coff
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=udi
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ os=
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=sysv2
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ os=
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ os=
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=sunos4
+ ;;
+ sun3)
+ basic_machine=m68k-sun
+ os=
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=sunos4
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ os=
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=solaris2
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ os=
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=unicos
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=tops20
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=vms
+ ;;
+ vsta)
+ basic_machine=i386-pc
+ os=vsta
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=vxworks
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=mingw32
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=unicos
+ ;;
+ *)
+ basic_machine=$1
+ os=
+ ;;
+ esac
;;
esac
-# Decode aliases for certain CPU-COMPANY combinations.
+# Decode 1-component or ad-hoc basic machines
case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | aarch64 | aarch64_be \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | am33_2.0 \
- | arc | arceb \
- | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
- | avr | avr32 \
- | be32 | be64 \
- | bfin \
- | c4x | c8051 | clipper \
- | d10v | d30v | dlx | dsp16xx \
- | epiphany \
- | fido | fr30 | frv \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | hexagon \
- | i370 | i860 | i960 | ia64 \
- | ip2k | iq2000 \
- | k1om \
- | le32 | le64 \
- | lm32 \
- | m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64el \
- | mips64octeon | mips64octeonel \
- | mips64orion | mips64orionel \
- | mips64r5900 | mips64r5900el \
- | mips64vr | mips64vrel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa32r6 | mipsisa32r6el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r6 | mipsisa64r6el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
- | mipstx39 | mipstx39el \
- | mn10200 | mn10300 \
- | moxie \
- | mt \
- | msp430 \
- | nds32 | nds32le | nds32be \
- | nios | nios2 | nios2eb | nios2el \
- | ns16k | ns32k \
- | open8 | or1k | or1knd | or32 \
- | pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle \
- | pyramid \
- | riscv32 | riscv64 \
- | rl78 | rx \
- | score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
- | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu \
- | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
- | ubicom32 \
- | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
- | we32k \
- | x86 | xc16x | xstormy16 | xtensa \
- | z8k | z80)
- basic_machine=$basic_machine-unknown
- ;;
- c54x)
- basic_machine=tic54x-unknown
- ;;
- c55x)
- basic_machine=tic55x-unknown
- ;;
- c6x)
- basic_machine=tic6x-unknown
- ;;
- m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
- basic_machine=$basic_machine-unknown
- os=-none
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
- ;;
- ms1)
- basic_machine=mt-unknown
+ # Here we handle the default manufacturer of certain CPU types. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ cpu=hppa1.1
+ vendor=winbond
;;
-
- strongarm | thumb | xscale)
- basic_machine=arm-unknown
+ op50n)
+ cpu=hppa1.1
+ vendor=oki
;;
- xgate)
- basic_machine=$basic_machine-unknown
- os=-none
+ op60c)
+ cpu=hppa1.1
+ vendor=oki
;;
- xscaleeb)
- basic_machine=armeb-unknown
+ ibm*)
+ cpu=i370
+ vendor=ibm
;;
-
- xscaleel)
- basic_machine=armel-unknown
+ orion105)
+ cpu=clipper
+ vendor=highlevel
;;
-
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i*86 | x86_64)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
+ mac | mpw | mac-mpw)
+ cpu=m68k
+ vendor=apple
;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | aarch64-* | aarch64_be-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* | avr32-* \
- | be32-* | be64-* \
- | bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* \
- | c8051-* | clipper-* | craynv-* | cydra-* \
- | d10v-* | d30v-* | dlx-* \
- | elxsi-* \
- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | hexagon-* \
- | i*86-* | i860-* | i960-* | ia64-* \
- | ip2k-* | iq2000-* \
- | k1om-* \
- | le32-* | le64-* \
- | lm32-* \
- | m32c-* | m32r-* | m32rle-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
- | microblaze-* | microblazeel-* \
- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
- | mips16-* \
- | mips64-* | mips64el-* \
- | mips64octeon-* | mips64octeonel-* \
- | mips64orion-* | mips64orionel-* \
- | mips64r5900-* | mips64r5900el-* \
- | mips64vr-* | mips64vrel-* \
- | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* \
- | mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
- | mipsisa32-* | mipsisa32el-* \
- | mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa32r6-* | mipsisa32r6el-* \
- | mipsisa64-* | mipsisa64el-* \
- | mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64r6-* | mipsisa64r6el-* \
- | mipsisa64sb1-* | mipsisa64sb1el-* \
- | mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipsr5900-* | mipsr5900el-* \
- | mipstx39-* | mipstx39el-* \
- | mmix-* \
- | mt-* \
- | msp430-* \
- | nds32-* | nds32le-* | nds32be-* \
- | nios-* | nios2-* | nios2eb-* | nios2el-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | open8-* \
- | or1k*-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
- | pyramid-* \
- | rl78-* | romp-* | rs6000-* | rx-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
- | sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
- | tahoe-* \
- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
- | tile*-* \
- | tron-* \
- | ubicom32-* \
- | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
- | vax-* \
- | we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* \
- | xstormy16-* | xtensa*-* \
- | ymp-* \
- | z8k-* | z80-*)
- ;;
- # Recognize the basic CPU types without company name, with glob match.
- xtensa*)
- basic_machine=$basic_machine-unknown
+ pmac | pmac-mpw)
+ cpu=powerpc
+ vendor=apple
;;
+
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-unknown
- os=-bsd
- ;;
3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
+ cpu=m68000
+ vendor=att
;;
3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- abacus)
- basic_machine=abacus-unknown
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- amigaos | amigados)
- basic_machine=m68k-unknown
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-unknown
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aros)
- basic_machine=i386-pc
- os=-aros
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- blackfin)
- basic_machine=bfin-unknown
- os=-linux
- ;;
- blackfin-*)
- basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
+ cpu=we32k
+ vendor=att
;;
bluegene*)
- basic_machine=powerpc-ibm
- os=-cnk
- ;;
- c54x-*)
- basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- c55x-*)
- basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- c6x-*)
- basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- c90)
- basic_machine=c90-cray
- os=-unicos
- ;;
- cegcc)
- basic_machine=arm-unknown
- os=-cegcc
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | j90)
- basic_machine=j90-cray
- os=-unicos
- ;;
- craynv)
- basic_machine=craynv-cray
- os=-unicosmp
- ;;
- cr16 | cr16-*)
- basic_machine=cr16-unknown
- os=-elf
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- crx)
- basic_machine=crx-unknown
- os=-elf
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
+ cpu=powerpc
+ vendor=ibm
+ os=cnk
;;
decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=-tops10
+ cpu=pdp10
+ vendor=dec
+ os=tops10
;;
decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=-tops20
+ cpu=pdp10
+ vendor=dec
+ os=tops20
;;
delta | 3300 | motorola-3300 | motorola-delta \
| 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- dicos)
- basic_machine=i686-pc
- os=-dicos
- ;;
- djgpp)
- basic_machine=i586-pc
- os=-msdosdjgpp
+ cpu=m68k
+ vendor=motorola
;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
- ;;
- dpx2* | dpx2*-bull)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
+ dpx2*)
+ cpu=m68k
+ vendor=bull
+ os=sysv3
;;
encore | umax | mmax)
- basic_machine=ns32k-encore
+ cpu=ns32k
+ vendor=encore
;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
+ elxsi)
+ cpu=elxsi
+ vendor=elxsi
+ os=${os:-bsd}
;;
fx2800)
- basic_machine=i860-alliant
+ cpu=i860
+ vendor=alliant
;;
genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- go32)
- basic_machine=i386-pc
- os=-go32
+ cpu=ns32k
+ vendor=ns
;;
h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
+ cpu=hppa1.1
+ vendor=hitachi
+ os=hiuxwe2
;;
hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
+ cpu=hppa1.0
+ vendor=hp
;;
hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
+ cpu=m68000
+ vendor=hp
;;
hp9k3[2-9][0-9])
- basic_machine=m68k-hp
+ cpu=m68k
+ vendor=hp
;;
hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
+ cpu=hppa1.0
+ vendor=hp
;;
hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k78[0-9] | hp78[0-9])
# FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
# FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
+ cpu=hppa1.1
+ vendor=hp
;;
hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppa-next)
- os=-nextstep3
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
+ cpu=hppa1.0
+ vendor=hp
;;
i*86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv32
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ os=sysv32
;;
i*86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv4
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ os=sysv4
;;
i*86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ os=sysv
;;
i*86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-solaris2
- ;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
+ cpu=`echo "$1" | sed -e 's/86.*/86/'`
+ vendor=pc
+ os=solaris2
;;
- i386-vsta | vsta)
- basic_machine=i386-unknown
- os=-vsta
+ j90 | j90-cray)
+ cpu=j90
+ vendor=cray
+ os=${os:-unicos}
;;
iris | iris4d)
- basic_machine=mips-sgi
+ cpu=mips
+ vendor=sgi
case $os in
- -irix*)
+ irix*)
;;
*)
- os=-irix4
+ os=irix4
;;
esac
;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- m68knommu)
- basic_machine=m68k-unknown
- os=-linux
- ;;
- m68knommu-*)
- basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- m88k-omron*)
- basic_machine=m88k-omron
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- microblaze*)
- basic_machine=microblaze-xilinx
- ;;
- mingw64)
- basic_machine=x86_64-pc
- os=-mingw64
- ;;
- mingw32)
- basic_machine=i686-pc
- os=-mingw32
- ;;
- mingw32ce)
- basic_machine=arm-unknown
- os=-mingw32ce
- ;;
miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mips3*-*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- morphos)
- basic_machine=powerpc-unknown
- os=-morphos
- ;;
- moxiebox)
- basic_machine=moxie-unknown
- os=-moxiebox
- ;;
- msdos)
- basic_machine=i386-pc
- os=-msdos
- ;;
- ms1-*)
- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
- ;;
- msys)
- basic_machine=i686-pc
- os=-msys
- ;;
- mvs)
- basic_machine=i370-ibm
- os=-mvs
- ;;
- nacl)
- basic_machine=le32-unknown
- os=-nacl
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
+ cpu=m68000
+ vendor=convergent
;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
+ *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ cpu=m68k
+ vendor=atari
+ os=mint
;;
- netwinder)
- basic_machine=armv4l-rebel
- os=-linux
+ mipsEE* | ee)
+ cpu=mips64r5900el
+ vendor=scei
+ case $os in
+ linux*)
+ ;;
+ *)
+ os=elf
+ ;;
+ esac
;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
+ iop)
+ cpu=mipsel
+ vendor=scei
+ os=irx
;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
+ dvp)
+ cpu=dvp
+ vendor=scei
+ os=elf
;;
news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
+ cpu=mips
+ vendor=sony
+ os=newsos
;;
- next | m*-next )
- basic_machine=m68k-next
+ next | m*-next)
+ cpu=m68k
+ vendor=next
case $os in
- -nextstep* )
+ openstep*)
+ ;;
+ nextstep*)
;;
- -ns2*)
- os=-nextstep2
+ ns2*)
+ os=nextstep2
;;
*)
- os=-nextstep3
+ os=nextstep3
;;
esac
;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- nonstopux)
- basic_machine=mips-compaq
- os=-nonstopux
- ;;
np1)
- basic_machine=np1-gould
- ;;
- neo-tandem)
- basic_machine=neo-tandem
- ;;
- nse-tandem)
- basic_machine=nse-tandem
- ;;
- nsr-tandem)
- basic_machine=nsr-tandem
+ cpu=np1
+ vendor=gould
;;
op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- openrisc | openrisc-*)
- basic_machine=or32-unknown
- ;;
- os400)
- basic_machine=powerpc-ibm
- os=-os400
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
+ cpu=hppa1.1
+ vendor=oki
+ os=proelf
;;
pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- parisc)
- basic_machine=hppa-unknown
- os=-linux
- ;;
- parisc-*)
- basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
+ cpu=hppa1.1
+ vendor=hitachi
+ os=hiuxwe2
;;
pbd)
- basic_machine=sparc-tti
+ cpu=sparc
+ vendor=tti
;;
pbb)
- basic_machine=m68k-tti
+ cpu=m68k
+ vendor=tti
;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pc98)
- basic_machine=i386-pc
- ;;
- pc98-*)
- basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86 | athlon | athlon_*)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2 | pentiumiii | pentium3)
- basic_machine=i686-pc
- ;;
- pentium4)
- basic_machine=i786-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium4-*)
- basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ pc532)
+ cpu=ns32k
+ vendor=pc532
;;
pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=power-ibm
- ;;
- ppc | ppcbe) basic_machine=powerpc-unknown
- ;;
- ppc-* | ppcbe-*)
- basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
- basic_machine=powerpcle-unknown
+ cpu=pn
+ vendor=gould
;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64) basic_machine=powerpc64-unknown
- ;;
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
- basic_machine=powerpc64le-unknown
- ;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ power)
+ cpu=power
+ vendor=ibm
;;
ps2)
- basic_machine=i386-ibm
- ;;
- pw32)
- basic_machine=i586-unknown
- os=-pw32
- ;;
- rdos | rdos64)
- basic_machine=x86_64-pc
- os=-rdos
- ;;
- rdos32)
- basic_machine=i386-pc
- os=-rdos
- ;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
+ cpu=i386
+ vendor=ibm
;;
rm[46]00)
- basic_machine=mips-siemens
+ cpu=mips
+ vendor=siemens
;;
rtpc | rtpc-*)
- basic_machine=romp-ibm
+ cpu=romp
+ vendor=ibm
;;
- s390 | s390-*)
- basic_machine=s390-ibm
- ;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
- ;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
+ sde)
+ cpu=mipsisa32
+ vendor=sde
+ os=${os:-elf}
;;
- sb1)
- basic_machine=mipsisa64sb1-unknown
+ simso-wrs)
+ cpu=sparclite
+ vendor=wrs
+ os=vxworks
;;
- sb1el)
- basic_machine=mipsisa64sb1el-unknown
+ tower | tower-32)
+ cpu=m68k
+ vendor=ncr
;;
- sde)
- basic_machine=mipsisa32-sde
- os=-elf
+ vpp*|vx|vx-*)
+ cpu=f301
+ vendor=fujitsu
;;
- sei)
- basic_machine=mips-sei
- os=-seiux
+ w65)
+ cpu=w65
+ vendor=wdc
;;
- sequent)
- basic_machine=i386-sequent
+ w89k-*)
+ cpu=hppa1.1
+ vendor=winbond
+ os=proelf
;;
- sh)
- basic_machine=sh-hitachi
- os=-hms
+ none)
+ cpu=none
+ vendor=none
;;
- sh5el)
- basic_machine=sh5le-unknown
+ leon|leon[3-9])
+ cpu=sparc
+ vendor=$basic_machine
;;
- sh64)
- basic_machine=sh64-unknown
+ leon-*|leon[3-9]-*)
+ cpu=sparc
+ vendor=`echo "$basic_machine" | sed 's/-.*//'`
;;
- sparclite-wrs | simso-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
+
+ *-*)
+ # shellcheck disable=SC2162
+ IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ cpu=$basic_machine
+ vendor=pc
;;
- spur)
- basic_machine=spur-unknown
+ # These rules are duplicated from below for sake of the special case above;
+ # i.e. things that normalized to x86 arches should also default to "pc"
+ pc98)
+ cpu=i386
+ vendor=pc
;;
- st2000)
- basic_machine=m68k-tandem
+ x64 | amd64)
+ cpu=x86_64
+ vendor=pc
;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
+ # Recognize the basic CPU types without company name.
+ *)
+ cpu=$basic_machine
+ vendor=unknown
;;
- strongarm-* | thumb-*)
- basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+ # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+ # some cases the only manufacturer, in others, it is the most popular.
+ craynv-unknown)
+ vendor=cray
+ os=${os:-unicosmp}
;;
- sun2)
- basic_machine=m68000-sun
+ c90-unknown | c90-cray)
+ vendor=cray
+ os=${os:-unicos}
;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
+ fx80-unknown)
+ vendor=alliant
;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
+ romp-unknown)
+ vendor=ibm
;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
+ mmix-unknown)
+ vendor=knuth
;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
+ microblaze-unknown | microblazeel-unknown)
+ vendor=xilinx
;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
+ rs6000-unknown)
+ vendor=ibm
;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
+ vax-unknown)
+ vendor=dec
;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
+ pdp11-unknown)
+ vendor=dec
;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
+ we32k-unknown)
+ vendor=att
;;
- sun4)
- basic_machine=sparc-sun
+ cydra-unknown)
+ vendor=cydrome
;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
+ i370-ibm*)
+ vendor=ibm
;;
- sv1)
- basic_machine=sv1-cray
- os=-unicos
+ orion-unknown)
+ vendor=highlevel
;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
+ xps-unknown | xps100-unknown)
+ cpu=xps100
+ vendor=honeywell
;;
- t3e)
- basic_machine=alphaev5-cray
- os=-unicos
+
+ # Here we normalize CPU types with a missing or matching vendor
+ dpx20-unknown | dpx20-bull)
+ cpu=rs6000
+ vendor=bull
+ os=${os:-bosx}
;;
- t90)
- basic_machine=t90-cray
- os=-unicos
+
+ # Here we normalize CPU types irrespective of the vendor
+ amd64-*)
+ cpu=x86_64
;;
- tile*)
- basic_machine=$basic_machine-unknown
- os=-linux-gnu
+ blackfin-*)
+ cpu=bfin
+ os=linux
;;
- tx39)
- basic_machine=mipstx39-unknown
+ c54x-*)
+ cpu=tic54x
;;
- tx39el)
- basic_machine=mipstx39el-unknown
+ c55x-*)
+ cpu=tic55x
;;
- toad1)
- basic_machine=pdp10-xkl
- os=-tops20
+ c6x-*)
+ cpu=tic6x
;;
- tower | tower-32)
- basic_machine=m68k-ncr
+ e500v[12]-*)
+ cpu=powerpc
+ os=$os"spe"
;;
- tpf)
- basic_machine=s390x-ibm
- os=-tpf
+ mips3*-*)
+ cpu=mips64
;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
+ ms1-*)
+ cpu=mt
;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
+ m68knommu-*)
+ cpu=m68k
+ os=linux
;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
+ m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+ cpu=s12z
;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
+ openrisc-*)
+ cpu=or32
;;
- vms)
- basic_machine=vax-dec
- os=-vms
+ parisc-*)
+ cpu=hppa
+ os=linux
;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ cpu=i586
;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
+ pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+ cpu=i686
;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ cpu=i686
;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
+ pentium4-*)
+ cpu=i786
;;
- w65*)
- basic_machine=w65-wdc
- os=-none
+ pc98-*)
+ cpu=i386
;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
+ ppc-* | ppcbe-*)
+ cpu=powerpc
;;
- xbox)
- basic_machine=i686-pc
- os=-mingw32
+ ppcle-* | powerpclittle-*)
+ cpu=powerpcle
;;
- xps | xps100)
- basic_machine=xps100-honeywell
+ ppc64-*)
+ cpu=powerpc64
;;
- xscale-* | xscalee[bl]-*)
- basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ppc64le-* | powerpc64little-*)
+ cpu=powerpc64le
;;
- ymp)
- basic_machine=ymp-cray
- os=-unicos
+ sb1-*)
+ cpu=mipsisa64sb1
;;
- z8k-*-coff)
- basic_machine=z8k-unknown
- os=-sim
+ sb1el-*)
+ cpu=mipsisa64sb1el
;;
- z80-*-coff)
- basic_machine=z80-unknown
- os=-sim
+ sh5e[lb]-*)
+ cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
;;
- none)
- basic_machine=none-none
- os=-none
+ spur-*)
+ cpu=spur
;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
+ strongarm-* | thumb-*)
+ cpu=arm
;;
- op50n)
- basic_machine=hppa1.1-oki
+ tx39-*)
+ cpu=mipstx39
;;
- op60c)
- basic_machine=hppa1.1-oki
+ tx39el-*)
+ cpu=mipstx39el
;;
- romp)
- basic_machine=romp-ibm
+ x64-*)
+ cpu=x86_64
;;
- mmix)
- basic_machine=mmix-knuth
+ xscale-* | xscalee[bl]-*)
+ cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
- rs6000)
- basic_machine=rs6000-ibm
+
+ # Recognize the canonical CPU Types that limit and/or modify the
+ # company names they are paired with.
+ cr16-*)
+ os=${os:-elf}
;;
- vax)
- basic_machine=vax-dec
+ crisv32-* | etraxfs*-*)
+ cpu=crisv32
+ vendor=axis
;;
- pdp10)
- # there are many clones, so DEC is not a safe bet
- basic_machine=pdp10-unknown
+ cris-* | etrax*-*)
+ cpu=cris
+ vendor=axis
;;
- pdp11)
- basic_machine=pdp11-dec
+ crx-*)
+ os=${os:-elf}
;;
- we32k)
- basic_machine=we32k-att
+ neo-tandem)
+ cpu=neo
+ vendor=tandem
;;
- sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
- basic_machine=sh-unknown
+ nse-tandem)
+ cpu=nse
+ vendor=tandem
;;
- sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
- basic_machine=sparc-sun
+ nsr-tandem)
+ cpu=nsr
+ vendor=tandem
;;
- cydra)
- basic_machine=cydra-cydrome
+ nsv-tandem)
+ cpu=nsv
+ vendor=tandem
;;
- orion)
- basic_machine=orion-highlevel
+ nsx-tandem)
+ cpu=nsx
+ vendor=tandem
;;
- orion105)
- basic_machine=clipper-highlevel
+ s390-*)
+ cpu=s390
+ vendor=ibm
;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
+ s390x-*)
+ cpu=s390x
+ vendor=ibm
;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
+ tile*-*)
+ os=${os:-linux-gnu}
;;
+
*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
+ # Recognize the canonical CPU types that are allowed with any
+ # company name.
+ case $cpu in
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | abacus \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+ | alphapca5[67] | alpha64pca5[67] \
+ | am33_2.0 \
+ | amdgcn \
+ | arc | arceb \
+ | arm | arm[lb]e | arme[lb] | armv* \
+ | avr | avr32 \
+ | asmjs \
+ | ba \
+ | be32 | be64 \
+ | bfin | bpf | bs2000 \
+ | c[123]* | c30 | [cjt]90 | c4x \
+ | c8051 | clipper | craynv | csky | cydra \
+ | d10v | d30v | dlx | dsp16xx | dvp \
+ | e2k | elxsi | epiphany \
+ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+ | h8300 | h8500 \
+ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i*86 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle \
+ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+ | m88110 | m88k | maxq | mb | mcore | mep | metag \
+ | microblaze | microblazeel \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64eb | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mmix \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nfp \
+ | nios | nios2 | nios2eb | nios2el \
+ | none | np1 | ns16k | ns32k | nvptx \
+ | open8 \
+ | or1k* \
+ | or32 \
+ | orion \
+ | picochip \
+ | pdp10 | pdp11 | pj | pjl | pn | power \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pru \
+ | pyramid \
+ | riscv | riscv32 | riscv64 \
+ | rl78 | romp | rs6000 | rx \
+ | score \
+ | sh | shl \
+ | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+ | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+ | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | spu \
+ | tahoe \
+ | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tron \
+ | ubicom32 \
+ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | vax \
+ | visium \
+ | w65 \
+ | wasm32 | wasm64 \
+ | we32k \
+ | x86 | x86_64 | xc16x | xgate | xps100 \
+ | xstormy16 | xtensa* \
+ | ymp \
+ | z8k | z80)
+ ;;
+
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+ exit 1
+ ;;
+ esac
;;
esac
# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+case $vendor in
+ digital*)
+ vendor=dec
;;
- *-commodore*)
- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ commodore*)
+ vendor=cbm
;;
*)
;;
@@ -1332,197 +1296,244 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
-if [ x"$os" != x"" ]
+if [ x$os != x ]
then
case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -auroraux)
- os=-auroraux
+ # First match some system type aliases that might get confused
+ # with valid system types.
+ # solaris* is a basic system type, with this one exception.
+ auroraux)
+ os=auroraux
;;
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ bluegene*)
+ os=cnk
;;
- -solaris)
- os=-solaris2
+ solaris1 | solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
;;
- -svr4*)
- os=-sysv4
+ solaris)
+ os=solaris2
;;
- -unixware*)
- os=-sysv4.2uw
+ unixware*)
+ os=sysv4.2uw
;;
- -gnu/linux*)
+ gnu/linux*)
os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
;;
- # First accept the basic system types.
+ # es1800 is here to avoid being matched by es* (a different OS)
+ es1800*)
+ os=ose
+ ;;
+ # Some version numbers need modification
+ chorusos*)
+ os=chorusos
+ ;;
+ isc)
+ os=isc2.2
+ ;;
+ sco6)
+ os=sco5v6
+ ;;
+ sco5)
+ os=sco3.2v5
+ ;;
+ sco4)
+ os=sco3.2v4
+ ;;
+ sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ ;;
+ sco3.2v[4-9]* | sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ ;;
+ scout)
+ # Don't match below
+ ;;
+ sco*)
+ os=sco3.2v2
+ ;;
+ psos*)
+ os=psos
+ ;;
+ # Now accept the basic system types.
# The portable systems comes first.
- # Each alternative MUST END IN A *, to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
- | -sym* | -kopensolaris* | -plan9* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -bitrig* | -openbsd* | -solidbsd* \
- | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
- | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* | -cegcc* \
- | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
- | -linux-newlib* | -linux-musl* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
- | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
- | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ # Each alternative MUST end in a * to match a version number.
+ # sysv* is not here because it comes later, after sysvr4.
+ gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+ | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
+ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+ | sym* | kopensolaris* | plan9* \
+ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+ | aos* | aros* | cloudabi* | sortix* | twizzler* \
+ | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+ | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+ | knetbsd* | mirbsd* | netbsd* \
+ | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
+ | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \
+ | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+ | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+ | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \
+ | chorusrdb* | cegcc* | glidix* \
+ | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+ | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \
+ | linux-newlib* | linux-musl* | linux-uclibc* \
+ | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+ | interix* | uwin* | mks* | rhapsody* | darwin* \
+ | openstep* | oskit* | conix* | pw32* | nonstopux* \
+ | storm-chaos* | tops10* | tenex* | tops20* | its* | irx* \
+ | os2* | vos* | palmos* | uclinux* | nucleus* \
+ | morphos* | superux* | rtmk* | windiss* \
+ | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+ | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+ | nsk* | powerunix)
# Remember, each alternative MUST END IN *, to match a version number.
;;
- -qnx*)
- case $basic_machine in
- x86-* | i*86-*)
+ qnx*)
+ case $cpu in
+ x86 | i*86)
;;
*)
- os=-nto$os
+ os=nto-$os
;;
esac
;;
- -nto-qnx*)
+ hiux*)
+ os=hiuxwe2
;;
- -nto*)
- os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ nto-qnx*)
;;
- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
- -mac*)
- os=`echo $os | sed -e 's|mac|macos|'`
+ sim | xray | os68k* | v88r* \
+ | windows* | osx | abug | netware* | os9* \
+ | macos* | mpw* | magic* | mmixware* | mon960* | lnews*)
;;
- -linux-dietlibc)
- os=-linux-dietlibc
+ linux-dietlibc)
+ os=linux-dietlibc
;;
- -linux*)
+ linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
- -sunos5*)
- os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ lynx*178)
+ os=lynxos178
+ ;;
+ lynx*5)
+ os=lynxos5
;;
- -sunos6*)
- os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ lynx*)
+ os=lynxos
;;
- -opened*)
- os=-openedition
+ mac*)
+ os=`echo "$os" | sed -e 's|mac|macos|'`
;;
- -os400*)
- os=-os400
+ opened*)
+ os=openedition
;;
- -wince*)
- os=-wince
+ os400*)
+ os=os400
;;
- -osfrose*)
- os=-osfrose
+ sunos5*)
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
;;
- -osf*)
- os=-osf
+ sunos6*)
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
;;
- -utek*)
- os=-bsd
+ wince*)
+ os=wince
;;
- -dynix*)
- os=-bsd
+ utek*)
+ os=bsd
;;
- -acis*)
- os=-aos
+ dynix*)
+ os=bsd
;;
- -atheos*)
- os=-atheos
+ acis*)
+ os=aos
;;
- -syllable*)
- os=-syllable
+ atheos*)
+ os=atheos
;;
- -386bsd)
- os=-bsd
+ syllable*)
+ os=syllable
;;
- -ctix* | -uts*)
- os=-sysv
+ 386bsd)
+ os=bsd
;;
- -nova*)
- os=-rtmk-nova
+ ctix* | uts*)
+ os=sysv
;;
- -ns2 )
- os=-nextstep2
+ nova*)
+ os=rtmk-nova
;;
- -nsk*)
- os=-nsk
+ ns2)
+ os=nextstep2
;;
# Preserve the version number of sinix5.
- -sinix5.*)
+ sinix5.*)
os=`echo $os | sed -e 's|sinix|sysv|'`
;;
- -sinix*)
- os=-sysv4
+ sinix*)
+ os=sysv4
;;
- -tpf*)
- os=-tpf
+ tpf*)
+ os=tpf
;;
- -triton*)
- os=-sysv3
+ triton*)
+ os=sysv3
;;
- -oss*)
- os=-sysv3
+ oss*)
+ os=sysv3
;;
- -svr4)
- os=-sysv4
+ svr4*)
+ os=sysv4
;;
- -svr3)
- os=-sysv3
+ svr3)
+ os=sysv3
;;
- -sysvr4)
- os=-sysv4
+ sysvr4)
+ os=sysv4
;;
- # This must come after -sysvr4.
- -sysv*)
+ # This must come after sysvr4.
+ sysv*)
;;
- -ose*)
- os=-ose
+ ose*)
+ os=ose
;;
- -es1800*)
- os=-ose
+ *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+ os=mint
;;
- -xenix)
- os=-xenix
+ zvmoe)
+ os=zvmoe
;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- os=-mint
+ dicos*)
+ os=dicos
;;
- -aros*)
- os=-aros
+ pikeos*)
+ # Until real need of OS specific support for
+ # particular features comes up, bare metal
+ # configurations are quite functional.
+ case $cpu in
+ arm*)
+ os=eabi
+ ;;
+ *)
+ os=elf
+ ;;
+ esac
;;
- -zvmoe)
- os=-zvmoe
+ nacl*)
;;
- -dicos*)
- os=-dicos
+ ios)
;;
- -nacl*)
+ none)
;;
- -none)
+ *-eabi)
;;
*)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
exit 1
;;
esac
@@ -1538,261 +1549,265 @@ else
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.
-case $basic_machine in
+case $cpu-$vendor in
score-*)
- os=-elf
+ os=elf
;;
spu-*)
- os=-elf
+ os=elf
;;
*-acorn)
- os=-riscix1.2
+ os=riscix1.2
;;
arm*-rebel)
- os=-linux
+ os=linux
;;
arm*-semi)
- os=-aout
+ os=aout
;;
c4x-* | tic4x-*)
- os=-coff
+ os=coff
;;
c8051-*)
- os=-elf
+ os=elf
+ ;;
+ clipper-intergraph)
+ os=clix
;;
hexagon-*)
- os=-elf
+ os=elf
;;
tic54x-*)
- os=-coff
+ os=coff
;;
tic55x-*)
- os=-coff
+ os=coff
;;
tic6x-*)
- os=-coff
+ os=coff
;;
# This must come before the *-dec entry.
pdp10-*)
- os=-tops20
+ os=tops20
;;
pdp11-*)
- os=-none
+ os=none
;;
*-dec | vax-*)
- os=-ultrix4.2
+ os=ultrix4.2
;;
m68*-apollo)
- os=-domain
+ os=domain
;;
i386-sun)
- os=-sunos4.0.2
+ os=sunos4.0.2
;;
m68000-sun)
- os=-sunos3
+ os=sunos3
;;
m68*-cisco)
- os=-aout
+ os=aout
;;
mep-*)
- os=-elf
+ os=elf
;;
mips*-cisco)
- os=-elf
+ os=elf
;;
mips*-*)
- os=-elf
+ os=elf
;;
or32-*)
- os=-coff
+ os=coff
;;
*-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
+ os=sysv3
;;
sparc-* | *-sun)
- os=-sunos4.1.1
+ os=sunos4.1.1
;;
- *-be)
- os=-beos
+ pru-*)
+ os=elf
;;
- *-haiku)
- os=-haiku
+ *-be)
+ os=beos
;;
*-ibm)
- os=-aix
+ os=aix
;;
*-knuth)
- os=-mmixware
+ os=mmixware
;;
*-wec)
- os=-proelf
+ os=proelf
;;
*-winbond)
- os=-proelf
+ os=proelf
;;
*-oki)
- os=-proelf
+ os=proelf
;;
*-hp)
- os=-hpux
+ os=hpux
;;
*-hitachi)
- os=-hiux
+ os=hiux
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
+ os=sysv
;;
*-cbm)
- os=-amigaos
+ os=amigaos
;;
*-dg)
- os=-dgux
+ os=dgux
;;
*-dolphin)
- os=-sysv3
+ os=sysv3
;;
m68k-ccur)
- os=-rtu
+ os=rtu
;;
m88k-omron*)
- os=-luna
+ os=luna
;;
- *-next )
- os=-nextstep
+ *-next)
+ os=nextstep
;;
*-sequent)
- os=-ptx
+ os=ptx
;;
*-crds)
- os=-unos
+ os=unos
;;
*-ns)
- os=-genix
+ os=genix
;;
i370-*)
- os=-mvs
- ;;
- *-next)
- os=-nextstep3
+ os=mvs
;;
*-gould)
- os=-sysv
+ os=sysv
;;
*-highlevel)
- os=-bsd
+ os=bsd
;;
*-encore)
- os=-bsd
+ os=bsd
;;
*-sgi)
- os=-irix
+ os=irix
;;
*-siemens)
- os=-sysv4
+ os=sysv4
;;
*-masscomp)
- os=-rtu
+ os=rtu
;;
f30[01]-fujitsu | f700-fujitsu)
- os=-uxpv
+ os=uxpv
;;
*-rom68k)
- os=-coff
+ os=coff
;;
*-*bug)
- os=-coff
+ os=coff
;;
*-apple)
- os=-macos
+ os=macos
;;
*-atari*)
- os=-mint
+ os=mint
+ ;;
+ *-wrs)
+ os=vxworks
;;
*)
- os=-none
+ os=none
;;
esac
fi
# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
+case $vendor in
+ unknown)
case $os in
- -riscix*)
+ riscix*)
vendor=acorn
;;
- -sunos*)
+ sunos*)
vendor=sun
;;
- -cnk*|-aix*)
+ cnk*|-aix*)
vendor=ibm
;;
- -beos*)
+ beos*)
vendor=be
;;
- -hpux*)
+ hpux*)
vendor=hp
;;
- -mpeix*)
+ mpeix*)
vendor=hp
;;
- -hiux*)
+ hiux*)
vendor=hitachi
;;
- -unos*)
+ unos*)
vendor=crds
;;
- -dgux*)
+ dgux*)
vendor=dg
;;
- -luna*)
+ luna*)
vendor=omron
;;
- -genix*)
+ genix*)
vendor=ns
;;
- -mvs* | -opened*)
+ clix*)
+ vendor=intergraph
+ ;;
+ mvs* | opened*)
vendor=ibm
;;
- -os400*)
+ os400*)
vendor=ibm
;;
- -ptx*)
+ ptx*)
vendor=sequent
;;
- -tpf*)
+ tpf*)
vendor=ibm
;;
- -vxsim* | -vxworks* | -windiss*)
+ vxsim* | vxworks* | windiss*)
vendor=wrs
;;
- -aux*)
+ aux*)
vendor=apple
;;
- -hms*)
+ hms*)
vendor=hitachi
;;
- -mpw* | -macos*)
+ mpw* | macos*)
vendor=apple
;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
vendor=atari
;;
- -vos*)
+ vos*)
vendor=stratus
;;
esac
- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;;
esac
-echo $basic_machine$os
+echo "$cpu-$vendor-$os"
exit
# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
+# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
diff --git a/3rdparty/expat/conftools/depcomp b/3rdparty/expat/conftools/depcomp
new file mode 100755
index 00000000000..6b391623c4b
--- /dev/null
+++ b/3rdparty/expat/conftools/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/3rdparty/expat/conftools/expatcfg-compiler-supports-visibility.m4 b/3rdparty/expat/conftools/expatcfg-compiler-supports-visibility.m4
new file mode 100644
index 00000000000..45d07edfd2c
--- /dev/null
+++ b/3rdparty/expat/conftools/expatcfg-compiler-supports-visibility.m4
@@ -0,0 +1,39 @@
+# expatcfg-compiler-supports-visibility.m4 --
+#
+# SYNOPSIS
+#
+# EXPATCFG_COMPILER_SUPPORTS_VISIBILITY([ACTION-IF-YES],
+# [ACTION-IF-NO])
+#
+# DESCRIPTION
+#
+# Check if the selected compiler supports the "visibility" attribute
+# and set the variable "expatcfg_cv_compiler_supports_visibility"
+# accordingly to "yes" or "no".
+#
+# In addition, execute ACTION-IF-YES or ACTION-IF-NO.
+#
+# LICENSE
+#
+# Copyright (c) 2018 The Expat Authors.
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This file is offered as-is,
+# without any warranty.
+
+AC_DEFUN([EXPATCFG_COMPILER_SUPPORTS_VISIBILITY],
+ [AC_CACHE_CHECK([whether compiler supports visibility],
+ [expatcfg_cv_compiler_supports_visibility],
+ [AS_VAR_SET([expatcfg_cv_compiler_supports_visibility],[no])
+ AS_VAR_COPY([OLDFLAGS],[CFLAGS])
+ AS_VAR_APPEND([CFLAGS],[" -fvisibility=hidden -Wall -Werror -Wno-unknown-warning-option"])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ void __attribute__((visibility("default"))) foo(void);
+ void foo(void) {}
+ ]])],
+ [AS_VAR_SET([expatcfg_cv_compiler_supports_visibility],[yes])])
+ AS_VAR_COPY([CFLAGS],[OLDFLAGS])])
+ AS_IF([test "$expatcfg_cv_compiler_supports_visibility" = yes],[$1],[$2])])
+
+# end of file
diff --git a/3rdparty/expat/conftools/get-version.sh b/3rdparty/expat/conftools/get-version.sh
index a70e0fb47a8..2592f103288 100755
--- a/3rdparty/expat/conftools/get-version.sh
+++ b/3rdparty/expat/conftools/get-version.sh
@@ -28,19 +28,8 @@ if test ! -r "$hdr"; then
exit 1
fi
-MAJOR_VERSION="`sed -n -e '/MAJOR_VERSION/s/[^0-9]*//gp' $hdr`"
-MINOR_VERSION="`sed -n -e '/MINOR_VERSION/s/[^0-9]*//gp' $hdr`"
-MICRO_VERSION="`sed -n -e '/MICRO_VERSION/s/[^0-9]*//gp' $hdr`"
+MAJOR_VERSION=$(sed -n -e '/MAJOR_VERSION/s/[^0-9]*//gp' "$hdr")
+MINOR_VERSION=$(sed -n -e '/MINOR_VERSION/s/[^0-9]*//gp' "$hdr")
+MICRO_VERSION=$(sed -n -e '/MICRO_VERSION/s/[^0-9]*//gp' "$hdr")
-# Determine how to tell echo not to print the trailing \n. This is
-# similar to Autoconf's @ECHO_C@ and @ECHO_N@; however, we don't
-# generate this file via autoconf (in fact, get-version.sh is used
-# to *create* ./configure), so we just do something similar inline.
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
- *c*,-n*) ECHO_N= ECHO_C='
-' ;;
- *c*,* ) ECHO_N=-n ECHO_C= ;;
- *) ECHO_N= ECHO_C='\c' ;;
-esac
-
-echo $ECHO_N "$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION$ECHO_C"
+printf '%s.%s.%s' "$MAJOR_VERSION" "$MINOR_VERSION" "$MICRO_VERSION"
diff --git a/3rdparty/expat/conftools/install-sh b/3rdparty/expat/conftools/install-sh
index 377bb8687ff..20d8b2eaea9 100755
--- a/3rdparty/expat/conftools/install-sh
+++ b/3rdparty/expat/conftools/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2011-11-20.07; # UTC
+scriptversion=2018-03-11.20; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC
# This script is compatible with the BSD install script, but was written
# from scratch.
+tab=' '
nl='
'
-IFS=" "" $nl"
+IFS=" $tab$nl"
-# set DOITPROG to echo to test this script
+# Set DOITPROG to "echo" to test this script.
-# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
-if test -z "$doit"; then
- doit_exec=exec
-else
- doit_exec=$doit
-fi
+doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@@ -68,17 +64,6 @@ mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
-posix_glob='?'
-initialize_posix_glob='
- test "$posix_glob" != "?" || {
- if (set -f) 2>/dev/null; then
- posix_glob=
- else
- posix_glob=:
- fi
- }
-'
-
posix_mkdir=
# Desired mode of installed file.
@@ -97,7 +82,7 @@ dir_arg=
dst_arg=
copy_on_change=false
-no_target_directory=
+is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@@ -137,46 +122,57 @@ while test $# -ne 0; do
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
- shift;;
+ shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
- case $mode in
- *' '* | *' '* | *'
-'* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
-o) chowncmd="$chownprog $2"
- shift;;
+ shift;;
-s) stripcmd=$stripprog;;
- -t) dst_arg=$2
- # Protect names problematic for 'test' and other utilities.
- case $dst_arg in
- -* | [=\(\)!]) dst_arg=./$dst_arg;;
- esac
- shift;;
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
- -T) no_target_directory=true;;
+ -T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
- --) shift
- break;;
+ --) shift
+ break;;
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
*) break;;
esac
shift
done
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
@@ -208,6 +204,15 @@ if test $# -eq 0; then
fi
if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
@@ -223,16 +228,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
- u_plus_rw=
+ u_plus_rw=
else
- u_plus_rw='% 200'
+ u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
- u_plus_rw=
+ u_plus_rw=
else
- u_plus_rw=,u+rw
+ u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@@ -266,122 +271,113 @@ do
fi
dst=$dst_arg
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
+ # If destination is a directory, append the input filename.
if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
fi
dstdir=$dst
- dst=$dstdir/`basename "$src"`
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
dstdir_status=0
else
- # Prefer dirname, but fall back on a substitute if dirname fails.
- dstdir=`
- (dirname "$dst") 2>/dev/null ||
- expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$dst" : 'X\(//\)[^/]' \| \
- X"$dst" : 'X\(//\)$' \| \
- X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
- echo X"$dst" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'
- `
-
+ dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
+ case $dstdir in
+ */) dstdirslash=$dstdir;;
+ *) dstdirslash=$dstdir/;;
+ esac
+
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
- # Create intermediate dirs using mode 755 as modified by the umask.
- # This is like FreeBSD 'install' as of 1997-10-28.
- umask=`umask`
- case $stripcmd.$umask in
- # Optimize common cases.
- *[2367][2367]) mkdir_umask=$umask;;
- .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
- *[0-7])
- mkdir_umask=`expr $umask + 22 \
- - $umask % 100 % 40 + $umask % 20 \
- - $umask % 10 % 4 + $umask % 2
- `;;
- *) mkdir_umask=$umask,go-w;;
- esac
-
- # With -d, create the new directory with the user-specified mode.
- # Otherwise, rely on $mkdir_umask.
- if test -n "$dir_arg"; then
- mkdir_mode=-m$mode
- else
- mkdir_mode=
- fi
-
- posix_mkdir=false
- case $umask in
- *[123567][0-7][0-7])
- # POSIX mkdir -p sets u+wx bits regardless of umask, which
- # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
- ;;
- *)
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
- trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
- if (umask $mkdir_umask &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
- then
- if test -z "$dir_arg" || {
- # Check for POSIX incompatibilities with -m.
- # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
- # other-writable bit of parent directory when it shouldn't.
- # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
- ls_ld_tmpdir=`ls -ld "$tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/d" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
- fi
- trap '' 0;;
- esac;;
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ # Note that $RANDOM variable is not portable (e.g. dash); Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p' feature.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
esac
if
$posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
@@ -391,53 +387,51 @@ do
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
- /*) prefix='/';;
- [-=\(\)!]*) prefix='./';;
- *) prefix='';;
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
esac
- eval "$initialize_posix_glob"
-
oIFS=$IFS
IFS=/
- $posix_glob set -f
+ set -f
set fnord $dstdir
shift
- $posix_glob set +f
+ set +f
IFS=$oIFS
prefixes=
for d
do
- test X"$d" = X && continue
-
- prefix=$prefix$d
- if test -d "$prefix"; then
- prefixes=
- else
- if $posix_mkdir; then
- (umask=$mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
- # Don't fail if two instances are running concurrently.
- test -d "$prefix" || exit 1
- else
- case $prefix in
- *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
- *) qprefix=$prefix;;
- esac
- prefixes="$prefixes '$qprefix'"
- fi
- fi
- prefix=$prefix/
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
done
if test -n "$prefixes"; then
- # Don't fail if two instances are running concurrently.
- (umask $mkdir_umask &&
- eval "\$doit_exec \$mkdirprog $prefixes") ||
- test -d "$dstdir" || exit 1
- obsolete_mkdir_used=true
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
fi
fi
fi
@@ -450,14 +444,25 @@ do
else
# Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_rm.$$_
+ dsttmp=${dstdirslash}_inst.$$_
+ rmtmp=${dstdirslash}_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
- (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+ (umask $cp_umask &&
+ { test -z "$stripcmd" || {
+ # Create $dsttmp read-write so that cp doesn't create it read-only,
+ # which would cause strip to fail.
+ if test -z "$doit"; then
+ : >"$dsttmp" # No need to fork-exec 'touch'.
+ else
+ $doit touch "$dsttmp"
+ fi
+ }
+ } &&
+ $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
@@ -472,15 +477,12 @@ do
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
- old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
- new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
-
- eval "$initialize_posix_glob" &&
- $posix_glob set -f &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
- $posix_glob set +f &&
-
+ set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
@@ -493,24 +495,24 @@ do
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
- # Now remove or move aside any old file at destination location.
- # We try this two ways since rm can't unlink itself on some
- # systems and the destination file might be busy for other
- # reasons. In this case, the final cleanup might fail but the new
- # file should still install successfully.
- {
- test ! -f "$dst" ||
- $doit $rmcmd -f "$dst" 2>/dev/null ||
- { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
- { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
- } ||
- { echo "$0: cannot unlink or rename $dst" >&2
- (exit 1); exit 1
- }
- } &&
-
- # Now rename the file to the real destination.
- $doit $mvcmd "$dsttmp" "$dst"
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
@@ -519,9 +521,9 @@ do
done
# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
+# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/3rdparty/expat/conftools/ltmain.sh b/3rdparty/expat/conftools/ltmain.sh
index bffda54187a..e774ddfe649 100644
--- a/3rdparty/expat/conftools/ltmain.sh
+++ b/3rdparty/expat/conftools/ltmain.sh
@@ -1,9 +1,12 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+## by inline-source v2014-01-03.01
-# libtool (GNU libtool) 2.4.2
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
-# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
@@ -23,881 +26,2159 @@
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING. If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html,
-# or obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# Usage: $progname [OPTION]... [MODE-ARG]...
-#
-# Provide generalized library-building support services.
-#
-# --config show all configuration variables
-# --debug enable verbose shell tracing
-# -n, --dry-run display commands without modifying any files
-# --features display basic configuration information and exit
-# --mode=MODE use operation mode MODE
-# --preserve-dup-deps don't remove duplicate dependency libraries
-# --quiet, --silent don't print informational messages
-# --no-quiet, --no-silent
-# print informational messages (default)
-# --no-warn don't display warning messages
-# --tag=TAG use configuration variables from tag TAG
-# -v, --verbose print more informational messages than default
-# --no-verbose don't print the extra informational messages
-# --version print version information
-# -h, --help, --help-all print short, long, or detailed help message
-#
-# MODE must be one of the following:
-#
-# clean remove files from the build directory
-# compile compile a source file into a libtool object
-# execute automatically set library path, then run a program
-# finish complete the installation of libtool libraries
-# install install libraries or executables
-# link create a library or an executable
-# uninstall remove libraries from an installed directory
-#
-# MODE-ARGS vary depending on the MODE. When passed as first option,
-# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
-# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
-#
-# When reporting a bug, please describe a test case to reproduce it and
-# include the following information:
-#
-# host-triplet: $host
-# shell: $SHELL
-# compiler: $LTCC
-# compiler flags: $LTCFLAGS
-# linker: $LD (gnu? $with_gnu_ld)
-# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.11
-# automake: $automake_version
-# autoconf: $autoconf_version
-#
-# Report bugs to <bug-libtool@gnu.org>.
-# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
-# General help using GNU software: <http://www.gnu.org/gethelp/>.
PROGRAM=libtool
PACKAGE=libtool
-VERSION="2.4.2 Debian-2.4.2-1.11"
-TIMESTAMP=""
-package_revision=1.3337
+VERSION=2.4.6
+package_revision=2.4.6
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-10-04.22; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
emulate sh
NULLCMD=:
- # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # 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
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-}
-# NLS nuisances: We save the old values to restore during execute mode.
-lt_user_locale=
-lt_safe_locale=
-for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
do
- eval "if test \"\${$lt_var+set}\" = set; then
- save_$lt_var=\$$lt_var
- $lt_var=C
- export $lt_var
- lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
- lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+ eval "if test set = \"\${$_G_var+set}\"; then
+ save_$_G_var=\$$_G_var
+ $_G_var=C
+ export $_G_var
+ _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+ _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
fi"
done
-LC_ALL=C
-LANGUAGE=C
-export LANGUAGE LC_ALL
-$lt_unset CDPATH
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp $nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
-# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
-# is ksh but when the shell is invoked as "sh" and the current value of
-# the _XPG environment variable is not equal to 1 (one), the special
-# positional parameter $0, within a function call, is the name of the
-# function.
-progpath="$0"
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+ _G_progs_list=$1
+ _G_check_func=$2
+ _G_PATH=${3-"$PATH"}
+
+ _G_path_prog_max=0
+ _G_path_prog_found=false
+ _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+ for _G_dir in $_G_PATH; do
+ IFS=$_G_save_IFS
+ test -z "$_G_dir" && _G_dir=.
+ for _G_prog_name in $_G_progs_list; do
+ for _exeext in '' .EXE; do
+ _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+ func_executable_p "$_G_path_prog" || continue
+ case `"$_G_path_prog" --version 2>&1` in
+ *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+ *) $_G_check_func $_G_path_prog
+ func_path_progs_result=$func_check_prog_result
+ ;;
+ esac
+ $_G_path_prog_found && break 3
+ done
+ done
+ done
+ IFS=$_G_save_IFS
+ test -z "$func_path_progs_result" && {
+ echo "no acceptable sed could be found in \$PATH" >&2
+ exit 1
+ }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+ _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for _G_i in 1 2 3 4 5 6 7; do
+ _G_sed_script=$_G_sed_script$nl$_G_sed_script
+ done
+ echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+ _G_sed_script=
+
+ func_check_prog_sed ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo '' >> conftest.nl
+ "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+ rm -f conftest.sed
+ SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+ func_check_prog_grep ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ _G_path_prog_max=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo 'GREP' >> conftest.nl
+ "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+ GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables. These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
: ${CP="cp -f"}
-test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
: ${MAKE="make"}
: ${MKDIR="mkdir"}
: ${MV="mv -f"}
: ${RM="rm -f"}
: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
-: ${Xsed="$SED -e 1s/^X//"}
-# Global variables:
-EXIT_SUCCESS=0
-EXIT_FAILURE=1
-EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
-EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
-exit_status=$EXIT_SUCCESS
-
-# Make sure IFS has a sensible default
-lt_nl='
-'
-IFS=" $lt_nl"
-
-dirname="s,/[^/]*$,,"
-basename="s,^.*/,,"
-
-# func_dirname file append nondir_replacement
-# Compute the dirname of FILE. If nonempty, add APPEND to the result,
-# otherwise set result to NONDIR_REPLACEMENT.
-func_dirname ()
-{
- func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
- if test "X$func_dirname_result" = "X${1}"; then
- func_dirname_result="${3}"
- else
- func_dirname_result="$func_dirname_result${2}"
- fi
-} # func_dirname may be replaced by extended shell implementation
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
-# func_basename file
-func_basename ()
-{
- func_basename_result=`$ECHO "${1}" | $SED "$basename"`
-} # func_basename may be replaced by extended shell implementation
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
-# func_dirname_and_basename file append nondir_replacement
-# perform func_basename and func_dirname in a single function
-# call:
-# dirname: Compute the dirname of FILE. If nonempty,
-# add APPEND to the result, otherwise set result
-# to NONDIR_REPLACEMENT.
-# value returned in "$func_dirname_result"
-# basename: Compute filename of FILE.
-# value retuned in "$func_basename_result"
-# Implementation must be kept synchronized with func_dirname
-# and func_basename. For efficiency, we do not delegate to
-# those functions but instead duplicate the functionality here.
-func_dirname_and_basename ()
-{
- # Extract subdirectory from the argument.
- func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
- if test "X$func_dirname_result" = "X${1}"; then
- func_dirname_result="${3}"
- else
- func_dirname_result="$func_dirname_result${2}"
- fi
- func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
-} # func_dirname_and_basename may be replaced by extended shell implementation
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes. A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same. If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion. Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+ s/$_G_bs4/&\\
+/g
+ s/^$_G_bs2$_G_dollar/$_G_bs&/
+ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+ s/\n//g"
-# func_stripname prefix suffix name
-# strip PREFIX and SUFFIX off of NAME.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-# func_strip_suffix prefix name
-func_stripname ()
-{
- case ${2} in
- .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
- *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
- esac
-} # func_stripname may be replaced by extended shell implementation
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
-# These SED scripts presuppose an absolute path with a trailing slash.
-pathcar='s,^/\([^/]*\).*$,\1,'
-pathcdr='s,^/[^/]*,,'
-removedotparts=':dotsl
- s@/\./@/@g
- t dotsl
- s,/\.$,/,'
-collapseslashes='s@/\{1,\}@/@g'
-finalslash='s,/*$,/,'
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
-# func_normal_abspath PATH
-# Remove doubled-up and trailing slashes, "." path components,
-# and cancel out any ".." path components in PATH after making
-# it an absolute path.
-# value returned in "$func_normal_abspath_result"
-func_normal_abspath ()
-{
- # Start from root dir and reassemble the path.
- func_normal_abspath_result=
- func_normal_abspath_tpath=$1
- func_normal_abspath_altnamespace=
- case $func_normal_abspath_tpath in
- "")
- # Empty path, that just means $cwd.
- func_stripname '' '/' "`pwd`"
- func_normal_abspath_result=$func_stripname_result
- return
- ;;
- # The next three entries are used to spot a run of precisely
- # two leading slashes without using negated character classes;
- # we take advantage of case's first-match behaviour.
- ///*)
- # Unusual form of absolute path, do nothing.
- ;;
- //*)
- # Not necessarily an ordinary path; POSIX reserves leading '//'
- # and for example Cygwin uses it to access remote file shares
- # over CIFS/SMB, so we conserve a leading double slash if found.
- func_normal_abspath_altnamespace=/
- ;;
- /*)
- # Absolute path, do nothing.
- ;;
- *)
- # Relative path, prepend $cwd.
- func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
- ;;
- esac
- # Cancel out all the simple stuff to save iterations. We also want
- # the path to end with a slash for ease of parsing, so make sure
- # there is one (and only one) here.
- func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
- -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
- while :; do
- # Processed it all yet?
- if test "$func_normal_abspath_tpath" = / ; then
- # If we ascended to the root using ".." the result may be empty now.
- if test -z "$func_normal_abspath_result" ; then
- func_normal_abspath_result=/
- fi
- break
- fi
- func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
- -e "$pathcar"`
- func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
- -e "$pathcdr"`
- # Figure out what to do with it
- case $func_normal_abspath_tcomponent in
- "")
- # Trailing empty path component, ignore it.
- ;;
- ..)
- # Parent dir; strip last assembled component from result.
- func_dirname "$func_normal_abspath_result"
- func_normal_abspath_result=$func_dirname_result
- ;;
- *)
- # Actual path component, append it.
- func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
- ;;
- esac
- done
- # Restore leading double-slash if one was found on entry.
- func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
-}
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
-# func_relative_path SRCDIR DSTDIR
-# generates a relative path from SRCDIR to DSTDIR, with a trailing
-# slash if non-empty, suitable for immediately appending a filename
-# without needing to append a separator.
-# value returned in "$func_relative_path_result"
-func_relative_path ()
-{
- func_relative_path_result=
- func_normal_abspath "$1"
- func_relative_path_tlibdir=$func_normal_abspath_result
- func_normal_abspath "$2"
- func_relative_path_tbindir=$func_normal_abspath_result
-
- # Ascend the tree starting from libdir
- while :; do
- # check if we have found a prefix of bindir
- case $func_relative_path_tbindir in
- $func_relative_path_tlibdir)
- # found an exact match
- func_relative_path_tcancelled=
- break
- ;;
- $func_relative_path_tlibdir*)
- # found a matching prefix
- func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
- func_relative_path_tcancelled=$func_stripname_result
- if test -z "$func_relative_path_result"; then
- func_relative_path_result=.
- fi
- break
- ;;
- *)
- func_dirname $func_relative_path_tlibdir
- func_relative_path_tlibdir=${func_dirname_result}
- if test "x$func_relative_path_tlibdir" = x ; then
- # Have to descend all the way to the root!
- func_relative_path_result=../$func_relative_path_result
- func_relative_path_tcancelled=$func_relative_path_tbindir
- break
- fi
- func_relative_path_result=../$func_relative_path_result
- ;;
- esac
- done
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
- # Now calculate path; take care to avoid doubling-up slashes.
- func_stripname '' '/' "$func_relative_path_result"
- func_relative_path_result=$func_stripname_result
- func_stripname '/' '/' "$func_relative_path_tcancelled"
- if test "x$func_stripname_result" != x ; then
- func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
- fi
+# By convention, finish your script with:
+#
+# exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
- # Normalisation. If bindir is libdir, return empty string,
- # else relative path ending with a slash; either way, target
- # file name can be directly appended.
- if test ! -z "$func_relative_path_result"; then
- func_stripname './' '' "$func_relative_path_result/"
- func_relative_path_result=$func_stripname_result
- fi
-}
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
-# The name of this program:
-func_dirname_and_basename "$progpath"
-progname=$func_basename_result
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
-# Make sure we have an absolute path for reexecution:
+# Make sure we have an absolute progpath for reexecution:
case $progpath in
[\\/]*|[A-Za-z]:\\*) ;;
*[\\/]*)
- progdir=$func_dirname_result
+ progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
progdir=`cd "$progdir" && pwd`
- progpath="$progdir/$progname"
+ progpath=$progdir/$progname
;;
*)
- save_IFS="$IFS"
+ _G_IFS=$IFS
IFS=${PATH_SEPARATOR-:}
for progdir in $PATH; do
- IFS="$save_IFS"
+ IFS=$_G_IFS
test -x "$progdir/$progname" && break
done
- IFS="$save_IFS"
+ IFS=$_G_IFS
test -n "$progdir" || progdir=`pwd`
- progpath="$progdir/$progname"
+ progpath=$progdir/$progname
;;
esac
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed="${SED}"' -e 1s/^X//'
-sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
-# Sed substitution that turns a string into a regex matching for the
-# string literally.
-sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
-# Sed substitution that converts a w32 file name or path
-# which contains forward slashes, into one that contains
-# (escaped) backslashes. A very naive implementation.
-lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
-
-# Re-`\' parameter expansions in output of double_quote_subst that were
-# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
-# in input to double_quote_subst, that '$' was protected from expansion.
-# Since each input `\' is now two `\'s, look for any number of runs of
-# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
-bs='\\'
-bs2='\\\\'
-bs4='\\\\\\\\'
-dollar='\$'
-sed_double_backslash="\
- s/$bs4/&\\
-/g
- s/^$bs2$dollar/$bs&/
- s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
- s/\n//g"
-
-# Standard options:
opt_dry_run=false
-opt_help=false
opt_quiet=false
opt_verbose=false
-opt_warning=:
-# func_echo arg...
-# Echo program name prefixed message, along with the current mode
-# name if it has been set yet.
-func_echo ()
+# Categories 'all' and 'none' are always available. Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'. Set
+# 'warning_func' to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
{
- $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+ $debug_cmd
+
+ test -t 1 && {
+ # COLORTERM and USE_ANSI_COLORS environment variables take
+ # precedence, because most terminfo databases neglect to describe
+ # whether color sequences are supported.
+ test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+ if test 1 = "$USE_ANSI_COLORS"; then
+ # Standard ANSI escape sequences
+ tc_reset=''
+ tc_bold=''; tc_standout=''
+ tc_red=''; tc_green=''
+ tc_blue=''; tc_cyan=''
+ else
+ # Otherwise trust the terminfo database after all.
+ test -n "`tput sgr0 2>/dev/null`" && {
+ tc_reset=`tput sgr0`
+ test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+ tc_standout=$tc_bold
+ test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+ test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+ test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+ test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+ test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+ }
+ fi
+ }
+
+ require_term_colors=:
}
-# func_verbose arg...
-# Echo program name prefixed message in verbose mode only.
-func_verbose ()
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+ # We should try to minimise forks, especially on Windows where they are
+ # unreasonably slow, so skip the feature probes when bash or zsh are
+ # being used:
+ if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+ : ${_G_HAVE_ARITH_OP="yes"}
+ : ${_G_HAVE_XSI_OPS="yes"}
+ # The += operator was introduced in bash 3.1
+ case $BASH_VERSION in
+ [12].* | 3.0 | 3.0*) ;;
+ *)
+ : ${_G_HAVE_PLUSEQ_OP="yes"}
+ ;;
+ esac
+ fi
+
+ # _G_HAVE_PLUSEQ_OP
+ # Can be empty, in which case the shell is probed, "yes" if += is
+ # useable or anything else if it does not work.
+ test -z "$_G_HAVE_PLUSEQ_OP" \
+ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+ && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_append ()
+ {
+ $debug_cmd
+
+ eval "$1+=\$2"
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_append ()
+ {
+ $debug_cmd
+
+ eval "$1=\$$1\$2"
+ }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+ eval 'func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1+=\\ \$func_quote_for_eval_result"
+ }'
+else
+ func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1=\$$1\\ \$func_quote_for_eval_result"
+ }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE. For example:
+#
+# func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
{
- $opt_verbose && func_echo ${1+"$@"}
+ $debug_cmd
- # A bug in bash halts the script if the last line of a function
- # fails when set -e is in force, so we need another command to
- # work around that:
- :
+ eval _G_current_value='`$ECHO $'$1'`'
+ _G_delim=`expr "$2" : '\(.\)'`
+
+ case $_G_delim$_G_current_value$_G_delim in
+ *"$2$_G_delim"*) ;;
+ *) func_append "$@" ;;
+ esac
}
-# func_echo_all arg...
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+ test -z "$_G_HAVE_ARITH_OP" \
+ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+ && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+ eval 'func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=$(( $* ))
+ }'
+else
+ func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=`expr "$@"`
+ }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ # If this shell supports suffix pattern removal, then use it to avoid
+ # forking. Hide the definitions single quotes in case the shell chokes
+ # on unsupported syntax...
+ _b='func_basename_result=${1##*/}'
+ _d='case $1 in
+ */*) func_dirname_result=${1%/*}$2 ;;
+ * ) func_dirname_result=$3 ;;
+ esac'
+
+else
+ # ...otherwise fall back to using sed.
+ _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+ _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"`
+ if test "X$func_dirname_result" = "X$1"; then
+ func_dirname_result=$3
+ else
+ func_append func_dirname_result "$2"
+ fi'
+fi
+
+eval 'func_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+ $debug_cmd
+
+ '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+ '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
# Invoke $ECHO with all args, space-separated.
func_echo_all ()
{
$ECHO "$*"
}
-# func_error arg...
-# Echo program name prefixed message to standard error.
-func_error ()
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
{
- $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+ $debug_cmd
+
+ $require_term_colors
+
+ _G_infix=$1; shift
+ _G_indent=$_G_infix
+ _G_prefix="$progname: $_G_infix: "
+ _G_message=$*
+
+ # Strip color escape sequences before counting printable length
+ for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+ do
+ test -n "$_G_tc" && {
+ _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+ _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+ }
+ done
+ _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes
+
+ func_echo_infix_1_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_infix_1_IFS
+ $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+ _G_prefix=$_G_indent
+ done
+ IFS=$func_echo_infix_1_IFS
}
-# func_warning arg...
-# Echo program name prefixed warning message to standard error.
-func_warning ()
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
{
- $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+ $debug_cmd
- # bash bug again:
- :
+ $require_term_colors
+
+ func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2
}
-# func_fatal_error arg...
+
+# func_fatal_error ARG...
+# -----------------------
# Echo program name prefixed message to standard error, and exit.
func_fatal_error ()
{
- func_error ${1+"$@"}
- exit $EXIT_FAILURE
-}
+ $debug_cmd
-# func_fatal_help arg...
-# Echo program name prefixed message to standard error, followed by
-# a help hint, and exit.
-func_fatal_help ()
-{
- func_error ${1+"$@"}
- func_fatal_error "$help"
+ func_error "$*"
+ exit $EXIT_FAILURE
}
-help="Try \`$progname --help' for more information." ## default
-# func_grep expression filename
+# func_grep EXPRESSION FILENAME
+# -----------------------------
# Check whether EXPRESSION matches any line of FILENAME, without output.
func_grep ()
{
+ $debug_cmd
+
$GREP "$1" "$2" >/dev/null 2>&1
}
-# func_mkdir_p directory-path
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+ test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=${#1}
+ }'
+else
+ func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+ }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
# Make sure the entire path to DIRECTORY-PATH is available.
func_mkdir_p ()
{
- my_directory_path="$1"
- my_dir_list=
+ $debug_cmd
- if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+ _G_directory_path=$1
+ _G_dir_list=
- # Protect directory names starting with `-'
- case $my_directory_path in
- -*) my_directory_path="./$my_directory_path" ;;
+ if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+ # Protect directory names starting with '-'
+ case $_G_directory_path in
+ -*) _G_directory_path=./$_G_directory_path ;;
esac
# While some portion of DIR does not yet exist...
- while test ! -d "$my_directory_path"; do
+ while test ! -d "$_G_directory_path"; do
# ...make a list in topmost first order. Use a colon delimited
# list incase some portion of path contains whitespace.
- my_dir_list="$my_directory_path:$my_dir_list"
+ _G_dir_list=$_G_directory_path:$_G_dir_list
# If the last portion added has no slash in it, the list is done
- case $my_directory_path in */*) ;; *) break ;; esac
+ case $_G_directory_path in */*) ;; *) break ;; esac
# ...otherwise throw away the child directory and loop
- my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+ _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
done
- my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+ _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
- save_mkdir_p_IFS="$IFS"; IFS=':'
- for my_dir in $my_dir_list; do
- IFS="$save_mkdir_p_IFS"
- # mkdir can fail with a `File exist' error if two processes
+ func_mkdir_p_IFS=$IFS; IFS=:
+ for _G_dir in $_G_dir_list; do
+ IFS=$func_mkdir_p_IFS
+ # mkdir can fail with a 'File exist' error if two processes
# try to create one of the directories concurrently. Don't
# stop in that case!
- $MKDIR "$my_dir" 2>/dev/null || :
+ $MKDIR "$_G_dir" 2>/dev/null || :
done
- IFS="$save_mkdir_p_IFS"
+ IFS=$func_mkdir_p_IFS
# Bail out if we (or some other process) failed to create a directory.
- test -d "$my_directory_path" || \
- func_fatal_error "Failed to create \`$1'"
+ test -d "$_G_directory_path" || \
+ func_fatal_error "Failed to create '$1'"
fi
}
-# func_mktempdir [string]
+# func_mktempdir [BASENAME]
+# -------------------------
# Make a temporary directory that won't clash with other running
# libtool processes, and avoids race conditions if possible. If
-# given, STRING is the basename for that directory.
+# given, BASENAME is the basename for that directory.
func_mktempdir ()
{
- my_template="${TMPDIR-/tmp}/${1-$progname}"
+ $debug_cmd
+
+ _G_template=${TMPDIR-/tmp}/${1-$progname}
- if test "$opt_dry_run" = ":"; then
+ if test : = "$opt_dry_run"; then
# Return a directory name, but don't create it in dry-run mode
- my_tmpdir="${my_template}-$$"
+ _G_tmpdir=$_G_template-$$
else
# If mktemp works, use that first and foremost
- my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+ _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
- if test ! -d "$my_tmpdir"; then
+ if test ! -d "$_G_tmpdir"; then
# Failing that, at least try and use $RANDOM to avoid a race
- my_tmpdir="${my_template}-${RANDOM-0}$$"
+ _G_tmpdir=$_G_template-${RANDOM-0}$$
- save_mktempdir_umask=`umask`
+ func_mktempdir_umask=`umask`
umask 0077
- $MKDIR "$my_tmpdir"
- umask $save_mktempdir_umask
+ $MKDIR "$_G_tmpdir"
+ umask $func_mktempdir_umask
fi
# If we're not in dry-run mode, bomb out on failure
- test -d "$my_tmpdir" || \
- func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+ test -d "$_G_tmpdir" || \
+ func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
fi
- $ECHO "$my_tmpdir"
+ $ECHO "$_G_tmpdir"
}
-# func_quote_for_eval arg
-# Aesthetically quote ARG to be evaled later.
-# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
-# is double-quoted, suitable for a subsequent eval, whereas
-# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
-# which are still active within double quotes backslashified.
-func_quote_for_eval ()
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
{
- case $1 in
- *[\\\`\"\$]*)
- func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+ $debug_cmd
+
+ # These SED scripts presuppose an absolute path with a trailing slash.
+ _G_pathcar='s|^/\([^/]*\).*$|\1|'
+ _G_pathcdr='s|^/[^/]*||'
+ _G_removedotparts=':dotsl
+ s|/\./|/|g
+ t dotsl
+ s|/\.$|/|'
+ _G_collapseslashes='s|/\{1,\}|/|g'
+ _G_finalslash='s|/*$|/|'
+
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
*)
- func_quote_for_eval_unquoted_result="$1" ;;
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
esac
- case $func_quote_for_eval_unquoted_result in
- # Double-quote args containing shell metacharacters to delay
- # word splitting, command substitution and and variable
- # expansion for a subsequent eval.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test / = "$func_normal_abspath_tpath"; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result"; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+ $debug_cmd
+
+ $opt_quiet || func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+ $debug_cmd
+
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=$func_dirname_result
+ if test -z "$func_relative_path_tlibdir"; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test -n "$func_stripname_result"; then
+ func_append func_relative_path_result "/$func_stripname_result"
+ fi
+
+ # Normalisation. If bindir is libdir, return '.' else relative path.
+ if test -n "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ fi
+
+ test -n "$func_relative_path_result" || func_relative_path_result=.
+
+ :
+}
+
+
+# func_quote ARG
+# --------------
+# Aesthetically quote one ARG, store the result into $func_quote_result. Note
+# that we keep attention to performance here (so far O(N) complexity as long as
+# func_append is O(1)).
+func_quote ()
+{
+ $debug_cmd
+
+ func_quote_result=$1
+
+ case $func_quote_result in
+ *[\\\`\"\$]*)
+ case $func_quote_result in
+ *[\[\*\?]*)
+ func_quote_result=`$ECHO "$func_quote_result" | $SED "$sed_quote_subst"`
+ return 0
+ ;;
+ esac
+
+ func_quote_old_IFS=$IFS
+ for _G_char in '\' '`' '"' '$'
+ do
+ # STATE($1) PREV($2) SEPARATOR($3)
+ set start "" ""
+ func_quote_result=dummy"$_G_char$func_quote_result$_G_char"dummy
+ IFS=$_G_char
+ for _G_part in $func_quote_result
+ do
+ case $1 in
+ quote)
+ func_append func_quote_result "$3$2"
+ set quote "$_G_part" "\\$_G_char"
+ ;;
+ start)
+ set first "" ""
+ func_quote_result=
+ ;;
+ first)
+ set quote "$_G_part" ""
+ ;;
+ esac
+ done
+ IFS=$func_quote_old_IFS
+ done
;;
- *)
- func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+ *) ;;
esac
}
-# func_quote_for_expand arg
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+# i) func_quote_for_eval_result
+# double-quoted, suitable for a subsequent eval
+# ii) func_quote_for_eval_unquoted_result
+# has all characters that are still active within double
+# quotes backslashified.
+func_quote_for_eval ()
+{
+ $debug_cmd
+
+ func_quote_for_eval_unquoted_result=
+ func_quote_for_eval_result=
+ while test 0 -lt $#; do
+ func_quote "$1"
+ _G_unquoted_arg=$func_quote_result
+ if test -n "$func_quote_for_eval_unquoted_result"; then
+ func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+ else
+ func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+ fi
+
+ case $_G_unquoted_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and variable expansion
+ # for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_quoted_arg=\"$_G_unquoted_arg\"
+ ;;
+ *)
+ _G_quoted_arg=$_G_unquoted_arg
+ ;;
+ esac
+
+ if test -n "$func_quote_for_eval_result"; then
+ func_append func_quote_for_eval_result " $_G_quoted_arg"
+ else
+ func_append func_quote_for_eval_result "$_G_quoted_arg"
+ fi
+ shift
+ done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
# Aesthetically quote ARG to be evaled later; same as above,
# but do not quote variable references.
func_quote_for_expand ()
{
+ $debug_cmd
+
case $1 in
*[\\\`\"]*)
- my_arg=`$ECHO "$1" | $SED \
- -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+ _G_arg=`$ECHO "$1" | $SED \
+ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
*)
- my_arg="$1" ;;
+ _G_arg=$1 ;;
esac
- case $my_arg in
+ case $_G_arg in
# Double-quote args containing shell metacharacters to delay
# word splitting and command substitution for a subsequent eval.
# Many Bourne shells cannot handle close brackets correctly
# in scan sets, so we specify it separately.
*[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- my_arg="\"$my_arg\""
+ _G_arg=\"$_G_arg\"
;;
esac
- func_quote_for_expand_result="$my_arg"
+ func_quote_for_expand_result=$_G_arg
}
-# func_show_eval cmd [fail_exp]
-# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_stripname ()
+ {
+ $debug_cmd
+
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary variable first.
+ func_stripname_result=$3
+ func_stripname_result=${func_stripname_result#"$1"}
+ func_stripname_result=${func_stripname_result%"$2"}
+ }'
+else
+ func_stripname ()
+ {
+ $debug_cmd
+
+ case $2 in
+ .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+ *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+ esac
+ }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
# is given, then evaluate it.
func_show_eval ()
{
- my_cmd="$1"
- my_fail_exp="${2-:}"
+ $debug_cmd
- ${opt_silent-false} || {
- func_quote_for_expand "$my_cmd"
- eval "func_echo $func_quote_for_expand_result"
- }
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ func_quote_for_expand "$_G_cmd"
+ eval "func_notquiet $func_quote_for_expand_result"
- if ${opt_dry_run-false}; then :; else
- eval "$my_cmd"
- my_status=$?
- if test "$my_status" -eq 0; then :; else
- eval "(exit $my_status); $my_fail_exp"
+ $opt_dry_run || {
+ eval "$_G_cmd"
+ _G_status=$?
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
fi
- fi
+ }
}
-# func_show_eval_locale cmd [fail_exp]
-# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
# is given, then evaluate it. Use the saved locale for evaluation.
func_show_eval_locale ()
{
- my_cmd="$1"
- my_fail_exp="${2-:}"
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
- ${opt_silent-false} || {
- func_quote_for_expand "$my_cmd"
+ $opt_quiet || {
+ func_quote_for_expand "$_G_cmd"
eval "func_echo $func_quote_for_expand_result"
}
- if ${opt_dry_run-false}; then :; else
- eval "$lt_user_locale
- $my_cmd"
- my_status=$?
- eval "$lt_safe_locale"
- if test "$my_status" -eq 0; then :; else
- eval "(exit $my_status); $my_fail_exp"
+ $opt_dry_run || {
+ eval "$_G_user_locale
+ $_G_cmd"
+ _G_status=$?
+ eval "$_G_safe_locale"
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
fi
- fi
+ }
}
+
# func_tr_sh
+# ----------
# Turn $1 into a string suitable for a shell variable name.
# Result is stored in $func_tr_sh_result. All characters
# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
# if $1 begins with a digit, a '_' is prepended as well.
func_tr_sh ()
{
- case $1 in
- [0-9]* | *[!a-zA-Z0-9_]*)
- func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
- ;;
- * )
- func_tr_sh_result=$1
- ;;
- esac
+ $debug_cmd
+
+ case $1 in
+ [0-9]* | *[!a-zA-Z0-9_]*)
+ func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+ ;;
+ * )
+ func_tr_sh_result=$1
+ ;;
+ esac
}
-# func_version
-# Echo version message to standard output and exit.
-func_version ()
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
{
- $opt_debug
+ $debug_cmd
- $SED -n '/(C)/!b go
- :more
- /\./!{
- N
- s/\n# / /
- b more
- }
- :go
- /^# '$PROGRAM' (GNU /,/# warranty; / {
- s/^# //
- s/^# *$//
- s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
- p
- }' < "$progpath"
- exit $?
+ $opt_verbose && func_echo "$*"
+
+ :
}
-# func_usage
-# Echo short help message to standard output and exit.
-func_usage ()
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
{
- $opt_debug
+ $debug_cmd
- $SED -n '/^# Usage:/,/^# *.*--help/ {
- s/^# //
- s/^# *$//
- s/\$progname/'$progname'/
- p
- }' < "$progpath"
- echo
- $ECHO "run \`$progname --help | more' for full usage"
- exit $?
+ $require_term_colors
+
+ func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+ $debug_cmd
+
+ # CATEGORY must be in the warning_categories list!
+ case " $warning_categories " in
+ *" $1 "*) ;;
+ *) func_internal_error "invalid warning category '$1'" ;;
+ esac
+
+ _G_category=$1
+ shift
+
+ case " $opt_warning_types " in
+ *" $_G_category "*) $warning_func ${1+"$@"} ;;
+ esac
}
-# func_help [NOEXIT]
-# Echo long help message to standard output and exit,
-# unless 'noexit' is passed as argument.
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+ $debug_cmd
+
+ printf '%s\n%s\n' "$1" "$2" \
+ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false. Use it like this:
+#
+# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+ $debug_cmd
+
+ test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2014-01-07.03; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+# #!/bin/sh
+# . relative/path/to/funclib.sh
+# . relative/path/to/options-parser
+# scriptversion=1.0
+# func_options ${1+"$@"}
+# eval set dummy "$func_options_result"; shift
+# ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'. Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+ --debug enable verbose shell tracing
+ -W, --warnings=CATEGORY
+ report the warnings falling in CATEGORY [all]
+ -v, --verbose verbosely report processing
+ --version print version information and exit
+ -h, --help print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+ 'all' show all warnings
+ 'none' turn off all the warnings
+ 'error' warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code. A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+ $debug_cmd
+
+ func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+ $debug_cmd
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not accept hook functions." ;;
+ esac
+
+ eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+ $debug_cmd
+
+ eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+ $debug_cmd
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+ esac
+
+ eval _G_hook_fns=\$$1_hooks; shift
+
+ for _G_hook in $_G_hook_fns; do
+ eval $_G_hook '"$@"'
+
+ # store returned options list back into positional
+ # parameters for next 'cmd' execution.
+ eval _G_hook_result=\$${_G_hook}_result
+ eval set dummy "$_G_hook_result"; shift
+ done
+
+ func_quote_for_eval ${1+"$@"}
+ func_run_hooks_result=$func_quote_for_eval_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, remove any
+# options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'. Like this:
+#
+# my_options_prep ()
+# {
+# $debug_cmd
+#
+# # Extend the existing usage message.
+# usage_message=$usage_message'
+# -s, --silent don'\''t print informational messages
+# '
+#
+# func_quote_for_eval ${1+"$@"}
+# my_options_prep_result=$func_quote_for_eval_result
+# }
+# func_add_hook func_options_prep my_options_prep
+#
+#
+# my_silent_option ()
+# {
+# $debug_cmd
+#
+# # Note that for efficiency, we parse as many options as we can
+# # recognise in a loop before passing the remainder back to the
+# # caller on the first unrecognised argument we encounter.
+# while test $# -gt 0; do
+# opt=$1; shift
+# case $opt in
+# --silent|-s) opt_silent=: ;;
+# # Separate non-argument short options:
+# -s*) func_split_short_opt "$_G_opt"
+# set dummy "$func_split_short_opt_name" \
+# "-$func_split_short_opt_arg" ${1+"$@"}
+# shift
+# ;;
+# *) set dummy "$_G_opt" "$*"; shift; break ;;
+# esac
+# done
+#
+# func_quote_for_eval ${1+"$@"}
+# my_silent_option_result=$func_quote_for_eval_result
+# }
+# func_add_hook func_parse_options my_silent_option
+#
+#
+# my_option_validation ()
+# {
+# $debug_cmd
+#
+# $opt_silent && $opt_verbose && func_fatal_help "\
+# '--silent' and '--verbose' options are mutually exclusive."
+#
+# func_quote_for_eval ${1+"$@"}
+# my_option_validation_result=$func_quote_for_eval_result
+# }
+# func_add_hook func_validate_options my_option_validation
+#
+# You'll alse need to manually amend $usage_message to reflect the extra
+# options you parse. It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+ $debug_cmd
+
+ func_options_prep ${1+"$@"}
+ eval func_parse_options \
+ ${func_options_prep_result+"$func_options_prep_result"}
+ eval func_validate_options \
+ ${func_parse_options_result+"$func_parse_options_result"}
+
+ eval func_run_hooks func_options \
+ ${func_validate_options_result+"$func_validate_options_result"}
+
+ # save modified positional parameters for caller
+ func_options_result=$func_run_hooks_result
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters. If a hook function modifies that list, and
+# needs to propogate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning.
+func_hookable func_options_prep
+func_options_prep ()
+{
+ $debug_cmd
+
+ # Option defaults:
+ opt_verbose=false
+ opt_warning_types=
+
+ func_run_hooks func_options_prep ${1+"$@"}
+
+ # save modified positional parameters for caller
+ func_options_prep_result=$func_run_hooks_result
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+ $debug_cmd
+
+ func_parse_options_result=
+
+ # this just eases exit handling
+ while test $# -gt 0; do
+ # Defer to hook functions for initial option parsing, so they
+ # get priority in the event of reusing an option name.
+ func_run_hooks func_parse_options ${1+"$@"}
+
+ # Adjust func_parse_options positional parameters to match
+ eval set dummy "$func_run_hooks_result"; shift
+
+ # Break out of the loop if we already parsed every option.
+ test $# -gt 0 || break
+
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --debug|-x) debug_cmd='set -x'
+ func_echo "enabling shell trace mode"
+ $debug_cmd
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ set dummy --warnings none ${1+"$@"}
+ shift
+ ;;
+
+ --warnings|--warning|-W)
+ test $# = 0 && func_missing_arg $_G_opt && break
+ case " $warning_categories $1" in
+ *" $1 "*)
+ # trailing space prevents matching last $1 above
+ func_append_uniq opt_warning_types " $1"
+ ;;
+ *all)
+ opt_warning_types=$warning_categories
+ ;;
+ *none)
+ opt_warning_types=none
+ warning_func=:
+ ;;
+ *error)
+ opt_warning_types=$warning_categories
+ warning_func=func_fatal_error
+ ;;
+ *)
+ func_fatal_error \
+ "unsupported warning category: '$1'"
+ ;;
+ esac
+ shift
+ ;;
+
+ --verbose|-v) opt_verbose=: ;;
+ --version) func_version ;;
+ -\?|-h) func_usage ;;
+ --help) func_help ;;
+
+ # Separate optargs to long options (plugins may need this):
+ --*=*) func_split_equals "$_G_opt"
+ set dummy "$func_split_equals_lhs" \
+ "$func_split_equals_rhs" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate optargs to short options:
+ -W*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate non-argument short options:
+ -\?*|-h*|-v*|-x*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "-$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ --) break ;;
+ -*) func_fatal_help "unrecognised option: '$_G_opt'" ;;
+ *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+ esac
+ done
+
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ func_parse_options_result=$func_quote_for_eval_result
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+ $debug_cmd
+
+ # Display all warnings if -W was not given.
+ test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+ func_run_hooks func_validate_options ${1+"$@"}
+
+ # Bail if the options were screwed!
+ $exit_cmd $EXIT_FAILURE
+
+ # save modified positional parameters for caller
+ func_validate_options_result=$func_run_hooks_result
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ eval \$ECHO \""$fatal_help"\"
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
func_help ()
{
- $opt_debug
-
- $SED -n '/^# Usage:/,/# Report bugs to/ {
- :print
- s/^# //
- s/^# *$//
- s*\$progname*'$progname'*
- s*\$host*'"$host"'*
- s*\$SHELL*'"$SHELL"'*
- s*\$LTCC*'"$LTCC"'*
- s*\$LTCFLAGS*'"$LTCFLAGS"'*
- s*\$LD*'"$LD"'*
- s/\$with_gnu_ld/'"$with_gnu_ld"'/
- s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
- s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
- p
- d
- }
- /^# .* home page:/b print
- /^# General help using/b print
- ' < "$progpath"
- ret=$?
- if test -z "$1"; then
- exit $ret
- fi
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message"
+ exit 0
}
-# func_missing_arg argname
+
+# func_missing_arg ARGNAME
+# ------------------------
# Echo program name prefixed message to standard error and set global
# exit_cmd.
func_missing_arg ()
{
- $opt_debug
+ $debug_cmd
- func_error "missing argument for $1."
+ func_error "Missing argument for '$1'."
exit_cmd=exit
}
-# func_split_short_opt shortopt
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=${1%%=*}
+ func_split_equals_rhs=${1#*=}
+ test "x$func_split_equals_lhs" = "x$1" \
+ && func_split_equals_rhs=
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+ func_split_equals_rhs=
+ test "x$func_split_equals_lhs" = "x$1" \
+ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+ }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
# Set func_split_short_opt_name and func_split_short_opt_arg shell
# variables after splitting SHORTOPT after the 2nd character.
-func_split_short_opt ()
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+ func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+ }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
{
- my_sed_short_opt='1s/^\(..\).*$/\1/;q'
- my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+ $debug_cmd
- func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
- func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
-} # func_split_short_opt may be replaced by extended shell implementation
+ func_usage_message
+ $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+ exit 0
+}
-# func_split_long_opt longopt
-# Set func_split_long_opt_name and func_split_long_opt_arg shell
-# variables after splitting LONGOPT at the `=' sign.
-func_split_long_opt ()
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
{
- my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
- my_sed_long_arg='1s/^--[^=]*=//'
+ $debug_cmd
- func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
- func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
-} # func_split_long_opt may be replaced by extended shell implementation
+ eval \$ECHO \""Usage: $usage"\"
+ echo
+ $SED -n 's|^# ||
+ /^Written by/{
+ x;p;x
+ }
+ h
+ /^Written by/q' < "$progpath"
+ echo
+ eval \$ECHO \""$usage_message"\"
+}
-exit_cmd=:
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $debug_cmd
+ printf '%s\n' "$progname $scriptversion"
+ $SED -n '
+ /(C)/!b go
+ :more
+ /\./!{
+ N
+ s|\n# | |
+ b more
+ }
+ :go
+ /^# Written by /,/# warranty; / {
+ s|^# ||
+ s|^# *$||
+ s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+ p
+ }
+ /^# Written by / {
+ s|^# ||
+ p
+ }
+ /^warranty; /q' < "$progpath"
+ exit $?
+}
-magic="%%%MAGIC variable%%%"
-magic_exe="%%%MAGIC EXE variable%%%"
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
-# Global variables.
-nonopt=
-preserve_args=
-lo2o="s/\\.lo\$/.${objext}/"
-o2lo="s/\\.${objext}\$/.lo/"
-extracted_archives=
-extracted_serial=0
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
-# If this variable is set in any of the actions, the command in it
-# will be execed at the end. This prevents here-documents from being
-# left over by shells.
-exec_cmd=
-# func_append var value
-# Append VALUE to the end of shell variable VAR.
-func_append ()
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
{
- eval "${1}=\$${1}\${2}"
-} # func_append may be replaced by extended shell implementation
+ $debug_cmd
-# func_append_quoted var value
-# Quote VALUE and append to the end of shell variable VAR, separated
-# by a space.
-func_append_quoted ()
-{
- func_quote_for_eval "${2}"
- eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
-} # func_append_quoted may be replaced by extended shell implementation
+ _G_message=$*
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
-# func_arith arithmetic-term...
-func_arith ()
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
{
- func_arith_result=`expr "${@}"`
-} # func_arith may be replaced by extended shell implementation
+ $debug_cmd
+ $warning_func ${1+"$@"}
+}
-# func_len string
-# STRING may not start with a hyphen.
-func_len ()
-{
- func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
-} # func_len may be replaced by extended shell implementation
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+ -n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --mode=MODE use operation mode MODE
+ --no-warnings equivalent to '-Wnone'
+ --preserve-dup-deps don't remove duplicate dependency libraries
+ --quiet, --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ -v, --verbose print more informational messages than default
+ --version print version information
+ -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all]
+ -h, --help, --help-all print short, long, or detailed help message
+"
-# func_lo2o object
-func_lo2o ()
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
{
- func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
-} # func_lo2o may be replaced by extended shell implementation
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+ host-triplet: $host
+ shell: $SHELL
+ compiler: $LTCC
+ compiler flags: $LTCFLAGS
+ linker: $LD (gnu? $with_gnu_ld)
+ version: $progname (GNU libtool) 2.4.6
+ automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+ autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+ exit 0
+}
-# func_xform libobj-or-source
-func_xform ()
-{
- func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
-} # func_xform may be replaced by extended shell implementation
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_lo2o ()
+ {
+ case $1 in
+ *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+ * ) func_lo2o_result=$1 ;;
+ esac
+ }'
+ # func_xform LIBOBJ-OR-SOURCE
+ # ---------------------------
+ # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+ # suffix to a '.lo' libtool-object suffix.
+ eval 'func_xform ()
+ {
+ func_xform_result=${1%.*}.lo
+ }'
+else
+ # ...otherwise fall back to using sed.
+ func_lo2o ()
+ {
+ func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+ }
-# func_fatal_configuration arg...
+ func_xform ()
+ {
+ func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+ }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
# Echo program name prefixed message to standard error, followed by
# a configuration failure hint, and exit.
func_fatal_configuration ()
{
- func_error ${1+"$@"}
- func_error "See the $PACKAGE documentation for more information."
- func_fatal_error "Fatal configuration error."
+ func__fatal_error ${1+"$@"} \
+ "See the $PACKAGE documentation for more information." \
+ "Fatal configuration error."
}
# func_config
+# -----------
# Display the configuration for all the tags in this script.
func_config ()
{
@@ -915,17 +2196,19 @@ func_config ()
exit $?
}
+
# func_features
+# -------------
# Display the features supported by this script.
func_features ()
{
echo "host: $host"
- if test "$build_libtool_libs" = yes; then
+ if test yes = "$build_libtool_libs"; then
echo "enable shared libraries"
else
echo "disable shared libraries"
fi
- if test "$build_old_libs" = yes; then
+ if test yes = "$build_old_libs"; then
echo "enable static libraries"
else
echo "disable static libraries"
@@ -934,289 +2217,297 @@ func_features ()
exit $?
}
-# func_enable_tag tagname
+
+# func_enable_tag TAGNAME
+# -----------------------
# Verify that TAGNAME is valid, and either flag an error and exit, or
# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
# variable here.
func_enable_tag ()
{
- # Global variable:
- tagname="$1"
+ # Global variable:
+ tagname=$1
- re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
- re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
- sed_extractcf="/$re_begincf/,/$re_endcf/p"
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf=/$re_begincf/,/$re_endcf/p
- # Validate tagname.
- case $tagname in
- *[!-_A-Za-z0-9,/]*)
- func_fatal_error "invalid tag name: $tagname"
- ;;
- esac
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
- # Don't test for the "default" C tag, as we know it's
- # there but not specially marked.
- case $tagname in
- CC) ;;
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
*)
- if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
- taglist="$taglist $tagname"
-
- # Evaluate the configuration. Be careful to quote the path
- # and the sed script, to avoid splitting on whitespace, but
- # also don't use non-portable quotes within backquotes within
- # quotes we have to do it in 2 steps:
- extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
- eval "$extractedcf"
- else
- func_error "ignoring unknown tag $tagname"
- fi
- ;;
- esac
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
}
+
# func_check_version_match
+# ------------------------
# Ensure that we are using m4 macros, and libtool script from the same
# release of libtool.
func_check_version_match ()
{
- if test "$package_revision" != "$macro_revision"; then
- if test "$VERSION" != "$macro_version"; then
- if test -z "$macro_version"; then
- cat >&2 <<_LT_EOF
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
$progname: definition of this LT_INIT comes from an older release.
$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
$progname: and run autoconf again.
_LT_EOF
- else
- cat >&2 <<_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
$progname: and run autoconf again.
_LT_EOF
- fi
- else
- cat >&2 <<_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
$progname: but the definition of this LT_INIT comes from revision $macro_revision.
$progname: You should recreate aclocal.m4 with macros from revision $package_revision
$progname: of $PACKAGE $VERSION and run autoconf again.
_LT_EOF
- fi
+ fi
- exit $EXIT_MISMATCH
- fi
+ exit $EXIT_MISMATCH
+ fi
}
-# Shorthand for --mode=foo, only valid as the first argument
-case $1 in
-clean|clea|cle|cl)
- shift; set dummy --mode clean ${1+"$@"}; shift
- ;;
-compile|compil|compi|comp|com|co|c)
- shift; set dummy --mode compile ${1+"$@"}; shift
- ;;
-execute|execut|execu|exec|exe|ex|e)
- shift; set dummy --mode execute ${1+"$@"}; shift
- ;;
-finish|finis|fini|fin|fi|f)
- shift; set dummy --mode finish ${1+"$@"}; shift
- ;;
-install|instal|insta|inst|ins|in|i)
- shift; set dummy --mode install ${1+"$@"}; shift
- ;;
-link|lin|li|l)
- shift; set dummy --mode link ${1+"$@"}; shift
- ;;
-uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
- shift; set dummy --mode uninstall ${1+"$@"}; shift
- ;;
-esac
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+ $debug_mode
+ # Option defaults:
+ opt_config=false
+ opt_dlopen=
+ opt_dry_run=false
+ opt_help=false
+ opt_mode=
+ opt_preserve_dup_deps=false
+ opt_quiet=false
+ nonopt=
+ preserve_args=
-# Option defaults:
-opt_debug=:
-opt_dry_run=false
-opt_config=false
-opt_preserve_dup_deps=false
-opt_features=false
-opt_finish=false
-opt_help=false
-opt_help_all=false
-opt_silent=:
-opt_warning=:
-opt_verbose=:
-opt_silent=false
-opt_verbose=false
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ esac
+
+ # Pass back the list of options.
+ func_quote_for_eval ${1+"$@"}
+ libtool_options_prep_result=$func_quote_for_eval_result
+}
+func_add_hook func_options_prep libtool_options_prep
-# Parse options once, thoroughly. This comes as soon as possible in the
-# script to make things like `--version' happen as quickly as we can.
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
{
- # this just eases exit handling
- while test $# -gt 0; do
- opt="$1"
- shift
- case $opt in
- --debug|-x) opt_debug='set -x'
- func_echo "enabling shell trace mode"
- $opt_debug
- ;;
- --dry-run|--dryrun|-n)
- opt_dry_run=:
- ;;
- --config)
- opt_config=:
-func_config
- ;;
- --dlopen|-dlopen)
- optarg="$1"
- opt_dlopen="${opt_dlopen+$opt_dlopen
-}$optarg"
- shift
- ;;
- --preserve-dup-deps)
- opt_preserve_dup_deps=:
- ;;
- --features)
- opt_features=:
-func_features
- ;;
- --finish)
- opt_finish=:
-set dummy --mode finish ${1+"$@"}; shift
- ;;
- --help)
- opt_help=:
- ;;
- --help-all)
- opt_help_all=:
-opt_help=': help-all'
- ;;
- --mode)
- test $# = 0 && func_missing_arg $opt && break
- optarg="$1"
- opt_mode="$optarg"
-case $optarg in
- # Valid mode arguments:
- clean|compile|execute|finish|install|link|relink|uninstall) ;;
-
- # Catch anything else as an error
- *) func_error "invalid argument for $opt"
- exit_cmd=exit
- break
- ;;
-esac
- shift
- ;;
- --no-silent|--no-quiet)
- opt_silent=false
-func_append preserve_args " $opt"
- ;;
- --no-warning|--no-warn)
- opt_warning=false
-func_append preserve_args " $opt"
- ;;
- --no-verbose)
- opt_verbose=false
-func_append preserve_args " $opt"
- ;;
- --silent|--quiet)
- opt_silent=:
-func_append preserve_args " $opt"
- opt_verbose=false
- ;;
- --verbose|-v)
- opt_verbose=:
-func_append preserve_args " $opt"
-opt_silent=false
- ;;
- --tag)
- test $# = 0 && func_missing_arg $opt && break
- optarg="$1"
- opt_tag="$optarg"
-func_append preserve_args " $opt $optarg"
-func_enable_tag "$optarg"
- shift
- ;;
-
- -\?|-h) func_usage ;;
- --help) func_help ;;
- --version) func_version ;;
-
- # Separate optargs to long options:
- --*=*)
- func_split_long_opt "$opt"
- set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
- shift
- ;;
-
- # Separate non-argument short options:
- -\?*|-h*|-n*|-v*)
- func_split_short_opt "$opt"
- set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
- shift
- ;;
-
- --) break ;;
- -*) func_fatal_help "unrecognized option \`$opt'" ;;
- *) set dummy "$opt" ${1+"$@"}; shift; break ;;
- esac
- done
+ $debug_cmd
- # Validate options:
+ # Perform our own loop to consume as many options as possible in
+ # each iteration.
+ while test $# -gt 0; do
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --dry-run|--dryrun|-n)
+ opt_dry_run=:
+ ;;
+
+ --config) func_config ;;
+
+ --dlopen|-dlopen)
+ opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_preserve_dup_deps=: ;;
+
+ --features) func_features ;;
+
+ --finish) set dummy --mode finish ${1+"$@"}; shift ;;
+
+ --help) opt_help=: ;;
+
+ --help-all) opt_help=': help-all' ;;
+
+ --mode) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_mode=$1
+ case $1 in
+ # Valid mode arguments:
+ clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $_G_opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+ shift
+ ;;
+
+ --no-silent|--no-quiet)
+ opt_quiet=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ opt_warning=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-verbose)
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --silent|--quiet)
+ opt_quiet=:
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --tag) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_tag=$1
+ func_append preserve_args " $_G_opt $1"
+ func_enable_tag "$1"
+ shift
+ ;;
+
+ --verbose|-v) opt_quiet=false
+ opt_verbose=:
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ # An option not handled by this hook function:
+ *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+ esac
+ done
- # save first non-option argument
- if test "$#" -gt 0; then
- nonopt="$opt"
- shift
- fi
- # preserve --debug
- test "$opt_debug" = : || func_append preserve_args " --debug"
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ libtool_parse_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_parse_options libtool_parse_options
- case $host in
- *cygwin* | *mingw* | *pw32* | *cegcc*)
- # don't eliminate duplications in $postdeps and $predeps
- opt_duplicate_compiler_generated_deps=:
- ;;
- *)
- opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
- ;;
- esac
- $opt_help || {
- # Sanity checks first:
- func_check_version_match
- if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
- func_fatal_configuration "not configured to build any kind of library"
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+ # save first non-option argument
+ if test 0 -lt $#; then
+ nonopt=$1
+ shift
fi
- # Darwin sucks
- eval std_shrext=\"$shrext_cmds\"
+ # preserve --debug
+ test : = "$debug_cmd" || func_append preserve_args " --debug"
- # Only execute mode is allowed to have -dlopen flags.
- if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
- func_error "unrecognized option \`-dlopen'"
- $ECHO "$help" 1>&2
- exit $EXIT_FAILURE
- fi
+ case $host in
+ # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+ # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+ *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+ ;;
+ esac
- # Change the help message to a mode-specific one.
- generic_help="$help"
- help="Try \`$progname --help --mode=$opt_mode' for more information."
- }
+ $opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+ test yes != "$build_libtool_libs" \
+ && test yes != "$build_old_libs" \
+ && func_fatal_configuration "not configured to build any kind of library"
- # Bail if the options were screwed
- $exit_cmd $EXIT_FAILURE
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+ func_error "unrecognized option '-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help=$help
+ help="Try '$progname --help --mode=$opt_mode' for more information."
+ }
+
+ # Pass back the unparsed argument list
+ func_quote_for_eval ${1+"$@"}
+ libtool_validate_options_result=$func_quote_for_eval_result
}
+func_add_hook func_validate_options libtool_validate_options
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
@@ -1224,24 +2515,52 @@ func_enable_tag "$optarg"
## Main. ##
## ----------- ##
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+ $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
# func_lalib_p file
-# True iff FILE is a libtool `.la' library or `.lo' object file.
+# True iff FILE is a libtool '.la' library or '.lo' object file.
# This function is only a basic sanity check; it will hardly flush out
# determined imposters.
func_lalib_p ()
{
test -f "$1" &&
- $SED -e 4q "$1" 2>/dev/null \
- | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+ $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
}
# func_lalib_unsafe_p file
-# True iff FILE is a libtool `.la' library or `.lo' object file.
+# True iff FILE is a libtool '.la' library or '.lo' object file.
# This function implements the same check as func_lalib_p without
# resorting to external programs. To this end, it redirects stdin and
# closes it afterwards, without saving the original file descriptor.
# As a safety measure, use it only where a negative result would be
-# fatal anyway. Works if `file' does not exist.
+# fatal anyway. Works if 'file' does not exist.
func_lalib_unsafe_p ()
{
lalib_p=no
@@ -1249,13 +2568,13 @@ func_lalib_unsafe_p ()
for lalib_p_l in 1 2 3 4
do
read lalib_p_line
- case "$lalib_p_line" in
+ case $lalib_p_line in
\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
esac
done
exec 0<&5 5<&-
fi
- test "$lalib_p" = yes
+ test yes = "$lalib_p"
}
# func_ltwrapper_script_p file
@@ -1264,7 +2583,8 @@ func_lalib_unsafe_p ()
# determined imposters.
func_ltwrapper_script_p ()
{
- func_lalib_p "$1"
+ test -f "$1" &&
+ $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
}
# func_ltwrapper_executable_p file
@@ -1289,7 +2609,7 @@ func_ltwrapper_scriptname ()
{
func_dirname_and_basename "$1" "" "."
func_stripname '' '.exe' "$func_basename_result"
- func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+ func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
}
# func_ltwrapper_p file
@@ -1308,11 +2628,13 @@ func_ltwrapper_p ()
# FAIL_CMD may read-access the current command in variable CMD!
func_execute_cmds ()
{
- $opt_debug
+ $debug_cmd
+
save_ifs=$IFS; IFS='~'
for cmd in $1; do
- IFS=$save_ifs
+ IFS=$sp$nl
eval cmd=\"$cmd\"
+ IFS=$save_ifs
func_show_eval "$cmd" "${2-:}"
done
IFS=$save_ifs
@@ -1324,10 +2646,11 @@ func_execute_cmds ()
# Note that it is not necessary on cygwin/mingw to append a dot to
# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
# behavior happens only for exec(3), not for open(2)! Also, sourcing
-# `FILE.' does not work on cygwin managed mounts.
+# 'FILE.' does not work on cygwin managed mounts.
func_source ()
{
- $opt_debug
+ $debug_cmd
+
case $1 in
*/* | *\\*) . "$1" ;;
*) . "./$1" ;;
@@ -1354,10 +2677,10 @@ func_resolve_sysroot ()
# store the result into func_replace_sysroot_result.
func_replace_sysroot ()
{
- case "$lt_sysroot:$1" in
+ case $lt_sysroot:$1 in
?*:"$lt_sysroot"*)
func_stripname "$lt_sysroot" '' "$1"
- func_replace_sysroot_result="=$func_stripname_result"
+ func_replace_sysroot_result='='$func_stripname_result
;;
*)
# Including no sysroot.
@@ -1374,7 +2697,8 @@ func_replace_sysroot ()
# arg is usually of the form 'gcc ...'
func_infer_tag ()
{
- $opt_debug
+ $debug_cmd
+
if test -n "$available_tags" && test -z "$tagname"; then
CC_quoted=
for arg in $CC; do
@@ -1393,7 +2717,7 @@ func_infer_tag ()
for z in $available_tags; do
if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
# Evaluate the configuration.
- eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
CC_quoted=
for arg in $CC; do
# Double-quote args containing other shell metacharacters.
@@ -1418,7 +2742,7 @@ func_infer_tag ()
# line option must be used.
if test -z "$tagname"; then
func_echo "unable to infer tagged configuration"
- func_fatal_error "specify a tag with \`--tag'"
+ func_fatal_error "specify a tag with '--tag'"
# else
# func_verbose "using $tagname tagged configuration"
fi
@@ -1434,15 +2758,15 @@ func_infer_tag ()
# but don't create it if we're doing a dry run.
func_write_libtool_object ()
{
- write_libobj=${1}
- if test "$build_libtool_libs" = yes; then
- write_lobj=\'${2}\'
+ write_libobj=$1
+ if test yes = "$build_libtool_libs"; then
+ write_lobj=\'$2\'
else
write_lobj=none
fi
- if test "$build_old_libs" = yes; then
- write_oldobj=\'${3}\'
+ if test yes = "$build_old_libs"; then
+ write_oldobj=\'$3\'
else
write_oldobj=none
fi
@@ -1450,7 +2774,7 @@ func_write_libtool_object ()
$opt_dry_run || {
cat >${write_libobj}T <<EOF
# $write_libobj - a libtool object file
-# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
@@ -1462,7 +2786,7 @@ pic_object=$write_lobj
non_pic_object=$write_oldobj
EOF
- $MV "${write_libobj}T" "${write_libobj}"
+ $MV "${write_libobj}T" "$write_libobj"
}
}
@@ -1482,8 +2806,9 @@ EOF
# be empty on error (or when ARG is empty)
func_convert_core_file_wine_to_w32 ()
{
- $opt_debug
- func_convert_core_file_wine_to_w32_result="$1"
+ $debug_cmd
+
+ func_convert_core_file_wine_to_w32_result=$1
if test -n "$1"; then
# Unfortunately, winepath does not exit with a non-zero error code, so we
# are forced to check the contents of stdout. On the other hand, if the
@@ -1491,9 +2816,9 @@ func_convert_core_file_wine_to_w32 ()
# *an error message* to stdout. So we must check for both error code of
# zero AND non-empty stdout, which explains the odd construction:
func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
- if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+ if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
- $SED -e "$lt_sed_naive_backslashify"`
+ $SED -e "$sed_naive_backslashify"`
else
func_convert_core_file_wine_to_w32_result=
fi
@@ -1514,18 +2839,19 @@ func_convert_core_file_wine_to_w32 ()
# are convertible, then the result may be empty.
func_convert_core_path_wine_to_w32 ()
{
- $opt_debug
+ $debug_cmd
+
# unfortunately, winepath doesn't convert paths, only file names
- func_convert_core_path_wine_to_w32_result=""
+ func_convert_core_path_wine_to_w32_result=
if test -n "$1"; then
oldIFS=$IFS
IFS=:
for func_convert_core_path_wine_to_w32_f in $1; do
IFS=$oldIFS
func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
- if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+ if test -n "$func_convert_core_file_wine_to_w32_result"; then
if test -z "$func_convert_core_path_wine_to_w32_result"; then
- func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+ func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
else
func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
fi
@@ -1554,7 +2880,8 @@ func_convert_core_path_wine_to_w32 ()
# environment variable; do not put it in $PATH.
func_cygpath ()
{
- $opt_debug
+ $debug_cmd
+
if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
if test "$?" -ne 0; then
@@ -1563,7 +2890,7 @@ func_cygpath ()
fi
else
func_cygpath_result=
- func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+ func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
fi
}
#end: func_cygpath
@@ -1574,10 +2901,11 @@ func_cygpath ()
# result in func_convert_core_msys_to_w32_result.
func_convert_core_msys_to_w32 ()
{
- $opt_debug
+ $debug_cmd
+
# awkward: cmd appends spaces to result
func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
- $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+ $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
}
#end: func_convert_core_msys_to_w32
@@ -1588,13 +2916,14 @@ func_convert_core_msys_to_w32 ()
# func_to_host_file_result to ARG1).
func_convert_file_check ()
{
- $opt_debug
- if test -z "$2" && test -n "$1" ; then
+ $debug_cmd
+
+ if test -z "$2" && test -n "$1"; then
func_error "Could not determine host file name corresponding to"
- func_error " \`$1'"
+ func_error " '$1'"
func_error "Continuing, but uninstalled executables may not work."
# Fallback:
- func_to_host_file_result="$1"
+ func_to_host_file_result=$1
fi
}
# end func_convert_file_check
@@ -1606,10 +2935,11 @@ func_convert_file_check ()
# func_to_host_file_result to a simplistic fallback value (see below).
func_convert_path_check ()
{
- $opt_debug
+ $debug_cmd
+
if test -z "$4" && test -n "$3"; then
func_error "Could not determine the host path corresponding to"
- func_error " \`$3'"
+ func_error " '$3'"
func_error "Continuing, but uninstalled executables may not work."
# Fallback. This is a deliberately simplistic "conversion" and
# should not be "improved". See libtool.info.
@@ -1618,7 +2948,7 @@ func_convert_path_check ()
func_to_host_path_result=`echo "$3" |
$SED -e "$lt_replace_pathsep_chars"`
else
- func_to_host_path_result="$3"
+ func_to_host_path_result=$3
fi
fi
}
@@ -1630,9 +2960,10 @@ func_convert_path_check ()
# and appending REPL if ORIG matches BACKPAT.
func_convert_path_front_back_pathsep ()
{
- $opt_debug
+ $debug_cmd
+
case $4 in
- $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+ $1 ) func_to_host_path_result=$3$func_to_host_path_result
;;
esac
case $4 in
@@ -1646,7 +2977,7 @@ func_convert_path_front_back_pathsep ()
##################################################
# $build to $host FILE NAME CONVERSION FUNCTIONS #
##################################################
-# invoked via `$to_host_file_cmd ARG'
+# invoked via '$to_host_file_cmd ARG'
#
# In each case, ARG is the path to be converted from $build to $host format.
# Result will be available in $func_to_host_file_result.
@@ -1657,7 +2988,8 @@ func_convert_path_front_back_pathsep ()
# in func_to_host_file_result.
func_to_host_file ()
{
- $opt_debug
+ $debug_cmd
+
$to_host_file_cmd "$1"
}
# end func_to_host_file
@@ -1669,7 +3001,8 @@ func_to_host_file ()
# in (the comma separated) LAZY, no conversion takes place.
func_to_tool_file ()
{
- $opt_debug
+ $debug_cmd
+
case ,$2, in
*,"$to_tool_file_cmd",*)
func_to_tool_file_result=$1
@@ -1687,7 +3020,7 @@ func_to_tool_file ()
# Copy ARG to func_to_host_file_result.
func_convert_file_noop ()
{
- func_to_host_file_result="$1"
+ func_to_host_file_result=$1
}
# end func_convert_file_noop
@@ -1698,11 +3031,12 @@ func_convert_file_noop ()
# func_to_host_file_result.
func_convert_file_msys_to_w32 ()
{
- $opt_debug
- func_to_host_file_result="$1"
+ $debug_cmd
+
+ func_to_host_file_result=$1
if test -n "$1"; then
func_convert_core_msys_to_w32 "$1"
- func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+ func_to_host_file_result=$func_convert_core_msys_to_w32_result
fi
func_convert_file_check "$1" "$func_to_host_file_result"
}
@@ -1714,8 +3048,9 @@ func_convert_file_msys_to_w32 ()
# func_to_host_file_result.
func_convert_file_cygwin_to_w32 ()
{
- $opt_debug
- func_to_host_file_result="$1"
+ $debug_cmd
+
+ func_to_host_file_result=$1
if test -n "$1"; then
# because $build is cygwin, we call "the" cygpath in $PATH; no need to use
# LT_CYGPATH in this case.
@@ -1731,11 +3066,12 @@ func_convert_file_cygwin_to_w32 ()
# and a working winepath. Returns result in func_to_host_file_result.
func_convert_file_nix_to_w32 ()
{
- $opt_debug
- func_to_host_file_result="$1"
+ $debug_cmd
+
+ func_to_host_file_result=$1
if test -n "$1"; then
func_convert_core_file_wine_to_w32 "$1"
- func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+ func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
fi
func_convert_file_check "$1" "$func_to_host_file_result"
}
@@ -1747,12 +3083,13 @@ func_convert_file_nix_to_w32 ()
# Returns result in func_to_host_file_result.
func_convert_file_msys_to_cygwin ()
{
- $opt_debug
- func_to_host_file_result="$1"
+ $debug_cmd
+
+ func_to_host_file_result=$1
if test -n "$1"; then
func_convert_core_msys_to_w32 "$1"
func_cygpath -u "$func_convert_core_msys_to_w32_result"
- func_to_host_file_result="$func_cygpath_result"
+ func_to_host_file_result=$func_cygpath_result
fi
func_convert_file_check "$1" "$func_to_host_file_result"
}
@@ -1765,13 +3102,14 @@ func_convert_file_msys_to_cygwin ()
# in func_to_host_file_result.
func_convert_file_nix_to_cygwin ()
{
- $opt_debug
- func_to_host_file_result="$1"
+ $debug_cmd
+
+ func_to_host_file_result=$1
if test -n "$1"; then
# convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
func_convert_core_file_wine_to_w32 "$1"
func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
- func_to_host_file_result="$func_cygpath_result"
+ func_to_host_file_result=$func_cygpath_result
fi
func_convert_file_check "$1" "$func_to_host_file_result"
}
@@ -1781,7 +3119,7 @@ func_convert_file_nix_to_cygwin ()
#############################################
# $build to $host PATH CONVERSION FUNCTIONS #
#############################################
-# invoked via `$to_host_path_cmd ARG'
+# invoked via '$to_host_path_cmd ARG'
#
# In each case, ARG is the path to be converted from $build to $host format.
# The result will be available in $func_to_host_path_result.
@@ -1805,10 +3143,11 @@ func_convert_file_nix_to_cygwin ()
to_host_path_cmd=
func_init_to_host_path_cmd ()
{
- $opt_debug
+ $debug_cmd
+
if test -z "$to_host_path_cmd"; then
func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
- to_host_path_cmd="func_convert_path_${func_stripname_result}"
+ to_host_path_cmd=func_convert_path_$func_stripname_result
fi
}
@@ -1818,7 +3157,8 @@ func_init_to_host_path_cmd ()
# in func_to_host_path_result.
func_to_host_path ()
{
- $opt_debug
+ $debug_cmd
+
func_init_to_host_path_cmd
$to_host_path_cmd "$1"
}
@@ -1829,7 +3169,7 @@ func_to_host_path ()
# Copy ARG to func_to_host_path_result.
func_convert_path_noop ()
{
- func_to_host_path_result="$1"
+ func_to_host_path_result=$1
}
# end func_convert_path_noop
@@ -1840,8 +3180,9 @@ func_convert_path_noop ()
# func_to_host_path_result.
func_convert_path_msys_to_w32 ()
{
- $opt_debug
- func_to_host_path_result="$1"
+ $debug_cmd
+
+ func_to_host_path_result=$1
if test -n "$1"; then
# Remove leading and trailing path separator characters from ARG. MSYS
# behavior is inconsistent here; cygpath turns them into '.;' and ';.';
@@ -1849,7 +3190,7 @@ func_convert_path_msys_to_w32 ()
func_stripname : : "$1"
func_to_host_path_tmp1=$func_stripname_result
func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
- func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+ func_to_host_path_result=$func_convert_core_msys_to_w32_result
func_convert_path_check : ";" \
"$func_to_host_path_tmp1" "$func_to_host_path_result"
func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
@@ -1863,8 +3204,9 @@ func_convert_path_msys_to_w32 ()
# func_to_host_file_result.
func_convert_path_cygwin_to_w32 ()
{
- $opt_debug
- func_to_host_path_result="$1"
+ $debug_cmd
+
+ func_to_host_path_result=$1
if test -n "$1"; then
# See func_convert_path_msys_to_w32:
func_stripname : : "$1"
@@ -1883,14 +3225,15 @@ func_convert_path_cygwin_to_w32 ()
# a working winepath. Returns result in func_to_host_file_result.
func_convert_path_nix_to_w32 ()
{
- $opt_debug
- func_to_host_path_result="$1"
+ $debug_cmd
+
+ func_to_host_path_result=$1
if test -n "$1"; then
# See func_convert_path_msys_to_w32:
func_stripname : : "$1"
func_to_host_path_tmp1=$func_stripname_result
func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
- func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+ func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
func_convert_path_check : ";" \
"$func_to_host_path_tmp1" "$func_to_host_path_result"
func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
@@ -1904,15 +3247,16 @@ func_convert_path_nix_to_w32 ()
# Returns result in func_to_host_file_result.
func_convert_path_msys_to_cygwin ()
{
- $opt_debug
- func_to_host_path_result="$1"
+ $debug_cmd
+
+ func_to_host_path_result=$1
if test -n "$1"; then
# See func_convert_path_msys_to_w32:
func_stripname : : "$1"
func_to_host_path_tmp1=$func_stripname_result
func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
- func_to_host_path_result="$func_cygpath_result"
+ func_to_host_path_result=$func_cygpath_result
func_convert_path_check : : \
"$func_to_host_path_tmp1" "$func_to_host_path_result"
func_convert_path_front_back_pathsep ":*" "*:" : "$1"
@@ -1927,8 +3271,9 @@ func_convert_path_msys_to_cygwin ()
# func_to_host_file_result.
func_convert_path_nix_to_cygwin ()
{
- $opt_debug
- func_to_host_path_result="$1"
+ $debug_cmd
+
+ func_to_host_path_result=$1
if test -n "$1"; then
# Remove leading and trailing path separator characters from
# ARG. msys behavior is inconsistent here, cygpath turns them
@@ -1937,7 +3282,7 @@ func_convert_path_nix_to_cygwin ()
func_to_host_path_tmp1=$func_stripname_result
func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
- func_to_host_path_result="$func_cygpath_result"
+ func_to_host_path_result=$func_cygpath_result
func_convert_path_check : : \
"$func_to_host_path_tmp1" "$func_to_host_path_result"
func_convert_path_front_back_pathsep ":*" "*:" : "$1"
@@ -1946,13 +3291,31 @@ func_convert_path_nix_to_cygwin ()
# end func_convert_path_nix_to_cygwin
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+ $debug_cmd
+
+ func_dll_def_p_tmp=`$SED -n \
+ -e 's/^[ ]*//' \
+ -e '/^\(;.*\)*$/d' \
+ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \
+ -e q \
+ "$1"`
+ test DEF = "$func_dll_def_p_tmp"
+}
+
+
# func_mode_compile arg...
func_mode_compile ()
{
- $opt_debug
+ $debug_cmd
+
# Get the compilation command and the source file.
base_compile=
- srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ srcfile=$nonopt # always keep a non-empty value in "srcfile"
suppress_opt=yes
suppress_output=
arg_mode=normal
@@ -1965,12 +3328,12 @@ func_mode_compile ()
case $arg_mode in
arg )
# do not "continue". Instead, add this to base_compile
- lastarg="$arg"
+ lastarg=$arg
arg_mode=normal
;;
target )
- libobj="$arg"
+ libobj=$arg
arg_mode=normal
continue
;;
@@ -1980,7 +3343,7 @@ func_mode_compile ()
case $arg in
-o)
test -n "$libobj" && \
- func_fatal_error "you cannot specify \`-o' more than once"
+ func_fatal_error "you cannot specify '-o' more than once"
arg_mode=target
continue
;;
@@ -2009,12 +3372,12 @@ func_mode_compile ()
func_stripname '-Wc,' '' "$arg"
args=$func_stripname_result
lastarg=
- save_ifs="$IFS"; IFS=','
+ save_ifs=$IFS; IFS=,
for arg in $args; do
- IFS="$save_ifs"
+ IFS=$save_ifs
func_append_quoted lastarg "$arg"
done
- IFS="$save_ifs"
+ IFS=$save_ifs
func_stripname ' ' '' "$lastarg"
lastarg=$func_stripname_result
@@ -2027,8 +3390,8 @@ func_mode_compile ()
# Accept the current argument as the source file.
# The previous "srcfile" becomes the current argument.
#
- lastarg="$srcfile"
- srcfile="$arg"
+ lastarg=$srcfile
+ srcfile=$arg
;;
esac # case $arg
;;
@@ -2043,13 +3406,13 @@ func_mode_compile ()
func_fatal_error "you must specify an argument for -Xcompile"
;;
target)
- func_fatal_error "you must specify a target with \`-o'"
+ func_fatal_error "you must specify a target with '-o'"
;;
*)
# Get the name of the library object.
test -z "$libobj" && {
func_basename "$srcfile"
- libobj="$func_basename_result"
+ libobj=$func_basename_result
}
;;
esac
@@ -2069,7 +3432,7 @@ func_mode_compile ()
case $libobj in
*.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
*)
- func_fatal_error "cannot determine name of library object from \`$libobj'"
+ func_fatal_error "cannot determine name of library object from '$libobj'"
;;
esac
@@ -2078,8 +3441,8 @@ func_mode_compile ()
for arg in $later; do
case $arg in
-shared)
- test "$build_libtool_libs" != yes && \
- func_fatal_configuration "can not build a shared library"
+ test yes = "$build_libtool_libs" \
+ || func_fatal_configuration "cannot build a shared library"
build_old_libs=no
continue
;;
@@ -2105,17 +3468,17 @@ func_mode_compile ()
func_quote_for_eval "$libobj"
test "X$libobj" != "X$func_quote_for_eval_result" \
&& $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
- && func_warning "libobj name \`$libobj' may not contain shell special characters."
+ && func_warning "libobj name '$libobj' may not contain shell special characters."
func_dirname_and_basename "$obj" "/" ""
- objname="$func_basename_result"
- xdir="$func_dirname_result"
- lobj=${xdir}$objdir/$objname
+ objname=$func_basename_result
+ xdir=$func_dirname_result
+ lobj=$xdir$objdir/$objname
test -z "$base_compile" && \
func_fatal_help "you must specify a compilation command"
# Delete any leftover library objects.
- if test "$build_old_libs" = yes; then
+ if test yes = "$build_old_libs"; then
removelist="$obj $lobj $libobj ${libobj}T"
else
removelist="$lobj $libobj ${libobj}T"
@@ -2127,16 +3490,16 @@ func_mode_compile ()
pic_mode=default
;;
esac
- if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
# non-PIC code in shared libraries is not supported
pic_mode=default
fi
# Calculate the filename of the output object if compiler does
# not support -o with -c
- if test "$compiler_c_o" = no; then
- output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
- lockfile="$output_obj.lock"
+ if test no = "$compiler_c_o"; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+ lockfile=$output_obj.lock
else
output_obj=
need_locks=no
@@ -2145,12 +3508,12 @@ func_mode_compile ()
# Lock this critical section if it is needed
# We use this script file to make the link, it avoids creating a new file
- if test "$need_locks" = yes; then
+ if test yes = "$need_locks"; then
until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
func_echo "Waiting for $lockfile to be removed"
sleep 2
done
- elif test "$need_locks" = warn; then
+ elif test warn = "$need_locks"; then
if test -f "$lockfile"; then
$ECHO "\
*** ERROR, $lockfile exists and contains:
@@ -2158,7 +3521,7 @@ func_mode_compile ()
This indicates that another process is trying to use the same
temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
+your compiler does not support '-c' and '-o' together. If you
repeat this compilation, it may succeed, by chance, but you had better
avoid parallel builds (make -j) in this platform, or get a better
compiler."
@@ -2180,11 +3543,11 @@ compiler."
qsrcfile=$func_quote_for_eval_result
# Only build a PIC object if we are building libtool libraries.
- if test "$build_libtool_libs" = yes; then
+ if test yes = "$build_libtool_libs"; then
# Without this assignment, base_compile gets emptied.
fbsd_hideous_sh_bug=$base_compile
- if test "$pic_mode" != no; then
+ if test no != "$pic_mode"; then
command="$base_compile $qsrcfile $pic_flag"
else
# Don't build PIC code
@@ -2201,7 +3564,7 @@ compiler."
func_show_eval_locale "$command" \
'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
- if test "$need_locks" = warn &&
+ if test warn = "$need_locks" &&
test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
$ECHO "\
*** ERROR, $lockfile contains:
@@ -2212,7 +3575,7 @@ $srcfile
This indicates that another process is trying to use the same
temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
+your compiler does not support '-c' and '-o' together. If you
repeat this compilation, it may succeed, by chance, but you had better
avoid parallel builds (make -j) in this platform, or get a better
compiler."
@@ -2228,20 +3591,20 @@ compiler."
fi
# Allow error messages only from the first compilation.
- if test "$suppress_opt" = yes; then
+ if test yes = "$suppress_opt"; then
suppress_output=' >/dev/null 2>&1'
fi
fi
# Only build a position-dependent object if we build old libraries.
- if test "$build_old_libs" = yes; then
- if test "$pic_mode" != yes; then
+ if test yes = "$build_old_libs"; then
+ if test yes != "$pic_mode"; then
# Don't build PIC code
command="$base_compile $qsrcfile$pie_flag"
else
command="$base_compile $qsrcfile $pic_flag"
fi
- if test "$compiler_c_o" = yes; then
+ if test yes = "$compiler_c_o"; then
func_append command " -o $obj"
fi
@@ -2250,7 +3613,7 @@ compiler."
func_show_eval_locale "$command" \
'$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
- if test "$need_locks" = warn &&
+ if test warn = "$need_locks" &&
test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
$ECHO "\
*** ERROR, $lockfile contains:
@@ -2261,7 +3624,7 @@ $srcfile
This indicates that another process is trying to use the same
temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
+your compiler does not support '-c' and '-o' together. If you
repeat this compilation, it may succeed, by chance, but you had better
avoid parallel builds (make -j) in this platform, or get a better
compiler."
@@ -2281,7 +3644,7 @@ compiler."
func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
# Unlock the critical section if it was locked
- if test "$need_locks" != no; then
+ if test no != "$need_locks"; then
removelist=$lockfile
$RM "$lockfile"
fi
@@ -2291,7 +3654,7 @@ compiler."
}
$opt_help || {
- test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+ test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
}
func_mode_help ()
@@ -2311,7 +3674,7 @@ func_mode_help ()
Remove files from the build directory.
RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
to RM.
If FILE is a libtool library, object or program, all the files associated
@@ -2330,16 +3693,16 @@ This mode accepts the following additional options:
-no-suppress do not suppress compiler output for multiple passes
-prefer-pic try to build PIC objects only
-prefer-non-pic try to build non-PIC objects only
- -shared do not build a \`.o' file suitable for static linking
- -static only build a \`.o' file suitable for static linking
+ -shared do not build a '.o' file suitable for static linking
+ -static only build a '.o' file suitable for static linking
-Wc,FLAG pass FLAG directly to the compiler
-COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
from the given SOURCEFILE.
The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix \`.c' with the
-library object suffix, \`.lo'."
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
;;
execute)
@@ -2352,7 +3715,7 @@ This mode accepts the following additional options:
-dlopen FILE add the directory containing FILE to the library path
-This mode sets the library path environment variable according to \`-dlopen'
+This mode sets the library path environment variable according to '-dlopen'
flags.
If any of the ARGS are libtool executable wrappers, then they are translated
@@ -2371,7 +3734,7 @@ Complete the installation of libtool libraries.
Each LIBDIR is a directory that contains libtool libraries.
The commands that this mode executes may require superuser privileges. Use
-the \`--dry-run' option if you just want to see what would be executed."
+the '--dry-run' option if you just want to see what would be executed."
;;
install)
@@ -2381,7 +3744,7 @@ the \`--dry-run' option if you just want to see what would be executed."
Install executables or libraries.
INSTALL-COMMAND is the installation command. The first component should be
-either the \`install' or \`cp' program.
+either the 'install' or 'cp' program.
The following components of INSTALL-COMMAND are treated specially:
@@ -2407,7 +3770,7 @@ The following components of LINK-COMMAND are treated specially:
-avoid-version do not add a version suffix if possible
-bindir BINDIR specify path to binaries directory (for systems where
libraries must be found in the PATH setting at runtime)
- -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime
-dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
-export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
-export-symbols SYMFILE
@@ -2421,7 +3784,8 @@ The following components of LINK-COMMAND are treated specially:
-no-install link a not-installable executable
-no-undefined declare that a library does not refer to external symbols
-o OUTPUT-FILE create OUTPUT-FILE from the specified objects
- -objectlist FILE Use a list of object files found in FILE to specify objects
+ -objectlist FILE use a list of object files found in FILE to specify objects
+ -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes)
-precious-files-regex REGEX
don't remove output files matching REGEX
-release RELEASE specify package release information
@@ -2441,20 +3805,20 @@ The following components of LINK-COMMAND are treated specially:
-Xlinker FLAG pass linker-specific FLAG directly to the linker
-XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
-All other options (arguments beginning with \`-') are ignored.
+All other options (arguments beginning with '-') are ignored.
-Every other argument is treated as a filename. Files ending in \`.la' are
+Every other argument is treated as a filename. Files ending in '.la' are
treated as uninstalled libtool libraries, other files are standard or library
object files.
-If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
-only library objects (\`.lo' files) may be specified, and \`-rpath' is
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
required, except when creating a convenience library.
-If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
-using \`ar' and \`ranlib', or on Windows using \`lib'.
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
-If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
is created, otherwise an executable program is created."
;;
@@ -2465,7 +3829,7 @@ is created, otherwise an executable program is created."
Remove libraries from an installation directory.
RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
to RM.
If FILE is a libtool library, all the files associated with it are deleted.
@@ -2473,17 +3837,17 @@ Otherwise, only FILE itself is deleted using RM."
;;
*)
- func_fatal_help "invalid operation mode \`$opt_mode'"
+ func_fatal_help "invalid operation mode '$opt_mode'"
;;
esac
echo
- $ECHO "Try \`$progname --help' for more information about other modes."
+ $ECHO "Try '$progname --help' for more information about other modes."
}
# Now that we've collected a possible --mode arg, show help if necessary
if $opt_help; then
- if test "$opt_help" = :; then
+ if test : = "$opt_help"; then
func_mode_help
else
{
@@ -2491,7 +3855,7 @@ if $opt_help; then
for opt_mode in compile link execute install finish uninstall clean; do
func_mode_help
done
- } | sed -n '1p; 2,$s/^Usage:/ or: /p'
+ } | $SED -n '1p; 2,$s/^Usage:/ or: /p'
{
func_help noexit
for opt_mode in compile link execute install finish uninstall clean; do
@@ -2499,7 +3863,7 @@ if $opt_help; then
func_mode_help
done
} |
- sed '1d
+ $SED '1d
/^When reporting/,/^Report/{
H
d
@@ -2516,16 +3880,17 @@ fi
# func_mode_execute arg...
func_mode_execute ()
{
- $opt_debug
+ $debug_cmd
+
# The first argument is the command name.
- cmd="$nonopt"
+ cmd=$nonopt
test -z "$cmd" && \
func_fatal_help "you must specify a COMMAND"
# Handle -dlopen flags immediately.
for file in $opt_dlopen; do
test -f "$file" \
- || func_fatal_help "\`$file' is not a file"
+ || func_fatal_help "'$file' is not a file"
dir=
case $file in
@@ -2535,7 +3900,7 @@ func_mode_execute ()
# Check to see that this really is a libtool archive.
func_lalib_unsafe_p "$file" \
- || func_fatal_help "\`$lib' is not a valid libtool archive"
+ || func_fatal_help "'$lib' is not a valid libtool archive"
# Read the libtool library.
dlname=
@@ -2546,18 +3911,18 @@ func_mode_execute ()
if test -z "$dlname"; then
# Warn if it was a shared library.
test -n "$library_names" && \
- func_warning "\`$file' was not linked with \`-export-dynamic'"
+ func_warning "'$file' was not linked with '-export-dynamic'"
continue
fi
func_dirname "$file" "" "."
- dir="$func_dirname_result"
+ dir=$func_dirname_result
if test -f "$dir/$objdir/$dlname"; then
func_append dir "/$objdir"
else
if test ! -f "$dir/$dlname"; then
- func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+ func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
fi
fi
;;
@@ -2565,18 +3930,18 @@ func_mode_execute ()
*.lo)
# Just add the directory containing the .lo file.
func_dirname "$file" "" "."
- dir="$func_dirname_result"
+ dir=$func_dirname_result
;;
*)
- func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+ func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
continue
;;
esac
# Get the absolute pathname.
absdir=`cd "$dir" && pwd`
- test -n "$absdir" && dir="$absdir"
+ test -n "$absdir" && dir=$absdir
# Now add the directory to shlibpath_var.
if eval "test -z \"\$$shlibpath_var\""; then
@@ -2588,7 +3953,7 @@ func_mode_execute ()
# This variable tells wrapper scripts just to set shlibpath_var
# rather than running their programs.
- libtool_execute_magic="$magic"
+ libtool_execute_magic=$magic
# Check if any of the arguments is a wrapper script.
args=
@@ -2601,12 +3966,12 @@ func_mode_execute ()
if func_ltwrapper_script_p "$file"; then
func_source "$file"
# Transform arg to wrapped name.
- file="$progdir/$program"
+ file=$progdir/$program
elif func_ltwrapper_executable_p "$file"; then
func_ltwrapper_scriptname "$file"
func_source "$func_ltwrapper_scriptname_result"
# Transform arg to wrapped name.
- file="$progdir/$program"
+ file=$progdir/$program
fi
;;
esac
@@ -2614,7 +3979,15 @@ func_mode_execute ()
func_append_quoted args "$file"
done
- if test "X$opt_dry_run" = Xfalse; then
+ if $opt_dry_run; then
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ else
if test -n "$shlibpath_var"; then
# Export the shlibpath_var.
eval "export $shlibpath_var"
@@ -2631,25 +4004,18 @@ func_mode_execute ()
done
# Now prepare to actually exec the command.
- exec_cmd="\$cmd$args"
- else
- # Display what would be done.
- if test -n "$shlibpath_var"; then
- eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
- echo "export $shlibpath_var"
- fi
- $ECHO "$cmd$args"
- exit $EXIT_SUCCESS
+ exec_cmd=\$cmd$args
fi
}
-test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
# func_mode_finish arg...
func_mode_finish ()
{
- $opt_debug
+ $debug_cmd
+
libs=
libdirs=
admincmds=
@@ -2663,11 +4029,11 @@ func_mode_finish ()
if func_lalib_unsafe_p "$opt"; then
func_append libs " $opt"
else
- func_warning "\`$opt' is not a valid libtool archive"
+ func_warning "'$opt' is not a valid libtool archive"
fi
else
- func_fatal_error "invalid argument \`$opt'"
+ func_fatal_error "invalid argument '$opt'"
fi
done
@@ -2682,12 +4048,12 @@ func_mode_finish ()
# Remove sysroot references
if $opt_dry_run; then
for lib in $libs; do
- echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+ echo "removing references to $lt_sysroot and '=' prefixes from $lib"
done
else
tmpdir=`func_mktempdir`
for lib in $libs; do
- sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+ $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
> $tmpdir/tmp-la
mv -f $tmpdir/tmp-la $lib
done
@@ -2712,7 +4078,7 @@ func_mode_finish ()
fi
# Exit here if they wanted silent mode.
- $opt_silent && exit $EXIT_SUCCESS
+ $opt_quiet && exit $EXIT_SUCCESS
if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
echo "----------------------------------------------------------------------"
@@ -2723,27 +4089,27 @@ func_mode_finish ()
echo
echo "If you ever happen to want to link against installed libraries"
echo "in a given directory, LIBDIR, you must either use libtool, and"
- echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ echo "specify the full pathname of the library, or use the '-LLIBDIR'"
echo "flag during linking and do at least one of the following:"
if test -n "$shlibpath_var"; then
- echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " - add LIBDIR to the '$shlibpath_var' environment variable"
echo " during execution"
fi
if test -n "$runpath_var"; then
- echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " - add LIBDIR to the '$runpath_var' environment variable"
echo " during linking"
fi
if test -n "$hardcode_libdir_flag_spec"; then
libdir=LIBDIR
eval flag=\"$hardcode_libdir_flag_spec\"
- $ECHO " - use the \`$flag' linker flag"
+ $ECHO " - use the '$flag' linker flag"
fi
if test -n "$admincmds"; then
$ECHO " - have your system administrator run these commands:$admincmds"
fi
if test -f /etc/ld.so.conf; then
- echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
fi
echo
@@ -2762,18 +4128,20 @@ func_mode_finish ()
exit $EXIT_SUCCESS
}
-test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
# func_mode_install arg...
func_mode_install ()
{
- $opt_debug
+ $debug_cmd
+
# There may be an optional sh(1) argument at the beginning of
# install_prog (especially on Windows NT).
- if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
# Allow the use of GNU shtool's install command.
- case $nonopt in *shtool*) :;; *) false;; esac; then
+ case $nonopt in *shtool*) :;; *) false;; esac
+ then
# Aesthetically quote it.
func_quote_for_eval "$nonopt"
install_prog="$func_quote_for_eval_result "
@@ -2800,7 +4168,7 @@ func_mode_install ()
opts=
prev=
install_type=
- isdir=no
+ isdir=false
stripme=
no_mode=:
for arg
@@ -2813,7 +4181,7 @@ func_mode_install ()
fi
case $arg in
- -d) isdir=yes ;;
+ -d) isdir=: ;;
-f)
if $install_cp; then :; else
prev=$arg
@@ -2831,7 +4199,7 @@ func_mode_install ()
*)
# If the previous option needed an argument, then skip it.
if test -n "$prev"; then
- if test "x$prev" = x-m && test -n "$install_override_mode"; then
+ if test X-m = "X$prev" && test -n "$install_override_mode"; then
arg2=$install_override_mode
no_mode=false
fi
@@ -2856,7 +4224,7 @@ func_mode_install ()
func_fatal_help "you must specify an install program"
test -n "$prev" && \
- func_fatal_help "the \`$prev' option requires an argument"
+ func_fatal_help "the '$prev' option requires an argument"
if test -n "$install_override_mode" && $no_mode; then
if $install_cp; then :; else
@@ -2878,19 +4246,19 @@ func_mode_install ()
dest=$func_stripname_result
# Check to see that the destination is a directory.
- test -d "$dest" && isdir=yes
- if test "$isdir" = yes; then
- destdir="$dest"
+ test -d "$dest" && isdir=:
+ if $isdir; then
+ destdir=$dest
destname=
else
func_dirname_and_basename "$dest" "" "."
- destdir="$func_dirname_result"
- destname="$func_basename_result"
+ destdir=$func_dirname_result
+ destname=$func_basename_result
# Not a directory, so check to see that there is only one file specified.
set dummy $files; shift
test "$#" -gt 1 && \
- func_fatal_help "\`$dest' is not a directory"
+ func_fatal_help "'$dest' is not a directory"
fi
case $destdir in
[\\/]* | [A-Za-z]:[\\/]*) ;;
@@ -2899,7 +4267,7 @@ func_mode_install ()
case $file in
*.lo) ;;
*)
- func_fatal_help "\`$destdir' must be an absolute directory name"
+ func_fatal_help "'$destdir' must be an absolute directory name"
;;
esac
done
@@ -2908,7 +4276,7 @@ func_mode_install ()
# This variable tells wrapper scripts just to set variables rather
# than running their programs.
- libtool_install_magic="$magic"
+ libtool_install_magic=$magic
staticlibs=
future_libdirs=
@@ -2928,7 +4296,7 @@ func_mode_install ()
# Check to see that this really is a libtool archive.
func_lalib_unsafe_p "$file" \
- || func_fatal_help "\`$file' is not a valid libtool archive"
+ || func_fatal_help "'$file' is not a valid libtool archive"
library_names=
old_library=
@@ -2950,7 +4318,7 @@ func_mode_install ()
fi
func_dirname "$file" "/" ""
- dir="$func_dirname_result"
+ dir=$func_dirname_result
func_append dir "$objdir"
if test -n "$relink_command"; then
@@ -2964,7 +4332,7 @@ func_mode_install ()
# are installed into $libdir/../bin (currently, that works fine)
# but it's something to keep an eye on.
test "$inst_prefix_dir" = "$destdir" && \
- func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
if test -n "$inst_prefix_dir"; then
# Stick the inst_prefix_dir data into the link command.
@@ -2973,29 +4341,36 @@ func_mode_install ()
relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
fi
- func_warning "relinking \`$file'"
+ func_warning "relinking '$file'"
func_show_eval "$relink_command" \
- 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
fi
# See the names of the shared library.
set dummy $library_names; shift
if test -n "$1"; then
- realname="$1"
+ realname=$1
shift
- srcname="$realname"
- test -n "$relink_command" && srcname="$realname"T
+ srcname=$realname
+ test -n "$relink_command" && srcname=${realname}T
# Install the shared library and build the symlinks.
func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
'exit $?'
- tstripme="$stripme"
+ tstripme=$stripme
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
case $realname in
*.dll.a)
- tstripme=""
+ tstripme=
+ ;;
+ esac
+ ;;
+ os2*)
+ case $realname in
+ *_dll.a)
+ tstripme=
;;
esac
;;
@@ -3006,7 +4381,7 @@ func_mode_install ()
if test "$#" -gt 0; then
# Delete the old symlinks, and create new ones.
- # Try `ln -sf' first, because the `ln' binary might depend on
+ # Try 'ln -sf' first, because the 'ln' binary might depend on
# the symlink we replace! Solaris /bin/ln does not understand -f,
# so we also need to try rm && ln -s.
for linkname
@@ -3017,14 +4392,14 @@ func_mode_install ()
fi
# Do each command in the postinstall commands.
- lib="$destdir/$realname"
+ lib=$destdir/$realname
func_execute_cmds "$postinstall_cmds" 'exit $?'
fi
# Install the pseudo-library for information purposes.
func_basename "$file"
- name="$func_basename_result"
- instname="$dir/$name"i
+ name=$func_basename_result
+ instname=$dir/${name}i
func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
# Maybe install the static library, too.
@@ -3036,11 +4411,11 @@ func_mode_install ()
# Figure out destination file name, if it wasn't already specified.
if test -n "$destname"; then
- destfile="$destdir/$destname"
+ destfile=$destdir/$destname
else
func_basename "$file"
- destfile="$func_basename_result"
- destfile="$destdir/$destfile"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
fi
# Deduce the name of the destination old-style object file.
@@ -3050,11 +4425,11 @@ func_mode_install ()
staticdest=$func_lo2o_result
;;
*.$objext)
- staticdest="$destfile"
+ staticdest=$destfile
destfile=
;;
*)
- func_fatal_help "cannot copy a libtool object to \`$destfile'"
+ func_fatal_help "cannot copy a libtool object to '$destfile'"
;;
esac
@@ -3063,7 +4438,7 @@ func_mode_install ()
func_show_eval "$install_prog $file $destfile" 'exit $?'
# Install the old object if enabled.
- if test "$build_old_libs" = yes; then
+ if test yes = "$build_old_libs"; then
# Deduce the name of the old-style object file.
func_lo2o "$file"
staticobj=$func_lo2o_result
@@ -3075,23 +4450,23 @@ func_mode_install ()
*)
# Figure out destination file name, if it wasn't already specified.
if test -n "$destname"; then
- destfile="$destdir/$destname"
+ destfile=$destdir/$destname
else
func_basename "$file"
- destfile="$func_basename_result"
- destfile="$destdir/$destfile"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
fi
# If the file is missing, and there is a .exe on the end, strip it
# because it is most likely a libtool script we actually want to
# install
- stripped_ext=""
+ stripped_ext=
case $file in
*.exe)
if test ! -f "$file"; then
func_stripname '' '.exe' "$file"
file=$func_stripname_result
- stripped_ext=".exe"
+ stripped_ext=.exe
fi
;;
esac
@@ -3119,19 +4494,19 @@ func_mode_install ()
# Check the variables that should have been set.
test -z "$generated_by_libtool_version" && \
- func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+ func_fatal_error "invalid libtool wrapper script '$wrapper'"
- finalize=yes
+ finalize=:
for lib in $notinst_deplibs; do
# Check to see that each library is installed.
libdir=
if test -f "$lib"; then
func_source "$lib"
fi
- libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
if test -n "$libdir" && test ! -f "$libfile"; then
- func_warning "\`$lib' has not been installed in \`$libdir'"
- finalize=no
+ func_warning "'$lib' has not been installed in '$libdir'"
+ finalize=false
fi
done
@@ -3139,29 +4514,29 @@ func_mode_install ()
func_source "$wrapper"
outputname=
- if test "$fast_install" = no && test -n "$relink_command"; then
+ if test no = "$fast_install" && test -n "$relink_command"; then
$opt_dry_run || {
- if test "$finalize" = yes; then
+ if $finalize; then
tmpdir=`func_mktempdir`
func_basename "$file$stripped_ext"
- file="$func_basename_result"
- outputname="$tmpdir/$file"
+ file=$func_basename_result
+ outputname=$tmpdir/$file
# Replace the output file specification.
relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
- $opt_silent || {
+ $opt_quiet || {
func_quote_for_expand "$relink_command"
eval "func_echo $func_quote_for_expand_result"
}
if eval "$relink_command"; then :
else
- func_error "error: relink \`$file' with the above command before installing it"
+ func_error "error: relink '$file' with the above command before installing it"
$opt_dry_run || ${RM}r "$tmpdir"
continue
fi
- file="$outputname"
+ file=$outputname
else
- func_warning "cannot relink \`$file'"
+ func_warning "cannot relink '$file'"
fi
}
else
@@ -3198,10 +4573,10 @@ func_mode_install ()
for file in $staticlibs; do
func_basename "$file"
- name="$func_basename_result"
+ name=$func_basename_result
# Set up the ranlib parameters.
- oldlib="$destdir/$name"
+ oldlib=$destdir/$name
func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
tool_oldlib=$func_to_tool_file_result
@@ -3216,18 +4591,18 @@ func_mode_install ()
done
test -n "$future_libdirs" && \
- func_warning "remember to run \`$progname --finish$future_libdirs'"
+ func_warning "remember to run '$progname --finish$future_libdirs'"
if test -n "$current_libdirs"; then
# Maybe just do a dry run.
$opt_dry_run && current_libdirs=" -n$current_libdirs"
- exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
else
exit $EXIT_SUCCESS
fi
}
-test "$opt_mode" = install && func_mode_install ${1+"$@"}
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
# func_generate_dlsyms outputname originator pic_p
@@ -3235,16 +4610,17 @@ test "$opt_mode" = install && func_mode_install ${1+"$@"}
# a dlpreopen symbol table.
func_generate_dlsyms ()
{
- $opt_debug
- my_outputname="$1"
- my_originator="$2"
- my_pic_p="${3-no}"
- my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+ $debug_cmd
+
+ my_outputname=$1
+ my_originator=$2
+ my_pic_p=${3-false}
+ my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
my_dlsyms=
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
if test -n "$NM" && test -n "$global_symbol_pipe"; then
- my_dlsyms="${my_outputname}S.c"
+ my_dlsyms=${my_outputname}S.c
else
func_error "not configured to extract global symbols from dlpreopened files"
fi
@@ -3255,7 +4631,7 @@ func_generate_dlsyms ()
"") ;;
*.c)
# Discover the nlist of each of the dlfiles.
- nlist="$output_objdir/${my_outputname}.nm"
+ nlist=$output_objdir/$my_outputname.nm
func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
@@ -3263,34 +4639,36 @@ func_generate_dlsyms ()
func_verbose "creating $output_objdir/$my_dlsyms"
$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
-/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
-/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
#ifdef __cplusplus
extern \"C\" {
#endif
-#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
#endif
/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
relocations are performed -- see ld's documentation on pseudo-relocs. */
# define LT_DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
/* This system does not cope well with relocations in const data. */
# define LT_DLSYM_CONST
#else
# define LT_DLSYM_CONST const
#endif
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
/* External symbol declarations for the compiler. */\
"
- if test "$dlself" = yes; then
- func_verbose "generating symbol list for \`$output'"
+ if test yes = "$dlself"; then
+ func_verbose "generating symbol list for '$output'"
$opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
@@ -3298,7 +4676,7 @@ extern \"C\" {
progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
for progfile in $progfiles; do
func_to_tool_file "$progfile" func_convert_file_msys_to_w32
- func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+ func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
$opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
done
@@ -3318,10 +4696,10 @@ extern \"C\" {
# Prepare the list of exported symbols
if test -z "$export_symbols"; then
- export_symbols="$output_objdir/$outputname.exp"
+ export_symbols=$output_objdir/$outputname.exp
$opt_dry_run || {
$RM $export_symbols
- eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
case $host in
*cygwin* | *mingw* | *cegcc* )
eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
@@ -3331,7 +4709,7 @@ extern \"C\" {
}
else
$opt_dry_run || {
- eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
eval '$MV "$nlist"T "$nlist"'
case $host in
@@ -3345,22 +4723,22 @@ extern \"C\" {
fi
for dlprefile in $dlprefiles; do
- func_verbose "extracting global C symbols from \`$dlprefile'"
+ func_verbose "extracting global C symbols from '$dlprefile'"
func_basename "$dlprefile"
- name="$func_basename_result"
+ name=$func_basename_result
case $host in
*cygwin* | *mingw* | *cegcc* )
# if an import library, we need to obtain dlname
if func_win32_import_lib_p "$dlprefile"; then
func_tr_sh "$dlprefile"
eval "curr_lafile=\$libfile_$func_tr_sh_result"
- dlprefile_dlbasename=""
+ dlprefile_dlbasename=
if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
# Use subshell, to avoid clobbering current variable values
dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
- if test -n "$dlprefile_dlname" ; then
+ if test -n "$dlprefile_dlname"; then
func_basename "$dlprefile_dlname"
- dlprefile_dlbasename="$func_basename_result"
+ dlprefile_dlbasename=$func_basename_result
else
# no lafile. user explicitly requested -dlpreopen <import library>.
$sharedlib_from_linklib_cmd "$dlprefile"
@@ -3368,7 +4746,7 @@ extern \"C\" {
fi
fi
$opt_dry_run || {
- if test -n "$dlprefile_dlbasename" ; then
+ if test -n "$dlprefile_dlbasename"; then
eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
else
func_warning "Could not compute DLL name from $name"
@@ -3424,6 +4802,11 @@ extern \"C\" {
echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
fi
+ func_show_eval '$RM "${nlist}I"'
+ if test -n "$global_symbol_to_import"; then
+ eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+ fi
+
echo >> "$output_objdir/$my_dlsyms" "\
/* The mapping between symbol names and symbols. */
@@ -3432,11 +4815,30 @@ typedef struct {
void *address;
} lt_dlsymlist;
extern LT_DLSYM_CONST lt_dlsymlist
-lt_${my_prefix}_LTX_preloaded_symbols[];
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+ LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+ for (; symbol->name; ++symbol)
+ {"
+ $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+ echo >> "$output_objdir/$my_dlsyms" "\
+ }
+}"
+ fi
+ echo >> "$output_objdir/$my_dlsyms" "\
LT_DLSYM_CONST lt_dlsymlist
lt_${my_prefix}_LTX_preloaded_symbols[] =
-{\
- { \"$my_originator\", (void *) 0 },"
+{ {\"$my_originator\", (void *) 0},"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {\"@INIT@\", (void *) &lt_syminit},"
+ fi
case $need_lib_prefix in
no)
@@ -3478,9 +4880,7 @@ static const void *lt_preloaded_setup() {
*-*-hpux*)
pic_flag_for_symtable=" $pic_flag" ;;
*)
- if test "X$my_pic_p" != Xno; then
- pic_flag_for_symtable=" $pic_flag"
- fi
+ $my_pic_p && pic_flag_for_symtable=" $pic_flag"
;;
esac
;;
@@ -3497,10 +4897,10 @@ static const void *lt_preloaded_setup() {
func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
# Clean up the generated files.
- func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
# Transform the symbol file into the correct name.
- symfileobj="$output_objdir/${my_outputname}S.$objext"
+ symfileobj=$output_objdir/${my_outputname}S.$objext
case $host in
*cygwin* | *mingw* | *cegcc* )
if test -f "$output_objdir/$my_outputname.def"; then
@@ -3518,7 +4918,7 @@ static const void *lt_preloaded_setup() {
esac
;;
*)
- func_fatal_error "unknown suffix for \`$my_dlsyms'"
+ func_fatal_error "unknown suffix for '$my_dlsyms'"
;;
esac
else
@@ -3532,6 +4932,32 @@ static const void *lt_preloaded_setup() {
fi
}
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+ test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+ test -n "$func_cygming_ms_implib_tmp"
+}
+
# func_win32_libid arg
# return the library type of file 'arg'
#
@@ -3541,8 +4967,9 @@ static const void *lt_preloaded_setup() {
# Despite the name, also deal with 64 bit binaries.
func_win32_libid ()
{
- $opt_debug
- win32_libid_type="unknown"
+ $debug_cmd
+
+ win32_libid_type=unknown
win32_fileres=`file -L $1 2>/dev/null`
case $win32_fileres in
*ar\ archive\ import\ library*) # definitely import
@@ -3552,16 +4979,29 @@ func_win32_libid ()
# Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
$EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
- func_to_tool_file "$1" func_convert_file_msys_to_w32
- win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
- $SED -n -e '
+ case $nm_interface in
+ "MS dumpbin")
+ if func_cygming_ms_implib_p "$1" ||
+ func_cygming_gnu_implib_p "$1"
+ then
+ win32_nmres=import
+ else
+ win32_nmres=
+ fi
+ ;;
+ *)
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+ $SED -n -e '
1,100{
/ I /{
- s,.*,import,
+ s|.*|import|
p
q
}
}'`
+ ;;
+ esac
case $win32_nmres in
import*) win32_libid_type="x86 archive import";;
*) win32_libid_type="x86 archive static";;
@@ -3593,7 +5033,8 @@ func_win32_libid ()
# $sharedlib_from_linklib_result
func_cygming_dll_for_implib ()
{
- $opt_debug
+ $debug_cmd
+
sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
}
@@ -3610,7 +5051,8 @@ func_cygming_dll_for_implib ()
# specified import library.
func_cygming_dll_for_implib_fallback_core ()
{
- $opt_debug
+ $debug_cmd
+
match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
$OBJDUMP -s --section "$1" "$2" 2>/dev/null |
$SED '/^Contents of section '"$match_literal"':/{
@@ -3646,8 +5088,8 @@ func_cygming_dll_for_implib_fallback_core ()
/./p' |
# we now have a list, one entry per line, of the stringified
# contents of the appropriate section of all members of the
- # archive which possess that section. Heuristic: eliminate
- # all those which have a first or second character that is
+ # archive that possess that section. Heuristic: eliminate
+ # all those that have a first or second character that is
# a '.' (that is, objdump's representation of an unprintable
# character.) This should work for all archives with less than
# 0x302f exports -- but will fail for DLLs whose name actually
@@ -3658,30 +5100,6 @@ func_cygming_dll_for_implib_fallback_core ()
$SED -e '/^\./d;/^.\./d;q'
}
-# func_cygming_gnu_implib_p ARG
-# This predicate returns with zero status (TRUE) if
-# ARG is a GNU/binutils-style import library. Returns
-# with nonzero status (FALSE) otherwise.
-func_cygming_gnu_implib_p ()
-{
- $opt_debug
- func_to_tool_file "$1" func_convert_file_msys_to_w32
- func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
- test -n "$func_cygming_gnu_implib_tmp"
-}
-
-# func_cygming_ms_implib_p ARG
-# This predicate returns with zero status (TRUE) if
-# ARG is an MS-style import library. Returns
-# with nonzero status (FALSE) otherwise.
-func_cygming_ms_implib_p ()
-{
- $opt_debug
- func_to_tool_file "$1" func_convert_file_msys_to_w32
- func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
- test -n "$func_cygming_ms_implib_tmp"
-}
-
# func_cygming_dll_for_implib_fallback ARG
# Platform-specific function to extract the
# name of the DLL associated with the specified
@@ -3695,16 +5113,17 @@ func_cygming_ms_implib_p ()
# $sharedlib_from_linklib_result
func_cygming_dll_for_implib_fallback ()
{
- $opt_debug
- if func_cygming_gnu_implib_p "$1" ; then
+ $debug_cmd
+
+ if func_cygming_gnu_implib_p "$1"; then
# binutils import library
sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
- elif func_cygming_ms_implib_p "$1" ; then
+ elif func_cygming_ms_implib_p "$1"; then
# ms-generated import library
sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
else
# unknown
- sharedlib_from_linklib_result=""
+ sharedlib_from_linklib_result=
fi
}
@@ -3712,10 +5131,11 @@ func_cygming_dll_for_implib_fallback ()
# func_extract_an_archive dir oldlib
func_extract_an_archive ()
{
- $opt_debug
- f_ex_an_ar_dir="$1"; shift
- f_ex_an_ar_oldlib="$1"
- if test "$lock_old_archive_extraction" = yes; then
+ $debug_cmd
+
+ f_ex_an_ar_dir=$1; shift
+ f_ex_an_ar_oldlib=$1
+ if test yes = "$lock_old_archive_extraction"; then
lockfile=$f_ex_an_ar_oldlib.lock
until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
func_echo "Waiting for $lockfile to be removed"
@@ -3724,7 +5144,7 @@ func_extract_an_archive ()
fi
func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
'stat=$?; rm -f "$lockfile"; exit $stat'
- if test "$lock_old_archive_extraction" = yes; then
+ if test yes = "$lock_old_archive_extraction"; then
$opt_dry_run || rm -f "$lockfile"
fi
if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
@@ -3738,22 +5158,23 @@ func_extract_an_archive ()
# func_extract_archives gentop oldlib ...
func_extract_archives ()
{
- $opt_debug
- my_gentop="$1"; shift
+ $debug_cmd
+
+ my_gentop=$1; shift
my_oldlibs=${1+"$@"}
- my_oldobjs=""
- my_xlib=""
- my_xabs=""
- my_xdir=""
+ my_oldobjs=
+ my_xlib=
+ my_xabs=
+ my_xdir=
for my_xlib in $my_oldlibs; do
# Extract the objects.
case $my_xlib in
- [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
*) my_xabs=`pwd`"/$my_xlib" ;;
esac
func_basename "$my_xlib"
- my_xlib="$func_basename_result"
+ my_xlib=$func_basename_result
my_xlib_u=$my_xlib
while :; do
case " $extracted_archives " in
@@ -3765,7 +5186,7 @@ func_extract_archives ()
esac
done
extracted_archives="$extracted_archives $my_xlib_u"
- my_xdir="$my_gentop/$my_xlib_u"
+ my_xdir=$my_gentop/$my_xlib_u
func_mkdir_p "$my_xdir"
@@ -3778,22 +5199,23 @@ func_extract_archives ()
cd $my_xdir || exit $?
darwin_archive=$my_xabs
darwin_curdir=`pwd`
- darwin_base_archive=`basename "$darwin_archive"`
+ func_basename "$darwin_archive"
+ darwin_base_archive=$func_basename_result
darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
if test -n "$darwin_arches"; then
darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
darwin_arch=
func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
- for darwin_arch in $darwin_arches ; do
- func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
- $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
- cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
- func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ for darwin_arch in $darwin_arches; do
+ func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+ $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+ cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+ func_extract_an_archive "`pwd`" "$darwin_base_archive"
cd "$darwin_curdir"
- $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
done # $darwin_arches
## Okay now we've a bunch of thin objects, gotta fatten them up :)
- darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
darwin_file=
darwin_files=
for darwin_file in $darwin_filelist; do
@@ -3815,7 +5237,7 @@ func_extract_archives ()
my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
done
- func_extract_archives_result="$my_oldobjs"
+ func_extract_archives_result=$my_oldobjs
}
@@ -3830,7 +5252,7 @@ func_extract_archives ()
#
# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
# variable will take. If 'yes', then the emitted script
-# will assume that the directory in which it is stored is
+# will assume that the directory where it is stored is
# the $objdir directory. This is a cygwin/mingw-specific
# behavior.
func_emit_wrapper ()
@@ -3841,7 +5263,7 @@ func_emit_wrapper ()
#! $SHELL
# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
#
# The $output program cannot be directly executed until all the libtool
# libraries that it depends on are installed.
@@ -3883,7 +5305,8 @@ else
if test \"\$libtool_execute_magic\" != \"$magic\"; then
file=\"\$0\""
- qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ func_quote "$ECHO"
+ qECHO=$func_quote_result
$ECHO "\
# A function that is used when there is no print builtin or printf.
@@ -3898,9 +5321,9 @@ _LTECHO_EOF'
# Very basic option parsing. These options are (a) specific to
# the libtool wrapper, (b) are identical between the wrapper
-# /script/ and the wrapper /executable/ which is used only on
+# /script/ and the wrapper /executable/ that is used only on
# windows platforms, and (c) all begin with the string "--lt-"
-# (application programs are unlikely to have options which match
+# (application programs are unlikely to have options that match
# this pattern).
#
# There are only two supported options: --lt-debug and
@@ -3933,7 +5356,7 @@ func_parse_lt_options ()
# Print the debug banner immediately:
if test -n \"\$lt_option_debug\"; then
- echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+ echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
fi
}
@@ -3944,7 +5367,7 @@ func_lt_dump_args ()
lt_dump_args_N=1;
for lt_arg
do
- \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
done
}
@@ -3958,7 +5381,7 @@ func_exec_program_core ()
*-*-mingw | *-*-os2* | *-cegcc*)
$ECHO "\
if test -n \"\$lt_option_debug\"; then
- \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
func_lt_dump_args \${1+\"\$@\"} 1>&2
fi
exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
@@ -3968,7 +5391,7 @@ func_exec_program_core ()
*)
$ECHO "\
if test -n \"\$lt_option_debug\"; then
- \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
func_lt_dump_args \${1+\"\$@\"} 1>&2
fi
exec \"\$progdir/\$program\" \${1+\"\$@\"}
@@ -4043,13 +5466,13 @@ func_exec_program ()
test -n \"\$absdir\" && thisdir=\"\$absdir\"
"
- if test "$fast_install" = yes; then
+ if test yes = "$fast_install"; then
$ECHO "\
program=lt-'$outputname'$exeext
progdir=\"\$thisdir/$objdir\"
if test ! -f \"\$progdir/\$program\" ||
- { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
test \"X\$file\" != \"X\$progdir/\$program\"; }; then
file=\"\$\$-\$program\"
@@ -4066,7 +5489,7 @@ func_exec_program ()
if test -n \"\$relink_command\"; then
if relink_command_output=\`eval \$relink_command 2>&1\`; then :
else
- $ECHO \"\$relink_command_output\" >&2
+ \$ECHO \"\$relink_command_output\" >&2
$RM \"\$progdir/\$file\"
exit 1
fi
@@ -4101,7 +5524,7 @@ func_exec_program ()
fi
# Export our shlibpath_var if we have one.
- if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
$ECHO "\
# Add our own library path to $shlibpath_var
$shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
@@ -4121,7 +5544,7 @@ func_exec_program ()
fi
else
# The program doesn't exist.
- \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
\$ECHO \"This script is just a wrapper for \$program.\" 1>&2
\$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
exit 1
@@ -4140,7 +5563,7 @@ func_emit_cwrapperexe_src ()
cat <<EOF
/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
- Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+ Generated by $PROGRAM (GNU $PACKAGE) $VERSION
The $output program cannot be directly executed until all the libtool
libraries that it depends on are installed.
@@ -4175,47 +5598,45 @@ EOF
#include <fcntl.h>
#include <sys/stat.h>
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
/* declarations of non-ANSI functions */
-#if defined(__MINGW32__)
+#if defined __MINGW32__
# ifdef __STRICT_ANSI__
int _putenv (const char *);
# endif
-#elif defined(__CYGWIN__)
+#elif defined __CYGWIN__
# ifdef __STRICT_ANSI__
char *realpath (const char *, char *);
int putenv (char *);
int setenv (const char *, const char *, int);
# endif
-/* #elif defined (other platforms) ... */
+/* #elif defined other_platform || defined ... */
#endif
/* portability defines, excluding path handling macros */
-#if defined(_MSC_VER)
+#if defined _MSC_VER
# define setmode _setmode
# define stat _stat
# define chmod _chmod
# define getcwd _getcwd
# define putenv _putenv
# define S_IXUSR _S_IEXEC
-# ifndef _INTPTR_T_DEFINED
-# define _INTPTR_T_DEFINED
-# define intptr_t int
-# endif
-#elif defined(__MINGW32__)
+#elif defined __MINGW32__
# define setmode _setmode
# define stat _stat
# define chmod _chmod
# define getcwd _getcwd
# define putenv _putenv
-#elif defined(__CYGWIN__)
+#elif defined __CYGWIN__
# define HAVE_SETENV
# define FOPEN_WB "wb"
-/* #elif defined (other platforms) ... */
+/* #elif defined other platforms ... */
#endif
-#if defined(PATH_MAX)
+#if defined PATH_MAX
# define LT_PATHMAX PATH_MAX
-#elif defined(MAXPATHLEN)
+#elif defined MAXPATHLEN
# define LT_PATHMAX MAXPATHLEN
#else
# define LT_PATHMAX 1024
@@ -4234,8 +5655,8 @@ int setenv (const char *, const char *, int);
# define PATH_SEPARATOR ':'
#endif
-#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
- defined (__OS2__)
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+ defined __OS2__
# define HAVE_DOS_BASED_FILE_SYSTEM
# define FOPEN_WB "wb"
# ifndef DIR_SEPARATOR_2
@@ -4268,10 +5689,10 @@ int setenv (const char *, const char *, int);
#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
#define XFREE(stale) do { \
- if (stale) { free ((void *) stale); stale = 0; } \
+ if (stale) { free (stale); stale = 0; } \
} while (0)
-#if defined(LT_DEBUGWRAPPER)
+#if defined LT_DEBUGWRAPPER
static int lt_debug = 1;
#else
static int lt_debug = 0;
@@ -4300,11 +5721,16 @@ void lt_dump_script (FILE *f);
EOF
cat <<EOF
-volatile const char * MAGIC_EXE = "$magic_exe";
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
const char * LIB_PATH_VARNAME = "$shlibpath_var";
EOF
- if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
func_to_host_path "$temp_rpath"
cat <<EOF
const char * LIB_PATH_VALUE = "$func_to_host_path_result";
@@ -4328,7 +5754,7 @@ const char * EXE_PATH_VALUE = "";
EOF
fi
- if test "$fast_install" = yes; then
+ if test yes = "$fast_install"; then
cat <<EOF
const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
EOF
@@ -4357,12 +5783,12 @@ main (int argc, char *argv[])
char *actual_cwrapper_name;
char *target_name;
char *lt_argv_zero;
- intptr_t rval = 127;
+ int rval = 127;
int i;
program_name = (char *) xstrdup (base_name (argv[0]));
- newargz = XMALLOC (char *, argc + 1);
+ newargz = XMALLOC (char *, (size_t) argc + 1);
/* very simple arg parsing; don't want to rely on getopt
* also, copy all non cwrapper options to newargz, except
@@ -4371,10 +5797,10 @@ main (int argc, char *argv[])
newargc=0;
for (i = 1; i < argc; i++)
{
- if (strcmp (argv[i], dumpscript_opt) == 0)
+ if (STREQ (argv[i], dumpscript_opt))
{
EOF
- case "$host" in
+ case $host in
*mingw* | *cygwin* )
# make stdout use "unix" line endings
echo " setmode(1,_O_BINARY);"
@@ -4385,12 +5811,12 @@ EOF
lt_dump_script (stdout);
return 0;
}
- if (strcmp (argv[i], debug_opt) == 0)
+ if (STREQ (argv[i], debug_opt))
{
lt_debug = 1;
continue;
}
- if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+ if (STREQ (argv[i], ltwrapper_option_prefix))
{
/* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
namespace, but it is not one of the ones we know about and
@@ -4413,7 +5839,7 @@ EOF
EOF
cat <<EOF
/* The GNU banner must be the first non-error debug message */
- lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
EOF
cat <<"EOF"
lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
@@ -4524,7 +5950,7 @@ EOF
cat <<"EOF"
/* execv doesn't actually work on mingw as expected on unix */
newargz = prepare_spawn (newargz);
- rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
if (rval == -1)
{
/* failed to start process */
@@ -4569,7 +5995,7 @@ base_name (const char *name)
{
const char *base;
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
/* Skip over the disk name in MSDOS pathnames. */
if (isalpha ((unsigned char) name[0]) && name[1] == ':')
name += 2;
@@ -4628,7 +6054,7 @@ find_executable (const char *wrapper)
const char *p_next;
/* static buffer for getcwd */
char tmp[LT_PATHMAX + 1];
- int tmp_len;
+ size_t tmp_len;
char *concat_name;
lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
@@ -4638,7 +6064,7 @@ find_executable (const char *wrapper)
return NULL;
/* Absolute path? */
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
{
concat_name = xstrdup (wrapper);
@@ -4656,7 +6082,7 @@ find_executable (const char *wrapper)
return concat_name;
XFREE (concat_name);
}
-#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
}
#endif
@@ -4679,7 +6105,7 @@ find_executable (const char *wrapper)
for (q = p; *q; q++)
if (IS_PATH_SEPARATOR (*q))
break;
- p_len = q - p;
+ p_len = (size_t) (q - p);
p_next = (*q == '\0' ? q : q + 1);
if (p_len == 0)
{
@@ -4798,7 +6224,7 @@ strendzap (char *str, const char *pat)
if (patlen <= len)
{
str += len - patlen;
- if (strcmp (str, pat) == 0)
+ if (STREQ (str, pat))
*str = '\0';
}
return str;
@@ -4863,7 +6289,7 @@ lt_setenv (const char *name, const char *value)
char *str = xstrdup (value);
setenv (name, str, 1);
#else
- int len = strlen (name) + 1 + strlen (value) + 1;
+ size_t len = strlen (name) + 1 + strlen (value) + 1;
char *str = XMALLOC (char, len);
sprintf (str, "%s=%s", name, value);
if (putenv (str) != EXIT_SUCCESS)
@@ -4880,8 +6306,8 @@ lt_extend_str (const char *orig_value, const char *add, int to_end)
char *new_value;
if (orig_value && *orig_value)
{
- int orig_value_len = strlen (orig_value);
- int add_len = strlen (add);
+ size_t orig_value_len = strlen (orig_value);
+ size_t add_len = strlen (add);
new_value = XMALLOC (char, add_len + orig_value_len + 1);
if (to_end)
{
@@ -4912,10 +6338,10 @@ lt_update_exe_path (const char *name, const char *value)
{
char *new_value = lt_extend_str (getenv (name), value, 0);
/* some systems can't cope with a ':'-terminated path #' */
- int len = strlen (new_value);
- while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ size_t len = strlen (new_value);
+ while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
{
- new_value[len-1] = '\0';
+ new_value[--len] = '\0';
}
lt_setenv (name, new_value);
XFREE (new_value);
@@ -5082,27 +6508,47 @@ EOF
# True if ARG is an import lib, as indicated by $file_magic_cmd
func_win32_import_lib_p ()
{
- $opt_debug
+ $debug_cmd
+
case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
*import*) : ;;
*) false ;;
esac
}
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+ $debug_cmd
+
+ case " $compile_command " in
+ *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+ suncc_use_cstd_abi=no
+ ;;
+ *)
+ suncc_use_cstd_abi=yes
+ ;;
+ esac
+}
+
# func_mode_link arg...
func_mode_link ()
{
- $opt_debug
+ $debug_cmd
+
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
# It is impossible to link a dll without this setting, and
# we shouldn't force the makefile maintainer to figure out
- # which system we are compiling for in order to pass an extra
+ # what system we are compiling for in order to pass an extra
# flag for every libtool invocation.
# allow_undefined=no
# FIXME: Unfortunately, there are problems with the above when trying
- # to make a dll which has undefined symbols, in which case not
+ # to make a dll that has undefined symbols, in which case not
# even a static library is built. For now, we need to specify
# -no-undefined on the libtool link line when we can be certain
# that all symbols are satisfied, otherwise we get a static library.
@@ -5146,10 +6592,11 @@ func_mode_link ()
module=no
no_install=no
objs=
+ os2dllname=
non_pic_objects=
precious_files_regex=
prefer_static_libs=no
- preload=no
+ preload=false
prev=
prevarg=
release=
@@ -5161,7 +6608,7 @@ func_mode_link ()
vinfo=
vinfo_number=no
weak_libs=
- single_module="${wl}-single_module"
+ single_module=$wl-single_module
func_infer_tag $base_compile
# We need to know -static, to get the right output filenames.
@@ -5169,15 +6616,15 @@ func_mode_link ()
do
case $arg in
-shared)
- test "$build_libtool_libs" != yes && \
- func_fatal_configuration "can not build a shared library"
+ test yes != "$build_libtool_libs" \
+ && func_fatal_configuration "cannot build a shared library"
build_old_libs=no
break
;;
-all-static | -static | -static-libtool-libs)
case $arg in
-all-static)
- if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
func_warning "complete static linking is impossible in this configuration"
fi
if test -n "$link_static_flag"; then
@@ -5210,7 +6657,7 @@ func_mode_link ()
# Go through the arguments, transforming them on the way.
while test "$#" -gt 0; do
- arg="$1"
+ arg=$1
shift
func_quote_for_eval "$arg"
qarg=$func_quote_for_eval_unquoted_result
@@ -5227,21 +6674,21 @@ func_mode_link ()
case $prev in
bindir)
- bindir="$arg"
+ bindir=$arg
prev=
continue
;;
dlfiles|dlprefiles)
- if test "$preload" = no; then
+ $preload || {
# Add the symbol object into the linking commands.
func_append compile_command " @SYMFILE@"
func_append finalize_command " @SYMFILE@"
- preload=yes
- fi
+ preload=:
+ }
case $arg in
*.la | *.lo) ;; # We handle these cases below.
force)
- if test "$dlself" = no; then
+ if test no = "$dlself"; then
dlself=needless
export_dynamic=yes
fi
@@ -5249,9 +6696,9 @@ func_mode_link ()
continue
;;
self)
- if test "$prev" = dlprefiles; then
+ if test dlprefiles = "$prev"; then
dlself=yes
- elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
dlself=yes
else
dlself=needless
@@ -5261,7 +6708,7 @@ func_mode_link ()
continue
;;
*)
- if test "$prev" = dlfiles; then
+ if test dlfiles = "$prev"; then
func_append dlfiles " $arg"
else
func_append dlprefiles " $arg"
@@ -5272,14 +6719,14 @@ func_mode_link ()
esac
;;
expsyms)
- export_symbols="$arg"
+ export_symbols=$arg
test -f "$arg" \
- || func_fatal_error "symbol file \`$arg' does not exist"
+ || func_fatal_error "symbol file '$arg' does not exist"
prev=
continue
;;
expsyms_regex)
- export_symbols_regex="$arg"
+ export_symbols_regex=$arg
prev=
continue
;;
@@ -5297,7 +6744,13 @@ func_mode_link ()
continue
;;
inst_prefix)
- inst_prefix_dir="$arg"
+ inst_prefix_dir=$arg
+ prev=
+ continue
+ ;;
+ mllvm)
+ # Clang does not use LLVM to link, so we can simply discard any
+ # '-mllvm $arg' options when doing the link step.
prev=
continue
;;
@@ -5321,21 +6774,21 @@ func_mode_link ()
if test -z "$pic_object" ||
test -z "$non_pic_object" ||
- test "$pic_object" = none &&
- test "$non_pic_object" = none; then
- func_fatal_error "cannot find name of object for \`$arg'"
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
fi
# Extract subdirectory from the argument.
func_dirname "$arg" "/" ""
- xdir="$func_dirname_result"
+ xdir=$func_dirname_result
- if test "$pic_object" != none; then
+ if test none != "$pic_object"; then
# Prepend the subdirectory the object is found in.
- pic_object="$xdir$pic_object"
+ pic_object=$xdir$pic_object
- if test "$prev" = dlfiles; then
- if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
func_append dlfiles " $pic_object"
prev=
continue
@@ -5346,7 +6799,7 @@ func_mode_link ()
fi
# CHECK ME: I think I busted this. -Ossama
- if test "$prev" = dlprefiles; then
+ if test dlprefiles = "$prev"; then
# Preload the old-style object.
func_append dlprefiles " $pic_object"
prev=
@@ -5354,23 +6807,23 @@ func_mode_link ()
# A PIC object.
func_append libobjs " $pic_object"
- arg="$pic_object"
+ arg=$pic_object
fi
# Non-PIC object.
- if test "$non_pic_object" != none; then
+ if test none != "$non_pic_object"; then
# Prepend the subdirectory the object is found in.
- non_pic_object="$xdir$non_pic_object"
+ non_pic_object=$xdir$non_pic_object
# A standard non-PIC object
func_append non_pic_objects " $non_pic_object"
- if test -z "$pic_object" || test "$pic_object" = none ; then
- arg="$non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
fi
else
# If the PIC object exists, use it instead.
# $xdir was prepended to $pic_object above.
- non_pic_object="$pic_object"
+ non_pic_object=$pic_object
func_append non_pic_objects " $non_pic_object"
fi
else
@@ -5378,7 +6831,7 @@ func_mode_link ()
if $opt_dry_run; then
# Extract subdirectory from the argument.
func_dirname "$arg" "/" ""
- xdir="$func_dirname_result"
+ xdir=$func_dirname_result
func_lo2o "$arg"
pic_object=$xdir$objdir/$func_lo2o_result
@@ -5386,24 +6839,29 @@ func_mode_link ()
func_append libobjs " $pic_object"
func_append non_pic_objects " $non_pic_object"
else
- func_fatal_error "\`$arg' is not a valid libtool object"
+ func_fatal_error "'$arg' is not a valid libtool object"
fi
fi
done
else
- func_fatal_error "link input file \`$arg' does not exist"
+ func_fatal_error "link input file '$arg' does not exist"
fi
arg=$save_arg
prev=
continue
;;
+ os2dllname)
+ os2dllname=$arg
+ prev=
+ continue
+ ;;
precious_regex)
- precious_files_regex="$arg"
+ precious_files_regex=$arg
prev=
continue
;;
release)
- release="-$arg"
+ release=-$arg
prev=
continue
;;
@@ -5415,7 +6873,7 @@ func_mode_link ()
func_fatal_error "only absolute run-paths are allowed"
;;
esac
- if test "$prev" = rpath; then
+ if test rpath = "$prev"; then
case "$rpath " in
*" $arg "*) ;;
*) func_append rpath " $arg" ;;
@@ -5430,7 +6888,7 @@ func_mode_link ()
continue
;;
shrext)
- shrext_cmds="$arg"
+ shrext_cmds=$arg
prev=
continue
;;
@@ -5470,7 +6928,7 @@ func_mode_link ()
esac
fi # test -n "$prev"
- prevarg="$arg"
+ prevarg=$arg
case $arg in
-all-static)
@@ -5484,7 +6942,7 @@ func_mode_link ()
-allow-undefined)
# FIXME: remove this flag sometime in the future.
- func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+ func_fatal_error "'-allow-undefined' must not be used because it is the default"
;;
-avoid-version)
@@ -5516,7 +6974,7 @@ func_mode_link ()
if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
func_fatal_error "more than one -exported-symbols argument is not allowed"
fi
- if test "X$arg" = "X-export-symbols"; then
+ if test X-export-symbols = "X$arg"; then
prev=expsyms
else
prev=expsyms_regex
@@ -5550,9 +7008,9 @@ func_mode_link ()
func_stripname "-L" '' "$arg"
if test -z "$func_stripname_result"; then
if test "$#" -gt 0; then
- func_fatal_error "require no space between \`-L' and \`$1'"
+ func_fatal_error "require no space between '-L' and '$1'"
else
- func_fatal_error "need path for \`-L' option"
+ func_fatal_error "need path for '-L' option"
fi
fi
func_resolve_sysroot "$func_stripname_result"
@@ -5563,8 +7021,8 @@ func_mode_link ()
*)
absdir=`cd "$dir" && pwd`
test -z "$absdir" && \
- func_fatal_error "cannot determine absolute directory name of \`$dir'"
- dir="$absdir"
+ func_fatal_error "cannot determine absolute directory name of '$dir'"
+ dir=$absdir
;;
esac
case "$deplibs " in
@@ -5599,7 +7057,7 @@ func_mode_link ()
;;
-l*)
- if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ if test X-lc = "X$arg" || test X-lm = "X$arg"; then
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
# These systems don't actually have a C or math library (as such)
@@ -5607,11 +7065,11 @@ func_mode_link ()
;;
*-*-os2*)
# These systems don't actually have a C library (as such)
- test "X$arg" = "X-lc" && continue
+ test X-lc = "X$arg" && continue
;;
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
# Do not include libc due to us having libc/libc_r.
- test "X$arg" = "X-lc" && continue
+ test X-lc = "X$arg" && continue
;;
*-*-rhapsody* | *-*-darwin1.[012])
# Rhapsody C and math libraries are in the System framework
@@ -5620,16 +7078,16 @@ func_mode_link ()
;;
*-*-sco3.2v5* | *-*-sco5v6*)
# Causes problems with __ctype
- test "X$arg" = "X-lc" && continue
+ test X-lc = "X$arg" && continue
;;
*-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
# Compiler inserts libc in the correct place for threads to work
- test "X$arg" = "X-lc" && continue
+ test X-lc = "X$arg" && continue
;;
esac
- elif test "X$arg" = "X-lc_r"; then
+ elif test X-lc_r = "X$arg"; then
case $host in
- *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
# Do not include libc_r directly, use -pthread flag.
continue
;;
@@ -5639,6 +7097,11 @@ func_mode_link ()
continue
;;
+ -mllvm)
+ prev=mllvm
+ continue
+ ;;
+
-module)
module=yes
continue
@@ -5664,11 +7127,21 @@ func_mode_link ()
*" $arg "*) ;;
* ) func_append new_inherited_linker_flags " $arg" ;;
esac
+
+ # As we are forced to pass -nostdlib to g++ during linking, the option
+ # -pthread{,s} is not in effect; add the -lpthread to $deplist
+ # explicitly to link correctly.
+ if test "$tagname" = CXX -a x"$with_gcc" = xyes; then
+ case "$arg" in
+ -pthread*) func_append deplibs " -lpthread" ;;
+ esac
+ fi
+
continue
;;
-multi_module)
- single_module="${wl}-multi_module"
+ single_module=$wl-multi_module
continue
;;
@@ -5682,8 +7155,8 @@ func_mode_link ()
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
# The PATH hackery in wrapper scripts is required on Windows
# and Darwin in order for the loader to find any dlls it needs.
- func_warning "\`-no-install' is ignored for $host"
- func_warning "assuming \`-no-fast-install' instead"
+ func_warning "'-no-install' is ignored for $host"
+ func_warning "assuming '-no-fast-install' instead"
fast_install=no
;;
*) no_install=yes ;;
@@ -5701,6 +7174,11 @@ func_mode_link ()
continue
;;
+ -os2dllname)
+ prev=os2dllname
+ continue
+ ;;
+
-o) prev=output ;;
-precious-files-regex)
@@ -5788,14 +7266,14 @@ func_mode_link ()
func_stripname '-Wc,' '' "$arg"
args=$func_stripname_result
arg=
- save_ifs="$IFS"; IFS=','
+ save_ifs=$IFS; IFS=,
for flag in $args; do
- IFS="$save_ifs"
+ IFS=$save_ifs
func_quote_for_eval "$flag"
func_append arg " $func_quote_for_eval_result"
func_append compiler_flags " $func_quote_for_eval_result"
done
- IFS="$save_ifs"
+ IFS=$save_ifs
func_stripname ' ' '' "$arg"
arg=$func_stripname_result
;;
@@ -5804,15 +7282,15 @@ func_mode_link ()
func_stripname '-Wl,' '' "$arg"
args=$func_stripname_result
arg=
- save_ifs="$IFS"; IFS=','
+ save_ifs=$IFS; IFS=,
for flag in $args; do
- IFS="$save_ifs"
+ IFS=$save_ifs
func_quote_for_eval "$flag"
func_append arg " $wl$func_quote_for_eval_result"
func_append compiler_flags " $wl$func_quote_for_eval_result"
func_append linker_flags " $func_quote_for_eval_result"
done
- IFS="$save_ifs"
+ IFS=$save_ifs
func_stripname ' ' '' "$arg"
arg=$func_stripname_result
;;
@@ -5835,7 +7313,7 @@ func_mode_link ()
# -msg_* for osf cc
-msg_*)
func_quote_for_eval "$arg"
- arg="$func_quote_for_eval_result"
+ arg=$func_quote_for_eval_result
;;
# Flags to be passed through unchanged, with rationale:
@@ -5847,25 +7325,50 @@ func_mode_link ()
# -m*, -t[45]*, -txscale* architecture-specific flags for GCC
# -F/path path to uninstalled frameworks, gcc on darwin
# -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # -fstack-protector* stack protector flags for GCC
# @file GCC response files
# -tp=* Portland pgcc target processor selection
# --sysroot=* for sysroot support
- # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ # -specs=* GCC specs files
+ # -stdlib=* select c++ std lib with clang
+ # -fsanitize=* Clang/GCC memory and address sanitizer
+ # -fuse-ld=* Linker select flags for GCC
-64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
- -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+ -specs=*|-fsanitize=*|-fuse-ld=*)
func_quote_for_eval "$arg"
- arg="$func_quote_for_eval_result"
+ arg=$func_quote_for_eval_result
func_append compile_command " $arg"
func_append finalize_command " $arg"
func_append compiler_flags " $arg"
continue
;;
+ -Z*)
+ if test os2 = "`expr $host : '.*\(os2\)'`"; then
+ # OS/2 uses -Zxxx to specify OS/2-specific options
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case $arg in
+ -Zlinker | -Zstack)
+ prev=xcompiler
+ ;;
+ esac
+ continue
+ else
+ # Otherwise treat like 'Some other compiler flag' below
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ fi
+ ;;
+
# Some other compiler flag.
-* | +*)
func_quote_for_eval "$arg"
- arg="$func_quote_for_eval_result"
+ arg=$func_quote_for_eval_result
;;
*.$objext)
@@ -5886,21 +7389,21 @@ func_mode_link ()
if test -z "$pic_object" ||
test -z "$non_pic_object" ||
- test "$pic_object" = none &&
- test "$non_pic_object" = none; then
- func_fatal_error "cannot find name of object for \`$arg'"
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
fi
# Extract subdirectory from the argument.
func_dirname "$arg" "/" ""
- xdir="$func_dirname_result"
+ xdir=$func_dirname_result
- if test "$pic_object" != none; then
+ test none = "$pic_object" || {
# Prepend the subdirectory the object is found in.
- pic_object="$xdir$pic_object"
+ pic_object=$xdir$pic_object
- if test "$prev" = dlfiles; then
- if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
func_append dlfiles " $pic_object"
prev=
continue
@@ -5911,7 +7414,7 @@ func_mode_link ()
fi
# CHECK ME: I think I busted this. -Ossama
- if test "$prev" = dlprefiles; then
+ if test dlprefiles = "$prev"; then
# Preload the old-style object.
func_append dlprefiles " $pic_object"
prev=
@@ -5919,23 +7422,23 @@ func_mode_link ()
# A PIC object.
func_append libobjs " $pic_object"
- arg="$pic_object"
- fi
+ arg=$pic_object
+ }
# Non-PIC object.
- if test "$non_pic_object" != none; then
+ if test none != "$non_pic_object"; then
# Prepend the subdirectory the object is found in.
- non_pic_object="$xdir$non_pic_object"
+ non_pic_object=$xdir$non_pic_object
# A standard non-PIC object
func_append non_pic_objects " $non_pic_object"
- if test -z "$pic_object" || test "$pic_object" = none ; then
- arg="$non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
fi
else
# If the PIC object exists, use it instead.
# $xdir was prepended to $pic_object above.
- non_pic_object="$pic_object"
+ non_pic_object=$pic_object
func_append non_pic_objects " $non_pic_object"
fi
else
@@ -5943,7 +7446,7 @@ func_mode_link ()
if $opt_dry_run; then
# Extract subdirectory from the argument.
func_dirname "$arg" "/" ""
- xdir="$func_dirname_result"
+ xdir=$func_dirname_result
func_lo2o "$arg"
pic_object=$xdir$objdir/$func_lo2o_result
@@ -5951,7 +7454,7 @@ func_mode_link ()
func_append libobjs " $pic_object"
func_append non_pic_objects " $non_pic_object"
else
- func_fatal_error "\`$arg' is not a valid libtool object"
+ func_fatal_error "'$arg' is not a valid libtool object"
fi
fi
;;
@@ -5967,11 +7470,11 @@ func_mode_link ()
# A libtool-controlled library.
func_resolve_sysroot "$arg"
- if test "$prev" = dlfiles; then
+ if test dlfiles = "$prev"; then
# This library was specified with -dlopen.
func_append dlfiles " $func_resolve_sysroot_result"
prev=
- elif test "$prev" = dlprefiles; then
+ elif test dlprefiles = "$prev"; then
# The library was specified with -dlpreopen.
func_append dlprefiles " $func_resolve_sysroot_result"
prev=
@@ -5986,7 +7489,7 @@ func_mode_link ()
# Unknown arguments in both finalize_command and compile_command need
# to be aesthetically quoted because they are evaled later.
func_quote_for_eval "$arg"
- arg="$func_quote_for_eval_result"
+ arg=$func_quote_for_eval_result
;;
esac # arg
@@ -5998,9 +7501,9 @@ func_mode_link ()
done # argument parsing loop
test -n "$prev" && \
- func_fatal_help "the \`$prevarg' option requires an argument"
+ func_fatal_help "the '$prevarg' option requires an argument"
- if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
eval arg=\"$export_dynamic_flag_spec\"
func_append compile_command " $arg"
func_append finalize_command " $arg"
@@ -6009,20 +7512,23 @@ func_mode_link ()
oldlibs=
# calculate the name of the file, without its directory
func_basename "$output"
- outputname="$func_basename_result"
- libobjs_save="$libobjs"
+ outputname=$func_basename_result
+ libobjs_save=$libobjs
if test -n "$shlibpath_var"; then
# get the directories listed in $shlibpath_var
- eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+ eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
else
shlib_search_path=
fi
eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+ # Definition is injected by LT_CONFIG during libtool generation.
+ func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
func_dirname "$output" "/" ""
- output_objdir="$func_dirname_result$objdir"
+ output_objdir=$func_dirname_result$objdir
func_to_tool_file "$output_objdir/"
tool_output_objdir=$func_to_tool_file_result
# Create the object directory.
@@ -6045,7 +7551,7 @@ func_mode_link ()
# Find all interdependent deplibs by searching for libraries
# that are linked more than once (e.g. -la -lb -la)
for deplib in $deplibs; do
- if $opt_preserve_dup_deps ; then
+ if $opt_preserve_dup_deps; then
case "$libs " in
*" $deplib "*) func_append specialdeplibs " $deplib" ;;
esac
@@ -6053,7 +7559,7 @@ func_mode_link ()
func_append libs " $deplib"
done
- if test "$linkmode" = lib; then
+ if test lib = "$linkmode"; then
libs="$predeps $libs $compiler_lib_search_path $postdeps"
# Compute libraries that are listed more than once in $predeps
@@ -6085,7 +7591,7 @@ func_mode_link ()
case $file in
*.la) ;;
*)
- func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+ func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
;;
esac
done
@@ -6093,7 +7599,7 @@ func_mode_link ()
prog)
compile_deplibs=
finalize_deplibs=
- alldeplibs=no
+ alldeplibs=false
newdlfiles=
newdlprefiles=
passes="conv scan dlopen dlpreopen link"
@@ -6105,32 +7611,29 @@ func_mode_link ()
for pass in $passes; do
# The preopen pass in lib mode reverses $deplibs; put it back here
# so that -L comes before libs that need it for instance...
- if test "$linkmode,$pass" = "lib,link"; then
+ if test lib,link = "$linkmode,$pass"; then
## FIXME: Find the place where the list is rebuilt in the wrong
## order, and fix it there properly
tmp_deplibs=
for deplib in $deplibs; do
tmp_deplibs="$deplib $tmp_deplibs"
done
- deplibs="$tmp_deplibs"
+ deplibs=$tmp_deplibs
fi
- if test "$linkmode,$pass" = "lib,link" ||
- test "$linkmode,$pass" = "prog,scan"; then
- libs="$deplibs"
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass"; then
+ libs=$deplibs
deplibs=
fi
- if test "$linkmode" = prog; then
+ if test prog = "$linkmode"; then
case $pass in
- dlopen) libs="$dlfiles" ;;
- dlpreopen) libs="$dlprefiles" ;;
- link)
- libs="$deplibs %DEPLIBS%"
- test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
- ;;
+ dlopen) libs=$dlfiles ;;
+ dlpreopen) libs=$dlprefiles ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
esac
fi
- if test "$linkmode,$pass" = "lib,dlpreopen"; then
+ if test lib,dlpreopen = "$linkmode,$pass"; then
# Collect and forward deplibs of preopened libtool libs
for lib in $dlprefiles; do
# Ignore non-libtool-libs
@@ -6151,26 +7654,26 @@ func_mode_link ()
esac
done
done
- libs="$dlprefiles"
+ libs=$dlprefiles
fi
- if test "$pass" = dlopen; then
+ if test dlopen = "$pass"; then
# Collect dlpreopened libraries
- save_deplibs="$deplibs"
+ save_deplibs=$deplibs
deplibs=
fi
for deplib in $libs; do
lib=
- found=no
+ found=false
case $deplib in
-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
|-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
- if test "$linkmode,$pass" = "prog,link"; then
+ if test prog,link = "$linkmode,$pass"; then
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
else
func_append compiler_flags " $deplib"
- if test "$linkmode" = lib ; then
+ if test lib = "$linkmode"; then
case "$new_inherited_linker_flags " in
*" $deplib "*) ;;
* ) func_append new_inherited_linker_flags " $deplib" ;;
@@ -6180,13 +7683,13 @@ func_mode_link ()
continue
;;
-l*)
- if test "$linkmode" != lib && test "$linkmode" != prog; then
- func_warning "\`-l' is ignored for archives/objects"
+ if test lib != "$linkmode" && test prog != "$linkmode"; then
+ func_warning "'-l' is ignored for archives/objects"
continue
fi
func_stripname '-l' '' "$deplib"
name=$func_stripname_result
- if test "$linkmode" = lib; then
+ if test lib = "$linkmode"; then
searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
else
searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
@@ -6194,31 +7697,22 @@ func_mode_link ()
for searchdir in $searchdirs; do
for search_ext in .la $std_shrext .so .a; do
# Search the libtool library
- lib="$searchdir/lib${name}${search_ext}"
+ lib=$searchdir/lib$name$search_ext
if test -f "$lib"; then
- if test "$search_ext" = ".la"; then
- found=yes
+ if test .la = "$search_ext"; then
+ found=:
else
- found=no
+ found=false
fi
break 2
fi
done
done
- if test "$found" != yes; then
- # deplib doesn't seem to be a libtool library
- if test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- deplibs="$deplib $deplibs"
- test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
- fi
- continue
- else # deplib is a libtool library
+ if $found; then
+ # deplib is a libtool library
# If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
# We need to do some special things here, and not later.
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
case " $predeps $postdeps " in
*" $deplib "*)
if func_lalib_p "$lib"; then
@@ -6226,19 +7720,19 @@ func_mode_link ()
old_library=
func_source "$lib"
for l in $old_library $library_names; do
- ll="$l"
+ ll=$l
done
- if test "X$ll" = "X$old_library" ; then # only static version available
- found=no
+ if test "X$ll" = "X$old_library"; then # only static version available
+ found=false
func_dirname "$lib" "" "."
- ladir="$func_dirname_result"
+ ladir=$func_dirname_result
lib=$ladir/$old_library
- if test "$linkmode,$pass" = "prog,link"; then
+ if test prog,link = "$linkmode,$pass"; then
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
else
deplibs="$deplib $deplibs"
- test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
fi
continue
fi
@@ -6247,15 +7741,25 @@ func_mode_link ()
*) ;;
esac
fi
+ else
+ # deplib doesn't seem to be a libtool library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
fi
;; # -l
*.ltframework)
- if test "$linkmode,$pass" = "prog,link"; then
+ if test prog,link = "$linkmode,$pass"; then
compile_deplibs="$deplib $compile_deplibs"
finalize_deplibs="$deplib $finalize_deplibs"
else
deplibs="$deplib $deplibs"
- if test "$linkmode" = lib ; then
+ if test lib = "$linkmode"; then
case "$new_inherited_linker_flags " in
*" $deplib "*) ;;
* ) func_append new_inherited_linker_flags " $deplib" ;;
@@ -6268,18 +7772,18 @@ func_mode_link ()
case $linkmode in
lib)
deplibs="$deplib $deplibs"
- test "$pass" = conv && continue
+ test conv = "$pass" && continue
newdependency_libs="$deplib $newdependency_libs"
func_stripname '-L' '' "$deplib"
func_resolve_sysroot "$func_stripname_result"
func_append newlib_search_path " $func_resolve_sysroot_result"
;;
prog)
- if test "$pass" = conv; then
+ if test conv = "$pass"; then
deplibs="$deplib $deplibs"
continue
fi
- if test "$pass" = scan; then
+ if test scan = "$pass"; then
deplibs="$deplib $deplibs"
else
compile_deplibs="$deplib $compile_deplibs"
@@ -6290,13 +7794,13 @@ func_mode_link ()
func_append newlib_search_path " $func_resolve_sysroot_result"
;;
*)
- func_warning "\`-L' is ignored for archives/objects"
+ func_warning "'-L' is ignored for archives/objects"
;;
esac # linkmode
continue
;; # -L
-R*)
- if test "$pass" = link; then
+ if test link = "$pass"; then
func_stripname '-R' '' "$deplib"
func_resolve_sysroot "$func_stripname_result"
dir=$func_resolve_sysroot_result
@@ -6314,7 +7818,7 @@ func_mode_link ()
lib=$func_resolve_sysroot_result
;;
*.$libext)
- if test "$pass" = conv; then
+ if test conv = "$pass"; then
deplibs="$deplib $deplibs"
continue
fi
@@ -6325,21 +7829,26 @@ func_mode_link ()
case " $dlpreconveniencelibs " in
*" $deplib "*) ;;
*)
- valid_a_lib=no
+ valid_a_lib=false
case $deplibs_check_method in
match_pattern*)
set dummy $deplibs_check_method; shift
match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
| $EGREP "$match_pattern_regex" > /dev/null; then
- valid_a_lib=yes
+ valid_a_lib=:
fi
;;
pass_all)
- valid_a_lib=yes
+ valid_a_lib=:
;;
esac
- if test "$valid_a_lib" != yes; then
+ if $valid_a_lib; then
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ else
echo
$ECHO "*** Warning: Trying to link with static lib archive $deplib."
echo "*** I have the capability to make that library automatically link in when"
@@ -6347,18 +7856,13 @@ func_mode_link ()
echo "*** shared version of the library, which you do not appear to have"
echo "*** because the file extensions .$libext of this argument makes me believe"
echo "*** that it is just a static archive that I should not use here."
- else
- echo
- $ECHO "*** Warning: Linking the shared library $output against the"
- $ECHO "*** static library $deplib is not portable!"
- deplibs="$deplib $deplibs"
fi
;;
esac
continue
;;
prog)
- if test "$pass" != link; then
+ if test link != "$pass"; then
deplibs="$deplib $deplibs"
else
compile_deplibs="$deplib $compile_deplibs"
@@ -6369,10 +7873,10 @@ func_mode_link ()
esac # linkmode
;; # *.$libext
*.lo | *.$objext)
- if test "$pass" = conv; then
+ if test conv = "$pass"; then
deplibs="$deplib $deplibs"
- elif test "$linkmode" = prog; then
- if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ elif test prog = "$linkmode"; then
+ if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
# If there is no dlopen support or we're linking statically,
# we need to preload.
func_append newdlprefiles " $deplib"
@@ -6385,22 +7889,20 @@ func_mode_link ()
continue
;;
%DEPLIBS%)
- alldeplibs=yes
+ alldeplibs=:
continue
;;
esac # case $deplib
- if test "$found" = yes || test -f "$lib"; then :
- else
- func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
- fi
+ $found || test -f "$lib" \
+ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
# Check to see that this really is a libtool archive.
func_lalib_unsafe_p "$lib" \
- || func_fatal_error "\`$lib' is not a valid libtool archive"
+ || func_fatal_error "'$lib' is not a valid libtool archive"
func_dirname "$lib" "" "."
- ladir="$func_dirname_result"
+ ladir=$func_dirname_result
dlname=
dlopen=
@@ -6430,36 +7932,36 @@ func_mode_link ()
done
fi
dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
- if test "$linkmode,$pass" = "lib,link" ||
- test "$linkmode,$pass" = "prog,scan" ||
- { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass" ||
+ { test prog != "$linkmode" && test lib != "$linkmode"; }; then
test -n "$dlopen" && func_append dlfiles " $dlopen"
test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
fi
- if test "$pass" = conv; then
+ if test conv = "$pass"; then
# Only check for convenience libraries
deplibs="$lib $deplibs"
if test -z "$libdir"; then
if test -z "$old_library"; then
- func_fatal_error "cannot find name of link library for \`$lib'"
+ func_fatal_error "cannot find name of link library for '$lib'"
fi
# It is a libtool convenience library, so add in its objects.
func_append convenience " $ladir/$objdir/$old_library"
func_append old_convenience " $ladir/$objdir/$old_library"
- tmp_libs=
- for deplib in $dependency_libs; do
- deplibs="$deplib $deplibs"
- if $opt_preserve_dup_deps ; then
- case "$tmp_libs " in
- *" $deplib "*) func_append specialdeplibs " $deplib" ;;
- esac
- fi
- func_append tmp_libs " $deplib"
- done
- elif test "$linkmode" != prog && test "$linkmode" != lib; then
- func_fatal_error "\`$lib' is not a convenience library"
+ elif test prog != "$linkmode" && test lib != "$linkmode"; then
+ func_fatal_error "'$lib' is not a convenience library"
fi
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done
continue
fi # $pass = conv
@@ -6467,26 +7969,26 @@ func_mode_link ()
# Get the name of the library we link against.
linklib=
if test -n "$old_library" &&
- { test "$prefer_static_libs" = yes ||
- test "$prefer_static_libs,$installed" = "built,no"; }; then
+ { test yes = "$prefer_static_libs" ||
+ test built,no = "$prefer_static_libs,$installed"; }; then
linklib=$old_library
else
for l in $old_library $library_names; do
- linklib="$l"
+ linklib=$l
done
fi
if test -z "$linklib"; then
- func_fatal_error "cannot find name of link library for \`$lib'"
+ func_fatal_error "cannot find name of link library for '$lib'"
fi
# This library was specified with -dlopen.
- if test "$pass" = dlopen; then
- if test -z "$libdir"; then
- func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
- fi
+ if test dlopen = "$pass"; then
+ test -z "$libdir" \
+ && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
if test -z "$dlname" ||
- test "$dlopen_support" != yes ||
- test "$build_libtool_libs" = no; then
+ test yes != "$dlopen_support" ||
+ test no = "$build_libtool_libs"
+ then
# If there is no dlname, no dlopen support or we're linking
# statically, we need to preload. We also need to preload any
# dependent libraries so libltdl's deplib preloader doesn't
@@ -6500,40 +8002,40 @@ func_mode_link ()
# We need an absolute path.
case $ladir in
- [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
*)
abs_ladir=`cd "$ladir" && pwd`
if test -z "$abs_ladir"; then
- func_warning "cannot determine absolute directory name of \`$ladir'"
+ func_warning "cannot determine absolute directory name of '$ladir'"
func_warning "passing it literally to the linker, although it might fail"
- abs_ladir="$ladir"
+ abs_ladir=$ladir
fi
;;
esac
func_basename "$lib"
- laname="$func_basename_result"
+ laname=$func_basename_result
# Find the relevant object directory and library name.
- if test "X$installed" = Xyes; then
+ if test yes = "$installed"; then
if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- func_warning "library \`$lib' was moved."
- dir="$ladir"
- absdir="$abs_ladir"
- libdir="$abs_ladir"
+ func_warning "library '$lib' was moved."
+ dir=$ladir
+ absdir=$abs_ladir
+ libdir=$abs_ladir
else
- dir="$lt_sysroot$libdir"
- absdir="$lt_sysroot$libdir"
+ dir=$lt_sysroot$libdir
+ absdir=$lt_sysroot$libdir
fi
- test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ test yes = "$hardcode_automatic" && avoidtemprpath=yes
else
if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- dir="$ladir"
- absdir="$abs_ladir"
+ dir=$ladir
+ absdir=$abs_ladir
# Remove this search path later
func_append notinst_path " $abs_ladir"
else
- dir="$ladir/$objdir"
- absdir="$abs_ladir/$objdir"
+ dir=$ladir/$objdir
+ absdir=$abs_ladir/$objdir
# Remove this search path later
func_append notinst_path " $abs_ladir"
fi
@@ -6542,11 +8044,11 @@ func_mode_link ()
name=$func_stripname_result
# This library was specified with -dlpreopen.
- if test "$pass" = dlpreopen; then
- if test -z "$libdir" && test "$linkmode" = prog; then
- func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+ if test dlpreopen = "$pass"; then
+ if test -z "$libdir" && test prog = "$linkmode"; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
fi
- case "$host" in
+ case $host in
# special handling for platforms with PE-DLLs.
*cygwin* | *mingw* | *cegcc* )
# Linker will automatically link against shared library if both
@@ -6590,9 +8092,9 @@ func_mode_link ()
if test -z "$libdir"; then
# Link the convenience library
- if test "$linkmode" = lib; then
+ if test lib = "$linkmode"; then
deplibs="$dir/$old_library $deplibs"
- elif test "$linkmode,$pass" = "prog,link"; then
+ elif test prog,link = "$linkmode,$pass"; then
compile_deplibs="$dir/$old_library $compile_deplibs"
finalize_deplibs="$dir/$old_library $finalize_deplibs"
else
@@ -6602,14 +8104,14 @@ func_mode_link ()
fi
- if test "$linkmode" = prog && test "$pass" != link; then
+ if test prog = "$linkmode" && test link != "$pass"; then
func_append newlib_search_path " $ladir"
deplibs="$lib $deplibs"
- linkalldeplibs=no
- if test "$link_all_deplibs" != no || test -z "$library_names" ||
- test "$build_libtool_libs" = no; then
- linkalldeplibs=yes
+ linkalldeplibs=false
+ if test no != "$link_all_deplibs" || test -z "$library_names" ||
+ test no = "$build_libtool_libs"; then
+ linkalldeplibs=:
fi
tmp_libs=
@@ -6621,14 +8123,14 @@ func_mode_link ()
;;
esac
# Need to link against all dependency_libs?
- if test "$linkalldeplibs" = yes; then
+ if $linkalldeplibs; then
deplibs="$deplib $deplibs"
else
# Need to hardcode shared library paths
# or/and link against static libraries
newdependency_libs="$deplib $newdependency_libs"
fi
- if $opt_preserve_dup_deps ; then
+ if $opt_preserve_dup_deps; then
case "$tmp_libs " in
*" $deplib "*) func_append specialdeplibs " $deplib" ;;
esac
@@ -6638,15 +8140,15 @@ func_mode_link ()
continue
fi # $linkmode = prog...
- if test "$linkmode,$pass" = "prog,link"; then
+ if test prog,link = "$linkmode,$pass"; then
if test -n "$library_names" &&
- { { test "$prefer_static_libs" = no ||
- test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ { { test no = "$prefer_static_libs" ||
+ test built,yes = "$prefer_static_libs,$installed"; } ||
test -z "$old_library"; }; then
# We need to hardcode the library path
- if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
# Make sure the rpath contains only unique directories.
- case "$temp_rpath:" in
+ case $temp_rpath: in
*"$absdir:"*) ;;
*) func_append temp_rpath "$absdir:" ;;
esac
@@ -6675,9 +8177,9 @@ func_mode_link ()
esac
fi # $linkmode,$pass = prog,link...
- if test "$alldeplibs" = yes &&
- { test "$deplibs_check_method" = pass_all ||
- { test "$build_libtool_libs" = yes &&
+ if $alldeplibs &&
+ { test pass_all = "$deplibs_check_method" ||
+ { test yes = "$build_libtool_libs" &&
test -n "$library_names"; }; }; then
# We only need to search for static libraries
continue
@@ -6686,19 +8188,19 @@ func_mode_link ()
link_static=no # Whether the deplib will be linked statically
use_static_libs=$prefer_static_libs
- if test "$use_static_libs" = built && test "$installed" = yes; then
+ if test built = "$use_static_libs" && test yes = "$installed"; then
use_static_libs=no
fi
if test -n "$library_names" &&
- { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ { test no = "$use_static_libs" || test -z "$old_library"; }; then
case $host in
- *cygwin* | *mingw* | *cegcc*)
+ *cygwin* | *mingw* | *cegcc* | *os2*)
# No point in relinking DLLs because paths are not encoded
func_append notinst_deplibs " $lib"
need_relink=no
;;
*)
- if test "$installed" = no; then
+ if test no = "$installed"; then
func_append notinst_deplibs " $lib"
need_relink=yes
fi
@@ -6708,24 +8210,24 @@ func_mode_link ()
# Warn about portability, can't link against -module's on some
# systems (darwin). Don't bleat about dlopened modules though!
- dlopenmodule=""
+ dlopenmodule=
for dlpremoduletest in $dlprefiles; do
if test "X$dlpremoduletest" = "X$lib"; then
- dlopenmodule="$dlpremoduletest"
+ dlopenmodule=$dlpremoduletest
break
fi
done
- if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+ if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
echo
- if test "$linkmode" = prog; then
+ if test prog = "$linkmode"; then
$ECHO "*** Warning: Linking the executable $output against the loadable module"
else
$ECHO "*** Warning: Linking the shared library $output against the loadable module"
fi
$ECHO "*** $linklib is not portable!"
fi
- if test "$linkmode" = lib &&
- test "$hardcode_into_libs" = yes; then
+ if test lib = "$linkmode" &&
+ test yes = "$hardcode_into_libs"; then
# Hardcode the library path.
# Skip directories that are in the system default run-time
# search path.
@@ -6753,43 +8255,43 @@ func_mode_link ()
# figure out the soname
set dummy $library_names
shift
- realname="$1"
+ realname=$1
shift
libname=`eval "\\$ECHO \"$libname_spec\""`
# use dlname if we got it. it's perfectly good, no?
if test -n "$dlname"; then
- soname="$dlname"
+ soname=$dlname
elif test -n "$soname_spec"; then
# bleh windows
case $host in
- *cygwin* | mingw* | *cegcc*)
+ *cygwin* | mingw* | *cegcc* | *os2*)
func_arith $current - $age
major=$func_arith_result
- versuffix="-$major"
+ versuffix=-$major
;;
esac
eval soname=\"$soname_spec\"
else
- soname="$realname"
+ soname=$realname
fi
# Make a new name for the extract_expsyms_cmds to use
- soroot="$soname"
+ soroot=$soname
func_basename "$soroot"
- soname="$func_basename_result"
+ soname=$func_basename_result
func_stripname 'lib' '.dll' "$soname"
newlib=libimp-$func_stripname_result.a
# If the library has no export list, then create one now
if test -f "$output_objdir/$soname-def"; then :
else
- func_verbose "extracting exported symbol list from \`$soname'"
+ func_verbose "extracting exported symbol list from '$soname'"
func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
fi
# Create $newlib
if test -f "$output_objdir/$newlib"; then :; else
- func_verbose "generating import library for \`$soname'"
+ func_verbose "generating import library for '$soname'"
func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
fi
# make sure the library variables are pointing to the new library
@@ -6797,58 +8299,58 @@ func_mode_link ()
linklib=$newlib
fi # test -n "$old_archive_from_expsyms_cmds"
- if test "$linkmode" = prog || test "$opt_mode" != relink; then
+ if test prog = "$linkmode" || test relink != "$opt_mode"; then
add_shlibpath=
add_dir=
add=
lib_linked=yes
case $hardcode_action in
immediate | unsupported)
- if test "$hardcode_direct" = no; then
- add="$dir/$linklib"
+ if test no = "$hardcode_direct"; then
+ add=$dir/$linklib
case $host in
- *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
- *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+ *-*-sysv4*uw2*) add_dir=-L$dir ;;
*-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
- *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-unixware7*) add_dir=-L$dir ;;
*-*-darwin* )
- # if the lib is a (non-dlopened) module then we can not
+ # if the lib is a (non-dlopened) module then we cannot
# link against it, someone is ignoring the earlier warnings
if /usr/bin/file -L $add 2> /dev/null |
- $GREP ": [^:]* bundle" >/dev/null ; then
+ $GREP ": [^:]* bundle" >/dev/null; then
if test "X$dlopenmodule" != "X$lib"; then
$ECHO "*** Warning: lib $linklib is a module, not a shared library"
- if test -z "$old_library" ; then
+ if test -z "$old_library"; then
echo
echo "*** And there doesn't seem to be a static archive available"
echo "*** The link will probably fail, sorry"
else
- add="$dir/$old_library"
+ add=$dir/$old_library
fi
elif test -n "$old_library"; then
- add="$dir/$old_library"
+ add=$dir/$old_library
fi
fi
esac
- elif test "$hardcode_minus_L" = no; then
+ elif test no = "$hardcode_minus_L"; then
case $host in
- *-*-sunos*) add_shlibpath="$dir" ;;
+ *-*-sunos*) add_shlibpath=$dir ;;
esac
- add_dir="-L$dir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = no; then
- add_shlibpath="$dir"
- add="-l$name"
+ add_dir=-L$dir
+ add=-l$name
+ elif test no = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
else
lib_linked=no
fi
;;
relink)
- if test "$hardcode_direct" = yes &&
- test "$hardcode_direct_absolute" = no; then
- add="$dir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$absdir"
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$dir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$absdir
# Try looking first in the location we're being installed to.
if test -n "$inst_prefix_dir"; then
case $libdir in
@@ -6857,10 +8359,10 @@ func_mode_link ()
;;
esac
fi
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- add_shlibpath="$dir"
- add="-l$name"
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
else
lib_linked=no
fi
@@ -6868,7 +8370,7 @@ func_mode_link ()
*) lib_linked=no ;;
esac
- if test "$lib_linked" != yes; then
+ if test yes != "$lib_linked"; then
func_fatal_configuration "unsupported hardcode properties"
fi
@@ -6878,15 +8380,15 @@ func_mode_link ()
*) func_append compile_shlibpath "$add_shlibpath:" ;;
esac
fi
- if test "$linkmode" = prog; then
+ if test prog = "$linkmode"; then
test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
test -n "$add" && compile_deplibs="$add $compile_deplibs"
else
test -n "$add_dir" && deplibs="$add_dir $deplibs"
test -n "$add" && deplibs="$add $deplibs"
- if test "$hardcode_direct" != yes &&
- test "$hardcode_minus_L" != yes &&
- test "$hardcode_shlibpath_var" = yes; then
+ if test yes != "$hardcode_direct" &&
+ test yes != "$hardcode_minus_L" &&
+ test yes = "$hardcode_shlibpath_var"; then
case :$finalize_shlibpath: in
*":$libdir:"*) ;;
*) func_append finalize_shlibpath "$libdir:" ;;
@@ -6895,33 +8397,33 @@ func_mode_link ()
fi
fi
- if test "$linkmode" = prog || test "$opt_mode" = relink; then
+ if test prog = "$linkmode" || test relink = "$opt_mode"; then
add_shlibpath=
add_dir=
add=
# Finalize command for both is simple: just hardcode it.
- if test "$hardcode_direct" = yes &&
- test "$hardcode_direct_absolute" = no; then
- add="$libdir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$libdir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$libdir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$libdir
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
case :$finalize_shlibpath: in
*":$libdir:"*) ;;
*) func_append finalize_shlibpath "$libdir:" ;;
esac
- add="-l$name"
- elif test "$hardcode_automatic" = yes; then
+ add=-l$name
+ elif test yes = "$hardcode_automatic"; then
if test -n "$inst_prefix_dir" &&
- test -f "$inst_prefix_dir$libdir/$linklib" ; then
- add="$inst_prefix_dir$libdir/$linklib"
+ test -f "$inst_prefix_dir$libdir/$linklib"; then
+ add=$inst_prefix_dir$libdir/$linklib
else
- add="$libdir/$linklib"
+ add=$libdir/$linklib
fi
else
# We cannot seem to hardcode it, guess we'll fake it.
- add_dir="-L$libdir"
+ add_dir=-L$libdir
# Try looking first in the location we're being installed to.
if test -n "$inst_prefix_dir"; then
case $libdir in
@@ -6930,10 +8432,10 @@ func_mode_link ()
;;
esac
fi
- add="-l$name"
+ add=-l$name
fi
- if test "$linkmode" = prog; then
+ if test prog = "$linkmode"; then
test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
else
@@ -6941,43 +8443,43 @@ func_mode_link ()
test -n "$add" && deplibs="$add $deplibs"
fi
fi
- elif test "$linkmode" = prog; then
+ elif test prog = "$linkmode"; then
# Here we assume that one of hardcode_direct or hardcode_minus_L
# is not unsupported. This is valid on all known static and
# shared platforms.
- if test "$hardcode_direct" != unsupported; then
- test -n "$old_library" && linklib="$old_library"
+ if test unsupported != "$hardcode_direct"; then
+ test -n "$old_library" && linklib=$old_library
compile_deplibs="$dir/$linklib $compile_deplibs"
finalize_deplibs="$dir/$linklib $finalize_deplibs"
else
compile_deplibs="-l$name -L$dir $compile_deplibs"
finalize_deplibs="-l$name -L$dir $finalize_deplibs"
fi
- elif test "$build_libtool_libs" = yes; then
+ elif test yes = "$build_libtool_libs"; then
# Not a shared library
- if test "$deplibs_check_method" != pass_all; then
+ if test pass_all != "$deplibs_check_method"; then
# We're trying link a shared library against a static one
# but the system doesn't support it.
# Just print a warning and add the library to dependency_libs so
# that the program can be linked against the static library.
echo
- $ECHO "*** Warning: This system can not link to static lib archive $lib."
+ $ECHO "*** Warning: This system cannot link to static lib archive $lib."
echo "*** I have the capability to make that library automatically link in when"
echo "*** you link to this library. But I can only do this if you have a"
echo "*** shared version of the library, which you do not appear to have."
- if test "$module" = yes; then
+ if test yes = "$module"; then
echo "*** But as you try to build a module library, libtool will still create "
echo "*** a static module, that should work as long as the dlopening application"
echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
if test -z "$global_symbol_pipe"; then
echo
echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
fi
- if test "$build_old_libs" = no; then
+ if test no = "$build_old_libs"; then
build_libtool_libs=module
build_old_libs=yes
else
@@ -6990,11 +8492,11 @@ func_mode_link ()
fi
fi # link shared/static library?
- if test "$linkmode" = lib; then
+ if test lib = "$linkmode"; then
if test -n "$dependency_libs" &&
- { test "$hardcode_into_libs" != yes ||
- test "$build_old_libs" = yes ||
- test "$link_static" = yes; }; then
+ { test yes != "$hardcode_into_libs" ||
+ test yes = "$build_old_libs" ||
+ test yes = "$link_static"; }; then
# Extract -R from dependency_libs
temp_deplibs=
for libdir in $dependency_libs; do
@@ -7008,12 +8510,12 @@ func_mode_link ()
*) func_append temp_deplibs " $libdir";;
esac
done
- dependency_libs="$temp_deplibs"
+ dependency_libs=$temp_deplibs
fi
func_append newlib_search_path " $absdir"
# Link against this library
- test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
# ... and its dependency_libs
tmp_libs=
for deplib in $dependency_libs; do
@@ -7023,7 +8525,7 @@ func_mode_link ()
func_resolve_sysroot "$func_stripname_result";;
*) func_resolve_sysroot "$deplib" ;;
esac
- if $opt_preserve_dup_deps ; then
+ if $opt_preserve_dup_deps; then
case "$tmp_libs " in
*" $func_resolve_sysroot_result "*)
func_append specialdeplibs " $func_resolve_sysroot_result" ;;
@@ -7032,12 +8534,12 @@ func_mode_link ()
func_append tmp_libs " $func_resolve_sysroot_result"
done
- if test "$link_all_deplibs" != no; then
+ if test no != "$link_all_deplibs"; then
# Add the search paths of all dependency libraries
for deplib in $dependency_libs; do
path=
case $deplib in
- -L*) path="$deplib" ;;
+ -L*) path=$deplib ;;
*.la)
func_resolve_sysroot "$deplib"
deplib=$func_resolve_sysroot_result
@@ -7045,12 +8547,12 @@ func_mode_link ()
dir=$func_dirname_result
# We need an absolute path.
case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
*)
absdir=`cd "$dir" && pwd`
if test -z "$absdir"; then
- func_warning "cannot determine absolute directory name of \`$dir'"
- absdir="$dir"
+ func_warning "cannot determine absolute directory name of '$dir'"
+ absdir=$dir
fi
;;
esac
@@ -7058,35 +8560,35 @@ func_mode_link ()
case $host in
*-*-darwin*)
depdepl=
- eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
- if test -n "$deplibrary_names" ; then
- for tmp in $deplibrary_names ; do
+ eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names"; then
+ for tmp in $deplibrary_names; do
depdepl=$tmp
done
- if test -f "$absdir/$objdir/$depdepl" ; then
- depdepl="$absdir/$objdir/$depdepl"
- darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -f "$absdir/$objdir/$depdepl"; then
+ depdepl=$absdir/$objdir/$depdepl
+ darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
if test -z "$darwin_install_name"; then
- darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
fi
- func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
- func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+ func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+ func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
path=
fi
fi
;;
*)
- path="-L$absdir/$objdir"
+ path=-L$absdir/$objdir
;;
esac
else
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
test -z "$libdir" && \
- func_fatal_error "\`$deplib' is not a valid libtool archive"
+ func_fatal_error "'$deplib' is not a valid libtool archive"
test "$absdir" != "$libdir" && \
- func_warning "\`$deplib' seems to be moved"
+ func_warning "'$deplib' seems to be moved"
- path="-L$absdir"
+ path=-L$absdir
fi
;;
esac
@@ -7098,23 +8600,23 @@ func_mode_link ()
fi # link_all_deplibs != no
fi # linkmode = lib
done # for deplib in $libs
- if test "$pass" = link; then
- if test "$linkmode" = "prog"; then
+ if test link = "$pass"; then
+ if test prog = "$linkmode"; then
compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
else
compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
fi
fi
- dependency_libs="$newdependency_libs"
- if test "$pass" = dlpreopen; then
+ dependency_libs=$newdependency_libs
+ if test dlpreopen = "$pass"; then
# Link the dlpreopened libraries before other libraries
for deplib in $save_deplibs; do
deplibs="$deplib $deplibs"
done
fi
- if test "$pass" != dlopen; then
- if test "$pass" != conv; then
+ if test dlopen != "$pass"; then
+ test conv = "$pass" || {
# Make sure lib_search_path contains only unique directories.
lib_search_path=
for dir in $newlib_search_path; do
@@ -7124,12 +8626,12 @@ func_mode_link ()
esac
done
newlib_search_path=
- fi
+ }
- if test "$linkmode,$pass" != "prog,link"; then
- vars="deplibs"
- else
+ if test prog,link = "$linkmode,$pass"; then
vars="compile_deplibs finalize_deplibs"
+ else
+ vars=deplibs
fi
for var in $vars dependency_libs; do
# Add libraries to $var in reverse order
@@ -7187,62 +8689,93 @@ func_mode_link ()
eval $var=\"$tmp_libs\"
done # for var
fi
+
+ # Add Sun CC postdeps if required:
+ test CXX = "$tagname" && {
+ case $host_os in
+ linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C++ 5.9
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ func_cc_basename "$CC"
+ case $func_cc_basename_result in
+ CC* | sunCC*)
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ }
+
# Last step: remove runtime libs from dependency_libs
# (they stay in deplibs)
tmp_libs=
- for i in $dependency_libs ; do
+ for i in $dependency_libs; do
case " $predeps $postdeps $compiler_lib_search_path " in
*" $i "*)
- i=""
+ i=
;;
esac
- if test -n "$i" ; then
+ if test -n "$i"; then
func_append tmp_libs " $i"
fi
done
dependency_libs=$tmp_libs
done # for pass
- if test "$linkmode" = prog; then
- dlfiles="$newdlfiles"
+ if test prog = "$linkmode"; then
+ dlfiles=$newdlfiles
fi
- if test "$linkmode" = prog || test "$linkmode" = lib; then
- dlprefiles="$newdlprefiles"
+ if test prog = "$linkmode" || test lib = "$linkmode"; then
+ dlprefiles=$newdlprefiles
fi
case $linkmode in
oldlib)
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- func_warning "\`-dlopen' is ignored for archives"
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for archives"
fi
case " $deplibs" in
*\ -l* | *\ -L*)
- func_warning "\`-l' and \`-L' are ignored for archives" ;;
+ func_warning "'-l' and '-L' are ignored for archives" ;;
esac
test -n "$rpath" && \
- func_warning "\`-rpath' is ignored for archives"
+ func_warning "'-rpath' is ignored for archives"
test -n "$xrpath" && \
- func_warning "\`-R' is ignored for archives"
+ func_warning "'-R' is ignored for archives"
test -n "$vinfo" && \
- func_warning "\`-version-info/-version-number' is ignored for archives"
+ func_warning "'-version-info/-version-number' is ignored for archives"
test -n "$release" && \
- func_warning "\`-release' is ignored for archives"
+ func_warning "'-release' is ignored for archives"
test -n "$export_symbols$export_symbols_regex" && \
- func_warning "\`-export-symbols' is ignored for archives"
+ func_warning "'-export-symbols' is ignored for archives"
# Now set the variables for building old libraries.
build_libtool_libs=no
- oldlibs="$output"
+ oldlibs=$output
func_append objs "$old_deplibs"
;;
lib)
- # Make sure we only generate libraries of the form `libNAME.la'.
+ # Make sure we only generate libraries of the form 'libNAME.la'.
case $outputname in
lib*)
func_stripname 'lib' '.la' "$outputname"
@@ -7251,10 +8784,10 @@ func_mode_link ()
eval libname=\"$libname_spec\"
;;
*)
- test "$module" = no && \
- func_fatal_help "libtool library \`$output' must begin with \`lib'"
+ test no = "$module" \
+ && func_fatal_help "libtool library '$output' must begin with 'lib'"
- if test "$need_lib_prefix" != no; then
+ if test no != "$need_lib_prefix"; then
# Add the "lib" prefix for modules if required
func_stripname '' '.la' "$outputname"
name=$func_stripname_result
@@ -7268,8 +8801,8 @@ func_mode_link ()
esac
if test -n "$objs"; then
- if test "$deplibs_check_method" != pass_all; then
- func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+ if test pass_all != "$deplibs_check_method"; then
+ func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
else
echo
$ECHO "*** Warning: Linking the shared library $output against the non-libtool"
@@ -7278,21 +8811,21 @@ func_mode_link ()
fi
fi
- test "$dlself" != no && \
- func_warning "\`-dlopen self' is ignored for libtool libraries"
+ test no = "$dlself" \
+ || func_warning "'-dlopen self' is ignored for libtool libraries"
set dummy $rpath
shift
- test "$#" -gt 1 && \
- func_warning "ignoring multiple \`-rpath's for a libtool library"
+ test 1 -lt "$#" \
+ && func_warning "ignoring multiple '-rpath's for a libtool library"
- install_libdir="$1"
+ install_libdir=$1
oldlibs=
if test -z "$rpath"; then
- if test "$build_libtool_libs" = yes; then
+ if test yes = "$build_libtool_libs"; then
# Building a libtool convenience library.
- # Some compilers have problems with a `.al' extension so
+ # Some compilers have problems with a '.al' extension so
# convenience libraries should have the same extension an
# archive normally would.
oldlibs="$output_objdir/$libname.$libext $oldlibs"
@@ -7301,20 +8834,20 @@ func_mode_link ()
fi
test -n "$vinfo" && \
- func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+ func_warning "'-version-info/-version-number' is ignored for convenience libraries"
test -n "$release" && \
- func_warning "\`-release' is ignored for convenience libraries"
+ func_warning "'-release' is ignored for convenience libraries"
else
# Parse the version information argument.
- save_ifs="$IFS"; IFS=':'
+ save_ifs=$IFS; IFS=:
set dummy $vinfo 0 0 0
shift
- IFS="$save_ifs"
+ IFS=$save_ifs
test -n "$7" && \
- func_fatal_help "too many parameters to \`-version-info'"
+ func_fatal_help "too many parameters to '-version-info'"
# convert absolute version numbers to libtool ages
# this retains compatibility with .la files and attempts
@@ -7322,45 +8855,42 @@ func_mode_link ()
case $vinfo_number in
yes)
- number_major="$1"
- number_minor="$2"
- number_revision="$3"
+ number_major=$1
+ number_minor=$2
+ number_revision=$3
#
# There are really only two kinds -- those that
# use the current revision as the major version
# and those that subtract age and use age as
# a minor version. But, then there is irix
- # which has an extra 1 added just for fun
+ # that has an extra 1 added just for fun
#
case $version_type in
# correct linux to gnu/linux during the next big refactor
- darwin|linux|osf|windows|none)
+ darwin|freebsd-elf|linux|osf|windows|none)
func_arith $number_major + $number_minor
current=$func_arith_result
- age="$number_minor"
- revision="$number_revision"
+ age=$number_minor
+ revision=$number_revision
;;
- freebsd-aout|freebsd-elf|qnx|sunos)
- current="$number_major"
- revision="$number_minor"
- age="0"
+ freebsd-aout|qnx|sunos)
+ current=$number_major
+ revision=$number_minor
+ age=0
;;
irix|nonstopux)
func_arith $number_major + $number_minor
current=$func_arith_result
- age="$number_minor"
- revision="$number_minor"
+ age=$number_minor
+ revision=$number_minor
lt_irix_increment=no
;;
- *)
- func_fatal_configuration "$modename: unknown library version type \`$version_type'"
- ;;
esac
;;
no)
- current="$1"
- revision="$2"
- age="$3"
+ current=$1
+ revision=$2
+ age=$3
;;
esac
@@ -7368,30 +8898,30 @@ func_mode_link ()
case $current in
0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
*)
- func_error "CURRENT \`$current' must be a nonnegative integer"
- func_fatal_error "\`$vinfo' is not valid version information"
+ func_error "CURRENT '$current' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
;;
esac
case $revision in
0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
*)
- func_error "REVISION \`$revision' must be a nonnegative integer"
- func_fatal_error "\`$vinfo' is not valid version information"
+ func_error "REVISION '$revision' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
;;
esac
case $age in
0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
*)
- func_error "AGE \`$age' must be a nonnegative integer"
- func_fatal_error "\`$vinfo' is not valid version information"
+ func_error "AGE '$age' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
;;
esac
if test "$age" -gt "$current"; then
- func_error "AGE \`$age' is greater than the current interface number \`$current'"
- func_fatal_error "\`$vinfo' is not valid version information"
+ func_error "AGE '$age' is greater than the current interface number '$current'"
+ func_fatal_error "'$vinfo' is not valid version information"
fi
# Calculate the version variables.
@@ -7406,26 +8936,36 @@ func_mode_link ()
# verstring for coding it into the library header
func_arith $current - $age
major=.$func_arith_result
- versuffix="$major.$age.$revision"
+ versuffix=$major.$age.$revision
# Darwin ld doesn't like 0 for these options...
func_arith $current + 1
minor_current=$func_arith_result
- xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ # On Darwin other compilers
+ case $CC in
+ nagfor*)
+ verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ ;;
+ *)
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+ esac
;;
freebsd-aout)
- major=".$current"
- versuffix=".$current.$revision";
+ major=.$current
+ versuffix=.$current.$revision
;;
freebsd-elf)
- major=".$current"
- versuffix=".$current"
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
;;
irix | nonstopux)
- if test "X$lt_irix_increment" = "Xno"; then
+ if test no = "$lt_irix_increment"; then
func_arith $current - $age
else
func_arith $current - $age + 1
@@ -7436,69 +8976,74 @@ func_mode_link ()
nonstopux) verstring_prefix=nonstopux ;;
*) verstring_prefix=sgi ;;
esac
- verstring="$verstring_prefix$major.$revision"
+ verstring=$verstring_prefix$major.$revision
# Add in all the interfaces that we are compatible with.
loop=$revision
- while test "$loop" -ne 0; do
+ while test 0 -ne "$loop"; do
func_arith $revision - $loop
iface=$func_arith_result
func_arith $loop - 1
loop=$func_arith_result
- verstring="$verstring_prefix$major.$iface:$verstring"
+ verstring=$verstring_prefix$major.$iface:$verstring
done
- # Before this point, $major must not contain `.'.
+ # Before this point, $major must not contain '.'.
major=.$major
- versuffix="$major.$revision"
+ versuffix=$major.$revision
;;
linux) # correct to gnu/linux during the next big refactor
func_arith $current - $age
major=.$func_arith_result
- versuffix="$major.$age.$revision"
+ versuffix=$major.$age.$revision
;;
osf)
func_arith $current - $age
major=.$func_arith_result
- versuffix=".$current.$age.$revision"
- verstring="$current.$age.$revision"
+ versuffix=.$current.$age.$revision
+ verstring=$current.$age.$revision
# Add in all the interfaces that we are compatible with.
loop=$age
- while test "$loop" -ne 0; do
+ while test 0 -ne "$loop"; do
func_arith $current - $loop
iface=$func_arith_result
func_arith $loop - 1
loop=$func_arith_result
- verstring="$verstring:${iface}.0"
+ verstring=$verstring:$iface.0
done
# Make executables depend on our current version.
- func_append verstring ":${current}.0"
+ func_append verstring ":$current.0"
;;
qnx)
- major=".$current"
- versuffix=".$current"
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sco)
+ major=.$current
+ versuffix=.$current
;;
sunos)
- major=".$current"
- versuffix=".$current.$revision"
+ major=.$current
+ versuffix=.$current.$revision
;;
windows)
# Use '-' rather than '.', since we only want one
- # extension on DOS 8.3 filesystems.
+ # extension on DOS 8.3 file systems.
func_arith $current - $age
major=$func_arith_result
- versuffix="-$major"
+ versuffix=-$major
;;
*)
- func_fatal_configuration "unknown library version type \`$version_type'"
+ func_fatal_configuration "unknown library version type '$version_type'"
;;
esac
@@ -7512,42 +9057,45 @@ func_mode_link ()
verstring=
;;
*)
- verstring="0.0"
+ verstring=0.0
;;
esac
- if test "$need_version" = no; then
+ if test no = "$need_version"; then
versuffix=
else
- versuffix=".0.0"
+ versuffix=.0.0
fi
fi
# Remove version info from name if versioning should be avoided
- if test "$avoid_version" = yes && test "$need_version" = no; then
+ if test yes,no = "$avoid_version,$need_version"; then
major=
versuffix=
- verstring=""
+ verstring=
fi
# Check to see if the archive will have undefined symbols.
- if test "$allow_undefined" = yes; then
- if test "$allow_undefined_flag" = unsupported; then
- func_warning "undefined symbols not allowed in $host shared libraries"
- build_libtool_libs=no
- build_old_libs=yes
+ if test yes = "$allow_undefined"; then
+ if test unsupported = "$allow_undefined_flag"; then
+ if test yes = "$build_old_libs"; then
+ func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+ build_libtool_libs=no
+ else
+ func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+ fi
fi
else
# Don't allow undefined symbols.
- allow_undefined_flag="$no_undefined_flag"
+ allow_undefined_flag=$no_undefined_flag
fi
fi
- func_generate_dlsyms "$libname" "$libname" "yes"
+ func_generate_dlsyms "$libname" "$libname" :
func_append libobjs " $symfileobj"
- test "X$libobjs" = "X " && libobjs=
+ test " " = "$libobjs" && libobjs=
- if test "$opt_mode" != relink; then
+ if test relink != "$opt_mode"; then
# Remove our outputs, but don't remove object files since they
# may have been created when compiling PIC objects.
removelist=
@@ -7556,8 +9104,8 @@ func_mode_link ()
case $p in
*.$objext | *.gcno)
;;
- $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
- if test "X$precious_files_regex" != "X"; then
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+ if test -n "$precious_files_regex"; then
if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
then
continue
@@ -7573,11 +9121,11 @@ func_mode_link ()
fi
# Now set the variables for building old libraries.
- if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
func_append oldlibs " $output_objdir/$libname.$libext"
# Transform .lo files to .o files.
- oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
fi
# Eliminate all temporary directories.
@@ -7598,13 +9146,13 @@ func_mode_link ()
*) func_append finalize_rpath " $libdir" ;;
esac
done
- if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
dependency_libs="$temp_xrpath $dependency_libs"
fi
fi
# Make sure dlfiles contains only unique files that won't be dlpreopened
- old_dlfiles="$dlfiles"
+ old_dlfiles=$dlfiles
dlfiles=
for lib in $old_dlfiles; do
case " $dlprefiles $dlfiles " in
@@ -7614,7 +9162,7 @@ func_mode_link ()
done
# Make sure dlprefiles contains only unique files
- old_dlprefiles="$dlprefiles"
+ old_dlprefiles=$dlprefiles
dlprefiles=
for lib in $old_dlprefiles; do
case "$dlprefiles " in
@@ -7623,7 +9171,7 @@ func_mode_link ()
esac
done
- if test "$build_libtool_libs" = yes; then
+ if test yes = "$build_libtool_libs"; then
if test -n "$rpath"; then
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
@@ -7647,7 +9195,7 @@ func_mode_link ()
;;
*)
# Add libc to deplibs on all other systems if necessary.
- if test "$build_libtool_need_lc" = "yes"; then
+ if test yes = "$build_libtool_need_lc"; then
func_append deplibs " -lc"
fi
;;
@@ -7663,9 +9211,9 @@ func_mode_link ()
# I'm not sure if I'm treating the release correctly. I think
# release should show up in the -l (ie -lgmp5) so we don't want to
# add it in twice. Is that correct?
- release=""
- versuffix=""
- major=""
+ release=
+ versuffix=
+ major=
newdeplibs=
droppeddeps=no
case $deplibs_check_method in
@@ -7694,20 +9242,20 @@ EOF
-l*)
func_stripname -l '' "$i"
name=$func_stripname_result
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
case " $predeps $postdeps " in
*" $i "*)
func_append newdeplibs " $i"
- i=""
+ i=
;;
esac
fi
- if test -n "$i" ; then
+ if test -n "$i"; then
libname=`eval "\\$ECHO \"$libname_spec\""`
deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
set dummy $deplib_matches; shift
deplib_match=$1
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
func_append newdeplibs " $i"
else
droppeddeps=yes
@@ -7737,20 +9285,20 @@ EOF
$opt_dry_run || $RM conftest
if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
ldd_output=`ldd conftest`
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
case " $predeps $postdeps " in
*" $i "*)
func_append newdeplibs " $i"
- i=""
+ i=
;;
esac
fi
- if test -n "$i" ; then
+ if test -n "$i"; then
libname=`eval "\\$ECHO \"$libname_spec\""`
deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
set dummy $deplib_matches; shift
deplib_match=$1
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
func_append newdeplibs " $i"
else
droppeddeps=yes
@@ -7787,24 +9335,24 @@ EOF
-l*)
func_stripname -l '' "$a_deplib"
name=$func_stripname_result
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
case " $predeps $postdeps " in
*" $a_deplib "*)
func_append newdeplibs " $a_deplib"
- a_deplib=""
+ a_deplib=
;;
esac
fi
- if test -n "$a_deplib" ; then
+ if test -n "$a_deplib"; then
libname=`eval "\\$ECHO \"$libname_spec\""`
if test -n "$file_magic_glob"; then
libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
else
libnameglob=$libname
fi
- test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+ test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- if test "$want_nocaseglob" = yes; then
+ if test yes = "$want_nocaseglob"; then
shopt -s nocaseglob
potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
$nocaseglob
@@ -7822,25 +9370,25 @@ EOF
# We might still enter an endless loop, since a link
# loop can be closed while we follow links,
# but so what?
- potlib="$potent_lib"
+ potlib=$potent_lib
while test -h "$potlib" 2>/dev/null; do
- potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
case $potliblink in
- [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
- *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+ [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+ *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
esac
done
if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
$SED -e 10q |
$EGREP "$file_magic_regex" > /dev/null; then
func_append newdeplibs " $a_deplib"
- a_deplib=""
+ a_deplib=
break 2
fi
done
done
fi
- if test -n "$a_deplib" ; then
+ if test -n "$a_deplib"; then
droppeddeps=yes
echo
$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
@@ -7848,7 +9396,7 @@ EOF
echo "*** you link to this library. But I can only do this if you have a"
echo "*** shared version of the library, which you do not appear to have"
echo "*** because I did check the linker path looking for a file starting"
- if test -z "$potlib" ; then
+ if test -z "$potlib"; then
$ECHO "*** with $libname but no candidates were found. (...for file magic test)"
else
$ECHO "*** with $libname and none of the candidates passed a file format test"
@@ -7871,30 +9419,30 @@ EOF
-l*)
func_stripname -l '' "$a_deplib"
name=$func_stripname_result
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
case " $predeps $postdeps " in
*" $a_deplib "*)
func_append newdeplibs " $a_deplib"
- a_deplib=""
+ a_deplib=
;;
esac
fi
- if test -n "$a_deplib" ; then
+ if test -n "$a_deplib"; then
libname=`eval "\\$ECHO \"$libname_spec\""`
for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
for potent_lib in $potential_libs; do
- potlib="$potent_lib" # see symlink-check above in file_magic test
+ potlib=$potent_lib # see symlink-check above in file_magic test
if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
$EGREP "$match_pattern_regex" > /dev/null; then
func_append newdeplibs " $a_deplib"
- a_deplib=""
+ a_deplib=
break 2
fi
done
done
fi
- if test -n "$a_deplib" ; then
+ if test -n "$a_deplib"; then
droppeddeps=yes
echo
$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
@@ -7902,7 +9450,7 @@ EOF
echo "*** you link to this library. But I can only do this if you have a"
echo "*** shared version of the library, which you do not appear to have"
echo "*** because I did check the linker path looking for a file starting"
- if test -z "$potlib" ; then
+ if test -z "$potlib"; then
$ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
else
$ECHO "*** with $libname and none of the candidates passed a file format test"
@@ -7918,18 +9466,18 @@ EOF
done # Gone through all deplibs.
;;
none | unknown | *)
- newdeplibs=""
+ newdeplibs=
tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
- if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
- for i in $predeps $postdeps ; do
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ for i in $predeps $postdeps; do
# can't use Xsed below, because $i might contain '/'
- tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
done
fi
case $tmp_deplibs in
*[!\ \ ]*)
echo
- if test "X$deplibs_check_method" = "Xnone"; then
+ if test none = "$deplibs_check_method"; then
echo "*** Warning: inter-library dependencies are not supported in this platform."
else
echo "*** Warning: inter-library dependencies are not known to be supported."
@@ -7953,8 +9501,8 @@ EOF
;;
esac
- if test "$droppeddeps" = yes; then
- if test "$module" = yes; then
+ if test yes = "$droppeddeps"; then
+ if test yes = "$module"; then
echo
echo "*** Warning: libtool could not satisfy all declared inter-library"
$ECHO "*** dependencies of module $libname. Therefore, libtool will create"
@@ -7963,12 +9511,12 @@ EOF
if test -z "$global_symbol_pipe"; then
echo
echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
fi
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
build_libtool_libs=module
build_old_libs=yes
else
@@ -7979,14 +9527,14 @@ EOF
echo "*** automatically added whenever a program is linked with this library"
echo "*** or is declared to -dlopen it."
- if test "$allow_undefined" = no; then
+ if test no = "$allow_undefined"; then
echo
echo "*** Since this library must not contain undefined symbols,"
echo "*** because either the platform does not support them or"
echo "*** it was explicitly requested with -no-undefined,"
echo "*** libtool will only create a static version of it."
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
build_libtool_libs=module
build_old_libs=yes
else
@@ -8032,7 +9580,7 @@ EOF
*) func_append new_libs " $deplib" ;;
esac
done
- deplibs="$new_libs"
+ deplibs=$new_libs
# All the library-specific variables (install_libdir is set above).
library_names=
@@ -8040,25 +9588,25 @@ EOF
dlname=
# Test again, we may have decided not to build it any more
- if test "$build_libtool_libs" = yes; then
- # Remove ${wl} instances when linking with ld.
+ if test yes = "$build_libtool_libs"; then
+ # Remove $wl instances when linking with ld.
# FIXME: should test the right _cmds variable.
case $archive_cmds in
*\$LD\ *) wl= ;;
esac
- if test "$hardcode_into_libs" = yes; then
+ if test yes = "$hardcode_into_libs"; then
# Hardcode the library paths
hardcode_libdirs=
dep_rpath=
- rpath="$finalize_rpath"
- test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+ rpath=$finalize_rpath
+ test relink = "$opt_mode" || rpath=$compile_rpath$rpath
for libdir in $rpath; do
if test -n "$hardcode_libdir_flag_spec"; then
if test -n "$hardcode_libdir_separator"; then
func_replace_sysroot "$libdir"
libdir=$func_replace_sysroot_result
if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
+ hardcode_libdirs=$libdir
else
# Just accumulate the unique libdirs.
case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
@@ -8083,7 +9631,7 @@ EOF
# Substitute the hardcoded libdirs into the rpath.
if test -n "$hardcode_libdir_separator" &&
test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
+ libdir=$hardcode_libdirs
eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
fi
if test -n "$runpath_var" && test -n "$perm_rpath"; then
@@ -8097,8 +9645,8 @@ EOF
test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
fi
- shlibpath="$finalize_shlibpath"
- test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ shlibpath=$finalize_shlibpath
+ test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
if test -n "$shlibpath"; then
eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
fi
@@ -8108,19 +9656,19 @@ EOF
eval library_names=\"$library_names_spec\"
set dummy $library_names
shift
- realname="$1"
+ realname=$1
shift
if test -n "$soname_spec"; then
eval soname=\"$soname_spec\"
else
- soname="$realname"
+ soname=$realname
fi
if test -z "$dlname"; then
dlname=$soname
fi
- lib="$output_objdir/$realname"
+ lib=$output_objdir/$realname
linknames=
for link
do
@@ -8134,7 +9682,7 @@ EOF
delfiles=
if test -n "$export_symbols" && test -n "$include_expsyms"; then
$opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
- export_symbols="$output_objdir/$libname.uexp"
+ export_symbols=$output_objdir/$libname.uexp
func_append delfiles " $export_symbols"
fi
@@ -8143,31 +9691,31 @@ EOF
cygwin* | mingw* | cegcc*)
if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
# exporting using user supplied symfile
- if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+ func_dll_def_p "$export_symbols" || {
# and it's NOT already a .def file. Must figure out
# which of the given symbols are data symbols and tag
# them as such. So, trigger use of export_symbols_cmds.
# export_symbols gets reassigned inside the "prepare
# the list of exported symbols" if statement, so the
# include_expsyms logic still works.
- orig_export_symbols="$export_symbols"
+ orig_export_symbols=$export_symbols
export_symbols=
always_export_symbols=yes
- fi
+ }
fi
;;
esac
# Prepare the list of exported symbols
if test -z "$export_symbols"; then
- if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
- func_verbose "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
+ if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
$opt_dry_run || $RM $export_symbols
cmds=$export_symbols_cmds
- save_ifs="$IFS"; IFS='~'
+ save_ifs=$IFS; IFS='~'
for cmd1 in $cmds; do
- IFS="$save_ifs"
+ IFS=$save_ifs
# Take the normal branch if the nm_file_list_spec branch
# doesn't work or if tool conversion is not needed.
case $nm_file_list_spec~$to_tool_file_cmd in
@@ -8181,7 +9729,7 @@ EOF
try_normal_branch=no
;;
esac
- if test "$try_normal_branch" = yes \
+ if test yes = "$try_normal_branch" \
&& { test "$len" -lt "$max_cmd_len" \
|| test "$max_cmd_len" -le -1; }
then
@@ -8192,7 +9740,7 @@ EOF
output_la=$func_basename_result
save_libobjs=$libobjs
save_output=$output
- output=${output_objdir}/${output_la}.nm
+ output=$output_objdir/$output_la.nm
func_to_tool_file "$output"
libobjs=$nm_file_list_spec$func_to_tool_file_result
func_append delfiles " $output"
@@ -8215,8 +9763,8 @@ EOF
break
fi
done
- IFS="$save_ifs"
- if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+ IFS=$save_ifs
+ if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
fi
@@ -8224,16 +9772,16 @@ EOF
fi
if test -n "$export_symbols" && test -n "$include_expsyms"; then
- tmp_export_symbols="$export_symbols"
- test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
$opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
fi
- if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+ if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
# The given exports_symbols file has to be filtered, so filter it.
- func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
# FIXME: $output_objdir/$libname.filter potentially contains lots of
- # 's' commands which not all seds can handle. GNU sed should be fine
+ # 's' commands, which not all seds can handle. GNU sed should be fine
# though. Also, the filter scales superlinearly with the number of
# global variables. join(1) would be nice here, but unfortunately
# isn't a blessed tool.
@@ -8252,11 +9800,11 @@ EOF
;;
esac
done
- deplibs="$tmp_deplibs"
+ deplibs=$tmp_deplibs
if test -n "$convenience"; then
if test -n "$whole_archive_flag_spec" &&
- test "$compiler_needs_object" = yes &&
+ test yes = "$compiler_needs_object" &&
test -z "$libobjs"; then
# extract the archives, so we have objects to list.
# TODO: could optimize this to just extract one archive.
@@ -8267,7 +9815,7 @@ EOF
eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
test "X$libobjs" = "X " && libobjs=
else
- gentop="$output_objdir/${outputname}x"
+ gentop=$output_objdir/${outputname}x
func_append generated " $gentop"
func_extract_archives $gentop $convenience
@@ -8276,18 +9824,18 @@ EOF
fi
fi
- if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
eval flag=\"$thread_safe_flag_spec\"
func_append linker_flags " $flag"
fi
# Make a backup of the uninstalled library when relinking
- if test "$opt_mode" = relink; then
+ if test relink = "$opt_mode"; then
$opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
fi
# Do each of the archive commands.
- if test "$module" = yes && test -n "$module_cmds" ; then
+ if test yes = "$module" && test -n "$module_cmds"; then
if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
eval test_cmds=\"$module_expsym_cmds\"
cmds=$module_expsym_cmds
@@ -8305,7 +9853,7 @@ EOF
fi
fi
- if test "X$skipped_export" != "X:" &&
+ if test : != "$skipped_export" &&
func_len " $test_cmds" &&
len=$func_len_result &&
test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
@@ -8338,8 +9886,8 @@ EOF
last_robj=
k=1
- if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
- output=${output_objdir}/${output_la}.lnkscript
+ if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+ output=$output_objdir/$output_la.lnkscript
func_verbose "creating GNU ld script: $output"
echo 'INPUT (' > $output
for obj in $save_libobjs
@@ -8351,14 +9899,14 @@ EOF
func_append delfiles " $output"
func_to_tool_file "$output"
output=$func_to_tool_file_result
- elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
- output=${output_objdir}/${output_la}.lnk
+ elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+ output=$output_objdir/$output_la.lnk
func_verbose "creating linker input file list: $output"
: > $output
set x $save_libobjs
shift
firstobj=
- if test "$compiler_needs_object" = yes; then
+ if test yes = "$compiler_needs_object"; then
firstobj="$1 "
shift
fi
@@ -8373,7 +9921,7 @@ EOF
else
if test -n "$save_libobjs"; then
func_verbose "creating reloadable object files..."
- output=$output_objdir/$output_la-${k}.$objext
+ output=$output_objdir/$output_la-$k.$objext
eval test_cmds=\"$reload_cmds\"
func_len " $test_cmds"
len0=$func_len_result
@@ -8385,13 +9933,13 @@ EOF
func_len " $obj"
func_arith $len + $func_len_result
len=$func_arith_result
- if test "X$objlist" = X ||
+ if test -z "$objlist" ||
test "$len" -lt "$max_cmd_len"; then
func_append objlist " $obj"
else
# The command $test_cmds is almost too long, add a
# command to the queue.
- if test "$k" -eq 1 ; then
+ if test 1 -eq "$k"; then
# The first file doesn't have a previous command to add.
reload_objs=$objlist
eval concat_cmds=\"$reload_cmds\"
@@ -8401,10 +9949,10 @@ EOF
reload_objs="$objlist $last_robj"
eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
fi
- last_robj=$output_objdir/$output_la-${k}.$objext
+ last_robj=$output_objdir/$output_la-$k.$objext
func_arith $k + 1
k=$func_arith_result
- output=$output_objdir/$output_la-${k}.$objext
+ output=$output_objdir/$output_la-$k.$objext
objlist=" $obj"
func_len " $last_robj"
func_arith $len0 + $func_len_result
@@ -8416,9 +9964,9 @@ EOF
# files will link in the last one created.
test -z "$concat_cmds" || concat_cmds=$concat_cmds~
reload_objs="$objlist $last_robj"
- eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+ eval concat_cmds=\"\$concat_cmds$reload_cmds\"
if test -n "$last_robj"; then
- eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
fi
func_append delfiles " $output"
@@ -8426,9 +9974,9 @@ EOF
output=
fi
- if ${skipped_export-false}; then
- func_verbose "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
+ ${skipped_export-false} && {
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
$opt_dry_run || $RM $export_symbols
libobjs=$output
# Append the command to create the export file.
@@ -8437,16 +9985,16 @@ EOF
if test -n "$last_robj"; then
eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
fi
- fi
+ }
test -n "$save_libobjs" &&
func_verbose "creating a temporary reloadable object file: $output"
# Loop through the commands generated above and execute them.
- save_ifs="$IFS"; IFS='~'
+ save_ifs=$IFS; IFS='~'
for cmd in $concat_cmds; do
- IFS="$save_ifs"
- $opt_silent || {
+ IFS=$save_ifs
+ $opt_quiet || {
func_quote_for_expand "$cmd"
eval "func_echo $func_quote_for_expand_result"
}
@@ -8454,7 +10002,7 @@ EOF
lt_exit=$?
# Restore the uninstalled library and exit
- if test "$opt_mode" = relink; then
+ if test relink = "$opt_mode"; then
( cd "$output_objdir" && \
$RM "${realname}T" && \
$MV "${realname}U" "$realname" )
@@ -8463,7 +10011,7 @@ EOF
exit $lt_exit
}
done
- IFS="$save_ifs"
+ IFS=$save_ifs
if test -n "$export_symbols_regex" && ${skipped_export-false}; then
func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
@@ -8471,18 +10019,18 @@ EOF
fi
fi
- if ${skipped_export-false}; then
+ ${skipped_export-false} && {
if test -n "$export_symbols" && test -n "$include_expsyms"; then
- tmp_export_symbols="$export_symbols"
- test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
$opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
fi
if test -n "$orig_export_symbols"; then
# The given exports_symbols file has to be filtered, so filter it.
- func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
# FIXME: $output_objdir/$libname.filter potentially contains lots of
- # 's' commands which not all seds can handle. GNU sed should be fine
+ # 's' commands, which not all seds can handle. GNU sed should be fine
# though. Also, the filter scales superlinearly with the number of
# global variables. join(1) would be nice here, but unfortunately
# isn't a blessed tool.
@@ -8491,7 +10039,7 @@ EOF
export_symbols=$output_objdir/$libname.def
$opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
fi
- fi
+ }
libobjs=$output
# Restore the value of output.
@@ -8505,7 +10053,7 @@ EOF
# value of $libobjs for piecewise linking.
# Do each of the archive commands.
- if test "$module" = yes && test -n "$module_cmds" ; then
+ if test yes = "$module" && test -n "$module_cmds"; then
if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
cmds=$module_expsym_cmds
else
@@ -8527,7 +10075,7 @@ EOF
# Add any objects from preloaded convenience libraries
if test -n "$dlprefiles"; then
- gentop="$output_objdir/${outputname}x"
+ gentop=$output_objdir/${outputname}x
func_append generated " $gentop"
func_extract_archives $gentop $dlprefiles
@@ -8535,11 +10083,12 @@ EOF
test "X$libobjs" = "X " && libobjs=
fi
- save_ifs="$IFS"; IFS='~'
+ save_ifs=$IFS; IFS='~'
for cmd in $cmds; do
- IFS="$save_ifs"
+ IFS=$sp$nl
eval cmd=\"$cmd\"
- $opt_silent || {
+ IFS=$save_ifs
+ $opt_quiet || {
func_quote_for_expand "$cmd"
eval "func_echo $func_quote_for_expand_result"
}
@@ -8547,7 +10096,7 @@ EOF
lt_exit=$?
# Restore the uninstalled library and exit
- if test "$opt_mode" = relink; then
+ if test relink = "$opt_mode"; then
( cd "$output_objdir" && \
$RM "${realname}T" && \
$MV "${realname}U" "$realname" )
@@ -8556,10 +10105,10 @@ EOF
exit $lt_exit
}
done
- IFS="$save_ifs"
+ IFS=$save_ifs
# Restore the uninstalled library and exit
- if test "$opt_mode" = relink; then
+ if test relink = "$opt_mode"; then
$opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
if test -n "$convenience"; then
@@ -8579,39 +10128,39 @@ EOF
done
# If -module or -export-dynamic was specified, set the dlname.
- if test "$module" = yes || test "$export_dynamic" = yes; then
+ if test yes = "$module" || test yes = "$export_dynamic"; then
# On all known operating systems, these are identical.
- dlname="$soname"
+ dlname=$soname
fi
fi
;;
obj)
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- func_warning "\`-dlopen' is ignored for objects"
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for objects"
fi
case " $deplibs" in
*\ -l* | *\ -L*)
- func_warning "\`-l' and \`-L' are ignored for objects" ;;
+ func_warning "'-l' and '-L' are ignored for objects" ;;
esac
test -n "$rpath" && \
- func_warning "\`-rpath' is ignored for objects"
+ func_warning "'-rpath' is ignored for objects"
test -n "$xrpath" && \
- func_warning "\`-R' is ignored for objects"
+ func_warning "'-R' is ignored for objects"
test -n "$vinfo" && \
- func_warning "\`-version-info' is ignored for objects"
+ func_warning "'-version-info' is ignored for objects"
test -n "$release" && \
- func_warning "\`-release' is ignored for objects"
+ func_warning "'-release' is ignored for objects"
case $output in
*.lo)
test -n "$objs$old_deplibs" && \
- func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+ func_fatal_error "cannot build library object '$output' from non-libtool objects"
libobj=$output
func_lo2o "$libobj"
@@ -8619,7 +10168,7 @@ EOF
;;
*)
libobj=
- obj="$output"
+ obj=$output
;;
esac
@@ -8632,17 +10181,19 @@ EOF
# the extraction.
reload_conv_objs=
gentop=
- # reload_cmds runs $LD directly, so let us get rid of
- # -Wl from whole_archive_flag_spec and hope we can get by with
- # turning comma into space..
- wl=
-
+ # if reload_cmds runs $LD directly, get rid of -Wl from
+ # whole_archive_flag_spec and hope we can get by with turning comma
+ # into space.
+ case $reload_cmds in
+ *\$LD[\ \$]*) wl= ;;
+ esac
if test -n "$convenience"; then
if test -n "$whole_archive_flag_spec"; then
eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
- reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
else
- gentop="$output_objdir/${obj}x"
+ gentop=$output_objdir/${obj}x
func_append generated " $gentop"
func_extract_archives $gentop $convenience
@@ -8651,12 +10202,12 @@ EOF
fi
# If we're not building shared, we need to use non_pic_objs
- test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+ test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
# Create the old-style object.
- reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+ reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
- output="$obj"
+ output=$obj
func_execute_cmds "$reload_cmds" 'exit $?'
# Exit if we aren't doing a library object file.
@@ -8668,7 +10219,7 @@ EOF
exit $EXIT_SUCCESS
fi
- if test "$build_libtool_libs" != yes; then
+ test yes = "$build_libtool_libs" || {
if test -n "$gentop"; then
func_show_eval '${RM}r "$gentop"'
fi
@@ -8678,12 +10229,12 @@ EOF
# $show "echo timestamp > $libobj"
# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
exit $EXIT_SUCCESS
- fi
+ }
- if test -n "$pic_flag" || test "$pic_mode" != default; then
+ if test -n "$pic_flag" || test default != "$pic_mode"; then
# Only do commands if we really have different PIC objects.
reload_objs="$libobjs $reload_conv_objs"
- output="$libobj"
+ output=$libobj
func_execute_cmds "$reload_cmds" 'exit $?'
fi
@@ -8700,16 +10251,14 @@ EOF
output=$func_stripname_result.exe;;
esac
test -n "$vinfo" && \
- func_warning "\`-version-info' is ignored for programs"
+ func_warning "'-version-info' is ignored for programs"
test -n "$release" && \
- func_warning "\`-release' is ignored for programs"
+ func_warning "'-release' is ignored for programs"
- test "$preload" = yes \
- && test "$dlopen_support" = unknown \
- && test "$dlopen_self" = unknown \
- && test "$dlopen_self_static" = unknown && \
- func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+ $preload \
+ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
case $host in
*-*-rhapsody* | *-*-darwin1.[012])
@@ -8723,11 +10272,11 @@ EOF
*-*-darwin*)
# Don't allow lazy linking, it breaks C++ global constructors
# But is supposedly fixed on 10.4 or later (yay!).
- if test "$tagname" = CXX ; then
+ if test CXX = "$tagname"; then
case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
10.[0123])
- func_append compile_command " ${wl}-bind_at_load"
- func_append finalize_command " ${wl}-bind_at_load"
+ func_append compile_command " $wl-bind_at_load"
+ func_append finalize_command " $wl-bind_at_load"
;;
esac
fi
@@ -8763,7 +10312,7 @@ EOF
*) func_append new_libs " $deplib" ;;
esac
done
- compile_deplibs="$new_libs"
+ compile_deplibs=$new_libs
func_append compile_command " $compile_deplibs"
@@ -8787,7 +10336,7 @@ EOF
if test -n "$hardcode_libdir_flag_spec"; then
if test -n "$hardcode_libdir_separator"; then
if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
+ hardcode_libdirs=$libdir
else
# Just accumulate the unique libdirs.
case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
@@ -8810,7 +10359,7 @@ EOF
fi
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
- testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+ testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
case :$dllsearchpath: in
*":$libdir:"*) ;;
::) dllsearchpath=$libdir;;
@@ -8827,10 +10376,10 @@ EOF
# Substitute the hardcoded libdirs into the rpath.
if test -n "$hardcode_libdir_separator" &&
test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
+ libdir=$hardcode_libdirs
eval rpath=\" $hardcode_libdir_flag_spec\"
fi
- compile_rpath="$rpath"
+ compile_rpath=$rpath
rpath=
hardcode_libdirs=
@@ -8838,7 +10387,7 @@ EOF
if test -n "$hardcode_libdir_flag_spec"; then
if test -n "$hardcode_libdir_separator"; then
if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
+ hardcode_libdirs=$libdir
else
# Just accumulate the unique libdirs.
case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
@@ -8863,45 +10412,43 @@ EOF
# Substitute the hardcoded libdirs into the rpath.
if test -n "$hardcode_libdir_separator" &&
test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
+ libdir=$hardcode_libdirs
eval rpath=\" $hardcode_libdir_flag_spec\"
fi
- finalize_rpath="$rpath"
+ finalize_rpath=$rpath
- if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ if test -n "$libobjs" && test yes = "$build_old_libs"; then
# Transform all the library objects into standard objects.
compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
fi
- func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+ func_generate_dlsyms "$outputname" "@PROGRAM@" false
# template prelinking step
if test -n "$prelink_cmds"; then
func_execute_cmds "$prelink_cmds" 'exit $?'
fi
- wrappers_required=yes
+ wrappers_required=:
case $host in
*cegcc* | *mingw32ce*)
# Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
- wrappers_required=no
+ wrappers_required=false
;;
*cygwin* | *mingw* )
- if test "$build_libtool_libs" != yes; then
- wrappers_required=no
- fi
+ test yes = "$build_libtool_libs" || wrappers_required=false
;;
*)
- if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
- wrappers_required=no
+ if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+ wrappers_required=false
fi
;;
esac
- if test "$wrappers_required" = no; then
+ $wrappers_required || {
# Replace the output file specification.
compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
- link_command="$compile_command$compile_rpath"
+ link_command=$compile_command$compile_rpath
# We have no uninstalled library dependencies, so finalize right now.
exit_status=0
@@ -8914,12 +10461,12 @@ EOF
fi
# Delete the generated files.
- if test -f "$output_objdir/${outputname}S.${objext}"; then
- func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+ if test -f "$output_objdir/${outputname}S.$objext"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
fi
exit $exit_status
- fi
+ }
if test -n "$compile_shlibpath$finalize_shlibpath"; then
compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
@@ -8949,9 +10496,9 @@ EOF
fi
fi
- if test "$no_install" = yes; then
+ if test yes = "$no_install"; then
# We don't need to create a wrapper script.
- link_command="$compile_var$compile_command$compile_rpath"
+ link_command=$compile_var$compile_command$compile_rpath
# Replace the output file specification.
link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
# Delete the old output file.
@@ -8968,27 +10515,28 @@ EOF
exit $EXIT_SUCCESS
fi
- if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
+ case $hardcode_action,$fast_install in
+ relink,*)
+ # Fast installation is not supported
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
- func_warning "this platform does not like uninstalled shared libraries"
- func_warning "\`$output' will be relinked during installation"
- else
- if test "$fast_install" != no; then
- link_command="$finalize_var$compile_command$finalize_rpath"
- if test "$fast_install" = yes; then
- relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
- else
- # fast_install is set to needless
- relink_command=
- fi
- else
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
- fi
- fi
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "'$output' will be relinked during installation"
+ ;;
+ *,yes)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ ;;
+ *,no)
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+ ;;
+ *,needless)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=
+ ;;
+ esac
# Replace the output file specification.
link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
@@ -9020,8 +10568,8 @@ EOF
relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
fi
done
- relink_command="(cd `pwd`; $relink_command)"
- relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ func_quote "(cd `pwd`; $relink_command)"
+ relink_command=$func_quote_result
fi
# Only actually do things if not in dry run mode.
@@ -9045,8 +10593,8 @@ EOF
func_dirname_and_basename "$output" "" "."
output_name=$func_basename_result
output_path=$func_dirname_result
- cwrappersource="$output_path/$objdir/lt-$output_name.c"
- cwrapper="$output_path/$output_name.exe"
+ cwrappersource=$output_path/$objdir/lt-$output_name.c
+ cwrapper=$output_path/$output_name.exe
$RM $cwrappersource $cwrapper
trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
@@ -9067,7 +10615,7 @@ EOF
trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
$opt_dry_run || {
# note: this script will not be executed, so do not chmod.
- if test "x$build" = "x$host" ; then
+ if test "x$build" = "x$host"; then
$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
else
func_emit_wrapper no > $func_ltwrapper_scriptname_result
@@ -9090,25 +10638,27 @@ EOF
# See if we need to build an old-fashioned archive.
for oldlib in $oldlibs; do
- if test "$build_libtool_libs" = convenience; then
- oldobjs="$libobjs_save $symfileobj"
- addlibs="$convenience"
- build_libtool_libs=no
- else
- if test "$build_libtool_libs" = module; then
- oldobjs="$libobjs_save"
+ case $build_libtool_libs in
+ convenience)
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs=$convenience
build_libtool_libs=no
- else
+ ;;
+ module)
+ oldobjs=$libobjs_save
+ addlibs=$old_convenience
+ build_libtool_libs=no
+ ;;
+ *)
oldobjs="$old_deplibs $non_pic_objects"
- if test "$preload" = yes && test -f "$symfileobj"; then
- func_append oldobjs " $symfileobj"
- fi
- fi
- addlibs="$old_convenience"
- fi
+ $preload && test -f "$symfileobj" \
+ && func_append oldobjs " $symfileobj"
+ addlibs=$old_convenience
+ ;;
+ esac
if test -n "$addlibs"; then
- gentop="$output_objdir/${outputname}x"
+ gentop=$output_objdir/${outputname}x
func_append generated " $gentop"
func_extract_archives $gentop $addlibs
@@ -9116,13 +10666,13 @@ EOF
fi
# Do each command in the archive commands.
- if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
cmds=$old_archive_from_new_cmds
else
# Add any objects from preloaded convenience libraries
if test -n "$dlprefiles"; then
- gentop="$output_objdir/${outputname}x"
+ gentop=$output_objdir/${outputname}x
func_append generated " $gentop"
func_extract_archives $gentop $dlprefiles
@@ -9143,7 +10693,7 @@ EOF
:
else
echo "copying selected object files to avoid basename conflicts..."
- gentop="$output_objdir/${outputname}x"
+ gentop=$output_objdir/${outputname}x
func_append generated " $gentop"
func_mkdir_p "$gentop"
save_oldobjs=$oldobjs
@@ -9152,7 +10702,7 @@ EOF
for obj in $save_oldobjs
do
func_basename "$obj"
- objbase="$func_basename_result"
+ objbase=$func_basename_result
case " $oldobjs " in
" ") oldobjs=$obj ;;
*[\ /]"$objbase "*)
@@ -9221,18 +10771,18 @@ EOF
else
# the above command should be used before it gets too long
oldobjs=$objlist
- if test "$obj" = "$last_oldobj" ; then
+ if test "$obj" = "$last_oldobj"; then
RANLIB=$save_RANLIB
fi
test -z "$concat_cmds" || concat_cmds=$concat_cmds~
- eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
objlist=
len=$len0
fi
done
RANLIB=$save_RANLIB
oldobjs=$objlist
- if test "X$oldobjs" = "X" ; then
+ if test -z "$oldobjs"; then
eval cmds=\"\$concat_cmds\"
else
eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
@@ -9249,7 +10799,7 @@ EOF
case $output in
*.la)
old_library=
- test "$build_old_libs" = yes && old_library="$libname.$libext"
+ test yes = "$build_old_libs" && old_library=$libname.$libext
func_verbose "creating $output"
# Preserve any variables that may affect compiler behavior
@@ -9264,31 +10814,32 @@ EOF
fi
done
# Quote the link command for shipping.
- relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
- relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
- if test "$hardcode_automatic" = yes ; then
+ relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ func_quote "$relink_command"
+ relink_command=$func_quote_result
+ if test yes = "$hardcode_automatic"; then
relink_command=
fi
# Only create the output if not a dry run.
$opt_dry_run || {
for installed in no yes; do
- if test "$installed" = yes; then
+ if test yes = "$installed"; then
if test -z "$install_libdir"; then
break
fi
- output="$output_objdir/$outputname"i
+ output=$output_objdir/${outputname}i
# Replace all uninstalled libtool libraries with the installed ones
newdependency_libs=
for deplib in $dependency_libs; do
case $deplib in
*.la)
func_basename "$deplib"
- name="$func_basename_result"
+ name=$func_basename_result
func_resolve_sysroot "$deplib"
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
test -z "$libdir" && \
- func_fatal_error "\`$deplib' is not a valid libtool archive"
+ func_fatal_error "'$deplib' is not a valid libtool archive"
func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
;;
-L*)
@@ -9304,23 +10855,23 @@ EOF
*) func_append newdependency_libs " $deplib" ;;
esac
done
- dependency_libs="$newdependency_libs"
+ dependency_libs=$newdependency_libs
newdlfiles=
for lib in $dlfiles; do
case $lib in
*.la)
func_basename "$lib"
- name="$func_basename_result"
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
test -z "$libdir" && \
- func_fatal_error "\`$lib' is not a valid libtool archive"
+ func_fatal_error "'$lib' is not a valid libtool archive"
func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
;;
*) func_append newdlfiles " $lib" ;;
esac
done
- dlfiles="$newdlfiles"
+ dlfiles=$newdlfiles
newdlprefiles=
for lib in $dlprefiles; do
case $lib in
@@ -9330,34 +10881,34 @@ EOF
# didn't already link the preopened objects directly into
# the library:
func_basename "$lib"
- name="$func_basename_result"
- eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
test -z "$libdir" && \
- func_fatal_error "\`$lib' is not a valid libtool archive"
+ func_fatal_error "'$lib' is not a valid libtool archive"
func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
;;
esac
done
- dlprefiles="$newdlprefiles"
+ dlprefiles=$newdlprefiles
else
newdlfiles=
for lib in $dlfiles; do
case $lib in
- [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
*) abs=`pwd`"/$lib" ;;
esac
func_append newdlfiles " $abs"
done
- dlfiles="$newdlfiles"
+ dlfiles=$newdlfiles
newdlprefiles=
for lib in $dlprefiles; do
case $lib in
- [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
*) abs=`pwd`"/$lib" ;;
esac
func_append newdlprefiles " $abs"
done
- dlprefiles="$newdlprefiles"
+ dlprefiles=$newdlprefiles
fi
$RM $output
# place dlname in correct position for cygwin
@@ -9373,10 +10924,9 @@ EOF
case $host,$output,$installed,$module,$dlname in
*cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
# If a -bindir argument was supplied, place the dll there.
- if test "x$bindir" != x ;
- then
+ if test -n "$bindir"; then
func_relative_path "$install_libdir" "$bindir"
- tdlname=$func_relative_path_result$dlname
+ tdlname=$func_relative_path_result/$dlname
else
# Otherwise fall back on heuristic.
tdlname=../bin/$dlname
@@ -9385,7 +10935,7 @@ EOF
esac
$ECHO > $output "\
# $outputname - a libtool library file
-# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
#
# Please DO NOT delete this file!
# It is necessary for linking the library.
@@ -9399,7 +10949,7 @@ library_names='$library_names'
# The name of the static archive.
old_library='$old_library'
-# Linker flags that can not go in dependency_libs.
+# Linker flags that cannot go in dependency_libs.
inherited_linker_flags='$new_inherited_linker_flags'
# Libraries that this one depends upon.
@@ -9425,7 +10975,7 @@ dlpreopen='$dlprefiles'
# Directory that this library needs to be installed in:
libdir='$install_libdir'"
- if test "$installed" = no && test "$need_relink" = yes; then
+ if test no,yes = "$installed,$need_relink"; then
$ECHO >> $output "\
relink_command=\"$relink_command\""
fi
@@ -9440,27 +10990,29 @@ relink_command=\"$relink_command\""
exit $EXIT_SUCCESS
}
-{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
- func_mode_link ${1+"$@"}
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+ func_mode_link ${1+"$@"}
+fi
# func_mode_uninstall arg...
func_mode_uninstall ()
{
- $opt_debug
- RM="$nonopt"
+ $debug_cmd
+
+ RM=$nonopt
files=
- rmforce=
+ rmforce=false
exit_status=0
# This variable tells wrapper scripts just to set variables rather
# than running their programs.
- libtool_install_magic="$magic"
+ libtool_install_magic=$magic
for arg
do
case $arg in
- -f) func_append RM " $arg"; rmforce=yes ;;
+ -f) func_append RM " $arg"; rmforce=: ;;
-*) func_append RM " $arg" ;;
*) func_append files " $arg" ;;
esac
@@ -9473,18 +11025,18 @@ func_mode_uninstall ()
for file in $files; do
func_dirname "$file" "" "."
- dir="$func_dirname_result"
- if test "X$dir" = X.; then
- odir="$objdir"
+ dir=$func_dirname_result
+ if test . = "$dir"; then
+ odir=$objdir
else
- odir="$dir/$objdir"
+ odir=$dir/$objdir
fi
func_basename "$file"
- name="$func_basename_result"
- test "$opt_mode" = uninstall && odir="$dir"
+ name=$func_basename_result
+ test uninstall = "$opt_mode" && odir=$dir
# Remember odir for removal later, being careful to avoid duplicates
- if test "$opt_mode" = clean; then
+ if test clean = "$opt_mode"; then
case " $rmdirs " in
*" $odir "*) ;;
*) func_append rmdirs " $odir" ;;
@@ -9499,11 +11051,11 @@ func_mode_uninstall ()
elif test -d "$file"; then
exit_status=1
continue
- elif test "$rmforce" = yes; then
+ elif $rmforce; then
continue
fi
- rmfiles="$file"
+ rmfiles=$file
case $name in
*.la)
@@ -9517,7 +11069,7 @@ func_mode_uninstall ()
done
test -n "$old_library" && func_append rmfiles " $odir/$old_library"
- case "$opt_mode" in
+ case $opt_mode in
clean)
case " $library_names " in
*" $dlname "*) ;;
@@ -9528,12 +11080,12 @@ func_mode_uninstall ()
uninstall)
if test -n "$library_names"; then
# Do each command in the postuninstall commands.
- func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
fi
if test -n "$old_library"; then
# Do each command in the old_postuninstall commands.
- func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
fi
# FIXME: should reinstall the best remaining shared library.
;;
@@ -9549,21 +11101,19 @@ func_mode_uninstall ()
func_source $dir/$name
# Add PIC object to the list of files to remove.
- if test -n "$pic_object" &&
- test "$pic_object" != none; then
+ if test -n "$pic_object" && test none != "$pic_object"; then
func_append rmfiles " $dir/$pic_object"
fi
# Add non-PIC object to the list of files to remove.
- if test -n "$non_pic_object" &&
- test "$non_pic_object" != none; then
+ if test -n "$non_pic_object" && test none != "$non_pic_object"; then
func_append rmfiles " $dir/$non_pic_object"
fi
fi
;;
*)
- if test "$opt_mode" = clean ; then
+ if test clean = "$opt_mode"; then
noexename=$name
case $file in
*.exe)
@@ -9590,12 +11140,12 @@ func_mode_uninstall ()
# note $name still contains .exe if it was in $file originally
# as does the version of $file that was added into $rmfiles
- func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
- if test "$fast_install" = yes && test -n "$relink_command"; then
+ func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+ if test yes = "$fast_install" && test -n "$relink_command"; then
func_append rmfiles " $odir/lt-$name"
fi
- if test "X$noexename" != "X$name" ; then
- func_append rmfiles " $odir/lt-${noexename}.c"
+ if test "X$noexename" != "X$name"; then
+ func_append rmfiles " $odir/lt-$noexename.c"
fi
fi
fi
@@ -9604,7 +11154,7 @@ func_mode_uninstall ()
func_show_eval "$RM $rmfiles" 'exit_status=1'
done
- # Try to remove the ${objdir}s in the directories where we deleted files
+ # Try to remove the $objdir's in the directories where we deleted files
for dir in $rmdirs; do
if test -d "$dir"; then
func_show_eval "rmdir $dir >/dev/null 2>&1"
@@ -9614,16 +11164,17 @@ func_mode_uninstall ()
exit $exit_status
}
-{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
- func_mode_uninstall ${1+"$@"}
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+ func_mode_uninstall ${1+"$@"}
+fi
test -z "$opt_mode" && {
- help="$generic_help"
+ help=$generic_help
func_fatal_help "you must specify a MODE"
}
test -z "$exec_cmd" && \
- func_fatal_help "invalid operation mode \`$opt_mode'"
+ func_fatal_help "invalid operation mode '$opt_mode'"
if test -n "$exec_cmd"; then
eval exec "$exec_cmd"
@@ -9634,7 +11185,7 @@ exit $exit_status
# The TAGs below are defined such that we never get into a situation
-# in which we disable both kinds of libraries. Given conflicting
+# where we disable both kinds of libraries. Given conflicting
# choices, we go for a static library, that is the most portable,
# since we can't tell whether shared libraries were disabled because
# the user asked for that or because the platform doesn't support
@@ -9657,5 +11208,3 @@ build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
# mode:shell-script
# sh-indentation:2
# End:
-# vi:sw=2
-
diff --git a/3rdparty/expat/conftools/missing b/3rdparty/expat/conftools/missing
new file mode 100755
index 00000000000..8d0eaad250f
--- /dev/null
+++ b/3rdparty/expat/conftools/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=https://www.perl.org/
+flex_URL=https://github.com/westes/flex
+gnu_software_URL=https://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/3rdparty/expat/conftools/mkinstalldirs b/3rdparty/expat/conftools/mkinstalldirs
deleted file mode 100755
index 4f58503ea4e..00000000000
--- a/3rdparty/expat/conftools/mkinstalldirs
+++ /dev/null
@@ -1,40 +0,0 @@
-#! /bin/sh
-# mkinstalldirs --- make directory hierarchy
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
-# Created: 1993-05-16
-# Public domain
-
-# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
-
-errstatus=0
-
-for file
-do
- set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
- shift
-
- pathcomp=
- for d
- do
- pathcomp="$pathcomp$d"
- case "$pathcomp" in
- -* ) pathcomp=./$pathcomp ;;
- esac
-
- if test ! -d "$pathcomp"; then
- echo "mkdir $pathcomp"
-
- mkdir "$pathcomp" || lasterr=$?
-
- if test ! -d "$pathcomp"; then
- errstatus=$lasterr
- fi
- fi
-
- pathcomp="$pathcomp/"
- done
-done
-
-exit $errstatus
-
-# mkinstalldirs ends here
diff --git a/3rdparty/expat/conftools/test-driver b/3rdparty/expat/conftools/test-driver
new file mode 100755
index 00000000000..89dba1e075c
--- /dev/null
+++ b/3rdparty/expat/conftools/test-driver
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 2011-2020 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error. This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+ echo "$0: $*" >&2
+ print_usage >&2
+ exit 2
+}
+
+print_usage ()
+{
+ cat <<END
+Usage:
+ test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+ [--expect-failure={yes|no}] [--color-tests={yes|no}]
+ [--enable-hard-errors={yes|no}] [--]
+ TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file= # Where to save the output of the test script.
+trs_file= # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+ case $1 in
+ --help) print_usage; exit $?;;
+ --version) echo "test-driver $scriptversion"; exit $?;;
+ --test-name) test_name=$2; shift;;
+ --log-file) log_file=$2; shift;;
+ --trs-file) trs_file=$2; shift;;
+ --color-tests) color_tests=$2; shift;;
+ --expect-failure) expect_failure=$2; shift;;
+ --enable-hard-errors) enable_hard_errors=$2; shift;;
+ --) shift; break;;
+ -*) usage_error "invalid option: '$1'";;
+ *) break;;
+ esac
+ shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file" = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+ usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+ usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+ # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+ red='' # Red.
+ grn='' # Green.
+ lgn='' # Light green.
+ blu='' # Blue.
+ mgn='' # Magenta.
+ std='' # No color.
+else
+ red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+ tweaked_estatus=1
+else
+ tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+ 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+ 0:*) col=$grn res=PASS recheck=no gcopy=no;;
+ 77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
+ 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
+ *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
+ *:*) col=$red res=FAIL recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/3rdparty/expat/doc/Makefile.am b/3rdparty/expat/doc/Makefile.am
new file mode 100644
index 00000000000..e2f029837a4
--- /dev/null
+++ b/3rdparty/expat/doc/Makefile.am
@@ -0,0 +1,59 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+.PHONY: dist-hook # not inside conditional to avoid automake warning
+
+if WITH_DOCBOOK
+dist_man_MANS = xmlwf.1
+
+xmlwf.1: xmlwf.xml
+ -rm -f $@
+ $(DOCBOOK_TO_MAN) $<
+ test -f $@ || mv XMLWF.1 $@
+else
+dist-hook:
+ @echo 'ERROR: Configure with --with-docbook for "make dist".' 1>&2
+ @false
+endif
+
+# https://www.gnu.org/software/automake/manual/automake.html#What-Gets-Cleaned
+.PHONY: clean-local
+clean-local: clean-local-check
+
+.PHONY: clean-local-check
+clean-local-check:
+ $(RM) xmlwf.1
+
+EXTRA_DIST = \
+ expat.png \
+ reference.html \
+ style.css \
+ valid-xhtml10.png \
+ xmlwf.xml
diff --git a/3rdparty/expat/doc/Makefile.in b/3rdparty/expat/doc/Makefile.in
new file mode 100644
index 00000000000..94550becf39
--- /dev/null
+++ b/3rdparty/expat/doc/Makefile.in
@@ -0,0 +1,602 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/expat_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+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 = 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__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)"
+NROFF = nroff
+MANS = $(dist_man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
+@WITH_DOCBOOK_TRUE@dist_man_MANS = xmlwf.1
+EXTRA_DIST = \
+ expat.png \
+ reference.html \
+ style.css \
+ valid-xhtml10.png \
+ xmlwf.xml
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(dist_man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(dist_man_MANS)'; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
+ } | 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 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=''; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(dist_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,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+@WITH_DOCBOOK_TRUE@dist-hook:
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$(top_distdir)" distdir="$(distdir)" \
+ dist-hook
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+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
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ clean-local cscopelist-am ctags-am dist-hook distclean \
+ distclean-generic distclean-libtool distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-man1 install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-man uninstall-man1
+
+.PRECIOUS: Makefile
+
+
+.PHONY: dist-hook # not inside conditional to avoid automake warning
+
+@WITH_DOCBOOK_TRUE@xmlwf.1: xmlwf.xml
+@WITH_DOCBOOK_TRUE@ -rm -f $@
+@WITH_DOCBOOK_TRUE@ $(DOCBOOK_TO_MAN) $<
+@WITH_DOCBOOK_TRUE@ test -f $@ || mv XMLWF.1 $@
+@WITH_DOCBOOK_FALSE@dist-hook:
+@WITH_DOCBOOK_FALSE@ @echo 'ERROR: Configure with --with-docbook for "make dist".' 1>&2
+@WITH_DOCBOOK_FALSE@ @false
+
+# https://www.gnu.org/software/automake/manual/automake.html#What-Gets-Cleaned
+.PHONY: clean-local
+clean-local: clean-local-check
+
+.PHONY: clean-local-check
+clean-local-check:
+ $(RM) xmlwf.1
+
+# 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:
diff --git a/3rdparty/expat/doc/expat.png b/3rdparty/expat/doc/expat.png
index 3d88eac4a13..7d7c3dbaebc 100644
--- a/3rdparty/expat/doc/expat.png
+++ b/3rdparty/expat/doc/expat.png
Binary files differ
diff --git a/3rdparty/expat/doc/reference.html b/3rdparty/expat/doc/reference.html
index a4ab40530aa..1e4780ed70c 100644
--- a/3rdparty/expat/doc/reference.html
+++ b/3rdparty/expat/doc/reference.html
@@ -31,7 +31,7 @@ the underlying XML parser for the open source Mozilla project, Perl's
other open-source XML parsers.</p>
<p>This library is the creation of James Clark, who's also given us
-groff (an nroff look-alike), Jade (an implemention of ISO's DSSSL
+groff (an nroff look-alike), Jade (an implementation of ISO's DSSSL
stylesheet language for SGML), XP (a Java XML parser package), XT (a
Java XSL engine). James was also the technical lead on the XML
Working Group at W3C that produced the XML specification.</p>
@@ -276,9 +276,11 @@ directions or Unix directions below.</p>
<p>If you're using the GNU compiler under cygwin, follow the Unix
directions in the next section. Otherwise if you have Microsoft's
-Developer Studio installed, then from Windows Explorer double-click on
-"expat.dsp" in the lib directory and build and install in the usual
-manner.</p>
+Developer Studio installed,
+you can use CMake to generate a <code>.sln</code> file, e.g.
+<code>
+cmake -G"Visual Studio 15 2017" -DCMAKE_BUILD_TYPE=RelWithDebInfo .
+</code>, and build Expat using <code>msbuild /m expat.sln</code> after.</p>
<p>Alternatively, you may download the Win32 binary package that
contains the "expat.h" include file and a pre-built DLL.</p>
@@ -360,7 +362,7 @@ off by default.</dd>
<dd>The number of input bytes of markup context which the parser will
ensure are available for reporting via <code><a href=
"#XML_GetInputContext" >XML_GetInputContext</a></code>. This is
-normally set to 1024, and must be set to a positive interger. If this
+normally set to 1024, and must be set to a positive integer. If this
is not defined, the input context will not be available and <code><a
href= "#XML_GetInputContext" >XML_GetInputContext</a></code> will
always report NULL. Without this, Expat has a smaller memory
@@ -373,7 +375,7 @@ the right MSVC magic annotations correct. This is ignored on other
platforms.</dd>
<dt>XML_ATTR_INFO</dt>
-<dd>If defined, makes the the additional function <code><a href=
+<dd>If defined, makes the additional function <code><a href=
"#XML_GetAttributeInfo" >XML_GetAttributeInfo</a></code> available
for reporting attribute byte offsets.</dd>
</dl>
@@ -739,7 +741,7 @@ arguments:</p>
<dt><code>XML_PARAM_ENTITY_PARSING_NEVER</code></dt>
<dd>Don't parse parameter entities or the external subset</dd>
<dt><code>XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE</code></dt>
-<dd>Parse parameter entites and the external subset unless
+<dd>Parse parameter entities and the external subset unless
<code>standalone</code> was set to "yes" in the XML declaration.</dd>
<dt><code>XML_PARAM_ENTITY_PARSING_ALWAYS</code></dt>
<dd>Always parse parameter entities and the external subset</dd>
@@ -767,7 +769,7 @@ include</p>
<li>Stopping parsing completely (simply free or reset the parser
instead of resuming in the outer parsing loop). This can be useful
- if a application-domain error is found in the XML being parsed or if
+ if an application-domain error is found in the XML being parsed or if
the result of the parse is determined not to be useful after
all.</li>
</ul>
@@ -1296,7 +1298,7 @@ typedef void
int len);
</pre>
<p>Set a text handler. The string your handler receives
-is <em>NOT nul-terminated</em>. You have to use the length argument
+is <em>NOT null-terminated</em>. You have to use the length argument
to deal with the end of the string. A single block of contiguous text
free of markup may still result in a sequence of calls to this handler.
In other words, if you're searching for a pattern in the text, it may
@@ -1564,7 +1566,7 @@ at most once per parsed (external) entity. The optional application
data pointer <code>encodingHandlerData</code> will be passed back to
the handler.</p>
-<p>The map array contains information for every possible possible leading
+<p>The map array contains information for every possible leading
byte in a byte sequence. If the corresponding value is &gt;= 0, then it's
a single byte sequence and the byte encodes that Unicode value. If the
value is -1, then that byte is invalid as the initial byte in a sequence.
@@ -1574,7 +1576,7 @@ call to the function pointed at by convert. This function may return -1
if the sequence itself is invalid. The convert pointer may be null if
there are only single byte codes. The data parameter passed to the convert
function is the data pointer from <code>XML_Encoding</code>. The
-string s is <em>NOT</em> nul-terminated and points at the sequence of
+string s is <em>NOT</em> null-terminated and points at the sequence of
bytes to be converted.</p>
<p>The function pointed at by <code>release</code> is called by the
@@ -1902,7 +1904,7 @@ of errors. The position reported is the byte position (in the original
document or entity encoding) of the first of the sequence of
characters that generated the current event (or the error that caused
the parse functions to return <code>XML_STATUS_ERROR</code>.) The
-exceptions are callbacks trigged by declarations in the document
+exceptions are callbacks triggered by declarations in the document
prologue, in which case they exact position reported is somewhere in the
relevant markup, but not necessarily as meaningful as for other
events.</p>
@@ -1999,7 +2001,7 @@ return NULL.</p>
<h3><a name="miscellaneous">Miscellaneous functions</a></h3>
<p>The functions in this section either obtain state information from
-the parser or can be used to dynamicly set parser options.</p>
+the parser or can be used to dynamically set parser options.</p>
<pre class="fcndec" id="XML_SetUserData">
void XMLCALL
@@ -2152,7 +2154,7 @@ function behavior. In order to have an effect this must be called
before parsing has started. Returns 1 if successful, 0 when called
after <code>XML_Parse</code> or <code>XML_ParseBuffer</code>.
<p><b>Note:</b>This call is optional, as the parser will auto-generate
-a new random salt value if no value has been set at the start of parsing.
+a new random salt value if no value has been set at the start of parsing.</p>
<p><b>Note:</b>One should not call <code>XML_SetHashSalt</code> with a
hash salt value of 0, as this value is used as sentinel value to indicate
that <code>XML_SetHashSalt</code> has <b>not</b> been called. Consequently
diff --git a/3rdparty/expat/doc/valid-xhtml10.png b/3rdparty/expat/doc/valid-xhtml10.png
index 2f755c62b52..8b5f1baeaa0 100644
--- a/3rdparty/expat/doc/valid-xhtml10.png
+++ b/3rdparty/expat/doc/valid-xhtml10.png
Binary files differ
diff --git a/3rdparty/expat/doc/xmlwf.1 b/3rdparty/expat/doc/xmlwf.1
index f45aea9cb4d..ca56bf97650 100644
--- a/3rdparty/expat/doc/xmlwf.1
+++ b/3rdparty/expat/doc/xmlwf.1
@@ -15,7 +15,7 @@ xmlwf \- Determines if an XML document is well-formed
\fBxmlwf\fR \kx
.if (\nx>(\n(.l/2)) .nr x (\n(.l/5)
'in \n(.iu+\nxu
-[\fB-s\fR] [\fB-n\fR] [\fB-p\fR] [\fB-x\fR] [\fB-e \fIencoding\fB\fR] [\fB-w\fR] [\fB-d \fIoutput-dir\fB\fR] [\fB-c\fR] [\fB-m\fR] [\fB-r\fR] [\fB-t\fR] [\fB-v\fR] [file ...]
+[\fB-s\fR] [\fB-n\fR] [\fB-p\fR] [\fB-x\fR] [\fB-e \fIencoding\fB\fR] [\fB-w\fR] [\fB-d \fIoutput-dir\fB\fR] [\fB-c\fR] [\fB-m\fR] [\fB-r\fR] [\fB-t\fR] [\fB-N\fR] [\fB-v\fR] [file ...]
'in \n(.iu-\nxu
.ad b
'hy
@@ -71,15 +71,15 @@ If the input file is well-formed and \fBxmlwf\fR
doesn't encounter any errors, the input file is simply copied to
the output directory unchanged.
This implies no namespaces (turns off \*(T<\fB\-n\fR\*(T>) and
-requires \*(T<\fB\-d\fR\*(T> to specify an output file.
+requires \*(T<\fB\-d\fR\*(T> to specify an output directory.
.TP
\*(T<\fB\-d output\-dir\fR\*(T>
Specifies a directory to contain transformed
representations of the input files.
By default, \*(T<\fB\-d\fR\*(T> outputs a canonical representation
(described below).
-You can select different output formats using \*(T<\fB\-c\fR\*(T>
-and \*(T<\fB\-m\fR\*(T>.
+You can select different output formats using \*(T<\fB\-c\fR\*(T>,
+\*(T<\fB\-m\fR\*(T> and \*(T<\fB\-N\fR\*(T>.
The output filenames will
be exactly the same as the input filenames or "STDIN" if the input is
@@ -115,6 +115,11 @@ Requires \*(T<\fB\-d\fR\*(T> to specify an output file.
Turns on namespace processing. (describe namespaces)
\*(T<\fB\-c\fR\*(T> disables namespaces.
.TP
+\*(T<\fB\-N\fR\*(T>
+Adds a doctype and notation declarations to canonical XML output.
+This matches the example output used by the formal XML test cases.
+Requires \*(T<\fB\-d\fR\*(T> to specify an output file.
+.TP
\*(T<\fB\-p\fR\*(T>
Tells xmlwf to process external DTDs and parameter
entities.
@@ -177,12 +182,14 @@ data from outside the XML file currently being parsed.
This is an example of an internal entity:
.nf
+
<!ENTITY vers '1.0.2'>
.fi
And here are some examples of external entities:
.nf
+
<!ENTITY header SYSTEM "header\-&vers;.xml"> (parsed)
<!ENTITY logo SYSTEM "logo.png" PNG> (unparsed)
.fi
@@ -193,6 +200,7 @@ Terminates the list of options. This is only needed if a filename
starts with a hyphen. For example:
.nf
+
xmlwf \-\- \-myfile.xml
.fi
@@ -206,14 +214,21 @@ If an input file is not well-formed,
\fBxmlwf\fR prints a single line describing
the problem to standard output. If a file is well formed,
\fBxmlwf\fR outputs nothing.
-Note that the result code is \fInot\fR set.
+.SH "EXIT STATUS"
+For option \*(T<\fB\-v\fR\*(T> or \*(T<\fB\-h\fR\*(T>, \fBxmlwf\fR always exits with status code 0. For other cases, the following exit status codes are returned:
+.TP
+\*(T<\fB0\fR\*(T>
+The input files are well-formed.
+.TP
+\*(T<\fB1\fR\*(T>
+An internal error occurred.
+.TP
+\*(T<\fB2\fR\*(T>
+An input file was not well-formed or could not be parsed.
+.TP
+\*(T<\fB3\fR\*(T>
+If using the \*(T<\fB\-d\fR\*(T> option, an error occurred opening an output file.
.SH BUGS
-\fBxmlwf\fR returns a 0 - noerr result,
-even if the file is not well-formed. There is no good way for
-a program to use \fBxmlwf\fR to quickly
-check a file -- it must parse \fBxmlwf\fR's
-standard output.
-.PP
The errors should go to standard error, not standard output.
.PP
There should be a way to get \*(T<\fB\-d\fR\*(T> to send its
@@ -228,6 +243,7 @@ me, I'd like to add this information to this manpage.
Here are some XML validators on the web:
.nf
+
http://www.hcrc.ed.ac.uk/~richard/xml\-check.html
http://www.stg.brown.edu/service/xmlvalid/
http://www.scripting.com/frontier5/xml/code/xmlValidator.html
@@ -235,6 +251,7 @@ http://www.xml.com/pub/a/tools/ruwf/check.html
.fi
.SH "SEE ALSO"
.nf
+
The Expat home page: http://www.libexpat.org/
The W3 XML specification: http://www.w3.org/TR/REC\-xml
.fi
diff --git a/3rdparty/expat/doc/xmlwf.sgml b/3rdparty/expat/doc/xmlwf.xml
index e1f779e1f3b..654466cef62 100644
--- a/3rdparty/expat/doc/xmlwf.sgml
+++ b/3rdparty/expat/doc/xmlwf.xml
@@ -1,14 +1,4 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-
-<!-- Process this file with docbook-to-man to generate an nroff manual
- page: `docbook-to-man manpage.sgml > manpage.1'. You may view
- the manual page with: `docbook-to-man manpage.sgml | nroff -man |
- less'. A typical entry in a Makefile or Makefile.am is:
-
-manpage.1: manpage.sgml
- docbook-to-man $< > $@
- -->
-
+<!DOCTYPE refentry [
<!-- Fill in your name for FIRSTNAME and SURNAME. -->
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
<!ENTITY dhsurname "<surname>Bronson</surname>">
@@ -68,6 +58,7 @@ manpage.1: manpage.sgml
<arg><option>-r</option></arg>
<arg><option>-t</option></arg>
+ <arg><option>-N</option></arg>
<arg><option>-v</option></arg>
@@ -156,7 +147,7 @@ supports both.
doesn't encounter any errors, the input file is simply copied to
the output directory unchanged.
This implies no namespaces (turns off <option>-n</option>) and
- requires <option>-d</option> to specify an output file.
+ requires <option>-d</option> to specify an output directory.
</para>
</listitem>
</varlistentry>
@@ -169,8 +160,8 @@ supports both.
representations of the input files.
By default, <option>-d</option> outputs a canonical representation
(described below).
- You can select different output formats using <option>-c</option>
- and <option>-m</option>.
+ You can select different output formats using <option>-c</option>,
+ <option>-m</option> and <option>-N</option>.
</para>
<para>
The output filenames will
@@ -230,6 +221,17 @@ supports both.
</varlistentry>
<varlistentry>
+ <term><option>-N</option></term>
+ <listitem>
+ <para>
+ Adds a doctype and notation declarations to canonical XML output.
+ This matches the example output used by the formal XML test cases.
+ Requires <option>-d</option> to specify an output file.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-p</option></term>
<listitem>
<para>
@@ -381,20 +383,41 @@ supports both.
<command>&dhpackage;</command> prints a single line describing
the problem to standard output. If a file is well formed,
<command>&dhpackage;</command> outputs nothing.
- Note that the result code is <emphasis>not</emphasis> set.
</para>
</refsect1>
+
+ <refsect1>
+ <title>EXIT STATUS</title>
+ <para>For option <option>-v</option> or <option>-h</option>, <command>&dhpackage;</command> always exits with status code 0. For other cases, the following exit status codes are returned:
+ <variablelist>
+ <varlistentry>
+ <term><option>0</option></term>
+ <listitem><para>The input files are well-formed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>1</option></term>
+ <listitem><para>An internal error occurred.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>2</option></term>
+ <listitem><para>An input file was not well-formed or could not be parsed.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>3</option></term>
+ <listitem><para>If using the <option>-d</option> option, an error occurred opening an output file.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
<refsect1>
<title>BUGS</title>
<para>
- <command>&dhpackage;</command> returns a 0 - noerr result,
- even if the file is not well-formed. There is no good way for
- a program to use <command>&dhpackage;</command> to quickly
- check a file -- it must parse <command>&dhpackage;</command>'s
- standard output.
- </para>
- <para>
The errors should go to standard error, not standard output.
</para>
<para>
@@ -448,20 +471,3 @@ The W3 XML specification: http://www.w3.org/TR/REC-xml
</para>
</refsect1>
</refentry>
-
-<!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-omittag:t
-sgml-shorttag:t
-sgml-minimize-attributes:nil
-sgml-always-quote-attributes:t
-sgml-indent-step:2
-sgml-indent-data:t
-sgml-parent-document:nil
-sgml-default-dtd-file:nil
-sgml-exposed-tags:nil
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-End:
--->
diff --git a/3rdparty/expat/examples/Makefile.am b/3rdparty/expat/examples/Makefile.am
new file mode 100644
index 00000000000..c3b1f7bedbf
--- /dev/null
+++ b/3rdparty/expat/examples/Makefile.am
@@ -0,0 +1,39 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+
+noinst_PROGRAMS = elements outline
+
+elements_SOURCES = elements.c
+elements_LDADD = ../lib/libexpat.la
+
+outline_SOURCES = outline.c
+outline_LDADD = ../lib/libexpat.la
diff --git a/3rdparty/expat/examples/Makefile.in b/3rdparty/expat/examples/Makefile.in
new file mode 100644
index 00000000000..7c4a296ba2b
--- /dev/null
+++ b/3rdparty/expat/examples/Makefile.in
@@ -0,0 +1,660 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = elements$(EXEEXT) outline$(EXEEXT)
+subdir = examples
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/expat_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_elements_OBJECTS = elements.$(OBJEXT)
+elements_OBJECTS = $(am_elements_OBJECTS)
+elements_DEPENDENCIES = ../lib/libexpat.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_outline_OBJECTS = outline.$(OBJEXT)
+outline_OBJECTS = $(am_outline_OBJECTS)
+outline_DEPENDENCIES = ../lib/libexpat.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/elements.Po ./$(DEPDIR)/outline.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(elements_SOURCES) $(outline_SOURCES)
+DIST_SOURCES = $(elements_SOURCES) $(outline_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/conftools/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
+elements_SOURCES = elements.c
+elements_LDADD = ../lib/libexpat.la
+outline_SOURCES = outline.c
+outline_LDADD = ../lib/libexpat.la
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu examples/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_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
+
+elements$(EXEEXT): $(elements_OBJECTS) $(elements_DEPENDENCIES) $(EXTRA_elements_DEPENDENCIES)
+ @rm -f elements$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(elements_OBJECTS) $(elements_LDADD) $(LIBS)
+
+outline$(EXEEXT): $(outline_OBJECTS) $(outline_DEPENDENCIES) $(EXTRA_outline_DEPENDENCIES)
+ @rm -f outline$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(outline_OBJECTS) $(outline_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elements.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/outline.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/elements.Po
+ -rm -f ./$(DEPDIR)/outline.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/elements.Po
+ -rm -f ./$(DEPDIR)/outline.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ 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 tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/3rdparty/expat/examples/elements.c b/3rdparty/expat/examples/elements.c
index bc04b6b1515..eb0c729bff1 100644
--- a/3rdparty/expat/examples/elements.c
+++ b/3rdparty/expat/examples/elements.c
@@ -3,63 +3,95 @@
the name of each element to standard output indenting child
elements by one tab stop more than their parent element.
It must be used with Expat compiled for UTF-8 output.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
-#include "expat.h"
-
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include <proto/expat.h>
-#endif
+#include <expat.h>
#ifdef XML_LARGE_SIZE
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
-#define XML_FMT_INT_MOD "I64"
+# define XML_FMT_INT_MOD "ll"
#else
-#define XML_FMT_INT_MOD "ll"
+# define XML_FMT_INT_MOD "l"
#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+# include <wchar.h>
+# define XML_FMT_STR "ls"
#else
-#define XML_FMT_INT_MOD "l"
+# define XML_FMT_STR "s"
#endif
static void XMLCALL
-startElement(void *userData, const char *name, const char **atts)
-{
+startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
int i;
int *depthPtr = (int *)userData;
+ (void)atts;
+
for (i = 0; i < *depthPtr; i++)
putchar('\t');
- puts(name);
+ printf("%" XML_FMT_STR "\n", name);
*depthPtr += 1;
}
static void XMLCALL
-endElement(void *userData, const char *name)
-{
+endElement(void *userData, const XML_Char *name) {
int *depthPtr = (int *)userData;
+ (void)name;
+
*depthPtr -= 1;
}
int
-main(int argc, char *argv[])
-{
+main(int argc, char *argv[]) {
char buf[BUFSIZ];
XML_Parser parser = XML_ParserCreate(NULL);
int done;
int depth = 0;
+ (void)argc;
+ (void)argv;
+
XML_SetUserData(parser, &depth);
XML_SetElementHandler(parser, startElement, endElement);
do {
size_t len = fread(buf, 1, sizeof(buf), stdin);
done = len < sizeof(buf);
- if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
- fprintf(stderr,
- "%s at line %" XML_FMT_INT_MOD "u\n",
+ if (XML_Parse(parser, buf, (int)len, done) == XML_STATUS_ERROR) {
+ fprintf(stderr, "%" XML_FMT_STR " at line %" XML_FMT_INT_MOD "u\n",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
+ XML_ParserFree(parser);
return 1;
}
- } while (!done);
+ } while (! done);
XML_ParserFree(parser);
return 0;
}
diff --git a/3rdparty/expat/examples/elements.dsp b/3rdparty/expat/examples/elements.dsp
deleted file mode 100644
index 5e750c4f6c4..00000000000
--- a/3rdparty/expat/examples/elements.dsp
+++ /dev/null
@@ -1,103 +0,0 @@
-# Microsoft Developer Studio Project File - Name="elements" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=elements - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "elements.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "elements.mak" CFG="elements - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "elements - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "elements - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "elements - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release-elements"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\lib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "XML_STATIC" /FD /c
-# SUBTRACT CPP /X /YX
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /machine:I386
-# ADD LINK32 libexpatMT.lib /nologo /subsystem:console /pdb:none /machine:I386 /libpath:"..\win32\bin\Release" /out:"..\win32\bin\Release\elements.exe"
-
-!ELSEIF "$(CFG)" == "elements - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug-elements"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /I "..\lib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "XML_STATIC" /FR /FD /GZ /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 libexpatMT.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /libpath:"..\win32\bin\Debug" /out:"..\win32\bin\Debug\elements.exe"
-
-!ENDIF
-
-# Begin Target
-
-# Name "elements - Win32 Release"
-# Name "elements - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\elements.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/examples/outline.c b/3rdparty/expat/examples/outline.c
index 3a3c8385512..d996b8e3a8d 100644
--- a/3rdparty/expat/examples/outline.c
+++ b/3rdparty/expat/examples/outline.c
@@ -1,62 +1,70 @@
-/*****************************************************************
- * outline.c
- *
- * Copyright 1999, Clark Cooper
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the license contained in the
- * COPYING file that comes with the expat distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Read an XML document from standard input and print an element
- * outline on standard output.
- * Must be used with Expat compiled for UTF-8 output.
- */
-
+/* Read an XML document from standard input and print an element
+ outline on standard output.
+ Must be used with Expat compiled for UTF-8 output.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
#include <stdio.h>
#include <expat.h>
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include <proto/expat.h>
-#endif
-
#ifdef XML_LARGE_SIZE
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
-#define XML_FMT_INT_MOD "I64"
+# define XML_FMT_INT_MOD "ll"
#else
-#define XML_FMT_INT_MOD "ll"
+# define XML_FMT_INT_MOD "l"
#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
#else
-#define XML_FMT_INT_MOD "l"
+# define XML_FMT_STR "s"
#endif
-#define BUFFSIZE 8192
+#define BUFFSIZE 8192
char Buff[BUFFSIZE];
int Depth;
static void XMLCALL
-start(void *data, const char *el, const char **attr)
-{
+start(void *data, const XML_Char *el, const XML_Char **attr) {
int i;
+ (void)data;
for (i = 0; i < Depth; i++)
printf(" ");
- printf("%s", el);
+ printf("%" XML_FMT_STR, el);
for (i = 0; attr[i]; i += 2) {
- printf(" %s='%s'", attr[i], attr[i + 1]);
+ printf(" %" XML_FMT_STR "='%" XML_FMT_STR "'", attr[i], attr[i + 1]);
}
printf("\n");
@@ -64,15 +72,19 @@ start(void *data, const char *el, const char **attr)
}
static void XMLCALL
-end(void *data, const char *el)
-{
+end(void *data, const XML_Char *el) {
+ (void)data;
+ (void)el;
+
Depth--;
}
int
-main(int argc, char *argv[])
-{
+main(int argc, char *argv[]) {
XML_Parser p = XML_ParserCreate(NULL);
+ (void)argc;
+ (void)argv;
+
if (! p) {
fprintf(stderr, "Couldn't allocate memory for parser\n");
exit(-1);
@@ -92,7 +104,8 @@ main(int argc, char *argv[])
done = feof(stdin);
if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) {
- fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%s\n",
+ fprintf(stderr,
+ "Parse error at line %" XML_FMT_INT_MOD "u:\n%" XML_FMT_STR "\n",
XML_GetCurrentLineNumber(p),
XML_ErrorString(XML_GetErrorCode(p)));
exit(-1);
diff --git a/3rdparty/expat/examples/outline.dsp b/3rdparty/expat/examples/outline.dsp
deleted file mode 100644
index acadf4bd7e5..00000000000
--- a/3rdparty/expat/examples/outline.dsp
+++ /dev/null
@@ -1,103 +0,0 @@
-# Microsoft Developer Studio Project File - Name="outline" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=outline - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "outline.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "outline.mak" CFG="outline - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "outline - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "outline - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "outline - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release-outline"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\lib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
-# SUBTRACT CPP /X /YX
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /machine:I386
-# ADD LINK32 libexpat.lib /nologo /subsystem:console /pdb:none /machine:I386 /libpath:"..\win32\bin\Release" /out:"..\win32\bin\Release\outline.exe"
-
-!ELSEIF "$(CFG)" == "outline - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug-outline"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\lib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 libexpat.lib /nologo /subsystem:console /pdb:none /debug /machine:I386 /libpath:"..\win32\bin\Debug" /out:"..\win32\bin\Debug\outline.exe"
-
-!ENDIF
-
-# Begin Target
-
-# Name "outline - Win32 Release"
-# Name "outline - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\outline.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/expat.dsw b/3rdparty/expat/expat.dsw
deleted file mode 100644
index 2d62eec5f6c..00000000000
--- a/3rdparty/expat/expat.dsw
+++ /dev/null
@@ -1,110 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "elements"=.\examples\elements.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name expat_static
- End Project Dependency
-}}}
-
-###############################################################################
-
-Project: "expat"=.\lib\expat.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "expat_static"=.\lib\expat_static.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "expatw"=.\lib\expatw.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "expatw_static"=.\lib\expatw_static.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "outline"=.\examples\outline.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name expat
- End Project Dependency
-}}}
-
-###############################################################################
-
-Project: "xmlwf"=.\xmlwf\xmlwf.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name expat
- End Project Dependency
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
diff --git a/3rdparty/expat/expat.pc.in b/3rdparty/expat/expat.pc.in
index 5207e3e1b06..bdfa47f8457 100644
--- a/3rdparty/expat/expat.pc.in
+++ b/3rdparty/expat/expat.pc.in
@@ -3,9 +3,9 @@ exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
-Name: expat
+Name: @_EXPAT_OUTPUT_NAME@
Version: @PACKAGE_VERSION@
Description: expat XML parser
URL: http://www.libexpat.org
-Libs: -L${libdir} -lexpat
+Libs: -L${libdir} -l@_EXPAT_OUTPUT_NAME@
Cflags: -I${includedir}
diff --git a/3rdparty/expat/expat_config.h.cmake b/3rdparty/expat/expat_config.h.cmake
index 25d79a6d5e6..173fed168c1 100644
--- a/3rdparty/expat/expat_config.h.cmake
+++ b/3rdparty/expat/expat_config.h.cmake
@@ -1,10 +1,13 @@
-/* expat_config.h.in. Generated from configure.in by autoheader. */
+/* expat_config.h.cmake. Based upon generated expat_config.h.in. */
/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
#cmakedefine BYTEORDER @BYTEORDER@
-/* Define to 1 if you have the `bcopy' function. */
-#cmakedefine HAVE_BCOPY
+/* Define to 1 if you have the `arc4random' function. */
+#cmakedefine HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#cmakedefine HAVE_ARC4RANDOM_BUF
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H
@@ -15,11 +18,14 @@
/* Define to 1 if you have the `getpagesize' function. */
#cmakedefine HAVE_GETPAGESIZE
+/* Define to 1 if you have the `getrandom' function. */
+#cmakedefine HAVE_GETRANDOM
+
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H
-/* Define to 1 if you have the `memmove' function. */
-#cmakedefine HAVE_MEMMOVE
+/* Define to 1 if you have the `bsd' library (-lbsd). */
+#cmakedefine HAVE_LIBBSD
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H
@@ -39,6 +45,9 @@
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H
+/* Define to 1 if you have `syscall' and `SYS_getrandom'. */
+#cmakedefine HAVE_SYSCALL_GETRANDOM
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H
@@ -48,20 +57,26 @@
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H
+/* Name of package */
+#define PACKAGE "@PACKAGE_NAME@"
+
/* Define to the address where bug reports for this package should be sent. */
-#cmakedefine PACKAGE_BUGREPORT
+#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
/* Define to the full name of this package. */
-#cmakedefine PACKAGE_NAME
+#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@"
/* Define to the full name and version of this package. */
-#cmakedefine PACKAGE_STRING
+#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@"
/* Define to the one symbol short name of this package. */
-#cmakedefine PACKAGE_TARNAME
+#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
/* Define to the version of this package. */
-#cmakedefine PACKAGE_VERSION
+#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@"
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS
@@ -69,10 +84,19 @@
/* whether byteorder is bigendian */
#cmakedefine WORDS_BIGENDIAN
+/* Define to allow retrieving the byte offsets for attribute names and values.
+ */
+#cmakedefine XML_ATTR_INFO
+
/* Define to specify how much context to retain around the current parse
point. */
#cmakedefine XML_CONTEXT_BYTES @XML_CONTEXT_BYTES@
+#if ! defined(_WIN32)
+/* Define to include code reading entropy from `/dev/urandom'. */
+ #cmakedefine XML_DEV_URANDOM
+#endif
+
/* Define to make parameter entity parsing functionality available. */
#cmakedefine XML_DTD
@@ -81,7 +105,7 @@
/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
#ifdef _MSC_VER
-# define __func__ __FUNCTION__
+# define __func__ __FUNCTION__
#endif
/* Define to `long' if <sys/types.h> does not define. */
diff --git a/3rdparty/expat/expat_config.h.in b/3rdparty/expat/expat_config.h.in
index 5fcd5fd8da6..59207b42e41 100644
--- a/3rdparty/expat/expat_config.h.in
+++ b/3rdparty/expat/expat_config.h.in
@@ -1,10 +1,16 @@
/* expat_config.h.in. Generated from configure.ac by autoheader. */
-/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* 1234 = LILENDIAN, 4321 = BIGENDIAN */
#undef BYTEORDER
-/* Define to 1 if you have the `bcopy' function. */
-#undef HAVE_BCOPY
+/* Define to 1 if you have the `arc4random' function. */
+#undef HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#undef HAVE_ARC4RANDOM_BUF
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
@@ -15,11 +21,14 @@
/* Define to 1 if you have the `getpagesize' function. */
#undef HAVE_GETPAGESIZE
+/* Define to 1 if you have the `getrandom' function. */
+#undef HAVE_GETRANDOM
+
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
-/* Define to 1 if you have the `memmove' function. */
-#undef HAVE_MEMMOVE
+/* Define to 1 if you have the `bsd' library (-lbsd). */
+#undef HAVE_LIBBSD
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
@@ -39,6 +48,9 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
+/* Define to 1 if you have `syscall' and `SYS_getrandom'. */
+#undef HAVE_SYSCALL_GETRANDOM
+
/* Define to 1 if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
@@ -51,10 +63,12 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
+/* Name of package */
+#undef PACKAGE
+
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
@@ -76,22 +90,38 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
-/* whether byteorder is bigendian */
-#undef WORDS_BIGENDIAN
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to allow retrieving the byte offsets for attribute names and values.
+ */
+#undef XML_ATTR_INFO
/* Define to specify how much context to retain around the current parse
point. */
#undef XML_CONTEXT_BYTES
+/* Define to include code reading entropy from `/dev/urandom'. */
+#undef XML_DEV_URANDOM
+
/* Define to make parameter entity parsing functionality available. */
#undef XML_DTD
/* Define to make XML Namespaces functionality available. */
#undef XML_NS
-/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
-#undef __func__
-
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
diff --git a/3rdparty/expat/fix-xmltest-log.sh b/3rdparty/expat/fix-xmltest-log.sh
new file mode 100755
index 00000000000..c143e93cf20
--- /dev/null
+++ b/3rdparty/expat/fix-xmltest-log.sh
@@ -0,0 +1,48 @@
+#! /usr/bin/env bash
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2019 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+set -e
+
+filename="${1:-tests/xmltest.log}"
+
+dos2unix "${filename}"
+
+tempfile="$(mktemp)"
+sed \
+ -e 's/^wine: Call .* msvcrt\.dll\._wperror, aborting$/ibm49i02.dtd: No such file or directory/' \
+ \
+ -e '/^wine: /d' \
+ -e '/^Application tried to create a window, but no driver could be loaded.$/d' \
+ -e '/^Make sure that your X server is running and that $DISPLAY is set correctly.$/d' \
+ -e '/^err:systray:initialize_systray Could not create tray window$/d' \
+ -e '/^In ibm\/invalid\/P49\/: Unhandled exception: unimplemented .\+/d' \
+ \
+ "${filename}" > "${tempfile}"
+mv "${tempfile}" "${filename}"
diff --git a/3rdparty/expat/lib/Makefile.MPW b/3rdparty/expat/lib/Makefile.MPW
deleted file mode 100644
index 046af005147..00000000000
--- a/3rdparty/expat/lib/Makefile.MPW
+++ /dev/null
@@ -1,206 +0,0 @@
-# File: Makefile.MPW
-# Targets: All, Dynamic, Static (and Clean, Clean-All)
-# Created: Tuesday, July 02, 2002
-#
-# MPW Makefile for building expat under the "classic" (i.e. pre-X) Mac OS
-# Copyright © 2002 Daryle Walker
-# Portions Copyright © 2002 Thomas Wegner
-# See the COPYING file for distribution information
-#
-# Description:
-# This Makefile lets you build static, dynamic (i.e. shared) and stub
-# versions of the expat library as well as the elements.c and outline.c
-# examples (built as tools for MPW). This is for PPC only; it should be
-# no problem to build a 68K version of the expat library, though.
-#
-# Usage:
-# Buildprogram All
-# or Buildprogram Dynamic
-# or Buildprogram Static
-#
-# Note: You first have to rename this file to "Makefile", or the Buildprogram
-# commando will not recognize it.
-#
-
-MAKEFILE = Makefile
-¥MondoBuild¥ = {MAKEFILE} # Make blank to avoid rebuilds when makefile is modified
-
-ObjDir = :
-SrcDir = :
-HdrDir = :
-
-ToolDir = ::examples:
-
-Includes = -i {HdrDir}
-
-Sym-PPC = -sym off
-
-Defines = -d MACOS_CLASSIC
-
-PPCCOptions = {Includes} {Sym-PPC} -w 35 {Defines}
-
-FragName = libexpat
-
-
-### Source Files ###
-
-SrcFiles = ¶
- "{SrcDir}xmlparse.c" ¶
- "{SrcDir}xmlrole.c" ¶
- "{SrcDir}xmltok.c"
-
-ToolSrcFiles = ¶
- "{ToolDir}elements.c" ¶
- "{ToolDir}outline.c"
-
-
-### Object Files ###
-
-ObjFiles-PPC = ¶
- "{ObjDir}xmlparse.c.o" ¶
- "{ObjDir}xmlrole.c.o" ¶
- "{ObjDir}xmltok.c.o"
-
-ElementToolObjFile = "{ObjDir}elements.c.o"
-
-OutlineToolObjFile = "{ObjDir}outline.c.o"
-
-
-### Libraries ###
-
-StLibFiles-PPC = ¶
- "{PPCLibraries}StdCRuntime.o" ¶
- "{PPCLibraries}PPCCRuntime.o" ¶
- "{PPCLibraries}PPCToolLibs.o"
-
-ShLibFiles-PPC = ¶
- "{SharedLibraries}InterfaceLib" ¶
- "{SharedLibraries}StdCLib" ¶
- "{SharedLibraries}MathLib"
-
-LibFiles-PPC = ¶
- {StLibFiles-PPC} ¶
- {ShLibFiles-PPC}
-
-
-### Special Files ###
-
-ExportFile = "{ObjDir}{FragName}.exp"
-
-StLibFile = "{ObjDir}{FragName}.MrC.o"
-
-ShLibFile = "{ObjDir}{FragName}"
-
-StubFile = "{ObjDir}{FragName}.stub"
-
-ElementsTool = "{ToolDir}elements"
-
-OutlineTool = "{ToolDir}outline"
-
-
-### Default Rules ###
-
-.c.o Ä .c {¥MondoBuild¥}
- {PPCC} {depDir}{default}.c -o {targDir}{default}.c.o {PPCCOptions}
-
-
-### Build Rules ###
-
-All Ä Dynamic {ElementsTool} {OutlineTool}
-
-Static Ä {StLibFile}
-
-Dynamic Ä Static {ShLibFile} {StubFile}
-
-{StLibFile} ÄÄ {ObjFiles-PPC} {StLibFiles-PPC} {¥MondoBuild¥}
- PPCLink ¶
- -o {Targ} ¶
- {ObjFiles-PPC} ¶
- {StLibFiles-PPC} ¶
- {Sym-PPC} ¶
- -mf -d ¶
- -t 'XCOF' ¶
- -c 'MPS ' ¶
- -xm l
-
-{ShLibFile} ÄÄ {StLibFile} {ShLibFiles-PPC} {ExportFile} {¥MondoBuild¥}
- PPCLink ¶
- -o {Targ} ¶
- {StLibFile} ¶
- {ShLibFiles-PPC} ¶
- {Sym-PPC} ¶
- -@export {ExportFile} ¶
- -fragname {FragName} ¶
- -mf -d ¶
- -t 'shlb' ¶
- -c '????' ¶
- -xm s
-
-{StubFile} ÄÄ {ShLibFile} {¥MondoBuild¥}
- shlb2stub -o {Targ} {ShLibFile}
-
-{ElementsTool} ÄÄ {ElementToolObjFile} {StubFile} {LibFiles-PPC} {¥MondoBuild¥}
- PPCLink ¶
- -o {Targ} ¶
- {ElementToolObjFile} ¶
- {StLibFile} ¶
- {LibFiles-PPC} ¶
- {Sym-PPC} ¶
- -mf -d ¶
- -t 'MPST' ¶
- -c 'MPS '
-
-{OutlineTool} ÄÄ {OutlineToolObjFile} {StubFile} {LibFiles-PPC} {¥MondoBuild¥}
- PPCLink ¶
- -o {Targ} ¶
- {OutlineToolObjFile} ¶
- {StLibFile} ¶
- {LibFiles-PPC} ¶
- {Sym-PPC} ¶
- -mf -d ¶
- -t 'MPST' ¶
- -c 'MPS '
-
-
-### Special Rules ###
-
-{ExportFile} ÄÄ "{HdrDir}expat.h" {¥MondoBuild¥}
- StreamEdit -d ¶
- -e "/¥('XMLPARSEAPI('Å') ')Ç0,1È'XML_'([A-Za-z0-9_]+)¨1'('/ Print 'XML_' ¨1" ¶
- "{HdrDir}expat.h" > {Targ}
-
-
-### Required Dependencies ###
-
-"{ObjDir}xmlparse.c.o" Ä "{SrcDir}xmlparse.c"
-"{ObjDir}xmlrole.c.o" Ä "{SrcDir}xmlrole.c"
-"{ObjDir}xmltok.c.o" Ä "{SrcDir}xmltok.c"
-
-"{ObjDir}elements.c.o" Ä "{ToolDir}elements.c"
-"{ObjDir}outline.c.o" Ä "{ToolDir}outline.c"
-
-
-### Optional Dependencies ###
-### Build this target to clean out generated intermediate files. ###
-
-Clean Ä
- Delete {ObjFiles-PPC} {ExportFile} {ElementToolObjFile} {OutlineToolObjFile}
-
-### Build this target to clean out all generated files. ###
-
-Clean-All Ä Clean
- Delete {StLibFile} {ShLibFile} {StubFile} {ElementsTool} {OutlineTool}
-
-### Build this target to generate "include file" dependencies. ###
-
-Dependencies Ä $OutOfDate
- MakeDepend ¶
- -append {MAKEFILE} ¶
- -ignore "{CIncludes}" ¶
- -objdir "{ObjDir}" ¶
- -objext .o ¶
- {Defines} ¶
- {Includes} ¶
- {SrcFiles}
-
-
diff --git a/3rdparty/expat/lib/Makefile.am b/3rdparty/expat/lib/Makefile.am
new file mode 100644
index 00000000000..05343e235d8
--- /dev/null
+++ b/3rdparty/expat/lib/Makefile.am
@@ -0,0 +1,76 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+include_HEADERS = \
+ ../expat_config.h \
+ expat.h \
+ expat_external.h
+
+lib_LTLIBRARIES = libexpat.la
+
+libexpat_la_LDFLAGS = \
+ @AM_LDFLAGS@ \
+ -no-undefined \
+ -version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
+
+libexpat_la_SOURCES = \
+ xmlparse.c \
+ xmltok.c \
+ xmlrole.c
+
+doc_DATA = \
+ ../AUTHORS \
+ ../Changes
+
+install-data-hook:
+ cd "$(DESTDIR)$(docdir)" && $(am__mv) Changes changelog
+
+uninstall-local:
+ $(RM) "$(DESTDIR)$(docdir)/changelog"
+
+EXTRA_DIST = \
+ ascii.h \
+ asciitab.h \
+ expat_external.h \
+ expat.h \
+ iasciitab.h \
+ internal.h \
+ latin1tab.h \
+ libexpat.def \
+ libexpatw.def \
+ nametab.h \
+ siphash.h \
+ utf8tab.h \
+ winconfig.h \
+ xmlrole.h \
+ xmltok.h \
+ xmltok_impl.c \
+ xmltok_impl.h \
+ xmltok_ns.c
diff --git a/3rdparty/expat/lib/Makefile.in b/3rdparty/expat/lib/Makefile.in
new file mode 100644
index 00000000000..10f20d5533d
--- /dev/null
+++ b/3rdparty/expat/lib/Makefile.in
@@ -0,0 +1,810 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lib
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(include_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/expat_config.h
+CONFIG_CLEAN_FILES =
+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 = 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__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" \
+ "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libexpat_la_LIBADD =
+am_libexpat_la_OBJECTS = xmlparse.lo xmltok.lo xmlrole.lo
+libexpat_la_OBJECTS = $(am_libexpat_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libexpat_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libexpat_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/xmlparse.Plo ./$(DEPDIR)/xmlrole.Plo \
+ ./$(DEPDIR)/xmltok.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libexpat_la_SOURCES)
+DIST_SOURCES = $(libexpat_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(doc_DATA)
+HEADERS = $(include_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/conftools/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
+include_HEADERS = \
+ ../expat_config.h \
+ expat.h \
+ expat_external.h
+
+lib_LTLIBRARIES = libexpat.la
+libexpat_la_LDFLAGS = \
+ @AM_LDFLAGS@ \
+ -no-undefined \
+ -version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
+
+libexpat_la_SOURCES = \
+ xmlparse.c \
+ xmltok.c \
+ xmlrole.c
+
+doc_DATA = \
+ ../AUTHORS \
+ ../Changes
+
+EXTRA_DIST = \
+ ascii.h \
+ asciitab.h \
+ expat_external.h \
+ expat.h \
+ iasciitab.h \
+ internal.h \
+ latin1tab.h \
+ libexpat.def \
+ libexpatw.def \
+ nametab.h \
+ siphash.h \
+ utf8tab.h \
+ winconfig.h \
+ xmlrole.h \
+ xmltok.h \
+ xmltok_impl.c \
+ xmltok_impl.h \
+ xmltok_ns.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lib/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ 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)
+ @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:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libexpat.la: $(libexpat_la_OBJECTS) $(libexpat_la_DEPENDENCIES) $(EXTRA_libexpat_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libexpat_la_LINK) -rpath $(libdir) $(libexpat_la_OBJECTS) $(libexpat_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlparse.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlrole.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmltok.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-docDATA: $(doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ 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)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/xmlparse.Plo
+ -rm -f ./$(DEPDIR)/xmlrole.Plo
+ -rm -f ./$(DEPDIR)/xmltok.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-docDATA install-includeHEADERS
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/xmlparse.Plo
+ -rm -f ./$(DEPDIR)/xmlrole.Plo
+ -rm -f ./$(DEPDIR)/xmltok.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-docDATA uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-local
+
+.MAKE: install-am install-data-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-data-hook install-docDATA 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-pdf \
+ install-pdf-am 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 tags-am uninstall uninstall-am uninstall-docDATA \
+ uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-local
+
+.PRECIOUS: Makefile
+
+
+install-data-hook:
+ cd "$(DESTDIR)$(docdir)" && $(am__mv) Changes changelog
+
+uninstall-local:
+ $(RM) "$(DESTDIR)$(docdir)/changelog"
+
+# 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:
diff --git a/3rdparty/expat/lib/amigaconfig.h b/3rdparty/expat/lib/amigaconfig.h
deleted file mode 100644
index 49c92c70149..00000000000
--- a/3rdparty/expat/lib/amigaconfig.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef AMIGACONFIG_H
-#define AMIGACONFIG_H
-
-/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
-#define BYTEORDER 4321
-
-/* Define to 1 if you have the `bcopy' function. */
-#define HAVE_BCOPY 1
-
-/* Define to 1 if you have the `memmove' function. */
-#define HAVE_MEMMOVE 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* whether byteorder is bigendian */
-#define WORDS_BIGENDIAN
-
-/* Define to specify how much context to retain around the current parse
- point. */
-#define XML_CONTEXT_BYTES 1024
-
-/* Define to make parameter entity parsing functionality available. */
-#define XML_DTD
-
-/* Define to make XML Namespaces functionality available. */
-#define XML_NS
-
-#endif /* AMIGACONFIG_H */
diff --git a/3rdparty/expat/lib/ascii.h b/3rdparty/expat/lib/ascii.h
index d10530b09bd..c3587e57332 100644
--- a/3rdparty/expat/lib/ascii.h
+++ b/3rdparty/expat/lib/ascii.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define ASCII_A 0x41
diff --git a/3rdparty/expat/lib/asciitab.h b/3rdparty/expat/lib/asciitab.h
index 79a15c28ca1..63b1d1b4482 100644
--- a/3rdparty/expat/lib/asciitab.h
+++ b/3rdparty/expat/lib/asciitab.h
@@ -1,36 +1,64 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
-/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
-/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
-/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
-/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
-/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
-/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
-/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
-/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
-/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
-/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+ /* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
+ /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+ /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+ /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+ /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+ /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+ /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+ /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+ /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+ /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+ /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+ /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+ /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+ /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+ /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+ /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+ /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/3rdparty/expat/lib/expat.dsp b/3rdparty/expat/lib/expat.dsp
deleted file mode 100644
index bf728da056a..00000000000
--- a/3rdparty/expat/lib/expat.dsp
+++ /dev/null
@@ -1,185 +0,0 @@
-# Microsoft Developer Studio Project File - Name="expat" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=expat - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "expat.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "expat.mak" CFG="expat - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "expat - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "expat - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "expat - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPAT_EXPORTS" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COMPILED_FROM_DSP" /FD /c
-# SUBTRACT CPP /YX /Yc /Yu
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /dll /machine:I386
-# ADD LINK32 /nologo /dll /pdb:none /machine:I386 /out:"..\win32\bin\Release\libexpat.dll"
-
-!ELSEIF "$(CFG)" == "expat - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPAT_EXPORTS" /Yu"stdafx.h" /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "COMPILED_FROM_DSP" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 /nologo /dll /pdb:none /debug /machine:I386 /out:"..\win32\bin\Debug\libexpat.dll"
-
-!ENDIF
-
-# Begin Target
-
-# Name "expat - Win32 Release"
-# Name "expat - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\libexpat.def
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlparse.c
-
-!IF "$(CFG)" == "expat - Win32 Release"
-
-!ELSEIF "$(CFG)" == "expat - Win32 Debug"
-
-# ADD CPP /GX- /Od
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_ns.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\ascii.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\asciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat_external.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\iasciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\internal.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\latin1tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\nametab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/lib/expat.h b/3rdparty/expat/lib/expat.h
index ec62f140515..cb828db155f 100644
--- a/3rdparty/expat/lib/expat.h
+++ b/3rdparty/expat/lib/expat.h
@@ -1,19 +1,38 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef Expat_INCLUDED
#define Expat_INCLUDED 1
-#ifdef __VMS
-/* 0 1 2 3 0 1 2 3
- 1234567890123456789012345678901 1234567890123456789012345678901 */
-#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler
-#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler
-#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler
-#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg
-#endif
-
#include <stdlib.h>
#include "expat_external.h"
@@ -24,10 +43,9 @@ extern "C" {
struct XML_ParserStruct;
typedef struct XML_ParserStruct *XML_Parser;
-/* Should this be defined using stdbool.h when C99 is available? */
typedef unsigned char XML_Bool;
-#define XML_TRUE ((XML_Bool) 1)
-#define XML_FALSE ((XML_Bool) 0)
+#define XML_TRUE ((XML_Bool)1)
+#define XML_FALSE ((XML_Bool)0)
/* The XML_Status enum gives the possible return values for several
API functions. The preprocessor #defines are included so this
@@ -95,7 +113,9 @@ enum XML_Error {
/* Added in 2.0. */
XML_ERROR_RESERVED_PREFIX_XML,
XML_ERROR_RESERVED_PREFIX_XMLNS,
- XML_ERROR_RESERVED_NAMESPACE_URI
+ XML_ERROR_RESERVED_NAMESPACE_URI,
+ /* Added in 2.2.1. */
+ XML_ERROR_INVALID_ARGUMENT
};
enum XML_Content_Type {
@@ -135,25 +155,23 @@ enum XML_Content_Quant {
typedef struct XML_cp XML_Content;
struct XML_cp {
- enum XML_Content_Type type;
- enum XML_Content_Quant quant;
- XML_Char * name;
- unsigned int numchildren;
- XML_Content * children;
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ XML_Char *name;
+ unsigned int numchildren;
+ XML_Content *children;
};
-
/* This is called for an element declaration. See above for
description of the model argument. It's the caller's responsibility
to free model when finished with it.
*/
-typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
- const XML_Char *name,
- XML_Content *model);
+typedef void(XMLCALL *XML_ElementDeclHandler)(void *userData,
+ const XML_Char *name,
+ XML_Content *model);
XMLPARSEAPI(void)
-XML_SetElementDeclHandler(XML_Parser parser,
- XML_ElementDeclHandler eldecl);
+XML_SetElementDeclHandler(XML_Parser parser, XML_ElementDeclHandler eldecl);
/* The Attlist declaration handler is called for *each* attribute. So
a single Attlist declaration with multiple attributes declared will
@@ -163,17 +181,12 @@ XML_SetElementDeclHandler(XML_Parser parser,
value will be NULL in the case of "#REQUIRED". If "isrequired" is
true and default is non-NULL, then this is a "#FIXED" default.
*/
-typedef void (XMLCALL *XML_AttlistDeclHandler) (
- void *userData,
- const XML_Char *elname,
- const XML_Char *attname,
- const XML_Char *att_type,
- const XML_Char *dflt,
- int isrequired);
+typedef void(XMLCALL *XML_AttlistDeclHandler)(
+ void *userData, const XML_Char *elname, const XML_Char *attname,
+ const XML_Char *att_type, const XML_Char *dflt, int isrequired);
XMLPARSEAPI(void)
-XML_SetAttlistDeclHandler(XML_Parser parser,
- XML_AttlistDeclHandler attdecl);
+XML_SetAttlistDeclHandler(XML_Parser parser, XML_AttlistDeclHandler attdecl);
/* The XML declaration handler is called for *both* XML declarations
and text declarations. The way to distinguish is that the version
@@ -183,15 +196,13 @@ XML_SetAttlistDeclHandler(XML_Parser parser,
was no standalone parameter in the declaration, that it was given
as no, or that it was given as yes.
*/
-typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData,
- const XML_Char *version,
- const XML_Char *encoding,
- int standalone);
+typedef void(XMLCALL *XML_XmlDeclHandler)(void *userData,
+ const XML_Char *version,
+ const XML_Char *encoding,
+ int standalone);
XMLPARSEAPI(void)
-XML_SetXmlDeclHandler(XML_Parser parser,
- XML_XmlDeclHandler xmldecl);
-
+XML_SetXmlDeclHandler(XML_Parser parser, XML_XmlDeclHandler xmldecl);
typedef struct {
void *(*malloc_fcn)(size_t size);
@@ -219,7 +230,6 @@ XML_ParserCreate(const XML_Char *encoding);
XMLPARSEAPI(XML_Parser)
XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
-
/* Constructs a new parser using the memory management suite referred to
by memsuite. If memsuite is NULL, then use the standard library memory
suite. If namespaceSeparator is non-NULL it creates a parser with
@@ -235,7 +245,7 @@ XML_ParserCreate_MM(const XML_Char *encoding,
const XML_Char *namespaceSeparator);
/* Prepare a parser object to be re-used. This is particularly
- valuable when memory allocation overhead is disproportionatly high,
+ valuable when memory allocation overhead is disproportionately high,
such as when a large number of small documnents need to be parsed.
All handlers are cleared from the parser, except for the
unknownEncodingHandler. The parser's external state is re-initialized
@@ -249,31 +259,27 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
/* atts is array of name/value pairs, terminated by 0;
names and values are 0 terminated.
*/
-typedef void (XMLCALL *XML_StartElementHandler) (void *userData,
- const XML_Char *name,
- const XML_Char **atts);
-
-typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
- const XML_Char *name);
+typedef void(XMLCALL *XML_StartElementHandler)(void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+typedef void(XMLCALL *XML_EndElementHandler)(void *userData,
+ const XML_Char *name);
/* s is not 0 terminated. */
-typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData,
- const XML_Char *s,
- int len);
+typedef void(XMLCALL *XML_CharacterDataHandler)(void *userData,
+ const XML_Char *s, int len);
/* target and data are 0 terminated */
-typedef void (XMLCALL *XML_ProcessingInstructionHandler) (
- void *userData,
- const XML_Char *target,
- const XML_Char *data);
+typedef void(XMLCALL *XML_ProcessingInstructionHandler)(void *userData,
+ const XML_Char *target,
+ const XML_Char *data);
/* data is 0 terminated */
-typedef void (XMLCALL *XML_CommentHandler) (void *userData,
- const XML_Char *data);
+typedef void(XMLCALL *XML_CommentHandler)(void *userData, const XML_Char *data);
-typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData);
-typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
+typedef void(XMLCALL *XML_StartCdataSectionHandler)(void *userData);
+typedef void(XMLCALL *XML_EndCdataSectionHandler)(void *userData);
/* This is called for any characters in the XML document for which
there is no applicable handler. This includes both characters that
@@ -288,25 +294,23 @@ typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
default handler: for example, a comment might be split between
multiple calls.
*/
-typedef void (XMLCALL *XML_DefaultHandler) (void *userData,
- const XML_Char *s,
- int len);
+typedef void(XMLCALL *XML_DefaultHandler)(void *userData, const XML_Char *s,
+ int len);
/* This is called for the start of the DOCTYPE declaration, before
any DTD or internal subset is parsed.
*/
-typedef void (XMLCALL *XML_StartDoctypeDeclHandler) (
- void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid,
- int has_internal_subset);
+typedef void(XMLCALL *XML_StartDoctypeDeclHandler)(void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid,
+ int has_internal_subset);
/* This is called for the start of the DOCTYPE declaration when the
closing > is encountered, but after processing any external
subset.
*/
-typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
+typedef void(XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
/* This is called for entity declarations. The is_parameter_entity
argument will be non-zero if the entity is a parameter entity, zero
@@ -314,7 +318,7 @@ typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
For internal entities (<!ENTITY foo "bar">), value will
be non-NULL and systemId, publicID, and notationName will be NULL.
- The value string is NOT nul-terminated; the length is provided in
+ The value string is NOT null-terminated; the length is provided in
the value_length argument. Since it is legal to have zero-length
values, do not use this argument to test for internal entities.
@@ -326,23 +330,17 @@ typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
Note that is_parameter_entity can't be changed to XML_Bool, since
that would break binary compatibility.
*/
-typedef void (XMLCALL *XML_EntityDeclHandler) (
- void *userData,
- const XML_Char *entityName,
- int is_parameter_entity,
- const XML_Char *value,
- int value_length,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName);
+typedef void(XMLCALL *XML_EntityDeclHandler)(
+ void *userData, const XML_Char *entityName, int is_parameter_entity,
+ const XML_Char *value, int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName);
XMLPARSEAPI(void)
-XML_SetEntityDeclHandler(XML_Parser parser,
- XML_EntityDeclHandler handler);
+XML_SetEntityDeclHandler(XML_Parser parser, XML_EntityDeclHandler handler);
/* OBSOLETE -- OBSOLETE -- OBSOLETE
- This handler has been superceded by the EntityDeclHandler above.
+ This handler has been superseded by the EntityDeclHandler above.
It is provided here for backward compatibility.
This is called for a declaration of an unparsed (NDATA) entity.
@@ -350,24 +348,20 @@ XML_SetEntityDeclHandler(XML_Parser parser,
entityName, systemId and notationName arguments will never be
NULL. The other arguments may be.
*/
-typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) (
- void *userData,
- const XML_Char *entityName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName);
+typedef void(XMLCALL *XML_UnparsedEntityDeclHandler)(
+ void *userData, const XML_Char *entityName, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName);
/* This is called for a declaration of notation. The base argument is
whatever was set by XML_SetBase. The notationName will never be
NULL. The other arguments can be.
*/
-typedef void (XMLCALL *XML_NotationDeclHandler) (
- void *userData,
- const XML_Char *notationName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId);
+typedef void(XMLCALL *XML_NotationDeclHandler)(void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
/* When namespace processing is enabled, these are called once for
each namespace declaration. The call to the start and end element
@@ -375,14 +369,12 @@ typedef void (XMLCALL *XML_NotationDeclHandler) (
declaration handlers. For an xmlns attribute, prefix will be
NULL. For an xmlns="" attribute, uri will be NULL.
*/
-typedef void (XMLCALL *XML_StartNamespaceDeclHandler) (
- void *userData,
- const XML_Char *prefix,
- const XML_Char *uri);
+typedef void(XMLCALL *XML_StartNamespaceDeclHandler)(void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
-typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
- void *userData,
- const XML_Char *prefix);
+typedef void(XMLCALL *XML_EndNamespaceDeclHandler)(void *userData,
+ const XML_Char *prefix);
/* This is called if the document is not standalone, that is, it has an
external subset or a reference to a parameter entity, but does not
@@ -393,7 +385,7 @@ typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
conditions above this handler will only be called if the referenced
entity was actually read.
*/
-typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
+typedef int(XMLCALL *XML_NotStandaloneHandler)(void *userData);
/* This is called for a reference to an external parsed general
entity. The referenced entity is not automatically parsed. The
@@ -429,12 +421,11 @@ typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
Note that unlike other handlers the first argument is the parser,
not userData.
*/
-typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
- XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId);
+typedef int(XMLCALL *XML_ExternalEntityRefHandler)(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
/* This is called in two situations:
1) An entity reference is encountered for which no declaration
@@ -446,10 +437,9 @@ typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
the event would be out of sync with the reporting of the
declarations or attribute values
*/
-typedef void (XMLCALL *XML_SkippedEntityHandler) (
- void *userData,
- const XML_Char *entityName,
- int is_parameter_entity);
+typedef void(XMLCALL *XML_SkippedEntityHandler)(void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
/* This structure is filled in by the XML_UnknownEncodingHandler to
provide information to the parser about encodings that are unknown
@@ -506,8 +496,8 @@ typedef void (XMLCALL *XML_SkippedEntityHandler) (
typedef struct {
int map[256];
void *data;
- int (XMLCALL *convert)(void *data, const char *s);
- void (XMLCALL *release)(void *data);
+ int(XMLCALL *convert)(void *data, const char *s);
+ void(XMLCALL *release)(void *data);
} XML_Encoding;
/* This is called for an encoding that is unknown to the parser.
@@ -525,23 +515,19 @@ typedef struct {
If info does not describe a suitable encoding, then the parser will
return an XML_UNKNOWN_ENCODING error.
*/
-typedef int (XMLCALL *XML_UnknownEncodingHandler) (
- void *encodingHandlerData,
- const XML_Char *name,
- XML_Encoding *info);
+typedef int(XMLCALL *XML_UnknownEncodingHandler)(void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
XMLPARSEAPI(void)
-XML_SetElementHandler(XML_Parser parser,
- XML_StartElementHandler start,
+XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start,
XML_EndElementHandler end);
XMLPARSEAPI(void)
-XML_SetStartElementHandler(XML_Parser parser,
- XML_StartElementHandler handler);
+XML_SetStartElementHandler(XML_Parser parser, XML_StartElementHandler handler);
XMLPARSEAPI(void)
-XML_SetEndElementHandler(XML_Parser parser,
- XML_EndElementHandler handler);
+XML_SetEndElementHandler(XML_Parser parser, XML_EndElementHandler handler);
XMLPARSEAPI(void)
XML_SetCharacterDataHandler(XML_Parser parser,
@@ -551,8 +537,7 @@ XMLPARSEAPI(void)
XML_SetProcessingInstructionHandler(XML_Parser parser,
XML_ProcessingInstructionHandler handler);
XMLPARSEAPI(void)
-XML_SetCommentHandler(XML_Parser parser,
- XML_CommentHandler handler);
+XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler);
XMLPARSEAPI(void)
XML_SetCdataSectionHandler(XML_Parser parser,
@@ -572,20 +557,17 @@ XML_SetEndCdataSectionHandler(XML_Parser parser,
default handler, or to the skipped entity handler, if one is set.
*/
XMLPARSEAPI(void)
-XML_SetDefaultHandler(XML_Parser parser,
- XML_DefaultHandler handler);
+XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler);
/* This sets the default handler but does not inhibit expansion of
internal entities. The entity reference will not be passed to the
default handler.
*/
XMLPARSEAPI(void)
-XML_SetDefaultHandlerExpand(XML_Parser parser,
- XML_DefaultHandler handler);
+XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler);
XMLPARSEAPI(void)
-XML_SetDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start,
+XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start,
XML_EndDoctypeDeclHandler end);
XMLPARSEAPI(void)
@@ -593,16 +575,14 @@ XML_SetStartDoctypeDeclHandler(XML_Parser parser,
XML_StartDoctypeDeclHandler start);
XMLPARSEAPI(void)
-XML_SetEndDoctypeDeclHandler(XML_Parser parser,
- XML_EndDoctypeDeclHandler end);
+XML_SetEndDoctypeDeclHandler(XML_Parser parser, XML_EndDoctypeDeclHandler end);
XMLPARSEAPI(void)
XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
XML_UnparsedEntityDeclHandler handler);
XMLPARSEAPI(void)
-XML_SetNotationDeclHandler(XML_Parser parser,
- XML_NotationDeclHandler handler);
+XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler);
XMLPARSEAPI(void)
XML_SetNamespaceDeclHandler(XML_Parser parser,
@@ -630,8 +610,7 @@ XML_SetExternalEntityRefHandler(XML_Parser parser,
instead of the parser object.
*/
XMLPARSEAPI(void)
-XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
- void *arg);
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg);
XMLPARSEAPI(void)
XML_SetSkippedEntityHandler(XML_Parser parser,
@@ -706,11 +685,11 @@ XML_UseParserAsHandlerArg(XML_Parser parser);
be called, despite an external subset being parsed.
Note: If XML_DTD is not defined when Expat is compiled, returns
XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+ Note: If parser == NULL, returns XML_ERROR_INVALID_ARGUMENT.
*/
XMLPARSEAPI(enum XML_Error)
XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
-
/* Sets the base to be used for resolving relative URIs in system
identifiers in declarations. Resolving relative identifiers is
left to the application: this value will be passed through as the
@@ -728,16 +707,17 @@ XML_GetBase(XML_Parser parser);
/* Returns the number of the attribute/value pairs passed in last call
to the XML_StartElementHandler that were specified in the start-tag
rather than defaulted. Each attribute/value pair counts as 2; thus
- this correspondds to an index into the atts array passed to the
- XML_StartElementHandler.
+ this corresponds to an index into the atts array passed to the
+ XML_StartElementHandler. Returns -1 if parser == NULL.
*/
XMLPARSEAPI(int)
XML_GetSpecifiedAttributeCount(XML_Parser parser);
/* Returns the index of the ID attribute passed in the last call to
- XML_StartElementHandler, or -1 if there is no ID attribute. Each
- attribute/value pair counts as 2; thus this correspondds to an
- index into the atts array passed to the XML_StartElementHandler.
+ XML_StartElementHandler, or -1 if there is no ID attribute or
+ parser == NULL. Each attribute/value pair counts as 2; thus this
+ corresponds to an index into the atts array passed to the
+ XML_StartElementHandler.
*/
XMLPARSEAPI(int)
XML_GetIdAttributeIndex(XML_Parser parser);
@@ -749,10 +729,10 @@ XML_GetIdAttributeIndex(XML_Parser parser);
info->valueEnd - info->valueStart = 4 bytes.
*/
typedef struct {
- XML_Index nameStart; /* Offset to beginning of the attribute name. */
- XML_Index nameEnd; /* Offset after the attribute name's last byte. */
- XML_Index valueStart; /* Offset to beginning of the attribute value. */
- XML_Index valueEnd; /* Offset after the attribute value's last byte. */
+ XML_Index nameStart; /* Offset to beginning of the attribute name. */
+ XML_Index nameEnd; /* Offset after the attribute name's last byte. */
+ XML_Index valueStart; /* Offset to beginning of the attribute value. */
+ XML_Index valueEnd; /* Offset after the attribute value's last byte. */
} XML_AttrInfo;
/* Returns an array of XML_AttrInfo structures for the attribute/value pairs
@@ -788,20 +768,20 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
(resumable = 0) an already suspended parser. Some call-backs may
still follow because they would otherwise get lost. Examples:
- endElementHandler() for empty elements when stopped in
- startElementHandler(),
- - endNameSpaceDeclHandler() when stopped in endElementHandler(),
+ startElementHandler(),
+ - endNameSpaceDeclHandler() when stopped in endElementHandler(),
and possibly others.
Can be called from most handlers, including DTD related call-backs,
except when parsing an external parameter entity and resumable != 0.
Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
- Possible error codes:
+ Possible error codes:
- XML_ERROR_SUSPENDED: when suspending an already suspended parser.
- XML_ERROR_FINISHED: when the parser has already finished.
- XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
- When resumable != 0 (true) then parsing is suspended, that is,
- XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED.
+ When resumable != 0 (true) then parsing is suspended, that is,
+ XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED.
Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
@@ -812,7 +792,7 @@ XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
the externalEntityRefHandler() to call XML_StopParser() on the parent
parser (recursively), if one wants to stop parsing altogether.
- When suspended, parsing can be resumed by calling XML_ResumeParser().
+ When suspended, parsing can be resumed by calling XML_ResumeParser().
*/
XMLPARSEAPI(enum XML_Status)
XML_StopParser(XML_Parser parser, XML_Bool resumable);
@@ -820,7 +800,7 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable);
/* Resumes parsing after it has been suspended with XML_StopParser().
Must not be called from within a handler call-back. Returns same
status codes as XML_Parse() or XML_ParseBuffer().
- Additional error code XML_ERROR_NOT_SUSPENDED possible.
+ Additional error code XML_ERROR_NOT_SUSPENDED possible.
*Note*:
This must be called on the most deeply nested child parser instance
@@ -832,12 +812,7 @@ XML_StopParser(XML_Parser parser, XML_Bool resumable);
XMLPARSEAPI(enum XML_Status)
XML_ResumeParser(XML_Parser parser);
-enum XML_Parsing {
- XML_INITIALIZED,
- XML_PARSING,
- XML_FINISHED,
- XML_SUSPENDED
-};
+enum XML_Parsing { XML_INITIALIZED, XML_PARSING, XML_FINISHED, XML_SUSPENDED };
typedef struct {
enum XML_Parsing parsing;
@@ -869,8 +844,7 @@ XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
Otherwise returns a new XML_Parser object.
*/
XMLPARSEAPI(XML_Parser)
-XML_ExternalEntityParserCreate(XML_Parser parser,
- const XML_Char *context,
+XML_ExternalEntityParserCreate(XML_Parser parser, const XML_Char *context,
const XML_Char *encoding);
enum XML_ParamEntityParsing {
@@ -901,6 +875,7 @@ enum XML_ParamEntityParsing {
entities is requested; otherwise it will return non-zero.
Note: If XML_SetParamEntityParsing is called after XML_Parse or
XML_ParseBuffer, then it has no effect and will always return 0.
+ Note: If parser == NULL, the function will do nothing and return 0.
*/
XMLPARSEAPI(int)
XML_SetParamEntityParsing(XML_Parser parser,
@@ -910,10 +885,10 @@ XML_SetParamEntityParsing(XML_Parser parser,
Helps in preventing DoS attacks based on predicting hash
function behavior. This must be called before parsing is started.
Returns 1 if successful, 0 when called after parsing has started.
+ Note: If parser == NULL, the function will do nothing and return 0.
*/
XMLPARSEAPI(int)
-XML_SetHashSalt(XML_Parser parser,
- unsigned long hash_salt);
+XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt);
/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
XML_GetErrorCode returns information about the error.
@@ -930,12 +905,16 @@ XML_GetErrorCode(XML_Parser parser);
be within the relevant markup. When called outside of the callback
functions, the position indicated will be just past the last parse
event (regardless of whether there was an associated callback).
-
+
They may also be called after returning from a call to XML_Parse
or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then
the location is the location of the character at which the error
was detected; otherwise the location is the location of the last
parse event, as described above.
+
+ Note: XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber
+ return 0 to indicate an error.
+ Note: XML_GetCurrentByteIndex returns -1 to indicate an error.
*/
XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
@@ -958,14 +937,12 @@ XML_GetCurrentByteCount(XML_Parser parser);
the handler that makes the call.
*/
XMLPARSEAPI(const char *)
-XML_GetInputContext(XML_Parser parser,
- int *offset,
- int *size);
+XML_GetInputContext(XML_Parser parser, int *offset, int *size);
/* For backwards compatibility with previous versions. */
-#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
+#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
-#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
+#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
/* Frees the content model passed to the element declaration handler */
XMLPARSEAPI(void)
@@ -973,9 +950,12 @@ XML_FreeContentModel(XML_Parser parser, XML_Content *model);
/* Exposing the memory handling functions used in Expat */
XMLPARSEAPI(void *)
+XML_ATTR_MALLOC
+XML_ATTR_ALLOC_SIZE(2)
XML_MemMalloc(XML_Parser parser, size_t size);
XMLPARSEAPI(void *)
+XML_ATTR_ALLOC_SIZE(3)
XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
XMLPARSEAPI(void)
@@ -1022,23 +1002,20 @@ enum XML_FeatureEnum {
};
typedef struct {
- enum XML_FeatureEnum feature;
- const XML_LChar *name;
- long int value;
+ enum XML_FeatureEnum feature;
+ const XML_LChar *name;
+ long int value;
} XML_Feature;
XMLPARSEAPI(const XML_Feature *)
XML_GetFeatureList(void);
-
-/* Expat follows the GNU/Linux convention of odd number minor version for
- beta/development releases and even number minor version for stable
- releases. Micro is bumped with each release, and set to 0 with each
- change to major or minor version.
+/* Expat follows the semantic versioning convention.
+ See http://semver.org.
*/
#define XML_MAJOR_VERSION 2
-#define XML_MINOR_VERSION 1
-#define XML_MICRO_VERSION 1
+#define XML_MINOR_VERSION 2
+#define XML_MICRO_VERSION 10
#ifdef __cplusplus
}
diff --git a/3rdparty/expat/lib/expat_external.h b/3rdparty/expat/lib/expat_external.h
index 2c03284ea26..b3b6e74d9d2 100644
--- a/3rdparty/expat/lib/expat_external.h
+++ b/3rdparty/expat/lib/expat_external.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef Expat_External_INCLUDED
@@ -7,10 +35,6 @@
/* External API definitions */
-#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
-#define XML_USE_MSC_EXTENSIONS 1
-#endif
-
/* Expat tries very hard to make the API boundary very specifically
defined. There are two macros defined to control this boundary;
each of these can be defined before including this header to
@@ -34,11 +58,11 @@
system headers may assume the cdecl convention.
*/
#ifndef XMLCALL
-#if defined(_MSC_VER)
-#define XMLCALL __cdecl
-#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
-#define XMLCALL __attribute__((cdecl))
-#else
+# if defined(_MSC_VER)
+# define XMLCALL __cdecl
+# elif defined(__GNUC__) && defined(__i386) && ! defined(__INTEL_COMPILER)
+# define XMLCALL __attribute__((cdecl))
+# else
/* For any platform which uses this definition and supports more than
one calling convention, we need to extend this definition to
declare the convention used on that platform, if it's possible to
@@ -49,28 +73,47 @@
pre-processor and how to specify the same calling convention as the
platform's malloc() implementation.
*/
-#define XMLCALL
-#endif
-#endif /* not defined XMLCALL */
-
+# define XMLCALL
+# endif
+#endif /* not defined XMLCALL */
-#if !defined(XML_STATIC) && !defined(XMLIMPORT)
-#ifndef XML_BUILDING_EXPAT
+#if ! defined(XML_STATIC) && ! defined(XMLIMPORT)
+# ifndef XML_BUILDING_EXPAT
/* using Expat from an application */
-#ifdef XML_USE_MSC_EXTENSIONS
-#define XMLIMPORT __declspec(dllimport)
-#endif
+# if defined(_MSC_EXTENSIONS) && ! defined(__BEOS__) && ! defined(__CYGWIN__)
+# define XMLIMPORT __declspec(dllimport)
+# endif
+
+# endif
+#endif /* not defined XML_STATIC */
+#ifndef XML_ENABLE_VISIBILITY
+# define XML_ENABLE_VISIBILITY 0
#endif
-#endif /* not defined XML_STATIC */
+#if ! defined(XMLIMPORT) && XML_ENABLE_VISIBILITY
+# define XMLIMPORT __attribute__((visibility("default")))
+#endif
/* If we didn't define it above, define it away: */
#ifndef XMLIMPORT
-#define XMLIMPORT
+# define XMLIMPORT
#endif
+#if defined(__GNUC__) \
+ && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+# define XML_ATTR_MALLOC __attribute__((__malloc__))
+#else
+# define XML_ATTR_MALLOC
+#endif
+
+#if defined(__GNUC__) \
+ && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+# define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+#else
+# define XML_ATTR_ALLOC_SIZE(x)
+#endif
#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
@@ -79,30 +122,30 @@ extern "C" {
#endif
#ifdef XML_UNICODE_WCHAR_T
-#define XML_UNICODE
+# ifndef XML_UNICODE
+# define XML_UNICODE
+# endif
+# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
+# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
+# endif
#endif
-#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
-#ifdef XML_UNICODE_WCHAR_T
+#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
+# ifdef XML_UNICODE_WCHAR_T
typedef wchar_t XML_Char;
typedef wchar_t XML_LChar;
-#else
+# else
typedef unsigned short XML_Char;
typedef char XML_LChar;
-#endif /* XML_UNICODE_WCHAR_T */
-#else /* Information is UTF-8 encoded. */
+# endif /* XML_UNICODE_WCHAR_T */
+#else /* Information is UTF-8 encoded. */
typedef char XML_Char;
typedef char XML_LChar;
-#endif /* XML_UNICODE */
+#endif /* XML_UNICODE */
-#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
-typedef __int64 XML_Index;
-typedef unsigned __int64 XML_Size;
-#else
+#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
typedef long long XML_Index;
typedef unsigned long long XML_Size;
-#endif
#else
typedef long XML_Index;
typedef unsigned long XML_Size;
diff --git a/3rdparty/expat/lib/expat_static.dsp b/3rdparty/expat/lib/expat_static.dsp
deleted file mode 100644
index 180f0dc6c88..00000000000
--- a/3rdparty/expat/lib/expat_static.dsp
+++ /dev/null
@@ -1,162 +0,0 @@
-# Microsoft Developer Studio Project File - Name="expat_static" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=expat_static - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "expat_static.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "expat_static.mak" CFG="expat_static - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "expat_static - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "expat_static - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "expat_static - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "expat_static___Win32_Release"
-# PROP BASE Intermediate_Dir "expat_static___Win32_Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release_static"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "COMPILED_FROM_DSP" /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x1009 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"..\win32\bin\Release\libexpatMT.lib"
-
-!ELSEIF "$(CFG)" == "expat_static - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "expat_static___Win32_Debug"
-# PROP BASE Intermediate_Dir "expat_static___Win32_Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug_static"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "COMPILED_FROM_DSP" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x1009 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"..\win32\bin\Debug\libexpatMT.lib"
-
-!ENDIF
-
-# Begin Target
-
-# Name "expat_static - Win32 Release"
-# Name "expat_static - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\xmlparse.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_ns.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\ascii.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\asciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat_external.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\iasciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\internal.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\latin1tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\nametab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.h
-# End Source File
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/lib/expatw.dsp b/3rdparty/expat/lib/expatw.dsp
deleted file mode 100644
index b91a117cc4a..00000000000
--- a/3rdparty/expat/lib/expatw.dsp
+++ /dev/null
@@ -1,185 +0,0 @@
-# Microsoft Developer Studio Project File - Name="expatw" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=expatw - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "expatw.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "expatw.mak" CFG="expatw - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "expatw - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "expatw - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "expatw - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release-w"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPAT_EXPORTS" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "COMPILED_FROM_DSP" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XML_UNICODE_WCHAR_T" /FD /c
-# SUBTRACT CPP /YX /Yc /Yu
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /dll /machine:I386
-# ADD LINK32 /nologo /dll /pdb:none /machine:I386 /out:"..\win32\bin\Release\libexpatw.dll"
-
-!ELSEIF "$(CFG)" == "expatw - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug-w"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPAT_EXPORTS" /Yu"stdafx.h" /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "_DEBUG" /D "COMPILED_FROM_DSP" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XML_UNICODE_WCHAR_T" /FR /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 /nologo /dll /pdb:none /debug /machine:I386 /out:"..\win32\bin\Debug\libexpatw.dll"
-
-!ENDIF
-
-# Begin Target
-
-# Name "expatw - Win32 Release"
-# Name "expatw - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\libexpatw.def
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlparse.c
-
-!IF "$(CFG)" == "expatw - Win32 Release"
-
-!ELSEIF "$(CFG)" == "expatw - Win32 Debug"
-
-# ADD CPP /GX- /Od
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_ns.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\ascii.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\asciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat_external.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\iasciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\internal.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\latin1tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\nametab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/lib/expatw_static.dsp b/3rdparty/expat/lib/expatw_static.dsp
deleted file mode 100644
index d28632cf494..00000000000
--- a/3rdparty/expat/lib/expatw_static.dsp
+++ /dev/null
@@ -1,162 +0,0 @@
-# Microsoft Developer Studio Project File - Name="expatw_static" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=expatw_static - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "expatw_static.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "expatw_static.mak" CFG="expatw_static - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "expatw_static - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "expatw_static - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "expatw_static - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "expatw_static___Win32_Release"
-# PROP BASE Intermediate_Dir "expatw_static___Win32_Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release-w_static"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "COMPILED_FROM_DSP" /D "XML_UNICODE_WCHAR_T" /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x1009 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"..\win32\bin\Release\libexpatwMT.lib"
-
-!ELSEIF "$(CFG)" == "expatw_static - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "expatw_static___Win32_Debug"
-# PROP BASE Intermediate_Dir "expatw_static___Win32_Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug-w_static"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_LIB" /D "COMPILED_FROM_DSP" /D "XML_UNICODE_WCHAR_T" /FR /FD /GZ /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x1009 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /out:"..\win32\bin\Debug\libexpatwMT.lib"
-
-!ENDIF
-
-# Begin Target
-
-# Name "expatw_static - Win32 Release"
-# Name "expatw_static - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\xmlparse.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_ns.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\ascii.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\asciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\expat_external.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\iasciitab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\internal.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\latin1tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\nametab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8tab.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlrole.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltok_impl.h
-# End Source File
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/lib/iasciitab.h b/3rdparty/expat/lib/iasciitab.h
index 24a1d5ccc9a..ea97cfcf678 100644
--- a/3rdparty/expat/lib/iasciitab.h
+++ b/3rdparty/expat/lib/iasciitab.h
@@ -1,37 +1,65 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
-/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
-/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
-/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
-/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
-/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
-/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
-/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
-/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
-/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
-/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+ /* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
+ /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+ /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+ /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+ /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+ /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+ /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+ /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+ /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+ /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+ /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+ /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+ /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+ /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+ /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+ /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+ /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/3rdparty/expat/lib/internal.h b/3rdparty/expat/lib/internal.h
index dd5454831da..60913dab762 100644
--- a/3rdparty/expat/lib/internal.h
+++ b/3rdparty/expat/lib/internal.h
@@ -18,9 +18,38 @@
Note: Use of these macros is based on judgement, not hard rules,
and therefore subject to change.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
+#if defined(__GNUC__) && defined(__i386__) && ! defined(__MINGW32__)
/* We'll use this version by default only where we know it helps.
regparm() generates warnings on Solaris boxes. See SF bug #692878.
@@ -30,8 +59,8 @@
#define FASTCALL __attribute__((stdcall, regparm(3)))
and let's try this:
*/
-#define FASTCALL __attribute__((regparm(3)))
-#define PTRFASTCALL __attribute__((regparm(3)))
+# define FASTCALL __attribute__((regparm(3)))
+# define PTRFASTCALL __attribute__((regparm(3)))
#endif
/* Using __fastcall seems to have an unexpected negative effect under
@@ -45,29 +74,50 @@
/* Make sure all of these are defined if they aren't already. */
#ifndef FASTCALL
-#define FASTCALL
+# define FASTCALL
#endif
#ifndef PTRCALL
-#define PTRCALL
+# define PTRCALL
#endif
#ifndef PTRFASTCALL
-#define PTRFASTCALL
+# define PTRFASTCALL
#endif
#ifndef XML_MIN_SIZE
-#if !defined(__cplusplus) && !defined(inline)
-#ifdef __GNUC__
-#define inline __inline
-#endif /* __GNUC__ */
-#endif
+# if ! defined(__cplusplus) && ! defined(inline)
+# ifdef __GNUC__
+# define inline __inline
+# endif /* __GNUC__ */
+# endif
#endif /* XML_MIN_SIZE */
#ifdef __cplusplus
-#define inline inline
+# define inline inline
#else
-#ifndef inline
-#define inline
+# ifndef inline
+# define inline
+# endif
+#endif
+
+#ifndef UNUSED_P
+# define UNUSED_P(p) (void)p
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef XML_ENABLE_VISIBILITY
+# if XML_ENABLE_VISIBILITY
+__attribute__((visibility("default")))
+# endif
#endif
+void
+_INTERNAL_trim_to_complete_utf8_characters(const char *from,
+ const char **fromLimRef);
+
+#ifdef __cplusplus
+}
#endif
diff --git a/3rdparty/expat/lib/latin1tab.h b/3rdparty/expat/lib/latin1tab.h
index 53c25d76b26..6f916041355 100644
--- a/3rdparty/expat/lib/latin1tab.h
+++ b/3rdparty/expat/lib/latin1tab.h
@@ -1,36 +1,64 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
-/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
-/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
-/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+ /* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
+ /* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+ /* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+ /* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+ /* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+ /* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+ /* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/3rdparty/expat/lib/libexpat.def b/3rdparty/expat/lib/libexpat.def
index 79b049116de..16faf5955e7 100644
--- a/3rdparty/expat/lib/libexpat.def
+++ b/3rdparty/expat/lib/libexpat.def
@@ -73,4 +73,6 @@ EXPORTS
XML_GetParsingStatus @65
; added with version 2.1.1
; XML_GetAttributeInfo @66
- XML_SetHashSalt @67@
+ XML_SetHashSalt @67
+; added with version 2.2.5
+ _INTERNAL_trim_to_complete_utf8_characters @68
diff --git a/3rdparty/expat/lib/libexpatw.def b/3rdparty/expat/lib/libexpatw.def
index 79b049116de..16faf5955e7 100644
--- a/3rdparty/expat/lib/libexpatw.def
+++ b/3rdparty/expat/lib/libexpatw.def
@@ -73,4 +73,6 @@ EXPORTS
XML_GetParsingStatus @65
; added with version 2.1.1
; XML_GetAttributeInfo @66
- XML_SetHashSalt @67@
+ XML_SetHashSalt @67
+; added with version 2.2.5
+ _INTERNAL_trim_to_complete_utf8_characters @68
diff --git a/3rdparty/expat/lib/macconfig.h b/3rdparty/expat/lib/macconfig.h
deleted file mode 100644
index 2725caaf54a..00000000000
--- a/3rdparty/expat/lib/macconfig.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*================================================================
-** Copyright 2000, Clark Cooper
-** All rights reserved.
-**
-** This is free software. You are permitted to copy, distribute, or modify
-** it under the terms of the MIT/X license (contained in the COPYING file
-** with this distribution.)
-**
-*/
-
-#ifndef MACCONFIG_H
-#define MACCONFIG_H
-
-
-/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
-#define BYTEORDER 4321
-
-/* Define to 1 if you have the `bcopy' function. */
-#undef HAVE_BCOPY
-
-/* Define to 1 if you have the `memmove' function. */
-#define HAVE_MEMMOVE
-
-/* Define to 1 if you have a working `mmap' system call. */
-#undef HAVE_MMAP
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
-/* whether byteorder is bigendian */
-#define WORDS_BIGENDIAN
-
-/* Define to specify how much context to retain around the current parse
- point. */
-#undef XML_CONTEXT_BYTES
-
-/* Define to make parameter entity parsing functionality available. */
-#define XML_DTD
-
-/* Define to make XML Namespaces functionality available. */
-#define XML_NS
-
-/* Define to empty if `const' does not conform to ANSI C. */
-#undef const
-
-/* Define to `long' if <sys/types.h> does not define. */
-#define off_t long
-
-/* Define to `unsigned' if <sys/types.h> does not define. */
-#undef size_t
-
-
-#endif /* ifndef MACCONFIG_H */
diff --git a/3rdparty/expat/lib/nametab.h b/3rdparty/expat/lib/nametab.h
index b05e62c77a6..3681df348ee 100644
--- a/3rdparty/expat/lib/nametab.h
+++ b/3rdparty/expat/lib/nametab.h
@@ -1,150 +1,136 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
static const unsigned namingBitmap[] = {
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
-0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
-0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
-0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
-0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
-0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
-0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
-0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
-0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
-0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
-0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
-0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
-0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
-0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
-0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
-0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
-0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
-0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
-0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
-0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
-0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
-0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
-0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
-0x40000000, 0xF580C900, 0x00000007, 0x02010800,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
-0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
-0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
-0x00000000, 0x00004C40, 0x00000000, 0x00000000,
-0x00000007, 0x00000000, 0x00000000, 0x00000000,
-0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
-0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
-0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
-0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
-0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
-0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
-0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
-0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
-0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
-0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
-0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
-0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
-0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
-0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
-0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
-0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
-0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
-0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
-0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
-0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
-0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
-0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
-0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
-0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
-0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
-0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
-0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
-0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x00000000, 0x00000000,
-0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
-0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
-0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x04000000,
+ 0x87FFFFFE, 0x07FFFFFE, 0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
+ 0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFE00F, 0xFC31FFFF, 0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+ 0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, 0xFFFF0003, 0xFFFFFFFF,
+ 0xFFFF199F, 0x033FCFFF, 0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+ 0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, 0x00000000, 0x07FFFFFE,
+ 0x000007FE, 0xFFFE0000, 0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
+ 0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, 0xFFF99FE0, 0x03C5FDFF,
+ 0xB0000000, 0x00030003, 0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
+ 0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, 0xFFF99FE0, 0x23CDFDFF,
+ 0xB0000000, 0x00000003, 0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
+ 0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, 0xFFFDDFE0, 0x03EFFDFF,
+ 0x40000000, 0x00000003, 0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x000D7FFF,
+ 0x0000003F, 0x00000000, 0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, 0x0007DAED, 0x50000000,
+ 0x82315001, 0x002C62AB, 0x40000000, 0xF580C900, 0x00000007, 0x02010800,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0FFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x03FFFFFF, 0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
+ 0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, 0x00000000, 0x00004C40,
+ 0x00000000, 0x00000000, 0x00000007, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, 0x001FFFFF, 0xFFFFFFFE,
+ 0xFFFFFFFF, 0x07FFFFFF, 0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000000F,
+ 0x00000000, 0x00000000, 0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
+ 0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, 0x00FFFFFF, 0x00000000,
+ 0xFFFF0000, 0xFFFFFFFF, 0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, 0xFFFFD7C0, 0xFFFFFFFB,
+ 0x547F7FFF, 0x000FFFFD, 0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+ 0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, 0x00000000, 0xFFFE0000,
+ 0x027FFFFF, 0xFFFFFFFE, 0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
+ 0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, 0xFFFFFFFF, 0x7CFFFFFF,
+ 0xFFEF7FFF, 0x03FF3DFF, 0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
+ 0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, 0xFFF987E4, 0xD36DFDFF,
+ 0x5E003987, 0x001FFFC0, 0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
+ 0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, 0xD63DC7EC, 0xC3BFC718,
+ 0x00803DC7, 0x0000FF80, 0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
+ 0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, 0xFFFDDFEC, 0xC3FFFDFF,
+ 0x00803DCF, 0x0000FFC3, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, 0xFEF02596, 0x3BFF6CAE,
+ 0x03FF3F5F, 0x00000000, 0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
+ 0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
+ 0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, 0x661FFFFF, 0xFFFFFFFE,
+ 0xFFFFFFFF, 0x77FFFFFF,
};
static const unsigned char nmstrtPages[] = {
-0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
-0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
-0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x09, 0x0A, 0x0B,
+ 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, 0x00, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char namePages[] = {
-0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
-0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
-0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
-0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
-0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, 0x00, 0x1F, 0x20, 0x21,
+ 0x22, 0x23, 0x24, 0x25, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, 0x26, 0x14, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
};
diff --git a/3rdparty/expat/lib/siphash.h b/3rdparty/expat/lib/siphash.h
new file mode 100644
index 00000000000..bfee65a332f
--- /dev/null
+++ b/3rdparty/expat/lib/siphash.h
@@ -0,0 +1,398 @@
+/* ==========================================================================
+ * siphash.h - SipHash-2-4 in a single header file
+ * --------------------------------------------------------------------------
+ * Derived by William Ahern from the reference implementation[1] published[2]
+ * by Jean-Philippe Aumasson and Daniel J. Berstein.
+ * Minimal changes by Sebastian Pipping and Victor Stinner on top, see below.
+ * Licensed under the CC0 Public Domain Dedication license.
+ *
+ * 1. https://www.131002.net/siphash/siphash24.c
+ * 2. https://www.131002.net/siphash/
+ * --------------------------------------------------------------------------
+ * HISTORY:
+ *
+ * 2019-08-03 (Sebastian Pipping)
+ * - Mark part of sip24_valid as to be excluded from clang-format
+ * - Re-format code using clang-format 9
+ *
+ * 2018-07-08 (Anton Maklakov)
+ * - Add "fall through" markers for GCC's -Wimplicit-fallthrough
+ *
+ * 2017-11-03 (Sebastian Pipping)
+ * - Hide sip_tobin and sip_binof unless SIPHASH_TOBIN macro is defined
+ *
+ * 2017-07-25 (Vadim Zeitlin)
+ * - Fix use of SIPHASH_MAIN macro
+ *
+ * 2017-07-05 (Sebastian Pipping)
+ * - Use _SIP_ULL macro to not require a C++11 compiler if compiled as C++
+ * - Add const qualifiers at two places
+ * - Ensure <=80 characters line length (assuming tab width 4)
+ *
+ * 2017-06-23 (Victor Stinner)
+ * - Address Win64 compile warnings
+ *
+ * 2017-06-18 (Sebastian Pipping)
+ * - Clarify license note in the header
+ * - Address C89 issues:
+ * - Stop using inline keyword (and let compiler decide)
+ * - Replace _Bool by int
+ * - Turn macro siphash24 into a function
+ * - Address invalid conversion (void pointer) by explicit cast
+ * - Address lack of stdint.h for Visual Studio 2003 to 2008
+ * - Always expose sip24_valid (for self-tests)
+ *
+ * 2012-11-04 - Born. (William Ahern)
+ * --------------------------------------------------------------------------
+ * USAGE:
+ *
+ * SipHash-2-4 takes as input two 64-bit words as the key, some number of
+ * message bytes, and outputs a 64-bit word as the message digest. This
+ * implementation employs two data structures: a struct sipkey for
+ * representing the key, and a struct siphash for representing the hash
+ * state.
+ *
+ * For converting a 16-byte unsigned char array to a key, use either the
+ * macro sip_keyof or the routine sip_tokey. The former instantiates a
+ * compound literal key, while the latter requires a key object as a
+ * parameter.
+ *
+ * unsigned char secret[16];
+ * arc4random_buf(secret, sizeof secret);
+ * struct sipkey *key = sip_keyof(secret);
+ *
+ * For hashing a message, use either the convenience macro siphash24 or the
+ * routines sip24_init, sip24_update, and sip24_final.
+ *
+ * struct siphash state;
+ * void *msg;
+ * size_t len;
+ * uint64_t hash;
+ *
+ * sip24_init(&state, key);
+ * sip24_update(&state, msg, len);
+ * hash = sip24_final(&state);
+ *
+ * or
+ *
+ * hash = siphash24(msg, len, key);
+ *
+ * To convert the 64-bit hash value to a canonical 8-byte little-endian
+ * binary representation, use either the macro sip_binof or the routine
+ * sip_tobin. The former instantiates and returns a compound literal array,
+ * while the latter requires an array object as a parameter.
+ * --------------------------------------------------------------------------
+ * NOTES:
+ *
+ * o Neither sip_keyof, sip_binof, nor siphash24 will work with compilers
+ * lacking compound literal support. Instead, you must use the lower-level
+ * interfaces which take as parameters the temporary state objects.
+ *
+ * o Uppercase macros may evaluate parameters more than once. Lowercase
+ * macros should not exhibit any such side effects.
+ * ==========================================================================
+ */
+#ifndef SIPHASH_H
+#define SIPHASH_H
+
+#include <stddef.h> /* size_t */
+
+#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
+/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+# include <stdint.h> /* uint64_t uint32_t uint8_t */
+#endif
+
+/*
+ * Workaround to not require a C++11 compiler for using ULL suffix
+ * if this code is included and compiled as C++; related GCC warning is:
+ * warning: use of C++11 long long integer constant [-Wlong-long]
+ */
+#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low)
+
+#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#define SIP_U32TO8_LE(p, v) \
+ (p)[0] = (uint8_t)((v) >> 0); \
+ (p)[1] = (uint8_t)((v) >> 8); \
+ (p)[2] = (uint8_t)((v) >> 16); \
+ (p)[3] = (uint8_t)((v) >> 24);
+
+#define SIP_U64TO8_LE(p, v) \
+ SIP_U32TO8_LE((p) + 0, (uint32_t)((v) >> 0)); \
+ SIP_U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
+
+#define SIP_U8TO64_LE(p) \
+ (((uint64_t)((p)[0]) << 0) | ((uint64_t)((p)[1]) << 8) \
+ | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) \
+ | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) \
+ | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
+
+#define SIPHASH_INITIALIZER \
+ { 0, 0, 0, 0, {0}, 0, 0 }
+
+struct siphash {
+ uint64_t v0, v1, v2, v3;
+
+ unsigned char buf[8], *p;
+ uint64_t c;
+}; /* struct siphash */
+
+#define SIP_KEYLEN 16
+
+struct sipkey {
+ uint64_t k[2];
+}; /* struct sipkey */
+
+#define sip_keyof(k) sip_tokey(&(struct sipkey){{0}}, (k))
+
+static struct sipkey *
+sip_tokey(struct sipkey *key, const void *src) {
+ key->k[0] = SIP_U8TO64_LE((const unsigned char *)src);
+ key->k[1] = SIP_U8TO64_LE((const unsigned char *)src + 8);
+ return key;
+} /* sip_tokey() */
+
+#ifdef SIPHASH_TOBIN
+
+# define sip_binof(v) sip_tobin((unsigned char[8]){0}, (v))
+
+static void *
+sip_tobin(void *dst, uint64_t u64) {
+ SIP_U64TO8_LE((unsigned char *)dst, u64);
+ return dst;
+} /* sip_tobin() */
+
+#endif /* SIPHASH_TOBIN */
+
+static void
+sip_round(struct siphash *H, const int rounds) {
+ int i;
+
+ for (i = 0; i < rounds; i++) {
+ H->v0 += H->v1;
+ H->v1 = SIP_ROTL(H->v1, 13);
+ H->v1 ^= H->v0;
+ H->v0 = SIP_ROTL(H->v0, 32);
+
+ H->v2 += H->v3;
+ H->v3 = SIP_ROTL(H->v3, 16);
+ H->v3 ^= H->v2;
+
+ H->v0 += H->v3;
+ H->v3 = SIP_ROTL(H->v3, 21);
+ H->v3 ^= H->v0;
+
+ H->v2 += H->v1;
+ H->v1 = SIP_ROTL(H->v1, 17);
+ H->v1 ^= H->v2;
+ H->v2 = SIP_ROTL(H->v2, 32);
+ }
+} /* sip_round() */
+
+static struct siphash *
+sip24_init(struct siphash *H, const struct sipkey *key) {
+ H->v0 = _SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0];
+ H->v1 = _SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1];
+ H->v2 = _SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0];
+ H->v3 = _SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1];
+
+ H->p = H->buf;
+ H->c = 0;
+
+ return H;
+} /* sip24_init() */
+
+#define sip_endof(a) (&(a)[sizeof(a) / sizeof *(a)])
+
+static struct siphash *
+sip24_update(struct siphash *H, const void *src, size_t len) {
+ const unsigned char *p = (const unsigned char *)src, *pe = p + len;
+ uint64_t m;
+
+ do {
+ while (p < pe && H->p < sip_endof(H->buf))
+ *H->p++ = *p++;
+
+ if (H->p < sip_endof(H->buf))
+ break;
+
+ m = SIP_U8TO64_LE(H->buf);
+ H->v3 ^= m;
+ sip_round(H, 2);
+ H->v0 ^= m;
+
+ H->p = H->buf;
+ H->c += 8;
+ } while (p < pe);
+
+ return H;
+} /* sip24_update() */
+
+static uint64_t
+sip24_final(struct siphash *H) {
+ const char left = (char)(H->p - H->buf);
+ uint64_t b = (H->c + left) << 56;
+
+ switch (left) {
+ case 7:
+ b |= (uint64_t)H->buf[6] << 48;
+ /* fall through */
+ case 6:
+ b |= (uint64_t)H->buf[5] << 40;
+ /* fall through */
+ case 5:
+ b |= (uint64_t)H->buf[4] << 32;
+ /* fall through */
+ case 4:
+ b |= (uint64_t)H->buf[3] << 24;
+ /* fall through */
+ case 3:
+ b |= (uint64_t)H->buf[2] << 16;
+ /* fall through */
+ case 2:
+ b |= (uint64_t)H->buf[1] << 8;
+ /* fall through */
+ case 1:
+ b |= (uint64_t)H->buf[0] << 0;
+ /* fall through */
+ case 0:
+ break;
+ }
+
+ H->v3 ^= b;
+ sip_round(H, 2);
+ H->v0 ^= b;
+ H->v2 ^= 0xff;
+ sip_round(H, 4);
+
+ return H->v0 ^ H->v1 ^ H->v2 ^ H->v3;
+} /* sip24_final() */
+
+static uint64_t
+siphash24(const void *src, size_t len, const struct sipkey *key) {
+ struct siphash state = SIPHASH_INITIALIZER;
+ return sip24_final(sip24_update(sip24_init(&state, key), src, len));
+} /* siphash24() */
+
+/*
+ * SipHash-2-4 output with
+ * k = 00 01 02 ...
+ * and
+ * in = (empty string)
+ * in = 00 (1 byte)
+ * in = 00 01 (2 bytes)
+ * in = 00 01 02 (3 bytes)
+ * ...
+ * in = 00 01 02 ... 3e (63 bytes)
+ */
+static int
+sip24_valid(void) {
+ /* clang-format off */
+ static const unsigned char vectors[64][8] = {
+ { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+ { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+ { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+ { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+ { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+ { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+ { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+ { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+ { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+ { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+ { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+ { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+ { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+ { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+ { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+ { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+ { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+ { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+ { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+ { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+ { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+ { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+ { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+ { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+ { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+ { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+ { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+ { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+ { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+ { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+ { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+ { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+ { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+ { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+ { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+ { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+ { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+ { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+ { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+ { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+ { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+ { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+ { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+ { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+ { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+ { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+ { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+ { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+ { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+ { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+ { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+ { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+ { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+ { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+ { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+ { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+ { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+ { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+ { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+ { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+ { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+ { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+ { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+ { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+ };
+ /* clang-format on */
+
+ unsigned char in[64];
+ struct sipkey k;
+ size_t i;
+
+ sip_tokey(&k, "\000\001\002\003\004\005\006\007\010\011"
+ "\012\013\014\015\016\017");
+
+ for (i = 0; i < sizeof in; ++i) {
+ in[i] = (unsigned char)i;
+
+ if (siphash24(in, i, &k) != SIP_U8TO64_LE(vectors[i]))
+ return 0;
+ }
+
+ return 1;
+} /* sip24_valid() */
+
+#ifdef SIPHASH_MAIN
+
+# include <stdio.h>
+
+int
+main(void) {
+ const int ok = sip24_valid();
+
+ if (ok)
+ puts("OK");
+ else
+ puts("FAIL");
+
+ return ! ok;
+} /* main() */
+
+#endif /* SIPHASH_MAIN */
+
+#endif /* SIPHASH_H */
diff --git a/3rdparty/expat/lib/utf8tab.h b/3rdparty/expat/lib/utf8tab.h
index 7bb3e77603f..a22986acbb9 100644
--- a/3rdparty/expat/lib/utf8tab.h
+++ b/3rdparty/expat/lib/utf8tab.h
@@ -1,37 +1,64 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
-*/
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
-/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
+ /* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+ /* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+ /* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+ /* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+ /* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+ /* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+ /* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
+ /* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+ /* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/3rdparty/expat/lib/winconfig.h b/3rdparty/expat/lib/winconfig.h
index c1b791d62d0..562a4a82dc1 100644
--- a/3rdparty/expat/lib/winconfig.h
+++ b/3rdparty/expat/lib/winconfig.h
@@ -1,10 +1,33 @@
-/*================================================================
-** Copyright 2000, Clark Cooper
-** All rights reserved.
-**
-** This is free software. You are permitted to copy, distribute, or modify
-** it under the terms of the MIT/X license (contained in the COPYING file
-** with this distribution.)
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef WINCONFIG_H
@@ -17,14 +40,17 @@
#include <memory.h>
#include <string.h>
-#define XML_NS 1
-#define XML_DTD 1
-#define XML_CONTEXT_BYTES 1024
+#if defined(HAVE_EXPAT_CONFIG_H) /* e.g. MinGW */
+# include <expat_config.h>
+#else /* !defined(HAVE_EXPAT_CONFIG_H) */
+
+# define XML_NS 1
+# define XML_DTD 1
+# define XML_CONTEXT_BYTES 1024
/* we will assume all Windows platforms are little endian */
-#define BYTEORDER 1234
+# define BYTEORDER 1234
-/* Windows has memmove() available. */
-#define HAVE_MEMMOVE
+#endif /* !defined(HAVE_EXPAT_CONFIG_H) */
#endif /* ndef WINCONFIG_H */
diff --git a/3rdparty/expat/lib/xmlparse.c b/3rdparty/expat/lib/xmlparse.c
index e308c795dd9..dfc316ca36c 100644
--- a/3rdparty/expat/lib/xmlparse.c
+++ b/3rdparty/expat/lib/xmlparse.c
@@ -1,88 +1,181 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/* 5cd169f2942b85c05e0b1b96f9990f91ac3d07e470ad7ce906ac8590c8ed4f35 (2.2.10+)
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#if ! defined(_GNU_SOURCE)
+# define _GNU_SOURCE 1 /* syscall prototype */
+#endif
+
+#ifdef _WIN32
+/* force stdlib to define rand_s() */
+# if ! defined(_CRT_RAND_S)
+# define _CRT_RAND_S
+# endif
+#endif
+
#include <stddef.h>
-#include <string.h> /* memset(), memcpy() */
+#include <string.h> /* memset(), memcpy() */
#include <assert.h>
-#include <limits.h> /* UINT_MAX */
-#include <time.h> /* time() */
+#include <limits.h> /* UINT_MAX */
+#include <stdio.h> /* fprintf */
+#include <stdlib.h> /* getenv, rand_s */
+
+#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
+/* vs2008/9.0 and earlier lack stdint.h; _MSC_VER 1600 is vs2010/10.0 */
+# if defined(_WIN64)
+typedef unsigned __int64 uintptr_t;
+# else
+typedef unsigned __int32 uintptr_t;
+# endif
+#else
+# include <stdint.h> /* uintptr_t */
+#endif
+
+#ifdef _WIN32
+# define getpid GetCurrentProcessId
+#else
+# include <sys/time.h> /* gettimeofday() */
+# include <sys/types.h> /* getpid() */
+# include <unistd.h> /* getpid() */
+# include <fcntl.h> /* O_RDONLY */
+# include <errno.h>
+#endif
#define XML_BUILDING_EXPAT 1
-#ifdef COMPILED_FROM_DSP
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
+#ifdef _WIN32
+# include "winconfig.h"
#elif defined(HAVE_EXPAT_CONFIG_H)
-#include <expat_config.h>
-#endif /* ndef COMPILED_FROM_DSP */
+# include <expat_config.h>
+#endif /* ndef _WIN32 */
#include "ascii.h"
#include "expat.h"
+#include "siphash.h"
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+# if defined(HAVE_GETRANDOM)
+# include <sys/random.h> /* getrandom */
+# else
+# include <unistd.h> /* syscall */
+# include <sys/syscall.h> /* SYS_getrandom */
+# endif
+# if ! defined(GRND_NONBLOCK)
+# define GRND_NONBLOCK 0x0001
+# endif /* defined(GRND_NONBLOCK) */
+#endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
+
+#if defined(HAVE_LIBBSD) \
+ && (defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_ARC4RANDOM))
+# include <bsd/stdlib.h>
+#endif
+
+#if defined(_WIN32) && ! defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
+#endif
+
+#if ! defined(HAVE_GETRANDOM) && ! defined(HAVE_SYSCALL_GETRANDOM) \
+ && ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) \
+ && ! defined(XML_DEV_URANDOM) && ! defined(_WIN32) \
+ && ! defined(XML_POOR_ENTROPY)
+# error You do not have support for any sources of high quality entropy \
+ enabled. For end user security, that is probably not what you want. \
+ \
+ Your options include: \
+ * Linux >=3.17 + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \
+ * Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
+ * BSD / macOS >=10.7 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
+ * BSD / macOS (including <10.7) (arc4random): HAVE_ARC4RANDOM, \
+ * libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \
+ * libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \
+ * Linux (including <3.17) / BSD / macOS (including <10.7) (/dev/urandom): XML_DEV_URANDOM, \
+ * Windows >=Vista (rand_s): _WIN32. \
+ \
+ If insist on not using any of these, bypass this error by defining \
+ XML_POOR_ENTROPY; you have been warned. \
+ \
+ If you have reasons to patch this detection code away or need changes \
+ to the build system, please open a bug. Thank you!
+#endif
#ifdef XML_UNICODE
-#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
-#define XmlConvert XmlUtf16Convert
-#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
-#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
-#define XmlEncode XmlUtf16Encode
-/* Using pointer subtraction to convert to integer type. */
-#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
+# define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+# define XmlConvert XmlUtf16Convert
+# define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+# define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+# define XmlEncode XmlUtf16Encode
+# define MUST_CONVERT(enc, s) (! (enc)->isUtf16 || (((uintptr_t)(s)) & 1))
typedef unsigned short ICHAR;
#else
-#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
-#define XmlConvert XmlUtf8Convert
-#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
-#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
-#define XmlEncode XmlUtf8Encode
-#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+# define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+# define XmlConvert XmlUtf8Convert
+# define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+# define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+# define XmlEncode XmlUtf8Encode
+# define MUST_CONVERT(enc, s) (! (enc)->isUtf8)
typedef char ICHAR;
#endif
-
#ifndef XML_NS
-#define XmlInitEncodingNS XmlInitEncoding
-#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
-#undef XmlGetInternalEncodingNS
-#define XmlGetInternalEncodingNS XmlGetInternalEncoding
-#define XmlParseXmlDeclNS XmlParseXmlDecl
+# define XmlInitEncodingNS XmlInitEncoding
+# define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+# undef XmlGetInternalEncodingNS
+# define XmlGetInternalEncodingNS XmlGetInternalEncoding
+# define XmlParseXmlDeclNS XmlParseXmlDecl
#endif
#ifdef XML_UNICODE
-#ifdef XML_UNICODE_WCHAR_T
-#define XML_T(x) (const wchar_t)x
-#define XML_L(x) L ## x
-#else
-#define XML_T(x) (const unsigned short)x
-#define XML_L(x) x
-#endif
+# ifdef XML_UNICODE_WCHAR_T
+# define XML_T(x) (const wchar_t) x
+# define XML_L(x) L##x
+# else
+# define XML_T(x) (const unsigned short)x
+# define XML_L(x) x
+# endif
#else
-#define XML_T(x) x
-#define XML_L(x) x
+# define XML_T(x) x
+# define XML_L(x) x
#endif
/* Round up n to be a multiple of sz, where sz is a power of 2. */
-#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+#define ROUND_UP(n, sz) (((n) + ((sz)-1)) & ~((sz)-1))
-/* Handle the case where memmove() doesn't exist. */
-#ifndef HAVE_MEMMOVE
-#ifdef HAVE_BCOPY
-#define memmove(d,s,l) bcopy((s),(d),(l))
-#else
-#error memmove does not exist on this platform, nor is a substitute available
-#endif /* HAVE_BCOPY */
-#endif /* HAVE_MEMMOVE */
+/* Do safe (NULL-aware) pointer arithmetic */
+#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
#include "internal.h"
#include "xmltok.h"
@@ -102,17 +195,9 @@ typedef struct {
const XML_Memory_Handling_Suite *mem;
} HASH_TABLE;
-/* Basic character hash algorithm, taken from Python's string hash:
- h = h * 1000003 ^ character, the constant being a prime number.
+static size_t keylen(KEY s);
-*/
-#ifdef XML_UNICODE
-#define CHAR_HASH(h, c) \
- (((h) * 0xF4243) ^ (unsigned short)(c))
-#else
-#define CHAR_HASH(h, c) \
- (((h) * 0xF4243) ^ (unsigned char)(c))
-#endif
+static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key);
/* For probing (after a collision) we need a step size relative prime
to the hash table size, which is a power of 2. We use double-hashing,
@@ -122,9 +207,9 @@ typedef struct {
We limit the maximum step size to table->size / 4 (mask >> 2) and make
it odd, since odd numbers are always relative prime to a power of 2.
*/
-#define SECOND_HASH(hash, mask, power) \
- ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
-#define PROBE_STEP(hash, mask, power) \
+#define SECOND_HASH(hash, mask, power) \
+ ((((hash) & ~(mask)) >> ((power)-1)) & ((mask) >> 2))
+#define PROBE_STEP(hash, mask, power) \
((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
typedef struct {
@@ -132,7 +217,7 @@ typedef struct {
NAMED **end;
} HASH_TABLE_ITER;
-#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
+#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
#define INIT_DATA_BUF_SIZE 1024
#define INIT_ATTS_SIZE 16
#define INIT_ATTS_VERSION 0xFFFFFFFF
@@ -179,20 +264,20 @@ typedef struct {
TAG objects in a free list.
*/
typedef struct tag {
- struct tag *parent; /* parent of this element */
- const char *rawName; /* tagName in the original encoding */
+ struct tag *parent; /* parent of this element */
+ const char *rawName; /* tagName in the original encoding */
int rawNameLength;
- TAG_NAME name; /* tagName in the API encoding */
- char *buf; /* buffer for name components */
- char *bufEnd; /* end of the buffer */
+ TAG_NAME name; /* tagName in the API encoding */
+ char *buf; /* buffer for name components */
+ char *bufEnd; /* end of the buffer */
BINDING *bindings;
} TAG;
typedef struct {
const XML_Char *name;
const XML_Char *textPtr;
- int textLen; /* length in XML_Chars */
- int processed; /* # of processed bytes - when suspended */
+ int textLen; /* length in XML_Chars */
+ int processed; /* # of processed bytes - when suspended */
const XML_Char *systemId;
const XML_Char *base;
const XML_Char *publicId;
@@ -203,13 +288,13 @@ typedef struct {
} ENTITY;
typedef struct {
- enum XML_Content_Type type;
- enum XML_Content_Quant quant;
- const XML_Char * name;
- int firstchild;
- int lastchild;
- int childcnt;
- int nextsib;
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ const XML_Char *name;
+ int firstchild;
+ int lastchild;
+ int childcnt;
+ int nextsib;
} CONTENT_SCAFFOLD;
#define INIT_SCAFFOLD_ELEMENTS 32
@@ -297,10 +382,8 @@ typedef struct open_internal_entity {
XML_Bool betweenDecl; /* WFC: PE Between Declarations */
} OPEN_INTERNAL_ENTITY;
-typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr);
+typedef enum XML_Error PTRCALL Processor(XML_Parser parser, const char *start,
+ const char *end, const char **endPtr);
static Processor prologProcessor;
static Processor prologInitProcessor;
@@ -321,128 +404,113 @@ static Processor externalEntityInitProcessor3;
static Processor externalEntityContentProcessor;
static Processor internalEntityProcessor;
-static enum XML_Error
-handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
-static enum XML_Error
-processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
- const char *s, const char *next);
-static enum XML_Error
-initializeEncoding(XML_Parser parser);
-static enum XML_Error
-doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
- const char *end, int tok, const char *next, const char **nextPtr,
- XML_Bool haveMore);
-static enum XML_Error
-processInternalEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl);
-static enum XML_Error
-doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
- const char *start, const char *end, const char **endPtr,
- XML_Bool haveMore);
-static enum XML_Error
-doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
- const char *end, const char **nextPtr, XML_Bool haveMore);
+static enum XML_Error handleUnknownEncoding(XML_Parser parser,
+ const XML_Char *encodingName);
+static enum XML_Error processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next);
+static enum XML_Error initializeEncoding(XML_Parser parser);
+static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
+ const char *s, const char *end, int tok,
+ const char *next, const char **nextPtr,
+ XML_Bool haveMore, XML_Bool allowClosingDoctype);
+static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl);
+static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
+ const ENCODING *enc, const char *start,
+ const char *end, const char **endPtr,
+ XML_Bool haveMore);
+static enum XML_Error doCdataSection(XML_Parser parser, const ENCODING *,
+ const char **startPtr, const char *end,
+ const char **nextPtr, XML_Bool haveMore);
#ifdef XML_DTD
-static enum XML_Error
-doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
- const char *end, const char **nextPtr, XML_Bool haveMore);
+static enum XML_Error doIgnoreSection(XML_Parser parser, const ENCODING *,
+ const char **startPtr, const char *end,
+ const char **nextPtr, XML_Bool haveMore);
#endif /* XML_DTD */
-static enum XML_Error
-storeAtts(XML_Parser parser, const ENCODING *, const char *s,
- TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
-static enum XML_Error
-addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
- const XML_Char *uri, BINDING **bindingsPtr);
-static int
-defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
- XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
-static enum XML_Error
-storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
- const char *, const char *, STRING_POOL *);
-static enum XML_Error
-appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
- const char *, const char *, STRING_POOL *);
-static ATTRIBUTE_ID *
-getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
- const char *end);
-static int
-setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
-static enum XML_Error
-storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
- const char *end);
-static int
-reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
- const char *start, const char *end);
-static int
-reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
- const char *end);
-static void
-reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
- const char *end);
-
-static const XML_Char * getContext(XML_Parser parser);
-static XML_Bool
-setContext(XML_Parser parser, const XML_Char *context);
+static void freeBindings(XML_Parser parser, BINDING *bindings);
+static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *,
+ const char *s, TAG_NAME *tagNamePtr,
+ BINDING **bindingsPtr);
+static enum XML_Error addBinding(XML_Parser parser, PREFIX *prefix,
+ const ATTRIBUTE_ID *attId, const XML_Char *uri,
+ BINDING **bindingsPtr);
+static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *dfltValue,
+ XML_Parser parser);
+static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *,
+ XML_Bool isCdata, const char *,
+ const char *, STRING_POOL *);
+static enum XML_Error appendAttributeValue(XML_Parser parser, const ENCODING *,
+ XML_Bool isCdata, const char *,
+ const char *, STRING_POOL *);
+static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static int reportComment(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static void reportDefault(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+
+static const XML_Char *getContext(XML_Parser parser);
+static XML_Bool setContext(XML_Parser parser, const XML_Char *context);
static void FASTCALL normalizePublicId(XML_Char *s);
-static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
-/* do not call if parentParser != NULL */
+static DTD *dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* do not call if m_parentParser != NULL */
static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
-static void
-dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
-static int
-dtdCopy(XML_Parser oldParser,
- DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
-static int
-copyEntityTable(XML_Parser oldParser,
- HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
-static NAMED *
-lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
-static void FASTCALL
-hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
+static void dtdDestroy(DTD *p, XML_Bool isDocEntity,
+ const XML_Memory_Handling_Suite *ms);
+static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
+ const XML_Memory_Handling_Suite *ms);
+static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *, STRING_POOL *,
+ const HASH_TABLE *);
+static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name,
+ size_t createSize);
+static void FASTCALL hashTableInit(HASH_TABLE *,
+ const XML_Memory_Handling_Suite *ms);
static void FASTCALL hashTableClear(HASH_TABLE *);
static void FASTCALL hashTableDestroy(HASH_TABLE *);
-static void FASTCALL
-hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
-static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+static void FASTCALL hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+static NAMED *FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
-static void FASTCALL
-poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL poolInit(STRING_POOL *,
+ const XML_Memory_Handling_Suite *ms);
static void FASTCALL poolClear(STRING_POOL *);
static void FASTCALL poolDestroy(STRING_POOL *);
-static XML_Char *
-poolAppend(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end);
-static XML_Char *
-poolStoreString(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end);
+static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
-static const XML_Char * FASTCALL
-poolCopyString(STRING_POOL *pool, const XML_Char *s);
-static const XML_Char *
-poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
-static const XML_Char * FASTCALL
-poolAppendString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool,
+ const XML_Char *s);
+static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s,
+ int n);
+static const XML_Char *FASTCALL poolAppendString(STRING_POOL *pool,
+ const XML_Char *s);
static int FASTCALL nextScaffoldPart(XML_Parser parser);
-static XML_Content * build_model(XML_Parser parser);
-static ELEMENT_TYPE *
-getElementType(XML_Parser parser, const ENCODING *enc,
- const char *ptr, const char *end);
+static XML_Content *build_model(XML_Parser parser);
+static ELEMENT_TYPE *getElementType(XML_Parser parser, const ENCODING *enc,
+ const char *ptr, const char *end);
-static unsigned long generate_hash_secret_salt(void);
+static XML_Char *copyString(const XML_Char *s,
+ const XML_Memory_Handling_Suite *memsuite);
+
+static unsigned long generate_hash_secret_salt(XML_Parser parser);
static XML_Bool startParsing(XML_Parser parser);
-static XML_Parser
-parserCreate(const XML_Char *encodingName,
- const XML_Memory_Handling_Suite *memsuite,
- const XML_Char *nameSep,
- DTD *dtd);
+static XML_Parser parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep, DTD *dtd);
-static void
-parserInit(XML_Parser parser, const XML_Char *encodingName);
+static void parserInit(XML_Parser parser, const XML_Char *encodingName);
#define poolStart(pool) ((pool)->start)
#define poolEnd(pool) ((pool)->ptr)
@@ -451,13 +519,13 @@ parserInit(XML_Parser parser, const XML_Char *encodingName);
#define poolLastChar(pool) (((pool)->ptr)[-1])
#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
#define poolFinish(pool) ((pool)->start = (pool)->ptr)
-#define poolAppendChar(pool, c) \
- (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
- ? 0 \
- : ((*((pool)->ptr)++ = c), 1))
+#define poolAppendChar(pool, c) \
+ (((pool)->ptr == (pool)->end && ! poolGrow(pool)) \
+ ? 0 \
+ : ((*((pool)->ptr)++ = c), 1))
struct XML_ParserStruct {
- /* The first member must be userData so that the XML_GetUserData
+ /* The first member must be m_userData so that the XML_GetUserData
macro works. */
void *m_userData;
void *m_handlerArg;
@@ -467,7 +535,7 @@ struct XML_ParserStruct {
const char *m_bufferPtr;
/* past last character to be parsed */
char *m_bufferEnd;
- /* allocated end of buffer */
+ /* allocated end of m_buffer */
const char *m_bufferLim;
XML_Index m_parseEndByteIndex;
const char *m_parseEndPtr;
@@ -505,7 +573,7 @@ struct XML_ParserStruct {
void *m_unknownEncodingMem;
void *m_unknownEncodingData;
void *m_unknownEncodingHandlerData;
- void (XMLCALL *m_unknownEncodingRelease)(void *);
+ void(XMLCALL *m_unknownEncodingRelease)(void *);
PROLOG_STATE m_prologState;
Processor *m_processor;
enum XML_Error m_errorCode;
@@ -559,188 +627,283 @@ struct XML_ParserStruct {
unsigned long m_hash_secret_salt;
};
-#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
-#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
-#define FREE(p) (parser->m_mem.free_fcn((p)))
-
-#define userData (parser->m_userData)
-#define handlerArg (parser->m_handlerArg)
-#define startElementHandler (parser->m_startElementHandler)
-#define endElementHandler (parser->m_endElementHandler)
-#define characterDataHandler (parser->m_characterDataHandler)
-#define processingInstructionHandler \
- (parser->m_processingInstructionHandler)
-#define commentHandler (parser->m_commentHandler)
-#define startCdataSectionHandler \
- (parser->m_startCdataSectionHandler)
-#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
-#define defaultHandler (parser->m_defaultHandler)
-#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
-#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
-#define unparsedEntityDeclHandler \
- (parser->m_unparsedEntityDeclHandler)
-#define notationDeclHandler (parser->m_notationDeclHandler)
-#define startNamespaceDeclHandler \
- (parser->m_startNamespaceDeclHandler)
-#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
-#define notStandaloneHandler (parser->m_notStandaloneHandler)
-#define externalEntityRefHandler \
- (parser->m_externalEntityRefHandler)
-#define externalEntityRefHandlerArg \
- (parser->m_externalEntityRefHandlerArg)
-#define internalEntityRefHandler \
- (parser->m_internalEntityRefHandler)
-#define skippedEntityHandler (parser->m_skippedEntityHandler)
-#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
-#define elementDeclHandler (parser->m_elementDeclHandler)
-#define attlistDeclHandler (parser->m_attlistDeclHandler)
-#define entityDeclHandler (parser->m_entityDeclHandler)
-#define xmlDeclHandler (parser->m_xmlDeclHandler)
-#define encoding (parser->m_encoding)
-#define initEncoding (parser->m_initEncoding)
-#define internalEncoding (parser->m_internalEncoding)
-#define unknownEncodingMem (parser->m_unknownEncodingMem)
-#define unknownEncodingData (parser->m_unknownEncodingData)
-#define unknownEncodingHandlerData \
- (parser->m_unknownEncodingHandlerData)
-#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
-#define protocolEncodingName (parser->m_protocolEncodingName)
-#define ns (parser->m_ns)
-#define ns_triplets (parser->m_ns_triplets)
-#define prologState (parser->m_prologState)
-#define processor (parser->m_processor)
-#define errorCode (parser->m_errorCode)
-#define eventPtr (parser->m_eventPtr)
-#define eventEndPtr (parser->m_eventEndPtr)
-#define positionPtr (parser->m_positionPtr)
-#define position (parser->m_position)
-#define openInternalEntities (parser->m_openInternalEntities)
-#define freeInternalEntities (parser->m_freeInternalEntities)
-#define defaultExpandInternalEntities \
- (parser->m_defaultExpandInternalEntities)
-#define tagLevel (parser->m_tagLevel)
-#define buffer (parser->m_buffer)
-#define bufferPtr (parser->m_bufferPtr)
-#define bufferEnd (parser->m_bufferEnd)
-#define parseEndByteIndex (parser->m_parseEndByteIndex)
-#define parseEndPtr (parser->m_parseEndPtr)
-#define bufferLim (parser->m_bufferLim)
-#define dataBuf (parser->m_dataBuf)
-#define dataBufEnd (parser->m_dataBufEnd)
-#define _dtd (parser->m_dtd)
-#define curBase (parser->m_curBase)
-#define declEntity (parser->m_declEntity)
-#define doctypeName (parser->m_doctypeName)
-#define doctypeSysid (parser->m_doctypeSysid)
-#define doctypePubid (parser->m_doctypePubid)
-#define declAttributeType (parser->m_declAttributeType)
-#define declNotationName (parser->m_declNotationName)
-#define declNotationPublicId (parser->m_declNotationPublicId)
-#define declElementType (parser->m_declElementType)
-#define declAttributeId (parser->m_declAttributeId)
-#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
-#define declAttributeIsId (parser->m_declAttributeIsId)
-#define freeTagList (parser->m_freeTagList)
-#define freeBindingList (parser->m_freeBindingList)
-#define inheritedBindings (parser->m_inheritedBindings)
-#define tagStack (parser->m_tagStack)
-#define atts (parser->m_atts)
-#define attsSize (parser->m_attsSize)
-#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
-#define idAttIndex (parser->m_idAttIndex)
-#define nsAtts (parser->m_nsAtts)
-#define nsAttsVersion (parser->m_nsAttsVersion)
-#define nsAttsPower (parser->m_nsAttsPower)
-#define attInfo (parser->m_attInfo)
-#define tempPool (parser->m_tempPool)
-#define temp2Pool (parser->m_temp2Pool)
-#define groupConnector (parser->m_groupConnector)
-#define groupSize (parser->m_groupSize)
-#define namespaceSeparator (parser->m_namespaceSeparator)
-#define parentParser (parser->m_parentParser)
-#define ps_parsing (parser->m_parsingStatus.parsing)
-#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
-#ifdef XML_DTD
-#define isParamEntity (parser->m_isParamEntity)
-#define useForeignDTD (parser->m_useForeignDTD)
-#define paramEntityParsing (parser->m_paramEntityParsing)
-#endif /* XML_DTD */
-#define hash_secret_salt (parser->m_hash_secret_salt)
+#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(parser, p, s) (parser->m_mem.realloc_fcn((p), (s)))
+#define FREE(parser, p) (parser->m_mem.free_fcn((p)))
XML_Parser XMLCALL
-XML_ParserCreate(const XML_Char *encodingName)
-{
+XML_ParserCreate(const XML_Char *encodingName) {
return XML_ParserCreate_MM(encodingName, NULL, NULL);
}
XML_Parser XMLCALL
-XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
-{
+XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
XML_Char tmp[2];
*tmp = nsSep;
return XML_ParserCreate_MM(encodingName, NULL, tmp);
}
-static const XML_Char implicitContext[] = {
- ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
- ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
- ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
- ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
- ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
- ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
-};
+static const XML_Char implicitContext[]
+ = {ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h,
+ ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
+ ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD,
+ ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r,
+ ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
+ ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8,
+ ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
+ ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e,
+ '\0'};
-static unsigned long
-generate_hash_secret_salt(void)
-{
- unsigned int seed = time(NULL) % UINT_MAX;
- srand(seed);
- return rand();
-}
-
-static XML_Bool /* only valid for root parser */
-startParsing(XML_Parser parser)
-{
- /* hash functions must be initialized before setContext() is called */
- if (hash_secret_salt == 0)
- hash_secret_salt = generate_hash_secret_salt();
- if (ns) {
- /* implicit context only set for root parser, since child
- parsers (i.e. external entity parsers) will inherit it
- */
- return setContext(parser, implicitContext);
+/* To avoid warnings about unused functions: */
+#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
+
+# if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+
+/* Obtain entropy on Linux 3.17+ */
+static int
+writeRandomBytes_getrandom_nonblock(void *target, size_t count) {
+ int success = 0; /* full count bytes written? */
+ size_t bytesWrittenTotal = 0;
+ const unsigned int getrandomFlags = GRND_NONBLOCK;
+
+ do {
+ void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
+ const size_t bytesToWrite = count - bytesWrittenTotal;
+
+ const int bytesWrittenMore =
+# if defined(HAVE_GETRANDOM)
+ getrandom(currentTarget, bytesToWrite, getrandomFlags);
+# else
+ syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags);
+# endif
+
+ if (bytesWrittenMore > 0) {
+ bytesWrittenTotal += bytesWrittenMore;
+ if (bytesWrittenTotal >= count)
+ success = 1;
+ }
+ } while (! success && (errno == EINTR));
+
+ return success;
+}
+
+# endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
+
+# if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
+
+/* Extract entropy from /dev/urandom */
+static int
+writeRandomBytes_dev_urandom(void *target, size_t count) {
+ int success = 0; /* full count bytes written? */
+ size_t bytesWrittenTotal = 0;
+
+ const int fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+
+ do {
+ void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
+ const size_t bytesToWrite = count - bytesWrittenTotal;
+
+ const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite);
+
+ if (bytesWrittenMore > 0) {
+ bytesWrittenTotal += bytesWrittenMore;
+ if (bytesWrittenTotal >= count)
+ success = 1;
+ }
+ } while (! success && (errno == EINTR));
+
+ close(fd);
+ return success;
+}
+
+# endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
+
+#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
+
+#if defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF)
+
+static void
+writeRandomBytes_arc4random(void *target, size_t count) {
+ size_t bytesWrittenTotal = 0;
+
+ while (bytesWrittenTotal < count) {
+ const uint32_t random32 = arc4random();
+ size_t i = 0;
+
+ for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
+ i++, bytesWrittenTotal++) {
+ const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
+ ((uint8_t *)target)[bytesWrittenTotal] = random8;
+ }
+ }
+}
+
+#endif /* defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) */
+
+#ifdef _WIN32
+
+/* Provide declaration of rand_s() for MinGW-32 (not 64, which has it),
+ as it didn't declare it in its header prior to version 5.3.0 of its
+ runtime package (mingwrt, containing stdlib.h). The upstream fix
+ was introduced at https://osdn.net/projects/mingw/ticket/39658 . */
+# if defined(__MINGW32__) && defined(__MINGW32_VERSION) \
+ && __MINGW32_VERSION < 5003000L && ! defined(__MINGW64_VERSION_MAJOR)
+__declspec(dllimport) int rand_s(unsigned int *);
+# endif
+
+/* Obtain entropy on Windows using the rand_s() function which
+ * generates cryptographically secure random numbers. Internally it
+ * uses RtlGenRandom API which is present in Windows XP and later.
+ */
+static int
+writeRandomBytes_rand_s(void *target, size_t count) {
+ size_t bytesWrittenTotal = 0;
+
+ while (bytesWrittenTotal < count) {
+ unsigned int random32 = 0;
+ size_t i = 0;
+
+ if (rand_s(&random32))
+ return 0; /* failure */
+
+ for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
+ i++, bytesWrittenTotal++) {
+ const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
+ ((uint8_t *)target)[bytesWrittenTotal] = random8;
}
- return XML_TRUE;
+ }
+ return 1; /* success */
+}
+
+#endif /* _WIN32 */
+
+#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
+
+static unsigned long
+gather_time_entropy(void) {
+# ifdef _WIN32
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft); /* never fails */
+ return ft.dwHighDateTime ^ ft.dwLowDateTime;
+# else
+ struct timeval tv;
+ int gettimeofday_res;
+
+ gettimeofday_res = gettimeofday(&tv, NULL);
+
+# if defined(NDEBUG)
+ (void)gettimeofday_res;
+# else
+ assert(gettimeofday_res == 0);
+# endif /* defined(NDEBUG) */
+
+ /* Microseconds time is <20 bits entropy */
+ return tv.tv_usec;
+# endif
+}
+
+#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
+
+static unsigned long
+ENTROPY_DEBUG(const char *label, unsigned long entropy) {
+ const char *const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
+ if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
+ fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n", label,
+ (int)sizeof(entropy) * 2, entropy, (unsigned long)sizeof(entropy));
+ }
+ return entropy;
+}
+
+static unsigned long
+generate_hash_secret_salt(XML_Parser parser) {
+ unsigned long entropy;
+ (void)parser;
+
+ /* "Failproof" high quality providers: */
+#if defined(HAVE_ARC4RANDOM_BUF)
+ arc4random_buf(&entropy, sizeof(entropy));
+ return ENTROPY_DEBUG("arc4random_buf", entropy);
+#elif defined(HAVE_ARC4RANDOM)
+ writeRandomBytes_arc4random((void *)&entropy, sizeof(entropy));
+ return ENTROPY_DEBUG("arc4random", entropy);
+#else
+ /* Try high quality providers first .. */
+# ifdef _WIN32
+ if (writeRandomBytes_rand_s((void *)&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("rand_s", entropy);
+ }
+# elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+ if (writeRandomBytes_getrandom_nonblock((void *)&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("getrandom", entropy);
+ }
+# endif
+# if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
+ if (writeRandomBytes_dev_urandom((void *)&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("/dev/urandom", entropy);
+ }
+# endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
+ /* .. and self-made low quality for backup: */
+
+ /* Process ID is 0 bits entropy if attacker has local access */
+ entropy = gather_time_entropy() ^ getpid();
+
+ /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
+ if (sizeof(unsigned long) == 4) {
+ return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
+ } else {
+ return ENTROPY_DEBUG("fallback(8)",
+ entropy * (unsigned long)2305843009213693951ULL);
+ }
+#endif
+}
+
+static unsigned long
+get_hash_secret_salt(XML_Parser parser) {
+ if (parser->m_parentParser != NULL)
+ return get_hash_secret_salt(parser->m_parentParser);
+ return parser->m_hash_secret_salt;
+}
+
+static XML_Bool /* only valid for root parser */
+startParsing(XML_Parser parser) {
+ /* hash functions must be initialized before setContext() is called */
+ if (parser->m_hash_secret_salt == 0)
+ parser->m_hash_secret_salt = generate_hash_secret_salt(parser);
+ if (parser->m_ns) {
+ /* implicit context only set for root parser, since child
+ parsers (i.e. external entity parsers) will inherit it
+ */
+ return setContext(parser, implicitContext);
+ }
+ return XML_TRUE;
}
XML_Parser XMLCALL
XML_ParserCreate_MM(const XML_Char *encodingName,
const XML_Memory_Handling_Suite *memsuite,
- const XML_Char *nameSep)
-{
+ const XML_Char *nameSep) {
return parserCreate(encodingName, memsuite, nameSep, NULL);
}
static XML_Parser
parserCreate(const XML_Char *encodingName,
- const XML_Memory_Handling_Suite *memsuite,
- const XML_Char *nameSep,
- DTD *dtd)
-{
+ const XML_Memory_Handling_Suite *memsuite, const XML_Char *nameSep,
+ DTD *dtd) {
XML_Parser parser;
if (memsuite) {
XML_Memory_Handling_Suite *mtemp;
- parser = (XML_Parser)
- memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+ parser = (XML_Parser)memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
if (parser != NULL) {
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
mtemp->malloc_fcn = memsuite->malloc_fcn;
mtemp->realloc_fcn = memsuite->realloc_fcn;
mtemp->free_fcn = memsuite->free_fcn;
}
- }
- else {
+ } else {
XML_Memory_Handling_Suite *mtemp;
parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
if (parser != NULL) {
@@ -751,287 +914,336 @@ parserCreate(const XML_Char *encodingName,
}
}
- if (!parser)
+ if (! parser)
return parser;
- buffer = NULL;
- bufferLim = NULL;
+ parser->m_buffer = NULL;
+ parser->m_bufferLim = NULL;
- attsSize = INIT_ATTS_SIZE;
- atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
- if (atts == NULL) {
- FREE(parser);
+ parser->m_attsSize = INIT_ATTS_SIZE;
+ parser->m_atts
+ = (ATTRIBUTE *)MALLOC(parser, parser->m_attsSize * sizeof(ATTRIBUTE));
+ if (parser->m_atts == NULL) {
+ FREE(parser, parser);
return NULL;
}
#ifdef XML_ATTR_INFO
- attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
- if (attInfo == NULL) {
- FREE(atts);
- FREE(parser);
+ parser->m_attInfo = (XML_AttrInfo *)MALLOC(
+ parser, parser->m_attsSize * sizeof(XML_AttrInfo));
+ if (parser->m_attInfo == NULL) {
+ FREE(parser, parser->m_atts);
+ FREE(parser, parser);
return NULL;
}
#endif
- dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
- if (dataBuf == NULL) {
- FREE(atts);
+ parser->m_dataBuf
+ = (XML_Char *)MALLOC(parser, INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ if (parser->m_dataBuf == NULL) {
+ FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE(attInfo);
+ FREE(parser, parser->m_attInfo);
#endif
- FREE(parser);
+ FREE(parser, parser);
return NULL;
}
- dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+ parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE;
if (dtd)
- _dtd = dtd;
+ parser->m_dtd = dtd;
else {
- _dtd = dtdCreate(&parser->m_mem);
- if (_dtd == NULL) {
- FREE(dataBuf);
- FREE(atts);
+ parser->m_dtd = dtdCreate(&parser->m_mem);
+ if (parser->m_dtd == NULL) {
+ FREE(parser, parser->m_dataBuf);
+ FREE(parser, parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE(attInfo);
+ FREE(parser, parser->m_attInfo);
#endif
- FREE(parser);
+ FREE(parser, parser);
return NULL;
}
}
- freeBindingList = NULL;
- freeTagList = NULL;
- freeInternalEntities = NULL;
+ parser->m_freeBindingList = NULL;
+ parser->m_freeTagList = NULL;
+ parser->m_freeInternalEntities = NULL;
- groupSize = 0;
- groupConnector = NULL;
+ parser->m_groupSize = 0;
+ parser->m_groupConnector = NULL;
- unknownEncodingHandler = NULL;
- unknownEncodingHandlerData = NULL;
+ parser->m_unknownEncodingHandler = NULL;
+ parser->m_unknownEncodingHandlerData = NULL;
- namespaceSeparator = ASCII_EXCL;
- ns = XML_FALSE;
- ns_triplets = XML_FALSE;
+ parser->m_namespaceSeparator = ASCII_EXCL;
+ parser->m_ns = XML_FALSE;
+ parser->m_ns_triplets = XML_FALSE;
- nsAtts = NULL;
- nsAttsVersion = 0;
- nsAttsPower = 0;
+ parser->m_nsAtts = NULL;
+ parser->m_nsAttsVersion = 0;
+ parser->m_nsAttsPower = 0;
- poolInit(&tempPool, &(parser->m_mem));
- poolInit(&temp2Pool, &(parser->m_mem));
+ parser->m_protocolEncodingName = NULL;
+
+ poolInit(&parser->m_tempPool, &(parser->m_mem));
+ poolInit(&parser->m_temp2Pool, &(parser->m_mem));
parserInit(parser, encodingName);
- if (encodingName && !protocolEncodingName) {
+ if (encodingName && ! parser->m_protocolEncodingName) {
XML_ParserFree(parser);
return NULL;
}
if (nameSep) {
- ns = XML_TRUE;
- internalEncoding = XmlGetInternalEncodingNS();
- namespaceSeparator = *nameSep;
- }
- else {
- internalEncoding = XmlGetInternalEncoding();
+ parser->m_ns = XML_TRUE;
+ parser->m_internalEncoding = XmlGetInternalEncodingNS();
+ parser->m_namespaceSeparator = *nameSep;
+ } else {
+ parser->m_internalEncoding = XmlGetInternalEncoding();
}
return parser;
}
static void
-parserInit(XML_Parser parser, const XML_Char *encodingName)
-{
- processor = prologInitProcessor;
- XmlPrologStateInit(&prologState);
- protocolEncodingName = (encodingName != NULL
- ? poolCopyString(&tempPool, encodingName)
- : NULL);
- curBase = NULL;
- XmlInitEncoding(&initEncoding, &encoding, 0);
- userData = NULL;
- handlerArg = NULL;
- startElementHandler = NULL;
- endElementHandler = NULL;
- characterDataHandler = NULL;
- processingInstructionHandler = NULL;
- commentHandler = NULL;
- startCdataSectionHandler = NULL;
- endCdataSectionHandler = NULL;
- defaultHandler = NULL;
- startDoctypeDeclHandler = NULL;
- endDoctypeDeclHandler = NULL;
- unparsedEntityDeclHandler = NULL;
- notationDeclHandler = NULL;
- startNamespaceDeclHandler = NULL;
- endNamespaceDeclHandler = NULL;
- notStandaloneHandler = NULL;
- externalEntityRefHandler = NULL;
- externalEntityRefHandlerArg = parser;
- skippedEntityHandler = NULL;
- elementDeclHandler = NULL;
- attlistDeclHandler = NULL;
- entityDeclHandler = NULL;
- xmlDeclHandler = NULL;
- bufferPtr = buffer;
- bufferEnd = buffer;
- parseEndByteIndex = 0;
- parseEndPtr = NULL;
- declElementType = NULL;
- declAttributeId = NULL;
- declEntity = NULL;
- doctypeName = NULL;
- doctypeSysid = NULL;
- doctypePubid = NULL;
- declAttributeType = NULL;
- declNotationName = NULL;
- declNotationPublicId = NULL;
- declAttributeIsCdata = XML_FALSE;
- declAttributeIsId = XML_FALSE;
- memset(&position, 0, sizeof(POSITION));
- errorCode = XML_ERROR_NONE;
- eventPtr = NULL;
- eventEndPtr = NULL;
- positionPtr = NULL;
- openInternalEntities = NULL;
- defaultExpandInternalEntities = XML_TRUE;
- tagLevel = 0;
- tagStack = NULL;
- inheritedBindings = NULL;
- nSpecifiedAtts = 0;
- unknownEncodingMem = NULL;
- unknownEncodingRelease = NULL;
- unknownEncodingData = NULL;
- parentParser = NULL;
- ps_parsing = XML_INITIALIZED;
+parserInit(XML_Parser parser, const XML_Char *encodingName) {
+ parser->m_processor = prologInitProcessor;
+ XmlPrologStateInit(&parser->m_prologState);
+ if (encodingName != NULL) {
+ parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ }
+ parser->m_curBase = NULL;
+ XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0);
+ parser->m_userData = NULL;
+ parser->m_handlerArg = NULL;
+ parser->m_startElementHandler = NULL;
+ parser->m_endElementHandler = NULL;
+ parser->m_characterDataHandler = NULL;
+ parser->m_processingInstructionHandler = NULL;
+ parser->m_commentHandler = NULL;
+ parser->m_startCdataSectionHandler = NULL;
+ parser->m_endCdataSectionHandler = NULL;
+ parser->m_defaultHandler = NULL;
+ parser->m_startDoctypeDeclHandler = NULL;
+ parser->m_endDoctypeDeclHandler = NULL;
+ parser->m_unparsedEntityDeclHandler = NULL;
+ parser->m_notationDeclHandler = NULL;
+ parser->m_startNamespaceDeclHandler = NULL;
+ parser->m_endNamespaceDeclHandler = NULL;
+ parser->m_notStandaloneHandler = NULL;
+ parser->m_externalEntityRefHandler = NULL;
+ parser->m_externalEntityRefHandlerArg = parser;
+ parser->m_skippedEntityHandler = NULL;
+ parser->m_elementDeclHandler = NULL;
+ parser->m_attlistDeclHandler = NULL;
+ parser->m_entityDeclHandler = NULL;
+ parser->m_xmlDeclHandler = NULL;
+ parser->m_bufferPtr = parser->m_buffer;
+ parser->m_bufferEnd = parser->m_buffer;
+ parser->m_parseEndByteIndex = 0;
+ parser->m_parseEndPtr = NULL;
+ parser->m_declElementType = NULL;
+ parser->m_declAttributeId = NULL;
+ parser->m_declEntity = NULL;
+ parser->m_doctypeName = NULL;
+ parser->m_doctypeSysid = NULL;
+ parser->m_doctypePubid = NULL;
+ parser->m_declAttributeType = NULL;
+ parser->m_declNotationName = NULL;
+ parser->m_declNotationPublicId = NULL;
+ parser->m_declAttributeIsCdata = XML_FALSE;
+ parser->m_declAttributeIsId = XML_FALSE;
+ memset(&parser->m_position, 0, sizeof(POSITION));
+ parser->m_errorCode = XML_ERROR_NONE;
+ parser->m_eventPtr = NULL;
+ parser->m_eventEndPtr = NULL;
+ parser->m_positionPtr = NULL;
+ parser->m_openInternalEntities = NULL;
+ parser->m_defaultExpandInternalEntities = XML_TRUE;
+ parser->m_tagLevel = 0;
+ parser->m_tagStack = NULL;
+ parser->m_inheritedBindings = NULL;
+ parser->m_nSpecifiedAtts = 0;
+ parser->m_unknownEncodingMem = NULL;
+ parser->m_unknownEncodingRelease = NULL;
+ parser->m_unknownEncodingData = NULL;
+ parser->m_parentParser = NULL;
+ parser->m_parsingStatus.parsing = XML_INITIALIZED;
#ifdef XML_DTD
- isParamEntity = XML_FALSE;
- useForeignDTD = XML_FALSE;
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ parser->m_isParamEntity = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
+ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif
- hash_secret_salt = 0;
+ parser->m_hash_secret_salt = 0;
}
-/* moves list of bindings to freeBindingList */
+/* moves list of bindings to m_freeBindingList */
static void FASTCALL
-moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
-{
+moveToFreeBindingList(XML_Parser parser, BINDING *bindings) {
while (bindings) {
BINDING *b = bindings;
bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
}
}
XML_Bool XMLCALL
-XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
-{
+XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
TAG *tStk;
OPEN_INTERNAL_ENTITY *openEntityList;
- if (parentParser)
+
+ if (parser == NULL)
+ return XML_FALSE;
+
+ if (parser->m_parentParser)
return XML_FALSE;
- /* move tagStack to freeTagList */
- tStk = tagStack;
+ /* move m_tagStack to m_freeTagList */
+ tStk = parser->m_tagStack;
while (tStk) {
TAG *tag = tStk;
tStk = tStk->parent;
- tag->parent = freeTagList;
+ tag->parent = parser->m_freeTagList;
moveToFreeBindingList(parser, tag->bindings);
tag->bindings = NULL;
- freeTagList = tag;
+ parser->m_freeTagList = tag;
}
- /* move openInternalEntities to freeInternalEntities */
- openEntityList = openInternalEntities;
+ /* move m_openInternalEntities to m_freeInternalEntities */
+ openEntityList = parser->m_openInternalEntities;
while (openEntityList) {
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
openEntityList = openEntity->next;
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
- }
- moveToFreeBindingList(parser, inheritedBindings);
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- poolClear(&tempPool);
- poolClear(&temp2Pool);
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
+ }
+ moveToFreeBindingList(parser, parser->m_inheritedBindings);
+ FREE(parser, parser->m_unknownEncodingMem);
+ if (parser->m_unknownEncodingRelease)
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ poolClear(&parser->m_tempPool);
+ poolClear(&parser->m_temp2Pool);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
+ parser->m_protocolEncodingName = NULL;
parserInit(parser, encodingName);
- dtdReset(_dtd, &parser->m_mem);
+ dtdReset(parser->m_dtd, &parser->m_mem);
return XML_TRUE;
}
enum XML_Status XMLCALL
-XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
-{
+XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
/* Block after XML_Parse()/XML_ParseBuffer() has been called.
XXX There's no way for the caller to determine which of the
XXX possible error cases caused the XML_STATUS_ERROR return.
*/
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING
+ || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return XML_STATUS_ERROR;
+
+ /* Get rid of any previous encoding name */
+ FREE(parser, (void *)parser->m_protocolEncodingName);
+
if (encodingName == NULL)
- protocolEncodingName = NULL;
+ /* No new encoding name */
+ parser->m_protocolEncodingName = NULL;
else {
- protocolEncodingName = poolCopyString(&tempPool, encodingName);
- if (!protocolEncodingName)
+ /* Copy the new encoding name into allocated memory */
+ parser->m_protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ if (! parser->m_protocolEncodingName)
return XML_STATUS_ERROR;
}
return XML_STATUS_OK;
}
XML_Parser XMLCALL
-XML_ExternalEntityParserCreate(XML_Parser oldParser,
- const XML_Char *context,
- const XML_Char *encodingName)
-{
+XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
+ const XML_Char *encodingName) {
XML_Parser parser = oldParser;
DTD *newDtd = NULL;
- DTD *oldDtd = _dtd;
- XML_StartElementHandler oldStartElementHandler = startElementHandler;
- XML_EndElementHandler oldEndElementHandler = endElementHandler;
- XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
- XML_ProcessingInstructionHandler oldProcessingInstructionHandler
- = processingInstructionHandler;
- XML_CommentHandler oldCommentHandler = commentHandler;
- XML_StartCdataSectionHandler oldStartCdataSectionHandler
- = startCdataSectionHandler;
- XML_EndCdataSectionHandler oldEndCdataSectionHandler
- = endCdataSectionHandler;
- XML_DefaultHandler oldDefaultHandler = defaultHandler;
- XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
- = unparsedEntityDeclHandler;
- XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
- XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
- = startNamespaceDeclHandler;
- XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
- = endNamespaceDeclHandler;
- XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
- XML_ExternalEntityRefHandler oldExternalEntityRefHandler
- = externalEntityRefHandler;
- XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
- XML_UnknownEncodingHandler oldUnknownEncodingHandler
- = unknownEncodingHandler;
- XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
- XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
- XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
- XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
- ELEMENT_TYPE * oldDeclElementType = declElementType;
-
- void *oldUserData = userData;
- void *oldHandlerArg = handlerArg;
- XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
- XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+ DTD *oldDtd;
+ XML_StartElementHandler oldStartElementHandler;
+ XML_EndElementHandler oldEndElementHandler;
+ XML_CharacterDataHandler oldCharacterDataHandler;
+ XML_ProcessingInstructionHandler oldProcessingInstructionHandler;
+ XML_CommentHandler oldCommentHandler;
+ XML_StartCdataSectionHandler oldStartCdataSectionHandler;
+ XML_EndCdataSectionHandler oldEndCdataSectionHandler;
+ XML_DefaultHandler oldDefaultHandler;
+ XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler;
+ XML_NotationDeclHandler oldNotationDeclHandler;
+ XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler;
+ XML_NotStandaloneHandler oldNotStandaloneHandler;
+ XML_ExternalEntityRefHandler oldExternalEntityRefHandler;
+ XML_SkippedEntityHandler oldSkippedEntityHandler;
+ XML_UnknownEncodingHandler oldUnknownEncodingHandler;
+ XML_ElementDeclHandler oldElementDeclHandler;
+ XML_AttlistDeclHandler oldAttlistDeclHandler;
+ XML_EntityDeclHandler oldEntityDeclHandler;
+ XML_XmlDeclHandler oldXmlDeclHandler;
+ ELEMENT_TYPE *oldDeclElementType;
+
+ void *oldUserData;
+ void *oldHandlerArg;
+ XML_Bool oldDefaultExpandInternalEntities;
+ XML_Parser oldExternalEntityRefHandlerArg;
#ifdef XML_DTD
- enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
- int oldInEntityValue = prologState.inEntityValue;
+ enum XML_ParamEntityParsing oldParamEntityParsing;
+ int oldInEntityValue;
#endif
- XML_Bool oldns_triplets = ns_triplets;
+ XML_Bool oldns_triplets;
/* Note that the new parser shares the same hash secret as the old
parser, so that dtdCopy and copyEntityTable can lookup values
from hash tables associated with either parser without us having
to worry which hash secrets each table has.
*/
- unsigned long oldhash_secret_salt = hash_secret_salt;
+ unsigned long oldhash_secret_salt;
+ /* Validate the oldParser parameter before we pull everything out of it */
+ if (oldParser == NULL)
+ return NULL;
+
+ /* Stash the original parser contents on the stack */
+ oldDtd = parser->m_dtd;
+ oldStartElementHandler = parser->m_startElementHandler;
+ oldEndElementHandler = parser->m_endElementHandler;
+ oldCharacterDataHandler = parser->m_characterDataHandler;
+ oldProcessingInstructionHandler = parser->m_processingInstructionHandler;
+ oldCommentHandler = parser->m_commentHandler;
+ oldStartCdataSectionHandler = parser->m_startCdataSectionHandler;
+ oldEndCdataSectionHandler = parser->m_endCdataSectionHandler;
+ oldDefaultHandler = parser->m_defaultHandler;
+ oldUnparsedEntityDeclHandler = parser->m_unparsedEntityDeclHandler;
+ oldNotationDeclHandler = parser->m_notationDeclHandler;
+ oldStartNamespaceDeclHandler = parser->m_startNamespaceDeclHandler;
+ oldEndNamespaceDeclHandler = parser->m_endNamespaceDeclHandler;
+ oldNotStandaloneHandler = parser->m_notStandaloneHandler;
+ oldExternalEntityRefHandler = parser->m_externalEntityRefHandler;
+ oldSkippedEntityHandler = parser->m_skippedEntityHandler;
+ oldUnknownEncodingHandler = parser->m_unknownEncodingHandler;
+ oldElementDeclHandler = parser->m_elementDeclHandler;
+ oldAttlistDeclHandler = parser->m_attlistDeclHandler;
+ oldEntityDeclHandler = parser->m_entityDeclHandler;
+ oldXmlDeclHandler = parser->m_xmlDeclHandler;
+ oldDeclElementType = parser->m_declElementType;
+
+ oldUserData = parser->m_userData;
+ oldHandlerArg = parser->m_handlerArg;
+ oldDefaultExpandInternalEntities = parser->m_defaultExpandInternalEntities;
+ oldExternalEntityRefHandlerArg = parser->m_externalEntityRefHandlerArg;
#ifdef XML_DTD
- if (!context)
+ oldParamEntityParsing = parser->m_paramEntityParsing;
+ oldInEntityValue = parser->m_prologState.inEntityValue;
+#endif
+ oldns_triplets = parser->m_ns_triplets;
+ /* Note that the new parser shares the same hash secret as the old
+ parser, so that dtdCopy and copyEntityTable can lookup values
+ from hash tables associated with either parser without us having
+ to worry which hash secrets each table has.
+ */
+ oldhash_secret_salt = parser->m_hash_secret_salt;
+
+#ifdef XML_DTD
+ if (! context)
newDtd = oldDtd;
#endif /* XML_DTD */
@@ -1040,445 +1252,458 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser,
here. This makes this function more painful to follow than it
would be otherwise.
*/
- if (ns) {
+ if (parser->m_ns) {
XML_Char tmp[2];
- *tmp = namespaceSeparator;
+ *tmp = parser->m_namespaceSeparator;
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
- }
- else {
+ } else {
parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
}
- if (!parser)
+ if (! parser)
return NULL;
- startElementHandler = oldStartElementHandler;
- endElementHandler = oldEndElementHandler;
- characterDataHandler = oldCharacterDataHandler;
- processingInstructionHandler = oldProcessingInstructionHandler;
- commentHandler = oldCommentHandler;
- startCdataSectionHandler = oldStartCdataSectionHandler;
- endCdataSectionHandler = oldEndCdataSectionHandler;
- defaultHandler = oldDefaultHandler;
- unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
- notationDeclHandler = oldNotationDeclHandler;
- startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
- endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
- notStandaloneHandler = oldNotStandaloneHandler;
- externalEntityRefHandler = oldExternalEntityRefHandler;
- skippedEntityHandler = oldSkippedEntityHandler;
- unknownEncodingHandler = oldUnknownEncodingHandler;
- elementDeclHandler = oldElementDeclHandler;
- attlistDeclHandler = oldAttlistDeclHandler;
- entityDeclHandler = oldEntityDeclHandler;
- xmlDeclHandler = oldXmlDeclHandler;
- declElementType = oldDeclElementType;
- userData = oldUserData;
+ parser->m_startElementHandler = oldStartElementHandler;
+ parser->m_endElementHandler = oldEndElementHandler;
+ parser->m_characterDataHandler = oldCharacterDataHandler;
+ parser->m_processingInstructionHandler = oldProcessingInstructionHandler;
+ parser->m_commentHandler = oldCommentHandler;
+ parser->m_startCdataSectionHandler = oldStartCdataSectionHandler;
+ parser->m_endCdataSectionHandler = oldEndCdataSectionHandler;
+ parser->m_defaultHandler = oldDefaultHandler;
+ parser->m_unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+ parser->m_notationDeclHandler = oldNotationDeclHandler;
+ parser->m_startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ parser->m_endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ parser->m_notStandaloneHandler = oldNotStandaloneHandler;
+ parser->m_externalEntityRefHandler = oldExternalEntityRefHandler;
+ parser->m_skippedEntityHandler = oldSkippedEntityHandler;
+ parser->m_unknownEncodingHandler = oldUnknownEncodingHandler;
+ parser->m_elementDeclHandler = oldElementDeclHandler;
+ parser->m_attlistDeclHandler = oldAttlistDeclHandler;
+ parser->m_entityDeclHandler = oldEntityDeclHandler;
+ parser->m_xmlDeclHandler = oldXmlDeclHandler;
+ parser->m_declElementType = oldDeclElementType;
+ parser->m_userData = oldUserData;
if (oldUserData == oldHandlerArg)
- handlerArg = userData;
+ parser->m_handlerArg = parser->m_userData;
else
- handlerArg = parser;
+ parser->m_handlerArg = parser;
if (oldExternalEntityRefHandlerArg != oldParser)
- externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
- defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
- ns_triplets = oldns_triplets;
- hash_secret_salt = oldhash_secret_salt;
- parentParser = oldParser;
+ parser->m_externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ parser->m_defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ parser->m_ns_triplets = oldns_triplets;
+ parser->m_hash_secret_salt = oldhash_secret_salt;
+ parser->m_parentParser = oldParser;
#ifdef XML_DTD
- paramEntityParsing = oldParamEntityParsing;
- prologState.inEntityValue = oldInEntityValue;
+ parser->m_paramEntityParsing = oldParamEntityParsing;
+ parser->m_prologState.inEntityValue = oldInEntityValue;
if (context) {
#endif /* XML_DTD */
- if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
- || !setContext(parser, context)) {
+ if (! dtdCopy(oldParser, parser->m_dtd, oldDtd, &parser->m_mem)
+ || ! setContext(parser, context)) {
XML_ParserFree(parser);
return NULL;
}
- processor = externalEntityInitProcessor;
+ parser->m_processor = externalEntityInitProcessor;
#ifdef XML_DTD
- }
- else {
- /* The DTD instance referenced by _dtd is shared between the document's
- root parser and external PE parsers, therefore one does not need to
- call setContext. In addition, one also *must* not call setContext,
- because this would overwrite existing prefix->binding pointers in
- _dtd with ones that get destroyed with the external PE parser.
- This would leave those prefixes with dangling pointers.
+ } else {
+ /* The DTD instance referenced by parser->m_dtd is shared between the
+ document's root parser and external PE parsers, therefore one does not
+ need to call setContext. In addition, one also *must* not call
+ setContext, because this would overwrite existing prefix->binding
+ pointers in parser->m_dtd with ones that get destroyed with the external
+ PE parser. This would leave those prefixes with dangling pointers.
*/
- isParamEntity = XML_TRUE;
- XmlPrologStateInitExternalEntity(&prologState);
- processor = externalParEntInitProcessor;
+ parser->m_isParamEntity = XML_TRUE;
+ XmlPrologStateInitExternalEntity(&parser->m_prologState);
+ parser->m_processor = externalParEntInitProcessor;
}
#endif /* XML_DTD */
return parser;
}
static void FASTCALL
-destroyBindings(BINDING *bindings, XML_Parser parser)
-{
+destroyBindings(BINDING *bindings, XML_Parser parser) {
for (;;) {
BINDING *b = bindings;
- if (!b)
+ if (! b)
break;
bindings = b->nextTagBinding;
- FREE(b->uri);
- FREE(b);
+ FREE(parser, b->uri);
+ FREE(parser, b);
}
}
void XMLCALL
-XML_ParserFree(XML_Parser parser)
-{
+XML_ParserFree(XML_Parser parser) {
TAG *tagList;
OPEN_INTERNAL_ENTITY *entityList;
if (parser == NULL)
return;
- /* free tagStack and freeTagList */
- tagList = tagStack;
+ /* free m_tagStack and m_freeTagList */
+ tagList = parser->m_tagStack;
for (;;) {
TAG *p;
if (tagList == NULL) {
- if (freeTagList == NULL)
+ if (parser->m_freeTagList == NULL)
break;
- tagList = freeTagList;
- freeTagList = NULL;
+ tagList = parser->m_freeTagList;
+ parser->m_freeTagList = NULL;
}
p = tagList;
tagList = tagList->parent;
- FREE(p->buf);
+ FREE(parser, p->buf);
destroyBindings(p->bindings, parser);
- FREE(p);
+ FREE(parser, p);
}
- /* free openInternalEntities and freeInternalEntities */
- entityList = openInternalEntities;
+ /* free m_openInternalEntities and m_freeInternalEntities */
+ entityList = parser->m_openInternalEntities;
for (;;) {
OPEN_INTERNAL_ENTITY *openEntity;
if (entityList == NULL) {
- if (freeInternalEntities == NULL)
+ if (parser->m_freeInternalEntities == NULL)
break;
- entityList = freeInternalEntities;
- freeInternalEntities = NULL;
+ entityList = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = NULL;
}
openEntity = entityList;
entityList = entityList->next;
- FREE(openEntity);
+ FREE(parser, openEntity);
}
- destroyBindings(freeBindingList, parser);
- destroyBindings(inheritedBindings, parser);
- poolDestroy(&tempPool);
- poolDestroy(&temp2Pool);
+ destroyBindings(parser->m_freeBindingList, parser);
+ destroyBindings(parser->m_inheritedBindings, parser);
+ poolDestroy(&parser->m_tempPool);
+ poolDestroy(&parser->m_temp2Pool);
+ FREE(parser, (void *)parser->m_protocolEncodingName);
#ifdef XML_DTD
/* external parameter entity parsers share the DTD structure
parser->m_dtd with the root parser, so we must not destroy it
*/
- if (!isParamEntity && _dtd)
+ if (! parser->m_isParamEntity && parser->m_dtd)
#else
- if (_dtd)
+ if (parser->m_dtd)
#endif /* XML_DTD */
- dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
- FREE((void *)atts);
+ dtdDestroy(parser->m_dtd, (XML_Bool)! parser->m_parentParser,
+ &parser->m_mem);
+ FREE(parser, (void *)parser->m_atts);
#ifdef XML_ATTR_INFO
- FREE((void *)attInfo);
+ FREE(parser, (void *)parser->m_attInfo);
#endif
- FREE(groupConnector);
- FREE(buffer);
- FREE(dataBuf);
- FREE(nsAtts);
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- FREE(parser);
+ FREE(parser, parser->m_groupConnector);
+ FREE(parser, parser->m_buffer);
+ FREE(parser, parser->m_dataBuf);
+ FREE(parser, parser->m_nsAtts);
+ FREE(parser, parser->m_unknownEncodingMem);
+ if (parser->m_unknownEncodingRelease)
+ parser->m_unknownEncodingRelease(parser->m_unknownEncodingData);
+ FREE(parser, parser);
}
void XMLCALL
-XML_UseParserAsHandlerArg(XML_Parser parser)
-{
- handlerArg = parser;
+XML_UseParserAsHandlerArg(XML_Parser parser) {
+ if (parser != NULL)
+ parser->m_handlerArg = parser;
}
enum XML_Error XMLCALL
-XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
-{
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) {
+ if (parser == NULL)
+ return XML_ERROR_INVALID_ARGUMENT;
#ifdef XML_DTD
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING
+ || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
- useForeignDTD = useDTD;
+ parser->m_useForeignDTD = useDTD;
return XML_ERROR_NONE;
#else
+ UNUSED_P(useDTD);
return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
#endif
}
void XMLCALL
-XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
-{
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) {
+ if (parser == NULL)
+ return;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING
+ || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return;
- ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+ parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
}
void XMLCALL
-XML_SetUserData(XML_Parser parser, void *p)
-{
- if (handlerArg == userData)
- handlerArg = userData = p;
+XML_SetUserData(XML_Parser parser, void *p) {
+ if (parser == NULL)
+ return;
+ if (parser->m_handlerArg == parser->m_userData)
+ parser->m_handlerArg = parser->m_userData = p;
else
- userData = p;
+ parser->m_userData = p;
}
enum XML_Status XMLCALL
-XML_SetBase(XML_Parser parser, const XML_Char *p)
-{
+XML_SetBase(XML_Parser parser, const XML_Char *p) {
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
if (p) {
- p = poolCopyString(&_dtd->pool, p);
- if (!p)
+ p = poolCopyString(&parser->m_dtd->pool, p);
+ if (! p)
return XML_STATUS_ERROR;
- curBase = p;
- }
- else
- curBase = NULL;
+ parser->m_curBase = p;
+ } else
+ parser->m_curBase = NULL;
return XML_STATUS_OK;
}
-const XML_Char * XMLCALL
-XML_GetBase(XML_Parser parser)
-{
- return curBase;
+const XML_Char *XMLCALL
+XML_GetBase(XML_Parser parser) {
+ if (parser == NULL)
+ return NULL;
+ return parser->m_curBase;
}
int XMLCALL
-XML_GetSpecifiedAttributeCount(XML_Parser parser)
-{
- return nSpecifiedAtts;
+XML_GetSpecifiedAttributeCount(XML_Parser parser) {
+ if (parser == NULL)
+ return -1;
+ return parser->m_nSpecifiedAtts;
}
int XMLCALL
-XML_GetIdAttributeIndex(XML_Parser parser)
-{
- return idAttIndex;
+XML_GetIdAttributeIndex(XML_Parser parser) {
+ if (parser == NULL)
+ return -1;
+ return parser->m_idAttIndex;
}
#ifdef XML_ATTR_INFO
-const XML_AttrInfo * XMLCALL
-XML_GetAttributeInfo(XML_Parser parser)
-{
- return attInfo;
+const XML_AttrInfo *XMLCALL
+XML_GetAttributeInfo(XML_Parser parser) {
+ if (parser == NULL)
+ return NULL;
+ return parser->m_attInfo;
}
#endif
void XMLCALL
-XML_SetElementHandler(XML_Parser parser,
- XML_StartElementHandler start,
- XML_EndElementHandler end)
-{
- startElementHandler = start;
- endElementHandler = end;
+XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start,
+ XML_EndElementHandler end) {
+ if (parser == NULL)
+ return;
+ parser->m_startElementHandler = start;
+ parser->m_endElementHandler = end;
}
void XMLCALL
-XML_SetStartElementHandler(XML_Parser parser,
- XML_StartElementHandler start) {
- startElementHandler = start;
+XML_SetStartElementHandler(XML_Parser parser, XML_StartElementHandler start) {
+ if (parser != NULL)
+ parser->m_startElementHandler = start;
}
void XMLCALL
-XML_SetEndElementHandler(XML_Parser parser,
- XML_EndElementHandler end) {
- endElementHandler = end;
+XML_SetEndElementHandler(XML_Parser parser, XML_EndElementHandler end) {
+ if (parser != NULL)
+ parser->m_endElementHandler = end;
}
void XMLCALL
XML_SetCharacterDataHandler(XML_Parser parser,
- XML_CharacterDataHandler handler)
-{
- characterDataHandler = handler;
+ XML_CharacterDataHandler handler) {
+ if (parser != NULL)
+ parser->m_characterDataHandler = handler;
}
void XMLCALL
XML_SetProcessingInstructionHandler(XML_Parser parser,
- XML_ProcessingInstructionHandler handler)
-{
- processingInstructionHandler = handler;
+ XML_ProcessingInstructionHandler handler) {
+ if (parser != NULL)
+ parser->m_processingInstructionHandler = handler;
}
void XMLCALL
-XML_SetCommentHandler(XML_Parser parser,
- XML_CommentHandler handler)
-{
- commentHandler = handler;
+XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler) {
+ if (parser != NULL)
+ parser->m_commentHandler = handler;
}
void XMLCALL
XML_SetCdataSectionHandler(XML_Parser parser,
XML_StartCdataSectionHandler start,
- XML_EndCdataSectionHandler end)
-{
- startCdataSectionHandler = start;
- endCdataSectionHandler = end;
+ XML_EndCdataSectionHandler end) {
+ if (parser == NULL)
+ return;
+ parser->m_startCdataSectionHandler = start;
+ parser->m_endCdataSectionHandler = end;
}
void XMLCALL
XML_SetStartCdataSectionHandler(XML_Parser parser,
XML_StartCdataSectionHandler start) {
- startCdataSectionHandler = start;
+ if (parser != NULL)
+ parser->m_startCdataSectionHandler = start;
}
void XMLCALL
XML_SetEndCdataSectionHandler(XML_Parser parser,
XML_EndCdataSectionHandler end) {
- endCdataSectionHandler = end;
+ if (parser != NULL)
+ parser->m_endCdataSectionHandler = end;
}
void XMLCALL
-XML_SetDefaultHandler(XML_Parser parser,
- XML_DefaultHandler handler)
-{
- defaultHandler = handler;
- defaultExpandInternalEntities = XML_FALSE;
+XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler) {
+ if (parser == NULL)
+ return;
+ parser->m_defaultHandler = handler;
+ parser->m_defaultExpandInternalEntities = XML_FALSE;
}
void XMLCALL
-XML_SetDefaultHandlerExpand(XML_Parser parser,
- XML_DefaultHandler handler)
-{
- defaultHandler = handler;
- defaultExpandInternalEntities = XML_TRUE;
+XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler) {
+ if (parser == NULL)
+ return;
+ parser->m_defaultHandler = handler;
+ parser->m_defaultExpandInternalEntities = XML_TRUE;
}
void XMLCALL
-XML_SetDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start,
- XML_EndDoctypeDeclHandler end)
-{
- startDoctypeDeclHandler = start;
- endDoctypeDeclHandler = end;
+XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end) {
+ if (parser == NULL)
+ return;
+ parser->m_startDoctypeDeclHandler = start;
+ parser->m_endDoctypeDeclHandler = end;
}
void XMLCALL
XML_SetStartDoctypeDeclHandler(XML_Parser parser,
XML_StartDoctypeDeclHandler start) {
- startDoctypeDeclHandler = start;
+ if (parser != NULL)
+ parser->m_startDoctypeDeclHandler = start;
}
void XMLCALL
-XML_SetEndDoctypeDeclHandler(XML_Parser parser,
- XML_EndDoctypeDeclHandler end) {
- endDoctypeDeclHandler = end;
+XML_SetEndDoctypeDeclHandler(XML_Parser parser, XML_EndDoctypeDeclHandler end) {
+ if (parser != NULL)
+ parser->m_endDoctypeDeclHandler = end;
}
void XMLCALL
XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
- XML_UnparsedEntityDeclHandler handler)
-{
- unparsedEntityDeclHandler = handler;
+ XML_UnparsedEntityDeclHandler handler) {
+ if (parser != NULL)
+ parser->m_unparsedEntityDeclHandler = handler;
}
void XMLCALL
-XML_SetNotationDeclHandler(XML_Parser parser,
- XML_NotationDeclHandler handler)
-{
- notationDeclHandler = handler;
+XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler) {
+ if (parser != NULL)
+ parser->m_notationDeclHandler = handler;
}
void XMLCALL
XML_SetNamespaceDeclHandler(XML_Parser parser,
XML_StartNamespaceDeclHandler start,
- XML_EndNamespaceDeclHandler end)
-{
- startNamespaceDeclHandler = start;
- endNamespaceDeclHandler = end;
+ XML_EndNamespaceDeclHandler end) {
+ if (parser == NULL)
+ return;
+ parser->m_startNamespaceDeclHandler = start;
+ parser->m_endNamespaceDeclHandler = end;
}
void XMLCALL
XML_SetStartNamespaceDeclHandler(XML_Parser parser,
XML_StartNamespaceDeclHandler start) {
- startNamespaceDeclHandler = start;
+ if (parser != NULL)
+ parser->m_startNamespaceDeclHandler = start;
}
void XMLCALL
XML_SetEndNamespaceDeclHandler(XML_Parser parser,
XML_EndNamespaceDeclHandler end) {
- endNamespaceDeclHandler = end;
+ if (parser != NULL)
+ parser->m_endNamespaceDeclHandler = end;
}
void XMLCALL
XML_SetNotStandaloneHandler(XML_Parser parser,
- XML_NotStandaloneHandler handler)
-{
- notStandaloneHandler = handler;
+ XML_NotStandaloneHandler handler) {
+ if (parser != NULL)
+ parser->m_notStandaloneHandler = handler;
}
void XMLCALL
XML_SetExternalEntityRefHandler(XML_Parser parser,
- XML_ExternalEntityRefHandler handler)
-{
- externalEntityRefHandler = handler;
+ XML_ExternalEntityRefHandler handler) {
+ if (parser != NULL)
+ parser->m_externalEntityRefHandler = handler;
}
void XMLCALL
-XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
-{
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) {
+ if (parser == NULL)
+ return;
if (arg)
- externalEntityRefHandlerArg = (XML_Parser)arg;
+ parser->m_externalEntityRefHandlerArg = (XML_Parser)arg;
else
- externalEntityRefHandlerArg = parser;
+ parser->m_externalEntityRefHandlerArg = parser;
}
void XMLCALL
XML_SetSkippedEntityHandler(XML_Parser parser,
- XML_SkippedEntityHandler handler)
-{
- skippedEntityHandler = handler;
+ XML_SkippedEntityHandler handler) {
+ if (parser != NULL)
+ parser->m_skippedEntityHandler = handler;
}
void XMLCALL
XML_SetUnknownEncodingHandler(XML_Parser parser,
- XML_UnknownEncodingHandler handler,
- void *data)
-{
- unknownEncodingHandler = handler;
- unknownEncodingHandlerData = data;
+ XML_UnknownEncodingHandler handler, void *data) {
+ if (parser == NULL)
+ return;
+ parser->m_unknownEncodingHandler = handler;
+ parser->m_unknownEncodingHandlerData = data;
}
void XMLCALL
-XML_SetElementDeclHandler(XML_Parser parser,
- XML_ElementDeclHandler eldecl)
-{
- elementDeclHandler = eldecl;
+XML_SetElementDeclHandler(XML_Parser parser, XML_ElementDeclHandler eldecl) {
+ if (parser != NULL)
+ parser->m_elementDeclHandler = eldecl;
}
void XMLCALL
-XML_SetAttlistDeclHandler(XML_Parser parser,
- XML_AttlistDeclHandler attdecl)
-{
- attlistDeclHandler = attdecl;
+XML_SetAttlistDeclHandler(XML_Parser parser, XML_AttlistDeclHandler attdecl) {
+ if (parser != NULL)
+ parser->m_attlistDeclHandler = attdecl;
}
void XMLCALL
-XML_SetEntityDeclHandler(XML_Parser parser,
- XML_EntityDeclHandler handler)
-{
- entityDeclHandler = handler;
+XML_SetEntityDeclHandler(XML_Parser parser, XML_EntityDeclHandler handler) {
+ if (parser != NULL)
+ parser->m_entityDeclHandler = handler;
}
void XMLCALL
-XML_SetXmlDeclHandler(XML_Parser parser,
- XML_XmlDeclHandler handler) {
- xmlDeclHandler = handler;
+XML_SetXmlDeclHandler(XML_Parser parser, XML_XmlDeclHandler handler) {
+ if (parser != NULL)
+ parser->m_xmlDeclHandler = handler;
}
int XMLCALL
XML_SetParamEntityParsing(XML_Parser parser,
- enum XML_ParamEntityParsing peParsing)
-{
+ enum XML_ParamEntityParsing peParsing) {
+ if (parser == NULL)
+ return 0;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING
+ || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return 0;
#ifdef XML_DTD
- paramEntityParsing = peParsing;
+ parser->m_paramEntityParsing = peParsing;
return 1;
#else
return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
@@ -1486,91 +1711,122 @@ XML_SetParamEntityParsing(XML_Parser parser,
}
int XMLCALL
-XML_SetHashSalt(XML_Parser parser,
- unsigned long hash_salt)
-{
+XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
+ if (parser == NULL)
+ return 0;
+ if (parser->m_parentParser)
+ return XML_SetHashSalt(parser->m_parentParser, hash_salt);
/* block after XML_Parse()/XML_ParseBuffer() has been called */
- if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ if (parser->m_parsingStatus.parsing == XML_PARSING
+ || parser->m_parsingStatus.parsing == XML_SUSPENDED)
return 0;
- hash_secret_salt = hash_salt;
+ parser->m_hash_secret_salt = hash_salt;
return 1;
}
enum XML_Status XMLCALL
-XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
-{
- switch (ps_parsing) {
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) {
+ if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) {
+ if (parser != NULL)
+ parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
+ return XML_STATUS_ERROR;
+ }
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
- if (parentParser == NULL && !startParsing(parser)) {
- errorCode = XML_ERROR_NO_MEMORY;
+ if (parser->m_parentParser == NULL && ! startParsing(parser)) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
+ /* fall through */
default:
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
}
if (len == 0) {
- ps_finalBuffer = (XML_Bool)isFinal;
- if (!isFinal)
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
+ if (! isFinal)
return XML_STATUS_OK;
- positionPtr = bufferPtr;
- parseEndPtr = bufferEnd;
+ parser->m_positionPtr = parser->m_bufferPtr;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
/* If data are left over from last buffer, and we now know that these
data are the final chunk of input, then we have to check them again
to detect errors based on that fact.
*/
- errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+ parser->m_errorCode
+ = parser->m_processor(parser, parser->m_bufferPtr,
+ parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode == XML_ERROR_NONE) {
- switch (ps_parsing) {
+ if (parser->m_errorCode == XML_ERROR_NONE) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ /* It is hard to be certain, but it seems that this case
+ * cannot occur. This code is cleaning up a previous parse
+ * with no new data (since len == 0). Changing the parsing
+ * state requires getting to execute a handler function, and
+ * there doesn't seem to be an opportunity for that while in
+ * this circumstance.
+ *
+ * Given the uncertainty, we retain the code but exclude it
+ * from coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
+ parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return XML_STATUS_SUSPENDED;
+ /* LCOV_EXCL_STOP */
case XML_INITIALIZED:
case XML_PARSING:
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
/* fall through */
default:
return XML_STATUS_OK;
}
}
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
#ifndef XML_CONTEXT_BYTES
- else if (bufferPtr == bufferEnd) {
+ else if (parser->m_bufferPtr == parser->m_bufferEnd) {
const char *end;
int nLeftOver;
enum XML_Status result;
- parseEndByteIndex += len;
- positionPtr = s;
- ps_finalBuffer = (XML_Bool)isFinal;
+ /* Detect overflow (a+b > MAX <==> b > MAX-a) */
+ if ((XML_Size)len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ parser->m_parseEndByteIndex += len;
+ parser->m_positionPtr = s;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+ parser->m_errorCode
+ = parser->m_processor(parser, s, parser->m_parseEndPtr = s + len, &end);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
- }
- else {
- switch (ps_parsing) {
+ } else {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
if (isFinal) {
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return XML_STATUS_OK;
}
/* fall through */
@@ -1579,35 +1835,38 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
}
}
- XmlUpdatePosition(encoding, positionPtr, end, &position);
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, end,
+ &parser->m_position);
nLeftOver = s + len - end;
if (nLeftOver) {
- if (buffer == NULL || nLeftOver > bufferLim - buffer) {
- /* FIXME avoid integer overflow */
- char *temp;
- temp = (buffer == NULL
- ? (char *)MALLOC(len * 2)
- : (char *)REALLOC(buffer, len * 2));
+ if (parser->m_buffer == NULL
+ || nLeftOver > parser->m_bufferLim - parser->m_buffer) {
+ /* avoid _signed_ integer overflow */
+ char *temp = NULL;
+ const int bytesToAllocate = (int)((unsigned)len * 2U);
+ if (bytesToAllocate > 0) {
+ temp = (char *)REALLOC(parser, parser->m_buffer, bytesToAllocate);
+ }
if (temp == NULL) {
- errorCode = XML_ERROR_NO_MEMORY;
- eventPtr = eventEndPtr = NULL;
- processor = errorProcessor;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
}
- buffer = temp;
- bufferLim = buffer + len * 2;
+ parser->m_buffer = temp;
+ parser->m_bufferLim = parser->m_buffer + bytesToAllocate;
}
- memcpy(buffer, end, nLeftOver);
+ memcpy(parser->m_buffer, end, nLeftOver);
}
- bufferPtr = buffer;
- bufferEnd = buffer + nLeftOver;
- positionPtr = bufferPtr;
- parseEndPtr = bufferEnd;
- eventPtr = bufferPtr;
- eventEndPtr = bufferPtr;
+ parser->m_bufferPtr = parser->m_buffer;
+ parser->m_bufferEnd = parser->m_buffer + nLeftOver;
+ parser->m_positionPtr = parser->m_bufferPtr;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
+ parser->m_eventPtr = parser->m_bufferPtr;
+ parser->m_eventEndPtr = parser->m_bufferPtr;
return result;
}
-#endif /* not defined XML_CONTEXT_BYTES */
+#endif /* not defined XML_CONTEXT_BYTES */
else {
void *buff = XML_GetBuffer(parser, len);
if (buff == NULL)
@@ -1620,375 +1879,470 @@ XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
}
enum XML_Status XMLCALL
-XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
-{
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal) {
const char *start;
enum XML_Status result = XML_STATUS_OK;
- switch (ps_parsing) {
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
case XML_INITIALIZED:
- if (parentParser == NULL && !startParsing(parser)) {
- errorCode = XML_ERROR_NO_MEMORY;
+ if (parser->m_parentParser == NULL && ! startParsing(parser)) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
+ /* fall through */
default:
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
}
- start = bufferPtr;
- positionPtr = start;
- bufferEnd += len;
- parseEndPtr = bufferEnd;
- parseEndByteIndex += len;
- ps_finalBuffer = (XML_Bool)isFinal;
+ start = parser->m_bufferPtr;
+ parser->m_positionPtr = start;
+ parser->m_bufferEnd += len;
+ parser->m_parseEndPtr = parser->m_bufferEnd;
+ parser->m_parseEndByteIndex += len;
+ parser->m_parsingStatus.finalBuffer = (XML_Bool)isFinal;
- errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(
+ parser, start, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
- }
- else {
- switch (ps_parsing) {
+ } else {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
if (isFinal) {
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
- default: ; /* should not happen */
+ default:; /* should not happen */
}
}
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
+ parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return result;
}
-void * XMLCALL
-XML_GetBuffer(XML_Parser parser, int len)
-{
+void *XMLCALL
+XML_GetBuffer(XML_Parser parser, int len) {
+ if (parser == NULL)
+ return NULL;
if (len < 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return NULL;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return NULL;
- default: ;
+ default:;
}
- if (len > bufferLim - bufferEnd) {
- int neededSize = len + (int)(bufferEnd - bufferPtr);
+ if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)) {
+#ifdef XML_CONTEXT_BYTES
+ int keep;
+#endif /* defined XML_CONTEXT_BYTES */
+ /* Do not invoke signed arithmetic overflow: */
+ int neededSize = (int)((unsigned)len
+ + (unsigned)EXPAT_SAFE_PTR_DIFF(
+ parser->m_bufferEnd, parser->m_bufferPtr));
if (neededSize < 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
#ifdef XML_CONTEXT_BYTES
- int keep = (int)(bufferPtr - buffer);
-
+ keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
neededSize += keep;
-#endif /* defined XML_CONTEXT_BYTES */
- if (neededSize <= bufferLim - buffer) {
+#endif /* defined XML_CONTEXT_BYTES */
+ if (neededSize
+ <= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
#ifdef XML_CONTEXT_BYTES
- if (keep < bufferPtr - buffer) {
- int offset = (int)(bufferPtr - buffer) - keep;
- memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
- bufferEnd -= offset;
- bufferPtr -= offset;
+ if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
+ int offset
+ = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)
+ - keep;
+ /* The buffer pointers cannot be NULL here; we have at least some bytes
+ * in the buffer */
+ memmove(parser->m_buffer, &parser->m_buffer[offset],
+ parser->m_bufferEnd - parser->m_bufferPtr + keep);
+ parser->m_bufferEnd -= offset;
+ parser->m_bufferPtr -= offset;
}
#else
- memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
- bufferEnd = buffer + (bufferEnd - bufferPtr);
- bufferPtr = buffer;
-#endif /* not defined XML_CONTEXT_BYTES */
- }
- else {
+ if (parser->m_buffer && parser->m_bufferPtr) {
+ memmove(parser->m_buffer, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ parser->m_bufferEnd
+ = parser->m_buffer
+ + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ parser->m_bufferPtr = parser->m_buffer;
+ }
+#endif /* not defined XML_CONTEXT_BYTES */
+ } else {
char *newBuf;
- int bufferSize = (int)(bufferLim - bufferPtr);
+ int bufferSize
+ = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferPtr);
if (bufferSize == 0)
bufferSize = INIT_BUFFER_SIZE;
do {
- bufferSize *= 2;
+ /* Do not invoke signed arithmetic overflow: */
+ bufferSize = (int)(2U * (unsigned)bufferSize);
} while (bufferSize < neededSize && bufferSize > 0);
if (bufferSize <= 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- newBuf = (char *)MALLOC(bufferSize);
+ newBuf = (char *)MALLOC(parser, bufferSize);
if (newBuf == 0) {
- errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- bufferLim = newBuf + bufferSize;
+ parser->m_bufferLim = newBuf + bufferSize;
#ifdef XML_CONTEXT_BYTES
- if (bufferPtr) {
- int keep = (int)(bufferPtr - buffer);
- if (keep > XML_CONTEXT_BYTES)
- keep = XML_CONTEXT_BYTES;
- memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
- FREE(buffer);
- buffer = newBuf;
- bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
- bufferPtr = buffer + keep;
- }
- else {
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
+ if (parser->m_bufferPtr) {
+ memcpy(newBuf, &parser->m_bufferPtr[-keep],
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
+ + keep);
+ FREE(parser, parser->m_buffer);
+ parser->m_buffer = newBuf;
+ parser->m_bufferEnd
+ = parser->m_buffer
+ + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
+ + keep;
+ parser->m_bufferPtr = parser->m_buffer + keep;
+ } else {
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_bufferEnd = newBuf;
+ parser->m_bufferPtr = parser->m_buffer = newBuf;
}
#else
- if (bufferPtr) {
- memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
- FREE(buffer);
+ if (parser->m_bufferPtr) {
+ memcpy(newBuf, parser->m_bufferPtr,
+ EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
+ FREE(parser, parser->m_buffer);
+ parser->m_bufferEnd
+ = newBuf
+ + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ } else {
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_bufferEnd = newBuf;
}
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
-#endif /* not defined XML_CONTEXT_BYTES */
+ parser->m_bufferPtr = parser->m_buffer = newBuf;
+#endif /* not defined XML_CONTEXT_BYTES */
}
- eventPtr = eventEndPtr = NULL;
- positionPtr = NULL;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_positionPtr = NULL;
}
- return bufferEnd;
+ return parser->m_bufferEnd;
}
enum XML_Status XMLCALL
-XML_StopParser(XML_Parser parser, XML_Bool resumable)
-{
- switch (ps_parsing) {
+XML_StopParser(XML_Parser parser, XML_Bool resumable) {
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
if (resumable) {
- errorCode = XML_ERROR_SUSPENDED;
+ parser->m_errorCode = XML_ERROR_SUSPENDED;
return XML_STATUS_ERROR;
}
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_FINISHED;
break;
case XML_FINISHED:
- errorCode = XML_ERROR_FINISHED;
+ parser->m_errorCode = XML_ERROR_FINISHED;
return XML_STATUS_ERROR;
default:
if (resumable) {
#ifdef XML_DTD
- if (isParamEntity) {
- errorCode = XML_ERROR_SUSPEND_PE;
+ if (parser->m_isParamEntity) {
+ parser->m_errorCode = XML_ERROR_SUSPEND_PE;
return XML_STATUS_ERROR;
}
#endif
- ps_parsing = XML_SUSPENDED;
- }
- else
- ps_parsing = XML_FINISHED;
+ parser->m_parsingStatus.parsing = XML_SUSPENDED;
+ } else
+ parser->m_parsingStatus.parsing = XML_FINISHED;
}
return XML_STATUS_OK;
}
enum XML_Status XMLCALL
-XML_ResumeParser(XML_Parser parser)
-{
+XML_ResumeParser(XML_Parser parser) {
enum XML_Status result = XML_STATUS_OK;
- if (ps_parsing != XML_SUSPENDED) {
- errorCode = XML_ERROR_NOT_SUSPENDED;
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ if (parser->m_parsingStatus.parsing != XML_SUSPENDED) {
+ parser->m_errorCode = XML_ERROR_NOT_SUSPENDED;
return XML_STATUS_ERROR;
}
- ps_parsing = XML_PARSING;
+ parser->m_parsingStatus.parsing = XML_PARSING;
- errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+ parser->m_errorCode = parser->m_processor(
+ parser, parser->m_bufferPtr, parser->m_parseEndPtr, &parser->m_bufferPtr);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
+ if (parser->m_errorCode != XML_ERROR_NONE) {
+ parser->m_eventEndPtr = parser->m_eventPtr;
+ parser->m_processor = errorProcessor;
return XML_STATUS_ERROR;
- }
- else {
- switch (ps_parsing) {
+ } else {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
result = XML_STATUS_SUSPENDED;
break;
case XML_INITIALIZED:
case XML_PARSING:
- if (ps_finalBuffer) {
- ps_parsing = XML_FINISHED;
+ if (parser->m_parsingStatus.finalBuffer) {
+ parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
- default: ;
+ default:;
}
}
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- positionPtr = bufferPtr;
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
+ parser->m_bufferPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_bufferPtr;
return result;
}
void XMLCALL
-XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
-{
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) {
+ if (parser == NULL)
+ return;
assert(status != NULL);
*status = parser->m_parsingStatus;
}
enum XML_Error XMLCALL
-XML_GetErrorCode(XML_Parser parser)
-{
- return errorCode;
+XML_GetErrorCode(XML_Parser parser) {
+ if (parser == NULL)
+ return XML_ERROR_INVALID_ARGUMENT;
+ return parser->m_errorCode;
}
XML_Index XMLCALL
-XML_GetCurrentByteIndex(XML_Parser parser)
-{
- if (eventPtr)
- return parseEndByteIndex - (parseEndPtr - eventPtr);
+XML_GetCurrentByteIndex(XML_Parser parser) {
+ if (parser == NULL)
+ return -1;
+ if (parser->m_eventPtr)
+ return (XML_Index)(parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - parser->m_eventPtr));
return -1;
}
int XMLCALL
-XML_GetCurrentByteCount(XML_Parser parser)
-{
- if (eventEndPtr && eventPtr)
- return (int)(eventEndPtr - eventPtr);
+XML_GetCurrentByteCount(XML_Parser parser) {
+ if (parser == NULL)
+ return 0;
+ if (parser->m_eventEndPtr && parser->m_eventPtr)
+ return (int)(parser->m_eventEndPtr - parser->m_eventPtr);
return 0;
}
-const char * XMLCALL
-XML_GetInputContext(XML_Parser parser, int *offset, int *size)
-{
+const char *XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size) {
#ifdef XML_CONTEXT_BYTES
- if (eventPtr && buffer) {
- *offset = (int)(eventPtr - buffer);
- *size = (int)(bufferEnd - buffer);
- return buffer;
+ if (parser == NULL)
+ return NULL;
+ if (parser->m_eventPtr && parser->m_buffer) {
+ if (offset != NULL)
+ *offset = (int)(parser->m_eventPtr - parser->m_buffer);
+ if (size != NULL)
+ *size = (int)(parser->m_bufferEnd - parser->m_buffer);
+ return parser->m_buffer;
}
+#else
+ (void)parser;
+ (void)offset;
+ (void)size;
#endif /* defined XML_CONTEXT_BYTES */
- return (char *) 0;
+ return (const char *)0;
}
XML_Size XMLCALL
-XML_GetCurrentLineNumber(XML_Parser parser)
-{
- if (eventPtr && eventPtr >= positionPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
+XML_GetCurrentLineNumber(XML_Parser parser) {
+ if (parser == NULL)
+ return 0;
+ if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
+ parser->m_eventPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_eventPtr;
}
- return position.lineNumber + 1;
+ return parser->m_position.lineNumber + 1;
}
XML_Size XMLCALL
-XML_GetCurrentColumnNumber(XML_Parser parser)
-{
- if (eventPtr && eventPtr >= positionPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
+XML_GetCurrentColumnNumber(XML_Parser parser) {
+ if (parser == NULL)
+ return 0;
+ if (parser->m_eventPtr && parser->m_eventPtr >= parser->m_positionPtr) {
+ XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr,
+ parser->m_eventPtr, &parser->m_position);
+ parser->m_positionPtr = parser->m_eventPtr;
}
- return position.columnNumber;
+ return parser->m_position.columnNumber;
}
void XMLCALL
-XML_FreeContentModel(XML_Parser parser, XML_Content *model)
-{
- FREE(model);
+XML_FreeContentModel(XML_Parser parser, XML_Content *model) {
+ if (parser != NULL)
+ FREE(parser, model);
}
-void * XMLCALL
-XML_MemMalloc(XML_Parser parser, size_t size)
-{
- return MALLOC(size);
+void *XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size) {
+ if (parser == NULL)
+ return NULL;
+ return MALLOC(parser, size);
}
-void * XMLCALL
-XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
-{
- return REALLOC(ptr, size);
+void *XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) {
+ if (parser == NULL)
+ return NULL;
+ return REALLOC(parser, ptr, size);
}
void XMLCALL
-XML_MemFree(XML_Parser parser, void *ptr)
-{
- FREE(ptr);
+XML_MemFree(XML_Parser parser, void *ptr) {
+ if (parser != NULL)
+ FREE(parser, ptr);
}
void XMLCALL
-XML_DefaultCurrent(XML_Parser parser)
-{
- if (defaultHandler) {
- if (openInternalEntities)
- reportDefault(parser,
- internalEncoding,
- openInternalEntities->internalEventPtr,
- openInternalEntities->internalEventEndPtr);
+XML_DefaultCurrent(XML_Parser parser) {
+ if (parser == NULL)
+ return;
+ if (parser->m_defaultHandler) {
+ if (parser->m_openInternalEntities)
+ reportDefault(parser, parser->m_internalEncoding,
+ parser->m_openInternalEntities->internalEventPtr,
+ parser->m_openInternalEntities->internalEventEndPtr);
else
- reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ reportDefault(parser, parser->m_encoding, parser->m_eventPtr,
+ parser->m_eventEndPtr);
}
}
-const XML_LChar * XMLCALL
-XML_ErrorString(enum XML_Error code)
-{
- static const XML_LChar* const message[] = {
- 0,
- XML_L("out of memory"),
- XML_L("syntax error"),
- XML_L("no element found"),
- XML_L("not well-formed (invalid token)"),
- XML_L("unclosed token"),
- XML_L("partial character"),
- XML_L("mismatched tag"),
- XML_L("duplicate attribute"),
- XML_L("junk after document element"),
- XML_L("illegal parameter entity reference"),
- XML_L("undefined entity"),
- XML_L("recursive entity reference"),
- XML_L("asynchronous entity"),
- XML_L("reference to invalid character number"),
- XML_L("reference to binary entity"),
- XML_L("reference to external entity in attribute"),
- XML_L("XML or text declaration not at start of entity"),
- XML_L("unknown encoding"),
- XML_L("encoding specified in XML declaration is incorrect"),
- XML_L("unclosed CDATA section"),
- XML_L("error in processing external entity reference"),
- XML_L("document is not standalone"),
- XML_L("unexpected parser state - please send a bug report"),
- XML_L("entity declared in parameter entity"),
- XML_L("requested feature requires XML_DTD support in Expat"),
- XML_L("cannot change setting once parsing has begun"),
- XML_L("unbound prefix"),
- XML_L("must not undeclare prefix"),
- XML_L("incomplete markup in parameter entity"),
- XML_L("XML declaration not well-formed"),
- XML_L("text declaration not well-formed"),
- XML_L("illegal character(s) in public id"),
- XML_L("parser suspended"),
- XML_L("parser not suspended"),
- XML_L("parsing aborted"),
- XML_L("parsing finished"),
- XML_L("cannot suspend in external parameter entity"),
- XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
- XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
- XML_L("prefix must not be bound to one of the reserved namespace names")
- };
- if (code > 0 && code < sizeof(message)/sizeof(message[0]))
- return message[code];
+const XML_LChar *XMLCALL
+XML_ErrorString(enum XML_Error code) {
+ switch (code) {
+ case XML_ERROR_NONE:
+ return NULL;
+ case XML_ERROR_NO_MEMORY:
+ return XML_L("out of memory");
+ case XML_ERROR_SYNTAX:
+ return XML_L("syntax error");
+ case XML_ERROR_NO_ELEMENTS:
+ return XML_L("no element found");
+ case XML_ERROR_INVALID_TOKEN:
+ return XML_L("not well-formed (invalid token)");
+ case XML_ERROR_UNCLOSED_TOKEN:
+ return XML_L("unclosed token");
+ case XML_ERROR_PARTIAL_CHAR:
+ return XML_L("partial character");
+ case XML_ERROR_TAG_MISMATCH:
+ return XML_L("mismatched tag");
+ case XML_ERROR_DUPLICATE_ATTRIBUTE:
+ return XML_L("duplicate attribute");
+ case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
+ return XML_L("junk after document element");
+ case XML_ERROR_PARAM_ENTITY_REF:
+ return XML_L("illegal parameter entity reference");
+ case XML_ERROR_UNDEFINED_ENTITY:
+ return XML_L("undefined entity");
+ case XML_ERROR_RECURSIVE_ENTITY_REF:
+ return XML_L("recursive entity reference");
+ case XML_ERROR_ASYNC_ENTITY:
+ return XML_L("asynchronous entity");
+ case XML_ERROR_BAD_CHAR_REF:
+ return XML_L("reference to invalid character number");
+ case XML_ERROR_BINARY_ENTITY_REF:
+ return XML_L("reference to binary entity");
+ case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
+ return XML_L("reference to external entity in attribute");
+ case XML_ERROR_MISPLACED_XML_PI:
+ return XML_L("XML or text declaration not at start of entity");
+ case XML_ERROR_UNKNOWN_ENCODING:
+ return XML_L("unknown encoding");
+ case XML_ERROR_INCORRECT_ENCODING:
+ return XML_L("encoding specified in XML declaration is incorrect");
+ case XML_ERROR_UNCLOSED_CDATA_SECTION:
+ return XML_L("unclosed CDATA section");
+ case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
+ return XML_L("error in processing external entity reference");
+ case XML_ERROR_NOT_STANDALONE:
+ return XML_L("document is not standalone");
+ case XML_ERROR_UNEXPECTED_STATE:
+ return XML_L("unexpected parser state - please send a bug report");
+ case XML_ERROR_ENTITY_DECLARED_IN_PE:
+ return XML_L("entity declared in parameter entity");
+ case XML_ERROR_FEATURE_REQUIRES_XML_DTD:
+ return XML_L("requested feature requires XML_DTD support in Expat");
+ case XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING:
+ return XML_L("cannot change setting once parsing has begun");
+ /* Added in 1.95.7. */
+ case XML_ERROR_UNBOUND_PREFIX:
+ return XML_L("unbound prefix");
+ /* Added in 1.95.8. */
+ case XML_ERROR_UNDECLARING_PREFIX:
+ return XML_L("must not undeclare prefix");
+ case XML_ERROR_INCOMPLETE_PE:
+ return XML_L("incomplete markup in parameter entity");
+ case XML_ERROR_XML_DECL:
+ return XML_L("XML declaration not well-formed");
+ case XML_ERROR_TEXT_DECL:
+ return XML_L("text declaration not well-formed");
+ case XML_ERROR_PUBLICID:
+ return XML_L("illegal character(s) in public id");
+ case XML_ERROR_SUSPENDED:
+ return XML_L("parser suspended");
+ case XML_ERROR_NOT_SUSPENDED:
+ return XML_L("parser not suspended");
+ case XML_ERROR_ABORTED:
+ return XML_L("parsing aborted");
+ case XML_ERROR_FINISHED:
+ return XML_L("parsing finished");
+ case XML_ERROR_SUSPEND_PE:
+ return XML_L("cannot suspend in external parameter entity");
+ /* Added in 2.0.0. */
+ case XML_ERROR_RESERVED_PREFIX_XML:
+ return XML_L(
+ "reserved prefix (xml) must not be undeclared or bound to another namespace name");
+ case XML_ERROR_RESERVED_PREFIX_XMLNS:
+ return XML_L("reserved prefix (xmlns) must not be declared or undeclared");
+ case XML_ERROR_RESERVED_NAMESPACE_URI:
+ return XML_L(
+ "prefix must not be bound to one of the reserved namespace names");
+ /* Added in 2.2.5. */
+ case XML_ERROR_INVALID_ARGUMENT: /* Constant added in 2.2.1, already */
+ return XML_L("invalid argument");
+ }
return NULL;
}
-const XML_LChar * XMLCALL
+const XML_LChar *XMLCALL
XML_ExpatVersion(void) {
-
/* V1 is used to string-ize the version number. However, it would
string-ize the actual version macro *names* unless we get them
substituted before being passed to V1. CPP is defined to expand
@@ -1997,8 +2351,8 @@ XML_ExpatVersion(void) {
with the correct numerals. */
/* ### I'm assuming cpp is portable in this respect... */
-#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
-#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
+#define V1(a, b, c) XML_L(#a) XML_L(".") XML_L(#b) XML_L(".") XML_L(#c)
+#define V2(a, b, c) XML_L("expat_") V1(a, b, c)
return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
@@ -2007,8 +2361,7 @@ XML_ExpatVersion(void) {
}
XML_Expat_Version XMLCALL
-XML_ExpatVersionInfo(void)
-{
+XML_ExpatVersionInfo(void) {
XML_Expat_Version version;
version.major = XML_MAJOR_VERSION;
@@ -2018,41 +2371,39 @@ XML_ExpatVersionInfo(void)
return version;
}
-const XML_Feature * XMLCALL
-XML_GetFeatureList(void)
-{
- static const XML_Feature features[] = {
- {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
- sizeof(XML_Char)},
- {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
- sizeof(XML_LChar)},
+const XML_Feature *XMLCALL
+XML_GetFeatureList(void) {
+ static const XML_Feature features[]
+ = {{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+ sizeof(XML_Char)},
+ {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+ sizeof(XML_LChar)},
#ifdef XML_UNICODE
- {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+ {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
#endif
#ifdef XML_UNICODE_WCHAR_T
- {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+ {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
#endif
#ifdef XML_DTD
- {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+ {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
#endif
#ifdef XML_CONTEXT_BYTES
- {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
- XML_CONTEXT_BYTES},
+ {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+ XML_CONTEXT_BYTES},
#endif
#ifdef XML_MIN_SIZE
- {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+ {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
#endif
#ifdef XML_NS
- {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+ {XML_FEATURE_NS, XML_L("XML_NS"), 0},
#endif
#ifdef XML_LARGE_SIZE
- {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+ {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
#endif
#ifdef XML_ATTR_INFO
- {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+ {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
#endif
- {XML_FEATURE_END, NULL, 0}
- };
+ {XML_FEATURE_END, NULL, 0}};
return features;
}
@@ -2063,14 +2414,13 @@ XML_GetFeatureList(void)
permanent location, since the parse buffer is about to be discarded.
*/
static XML_Bool
-storeRawNames(XML_Parser parser)
-{
- TAG *tag = tagStack;
+storeRawNames(XML_Parser parser) {
+ TAG *tag = parser->m_tagStack;
while (tag) {
int bufSize;
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
char *rawNameBuf = tag->buf + nameLen;
- /* Stop if already stored. Since tagStack is a stack, we can stop
+ /* Stop if already stored. Since m_tagStack is a stack, we can stop
at the first entry that has already been copied; everything
below it in the stack is already been accounted for in a
previous call to this function.
@@ -2082,7 +2432,7 @@ storeRawNames(XML_Parser parser)
*/
bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
if (bufSize > tag->bufEnd - tag->buf) {
- char *temp = (char *)REALLOC(tag->buf, bufSize);
+ char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
if (temp == NULL)
return XML_FALSE;
/* if tag->name.str points to tag->buf (only when namespace
@@ -2094,8 +2444,8 @@ storeRawNames(XML_Parser parser)
then update it as well, since it will always point into tag->buf
*/
if (tag->name.localPart)
- tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
- (XML_Char *)tag->buf);
+ tag->name.localPart
+ = (XML_Char *)temp + (tag->name.localPart - (XML_Char *)tag->buf);
tag->buf = temp;
tag->bufEnd = temp + bufSize;
rawNameBuf = temp + nameLen;
@@ -2108,41 +2458,33 @@ storeRawNames(XML_Parser parser)
}
static enum XML_Error PTRCALL
-contentProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = doContent(parser, 0, encoding, start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+contentProcessor(XML_Parser parser, const char *start, const char *end,
+ const char **endPtr) {
+ enum XML_Error result
+ = doContent(parser, 0, parser->m_encoding, start, end, endPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer);
if (result == XML_ERROR_NONE) {
- if (!storeRawNames(parser))
+ if (! storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
}
return result;
}
static enum XML_Error PTRCALL
-externalEntityInitProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
+externalEntityInitProcessor(XML_Parser parser, const char *start,
+ const char *end, const char **endPtr) {
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
- processor = externalEntityInitProcessor2;
+ parser->m_processor = externalEntityInitProcessor2;
return externalEntityInitProcessor2(parser, start, end, endPtr);
}
static enum XML_Error PTRCALL
-externalEntityInitProcessor2(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
+externalEntityInitProcessor2(XML_Parser parser, const char *start,
+ const char *end, const char **endPtr) {
const char *next = start; /* XmlContentTok doesn't always set the last arg */
- int tok = XmlContentTok(encoding, start, end, &next);
+ int tok = XmlContentTok(parser->m_encoding, start, end, &next);
switch (tok) {
case XML_TOK_BOM:
/* If we are at the end of the buffer, this would cause the next stage,
@@ -2150,115 +2492,102 @@ externalEntityInitProcessor2(XML_Parser parser,
doContent (by detecting XML_TOK_NONE) without processing any xml text
declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
*/
- if (next == end && !ps_finalBuffer) {
+ if (next == end && ! parser->m_parsingStatus.finalBuffer) {
*endPtr = next;
return XML_ERROR_NONE;
}
start = next;
break;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (! parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
- eventPtr = start;
+ parser->m_eventPtr = start;
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (! parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
- eventPtr = start;
+ parser->m_eventPtr = start;
return XML_ERROR_PARTIAL_CHAR;
}
- processor = externalEntityInitProcessor3;
+ parser->m_processor = externalEntityInitProcessor3;
return externalEntityInitProcessor3(parser, start, end, endPtr);
}
static enum XML_Error PTRCALL
-externalEntityInitProcessor3(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
+externalEntityInitProcessor3(XML_Parser parser, const char *start,
+ const char *end, const char **endPtr) {
int tok;
const char *next = start; /* XmlContentTok doesn't always set the last arg */
- eventPtr = start;
- tok = XmlContentTok(encoding, start, end, &next);
- eventEndPtr = next;
+ parser->m_eventPtr = start;
+ tok = XmlContentTok(parser->m_encoding, start, end, &next);
+ parser->m_eventEndPtr = next;
switch (tok) {
- case XML_TOK_XML_DECL:
- {
- enum XML_Error result;
- result = processXmlDecl(parser, 1, start, next);
- if (result != XML_ERROR_NONE)
- return result;
- switch (ps_parsing) {
- case XML_SUSPENDED:
- *endPtr = next;
- return XML_ERROR_NONE;
- case XML_FINISHED:
- return XML_ERROR_ABORTED;
- default:
- start = next;
- }
+ case XML_TOK_XML_DECL: {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 1, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ switch (parser->m_parsingStatus.parsing) {
+ case XML_SUSPENDED:
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ start = next;
}
- break;
+ } break;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (! parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (! parser->m_parsingStatus.finalBuffer) {
*endPtr = start;
return XML_ERROR_NONE;
}
return XML_ERROR_PARTIAL_CHAR;
}
- processor = externalEntityContentProcessor;
- tagLevel = 1;
+ parser->m_processor = externalEntityContentProcessor;
+ parser->m_tagLevel = 1;
return externalEntityContentProcessor(parser, start, end, endPtr);
}
static enum XML_Error PTRCALL
-externalEntityContentProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = doContent(parser, 1, encoding, start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+externalEntityContentProcessor(XML_Parser parser, const char *start,
+ const char *end, const char **endPtr) {
+ enum XML_Error result
+ = doContent(parser, 1, parser->m_encoding, start, end, endPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer);
if (result == XML_ERROR_NONE) {
- if (!storeRawNames(parser))
+ if (! storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
}
return result;
}
static enum XML_Error
-doContent(XML_Parser parser,
- int startTagLevel,
- const ENCODING *enc,
- const char *s,
- const char *end,
- const char **nextPtr,
- XML_Bool haveMore)
-{
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+ const char *s, const char *end, const char **nextPtr,
+ XML_Bool haveMore) {
/* save one level of indirection */
- DTD * const dtd = _dtd;
+ DTD *const dtd = parser->m_dtd;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
+ } else {
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
*eventPP = s;
@@ -2273,18 +2602,17 @@ doContent(XML_Parser parser,
return XML_ERROR_NONE;
}
*eventEndPP = end;
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
- }
- else if (defaultHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
XML_SUSPENDED, XML_FINISHED?
*/
if (startTagLevel == 0)
return XML_ERROR_NO_ELEMENTS;
- if (tagLevel != startTagLevel)
+ if (parser->m_tagLevel != startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
*nextPtr = end;
return XML_ERROR_NONE;
@@ -2294,7 +2622,7 @@ doContent(XML_Parser parser,
return XML_ERROR_NONE;
}
if (startTagLevel > 0) {
- if (tagLevel != startTagLevel)
+ if (parser->m_tagLevel != startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
*nextPtr = s;
return XML_ERROR_NONE;
@@ -2315,321 +2643,314 @@ doContent(XML_Parser parser,
return XML_ERROR_NONE;
}
return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_ENTITY_REF:
- {
- const XML_Char *name;
- ENTITY *entity;
- XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (ch) {
- if (characterDataHandler)
- characterDataHandler(handlerArg, &ch, 1);
- else if (defaultHandler)
+ case XML_TOK_ENTITY_REF: {
+ const XML_Char *name;
+ ENTITY *entity;
+ XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+ enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
+ if (ch) {
+ if (parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
+ else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (! name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity or default handler.
+ */
+ if (! dtd->hasParamEntityRefs || dtd->standalone) {
+ if (! entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (! entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ } else if (! entity) {
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
+ else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->notation)
+ return XML_ERROR_BINARY_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ if (! parser->m_defaultExpandInternalEntities) {
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name,
+ 0);
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
- name = poolStoreString(&dtd->pool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
+ result = processInternalEntity(parser, entity, XML_FALSE);
+ if (result != XML_ERROR_NONE)
+ return result;
+ } else if (parser->m_externalEntityRefHandler) {
+ const XML_Char *context;
+ entity->open = XML_TRUE;
+ context = getContext(parser);
+ entity->open = XML_FALSE;
+ if (! context)
return XML_ERROR_NO_MEMORY;
- entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
- poolDiscard(&dtd->pool);
- /* First, determine if a check for an existing declaration is needed;
- if yes, check that the entity exists, and that it is internal,
- otherwise call the skipped entity or default handler.
- */
- if (!dtd->hasParamEntityRefs || dtd->standalone) {
- if (!entity)
- return XML_ERROR_UNDEFINED_ENTITY;
- else if (!entity->is_internal)
- return XML_ERROR_ENTITY_DECLARED_IN_PE;
- }
- else if (!entity) {
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- }
- if (entity->open)
- return XML_ERROR_RECURSIVE_ENTITY_REF;
- if (entity->notation)
- return XML_ERROR_BINARY_ENTITY_REF;
- if (entity->textPtr) {
- enum XML_Error result;
- if (!defaultExpandInternalEntities) {
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, entity->name, 0);
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- }
- result = processInternalEntity(parser, entity, XML_FALSE);
- if (result != XML_ERROR_NONE)
- return result;
- }
- else if (externalEntityRefHandler) {
- const XML_Char *context;
- entity->open = XML_TRUE;
- context = getContext(parser);
- entity->open = XML_FALSE;
- if (!context)
- return XML_ERROR_NO_MEMORY;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- context,
- entity->base,
- entity->systemId,
- entity->publicId))
- return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
- poolDiscard(&tempPool);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- }
+ if (! parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, context, entity->base,
+ entity->systemId, entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ poolDiscard(&parser->m_tempPool);
+ } else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
case XML_TOK_START_TAG_NO_ATTS:
/* fall through */
- case XML_TOK_START_TAG_WITH_ATTS:
- {
- TAG *tag;
- enum XML_Error result;
- XML_Char *toPtr;
- if (freeTagList) {
- tag = freeTagList;
- freeTagList = freeTagList->parent;
+ case XML_TOK_START_TAG_WITH_ATTS: {
+ TAG *tag;
+ enum XML_Error result;
+ XML_Char *toPtr;
+ if (parser->m_freeTagList) {
+ tag = parser->m_freeTagList;
+ parser->m_freeTagList = parser->m_freeTagList->parent;
+ } else {
+ tag = (TAG *)MALLOC(parser, sizeof(TAG));
+ if (! tag)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = (char *)MALLOC(parser, INIT_TAG_BUF_SIZE);
+ if (! tag->buf) {
+ FREE(parser, tag);
+ return XML_ERROR_NO_MEMORY;
}
- else {
- tag = (TAG *)MALLOC(sizeof(TAG));
- if (!tag)
- return XML_ERROR_NO_MEMORY;
- tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
- if (!tag->buf) {
- FREE(tag);
- return XML_ERROR_NO_MEMORY;
+ tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+ }
+ tag->bindings = NULL;
+ tag->parent = parser->m_tagStack;
+ parser->m_tagStack = tag;
+ tag->name.localPart = NULL;
+ tag->name.prefix = NULL;
+ tag->rawName = s + enc->minBytesPerChar;
+ tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+ ++parser->m_tagLevel;
+ {
+ const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+ const char *fromPtr = tag->rawName;
+ toPtr = (XML_Char *)tag->buf;
+ for (;;) {
+ int bufSize;
+ int convLen;
+ const enum XML_Convert_Result convert_res
+ = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr,
+ (ICHAR *)tag->bufEnd - 1);
+ convLen = (int)(toPtr - (XML_Char *)tag->buf);
+ if ((fromPtr >= rawNameEnd)
+ || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
+ tag->name.strLen = convLen;
+ break;
}
- tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
- }
- tag->bindings = NULL;
- tag->parent = tagStack;
- tagStack = tag;
- tag->name.localPart = NULL;
- tag->name.prefix = NULL;
- tag->rawName = s + enc->minBytesPerChar;
- tag->rawNameLength = XmlNameLength(enc, tag->rawName);
- ++tagLevel;
- {
- const char *rawNameEnd = tag->rawName + tag->rawNameLength;
- const char *fromPtr = tag->rawName;
- toPtr = (XML_Char *)tag->buf;
- for (;;) {
- int bufSize;
- int convLen;
- XmlConvert(enc,
- &fromPtr, rawNameEnd,
- (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
- convLen = (int)(toPtr - (XML_Char *)tag->buf);
- if (fromPtr == rawNameEnd) {
- tag->name.strLen = convLen;
- break;
- }
- bufSize = (int)(tag->bufEnd - tag->buf) << 1;
- {
- char *temp = (char *)REALLOC(tag->buf, bufSize);
- if (temp == NULL)
- return XML_ERROR_NO_MEMORY;
- tag->buf = temp;
- tag->bufEnd = temp + bufSize;
- toPtr = (XML_Char *)temp + convLen;
- }
+ bufSize = (int)(tag->bufEnd - tag->buf) << 1;
+ {
+ char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ toPtr = (XML_Char *)temp + convLen;
}
}
- tag->name.str = (XML_Char *)tag->buf;
- *toPtr = XML_T('\0');
- result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
- if (result)
- return result;
- if (startElementHandler)
- startElementHandler(handlerArg, tag->name.str,
- (const XML_Char **)atts);
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- poolClear(&tempPool);
- break;
}
+ tag->name.str = (XML_Char *)tag->buf;
+ *toPtr = XML_T('\0');
+ result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+ if (result)
+ return result;
+ if (parser->m_startElementHandler)
+ parser->m_startElementHandler(parser->m_handlerArg, tag->name.str,
+ (const XML_Char **)parser->m_atts);
+ else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&parser->m_tempPool);
+ break;
+ }
case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
/* fall through */
- case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
- {
- const char *rawName = s + enc->minBytesPerChar;
- enum XML_Error result;
- BINDING *bindings = NULL;
- XML_Bool noElmHandlers = XML_TRUE;
- TAG_NAME name;
- name.str = poolStoreString(&tempPool, enc, rawName,
- rawName + XmlNameLength(enc, rawName));
- if (!name.str)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- result = storeAtts(parser, enc, s, &name, &bindings);
- if (result)
- return result;
- poolFinish(&tempPool);
- if (startElementHandler) {
- startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
- noElmHandlers = XML_FALSE;
- }
- if (endElementHandler) {
- if (startElementHandler)
- *eventPP = *eventEndPP;
- endElementHandler(handlerArg, name.str);
- noElmHandlers = XML_FALSE;
- }
- if (noElmHandlers && defaultHandler)
- reportDefault(parser, enc, s, next);
- poolClear(&tempPool);
- while (bindings) {
- BINDING *b = bindings;
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
- bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
- b->prefix->binding = b->prevPrefixBinding;
- }
+ case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: {
+ const char *rawName = s + enc->minBytesPerChar;
+ enum XML_Error result;
+ BINDING *bindings = NULL;
+ XML_Bool noElmHandlers = XML_TRUE;
+ TAG_NAME name;
+ name.str = poolStoreString(&parser->m_tempPool, enc, rawName,
+ rawName + XmlNameLength(enc, rawName));
+ if (! name.str)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&parser->m_tempPool);
+ result = storeAtts(parser, enc, s, &name, &bindings);
+ if (result != XML_ERROR_NONE) {
+ freeBindings(parser, bindings);
+ return result;
+ }
+ poolFinish(&parser->m_tempPool);
+ if (parser->m_startElementHandler) {
+ parser->m_startElementHandler(parser->m_handlerArg, name.str,
+ (const XML_Char **)parser->m_atts);
+ noElmHandlers = XML_FALSE;
+ }
+ if (parser->m_endElementHandler) {
+ if (parser->m_startElementHandler)
+ *eventPP = *eventEndPP;
+ parser->m_endElementHandler(parser->m_handlerArg, name.str);
+ noElmHandlers = XML_FALSE;
+ }
+ if (noElmHandlers && parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&parser->m_tempPool);
+ freeBindings(parser, bindings);
+ }
+ if ((parser->m_tagLevel == 0)
+ && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
+ if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
+ parser->m_processor = epilogProcessor;
+ else
+ return epilogProcessor(parser, next, end, nextPtr);
}
- if (tagLevel == 0)
- return epilogProcessor(parser, next, end, nextPtr);
break;
case XML_TOK_END_TAG:
- if (tagLevel == startTagLevel)
+ if (parser->m_tagLevel == startTagLevel)
return XML_ERROR_ASYNC_ENTITY;
else {
int len;
const char *rawName;
- TAG *tag = tagStack;
- tagStack = tag->parent;
- tag->parent = freeTagList;
- freeTagList = tag;
- rawName = s + enc->minBytesPerChar*2;
+ TAG *tag = parser->m_tagStack;
+ parser->m_tagStack = tag->parent;
+ tag->parent = parser->m_freeTagList;
+ parser->m_freeTagList = tag;
+ rawName = s + enc->minBytesPerChar * 2;
len = XmlNameLength(enc, rawName);
if (len != tag->rawNameLength
|| memcmp(tag->rawName, rawName, len) != 0) {
*eventPP = rawName;
return XML_ERROR_TAG_MISMATCH;
}
- --tagLevel;
- if (endElementHandler) {
+ --parser->m_tagLevel;
+ if (parser->m_endElementHandler) {
const XML_Char *localPart;
const XML_Char *prefix;
XML_Char *uri;
localPart = tag->name.localPart;
- if (ns && localPart) {
+ if (parser->m_ns && localPart) {
/* localPart and prefix may have been overwritten in
tag->name.str, since this points to the binding->uri
buffer which gets re-used; so we have to add them again
*/
uri = (XML_Char *)tag->name.str + tag->name.uriLen;
/* don't need to check for space - already done in storeAtts() */
- while (*localPart) *uri++ = *localPart++;
+ while (*localPart)
+ *uri++ = *localPart++;
prefix = (XML_Char *)tag->name.prefix;
- if (ns_triplets && prefix) {
- *uri++ = namespaceSeparator;
- while (*prefix) *uri++ = *prefix++;
- }
+ if (parser->m_ns_triplets && prefix) {
+ *uri++ = parser->m_namespaceSeparator;
+ while (*prefix)
+ *uri++ = *prefix++;
+ }
*uri = XML_T('\0');
}
- endElementHandler(handlerArg, tag->name.str);
- }
- else if (defaultHandler)
+ parser->m_endElementHandler(parser->m_handlerArg, tag->name.str);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
while (tag->bindings) {
BINDING *b = tag->bindings;
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ if (parser->m_endNamespaceDeclHandler)
+ parser->m_endNamespaceDeclHandler(parser->m_handlerArg,
+ b->prefix->name);
tag->bindings = tag->bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
b->prefix->binding = b->prevPrefixBinding;
}
- if (tagLevel == 0)
- return epilogProcessor(parser, next, end, nextPtr);
- }
- break;
- case XML_TOK_CHAR_REF:
- {
- int n = XmlCharRefNumber(enc, s);
- if (n < 0)
- return XML_ERROR_BAD_CHAR_REF;
- if (characterDataHandler) {
- XML_Char buf[XML_ENCODE_MAX];
- characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ if ((parser->m_tagLevel == 0)
+ && (parser->m_parsingStatus.parsing != XML_FINISHED)) {
+ if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
+ parser->m_processor = epilogProcessor;
+ else
+ return epilogProcessor(parser, next, end, nextPtr);
}
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
}
break;
+ case XML_TOK_CHAR_REF: {
+ int n = XmlCharRefNumber(enc, s);
+ if (n < 0)
+ return XML_ERROR_BAD_CHAR_REF;
+ if (parser->m_characterDataHandler) {
+ XML_Char buf[XML_ENCODE_MAX];
+ parser->m_characterDataHandler(parser->m_handlerArg, buf,
+ XmlEncode(n, (ICHAR *)buf));
+ } else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ } break;
case XML_TOK_XML_DECL:
return XML_ERROR_MISPLACED_XML_PI;
case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
- }
- else if (defaultHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
- case XML_TOK_CDATA_SECT_OPEN:
- {
- enum XML_Error result;
- if (startCdataSectionHandler)
- startCdataSectionHandler(handlerArg);
-#if 0
- /* Suppose you doing a transformation on a document that involves
- changing only the character data. You set up a defaultHandler
- and a characterDataHandler. The defaultHandler simply copies
- characters through. The characterDataHandler does the
- transformation and writes the characters out escaping them as
- necessary. This case will fail to work if we leave out the
- following two lines (because & and < inside CDATA sections will
- be incorrectly escaped).
-
- However, now we have a start/endCdataSectionHandler, so it seems
- easier to let the user deal with this.
- */
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
-#endif
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
- if (result != XML_ERROR_NONE)
- return result;
- else if (!next) {
- processor = cdataSectionProcessor;
- return result;
- }
+ case XML_TOK_CDATA_SECT_OPEN: {
+ enum XML_Error result;
+ if (parser->m_startCdataSectionHandler)
+ parser->m_startCdataSectionHandler(parser->m_handlerArg);
+ /* BEGIN disabled code */
+ /* Suppose you doing a transformation on a document that involves
+ changing only the character data. You set up a defaultHandler
+ and a characterDataHandler. The defaultHandler simply copies
+ characters through. The characterDataHandler does the
+ transformation and writes the characters out escaping them as
+ necessary. This case will fail to work if we leave out the
+ following two lines (because & and < inside CDATA sections will
+ be incorrectly escaped).
+
+ However, now we have a start/endCdataSectionHandler, so it seems
+ easier to let the user deal with this.
+ */
+ else if (0 && parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ 0);
+ /* END disabled code */
+ else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (! next) {
+ parser->m_processor = cdataSectionProcessor;
+ return result;
}
- break;
+ } break;
case XML_TOK_TRAILING_RSQB:
if (haveMore) {
*nextPtr = s;
return XML_ERROR_NONE;
}
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
if (MUST_CONVERT(enc, s)) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
- characterDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
- }
- else
- characterDataHandler(handlerArg,
- (XML_Char *)s,
- (int)((XML_Char *)end - (XML_Char *)s));
- }
- else if (defaultHandler)
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
+ parser->m_characterDataHandler(
+ parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
+ } else
+ parser->m_characterDataHandler(
+ parser->m_handlerArg, (XML_Char *)s,
+ (int)((XML_Char *)end - (XML_Char *)s));
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
XML_SUSPENDED, XML_FINISHED?
@@ -2638,63 +2959,90 @@ doContent(XML_Parser parser,
*eventPP = end;
return XML_ERROR_NO_ELEMENTS;
}
- if (tagLevel != startTagLevel) {
+ if (parser->m_tagLevel != startTagLevel) {
*eventPP = end;
return XML_ERROR_ASYNC_ENTITY;
}
*nextPtr = end;
return XML_ERROR_NONE;
- case XML_TOK_DATA_CHARS:
- {
- XML_CharacterDataHandler charDataHandler = characterDataHandler;
- if (charDataHandler) {
- if (MUST_CONVERT(enc, s)) {
- for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
- *eventEndPP = s;
- charDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
- if (s == next)
- break;
- *eventPP = s;
- }
+ case XML_TOK_DATA_CHARS: {
+ XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
+ if (charDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(
+ enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
+ *eventEndPP = s;
+ charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
+ if ((convert_res == XML_CONVERT_COMPLETED)
+ || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+ break;
+ *eventPP = s;
}
- else
- charDataHandler(handlerArg,
- (XML_Char *)s,
- (int)((XML_Char *)next - (XML_Char *)s));
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- }
- break;
+ } else
+ charDataHandler(parser->m_handlerArg, (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ } else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ } break;
case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, enc, s, next))
+ if (! reportProcessingInstruction(parser, enc, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_COMMENT:
- if (!reportComment(parser, enc, s, next))
+ if (! reportComment(parser, enc, s, next))
return XML_ERROR_NO_MEMORY;
break;
default:
- if (defaultHandler)
+ /* All of the tokens produced by XmlContentTok() have their own
+ * explicit cases, so this default is not strictly necessary.
+ * However it is a useful safety net, so we retain the code and
+ * simply exclude it from the coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
+ /* LCOV_EXCL_STOP */
}
*eventPP = s = next;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
- default: ;
+ default:;
}
}
/* not reached */
}
+/* This function does not call free() on the allocated memory, merely
+ * moving it to the parser's m_freeBindingList where it can be freed or
+ * reused as appropriate.
+ */
+static void
+freeBindings(XML_Parser parser, BINDING *bindings) {
+ while (bindings) {
+ BINDING *b = bindings;
+
+ /* m_startNamespaceDeclHandler will have been called for this
+ * binding in addBindings(), so call the end handler now.
+ */
+ if (parser->m_endNamespaceDeclHandler)
+ parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
+
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = parser->m_freeBindingList;
+ parser->m_freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+}
+
/* Precondition: all arguments must be non-NULL;
Purpose:
- normalize attributes
@@ -2706,14 +3054,12 @@ doContent(XML_Parser parser,
- generate namespace aware element name (URI, prefix)
*/
static enum XML_Error
-storeAtts(XML_Parser parser, const ENCODING *enc,
- const char *attStr, TAG_NAME *tagNamePtr,
- BINDING **bindingsPtr)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr,
+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
ELEMENT_TYPE *elementType;
int nDefaultAtts;
- const XML_Char **appAtts; /* the attribute list for the application */
+ const XML_Char **appAtts; /* the attribute list for the application */
int attIndex = 0;
int prefixLen;
int i;
@@ -2724,75 +3070,84 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
const XML_Char *localPart;
/* lookup the element type name */
- elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
- if (!elementType) {
+ elementType
+ = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str, 0);
+ if (! elementType) {
const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
- if (!name)
+ if (! name)
return XML_ERROR_NO_MEMORY;
elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
sizeof(ELEMENT_TYPE));
- if (!elementType)
+ if (! elementType)
return XML_ERROR_NO_MEMORY;
- if (ns && !setElementTypePrefix(parser, elementType))
+ if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
return XML_ERROR_NO_MEMORY;
}
nDefaultAtts = elementType->nDefaultAtts;
/* get the attributes from the tokenizer */
- n = XmlGetAttributes(enc, attStr, attsSize, atts);
- if (n + nDefaultAtts > attsSize) {
- int oldAttsSize = attsSize;
+ n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
+ if (n + nDefaultAtts > parser->m_attsSize) {
+ int oldAttsSize = parser->m_attsSize;
ATTRIBUTE *temp;
#ifdef XML_ATTR_INFO
XML_AttrInfo *temp2;
#endif
- attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
- temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
- if (temp == NULL)
+ parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ temp = (ATTRIBUTE *)REALLOC(parser, (void *)parser->m_atts,
+ parser->m_attsSize * sizeof(ATTRIBUTE));
+ if (temp == NULL) {
+ parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
- atts = temp;
+ }
+ parser->m_atts = temp;
#ifdef XML_ATTR_INFO
- temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
- if (temp2 == NULL)
+ temp2 = (XML_AttrInfo *)REALLOC(parser, (void *)parser->m_attInfo,
+ parser->m_attsSize * sizeof(XML_AttrInfo));
+ if (temp2 == NULL) {
+ parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
- attInfo = temp2;
+ }
+ parser->m_attInfo = temp2;
#endif
if (n > oldAttsSize)
- XmlGetAttributes(enc, attStr, n, atts);
+ XmlGetAttributes(enc, attStr, n, parser->m_atts);
}
- appAtts = (const XML_Char **)atts;
+ appAtts = (const XML_Char **)parser->m_atts;
for (i = 0; i < n; i++) {
- ATTRIBUTE *currAtt = &atts[i];
+ ATTRIBUTE *currAtt = &parser->m_atts[i];
#ifdef XML_ATTR_INFO
- XML_AttrInfo *currAttInfo = &attInfo[i];
+ XML_AttrInfo *currAttInfo = &parser->m_attInfo[i];
#endif
/* add the name and value to the attribute list */
- ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
- currAtt->name
- + XmlNameLength(enc, currAtt->name));
- if (!attId)
+ ATTRIBUTE_ID *attId
+ = getAttributeId(parser, enc, currAtt->name,
+ currAtt->name + XmlNameLength(enc, currAtt->name));
+ if (! attId)
return XML_ERROR_NO_MEMORY;
#ifdef XML_ATTR_INFO
- currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
- currAttInfo->nameEnd = currAttInfo->nameStart +
- XmlNameLength(enc, currAtt->name);
- currAttInfo->valueStart = parseEndByteIndex -
- (parseEndPtr - currAtt->valuePtr);
- currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+ currAttInfo->nameStart
+ = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->name);
+ currAttInfo->nameEnd
+ = currAttInfo->nameStart + XmlNameLength(enc, currAtt->name);
+ currAttInfo->valueStart = parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - currAtt->valuePtr);
+ currAttInfo->valueEnd = parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - currAtt->valueEnd);
#endif
/* Detect duplicate attributes by their QNames. This does not work when
namespace processing is turned on and different prefixes for the same
namespace are used. For this case we have a check further down.
*/
if ((attId->name)[-1]) {
- if (enc == encoding)
- eventPtr = atts[i].name;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = parser->m_atts[i].name;
return XML_ERROR_DUPLICATE_ATTRIBUTE;
}
(attId->name)[-1] = 1;
appAtts[attIndex++] = attId->name;
- if (!atts[i].normalized) {
+ if (! parser->m_atts[i].normalized) {
enum XML_Error result;
XML_Bool isCdata = XML_TRUE;
@@ -2808,21 +3163,21 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
}
/* normalize the attribute value */
- result = storeAttributeValue(parser, enc, isCdata,
- atts[i].valuePtr, atts[i].valueEnd,
- &tempPool);
+ result = storeAttributeValue(
+ parser, enc, isCdata, parser->m_atts[i].valuePtr,
+ parser->m_atts[i].valueEnd, &parser->m_tempPool);
if (result)
return result;
- appAtts[attIndex] = poolStart(&tempPool);
- poolFinish(&tempPool);
- }
- else {
+ appAtts[attIndex] = poolStart(&parser->m_tempPool);
+ poolFinish(&parser->m_tempPool);
+ } else {
/* the value did not need normalizing */
- appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
- atts[i].valueEnd);
+ appAtts[attIndex] = poolStoreString(&parser->m_tempPool, enc,
+ parser->m_atts[i].valuePtr,
+ parser->m_atts[i].valueEnd);
if (appAtts[attIndex] == 0)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
}
/* handle prefixed attribute names */
if (attId->prefix) {
@@ -2833,49 +3188,44 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
if (result)
return result;
--attIndex;
- }
- else {
+ } else {
/* deal with other prefixed names later */
attIndex++;
nPrefixes++;
(attId->name)[-1] = 2;
}
- }
- else
+ } else
attIndex++;
}
/* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
- nSpecifiedAtts = attIndex;
+ parser->m_nSpecifiedAtts = attIndex;
if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
for (i = 0; i < attIndex; i += 2)
if (appAtts[i] == elementType->idAtt->name) {
- idAttIndex = i;
+ parser->m_idAttIndex = i;
break;
}
- }
- else
- idAttIndex = -1;
+ } else
+ parser->m_idAttIndex = -1;
/* do attribute defaulting */
for (i = 0; i < nDefaultAtts; i++) {
const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
- if (!(da->id->name)[-1] && da->value) {
+ if (! (da->id->name)[-1] && da->value) {
if (da->id->prefix) {
if (da->id->xmlns) {
enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
da->value, bindingsPtr);
if (result)
return result;
- }
- else {
+ } else {
(da->id->name)[-1] = 2;
nPrefixes++;
appAtts[attIndex++] = da->id->name;
appAtts[attIndex++] = da->value;
}
- }
- else {
+ } else {
(da->id->name)[-1] = 1;
appAtts[attIndex++] = da->id->name;
appAtts[attIndex++] = da->value;
@@ -2888,110 +3238,142 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
and clear flags that say whether attributes were specified */
i = 0;
if (nPrefixes) {
- int j; /* hash table index */
- unsigned long version = nsAttsVersion;
- int nsAttsSize = (int)1 << nsAttsPower;
+ int j; /* hash table index */
+ unsigned long version = parser->m_nsAttsVersion;
+ int nsAttsSize = (int)1 << parser->m_nsAttsPower;
+ unsigned char oldNsAttsPower = parser->m_nsAttsPower;
/* size of hash table must be at least 2 * (# of prefixed attributes) */
- if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
+ if ((nPrefixes << 1)
+ >> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
NS_ATT *temp;
/* hash table size must also be a power of 2 and >= 8 */
- while (nPrefixes >> nsAttsPower++);
- if (nsAttsPower < 3)
- nsAttsPower = 3;
- nsAttsSize = (int)1 << nsAttsPower;
- temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
- if (!temp)
+ while (nPrefixes >> parser->m_nsAttsPower++)
+ ;
+ if (parser->m_nsAttsPower < 3)
+ parser->m_nsAttsPower = 3;
+ nsAttsSize = (int)1 << parser->m_nsAttsPower;
+ temp = (NS_ATT *)REALLOC(parser, parser->m_nsAtts,
+ nsAttsSize * sizeof(NS_ATT));
+ if (! temp) {
+ /* Restore actual size of memory in m_nsAtts */
+ parser->m_nsAttsPower = oldNsAttsPower;
return XML_ERROR_NO_MEMORY;
- nsAtts = temp;
- version = 0; /* force re-initialization of nsAtts hash table */
+ }
+ parser->m_nsAtts = temp;
+ version = 0; /* force re-initialization of m_nsAtts hash table */
}
- /* using a version flag saves us from initializing nsAtts every time */
- if (!version) { /* initialize version flags when version wraps around */
+ /* using a version flag saves us from initializing m_nsAtts every time */
+ if (! version) { /* initialize version flags when version wraps around */
version = INIT_ATTS_VERSION;
- for (j = nsAttsSize; j != 0; )
- nsAtts[--j].version = version;
+ for (j = nsAttsSize; j != 0;)
+ parser->m_nsAtts[--j].version = version;
}
- nsAttsVersion = --version;
+ parser->m_nsAttsVersion = --version;
/* expand prefixed names and check for duplicates */
for (; i < attIndex; i += 2) {
const XML_Char *s = appAtts[i];
- if (s[-1] == 2) { /* prefixed */
+ if (s[-1] == 2) { /* prefixed */
ATTRIBUTE_ID *id;
const BINDING *b;
- unsigned long uriHash = hash_secret_salt;
- ((XML_Char *)s)[-1] = 0; /* clear flag */
+ unsigned long uriHash;
+ struct siphash sip_state;
+ struct sipkey sip_key;
+
+ copy_salt_to_sipkey(parser, &sip_key);
+ sip24_init(&sip_state, &sip_key);
+
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
- if (!id || !id->prefix)
- return XML_ERROR_NO_MEMORY;
+ if (! id || ! id->prefix) {
+ /* This code is walking through the appAtts array, dealing
+ * with (in this case) a prefixed attribute name. To be in
+ * the array, the attribute must have already been bound, so
+ * has to have passed through the hash table lookup once
+ * already. That implies that an entry for it already
+ * exists, so the lookup above will return a pointer to
+ * already allocated memory. There is no opportunaity for
+ * the allocator to fail, so the condition above cannot be
+ * fulfilled.
+ *
+ * Since it is difficult to be certain that the above
+ * analysis is complete, we retain the test and merely
+ * remove the code from coverage tests.
+ */
+ return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
+ }
b = id->prefix->binding;
- if (!b)
+ if (! b)
return XML_ERROR_UNBOUND_PREFIX;
- /* as we expand the name we also calculate its hash value */
for (j = 0; j < b->uriLen; j++) {
const XML_Char c = b->uri[j];
- if (!poolAppendChar(&tempPool, c))
+ if (! poolAppendChar(&parser->m_tempPool, c))
return XML_ERROR_NO_MEMORY;
- uriHash = CHAR_HASH(uriHash, c);
}
+
+ sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
+
while (*s++ != XML_T(ASCII_COLON))
;
- do { /* copies null terminator */
- const XML_Char c = *s;
- if (!poolAppendChar(&tempPool, *s))
+
+ sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
+
+ do { /* copies null terminator */
+ if (! poolAppendChar(&parser->m_tempPool, *s))
return XML_ERROR_NO_MEMORY;
- uriHash = CHAR_HASH(uriHash, c);
} while (*s++);
+ uriHash = (unsigned long)sip24_final(&sip_state);
+
{ /* Check hash table for duplicate of expanded name (uriName).
Derived from code in lookup(parser, HASH_TABLE *table, ...).
*/
unsigned char step = 0;
unsigned long mask = nsAttsSize - 1;
- j = uriHash & mask; /* index into hash table */
- while (nsAtts[j].version == version) {
+ j = uriHash & mask; /* index into hash table */
+ while (parser->m_nsAtts[j].version == version) {
/* for speed we compare stored hash values first */
- if (uriHash == nsAtts[j].hash) {
- const XML_Char *s1 = poolStart(&tempPool);
- const XML_Char *s2 = nsAtts[j].uriName;
+ if (uriHash == parser->m_nsAtts[j].hash) {
+ const XML_Char *s1 = poolStart(&parser->m_tempPool);
+ const XML_Char *s2 = parser->m_nsAtts[j].uriName;
/* s1 is null terminated, but not s2 */
- for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
+ for (; *s1 == *s2 && *s1 != 0; s1++, s2++)
+ ;
if (*s1 == 0)
return XML_ERROR_DUPLICATE_ATTRIBUTE;
}
- if (!step)
- step = PROBE_STEP(uriHash, mask, nsAttsPower);
+ if (! step)
+ step = PROBE_STEP(uriHash, mask, parser->m_nsAttsPower);
j < step ? (j += nsAttsSize - step) : (j -= step);
}
}
- if (ns_triplets) { /* append namespace separator and prefix */
- tempPool.ptr[-1] = namespaceSeparator;
+ if (parser->m_ns_triplets) { /* append namespace separator and prefix */
+ parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator;
s = b->prefix->name;
do {
- if (!poolAppendChar(&tempPool, *s))
+ if (! poolAppendChar(&parser->m_tempPool, *s))
return XML_ERROR_NO_MEMORY;
} while (*s++);
}
/* store expanded name in attribute list */
- s = poolStart(&tempPool);
- poolFinish(&tempPool);
+ s = poolStart(&parser->m_tempPool);
+ poolFinish(&parser->m_tempPool);
appAtts[i] = s;
/* fill empty slot with new version, uriName and hash value */
- nsAtts[j].version = version;
- nsAtts[j].hash = uriHash;
- nsAtts[j].uriName = s;
+ parser->m_nsAtts[j].version = version;
+ parser->m_nsAtts[j].hash = uriHash;
+ parser->m_nsAtts[j].uriName = s;
- if (!--nPrefixes) {
+ if (! --nPrefixes) {
i += 2;
break;
}
- }
- else /* not prefixed */
- ((XML_Char *)s)[-1] = 0; /* clear flag */
+ } else /* not prefixed */
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
}
}
/* clear flags for the remaining attributes */
@@ -3000,56 +3382,54 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
binding->attId->name[-1] = 0;
- if (!ns)
+ if (! parser->m_ns)
return XML_ERROR_NONE;
/* expand the element type name */
if (elementType->prefix) {
binding = elementType->prefix->binding;
- if (!binding)
+ if (! binding)
return XML_ERROR_UNBOUND_PREFIX;
localPart = tagNamePtr->str;
while (*localPart++ != XML_T(ASCII_COLON))
;
- }
- else if (dtd->defaultPrefix.binding) {
+ } else if (dtd->defaultPrefix.binding) {
binding = dtd->defaultPrefix.binding;
localPart = tagNamePtr->str;
- }
- else
+ } else
return XML_ERROR_NONE;
prefixLen = 0;
- if (ns_triplets && binding->prefix->name) {
+ if (parser->m_ns_triplets && binding->prefix->name) {
for (; binding->prefix->name[prefixLen++];)
- ; /* prefixLen includes null terminator */
+ ; /* prefixLen includes null terminator */
}
tagNamePtr->localPart = localPart;
tagNamePtr->uriLen = binding->uriLen;
tagNamePtr->prefix = binding->prefix->name;
tagNamePtr->prefixLen = prefixLen;
for (i = 0; localPart[i++];)
- ; /* i includes null terminator */
+ ; /* i includes null terminator */
n = i + binding->uriLen + prefixLen;
if (n > binding->uriAlloc) {
TAG *p;
- uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
- if (!uri)
+ uri = (XML_Char *)MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
+ if (! uri)
return XML_ERROR_NO_MEMORY;
binding->uriAlloc = n + EXPAND_SPARE;
memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
- for (p = tagStack; p; p = p->parent)
+ for (p = parser->m_tagStack; p; p = p->parent)
if (p->name.str == binding->uri)
p->name.str = uri;
- FREE(binding->uri);
+ FREE(parser, binding->uri);
binding->uri = uri;
}
- /* if namespaceSeparator != '\0' then uri includes it already */
+ /* if m_namespaceSeparator != '\0' then uri includes it already */
uri = binding->uri + binding->uriLen;
memcpy(uri, localPart, i * sizeof(XML_Char));
/* we always have a namespace separator between localPart and prefix */
if (prefixLen) {
uri += i - 1;
- *uri = namespaceSeparator; /* replace null terminator */
+ *uri = parser->m_namespaceSeparator; /* replace null terminator */
memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
}
tagNamePtr->str = binding->uri;
@@ -3061,27 +3441,25 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
*/
static enum XML_Error
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
- const XML_Char *uri, BINDING **bindingsPtr)
-{
- static const XML_Char xmlNamespace[] = {
- ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
- ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
- ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
- ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH,
- ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
- ASCII_e, '\0'
- };
- static const int xmlLen =
- (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
- static const XML_Char xmlnsNamespace[] = {
- ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
- ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
- ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0,
- ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s,
- ASCII_SLASH, '\0'
- };
- static const int xmlnsLen =
- (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
+ const XML_Char *uri, BINDING **bindingsPtr) {
+ static const XML_Char xmlNamespace[]
+ = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON,
+ ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
+ ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o,
+ ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M,
+ ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9,
+ ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m,
+ ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
+ ASCII_e, '\0'};
+ static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
+ static const XML_Char xmlnsNamespace[]
+ = {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
+ ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w,
+ ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH,
+ ASCII_2, ASCII_0, ASCII_0, ASCII_0, ASCII_SLASH, ASCII_x,
+ ASCII_m, ASCII_l, ASCII_n, ASCII_s, ASCII_SLASH, '\0'};
+ static const int xmlnsLen
+ = (int)sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1;
XML_Bool mustBeXML = XML_FALSE;
XML_Bool isXML = XML_TRUE;
@@ -3094,14 +3472,11 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (*uri == XML_T('\0') && prefix->name)
return XML_ERROR_UNDECLARING_PREFIX;
- if (prefix->name
- && prefix->name[0] == XML_T(ASCII_x)
+ if (prefix->name && prefix->name[0] == XML_T(ASCII_x)
&& prefix->name[1] == XML_T(ASCII_m)
&& prefix->name[2] == XML_T(ASCII_l)) {
-
/* Not allowed to bind xmlns */
- if (prefix->name[3] == XML_T(ASCII_n)
- && prefix->name[4] == XML_T(ASCII_s)
+ if (prefix->name[3] == XML_T(ASCII_n) && prefix->name[4] == XML_T(ASCII_s)
&& prefix->name[5] == XML_T('\0'))
return XML_ERROR_RESERVED_PREFIX_XMLNS;
@@ -3113,7 +3488,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
isXML = XML_FALSE;
- if (!mustBeXML && isXMLNS
+ if (! mustBeXML && isXMLNS
&& (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
isXMLNS = XML_FALSE;
}
@@ -3127,49 +3502,49 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
if (isXMLNS)
return XML_ERROR_RESERVED_NAMESPACE_URI;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len++;
- if (freeBindingList) {
- b = freeBindingList;
+ if (parser->m_freeBindingList) {
+ b = parser->m_freeBindingList;
if (len > b->uriAlloc) {
- XML_Char *temp = (XML_Char *)REALLOC(b->uri,
- sizeof(XML_Char) * (len + EXPAND_SPARE));
+ XML_Char *temp = (XML_Char *)REALLOC(
+ parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (temp == NULL)
return XML_ERROR_NO_MEMORY;
b->uri = temp;
b->uriAlloc = len + EXPAND_SPARE;
}
- freeBindingList = b->nextTagBinding;
- }
- else {
- b = (BINDING *)MALLOC(sizeof(BINDING));
- if (!b)
+ parser->m_freeBindingList = b->nextTagBinding;
+ } else {
+ b = (BINDING *)MALLOC(parser, sizeof(BINDING));
+ if (! b)
return XML_ERROR_NO_MEMORY;
- b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
- if (!b->uri) {
- FREE(b);
+ b->uri
+ = (XML_Char *)MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (! b->uri) {
+ FREE(parser, b);
return XML_ERROR_NO_MEMORY;
}
b->uriAlloc = len + EXPAND_SPARE;
}
b->uriLen = len;
memcpy(b->uri, uri, len * sizeof(XML_Char));
- if (namespaceSeparator)
- b->uri[len - 1] = namespaceSeparator;
+ if (parser->m_namespaceSeparator)
+ b->uri[len - 1] = parser->m_namespaceSeparator;
b->prefix = prefix;
b->attId = attId;
b->prevPrefixBinding = prefix->binding;
/* NULL binding when default namespace undeclared */
- if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+ if (*uri == XML_T('\0') && prefix == &parser->m_dtd->defaultPrefix)
prefix->binding = NULL;
else
prefix->binding = b;
b->nextTagBinding = *bindingsPtr;
*bindingsPtr = b;
/* if attId == NULL then we are not starting a namespace scope */
- if (attId && startNamespaceDeclHandler)
- startNamespaceDeclHandler(handlerArg, prefix->name,
- prefix->binding ? uri : 0);
+ if (attId && parser->m_startNamespaceDeclHandler)
+ parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name,
+ prefix->binding ? uri : 0);
return XML_ERROR_NONE;
}
@@ -3177,22 +3552,19 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
the whole file is parsed with one call.
*/
static enum XML_Error PTRCALL
-cdataSectionProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = doCdataSection(parser, encoding, &start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+cdataSectionProcessor(XML_Parser parser, const char *start, const char *end,
+ const char **endPtr) {
+ enum XML_Error result
+ = doCdataSection(parser, parser->m_encoding, &start, end, endPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer);
if (result != XML_ERROR_NONE)
return result;
if (start) {
- if (parentParser) { /* we are parsing an external entity */
- processor = externalEntityContentProcessor;
+ if (parser->m_parentParser) { /* we are parsing an external entity */
+ parser->m_processor = externalEntityContentProcessor;
return externalEntityContentProcessor(parser, start, end, endPtr);
- }
- else {
- processor = contentProcessor;
+ } else {
+ parser->m_processor = contentProcessor;
return contentProcessor(parser, start, end, endPtr);
}
}
@@ -3203,82 +3575,73 @@ cdataSectionProcessor(XML_Parser parser,
the section is not yet closed.
*/
static enum XML_Error
-doCdataSection(XML_Parser parser,
- const ENCODING *enc,
- const char **startPtr,
- const char *end,
- const char **nextPtr,
- XML_Bool haveMore)
-{
+doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore) {
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
*eventPP = s;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventEndPP = &parser->m_eventEndPtr;
+ } else {
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
*eventPP = s;
*startPtr = NULL;
for (;;) {
- const char *next;
+ const char *next = s; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
int tok = XmlCdataSectionTok(enc, s, end, &next);
*eventEndPP = next;
switch (tok) {
case XML_TOK_CDATA_SECT_CLOSE:
- if (endCdataSectionHandler)
- endCdataSectionHandler(handlerArg);
-#if 0
+ if (parser->m_endCdataSectionHandler)
+ parser->m_endCdataSectionHandler(parser->m_handlerArg);
+ /* BEGIN disabled code */
/* see comment under XML_TOK_CDATA_SECT_OPEN */
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
-#endif
- else if (defaultHandler)
+ else if (0 && parser->m_characterDataHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ 0);
+ /* END disabled code */
+ else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
else
return XML_ERROR_NONE;
case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
+ if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
- }
- else if (defaultHandler)
+ parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
- case XML_TOK_DATA_CHARS:
- {
- XML_CharacterDataHandler charDataHandler = characterDataHandler;
- if (charDataHandler) {
- if (MUST_CONVERT(enc, s)) {
- for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
- *eventEndPP = next;
- charDataHandler(handlerArg, dataBuf,
- (int)(dataPtr - (ICHAR *)dataBuf));
- if (s == next)
- break;
- *eventPP = s;
- }
+ case XML_TOK_DATA_CHARS: {
+ XML_CharacterDataHandler charDataHandler = parser->m_characterDataHandler;
+ if (charDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(
+ enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
+ *eventEndPP = next;
+ charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
+ if ((convert_res == XML_CONVERT_COMPLETED)
+ || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+ break;
+ *eventPP = s;
}
- else
- charDataHandler(handlerArg,
- (XML_Char *)s,
- (int)((XML_Char *)next - (XML_Char *)s));
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- }
- break;
+ } else
+ charDataHandler(parser->m_handlerArg, (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ } else if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ } break;
case XML_TOK_INVALID:
*eventPP = next;
return XML_ERROR_INVALID_TOKEN;
@@ -3296,18 +3659,26 @@ doCdataSection(XML_Parser parser,
}
return XML_ERROR_UNCLOSED_CDATA_SECTION;
default:
+ /* Every token returned by XmlCdataSectionTok() has its own
+ * explicit case, so this default case will never be executed.
+ * We retain it as a safety net and exclude it from the coverage
+ * statistics.
+ *
+ * LCOV_EXCL_START
+ */
*eventPP = next;
return XML_ERROR_UNEXPECTED_STATE;
+ /* LCOV_EXCL_STOP */
}
*eventPP = s = next;
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
- default: ;
+ default:;
}
}
/* not reached */
@@ -3319,17 +3690,15 @@ doCdataSection(XML_Parser parser,
the whole file is parsed with one call.
*/
static enum XML_Error PTRCALL
-ignoreSectionProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
- endPtr, (XML_Bool)!ps_finalBuffer);
+ignoreSectionProcessor(XML_Parser parser, const char *start, const char *end,
+ const char **endPtr) {
+ enum XML_Error result
+ = doIgnoreSection(parser, parser->m_encoding, &start, end, endPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer);
if (result != XML_ERROR_NONE)
return result;
if (start) {
- processor = prologProcessor;
+ parser->m_processor = prologProcessor;
return prologProcessor(parser, start, end, endPtr);
}
return result;
@@ -3339,26 +3708,32 @@ ignoreSectionProcessor(XML_Parser parser,
if the section is not yet closed.
*/
static enum XML_Error
-doIgnoreSection(XML_Parser parser,
- const ENCODING *enc,
- const char **startPtr,
- const char *end,
- const char **nextPtr,
- XML_Bool haveMore)
-{
- const char *next;
+doIgnoreSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore) {
+ const char *next = *startPtr; /* in case of XML_TOK_NONE or XML_TOK_PARTIAL */
int tok;
const char *s = *startPtr;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
*eventPP = s;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ eventEndPP = &parser->m_eventEndPtr;
+ } else {
+ /* It's not entirely clear, but it seems the following two lines
+ * of code cannot be executed. The only occasions on which 'enc'
+ * is not 'encoding' are when this function is called
+ * from the internal entity processing, and IGNORE sections are an
+ * error in internal entities.
+ *
+ * Since it really isn't clear that this is true, we keep the code
+ * and just remove it from our coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
+ /* LCOV_EXCL_STOP */
}
*eventPP = s;
*startPtr = NULL;
@@ -3366,11 +3741,11 @@ doIgnoreSection(XML_Parser parser,
*eventEndPP = next;
switch (tok) {
case XML_TOK_IGNORE_SECT:
- if (defaultHandler)
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
else
return XML_ERROR_NONE;
@@ -3391,8 +3766,16 @@ doIgnoreSection(XML_Parser parser,
}
return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
default:
+ /* All of the tokens that XmlIgnoreSectionTok() returns have
+ * explicit cases to handle them, so this default case is never
+ * executed. We keep it as a safety net anyway, and remove it
+ * from our test coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
*eventPP = next;
return XML_ERROR_UNEXPECTED_STATE;
+ /* LCOV_EXCL_STOP */
}
/* not reached */
}
@@ -3400,38 +3783,38 @@ doIgnoreSection(XML_Parser parser,
#endif /* XML_DTD */
static enum XML_Error
-initializeEncoding(XML_Parser parser)
-{
+initializeEncoding(XML_Parser parser) {
const char *s;
#ifdef XML_UNICODE
char encodingBuf[128];
- if (!protocolEncodingName)
+ /* See comments abount `protoclEncodingName` in parserInit() */
+ if (! parser->m_protocolEncodingName)
s = NULL;
else {
int i;
- for (i = 0; protocolEncodingName[i]; i++) {
+ for (i = 0; parser->m_protocolEncodingName[i]; i++) {
if (i == sizeof(encodingBuf) - 1
- || (protocolEncodingName[i] & ~0x7f) != 0) {
+ || (parser->m_protocolEncodingName[i] & ~0x7f) != 0) {
encodingBuf[0] = '\0';
break;
}
- encodingBuf[i] = (char)protocolEncodingName[i];
+ encodingBuf[i] = (char)parser->m_protocolEncodingName[i];
}
encodingBuf[i] = '\0';
s = encodingBuf;
}
#else
- s = protocolEncodingName;
+ s = parser->m_protocolEncodingName;
#endif
- if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ if ((parser->m_ns ? XmlInitEncodingNS : XmlInitEncoding)(
+ &parser->m_initEncoding, &parser->m_encoding, s))
return XML_ERROR_NONE;
- return handleUnknownEncoding(parser, protocolEncodingName);
+ return handleUnknownEncoding(parser, parser->m_protocolEncodingName);
}
static enum XML_Error
-processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
- const char *s, const char *next)
-{
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *s,
+ const char *next) {
const char *encodingName = NULL;
const XML_Char *storedEncName = NULL;
const ENCODING *newEncoding = NULL;
@@ -3439,88 +3822,82 @@ processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
const char *versionend;
const XML_Char *storedversion = NULL;
int standalone = -1;
- if (!(ns
- ? XmlParseXmlDeclNS
- : XmlParseXmlDecl)(isGeneralTextEntity,
- encoding,
- s,
- next,
- &eventPtr,
- &version,
- &versionend,
- &encodingName,
- &newEncoding,
- &standalone)) {
+ if (! (parser->m_ns ? XmlParseXmlDeclNS : XmlParseXmlDecl)(
+ isGeneralTextEntity, parser->m_encoding, s, next, &parser->m_eventPtr,
+ &version, &versionend, &encodingName, &newEncoding, &standalone)) {
if (isGeneralTextEntity)
return XML_ERROR_TEXT_DECL;
else
return XML_ERROR_XML_DECL;
}
- if (!isGeneralTextEntity && standalone == 1) {
- _dtd->standalone = XML_TRUE;
+ if (! isGeneralTextEntity && standalone == 1) {
+ parser->m_dtd->standalone = XML_TRUE;
#ifdef XML_DTD
- if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+ if (parser->m_paramEntityParsing
+ == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+ parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif /* XML_DTD */
}
- if (xmlDeclHandler) {
+ if (parser->m_xmlDeclHandler) {
if (encodingName != NULL) {
- storedEncName = poolStoreString(&temp2Pool,
- encoding,
- encodingName,
- encodingName
- + XmlNameLength(encoding, encodingName));
- if (!storedEncName)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&temp2Pool);
+ storedEncName = poolStoreString(
+ &parser->m_temp2Pool, parser->m_encoding, encodingName,
+ encodingName + XmlNameLength(parser->m_encoding, encodingName));
+ if (! storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&parser->m_temp2Pool);
}
if (version) {
- storedversion = poolStoreString(&temp2Pool,
- encoding,
- version,
- versionend - encoding->minBytesPerChar);
- if (!storedversion)
+ storedversion
+ = poolStoreString(&parser->m_temp2Pool, parser->m_encoding, version,
+ versionend - parser->m_encoding->minBytesPerChar);
+ if (! storedversion)
return XML_ERROR_NO_MEMORY;
}
- xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
- }
- else if (defaultHandler)
- reportDefault(parser, encoding, s, next);
- if (protocolEncodingName == NULL) {
+ parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName,
+ standalone);
+ } else if (parser->m_defaultHandler)
+ reportDefault(parser, parser->m_encoding, s, next);
+ if (parser->m_protocolEncodingName == NULL) {
if (newEncoding) {
- if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
- eventPtr = encodingName;
+ /* Check that the specified encoding does not conflict with what
+ * the parser has already deduced. Do we have the same number
+ * of bytes in the smallest representation of a character? If
+ * this is UTF-16, is it the same endianness?
+ */
+ if (newEncoding->minBytesPerChar != parser->m_encoding->minBytesPerChar
+ || (newEncoding->minBytesPerChar == 2
+ && newEncoding != parser->m_encoding)) {
+ parser->m_eventPtr = encodingName;
return XML_ERROR_INCORRECT_ENCODING;
}
- encoding = newEncoding;
- }
- else if (encodingName) {
+ parser->m_encoding = newEncoding;
+ } else if (encodingName) {
enum XML_Error result;
- if (!storedEncName) {
+ if (! storedEncName) {
storedEncName = poolStoreString(
- &temp2Pool, encoding, encodingName,
- encodingName + XmlNameLength(encoding, encodingName));
- if (!storedEncName)
+ &parser->m_temp2Pool, parser->m_encoding, encodingName,
+ encodingName + XmlNameLength(parser->m_encoding, encodingName));
+ if (! storedEncName)
return XML_ERROR_NO_MEMORY;
}
result = handleUnknownEncoding(parser, storedEncName);
- poolClear(&temp2Pool);
+ poolClear(&parser->m_temp2Pool);
if (result == XML_ERROR_UNKNOWN_ENCODING)
- eventPtr = encodingName;
+ parser->m_eventPtr = encodingName;
return result;
}
}
if (storedEncName || storedversion)
- poolClear(&temp2Pool);
+ poolClear(&parser->m_temp2Pool);
return XML_ERROR_NONE;
}
static enum XML_Error
-handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
-{
- if (unknownEncodingHandler) {
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) {
+ if (parser->m_unknownEncodingHandler) {
XML_Encoding info;
int i;
for (i = 0; i < 256; i++)
@@ -3528,25 +3905,21 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
info.convert = NULL;
info.data = NULL;
info.release = NULL;
- if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
- &info)) {
+ if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData,
+ encodingName, &info)) {
ENCODING *enc;
- unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
- if (!unknownEncodingMem) {
+ parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
+ if (! parser->m_unknownEncodingMem) {
if (info.release)
info.release(info.data);
return XML_ERROR_NO_MEMORY;
}
- enc = (ns
- ? XmlInitUnknownEncodingNS
- : XmlInitUnknownEncoding)(unknownEncodingMem,
- info.map,
- info.convert,
- info.data);
+ enc = (parser->m_ns ? XmlInitUnknownEncodingNS : XmlInitUnknownEncoding)(
+ parser->m_unknownEncodingMem, info.map, info.convert, info.data);
if (enc) {
- unknownEncodingData = info.data;
- unknownEncodingRelease = info.release;
- encoding = enc;
+ parser->m_unknownEncodingData = info.data;
+ parser->m_unknownEncodingRelease = info.release;
+ parser->m_encoding = enc;
return XML_ERROR_NONE;
}
}
@@ -3557,60 +3930,50 @@ handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
}
static enum XML_Error PTRCALL
-prologInitProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+prologInitProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
- processor = prologProcessor;
+ parser->m_processor = prologProcessor;
return prologProcessor(parser, s, end, nextPtr);
}
#ifdef XML_DTD
static enum XML_Error PTRCALL
-externalParEntInitProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+externalParEntInitProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
enum XML_Error result = initializeEncoding(parser);
if (result != XML_ERROR_NONE)
return result;
/* we know now that XML_Parse(Buffer) has been called,
so we consider the external parameter entity read */
- _dtd->paramEntityRead = XML_TRUE;
+ parser->m_dtd->paramEntityRead = XML_TRUE;
- if (prologState.inEntityValue) {
- processor = entityValueInitProcessor;
+ if (parser->m_prologState.inEntityValue) {
+ parser->m_processor = entityValueInitProcessor;
return entityValueInitProcessor(parser, s, end, nextPtr);
- }
- else {
- processor = externalParEntProcessor;
+ } else {
+ parser->m_processor = externalParEntProcessor;
return externalParEntProcessor(parser, s, end, nextPtr);
}
}
static enum XML_Error PTRCALL
-entityValueInitProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
int tok;
const char *start = s;
const char *next = start;
- eventPtr = start;
+ parser->m_eventPtr = start;
for (;;) {
- tok = XmlPrologTok(encoding, start, end, &next);
- eventEndPtr = next;
+ tok = XmlPrologTok(parser->m_encoding, start, end, &next);
+ parser->m_eventEndPtr = next;
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -3621,29 +3984,27 @@ entityValueInitProcessor(XML_Parser parser,
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_NONE: /* start == end */
+ case XML_TOK_NONE: /* start == end */
default:
break;
}
/* found end of entity value - can store it now */
- return storeEntityValue(parser, encoding, s, end);
- }
- else if (tok == XML_TOK_XML_DECL) {
+ return storeEntityValue(parser, parser->m_encoding, s, end);
+ } else if (tok == XML_TOK_XML_DECL) {
enum XML_Error result;
result = processXmlDecl(parser, 0, start, next);
if (result != XML_ERROR_NONE)
return result;
- switch (ps_parsing) {
- case XML_SUSPENDED:
- *nextPtr = next;
- return XML_ERROR_NONE;
- case XML_FINISHED:
+ /* At this point, m_parsingStatus.parsing cannot be XML_SUSPENDED. For
+ * that to happen, a parameter entity parsing handler must have attempted
+ * to suspend the parser, which fails and raises an error. The parser can
+ * be aborted, but can't be suspended.
+ */
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
- default:
- *nextPtr = next;
- }
+ *nextPtr = next;
/* stop scanning for text declaration - we found one */
- processor = entityValueProcessor;
+ parser->m_processor = entityValueProcessor;
return entityValueProcessor(parser, next, end, nextPtr);
}
/* If we are at the end of the buffer, this would cause XmlPrologTok to
@@ -3653,27 +4014,33 @@ entityValueInitProcessor(XML_Parser parser,
then, when this routine is entered the next time, XmlPrologTok will
return XML_TOK_INVALID, since the BOM is still in the buffer
*/
- else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+ else if (tok == XML_TOK_BOM && next == end
+ && ! parser->m_parsingStatus.finalBuffer) {
*nextPtr = next;
return XML_ERROR_NONE;
}
+ /* If we get this token, we have the start of what might be a
+ normal tag, but not a declaration (i.e. it doesn't begin with
+ "<!"). In a DTD context, that isn't legal.
+ */
+ else if (tok == XML_TOK_INSTANCE_START) {
+ *nextPtr = next;
+ return XML_ERROR_SYNTAX;
+ }
start = next;
- eventPtr = start;
+ parser->m_eventPtr = start;
}
}
static enum XML_Error PTRCALL
-externalParEntProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+externalParEntProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
const char *next = s;
int tok;
- tok = XmlPrologTok(encoding, s, end, &next);
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -3684,7 +4051,7 @@ externalParEntProcessor(XML_Parser parser,
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_NONE: /* start == end */
+ case XML_TOK_NONE: /* start == end */
default:
break;
}
@@ -3695,29 +4062,26 @@ externalParEntProcessor(XML_Parser parser,
*/
else if (tok == XML_TOK_BOM) {
s = next;
- tok = XmlPrologTok(encoding, s, end, &next);
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
}
- processor = prologProcessor;
- return doProlog(parser, encoding, s, end, tok, next,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ parser->m_processor = prologProcessor;
+ return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
}
static enum XML_Error PTRCALL
-entityValueProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+entityValueProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
const char *start = s;
const char *next = s;
- const ENCODING *enc = encoding;
+ const ENCODING *enc = parser->m_encoding;
int tok;
for (;;) {
tok = XmlPrologTok(enc, start, end, &next);
if (tok <= 0) {
- if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ if (! parser->m_parsingStatus.finalBuffer && tok != XML_TOK_INVALID) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -3728,7 +4092,7 @@ entityValueProcessor(XML_Parser parser,
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_NONE: /* start == end */
+ case XML_TOK_NONE: /* start == end */
default:
break;
}
@@ -3742,64 +4106,57 @@ entityValueProcessor(XML_Parser parser,
#endif /* XML_DTD */
static enum XML_Error PTRCALL
-prologProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+prologProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
const char *next = s;
- int tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
}
static enum XML_Error
-doProlog(XML_Parser parser,
- const ENCODING *enc,
- const char *s,
- const char *end,
- int tok,
- const char *next,
- const char **nextPtr,
- XML_Bool haveMore)
-{
+doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
+ int tok, const char *next, const char **nextPtr, XML_Bool haveMore,
+ XML_Bool allowClosingDoctype) {
#ifdef XML_DTD
- static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' };
+ static const XML_Char externalSubsetName[] = {ASCII_HASH, '\0'};
#endif /* XML_DTD */
- static const XML_Char atypeCDATA[] =
- { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
- static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' };
- static const XML_Char atypeIDREF[] =
- { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
- static const XML_Char atypeIDREFS[] =
- { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
- static const XML_Char atypeENTITY[] =
- { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
- static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N,
- ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
- static const XML_Char atypeNMTOKEN[] = {
- ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
- static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T,
- ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
- static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T,
- ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' };
- static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' };
- static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
+ static const XML_Char atypeCDATA[]
+ = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'};
+ static const XML_Char atypeID[] = {ASCII_I, ASCII_D, '\0'};
+ static const XML_Char atypeIDREF[]
+ = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0'};
+ static const XML_Char atypeIDREFS[]
+ = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0'};
+ static const XML_Char atypeENTITY[]
+ = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0'};
+ static const XML_Char atypeENTITIES[]
+ = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T,
+ ASCII_I, ASCII_E, ASCII_S, '\0'};
+ static const XML_Char atypeNMTOKEN[]
+ = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0'};
+ static const XML_Char atypeNMTOKENS[]
+ = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K,
+ ASCII_E, ASCII_N, ASCII_S, '\0'};
+ static const XML_Char notationPrefix[]
+ = {ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T,
+ ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0'};
+ static const XML_Char enumValueSep[] = {ASCII_PIPE, '\0'};
+ static const XML_Char enumValueStart[] = {ASCII_LPAREN, '\0'};
/* save one level of indirection */
- DTD * const dtd = _dtd;
+ DTD *const dtd = parser->m_dtd;
const char **eventPP;
const char **eventEndPP;
enum XML_Content_Quant quant;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
+ } else {
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
}
for (;;) {
@@ -3826,7 +4183,8 @@ doProlog(XML_Parser parser,
case XML_TOK_NONE:
#ifdef XML_DTD
/* for internal PE NOT referenced between declarations */
- if (enc != encoding && !openInternalEntities->betweenDecl) {
+ if (enc != parser->m_encoding
+ && ! parser->m_openInternalEntities->betweenDecl) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -3834,8 +4192,8 @@ doProlog(XML_Parser parser,
complete markup, not only for external PEs, but also for
internal PEs if the reference occurs between declarations.
*/
- if (isParamEntity || enc != encoding) {
- if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+ if (parser->m_isParamEntity || enc != parser->m_encoding) {
+ if (XmlTokenRole(&parser->m_prologState, XML_TOK_NONE, end, end, enc)
== XML_ROLE_ERROR)
return XML_ERROR_INCOMPLETE_PE;
*nextPtr = s;
@@ -3849,142 +4207,148 @@ doProlog(XML_Parser parser,
break;
}
}
- role = XmlTokenRole(&prologState, tok, s, next, enc);
+ role = XmlTokenRole(&parser->m_prologState, tok, s, next, enc);
switch (role) {
- case XML_ROLE_XML_DECL:
- {
- enum XML_Error result = processXmlDecl(parser, 0, s, next);
- if (result != XML_ERROR_NONE)
- return result;
- enc = encoding;
- handleDefault = XML_FALSE;
- }
- break;
+ case XML_ROLE_XML_DECL: {
+ enum XML_Error result = processXmlDecl(parser, 0, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = parser->m_encoding;
+ handleDefault = XML_FALSE;
+ } break;
case XML_ROLE_DOCTYPE_NAME:
- if (startDoctypeDeclHandler) {
- doctypeName = poolStoreString(&tempPool, enc, s, next);
- if (!doctypeName)
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_doctypeName
+ = poolStoreString(&parser->m_tempPool, enc, s, next);
+ if (! parser->m_doctypeName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- doctypePubid = NULL;
+ poolFinish(&parser->m_tempPool);
+ parser->m_doctypePubid = NULL;
handleDefault = XML_FALSE;
}
- doctypeSysid = NULL; /* always initialize to NULL */
+ parser->m_doctypeSysid = NULL; /* always initialize to NULL */
break;
case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
- if (startDoctypeDeclHandler) {
- startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
- doctypePubid, 1);
- doctypeName = NULL;
- poolClear(&tempPool);
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_startDoctypeDeclHandler(
+ parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
+ parser->m_doctypePubid, 1);
+ parser->m_doctypeName = NULL;
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
#ifdef XML_DTD
- case XML_ROLE_TEXT_DECL:
- {
- enum XML_Error result = processXmlDecl(parser, 1, s, next);
- if (result != XML_ERROR_NONE)
- return result;
- enc = encoding;
- handleDefault = XML_FALSE;
- }
- break;
+ case XML_ROLE_TEXT_DECL: {
+ enum XML_Error result = processXmlDecl(parser, 1, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = parser->m_encoding;
+ handleDefault = XML_FALSE;
+ } break;
#endif /* XML_DTD */
case XML_ROLE_DOCTYPE_PUBLIC_ID:
#ifdef XML_DTD
- useForeignDTD = XML_FALSE;
- declEntity = (ENTITY *)lookup(parser,
- &dtd->paramEntities,
- externalSubsetName,
- sizeof(ENTITY));
- if (!declEntity)
+ parser->m_useForeignDTD = XML_FALSE;
+ parser->m_declEntity = (ENTITY *)lookup(
+ parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY));
+ if (! parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
#endif /* XML_DTD */
dtd->hasParamEntityRefs = XML_TRUE;
- if (startDoctypeDeclHandler) {
+ if (parser->m_startDoctypeDeclHandler) {
XML_Char *pubId;
- if (!XmlIsPublicId(enc, s, next, eventPP))
+ if (! XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
- pubId = poolStoreString(&tempPool, enc,
+ pubId = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (!pubId)
+ if (! pubId)
return XML_ERROR_NO_MEMORY;
normalizePublicId(pubId);
- poolFinish(&tempPool);
- doctypePubid = pubId;
+ poolFinish(&parser->m_tempPool);
+ parser->m_doctypePubid = pubId;
handleDefault = XML_FALSE;
goto alreadyChecked;
}
/* fall through */
case XML_ROLE_ENTITY_PUBLIC_ID:
- if (!XmlIsPublicId(enc, s, next, eventPP))
+ if (! XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
alreadyChecked:
- if (dtd->keepProcessing && declEntity) {
- XML_Char *tem = poolStoreString(&dtd->pool,
- enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!tem)
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ XML_Char *tem
+ = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (! tem)
return XML_ERROR_NO_MEMORY;
normalizePublicId(tem);
- declEntity->publicId = tem;
+ parser->m_declEntity->publicId = tem;
poolFinish(&dtd->pool);
- if (entityDeclHandler)
+ /* Don't suppress the default handler if we fell through from
+ * the XML_ROLE_DOCTYPE_PUBLIC_ID case.
+ */
+ if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_PUBLIC_ID)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_DOCTYPE_CLOSE:
- if (doctypeName) {
- startDoctypeDeclHandler(handlerArg, doctypeName,
- doctypeSysid, doctypePubid, 0);
- poolClear(&tempPool);
+ if (allowClosingDoctype != XML_TRUE) {
+ /* Must not close doctype from within expanded parameter entities */
+ return XML_ERROR_INVALID_TOKEN;
+ }
+
+ if (parser->m_doctypeName) {
+ parser->m_startDoctypeDeclHandler(
+ parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
+ parser->m_doctypePubid, 0);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
- /* doctypeSysid will be non-NULL in the case of a previous
- XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+ /* parser->m_doctypeSysid will be non-NULL in the case of a previous
+ XML_ROLE_DOCTYPE_SYSTEM_ID, even if parser->m_startDoctypeDeclHandler
was not set, indicating an external subset
*/
#ifdef XML_DTD
- if (doctypeSysid || useForeignDTD) {
+ if (parser->m_doctypeSysid || parser->m_useForeignDTD) {
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
dtd->hasParamEntityRefs = XML_TRUE;
- if (paramEntityParsing && externalEntityRefHandler) {
- ENTITY *entity = (ENTITY *)lookup(parser,
- &dtd->paramEntities,
- externalSubsetName,
- sizeof(ENTITY));
- if (!entity)
- return XML_ERROR_NO_MEMORY;
- if (useForeignDTD)
- entity->base = curBase;
+ if (parser->m_paramEntityParsing
+ && parser->m_externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ externalSubsetName, sizeof(ENTITY));
+ if (! entity) {
+ /* The external subset name "#" will have already been
+ * inserted into the hash table at the start of the
+ * external entity parsing, so no allocation will happen
+ * and lookup() cannot fail.
+ */
+ return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
+ }
+ if (parser->m_useForeignDTD)
+ entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- 0,
- entity->base,
- entity->systemId,
- entity->publicId))
+ if (! parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId))
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
- if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ if (! dtd->standalone && parser->m_notStandaloneHandler
+ && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
}
/* if we didn't read the foreign DTD then this means that there
is no external subset and we must reset dtd->hasParamEntityRefs
*/
- else if (!doctypeSysid)
+ else if (! parser->m_doctypeSysid)
dtd->hasParamEntityRefs = hadParamEntityRefs;
/* end of DTD - no need to update dtd->keepProcessing */
}
- useForeignDTD = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
}
#endif /* XML_DTD */
- if (endDoctypeDeclHandler) {
- endDoctypeDeclHandler(handlerArg);
+ if (parser->m_endDoctypeDeclHandler) {
+ parser->m_endDoctypeDeclHandler(parser->m_handlerArg);
handleDefault = XML_FALSE;
}
break;
@@ -3993,27 +4357,24 @@ doProlog(XML_Parser parser,
/* if there is no DOCTYPE declaration then now is the
last chance to read the foreign DTD
*/
- if (useForeignDTD) {
+ if (parser->m_useForeignDTD) {
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
dtd->hasParamEntityRefs = XML_TRUE;
- if (paramEntityParsing && externalEntityRefHandler) {
+ if (parser->m_paramEntityParsing
+ && parser->m_externalEntityRefHandler) {
ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
- externalSubsetName,
- sizeof(ENTITY));
- if (!entity)
+ externalSubsetName, sizeof(ENTITY));
+ if (! entity)
return XML_ERROR_NO_MEMORY;
- entity->base = curBase;
+ entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- 0,
- entity->base,
- entity->systemId,
- entity->publicId))
+ if (! parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId))
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
- if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ if (! dtd->standalone && parser->m_notStandaloneHandler
+ && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
}
/* if we didn't read the foreign DTD then this means that there
@@ -4025,93 +4386,93 @@ doProlog(XML_Parser parser,
}
}
#endif /* XML_DTD */
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
return contentProcessor(parser, s, end, nextPtr);
case XML_ROLE_ATTLIST_ELEMENT_NAME:
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
+ parser->m_declElementType = getElementType(parser, enc, s, next);
+ if (! parser->m_declElementType)
return XML_ERROR_NO_MEMORY;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_NAME:
- declAttributeId = getAttributeId(parser, enc, s, next);
- if (!declAttributeId)
+ parser->m_declAttributeId = getAttributeId(parser, enc, s, next);
+ if (! parser->m_declAttributeId)
return XML_ERROR_NO_MEMORY;
- declAttributeIsCdata = XML_FALSE;
- declAttributeType = NULL;
- declAttributeIsId = XML_FALSE;
+ parser->m_declAttributeIsCdata = XML_FALSE;
+ parser->m_declAttributeType = NULL;
+ parser->m_declAttributeIsId = XML_FALSE;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
- declAttributeIsCdata = XML_TRUE;
- declAttributeType = atypeCDATA;
+ parser->m_declAttributeIsCdata = XML_TRUE;
+ parser->m_declAttributeType = atypeCDATA;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ID:
- declAttributeIsId = XML_TRUE;
- declAttributeType = atypeID;
+ parser->m_declAttributeIsId = XML_TRUE;
+ parser->m_declAttributeType = atypeID;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
- declAttributeType = atypeIDREF;
+ parser->m_declAttributeType = atypeIDREF;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
- declAttributeType = atypeIDREFS;
+ parser->m_declAttributeType = atypeIDREFS;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
- declAttributeType = atypeENTITY;
+ parser->m_declAttributeType = atypeENTITY;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
- declAttributeType = atypeENTITIES;
+ parser->m_declAttributeType = atypeENTITIES;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
- declAttributeType = atypeNMTOKEN;
+ parser->m_declAttributeType = atypeNMTOKEN;
goto checkAttListDeclHandler;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
- declAttributeType = atypeNMTOKENS;
+ parser->m_declAttributeType = atypeNMTOKENS;
checkAttListDeclHandler:
- if (dtd->keepProcessing && attlistDeclHandler)
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
- if (dtd->keepProcessing && attlistDeclHandler) {
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler) {
const XML_Char *prefix;
- if (declAttributeType) {
+ if (parser->m_declAttributeType) {
prefix = enumValueSep;
+ } else {
+ prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE ? notationPrefix
+ : enumValueStart);
}
- else {
- prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
- ? notationPrefix
- : enumValueStart);
- }
- if (!poolAppendString(&tempPool, prefix))
+ if (! poolAppendString(&parser->m_tempPool, prefix))
return XML_ERROR_NO_MEMORY;
- if (!poolAppend(&tempPool, enc, s, next))
+ if (! poolAppend(&parser->m_tempPool, enc, s, next))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
+ parser->m_declAttributeType = parser->m_tempPool.start;
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
if (dtd->keepProcessing) {
- if (!defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, declAttributeIsId,
- 0, parser))
+ if (! defineAttribute(parser->m_declElementType,
+ parser->m_declAttributeId,
+ parser->m_declAttributeIsCdata,
+ parser->m_declAttributeIsId, 0, parser))
return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == XML_T(ASCII_LPAREN)
- || (*declAttributeType == XML_T(ASCII_N)
- && declAttributeType[1] == XML_T(ASCII_O))) {
+ if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
+ if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
+ || (*parser->m_declAttributeType == XML_T(ASCII_N)
+ && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
/* Enumerated or Notation type */
- if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
- || !poolAppendChar(&tempPool, XML_T('\0')))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
+ || ! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
+ parser->m_declAttributeType = parser->m_tempPool.start;
+ poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
- 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
+ parser->m_attlistDeclHandler(
+ parser->m_handlerArg, parser->m_declElementType->name,
+ parser->m_declAttributeId->name, parser->m_declAttributeType, 0,
+ role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
@@ -4120,61 +4481,57 @@ doProlog(XML_Parser parser,
case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
if (dtd->keepProcessing) {
const XML_Char *attVal;
- enum XML_Error result =
- storeAttributeValue(parser, enc, declAttributeIsCdata,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar,
- &dtd->pool);
+ enum XML_Error result = storeAttributeValue(
+ parser, enc, parser->m_declAttributeIsCdata,
+ s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd->pool);
if (result)
return result;
attVal = poolStart(&dtd->pool);
poolFinish(&dtd->pool);
/* ID attributes aren't allowed to have a default */
- if (!defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, XML_FALSE, attVal, parser))
+ if (! defineAttribute(
+ parser->m_declElementType, parser->m_declAttributeId,
+ parser->m_declAttributeIsCdata, XML_FALSE, attVal, parser))
return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == XML_T(ASCII_LPAREN)
- || (*declAttributeType == XML_T(ASCII_N)
- && declAttributeType[1] == XML_T(ASCII_O))) {
+ if (parser->m_attlistDeclHandler && parser->m_declAttributeType) {
+ if (*parser->m_declAttributeType == XML_T(ASCII_LPAREN)
+ || (*parser->m_declAttributeType == XML_T(ASCII_N)
+ && parser->m_declAttributeType[1] == XML_T(ASCII_O))) {
/* Enumerated or Notation type */
- if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
- || !poolAppendChar(&tempPool, XML_T('\0')))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_RPAREN))
+ || ! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
+ parser->m_declAttributeType = parser->m_tempPool.start;
+ poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
- attVal,
- role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
+ parser->m_attlistDeclHandler(
+ parser->m_handlerArg, parser->m_declElementType->name,
+ parser->m_declAttributeId->name, parser->m_declAttributeType,
+ attVal, role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+ poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
}
break;
case XML_ROLE_ENTITY_VALUE:
if (dtd->keepProcessing) {
- enum XML_Error result = storeEntityValue(parser, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (declEntity) {
- declEntity->textPtr = poolStart(&dtd->entityValuePool);
- declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+ enum XML_Error result = storeEntityValue(
+ parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar);
+ if (parser->m_declEntity) {
+ parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
+ parser->m_declEntity->textLen
+ = (int)(poolLength(&dtd->entityValuePool));
poolFinish(&dtd->entityValuePool);
- if (entityDeclHandler) {
+ if (parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
- declEntity->textPtr,
- declEntity->textLen,
- curBase, 0, 0, 0);
+ parser->m_entityDeclHandler(
+ parser->m_handlerArg, parser->m_declEntity->name,
+ parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
+ parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
handleDefault = XML_FALSE;
}
- }
- else
+ } else
poolDiscard(&dtd->entityValuePool);
if (result != XML_ERROR_NONE)
return result;
@@ -4182,227 +4539,212 @@ doProlog(XML_Parser parser,
break;
case XML_ROLE_DOCTYPE_SYSTEM_ID:
#ifdef XML_DTD
- useForeignDTD = XML_FALSE;
+ parser->m_useForeignDTD = XML_FALSE;
#endif /* XML_DTD */
dtd->hasParamEntityRefs = XML_TRUE;
- if (startDoctypeDeclHandler) {
- doctypeSysid = poolStoreString(&tempPool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (doctypeSysid == NULL)
+ if (parser->m_startDoctypeDeclHandler) {
+ parser->m_doctypeSysid = poolStoreString(&parser->m_tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (parser->m_doctypeSysid == NULL)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
#ifdef XML_DTD
else
- /* use externalSubsetName to make doctypeSysid non-NULL
- for the case where no startDoctypeDeclHandler is set */
- doctypeSysid = externalSubsetName;
+ /* use externalSubsetName to make parser->m_doctypeSysid non-NULL
+ for the case where no parser->m_startDoctypeDeclHandler is set */
+ parser->m_doctypeSysid = externalSubsetName;
#endif /* XML_DTD */
- if (!dtd->standalone
+ if (! dtd->standalone
#ifdef XML_DTD
- && !paramEntityParsing
+ && ! parser->m_paramEntityParsing
#endif /* XML_DTD */
- && notStandaloneHandler
- && !notStandaloneHandler(handlerArg))
+ && parser->m_notStandaloneHandler
+ && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
#ifndef XML_DTD
break;
-#else /* XML_DTD */
- if (!declEntity) {
- declEntity = (ENTITY *)lookup(parser,
- &dtd->paramEntities,
- externalSubsetName,
- sizeof(ENTITY));
- if (!declEntity)
+#else /* XML_DTD */
+ if (! parser->m_declEntity) {
+ parser->m_declEntity = (ENTITY *)lookup(
+ parser, &dtd->paramEntities, externalSubsetName, sizeof(ENTITY));
+ if (! parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- declEntity->publicId = NULL;
+ parser->m_declEntity->publicId = NULL;
}
- /* fall through */
#endif /* XML_DTD */
+ /* fall through */
case XML_ROLE_ENTITY_SYSTEM_ID:
- if (dtd->keepProcessing && declEntity) {
- declEntity->systemId = poolStoreString(&dtd->pool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!declEntity->systemId)
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ parser->m_declEntity->systemId
+ = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (! parser->m_declEntity->systemId)
return XML_ERROR_NO_MEMORY;
- declEntity->base = curBase;
+ parser->m_declEntity->base = parser->m_curBase;
poolFinish(&dtd->pool);
- if (entityDeclHandler)
+ /* Don't suppress the default handler if we fell through from
+ * the XML_ROLE_DOCTYPE_SYSTEM_ID case.
+ */
+ if (parser->m_entityDeclHandler && role == XML_ROLE_ENTITY_SYSTEM_ID)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_ENTITY_COMPLETE:
- if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+ if (dtd->keepProcessing && parser->m_declEntity
+ && parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
- 0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- 0);
+ parser->m_entityDeclHandler(
+ parser->m_handlerArg, parser->m_declEntity->name,
+ parser->m_declEntity->is_param, 0, 0, parser->m_declEntity->base,
+ parser->m_declEntity->systemId, parser->m_declEntity->publicId, 0);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_ENTITY_NOTATION_NAME:
- if (dtd->keepProcessing && declEntity) {
- declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
- if (!declEntity->notation)
+ if (dtd->keepProcessing && parser->m_declEntity) {
+ parser->m_declEntity->notation
+ = poolStoreString(&dtd->pool, enc, s, next);
+ if (! parser->m_declEntity->notation)
return XML_ERROR_NO_MEMORY;
poolFinish(&dtd->pool);
- if (unparsedEntityDeclHandler) {
+ if (parser->m_unparsedEntityDeclHandler) {
*eventEndPP = s;
- unparsedEntityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
+ parser->m_unparsedEntityDeclHandler(
+ parser->m_handlerArg, parser->m_declEntity->name,
+ parser->m_declEntity->base, parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId, parser->m_declEntity->notation);
handleDefault = XML_FALSE;
- }
- else if (entityDeclHandler) {
+ } else if (parser->m_entityDeclHandler) {
*eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- 0,0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
+ parser->m_entityDeclHandler(
+ parser->m_handlerArg, parser->m_declEntity->name, 0, 0, 0,
+ parser->m_declEntity->base, parser->m_declEntity->systemId,
+ parser->m_declEntity->publicId, parser->m_declEntity->notation);
handleDefault = XML_FALSE;
}
}
break;
- case XML_ROLE_GENERAL_ENTITY_NAME:
- {
- if (XmlPredefinedEntityName(enc, s, next)) {
- declEntity = NULL;
- break;
- }
- if (dtd->keepProcessing) {
- const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
- sizeof(ENTITY));
- if (!declEntity)
- return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
- poolDiscard(&dtd->pool);
- declEntity = NULL;
- }
- else {
- poolFinish(&dtd->pool);
- declEntity->publicId = NULL;
- declEntity->is_param = XML_FALSE;
- /* if we have a parent parser or are reading an internal parameter
- entity, then the entity declaration is not considered "internal"
- */
- declEntity->is_internal = !(parentParser || openInternalEntities);
- if (entityDeclHandler)
- handleDefault = XML_FALSE;
- }
- }
- else {
+ case XML_ROLE_GENERAL_ENTITY_NAME: {
+ if (XmlPredefinedEntityName(enc, s, next)) {
+ parser->m_declEntity = NULL;
+ break;
+ }
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (! name)
+ return XML_ERROR_NO_MEMORY;
+ parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities,
+ name, sizeof(ENTITY));
+ if (! parser->m_declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (parser->m_declEntity->name != name) {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
+ } else {
+ poolFinish(&dtd->pool);
+ parser->m_declEntity->publicId = NULL;
+ parser->m_declEntity->is_param = XML_FALSE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ parser->m_declEntity->is_internal
+ = ! (parser->m_parentParser || parser->m_openInternalEntities);
+ if (parser->m_entityDeclHandler)
+ handleDefault = XML_FALSE;
}
+ } else {
+ poolDiscard(&dtd->pool);
+ parser->m_declEntity = NULL;
}
- break;
+ } break;
case XML_ROLE_PARAM_ENTITY_NAME:
#ifdef XML_DTD
if (dtd->keepProcessing) {
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
- if (!name)
+ if (! name)
return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
- name, sizeof(ENTITY));
- if (!declEntity)
+ parser->m_declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ name, sizeof(ENTITY));
+ if (! parser->m_declEntity)
return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
+ if (parser->m_declEntity->name != name) {
poolDiscard(&dtd->pool);
- declEntity = NULL;
- }
- else {
+ parser->m_declEntity = NULL;
+ } else {
poolFinish(&dtd->pool);
- declEntity->publicId = NULL;
- declEntity->is_param = XML_TRUE;
+ parser->m_declEntity->publicId = NULL;
+ parser->m_declEntity->is_param = XML_TRUE;
/* if we have a parent parser or are reading an internal parameter
entity, then the entity declaration is not considered "internal"
*/
- declEntity->is_internal = !(parentParser || openInternalEntities);
- if (entityDeclHandler)
+ parser->m_declEntity->is_internal
+ = ! (parser->m_parentParser || parser->m_openInternalEntities);
+ if (parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
}
- }
- else {
+ } else {
poolDiscard(&dtd->pool);
- declEntity = NULL;
+ parser->m_declEntity = NULL;
}
-#else /* not XML_DTD */
- declEntity = NULL;
+#else /* not XML_DTD */
+ parser->m_declEntity = NULL;
#endif /* XML_DTD */
break;
case XML_ROLE_NOTATION_NAME:
- declNotationPublicId = NULL;
- declNotationName = NULL;
- if (notationDeclHandler) {
- declNotationName = poolStoreString(&tempPool, enc, s, next);
- if (!declNotationName)
+ parser->m_declNotationPublicId = NULL;
+ parser->m_declNotationName = NULL;
+ if (parser->m_notationDeclHandler) {
+ parser->m_declNotationName
+ = poolStoreString(&parser->m_tempPool, enc, s, next);
+ if (! parser->m_declNotationName)
return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_NOTATION_PUBLIC_ID:
- if (!XmlIsPublicId(enc, s, next, eventPP))
+ if (! XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
- if (declNotationName) { /* means notationDeclHandler != NULL */
- XML_Char *tem = poolStoreString(&tempPool,
- enc,
+ if (parser
+ ->m_declNotationName) { /* means m_notationDeclHandler != NULL */
+ XML_Char *tem = poolStoreString(&parser->m_tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (!tem)
+ if (! tem)
return XML_ERROR_NO_MEMORY;
normalizePublicId(tem);
- declNotationPublicId = tem;
- poolFinish(&tempPool);
+ parser->m_declNotationPublicId = tem;
+ poolFinish(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_NOTATION_SYSTEM_ID:
- if (declNotationName && notationDeclHandler) {
- const XML_Char *systemId
- = poolStoreString(&tempPool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!systemId)
+ if (parser->m_declNotationName && parser->m_notationDeclHandler) {
+ const XML_Char *systemId = poolStoreString(&parser->m_tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (! systemId)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
- systemId,
- declNotationPublicId);
+ parser->m_notationDeclHandler(
+ parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase,
+ systemId, parser->m_declNotationPublicId);
handleDefault = XML_FALSE;
}
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_NOTATION_NO_SYSTEM_ID:
- if (declNotationPublicId && notationDeclHandler) {
+ if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) {
*eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
- 0,
- declNotationPublicId);
+ parser->m_notationDeclHandler(
+ parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase,
+ 0, parser->m_declNotationPublicId);
handleDefault = XML_FALSE;
}
- poolClear(&tempPool);
+ poolClear(&parser->m_tempPool);
break;
case XML_ROLE_ERROR:
switch (tok) {
@@ -4416,90 +4758,95 @@ doProlog(XML_Parser parser,
return XML_ERROR_SYNTAX;
}
#ifdef XML_DTD
- case XML_ROLE_IGNORE_SECT:
- {
- enum XML_Error result;
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- handleDefault = XML_FALSE;
- result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
- if (result != XML_ERROR_NONE)
- return result;
- else if (!next) {
- processor = ignoreSectionProcessor;
- return result;
- }
+ case XML_ROLE_IGNORE_SECT: {
+ enum XML_Error result;
+ if (parser->m_defaultHandler)
+ reportDefault(parser, enc, s, next);
+ handleDefault = XML_FALSE;
+ result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (! next) {
+ parser->m_processor = ignoreSectionProcessor;
+ return result;
}
- break;
+ } break;
#endif /* XML_DTD */
case XML_ROLE_GROUP_OPEN:
- if (prologState.level >= groupSize) {
- if (groupSize) {
- char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
- if (temp == NULL)
- return XML_ERROR_NO_MEMORY;
- groupConnector = temp;
+ if (parser->m_prologState.level >= parser->m_groupSize) {
+ if (parser->m_groupSize) {
+ {
+ char *const new_connector = (char *)REALLOC(
+ parser, parser->m_groupConnector, parser->m_groupSize *= 2);
+ if (new_connector == NULL) {
+ parser->m_groupSize /= 2;
+ return XML_ERROR_NO_MEMORY;
+ }
+ parser->m_groupConnector = new_connector;
+ }
+
if (dtd->scaffIndex) {
- int *temp = (int *)REALLOC(dtd->scaffIndex,
- groupSize * sizeof(int));
- if (temp == NULL)
+ int *const new_scaff_index = (int *)REALLOC(
+ parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
+ if (new_scaff_index == NULL)
return XML_ERROR_NO_MEMORY;
- dtd->scaffIndex = temp;
+ dtd->scaffIndex = new_scaff_index;
}
- }
- else {
- groupConnector = (char *)MALLOC(groupSize = 32);
- if (!groupConnector)
+ } else {
+ parser->m_groupConnector
+ = (char *)MALLOC(parser, parser->m_groupSize = 32);
+ if (! parser->m_groupConnector) {
+ parser->m_groupSize = 0;
return XML_ERROR_NO_MEMORY;
+ }
}
}
- groupConnector[prologState.level] = 0;
+ parser->m_groupConnector[parser->m_prologState.level] = 0;
if (dtd->in_eldecl) {
int myindex = nextScaffoldPart(parser);
if (myindex < 0)
return XML_ERROR_NO_MEMORY;
+ assert(dtd->scaffIndex != NULL);
dtd->scaffIndex[dtd->scaffLevel] = myindex;
dtd->scaffLevel++;
dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
case XML_ROLE_GROUP_SEQUENCE:
- if (groupConnector[prologState.level] == ASCII_PIPE)
+ if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_PIPE)
return XML_ERROR_SYNTAX;
- groupConnector[prologState.level] = ASCII_COMMA;
- if (dtd->in_eldecl && elementDeclHandler)
+ parser->m_groupConnector[parser->m_prologState.level] = ASCII_COMMA;
+ if (dtd->in_eldecl && parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_GROUP_CHOICE:
- if (groupConnector[prologState.level] == ASCII_COMMA)
+ if (parser->m_groupConnector[parser->m_prologState.level] == ASCII_COMMA)
return XML_ERROR_SYNTAX;
if (dtd->in_eldecl
- && !groupConnector[prologState.level]
+ && ! parser->m_groupConnector[parser->m_prologState.level]
&& (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
- != XML_CTYPE_MIXED)
- ) {
+ != XML_CTYPE_MIXED)) {
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
= XML_CTYPE_CHOICE;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
- groupConnector[prologState.level] = ASCII_PIPE;
+ parser->m_groupConnector[parser->m_prologState.level] = ASCII_PIPE;
break;
case XML_ROLE_PARAM_ENTITY_REF:
#ifdef XML_DTD
case XML_ROLE_INNER_PARAM_ENTITY_REF:
dtd->hasParamEntityRefs = XML_TRUE;
- if (!paramEntityParsing)
+ if (! parser->m_paramEntityParsing)
dtd->keepProcessing = dtd->standalone;
else {
const XML_Char *name;
ENTITY *entity;
- name = poolStoreString(&dtd->pool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
+ name = poolStoreString(&dtd->pool, enc, s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (! name)
return XML_ERROR_NO_MEMORY;
entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
poolDiscard(&dtd->pool);
@@ -4507,20 +4854,40 @@ doProlog(XML_Parser parser,
if yes, check that the entity exists, and that it is internal,
otherwise call the skipped entity handler
*/
- if (prologState.documentEntity &&
- (dtd->standalone
- ? !openInternalEntities
- : !dtd->hasParamEntityRefs)) {
- if (!entity)
+ if (parser->m_prologState.documentEntity
+ && (dtd->standalone ? ! parser->m_openInternalEntities
+ : ! dtd->hasParamEntityRefs)) {
+ if (! entity)
return XML_ERROR_UNDEFINED_ENTITY;
- else if (!entity->is_internal)
- return XML_ERROR_ENTITY_DECLARED_IN_PE;
- }
- else if (!entity) {
+ else if (! entity->is_internal) {
+ /* It's hard to exhaustively search the code to be sure,
+ * but there doesn't seem to be a way of executing the
+ * following line. There are two cases:
+ *
+ * If 'standalone' is false, the DTD must have no
+ * parameter entities or we wouldn't have passed the outer
+ * 'if' statement. That measn the only entity in the hash
+ * table is the external subset name "#" which cannot be
+ * given as a parameter entity name in XML syntax, so the
+ * lookup must have returned NULL and we don't even reach
+ * the test for an internal entity.
+ *
+ * If 'standalone' is true, it does not seem to be
+ * possible to create entities taking this code path that
+ * are not internal entities, so fail the test above.
+ *
+ * Because this analysis is very uncertain, the code is
+ * being left in place and merely removed from the
+ * coverage test statistics.
+ */
+ return XML_ERROR_ENTITY_DECLARED_IN_PE; /* LCOV_EXCL_LINE */
+ }
+ } else if (! entity) {
dtd->keepProcessing = dtd->standalone;
/* cannot report skipped entities in declarations */
- if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
- skippedEntityHandler(handlerArg, name, 1);
+ if ((role == XML_ROLE_PARAM_ENTITY_REF)
+ && parser->m_skippedEntityHandler) {
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1);
handleDefault = XML_FALSE;
}
break;
@@ -4529,50 +4896,46 @@ doProlog(XML_Parser parser,
return XML_ERROR_RECURSIVE_ENTITY_REF;
if (entity->textPtr) {
enum XML_Error result;
- XML_Bool betweenDecl =
- (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+ XML_Bool betweenDecl
+ = (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
result = processInternalEntity(parser, entity, betweenDecl);
if (result != XML_ERROR_NONE)
return result;
handleDefault = XML_FALSE;
break;
}
- if (externalEntityRefHandler) {
+ if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- 0,
- entity->base,
- entity->systemId,
- entity->publicId)) {
+ if (! parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId)) {
entity->open = XML_FALSE;
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
}
entity->open = XML_FALSE;
handleDefault = XML_FALSE;
- if (!dtd->paramEntityRead) {
+ if (! dtd->paramEntityRead) {
dtd->keepProcessing = dtd->standalone;
break;
}
- }
- else {
+ } else {
dtd->keepProcessing = dtd->standalone;
break;
}
}
#endif /* XML_DTD */
- if (!dtd->standalone &&
- notStandaloneHandler &&
- !notStandaloneHandler(handlerArg))
+ if (! dtd->standalone && parser->m_notStandaloneHandler
+ && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
return XML_ERROR_NOT_STANDALONE;
break;
- /* Element declaration stuff */
+ /* Element declaration stuff */
case XML_ROLE_ELEMENT_NAME:
- if (elementDeclHandler) {
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
+ if (parser->m_elementDeclHandler) {
+ parser->m_declElementType = getElementType(parser, enc, s, next);
+ if (! parser->m_declElementType)
return XML_ERROR_NO_MEMORY;
dtd->scaffLevel = 0;
dtd->scaffCount = 0;
@@ -4584,19 +4947,20 @@ doProlog(XML_Parser parser,
case XML_ROLE_CONTENT_ANY:
case XML_ROLE_CONTENT_EMPTY:
if (dtd->in_eldecl) {
- if (elementDeclHandler) {
- XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
- if (!content)
+ if (parser->m_elementDeclHandler) {
+ XML_Content *content
+ = (XML_Content *)MALLOC(parser, sizeof(XML_Content));
+ if (! content)
return XML_ERROR_NO_MEMORY;
content->quant = XML_CQUANT_NONE;
content->name = NULL;
content->numchildren = 0;
content->children = NULL;
- content->type = ((role == XML_ROLE_CONTENT_ANY) ?
- XML_CTYPE_ANY :
- XML_CTYPE_EMPTY);
+ content->type = ((role == XML_ROLE_CONTENT_ANY) ? XML_CTYPE_ANY
+ : XML_CTYPE_EMPTY);
*eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, content);
+ parser->m_elementDeclHandler(
+ parser->m_handlerArg, parser->m_declElementType->name, content);
handleDefault = XML_FALSE;
}
dtd->in_eldecl = XML_FALSE;
@@ -4607,7 +4971,7 @@ doProlog(XML_Parser parser,
if (dtd->in_eldecl) {
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
= XML_CTYPE_MIXED;
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
@@ -4628,23 +4992,23 @@ doProlog(XML_Parser parser,
ELEMENT_TYPE *el;
const XML_Char *name;
int nameLen;
- const char *nxt = (quant == XML_CQUANT_NONE
- ? next
- : next - enc->minBytesPerChar);
+ const char *nxt
+ = (quant == XML_CQUANT_NONE ? next : next - enc->minBytesPerChar);
int myindex = nextScaffoldPart(parser);
if (myindex < 0)
return XML_ERROR_NO_MEMORY;
dtd->scaffold[myindex].type = XML_CTYPE_NAME;
dtd->scaffold[myindex].quant = quant;
el = getElementType(parser, enc, s, nxt);
- if (!el)
+ if (! el)
return XML_ERROR_NO_MEMORY;
name = el->name;
dtd->scaffold[myindex].name = name;
nameLen = 0;
- for (; name[nameLen++]; );
- dtd->contentStringLen += nameLen;
- if (elementDeclHandler)
+ for (; name[nameLen++];)
+ ;
+ dtd->contentStringLen += nameLen;
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
}
break;
@@ -4662,17 +5026,18 @@ doProlog(XML_Parser parser,
quant = XML_CQUANT_PLUS;
closeGroup:
if (dtd->in_eldecl) {
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
dtd->scaffLevel--;
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
if (dtd->scaffLevel == 0) {
- if (!handleDefault) {
+ if (! handleDefault) {
XML_Content *model = build_model(parser);
- if (!model)
+ if (! model)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, model);
+ parser->m_elementDeclHandler(
+ parser->m_handlerArg, parser->m_declElementType->name, model);
}
dtd->in_eldecl = XML_FALSE;
dtd->contentStringLen = 0;
@@ -4682,12 +5047,12 @@ doProlog(XML_Parser parser,
/* End element declaration stuff */
case XML_ROLE_PI:
- if (!reportProcessingInstruction(parser, enc, s, next))
+ if (! reportProcessingInstruction(parser, enc, s, next))
return XML_ERROR_NO_MEMORY;
handleDefault = XML_FALSE;
break;
case XML_ROLE_COMMENT:
- if (!reportComment(parser, enc, s, next))
+ if (! reportComment(parser, enc, s, next))
return XML_ERROR_NO_MEMORY;
handleDefault = XML_FALSE;
break;
@@ -4699,31 +5064,31 @@ doProlog(XML_Parser parser,
}
break;
case XML_ROLE_DOCTYPE_NONE:
- if (startDoctypeDeclHandler)
+ if (parser->m_startDoctypeDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ENTITY_NONE:
- if (dtd->keepProcessing && entityDeclHandler)
+ if (dtd->keepProcessing && parser->m_entityDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_NOTATION_NONE:
- if (notationDeclHandler)
+ if (parser->m_notationDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ATTLIST_NONE:
- if (dtd->keepProcessing && attlistDeclHandler)
+ if (dtd->keepProcessing && parser->m_attlistDeclHandler)
handleDefault = XML_FALSE;
break;
case XML_ROLE_ELEMENT_NONE:
- if (elementDeclHandler)
+ if (parser->m_elementDeclHandler)
handleDefault = XML_FALSE;
break;
} /* end of big switch */
- if (handleDefault && defaultHandler)
+ if (handleDefault && parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
- switch (ps_parsing) {
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
@@ -4738,23 +5103,20 @@ doProlog(XML_Parser parser,
}
static enum XML_Error PTRCALL
-epilogProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- processor = epilogProcessor;
- eventPtr = s;
+epilogProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
+ parser->m_processor = epilogProcessor;
+ parser->m_eventPtr = s;
for (;;) {
const char *next = NULL;
- int tok = XmlPrologTok(encoding, s, end, &next);
- eventEndPtr = next;
+ int tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ parser->m_eventEndPtr = next;
switch (tok) {
/* report partial linebreak - it might be the last token */
case -XML_TOK_PROLOG_S:
- if (defaultHandler) {
- reportDefault(parser, encoding, s, next);
- if (ps_parsing == XML_FINISHED)
+ if (parser->m_defaultHandler) {
+ reportDefault(parser, parser->m_encoding, s, next);
+ if (parser->m_parsingStatus.parsing == XML_FINISHED)
return XML_ERROR_ABORTED;
}
*nextPtr = next;
@@ -4763,28 +5125,28 @@ epilogProcessor(XML_Parser parser,
*nextPtr = s;
return XML_ERROR_NONE;
case XML_TOK_PROLOG_S:
- if (defaultHandler)
- reportDefault(parser, encoding, s, next);
+ if (parser->m_defaultHandler)
+ reportDefault(parser, parser->m_encoding, s, next);
break;
case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, encoding, s, next))
+ if (! reportProcessingInstruction(parser, parser->m_encoding, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_COMMENT:
- if (!reportComment(parser, encoding, s, next))
+ if (! reportComment(parser, parser->m_encoding, s, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_INVALID:
- eventPtr = next;
+ parser->m_eventPtr = next;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_PARTIAL:
- if (!ps_finalBuffer) {
+ if (! parser->m_parsingStatus.finalBuffer) {
*nextPtr = s;
return XML_ERROR_NONE;
}
return XML_ERROR_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
- if (!ps_finalBuffer) {
+ if (! parser->m_parsingStatus.finalBuffer) {
*nextPtr = s;
return XML_ERROR_NONE;
}
@@ -4792,167 +5154,162 @@ epilogProcessor(XML_Parser parser,
default:
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
}
- eventPtr = s = next;
- switch (ps_parsing) {
+ parser->m_eventPtr = s = next;
+ switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
- default: ;
+ default:;
}
}
}
static enum XML_Error
-processInternalEntity(XML_Parser parser, ENTITY *entity,
- XML_Bool betweenDecl)
-{
+processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
const char *textStart, *textEnd;
const char *next;
enum XML_Error result;
OPEN_INTERNAL_ENTITY *openEntity;
- if (freeInternalEntities) {
- openEntity = freeInternalEntities;
- freeInternalEntities = openEntity->next;
- }
- else {
- openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
- if (!openEntity)
+ if (parser->m_freeInternalEntities) {
+ openEntity = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity->next;
+ } else {
+ openEntity
+ = (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
+ if (! openEntity)
return XML_ERROR_NO_MEMORY;
}
entity->open = XML_TRUE;
entity->processed = 0;
- openEntity->next = openInternalEntities;
- openInternalEntities = openEntity;
+ openEntity->next = parser->m_openInternalEntities;
+ parser->m_openInternalEntities = openEntity;
openEntity->entity = entity;
- openEntity->startTagLevel = tagLevel;
+ openEntity->startTagLevel = parser->m_tagLevel;
openEntity->betweenDecl = betweenDecl;
openEntity->internalEventPtr = NULL;
openEntity->internalEventEndPtr = NULL;
- textStart = (char *)entity->textPtr;
- textEnd = (char *)(entity->textPtr + entity->textLen);
+ textStart = (const char *)entity->textPtr;
+ textEnd = (const char *)(entity->textPtr + entity->textLen);
+ /* Set a safe default value in case 'next' does not get set */
+ next = textStart;
#ifdef XML_DTD
if (entity->is_param) {
- int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
- result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
- next, &next, XML_FALSE);
- }
- else
+ int tok
+ = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
+ tok, next, &next, XML_FALSE, XML_FALSE);
+ } else
#endif /* XML_DTD */
- result = doContent(parser, tagLevel, internalEncoding, textStart,
- textEnd, &next, XML_FALSE);
+ result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
+ textStart, textEnd, &next, XML_FALSE);
if (result == XML_ERROR_NONE) {
- if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - textStart);
- processor = internalEntityProcessor;
- }
- else {
+ parser->m_processor = internalEntityProcessor;
+ } else {
entity->open = XML_FALSE;
- openInternalEntities = openEntity->next;
+ parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
}
}
return result;
}
static enum XML_Error PTRCALL
-internalEntityProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
+internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
ENTITY *entity;
const char *textStart, *textEnd;
const char *next;
enum XML_Error result;
- OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
- if (!openEntity)
+ OPEN_INTERNAL_ENTITY *openEntity = parser->m_openInternalEntities;
+ if (! openEntity)
return XML_ERROR_UNEXPECTED_STATE;
entity = openEntity->entity;
- textStart = ((char *)entity->textPtr) + entity->processed;
- textEnd = (char *)(entity->textPtr + entity->textLen);
+ textStart = ((const char *)entity->textPtr) + entity->processed;
+ textEnd = (const char *)(entity->textPtr + entity->textLen);
+ /* Set a safe default value in case 'next' does not get set */
+ next = textStart;
#ifdef XML_DTD
if (entity->is_param) {
- int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
- result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
- next, &next, XML_FALSE);
- }
- else
+ int tok
+ = XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
+ tok, next, &next, XML_FALSE, XML_TRUE);
+ } else
#endif /* XML_DTD */
- result = doContent(parser, openEntity->startTagLevel, internalEncoding,
- textStart, textEnd, &next, XML_FALSE);
+ result = doContent(parser, openEntity->startTagLevel,
+ parser->m_internalEncoding, textStart, textEnd, &next,
+ XML_FALSE);
if (result != XML_ERROR_NONE)
return result;
- else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
- entity->processed = (int)(next - (char *)entity->textPtr);
+ else if (textEnd != next
+ && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - (const char *)entity->textPtr);
return result;
- }
- else {
+ } else {
entity->open = XML_FALSE;
- openInternalEntities = openEntity->next;
+ parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
- openEntity->next = freeInternalEntities;
- freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeInternalEntities;
+ parser->m_freeInternalEntities = openEntity;
}
#ifdef XML_DTD
if (entity->is_param) {
int tok;
- processor = prologProcessor;
- tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next, nextPtr,
- (XML_Bool)!ps_finalBuffer);
- }
- else
+ parser->m_processor = prologProcessor;
+ tok = XmlPrologTok(parser->m_encoding, s, end, &next);
+ return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE);
+ } else
#endif /* XML_DTD */
{
- processor = contentProcessor;
+ parser->m_processor = contentProcessor;
/* see externalEntityContentProcessor vs contentProcessor */
- return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
- nextPtr, (XML_Bool)!ps_finalBuffer);
+ return doContent(parser, parser->m_parentParser ? 1 : 0, parser->m_encoding,
+ s, end, nextPtr,
+ (XML_Bool)! parser->m_parsingStatus.finalBuffer);
}
}
static enum XML_Error PTRCALL
-errorProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- return errorCode;
+errorProcessor(XML_Parser parser, const char *s, const char *end,
+ const char **nextPtr) {
+ UNUSED_P(s);
+ UNUSED_P(end);
+ UNUSED_P(nextPtr);
+ return parser->m_errorCode;
}
static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
- const char *ptr, const char *end,
- STRING_POOL *pool)
-{
- enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
- end, pool);
+ const char *ptr, const char *end, STRING_POOL *pool) {
+ enum XML_Error result
+ = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
if (result)
return result;
- if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+ if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
poolChop(pool);
- if (!poolAppendChar(pool, XML_T('\0')))
+ if (! poolAppendChar(pool, XML_T('\0')))
return XML_ERROR_NO_MEMORY;
return XML_ERROR_NONE;
}
static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
- const char *ptr, const char *end,
- STRING_POOL *pool)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+ const char *ptr, const char *end, STRING_POOL *pool) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
for (;;) {
const char *next;
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
@@ -4960,41 +5317,42 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
case XML_TOK_NONE:
return XML_ERROR_NONE;
case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = next;
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = ptr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_CHAR_REF:
- {
- XML_Char buf[XML_ENCODE_MAX];
- int i;
- int n = XmlCharRefNumber(enc, ptr);
- if (n < 0) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_BAD_CHAR_REF;
- }
- if (!isCdata
- && n == 0x20 /* space */
- && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
- break;
- n = XmlEncode(n, (ICHAR *)buf);
- if (!n) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_BAD_CHAR_REF;
- }
- for (i = 0; i < n; i++) {
- if (!poolAppendChar(pool, buf[i]))
- return XML_ERROR_NO_MEMORY;
- }
+ case XML_TOK_CHAR_REF: {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, ptr);
+ if (n < 0) {
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
}
- break;
+ if (! isCdata && n == 0x20 /* space */
+ && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ n = XmlEncode(n, (ICHAR *)buf);
+ /* The XmlEncode() functions can never return 0 here. That
+ * error return happens if the code point passed in is either
+ * negative or greater than or equal to 0x110000. The
+ * XmlCharRefNumber() functions will all return a number
+ * strictly less than 0x110000 or a negative value if an error
+ * occurred. The negative value is intercepted above, so
+ * XmlEncode() is never passed a value it might return an
+ * error for.
+ */
+ for (i = 0; i < n; i++) {
+ if (! poolAppendChar(pool, buf[i]))
+ return XML_ERROR_NO_MEMORY;
+ }
+ } break;
case XML_TOK_DATA_CHARS:
- if (!poolAppend(pool, enc, ptr, next))
+ if (! poolAppend(pool, enc, ptr, next))
return XML_ERROR_NO_MEMORY;
break;
case XML_TOK_TRAILING_CR:
@@ -5002,95 +5360,119 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
/* fall through */
case XML_TOK_ATTRIBUTE_VALUE_S:
case XML_TOK_DATA_NEWLINE:
- if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ if (! isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
break;
- if (!poolAppendChar(pool, 0x20))
+ if (! poolAppendChar(pool, 0x20))
return XML_ERROR_NO_MEMORY;
break;
- case XML_TOK_ENTITY_REF:
- {
- const XML_Char *name;
- ENTITY *entity;
- char checkEntityDecl;
- XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
- ptr + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (ch) {
- if (!poolAppendChar(pool, ch))
- return XML_ERROR_NO_MEMORY;
- break;
- }
- name = poolStoreString(&temp2Pool, enc,
- ptr + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
+ case XML_TOK_ENTITY_REF: {
+ const XML_Char *name;
+ ENTITY *entity;
+ char checkEntityDecl;
+ XML_Char ch = (XML_Char)XmlPredefinedEntityName(
+ enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar);
+ if (ch) {
+ if (! poolAppendChar(pool, ch))
return XML_ERROR_NO_MEMORY;
- entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
- poolDiscard(&temp2Pool);
- /* First, determine if a check for an existing declaration is needed;
- if yes, check that the entity exists, and that it is internal.
- */
- if (pool == &dtd->pool) /* are we called from prolog? */
- checkEntityDecl =
+ break;
+ }
+ name = poolStoreString(&parser->m_temp2Pool, enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (! name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+ poolDiscard(&parser->m_temp2Pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal.
+ */
+ if (pool == &dtd->pool) /* are we called from prolog? */
+ checkEntityDecl =
#ifdef XML_DTD
- prologState.documentEntity &&
+ parser->m_prologState.documentEntity &&
#endif /* XML_DTD */
- (dtd->standalone
- ? !openInternalEntities
- : !dtd->hasParamEntityRefs);
- else /* if (pool == &tempPool): we are called from content */
- checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
- if (checkEntityDecl) {
- if (!entity)
- return XML_ERROR_UNDEFINED_ENTITY;
- else if (!entity->is_internal)
- return XML_ERROR_ENTITY_DECLARED_IN_PE;
- }
- else if (!entity) {
- /* Cannot report skipped entity here - see comments on
- skippedEntityHandler.
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
- */
- /* Cannot call the default handler because this would be
- out of sync with the call to the startElementHandler.
- if ((pool == &tempPool) && defaultHandler)
- reportDefault(parser, enc, ptr, next);
- */
- break;
- }
- if (entity->open) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_RECURSIVE_ENTITY_REF;
- }
- if (entity->notation) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_BINARY_ENTITY_REF;
- }
- if (!entity->textPtr) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
- }
- else {
- enum XML_Error result;
- const XML_Char *textEnd = entity->textPtr + entity->textLen;
- entity->open = XML_TRUE;
- result = appendAttributeValue(parser, internalEncoding, isCdata,
- (char *)entity->textPtr,
- (char *)textEnd, pool);
- entity->open = XML_FALSE;
- if (result)
- return result;
+ (dtd->standalone ? ! parser->m_openInternalEntities
+ : ! dtd->hasParamEntityRefs);
+ else /* if (pool == &parser->m_tempPool): we are called from content */
+ checkEntityDecl = ! dtd->hasParamEntityRefs || dtd->standalone;
+ if (checkEntityDecl) {
+ if (! entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (! entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ } else if (! entity) {
+ /* Cannot report skipped entity here - see comments on
+ parser->m_skippedEntityHandler.
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
+ */
+ /* Cannot call the default handler because this would be
+ out of sync with the call to the startElementHandler.
+ if ((pool == &parser->m_tempPool) && parser->m_defaultHandler)
+ reportDefault(parser, enc, ptr, next);
+ */
+ break;
+ }
+ if (entity->open) {
+ if (enc == parser->m_encoding) {
+ /* It does not appear that this line can be executed.
+ *
+ * The "if (entity->open)" check catches recursive entity
+ * definitions. In order to be called with an open
+ * entity, it must have gone through this code before and
+ * been through the recursive call to
+ * appendAttributeValue() some lines below. That call
+ * sets the local encoding ("enc") to the parser's
+ * internal encoding (internal_utf8 or internal_utf16),
+ * which can never be the same as the principle encoding.
+ * It doesn't appear there is another code path that gets
+ * here with entity->open being TRUE.
+ *
+ * Since it is not certain that this logic is watertight,
+ * we keep the line and merely exclude it from coverage
+ * tests.
+ */
+ parser->m_eventPtr = ptr; /* LCOV_EXCL_LINE */
}
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
}
- break;
+ if (entity->notation) {
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
+ return XML_ERROR_BINARY_ENTITY_REF;
+ }
+ if (! entity->textPtr) {
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
+ return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+ } else {
+ enum XML_Error result;
+ const XML_Char *textEnd = entity->textPtr + entity->textLen;
+ entity->open = XML_TRUE;
+ result = appendAttributeValue(parser, parser->m_internalEncoding,
+ isCdata, (const char *)entity->textPtr,
+ (const char *)textEnd, pool);
+ entity->open = XML_FALSE;
+ if (result)
+ return result;
+ }
+ } break;
default:
- if (enc == encoding)
- eventPtr = ptr;
+ /* The only token returned by XmlAttributeValueTok() that does
+ * not have an explicit case here is XML_TOK_PARTIAL_CHAR.
+ * Getting that would require an entity name to contain an
+ * incomplete XML character (e.g. \xE2\x82); however previous
+ * tokenisers will have already recognised and rejected such
+ * names before XmlAttributeValueTok() gets a look-in. This
+ * default case should be retained as a safety net, but the code
+ * excluded from coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = ptr;
return XML_ERROR_UNEXPECTED_STATE;
+ /* LCOV_EXCL_STOP */
}
ptr = next;
}
@@ -5098,23 +5480,20 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
}
static enum XML_Error
-storeEntityValue(XML_Parser parser,
- const ENCODING *enc,
- const char *entityTextPtr,
- const char *entityTextEnd)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+storeEntityValue(XML_Parser parser, const ENCODING *enc,
+ const char *entityTextPtr, const char *entityTextEnd) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
#ifdef XML_DTD
- int oldInEntityValue = prologState.inEntityValue;
- prologState.inEntityValue = 1;
+ int oldInEntityValue = parser->m_prologState.inEntityValue;
+ parser->m_prologState.inEntityValue = 1;
#endif /* XML_DTD */
/* never return Null for the value argument in EntityDeclHandler,
since this would indicate an external entity; therefore we
have to make sure that entityValuePool.start is not null */
- if (!pool->blocks) {
- if (!poolGrow(pool))
+ if (! pool->blocks) {
+ if (! poolGrow(pool))
return XML_ERROR_NO_MEMORY;
}
@@ -5124,61 +5503,55 @@ storeEntityValue(XML_Parser parser,
switch (tok) {
case XML_TOK_PARAM_ENTITY_REF:
#ifdef XML_DTD
- if (isParamEntity || enc != encoding) {
+ if (parser->m_isParamEntity || enc != parser->m_encoding) {
const XML_Char *name;
ENTITY *entity;
- name = poolStoreString(&tempPool, enc,
+ name = poolStoreString(&parser->m_tempPool, enc,
entityTextPtr + enc->minBytesPerChar,
next - enc->minBytesPerChar);
- if (!name) {
+ if (! name) {
result = XML_ERROR_NO_MEMORY;
goto endEntityValue;
}
entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
- poolDiscard(&tempPool);
- if (!entity) {
+ poolDiscard(&parser->m_tempPool);
+ if (! entity) {
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */
/* cannot report skipped entity here - see comments on
- skippedEntityHandler
- if (skippedEntityHandler)
- skippedEntityHandler(handlerArg, name, 0);
+ parser->m_skippedEntityHandler
+ if (parser->m_skippedEntityHandler)
+ parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
*/
dtd->keepProcessing = dtd->standalone;
goto endEntityValue;
}
if (entity->open) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_RECURSIVE_ENTITY_REF;
goto endEntityValue;
}
if (entity->systemId) {
- if (externalEntityRefHandler) {
+ if (parser->m_externalEntityRefHandler) {
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- 0,
- entity->base,
- entity->systemId,
- entity->publicId)) {
+ if (! parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId)) {
entity->open = XML_FALSE;
result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
goto endEntityValue;
}
entity->open = XML_FALSE;
- if (!dtd->paramEntityRead)
+ if (! dtd->paramEntityRead)
dtd->keepProcessing = dtd->standalone;
- }
- else
+ } else
dtd->keepProcessing = dtd->standalone;
- }
- else {
+ } else {
entity->open = XML_TRUE;
- result = storeEntityValue(parser,
- internalEncoding,
- (char *)entity->textPtr,
- (char *)(entity->textPtr
- + entity->textLen));
+ result = storeEntityValue(
+ parser, parser->m_internalEncoding, (const char *)entity->textPtr,
+ (const char *)(entity->textPtr + entity->textLen));
entity->open = XML_FALSE;
if (result)
goto endEntityValue;
@@ -5188,7 +5561,7 @@ storeEntityValue(XML_Parser parser,
#endif /* XML_DTD */
/* In the internal subset, PE references are not legal
within markup declarations, e.g entity values in this case. */
- eventPtr = entityTextPtr;
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_PARAM_ENTITY_REF;
goto endEntityValue;
case XML_TOK_NONE:
@@ -5196,7 +5569,7 @@ storeEntityValue(XML_Parser parser,
goto endEntityValue;
case XML_TOK_ENTITY_REF:
case XML_TOK_DATA_CHARS:
- if (!poolAppend(pool, enc, entityTextPtr, next)) {
+ if (! poolAppend(pool, enc, entityTextPtr, next)) {
result = XML_ERROR_NO_MEMORY;
goto endEntityValue;
}
@@ -5205,67 +5578,75 @@ storeEntityValue(XML_Parser parser,
next = entityTextPtr + enc->minBytesPerChar;
/* fall through */
case XML_TOK_DATA_NEWLINE:
- if (pool->end == pool->ptr && !poolGrow(pool)) {
- result = XML_ERROR_NO_MEMORY;
+ if (pool->end == pool->ptr && ! poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
goto endEntityValue;
}
*(pool->ptr)++ = 0xA;
break;
- case XML_TOK_CHAR_REF:
- {
- XML_Char buf[XML_ENCODE_MAX];
- int i;
- int n = XmlCharRefNumber(enc, entityTextPtr);
- if (n < 0) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- result = XML_ERROR_BAD_CHAR_REF;
- goto endEntityValue;
- }
- n = XmlEncode(n, (ICHAR *)buf);
- if (!n) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- result = XML_ERROR_BAD_CHAR_REF;
+ case XML_TOK_CHAR_REF: {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, entityTextPtr);
+ if (n < 0) {
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
+ result = XML_ERROR_BAD_CHAR_REF;
+ goto endEntityValue;
+ }
+ n = XmlEncode(n, (ICHAR *)buf);
+ /* The XmlEncode() functions can never return 0 here. That
+ * error return happens if the code point passed in is either
+ * negative or greater than or equal to 0x110000. The
+ * XmlCharRefNumber() functions will all return a number
+ * strictly less than 0x110000 or a negative value if an error
+ * occurred. The negative value is intercepted above, so
+ * XmlEncode() is never passed a value it might return an
+ * error for.
+ */
+ for (i = 0; i < n; i++) {
+ if (pool->end == pool->ptr && ! poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
goto endEntityValue;
}
- for (i = 0; i < n; i++) {
- if (pool->end == pool->ptr && !poolGrow(pool)) {
- result = XML_ERROR_NO_MEMORY;
- goto endEntityValue;
- }
- *(pool->ptr)++ = buf[i];
- }
+ *(pool->ptr)++ = buf[i];
}
- break;
+ } break;
case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_INVALID_TOKEN;
goto endEntityValue;
case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = next;
result = XML_ERROR_INVALID_TOKEN;
goto endEntityValue;
default:
- if (enc == encoding)
- eventPtr = entityTextPtr;
+ /* This default case should be unnecessary -- all the tokens
+ * that XmlEntityValueTok() can return have their own explicit
+ * cases -- but should be retained for safety. We do however
+ * exclude it from the coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
+ if (enc == parser->m_encoding)
+ parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_UNEXPECTED_STATE;
goto endEntityValue;
+ /* LCOV_EXCL_STOP */
}
entityTextPtr = next;
}
endEntityValue:
#ifdef XML_DTD
- prologState.inEntityValue = oldInEntityValue;
+ parser->m_prologState.inEntityValue = oldInEntityValue;
#endif /* XML_DTD */
return result;
}
static void FASTCALL
-normalizeLines(XML_Char *s)
-{
+normalizeLines(XML_Char *s) {
XML_Char *p;
for (;; s++) {
if (*s == XML_T('\0'))
@@ -5279,8 +5660,7 @@ normalizeLines(XML_Char *s)
*p++ = 0xA;
if (*++s == 0xA)
s++;
- }
- else
+ } else
*p++ = *s++;
} while (*s);
*p = XML_T('\0');
@@ -5288,87 +5668,100 @@ normalizeLines(XML_Char *s)
static int
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
- const char *start, const char *end)
-{
+ const char *start, const char *end) {
const XML_Char *target;
XML_Char *data;
const char *tem;
- if (!processingInstructionHandler) {
- if (defaultHandler)
+ if (! parser->m_processingInstructionHandler) {
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, start, end);
return 1;
}
start += enc->minBytesPerChar * 2;
tem = start + XmlNameLength(enc, start);
- target = poolStoreString(&tempPool, enc, start, tem);
- if (!target)
+ target = poolStoreString(&parser->m_tempPool, enc, start, tem);
+ if (! target)
return 0;
- poolFinish(&tempPool);
- data = poolStoreString(&tempPool, enc,
- XmlSkipS(enc, tem),
- end - enc->minBytesPerChar*2);
- if (!data)
+ poolFinish(&parser->m_tempPool);
+ data = poolStoreString(&parser->m_tempPool, enc, XmlSkipS(enc, tem),
+ end - enc->minBytesPerChar * 2);
+ if (! data)
return 0;
normalizeLines(data);
- processingInstructionHandler(handlerArg, target, data);
- poolClear(&tempPool);
+ parser->m_processingInstructionHandler(parser->m_handlerArg, target, data);
+ poolClear(&parser->m_tempPool);
return 1;
}
static int
-reportComment(XML_Parser parser, const ENCODING *enc,
- const char *start, const char *end)
-{
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end) {
XML_Char *data;
- if (!commentHandler) {
- if (defaultHandler)
+ if (! parser->m_commentHandler) {
+ if (parser->m_defaultHandler)
reportDefault(parser, enc, start, end);
return 1;
}
- data = poolStoreString(&tempPool,
- enc,
+ data = poolStoreString(&parser->m_tempPool, enc,
start + enc->minBytesPerChar * 4,
end - enc->minBytesPerChar * 3);
- if (!data)
+ if (! data)
return 0;
normalizeLines(data);
- commentHandler(handlerArg, data);
- poolClear(&tempPool);
+ parser->m_commentHandler(parser->m_handlerArg, data);
+ poolClear(&parser->m_tempPool);
return 1;
}
static void
-reportDefault(XML_Parser parser, const ENCODING *enc,
- const char *s, const char *end)
-{
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *s,
+ const char *end) {
if (MUST_CONVERT(enc, s)) {
+ enum XML_Convert_Result convert_res;
const char **eventPP;
const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ if (enc == parser->m_encoding) {
+ eventPP = &parser->m_eventPtr;
+ eventEndPP = &parser->m_eventEndPtr;
+ } else {
+ /* To get here, two things must be true; the parser must be
+ * using a character encoding that is not the same as the
+ * encoding passed in, and the encoding passed in must need
+ * conversion to the internal format (UTF-8 unless XML_UNICODE
+ * is defined). The only occasions on which the encoding passed
+ * in is not the same as the parser's encoding are when it is
+ * the internal encoding (e.g. a previously defined parameter
+ * entity, already converted to internal format). This by
+ * definition doesn't need conversion, so the whole branch never
+ * gets executed.
+ *
+ * For safety's sake we don't delete these lines and merely
+ * exclude them from coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
+ eventPP = &(parser->m_openInternalEntities->internalEventPtr);
+ eventEndPP = &(parser->m_openInternalEntities->internalEventEndPtr);
+ /* LCOV_EXCL_STOP */
}
do {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
+ convert_res
+ = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
- defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+ parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf,
+ (int)(dataPtr - (ICHAR *)parser->m_dataBuf));
*eventPP = s;
- } while (s != end);
- }
- else
- defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+ } while ((convert_res != XML_CONVERT_COMPLETED)
+ && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
+ } else
+ parser->m_defaultHandler(parser->m_handlerArg, (XML_Char *)s,
+ (int)((XML_Char *)end - (XML_Char *)s));
}
-
static int
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
- XML_Bool isId, const XML_Char *value, XML_Parser parser)
-{
+ XML_Bool isId, const XML_Char *value, XML_Parser parser) {
DEFAULT_ATTRIBUTE *att;
if (value || isId) {
/* The handling of default attributes gets messed up if we have
@@ -5377,22 +5770,23 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
for (i = 0; i < type->nDefaultAtts; i++)
if (attId == type->defaultAtts[i].id)
return 1;
- if (isId && !type->idAtt && !attId->xmlns)
+ if (isId && ! type->idAtt && ! attId->xmlns)
type->idAtt = attId;
}
if (type->nDefaultAtts == type->allocDefaultAtts) {
if (type->allocDefaultAtts == 0) {
type->allocDefaultAtts = 8;
- type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
- * sizeof(DEFAULT_ATTRIBUTE));
- if (!type->defaultAtts)
+ type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(
+ parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ if (! type->defaultAtts) {
+ type->allocDefaultAtts = 0;
return 0;
- }
- else {
+ }
+ } else {
DEFAULT_ATTRIBUTE *temp;
int count = type->allocDefaultAtts * 2;
- temp = (DEFAULT_ATTRIBUTE *)
- REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ temp = (DEFAULT_ATTRIBUTE *)REALLOC(parser, type->defaultAtts,
+ (count * sizeof(DEFAULT_ATTRIBUTE)));
if (temp == NULL)
return 0;
type->allocDefaultAtts = count;
@@ -5403,92 +5797,89 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
att->id = attId;
att->value = value;
att->isCdata = isCdata;
- if (!isCdata)
+ if (! isCdata)
attId->maybeTokenized = XML_TRUE;
type->nDefaultAtts += 1;
return 1;
}
static int
-setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *name;
for (name = elementType->name; *name; name++) {
if (*name == XML_T(ASCII_COLON)) {
PREFIX *prefix;
const XML_Char *s;
for (s = elementType->name; s != name; s++) {
- if (!poolAppendChar(&dtd->pool, *s))
+ if (! poolAppendChar(&dtd->pool, *s))
return 0;
}
- if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ if (! poolAppendChar(&dtd->pool, XML_T('\0')))
return 0;
prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
sizeof(PREFIX));
- if (!prefix)
+ if (! prefix)
return 0;
if (prefix->name == poolStart(&dtd->pool))
poolFinish(&dtd->pool);
else
poolDiscard(&dtd->pool);
elementType->prefix = prefix;
-
+ break;
}
}
return 1;
}
static ATTRIBUTE_ID *
-getAttributeId(XML_Parser parser, const ENCODING *enc,
- const char *start, const char *end)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
ATTRIBUTE_ID *id;
const XML_Char *name;
- if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ if (! poolAppendChar(&dtd->pool, XML_T('\0')))
return NULL;
name = poolStoreString(&dtd->pool, enc, start, end);
- if (!name)
+ if (! name)
return NULL;
/* skip quotation mark - its storage will be re-used (like in name[-1]) */
++name;
- id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
- if (!id)
+ id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name,
+ sizeof(ATTRIBUTE_ID));
+ if (! id)
return NULL;
if (id->name != name)
poolDiscard(&dtd->pool);
else {
poolFinish(&dtd->pool);
- if (!ns)
+ if (! parser->m_ns)
;
- else if (name[0] == XML_T(ASCII_x)
- && name[1] == XML_T(ASCII_m)
- && name[2] == XML_T(ASCII_l)
- && name[3] == XML_T(ASCII_n)
- && name[4] == XML_T(ASCII_s)
- && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
+ else if (name[0] == XML_T(ASCII_x) && name[1] == XML_T(ASCII_m)
+ && name[2] == XML_T(ASCII_l) && name[3] == XML_T(ASCII_n)
+ && name[4] == XML_T(ASCII_s)
+ && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
if (name[5] == XML_T('\0'))
id->prefix = &dtd->defaultPrefix;
else
- id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
+ id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6,
+ sizeof(PREFIX));
id->xmlns = XML_TRUE;
- }
- else {
+ } else {
int i;
for (i = 0; name[i]; i++) {
/* attributes without prefix are *not* in the default namespace */
if (name[i] == XML_T(ASCII_COLON)) {
int j;
for (j = 0; j < i; j++) {
- if (!poolAppendChar(&dtd->pool, name[j]))
+ if (! poolAppendChar(&dtd->pool, name[j]))
return NULL;
}
- if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ if (! poolAppendChar(&dtd->pool, XML_T('\0')))
return NULL;
- id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
- sizeof(PREFIX));
- if (!id->prefix)
+ id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes,
+ poolStart(&dtd->pool), sizeof(PREFIX));
+ if (! id->prefix)
return NULL;
if (id->prefix->name == poolStart(&dtd->pool))
poolFinish(&dtd->pool);
@@ -5505,23 +5896,44 @@ getAttributeId(XML_Parser parser, const ENCODING *enc,
#define CONTEXT_SEP XML_T(ASCII_FF)
static const XML_Char *
-getContext(XML_Parser parser)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+getContext(XML_Parser parser) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
HASH_TABLE_ITER iter;
XML_Bool needSep = XML_FALSE;
if (dtd->defaultPrefix.binding) {
int i;
int len;
- if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
len = dtd->defaultPrefix.binding->uriLen;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len--;
- for (i = 0; i < len; i++)
- if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i]))
- return NULL;
+ for (i = 0; i < len; i++) {
+ if (! poolAppendChar(&parser->m_tempPool,
+ dtd->defaultPrefix.binding->uri[i])) {
+ /* Because of memory caching, I don't believe this line can be
+ * executed.
+ *
+ * This is part of a loop copying the default prefix binding
+ * URI into the parser's temporary string pool. Previously,
+ * that URI was copied into the same string pool, with a
+ * terminating NUL character, as part of setContext(). When
+ * the pool was cleared, that leaves a block definitely big
+ * enough to hold the URI on the free block list of the pool.
+ * The URI copy in getContext() therefore cannot run out of
+ * memory.
+ *
+ * If the pool is used between the setContext() and
+ * getContext() calls, the worst it can do is leave a bigger
+ * block on the front of the free list. Given that this is
+ * all somewhat inobvious and program logic can be changed, we
+ * don't delete the line but we do exclude it from the test
+ * coverage statistics.
+ */
+ return NULL; /* LCOV_EXCL_LINE */
+ }
+ }
needSep = XML_TRUE;
}
@@ -5531,102 +5943,107 @@ getContext(XML_Parser parser)
int len;
const XML_Char *s;
PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
- if (!prefix)
+ if (! prefix)
break;
- if (!prefix->binding)
- continue;
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ if (! prefix->binding) {
+ /* This test appears to be (justifiable) paranoia. There does
+ * not seem to be a way of injecting a prefix without a binding
+ * that doesn't get errored long before this function is called.
+ * The test should remain for safety's sake, so we instead
+ * exclude the following line from the coverage statistics.
+ */
+ continue; /* LCOV_EXCL_LINE */
+ }
+ if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
for (s = prefix->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
+ if (! poolAppendChar(&parser->m_tempPool, *s))
return NULL;
- if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
len = prefix->binding->uriLen;
- if (namespaceSeparator)
+ if (parser->m_namespaceSeparator)
len--;
for (i = 0; i < len; i++)
- if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ if (! poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i]))
return NULL;
needSep = XML_TRUE;
}
-
hashTableIterInit(&iter, &(dtd->generalEntities));
for (;;) {
const XML_Char *s;
ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
- if (!e)
+ if (! e)
break;
- if (!e->open)
+ if (! e->open)
continue;
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
for (s = e->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
+ if (! poolAppendChar(&parser->m_tempPool, *s))
return 0;
needSep = XML_TRUE;
}
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return NULL;
- return tempPool.start;
+ return parser->m_tempPool.start;
}
static XML_Bool
-setContext(XML_Parser parser, const XML_Char *context)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+setContext(XML_Parser parser, const XML_Char *context) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *s = context;
while (*context != XML_T('\0')) {
if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
ENTITY *e;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+ e = (ENTITY *)lookup(parser, &dtd->generalEntities,
+ poolStart(&parser->m_tempPool), 0);
if (e)
e->open = XML_TRUE;
if (*s != XML_T('\0'))
s++;
context = s;
- poolDiscard(&tempPool);
- }
- else if (*s == XML_T(ASCII_EQUALS)) {
+ poolDiscard(&parser->m_tempPool);
+ } else if (*s == XML_T(ASCII_EQUALS)) {
PREFIX *prefix;
- if (poolLength(&tempPool) == 0)
+ if (poolLength(&parser->m_tempPool) == 0)
prefix = &dtd->defaultPrefix;
else {
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
- sizeof(PREFIX));
- if (!prefix)
+ prefix
+ = (PREFIX *)lookup(parser, &dtd->prefixes,
+ poolStart(&parser->m_tempPool), sizeof(PREFIX));
+ if (! prefix)
return XML_FALSE;
- if (prefix->name == poolStart(&tempPool)) {
+ if (prefix->name == poolStart(&parser->m_tempPool)) {
prefix->name = poolCopyString(&dtd->pool, prefix->name);
- if (!prefix->name)
+ if (! prefix->name)
return XML_FALSE;
}
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
}
- for (context = s + 1;
- *context != CONTEXT_SEP && *context != XML_T('\0');
+ for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0');
context++)
- if (!poolAppendChar(&tempPool, *context))
+ if (! poolAppendChar(&parser->m_tempPool, *context))
return XML_FALSE;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
+ if (! poolAppendChar(&parser->m_tempPool, XML_T('\0')))
return XML_FALSE;
- if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
- &inheritedBindings) != XML_ERROR_NONE)
+ if (addBinding(parser, prefix, NULL, poolStart(&parser->m_tempPool),
+ &parser->m_inheritedBindings)
+ != XML_ERROR_NONE)
return XML_FALSE;
- poolDiscard(&tempPool);
+ poolDiscard(&parser->m_tempPool);
if (*context != XML_T('\0'))
++context;
s = context;
- }
- else {
- if (!poolAppendChar(&tempPool, *s))
+ } else {
+ if (! poolAppendChar(&parser->m_tempPool, *s))
return XML_FALSE;
s++;
}
@@ -5635,8 +6052,7 @@ setContext(XML_Parser parser, const XML_Char *context)
}
static void FASTCALL
-normalizePublicId(XML_Char *publicId)
-{
+normalizePublicId(XML_Char *publicId) {
XML_Char *p = publicId;
XML_Char *s;
for (s = publicId; *s; s++) {
@@ -5657,8 +6073,7 @@ normalizePublicId(XML_Char *publicId)
}
static DTD *
-dtdCreate(const XML_Memory_Handling_Suite *ms)
-{
+dtdCreate(const XML_Memory_Handling_Suite *ms) {
DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
if (p == NULL)
return p;
@@ -5690,13 +6105,12 @@ dtdCreate(const XML_Memory_Handling_Suite *ms)
}
static void
-dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
-{
+dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) {
HASH_TABLE_ITER iter;
hashTableIterInit(&iter, &(p->elementTypes));
for (;;) {
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
- if (!e)
+ if (! e)
break;
if (e->allocDefaultAtts != 0)
ms->free_fcn(e->defaultAtts);
@@ -5732,13 +6146,12 @@ dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
}
static void
-dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
-{
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) {
HASH_TABLE_ITER iter;
hashTableIterInit(&iter, &(p->elementTypes));
for (;;) {
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
- if (!e)
+ if (! e)
break;
if (e->allocDefaultAtts != 0)
ms->free_fcn(e->defaultAtts);
@@ -5763,8 +6176,8 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
The new DTD has already been initialized.
*/
static int
-dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
-{
+dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd,
+ const XML_Memory_Handling_Suite *ms) {
HASH_TABLE_ITER iter;
/* Copy the prefix table. */
@@ -5773,12 +6186,12 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_H
for (;;) {
const XML_Char *name;
const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
- if (!oldP)
+ if (! oldP)
break;
name = poolCopyString(&(newDtd->pool), oldP->name);
- if (!name)
+ if (! name)
return 0;
- if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
+ if (! lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
return 0;
}
@@ -5791,18 +6204,18 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_H
const XML_Char *name;
const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
- if (!oldA)
+ if (! oldA)
break;
/* Remember to allocate the scratch byte before the name. */
- if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+ if (! poolAppendChar(&(newDtd->pool), XML_T('\0')))
return 0;
name = poolCopyString(&(newDtd->pool), oldA->name);
- if (!name)
+ if (! name)
return 0;
++name;
newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
sizeof(ATTRIBUTE_ID));
- if (!newA)
+ if (! newA)
return 0;
newA->maybeTokenized = oldA->maybeTokenized;
if (oldA->prefix) {
@@ -5824,58 +6237,52 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_H
ELEMENT_TYPE *newE;
const XML_Char *name;
const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
- if (!oldE)
+ if (! oldE)
break;
name = poolCopyString(&(newDtd->pool), oldE->name);
- if (!name)
+ if (! name)
return 0;
newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
sizeof(ELEMENT_TYPE));
- if (!newE)
+ if (! newE)
return 0;
if (oldE->nDefaultAtts) {
- newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
- ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
- if (!newE->defaultAtts) {
- ms->free_fcn(newE);
+ newE->defaultAtts = (DEFAULT_ATTRIBUTE *)ms->malloc_fcn(
+ oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ if (! newE->defaultAtts) {
return 0;
}
}
if (oldE->idAtt)
- newE->idAtt = (ATTRIBUTE_ID *)
- lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
+ newE->idAtt = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds),
+ oldE->idAtt->name, 0);
newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
if (oldE->prefix)
newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
oldE->prefix->name, 0);
for (i = 0; i < newE->nDefaultAtts; i++) {
- newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
- lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(
+ oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
if (oldE->defaultAtts[i].value) {
newE->defaultAtts[i].value
= poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
- if (!newE->defaultAtts[i].value)
+ if (! newE->defaultAtts[i].value)
return 0;
- }
- else
+ } else
newE->defaultAtts[i].value = NULL;
}
}
/* Copy the entity tables. */
- if (!copyEntityTable(oldParser,
- &(newDtd->generalEntities),
- &(newDtd->pool),
- &(oldDtd->generalEntities)))
- return 0;
+ if (! copyEntityTable(oldParser, &(newDtd->generalEntities), &(newDtd->pool),
+ &(oldDtd->generalEntities)))
+ return 0;
#ifdef XML_DTD
- if (!copyEntityTable(oldParser,
- &(newDtd->paramEntities),
- &(newDtd->pool),
- &(oldDtd->paramEntities)))
- return 0;
+ if (! copyEntityTable(oldParser, &(newDtd->paramEntities), &(newDtd->pool),
+ &(oldDtd->paramEntities)))
+ return 0;
newDtd->paramEntityRead = oldDtd->paramEntityRead;
#endif /* XML_DTD */
@@ -5892,14 +6299,11 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_H
newDtd->scaffIndex = oldDtd->scaffIndex;
return 1;
-} /* End dtdCopy */
+} /* End dtdCopy */
static int
-copyEntityTable(XML_Parser oldParser,
- HASH_TABLE *newTable,
- STRING_POOL *newPool,
- const HASH_TABLE *oldTable)
-{
+copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable,
+ STRING_POOL *newPool, const HASH_TABLE *oldTable) {
HASH_TABLE_ITER iter;
const XML_Char *cachedOldBase = NULL;
const XML_Char *cachedNewBase = NULL;
@@ -5910,17 +6314,17 @@ copyEntityTable(XML_Parser oldParser,
ENTITY *newE;
const XML_Char *name;
const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
- if (!oldE)
+ if (! oldE)
break;
name = poolCopyString(newPool, oldE->name);
- if (!name)
+ if (! name)
return 0;
newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
- if (!newE)
+ if (! newE)
return 0;
if (oldE->systemId) {
const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
- if (!tem)
+ if (! tem)
return 0;
newE->systemId = tem;
if (oldE->base) {
@@ -5929,29 +6333,28 @@ copyEntityTable(XML_Parser oldParser,
else {
cachedOldBase = oldE->base;
tem = poolCopyString(newPool, cachedOldBase);
- if (!tem)
+ if (! tem)
return 0;
cachedNewBase = newE->base = tem;
}
}
if (oldE->publicId) {
tem = poolCopyString(newPool, oldE->publicId);
- if (!tem)
+ if (! tem)
return 0;
newE->publicId = tem;
}
- }
- else {
- const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
- oldE->textLen);
- if (!tem)
+ } else {
+ const XML_Char *tem
+ = poolCopyStringN(newPool, oldE->textPtr, oldE->textLen);
+ if (! tem)
return 0;
newE->textPtr = tem;
newE->textLen = oldE->textLen;
}
if (oldE->notation) {
const XML_Char *tem = poolCopyString(newPool, oldE->notation);
- if (!tem)
+ if (! tem)
return 0;
newE->notation = tem;
}
@@ -5964,44 +6367,57 @@ copyEntityTable(XML_Parser oldParser,
#define INIT_POWER 6
static XML_Bool FASTCALL
-keyeq(KEY s1, KEY s2)
-{
+keyeq(KEY s1, KEY s2) {
for (; *s1 == *s2; s1++, s2++)
if (*s1 == 0)
return XML_TRUE;
return XML_FALSE;
}
+static size_t
+keylen(KEY s) {
+ size_t len = 0;
+ for (; *s; s++, len++)
+ ;
+ return len;
+}
+
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key) {
+ key->k[0] = 0;
+ key->k[1] = get_hash_secret_salt(parser);
+}
+
static unsigned long FASTCALL
-hash(XML_Parser parser, KEY s)
-{
- unsigned long h = hash_secret_salt;
- while (*s)
- h = CHAR_HASH(h, *s++);
- return h;
+hash(XML_Parser parser, KEY s) {
+ struct siphash state;
+ struct sipkey key;
+ (void)sip24_valid;
+ copy_salt_to_sipkey(parser, &key);
+ sip24_init(&state, &key);
+ sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
+ return (unsigned long)sip24_final(&state);
}
static NAMED *
-lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
-{
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) {
size_t i;
if (table->size == 0) {
size_t tsize;
- if (!createSize)
+ if (! createSize)
return NULL;
table->power = INIT_POWER;
/* table->size is a power of 2 */
table->size = (size_t)1 << INIT_POWER;
tsize = table->size * sizeof(NAMED *);
table->v = (NAMED **)table->mem->malloc_fcn(tsize);
- if (!table->v) {
+ if (! table->v) {
table->size = 0;
return NULL;
}
memset(table->v, 0, tsize);
i = hash(parser, name) & ((unsigned long)table->size - 1);
- }
- else {
+ } else {
unsigned long h = hash(parser, name);
unsigned long mask = (unsigned long)table->size - 1;
unsigned char step = 0;
@@ -6009,11 +6425,11 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
while (table->v[i]) {
if (keyeq(name, table->v[i]->name))
return table->v[i];
- if (!step)
+ if (! step)
step = PROBE_STEP(h, mask, table->power);
i < step ? (i += table->size - step) : (i -= step);
}
- if (!createSize)
+ if (! createSize)
return NULL;
/* check for overflow (table is half full) */
@@ -6023,7 +6439,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
unsigned long newMask = (unsigned long)newSize - 1;
size_t tsize = newSize * sizeof(NAMED *);
NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
- if (!newV)
+ if (! newV)
return NULL;
memset(newV, 0, tsize);
for (i = 0; i < table->size; i++)
@@ -6032,7 +6448,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
size_t j = newHash & newMask;
step = 0;
while (newV[j]) {
- if (!step)
+ if (! step)
step = PROBE_STEP(newHash, newMask, newPower);
j < step ? (j += newSize - step) : (j -= step);
}
@@ -6045,14 +6461,14 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
i = h & newMask;
step = 0;
while (table->v[i]) {
- if (!step)
+ if (! step)
step = PROBE_STEP(h, newMask, newPower);
i < step ? (i += newSize - step) : (i -= step);
}
}
}
table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
- if (!table->v[i])
+ if (! table->v[i])
return NULL;
memset(table->v[i], 0, createSize);
table->v[i]->name = name;
@@ -6061,8 +6477,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
}
static void FASTCALL
-hashTableClear(HASH_TABLE *table)
-{
+hashTableClear(HASH_TABLE *table) {
size_t i;
for (i = 0; i < table->size; i++) {
table->mem->free_fcn(table->v[i]);
@@ -6072,8 +6487,7 @@ hashTableClear(HASH_TABLE *table)
}
static void FASTCALL
-hashTableDestroy(HASH_TABLE *table)
-{
+hashTableDestroy(HASH_TABLE *table) {
size_t i;
for (i = 0; i < table->size; i++)
table->mem->free_fcn(table->v[i]);
@@ -6081,8 +6495,7 @@ hashTableDestroy(HASH_TABLE *table)
}
static void FASTCALL
-hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
-{
+hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) {
p->power = 0;
p->size = 0;
p->used = 0;
@@ -6091,15 +6504,13 @@ hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
}
static void FASTCALL
-hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
-{
+hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) {
iter->p = table->v;
- iter->end = iter->p + table->size;
+ iter->end = iter->p ? iter->p + table->size : NULL;
}
-static NAMED * FASTCALL
-hashTableIterNext(HASH_TABLE_ITER *iter)
-{
+static NAMED *FASTCALL
+hashTableIterNext(HASH_TABLE_ITER *iter) {
while (iter->p != iter->end) {
NAMED *tem = *(iter->p)++;
if (tem)
@@ -6109,8 +6520,7 @@ hashTableIterNext(HASH_TABLE_ITER *iter)
}
static void FASTCALL
-poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
-{
+poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) {
pool->blocks = NULL;
pool->freeBlocks = NULL;
pool->start = NULL;
@@ -6120,9 +6530,8 @@ poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
}
static void FASTCALL
-poolClear(STRING_POOL *pool)
-{
- if (!pool->freeBlocks)
+poolClear(STRING_POOL *pool) {
+ if (! pool->freeBlocks)
pool->freeBlocks = pool->blocks;
else {
BLOCK *p = pool->blocks;
@@ -6140,8 +6549,7 @@ poolClear(STRING_POOL *pool)
}
static void FASTCALL
-poolDestroy(STRING_POOL *pool)
-{
+poolDestroy(STRING_POOL *pool) {
BLOCK *p = pool->blocks;
while (p) {
BLOCK *tem = p->next;
@@ -6157,26 +6565,26 @@ poolDestroy(STRING_POOL *pool)
}
static XML_Char *
-poolAppend(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end)
-{
- if (!pool->ptr && !poolGrow(pool))
+poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
+ const char *end) {
+ if (! pool->ptr && ! poolGrow(pool))
return NULL;
for (;;) {
- XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
- if (ptr == end)
+ const enum XML_Convert_Result convert_res = XmlConvert(
+ enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+ if ((convert_res == XML_CONVERT_COMPLETED)
+ || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
- if (!poolGrow(pool))
+ if (! poolGrow(pool))
return NULL;
}
return pool->start;
}
-static const XML_Char * FASTCALL
-poolCopyString(STRING_POOL *pool, const XML_Char *s)
-{
+static const XML_Char *FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s) {
do {
- if (!poolAppendChar(pool, *s))
+ if (! poolAppendChar(pool, *s))
return NULL;
} while (*s++);
s = pool->start;
@@ -6185,12 +6593,23 @@ poolCopyString(STRING_POOL *pool, const XML_Char *s)
}
static const XML_Char *
-poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
-{
- if (!pool->ptr && !poolGrow(pool))
- return NULL;
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) {
+ if (! pool->ptr && ! poolGrow(pool)) {
+ /* The following line is unreachable given the current usage of
+ * poolCopyStringN(). Currently it is called from exactly one
+ * place to copy the text of a simple general entity. By that
+ * point, the name of the entity is already stored in the pool, so
+ * pool->ptr cannot be NULL.
+ *
+ * If poolCopyStringN() is used elsewhere as it well might be,
+ * this line may well become executable again. Regardless, this
+ * sort of check shouldn't be removed lightly, so we just exclude
+ * it from the coverage statistics.
+ */
+ return NULL; /* LCOV_EXCL_LINE */
+ }
for (; n > 0; --n, s++) {
- if (!poolAppendChar(pool, *s))
+ if (! poolAppendChar(pool, *s))
return NULL;
}
s = pool->start;
@@ -6198,11 +6617,10 @@ poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
return s;
}
-static const XML_Char * FASTCALL
-poolAppendString(STRING_POOL *pool, const XML_Char *s)
-{
+static const XML_Char *FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s) {
while (*s) {
- if (!poolAppendChar(pool, *s))
+ if (! poolAppendChar(pool, *s))
return NULL;
s++;
}
@@ -6210,20 +6628,46 @@ poolAppendString(STRING_POOL *pool, const XML_Char *s)
}
static XML_Char *
-poolStoreString(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end)
-{
- if (!poolAppend(pool, enc, ptr, end))
+poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr,
+ const char *end) {
+ if (! poolAppend(pool, enc, ptr, end))
return NULL;
- if (pool->ptr == pool->end && !poolGrow(pool))
+ if (pool->ptr == pool->end && ! poolGrow(pool))
return NULL;
*(pool->ptr)++ = 0;
return pool->start;
}
+static size_t
+poolBytesToAllocateFor(int blockSize) {
+ /* Unprotected math would be:
+ ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char);
+ **
+ ** Detect overflow, avoiding _signed_ overflow undefined behavior
+ ** For a + b * c we check b * c in isolation first, so that addition of a
+ ** on top has no chance of making us accept a small non-negative number
+ */
+ const size_t stretch = sizeof(XML_Char); /* can be 4 bytes */
+
+ if (blockSize <= 0)
+ return 0;
+
+ if (blockSize > (int)(INT_MAX / stretch))
+ return 0;
+
+ {
+ const int stretchedBlockSize = blockSize * (int)stretch;
+ const int bytesToAllocate
+ = (int)(offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
+ if (bytesToAllocate < 0)
+ return 0;
+
+ return (size_t)bytesToAllocate;
+ }
+}
+
static XML_Bool FASTCALL
-poolGrow(STRING_POOL *pool)
-{
+poolGrow(STRING_POOL *pool) {
if (pool->freeBlocks) {
if (pool->start == 0) {
pool->blocks = pool->freeBlocks;
@@ -6248,36 +6692,77 @@ poolGrow(STRING_POOL *pool)
}
}
if (pool->blocks && pool->start == pool->blocks->s) {
- int blockSize = (int)(pool->end - pool->start)*2;
- BLOCK *temp = (BLOCK *)
- pool->mem->realloc_fcn(pool->blocks,
- (offsetof(BLOCK, s)
- + blockSize * sizeof(XML_Char)));
+ BLOCK *temp;
+ int blockSize = (int)((unsigned)(pool->end - pool->start) * 2U);
+ size_t bytesToAllocate;
+
+ /* NOTE: Needs to be calculated prior to calling `realloc`
+ to avoid dangling pointers: */
+ const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
+
+ if (blockSize < 0) {
+ /* This condition traps a situation where either more than
+ * INT_MAX/2 bytes have already been allocated. This isn't
+ * readily testable, since it is unlikely that an average
+ * machine will have that much memory, so we exclude it from the
+ * coverage statistics.
+ */
+ return XML_FALSE; /* LCOV_EXCL_LINE */
+ }
+
+ bytesToAllocate = poolBytesToAllocateFor(blockSize);
+ if (bytesToAllocate == 0)
+ return XML_FALSE;
+
+ temp = (BLOCK *)pool->mem->realloc_fcn(pool->blocks,
+ (unsigned)bytesToAllocate);
if (temp == NULL)
return XML_FALSE;
pool->blocks = temp;
pool->blocks->size = blockSize;
- pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->ptr = pool->blocks->s + offsetInsideBlock;
pool->start = pool->blocks->s;
pool->end = pool->start + blockSize;
- }
- else {
+ } else {
BLOCK *tem;
int blockSize = (int)(pool->end - pool->start);
+ size_t bytesToAllocate;
+
+ if (blockSize < 0) {
+ /* This condition traps a situation where either more than
+ * INT_MAX bytes have already been allocated (which is prevented
+ * by various pieces of program logic, not least this one, never
+ * mind the unlikelihood of actually having that much memory) or
+ * the pool control fields have been corrupted (which could
+ * conceivably happen in an extremely buggy user handler
+ * function). Either way it isn't readily testable, so we
+ * exclude it from the coverage statistics.
+ */
+ return XML_FALSE; /* LCOV_EXCL_LINE */
+ }
+
if (blockSize < INIT_BLOCK_SIZE)
blockSize = INIT_BLOCK_SIZE;
- else
+ else {
+ /* Detect overflow, avoiding _signed_ overflow undefined behavior */
+ if ((int)((unsigned)blockSize * 2U) < 0) {
+ return XML_FALSE;
+ }
blockSize *= 2;
- tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
- + blockSize * sizeof(XML_Char));
- if (!tem)
+ }
+
+ bytesToAllocate = poolBytesToAllocateFor(blockSize);
+ if (bytesToAllocate == 0)
+ return XML_FALSE;
+
+ tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
+ if (! tem)
return XML_FALSE;
tem->size = blockSize;
tem->next = pool->blocks;
pool->blocks = tem;
if (pool->ptr != pool->start)
- memcpy(tem->s, pool->start,
- (pool->ptr - pool->start) * sizeof(XML_Char));
+ memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char));
pool->ptr = tem->s + (pool->ptr - pool->start);
pool->start = tem->s;
pool->end = tem->s + blockSize;
@@ -6286,15 +6771,14 @@ poolGrow(STRING_POOL *pool)
}
static int FASTCALL
-nextScaffoldPart(XML_Parser parser)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
- CONTENT_SCAFFOLD * me;
+nextScaffoldPart(XML_Parser parser) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
+ CONTENT_SCAFFOLD *me;
int next;
- if (!dtd->scaffIndex) {
- dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
- if (!dtd->scaffIndex)
+ if (! dtd->scaffIndex) {
+ dtd->scaffIndex = (int *)MALLOC(parser, parser->m_groupSize * sizeof(int));
+ if (! dtd->scaffIndex)
return -1;
dtd->scaffIndex[0] = 0;
}
@@ -6302,15 +6786,14 @@ nextScaffoldPart(XML_Parser parser)
if (dtd->scaffCount >= dtd->scaffSize) {
CONTENT_SCAFFOLD *temp;
if (dtd->scaffold) {
- temp = (CONTENT_SCAFFOLD *)
- REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+ temp = (CONTENT_SCAFFOLD *)REALLOC(
+ parser, dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
return -1;
dtd->scaffSize *= 2;
- }
- else {
- temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
- * sizeof(CONTENT_SCAFFOLD));
+ } else {
+ temp = (CONTENT_SCAFFOLD *)MALLOC(parser, INIT_SCAFFOLD_ELEMENTS
+ * sizeof(CONTENT_SCAFFOLD));
if (temp == NULL)
return -1;
dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
@@ -6320,11 +6803,12 @@ nextScaffoldPart(XML_Parser parser)
next = dtd->scaffCount++;
me = &dtd->scaffold[next];
if (dtd->scaffLevel) {
- CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
+ CONTENT_SCAFFOLD *parent
+ = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]];
if (parent->lastchild) {
dtd->scaffold[parent->lastchild].nextsib = next;
}
- if (!parent->childcnt)
+ if (! parent->childcnt)
parent->firstchild = next;
parent->lastchild = next;
parent->childcnt++;
@@ -6334,13 +6818,9 @@ nextScaffoldPart(XML_Parser parser)
}
static void
-build_node(XML_Parser parser,
- int src_node,
- XML_Content *dest,
- XML_Content **contpos,
- XML_Char **strpos)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+build_node(XML_Parser parser, int src_node, XML_Content *dest,
+ XML_Content **contpos, XML_Char **strpos) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
dest->type = dtd->scaffold[src_node].type;
dest->quant = dtd->scaffold[src_node].quant;
if (dest->type == XML_CTYPE_NAME) {
@@ -6349,21 +6829,19 @@ build_node(XML_Parser parser,
src = dtd->scaffold[src_node].name;
for (;;) {
*(*strpos)++ = *src;
- if (!*src)
+ if (! *src)
break;
src++;
}
dest->numchildren = 0;
dest->children = NULL;
- }
- else {
+ } else {
unsigned int i;
int cn;
dest->numchildren = dtd->scaffold[src_node].childcnt;
dest->children = *contpos;
*contpos += dest->numchildren;
- for (i = 0, cn = dtd->scaffold[src_node].firstchild;
- i < dest->numchildren;
+ for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
i++, cn = dtd->scaffold[cn].nextsib) {
build_node(parser, cn, &(dest->children[i]), contpos, strpos);
}
@@ -6372,20 +6850,19 @@ build_node(XML_Parser parser,
}
static XML_Content *
-build_model (XML_Parser parser)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+build_model(XML_Parser parser) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
XML_Content *ret;
XML_Content *cpos;
- XML_Char * str;
+ XML_Char *str;
int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ (dtd->contentStringLen * sizeof(XML_Char)));
- ret = (XML_Content *)MALLOC(allocsize);
- if (!ret)
+ ret = (XML_Content *)MALLOC(parser, allocsize);
+ if (! ret)
return NULL;
- str = (XML_Char *) (&ret[dtd->scaffCount]);
+ str = (XML_Char *)(&ret[dtd->scaffCount]);
cpos = &ret[1];
build_node(parser, 0, ret, &cpos, &str);
@@ -6393,26 +6870,45 @@ build_model (XML_Parser parser)
}
static ELEMENT_TYPE *
-getElementType(XML_Parser parser,
- const ENCODING *enc,
- const char *ptr,
- const char *end)
-{
- DTD * const dtd = _dtd; /* save one level of indirection */
+getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
+ const char *end) {
+ DTD *const dtd = parser->m_dtd; /* save one level of indirection */
const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
ELEMENT_TYPE *ret;
- if (!name)
+ if (! name)
return NULL;
- ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
- if (!ret)
+ ret = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
+ sizeof(ELEMENT_TYPE));
+ if (! ret)
return NULL;
if (ret->name != name)
poolDiscard(&dtd->pool);
else {
poolFinish(&dtd->pool);
- if (!setElementTypePrefix(parser, ret))
+ if (! setElementTypePrefix(parser, ret))
return NULL;
}
return ret;
}
+
+static XML_Char *
+copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
+ int charsRequired = 0;
+ XML_Char *result;
+
+ /* First determine how long the string is */
+ while (s[charsRequired] != 0) {
+ charsRequired++;
+ }
+ /* Include the terminator */
+ charsRequired++;
+
+ /* Now allocate space for the copy */
+ result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char));
+ if (result == NULL)
+ return NULL;
+ /* Copy the original into place */
+ memcpy(result, s, charsRequired * sizeof(XML_Char));
+ return result;
+}
diff --git a/3rdparty/expat/lib/xmlrole.c b/3rdparty/expat/lib/xmlrole.c
index 44772e21dd3..3b676a415d8 100644
--- a/3rdparty/expat/lib/xmlrole.c
+++ b/3rdparty/expat/lib/xmlrole.c
@@ -1,22 +1,44 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stddef.h>
-#ifdef COMPILED_FROM_DSP
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
+#ifdef _WIN32
+# include "winconfig.h"
#else
-#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
-#endif
-#endif /* ndef COMPILED_FROM_DSP */
+# ifdef HAVE_EXPAT_CONFIG_H
+# include <expat_config.h>
+# endif
+#endif /* ndef _WIN32 */
#include "expat_external.h"
#include "internal.h"
@@ -30,107 +52,88 @@
*/
-static const char KW_ANY[] = {
- ASCII_A, ASCII_N, ASCII_Y, '\0' };
-static const char KW_ATTLIST[] = {
- ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
-static const char KW_CDATA[] = {
- ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_DOCTYPE[] = {
- ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
-static const char KW_ELEMENT[] = {
- ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
-static const char KW_EMPTY[] = {
- ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
-static const char KW_ENTITIES[] = {
- ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S,
- '\0' };
-static const char KW_ENTITY[] = {
- ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
-static const char KW_FIXED[] = {
- ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
-static const char KW_ID[] = {
- ASCII_I, ASCII_D, '\0' };
-static const char KW_IDREF[] = {
- ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
-static const char KW_IDREFS[] = {
- ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+static const char KW_ANY[] = {ASCII_A, ASCII_N, ASCII_Y, '\0'};
+static const char KW_ATTLIST[]
+ = {ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0'};
+static const char KW_CDATA[]
+ = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'};
+static const char KW_DOCTYPE[]
+ = {ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0'};
+static const char KW_ELEMENT[]
+ = {ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0'};
+static const char KW_EMPTY[]
+ = {ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0'};
+static const char KW_ENTITIES[] = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T,
+ ASCII_I, ASCII_E, ASCII_S, '\0'};
+static const char KW_ENTITY[]
+ = {ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0'};
+static const char KW_FIXED[]
+ = {ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0'};
+static const char KW_ID[] = {ASCII_I, ASCII_D, '\0'};
+static const char KW_IDREF[]
+ = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0'};
+static const char KW_IDREFS[]
+ = {ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0'};
#ifdef XML_DTD
-static const char KW_IGNORE[] = {
- ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
+static const char KW_IGNORE[]
+ = {ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0'};
#endif
-static const char KW_IMPLIED[] = {
- ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
+static const char KW_IMPLIED[]
+ = {ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0'};
#ifdef XML_DTD
-static const char KW_INCLUDE[] = {
- ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
+static const char KW_INCLUDE[]
+ = {ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0'};
#endif
-static const char KW_NDATA[] = {
- ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_NMTOKEN[] = {
- ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
-static const char KW_NMTOKENS[] = {
- ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S,
- '\0' };
-static const char KW_NOTATION[] =
- { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N,
- '\0' };
-static const char KW_PCDATA[] = {
- ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_PUBLIC[] = {
- ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
-static const char KW_REQUIRED[] = {
- ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D,
- '\0' };
-static const char KW_SYSTEM[] = {
- ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
+static const char KW_NDATA[]
+ = {ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'};
+static const char KW_NMTOKEN[]
+ = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0'};
+static const char KW_NMTOKENS[] = {ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K,
+ ASCII_E, ASCII_N, ASCII_S, '\0'};
+static const char KW_NOTATION[] = {ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T,
+ ASCII_I, ASCII_O, ASCII_N, '\0'};
+static const char KW_PCDATA[]
+ = {ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0'};
+static const char KW_PUBLIC[]
+ = {ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0'};
+static const char KW_REQUIRED[] = {ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I,
+ ASCII_R, ASCII_E, ASCII_D, '\0'};
+static const char KW_SYSTEM[]
+ = {ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0'};
#ifndef MIN_BYTES_PER_CHAR
-#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
+# define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
#endif
#ifdef XML_DTD
-#define setTopLevel(state) \
- ((state)->handler = ((state)->documentEntity \
- ? internalSubset \
- : externalSubset1))
+# define setTopLevel(state) \
+ ((state)->handler \
+ = ((state)->documentEntity ? internalSubset : externalSubset1))
#else /* not XML_DTD */
-#define setTopLevel(state) ((state)->handler = internalSubset)
+# define setTopLevel(state) ((state)->handler = internalSubset)
#endif /* not XML_DTD */
-typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
+typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, int tok,
+ const char *ptr, const char *end,
const ENCODING *enc);
-static PROLOG_HANDLER
- prolog0, prolog1, prolog2,
- doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
- internalSubset,
- entity0, entity1, entity2, entity3, entity4, entity5, entity6,
- entity7, entity8, entity9, entity10,
- notation0, notation1, notation2, notation3, notation4,
- attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
- attlist7, attlist8, attlist9,
- element0, element1, element2, element3, element4, element5, element6,
- element7,
+static PROLOG_HANDLER prolog0, prolog1, prolog2, doctype0, doctype1, doctype2,
+ doctype3, doctype4, doctype5, internalSubset, entity0, entity1, entity2,
+ entity3, entity4, entity5, entity6, entity7, entity8, entity9, entity10,
+ notation0, notation1, notation2, notation3, notation4, attlist0, attlist1,
+ attlist2, attlist3, attlist4, attlist5, attlist6, attlist7, attlist8,
+ attlist9, element0, element1, element2, element3, element4, element5,
+ element6, element7,
#ifdef XML_DTD
- externalSubset0, externalSubset1,
- condSect0, condSect1, condSect2,
+ externalSubset0, externalSubset1, condSect0, condSect1, condSect2,
#endif /* XML_DTD */
- declClose,
- error;
+ declClose, error;
static int FASTCALL common(PROLOG_STATE *state, int tok);
static int PTRCALL
-prolog0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+prolog0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
state->handler = prolog1;
@@ -147,10 +150,8 @@ prolog0(PROLOG_STATE *state,
case XML_TOK_BOM:
return XML_ROLE_NONE;
case XML_TOK_DECL_OPEN:
- if (!XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_DOCTYPE))
+ if (! XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end,
+ KW_DOCTYPE))
break;
state->handler = doctype0;
return XML_ROLE_DOCTYPE_NONE;
@@ -162,12 +163,8 @@ prolog0(PROLOG_STATE *state,
}
static int PTRCALL
-prolog1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+prolog1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NONE;
@@ -176,12 +173,17 @@ prolog1(PROLOG_STATE *state,
case XML_TOK_COMMENT:
return XML_ROLE_COMMENT;
case XML_TOK_BOM:
- return XML_ROLE_NONE;
+ /* This case can never arise. To reach this role function, the
+ * parse must have passed through prolog0 and therefore have had
+ * some form of input, even if only a space. At that point, a
+ * byte order mark is no longer a valid character (though
+ * technically it should be interpreted as a non-breaking space),
+ * so will be rejected by the tokenizing stages.
+ */
+ return XML_ROLE_NONE; /* LCOV_EXCL_LINE */
case XML_TOK_DECL_OPEN:
- if (!XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_DOCTYPE))
+ if (! XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end,
+ KW_DOCTYPE))
break;
state->handler = doctype0;
return XML_ROLE_DOCTYPE_NONE;
@@ -193,12 +195,11 @@ prolog1(PROLOG_STATE *state,
}
static int PTRCALL
-prolog2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+prolog2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NONE;
@@ -214,12 +215,11 @@ prolog2(PROLOG_STATE *state,
}
static int PTRCALL
-doctype0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+doctype0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_DOCTYPE_NONE;
@@ -232,12 +232,8 @@ doctype0(PROLOG_STATE *state,
}
static int PTRCALL
-doctype1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+doctype1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_DOCTYPE_NONE;
@@ -262,12 +258,11 @@ doctype1(PROLOG_STATE *state,
}
static int PTRCALL
-doctype2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+doctype2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_DOCTYPE_NONE;
@@ -279,12 +274,11 @@ doctype2(PROLOG_STATE *state,
}
static int PTRCALL
-doctype3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+doctype3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_DOCTYPE_NONE;
@@ -296,12 +290,11 @@ doctype3(PROLOG_STATE *state,
}
static int PTRCALL
-doctype4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+doctype4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_DOCTYPE_NONE;
@@ -316,12 +309,11 @@ doctype4(PROLOG_STATE *state,
}
static int PTRCALL
-doctype5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+doctype5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_DOCTYPE_NONE;
@@ -333,40 +325,28 @@ doctype5(PROLOG_STATE *state,
}
static int PTRCALL
-internalSubset(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+internalSubset(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NONE;
case XML_TOK_DECL_OPEN:
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end,
KW_ENTITY)) {
state->handler = entity0;
return XML_ROLE_ENTITY_NONE;
}
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end,
KW_ATTLIST)) {
state->handler = attlist0;
return XML_ROLE_ATTLIST_NONE;
}
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end,
KW_ELEMENT)) {
state->handler = element0;
return XML_ROLE_ELEMENT_NONE;
}
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end,
KW_NOTATION)) {
state->handler = notation0;
return XML_ROLE_NOTATION_NONE;
@@ -390,12 +370,8 @@ internalSubset(PROLOG_STATE *state,
#ifdef XML_DTD
static int PTRCALL
-externalSubset0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+externalSubset0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
state->handler = externalSubset1;
if (tok == XML_TOK_XML_DECL)
return XML_ROLE_TEXT_DECL;
@@ -403,12 +379,8 @@ externalSubset0(PROLOG_STATE *state,
}
static int PTRCALL
-externalSubset1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+externalSubset1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_COND_SECT_OPEN:
state->handler = condSect0;
@@ -435,12 +407,11 @@ externalSubset1(PROLOG_STATE *state,
#endif /* XML_DTD */
static int PTRCALL
-entity0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -455,12 +426,11 @@ entity0(PROLOG_STATE *state,
}
static int PTRCALL
-entity1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -472,12 +442,8 @@ entity1(PROLOG_STATE *state,
}
static int PTRCALL
-entity2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -500,12 +466,11 @@ entity2(PROLOG_STATE *state,
}
static int PTRCALL
-entity3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -517,12 +482,11 @@ entity3(PROLOG_STATE *state,
}
static int PTRCALL
-entity4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -534,12 +498,8 @@ entity4(PROLOG_STATE *state,
}
static int PTRCALL
-entity5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -557,12 +517,11 @@ entity5(PROLOG_STATE *state,
}
static int PTRCALL
-entity6(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity6(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -575,12 +534,8 @@ entity6(PROLOG_STATE *state,
}
static int PTRCALL
-entity7(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity7(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -603,12 +558,11 @@ entity7(PROLOG_STATE *state,
}
static int PTRCALL
-entity8(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity8(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -620,12 +574,11 @@ entity8(PROLOG_STATE *state,
}
static int PTRCALL
-entity9(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity9(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -637,12 +590,11 @@ entity9(PROLOG_STATE *state,
}
static int PTRCALL
-entity10(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+entity10(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ENTITY_NONE;
@@ -654,12 +606,11 @@ entity10(PROLOG_STATE *state,
}
static int PTRCALL
-notation0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+notation0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NOTATION_NONE;
@@ -671,12 +622,8 @@ notation0(PROLOG_STATE *state,
}
static int PTRCALL
-notation1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+notation1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NOTATION_NONE;
@@ -695,12 +642,11 @@ notation1(PROLOG_STATE *state,
}
static int PTRCALL
-notation2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+notation2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NOTATION_NONE;
@@ -712,12 +658,11 @@ notation2(PROLOG_STATE *state,
}
static int PTRCALL
-notation3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+notation3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NOTATION_NONE;
@@ -730,12 +675,11 @@ notation3(PROLOG_STATE *state,
}
static int PTRCALL
-notation4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+notation4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NOTATION_NONE;
@@ -751,12 +695,11 @@ notation4(PROLOG_STATE *state,
}
static int PTRCALL
-attlist0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -769,12 +712,11 @@ attlist0(PROLOG_STATE *state,
}
static int PTRCALL
-attlist1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -790,34 +732,23 @@ attlist1(PROLOG_STATE *state,
}
static int PTRCALL
-attlist2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
- case XML_TOK_NAME:
- {
- static const char * const types[] = {
- KW_CDATA,
- KW_ID,
- KW_IDREF,
- KW_IDREFS,
- KW_ENTITY,
- KW_ENTITIES,
- KW_NMTOKEN,
- KW_NMTOKENS,
- };
- int i;
- for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
- if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
- state->handler = attlist8;
- return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
- }
- }
+ case XML_TOK_NAME: {
+ static const char *const types[] = {
+ KW_CDATA, KW_ID, KW_IDREF, KW_IDREFS,
+ KW_ENTITY, KW_ENTITIES, KW_NMTOKEN, KW_NMTOKENS,
+ };
+ int i;
+ for (i = 0; i < (int)(sizeof(types) / sizeof(types[0])); i++)
+ if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
+ state->handler = attlist8;
+ return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
+ }
+ }
if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
state->handler = attlist5;
return XML_ROLE_ATTLIST_NONE;
@@ -831,12 +762,11 @@ attlist2(PROLOG_STATE *state,
}
static int PTRCALL
-attlist3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -850,12 +780,11 @@ attlist3(PROLOG_STATE *state,
}
static int PTRCALL
-attlist4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -870,12 +799,11 @@ attlist4(PROLOG_STATE *state,
}
static int PTRCALL
-attlist5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -887,12 +815,11 @@ attlist5(PROLOG_STATE *state,
}
static int PTRCALL
-attlist6(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist6(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -904,12 +831,11 @@ attlist6(PROLOG_STATE *state,
}
static int PTRCALL
-attlist7(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist7(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -925,33 +851,23 @@ attlist7(PROLOG_STATE *state,
/* default value */
static int PTRCALL
-attlist8(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist8(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
case XML_TOK_POUND_NAME:
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end,
KW_IMPLIED)) {
state->handler = attlist1;
return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
}
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end,
KW_REQUIRED)) {
state->handler = attlist1;
return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
}
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end,
KW_FIXED)) {
state->handler = attlist9;
return XML_ROLE_ATTLIST_NONE;
@@ -965,12 +881,11 @@ attlist8(PROLOG_STATE *state,
}
static int PTRCALL
-attlist9(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+attlist9(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ATTLIST_NONE;
@@ -982,12 +897,11 @@ attlist9(PROLOG_STATE *state,
}
static int PTRCALL
-element0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1000,12 +914,8 @@ element0(PROLOG_STATE *state,
}
static int PTRCALL
-element1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1030,19 +940,13 @@ element1(PROLOG_STATE *state,
}
static int PTRCALL
-element2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
case XML_TOK_POUND_NAME:
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
+ if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end,
KW_PCDATA)) {
state->handler = element3;
return XML_ROLE_CONTENT_PCDATA;
@@ -1070,12 +974,11 @@ element2(PROLOG_STATE *state,
}
static int PTRCALL
-element3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element3(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1095,12 +998,11 @@ element3(PROLOG_STATE *state,
}
static int PTRCALL
-element4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element4(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1113,12 +1015,11 @@ element4(PROLOG_STATE *state,
}
static int PTRCALL
-element5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element5(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1134,12 +1035,11 @@ element5(PROLOG_STATE *state,
}
static int PTRCALL
-element6(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element6(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1164,12 +1064,11 @@ element6(PROLOG_STATE *state,
}
static int PTRCALL
-element7(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+element7(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_ELEMENT_NONE;
@@ -1214,12 +1113,8 @@ element7(PROLOG_STATE *state,
#ifdef XML_DTD
static int PTRCALL
-condSect0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+condSect0(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NONE;
@@ -1238,12 +1133,11 @@ condSect0(PROLOG_STATE *state,
}
static int PTRCALL
-condSect1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+condSect1(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NONE;
@@ -1256,12 +1150,11 @@ condSect1(PROLOG_STATE *state,
}
static int PTRCALL
-condSect2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+condSect2(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return XML_ROLE_NONE;
@@ -1275,12 +1168,11 @@ condSect2(PROLOG_STATE *state,
#endif /* XML_DTD */
static int PTRCALL
-declClose(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+declClose(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
switch (tok) {
case XML_TOK_PROLOG_S:
return state->role_none;
@@ -1291,30 +1183,52 @@ declClose(PROLOG_STATE *state,
return common(state, tok);
}
+/* This function will only be invoked if the internal logic of the
+ * parser has broken down. It is used in two cases:
+ *
+ * 1: When the XML prolog has been finished. At this point the
+ * processor (the parser level above these role handlers) should
+ * switch from prologProcessor to contentProcessor and reinitialise
+ * the handler function.
+ *
+ * 2: When an error has been detected (via common() below). At this
+ * point again the processor should be switched to errorProcessor,
+ * which will never call a handler.
+ *
+ * The result of this is that error() can only be called if the
+ * processor switch failed to happen, which is an internal error and
+ * therefore we shouldn't be able to provoke it simply by using the
+ * library. It is a necessary backstop, however, so we merely exclude
+ * it from the coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
static int PTRCALL
-error(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
+error(PROLOG_STATE *state, int tok, const char *ptr, const char *end,
+ const ENCODING *enc) {
+ UNUSED_P(state);
+ UNUSED_P(tok);
+ UNUSED_P(ptr);
+ UNUSED_P(end);
+ UNUSED_P(enc);
return XML_ROLE_NONE;
}
+/* LCOV_EXCL_STOP */
static int FASTCALL
-common(PROLOG_STATE *state, int tok)
-{
+common(PROLOG_STATE *state, int tok) {
#ifdef XML_DTD
- if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
+ if (! state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
return XML_ROLE_INNER_PARAM_ENTITY_REF;
+#else
+ UNUSED_P(tok);
#endif
state->handler = error;
return XML_ROLE_ERROR;
}
void
-XmlPrologStateInit(PROLOG_STATE *state)
-{
+XmlPrologStateInit(PROLOG_STATE *state) {
state->handler = prolog0;
#ifdef XML_DTD
state->documentEntity = 1;
@@ -1326,8 +1240,7 @@ XmlPrologStateInit(PROLOG_STATE *state)
#ifdef XML_DTD
void
-XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
-{
+XmlPrologStateInitExternalEntity(PROLOG_STATE *state) {
state->handler = externalSubset0;
state->documentEntity = 0;
state->includeLevel = 0;
diff --git a/3rdparty/expat/lib/xmlrole.h b/3rdparty/expat/lib/xmlrole.h
index 4dd9f06f976..036aba64fd2 100644
--- a/3rdparty/expat/lib/xmlrole.h
+++ b/3rdparty/expat/lib/xmlrole.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef XmlRole_INCLUDED
@@ -8,7 +36,7 @@
#ifdef __VMS
/* 0 1 2 3 0 1 2 3
1234567890123456789012345678901 1234567890123456789012345678901 */
-#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
+# define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
#endif
#include "xmltok.h"
@@ -85,11 +113,8 @@ enum {
};
typedef struct prolog_state {
- int (PTRCALL *handler) (struct prolog_state *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc);
+ int(PTRCALL *handler)(struct prolog_state *state, int tok, const char *ptr,
+ const char *end, const ENCODING *enc);
unsigned level;
int role_none;
#ifdef XML_DTD
@@ -104,8 +129,8 @@ void XmlPrologStateInit(PROLOG_STATE *);
void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
#endif /* XML_DTD */
-#define XmlTokenRole(state, tok, ptr, end, enc) \
- (((state)->handler)(state, tok, ptr, end, enc))
+#define XmlTokenRole(state, tok, ptr, end, enc) \
+ (((state)->handler)(state, tok, ptr, end, enc))
#ifdef __cplusplus
}
diff --git a/3rdparty/expat/lib/xmltok.c b/3rdparty/expat/lib/xmltok.c
index bf09dfc72b9..c4f9897f7dc 100644
--- a/3rdparty/expat/lib/xmltok.c
+++ b/3rdparty/expat/lib/xmltok.c
@@ -1,22 +1,54 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stddef.h>
+#include <string.h> /* memcpy */
-#ifdef COMPILED_FROM_DSP
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
+#if defined(_MSC_VER) && (_MSC_VER <= 1700)
+/* for vs2012/11.0/1700 and earlier Visual Studio compilers */
+# define bool int
+# define false 0
+# define true 1
#else
-#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
+# include <stdbool.h>
#endif
-#endif /* ndef COMPILED_FROM_DSP */
+
+#ifdef _WIN32
+# include "winconfig.h"
+#else
+# ifdef HAVE_EXPAT_CONFIG_H
+# include <expat_config.h>
+# endif
+#endif /* ndef _WIN32 */
#include "expat_external.h"
#include "internal.h"
@@ -24,59 +56,49 @@
#include "nametab.h"
#ifdef XML_DTD
-#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
+# define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
#else
-#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
+# define IGNORE_SECTION_TOK_VTABLE /* as nothing */
#endif
-#define VTABLE1 \
- { PREFIX(prologTok), PREFIX(contentTok), \
- PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
- { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
- PREFIX(sameName), \
- PREFIX(nameMatchesAscii), \
- PREFIX(nameLength), \
- PREFIX(skipS), \
- PREFIX(getAtts), \
- PREFIX(charRefNumber), \
- PREFIX(predefinedEntityName), \
- PREFIX(updatePosition), \
- PREFIX(isPublicId)
+#define VTABLE1 \
+ {PREFIX(prologTok), PREFIX(contentTok), \
+ PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE}, \
+ {PREFIX(attributeValueTok), PREFIX(entityValueTok)}, \
+ PREFIX(nameMatchesAscii), PREFIX(nameLength), PREFIX(skipS), \
+ PREFIX(getAtts), PREFIX(charRefNumber), PREFIX(predefinedEntityName), \
+ PREFIX(updatePosition), PREFIX(isPublicId)
#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
-#define UCS2_GET_NAMING(pages, hi, lo) \
- (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
+#define UCS2_GET_NAMING(pages, hi, lo) \
+ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo)&0x1F)))
/* A 2 byte UTF-8 representation splits the characters 11 bits between
the bottom 5 and 6 bits of the bytes. We need 8 bits to index into
pages, 3 bits to add to that index and 5 bits to generate the mask.
*/
-#define UTF8_GET_NAMING2(pages, byte) \
- (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
- + ((((byte)[0]) & 3) << 1) \
- + ((((byte)[1]) >> 5) & 1)] \
- & (1 << (((byte)[1]) & 0x1F)))
+#define UTF8_GET_NAMING2(pages, byte) \
+ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
+ + ((((byte)[0]) & 3) << 1) + ((((byte)[1]) >> 5) & 1)] \
+ & (1u << (((byte)[1]) & 0x1F)))
/* A 3 byte UTF-8 representation splits the characters 16 bits between
the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index
into pages, 3 bits to add to that index and 5 bits to generate the
mask.
*/
-#define UTF8_GET_NAMING3(pages, byte) \
- (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
- + ((((byte)[1]) >> 2) & 0xF)] \
- << 3) \
- + ((((byte)[1]) & 3) << 1) \
- + ((((byte)[2]) >> 5) & 1)] \
- & (1 << (((byte)[2]) & 0x1F)))
-
-#define UTF8_GET_NAMING(pages, p, n) \
- ((n) == 2 \
- ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
- : ((n) == 3 \
- ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
- : 0))
+#define UTF8_GET_NAMING3(pages, byte) \
+ (namingBitmap \
+ [((pages)[((((byte)[0]) & 0xF) << 4) + ((((byte)[1]) >> 2) & 0xF)] \
+ << 3) \
+ + ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)] \
+ & (1u << (((byte)[2]) & 0x1F)))
+
+#define UTF8_GET_NAMING(pages, p, n) \
+ ((n) == 2 \
+ ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
+ : ((n) == 3 ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) : 0))
/* Detection of invalid UTF-8 sequences is based on Table 3.1B
of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
@@ -88,88 +110,76 @@
(A & 0xC0) == 0xC0 means A > 0xBF
*/
-#define UTF8_INVALID2(p) \
+#define UTF8_INVALID2(p) \
((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0)
-#define UTF8_INVALID3(p) \
- (((p)[2] & 0x80) == 0 \
- || \
- ((*p) == 0xEF && (p)[1] == 0xBF \
- ? \
- (p)[2] > 0xBD \
- : \
- ((p)[2] & 0xC0) == 0xC0) \
- || \
- ((*p) == 0xE0 \
- ? \
- (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
- : \
- ((p)[1] & 0x80) == 0 \
- || \
- ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
-
-#define UTF8_INVALID4(p) \
- (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \
- || \
- ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \
- || \
- ((*p) == 0xF0 \
- ? \
- (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
- : \
- ((p)[1] & 0x80) == 0 \
- || \
- ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
+#define UTF8_INVALID3(p) \
+ (((p)[2] & 0x80) == 0 \
+ || ((*p) == 0xEF && (p)[1] == 0xBF ? (p)[2] > 0xBD \
+ : ((p)[2] & 0xC0) == 0xC0) \
+ || ((*p) == 0xE0 \
+ ? (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
+ : ((p)[1] & 0x80) == 0 \
+ || ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
+
+#define UTF8_INVALID4(p) \
+ (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 || ((p)[2] & 0x80) == 0 \
+ || ((p)[2] & 0xC0) == 0xC0 \
+ || ((*p) == 0xF0 \
+ ? (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
+ : ((p)[1] & 0x80) == 0 \
+ || ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
static int PTRFASTCALL
-isNever(const ENCODING *enc, const char *p)
-{
+isNever(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ UNUSED_P(p);
return 0;
}
static int PTRFASTCALL
-utf8_isName2(const ENCODING *enc, const char *p)
-{
+utf8_isName2(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
}
static int PTRFASTCALL
-utf8_isName3(const ENCODING *enc, const char *p)
-{
+utf8_isName3(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
}
#define utf8_isName4 isNever
static int PTRFASTCALL
-utf8_isNmstrt2(const ENCODING *enc, const char *p)
-{
+utf8_isNmstrt2(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
}
static int PTRFASTCALL
-utf8_isNmstrt3(const ENCODING *enc, const char *p)
-{
+utf8_isNmstrt3(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
}
#define utf8_isNmstrt4 isNever
static int PTRFASTCALL
-utf8_isInvalid2(const ENCODING *enc, const char *p)
-{
+utf8_isInvalid2(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_INVALID2((const unsigned char *)p);
}
static int PTRFASTCALL
-utf8_isInvalid3(const ENCODING *enc, const char *p)
-{
+utf8_isInvalid3(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_INVALID3((const unsigned char *)p);
}
static int PTRFASTCALL
-utf8_isInvalid4(const ENCODING *enc, const char *p)
-{
+utf8_isInvalid4(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return UTF8_INVALID4((const unsigned char *)p);
}
@@ -177,50 +187,44 @@ struct normal_encoding {
ENCODING enc;
unsigned char type[256];
#ifdef XML_MIN_SIZE
- int (PTRFASTCALL *byteType)(const ENCODING *, const char *);
- int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
- int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
- int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
- int (PTRCALL *charMatches)(const ENCODING *, const char *, int);
+ int(PTRFASTCALL *byteType)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
+ int(PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
+ int(PTRCALL *charMatches)(const ENCODING *, const char *, int);
#endif /* XML_MIN_SIZE */
- int (PTRFASTCALL *isName2)(const ENCODING *, const char *);
- int (PTRFASTCALL *isName3)(const ENCODING *, const char *);
- int (PTRFASTCALL *isName4)(const ENCODING *, const char *);
- int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
- int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
- int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
- int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
- int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
- int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isName2)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isName3)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isName4)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
+ int(PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
};
-#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc))
+#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *)(enc))
#ifdef XML_MIN_SIZE
-#define STANDARD_VTABLE(E) \
- E ## byteType, \
- E ## isNameMin, \
- E ## isNmstrtMin, \
- E ## byteToAscii, \
- E ## charMatches,
+# define STANDARD_VTABLE(E) \
+ E##byteType, E##isNameMin, E##isNmstrtMin, E##byteToAscii, E##charMatches,
#else
-#define STANDARD_VTABLE(E) /* as nothing */
+# define STANDARD_VTABLE(E) /* as nothing */
#endif
-#define NORMAL_VTABLE(E) \
- E ## isName2, \
- E ## isName3, \
- E ## isName4, \
- E ## isNmstrt2, \
- E ## isNmstrt3, \
- E ## isNmstrt4, \
- E ## isInvalid2, \
- E ## isInvalid3, \
- E ## isInvalid4
+#define NORMAL_VTABLE(E) \
+ E##isName2, E##isName3, E##isName4, E##isNmstrt2, E##isNmstrt3, \
+ E##isNmstrt4, E##isInvalid2, E##isInvalid3, E##isInvalid4
+
+#define NULL_VTABLE \
+ /* isName2 */ NULL, /* isName3 */ NULL, /* isName4 */ NULL, \
+ /* isNmstrt2 */ NULL, /* isNmstrt3 */ NULL, /* isNmstrt4 */ NULL, \
+ /* isInvalid2 */ NULL, /* isInvalid3 */ NULL, /* isInvalid4 */ NULL
static int FASTCALL checkCharRefNumber(int);
@@ -228,75 +232,70 @@ static int FASTCALL checkCharRefNumber(int);
#include "ascii.h"
#ifdef XML_MIN_SIZE
-#define sb_isNameMin isNever
-#define sb_isNmstrtMin isNever
+# define sb_isNameMin isNever
+# define sb_isNmstrtMin isNever
#endif
#ifdef XML_MIN_SIZE
-#define MINBPC(enc) ((enc)->minBytesPerChar)
+# define MINBPC(enc) ((enc)->minBytesPerChar)
#else
/* minimum bytes per character */
-#define MINBPC(enc) 1
+# define MINBPC(enc) 1
#endif
-#define SB_BYTE_TYPE(enc, p) \
+#define SB_BYTE_TYPE(enc, p) \
(((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
#ifdef XML_MIN_SIZE
static int PTRFASTCALL
-sb_byteType(const ENCODING *enc, const char *p)
-{
+sb_byteType(const ENCODING *enc, const char *p) {
return SB_BYTE_TYPE(enc, p);
}
-#define BYTE_TYPE(enc, p) \
- (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
+# define BYTE_TYPE(enc, p) (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
#else
-#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
+# define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
#endif
#ifdef XML_MIN_SIZE
-#define BYTE_TO_ASCII(enc, p) \
- (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
+# define BYTE_TO_ASCII(enc, p) (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
static int PTRFASTCALL
-sb_byteToAscii(const ENCODING *enc, const char *p)
-{
+sb_byteToAscii(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
return *p;
}
#else
-#define BYTE_TO_ASCII(enc, p) (*(p))
+# define BYTE_TO_ASCII(enc, p) (*(p))
#endif
-#define IS_NAME_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p))
-#define IS_NMSTRT_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p))
-#define IS_INVALID_CHAR(enc, p, n) \
- (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p))
+#define IS_NAME_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isName##n(enc, p))
+#define IS_NMSTRT_CHAR(enc, p, n) (AS_NORMAL_ENCODING(enc)->isNmstrt##n(enc, p))
+#define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid##n(enc, p))
#ifdef XML_MIN_SIZE
-#define IS_NAME_CHAR_MINBPC(enc, p) \
- (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
- (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
+# define IS_NAME_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
+# define IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
#else
-#define IS_NAME_CHAR_MINBPC(enc, p) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
+# define IS_NAME_CHAR_MINBPC(enc, p) (0)
+# define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
#endif
#ifdef XML_MIN_SIZE
-#define CHAR_MATCHES(enc, p, c) \
- (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
+# define CHAR_MATCHES(enc, p, c) \
+ (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
static int PTRCALL
-sb_charMatches(const ENCODING *enc, const char *p, int c)
-{
+sb_charMatches(const ENCODING *enc, const char *p, int c) {
+ UNUSED_P(enc);
return *p == c;
}
#else
/* c is an ASCII character */
-#define CHAR_MATCHES(enc, p, c) (*(p) == c)
+# define CHAR_MATCHES(enc, p, c) (*(p) == c)
#endif
-#define PREFIX(ident) normal_ ## ident
+#define PREFIX(ident) normal_##ident
#define XML_TOK_IMPL_C
#include "xmltok_impl.c"
#undef XML_TOK_IMPL_C
@@ -311,223 +310,301 @@ sb_charMatches(const ENCODING *enc, const char *p, int c)
#undef IS_NMSTRT_CHAR_MINBPC
#undef IS_INVALID_CHAR
-enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
- UTF8_cval1 = 0x00,
- UTF8_cval2 = 0xc0,
- UTF8_cval3 = 0xe0,
- UTF8_cval4 = 0xf0
+enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
+ UTF8_cval1 = 0x00,
+ UTF8_cval2 = 0xc0,
+ UTF8_cval3 = 0xe0,
+ UTF8_cval4 = 0xf0
};
-static void PTRCALL
-utf8_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
- char *to;
- const char *from;
- if (fromLim - *fromP > toLim - *toP) {
- /* Avoid copying partial characters. */
- for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
- if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
+void
+_INTERNAL_trim_to_complete_utf8_characters(const char *from,
+ const char **fromLimRef) {
+ const char *fromLim = *fromLimRef;
+ size_t walked = 0;
+ for (; fromLim > from; fromLim--, walked++) {
+ const unsigned char prev = (unsigned char)fromLim[-1];
+ if ((prev & 0xf8u)
+ == 0xf0u) { /* 4-byte character, lead by 0b11110xxx byte */
+ if (walked + 1 >= 4) {
+ fromLim += 4 - 1;
+ break;
+ } else {
+ walked = 0;
+ }
+ } else if ((prev & 0xf0u)
+ == 0xe0u) { /* 3-byte character, lead by 0b1110xxxx byte */
+ if (walked + 1 >= 3) {
+ fromLim += 3 - 1;
break;
+ } else {
+ walked = 0;
+ }
+ } else if ((prev & 0xe0u)
+ == 0xc0u) { /* 2-byte character, lead by 0b110xxxxx byte */
+ if (walked + 1 >= 2) {
+ fromLim += 2 - 1;
+ break;
+ } else {
+ walked = 0;
+ }
+ } else if ((prev & 0x80u)
+ == 0x00u) { /* 1-byte character, matching 0b0xxxxxxx */
+ break;
+ }
}
- for (to = *toP, from = *fromP; from != fromLim; from++, to++)
- *to = *from;
- *fromP = from;
- *toP = to;
+ *fromLimRef = fromLim;
}
-static void PTRCALL
-utf8_toUtf16(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- unsigned short **toP, const unsigned short *toLim)
-{
+static enum XML_Convert_Result PTRCALL
+utf8_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
+ char **toP, const char *toLim) {
+ bool input_incomplete = false;
+ bool output_exhausted = false;
+
+ /* Avoid copying partial characters (due to limited space). */
+ const ptrdiff_t bytesAvailable = fromLim - *fromP;
+ const ptrdiff_t bytesStorable = toLim - *toP;
+ UNUSED_P(enc);
+ if (bytesAvailable > bytesStorable) {
+ fromLim = *fromP + bytesStorable;
+ output_exhausted = true;
+ }
+
+ /* Avoid copying partial characters (from incomplete input). */
+ {
+ const char *const fromLimBefore = fromLim;
+ _INTERNAL_trim_to_complete_utf8_characters(*fromP, &fromLim);
+ if (fromLim < fromLimBefore) {
+ input_incomplete = true;
+ }
+ }
+
+ {
+ const ptrdiff_t bytesToCopy = fromLim - *fromP;
+ memcpy(*toP, *fromP, bytesToCopy);
+ *fromP += bytesToCopy;
+ *toP += bytesToCopy;
+ }
+
+ if (output_exhausted) /* needs to go first */
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else if (input_incomplete)
+ return XML_CONVERT_INPUT_INCOMPLETE;
+ else
+ return XML_CONVERT_COMPLETED;
+}
+
+static enum XML_Convert_Result PTRCALL
+utf8_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim) {
+ enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
unsigned short *to = *toP;
const char *from = *fromP;
- while (from != fromLim && to != toLim) {
+ while (from < fromLim && to < toLim) {
switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
case BT_LEAD2:
+ if (fromLim - from < 2) {
+ res = XML_CONVERT_INPUT_INCOMPLETE;
+ goto after;
+ }
*to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
from += 2;
break;
case BT_LEAD3:
- *to++ = (unsigned short)(((from[0] & 0xf) << 12)
- | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
+ if (fromLim - from < 3) {
+ res = XML_CONVERT_INPUT_INCOMPLETE;
+ goto after;
+ }
+ *to++ = (unsigned short)(((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6)
+ | (from[2] & 0x3f));
from += 3;
break;
- case BT_LEAD4:
- {
- unsigned long n;
- if (to + 1 == toLim)
- goto after;
- n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
- | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
- n -= 0x10000;
- to[0] = (unsigned short)((n >> 10) | 0xD800);
- to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
- to += 2;
- from += 4;
+ case BT_LEAD4: {
+ unsigned long n;
+ if (toLim - to < 2) {
+ res = XML_CONVERT_OUTPUT_EXHAUSTED;
+ goto after;
}
- break;
+ if (fromLim - from < 4) {
+ res = XML_CONVERT_INPUT_INCOMPLETE;
+ goto after;
+ }
+ n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
+ | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
+ n -= 0x10000;
+ to[0] = (unsigned short)((n >> 10) | 0xD800);
+ to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
+ to += 2;
+ from += 4;
+ } break;
default:
*to++ = *from++;
break;
}
}
+ if (from < fromLim)
+ res = XML_CONVERT_OUTPUT_EXHAUSTED;
after:
*fromP = from;
*toP = to;
+ return res;
}
#ifdef XML_NS
-static const struct normal_encoding utf8_encoding_ns = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
-#include "asciitab.h"
-#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
+static const struct normal_encoding utf8_encoding_ns
+ = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0},
+ {
+# include "asciitab.h"
+# include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)};
#endif
-static const struct normal_encoding utf8_encoding = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
+static const struct normal_encoding utf8_encoding
+ = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0},
+ {
#define BT_COLON BT_NMSTRT
#include "asciitab.h"
#undef BT_COLON
#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)};
#ifdef XML_NS
-static const struct normal_encoding internal_utf8_encoding_ns = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
-#include "iasciitab.h"
-#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
+static const struct normal_encoding internal_utf8_encoding_ns
+ = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0},
+ {
+# include "iasciitab.h"
+# include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)};
#endif
-static const struct normal_encoding internal_utf8_encoding = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
+static const struct normal_encoding internal_utf8_encoding
+ = {{VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0},
+ {
#define BT_COLON BT_NMSTRT
#include "iasciitab.h"
#undef BT_COLON
#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)};
-static void PTRCALL
-latin1_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
+ char **toP, const char *toLim) {
+ UNUSED_P(enc);
for (;;) {
unsigned char c;
if (*fromP == fromLim)
- break;
+ return XML_CONVERT_COMPLETED;
c = (unsigned char)**fromP;
if (c & 0x80) {
if (toLim - *toP < 2)
- break;
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
*(*toP)++ = (char)((c >> 6) | UTF8_cval2);
*(*toP)++ = (char)((c & 0x3f) | 0x80);
(*fromP)++;
- }
- else {
+ } else {
if (*toP == toLim)
- break;
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
*(*toP)++ = *(*fromP)++;
}
}
}
-static void PTRCALL
-latin1_toUtf16(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- unsigned short **toP, const unsigned short *toLim)
-{
- while (*fromP != fromLim && *toP != toLim)
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim) {
+ UNUSED_P(enc);
+ while (*fromP < fromLim && *toP < toLim)
*(*toP)++ = (unsigned char)*(*fromP)++;
+
+ if ((*toP == toLim) && (*fromP < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
}
#ifdef XML_NS
-static const struct normal_encoding latin1_encoding_ns = {
- { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
- {
-#include "asciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(sb_)
-};
+static const struct normal_encoding latin1_encoding_ns
+ = {{VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0},
+ {
+# include "asciitab.h"
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE};
#endif
-static const struct normal_encoding latin1_encoding = {
- { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
- {
+static const struct normal_encoding latin1_encoding
+ = {{VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0},
+ {
#define BT_COLON BT_NMSTRT
#include "asciitab.h"
#undef BT_COLON
#include "latin1tab.h"
- },
- STANDARD_VTABLE(sb_)
-};
-
-static void PTRCALL
-ascii_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
- while (*fromP != fromLim && *toP != toLim)
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE};
+
+static enum XML_Convert_Result PTRCALL
+ascii_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
+ char **toP, const char *toLim) {
+ UNUSED_P(enc);
+ while (*fromP < fromLim && *toP < toLim)
*(*toP)++ = *(*fromP)++;
+
+ if ((*toP == toLim) && (*fromP < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
}
#ifdef XML_NS
-static const struct normal_encoding ascii_encoding_ns = {
- { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
- {
-#include "asciitab.h"
-/* BT_NONXML == 0 */
- },
- STANDARD_VTABLE(sb_)
-};
+static const struct normal_encoding ascii_encoding_ns
+ = {{VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0},
+ {
+# include "asciitab.h"
+ /* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE};
#endif
-static const struct normal_encoding ascii_encoding = {
- { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
- {
+static const struct normal_encoding ascii_encoding
+ = {{VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0},
+ {
#define BT_COLON BT_NMSTRT
#include "asciitab.h"
#undef BT_COLON
-/* BT_NONXML == 0 */
- },
- STANDARD_VTABLE(sb_)
-};
+ /* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE};
static int PTRFASTCALL
-unicode_byte_type(char hi, char lo)
-{
+unicode_byte_type(char hi, char lo) {
switch ((unsigned char)hi) {
- case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ /* 0xD800-0xDBFF first 16-bit code unit or high surrogate (W1) */
+ case 0xD8:
+ case 0xD9:
+ case 0xDA:
+ case 0xDB:
return BT_LEAD4;
- case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ /* 0xDC00-0xDFFF second 16-bit code unit or low surrogate (W2) */
+ case 0xDC:
+ case 0xDD:
+ case 0xDE:
+ case 0xDF:
return BT_TRAIL;
case 0xFF:
switch ((unsigned char)lo) {
- case 0xFF:
- case 0xFE:
+ case 0xFF: /* noncharacter-FFFF */
+ case 0xFE: /* noncharacter-FFFE */
return BT_NONXML;
}
break;
@@ -535,85 +612,105 @@ unicode_byte_type(char hi, char lo)
return BT_NONASCII;
}
-#define DEFINE_UTF16_TO_UTF8(E) \
-static void PTRCALL \
-E ## toUtf8(const ENCODING *enc, \
- const char **fromP, const char *fromLim, \
- char **toP, const char *toLim) \
-{ \
- const char *from; \
- for (from = *fromP; from != fromLim; from += 2) { \
- int plane; \
- unsigned char lo2; \
- unsigned char lo = GET_LO(from); \
- unsigned char hi = GET_HI(from); \
- switch (hi) { \
- case 0: \
- if (lo < 0x80) { \
- if (*toP == toLim) { \
- *fromP = from; \
- return; \
- } \
- *(*toP)++ = lo; \
- break; \
- } \
- /* fall through */ \
- case 0x1: case 0x2: case 0x3: \
- case 0x4: case 0x5: case 0x6: case 0x7: \
- if (toLim - *toP < 2) { \
- *fromP = from; \
- return; \
- } \
- *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
- *(*toP)++ = ((lo & 0x3f) | 0x80); \
- break; \
- default: \
- if (toLim - *toP < 3) { \
- *fromP = from; \
- return; \
- } \
- /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
- *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
- *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
- *(*toP)++ = ((lo & 0x3f) | 0x80); \
- break; \
- case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
- if (toLim - *toP < 4) { \
- *fromP = from; \
- return; \
- } \
- plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
- *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
- *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
- from += 2; \
- lo2 = GET_LO(from); \
- *(*toP)++ = (((lo & 0x3) << 4) \
- | ((GET_HI(from) & 0x3) << 2) \
- | (lo2 >> 6) \
- | 0x80); \
- *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
- break; \
- } \
- } \
- *fromP = from; \
-}
+#define DEFINE_UTF16_TO_UTF8(E) \
+ static enum XML_Convert_Result PTRCALL E##toUtf8( \
+ const ENCODING *enc, const char **fromP, const char *fromLim, \
+ char **toP, const char *toLim) { \
+ const char *from = *fromP; \
+ UNUSED_P(enc); \
+ fromLim = from + (((fromLim - from) >> 1) << 1); /* shrink to even */ \
+ for (; from < fromLim; from += 2) { \
+ int plane; \
+ unsigned char lo2; \
+ unsigned char lo = GET_LO(from); \
+ unsigned char hi = GET_HI(from); \
+ switch (hi) { \
+ case 0: \
+ if (lo < 0x80) { \
+ if (*toP == toLim) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ *(*toP)++ = lo; \
+ break; \
+ } \
+ /* fall through */ \
+ case 0x1: \
+ case 0x2: \
+ case 0x3: \
+ case 0x4: \
+ case 0x5: \
+ case 0x6: \
+ case 0x7: \
+ if (toLim - *toP < 2) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ default: \
+ if (toLim - *toP < 3) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
+ *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
+ *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ case 0xD8: \
+ case 0xD9: \
+ case 0xDA: \
+ case 0xDB: \
+ if (toLim - *toP < 4) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ if (fromLim - from < 4) { \
+ *fromP = from; \
+ return XML_CONVERT_INPUT_INCOMPLETE; \
+ } \
+ plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
+ *(*toP)++ = (char)((plane >> 2) | UTF8_cval4); \
+ *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
+ from += 2; \
+ lo2 = GET_LO(from); \
+ *(*toP)++ = (((lo & 0x3) << 4) | ((GET_HI(from) & 0x3) << 2) \
+ | (lo2 >> 6) | 0x80); \
+ *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
+ break; \
+ } \
+ } \
+ *fromP = from; \
+ if (from < fromLim) \
+ return XML_CONVERT_INPUT_INCOMPLETE; \
+ else \
+ return XML_CONVERT_COMPLETED; \
+ }
-#define DEFINE_UTF16_TO_UTF16(E) \
-static void PTRCALL \
-E ## toUtf16(const ENCODING *enc, \
- const char **fromP, const char *fromLim, \
- unsigned short **toP, const unsigned short *toLim) \
-{ \
- /* Avoid copying first half only of surrogate */ \
- if (fromLim - *fromP > ((toLim - *toP) << 1) \
- && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
- fromLim -= 2; \
- for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
- *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
-}
+#define DEFINE_UTF16_TO_UTF16(E) \
+ static enum XML_Convert_Result PTRCALL E##toUtf16( \
+ const ENCODING *enc, const char **fromP, const char *fromLim, \
+ unsigned short **toP, const unsigned short *toLim) { \
+ enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
+ UNUSED_P(enc); \
+ fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \
+ /* Avoid copying first half only of surrogate */ \
+ if (fromLim - *fromP > ((toLim - *toP) << 1) \
+ && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
+ fromLim -= 2; \
+ res = XML_CONVERT_INPUT_INCOMPLETE; \
+ } \
+ for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \
+ *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+ if ((*toP == toLim) && (*fromP < fromLim)) \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ else \
+ return res; \
+ }
-#define SET2(ptr, ch) \
- (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
+#define SET2(ptr, ch) (((ptr)[0] = ((ch)&0xff)), ((ptr)[1] = ((ch) >> 8)))
#define GET_LO(ptr) ((unsigned char)(ptr)[0])
#define GET_HI(ptr) ((unsigned char)(ptr)[1])
@@ -624,8 +721,7 @@ DEFINE_UTF16_TO_UTF16(little2_)
#undef GET_LO
#undef GET_HI
-#define SET2(ptr, ch) \
- (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
+#define SET2(ptr, ch) (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch)&0xFF)))
#define GET_LO(ptr) ((unsigned char)(ptr)[1])
#define GET_HI(ptr) ((unsigned char)(ptr)[0])
@@ -636,317 +732,307 @@ DEFINE_UTF16_TO_UTF16(big2_)
#undef GET_LO
#undef GET_HI
-#define LITTLE2_BYTE_TYPE(enc, p) \
- ((p)[1] == 0 \
- ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
- : unicode_byte_type((p)[1], (p)[0]))
-#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
-#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
-#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
+#define LITTLE2_BYTE_TYPE(enc, p) \
+ ((p)[1] == 0 ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
+ : unicode_byte_type((p)[1], (p)[0]))
+#define LITTLE2_BYTE_TO_ASCII(p) ((p)[1] == 0 ? (p)[0] : -1)
+#define LITTLE2_CHAR_MATCHES(p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_IS_NAME_CHAR_MINBPC(p) \
UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
-#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(p) \
UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
#ifdef XML_MIN_SIZE
static int PTRFASTCALL
-little2_byteType(const ENCODING *enc, const char *p)
-{
+little2_byteType(const ENCODING *enc, const char *p) {
return LITTLE2_BYTE_TYPE(enc, p);
}
static int PTRFASTCALL
-little2_byteToAscii(const ENCODING *enc, const char *p)
-{
- return LITTLE2_BYTE_TO_ASCII(enc, p);
+little2_byteToAscii(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ return LITTLE2_BYTE_TO_ASCII(p);
}
static int PTRCALL
-little2_charMatches(const ENCODING *enc, const char *p, int c)
-{
- return LITTLE2_CHAR_MATCHES(enc, p, c);
+little2_charMatches(const ENCODING *enc, const char *p, int c) {
+ UNUSED_P(enc);
+ return LITTLE2_CHAR_MATCHES(p, c);
}
static int PTRFASTCALL
-little2_isNameMin(const ENCODING *enc, const char *p)
-{
- return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
+little2_isNameMin(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ return LITTLE2_IS_NAME_CHAR_MINBPC(p);
}
static int PTRFASTCALL
-little2_isNmstrtMin(const ENCODING *enc, const char *p)
-{
- return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+little2_isNmstrtMin(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ return LITTLE2_IS_NMSTRT_CHAR_MINBPC(p);
}
-#undef VTABLE
-#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
+# undef VTABLE
+# define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
#else /* not XML_MIN_SIZE */
-#undef PREFIX
-#define PREFIX(ident) little2_ ## ident
-#define MINBPC(enc) 2
+# undef PREFIX
+# define PREFIX(ident) little2_##ident
+# define MINBPC(enc) 2
/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
-#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
-#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
-#define IS_NAME_CHAR(enc, p, n) 0
-#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
-#define IS_NMSTRT_CHAR(enc, p, n) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
-
-#define XML_TOK_IMPL_C
-#include "xmltok_impl.c"
-#undef XML_TOK_IMPL_C
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
+# define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+# define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(p)
+# define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(p, c)
+# define IS_NAME_CHAR(enc, p, n) 0
+# define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(p)
+# define IS_NMSTRT_CHAR(enc, p, n) (0)
+# define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(p)
+
+# define XML_TOK_IMPL_C
+# include "xmltok_impl.c"
+# undef XML_TOK_IMPL_C
+
+# undef MINBPC
+# undef BYTE_TYPE
+# undef BYTE_TO_ASCII
+# undef CHAR_MATCHES
+# undef IS_NAME_CHAR
+# undef IS_NAME_CHAR_MINBPC
+# undef IS_NMSTRT_CHAR
+# undef IS_NMSTRT_CHAR_MINBPC
+# undef IS_INVALID_CHAR
#endif /* not XML_MIN_SIZE */
#ifdef XML_NS
-static const struct normal_encoding little2_encoding_ns = {
- { VTABLE, 2, 0,
-#if BYTEORDER == 1234
- 1
-#else
- 0
-#endif
- },
- {
-#include "asciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_)
-};
+static const struct normal_encoding little2_encoding_ns
+ = {{VTABLE, 2, 0,
+# if BYTEORDER == 1234
+ 1
+# else
+ 0
+# endif
+ },
+ {
+# include "asciitab.h"
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE};
#endif
-static const struct normal_encoding little2_encoding = {
- { VTABLE, 2, 0,
+static const struct normal_encoding little2_encoding
+ = {{VTABLE, 2, 0,
#if BYTEORDER == 1234
- 1
+ 1
#else
- 0
+ 0
#endif
- },
- {
+ },
+ {
#define BT_COLON BT_NMSTRT
#include "asciitab.h"
#undef BT_COLON
#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_)
-};
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE};
#if BYTEORDER != 4321
-#ifdef XML_NS
+# ifdef XML_NS
-static const struct normal_encoding internal_little2_encoding_ns = {
- { VTABLE, 2, 0, 1 },
- {
-#include "iasciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_)
-};
+static const struct normal_encoding internal_little2_encoding_ns
+ = {{VTABLE, 2, 0, 1},
+ {
+# include "iasciitab.h"
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE};
-#endif
+# endif
-static const struct normal_encoding internal_little2_encoding = {
- { VTABLE, 2, 0, 1 },
- {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_)
-};
+static const struct normal_encoding internal_little2_encoding
+ = {{VTABLE, 2, 0, 1},
+ {
+# define BT_COLON BT_NMSTRT
+# include "iasciitab.h"
+# undef BT_COLON
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE};
#endif
-
-#define BIG2_BYTE_TYPE(enc, p) \
- ((p)[0] == 0 \
- ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
- : unicode_byte_type((p)[0], (p)[1]))
-#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
-#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
-#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
+#define BIG2_BYTE_TYPE(enc, p) \
+ ((p)[0] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
+ : unicode_byte_type((p)[0], (p)[1]))
+#define BIG2_BYTE_TO_ASCII(p) ((p)[0] == 0 ? (p)[1] : -1)
+#define BIG2_CHAR_MATCHES(p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_IS_NAME_CHAR_MINBPC(p) \
UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
-#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+#define BIG2_IS_NMSTRT_CHAR_MINBPC(p) \
UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
#ifdef XML_MIN_SIZE
static int PTRFASTCALL
-big2_byteType(const ENCODING *enc, const char *p)
-{
+big2_byteType(const ENCODING *enc, const char *p) {
return BIG2_BYTE_TYPE(enc, p);
}
static int PTRFASTCALL
-big2_byteToAscii(const ENCODING *enc, const char *p)
-{
- return BIG2_BYTE_TO_ASCII(enc, p);
+big2_byteToAscii(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ return BIG2_BYTE_TO_ASCII(p);
}
static int PTRCALL
-big2_charMatches(const ENCODING *enc, const char *p, int c)
-{
- return BIG2_CHAR_MATCHES(enc, p, c);
+big2_charMatches(const ENCODING *enc, const char *p, int c) {
+ UNUSED_P(enc);
+ return BIG2_CHAR_MATCHES(p, c);
}
static int PTRFASTCALL
-big2_isNameMin(const ENCODING *enc, const char *p)
-{
- return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
+big2_isNameMin(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ return BIG2_IS_NAME_CHAR_MINBPC(p);
}
static int PTRFASTCALL
-big2_isNmstrtMin(const ENCODING *enc, const char *p)
-{
- return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+big2_isNmstrtMin(const ENCODING *enc, const char *p) {
+ UNUSED_P(enc);
+ return BIG2_IS_NMSTRT_CHAR_MINBPC(p);
}
-#undef VTABLE
-#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
+# undef VTABLE
+# define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
#else /* not XML_MIN_SIZE */
-#undef PREFIX
-#define PREFIX(ident) big2_ ## ident
-#define MINBPC(enc) 2
+# undef PREFIX
+# define PREFIX(ident) big2_##ident
+# define MINBPC(enc) 2
/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
-#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
-#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
-#define IS_NAME_CHAR(enc, p, n) 0
-#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
-#define IS_NMSTRT_CHAR(enc, p, n) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
-
-#define XML_TOK_IMPL_C
-#include "xmltok_impl.c"
-#undef XML_TOK_IMPL_C
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
+# define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+# define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(p)
+# define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(p, c)
+# define IS_NAME_CHAR(enc, p, n) 0
+# define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(p)
+# define IS_NMSTRT_CHAR(enc, p, n) (0)
+# define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(p)
+
+# define XML_TOK_IMPL_C
+# include "xmltok_impl.c"
+# undef XML_TOK_IMPL_C
+
+# undef MINBPC
+# undef BYTE_TYPE
+# undef BYTE_TO_ASCII
+# undef CHAR_MATCHES
+# undef IS_NAME_CHAR
+# undef IS_NAME_CHAR_MINBPC
+# undef IS_NMSTRT_CHAR
+# undef IS_NMSTRT_CHAR_MINBPC
+# undef IS_INVALID_CHAR
#endif /* not XML_MIN_SIZE */
#ifdef XML_NS
-static const struct normal_encoding big2_encoding_ns = {
- { VTABLE, 2, 0,
-#if BYTEORDER == 4321
- 1
-#else
- 0
-#endif
- },
- {
-#include "asciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_)
-};
+static const struct normal_encoding big2_encoding_ns
+ = {{VTABLE, 2, 0,
+# if BYTEORDER == 4321
+ 1
+# else
+ 0
+# endif
+ },
+ {
+# include "asciitab.h"
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE};
#endif
-static const struct normal_encoding big2_encoding = {
- { VTABLE, 2, 0,
+static const struct normal_encoding big2_encoding
+ = {{VTABLE, 2, 0,
#if BYTEORDER == 4321
- 1
+ 1
#else
- 0
+ 0
#endif
- },
- {
+ },
+ {
#define BT_COLON BT_NMSTRT
#include "asciitab.h"
#undef BT_COLON
#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_)
-};
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE};
#if BYTEORDER != 1234
-#ifdef XML_NS
+# ifdef XML_NS
-static const struct normal_encoding internal_big2_encoding_ns = {
- { VTABLE, 2, 0, 1 },
- {
-#include "iasciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_)
-};
+static const struct normal_encoding internal_big2_encoding_ns
+ = {{VTABLE, 2, 0, 1},
+ {
+# include "iasciitab.h"
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE};
-#endif
+# endif
-static const struct normal_encoding internal_big2_encoding = {
- { VTABLE, 2, 0, 1 },
- {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_)
-};
+static const struct normal_encoding internal_big2_encoding
+ = {{VTABLE, 2, 0, 1},
+ {
+# define BT_COLON BT_NMSTRT
+# include "iasciitab.h"
+# undef BT_COLON
+# include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE};
#endif
#undef PREFIX
static int FASTCALL
-streqci(const char *s1, const char *s2)
-{
+streqci(const char *s1, const char *s2) {
for (;;) {
char c1 = *s1++;
char c2 = *s2++;
if (ASCII_a <= c1 && c1 <= ASCII_z)
c1 += ASCII_A - ASCII_a;
if (ASCII_a <= c2 && c2 <= ASCII_z)
- c2 += ASCII_A - ASCII_a;
+ /* The following line will never get executed. streqci() is
+ * only called from two places, both of which guarantee to put
+ * upper-case strings into s2.
+ */
+ c2 += ASCII_A - ASCII_a; /* LCOV_EXCL_LINE */
if (c1 != c2)
return 0;
- if (!c1)
+ if (! c1)
break;
}
return 1;
}
static void PTRCALL
-initUpdatePosition(const ENCODING *enc, const char *ptr,
- const char *end, POSITION *pos)
-{
+initUpdatePosition(const ENCODING *enc, const char *ptr, const char *end,
+ POSITION *pos) {
+ UNUSED_P(enc);
normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
}
static int
-toAscii(const ENCODING *enc, const char *ptr, const char *end)
-{
+toAscii(const ENCODING *enc, const char *ptr, const char *end) {
char buf[1];
char *p = buf;
XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
@@ -957,8 +1043,7 @@ toAscii(const ENCODING *enc, const char *ptr, const char *end)
}
static int FASTCALL
-isSpace(int c)
-{
+isSpace(int c) {
switch (c) {
case 0x20:
case 0xD:
@@ -973,21 +1058,16 @@ isSpace(int c)
followed by name=val.
*/
static int
-parsePseudoAttribute(const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **namePtr,
- const char **nameEndPtr,
- const char **valPtr,
- const char **nextTokPtr)
-{
+parsePseudoAttribute(const ENCODING *enc, const char *ptr, const char *end,
+ const char **namePtr, const char **nameEndPtr,
+ const char **valPtr, const char **nextTokPtr) {
int c;
char open;
if (ptr == end) {
*namePtr = NULL;
return 1;
}
- if (!isSpace(toAscii(enc, ptr, end))) {
+ if (! isSpace(toAscii(enc, ptr, end))) {
*nextTokPtr = ptr;
return 0;
}
@@ -1043,12 +1123,9 @@ parsePseudoAttribute(const ENCODING *enc,
c = toAscii(enc, ptr, end);
if (c == open)
break;
- if (!(ASCII_a <= c && c <= ASCII_z)
- && !(ASCII_A <= c && c <= ASCII_Z)
- && !(ASCII_0 <= c && c <= ASCII_9)
- && c != ASCII_PERIOD
- && c != ASCII_MINUS
- && c != ASCII_UNDERSCORE) {
+ if (! (ASCII_a <= c && c <= ASCII_z) && ! (ASCII_A <= c && c <= ASCII_Z)
+ && ! (ASCII_0 <= c && c <= ASCII_9) && c != ASCII_PERIOD
+ && c != ASCII_MINUS && c != ASCII_UNDERSCORE) {
*nextTokPtr = ptr;
return 0;
}
@@ -1057,68 +1134,52 @@ parsePseudoAttribute(const ENCODING *enc,
return 1;
}
-static const char KW_version[] = {
- ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
-};
+static const char KW_version[]
+ = {ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'};
-static const char KW_encoding[] = {
- ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
-};
+static const char KW_encoding[] = {ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d,
+ ASCII_i, ASCII_n, ASCII_g, '\0'};
-static const char KW_standalone[] = {
- ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o,
- ASCII_n, ASCII_e, '\0'
-};
+static const char KW_standalone[]
+ = {ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a,
+ ASCII_l, ASCII_o, ASCII_n, ASCII_e, '\0'};
-static const char KW_yes[] = {
- ASCII_y, ASCII_e, ASCII_s, '\0'
-};
+static const char KW_yes[] = {ASCII_y, ASCII_e, ASCII_s, '\0'};
-static const char KW_no[] = {
- ASCII_n, ASCII_o, '\0'
-};
+static const char KW_no[] = {ASCII_n, ASCII_o, '\0'};
static int
-doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
- const char *,
+doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, const char *,
const char *),
- int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
- const char **encodingName,
- const ENCODING **encoding,
- int *standalone)
-{
+ int isGeneralTextEntity, const ENCODING *enc, const char *ptr,
+ const char *end, const char **badPtr, const char **versionPtr,
+ const char **versionEndPtr, const char **encodingName,
+ const ENCODING **encoding, int *standalone) {
const char *val = NULL;
const char *name = NULL;
const char *nameEnd = NULL;
ptr += 5 * enc->minBytesPerChar;
end -= 2 * enc->minBytesPerChar;
- if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
- || !name) {
+ if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
+ || ! name) {
*badPtr = ptr;
return 0;
}
- if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
- if (!isGeneralTextEntity) {
+ if (! XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
+ if (! isGeneralTextEntity) {
*badPtr = name;
return 0;
}
- }
- else {
+ } else {
if (versionPtr)
*versionPtr = val;
if (versionEndPtr)
*versionEndPtr = ptr;
- if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
*badPtr = ptr;
return 0;
}
- if (!name) {
+ if (! name) {
if (isGeneralTextEntity) {
/* a TextDecl must have an EncodingDecl */
*badPtr = ptr;
@@ -1129,7 +1190,7 @@ doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
}
if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
int c = toAscii(enc, val, end);
- if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
+ if (! (ASCII_a <= c && c <= ASCII_z) && ! (ASCII_A <= c && c <= ASCII_Z)) {
*badPtr = val;
return 0;
}
@@ -1137,14 +1198,14 @@ doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
*encodingName = val;
if (encoding)
*encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
- if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
*badPtr = ptr;
return 0;
}
- if (!name)
+ if (! name)
return 1;
}
- if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
+ if (! XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
|| isGeneralTextEntity) {
*badPtr = name;
return 0;
@@ -1152,12 +1213,10 @@ doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
if (standalone)
*standalone = 1;
- }
- else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
+ } else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
if (standalone)
*standalone = 0;
- }
- else {
+ } else {
*badPtr = val;
return 0;
}
@@ -1171,11 +1230,16 @@ doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
}
static int FASTCALL
-checkCharRefNumber(int result)
-{
+checkCharRefNumber(int result) {
switch (result >> 8) {
- case 0xD8: case 0xD9: case 0xDA: case 0xDB:
- case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ case 0xD8:
+ case 0xD9:
+ case 0xDA:
+ case 0xDB:
+ case 0xDC:
+ case 0xDD:
+ case 0xDE:
+ case 0xDF:
return -1;
case 0:
if (latin1_encoding.type[result] == BT_NONXML)
@@ -1190,8 +1254,7 @@ checkCharRefNumber(int result)
}
int FASTCALL
-XmlUtf8Encode(int c, char *buf)
-{
+XmlUtf8Encode(int c, char *buf) {
enum {
/* minN is minimum legal resulting value for N byte sequence */
min2 = 0x80,
@@ -1200,7 +1263,7 @@ XmlUtf8Encode(int c, char *buf)
};
if (c < 0)
- return 0;
+ return 0; /* LCOV_EXCL_LINE: this case is always eliminated beforehand */
if (c < min2) {
buf[0] = (char)(c | UTF8_cval1);
return 1;
@@ -1223,12 +1286,11 @@ XmlUtf8Encode(int c, char *buf)
buf[3] = (char)((c & 0x3f) | 0x80);
return 4;
}
- return 0;
+ return 0; /* LCOV_EXCL_LINE: this case too is eliminated before calling */
}
int FASTCALL
-XmlUtf16Encode(int charNum, unsigned short *buf)
-{
+XmlUtf16Encode(int charNum, unsigned short *buf) {
if (charNum < 0)
return 0;
if (charNum < 0x10000) {
@@ -1252,17 +1314,15 @@ struct unknown_encoding {
char utf8[256][4];
};
-#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc))
+#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *)(enc))
int
-XmlSizeOfUnknownEncoding(void)
-{
+XmlSizeOfUnknownEncoding(void) {
return sizeof(struct unknown_encoding);
}
static int PTRFASTCALL
-unknown_isName(const ENCODING *enc, const char *p)
-{
+unknown_isName(const ENCODING *enc, const char *p) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
int c = uenc->convert(uenc->userData, p);
if (c & ~0xFFFF)
@@ -1271,8 +1331,7 @@ unknown_isName(const ENCODING *enc, const char *p)
}
static int PTRFASTCALL
-unknown_isNmstrt(const ENCODING *enc, const char *p)
-{
+unknown_isNmstrt(const ENCODING *enc, const char *p) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
int c = uenc->convert(uenc->userData, p);
if (c & ~0xFFFF)
@@ -1281,81 +1340,72 @@ unknown_isNmstrt(const ENCODING *enc, const char *p)
}
static int PTRFASTCALL
-unknown_isInvalid(const ENCODING *enc, const char *p)
-{
+unknown_isInvalid(const ENCODING *enc, const char *p) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
int c = uenc->convert(uenc->userData, p);
return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
}
-static void PTRCALL
-unknown_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
+static enum XML_Convert_Result PTRCALL
+unknown_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim,
+ char **toP, const char *toLim) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
char buf[XML_UTF8_ENCODE_MAX];
for (;;) {
const char *utf8;
int n;
if (*fromP == fromLim)
- break;
+ return XML_CONVERT_COMPLETED;
utf8 = uenc->utf8[(unsigned char)**fromP];
n = *utf8++;
if (n == 0) {
int c = uenc->convert(uenc->userData, *fromP);
n = XmlUtf8Encode(c, buf);
if (n > toLim - *toP)
- break;
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
utf8 = buf;
*fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
- (BT_LEAD2 - 2));
- }
- else {
+ } else {
if (n > toLim - *toP)
- break;
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
(*fromP)++;
}
- do {
- *(*toP)++ = *utf8++;
- } while (--n != 0);
+ memcpy(*toP, utf8, n);
+ *toP += n;
}
}
-static void PTRCALL
-unknown_toUtf16(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- unsigned short **toP, const unsigned short *toLim)
-{
+static enum XML_Convert_Result PTRCALL
+unknown_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim) {
const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
- while (*fromP != fromLim && *toP != toLim) {
+ while (*fromP < fromLim && *toP < toLim) {
unsigned short c = uenc->utf16[(unsigned char)**fromP];
if (c == 0) {
- c = (unsigned short)
- uenc->convert(uenc->userData, *fromP);
+ c = (unsigned short)uenc->convert(uenc->userData, *fromP);
*fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
- (BT_LEAD2 - 2));
- }
- else
+ } else
(*fromP)++;
*(*toP)++ = c;
}
+
+ if ((*toP == toLim) && (*fromP < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
}
ENCODING *
-XmlInitUnknownEncoding(void *mem,
- int *table,
- CONVERTER convert,
- void *userData)
-{
+XmlInitUnknownEncoding(void *mem, int *table, CONVERTER convert,
+ void *userData) {
int i;
struct unknown_encoding *e = (struct unknown_encoding *)mem;
- for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
- ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
+ memcpy(mem, &latin1_encoding, sizeof(struct normal_encoding));
for (i = 0; i < 128; i++)
if (latin1_encoding.type[i] != BT_OTHER
- && latin1_encoding.type[i] != BT_NONXML
- && table[i] != i)
+ && latin1_encoding.type[i] != BT_NONXML && table[i] != i)
return 0;
for (i = 0; i < 256; i++) {
int c = table[i];
@@ -1365,32 +1415,30 @@ XmlInitUnknownEncoding(void *mem,
e->utf16[i] = 0xFFFF;
e->utf8[i][0] = 1;
e->utf8[i][1] = 0;
- }
- else if (c < 0) {
+ } else if (c < 0) {
if (c < -4)
return 0;
+ /* Multi-byte sequences need a converter function */
+ if (! convert)
+ return 0;
e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2));
e->utf8[i][0] = 0;
e->utf16[i] = 0;
- }
- else if (c < 0x80) {
+ } else if (c < 0x80) {
if (latin1_encoding.type[c] != BT_OTHER
- && latin1_encoding.type[c] != BT_NONXML
- && c != i)
+ && latin1_encoding.type[c] != BT_NONXML && c != i)
return 0;
e->normal.type[i] = latin1_encoding.type[c];
e->utf8[i][0] = 1;
e->utf8[i][1] = (char)c;
e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c);
- }
- else if (checkCharRefNumber(c) < 0) {
+ } else if (checkCharRefNumber(c) < 0) {
e->normal.type[i] = BT_NONXML;
/* This shouldn't really get used. */
e->utf16[i] = 0xFFFF;
e->utf8[i][0] = 1;
e->utf8[i][1] = 0;
- }
- else {
+ } else {
if (c > 0xFFFF)
return 0;
if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
@@ -1435,44 +1483,32 @@ enum {
NO_ENC
};
-static const char KW_ISO_8859_1[] = {
- ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9,
- ASCII_MINUS, ASCII_1, '\0'
-};
-static const char KW_US_ASCII[] = {
- ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I,
- '\0'
-};
-static const char KW_UTF_8[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
-};
-static const char KW_UTF_16[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
-};
-static const char KW_UTF_16BE[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E,
- '\0'
-};
-static const char KW_UTF_16LE[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E,
- '\0'
-};
+static const char KW_ISO_8859_1[]
+ = {ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8,
+ ASCII_5, ASCII_9, ASCII_MINUS, ASCII_1, '\0'};
+static const char KW_US_ASCII[]
+ = {ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S,
+ ASCII_C, ASCII_I, ASCII_I, '\0'};
+static const char KW_UTF_8[]
+ = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'};
+static const char KW_UTF_16[]
+ = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'};
+static const char KW_UTF_16BE[]
+ = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1,
+ ASCII_6, ASCII_B, ASCII_E, '\0'};
+static const char KW_UTF_16LE[]
+ = {ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1,
+ ASCII_6, ASCII_L, ASCII_E, '\0'};
static int FASTCALL
-getEncodingIndex(const char *name)
-{
- static const char * const encodingNames[] = {
- KW_ISO_8859_1,
- KW_US_ASCII,
- KW_UTF_8,
- KW_UTF_16,
- KW_UTF_16BE,
- KW_UTF_16LE,
+getEncodingIndex(const char *name) {
+ static const char *const encodingNames[] = {
+ KW_ISO_8859_1, KW_US_ASCII, KW_UTF_8, KW_UTF_16, KW_UTF_16BE, KW_UTF_16LE,
};
int i;
if (name == NULL)
return NO_ENC;
- for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
+ for (i = 0; i < (int)(sizeof(encodingNames) / sizeof(encodingNames[0])); i++)
if (streqci(name, encodingNames[i]))
return i;
return UNKNOWN_ENC;
@@ -1492,18 +1528,12 @@ getEncodingIndex(const char *name)
XML_PROLOG_STATE otherwise.
*/
-
static int
-initScan(const ENCODING * const *encodingTable,
- const INIT_ENCODING *enc,
- int state,
- const char *ptr,
- const char *end,
- const char **nextTokPtr)
-{
+initScan(const ENCODING *const *encodingTable, const INIT_ENCODING *enc,
+ int state, const char *ptr, const char *end, const char **nextTokPtr) {
const ENCODING **encPtr;
- if (ptr == end)
+ if (ptr >= end)
return XML_TOK_NONE;
encPtr = enc->encPtr;
if (ptr + 1 == end) {
@@ -1525,20 +1555,17 @@ initScan(const ENCODING * const *encodingTable,
case 0xFE:
case 0xFF:
case 0xEF: /* possibly first byte of UTF-8 BOM */
- if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
- && state == XML_CONTENT_STATE)
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE)
break;
/* fall through */
case 0x00:
case 0x3C:
return XML_TOK_PARTIAL;
}
- }
- else {
+ } else {
switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
case 0xFEFF:
- if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
- && state == XML_CONTENT_STATE)
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE)
break;
*nextTokPtr = ptr + 2;
*encPtr = encodingTable[UTF_16BE_ENC];
@@ -1552,8 +1579,7 @@ initScan(const ENCODING * const *encodingTable,
*encPtr = encodingTable[UTF_16LE_ENC];
return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
case 0xFFFE:
- if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
- && state == XML_CONTENT_STATE)
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE)
break;
*nextTokPtr = ptr + 2;
*encPtr = encodingTable[UTF_16LE_ENC];
@@ -1568,8 +1594,8 @@ initScan(const ENCODING * const *encodingTable,
*/
if (state == XML_CONTENT_STATE) {
int e = INIT_ENC_INDEX(enc);
- if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC
- || e == UTF_16LE_ENC || e == UTF_16_ENC)
+ if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC
+ || e == UTF_16_ENC)
break;
}
if (ptr + 2 == end)
@@ -1592,8 +1618,7 @@ initScan(const ENCODING * const *encodingTable,
break;
*encPtr = encodingTable[UTF_16BE_ENC];
return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
- }
- else if (ptr[1] == '\0') {
+ } else if (ptr[1] == '\0') {
/* We could recover here in the case:
- parsing an external entity
- second byte is 0
@@ -1615,7 +1640,6 @@ initScan(const ENCODING * const *encodingTable,
return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
}
-
#define NS(x) x
#define ns(x) x
#define XML_TOK_NS_C
@@ -1626,22 +1650,19 @@ initScan(const ENCODING * const *encodingTable,
#ifdef XML_NS
-#define NS(x) x ## NS
-#define ns(x) x ## _ns
+# define NS(x) x##NS
+# define ns(x) x##_ns
-#define XML_TOK_NS_C
-#include "xmltok_ns.c"
-#undef XML_TOK_NS_C
+# define XML_TOK_NS_C
+# include "xmltok_ns.c"
+# undef XML_TOK_NS_C
-#undef NS
-#undef ns
+# undef NS
+# undef ns
ENCODING *
-XmlInitUnknownEncodingNS(void *mem,
- int *table,
- CONVERTER convert,
- void *userData)
-{
+XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert,
+ void *userData) {
ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
if (enc)
((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
diff --git a/3rdparty/expat/lib/xmltok.h b/3rdparty/expat/lib/xmltok.h
index ca867aa6b42..2adbf5307be 100644
--- a/3rdparty/expat/lib/xmltok.h
+++ b/3rdparty/expat/lib/xmltok.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef XmlTok_INCLUDED
@@ -10,16 +38,18 @@ extern "C" {
#endif
/* The following token may be returned by XmlContentTok */
-#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
- start of illegal ]]> sequence */
+#define XML_TOK_TRAILING_RSQB \
+ -5 /* ] or ]] at the end of the scan; might be \
+ start of illegal ]]> sequence */
/* The following tokens may be returned by both XmlPrologTok and
XmlContentTok.
*/
-#define XML_TOK_NONE -4 /* The string to be scanned is empty */
-#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
- might be part of CRLF sequence */
-#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
-#define XML_TOK_PARTIAL -1 /* only part of a token */
+#define XML_TOK_NONE -4 /* The string to be scanned is empty */
+#define XML_TOK_TRAILING_CR \
+ -3 /* A CR at the end of the scan; \
+ might be part of CRLF sequence */
+#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
+#define XML_TOK_PARTIAL -1 /* only part of a token */
#define XML_TOK_INVALID 0
/* The following tokens are returned by XmlContentTok; some are also
@@ -34,24 +64,24 @@ extern "C" {
#define XML_TOK_DATA_NEWLINE 7
#define XML_TOK_CDATA_SECT_OPEN 8
#define XML_TOK_ENTITY_REF 9
-#define XML_TOK_CHAR_REF 10 /* numeric character reference */
+#define XML_TOK_CHAR_REF 10 /* numeric character reference */
/* The following tokens may be returned by both XmlPrologTok and
XmlContentTok.
*/
-#define XML_TOK_PI 11 /* processing instruction */
-#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
+#define XML_TOK_PI 11 /* processing instruction */
+#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
#define XML_TOK_COMMENT 13
-#define XML_TOK_BOM 14 /* Byte order mark */
+#define XML_TOK_BOM 14 /* Byte order mark */
/* The following tokens are returned only by XmlPrologTok */
#define XML_TOK_PROLOG_S 15
-#define XML_TOK_DECL_OPEN 16 /* <!foo */
-#define XML_TOK_DECL_CLOSE 17 /* > */
+#define XML_TOK_DECL_OPEN 16 /* <!foo */
+#define XML_TOK_DECL_CLOSE 17 /* > */
#define XML_TOK_NAME 18
#define XML_TOK_NMTOKEN 19
-#define XML_TOK_POUND_NAME 20 /* #name */
-#define XML_TOK_OR 21 /* | */
+#define XML_TOK_POUND_NAME 20 /* #name */
+#define XML_TOK_OR 21 /* | */
#define XML_TOK_PERCENT 22
#define XML_TOK_OPEN_PAREN 23
#define XML_TOK_CLOSE_PAREN 24
@@ -62,14 +92,14 @@ extern "C" {
#define XML_TOK_INSTANCE_START 29
/* The following occur only in element type declarations */
-#define XML_TOK_NAME_QUESTION 30 /* name? */
-#define XML_TOK_NAME_ASTERISK 31 /* name* */
-#define XML_TOK_NAME_PLUS 32 /* name+ */
-#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
-#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
-#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
-#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
-#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
+#define XML_TOK_NAME_QUESTION 30 /* name? */
+#define XML_TOK_NAME_ASTERISK 31 /* name* */
+#define XML_TOK_NAME_PLUS 32 /* name+ */
+#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
+#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
+#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
+#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
+#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
#define XML_TOK_COMMA 38
/* The following token is returned only by XmlAttributeValueTok */
@@ -84,20 +114,20 @@ extern "C" {
#define XML_TOK_PREFIXED_NAME 41
#ifdef XML_DTD
-#define XML_TOK_IGNORE_SECT 42
+# define XML_TOK_IGNORE_SECT 42
#endif /* XML_DTD */
#ifdef XML_DTD
-#define XML_N_STATES 4
+# define XML_N_STATES 4
#else /* not XML_DTD */
-#define XML_N_STATES 3
+# define XML_N_STATES 3
#endif /* not XML_DTD */
#define XML_PROLOG_STATE 0
#define XML_CONTENT_STATE 1
#define XML_CDATA_SECTION_STATE 2
#ifdef XML_DTD
-#define XML_IGNORE_SECTION_STATE 3
+# define XML_IGNORE_SECTION_STATE 3
#endif /* XML_DTD */
#define XML_N_LITERAL_TYPES 2
@@ -125,49 +155,41 @@ typedef struct {
struct encoding;
typedef struct encoding ENCODING;
-typedef int (PTRCALL *SCANNER)(const ENCODING *,
- const char *,
- const char *,
- const char **);
+typedef int(PTRCALL *SCANNER)(const ENCODING *, const char *, const char *,
+ const char **);
+
+enum XML_Convert_Result {
+ XML_CONVERT_COMPLETED = 0,
+ XML_CONVERT_INPUT_INCOMPLETE = 1,
+ XML_CONVERT_OUTPUT_EXHAUSTED
+ = 2 /* and therefore potentially input remaining as well */
+};
struct encoding {
SCANNER scanners[XML_N_STATES];
SCANNER literalScanners[XML_N_LITERAL_TYPES];
- int (PTRCALL *sameName)(const ENCODING *,
- const char *,
- const char *);
- int (PTRCALL *nameMatchesAscii)(const ENCODING *,
- const char *,
- const char *,
- const char *);
- int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
+ int(PTRCALL *nameMatchesAscii)(const ENCODING *, const char *, const char *,
+ const char *);
+ int(PTRFASTCALL *nameLength)(const ENCODING *, const char *);
const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
- int (PTRCALL *getAtts)(const ENCODING *enc,
- const char *ptr,
- int attsMax,
- ATTRIBUTE *atts);
- int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
- int (PTRCALL *predefinedEntityName)(const ENCODING *,
- const char *,
- const char *);
- void (PTRCALL *updatePosition)(const ENCODING *,
- const char *ptr,
- const char *end,
- POSITION *);
- int (PTRCALL *isPublicId)(const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr);
- void (PTRCALL *utf8Convert)(const ENCODING *enc,
- const char **fromP,
- const char *fromLim,
- char **toP,
- const char *toLim);
- void (PTRCALL *utf16Convert)(const ENCODING *enc,
- const char **fromP,
- const char *fromLim,
- unsigned short **toP,
- const unsigned short *toLim);
+ int(PTRCALL *getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
+ ATTRIBUTE *atts);
+ int(PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
+ int(PTRCALL *predefinedEntityName)(const ENCODING *, const char *,
+ const char *);
+ void(PTRCALL *updatePosition)(const ENCODING *, const char *ptr,
+ const char *end, POSITION *);
+ int(PTRCALL *isPublicId)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **badPtr);
+ enum XML_Convert_Result(PTRCALL *utf8Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim, char **toP,
+ const char *toLim);
+ enum XML_Convert_Result(PTRCALL *utf16Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ unsigned short **toP,
+ const unsigned short *toLim);
int minBytesPerChar;
char isUtf8;
char isUtf16;
@@ -194,68 +216,62 @@ struct encoding {
the prolog outside literals, comments and processing instructions.
*/
-
-#define XmlTok(enc, state, ptr, end, nextTokPtr) \
+#define XmlTok(enc, state, ptr, end, nextTokPtr) \
(((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
-#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
+#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
-#define XmlContentTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
+#define XmlContentTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
-#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
+#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
#ifdef XML_DTD
-#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
+# define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
#endif /* XML_DTD */
/* This is used for performing a 2nd-level tokenization on the content
of a literal that has already been returned by XmlTok.
*/
-#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
+#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
(((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
-#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
- XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
+#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
-#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
- XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
+#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
-#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
-
-#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
+#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
(((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
-#define XmlNameLength(enc, ptr) \
- (((enc)->nameLength)(enc, ptr))
+#define XmlNameLength(enc, ptr) (((enc)->nameLength)(enc, ptr))
-#define XmlSkipS(enc, ptr) \
- (((enc)->skipS)(enc, ptr))
+#define XmlSkipS(enc, ptr) (((enc)->skipS)(enc, ptr))
-#define XmlGetAttributes(enc, ptr, attsMax, atts) \
+#define XmlGetAttributes(enc, ptr, attsMax, atts) \
(((enc)->getAtts)(enc, ptr, attsMax, atts))
-#define XmlCharRefNumber(enc, ptr) \
- (((enc)->charRefNumber)(enc, ptr))
+#define XmlCharRefNumber(enc, ptr) (((enc)->charRefNumber)(enc, ptr))
-#define XmlPredefinedEntityName(enc, ptr, end) \
+#define XmlPredefinedEntityName(enc, ptr, end) \
(((enc)->predefinedEntityName)(enc, ptr, end))
-#define XmlUpdatePosition(enc, ptr, end, pos) \
+#define XmlUpdatePosition(enc, ptr, end, pos) \
(((enc)->updatePosition)(enc, ptr, end, pos))
-#define XmlIsPublicId(enc, ptr, end, badPtr) \
+#define XmlIsPublicId(enc, ptr, end, badPtr) \
(((enc)->isPublicId)(enc, ptr, end, badPtr))
-#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
+#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
(((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
-#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
+#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
(((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
typedef struct {
@@ -263,16 +279,11 @@ typedef struct {
const ENCODING **encPtr;
} INIT_ENCODING;
-int XmlParseXmlDecl(int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
+int XmlParseXmlDecl(int isGeneralTextEntity, const ENCODING *enc,
+ const char *ptr, const char *end, const char **badPtr,
+ const char **versionPtr, const char **versionEndPtr,
const char **encodingNamePtr,
- const ENCODING **namedEncodingPtr,
- int *standalonePtr);
+ const ENCODING **namedEncodingPtr, int *standalonePtr);
int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
const ENCODING *XmlGetUtf8InternalEncoding(void);
@@ -281,34 +292,22 @@ int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
int XmlSizeOfUnknownEncoding(void);
+typedef int(XMLCALL *CONVERTER)(void *userData, const char *p);
-typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
-
-ENCODING *
-XmlInitUnknownEncoding(void *mem,
- int *table,
- CONVERTER convert,
- void *userData);
+ENCODING *XmlInitUnknownEncoding(void *mem, int *table, CONVERTER convert,
+ void *userData);
-int XmlParseXmlDeclNS(int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
+int XmlParseXmlDeclNS(int isGeneralTextEntity, const ENCODING *enc,
+ const char *ptr, const char *end, const char **badPtr,
+ const char **versionPtr, const char **versionEndPtr,
const char **encodingNamePtr,
- const ENCODING **namedEncodingPtr,
- int *standalonePtr);
+ const ENCODING **namedEncodingPtr, int *standalonePtr);
int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
const ENCODING *XmlGetUtf8InternalEncodingNS(void);
const ENCODING *XmlGetUtf16InternalEncodingNS(void);
-ENCODING *
-XmlInitUnknownEncodingNS(void *mem,
- int *table,
- CONVERTER convert,
- void *userData);
+ENCODING *XmlInitUnknownEncodingNS(void *mem, int *table, CONVERTER convert,
+ void *userData);
#ifdef __cplusplus
}
#endif
diff --git a/3rdparty/expat/lib/xmltok_impl.c b/3rdparty/expat/lib/xmltok_impl.c
index 9c2895b8773..06d5c90851f 100644
--- a/3rdparty/expat/lib/xmltok_impl.c
+++ b/3rdparty/expat/lib/xmltok_impl.c
@@ -1,114 +1,155 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/* This file is included!
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/* This file is included! */
#ifdef XML_TOK_IMPL_C
-#ifndef IS_INVALID_CHAR
-#define IS_INVALID_CHAR(enc, ptr, n) (0)
-#endif
+# ifndef IS_INVALID_CHAR
+# define IS_INVALID_CHAR(enc, ptr, n) (0)
+# endif
-#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (IS_INVALID_CHAR(enc, ptr, n)) { \
- *(nextTokPtr) = (ptr); \
- return XML_TOK_INVALID; \
- } \
- ptr += n; \
- break;
+# define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
+ case BT_LEAD##n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
-#define INVALID_CASES(ptr, nextTokPtr) \
- INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
- INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
- INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
- case BT_NONXML: \
- case BT_MALFORM: \
- case BT_TRAIL: \
- *(nextTokPtr) = (ptr); \
+# define INVALID_CASES(ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
+ case BT_NONXML: \
+ case BT_MALFORM: \
+ case BT_TRAIL: \
+ *(nextTokPtr) = (ptr); \
return XML_TOK_INVALID;
-#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (!IS_NAME_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- ptr += n; \
- break;
+# define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD##n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (! IS_NAME_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+# define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (! IS_NAME_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ /* fall through */ \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ case BT_DIGIT: \
+ case BT_NAME: \
+ case BT_MINUS: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
-#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
- case BT_NONASCII: \
- if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- case BT_NMSTRT: \
- case BT_HEX: \
- case BT_DIGIT: \
- case BT_NAME: \
- case BT_MINUS: \
- ptr += MINBPC(enc); \
- break; \
- CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
- CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
- CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
+# define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD##n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (! IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
-#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- ptr += n; \
- break;
+# define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (! IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ /* fall through */ \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
-#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
- case BT_NONASCII: \
- if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- case BT_NMSTRT: \
- case BT_HEX: \
- ptr += MINBPC(enc); \
- break; \
- CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
- CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
- CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
+# ifndef PREFIX
+# define PREFIX(ident) ident
+# endif
-#ifndef PREFIX
-#define PREFIX(ident) ident
-#endif
+# define HAS_CHARS(enc, ptr, end, count) (end - ptr >= count * MINBPC(enc))
+
+# define HAS_CHAR(enc, ptr, end) HAS_CHARS(enc, ptr, end, 1)
+
+# define REQUIRE_CHARS(enc, ptr, end, count) \
+ { \
+ if (! HAS_CHARS(enc, ptr, end, count)) { \
+ return XML_TOK_PARTIAL; \
+ } \
+ }
+
+# define REQUIRE_CHAR(enc, ptr, end) REQUIRE_CHARS(enc, ptr, end, 1)
/* ptr points to character following "<!-" */
static int PTRCALL
-PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- if (ptr != end) {
- if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+PREFIX(scanComment)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ if (HAS_CHAR(enc, ptr, end)) {
+ if (! CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
ptr += MINBPC(enc);
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- INVALID_CASES(ptr, nextTokPtr)
+ INVALID_CASES(ptr, nextTokPtr)
case BT_MINUS:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
@@ -128,11 +169,9 @@ PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
/* ptr points to character following "<!" */
static int PTRCALL
-PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
+PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
case BT_MINUS:
return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -147,19 +186,23 @@ PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
case BT_PERCNT:
- if (ptr + MINBPC(enc) == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHARS(enc, ptr, end, 2);
/* don't allow <!ENTITY% foo "whatever"> */
switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
- case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ case BT_PERCNT:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
/* fall through */
- case BT_S: case BT_CR: case BT_LF:
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
*nextTokPtr = ptr;
return XML_TOK_DECL_OPEN;
case BT_NMSTRT:
@@ -175,12 +218,12 @@ PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
}
static int PTRCALL
-PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
- const char *end, int *tokPtr)
-{
+PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end,
+ int *tokPtr) {
int upper = 0;
+ UNUSED_P(enc);
*tokPtr = XML_TOK_PI;
- if (end - ptr != MINBPC(enc)*3)
+ if (end - ptr != MINBPC(enc) * 3)
return 1;
switch (BYTE_TO_ASCII(enc, ptr)) {
case ASCII_x:
@@ -220,35 +263,34 @@ PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
/* ptr points to character following "<?" */
static int PTRCALL
-PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
+PREFIX(scanPi)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
int tok;
const char *target = ptr;
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_CR: case BT_LF:
- if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ if (! PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
ptr += MINBPC(enc);
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- INVALID_CASES(ptr, nextTokPtr)
+ INVALID_CASES(ptr, nextTokPtr)
case BT_QUEST:
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
*nextTokPtr = ptr + MINBPC(enc);
return tok;
@@ -261,13 +303,12 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
}
return XML_TOK_PARTIAL;
case BT_QUEST:
- if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ if (! PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
*nextTokPtr = ptr + MINBPC(enc);
return tok;
@@ -282,17 +323,16 @@ PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
}
static int PTRCALL
-PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
- ASCII_T, ASCII_A, ASCII_LSQB };
+PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ static const char CDATA_LSQB[]
+ = {ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, ASCII_LSQB};
int i;
+ UNUSED_P(enc);
/* CDATA[ */
- if (end - ptr < 6 * MINBPC(enc))
- return XML_TOK_PARTIAL;
+ REQUIRE_CHARS(enc, ptr, end, 6);
for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
- if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
+ if (! CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
@@ -302,10 +342,9 @@ PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
}
static int PTRCALL
-PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- if (ptr == end)
+PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ if (ptr >= end)
return XML_TOK_NONE;
if (MINBPC(enc) > 1) {
size_t n = end - ptr;
@@ -319,14 +358,12 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
switch (BYTE_TYPE(enc, ptr)) {
case BT_RSQB:
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ REQUIRE_CHAR(enc, ptr, end);
+ if (! CHAR_MATCHES(enc, ptr, ASCII_RSQB))
break;
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ REQUIRE_CHAR(enc, ptr, end);
+ if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) {
ptr -= MINBPC(enc);
break;
}
@@ -334,8 +371,7 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
return XML_TOK_CDATA_SECT_CLOSE;
case BT_CR:
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
if (BYTE_TYPE(enc, ptr) == BT_LF)
ptr += MINBPC(enc);
*nextTokPtr = ptr;
@@ -343,23 +379,25 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
case BT_LF:
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_DATA_NEWLINE;
- INVALID_CASES(ptr, nextTokPtr)
+ INVALID_CASES(ptr, nextTokPtr)
default:
ptr += MINBPC(enc);
break;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_DATA_CHARS; \
- } \
- ptr += n; \
- break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_NONXML:
case BT_MALFORM:
case BT_TRAIL:
@@ -380,24 +418,26 @@ PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
/* ptr points to character following "</" */
static int PTRCALL
-PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
+PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_CR: case BT_LF:
- for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
switch (BYTE_TYPE(enc, ptr)) {
- case BT_S: case BT_CR: case BT_LF:
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
break;
case BT_GT:
*nextTokPtr = ptr + MINBPC(enc);
@@ -408,13 +448,13 @@ PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
}
}
return XML_TOK_PARTIAL;
-#ifdef XML_NS
+# ifdef XML_NS
case BT_COLON:
/* no need to check qname syntax here,
since end-tag must match exactly */
ptr += MINBPC(enc);
break;
-#endif
+# endif
case BT_GT:
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_END_TAG;
@@ -429,10 +469,9 @@ PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
/* ptr points to character following "&#X" */
static int PTRCALL
-PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- if (ptr != end) {
+PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ if (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
case BT_DIGIT:
case BT_HEX:
@@ -441,7 +480,7 @@ PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
switch (BYTE_TYPE(enc, ptr)) {
case BT_DIGIT:
case BT_HEX:
@@ -461,10 +500,9 @@ PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
/* ptr points to character following "&#" */
static int PTRCALL
-PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
- if (ptr != end) {
+PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ if (HAS_CHAR(enc, ptr, end)) {
if (CHAR_MATCHES(enc, ptr, ASCII_x))
return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
switch (BYTE_TYPE(enc, ptr)) {
@@ -474,7 +512,7 @@ PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
switch (BYTE_TYPE(enc, ptr)) {
case BT_DIGIT:
break;
@@ -494,21 +532,19 @@ PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
static int PTRCALL
PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ const char **nextTokPtr) {
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
case BT_NUM:
return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
case BT_SEMI:
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_ENTITY_REF;
@@ -524,15 +560,14 @@ PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
static int PTRCALL
PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
-#ifdef XML_NS
+ const char **nextTokPtr) {
+# ifdef XML_NS
int hadColon = 0;
-#endif
- while (ptr != end) {
+# endif
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-#ifdef XML_NS
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+# ifdef XML_NS
case BT_COLON:
if (hadColon) {
*nextTokPtr = ptr;
@@ -540,23 +575,23 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
}
hadColon = 1;
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
break;
-#endif
- case BT_S: case BT_CR: case BT_LF:
+# endif
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
for (;;) {
int t;
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
t = BYTE_TYPE(enc, ptr);
if (t == BT_EQUALS)
break;
@@ -570,107 +605,102 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
return XML_TOK_INVALID;
}
}
- /* fall through */
- case BT_EQUALS:
- {
- int open;
-#ifdef XML_NS
- hadColon = 0;
-#endif
- for (;;) {
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- open = BYTE_TYPE(enc, ptr);
- if (open == BT_QUOT || open == BT_APOS)
- break;
- switch (open) {
- case BT_S:
- case BT_LF:
- case BT_CR:
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
+ /* fall through */
+ case BT_EQUALS: {
+ int open;
+# ifdef XML_NS
+ hadColon = 0;
+# endif
+ for (;;) {
ptr += MINBPC(enc);
- /* in attribute value */
- for (;;) {
- int t;
- if (ptr == end)
- return XML_TOK_PARTIAL;
- t = BYTE_TYPE(enc, ptr);
- if (t == open)
- break;
- switch (t) {
+ REQUIRE_CHAR(enc, ptr, end);
+ open = BYTE_TYPE(enc, ptr);
+ if (open == BT_QUOT || open == BT_APOS)
+ break;
+ switch (open) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ ptr += MINBPC(enc);
+ /* in attribute value */
+ for (;;) {
+ int t;
+ REQUIRE_CHAR(enc, ptr, end);
+ t = BYTE_TYPE(enc, ptr);
+ if (t == open)
+ break;
+ switch (t) {
INVALID_CASES(ptr, nextTokPtr)
- case BT_AMP:
- {
- int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
- if (tok <= 0) {
- if (tok == XML_TOK_INVALID)
- *nextTokPtr = ptr;
- return tok;
- }
- break;
- }
- case BT_LT:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- default:
- ptr += MINBPC(enc);
- break;
+ case BT_AMP: {
+ int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
+ if (tok <= 0) {
+ if (tok == XML_TOK_INVALID)
+ *nextTokPtr = ptr;
+ return tok;
}
+ break;
+ }
+ case BT_LT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ default:
+ ptr += MINBPC(enc);
+ break;
}
+ }
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ break;
+ case BT_SOL:
+ goto sol;
+ case BT_GT:
+ goto gt;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* ptr points to closing quote */
+ for (;;) {
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
case BT_S:
case BT_CR:
case BT_LF:
- break;
- case BT_SOL:
- goto sol;
+ continue;
case BT_GT:
- goto gt;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- /* ptr points to closing quote */
- for (;;) {
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_WITH_ATTS;
+ case BT_SOL:
+ sol:
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_CR: case BT_LF:
- continue;
- case BT_GT:
- gt:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_START_TAG_WITH_ATTS;
- case BT_SOL:
- sol:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
- default:
+ REQUIRE_CHAR(enc, ptr, end);
+ if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- break;
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
}
break;
}
+ break;
+ }
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
@@ -683,24 +713,21 @@ PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
static int PTRCALL
PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
-#ifdef XML_NS
+ const char **nextTokPtr) {
+# ifdef XML_NS
int hadColon;
-#endif
- if (ptr == end)
- return XML_TOK_PARTIAL;
+# endif
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
case BT_EXCL:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
case BT_MINUS:
return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
case BT_LSQB:
- return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc),
- end, nextTokPtr);
+ return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc), end, nextTokPtr);
}
*nextTokPtr = ptr;
return XML_TOK_INVALID;
@@ -712,14 +739,14 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
-#ifdef XML_NS
+# ifdef XML_NS
hadColon = 0;
-#endif
+# endif
/* we have a start-tag */
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-#ifdef XML_NS
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+# ifdef XML_NS
case BT_COLON:
if (hadColon) {
*nextTokPtr = ptr;
@@ -727,37 +754,39 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
}
hadColon = 1;
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
break;
-#endif
- case BT_S: case BT_CR: case BT_LF:
- {
- ptr += MINBPC(enc);
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
+# endif
+ case BT_S:
+ case BT_CR:
+ case BT_LF: {
+ ptr += MINBPC(enc);
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_GT:
- goto gt;
- case BT_SOL:
- goto sol;
- case BT_S: case BT_CR: case BT_LF:
- ptr += MINBPC(enc);
- continue;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
+ case BT_GT:
+ goto gt;
+ case BT_SOL:
+ goto sol;
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ ptr += MINBPC(enc);
+ continue;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
}
- return XML_TOK_PARTIAL;
+ return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
}
+ return XML_TOK_PARTIAL;
+ }
case BT_GT:
gt:
*nextTokPtr = ptr + MINBPC(enc);
@@ -765,9 +794,8 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
case BT_SOL:
sol:
ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ REQUIRE_CHAR(enc, ptr, end);
+ if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
@@ -783,9 +811,8 @@ PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
static int PTRCALL
PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
+ const char **nextTokPtr) {
+ if (ptr >= end)
return XML_TOK_NONE;
if (MINBPC(enc) > 1) {
size_t n = end - ptr;
@@ -803,7 +830,7 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
case BT_CR:
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return XML_TOK_TRAILING_CR;
if (BYTE_TYPE(enc, ptr) == BT_LF)
ptr += MINBPC(enc);
@@ -814,50 +841,52 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
return XML_TOK_DATA_NEWLINE;
case BT_RSQB:
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return XML_TOK_TRAILING_RSQB;
- if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ if (! CHAR_MATCHES(enc, ptr, ASCII_RSQB))
break;
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return XML_TOK_TRAILING_RSQB;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ if (! CHAR_MATCHES(enc, ptr, ASCII_GT)) {
ptr -= MINBPC(enc);
break;
}
*nextTokPtr = ptr;
return XML_TOK_INVALID;
- INVALID_CASES(ptr, nextTokPtr)
+ INVALID_CASES(ptr, nextTokPtr)
default:
ptr += MINBPC(enc);
break;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_DATA_CHARS; \
- } \
- ptr += n; \
- break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_RSQB:
- if (ptr + MINBPC(enc) != end) {
- if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
- ptr += MINBPC(enc);
- break;
- }
- if (ptr + 2*MINBPC(enc) != end) {
- if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
- ptr += MINBPC(enc);
- break;
- }
- *nextTokPtr = ptr + 2*MINBPC(enc);
- return XML_TOK_INVALID;
- }
+ if (HAS_CHARS(enc, ptr, end, 2)) {
+ if (! CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ if (HAS_CHARS(enc, ptr, end, 3)) {
+ if (! CHAR_MATCHES(enc, ptr + 2 * MINBPC(enc), ASCII_GT)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + 2 * MINBPC(enc);
+ return XML_TOK_INVALID;
+ }
}
/* fall through */
case BT_AMP:
@@ -882,22 +911,23 @@ PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
static int PTRCALL
PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ const char **nextTokPtr) {
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ case BT_PERCNT:
*nextTokPtr = ptr;
return XML_TOK_PERCENT;
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
case BT_SEMI:
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_PARAM_ENTITY_REF;
@@ -911,21 +941,24 @@ PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
static int PTRCALL
PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ const char **nextTokPtr) {
+ REQUIRE_CHAR(enc, ptr, end);
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_CR: case BT_LF: case BT_S:
- case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_CR:
+ case BT_LF:
+ case BT_S:
+ case BT_RPAR:
+ case BT_GT:
+ case BT_PERCNT:
+ case BT_VERBAR:
*nextTokPtr = ptr;
return XML_TOK_POUND_NAME;
default:
@@ -937,25 +970,27 @@ PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
}
static int PTRCALL
-PREFIX(scanLit)(int open, const ENCODING *enc,
- const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- while (ptr != end) {
+PREFIX(scanLit)(int open, const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
+ while (HAS_CHAR(enc, ptr, end)) {
int t = BYTE_TYPE(enc, ptr);
switch (t) {
- INVALID_CASES(ptr, nextTokPtr)
+ INVALID_CASES(ptr, nextTokPtr)
case BT_QUOT:
case BT_APOS:
ptr += MINBPC(enc);
if (t != open)
break;
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return -XML_TOK_LITERAL;
*nextTokPtr = ptr;
switch (BYTE_TYPE(enc, ptr)) {
- case BT_S: case BT_CR: case BT_LF:
- case BT_GT: case BT_PERCNT: case BT_LSQB:
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ case BT_GT:
+ case BT_PERCNT:
+ case BT_LSQB:
return XML_TOK_LITERAL;
default:
return XML_TOK_INVALID;
@@ -970,10 +1005,9 @@ PREFIX(scanLit)(int open, const ENCODING *enc,
static int PTRCALL
PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
+ const char **nextTokPtr) {
int tok;
- if (ptr == end)
+ if (ptr >= end)
return XML_TOK_NONE;
if (MINBPC(enc) > 1) {
size_t n = end - ptr;
@@ -989,28 +1023,26 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
case BT_APOS:
return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_LT:
- {
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_EXCL:
- return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_QUEST:
- return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_NMSTRT:
- case BT_HEX:
- case BT_NONASCII:
- case BT_LEAD2:
- case BT_LEAD3:
- case BT_LEAD4:
- *nextTokPtr = ptr - MINBPC(enc);
- return XML_TOK_INSTANCE_START;
- }
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
+ case BT_LT: {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_EXCL:
+ return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_NMSTRT:
+ case BT_HEX:
+ case BT_NONASCII:
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ *nextTokPtr = ptr - MINBPC(enc);
+ return XML_TOK_INSTANCE_START;
}
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
case BT_CR:
if (ptr + MINBPC(enc) == end) {
*nextTokPtr = end;
@@ -1018,13 +1050,15 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
return -XML_TOK_PROLOG_S;
}
/* fall through */
- case BT_S: case BT_LF:
+ case BT_S:
+ case BT_LF:
for (;;) {
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
break;
switch (BYTE_TYPE(enc, ptr)) {
- case BT_S: case BT_LF:
+ case BT_S:
+ case BT_LF:
break;
case BT_CR:
/* don't split CR/LF pair */
@@ -1048,13 +1082,12 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
return XML_TOK_OPEN_BRACKET;
case BT_RSQB:
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return -XML_TOK_CLOSE_BRACKET;
if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
- if (ptr + MINBPC(enc) == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHARS(enc, ptr, end, 2);
if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
- *nextTokPtr = ptr + 2*MINBPC(enc);
+ *nextTokPtr = ptr + 2 * MINBPC(enc);
return XML_TOK_COND_SECT_CLOSE;
}
}
@@ -1065,7 +1098,7 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
return XML_TOK_OPEN_PAREN;
case BT_RPAR:
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return -XML_TOK_CLOSE_PAREN;
switch (BYTE_TYPE(enc, ptr)) {
case BT_AST:
@@ -1077,8 +1110,12 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
case BT_PLUS:
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_CLOSE_PAREN_PLUS;
- case BT_CR: case BT_LF: case BT_S:
- case BT_GT: case BT_COMMA: case BT_VERBAR:
+ case BT_CR:
+ case BT_LF:
+ case BT_S:
+ case BT_GT:
+ case BT_COMMA:
+ case BT_VERBAR:
case BT_RPAR:
*nextTokPtr = ptr;
return XML_TOK_CLOSE_PAREN;
@@ -1093,24 +1130,26 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
return XML_TOK_DECL_CLOSE;
case BT_NUM:
return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
- ptr += n; \
- tok = XML_TOK_NAME; \
- break; \
- } \
- if (IS_NAME_CHAR(enc, ptr, n)) { \
- ptr += n; \
- tok = XML_TOK_NMTOKEN; \
- break; \
- } \
- *nextTokPtr = ptr; \
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NAME; \
+ break; \
+ } \
+ if (IS_NAME_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NMTOKEN; \
+ break; \
+ } \
+ *nextTokPtr = ptr; \
return XML_TOK_INVALID;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_NMSTRT:
case BT_HEX:
tok = XML_TOK_NAME;
@@ -1119,9 +1158,9 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
case BT_DIGIT:
case BT_NAME:
case BT_MINUS:
-#ifdef XML_NS
+# ifdef XML_NS
case BT_COLON:
-#endif
+# endif
tok = XML_TOK_NMTOKEN;
ptr += MINBPC(enc);
break;
@@ -1141,24 +1180,29 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_GT: case BT_RPAR: case BT_COMMA:
- case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
- case BT_S: case BT_CR: case BT_LF:
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT:
+ case BT_RPAR:
+ case BT_COMMA:
+ case BT_VERBAR:
+ case BT_LSQB:
+ case BT_PERCNT:
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
*nextTokPtr = ptr;
return tok;
-#ifdef XML_NS
+# ifdef XML_NS
case BT_COLON:
ptr += MINBPC(enc);
switch (tok) {
case XML_TOK_NAME:
- if (ptr == end)
- return XML_TOK_PARTIAL;
+ REQUIRE_CHAR(enc, ptr, end);
tok = XML_TOK_PREFIXED_NAME;
switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
default:
tok = XML_TOK_NMTOKEN;
break;
@@ -1169,23 +1213,23 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
break;
}
break;
-#endif
+# endif
case BT_PLUS:
- if (tok == XML_TOK_NMTOKEN) {
+ if (tok == XML_TOK_NMTOKEN) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_NAME_PLUS;
case BT_AST:
- if (tok == XML_TOK_NMTOKEN) {
+ if (tok == XML_TOK_NMTOKEN) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
*nextTokPtr = ptr + MINBPC(enc);
return XML_TOK_NAME_ASTERISK;
case BT_QUEST:
- if (tok == XML_TOK_NMTOKEN) {
+ if (tok == XML_TOK_NMTOKEN) {
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
@@ -1200,19 +1244,30 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
}
static int PTRCALL
-PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
+PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
const char *start;
- if (ptr == end)
+ if (ptr >= end)
return XML_TOK_NONE;
+ else if (! HAS_CHAR(enc, ptr, end)) {
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
+ * already been eliminated from the input. Retaining the paranoia
+ * check is still valuable, however.
+ */
+ return XML_TOK_PARTIAL; /* LCOV_EXCL_LINE */
+ }
start = ptr;
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: ptr += n; break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_AMP:
if (ptr == start)
return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -1232,7 +1287,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
case BT_CR:
if (ptr == start) {
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return XML_TOK_TRAILING_CR;
if (BYTE_TYPE(enc, ptr) == BT_LF)
ptr += MINBPC(enc);
@@ -1258,19 +1313,30 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
}
static int PTRCALL
-PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
+PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
const char *start;
- if (ptr == end)
+ if (ptr >= end)
return XML_TOK_NONE;
+ else if (! HAS_CHAR(enc, ptr, end)) {
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
+ * already been eliminated from the input. Retaining the paranoia
+ * check is still valuable, however.
+ */
+ return XML_TOK_PARTIAL; /* LCOV_EXCL_LINE */
+ }
start = ptr;
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: ptr += n; break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_AMP:
if (ptr == start)
return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
@@ -1278,8 +1344,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
return XML_TOK_DATA_CHARS;
case BT_PERCNT:
if (ptr == start) {
- int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
- end, nextTokPtr);
+ int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
}
*nextTokPtr = ptr;
@@ -1294,7 +1359,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
case BT_CR:
if (ptr == start) {
ptr += MINBPC(enc);
- if (ptr == end)
+ if (! HAS_CHAR(enc, ptr, end))
return XML_TOK_TRAILING_CR;
if (BYTE_TYPE(enc, ptr) == BT_LF)
ptr += MINBPC(enc);
@@ -1312,12 +1377,11 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
return XML_TOK_DATA_CHARS;
}
-#ifdef XML_DTD
+# ifdef XML_DTD
static int PTRCALL
-PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
- const char *end, const char **nextTokPtr)
-{
+PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr) {
int level = 0;
if (MINBPC(enc) > 1) {
size_t n = end - ptr;
@@ -1326,15 +1390,15 @@ PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
end = ptr + n;
}
}
- while (ptr != end) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
- INVALID_CASES(ptr, nextTokPtr)
+ INVALID_CASES(ptr, nextTokPtr)
case BT_LT:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
++level;
ptr += MINBPC(enc);
@@ -1342,11 +1406,11 @@ PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
}
break;
case BT_RSQB:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
ptr += MINBPC(enc);
if (level == 0) {
@@ -1365,15 +1429,14 @@ PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
return XML_TOK_PARTIAL;
}
-#endif /* XML_DTD */
+# endif /* XML_DTD */
static int PTRCALL
PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
- const char **badPtr)
-{
+ const char **badPtr) {
ptr += MINBPC(enc);
end -= MINBPC(enc);
- for (; ptr != end; ptr += MINBPC(enc)) {
+ for (; HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
switch (BYTE_TYPE(enc, ptr)) {
case BT_DIGIT:
case BT_HEX:
@@ -1393,9 +1456,9 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
case BT_AST:
case BT_PERCNT:
case BT_NUM:
-#ifdef XML_NS
+# ifdef XML_NS
case BT_COLON:
-#endif
+# endif
break;
case BT_S:
if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
@@ -1405,8 +1468,9 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
break;
case BT_NAME:
case BT_NMSTRT:
- if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
+ if (! (BYTE_TO_ASCII(enc, ptr) & ~0x7f))
break;
+ /* fall through */
default:
switch (BYTE_TO_ASCII(enc, ptr)) {
case 0x24: /* $ */
@@ -1428,9 +1492,8 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
*/
static int PTRCALL
-PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
- int attsMax, ATTRIBUTE *atts)
-{
+PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
+ ATTRIBUTE *atts) {
enum { other, inName, inValue } state = inName;
int nAtts = 0;
int open = 0; /* defined when state == inValue;
@@ -1438,32 +1501,35 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
switch (BYTE_TYPE(enc, ptr)) {
-#define START_NAME \
- if (state == other) { \
- if (nAtts < attsMax) { \
- atts[nAtts].name = ptr; \
- atts[nAtts].normalized = 1; \
- } \
- state = inName; \
- }
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define START_NAME \
+ if (state == other) { \
+ if (nAtts < attsMax) { \
+ atts[nAtts].name = ptr; \
+ atts[nAtts].normalized = 1; \
+ } \
+ state = inName; \
+ }
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ START_NAME ptr += (n - MINBPC(enc)); \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_NONASCII:
case BT_NMSTRT:
case BT_HEX:
START_NAME
break;
-#undef START_NAME
+# undef START_NAME
case BT_QUOT:
if (state != inValue) {
if (nAtts < attsMax)
atts[nAtts].valuePtr = ptr + MINBPC(enc);
state = inValue;
open = BT_QUOT;
- }
- else if (open == BT_QUOT) {
+ } else if (open == BT_QUOT) {
state = other;
if (nAtts < attsMax)
atts[nAtts].valueEnd = ptr;
@@ -1476,8 +1542,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
atts[nAtts].valuePtr = ptr + MINBPC(enc);
state = inValue;
open = BT_APOS;
- }
- else if (open == BT_APOS) {
+ } else if (open == BT_APOS) {
state = other;
if (nAtts < attsMax)
atts[nAtts].valueEnd = ptr;
@@ -1491,16 +1556,15 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
case BT_S:
if (state == inName)
state = other;
- else if (state == inValue
- && nAtts < attsMax
- && atts[nAtts].normalized
+ else if (state == inValue && nAtts < attsMax && atts[nAtts].normalized
&& (ptr == atts[nAtts].valuePtr
|| BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
|| BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
|| BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
atts[nAtts].normalized = 0;
break;
- case BT_CR: case BT_LF:
+ case BT_CR:
+ case BT_LF:
/* This case ensures that the first attribute name is counted
Apart from that we could just change state on the quote. */
if (state == inName)
@@ -1521,29 +1585,44 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
}
static int PTRFASTCALL
-PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
-{
+PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) {
int result = 0;
/* skip &# */
- ptr += 2*MINBPC(enc);
+ UNUSED_P(enc);
+ ptr += 2 * MINBPC(enc);
if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
- for (ptr += MINBPC(enc);
- !CHAR_MATCHES(enc, ptr, ASCII_SEMI);
+ for (ptr += MINBPC(enc); ! CHAR_MATCHES(enc, ptr, ASCII_SEMI);
ptr += MINBPC(enc)) {
int c = BYTE_TO_ASCII(enc, ptr);
switch (c) {
- case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
- case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
+ case ASCII_0:
+ case ASCII_1:
+ case ASCII_2:
+ case ASCII_3:
+ case ASCII_4:
+ case ASCII_5:
+ case ASCII_6:
+ case ASCII_7:
+ case ASCII_8:
+ case ASCII_9:
result <<= 4;
result |= (c - ASCII_0);
break;
- case ASCII_A: case ASCII_B: case ASCII_C:
- case ASCII_D: case ASCII_E: case ASCII_F:
+ case ASCII_A:
+ case ASCII_B:
+ case ASCII_C:
+ case ASCII_D:
+ case ASCII_E:
+ case ASCII_F:
result <<= 4;
result += 10 + (c - ASCII_A);
break;
- case ASCII_a: case ASCII_b: case ASCII_c:
- case ASCII_d: case ASCII_e: case ASCII_f:
+ case ASCII_a:
+ case ASCII_b:
+ case ASCII_c:
+ case ASCII_d:
+ case ASCII_e:
+ case ASCII_f:
result <<= 4;
result += 10 + (c - ASCII_a);
break;
@@ -1551,9 +1630,8 @@ PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
if (result >= 0x110000)
return -1;
}
- }
- else {
- for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
+ } else {
+ for (; ! CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
int c = BYTE_TO_ASCII(enc, ptr);
result *= 10;
result += (c - ASCII_0);
@@ -1566,9 +1644,9 @@ PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
static int PTRCALL
PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
- const char *end)
-{
- switch ((end - ptr)/MINBPC(enc)) {
+ const char *end) {
+ UNUSED_P(enc);
+ switch ((end - ptr) / MINBPC(enc)) {
case 2:
if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
switch (BYTE_TO_ASCII(enc, ptr)) {
@@ -1619,97 +1697,42 @@ PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
}
static int PTRCALL
-PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
-{
- for (;;) {
- switch (BYTE_TYPE(enc, ptr1)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (*ptr1++ != *ptr2++) \
- return 0;
- LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
-#undef LEAD_CASE
- /* fall through */
- if (*ptr1++ != *ptr2++)
- return 0;
- break;
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 1) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 2) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 3) {
- if (*ptr2++ != *ptr1++)
- return 0;
- }
- }
- }
- break;
- default:
- if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
- return 1;
- switch (BYTE_TYPE(enc, ptr2)) {
- case BT_LEAD2:
- case BT_LEAD3:
- case BT_LEAD4:
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- return 0;
- default:
- return 1;
- }
- }
- }
- /* not reached */
-}
-
-static int PTRCALL
PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
- const char *end1, const char *ptr2)
-{
+ const char *end1, const char *ptr2) {
+ UNUSED_P(enc);
for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
- if (ptr1 == end1)
- return 0;
- if (!CHAR_MATCHES(enc, ptr1, *ptr2))
+ if (end1 - ptr1 < MINBPC(enc)) {
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
+ * already been eliminated from the input. Retaining the
+ * paranoia check is still valuable, however.
+ */
+ return 0; /* LCOV_EXCL_LINE */
+ }
+ if (! CHAR_MATCHES(enc, ptr1, *ptr2))
return 0;
}
return ptr1 == end1;
}
static int PTRFASTCALL
-PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
-{
+PREFIX(nameLength)(const ENCODING *enc, const char *ptr) {
const char *start = ptr;
for (;;) {
switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: ptr += n; break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_NONASCII:
case BT_NMSTRT:
-#ifdef XML_NS
+# ifdef XML_NS
case BT_COLON:
-#endif
+# endif
case BT_HEX:
case BT_DIGIT:
case BT_NAME:
@@ -1722,9 +1745,8 @@ PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
}
}
-static const char * PTRFASTCALL
-PREFIX(skipS)(const ENCODING *enc, const char *ptr)
-{
+static const char *PTRFASTCALL
+PREFIX(skipS)(const ENCODING *enc, const char *ptr) {
for (;;) {
switch (BYTE_TYPE(enc, ptr)) {
case BT_LF:
@@ -1739,45 +1761,45 @@ PREFIX(skipS)(const ENCODING *enc, const char *ptr)
}
static void PTRCALL
-PREFIX(updatePosition)(const ENCODING *enc,
- const char *ptr,
- const char *end,
- POSITION *pos)
-{
- while (ptr < end) {
+PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
+ POSITION *pos) {
+ while (HAS_CHAR(enc, ptr, end)) {
switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- ptr += n; \
- break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
+# define LEAD_CASE(n) \
+ case BT_LEAD##n: \
+ ptr += n; \
+ pos->columnNumber++; \
+ break;
+ LEAD_CASE(2)
+ LEAD_CASE(3)
+ LEAD_CASE(4)
+# undef LEAD_CASE
case BT_LF:
- pos->columnNumber = (XML_Size)-1;
+ pos->columnNumber = 0;
pos->lineNumber++;
ptr += MINBPC(enc);
break;
case BT_CR:
pos->lineNumber++;
ptr += MINBPC(enc);
- if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+ if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF)
ptr += MINBPC(enc);
- pos->columnNumber = (XML_Size)-1;
+ pos->columnNumber = 0;
break;
default:
ptr += MINBPC(enc);
+ pos->columnNumber++;
break;
}
- pos->columnNumber++;
}
}
-#undef DO_LEAD_CASE
-#undef MULTIBYTE_CASES
-#undef INVALID_CASES
-#undef CHECK_NAME_CASE
-#undef CHECK_NAME_CASES
-#undef CHECK_NMSTRT_CASE
-#undef CHECK_NMSTRT_CASES
+# undef DO_LEAD_CASE
+# undef MULTIBYTE_CASES
+# undef INVALID_CASES
+# undef CHECK_NAME_CASE
+# undef CHECK_NAME_CASES
+# undef CHECK_NMSTRT_CASE
+# undef CHECK_NMSTRT_CASES
#endif /* XML_TOK_IMPL_C */
diff --git a/3rdparty/expat/lib/xmltok_impl.h b/3rdparty/expat/lib/xmltok_impl.h
index da0ea60a657..e925dbc7e2c 100644
--- a/3rdparty/expat/lib/xmltok_impl.h
+++ b/3rdparty/expat/lib/xmltok_impl.h
@@ -1,46 +1,73 @@
/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
enum {
- BT_NONXML,
- BT_MALFORM,
- BT_LT,
- BT_AMP,
- BT_RSQB,
- BT_LEAD2,
- BT_LEAD3,
- BT_LEAD4,
- BT_TRAIL,
- BT_CR,
- BT_LF,
- BT_GT,
- BT_QUOT,
- BT_APOS,
- BT_EQUALS,
- BT_QUEST,
- BT_EXCL,
- BT_SOL,
- BT_SEMI,
- BT_NUM,
- BT_LSQB,
- BT_S,
- BT_NMSTRT,
- BT_COLON,
- BT_HEX,
- BT_DIGIT,
- BT_NAME,
- BT_MINUS,
- BT_OTHER, /* known not to be a name or name start character */
+ BT_NONXML, /* e.g. noncharacter-FFFF */
+ BT_MALFORM, /* illegal, with regard to encoding */
+ BT_LT, /* less than = "<" */
+ BT_AMP, /* ampersand = "&" */
+ BT_RSQB, /* right square bracket = "[" */
+ BT_LEAD2, /* lead byte of a 2-byte UTF-8 character */
+ BT_LEAD3, /* lead byte of a 3-byte UTF-8 character */
+ BT_LEAD4, /* lead byte of a 4-byte UTF-8 character */
+ BT_TRAIL, /* trailing unit, e.g. second 16-bit unit of a 4-byte char. */
+ BT_CR, /* carriage return = "\r" */
+ BT_LF, /* line feed = "\n" */
+ BT_GT, /* greater than = ">" */
+ BT_QUOT, /* quotation character = "\"" */
+ BT_APOS, /* aposthrophe = "'" */
+ BT_EQUALS, /* equal sign = "=" */
+ BT_QUEST, /* question mark = "?" */
+ BT_EXCL, /* exclamation mark = "!" */
+ BT_SOL, /* solidus, slash = "/" */
+ BT_SEMI, /* semicolon = ";" */
+ BT_NUM, /* number sign = "#" */
+ BT_LSQB, /* left square bracket = "[" */
+ BT_S, /* white space, e.g. "\t", " "[, "\r"] */
+ BT_NMSTRT, /* non-hex name start letter = "G".."Z" + "g".."z" + "_" */
+ BT_COLON, /* colon = ":" */
+ BT_HEX, /* hex letter = "A".."F" + "a".."f" */
+ BT_DIGIT, /* digit = "0".."9" */
+ BT_NAME, /* dot and middle dot = "." + chr(0xb7) */
+ BT_MINUS, /* minus = "-" */
+ BT_OTHER, /* known not to be a name or name start character */
BT_NONASCII, /* might be a name or name start character */
- BT_PERCNT,
- BT_LPAR,
- BT_RPAR,
- BT_AST,
- BT_PLUS,
- BT_COMMA,
- BT_VERBAR
+ BT_PERCNT, /* percent sign = "%" */
+ BT_LPAR, /* left parenthesis = "(" */
+ BT_RPAR, /* right parenthesis = "(" */
+ BT_AST, /* asterisk = "*" */
+ BT_PLUS, /* plus sign = "+" */
+ BT_COMMA, /* comma = "," */
+ BT_VERBAR /* vertical bar = "|" */
};
#include <stddef.h>
diff --git a/3rdparty/expat/lib/xmltok_ns.c b/3rdparty/expat/lib/xmltok_ns.c
index c3b88fdf4e3..919c74e9f97 100644
--- a/3rdparty/expat/lib/xmltok_ns.c
+++ b/3rdparty/expat/lib/xmltok_ns.c
@@ -1,61 +1,79 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/* This file is included!
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/* This file is included! */
#ifdef XML_TOK_NS_C
const ENCODING *
-NS(XmlGetUtf8InternalEncoding)(void)
-{
+NS(XmlGetUtf8InternalEncoding)(void) {
return &ns(internal_utf8_encoding).enc;
}
const ENCODING *
-NS(XmlGetUtf16InternalEncoding)(void)
-{
-#if BYTEORDER == 1234
+NS(XmlGetUtf16InternalEncoding)(void) {
+# if BYTEORDER == 1234
return &ns(internal_little2_encoding).enc;
-#elif BYTEORDER == 4321
+# elif BYTEORDER == 4321
return &ns(internal_big2_encoding).enc;
-#else
+# else
const short n = 1;
- return (*(const char *)&n
- ? &ns(internal_little2_encoding).enc
- : &ns(internal_big2_encoding).enc);
-#endif
+ return (*(const char *)&n ? &ns(internal_little2_encoding).enc
+ : &ns(internal_big2_encoding).enc);
+# endif
}
-static const ENCODING * const NS(encodings)[] = {
- &ns(latin1_encoding).enc,
- &ns(ascii_encoding).enc,
- &ns(utf8_encoding).enc,
- &ns(big2_encoding).enc,
- &ns(big2_encoding).enc,
- &ns(little2_encoding).enc,
- &ns(utf8_encoding).enc /* NO_ENC */
+static const ENCODING *const NS(encodings)[] = {
+ &ns(latin1_encoding).enc, &ns(ascii_encoding).enc,
+ &ns(utf8_encoding).enc, &ns(big2_encoding).enc,
+ &ns(big2_encoding).enc, &ns(little2_encoding).enc,
+ &ns(utf8_encoding).enc /* NO_ENC */
};
static int PTRCALL
NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- return initScan(NS(encodings), (const INIT_ENCODING *)enc,
- XML_PROLOG_STATE, ptr, end, nextTokPtr);
+ const char **nextTokPtr) {
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE,
+ ptr, end, nextTokPtr);
}
static int PTRCALL
NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- return initScan(NS(encodings), (const INIT_ENCODING *)enc,
- XML_CONTENT_STATE, ptr, end, nextTokPtr);
+ const char **nextTokPtr) {
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE,
+ ptr, end, nextTokPtr);
}
int
NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
- const char *name)
-{
+ const char *name) {
int i = getEncodingIndex(name);
if (i == UNKNOWN_ENC)
return 0;
@@ -69,9 +87,8 @@ NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
}
static const ENCODING *
-NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
-{
-#define ENCODING_MAX 128
+NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) {
+# define ENCODING_MAX 128
char buf[ENCODING_MAX];
char *p = buf;
int i;
@@ -88,28 +105,14 @@ NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
}
int
-NS(XmlParseXmlDecl)(int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
- const char **encodingName,
- const ENCODING **encoding,
- int *standalone)
-{
- return doParseXmlDecl(NS(findEncoding),
- isGeneralTextEntity,
- enc,
- ptr,
- end,
- badPtr,
- versionPtr,
- versionEndPtr,
- encodingName,
- encoding,
- standalone);
+NS(XmlParseXmlDecl)(int isGeneralTextEntity, const ENCODING *enc,
+ const char *ptr, const char *end, const char **badPtr,
+ const char **versionPtr, const char **versionEndPtr,
+ const char **encodingName, const ENCODING **encoding,
+ int *standalone) {
+ return doParseXmlDecl(NS(findEncoding), isGeneralTextEntity, enc, ptr, end,
+ badPtr, versionPtr, versionEndPtr, encodingName,
+ encoding, standalone);
}
#endif /* XML_TOK_NS_C */
diff --git a/3rdparty/expat/m4/libtool.m4 b/3rdparty/expat/m4/libtool.m4
index d7c043f4f99..ae7c9061329 100644
--- a/3rdparty/expat/m4/libtool.m4
+++ b/3rdparty/expat/m4/libtool.m4
@@ -1,8 +1,6 @@
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-# Foundation, Inc.
+# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
# Written by Gordon Matzigkeit, 1996
#
# This file is free software; the Free Software Foundation gives
@@ -10,36 +8,30 @@
# modifications, as long as this notice is preserved.
m4_define([_LT_COPYING], [dnl
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
-# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
-# Foundation, Inc.
-# Written by Gordon Matzigkeit, 1996
-#
-# This file is part of GNU Libtool.
-#
-# GNU Libtool is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
#
-# GNU Libtool is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with GNU Libtool; see the file COPYING. If not, a copy
-# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
-# obtained by writing to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
])
-# serial 57 LT_INIT
+# serial 58 LT_INIT
# LT_PREREQ(VERSION)
@@ -67,7 +59,7 @@ esac
# LT_INIT([OPTIONS])
# ------------------
AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
AC_BEFORE([$0], [LT_LANG])dnl
AC_BEFORE([$0], [LT_OUTPUT])dnl
@@ -91,7 +83,7 @@ dnl Parse OPTIONS
_LT_SET_OPTIONS([$0], [$1])
# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS="$ltmain"
+LIBTOOL_DEPS=$ltmain
# Always use our own libtool.
LIBTOOL='$(SHELL) $(top_builddir)/libtool'
@@ -111,26 +103,43 @@ dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in @S|@*""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
# _LT_CC_BASENAME(CC)
# -------------------
-# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
m4_defun([_LT_CC_BASENAME],
-[for cc_temp in $1""; do
- case $cc_temp in
- compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
- distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
- \-*) ;;
- *) break;;
- esac
-done
-cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
])
# _LT_FILEUTILS_DEFAULTS
# ----------------------
# It is okay to use these file commands and assume they have been set
-# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
m4_defun([_LT_FILEUTILS_DEFAULTS],
[: ${CP="cp -f"}
: ${MV="mv -f"}
@@ -177,15 +186,16 @@ m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
m4_require([_LT_CMD_OLD_ARCHIVE])dnl
m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
_LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options which allow our
+# See if we are running on zsh, and set the options that allow our
# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}" ; then
+if test -n "\${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
])
-if test -n "${ZSH_VERSION+set}" ; then
+if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
@@ -198,7 +208,7 @@ aix3*)
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
- if test "X${COLLECT_NAMES+set}" != Xset; then
+ if test set != "${COLLECT_NAMES+set}"; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
@@ -209,14 +219,14 @@ esac
ofile=libtool
can_build_shared=yes
-# All known linkers require a `.a' archive for static linking (except MSVC,
+# All known linkers require a '.a' archive for static linking (except MSVC,
# which needs '.lib').
libext=a
-with_gnu_ld="$lt_cv_prog_gnu_ld"
+with_gnu_ld=$lt_cv_prog_gnu_ld
-old_CC="$CC"
-old_CFLAGS="$CFLAGS"
+old_CC=$CC
+old_CFLAGS=$CFLAGS
# Set sane defaults for various variables
test -z "$CC" && CC=cc
@@ -269,14 +279,14 @@ no_glob_subst='s/\*/\\\*/g'
# _LT_PROG_LTMAIN
# ---------------
-# Note that this code is called both from `configure', and `config.status'
+# Note that this code is called both from 'configure', and 'config.status'
# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
-# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
# so we pass a copy along to make sure it has a sensible value anyway.
m4_defun([_LT_PROG_LTMAIN],
[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
-ltmain="$ac_aux_dir/ltmain.sh"
+ltmain=$ac_aux_dir/ltmain.sh
])# _LT_PROG_LTMAIN
@@ -286,7 +296,7 @@ ltmain="$ac_aux_dir/ltmain.sh"
# So that we can recreate a full libtool script including additional
# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the `libtool'
+# in macros and then make a single call at the end using the 'libtool'
# label.
@@ -421,8 +431,8 @@ m4_define([_lt_decl_all_varnames],
# _LT_CONFIG_STATUS_DECLARE([VARNAME])
# ------------------------------------
-# Quote a variable value, and forward it to `config.status' so that its
-# declaration there will have the same value as in `configure'. VARNAME
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'. VARNAME
# must have a single quote delimited value for this to work.
m4_define([_LT_CONFIG_STATUS_DECLARE],
[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
@@ -446,7 +456,7 @@ m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
# Output comment and list of tags supported by the script
m4_defun([_LT_LIBTOOL_TAGS],
[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags="_LT_TAGS"dnl
+available_tags='_LT_TAGS'dnl
])
@@ -474,7 +484,7 @@ m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
# _LT_LIBTOOL_CONFIG_VARS
# -----------------------
# Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
# section) are produced by _LT_LIBTOOL_TAG_VARS.
m4_defun([_LT_LIBTOOL_CONFIG_VARS],
@@ -500,8 +510,8 @@ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
# variables for single and double quote escaping we saved from calls
# to _LT_DECL, we can put quote escaped variables declarations
-# into `config.status', and then the shell code to quote escape them in
-# for loops in `config.status'. Finally, any additional code accumulated
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'. Finally, any additional code accumulated
# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
m4_defun([_LT_CONFIG_COMMANDS],
[AC_PROVIDE_IFELSE([LT_OUTPUT],
@@ -547,7 +557,7 @@ for var in lt_decl_all_varnames([[ \
]], lt_decl_quote_varnames); do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[[\\\\\\\`\\"\\\$]]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -560,7 +570,7 @@ for var in lt_decl_all_varnames([[ \
]], lt_decl_dquote_varnames); do
case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
*[[\\\\\\\`\\"\\\$]]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
;;
*)
eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
@@ -576,7 +586,7 @@ _LT_OUTPUT_LIBTOOL_INIT
# Generate a child script FILE with all initialization necessary to
# reuse the environment learned by the parent script, and make the
# file executable. If COMMENT is supplied, it is inserted after the
-# `#!' sequence but before initialization text begins. After this
+# '#!' sequence but before initialization text begins. After this
# macro, additional text can be appended to FILE to form the body of
# the child script. The macro ends with non-zero status if the
# file could not be fully written (such as if the disk is full).
@@ -598,7 +608,7 @@ AS_SHELL_SANITIZE
_AS_PREPARE
exec AS_MESSAGE_FD>&1
_ASEOF
-test $lt_write_fail = 0 && chmod +x $1[]dnl
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
# LT_OUTPUT
@@ -621,7 +631,7 @@ exec AS_MESSAGE_LOG_FD>>config.log
} >&AS_MESSAGE_LOG_FD
lt_cl_help="\
-\`$as_me' creates a local libtool stub from the current configuration,
+'$as_me' creates a local libtool stub from the current configuration,
for use in further configure time tests before the real libtool is
generated.
@@ -643,7 +653,7 @@ Copyright (C) 2011 Free Software Foundation, Inc.
This config.lt script is free software; the Free Software Foundation
gives unlimited permision to copy, distribute and modify it."
-while test $[#] != 0
+while test 0 != $[#]
do
case $[1] in
--version | --v* | -V )
@@ -656,10 +666,10 @@ do
lt_cl_silent=: ;;
-*) AC_MSG_ERROR([unrecognized option: $[1]
-Try \`$[0] --help' for more information.]) ;;
+Try '$[0] --help' for more information.]) ;;
*) AC_MSG_ERROR([unrecognized argument: $[1]
-Try \`$[0] --help' for more information.]) ;;
+Try '$[0] --help' for more information.]) ;;
esac
shift
done
@@ -685,7 +695,7 @@ chmod +x "$CONFIG_LT"
# open by configure. Here we exec the FD to /dev/null, effectively closing
# config.log, so it can be properly (re)opened and appended to by config.lt.
lt_cl_success=:
-test "$silent" = yes &&
+test yes = "$silent" &&
lt_config_lt_args="$lt_config_lt_args --quiet"
exec AS_MESSAGE_LOG_FD>/dev/null
$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
@@ -705,27 +715,31 @@ m4_defun([_LT_CONFIG],
_LT_CONFIG_SAVE_COMMANDS([
m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
m4_if(_LT_TAG, [C], [
- # See if we are running on zsh, and set the options which allow our
+ # See if we are running on zsh, and set the options that allow our
# commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}" ; then
+ if test -n "${ZSH_VERSION+set}"; then
setopt NO_GLOB_SUBST
fi
- cfgfile="${ofile}T"
+ cfgfile=${ofile}T
trap "$RM \"$cfgfile\"; exit 1" 1 2 15
$RM "$cfgfile"
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
-
-# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
-# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Generated automatically by $as_me ($PACKAGE) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-#
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
_LT_COPYING
_LT_LIBTOOL_TAGS
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
# ### BEGIN LIBTOOL CONFIG
_LT_LIBTOOL_CONFIG_VARS
_LT_LIBTOOL_TAG_VARS
@@ -733,13 +747,24 @@ _LT_LIBTOOL_TAG_VARS
_LT_EOF
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
case $host_os in
aix3*)
cat <<\_LT_EOF >> "$cfgfile"
# AIX sometimes has problems with the GCC collect2 program. For some
# reason, if we set the COLLECT_NAMES environment variable, the problems
# vanish in a puff of smoke.
-if test "X${COLLECT_NAMES+set}" != Xset; then
+if test set != "${COLLECT_NAMES+set}"; then
COLLECT_NAMES=
export COLLECT_NAMES
fi
@@ -756,8 +781,6 @@ _LT_EOF
sed '$q' "$ltmain" >> "$cfgfile" \
|| (rm -f "$cfgfile"; exit 1)
- _LT_PROG_REPLACE_SHELLFNS
-
mv -f "$cfgfile" "$ofile" ||
(rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
chmod +x "$ofile"
@@ -775,7 +798,6 @@ _LT_EOF
[m4_if([$1], [], [
PACKAGE='$PACKAGE'
VERSION='$VERSION'
- TIMESTAMP='$TIMESTAMP'
RM='$RM'
ofile='$ofile'], [])
])dnl /_LT_CONFIG_SAVE_COMMANDS
@@ -974,7 +996,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
[lt_cv_apple_cc_single_mod=no
- if test -z "${LT_MULTI_MODULE}"; then
+ if test -z "$LT_MULTI_MODULE"; then
# By default we will add the -single_module flag. You can override
# by either setting the environment variable LT_MULTI_MODULE
# non-empty at configure time, or by adding -multi_module to the
@@ -992,7 +1014,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
cat conftest.err >&AS_MESSAGE_LOG_FD
# Otherwise, if the output was created with a 0 exit code from
# the compiler, it worked.
- elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
lt_cv_apple_cc_single_mod=yes
else
cat conftest.err >&AS_MESSAGE_LOG_FD
@@ -1010,7 +1032,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
[lt_cv_ld_exported_symbols_list=yes],
[lt_cv_ld_exported_symbols_list=no])
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
])
AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
@@ -1032,7 +1054,7 @@ _LT_EOF
_lt_result=$?
if test -s conftest.err && $GREP force_load conftest.err; then
cat conftest.err >&AS_MESSAGE_LOG_FD
- elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
lt_cv_ld_force_load=yes
else
cat conftest.err >&AS_MESSAGE_LOG_FD
@@ -1042,32 +1064,32 @@ _LT_EOF
])
case $host_os in
rhapsody* | darwin1.[[012]])
- _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
darwin1.*)
- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
darwin*) # darwin 5.x on
# if running on 10.5 or later, the deployment target defaults
# to the OS version, if on x86, and 10.4, the deployment
# target defaults to 10.4. Don't you love it?
case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]]*)
- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]][[,.]]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
10.*)
- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
esac
;;
esac
- if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
_lt_dar_single_mod='$single_module'
fi
- if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
- _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
else
- _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
fi
- if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
_lt_dsymutil='~$DSYMUTIL $lib || :'
else
_lt_dsymutil=
@@ -1087,29 +1109,29 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_automatic, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- if test "$lt_cv_ld_force_load" = "yes"; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ if test yes = "$lt_cv_ld_force_load"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
[FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=''
fi
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
case $cc_basename in
- ifort*) _lt_dar_can_shared=yes ;;
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
*) _lt_dar_can_shared=$GCC ;;
esac
- if test "$_lt_dar_can_shared" = "yes"; then
+ if test yes = "$_lt_dar_can_shared"; then
output_verbose_link_cmd=func_echo_all
- _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
- _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
- _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
m4_if([$1], [CXX],
-[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
- _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+[ if test yes != "$lt_cv_apple_cc_single_mod"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
fi
],[])
else
@@ -1129,7 +1151,7 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES],
# Allow to override them for all tags through lt_cv_aix_libpath.
m4_defun([_LT_SYS_MODULE_PATH_AIX],
[m4_require([_LT_DECL_SED])dnl
-if test "${lt_cv_aix_libpath+set}" = set; then
+if test set = "${lt_cv_aix_libpath+set}"; then
aix_libpath=$lt_cv_aix_libpath
else
AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
@@ -1147,7 +1169,7 @@ else
_LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
fi],[])
if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
- _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
fi
])
aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
@@ -1167,8 +1189,8 @@ m4_define([_LT_SHELL_INIT],
# -----------------------
# Find how we can fake an echo command that does not interpret backslash.
# In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script which will find a shell with a builtin
-# printf (which we can use as an echo command).
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
m4_defun([_LT_PROG_ECHO_BACKSLASH],
[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
@@ -1196,10 +1218,10 @@ fi
# Invoke $ECHO with all args, space-separated.
func_echo_all ()
{
- $ECHO "$*"
+ $ECHO "$*"
}
-case "$ECHO" in
+case $ECHO in
printf*) AC_MSG_RESULT([printf]) ;;
print*) AC_MSG_RESULT([print -r]) ;;
*) AC_MSG_RESULT([cat]) ;;
@@ -1225,16 +1247,17 @@ _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
AC_DEFUN([_LT_WITH_SYSROOT],
[AC_MSG_CHECKING([for sysroot])
AC_ARG_WITH([sysroot],
-[ --with-sysroot[=DIR] Search for dependent libraries within DIR
- (or the compiler's sysroot if not specified).],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+ [Search for dependent libraries within DIR (or the compiler's sysroot
+ if not specified).])],
[], [with_sysroot=no])
dnl lt_sysroot will always be passed unquoted. We quote it here
dnl in case the user passed a directory name.
lt_sysroot=
-case ${with_sysroot} in #(
+case $with_sysroot in #(
yes)
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
lt_sysroot=`$CC --print-sysroot 2>/dev/null`
fi
;; #(
@@ -1244,14 +1267,14 @@ case ${with_sysroot} in #(
no|'')
;; #(
*)
- AC_MSG_RESULT([${with_sysroot}])
+ AC_MSG_RESULT([$with_sysroot])
AC_MSG_ERROR([The sysroot must be an absolute path.])
;;
esac
AC_MSG_RESULT([${lt_sysroot:-no}])
_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and in which our libraries should be installed.])])
+[dependent libraries, and where our libraries should be installed.])])
# _LT_ENABLE_LOCK
# ---------------
@@ -1259,31 +1282,33 @@ m4_defun([_LT_ENABLE_LOCK],
[AC_ARG_ENABLE([libtool-lock],
[AS_HELP_STRING([--disable-libtool-lock],
[avoid locking (might break parallel builds)])])
-test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
# Some flags need to be propagated to the compiler or linker for good
# libtool support.
case $host in
ia64-*-hpux*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
*ELF-32*)
- HPUX_IA64_MODE="32"
+ HPUX_IA64_MODE=32
;;
*ELF-64*)
- HPUX_IA64_MODE="64"
+ HPUX_IA64_MODE=64
;;
esac
fi
rm -rf conftest*
;;
*-*-irix6*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
case `/usr/bin/file conftest.$ac_objext` in
*32-bit*)
LD="${LD-ld} -melf32bsmip"
@@ -1312,9 +1337,46 @@ ia64-*-hpux*)
rm -rf conftest*
;;
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
@@ -1333,10 +1395,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
;;
esac
;;
- powerpc64le-*)
+ powerpc64le-*linux*)
LD="${LD-ld} -m elf32lppclinux"
;;
- powerpc64-*)
+ powerpc64-*linux*)
LD="${LD-ld} -m elf32ppclinux"
;;
s390x-*linux*)
@@ -1355,10 +1417,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
x86_64-*linux*)
LD="${LD-ld} -m elf_x86_64"
;;
- powerpcle-*)
+ powerpcle-*linux*|powerpc64le-*linux*)
LD="${LD-ld} -m elf64lppc"
;;
- powerpc-*)
+ powerpc-*linux*|powerpc64-*linux*)
LD="${LD-ld} -m elf64ppc"
;;
s390*-*linux*|s390*-*tpf*)
@@ -1376,19 +1438,20 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS="$CFLAGS"
+ SAVE_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -belf"
AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
[AC_LANG_PUSH(C)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
AC_LANG_POP])
- if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ if test yes != "$lt_cv_cc_needs_belf"; then
# this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS="$SAVE_CFLAGS"
+ CFLAGS=$SAVE_CFLAGS
fi
;;
*-*solaris*)
- # Find out which ABI we are using.
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
echo 'int i;' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.o` in
@@ -1396,7 +1459,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
case $lt_cv_prog_gnu_ld in
yes*)
case $host in
- i?86-*-solaris*)
+ i?86-*-solaris*|x86_64-*-solaris*)
LD="${LD-ld} -m elf_x86_64"
;;
sparc*-*-solaris*)
@@ -1405,7 +1468,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
esac
# GNU ld 2.21 introduced _sol2 emulations. Use them if available.
if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD="${LD-ld}_sol2"
+ LD=${LD-ld}_sol2
fi
;;
*)
@@ -1421,7 +1484,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
;;
esac
-need_locks="$enable_libtool_lock"
+need_locks=$enable_libtool_lock
])# _LT_ENABLE_LOCK
@@ -1440,11 +1503,11 @@ AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
[echo conftest.$ac_objext > conftest.lst
lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
AC_TRY_EVAL([lt_ar_try])
- if test "$ac_status" -eq 0; then
+ if test 0 -eq "$ac_status"; then
# Ensure the archiver fails upon bogus file names.
rm -f conftest.$ac_objext libconftest.a
AC_TRY_EVAL([lt_ar_try])
- if test "$ac_status" -ne 0; then
+ if test 0 -ne "$ac_status"; then
lt_cv_ar_at_file=@
fi
fi
@@ -1452,7 +1515,7 @@ AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
])
])
-if test "x$lt_cv_ar_at_file" = xno; then
+if test no = "$lt_cv_ar_at_file"; then
archiver_list_spec=
else
archiver_list_spec=$lt_cv_ar_at_file
@@ -1483,7 +1546,7 @@ old_postuninstall_cmds=
if test -n "$RANLIB"; then
case $host_os in
- openbsd*)
+ bitrig* | openbsd*)
old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
;;
*)
@@ -1519,7 +1582,7 @@ AC_CACHE_CHECK([$1], [$2],
[$2=no
m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="$3"
+ lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment
# Insert the option either (1) after the last *FLAGS variable, or
# (2) before a word containing "conftest.", or (3) at the end.
# Note that $ac_compile itself does not contain backslashes and begins
@@ -1546,7 +1609,7 @@ AC_CACHE_CHECK([$1], [$2],
$RM conftest*
])
-if test x"[$]$2" = xyes; then
+if test yes = "[$]$2"; then
m4_if([$5], , :, [$5])
else
m4_if([$6], , :, [$6])
@@ -1568,7 +1631,7 @@ AC_DEFUN([_LT_LINKER_OPTION],
m4_require([_LT_DECL_SED])dnl
AC_CACHE_CHECK([$1], [$2],
[$2=no
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $3"
echo "$lt_simple_link_test_code" > conftest.$ac_ext
if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
@@ -1587,10 +1650,10 @@ AC_CACHE_CHECK([$1], [$2],
fi
fi
$RM -r conftest*
- LDFLAGS="$save_LDFLAGS"
+ LDFLAGS=$save_LDFLAGS
])
-if test x"[$]$2" = xyes; then
+if test yes = "[$]$2"; then
m4_if([$4], , :, [$4])
else
m4_if([$5], , :, [$5])
@@ -1611,7 +1674,7 @@ AC_DEFUN([LT_CMD_MAX_LEN],
AC_MSG_CHECKING([the maximum length of command line arguments])
AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
i=0
- teststring="ABCD"
+ teststring=ABCD
case $build_os in
msdosdjgpp*)
@@ -1645,13 +1708,18 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
lt_cv_sys_max_cmd_len=8192;
;;
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
amigaos*)
# On AmigaOS with pdksh, this test takes hours, literally.
# So we just punt and use a minimum line length of 8192.
lt_cv_sys_max_cmd_len=8192;
;;
- netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
# This has been around since 386BSD, at least. Likely further.
if test -x /sbin/sysctl; then
lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
@@ -1702,22 +1770,22 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
*)
lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
if test -n "$lt_cv_sys_max_cmd_len" && \
- test undefined != "$lt_cv_sys_max_cmd_len"; then
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
else
# Make teststring a little bigger before we do anything with it.
# a 1K string should be a reasonable start.
- for i in 1 2 3 4 5 6 7 8 ; do
+ for i in 1 2 3 4 5 6 7 8; do
teststring=$teststring$teststring
done
SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
# If test is not a shell built-in, we'll probably end up computing a
# maximum length that is only half of the actual maximum length, but
# we can't tell.
- while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
= "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test $i != 17 # 1/2 MB should be enough
+ test 17 != "$i" # 1/2 MB should be enough
do
i=`expr $i + 1`
teststring=$teststring$teststring
@@ -1733,7 +1801,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
;;
esac
])
-if test -n $lt_cv_sys_max_cmd_len ; then
+if test -n "$lt_cv_sys_max_cmd_len"; then
AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
else
AC_MSG_RESULT(none)
@@ -1761,7 +1829,7 @@ m4_defun([_LT_HEADER_DLFCN],
# ----------------------------------------------------------------
m4_defun([_LT_TRY_DLOPEN_SELF],
[m4_require([_LT_HEADER_DLFCN])dnl
-if test "$cross_compiling" = yes; then :
+if test yes = "$cross_compiling"; then :
[$4]
else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
@@ -1808,9 +1876,9 @@ else
# endif
#endif
-/* When -fvisbility=hidden is used, assume the code has been annotated
+/* When -fvisibility=hidden is used, assume the code has been annotated
correspondingly for the symbols needed. */
-#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
int fnord () __attribute__((visibility("default")));
#endif
@@ -1836,7 +1904,7 @@ int main ()
return status;
}]
_LT_EOF
- if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
(./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
lt_status=$?
case x$lt_status in
@@ -1857,7 +1925,7 @@ rm -fr conftest*
# ------------------
AC_DEFUN([LT_SYS_DLOPEN_SELF],
[m4_require([_LT_HEADER_DLFCN])dnl
-if test "x$enable_dlopen" != xyes; then
+if test yes != "$enable_dlopen"; then
enable_dlopen=unknown
enable_dlopen_self=unknown
enable_dlopen_self_static=unknown
@@ -1867,44 +1935,52 @@ else
case $host_os in
beos*)
- lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen=load_add_on
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
;;
mingw* | pw32* | cegcc*)
- lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen=LoadLibrary
lt_cv_dlopen_libs=
;;
cygwin*)
- lt_cv_dlopen="dlopen"
+ lt_cv_dlopen=dlopen
lt_cv_dlopen_libs=
;;
darwin*)
- # if libdl is installed we need to link against it
+ # if libdl is installed we need to link against it
AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
- lt_cv_dlopen="dyld"
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+ lt_cv_dlopen=dyld
lt_cv_dlopen_libs=
lt_cv_dlopen_self=yes
])
;;
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
*)
AC_CHECK_FUNC([shl_load],
- [lt_cv_dlopen="shl_load"],
+ [lt_cv_dlopen=shl_load],
[AC_CHECK_LIB([dld], [shl_load],
- [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
[AC_CHECK_FUNC([dlopen],
- [lt_cv_dlopen="dlopen"],
+ [lt_cv_dlopen=dlopen],
[AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
[AC_CHECK_LIB([svld], [dlopen],
- [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
[AC_CHECK_LIB([dld], [dld_link],
- [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
])
])
])
@@ -1913,21 +1989,21 @@ else
;;
esac
- if test "x$lt_cv_dlopen" != xno; then
- enable_dlopen=yes
- else
+ if test no = "$lt_cv_dlopen"; then
enable_dlopen=no
+ else
+ enable_dlopen=yes
fi
case $lt_cv_dlopen in
dlopen)
- save_CPPFLAGS="$CPPFLAGS"
- test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
- save_LDFLAGS="$LDFLAGS"
+ save_LDFLAGS=$LDFLAGS
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
- save_LIBS="$LIBS"
+ save_LIBS=$LIBS
LIBS="$lt_cv_dlopen_libs $LIBS"
AC_CACHE_CHECK([whether a program can dlopen itself],
@@ -1937,7 +2013,7 @@ else
lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
])
- if test "x$lt_cv_dlopen_self" = xyes; then
+ if test yes = "$lt_cv_dlopen_self"; then
wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
lt_cv_dlopen_self_static, [dnl
@@ -1947,9 +2023,9 @@ else
])
fi
- CPPFLAGS="$save_CPPFLAGS"
- LDFLAGS="$save_LDFLAGS"
- LIBS="$save_LIBS"
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
;;
esac
@@ -2041,8 +2117,8 @@ m4_defun([_LT_COMPILER_FILE_LOCKS],
m4_require([_LT_FILEUTILS_DEFAULTS])dnl
_LT_COMPILER_C_O([$1])
-hard_links="nottested"
-if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
# do not overwrite the value of need_locks provided by the user
AC_MSG_CHECKING([if we can lock with hard links])
hard_links=yes
@@ -2052,8 +2128,8 @@ if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" !=
ln conftest.a conftest.b 2>&5 || hard_links=no
ln conftest.a conftest.b 2>/dev/null && hard_links=no
AC_MSG_RESULT([$hard_links])
- if test "$hard_links" = no; then
- AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ if test no = "$hard_links"; then
+ AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
need_locks=warn
fi
else
@@ -2080,8 +2156,8 @@ objdir=$lt_cv_objdir
_LT_DECL([], [objdir], [0],
[The name of the directory that contains temporary libtool files])dnl
m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
- [Define to the sub-directory in which libtool stores uninstalled libraries.])
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+ [Define to the sub-directory where libtool stores uninstalled libraries.])
])# _LT_CHECK_OBJDIR
@@ -2093,15 +2169,15 @@ m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
_LT_TAGVAR(hardcode_action, $1)=
if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
test -n "$_LT_TAGVAR(runpath_var, $1)" ||
- test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+ test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
# We can hardcode non-existent directories.
- if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
# If the only mechanism to avoid hardcoding is shlibpath_var, we
# have to relink, otherwise we might link with an installed library
# when we should be linking with a yet-to-be-installed one
- ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
- test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+ test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
# Linking always hardcodes the temporary library directory.
_LT_TAGVAR(hardcode_action, $1)=relink
else
@@ -2115,12 +2191,12 @@ else
fi
AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
- test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+ test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
# Fast installation is not supported
enable_fast_install=no
-elif test "$shlibpath_overrides_runpath" = yes ||
- test "$enable_shared" = no; then
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
# Fast installation is not necessary
enable_fast_install=needless
fi
@@ -2144,7 +2220,7 @@ else
# FIXME - insert some real tests, host_os isn't really good enough
case $host_os in
darwin*)
- if test -n "$STRIP" ; then
+ if test -n "$STRIP"; then
striplib="$STRIP -x"
old_striplib="$STRIP -S"
AC_MSG_RESULT([yes])
@@ -2162,6 +2238,47 @@ _LT_DECL([], [striplib], [1])
])# _LT_CMD_STRIPLIB
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x@S|@2 in
+ x)
+ ;;
+ *:)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+ ;;
+ x:*)
+ eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+ ;;
+ *)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
# _LT_SYS_DYNAMIC_LINKER([TAG])
# -----------------------------
# PORTME Fill in your ld.so characteristics
@@ -2172,17 +2289,18 @@ m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_OBJDUMP])dnl
m4_require([_LT_DECL_SED])dnl
m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
AC_MSG_CHECKING([dynamic linker characteristics])
m4_if([$1],
[], [
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
case $host_os in
- darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
- *) lt_awk_arg="/^libraries:/" ;;
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
esac
case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
- *) lt_sed_strip_eq="s,=/,/,g" ;;
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
esac
lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
case $lt_search_path_spec in
@@ -2198,28 +2316,35 @@ if test "$GCC" = yes; then
;;
esac
# Ok, now we have the path, separated by spaces, we can step through it
- # and add multilib dir if necessary.
+ # and add multilib dir if necessary...
lt_tmp_lt_search_path_spec=
- lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
for lt_sys_path in $lt_search_path_spec; do
- if test -d "$lt_sys_path/$lt_multi_os_dir"; then
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
- else
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
test -d "$lt_sys_path" && \
lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
fi
done
lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS=" "; FS="/|\n";} {
- lt_foo="";
- lt_count=0;
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
for (lt_i = NF; lt_i > 0; lt_i--) {
if ($lt_i != "" && $lt_i != ".") {
if ($lt_i == "..") {
lt_count++;
} else {
if (lt_count == 0) {
- lt_foo="/" $lt_i lt_foo;
+ lt_foo = "/" $lt_i lt_foo;
} else {
lt_count--;
}
@@ -2233,7 +2358,7 @@ BEGIN {RS=" "; FS="/|\n";} {
# for these hosts.
case $host_os in
mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
- $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
esac
sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
else
@@ -2242,7 +2367,7 @@ fi])
library_names_spec=
libname_spec='lib$name'
soname_spec=
-shrext_cmds=".so"
+shrext_cmds=.so
postinstall_cmds=
postuninstall_cmds=
finish_cmds=
@@ -2259,14 +2384,17 @@ hardcode_into_libs=no
# flags to be left without arguments
need_version=unknown
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
case $host_os in
aix3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
shlibpath_var=LIBPATH
# AIX 3 has no versioning support, so we append a major version to the name.
- soname_spec='${libname}${release}${shared_ext}$major'
+ soname_spec='$libname$release$shared_ext$major'
;;
aix[[4-9]]*)
@@ -2274,41 +2402,91 @@ aix[[4-9]]*)
need_lib_prefix=no
need_version=no
hardcode_into_libs=yes
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 supports IA64
- library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
else
# With GCC up to 2.95.x, collect2 would create an import file
# for dependence libraries. The import file would start with
- # the line `#! .'. This would cause the generated library to
- # depend on `.', always an invalid library. This was fixed in
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
# development snapshots of GCC prior to 3.0.
case $host_os in
aix4 | aix4.[[01]] | aix4.[[01]].*)
if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
echo ' yes '
- echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
:
else
can_build_shared=no
fi
;;
esac
- # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
# soname into executable. Probably we can add versioning support to
# collect2, so additional links can be useful in future.
- if test "$aix_use_runtimelinking" = yes; then
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
# If using run time linking (on AIX 4.2 or later) use lib<name>.so
# instead of lib<name>.a to let people know that these are not
# typical AIX shared libraries.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a[(]lib.so.V[)]'
# We preserve .a as extension for shared libraries through AIX4.2
# and later when we are not doing run time linking.
- library_names_spec='${libname}${release}.a $libname.a'
- soname_spec='${libname}${release}${shared_ext}$major'
- fi
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
shlibpath_var=LIBPATH
fi
;;
@@ -2318,18 +2496,18 @@ amigaos*)
powerpc)
# Since July 2007 AmigaOS4 officially supports .so libraries.
# When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
;;
m68k)
library_names_spec='$libname.ixlibrary $libname.a'
# Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
;;
esac
;;
beos*)
- library_names_spec='${libname}${shared_ext}'
+ library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"
shlibpath_var=LIBRARY_PATH
;;
@@ -2337,8 +2515,8 @@ beos*)
bsdi[[45]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
@@ -2350,7 +2528,7 @@ bsdi[[45]]*)
cygwin* | mingw* | pw32* | cegcc*)
version_type=windows
- shrext_cmds=".dll"
+ shrext_cmds=.dll
need_version=no
need_lib_prefix=no
@@ -2359,8 +2537,8 @@ cygwin* | mingw* | pw32* | cegcc*)
# gcc
library_names_spec='$libname.dll.a'
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname~
@@ -2376,17 +2554,17 @@ cygwin* | mingw* | pw32* | cegcc*)
case $host_os in
cygwin*)
# Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
;;
mingw* | cegcc*)
# MinGW DLLs use traditional 'lib' prefix
- soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
;;
pw32*)
# pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
;;
esac
dynamic_linker='Win32 ld.exe'
@@ -2395,8 +2573,8 @@ m4_if([$1], [],[
*,cl*)
# Native MSVC
libname_spec='$name'
- soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
- library_names_spec='${libname}.dll.lib'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
case $build_os in
mingw*)
@@ -2423,7 +2601,7 @@ m4_if([$1], [],[
sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
;;
*)
- sys_lib_search_path_spec="$LIB"
+ sys_lib_search_path_spec=$LIB
if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
# It is most probably a Windows format PATH.
sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
@@ -2436,8 +2614,8 @@ m4_if([$1], [],[
esac
# DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \${file}`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
dldir=$destdir/`dirname \$dlpath`~
test -d \$dldir || mkdir -p \$dldir~
$install_prog $dir/$dlname \$dldir/$dlname'
@@ -2450,7 +2628,7 @@ m4_if([$1], [],[
*)
# Assume MSVC wrapper
- library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
dynamic_linker='Win32 ld.exe'
;;
esac
@@ -2463,11 +2641,11 @@ darwin* | rhapsody*)
version_type=darwin
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
- soname_spec='${libname}${release}${major}$shared_ext'
+ library_names_spec='$libname$release$versuffix$shared_ext $libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
shlibpath_overrides_runpath=yes
shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+ shrext_cmds='`test .$module = .yes && echo .bundle || echo .dylib`'
m4_if([$1], [],[
sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
@@ -2477,8 +2655,8 @@ dgux*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -2493,17 +2671,31 @@ freebsd* | dragonfly*)
*) objformat=elf ;;
esac
fi
- version_type=freebsd-$objformat
+ # Handle Gentoo/FreeBSD as it was Linux
+ case $host_vendor in
+ gentoo)
+ version_type=linux ;;
+ *)
+ version_type=freebsd-$objformat ;;
+ esac
+
case $version_type in
freebsd-elf*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
need_version=no
need_lib_prefix=no
;;
freebsd-*)
- library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
need_version=yes
;;
+ linux)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ need_lib_prefix=no
+ need_version=no
+ ;;
esac
shlibpath_var=LD_LIBRARY_PATH
case $host_os in
@@ -2531,10 +2723,10 @@ haiku*)
need_lib_prefix=no
need_version=no
dynamic_linker="$host_os runtime_loader"
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=yes
+ shlibpath_overrides_runpath=no
sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
hardcode_into_libs=yes
;;
@@ -2552,14 +2744,15 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.so"
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- if test "X$HPUX_IA64_MODE" = X32; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
else
sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
fi
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
hppa*64*)
shrext_cmds='.sl'
@@ -2567,8 +2760,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
@@ -2577,8 +2770,8 @@ hpux9* | hpux10* | hpux11*)
dynamic_linker="$host_os dld.sl"
shlibpath_var=SHLIB_PATH
shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
;;
esac
# HP-UX runs *really* slowly unless shared libraries are mode 555, ...
@@ -2591,8 +2784,8 @@ interix[[3-9]]*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -2603,7 +2796,7 @@ irix5* | irix6* | nonstopux*)
case $host_os in
nonstopux*) version_type=nonstopux ;;
*)
- if test "$lt_cv_prog_gnu_ld" = yes; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
version_type=linux # correct to gnu/linux during the next big refactor
else
version_type=irix
@@ -2611,8 +2804,8 @@ irix5* | irix6* | nonstopux*)
esac
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
case $host_os in
irix5* | nonstopux*)
libsuff= shlibsuff=
@@ -2631,8 +2824,8 @@ irix5* | irix6* | nonstopux*)
esac
shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
- sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
hardcode_into_libs=yes
;;
@@ -2641,13 +2834,33 @@ linux*oldld* | linux*aout* | linux*coff*)
dynamic_linker=no
;;
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ ;;
+
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
@@ -2672,7 +2885,12 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
# before this can be enabled.
hardcode_into_libs=yes
- # Append ld.so.conf contents to the search path
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
@@ -2687,29 +2905,17 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
dynamic_linker='GNU/Linux ld.so'
;;
-netbsdelf*-gnu)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='NetBSD ld.elf_so'
- ;;
-
netbsd*)
version_type=sunos
need_lib_prefix=no
need_version=no
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
dynamic_linker='NetBSD (a.out) ld.so'
else
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
dynamic_linker='NetBSD ld.elf_so'
fi
shlibpath_var=LD_LIBRARY_PATH
@@ -2719,7 +2925,7 @@ netbsd*)
newsos6)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
;;
@@ -2728,58 +2934,68 @@ newsos6)
version_type=qnx
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='ldqnx.so'
;;
-openbsd*)
+openbsd* | bitrig*)
version_type=sunos
- sys_lib_dlsearch_path_spec="/usr/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib
need_lib_prefix=no
- # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
- case $host_os in
- openbsd3.3 | openbsd3.3.*) need_version=yes ;;
- *) need_version=no ;;
- esac
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- case $host_os in
- openbsd2.[[89]] | openbsd2.[[89]].*)
- shlibpath_overrides_runpath=no
- ;;
- *)
- shlibpath_overrides_runpath=yes
- ;;
- esac
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
else
- shlibpath_overrides_runpath=yes
+ need_version=yes
fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
;;
os2*)
libname_spec='$name'
- shrext_cmds=".dll"
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
need_lib_prefix=no
- library_names_spec='$libname${shared_ext} $libname.a'
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
dynamic_linker='OS/2 ld.exe'
- shlibpath_var=LIBPATH
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
;;
osf3* | osf4* | osf5*)
version_type=osf
need_lib_prefix=no
need_version=no
- soname_spec='${libname}${release}${shared_ext}$major'
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
;;
rdos*)
@@ -2790,8 +3006,8 @@ solaris*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
@@ -2801,11 +3017,11 @@ solaris*)
sunos4*)
version_type=sunos
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
need_lib_prefix=no
fi
need_version=yes
@@ -2813,8 +3029,8 @@ sunos4*)
sysv4 | sysv4.3*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
case $host_vendor in
sni)
@@ -2835,24 +3051,24 @@ sysv4 | sysv4.3*)
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
- soname_spec='$libname${shared_ext}.$major'
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
shlibpath_var=LD_LIBRARY_PATH
fi
;;
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- version_type=freebsd-elf
+ version_type=sco
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=yes
hardcode_into_libs=yes
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
else
sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
@@ -2870,7 +3086,7 @@ tpf*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
@@ -2878,8 +3094,8 @@ tpf*)
uts4*)
version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
shlibpath_var=LD_LIBRARY_PATH
;;
@@ -2888,20 +3104,30 @@ uts4*)
;;
esac
AC_MSG_RESULT([$dynamic_linker])
-test "$dynamic_linker" = no && can_build_shared=no
+test no = "$dynamic_linker" && can_build_shared=no
variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
fi
-if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
- sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
fi
-if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
- sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
fi
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
_LT_DECL([], [variables_saved_for_relink], [1],
[Variables whose values should be saved in libtool wrapper scripts and
restored at link time])
@@ -2934,39 +3160,41 @@ _LT_DECL([], [hardcode_into_libs], [0],
[Whether we should hardcode library paths into libraries])
_LT_DECL([], [sys_lib_search_path_spec], [2],
[Compile-time system search path for libraries])
-_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
- [Run-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+ [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+ [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
])# _LT_SYS_DYNAMIC_LINKER
# _LT_PATH_TOOL_PREFIX(TOOL)
# --------------------------
-# find a file program which can recognize shared library
+# find a file program that can recognize shared library
AC_DEFUN([_LT_PATH_TOOL_PREFIX],
[m4_require([_LT_DECL_EGREP])dnl
AC_MSG_CHECKING([for $1])
AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
[case $MAGIC_CMD in
[[\\/*] | ?:[\\/]*])
- lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
;;
*)
- lt_save_MAGIC_CMD="$MAGIC_CMD"
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
dnl $ac_dummy forces splitting on constant user-supplied paths.
dnl POSIX.2 word splitting is done only on the output of word expansions,
dnl not every word. This closes a longstanding sh security hole.
ac_dummy="m4_if([$2], , $PATH, [$2])"
for ac_dir in $ac_dummy; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$1; then
- lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -f "$ac_dir/$1"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
if test -n "$file_magic_test_file"; then
case $deplibs_check_method in
"file_magic "*)
file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
$EGREP "$file_magic_regex" > /dev/null; then
:
@@ -2989,11 +3217,11 @@ _LT_EOF
break
fi
done
- IFS="$lt_save_ifs"
- MAGIC_CMD="$lt_save_MAGIC_CMD"
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
;;
esac])
-MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
if test -n "$MAGIC_CMD"; then
AC_MSG_RESULT($MAGIC_CMD)
else
@@ -3011,7 +3239,7 @@ dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
# _LT_PATH_MAGIC
# --------------
-# find a file program which can recognize a shared library
+# find a file program that can recognize a shared library
m4_defun([_LT_PATH_MAGIC],
[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
if test -z "$lt_cv_path_MAGIC_CMD"; then
@@ -3038,16 +3266,16 @@ m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
AC_ARG_WITH([gnu-ld],
[AS_HELP_STRING([--with-gnu-ld],
[assume the C compiler uses GNU ld @<:@default=no@:>@])],
- [test "$withval" = no || with_gnu_ld=yes],
+ [test no = "$withval" || with_gnu_ld=yes],
[with_gnu_ld=no])dnl
ac_prog=ld
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
# Check if gcc -print-prog-name=ld gives a path.
AC_MSG_CHECKING([for ld used by $CC])
case $host in
*-*-mingw*)
- # gcc leaves a trailing carriage return which upsets mingw
+ # gcc leaves a trailing carriage return, which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
@@ -3061,7 +3289,7 @@ if test "$GCC" = yes; then
while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
done
- test -z "$LD" && LD="$ac_prog"
+ test -z "$LD" && LD=$ac_prog
;;
"")
# If it fails, then pretend we aren't using GCC.
@@ -3072,37 +3300,37 @@ if test "$GCC" = yes; then
with_gnu_ld=unknown
;;
esac
-elif test "$with_gnu_ld" = yes; then
+elif test yes = "$with_gnu_ld"; then
AC_MSG_CHECKING([for GNU ld])
else
AC_MSG_CHECKING([for non-GNU ld])
fi
AC_CACHE_VAL(lt_cv_path_LD,
[if test -z "$LD"; then
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD="$ac_dir/$ac_prog"
+ lt_cv_path_LD=$ac_dir/$ac_prog
# Check to see if the program is GNU ld. I'd rather use --version,
# but apparently some variants of GNU ld only accept -v.
# Break only if it was the GNU/non-GNU ld that we prefer.
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
*GNU* | *'with BFD'*)
- test "$with_gnu_ld" != no && break
+ test no != "$with_gnu_ld" && break
;;
*)
- test "$with_gnu_ld" != yes && break
+ test yes != "$with_gnu_ld" && break
;;
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
else
- lt_cv_path_LD="$LD" # Let the user override the test with a path.
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
fi])
-LD="$lt_cv_path_LD"
+LD=$lt_cv_path_LD
if test -n "$LD"; then
AC_MSG_RESULT($LD)
else
@@ -3156,13 +3384,13 @@ esac
reload_cmds='$LD$reload_flag -o $output$reload_objs'
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- if test "$GCC" != yes; then
+ if test yes != "$GCC"; then
reload_cmds=false
fi
;;
darwin*)
- if test "$GCC" = yes; then
- reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
else
reload_cmds='$LD$reload_flag -o $output$reload_objs'
fi
@@ -3173,6 +3401,43 @@ _LT_TAGDECL([], [reload_cmds], [2])dnl
])# _LT_CMD_RELOAD
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+ [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
# _LT_CHECK_MAGIC_METHOD
# ----------------------
# how to check for library dependencies
@@ -3188,13 +3453,13 @@ lt_cv_deplibs_check_method='unknown'
# Need to set the preceding variable on all platforms that support
# interlibrary dependencies.
# 'none' -- dependencies not supported.
-# `unknown' -- same as none, but documents that we really don't know.
+# 'unknown' -- same as none, but documents that we really don't know.
# 'pass_all' -- all dependencies passed with no checks.
# 'test_compile' -- check by making test program.
# 'file_magic [[regex]]' -- check by looking for files in library path
-# which responds to the $file_magic_cmd with a given extended regex.
-# If you have `file' or equivalent on your system and you're not sure
-# whether `pass_all' will *always* work, you probably want this one.
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
case $host_os in
aix[[4-9]]*)
@@ -3221,8 +3486,7 @@ mingw* | pw32*)
# Base MSYS/MinGW do not provide the 'file' command needed by
# func_win32_libid shell function, so use a weaker test based on 'objdump',
# unless we find 'file', for example because we are cross-compiling.
- # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
- if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ if ( file / ) >/dev/null 2>&1; then
lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
lt_cv_file_magic_cmd='func_win32_libid'
else
@@ -3300,7 +3564,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
lt_cv_deplibs_check_method=pass_all
;;
-netbsd* | netbsdelf*-gnu)
+netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
else
@@ -3318,8 +3582,8 @@ newos6*)
lt_cv_deplibs_check_method=pass_all
;;
-openbsd*)
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
else
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
@@ -3372,6 +3636,9 @@ sysv4 | sysv4.3*)
tpf*)
lt_cv_deplibs_check_method=pass_all
;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
esac
])
@@ -3412,33 +3679,38 @@ AC_DEFUN([LT_PATH_NM],
AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
[if test -n "$NM"; then
# Let the user override the test.
- lt_cv_path_NM="$NM"
+ lt_cv_path_NM=$NM
else
- lt_nm_to_check="${ac_tool_prefix}nm"
+ lt_nm_to_check=${ac_tool_prefix}nm
if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
lt_nm_to_check="$lt_nm_to_check nm"
fi
for lt_tmp_nm in $lt_nm_to_check; do
- lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
test -z "$ac_dir" && ac_dir=.
- tmp_nm="$ac_dir/$lt_tmp_nm"
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
# Check to see if the nm accepts a BSD-compat flag.
- # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
# Tru64's nm complains that /dev/null is an invalid object file
- case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
- */dev/null* | *'Invalid file or object type'*)
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
lt_cv_path_NM="$tmp_nm -B"
- break
+ break 2
;;
*)
case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
*/dev/null*)
lt_cv_path_NM="$tmp_nm -p"
- break
+ break 2
;;
*)
lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
@@ -3449,21 +3721,21 @@ else
esac
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
done
: ${lt_cv_path_NM=no}
fi])
-if test "$lt_cv_path_NM" != "no"; then
- NM="$lt_cv_path_NM"
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
else
# Didn't find any BSD compatible name lister, look for dumpbin.
if test -n "$DUMPBIN"; then :
# Let the user override the test.
else
AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
- case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
*COFF*)
- DUMPBIN="$DUMPBIN -symbols"
+ DUMPBIN="$DUMPBIN -symbols -headers"
;;
*)
DUMPBIN=:
@@ -3471,8 +3743,8 @@ else
esac
fi
AC_SUBST([DUMPBIN])
- if test "$DUMPBIN" != ":"; then
- NM="$DUMPBIN"
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
fi
fi
test -z "$NM" && NM=nm
@@ -3518,8 +3790,8 @@ lt_cv_sharedlib_from_linklib_cmd,
case $host_os in
cygwin* | mingw* | pw32* | cegcc*)
- # two different shell functions defined in ltmain.sh
- # decide which to use based on capabilities of $DLLTOOL
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
case `$DLLTOOL --help 2>&1` in
*--identify-strict*)
lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
@@ -3531,7 +3803,7 @@ cygwin* | mingw* | pw32* | cegcc*)
;;
*)
# fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
;;
esac
])
@@ -3558,13 +3830,28 @@ AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool
lt_cv_path_mainfest_tool=yes
fi
rm -f conftest*])
-if test "x$lt_cv_path_mainfest_tool" != xyes; then
+if test yes != "$lt_cv_path_mainfest_tool"; then
MANIFEST_TOOL=:
fi
_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
])# _LT_PATH_MANIFEST_TOOL
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+ test DEF = "`$SED -n dnl
+ -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace
+ -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments
+ -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl
+ -e q dnl Only consider the first "real" line
+ $1`" dnl
+])# _LT_DLL_DEF_P
+
+
# LT_LIB_M
# --------
# check for math library
@@ -3576,11 +3863,11 @@ case $host in
# These system don't have libm, or don't need it
;;
*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
;;
*)
- AC_CHECK_LIB(m, cos, LIBM="-lm")
+ AC_CHECK_LIB(m, cos, LIBM=-lm)
;;
esac
AC_SUBST([LIBM])
@@ -3599,7 +3886,7 @@ m4_defun([_LT_COMPILER_NO_RTTI],
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-if test "$GCC" = yes; then
+if test yes = "$GCC"; then
case $cc_basename in
nvcc*)
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
@@ -3651,7 +3938,7 @@ cygwin* | mingw* | pw32* | cegcc*)
symcode='[[ABCDGISTW]]'
;;
hpux*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
symcode='[[ABCDEGRST]]'
fi
;;
@@ -3684,14 +3971,44 @@ case `$NM -V 2>&1` in
symcode='[[ABCDGIRSTW]]' ;;
esac
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
# Transform an extracted symbol line into a proper C declaration.
# Some systems (esp. on ia64) link data and code symbols differently,
# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
# Handle CRLF in mingw tool chain
opt_cr=
@@ -3709,21 +4026,24 @@ for ac_symprfx in "" "_"; do
# Write the raw and C identifiers.
if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Fake it for dumpbin and say T for any non-static function
- # and D for any global variable.
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
# Also find C++ and __fastcall symbols from MSVC++,
# which start with @ or ?.
lt_cv_sys_global_symbol_pipe="$AWK ['"\
" {last_section=section; section=\$ 3};"\
" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
" \$ 0!~/External *\|/{next};"\
" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
" {if(hide[section]) next};"\
-" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
-" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
-" s[1]~/^[@?]/{print s[1], s[1]; next};"\
-" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
" ' prfx=^$ac_symprfx]"
else
lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
@@ -3763,11 +4083,11 @@ _LT_EOF
if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
cat <<_LT_EOF > conftest.$ac_ext
/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-/* DATA imports from DLLs on WIN32 con't be const, because runtime
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
relocations are performed -- see ld's documentation on pseudo-relocs. */
# define LT@&t@_DLSYM_CONST
-#elif defined(__osf__)
+#elif defined __osf__
/* This system does not cope well with relocations in const data. */
# define LT@&t@_DLSYM_CONST
#else
@@ -3793,7 +4113,7 @@ lt__PROGRAM__LTX_preloaded_symbols[[]] =
{
{ "@PROGRAM@", (void *) 0 },
_LT_EOF
- $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
cat <<\_LT_EOF >> conftest.$ac_ext
{0, (void *) 0}
};
@@ -3813,9 +4133,9 @@ _LT_EOF
mv conftest.$ac_objext conftstm.$ac_objext
lt_globsym_save_LIBS=$LIBS
lt_globsym_save_CFLAGS=$CFLAGS
- LIBS="conftstm.$ac_objext"
+ LIBS=conftstm.$ac_objext
CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
- if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
pipe_works=yes
fi
LIBS=$lt_globsym_save_LIBS
@@ -3836,7 +4156,7 @@ _LT_EOF
rm -rf conftest* conftst*
# Do not use the global_symbol_pipe unless it works.
- if test "$pipe_works" = yes; then
+ if test yes = "$pipe_works"; then
break
else
lt_cv_sys_global_symbol_pipe=
@@ -3863,12 +4183,16 @@ _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
[Take the output of nm and produce a listing of raw symbols and C names])
_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
[Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+ [Transform the output of nm into a list of symbols to manually relocate])
_LT_DECL([global_symbol_to_c_name_address],
[lt_cv_sys_global_symbol_to_c_name_address], [1],
[Transform the output of nm in a C name address pair])
_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
[lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
[Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+ [The name lister interface])
_LT_DECL([], [nm_file_list_spec], [1],
[Specify filename containing input files for $NM])
]) # _LT_CMD_GLOBAL_SYMBOLS
@@ -3884,17 +4208,18 @@ _LT_TAGVAR(lt_prog_compiler_static, $1)=
m4_if([$1], [CXX], [
# C++ specific cases for pic, static, wl, etc.
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
case $host_os in
aix*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
amigaos*)
@@ -3905,8 +4230,8 @@ m4_if([$1], [CXX], [
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
esac
@@ -3922,6 +4247,11 @@ m4_if([$1], [CXX], [
# (--disable-auto-import) libraries
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
;;
darwin* | rhapsody*)
# PIC is the default on this platform
@@ -3971,7 +4301,7 @@ m4_if([$1], [CXX], [
case $host_os in
aix[[4-9]]*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
else
@@ -4012,14 +4342,14 @@ m4_if([$1], [CXX], [
case $cc_basename in
CC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
- if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ if test ia64 != "$host_cpu"; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
fi
;;
aCC*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
case $host_cpu in
hppa*64*|ia64*)
# +Z the default
@@ -4056,7 +4386,7 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
ecpc* )
- # old Intel C++ for x86_64 which still supported -KPIC.
+ # old Intel C++ for x86_64, which still supported -KPIC.
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
@@ -4112,7 +4442,7 @@ m4_if([$1], [CXX], [
;;
esac
;;
- netbsd* | netbsdelf*-gnu)
+ netbsd*)
;;
*qnx* | *nto*)
# QNX uses GNU C++, but need to define -shared option too, otherwise
@@ -4201,17 +4531,18 @@ m4_if([$1], [CXX], [
fi
],
[
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
case $host_os in
aix*)
# All AIX code is PIC.
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
;;
amigaos*)
@@ -4222,8 +4553,8 @@ m4_if([$1], [CXX], [
;;
m68k)
# FIXME: we need at least 68020 code to build shared libraries, but
- # adding the `-m68020' flag to GCC prevents building anything better,
- # like `-m68040'.
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
;;
esac
@@ -4240,6 +4571,11 @@ m4_if([$1], [CXX], [
# (--disable-auto-import) libraries
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
;;
darwin* | rhapsody*)
@@ -4310,7 +4646,7 @@ m4_if([$1], [CXX], [
case $host_os in
aix*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# AIX 5 now supports IA64 processor
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
else
@@ -4318,11 +4654,30 @@ m4_if([$1], [CXX], [
fi
;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+
mingw* | cygwin* | pw32* | os2* | cegcc*)
# This hack is so that the source file can tell whether it is being
# built for inclusion in a dll (and should export symbols for example).
m4_if([$1], [GCJ], [],
[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
;;
hpux9* | hpux10* | hpux11*)
@@ -4338,7 +4693,7 @@ m4_if([$1], [CXX], [
;;
esac
# Is there a better lt_prog_compiler_static that works with the bundled CC?
- _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
;;
irix5* | irix6* | nonstopux*)
@@ -4349,7 +4704,7 @@ m4_if([$1], [CXX], [
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
case $cc_basename in
- # old Intel for x86_64 which still supported -KPIC.
+ # old Intel for x86_64, which still supported -KPIC.
ecc*)
_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
@@ -4374,6 +4729,12 @@ m4_if([$1], [CXX], [
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group compilers (*not* the Pentium gcc compiler,
# which looks to be a dead project)
@@ -4471,7 +4832,7 @@ m4_if([$1], [CXX], [
;;
sysv4*MP*)
- if test -d /usr/nec ;then
+ if test -d /usr/nec; then
_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
fi
@@ -4500,7 +4861,7 @@ m4_if([$1], [CXX], [
fi
])
case $host_os in
- # For platforms which do not support PIC, -DPIC is meaningless:
+ # For platforms that do not support PIC, -DPIC is meaningless:
*djgpp*)
_LT_TAGVAR(lt_prog_compiler_pic, $1)=
;;
@@ -4566,17 +4927,21 @@ m4_if([$1], [CXX], [
case $host_os in
aix[[4-9]]*)
# If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to AIX nm, but means don't demangle with GNU nm
- # Also, AIX nm treats weak defined symbols like other global defined
- # symbols, whereas GNU nm marks them as "W".
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
;;
pw32*)
- _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
;;
cygwin* | mingw* | cegcc*)
case $cc_basename in
@@ -4589,9 +4954,6 @@ m4_if([$1], [CXX], [
;;
esac
;;
- linux* | k*bsd*-gnu | gnu*)
- _LT_TAGVAR(link_all_deplibs, $1)=no
- ;;
*)
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
;;
@@ -4625,9 +4987,9 @@ m4_if([$1], [CXX], [
# included in the symbol list
_LT_TAGVAR(include_expsyms, $1)=
# exclude_expsyms can be an extended regexp of symbols to exclude
- # it will be wrapped by ` (' and `)$', so one must not match beginning or
- # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
- # as well as any symbol that contains `d'.
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
_LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
# platforms (ab)use it in PIC code, but their linkers get confused if
@@ -4643,7 +5005,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
# FIXME: the MSVC++ port hasn't been tested in a loooong time
# When not using gcc, we currently assume that we are using
# Microsoft Visual C++.
- if test "$GCC" != yes; then
+ if test yes != "$GCC"; then
with_gnu_ld=no
fi
;;
@@ -4651,12 +5013,9 @@ dnl Note also adjust exclude_expsyms for C++ above.
# we just hope/assume this is gcc and not c89 (= MSVC++)
with_gnu_ld=yes
;;
- openbsd*)
+ openbsd* | bitrig*)
with_gnu_ld=no
;;
- linux* | k*bsd*-gnu | gnu*)
- _LT_TAGVAR(link_all_deplibs, $1)=no
- ;;
esac
_LT_TAGVAR(ld_shlibs, $1)=yes
@@ -4664,7 +5023,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
# On some targets, GNU ld is compatible enough with the native linker
# that we're better off using the native interface for both.
lt_use_gnu_ld_interface=no
- if test "$with_gnu_ld" = yes; then
+ if test yes = "$with_gnu_ld"; then
case $host_os in
aix*)
# The AIX port of GNU ld has always aspired to compatibility
@@ -4686,24 +5045,24 @@ dnl Note also adjust exclude_expsyms for C++ above.
esac
fi
- if test "$lt_use_gnu_ld_interface" = yes; then
+ if test yes = "$lt_use_gnu_ld_interface"; then
# If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='${wl}'
+ wlarc='$wl'
# Set some defaults for GNU ld with shared library support. These
# are reset later if shared libraries are not supported. Putting them
# here allows them to be overridden if necessary.
runpath_var=LD_RUN_PATH
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
# ancient GNU ld didn't support --whole-archive et. al.
if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
supports_anon_versioning=no
- case `$LD -v 2>&1` in
+ case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
*GNU\ gold*) supports_anon_versioning=yes ;;
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
@@ -4716,7 +5075,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
case $host_os in
aix[[3-9]]*)
# On AIX/PPC, the GNU linker is very broken
- if test "$host_cpu" != ia64; then
+ if test ia64 != "$host_cpu"; then
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
@@ -4735,7 +5094,7 @@ _LT_EOF
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)=''
;;
m68k)
@@ -4751,7 +5110,7 @@ _LT_EOF
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
- _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -4761,7 +5120,7 @@ _LT_EOF
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -4769,61 +5128,89 @@ _LT_EOF
_LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is; otherwise, prepend...
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
haiku*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
interix[[3-9]]*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
tmp_diet=no
- if test "$host_os" = linux-dietlibc; then
+ if test linux-dietlibc = "$host_os"; then
case $cc_basename in
diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
esac
fi
if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
- && test "$tmp_diet" = no
+ && test no = "$tmp_diet"
then
tmp_addflag=' $pic_flag'
tmp_sharedflag='-shared'
case $cc_basename,$host_cpu in
pgcc*) # Portland Group C compiler
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
tmp_addflag=' $pic_flag'
;;
pgf77* | pgf90* | pgf95* | pgfortran*)
# Portland Group f77 and f90 compilers
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
tmp_addflag=' $pic_flag -Mnomain' ;;
ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
tmp_addflag=' -i_dynamic' ;;
@@ -4834,42 +5221,47 @@ _LT_EOF
lf95*) # Lahey Fortran 8.1
_LT_TAGVAR(whole_archive_flag_spec, $1)=
tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
tmp_sharedflag='-qmkshrobj'
tmp_addflag= ;;
nvcc*) # Cuda Compiler Driver 2.2
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
;;
esac
case `$CC -V 2>&1 | sed 5q` in
*Sun\ C*) # Sun C 5.9
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
tmp_sharedflag='-G' ;;
*Sun\ F*) # Sun Fortran 8.3
tmp_sharedflag='-G' ;;
esac
- _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
case $cc_basename in
+ tcc*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+ ;;
xlf* | bgf* | bgxlf* | mpixlf*)
# IBM XL Fortran 10.1 on PPC cannot create shared libs itself
_LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
fi
;;
esac
@@ -4878,13 +5270,13 @@ _LT_EOF
fi
;;
- netbsd* | netbsdelf*-gnu)
+ netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc=
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
fi
;;
@@ -4902,8 +5294,8 @@ _LT_EOF
_LT_EOF
elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -4915,7 +5307,7 @@ _LT_EOF
_LT_TAGVAR(ld_shlibs, $1)=no
cat <<_LT_EOF 1>&2
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
*** reliably create shared libraries on SCO systems. Therefore, libtool
*** is disabling shared libraries support. We urge you to upgrade GNU
*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
@@ -4930,9 +5322,9 @@ _LT_EOF
# DT_RUNPATH tag from executables and libraries. But doing so
# requires that you compile everything twice, which is a pain.
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -4949,15 +5341,15 @@ _LT_EOF
*)
if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
;;
esac
- if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
runpath_var=
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
_LT_TAGVAR(export_dynamic_flag_spec, $1)=
@@ -4973,7 +5365,7 @@ _LT_EOF
# Note: this linker hardcodes the directories in LIBPATH if there
# are no directories specified by -L.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
- if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
# Neither direct hardcoding nor static linking is supported with a
# broken collect2.
_LT_TAGVAR(hardcode_direct, $1)=unsupported
@@ -4981,34 +5373,57 @@ _LT_EOF
;;
aix[[4-9]]*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
- no_entry_flag=""
+ no_entry_flag=
else
# If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to AIX nm, but means don't demangle with GNU nm
- # Also, AIX nm treats weak defined symbols like other global
- # defined symbols, whereas GNU nm marks them as "W".
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
else
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
fi
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
for ld_flag in $LDFLAGS; do
- if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
aix_use_runtimelinking=yes
break
fi
done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
;;
esac
@@ -5027,13 +5442,21 @@ _LT_EOF
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
- if test "$GCC" = yes; then
+ if test yes = "$GCC"; then
case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
- collect2name=`${CC} -print-prog-name=collect2`
+ collect2name=`$CC -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
@@ -5052,62 +5475,80 @@ _LT_EOF
;;
esac
shared_flag='-shared'
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag="$shared_flag "'${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
fi
- _LT_TAGVAR(link_all_deplibs, $1)=no
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
else
# not using gcc
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
else
- shared_flag='${wl}-bM:SRE'
+ shared_flag='$wl-bM:SRE'
fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
fi
fi
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to export.
_LT_TAGVAR(always_export_symbols, $1)=yes
- if test "$aix_use_runtimelinking" = yes; then
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
# Determine the default libpath from the value encoded in an
# empty executable.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
else
- if test "$host_cpu" = ia64; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
_LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$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"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$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.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
- if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
# We only use this code for GNU lds that support --whole-archive.
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
_LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- # This is similar to how AIX traditionally builds its shared libraries.
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
fi
fi
;;
@@ -5116,7 +5557,7 @@ _LT_EOF
case $host_cpu in
powerpc)
# see comment about AmigaOS4 .so support
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)=''
;;
m68k)
@@ -5146,16 +5587,17 @@ _LT_EOF
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
- else
- sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
@@ -5164,18 +5606,18 @@ _LT_EOF
# Don't use ranlib
_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile="$lt_outputfile.exe"
- lt_tool_outputfile="$lt_tool_outputfile.exe"
- ;;
- esac~
- if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
;;
*)
# Assume MSVC wrapper
@@ -5184,7 +5626,7 @@ _LT_EOF
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
# The linker will automatically build a .lib file if we build a DLL.
@@ -5234,33 +5676,33 @@ _LT_EOF
;;
hpux9*)
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
else
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_direct, $1)=yes
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
;;
hpux10*)
- if test "$GCC" = yes && test "$with_gnu_ld" = no; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
fi
- if test "$with_gnu_ld" = no; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
_LT_TAGVAR(hardcode_minus_L, $1)=yes
@@ -5268,25 +5710,25 @@ _LT_EOF
;;
hpux11*)
- if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ if test yes,no = "$GCC,$with_gnu_ld"; then
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
else
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
m4_if($1, [], [
@@ -5294,14 +5736,14 @@ _LT_EOF
# (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
_LT_LINKER_OPTION([if $CC understands -b],
_LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
- [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
[_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
- [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
;;
esac
fi
- if test "$with_gnu_ld" = no; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
@@ -5312,7 +5754,7 @@ _LT_EOF
*)
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# hardcode_minus_L: Not really in the search PATH,
# but as the default location of the library.
@@ -5323,16 +5765,16 @@ _LT_EOF
;;
irix5* | irix6* | nonstopux*)
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
# Try to use the -exported_symbol ld option, if it does not
# work, assume that -exports_file does not work either and
# implicitly export all symbols.
# This should be the same for all languages, so no per-tag cache variable.
AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
[lt_cv_irix_exported_symbol],
- [save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ [save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
AC_LINK_IFELSE(
[AC_LANG_SOURCE(
[AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
@@ -5345,22 +5787,32 @@ _LT_EOF
end]])])],
[lt_cv_irix_exported_symbol=yes],
[lt_cv_irix_exported_symbol=no])
- LDFLAGS="$save_LDFLAGS"])
- if test "$lt_cv_irix_exported_symbol" = yes; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ LDFLAGS=$save_LDFLAGS])
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
fi
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(inherit_rpath, $1)=yes
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
- netbsd* | netbsdelf*-gnu)
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else
@@ -5374,7 +5826,7 @@ _LT_EOF
newsos6)
_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
;;
@@ -5382,27 +5834,19 @@ _LT_EOF
*nto* | *qnx*)
;;
- openbsd*)
+ openbsd* | bitrig*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
else
- case $host_os in
- openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- ;;
- esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
fi
else
_LT_TAGVAR(ld_shlibs, $1)=no
@@ -5413,33 +5857,53 @@ _LT_EOF
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
_LT_TAGVAR(hardcode_minus_L, $1)=yes
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
;;
osf3*)
- if test "$GCC" = yes; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
else
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
;;
osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test "$GCC" = yes; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
else
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
- $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
# Both c and cxx compiler support -rpath directly
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -5450,24 +5914,24 @@ _LT_EOF
solaris*)
_LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
- if test "$GCC" = yes; then
- wlarc='${wl}'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
else
case `$CC -V 2>&1` in
*"Compilers 5.0"*)
wlarc=''
- _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
;;
*)
- wlarc='${wl}'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
;;
esac
fi
@@ -5477,11 +5941,11 @@ _LT_EOF
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine and reorder linker options,
- # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
# but is careful enough not to reorder.
# Supported since Solaris 2.6 (maybe 2.5.1?)
- if test "$GCC" = yes; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
fi
@@ -5491,10 +5955,10 @@ _LT_EOF
;;
sunos4*)
- if test "x$host_vendor" = xsequent; then
+ if test sequent = "$host_vendor"; then
# Use $CC to link under sequent, because it throws in some extra .o
# files that make .init and .fini sections work.
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
else
_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
fi
@@ -5543,43 +6007,43 @@ _LT_EOF
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var='LD_RUN_PATH'
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
sysv5* | sco3.2v5* | sco5v6*)
- # Note: We can NOT use -z defs as we might desire, because we do not
+ # Note: We CANNOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
- _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
runpath_var='LD_RUN_PATH'
- if test "$GCC" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
fi
;;
@@ -5594,17 +6058,17 @@ _LT_EOF
;;
esac
- if test x$host_vendor = xsni; then
+ if test sni = "$host_vendor"; then
case $host in
sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
;;
esac
fi
fi
])
AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
@@ -5621,7 +6085,7 @@ x|xyes)
# Assume -lc should be added
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- if test "$enable_shared" = yes && test "$GCC" = yes; then
+ if test yes,yes = "$GCC,$enable_shared"; then
case $_LT_TAGVAR(archive_cmds, $1) in
*'~'*)
# FIXME: we may have to deal with multi-command sequences.
@@ -5701,12 +6165,12 @@ _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
_LT_TAGDECL([], [hardcode_libdir_separator], [1],
[Whether we need a single "-rpath" flag with a separated argument])
_LT_TAGDECL([], [hardcode_direct], [0],
- [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
DIR into the resulting binary])
_LT_TAGDECL([], [hardcode_direct_absolute], [0],
- [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
DIR into the resulting binary and the resulting library dependency is
- "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ "absolute", i.e impossible to change by setting $shlibpath_var if the
library is relocated])
_LT_TAGDECL([], [hardcode_minus_L], [0],
[Set to "yes" if using the -LDIR flag during linking hardcodes DIR
@@ -5747,10 +6211,10 @@ dnl [Compiler flag to generate thread safe objects])
# ------------------------
# Ensure that the configuration variables for a C compiler are suitably
# defined. These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
+# the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_C_CONFIG],
[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC="$CC"
+lt_save_CC=$CC
AC_LANG_PUSH(C)
# Source file extension for C test sources.
@@ -5790,18 +6254,18 @@ if test -n "$compiler"; then
LT_SYS_DLOPEN_SELF
_LT_CMD_STRIPLIB
- # Report which library types will actually be built
+ # Report what library types will actually be built
AC_MSG_CHECKING([if libtool supports shared libraries])
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
- test "$can_build_shared" = "no" && enable_shared=no
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
@@ -5809,8 +6273,12 @@ if test -n "$compiler"; then
;;
aix[[4-9]]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -5818,13 +6286,13 @@ if test -n "$compiler"; then
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
- test "$enable_shared" = yes || enable_static=yes
+ test yes = "$enable_shared" || enable_static=yes
AC_MSG_RESULT([$enable_static])
_LT_CONFIG($1)
fi
AC_LANG_POP
-CC="$lt_save_CC"
+CC=$lt_save_CC
])# _LT_LANG_C_CONFIG
@@ -5832,14 +6300,14 @@ CC="$lt_save_CC"
# --------------------------
# Ensure that the configuration variables for a C++ compiler are suitably
# defined. These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to `libtool'.
+# the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_CXX_CONFIG],
[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
m4_require([_LT_DECL_EGREP])dnl
m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
- ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
- (test "X$CXX" != "Xg++"))) ; then
+if test -n "$CXX" && ( test no != "$CXX" &&
+ ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+ (test g++ != "$CXX"))); then
AC_PROG_CXXCPP
else
_lt_caught_CXX_error=yes
@@ -5881,7 +6349,7 @@ _LT_TAGVAR(objext, $1)=$objext
# the CXX compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_caught_CXX_error" != yes; then
+if test yes != "$_lt_caught_CXX_error"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="int some_variable = 0;"
@@ -5923,35 +6391,35 @@ if test "$_lt_caught_CXX_error" != yes; then
if test -n "$compiler"; then
# We don't want -fno-exception when compiling C++ code, so set the
# no_builtin_flag separately
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
else
_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
fi
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
# Set up default GNU C++ configuration
LT_PATH_LD
# Check if GNU C++ uses GNU ld as the underlying linker, since the
# archiving commands below assume that GNU ld is being used.
- if test "$with_gnu_ld" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ if test yes = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
# If archive_cmds runs LD, not CC, wlarc should be empty
# XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
# investigate it a little bit more. (MM)
- wlarc='${wl}'
+ wlarc='$wl'
# ancient GNU ld didn't support --whole-archive et. al.
if eval "`$CC -print-prog-name=ld` --help 2>&1" |
$GREP 'no-whole-archive' > /dev/null; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
else
_LT_TAGVAR(whole_archive_flag_spec, $1)=
fi
@@ -5987,18 +6455,30 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aix[[4-9]]*)
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# On IA64, the linker does run time linking by default, so we don't
# have to do anything special.
aix_use_runtimelinking=no
exp_sym_flag='-Bexport'
- no_entry_flag=""
+ no_entry_flag=
else
aix_use_runtimelinking=no
# Test if we are trying to use run time linking or normal
# AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # need to do runtime linking.
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
for ld_flag in $LDFLAGS; do
case $ld_flag in
@@ -6008,6 +6488,13 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
esac
done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
;;
esac
@@ -6026,13 +6513,21 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
- if test "$GXX" = yes; then
+ if test yes = "$GXX"; then
case $host_os in aix4.[[012]]|aix4.[[012]].*)
# We only want to do this on AIX 4.2 and lower, the check
# below for broken collect2 doesn't work under 4.3+
- collect2name=`${CC} -print-prog-name=collect2`
+ collect2name=`$CC -print-prog-name=collect2`
if test -f "$collect2name" &&
strings "$collect2name" | $GREP resolve_lib_name >/dev/null
then
@@ -6050,64 +6545,84 @@ if test "$_lt_caught_CXX_error" != yes; then
fi
esac
shared_flag='-shared'
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag="$shared_flag "'${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag=$shared_flag' $wl-G'
fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
else
# not using gcc
- if test "$host_cpu" = ia64; then
+ if test ia64 = "$host_cpu"; then
# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
# chokes on -Wl,-G. The following line is correct:
shared_flag='-G'
else
- if test "$aix_use_runtimelinking" = yes; then
- shared_flag='${wl}-G'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
else
- shared_flag='${wl}-bM:SRE'
+ shared_flag='$wl-bM:SRE'
fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
fi
fi
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
# It seems that -bexpall does not export symbols beginning with
# underscore (_), so it is better to generate a list of symbols to
# export.
_LT_TAGVAR(always_export_symbols, $1)=yes
- if test "$aix_use_runtimelinking" = yes; then
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
# Warning - without using the other runtime loading flags (-brtl),
# -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # The "-G" linker flag allows undefined symbols.
+ _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
# Determine the default libpath from the value encoded in an empty
# executable.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
else
- if test "$host_cpu" = ia64; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
_LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$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"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$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.
_LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
# Warning - without using the other run time loading flags,
# -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
- if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
# We only use this code for GNU lds that support --whole-archive.
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
else
# Exported symbols can be pulled into shared objects from archives
_LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
fi
_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- # This is similar to how AIX traditionally builds its shared
- # libraries.
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared
+ # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
fi
fi
;;
@@ -6117,7 +6632,7 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
# support --undefined. This deserves some investigation. FIXME
- _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -6145,57 +6660,58 @@ if test "$_lt_caught_CXX_error" != yes; then
# Tell ltmain to make .lib files, not .a files.
libext=lib
# Tell ltmain to make .dll files, not .so files.
- shrext_cmds=".dll"
+ shrext_cmds=.dll
# FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
- else
- $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
# The linker will not automatically build a static lib if we build a DLL.
# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
# Don't use ranlib
_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile="$lt_outputfile.exe"
- lt_tool_outputfile="$lt_tool_outputfile.exe"
- ;;
- esac~
- func_to_tool_file "$lt_outputfile"~
- if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
;;
*)
# g++
# _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
# as there is no search path for DLLs.
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
_LT_TAGVAR(always_export_symbols, $1)=no
_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file (1st line
- # is EXPORTS), use it as is; otherwise, prepend...
- _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
else
_LT_TAGVAR(ld_shlibs, $1)=no
fi
@@ -6206,6 +6722,34 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_DARWIN_LINKER_FEATURES($1)
;;
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
dgux*)
case $cc_basename in
ec++*)
@@ -6241,14 +6785,14 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
haiku*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
hpux9*)
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
# but as the default
@@ -6260,7 +6804,7 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=no
;;
aCC*)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
@@ -6269,11 +6813,11 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes; then
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
else
# FIXME: insert proper C++ library support
_LT_TAGVAR(ld_shlibs, $1)=no
@@ -6283,15 +6827,15 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
hpux10*|hpux11*)
- if test $with_gnu_ld = no; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
case $host_cpu in
hppa*64*|ia64*)
;;
*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
;;
esac
fi
@@ -6317,13 +6861,13 @@ if test "$_lt_caught_CXX_error" != yes; then
aCC*)
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
# Commands to make compiler produce verbose output that lists
@@ -6334,20 +6878,20 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes; then
- if test $with_gnu_ld = no; then
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
case $host_cpu in
hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
;;
esac
fi
@@ -6362,22 +6906,22 @@ if test "$_lt_caught_CXX_error" != yes; then
interix[[3-9]]*)
_LT_TAGVAR(hardcode_direct, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
# Instead, shared libraries are loaded at an image base (0x10000000 by
# default) and relocated if they conflict, which is a slow very memory
# consuming and fragmenting process. To avoid this, we pick a random,
# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
# time. Moving up from 0x10000000 also allows more sbrk(2) space.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
;;
irix5* | irix6*)
case $cc_basename in
CC*)
# SGI C++
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
# Archives containing C++ object files must be created using
# "CC -ar", where "CC" is the IRIX C++ compiler. This is
@@ -6386,17 +6930,17 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
;;
*)
- if test "$GXX" = yes; then
- if test "$with_gnu_ld" = no; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
fi
fi
_LT_TAGVAR(link_all_deplibs, $1)=yes
;;
esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
_LT_TAGVAR(inherit_rpath, $1)=yes
;;
@@ -6409,8 +6953,8 @@ if test "$_lt_caught_CXX_error" != yes; then
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
- _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
@@ -6419,10 +6963,10 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
# Archives containing C++ object files must be created using
# "CC -Bstatic", where "CC" is the KAI C++ compiler.
@@ -6436,59 +6980,59 @@ if test "$_lt_caught_CXX_error" != yes; then
# earlier do not add the objects themselves.
case `$CC -V 2>&1` in
*"Version 7."*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 8.0 or newer
tmp_idyn=
case $host_cpu in
ia64*) tmp_idyn=' -i_dynamic';;
esac
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
;;
pgCC* | pgcpp*)
# Portland Group C++ compiler
case `$CC -V` in
*pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
_LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
- compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
_LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
- $RANLIB $oldlib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
_LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
*) # Version 6 and above use weak symbols
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
;;
esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
;;
cxx*)
# Compaq C++
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
runpath_var=LD_RUN_PATH
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
@@ -6502,18 +7046,18 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
;;
xl* | mpixl* | bgxl*)
# IBM XL 8.0 on PPC, with GNU ld
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
- _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
- if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
fi
;;
*)
@@ -6521,10 +7065,10 @@ if test "$_lt_caught_CXX_error" != yes; then
*Sun\ C*)
# Sun C++ 5.9
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
_LT_TAGVAR(compiler_needs_object, $1)=yes
# Not sure whether something based on
@@ -6582,22 +7126,17 @@ if test "$_lt_caught_CXX_error" != yes; then
_LT_TAGVAR(ld_shlibs, $1)=yes
;;
- openbsd2*)
- # C++ shared libraries are fairly broken
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- openbsd*)
+ openbsd* | bitrig*)
if test -f /usr/libexec/ld.so; then
_LT_TAGVAR(hardcode_direct, $1)=yes
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
- _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
fi
output_verbose_link_cmd=func_echo_all
else
@@ -6613,9 +7152,9 @@ if test "$_lt_caught_CXX_error" != yes; then
# KCC will only create a shared library if the output file
# ends with ".so" (or ".sl" for HP-UX), so rename the library
# to its proper name (with version) after linking.
- _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Archives containing C++ object files must be created using
@@ -6633,17 +7172,17 @@ if test "$_lt_caught_CXX_error" != yes; then
cxx*)
case $host in
osf3*)
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
;;
*)
_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
- echo "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
- $RM $lib.exp'
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+ $RM $lib.exp'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
;;
esac
@@ -6658,21 +7197,21 @@ if test "$_lt_caught_CXX_error" != yes; then
# explicitly linking system object files so we need to strip them
# from the output so that they don't get included in the library
# dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
;;
*)
- if test "$GXX" = yes && test "$with_gnu_ld" = no; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
case $host in
osf3*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
;;
esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=:
# Commands to make compiler produce verbose output that lists
@@ -6718,9 +7257,9 @@ if test "$_lt_caught_CXX_error" != yes; then
# Sun C++ 4.2, 5.x and Centerline C++
_LT_TAGVAR(archive_cmds_need_lc,$1)=yes
_LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
@@ -6728,7 +7267,7 @@ if test "$_lt_caught_CXX_error" != yes; then
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
# The compiler driver will combine and reorder linker options,
- # but understands `-z linker_flag'.
+ # but understands '-z linker_flag'.
# Supported since Solaris 2.6 (maybe 2.5.1?)
_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
;;
@@ -6745,30 +7284,30 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
gcx*)
# Green Hills C++ Compiler
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
# The C++ compiler must be used to create the archive.
_LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
;;
*)
# GNU C++ compiler with Solaris linker
- if test "$GXX" = yes && test "$with_gnu_ld" = no; then
- _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
if $CC --version | $GREP -v '^2\.7' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
# linking a shared library.
output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
else
- # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # g++ 2.7 appears to require '-G' NOT '-shared' on this
# platform.
- _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
# Commands to make compiler produce verbose output that lists
# what "hidden" libraries, object files and flags are used when
@@ -6776,11 +7315,11 @@ if test "$_lt_caught_CXX_error" != yes; then
output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
case $host_os in
solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
*)
- _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
;;
esac
fi
@@ -6789,52 +7328,52 @@ if test "$_lt_caught_CXX_error" != yes; then
;;
sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
sysv5* | sco3.2v5* | sco5v6*)
- # Note: We can NOT use -z defs as we might desire, because we do not
+ # Note: We CANNOT use -z defs as we might desire, because we do not
# link with -lc, and that would cause any symbols used from libc to
# always be unresolved, which means just about no library would
# ever link correctly. If we're not using GNU ld we use -z text
# though, which does catch some bad symbols but isn't as heavy-handed
# as -z defs.
- _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
- _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
_LT_TAGVAR(archive_cmds_need_lc, $1)=no
_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
_LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
runpath_var='LD_RUN_PATH'
case $cc_basename in
CC*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
_LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
- '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
_LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
- '"$_LT_TAGVAR(reload_cmds, $1)"
+ '"$_LT_TAGVAR(reload_cmds, $1)"
;;
*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
;;
esac
;;
@@ -6865,10 +7404,10 @@ if test "$_lt_caught_CXX_error" != yes; then
esac
AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
- test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+ test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
- _LT_TAGVAR(GCC, $1)="$GXX"
- _LT_TAGVAR(LD, $1)="$LD"
+ _LT_TAGVAR(GCC, $1)=$GXX
+ _LT_TAGVAR(LD, $1)=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -6895,7 +7434,7 @@ if test "$_lt_caught_CXX_error" != yes; then
lt_cv_path_LD=$lt_save_path_LD
lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test "$_lt_caught_CXX_error" != yes
+fi # test yes != "$_lt_caught_CXX_error"
AC_LANG_POP
])# _LT_LANG_CXX_CONFIG
@@ -6917,13 +7456,14 @@ AC_REQUIRE([_LT_DECL_SED])
AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
func_stripname_cnf ()
{
- case ${2} in
- .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
- *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ case @S|@2 in
+ .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+ *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
esac
} # func_stripname_cnf
])# _LT_FUNC_STRIPNAME_CNF
+
# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
# ---------------------------------
# Figure out "hidden" library dependencies from verbose
@@ -7007,13 +7547,13 @@ if AC_TRY_EVAL(ac_compile); then
pre_test_object_deps_done=no
for p in `eval "$output_verbose_link_cmd"`; do
- case ${prev}${p} in
+ case $prev$p in
-L* | -R* | -l*)
# Some compilers place space between "-{L,R}" and the path.
# Remove the space.
- if test $p = "-L" ||
- test $p = "-R"; then
+ if test x-L = "$p" ||
+ test x-R = "$p"; then
prev=$p
continue
fi
@@ -7029,16 +7569,16 @@ if AC_TRY_EVAL(ac_compile); then
case $p in
=*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
esac
- if test "$pre_test_object_deps_done" = no; then
- case ${prev} in
+ if test no = "$pre_test_object_deps_done"; then
+ case $prev in
-L | -R)
# Internal compiler library paths should come after those
# provided the user. The postdeps already come after the
# user supplied libs so there is no need to process them.
if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
- _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
else
- _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
fi
;;
# The "-l" case would never come before the object being
@@ -7046,9 +7586,9 @@ if AC_TRY_EVAL(ac_compile); then
esac
else
if test -z "$_LT_TAGVAR(postdeps, $1)"; then
- _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ _LT_TAGVAR(postdeps, $1)=$prev$p
else
- _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
fi
fi
prev=
@@ -7063,15 +7603,15 @@ if AC_TRY_EVAL(ac_compile); then
continue
fi
- if test "$pre_test_object_deps_done" = no; then
+ if test no = "$pre_test_object_deps_done"; then
if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
- _LT_TAGVAR(predep_objects, $1)="$p"
+ _LT_TAGVAR(predep_objects, $1)=$p
else
_LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
fi
else
if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
- _LT_TAGVAR(postdep_objects, $1)="$p"
+ _LT_TAGVAR(postdep_objects, $1)=$p
else
_LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
fi
@@ -7102,51 +7642,6 @@ interix[[3-9]]*)
_LT_TAGVAR(postdep_objects,$1)=
_LT_TAGVAR(postdeps,$1)=
;;
-
-linux*)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- # Sun C++ 5.9
-
- # The more standards-conforming stlport4 library is
- # incompatible with the Cstd library. Avoid specifying
- # it if it's in CXXFLAGS. Ignore libCrun as
- # -library=stlport4 depends on it.
- case " $CXX $CXXFLAGS " in
- *" -library=stlport4 "*)
- solaris_use_stlport4=yes
- ;;
- esac
-
- if test "$solaris_use_stlport4" != yes; then
- _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
- fi
- ;;
- esac
- ;;
-
-solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # The more standards-conforming stlport4 library is
- # incompatible with the Cstd library. Avoid specifying
- # it if it's in CXXFLAGS. Ignore libCrun as
- # -library=stlport4 depends on it.
- case " $CXX $CXXFLAGS " in
- *" -library=stlport4 "*)
- solaris_use_stlport4=yes
- ;;
- esac
-
- # Adding this requires a known-good setup of shared libraries for
- # Sun compiler versions before 5.6, else PIC objects from an old
- # archive will be linked into the output, leading to subtle bugs.
- if test "$solaris_use_stlport4" != yes; then
- _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
- fi
- ;;
- esac
- ;;
esac
])
@@ -7155,7 +7650,7 @@ case " $_LT_TAGVAR(postdeps, $1) " in
esac
_LT_TAGVAR(compiler_lib_search_dirs, $1)=
if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
fi
_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
[The directories searched by this compiler when creating a shared library])
@@ -7175,10 +7670,10 @@ _LT_TAGDECL([], [compiler_lib_search_path], [1],
# --------------------------
# Ensure that the configuration variables for a Fortran 77 compiler are
# suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_F77_CONFIG],
[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test "X$F77" = "Xno"; then
+if test -z "$F77" || test no = "$F77"; then
_lt_disable_F77=yes
fi
@@ -7215,7 +7710,7 @@ _LT_TAGVAR(objext, $1)=$objext
# the F77 compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_F77" != yes; then
+if test yes != "$_lt_disable_F77"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="\
subroutine t
@@ -7237,7 +7732,7 @@ if test "$_lt_disable_F77" != yes; then
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
- lt_save_CC="$CC"
+ lt_save_CC=$CC
lt_save_GCC=$GCC
lt_save_CFLAGS=$CFLAGS
CC=${F77-"f77"}
@@ -7251,21 +7746,25 @@ if test "$_lt_disable_F77" != yes; then
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
- test "$can_build_shared" = "no" && enable_shared=no
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -7273,11 +7772,11 @@ if test "$_lt_disable_F77" != yes; then
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
- test "$enable_shared" = yes || enable_static=yes
+ test yes = "$enable_shared" || enable_static=yes
AC_MSG_RESULT([$enable_static])
- _LT_TAGVAR(GCC, $1)="$G77"
- _LT_TAGVAR(LD, $1)="$LD"
+ _LT_TAGVAR(GCC, $1)=$G77
+ _LT_TAGVAR(LD, $1)=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -7294,9 +7793,9 @@ if test "$_lt_disable_F77" != yes; then
fi # test -n "$compiler"
GCC=$lt_save_GCC
- CC="$lt_save_CC"
- CFLAGS="$lt_save_CFLAGS"
-fi # test "$_lt_disable_F77" != yes
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
AC_LANG_POP
])# _LT_LANG_F77_CONFIG
@@ -7306,11 +7805,11 @@ AC_LANG_POP
# -------------------------
# Ensure that the configuration variables for a Fortran compiler are
# suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_FC_CONFIG],
[AC_LANG_PUSH(Fortran)
-if test -z "$FC" || test "X$FC" = "Xno"; then
+if test -z "$FC" || test no = "$FC"; then
_lt_disable_FC=yes
fi
@@ -7347,7 +7846,7 @@ _LT_TAGVAR(objext, $1)=$objext
# the FC compiler isn't working. Some variables (like enable_shared)
# are currently assumed to apply to all compilers on this platform,
# and will be corrupted by setting them based on a non-working compiler.
-if test "$_lt_disable_FC" != yes; then
+if test yes != "$_lt_disable_FC"; then
# Code to be used in simple compile tests
lt_simple_compile_test_code="\
subroutine t
@@ -7369,7 +7868,7 @@ if test "$_lt_disable_FC" != yes; then
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
- lt_save_CC="$CC"
+ lt_save_CC=$CC
lt_save_GCC=$GCC
lt_save_CFLAGS=$CFLAGS
CC=${FC-"f95"}
@@ -7385,21 +7884,25 @@ if test "$_lt_disable_FC" != yes; then
AC_MSG_RESULT([$can_build_shared])
AC_MSG_CHECKING([whether to build shared libraries])
- test "$can_build_shared" = "no" && enable_shared=no
+ test no = "$can_build_shared" && enable_shared=no
# On AIX, shared libraries and static libraries use the same namespace, and
# are all built from PIC.
case $host_os in
aix3*)
- test "$enable_shared" = yes && enable_static=no
+ test yes = "$enable_shared" && enable_static=no
if test -n "$RANLIB"; then
archive_cmds="$archive_cmds~\$RANLIB \$lib"
postinstall_cmds='$RANLIB $lib'
fi
;;
aix[[4-9]]*)
- if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
- test "$enable_shared" = yes && enable_static=no
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
fi
;;
esac
@@ -7407,11 +7910,11 @@ if test "$_lt_disable_FC" != yes; then
AC_MSG_CHECKING([whether to build static libraries])
# Make sure either enable_shared or enable_static is yes.
- test "$enable_shared" = yes || enable_static=yes
+ test yes = "$enable_shared" || enable_static=yes
AC_MSG_RESULT([$enable_static])
- _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
- _LT_TAGVAR(LD, $1)="$LD"
+ _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+ _LT_TAGVAR(LD, $1)=$LD
## CAVEAT EMPTOR:
## There is no encapsulation within the following macros, do not change
@@ -7431,7 +7934,7 @@ if test "$_lt_disable_FC" != yes; then
GCC=$lt_save_GCC
CC=$lt_save_CC
CFLAGS=$lt_save_CFLAGS
-fi # test "$_lt_disable_FC" != yes
+fi # test yes != "$_lt_disable_FC"
AC_LANG_POP
])# _LT_LANG_FC_CONFIG
@@ -7441,7 +7944,7 @@ AC_LANG_POP
# --------------------------
# Ensure that the configuration variables for the GNU Java Compiler compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_GCJ_CONFIG],
[AC_REQUIRE([LT_PROG_GCJ])dnl
AC_LANG_SAVE
@@ -7475,7 +7978,7 @@ CC=${GCJ-"gcj"}
CFLAGS=$GCJFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
+_LT_TAGVAR(LD, $1)=$LD
_LT_CC_BASENAME([$compiler])
# GCJ did not exist at the time GCC didn't implicitly link libc in.
@@ -7512,7 +8015,7 @@ CFLAGS=$lt_save_CFLAGS
# --------------------------
# Ensure that the configuration variables for the GNU Go compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_GO_CONFIG],
[AC_REQUIRE([LT_PROG_GO])dnl
AC_LANG_SAVE
@@ -7546,7 +8049,7 @@ CC=${GOC-"gccgo"}
CFLAGS=$GOFLAGS
compiler=$CC
_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)="$LD"
+_LT_TAGVAR(LD, $1)=$LD
_LT_CC_BASENAME([$compiler])
# Go did not exist at the time GCC didn't implicitly link libc in.
@@ -7583,7 +8086,7 @@ CFLAGS=$lt_save_CFLAGS
# -------------------------
# Ensure that the configuration variables for the Windows resource compiler
# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to `libtool'.
+# to write the compiler configuration to 'libtool'.
m4_defun([_LT_LANG_RC_CONFIG],
[AC_REQUIRE([LT_PROG_RC])dnl
AC_LANG_SAVE
@@ -7599,7 +8102,7 @@ _LT_TAGVAR(objext, $1)=$objext
lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
# Code to be used in simple link tests
-lt_simple_link_test_code="$lt_simple_compile_test_code"
+lt_simple_link_test_code=$lt_simple_compile_test_code
# ltmain only uses $CC for tagged configurations so make sure $CC is set.
_LT_TAG_COMPILER
@@ -7609,7 +8112,7 @@ _LT_COMPILER_BOILERPLATE
_LT_LINKER_BOILERPLATE
# Allow CC to be a program name with arguments.
-lt_save_CC="$CC"
+lt_save_CC=$CC
lt_save_CFLAGS=$CFLAGS
lt_save_GCC=$GCC
GCC=
@@ -7638,7 +8141,7 @@ AC_DEFUN([LT_PROG_GCJ],
[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
[m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
[AC_CHECK_TOOL(GCJ, gcj,)
- test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
AC_SUBST(GCJFLAGS)])])[]dnl
])
@@ -7749,7 +8252,7 @@ lt_ac_count=0
# Add /usr/xpg4/bin/sed as it is typically found on Solaris
# along with /bin/sed that truncates output.
for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
- test ! -f $lt_ac_sed && continue
+ test ! -f "$lt_ac_sed" && continue
cat /dev/null > conftest.in
lt_ac_count=0
echo $ECHO_N "0123456789$ECHO_C" >conftest.in
@@ -7766,9 +8269,9 @@ for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
$lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
cmp -s conftest.out conftest.nl || break
# 10000 chars as input seems more than enough
- test $lt_ac_count -gt 10 && break
+ test 10 -lt "$lt_ac_count" && break
lt_ac_count=`expr $lt_ac_count + 1`
- if test $lt_ac_count -gt $lt_ac_max; then
+ if test "$lt_ac_count" -gt "$lt_ac_max"; then
lt_ac_max=$lt_ac_count
lt_cv_path_SED=$lt_ac_sed
fi
@@ -7792,27 +8295,7 @@ dnl AC_DEFUN([LT_AC_PROG_SED], [])
# Find out whether the shell is Bourne or XSI compatible,
# or has some other useful features.
m4_defun([_LT_CHECK_SHELL_FEATURES],
-[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
-# Try some XSI features
-xsi_shell=no
-( _lt_dummy="a/b/c"
- test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
- = c,a/b,b/c, \
- && eval 'test $(( 1 + 1 )) -eq 2 \
- && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
- && xsi_shell=yes
-AC_MSG_RESULT([$xsi_shell])
-_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
-
-AC_MSG_CHECKING([whether the shell understands "+="])
-lt_shell_append=no
-( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
- >/dev/null 2>&1 \
- && lt_shell_append=yes
-AC_MSG_RESULT([$lt_shell_append])
-_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
lt_unset=unset
else
lt_unset=false
@@ -7836,102 +8319,9 @@ _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
])# _LT_CHECK_SHELL_FEATURES
-# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
-# ------------------------------------------------------
-# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
-# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
-m4_defun([_LT_PROG_FUNCTION_REPLACE],
-[dnl {
-sed -e '/^$1 ()$/,/^} # $1 /c\
-$1 ()\
-{\
-m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
-} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
-test 0 -eq $? || _lt_function_replace_fail=:
-])
-
-
-# _LT_PROG_REPLACE_SHELLFNS
-# -------------------------
-# Replace existing portable implementations of several shell functions with
-# equivalent extended shell implementations where those features are available..
-m4_defun([_LT_PROG_REPLACE_SHELLFNS],
-[if test x"$xsi_shell" = xyes; then
- _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
- case ${1} in
- */*) func_dirname_result="${1%/*}${2}" ;;
- * ) func_dirname_result="${3}" ;;
- esac])
-
- _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
- func_basename_result="${1##*/}"])
-
- _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
- case ${1} in
- */*) func_dirname_result="${1%/*}${2}" ;;
- * ) func_dirname_result="${3}" ;;
- esac
- func_basename_result="${1##*/}"])
-
- _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
- # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
- # positional parameters, so assign one to ordinary parameter first.
- func_stripname_result=${3}
- func_stripname_result=${func_stripname_result#"${1}"}
- func_stripname_result=${func_stripname_result%"${2}"}])
-
- _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
- func_split_long_opt_name=${1%%=*}
- func_split_long_opt_arg=${1#*=}])
-
- _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
- func_split_short_opt_arg=${1#??}
- func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
-
- _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
- case ${1} in
- *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
- *) func_lo2o_result=${1} ;;
- esac])
-
- _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
-
- _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
-
- _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
-fi
-
-if test x"$lt_shell_append" = xyes; then
- _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
-
- _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
- func_quote_for_eval "${2}"
-dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
- eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
-
- # Save a `func_append' function call where possible by direct use of '+='
- sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
- test 0 -eq $? || _lt_function_replace_fail=:
-else
- # Save a `func_append' function call even when '+=' is not available
- sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
- && mv -f "$cfgfile.tmp" "$cfgfile" \
- || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
- test 0 -eq $? || _lt_function_replace_fail=:
-fi
-
-if test x"$_lt_function_replace_fail" = x":"; then
- AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
-fi
-])
-
# _LT_PATH_CONVERSION_FUNCTIONS
# -----------------------------
-# Determine which file name conversion functions should be used by
+# Determine what file name conversion functions should be used by
# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
# for certain cross-compile configurations and native mingw.
m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
diff --git a/3rdparty/expat/m4/ltoptions.m4 b/3rdparty/expat/m4/ltoptions.m4
index 5d9acd8e23b..94b08297666 100644
--- a/3rdparty/expat/m4/ltoptions.m4
+++ b/3rdparty/expat/m4/ltoptions.m4
@@ -1,14 +1,14 @@
# Helper functions for option handling. -*- Autoconf -*-
#
-# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
-# Inc.
+# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file 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.
-# serial 7 ltoptions.m4
+# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
@@ -29,7 +29,7 @@ m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
- [m4_warning([Unknown $1 option `$2'])])[]dnl
+ [m4_warning([Unknown $1 option '$2'])])[]dnl
])
@@ -75,13 +75,15 @@ m4_if([$1],[LT_INIT],[
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
- dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
- [_LT_ENABLE_FAST_INSTALL])
+ [_LT_ENABLE_FAST_INSTALL])
+ _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+ [_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
@@ -112,7 +114,7 @@ AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `dlopen' option into LT_INIT's first parameter.])
+put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
@@ -148,7 +150,7 @@ AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `win32-dll' option into LT_INIT's first parameter.])
+put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
@@ -157,9 +159,9 @@ dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
-# implement the --enable-shared flag, and supports the `shared' and
-# `disable-shared' LT_INIT options.
-# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
@@ -172,14 +174,14 @@ AC_ARG_ENABLE([shared],
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
@@ -211,9 +213,9 @@ dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
-# implement the --enable-static flag, and support the `static' and
-# `disable-static' LT_INIT options.
-# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
@@ -226,14 +228,14 @@ AC_ARG_ENABLE([static],
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
@@ -265,9 +267,9 @@ dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
-# implement the --enable-fast-install flag, and support the `fast-install'
-# and `disable-fast-install' LT_INIT options.
-# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
@@ -280,14 +282,14 @@ AC_ARG_ENABLE([fast-install],
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
@@ -304,14 +306,14 @@ AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `fast-install' option into LT_INIT's first parameter.])
+the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the `disable-fast-install' option into LT_INIT's first parameter.])
+the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
@@ -319,11 +321,64 @@ dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+ AC_MSG_CHECKING([which variant of shared library versioning to provide])
+ AC_ARG_WITH([aix-soname],
+ [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+ [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+ [case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname],
+ [AC_CACHE_VAL([lt_cv_with_aix_soname],
+ [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+ with_aix_soname=$lt_cv_with_aix_soname])
+ AC_MSG_RESULT([$with_aix_soname])
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+ [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
# _LT_WITH_PIC([MODE])
# --------------------
-# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
-# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
@@ -334,19 +389,17 @@ m4_define([_LT_WITH_PIC],
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
- lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
- IFS="$lt_save_ifs"
+ IFS=$lt_save_ifs
;;
esac],
- [pic_mode=default])
-
-test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+ [pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
@@ -359,7 +412,7 @@ AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the `pic-only' option into LT_INIT's first parameter.])
+put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
diff --git a/3rdparty/expat/m4/ltsugar.m4 b/3rdparty/expat/m4/ltsugar.m4
index 9000a057d31..48bc9344a4d 100644
--- a/3rdparty/expat/m4/ltsugar.m4
+++ b/3rdparty/expat/m4/ltsugar.m4
@@ -1,6 +1,7 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
-# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
@@ -33,7 +34,7 @@ m4_define([_lt_join],
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
-# Autoconf-2.59 which quotes differently.
+# Autoconf-2.59, which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
@@ -44,7 +45,7 @@ m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
-# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
diff --git a/3rdparty/expat/m4/ltversion.m4 b/3rdparty/expat/m4/ltversion.m4
index 07a8602d48d..fa04b52a3bf 100644
--- a/3rdparty/expat/m4/ltversion.m4
+++ b/3rdparty/expat/m4/ltversion.m4
@@ -1,6 +1,6 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
-# Copyright (C) 2004 Free Software Foundation, Inc.
+# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
@@ -9,15 +9,15 @@
# @configure_input@
-# serial 3337 ltversion.m4
+# serial 4179 ltversion.m4
# This file is part of GNU Libtool
-m4_define([LT_PACKAGE_VERSION], [2.4.2])
-m4_define([LT_PACKAGE_REVISION], [1.3337])
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.2'
-macro_revision='1.3337'
+[macro_version='2.4.6'
+macro_revision='2.4.6'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])
diff --git a/3rdparty/expat/m4/lt~obsolete.m4 b/3rdparty/expat/m4/lt~obsolete.m4
index c573da90c5c..c6b26f88f6c 100644
--- a/3rdparty/expat/m4/lt~obsolete.m4
+++ b/3rdparty/expat/m4/lt~obsolete.m4
@@ -1,6 +1,7 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
-# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+# Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
@@ -11,7 +12,7 @@
# These exist entirely to fool aclocal when bootstrapping libtool.
#
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
@@ -25,7 +26,7 @@
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
diff --git a/3rdparty/expat/run.sh.in b/3rdparty/expat/run.sh.in
new file mode 100644
index 00000000000..ff3fb36447c
--- /dev/null
+++ b/3rdparty/expat/run.sh.in
@@ -0,0 +1,12 @@
+#! /usr/bin/env bash
+# Copyright (C) 2017 Expat development team
+# Licensed under the MIT license
+
+case "@host@" in
+*-mingw*)
+ exec wine "$@"
+ ;;
+*)
+ exec "$@"
+ ;;
+esac
diff --git a/3rdparty/expat/test-driver-wrapper.sh b/3rdparty/expat/test-driver-wrapper.sh
new file mode 100755
index 00000000000..36a185266c6
--- /dev/null
+++ b/3rdparty/expat/test-driver-wrapper.sh
@@ -0,0 +1,43 @@
+#! /usr/bin/env bash
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+set -e
+top_srcdir="$(dirname "$(type -p "$0")")"
+top_builddir=..
+
+# Suck up all dash-dash test-driver arguments
+test_driver_args=()
+while [[ ${1} != '--' ]]; do
+ test_driver_args=( "${test_driver_args[@]}" "${1}" )
+ shift
+done
+shift # drop "--"
+
+exec "${top_srcdir}"/conftools/test-driver "${test_driver_args[@]}" "${top_builddir}"/run.sh "$@"
diff --git a/3rdparty/expat/tests/Makefile.am b/3rdparty/expat/tests/Makefile.am
new file mode 100644
index 00000000000..e19fc1ae8ad
--- /dev/null
+++ b/3rdparty/expat/tests/Makefile.am
@@ -0,0 +1,66 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+SUBDIRS = . benchmark
+
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+
+noinst_LIBRARIES = libruntests.a
+
+check_PROGRAMS = runtests runtestspp
+TESTS = runtests runtestspp
+
+# To support MinGW and Non-MinGW at the same time:
+LOG_DRIVER = $(srcdir)/../test-driver-wrapper.sh
+
+libruntests_a_SOURCES = \
+ chardata.c \
+ structdata.c \
+ memcheck.c \
+ minicheck.c
+
+runtests_SOURCES = \
+ runtests.c
+
+runtestspp_SOURCES = \
+ runtestspp.cpp
+
+runtests_LDADD = libruntests.a ../lib/libexpat.la
+runtestspp_LDADD = libruntests.a ../lib/libexpat.la
+
+EXTRA_DIST = \
+ chardata.h \
+ structdata.h \
+ minicheck.h \
+ memcheck.h \
+ README.txt \
+ udiffer.py \
+ xmltest.log.expected \
+ xmltest.sh
diff --git a/3rdparty/expat/tests/Makefile.in b/3rdparty/expat/tests/Makefile.in
new file mode 100644
index 00000000000..8b9b38eadcd
--- /dev/null
+++ b/3rdparty/expat/tests/Makefile.in
@@ -0,0 +1,1254 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = runtests$(EXEEXT) runtestspp$(EXEEXT)
+TESTS = runtests$(EXEEXT) runtestspp$(EXEEXT)
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/expat_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo " AR " $@;
+am__v_AR_1 =
+libruntests_a_AR = $(AR) $(ARFLAGS)
+libruntests_a_LIBADD =
+am_libruntests_a_OBJECTS = chardata.$(OBJEXT) structdata.$(OBJEXT) \
+ memcheck.$(OBJEXT) minicheck.$(OBJEXT)
+libruntests_a_OBJECTS = $(am_libruntests_a_OBJECTS)
+am_runtests_OBJECTS = runtests.$(OBJEXT)
+runtests_OBJECTS = $(am_runtests_OBJECTS)
+runtests_DEPENDENCIES = libruntests.a ../lib/libexpat.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_runtestspp_OBJECTS = runtestspp.$(OBJEXT)
+runtestspp_OBJECTS = $(am_runtestspp_OBJECTS)
+runtestspp_DEPENDENCIES = libruntests.a ../lib/libexpat.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/chardata.Po ./$(DEPDIR)/memcheck.Po \
+ ./$(DEPDIR)/minicheck.Po ./$(DEPDIR)/runtests.Po \
+ ./$(DEPDIR)/runtestspp.Po ./$(DEPDIR)/structdata.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(libruntests_a_SOURCES) $(runtests_SOURCES) \
+ $(runtestspp_SOURCES)
+DIST_SOURCES = $(libruntests_a_SOURCES) $(runtests_SOURCES) \
+ $(runtestspp_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ check recheck distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+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 = 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__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/conftools/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/conftools/depcomp \
+ $(top_srcdir)/conftools/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
+SUBDIRS = . benchmark
+noinst_LIBRARIES = libruntests.a
+
+# To support MinGW and Non-MinGW at the same time:
+LOG_DRIVER = $(srcdir)/../test-driver-wrapper.sh
+libruntests_a_SOURCES = \
+ chardata.c \
+ structdata.c \
+ memcheck.c \
+ minicheck.c
+
+runtests_SOURCES = \
+ runtests.c
+
+runtestspp_SOURCES = \
+ runtestspp.cpp
+
+runtests_LDADD = libruntests.a ../lib/libexpat.la
+runtestspp_LDADD = libruntests.a ../lib/libexpat.la
+EXTRA_DIST = \
+ chardata.h \
+ structdata.h \
+ minicheck.h \
+ memcheck.h \
+ README.txt \
+ udiffer.py \
+ xmltest.log.expected \
+ xmltest.sh
+
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_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
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+libruntests.a: $(libruntests_a_OBJECTS) $(libruntests_a_DEPENDENCIES) $(EXTRA_libruntests_a_DEPENDENCIES)
+ $(AM_V_at)-rm -f libruntests.a
+ $(AM_V_AR)$(libruntests_a_AR) libruntests.a $(libruntests_a_OBJECTS) $(libruntests_a_LIBADD)
+ $(AM_V_at)$(RANLIB) libruntests.a
+
+runtests$(EXEEXT): $(runtests_OBJECTS) $(runtests_DEPENDENCIES) $(EXTRA_runtests_DEPENDENCIES)
+ @rm -f runtests$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(runtests_OBJECTS) $(runtests_LDADD) $(LIBS)
+
+runtestspp$(EXEEXT): $(runtestspp_OBJECTS) $(runtestspp_DEPENDENCIES) $(EXTRA_runtestspp_DEPENDENCIES)
+ @rm -f runtestspp$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(runtestspp_OBJECTS) $(runtestspp_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chardata.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memcheck.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minicheck.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtests.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtestspp.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/structdata.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS: $(check_PROGRAMS)
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+runtests.log: runtests$(EXEEXT)
+ @p='runtests$(EXEEXT)'; \
+ b='runtests'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+runtestspp.log: runtestspp$(EXEEXT)
+ @p='runtestspp$(EXEEXT)'; \
+ b='runtestspp'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile $(LIBRARIES)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f ./$(DEPDIR)/chardata.Po
+ -rm -f ./$(DEPDIR)/memcheck.Po
+ -rm -f ./$(DEPDIR)/minicheck.Po
+ -rm -f ./$(DEPDIR)/runtests.Po
+ -rm -f ./$(DEPDIR)/runtestspp.Po
+ -rm -f ./$(DEPDIR)/structdata.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f ./$(DEPDIR)/chardata.Po
+ -rm -f ./$(DEPDIR)/memcheck.Po
+ -rm -f ./$(DEPDIR)/minicheck.Po
+ -rm -f ./$(DEPDIR)/runtests.Po
+ -rm -f ./$(DEPDIR)/runtestspp.Po
+ -rm -f ./$(DEPDIR)/structdata.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--depfiles check check-TESTS check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/3rdparty/expat/tests/benchmark/Makefile.am b/3rdparty/expat/tests/benchmark/Makefile.am
new file mode 100644
index 00000000000..5ea8dc10c5b
--- /dev/null
+++ b/3rdparty/expat/tests/benchmark/Makefile.am
@@ -0,0 +1,40 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../../lib
+
+noinst_PROGRAMS = benchmark
+
+benchmark_SOURCES = benchmark.c
+
+benchmark_LDADD = ../../lib/libexpat.la
+
+EXTRA_DIST = \
+ README.txt
diff --git a/3rdparty/expat/tests/benchmark/Makefile.in b/3rdparty/expat/tests/benchmark/Makefile.in
new file mode 100644
index 00000000000..665bca31e35
--- /dev/null
+++ b/3rdparty/expat/tests/benchmark/Makefile.in
@@ -0,0 +1,651 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = benchmark$(EXEEXT)
+subdir = tests/benchmark
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/expat_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_benchmark_OBJECTS = benchmark.$(OBJEXT)
+benchmark_OBJECTS = $(am_benchmark_OBJECTS)
+benchmark_DEPENDENCIES = ../../lib/libexpat.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/benchmark.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(benchmark_SOURCES)
+DIST_SOURCES = $(benchmark_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/conftools/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../../lib
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
+benchmark_SOURCES = benchmark.c
+benchmark_LDADD = ../../lib/libexpat.la
+EXTRA_DIST = \
+ README.txt
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/benchmark/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tests/benchmark/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_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
+
+benchmark$(EXEEXT): $(benchmark_OBJECTS) $(benchmark_DEPENDENCIES) $(EXTRA_benchmark_DEPENDENCIES)
+ @rm -f benchmark$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(benchmark_OBJECTS) $(benchmark_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/benchmark.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/benchmark.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/benchmark.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstPROGRAMS cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ 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 tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/3rdparty/expat/tests/benchmark/benchmark.c b/3rdparty/expat/tests/benchmark/benchmark.c
index 0f0fd18c1d5..fda8268f189 100644
--- a/3rdparty/expat/tests/benchmark/benchmark.c
+++ b/3rdparty/expat/tests/benchmark/benchmark.c
@@ -1,45 +1,76 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "expat.h"
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include <proto/expat.h>
+#ifdef XML_LARGE_SIZE
+# define XML_FMT_INT_MOD "ll"
+#else
+# define XML_FMT_INT_MOD "l"
#endif
-#ifdef XML_LARGE_SIZE
-#define XML_FMT_INT_MOD "ll"
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
#else
-#define XML_FMT_INT_MOD "l"
+# define XML_FMT_STR "s"
#endif
static void
-usage(const char *prog, int rc)
-{
- fprintf(stderr,
- "usage: %s [-n] filename bufferSize nr_of_loops\n", prog);
+usage(const char *prog, int rc) {
+ fprintf(stderr, "usage: %s [-n] filename bufferSize nr_of_loops\n", prog);
exit(rc);
}
-int main (int argc, char *argv[])
-{
- XML_Parser parser;
- char *XMLBuf, *XMLBufEnd, *XMLBufPtr;
- FILE *fd;
+int
+main(int argc, char *argv[]) {
+ XML_Parser parser;
+ char *XMLBuf, *XMLBufEnd, *XMLBufPtr;
+ FILE *fd;
struct stat fileAttr;
- int nrOfLoops, bufferSize, fileSize, i, isFinal;
- int j = 0, ns = 0;
- clock_t tstart, tend;
- double cpuTime = 0.0;
+ int nrOfLoops, bufferSize, fileSize, i, isFinal;
+ int j = 0, ns = 0;
+ clock_t tstart, tend;
+ double cpuTime = 0.0;
if (argc > 1) {
if (argv[1][0] == '-') {
if (argv[1][1] == 'n' && argv[1][2] == '\0') {
ns = 1;
j = 1;
- }
- else
+ } else
usage(argv[0], 1);
}
}
@@ -47,29 +78,28 @@ int main (int argc, char *argv[])
if (argc != j + 4)
usage(argv[0], 1);
- if (stat (argv[j + 1], &fileAttr) != 0) {
- fprintf (stderr, "could not access file '%s'\n", argv[j + 1]);
+ if (stat(argv[j + 1], &fileAttr) != 0) {
+ fprintf(stderr, "could not access file '%s'\n", argv[j + 1]);
return 2;
}
-
- fd = fopen (argv[j + 1], "r");
- if (!fd) {
- fprintf (stderr, "could not open file '%s'\n", argv[j + 1]);
+
+ fd = fopen(argv[j + 1], "r");
+ if (! fd) {
+ fprintf(stderr, "could not open file '%s'\n", argv[j + 1]);
exit(2);
}
-
- bufferSize = atoi (argv[j + 2]);
- nrOfLoops = atoi (argv[j + 3]);
+
+ bufferSize = atoi(argv[j + 2]);
+ nrOfLoops = atoi(argv[j + 3]);
if (bufferSize <= 0 || nrOfLoops <= 0) {
- fprintf (stderr,
- "buffer size and nr of loops must be greater than zero.\n");
+ fprintf(stderr, "buffer size and nr of loops must be greater than zero.\n");
exit(3);
}
- XMLBuf = malloc (fileAttr.st_size);
- fileSize = fread (XMLBuf, sizeof (char), fileAttr.st_size, fd);
- fclose (fd);
-
+ XMLBuf = malloc(fileAttr.st_size);
+ fileSize = fread(XMLBuf, sizeof(char), fileAttr.st_size, fd);
+ fclose(fd);
+
if (ns)
parser = XML_ParserCreateNS(NULL, '!');
else
@@ -87,28 +117,29 @@ int main (int argc, char *argv[])
isFinal = 1;
else
parseBufferSize = bufferSize;
- if (!XML_Parse (parser, XMLBufPtr, parseBufferSize, isFinal)) {
- fprintf (stderr, "error '%s' at line %" XML_FMT_INT_MOD \
- "u character %" XML_FMT_INT_MOD "u\n",
- XML_ErrorString (XML_GetErrorCode (parser)),
- XML_GetCurrentLineNumber (parser),
- XML_GetCurrentColumnNumber (parser));
- free (XMLBuf);
- XML_ParserFree (parser);
- exit (4);
+ if (! XML_Parse(parser, XMLBufPtr, parseBufferSize, isFinal)) {
+ fprintf(stderr,
+ "error '%" XML_FMT_STR "' at line %" XML_FMT_INT_MOD
+ "u character %" XML_FMT_INT_MOD "u\n",
+ XML_ErrorString(XML_GetErrorCode(parser)),
+ XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser));
+ free(XMLBuf);
+ XML_ParserFree(parser);
+ exit(4);
}
XMLBufPtr += bufferSize;
- } while (!isFinal);
+ } while (! isFinal);
tend = clock();
- cpuTime += ((double) (tend - tstart)) / CLOCKS_PER_SEC;
+ cpuTime += ((double)(tend - tstart)) / CLOCKS_PER_SEC;
XML_ParserReset(parser, NULL);
i++;
}
- XML_ParserFree (parser);
- free (XMLBuf);
-
- printf ("%d loops, with buffer size %d. Average time per loop: %f\n",
- nrOfLoops, bufferSize, cpuTime / (double) nrOfLoops);
+ XML_ParserFree(parser);
+ free(XMLBuf);
+
+ printf("%d loops, with buffer size %d. Average time per loop: %f\n",
+ nrOfLoops, bufferSize, cpuTime / (double)nrOfLoops);
return 0;
}
diff --git a/3rdparty/expat/tests/benchmark/benchmark.dsp b/3rdparty/expat/tests/benchmark/benchmark.dsp
deleted file mode 100644
index b58a39b9ef1..00000000000
--- a/3rdparty/expat/tests/benchmark/benchmark.dsp
+++ /dev/null
@@ -1,88 +0,0 @@
-# Microsoft Developer Studio Project File - Name="benchmark" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=benchmark - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "benchmark.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "benchmark.mak" CFG="benchmark - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "benchmark - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "benchmark - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "benchmark - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /W3 /GX /O2 /I "..\..\lib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD BASE RSC /l 0x1009 /d "NDEBUG"
-# ADD RSC /l 0x1009 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /machine:I386
-# ADD LINK32 libexpat.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\win32\bin\Release"
-
-!ELSEIF "$(CFG)" == "benchmark - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\lib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD BASE RSC /l 0x1009 /d "_DEBUG"
-# ADD RSC /l 0x1009 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 libexpat.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\..\win32\bin\Debug"
-
-!ENDIF
-
-# Begin Target
-
-# Name "benchmark - Win32 Release"
-# Name "benchmark - Win32 Debug"
-# Begin Source File
-
-SOURCE=.\benchmark.c
-# End Source File
-# End Target
-# End Project
diff --git a/3rdparty/expat/tests/benchmark/benchmark.dsw b/3rdparty/expat/tests/benchmark/benchmark.dsw
deleted file mode 100644
index db8504c0f30..00000000000
--- a/3rdparty/expat/tests/benchmark/benchmark.dsw
+++ /dev/null
@@ -1,44 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "benchmark"=.\benchmark.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
- Begin Project Dependency
- Project_Dep_Name expat
- End Project Dependency
-}}}
-
-###############################################################################
-
-Project: "expat"=..\..\lib\expat.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
diff --git a/3rdparty/expat/tests/chardata.c b/3rdparty/expat/tests/chardata.c
index 02243e048c7..75a50166ec5 100644
--- a/3rdparty/expat/tests/chardata.c
+++ b/3rdparty/expat/tests/chardata.c
@@ -1,11 +1,37 @@
-/* Copyright (c) 1998-2003 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
-
- chardata.c
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
+# include <expat_config.h>
#endif
#include "minicheck.h"
@@ -15,113 +41,58 @@
#include "chardata.h"
-
static int
-xmlstrlen(const XML_Char *s)
-{
- int len = 0;
- assert(s != NULL);
- while (s[len] != 0)
- ++len;
- return len;
+xmlstrlen(const XML_Char *s) {
+ int len = 0;
+ assert(s != NULL);
+ while (s[len] != 0)
+ ++len;
+ return len;
}
-
void
-CharData_Init(CharData *storage)
-{
- assert(storage != NULL);
- storage->count = -1;
+CharData_Init(CharData *storage) {
+ assert(storage != NULL);
+ storage->count = -1;
}
void
-CharData_AppendString(CharData *storage, const char *s)
-{
- int maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
- int len;
-
- assert(s != NULL);
- len = strlen(s);
- if (storage->count < 0)
- storage->count = 0;
- if ((len + storage->count) > maxchars) {
- len = (maxchars - storage->count);
- }
- if (len + storage->count < sizeof(storage->data)) {
- memcpy(storage->data + storage->count, s, len);
- storage->count += len;
- }
-}
-
-void
-CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len)
-{
- int maxchars;
-
- assert(storage != NULL);
- assert(s != NULL);
- maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
- if (storage->count < 0)
- storage->count = 0;
- if (len < 0)
- len = xmlstrlen(s);
- if ((len + storage->count) > maxchars) {
- len = (maxchars - storage->count);
- }
- if (len + storage->count < sizeof(storage->data)) {
- memcpy(storage->data + storage->count, s,
- len * sizeof(storage->data[0]));
- storage->count += len;
- }
-}
-
-int
-CharData_CheckString(CharData *storage, const char *expected)
-{
- char buffer[1280];
- int len;
- int count;
-
- assert(storage != NULL);
- assert(expected != NULL);
- count = (storage->count < 0) ? 0 : storage->count;
- len = strlen(expected);
- if (len != count) {
- if (sizeof(XML_Char) == 1)
- sprintf(buffer, "wrong number of data characters:"
- " got %d, expected %d:\n%s", count, len, storage->data);
- else
- sprintf(buffer,
- "wrong number of data characters: got %d, expected %d",
- count, len);
- fail(buffer);
- return 0;
- }
- if (memcmp(expected, storage->data, len) != 0) {
- fail("got bad data bytes");
- return 0;
- }
- return 1;
+CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len) {
+ int maxchars;
+
+ assert(storage != NULL);
+ assert(s != NULL);
+ maxchars = sizeof(storage->data) / sizeof(storage->data[0]);
+ if (storage->count < 0)
+ storage->count = 0;
+ if (len < 0)
+ len = xmlstrlen(s);
+ if ((len + storage->count) > maxchars) {
+ len = (maxchars - storage->count);
+ }
+ if (len + storage->count < (int)sizeof(storage->data)) {
+ memcpy(storage->data + storage->count, s, len * sizeof(storage->data[0]));
+ storage->count += len;
+ }
}
int
-CharData_CheckXMLChars(CharData *storage, const XML_Char *expected)
-{
- char buffer[1024];
- int len = xmlstrlen(expected);
- int count;
-
- assert(storage != NULL);
- count = (storage->count < 0) ? 0 : storage->count;
- if (len != count) {
- sprintf(buffer, "wrong number of data characters: got %d, expected %d",
- count, len);
- fail(buffer);
- return 0;
- }
- if (memcmp(expected, storage->data, len * sizeof(storage->data[0])) != 0) {
- fail("got bad data bytes");
- return 0;
- }
- return 1;
+CharData_CheckXMLChars(CharData *storage, const XML_Char *expected) {
+ char buffer[1024];
+ int len = xmlstrlen(expected);
+ int count;
+
+ assert(storage != NULL);
+ count = (storage->count < 0) ? 0 : storage->count;
+ if (len != count) {
+ sprintf(buffer, "wrong number of data characters: got %d, expected %d",
+ count, len);
+ fail(buffer);
+ return 0;
+ }
+ if (memcmp(expected, storage->data, len * sizeof(storage->data[0])) != 0) {
+ fail("got bad data bytes");
+ return 0;
+ }
+ return 1;
}
diff --git a/3rdparty/expat/tests/chardata.h b/3rdparty/expat/tests/chardata.h
index e8dc4ce22c4..4001b9b9d15 100644
--- a/3rdparty/expat/tests/chardata.h
+++ b/3rdparty/expat/tests/chardata.h
@@ -1,7 +1,34 @@
-/* chardata.h
-
- Interface to some helper routines used to accumulate and check text
+/* Interface to some helper routines used to accumulate and check text
and attribute content.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef __cplusplus
@@ -9,31 +36,24 @@ extern "C" {
#endif
#ifndef XML_CHARDATA_H
-#define XML_CHARDATA_H 1
-
-#ifndef XML_VERSION
-#include "expat.h" /* need XML_Char */
-#endif
+# define XML_CHARDATA_H 1
+# ifndef XML_VERSION
+# include "expat.h" /* need XML_Char */
+# endif
typedef struct {
- int count; /* # of chars, < 0 if not set */
- XML_Char data[1024];
+ int count; /* # of chars, < 0 if not set */
+ XML_Char data[2048];
} CharData;
-
void CharData_Init(CharData *storage);
-void CharData_AppendString(CharData *storage, const char *s);
-
void CharData_AppendXMLChars(CharData *storage, const XML_Char *s, int len);
-int CharData_CheckString(CharData *storage, const char *s);
-
int CharData_CheckXMLChars(CharData *storage, const XML_Char *s);
-
-#endif /* XML_CHARDATA_H */
+#endif /* XML_CHARDATA_H */
#ifdef __cplusplus
}
diff --git a/3rdparty/expat/tests/memcheck.c b/3rdparty/expat/tests/memcheck.c
new file mode 100644
index 00000000000..41355f6c8d9
--- /dev/null
+++ b/3rdparty/expat/tests/memcheck.c
@@ -0,0 +1,190 @@
+/* Debug allocators for the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "memcheck.h"
+
+/* Structures to keep track of what has been allocated. Speed isn't a
+ * big issue for the tests this is required for, so we will use a
+ * doubly-linked list to make deletion easier.
+ */
+
+typedef struct allocation_entry {
+ struct allocation_entry *next;
+ struct allocation_entry *prev;
+ void *allocation;
+ size_t num_bytes;
+} AllocationEntry;
+
+static AllocationEntry *alloc_head = NULL;
+static AllocationEntry *alloc_tail = NULL;
+
+static AllocationEntry *find_allocation(void *ptr);
+
+/* Allocate some memory and keep track of it. */
+void *
+tracking_malloc(size_t size) {
+ AllocationEntry *entry = malloc(sizeof(AllocationEntry));
+
+ if (entry == NULL) {
+ printf("Allocator failure\n");
+ return NULL;
+ }
+ entry->num_bytes = size;
+ entry->allocation = malloc(size);
+ if (entry->allocation == NULL) {
+ free(entry);
+ return NULL;
+ }
+ entry->next = NULL;
+
+ /* Add to the list of allocations */
+ if (alloc_head == NULL) {
+ entry->prev = NULL;
+ alloc_head = alloc_tail = entry;
+ } else {
+ entry->prev = alloc_tail;
+ alloc_tail->next = entry;
+ alloc_tail = entry;
+ }
+
+ return entry->allocation;
+}
+
+static AllocationEntry *
+find_allocation(void *ptr) {
+ AllocationEntry *entry;
+
+ for (entry = alloc_head; entry != NULL; entry = entry->next) {
+ if (entry->allocation == ptr) {
+ return entry;
+ }
+ }
+ return NULL;
+}
+
+/* Free some memory and remove the tracking for it */
+void
+tracking_free(void *ptr) {
+ AllocationEntry *entry;
+
+ if (ptr == NULL) {
+ /* There won't be an entry for this */
+ return;
+ }
+
+ entry = find_allocation(ptr);
+ if (entry != NULL) {
+ /* This is the relevant allocation. Unlink it */
+ if (entry->prev != NULL)
+ entry->prev->next = entry->next;
+ else
+ alloc_head = entry->next;
+ if (entry->next != NULL)
+ entry->next->prev = entry->prev;
+ else
+ alloc_tail = entry->next;
+ free(entry);
+ } else {
+ printf("Attempting to free unallocated memory at %p\n", ptr);
+ }
+ free(ptr);
+}
+
+/* Reallocate some memory and keep track of it */
+void *
+tracking_realloc(void *ptr, size_t size) {
+ AllocationEntry *entry;
+
+ if (ptr == NULL) {
+ /* By definition, this is equivalent to malloc(size) */
+ return tracking_malloc(size);
+ }
+ if (size == 0) {
+ /* By definition, this is equivalent to free(ptr) */
+ tracking_free(ptr);
+ return NULL;
+ }
+
+ /* Find the allocation entry for this memory */
+ entry = find_allocation(ptr);
+ if (entry == NULL) {
+ printf("Attempting to realloc unallocated memory at %p\n", ptr);
+ entry = malloc(sizeof(AllocationEntry));
+ if (entry == NULL) {
+ printf("Reallocator failure\n");
+ return NULL;
+ }
+ entry->allocation = realloc(ptr, size);
+ if (entry->allocation == NULL) {
+ free(entry);
+ return NULL;
+ }
+
+ /* Add to the list of allocations */
+ entry->next = NULL;
+ if (alloc_head == NULL) {
+ entry->prev = NULL;
+ alloc_head = alloc_tail = entry;
+ } else {
+ entry->prev = alloc_tail;
+ alloc_tail->next = entry;
+ alloc_tail = entry;
+ }
+ } else {
+ entry->allocation = realloc(ptr, size);
+ if (entry->allocation == NULL) {
+ /* Realloc semantics say the original is still allocated */
+ entry->allocation = ptr;
+ return NULL;
+ }
+ }
+
+ entry->num_bytes = size;
+ return entry->allocation;
+}
+
+int
+tracking_report(void) {
+ AllocationEntry *entry;
+
+ if (alloc_head == NULL)
+ return 1;
+
+ /* Otherwise we have allocations that haven't been freed */
+ for (entry = alloc_head; entry != NULL; entry = entry->next) {
+ printf("Allocated %lu bytes at %p\n", (long unsigned)entry->num_bytes,
+ entry->allocation);
+ }
+ return 0;
+}
diff --git a/3rdparty/expat/tests/memcheck.h b/3rdparty/expat/tests/memcheck.h
new file mode 100644
index 00000000000..4d20f4bb972
--- /dev/null
+++ b/3rdparty/expat/tests/memcheck.h
@@ -0,0 +1,57 @@
+/* Interface to allocation functions that will track what has or has
+ not been freed.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_MEMCHECK_H
+# define XML_MEMCHECK_H 1
+
+/* Allocation declarations */
+
+void *tracking_malloc(size_t size);
+void tracking_free(void *ptr);
+void *tracking_realloc(void *ptr, size_t size);
+
+/* End-of-test check to see if unfreed allocations remain. Returns
+ * TRUE (1) if there is nothing, otherwise prints a report of the
+ * remaining allocations and returns FALSE (0).
+ */
+int tracking_report(void);
+
+#endif /* XML_MEMCHECK_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/3rdparty/expat/tests/minicheck.c b/3rdparty/expat/tests/minicheck.c
index d2f4295ffb9..a5a1efb159f 100644
--- a/3rdparty/expat/tests/minicheck.c
+++ b/3rdparty/expat/tests/minicheck.c
@@ -1,85 +1,130 @@
/* Miniature re-implementation of the "check" library.
- *
- * This is intended to support just enough of check to run the Expat
- * tests. This interface is based entirely on the portion of the
- * check library being used.
- */
+
+ This is intended to support just enough of check to run the Expat
+ tests. This interface is based entirely on the portion of the
+ check library being used.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <assert.h>
+#include <string.h>
+#include "internal.h" /* for UNUSED_P only */
#include "minicheck.h"
Suite *
-suite_create(char *name)
-{
- Suite *suite = (Suite *) calloc(1, sizeof(Suite));
- if (suite != NULL) {
- suite->name = name;
- }
- return suite;
+suite_create(const char *name) {
+ Suite *suite = (Suite *)calloc(1, sizeof(Suite));
+ if (suite != NULL) {
+ suite->name = name;
+ }
+ return suite;
}
TCase *
-tcase_create(char *name)
-{
- TCase *tc = (TCase *) calloc(1, sizeof(TCase));
- if (tc != NULL) {
- tc->name = name;
- }
- return tc;
+tcase_create(const char *name) {
+ TCase *tc = (TCase *)calloc(1, sizeof(TCase));
+ if (tc != NULL) {
+ tc->name = name;
+ }
+ return tc;
}
void
-suite_add_tcase(Suite *suite, TCase *tc)
-{
- assert(suite != NULL);
- assert(tc != NULL);
- assert(tc->next_tcase == NULL);
-
- tc->next_tcase = suite->tests;
- suite->tests = tc;
+suite_add_tcase(Suite *suite, TCase *tc) {
+ assert(suite != NULL);
+ assert(tc != NULL);
+ assert(tc->next_tcase == NULL);
+
+ tc->next_tcase = suite->tests;
+ suite->tests = tc;
}
void
-tcase_add_checked_fixture(TCase *tc,
- tcase_setup_function setup,
- tcase_teardown_function teardown)
-{
- assert(tc != NULL);
- tc->setup = setup;
- tc->teardown = teardown;
+tcase_add_checked_fixture(TCase *tc, tcase_setup_function setup,
+ tcase_teardown_function teardown) {
+ assert(tc != NULL);
+ tc->setup = setup;
+ tc->teardown = teardown;
}
void
-tcase_add_test(TCase *tc, tcase_test_function test)
-{
- assert(tc != NULL);
- if (tc->allocated == tc->ntests) {
- int nalloc = tc->allocated + 100;
- size_t new_size = sizeof(tcase_test_function) * nalloc;
- tcase_test_function *new_tests = realloc(tc->tests, new_size);
- assert(new_tests != NULL);
- if (new_tests != tc->tests) {
- free(tc->tests);
- tc->tests = new_tests;
- }
- tc->allocated = nalloc;
- }
- tc->tests[tc->ntests] = test;
- tc->ntests++;
+tcase_add_test(TCase *tc, tcase_test_function test) {
+ assert(tc != NULL);
+ if (tc->allocated == tc->ntests) {
+ int nalloc = tc->allocated + 100;
+ size_t new_size = sizeof(tcase_test_function) * nalloc;
+ tcase_test_function *new_tests = realloc(tc->tests, new_size);
+ assert(new_tests != NULL);
+ tc->tests = new_tests;
+ tc->allocated = nalloc;
+ }
+ tc->tests[tc->ntests] = test;
+ tc->ntests++;
+}
+
+static void
+tcase_free(TCase *tc) {
+ if (! tc) {
+ return;
+ }
+
+ free(tc->tests);
+ free(tc);
+}
+
+static void
+suite_free(Suite *suite) {
+ if (! suite) {
+ return;
+ }
+
+ while (suite->tests != NULL) {
+ TCase *next = suite->tests->next_tcase;
+ tcase_free(suite->tests);
+ suite->tests = next;
+ }
+ free(suite);
}
SRunner *
-srunner_create(Suite *suite)
-{
- SRunner *runner = calloc(1, sizeof(SRunner));
- if (runner != NULL) {
- runner->suite = suite;
- }
- return runner;
+srunner_create(Suite *suite) {
+ SRunner *runner = calloc(1, sizeof(SRunner));
+ if (runner != NULL) {
+ runner->suite = suite;
+ }
+ return runner;
}
static jmp_buf env;
@@ -89,94 +134,96 @@ static int _check_current_lineno = -1;
static char const *_check_current_filename = NULL;
void
-_check_set_test_info(char const *function, char const *filename, int lineno)
-{
- _check_current_function = function;
- _check_current_lineno = lineno;
- _check_current_filename = filename;
+_check_set_test_info(char const *function, char const *filename, int lineno) {
+ _check_current_function = function;
+ _check_current_lineno = lineno;
+ _check_current_filename = filename;
}
-
static void
-add_failure(SRunner *runner, int verbosity)
-{
- runner->nfailures++;
- if (verbosity >= CK_VERBOSE) {
- printf("%s:%d: %s\n", _check_current_filename,
- _check_current_lineno, _check_current_function);
- }
+add_failure(SRunner *runner, int verbosity) {
+ runner->nfailures++;
+ if (verbosity >= CK_VERBOSE) {
+ printf("%s:%d: %s\n", _check_current_filename, _check_current_lineno,
+ _check_current_function);
+ }
}
void
-srunner_run_all(SRunner *runner, int verbosity)
-{
- Suite *suite;
- TCase *tc;
- assert(runner != NULL);
- suite = runner->suite;
- tc = suite->tests;
- while (tc != NULL) {
- int i;
- for (i = 0; i < tc->ntests; ++i) {
- runner->nchecks++;
-
- if (tc->setup != NULL) {
- /* setup */
- if (setjmp(env)) {
- add_failure(runner, verbosity);
- continue;
- }
- tc->setup();
- }
- /* test */
- if (setjmp(env)) {
- add_failure(runner, verbosity);
- continue;
- }
- (tc->tests[i])();
-
- /* teardown */
- if (tc->teardown != NULL) {
- if (setjmp(env)) {
- add_failure(runner, verbosity);
- continue;
- }
- tc->teardown();
- }
+srunner_run_all(SRunner *runner, int verbosity) {
+ Suite *suite;
+ TCase *volatile tc;
+ assert(runner != NULL);
+ suite = runner->suite;
+ tc = suite->tests;
+ while (tc != NULL) {
+ volatile int i;
+ for (i = 0; i < tc->ntests; ++i) {
+ runner->nchecks++;
+
+ if (tc->setup != NULL) {
+ /* setup */
+ if (setjmp(env)) {
+ add_failure(runner, verbosity);
+ continue;
}
- tc = tc->next_tcase;
- }
- if (verbosity) {
- int passed = runner->nchecks - runner->nfailures;
- double percentage = ((double) passed) / runner->nchecks;
- int display = (int) (percentage * 100);
- printf("%d%%: Checks: %d, Failed: %d\n",
- display, runner->nchecks, runner->nfailures);
+ tc->setup();
+ }
+ /* test */
+ if (setjmp(env)) {
+ add_failure(runner, verbosity);
+ continue;
+ }
+ (tc->tests[i])();
+
+ /* teardown */
+ if (tc->teardown != NULL) {
+ if (setjmp(env)) {
+ add_failure(runner, verbosity);
+ continue;
+ }
+ tc->teardown();
+ }
}
+ tc = tc->next_tcase;
+ }
+ if (verbosity) {
+ int passed = runner->nchecks - runner->nfailures;
+ double percentage = ((double)passed) / runner->nchecks;
+ int display = (int)(percentage * 100);
+ printf("%d%%: Checks: %d, Failed: %d\n", display, runner->nchecks,
+ runner->nfailures);
+ }
}
void
-_fail_unless(int condition, const char *file, int line, char *msg)
-{
- /* Always print the error message so it isn't lost. In this case,
- we have a failure, so there's no reason to be quiet about what
- it is.
- */
- if (msg != NULL)
- printf("%s", msg);
- longjmp(env, 1);
+_fail_unless(int condition, const char *file, int line, const char *msg) {
+ /* Always print the error message so it isn't lost. In this case,
+ we have a failure, so there's no reason to be quiet about what
+ it is.
+ */
+ UNUSED_P(condition);
+ UNUSED_P(file);
+ UNUSED_P(line);
+ if (msg != NULL) {
+ const int has_newline = (msg[strlen(msg) - 1] == '\n');
+ fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n");
+ }
+ longjmp(env, 1);
}
int
-srunner_ntests_failed(SRunner *runner)
-{
- assert(runner != NULL);
- return runner->nfailures;
+srunner_ntests_failed(SRunner *runner) {
+ assert(runner != NULL);
+ return runner->nfailures;
}
void
-srunner_free(SRunner *runner)
-{
- free(runner->suite);
- free(runner);
+srunner_free(SRunner *runner) {
+ if (! runner) {
+ return;
+ }
+
+ suite_free(runner->suite);
+ free(runner);
}
diff --git a/3rdparty/expat/tests/minicheck.h b/3rdparty/expat/tests/minicheck.h
index c917c026971..88a16584fb5 100644
--- a/3rdparty/expat/tests/minicheck.h
+++ b/3rdparty/expat/tests/minicheck.h
@@ -1,37 +1,69 @@
/* Miniature re-implementation of the "check" library.
- *
- * This is intended to support just enough of check to run the Expat
- * tests. This interface is based entirely on the portion of the
- * check library being used.
- *
- * This is *source* compatible, but not necessary *link* compatible.
- */
+
+ This is intended to support just enough of check to run the Expat
+ tests. This interface is based entirely on the portion of the
+ check library being used.
+
+ This is *source* compatible, but not necessary *link* compatible.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
#ifdef __cplusplus
extern "C" {
#endif
#define CK_NOFORK 0
-#define CK_FORK 1
+#define CK_FORK 1
-#define CK_SILENT 0
-#define CK_NORMAL 1
+#define CK_SILENT 0
+#define CK_NORMAL 1
#define CK_VERBOSE 2
/* Workaround for Microsoft's compiler and Tru64 Unix systems where the
- C compiler has a working __func__, but the C++ compiler only has a
+ C compiler has a working __func__, but the C++ compiler only has a
working __FUNCTION__. This could be fixed in configure.in, but it's
not worth it right now. */
-#if defined (_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
-#define __func__ __FUNCTION__
+#if defined(_MSC_VER) || (defined(__osf__) && defined(__cplusplus))
+# define __func__ __FUNCTION__
#endif
-#define START_TEST(testname) static void testname(void) { \
- _check_set_test_info(__func__, __FILE__, __LINE__); \
+#define START_TEST(testname) \
+ static void testname(void) { \
+ _check_set_test_info(__func__, __FILE__, __LINE__); \
{
-#define END_TEST } }
+#define END_TEST \
+ } \
+ }
-#define fail(msg) _fail_unless(0, __FILE__, __LINE__, msg)
+#define fail(msg) _fail_unless(0, __FILE__, __LINE__, msg)
typedef void (*tcase_setup_function)(void);
typedef void (*tcase_teardown_function)(void);
@@ -42,42 +74,39 @@ typedef struct Suite Suite;
typedef struct TCase TCase;
struct SRunner {
- Suite *suite;
- int nchecks;
- int nfailures;
+ Suite *suite;
+ int nchecks;
+ int nfailures;
};
struct Suite {
- char *name;
- TCase *tests;
+ const char *name;
+ TCase *tests;
};
struct TCase {
- char *name;
- tcase_setup_function setup;
- tcase_teardown_function teardown;
- tcase_test_function *tests;
- int ntests;
- int allocated;
- TCase *next_tcase;
+ const char *name;
+ tcase_setup_function setup;
+ tcase_teardown_function teardown;
+ tcase_test_function *tests;
+ int ntests;
+ int allocated;
+ TCase *next_tcase;
};
-
/* Internal helper. */
-void _check_set_test_info(char const *function,
- char const *filename, int lineno);
-
+void _check_set_test_info(char const *function, char const *filename,
+ int lineno);
/*
* Prototypes for the actual implementation.
*/
-void _fail_unless(int condition, const char *file, int line, char *msg);
-Suite *suite_create(char *name);
-TCase *tcase_create(char *name);
+void _fail_unless(int condition, const char *file, int line, const char *msg);
+Suite *suite_create(const char *name);
+TCase *tcase_create(const char *name);
void suite_add_tcase(Suite *suite, TCase *tc);
-void tcase_add_checked_fixture(TCase *,
- tcase_setup_function,
+void tcase_add_checked_fixture(TCase *, tcase_setup_function,
tcase_teardown_function);
void tcase_add_test(TCase *tc, tcase_test_function test);
SRunner *srunner_create(Suite *suite);
diff --git a/3rdparty/expat/tests/runtests.c b/3rdparty/expat/tests/runtests.c
index 614d6b24873..2490d86b9ab 100644
--- a/3rdparty/expat/tests/runtests.c
+++ b/3rdparty/expat/tests/runtests.c
@@ -1,49 +1,136 @@
-/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
-
- runtest.c : run the Expat test suite
+/* Run the Expat test suite
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#if defined(NDEBUG)
+# undef NDEBUG /* because test suite relies on assert(...) at the moment */
+#endif
+
#ifdef HAVE_EXPAT_CONFIG_H
-#include <expat_config.h>
+# include <expat_config.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <stdint.h>
+#include <stddef.h> /* ptrdiff_t */
+#include <ctype.h>
+#include <limits.h>
+
+#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER < 1600)
+/* For vs2003/7.1 up to vs2008/9.0; _MSC_VER 1600 is vs2010/10.0 */
+# if defined(_WIN64)
+typedef __int64 intptr_t;
+# else
+typedef __int32 intptr_t;
+# endif
+typedef unsigned __int64 uint64_t;
+#else
+# include <stdint.h> /* intptr_t uint64_t */
+#endif
+
+#if ! defined(__cplusplus)
+# if defined(_MSC_VER) && (_MSC_VER <= 1700)
+/* for vs2012/11.0/1700 and earlier Visual Studio compilers */
+# define bool int
+# define false 0
+# define true 1
+# else
+# include <stdbool.h>
+# endif
+#endif
#include "expat.h"
#include "chardata.h"
+#include "structdata.h"
+#include "internal.h" /* for UNUSED_P only */
#include "minicheck.h"
-
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include <proto/expat.h>
-#endif
+#include "memcheck.h"
+#include "siphash.h"
+#include "ascii.h" /* for ASCII_xxx */
#ifdef XML_LARGE_SIZE
-#define XML_FMT_INT_MOD "ll"
+# define XML_FMT_INT_MOD "ll"
#else
-#define XML_FMT_INT_MOD "l"
+# define XML_FMT_INT_MOD "l"
#endif
-static XML_Parser parser;
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_CHAR "lc"
+# define XML_FMT_STR "ls"
+# include <wchar.h>
+# define xcstrlen(s) wcslen(s)
+# define xcstrcmp(s, t) wcscmp((s), (t))
+# define xcstrncmp(s, t, n) wcsncmp((s), (t), (n))
+# define XCS(s) _XCS(s)
+# define _XCS(s) L##s
+#else
+# ifdef XML_UNICODE
+# error "No support for UTF-16 character without wchar_t in tests"
+# else
+# define XML_FMT_CHAR "c"
+# define XML_FMT_STR "s"
+# define xcstrlen(s) strlen(s)
+# define xcstrcmp(s, t) strcmp((s), (t))
+# define xcstrncmp(s, t, n) strncmp((s), (t), (n))
+# define XCS(s) s
+# endif /* XML_UNICODE */
+#endif /* XML_UNICODE_WCHAR_T */
+
+static XML_Parser g_parser = NULL;
+static void
+tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) {
+#ifdef XML_DTD
+ tcase_add_test(tc, test);
+#else
+ UNUSED_P(tc);
+ UNUSED_P(test);
+#endif
+}
static void
-basic_setup(void)
-{
- parser = XML_ParserCreate(NULL);
- if (parser == NULL)
- fail("Parser not created.");
+basic_setup(void) {
+ g_parser = XML_ParserCreate(NULL);
+ if (g_parser == NULL)
+ fail("Parser not created.");
}
static void
-basic_teardown(void)
-{
- if (parser != NULL)
- XML_ParserFree(parser);
+basic_teardown(void) {
+ if (g_parser != NULL) {
+ XML_ParserFree(g_parser);
+ g_parser = NULL;
+ }
}
/* Generate a failure using the parser state to create an error message;
@@ -51,259 +138,597 @@ basic_teardown(void)
expecting.
*/
static void
-_xml_failure(XML_Parser parser, const char *file, int line)
-{
- char buffer[1024];
- enum XML_Error err = XML_GetErrorCode(parser);
- sprintf(buffer,
- " %d: %s (line %" XML_FMT_INT_MOD "u, offset %"\
- XML_FMT_INT_MOD "u)\n reported from %s, line %d\n",
- err,
- XML_ErrorString(err),
- XML_GetCurrentLineNumber(parser),
- XML_GetCurrentColumnNumber(parser),
- file, line);
- _fail_unless(0, file, line, buffer);
+_xml_failure(XML_Parser parser, const char *file, int line) {
+ char buffer[1024];
+ enum XML_Error err = XML_GetErrorCode(parser);
+ sprintf(buffer,
+ " %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
+ "u, offset %" XML_FMT_INT_MOD "u)\n reported from %s, line %d\n",
+ err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser), file, line);
+ _fail_unless(0, file, line, buffer);
+}
+
+static enum XML_Status
+_XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
+ int isFinal) {
+ enum XML_Status res = XML_STATUS_ERROR;
+ int offset = 0;
+
+ if (len == 0) {
+ return XML_Parse(parser, s, len, isFinal);
+ }
+
+ for (; offset < len; offset++) {
+ const int innerIsFinal = (offset == len - 1) && isFinal;
+ const char c = s[offset]; /* to help out-of-bounds detection */
+ res = XML_Parse(parser, &c, sizeof(char), innerIsFinal);
+ if (res != XML_STATUS_OK) {
+ return res;
+ }
+ }
+ return res;
}
#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
static void
-_expect_failure(char *text, enum XML_Error errorCode, char *errorMessage,
- char *file, int lineno)
-{
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK)
- /* Hackish use of _fail_unless() macro, but let's us report
- the right filename and line number. */
- _fail_unless(0, file, lineno, errorMessage);
- if (XML_GetErrorCode(parser) != errorCode)
- _xml_failure(parser, file, lineno);
+_expect_failure(const char *text, enum XML_Error errorCode,
+ const char *errorMessage, const char *file, int lineno) {
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ /* Hackish use of _fail_unless() macro, but let's us report
+ the right filename and line number. */
+ _fail_unless(0, file, lineno, errorMessage);
+ if (XML_GetErrorCode(g_parser) != errorCode)
+ _xml_failure(g_parser, file, lineno);
}
-#define expect_failure(text, errorCode, errorMessage) \
- _expect_failure((text), (errorCode), (errorMessage), \
- __FILE__, __LINE__)
+#define expect_failure(text, errorCode, errorMessage) \
+ _expect_failure((text), (errorCode), (errorMessage), __FILE__, __LINE__)
/* Dummy handlers for when we need to set a handler to tickle a bug,
but it doesn't need to do anything.
*/
+static unsigned long dummy_handler_flags = 0;
+
+#define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
+#define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
+#define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
+#define DUMMY_NOTATION_DECL_HANDLER_FLAG (1UL << 3)
+#define DUMMY_ELEMENT_DECL_HANDLER_FLAG (1UL << 4)
+#define DUMMY_ATTLIST_DECL_HANDLER_FLAG (1UL << 5)
+#define DUMMY_COMMENT_HANDLER_FLAG (1UL << 6)
+#define DUMMY_PI_HANDLER_FLAG (1UL << 7)
+#define DUMMY_START_ELEMENT_HANDLER_FLAG (1UL << 8)
+#define DUMMY_START_CDATA_HANDLER_FLAG (1UL << 9)
+#define DUMMY_END_CDATA_HANDLER_FLAG (1UL << 10)
+#define DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG (1UL << 11)
+#define DUMMY_START_NS_DECL_HANDLER_FLAG (1UL << 12)
+#define DUMMY_END_NS_DECL_HANDLER_FLAG (1UL << 13)
+#define DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG (1UL << 14)
+#define DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG (1UL << 15)
+#define DUMMY_SKIP_HANDLER_FLAG (1UL << 16)
+#define DUMMY_DEFAULT_HANDLER_FLAG (1UL << 17)
+
+static void XMLCALL
+dummy_xdecl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ UNUSED_P(userData);
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ UNUSED_P(standalone);
+}
+
+static void XMLCALL
+dummy_start_doctype_handler(void *userData, const XML_Char *doctypeName,
+ const XML_Char *sysid, const XML_Char *pubid,
+ int has_internal_subset) {
+ UNUSED_P(userData);
+ UNUSED_P(doctypeName);
+ UNUSED_P(sysid);
+ UNUSED_P(pubid);
+ UNUSED_P(has_internal_subset);
+ dummy_handler_flags |= DUMMY_START_DOCTYPE_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_start_doctype_handler(void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid,
- int has_internal_subset)
-{}
+dummy_end_doctype_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_END_DOCTYPE_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_end_doctype_handler(void *userData)
-{}
+dummy_entity_decl_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ UNUSED_P(userData);
+ UNUSED_P(entityName);
+ UNUSED_P(is_parameter_entity);
+ UNUSED_P(value);
+ UNUSED_P(value_length);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ dummy_handler_flags |= DUMMY_ENTITY_DECL_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_entity_decl_handler(void *userData,
- const XML_Char *entityName,
- int is_parameter_entity,
- const XML_Char *value,
- int value_length,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName)
-{}
+dummy_notation_decl_handler(void *userData, const XML_Char *notationName,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(userData);
+ UNUSED_P(notationName);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ dummy_handler_flags |= DUMMY_NOTATION_DECL_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_notation_decl_handler(void *userData,
- const XML_Char *notationName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{}
+dummy_element_decl_handler(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ /* The content model must be freed by the handler. Unfortunately
+ * we cannot pass the parser as the userData because this is used
+ * with other handlers that require other userData.
+ */
+ XML_FreeContentModel(g_parser, model);
+ dummy_handler_flags |= DUMMY_ELEMENT_DECL_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_element_decl_handler(void *userData,
- const XML_Char *name,
- XML_Content *model)
-{}
+dummy_attlist_decl_handler(void *userData, const XML_Char *elname,
+ const XML_Char *attname, const XML_Char *att_type,
+ const XML_Char *dflt, int isrequired) {
+ UNUSED_P(userData);
+ UNUSED_P(elname);
+ UNUSED_P(attname);
+ UNUSED_P(att_type);
+ UNUSED_P(dflt);
+ UNUSED_P(isrequired);
+ dummy_handler_flags |= DUMMY_ATTLIST_DECL_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_attlist_decl_handler(void *userData,
- const XML_Char *elname,
- const XML_Char *attname,
- const XML_Char *att_type,
- const XML_Char *dflt,
- int isrequired)
-{}
+dummy_comment_handler(void *userData, const XML_Char *data) {
+ UNUSED_P(userData);
+ UNUSED_P(data);
+ dummy_handler_flags |= DUMMY_COMMENT_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_comment_handler(void *userData, const XML_Char *data)
-{}
+dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) {
+ UNUSED_P(userData);
+ UNUSED_P(target);
+ UNUSED_P(data);
+ dummy_handler_flags |= DUMMY_PI_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data)
-{}
+dummy_start_element(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ UNUSED_P(atts);
+ dummy_handler_flags |= DUMMY_START_ELEMENT_HANDLER_FLAG;
+}
static void XMLCALL
-dummy_start_element(void *userData,
- const XML_Char *name, const XML_Char **atts)
-{}
+dummy_end_element(void *userData, const XML_Char *name) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+}
+static void XMLCALL
+dummy_start_cdata_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_START_CDATA_HANDLER_FLAG;
+}
+
+static void XMLCALL
+dummy_end_cdata_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_END_CDATA_HANDLER_FLAG;
+}
+
+static void XMLCALL
+dummy_cdata_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+}
+
+static void XMLCALL
+dummy_start_namespace_decl_handler(void *userData, const XML_Char *prefix,
+ const XML_Char *uri) {
+ UNUSED_P(userData);
+ UNUSED_P(prefix);
+ UNUSED_P(uri);
+ dummy_handler_flags |= DUMMY_START_NS_DECL_HANDLER_FLAG;
+}
+
+static void XMLCALL
+dummy_end_namespace_decl_handler(void *userData, const XML_Char *prefix) {
+ UNUSED_P(userData);
+ UNUSED_P(prefix);
+ dummy_handler_flags |= DUMMY_END_NS_DECL_HANDLER_FLAG;
+}
+
+/* This handler is obsolete, but while the code exists we should
+ * ensure that dealing with the handler is covered by tests.
+ */
+static void XMLCALL
+dummy_unparsed_entity_decl_handler(void *userData, const XML_Char *entityName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName) {
+ UNUSED_P(userData);
+ UNUSED_P(entityName);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ dummy_handler_flags |= DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG;
+}
+
+static void XMLCALL
+dummy_default_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+}
+
+static void XMLCALL
+dummy_start_doctype_decl_handler(void *userData, const XML_Char *doctypeName,
+ const XML_Char *sysid, const XML_Char *pubid,
+ int has_internal_subset) {
+ UNUSED_P(userData);
+ UNUSED_P(doctypeName);
+ UNUSED_P(sysid);
+ UNUSED_P(pubid);
+ UNUSED_P(has_internal_subset);
+ dummy_handler_flags |= DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG;
+}
+
+static void XMLCALL
+dummy_end_doctype_decl_handler(void *userData) {
+ UNUSED_P(userData);
+ dummy_handler_flags |= DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG;
+}
+
+static void XMLCALL
+dummy_skip_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity) {
+ UNUSED_P(userData);
+ UNUSED_P(entityName);
+ UNUSED_P(is_parameter_entity);
+ dummy_handler_flags |= DUMMY_SKIP_HANDLER_FLAG;
+}
+
+/* Useful external entity handler */
+typedef struct ExtOption {
+ const XML_Char *system_id;
+ const char *parse_text;
+} ExtOption;
+
+static int XMLCALL
+external_entity_optioner(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtOption *options = (ExtOption *)XML_GetUserData(parser);
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ while (options->parse_text != NULL) {
+ if (! xcstrcmp(systemId, options->system_id)) {
+ enum XML_Status rc;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ rc = _XML_Parse_SINGLE_BYTES(ext_parser, options->parse_text,
+ (int)strlen(options->parse_text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ return rc;
+ }
+ options++;
+ }
+ fail("No suitable option found");
+ return XML_STATUS_ERROR;
+}
+
+/*
+ * Parameter entity evaluation support.
+ */
+#define ENTITY_MATCH_FAIL (-1)
+#define ENTITY_MATCH_NOT_FOUND (0)
+#define ENTITY_MATCH_SUCCESS (1)
+static const XML_Char *entity_name_to_match = NULL;
+static const XML_Char *entity_value_to_match = NULL;
+static int entity_match_flag = ENTITY_MATCH_NOT_FOUND;
+
+static void XMLCALL
+param_entity_match_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ UNUSED_P(userData);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ if (! is_parameter_entity || entity_name_to_match == NULL
+ || entity_value_to_match == NULL) {
+ return;
+ }
+ if (! xcstrcmp(entityName, entity_name_to_match)) {
+ /* The cast here is safe because we control the horizontal and
+ * the vertical, and we therefore know our strings are never
+ * going to overflow an int.
+ */
+ if (value_length != (int)xcstrlen(entity_value_to_match)
+ || xcstrncmp(value, entity_value_to_match, value_length)) {
+ entity_match_flag = ENTITY_MATCH_FAIL;
+ } else {
+ entity_match_flag = ENTITY_MATCH_SUCCESS;
+ }
+ }
+ /* Else leave the match flag alone */
+}
/*
* Character & encoding tests.
*/
-START_TEST(test_nul_byte)
-{
- char text[] = "<doc>\0</doc>";
+START_TEST(test_nul_byte) {
+ char text[] = "<doc>\0</doc>";
- /* test that a NUL byte (in US-ASCII data) is an error */
- if (XML_Parse(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK)
- fail("Parser did not report error on NUL-byte.");
- if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(parser);
+ /* test that a NUL byte (in US-ASCII data) is an error */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Parser did not report error on NUL-byte.");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_u0000_char) {
+ /* test that a NUL byte (in US-ASCII data) is an error */
+ expect_failure("<doc>&#0;</doc>", XML_ERROR_BAD_CHAR_REF,
+ "Parser did not report error on NUL-byte.");
+}
+END_TEST
+
+START_TEST(test_siphash_self) {
+ if (! sip24_valid())
+ fail("SipHash self-test failed");
+}
+END_TEST
+
+START_TEST(test_siphash_spec) {
+ /* https://131002.net/siphash/siphash.pdf (page 19, "Test values") */
+ const char message[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
+ "\x0a\x0b\x0c\x0d\x0e";
+ const size_t len = sizeof(message) - 1;
+ const uint64_t expected = _SIP_ULL(0xa129ca61U, 0x49be45e5U);
+ struct siphash state;
+ struct sipkey key;
+
+ sip_tokey(&key, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
+ "\x0a\x0b\x0c\x0d\x0e\x0f");
+ sip24_init(&state, &key);
+
+ /* Cover spread across calls */
+ sip24_update(&state, message, 4);
+ sip24_update(&state, message + 4, len - 4);
+
+ /* Cover null length */
+ sip24_update(&state, message, 0);
+
+ if (sip24_final(&state) != expected)
+ fail("sip24_final failed spec test\n");
+
+ /* Cover wrapper */
+ if (siphash24(message, len, &key) != expected)
+ fail("siphash24 failed spec test\n");
}
END_TEST
+START_TEST(test_bom_utf8) {
+ /* This test is really just making sure we don't core on a UTF-8 BOM. */
+ const char *text = "\357\273\277<e/>";
-START_TEST(test_u0000_char)
-{
- /* test that a NUL byte (in US-ASCII data) is an error */
- expect_failure("<doc>&#0;</doc>",
- XML_ERROR_BAD_CHAR_REF,
- "Parser did not report error on NUL-byte.");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
-START_TEST(test_bom_utf8)
-{
- /* This test is really just making sure we don't core on a UTF-8 BOM. */
- char *text = "\357\273\277<e/>";
+START_TEST(test_bom_utf16_be) {
+ char text[] = "\376\377\0<\0e\0/\0>";
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
-START_TEST(test_bom_utf16_be)
-{
- char text[] = "\376\377\0<\0e\0/\0>";
+START_TEST(test_bom_utf16_le) {
+ char text[] = "\377\376<\0e\0/\0>\0";
- if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
-START_TEST(test_bom_utf16_le)
-{
- char text[] = "\377\376<\0e\0/\0>\0";
+/* Parse whole buffer at once to exercise a different code path */
+START_TEST(test_nobom_utf16_le) {
+ char text[] = " \0<\0e\0/\0>\0";
- if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ if (XML_Parse(g_parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
static void XMLCALL
-accumulate_characters(void *userData, const XML_Char *s, int len)
-{
- CharData_AppendXMLChars((CharData *)userData, s, len);
+accumulate_characters(void *userData, const XML_Char *s, int len) {
+ CharData_AppendXMLChars((CharData *)userData, s, len);
}
static void XMLCALL
accumulate_attribute(void *userData, const XML_Char *name,
- const XML_Char **atts)
-{
- CharData *storage = (CharData *)userData;
- if (storage->count < 0 && atts != NULL && atts[0] != NULL) {
- /* "accumulate" the value of the first attribute we see */
- CharData_AppendXMLChars(storage, atts[1], -1);
- }
+ const XML_Char **atts) {
+ CharData *storage = (CharData *)userData;
+ UNUSED_P(name);
+ /* Check there are attributes to deal with */
+ if (atts == NULL)
+ return;
+
+ while (storage->count < 0 && atts[0] != NULL) {
+ /* "accumulate" the value of the first attribute we see */
+ CharData_AppendXMLChars(storage, atts[1], -1);
+ atts += 2;
+ }
}
-
static void
-_run_character_check(XML_Char *text, XML_Char *expected,
- const char *file, int line)
-{
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(parser, &storage);
- XML_SetCharacterDataHandler(parser, accumulate_characters);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- _xml_failure(parser, file, line);
- CharData_CheckXMLChars(&storage, expected);
+_run_character_check(const char *text, const XML_Char *expected,
+ const char *file, int line) {
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ _xml_failure(g_parser, file, line);
+ CharData_CheckXMLChars(&storage, expected);
}
-#define run_character_check(text, expected) \
- _run_character_check(text, expected, __FILE__, __LINE__)
+#define run_character_check(text, expected) \
+ _run_character_check(text, expected, __FILE__, __LINE__)
static void
-_run_attribute_check(XML_Char *text, XML_Char *expected,
- const char *file, int line)
-{
- CharData storage;
+_run_attribute_check(const char *text, const XML_Char *expected,
+ const char *file, int line) {
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ _xml_failure(g_parser, file, line);
+ CharData_CheckXMLChars(&storage, expected);
+}
- CharData_Init(&storage);
- XML_SetUserData(parser, &storage);
- XML_SetStartElementHandler(parser, accumulate_attribute);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- _xml_failure(parser, file, line);
- CharData_CheckXMLChars(&storage, expected);
+#define run_attribute_check(text, expected) \
+ _run_attribute_check(text, expected, __FILE__, __LINE__)
+
+typedef struct ExtTest {
+ const char *parse_text;
+ const XML_Char *encoding;
+ CharData *storage;
+} ExtTest;
+
+static void XMLCALL
+ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
+ ExtTest *test_data = (ExtTest *)userData;
+ accumulate_characters(test_data->storage, s, len);
}
-#define run_attribute_check(text, expected) \
- _run_attribute_check(text, expected, __FILE__, __LINE__)
+static void
+_run_ext_character_check(const char *text, ExtTest *test_data,
+ const XML_Char *expected, const char *file, int line) {
+ CharData *const storage = (CharData *)malloc(sizeof(CharData));
+
+ CharData_Init(storage);
+ test_data->storage = storage;
+ XML_SetUserData(g_parser, test_data);
+ XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ _xml_failure(g_parser, file, line);
+ CharData_CheckXMLChars(storage, expected);
+
+ free(storage);
+}
+
+#define run_ext_character_check(text, test_data, expected) \
+ _run_ext_character_check(text, test_data, expected, __FILE__, __LINE__)
/* Regression test for SF bug #491986. */
-START_TEST(test_danish_latin1)
-{
- char *text =
- "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
- run_character_check(text,
- "J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
+START_TEST(test_danish_latin1) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
+#ifdef XML_UNICODE
+ const XML_Char *expected
+ = XCS("J\x00f8rgen \x00e6\x00f8\x00e5\x00c6\x00d8\x00c5");
+#else
+ const XML_Char *expected
+ = XCS("J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
+#endif
+ run_character_check(text, expected);
}
END_TEST
-
/* Regression test for SF bug #514281. */
-START_TEST(test_french_charref_hexidecimal)
-{
- char *text =
- "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
- run_character_check(text,
- "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+START_TEST(test_french_charref_hexidecimal) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
+#else
+ const XML_Char *expected
+ = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+#endif
+ run_character_check(text, expected);
}
END_TEST
-START_TEST(test_french_charref_decimal)
-{
- char *text =
- "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
- run_character_check(text,
- "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+START_TEST(test_french_charref_decimal) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
+#else
+ const XML_Char *expected
+ = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+#endif
+ run_character_check(text, expected);
}
END_TEST
-START_TEST(test_french_latin1)
-{
- char *text =
- "<?xml version='1.0' encoding='iso-8859-1'?>\n"
- "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
- run_character_check(text,
- "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+START_TEST(test_french_latin1) {
+ const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9\x00e8\x00e0\x00e7\x00ea\x00c8");
+#else
+ const XML_Char *expected
+ = XCS("\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
+#endif
+ run_character_check(text, expected);
}
END_TEST
-START_TEST(test_french_utf8)
-{
- char *text =
- "<?xml version='1.0' encoding='utf-8'?>\n"
- "<doc>\xC3\xA9</doc>";
- run_character_check(text, "\xC3\xA9");
+START_TEST(test_french_utf8) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>\xC3\xA9</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9");
+#else
+ const XML_Char *expected = XCS("\xC3\xA9");
+#endif
+ run_character_check(text, expected);
}
END_TEST
@@ -312,10 +737,14 @@ END_TEST
characters as PCDATA and attribute value content, and XML Name
characters as part of element and attribute names.
*/
-START_TEST(test_utf8_false_rejection)
-{
- char *text = "<doc>\xEF\xBA\xBF</doc>";
- run_character_check(text, "\xEF\xBA\xBF");
+START_TEST(test_utf8_false_rejection) {
+ const char *text = "<doc>\xEF\xBA\xBF</doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\xfebf");
+#else
+ const XML_Char *expected = XCS("\xEF\xBA\xBF");
+#endif
+ run_character_check(text, expected);
}
END_TEST
@@ -324,240 +753,443 @@ END_TEST
character will not be mistakenly interpreted as a valid UTF-8
sequence.
*/
-START_TEST(test_illegal_utf8)
-{
- char text[100];
- int i;
+START_TEST(test_illegal_utf8) {
+ char text[100];
+ int i;
+
+ for (i = 128; i <= 255; ++i) {
+ sprintf(text, "<e>%ccd</e>", i);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK) {
+ sprintf(text, "expected token error for '%c' (ordinal %d) in UTF-8 text",
+ i, i);
+ fail(text);
+ } else if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+ /* Reset the parser since we use the same parser repeatedly. */
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
- for (i = 128; i <= 255; ++i) {
- sprintf(text, "<e>%ccd</e>", i);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) {
- sprintf(text,
- "expected token error for '%c' (ordinal %d) in UTF-8 text",
- i, i);
- fail(text);
- }
- else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
- xml_failure(parser);
- /* Reset the parser since we use the same parser repeatedly. */
- XML_ParserReset(parser, NULL);
+/* Examples, not masks: */
+#define UTF8_LEAD_1 "\x7f" /* 0b01111111 */
+#define UTF8_LEAD_2 "\xdf" /* 0b11011111 */
+#define UTF8_LEAD_3 "\xef" /* 0b11101111 */
+#define UTF8_LEAD_4 "\xf7" /* 0b11110111 */
+#define UTF8_FOLLOW "\xbf" /* 0b10111111 */
+
+START_TEST(test_utf8_auto_align) {
+ struct TestCase {
+ ptrdiff_t expectedMovementInChars;
+ const char *input;
+ };
+
+ struct TestCase cases[] = {
+ {00, ""},
+
+ {00, UTF8_LEAD_1},
+
+ {-1, UTF8_LEAD_2},
+ {00, UTF8_LEAD_2 UTF8_FOLLOW},
+
+ {-1, UTF8_LEAD_3},
+ {-2, UTF8_LEAD_3 UTF8_FOLLOW},
+ {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
+
+ {-1, UTF8_LEAD_4},
+ {-2, UTF8_LEAD_4 UTF8_FOLLOW},
+ {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
+ {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
+ };
+
+ size_t i = 0;
+ bool success = true;
+ for (; i < sizeof(cases) / sizeof(*cases); i++) {
+ const char *fromLim = cases[i].input + strlen(cases[i].input);
+ const char *const fromLimInitially = fromLim;
+ ptrdiff_t actualMovementInChars;
+
+ _INTERNAL_trim_to_complete_utf8_characters(cases[i].input, &fromLim);
+
+ actualMovementInChars = (fromLim - fromLimInitially);
+ if (actualMovementInChars != cases[i].expectedMovementInChars) {
+ size_t j = 0;
+ success = false;
+ printf("[-] UTF-8 case %2u: Expected movement by %2d chars"
+ ", actually moved by %2d chars: \"",
+ (unsigned)(i + 1), (int)cases[i].expectedMovementInChars,
+ (int)actualMovementInChars);
+ for (; j < strlen(cases[i].input); j++) {
+ printf("\\x%02x", (unsigned char)cases[i].input[j]);
+ }
+ printf("\"\n");
}
+ }
+
+ if (! success) {
+ fail("UTF-8 auto-alignment is not bullet-proof\n");
+ }
}
END_TEST
-START_TEST(test_utf16)
-{
- /* <?xml version="1.0" encoding="UTF-16"?>
- <doc a='123'>some text</doc>
- */
- char text[] =
- "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
+START_TEST(test_utf16) {
+ /* <?xml version="1.0" encoding="UTF-16"?>
+ * <doc a='123'>some {A} text</doc>
+ *
+ * where {A} is U+FF21, FULLWIDTH LATIN CAPITAL LETTER A
+ */
+ char text[]
+ = "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
"\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
"\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
"\000'\000?\000>\000\n"
- "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'"
- "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/"
- "\000d\000o\000c\000>";
- if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
-}
-END_TEST
-
-START_TEST(test_utf16_le_epilog_newline)
-{
- unsigned int first_chunk_bytes = 17;
- char text[] =
- "\xFF\xFE" /* BOM */
- "<\000e\000/\000>\000" /* document element */
- "\r\000\n\000\r\000\n\000"; /* epilog */
-
- if (first_chunk_bytes >= sizeof(text) - 1)
- fail("bad value of first_chunk_bytes");
- if ( XML_Parse(parser, text, first_chunk_bytes, XML_FALSE)
- == XML_STATUS_ERROR)
- xml_failure(parser);
- else {
- enum XML_Status rc;
- rc = XML_Parse(parser, text + first_chunk_bytes,
- sizeof(text) - first_chunk_bytes - 1, XML_TRUE);
- if (rc == XML_STATUS_ERROR)
- xml_failure(parser);
- }
+ "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'\000>"
+ "\000s\000o\000m\000e\000 \xff\x21\000 \000t\000e\000x\000t\000"
+ "<\000/\000d\000o\000c\000>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("some \xff21 text");
+#else
+ const XML_Char *expected = XCS("some \357\274\241 text");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_le_epilog_newline) {
+ unsigned int first_chunk_bytes = 17;
+ char text[] = "\xFF\xFE" /* BOM */
+ "<\000e\000/\000>\000" /* document element */
+ "\r\000\n\000\r\000\n\000"; /* epilog */
+
+ if (first_chunk_bytes >= sizeof(text) - 1)
+ fail("bad value of first_chunk_bytes");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, first_chunk_bytes, XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ else {
+ enum XML_Status rc;
+ rc = _XML_Parse_SINGLE_BYTES(g_parser, text + first_chunk_bytes,
+ sizeof(text) - first_chunk_bytes - 1,
+ XML_TRUE);
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ }
+}
+END_TEST
+
+/* Test that an outright lie in the encoding is faulted */
+START_TEST(test_not_utf16) {
+ const char *text = "<?xml version='1.0' encoding='utf-16'?>"
+ "<doc>Hi</doc>";
+
+ /* Use a handler to provoke the appropriate code paths */
+ XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
+ expect_failure(text, XML_ERROR_INCORRECT_ENCODING,
+ "UTF-16 declared in UTF-8 not faulted");
+}
+END_TEST
+
+/* Test that an unknown encoding is rejected */
+START_TEST(test_bad_encoding) {
+ const char *text = "<doc>Hi</doc>";
+
+ if (! XML_SetEncoding(g_parser, XCS("unknown-encoding")))
+ fail("XML_SetEncoding failed");
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Unknown encoding not faulted");
}
END_TEST
/* Regression test for SF bug #481609, #774028. */
-START_TEST(test_latin1_umlauts)
-{
- char *text =
- "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+START_TEST(test_latin1_umlauts) {
+ const char *text
+ = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
"<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
" >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
- char *utf8 =
- "\xC3\xA4 \xC3\xB6 \xC3\xBC "
- "\xC3\xA4 \xC3\xB6 \xC3\xBC "
- "\xC3\xA4 \xC3\xB6 \xC3\xBC >";
- run_character_check(text, utf8);
- XML_ParserReset(parser, NULL);
- run_attribute_check(text, utf8);
+#ifdef XML_UNICODE
+ /* Expected results in UTF-16 */
+ const XML_Char *expected = XCS("\x00e4 \x00f6 \x00fc ")
+ XCS("\x00e4 \x00f6 \x00fc ") XCS("\x00e4 \x00f6 \x00fc >");
+#else
+ /* Expected results in UTF-8 */
+ const XML_Char *expected = XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ")
+ XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC ") XCS("\xC3\xA4 \xC3\xB6 \xC3\xBC >");
+#endif
+
+ run_character_check(text, expected);
+ XML_ParserReset(g_parser, NULL);
+ run_attribute_check(text, expected);
+ /* Repeat with a default handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ run_character_check(text, expected);
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ run_attribute_check(text, expected);
+}
+END_TEST
+
+/* Test that an element name with a 4-byte UTF-8 character is rejected */
+START_TEST(test_long_utf8_character) {
+ const char *text
+ = "<?xml version='1.0' encoding='utf-8'?>\n"
+ /* 0xf0 0x90 0x80 0x80 = U+10000, the first Linear B character */
+ "<do\xf0\x90\x80\x80/>";
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "4-byte UTF-8 character in element name not faulted");
+}
+END_TEST
+
+/* Test that a long latin-1 attribute (too long to convert in one go)
+ * is correctly converted
+ */
+START_TEST(test_long_latin1_attribute) {
+ const char *text
+ = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
+ "<doc att='"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ /* Last character splits across a buffer boundary */
+ "\xe4'>\n</doc>";
+
+ const XML_Char *expected =
+ /* 64 characters per line */
+ /* clang-format off */
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO")
+ /* clang-format on */
+#ifdef XML_UNICODE
+ XCS("\x00e4");
+#else
+ XCS("\xc3\xa4");
+#endif
+
+ run_attribute_check(text, expected);
+}
+END_TEST
+
+/* Test that a long ASCII attribute (too long to convert in one go)
+ * is correctly converted
+ */
+START_TEST(test_long_ascii_attribute) {
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc att='"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "01234'>\n</doc>";
+ const XML_Char *expected =
+ /* 64 characters per line */
+ /* clang-format off */
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("01234");
+ /* clang-format on */
+
+ run_attribute_check(text, expected);
}
END_TEST
/* Regression test #1 for SF bug #653180. */
-START_TEST(test_line_number_after_parse)
-{
- char *text =
- "<tag>\n"
- "\n"
- "\n</tag>";
- XML_Size lineno;
-
- if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
- xml_failure(parser);
- lineno = XML_GetCurrentLineNumber(parser);
- if (lineno != 4) {
- char buffer[100];
- sprintf(buffer,
- "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
- fail(buffer);
- }
+START_TEST(test_line_number_after_parse) {
+ const char *text = "<tag>\n"
+ "\n"
+ "\n</tag>";
+ XML_Size lineno;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ lineno = XML_GetCurrentLineNumber(g_parser);
+ if (lineno != 4) {
+ char buffer[100];
+ sprintf(buffer, "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
+ fail(buffer);
+ }
}
END_TEST
/* Regression test #2 for SF bug #653180. */
-START_TEST(test_column_number_after_parse)
-{
- char *text = "<tag></tag>";
- XML_Size colno;
-
- if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
- xml_failure(parser);
- colno = XML_GetCurrentColumnNumber(parser);
- if (colno != 11) {
- char buffer[100];
- sprintf(buffer,
- "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
- fail(buffer);
- }
+START_TEST(test_column_number_after_parse) {
+ const char *text = "<tag></tag>";
+ XML_Size colno;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ colno = XML_GetCurrentColumnNumber(g_parser);
+ if (colno != 11) {
+ char buffer[100];
+ sprintf(buffer, "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
+ fail(buffer);
+ }
}
END_TEST
+#define STRUCT_START_TAG 0
+#define STRUCT_END_TAG 1
static void XMLCALL
start_element_event_handler2(void *userData, const XML_Char *name,
- const XML_Char **attr)
-{
- CharData *storage = (CharData *) userData;
- char buffer[100];
-
- sprintf(buffer,
- "<%s> at col:%" XML_FMT_INT_MOD "u line:%"\
- XML_FMT_INT_MOD "u\n", name,
- XML_GetCurrentColumnNumber(parser),
- XML_GetCurrentLineNumber(parser));
- CharData_AppendString(storage, buffer);
+ const XML_Char **attr) {
+ StructData *storage = (StructData *)userData;
+ UNUSED_P(attr);
+ StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
+ XML_GetCurrentLineNumber(g_parser), STRUCT_START_TAG);
}
static void XMLCALL
-end_element_event_handler2(void *userData, const XML_Char *name)
-{
- CharData *storage = (CharData *) userData;
- char buffer[100];
-
- sprintf(buffer,
- "</%s> at col:%" XML_FMT_INT_MOD "u line:%"\
- XML_FMT_INT_MOD "u\n", name,
- XML_GetCurrentColumnNumber(parser),
- XML_GetCurrentLineNumber(parser));
- CharData_AppendString(storage, buffer);
+end_element_event_handler2(void *userData, const XML_Char *name) {
+ StructData *storage = (StructData *)userData;
+ StructData_AddItem(storage, name, XML_GetCurrentColumnNumber(g_parser),
+ XML_GetCurrentLineNumber(g_parser), STRUCT_END_TAG);
}
/* Regression test #3 for SF bug #653180. */
-START_TEST(test_line_and_column_numbers_inside_handlers)
-{
- char *text =
- "<a>\n" /* Unix end-of-line */
- " <b>\r\n" /* Windows end-of-line */
- " <c/>\r" /* Mac OS end-of-line */
- " </b>\n"
- " <d>\n"
- " <f/>\n"
- " </d>\n"
- "</a>";
- char *expected =
- "<a> at col:0 line:1\n"
- "<b> at col:2 line:2\n"
- "<c> at col:4 line:3\n"
- "</c> at col:8 line:3\n"
- "</b> at col:2 line:4\n"
- "<d> at col:2 line:5\n"
- "<f> at col:4 line:6\n"
- "</f> at col:8 line:6\n"
- "</d> at col:2 line:7\n"
- "</a> at col:0 line:8\n";
- CharData storage;
-
- CharData_Init(&storage);
- XML_SetUserData(parser, &storage);
- XML_SetStartElementHandler(parser, start_element_event_handler2);
- XML_SetEndElementHandler(parser, end_element_event_handler2);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
-
- CharData_CheckString(&storage, expected);
+START_TEST(test_line_and_column_numbers_inside_handlers) {
+ const char *text = "<a>\n" /* Unix end-of-line */
+ " <b>\r\n" /* Windows end-of-line */
+ " <c/>\r" /* Mac OS end-of-line */
+ " </b>\n"
+ " <d>\n"
+ " <f/>\n"
+ " </d>\n"
+ "</a>";
+ const StructDataEntry expected[]
+ = {{XCS("a"), 0, 1, STRUCT_START_TAG}, {XCS("b"), 2, 2, STRUCT_START_TAG},
+ {XCS("c"), 4, 3, STRUCT_START_TAG}, {XCS("c"), 8, 3, STRUCT_END_TAG},
+ {XCS("b"), 2, 4, STRUCT_END_TAG}, {XCS("d"), 2, 5, STRUCT_START_TAG},
+ {XCS("f"), 4, 6, STRUCT_START_TAG}, {XCS("f"), 8, 6, STRUCT_END_TAG},
+ {XCS("d"), 2, 7, STRUCT_END_TAG}, {XCS("a"), 0, 8, STRUCT_END_TAG}};
+ const int expected_count = sizeof(expected) / sizeof(StructDataEntry);
+ StructData storage;
+
+ StructData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, start_element_event_handler2);
+ XML_SetEndElementHandler(g_parser, end_element_event_handler2);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ StructData_CheckItems(&storage, expected, expected_count);
+ StructData_Dispose(&storage);
}
END_TEST
/* Regression test #4 for SF bug #653180. */
-START_TEST(test_line_number_after_error)
-{
- char *text =
- "<a>\n"
- " <b>\n"
- " </a>"; /* missing </b> */
- XML_Size lineno;
- if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
- fail("Expected a parse error");
-
- lineno = XML_GetCurrentLineNumber(parser);
- if (lineno != 3) {
- char buffer[100];
- sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
- fail(buffer);
- }
+START_TEST(test_line_number_after_error) {
+ const char *text = "<a>\n"
+ " <b>\n"
+ " </a>"; /* missing </b> */
+ XML_Size lineno;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ != XML_STATUS_ERROR)
+ fail("Expected a parse error");
+
+ lineno = XML_GetCurrentLineNumber(g_parser);
+ if (lineno != 3) {
+ char buffer[100];
+ sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
+ fail(buffer);
+ }
}
END_TEST
-
+
/* Regression test #5 for SF bug #653180. */
-START_TEST(test_column_number_after_error)
-{
- char *text =
- "<a>\n"
- " <b>\n"
- " </a>"; /* missing </b> */
- XML_Size colno;
- if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
- fail("Expected a parse error");
-
- colno = XML_GetCurrentColumnNumber(parser);
- if (colno != 4) {
- char buffer[100];
- sprintf(buffer,
- "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
- fail(buffer);
- }
+START_TEST(test_column_number_after_error) {
+ const char *text = "<a>\n"
+ " <b>\n"
+ " </a>"; /* missing </b> */
+ XML_Size colno;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ != XML_STATUS_ERROR)
+ fail("Expected a parse error");
+
+ colno = XML_GetCurrentColumnNumber(g_parser);
+ if (colno != 4) {
+ char buffer[100];
+ sprintf(buffer, "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
+ fail(buffer);
+ }
}
END_TEST
/* Regression test for SF bug #478332. */
-START_TEST(test_really_long_lines)
-{
- /* This parses an input line longer than INIT_DATA_BUF_SIZE
- characters long (defined to be 1024 in xmlparse.c). We take a
- really cheesy approach to building the input buffer, because
- this avoids writing bugs in buffer-filling code.
- */
- char *text =
- "<e>"
+START_TEST(test_really_long_lines) {
+ /* This parses an input line longer than INIT_DATA_BUF_SIZE
+ characters long (defined to be 1024 in xmlparse.c). We take a
+ really cheesy approach to building the input buffer, because
+ this avoids writing bugs in buffer-filling code.
+ */
+ const char *text
+ = "<e>"
/* 64 chars */
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
/* until we have at least 1024 characters on the line: */
@@ -578,40 +1210,89 @@ START_TEST(test_really_long_lines)
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
"</e>";
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
+/* Test cdata processing across a buffer boundary */
+START_TEST(test_really_long_encoded_lines) {
+ /* As above, except that we want to provoke an output buffer
+ * overflow with a non-trivial encoding. For this we need to pass
+ * the whole cdata in one go, not byte-by-byte.
+ */
+ void *buffer;
+ const char *text
+ = "<?xml version='1.0' encoding='iso-8859-1'?>"
+ "<e>"
+ /* 64 chars */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ /* until we have at least 1024 characters on the line: */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
+ "</e>";
+ int parse_len = (int)strlen(text);
+
+ /* Need a cdata handler to provoke the code path we want to test */
+ XML_SetCharacterDataHandler(g_parser, dummy_cdata_handler);
+ buffer = XML_GetBuffer(g_parser, parse_len);
+ if (buffer == NULL)
+ fail("Could not allocate parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, text, parse_len);
+ if (XML_ParseBuffer(g_parser, parse_len, XML_TRUE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
/*
* Element event tests.
*/
static void XMLCALL
-end_element_event_handler(void *userData, const XML_Char *name)
-{
- CharData *storage = (CharData *) userData;
- CharData_AppendString(storage, "/");
- CharData_AppendXMLChars(storage, name, -1);
+start_element_event_handler(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(atts);
+ CharData_AppendXMLChars((CharData *)userData, name, -1);
}
-START_TEST(test_end_element_events)
-{
- char *text = "<a><b><c/></b><d><f/></d></a>";
- char *expected = "/c/b/f/d/a";
- CharData storage;
+static void XMLCALL
+end_element_event_handler(void *userData, const XML_Char *name) {
+ CharData *storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("/"), 1);
+ CharData_AppendXMLChars(storage, name, -1);
+}
- CharData_Init(&storage);
- XML_SetUserData(parser, &storage);
- XML_SetEndElementHandler(parser, end_element_event_handler);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
- CharData_CheckString(&storage, expected);
+START_TEST(test_end_element_events) {
+ const char *text = "<a><b><c/></b><d><f/></d></a>";
+ const XML_Char *expected = XCS("/c/b/f/d/a");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetEndElementHandler(g_parser, end_element_event_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
}
END_TEST
-
/*
* Attribute tests.
*/
@@ -626,84 +1307,82 @@ END_TEST
attribute data types do. (Section 3.3.3 of the recommendation.)
*/
static int
-is_whitespace_normalized(const XML_Char *s, int is_cdata)
-{
- int blanks = 0;
- int at_start = 1;
- while (*s) {
- if (*s == ' ')
- ++blanks;
- else if (*s == '\t' || *s == '\n' || *s == '\r')
- return 0;
- else {
- if (at_start) {
- at_start = 0;
- if (blanks && !is_cdata)
- /* illegal leading blanks */
- return 0;
- }
- else if (blanks > 1 && !is_cdata)
- return 0;
- blanks = 0;
- }
- ++s;
- }
- if (blanks && !is_cdata)
+is_whitespace_normalized(const XML_Char *s, int is_cdata) {
+ int blanks = 0;
+ int at_start = 1;
+ while (*s) {
+ if (*s == XCS(' '))
+ ++blanks;
+ else if (*s == XCS('\t') || *s == XCS('\n') || *s == XCS('\r'))
+ return 0;
+ else {
+ if (at_start) {
+ at_start = 0;
+ if (blanks && ! is_cdata)
+ /* illegal leading blanks */
+ return 0;
+ } else if (blanks > 1 && ! is_cdata)
return 0;
- return 1;
+ blanks = 0;
+ }
+ ++s;
+ }
+ if (blanks && ! is_cdata)
+ return 0;
+ return 1;
}
/* Check the attribute whitespace checker: */
static void
-testhelper_is_whitespace_normalized(void)
-{
- assert(is_whitespace_normalized("abc", 0));
- assert(is_whitespace_normalized("abc", 1));
- assert(is_whitespace_normalized("abc def ghi", 0));
- assert(is_whitespace_normalized("abc def ghi", 1));
- assert(!is_whitespace_normalized(" abc def ghi", 0));
- assert(is_whitespace_normalized(" abc def ghi", 1));
- assert(!is_whitespace_normalized("abc def ghi", 0));
- assert(is_whitespace_normalized("abc def ghi", 1));
- assert(!is_whitespace_normalized("abc def ghi ", 0));
- assert(is_whitespace_normalized("abc def ghi ", 1));
- assert(!is_whitespace_normalized(" ", 0));
- assert(is_whitespace_normalized(" ", 1));
- assert(!is_whitespace_normalized("\t", 0));
- assert(!is_whitespace_normalized("\t", 1));
- assert(!is_whitespace_normalized("\n", 0));
- assert(!is_whitespace_normalized("\n", 1));
- assert(!is_whitespace_normalized("\r", 0));
- assert(!is_whitespace_normalized("\r", 1));
- assert(!is_whitespace_normalized("abc\t def", 1));
+testhelper_is_whitespace_normalized(void) {
+ assert(is_whitespace_normalized(XCS("abc"), 0));
+ assert(is_whitespace_normalized(XCS("abc"), 1));
+ assert(is_whitespace_normalized(XCS("abc def ghi"), 0));
+ assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
+ assert(! is_whitespace_normalized(XCS(" abc def ghi"), 0));
+ assert(is_whitespace_normalized(XCS(" abc def ghi"), 1));
+ assert(! is_whitespace_normalized(XCS("abc def ghi"), 0));
+ assert(is_whitespace_normalized(XCS("abc def ghi"), 1));
+ assert(! is_whitespace_normalized(XCS("abc def ghi "), 0));
+ assert(is_whitespace_normalized(XCS("abc def ghi "), 1));
+ assert(! is_whitespace_normalized(XCS(" "), 0));
+ assert(is_whitespace_normalized(XCS(" "), 1));
+ assert(! is_whitespace_normalized(XCS("\t"), 0));
+ assert(! is_whitespace_normalized(XCS("\t"), 1));
+ assert(! is_whitespace_normalized(XCS("\n"), 0));
+ assert(! is_whitespace_normalized(XCS("\n"), 1));
+ assert(! is_whitespace_normalized(XCS("\r"), 0));
+ assert(! is_whitespace_normalized(XCS("\r"), 1));
+ assert(! is_whitespace_normalized(XCS("abc\t def"), 1));
}
static void XMLCALL
-check_attr_contains_normalized_whitespace(void *userData,
- const XML_Char *name,
- const XML_Char **atts)
-{
- int i;
- for (i = 0; atts[i] != NULL; i += 2) {
- const XML_Char *attrname = atts[i];
- const XML_Char *value = atts[i + 1];
- if (strcmp("attr", attrname) == 0
- || strcmp("ents", attrname) == 0
- || strcmp("refs", attrname) == 0) {
- if (!is_whitespace_normalized(value, 0)) {
- char buffer[256];
- sprintf(buffer, "attribute value not normalized: %s='%s'",
- attrname, value);
- fail(buffer);
- }
- }
+check_attr_contains_normalized_whitespace(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ int i;
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ for (i = 0; atts[i] != NULL; i += 2) {
+ const XML_Char *attrname = atts[i];
+ const XML_Char *value = atts[i + 1];
+ if (xcstrcmp(XCS("attr"), attrname) == 0
+ || xcstrcmp(XCS("ents"), attrname) == 0
+ || xcstrcmp(XCS("refs"), attrname) == 0) {
+ if (! is_whitespace_normalized(value, 0)) {
+ char buffer[256];
+ sprintf(buffer,
+ "attribute value not normalized: %" XML_FMT_STR
+ "='%" XML_FMT_STR "'",
+ attrname, value);
+ fail(buffer);
+ }
}
+ }
}
-START_TEST(test_attr_whitespace_normalization)
-{
- char *text =
- "<!DOCTYPE doc [\n"
+START_TEST(test_attr_whitespace_normalization) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
" <!ATTLIST doc\n"
" attr NMTOKENS #REQUIRED\n"
" ents ENTITIES #REQUIRED\n"
@@ -716,97 +1395,253 @@ START_TEST(test_attr_whitespace_normalization)
" <e id='id-2'/>\n"
"</doc>";
- XML_SetStartElementHandler(parser,
- check_attr_contains_normalized_whitespace);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ XML_SetStartElementHandler(g_parser,
+ check_attr_contains_normalized_whitespace);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
-
/*
* XML declaration tests.
*/
-START_TEST(test_xmldecl_misplaced)
-{
- expect_failure("\n"
- "<?xml version='1.0'?>\n"
- "<a/>",
- XML_ERROR_MISPLACED_XML_PI,
- "failed to report misplaced XML declaration");
+START_TEST(test_xmldecl_misplaced) {
+ expect_failure("\n"
+ "<?xml version='1.0'?>\n"
+ "<a/>",
+ XML_ERROR_MISPLACED_XML_PI,
+ "failed to report misplaced XML declaration");
+}
+END_TEST
+
+START_TEST(test_xmldecl_invalid) {
+ expect_failure("<?xml version='1.0' \xc3\xa7?>\n<doc/>", XML_ERROR_XML_DECL,
+ "Failed to report invalid XML declaration");
+}
+END_TEST
+
+START_TEST(test_xmldecl_missing_attr) {
+ expect_failure("<?xml ='1.0'?>\n<doc/>\n", XML_ERROR_XML_DECL,
+ "Failed to report missing XML declaration attribute");
+}
+END_TEST
+
+START_TEST(test_xmldecl_missing_value) {
+ expect_failure("<?xml version='1.0' encoding='us-ascii' standalone?>\n"
+ "<doc/>",
+ XML_ERROR_XML_DECL,
+ "Failed to report missing attribute value");
}
END_TEST
/* Regression test for SF bug #584832. */
static int XMLCALL
-UnknownEncodingHandler(void *data,const XML_Char *encoding,XML_Encoding *info)
-{
- if (strcmp(encoding,"unsupported-encoding") == 0) {
- int i;
- for (i = 0; i < 256; ++i)
- info->map[i] = i;
- info->data = NULL;
- info->convert = NULL;
- info->release = NULL;
- return XML_STATUS_OK;
- }
- return XML_STATUS_ERROR;
+UnknownEncodingHandler(void *data, const XML_Char *encoding,
+ XML_Encoding *info) {
+ UNUSED_P(data);
+ if (xcstrcmp(encoding, XCS("unsupported-encoding")) == 0) {
+ int i;
+ for (i = 0; i < 256; ++i)
+ info->map[i] = i;
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = NULL;
+ return XML_STATUS_OK;
+ }
+ return XML_STATUS_ERROR;
}
-START_TEST(test_unknown_encoding_internal_entity)
-{
- char *text =
- "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
- "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
- "<test a='&foo;'/>";
+START_TEST(test_unknown_encoding_internal_entity) {
+ const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
+ "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
+ "<test a='&foo;'/>";
- XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ XML_SetUnknownEncodingHandler(g_parser, UnknownEncodingHandler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test unrecognised encoding handler */
+static void
+dummy_release(void *data) {
+ UNUSED_P(data);
+}
+
+static int XMLCALL
+UnrecognisedEncodingHandler(void *data, const XML_Char *encoding,
+ XML_Encoding *info) {
+ UNUSED_P(data);
+ UNUSED_P(encoding);
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = dummy_release;
+ return XML_STATUS_ERROR;
+}
+
+START_TEST(test_unrecognised_encoding_internal_entity) {
+ const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
+ "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
+ "<test a='&foo;'/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, UnrecognisedEncodingHandler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Unrecognised encoding not rejected");
}
END_TEST
/* Regression test for SF bug #620106. */
static int XMLCALL
-external_entity_loader_set_encoding(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- /* This text says it's an unsupported encoding, but it's really
- UTF-8, which we tell Expat using XML_SetEncoding().
- */
- char *text =
- "<?xml encoding='iso-8859-3'?>"
- "\xC3\xA9";
- XML_Parser extparser;
-
- extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (extparser == NULL)
- fail("Could not create external entity parser.");
- if (!XML_SetEncoding(extparser, "utf-8"))
- fail("XML_SetEncoding() ignored for external entity");
- if ( XML_Parse(extparser, text, strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(parser);
- return 0;
- }
- return 1;
+external_entity_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtTest *test_data = (ExtTest *)XML_GetUserData(parser);
+ XML_Parser extparser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (extparser == NULL)
+ fail("Could not create external entity parser.");
+ if (test_data->encoding != NULL) {
+ if (! XML_SetEncoding(extparser, test_data->encoding))
+ fail("XML_SetEncoding() ignored for external entity");
+ }
+ if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
+ (int)strlen(test_data->parse_text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(extparser);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(extparser);
+ return XML_STATUS_OK;
}
-START_TEST(test_ext_entity_set_encoding)
-{
- char *text =
- "<!DOCTYPE doc [\n"
- " <!ENTITY en SYSTEM 'http://xml.libexpat.org/dummy.ent'>\n"
- "]>\n"
- "<doc>&en;</doc>";
+START_TEST(test_ext_entity_set_encoding) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest test_data
+ = {/* This text says it's an unsupported encoding, but it's really
+ UTF-8, which we tell Expat using XML_SetEncoding().
+ */
+ "<?xml encoding='iso-8859-3'?>\xC3\xA9", XCS("utf-8"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9");
+#else
+ const XML_Char *expected = XCS("\xc3\xa9");
+#endif
- XML_SetExternalEntityRefHandler(parser,
- external_entity_loader_set_encoding);
- run_character_check(text, "\xC3\xA9");
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ run_ext_character_check(text, &test_data, expected);
+}
+END_TEST
+
+/* Test external entities with no handler */
+START_TEST(test_ext_entity_no_handler) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ run_character_check(text, XCS(""));
+}
+END_TEST
+
+/* Test UTF-8 BOM is accepted */
+START_TEST(test_ext_entity_set_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest test_data = {"\xEF\xBB\xBF" /* BOM */
+ "<?xml encoding='iso-8859-3'?>"
+ "\xC3\xA9",
+ XCS("utf-8"), NULL};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9");
+#else
+ const XML_Char *expected = XCS("\xc3\xa9");
+#endif
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ run_ext_character_check(text, &test_data, expected);
+}
+END_TEST
+
+/* Test that bad encodings are faulted */
+typedef struct ext_faults {
+ const char *parse_text;
+ const char *fail_text;
+ const XML_Char *encoding;
+ enum XML_Error error;
+} ExtFaults;
+
+static int XMLCALL
+external_entity_faulter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser ext_parser;
+ ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (fault->encoding != NULL) {
+ if (! XML_SetEncoding(ext_parser, fault->encoding))
+ fail("XML_SetEncoding failed");
+ }
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
+ (int)strlen(fault->parse_text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail(fault->fail_text);
+ if (XML_GetErrorCode(ext_parser) != fault->error)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+}
+
+START_TEST(test_ext_entity_bad_encoding) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtFaults fault
+ = {"<?xml encoding='iso-8859-3'?>u", "Unsupported encoding not faulted",
+ XCS("unknown"), XML_ERROR_UNKNOWN_ENCODING};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad encoding should not have been accepted");
+}
+END_TEST
+
+/* Try handing an invalid encoding to an external entity parser */
+START_TEST(test_ext_entity_bad_encoding_2) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtFaults fault
+ = {"<!ELEMENT doc (#PCDATA)*>", "Unknown encoding not faulted",
+ XCS("unknown-encoding"), XML_ERROR_UNKNOWN_ENCODING};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad encoding not faulted in external entity handler");
}
END_TEST
@@ -814,12 +1649,12 @@ END_TEST
read an external subset. This was fixed in Expat 1.95.5.
*/
START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
- char *text =
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
@@ -827,9 +1662,8 @@ END_TEST
have an external subset.
*/
START_TEST(test_wfc_undeclared_entity_no_external_subset) {
- expect_failure("<doc>&entity;</doc>",
- XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity w/out a DTD.");
+ expect_failure("<doc>&entity;</doc>", XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity w/out a DTD.");
}
END_TEST
@@ -837,55 +1671,50 @@ END_TEST
read an external subset, but have been declared standalone.
*/
START_TEST(test_wfc_undeclared_entity_standalone) {
- char *text =
- "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
"<!DOCTYPE doc SYSTEM 'foo'>\n"
"<doc>&entity;</doc>";
- expect_failure(text,
- XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity (standalone).");
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity (standalone).");
}
END_TEST
-static int XMLCALL
-external_entity_loader(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- char *text = (char *)XML_GetUserData(parser);
- XML_Parser extparser;
-
- extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (extparser == NULL)
- fail("Could not create external entity parser.");
- if ( XML_Parse(extparser, text, strlen(text), XML_TRUE)
- == XML_STATUS_ERROR) {
- xml_failure(parser);
- return XML_STATUS_ERROR;
- }
- return XML_STATUS_OK;
-}
-
/* Test that an error is reported for unknown entities if we have read
an external subset, and standalone is true.
*/
START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
- char *text =
- "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
"<!DOCTYPE doc SYSTEM 'foo'>\n"
"<doc>&entity;</doc>";
- char *foo_text =
- "<!ELEMENT doc (#PCDATA)*>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
- XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(parser, foo_text);
- XML_SetExternalEntityRefHandler(parser, external_entity_loader);
- expect_failure(text,
- XML_ERROR_UNDEFINED_ENTITY,
- "Parser did not report undefined entity (external DTD).");
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity (external DTD).");
+}
+END_TEST
+
+/* Test that external entity handling is not done if the parsing flag
+ * is set to UNLESS_STANDALONE
+ */
+START_TEST(test_entity_with_external_subset_unless_standalone) {
+ const char *text
+ = "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ENTITY entity 'bar'>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Parser did not report undefined entity");
}
END_TEST
@@ -893,59 +1722,210 @@ END_TEST
an external subset, and standalone is false.
*/
START_TEST(test_wfc_undeclared_entity_with_external_subset) {
- char *text =
- "<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc SYSTEM 'foo'>\n"
- "<doc>&entity;</doc>";
- char *foo_text =
- "<!ELEMENT doc (#PCDATA)*>";
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ run_ext_character_check(text, &test_data, XCS(""));
+}
+END_TEST
+
+/* Test that an error is reported if our NotStandalone handler fails */
+static int XMLCALL
+reject_not_standalone_handler(void *userData) {
+ UNUSED_P(userData);
+ return XML_STATUS_ERROR;
+}
- XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetUserData(parser, foo_text);
- XML_SetExternalEntityRefHandler(parser, external_entity_loader);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+START_TEST(test_not_standalone_handler_reject) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
+ expect_failure(text, XML_ERROR_NOT_STANDALONE,
+ "NotStandalone handler failed to reject");
+
+ /* Try again but without external entity handling */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
+ expect_failure(text, XML_ERROR_NOT_STANDALONE,
+ "NotStandalone handler failed to reject");
}
END_TEST
-START_TEST(test_wfc_no_recursive_entity_refs)
-{
- char *text =
- "<!DOCTYPE doc [\n"
- " <!ENTITY entity '&#38;entity;'>\n"
- "]>\n"
- "<doc>&entity;</doc>";
+/* Test that no error is reported if our NotStandalone handler succeeds */
+static int XMLCALL
+accept_not_standalone_handler(void *userData) {
+ UNUSED_P(userData);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_not_standalone_handler_accept) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
+ run_ext_character_check(text, &test_data, XCS(""));
+
+ /* Repeat wtihout the external entity handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetNotStandaloneHandler(g_parser, accept_not_standalone_handler);
+ run_character_check(text, XCS(""));
+}
+END_TEST
+
+START_TEST(test_wfc_no_recursive_entity_refs) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#38;entity;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
- expect_failure(text,
- XML_ERROR_RECURSIVE_ENTITY_REF,
- "Parser did not report recursive entity reference.");
+ expect_failure(text, XML_ERROR_RECURSIVE_ENTITY_REF,
+ "Parser did not report recursive entity reference.");
+}
+END_TEST
+
+/* Test incomplete external entities are faulted */
+START_TEST(test_ext_entity_invalid_parse) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ const ExtFaults faults[]
+ = {{"<", "Incomplete element declaration not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {"<\xe2\x82", /* First two bytes of a three-byte char */
+ "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
+ {"<tag>\xe2\x82", "Incomplete character in CDATA not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ const ExtFaults *fault = faults;
+
+ for (; fault->parse_text != NULL; fault++) {
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, (void *)fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Parser did not report external entity error");
+ XML_ParserReset(g_parser, NULL);
+ }
}
END_TEST
/* Regression test for SF bug #483514. */
-START_TEST(test_dtd_default_handling)
-{
- char *text =
- "<!DOCTYPE doc [\n"
- "<!ENTITY e SYSTEM 'http://xml.libexpat.org/e'>\n"
- "<!NOTATION n SYSTEM 'http://xml.libexpat.org/n'>\n"
- "<!ELEMENT doc EMPTY>\n"
- "<!ATTLIST doc a CDATA #IMPLIED>\n"
- "<?pi in dtd?>\n"
- "<!--comment in dtd-->\n"
- "]><doc/>";
+START_TEST(test_dtd_default_handling) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
+ "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ATTLIST doc a CDATA #IMPLIED>\n"
+ "<?pi in dtd?>\n"
+ "<!--comment in dtd-->\n"
+ "]><doc/>";
+
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
+ XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
+ run_character_check(text, XCS("\n\n\n\n\n\n\n<doc/>"));
+}
+END_TEST
- XML_SetDefaultHandler(parser, accumulate_characters);
- XML_SetDoctypeDeclHandler(parser,
- dummy_start_doctype_handler,
- dummy_end_doctype_handler);
- XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler);
- XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler);
- XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
- XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler);
- XML_SetProcessingInstructionHandler(parser, dummy_pi_handler);
- XML_SetCommentHandler(parser, dummy_comment_handler);
- run_character_check(text, "\n\n\n\n\n\n\n<doc/>");
+/* Test handling of attribute declarations */
+typedef struct AttTest {
+ const char *definition;
+ const XML_Char *element_name;
+ const XML_Char *attr_name;
+ const XML_Char *attr_type;
+ const XML_Char *default_value;
+ int is_required;
+} AttTest;
+
+static void XMLCALL
+verify_attlist_decl_handler(void *userData, const XML_Char *element_name,
+ const XML_Char *attr_name,
+ const XML_Char *attr_type,
+ const XML_Char *default_value, int is_required) {
+ AttTest *at = (AttTest *)userData;
+
+ if (xcstrcmp(element_name, at->element_name))
+ fail("Unexpected element name in attribute declaration");
+ if (xcstrcmp(attr_name, at->attr_name))
+ fail("Unexpected attribute name in attribute declaration");
+ if (xcstrcmp(attr_type, at->attr_type))
+ fail("Unexpected attribute type in attribute declaration");
+ if ((default_value == NULL && at->default_value != NULL)
+ || (default_value != NULL && at->default_value == NULL)
+ || (default_value != NULL && xcstrcmp(default_value, at->default_value)))
+ fail("Unexpected default value in attribute declaration");
+ if (is_required != at->is_required)
+ fail("Requirement mismatch in attribute declaration");
+}
+
+START_TEST(test_dtd_attr_handling) {
+ const char *prolog = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc EMPTY>\n";
+ AttTest attr_data[]
+ = {{"<!ATTLIST doc a ( one | two | three ) #REQUIRED>\n"
+ "]>"
+ "<doc a='two'/>",
+ XCS("doc"), XCS("a"),
+ XCS("(one|two|three)"), /* Extraneous spaces will be removed */
+ NULL, XML_TRUE},
+ {"<!NOTATION foo SYSTEM 'http://example.org/foo'>\n"
+ "<!ATTLIST doc a NOTATION (foo) #IMPLIED>\n"
+ "]>"
+ "<doc/>",
+ XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), NULL, XML_FALSE},
+ {"<!ATTLIST doc a NOTATION (foo) 'bar'>\n"
+ "]>"
+ "<doc/>",
+ XCS("doc"), XCS("a"), XCS("NOTATION(foo)"), XCS("bar"), XML_FALSE},
+ {"<!ATTLIST doc a CDATA '\xdb\xb2'>\n"
+ "]>"
+ "<doc/>",
+ XCS("doc"), XCS("a"), XCS("CDATA"),
+#ifdef XML_UNICODE
+ XCS("\x06f2"),
+#else
+ XCS("\xdb\xb2"),
+#endif
+ XML_FALSE},
+ {NULL, NULL, NULL, NULL, NULL, XML_FALSE}};
+ AttTest *test;
+
+ for (test = attr_data; test->definition != NULL; test++) {
+ XML_SetAttlistDeclHandler(g_parser, verify_attlist_decl_handler);
+ XML_SetUserData(g_parser, test);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)strlen(prolog),
+ XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, test->definition,
+ (int)strlen(test->definition), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ XML_ParserReset(g_parser, NULL);
+ }
}
END_TEST
@@ -955,15 +1935,14 @@ END_TEST
when namespace processing is not enabled.
(See Namespaces in XML, section 2.)
*/
-START_TEST(test_empty_ns_without_namespaces)
-{
- char *text =
- "<doc xmlns:prefix='http://www.example.com/'>\n"
- " <e xmlns:prefix=''/>\n"
- "</doc>";
-
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+START_TEST(test_empty_ns_without_namespaces) {
+ const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
+ " <e xmlns:prefix=''/>\n"
+ "</doc>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
@@ -971,113 +1950,4539 @@ END_TEST
Checks that an xmlns:prefix attribute set in an attribute's default
value isn't misinterpreted.
*/
-START_TEST(test_ns_in_attribute_default_without_namespaces)
-{
- char *text =
- "<!DOCTYPE e:element [\n"
- " <!ATTLIST e:element\n"
- " xmlns:e CDATA 'http://example.com/'>\n"
- " ]>\n"
- "<e:element/>";
-
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
-}
-END_TEST
-
-static char *long_character_data_text =
- "<?xml version='1.0' encoding='iso-8859-1'?><s>"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "012345678901234567890123456789012345678901234567890123456789"
- "</s>";
+START_TEST(test_ns_in_attribute_default_without_namespaces) {
+ const char *text = "<!DOCTYPE e:element [\n"
+ " <!ATTLIST e:element\n"
+ " xmlns:e CDATA 'http://example.org/'>\n"
+ " ]>\n"
+ "<e:element/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+static const char *long_character_data_text
+ = "<?xml version='1.0' encoding='iso-8859-1'?><s>"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "</s>";
static XML_Bool resumable = XML_FALSE;
static void
-clearing_aborting_character_handler(void *userData,
- const XML_Char *s, int len)
-{
- XML_StopParser(parser, resumable);
- XML_SetCharacterDataHandler(parser, NULL);
+clearing_aborting_character_handler(void *userData, const XML_Char *s,
+ int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_StopParser(g_parser, resumable);
+ XML_SetCharacterDataHandler(g_parser, NULL);
}
/* Regression test for SF bug #1515266: missing check of stopped
parser in doContext() 'for' loop. */
-START_TEST(test_stop_parser_between_char_data_calls)
-{
- /* The sample data must be big enough that there are two calls to
- the character data handler from within the inner "for" loop of
- the XML_TOK_DATA_CHARS case in doContent(), and the character
- handler must stop the parser and clear the character data
- handler.
- */
- char *text = long_character_data_text;
-
- XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
- resumable = XML_FALSE;
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
- xml_failure(parser);
- if (XML_GetErrorCode(parser) != XML_ERROR_ABORTED)
- xml_failure(parser);
+START_TEST(test_stop_parser_between_char_data_calls) {
+ /* The sample data must be big enough that there are two calls to
+ the character data handler from within the inner "for" loop of
+ the XML_TOK_DATA_CHARS case in doContent(), and the character
+ handler must stop the parser and clear the character data
+ handler.
+ */
+ const char *text = long_character_data_text;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
+ xml_failure(g_parser);
}
END_TEST
/* Regression test for SF bug #1515266: missing check of stopped
parser in doContext() 'for' loop. */
-START_TEST(test_suspend_parser_between_char_data_calls)
-{
- /* The sample data must be big enough that there are two calls to
- the character data handler from within the inner "for" loop of
- the XML_TOK_DATA_CHARS case in doContent(), and the character
- handler must stop the parser and clear the character data
- handler.
- */
- char *text = long_character_data_text;
+START_TEST(test_suspend_parser_between_char_data_calls) {
+ /* The sample data must be big enough that there are two calls to
+ the character data handler from within the inner "for" loop of
+ the XML_TOK_DATA_CHARS case in doContent(), and the character
+ handler must stop the parser and clear the character data
+ handler.
+ */
+ const char *text = long_character_data_text;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+ /* Try parsing directly */
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Attempt to continue parse while suspended not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ fail("Suspended parse not faulted with correct error");
+}
+END_TEST
+
+static XML_Bool abortable = XML_FALSE;
+
+static void
+parser_stop_character_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_StopParser(g_parser, resumable);
+ XML_SetCharacterDataHandler(g_parser, NULL);
+ if (! resumable) {
+ /* Check that aborting an aborted parser is faulted */
+ if (XML_StopParser(g_parser, XML_FALSE) != XML_STATUS_ERROR)
+ fail("Aborting aborted parser not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
+ xml_failure(g_parser);
+ } else if (abortable) {
+ /* Check that aborting a suspended parser works */
+ if (XML_StopParser(g_parser, XML_FALSE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ } else {
+ /* Check that suspending a suspended parser works */
+ if (XML_StopParser(g_parser, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Suspending suspended parser not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ xml_failure(g_parser);
+ }
+}
+
+/* Test repeated calls to XML_StopParser are handled correctly */
+START_TEST(test_repeated_stop_parser_between_char_data_calls) {
+ const char *text = long_character_data_text;
+
+ XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
+ resumable = XML_FALSE;
+ abortable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Failed to double-stop parser");
+
+ XML_ParserReset(g_parser, NULL);
+ XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
+ resumable = XML_TRUE;
+ abortable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ fail("Failed to double-suspend parser");
+
+ XML_ParserReset(g_parser, NULL);
+ XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
+ resumable = XML_TRUE;
+ abortable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Failed to suspend-abort parser");
+}
+END_TEST
+
+START_TEST(test_good_cdata_ascii) {
+ const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
+ const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ /* Add start and end handlers for coverage */
+ XML_SetStartCdataSectionHandler(g_parser, dummy_start_cdata_handler);
+ XML_SetEndCdataSectionHandler(g_parser, dummy_end_cdata_handler);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+
+ /* Try again, this time with a default handler */
+ XML_ParserReset(g_parser, NULL);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_good_cdata_utf16) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[hello]]></a>
+ */
+ const char text[]
+ = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
+ const XML_Char *expected = XCS("hello");
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_good_cdata_utf16_le) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[hello]]></a>
+ */
+ const char text[]
+ = "<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>\0";
+ const XML_Char *expected = XCS("hello");
+
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test UTF16 conversion of a long cdata string */
+
+/* 16 characters: handy macro to reduce visual clutter */
+#define A_TO_P_IN_UTF16 "\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P"
+
+START_TEST(test_long_cdata_utf16) {
+ /* Test data is:
+ * <?xlm version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[
+ * ABCDEFGHIJKLMNOP
+ * ]]></a>
+ */
+ const char text[]
+ = "\0<\0?\0x\0m\0l\0 "
+ "\0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0 "
+ "\0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0\x31\0\x36\0'\0?\0>"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
+ /* 64 characters per line */
+ /* clang-format off */
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16 A_TO_P_IN_UTF16
+ A_TO_P_IN_UTF16
+ /* clang-format on */
+ "\0]\0]\0>\0<\0/\0a\0>";
+ const XML_Char *expected =
+ /* clang-format off */
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP")
+ XCS("ABCDEFGHIJKLMNOP");
+ /* clang-format on */
+ CharData storage;
+ void *buffer;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ buffer = XML_GetBuffer(g_parser, sizeof(text) - 1);
+ if (buffer == NULL)
+ fail("Could not allocate parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, text, sizeof(text) - 1);
+ if (XML_ParseBuffer(g_parser, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test handling of multiple unit UTF-16 characters */
+#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
+START_TEST(test_multichar_cdata_utf16) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[{MINIM}{CROTCHET}]]></a>
+ *
+ * where {MINIM} is U+1d15e (a minim or half-note)
+ * UTF-16: 0xd834 0xdd5e
+ * UTF-8: 0xf0 0x9d 0x85 0x9e
+ * and {CROTCHET} is U+1d15f (a crotchet or quarter-note)
+ * UTF-16: 0xd834 0xdd5f
+ * UTF-8: 0xf0 0x9d 0x85 0x9f
+ */
+ const char text[] = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
+ "\xd8\x34\xdd\x5e\xd8\x34\xdd\x5f"
+ "\0]\0]\0>\0<\0/\0a\0>";
+# ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\xd834\xdd5e\xd834\xdd5f");
+# else
+ const XML_Char *expected = XCS("\xf0\x9d\x85\x9e\xf0\x9d\x85\x9f");
+# endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+#endif /* ifndef XML_MIN_SIZE */
+
+/* Test that an element name with a UTF-16 surrogate pair is rejected */
+START_TEST(test_utf16_bad_surrogate_pair) {
+ /* Test data is:
+ * <?xml version='1.0' encoding='utf-16'?>
+ * <a><![CDATA[{BADLINB}]]></a>
+ *
+ * where {BADLINB} is U+10000 (the first Linear B character)
+ * with the UTF-16 surrogate pair in the wrong order, i.e.
+ * 0xdc00 0xd800
+ */
+ const char text[] = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0["
+ "\xdc\x00\xd8\x00"
+ "\0]\0]\0>\0<\0/\0a\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Reversed UTF-16 surrogate pair not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bad_cdata) {
+ struct CaseData {
+ const char *text;
+ enum XML_Error expectedError;
+ };
+
+ struct CaseData cases[]
+ = {{"<a><", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
+ {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
+
+ {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
+
+ {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
+ {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
+ {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
+ {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
+
+ {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}};
+
+ size_t i = 0;
+ for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
+ const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
+ g_parser, cases[i].text, (int)strlen(cases[i].text), XML_TRUE);
+ const enum XML_Error actualError = XML_GetErrorCode(g_parser);
+
+ assert(actualStatus == XML_STATUS_ERROR);
+
+ if (actualError != cases[i].expectedError) {
+ char message[100];
+ sprintf(message,
+ "Expected error %d but got error %d for case %u: \"%s\"\n",
+ cases[i].expectedError, actualError, (unsigned int)i + 1,
+ cases[i].text);
+ fail(message);
+ }
+
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test failures in UTF-16 CDATA */
+#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
+START_TEST(test_bad_cdata_utf16) {
+ struct CaseData {
+ size_t text_bytes;
+ const char *text;
+ enum XML_Error expected_error;
+ };
+
+ const char prolog[] = "\0<\0?\0x\0m\0l\0"
+ " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
+ " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0"
+ "1\0"
+ "6\0'"
+ "\0?\0>\0\n"
+ "\0<\0a\0>";
+ struct CaseData cases[] = {
+ {1, "\0", XML_ERROR_UNCLOSED_TOKEN},
+ {2, "\0<", XML_ERROR_UNCLOSED_TOKEN},
+ {3, "\0<\0", XML_ERROR_UNCLOSED_TOKEN},
+ {4, "\0<\0!", XML_ERROR_UNCLOSED_TOKEN},
+ {5, "\0<\0!\0", XML_ERROR_UNCLOSED_TOKEN},
+ {6, "\0<\0!\0[", XML_ERROR_UNCLOSED_TOKEN},
+ {7, "\0<\0!\0[\0", XML_ERROR_UNCLOSED_TOKEN},
+ {8, "\0<\0!\0[\0C", XML_ERROR_UNCLOSED_TOKEN},
+ {9, "\0<\0!\0[\0C\0", XML_ERROR_UNCLOSED_TOKEN},
+ {10, "\0<\0!\0[\0C\0D", XML_ERROR_UNCLOSED_TOKEN},
+ {11, "\0<\0!\0[\0C\0D\0", XML_ERROR_UNCLOSED_TOKEN},
+ {12, "\0<\0!\0[\0C\0D\0A", XML_ERROR_UNCLOSED_TOKEN},
+ {13, "\0<\0!\0[\0C\0D\0A\0", XML_ERROR_UNCLOSED_TOKEN},
+ {14, "\0<\0!\0[\0C\0D\0A\0T", XML_ERROR_UNCLOSED_TOKEN},
+ {15, "\0<\0!\0[\0C\0D\0A\0T\0", XML_ERROR_UNCLOSED_TOKEN},
+ {16, "\0<\0!\0[\0C\0D\0A\0T\0A", XML_ERROR_UNCLOSED_TOKEN},
+ {17, "\0<\0!\0[\0C\0D\0A\0T\0A\0", XML_ERROR_UNCLOSED_TOKEN},
+ {18, "\0<\0!\0[\0C\0D\0A\0T\0A\0[", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {19, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {20, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z", XML_ERROR_UNCLOSED_CDATA_SECTION},
+ /* Now add a four-byte UTF-16 character */
+ {21, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8",
+ XML_ERROR_UNCLOSED_CDATA_SECTION},
+ {22, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34", XML_ERROR_PARTIAL_CHAR},
+ {23, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd",
+ XML_ERROR_PARTIAL_CHAR},
+ {24, "\0<\0!\0[\0C\0D\0A\0T\0A\0[\0Z\xd8\x34\xdd\x5e",
+ XML_ERROR_UNCLOSED_CDATA_SECTION}};
+ size_t i;
+
+ for (i = 0; i < sizeof(cases) / sizeof(struct CaseData); i++) {
+ enum XML_Status actual_status;
+ enum XML_Error actual_error;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, prolog, (int)sizeof(prolog) - 1,
+ XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ actual_status = _XML_Parse_SINGLE_BYTES(g_parser, cases[i].text,
+ (int)cases[i].text_bytes, XML_TRUE);
+ assert(actual_status == XML_STATUS_ERROR);
+ actual_error = XML_GetErrorCode(g_parser);
+ if (actual_error != cases[i].expected_error) {
+ char message[1024];
+
+ sprintf(message,
+ "Expected error %d (%" XML_FMT_STR "), got %d (%" XML_FMT_STR
+ ") for case %lu\n",
+ cases[i].expected_error, XML_ErrorString(cases[i].expected_error),
+ actual_error, XML_ErrorString(actual_error),
+ (long unsigned)(i + 1));
+ fail(message);
+ }
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+#endif /* ifndef XML_MIN_SIZE */
+
+static const char *long_cdata_text
+ = "<s><![CDATA["
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "012345678901234567890123456789012345678901234567890123456789"
+ "]]></s>";
+
+/* Test stopping the parser in cdata handler */
+START_TEST(test_stop_parser_between_cdata_calls) {
+ const char *text = long_cdata_text;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ resumable = XML_FALSE;
+ expect_failure(text, XML_ERROR_ABORTED, "Parse not aborted in CDATA handler");
+}
+END_TEST
+
+/* Test suspending the parser in cdata handler */
+START_TEST(test_suspend_parser_between_cdata_calls) {
+ const char *text = long_cdata_text;
+ enum XML_Status result;
+
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ resumable = XML_TRUE;
+ result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+ if (result != XML_STATUS_SUSPENDED) {
+ if (result == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ fail("Parse not suspended in CDATA handler");
+ }
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test memory allocation functions */
+START_TEST(test_memory_allocation) {
+ char *buffer = (char *)XML_MemMalloc(g_parser, 256);
+ char *p;
+
+ if (buffer == NULL) {
+ fail("Allocation failed");
+ } else {
+ /* Try writing to memory; some OSes try to cheat! */
+ buffer[0] = 'T';
+ buffer[1] = 'E';
+ buffer[2] = 'S';
+ buffer[3] = 'T';
+ buffer[4] = '\0';
+ if (strcmp(buffer, "TEST") != 0) {
+ fail("Memory not writable");
+ } else {
+ p = (char *)XML_MemRealloc(g_parser, buffer, 512);
+ if (p == NULL) {
+ fail("Reallocation failed");
+ } else {
+ /* Write again, just to be sure */
+ buffer = p;
+ buffer[0] = 'V';
+ if (strcmp(buffer, "VEST") != 0) {
+ fail("Reallocated memory not writable");
+ }
+ }
+ }
+ XML_MemFree(g_parser, buffer);
+ }
+}
+END_TEST
+
+static void XMLCALL
+record_default_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ CharData_AppendXMLChars((CharData *)userData, XCS("D"), 1);
+}
+
+static void XMLCALL
+record_cdata_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ CharData_AppendXMLChars((CharData *)userData, XCS("C"), 1);
+ XML_DefaultCurrent(g_parser);
+}
+
+static void XMLCALL
+record_cdata_nodefault_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ CharData_AppendXMLChars((CharData *)userData, XCS("c"), 1);
+}
+
+static void XMLCALL
+record_skip_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity) {
+ UNUSED_P(entityName);
+ CharData_AppendXMLChars((CharData *)userData,
+ is_parameter_entity ? XCS("E") : XCS("e"), 1);
+}
+
+/* Test XML_DefaultCurrent() passes handling on correctly */
+START_TEST(test_default_current) {
+ const char *text = "<doc>hell]</doc>";
+ const char *entity_text = "<!DOCTYPE doc [\n"
+ "<!ENTITY entity '&#37;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+ CharData storage;
+
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS("DCDCDCDCDCDD"));
+
+ /* Again, without the defaulting */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS("DcccccD"));
+
+ /* Now with an internal entity to complicate matters */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* The default handler suppresses the entity */
+ CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDDD"));
+
+ /* Again, with a skip handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ XML_SetSkippedEntityHandler(g_parser, record_skip_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* The default handler suppresses the entity */
+ CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDeD"));
+
+ /* This time, allow the entity through */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDCDD"));
+
+ /* Finally, without passing the cdata to the default handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandlerExpand(g_parser, record_default_handler);
+ XML_SetCharacterDataHandler(g_parser, record_cdata_nodefault_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, entity_text, (int)strlen(entity_text),
+ XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS("DDDDDDDDDDDDDDDDDcD"));
+}
+END_TEST
+
+/* Test DTD element parsing code paths */
+START_TEST(test_dtd_elements) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc (chapter)>\n"
+ "<!ELEMENT chapter (#PCDATA)>\n"
+ "]>\n"
+ "<doc><chapter>Wombats are go</chapter></doc>";
+
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test foreign DTD handling */
+START_TEST(test_set_foreign_dtd) {
+ const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
+ const char *text2 = "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ /* Check hash salt is passed through too */
+ XML_SetHashSalt(g_parser, 0x12345678);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ /* Add a default handler to exercise more code paths */
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Ensure that trying to set the DTD after parsing has started
+ * is faulted, even if it's the same setting.
+ */
+ if (XML_UseForeignDTD(g_parser, XML_TRUE)
+ != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
+ fail("Failed to reject late foreign DTD setting");
+ /* Ditto for the hash salt */
+ if (XML_SetHashSalt(g_parser, 0x23456789))
+ fail("Failed to reject late hash salt change");
+
+ /* Now finish the parse */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test foreign DTD handling with a failing NotStandalone handler */
+START_TEST(test_foreign_dtd_not_standalone) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetNotStandaloneHandler(g_parser, reject_not_standalone_handler);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ expect_failure(text, XML_ERROR_NOT_STANDALONE,
+ "NotStandalonehandler failed to reject");
+}
+END_TEST
+
+/* Test invalid character in a foreign DTD is faulted */
+START_TEST(test_invalid_foreign_dtd) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+ ExtFaults test_data
+ = {"$", "Dollar not faulted", NULL, XML_ERROR_INVALID_TOKEN};
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_UseForeignDTD(g_parser, XML_TRUE);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad DTD should not have been accepted");
+}
+END_TEST
+
+/* Test foreign DTD use with a doctype */
+START_TEST(test_foreign_dtd_with_doctype) {
+ const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
+ const char *text2 = "<doc>&entity;</doc>";
+ ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
+
+ /* Check hash salt is passed through too */
+ XML_SetHashSalt(g_parser, 0x12345678);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ /* Add a default handler to exercise more code paths */
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Ensure that trying to set the DTD after parsing has started
+ * is faulted, even if it's the same setting.
+ */
+ if (XML_UseForeignDTD(g_parser, XML_TRUE)
+ != XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
+ fail("Failed to reject late foreign DTD setting");
+ /* Ditto for the hash salt */
+ if (XML_SetHashSalt(g_parser, 0x23456789))
+ fail("Failed to reject late hash salt change");
+
+ /* Now finish the parse */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test XML_UseForeignDTD with no external subset present */
+static int XMLCALL
+external_entity_null_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ UNUSED_P(parser);
+ UNUSED_P(context);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_foreign_dtd_without_external_subset) {
+ const char *text = "<!DOCTYPE doc [<!ENTITY foo 'bar'>]>\n"
+ "<doc>&foo;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, NULL);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
+ XML_UseForeignDTD(g_parser, XML_TRUE);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_empty_foreign_dtd) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
+ XML_UseForeignDTD(g_parser, XML_TRUE);
+ expect_failure(text, XML_ERROR_UNDEFINED_ENTITY,
+ "Undefined entity not faulted");
+}
+END_TEST
+
+/* Test XML Base is set and unset appropriately */
+START_TEST(test_set_base) {
+ const XML_Char *old_base;
+ const XML_Char *new_base = XCS("/local/file/name.xml");
+
+ old_base = XML_GetBase(g_parser);
+ if (XML_SetBase(g_parser, new_base) != XML_STATUS_OK)
+ fail("Unable to set base");
+ if (xcstrcmp(XML_GetBase(g_parser), new_base) != 0)
+ fail("Base setting not correct");
+ if (XML_SetBase(g_parser, NULL) != XML_STATUS_OK)
+ fail("Unable to NULL base");
+ if (XML_GetBase(g_parser) != NULL)
+ fail("Base setting not nulled");
+ XML_SetBase(g_parser, old_base);
+}
+END_TEST
+
+/* Test attribute counts, indexing, etc */
+typedef struct attrInfo {
+ const XML_Char *name;
+ const XML_Char *value;
+} AttrInfo;
+
+typedef struct elementInfo {
+ const XML_Char *name;
+ int attr_count;
+ const XML_Char *id_name;
+ AttrInfo *attributes;
+} ElementInfo;
+
+static void XMLCALL
+counting_start_element_handler(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ ElementInfo *info = (ElementInfo *)userData;
+ AttrInfo *attr;
+ int count, id, i;
+
+ while (info->name != NULL) {
+ if (! xcstrcmp(name, info->name))
+ break;
+ info++;
+ }
+ if (info->name == NULL)
+ fail("Element not recognised");
+ /* The attribute count is twice what you might expect. It is a
+ * count of items in atts, an array which contains alternating
+ * attribute names and attribute values. For the naive user this
+ * is possibly a little unexpected, but it is what the
+ * documentation in expat.h tells us to expect.
+ */
+ count = XML_GetSpecifiedAttributeCount(g_parser);
+ if (info->attr_count * 2 != count) {
+ fail("Not got expected attribute count");
+ return;
+ }
+ id = XML_GetIdAttributeIndex(g_parser);
+ if (id == -1 && info->id_name != NULL) {
+ fail("ID not present");
+ return;
+ }
+ if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
+ fail("ID does not have the correct name");
+ return;
+ }
+ for (i = 0; i < info->attr_count; i++) {
+ attr = info->attributes;
+ while (attr->name != NULL) {
+ if (! xcstrcmp(atts[0], attr->name))
+ break;
+ attr++;
+ }
+ if (attr->name == NULL) {
+ fail("Attribute not recognised");
+ return;
+ }
+ if (xcstrcmp(atts[1], attr->value)) {
+ fail("Attribute has wrong value");
+ return;
+ }
+ /* Remember, two entries in atts per attribute (see above) */
+ atts += 2;
+ }
+}
+
+START_TEST(test_attributes) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc (tag)>\n"
+ "<!ATTLIST doc id ID #REQUIRED>\n"
+ "]>"
+ "<doc a='1' id='one' b='2'>"
+ "<tag c='3'/>"
+ "</doc>";
+ AttrInfo doc_info[] = {{XCS("a"), XCS("1")},
+ {XCS("b"), XCS("2")},
+ {XCS("id"), XCS("one")},
+ {NULL, NULL}};
+ AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
+ {XCS("tag"), 1, NULL, NULL},
+ {NULL, 0, NULL, NULL}};
+ info[0].attributes = doc_info;
+ info[1].attributes = tag_info;
+
+ XML_SetStartElementHandler(g_parser, counting_start_element_handler);
+ XML_SetUserData(g_parser, info);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test reset works correctly in the middle of processing an internal
+ * entity. Exercises some obscure code in XML_ParserReset().
+ */
+START_TEST(test_reset_in_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY wombat 'wom'>\n"
+ "<!ENTITY entity 'hi &wom; there'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+ XML_ParsingStatus status;
+
+ resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_SUSPENDED)
+ fail("Parsing status not SUSPENDED");
+ XML_ParserReset(g_parser, NULL);
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_INITIALIZED)
+ fail("Parsing status doesn't reset to INITIALIZED");
+}
+END_TEST
+
+/* Test that resume correctly passes through parse errors */
+START_TEST(test_resume_invalid_parse) {
+ const char *text = "<doc>Hello</doc"; /* Missing closing wedge */
+
+ resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_ResumeParser(g_parser) == XML_STATUS_OK)
+ fail("Resumed invalid parse not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_UNCLOSED_TOKEN)
+ fail("Invalid parse not correctly faulted");
+}
+END_TEST
+
+/* Test that re-suspended parses are correctly passed through */
+START_TEST(test_resume_resuspended) {
+ const char *text = "<doc>Hello<meep/>world</doc>";
+
+ resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ resumable = XML_TRUE;
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
+ fail("Resumption not suspended");
+ /* This one should succeed and finish up */
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that CDATA shows up correctly through a default handler */
+START_TEST(test_cdata_default) {
+ const char *text = "<doc><![CDATA[Hello\nworld]]></doc>";
+ const XML_Char *expected = XCS("<doc><![CDATA[Hello\nworld]]></doc>");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test resetting a subordinate parser does exactly nothing */
+static int XMLCALL
+external_entity_resetter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+ XML_ParsingStatus status;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_GetParsingStatus(ext_parser, &status);
+ if (status.parsing != XML_INITIALIZED) {
+ fail("Parsing status is not INITIALIZED");
+ return XML_STATUS_ERROR;
+ }
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(parser);
+ return XML_STATUS_ERROR;
+ }
+ XML_GetParsingStatus(ext_parser, &status);
+ if (status.parsing != XML_FINISHED) {
+ fail("Parsing status is not FINISHED");
+ return XML_STATUS_ERROR;
+ }
+ /* Check we can't parse here */
+ if (XML_Parse(ext_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Parsing when finished not faulted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_FINISHED)
+ fail("Parsing when finished faulted with wrong code");
+ XML_ParserReset(ext_parser, NULL);
+ XML_GetParsingStatus(ext_parser, &status);
+ if (status.parsing != XML_FINISHED) {
+ fail("Parsing status not still FINISHED");
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_subordinate_reset) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_resetter);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending a subordinate parser */
+
+static void XMLCALL
+entity_suspending_decl_handler(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ XML_Parser ext_parser = (XML_Parser)userData;
+
+ UNUSED_P(name);
+ if (XML_StopParser(ext_parser, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Attempting to suspend a subordinate parser not faulted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_SUSPEND_PE)
+ fail("Suspending subordinate parser get wrong code");
+ XML_SetElementDeclHandler(ext_parser, NULL);
+ XML_FreeContentModel(g_parser, model);
+}
+
+static int XMLCALL
+external_entity_suspender(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetElementDeclHandler(ext_parser, entity_suspending_decl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(ext_parser);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_subordinate_suspend) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_suspender);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending a subordinate parser from an XML declaration */
+/* Increases code coverage of the tests */
+static void XMLCALL
+entity_suspending_xdecl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ XML_Parser ext_parser = (XML_Parser)userData;
+
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ UNUSED_P(standalone);
+ XML_StopParser(ext_parser, resumable);
+ XML_SetXmlDeclHandler(ext_parser, NULL);
+}
+
+static int XMLCALL
+external_entity_suspend_xmldecl(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>";
+ XML_Parser ext_parser;
+ XML_ParsingStatus status;
+ enum XML_Status rc;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ rc = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_GetParsingStatus(ext_parser, &status);
+ if (resumable) {
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ if (status.parsing != XML_SUSPENDED)
+ fail("Ext Parsing status not SUSPENDED");
+ } else {
+ if (rc != XML_STATUS_ERROR)
+ fail("Ext parsing not aborted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
+ xml_failure(ext_parser);
+ if (status.parsing != XML_FINISHED)
+ fail("Ext Parsing status not FINISHED");
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_subordinate_xdecl_suspend) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
+ resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_subordinate_xdecl_abort) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_suspend_xmldecl);
+ resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test external entity fault handling with suspension */
+static int XMLCALL
+external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser ext_parser;
+ ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ void *buffer;
+ int parse_len = (int)strlen(fault->parse_text);
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ resumable = XML_TRUE;
+ buffer = XML_GetBuffer(ext_parser, parse_len);
+ if (buffer == NULL)
+ fail("Could not allocate parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, fault->parse_text, parse_len);
+ if (XML_ParseBuffer(ext_parser, parse_len, XML_FALSE) != XML_STATUS_SUSPENDED)
+ fail("XML declaration did not suspend");
+ if (XML_ResumeParser(ext_parser) != XML_STATUS_OK)
+ xml_failure(ext_parser);
+ if (XML_ParseBuffer(ext_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail(fault->fail_text);
+ if (XML_GetErrorCode(ext_parser) != fault->error)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+}
+
+START_TEST(test_ext_entity_invalid_suspended_parse) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtFaults faults[]
+ = {{"<?xml version='1.0' encoding='us-ascii'?><",
+ "Incomplete element declaration not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {/* First two bytes of a three-byte char */
+ "<?xml version='1.0' encoding='utf-8'?>\xe2\x82",
+ "Incomplete character not faulted", NULL, XML_ERROR_PARTIAL_CHAR},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ ExtFaults *fault;
+
+ for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser,
+ external_entity_suspending_faulter);
+ XML_SetUserData(g_parser, fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Parser did not report external entity error");
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test setting an explicit encoding */
+START_TEST(test_explicit_encoding) {
+ const char *text1 = "<doc>Hello ";
+ const char *text2 = " World</doc>";
+
+ /* Just check that we can set the encoding to NULL before starting */
+ if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
+ fail("Failed to initialise encoding to NULL");
+ /* Say we are UTF-8 */
+ if (XML_SetEncoding(g_parser, XCS("utf-8")) != XML_STATUS_OK)
+ fail("Failed to set explicit encoding");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Try to switch encodings mid-parse */
+ if (XML_SetEncoding(g_parser, XCS("us-ascii")) != XML_STATUS_ERROR)
+ fail("Allowed encoding change");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Try now the parse is over */
+ if (XML_SetEncoding(g_parser, NULL) != XML_STATUS_OK)
+ fail("Failed to unset encoding");
+}
+END_TEST
+
+/* Test handling of trailing CR (rather than newline) */
+static void XMLCALL
+cr_cdata_handler(void *userData, const XML_Char *s, int len) {
+ int *pfound = (int *)userData;
+
+ /* Internal processing turns the CR into a newline for the
+ * character data handler, but not for the default handler
+ */
+ if (len == 1 && (*s == XCS('\n') || *s == XCS('\r')))
+ *pfound = 1;
+}
+
+START_TEST(test_trailing_cr) {
+ const char *text = "<doc>\r";
+ int found_cr;
+
+ /* Try with a character handler, for code coverage */
+ XML_SetCharacterDataHandler(g_parser, cr_cdata_handler);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_cr == 0)
+ fail("Did not catch the carriage return");
+ XML_ParserReset(g_parser, NULL);
+
+ /* Now with a default handler instead */
+ XML_SetDefaultHandler(g_parser, cr_cdata_handler);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_cr == 0)
+ fail("Did not catch default carriage return");
+}
+END_TEST
+
+/* Test trailing CR in an external entity parse */
+static int XMLCALL
+external_entity_cr_catcher(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "\r";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+static int XMLCALL
+external_entity_bad_cr_catcher(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<tag>\r";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetCharacterDataHandler(ext_parser, cr_cdata_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Async entity error not caught");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
+ xml_failure(ext_parser);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_trailing_cr) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int found_cr;
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_cr_catcher);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (found_cr == 0)
+ fail("No carriage return found");
+ XML_ParserReset(g_parser, NULL);
+
+ /* Try again with a different trailing CR */
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_bad_cr_catcher);
+ XML_SetUserData(g_parser, &found_cr);
+ found_cr = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (found_cr == 0)
+ fail("No carriage return found");
+}
+END_TEST
+
+/* Test handling of trailing square bracket */
+static void XMLCALL
+rsqb_handler(void *userData, const XML_Char *s, int len) {
+ int *pfound = (int *)userData;
+
+ if (len == 1 && *s == XCS(']'))
+ *pfound = 1;
+}
+
+START_TEST(test_trailing_rsqb) {
+ const char *text8 = "<doc>]";
+ const char text16[] = "\xFF\xFE<\000d\000o\000c\000>\000]\000";
+ int found_rsqb;
+ int text8_len = (int)strlen(text8);
+
+ XML_SetCharacterDataHandler(g_parser, rsqb_handler);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text8, text8_len, XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_rsqb == 0)
+ fail("Did not catch the right square bracket");
+
+ /* Try again with a different encoding */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetCharacterDataHandler(g_parser, rsqb_handler);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
+ XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_rsqb == 0)
+ fail("Did not catch the right square bracket");
+
+ /* And finally with a default handler */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetDefaultHandler(g_parser, rsqb_handler);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text16, (int)sizeof(text16) - 1,
+ XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Failed to fault unclosed doc");
+ if (found_rsqb == 0)
+ fail("Did not catch the right square bracket");
+}
+END_TEST
+
+/* Test trailing right square bracket in an external entity parse */
+static int XMLCALL
+external_entity_rsqb_catcher(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<tag>]";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetCharacterDataHandler(ext_parser, rsqb_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Async entity error not caught");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ASYNC_ENTITY)
+ xml_failure(ext_parser);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_trailing_rsqb) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int found_rsqb;
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_rsqb_catcher);
+ XML_SetUserData(g_parser, &found_rsqb);
+ found_rsqb = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (found_rsqb == 0)
+ fail("No right square bracket found");
+}
+END_TEST
+
+/* Test CDATA handling in an external entity */
+static int XMLCALL
+external_entity_good_cdata_ascii(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
+ const XML_Char *expected = XCS("<greeting>Hello, world!</greeting>");
+ CharData storage;
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ CharData_Init(&storage);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ XML_SetUserData(ext_parser, &storage);
+ XML_SetCharacterDataHandler(ext_parser, accumulate_characters);
+
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ CharData_CheckXMLChars(&storage, expected);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_good_cdata) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_good_cdata_ascii);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test user parameter settings */
+/* Variable holding the expected handler userData */
+static void *handler_data = NULL;
+/* Count of the number of times the comment handler has been invoked */
+static int comment_count = 0;
+/* Count of the number of skipped entities */
+static int skip_count = 0;
+/* Count of the number of times the XML declaration handler is invoked */
+static int xdecl_count = 0;
+
+static void XMLCALL
+xml_decl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ if (userData != handler_data)
+ fail("User data (xml decl) not correctly set");
+ if (standalone != -1)
+ fail("Standalone not flagged as not present in XML decl");
+ xdecl_count++;
+}
+
+static void XMLCALL
+param_check_skip_handler(void *userData, const XML_Char *entityName,
+ int is_parameter_entity) {
+ UNUSED_P(entityName);
+ UNUSED_P(is_parameter_entity);
+ if (userData != handler_data)
+ fail("User data (skip) not correctly set");
+ skip_count++;
+}
+
+static void XMLCALL
+data_check_comment_handler(void *userData, const XML_Char *data) {
+ UNUSED_P(data);
+ /* Check that the userData passed through is what we expect */
+ if (userData != handler_data)
+ fail("User data (parser) not correctly set");
+ /* Check that the user data in the parser is appropriate */
+ if (XML_GetUserData(userData) != (void *)1)
+ fail("User data in parser not correctly set");
+ comment_count++;
+}
+
+static int XMLCALL
+external_entity_param_checker(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!-- Subordinate parser -->\n"
+ "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ handler_data = ext_parser;
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(parser);
+ return XML_STATUS_ERROR;
+ }
+ handler_data = parser;
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_user_parameters) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!-- Primary parse -->\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;";
+ const char *epilog = "<!-- Back to primary parser -->\n"
+ "</doc>";
+
+ comment_count = 0;
+ skip_count = 0;
+ xdecl_count = 0;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetXmlDeclHandler(g_parser, xml_decl_handler);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_param_checker);
+ XML_SetCommentHandler(g_parser, data_check_comment_handler);
+ XML_SetSkippedEntityHandler(g_parser, param_check_skip_handler);
+ XML_UseParserAsHandlerArg(g_parser);
+ XML_SetUserData(g_parser, (void *)1);
+ handler_data = g_parser;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (comment_count != 2)
+ fail("Comment handler not invoked enough times");
+ /* Ensure we can't change policy mid-parse */
+ if (XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_NEVER))
+ fail("Changed param entity parsing policy while parsing");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (comment_count != 3)
+ fail("Comment handler not invoked enough times");
+ if (skip_count != 1)
+ fail("Skip handler not invoked enough times");
+ if (xdecl_count != 1)
+ fail("XML declaration handler not invoked");
+}
+END_TEST
+
+/* Test that an explicit external entity handler argument replaces
+ * the parser as the first argument.
+ *
+ * We do not call the first parameter to the external entity handler
+ * 'parser' for once, since the first time the handler is called it
+ * will actually be a text string. We need to be able to access the
+ * global 'parser' variable to create our external entity parser from,
+ * since there are code paths we need to ensure get executed.
+ */
+static int XMLCALL
+external_entity_ref_param_checker(XML_Parser parameter, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc (#PCDATA)*>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if ((void *)parameter != handler_data)
+ fail("External entity ref handler parameter not correct");
+
+ /* Here we use the global 'parser' variable */
+ ext_parser = XML_ExternalEntityParserCreate(g_parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_ref_parameter) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
+ /* Set a handler arg that is not NULL and not parser (which is
+ * what NULL would cause to be passed.
+ */
+ XML_SetExternalEntityRefHandlerArg(g_parser, (void *)text);
+ handler_data = (void *)text;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Now try again with unset args */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_ref_param_checker);
+ XML_SetExternalEntityRefHandlerArg(g_parser, NULL);
+ handler_data = (void *)g_parser;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test the parsing of an empty string */
+START_TEST(test_empty_parse) {
+ const char *text = "<doc></doc>";
+ const char *partial = "<doc>";
+
+ if (XML_Parse(g_parser, NULL, 0, XML_FALSE) == XML_STATUS_ERROR)
+ fail("Parsing empty string faulted");
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Parsing final empty string not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_ELEMENTS)
+ fail("Parsing final empty string faulted for wrong reason");
+
+ /* Now try with valid text before the empty end */
+ XML_ParserReset(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) == XML_STATUS_ERROR)
+ fail("Parsing final empty string faulted");
+
+ /* Now try with invalid text before the empty end */
+ XML_ParserReset(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, partial, (int)strlen(partial),
+ XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Parsing final incomplete empty string not faulted");
+}
+END_TEST
+
+/* Test odd corners of the XML_GetBuffer interface */
+static enum XML_Status
+get_feature(enum XML_FeatureEnum feature_id, long *presult) {
+ const XML_Feature *feature = XML_GetFeatureList();
+
+ if (feature == NULL)
+ return XML_STATUS_ERROR;
+ for (; feature->feature != XML_FEATURE_END; feature++) {
+ if (feature->feature == feature_id) {
+ *presult = feature->value;
+ return XML_STATUS_OK;
+ }
+ }
+ return XML_STATUS_ERROR;
+}
+
+/* Having an element name longer than 1024 characters exercises some
+ * of the pool allocation code in the parser that otherwise does not
+ * get executed. The count at the end of the line is the number of
+ * characters (bytes) in the element name by that point.x
+ */
+static const char *get_buffer_test_text
+ = "<documentwitharidiculouslylongelementnametotease" /* 0x030 */
+ "aparticularcorneroftheallocationinXML_GetBuffers" /* 0x060 */
+ "othatwecanimprovethecoverageyetagain012345678901" /* 0x090 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0c0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x0f0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x120 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x150 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x180 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1b0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x1e0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x210 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x240 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x270 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2a0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x2d0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x300 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x330 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x360 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x390 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3c0 */
+ "123456789abcdef0123456789abcdef0123456789abcdef0" /* 0x3f0 */
+ "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */
+
+/* Test odd corners of the XML_GetBuffer interface */
+START_TEST(test_get_buffer_1) {
+ const char *text = get_buffer_test_text;
+ void *buffer;
+ long context_bytes;
+
+ /* Attempt to allocate a negative length buffer */
+ if (XML_GetBuffer(g_parser, -12) != NULL)
+ fail("Negative length buffer not failed");
+
+ /* Now get a small buffer and extend it past valid length */
+ buffer = XML_GetBuffer(g_parser, 1536);
+ if (buffer == NULL)
+ fail("1.5K buffer failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (XML_GetBuffer(g_parser, INT_MAX) != NULL)
+ fail("INT_MAX buffer not failed");
+
+ /* Now try extending it a more reasonable but still too large
+ * amount. The allocator in XML_GetBuffer() doubles the buffer
+ * size until it exceeds the requested amount or INT_MAX. If it
+ * exceeds INT_MAX, it rejects the request, so we want a request
+ * between INT_MAX and INT_MAX/2. A gap of 1K seems comfortable,
+ * with an extra byte just to ensure that the request is off any
+ * boundary. The request will be inflated internally by
+ * XML_CONTEXT_BYTES (if defined), so we subtract that from our
+ * request.
+ */
+ if (get_feature(XML_FEATURE_CONTEXT_BYTES, &context_bytes) != XML_STATUS_OK)
+ context_bytes = 0;
+ if (XML_GetBuffer(g_parser, INT_MAX - (context_bytes + 1025)) != NULL)
+ fail("INT_MAX- buffer not failed");
+
+ /* Now try extending it a carefully crafted amount */
+ if (XML_GetBuffer(g_parser, 1000) == NULL)
+ fail("1000 buffer failed");
+}
+END_TEST
+
+/* Test more corners of the XML_GetBuffer interface */
+START_TEST(test_get_buffer_2) {
+ const char *text = get_buffer_test_text;
+ void *buffer;
+
+ /* Now get a decent buffer */
+ buffer = XML_GetBuffer(g_parser, 1536);
+ if (buffer == NULL)
+ fail("1.5K buffer failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Extend it, to catch a different code path */
+ if (XML_GetBuffer(g_parser, 1024) == NULL)
+ fail("1024 buffer failed");
+}
+END_TEST
+
+/* Test position information macros */
+START_TEST(test_byte_info_at_end) {
+ const char *text = "<doc></doc>";
+
+ if (XML_GetCurrentByteIndex(g_parser) != -1
+ || XML_GetCurrentByteCount(g_parser) != 0)
+ fail("Byte index/count incorrect at start of parse");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* At end, the count will be zero and the index the end of string */
+ if (XML_GetCurrentByteCount(g_parser) != 0)
+ fail("Terminal byte count incorrect");
+ if (XML_GetCurrentByteIndex(g_parser) != (XML_Index)strlen(text))
+ fail("Terminal byte index incorrect");
+}
+END_TEST
+
+/* Test position information from errors */
+#define PRE_ERROR_STR "<doc></"
+#define POST_ERROR_STR "wombat></doc>"
+START_TEST(test_byte_info_at_error) {
+ const char *text = PRE_ERROR_STR POST_ERROR_STR;
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ fail("Syntax error not faulted");
+ if (XML_GetCurrentByteCount(g_parser) != 0)
+ fail("Error byte count incorrect");
+ if (XML_GetCurrentByteIndex(g_parser) != strlen(PRE_ERROR_STR))
+ fail("Error byte index incorrect");
+}
+END_TEST
+#undef PRE_ERROR_STR
+#undef POST_ERROR_STR
+
+/* Test position information in handler */
+typedef struct ByteTestData {
+ int start_element_len;
+ int cdata_len;
+ int total_string_len;
+} ByteTestData;
+
+static void
+byte_character_handler(void *userData, const XML_Char *s, int len) {
+#ifdef XML_CONTEXT_BYTES
+ int offset, size;
+ const char *buffer;
+ ByteTestData *data = (ByteTestData *)userData;
+
+ UNUSED_P(s);
+ buffer = XML_GetInputContext(g_parser, &offset, &size);
+ if (buffer == NULL)
+ fail("Failed to get context buffer");
+ if (offset != data->start_element_len)
+ fail("Context offset in unexpected position");
+ if (len != data->cdata_len)
+ fail("CDATA length reported incorrectly");
+ if (size != data->total_string_len)
+ fail("Context size is not full buffer");
+ if (XML_GetCurrentByteIndex(g_parser) != offset)
+ fail("Character byte index incorrect");
+ if (XML_GetCurrentByteCount(g_parser) != len)
+ fail("Character byte count incorrect");
+#else
+ UNUSED_P(s);
+ UNUSED_P(userData);
+ UNUSED_P(len);
+#endif
+}
+
+#define START_ELEMENT "<e>"
+#define CDATA_TEXT "Hello"
+#define END_ELEMENT "</e>"
+START_TEST(test_byte_info_at_cdata) {
+ const char *text = START_ELEMENT CDATA_TEXT END_ELEMENT;
+ int offset, size;
+ ByteTestData data;
+
+ /* Check initial context is empty */
+ if (XML_GetInputContext(g_parser, &offset, &size) != NULL)
+ fail("Unexpected context at start of parse");
+
+ data.start_element_len = (int)strlen(START_ELEMENT);
+ data.cdata_len = (int)strlen(CDATA_TEXT);
+ data.total_string_len = (int)strlen(text);
+ XML_SetCharacterDataHandler(g_parser, byte_character_handler);
+ XML_SetUserData(g_parser, &data);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE) != XML_STATUS_OK)
+ xml_failure(g_parser);
+}
+END_TEST
+#undef START_ELEMENT
+#undef CDATA_TEXT
+#undef END_ELEMENT
+
+/* Test predefined entities are correctly recognised */
+START_TEST(test_predefined_entities) {
+ const char *text = "<doc>&lt;&gt;&amp;&quot;&apos;</doc>";
+ const XML_Char *expected = XCS("<doc>&lt;&gt;&amp;&quot;&apos;</doc>");
+ const XML_Char *result = XCS("<>&\"'");
+ CharData storage;
+
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ /* run_character_check uses XML_SetCharacterDataHandler(), which
+ * unfortunately heads off a code path that we need to exercise.
+ */
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* The default handler doesn't translate the entities */
+ CharData_CheckXMLChars(&storage, expected);
+
+ /* Now try again and check the translation */
+ XML_ParserReset(g_parser, NULL);
+ run_character_check(text, result);
+}
+END_TEST
+
+/* Regression test that an invalid tag in an external parameter
+ * reference in an external DTD is correctly faulted.
+ *
+ * Only a few specific tags are legal in DTDs ignoring comments and
+ * processing instructions, all of which begin with an exclamation
+ * mark. "<el/>" is not one of them, so the parser should raise an
+ * error on encountering it.
+ */
+static int XMLCALL
+external_entity_param(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n";
+ const char *text2 = "<!ELEMENT el EMPTY>\n"
+ "<el/>\n";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Inner DTD with invalid tag not rejected");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_EXTERNAL_ENTITY_HANDLING)
+ xml_failure(ext_parser);
+ } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid tag in external param not rejected");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_SYNTAX)
+ xml_failure(ext_parser);
+ } else {
+ fail("Unknown system ID");
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+}
+
+START_TEST(test_invalid_tag_in_dtd) {
+ const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_param);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Invalid tag IN DTD external param not rejected");
+}
+END_TEST
+
+/* Test entities not quite the predefined ones are not mis-recognised */
+START_TEST(test_not_predefined_entities) {
+ const char *text[] = {"<doc>&pt;</doc>", "<doc>&amo;</doc>",
+ "<doc>&quid;</doc>", "<doc>&apod;</doc>", NULL};
+ int i = 0;
+
+ while (text[i] != NULL) {
+ expect_failure(text[i], XML_ERROR_UNDEFINED_ENTITY,
+ "Undefined entity not rejected");
+ XML_ParserReset(g_parser, NULL);
+ i++;
+ }
+}
+END_TEST
+
+/* Test conditional inclusion (IGNORE) */
+static int XMLCALL
+external_entity_load_ignore(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ignore_section) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc><e>&entity;</e></doc>";
+ const XML_Char *expected
+ = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&entity;");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetEndElementHandler(g_parser, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+static int XMLCALL
+external_entity_load_ignore_utf16(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char text[] =
+ /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
+ "<\0!\0[\0I\0G\0N\0O\0R\0E\0[\0"
+ "<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 \0"
+ "(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>\0";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ignore_section_utf16) {
+ const char text[] =
+ /* <!DOCTYPE d SYSTEM 's'> */
+ "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
+ "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n\0"
+ /* <d><e>&en;</e></d> */
+ "<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>\0";
+ const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_load_ignore_utf16);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetEndElementHandler(g_parser, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+static int XMLCALL
+external_entity_load_ignore_utf16_be(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char text[] =
+ /* <![IGNORE[<!ELEMENT e (#PCDATA)*>]]> */
+ "\0<\0!\0[\0I\0G\0N\0O\0R\0E\0["
+ "\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 \0e\0 "
+ "\0(\0#\0P\0C\0D\0A\0T\0A\0)\0*\0>\0]\0]\0>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ignore_section_utf16_be) {
+ const char text[] =
+ /* <!DOCTYPE d SYSTEM 's'> */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 "
+ "\0S\0Y\0S\0T\0E\0M\0 \0'\0s\0'\0>\0\n"
+ /* <d><e>&en;</e></d> */
+ "\0<\0d\0>\0<\0e\0>\0&\0e\0n\0;\0<\0/\0e\0>\0<\0/\0d\0>";
+ const XML_Char *expected = XCS("<![IGNORE[<!ELEMENT e (#PCDATA)*>]]>\n&en;");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetExternalEntityRefHandler(g_parser,
+ external_entity_load_ignore_utf16_be);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetStartDoctypeDeclHandler(g_parser, dummy_start_doctype_handler);
+ XML_SetEndDoctypeDeclHandler(g_parser, dummy_end_doctype_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetEndElementHandler(g_parser, dummy_end_element);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test mis-formatted conditional exclusion */
+START_TEST(test_bad_ignore_section) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc><e>&entity;</e></doc>";
+ ExtFaults faults[]
+ = {{"<![IGNORE[<!ELEM", "Broken-off declaration not faulted", NULL,
+ XML_ERROR_SYNTAX},
+ {"<![IGNORE[\x01]]>", "Invalid XML character not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN},
+ {/* FIrst two bytes of a three-byte char */
+ "<![IGNORE[\xe2\x82", "Partial XML character not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ ExtFaults *fault;
+
+ for (fault = &faults[0]; fault->parse_text != NULL; fault++) {
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Incomplete IGNORE section not failed");
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test recursive parsing */
+static int XMLCALL
+external_entity_valuer(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ enum XML_Status status;
+ enum XML_Error error;
+
+ status = _XML_Parse_SINGLE_BYTES(ext_parser, fault->parse_text,
+ (int)strlen(fault->parse_text), XML_TRUE);
+ if (fault->error == XML_ERROR_NONE) {
+ if (status == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ } else {
+ if (status != XML_STATUS_ERROR)
+ fail(fault->fail_text);
+ error = XML_GetErrorCode(ext_parser);
+ if (error != fault->error
+ && (fault->error != XML_ERROR_XML_DECL
+ || error != XML_ERROR_TEXT_DECL))
+ xml_failure(ext_parser);
+ }
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_external_entity_values) {
+ const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+ ExtFaults data_004_2[] = {
+ {"<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL, XML_ERROR_NONE},
+ {"<!ATTLIST $doc a1 CDATA 'value'>", "Invalid token not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN},
+ {"'wombat", "Unterminated string not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {"\xe2\x82", "Partial UTF-8 character not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {"<?xml version='1.0' encoding='utf-8'?>\n", NULL, NULL, XML_ERROR_NONE},
+ {"<?xml?>", "Malformed XML declaration not faulted", NULL,
+ XML_ERROR_XML_DECL},
+ {/* UTF-8 BOM */
+ "\xEF\xBB\xBF<!ATTLIST doc a1 CDATA 'value'>", NULL, NULL,
+ XML_ERROR_NONE},
+ {"<?xml version='1.0' encoding='utf-8'?>\n$",
+ "Invalid token after text declaration not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN},
+ {"<?xml version='1.0' encoding='utf-8'?>\n'wombat",
+ "Unterminated string after text decl not faulted", NULL,
+ XML_ERROR_UNCLOSED_TOKEN},
+ {"<?xml version='1.0' encoding='utf-8'?>\n\xe2\x82",
+ "Partial UTF-8 character after text decl not faulted", NULL,
+ XML_ERROR_PARTIAL_CHAR},
+ {"%e1;", "Recursive parameter entity not faulted", NULL,
+ XML_ERROR_RECURSIVE_ENTITY_REF},
+ {NULL, NULL, NULL, XML_ERROR_NONE}};
+ int i;
+
+ for (i = 0; data_004_2[i].parse_text != NULL; i++) {
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_valuer);
+ XML_SetUserData(g_parser, &data_004_2[i]);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ XML_ParserReset(g_parser, NULL);
+ }
+}
+END_TEST
+
+/* Test the recursive parse interacts with a not standalone handler */
+static int XMLCALL
+external_entity_not_standalone(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM 'bar'>\n"
+ "%e1;\n";
+ const char *text2 = "<!ATTLIST doc a1 CDATA 'value'>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (! xcstrcmp(systemId, XCS("foo"))) {
+ XML_SetNotStandaloneHandler(ext_parser, reject_not_standalone_handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Expected not standalone rejection");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_NOT_STANDALONE)
+ xml_failure(ext_parser);
+ XML_SetNotStandaloneHandler(ext_parser, NULL);
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+ } else if (! xcstrcmp(systemId, XCS("bar"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_not_standalone) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc></doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_not_standalone);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Standalone rejection not caught");
+}
+END_TEST
+
+static int XMLCALL
+external_entity_value_aborter(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM '004-2.ent'>\n"
+ "<!ENTITY % e2 '%e1;'>\n"
+ "%e1;\n";
+ const char *text2 = "<?xml version='1.0' encoding='utf-8'?>";
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL)
+ return XML_STATUS_OK;
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+ if (! xcstrcmp(systemId, XCS("004-1.ent"))) {
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text1, (int)strlen(text1), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+ }
+ if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
+ XML_SetXmlDeclHandler(ext_parser, entity_suspending_xdecl_handler);
+ XML_SetUserData(ext_parser, ext_parser);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text2, (int)strlen(text2), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Aborted parse not faulted");
+ if (XML_GetErrorCode(ext_parser) != XML_ERROR_ABORTED)
+ xml_failure(ext_parser);
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_ext_entity_value_abort) {
+ const char *text = "<!DOCTYPE doc SYSTEM '004-1.ent'>\n"
+ "<doc></doc>\n";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_value_aborter);
+ resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_bad_public_doctype) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!DOCTYPE doc PUBLIC '{BadName}' 'test'>\n"
+ "<doc></doc>";
+
+ /* Setting a handler provokes a particular code path */
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
+ dummy_end_doctype_handler);
+ expect_failure(text, XML_ERROR_PUBLICID, "Bad Public ID not failed");
+}
+END_TEST
+
+/* Test based on ibm/valid/P32/ibm32v04.xml */
+START_TEST(test_attribute_enum_value) {
+ const char *text = "<?xml version='1.0' standalone='no'?>\n"
+ "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
+ "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
+ ExtTest dtd_data
+ = {"<!ELEMENT animal (#PCDATA|a)*>\n"
+ "<!ELEMENT a EMPTY>\n"
+ "<!ATTLIST animal xml:space (default|preserve) 'preserve'>",
+ NULL, NULL};
+ const XML_Char *expected = XCS("This is a \n \n\nyellow tiger");
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetUserData(g_parser, &dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ /* An attribute list handler provokes a different code path */
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ run_ext_character_check(text, &dtd_data, expected);
+}
+END_TEST
+
+/* Slightly bizarrely, the library seems to silently ignore entity
+ * definitions for predefined entities, even when they are wrong. The
+ * language of the XML 1.0 spec is somewhat unhelpful as to what ought
+ * to happen, so this is currently treated as acceptable.
+ */
+START_TEST(test_predefined_entity_redefinition) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY apos 'foo'>\n"
+ "]>\n"
+ "<doc>&apos;</doc>";
+ run_character_check(text, XCS("'"));
+}
+END_TEST
+
+/* Test that the parser stops processing the DTD after an unresolved
+ * parameter entity is encountered.
+ */
+START_TEST(test_dtd_stop_processing) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "%foo;\n"
+ "<!ENTITY bar 'bas'>\n"
+ "]><doc/>";
+
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (dummy_handler_flags != 0)
+ fail("DTD processing still going after undefined PE");
+}
+END_TEST
+
+/* Test public notations with no system ID */
+START_TEST(test_public_notation_no_sysid) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!NOTATION note PUBLIC 'foo'>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+
+ dummy_handler_flags = 0;
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
+ fail("Notation declaration handler not called");
+}
+END_TEST
+
+static void XMLCALL
+record_element_start_handler(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(atts);
+ CharData_AppendXMLChars((CharData *)userData, name, (int)xcstrlen(name));
+}
+
+START_TEST(test_nested_groups) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc "
+ /* Sixteen elements per line */
+ "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
+ "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
+ "))))))))))))))))))))))))))))))))>\n"
+ "<!ELEMENT e EMPTY>"
+ "]>\n"
+ "<doc><e/></doc>";
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS("doce"));
+ if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler not fired");
+}
+END_TEST
+
+START_TEST(test_group_choice) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc (a|b|c)+>\n"
+ "<!ELEMENT a EMPTY>\n"
+ "<!ELEMENT b (#PCDATA)>\n"
+ "<!ELEMENT c ANY>\n"
+ "]>\n"
+ "<doc>\n"
+ "<a/>\n"
+ "<b attr='foo'>This is a foo</b>\n"
+ "<c></c>\n"
+ "</doc>\n";
+
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler flag not raised");
+}
+END_TEST
+
+static int XMLCALL
+external_entity_public(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text1 = (const char *)XML_GetUserData(parser);
+ const char *text2 = "<!ATTLIST doc a CDATA 'value'>";
+ const char *text = NULL;
+ XML_Parser ext_parser;
+ int parse_res;
+
+ UNUSED_P(base);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ if (systemId != NULL && ! xcstrcmp(systemId, XCS("http://example.org/"))) {
+ text = text1;
+ } else if (publicId != NULL && ! xcstrcmp(publicId, XCS("foo"))) {
+ text = text2;
+ } else
+ fail("Unexpected parameters to external entity parser");
+ assert(text != NULL);
+ parse_res
+ = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ return parse_res;
+}
+
+START_TEST(test_standalone_parameter_entity) {
+ const char *text = "<?xml version='1.0' standalone='yes'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/' [\n"
+ "<!ENTITY % entity '<!ELEMENT doc (#PCDATA)>'>\n"
+ "%entity;\n"
+ "]>\n"
+ "<doc></doc>";
+ char dtd_data[] = "<!ENTITY % e1 'foo'>\n";
+
+ XML_SetUserData(g_parser, dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test skipping of parameter entity in an external DTD */
+/* Derived from ibm/invalid/P69/ibm69i01.xml */
+START_TEST(test_skipped_parameter_entity) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
+ "<!ELEMENT root (#PCDATA|a)* >\n"
+ "]>\n"
+ "<root></root>";
+ ExtTest dtd_data = {"%pe2;", NULL, NULL};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetUserData(g_parser, &dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetSkippedEntityHandler(g_parser, dummy_skip_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (dummy_handler_flags != DUMMY_SKIP_HANDLER_FLAG)
+ fail("Skip handler not executed");
+}
+END_TEST
+
+/* Test recursive parameter entity definition rejected in external DTD */
+START_TEST(test_recursive_external_parameter_entity) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE root SYSTEM 'http://example.org/dtd.ent' [\n"
+ "<!ELEMENT root (#PCDATA|a)* >\n"
+ "]>\n"
+ "<root></root>";
+ ExtFaults dtd_data = {"<!ENTITY % pe2 '&#37;pe2;'>\n%pe2;",
+ "Recursive external parameter entity not faulted", NULL,
+ XML_ERROR_RECURSIVE_ENTITY_REF};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &dtd_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Recursive external parameter not spotted");
+}
+END_TEST
+
+/* Test undefined parameter entity in external entity handler */
+static int XMLCALL
+external_entity_devaluer(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 SYSTEM 'bar'>\n"
+ "%e1;\n";
+ XML_Parser ext_parser;
+ intptr_t clear_handler = (intptr_t)XML_GetUserData(parser);
+
+ UNUSED_P(base);
+ UNUSED_P(publicId);
+ if (systemId == NULL || ! xcstrcmp(systemId, XCS("bar")))
+ return XML_STATUS_OK;
+ if (xcstrcmp(systemId, XCS("foo")))
+ fail("Unexpected system ID");
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could note create external entity parser");
+ if (clear_handler)
+ XML_SetExternalEntityRefHandler(ext_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(ext_parser);
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_undefined_ext_entity_in_external_dtd) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc></doc>\n";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
+ XML_SetUserData(g_parser, (void *)(intptr_t)XML_FALSE);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Now repeat without the external entity ref handler invoking
+ * another copy of itself.
+ */
+ XML_ParserReset(g_parser, NULL);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_devaluer);
+ XML_SetUserData(g_parser, (void *)(intptr_t)XML_TRUE);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+static void XMLCALL
+aborting_xdecl_handler(void *userData, const XML_Char *version,
+ const XML_Char *encoding, int standalone) {
+ UNUSED_P(userData);
+ UNUSED_P(version);
+ UNUSED_P(encoding);
+ UNUSED_P(standalone);
+ XML_StopParser(g_parser, resumable);
+ XML_SetXmlDeclHandler(g_parser, NULL);
+}
+
+/* Test suspending the parse on receiving an XML declaration works */
+START_TEST(test_suspend_xdecl) {
+ const char *text = long_character_data_text;
+
+ XML_SetXmlDeclHandler(g_parser, aborting_xdecl_handler);
+ resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+ /* Attempt to start a new parse while suspended */
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Attempt to parse while suspended not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ fail("Suspended parse not faulted with correct error");
+}
+END_TEST
+
+/* Test aborting the parse in an epilog works */
+static void XMLCALL
+selective_aborting_default_handler(void *userData, const XML_Char *s, int len) {
+ const XML_Char *match = (const XML_Char *)userData;
+
+ if (match == NULL
+ || (xcstrlen(match) == (unsigned)len && ! xcstrncmp(match, s, len))) {
+ XML_StopParser(g_parser, resumable);
+ XML_SetDefaultHandler(g_parser, NULL);
+ }
+}
+
+START_TEST(test_abort_epilog) {
+ const char *text = "<doc></doc>\n\r\n";
+ XML_Char match[] = XCS("\r");
+
+ XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
+ XML_SetUserData(g_parser, match);
+ resumable = XML_FALSE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Abort not triggered");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_ABORTED)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test a different code path for abort in the epilog */
+START_TEST(test_abort_epilog_2) {
+ const char *text = "<doc></doc>\n";
+ XML_Char match[] = XCS("\n");
+
+ XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
+ XML_SetUserData(g_parser, match);
+ resumable = XML_FALSE;
+ expect_failure(text, XML_ERROR_ABORTED, "Abort not triggered");
+}
+END_TEST
+
+/* Test suspension from the epilog */
+START_TEST(test_suspend_epilog) {
+ const char *text = "<doc></doc>\n";
+ XML_Char match[] = XCS("\n");
+
+ XML_SetDefaultHandler(g_parser, selective_aborting_default_handler);
+ XML_SetUserData(g_parser, match);
+ resumable = XML_TRUE;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+}
+END_TEST
+
+static void XMLCALL
+suspending_end_handler(void *userData, const XML_Char *s) {
+ UNUSED_P(s);
+ XML_StopParser((XML_Parser)userData, 1);
+}
+
+START_TEST(test_suspend_in_sole_empty_tag) {
+ const char *text = "<doc/>";
+ enum XML_Status rc;
+
+ XML_SetEndElementHandler(g_parser, suspending_end_handler);
+ XML_SetUserData(g_parser, g_parser);
+ rc = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ else if (rc != XML_STATUS_SUSPENDED)
+ fail("Suspend not triggered");
+ rc = XML_ResumeParser(g_parser);
+ if (rc == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ else if (rc != XML_STATUS_OK)
+ fail("Resume failed");
+}
+END_TEST
+
+START_TEST(test_unfinished_epilog) {
+ const char *text = "<doc></doc><";
+
+ expect_failure(text, XML_ERROR_UNCLOSED_TOKEN,
+ "Incomplete epilog entry not faulted");
+}
+END_TEST
+
+START_TEST(test_partial_char_in_epilog) {
+ const char *text = "<doc></doc>\xe2\x82";
+
+ /* First check that no fault is raised if the parse is not finished */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ /* Now check that it is faulted once we finish */
+ if (XML_ParseBuffer(g_parser, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Partial character in epilog not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_PARTIAL_CHAR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_hash_collision) {
+ /* For full coverage of the lookup routine, we need to ensure a
+ * hash collision even though we can only tell that we have one
+ * through breakpoint debugging or coverage statistics. The
+ * following will cause a hash collision on machines with a 64-bit
+ * long type; others will have to experiment. The full coverage
+ * tests invoked from qa.sh usually provide a hash collision, but
+ * not always. This is an attempt to provide insurance.
+ */
+#define COLLIDING_HASH_SALT (unsigned long)_SIP_ULL(0xffffffffU, 0xff99fc90U)
+ const char *text
+ = "<doc>\n"
+ "<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
+ "<b1></b1><b2 attr='foo'>This is a foo</b2><b3></b3><b4></b4>\n"
+ "<b5></b5><b6></b6><b7></b7><b8></b8>\n"
+ "<c1/><c2/><c3/><c4/><c5/><c6/><c7/><c8/>\n"
+ "<d1/><d2/><d3/><d4/><d5/><d6/><d7/>\n"
+ "<d8>This triggers the table growth and collides with b2</d8>\n"
+ "</doc>\n";
+
+ XML_SetHashSalt(g_parser, COLLIDING_HASH_SALT);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+#undef COLLIDING_HASH_SALT
+
+/* Test resuming a parse suspended in entity substitution */
+static void XMLCALL
+start_element_suspender(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(atts);
+ if (! xcstrcmp(name, XCS("suspend")))
+ XML_StopParser(g_parser, XML_TRUE);
+ if (! xcstrcmp(name, XCS("abort")))
+ XML_StopParser(g_parser, XML_FALSE);
+}
+
+START_TEST(test_suspend_resume_internal_entity) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ENTITY foo '<suspend>Hi<suspend>Ho</suspend></suspend>'>\n"
+ "]>\n"
+ "<doc>&foo;</doc>\n";
+ const XML_Char *expected1 = XCS("Hi");
+ const XML_Char *expected2 = XCS("HiHo");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, start_element_suspender);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS(""));
+ if (XML_ResumeParser(g_parser) != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected1);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected2);
+}
+END_TEST
+
+/* Test syntax error is caught at parse resumption */
+START_TEST(test_resume_entity_with_syntax_error) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY foo '<suspend>Hi</wombat>'>\n"
+ "]>\n"
+ "<doc>&foo;</doc>\n";
+
+ XML_SetStartElementHandler(g_parser, start_element_suspender);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
+ fail("Syntax error in entity not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_TAG_MISMATCH)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test suspending and resuming in a parameter entity substitution */
+static void XMLCALL
+element_decl_suspender(void *userData, const XML_Char *name,
+ XML_Content *model) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ XML_StopParser(g_parser, XML_TRUE);
+ XML_FreeContentModel(g_parser, model);
+}
+
+START_TEST(test_suspend_resume_parameter_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY % foo '<!ELEMENT doc (#PCDATA)*>'>\n"
+ "%foo;\n"
+ "]>\n"
+ "<doc>Hello, world</doc>";
+ const XML_Char *expected = XCS("Hello, world");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetElementDeclHandler(g_parser, element_decl_suspender);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, XCS(""));
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test attempting to use parser after an error is faulted */
+START_TEST(test_restart_on_error) {
+ const char *text = "<$doc><doc></doc>";
+
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid tag name not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+ if (XML_Parse(g_parser, NULL, 0, XML_TRUE) != XML_STATUS_ERROR)
+ fail("Restarting invalid parse not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that angle brackets in an attribute default value are faulted */
+START_TEST(test_reject_lt_in_attribute_value) {
+ const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '<bar>'>]>\n"
+ "<doc></doc>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad attribute default not faulted");
+}
+END_TEST
+
+START_TEST(test_reject_unfinished_param_in_att_value) {
+ const char *text = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '&foo'>]>\n"
+ "<doc></doc>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad attribute default not faulted");
+}
+END_TEST
+
+START_TEST(test_trailing_cr_in_att_value) {
+ const char *text = "<doc a='value\r'/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Try parsing a general entity within a parameter entity in a
+ * standalone internal DTD. Covers a corner case in the parser.
+ */
+START_TEST(test_standalone_internal_entity) {
+ const char *text = "<?xml version='1.0' standalone='yes' ?>\n"
+ "<!DOCTYPE doc [\n"
+ " <!ELEMENT doc (#PCDATA)>\n"
+ " <!ENTITY % pe '<!ATTLIST doc att2 CDATA \"&ge;\">'>\n"
+ " <!ENTITY ge 'AttDefaultValue'>\n"
+ " %pe;\n"
+ "]>\n"
+ "<doc att2='any'/>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that a reference to an unknown external entity is skipped */
+START_TEST(test_skipped_external_entity) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc></doc>\n";
+ ExtTest test_data = {"<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e2 '%e1;'>\n",
+ NULL, NULL};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test a different form of unknown external entity */
+typedef struct ext_hdlr_data {
+ const char *parse_text;
+ XML_ExternalEntityRefHandler handler;
+} ExtHdlrData;
+
+static int XMLCALL
+external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser);
+ XML_Parser ext_parser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser.");
+ /* Use the requested entity parser for further externals */
+ XML_SetExternalEntityRefHandler(ext_parser, test_data->handler);
+ if (_XML_Parse_SINGLE_BYTES(ext_parser, test_data->parse_text,
+ (int)strlen(test_data->parse_text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(ext_parser);
+ }
+
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_skipped_null_loaded_ext_entity) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
+ "<doc />";
+ ExtHdlrData test_data
+ = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
+ "<!ENTITY % pe2 '%pe1;'>\n"
+ "%pe2;\n",
+ external_entity_null_loader};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_skipped_unloaded_ext_entity) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
+ "<doc />";
+ ExtHdlrData test_data
+ = {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
+ "<!ENTITY % pe2 '%pe1;'>\n"
+ "%pe2;\n",
+ NULL};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_oneshot_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that a parameter entity value ending with a carriage return
+ * has it translated internally into a newline.
+ */
+START_TEST(test_param_entity_with_trailing_cr) {
+#define PARAM_ENTITY_NAME "pe"
+#define PARAM_ENTITY_CORE_VALUE "<!ATTLIST doc att CDATA \"default\">"
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc/>";
+ ExtTest test_data
+ = {"<!ENTITY % " PARAM_ENTITY_NAME " '" PARAM_ENTITY_CORE_VALUE "\r'>\n"
+ "%" PARAM_ENTITY_NAME ";\n",
+ NULL, NULL};
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
+ XML_SetEntityDeclHandler(g_parser, param_entity_match_handler);
+ entity_name_to_match = XCS(PARAM_ENTITY_NAME);
+ entity_value_to_match = XCS(PARAM_ENTITY_CORE_VALUE) XCS("\n");
+ entity_match_flag = ENTITY_MATCH_NOT_FOUND;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (entity_match_flag == ENTITY_MATCH_FAIL)
+ fail("Parameter entity CR->NEWLINE conversion failed");
+ else if (entity_match_flag == ENTITY_MATCH_NOT_FOUND)
+ fail("Parameter entity not parsed");
+}
+#undef PARAM_ENTITY_NAME
+#undef PARAM_ENTITY_CORE_VALUE
+END_TEST
+
+START_TEST(test_invalid_character_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#x110000;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_BAD_CHAR_REF,
+ "Out of range character reference not faulted");
+}
+END_TEST
+
+START_TEST(test_invalid_character_entity_2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#xg0;'>\n"
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Out of range character reference not faulted");
+}
+END_TEST
+
+START_TEST(test_invalid_character_entity_3) {
+ const char text[] =
+ /* <!DOCTYPE doc [\n */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
+ /* U+0E04 = KHO KHWAI
+ * U+0E08 = CHO CHAN */
+ /* <!ENTITY entity '&\u0e04\u0e08;'>\n */
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0n\0t\0i\0t\0y\0 "
+ "\0'\0&\x0e\x04\x0e\x08\0;\0'\0>\0\n"
+ /* ]>\n */
+ "\0]\0>\0\n"
+ /* <doc>&entity;</doc> */
+ "\0<\0d\0o\0c\0>\0&\0e\0n\0t\0i\0t\0y\0;\0<\0/\0d\0o\0c\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid start of entity name not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_UNDEFINED_ENTITY)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_invalid_character_entity_4) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY entity '&#1114112;'>\n" /* = &#x110000 */
+ "]>\n"
+ "<doc>&entity;</doc>";
+
+ expect_failure(text, XML_ERROR_BAD_CHAR_REF,
+ "Out of range character reference not faulted");
+}
+END_TEST
+
+/* Test that processing instructions are picked up by a default handler */
+START_TEST(test_pi_handled_in_default) {
+ const char *text = "<?test processing instruction?>\n<doc/>";
+ const XML_Char *expected = XCS("<?test processing instruction?>\n<doc/>");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that comments are picked up by a default handler */
+START_TEST(test_comment_handled_in_default) {
+ const char *text = "<!-- This is a comment -->\n<doc/>";
+ const XML_Char *expected = XCS("<!-- This is a comment -->\n<doc/>");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test PIs that look almost but not quite like XML declarations */
+static void XMLCALL
+accumulate_pi_characters(void *userData, const XML_Char *target,
+ const XML_Char *data) {
+ CharData *storage = (CharData *)userData;
+
+ CharData_AppendXMLChars(storage, target, -1);
+ CharData_AppendXMLChars(storage, XCS(": "), 2);
+ CharData_AppendXMLChars(storage, data, -1);
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
+}
+
+START_TEST(test_pi_yml) {
+ const char *text = "<?yml something like data?><doc/>";
+ const XML_Char *expected = XCS("yml: something like data\n");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_pi_xnl) {
+ const char *text = "<?xnl nothing like data?><doc/>";
+ const XML_Char *expected = XCS("xnl: nothing like data\n");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_pi_xmm) {
+ const char *text = "<?xmm everything like data?><doc/>";
+ const XML_Char *expected = XCS("xmm: everything like data\n");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_pi) {
+ const char text[] =
+ /* <?{KHO KHWAI}{CHO CHAN}?>
+ * where {KHO KHWAI} = U+0E04
+ * and {CHO CHAN} = U+0E08
+ */
+ "<\0?\0\x04\x0e\x08\x0e?\0>\0"
+ /* <q/> */
+ "<\0q\0/\0>\0";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x0e04\x0e08: \n");
+#else
+ const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_be_pi) {
+ const char text[] =
+ /* <?{KHO KHWAI}{CHO CHAN}?>
+ * where {KHO KHWAI} = U+0E04
+ * and {CHO CHAN} = U+0E08
+ */
+ "\0<\0?\x0e\x04\x0e\x08\0?\0>"
+ /* <q/> */
+ "\0<\0q\0/\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x0e04\x0e08: \n");
+#else
+ const XML_Char *expected = XCS("\xe0\xb8\x84\xe0\xb8\x88: \n");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetProcessingInstructionHandler(g_parser, accumulate_pi_characters);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that comments can be picked up and translated */
+static void XMLCALL
+accumulate_comment(void *userData, const XML_Char *data) {
+ CharData *storage = (CharData *)userData;
+
+ CharData_AppendXMLChars(storage, data, -1);
+}
+
+START_TEST(test_utf16_be_comment) {
+ const char text[] =
+ /* <!-- Comment A --> */
+ "\0<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0A\0 \0-\0-\0>\0\n"
+ /* <doc/> */
+ "\0<\0d\0o\0c\0/\0>";
+ const XML_Char *expected = XCS(" Comment A ");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetCommentHandler(g_parser, accumulate_comment);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_le_comment) {
+ const char text[] =
+ /* <!-- Comment B --> */
+ "<\0!\0-\0-\0 \0C\0o\0m\0m\0e\0n\0t\0 \0B\0 \0-\0-\0>\0\n\0"
+ /* <doc/> */
+ "<\0d\0o\0c\0/\0>\0";
+ const XML_Char *expected = XCS(" Comment B ");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetCommentHandler(g_parser, accumulate_comment);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that the unknown encoding handler with map entries that expect
+ * conversion but no conversion function is faulted
+ */
+static int XMLCALL
+failing_converter(void *data, const char *s) {
+ UNUSED_P(data);
+ UNUSED_P(s);
+ /* Always claim to have failed */
+ return -1;
+}
+
+static int XMLCALL
+prefix_converter(void *data, const char *s) {
+ UNUSED_P(data);
+ /* If the first byte is 0xff, raise an error */
+ if (s[0] == (char)-1)
+ return -1;
+ /* Just add the low bits of the first byte to the second */
+ return (s[1] + (s[0] & 0x7f)) & 0x01ff;
+}
+
+static int XMLCALL
+MiscEncodingHandler(void *data, const XML_Char *encoding, XML_Encoding *info) {
+ int i;
+ int high_map = -2; /* Assume a 2-byte sequence */
+
+ if (! xcstrcmp(encoding, XCS("invalid-9"))
+ || ! xcstrcmp(encoding, XCS("ascii-like"))
+ || ! xcstrcmp(encoding, XCS("invalid-len"))
+ || ! xcstrcmp(encoding, XCS("invalid-a"))
+ || ! xcstrcmp(encoding, XCS("invalid-surrogate"))
+ || ! xcstrcmp(encoding, XCS("invalid-high")))
+ high_map = -1;
+
+ for (i = 0; i < 128; ++i)
+ info->map[i] = i;
+ for (; i < 256; ++i)
+ info->map[i] = high_map;
+
+ /* If required, put an invalid value in the ASCII entries */
+ if (! xcstrcmp(encoding, XCS("invalid-9")))
+ info->map[9] = 5;
+ /* If required, have a top-bit set character starts a 5-byte sequence */
+ if (! xcstrcmp(encoding, XCS("invalid-len")))
+ info->map[0x81] = -5;
+ /* If required, make a top-bit set character a valid ASCII character */
+ if (! xcstrcmp(encoding, XCS("invalid-a")))
+ info->map[0x82] = 'a';
+ /* If required, give a top-bit set character a forbidden value,
+ * what would otherwise be the first of a surrogate pair.
+ */
+ if (! xcstrcmp(encoding, XCS("invalid-surrogate")))
+ info->map[0x83] = 0xd801;
+ /* If required, give a top-bit set character too high a value */
+ if (! xcstrcmp(encoding, XCS("invalid-high")))
+ info->map[0x84] = 0x010101;
+
+ info->data = data;
+ info->release = NULL;
+ if (! xcstrcmp(encoding, XCS("failing-conv")))
+ info->convert = failing_converter;
+ else if (! xcstrcmp(encoding, XCS("prefix-conv")))
+ info->convert = prefix_converter;
+ else
+ info->convert = NULL;
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_missing_encoding_conversion_fn) {
+ const char *text = "<?xml version='1.0' encoding='no-conv'?>\n"
+ "<doc>\x81</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ /* MiscEncodingHandler sets up an encoding with every top-bit-set
+ * character introducing a two-byte sequence. For this, it
+ * requires a convert function. The above function call doesn't
+ * pass one through, so when BadEncodingHandler actually gets
+ * called it should supply an invalid encoding.
+ */
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Encoding with missing convert() not faulted");
+}
+END_TEST
+
+START_TEST(test_failing_encoding_conversion_fn) {
+ const char *text = "<?xml version='1.0' encoding='failing-conv'?>\n"
+ "<doc>\x81</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ /* BadEncodingHandler sets up an encoding with every top-bit-set
+ * character introducing a two-byte sequence. For this, it
+ * requires a convert function. The above function call passes
+ * one that insists all possible sequences are invalid anyway.
+ */
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Encoding with failing convert() not faulted");
+}
+END_TEST
+
+/* Test unknown encoding conversions */
+START_TEST(test_unknown_encoding_success) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ /* Equivalent to <eoc>Hello, world</eoc> */
+ "<\x81\x64\x80oc>Hello, world</\x81\x64\x80oc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ run_character_check(text, XCS("Hello, world"));
+}
+END_TEST
+
+/* Test bad name character in unknown encoding */
+START_TEST(test_unknown_encoding_bad_name) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<\xff\x64oc>Hello, world</\xff\x64oc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad name start in unknown encoding not faulted");
+}
+END_TEST
+
+/* Test bad mid-name character in unknown encoding */
+START_TEST(test_unknown_encoding_bad_name_2) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<d\xffoc>Hello, world</d\xffoc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad name in unknown encoding not faulted");
+}
+END_TEST
+
+/* Test element name that is long enough to fill the conversion buffer
+ * in an unknown encoding, finishing with an encoded character.
+ */
+START_TEST(test_unknown_encoding_long_name_1) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>"
+ "Hi"
+ "</abcdefghabcdefghabcdefghijkl\x80m\x80n\x80o\x80p>";
+ const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test element name that is long enough to fill the conversion buffer
+ * in an unknown encoding, finishing with an simple character.
+ */
+START_TEST(test_unknown_encoding_long_name_2) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<abcdefghabcdefghabcdefghijklmnop>"
+ "Hi"
+ "</abcdefghabcdefghabcdefghijklmnop>";
+ const XML_Char *expected = XCS("abcdefghabcdefghabcdefghijklmnop");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_invalid_unknown_encoding) {
+ const char *text = "<?xml version='1.0' encoding='invalid-9'?>\n"
+ "<doc>Hello world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_ascii_encoding_ok) {
+ const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ run_character_check(text, XCS("Hello, world"));
+}
+END_TEST
+
+START_TEST(test_unknown_ascii_encoding_fail) {
+ const char *text = "<?xml version='1.0' encoding='ascii-like'?>\n"
+ "<doc>Hello, \x80 world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_length) {
+ const char *text = "<?xml version='1.0' encoding='invalid-len'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_topbit) {
+ const char *text = "<?xml version='1.0' encoding='invalid-a'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_surrogate) {
+ const char *text = "<?xml version='1.0' encoding='invalid-surrogate'?>\n"
+ "<doc>Hello, \x82 world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_high) {
+ const char *text = "<?xml version='1.0' encoding='invalid-high'?>\n"
+ "<doc>Hello, world</doc>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_UNKNOWN_ENCODING,
+ "Invalid unknown encoding not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_invalid_attr_value) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<doc attr='\xff\x30'/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid attribute valid not faulted");
+}
+END_TEST
+
+/* Test an external entity parser set to use latin-1 detects UTF-16
+ * BOMs correctly.
+ */
+enum ee_parse_flags { EE_PARSE_NONE = 0x00, EE_PARSE_FULL_BUFFER = 0x01 };
+
+typedef struct ExtTest2 {
+ const char *parse_text;
+ int parse_len;
+ const XML_Char *encoding;
+ CharData *storage;
+ enum ee_parse_flags flags;
+} ExtTest2;
+
+static int XMLCALL
+external_entity_loader2(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser);
+ XML_Parser extparser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (extparser == NULL)
+ fail("Coulr not create external entity parser");
+ if (test_data->encoding != NULL) {
+ if (! XML_SetEncoding(extparser, test_data->encoding))
+ fail("XML_SetEncoding() ignored for external entity");
+ }
+ if (test_data->flags & EE_PARSE_FULL_BUFFER) {
+ if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
+ XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(extparser);
+ }
+ } else if (_XML_Parse_SINGLE_BYTES(extparser, test_data->parse_text,
+ test_data->parse_len, XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(extparser);
+ }
+
+ XML_ParserFree(extparser);
+ return XML_STATUS_OK;
+}
+
+/* Test that UTF-16 BOM does not select UTF-16 given explicit encoding */
+static void XMLCALL
+ext2_accumulate_characters(void *userData, const XML_Char *s, int len) {
+ ExtTest2 *test_data = (ExtTest2 *)userData;
+ accumulate_characters(test_data->storage, s, len);
+}
+
+START_TEST(test_ext_entity_latin1_utf16le_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00ff\x00feL ");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ext_entity_latin1_utf16be_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_NONE};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00fe\x00ff L");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = XCS("\xc3\xbe\xc3\xbf L");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Parsing the full buffer rather than a byte at a time makes a
+ * difference to the encoding scanning code, so repeat the above tests
+ * without breaking them down by byte.
+ */
+START_TEST(test_ext_entity_latin1_utf16le_bom2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xff\xfe\x4c\x20", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00ff\x00feL ");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = XCS("\xc3\xbf\xc3\xbeL ");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ext_entity_latin1_utf16be_bom2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {/* If UTF-16, 0xfeff is the BOM and 0x204c is black left bullet */
+ /* If Latin-1, 0xff = Y-diaeresis, 0xfe = lowercase thorn,
+ * 0x4c = L and 0x20 is a space
+ */
+ "\xfe\xff\x20\x4c", 4, XCS("iso-8859-1"), NULL, EE_PARSE_FULL_BUFFER};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00fe\x00ff L");
+#else
+ /* In UTF-8, y-diaeresis is 0xc3 0xbf, lowercase thorn is 0xc3 0xbe */
+ const XML_Char *expected = "\xc3\xbe\xc3\xbf L";
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test little-endian UTF-16 given an explicit big-endian encoding */
+START_TEST(test_ext_entity_utf16_be) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {"<\0e\0/\0>\0", 8, XCS("utf-16be"), NULL, EE_PARSE_NONE};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
+#else
+ const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
+ "\xe6\x94\x80" /* U+6500 */
+ "\xe2\xbc\x80" /* U+2F00 */
+ "\xe3\xb8\x80"); /* U+3E00 */
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test big-endian UTF-16 given an explicit little-endian encoding */
+START_TEST(test_ext_entity_utf16_le) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {"\0<\0e\0/\0>", 8, XCS("utf-16le"), NULL, EE_PARSE_NONE};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x3c00\x6500\x2f00\x3e00");
+#else
+ const XML_Char *expected = XCS("\xe3\xb0\x80" /* U+3C00 */
+ "\xe6\x94\x80" /* U+6500 */
+ "\xe2\xbc\x80" /* U+2F00 */
+ "\xe3\xb8\x80"); /* U+3E00 */
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test little-endian UTF-16 given no explicit encoding.
+ * The existing default encoding (UTF-8) is assumed to hold without a
+ * BOM to contradict it, so the entity value will in fact provoke an
+ * error because 0x00 is not a valid XML character. We parse the
+ * whole buffer in one go rather than feeding it in byte by byte to
+ * exercise different code paths in the initial scanning routines.
+ */
+typedef struct ExtFaults2 {
+ const char *parse_text;
+ int parse_len;
+ const char *fail_text;
+ const XML_Char *encoding;
+ enum XML_Error error;
+} ExtFaults2;
+
+static int XMLCALL
+external_entity_faulter2(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser);
+ XML_Parser extparser;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (extparser == NULL)
+ fail("Could not create external entity parser");
+ if (test_data->encoding != NULL) {
+ if (! XML_SetEncoding(extparser, test_data->encoding))
+ fail("XML_SetEncoding() ignored for external entity");
+ }
+ if (XML_Parse(extparser, test_data->parse_text, test_data->parse_len,
+ XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail(test_data->fail_text);
+ if (XML_GetErrorCode(extparser) != test_data->error)
+ xml_failure(extparser);
+
+ XML_ParserFree(extparser);
+ return XML_STATUS_ERROR;
+}
+
+START_TEST(test_ext_entity_utf16_unknown) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtFaults2 test_data
+ = {"a\0b\0c\0", 6, "Invalid character in entity not faulted", NULL,
+ XML_ERROR_INVALID_TOKEN};
+
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter2);
+ XML_SetUserData(g_parser, &test_data);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Invalid character should not have been accepted");
+}
+END_TEST
+
+/* Test not-quite-UTF-8 BOM (0xEF 0xBB 0xBF) */
+START_TEST(test_ext_entity_utf8_non_bom) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtTest2 test_data
+ = {"\xef\xbb\x80", /* Arabic letter DAD medial form, U+FEC0 */
+ 3, NULL, NULL, EE_PARSE_NONE};
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\xfec0");
+#else
+ const XML_Char *expected = XCS("\xef\xbb\x80");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that UTF-8 in a CDATA section is correctly passed through */
+START_TEST(test_utf8_in_cdata_section) {
+ const char *text = "<doc><![CDATA[one \xc3\xa9 two]]></doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("one \x00e9 two");
+#else
+ const XML_Char *expected = XCS("one \xc3\xa9 two");
+#endif
+
+ run_character_check(text, expected);
+}
+END_TEST
+
+/* Test that little-endian UTF-16 in a CDATA section is handled */
+START_TEST(test_utf8_in_cdata_section_2) {
+ const char *text = "<doc><![CDATA[\xc3\xa9]\xc3\xa9two]]></doc>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e9]\x00e9two");
+#else
+ const XML_Char *expected = XCS("\xc3\xa9]\xc3\xa9two");
+#endif
+
+ run_character_check(text, expected);
+}
+END_TEST
+
+/* Test trailing spaces in elements are accepted */
+static void XMLCALL
+record_element_end_handler(void *userData, const XML_Char *name) {
+ CharData *storage = (CharData *)userData;
+
+ CharData_AppendXMLChars(storage, XCS("/"), 1);
+ CharData_AppendXMLChars(storage, name, -1);
+}
+
+START_TEST(test_trailing_spaces_in_elements) {
+ const char *text = "<doc >Hi</doc >";
+ const XML_Char *expected = XCS("doc/doc");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetElementHandler(g_parser, record_element_start_handler,
+ record_element_end_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_attribute) {
+ const char text[] =
+ /* <d {KHO KHWAI}{CHO CHAN}='a'/>
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ "<\0d\0 \0\x04\x0e\x08\x0e=\0'\0a\0'\0/\0>\0";
+ const XML_Char *expected = XCS("a");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_utf16_second_attr) {
+ /* <d a='1' {KHO KHWAI}{CHO CHAN}='2'/>
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ const char text[] = "<\0d\0 \0a\0=\0'\0\x31\0'\0 \0"
+ "\x04\x0e\x08\x0e=\0'\0\x32\0'\0/\0>\0";
+ const XML_Char *expected = XCS("1");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_attr_after_solidus) {
+ const char *text = "<doc attr1='a' / attr2='b'>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN, "Misplaced / not faulted");
+}
+END_TEST
+
+static void XMLCALL
+accumulate_entity_decl(void *userData, const XML_Char *entityName,
+ int is_parameter_entity, const XML_Char *value,
+ int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ CharData *storage = (CharData *)userData;
+
+ UNUSED_P(is_parameter_entity);
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ UNUSED_P(notationName);
+ CharData_AppendXMLChars(storage, entityName, -1);
+ CharData_AppendXMLChars(storage, XCS("="), 1);
+ CharData_AppendXMLChars(storage, value, value_length);
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
+}
+
+START_TEST(test_utf16_pe) {
+ /* <!DOCTYPE doc [
+ * <!ENTITY % {KHO KHWAI}{CHO CHAN} '<!ELEMENT doc (#PCDATA)>'>
+ * %{KHO KHWAI}{CHO CHAN};
+ * ]>
+ * <doc></doc>
+ *
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ const char text[] = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0\n"
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \x0e\x04\x0e\x08\0 "
+ "\0'\0<\0!\0E\0L\0E\0M\0E\0N\0T\0 "
+ "\0d\0o\0c\0 \0(\0#\0P\0C\0D\0A\0T\0A\0)\0>\0'\0>\0\n"
+ "\0%\x0e\x04\x0e\x08\0;\0\n"
+ "\0]\0>\0\n"
+ "\0<\0d\0o\0c\0>\0<\0/\0d\0o\0c\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x0e04\x0e08=<!ELEMENT doc (#PCDATA)>\n");
+#else
+ const XML_Char *expected
+ = XCS("\xe0\xb8\x84\xe0\xb8\x88=<!ELEMENT doc (#PCDATA)>\n");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetEntityDeclHandler(g_parser, accumulate_entity_decl);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that duff attribute description keywords are rejected */
+START_TEST(test_bad_attr_desc_keyword) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attr CDATA #!IMPLIED>\n"
+ "]>\n"
+ "<doc />";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Bad keyword !IMPLIED not faulted");
+}
+END_TEST
+
+/* Test that an invalid attribute description keyword consisting of
+ * UTF-16 characters with their top bytes non-zero are correctly
+ * faulted
+ */
+START_TEST(test_bad_attr_desc_keyword_utf16) {
+ /* <!DOCTYPE d [
+ * <!ATTLIST d a CDATA #{KHO KHWAI}{CHO CHAN}>
+ * ]><d/>
+ *
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ * and {CHO CHAN} = U+0E08 = 0xe0 0xb8 0x88 in UTF-8
+ */
+ const char text[]
+ = "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
+ "\0<\0!\0A\0T\0T\0L\0I\0S\0T\0 \0d\0 \0a\0 \0C\0D\0A\0T\0A\0 "
+ "\0#\x0e\x04\x0e\x08\0>\0\n"
+ "\0]\0>\0<\0d\0/\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid UTF16 attribute keyword not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that invalid syntax in a <!DOCTYPE> is rejected. Do this
+ * using prefix-encoding (see above) to trigger specific code paths
+ */
+START_TEST(test_bad_doctype) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<!DOCTYPE doc [ \x80\x44 ]><doc/>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Invalid bytes in DOCTYPE not faulted");
+}
+END_TEST
- XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
- resumable = XML_TRUE;
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_SUSPENDED)
- xml_failure(parser);
- if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
- xml_failure(parser);
+START_TEST(test_bad_doctype_utf16) {
+ const char text[] =
+ /* <!DOCTYPE doc [ \x06f2 ]><doc/>
+ *
+ * U+06F2 = EXTENDED ARABIC-INDIC DIGIT TWO, a valid number
+ * (name character) but not a valid letter (name start character)
+ */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0o\0c\0 \0[\0 "
+ "\x06\xf2"
+ "\0 \0]\0>\0<\0d\0o\0c\0/\0>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Invalid bytes in DOCTYPE not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SYNTAX)
+ xml_failure(g_parser);
}
END_TEST
+START_TEST(test_bad_doctype_plus) {
+ const char *text = "<!DOCTYPE 1+ [ <!ENTITY foo 'bar'> ]>\n"
+ "<1+>&foo;</1+>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "'+' in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_bad_doctype_star) {
+ const char *text = "<!DOCTYPE 1* [ <!ENTITY foo 'bar'> ]>\n"
+ "<1*>&foo;</1*>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "'*' in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_bad_doctype_query) {
+ const char *text = "<!DOCTYPE 1? [ <!ENTITY foo 'bar'> ]>\n"
+ "<1?>&foo;</1?>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "'?' in document name not faulted");
+}
+END_TEST
+
+START_TEST(test_unknown_encoding_bad_ignore) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>"
+ "<!DOCTYPE doc SYSTEM 'foo'>"
+ "<doc><e>&entity;</e></doc>";
+ ExtFaults fault = {"<![IGNORE[<!ELEMENT \xffG (#PCDATA)*>]]>",
+ "Invalid character not faulted", XCS("prefix-conv"),
+ XML_ERROR_INVALID_TOKEN};
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ XML_SetUserData(g_parser, &fault);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Bad IGNORE section with unknown encoding not failed");
+}
+END_TEST
+
+START_TEST(test_entity_in_utf16_be_attr) {
+ const char text[] =
+ /* <e a='&#228; &#x00E4;'></e> */
+ "\0<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 "
+ "\0&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e4 \x00e4");
+#else
+ const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_entity_in_utf16_le_attr) {
+ const char text[] =
+ /* <e a='&#228; &#x00E4;'></e> */
+ "<\0e\0 \0a\0=\0'\0&\0#\0\x32\0\x32\0\x38\0;\0 \0"
+ "&\0#\0x\0\x30\0\x30\0E\0\x34\0;\0'\0>\0<\0/\0e\0>\0";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("\x00e4 \x00e4");
+#else
+ const XML_Char *expected = XCS("\xc3\xa4 \xc3\xa4");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_entity_public_utf16_be) {
+ const char text[] =
+ /* <!DOCTYPE d [ */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n"
+ /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 "
+ "\0'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n"
+ /* %e; */
+ "\0%\0e\0;\0\n"
+ /* ]> */
+ "\0]\0>\0\n"
+ /* <d>&j;</d> */
+ "\0<\0d\0>\0&\0j\0;\0<\0/\0d\0>";
+ ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
+ "\0<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>",
+ 34, NULL, NULL, EE_PARSE_NONE};
+ const XML_Char *expected = XCS("baz");
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_entity_public_utf16_le) {
+ const char text[] =
+ /* <!DOCTYPE d [ */
+ "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
+ /* <!ENTITY % e PUBLIC 'foo' 'bar.ent'> */
+ "<\0!\0E\0N\0T\0I\0T\0Y\0 \0%\0 \0e\0 \0P\0U\0B\0L\0I\0C\0 \0"
+ "'\0f\0o\0o\0'\0 \0'\0b\0a\0r\0.\0e\0n\0t\0'\0>\0\n\0"
+ /* %e; */
+ "%\0e\0;\0\n\0"
+ /* ]> */
+ "]\0>\0\n\0"
+ /* <d>&j;</d> */
+ "<\0d\0>\0&\0j\0;\0<\0/\0d\0>\0";
+ ExtTest2 test_data = {/* <!ENTITY j 'baz'> */
+ "<\0!\0E\0N\0T\0I\0T\0Y\0 \0j\0 \0'\0b\0a\0z\0'\0>\0",
+ 34, NULL, NULL, EE_PARSE_NONE};
+ const XML_Char *expected = XCS("baz");
+ CharData storage;
+
+ CharData_Init(&storage);
+ test_data.storage = &storage;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_loader2);
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetCharacterDataHandler(g_parser, ext2_accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+/* Test that a doctype with neither an internal nor external subset is
+ * faulted
+ */
+START_TEST(test_short_doctype) {
+ const char *text = "<!DOCTYPE doc></doc>";
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "DOCTYPE without subset not rejected");
+}
+END_TEST
+
+START_TEST(test_short_doctype_2) {
+ const char *text = "<!DOCTYPE doc PUBLIC></doc>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "DOCTYPE without Public ID not rejected");
+}
+END_TEST
+
+START_TEST(test_short_doctype_3) {
+ const char *text = "<!DOCTYPE doc SYSTEM></doc>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "DOCTYPE without System ID not rejected");
+}
+END_TEST
+
+START_TEST(test_long_doctype) {
+ const char *text = "<!DOCTYPE doc PUBLIC 'foo' 'bar' 'baz'></doc>";
+ expect_failure(text, XML_ERROR_SYNTAX, "DOCTYPE with extra ID not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_entity) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY foo PUBLIC>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+/* Test unquoted value is faulted */
+START_TEST(test_bad_entity_2) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY % foo bar>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_entity_3) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY % foo PUBLIC>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Parameter ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_entity_4) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY % foo SYSTEM>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Parameter ENTITY without Public ID is not rejected");
+}
+END_TEST
+
+START_TEST(test_bad_notation) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!NOTATION n SYSTEM>\n"
+ "]>\n"
+ "<doc/>";
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Notation without System ID is not rejected");
+}
+END_TEST
+
+/* Test for issue #11, wrongly suppressed default handler */
+typedef struct default_check {
+ const XML_Char *expected;
+ const int expectedLen;
+ XML_Bool seen;
+} DefaultCheck;
+
+static void XMLCALL
+checking_default_handler(void *userData, const XML_Char *s, int len) {
+ DefaultCheck *data = (DefaultCheck *)userData;
+ int i;
+
+ for (i = 0; data[i].expected != NULL; i++) {
+ if (data[i].expectedLen == len
+ && ! memcmp(data[i].expected, s, len * sizeof(XML_Char))) {
+ data[i].seen = XML_TRUE;
+ break;
+ }
+ }
+}
+
+START_TEST(test_default_doctype_handler) {
+ const char *text = "<!DOCTYPE doc PUBLIC 'pubname' 'test.dtd' [\n"
+ " <!ENTITY foo 'bar'>\n"
+ "]>\n"
+ "<doc>&foo;</doc>";
+ DefaultCheck test_data[] = {{XCS("'pubname'"), 9, XML_FALSE},
+ {XCS("'test.dtd'"), 10, XML_FALSE},
+ {NULL, 0, XML_FALSE}};
+ int i;
+
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetDefaultHandler(g_parser, checking_default_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ for (i = 0; test_data[i].expected != NULL; i++)
+ if (! test_data[i].seen)
+ fail("Default handler not run for public !DOCTYPE");
+}
+END_TEST
+
+START_TEST(test_empty_element_abort) {
+ const char *text = "<abort/>";
+
+ XML_SetStartElementHandler(g_parser, start_element_suspender);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Expected to error on abort");
+}
+END_TEST
/*
* Namespaces tests.
*/
static void
-namespace_setup(void)
-{
- parser = XML_ParserCreateNS(NULL, ' ');
- if (parser == NULL)
- fail("Parser not created.");
+namespace_setup(void) {
+ g_parser = XML_ParserCreateNS(NULL, XCS(' '));
+ if (g_parser == NULL)
+ fail("Parser not created.");
}
static void
-namespace_teardown(void)
-{
- basic_teardown();
+namespace_teardown(void) {
+ basic_teardown();
}
/* Check that an element name and attribute name match the expected values.
@@ -1085,20 +6490,23 @@ namespace_teardown(void)
provided as the userData argument; the first is the expected
element name, and the second is the expected attribute name.
*/
+static int triplet_start_flag = XML_FALSE;
+static int triplet_end_flag = XML_FALSE;
+
static void XMLCALL
triplet_start_checker(void *userData, const XML_Char *name,
- const XML_Char **atts)
-{
- char **elemstr = (char **)userData;
- char buffer[1024];
- if (strcmp(elemstr[0], name) != 0) {
- sprintf(buffer, "unexpected start string: '%s'", name);
- fail(buffer);
- }
- if (strcmp(elemstr[1], atts[0]) != 0) {
- sprintf(buffer, "unexpected attribute string: '%s'", atts[0]);
- fail(buffer);
- }
+ const XML_Char **atts) {
+ XML_Char **elemstr = (XML_Char **)userData;
+ char buffer[1024];
+ if (xcstrcmp(elemstr[0], name) != 0) {
+ sprintf(buffer, "unexpected start string: '%" XML_FMT_STR "'", name);
+ fail(buffer);
+ }
+ if (xcstrcmp(elemstr[1], atts[0]) != 0) {
+ sprintf(buffer, "unexpected attribute string: '%" XML_FMT_STR "'", atts[0]);
+ fail(buffer);
+ }
+ triplet_start_flag = XML_TRUE;
}
/* Check that the element name passed to the end-element handler matches
@@ -1106,410 +6514,5124 @@ triplet_start_checker(void *userData, const XML_Char *name,
in an array of strings passed as the userData argument.
*/
static void XMLCALL
-triplet_end_checker(void *userData, const XML_Char *name)
-{
- char **elemstr = (char **)userData;
- if (strcmp(elemstr[0], name) != 0) {
- char buffer[1024];
- sprintf(buffer, "unexpected end string: '%s'", name);
- fail(buffer);
- }
+triplet_end_checker(void *userData, const XML_Char *name) {
+ XML_Char **elemstr = (XML_Char **)userData;
+ if (xcstrcmp(elemstr[0], name) != 0) {
+ char buffer[1024];
+ sprintf(buffer, "unexpected end string: '%" XML_FMT_STR "'", name);
+ fail(buffer);
+ }
+ triplet_end_flag = XML_TRUE;
}
-START_TEST(test_return_ns_triplet)
-{
- char *text =
- "<foo:e xmlns:foo='http://expat.sf.net/' bar:a='12'\n"
- " xmlns:bar='http://expat.sf.net/'></foo:e>";
- char *elemstr[] = {
- "http://expat.sf.net/ e foo",
- "http://expat.sf.net/ a bar"
- };
- XML_SetReturnNSTriplet(parser, XML_TRUE);
- XML_SetUserData(parser, elemstr);
- XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+START_TEST(test_return_ns_triplet) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>";
+ const char *epilog = "</foo:e>";
+ const XML_Char *elemstr[]
+ = {XCS("http://example.org/ e foo"), XCS("http://example.org/ a bar")};
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ XML_SetNamespaceDeclHandler(g_parser, dummy_start_namespace_decl_handler,
+ dummy_end_namespace_decl_handler);
+ triplet_start_flag = XML_FALSE;
+ triplet_end_flag = XML_FALSE;
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (! triplet_start_flag)
+ fail("triplet_start_checker not invoked");
+ /* Check that unsetting "return triplets" fails while still parsing */
+ XML_SetReturnNSTriplet(g_parser, XML_FALSE);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, epilog, (int)strlen(epilog), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (! triplet_end_flag)
+ fail("triplet_end_checker not invoked");
+ if (dummy_handler_flags
+ != (DUMMY_START_NS_DECL_HANDLER_FLAG | DUMMY_END_NS_DECL_HANDLER_FLAG))
+ fail("Namespace handlers not called");
}
END_TEST
static void XMLCALL
overwrite_start_checker(void *userData, const XML_Char *name,
- const XML_Char **atts)
-{
- CharData *storage = (CharData *) userData;
- CharData_AppendString(storage, "start ");
- CharData_AppendXMLChars(storage, name, -1);
- while (*atts != NULL) {
- CharData_AppendString(storage, "\nattribute ");
- CharData_AppendXMLChars(storage, *atts, -1);
- atts += 2;
- }
- CharData_AppendString(storage, "\n");
+ const XML_Char **atts) {
+ CharData *storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("start "), 6);
+ CharData_AppendXMLChars(storage, name, -1);
+ while (*atts != NULL) {
+ CharData_AppendXMLChars(storage, XCS("\nattribute "), 11);
+ CharData_AppendXMLChars(storage, *atts, -1);
+ atts += 2;
+ }
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
}
static void XMLCALL
-overwrite_end_checker(void *userData, const XML_Char *name)
-{
- CharData *storage = (CharData *) userData;
- CharData_AppendString(storage, "end ");
- CharData_AppendXMLChars(storage, name, -1);
- CharData_AppendString(storage, "\n");
+overwrite_end_checker(void *userData, const XML_Char *name) {
+ CharData *storage = (CharData *)userData;
+ CharData_AppendXMLChars(storage, XCS("end "), 4);
+ CharData_AppendXMLChars(storage, name, -1);
+ CharData_AppendXMLChars(storage, XCS("\n"), 1);
}
static void
-run_ns_tagname_overwrite_test(char *text, char *result)
-{
- CharData storage;
- CharData_Init(&storage);
- XML_SetUserData(parser, &storage);
- XML_SetElementHandler(parser,
- overwrite_start_checker, overwrite_end_checker);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
- CharData_CheckString(&storage, result);
+run_ns_tagname_overwrite_test(const char *text, const XML_Char *result) {
+ CharData storage;
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetElementHandler(g_parser, overwrite_start_checker,
+ overwrite_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, result);
}
/* Regression test for SF bug #566334. */
-START_TEST(test_ns_tagname_overwrite)
-{
- char *text =
- "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
- " <n:f n:attr='foo'/>\n"
- " <n:g n:attr2='bar'/>\n"
- "</n:e>";
- char *result =
- "start http://xml.libexpat.org/ e\n"
- "start http://xml.libexpat.org/ f\n"
- "attribute http://xml.libexpat.org/ attr\n"
- "end http://xml.libexpat.org/ f\n"
- "start http://xml.libexpat.org/ g\n"
- "attribute http://xml.libexpat.org/ attr2\n"
- "end http://xml.libexpat.org/ g\n"
- "end http://xml.libexpat.org/ e\n";
- run_ns_tagname_overwrite_test(text, result);
+START_TEST(test_ns_tagname_overwrite) {
+ const char *text = "<n:e xmlns:n='http://example.org/'>\n"
+ " <n:f n:attr='foo'/>\n"
+ " <n:g n:attr2='bar'/>\n"
+ "</n:e>";
+ const XML_Char *result = XCS("start http://example.org/ e\n")
+ XCS("start http://example.org/ f\n")
+ XCS("attribute http://example.org/ attr\n")
+ XCS("end http://example.org/ f\n")
+ XCS("start http://example.org/ g\n")
+ XCS("attribute http://example.org/ attr2\n")
+ XCS("end http://example.org/ g\n")
+ XCS("end http://example.org/ e\n");
+ run_ns_tagname_overwrite_test(text, result);
}
END_TEST
/* Regression test for SF bug #566334. */
-START_TEST(test_ns_tagname_overwrite_triplet)
-{
- char *text =
- "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
- " <n:f n:attr='foo'/>\n"
- " <n:g n:attr2='bar'/>\n"
- "</n:e>";
- char *result =
- "start http://xml.libexpat.org/ e n\n"
- "start http://xml.libexpat.org/ f n\n"
- "attribute http://xml.libexpat.org/ attr n\n"
- "end http://xml.libexpat.org/ f n\n"
- "start http://xml.libexpat.org/ g n\n"
- "attribute http://xml.libexpat.org/ attr2 n\n"
- "end http://xml.libexpat.org/ g n\n"
- "end http://xml.libexpat.org/ e n\n";
- XML_SetReturnNSTriplet(parser, XML_TRUE);
- run_ns_tagname_overwrite_test(text, result);
+START_TEST(test_ns_tagname_overwrite_triplet) {
+ const char *text = "<n:e xmlns:n='http://example.org/'>\n"
+ " <n:f n:attr='foo'/>\n"
+ " <n:g n:attr2='bar'/>\n"
+ "</n:e>";
+ const XML_Char *result = XCS("start http://example.org/ e n\n")
+ XCS("start http://example.org/ f n\n")
+ XCS("attribute http://example.org/ attr n\n")
+ XCS("end http://example.org/ f n\n")
+ XCS("start http://example.org/ g n\n")
+ XCS("attribute http://example.org/ attr2 n\n")
+ XCS("end http://example.org/ g n\n")
+ XCS("end http://example.org/ e n\n");
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ run_ns_tagname_overwrite_test(text, result);
}
END_TEST
-
/* Regression test for SF bug #620343. */
static void XMLCALL
-start_element_fail(void *userData,
- const XML_Char *name, const XML_Char **atts)
-{
- /* We should never get here. */
- fail("should never reach start_element_fail()");
+start_element_fail(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ UNUSED_P(atts);
+
+ /* We should never get here. */
+ fail("should never reach start_element_fail()");
}
static void XMLCALL
-start_ns_clearing_start_element(void *userData,
- const XML_Char *prefix,
- const XML_Char *uri)
-{
- XML_SetStartElementHandler((XML_Parser) userData, NULL);
+start_ns_clearing_start_element(void *userData, const XML_Char *prefix,
+ const XML_Char *uri) {
+ UNUSED_P(prefix);
+ UNUSED_P(uri);
+ XML_SetStartElementHandler((XML_Parser)userData, NULL);
}
-START_TEST(test_start_ns_clears_start_element)
-{
- /* This needs to use separate start/end tags; using the empty tag
- syntax doesn't cause the problematic path through Expat to be
- taken.
- */
- char *text = "<e xmlns='http://xml.libexpat.org/'></e>";
-
- XML_SetStartElementHandler(parser, start_element_fail);
- XML_SetStartNamespaceDeclHandler(parser, start_ns_clearing_start_element);
- XML_UseParserAsHandlerArg(parser);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+START_TEST(test_start_ns_clears_start_element) {
+ /* This needs to use separate start/end tags; using the empty tag
+ syntax doesn't cause the problematic path through Expat to be
+ taken.
+ */
+ const char *text = "<e xmlns='http://example.org/'></e>";
+
+ XML_SetStartElementHandler(g_parser, start_element_fail);
+ XML_SetStartNamespaceDeclHandler(g_parser, start_ns_clearing_start_element);
+ XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
+ XML_UseParserAsHandlerArg(g_parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
}
END_TEST
/* Regression test for SF bug #616863. */
static int XMLCALL
-external_entity_handler(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
- char *text;
- XML_Parser p2;
-
- if (callno == 1)
- text = ("<!ELEMENT doc (e+)>\n"
- "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
- "<!ELEMENT e EMPTY>\n");
- else
- text = ("<?xml version='1.0' encoding='us-ascii'?>"
- "<e/>");
-
- XML_SetUserData(parser, (void *) callno);
- p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
- if (XML_Parse(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) {
- xml_failure(p2);
- return 0;
+external_entity_handler(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
+ const char *text;
+ XML_Parser p2;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if (callno == 1)
+ text = ("<!ELEMENT doc (e+)>\n"
+ "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
+ "<!ELEMENT e EMPTY>\n");
+ else
+ text = ("<?xml version='1.0' encoding='us-ascii'?>"
+ "<e/>");
+
+ XML_SetUserData(parser, (void *)callno);
+ p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (_XML_Parse_SINGLE_BYTES(p2, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(p2);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(p2);
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_default_ns_from_ext_subset_and_ext_ge) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/ns1'>\n"
+ "&en;\n"
+ "</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_handler);
+ /* We actually need to set this handler to tickle this bug. */
+ XML_SetStartElementHandler(g_parser, dummy_start_element);
+ XML_SetUserData(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test #1 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_1) {
+ const char *text = "<doc xmlns:prefix='http://example.org/'>\n"
+ " <e xmlns:prefix=''/>\n"
+ "</doc>";
+
+ expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
+ "Did not report re-setting namespace"
+ " URI with prefix to ''.");
+}
+END_TEST
+
+/* Regression test #2 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_2) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<docelem xmlns:pre=''/>";
+
+ expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
+ "Did not report setting namespace URI with prefix to ''.");
+}
+END_TEST
+
+/* Regression test #3 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_3) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ELEMENT doc EMPTY>\n"
+ " <!ATTLIST doc\n"
+ " xmlns:prefix CDATA ''>\n"
+ "]>\n"
+ "<doc/>";
+
+ expect_failure(text, XML_ERROR_UNDECLARING_PREFIX,
+ "Didn't report attr default setting NS w/ prefix to ''.");
+}
+END_TEST
+
+/* Regression test #4 for SF bug #673791. */
+START_TEST(test_ns_prefix_with_empty_uri_4) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ELEMENT prefix:doc EMPTY>\n"
+ " <!ATTLIST prefix:doc\n"
+ " xmlns:prefix CDATA 'http://example.org/'>\n"
+ "]>\n"
+ "<prefix:doc/>";
+ /* Packaged info expected by the end element handler;
+ the weird structuring lets us re-use the triplet_end_checker()
+ function also used for another test. */
+ const XML_Char *elemstr[] = {XCS("http://example.org/ doc prefix")};
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetEndElementHandler(g_parser, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test with non-xmlns prefix */
+START_TEST(test_ns_unbound_prefix) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ELEMENT prefix:doc EMPTY>\n"
+ " <!ATTLIST prefix:doc\n"
+ " notxmlns:prefix CDATA 'http://example.org/'>\n"
+ "]>\n"
+ "<prefix:doc/>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Unbound prefix incorrectly passed");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_UNBOUND_PREFIX)
+ xml_failure(g_parser);
+}
+END_TEST
+
+START_TEST(test_ns_default_with_empty_uri) {
+ const char *text = "<doc xmlns='http://example.org/'>\n"
+ " <e xmlns=''/>\n"
+ "</doc>";
+ /* Add some handlers to exercise extra code paths */
+ XML_SetStartNamespaceDeclHandler(g_parser,
+ dummy_start_namespace_decl_handler);
+ XML_SetEndNamespaceDeclHandler(g_parser, dummy_end_namespace_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #692964: two prefixes for one namespace. */
+START_TEST(test_ns_duplicate_attrs_diff_prefixes) {
+ const char *text = "<doc xmlns:a='http://example.org/a'\n"
+ " xmlns:b='http://example.org/a'\n"
+ " a:a='v' b:a='v' />";
+ expect_failure(text, XML_ERROR_DUPLICATE_ATTRIBUTE,
+ "did not report multiple attributes with same URI+name");
+}
+END_TEST
+
+START_TEST(test_ns_duplicate_hashes) {
+ /* The hash of an attribute is calculated as the hash of its URI
+ * concatenated with a space followed by its name (after the
+ * colon). We wish to generate attributes with the same hash
+ * value modulo the attribute table size so that we can check that
+ * the attribute hash table works correctly. The attribute hash
+ * table size will be the smallest power of two greater than the
+ * number of attributes, but at least eight. There is
+ * unfortunately no programmatic way of getting the hash or the
+ * table size at user level, but the test code coverage percentage
+ * will drop if the hashes cease to point to the same row.
+ *
+ * The cunning plan is to have few enough attributes to have a
+ * reliable table size of 8, and have the single letter attribute
+ * names be 8 characters apart, producing a hash which will be the
+ * same modulo 8.
+ */
+ const char *text = "<doc xmlns:a='http://example.org/a'\n"
+ " a:a='v' a:i='w' />";
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Regression test for SF bug #695401: unbound prefix. */
+START_TEST(test_ns_unbound_prefix_on_attribute) {
+ const char *text = "<doc a:attr=''/>";
+ expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
+ "did not report unbound prefix on attribute");
+}
+END_TEST
+
+/* Regression test for SF bug #695401: unbound prefix. */
+START_TEST(test_ns_unbound_prefix_on_element) {
+ const char *text = "<a:doc/>";
+ expect_failure(text, XML_ERROR_UNBOUND_PREFIX,
+ "did not report unbound prefix on element");
+}
+END_TEST
+
+/* Test that the parsing status is correctly reset by XML_ParserReset().
+ * We usE test_return_ns_triplet() for our example parse to improve
+ * coverage of tidying up code executed.
+ */
+START_TEST(test_ns_parser_reset) {
+ XML_ParsingStatus status;
+
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_INITIALIZED)
+ fail("parsing status doesn't start INITIALIZED");
+ test_return_ns_triplet();
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_FINISHED)
+ fail("parsing status doesn't end FINISHED");
+ XML_ParserReset(g_parser, NULL);
+ XML_GetParsingStatus(g_parser, &status);
+ if (status.parsing != XML_INITIALIZED)
+ fail("parsing status doesn't reset to INITIALIZED");
+}
+END_TEST
+
+/* Test that long element names with namespaces are handled correctly */
+START_TEST(test_ns_long_element) {
+ const char *text
+ = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
+ " xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</foo:thisisalongenoughelementnametotriggerareallocation>";
+ const XML_Char *elemstr[]
+ = {XCS("http://example.org/")
+ XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
+ XCS("http://example.org/ a bar")};
+
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test mixed population of prefixed and unprefixed attributes */
+START_TEST(test_ns_mixed_prefix_atts) {
+ const char *text = "<e a='12' bar:b='13'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</e>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test having a long namespaced element name inside a short one.
+ * This exercises some internal buffer reallocation that is shared
+ * across elements with the same namespace URI.
+ */
+START_TEST(test_ns_extend_uri_buffer) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/'>"
+ " <foo:thisisalongenoughnametotriggerallocationaction"
+ " foo:a='12' />"
+ "</foo:e>";
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test that xmlns is correctly rejected as an attribute in the xmlns
+ * namespace, but not in other namespaces
+ */
+START_TEST(test_ns_reserved_attributes) {
+ const char *text1
+ = "<foo:e xmlns:foo='http://example.org/' xmlns:xmlns='12' />";
+ const char *text2
+ = "<foo:e xmlns:foo='http://example.org/' foo:xmlns='12' />";
+ expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XMLNS,
+ "xmlns not rejected as an attribute");
+ XML_ParserReset(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test more reserved attributes */
+START_TEST(test_ns_reserved_attributes_2) {
+ const char *text1 = "<foo:e xmlns:foo='http://example.org/'"
+ " xmlns:xml='http://example.org/' />";
+ const char *text2
+ = "<foo:e xmlns:foo='http://www.w3.org/XML/1998/namespace' />";
+ const char *text3 = "<foo:e xmlns:foo='http://www.w3.org/2000/xmlns/' />";
+
+ expect_failure(text1, XML_ERROR_RESERVED_PREFIX_XML,
+ "xml not rejected as an attribute");
+ XML_ParserReset(g_parser, NULL);
+ expect_failure(text2, XML_ERROR_RESERVED_NAMESPACE_URI,
+ "Use of w3.org URL not faulted");
+ XML_ParserReset(g_parser, NULL);
+ expect_failure(text3, XML_ERROR_RESERVED_NAMESPACE_URI,
+ "Use of w3.org xmlns URL not faulted");
+}
+END_TEST
+
+/* Test string pool handling of namespace names of 2048 characters */
+/* Exercises a particular string pool growth path */
+START_TEST(test_ns_extremely_long_prefix) {
+ /* C99 compilers are only required to support 4095-character
+ * strings, so the following needs to be split in two to be safe
+ * for all compilers.
+ */
+ const char *text1
+ = "<doc "
+ /* 64 character on each line */
+ /* ...gives a total length of 2048 */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":a='12'";
+ const char *text2
+ = " xmlns:"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "='foo'\n>"
+ "</doc>";
+
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+/* Test unknown encoding handlers in namespace setup */
+START_TEST(test_ns_unknown_encoding_success) {
+ const char *text = "<?xml version='1.0' encoding='prefix-conv'?>\n"
+ "<foo:e xmlns:foo='http://example.org/'>Hi</foo:e>";
+
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ run_character_check(text, XCS("Hi"));
+}
+END_TEST
+
+/* Test that too many colons are rejected */
+START_TEST(test_ns_double_colon) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' foo:a:b='bar' />";
+ const enum XML_Status status
+ = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+#ifdef XML_NS
+ if ((status == XML_STATUS_OK)
+ || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
+ fail("Double colon in attribute name not faulted"
+ " (despite active namespace support)");
+ }
+#else
+ if (status != XML_STATUS_OK) {
+ fail("Double colon in attribute name faulted"
+ " (despite inactive namespace support");
+ }
+#endif
+}
+END_TEST
+
+START_TEST(test_ns_double_colon_element) {
+ const char *text = "<foo:bar:e xmlns:foo='http://example.org/' />";
+ const enum XML_Status status
+ = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
+#ifdef XML_NS
+ if ((status == XML_STATUS_OK)
+ || (XML_GetErrorCode(g_parser) != XML_ERROR_INVALID_TOKEN)) {
+ fail("Double colon in element name not faulted"
+ " (despite active namespace support)");
+ }
+#else
+ if (status != XML_STATUS_OK) {
+ fail("Double colon in element name faulted"
+ " (despite inactive namespace support");
+ }
+#endif
+}
+END_TEST
+
+/* Test that non-name characters after a colon are rejected */
+START_TEST(test_ns_bad_attr_leafname) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' foo:?ar='baz' />";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character in leafname not faulted");
+}
+END_TEST
+
+START_TEST(test_ns_bad_element_leafname) {
+ const char *text = "<foo:?oc xmlns:foo='http://example.org/' />";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character in element leafname not faulted");
+}
+END_TEST
+
+/* Test high-byte-set UTF-16 characters are valid in a leafname */
+START_TEST(test_ns_utf16_leafname) {
+ const char text[] =
+ /* <n:e xmlns:n='URI' n:{KHO KHWAI}='a' />
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ */
+ "<\0n\0:\0e\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0 \0"
+ "n\0:\0\x04\x0e=\0'\0a\0'\0 \0/\0>\0";
+ const XML_Char *expected = XCS("a");
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, accumulate_attribute);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ns_utf16_element_leafname) {
+ const char text[] =
+ /* <n:{KHO KHWAI} xmlns:n='URI'/>
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ */
+ "\0<\0n\0:\x0e\x04\0 \0x\0m\0l\0n\0s\0:\0n\0=\0'\0U\0R\0I\0'\0/\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("URI \x0e04");
+#else
+ const XML_Char *expected = XCS("URI \xe0\xb8\x84");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetStartElementHandler(g_parser, start_element_event_handler);
+ XML_SetUserData(g_parser, &storage);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ns_utf16_doctype) {
+ const char text[] =
+ /* <!DOCTYPE foo:{KHO KHWAI} [ <!ENTITY bar 'baz'> ]>\n
+ * where {KHO KHWAI} = U+0E04 = 0xe0 0xb8 0x84 in UTF-8
+ */
+ "\0<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0f\0o\0o\0:\x0e\x04\0 "
+ "\0[\0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0b\0a\0r\0 \0'\0b\0a\0z\0'\0>\0 "
+ "\0]\0>\0\n"
+ /* <foo:{KHO KHWAI} xmlns:foo='URI'>&bar;</foo:{KHO KHWAI}> */
+ "\0<\0f\0o\0o\0:\x0e\x04\0 "
+ "\0x\0m\0l\0n\0s\0:\0f\0o\0o\0=\0'\0U\0R\0I\0'\0>"
+ "\0&\0b\0a\0r\0;"
+ "\0<\0/\0f\0o\0o\0:\x0e\x04\0>";
+#ifdef XML_UNICODE
+ const XML_Char *expected = XCS("URI \x0e04");
+#else
+ const XML_Char *expected = XCS("URI \xe0\xb8\x84");
+#endif
+ CharData storage;
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetStartElementHandler(g_parser, start_element_event_handler);
+ XML_SetUnknownEncodingHandler(g_parser, MiscEncodingHandler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+START_TEST(test_ns_invalid_doctype) {
+ const char *text = "<!DOCTYPE foo:!bad [ <!ENTITY bar 'baz' ]>\n"
+ "<foo:!bad>&bar;</foo:!bad>";
+
+ expect_failure(text, XML_ERROR_INVALID_TOKEN,
+ "Invalid character in document local name not faulted");
+}
+END_TEST
+
+START_TEST(test_ns_double_colon_doctype) {
+ const char *text = "<!DOCTYPE foo:a:doc [ <!ENTITY bar 'baz' ]>\n"
+ "<foo:a:doc>&bar;</foo:a:doc>";
+
+ expect_failure(text, XML_ERROR_SYNTAX,
+ "Double colon in document name not faulted");
+}
+END_TEST
+
+/* Control variable; the number of times duff_allocator() will successfully
+ * allocate */
+#define ALLOC_ALWAYS_SUCCEED (-1)
+#define REALLOC_ALWAYS_SUCCEED (-1)
+
+static intptr_t allocation_count = ALLOC_ALWAYS_SUCCEED;
+static intptr_t reallocation_count = REALLOC_ALWAYS_SUCCEED;
+
+/* Crocked allocator for allocation failure tests */
+static void *
+duff_allocator(size_t size) {
+ if (allocation_count == 0)
+ return NULL;
+ if (allocation_count != ALLOC_ALWAYS_SUCCEED)
+ allocation_count--;
+ return malloc(size);
+}
+
+/* Crocked reallocator for allocation failure tests */
+static void *
+duff_reallocator(void *ptr, size_t size) {
+ if (reallocation_count == 0)
+ return NULL;
+ if (reallocation_count != REALLOC_ALWAYS_SUCCEED)
+ reallocation_count--;
+ return realloc(ptr, size);
+}
+
+/* Test that a failure to allocate the parser structure fails gracefully */
+START_TEST(test_misc_alloc_create_parser) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
+ unsigned int i;
+ const unsigned int max_alloc_count = 10;
+
+ /* Something this simple shouldn't need more than 10 allocations */
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
+ if (g_parser != NULL)
+ break;
+ }
+ if (i == 0)
+ fail("Parser unexpectedly ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Parser not created with max allocation count");
+}
+END_TEST
+
+/* Test memory allocation failures for a parser with an encoding */
+START_TEST(test_misc_alloc_create_parser_with_encoding) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
+ unsigned int i;
+ const unsigned int max_alloc_count = 10;
+
+ /* Try several levels of allocation */
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ g_parser = XML_ParserCreate_MM(XCS("us-ascii"), &memsuite, NULL);
+ if (g_parser != NULL)
+ break;
+ }
+ if (i == 0)
+ fail("Parser ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Parser not created with max allocation count");
+}
+END_TEST
+
+/* Test that freeing a NULL parser doesn't cause an explosion.
+ * (Not actually tested anywhere else)
+ */
+START_TEST(test_misc_null_parser) {
+ XML_ParserFree(NULL);
+}
+END_TEST
+
+/* Test that XML_ErrorString rejects out-of-range codes */
+START_TEST(test_misc_error_string) {
+ if (XML_ErrorString((enum XML_Error) - 1) != NULL)
+ fail("Negative error code not rejected");
+ if (XML_ErrorString((enum XML_Error)100) != NULL)
+ fail("Large error code not rejected");
+}
+END_TEST
+
+/* Test the version information is consistent */
+
+/* Since we are working in XML_LChars (potentially 16-bits), we
+ * can't use the standard C library functions for character
+ * manipulation and have to roll our own.
+ */
+static int
+parse_version(const XML_LChar *version_text,
+ XML_Expat_Version *version_struct) {
+ if (! version_text)
+ return XML_FALSE;
+
+ while (*version_text != 0x00) {
+ if (*version_text >= ASCII_0 && *version_text <= ASCII_9)
+ break;
+ version_text++;
+ }
+ if (*version_text == 0x00)
+ return XML_FALSE;
+
+ /* version_struct->major = strtoul(version_text, 10, &version_text) */
+ version_struct->major = 0;
+ while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
+ version_struct->major
+ = 10 * version_struct->major + (*version_text++ - ASCII_0);
+ }
+ if (*version_text++ != ASCII_PERIOD)
+ return XML_FALSE;
+
+ /* Now for the minor version number */
+ version_struct->minor = 0;
+ while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
+ version_struct->minor
+ = 10 * version_struct->minor + (*version_text++ - ASCII_0);
+ }
+ if (*version_text++ != ASCII_PERIOD)
+ return XML_FALSE;
+
+ /* Finally the micro version number */
+ version_struct->micro = 0;
+ while (*version_text >= ASCII_0 && *version_text <= ASCII_9) {
+ version_struct->micro
+ = 10 * version_struct->micro + (*version_text++ - ASCII_0);
+ }
+ if (*version_text != 0x00)
+ return XML_FALSE;
+ return XML_TRUE;
+}
+
+static int
+versions_equal(const XML_Expat_Version *first,
+ const XML_Expat_Version *second) {
+ return (first->major == second->major && first->minor == second->minor
+ && first->micro == second->micro);
+}
+
+START_TEST(test_misc_version) {
+ XML_Expat_Version read_version = XML_ExpatVersionInfo();
+ /* Silence compiler warning with the following assignment */
+ XML_Expat_Version parsed_version = {0, 0, 0};
+ const XML_LChar *version_text = XML_ExpatVersion();
+
+ if (version_text == NULL)
+ fail("Could not obtain version text");
+ assert(version_text != NULL);
+ if (! parse_version(version_text, &parsed_version))
+ fail("Unable to parse version text");
+ if (! versions_equal(&read_version, &parsed_version))
+ fail("Version mismatch");
+
+#if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T)
+ if (xcstrcmp(version_text, XCS("expat_2.2.10"))) /* needs bump on releases */
+ fail("XML_*_VERSION in expat.h out of sync?\n");
+#else
+ /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T
+ * then XML_LChar is defined as char, for some reason.
+ */
+ if (strcmp(version_text, "expat_2.2.5")) /* needs bump on releases */
+ fail("XML_*_VERSION in expat.h out of sync?\n");
+#endif /* ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T) */
+}
+END_TEST
+
+/* Test feature information */
+START_TEST(test_misc_features) {
+ const XML_Feature *features = XML_GetFeatureList();
+
+ /* Prevent problems with double-freeing parsers */
+ g_parser = NULL;
+ if (features == NULL) {
+ fail("Failed to get feature information");
+ } else {
+ /* Loop through the features checking what we can */
+ while (features->feature != XML_FEATURE_END) {
+ switch (features->feature) {
+ case XML_FEATURE_SIZEOF_XML_CHAR:
+ if (features->value != sizeof(XML_Char))
+ fail("Incorrect size of XML_Char");
+ break;
+ case XML_FEATURE_SIZEOF_XML_LCHAR:
+ if (features->value != sizeof(XML_LChar))
+ fail("Incorrect size of XML_LChar");
+ break;
+ default:
+ break;
+ }
+ features++;
}
- XML_ParserFree(p2);
- return 1;
+ }
+}
+END_TEST
+
+/* Regression test for GitHub Issue #17: memory leak parsing attribute
+ * values with mixed bound and unbound namespaces.
+ */
+START_TEST(test_misc_attribute_leak) {
+ const char *text = "<D xmlns:L=\"D\" l:a='' L:a=''/>";
+ XML_Memory_Handling_Suite memsuite
+ = {tracking_malloc, tracking_realloc, tracking_free};
+
+ g_parser = XML_ParserCreate_MM(XCS("UTF-8"), &memsuite, XCS("\n"));
+ expect_failure(text, XML_ERROR_UNBOUND_PREFIX, "Unbound prefixes not found");
+ XML_ParserFree(g_parser);
+ /* Prevent the teardown trying to double free */
+ g_parser = NULL;
+
+ if (! tracking_report())
+ fail("Memory leak found");
+}
+END_TEST
+
+/* Test parser created for UTF-16LE is successful */
+START_TEST(test_misc_utf16le) {
+ const char text[] =
+ /* <?xml version='1.0'?><q>Hi</q> */
+ "<\0?\0x\0m\0l\0 \0"
+ "v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0?\0>\0"
+ "<\0q\0>\0H\0i\0<\0/\0q\0>\0";
+ const XML_Char *expected = XCS("Hi");
+ CharData storage;
+
+ g_parser = XML_ParserCreate(XCS("UTF-16LE"));
+ if (g_parser == NULL)
+ fail("Parser not created");
+
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)sizeof(text) - 1, XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+ CharData_CheckXMLChars(&storage, expected);
+}
+END_TEST
+
+typedef struct {
+ XML_Parser parser;
+ int deep;
+} DataIssue240;
+
+static void
+start_element_issue_240(void *userData, const XML_Char *name,
+ const XML_Char **atts) {
+ DataIssue240 *mydata = (DataIssue240 *)userData;
+ UNUSED_P(name);
+ UNUSED_P(atts);
+ mydata->deep++;
+}
+
+static void
+end_element_issue_240(void *userData, const XML_Char *name) {
+ DataIssue240 *mydata = (DataIssue240 *)userData;
+
+ UNUSED_P(name);
+ mydata->deep--;
+ if (mydata->deep == 0) {
+ XML_StopParser(mydata->parser, 0);
+ }
+}
+
+START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
+ XML_Parser parser;
+ DataIssue240 *mydata;
+ enum XML_Status result;
+ const char *const doc1 = "<doc><e1/><e><foo/></e></doc>";
+
+ parser = XML_ParserCreate(NULL);
+ XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
+ mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
+ mydata->parser = parser;
+ mydata->deep = 0;
+ XML_SetUserData(parser, mydata);
+
+ result = XML_Parse(parser, doc1, (int)strlen(doc1), 1);
+ XML_ParserFree(parser);
+ free(mydata);
+ if (result != XML_STATUS_ERROR)
+ fail("Stopping the parser did not work as expected");
+}
+END_TEST
+
+START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
+ XML_Parser parser;
+ DataIssue240 *mydata;
+ enum XML_Status result;
+ const char *const doc2 = "<doc><elem/></doc>";
+
+ parser = XML_ParserCreate(NULL);
+ XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
+ mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
+ mydata->parser = parser;
+ mydata->deep = 0;
+ XML_SetUserData(parser, mydata);
+
+ result = XML_Parse(parser, doc2, (int)strlen(doc2), 1);
+ XML_ParserFree(parser);
+ free(mydata);
+ if (result != XML_STATUS_ERROR)
+ fail("Stopping the parser did not work as expected");
+}
+END_TEST
+
+START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
+ const char *const inputOne = "<!DOCTYPE d [\n"
+ "<!ENTITY % e ']><d/>'>\n"
+ "\n"
+ "%e;";
+ const char *const inputTwo = "<!DOCTYPE d [\n"
+ "<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&e1;'>\n"
+ "\n"
+ "%e2;";
+ const char *const inputThree = "<!DOCTYPE d [\n"
+ "<!ENTITY % e ']><d'>\n"
+ "\n"
+ "%e;";
+ const char *const inputIssue317 = "<!DOCTYPE doc [\n"
+ "<!ENTITY % foo ']>\n"
+ "<doc>Hell<oc (#PCDATA)*>'>\n"
+ "%foo;\n"
+ "]>\n"
+ "<doc>Hello, world</dVc>";
+
+ const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
+ size_t inputIndex = 0;
+
+ for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
+ XML_Parser parser;
+ enum XML_Status parseResult;
+ int setParamEntityResult;
+ XML_Size lineNumber;
+ XML_Size columnNumber;
+ const char *const input = inputs[inputIndex];
+
+ parser = XML_ParserCreate(NULL);
+ setParamEntityResult
+ = XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ if (setParamEntityResult != 1)
+ fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
+
+ parseResult = XML_Parse(parser, input, (int)strlen(input), 0);
+ if (parseResult != XML_STATUS_ERROR) {
+ parseResult = XML_Parse(parser, "", 0, 1);
+ if (parseResult != XML_STATUS_ERROR) {
+ fail("Parsing was expected to fail but succeeded.");
+ }
+ }
+
+ if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
+ fail("Error code does not match XML_ERROR_INVALID_TOKEN");
+
+ lineNumber = XML_GetCurrentLineNumber(parser);
+ if (lineNumber != 4)
+ fail("XML_GetCurrentLineNumber does not work as expected.");
+
+ columnNumber = XML_GetCurrentColumnNumber(parser);
+ if (columnNumber != 0)
+ fail("XML_GetCurrentColumnNumber does not work as expected.");
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+static void
+alloc_setup(void) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
+
+ /* Ensure the parser creation will go through */
+ allocation_count = ALLOC_ALWAYS_SUCCEED;
+ reallocation_count = REALLOC_ALWAYS_SUCCEED;
+ g_parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
+ if (g_parser == NULL)
+ fail("Parser not created");
+}
+
+static void
+alloc_teardown(void) {
+ basic_teardown();
+}
+
+/* Test the effects of allocation failures on xml declaration processing */
+START_TEST(test_alloc_parse_xdecl) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>Hello, world</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* Resetting the parser is insufficient, because some memory
+ * allocations are cached within the parser. Instead we use
+ * the teardown and setup routines to ensure that we have the
+ * right sort of parser back in our hands.
+ */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+/* As above, but with an encoding big enough to cause storing the
+ * version information to expand the string pool being used.
+ */
+static int XMLCALL
+long_encoding_handler(void *userData, const XML_Char *encoding,
+ XML_Encoding *info) {
+ int i;
+
+ UNUSED_P(userData);
+ UNUSED_P(encoding);
+ for (i = 0; i < 256; i++)
+ info->map[i] = i;
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = NULL;
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_alloc_parse_xdecl_2) {
+ const char *text
+ = "<?xml version='1.0' encoding='"
+ /* Each line is 64 characters */
+ "ThisIsAStupidlyLongEncodingNameIntendedToTriggerPoolGrowth123456"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN"
+ "'?>"
+ "<doc>Hello, world</doc>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetXmlDeclHandler(g_parser, dummy_xdecl_handler);
+ XML_SetUnknownEncodingHandler(g_parser, long_encoding_handler, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+/* Test the effects of allocation failures on a straightforward parse */
+START_TEST(test_alloc_parse_pi) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<?pi unknown?>\n"
+ "<doc>"
+ "Hello, world"
+ "</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_pi_2) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>"
+ "Hello, world"
+ "<?pi unknown?>\n"
+ "</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_pi_3) {
+ const char *text
+ = "<?"
+ /* 64 characters per line */
+ "This processing instruction should be long enough to ensure that"
+ "it triggers the growth of an internal string pool when the "
+ "allocator fails at a cruicial moment FGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "Q?><doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_comment) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!-- Test parsing this comment -->"
+ "<doc>Hi</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_comment_2) {
+ const char *text = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<doc>"
+ "Hello, world"
+ "<!-- Parse this comment too -->"
+ "</doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed with max allocations");
+}
+END_TEST
+
+static int XMLCALL
+external_entity_duff_loader(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser new_parser;
+ unsigned int i;
+ const unsigned int max_alloc_count = 10;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ /* Try a few different allocation levels */
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser != NULL) {
+ XML_ParserFree(new_parser);
+ break;
+ }
+ }
+ if (i == 0)
+ fail("External parser creation ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Extern parser not created with max allocation count");
+
+ /* Make sure other random allocation doesn't now fail */
+ allocation_count = ALLOC_ALWAYS_SUCCEED;
+
+ /* Make sure the failure code path is executed too */
+ return XML_STATUS_ERROR;
}
-START_TEST(test_default_ns_from_ext_subset_and_ext_ge)
-{
- char *text =
- "<?xml version='1.0'?>\n"
- "<!DOCTYPE doc SYSTEM 'http://xml.libexpat.org/doc.dtd' [\n"
- " <!ENTITY en SYSTEM 'http://xml.libexpat.org/entity.ent'>\n"
+/* Test that external parser creation running out of memory is
+ * correctly reported. Based on the external entity test cases.
+ */
+START_TEST(test_alloc_create_external_parser) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, foo_text);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_duff_loader);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR) {
+ fail("External parser allocator returned success incorrectly");
+ }
+}
+END_TEST
+
+/* More external parser memory allocation testing */
+START_TEST(test_alloc_run_external_parser) {
+ const char *text = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<!DOCTYPE doc SYSTEM 'foo'>\n"
+ "<doc>&entity;</doc>";
+ char foo_text[] = "<!ELEMENT doc (#PCDATA)*>";
+ unsigned int i;
+ const unsigned int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, foo_text);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_null_loader);
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing ignored failing allocator");
+ else if (i == max_alloc_count)
+ fail("Parsing failed with allocation count 10");
+}
+END_TEST
+
+static int XMLCALL
+external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ intptr_t callno = (intptr_t)XML_GetUserData(parser);
+ const char *text;
+ XML_Parser new_parser;
+ int i;
+ const int max_alloc_count = 20;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if (callno == 0) {
+ /* First time through, check how many calls to malloc occur */
+ text = ("<!ELEMENT doc (e+)>\n"
+ "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
+ "<!ELEMENT e EMPTY>\n");
+ allocation_count = 10000;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser == NULL) {
+ fail("Unable to allocate first external parser");
+ return XML_STATUS_ERROR;
+ }
+ /* Stash the number of calls in the user data */
+ XML_SetUserData(parser, (void *)(intptr_t)(10000 - allocation_count));
+ } else {
+ text = ("<?xml version='1.0' encoding='us-ascii'?>"
+ "<e/>");
+ /* Try at varying levels to exercise more code paths */
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = callno + i;
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser != NULL)
+ break;
+ }
+ if (i == 0) {
+ fail("Second external parser unexpectedly created");
+ XML_ParserFree(new_parser);
+ return XML_STATUS_ERROR;
+ } else if (i == max_alloc_count) {
+ fail("Second external parser not created");
+ return XML_STATUS_ERROR;
+ }
+ }
+
+ allocation_count = ALLOC_ALWAYS_SUCCEED;
+ if (_XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR) {
+ xml_failure(new_parser);
+ return XML_STATUS_ERROR;
+ }
+ XML_ParserFree(new_parser);
+ return XML_STATUS_OK;
+}
+
+/* Test that running out of memory in dtdCopy is correctly reported.
+ * Based on test_default_ns_from_ext_subset_and_ext_ge()
+ */
+START_TEST(test_alloc_dtd_copy_default_atts) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/ns1'>\n"
+ "&en;\n"
+ "</doc>";
+
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler);
+ XML_SetUserData(g_parser, NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+}
+END_TEST
+
+static int XMLCALL
+external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ intptr_t callno = (intptr_t)XML_GetUserData(parser);
+ const char *text;
+ XML_Parser new_parser;
+ enum XML_Status rv;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ if (callno == 0) {
+ /* Try different allocation levels for whole exercise */
+ text = ("<!ELEMENT doc (e+)>\n"
+ "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
+ "<!ELEMENT e EMPTY>\n");
+ XML_SetUserData(parser, (void *)(intptr_t)1);
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser == NULL)
+ return XML_STATUS_ERROR;
+ rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
+ } else {
+ /* Just run through once */
+ text = ("<?xml version='1.0' encoding='us-ascii'?>"
+ "<e/>");
+ new_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (new_parser == NULL)
+ return XML_STATUS_ERROR;
+ rv = _XML_Parse_SINGLE_BYTES(new_parser, text, (int)strlen(text), XML_TRUE);
+ }
+ XML_ParserFree(new_parser);
+ if (rv == XML_STATUS_ERROR)
+ return XML_STATUS_ERROR;
+ return XML_STATUS_OK;
+}
+
+/* Test more external entity allocation failure paths */
+START_TEST(test_alloc_external_entity) {
+ const char *text = "<?xml version='1.0'?>\n"
+ "<!DOCTYPE doc SYSTEM 'http://example.org/doc.dtd' [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/entity.ent'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/ns1'>\n"
+ "&en;\n"
+ "</doc>";
+ int i;
+ const int alloc_test_max_repeats = 50;
+
+ for (i = 0; i < alloc_test_max_repeats; i++) {
+ allocation_count = -1;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_dbl_handler_2);
+ XML_SetUserData(g_parser, NULL);
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ allocation_count = -1;
+ if (i == 0)
+ fail("External entity parsed despite duff allocator");
+ if (i == alloc_test_max_repeats)
+ fail("External entity not parsed at max allocation count");
+}
+END_TEST
+
+/* Test more allocation failure paths */
+static int XMLCALL
+external_entity_alloc_set_encoding(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId) {
+ /* As for external_entity_loader() */
+ const char *text = "<?xml encoding='iso-8859-3'?>"
+ "\xC3\xA9";
+ XML_Parser ext_parser;
+ enum XML_Status status;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ if (! XML_SetEncoding(ext_parser, XCS("utf-8"))) {
+ XML_ParserFree(ext_parser);
+ return XML_STATUS_ERROR;
+ }
+ status
+ = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ if (status == XML_STATUS_ERROR)
+ return XML_STATUS_ERROR;
+ return XML_STATUS_OK;
+}
+
+START_TEST(test_alloc_ext_entity_set_encoding) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int i;
+ const int max_allocation_count = 30;
+
+ for (i = 0; i < max_allocation_count; i++) {
+ XML_SetExternalEntityRefHandler(g_parser,
+ external_entity_alloc_set_encoding);
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ break;
+ allocation_count = -1;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Encoding check succeeded despite failing allocator");
+ if (i == max_allocation_count)
+ fail("Encoding failed at max allocation count");
+}
+END_TEST
+
+static int XMLCALL
+unknown_released_encoding_handler(void *data, const XML_Char *encoding,
+ XML_Encoding *info) {
+ UNUSED_P(data);
+ if (! xcstrcmp(encoding, XCS("unsupported-encoding"))) {
+ int i;
+
+ for (i = 0; i < 256; i++)
+ info->map[i] = i;
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = dummy_release;
+ return XML_STATUS_OK;
+ }
+ return XML_STATUS_ERROR;
+}
+
+/* Test the effects of allocation failure in internal entities.
+ * Based on test_unknown_encoding_internal_entity
+ */
+START_TEST(test_alloc_internal_entity) {
+ const char *text = "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
+ "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
+ "<test a='&foo;'/>";
+ unsigned int i;
+ const unsigned int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUnknownEncodingHandler(g_parser, unknown_released_encoding_handler,
+ NULL);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Internal entity worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Internal entity failed at max allocation count");
+}
+END_TEST
+
+/* Test the robustness against allocation failure of element handling
+ * Based on test_dtd_default_handling().
+ */
+START_TEST(test_alloc_dtd_default_handling) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ENTITY e SYSTEM 'http://example.org/e'>\n"
+ "<!NOTATION n SYSTEM 'http://example.org/n'>\n"
+ "<!ENTITY e1 SYSTEM 'http://example.org/e' NDATA n>\n"
+ "<!ELEMENT doc (#PCDATA)>\n"
+ "<!ATTLIST doc a CDATA #IMPLIED>\n"
+ "<?pi in dtd?>\n"
+ "<!--comment in dtd-->\n"
+ "]>\n"
+ "<doc><![CDATA[text in doc]]></doc>";
+ const XML_Char *expected = XCS("\n\n\n\n\n\n\n\n\n<doc>text in doc</doc>");
+ CharData storage;
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ dummy_handler_flags = 0;
+ XML_SetDefaultHandler(g_parser, accumulate_characters);
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_handler,
+ dummy_end_doctype_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ XML_SetCdataSectionHandler(g_parser, dummy_start_cdata_handler,
+ dummy_end_cdata_handler);
+ XML_SetUnparsedEntityDeclHandler(g_parser,
+ dummy_unparsed_entity_decl_handler);
+ CharData_Init(&storage);
+ XML_SetUserData(g_parser, &storage);
+ XML_SetCharacterDataHandler(g_parser, accumulate_characters);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Default DTD parsed despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Default DTD not parsed with maximum alloc count");
+ CharData_CheckXMLChars(&storage, expected);
+ if (dummy_handler_flags
+ != (DUMMY_START_DOCTYPE_HANDLER_FLAG | DUMMY_END_DOCTYPE_HANDLER_FLAG
+ | DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG
+ | DUMMY_ELEMENT_DECL_HANDLER_FLAG | DUMMY_ATTLIST_DECL_HANDLER_FLAG
+ | DUMMY_COMMENT_HANDLER_FLAG | DUMMY_PI_HANDLER_FLAG
+ | DUMMY_START_CDATA_HANDLER_FLAG | DUMMY_END_CDATA_HANDLER_FLAG
+ | DUMMY_UNPARSED_ENTITY_DECL_HANDLER_FLAG))
+ fail("Not all handlers were called");
+}
+END_TEST
+
+/* Test robustness of XML_SetEncoding() with a failing allocator */
+START_TEST(test_alloc_explicit_encoding) {
+ int i;
+ const int max_alloc_count = 5;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (XML_SetEncoding(g_parser, XCS("us-ascii")) == XML_STATUS_OK)
+ break;
+ }
+ if (i == 0)
+ fail("Encoding set despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Encoding not set at max allocation count");
+}
+END_TEST
+
+/* Test robustness of XML_SetBase against a failing allocator */
+START_TEST(test_alloc_set_base) {
+ const XML_Char *new_base = XCS("/local/file/name.xml");
+ int i;
+ const int max_alloc_count = 5;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (XML_SetBase(g_parser, new_base) == XML_STATUS_OK)
+ break;
+ }
+ if (i == 0)
+ fail("Base set despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Base not set with max allocation count");
+}
+END_TEST
+
+/* Test buffer extension in the face of a duff reallocator */
+START_TEST(test_alloc_realloc_buffer) {
+ const char *text = get_buffer_test_text;
+ void *buffer;
+ int i;
+ const int max_realloc_count = 10;
+
+ /* Get a smallish buffer */
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ buffer = XML_GetBuffer(g_parser, 1536);
+ if (buffer == NULL)
+ fail("1.5K buffer reallocation failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_FALSE)
+ == XML_STATUS_OK)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ reallocation_count = -1;
+ if (i == 0)
+ fail("Parse succeeded with no reallocation");
+ else if (i == max_realloc_count)
+ fail("Parse failed with max reallocation count");
+}
+END_TEST
+
+/* Same test for external entity parsers */
+static int XMLCALL
+external_entity_reallocator(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = get_buffer_test_text;
+ XML_Parser ext_parser;
+ void *buffer;
+ enum XML_Status status;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ fail("Could not create external entity parser");
+
+ reallocation_count = (intptr_t)XML_GetUserData(parser);
+ buffer = XML_GetBuffer(ext_parser, 1536);
+ if (buffer == NULL)
+ fail("Buffer allocation failed");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ status = XML_ParseBuffer(ext_parser, (int)strlen(text), XML_FALSE);
+ reallocation_count = -1;
+ XML_ParserFree(ext_parser);
+ return (status == XML_STATUS_OK) ? XML_STATUS_OK : XML_STATUS_ERROR;
+}
+
+START_TEST(test_alloc_ext_entity_realloc_buffer) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY en SYSTEM 'http://example.org/dummy.ent'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_reallocator);
+ XML_SetUserData(g_parser, (void *)(intptr_t)i);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_OK)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Succeeded with no reallocations");
+ if (i == max_realloc_count)
+ fail("Failed with max reallocations");
+}
+END_TEST
+
+/* Test elements with many attributes are handled correctly */
+START_TEST(test_alloc_realloc_many_attributes) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ATTLIST doc za CDATA 'default'>\n"
+ "<!ATTLIST doc zb CDATA 'def2'>\n"
+ "<!ATTLIST doc zc CDATA 'def3'>\n"
+ "]>\n"
+ "<doc a='1'"
+ " b='2'"
+ " c='3'"
+ " d='4'"
+ " e='5'"
+ " f='6'"
+ " g='7'"
+ " h='8'"
+ " i='9'"
+ " j='10'"
+ " k='11'"
+ " l='12'"
+ " m='13'"
+ " n='14'"
+ " p='15'"
+ " q='16'"
+ " r='17'"
+ " s='18'>"
+ "</doc>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite no reallocations");
+ if (i == max_realloc_count)
+ fail("Parse failed at max reallocations");
+}
+END_TEST
+
+/* Test handling of a public entity with failing allocator */
+START_TEST(test_alloc_public_entity_value) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc></doc>\n";
+ char dtd_text[]
+ = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % e1 PUBLIC 'foo' 'bar.ent'>\n"
+ "<!ENTITY % "
+ /* Each line is 64 characters */
+ "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " '%e1;'>\n"
+ "%e1;\n";
+ int i;
+ const int max_alloc_count = 50;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ dummy_handler_flags = 0;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
+ /* Provoke a particular code path */
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocation");
+ if (i == max_alloc_count)
+ fail("Parsing failed at max allocation count");
+ if (dummy_handler_flags != DUMMY_ENTITY_DECL_HANDLER_FLAG)
+ fail("Entity declaration handler not called");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_subst_public_entity_value) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc></doc>\n";
+ char dtd_text[]
+ = "<!ELEMENT doc EMPTY>\n"
+ "<!ENTITY % "
+ /* Each line is 64 characters */
+ "ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " PUBLIC 'foo' 'bar.ent'>\n"
+ "%ThisIsAStupidlyLongParameterNameIntendedToTriggerPoolGrowth12345"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP;";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_public);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocation");
+ if (i == max_realloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_public_doctype) {
+ const char *text
+ = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!DOCTYPE doc PUBLIC '"
+ /* 64 characters per line */
+ "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "' 'test'>\n"
+ "<doc></doc>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ dummy_handler_flags = 0;
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
+ dummy_end_doctype_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags
+ != (DUMMY_START_DOCTYPE_DECL_HANDLER_FLAG
+ | DUMMY_END_DOCTYPE_DECL_HANDLER_FLAG))
+ fail("Doctype handler functions not called");
+}
+END_TEST
+
+START_TEST(test_alloc_parse_public_doctype_long_name) {
+ const char *text
+ = "<?xml version='1.0' encoding='utf-8'?>\n"
+ "<!DOCTYPE doc PUBLIC 'http://example.com/foo' '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "'>\n"
+ "<doc></doc>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetDoctypeDeclHandler(g_parser, dummy_start_doctype_decl_handler,
+ dummy_end_doctype_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+static int XMLCALL
+external_entity_alloc(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ const char *text = (const char *)XML_GetUserData(parser);
+ XML_Parser ext_parser;
+ int parse_res;
+
+ UNUSED_P(base);
+ UNUSED_P(systemId);
+ UNUSED_P(publicId);
+ ext_parser = XML_ExternalEntityParserCreate(parser, context, NULL);
+ if (ext_parser == NULL)
+ return XML_STATUS_ERROR;
+ parse_res
+ = _XML_Parse_SINGLE_BYTES(ext_parser, text, (int)strlen(text), XML_TRUE);
+ XML_ParserFree(ext_parser);
+ return parse_res;
+}
+
+/* Test foreign DTD handling */
+START_TEST(test_alloc_set_foreign_dtd) {
+ const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
+ "<doc>&entity;</doc>";
+ char text2[] = "<!ELEMENT doc (#PCDATA)*>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(g_parser, &text2);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (XML_UseForeignDTD(g_parser, XML_TRUE) != XML_ERROR_NONE)
+ fail("Could not set foreign DTD");
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test based on ibm/valid/P32/ibm32v04.xml */
+START_TEST(test_alloc_attribute_enum_value) {
+ const char *text = "<?xml version='1.0' standalone='no'?>\n"
+ "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
+ "<animal>This is a \n <a/> \n\nyellow tiger</animal>";
+ char dtd_text[] = "<!ELEMENT animal (#PCDATA|a)*>\n"
+ "<!ELEMENT a EMPTY>\n"
+ "<!ATTLIST animal xml:space (default|preserve) 'preserve'>";
+ int i;
+ const int max_alloc_count = 30;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ /* An attribute list handler provokes a different code path */
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test attribute enums sufficient to overflow the string pool */
+START_TEST(test_alloc_realloc_attribute_enum_value) {
+ const char *text = "<?xml version='1.0' standalone='no'?>\n"
+ "<!DOCTYPE animal SYSTEM 'test.dtd'>\n"
+ "<animal>This is a yellow tiger</animal>";
+ /* We wish to define a collection of attribute enums that will
+ * cause the string pool storing them to have to expand. This
+ * means more than 1024 bytes, including the parentheses and
+ * separator bars.
+ */
+ char dtd_text[]
+ = "<!ELEMENT animal (#PCDATA)*>\n"
+ "<!ATTLIST animal thing "
+ "(default"
+ /* Each line is 64 characters */
+ "|ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO)"
+ " 'default'>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ /* An attribute list handler provokes a different code path */
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+/* Test attribute enums in a #IMPLIED attribute forcing pool growth */
+START_TEST(test_alloc_realloc_implied_attribute) {
+ /* Forcing this particular code path is a balancing act. The
+ * addition of the closing parenthesis and terminal NUL must be
+ * what pushes the string of enums over the 1024-byte limit,
+ * otherwise a different code path will pick up the realloc.
+ */
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ATTLIST doc a "
+ /* Each line is 64 characters */
+ "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
+ " #IMPLIED>\n"
+ "]><doc/>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+/* Test attribute enums in a defaulted attribute forcing pool growth */
+START_TEST(test_alloc_realloc_default_attribute) {
+ /* Forcing this particular code path is a balancing act. The
+ * addition of the closing parenthesis and terminal NUL must be
+ * what pushes the string of enums over the 1024-byte limit,
+ * otherwise a different code path will pick up the realloc.
+ */
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "<!ATTLIST doc a "
+ /* Each line is 64 characters */
+ "(ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|BBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|CBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|DBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|EBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|FBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|GBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|HBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|IBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|JBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|KBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|LBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|MBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|NBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|OBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO"
+ "|PBCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMN)"
+ " 'ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNO'"
+ ">\n]><doc/>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetAttlistDeclHandler(g_parser, dummy_attlist_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+/* Test long notation name with dodgy allocator */
+START_TEST(test_alloc_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!NOTATION "
+ /* Each line is 64 characters */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " SYSTEM 'http://example.org/n'>\n"
+ "<!ENTITY e SYSTEM 'http://example.org/e' NDATA "
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ">\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ dummy_handler_flags = 0;
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ XML_SetEntityDeclHandler(g_parser, dummy_entity_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags
+ != (DUMMY_ENTITY_DECL_HANDLER_FLAG | DUMMY_NOTATION_DECL_HANDLER_FLAG))
+ fail("Entity declaration handler not called");
+}
+END_TEST
+
+/* Test public notation with dodgy allocator */
+START_TEST(test_alloc_public_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!NOTATION note PUBLIC '"
+ /* 64 characters per line */
+ "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "' 'foo'>\n"
+ "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ dummy_handler_flags = 0;
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
+ fail("Notation handler not called");
+}
+END_TEST
+
+/* Test public notation with dodgy allocator */
+START_TEST(test_alloc_system_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!NOTATION note SYSTEM '"
+ /* 64 characters per line */
+ "http://example.com/a/long/enough/name/to/trigger/pool/growth/zz/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "'>\n"
+ "<!ENTITY e SYSTEM 'http://example.com/e' NDATA note>\n"
+ "<!ELEMENT doc EMPTY>\n"
+ "]>\n<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ dummy_handler_flags = 0;
+ XML_SetNotationDeclHandler(g_parser, dummy_notation_decl_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite allocation failures");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags != DUMMY_NOTATION_DECL_HANDLER_FLAG)
+ fail("Notation handler not called");
+}
+END_TEST
+
+START_TEST(test_alloc_nested_groups) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc "
+ /* Sixteen elements per line */
+ "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
+ "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
+ "))))))))))))))))))))))))))))))))>\n"
+ "<!ELEMENT e EMPTY>"
+ "]>\n"
+ "<doc><e/></doc>";
+ CharData storage;
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ CharData_Init(&storage);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum reallocation count");
+ CharData_CheckXMLChars(&storage, XCS("doce"));
+ if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler not fired");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_nested_groups) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc "
+ /* Sixteen elements per line */
+ "(e,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,"
+ "(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?,(e?"
+ "))))))))))))))))))))))))))))))))>\n"
+ "<!ELEMENT e EMPTY>"
+ "]>\n"
+ "<doc><e/></doc>";
+ CharData storage;
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ CharData_Init(&storage);
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ XML_SetStartElementHandler(g_parser, record_element_start_handler);
+ XML_SetUserData(g_parser, &storage);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+ CharData_CheckXMLChars(&storage, XCS("doce"));
+ if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler not fired");
+}
+END_TEST
+
+START_TEST(test_alloc_large_group) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc ("
+ "a1|a2|a3|a4|a5|a6|a7|a8|"
+ "b1|b2|b3|b4|b5|b6|b7|b8|"
+ "c1|c2|c3|c4|c5|c6|c7|c8|"
+ "d1|d2|d3|d4|d5|d6|d7|d8|"
+ "e1"
+ ")+>\n"
+ "]>\n"
+ "<doc>\n"
+ "<a1/>\n"
+ "</doc>\n";
+ int i;
+ const int max_alloc_count = 50;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler flag not raised");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_group_choice) {
+ const char *text = "<!DOCTYPE doc [\n"
+ "<!ELEMENT doc ("
+ "a1|a2|a3|a4|a5|a6|a7|a8|"
+ "b1|b2|b3|b4|b5|b6|b7|b8|"
+ "c1|c2|c3|c4|c5|c6|c7|c8|"
+ "d1|d2|d3|d4|d5|d6|d7|d8|"
+ "e1"
+ ")+>\n"
+ "]>\n"
+ "<doc>\n"
+ "<a1/>\n"
+ "<b2 attr='foo'>This is a foo</b2>\n"
+ "<c3></c3>\n"
+ "</doc>\n";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetElementDeclHandler(g_parser, dummy_element_decl_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+ if (dummy_handler_flags != DUMMY_ELEMENT_DECL_HANDLER_FLAG)
+ fail("Element handler flag not raised");
+}
+END_TEST
+
+START_TEST(test_alloc_pi_in_epilog) {
+ const char *text = "<doc></doc>\n"
+ "<?pi in epilog?>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetProcessingInstructionHandler(g_parser, dummy_pi_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse completed despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags != DUMMY_PI_HANDLER_FLAG)
+ fail("Processing instruction handler not invoked");
+}
+END_TEST
+
+START_TEST(test_alloc_comment_in_epilog) {
+ const char *text = "<doc></doc>\n"
+ "<!-- comment in epilog -->";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetCommentHandler(g_parser, dummy_comment_handler);
+ dummy_handler_flags = 0;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse completed despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+ if (dummy_handler_flags != DUMMY_COMMENT_HANDLER_FLAG)
+ fail("Processing instruction handler not invoked");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_long_attribute_value) {
+ const char *text
+ = "<!DOCTYPE doc [<!ENTITY foo '"
+ /* Each line is 64 characters */
+ "This entity will be substituted as an attribute value, and is "
+ "calculated to be exactly long enough that the terminating NUL "
+ "that the library adds internally will trigger the string pool to"
+ "grow. GHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>]>\n"
+ "<doc a='&foo;'></doc>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_attribute_whitespace) {
+ const char *text = "<doc a=' '></doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_attribute_predefined_entity) {
+ const char *text = "<doc a='&amp;'></doc>";
+ int i;
+ const int max_alloc_count = 15;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test that a character reference at the end of a suitably long
+ * default value for an attribute can trigger pool growth, and recovers
+ * if the allocator fails on it.
+ */
+START_TEST(test_alloc_long_attr_default_with_char_ref) {
+ const char *text
+ = "<!DOCTYPE doc [<!ATTLIST doc a CDATA '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHI"
+ "&#x31;'>]>\n"
+ "<doc/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test that a long character reference substitution triggers a pool
+ * expansion correctly for an attribute value.
+ */
+START_TEST(test_alloc_long_attr_value) {
+ const char *text
+ = "<!DOCTYPE test [<!ENTITY foo '\n"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>]>\n"
+ "<test a='&foo;'/>";
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing allocator");
+ if (i == max_alloc_count)
+ fail("Parse failed at maximum allocation count");
+}
+END_TEST
+
+/* Test that an error in a nested parameter entity substitution is
+ * handled correctly. It seems unlikely that the code path being
+ * exercised can be reached purely by carefully crafted XML, but an
+ * allocation error in the right place will definitely do it.
+ */
+START_TEST(test_alloc_nested_entities) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/one.ent'>\n"
+ "<doc />";
+ ExtFaults test_data
+ = {"<!ENTITY % pe1 '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>\n"
+ "<!ENTITY % pe2 '%pe1;'>\n"
+ "%pe2;",
+ "Memory Fail not faulted", NULL, XML_ERROR_NO_MEMORY};
+
+ /* Causes an allocation error in a nested storeEntityValue() */
+ allocation_count = 12;
+ XML_SetUserData(g_parser, &test_data);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_faulter);
+ expect_failure(text, XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ "Entity allocation failure not noted");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_param_entity_newline) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc/>";
+ char dtd_text[]
+ = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
+ /* 64 characters per line */
+ "This default value is carefully crafted so that the carriage "
+ "return right at the end of the entity string causes an internal "
+ "string pool to have to grow. This allows us to test the alloc "
+ "failure path from that point. OPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDE"
+ "\">\n'>"
+ "%pe;\n";
+ int i;
+ const int max_realloc_count = 5;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_ce_extends_pe) {
+ const char *text = "<!DOCTYPE doc SYSTEM 'http://example.org/'>\n"
+ "<doc/>";
+ char dtd_text[]
+ = "<!ENTITY % pe '<!ATTLIST doc att CDATA \""
+ /* 64 characters per line */
+ "This default value is carefully crafted so that the character "
+ "entity at the end causes an internal string pool to have to "
+ "grow. This allows us to test the allocation failure path from "
+ "that point onwards. EFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFG&#x51;"
+ "\">\n'>"
+ "%pe;\n";
+ int i;
+ const int max_realloc_count = 5;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetUserData(g_parser, dtd_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_realloc_attributes) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc\n"
+ " a1 (a|b|c) 'a'\n"
+ " a2 (foo|bar) #IMPLIED\n"
+ " a3 NMTOKEN #IMPLIED\n"
+ " a4 NMTOKENS #IMPLIED\n"
+ " a5 ID #IMPLIED\n"
+ " a6 IDREF #IMPLIED\n"
+ " a7 IDREFS #IMPLIED\n"
+ " a8 ENTITY #IMPLIED\n"
+ " a9 ENTITIES #IMPLIED\n"
+ " a10 CDATA #IMPLIED\n"
+ " >]>\n"
+ "<doc>wombat</doc>\n";
+ int i;
+ const int max_realloc_count = 5;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+
+ if (i == 0)
+ fail("Parse succeeded despite failing reallocator");
+ if (i == max_realloc_count)
+ fail("Parse failed at maximum reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_doc_name) {
+ const char *text =
+ /* 64 characters per line */
+ "<LongRootElementNameThatWillCauseTheNextAllocationToExpandTheStr"
+ "ingPoolForTheDTDQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ " a='1'/>";
+ int i;
+ const int max_alloc_count = 20;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_base) {
+ const char *text = "<!DOCTYPE doc [\n"
+ " <!ENTITY e SYSTEM 'foo'>\n"
+ "]>\n"
+ "<doc>&e;</doc>";
+ char entity_text[] = "Hello world";
+ const XML_Char *base =
+ /* 64 characters per line */
+ /* clang-format off */
+ XCS("LongBaseURI/that/will/overflow/an/internal/buffer/and/cause/it/t")
+ XCS("o/have/to/grow/PQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/");
+ /* clang-format on */
+ int i;
+ const int max_alloc_count = 25;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, entity_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (XML_SetBase(g_parser, base) == XML_STATUS_ERROR) {
+ XML_ParserReset(g_parser, NULL);
+ continue;
+ }
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_public_id) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY e PUBLIC '"
+ /* 64 characters per line */
+ "LongPublicIDThatShouldResultInAnInternalStringPoolGrowingAtASpec"
+ "ificMomentKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "' 'bar'>\n"
+ "]>\n"
+ "<doc>&e;</doc>";
+ char entity_text[] = "Hello world";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, entity_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_entity_value) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ENTITY e1 '"
+ /* 64 characters per line */
+ "Long entity value that should provoke a string pool to grow whil"
+ "e setting up to parse the external entity below. xyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "'>\n"
+ " <!ENTITY e2 SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc>&e2;</doc>";
+ char entity_text[] = "Hello world";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, entity_text);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_alloc);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_alloc_long_notation) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!NOTATION note SYSTEM '"
+ /* 64 characters per line */
+ "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
+ "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "'>\n"
+ " <!ENTITY e1 SYSTEM 'foo' NDATA "
+ /* 64 characters per line */
+ "ALongNotationNameThatShouldProvokeStringPoolGrowthWhileCallingAn"
+ "ExternalEntityParserUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"
+ ">\n"
+ " <!ENTITY e2 SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc>&e2;</doc>";
+ ExtOption options[]
+ = {{XCS("foo"), "Entity Foo"}, {XCS("bar"), "Entity Bar"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_alloc_parse_xdecl() */
+ alloc_teardown();
+ alloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+static void
+nsalloc_setup(void) {
+ XML_Memory_Handling_Suite memsuite = {duff_allocator, duff_reallocator, free};
+ XML_Char ns_sep[2] = {' ', '\0'};
+
+ /* Ensure the parser creation will go through */
+ allocation_count = ALLOC_ALWAYS_SUCCEED;
+ reallocation_count = REALLOC_ALWAYS_SUCCEED;
+ g_parser = XML_ParserCreate_MM(NULL, &memsuite, ns_sep);
+ if (g_parser == NULL)
+ fail("Parser not created");
+}
+
+static void
+nsalloc_teardown(void) {
+ basic_teardown();
+}
+
+/* Test the effects of allocation failure in simple namespace parsing.
+ * Based on test_ns_default_with_empty_uri()
+ */
+START_TEST(test_nsalloc_xmlns) {
+ const char *text = "<doc xmlns='http://example.org/'>\n"
+ " <e xmlns=''/>\n"
+ "</doc>";
+ unsigned int i;
+ const unsigned int max_alloc_count = 30;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ /* Exercise more code paths with a default handler */
+ XML_SetDefaultHandler(g_parser, dummy_default_handler);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* Resetting the parser is insufficient, because some memory
+ * allocations are cached within the parser. Instead we use
+ * the teardown and setup routines to ensure that we have the
+ * right sort of parser back in our hands.
+ */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at maximum allocation count");
+}
+END_TEST
+
+/* Test XML_ParseBuffer interface with namespace and a dicky allocator */
+START_TEST(test_nsalloc_parse_buffer) {
+ const char *text = "<doc>Hello</doc>";
+ void *buffer;
+
+ /* Try a parse before the start of the world */
+ /* (Exercises new code path) */
+ allocation_count = 0;
+ if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_ERROR)
+ fail("Pre-init XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NO_MEMORY)
+ fail("Pre-init XML_ParseBuffer faulted for wrong reason");
+
+ /* Now with actual memory allocation */
+ allocation_count = ALLOC_ALWAYS_SUCCEED;
+ if (XML_ParseBuffer(g_parser, 0, XML_FALSE) != XML_STATUS_OK)
+ xml_failure(g_parser);
+
+ /* Check that resuming an unsuspended parser is faulted */
+ if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
+ fail("Resuming unsuspended parser not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NOT_SUSPENDED)
+ xml_failure(g_parser);
+
+ /* Get the parser into suspended state */
+ XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
+ resumable = XML_TRUE;
+ buffer = XML_GetBuffer(g_parser, (int)strlen(text));
+ if (buffer == NULL)
+ fail("Could not acquire parse buffer");
+ assert(buffer != NULL);
+ memcpy(buffer, text, strlen(text));
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
+ xml_failure(g_parser);
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Suspended XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_SUSPENDED)
+ xml_failure(g_parser);
+ if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
+ fail("Suspended XML_GetBuffer not faulted");
+
+ /* Get it going again and complete the world */
+ XML_SetCharacterDataHandler(g_parser, NULL);
+ if (XML_ResumeParser(g_parser) != XML_STATUS_OK)
+ xml_failure(g_parser);
+ if (XML_ParseBuffer(g_parser, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ fail("Post-finishing XML_ParseBuffer not faulted");
+ if (XML_GetErrorCode(g_parser) != XML_ERROR_FINISHED)
+ xml_failure(g_parser);
+ if (XML_GetBuffer(g_parser, (int)strlen(text)) != NULL)
+ fail("Post-finishing XML_GetBuffer not faulted");
+}
+END_TEST
+
+/* Check handling of long prefix names (pool growth) */
+START_TEST(test_nsalloc_long_prefix) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Check handling of long uri names (pool growth) */
+START_TEST(test_nsalloc_long_uri) {
+ const char *text
+ = "<foo:e xmlns:foo='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "' bar:a='12'\n"
+ "xmlns:bar='http://example.org/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789A/"
+ "'>"
+ "</foo:e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test handling of long attribute names with prefixes */
+START_TEST(test_nsalloc_long_attr) {
+ const char *text
+ = "<foo:e xmlns:foo='http://example.org/' bar:"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='12'\n"
+ "xmlns:bar='http://example.org/'>"
+ "</foo:e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test handling of an attribute name with a long namespace prefix */
+START_TEST(test_nsalloc_long_attr_prefix) {
+ const char *text
+ = "<foo:e xmlns:foo='http://example.org/' "
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":a='12'\n"
+ "xmlns:"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>"
+ "</foo:e>";
+ const XML_Char *elemstr[] = {
+ /* clang-format off */
+ XCS("http://example.org/ e foo"),
+ XCS("http://example.org/ a ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ XCS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ")
+ /* clang-format on */
+ };
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Test attribute handling in the face of a dodgy reallocator */
+START_TEST(test_nsalloc_realloc_attributes) {
+ const char *text = "<foo:e xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</foo:e>";
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+/* Test long element names with namespaces under a failing allocator */
+START_TEST(test_nsalloc_long_element) {
+ const char *text
+ = "<foo:thisisalongenoughelementnametotriggerareallocation\n"
+ " xmlns:foo='http://example.org/' bar:a='12'\n"
+ " xmlns:bar='http://example.org/'>"
+ "</foo:thisisalongenoughelementnametotriggerareallocation>";
+ const XML_Char *elemstr[]
+ = {XCS("http://example.org/")
+ XCS(" thisisalongenoughelementnametotriggerareallocation foo"),
+ XCS("http://example.org/ a bar")};
+ int i;
+ const int max_alloc_count = 30;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetReturnNSTriplet(g_parser, XML_TRUE);
+ XML_SetUserData(g_parser, (void *)elemstr);
+ XML_SetElementHandler(g_parser, triplet_start_checker, triplet_end_checker);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+/* Test the effects of reallocation failure when reassigning a
+ * binding.
+ *
+ * XML_ParserReset does not free the BINDING structures used by a
+ * parser, but instead adds them to an internal free list to be reused
+ * as necessary. Likewise the URI buffers allocated for the binding
+ * aren't freed, but kept attached to their existing binding. If the
+ * new binding has a longer URI, it will need reallocation. This test
+ * provokes that reallocation, and tests the control path if it fails.
+ */
+START_TEST(test_nsalloc_realloc_binding_uri) {
+ const char *first = "<doc xmlns='http://example.org/'>\n"
+ " <e xmlns='' />\n"
+ "</doc>";
+ const char *second
+ = "<doc xmlns='http://example.org/long/enough/URI/to/reallocate/'>\n"
+ " <e xmlns='' />\n"
+ "</doc>";
+ unsigned i;
+ const unsigned max_realloc_count = 10;
+
+ /* First, do a full parse that will leave bindings around */
+ if (_XML_Parse_SINGLE_BYTES(g_parser, first, (int)strlen(first), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(g_parser);
+
+ /* Now repeat with a longer URI and a duff reallocator */
+ for (i = 0; i < max_realloc_count; i++) {
+ XML_ParserReset(g_parser, NULL);
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, second, (int)strlen(second), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocation");
+ else if (i == max_realloc_count)
+ fail("Parsing failed at max reallocation count");
+}
+END_TEST
+
+/* Check handling of long prefix names (pool growth) */
+START_TEST(test_nsalloc_realloc_long_prefix) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":foo>";
+ int i;
+ const int max_realloc_count = 12;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+/* Check handling of even long prefix names (different code path) */
+START_TEST(test_nsalloc_realloc_longer_prefix) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "Q:foo xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "Q='http://example.org/'>"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "Q:foo>";
+ int i;
+ const int max_realloc_count = 12;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_namespace) {
+ const char *text1
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":e xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "='http://example.org/'>\n";
+ const char *text2
+ = "<"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":f "
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":attr='foo'/>\n"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ ":e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ != XML_STATUS_ERROR
+ && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
+ XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* Using a slightly shorter namespace name provokes allocations in
+ * slightly different places in the code.
+ */
+START_TEST(test_nsalloc_less_long_namespace) {
+ const char *text
+ = "<"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":e xmlns:"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ "='http://example.org/'>\n"
+ "<"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":f "
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":att='foo'/>\n"
+ "</"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AZ"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345678"
+ ":e>";
+ int i;
+ const int max_alloc_count = 40;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_context) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ATTLIST doc baz ID #REQUIRED>\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
+ "' baz='2'>\n"
+ "&en;"
+ "</doc>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 70;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+/* This function is void; it will throw a fail() on error, so if it
+ * returns normally it must have succeeded.
+ */
+static void
+context_realloc_test(const char *text) {
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_realloc_count = 6;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+
+START_TEST(test_nsalloc_realloc_long_context) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
"]>\n"
- "<doc xmlns='http://xml.libexpat.org/ns1'>\n"
- "&en;\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKL"
+ "'>\n"
+ "&en;"
"</doc>";
- XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
- XML_SetExternalEntityRefHandler(parser, external_entity_handler);
- /* We actually need to set this handler to tickle this bug. */
- XML_SetStartElementHandler(parser, dummy_start_element);
- XML_SetUserData(parser, NULL);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+ context_realloc_test(text);
}
END_TEST
-/* Regression test #1 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_1)
-{
- char *text =
- "<doc xmlns:prefix='http://xml.libexpat.org/'>\n"
- " <e xmlns:prefix=''/>\n"
+START_TEST(test_nsalloc_realloc_long_context_2) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJK"
+ "'>\n"
+ "&en;"
"</doc>";
- expect_failure(text,
- XML_ERROR_UNDECLARING_PREFIX,
- "Did not report re-setting namespace"
- " URI with prefix to ''.");
+ context_realloc_test(text);
}
END_TEST
-/* Regression test #2 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_2)
-{
- char *text =
- "<?xml version='1.0'?>\n"
- "<docelem xmlns:pre=''/>";
+START_TEST(test_nsalloc_realloc_long_context_3) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGH"
+ "'>\n"
+ "&en;"
+ "</doc>";
- expect_failure(text,
- XML_ERROR_UNDECLARING_PREFIX,
- "Did not report setting namespace URI with prefix to ''.");
+ context_realloc_test(text);
}
END_TEST
-/* Regression test #3 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_3)
-{
- char *text =
- "<!DOCTYPE doc [\n"
- " <!ELEMENT doc EMPTY>\n"
- " <!ATTLIST doc\n"
- " xmlns:prefix CDATA ''>\n"
+START_TEST(test_nsalloc_realloc_long_context_4) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
"]>\n"
- "<doc/>";
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO"
+ "'>\n"
+ "&en;"
+ "</doc>";
- expect_failure(text,
- XML_ERROR_UNDECLARING_PREFIX,
- "Didn't report attr default setting NS w/ prefix to ''.");
+ context_realloc_test(text);
}
END_TEST
-/* Regression test #4 for SF bug #673791. */
-START_TEST(test_ns_prefix_with_empty_uri_4)
-{
- char *text =
- "<!DOCTYPE doc [\n"
- " <!ELEMENT prefix:doc EMPTY>\n"
- " <!ATTLIST prefix:doc\n"
- " xmlns:prefix CDATA 'http://xml.libexpat.org/'>\n"
+START_TEST(test_nsalloc_realloc_long_context_5) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
"]>\n"
- "<prefix:doc/>";
- /* Packaged info expected by the end element handler;
- the weird structuring lets us re-use the triplet_end_checker()
- function also used for another test. */
- char *elemstr[] = {
- "http://xml.libexpat.org/ doc prefix"
- };
- XML_SetReturnNSTriplet(parser, XML_TRUE);
- XML_SetUserData(parser, elemstr);
- XML_SetEndElementHandler(parser, triplet_end_checker);
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
-}
-END_TEST
-
-START_TEST(test_ns_default_with_empty_uri)
-{
- char *text =
- "<doc xmlns='http://xml.libexpat.org/'>\n"
- " <e xmlns=''/>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABC"
+ "'>\n"
+ "&en;"
"</doc>";
- if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
- xml_failure(parser);
+
+ context_realloc_test(text);
}
END_TEST
-/* Regression test for SF bug #692964: two prefixes for one namespace. */
-START_TEST(test_ns_duplicate_attrs_diff_prefixes)
-{
- char *text =
- "<doc xmlns:a='http://xml.libexpat.org/a'\n"
- " xmlns:b='http://xml.libexpat.org/a'\n"
- " a:a='v' b:a='v' />";
- expect_failure(text,
- XML_ERROR_DUPLICATE_ATTRIBUTE,
- "did not report multiple attributes with same URI+name");
+START_TEST(test_nsalloc_realloc_long_context_6) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNOP"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
}
END_TEST
-/* Regression test for SF bug #695401: unbound prefix. */
-START_TEST(test_ns_unbound_prefix_on_attribute)
-{
- char *text = "<doc a:attr=''/>";
- expect_failure(text,
- XML_ERROR_UNBOUND_PREFIX,
- "did not report unbound prefix on attribute");
+START_TEST(test_nsalloc_realloc_long_context_7) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLM"
+ "'>\n"
+ "&en;"
+ "</doc>";
+
+ context_realloc_test(text);
}
END_TEST
-/* Regression test for SF bug #695401: unbound prefix. */
-START_TEST(test_ns_unbound_prefix_on_element)
-{
- char *text = "<a:doc/>";
- expect_failure(text,
- XML_ERROR_UNBOUND_PREFIX,
- "did not report unbound prefix on element");
+START_TEST(test_nsalloc_realloc_long_ge_name) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY "
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ " SYSTEM 'bar'>\n"
+ "]>\n"
+ "<doc xmlns='http://example.org/baz'>\n"
+ "&"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ";"
+ "</doc>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT el EMPTY>"}, {XCS("bar"), "<el/>"}, {NULL, NULL}};
+ int i;
+ const int max_realloc_count = 10;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
}
END_TEST
-static Suite *
-make_suite(void)
-{
- Suite *s = suite_create("basic");
- TCase *tc_basic = tcase_create("basic tests");
- TCase *tc_namespace = tcase_create("XML namespaces");
-
- suite_add_tcase(s, tc_basic);
- tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
- tcase_add_test(tc_basic, test_nul_byte);
- tcase_add_test(tc_basic, test_u0000_char);
- tcase_add_test(tc_basic, test_bom_utf8);
- tcase_add_test(tc_basic, test_bom_utf16_be);
- tcase_add_test(tc_basic, test_bom_utf16_le);
- tcase_add_test(tc_basic, test_illegal_utf8);
- tcase_add_test(tc_basic, test_utf16);
- tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
- tcase_add_test(tc_basic, test_latin1_umlauts);
- /* Regression test for SF bug #491986. */
- tcase_add_test(tc_basic, test_danish_latin1);
- /* Regression test for SF bug #514281. */
- tcase_add_test(tc_basic, test_french_charref_hexidecimal);
- tcase_add_test(tc_basic, test_french_charref_decimal);
- tcase_add_test(tc_basic, test_french_latin1);
- tcase_add_test(tc_basic, test_french_utf8);
- tcase_add_test(tc_basic, test_utf8_false_rejection);
- tcase_add_test(tc_basic, test_line_number_after_parse);
- tcase_add_test(tc_basic, test_column_number_after_parse);
- tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
- tcase_add_test(tc_basic, test_line_number_after_error);
- tcase_add_test(tc_basic, test_column_number_after_error);
- tcase_add_test(tc_basic, test_really_long_lines);
- tcase_add_test(tc_basic, test_end_element_events);
- tcase_add_test(tc_basic, test_attr_whitespace_normalization);
- tcase_add_test(tc_basic, test_xmldecl_misplaced);
- tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
- tcase_add_test(tc_basic,
- test_wfc_undeclared_entity_unread_external_subset);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
- tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
- tcase_add_test(tc_basic,
- test_wfc_undeclared_entity_with_external_subset_standalone);
- tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
- tcase_add_test(tc_basic, test_ext_entity_set_encoding);
- tcase_add_test(tc_basic, test_dtd_default_handling);
- tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
- tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
- tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
- tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
-
- suite_add_tcase(s, tc_namespace);
- tcase_add_checked_fixture(tc_namespace,
- namespace_setup, namespace_teardown);
- tcase_add_test(tc_namespace, test_return_ns_triplet);
- tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
- tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
- tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
- tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
- tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
- tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
- tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
- tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
- tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
-
- return s;
+/* Test that when a namespace is passed through the context mechanism
+ * to an external entity parser, the parsers handle reallocation
+ * failures correctly. The prefix is exactly the right length to
+ * provoke particular uncommon code paths.
+ */
+START_TEST(test_nsalloc_realloc_long_context_in_dtd) {
+ const char *text1
+ = "<!DOCTYPE "
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":doc [\n"
+ " <!ENTITY First SYSTEM 'foo/First'>\n"
+ "]>\n"
+ "<"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":doc xmlns:"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "='foo/Second'>&First;";
+ const char *text2
+ = "</"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ ":doc>";
+ ExtOption options[] = {{XCS("foo/First"), "Hello world"}, {NULL, NULL}};
+ int i;
+ const int max_realloc_count = 20;
+
+ for (i = 0; i < max_realloc_count; i++) {
+ reallocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text1, (int)strlen(text1), XML_FALSE)
+ != XML_STATUS_ERROR
+ && _XML_Parse_SINGLE_BYTES(g_parser, text2, (int)strlen(text2),
+ XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing reallocations");
+ else if (i == max_realloc_count)
+ fail("Parsing failed even at max reallocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_default_in_ext) {
+ const char *text
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST e a1 CDATA '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"
+ "'>\n"
+ " <!ENTITY x SYSTEM 'foo'>\n"
+ "]>\n"
+ "<doc>&x;</doc>";
+ ExtOption options[] = {{XCS("foo"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 50;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
+}
+END_TEST
+
+START_TEST(test_nsalloc_long_systemid_in_ext) {
+ const char *text
+ = "<!DOCTYPE doc SYSTEM 'foo' [\n"
+ " <!ENTITY en SYSTEM '"
+ /* 64 characters per line */
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"
+ "'>\n"
+ "]>\n"
+ "<doc>&en;</doc>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"},
+ {/* clang-format off */
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/")
+ XCS("ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/ABCDEFGHIJKLMNO/"),
+ /* clang-format on */
+ "<e/>"},
+ {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 55;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Parsing worked despite failing allocations");
+ else if (i == max_alloc_count)
+ fail("Parsing failed even at max allocation count");
}
+END_TEST
+
+/* Test the effects of allocation failure on parsing an element in a
+ * namespace. Based on test_nsalloc_long_context.
+ */
+START_TEST(test_nsalloc_prefixed_element) {
+ const char *text = "<!DOCTYPE pfx:element SYSTEM 'foo' [\n"
+ " <!ATTLIST pfx:element baz ID #REQUIRED>\n"
+ " <!ENTITY en SYSTEM 'bar'>\n"
+ "]>\n"
+ "<pfx:element xmlns:pfx='http://example.org/' baz='2'>\n"
+ "&en;"
+ "</pfx:element>";
+ ExtOption options[] = {
+ {XCS("foo"), "<!ELEMENT e EMPTY>"}, {XCS("bar"), "<e/>"}, {NULL, NULL}};
+ int i;
+ const int max_alloc_count = 70;
+
+ for (i = 0; i < max_alloc_count; i++) {
+ allocation_count = i;
+ XML_SetUserData(g_parser, options);
+ XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetExternalEntityRefHandler(g_parser, external_entity_optioner);
+ if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_ERROR)
+ break;
+
+ /* See comment in test_nsalloc_xmlns() */
+ nsalloc_teardown();
+ nsalloc_setup();
+ }
+ if (i == 0)
+ fail("Success despite failing allocator");
+ else if (i == max_alloc_count)
+ fail("Failed even at full allocation count");
+}
+END_TEST
+static Suite *
+make_suite(void) {
+ Suite *s = suite_create("basic");
+ TCase *tc_basic = tcase_create("basic tests");
+ TCase *tc_namespace = tcase_create("XML namespaces");
+ TCase *tc_misc = tcase_create("miscellaneous tests");
+ TCase *tc_alloc = tcase_create("allocation tests");
+ TCase *tc_nsalloc = tcase_create("namespace allocation tests");
+
+ suite_add_tcase(s, tc_basic);
+ tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
+ tcase_add_test(tc_basic, test_nul_byte);
+ tcase_add_test(tc_basic, test_u0000_char);
+ tcase_add_test(tc_basic, test_siphash_self);
+ tcase_add_test(tc_basic, test_siphash_spec);
+ tcase_add_test(tc_basic, test_bom_utf8);
+ tcase_add_test(tc_basic, test_bom_utf16_be);
+ tcase_add_test(tc_basic, test_bom_utf16_le);
+ tcase_add_test(tc_basic, test_nobom_utf16_le);
+ tcase_add_test(tc_basic, test_illegal_utf8);
+ tcase_add_test(tc_basic, test_utf8_auto_align);
+ tcase_add_test(tc_basic, test_utf16);
+ tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
+ tcase_add_test(tc_basic, test_not_utf16);
+ tcase_add_test(tc_basic, test_bad_encoding);
+ tcase_add_test(tc_basic, test_latin1_umlauts);
+ tcase_add_test(tc_basic, test_long_utf8_character);
+ tcase_add_test(tc_basic, test_long_latin1_attribute);
+ tcase_add_test(tc_basic, test_long_ascii_attribute);
+ /* Regression test for SF bug #491986. */
+ tcase_add_test(tc_basic, test_danish_latin1);
+ /* Regression test for SF bug #514281. */
+ tcase_add_test(tc_basic, test_french_charref_hexidecimal);
+ tcase_add_test(tc_basic, test_french_charref_decimal);
+ tcase_add_test(tc_basic, test_french_latin1);
+ tcase_add_test(tc_basic, test_french_utf8);
+ tcase_add_test(tc_basic, test_utf8_false_rejection);
+ tcase_add_test(tc_basic, test_line_number_after_parse);
+ tcase_add_test(tc_basic, test_column_number_after_parse);
+ tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
+ tcase_add_test(tc_basic, test_line_number_after_error);
+ tcase_add_test(tc_basic, test_column_number_after_error);
+ tcase_add_test(tc_basic, test_really_long_lines);
+ tcase_add_test(tc_basic, test_really_long_encoded_lines);
+ tcase_add_test(tc_basic, test_end_element_events);
+ tcase_add_test(tc_basic, test_attr_whitespace_normalization);
+ tcase_add_test(tc_basic, test_xmldecl_misplaced);
+ tcase_add_test(tc_basic, test_xmldecl_invalid);
+ tcase_add_test(tc_basic, test_xmldecl_missing_attr);
+ tcase_add_test(tc_basic, test_xmldecl_missing_value);
+ tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
+ tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_unread_external_subset);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
+ tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
+ tcase_add_test(tc_basic, test_not_standalone_handler_reject);
+ tcase_add_test(tc_basic, test_not_standalone_handler_accept);
+ tcase_add_test(tc_basic,
+ test_wfc_undeclared_entity_with_external_subset_standalone);
+ tcase_add_test(tc_basic, test_entity_with_external_subset_unless_standalone);
+ tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_no_handler);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_bom);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_bad_encoding_2);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_ext_entity_invalid_suspended_parse);
+ tcase_add_test(tc_basic, test_dtd_default_handling);
+ tcase_add_test(tc_basic, test_dtd_attr_handling);
+ tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
+ tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
+ tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
+ tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
+ tcase_add_test(tc_basic, test_repeated_stop_parser_between_char_data_calls);
+ tcase_add_test(tc_basic, test_good_cdata_ascii);
+ tcase_add_test(tc_basic, test_good_cdata_utf16);
+ tcase_add_test(tc_basic, test_good_cdata_utf16_le);
+ tcase_add_test(tc_basic, test_long_cdata_utf16);
+#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
+ tcase_add_test(tc_basic, test_multichar_cdata_utf16);
+#endif
+ tcase_add_test(tc_basic, test_utf16_bad_surrogate_pair);
+ tcase_add_test(tc_basic, test_bad_cdata);
+#ifndef XML_MIN_SIZE /* FIXME workaround -DXML_MIN_SIZE + ASan (issue #332) */
+ tcase_add_test(tc_basic, test_bad_cdata_utf16);
+#endif
+ tcase_add_test(tc_basic, test_stop_parser_between_cdata_calls);
+ tcase_add_test(tc_basic, test_suspend_parser_between_cdata_calls);
+ tcase_add_test(tc_basic, test_memory_allocation);
+ tcase_add_test(tc_basic, test_default_current);
+ tcase_add_test(tc_basic, test_dtd_elements);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_with_doctype);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_foreign_dtd_without_external_subset);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
+ tcase_add_test(tc_basic, test_set_base);
+ tcase_add_test(tc_basic, test_attributes);
+ tcase_add_test(tc_basic, test_reset_in_entity);
+ tcase_add_test(tc_basic, test_resume_invalid_parse);
+ tcase_add_test(tc_basic, test_resume_resuspended);
+ tcase_add_test(tc_basic, test_cdata_default);
+ tcase_add_test(tc_basic, test_subordinate_reset);
+ tcase_add_test(tc_basic, test_subordinate_suspend);
+ tcase_add_test(tc_basic, test_subordinate_xdecl_suspend);
+ tcase_add_test(tc_basic, test_subordinate_xdecl_abort);
+ tcase_add_test(tc_basic, test_explicit_encoding);
+ tcase_add_test(tc_basic, test_trailing_cr);
+ tcase_add_test(tc_basic, test_ext_entity_trailing_cr);
+ tcase_add_test(tc_basic, test_trailing_rsqb);
+ tcase_add_test(tc_basic, test_ext_entity_trailing_rsqb);
+ tcase_add_test(tc_basic, test_ext_entity_good_cdata);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_user_parameters);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_ref_parameter);
+ tcase_add_test(tc_basic, test_empty_parse);
+ tcase_add_test(tc_basic, test_get_buffer_1);
+ tcase_add_test(tc_basic, test_get_buffer_2);
+ tcase_add_test(tc_basic, test_byte_info_at_end);
+ tcase_add_test(tc_basic, test_byte_info_at_error);
+ tcase_add_test(tc_basic, test_byte_info_at_cdata);
+ tcase_add_test(tc_basic, test_predefined_entities);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_tag_in_dtd);
+ tcase_add_test(tc_basic, test_not_predefined_entities);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ignore_section_utf16_be);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_bad_ignore_section);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_external_entity_values);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_not_standalone);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_value_abort);
+ tcase_add_test(tc_basic, test_bad_public_doctype);
+ tcase_add_test(tc_basic, test_attribute_enum_value);
+ tcase_add_test(tc_basic, test_predefined_entity_redefinition);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_dtd_stop_processing);
+ tcase_add_test(tc_basic, test_public_notation_no_sysid);
+ tcase_add_test(tc_basic, test_nested_groups);
+ tcase_add_test(tc_basic, test_group_choice);
+ tcase_add_test(tc_basic, test_standalone_parameter_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_skipped_parameter_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_recursive_external_parameter_entity);
+ tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
+ tcase_add_test(tc_basic, test_suspend_xdecl);
+ tcase_add_test(tc_basic, test_abort_epilog);
+ tcase_add_test(tc_basic, test_abort_epilog_2);
+ tcase_add_test(tc_basic, test_suspend_epilog);
+ tcase_add_test(tc_basic, test_suspend_in_sole_empty_tag);
+ tcase_add_test(tc_basic, test_unfinished_epilog);
+ tcase_add_test(tc_basic, test_partial_char_in_epilog);
+ tcase_add_test(tc_basic, test_hash_collision);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_internal_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_resume_entity_with_syntax_error);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_suspend_resume_parameter_entity);
+ tcase_add_test(tc_basic, test_restart_on_error);
+ tcase_add_test(tc_basic, test_reject_lt_in_attribute_value);
+ tcase_add_test(tc_basic, test_reject_unfinished_param_in_att_value);
+ tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
+ tcase_add_test(tc_basic, test_standalone_internal_entity);
+ tcase_add_test(tc_basic, test_skipped_external_entity);
+ tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
+ tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
+ tcase_add_test(tc_basic, test_invalid_character_entity);
+ tcase_add_test(tc_basic, test_invalid_character_entity_2);
+ tcase_add_test(tc_basic, test_invalid_character_entity_3);
+ tcase_add_test(tc_basic, test_invalid_character_entity_4);
+ tcase_add_test(tc_basic, test_pi_handled_in_default);
+ tcase_add_test(tc_basic, test_comment_handled_in_default);
+ tcase_add_test(tc_basic, test_pi_yml);
+ tcase_add_test(tc_basic, test_pi_xnl);
+ tcase_add_test(tc_basic, test_pi_xmm);
+ tcase_add_test(tc_basic, test_utf16_pi);
+ tcase_add_test(tc_basic, test_utf16_be_pi);
+ tcase_add_test(tc_basic, test_utf16_be_comment);
+ tcase_add_test(tc_basic, test_utf16_le_comment);
+ tcase_add_test(tc_basic, test_missing_encoding_conversion_fn);
+ tcase_add_test(tc_basic, test_failing_encoding_conversion_fn);
+ tcase_add_test(tc_basic, test_unknown_encoding_success);
+ tcase_add_test(tc_basic, test_unknown_encoding_bad_name);
+ tcase_add_test(tc_basic, test_unknown_encoding_bad_name_2);
+ tcase_add_test(tc_basic, test_unknown_encoding_long_name_1);
+ tcase_add_test(tc_basic, test_unknown_encoding_long_name_2);
+ tcase_add_test(tc_basic, test_invalid_unknown_encoding);
+ tcase_add_test(tc_basic, test_unknown_ascii_encoding_ok);
+ tcase_add_test(tc_basic, test_unknown_ascii_encoding_fail);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_length);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_topbit);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_surrogate);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_high);
+ tcase_add_test(tc_basic, test_unknown_encoding_invalid_attr_value);
+ tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom);
+ tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom);
+ tcase_add_test(tc_basic, test_ext_entity_latin1_utf16le_bom2);
+ tcase_add_test(tc_basic, test_ext_entity_latin1_utf16be_bom2);
+ tcase_add_test(tc_basic, test_ext_entity_utf16_be);
+ tcase_add_test(tc_basic, test_ext_entity_utf16_le);
+ tcase_add_test(tc_basic, test_ext_entity_utf16_unknown);
+ tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
+ tcase_add_test(tc_basic, test_utf8_in_cdata_section);
+ tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
+ tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
+ tcase_add_test(tc_basic, test_utf16_attribute);
+ tcase_add_test(tc_basic, test_utf16_second_attr);
+ tcase_add_test(tc_basic, test_attr_after_solidus);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_utf16_pe);
+ tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
+ tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
+ tcase_add_test(tc_basic, test_bad_doctype);
+ tcase_add_test(tc_basic, test_bad_doctype_utf16);
+ tcase_add_test(tc_basic, test_bad_doctype_plus);
+ tcase_add_test(tc_basic, test_bad_doctype_star);
+ tcase_add_test(tc_basic, test_bad_doctype_query);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_unknown_encoding_bad_ignore);
+ tcase_add_test(tc_basic, test_entity_in_utf16_be_attr);
+ tcase_add_test(tc_basic, test_entity_in_utf16_le_attr);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_be);
+ tcase_add_test__ifdef_xml_dtd(tc_basic, test_entity_public_utf16_le);
+ tcase_add_test(tc_basic, test_short_doctype);
+ tcase_add_test(tc_basic, test_short_doctype_2);
+ tcase_add_test(tc_basic, test_short_doctype_3);
+ tcase_add_test(tc_basic, test_long_doctype);
+ tcase_add_test(tc_basic, test_bad_entity);
+ tcase_add_test(tc_basic, test_bad_entity_2);
+ tcase_add_test(tc_basic, test_bad_entity_3);
+ tcase_add_test(tc_basic, test_bad_entity_4);
+ tcase_add_test(tc_basic, test_bad_notation);
+ tcase_add_test(tc_basic, test_default_doctype_handler);
+ tcase_add_test(tc_basic, test_empty_element_abort);
+
+ suite_add_tcase(s, tc_namespace);
+ tcase_add_checked_fixture(tc_namespace, namespace_setup, namespace_teardown);
+ tcase_add_test(tc_namespace, test_return_ns_triplet);
+ tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
+ tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
+ tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
+ tcase_add_test__ifdef_xml_dtd(tc_namespace,
+ test_default_ns_from_ext_subset_and_ext_ge);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
+ tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
+ tcase_add_test(tc_namespace, test_ns_unbound_prefix);
+ tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
+ tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
+ tcase_add_test(tc_namespace, test_ns_duplicate_hashes);
+ tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
+ tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
+ tcase_add_test(tc_namespace, test_ns_parser_reset);
+ tcase_add_test(tc_namespace, test_ns_long_element);
+ tcase_add_test(tc_namespace, test_ns_mixed_prefix_atts);
+ tcase_add_test(tc_namespace, test_ns_extend_uri_buffer);
+ tcase_add_test(tc_namespace, test_ns_reserved_attributes);
+ tcase_add_test(tc_namespace, test_ns_reserved_attributes_2);
+ tcase_add_test(tc_namespace, test_ns_extremely_long_prefix);
+ tcase_add_test(tc_namespace, test_ns_unknown_encoding_success);
+ tcase_add_test(tc_namespace, test_ns_double_colon);
+ tcase_add_test(tc_namespace, test_ns_double_colon_element);
+ tcase_add_test(tc_namespace, test_ns_bad_attr_leafname);
+ tcase_add_test(tc_namespace, test_ns_bad_element_leafname);
+ tcase_add_test(tc_namespace, test_ns_utf16_leafname);
+ tcase_add_test(tc_namespace, test_ns_utf16_element_leafname);
+ tcase_add_test(tc_namespace, test_ns_utf16_doctype);
+ tcase_add_test(tc_namespace, test_ns_invalid_doctype);
+ tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
+
+ suite_add_tcase(s, tc_misc);
+ tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
+ tcase_add_test(tc_misc, test_misc_alloc_create_parser);
+ tcase_add_test(tc_misc, test_misc_alloc_create_parser_with_encoding);
+ tcase_add_test(tc_misc, test_misc_null_parser);
+ tcase_add_test(tc_misc, test_misc_error_string);
+ tcase_add_test(tc_misc, test_misc_version);
+ tcase_add_test(tc_misc, test_misc_features);
+ tcase_add_test(tc_misc, test_misc_attribute_leak);
+ tcase_add_test(tc_misc, test_misc_utf16le);
+ tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_1);
+ tcase_add_test(tc_misc, test_misc_stop_during_end_handler_issue_240_2);
+ tcase_add_test__ifdef_xml_dtd(
+ tc_misc, test_misc_deny_internal_entity_closing_doctype_issue_317);
+
+ suite_add_tcase(s, tc_alloc);
+ tcase_add_checked_fixture(tc_alloc, alloc_setup, alloc_teardown);
+ tcase_add_test(tc_alloc, test_alloc_parse_xdecl);
+ tcase_add_test(tc_alloc, test_alloc_parse_xdecl_2);
+ tcase_add_test(tc_alloc, test_alloc_parse_pi);
+ tcase_add_test(tc_alloc, test_alloc_parse_pi_2);
+ tcase_add_test(tc_alloc, test_alloc_parse_pi_3);
+ tcase_add_test(tc_alloc, test_alloc_parse_comment);
+ tcase_add_test(tc_alloc, test_alloc_parse_comment_2);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_create_external_parser);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_run_external_parser);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_copy_default_atts);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_external_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_ext_entity_set_encoding);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_internal_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_default_handling);
+ tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
+ tcase_add_test(tc_alloc, test_alloc_set_base);
+ tcase_add_test(tc_alloc, test_alloc_realloc_buffer);
+ tcase_add_test(tc_alloc, test_alloc_ext_entity_realloc_buffer);
+ tcase_add_test(tc_alloc, test_alloc_realloc_many_attributes);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_public_entity_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_subst_public_entity_value);
+ tcase_add_test(tc_alloc, test_alloc_parse_public_doctype);
+ tcase_add_test(tc_alloc, test_alloc_parse_public_doctype_long_name);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_set_foreign_dtd);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_attribute_enum_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_attribute_enum_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_implied_attribute);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_default_attribute);
+ tcase_add_test(tc_alloc, test_alloc_notation);
+ tcase_add_test(tc_alloc, test_alloc_public_notation);
+ tcase_add_test(tc_alloc, test_alloc_system_notation);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_groups);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_nested_groups);
+ tcase_add_test(tc_alloc, test_alloc_large_group);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_group_choice);
+ tcase_add_test(tc_alloc, test_alloc_pi_in_epilog);
+ tcase_add_test(tc_alloc, test_alloc_comment_in_epilog);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_long_attribute_value);
+ tcase_add_test(tc_alloc, test_alloc_attribute_whitespace);
+ tcase_add_test(tc_alloc, test_alloc_attribute_predefined_entity);
+ tcase_add_test(tc_alloc, test_alloc_long_attr_default_with_char_ref);
+ tcase_add_test(tc_alloc, test_alloc_long_attr_value);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_nested_entities);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc,
+ test_alloc_realloc_param_entity_newline);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_ce_extends_pe);
+ tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_realloc_attributes);
+ tcase_add_test(tc_alloc, test_alloc_long_doc_name);
+ tcase_add_test(tc_alloc, test_alloc_long_base);
+ tcase_add_test(tc_alloc, test_alloc_long_public_id);
+ tcase_add_test(tc_alloc, test_alloc_long_entity_value);
+ tcase_add_test(tc_alloc, test_alloc_long_notation);
+
+ suite_add_tcase(s, tc_nsalloc);
+ tcase_add_checked_fixture(tc_nsalloc, nsalloc_setup, nsalloc_teardown);
+ tcase_add_test(tc_nsalloc, test_nsalloc_xmlns);
+ tcase_add_test(tc_nsalloc, test_nsalloc_parse_buffer);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_uri);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_attr);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_attr_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_attributes);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_element);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_binding_uri);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_longer_prefix);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_namespace);
+ tcase_add_test(tc_nsalloc, test_nsalloc_less_long_namespace);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_context);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_2);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_3);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_4);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_5);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_6);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_7);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_ge_name);
+ tcase_add_test(tc_nsalloc, test_nsalloc_realloc_long_context_in_dtd);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_default_in_ext);
+ tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
+ tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
+
+ return s;
+}
int
-main(int argc, char *argv[])
-{
- int i, nf;
- int verbosity = CK_NORMAL;
- Suite *s = make_suite();
- SRunner *sr = srunner_create(s);
-
- /* run the tests for internal helper functions */
- testhelper_is_whitespace_normalized();
-
- for (i = 1; i < argc; ++i) {
- char *opt = argv[i];
- if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
- verbosity = CK_VERBOSE;
- else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
- verbosity = CK_SILENT;
- else {
- fprintf(stderr, "runtests: unknown option '%s'\n", opt);
- return 2;
- }
+main(int argc, char *argv[]) {
+ int i, nf;
+ int verbosity = CK_NORMAL;
+ Suite *s = make_suite();
+ SRunner *sr = srunner_create(s);
+
+ /* run the tests for internal helper functions */
+ testhelper_is_whitespace_normalized();
+
+ for (i = 1; i < argc; ++i) {
+ char *opt = argv[i];
+ if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
+ verbosity = CK_VERBOSE;
+ else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
+ verbosity = CK_SILENT;
+ else {
+ fprintf(stderr, "runtests: unknown option '%s'\n", opt);
+ return 2;
}
- if (verbosity != CK_SILENT)
- printf("Expat version: %s\n", XML_ExpatVersion());
- srunner_run_all(sr, verbosity);
- nf = srunner_ntests_failed(sr);
- srunner_free(sr);
-
- return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+ if (verbosity != CK_SILENT)
+ printf("Expat version: %" XML_FMT_STR "\n", XML_ExpatVersion());
+ srunner_run_all(sr, verbosity);
+ nf = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/3rdparty/expat/tests/runtestspp.cpp b/3rdparty/expat/tests/runtestspp.cpp
index c35dc583d57..fd3ceaa97a3 100644
--- a/3rdparty/expat/tests/runtestspp.cpp
+++ b/3rdparty/expat/tests/runtestspp.cpp
@@ -1,6 +1,36 @@
-// C++ compilation harness for the test suite.
-//
-// This is used to ensure the Expat headers can be included from C++
-// and have everything work as expected.
-//
+/* C++ compilation harness for the test suite.
+
+ This is used to ensure the Expat headers can be included from C++
+ and have everything work as expected.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
#include "runtests.c"
diff --git a/3rdparty/expat/tests/structdata.c b/3rdparty/expat/tests/structdata.c
new file mode 100644
index 00000000000..e81b7b18460
--- /dev/null
+++ b/3rdparty/expat/tests/structdata.c
@@ -0,0 +1,155 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef HAVE_EXPAT_CONFIG_H
+# include "expat_config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "structdata.h"
+#include "minicheck.h"
+
+#define STRUCT_EXTENSION_COUNT 8
+
+#ifdef XML_UNICODE_WCHAR_T
+# include <wchar.h>
+# define XML_FMT_STR "ls"
+# define xcstrlen(s) wcslen(s)
+# define xcstrcmp(s, t) wcscmp((s), (t))
+#else
+# define XML_FMT_STR "s"
+# define xcstrlen(s) strlen(s)
+# define xcstrcmp(s, t) strcmp((s), (t))
+#endif
+
+static XML_Char *
+xmlstrdup(const XML_Char *s) {
+ size_t byte_count = (xcstrlen(s) + 1) * sizeof(XML_Char);
+ XML_Char *dup = malloc(byte_count);
+
+ assert(dup != NULL);
+ memcpy(dup, s, byte_count);
+ return dup;
+}
+
+void
+StructData_Init(StructData *storage) {
+ assert(storage != NULL);
+ storage->count = 0;
+ storage->max_count = 0;
+ storage->entries = NULL;
+}
+
+void
+StructData_AddItem(StructData *storage, const XML_Char *s, int data0, int data1,
+ int data2) {
+ StructDataEntry *entry;
+
+ assert(storage != NULL);
+ assert(s != NULL);
+ if (storage->count == storage->max_count) {
+ StructDataEntry *new;
+
+ storage->max_count += STRUCT_EXTENSION_COUNT;
+ new = realloc(storage->entries,
+ storage->max_count * sizeof(StructDataEntry));
+ assert(new != NULL);
+ storage->entries = new;
+ }
+
+ entry = &storage->entries[storage->count];
+ entry->str = xmlstrdup(s);
+ entry->data0 = data0;
+ entry->data1 = data1;
+ entry->data2 = data2;
+ storage->count++;
+}
+
+/* 'fail()' aborts the function via a longjmp, so there is no point
+ * in returning a value from this function.
+ */
+void
+StructData_CheckItems(StructData *storage, const StructDataEntry *expected,
+ int count) {
+ char buffer[1024];
+ int i;
+
+ assert(storage != NULL);
+ assert(expected != NULL);
+ if (count != storage->count) {
+ sprintf(buffer, "wrong number of entries: got %d, expected %d",
+ storage->count, count);
+ StructData_Dispose(storage);
+ fail(buffer);
+ } else {
+ for (i = 0; i < count; i++) {
+ const StructDataEntry *got = &storage->entries[i];
+ const StructDataEntry *want = &expected[i];
+
+ assert(got != NULL);
+ assert(want != NULL);
+
+ if (xcstrcmp(got->str, want->str) != 0) {
+ StructData_Dispose(storage);
+ fail("structure got bad string");
+ } else {
+ if (got->data0 != want->data0 || got->data1 != want->data1
+ || got->data2 != want->data2) {
+ sprintf(buffer,
+ "struct '%" XML_FMT_STR
+ "' expected (%d,%d,%d), got (%d,%d,%d)",
+ got->str, want->data0, want->data1, want->data2, got->data0,
+ got->data1, got->data2);
+ StructData_Dispose(storage);
+ fail(buffer);
+ }
+ }
+ }
+ }
+}
+
+void
+StructData_Dispose(StructData *storage) {
+ int i;
+
+ assert(storage != NULL);
+ for (i = 0; i < storage->count; i++)
+ free((void *)storage->entries[i].str);
+ free(storage->entries);
+
+ storage->count = 0;
+ storage->entries = NULL;
+}
diff --git a/3rdparty/expat/tests/structdata.h b/3rdparty/expat/tests/structdata.h
new file mode 100644
index 00000000000..870ffaf2af0
--- /dev/null
+++ b/3rdparty/expat/tests/structdata.h
@@ -0,0 +1,70 @@
+/* Interface to some helper routines used to accumulate and check
+ structured content.
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef XML_STRUCTDATA_H
+# define XML_STRUCTDATA_H 1
+
+# include "expat.h"
+
+typedef struct {
+ const XML_Char *str;
+ int data0;
+ int data1;
+ int data2;
+} StructDataEntry;
+
+typedef struct {
+ int count; /* Number of entries used */
+ int max_count; /* Number of StructDataEntry items in `entries` */
+ StructDataEntry *entries;
+} StructData;
+
+void StructData_Init(StructData *storage);
+
+void StructData_AddItem(StructData *storage, const XML_Char *s, int data0,
+ int data1, int data2);
+
+void StructData_CheckItems(StructData *storage, const StructDataEntry *expected,
+ int count);
+
+void StructData_Dispose(StructData *storage);
+
+#endif /* XML_STRUCTDATA_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/3rdparty/expat/tests/udiffer.py b/3rdparty/expat/tests/udiffer.py
new file mode 100755
index 00000000000..6fb91be7e3d
--- /dev/null
+++ b/3rdparty/expat/tests/udiffer.py
@@ -0,0 +1,62 @@
+#! /usr/bin/env python3
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import argparse
+import difflib
+import sys
+
+
+def _read_lines(filename):
+ try:
+ with open(filename) as f:
+ return f.readlines()
+ except UnicodeDecodeError:
+ with open(filename, encoding='utf_16') as f:
+ return f.readlines()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('first', metavar='FILE')
+ parser.add_argument('second', metavar='FILE')
+ config = parser.parse_args()
+
+ first = _read_lines(config.first)
+ second = _read_lines(config.second)
+
+ diffs = list(difflib.unified_diff(first, second, fromfile=config.first,
+ tofile=config.second))
+ if diffs:
+ sys.stdout.writelines(diffs)
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/3rdparty/expat/tests/xmltest.log.expected b/3rdparty/expat/tests/xmltest.log.expected
new file mode 100644
index 00000000000..032f5464243
--- /dev/null
+++ b/3rdparty/expat/tests/xmltest.log.expected
@@ -0,0 +1,10 @@
+Output differs: ibm/valid/P02/ibm02v01.xml
+ibm49i02.dtd: No such file or directory
+Expected not well-formed: ibm/not-wf/misc/432gewf.xml
+Expected not well-formed: xmltest/not-wf/not-sa/005.xml
+Expected not well-formed: sun/not-wf/uri01.xml
+Expected not well-formed: oasis/p06fail1.xml
+Expected not well-formed: oasis/p08fail1.xml
+Expected not well-formed: oasis/p08fail2.xml
+Passed: 1801
+Failed: 8
diff --git a/3rdparty/expat/tests/xmltest.sh b/3rdparty/expat/tests/xmltest.sh
index 793a5cc2819..9b500351143 100755
--- a/3rdparty/expat/tests/xmltest.sh
+++ b/3rdparty/expat/tests/xmltest.sh
@@ -1,4 +1,4 @@
-#! /bin/sh
+#! /usr/bin/env bash
# EXPAT TEST SCRIPT FOR W3C XML TEST SUITE
@@ -20,15 +20,18 @@
# produced by xmlwf conforms to an older definition of canonical XML
# and does not generate notation declarations.
+shopt -s nullglob
+
+# Note: OUTPUT must terminate with the directory separator.
+OUTPUT="$PWD/tests/out/"
+TS="$PWD/tests/"
+
MYDIR="`dirname \"$0\"`"
cd "$MYDIR"
MYDIR="`pwd`"
-XMLWF="`dirname \"$MYDIR\"`/xmlwf/xmlwf"
-# XMLWF=/usr/local/bin/xmlwf
-TS="$MYDIR/XML-Test-Suite"
-# OUTPUT must terminate with the directory separator.
-OUTPUT="$TS/out/"
-# OUTPUT=/home/tmp/xml-testsuite-out/
+XMLWF="${1:-`dirname \"$MYDIR\"`/xmlwf/xmlwf}"
+# Unicode-aware diff utility
+DIFF="${MYDIR}/udiffer.py"
# RunXmlwfNotWF file reldir
@@ -36,9 +39,7 @@ OUTPUT="$TS/out/"
RunXmlwfNotWF() {
file="$1"
reldir="$2"
- $XMLWF -p "$file" > outfile || return $?
- read outdata < outfile
- if test "$outdata" = "" ; then
+ if $XMLWF -p "$file" > /dev/null; then
echo "Expected not well-formed: $reldir$file"
return 1
else
@@ -51,11 +52,11 @@ RunXmlwfNotWF() {
RunXmlwfWF() {
file="$1"
reldir="$2"
- $XMLWF -p -d "$OUTPUT$reldir" "$file" > outfile || return $?
+ $XMLWF -p -N -d "$OUTPUT$reldir" "$file" > outfile || return $?
read outdata < outfile
if test "$outdata" = "" ; then
if [ -f "out/$file" ] ; then
- diff -u "$OUTPUT$reldir$file" "out/$file" > outfile
+ $DIFF "$OUTPUT$reldir$file" "out/$file" > outfile
if [ -s outfile ] ; then
cp outfile "$OUTPUT$reldir$file.diff"
echo "Output differs: $reldir$file"
@@ -96,11 +97,12 @@ for xmldir in ibm/valid/P* \
sun/invalid ; do
cd "$TS/xmlconf/$xmldir"
mkdir -p "$OUTPUT$xmldir"
- for xmlfile in *.xml ; do
+ for xmlfile in $(ls -1 *.xml | sort -d) ; do
+ [[ -f "$xmlfile" ]] || continue
RunXmlwfWF "$xmlfile" "$xmldir/"
UpdateStatus $?
done
- rm outfile
+ rm -f outfile
done
cd "$TS/xmlconf/oasis"
@@ -128,7 +130,6 @@ for xmldir in ibm/not-wf/P* \
RunXmlwfNotWF "$xmlfile" "$xmldir/"
UpdateStatus $?
done
- rm outfile
done
cd "$TS/xmlconf/oasis"
@@ -136,7 +137,6 @@ for xmlfile in *fail*.xml ; do
RunXmlwfNotWF "$xmlfile" "oasis/"
UpdateStatus $?
done
-rm outfile
echo "Passed: $SUCCESS"
echo "Failed: $ERROR"
diff --git a/3rdparty/expat/vms/README.vms b/3rdparty/expat/vms/README.vms
deleted file mode 100644
index 3dd2ca73fee..00000000000
--- a/3rdparty/expat/vms/README.vms
+++ /dev/null
@@ -1,23 +0,0 @@
-4-jun-2002 Craig A. Berry
- Added rudimentary build procedures for
- OpenVMS based on work by Martin Vorlaender.
-
-
-You'll need MMS or its freeware equivalent MMK. Just go to the
-top-level directory and type
-
-$ MMS/DESCRIPTION=[.vms]
-
- or
-
-$ MMK/DESCRIPTION=[.vms]
-
-You'll end up with the object library expat.olb. For now, installation
-consists merely of copying the object library, include files, and
-documentation to a suitable location.
-
-To-do list:
-
- -- create a shareable image
- -- build and run the tests and build the xmlwf utility
- -- create an install target
diff --git a/3rdparty/expat/vms/descrip.mms b/3rdparty/expat/vms/descrip.mms
deleted file mode 100644
index d9ee3d98e41..00000000000
--- a/3rdparty/expat/vms/descrip.mms
+++ /dev/null
@@ -1,70 +0,0 @@
-# Bare bones description file (Makefile) for OpenVMS
-
-PACKAGE = expat
-VERSION = 1.95.8
-EXPAT_MAJOR_VERSION=1
-EXPAT_MINOR_VERSION=95
-EXPAT_EDIT=8
-
-O = .obj
-OLB = .olb
-
-LIBRARY = expat$(OLB)
-LIBDIR = [.lib]
-SOURCES = $(LIBDIR)xmlparse.c $(LIBDIR)xmltok.c $(LIBDIR)xmlrole.c
-OBJECTS = xmlparse$(O) xmltok$(O) xmlrole$(O)
-
-TEMPLATES = xmltok_impl.c xmltok_ns.c
-APIHEADER = $(LIBDIR)expat.h
-HEADERS = $(LIBDIR)ascii.h $(LIBDIR)iasciitab.h $(LIBDIR)utf8tab.h $(LIBDIR)xmltok.h \
- $(LIBDIR)asciitab.h $(LIBDIR)latin1tab.h \
- $(LIBDIR)nametab.h $(LIBDIR)xmldef.h $(LIBDIR)xmlrole.h $(LIBDIR)xmltok_impl.h
-
-CONFIG_HEADER = expat_config.h
-INCLUDES = /INCLUDE=([],[.lib])
-DEFS = /DEFINE=(PACKAGE="""$(PACKAGE)""",VERSION="""$(PACKAGE)_$(VERSION)""",HAVE_EXPAT_CONFIG_H)
-LIBREVISION = 0
-LIBCURRENT = 1
-LIBAGE = 0
-#
-COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
-#
-# DISTFILES = $(DIST_COMMON) $(SOURCES) $(TEMPLATES) $(APIHEADER) $(HEADERS)
-#
-# TAR = gtar
-# GZIP_ENV = --best
-#
-.FIRST :
- IF F$SEARCH("$(LIBRARY)") .EQS. "" THEN $(LIBR) /CREATE /OBJECT $(LIBRARY)
-
-all : $(LIBRARY)
- @ write sys$output "All made."
-
-.SUFFIXES :
-.SUFFIXES : $(OLB) $(O) .C .H
-
-.c$(O) :
- $(COMPILE) $(MMS$SOURCE)
-
-$(O)$(OLB) :
- @ IF F$SEARCH("$(MMS$TARGET)") .EQS. "" -
- THEN LIBRARY/CREATE/LOG $(MMS$TARGET)
- @ LIBRARY /REPLACE /LOG $(MMS$TARGET) $(MMS$SOURCE)
-
-clean :
- DELETE $(LIBRARY);*,*$(O);*
-
-$(LIBRARY) : $(LIBRARY)( $(OBJECTS) )
- $(LIBR) /COMPRESS $(MMS$TARGET)
-
-$(CONFIG_HEADER) : [.vms]expat_config.h
- COPY/LOG $(MMS$SOURCE) $(MMS$TARGET)
-
-xmlparse$(O) : $(LIBDIR)xmlparse.c $(LIBDIR)expat.h $(LIBDIR)xmlrole.h $(LIBDIR)xmltok.h $(CONFIG_HEADER)
-
-xmlrole$(O) : $(LIBDIR)xmlrole.c $(LIBDIR)ascii.h $(LIBDIR)xmlrole.h $(CONFIG_HEADER)
-
-xmltok$(O) : $(LIBDIR)xmltok.c $(LIBDIR)xmltok_impl.c $(LIBDIR)xmltok_ns.c \
- $(LIBDIR)ascii.h $(LIBDIR)asciitab.h $(LIBDIR)iasciitab.h $(LIBDIR)latin1tab.h \
- $(LIBDIR)nametab.h $(LIBDIR)utf8tab.h $(LIBDIR)xmltok.h $(LIBDIR)xmltok_impl.h $(CONFIG_HEADER)
-
diff --git a/3rdparty/expat/vms/expat_config.h b/3rdparty/expat/vms/expat_config.h
deleted file mode 100644
index d5db89e56c6..00000000000
--- a/3rdparty/expat/vms/expat_config.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright 2000, Clark Cooper
- All rights reserved.
-
- This is free software. You are permitted to copy, distribute, or modify
- it under the terms of the MIT/X license (contained in the COPYING file
- with this distribution.)
-*/
-
-/* Define to empty if the keyword does not work. */
-#undef const
-
-/* Define if you have a working `mmap' system call. */
-#undef HAVE_MMAP
-
-/* Define to `long' if <sys/types.h> doesn't define. */
-#undef off_t
-
-/* Define to `unsigned' if <sys/types.h> doesn't define. */
-#undef size_t
-
-/* Define if your processor stores words with the most significant
- byte first (like Motorola and SPARC, unlike Intel and VAX). */
-#undef WORDS_BIGENDIAN
-
-/* Define if you have the bcopy function. */
-#undef HAVE_BCOPY
-
-/* Define if you have the memmove function. */
-#define HAVE_MEMMOVE 1
-
-/* Define if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-#define XML_NS
-#define XML_DTD
-
-#ifdef WORDS_BIGENDIAN
-#define XML_BYTE_ORDER 21
-#else
-#define XML_BYTE_ORDER 12
-#endif
-
-#define XML_CONTEXT_BYTES 1024
-
-#ifndef HAVE_MEMMOVE
-#ifdef HAVE_BCOPY
-#define memmove(d,s,l) bcopy((s),(d),(l))
-#else
-#define memmove(d,s,l) ;punting on memmove;
-#endif
-
-#endif
diff --git a/3rdparty/expat/win32/MANIFEST.txt b/3rdparty/expat/win32/MANIFEST.txt
index b7cd3954385..58201fa1679 100644
--- a/3rdparty/expat/win32/MANIFEST.txt
+++ b/3rdparty/expat/win32/MANIFEST.txt
@@ -17,11 +17,9 @@ directory you specified to the installer.
The XML well-formedness checker xmlwf.
<top>\Source\ Source code, which may interest some developers,
- including a workspace for Microsft Visual C++.
+ including a workspace for Microsoft Visual C++.
The source code includes the parser, the well-
formedness checker, and a couple of small sample
applications.
- <top>\Source\bcb5\ Project files for Borland C++ Builder 5 and BCC 5.5.
-
diff --git a/3rdparty/expat/win32/README.txt b/3rdparty/expat/win32/README.txt
index e3702ae6217..d1069cdd2f0 100644
--- a/3rdparty/expat/win32/README.txt
+++ b/3rdparty/expat/win32/README.txt
@@ -1,26 +1,22 @@
-Expat can be built on Windows in three ways:
- using MS Visual C++ (6.0 or .NET), Borland C++ Builder 5 or Cygwin.
+Expat can be built on Windows in two ways:
+ using MS Visual Studio .NET or Cygwin.
* Cygwin:
This follows the Unix build procedures.
-* C++ Builder 5:
- Possible with make files in the BCB5 subdirectory.
- Details can be found in the ReadMe file located there.
+* MS Visual Studio 2008, 2010, 2013, 2015 and 2017:
+ Use CMake to generate a solution file for Visual Studio, then use msbuild
+ to compile. For example:
-* MS Visual C++ 6:
- Based on the workspace file expat.dsw. The related project
- files (.dsp) are located in the lib subdirectory.
-
-* MS Visual Studio .NET 2002, 2003, 2005, 2008, 2010:
- The VC++ 6 workspace file (expat.dsw) and project files (.dsp)
- can be opened and imported in VS.NET without problems.
+ md build
+ cd build
+ cmake -G"Visual Studio 15 2017" -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
+ msbuild /m expat.sln
* All MS C/C++ compilers:
- The output for all projects will be generated in the win32\bin
- directory, intermediate files will be located in project-specific
- subdirectories of win32\tmp.
+ The output for all projects will be generated in the <CMAKE_BUILD_TYPE>\
+ and xmlwf\<CMAKE_BUILD_TYPE>\ directories.
* Creating MinGW dynamic libraries from MS VC++ DLLs:
@@ -42,39 +38,23 @@ Expat can be built on Windows in three ways:
Dynamic Linking:
- By default the Expat Dlls are built to link statically
+ By default the Expat Dlls are built to link dynamically
with the multi-threaded run-time library.
The libraries are named
- libexpat(w).dll
- libexpat(w).lib (import library)
The "w" indicates the UTF-16 version of the library.
- One rarely uses other versions of the Dll, but they can
- be built easily by specifying a different RTL linkage in
- the IDE on the C/C++ tab under the category Code Generation.
+ Versions that are statically linking with the multi-threaded run-time library
+ can be built with -DEXPAT_MSVC_STATIC_CRT=ON.
- Static Linking:
+ Static Linking: (through -DEXPAT_SHARED_LIBS=OFF)
The libraries should be named like this:
- Single-theaded: libexpat(w)ML.lib
Multi-threaded: libexpat(w)MT.lib
Multi-threaded Dll: libexpat(w)MD.lib
The suffixes conform to the compiler switch settings
- /ML, /MT and /MD for MS VC++.
-
- Note: In Visual Studio 2005 (Visual C++ 8.0) and later, the
- single-threaded runtime library is not supported anymore.
-
- By default, the expat-static and expatw-static projects are set up
- to link statically against the multithreaded run-time library,
- so they will build libexpatMT.lib or libexpatwMT.lib files.
-
- To build the other versions of the static library,
- go to Project - Settings:
- - specify a different RTL linkage on the C/C++ tab
- under the category Code Generation.
- - then, on the Library tab, change the output file name
- accordingly, as described above
+ /MT and /MD for MS VC++.
An application linking to the static libraries must
have the global macro XML_STATIC defined.
diff --git a/3rdparty/expat/win32/build_expat_iss.bat b/3rdparty/expat/win32/build_expat_iss.bat
new file mode 100644
index 00000000000..4e31c17dfc3
--- /dev/null
+++ b/3rdparty/expat/win32/build_expat_iss.bat
@@ -0,0 +1,84 @@
+REM Batch script to build Inno Setup installer for libexpat for Windows
+REM Call from parent directory, e.g.: cmd /c win32\build_expat_iss.bat
+REM __ __ _
+REM ___\ \/ /_ __ __ _| |_
+REM / _ \\ /| '_ \ / _` | __|
+REM | __// \| |_) | (_| | |_
+REM \___/_/\_\ .__/ \__,_|\__|
+REM |_| XML parser
+REM
+REM Copyright (C) 2019 Expat development team
+REM Licensed under the MIT license:
+REM
+REM Permission is hereby granted, free of charge, to any person obtaining
+REM a copy of this software and associated documentation files (the
+REM "Software"), to deal in the Software without restriction, including
+REM without limitation the rights to use, copy, modify, merge, publish,
+REM distribute, sublicense, and/or sell copies of the Software, and to permit
+REM persons to whom the Software is furnished to do so, subject to the
+REM following conditions:
+REM
+REM The above copyright notice and this permission notice shall be included
+REM in all copies or substantial portions of the Software.
+REM
+REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+REM EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+REM MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+REM NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+REM DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+REM OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+REM USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+SET GENERATOR=Visual Studio 15 2017
+
+REM Read by msbuild!
+SET CONFIGURATION=RelWithDebInfo
+
+REM Where Inno Setup expects build results
+SET BINDIR=win32\bin\Release
+
+
+MD %BINDIR% || EXIT /b 1
+
+
+MD build_shared_char || EXIT /b 1
+CD build_shared_char || EXIT /b 1
+ cmake -G"%GENERATOR%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DEXPAT_MSVC_STATIC_CRT=ON -DEXPAT_BUILD_EXAMPLES=OFF -DEXPAT_BUILD_TESTS=OFF -DEXPAT_BUILD_TOOLS=OFF .. || EXIT /b 1
+ msbuild /m expat.sln || EXIT /b 1
+ DIR %CONFIGURATION% || EXIT /b 1
+ CD .. || EXIT /b 1
+COPY build_shared_char\%CONFIGURATION%\libexpat.dll %BINDIR%\ || EXIT /b 1
+COPY build_shared_char\%CONFIGURATION%\libexpat.lib %BINDIR%\ || EXIT /b 1
+
+
+MD build_static_char || EXIT /b 1
+CD build_static_char || EXIT /b 1
+ cmake -G"%GENERATOR%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DEXPAT_MSVC_STATIC_CRT=ON -DEXPAT_BUILD_EXAMPLES=OFF -DEXPAT_BUILD_TESTS=OFF -DEXPAT_SHARED_LIBS=OFF .. || EXIT /b 1
+ msbuild /m expat.sln || EXIT /b 1
+ DIR %CONFIGURATION% || EXIT /b 1
+ CD .. || EXIT /b 1
+COPY build_static_char\%CONFIGURATION%\libexpatMT.lib %BINDIR%\ || EXIT /b 1
+COPY build_static_char\xmlwf\%CONFIGURATION%\xmlwf.exe %BINDIR%\ || EXIT /b 1
+
+
+MD build_shared_wchar_t || EXIT /b 1
+CD build_shared_wchar_t || EXIT /b 1
+ cmake -G"%GENERATOR%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DEXPAT_MSVC_STATIC_CRT=ON -DEXPAT_BUILD_EXAMPLES=OFF -DEXPAT_BUILD_TESTS=OFF -DEXPAT_BUILD_TOOLS=OFF -DEXPAT_CHAR_TYPE=wchar_t .. || EXIT /b 1
+ msbuild /m expat.sln || EXIT /b 1
+ DIR %CONFIGURATION% || EXIT /b 1
+ CD .. || EXIT /b 1
+COPY build_shared_wchar_t\%CONFIGURATION%\libexpatw.dll %BINDIR%\ || EXIT /b 1
+COPY build_shared_wchar_t\%CONFIGURATION%\libexpatw.lib %BINDIR%\ || EXIT /b 1
+
+
+MD build_static_wchar_t || EXIT /b 1
+CD build_static_wchar_t || EXIT /b 1
+ cmake -G"%GENERATOR%" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DEXPAT_MSVC_STATIC_CRT=ON -DEXPAT_BUILD_EXAMPLES=OFF -DEXPAT_BUILD_TESTS=OFF -DEXPAT_BUILD_TOOLS=OFF -DEXPAT_SHARED_LIBS=OFF -DEXPAT_CHAR_TYPE=wchar_t .. || EXIT /b 1
+ msbuild /m expat.sln || EXIT /b 1
+ DIR %CONFIGURATION% || EXIT /b 1
+ CD .. || EXIT /b 1
+COPY build_static_wchar_t\%CONFIGURATION%\libexpatwMT.lib %BINDIR%\ || EXIT /b 1
+
+
+DIR %BINDIR% || EXIT /b 1
+iscc win32\expat.iss || EXIT /b 1
diff --git a/3rdparty/expat/win32/expat.iss b/3rdparty/expat/win32/expat.iss
index 793887b6474..ef95f175857 100644
--- a/3rdparty/expat/win32/expat.iss
+++ b/3rdparty/expat/win32/expat.iss
@@ -4,20 +4,23 @@
; This script was contributed by Tim Peters.
; It was designed for Inno Setup 2.0.19 but works with later versions as well.
+#define expatVer "2.2.10"
+
[Setup]
AppName=Expat
AppId=expat
-AppVersion=2.1.1
-AppVerName=Expat 2.1.1
-AppCopyright=Copyright © 1998-2012 Thai Open Source Software Center, Clark Cooper, and the Expat maintainers
+AppVersion={#expatVer}
+AppVerName=Expat {#expatVer}
+AppCopyright=Copyright © 1998-2017 Thai Open Source Software Center, Clark Cooper, and the Expat maintainers
AppPublisher=The Expat Developers
AppPublisherURL=http://www.libexpat.org/
AppSupportURL=http://www.libexpat.org/
AppUpdatesURL=http://www.libexpat.org/
-UninstallDisplayName=Expat XML Parser 2.1.1
-VersionInfoVersion=2.1.1
+UninstallDisplayName=Expat XML Parser {#expatVer}
+VersionInfoVersion={#expatVer}
+OutputBaseFilename=expat-win32bin-{#expatVer}
-DefaultDirName={pf}\Expat 2.1.1
+DefaultDirName={pf}\Expat {#expatVer}
UninstallFilesDir={app}\Uninstall
Compression=lzma
@@ -32,37 +35,34 @@ DisableReadyPage=yes
[Files]
Flags: ignoreversion; Source: win32\bin\Release\xmlwf.exe; DestDir: "{app}\Bin"
Flags: ignoreversion; Source: win32\MANIFEST.txt; DestDir: "{app}"
+Flags: ignoreversion; Source: AUTHORS; DestDir: "{app}"; DestName: AUTHORS.txt
Flags: ignoreversion; Source: Changes; DestDir: "{app}"; DestName: Changes.txt
Flags: ignoreversion; Source: COPYING; DestDir: "{app}"; DestName: COPYING.txt
-Flags: ignoreversion; Source: README; DestDir: "{app}"; DestName: README.txt
+Flags: ignoreversion; Source: README.md; DestDir: "{app}"; DestName: README.txt
Flags: ignoreversion; Source: doc\*.html; DestDir: "{app}\Doc"
Flags: ignoreversion; Source: doc\*.css; DestDir: "{app}\Doc"
Flags: ignoreversion; Source: doc\*.png; DestDir: "{app}\Doc"
Flags: ignoreversion; Source: win32\bin\Release\*.dll; DestDir: "{app}\Bin"
Flags: ignoreversion; Source: win32\bin\Release\*.lib; DestDir: "{app}\Bin"
-Flags: ignoreversion; Source: expat.dsw; DestDir: "{app}\Source"
Flags: ignoreversion; Source: win32\README.txt; DestDir: "{app}\Source"
-Flags: ignoreversion; Source: bcb5\*.bp*; DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.mak; DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.def; DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.txt; DestDir: "{app}\Source\bcb5"
-Flags: ignoreversion; Source: bcb5\*.bat; DestDir: "{app}\Source\bcb5"
+Flags: ignoreversion; Source: Changes; DestDir: "{app}\Source"
+Flags: ignoreversion; Source: CMake.README; DestDir: "{app}\Source"
+Flags: ignoreversion; Source: CMakeLists.txt; DestDir: "{app}\Source"
+Flags: ignoreversion; Source: ConfigureChecks.cmake; DestDir: "{app}\Source"
+Flags: ignoreversion; Source: expat_config.h.cmake; DestDir: "{app}\Source"
+Flags: ignoreversion; Source: cmake\expat-config.cmake.in; DestDir: "{app}\Source\cmake"
Flags: ignoreversion; Source: lib\*.c; DestDir: "{app}\Source\lib"
Flags: ignoreversion; Source: lib\*.h; DestDir: "{app}\Source\lib"
Flags: ignoreversion; Source: lib\*.def; DestDir: "{app}\Source\lib"
-Flags: ignoreversion; Source: lib\*.dsp; DestDir: "{app}\Source\lib"
Flags: ignoreversion; Source: examples\*.c; DestDir: "{app}\Source\examples"
-Flags: ignoreversion; Source: examples\*.dsp; DestDir: "{app}\Source\examples"
Flags: ignoreversion; Source: tests\*.c; DestDir: "{app}\Source\tests"
Flags: ignoreversion; Source: tests\*.cpp; DestDir: "{app}\Source\tests"
Flags: ignoreversion; Source: tests\*.h; DestDir: "{app}\Source\tests"
Flags: ignoreversion; Source: tests\README.txt; DestDir: "{app}\Source\tests"
Flags: ignoreversion; Source: tests\benchmark\*.c; DestDir: "{app}\Source\tests\benchmark"
-Flags: ignoreversion; Source: tests\benchmark\*.ds*; DestDir: "{app}\Source\tests\benchmark"
Flags: ignoreversion; Source: tests\benchmark\README.txt; DestDir: "{app}\Source\tests\benchmark"
Flags: ignoreversion; Source: xmlwf\*.c*; DestDir: "{app}\Source\xmlwf"
Flags: ignoreversion; Source: xmlwf\*.h; DestDir: "{app}\Source\xmlwf"
-Flags: ignoreversion; Source: xmlwf\*.dsp; DestDir: "{app}\Source\xmlwf"
[Messages]
WelcomeLabel1=Welcome to the Expat XML Parser Setup Wizard
diff --git a/3rdparty/expat/xmlwf/Makefile.am b/3rdparty/expat/xmlwf/Makefile.am
new file mode 100644
index 00000000000..f35ade7a77a
--- /dev/null
+++ b/3rdparty/expat/xmlwf/Makefile.am
@@ -0,0 +1,60 @@
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+bin_PROGRAMS = xmlwf
+
+xmlwf_LDADD = ../lib/libexpat.la
+xmlwf_SOURCES = \
+ xmlwf.c \
+ xmlfile.c \
+ codepage.c \
+ @FILEMAP@.c
+
+xmlwf_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+xmlwf_LDFLAGS = @AM_LDFLAGS@
+
+if MINGW
+if UNICODE
+xmlwf_CPPFLAGS += -mwindows
+xmlwf_LDFLAGS += -municode
+endif
+endif
+
+EXTRA_DIST = \
+ codepage.h \
+ ct.c \
+ filemap.h \
+ readfilemap.c \
+ unixfilemap.c \
+ win32filemap.c \
+ xmlfile.h \
+ xmlmime.c \
+ xmlmime.h \
+ xmltchar.h
diff --git a/3rdparty/expat/xmlwf/Makefile.in b/3rdparty/expat/xmlwf/Makefile.in
new file mode 100644
index 00000000000..531475ab243
--- /dev/null
+++ b/3rdparty/expat/xmlwf/Makefile.in
@@ -0,0 +1,783 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 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.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2017 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = xmlwf$(EXEEXT)
+@MINGW_TRUE@@UNICODE_TRUE@am__append_1 = -mwindows
+@MINGW_TRUE@@UNICODE_TRUE@am__append_2 = -municode
+subdir = xmlwf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/conftools/ax-require-defined.m4 \
+ $(top_srcdir)/conftools/ax-check-compile-flag.m4 \
+ $(top_srcdir)/conftools/ax-check-link-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-flag.m4 \
+ $(top_srcdir)/conftools/ax-append-compile-flags.m4 \
+ $(top_srcdir)/conftools/ax-append-link-flags.m4 \
+ $(top_srcdir)/conftools/expatcfg-compiler-supports-visibility.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/expat_config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_xmlwf_OBJECTS = xmlwf-xmlwf.$(OBJEXT) xmlwf-xmlfile.$(OBJEXT) \
+ xmlwf-codepage.$(OBJEXT) xmlwf-@FILEMAP@.$(OBJEXT)
+xmlwf_OBJECTS = $(am_xmlwf_OBJECTS)
+xmlwf_DEPENDENCIES = ../lib/libexpat.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+xmlwf_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(xmlwf_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/conftools/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/xmlwf-@FILEMAP@.Po \
+ ./$(DEPDIR)/xmlwf-codepage.Po ./$(DEPDIR)/xmlwf-xmlfile.Po \
+ ./$(DEPDIR)/xmlwf-xmlwf.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(xmlwf_SOURCES)
+DIST_SOURCES = $(xmlwf_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/conftools/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CFLAGS = @AM_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_CXXFLAGS = @AM_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LDFLAGS = @AM_LDFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOCBOOK_TO_MAN = @DOCBOOK_TO_MAN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILEMAP = @FILEMAP@
+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@
+LIBAGE = @LIBAGE@
+LIBCURRENT = @LIBCURRENT@
+LIBOBJS = @LIBOBJS@
+LIBREVISION = @LIBREVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+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@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+_EXPAT_OUTPUT_NAME = @_EXPAT_OUTPUT_NAME@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+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@
+xmlwf_LDADD = ../lib/libexpat.la
+xmlwf_SOURCES = \
+ xmlwf.c \
+ xmlfile.c \
+ codepage.c \
+ @FILEMAP@.c
+
+xmlwf_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib $(am__append_1)
+xmlwf_LDFLAGS = @AM_LDFLAGS@ $(am__append_2)
+EXTRA_DIST = \
+ codepage.h \
+ ct.c \
+ filemap.h \
+ readfilemap.c \
+ unixfilemap.c \
+ win32filemap.c \
+ xmlfile.h \
+ xmlmime.c \
+ xmlmime.h \
+ xmltchar.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu xmlwf/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu xmlwf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ 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)'; 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)'; 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
+
+xmlwf$(EXEEXT): $(xmlwf_OBJECTS) $(xmlwf_DEPENDENCIES) $(EXTRA_xmlwf_DEPENDENCIES)
+ @rm -f xmlwf$(EXEEXT)
+ $(AM_V_CCLD)$(xmlwf_LINK) $(xmlwf_OBJECTS) $(xmlwf_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-@FILEMAP@.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-codepage.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-xmlfile.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlwf-xmlwf.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+xmlwf-xmlwf.o: xmlwf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-xmlwf.o -MD -MP -MF $(DEPDIR)/xmlwf-xmlwf.Tpo -c -o xmlwf-xmlwf.o `test -f 'xmlwf.c' || echo '$(srcdir)/'`xmlwf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-xmlwf.Tpo $(DEPDIR)/xmlwf-xmlwf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xmlwf.c' object='xmlwf-xmlwf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-xmlwf.o `test -f 'xmlwf.c' || echo '$(srcdir)/'`xmlwf.c
+
+xmlwf-xmlwf.obj: xmlwf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-xmlwf.obj -MD -MP -MF $(DEPDIR)/xmlwf-xmlwf.Tpo -c -o xmlwf-xmlwf.obj `if test -f 'xmlwf.c'; then $(CYGPATH_W) 'xmlwf.c'; else $(CYGPATH_W) '$(srcdir)/xmlwf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-xmlwf.Tpo $(DEPDIR)/xmlwf-xmlwf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xmlwf.c' object='xmlwf-xmlwf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-xmlwf.obj `if test -f 'xmlwf.c'; then $(CYGPATH_W) 'xmlwf.c'; else $(CYGPATH_W) '$(srcdir)/xmlwf.c'; fi`
+
+xmlwf-xmlfile.o: xmlfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-xmlfile.o -MD -MP -MF $(DEPDIR)/xmlwf-xmlfile.Tpo -c -o xmlwf-xmlfile.o `test -f 'xmlfile.c' || echo '$(srcdir)/'`xmlfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-xmlfile.Tpo $(DEPDIR)/xmlwf-xmlfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xmlfile.c' object='xmlwf-xmlfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-xmlfile.o `test -f 'xmlfile.c' || echo '$(srcdir)/'`xmlfile.c
+
+xmlwf-xmlfile.obj: xmlfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-xmlfile.obj -MD -MP -MF $(DEPDIR)/xmlwf-xmlfile.Tpo -c -o xmlwf-xmlfile.obj `if test -f 'xmlfile.c'; then $(CYGPATH_W) 'xmlfile.c'; else $(CYGPATH_W) '$(srcdir)/xmlfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-xmlfile.Tpo $(DEPDIR)/xmlwf-xmlfile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xmlfile.c' object='xmlwf-xmlfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-xmlfile.obj `if test -f 'xmlfile.c'; then $(CYGPATH_W) 'xmlfile.c'; else $(CYGPATH_W) '$(srcdir)/xmlfile.c'; fi`
+
+xmlwf-codepage.o: codepage.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-codepage.o -MD -MP -MF $(DEPDIR)/xmlwf-codepage.Tpo -c -o xmlwf-codepage.o `test -f 'codepage.c' || echo '$(srcdir)/'`codepage.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-codepage.Tpo $(DEPDIR)/xmlwf-codepage.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codepage.c' object='xmlwf-codepage.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-codepage.o `test -f 'codepage.c' || echo '$(srcdir)/'`codepage.c
+
+xmlwf-codepage.obj: codepage.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-codepage.obj -MD -MP -MF $(DEPDIR)/xmlwf-codepage.Tpo -c -o xmlwf-codepage.obj `if test -f 'codepage.c'; then $(CYGPATH_W) 'codepage.c'; else $(CYGPATH_W) '$(srcdir)/codepage.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-codepage.Tpo $(DEPDIR)/xmlwf-codepage.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codepage.c' object='xmlwf-codepage.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-codepage.obj `if test -f 'codepage.c'; then $(CYGPATH_W) 'codepage.c'; else $(CYGPATH_W) '$(srcdir)/codepage.c'; fi`
+
+xmlwf-@FILEMAP@.o: @FILEMAP@.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-@FILEMAP@.o -MD -MP -MF $(DEPDIR)/xmlwf-@FILEMAP@.Tpo -c -o xmlwf-@FILEMAP@.o `test -f '@FILEMAP@.c' || echo '$(srcdir)/'`@FILEMAP@.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-@FILEMAP@.Tpo $(DEPDIR)/xmlwf-@FILEMAP@.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='@FILEMAP@.c' object='xmlwf-@FILEMAP@.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-@FILEMAP@.o `test -f '@FILEMAP@.c' || echo '$(srcdir)/'`@FILEMAP@.c
+
+xmlwf-@FILEMAP@.obj: @FILEMAP@.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xmlwf-@FILEMAP@.obj -MD -MP -MF $(DEPDIR)/xmlwf-@FILEMAP@.Tpo -c -o xmlwf-@FILEMAP@.obj `if test -f '@FILEMAP@.c'; then $(CYGPATH_W) '@FILEMAP@.c'; else $(CYGPATH_W) '$(srcdir)/@FILEMAP@.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/xmlwf-@FILEMAP@.Tpo $(DEPDIR)/xmlwf-@FILEMAP@.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='@FILEMAP@.c' object='xmlwf-@FILEMAP@.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(xmlwf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xmlwf-@FILEMAP@.obj `if test -f '@FILEMAP@.c'; then $(CYGPATH_W) '@FILEMAP@.c'; else $(CYGPATH_W) '$(srcdir)/@FILEMAP@.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @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; \
+ 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 -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/xmlwf-@FILEMAP@.Po
+ -rm -f ./$(DEPDIR)/xmlwf-codepage.Po
+ -rm -f ./$(DEPDIR)/xmlwf-xmlfile.Po
+ -rm -f ./$(DEPDIR)/xmlwf-xmlwf.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/xmlwf-@FILEMAP@.Po
+ -rm -f ./$(DEPDIR)/xmlwf-codepage.Po
+ -rm -f ./$(DEPDIR)/xmlwf-xmlfile.Po
+ -rm -f ./$(DEPDIR)/xmlwf-xmlwf.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir 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-info install-info-am install-man install-pdf \
+ install-pdf-am 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 tags-am uninstall uninstall-am uninstall-binPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# 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:
diff --git a/3rdparty/expat/xmlwf/codepage.c b/3rdparty/expat/xmlwf/codepage.c
index 57e48ff2d12..44d2035811d 100644
--- a/3rdparty/expat/xmlwf/codepage.c
+++ b/3rdparty/expat/xmlwf/codepage.c
@@ -1,26 +1,56 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "codepage.h"
+#include "internal.h" /* for UNUSED_P only */
-#if (defined(WIN32) || (defined(__WATCOMC__) && defined(__NT__)))
-#define STRICT 1
-#define WIN32_LEAN_AND_MEAN 1
+#if defined(_WIN32)
+# define STRICT 1
+# define WIN32_LEAN_AND_MEAN 1
-#include <windows.h>
+# include <windows.h>
+#endif /* defined(_WIN32) */
int
-codepageMap(int cp, int *map)
-{
+codepageMap(int cp, int *map) {
+#if defined(_WIN32)
int i;
CPINFO info;
- if (!GetCPInfo(cp, &info) || info.MaxCharSize > 2)
+ if (! GetCPInfo(cp, &info) || info.MaxCharSize > 2)
return 0;
for (i = 0; i < 256; i++)
map[i] = -1;
if (info.MaxCharSize > 1) {
- for (i = 0; i < MAX_LEADBYTES; i+=2) {
+ for (i = 0; i < MAX_LEADBYTES; i += 2) {
int j, lim;
if (info.LeadByte[i] == 0 && info.LeadByte[i + 1] == 0)
break;
@@ -30,39 +60,35 @@ codepageMap(int cp, int *map)
}
}
for (i = 0; i < 256; i++) {
- if (map[i] == -1) {
- char c = (char)i;
- unsigned short n;
- if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS,
- &c, 1, &n, 1) == 1)
- map[i] = n;
- }
+ if (map[i] == -1) {
+ char c = (char)i;
+ unsigned short n;
+ if (MultiByteToWideChar(cp, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, &c, 1,
+ &n, 1)
+ == 1)
+ map[i] = n;
+ }
}
return 1;
+#else
+ UNUSED_P(cp);
+ UNUSED_P(map);
+ return 0;
+#endif
}
int
-codepageConvert(int cp, const char *p)
-{
+codepageConvert(int cp, const char *p) {
+#if defined(_WIN32)
unsigned short c;
- if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS,
- p, 2, &c, 1) == 1)
+ if (MultiByteToWideChar(cp, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, p, 2, &c,
+ 1)
+ == 1)
return c;
return -1;
-}
-
-#else /* not WIN32 */
-
-int
-codepageMap(int cp, int *map)
-{
- return 0;
-}
-
-int
-codepageConvert(int cp, const char *p)
-{
+#else
+ UNUSED_P(cp);
+ UNUSED_P(p);
return -1;
+#endif
}
-
-#endif /* not WIN32 */
diff --git a/3rdparty/expat/xmlwf/codepage.h b/3rdparty/expat/xmlwf/codepage.h
index 6a4df68883e..1b75d58365f 100644
--- a/3rdparty/expat/xmlwf/codepage.h
+++ b/3rdparty/expat/xmlwf/codepage.h
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
int codepageMap(int cp, int *map);
diff --git a/3rdparty/expat/xmlwf/ct.c b/3rdparty/expat/xmlwf/ct.c
index 95903a34500..dcf92bab568 100644
--- a/3rdparty/expat/xmlwf/ct.c
+++ b/3rdparty/expat/xmlwf/ct.c
@@ -1,8 +1,39 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
#define CHARSET_MAX 41
static const char *
-getTok(const char **pp)
-{
+getTok(const char **pp) {
enum { inAtom, inString, init, inComment };
int state = init;
const char *tokStart = 0;
@@ -70,9 +101,8 @@ getTok(const char **pp)
/* key must be lowercase ASCII */
static int
-matchkey(const char *start, const char *end, const char *key)
-{
- if (!start)
+matchkey(const char *start, const char *end, const char *key) {
+ if (! start)
return 0;
for (; start != end; start++, key++)
if (*start != *key && *start != 'A' + (*key - 'a'))
@@ -81,8 +111,7 @@ matchkey(const char *start, const char *end, const char *key)
}
void
-getXMLCharset(const char *buf, char *charset)
-{
+getXMLCharset(const char *buf, char *charset) {
const char *next, *p;
charset[0] = '\0';
@@ -90,10 +119,10 @@ getXMLCharset(const char *buf, char *charset)
p = getTok(&next);
if (matchkey(p, next, "text"))
strcpy(charset, "us-ascii");
- else if (!matchkey(p, next, "application"))
+ else if (! matchkey(p, next, "application"))
return;
p = getTok(&next);
- if (!p || *p != '/')
+ if (! p || *p != '/')
return;
p = getTok(&next);
if (matchkey(p, next, "xml"))
@@ -119,8 +148,7 @@ getXMLCharset(const char *buf, char *charset)
*s++ = *p;
}
*s++ = '\0';
- }
- else {
+ } else {
if (next - p > CHARSET_MAX - 1)
break;
while (p != next)
@@ -131,15 +159,13 @@ getXMLCharset(const char *buf, char *charset)
}
}
}
- }
- else
- p = getTok(&next);
+ } else
+ p = getTok(&next);
}
}
int
-main(int argc, char **argv)
-{
+main(int argc, char **argv) {
char buf[CHARSET_MAX];
getXMLCharset(argv[1], buf);
printf("charset = \"%s\"\n", buf);
diff --git a/3rdparty/expat/xmlwf/filemap.h b/3rdparty/expat/xmlwf/filemap.h
index 814edec2528..ef66114422f 100644
--- a/3rdparty/expat/xmlwf/filemap.h
+++ b/3rdparty/expat/xmlwf/filemap.h
@@ -1,17 +1,53 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <limits.h> /* INT_MAX */
#include <stddef.h>
+/* The following limit (for XML_Parse's int len) derives from
+ * this loop in xmparse.c:
+ *
+ * do {
+ * bufferSize = (int) (2U * (unsigned) bufferSize);
+ * } while (bufferSize < neededSize && bufferSize > 0);
+ */
+#define XML_MAX_CHUNK_LEN (INT_MAX / 2 + 1)
+
#ifdef XML_UNICODE
int filemap(const wchar_t *name,
- void (*processor)(const void *, size_t,
- const wchar_t *, void *arg),
+ void (*processor)(const void *, size_t, const wchar_t *, void *arg),
void *arg);
#else
int filemap(const char *name,
- void (*processor)(const void *, size_t,
- const char *, void *arg),
+ void (*processor)(const void *, size_t, const char *, void *arg),
void *arg);
#endif
diff --git a/3rdparty/expat/xmlwf/readfilemap.c b/3rdparty/expat/xmlwf/readfilemap.c
index bd32b934147..d5b84f995ad 100644
--- a/3rdparty/expat/xmlwf/readfilemap.c
+++ b/3rdparty/expat/xmlwf/readfilemap.c
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
@@ -8,64 +36,76 @@
#include <stdlib.h>
#include <stdio.h>
-#ifdef __WATCOMC__
-#ifndef __LINUX__
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
+/* Functions close(2) and read(2) */
+#if ! defined(_WIN32) && ! defined(_WIN64)
+# include <unistd.h>
#endif
-#ifdef __BEOS__
-#include <unistd.h>
+/* Function "read": */
+#if defined(_MSC_VER)
+# include <io.h>
+/* https://msdn.microsoft.com/en-us/library/wyssk1bs(v=vs.100).aspx */
+# define _EXPAT_read _read
+# define _EXPAT_read_count_t int
+# define _EXPAT_read_req_t unsigned int
+#else /* POSIX */
+/* http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html */
+# define _EXPAT_read read
+# define _EXPAT_read_count_t ssize_t
+# define _EXPAT_read_req_t size_t
#endif
#ifndef S_ISREG
-#ifndef S_IFREG
-#define S_IFREG _S_IFREG
-#endif
-#ifndef S_IFMT
-#define S_IFMT _S_IFMT
-#endif
-#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+# ifndef S_IFREG
+# define S_IFREG _S_IFREG
+# endif
+# ifndef S_IFMT
+# define S_IFMT _S_IFMT
+# endif
+# define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#endif /* not S_ISREG */
#ifndef O_BINARY
-#ifdef _O_BINARY
-#define O_BINARY _O_BINARY
-#else
-#define O_BINARY 0
-#endif
+# ifdef _O_BINARY
+# define O_BINARY _O_BINARY
+# else
+# define O_BINARY 0
+# endif
#endif
+#include "xmltchar.h"
#include "filemap.h"
int
-filemap(const char *name,
- void (*processor)(const void *, size_t, const char *, void *arg),
- void *arg)
-{
+filemap(const tchar *name,
+ void (*processor)(const void *, size_t, const tchar *, void *arg),
+ void *arg) {
size_t nbytes;
int fd;
- int n;
+ _EXPAT_read_count_t n;
struct stat sb;
void *p;
- fd = open(name, O_RDONLY|O_BINARY);
+ fd = topen(name, O_RDONLY | O_BINARY);
if (fd < 0) {
- perror(name);
+ tperror(name);
return 0;
}
if (fstat(fd, &sb) < 0) {
- perror(name);
+ tperror(name);
close(fd);
return 0;
}
- if (!S_ISREG(sb.st_mode)) {
- fprintf(stderr, "%s: not a regular file\n", name);
+ if (! S_ISREG(sb.st_mode)) {
+ ftprintf(stderr, T("%s: not a regular file\n"), name);
close(fd);
return 0;
}
+ if (sb.st_size > XML_MAX_CHUNK_LEN) {
+ close(fd);
+ return 2; /* Cannot be passed to XML_Parse in one go */
+ }
+
nbytes = sb.st_size;
/* malloc will return NULL with nbytes == 0, handle files with size 0 */
if (nbytes == 0) {
@@ -75,20 +115,20 @@ filemap(const char *name,
return 1;
}
p = malloc(nbytes);
- if (!p) {
- fprintf(stderr, "%s: out of memory\n", name);
+ if (! p) {
+ ftprintf(stderr, T("%s: out of memory\n"), name);
close(fd);
return 0;
}
- n = read(fd, p, nbytes);
+ n = _EXPAT_read(fd, p, (_EXPAT_read_req_t)nbytes);
if (n < 0) {
- perror(name);
+ tperror(name);
free(p);
close(fd);
return 0;
}
- if (n != nbytes) {
- fprintf(stderr, "%s: read unexpected number of bytes\n", name);
+ if (n != (_EXPAT_read_count_t)nbytes) {
+ ftprintf(stderr, T("%s: read unexpected number of bytes\n"), name);
free(p);
close(fd);
return 0;
diff --git a/3rdparty/expat/xmlwf/unixfilemap.c b/3rdparty/expat/xmlwf/unixfilemap.c
index e13299da05f..0d0dc0424dc 100644
--- a/3rdparty/expat/xmlwf/unixfilemap.c
+++ b/3rdparty/expat/xmlwf/unixfilemap.c
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <sys/types.h>
@@ -12,36 +40,46 @@
#include <unistd.h>
#ifndef MAP_FILE
-#define MAP_FILE 0
+# define MAP_FILE 0
#endif
+#include "xmltchar.h"
#include "filemap.h"
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_FMT_STR "ls"
+#else
+# define XML_FMT_STR "s"
+#endif
+
int
-filemap(const char *name,
- void (*processor)(const void *, size_t, const char *, void *arg),
- void *arg)
-{
+filemap(const tchar *name,
+ void (*processor)(const void *, size_t, const tchar *, void *arg),
+ void *arg) {
int fd;
size_t nbytes;
struct stat sb;
void *p;
- fd = open(name, O_RDONLY);
+ fd = topen(name, O_RDONLY);
if (fd < 0) {
- perror(name);
+ tperror(name);
return 0;
}
if (fstat(fd, &sb) < 0) {
- perror(name);
+ tperror(name);
close(fd);
return 0;
}
- if (!S_ISREG(sb.st_mode)) {
+ if (! S_ISREG(sb.st_mode)) {
close(fd);
- fprintf(stderr, "%s: not a regular file\n", name);
+ fprintf(stderr, "%" XML_FMT_STR ": not a regular file\n", name);
return 0;
}
+ if (sb.st_size > XML_MAX_CHUNK_LEN) {
+ close(fd);
+ return 2; /* Cannot be passed to XML_Parse in one go */
+ }
nbytes = sb.st_size;
/* mmap fails for zero length files */
@@ -51,10 +89,10 @@ filemap(const char *name,
close(fd);
return 1;
}
- p = (void *)mmap((void *)0, (size_t)nbytes, PROT_READ,
- MAP_FILE|MAP_PRIVATE, fd, (off_t)0);
+ p = (void *)mmap((void *)0, (size_t)nbytes, PROT_READ, MAP_FILE | MAP_PRIVATE,
+ fd, (off_t)0);
if (p == (void *)-1) {
- perror(name);
+ tperror(name);
close(fd);
return 0;
}
diff --git a/3rdparty/expat/xmlwf/win32filemap.c b/3rdparty/expat/xmlwf/win32filemap.c
index 41dc35b614d..0c9b7ecc5ff 100644
--- a/3rdparty/expat/xmlwf/win32filemap.c
+++ b/3rdparty/expat/xmlwf/win32filemap.c
@@ -1,19 +1,47 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define STRICT 1
#define WIN32_LEAN_AND_MEAN 1
#ifdef XML_UNICODE_WCHAR_T
-#ifndef XML_UNICODE
-#define XML_UNICODE
-#endif
+# ifndef XML_UNICODE
+# define XML_UNICODE
+# endif
#endif
#ifdef XML_UNICODE
-#define UNICODE
-#define _UNICODE
+# define UNICODE
+# define _UNICODE
#endif /* XML_UNICODE */
#include <windows.h>
#include <stdio.h>
@@ -25,8 +53,7 @@ static void win32perror(const TCHAR *);
int
filemap(const TCHAR *name,
void (*processor)(const void *, size_t, const TCHAR *, void *arg),
- void *arg)
-{
+ void *arg) {
HANDLE f;
HANDLE m;
DWORD size;
@@ -34,7 +61,7 @@ filemap(const TCHAR *name,
void *p;
f = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (f == INVALID_HANDLE_VALUE) {
win32perror(name);
return 0;
@@ -42,11 +69,12 @@ filemap(const TCHAR *name,
size = GetFileSize(f, &sizeHi);
if (size == (DWORD)-1) {
win32perror(name);
+ CloseHandle(f);
return 0;
}
- if (sizeHi) {
- _ftprintf(stderr, _T("%s: bigger than 2Gb\n"), name);
- return 0;
+ if (sizeHi || (size > XML_MAX_CHUNK_LEN)) {
+ CloseHandle(f);
+ return 2; /* Cannot be passed to XML_Parse in one go */
}
/* CreateFileMapping barfs on zero length files */
if (size == 0) {
@@ -68,7 +96,7 @@ filemap(const TCHAR *name,
CloseHandle(f);
return 0;
}
- processor(p, size, name, arg);
+ processor(p, size, name, arg);
UnmapViewOfFile(p);
CloseHandle(m);
CloseHandle(f);
@@ -76,21 +104,15 @@ filemap(const TCHAR *name,
}
static void
-win32perror(const TCHAR *s)
-{
+win32perror(const TCHAR *s) {
LPVOID buf;
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
- | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &buf,
- 0,
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0,
NULL)) {
_ftprintf(stderr, _T("%s: %s"), s, buf);
fflush(stderr);
LocalFree(buf);
- }
- else
+ } else
_ftprintf(stderr, _T("%s: unknown Windows error\n"), s);
}
diff --git a/3rdparty/expat/xmlwf/xmlfile.c b/3rdparty/expat/xmlwf/xmlfile.c
index 99eeeaaef28..e3d22c574c5 100644
--- a/3rdparty/expat/xmlwf/xmlfile.c
+++ b/3rdparty/expat/xmlwf/xmlfile.c
@@ -1,5 +1,33 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
@@ -8,118 +36,104 @@
#include <string.h>
#include <fcntl.h>
-#ifdef COMPILED_FROM_DSP
-#include "winconfig.h"
-#elif defined(MACOS_CLASSIC)
-#include "macconfig.h"
-#elif defined(__amigaos__)
-#include "amigaconfig.h"
-#elif defined(__WATCOMC__)
-#include "watcomconfig.h"
+#ifdef _WIN32
+# include "winconfig.h"
#elif defined(HAVE_EXPAT_CONFIG_H)
-#include <expat_config.h>
-#endif /* ndef COMPILED_FROM_DSP */
+# include <expat_config.h>
+#endif /* ndef _WIN32 */
#include "expat.h"
+#include "internal.h" /* for UNUSED_P only */
#include "xmlfile.h"
#include "xmltchar.h"
#include "filemap.h"
-#if (defined(_MSC_VER) || (defined(__WATCOMC__) && !defined(__LINUX__)))
-#include <io.h>
-#endif
-
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include <proto/expat.h>
+#if defined(_MSC_VER)
+# include <io.h>
#endif
#ifdef HAVE_UNISTD_H
-#include <unistd.h>
+# include <unistd.h>
#endif
#ifndef O_BINARY
-#ifdef _O_BINARY
-#define O_BINARY _O_BINARY
-#else
-#define O_BINARY 0
-#endif
+# ifdef _O_BINARY
+# define O_BINARY _O_BINARY
+# else
+# define O_BINARY 0
+# endif
#endif
#ifdef _DEBUG
-#define READ_SIZE 16
+# define READ_SIZE 16
#else
-#define READ_SIZE (1024*8)
+# define READ_SIZE (1024 * 8)
#endif
-
typedef struct {
XML_Parser parser;
int *retPtr;
} PROCESS_ARGS;
+static int processStream(const XML_Char *filename, XML_Parser parser);
+
static void
-reportError(XML_Parser parser, const XML_Char *filename)
-{
+reportError(XML_Parser parser, const XML_Char *filename) {
enum XML_Error code = XML_GetErrorCode(parser);
const XML_Char *message = XML_ErrorString(code);
if (message)
- ftprintf(stdout, T("%s:%" XML_FMT_INT_MOD "u:%" XML_FMT_INT_MOD "u: %s\n"),
- filename,
- XML_GetErrorLineNumber(parser),
- XML_GetErrorColumnNumber(parser),
- message);
+ ftprintf(stdout,
+ T("%s") T(":%") T(XML_FMT_INT_MOD) T("u") T(":%")
+ T(XML_FMT_INT_MOD) T("u") T(": %s\n"),
+ filename, XML_GetErrorLineNumber(parser),
+ XML_GetErrorColumnNumber(parser), message);
else
ftprintf(stderr, T("%s: (unknown message %d)\n"), filename, code);
}
-
+
/* This implementation will give problems on files larger than INT_MAX. */
static void
-processFile(const void *data, size_t size,
- const XML_Char *filename, void *args)
-{
+processFile(const void *data, size_t size, const XML_Char *filename,
+ void *args) {
XML_Parser parser = ((PROCESS_ARGS *)args)->parser;
int *retPtr = ((PROCESS_ARGS *)args)->retPtr;
if (XML_Parse(parser, (const char *)data, (int)size, 1) == XML_STATUS_ERROR) {
reportError(parser, filename);
*retPtr = 0;
- }
- else
+ } else
*retPtr = 1;
}
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
static int
-isAsciiLetter(XML_Char c)
-{
+isAsciiLetter(XML_Char c) {
return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z'));
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
static const XML_Char *
resolveSystemId(const XML_Char *base, const XML_Char *systemId,
- XML_Char **toFree)
-{
+ XML_Char **toFree) {
XML_Char *s;
*toFree = 0;
- if (!base
- || *systemId == T('/')
-#if (defined(WIN32) || defined(__WATCOMC__))
+ if (! base || *systemId == T('/')
+#if defined(_WIN32)
|| *systemId == T('\\')
|| (isAsciiLetter(systemId[0]) && systemId[1] == T(':'))
#endif
- )
+ )
return systemId;
*toFree = (XML_Char *)malloc((tcslen(base) + tcslen(systemId) + 2)
* sizeof(XML_Char));
- if (!*toFree)
+ if (! *toFree)
return systemId;
tcscpy(*toFree, base);
s = *toFree;
if (tcsrchr(s, T('/')))
s = tcsrchr(s, T('/')) + 1;
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
if (tcsrchr(s, T('\\')))
s = tcsrchr(s, T('\\')) + 1;
#endif
@@ -128,36 +142,45 @@ resolveSystemId(const XML_Char *base, const XML_Char *systemId,
}
static int
-externalEntityRefFilemap(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
+externalEntityRefFilemap(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
int result;
XML_Char *s;
const XML_Char *filename;
XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
+ int filemapRes;
PROCESS_ARGS args;
+ UNUSED_P(publicId);
args.retPtr = &result;
args.parser = entParser;
filename = resolveSystemId(base, systemId, &s);
XML_SetBase(entParser, filename);
- if (!filemap(filename, processFile, &args))
+ filemapRes = filemap(filename, processFile, &args);
+ switch (filemapRes) {
+ case 0:
result = 0;
+ break;
+ case 2:
+ ftprintf(stderr,
+ T("%s: file too large for memory-mapping")
+ T(", switching to streaming\n"),
+ filename);
+ result = processStream(filename, entParser);
+ break;
+ }
free(s);
XML_ParserFree(entParser);
return result;
}
static int
-processStream(const XML_Char *filename, XML_Parser parser)
-{
- /* passing NULL for filename means read intput from stdin */
- int fd = 0; /* 0 is the fileno for stdin */
+processStream(const XML_Char *filename, XML_Parser parser) {
+ /* passing NULL for filename means read input from stdin */
+ int fd = 0; /* 0 is the fileno for stdin */
if (filename != NULL) {
- fd = topen(filename, O_BINARY|O_RDONLY);
+ fd = topen(filename, O_BINARY | O_RDONLY);
if (fd < 0) {
tperror(filename);
return 0;
@@ -166,22 +189,22 @@ processStream(const XML_Char *filename, XML_Parser parser)
for (;;) {
int nread;
char *buf = (char *)XML_GetBuffer(parser, READ_SIZE);
- if (!buf) {
+ if (! buf) {
if (filename != NULL)
close(fd);
ftprintf(stderr, T("%s: out of memory\n"),
- filename != NULL ? filename : "xmlwf");
+ filename != NULL ? filename : T("xmlwf"));
return 0;
}
nread = read(fd, buf, READ_SIZE);
if (nread < 0) {
- tperror(filename != NULL ? filename : "STDIN");
+ tperror(filename != NULL ? filename : T("STDIN"));
if (filename != NULL)
close(fd);
return 0;
}
if (XML_ParseBuffer(parser, nread, nread == 0) == XML_STATUS_ERROR) {
- reportError(parser, filename != NULL ? filename : "STDIN");
+ reportError(parser, filename != NULL ? filename : T("STDIN"));
if (filename != NULL)
close(fd);
return 0;
@@ -189,23 +212,22 @@ processStream(const XML_Char *filename, XML_Parser parser)
if (nread == 0) {
if (filename != NULL)
close(fd);
- break;;
+ break;
+ ;
}
}
return 1;
}
static int
-externalEntityRefStream(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
+externalEntityRefStream(XML_Parser parser, const XML_Char *context,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
XML_Char *s;
const XML_Char *filename;
int ret;
XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
+ UNUSED_P(publicId);
filename = resolveSystemId(base, systemId, &s);
XML_SetBase(entParser, filename);
ret = processStream(filename, entParser);
@@ -215,30 +237,37 @@ externalEntityRefStream(XML_Parser parser,
}
int
-XML_ProcessFile(XML_Parser parser,
- const XML_Char *filename,
- unsigned flags)
-{
+XML_ProcessFile(XML_Parser parser, const XML_Char *filename, unsigned flags) {
int result;
- if (!XML_SetBase(parser, filename)) {
+ if (! XML_SetBase(parser, filename)) {
ftprintf(stderr, T("%s: out of memory"), filename);
exit(1);
}
if (flags & XML_EXTERNAL_ENTITIES)
- XML_SetExternalEntityRefHandler(parser,
- (flags & XML_MAP_FILE)
- ? externalEntityRefFilemap
- : externalEntityRefStream);
+ XML_SetExternalEntityRefHandler(parser, (flags & XML_MAP_FILE)
+ ? externalEntityRefFilemap
+ : externalEntityRefStream);
if (flags & XML_MAP_FILE) {
+ int filemapRes;
PROCESS_ARGS args;
args.retPtr = &result;
args.parser = parser;
- if (!filemap(filename, processFile, &args))
+ filemapRes = filemap(filename, processFile, &args);
+ switch (filemapRes) {
+ case 0:
result = 0;
- }
- else
+ break;
+ case 2:
+ ftprintf(stderr,
+ T("%s: file too large for memory-mapping")
+ T(", switching to streaming\n"),
+ filename);
+ result = processStream(filename, parser);
+ break;
+ }
+ } else
result = processStream(filename, parser);
return result;
}
diff --git a/3rdparty/expat/xmlwf/xmlfile.h b/3rdparty/expat/xmlwf/xmlfile.h
index d093ecc06f9..6e5d5b49eb7 100644
--- a/3rdparty/expat/xmlwf/xmlfile.h
+++ b/3rdparty/expat/xmlwf/xmlfile.h
@@ -1,20 +1,43 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define XML_MAP_FILE 01
#define XML_EXTERNAL_ENTITIES 02
#ifdef XML_LARGE_SIZE
-#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
-#define XML_FMT_INT_MOD "I64"
-#else
-#define XML_FMT_INT_MOD "ll"
-#endif
+# define XML_FMT_INT_MOD "ll"
#else
-#define XML_FMT_INT_MOD "l"
+# define XML_FMT_INT_MOD "l"
#endif
-extern int XML_ProcessFile(XML_Parser parser,
- const XML_Char *filename,
+extern int XML_ProcessFile(XML_Parser parser, const XML_Char *filename,
unsigned flags);
diff --git a/3rdparty/expat/xmlwf/xmlmime.c b/3rdparty/expat/xmlwf/xmlmime.c
index 56a0e7f40e4..39160d7198c 100644
--- a/3rdparty/expat/xmlwf/xmlmime.c
+++ b/3rdparty/expat/xmlwf/xmlmime.c
@@ -1,9 +1,40 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
#include <string.h>
#include "xmlmime.h"
static const char *
-getTok(const char **pp)
-{
+getTok(const char **pp) {
/* inComment means one level of nesting; inComment+1 means two levels etc */
enum { inAtom, inString, init, inComment };
int state = init;
@@ -74,9 +105,8 @@ getTok(const char **pp)
/* key must be lowercase ASCII */
static int
-matchkey(const char *start, const char *end, const char *key)
-{
- if (!start)
+matchkey(const char *start, const char *end, const char *key) {
+ if (! start)
return 0;
for (; start != end; start++, key++)
if (*start != *key && *start != 'A' + (*key - 'a'))
@@ -85,8 +115,7 @@ matchkey(const char *start, const char *end, const char *key)
}
void
-getXMLCharset(const char *buf, char *charset)
-{
+getXMLCharset(const char *buf, char *charset) {
const char *next, *p;
charset[0] = '\0';
@@ -94,16 +123,18 @@ getXMLCharset(const char *buf, char *charset)
p = getTok(&next);
if (matchkey(p, next, "text"))
strcpy(charset, "us-ascii");
- else if (!matchkey(p, next, "application"))
+ else if (! matchkey(p, next, "application"))
return;
p = getTok(&next);
- if (!p || *p != '/')
+ if (! p || *p != '/')
return;
p = getTok(&next);
-#if 0
- if (!matchkey(p, next, "xml") && charset[0] == '\0')
- return;
-#endif
+ /* BEGIN disabled code */
+ if (0) {
+ if (! matchkey(p, next, "xml") && charset[0] == '\0')
+ return;
+ }
+ /* END disabled code */
p = getTok(&next);
while (p) {
if (*p == ';') {
@@ -125,8 +156,7 @@ getXMLCharset(const char *buf, char *charset)
*s++ = *p;
}
*s++ = '\0';
- }
- else {
+ } else {
if (next - p > CHARSET_MAX - 1)
break;
while (p != next)
@@ -138,19 +168,17 @@ getXMLCharset(const char *buf, char *charset)
}
break;
}
- }
- else
- p = getTok(&next);
+ } else
+ p = getTok(&next);
}
}
#ifdef TEST
-#include <stdio.h>
+# include <stdio.h>
int
-main(int argc, char *argv[])
-{
+main(int argc, char *argv[]) {
char buf[CHARSET_MAX];
if (argc <= 1)
return 1;
diff --git a/3rdparty/expat/xmlwf/xmlmime.h b/3rdparty/expat/xmlwf/xmlmime.h
index bf0356df0d9..0471286234a 100644
--- a/3rdparty/expat/xmlwf/xmlmime.h
+++ b/3rdparty/expat/xmlwf/xmlmime.h
@@ -1,3 +1,35 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/3rdparty/expat/xmlwf/xmltchar.h b/3rdparty/expat/xmlwf/xmltchar.h
index 1088575512d..d7e7b411b44 100644
--- a/3rdparty/expat/xmlwf/xmltchar.h
+++ b/3rdparty/expat/xmlwf/xmltchar.h
@@ -1,36 +1,74 @@
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* Ensures compile-time constants are consistent */
+#include "expat_external.h"
+
#ifdef XML_UNICODE
-#ifndef XML_UNICODE_WCHAR_T
-#error xmlwf requires a 16-bit Unicode-compatible wchar_t
-#endif
-#define T(x) L ## x
-#define ftprintf fwprintf
-#define tfopen _wfopen
-#define fputts fputws
-#define puttc putwc
-#define tcscmp wcscmp
-#define tcscpy wcscpy
-#define tcscat wcscat
-#define tcschr wcschr
-#define tcsrchr wcsrchr
-#define tcslen wcslen
-#define tperror _wperror
-#define topen _wopen
-#define tmain wmain
-#define tremove _wremove
+# ifndef XML_UNICODE_WCHAR_T
+# error xmlwf requires a 16-bit Unicode-compatible wchar_t
+# endif
+# define _PREPEND_BIG_L(x) L##x
+# define T(x) _PREPEND_BIG_L(x)
+# define ftprintf fwprintf
+# define tfopen _wfopen
+# define fputts fputws
+# define puttc putwc
+# define tcscmp wcscmp
+# define tcscpy wcscpy
+# define tcscat wcscat
+# define tcschr wcschr
+# define tcsrchr wcsrchr
+# define tcslen wcslen
+# define tperror _wperror
+# define topen _wopen
+# define tmain wmain
+# define tremove _wremove
+# define tchar wchar_t
#else /* not XML_UNICODE */
-#define T(x) x
-#define ftprintf fprintf
-#define tfopen fopen
-#define fputts fputs
-#define puttc putc
-#define tcscmp strcmp
-#define tcscpy strcpy
-#define tcscat strcat
-#define tcschr strchr
-#define tcsrchr strrchr
-#define tcslen strlen
-#define tperror perror
-#define topen open
-#define tmain main
-#define tremove remove
+# define T(x) x
+# define ftprintf fprintf
+# define tfopen fopen
+# define fputts fputs
+# define puttc putc
+# define tcscmp strcmp
+# define tcscpy strcpy
+# define tcscat strcat
+# define tcschr strchr
+# define tcsrchr strrchr
+# define tcslen strlen
+# define tperror perror
+# define topen open
+# define tmain main
+# define tremove remove
+# define tchar char
#endif /* not XML_UNICODE */
diff --git a/3rdparty/expat/xmlwf/xmlurl.h b/3rdparty/expat/xmlwf/xmlurl.h
deleted file mode 100644
index d329913ac85..00000000000
--- a/3rdparty/expat/xmlwf/xmlurl.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int XML_URLInit();
-void XML_URLUninit();
-int XML_ProcessURL(XML_Parser parser,
- const XML_Char *url,
- unsigned flags);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/3rdparty/expat/xmlwf/xmlwf.c b/3rdparty/expat/xmlwf/xmlwf.c
index c4090b0e406..5121fa1028e 100644
--- a/3rdparty/expat/xmlwf/xmlwf.c
+++ b/3rdparty/expat/xmlwf/xmlwf.c
@@ -1,7 +1,36 @@
-/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
- See the file COPYING for copying permission.
+/*
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+ Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
+ Copyright (c) 2000-2017 Expat development team
+ Licensed under the MIT license:
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to permit
+ persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -9,25 +38,39 @@
#include "expat.h"
#include "codepage.h"
+#include "internal.h" /* for UNUSED_P only */
#include "xmlfile.h"
#include "xmltchar.h"
#ifdef _MSC_VER
-#include <crtdbg.h>
+# include <crtdbg.h>
#endif
-#if defined(__amigaos__) && defined(__USE_INLINE__)
-#include <proto/expat.h>
+#ifdef XML_UNICODE
+# include <wchar.h>
#endif
+/* Structures for handler user data */
+typedef struct NotationList {
+ struct NotationList *next;
+ const XML_Char *notationName;
+ const XML_Char *systemId;
+ const XML_Char *publicId;
+} NotationList;
+
+typedef struct xmlwfUserData {
+ FILE *fp;
+ NotationList *notationListHead;
+ const XML_Char *currentDoctypeName;
+} XmlwfUserData;
+
/* This ensures proper sorting. */
#define NSSEP T('\001')
static void XMLCALL
-characterData(void *userData, const XML_Char *s, int len)
-{
- FILE *fp = (FILE *)userData;
+characterData(void *userData, const XML_Char *s, int len) {
+ FILE *fp = ((XmlwfUserData *)userData)->fp;
for (; len > 0; --len, ++s) {
switch (*s) {
case T('&'):
@@ -61,10 +104,10 @@ characterData(void *userData, const XML_Char *s, int len)
}
static void
-attributeValue(FILE *fp, const XML_Char *s)
-{
+attributeValue(FILE *fp, const XML_Char *s) {
puttc(T('='), fp);
puttc(T('"'), fp);
+ assert(s);
for (;;) {
switch (*s) {
case 0:
@@ -112,17 +155,15 @@ attributeValue(FILE *fp, const XML_Char *s)
is equivalent to lexicographically comparing based on the character number. */
static int
-attcmp(const void *att1, const void *att2)
-{
+attcmp(const void *att1, const void *att2) {
return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2);
}
static void XMLCALL
-startElement(void *userData, const XML_Char *name, const XML_Char **atts)
-{
+startElement(void *userData, const XML_Char *name, const XML_Char **atts) {
int nAtts;
const XML_Char **p;
- FILE *fp = (FILE *)userData;
+ FILE *fp = ((XmlwfUserData *)userData)->fp;
puttc(T('<'), fp);
fputts(name, fp);
@@ -142,9 +183,8 @@ startElement(void *userData, const XML_Char *name, const XML_Char **atts)
}
static void XMLCALL
-endElement(void *userData, const XML_Char *name)
-{
- FILE *fp = (FILE *)userData;
+endElement(void *userData, const XML_Char *name) {
+ FILE *fp = ((XmlwfUserData *)userData)->fp;
puttc(T('<'), fp);
puttc(T('/'), fp);
fputts(name, fp);
@@ -152,8 +192,7 @@ endElement(void *userData, const XML_Char *name)
}
static int
-nsattcmp(const void *p1, const void *p2)
-{
+nsattcmp(const void *p1, const void *p2) {
const XML_Char *att1 = *(const XML_Char **)p1;
const XML_Char *att2 = *(const XML_Char **)p2;
int sep1 = (tcsrchr(att1, NSSEP) != 0);
@@ -164,12 +203,11 @@ nsattcmp(const void *p1, const void *p2)
}
static void XMLCALL
-startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
-{
+startElementNS(void *userData, const XML_Char *name, const XML_Char **atts) {
int nAtts;
int nsi;
const XML_Char **p;
- FILE *fp = (FILE *)userData;
+ FILE *fp = ((XmlwfUserData *)userData)->fp;
const XML_Char *sep;
puttc(T('<'), fp);
@@ -180,8 +218,7 @@ startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
fputts(T(" xmlns:n1"), fp);
attributeValue(fp, name);
nsi = 2;
- }
- else {
+ } else {
fputts(name, fp);
nsi = 1;
}
@@ -199,8 +236,7 @@ startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
if (sep) {
ftprintf(fp, T("n%d:"), nsi);
fputts(sep + 1, fp);
- }
- else
+ } else
fputts(name, fp);
attributeValue(fp, *atts);
if (sep) {
@@ -213,9 +249,8 @@ startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
}
static void XMLCALL
-endElementNS(void *userData, const XML_Char *name)
-{
- FILE *fp = (FILE *)userData;
+endElementNS(void *userData, const XML_Char *name) {
+ FILE *fp = ((XmlwfUserData *)userData)->fp;
const XML_Char *sep;
puttc(T('<'), fp);
puttc(T('/'), fp);
@@ -223,8 +258,7 @@ endElementNS(void *userData, const XML_Char *name)
if (sep) {
fputts(T("n1:"), fp);
fputts(sep + 1, fp);
- }
- else
+ } else
fputts(name, fp);
puttc(T('>'), fp);
}
@@ -233,9 +267,8 @@ endElementNS(void *userData, const XML_Char *name)
static void XMLCALL
processingInstruction(void *userData, const XML_Char *target,
- const XML_Char *data)
-{
- FILE *fp = (FILE *)userData;
+ const XML_Char *data) {
+ FILE *fp = ((XmlwfUserData *)userData)->fp;
puttc(T('<'), fp);
puttc(T('?'), fp);
fputts(target, fp);
@@ -245,112 +278,302 @@ processingInstruction(void *userData, const XML_Char *target,
puttc(T('>'), fp);
}
+static XML_Char *
+xcsdup(const XML_Char *s) {
+ XML_Char *result;
+ int count = 0;
+ int numBytes;
+
+ /* Get the length of the string, including terminator */
+ while (s[count++] != 0) {
+ /* Do nothing */
+ }
+ numBytes = count * sizeof(XML_Char);
+ result = malloc(numBytes);
+ if (result == NULL)
+ return NULL;
+ memcpy(result, s, numBytes);
+ return result;
+}
+
+static void XMLCALL
+startDoctypeDecl(void *userData, const XML_Char *doctypeName,
+ const XML_Char *sysid, const XML_Char *publid,
+ int has_internal_subset) {
+ XmlwfUserData *data = (XmlwfUserData *)userData;
+ UNUSED_P(sysid);
+ UNUSED_P(publid);
+ UNUSED_P(has_internal_subset);
+ data->currentDoctypeName = xcsdup(doctypeName);
+}
+
+static void
+freeNotations(XmlwfUserData *data) {
+ NotationList *notationListHead = data->notationListHead;
+
+ while (notationListHead != NULL) {
+ NotationList *next = notationListHead->next;
+ free((void *)notationListHead->notationName);
+ free((void *)notationListHead->systemId);
+ free((void *)notationListHead->publicId);
+ free(notationListHead);
+ notationListHead = next;
+ }
+ data->notationListHead = NULL;
+}
+
+static int
+xcscmp(const XML_Char *xs, const XML_Char *xt) {
+ while (*xs != 0 && *xt != 0) {
+ if (*xs < *xt)
+ return -1;
+ if (*xs > *xt)
+ return 1;
+ xs++;
+ xt++;
+ }
+ if (*xs < *xt)
+ return -1;
+ if (*xs > *xt)
+ return 1;
+ return 0;
+}
+
+static int
+notationCmp(const void *a, const void *b) {
+ const NotationList *const n1 = *(NotationList **)a;
+ const NotationList *const n2 = *(NotationList **)b;
+
+ return xcscmp(n1->notationName, n2->notationName);
+}
+
+static void XMLCALL
+endDoctypeDecl(void *userData) {
+ XmlwfUserData *data = (XmlwfUserData *)userData;
+ NotationList **notations;
+ int notationCount = 0;
+ NotationList *p;
+ int i;
+
+ /* How many notations do we have? */
+ for (p = data->notationListHead; p != NULL; p = p->next)
+ notationCount++;
+ if (notationCount == 0) {
+ /* Nothing to report */
+ free((void *)data->currentDoctypeName);
+ data->currentDoctypeName = NULL;
+ return;
+ }
+
+ notations = malloc(notationCount * sizeof(NotationList *));
+ if (notations == NULL) {
+ fprintf(stderr, "Unable to sort notations");
+ freeNotations(data);
+ return;
+ }
+
+ for (p = data->notationListHead, i = 0; i < notationCount; p = p->next, i++) {
+ notations[i] = p;
+ }
+ qsort(notations, notationCount, sizeof(NotationList *), notationCmp);
+
+ /* Output the DOCTYPE header */
+ fputts(T("<!DOCTYPE "), data->fp);
+ fputts(data->currentDoctypeName, data->fp);
+ fputts(T(" [\n"), data->fp);
+
+ /* Now the NOTATIONs */
+ for (i = 0; i < notationCount; i++) {
+ fputts(T("<!NOTATION "), data->fp);
+ fputts(notations[i]->notationName, data->fp);
+ if (notations[i]->publicId != NULL) {
+ fputts(T(" PUBLIC '"), data->fp);
+ fputts(notations[i]->publicId, data->fp);
+ puttc(T('\''), data->fp);
+ if (notations[i]->systemId != NULL) {
+ puttc(T(' '), data->fp);
+ puttc(T('\''), data->fp);
+ fputts(notations[i]->systemId, data->fp);
+ puttc(T('\''), data->fp);
+ }
+ } else if (notations[i]->systemId != NULL) {
+ fputts(T(" SYSTEM '"), data->fp);
+ fputts(notations[i]->systemId, data->fp);
+ puttc(T('\''), data->fp);
+ }
+ puttc(T('>'), data->fp);
+ puttc(T('\n'), data->fp);
+ }
+
+ /* Finally end the DOCTYPE */
+ fputts(T("]>\n"), data->fp);
+
+ free(notations);
+ freeNotations(data);
+ free((void *)data->currentDoctypeName);
+ data->currentDoctypeName = NULL;
+}
+
+static void XMLCALL
+notationDecl(void *userData, const XML_Char *notationName, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId) {
+ XmlwfUserData *data = (XmlwfUserData *)userData;
+ NotationList *entry = malloc(sizeof(NotationList));
+ const char *errorMessage = "Unable to store NOTATION for output\n";
+
+ UNUSED_P(base);
+ if (entry == NULL) {
+ fputs(errorMessage, stderr);
+ return; /* Nothing we can really do about this */
+ }
+ entry->notationName = xcsdup(notationName);
+ if (entry->notationName == NULL) {
+ fputs(errorMessage, stderr);
+ free(entry);
+ return;
+ }
+ if (systemId != NULL) {
+ entry->systemId = xcsdup(systemId);
+ if (entry->systemId == NULL) {
+ fputs(errorMessage, stderr);
+ free((void *)entry->notationName);
+ free(entry);
+ return;
+ }
+ } else {
+ entry->systemId = NULL;
+ }
+ if (publicId != NULL) {
+ entry->publicId = xcsdup(publicId);
+ if (entry->publicId == NULL) {
+ fputs(errorMessage, stderr);
+ free((void *)entry->systemId); /* Safe if it's NULL */
+ free((void *)entry->notationName);
+ free(entry);
+ return;
+ }
+ } else {
+ entry->publicId = NULL;
+ }
+
+ entry->next = data->notationListHead;
+ data->notationListHead = entry;
+}
+
#endif /* not W3C14N */
static void XMLCALL
-defaultCharacterData(void *userData, const XML_Char *s, int len)
-{
- XML_DefaultCurrent((XML_Parser) userData);
+defaultCharacterData(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_DefaultCurrent((XML_Parser)userData);
}
static void XMLCALL
defaultStartElement(void *userData, const XML_Char *name,
- const XML_Char **atts)
-{
- XML_DefaultCurrent((XML_Parser) userData);
+ const XML_Char **atts) {
+ UNUSED_P(name);
+ UNUSED_P(atts);
+ XML_DefaultCurrent((XML_Parser)userData);
}
static void XMLCALL
-defaultEndElement(void *userData, const XML_Char *name)
-{
- XML_DefaultCurrent((XML_Parser) userData);
+defaultEndElement(void *userData, const XML_Char *name) {
+ UNUSED_P(name);
+ XML_DefaultCurrent((XML_Parser)userData);
}
static void XMLCALL
defaultProcessingInstruction(void *userData, const XML_Char *target,
- const XML_Char *data)
-{
- XML_DefaultCurrent((XML_Parser) userData);
+ const XML_Char *data) {
+ UNUSED_P(target);
+ UNUSED_P(data);
+ XML_DefaultCurrent((XML_Parser)userData);
}
static void XMLCALL
-nopCharacterData(void *userData, const XML_Char *s, int len)
-{
+nopCharacterData(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(userData);
+ UNUSED_P(s);
+ UNUSED_P(len);
}
static void XMLCALL
-nopStartElement(void *userData, const XML_Char *name, const XML_Char **atts)
-{
+nopStartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
+ UNUSED_P(atts);
}
static void XMLCALL
-nopEndElement(void *userData, const XML_Char *name)
-{
+nopEndElement(void *userData, const XML_Char *name) {
+ UNUSED_P(userData);
+ UNUSED_P(name);
}
static void XMLCALL
nopProcessingInstruction(void *userData, const XML_Char *target,
- const XML_Char *data)
-{
+ const XML_Char *data) {
+ UNUSED_P(userData);
+ UNUSED_P(target);
+ UNUSED_P(data);
}
static void XMLCALL
-markup(void *userData, const XML_Char *s, int len)
-{
- FILE *fp = (FILE *)XML_GetUserData((XML_Parser) userData);
+markup(void *userData, const XML_Char *s, int len) {
+ FILE *fp = ((XmlwfUserData *)XML_GetUserData((XML_Parser)userData))->fp;
for (; len > 0; --len, ++s)
puttc(*s, fp);
}
static void
-metaLocation(XML_Parser parser)
-{
+metaLocation(XML_Parser parser) {
const XML_Char *uri = XML_GetBase(parser);
+ FILE *fp = ((XmlwfUserData *)XML_GetUserData(parser))->fp;
if (uri)
- ftprintf((FILE *)XML_GetUserData(parser), T(" uri=\"%s\""), uri);
- ftprintf((FILE *)XML_GetUserData(parser),
- T(" byte=\"%" XML_FMT_INT_MOD "d\" nbytes=\"%d\" \
- line=\"%" XML_FMT_INT_MOD "u\" col=\"%" XML_FMT_INT_MOD "u\""),
- XML_GetCurrentByteIndex(parser),
- XML_GetCurrentByteCount(parser),
+ ftprintf(fp, T(" uri=\"%s\""), uri);
+ ftprintf(fp,
+ T(" byte=\"%") T(XML_FMT_INT_MOD) T("d\"") T(" nbytes=\"%d\"")
+ T(" line=\"%") T(XML_FMT_INT_MOD) T("u\"") T(" col=\"%")
+ T(XML_FMT_INT_MOD) T("u\""),
+ XML_GetCurrentByteIndex(parser), XML_GetCurrentByteCount(parser),
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser));
}
static void
-metaStartDocument(void *userData)
-{
- fputts(T("<document>\n"), (FILE *)XML_GetUserData((XML_Parser) userData));
+metaStartDocument(void *userData) {
+ fputts(T("<document>\n"),
+ ((XmlwfUserData *)XML_GetUserData((XML_Parser)userData))->fp);
}
static void
-metaEndDocument(void *userData)
-{
- fputts(T("</document>\n"), (FILE *)XML_GetUserData((XML_Parser) userData));
+metaEndDocument(void *userData) {
+ fputts(T("</document>\n"),
+ ((XmlwfUserData *)XML_GetUserData((XML_Parser)userData))->fp);
}
static void XMLCALL
-metaStartElement(void *userData, const XML_Char *name,
- const XML_Char **atts)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaStartElement(void *userData, const XML_Char *name, const XML_Char **atts) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
const XML_Char **specifiedAttsEnd
- = atts + XML_GetSpecifiedAttributeCount(parser);
+ = atts + XML_GetSpecifiedAttributeCount(parser);
const XML_Char **idAttPtr;
int idAttIndex = XML_GetIdAttributeIndex(parser);
if (idAttIndex < 0)
idAttPtr = 0;
else
idAttPtr = atts + idAttIndex;
-
+
ftprintf(fp, T("<starttag name=\"%s\""), name);
metaLocation(parser);
if (*atts) {
fputts(T(">\n"), fp);
do {
ftprintf(fp, T("<attribute name=\"%s\" value=\""), atts[0]);
- characterData(fp, atts[1], (int)tcslen(atts[1]));
+ characterData(data, atts[1], (int)tcslen(atts[1]));
if (atts >= specifiedAttsEnd)
fputts(T("\" defaulted=\"yes\"/>\n"), fp);
else if (atts == idAttPtr)
@@ -359,16 +582,15 @@ metaStartElement(void *userData, const XML_Char *name,
fputts(T("\"/>\n"), fp);
} while (*(atts += 2));
fputts(T("</starttag>\n"), fp);
- }
- else
+ } else
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaEndElement(void *userData, const XML_Char *name)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaEndElement(void *userData, const XML_Char *name) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
ftprintf(fp, T("<endtag name=\"%s\""), name);
metaLocation(parser);
fputts(T("/>\n"), fp);
@@ -376,145 +598,139 @@ metaEndElement(void *userData, const XML_Char *name)
static void XMLCALL
metaProcessingInstruction(void *userData, const XML_Char *target,
- const XML_Char *data)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+ const XML_Char *data) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *usrData = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = usrData->fp;
ftprintf(fp, T("<pi target=\"%s\" data=\""), target);
- characterData(fp, data, (int)tcslen(data));
+ characterData(usrData, data, (int)tcslen(data));
puttc(T('"'), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaComment(void *userData, const XML_Char *data)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaComment(void *userData, const XML_Char *data) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *usrData = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = usrData->fp;
fputts(T("<comment data=\""), fp);
- characterData(fp, data, (int)tcslen(data));
+ characterData(usrData, data, (int)tcslen(data));
puttc(T('"'), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaStartCdataSection(void *userData)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaStartCdataSection(void *userData) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
fputts(T("<startcdata"), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaEndCdataSection(void *userData)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaEndCdataSection(void *userData) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
fputts(T("<endcdata"), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaCharacterData(void *userData, const XML_Char *s, int len)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaCharacterData(void *userData, const XML_Char *s, int len) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
fputts(T("<chars str=\""), fp);
- characterData(fp, s, len);
+ characterData(data, s, len);
puttc(T('"'), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaStartDoctypeDecl(void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid,
- int has_internal_subset)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaStartDoctypeDecl(void *userData, const XML_Char *doctypeName,
+ const XML_Char *sysid, const XML_Char *pubid,
+ int has_internal_subset) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
+ UNUSED_P(sysid);
+ UNUSED_P(pubid);
+ UNUSED_P(has_internal_subset);
ftprintf(fp, T("<startdoctype name=\"%s\""), doctypeName);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaEndDoctypeDecl(void *userData)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaEndDoctypeDecl(void *userData) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
fputts(T("<enddoctype"), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaNotationDecl(void *userData,
- const XML_Char *notationName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaNotationDecl(void *userData, const XML_Char *notationName,
+ const XML_Char *base, const XML_Char *systemId,
+ const XML_Char *publicId) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
+ UNUSED_P(base);
ftprintf(fp, T("<notation name=\"%s\""), notationName);
if (publicId)
ftprintf(fp, T(" public=\"%s\""), publicId);
if (systemId) {
fputts(T(" system=\""), fp);
- characterData(fp, systemId, (int)tcslen(systemId));
+ characterData(data, systemId, (int)tcslen(systemId));
puttc(T('"'), fp);
}
metaLocation(parser);
fputts(T("/>\n"), fp);
}
-
static void XMLCALL
-metaEntityDecl(void *userData,
- const XML_Char *entityName,
- int is_param,
- const XML_Char *value,
- int value_length,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaEntityDecl(void *userData, const XML_Char *entityName, int is_param,
+ const XML_Char *value, int value_length, const XML_Char *base,
+ const XML_Char *systemId, const XML_Char *publicId,
+ const XML_Char *notationName) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
+ UNUSED_P(is_param);
+ UNUSED_P(base);
if (value) {
ftprintf(fp, T("<entity name=\"%s\""), entityName);
metaLocation(parser);
puttc(T('>'), fp);
- characterData(fp, value, value_length);
+ characterData(data, value, value_length);
fputts(T("</entity/>\n"), fp);
- }
- else if (notationName) {
+ } else if (notationName) {
ftprintf(fp, T("<entity name=\"%s\""), entityName);
if (publicId)
ftprintf(fp, T(" public=\"%s\""), publicId);
fputts(T(" system=\""), fp);
- characterData(fp, systemId, (int)tcslen(systemId));
+ characterData(data, systemId, (int)tcslen(systemId));
puttc(T('"'), fp);
ftprintf(fp, T(" notation=\"%s\""), notationName);
metaLocation(parser);
fputts(T("/>\n"), fp);
- }
- else {
+ } else {
ftprintf(fp, T("<entity name=\"%s\""), entityName);
if (publicId)
ftprintf(fp, T(" public=\"%s\""), publicId);
fputts(T(" system=\""), fp);
- characterData(fp, systemId, (int)tcslen(systemId));
+ characterData(data, systemId, (int)tcslen(systemId));
puttc(T('"'), fp);
metaLocation(parser);
fputts(T("/>\n"), fp);
@@ -522,95 +738,91 @@ metaEntityDecl(void *userData,
}
static void XMLCALL
-metaStartNamespaceDecl(void *userData,
- const XML_Char *prefix,
- const XML_Char *uri)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
+metaStartNamespaceDecl(void *userData, const XML_Char *prefix,
+ const XML_Char *uri) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
fputts(T("<startns"), fp);
if (prefix)
ftprintf(fp, T(" prefix=\"%s\""), prefix);
if (uri) {
fputts(T(" ns=\""), fp);
- characterData(fp, uri, (int)tcslen(uri));
+ characterData(data, uri, (int)tcslen(uri));
fputts(T("\"/>\n"), fp);
- }
- else
+ } else
fputts(T("/>\n"), fp);
}
static void XMLCALL
-metaEndNamespaceDecl(void *userData, const XML_Char *prefix)
-{
- XML_Parser parser = (XML_Parser) userData;
- FILE *fp = (FILE *)XML_GetUserData(parser);
- if (!prefix)
+metaEndNamespaceDecl(void *userData, const XML_Char *prefix) {
+ XML_Parser parser = (XML_Parser)userData;
+ XmlwfUserData *data = (XmlwfUserData *)XML_GetUserData(parser);
+ FILE *fp = data->fp;
+ if (! prefix)
fputts(T("<endns/>\n"), fp);
else
ftprintf(fp, T("<endns prefix=\"%s\"/>\n"), prefix);
}
static int XMLCALL
-unknownEncodingConvert(void *data, const char *p)
-{
+unknownEncodingConvert(void *data, const char *p) {
return codepageConvert(*(int *)data, p);
}
static int XMLCALL
-unknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info)
-{
+unknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info) {
int cp;
static const XML_Char prefixL[] = T("windows-");
static const XML_Char prefixU[] = T("WINDOWS-");
int i;
+ UNUSED_P(userData);
for (i = 0; prefixU[i]; i++)
if (name[i] != prefixU[i] && name[i] != prefixL[i])
return 0;
-
+
cp = 0;
for (; name[i]; i++) {
static const XML_Char digits[] = T("0123456789");
const XML_Char *s = tcschr(digits, name[i]);
- if (!s)
+ if (! s)
return 0;
cp *= 10;
cp += (int)(s - digits);
if (cp >= 0x10000)
return 0;
}
- if (!codepageMap(cp, info->map))
+ if (! codepageMap(cp, info->map))
return 0;
info->convert = unknownEncodingConvert;
/* We could just cast the code page integer to a void *,
and avoid the use of release. */
info->release = free;
info->data = malloc(sizeof(int));
- if (!info->data)
+ if (! info->data)
return 0;
*(int *)info->data = cp;
return 1;
}
static int XMLCALL
-notStandalone(void *userData)
-{
+notStandalone(void *userData) {
+ UNUSED_P(userData);
return 0;
}
static void
-showVersion(XML_Char *prog)
-{
+showVersion(XML_Char *prog) {
XML_Char *s = prog;
XML_Char ch;
const XML_Feature *features = XML_GetFeatureList();
while ((ch = *s) != 0) {
if (ch == '/'
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
|| ch == '\\'
#endif
- )
+ )
prog = s + 1;
++s;
}
@@ -631,16 +843,56 @@ showVersion(XML_Char *prog)
}
static void
-usage(const XML_Char *prog, int rc)
-{
- ftprintf(stderr,
- T("usage: %s [-s] [-n] [-p] [-x] [-e encoding] [-w] [-d output-dir] [-c] [-m] [-r] [-t] [file ...]\n"), prog);
+usage(const XML_Char *prog, int rc) {
+ ftprintf(
+ stderr,
+ /* Generated with:
+ * $ xmlwf/xmlwf_helpgen.sh
+ */
+ /* clang-format off */
+ T("usage: %s [-s] [-n] [-p] [-x] [-e ENCODING] [-w] [-r] [-d DIRECTORY]\n")
+ T(" [-c | -m | -t] [-N]\n")
+ T(" [FILE [FILE ...]]\n")
+ T("\n")
+ T("xmlwf - Determines if an XML document is well-formed\n")
+ T("\n")
+ T("positional arguments:\n")
+ T(" FILE file to process (default: STDIN)\n")
+ T("\n")
+ T("input control arguments:\n")
+ T(" -s print an error if the document is not [s]tandalone\n")
+ T(" -n enable [n]amespace processing\n")
+ T(" -p enable processing external DTDs and [p]arameter entities\n")
+ T(" -x enable processing of e[x]ternal entities\n")
+ T(" -e ENCODING override any in-document [e]ncoding declaration\n")
+ T(" -w enable support for [W]indows code pages\n")
+ T(" -r disable memory-mapping and use normal file [r]ead IO calls instead\n")
+ T("\n")
+ T("output control arguments:\n")
+ T(" -d DIRECTORY output [d]estination directory\n")
+ T(" -c write a [c]opy of input XML, not canonical XML\n")
+ T(" -m write [m]eta XML, not canonical XML\n")
+ T(" -t write no XML output for [t]iming of plain parsing\n")
+ T(" -N enable adding doctype and [n]otation declarations\n")
+ T("\n")
+ T("info arguments:\n")
+ T(" -h show this [h]elp message and exit\n")
+ T(" -v show program's [v]ersion number and exit\n")
+ T("\n")
+ T("xmlwf of libexpat is software libre, licensed under the MIT license.\n")
+ T("Please report bugs at https://github.com/libexpat/libexpat/issues. Thank you!\n")
+ , /* clang-format on */
+ prog);
exit(rc);
}
+#if defined(__MINGW32__) && defined(XML_UNICODE)
+/* Silence warning about missing prototype */
+int wmain(int argc, XML_Char **argv);
+#endif
+
int
-tmain(int argc, XML_Char **argv)
-{
+tmain(int argc, XML_Char **argv) {
int i, j;
const XML_Char *outputDir = NULL;
const XML_Char *encoding = NULL;
@@ -649,12 +901,14 @@ tmain(int argc, XML_Char **argv)
int outputType = 0;
int useNamespaces = 0;
int requireStandalone = 0;
- enum XML_ParamEntityParsing paramEntityParsing =
- XML_PARAM_ENTITY_PARSING_NEVER;
+ int requiresNotations = 0;
+ enum XML_ParamEntityParsing paramEntityParsing
+ = XML_PARAM_ENTITY_PARSING_NEVER;
int useStdin = 0;
+ XmlwfUserData userData = {NULL, NULL, NULL};
#ifdef _MSC_VER
- _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
i = 1;
@@ -706,13 +960,16 @@ tmain(int argc, XML_Char **argv)
outputType = 't';
j++;
break;
+ case T('N'):
+ requiresNotations = 1;
+ j++;
+ break;
case T('d'):
if (argv[i][j + 1] == T('\0')) {
if (++i == argc)
usage(argv[0], 2);
outputDir = argv[i];
- }
- else
+ } else
outputDir = argv[i] + j + 1;
i++;
j = 0;
@@ -722,8 +979,7 @@ tmain(int argc, XML_Char **argv)
if (++i == argc)
usage(argv[0], 2);
encoding = argv[i];
- }
- else
+ } else
encoding = argv[i] + j + 1;
i++;
j = 0;
@@ -751,7 +1007,6 @@ tmain(int argc, XML_Char **argv)
i--;
}
for (; i < argc; i++) {
- FILE *fp = 0;
XML_Char *outName = 0;
int result;
XML_Parser parser;
@@ -759,6 +1014,12 @@ tmain(int argc, XML_Char **argv)
parser = XML_ParserCreateNS(encoding, NSSEP);
else
parser = XML_ParserCreate(encoding);
+
+ if (! parser) {
+ tperror(T("Could not instantiate parser"));
+ exit(1);
+ }
+
if (requireStandalone)
XML_SetNotStandaloneHandler(parser, notStandalone);
XML_SetParamEntityParsing(parser, paramEntityParsing);
@@ -769,18 +1030,17 @@ tmain(int argc, XML_Char **argv)
XML_SetElementHandler(parser, nopStartElement, nopEndElement);
XML_SetCharacterDataHandler(parser, nopCharacterData);
XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction);
- }
- else if (outputDir) {
- const XML_Char * delim = T("/");
+ } else if (outputDir) {
+ const XML_Char *delim = T("/");
const XML_Char *file = useStdin ? T("STDIN") : argv[i];
- if (!useStdin) {
+ if (! useStdin) {
/* Jump after last (back)slash */
- const XML_Char * lastDelim = tcsrchr(file, delim[0]);
+ const XML_Char *lastDelim = tcsrchr(file, delim[0]);
if (lastDelim)
file = lastDelim + 1;
-#if (defined(WIN32) || defined(__WATCOMC__))
+#if defined(_WIN32)
else {
- const XML_Char * winDelim = T("\\");
+ const XML_Char *winDelim = T("\\");
lastDelim = tcsrchr(file, winDelim[0]);
if (lastDelim) {
file = lastDelim + 1;
@@ -790,20 +1050,24 @@ tmain(int argc, XML_Char **argv)
#endif
}
outName = (XML_Char *)malloc((tcslen(outputDir) + tcslen(file) + 2)
- * sizeof(XML_Char));
+ * sizeof(XML_Char));
+ if (! outName) {
+ tperror(T("Could not allocate memory"));
+ exit(1);
+ }
tcscpy(outName, outputDir);
tcscat(outName, delim);
tcscat(outName, file);
- fp = tfopen(outName, T("wb"));
- if (!fp) {
+ userData.fp = tfopen(outName, T("wb"));
+ if (! userData.fp) {
tperror(outName);
- exit(1);
+ exit(3);
}
- setvbuf(fp, NULL, _IOFBF, 16384);
+ setvbuf(userData.fp, NULL, _IOFBF, 16384);
#ifdef XML_UNICODE
- puttc(0xFEFF, fp);
+ puttc(0xFEFF, userData.fp);
#endif
- XML_SetUserData(parser, fp);
+ XML_SetUserData(parser, &userData);
switch (outputType) {
case 'm':
XML_UseParserAsHandlerArg(parser);
@@ -837,6 +1101,10 @@ tmain(int argc, XML_Char **argv)
XML_SetCharacterDataHandler(parser, characterData);
#ifndef W3C14N
XML_SetProcessingInstructionHandler(parser, processingInstruction);
+ if (requiresNotations) {
+ XML_SetDoctypeDeclHandler(parser, startDoctypeDecl, endDoctypeDecl);
+ XML_SetNotationDeclHandler(parser, notationDecl);
+ }
#endif /* not W3C14N */
break;
}
@@ -847,14 +1115,16 @@ tmain(int argc, XML_Char **argv)
if (outputDir) {
if (outputType == 'm')
metaEndDocument(parser);
- fclose(fp);
- if (!result) {
+ fclose(userData.fp);
+ if (! result) {
tremove(outName);
- exit(2);
}
free(outName);
}
XML_ParserFree(parser);
+ if (! result) {
+ exit(2);
+ }
}
return 0;
}
diff --git a/3rdparty/expat/xmlwf/xmlwf.dsp b/3rdparty/expat/xmlwf/xmlwf.dsp
deleted file mode 100644
index eb80c62bea6..00000000000
--- a/3rdparty/expat/xmlwf/xmlwf.dsp
+++ /dev/null
@@ -1,139 +0,0 @@
-# Microsoft Developer Studio Project File - Name="xmlwf" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=xmlwf - Win32 Release
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "xmlwf.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "xmlwf.mak" CFG="xmlwf - Win32 Release"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "xmlwf - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "xmlwf - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "xmlwf - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir ".\Release"
-# PROP BASE Intermediate_Dir ".\Release"
-# PROP BASE Target_Dir "."
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\win32\bin\Release"
-# PROP Intermediate_Dir "..\win32\tmp\Release-xmlwf"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir "."
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\lib" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "COMPILED_FROM_DSP" /FD /c
-# SUBTRACT CPP /YX /Yc /Yu
-# ADD BASE RSC /l 0x809 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /machine:I386
-# ADD LINK32 libexpat.lib setargv.obj /nologo /subsystem:console /pdb:none /machine:I386 /libpath:"..\win32\bin\Release" /out:"..\win32\bin\Release\xmlwf.exe"
-# SUBTRACT LINK32 /nodefaultlib
-
-!ELSEIF "$(CFG)" == "xmlwf - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir ".\Debug"
-# PROP BASE Intermediate_Dir ".\Debug"
-# PROP BASE Target_Dir "."
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\win32\bin\Debug"
-# PROP Intermediate_Dir "..\win32\tmp\Debug-xmlwf"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir "."
-# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c
-# ADD CPP /nologo /MTd /W3 /GX /ZI /Od /I "..\lib" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "COMPILED_FROM_DSP" /FD /c
-# SUBTRACT CPP /Fr /YX
-# ADD BASE RSC /l 0x809 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /subsystem:console /debug /machine:I386
-# ADD LINK32 libexpat.lib setargv.obj /nologo /subsystem:console /pdb:none /debug /machine:I386 /libpath:"..\win32\bin\Debug" /out:"..\win32\bin\Debug\xmlwf.exe"
-
-!ENDIF
-
-# Begin Target
-
-# Name "xmlwf - Win32 Release"
-# Name "xmlwf - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
-# Begin Source File
-
-SOURCE=.\codepage.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\readfilemap.c
-# PROP Exclude_From_Build 1
-# End Source File
-# Begin Source File
-
-SOURCE=.\unixfilemap.c
-# PROP Exclude_From_Build 1
-# End Source File
-# Begin Source File
-
-SOURCE=.\win32filemap.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlfile.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlwf.c
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
-# Begin Source File
-
-SOURCE=.\codepage.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmlfile.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\xmltchar.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/3rdparty/expat/xmlwf/xmlwf_helpgen.py b/3rdparty/expat/xmlwf/xmlwf_helpgen.py
new file mode 100755
index 00000000000..939286e5c2c
--- /dev/null
+++ b/3rdparty/expat/xmlwf/xmlwf_helpgen.py
@@ -0,0 +1,69 @@
+#! /usr/bin/env python3
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2019 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+import argparse
+
+epilog = """
+xmlwf of libexpat is software libre, licensed under the MIT license.
+Please report bugs at https://github.com/libexpat/libexpat/issues. Thank you!
+"""
+
+parser = argparse.ArgumentParser(prog='xmlwf', add_help=False,
+ description='xmlwf - Determines if an XML document is well-formed',
+ formatter_class=argparse.RawTextHelpFormatter,
+ epilog=epilog)
+
+input_related = parser.add_argument_group('input control arguments')
+input_related.add_argument('-s', action='store_true', help='print an error if the document is not [s]tandalone')
+input_related.add_argument('-n', action='store_true', help='enable [n]amespace processing')
+input_related.add_argument('-p', action='store_true', help='enable processing external DTDs and [p]arameter entities')
+input_related.add_argument('-x', action='store_true', help='enable processing of e[x]ternal entities')
+input_related.add_argument('-e', action='store', metavar='ENCODING', help='override any in-document [e]ncoding declaration')
+input_related.add_argument('-w', action='store_true', help='enable support for [W]indows code pages')
+input_related.add_argument('-r', action='store_true', help='disable memory-mapping and use normal file [r]ead IO calls instead')
+
+output_related = parser.add_argument_group('output control arguments')
+output_related.add_argument('-d', action='store', metavar='DIRECTORY', help='output [d]estination directory')
+output_mode = output_related.add_mutually_exclusive_group()
+output_mode.add_argument('-c', action='store_true', help='write a [c]opy of input XML, not canonical XML')
+output_mode.add_argument('-m', action='store_true', help='write [m]eta XML, not canonical XML')
+output_mode.add_argument('-t', action='store_true', help='write no XML output for [t]iming of plain parsing')
+output_related.add_argument('-N', action='store_true', help='enable adding doctype and [n]otation declarations')
+
+parser.add_argument('files', metavar='FILE', nargs='*', help='file to process (default: STDIN)')
+
+info = parser.add_argument_group('info arguments')
+info = info.add_mutually_exclusive_group()
+info.add_argument('-h', action='store_true', help='show this [h]elp message and exit')
+info.add_argument('-v', action='store_true', help='show program\'s [v]ersion number and exit')
+
+
+if __name__ == '__main__':
+ parser.print_help()
diff --git a/3rdparty/expat/xmlwf/xmlwf_helpgen.sh b/3rdparty/expat/xmlwf/xmlwf_helpgen.sh
new file mode 100755
index 00000000000..6b0fbf929a0
--- /dev/null
+++ b/3rdparty/expat/xmlwf/xmlwf_helpgen.sh
@@ -0,0 +1,35 @@
+#! /usr/bin/env bash
+# __ __ _
+# ___\ \/ /_ __ __ _| |_
+# / _ \\ /| '_ \ / _` | __|
+# | __// \| |_) | (_| | |_
+# \___/_/\_\ .__/ \__,_|\__|
+# |_| XML parser
+#
+# Copyright (c) 2019 Expat development team
+# Licensed under the MIT license:
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+./xmlwf/xmlwf_helpgen.py | sed \
+ -e 's,usage: xmlwf,usage: %s,' \
+ -e 's, \[-h | -v\],,' \
+ -e 's,^, T(",' \
+ -e 's,$,\\n"),'
diff --git a/3rdparty/expat/xmlwf/xmlwin32url.cxx b/3rdparty/expat/xmlwf/xmlwin32url.cxx
deleted file mode 100644
index bbfcce22c96..00000000000
--- a/3rdparty/expat/xmlwf/xmlwin32url.cxx
+++ /dev/null
@@ -1,395 +0,0 @@
-#include "expat.h"
-#ifdef XML_UNICODE
-#define UNICODE
-#endif
-#include <windows.h>
-#include <urlmon.h>
-#include <wininet.h>
-#include <stdio.h>
-#include <tchar.h>
-#include "xmlurl.h"
-#include "xmlmime.h"
-
-static int
-processURL(XML_Parser parser, IMoniker *baseMoniker, const XML_Char *url);
-
-typedef void (*StopHandler)(void *, HRESULT);
-
-class Callback : public IBindStatusCallback {
-public:
- // IUnknown methods
- STDMETHODIMP QueryInterface(REFIID,void **);
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
- // IBindStatusCallback methods
- STDMETHODIMP OnStartBinding(DWORD, IBinding *);
- STDMETHODIMP GetPriority(LONG *);
- STDMETHODIMP OnLowResource(DWORD);
- STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR);
- STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR);
- STDMETHODIMP GetBindInfo(DWORD *, BINDINFO *);
- STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC *, STGMEDIUM *);
- STDMETHODIMP OnObjectAvailable(REFIID, IUnknown *);
- Callback(XML_Parser, IMoniker *, StopHandler, void *);
- ~Callback();
- int externalEntityRef(const XML_Char *context,
- const XML_Char *systemId, const XML_Char *publicId);
-private:
- XML_Parser parser_;
- IMoniker *baseMoniker_;
- DWORD totalRead_;
- ULONG ref_;
- IBinding *pBinding_;
- StopHandler stopHandler_;
- void *stopArg_;
-};
-
-STDMETHODIMP_(ULONG)
-Callback::AddRef()
-{
- return ref_++;
-}
-
-STDMETHODIMP_(ULONG)
-Callback::Release()
-{
- if (--ref_ == 0) {
- delete this;
- return 0;
- }
- return ref_;
-}
-
-STDMETHODIMP
-Callback::QueryInterface(REFIID riid, void** ppv)
-{
- if (IsEqualGUID(riid, IID_IUnknown))
- *ppv = (IUnknown *)this;
- else if (IsEqualGUID(riid, IID_IBindStatusCallback))
- *ppv = (IBindStatusCallback *)this;
- else
- return E_NOINTERFACE;
- ((LPUNKNOWN)*ppv)->AddRef();
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::OnStartBinding(DWORD, IBinding* pBinding)
-{
- pBinding_ = pBinding;
- pBinding->AddRef();
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::GetPriority(LONG *)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP
-Callback::OnLowResource(DWORD)
-{
- return E_NOTIMPL;
-}
-
-STDMETHODIMP
-Callback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR)
-{
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::OnStopBinding(HRESULT hr, LPCWSTR szError)
-{
- if (pBinding_) {
- pBinding_->Release();
- pBinding_ = 0;
- }
- if (baseMoniker_) {
- baseMoniker_->Release();
- baseMoniker_ = 0;
- }
- stopHandler_(stopArg_, hr);
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo)
-{
- *pgrfBINDF = BINDF_ASYNCHRONOUS;
- return S_OK;
-}
-
-static void
-reportError(XML_Parser parser)
-{
- int code = XML_GetErrorCode(parser);
- const XML_Char *message = XML_ErrorString(code);
- if (message)
- _ftprintf(stderr, _T("%s:%d:%ld: %s\n"),
- XML_GetBase(parser),
- XML_GetErrorLineNumber(parser),
- XML_GetErrorColumnNumber(parser),
- message);
- else
- _ftprintf(stderr, _T("%s: (unknown message %d)\n"),
- XML_GetBase(parser), code);
-}
-
-STDMETHODIMP
-Callback::OnDataAvailable(DWORD grfBSCF,
- DWORD dwSize,
- FORMATETC *pfmtetc,
- STGMEDIUM* pstgmed)
-{
- if (grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
- IWinInetHttpInfo *hp;
- HRESULT hr = pBinding_->QueryInterface(IID_IWinInetHttpInfo,
- (void **)&hp);
- if (SUCCEEDED(hr)) {
- char contentType[1024];
- DWORD bufSize = sizeof(contentType);
- DWORD flags = 0;
- contentType[0] = 0;
- hr = hp->QueryInfo(HTTP_QUERY_CONTENT_TYPE, contentType,
- &bufSize, 0, NULL);
- if (SUCCEEDED(hr)) {
- char charset[CHARSET_MAX];
- getXMLCharset(contentType, charset);
- if (charset[0]) {
-#ifdef XML_UNICODE
- XML_Char wcharset[CHARSET_MAX];
- XML_Char *p1 = wcharset;
- const char *p2 = charset;
- while ((*p1++ = (unsigned char)*p2++) != 0)
- ;
- XML_SetEncoding(parser_, wcharset);
-#else
- XML_SetEncoding(parser_, charset);
-#endif
- }
- }
- hp->Release();
- }
- }
- if (!parser_)
- return E_ABORT;
- if (pstgmed->tymed == TYMED_ISTREAM) {
- while (totalRead_ < dwSize) {
-#define READ_MAX (64*1024)
- DWORD nToRead = dwSize - totalRead_;
- if (nToRead > READ_MAX)
- nToRead = READ_MAX;
- void *buf = XML_GetBuffer(parser_, nToRead);
- if (!buf) {
- _ftprintf(stderr, _T("out of memory\n"));
- return E_ABORT;
- }
- DWORD nRead;
- HRESULT hr = pstgmed->pstm->Read(buf, nToRead, &nRead);
- if (SUCCEEDED(hr)) {
- totalRead_ += nRead;
- if (!XML_ParseBuffer(parser_,
- nRead,
- (grfBSCF & BSCF_LASTDATANOTIFICATION) != 0
- && totalRead_ == dwSize)) {
- reportError(parser_);
- return E_ABORT;
- }
- }
- }
- }
- return S_OK;
-}
-
-STDMETHODIMP
-Callback::OnObjectAvailable(REFIID, IUnknown *)
-{
- return S_OK;
-}
-
-int
-Callback::externalEntityRef(const XML_Char *context,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- XML_Parser entParser = XML_ExternalEntityParserCreate(parser_, context, 0);
- XML_SetBase(entParser, systemId);
- int ret = processURL(entParser, baseMoniker_, systemId);
- XML_ParserFree(entParser);
- return ret;
-}
-
-Callback::Callback(XML_Parser parser, IMoniker *baseMoniker,
- StopHandler stopHandler, void *stopArg)
-: parser_(parser),
- baseMoniker_(baseMoniker),
- ref_(0),
- pBinding_(0),
- totalRead_(0),
- stopHandler_(stopHandler),
- stopArg_(stopArg)
-{
- if (baseMoniker_)
- baseMoniker_->AddRef();
-}
-
-Callback::~Callback()
-{
- if (pBinding_)
- pBinding_->Release();
- if (baseMoniker_)
- baseMoniker_->Release();
-}
-
-static int
-externalEntityRef(void *arg,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId)
-{
- return ((Callback *)arg)->externalEntityRef(context, systemId, publicId);
-}
-
-
-static HRESULT
-openStream(XML_Parser parser,
- IMoniker *baseMoniker,
- const XML_Char *uri,
- StopHandler stopHandler, void *stopArg)
-{
- if (!XML_SetBase(parser, uri))
- return E_OUTOFMEMORY;
- HRESULT hr;
- IMoniker *m;
-#ifdef XML_UNICODE
- hr = CreateURLMoniker(0, uri, &m);
-#else
- LPWSTR uriw = new wchar_t[strlen(uri) + 1];
- for (int i = 0;; i++) {
- uriw[i] = uri[i];
- if (uriw[i] == 0)
- break;
- }
- hr = CreateURLMoniker(baseMoniker, uriw, &m);
- delete [] uriw;
-#endif
- if (FAILED(hr))
- return hr;
- IBindStatusCallback *cb = new Callback(parser, m, stopHandler, stopArg);
- XML_SetExternalEntityRefHandler(parser, externalEntityRef);
- XML_SetExternalEntityRefHandlerArg(parser, cb);
- cb->AddRef();
- IBindCtx *b;
- if (FAILED(hr = CreateAsyncBindCtx(0, cb, 0, &b))) {
- cb->Release();
- m->Release();
- return hr;
- }
- cb->Release();
- IStream *pStream;
- hr = m->BindToStorage(b, 0, IID_IStream, (void **)&pStream);
- if (SUCCEEDED(hr)) {
- if (pStream)
- pStream->Release();
- }
- if (hr == MK_S_ASYNCHRONOUS)
- hr = S_OK;
- m->Release();
- b->Release();
- return hr;
-}
-
-struct QuitInfo {
- const XML_Char *url;
- HRESULT hr;
- int stop;
-};
-
-static void
-winPerror(const XML_Char *url, HRESULT hr)
-{
- LPVOID buf;
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
- | FORMAT_MESSAGE_FROM_HMODULE,
- GetModuleHandleA("urlmon.dll"),
- hr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &buf,
- 0,
- NULL)
- || FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
- | FORMAT_MESSAGE_FROM_SYSTEM,
- 0,
- hr,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &buf,
- 0,
- NULL)) {
- /* The system error messages seem to end with a newline. */
- _ftprintf(stderr, _T("%s: %s"), url, buf);
- fflush(stderr);
- LocalFree(buf);
- }
- else
- _ftprintf(stderr, _T("%s: error %x\n"), url, hr);
-}
-
-static void
-threadQuit(void *p, HRESULT hr)
-{
- QuitInfo *qi = (QuitInfo *)p;
- qi->hr = hr;
- qi->stop = 1;
-}
-
-extern "C"
-int
-XML_URLInit(void)
-{
- return SUCCEEDED(CoInitialize(0));
-}
-
-extern "C"
-void
-XML_URLUninit(void)
-{
- CoUninitialize();
-}
-
-static int
-processURL(XML_Parser parser, IMoniker *baseMoniker,
- const XML_Char *url)
-{
- QuitInfo qi;
- qi.stop = 0;
- qi.url = url;
-
- XML_SetBase(parser, url);
- HRESULT hr = openStream(parser, baseMoniker, url, threadQuit, &qi);
- if (FAILED(hr)) {
- winPerror(url, hr);
- return 0;
- }
- else if (FAILED(qi.hr)) {
- winPerror(url, qi.hr);
- return 0;
- }
- MSG msg;
- while (!qi.stop && GetMessage (&msg, NULL, 0, 0)) {
- TranslateMessage (&msg);
- DispatchMessage (&msg);
- }
- return 1;
-}
-
-extern "C"
-int
-XML_ProcessURL(XML_Parser parser,
- const XML_Char *url,
- unsigned flags)
-{
- return processURL(parser, 0, url);
-}
diff --git a/3rdparty/nanosvg/README.md b/3rdparty/nanosvg/README.md
index a672d6f60e6..0865cbe2673 100644
--- a/3rdparty/nanosvg/README.md
+++ b/3rdparty/nanosvg/README.md
@@ -1,9 +1,11 @@
+*This project is not actively maintained.*
+
Nano SVG
==========
## Parser
-![screenshot of some splines rendered witht the sample program](/example/screenshot-1.png?raw=true)
+![screenshot of some splines rendered with the sample program](/example/screenshot-1.png?raw=true)
NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
@@ -17,7 +19,7 @@ That is, you should get the same looking data as your designed in your favorite
NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
-The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
+The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
DPI (dots-per-inch) controls how the unit conversion is done.
If you don't know or care about the units stuff, "px" and 96 should get you going.
@@ -97,4 +99,4 @@ $ ./example
# License
-The library is licensed under [zlib license](LICENSE.txt) \ No newline at end of file
+The library is licensed under [zlib license](LICENSE.txt)
diff --git a/3rdparty/nanosvg/example/example2.c b/3rdparty/nanosvg/example/example2.c
index 50fe2a4e12b..9ae9b5952fe 100644
--- a/3rdparty/nanosvg/example/example2.c
+++ b/3rdparty/nanosvg/example/example2.c
@@ -32,7 +32,7 @@ int main()
NSVGrasterizer *rast = NULL;
unsigned char* img = NULL;
int w, h;
- const char* filename = "../example/_test.svg";
+ const char* filename = "../example/23.svg";
printf("parsing %s\n", filename);
image = nsvgParseFromFile(filename, "px", 96.0f);
diff --git a/3rdparty/nanosvg/premake4.lua b/3rdparty/nanosvg/premake4.lua
index 2c6cfd4210e..8befd82ef3e 100644
--- a/3rdparty/nanosvg/premake4.lua
+++ b/3rdparty/nanosvg/premake4.lua
@@ -14,7 +14,7 @@ solution "nanosvg"
targetdir("build")
configuration { "linux" }
- links { "X11","Xrandr", "rt", "GL", "GLU", "pthread" }
+ links { "X11","Xrandr", "rt", "GL", "GLU", "pthread", "glfw" }
configuration { "windows" }
links { "glu32","opengl32", "gdi32", "winmm", "user32" }
diff --git a/3rdparty/nanosvg/src/nanosvg.h b/3rdparty/nanosvg/src/nanosvg.h
index e41e093a97c..22edd71d735 100644
--- a/3rdparty/nanosvg/src/nanosvg.h
+++ b/3rdparty/nanosvg/src/nanosvg.h
@@ -29,9 +29,11 @@
#ifndef NANOSVG_H
#define NANOSVG_H
+#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
+#endif
// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
//
@@ -45,15 +47,15 @@ extern "C" {
// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
//
-// The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
+// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
// DPI (dots-per-inch) controls how the unit conversion is done.
//
// If you don't know or care about the units stuff, "px" and 96 should get you going.
/* Example Usage:
- // Load
- NSVGImage* image;
+ // Load SVG
+ NSVGimage* image;
image = nsvgParseFromFile("test.svg", "px", 96);
printf("size: %f x %f\n", image->width, image->height);
// Use...
@@ -73,30 +75,30 @@ enum NSVGpaintType {
NSVG_PAINT_NONE = 0,
NSVG_PAINT_COLOR = 1,
NSVG_PAINT_LINEAR_GRADIENT = 2,
- NSVG_PAINT_RADIAL_GRADIENT = 3,
+ NSVG_PAINT_RADIAL_GRADIENT = 3
};
enum NSVGspreadType {
NSVG_SPREAD_PAD = 0,
NSVG_SPREAD_REFLECT = 1,
- NSVG_SPREAD_REPEAT = 2,
+ NSVG_SPREAD_REPEAT = 2
};
enum NSVGlineJoin {
NSVG_JOIN_MITER = 0,
NSVG_JOIN_ROUND = 1,
- NSVG_JOIN_BEVEL = 2,
+ NSVG_JOIN_BEVEL = 2
};
enum NSVGlineCap {
NSVG_CAP_BUTT = 0,
NSVG_CAP_ROUND = 1,
- NSVG_CAP_SQUARE = 2,
+ NSVG_CAP_SQUARE = 2
};
enum NSVGfillRule {
NSVG_FILLRULE_NONZERO = 0,
- NSVG_FILLRULE_EVENODD = 1,
+ NSVG_FILLRULE_EVENODD = 1
};
enum NSVGflags {
@@ -146,6 +148,7 @@ typedef struct NSVGshape
char strokeDashCount; // Number of dash values in dash array.
char strokeLineJoin; // Stroke join type.
char strokeLineCap; // Stroke cap type.
+ float miterLimit; // Miter limit
char fillRule; // Fill rule, see NSVGfillRule.
unsigned char flags; // Logical or of NSVG_FLAGS_* flags
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
@@ -167,24 +170,28 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
// Important note: changes the string.
NSVGimage* nsvgParse(char* input, const char* units, float dpi);
-// Deletes list of paths.
+// Duplicates a path.
+NSVGpath* nsvgDuplicatePath(NSVGpath* p);
+
+// Deletes an image.
void nsvgDelete(NSVGimage* image);
+#ifndef NANOSVG_CPLUSPLUS
#ifdef __cplusplus
-};
+}
+#endif
#endif
#endif // NANOSVG_H
#ifdef NANOSVG_IMPLEMENTATION
-#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define NSVG_PI (3.14159265358979323846264338327f)
-#define NSVG_KAPPA90 (0.5522847493f) // Lenght proportional to radius of a cubic bezier handle for 90deg arcs.
+#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
#define NSVG_ALIGN_MIN 0
#define NSVG_ALIGN_MID 1
@@ -216,12 +223,7 @@ static int nsvg__isspace(char c)
static int nsvg__isdigit(char c)
{
- return strchr("0123456789", c) != 0;
-}
-
-static int nsvg__isnum(char c)
-{
- return strchr("0123456789+-.eE", c) != 0;
+ return c >= '0' && c <= '9';
}
static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
@@ -280,6 +282,9 @@ static void nsvg__parseElement(char* s,
// Get attribs
while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
+ char* name = NULL;
+ char* value = NULL;
+
// Skip white space before the attrib name
while (*s && nsvg__isspace(*s)) s++;
if (!*s) break;
@@ -287,7 +292,7 @@ static void nsvg__parseElement(char* s,
end = 1;
break;
}
- attr[nattr++] = s;
+ name = s;
// Find end of the attrib name.
while (*s && !nsvg__isspace(*s) && *s != '=') s++;
if (*s) { *s++ = '\0'; }
@@ -297,9 +302,15 @@ static void nsvg__parseElement(char* s,
quote = *s;
s++;
// Store value and find the end of it.
- attr[nattr++] = s;
+ value = s;
while (*s && *s != quote) s++;
if (*s) { *s++ = '\0'; }
+
+ // Store only well formed attributes
+ if (name && value) {
+ attr[nattr++] = name;
+ attr[nattr++] = value;
+ }
}
// List terminator
@@ -350,7 +361,7 @@ int nsvg__parseXML(char* input,
enum NSVGgradientUnits {
NSVG_USER_SPACE = 0,
- NSVG_OBJECT_SPACE = 1,
+ NSVG_OBJECT_SPACE = 1
};
#define NSVG_MAX_DASHES 8
@@ -365,7 +376,7 @@ enum NSVGunits {
NSVG_UNITS_IN,
NSVG_UNITS_PERCENT,
NSVG_UNITS_EM,
- NSVG_UNITS_EX,
+ NSVG_UNITS_EX
};
typedef struct NSVGcoordinate {
@@ -416,6 +427,7 @@ typedef struct NSVGattrib
int strokeDashCount;
char strokeLineJoin;
char strokeLineCap;
+ float miterLimit;
char fillRule;
float fontSize;
unsigned int stopColor;
@@ -436,6 +448,7 @@ typedef struct NSVGparser
NSVGpath* plist;
NSVGimage* image;
NSVGgradientData* gradients;
+ NSVGshape* shapesTail;
float viewMinx, viewMiny, viewWidth, viewHeight;
int alignX, alignY, alignType;
float dpi;
@@ -625,6 +638,7 @@ static NSVGparser* nsvg__createParser()
p->attr[0].strokeWidth = 1;
p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
+ p->attr[0].miterLimit = 4;
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
p->attr[0].hasFill = 1;
p->attr[0].visible = 1;
@@ -721,9 +735,11 @@ static void nsvg__lineTo(NSVGparser* p, float x, float y)
static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
{
- nsvg__addPoint(p, cpx1, cpy1);
- nsvg__addPoint(p, cpx2, cpy2);
- nsvg__addPoint(p, x, y);
+ if (p->npts > 0) {
+ nsvg__addPoint(p, cpx1, cpy1);
+ nsvg__addPoint(p, cpx2, cpy2);
+ nsvg__addPoint(p, x, y);
+ }
}
static NSVGattrib* nsvg__getAttr(NSVGparser* p)
@@ -793,7 +809,9 @@ static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig,
static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
{
NSVGgradientData* grad = p->gradients;
- while (grad) {
+ if (id == NULL || *id == '\0')
+ return NULL;
+ while (grad != NULL) {
if (strcmp(grad->id, id) == 0)
return grad;
grad = grad->next;
@@ -810,19 +828,26 @@ static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const f
NSVGgradient* grad;
float ox, oy, sw, sh, sl;
int nstops = 0;
+ int refIter;
data = nsvg__findGradientData(p, id);
if (data == NULL) return NULL;
// TODO: use ref to fill in all unset values too.
ref = data;
+ refIter = 0;
while (ref != NULL) {
+ NSVGgradientData* nextRef = NULL;
if (stops == NULL && ref->stops != NULL) {
stops = ref->stops;
nstops = ref->nstops;
break;
}
- ref = nsvg__findGradientData(p, ref->ref);
+ nextRef = nsvg__findGradientData(p, ref->ref);
+ if (nextRef == ref) break; // prevent infite loops on malformed data
+ ref = nextRef;
+ refIter++;
+ if (refIter > 32) break; // prevent infite loops on malformed data
}
if (stops == NULL) return NULL;
@@ -923,7 +948,7 @@ static void nsvg__addShape(NSVGparser* p)
{
NSVGattrib* attr = nsvg__getAttr(p);
float scale = 1.0f;
- NSVGshape *shape, *cur, *prev;
+ NSVGshape* shape;
NSVGpath* path;
int i;
@@ -939,11 +964,12 @@ static void nsvg__addShape(NSVGparser* p)
scale = nsvg__getAverageScale(attr->xform);
shape->strokeWidth = attr->strokeWidth * scale;
shape->strokeDashOffset = attr->strokeDashOffset * scale;
- shape->strokeDashCount = attr->strokeDashCount;
+ shape->strokeDashCount = (char)attr->strokeDashCount;
for (i = 0; i < attr->strokeDashCount; i++)
shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
shape->strokeLineJoin = attr->strokeLineJoin;
shape->strokeLineCap = attr->strokeLineCap;
+ shape->miterLimit = attr->miterLimit;
shape->fillRule = attr->fillRule;
shape->opacity = attr->opacity;
@@ -999,16 +1025,11 @@ static void nsvg__addShape(NSVGparser* p)
shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
// Add to tail
- prev = NULL;
- cur = p->image->shapes;
- while (cur != NULL) {
- prev = cur;
- cur = cur->next;
- }
- if (prev == NULL)
+ if (p->image->shapes == NULL)
p->image->shapes = shape;
else
- prev->next = shape;
+ p->shapesTail->next = shape;
+ p->shapesTail = shape;
return;
@@ -1030,6 +1051,10 @@ static void nsvg__addPath(NSVGparser* p, char closed)
if (closed)
nsvg__lineTo(p, p->pts[0], p->pts[1]);
+ // Expect 1 + N*3 points (N = number of cubic bezier segments).
+ if ((p->npts % 3) != 1)
+ return;
+
path = (NSVGpath*)malloc(sizeof(NSVGpath));
if (path == NULL) goto error;
memset(path, 0, sizeof(NSVGpath));
@@ -1072,6 +1097,66 @@ error:
}
}
+// We roll our own string to float because the std library one uses locale and messes things up.
+static double nsvg__atof(const char* s)
+{
+ char* cur = (char*)s;
+ char* end = NULL;
+ double res = 0.0, sign = 1.0;
+ long long intPart = 0, fracPart = 0;
+ char hasIntPart = 0, hasFracPart = 0;
+
+ // Parse optional sign
+ if (*cur == '+') {
+ cur++;
+ } else if (*cur == '-') {
+ sign = -1;
+ cur++;
+ }
+
+ // Parse integer part
+ if (nsvg__isdigit(*cur)) {
+ // Parse digit sequence
+ intPart = strtoll(cur, &end, 10);
+ if (cur != end) {
+ res = (double)intPart;
+ hasIntPart = 1;
+ cur = end;
+ }
+ }
+
+ // Parse fractional part.
+ if (*cur == '.') {
+ cur++; // Skip '.'
+ if (nsvg__isdigit(*cur)) {
+ // Parse digit sequence
+ fracPart = strtoll(cur, &end, 10);
+ if (cur != end) {
+ res += (double)fracPart / pow(10.0, (double)(end - cur));
+ hasFracPart = 1;
+ cur = end;
+ }
+ }
+ }
+
+ // A valid number should have integer or fractional part.
+ if (!hasIntPart && !hasFracPart)
+ return 0.0;
+
+ // Parse optional exponent
+ if (*cur == 'e' || *cur == 'E') {
+ long expPart = 0;
+ cur++; // skip 'E'
+ expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
+ if (cur != end) {
+ res *= pow(10.0, (double)expPart);
+ }
+ }
+
+ return res * sign;
+}
+
+
static const char* nsvg__parseNumber(const char* s, char* it, const int size)
{
const int last = size-1;
@@ -1098,7 +1183,7 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size)
}
}
// exponent
- if (*s == 'e' || *s == 'E') {
+ if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
if (i < last) it[i++] = *s;
s++;
if (*s == '-' || *s == '+') {
@@ -1352,13 +1437,19 @@ static unsigned int nsvg__parseColor(const char* str)
static float nsvg__parseOpacity(const char* str)
{
- float val = 0;
- sscanf(str, "%f", &val);
+ float val = nsvg__atof(str);
if (val < 0.0f) val = 0.0f;
if (val > 1.0f) val = 1.0f;
return val;
}
+static float nsvg__parseMiterLimit(const char* str)
+{
+ float val = nsvg__atof(str);
+ if (val < 0.0f) val = 0.0f;
+ return val;
+}
+
static int nsvg__parseUnits(const char* units)
{
if (units[0] == 'p' && units[1] == 'x')
@@ -1382,12 +1473,21 @@ static int nsvg__parseUnits(const char* units)
return NSVG_UNITS_USER;
}
+static int nsvg__isCoordinate(const char* s)
+{
+ // optional sign
+ if (*s == '-' || *s == '+')
+ s++;
+ // must have at least one digit
+ return nsvg__isdigit(*s);
+}
+
static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
{
NSVGcoordinate coord = {0, NSVG_UNITS_USER};
- char units[32]="";
- sscanf(str, "%f%s", &coord.value, units);
- coord.units = nsvg__parseUnits(units);
+ char buf[64];
+ coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
+ coord.value = nsvg__atof(buf);
return coord;
}
@@ -1423,7 +1523,7 @@ static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int
if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
if (*na >= maxNa) return 0;
ptr = nsvg__parseNumber(ptr, it, 64);
- args[(*na)++] = (float)atof(it);
+ args[(*na)++] = (float)nsvg__atof(it);
} else {
++ptr;
}
@@ -1521,25 +1621,32 @@ static int nsvg__parseRotate(float* xform, const char* str)
static void nsvg__parseTransform(float* xform, const char* str)
{
float t[6];
+ int len;
nsvg__xformIdentity(xform);
while (*str)
{
if (strncmp(str, "matrix", 6) == 0)
- str += nsvg__parseMatrix(t, str);
+ len = nsvg__parseMatrix(t, str);
else if (strncmp(str, "translate", 9) == 0)
- str += nsvg__parseTranslate(t, str);
+ len = nsvg__parseTranslate(t, str);
else if (strncmp(str, "scale", 5) == 0)
- str += nsvg__parseScale(t, str);
+ len = nsvg__parseScale(t, str);
else if (strncmp(str, "rotate", 6) == 0)
- str += nsvg__parseRotate(t, str);
+ len = nsvg__parseRotate(t, str);
else if (strncmp(str, "skewX", 5) == 0)
- str += nsvg__parseSkewX(t, str);
+ len = nsvg__parseSkewX(t, str);
else if (strncmp(str, "skewY", 5) == 0)
- str += nsvg__parseSkewY(t, str);
+ len = nsvg__parseSkewY(t, str);
else{
++str;
continue;
}
+ if (len != 0) {
+ str += len;
+ } else {
+ ++str;
+ continue;
+ }
nsvg__xformPremultiply(xform, t);
}
@@ -1579,7 +1686,7 @@ static char nsvg__parseLineJoin(const char* str)
else if (strcmp(str, "bevel") == 0)
return NSVG_JOIN_BEVEL;
// TODO: handle inherit.
- return NSVG_CAP_BUTT;
+ return NSVG_JOIN_MITER;
}
static char nsvg__parseFillRule(const char* str)
@@ -1685,6 +1792,8 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
attr->strokeLineCap = nsvg__parseLineCap(value);
} else if (strcmp(name, "stroke-linejoin") == 0) {
attr->strokeLineJoin = nsvg__parseLineJoin(value);
+ } else if (strcmp(name, "stroke-miterlimit") == 0) {
+ attr->miterLimit = nsvg__parseMiterLimit(value);
} else if (strcmp(name, "fill-rule") == 0) {
attr->fillRule = nsvg__parseFillRule(value);
} else if (strcmp(name, "font-size") == 0) {
@@ -1798,8 +1907,11 @@ static int nsvg__getArgsPerElement(char cmd)
case 'a':
case 'A':
return 7;
+ case 'z':
+ case 'Z':
+ return 0;
}
- return 0;
+ return -1;
}
static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
@@ -2001,7 +2113,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
rx = fabsf(args[0]); // y radius
ry = fabsf(args[1]); // x radius
- rotx = args[2] / 180.0f * NSVG_PI; // x rotation engle
+ rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
x1 = *cpx; // start point
@@ -2066,13 +2178,10 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
- if (fa) {
- // Choose large arc
- if (da > 0.0f)
- da = da - 2*NSVG_PI;
- else
- da = 2*NSVG_PI + da;
- }
+ if (fs == 0 && da > 0)
+ da -= 2 * NSVG_PI;
+ else if (fs == 1 && da < 0)
+ da += 2 * NSVG_PI;
// Approximate the arc using cubic spline segments.
t[0] = cosrx; t[1] = sinrx;
@@ -2088,7 +2197,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
kappa = -kappa;
for (i = 0; i <= ndivs; i++) {
- a = a1 + da * (i/(float)ndivs);
+ a = a1 + da * ((float)i/(float)ndivs);
dx = cosf(a);
dy = sinf(a);
nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
@@ -2112,6 +2221,7 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
float args[10];
int nargs;
int rargs = 0;
+ char initPoint;
float cpx, cpy, cpx2, cpy2;
const char* tmp[4];
char closedFlag;
@@ -2134,15 +2244,16 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
nsvg__resetPath(p);
cpx = 0; cpy = 0;
cpx2 = 0; cpy2 = 0;
+ initPoint = 0;
closedFlag = 0;
nargs = 0;
while (*s) {
s = nsvg__getNextPathItem(s, item);
if (!*item) break;
- if (nsvg__isnum(item[0])) {
+ if (cmd != '\0' && nsvg__isCoordinate(item)) {
if (nargs < 10)
- args[nargs++] = (float)atof(item);
+ args[nargs++] = (float)nsvg__atof(item);
if (nargs >= rargs) {
switch (cmd) {
case 'm':
@@ -2151,23 +2262,24 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
// Moveto can be followed by multiple coordinate pairs,
// which should be treated as linetos.
cmd = (cmd == 'm') ? 'l' : 'L';
- rargs = nsvg__getArgsPerElement(cmd);
- cpx2 = cpx; cpy2 = cpy;
+ rargs = nsvg__getArgsPerElement(cmd);
+ cpx2 = cpx; cpy2 = cpy;
+ initPoint = 1;
break;
case 'l':
case 'L':
nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
case 'H':
case 'h':
nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
case 'V':
case 'v':
nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
case 'C':
case 'c':
@@ -2188,13 +2300,13 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
case 'A':
case 'a':
nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
break;
default:
if (nargs >= 2) {
cpx = args[nargs-2];
cpy = args[nargs-1];
- cpx2 = cpx; cpy2 = cpy;
+ cpx2 = cpx; cpy2 = cpy;
}
break;
}
@@ -2202,7 +2314,6 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
}
} else {
cmd = item[0];
- rargs = nsvg__getArgsPerElement(cmd);
if (cmd == 'M' || cmd == 'm') {
// Commit path.
if (p->npts > 0)
@@ -2211,7 +2322,11 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
nsvg__resetPath(p);
closedFlag = 0;
nargs = 0;
- } else if (cmd == 'Z' || cmd == 'z') {
+ } else if (initPoint == 0) {
+ // Do not allow other commands until initial point has been set (moveTo called once).
+ cmd = '\0';
+ }
+ if (cmd == 'Z' || cmd == 'z') {
closedFlag = 1;
// Commit path.
if (p->npts > 0) {
@@ -2227,6 +2342,12 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
closedFlag = 0;
nargs = 0;
}
+ rargs = nsvg__getArgsPerElement(cmd);
+ if (rargs == -1) {
+ // Command not recognized
+ cmd = '\0';
+ rargs = 0;
+ }
}
}
// Commit path.
@@ -2399,7 +2520,7 @@ static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
nargs = 0;
while (*s) {
s = nsvg__getNextPathItem(s, item);
- args[nargs++] = (float)atof(item);
+ args[nargs++] = (float)nsvg__atof(item);
if (nargs >= 2) {
if (npts == 0)
nsvg__moveTo(p, args[0], args[1]);
@@ -2424,11 +2545,26 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr)
for (i = 0; attr[i]; i += 2) {
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
if (strcmp(attr[i], "width") == 0) {
- p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
+ p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "height") == 0) {
- p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
+ p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
} else if (strcmp(attr[i], "viewBox") == 0) {
- sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight);
+ const char *s = attr[i + 1];
+ char buf[64];
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewMinx = nsvg__atof(buf);
+ while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+ if (!*s) return;
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewMiny = nsvg__atof(buf);
+ while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+ if (!*s) return;
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewWidth = nsvg__atof(buf);
+ while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+ if (!*s) return;
+ s = nsvg__parseNumber(s, buf, 64);
+ p->viewHeight = nsvg__atof(buf);
} else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
if (strstr(attr[i + 1], "none") != 0) {
// No uniform scaling
@@ -2593,7 +2729,6 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
if (p->pathFlag) // Do not allow nested paths.
return;
nsvg__pushAttr(p);
- p->pathFlag = 1;
p->shapeFlag = 1;
nsvg__parsePath(p, attr);
nsvg__popAttr(p);
@@ -2721,12 +2856,12 @@ static float nsvg__viewAlign(float content, float container, int type)
static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
{
- grad->xform[0] *= sx;
- grad->xform[1] *= sx;
- grad->xform[2] *= sy;
- grad->xform[3] *= sy;
- grad->xform[4] += tx*sx;
- grad->xform[5] += ty*sx;
+ float t[6];
+ nsvg__xformSetTranslation(t, tx, ty);
+ nsvg__xformMultiply (grad->xform, t);
+
+ nsvg__xformSetScale(t, sx, sy);
+ nsvg__xformMultiply (grad->xform, t);
}
static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
@@ -2873,6 +3008,36 @@ error:
return NULL;
}
+NSVGpath* nsvgDuplicatePath(NSVGpath* p)
+{
+ NSVGpath* res = NULL;
+
+ if (p == NULL)
+ return NULL;
+
+ res = (NSVGpath*)malloc(sizeof(NSVGpath));
+ if (res == NULL) goto error;
+ memset(res, 0, sizeof(NSVGpath));
+
+ res->pts = (float*)malloc(p->npts*2*sizeof(float));
+ if (res->pts == NULL) goto error;
+ memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
+ res->npts = p->npts;
+
+ memcpy(res->bounds, p->bounds, sizeof(p->bounds));
+
+ res->closed = p->closed;
+
+ return res;
+
+error:
+ if (res != NULL) {
+ free(res->pts);
+ free(res);
+ }
+ return NULL;
+}
+
void nsvgDelete(NSVGimage* image)
{
NSVGshape *snext, *shape;
diff --git a/3rdparty/nanosvg/src/nanosvgrast.h b/3rdparty/nanosvg/src/nanosvgrast.h
index c71d7b4a7c1..b740c316ca2 100644
--- a/3rdparty/nanosvg/src/nanosvgrast.h
+++ b/3rdparty/nanosvg/src/nanosvgrast.h
@@ -25,15 +25,18 @@
#ifndef NANOSVGRAST_H
#define NANOSVGRAST_H
+#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus
extern "C" {
#endif
+#endif
typedef struct NSVGrasterizer NSVGrasterizer;
/* Example Usage:
// Load SVG
- struct SNVGImage* image = nsvgParseFromFile("test.svg.");
+ NSVGimage* image;
+ image = nsvgParseFromFile("test.svg", "px", 96);
// Create rasterizer (can be used to render multiple images).
struct NSVGrasterizer* rast = nsvgCreateRasterizer();
@@ -63,8 +66,10 @@ void nsvgRasterize(NSVGrasterizer* r,
void nsvgDeleteRasterizer(NSVGrasterizer*);
+#ifndef NANOSVGRAST_CPLUSPLUS
#ifdef __cplusplus
-};
+}
+#endif
#endif
#endif // NANOSVGRAST_H
@@ -239,7 +244,7 @@ static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
if (r->npoints > 0) {
pt = &r->points[r->npoints-1];
if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
- pt->flags |= flags;
+ pt->flags = (unsigned char)(pt->flags | flags);
return;
}
}
@@ -388,7 +393,7 @@ enum NSVGpointFlags
{
NSVG_PT_CORNER = 0x01,
NSVG_PT_BEVEL = 0x02,
- NSVG_PT_LEFT = 0x04,
+ NSVG_PT_LEFT = 0x04
};
static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
@@ -454,7 +459,7 @@ static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right,
float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
for (i = 0; i < ncap; i++) {
- float a = i/(float)(ncap-1)*NSVG_PI;
+ float a = (float)i/(float)(ncap-1)*NSVG_PI;
float ax = cosf(a) * w, ay = sinf(a) * w;
float x = px - dlx*ax - dx*ay;
float y = py - dly*ax - dy*ay;
@@ -551,7 +556,7 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right
if (da < NSVG_PI) da += NSVG_PI*2;
if (da > NSVG_PI) da -= NSVG_PI*2;
- n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * ncap);
+ n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
if (n < 2) n = 2;
if (n > ncap) n = ncap;
@@ -561,7 +566,7 @@ static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right
ry = right->y;
for (i = 0; i < n; i++) {
- float u = i/(float)(n-1);
+ float u = (float)i/(float)(n-1);
float a = a0 + u*da;
float ax = cosf(a) * w, ay = sinf(a) * w;
float lx1 = p1->x - ax, ly1 = p1->y - ay;
@@ -732,7 +737,7 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float
int i, j, closed;
NSVGpath* path;
NSVGpoint* p0, *p1;
- float miterLimit = 4;
+ float miterLimit = shape->miterLimit;
int lineJoin = shape->strokeLineJoin;
int lineCap = shape->strokeLineCap;
float lineWidth = shape->strokeWidth * scale;
@@ -838,8 +843,8 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float
static int nsvg__cmpEdge(const void *p, const void *q)
{
- NSVGedge* a = (NSVGedge*)p;
- NSVGedge* b = (NSVGedge*)q;
+ const NSVGedge* a = (const NSVGedge*)p;
+ const NSVGedge* b = (const NSVGedge*)q;
if (a->y0 < b->y0) return -1;
if (a->y0 > b->y0) return 1;
@@ -892,20 +897,20 @@ static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1,
if (i < len && j >= 0) {
if (i == j) {
// x0,x1 are the same pixel, so compute combined coverage
- scanline[i] += (unsigned char)((x1 - x0) * maxWeight >> NSVG__FIXSHIFT);
+ scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
} else {
if (i >= 0) // add antialiasing for x0
- scanline[i] += (unsigned char)(((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT);
+ scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
else
i = -1; // clip
if (j < len) // add antialiasing for x1
- scanline[j] += (unsigned char)(((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT);
+ scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
else
j = len; // clip
for (++i; i < j; ++i) // fill pixels between x0 and x1
- scanline[i] += (unsigned char)maxWeight;
+ scanline[i] = (unsigned char)(scanline[i] + maxWeight);
}
}
}
@@ -1021,8 +1026,8 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co
int i, cr, cg, cb, ca;
unsigned int c;
- fx = (x - tx) / scale;
- fy = (y - ty) / scale;
+ fx = ((float)x - tx) / scale;
+ fy = ((float)y - ty) / scale;
dx = 1.0f / scale;
for (i = 0; i < count; i++) {
@@ -1066,8 +1071,8 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co
int i, cr, cg, cb, ca;
unsigned int c;
- fx = (x - tx) / scale;
- fy = (y - ty) / scale;
+ fx = ((float)x - tx) / scale;
+ fy = ((float)y - ty) / scale;
dx = 1.0f / scale;
for (i = 0; i < count; i++) {
@@ -1121,7 +1126,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl
xmax = 0;
for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
// find center of pixel for this scanline
- float scany = y*NSVG__SUBSAMPLES + s + 0.5f;
+ float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
NSVGactiveEdge **step = &active;
// update all active edges;
diff --git a/3rdparty/sqlite3/shell.c b/3rdparty/sqlite3/shell.c
index 732ef628328..a1a77e49fa5 100644
--- a/3rdparty/sqlite3/shell.c
+++ b/3rdparty/sqlite3/shell.c
@@ -1,3 +1,21 @@
+/* DO NOT EDIT!
+** This file is automatically generated by the script in the canonical
+** SQLite source tree at tool/mkshellc.tcl. That script combines source
+** code from various constituent source files of SQLite into this single
+** "shell.c" file used to implement the SQLite command-line shell.
+**
+** Most of the code found below comes from the "src/shell.c.in" file in
+** the canonical SQLite source tree. That main file contains "INCLUDE"
+** lines that specify other files in the canonical source tree that are
+** inserted to getnerate this complete program source file.
+**
+** The code from multiple files is combined into this single "shell.c"
+** source file to help make the command-line program easier to compile.
+**
+** To modify this program, get a copy of the canonical SQLite source tree,
+** edit the src/shell.c.in" and/or some of the other files that are included
+** by "src/shell.c.in", then rerun the tool/mkshellc.tcl script.
+*/
/*
** 2001 September 15
**
@@ -18,13 +36,35 @@
#endif
/*
-** If requested, include the SQLite compiler options file for MSVC.
+** Determine if we are dealing with WinRT, which provides only a subset of
+** the full Win32 API.
*/
-#if defined(INCLUDE_MSVC_H)
-#include "msvc.h"
+#if !defined(SQLITE_OS_WINRT)
+# define SQLITE_OS_WINRT 0
#endif
/*
+** Warning pragmas copied from msvc.h in the core.
+*/
+#if defined(_MSC_VER)
+#pragma warning(disable : 4054)
+#pragma warning(disable : 4055)
+#pragma warning(disable : 4100)
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4130)
+#pragma warning(disable : 4152)
+#pragma warning(disable : 4189)
+#pragma warning(disable : 4206)
+#pragma warning(disable : 4210)
+#pragma warning(disable : 4232)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305)
+#pragma warning(disable : 4306)
+#pragma warning(disable : 4702)
+#pragma warning(disable : 4706)
+#endif /* defined(_MSC_VER) */
+
+/*
** No support for loadable extensions in VxWorks.
*/
#if (defined(__RTP__) || defined(_WRS_KERNEL)) && !SQLITE_OMIT_LOAD_EXTENSION
@@ -47,6 +87,9 @@
#include <stdio.h>
#include <assert.h>
#include "sqlite3.h"
+typedef sqlite3_int64 i64;
+typedef sqlite3_uint64 u64;
+typedef unsigned char u8;
#if SQLITE_USER_AUTHENTICATION
# include "sqlite3userauth.h"
#endif
@@ -58,9 +101,22 @@
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
# include <pwd.h>
# endif
+#endif
+#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
# include <unistd.h>
-# include <sys/types.h>
+# include <dirent.h>
+# define GETPID getpid
+# if defined(__MINGW32__)
+# define DIRENT dirent
+# ifndef S_ISLNK
+# define S_ISLNK(mode) (0)
+# endif
+# endif
+#else
+# define GETPID (int)GetCurrentProcessId
#endif
+#include <sys/types.h>
+#include <sys/stat.h>
#if HAVE_READLINE
# include <readline/readline.h>
@@ -99,16 +155,26 @@
#if defined(_WIN32) || defined(WIN32)
-# include <io.h>
-# include <fcntl.h>
-# define isatty(h) _isatty(h)
-# ifndef access
-# define access(f,m) _access((f),(m))
+# if SQLITE_OS_WINRT
+# define SQLITE_OMIT_POPEN 1
+# else
+# include <io.h>
+# include <fcntl.h>
+# define isatty(h) _isatty(h)
+# ifndef access
+# define access(f,m) _access((f),(m))
+# endif
+# ifndef unlink
+# define unlink _unlink
+# endif
+# ifndef strdup
+# define strdup _strdup
+# endif
+# undef popen
+# define popen _popen
+# undef pclose
+# define pclose _pclose
# endif
-# undef popen
-# define popen _popen
-# undef pclose
-# define pclose _pclose
#else
/* Make sure isatty() has a prototype. */
extern int isatty(int);
@@ -137,6 +203,9 @@
#define ToLower(X) (char)tolower((unsigned char)X)
#if defined(_WIN32) || defined(WIN32)
+#if SQLITE_OS_WINRT
+#include <intrin.h>
+#endif
#include <windows.h>
/* string conversion routines only needed on Win32 */
@@ -152,7 +221,7 @@ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText);
** rendering quoted strings that contain \n characters). The following
** routines take care of that.
*/
-#if defined(_WIN32) || defined(WIN32)
+#if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
static void setBinaryMode(FILE *file, int isOutput){
if( isOutput ) fflush(file);
_setmode(_fileno(file), _O_BINARY);
@@ -256,6 +325,7 @@ static int hasTimer(void){
if( getProcessTimesAddr ){
return 1;
} else {
+#if !SQLITE_OS_WINRT
/* GetProcessTimes() isn't supported in WIN95 and some other Windows
** versions. See if the version we are running on has it, and if it
** does, save off a pointer to it and the current process handle.
@@ -272,6 +342,7 @@ static int hasTimer(void){
FreeLibrary(hinstLib);
}
}
+#endif
}
return 0;
}
@@ -326,6 +397,11 @@ static void endTimer(void){
#define UNUSED_PARAMETER(x) (void)(x)
/*
+** Number of elements in an array
+*/
+#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
+
+/*
** If the following flag is set, then command execution stops
** at an error if we are not interactive.
*/
@@ -356,6 +432,15 @@ static sqlite3 *globalDb = 0;
*/
static volatile int seenInterrupt = 0;
+#ifdef SQLITE_DEBUG
+/*
+** Out-of-memory simulator variables
+*/
+static unsigned int oomCounter = 0; /* Simulate OOM when equals 1 */
+static unsigned int oomRepeat = 0; /* Number of OOMs in a row */
+static void*(*defaultMalloc)(int) = 0; /* The low-level malloc routine */
+#endif /* SQLITE_DEBUG */
+
/*
** This is the name of our program. It is set in main(), used
** in a number of other places, mostly for error messages.
@@ -401,6 +486,55 @@ void utf8_printf(FILE *out, const char *zFormat, ...){
# define raw_printf fprintf
#endif
+/* Indicate out-of-memory and exit. */
+static void shell_out_of_memory(void){
+ raw_printf(stderr,"Error: out of memory\n");
+ exit(1);
+}
+
+#ifdef SQLITE_DEBUG
+/* This routine is called when a simulated OOM occurs. It is broken
+** out as a separate routine to make it easy to set a breakpoint on
+** the OOM
+*/
+void shellOomFault(void){
+ if( oomRepeat>0 ){
+ oomRepeat--;
+ }else{
+ oomCounter--;
+ }
+}
+#endif /* SQLITE_DEBUG */
+
+#ifdef SQLITE_DEBUG
+/* This routine is a replacement malloc() that is used to simulate
+** Out-Of-Memory (OOM) errors for testing purposes.
+*/
+static void *oomMalloc(int nByte){
+ if( oomCounter ){
+ if( oomCounter==1 ){
+ shellOomFault();
+ return 0;
+ }else{
+ oomCounter--;
+ }
+ }
+ return defaultMalloc(nByte);
+}
+#endif /* SQLITE_DEBUG */
+
+#ifdef SQLITE_DEBUG
+/* Register the OOM simulator. This must occur before any memory
+** allocations */
+static void registerOomSimulator(void){
+ sqlite3_mem_methods mem;
+ sqlite3_config(SQLITE_CONFIG_GETMALLOC, &mem);
+ defaultMalloc = mem.xMalloc;
+ mem.xMalloc = oomMalloc;
+ sqlite3_config(SQLITE_CONFIG_MALLOC, &mem);
+}
+#endif
+
/*
** Write I/O traces to the following stream.
*/
@@ -427,6 +561,36 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){
}
#endif
+/*
+** Output string zUtf to stream pOut as w characters. If w is negative,
+** then right-justify the text. W is the width in UTF-8 characters, not
+** in bytes. This is different from the %*.*s specification in printf
+** since with %*.*s the width is measured in bytes, not characters.
+*/
+static void utf8_width_print(FILE *pOut, int w, const char *zUtf){
+ int i;
+ int n;
+ int aw = w<0 ? -w : w;
+ char zBuf[1000];
+ if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3;
+ for(i=n=0; zUtf[i]; i++){
+ if( (zUtf[i]&0xc0)!=0x80 ){
+ n++;
+ if( n==aw ){
+ do{ i++; }while( (zUtf[i]&0xc0)==0x80 );
+ break;
+ }
+ }
+ }
+ if( n>=aw ){
+ utf8_printf(pOut, "%.*s", i, zUtf);
+ }else if( w<0 ){
+ utf8_printf(pOut, "%*s%s", aw-n, "", zUtf);
+ }else{
+ utf8_printf(pOut, "%s%*s", zUtf, aw-n, "");
+ }
+}
+
/*
** Determines if a string is a number of not.
@@ -456,28 +620,6 @@ static int isNumber(const char *z, int *realnum){
}
/*
-** A global char* and an SQL function to access its current value
-** from within an SQL statement. This program used to use the
-** sqlite_exec_printf() API to substitue a string into an SQL statement.
-** The correct way to do this with sqlite3 is to use the bind API, but
-** since the shell is built around the callback paradigm it would be a lot
-** of work. Instead just use this hack, which is quite harmless.
-*/
-static const char *zShellStatic = 0;
-static void shellstaticFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- assert( 0==argc );
- assert( zShellStatic );
- UNUSED_PARAMETER(argc);
- UNUSED_PARAMETER(argv);
- sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
-}
-
-
-/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
*/
@@ -488,6 +630,33 @@ static int strlen30(const char *z){
}
/*
+** Return the length of a string in characters. Multibyte UTF8 characters
+** count as a single character.
+*/
+static int strlenChar(const char *z){
+ int n = 0;
+ while( *z ){
+ if( (0xc0&*(z++))!=0x80 ) n++;
+ }
+ return n;
+}
+
+/*
+** Return true if zFile does not exist or if it is not an ordinary file.
+*/
+#ifdef _WIN32
+# define notNormalFile(X) 0
+#else
+static int notNormalFile(const char *zFile){
+ struct stat x;
+ int rc;
+ memset(&x, 0, sizeof(x));
+ rc = stat(zFile, &x);
+ return rc || !S_ISREG(x.st_mode);
+}
+#endif
+
+/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
@@ -504,7 +673,7 @@ static char *local_getline(char *zLine, FILE *in){
if( n+100>nLine ){
nLine = nLine*2 + 100;
zLine = realloc(zLine, nLine);
- if( zLine==0 ) return 0;
+ if( zLine==0 ) shell_out_of_memory();
}
if( fgets(&zLine[n], nLine - n, in)==0 ){
if( n==0 ){
@@ -531,10 +700,7 @@ static char *local_getline(char *zLine, FILE *in){
int nTrans = strlen30(zTrans)+1;
if( nTrans>nLine ){
zLine = realloc(zLine, nTrans);
- if( zLine==0 ){
- sqlite3_free(zTrans);
- return 0;
- }
+ if( zLine==0 ) shell_out_of_memory();
}
memcpy(zLine, zTrans, nTrans);
sqlite3_free(zTrans);
@@ -578,6 +744,9887 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
return zResult;
}
+
+/*
+** Return the value of a hexadecimal digit. Return -1 if the input
+** is not a hex digit.
+*/
+static int hexDigitValue(char c){
+ if( c>='0' && c<='9' ) return c - '0';
+ if( c>='a' && c<='f' ) return c - 'a' + 10;
+ if( c>='A' && c<='F' ) return c - 'A' + 10;
+ return -1;
+}
+
+/*
+** Interpret zArg as an integer value, possibly with suffixes.
+*/
+static sqlite3_int64 integerValue(const char *zArg){
+ sqlite3_int64 v = 0;
+ static const struct { char *zSuffix; int iMult; } aMult[] = {
+ { "KiB", 1024 },
+ { "MiB", 1024*1024 },
+ { "GiB", 1024*1024*1024 },
+ { "KB", 1000 },
+ { "MB", 1000000 },
+ { "GB", 1000000000 },
+ { "K", 1000 },
+ { "M", 1000000 },
+ { "G", 1000000000 },
+ };
+ int i;
+ int isNeg = 0;
+ if( zArg[0]=='-' ){
+ isNeg = 1;
+ zArg++;
+ }else if( zArg[0]=='+' ){
+ zArg++;
+ }
+ if( zArg[0]=='0' && zArg[1]=='x' ){
+ int x;
+ zArg += 2;
+ while( (x = hexDigitValue(zArg[0]))>=0 ){
+ v = (v<<4) + x;
+ zArg++;
+ }
+ }else{
+ while( IsDigit(zArg[0]) ){
+ v = v*10 + zArg[0] - '0';
+ zArg++;
+ }
+ }
+ for(i=0; i<ArraySize(aMult); i++){
+ if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
+ v *= aMult[i].iMult;
+ break;
+ }
+ }
+ return isNeg? -v : v;
+}
+
+/*
+** A variable length string to which one can append text.
+*/
+typedef struct ShellText ShellText;
+struct ShellText {
+ char *z;
+ int n;
+ int nAlloc;
+};
+
+/*
+** Initialize and destroy a ShellText object
+*/
+static void initText(ShellText *p){
+ memset(p, 0, sizeof(*p));
+}
+static void freeText(ShellText *p){
+ free(p->z);
+ initText(p);
+}
+
+/* zIn is either a pointer to a NULL-terminated string in memory obtained
+** from malloc(), or a NULL pointer. The string pointed to by zAppend is
+** added to zIn, and the result returned in memory obtained from malloc().
+** zIn, if it was not NULL, is freed.
+**
+** If the third argument, quote, is not '\0', then it is used as a
+** quote character for zAppend.
+*/
+static void appendText(ShellText *p, char const *zAppend, char quote){
+ int len;
+ int i;
+ int nAppend = strlen30(zAppend);
+
+ len = nAppend+p->n+1;
+ if( quote ){
+ len += 2;
+ for(i=0; i<nAppend; i++){
+ if( zAppend[i]==quote ) len++;
+ }
+ }
+
+ if( p->n+len>=p->nAlloc ){
+ p->nAlloc = p->nAlloc*2 + len + 20;
+ p->z = realloc(p->z, p->nAlloc);
+ if( p->z==0 ) shell_out_of_memory();
+ }
+
+ if( quote ){
+ char *zCsr = p->z+p->n;
+ *zCsr++ = quote;
+ for(i=0; i<nAppend; i++){
+ *zCsr++ = zAppend[i];
+ if( zAppend[i]==quote ) *zCsr++ = quote;
+ }
+ *zCsr++ = quote;
+ p->n = (int)(zCsr - p->z);
+ *zCsr = '\0';
+ }else{
+ memcpy(p->z+p->n, zAppend, nAppend);
+ p->n += nAppend;
+ p->z[p->n] = '\0';
+ }
+}
+
+/*
+** Attempt to determine if identifier zName needs to be quoted, either
+** because it contains non-alphanumeric characters, or because it is an
+** SQLite keyword. Be conservative in this estimate: When in doubt assume
+** that quoting is required.
+**
+** Return '"' if quoting is required. Return 0 if no quoting is required.
+*/
+static char quoteChar(const char *zName){
+ int i;
+ if( !isalpha((unsigned char)zName[0]) && zName[0]!='_' ) return '"';
+ for(i=0; zName[i]; i++){
+ if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ) return '"';
+ }
+ return sqlite3_keyword_check(zName, i) ? '"' : 0;
+}
+
+/*
+** Construct a fake object name and column list to describe the structure
+** of the view, virtual table, or table valued function zSchema.zName.
+*/
+static char *shellFakeSchema(
+ sqlite3 *db, /* The database connection containing the vtab */
+ const char *zSchema, /* Schema of the database holding the vtab */
+ const char *zName /* The name of the virtual table */
+){
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ ShellText s;
+ char cQuote;
+ char *zDiv = "(";
+ int nRow = 0;
+
+ zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;",
+ zSchema ? zSchema : "main", zName);
+ sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ initText(&s);
+ if( zSchema ){
+ cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0;
+ appendText(&s, zSchema, cQuote);
+ appendText(&s, ".", 0);
+ }
+ cQuote = quoteChar(zName);
+ appendText(&s, zName, cQuote);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zCol = (const char*)sqlite3_column_text(pStmt, 1);
+ nRow++;
+ appendText(&s, zDiv, 0);
+ zDiv = ",";
+ cQuote = quoteChar(zCol);
+ appendText(&s, zCol, cQuote);
+ }
+ appendText(&s, ")", 0);
+ sqlite3_finalize(pStmt);
+ if( nRow==0 ){
+ freeText(&s);
+ s.z = 0;
+ }
+ return s.z;
+}
+
+/*
+** SQL function: shell_module_schema(X)
+**
+** Return a fake schema for the table-valued function or eponymous virtual
+** table X.
+*/
+static void shellModuleSchema(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ const char *zName = (const char*)sqlite3_value_text(apVal[0]);
+ char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName);
+ UNUSED_PARAMETER(nVal);
+ if( zFake ){
+ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake),
+ -1, sqlite3_free);
+ free(zFake);
+ }
+}
+
+/*
+** SQL function: shell_add_schema(S,X)
+**
+** Add the schema name X to the CREATE statement in S and return the result.
+** Examples:
+**
+** CREATE TABLE t1(x) -> CREATE TABLE xyz.t1(x);
+**
+** Also works on
+**
+** CREATE INDEX
+** CREATE UNIQUE INDEX
+** CREATE VIEW
+** CREATE TRIGGER
+** CREATE VIRTUAL TABLE
+**
+** This UDF is used by the .schema command to insert the schema name of
+** attached databases into the middle of the sqlite_schema.sql field.
+*/
+static void shellAddSchemaName(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ static const char *aPrefix[] = {
+ "TABLE",
+ "INDEX",
+ "UNIQUE INDEX",
+ "VIEW",
+ "TRIGGER",
+ "VIRTUAL TABLE"
+ };
+ int i = 0;
+ const char *zIn = (const char*)sqlite3_value_text(apVal[0]);
+ const char *zSchema = (const char*)sqlite3_value_text(apVal[1]);
+ const char *zName = (const char*)sqlite3_value_text(apVal[2]);
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+ UNUSED_PARAMETER(nVal);
+ if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){
+ for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){
+ int n = strlen30(aPrefix[i]);
+ if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){
+ char *z = 0;
+ char *zFake = 0;
+ if( zSchema ){
+ char cQuote = quoteChar(zSchema);
+ if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){
+ z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8);
+ }else{
+ z = sqlite3_mprintf("%.*s %s.%s", n+7, zIn, zSchema, zIn+n+8);
+ }
+ }
+ if( zName
+ && aPrefix[i][0]=='V'
+ && (zFake = shellFakeSchema(db, zSchema, zName))!=0
+ ){
+ if( z==0 ){
+ z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake);
+ }else{
+ z = sqlite3_mprintf("%z\n/* %s */", z, zFake);
+ }
+ free(zFake);
+ }
+ if( z ){
+ sqlite3_result_text(pCtx, z, -1, sqlite3_free);
+ return;
+ }
+ }
+ }
+ }
+ sqlite3_result_value(pCtx, apVal[0]);
+}
+
+/*
+** The source code for several run-time loadable extensions is inserted
+** below by the ../tool/mkshellc.tcl script. Before processing that included
+** code, we need to override some macros to make the included program code
+** work here in the middle of this regular program.
+*/
+#define SQLITE_EXTENSION_INIT1
+#define SQLITE_EXTENSION_INIT2(X) (void)(X)
+
+#if defined(_WIN32) && defined(_MSC_VER)
+/************************* Begin test_windirent.h ******************/
+/*
+** 2015 November 30
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains declarations for most of the opendir() family of
+** POSIX functions on Win32 using the MSVCRT.
+*/
+
+#if defined(_WIN32) && defined(_MSC_VER) && !defined(SQLITE_WINDIRENT_H)
+#define SQLITE_WINDIRENT_H
+
+/*
+** We need several data types from the Windows SDK header.
+*/
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include "windows.h"
+
+/*
+** We need several support functions from the SQLite core.
+*/
+
+/* #include "sqlite3.h" */
+
+/*
+** We need several things from the ANSI and MSVCRT headers.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*
+** We may need several defines that should have been in "sys/stat.h".
+*/
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISLNK
+#define S_ISLNK(mode) (0)
+#endif
+
+/*
+** We may need to provide the "mode_t" type.
+*/
+
+#ifndef MODE_T_DEFINED
+ #define MODE_T_DEFINED
+ typedef unsigned short mode_t;
+#endif
+
+/*
+** We may need to provide the "ino_t" type.
+*/
+
+#ifndef INO_T_DEFINED
+ #define INO_T_DEFINED
+ typedef unsigned short ino_t;
+#endif
+
+/*
+** We need to define "NAME_MAX" if it was not present in "limits.h".
+*/
+
+#ifndef NAME_MAX
+# ifdef FILENAME_MAX
+# define NAME_MAX (FILENAME_MAX)
+# else
+# define NAME_MAX (260)
+# endif
+#endif
+
+/*
+** We need to define "NULL_INTPTR_T" and "BAD_INTPTR_T".
+*/
+
+#ifndef NULL_INTPTR_T
+# define NULL_INTPTR_T ((intptr_t)(0))
+#endif
+
+#ifndef BAD_INTPTR_T
+# define BAD_INTPTR_T ((intptr_t)(-1))
+#endif
+
+/*
+** We need to provide the necessary structures and related types.
+*/
+
+#ifndef DIRENT_DEFINED
+#define DIRENT_DEFINED
+typedef struct DIRENT DIRENT;
+typedef DIRENT *LPDIRENT;
+struct DIRENT {
+ ino_t d_ino; /* Sequence number, do not use. */
+ unsigned d_attributes; /* Win32 file attributes. */
+ char d_name[NAME_MAX + 1]; /* Name within the directory. */
+};
+#endif
+
+#ifndef DIR_DEFINED
+#define DIR_DEFINED
+typedef struct DIR DIR;
+typedef DIR *LPDIR;
+struct DIR {
+ intptr_t d_handle; /* Value returned by "_findfirst". */
+ DIRENT d_first; /* DIRENT constructed based on "_findfirst". */
+ DIRENT d_next; /* DIRENT constructed based on "_findnext". */
+};
+#endif
+
+/*
+** Provide a macro, for use by the implementation, to determine if a
+** particular directory entry should be skipped over when searching for
+** the next directory entry that should be returned by the readdir() or
+** readdir_r() functions.
+*/
+
+#ifndef is_filtered
+# define is_filtered(a) ((((a).attrib)&_A_HIDDEN) || (((a).attrib)&_A_SYSTEM))
+#endif
+
+/*
+** Provide the function prototype for the POSIX compatiable getenv()
+** function. This function is not thread-safe.
+*/
+
+extern const char *windirent_getenv(const char *name);
+
+/*
+** Finally, we can provide the function prototypes for the opendir(),
+** readdir(), readdir_r(), and closedir() POSIX functions.
+*/
+
+extern LPDIR opendir(const char *dirname);
+extern LPDIRENT readdir(LPDIR dirp);
+extern INT readdir_r(LPDIR dirp, LPDIRENT entry, LPDIRENT *result);
+extern INT closedir(LPDIR dirp);
+
+#endif /* defined(WIN32) && defined(_MSC_VER) */
+
+/************************* End test_windirent.h ********************/
+/************************* Begin test_windirent.c ******************/
+/*
+** 2015 November 30
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains code to implement most of the opendir() family of
+** POSIX functions on Win32 using the MSVCRT.
+*/
+
+#if defined(_WIN32) && defined(_MSC_VER)
+/* #include "test_windirent.h" */
+
+/*
+** Implementation of the POSIX getenv() function using the Win32 API.
+** This function is not thread-safe.
+*/
+const char *windirent_getenv(
+ const char *name
+){
+ static char value[32768]; /* Maximum length, per MSDN */
+ DWORD dwSize = sizeof(value) / sizeof(char); /* Size in chars */
+ DWORD dwRet; /* Value returned by GetEnvironmentVariableA() */
+
+ memset(value, 0, sizeof(value));
+ dwRet = GetEnvironmentVariableA(name, value, dwSize);
+ if( dwRet==0 || dwRet>dwSize ){
+ /*
+ ** The function call to GetEnvironmentVariableA() failed -OR-
+ ** the buffer is not large enough. Either way, return NULL.
+ */
+ return 0;
+ }else{
+ /*
+ ** The function call to GetEnvironmentVariableA() succeeded
+ ** -AND- the buffer contains the entire value.
+ */
+ return value;
+ }
+}
+
+/*
+** Implementation of the POSIX opendir() function using the MSVCRT.
+*/
+LPDIR opendir(
+ const char *dirname
+){
+ struct _finddata_t data;
+ LPDIR dirp = (LPDIR)sqlite3_malloc(sizeof(DIR));
+ SIZE_T namesize = sizeof(data.name) / sizeof(data.name[0]);
+
+ if( dirp==NULL ) return NULL;
+ memset(dirp, 0, sizeof(DIR));
+
+ /* TODO: Remove this if Unix-style root paths are not used. */
+ if( sqlite3_stricmp(dirname, "/")==0 ){
+ dirname = windirent_getenv("SystemDrive");
+ }
+
+ memset(&data, 0, sizeof(struct _finddata_t));
+ _snprintf(data.name, namesize, "%s\\*", dirname);
+ dirp->d_handle = _findfirst(data.name, &data);
+
+ if( dirp->d_handle==BAD_INTPTR_T ){
+ closedir(dirp);
+ return NULL;
+ }
+
+ /* TODO: Remove this block to allow hidden and/or system files. */
+ if( is_filtered(data) ){
+next:
+
+ memset(&data, 0, sizeof(struct _finddata_t));
+ if( _findnext(dirp->d_handle, &data)==-1 ){
+ closedir(dirp);
+ return NULL;
+ }
+
+ /* TODO: Remove this block to allow hidden and/or system files. */
+ if( is_filtered(data) ) goto next;
+ }
+
+ dirp->d_first.d_attributes = data.attrib;
+ strncpy(dirp->d_first.d_name, data.name, NAME_MAX);
+ dirp->d_first.d_name[NAME_MAX] = '\0';
+
+ return dirp;
+}
+
+/*
+** Implementation of the POSIX readdir() function using the MSVCRT.
+*/
+LPDIRENT readdir(
+ LPDIR dirp
+){
+ struct _finddata_t data;
+
+ if( dirp==NULL ) return NULL;
+
+ if( dirp->d_first.d_ino==0 ){
+ dirp->d_first.d_ino++;
+ dirp->d_next.d_ino++;
+
+ return &dirp->d_first;
+ }
+
+next:
+
+ memset(&data, 0, sizeof(struct _finddata_t));
+ if( _findnext(dirp->d_handle, &data)==-1 ) return NULL;
+
+ /* TODO: Remove this block to allow hidden and/or system files. */
+ if( is_filtered(data) ) goto next;
+
+ dirp->d_next.d_ino++;
+ dirp->d_next.d_attributes = data.attrib;
+ strncpy(dirp->d_next.d_name, data.name, NAME_MAX);
+ dirp->d_next.d_name[NAME_MAX] = '\0';
+
+ return &dirp->d_next;
+}
+
+/*
+** Implementation of the POSIX readdir_r() function using the MSVCRT.
+*/
+INT readdir_r(
+ LPDIR dirp,
+ LPDIRENT entry,
+ LPDIRENT *result
+){
+ struct _finddata_t data;
+
+ if( dirp==NULL ) return EBADF;
+
+ if( dirp->d_first.d_ino==0 ){
+ dirp->d_first.d_ino++;
+ dirp->d_next.d_ino++;
+
+ entry->d_ino = dirp->d_first.d_ino;
+ entry->d_attributes = dirp->d_first.d_attributes;
+ strncpy(entry->d_name, dirp->d_first.d_name, NAME_MAX);
+ entry->d_name[NAME_MAX] = '\0';
+
+ *result = entry;
+ return 0;
+ }
+
+next:
+
+ memset(&data, 0, sizeof(struct _finddata_t));
+ if( _findnext(dirp->d_handle, &data)==-1 ){
+ *result = NULL;
+ return ENOENT;
+ }
+
+ /* TODO: Remove this block to allow hidden and/or system files. */
+ if( is_filtered(data) ) goto next;
+
+ entry->d_ino = (ino_t)-1; /* not available */
+ entry->d_attributes = data.attrib;
+ strncpy(entry->d_name, data.name, NAME_MAX);
+ entry->d_name[NAME_MAX] = '\0';
+
+ *result = entry;
+ return 0;
+}
+
+/*
+** Implementation of the POSIX closedir() function using the MSVCRT.
+*/
+INT closedir(
+ LPDIR dirp
+){
+ INT result = 0;
+
+ if( dirp==NULL ) return EINVAL;
+
+ if( dirp->d_handle!=NULL_INTPTR_T && dirp->d_handle!=BAD_INTPTR_T ){
+ result = _findclose(dirp->d_handle);
+ }
+
+ sqlite3_free(dirp);
+ return result;
+}
+
+#endif /* defined(WIN32) && defined(_MSC_VER) */
+
+/************************* End test_windirent.c ********************/
+#define dirent DIRENT
+#endif
+/************************* Begin ../ext/misc/shathree.c ******************/
+/*
+** 2017-03-08
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements functions that compute SHA3 hashes.
+** Two SQL functions are implemented:
+**
+** sha3(X,SIZE)
+** sha3_query(Y,SIZE)
+**
+** The sha3(X) function computes the SHA3 hash of the input X, or NULL if
+** X is NULL.
+**
+** The sha3_query(Y) function evalutes all queries in the SQL statements of Y
+** and returns a hash of their results.
+**
+** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm
+** is used. If SIZE is included it must be one of the integers 224, 256,
+** 384, or 512, to determine SHA3 hash variant that is computed.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <stdarg.h>
+/* typedef sqlite3_uint64 u64; */
+
+/******************************************************************************
+** The Hash Engine
+*/
+/*
+** Macros to determine whether the machine is big or little endian,
+** and whether or not that determination is run-time or compile-time.
+**
+** For best performance, an attempt is made to guess at the byte-order
+** using C-preprocessor macros. If that is unsuccessful, or if
+** -DSHA3_BYTEORDER=0 is set, then byte-order is determined
+** at run-time.
+*/
+#ifndef SHA3_BYTEORDER
+# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__arm__)
+# define SHA3_BYTEORDER 1234
+# elif defined(sparc) || defined(__ppc__)
+# define SHA3_BYTEORDER 4321
+# else
+# define SHA3_BYTEORDER 0
+# endif
+#endif
+
+
+/*
+** State structure for a SHA3 hash in progress
+*/
+typedef struct SHA3Context SHA3Context;
+struct SHA3Context {
+ union {
+ u64 s[25]; /* Keccak state. 5x5 lines of 64 bits each */
+ unsigned char x[1600]; /* ... or 1600 bytes */
+ } u;
+ unsigned nRate; /* Bytes of input accepted per Keccak iteration */
+ unsigned nLoaded; /* Input bytes loaded into u.x[] so far this cycle */
+ unsigned ixMask; /* Insert next input into u.x[nLoaded^ixMask]. */
+};
+
+/*
+** A single step of the Keccak mixing function for a 1600-bit state
+*/
+static void KeccakF1600Step(SHA3Context *p){
+ int i;
+ u64 b0, b1, b2, b3, b4;
+ u64 c0, c1, c2, c3, c4;
+ u64 d0, d1, d2, d3, d4;
+ static const u64 RC[] = {
+ 0x0000000000000001ULL, 0x0000000000008082ULL,
+ 0x800000000000808aULL, 0x8000000080008000ULL,
+ 0x000000000000808bULL, 0x0000000080000001ULL,
+ 0x8000000080008081ULL, 0x8000000000008009ULL,
+ 0x000000000000008aULL, 0x0000000000000088ULL,
+ 0x0000000080008009ULL, 0x000000008000000aULL,
+ 0x000000008000808bULL, 0x800000000000008bULL,
+ 0x8000000000008089ULL, 0x8000000000008003ULL,
+ 0x8000000000008002ULL, 0x8000000000000080ULL,
+ 0x000000000000800aULL, 0x800000008000000aULL,
+ 0x8000000080008081ULL, 0x8000000000008080ULL,
+ 0x0000000080000001ULL, 0x8000000080008008ULL
+ };
+# define a00 (p->u.s[0])
+# define a01 (p->u.s[1])
+# define a02 (p->u.s[2])
+# define a03 (p->u.s[3])
+# define a04 (p->u.s[4])
+# define a10 (p->u.s[5])
+# define a11 (p->u.s[6])
+# define a12 (p->u.s[7])
+# define a13 (p->u.s[8])
+# define a14 (p->u.s[9])
+# define a20 (p->u.s[10])
+# define a21 (p->u.s[11])
+# define a22 (p->u.s[12])
+# define a23 (p->u.s[13])
+# define a24 (p->u.s[14])
+# define a30 (p->u.s[15])
+# define a31 (p->u.s[16])
+# define a32 (p->u.s[17])
+# define a33 (p->u.s[18])
+# define a34 (p->u.s[19])
+# define a40 (p->u.s[20])
+# define a41 (p->u.s[21])
+# define a42 (p->u.s[22])
+# define a43 (p->u.s[23])
+# define a44 (p->u.s[24])
+# define ROL64(a,x) ((a<<x)|(a>>(64-x)))
+
+ for(i=0; i<24; i+=4){
+ c0 = a00^a10^a20^a30^a40;
+ c1 = a01^a11^a21^a31^a41;
+ c2 = a02^a12^a22^a32^a42;
+ c3 = a03^a13^a23^a33^a43;
+ c4 = a04^a14^a24^a34^a44;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a11^d1), 44);
+ b2 = ROL64((a22^d2), 43);
+ b3 = ROL64((a33^d3), 21);
+ b4 = ROL64((a44^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i];
+ a11 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a20^d0), 3);
+ b3 = ROL64((a31^d1), 45);
+ b4 = ROL64((a42^d2), 61);
+ b0 = ROL64((a03^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a20 = b0 ^((~b1)& b2 );
+ a31 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a40^d0), 18);
+ b0 = ROL64((a01^d1), 1);
+ b1 = ROL64((a12^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a34^d4), 8);
+ a40 = b0 ^((~b1)& b2 );
+ a01 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a10^d0), 36);
+ b2 = ROL64((a21^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a43^d3), 56);
+ b0 = ROL64((a04^d4), 27);
+ a10 = b0 ^((~b1)& b2 );
+ a21 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a30^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a02^d2), 62);
+ b1 = ROL64((a13^d3), 55);
+ b2 = ROL64((a24^d4), 39);
+ a30 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ c0 = a00^a20^a40^a10^a30;
+ c1 = a11^a31^a01^a21^a41;
+ c2 = a22^a42^a12^a32^a02;
+ c3 = a33^a03^a23^a43^a13;
+ c4 = a44^a14^a34^a04^a24;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a31^d1), 44);
+ b2 = ROL64((a12^d2), 43);
+ b3 = ROL64((a43^d3), 21);
+ b4 = ROL64((a24^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i+1];
+ a31 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a40^d0), 3);
+ b3 = ROL64((a21^d1), 45);
+ b4 = ROL64((a02^d2), 61);
+ b0 = ROL64((a33^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a40 = b0 ^((~b1)& b2 );
+ a21 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a30^d0), 18);
+ b0 = ROL64((a11^d1), 1);
+ b1 = ROL64((a42^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a04^d4), 8);
+ a30 = b0 ^((~b1)& b2 );
+ a11 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a20^d0), 36);
+ b2 = ROL64((a01^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a13^d3), 56);
+ b0 = ROL64((a44^d4), 27);
+ a20 = b0 ^((~b1)& b2 );
+ a01 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a10^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a22^d2), 62);
+ b1 = ROL64((a03^d3), 55);
+ b2 = ROL64((a34^d4), 39);
+ a10 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ c0 = a00^a40^a30^a20^a10;
+ c1 = a31^a21^a11^a01^a41;
+ c2 = a12^a02^a42^a32^a22;
+ c3 = a43^a33^a23^a13^a03;
+ c4 = a24^a14^a04^a44^a34;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a21^d1), 44);
+ b2 = ROL64((a42^d2), 43);
+ b3 = ROL64((a13^d3), 21);
+ b4 = ROL64((a34^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i+2];
+ a21 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a30^d0), 3);
+ b3 = ROL64((a01^d1), 45);
+ b4 = ROL64((a22^d2), 61);
+ b0 = ROL64((a43^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a30 = b0 ^((~b1)& b2 );
+ a01 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a10^d0), 18);
+ b0 = ROL64((a31^d1), 1);
+ b1 = ROL64((a02^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a44^d4), 8);
+ a10 = b0 ^((~b1)& b2 );
+ a31 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a40^d0), 36);
+ b2 = ROL64((a11^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a03^d3), 56);
+ b0 = ROL64((a24^d4), 27);
+ a40 = b0 ^((~b1)& b2 );
+ a11 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a20^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a12^d2), 62);
+ b1 = ROL64((a33^d3), 55);
+ b2 = ROL64((a04^d4), 39);
+ a20 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ c0 = a00^a30^a10^a40^a20;
+ c1 = a21^a01^a31^a11^a41;
+ c2 = a42^a22^a02^a32^a12;
+ c3 = a13^a43^a23^a03^a33;
+ c4 = a34^a14^a44^a24^a04;
+ d0 = c4^ROL64(c1, 1);
+ d1 = c0^ROL64(c2, 1);
+ d2 = c1^ROL64(c3, 1);
+ d3 = c2^ROL64(c4, 1);
+ d4 = c3^ROL64(c0, 1);
+
+ b0 = (a00^d0);
+ b1 = ROL64((a01^d1), 44);
+ b2 = ROL64((a02^d2), 43);
+ b3 = ROL64((a03^d3), 21);
+ b4 = ROL64((a04^d4), 14);
+ a00 = b0 ^((~b1)& b2 );
+ a00 ^= RC[i+3];
+ a01 = b1 ^((~b2)& b3 );
+ a02 = b2 ^((~b3)& b4 );
+ a03 = b3 ^((~b4)& b0 );
+ a04 = b4 ^((~b0)& b1 );
+
+ b2 = ROL64((a10^d0), 3);
+ b3 = ROL64((a11^d1), 45);
+ b4 = ROL64((a12^d2), 61);
+ b0 = ROL64((a13^d3), 28);
+ b1 = ROL64((a14^d4), 20);
+ a10 = b0 ^((~b1)& b2 );
+ a11 = b1 ^((~b2)& b3 );
+ a12 = b2 ^((~b3)& b4 );
+ a13 = b3 ^((~b4)& b0 );
+ a14 = b4 ^((~b0)& b1 );
+
+ b4 = ROL64((a20^d0), 18);
+ b0 = ROL64((a21^d1), 1);
+ b1 = ROL64((a22^d2), 6);
+ b2 = ROL64((a23^d3), 25);
+ b3 = ROL64((a24^d4), 8);
+ a20 = b0 ^((~b1)& b2 );
+ a21 = b1 ^((~b2)& b3 );
+ a22 = b2 ^((~b3)& b4 );
+ a23 = b3 ^((~b4)& b0 );
+ a24 = b4 ^((~b0)& b1 );
+
+ b1 = ROL64((a30^d0), 36);
+ b2 = ROL64((a31^d1), 10);
+ b3 = ROL64((a32^d2), 15);
+ b4 = ROL64((a33^d3), 56);
+ b0 = ROL64((a34^d4), 27);
+ a30 = b0 ^((~b1)& b2 );
+ a31 = b1 ^((~b2)& b3 );
+ a32 = b2 ^((~b3)& b4 );
+ a33 = b3 ^((~b4)& b0 );
+ a34 = b4 ^((~b0)& b1 );
+
+ b3 = ROL64((a40^d0), 41);
+ b4 = ROL64((a41^d1), 2);
+ b0 = ROL64((a42^d2), 62);
+ b1 = ROL64((a43^d3), 55);
+ b2 = ROL64((a44^d4), 39);
+ a40 = b0 ^((~b1)& b2 );
+ a41 = b1 ^((~b2)& b3 );
+ a42 = b2 ^((~b3)& b4 );
+ a43 = b3 ^((~b4)& b0 );
+ a44 = b4 ^((~b0)& b1 );
+ }
+}
+
+/*
+** Initialize a new hash. iSize determines the size of the hash
+** in bits and should be one of 224, 256, 384, or 512. Or iSize
+** can be zero to use the default hash size of 256 bits.
+*/
+static void SHA3Init(SHA3Context *p, int iSize){
+ memset(p, 0, sizeof(*p));
+ if( iSize>=128 && iSize<=512 ){
+ p->nRate = (1600 - ((iSize + 31)&~31)*2)/8;
+ }else{
+ p->nRate = (1600 - 2*256)/8;
+ }
+#if SHA3_BYTEORDER==1234
+ /* Known to be little-endian at compile-time. No-op */
+#elif SHA3_BYTEORDER==4321
+ p->ixMask = 7; /* Big-endian */
+#else
+ {
+ static unsigned int one = 1;
+ if( 1==*(unsigned char*)&one ){
+ /* Little endian. No byte swapping. */
+ p->ixMask = 0;
+ }else{
+ /* Big endian. Byte swap. */
+ p->ixMask = 7;
+ }
+ }
+#endif
+}
+
+/*
+** Make consecutive calls to the SHA3Update function to add new content
+** to the hash
+*/
+static void SHA3Update(
+ SHA3Context *p,
+ const unsigned char *aData,
+ unsigned int nData
+){
+ unsigned int i = 0;
+#if SHA3_BYTEORDER==1234
+ if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){
+ for(; i+7<nData; i+=8){
+ p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i];
+ p->nLoaded += 8;
+ if( p->nLoaded>=p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+ }
+#endif
+ for(; i<nData; i++){
+#if SHA3_BYTEORDER==1234
+ p->u.x[p->nLoaded] ^= aData[i];
+#elif SHA3_BYTEORDER==4321
+ p->u.x[p->nLoaded^0x07] ^= aData[i];
+#else
+ p->u.x[p->nLoaded^p->ixMask] ^= aData[i];
+#endif
+ p->nLoaded++;
+ if( p->nLoaded==p->nRate ){
+ KeccakF1600Step(p);
+ p->nLoaded = 0;
+ }
+ }
+}
+
+/*
+** After all content has been added, invoke SHA3Final() to compute
+** the final hash. The function returns a pointer to the binary
+** hash value.
+*/
+static unsigned char *SHA3Final(SHA3Context *p){
+ unsigned int i;
+ if( p->nLoaded==p->nRate-1 ){
+ const unsigned char c1 = 0x86;
+ SHA3Update(p, &c1, 1);
+ }else{
+ const unsigned char c2 = 0x06;
+ const unsigned char c3 = 0x80;
+ SHA3Update(p, &c2, 1);
+ p->nLoaded = p->nRate - 1;
+ SHA3Update(p, &c3, 1);
+ }
+ for(i=0; i<p->nRate; i++){
+ p->u.x[i+p->nRate] = p->u.x[i^p->ixMask];
+ }
+ return &p->u.x[p->nRate];
+}
+/* End of the hashing logic
+*****************************************************************************/
+
+/*
+** Implementation of the sha3(X,SIZE) function.
+**
+** Return a BLOB which is the SIZE-bit SHA3 hash of X. The default
+** size is 256. If X is a BLOB, it is hashed as is.
+** For all other non-NULL types of input, X is converted into a UTF-8 string
+** and the string is hashed without the trailing 0x00 terminator. The hash
+** of a NULL value is NULL.
+*/
+static void sha3Func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ SHA3Context cx;
+ int eType = sqlite3_value_type(argv[0]);
+ int nByte = sqlite3_value_bytes(argv[0]);
+ int iSize;
+ if( argc==1 ){
+ iSize = 256;
+ }else{
+ iSize = sqlite3_value_int(argv[1]);
+ if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
+ sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
+ "384 512", -1);
+ return;
+ }
+ }
+ if( eType==SQLITE_NULL ) return;
+ SHA3Init(&cx, iSize);
+ if( eType==SQLITE_BLOB ){
+ SHA3Update(&cx, sqlite3_value_blob(argv[0]), nByte);
+ }else{
+ SHA3Update(&cx, sqlite3_value_text(argv[0]), nByte);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+/* Compute a string using sqlite3_vsnprintf() with a maximum length
+** of 50 bytes and add it to the hash.
+*/
+static void hash_step_vformat(
+ SHA3Context *p, /* Add content to this context */
+ const char *zFormat,
+ ...
+){
+ va_list ap;
+ int n;
+ char zBuf[50];
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(sizeof(zBuf),zBuf,zFormat,ap);
+ va_end(ap);
+ n = (int)strlen(zBuf);
+ SHA3Update(p, (unsigned char*)zBuf, n);
+}
+
+/*
+** Implementation of the sha3_query(SQL,SIZE) function.
+**
+** This function compiles and runs the SQL statement(s) given in the
+** argument. The results are hashed using a SIZE-bit SHA3. The default
+** size is 256.
+**
+** The format of the byte stream that is hashed is summarized as follows:
+**
+** S<n>:<sql>
+** R
+** N
+** I<int>
+** F<ieee-float>
+** B<size>:<bytes>
+** T<size>:<text>
+**
+** <sql> is the original SQL text for each statement run and <n> is
+** the size of that text. The SQL text is UTF-8. A single R character
+** occurs before the start of each row. N means a NULL value.
+** I mean an 8-byte little-endian integer <int>. F is a floating point
+** number with an 8-byte little-endian IEEE floating point value <ieee-float>.
+** B means blobs of <size> bytes. T means text rendered as <size>
+** bytes of UTF-8. The <n> and <size> values are expressed as an ASCII
+** text integers.
+**
+** For each SQL statement in the X input, there is one S segment. Each
+** S segment is followed by zero or more R segments, one for each row in the
+** result set. After each R, there are one or more N, I, F, B, or T segments,
+** one for each column in the result set. Segments are concatentated directly
+** with no delimiters of any kind.
+*/
+static void sha3QueryFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ sqlite3_stmt *pStmt = 0;
+ int nCol; /* Number of columns in the result set */
+ int i; /* Loop counter */
+ int rc;
+ int n;
+ const char *z;
+ SHA3Context cx;
+ int iSize;
+
+ if( argc==1 ){
+ iSize = 256;
+ }else{
+ iSize = sqlite3_value_int(argv[1]);
+ if( iSize!=224 && iSize!=256 && iSize!=384 && iSize!=512 ){
+ sqlite3_result_error(context, "SHA3 size should be one of: 224 256 "
+ "384 512", -1);
+ return;
+ }
+ }
+ if( zSql==0 ) return;
+ SHA3Init(&cx, iSize);
+ while( zSql[0] ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
+ if( rc ){
+ char *zMsg = sqlite3_mprintf("error SQL statement [%s]: %s",
+ zSql, sqlite3_errmsg(db));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ if( !sqlite3_stmt_readonly(pStmt) ){
+ char *zMsg = sqlite3_mprintf("non-query: [%s]", sqlite3_sql(pStmt));
+ sqlite3_finalize(pStmt);
+ sqlite3_result_error(context, zMsg, -1);
+ sqlite3_free(zMsg);
+ return;
+ }
+ nCol = sqlite3_column_count(pStmt);
+ z = sqlite3_sql(pStmt);
+ n = (int)strlen(z);
+ hash_step_vformat(&cx,"S%d:",n);
+ SHA3Update(&cx,(unsigned char*)z,n);
+
+ /* Compute a hash over the result of the query */
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ SHA3Update(&cx,(const unsigned char*)"R",1);
+ for(i=0; i<nCol; i++){
+ switch( sqlite3_column_type(pStmt,i) ){
+ case SQLITE_NULL: {
+ SHA3Update(&cx, (const unsigned char*)"N",1);
+ break;
+ }
+ case SQLITE_INTEGER: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ sqlite3_int64 v = sqlite3_column_int64(pStmt,i);
+ memcpy(&u, &v, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'I';
+ SHA3Update(&cx, x, 9);
+ break;
+ }
+ case SQLITE_FLOAT: {
+ sqlite3_uint64 u;
+ int j;
+ unsigned char x[9];
+ double r = sqlite3_column_double(pStmt,i);
+ memcpy(&u, &r, 8);
+ for(j=8; j>=1; j--){
+ x[j] = u & 0xff;
+ u >>= 8;
+ }
+ x[0] = 'F';
+ SHA3Update(&cx,x,9);
+ break;
+ }
+ case SQLITE_TEXT: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_text(pStmt, i);
+ hash_step_vformat(&cx,"T%d:",n2);
+ SHA3Update(&cx, z2, n2);
+ break;
+ }
+ case SQLITE_BLOB: {
+ int n2 = sqlite3_column_bytes(pStmt, i);
+ const unsigned char *z2 = sqlite3_column_blob(pStmt, i);
+ hash_step_vformat(&cx,"B%d:",n2);
+ SHA3Update(&cx, z2, n2);
+ break;
+ }
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ }
+ sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT);
+}
+
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_shathree_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "sha3", 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, sha3Func, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3", 2,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC,
+ 0, sha3Func, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_query", 1,
+ SQLITE_UTF8 | SQLITE_DIRECTONLY,
+ 0, sha3QueryFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sha3_query", 2,
+ SQLITE_UTF8 | SQLITE_DIRECTONLY,
+ 0, sha3QueryFunc, 0, 0);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/shathree.c ********************/
+/************************* Begin ../ext/misc/fileio.c ******************/
+/*
+** 2014-06-13
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements SQL functions readfile() and
+** writefile(), and eponymous virtual type "fsdir".
+**
+** WRITEFILE(FILE, DATA [, MODE [, MTIME]]):
+**
+** If neither of the optional arguments is present, then this UDF
+** function writes blob DATA to file FILE. If successful, the number
+** of bytes written is returned. If an error occurs, NULL is returned.
+**
+** If the first option argument - MODE - is present, then it must
+** be passed an integer value that corresponds to a POSIX mode
+** value (file type + permissions, as returned in the stat.st_mode
+** field by the stat() system call). Three types of files may
+** be written/created:
+**
+** regular files: (mode & 0170000)==0100000
+** symbolic links: (mode & 0170000)==0120000
+** directories: (mode & 0170000)==0040000
+**
+** For a directory, the DATA is ignored. For a symbolic link, it is
+** interpreted as text and used as the target of the link. For a
+** regular file, it is interpreted as a blob and written into the
+** named file. Regardless of the type of file, its permissions are
+** set to (mode & 0777) before returning.
+**
+** If the optional MTIME argument is present, then it is interpreted
+** as an integer - the number of seconds since the unix epoch. The
+** modification-time of the target file is set to this value before
+** returning.
+**
+** If three or more arguments are passed to this function and an
+** error is encountered, an exception is raised.
+**
+** READFILE(FILE):
+**
+** Read and return the contents of file FILE (type blob) from disk.
+**
+** FSDIR:
+**
+** Used as follows:
+**
+** SELECT * FROM fsdir($path [, $dir]);
+**
+** Parameter $path is an absolute or relative pathname. If the file that it
+** refers to does not exist, it is an error. If the path refers to a regular
+** file or symbolic link, it returns a single row. Or, if the path refers
+** to a directory, it returns one row for the directory, and one row for each
+** file within the hierarchy rooted at $path.
+**
+** Each row has the following columns:
+**
+** name: Path to file or directory (text value).
+** mode: Value of stat.st_mode for directory entry (an integer).
+** mtime: Value of stat.st_mtime for directory entry (an integer).
+** data: For a regular file, a blob containing the file data. For a
+** symlink, a text value containing the text of the link. For a
+** directory, NULL.
+**
+** If a non-NULL value is specified for the optional $dir parameter and
+** $path is a relative path, then $path is interpreted relative to $dir.
+** And the paths returned in the "name" column of the table are also
+** relative to directory $dir.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#if !defined(_WIN32) && !defined(WIN32)
+# include <unistd.h>
+# include <dirent.h>
+# include <utime.h>
+# include <sys/time.h>
+#else
+# include "windows.h"
+# include <io.h>
+# include <direct.h>
+/* # include "test_windirent.h" */
+# define dirent DIRENT
+# ifndef chmod
+# define chmod _chmod
+# endif
+# ifndef stat
+# define stat _stat
+# endif
+# define mkdir(path,mode) _mkdir(path)
+# define lstat(path,buf) stat(path,buf)
+#endif
+#include <time.h>
+#include <errno.h>
+
+
+/*
+** Structure of the fsdir() table-valued function
+*/
+ /* 0 1 2 3 4 5 */
+#define FSDIR_SCHEMA "(name,mode,mtime,data,path HIDDEN,dir HIDDEN)"
+#define FSDIR_COLUMN_NAME 0 /* Name of the file */
+#define FSDIR_COLUMN_MODE 1 /* Access mode */
+#define FSDIR_COLUMN_MTIME 2 /* Last modification time */
+#define FSDIR_COLUMN_DATA 3 /* File content */
+#define FSDIR_COLUMN_PATH 4 /* Path to top of search */
+#define FSDIR_COLUMN_DIR 5 /* Path is relative to this directory */
+
+
+/*
+** Set the result stored by context ctx to a blob containing the
+** contents of file zName. Or, leave the result unchanged (NULL)
+** if the file does not exist or is unreadable.
+**
+** If the file exceeds the SQLite blob size limit, through an
+** SQLITE_TOOBIG error.
+**
+** Throw an SQLITE_IOERR if there are difficulties pulling the file
+** off of disk.
+*/
+static void readFileContents(sqlite3_context *ctx, const char *zName){
+ FILE *in;
+ sqlite3_int64 nIn;
+ void *pBuf;
+ sqlite3 *db;
+ int mxBlob;
+
+ in = fopen(zName, "rb");
+ if( in==0 ){
+ /* File does not exist or is unreadable. Leave the result set to NULL. */
+ return;
+ }
+ fseek(in, 0, SEEK_END);
+ nIn = ftell(in);
+ rewind(in);
+ db = sqlite3_context_db_handle(ctx);
+ mxBlob = sqlite3_limit(db, SQLITE_LIMIT_LENGTH, -1);
+ if( nIn>mxBlob ){
+ sqlite3_result_error_code(ctx, SQLITE_TOOBIG);
+ fclose(in);
+ return;
+ }
+ pBuf = sqlite3_malloc64( nIn ? nIn : 1 );
+ if( pBuf==0 ){
+ sqlite3_result_error_nomem(ctx);
+ fclose(in);
+ return;
+ }
+ if( nIn==(sqlite3_int64)fread(pBuf, 1, (size_t)nIn, in) ){
+ sqlite3_result_blob64(ctx, pBuf, nIn, sqlite3_free);
+ }else{
+ sqlite3_result_error_code(ctx, SQLITE_IOERR);
+ sqlite3_free(pBuf);
+ }
+ fclose(in);
+}
+
+/*
+** Implementation of the "readfile(X)" SQL function. The entire content
+** of the file named X is read and returned as a BLOB. NULL is returned
+** if the file does not exist or is unreadable.
+*/
+static void readfileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zName;
+ (void)(argc); /* Unused parameter */
+ zName = (const char*)sqlite3_value_text(argv[0]);
+ if( zName==0 ) return;
+ readFileContents(context, zName);
+}
+
+/*
+** Set the error message contained in context ctx to the results of
+** vprintf(zFmt, ...).
+*/
+static void ctxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
+ char *zMsg = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zMsg = sqlite3_vmprintf(zFmt, ap);
+ sqlite3_result_error(ctx, zMsg, -1);
+ sqlite3_free(zMsg);
+ va_end(ap);
+}
+
+#if defined(_WIN32)
+/*
+** This function is designed to convert a Win32 FILETIME structure into the
+** number of seconds since the Unix Epoch (1970-01-01 00:00:00 UTC).
+*/
+static sqlite3_uint64 fileTimeToUnixTime(
+ LPFILETIME pFileTime
+){
+ SYSTEMTIME epochSystemTime;
+ ULARGE_INTEGER epochIntervals;
+ FILETIME epochFileTime;
+ ULARGE_INTEGER fileIntervals;
+
+ memset(&epochSystemTime, 0, sizeof(SYSTEMTIME));
+ epochSystemTime.wYear = 1970;
+ epochSystemTime.wMonth = 1;
+ epochSystemTime.wDay = 1;
+ SystemTimeToFileTime(&epochSystemTime, &epochFileTime);
+ epochIntervals.LowPart = epochFileTime.dwLowDateTime;
+ epochIntervals.HighPart = epochFileTime.dwHighDateTime;
+
+ fileIntervals.LowPart = pFileTime->dwLowDateTime;
+ fileIntervals.HighPart = pFileTime->dwHighDateTime;
+
+ return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
+}
+
+/*
+** This function attempts to normalize the time values found in the stat()
+** buffer to UTC. This is necessary on Win32, where the runtime library
+** appears to return these values as local times.
+*/
+static void statTimesToUtc(
+ const char *zPath,
+ struct stat *pStatBuf
+){
+ HANDLE hFindFile;
+ WIN32_FIND_DATAW fd;
+ LPWSTR zUnicodeName;
+ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
+ zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
+ if( zUnicodeName ){
+ memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
+ hFindFile = FindFirstFileW(zUnicodeName, &fd);
+ if( hFindFile!=NULL ){
+ pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
+ pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime);
+ pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime);
+ FindClose(hFindFile);
+ }
+ sqlite3_free(zUnicodeName);
+ }
+}
+#endif
+
+/*
+** This function is used in place of stat(). On Windows, special handling
+** is required in order for the included time to be returned as UTC. On all
+** other systems, this function simply calls stat().
+*/
+static int fileStat(
+ const char *zPath,
+ struct stat *pStatBuf
+){
+#if defined(_WIN32)
+ int rc = stat(zPath, pStatBuf);
+ if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
+ return rc;
+#else
+ return stat(zPath, pStatBuf);
+#endif
+}
+
+/*
+** This function is used in place of lstat(). On Windows, special handling
+** is required in order for the included time to be returned as UTC. On all
+** other systems, this function simply calls lstat().
+*/
+static int fileLinkStat(
+ const char *zPath,
+ struct stat *pStatBuf
+){
+#if defined(_WIN32)
+ int rc = lstat(zPath, pStatBuf);
+ if( rc==0 ) statTimesToUtc(zPath, pStatBuf);
+ return rc;
+#else
+ return lstat(zPath, pStatBuf);
+#endif
+}
+
+/*
+** Argument zFile is the name of a file that will be created and/or written
+** by SQL function writefile(). This function ensures that the directory
+** zFile will be written to exists, creating it if required. The permissions
+** for any path components created by this function are set in accordance
+** with the current umask.
+**
+** If an OOM condition is encountered, SQLITE_NOMEM is returned. Otherwise,
+** SQLITE_OK is returned if the directory is successfully created, or
+** SQLITE_ERROR otherwise.
+*/
+static int makeDirectory(
+ const char *zFile
+){
+ char *zCopy = sqlite3_mprintf("%s", zFile);
+ int rc = SQLITE_OK;
+
+ if( zCopy==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int nCopy = (int)strlen(zCopy);
+ int i = 1;
+
+ while( rc==SQLITE_OK ){
+ struct stat sStat;
+ int rc2;
+
+ for(; zCopy[i]!='/' && i<nCopy; i++);
+ if( i==nCopy ) break;
+ zCopy[i] = '\0';
+
+ rc2 = fileStat(zCopy, &sStat);
+ if( rc2!=0 ){
+ if( mkdir(zCopy, 0777) ) rc = SQLITE_ERROR;
+ }else{
+ if( !S_ISDIR(sStat.st_mode) ) rc = SQLITE_ERROR;
+ }
+ zCopy[i] = '/';
+ i++;
+ }
+
+ sqlite3_free(zCopy);
+ }
+
+ return rc;
+}
+
+/*
+** This function does the work for the writefile() UDF. Refer to
+** header comments at the top of this file for details.
+*/
+static int writeFile(
+ sqlite3_context *pCtx, /* Context to return bytes written in */
+ const char *zFile, /* File to write */
+ sqlite3_value *pData, /* Data to write */
+ mode_t mode, /* MODE parameter passed to writefile() */
+ sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */
+){
+#if !defined(_WIN32) && !defined(WIN32)
+ if( S_ISLNK(mode) ){
+ const char *zTo = (const char*)sqlite3_value_text(pData);
+ if( symlink(zTo, zFile)<0 ) return 1;
+ }else
+#endif
+ {
+ if( S_ISDIR(mode) ){
+ if( mkdir(zFile, mode) ){
+ /* The mkdir() call to create the directory failed. This might not
+ ** be an error though - if there is already a directory at the same
+ ** path and either the permissions already match or can be changed
+ ** to do so using chmod(), it is not an error. */
+ struct stat sStat;
+ if( errno!=EEXIST
+ || 0!=fileStat(zFile, &sStat)
+ || !S_ISDIR(sStat.st_mode)
+ || ((sStat.st_mode&0777)!=(mode&0777) && 0!=chmod(zFile, mode&0777))
+ ){
+ return 1;
+ }
+ }
+ }else{
+ sqlite3_int64 nWrite = 0;
+ const char *z;
+ int rc = 0;
+ FILE *out = fopen(zFile, "wb");
+ if( out==0 ) return 1;
+ z = (const char*)sqlite3_value_blob(pData);
+ if( z ){
+ sqlite3_int64 n = fwrite(z, 1, sqlite3_value_bytes(pData), out);
+ nWrite = sqlite3_value_bytes(pData);
+ if( nWrite!=n ){
+ rc = 1;
+ }
+ }
+ fclose(out);
+ if( rc==0 && mode && chmod(zFile, mode & 0777) ){
+ rc = 1;
+ }
+ if( rc ) return 2;
+ sqlite3_result_int64(pCtx, nWrite);
+ }
+ }
+
+ if( mtime>=0 ){
+#if defined(_WIN32)
+#if !SQLITE_OS_WINRT
+ /* Windows */
+ FILETIME lastAccess;
+ FILETIME lastWrite;
+ SYSTEMTIME currentTime;
+ LONGLONG intervals;
+ HANDLE hFile;
+ LPWSTR zUnicodeName;
+ extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
+
+ GetSystemTime(&currentTime);
+ SystemTimeToFileTime(&currentTime, &lastAccess);
+ intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
+ lastWrite.dwLowDateTime = (DWORD)intervals;
+ lastWrite.dwHighDateTime = intervals >> 32;
+ zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
+ if( zUnicodeName==0 ){
+ return 1;
+ }
+ hFile = CreateFileW(
+ zUnicodeName, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL
+ );
+ sqlite3_free(zUnicodeName);
+ if( hFile!=INVALID_HANDLE_VALUE ){
+ BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite);
+ CloseHandle(hFile);
+ return !bResult;
+ }else{
+ return 1;
+ }
+#endif
+#elif defined(AT_FDCWD) && 0 /* utimensat() is not universally available */
+ /* Recent unix */
+ struct timespec times[2];
+ times[0].tv_nsec = times[1].tv_nsec = 0;
+ times[0].tv_sec = time(0);
+ times[1].tv_sec = mtime;
+ if( utimensat(AT_FDCWD, zFile, times, AT_SYMLINK_NOFOLLOW) ){
+ return 1;
+ }
+#else
+ /* Legacy unix */
+ struct timeval times[2];
+ times[0].tv_usec = times[1].tv_usec = 0;
+ times[0].tv_sec = time(0);
+ times[1].tv_sec = mtime;
+ if( utimes(zFile, times) ){
+ return 1;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+/*
+** Implementation of the "writefile(W,X[,Y[,Z]]])" SQL function.
+** Refer to header comments at the top of this file for details.
+*/
+static void writefileFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zFile;
+ mode_t mode = 0;
+ int res;
+ sqlite3_int64 mtime = -1;
+
+ if( argc<2 || argc>4 ){
+ sqlite3_result_error(context,
+ "wrong number of arguments to function writefile()", -1
+ );
+ return;
+ }
+
+ zFile = (const char*)sqlite3_value_text(argv[0]);
+ if( zFile==0 ) return;
+ if( argc>=3 ){
+ mode = (mode_t)sqlite3_value_int(argv[2]);
+ }
+ if( argc==4 ){
+ mtime = sqlite3_value_int64(argv[3]);
+ }
+
+ res = writeFile(context, zFile, argv[1], mode, mtime);
+ if( res==1 && errno==ENOENT ){
+ if( makeDirectory(zFile)==SQLITE_OK ){
+ res = writeFile(context, zFile, argv[1], mode, mtime);
+ }
+ }
+
+ if( argc>2 && res!=0 ){
+ if( S_ISLNK(mode) ){
+ ctxErrorMsg(context, "failed to create symlink: %s", zFile);
+ }else if( S_ISDIR(mode) ){
+ ctxErrorMsg(context, "failed to create directory: %s", zFile);
+ }else{
+ ctxErrorMsg(context, "failed to write file: %s", zFile);
+ }
+ }
+}
+
+/*
+** SQL function: lsmode(MODE)
+**
+** Given a numberic st_mode from stat(), convert it into a human-readable
+** text string in the style of "ls -l".
+*/
+static void lsModeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ int iMode = sqlite3_value_int(argv[0]);
+ char z[16];
+ (void)argc;
+ if( S_ISLNK(iMode) ){
+ z[0] = 'l';
+ }else if( S_ISREG(iMode) ){
+ z[0] = '-';
+ }else if( S_ISDIR(iMode) ){
+ z[0] = 'd';
+ }else{
+ z[0] = '?';
+ }
+ for(i=0; i<3; i++){
+ int m = (iMode >> ((2-i)*3));
+ char *a = &z[1 + i*3];
+ a[0] = (m & 0x4) ? 'r' : '-';
+ a[1] = (m & 0x2) ? 'w' : '-';
+ a[2] = (m & 0x1) ? 'x' : '-';
+ }
+ z[10] = '\0';
+ sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT);
+}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Cursor type for recursively iterating through a directory structure.
+*/
+typedef struct fsdir_cursor fsdir_cursor;
+typedef struct FsdirLevel FsdirLevel;
+
+struct FsdirLevel {
+ DIR *pDir; /* From opendir() */
+ char *zDir; /* Name of directory (nul-terminated) */
+};
+
+struct fsdir_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+
+ int nLvl; /* Number of entries in aLvl[] array */
+ int iLvl; /* Index of current entry */
+ FsdirLevel *aLvl; /* Hierarchy of directories being traversed */
+
+ const char *zBase;
+ int nBase;
+
+ struct stat sStat; /* Current lstat() results */
+ char *zPath; /* Path to current entry */
+ sqlite3_int64 iRowid; /* Current rowid */
+};
+
+typedef struct fsdir_tab fsdir_tab;
+struct fsdir_tab {
+ sqlite3_vtab base; /* Base class - must be first */
+};
+
+/*
+** Construct a new fsdir virtual table object.
+*/
+static int fsdirConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ fsdir_tab *pNew = 0;
+ int rc;
+ (void)pAux;
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
+ rc = sqlite3_declare_vtab(db, "CREATE TABLE x" FSDIR_SCHEMA);
+ if( rc==SQLITE_OK ){
+ pNew = (fsdir_tab*)sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ }
+ *ppVtab = (sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** This method is the destructor for fsdir vtab objects.
+*/
+static int fsdirDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new fsdir_cursor object.
+*/
+static int fsdirOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ fsdir_cursor *pCur;
+ (void)p;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->iLvl = -1;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Reset a cursor back to the state it was in when first returned
+** by fsdirOpen().
+*/
+static void fsdirResetCursor(fsdir_cursor *pCur){
+ int i;
+ for(i=0; i<=pCur->iLvl; i++){
+ FsdirLevel *pLvl = &pCur->aLvl[i];
+ if( pLvl->pDir ) closedir(pLvl->pDir);
+ sqlite3_free(pLvl->zDir);
+ }
+ sqlite3_free(pCur->zPath);
+ sqlite3_free(pCur->aLvl);
+ pCur->aLvl = 0;
+ pCur->zPath = 0;
+ pCur->zBase = 0;
+ pCur->nBase = 0;
+ pCur->nLvl = 0;
+ pCur->iLvl = -1;
+ pCur->iRowid = 1;
+}
+
+/*
+** Destructor for an fsdir_cursor.
+*/
+static int fsdirClose(sqlite3_vtab_cursor *cur){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+
+ fsdirResetCursor(pCur);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+/*
+** Set the error message for the virtual table associated with cursor
+** pCur to the results of vprintf(zFmt, ...).
+*/
+static void fsdirSetErrmsg(fsdir_cursor *pCur, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ pCur->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+}
+
+
+/*
+** Advance an fsdir_cursor to its next row of output.
+*/
+static int fsdirNext(sqlite3_vtab_cursor *cur){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ mode_t m = pCur->sStat.st_mode;
+
+ pCur->iRowid++;
+ if( S_ISDIR(m) ){
+ /* Descend into this directory */
+ int iNew = pCur->iLvl + 1;
+ FsdirLevel *pLvl;
+ if( iNew>=pCur->nLvl ){
+ int nNew = iNew+1;
+ sqlite3_int64 nByte = nNew*sizeof(FsdirLevel);
+ FsdirLevel *aNew = (FsdirLevel*)sqlite3_realloc64(pCur->aLvl, nByte);
+ if( aNew==0 ) return SQLITE_NOMEM;
+ memset(&aNew[pCur->nLvl], 0, sizeof(FsdirLevel)*(nNew-pCur->nLvl));
+ pCur->aLvl = aNew;
+ pCur->nLvl = nNew;
+ }
+ pCur->iLvl = iNew;
+ pLvl = &pCur->aLvl[iNew];
+
+ pLvl->zDir = pCur->zPath;
+ pCur->zPath = 0;
+ pLvl->pDir = opendir(pLvl->zDir);
+ if( pLvl->pDir==0 ){
+ fsdirSetErrmsg(pCur, "cannot read directory: %s", pCur->zPath);
+ return SQLITE_ERROR;
+ }
+ }
+
+ while( pCur->iLvl>=0 ){
+ FsdirLevel *pLvl = &pCur->aLvl[pCur->iLvl];
+ struct dirent *pEntry = readdir(pLvl->pDir);
+ if( pEntry ){
+ if( pEntry->d_name[0]=='.' ){
+ if( pEntry->d_name[1]=='.' && pEntry->d_name[2]=='\0' ) continue;
+ if( pEntry->d_name[1]=='\0' ) continue;
+ }
+ sqlite3_free(pCur->zPath);
+ pCur->zPath = sqlite3_mprintf("%s/%s", pLvl->zDir, pEntry->d_name);
+ if( pCur->zPath==0 ) return SQLITE_NOMEM;
+ if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
+ fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+ }
+ closedir(pLvl->pDir);
+ sqlite3_free(pLvl->zDir);
+ pLvl->pDir = 0;
+ pLvl->zDir = 0;
+ pCur->iLvl--;
+ }
+
+ /* EOF */
+ sqlite3_free(pCur->zPath);
+ pCur->zPath = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the series_cursor
+** is currently pointing.
+*/
+static int fsdirColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ switch( i ){
+ case FSDIR_COLUMN_NAME: {
+ sqlite3_result_text(ctx, &pCur->zPath[pCur->nBase], -1, SQLITE_TRANSIENT);
+ break;
+ }
+
+ case FSDIR_COLUMN_MODE:
+ sqlite3_result_int64(ctx, pCur->sStat.st_mode);
+ break;
+
+ case FSDIR_COLUMN_MTIME:
+ sqlite3_result_int64(ctx, pCur->sStat.st_mtime);
+ break;
+
+ case FSDIR_COLUMN_DATA: {
+ mode_t m = pCur->sStat.st_mode;
+ if( S_ISDIR(m) ){
+ sqlite3_result_null(ctx);
+#if !defined(_WIN32) && !defined(WIN32)
+ }else if( S_ISLNK(m) ){
+ char aStatic[64];
+ char *aBuf = aStatic;
+ sqlite3_int64 nBuf = 64;
+ int n;
+
+ while( 1 ){
+ n = readlink(pCur->zPath, aBuf, nBuf);
+ if( n<nBuf ) break;
+ if( aBuf!=aStatic ) sqlite3_free(aBuf);
+ nBuf = nBuf*2;
+ aBuf = sqlite3_malloc64(nBuf);
+ if( aBuf==0 ){
+ sqlite3_result_error_nomem(ctx);
+ return SQLITE_NOMEM;
+ }
+ }
+
+ sqlite3_result_text(ctx, aBuf, n, SQLITE_TRANSIENT);
+ if( aBuf!=aStatic ) sqlite3_free(aBuf);
+#endif
+ }else{
+ readFileContents(ctx, pCur->zPath);
+ }
+ }
+ case FSDIR_COLUMN_PATH:
+ default: {
+ /* The FSDIR_COLUMN_PATH and FSDIR_COLUMN_DIR are input parameters.
+ ** always return their values as NULL */
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** first row returned is assigned rowid value 1, and each subsequent
+** row a value 1 more than that of the previous.
+*/
+static int fsdirRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int fsdirEof(sqlite3_vtab_cursor *cur){
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ return (pCur->zPath==0);
+}
+
+/*
+** xFilter callback.
+**
+** idxNum==1 PATH parameter only
+** idxNum==2 Both PATH and DIR supplied
+*/
+static int fsdirFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ const char *zDir = 0;
+ fsdir_cursor *pCur = (fsdir_cursor*)cur;
+ (void)idxStr;
+ fsdirResetCursor(pCur);
+
+ if( idxNum==0 ){
+ fsdirSetErrmsg(pCur, "table function fsdir requires an argument");
+ return SQLITE_ERROR;
+ }
+
+ assert( argc==idxNum && (argc==1 || argc==2) );
+ zDir = (const char*)sqlite3_value_text(argv[0]);
+ if( zDir==0 ){
+ fsdirSetErrmsg(pCur, "table function fsdir requires a non-NULL argument");
+ return SQLITE_ERROR;
+ }
+ if( argc==2 ){
+ pCur->zBase = (const char*)sqlite3_value_text(argv[1]);
+ }
+ if( pCur->zBase ){
+ pCur->nBase = (int)strlen(pCur->zBase)+1;
+ pCur->zPath = sqlite3_mprintf("%s/%s", pCur->zBase, zDir);
+ }else{
+ pCur->zPath = sqlite3_mprintf("%s", zDir);
+ }
+
+ if( pCur->zPath==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( fileLinkStat(pCur->zPath, &pCur->sStat) ){
+ fsdirSetErrmsg(pCur, "cannot stat file: %s", pCur->zPath);
+ return SQLITE_ERROR;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the generate_series virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** In this implementation idxNum is used to represent the
+** query plan. idxStr is unused.
+**
+** The query plan is represented by values of idxNum:
+**
+** (1) The path value is supplied by argv[0]
+** (2) Path is in argv[0] and dir is in argv[1]
+*/
+static int fsdirBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop over constraints */
+ int idxPath = -1; /* Index in pIdxInfo->aConstraint of PATH= */
+ int idxDir = -1; /* Index in pIdxInfo->aConstraint of DIR= */
+ int seenPath = 0; /* True if an unusable PATH= constraint is seen */
+ int seenDir = 0; /* True if an unusable DIR= constraint is seen */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ (void)tab;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ switch( pConstraint->iColumn ){
+ case FSDIR_COLUMN_PATH: {
+ if( pConstraint->usable ){
+ idxPath = i;
+ seenPath = 0;
+ }else if( idxPath<0 ){
+ seenPath = 1;
+ }
+ break;
+ }
+ case FSDIR_COLUMN_DIR: {
+ if( pConstraint->usable ){
+ idxDir = i;
+ seenDir = 0;
+ }else if( idxDir<0 ){
+ seenDir = 1;
+ }
+ break;
+ }
+ }
+ }
+ if( seenPath || seenDir ){
+ /* If input parameters are unusable, disallow this plan */
+ return SQLITE_CONSTRAINT;
+ }
+
+ if( idxPath<0 ){
+ pIdxInfo->idxNum = 0;
+ /* The pIdxInfo->estimatedCost should have been initialized to a huge
+ ** number. Leave it unchanged. */
+ pIdxInfo->estimatedRows = 0x7fffffff;
+ }else{
+ pIdxInfo->aConstraintUsage[idxPath].omit = 1;
+ pIdxInfo->aConstraintUsage[idxPath].argvIndex = 1;
+ if( idxDir>=0 ){
+ pIdxInfo->aConstraintUsage[idxDir].omit = 1;
+ pIdxInfo->aConstraintUsage[idxDir].argvIndex = 2;
+ pIdxInfo->idxNum = 2;
+ pIdxInfo->estimatedCost = 10.0;
+ }else{
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->estimatedCost = 100.0;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Register the "fsdir" virtual table.
+*/
+static int fsdirRegister(sqlite3 *db){
+ static sqlite3_module fsdirModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ fsdirConnect, /* xConnect */
+ fsdirBestIndex, /* xBestIndex */
+ fsdirDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ fsdirOpen, /* xOpen - open a cursor */
+ fsdirClose, /* xClose - close a cursor */
+ fsdirFilter, /* xFilter - configure scan constraints */
+ fsdirNext, /* xNext - advance a cursor */
+ fsdirEof, /* xEof - check for end of scan */
+ fsdirColumn, /* xColumn - read data */
+ fsdirRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ };
+
+ int rc = sqlite3_create_module(db, "fsdir", &fsdirModule, 0);
+ return rc;
+}
+#else /* SQLITE_OMIT_VIRTUALTABLE */
+# define fsdirRegister(x) SQLITE_OK
+#endif
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_fileio_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "readfile", 1,
+ SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
+ readfileFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "writefile", -1,
+ SQLITE_UTF8|SQLITE_DIRECTONLY, 0,
+ writefileFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0,
+ lsModeFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = fsdirRegister(db);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/fileio.c ********************/
+/************************* Begin ../ext/misc/completion.c ******************/
+/*
+** 2017-07-10
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements an eponymous virtual table that returns suggested
+** completions for a partial SQL input.
+**
+** Suggested usage:
+**
+** SELECT DISTINCT candidate COLLATE nocase
+** FROM completion($prefix,$wholeline)
+** ORDER BY 1;
+**
+** The two query parameters are optional. $prefix is the text of the
+** current word being typed and that is to be completed. $wholeline is
+** the complete input line, used for context.
+**
+** The raw completion() table might return the same candidate multiple
+** times, for example if the same column name is used to two or more
+** tables. And the candidates are returned in an arbitrary order. Hence,
+** the DISTINCT and ORDER BY are recommended.
+**
+** This virtual table operates at the speed of human typing, and so there
+** is no attempt to make it fast. Even a slow implementation will be much
+** faster than any human can type.
+**
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* completion_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a completion virtual table
+*/
+typedef struct completion_vtab completion_vtab;
+struct completion_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this completion vtab */
+};
+
+/* completion_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct completion_cursor completion_cursor;
+struct completion_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ int nPrefix, nLine; /* Number of bytes in zPrefix and zLine */
+ char *zPrefix; /* The prefix for the word we want to complete */
+ char *zLine; /* The whole that we want to complete */
+ const char *zCurrentRow; /* Current output row */
+ int szRow; /* Length of the zCurrentRow string */
+ sqlite3_stmt *pStmt; /* Current statement */
+ sqlite3_int64 iRowid; /* The rowid */
+ int ePhase; /* Current phase */
+ int j; /* inter-phase counter */
+};
+
+/* Values for ePhase:
+*/
+#define COMPLETION_FIRST_PHASE 1
+#define COMPLETION_KEYWORDS 1
+#define COMPLETION_PRAGMAS 2
+#define COMPLETION_FUNCTIONS 3
+#define COMPLETION_COLLATIONS 4
+#define COMPLETION_INDEXES 5
+#define COMPLETION_TRIGGERS 6
+#define COMPLETION_DATABASES 7
+#define COMPLETION_TABLES 8 /* Also VIEWs and TRIGGERs */
+#define COMPLETION_COLUMNS 9
+#define COMPLETION_MODULES 10
+#define COMPLETION_EOF 11
+
+/*
+** The completionConnect() method is invoked to create a new
+** completion_vtab that describes the completion virtual table.
+**
+** Think of this routine as the constructor for completion_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the completion_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against completion will look like.
+*/
+static int completionConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ completion_vtab *pNew;
+ int rc;
+
+ (void)(pAux); /* Unused parameter */
+ (void)(argc); /* Unused parameter */
+ (void)(argv); /* Unused parameter */
+ (void)(pzErr); /* Unused parameter */
+
+/* Column numbers */
+#define COMPLETION_COLUMN_CANDIDATE 0 /* Suggested completion of the input */
+#define COMPLETION_COLUMN_PREFIX 1 /* Prefix of the word to be completed */
+#define COMPLETION_COLUMN_WHOLELINE 2 /* Entire line seen so far */
+#define COMPLETION_COLUMN_PHASE 3 /* ePhase - used for debugging only */
+
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x("
+ " candidate TEXT,"
+ " prefix TEXT HIDDEN,"
+ " wholeline TEXT HIDDEN,"
+ " phase INT HIDDEN" /* Used for debugging only */
+ ")");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for completion_cursor objects.
+*/
+static int completionDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new completion_cursor object.
+*/
+static int completionOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ completion_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((completion_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Reset the completion_cursor.
+*/
+static void completionCursorReset(completion_cursor *pCur){
+ sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0;
+ sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0;
+ sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0;
+ pCur->j = 0;
+}
+
+/*
+** Destructor for a completion_cursor.
+*/
+static int completionClose(sqlite3_vtab_cursor *cur){
+ completionCursorReset((completion_cursor*)cur);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+/*
+** Advance a completion_cursor to its next row of output.
+**
+** The ->ePhase, ->j, and ->pStmt fields of the completion_cursor object
+** record the current state of the scan. This routine sets ->zCurrentRow
+** to the current row of output and then returns. If no more rows remain,
+** then ->ePhase is set to COMPLETION_EOF which will signal the virtual
+** table that has reached the end of its scan.
+**
+** The current implementation just lists potential identifiers and
+** keywords and filters them by zPrefix. Future enhancements should
+** take zLine into account to try to restrict the set of identifiers and
+** keywords based on what would be legal at the current point of input.
+*/
+static int completionNext(sqlite3_vtab_cursor *cur){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ int eNextPhase = 0; /* Next phase to try if current phase reaches end */
+ int iCol = -1; /* If >=0, step pCur->pStmt and use the i-th column */
+ pCur->iRowid++;
+ while( pCur->ePhase!=COMPLETION_EOF ){
+ switch( pCur->ePhase ){
+ case COMPLETION_KEYWORDS: {
+ if( pCur->j >= sqlite3_keyword_count() ){
+ pCur->zCurrentRow = 0;
+ pCur->ePhase = COMPLETION_DATABASES;
+ }else{
+ sqlite3_keyword_name(pCur->j++, &pCur->zCurrentRow, &pCur->szRow);
+ }
+ iCol = -1;
+ break;
+ }
+ case COMPLETION_DATABASES: {
+ if( pCur->pStmt==0 ){
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1,
+ &pCur->pStmt, 0);
+ }
+ iCol = 1;
+ eNextPhase = COMPLETION_TABLES;
+ break;
+ }
+ case COMPLETION_TABLES: {
+ if( pCur->pStmt==0 ){
+ sqlite3_stmt *pS2;
+ char *zSql = 0;
+ const char *zSep = "";
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
+ while( sqlite3_step(pS2)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
+ zSql = sqlite3_mprintf(
+ "%z%s"
+ "SELECT name FROM \"%w\".sqlite_schema",
+ zSql, zSep, zDb
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ zSep = " UNION ";
+ }
+ sqlite3_finalize(pS2);
+ sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ iCol = 0;
+ eNextPhase = COMPLETION_COLUMNS;
+ break;
+ }
+ case COMPLETION_COLUMNS: {
+ if( pCur->pStmt==0 ){
+ sqlite3_stmt *pS2;
+ char *zSql = 0;
+ const char *zSep = "";
+ sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0);
+ while( sqlite3_step(pS2)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pS2, 1);
+ zSql = sqlite3_mprintf(
+ "%z%s"
+ "SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
+ " JOIN pragma_table_info(sm.name,%Q) AS pti"
+ " WHERE sm.type='table'",
+ zSql, zSep, zDb, zDb
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ zSep = " UNION ";
+ }
+ sqlite3_finalize(pS2);
+ sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ iCol = 0;
+ eNextPhase = COMPLETION_EOF;
+ break;
+ }
+ }
+ if( iCol<0 ){
+ /* This case is when the phase presets zCurrentRow */
+ if( pCur->zCurrentRow==0 ) continue;
+ }else{
+ if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){
+ /* Extract the next row of content */
+ pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol);
+ pCur->szRow = sqlite3_column_bytes(pCur->pStmt, iCol);
+ }else{
+ /* When all rows are finished, advance to the next phase */
+ sqlite3_finalize(pCur->pStmt);
+ pCur->pStmt = 0;
+ pCur->ePhase = eNextPhase;
+ continue;
+ }
+ }
+ if( pCur->nPrefix==0 ) break;
+ if( pCur->nPrefix<=pCur->szRow
+ && sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0
+ ){
+ break;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the completion_cursor
+** is currently pointing.
+*/
+static int completionColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ switch( i ){
+ case COMPLETION_COLUMN_CANDIDATE: {
+ sqlite3_result_text(ctx, pCur->zCurrentRow, pCur->szRow,SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_PREFIX: {
+ sqlite3_result_text(ctx, pCur->zPrefix, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_WHOLELINE: {
+ sqlite3_result_text(ctx, pCur->zLine, -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case COMPLETION_COLUMN_PHASE: {
+ sqlite3_result_int(ctx, pCur->ePhase);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int completionEof(sqlite3_vtab_cursor *cur){
+ completion_cursor *pCur = (completion_cursor*)cur;
+ return pCur->ePhase >= COMPLETION_EOF;
+}
+
+/*
+** This method is called to "rewind" the completion_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to completionColumn() or completionRowid() or
+** completionEof().
+*/
+static int completionFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ completion_cursor *pCur = (completion_cursor *)pVtabCursor;
+ int iArg = 0;
+ (void)(idxStr); /* Unused parameter */
+ (void)(argc); /* Unused parameter */
+ completionCursorReset(pCur);
+ if( idxNum & 1 ){
+ pCur->nPrefix = sqlite3_value_bytes(argv[iArg]);
+ if( pCur->nPrefix>0 ){
+ pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
+ if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
+ }
+ iArg = 1;
+ }
+ if( idxNum & 2 ){
+ pCur->nLine = sqlite3_value_bytes(argv[iArg]);
+ if( pCur->nLine>0 ){
+ pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
+ if( pCur->zLine==0 ) return SQLITE_NOMEM;
+ }
+ }
+ if( pCur->zLine!=0 && pCur->zPrefix==0 ){
+ int i = pCur->nLine;
+ while( i>0 && (isalnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
+ i--;
+ }
+ pCur->nPrefix = pCur->nLine - i;
+ if( pCur->nPrefix>0 ){
+ pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
+ if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
+ }
+ }
+ pCur->iRowid = 0;
+ pCur->ePhase = COMPLETION_FIRST_PHASE;
+ return completionNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the completion virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+**
+** There are two hidden parameters that act as arguments to the table-valued
+** function: "prefix" and "wholeline". Bit 0 of idxNum is set if "prefix"
+** is available and bit 1 is set if "wholeline" is available.
+*/
+static int completionBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop over constraints */
+ int idxNum = 0; /* The query plan bitmask */
+ int prefixIdx = -1; /* Index of the start= constraint, or -1 if none */
+ int wholelineIdx = -1; /* Index of the stop= constraint, or -1 if none */
+ int nArg = 0; /* Number of arguments that completeFilter() expects */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ (void)(tab); /* Unused parameter */
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ switch( pConstraint->iColumn ){
+ case COMPLETION_COLUMN_PREFIX:
+ prefixIdx = i;
+ idxNum |= 1;
+ break;
+ case COMPLETION_COLUMN_WHOLELINE:
+ wholelineIdx = i;
+ idxNum |= 2;
+ break;
+ }
+ }
+ if( prefixIdx>=0 ){
+ pIdxInfo->aConstraintUsage[prefixIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[prefixIdx].omit = 1;
+ }
+ if( wholelineIdx>=0 ){
+ pIdxInfo->aConstraintUsage[wholelineIdx].argvIndex = ++nArg;
+ pIdxInfo->aConstraintUsage[wholelineIdx].omit = 1;
+ }
+ pIdxInfo->idxNum = idxNum;
+ pIdxInfo->estimatedCost = (double)5000 - 1000*nArg;
+ pIdxInfo->estimatedRows = 500 - 100*nArg;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** completion virtual table.
+*/
+static sqlite3_module completionModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ completionConnect, /* xConnect */
+ completionBestIndex, /* xBestIndex */
+ completionDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ completionOpen, /* xOpen - open a cursor */
+ completionClose, /* xClose - close a cursor */
+ completionFilter, /* xFilter - configure scan constraints */
+ completionNext, /* xNext - advance a cursor */
+ completionEof, /* xEof - check for end of scan */
+ completionColumn, /* xColumn - read data */
+ completionRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+int sqlite3CompletionVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "completion", &completionModule, 0);
+#endif
+ return rc;
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_completion_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)(pzErrMsg); /* Unused parameter */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3CompletionVtabInit(db);
+#endif
+ return rc;
+}
+
+/************************* End ../ext/misc/completion.c ********************/
+/************************* Begin ../ext/misc/appendvfs.c ******************/
+/*
+** 2017-10-20
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file implements a VFS shim that allows an SQLite database to be
+** appended onto the end of some other file, such as an executable.
+**
+** A special record must appear at the end of the file that identifies the
+** file as an appended database and provides an offset to page 1. For
+** best performance page 1 should be located at a disk page boundary, though
+** that is not required.
+**
+** When opening a database using this VFS, the connection might treat
+** the file as an ordinary SQLite database, or it might treat is as a
+** database appended onto some other file. Here are the rules:
+**
+** (1) When opening a new empty file, that file is treated as an ordinary
+** database.
+**
+** (2) When opening a file that begins with the standard SQLite prefix
+** string "SQLite format 3", that file is treated as an ordinary
+** database.
+**
+** (3) When opening a file that ends with the appendvfs trailer string
+** "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended
+** database.
+**
+** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is
+** set, then a new database is appended to the already existing file.
+**
+** (5) Otherwise, SQLITE_CANTOPEN is returned.
+**
+** To avoid unnecessary complications with the PENDING_BYTE, the size of
+** the file containing the database is limited to 1GB. This VFS will refuse
+** to read or write past the 1GB mark. This restriction might be lifted in
+** future versions. For now, if you need a large database, then keep the
+** database in a separate file.
+**
+** If the file being opened is not an appended database, then this shim is
+** a pass-through into the default underlying VFS.
+**/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+/* The append mark at the end of the database is:
+**
+** Start-Of-SQLite3-NNNNNNNN
+** 123456789 123456789 12345
+**
+** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
+** the offset to page 1.
+*/
+#define APND_MARK_PREFIX "Start-Of-SQLite3-"
+#define APND_MARK_PREFIX_SZ 17
+#define APND_MARK_SIZE 25
+
+/*
+** Maximum size of the combined prefix + database + append-mark. This
+** must be less than 0x40000000 to avoid locking issues on Windows.
+*/
+#define APND_MAX_SIZE (65536*15259)
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct sqlite3_vfs ApndVfs;
+typedef struct ApndFile ApndFile;
+
+/* Access to a lower-level VFS that (might) implement dynamic loading,
+** access to randomness, etc.
+*/
+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
+#define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
+
+/* An open file */
+struct ApndFile {
+ sqlite3_file base; /* IO methods */
+ sqlite3_int64 iPgOne; /* File offset to page 1 */
+ sqlite3_int64 iMark; /* Start of the append-mark */
+};
+
+/*
+** Methods for ApndFile
+*/
+static int apndClose(sqlite3_file*);
+static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int apndWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int apndTruncate(sqlite3_file*, sqlite3_int64 size);
+static int apndSync(sqlite3_file*, int flags);
+static int apndFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int apndLock(sqlite3_file*, int);
+static int apndUnlock(sqlite3_file*, int);
+static int apndCheckReservedLock(sqlite3_file*, int *pResOut);
+static int apndFileControl(sqlite3_file*, int op, void *pArg);
+static int apndSectorSize(sqlite3_file*);
+static int apndDeviceCharacteristics(sqlite3_file*);
+static int apndShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
+static int apndShmLock(sqlite3_file*, int offset, int n, int flags);
+static void apndShmBarrier(sqlite3_file*);
+static int apndShmUnmap(sqlite3_file*, int deleteFlag);
+static int apndFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+static int apndUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+
+/*
+** Methods for ApndVfs
+*/
+static int apndOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int apndDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int apndAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int apndFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *apndDlOpen(sqlite3_vfs*, const char *zFilename);
+static void apndDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void apndDlClose(sqlite3_vfs*, void*);
+static int apndRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int apndSleep(sqlite3_vfs*, int microseconds);
+static int apndCurrentTime(sqlite3_vfs*, double*);
+static int apndGetLastError(sqlite3_vfs*, int, char *);
+static int apndCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+static int apndSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
+static sqlite3_syscall_ptr apndGetSystemCall(sqlite3_vfs*, const char *z);
+static const char *apndNextSystemCall(sqlite3_vfs*, const char *zName);
+
+static sqlite3_vfs apnd_vfs = {
+ 3, /* iVersion (set when registered) */
+ 0, /* szOsFile (set when registered) */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "apndvfs", /* zName */
+ 0, /* pAppData (set when registered) */
+ apndOpen, /* xOpen */
+ apndDelete, /* xDelete */
+ apndAccess, /* xAccess */
+ apndFullPathname, /* xFullPathname */
+ apndDlOpen, /* xDlOpen */
+ apndDlError, /* xDlError */
+ apndDlSym, /* xDlSym */
+ apndDlClose, /* xDlClose */
+ apndRandomness, /* xRandomness */
+ apndSleep, /* xSleep */
+ apndCurrentTime, /* xCurrentTime */
+ apndGetLastError, /* xGetLastError */
+ apndCurrentTimeInt64, /* xCurrentTimeInt64 */
+ apndSetSystemCall, /* xSetSystemCall */
+ apndGetSystemCall, /* xGetSystemCall */
+ apndNextSystemCall /* xNextSystemCall */
+};
+
+static const sqlite3_io_methods apnd_io_methods = {
+ 3, /* iVersion */
+ apndClose, /* xClose */
+ apndRead, /* xRead */
+ apndWrite, /* xWrite */
+ apndTruncate, /* xTruncate */
+ apndSync, /* xSync */
+ apndFileSize, /* xFileSize */
+ apndLock, /* xLock */
+ apndUnlock, /* xUnlock */
+ apndCheckReservedLock, /* xCheckReservedLock */
+ apndFileControl, /* xFileControl */
+ apndSectorSize, /* xSectorSize */
+ apndDeviceCharacteristics, /* xDeviceCharacteristics */
+ apndShmMap, /* xShmMap */
+ apndShmLock, /* xShmLock */
+ apndShmBarrier, /* xShmBarrier */
+ apndShmUnmap, /* xShmUnmap */
+ apndFetch, /* xFetch */
+ apndUnfetch /* xUnfetch */
+};
+
+
+
+/*
+** Close an apnd-file.
+*/
+static int apndClose(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xClose(pFile);
+}
+
+/*
+** Read data from an apnd-file.
+*/
+static int apndRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne);
+}
+
+/*
+** Add the append-mark onto the end of the file.
+*/
+static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){
+ int i;
+ unsigned char a[APND_MARK_SIZE];
+ memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
+ for(i=0; i<8; i++){
+ a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff;
+ }
+ return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark);
+}
+
+/*
+** Write data to an apnd-file.
+*/
+static int apndWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ int rc;
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL;
+ rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne);
+ if( rc==SQLITE_OK && iOfst + iAmt + p->iPgOne > p->iMark ){
+ sqlite3_int64 sz = 0;
+ rc = pFile->pMethods->xFileSize(pFile, &sz);
+ if( rc==SQLITE_OK ){
+ p->iMark = sz - APND_MARK_SIZE;
+ if( iOfst + iAmt + p->iPgOne > p->iMark ){
+ p->iMark = p->iPgOne + iOfst + iAmt;
+ rc = apndWriteMark(p, pFile);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Truncate an apnd-file.
+*/
+static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ int rc;
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE);
+ if( rc==SQLITE_OK ){
+ p->iMark = p->iPgOne+size;
+ rc = apndWriteMark(p, pFile);
+ }
+ return rc;
+}
+
+/*
+** Sync an apnd-file.
+*/
+static int apndSync(sqlite3_file *pFile, int flags){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xSync(pFile, flags);
+}
+
+/*
+** Return the current file-size of an apnd-file.
+*/
+static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ ApndFile *p = (ApndFile *)pFile;
+ int rc;
+ pFile = ORIGFILE(p);
+ rc = pFile->pMethods->xFileSize(pFile, pSize);
+ if( rc==SQLITE_OK && p->iPgOne ){
+ *pSize -= p->iPgOne + APND_MARK_SIZE;
+ }
+ return rc;
+}
+
+/*
+** Lock an apnd-file.
+*/
+static int apndLock(sqlite3_file *pFile, int eLock){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xLock(pFile, eLock);
+}
+
+/*
+** Unlock an apnd-file.
+*/
+static int apndUnlock(sqlite3_file *pFile, int eLock){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xUnlock(pFile, eLock);
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an apnd-file.
+*/
+static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
+}
+
+/*
+** File control method. For custom operations on an apnd-file.
+*/
+static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){
+ ApndFile *p = (ApndFile *)pFile;
+ int rc;
+ pFile = ORIGFILE(pFile);
+ rc = pFile->pMethods->xFileControl(pFile, op, pArg);
+ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
+ *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg);
+ }
+ return rc;
+}
+
+/*
+** Return the sector-size in bytes for an apnd-file.
+*/
+static int apndSectorSize(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xSectorSize(pFile);
+}
+
+/*
+** Return the device characteristic flags supported by an apnd-file.
+*/
+static int apndDeviceCharacteristics(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xDeviceCharacteristics(pFile);
+}
+
+/* Create a shared memory file mapping */
+static int apndShmMap(
+ sqlite3_file *pFile,
+ int iPg,
+ int pgsz,
+ int bExtend,
+ void volatile **pp
+){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
+}
+
+/* Perform locking on a shared-memory segment */
+static int apndShmLock(sqlite3_file *pFile, int offset, int n, int flags){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmLock(pFile,offset,n,flags);
+}
+
+/* Memory barrier operation on shared memory */
+static void apndShmBarrier(sqlite3_file *pFile){
+ pFile = ORIGFILE(pFile);
+ pFile->pMethods->xShmBarrier(pFile);
+}
+
+/* Unmap a shared memory segment */
+static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
+}
+
+/* Fetch a page of a memory-mapped file */
+static int apndFetch(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOfst,
+ int iAmt,
+ void **pp
+){
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
+}
+
+/* Release a memory-mapped page */
+static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
+ ApndFile *p = (ApndFile *)pFile;
+ pFile = ORIGFILE(pFile);
+ return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage);
+}
+
+/*
+** Check to see if the file is an ordinary SQLite database file.
+*/
+static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){
+ int rc;
+ char zHdr[16];
+ static const char aSqliteHdr[] = "SQLite format 3";
+ if( sz<512 ) return 0;
+ rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0);
+ if( rc ) return 0;
+ return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0;
+}
+
+/*
+** Try to read the append-mark off the end of a file. Return the
+** start of the appended database if the append-mark is present. If
+** there is no append-mark, return -1;
+*/
+static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){
+ int rc, i;
+ sqlite3_int64 iMark;
+ unsigned char a[APND_MARK_SIZE];
+
+ if( sz<=APND_MARK_SIZE ) return -1;
+ rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE);
+ if( rc ) return -1;
+ if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1;
+ iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56;
+ for(i=1; i<8; i++){
+ iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i);
+ }
+ return iMark;
+}
+
+/*
+** Open an apnd file handle.
+*/
+static int apndOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ ApndFile *p;
+ sqlite3_file *pSubFile;
+ sqlite3_vfs *pSubVfs;
+ int rc;
+ sqlite3_int64 sz;
+ pSubVfs = ORIGVFS(pVfs);
+ if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
+ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
+ }
+ p = (ApndFile*)pFile;
+ memset(p, 0, sizeof(*p));
+ pSubFile = ORIGFILE(pFile);
+ pFile->pMethods = &apnd_io_methods;
+ rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
+ if( rc ) goto apnd_open_done;
+ rc = pSubFile->pMethods->xFileSize(pSubFile, &sz);
+ if( rc ){
+ pSubFile->pMethods->xClose(pSubFile);
+ goto apnd_open_done;
+ }
+ if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){
+ memmove(pFile, pSubFile, pSubVfs->szOsFile);
+ return SQLITE_OK;
+ }
+ p->iMark = 0;
+ p->iPgOne = apndReadMark(sz, pFile);
+ if( p->iPgOne>0 ){
+ return SQLITE_OK;
+ }
+ if( (flags & SQLITE_OPEN_CREATE)==0 ){
+ pSubFile->pMethods->xClose(pSubFile);
+ rc = SQLITE_CANTOPEN;
+ }
+ p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff;
+apnd_open_done:
+ if( rc ) pFile->pMethods = 0;
+ return rc;
+}
+
+/*
+** All other VFS methods are pass-thrus.
+*/
+static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
+}
+static int apndAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
+}
+static int apndFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
+}
+static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
+}
+static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
+}
+static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
+}
+static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
+}
+static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
+}
+static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
+}
+static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
+}
+static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
+}
+static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
+}
+static int apndSetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_syscall_ptr pCall
+){
+ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
+}
+static sqlite3_syscall_ptr apndGetSystemCall(
+ sqlite3_vfs *pVfs,
+ const char *zName
+){
+ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
+}
+static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
+ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
+}
+
+
+#ifdef _WIN32
+
+#endif
+/*
+** This routine is called when the extension is loaded.
+** Register the new VFS.
+*/
+int sqlite3_appendvfs_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ sqlite3_vfs *pOrig;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg;
+ (void)db;
+ pOrig = sqlite3_vfs_find(0);
+ apnd_vfs.iVersion = pOrig->iVersion;
+ apnd_vfs.pAppData = pOrig;
+ apnd_vfs.szOsFile = pOrig->szOsFile + sizeof(ApndFile);
+ rc = sqlite3_vfs_register(&apnd_vfs, 0);
+#ifdef APPENDVFS_TEST
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
+ }
+#endif
+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
+ return rc;
+}
+
+/************************* End ../ext/misc/appendvfs.c ********************/
+/************************* Begin ../ext/misc/memtrace.c ******************/
+/*
+** 2019-01-21
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements an extension that uses the SQLITE_CONFIG_MALLOC
+** mechanism to add a tracing layer on top of SQLite. If this extension
+** is registered prior to sqlite3_initialize(), it will cause all memory
+** allocation activities to be logged on standard output, or to some other
+** FILE specified by the initializer.
+**
+** This file needs to be compiled into the application that uses it.
+**
+** This extension is used to implement the --memtrace option of the
+** command-line shell.
+*/
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+/* The original memory allocation routines */
+static sqlite3_mem_methods memtraceBase;
+static FILE *memtraceOut;
+
+/* Methods that trace memory allocations */
+static void *memtraceMalloc(int n){
+ if( memtraceOut ){
+ fprintf(memtraceOut, "MEMTRACE: allocate %d bytes\n",
+ memtraceBase.xRoundup(n));
+ }
+ return memtraceBase.xMalloc(n);
+}
+static void memtraceFree(void *p){
+ if( p==0 ) return;
+ if( memtraceOut ){
+ fprintf(memtraceOut, "MEMTRACE: free %d bytes\n", memtraceBase.xSize(p));
+ }
+ memtraceBase.xFree(p);
+}
+static void *memtraceRealloc(void *p, int n){
+ if( p==0 ) return memtraceMalloc(n);
+ if( n==0 ){
+ memtraceFree(p);
+ return 0;
+ }
+ if( memtraceOut ){
+ fprintf(memtraceOut, "MEMTRACE: resize %d -> %d bytes\n",
+ memtraceBase.xSize(p), memtraceBase.xRoundup(n));
+ }
+ return memtraceBase.xRealloc(p, n);
+}
+static int memtraceSize(void *p){
+ return memtraceBase.xSize(p);
+}
+static int memtraceRoundup(int n){
+ return memtraceBase.xRoundup(n);
+}
+static int memtraceInit(void *p){
+ return memtraceBase.xInit(p);
+}
+static void memtraceShutdown(void *p){
+ memtraceBase.xShutdown(p);
+}
+
+/* The substitute memory allocator */
+static sqlite3_mem_methods ersaztMethods = {
+ memtraceMalloc,
+ memtraceFree,
+ memtraceRealloc,
+ memtraceSize,
+ memtraceRoundup,
+ memtraceInit,
+ memtraceShutdown,
+ 0
+};
+
+/* Begin tracing memory allocations to out. */
+int sqlite3MemTraceActivate(FILE *out){
+ int rc = SQLITE_OK;
+ if( memtraceBase.xMalloc==0 ){
+ rc = sqlite3_config(SQLITE_CONFIG_GETMALLOC, &memtraceBase);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &ersaztMethods);
+ }
+ }
+ memtraceOut = out;
+ return rc;
+}
+
+/* Deactivate memory tracing */
+int sqlite3MemTraceDeactivate(void){
+ int rc = SQLITE_OK;
+ if( memtraceBase.xMalloc!=0 ){
+ rc = sqlite3_config(SQLITE_CONFIG_MALLOC, &memtraceBase);
+ if( rc==SQLITE_OK ){
+ memset(&memtraceBase, 0, sizeof(memtraceBase));
+ }
+ }
+ memtraceOut = 0;
+ return rc;
+}
+
+/************************* End ../ext/misc/memtrace.c ********************/
+/************************* Begin ../ext/misc/uint.c ******************/
+/*
+** 2020-04-14
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements the UINT collating sequence.
+**
+** UINT works like BINARY for text, except that embedded strings
+** of digits compare in numeric order.
+**
+** * Leading zeros are handled properly, in the sense that
+** they do not mess of the maginitude comparison of embedded
+** strings of digits. "x00123y" is equal to "x123y".
+**
+** * Only unsigned integers are recognized. Plus and minus
+** signs are ignored. Decimal points and exponential notation
+** are ignored.
+**
+** * Embedded integers can be of arbitrary length. Comparison
+** is *not* limited integers that can be expressed as a
+** 64-bit machine integer.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+/*
+** Compare text in lexicographic order, except strings of digits
+** compare in numeric order.
+*/
+static int uintCollFunc(
+ void *notUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const unsigned char *zA = (const unsigned char*)pKey1;
+ const unsigned char *zB = (const unsigned char*)pKey2;
+ int i=0, j=0, x;
+ (void)notUsed;
+ while( i<nKey1 && j<nKey2 ){
+ x = zA[i] - zB[j];
+ if( isdigit(zA[i]) ){
+ int k;
+ if( !isdigit(zB[j]) ) return x;
+ while( i<nKey1 && zA[i]=='0' ){ i++; }
+ while( j<nKey2 && zB[j]=='0' ){ j++; }
+ k = 0;
+ while( i+k<nKey1 && isdigit(zA[i+k])
+ && j+k<nKey2 && isdigit(zB[j+k]) ){
+ k++;
+ }
+ if( i+k<nKey1 && isdigit(zA[i+k]) ){
+ return +1;
+ }else if( j+k<nKey2 && isdigit(zB[j+k]) ){
+ return -1;
+ }else{
+ x = memcmp(zA+i, zB+j, k);
+ if( x ) return x;
+ i += k;
+ j += k;
+ }
+ }else if( x ){
+ return x;
+ }else{
+ i++;
+ j++;
+ }
+ }
+ return (nKey1 - i) - (nKey2 - j);
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_uint_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
+}
+
+/************************* End ../ext/misc/uint.c ********************/
+/************************* Begin ../ext/misc/decimal.c ******************/
+/*
+** 2020-06-22
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** Routines to implement arbitrary-precision decimal math.
+**
+** The focus here is on simplicity and correctness, not performance.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(X) (void)(X)
+#endif
+
+
+/* A decimal object */
+typedef struct Decimal Decimal;
+struct Decimal {
+ char sign; /* 0 for positive, 1 for negative */
+ char oom; /* True if an OOM is encountered */
+ char isNull; /* True if holds a NULL rather than a number */
+ char isInit; /* True upon initialization */
+ int nDigit; /* Total number of digits */
+ int nFrac; /* Number of digits to the right of the decimal point */
+ signed char *a; /* Array of digits. Most significant first. */
+};
+
+/*
+** Release memory held by a Decimal, but do not free the object itself.
+*/
+static void decimal_clear(Decimal *p){
+ sqlite3_free(p->a);
+}
+
+/*
+** Destroy a Decimal object
+*/
+static void decimal_free(Decimal *p){
+ if( p ){
+ decimal_clear(p);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Allocate a new Decimal object. Initialize it to the number given
+** by the input string.
+*/
+static Decimal *decimal_new(
+ sqlite3_context *pCtx,
+ sqlite3_value *pIn,
+ int nAlt,
+ const unsigned char *zAlt
+){
+ Decimal *p;
+ int n, i;
+ const unsigned char *zIn;
+ int iExp = 0;
+ p = sqlite3_malloc( sizeof(*p) );
+ if( p==0 ) goto new_no_mem;
+ p->sign = 0;
+ p->oom = 0;
+ p->isInit = 1;
+ p->isNull = 0;
+ p->nDigit = 0;
+ p->nFrac = 0;
+ if( zAlt ){
+ n = nAlt,
+ zIn = zAlt;
+ }else{
+ if( sqlite3_value_type(pIn)==SQLITE_NULL ){
+ p->a = 0;
+ p->isNull = 1;
+ return p;
+ }
+ n = sqlite3_value_bytes(pIn);
+ zIn = sqlite3_value_text(pIn);
+ }
+ p->a = sqlite3_malloc64( n+1 );
+ if( p->a==0 ) goto new_no_mem;
+ for(i=0; isspace(zIn[i]); i++){}
+ if( zIn[i]=='-' ){
+ p->sign = 1;
+ i++;
+ }else if( zIn[i]=='+' ){
+ i++;
+ }
+ while( i<n && zIn[i]=='0' ) i++;
+ while( i<n ){
+ char c = zIn[i];
+ if( c>='0' && c<='9' ){
+ p->a[p->nDigit++] = c - '0';
+ }else if( c=='.' ){
+ p->nFrac = p->nDigit + 1;
+ }else if( c=='e' || c=='E' ){
+ int j = i+1;
+ int neg = 0;
+ if( j>=n ) break;
+ if( zIn[j]=='-' ){
+ neg = 1;
+ j++;
+ }else if( zIn[j]=='+' ){
+ j++;
+ }
+ while( j<n && iExp<1000000 ){
+ if( zIn[j]>='0' && zIn[j]<='9' ){
+ iExp = iExp*10 + zIn[j] - '0';
+ }
+ j++;
+ }
+ if( neg ) iExp = -iExp;
+ break;
+ }
+ i++;
+ }
+ if( p->nFrac ){
+ p->nFrac = p->nDigit - (p->nFrac - 1);
+ }
+ if( iExp>0 ){
+ if( p->nFrac>0 ){
+ if( iExp<=p->nFrac ){
+ p->nFrac -= iExp;
+ iExp = 0;
+ }else{
+ iExp -= p->nFrac;
+ p->nFrac = 0;
+ }
+ }
+ if( iExp>0 ){
+ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
+ if( p->a==0 ) goto new_no_mem;
+ memset(p->a+p->nDigit, 0, iExp);
+ p->nDigit += iExp;
+ }
+ }else if( iExp<0 ){
+ int nExtra;
+ iExp = -iExp;
+ nExtra = p->nDigit - p->nFrac - 1;
+ if( nExtra ){
+ if( nExtra>=iExp ){
+ p->nFrac += iExp;
+ iExp = 0;
+ }else{
+ iExp -= nExtra;
+ p->nFrac = p->nDigit - 1;
+ }
+ }
+ if( iExp>0 ){
+ p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
+ if( p->a==0 ) goto new_no_mem;
+ memmove(p->a+iExp, p->a, p->nDigit);
+ memset(p->a, 0, iExp);
+ p->nDigit += iExp;
+ p->nFrac += iExp;
+ }
+ }
+ return p;
+
+new_no_mem:
+ if( pCtx ) sqlite3_result_error_nomem(pCtx);
+ sqlite3_free(p);
+ return 0;
+}
+
+/*
+** Make the given Decimal the result.
+*/
+static void decimal_result(sqlite3_context *pCtx, Decimal *p){
+ char *z;
+ int i, j;
+ int n;
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ if( p->isNull ){
+ sqlite3_result_null(pCtx);
+ return;
+ }
+ z = sqlite3_malloc( p->nDigit+4 );
+ if( z==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ i = 0;
+ if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){
+ p->sign = 0;
+ }
+ if( p->sign ){
+ z[0] = '-';
+ i = 1;
+ }
+ n = p->nDigit - p->nFrac;
+ if( n<=0 ){
+ z[i++] = '0';
+ }
+ j = 0;
+ while( n>1 && p->a[j]==0 ){
+ j++;
+ n--;
+ }
+ while( n>0 ){
+ z[i++] = p->a[j] + '0';
+ j++;
+ n--;
+ }
+ if( p->nFrac ){
+ z[i++] = '.';
+ do{
+ z[i++] = p->a[j] + '0';
+ j++;
+ }while( j<p->nDigit );
+ }
+ z[i] = 0;
+ sqlite3_result_text(pCtx, z, i, sqlite3_free);
+}
+
+/*
+** SQL Function: decimal(X)
+**
+** Convert input X into decimal and then back into text
+*/
+static void decimalFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p = decimal_new(context, argv[0], 0, 0);
+ UNUSED_PARAMETER(argc);
+ decimal_result(context, p);
+ decimal_free(p);
+}
+
+/*
+** Compare to Decimal objects. Return negative, 0, or positive if the
+** first object is less than, equal to, or greater than the second.
+**
+** Preconditions for this routine:
+**
+** pA!=0
+** pA->isNull==0
+** pB!=0
+** pB->isNull==0
+*/
+static int decimal_cmp(const Decimal *pA, const Decimal *pB){
+ int nASig, nBSig, rc, n;
+ if( pA->sign!=pB->sign ){
+ return pA->sign ? -1 : +1;
+ }
+ if( pA->sign ){
+ const Decimal *pTemp = pA;
+ pA = pB;
+ pB = pTemp;
+ }
+ nASig = pA->nDigit - pA->nFrac;
+ nBSig = pB->nDigit - pB->nFrac;
+ if( nASig!=nBSig ){
+ return nASig - nBSig;
+ }
+ n = pA->nDigit;
+ if( n>pB->nDigit ) n = pB->nDigit;
+ rc = memcmp(pA->a, pB->a, n);
+ if( rc==0 ){
+ rc = pA->nDigit - pB->nDigit;
+ }
+ return rc;
+}
+
+/*
+** SQL Function: decimal_cmp(X, Y)
+**
+** Return negative, zero, or positive if X is less then, equal to, or
+** greater than Y.
+*/
+static void decimalCmpFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = 0, *pB = 0;
+ int rc;
+
+ UNUSED_PARAMETER(argc);
+ pA = decimal_new(context, argv[0], 0, 0);
+ if( pA==0 || pA->isNull ) goto cmp_done;
+ pB = decimal_new(context, argv[1], 0, 0);
+ if( pB==0 || pB->isNull ) goto cmp_done;
+ rc = decimal_cmp(pA, pB);
+ if( rc<0 ) rc = -1;
+ else if( rc>0 ) rc = +1;
+ sqlite3_result_int(context, rc);
+cmp_done:
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+/*
+** Expand the Decimal so that it has a least nDigit digits and nFrac
+** digits to the right of the decimal point.
+*/
+static void decimal_expand(Decimal *p, int nDigit, int nFrac){
+ int nAddSig;
+ int nAddFrac;
+ if( p==0 ) return;
+ nAddFrac = nFrac - p->nFrac;
+ nAddSig = (nDigit - p->nDigit) - nAddFrac;
+ if( nAddFrac==0 && nAddSig==0 ) return;
+ p->a = sqlite3_realloc64(p->a, nDigit+1);
+ if( p->a==0 ){
+ p->oom = 1;
+ return;
+ }
+ if( nAddSig ){
+ memmove(p->a+nAddSig, p->a, p->nDigit);
+ memset(p->a, 0, nAddSig);
+ p->nDigit += nAddSig;
+ }
+ if( nAddFrac ){
+ memset(p->a+p->nDigit, 0, nAddFrac);
+ p->nDigit += nAddFrac;
+ p->nFrac += nAddFrac;
+ }
+}
+
+/*
+** Add the value pB into pA.
+**
+** Both pA and pB might become denormalized by this routine.
+*/
+static void decimal_add(Decimal *pA, Decimal *pB){
+ int nSig, nFrac, nDigit;
+ int i, rc;
+ if( pA==0 ){
+ return;
+ }
+ if( pA->oom || pB==0 || pB->oom ){
+ pA->oom = 1;
+ return;
+ }
+ if( pA->isNull || pB->isNull ){
+ pA->isNull = 1;
+ return;
+ }
+ nSig = pA->nDigit - pA->nFrac;
+ if( nSig && pA->a[0]==0 ) nSig--;
+ if( nSig<pB->nDigit-pB->nFrac ){
+ nSig = pB->nDigit - pB->nFrac;
+ }
+ nFrac = pA->nFrac;
+ if( nFrac<pB->nFrac ) nFrac = pB->nFrac;
+ nDigit = nSig + nFrac + 1;
+ decimal_expand(pA, nDigit, nFrac);
+ decimal_expand(pB, nDigit, nFrac);
+ if( pA->oom || pB->oom ){
+ pA->oom = 1;
+ }else{
+ if( pA->sign==pB->sign ){
+ int carry = 0;
+ for(i=nDigit-1; i>=0; i--){
+ int x = pA->a[i] + pB->a[i] + carry;
+ if( x>=10 ){
+ carry = 1;
+ pA->a[i] = x - 10;
+ }else{
+ carry = 0;
+ pA->a[i] = x;
+ }
+ }
+ }else{
+ signed char *aA, *aB;
+ int borrow = 0;
+ rc = memcmp(pA->a, pB->a, nDigit);
+ if( rc<0 ){
+ aA = pB->a;
+ aB = pA->a;
+ pA->sign = !pA->sign;
+ }else{
+ aA = pA->a;
+ aB = pB->a;
+ }
+ for(i=nDigit-1; i>=0; i--){
+ int x = aA[i] - aB[i] - borrow;
+ if( x<0 ){
+ pA->a[i] = x+10;
+ borrow = 1;
+ }else{
+ pA->a[i] = x;
+ borrow = 0;
+ }
+ }
+ }
+ }
+}
+
+/*
+** Compare text in decimal order.
+*/
+static int decimalCollFunc(
+ void *notUsed,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const unsigned char *zA = (const unsigned char*)pKey1;
+ const unsigned char *zB = (const unsigned char*)pKey2;
+ Decimal *pA = decimal_new(0, 0, nKey1, zA);
+ Decimal *pB = decimal_new(0, 0, nKey2, zB);
+ int rc;
+ UNUSED_PARAMETER(notUsed);
+ if( pA==0 || pB==0 ){
+ rc = 0;
+ }else{
+ rc = decimal_cmp(pA, pB);
+ }
+ decimal_free(pA);
+ decimal_free(pB);
+ return rc;
+}
+
+
+/*
+** SQL Function: decimal_add(X, Y)
+** decimal_sub(X, Y)
+**
+** Return the sum or difference of X and Y.
+*/
+static void decimalAddFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ UNUSED_PARAMETER(argc);
+ decimal_add(pA, pB);
+ decimal_result(context, pA);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+static void decimalSubFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ UNUSED_PARAMETER(argc);
+ if( pB==0 ) return;
+ pB->sign = !pB->sign;
+ decimal_add(pA, pB);
+ decimal_result(context, pA);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+/* Aggregate funcion: decimal_sum(X)
+**
+** Works like sum() except that it uses decimal arithmetic for unlimited
+** precision.
+*/
+static void decimalSumStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p;
+ Decimal *pArg;
+ UNUSED_PARAMETER(argc);
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( !p->isInit ){
+ p->isInit = 1;
+ p->a = sqlite3_malloc(2);
+ if( p->a==0 ){
+ p->oom = 1;
+ }else{
+ p->a[0] = 0;
+ }
+ p->nDigit = 1;
+ p->nFrac = 0;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pArg = decimal_new(context, argv[0], 0, 0);
+ decimal_add(p, pArg);
+ decimal_free(pArg);
+}
+static void decimalSumInverse(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *p;
+ Decimal *pArg;
+ UNUSED_PARAMETER(argc);
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ if( p==0 ) return;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pArg = decimal_new(context, argv[0], 0, 0);
+ if( pArg ) pArg->sign = !pArg->sign;
+ decimal_add(p, pArg);
+ decimal_free(pArg);
+}
+static void decimalSumValue(sqlite3_context *context){
+ Decimal *p = sqlite3_aggregate_context(context, 0);
+ if( p==0 ) return;
+ decimal_result(context, p);
+}
+static void decimalSumFinalize(sqlite3_context *context){
+ Decimal *p = sqlite3_aggregate_context(context, 0);
+ if( p==0 ) return;
+ decimal_result(context, p);
+ decimal_clear(p);
+}
+
+/*
+** SQL Function: decimal_mul(X, Y)
+**
+** Return the product of X and Y.
+**
+** All significant digits after the decimal point are retained.
+** Trailing zeros after the decimal point are omitted as long as
+** the number of digits after the decimal point is no less than
+** either the number of digits in either input.
+*/
+static void decimalMulFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ Decimal *pA = decimal_new(context, argv[0], 0, 0);
+ Decimal *pB = decimal_new(context, argv[1], 0, 0);
+ signed char *acc = 0;
+ int i, j, k;
+ int minFrac;
+ UNUSED_PARAMETER(argc);
+ if( pA==0 || pA->oom || pA->isNull
+ || pB==0 || pB->oom || pB->isNull
+ ){
+ goto mul_end;
+ }
+ acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
+ if( acc==0 ){
+ sqlite3_result_error_nomem(context);
+ goto mul_end;
+ }
+ memset(acc, 0, pA->nDigit + pB->nDigit + 2);
+ minFrac = pA->nFrac;
+ if( pB->nFrac<minFrac ) minFrac = pB->nFrac;
+ for(i=pA->nDigit-1; i>=0; i--){
+ signed char f = pA->a[i];
+ int carry = 0, x;
+ for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
+ x = acc[k] + f*pB->a[j] + carry;
+ acc[k] = x%10;
+ carry = x/10;
+ }
+ x = acc[k] + carry;
+ acc[k] = x%10;
+ acc[k-1] += x/10;
+ }
+ sqlite3_free(pA->a);
+ pA->a = acc;
+ acc = 0;
+ pA->nDigit += pB->nDigit + 2;
+ pA->nFrac += pB->nFrac;
+ pA->sign ^= pB->sign;
+ while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
+ pA->nFrac--;
+ pA->nDigit--;
+ }
+ decimal_result(context, pA);
+
+mul_end:
+ sqlite3_free(acc);
+ decimal_free(pA);
+ decimal_free(pB);
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_decimal_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ static const struct {
+ const char *zFuncName;
+ int nArg;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "decimal", 1, decimalFunc },
+ { "decimal_cmp", 2, decimalCmpFunc },
+ { "decimal_add", 2, decimalAddFunc },
+ { "decimal_sub", 2, decimalSubFunc },
+ { "decimal_mul", 2, decimalMulFunc },
+ };
+ unsigned int i;
+ (void)pzErrMsg; /* Unused parameter */
+
+ SQLITE_EXTENSION_INIT2(pApi);
+
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
+ 0, aFunc[i].xFunc, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_window_function(db, "decimal_sum", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0,
+ decimalSumStep, decimalSumFinalize,
+ decimalSumValue, decimalSumInverse, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8,
+ 0, decimalCollFunc);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/decimal.c ********************/
+/************************* Begin ../ext/misc/ieee754.c ******************/
+/*
+** 2013-04-17
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements functions for the exact display
+** and input of IEEE754 Binary64 floating-point numbers.
+**
+** ieee754(X)
+** ieee754(Y,Z)
+**
+** In the first form, the value X should be a floating-point number.
+** The function will return a string of the form 'ieee754(Y,Z)' where
+** Y and Z are integers such that X==Y*pow(2,Z).
+**
+** In the second form, Y and Z are integers which are the mantissa and
+** base-2 exponent of a new floating point number. The function returns
+** a floating-point value equal to Y*pow(2,Z).
+**
+** Examples:
+**
+** ieee754(2.0) -> 'ieee754(2,0)'
+** ieee754(45.25) -> 'ieee754(181,-2)'
+** ieee754(2, 0) -> 2.0
+** ieee754(181, -2) -> 45.25
+**
+** Two additional functions break apart the one-argument ieee754()
+** result into separate integer values:
+**
+** ieee754_mantissa(45.25) -> 181
+** ieee754_exponent(45.25) -> -2
+**
+** These functions convert binary64 numbers into blobs and back again.
+**
+** ieee754_from_blob(x'3ff0000000000000') -> 1.0
+** ieee754_to_blob(1.0) -> x'3ff0000000000000'
+**
+** In all single-argument functions, if the argument is an 8-byte blob
+** then that blob is interpreted as a big-endian binary64 value.
+**
+**
+** EXACT DECIMAL REPRESENTATION OF BINARY64 VALUES
+** -----------------------------------------------
+**
+** This extension in combination with the separate 'decimal' extension
+** can be used to compute the exact decimal representation of binary64
+** values. To begin, first compute a table of exponent values:
+**
+** CREATE TABLE pow2(x INTEGER PRIMARY KEY, v TEXT);
+** WITH RECURSIVE c(x,v) AS (
+** VALUES(0,'1')
+** UNION ALL
+** SELECT x+1, decimal_mul(v,'2') FROM c WHERE x+1<=971
+** ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+** WITH RECURSIVE c(x,v) AS (
+** VALUES(-1,'0.5')
+** UNION ALL
+** SELECT x-1, decimal_mul(v,'0.5') FROM c WHERE x-1>=-1075
+** ) INSERT INTO pow2(x,v) SELECT x, v FROM c;
+**
+** Then, to compute the exact decimal representation of a floating
+** point value (the value 47.49 is used in the example) do:
+**
+** WITH c(n) AS (VALUES(47.49))
+** ---------------^^^^^---- Replace with whatever you want
+** SELECT decimal_mul(ieee754_mantissa(c.n),pow2.v)
+** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.n);
+**
+** Here is a query to show various boundry values for the binary64
+** number format:
+**
+** WITH c(name,bin) AS (VALUES
+** ('minimum positive value', x'0000000000000001'),
+** ('maximum subnormal value', x'000fffffffffffff'),
+** ('mininum positive nornal value', x'0010000000000000'),
+** ('maximum value', x'7fefffffffffffff'))
+** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v)
+** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin);
+**
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <assert.h>
+#include <string.h>
+
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(X) (void)(X)
+#endif
+
+/*
+** Implementation of the ieee754() function
+*/
+static void ieee754func(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ if( argc==1 ){
+ sqlite3_int64 m, a;
+ double r;
+ int e;
+ int isNeg;
+ char zResult[100];
+ assert( sizeof(m)==sizeof(r) );
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB
+ && sqlite3_value_bytes(argv[0])==sizeof(r)
+ ){
+ const unsigned char *x = sqlite3_value_blob(argv[0]);
+ unsigned int i;
+ sqlite3_uint64 v = 0;
+ for(i=0; i<sizeof(r); i++){
+ v = (v<<8) | x[i];
+ }
+ memcpy(&r, &v, sizeof(r));
+ }else{
+ r = sqlite3_value_double(argv[0]);
+ }
+ if( r<0.0 ){
+ isNeg = 1;
+ r = -r;
+ }else{
+ isNeg = 0;
+ }
+ memcpy(&a,&r,sizeof(a));
+ if( a==0 ){
+ e = 0;
+ m = 0;
+ }else{
+ e = a>>52;
+ m = a & ((((sqlite3_int64)1)<<52)-1);
+ if( e==0 ){
+ m <<= 1;
+ }else{
+ m |= ((sqlite3_int64)1)<<52;
+ }
+ while( e<1075 && m>0 && (m&1)==0 ){
+ m >>= 1;
+ e++;
+ }
+ if( isNeg ) m = -m;
+ }
+ switch( *(int*)sqlite3_user_data(context) ){
+ case 0:
+ sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
+ m, e-1075);
+ sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
+ break;
+ case 1:
+ sqlite3_result_int64(context, m);
+ break;
+ case 2:
+ sqlite3_result_int(context, e-1075);
+ break;
+ }
+ }else{
+ sqlite3_int64 m, e, a;
+ double r;
+ int isNeg = 0;
+ m = sqlite3_value_int64(argv[0]);
+ e = sqlite3_value_int64(argv[1]);
+ if( m<0 ){
+ isNeg = 1;
+ m = -m;
+ if( m<0 ) return;
+ }else if( m==0 && e>-1000 && e<1000 ){
+ sqlite3_result_double(context, 0.0);
+ return;
+ }
+ while( (m>>32)&0xffe00000 ){
+ m >>= 1;
+ e++;
+ }
+ while( m!=0 && ((m>>32)&0xfff00000)==0 ){
+ m <<= 1;
+ e--;
+ }
+ e += 1075;
+ if( e<=0 ){
+ /* Subnormal */
+ m >>= 1-e;
+ e = 0;
+ }else if( e>0x7ff ){
+ e = 0x7ff;
+ }
+ a = m & ((((sqlite3_int64)1)<<52)-1);
+ a |= e<<52;
+ if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
+ memcpy(&r, &a, sizeof(r));
+ sqlite3_result_double(context, r);
+ }
+}
+
+/*
+** Functions to convert between blobs and floats.
+*/
+static void ieee754func_from_blob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ UNUSED_PARAMETER(argc);
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB
+ && sqlite3_value_bytes(argv[0])==sizeof(double)
+ ){
+ double r;
+ const unsigned char *x = sqlite3_value_blob(argv[0]);
+ unsigned int i;
+ sqlite3_uint64 v = 0;
+ for(i=0; i<sizeof(r); i++){
+ v = (v<<8) | x[i];
+ }
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(context, r);
+ }
+}
+static void ieee754func_to_blob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ UNUSED_PARAMETER(argc);
+ if( sqlite3_value_type(argv[0])==SQLITE_FLOAT
+ || sqlite3_value_type(argv[0])==SQLITE_INTEGER
+ ){
+ double r = sqlite3_value_double(argv[0]);
+ sqlite3_uint64 v;
+ unsigned char a[sizeof(r)];
+ unsigned int i;
+ memcpy(&v, &r, sizeof(r));
+ for(i=1; i<=sizeof(r); i++){
+ a[sizeof(r)-i] = v&0xff;
+ v >>= 8;
+ }
+ sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT);
+ }
+}
+
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_ieee_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ static const struct {
+ char *zFName;
+ int nArg;
+ int iAux;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "ieee754", 1, 0, ieee754func },
+ { "ieee754", 2, 0, ieee754func },
+ { "ieee754_mantissa", 1, 1, ieee754func },
+ { "ieee754_exponent", 1, 2, ieee754func },
+ { "ieee754_to_blob", 1, 0, ieee754func_to_blob },
+ { "ieee754_from_blob", 1, 0, ieee754func_from_blob },
+
+ };
+ unsigned int i;
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zFName, aFunc[i].nArg,
+ SQLITE_UTF8|SQLITE_INNOCUOUS,
+ (void*)&aFunc[i].iAux,
+ aFunc[i].xFunc, 0, 0);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/ieee754.c ********************/
+#ifdef SQLITE_HAVE_ZLIB
+/************************* Begin ../ext/misc/zipfile.c ******************/
+/*
+** 2017-12-26
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file implements a virtual table for reading and writing ZIP archive
+** files.
+**
+** Usage example:
+**
+** SELECT name, sz, datetime(mtime,'unixepoch') FROM zipfile($filename);
+**
+** Current limitations:
+**
+** * No support for encryption
+** * No support for ZIP archives spanning multiple files
+** * No support for zip64 extensions
+** * Only the "inflate/deflate" (zlib) compression method is supported
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <zlib.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+#ifndef SQLITE_AMALGAMATION
+
+/* typedef sqlite3_int64 i64; */
+/* typedef unsigned char u8; */
+typedef unsigned short u16;
+typedef unsigned long u32;
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
+# define ALWAYS(X) (1)
+# define NEVER(X) (0)
+#elif !defined(NDEBUG)
+# define ALWAYS(X) ((X)?1:(assert(0),0))
+# define NEVER(X) ((X)?(assert(0),1):0)
+#else
+# define ALWAYS(X) (X)
+# define NEVER(X) (X)
+#endif
+
+#endif /* SQLITE_AMALGAMATION */
+
+/*
+** Definitions for mode bitmasks S_IFDIR, S_IFREG and S_IFLNK.
+**
+** In some ways it would be better to obtain these values from system
+** header files. But, the dependency is undesirable and (a) these
+** have been stable for decades, (b) the values are part of POSIX and
+** are also made explicit in [man stat], and (c) are part of the
+** file format for zip archives.
+*/
+#ifndef S_IFDIR
+# define S_IFDIR 0040000
+#endif
+#ifndef S_IFREG
+# define S_IFREG 0100000
+#endif
+#ifndef S_IFLNK
+# define S_IFLNK 0120000
+#endif
+
+static const char ZIPFILE_SCHEMA[] =
+ "CREATE TABLE y("
+ "name PRIMARY KEY," /* 0: Name of file in zip archive */
+ "mode," /* 1: POSIX mode for file */
+ "mtime," /* 2: Last modification time (secs since 1970)*/
+ "sz," /* 3: Size of object */
+ "rawdata," /* 4: Raw data */
+ "data," /* 5: Uncompressed data */
+ "method," /* 6: Compression method (integer) */
+ "z HIDDEN" /* 7: Name of zip file */
+ ") WITHOUT ROWID;";
+
+#define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "file" in the above */
+#define ZIPFILE_BUFFER_SIZE (64*1024)
+
+
+/*
+** Magic numbers used to read and write zip files.
+**
+** ZIPFILE_NEWENTRY_MADEBY:
+** Use this value for the "version-made-by" field in new zip file
+** entries. The upper byte indicates "unix", and the lower byte
+** indicates that the zip file matches pkzip specification 3.0.
+** This is what info-zip seems to do.
+**
+** ZIPFILE_NEWENTRY_REQUIRED:
+** Value for "version-required-to-extract" field of new entries.
+** Version 2.0 is required to support folders and deflate compression.
+**
+** ZIPFILE_NEWENTRY_FLAGS:
+** Value for "general-purpose-bit-flags" field of new entries. Bit
+** 11 means "utf-8 filename and comment".
+**
+** ZIPFILE_SIGNATURE_CDS:
+** First 4 bytes of a valid CDS record.
+**
+** ZIPFILE_SIGNATURE_LFH:
+** First 4 bytes of a valid LFH record.
+**
+** ZIPFILE_SIGNATURE_EOCD
+** First 4 bytes of a valid EOCD record.
+*/
+#define ZIPFILE_EXTRA_TIMESTAMP 0x5455
+#define ZIPFILE_NEWENTRY_MADEBY ((3<<8) + 30)
+#define ZIPFILE_NEWENTRY_REQUIRED 20
+#define ZIPFILE_NEWENTRY_FLAGS 0x800
+#define ZIPFILE_SIGNATURE_CDS 0x02014b50
+#define ZIPFILE_SIGNATURE_LFH 0x04034b50
+#define ZIPFILE_SIGNATURE_EOCD 0x06054b50
+
+/*
+** The sizes of the fixed-size part of each of the three main data
+** structures in a zip archive.
+*/
+#define ZIPFILE_LFH_FIXED_SZ 30
+#define ZIPFILE_EOCD_FIXED_SZ 22
+#define ZIPFILE_CDS_FIXED_SZ 46
+
+/*
+*** 4.3.16 End of central directory record:
+***
+*** end of central dir signature 4 bytes (0x06054b50)
+*** number of this disk 2 bytes
+*** number of the disk with the
+*** start of the central directory 2 bytes
+*** total number of entries in the
+*** central directory on this disk 2 bytes
+*** total number of entries in
+*** the central directory 2 bytes
+*** size of the central directory 4 bytes
+*** offset of start of central
+*** directory with respect to
+*** the starting disk number 4 bytes
+*** .ZIP file comment length 2 bytes
+*** .ZIP file comment (variable size)
+*/
+typedef struct ZipfileEOCD ZipfileEOCD;
+struct ZipfileEOCD {
+ u16 iDisk;
+ u16 iFirstDisk;
+ u16 nEntry;
+ u16 nEntryTotal;
+ u32 nSize;
+ u32 iOffset;
+};
+
+/*
+*** 4.3.12 Central directory structure:
+***
+*** ...
+***
+*** central file header signature 4 bytes (0x02014b50)
+*** version made by 2 bytes
+*** version needed to extract 2 bytes
+*** general purpose bit flag 2 bytes
+*** compression method 2 bytes
+*** last mod file time 2 bytes
+*** last mod file date 2 bytes
+*** crc-32 4 bytes
+*** compressed size 4 bytes
+*** uncompressed size 4 bytes
+*** file name length 2 bytes
+*** extra field length 2 bytes
+*** file comment length 2 bytes
+*** disk number start 2 bytes
+*** internal file attributes 2 bytes
+*** external file attributes 4 bytes
+*** relative offset of local header 4 bytes
+*/
+typedef struct ZipfileCDS ZipfileCDS;
+struct ZipfileCDS {
+ u16 iVersionMadeBy;
+ u16 iVersionExtract;
+ u16 flags;
+ u16 iCompression;
+ u16 mTime;
+ u16 mDate;
+ u32 crc32;
+ u32 szCompressed;
+ u32 szUncompressed;
+ u16 nFile;
+ u16 nExtra;
+ u16 nComment;
+ u16 iDiskStart;
+ u16 iInternalAttr;
+ u32 iExternalAttr;
+ u32 iOffset;
+ char *zFile; /* Filename (sqlite3_malloc()) */
+};
+
+/*
+*** 4.3.7 Local file header:
+***
+*** local file header signature 4 bytes (0x04034b50)
+*** version needed to extract 2 bytes
+*** general purpose bit flag 2 bytes
+*** compression method 2 bytes
+*** last mod file time 2 bytes
+*** last mod file date 2 bytes
+*** crc-32 4 bytes
+*** compressed size 4 bytes
+*** uncompressed size 4 bytes
+*** file name length 2 bytes
+*** extra field length 2 bytes
+***
+*/
+typedef struct ZipfileLFH ZipfileLFH;
+struct ZipfileLFH {
+ u16 iVersionExtract;
+ u16 flags;
+ u16 iCompression;
+ u16 mTime;
+ u16 mDate;
+ u32 crc32;
+ u32 szCompressed;
+ u32 szUncompressed;
+ u16 nFile;
+ u16 nExtra;
+};
+
+typedef struct ZipfileEntry ZipfileEntry;
+struct ZipfileEntry {
+ ZipfileCDS cds; /* Parsed CDS record */
+ u32 mUnixTime; /* Modification time, in UNIX format */
+ u8 *aExtra; /* cds.nExtra+cds.nComment bytes of extra data */
+ i64 iDataOff; /* Offset to data in file (if aData==0) */
+ u8 *aData; /* cds.szCompressed bytes of compressed data */
+ ZipfileEntry *pNext; /* Next element in in-memory CDS */
+};
+
+/*
+** Cursor type for zipfile tables.
+*/
+typedef struct ZipfileCsr ZipfileCsr;
+struct ZipfileCsr {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ i64 iId; /* Cursor ID */
+ u8 bEof; /* True when at EOF */
+ u8 bNoop; /* If next xNext() call is no-op */
+
+ /* Used outside of write transactions */
+ FILE *pFile; /* Zip file */
+ i64 iNextOff; /* Offset of next record in central directory */
+ ZipfileEOCD eocd; /* Parse of central directory record */
+
+ ZipfileEntry *pFreeEntry; /* Free this list when cursor is closed or reset */
+ ZipfileEntry *pCurrent; /* Current entry */
+ ZipfileCsr *pCsrNext; /* Next cursor on same virtual table */
+};
+
+typedef struct ZipfileTab ZipfileTab;
+struct ZipfileTab {
+ sqlite3_vtab base; /* Base class - must be first */
+ char *zFile; /* Zip file this table accesses (may be NULL) */
+ sqlite3 *db; /* Host database connection */
+ u8 *aBuffer; /* Temporary buffer used for various tasks */
+
+ ZipfileCsr *pCsrList; /* List of cursors */
+ i64 iNextCsrid;
+
+ /* The following are used by write transactions only */
+ ZipfileEntry *pFirstEntry; /* Linked list of all files (if pWriteFd!=0) */
+ ZipfileEntry *pLastEntry; /* Last element in pFirstEntry list */
+ FILE *pWriteFd; /* File handle open on zip archive */
+ i64 szCurrent; /* Current size of zip archive */
+ i64 szOrig; /* Size of archive at start of transaction */
+};
+
+/*
+** Set the error message contained in context ctx to the results of
+** vprintf(zFmt, ...).
+*/
+static void zipfileCtxErrorMsg(sqlite3_context *ctx, const char *zFmt, ...){
+ char *zMsg = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zMsg = sqlite3_vmprintf(zFmt, ap);
+ sqlite3_result_error(ctx, zMsg, -1);
+ sqlite3_free(zMsg);
+ va_end(ap);
+}
+
+/*
+** If string zIn is quoted, dequote it in place. Otherwise, if the string
+** is not quoted, do nothing.
+*/
+static void zipfileDequote(char *zIn){
+ char q = zIn[0];
+ if( q=='"' || q=='\'' || q=='`' || q=='[' ){
+ int iIn = 1;
+ int iOut = 0;
+ if( q=='[' ) q = ']';
+ while( ALWAYS(zIn[iIn]) ){
+ char c = zIn[iIn++];
+ if( c==q && zIn[iIn++]!=q ) break;
+ zIn[iOut++] = c;
+ }
+ zIn[iOut] = '\0';
+ }
+}
+
+/*
+** Construct a new ZipfileTab virtual table object.
+**
+** argv[0] -> module name ("zipfile")
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[...] -> "column name" and other module argument fields.
+*/
+static int zipfileConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE;
+ int nFile = 0;
+ const char *zFile = 0;
+ ZipfileTab *pNew = 0;
+ int rc;
+
+ /* If the table name is not "zipfile", require that the argument be
+ ** specified. This stops zipfile tables from being created as:
+ **
+ ** CREATE VIRTUAL TABLE zzz USING zipfile();
+ **
+ ** It does not prevent:
+ **
+ ** CREATE VIRTUAL TABLE zipfile USING zipfile();
+ */
+ assert( 0==sqlite3_stricmp(argv[0], "zipfile") );
+ if( (0!=sqlite3_stricmp(argv[2], "zipfile") && argc<4) || argc>4 ){
+ *pzErr = sqlite3_mprintf("zipfile constructor requires one argument");
+ return SQLITE_ERROR;
+ }
+
+ if( argc>3 ){
+ zFile = argv[3];
+ nFile = (int)strlen(zFile)+1;
+ }
+
+ rc = sqlite3_declare_vtab(db, ZIPFILE_SCHEMA);
+ if( rc==SQLITE_OK ){
+ pNew = (ZipfileTab*)sqlite3_malloc64((sqlite3_int64)nByte+nFile);
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, nByte+nFile);
+ pNew->db = db;
+ pNew->aBuffer = (u8*)&pNew[1];
+ if( zFile ){
+ pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE];
+ memcpy(pNew->zFile, zFile, nFile);
+ zipfileDequote(pNew->zFile);
+ }
+ }
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ *ppVtab = (sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** Free the ZipfileEntry structure indicated by the only argument.
+*/
+static void zipfileEntryFree(ZipfileEntry *p){
+ if( p ){
+ sqlite3_free(p->cds.zFile);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Release resources that should be freed at the end of a write
+** transaction.
+*/
+static void zipfileCleanupTransaction(ZipfileTab *pTab){
+ ZipfileEntry *pEntry;
+ ZipfileEntry *pNext;
+
+ if( pTab->pWriteFd ){
+ fclose(pTab->pWriteFd);
+ pTab->pWriteFd = 0;
+ }
+ for(pEntry=pTab->pFirstEntry; pEntry; pEntry=pNext){
+ pNext = pEntry->pNext;
+ zipfileEntryFree(pEntry);
+ }
+ pTab->pFirstEntry = 0;
+ pTab->pLastEntry = 0;
+ pTab->szCurrent = 0;
+ pTab->szOrig = 0;
+}
+
+/*
+** This method is the destructor for zipfile vtab objects.
+*/
+static int zipfileDisconnect(sqlite3_vtab *pVtab){
+ zipfileCleanupTransaction((ZipfileTab*)pVtab);
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new ZipfileCsr object.
+*/
+static int zipfileOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
+ ZipfileTab *pTab = (ZipfileTab*)p;
+ ZipfileCsr *pCsr;
+ pCsr = sqlite3_malloc(sizeof(*pCsr));
+ *ppCsr = (sqlite3_vtab_cursor*)pCsr;
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memset(pCsr, 0, sizeof(*pCsr));
+ pCsr->iId = ++pTab->iNextCsrid;
+ pCsr->pCsrNext = pTab->pCsrList;
+ pTab->pCsrList = pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Reset a cursor back to the state it was in when first returned
+** by zipfileOpen().
+*/
+static void zipfileResetCursor(ZipfileCsr *pCsr){
+ ZipfileEntry *p;
+ ZipfileEntry *pNext;
+
+ pCsr->bEof = 0;
+ if( pCsr->pFile ){
+ fclose(pCsr->pFile);
+ pCsr->pFile = 0;
+ zipfileEntryFree(pCsr->pCurrent);
+ pCsr->pCurrent = 0;
+ }
+
+ for(p=pCsr->pFreeEntry; p; p=pNext){
+ pNext = p->pNext;
+ zipfileEntryFree(p);
+ }
+}
+
+/*
+** Destructor for an ZipfileCsr.
+*/
+static int zipfileClose(sqlite3_vtab_cursor *cur){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ ZipfileTab *pTab = (ZipfileTab*)(pCsr->base.pVtab);
+ ZipfileCsr **pp;
+ zipfileResetCursor(pCsr);
+
+ /* Remove this cursor from the ZipfileTab.pCsrList list. */
+ for(pp=&pTab->pCsrList; *pp!=pCsr; pp=&((*pp)->pCsrNext));
+ *pp = pCsr->pCsrNext;
+
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Set the error message for the virtual table associated with cursor
+** pCsr to the results of vprintf(zFmt, ...).
+*/
+static void zipfileTableErr(ZipfileTab *pTab, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ sqlite3_free(pTab->base.zErrMsg);
+ pTab->base.zErrMsg = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+}
+static void zipfileCursorErr(ZipfileCsr *pCsr, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ sqlite3_free(pCsr->base.pVtab->zErrMsg);
+ pCsr->base.pVtab->zErrMsg = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+}
+
+/*
+** Read nRead bytes of data from offset iOff of file pFile into buffer
+** aRead[]. Return SQLITE_OK if successful, or an SQLite error code
+** otherwise.
+**
+** If an error does occur, output variable (*pzErrmsg) may be set to point
+** to an English language error message. It is the responsibility of the
+** caller to eventually free this buffer using
+** sqlite3_free().
+*/
+static int zipfileReadData(
+ FILE *pFile, /* Read from this file */
+ u8 *aRead, /* Read into this buffer */
+ int nRead, /* Number of bytes to read */
+ i64 iOff, /* Offset to read from */
+ char **pzErrmsg /* OUT: Error message (from sqlite3_malloc) */
+){
+ size_t n;
+ fseek(pFile, (long)iOff, SEEK_SET);
+ n = fread(aRead, 1, nRead, pFile);
+ if( (int)n!=nRead ){
+ *pzErrmsg = sqlite3_mprintf("error in fread()");
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+static int zipfileAppendData(
+ ZipfileTab *pTab,
+ const u8 *aWrite,
+ int nWrite
+){
+ size_t n;
+ fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET);
+ n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd);
+ if( (int)n!=nWrite ){
+ pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()");
+ return SQLITE_ERROR;
+ }
+ pTab->szCurrent += nWrite;
+ return SQLITE_OK;
+}
+
+/*
+** Read and return a 16-bit little-endian unsigned integer from buffer aBuf.
+*/
+static u16 zipfileGetU16(const u8 *aBuf){
+ return (aBuf[1] << 8) + aBuf[0];
+}
+
+/*
+** Read and return a 32-bit little-endian unsigned integer from buffer aBuf.
+*/
+static u32 zipfileGetU32(const u8 *aBuf){
+ return ((u32)(aBuf[3]) << 24)
+ + ((u32)(aBuf[2]) << 16)
+ + ((u32)(aBuf[1]) << 8)
+ + ((u32)(aBuf[0]) << 0);
+}
+
+/*
+** Write a 16-bit little endiate integer into buffer aBuf.
+*/
+static void zipfilePutU16(u8 *aBuf, u16 val){
+ aBuf[0] = val & 0xFF;
+ aBuf[1] = (val>>8) & 0xFF;
+}
+
+/*
+** Write a 32-bit little endiate integer into buffer aBuf.
+*/
+static void zipfilePutU32(u8 *aBuf, u32 val){
+ aBuf[0] = val & 0xFF;
+ aBuf[1] = (val>>8) & 0xFF;
+ aBuf[2] = (val>>16) & 0xFF;
+ aBuf[3] = (val>>24) & 0xFF;
+}
+
+#define zipfileRead32(aBuf) ( aBuf+=4, zipfileGetU32(aBuf-4) )
+#define zipfileRead16(aBuf) ( aBuf+=2, zipfileGetU16(aBuf-2) )
+
+#define zipfileWrite32(aBuf,val) { zipfilePutU32(aBuf,val); aBuf+=4; }
+#define zipfileWrite16(aBuf,val) { zipfilePutU16(aBuf,val); aBuf+=2; }
+
+/*
+** Magic numbers used to read CDS records.
+*/
+#define ZIPFILE_CDS_NFILE_OFF 28
+#define ZIPFILE_CDS_SZCOMPRESSED_OFF 20
+
+/*
+** Decode the CDS record in buffer aBuf into (*pCDS). Return SQLITE_ERROR
+** if the record is not well-formed, or SQLITE_OK otherwise.
+*/
+static int zipfileReadCDS(u8 *aBuf, ZipfileCDS *pCDS){
+ u8 *aRead = aBuf;
+ u32 sig = zipfileRead32(aRead);
+ int rc = SQLITE_OK;
+ if( sig!=ZIPFILE_SIGNATURE_CDS ){
+ rc = SQLITE_ERROR;
+ }else{
+ pCDS->iVersionMadeBy = zipfileRead16(aRead);
+ pCDS->iVersionExtract = zipfileRead16(aRead);
+ pCDS->flags = zipfileRead16(aRead);
+ pCDS->iCompression = zipfileRead16(aRead);
+ pCDS->mTime = zipfileRead16(aRead);
+ pCDS->mDate = zipfileRead16(aRead);
+ pCDS->crc32 = zipfileRead32(aRead);
+ pCDS->szCompressed = zipfileRead32(aRead);
+ pCDS->szUncompressed = zipfileRead32(aRead);
+ assert( aRead==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
+ pCDS->nFile = zipfileRead16(aRead);
+ pCDS->nExtra = zipfileRead16(aRead);
+ pCDS->nComment = zipfileRead16(aRead);
+ pCDS->iDiskStart = zipfileRead16(aRead);
+ pCDS->iInternalAttr = zipfileRead16(aRead);
+ pCDS->iExternalAttr = zipfileRead32(aRead);
+ pCDS->iOffset = zipfileRead32(aRead);
+ assert( aRead==&aBuf[ZIPFILE_CDS_FIXED_SZ] );
+ }
+
+ return rc;
+}
+
+/*
+** Decode the LFH record in buffer aBuf into (*pLFH). Return SQLITE_ERROR
+** if the record is not well-formed, or SQLITE_OK otherwise.
+*/
+static int zipfileReadLFH(
+ u8 *aBuffer,
+ ZipfileLFH *pLFH
+){
+ u8 *aRead = aBuffer;
+ int rc = SQLITE_OK;
+
+ u32 sig = zipfileRead32(aRead);
+ if( sig!=ZIPFILE_SIGNATURE_LFH ){
+ rc = SQLITE_ERROR;
+ }else{
+ pLFH->iVersionExtract = zipfileRead16(aRead);
+ pLFH->flags = zipfileRead16(aRead);
+ pLFH->iCompression = zipfileRead16(aRead);
+ pLFH->mTime = zipfileRead16(aRead);
+ pLFH->mDate = zipfileRead16(aRead);
+ pLFH->crc32 = zipfileRead32(aRead);
+ pLFH->szCompressed = zipfileRead32(aRead);
+ pLFH->szUncompressed = zipfileRead32(aRead);
+ pLFH->nFile = zipfileRead16(aRead);
+ pLFH->nExtra = zipfileRead16(aRead);
+ }
+ return rc;
+}
+
+
+/*
+** Buffer aExtra (size nExtra bytes) contains zip archive "extra" fields.
+** Scan through this buffer to find an "extra-timestamp" field. If one
+** exists, extract the 32-bit modification-timestamp from it and store
+** the value in output parameter *pmTime.
+**
+** Zero is returned if no extra-timestamp record could be found (and so
+** *pmTime is left unchanged), or non-zero otherwise.
+**
+** The general format of an extra field is:
+**
+** Header ID 2 bytes
+** Data Size 2 bytes
+** Data N bytes
+*/
+static int zipfileScanExtra(u8 *aExtra, int nExtra, u32 *pmTime){
+ int ret = 0;
+ u8 *p = aExtra;
+ u8 *pEnd = &aExtra[nExtra];
+
+ while( p<pEnd ){
+ u16 id = zipfileRead16(p);
+ u16 nByte = zipfileRead16(p);
+
+ switch( id ){
+ case ZIPFILE_EXTRA_TIMESTAMP: {
+ u8 b = p[0];
+ if( b & 0x01 ){ /* 0x01 -> modtime is present */
+ *pmTime = zipfileGetU32(&p[1]);
+ ret = 1;
+ }
+ break;
+ }
+ }
+
+ p += nByte;
+ }
+ return ret;
+}
+
+/*
+** Convert the standard MS-DOS timestamp stored in the mTime and mDate
+** fields of the CDS structure passed as the only argument to a 32-bit
+** UNIX seconds-since-the-epoch timestamp. Return the result.
+**
+** "Standard" MS-DOS time format:
+**
+** File modification time:
+** Bits 00-04: seconds divided by 2
+** Bits 05-10: minute
+** Bits 11-15: hour
+** File modification date:
+** Bits 00-04: day
+** Bits 05-08: month (1-12)
+** Bits 09-15: years from 1980
+**
+** https://msdn.microsoft.com/en-us/library/9kkf9tah.aspx
+*/
+static u32 zipfileMtime(ZipfileCDS *pCDS){
+ int Y = (1980 + ((pCDS->mDate >> 9) & 0x7F));
+ int M = ((pCDS->mDate >> 5) & 0x0F);
+ int D = (pCDS->mDate & 0x1F);
+ int B = -13;
+
+ int sec = (pCDS->mTime & 0x1F)*2;
+ int min = (pCDS->mTime >> 5) & 0x3F;
+ int hr = (pCDS->mTime >> 11) & 0x1F;
+ i64 JD;
+
+ /* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */
+
+ /* Calculate the JD in seconds for noon on the day in question */
+ if( M<3 ){
+ Y = Y-1;
+ M = M+12;
+ }
+ JD = (i64)(24*60*60) * (
+ (int)(365.25 * (Y + 4716))
+ + (int)(30.6001 * (M + 1))
+ + D + B - 1524
+ );
+
+ /* Correct the JD for the time within the day */
+ JD += (hr-12) * 3600 + min * 60 + sec;
+
+ /* Convert JD to unix timestamp (the JD epoch is 2440587.5) */
+ return (u32)(JD - (i64)(24405875) * 24*60*6);
+}
+
+/*
+** The opposite of zipfileMtime(). This function populates the mTime and
+** mDate fields of the CDS structure passed as the first argument according
+** to the UNIX timestamp value passed as the second.
+*/
+static void zipfileMtimeToDos(ZipfileCDS *pCds, u32 mUnixTime){
+ /* Convert unix timestamp to JD (2440588 is noon on 1/1/1970) */
+ i64 JD = (i64)2440588 + mUnixTime / (24*60*60);
+
+ int A, B, C, D, E;
+ int yr, mon, day;
+ int hr, min, sec;
+
+ A = (int)((JD - 1867216.25)/36524.25);
+ A = (int)(JD + 1 + A - (A/4));
+ B = A + 1524;
+ C = (int)((B - 122.1)/365.25);
+ D = (36525*(C&32767))/100;
+ E = (int)((B-D)/30.6001);
+
+ day = B - D - (int)(30.6001*E);
+ mon = (E<14 ? E-1 : E-13);
+ yr = mon>2 ? C-4716 : C-4715;
+
+ hr = (mUnixTime % (24*60*60)) / (60*60);
+ min = (mUnixTime % (60*60)) / 60;
+ sec = (mUnixTime % 60);
+
+ if( yr>=1980 ){
+ pCds->mDate = (u16)(day + (mon << 5) + ((yr-1980) << 9));
+ pCds->mTime = (u16)(sec/2 + (min<<5) + (hr<<11));
+ }else{
+ pCds->mDate = pCds->mTime = 0;
+ }
+
+ assert( mUnixTime<315507600
+ || mUnixTime==zipfileMtime(pCds)
+ || ((mUnixTime % 2) && mUnixTime-1==zipfileMtime(pCds))
+ /* || (mUnixTime % 2) */
+ );
+}
+
+/*
+** If aBlob is not NULL, then it is a pointer to a buffer (nBlob bytes in
+** size) containing an entire zip archive image. Or, if aBlob is NULL,
+** then pFile is a file-handle open on a zip file. In either case, this
+** function creates a ZipfileEntry object based on the zip archive entry
+** for which the CDS record is at offset iOff.
+**
+** If successful, SQLITE_OK is returned and (*ppEntry) set to point to
+** the new object. Otherwise, an SQLite error code is returned and the
+** final value of (*ppEntry) undefined.
+*/
+static int zipfileGetEntry(
+ ZipfileTab *pTab, /* Store any error message here */
+ const u8 *aBlob, /* Pointer to in-memory file image */
+ int nBlob, /* Size of aBlob[] in bytes */
+ FILE *pFile, /* If aBlob==0, read from this file */
+ i64 iOff, /* Offset of CDS record */
+ ZipfileEntry **ppEntry /* OUT: Pointer to new object */
+){
+ u8 *aRead;
+ char **pzErr = &pTab->base.zErrMsg;
+ int rc = SQLITE_OK;
+
+ if( aBlob==0 ){
+ aRead = pTab->aBuffer;
+ rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr);
+ }else{
+ aRead = (u8*)&aBlob[iOff];
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3_int64 nAlloc;
+ ZipfileEntry *pNew;
+
+ int nFile = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF]);
+ int nExtra = zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+2]);
+ nExtra += zipfileGetU16(&aRead[ZIPFILE_CDS_NFILE_OFF+4]);
+
+ nAlloc = sizeof(ZipfileEntry) + nExtra;
+ if( aBlob ){
+ nAlloc += zipfileGetU32(&aRead[ZIPFILE_CDS_SZCOMPRESSED_OFF]);
+ }
+
+ pNew = (ZipfileEntry*)sqlite3_malloc64(nAlloc);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pNew, 0, sizeof(ZipfileEntry));
+ rc = zipfileReadCDS(aRead, &pNew->cds);
+ if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("failed to read CDS at offset %lld", iOff);
+ }else if( aBlob==0 ){
+ rc = zipfileReadData(
+ pFile, aRead, nExtra+nFile, iOff+ZIPFILE_CDS_FIXED_SZ, pzErr
+ );
+ }else{
+ aRead = (u8*)&aBlob[iOff + ZIPFILE_CDS_FIXED_SZ];
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ u32 *pt = &pNew->mUnixTime;
+ pNew->cds.zFile = sqlite3_mprintf("%.*s", nFile, aRead);
+ pNew->aExtra = (u8*)&pNew[1];
+ memcpy(pNew->aExtra, &aRead[nFile], nExtra);
+ if( pNew->cds.zFile==0 ){
+ rc = SQLITE_NOMEM;
+ }else if( 0==zipfileScanExtra(&aRead[nFile], pNew->cds.nExtra, pt) ){
+ pNew->mUnixTime = zipfileMtime(&pNew->cds);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ static const int szFix = ZIPFILE_LFH_FIXED_SZ;
+ ZipfileLFH lfh;
+ if( pFile ){
+ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
+ }else{
+ aRead = (u8*)&aBlob[pNew->cds.iOffset];
+ }
+
+ rc = zipfileReadLFH(aRead, &lfh);
+ if( rc==SQLITE_OK ){
+ pNew->iDataOff = pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
+ pNew->iDataOff += lfh.nFile + lfh.nExtra;
+ if( aBlob && pNew->cds.szCompressed ){
+ pNew->aData = &pNew->aExtra[nExtra];
+ memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
+ }
+ }else{
+ *pzErr = sqlite3_mprintf("failed to read LFH at offset %d",
+ (int)pNew->cds.iOffset
+ );
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ zipfileEntryFree(pNew);
+ }else{
+ *ppEntry = pNew;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Advance an ZipfileCsr to its next row of output.
+*/
+static int zipfileNext(sqlite3_vtab_cursor *cur){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ int rc = SQLITE_OK;
+
+ if( pCsr->pFile ){
+ i64 iEof = pCsr->eocd.iOffset + pCsr->eocd.nSize;
+ zipfileEntryFree(pCsr->pCurrent);
+ pCsr->pCurrent = 0;
+ if( pCsr->iNextOff>=iEof ){
+ pCsr->bEof = 1;
+ }else{
+ ZipfileEntry *p = 0;
+ ZipfileTab *pTab = (ZipfileTab*)(cur->pVtab);
+ rc = zipfileGetEntry(pTab, 0, 0, pCsr->pFile, pCsr->iNextOff, &p);
+ if( rc==SQLITE_OK ){
+ pCsr->iNextOff += ZIPFILE_CDS_FIXED_SZ;
+ pCsr->iNextOff += (int)p->cds.nExtra + p->cds.nFile + p->cds.nComment;
+ }
+ pCsr->pCurrent = p;
+ }
+ }else{
+ if( !pCsr->bNoop ){
+ pCsr->pCurrent = pCsr->pCurrent->pNext;
+ }
+ if( pCsr->pCurrent==0 ){
+ pCsr->bEof = 1;
+ }
+ }
+
+ pCsr->bNoop = 0;
+ return rc;
+}
+
+static void zipfileFree(void *p) {
+ sqlite3_free(p);
+}
+
+/*
+** Buffer aIn (size nIn bytes) contains compressed data. Uncompressed, the
+** size is nOut bytes. This function uncompresses the data and sets the
+** return value in context pCtx to the result (a blob).
+**
+** If an error occurs, an error code is left in pCtx instead.
+*/
+static void zipfileInflate(
+ sqlite3_context *pCtx, /* Store result here */
+ const u8 *aIn, /* Compressed data */
+ int nIn, /* Size of buffer aIn[] in bytes */
+ int nOut /* Expected output size */
+){
+ u8 *aRes = sqlite3_malloc(nOut);
+ if( aRes==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ int err;
+ z_stream str;
+ memset(&str, 0, sizeof(str));
+
+ str.next_in = (Byte*)aIn;
+ str.avail_in = nIn;
+ str.next_out = (Byte*)aRes;
+ str.avail_out = nOut;
+
+ err = inflateInit2(&str, -15);
+ if( err!=Z_OK ){
+ zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err);
+ }else{
+ err = inflate(&str, Z_NO_FLUSH);
+ if( err!=Z_STREAM_END ){
+ zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err);
+ }else{
+ sqlite3_result_blob(pCtx, aRes, nOut, zipfileFree);
+ aRes = 0;
+ }
+ }
+ sqlite3_free(aRes);
+ inflateEnd(&str);
+ }
+}
+
+/*
+** Buffer aIn (size nIn bytes) contains uncompressed data. This function
+** compresses it and sets (*ppOut) to point to a buffer containing the
+** compressed data. The caller is responsible for eventually calling
+** sqlite3_free() to release buffer (*ppOut). Before returning, (*pnOut)
+** is set to the size of buffer (*ppOut) in bytes.
+**
+** If no error occurs, SQLITE_OK is returned. Otherwise, an SQLite error
+** code is returned and an error message left in virtual-table handle
+** pTab. The values of (*ppOut) and (*pnOut) are left unchanged in this
+** case.
+*/
+static int zipfileDeflate(
+ const u8 *aIn, int nIn, /* Input */
+ u8 **ppOut, int *pnOut, /* Output */
+ char **pzErr /* OUT: Error message */
+){
+ int rc = SQLITE_OK;
+ sqlite3_int64 nAlloc;
+ z_stream str;
+ u8 *aOut;
+
+ memset(&str, 0, sizeof(str));
+ str.next_in = (Bytef*)aIn;
+ str.avail_in = nIn;
+ deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
+
+ nAlloc = deflateBound(&str, nIn);
+ aOut = (u8*)sqlite3_malloc64(nAlloc);
+ if( aOut==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int res;
+ str.next_out = aOut;
+ str.avail_out = nAlloc;
+ res = deflate(&str, Z_FINISH);
+ if( res==Z_STREAM_END ){
+ *ppOut = aOut;
+ *pnOut = (int)str.total_out;
+ }else{
+ sqlite3_free(aOut);
+ *pzErr = sqlite3_mprintf("zipfile: deflate() error");
+ rc = SQLITE_ERROR;
+ }
+ deflateEnd(&str);
+ }
+
+ return rc;
+}
+
+
+/*
+** Return values of columns for the row at which the series_cursor
+** is currently pointing.
+*/
+static int zipfileColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ ZipfileCDS *pCDS = &pCsr->pCurrent->cds;
+ int rc = SQLITE_OK;
+ switch( i ){
+ case 0: /* name */
+ sqlite3_result_text(ctx, pCDS->zFile, -1, SQLITE_TRANSIENT);
+ break;
+ case 1: /* mode */
+ /* TODO: Whether or not the following is correct surely depends on
+ ** the platform on which the archive was created. */
+ sqlite3_result_int(ctx, pCDS->iExternalAttr >> 16);
+ break;
+ case 2: { /* mtime */
+ sqlite3_result_int64(ctx, pCsr->pCurrent->mUnixTime);
+ break;
+ }
+ case 3: { /* sz */
+ if( sqlite3_vtab_nochange(ctx)==0 ){
+ sqlite3_result_int64(ctx, pCDS->szUncompressed);
+ }
+ break;
+ }
+ case 4: /* rawdata */
+ if( sqlite3_vtab_nochange(ctx) ) break;
+ case 5: { /* data */
+ if( i==4 || pCDS->iCompression==0 || pCDS->iCompression==8 ){
+ int sz = pCDS->szCompressed;
+ int szFinal = pCDS->szUncompressed;
+ if( szFinal>0 ){
+ u8 *aBuf;
+ u8 *aFree = 0;
+ if( pCsr->pCurrent->aData ){
+ aBuf = pCsr->pCurrent->aData;
+ }else{
+ aBuf = aFree = sqlite3_malloc64(sz);
+ if( aBuf==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ FILE *pFile = pCsr->pFile;
+ if( pFile==0 ){
+ pFile = ((ZipfileTab*)(pCsr->base.pVtab))->pWriteFd;
+ }
+ rc = zipfileReadData(pFile, aBuf, sz, pCsr->pCurrent->iDataOff,
+ &pCsr->base.pVtab->zErrMsg
+ );
+ }
+ }
+ if( rc==SQLITE_OK ){
+ if( i==5 && pCDS->iCompression ){
+ zipfileInflate(ctx, aBuf, sz, szFinal);
+ }else{
+ sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT);
+ }
+ }
+ sqlite3_free(aFree);
+ }else{
+ /* Figure out if this is a directory or a zero-sized file. Consider
+ ** it to be a directory either if the mode suggests so, or if
+ ** the final character in the name is '/'. */
+ u32 mode = pCDS->iExternalAttr >> 16;
+ if( !(mode & S_IFDIR) && pCDS->zFile[pCDS->nFile-1]!='/' ){
+ sqlite3_result_blob(ctx, "", 0, SQLITE_STATIC);
+ }
+ }
+ }
+ break;
+ }
+ case 6: /* method */
+ sqlite3_result_int(ctx, pCDS->iCompression);
+ break;
+ default: /* z */
+ assert( i==7 );
+ sqlite3_result_int64(ctx, pCsr->iId);
+ break;
+ }
+
+ return rc;
+}
+
+/*
+** Return TRUE if the cursor is at EOF.
+*/
+static int zipfileEof(sqlite3_vtab_cursor *cur){
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ return pCsr->bEof;
+}
+
+/*
+** If aBlob is not NULL, then it points to a buffer nBlob bytes in size
+** containing an entire zip archive image. Or, if aBlob is NULL, then pFile
+** is guaranteed to be a file-handle open on a zip file.
+**
+** This function attempts to locate the EOCD record within the zip archive
+** and populate *pEOCD with the results of decoding it. SQLITE_OK is
+** returned if successful. Otherwise, an SQLite error code is returned and
+** an English language error message may be left in virtual-table pTab.
+*/
+static int zipfileReadEOCD(
+ ZipfileTab *pTab, /* Return errors here */
+ const u8 *aBlob, /* Pointer to in-memory file image */
+ int nBlob, /* Size of aBlob[] in bytes */
+ FILE *pFile, /* Read from this file if aBlob==0 */
+ ZipfileEOCD *pEOCD /* Object to populate */
+){
+ u8 *aRead = pTab->aBuffer; /* Temporary buffer */
+ int nRead; /* Bytes to read from file */
+ int rc = SQLITE_OK;
+
+ if( aBlob==0 ){
+ i64 iOff; /* Offset to read from */
+ i64 szFile; /* Total size of file in bytes */
+ fseek(pFile, 0, SEEK_END);
+ szFile = (i64)ftell(pFile);
+ if( szFile==0 ){
+ memset(pEOCD, 0, sizeof(ZipfileEOCD));
+ return SQLITE_OK;
+ }
+ nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
+ iOff = szFile - nRead;
+ rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
+ }else{
+ nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE));
+ aRead = (u8*)&aBlob[nBlob-nRead];
+ }
+
+ if( rc==SQLITE_OK ){
+ int i;
+
+ /* Scan backwards looking for the signature bytes */
+ for(i=nRead-20; i>=0; i--){
+ if( aRead[i]==0x50 && aRead[i+1]==0x4b
+ && aRead[i+2]==0x05 && aRead[i+3]==0x06
+ ){
+ break;
+ }
+ }
+ if( i<0 ){
+ pTab->base.zErrMsg = sqlite3_mprintf(
+ "cannot find end of central directory record"
+ );
+ return SQLITE_ERROR;
+ }
+
+ aRead += i+4;
+ pEOCD->iDisk = zipfileRead16(aRead);
+ pEOCD->iFirstDisk = zipfileRead16(aRead);
+ pEOCD->nEntry = zipfileRead16(aRead);
+ pEOCD->nEntryTotal = zipfileRead16(aRead);
+ pEOCD->nSize = zipfileRead32(aRead);
+ pEOCD->iOffset = zipfileRead32(aRead);
+ }
+
+ return rc;
+}
+
+/*
+** Add object pNew to the linked list that begins at ZipfileTab.pFirstEntry
+** and ends with pLastEntry. If argument pBefore is NULL, then pNew is added
+** to the end of the list. Otherwise, it is added to the list immediately
+** before pBefore (which is guaranteed to be a part of said list).
+*/
+static void zipfileAddEntry(
+ ZipfileTab *pTab,
+ ZipfileEntry *pBefore,
+ ZipfileEntry *pNew
+){
+ assert( (pTab->pFirstEntry==0)==(pTab->pLastEntry==0) );
+ assert( pNew->pNext==0 );
+ if( pBefore==0 ){
+ if( pTab->pFirstEntry==0 ){
+ pTab->pFirstEntry = pTab->pLastEntry = pNew;
+ }else{
+ assert( pTab->pLastEntry->pNext==0 );
+ pTab->pLastEntry->pNext = pNew;
+ pTab->pLastEntry = pNew;
+ }
+ }else{
+ ZipfileEntry **pp;
+ for(pp=&pTab->pFirstEntry; *pp!=pBefore; pp=&((*pp)->pNext));
+ pNew->pNext = pBefore;
+ *pp = pNew;
+ }
+}
+
+static int zipfileLoadDirectory(ZipfileTab *pTab, const u8 *aBlob, int nBlob){
+ ZipfileEOCD eocd;
+ int rc;
+ int i;
+ i64 iOff;
+
+ rc = zipfileReadEOCD(pTab, aBlob, nBlob, pTab->pWriteFd, &eocd);
+ iOff = eocd.iOffset;
+ for(i=0; rc==SQLITE_OK && i<eocd.nEntry; i++){
+ ZipfileEntry *pNew = 0;
+ rc = zipfileGetEntry(pTab, aBlob, nBlob, pTab->pWriteFd, iOff, &pNew);
+
+ if( rc==SQLITE_OK ){
+ zipfileAddEntry(pTab, 0, pNew);
+ iOff += ZIPFILE_CDS_FIXED_SZ;
+ iOff += (int)pNew->cds.nExtra + pNew->cds.nFile + pNew->cds.nComment;
+ }
+ }
+ return rc;
+}
+
+/*
+** xFilter callback.
+*/
+static int zipfileFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab;
+ ZipfileCsr *pCsr = (ZipfileCsr*)cur;
+ const char *zFile = 0; /* Zip file to scan */
+ int rc = SQLITE_OK; /* Return Code */
+ int bInMemory = 0; /* True for an in-memory zipfile */
+
+ zipfileResetCursor(pCsr);
+
+ if( pTab->zFile ){
+ zFile = pTab->zFile;
+ }else if( idxNum==0 ){
+ zipfileCursorErr(pCsr, "zipfile() function requires an argument");
+ return SQLITE_ERROR;
+ }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
+ const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]);
+ int nBlob = sqlite3_value_bytes(argv[0]);
+ assert( pTab->pFirstEntry==0 );
+ rc = zipfileLoadDirectory(pTab, aBlob, nBlob);
+ pCsr->pFreeEntry = pTab->pFirstEntry;
+ pTab->pFirstEntry = pTab->pLastEntry = 0;
+ if( rc!=SQLITE_OK ) return rc;
+ bInMemory = 1;
+ }else{
+ zFile = (const char*)sqlite3_value_text(argv[0]);
+ }
+
+ if( 0==pTab->pWriteFd && 0==bInMemory ){
+ pCsr->pFile = fopen(zFile, "rb");
+ if( pCsr->pFile==0 ){
+ zipfileCursorErr(pCsr, "cannot open file: %s", zFile);
+ rc = SQLITE_ERROR;
+ }else{
+ rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd);
+ if( rc==SQLITE_OK ){
+ if( pCsr->eocd.nEntry==0 ){
+ pCsr->bEof = 1;
+ }else{
+ pCsr->iNextOff = pCsr->eocd.iOffset;
+ rc = zipfileNext(cur);
+ }
+ }
+ }
+ }else{
+ pCsr->bNoop = 1;
+ pCsr->pCurrent = pCsr->pFreeEntry ? pCsr->pFreeEntry : pTab->pFirstEntry;
+ rc = zipfileNext(cur);
+ }
+
+ return rc;
+}
+
+/*
+** xBestIndex callback.
+*/
+static int zipfileBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int idx = -1;
+ int unusable = 0;
+
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
+ if( pCons->iColumn!=ZIPFILE_F_COLUMN_IDX ) continue;
+ if( pCons->usable==0 ){
+ unusable = 1;
+ }else if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ idx = i;
+ }
+ }
+ pIdxInfo->estimatedCost = 1000.0;
+ if( idx>=0 ){
+ pIdxInfo->aConstraintUsage[idx].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[idx].omit = 1;
+ pIdxInfo->idxNum = 1;
+ }else if( unusable ){
+ return SQLITE_CONSTRAINT;
+ }
+ return SQLITE_OK;
+}
+
+static ZipfileEntry *zipfileNewEntry(const char *zPath){
+ ZipfileEntry *pNew;
+ pNew = sqlite3_malloc(sizeof(ZipfileEntry));
+ if( pNew ){
+ memset(pNew, 0, sizeof(ZipfileEntry));
+ pNew->cds.zFile = sqlite3_mprintf("%s", zPath);
+ if( pNew->cds.zFile==0 ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }
+ return pNew;
+}
+
+static int zipfileSerializeLFH(ZipfileEntry *pEntry, u8 *aBuf){
+ ZipfileCDS *pCds = &pEntry->cds;
+ u8 *a = aBuf;
+
+ pCds->nExtra = 9;
+
+ /* Write the LFH itself */
+ zipfileWrite32(a, ZIPFILE_SIGNATURE_LFH);
+ zipfileWrite16(a, pCds->iVersionExtract);
+ zipfileWrite16(a, pCds->flags);
+ zipfileWrite16(a, pCds->iCompression);
+ zipfileWrite16(a, pCds->mTime);
+ zipfileWrite16(a, pCds->mDate);
+ zipfileWrite32(a, pCds->crc32);
+ zipfileWrite32(a, pCds->szCompressed);
+ zipfileWrite32(a, pCds->szUncompressed);
+ zipfileWrite16(a, (u16)pCds->nFile);
+ zipfileWrite16(a, pCds->nExtra);
+ assert( a==&aBuf[ZIPFILE_LFH_FIXED_SZ] );
+
+ /* Add the file name */
+ memcpy(a, pCds->zFile, (int)pCds->nFile);
+ a += (int)pCds->nFile;
+
+ /* The "extra" data */
+ zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP);
+ zipfileWrite16(a, 5);
+ *a++ = 0x01;
+ zipfileWrite32(a, pEntry->mUnixTime);
+
+ return a-aBuf;
+}
+
+static int zipfileAppendEntry(
+ ZipfileTab *pTab,
+ ZipfileEntry *pEntry,
+ const u8 *pData,
+ int nData
+){
+ u8 *aBuf = pTab->aBuffer;
+ int nBuf;
+ int rc;
+
+ nBuf = zipfileSerializeLFH(pEntry, aBuf);
+ rc = zipfileAppendData(pTab, aBuf, nBuf);
+ if( rc==SQLITE_OK ){
+ pEntry->iDataOff = pTab->szCurrent;
+ rc = zipfileAppendData(pTab, pData, nData);
+ }
+
+ return rc;
+}
+
+static int zipfileGetMode(
+ sqlite3_value *pVal,
+ int bIsDir, /* If true, default to directory */
+ u32 *pMode, /* OUT: Mode value */
+ char **pzErr /* OUT: Error message */
+){
+ const char *z = (const char*)sqlite3_value_text(pVal);
+ u32 mode = 0;
+ if( z==0 ){
+ mode = (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644));
+ }else if( z[0]>='0' && z[0]<='9' ){
+ mode = (unsigned int)sqlite3_value_int(pVal);
+ }else{
+ const char zTemplate[11] = "-rwxrwxrwx";
+ int i;
+ if( strlen(z)!=10 ) goto parse_error;
+ switch( z[0] ){
+ case '-': mode |= S_IFREG; break;
+ case 'd': mode |= S_IFDIR; break;
+ case 'l': mode |= S_IFLNK; break;
+ default: goto parse_error;
+ }
+ for(i=1; i<10; i++){
+ if( z[i]==zTemplate[i] ) mode |= 1 << (9-i);
+ else if( z[i]!='-' ) goto parse_error;
+ }
+ }
+ if( ((mode & S_IFDIR)==0)==bIsDir ){
+ /* The "mode" attribute is a directory, but data has been specified.
+ ** Or vice-versa - no data but "mode" is a file or symlink. */
+ *pzErr = sqlite3_mprintf("zipfile: mode does not match data");
+ return SQLITE_CONSTRAINT;
+ }
+ *pMode = mode;
+ return SQLITE_OK;
+
+ parse_error:
+ *pzErr = sqlite3_mprintf("zipfile: parse error in mode: %s", z);
+ return SQLITE_ERROR;
+}
+
+/*
+** Both (const char*) arguments point to nul-terminated strings. Argument
+** nB is the value of strlen(zB). This function returns 0 if the strings are
+** identical, ignoring any trailing '/' character in either path. */
+static int zipfileComparePath(const char *zA, const char *zB, int nB){
+ int nA = (int)strlen(zA);
+ if( nA>0 && zA[nA-1]=='/' ) nA--;
+ if( nB>0 && zB[nB-1]=='/' ) nB--;
+ if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
+ return 1;
+}
+
+static int zipfileBegin(sqlite3_vtab *pVtab){
+ ZipfileTab *pTab = (ZipfileTab*)pVtab;
+ int rc = SQLITE_OK;
+
+ assert( pTab->pWriteFd==0 );
+ if( pTab->zFile==0 || pTab->zFile[0]==0 ){
+ pTab->base.zErrMsg = sqlite3_mprintf("zipfile: missing filename");
+ return SQLITE_ERROR;
+ }
+
+ /* Open a write fd on the file. Also load the entire central directory
+ ** structure into memory. During the transaction any new file data is
+ ** appended to the archive file, but the central directory is accumulated
+ ** in main-memory until the transaction is committed. */
+ pTab->pWriteFd = fopen(pTab->zFile, "ab+");
+ if( pTab->pWriteFd==0 ){
+ pTab->base.zErrMsg = sqlite3_mprintf(
+ "zipfile: failed to open file %s for writing", pTab->zFile
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ fseek(pTab->pWriteFd, 0, SEEK_END);
+ pTab->szCurrent = pTab->szOrig = (i64)ftell(pTab->pWriteFd);
+ rc = zipfileLoadDirectory(pTab, 0, 0);
+ }
+
+ if( rc!=SQLITE_OK ){
+ zipfileCleanupTransaction(pTab);
+ }
+
+ return rc;
+}
+
+/*
+** Return the current time as a 32-bit timestamp in UNIX epoch format (like
+** time(2)).
+*/
+static u32 zipfileTime(void){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
+ u32 ret;
+ if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
+ i64 ms;
+ pVfs->xCurrentTimeInt64(pVfs, &ms);
+ ret = (u32)((ms/1000) - ((i64)24405875 * 8640));
+ }else{
+ double day;
+ pVfs->xCurrentTime(pVfs, &day);
+ ret = (u32)((day - 2440587.5) * 86400);
+ }
+ return ret;
+}
+
+/*
+** Return a 32-bit timestamp in UNIX epoch format.
+**
+** If the value passed as the only argument is either NULL or an SQL NULL,
+** return the current time. Otherwise, return the value stored in (*pVal)
+** cast to a 32-bit unsigned integer.
+*/
+static u32 zipfileGetTime(sqlite3_value *pVal){
+ if( pVal==0 || sqlite3_value_type(pVal)==SQLITE_NULL ){
+ return zipfileTime();
+ }
+ return (u32)sqlite3_value_int64(pVal);
+}
+
+/*
+** Unless it is NULL, entry pOld is currently part of the pTab->pFirstEntry
+** linked list. Remove it from the list and free the object.
+*/
+static void zipfileRemoveEntryFromList(ZipfileTab *pTab, ZipfileEntry *pOld){
+ if( pOld ){
+ ZipfileEntry **pp;
+ for(pp=&pTab->pFirstEntry; (*pp)!=pOld; pp=&((*pp)->pNext));
+ *pp = (*pp)->pNext;
+ zipfileEntryFree(pOld);
+ }
+}
+
+/*
+** xUpdate method.
+*/
+static int zipfileUpdate(
+ sqlite3_vtab *pVtab,
+ int nVal,
+ sqlite3_value **apVal,
+ sqlite_int64 *pRowid
+){
+ ZipfileTab *pTab = (ZipfileTab*)pVtab;
+ int rc = SQLITE_OK; /* Return Code */
+ ZipfileEntry *pNew = 0; /* New in-memory CDS entry */
+
+ u32 mode = 0; /* Mode for new entry */
+ u32 mTime = 0; /* Modification time for new entry */
+ i64 sz = 0; /* Uncompressed size */
+ const char *zPath = 0; /* Path for new entry */
+ int nPath = 0; /* strlen(zPath) */
+ const u8 *pData = 0; /* Pointer to buffer containing content */
+ int nData = 0; /* Size of pData buffer in bytes */
+ int iMethod = 0; /* Compression method for new entry */
+ u8 *pFree = 0; /* Free this */
+ char *zFree = 0; /* Also free this */
+ ZipfileEntry *pOld = 0;
+ ZipfileEntry *pOld2 = 0;
+ int bUpdate = 0; /* True for an update that modifies "name" */
+ int bIsDir = 0;
+ u32 iCrc32 = 0;
+
+ if( pTab->pWriteFd==0 ){
+ rc = zipfileBegin(pVtab);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
+ /* If this is a DELETE or UPDATE, find the archive entry to delete. */
+ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
+ const char *zDelete = (const char*)sqlite3_value_text(apVal[0]);
+ int nDelete = (int)strlen(zDelete);
+ if( nVal>1 ){
+ const char *zUpdate = (const char*)sqlite3_value_text(apVal[1]);
+ if( zUpdate && zipfileComparePath(zUpdate, zDelete, nDelete)!=0 ){
+ bUpdate = 1;
+ }
+ }
+ for(pOld=pTab->pFirstEntry; 1; pOld=pOld->pNext){
+ if( zipfileComparePath(pOld->cds.zFile, zDelete, nDelete)==0 ){
+ break;
+ }
+ assert( pOld->pNext );
+ }
+ }
+
+ if( nVal>1 ){
+ /* Check that "sz" and "rawdata" are both NULL: */
+ if( sqlite3_value_type(apVal[5])!=SQLITE_NULL ){
+ zipfileTableErr(pTab, "sz must be NULL");
+ rc = SQLITE_CONSTRAINT;
+ }
+ if( sqlite3_value_type(apVal[6])!=SQLITE_NULL ){
+ zipfileTableErr(pTab, "rawdata must be NULL");
+ rc = SQLITE_CONSTRAINT;
+ }
+
+ if( rc==SQLITE_OK ){
+ if( sqlite3_value_type(apVal[7])==SQLITE_NULL ){
+ /* data=NULL. A directory */
+ bIsDir = 1;
+ }else{
+ /* Value specified for "data", and possibly "method". This must be
+ ** a regular file or a symlink. */
+ const u8 *aIn = sqlite3_value_blob(apVal[7]);
+ int nIn = sqlite3_value_bytes(apVal[7]);
+ int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL;
+
+ iMethod = sqlite3_value_int(apVal[8]);
+ sz = nIn;
+ pData = aIn;
+ nData = nIn;
+ if( iMethod!=0 && iMethod!=8 ){
+ zipfileTableErr(pTab, "unknown compression method: %d", iMethod);
+ rc = SQLITE_CONSTRAINT;
+ }else{
+ if( bAuto || iMethod ){
+ int nCmp;
+ rc = zipfileDeflate(aIn, nIn, &pFree, &nCmp, &pTab->base.zErrMsg);
+ if( rc==SQLITE_OK ){
+ if( iMethod || nCmp<nIn ){
+ iMethod = 8;
+ pData = pFree;
+ nData = nCmp;
+ }
+ }
+ }
+ iCrc32 = crc32(0, aIn, nIn);
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = zipfileGetMode(apVal[3], bIsDir, &mode, &pTab->base.zErrMsg);
+ }
+
+ if( rc==SQLITE_OK ){
+ zPath = (const char*)sqlite3_value_text(apVal[2]);
+ if( zPath==0 ) zPath = "";
+ nPath = (int)strlen(zPath);
+ mTime = zipfileGetTime(apVal[4]);
+ }
+
+ if( rc==SQLITE_OK && bIsDir ){
+ /* For a directory, check that the last character in the path is a
+ ** '/'. This appears to be required for compatibility with info-zip
+ ** (the unzip command on unix). It does not create directories
+ ** otherwise. */
+ if( nPath<=0 || zPath[nPath-1]!='/' ){
+ zFree = sqlite3_mprintf("%s/", zPath);
+ zPath = (const char*)zFree;
+ if( zFree==0 ){
+ rc = SQLITE_NOMEM;
+ nPath = 0;
+ }else{
+ nPath = (int)strlen(zPath);
+ }
+ }
+ }
+
+ /* Check that we're not inserting a duplicate entry -OR- updating an
+ ** entry with a path, thereby making it into a duplicate. */
+ if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){
+ ZipfileEntry *p;
+ for(p=pTab->pFirstEntry; p; p=p->pNext){
+ if( zipfileComparePath(p->cds.zFile, zPath, nPath)==0 ){
+ switch( sqlite3_vtab_on_conflict(pTab->db) ){
+ case SQLITE_IGNORE: {
+ goto zipfile_update_done;
+ }
+ case SQLITE_REPLACE: {
+ pOld2 = p;
+ break;
+ }
+ default: {
+ zipfileTableErr(pTab, "duplicate name: \"%s\"", zPath);
+ rc = SQLITE_CONSTRAINT;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Create the new CDS record. */
+ pNew = zipfileNewEntry(zPath);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pNew->cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
+ pNew->cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
+ pNew->cds.flags = ZIPFILE_NEWENTRY_FLAGS;
+ pNew->cds.iCompression = (u16)iMethod;
+ zipfileMtimeToDos(&pNew->cds, mTime);
+ pNew->cds.crc32 = iCrc32;
+ pNew->cds.szCompressed = nData;
+ pNew->cds.szUncompressed = (u32)sz;
+ pNew->cds.iExternalAttr = (mode<<16);
+ pNew->cds.iOffset = (u32)pTab->szCurrent;
+ pNew->cds.nFile = (u16)nPath;
+ pNew->mUnixTime = (u32)mTime;
+ rc = zipfileAppendEntry(pTab, pNew, pData, nData);
+ zipfileAddEntry(pTab, pOld, pNew);
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK && (pOld || pOld2) ){
+ ZipfileCsr *pCsr;
+ for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
+ if( pCsr->pCurrent && (pCsr->pCurrent==pOld || pCsr->pCurrent==pOld2) ){
+ pCsr->pCurrent = pCsr->pCurrent->pNext;
+ pCsr->bNoop = 1;
+ }
+ }
+
+ zipfileRemoveEntryFromList(pTab, pOld);
+ zipfileRemoveEntryFromList(pTab, pOld2);
+ }
+
+zipfile_update_done:
+ sqlite3_free(pFree);
+ sqlite3_free(zFree);
+ return rc;
+}
+
+static int zipfileSerializeEOCD(ZipfileEOCD *p, u8 *aBuf){
+ u8 *a = aBuf;
+ zipfileWrite32(a, ZIPFILE_SIGNATURE_EOCD);
+ zipfileWrite16(a, p->iDisk);
+ zipfileWrite16(a, p->iFirstDisk);
+ zipfileWrite16(a, p->nEntry);
+ zipfileWrite16(a, p->nEntryTotal);
+ zipfileWrite32(a, p->nSize);
+ zipfileWrite32(a, p->iOffset);
+ zipfileWrite16(a, 0); /* Size of trailing comment in bytes*/
+
+ return a-aBuf;
+}
+
+static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){
+ int nBuf = zipfileSerializeEOCD(p, pTab->aBuffer);
+ assert( nBuf==ZIPFILE_EOCD_FIXED_SZ );
+ return zipfileAppendData(pTab, pTab->aBuffer, nBuf);
+}
+
+/*
+** Serialize the CDS structure into buffer aBuf[]. Return the number
+** of bytes written.
+*/
+static int zipfileSerializeCDS(ZipfileEntry *pEntry, u8 *aBuf){
+ u8 *a = aBuf;
+ ZipfileCDS *pCDS = &pEntry->cds;
+
+ if( pEntry->aExtra==0 ){
+ pCDS->nExtra = 9;
+ }
+
+ zipfileWrite32(a, ZIPFILE_SIGNATURE_CDS);
+ zipfileWrite16(a, pCDS->iVersionMadeBy);
+ zipfileWrite16(a, pCDS->iVersionExtract);
+ zipfileWrite16(a, pCDS->flags);
+ zipfileWrite16(a, pCDS->iCompression);
+ zipfileWrite16(a, pCDS->mTime);
+ zipfileWrite16(a, pCDS->mDate);
+ zipfileWrite32(a, pCDS->crc32);
+ zipfileWrite32(a, pCDS->szCompressed);
+ zipfileWrite32(a, pCDS->szUncompressed);
+ assert( a==&aBuf[ZIPFILE_CDS_NFILE_OFF] );
+ zipfileWrite16(a, pCDS->nFile);
+ zipfileWrite16(a, pCDS->nExtra);
+ zipfileWrite16(a, pCDS->nComment);
+ zipfileWrite16(a, pCDS->iDiskStart);
+ zipfileWrite16(a, pCDS->iInternalAttr);
+ zipfileWrite32(a, pCDS->iExternalAttr);
+ zipfileWrite32(a, pCDS->iOffset);
+
+ memcpy(a, pCDS->zFile, pCDS->nFile);
+ a += pCDS->nFile;
+
+ if( pEntry->aExtra ){
+ int n = (int)pCDS->nExtra + (int)pCDS->nComment;
+ memcpy(a, pEntry->aExtra, n);
+ a += n;
+ }else{
+ assert( pCDS->nExtra==9 );
+ zipfileWrite16(a, ZIPFILE_EXTRA_TIMESTAMP);
+ zipfileWrite16(a, 5);
+ *a++ = 0x01;
+ zipfileWrite32(a, pEntry->mUnixTime);
+ }
+
+ return a-aBuf;
+}
+
+static int zipfileCommit(sqlite3_vtab *pVtab){
+ ZipfileTab *pTab = (ZipfileTab*)pVtab;
+ int rc = SQLITE_OK;
+ if( pTab->pWriteFd ){
+ i64 iOffset = pTab->szCurrent;
+ ZipfileEntry *p;
+ ZipfileEOCD eocd;
+ int nEntry = 0;
+
+ /* Write out all entries */
+ for(p=pTab->pFirstEntry; rc==SQLITE_OK && p; p=p->pNext){
+ int n = zipfileSerializeCDS(p, pTab->aBuffer);
+ rc = zipfileAppendData(pTab, pTab->aBuffer, n);
+ nEntry++;
+ }
+
+ /* Write out the EOCD record */
+ eocd.iDisk = 0;
+ eocd.iFirstDisk = 0;
+ eocd.nEntry = (u16)nEntry;
+ eocd.nEntryTotal = (u16)nEntry;
+ eocd.nSize = (u32)(pTab->szCurrent - iOffset);
+ eocd.iOffset = (u32)iOffset;
+ rc = zipfileAppendEOCD(pTab, &eocd);
+
+ zipfileCleanupTransaction(pTab);
+ }
+ return rc;
+}
+
+static int zipfileRollback(sqlite3_vtab *pVtab){
+ return zipfileCommit(pVtab);
+}
+
+static ZipfileCsr *zipfileFindCursor(ZipfileTab *pTab, i64 iId){
+ ZipfileCsr *pCsr;
+ for(pCsr=pTab->pCsrList; pCsr; pCsr=pCsr->pCsrNext){
+ if( iId==pCsr->iId ) break;
+ }
+ return pCsr;
+}
+
+static void zipfileFunctionCds(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ ZipfileCsr *pCsr;
+ ZipfileTab *pTab = (ZipfileTab*)sqlite3_user_data(context);
+ assert( argc>0 );
+
+ pCsr = zipfileFindCursor(pTab, sqlite3_value_int64(argv[0]));
+ if( pCsr ){
+ ZipfileCDS *p = &pCsr->pCurrent->cds;
+ char *zRes = sqlite3_mprintf("{"
+ "\"version-made-by\" : %u, "
+ "\"version-to-extract\" : %u, "
+ "\"flags\" : %u, "
+ "\"compression\" : %u, "
+ "\"time\" : %u, "
+ "\"date\" : %u, "
+ "\"crc32\" : %u, "
+ "\"compressed-size\" : %u, "
+ "\"uncompressed-size\" : %u, "
+ "\"file-name-length\" : %u, "
+ "\"extra-field-length\" : %u, "
+ "\"file-comment-length\" : %u, "
+ "\"disk-number-start\" : %u, "
+ "\"internal-attr\" : %u, "
+ "\"external-attr\" : %u, "
+ "\"offset\" : %u }",
+ (u32)p->iVersionMadeBy, (u32)p->iVersionExtract,
+ (u32)p->flags, (u32)p->iCompression,
+ (u32)p->mTime, (u32)p->mDate,
+ (u32)p->crc32, (u32)p->szCompressed,
+ (u32)p->szUncompressed, (u32)p->nFile,
+ (u32)p->nExtra, (u32)p->nComment,
+ (u32)p->iDiskStart, (u32)p->iInternalAttr,
+ (u32)p->iExternalAttr, (u32)p->iOffset
+ );
+
+ if( zRes==0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_text(context, zRes, -1, SQLITE_TRANSIENT);
+ sqlite3_free(zRes);
+ }
+ }
+}
+
+/*
+** xFindFunction method.
+*/
+static int zipfileFindFunction(
+ sqlite3_vtab *pVtab, /* Virtual table handle */
+ int nArg, /* Number of SQL function arguments */
+ const char *zName, /* Name of SQL function */
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
+ void **ppArg /* OUT: User data for *pxFunc */
+){
+ if( sqlite3_stricmp("zipfile_cds", zName)==0 ){
+ *pxFunc = zipfileFunctionCds;
+ *ppArg = (void*)pVtab;
+ return 1;
+ }
+ return 0;
+}
+
+typedef struct ZipfileBuffer ZipfileBuffer;
+struct ZipfileBuffer {
+ u8 *a; /* Pointer to buffer */
+ int n; /* Size of buffer in bytes */
+ int nAlloc; /* Byte allocated at a[] */
+};
+
+typedef struct ZipfileCtx ZipfileCtx;
+struct ZipfileCtx {
+ int nEntry;
+ ZipfileBuffer body;
+ ZipfileBuffer cds;
+};
+
+static int zipfileBufferGrow(ZipfileBuffer *pBuf, int nByte){
+ if( pBuf->n+nByte>pBuf->nAlloc ){
+ u8 *aNew;
+ sqlite3_int64 nNew = pBuf->n ? pBuf->n*2 : 512;
+ int nReq = pBuf->n + nByte;
+
+ while( nNew<nReq ) nNew = nNew*2;
+ aNew = sqlite3_realloc64(pBuf->a, nNew);
+ if( aNew==0 ) return SQLITE_NOMEM;
+ pBuf->a = aNew;
+ pBuf->nAlloc = (int)nNew;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** xStep() callback for the zipfile() aggregate. This can be called in
+** any of the following ways:
+**
+** SELECT zipfile(name,data) ...
+** SELECT zipfile(name,mode,mtime,data) ...
+** SELECT zipfile(name,mode,mtime,data,method) ...
+*/
+void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){
+ ZipfileCtx *p; /* Aggregate function context */
+ ZipfileEntry e; /* New entry to add to zip archive */
+
+ sqlite3_value *pName = 0;
+ sqlite3_value *pMode = 0;
+ sqlite3_value *pMtime = 0;
+ sqlite3_value *pData = 0;
+ sqlite3_value *pMethod = 0;
+
+ int bIsDir = 0;
+ u32 mode;
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ int iMethod = -1; /* Compression method to use (0 or 8) */
+
+ const u8 *aData = 0; /* Possibly compressed data for new entry */
+ int nData = 0; /* Size of aData[] in bytes */
+ int szUncompressed = 0; /* Size of data before compression */
+ u8 *aFree = 0; /* Free this before returning */
+ u32 iCrc32 = 0; /* crc32 of uncompressed data */
+
+ char *zName = 0; /* Path (name) of new entry */
+ int nName = 0; /* Size of zName in bytes */
+ char *zFree = 0; /* Free this before returning */
+ int nByte;
+
+ memset(&e, 0, sizeof(e));
+ p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
+ if( p==0 ) return;
+
+ /* Martial the arguments into stack variables */
+ if( nVal!=2 && nVal!=4 && nVal!=5 ){
+ zErr = sqlite3_mprintf("wrong number of arguments to function zipfile()");
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+ pName = apVal[0];
+ if( nVal==2 ){
+ pData = apVal[1];
+ }else{
+ pMode = apVal[1];
+ pMtime = apVal[2];
+ pData = apVal[3];
+ if( nVal==5 ){
+ pMethod = apVal[4];
+ }
+ }
+
+ /* Check that the 'name' parameter looks ok. */
+ zName = (char*)sqlite3_value_text(pName);
+ nName = sqlite3_value_bytes(pName);
+ if( zName==0 ){
+ zErr = sqlite3_mprintf("first argument to zipfile() must be non-NULL");
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+
+ /* Inspect the 'method' parameter. This must be either 0 (store), 8 (use
+ ** deflate compression) or NULL (choose automatically). */
+ if( pMethod && SQLITE_NULL!=sqlite3_value_type(pMethod) ){
+ iMethod = (int)sqlite3_value_int64(pMethod);
+ if( iMethod!=0 && iMethod!=8 ){
+ zErr = sqlite3_mprintf("illegal method value: %d", iMethod);
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+ }
+
+ /* Now inspect the data. If this is NULL, then the new entry must be a
+ ** directory. Otherwise, figure out whether or not the data should
+ ** be deflated or simply stored in the zip archive. */
+ if( sqlite3_value_type(pData)==SQLITE_NULL ){
+ bIsDir = 1;
+ iMethod = 0;
+ }else{
+ aData = sqlite3_value_blob(pData);
+ szUncompressed = nData = sqlite3_value_bytes(pData);
+ iCrc32 = crc32(0, aData, nData);
+ if( iMethod<0 || iMethod==8 ){
+ int nOut = 0;
+ rc = zipfileDeflate(aData, nData, &aFree, &nOut, &zErr);
+ if( rc!=SQLITE_OK ){
+ goto zipfile_step_out;
+ }
+ if( iMethod==8 || nOut<nData ){
+ aData = aFree;
+ nData = nOut;
+ iMethod = 8;
+ }else{
+ iMethod = 0;
+ }
+ }
+ }
+
+ /* Decode the "mode" argument. */
+ rc = zipfileGetMode(pMode, bIsDir, &mode, &zErr);
+ if( rc ) goto zipfile_step_out;
+
+ /* Decode the "mtime" argument. */
+ e.mUnixTime = zipfileGetTime(pMtime);
+
+ /* If this is a directory entry, ensure that there is exactly one '/'
+ ** at the end of the path. Or, if this is not a directory and the path
+ ** ends in '/' it is an error. */
+ if( bIsDir==0 ){
+ if( nName>0 && zName[nName-1]=='/' ){
+ zErr = sqlite3_mprintf("non-directory name must not end with /");
+ rc = SQLITE_ERROR;
+ goto zipfile_step_out;
+ }
+ }else{
+ if( nName==0 || zName[nName-1]!='/' ){
+ zName = zFree = sqlite3_mprintf("%s/", zName);
+ if( zName==0 ){
+ rc = SQLITE_NOMEM;
+ goto zipfile_step_out;
+ }
+ nName = (int)strlen(zName);
+ }else{
+ while( nName>1 && zName[nName-2]=='/' ) nName--;
+ }
+ }
+
+ /* Assemble the ZipfileEntry object for the new zip archive entry */
+ e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY;
+ e.cds.iVersionExtract = ZIPFILE_NEWENTRY_REQUIRED;
+ e.cds.flags = ZIPFILE_NEWENTRY_FLAGS;
+ e.cds.iCompression = (u16)iMethod;
+ zipfileMtimeToDos(&e.cds, (u32)e.mUnixTime);
+ e.cds.crc32 = iCrc32;
+ e.cds.szCompressed = nData;
+ e.cds.szUncompressed = szUncompressed;
+ e.cds.iExternalAttr = (mode<<16);
+ e.cds.iOffset = p->body.n;
+ e.cds.nFile = (u16)nName;
+ e.cds.zFile = zName;
+
+ /* Append the LFH to the body of the new archive */
+ nByte = ZIPFILE_LFH_FIXED_SZ + e.cds.nFile + 9;
+ if( (rc = zipfileBufferGrow(&p->body, nByte)) ) goto zipfile_step_out;
+ p->body.n += zipfileSerializeLFH(&e, &p->body.a[p->body.n]);
+
+ /* Append the data to the body of the new archive */
+ if( nData>0 ){
+ if( (rc = zipfileBufferGrow(&p->body, nData)) ) goto zipfile_step_out;
+ memcpy(&p->body.a[p->body.n], aData, nData);
+ p->body.n += nData;
+ }
+
+ /* Append the CDS record to the directory of the new archive */
+ nByte = ZIPFILE_CDS_FIXED_SZ + e.cds.nFile + 9;
+ if( (rc = zipfileBufferGrow(&p->cds, nByte)) ) goto zipfile_step_out;
+ p->cds.n += zipfileSerializeCDS(&e, &p->cds.a[p->cds.n]);
+
+ /* Increment the count of entries in the archive */
+ p->nEntry++;
+
+ zipfile_step_out:
+ sqlite3_free(aFree);
+ sqlite3_free(zFree);
+ if( rc ){
+ if( zErr ){
+ sqlite3_result_error(pCtx, zErr, -1);
+ }else{
+ sqlite3_result_error_code(pCtx, rc);
+ }
+ }
+ sqlite3_free(zErr);
+}
+
+/*
+** xFinalize() callback for zipfile aggregate function.
+*/
+void zipfileFinal(sqlite3_context *pCtx){
+ ZipfileCtx *p;
+ ZipfileEOCD eocd;
+ sqlite3_int64 nZip;
+ u8 *aZip;
+
+ p = (ZipfileCtx*)sqlite3_aggregate_context(pCtx, sizeof(ZipfileCtx));
+ if( p==0 ) return;
+ if( p->nEntry>0 ){
+ memset(&eocd, 0, sizeof(eocd));
+ eocd.nEntry = (u16)p->nEntry;
+ eocd.nEntryTotal = (u16)p->nEntry;
+ eocd.nSize = p->cds.n;
+ eocd.iOffset = p->body.n;
+
+ nZip = p->body.n + p->cds.n + ZIPFILE_EOCD_FIXED_SZ;
+ aZip = (u8*)sqlite3_malloc64(nZip);
+ if( aZip==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ memcpy(aZip, p->body.a, p->body.n);
+ memcpy(&aZip[p->body.n], p->cds.a, p->cds.n);
+ zipfileSerializeEOCD(&eocd, &aZip[p->body.n + p->cds.n]);
+ sqlite3_result_blob(pCtx, aZip, (int)nZip, zipfileFree);
+ }
+ }
+
+ sqlite3_free(p->body.a);
+ sqlite3_free(p->cds.a);
+}
+
+
+/*
+** Register the "zipfile" virtual table.
+*/
+static int zipfileRegister(sqlite3 *db){
+ static sqlite3_module zipfileModule = {
+ 1, /* iVersion */
+ zipfileConnect, /* xCreate */
+ zipfileConnect, /* xConnect */
+ zipfileBestIndex, /* xBestIndex */
+ zipfileDisconnect, /* xDisconnect */
+ zipfileDisconnect, /* xDestroy */
+ zipfileOpen, /* xOpen - open a cursor */
+ zipfileClose, /* xClose - close a cursor */
+ zipfileFilter, /* xFilter - configure scan constraints */
+ zipfileNext, /* xNext - advance a cursor */
+ zipfileEof, /* xEof - check for end of scan */
+ zipfileColumn, /* xColumn - read data */
+ 0, /* xRowid - read data */
+ zipfileUpdate, /* xUpdate */
+ zipfileBegin, /* xBegin */
+ 0, /* xSync */
+ zipfileCommit, /* xCommit */
+ zipfileRollback, /* xRollback */
+ zipfileFindFunction, /* xFindMethod */
+ 0, /* xRename */
+ };
+
+ int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0);
+ if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "zipfile", -1, SQLITE_UTF8, 0, 0,
+ zipfileStep, zipfileFinal
+ );
+ }
+ return rc;
+}
+#else /* SQLITE_OMIT_VIRTUALTABLE */
+# define zipfileRegister(x) SQLITE_OK
+#endif
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_zipfile_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ return zipfileRegister(db);
+}
+
+/************************* End ../ext/misc/zipfile.c ********************/
+/************************* Begin ../ext/misc/sqlar.c ******************/
+/*
+** 2017-12-17
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
+** for working with sqlar archives and used by the shell tool's built-in
+** sqlar support.
+*/
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+#include <zlib.h>
+#include <assert.h>
+
+/*
+** Implementation of the "sqlar_compress(X)" SQL function.
+**
+** If the type of X is SQLITE_BLOB, and compressing that blob using
+** zlib utility function compress() yields a smaller blob, return the
+** compressed blob. Otherwise, return a copy of X.
+**
+** SQLar uses the "zlib format" for compressed content. The zlib format
+** contains a two-byte identification header and a four-byte checksum at
+** the end. This is different from ZIP which uses the raw deflate format.
+**
+** Future enhancements to SQLar might add support for new compression formats.
+** If so, those new formats will be identified by alternative headers in the
+** compressed data.
+*/
+static void sqlarCompressFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
+ const Bytef *pData = sqlite3_value_blob(argv[0]);
+ uLong nData = sqlite3_value_bytes(argv[0]);
+ uLongf nOut = compressBound(nData);
+ Bytef *pOut;
+
+ pOut = (Bytef*)sqlite3_malloc(nOut);
+ if( pOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }else{
+ if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
+ sqlite3_result_error(context, "error in compress()", -1);
+ }else if( nOut<nData ){
+ sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_value(context, argv[0]);
+ }
+ sqlite3_free(pOut);
+ }
+ }else{
+ sqlite3_result_value(context, argv[0]);
+ }
+}
+
+/*
+** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
+**
+** Parameter SZ is interpreted as an integer. If it is less than or
+** equal to zero, then this function returns a copy of X. Or, if
+** SZ is equal to the size of X when interpreted as a blob, also
+** return a copy of X. Otherwise, decompress blob X using zlib
+** utility function uncompress() and return the results (another
+** blob).
+*/
+static void sqlarUncompressFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ uLong nData;
+ uLongf sz;
+
+ assert( argc==2 );
+ sz = sqlite3_value_int(argv[1]);
+
+ if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
+ sqlite3_result_value(context, argv[0]);
+ }else{
+ const Bytef *pData= sqlite3_value_blob(argv[0]);
+ Bytef *pOut = sqlite3_malloc(sz);
+ if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
+ sqlite3_result_error(context, "error in uncompress()", -1);
+ }else{
+ sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
+ }
+ sqlite3_free(pOut);
+ }
+}
+
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_sqlar_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ rc = sqlite3_create_function(db, "sqlar_compress", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
+ sqlarCompressFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "sqlar_uncompress", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS, 0,
+ sqlarUncompressFunc, 0, 0);
+ }
+ return rc;
+}
+
+/************************* End ../ext/misc/sqlar.c ********************/
+#endif
+/************************* Begin ../ext/expert/sqlite3expert.h ******************/
+/*
+** 2017 April 07
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+*/
+#if !defined(SQLITEEXPERT_H)
+#define SQLITEEXPERT_H 1
+/* #include "sqlite3.h" */
+
+typedef struct sqlite3expert sqlite3expert;
+
+/*
+** Create a new sqlite3expert object.
+**
+** If successful, a pointer to the new object is returned and (*pzErr) set
+** to NULL. Or, if an error occurs, NULL is returned and (*pzErr) set to
+** an English-language error message. In this case it is the responsibility
+** of the caller to eventually free the error message buffer using
+** sqlite3_free().
+*/
+sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErr);
+
+/*
+** Configure an sqlite3expert object.
+**
+** EXPERT_CONFIG_SAMPLE:
+** By default, sqlite3_expert_analyze() generates sqlite_stat1 data for
+** each candidate index. This involves scanning and sorting the entire
+** contents of each user database table once for each candidate index
+** associated with the table. For large databases, this can be
+** prohibitively slow. This option allows the sqlite3expert object to
+** be configured so that sqlite_stat1 data is instead generated based on a
+** subset of each table, or so that no sqlite_stat1 data is used at all.
+**
+** A single integer argument is passed to this option. If the value is less
+** than or equal to zero, then no sqlite_stat1 data is generated or used by
+** the analysis - indexes are recommended based on the database schema only.
+** Or, if the value is 100 or greater, complete sqlite_stat1 data is
+** generated for each candidate index (this is the default). Finally, if the
+** value falls between 0 and 100, then it represents the percentage of user
+** table rows that should be considered when generating sqlite_stat1 data.
+**
+** Examples:
+**
+** // Do not generate any sqlite_stat1 data
+** sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 0);
+**
+** // Generate sqlite_stat1 data based on 10% of the rows in each table.
+** sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 10);
+*/
+int sqlite3_expert_config(sqlite3expert *p, int op, ...);
+
+#define EXPERT_CONFIG_SAMPLE 1 /* int */
+
+/*
+** Specify zero or more SQL statements to be included in the analysis.
+**
+** Buffer zSql must contain zero or more complete SQL statements. This
+** function parses all statements contained in the buffer and adds them
+** to the internal list of statements to analyze. If successful, SQLITE_OK
+** is returned and (*pzErr) set to NULL. Or, if an error occurs - for example
+** due to a error in the SQL - an SQLite error code is returned and (*pzErr)
+** may be set to point to an English language error message. In this case
+** the caller is responsible for eventually freeing the error message buffer
+** using sqlite3_free().
+**
+** If an error does occur while processing one of the statements in the
+** buffer passed as the second argument, none of the statements in the
+** buffer are added to the analysis.
+**
+** This function must be called before sqlite3_expert_analyze(). If a call
+** to this function is made on an sqlite3expert object that has already
+** been passed to sqlite3_expert_analyze() SQLITE_MISUSE is returned
+** immediately and no statements are added to the analysis.
+*/
+int sqlite3_expert_sql(
+ sqlite3expert *p, /* From a successful sqlite3_expert_new() */
+ const char *zSql, /* SQL statement(s) to add */
+ char **pzErr /* OUT: Error message (if any) */
+);
+
+
+/*
+** This function is called after the sqlite3expert object has been configured
+** with all SQL statements using sqlite3_expert_sql() to actually perform
+** the analysis. Once this function has been called, it is not possible to
+** add further SQL statements to the analysis.
+**
+** If successful, SQLITE_OK is returned and (*pzErr) is set to NULL. Or, if
+** an error occurs, an SQLite error code is returned and (*pzErr) set to
+** point to a buffer containing an English language error message. In this
+** case it is the responsibility of the caller to eventually free the buffer
+** using sqlite3_free().
+**
+** If an error does occur within this function, the sqlite3expert object
+** is no longer useful for any purpose. At that point it is no longer
+** possible to add further SQL statements to the object or to re-attempt
+** the analysis. The sqlite3expert object must still be freed using a call
+** sqlite3_expert_destroy().
+*/
+int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr);
+
+/*
+** Return the total number of statements loaded using sqlite3_expert_sql().
+** The total number of SQL statements may be different from the total number
+** to calls to sqlite3_expert_sql().
+*/
+int sqlite3_expert_count(sqlite3expert*);
+
+/*
+** Return a component of the report.
+**
+** This function is called after sqlite3_expert_analyze() to extract the
+** results of the analysis. Each call to this function returns either a
+** NULL pointer or a pointer to a buffer containing a nul-terminated string.
+** The value passed as the third argument must be one of the EXPERT_REPORT_*
+** #define constants defined below.
+**
+** For some EXPERT_REPORT_* parameters, the buffer returned contains
+** information relating to a specific SQL statement. In these cases that
+** SQL statement is identified by the value passed as the second argument.
+** SQL statements are numbered from 0 in the order in which they are parsed.
+** If an out-of-range value (less than zero or equal to or greater than the
+** value returned by sqlite3_expert_count()) is passed as the second argument
+** along with such an EXPERT_REPORT_* parameter, NULL is always returned.
+**
+** EXPERT_REPORT_SQL:
+** Return the text of SQL statement iStmt.
+**
+** EXPERT_REPORT_INDEXES:
+** Return a buffer containing the CREATE INDEX statements for all recommended
+** indexes for statement iStmt. If there are no new recommeded indexes, NULL
+** is returned.
+**
+** EXPERT_REPORT_PLAN:
+** Return a buffer containing the EXPLAIN QUERY PLAN output for SQL query
+** iStmt after the proposed indexes have been added to the database schema.
+**
+** EXPERT_REPORT_CANDIDATES:
+** Return a pointer to a buffer containing the CREATE INDEX statements
+** for all indexes that were tested (for all SQL statements). The iStmt
+** parameter is ignored for EXPERT_REPORT_CANDIDATES calls.
+*/
+const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
+
+/*
+** Values for the third argument passed to sqlite3_expert_report().
+*/
+#define EXPERT_REPORT_SQL 1
+#define EXPERT_REPORT_INDEXES 2
+#define EXPERT_REPORT_PLAN 3
+#define EXPERT_REPORT_CANDIDATES 4
+
+/*
+** Free an (sqlite3expert*) handle and all associated resources. There
+** should be one call to this function for each successful call to
+** sqlite3-expert_new().
+*/
+void sqlite3_expert_destroy(sqlite3expert*);
+
+#endif /* !defined(SQLITEEXPERT_H) */
+
+/************************* End ../ext/expert/sqlite3expert.h ********************/
+/************************* Begin ../ext/expert/sqlite3expert.c ******************/
+/*
+** 2017 April 09
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+*/
+/* #include "sqlite3expert.h" */
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* typedef sqlite3_int64 i64; */
+/* typedef sqlite3_uint64 u64; */
+
+typedef struct IdxColumn IdxColumn;
+typedef struct IdxConstraint IdxConstraint;
+typedef struct IdxScan IdxScan;
+typedef struct IdxStatement IdxStatement;
+typedef struct IdxTable IdxTable;
+typedef struct IdxWrite IdxWrite;
+
+#define STRLEN (int)strlen
+
+/*
+** A temp table name that we assume no user database will actually use.
+** If this assumption proves incorrect triggers on the table with the
+** conflicting name will be ignored.
+*/
+#define UNIQUE_TABLE_NAME "t592690916721053953805701627921227776"
+
+/*
+** A single constraint. Equivalent to either "col = ?" or "col < ?" (or
+** any other type of single-ended range constraint on a column).
+**
+** pLink:
+** Used to temporarily link IdxConstraint objects into lists while
+** creating candidate indexes.
+*/
+struct IdxConstraint {
+ char *zColl; /* Collation sequence */
+ int bRange; /* True for range, false for eq */
+ int iCol; /* Constrained table column */
+ int bFlag; /* Used by idxFindCompatible() */
+ int bDesc; /* True if ORDER BY <expr> DESC */
+ IdxConstraint *pNext; /* Next constraint in pEq or pRange list */
+ IdxConstraint *pLink; /* See above */
+};
+
+/*
+** A single scan of a single table.
+*/
+struct IdxScan {
+ IdxTable *pTab; /* Associated table object */
+ int iDb; /* Database containing table zTable */
+ i64 covering; /* Mask of columns required for cov. index */
+ IdxConstraint *pOrder; /* ORDER BY columns */
+ IdxConstraint *pEq; /* List of == constraints */
+ IdxConstraint *pRange; /* List of < constraints */
+ IdxScan *pNextScan; /* Next IdxScan object for same analysis */
+};
+
+/*
+** Information regarding a single database table. Extracted from
+** "PRAGMA table_info" by function idxGetTableInfo().
+*/
+struct IdxColumn {
+ char *zName;
+ char *zColl;
+ int iPk;
+};
+struct IdxTable {
+ int nCol;
+ char *zName; /* Table name */
+ IdxColumn *aCol;
+ IdxTable *pNext; /* Next table in linked list of all tables */
+};
+
+/*
+** An object of the following type is created for each unique table/write-op
+** seen. The objects are stored in a singly-linked list beginning at
+** sqlite3expert.pWrite.
+*/
+struct IdxWrite {
+ IdxTable *pTab;
+ int eOp; /* SQLITE_UPDATE, DELETE or INSERT */
+ IdxWrite *pNext;
+};
+
+/*
+** Each statement being analyzed is represented by an instance of this
+** structure.
+*/
+struct IdxStatement {
+ int iId; /* Statement number */
+ char *zSql; /* SQL statement */
+ char *zIdx; /* Indexes */
+ char *zEQP; /* Plan */
+ IdxStatement *pNext;
+};
+
+
+/*
+** A hash table for storing strings. With space for a payload string
+** with each entry. Methods are:
+**
+** idxHashInit()
+** idxHashClear()
+** idxHashAdd()
+** idxHashSearch()
+*/
+#define IDX_HASH_SIZE 1023
+typedef struct IdxHashEntry IdxHashEntry;
+typedef struct IdxHash IdxHash;
+struct IdxHashEntry {
+ char *zKey; /* nul-terminated key */
+ char *zVal; /* nul-terminated value string */
+ char *zVal2; /* nul-terminated value string 2 */
+ IdxHashEntry *pHashNext; /* Next entry in same hash bucket */
+ IdxHashEntry *pNext; /* Next entry in hash */
+};
+struct IdxHash {
+ IdxHashEntry *pFirst;
+ IdxHashEntry *aHash[IDX_HASH_SIZE];
+};
+
+/*
+** sqlite3expert object.
+*/
+struct sqlite3expert {
+ int iSample; /* Percentage of tables to sample for stat1 */
+ sqlite3 *db; /* User database */
+ sqlite3 *dbm; /* In-memory db for this analysis */
+ sqlite3 *dbv; /* Vtab schema for this analysis */
+ IdxTable *pTable; /* List of all IdxTable objects */
+ IdxScan *pScan; /* List of scan objects */
+ IdxWrite *pWrite; /* List of write objects */
+ IdxStatement *pStatement; /* List of IdxStatement objects */
+ int bRun; /* True once analysis has run */
+ char **pzErrmsg;
+ int rc; /* Error code from whereinfo hook */
+ IdxHash hIdx; /* Hash containing all candidate indexes */
+ char *zCandidates; /* For EXPERT_REPORT_CANDIDATES */
+};
+
+
+/*
+** Allocate and return nByte bytes of zeroed memory using sqlite3_malloc().
+** If the allocation fails, set *pRc to SQLITE_NOMEM and return NULL.
+*/
+static void *idxMalloc(int *pRc, int nByte){
+ void *pRet;
+ assert( *pRc==SQLITE_OK );
+ assert( nByte>0 );
+ pRet = sqlite3_malloc(nByte);
+ if( pRet ){
+ memset(pRet, 0, nByte);
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
+ return pRet;
+}
+
+/*
+** Initialize an IdxHash hash table.
+*/
+static void idxHashInit(IdxHash *pHash){
+ memset(pHash, 0, sizeof(IdxHash));
+}
+
+/*
+** Reset an IdxHash hash table.
+*/
+static void idxHashClear(IdxHash *pHash){
+ int i;
+ for(i=0; i<IDX_HASH_SIZE; i++){
+ IdxHashEntry *pEntry;
+ IdxHashEntry *pNext;
+ for(pEntry=pHash->aHash[i]; pEntry; pEntry=pNext){
+ pNext = pEntry->pHashNext;
+ sqlite3_free(pEntry->zVal2);
+ sqlite3_free(pEntry);
+ }
+ }
+ memset(pHash, 0, sizeof(IdxHash));
+}
+
+/*
+** Return the index of the hash bucket that the string specified by the
+** arguments to this function belongs.
+*/
+static int idxHashString(const char *z, int n){
+ unsigned int ret = 0;
+ int i;
+ for(i=0; i<n; i++){
+ ret += (ret<<3) + (unsigned char)(z[i]);
+ }
+ return (int)(ret % IDX_HASH_SIZE);
+}
+
+/*
+** If zKey is already present in the hash table, return non-zero and do
+** nothing. Otherwise, add an entry with key zKey and payload string zVal to
+** the hash table passed as the second argument.
+*/
+static int idxHashAdd(
+ int *pRc,
+ IdxHash *pHash,
+ const char *zKey,
+ const char *zVal
+){
+ int nKey = STRLEN(zKey);
+ int iHash = idxHashString(zKey, nKey);
+ int nVal = (zVal ? STRLEN(zVal) : 0);
+ IdxHashEntry *pEntry;
+ assert( iHash>=0 );
+ for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
+ if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
+ return 1;
+ }
+ }
+ pEntry = idxMalloc(pRc, sizeof(IdxHashEntry) + nKey+1 + nVal+1);
+ if( pEntry ){
+ pEntry->zKey = (char*)&pEntry[1];
+ memcpy(pEntry->zKey, zKey, nKey);
+ if( zVal ){
+ pEntry->zVal = &pEntry->zKey[nKey+1];
+ memcpy(pEntry->zVal, zVal, nVal);
+ }
+ pEntry->pHashNext = pHash->aHash[iHash];
+ pHash->aHash[iHash] = pEntry;
+
+ pEntry->pNext = pHash->pFirst;
+ pHash->pFirst = pEntry;
+ }
+ return 0;
+}
+
+/*
+** If zKey/nKey is present in the hash table, return a pointer to the
+** hash-entry object.
+*/
+static IdxHashEntry *idxHashFind(IdxHash *pHash, const char *zKey, int nKey){
+ int iHash;
+ IdxHashEntry *pEntry;
+ if( nKey<0 ) nKey = STRLEN(zKey);
+ iHash = idxHashString(zKey, nKey);
+ assert( iHash>=0 );
+ for(pEntry=pHash->aHash[iHash]; pEntry; pEntry=pEntry->pHashNext){
+ if( STRLEN(pEntry->zKey)==nKey && 0==memcmp(pEntry->zKey, zKey, nKey) ){
+ return pEntry;
+ }
+ }
+ return 0;
+}
+
+/*
+** If the hash table contains an entry with a key equal to the string
+** passed as the final two arguments to this function, return a pointer
+** to the payload string. Otherwise, if zKey/nKey is not present in the
+** hash table, return NULL.
+*/
+static const char *idxHashSearch(IdxHash *pHash, const char *zKey, int nKey){
+ IdxHashEntry *pEntry = idxHashFind(pHash, zKey, nKey);
+ if( pEntry ) return pEntry->zVal;
+ return 0;
+}
+
+/*
+** Allocate and return a new IdxConstraint object. Set the IdxConstraint.zColl
+** variable to point to a copy of nul-terminated string zColl.
+*/
+static IdxConstraint *idxNewConstraint(int *pRc, const char *zColl){
+ IdxConstraint *pNew;
+ int nColl = STRLEN(zColl);
+
+ assert( *pRc==SQLITE_OK );
+ pNew = (IdxConstraint*)idxMalloc(pRc, sizeof(IdxConstraint) * nColl + 1);
+ if( pNew ){
+ pNew->zColl = (char*)&pNew[1];
+ memcpy(pNew->zColl, zColl, nColl+1);
+ }
+ return pNew;
+}
+
+/*
+** An error associated with database handle db has just occurred. Pass
+** the error message to callback function xOut.
+*/
+static void idxDatabaseError(
+ sqlite3 *db, /* Database handle */
+ char **pzErrmsg /* Write error here */
+){
+ *pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+}
+
+/*
+** Prepare an SQL statement.
+*/
+static int idxPrepareStmt(
+ sqlite3 *db, /* Database handle to compile against */
+ sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */
+ char **pzErrmsg, /* OUT: sqlite3_malloc()ed error message */
+ const char *zSql /* SQL statement to compile */
+){
+ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
+ if( rc!=SQLITE_OK ){
+ *ppStmt = 0;
+ idxDatabaseError(db, pzErrmsg);
+ }
+ return rc;
+}
+
+/*
+** Prepare an SQL statement using the results of a printf() formatting.
+*/
+static int idxPrintfPrepareStmt(
+ sqlite3 *db, /* Database handle to compile against */
+ sqlite3_stmt **ppStmt, /* OUT: Compiled SQL statement */
+ char **pzErrmsg, /* OUT: sqlite3_malloc()ed error message */
+ const char *zFmt, /* printf() format of SQL statement */
+ ... /* Trailing printf() arguments */
+){
+ va_list ap;
+ int rc;
+ char *zSql;
+ va_start(ap, zFmt);
+ zSql = sqlite3_vmprintf(zFmt, ap);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = idxPrepareStmt(db, ppStmt, pzErrmsg, zSql);
+ sqlite3_free(zSql);
+ }
+ va_end(ap);
+ return rc;
+}
+
+
+/*************************************************************************
+** Beginning of virtual table implementation.
+*/
+typedef struct ExpertVtab ExpertVtab;
+struct ExpertVtab {
+ sqlite3_vtab base;
+ IdxTable *pTab;
+ sqlite3expert *pExpert;
+};
+
+typedef struct ExpertCsr ExpertCsr;
+struct ExpertCsr {
+ sqlite3_vtab_cursor base;
+ sqlite3_stmt *pData;
+};
+
+static char *expertDequote(const char *zIn){
+ int n = STRLEN(zIn);
+ char *zRet = sqlite3_malloc(n);
+
+ assert( zIn[0]=='\'' );
+ assert( zIn[n-1]=='\'' );
+
+ if( zRet ){
+ int iOut = 0;
+ int iIn = 0;
+ for(iIn=1; iIn<(n-1); iIn++){
+ if( zIn[iIn]=='\'' ){
+ assert( zIn[iIn+1]=='\'' );
+ iIn++;
+ }
+ zRet[iOut++] = zIn[iIn];
+ }
+ zRet[iOut] = '\0';
+ }
+
+ return zRet;
+}
+
+/*
+** This function is the implementation of both the xConnect and xCreate
+** methods of the r-tree virtual table.
+**
+** argv[0] -> module name
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[...] -> column names...
+*/
+static int expertConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3expert *pExpert = (sqlite3expert*)pAux;
+ ExpertVtab *p = 0;
+ int rc;
+
+ if( argc!=4 ){
+ *pzErr = sqlite3_mprintf("internal error!");
+ rc = SQLITE_ERROR;
+ }else{
+ char *zCreateTable = expertDequote(argv[3]);
+ if( zCreateTable ){
+ rc = sqlite3_declare_vtab(db, zCreateTable);
+ if( rc==SQLITE_OK ){
+ p = idxMalloc(&rc, sizeof(ExpertVtab));
+ }
+ if( rc==SQLITE_OK ){
+ p->pExpert = pExpert;
+ p->pTab = pExpert->pTable;
+ assert( sqlite3_stricmp(p->pTab->zName, argv[2])==0 );
+ }
+ sqlite3_free(zCreateTable);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+
+ *ppVtab = (sqlite3_vtab*)p;
+ return rc;
+}
+
+static int expertDisconnect(sqlite3_vtab *pVtab){
+ ExpertVtab *p = (ExpertVtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+static int expertBestIndex(sqlite3_vtab *pVtab, sqlite3_index_info *pIdxInfo){
+ ExpertVtab *p = (ExpertVtab*)pVtab;
+ int rc = SQLITE_OK;
+ int n = 0;
+ IdxScan *pScan;
+ const int opmask =
+ SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_GT |
+ SQLITE_INDEX_CONSTRAINT_LT | SQLITE_INDEX_CONSTRAINT_GE |
+ SQLITE_INDEX_CONSTRAINT_LE;
+
+ pScan = idxMalloc(&rc, sizeof(IdxScan));
+ if( pScan ){
+ int i;
+
+ /* Link the new scan object into the list */
+ pScan->pTab = p->pTab;
+ pScan->pNextScan = p->pExpert->pScan;
+ p->pExpert->pScan = pScan;
+
+ /* Add the constraints to the IdxScan object */
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i];
+ if( pCons->usable
+ && pCons->iColumn>=0
+ && p->pTab->aCol[pCons->iColumn].iPk==0
+ && (pCons->op & opmask)
+ ){
+ IdxConstraint *pNew;
+ const char *zColl = sqlite3_vtab_collation(pIdxInfo, i);
+ pNew = idxNewConstraint(&rc, zColl);
+ if( pNew ){
+ pNew->iCol = pCons->iColumn;
+ if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ pNew->pNext = pScan->pEq;
+ pScan->pEq = pNew;
+ }else{
+ pNew->bRange = 1;
+ pNew->pNext = pScan->pRange;
+ pScan->pRange = pNew;
+ }
+ }
+ n++;
+ pIdxInfo->aConstraintUsage[i].argvIndex = n;
+ }
+ }
+
+ /* Add the ORDER BY to the IdxScan object */
+ for(i=pIdxInfo->nOrderBy-1; i>=0; i--){
+ int iCol = pIdxInfo->aOrderBy[i].iColumn;
+ if( iCol>=0 ){
+ IdxConstraint *pNew = idxNewConstraint(&rc, p->pTab->aCol[iCol].zColl);
+ if( pNew ){
+ pNew->iCol = iCol;
+ pNew->bDesc = pIdxInfo->aOrderBy[i].desc;
+ pNew->pNext = pScan->pOrder;
+ pNew->pLink = pScan->pOrder;
+ pScan->pOrder = pNew;
+ n++;
+ }
+ }
+ }
+ }
+
+ pIdxInfo->estimatedCost = 1000000.0 / (n+1);
+ return rc;
+}
+
+static int expertUpdate(
+ sqlite3_vtab *pVtab,
+ int nData,
+ sqlite3_value **azData,
+ sqlite_int64 *pRowid
+){
+ (void)pVtab;
+ (void)nData;
+ (void)azData;
+ (void)pRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Virtual table module xOpen method.
+*/
+static int expertOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ int rc = SQLITE_OK;
+ ExpertCsr *pCsr;
+ (void)pVTab;
+ pCsr = idxMalloc(&rc, sizeof(ExpertCsr));
+ *ppCursor = (sqlite3_vtab_cursor*)pCsr;
+ return rc;
+}
+
+/*
+** Virtual table module xClose method.
+*/
+static int expertClose(sqlite3_vtab_cursor *cur){
+ ExpertCsr *pCsr = (ExpertCsr*)cur;
+ sqlite3_finalize(pCsr->pData);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Virtual table module xEof method.
+**
+** Return non-zero if the cursor does not currently point to a valid
+** record (i.e if the scan has finished), or zero otherwise.
+*/
+static int expertEof(sqlite3_vtab_cursor *cur){
+ ExpertCsr *pCsr = (ExpertCsr*)cur;
+ return pCsr->pData==0;
+}
+
+/*
+** Virtual table module xNext method.
+*/
+static int expertNext(sqlite3_vtab_cursor *cur){
+ ExpertCsr *pCsr = (ExpertCsr*)cur;
+ int rc = SQLITE_OK;
+
+ assert( pCsr->pData );
+ rc = sqlite3_step(pCsr->pData);
+ if( rc!=SQLITE_ROW ){
+ rc = sqlite3_finalize(pCsr->pData);
+ pCsr->pData = 0;
+ }else{
+ rc = SQLITE_OK;
+ }
+
+ return rc;
+}
+
+/*
+** Virtual table module xRowid method.
+*/
+static int expertRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ (void)cur;
+ *pRowid = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Virtual table module xColumn method.
+*/
+static int expertColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+ ExpertCsr *pCsr = (ExpertCsr*)cur;
+ sqlite3_value *pVal;
+ pVal = sqlite3_column_value(pCsr->pData, i);
+ if( pVal ){
+ sqlite3_result_value(ctx, pVal);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Virtual table module xFilter method.
+*/
+static int expertFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ ExpertCsr *pCsr = (ExpertCsr*)cur;
+ ExpertVtab *pVtab = (ExpertVtab*)(cur->pVtab);
+ sqlite3expert *pExpert = pVtab->pExpert;
+ int rc;
+
+ (void)idxNum;
+ (void)idxStr;
+ (void)argc;
+ (void)argv;
+ rc = sqlite3_finalize(pCsr->pData);
+ pCsr->pData = 0;
+ if( rc==SQLITE_OK ){
+ rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
+ "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
+ );
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = expertNext(cur);
+ }
+ return rc;
+}
+
+static int idxRegisterVtab(sqlite3expert *p){
+ static sqlite3_module expertModule = {
+ 2, /* iVersion */
+ expertConnect, /* xCreate - create a table */
+ expertConnect, /* xConnect - connect to an existing table */
+ expertBestIndex, /* xBestIndex - Determine search strategy */
+ expertDisconnect, /* xDisconnect - Disconnect from a table */
+ expertDisconnect, /* xDestroy - Drop a table */
+ expertOpen, /* xOpen - open a cursor */
+ expertClose, /* xClose - close a cursor */
+ expertFilter, /* xFilter - configure scan constraints */
+ expertNext, /* xNext - advance a cursor */
+ expertEof, /* xEof */
+ expertColumn, /* xColumn - read data */
+ expertRowid, /* xRowid - read data */
+ expertUpdate, /* xUpdate - write data */
+ 0, /* xBegin - begin transaction */
+ 0, /* xSync - sync transaction */
+ 0, /* xCommit - commit transaction */
+ 0, /* xRollback - rollback transaction */
+ 0, /* xFindFunction - function overloading */
+ 0, /* xRename - rename the table */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ };
+
+ return sqlite3_create_module(p->dbv, "expert", &expertModule, (void*)p);
+}
+/*
+** End of virtual table implementation.
+*************************************************************************/
+/*
+** Finalize SQL statement pStmt. If (*pRc) is SQLITE_OK when this function
+** is called, set it to the return value of sqlite3_finalize() before
+** returning. Otherwise, discard the sqlite3_finalize() return value.
+*/
+static void idxFinalize(int *pRc, sqlite3_stmt *pStmt){
+ int rc = sqlite3_finalize(pStmt);
+ if( *pRc==SQLITE_OK ) *pRc = rc;
+}
+
+/*
+** Attempt to allocate an IdxTable structure corresponding to table zTab
+** in the main database of connection db. If successful, set (*ppOut) to
+** point to the new object and return SQLITE_OK. Otherwise, return an
+** SQLite error code and set (*ppOut) to NULL. In this case *pzErrmsg may be
+** set to point to an error string.
+**
+** It is the responsibility of the caller to eventually free either the
+** IdxTable object or error message using sqlite3_free().
+*/
+static int idxGetTableInfo(
+ sqlite3 *db, /* Database connection to read details from */
+ const char *zTab, /* Table name */
+ IdxTable **ppOut, /* OUT: New object (if successful) */
+ char **pzErrmsg /* OUT: Error message (if not) */
+){
+ sqlite3_stmt *p1 = 0;
+ int nCol = 0;
+ int nTab = STRLEN(zTab);
+ int nByte = sizeof(IdxTable) + nTab + 1;
+ IdxTable *pNew = 0;
+ int rc, rc2;
+ char *pCsr = 0;
+
+ rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
+ const char *zCol = (const char*)sqlite3_column_text(p1, 1);
+ nByte += 1 + STRLEN(zCol);
+ rc = sqlite3_table_column_metadata(
+ db, "main", zTab, zCol, 0, &zCol, 0, 0, 0
+ );
+ nByte += 1 + STRLEN(zCol);
+ nCol++;
+ }
+ rc2 = sqlite3_reset(p1);
+ if( rc==SQLITE_OK ) rc = rc2;
+
+ nByte += sizeof(IdxColumn) * nCol;
+ if( rc==SQLITE_OK ){
+ pNew = idxMalloc(&rc, nByte);
+ }
+ if( rc==SQLITE_OK ){
+ pNew->aCol = (IdxColumn*)&pNew[1];
+ pNew->nCol = nCol;
+ pCsr = (char*)&pNew->aCol[nCol];
+ }
+
+ nCol = 0;
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
+ const char *zCol = (const char*)sqlite3_column_text(p1, 1);
+ int nCopy = STRLEN(zCol) + 1;
+ pNew->aCol[nCol].zName = pCsr;
+ pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5);
+ memcpy(pCsr, zCol, nCopy);
+ pCsr += nCopy;
+
+ rc = sqlite3_table_column_metadata(
+ db, "main", zTab, zCol, 0, &zCol, 0, 0, 0
+ );
+ if( rc==SQLITE_OK ){
+ nCopy = STRLEN(zCol) + 1;
+ pNew->aCol[nCol].zColl = pCsr;
+ memcpy(pCsr, zCol, nCopy);
+ pCsr += nCopy;
+ }
+
+ nCol++;
+ }
+ idxFinalize(&rc, p1);
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }else{
+ pNew->zName = pCsr;
+ memcpy(pNew->zName, zTab, nTab+1);
+ }
+
+ *ppOut = pNew;
+ return rc;
+}
+
+/*
+** This function is a no-op if *pRc is set to anything other than
+** SQLITE_OK when it is called.
+**
+** If *pRc is initially set to SQLITE_OK, then the text specified by
+** the printf() style arguments is appended to zIn and the result returned
+** in a buffer allocated by sqlite3_malloc(). sqlite3_free() is called on
+** zIn before returning.
+*/
+static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
+ va_list ap;
+ char *zAppend = 0;
+ char *zRet = 0;
+ int nIn = zIn ? STRLEN(zIn) : 0;
+ int nAppend = 0;
+ va_start(ap, zFmt);
+ if( *pRc==SQLITE_OK ){
+ zAppend = sqlite3_vmprintf(zFmt, ap);
+ if( zAppend ){
+ nAppend = STRLEN(zAppend);
+ zRet = (char*)sqlite3_malloc(nIn + nAppend + 1);
+ }
+ if( zAppend && zRet ){
+ if( nIn ) memcpy(zRet, zIn, nIn);
+ memcpy(&zRet[nIn], zAppend, nAppend+1);
+ }else{
+ sqlite3_free(zRet);
+ zRet = 0;
+ *pRc = SQLITE_NOMEM;
+ }
+ sqlite3_free(zAppend);
+ sqlite3_free(zIn);
+ }
+ va_end(ap);
+ return zRet;
+}
+
+/*
+** Return true if zId must be quoted in order to use it as an SQL
+** identifier, or false otherwise.
+*/
+static int idxIdentifierRequiresQuotes(const char *zId){
+ int i;
+ for(i=0; zId[i]; i++){
+ if( !(zId[i]=='_')
+ && !(zId[i]>='0' && zId[i]<='9')
+ && !(zId[i]>='a' && zId[i]<='z')
+ && !(zId[i]>='A' && zId[i]<='Z')
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** This function appends an index column definition suitable for constraint
+** pCons to the string passed as zIn and returns the result.
+*/
+static char *idxAppendColDefn(
+ int *pRc, /* IN/OUT: Error code */
+ char *zIn, /* Column defn accumulated so far */
+ IdxTable *pTab, /* Table index will be created on */
+ IdxConstraint *pCons
+){
+ char *zRet = zIn;
+ IdxColumn *p = &pTab->aCol[pCons->iCol];
+ if( zRet ) zRet = idxAppendText(pRc, zRet, ", ");
+
+ if( idxIdentifierRequiresQuotes(p->zName) ){
+ zRet = idxAppendText(pRc, zRet, "%Q", p->zName);
+ }else{
+ zRet = idxAppendText(pRc, zRet, "%s", p->zName);
+ }
+
+ if( sqlite3_stricmp(p->zColl, pCons->zColl) ){
+ if( idxIdentifierRequiresQuotes(pCons->zColl) ){
+ zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl);
+ }else{
+ zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl);
+ }
+ }
+
+ if( pCons->bDesc ){
+ zRet = idxAppendText(pRc, zRet, " DESC");
+ }
+ return zRet;
+}
+
+/*
+** Search database dbm for an index compatible with the one idxCreateFromCons()
+** would create from arguments pScan, pEq and pTail. If no error occurs and
+** such an index is found, return non-zero. Or, if no such index is found,
+** return zero.
+**
+** If an error occurs, set *pRc to an SQLite error code and return zero.
+*/
+static int idxFindCompatible(
+ int *pRc, /* OUT: Error code */
+ sqlite3* dbm, /* Database to search */
+ IdxScan *pScan, /* Scan for table to search for index on */
+ IdxConstraint *pEq, /* List of == constraints */
+ IdxConstraint *pTail /* List of range constraints */
+){
+ const char *zTbl = pScan->pTab->zName;
+ sqlite3_stmt *pIdxList = 0;
+ IdxConstraint *pIter;
+ int nEq = 0; /* Number of elements in pEq */
+ int rc;
+
+ /* Count the elements in list pEq */
+ for(pIter=pEq; pIter; pIter=pIter->pLink) nEq++;
+
+ rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl);
+ while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){
+ int bMatch = 1;
+ IdxConstraint *pT = pTail;
+ sqlite3_stmt *pInfo = 0;
+ const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1);
+
+ /* Zero the IdxConstraint.bFlag values in the pEq list */
+ for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0;
+
+ rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx);
+ while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){
+ int iIdx = sqlite3_column_int(pInfo, 0);
+ int iCol = sqlite3_column_int(pInfo, 1);
+ const char *zColl = (const char*)sqlite3_column_text(pInfo, 4);
+
+ if( iIdx<nEq ){
+ for(pIter=pEq; pIter; pIter=pIter->pLink){
+ if( pIter->bFlag ) continue;
+ if( pIter->iCol!=iCol ) continue;
+ if( sqlite3_stricmp(pIter->zColl, zColl) ) continue;
+ pIter->bFlag = 1;
+ break;
+ }
+ if( pIter==0 ){
+ bMatch = 0;
+ break;
+ }
+ }else{
+ if( pT ){
+ if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){
+ bMatch = 0;
+ break;
+ }
+ pT = pT->pLink;
+ }
+ }
+ }
+ idxFinalize(&rc, pInfo);
+
+ if( rc==SQLITE_OK && bMatch ){
+ sqlite3_finalize(pIdxList);
+ return 1;
+ }
+ }
+ idxFinalize(&rc, pIdxList);
+
+ *pRc = rc;
+ return 0;
+}
+
+static int idxCreateFromCons(
+ sqlite3expert *p,
+ IdxScan *pScan,
+ IdxConstraint *pEq,
+ IdxConstraint *pTail
+){
+ sqlite3 *dbm = p->dbm;
+ int rc = SQLITE_OK;
+ if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
+ IdxTable *pTab = pScan->pTab;
+ char *zCols = 0;
+ char *zIdx = 0;
+ IdxConstraint *pCons;
+ unsigned int h = 0;
+ const char *zFmt;
+
+ for(pCons=pEq; pCons; pCons=pCons->pLink){
+ zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
+ }
+ for(pCons=pTail; pCons; pCons=pCons->pLink){
+ zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
+ }
+
+ if( rc==SQLITE_OK ){
+ /* Hash the list of columns to come up with a name for the index */
+ const char *zTable = pScan->pTab->zName;
+ char *zName; /* Index name */
+ int i;
+ for(i=0; zCols[i]; i++){
+ h += ((h<<3) + zCols[i]);
+ }
+ zName = sqlite3_mprintf("%s_idx_%08x", zTable, h);
+ if( zName==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ if( idxIdentifierRequiresQuotes(zTable) ){
+ zFmt = "CREATE INDEX '%q' ON %Q(%s)";
+ }else{
+ zFmt = "CREATE INDEX %s ON %s(%s)";
+ }
+ zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols);
+ if( !zIdx ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg);
+ idxHashAdd(&rc, &p->hIdx, zName, zIdx);
+ }
+ sqlite3_free(zName);
+ sqlite3_free(zIdx);
+ }
+ }
+
+ sqlite3_free(zCols);
+ }
+ return rc;
+}
+
+/*
+** Return true if list pList (linked by IdxConstraint.pLink) contains
+** a constraint compatible with *p. Otherwise return false.
+*/
+static int idxFindConstraint(IdxConstraint *pList, IdxConstraint *p){
+ IdxConstraint *pCmp;
+ for(pCmp=pList; pCmp; pCmp=pCmp->pLink){
+ if( p->iCol==pCmp->iCol ) return 1;
+ }
+ return 0;
+}
+
+static int idxCreateFromWhere(
+ sqlite3expert *p,
+ IdxScan *pScan, /* Create indexes for this scan */
+ IdxConstraint *pTail /* range/ORDER BY constraints for inclusion */
+){
+ IdxConstraint *p1 = 0;
+ IdxConstraint *pCon;
+ int rc;
+
+ /* Gather up all the == constraints. */
+ for(pCon=pScan->pEq; pCon; pCon=pCon->pNext){
+ if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
+ pCon->pLink = p1;
+ p1 = pCon;
+ }
+ }
+
+ /* Create an index using the == constraints collected above. And the
+ ** range constraint/ORDER BY terms passed in by the caller, if any. */
+ rc = idxCreateFromCons(p, pScan, p1, pTail);
+
+ /* If no range/ORDER BY passed by the caller, create a version of the
+ ** index for each range constraint. */
+ if( pTail==0 ){
+ for(pCon=pScan->pRange; rc==SQLITE_OK && pCon; pCon=pCon->pNext){
+ assert( pCon->pLink==0 );
+ if( !idxFindConstraint(p1, pCon) && !idxFindConstraint(pTail, pCon) ){
+ rc = idxCreateFromCons(p, pScan, p1, pCon);
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Create candidate indexes in database [dbm] based on the data in
+** linked-list pScan.
+*/
+static int idxCreateCandidates(sqlite3expert *p){
+ int rc = SQLITE_OK;
+ IdxScan *pIter;
+
+ for(pIter=p->pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
+ rc = idxCreateFromWhere(p, pIter, 0);
+ if( rc==SQLITE_OK && pIter->pOrder ){
+ rc = idxCreateFromWhere(p, pIter, pIter->pOrder);
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Free all elements of the linked list starting at pConstraint.
+*/
+static void idxConstraintFree(IdxConstraint *pConstraint){
+ IdxConstraint *pNext;
+ IdxConstraint *p;
+
+ for(p=pConstraint; p; p=pNext){
+ pNext = p->pNext;
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Free all elements of the linked list starting from pScan up until pLast
+** (pLast is not freed).
+*/
+static void idxScanFree(IdxScan *pScan, IdxScan *pLast){
+ IdxScan *p;
+ IdxScan *pNext;
+ for(p=pScan; p!=pLast; p=pNext){
+ pNext = p->pNextScan;
+ idxConstraintFree(p->pOrder);
+ idxConstraintFree(p->pEq);
+ idxConstraintFree(p->pRange);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Free all elements of the linked list starting from pStatement up
+** until pLast (pLast is not freed).
+*/
+static void idxStatementFree(IdxStatement *pStatement, IdxStatement *pLast){
+ IdxStatement *p;
+ IdxStatement *pNext;
+ for(p=pStatement; p!=pLast; p=pNext){
+ pNext = p->pNext;
+ sqlite3_free(p->zEQP);
+ sqlite3_free(p->zIdx);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Free the linked list of IdxTable objects starting at pTab.
+*/
+static void idxTableFree(IdxTable *pTab){
+ IdxTable *pIter;
+ IdxTable *pNext;
+ for(pIter=pTab; pIter; pIter=pNext){
+ pNext = pIter->pNext;
+ sqlite3_free(pIter);
+ }
+}
+
+/*
+** Free the linked list of IdxWrite objects starting at pTab.
+*/
+static void idxWriteFree(IdxWrite *pTab){
+ IdxWrite *pIter;
+ IdxWrite *pNext;
+ for(pIter=pTab; pIter; pIter=pNext){
+ pNext = pIter->pNext;
+ sqlite3_free(pIter);
+ }
+}
+
+
+
+/*
+** This function is called after candidate indexes have been created. It
+** runs all the queries to see which indexes they prefer, and populates
+** IdxStatement.zIdx and IdxStatement.zEQP with the results.
+*/
+int idxFindIndexes(
+ sqlite3expert *p,
+ char **pzErr /* OUT: Error message (sqlite3_malloc) */
+){
+ IdxStatement *pStmt;
+ sqlite3 *dbm = p->dbm;
+ int rc = SQLITE_OK;
+
+ IdxHash hIdx;
+ idxHashInit(&hIdx);
+
+ for(pStmt=p->pStatement; rc==SQLITE_OK && pStmt; pStmt=pStmt->pNext){
+ IdxHashEntry *pEntry;
+ sqlite3_stmt *pExplain = 0;
+ idxHashClear(&hIdx);
+ rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr,
+ "EXPLAIN QUERY PLAN %s", pStmt->zSql
+ );
+ while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){
+ /* int iId = sqlite3_column_int(pExplain, 0); */
+ /* int iParent = sqlite3_column_int(pExplain, 1); */
+ /* int iNotUsed = sqlite3_column_int(pExplain, 2); */
+ const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3);
+ int nDetail;
+ int i;
+
+ if( !zDetail ) continue;
+ nDetail = STRLEN(zDetail);
+
+ for(i=0; i<nDetail; i++){
+ const char *zIdx = 0;
+ if( i+13<nDetail && memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){
+ zIdx = &zDetail[i+13];
+ }else if( i+22<nDetail
+ && memcmp(&zDetail[i], " USING COVERING INDEX ", 22)==0
+ ){
+ zIdx = &zDetail[i+22];
+ }
+ if( zIdx ){
+ const char *zSql;
+ int nIdx = 0;
+ while( zIdx[nIdx]!='\0' && (zIdx[nIdx]!=' ' || zIdx[nIdx+1]!='(') ){
+ nIdx++;
+ }
+ zSql = idxHashSearch(&p->hIdx, zIdx, nIdx);
+ if( zSql ){
+ idxHashAdd(&rc, &hIdx, zSql, 0);
+ if( rc ) goto find_indexes_out;
+ }
+ break;
+ }
+ }
+
+ if( zDetail[0]!='-' ){
+ pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail);
+ }
+ }
+
+ for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
+ pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey);
+ }
+
+ idxFinalize(&rc, pExplain);
+ }
+
+ find_indexes_out:
+ idxHashClear(&hIdx);
+ return rc;
+}
+
+static int idxAuthCallback(
+ void *pCtx,
+ int eOp,
+ const char *z3,
+ const char *z4,
+ const char *zDb,
+ const char *zTrigger
+){
+ int rc = SQLITE_OK;
+ (void)z4;
+ (void)zTrigger;
+ if( eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE || eOp==SQLITE_DELETE ){
+ if( sqlite3_stricmp(zDb, "main")==0 ){
+ sqlite3expert *p = (sqlite3expert*)pCtx;
+ IdxTable *pTab;
+ for(pTab=p->pTable; pTab; pTab=pTab->pNext){
+ if( 0==sqlite3_stricmp(z3, pTab->zName) ) break;
+ }
+ if( pTab ){
+ IdxWrite *pWrite;
+ for(pWrite=p->pWrite; pWrite; pWrite=pWrite->pNext){
+ if( pWrite->pTab==pTab && pWrite->eOp==eOp ) break;
+ }
+ if( pWrite==0 ){
+ pWrite = idxMalloc(&rc, sizeof(IdxWrite));
+ if( rc==SQLITE_OK ){
+ pWrite->pTab = pTab;
+ pWrite->eOp = eOp;
+ pWrite->pNext = p->pWrite;
+ p->pWrite = pWrite;
+ }
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+static int idxProcessOneTrigger(
+ sqlite3expert *p,
+ IdxWrite *pWrite,
+ char **pzErr
+){
+ static const char *zInt = UNIQUE_TABLE_NAME;
+ static const char *zDrop = "DROP TABLE " UNIQUE_TABLE_NAME;
+ IdxTable *pTab = pWrite->pTab;
+ const char *zTab = pTab->zName;
+ const char *zSql =
+ "SELECT 'CREATE TEMP' || substr(sql, 7) FROM sqlite_schema "
+ "WHERE tbl_name = %Q AND type IN ('table', 'trigger') "
+ "ORDER BY type;";
+ sqlite3_stmt *pSelect = 0;
+ int rc = SQLITE_OK;
+ char *zWrite = 0;
+
+ /* Create the table and its triggers in the temp schema */
+ rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab);
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){
+ const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0);
+ rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr);
+ }
+ idxFinalize(&rc, pSelect);
+
+ /* Rename the table in the temp schema to zInt */
+ if( rc==SQLITE_OK ){
+ char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt);
+ if( z==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_exec(p->dbv, z, 0, 0, pzErr);
+ sqlite3_free(z);
+ }
+ }
+
+ switch( pWrite->eOp ){
+ case SQLITE_INSERT: {
+ int i;
+ zWrite = idxAppendText(&rc, zWrite, "INSERT INTO %Q VALUES(", zInt);
+ for(i=0; i<pTab->nCol; i++){
+ zWrite = idxAppendText(&rc, zWrite, "%s?", i==0 ? "" : ", ");
+ }
+ zWrite = idxAppendText(&rc, zWrite, ")");
+ break;
+ }
+ case SQLITE_UPDATE: {
+ int i;
+ zWrite = idxAppendText(&rc, zWrite, "UPDATE %Q SET ", zInt);
+ for(i=0; i<pTab->nCol; i++){
+ zWrite = idxAppendText(&rc, zWrite, "%s%Q=?", i==0 ? "" : ", ",
+ pTab->aCol[i].zName
+ );
+ }
+ break;
+ }
+ default: {
+ assert( pWrite->eOp==SQLITE_DELETE );
+ if( rc==SQLITE_OK ){
+ zWrite = sqlite3_mprintf("DELETE FROM %Q", zInt);
+ if( zWrite==0 ) rc = SQLITE_NOMEM;
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3_stmt *pX = 0;
+ rc = sqlite3_prepare_v2(p->dbv, zWrite, -1, &pX, 0);
+ idxFinalize(&rc, pX);
+ if( rc!=SQLITE_OK ){
+ idxDatabaseError(p->dbv, pzErr);
+ }
+ }
+ sqlite3_free(zWrite);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(p->dbv, zDrop, 0, 0, pzErr);
+ }
+
+ return rc;
+}
+
+static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
+ int rc = SQLITE_OK;
+ IdxWrite *pEnd = 0;
+ IdxWrite *pFirst = p->pWrite;
+
+ while( rc==SQLITE_OK && pFirst!=pEnd ){
+ IdxWrite *pIter;
+ for(pIter=pFirst; rc==SQLITE_OK && pIter!=pEnd; pIter=pIter->pNext){
+ rc = idxProcessOneTrigger(p, pIter, pzErr);
+ }
+ pEnd = pFirst;
+ pFirst = p->pWrite;
+ }
+
+ return rc;
+}
+
+
+static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
+ int rc = idxRegisterVtab(p);
+ sqlite3_stmt *pSchema = 0;
+
+ /* For each table in the main db schema:
+ **
+ ** 1) Add an entry to the p->pTable list, and
+ ** 2) Create the equivalent virtual table in dbv.
+ */
+ rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
+ "SELECT type, name, sql, 1 FROM sqlite_schema "
+ "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
+ " UNION ALL "
+ "SELECT type, name, sql, 2 FROM sqlite_schema "
+ "WHERE type = 'trigger'"
+ " AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
+ "ORDER BY 4, 1"
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
+ const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
+ const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
+ const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
+
+ if( zType[0]=='v' || zType[1]=='r' ){
+ rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
+ }else{
+ IdxTable *pTab;
+ rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
+ if( rc==SQLITE_OK ){
+ int i;
+ char *zInner = 0;
+ char *zOuter = 0;
+ pTab->pNext = p->pTable;
+ p->pTable = pTab;
+
+ /* The statement the vtab will pass to sqlite3_declare_vtab() */
+ zInner = idxAppendText(&rc, 0, "CREATE TABLE x(");
+ for(i=0; i<pTab->nCol; i++){
+ zInner = idxAppendText(&rc, zInner, "%s%Q COLLATE %s",
+ (i==0 ? "" : ", "), pTab->aCol[i].zName, pTab->aCol[i].zColl
+ );
+ }
+ zInner = idxAppendText(&rc, zInner, ")");
+
+ /* The CVT statement to create the vtab */
+ zOuter = idxAppendText(&rc, 0,
+ "CREATE VIRTUAL TABLE %Q USING expert(%Q)", zName, zInner
+ );
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(p->dbv, zOuter, 0, 0, pzErrmsg);
+ }
+ sqlite3_free(zInner);
+ sqlite3_free(zOuter);
+ }
+ }
+ }
+ idxFinalize(&rc, pSchema);
+ return rc;
+}
+
+struct IdxSampleCtx {
+ int iTarget;
+ double target; /* Target nRet/nRow value */
+ double nRow; /* Number of rows seen */
+ double nRet; /* Number of rows returned */
+};
+
+static void idxSampleFunc(
+ sqlite3_context *pCtx,
+ int argc,
+ sqlite3_value **argv
+){
+ struct IdxSampleCtx *p = (struct IdxSampleCtx*)sqlite3_user_data(pCtx);
+ int bRet;
+
+ (void)argv;
+ assert( argc==0 );
+ if( p->nRow==0.0 ){
+ bRet = 1;
+ }else{
+ bRet = (p->nRet / p->nRow) <= p->target;
+ if( bRet==0 ){
+ unsigned short rnd;
+ sqlite3_randomness(2, (void*)&rnd);
+ bRet = ((int)rnd % 100) <= p->iTarget;
+ }
+ }
+
+ sqlite3_result_int(pCtx, bRet);
+ p->nRow += 1.0;
+ p->nRet += (double)bRet;
+}
+
+struct IdxRemCtx {
+ int nSlot;
+ struct IdxRemSlot {
+ int eType; /* SQLITE_NULL, INTEGER, REAL, TEXT, BLOB */
+ i64 iVal; /* SQLITE_INTEGER value */
+ double rVal; /* SQLITE_FLOAT value */
+ int nByte; /* Bytes of space allocated at z */
+ int n; /* Size of buffer z */
+ char *z; /* SQLITE_TEXT/BLOB value */
+ } aSlot[1];
+};
+
+/*
+** Implementation of scalar function rem().
+*/
+static void idxRemFunc(
+ sqlite3_context *pCtx,
+ int argc,
+ sqlite3_value **argv
+){
+ struct IdxRemCtx *p = (struct IdxRemCtx*)sqlite3_user_data(pCtx);
+ struct IdxRemSlot *pSlot;
+ int iSlot;
+ assert( argc==2 );
+
+ iSlot = sqlite3_value_int(argv[0]);
+ assert( iSlot<=p->nSlot );
+ pSlot = &p->aSlot[iSlot];
+
+ switch( pSlot->eType ){
+ case SQLITE_NULL:
+ /* no-op */
+ break;
+
+ case SQLITE_INTEGER:
+ sqlite3_result_int64(pCtx, pSlot->iVal);
+ break;
+
+ case SQLITE_FLOAT:
+ sqlite3_result_double(pCtx, pSlot->rVal);
+ break;
+
+ case SQLITE_BLOB:
+ sqlite3_result_blob(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
+ break;
+
+ case SQLITE_TEXT:
+ sqlite3_result_text(pCtx, pSlot->z, pSlot->n, SQLITE_TRANSIENT);
+ break;
+ }
+
+ pSlot->eType = sqlite3_value_type(argv[1]);
+ switch( pSlot->eType ){
+ case SQLITE_NULL:
+ /* no-op */
+ break;
+
+ case SQLITE_INTEGER:
+ pSlot->iVal = sqlite3_value_int64(argv[1]);
+ break;
+
+ case SQLITE_FLOAT:
+ pSlot->rVal = sqlite3_value_double(argv[1]);
+ break;
+
+ case SQLITE_BLOB:
+ case SQLITE_TEXT: {
+ int nByte = sqlite3_value_bytes(argv[1]);
+ if( nByte>pSlot->nByte ){
+ char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2);
+ if( zNew==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+ pSlot->nByte = nByte*2;
+ pSlot->z = zNew;
+ }
+ pSlot->n = nByte;
+ if( pSlot->eType==SQLITE_BLOB ){
+ memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte);
+ }else{
+ memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte);
+ }
+ break;
+ }
+ }
+}
+
+static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){
+ int rc = SQLITE_OK;
+ const char *zMax =
+ "SELECT max(i.seqno) FROM "
+ " sqlite_schema AS s, "
+ " pragma_index_list(s.name) AS l, "
+ " pragma_index_info(l.name) AS i "
+ "WHERE s.type = 'table'";
+ sqlite3_stmt *pMax = 0;
+
+ *pnMax = 0;
+ rc = idxPrepareStmt(db, &pMax, pzErr, zMax);
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){
+ *pnMax = sqlite3_column_int(pMax, 0) + 1;
+ }
+ idxFinalize(&rc, pMax);
+
+ return rc;
+}
+
+static int idxPopulateOneStat1(
+ sqlite3expert *p,
+ sqlite3_stmt *pIndexXInfo,
+ sqlite3_stmt *pWriteStat,
+ const char *zTab,
+ const char *zIdx,
+ char **pzErr
+){
+ char *zCols = 0;
+ char *zOrder = 0;
+ char *zQuery = 0;
+ int nCol = 0;
+ int i;
+ sqlite3_stmt *pQuery = 0;
+ int *aStat = 0;
+ int rc = SQLITE_OK;
+
+ assert( p->iSample>0 );
+
+ /* Formulate the query text */
+ sqlite3_bind_text(pIndexXInfo, 1, zIdx, -1, SQLITE_STATIC);
+ while( SQLITE_OK==rc && SQLITE_ROW==sqlite3_step(pIndexXInfo) ){
+ const char *zComma = zCols==0 ? "" : ", ";
+ const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
+ const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
+ zCols = idxAppendText(&rc, zCols,
+ "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
+ );
+ zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
+ }
+ sqlite3_reset(pIndexXInfo);
+ if( rc==SQLITE_OK ){
+ if( p->iSample==100 ){
+ zQuery = sqlite3_mprintf(
+ "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder
+ );
+ }else{
+ zQuery = sqlite3_mprintf(
+ "SELECT %s FROM temp."UNIQUE_TABLE_NAME" x ORDER BY %s", zCols, zOrder
+ );
+ }
+ }
+ sqlite3_free(zCols);
+ sqlite3_free(zOrder);
+
+ /* Formulate the query text */
+ if( rc==SQLITE_OK ){
+ sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
+ rc = idxPrepareStmt(dbrem, &pQuery, pzErr, zQuery);
+ }
+ sqlite3_free(zQuery);
+
+ if( rc==SQLITE_OK ){
+ aStat = (int*)idxMalloc(&rc, sizeof(int)*(nCol+1));
+ }
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
+ IdxHashEntry *pEntry;
+ char *zStat = 0;
+ for(i=0; i<=nCol; i++) aStat[i] = 1;
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pQuery) ){
+ aStat[0]++;
+ for(i=0; i<nCol; i++){
+ if( sqlite3_column_int(pQuery, i)==0 ) break;
+ }
+ for(/*no-op*/; i<nCol; i++){
+ aStat[i+1]++;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ int s0 = aStat[0];
+ zStat = sqlite3_mprintf("%d", s0);
+ if( zStat==0 ) rc = SQLITE_NOMEM;
+ for(i=1; rc==SQLITE_OK && i<=nCol; i++){
+ zStat = idxAppendText(&rc, zStat, " %d", (s0+aStat[i]/2) / aStat[i]);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pWriteStat, 1, zTab, -1, SQLITE_STATIC);
+ sqlite3_bind_text(pWriteStat, 2, zIdx, -1, SQLITE_STATIC);
+ sqlite3_bind_text(pWriteStat, 3, zStat, -1, SQLITE_STATIC);
+ sqlite3_step(pWriteStat);
+ rc = sqlite3_reset(pWriteStat);
+ }
+
+ pEntry = idxHashFind(&p->hIdx, zIdx, STRLEN(zIdx));
+ if( pEntry ){
+ assert( pEntry->zVal2==0 );
+ pEntry->zVal2 = zStat;
+ }else{
+ sqlite3_free(zStat);
+ }
+ }
+ sqlite3_free(aStat);
+ idxFinalize(&rc, pQuery);
+
+ return rc;
+}
+
+static int idxBuildSampleTable(sqlite3expert *p, const char *zTab){
+ int rc;
+ char *zSql;
+
+ rc = sqlite3_exec(p->dbv,"DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
+ if( rc!=SQLITE_OK ) return rc;
+
+ zSql = sqlite3_mprintf(
+ "CREATE TABLE temp." UNIQUE_TABLE_NAME " AS SELECT * FROM %Q", zTab
+ );
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_exec(p->dbv, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+
+ return rc;
+}
+
+/*
+** This function is called as part of sqlite3_expert_analyze(). Candidate
+** indexes have already been created in database sqlite3expert.dbm, this
+** function populates sqlite_stat1 table in the same database.
+**
+** The stat1 data is generated by querying the
+*/
+static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
+ int rc = SQLITE_OK;
+ int nMax =0;
+ struct IdxRemCtx *pCtx = 0;
+ struct IdxSampleCtx samplectx;
+ int i;
+ i64 iPrev = -100000;
+ sqlite3_stmt *pAllIndex = 0;
+ sqlite3_stmt *pIndexXInfo = 0;
+ sqlite3_stmt *pWrite = 0;
+
+ const char *zAllIndex =
+ "SELECT s.rowid, s.name, l.name FROM "
+ " sqlite_schema AS s, "
+ " pragma_index_list(s.name) AS l "
+ "WHERE s.type = 'table'";
+ const char *zIndexXInfo =
+ "SELECT name, coll FROM pragma_index_xinfo(?) WHERE key";
+ const char *zWrite = "INSERT INTO sqlite_stat1 VALUES(?, ?, ?)";
+
+ /* If iSample==0, no sqlite_stat1 data is required. */
+ if( p->iSample==0 ) return SQLITE_OK;
+
+ rc = idxLargestIndex(p->dbm, &nMax, pzErr);
+ if( nMax<=0 || rc!=SQLITE_OK ) return rc;
+
+ rc = sqlite3_exec(p->dbm, "ANALYZE; PRAGMA writable_schema=1", 0, 0, 0);
+
+ if( rc==SQLITE_OK ){
+ int nByte = sizeof(struct IdxRemCtx) + (sizeof(struct IdxRemSlot) * nMax);
+ pCtx = (struct IdxRemCtx*)idxMalloc(&rc, nByte);
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
+ rc = sqlite3_create_function(
+ dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
+ );
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(
+ p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
+ );
+ }
+
+ if( rc==SQLITE_OK ){
+ pCtx->nSlot = nMax+1;
+ rc = idxPrepareStmt(p->dbm, &pAllIndex, pzErr, zAllIndex);
+ }
+ if( rc==SQLITE_OK ){
+ rc = idxPrepareStmt(p->dbm, &pIndexXInfo, pzErr, zIndexXInfo);
+ }
+ if( rc==SQLITE_OK ){
+ rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite);
+ }
+
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){
+ i64 iRowid = sqlite3_column_int64(pAllIndex, 0);
+ const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1);
+ const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2);
+ if( p->iSample<100 && iPrev!=iRowid ){
+ samplectx.target = (double)p->iSample / 100.0;
+ samplectx.iTarget = p->iSample;
+ samplectx.nRow = 0.0;
+ samplectx.nRet = 0.0;
+ rc = idxBuildSampleTable(p, zTab);
+ if( rc!=SQLITE_OK ) break;
+ }
+ rc = idxPopulateOneStat1(p, pIndexXInfo, pWrite, zTab, zIdx, pzErr);
+ iPrev = iRowid;
+ }
+ if( rc==SQLITE_OK && p->iSample<100 ){
+ rc = sqlite3_exec(p->dbv,
+ "DROP TABLE IF EXISTS temp." UNIQUE_TABLE_NAME, 0,0,0
+ );
+ }
+
+ idxFinalize(&rc, pAllIndex);
+ idxFinalize(&rc, pIndexXInfo);
+ idxFinalize(&rc, pWrite);
+
+ for(i=0; i<pCtx->nSlot; i++){
+ sqlite3_free(pCtx->aSlot[i].z);
+ }
+ sqlite3_free(pCtx);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
+ }
+
+ sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
+ return rc;
+}
+
+/*
+** Allocate a new sqlite3expert object.
+*/
+sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
+ int rc = SQLITE_OK;
+ sqlite3expert *pNew;
+
+ pNew = (sqlite3expert*)idxMalloc(&rc, sizeof(sqlite3expert));
+
+ /* Open two in-memory databases to work with. The "vtab database" (dbv)
+ ** will contain a virtual table corresponding to each real table in
+ ** the user database schema, and a copy of each view. It is used to
+ ** collect information regarding the WHERE, ORDER BY and other clauses
+ ** of the user's query.
+ */
+ if( rc==SQLITE_OK ){
+ pNew->db = db;
+ pNew->iSample = 100;
+ rc = sqlite3_open(":memory:", &pNew->dbv);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_open(":memory:", &pNew->dbm);
+ if( rc==SQLITE_OK ){
+ sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0);
+ }
+ }
+
+
+ /* Copy the entire schema of database [db] into [dbm]. */
+ if( rc==SQLITE_OK ){
+ sqlite3_stmt *pSql;
+ rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
+ "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
+ " AND sql NOT LIKE 'CREATE VIRTUAL %%'"
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+ const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
+ rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
+ }
+ idxFinalize(&rc, pSql);
+ }
+
+ /* Create the vtab schema */
+ if( rc==SQLITE_OK ){
+ rc = idxCreateVtabSchema(pNew, pzErrmsg);
+ }
+
+ /* Register the auth callback with dbv */
+ if( rc==SQLITE_OK ){
+ sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
+ }
+
+ /* If an error has occurred, free the new object and reutrn NULL. Otherwise,
+ ** return the new sqlite3expert handle. */
+ if( rc!=SQLITE_OK ){
+ sqlite3_expert_destroy(pNew);
+ pNew = 0;
+ }
+ return pNew;
+}
+
+/*
+** Configure an sqlite3expert object.
+*/
+int sqlite3_expert_config(sqlite3expert *p, int op, ...){
+ int rc = SQLITE_OK;
+ va_list ap;
+ va_start(ap, op);
+ switch( op ){
+ case EXPERT_CONFIG_SAMPLE: {
+ int iVal = va_arg(ap, int);
+ if( iVal<0 ) iVal = 0;
+ if( iVal>100 ) iVal = 100;
+ p->iSample = iVal;
+ break;
+ }
+ default:
+ rc = SQLITE_NOTFOUND;
+ break;
+ }
+
+ va_end(ap);
+ return rc;
+}
+
+/*
+** Add an SQL statement to the analysis.
+*/
+int sqlite3_expert_sql(
+ sqlite3expert *p, /* From sqlite3_expert_new() */
+ const char *zSql, /* SQL statement to add */
+ char **pzErr /* OUT: Error message (if any) */
+){
+ IdxScan *pScanOrig = p->pScan;
+ IdxStatement *pStmtOrig = p->pStatement;
+ int rc = SQLITE_OK;
+ const char *zStmt = zSql;
+
+ if( p->bRun ) return SQLITE_MISUSE;
+
+ while( rc==SQLITE_OK && zStmt && zStmt[0] ){
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(p->dbv, zStmt, -1, &pStmt, &zStmt);
+ if( rc==SQLITE_OK ){
+ if( pStmt ){
+ IdxStatement *pNew;
+ const char *z = sqlite3_sql(pStmt);
+ int n = STRLEN(z);
+ pNew = (IdxStatement*)idxMalloc(&rc, sizeof(IdxStatement) + n+1);
+ if( rc==SQLITE_OK ){
+ pNew->zSql = (char*)&pNew[1];
+ memcpy(pNew->zSql, z, n+1);
+ pNew->pNext = p->pStatement;
+ if( p->pStatement ) pNew->iId = p->pStatement->iId+1;
+ p->pStatement = pNew;
+ }
+ sqlite3_finalize(pStmt);
+ }
+ }else{
+ idxDatabaseError(p->dbv, pzErr);
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ idxScanFree(p->pScan, pScanOrig);
+ idxStatementFree(p->pStatement, pStmtOrig);
+ p->pScan = pScanOrig;
+ p->pStatement = pStmtOrig;
+ }
+
+ return rc;
+}
+
+int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr){
+ int rc;
+ IdxHashEntry *pEntry;
+
+ /* Do trigger processing to collect any extra IdxScan structures */
+ rc = idxProcessTriggers(p, pzErr);
+
+ /* Create candidate indexes within the in-memory database file */
+ if( rc==SQLITE_OK ){
+ rc = idxCreateCandidates(p);
+ }
+
+ /* Generate the stat1 data */
+ if( rc==SQLITE_OK ){
+ rc = idxPopulateStat1(p, pzErr);
+ }
+
+ /* Formulate the EXPERT_REPORT_CANDIDATES text */
+ for(pEntry=p->hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
+ p->zCandidates = idxAppendText(&rc, p->zCandidates,
+ "%s;%s%s\n", pEntry->zVal,
+ pEntry->zVal2 ? " -- stat1: " : "", pEntry->zVal2
+ );
+ }
+
+ /* Figure out which of the candidate indexes are preferred by the query
+ ** planner and report the results to the user. */
+ if( rc==SQLITE_OK ){
+ rc = idxFindIndexes(p, pzErr);
+ }
+
+ if( rc==SQLITE_OK ){
+ p->bRun = 1;
+ }
+ return rc;
+}
+
+/*
+** Return the total number of statements that have been added to this
+** sqlite3expert using sqlite3_expert_sql().
+*/
+int sqlite3_expert_count(sqlite3expert *p){
+ int nRet = 0;
+ if( p->pStatement ) nRet = p->pStatement->iId+1;
+ return nRet;
+}
+
+/*
+** Return a component of the report.
+*/
+const char *sqlite3_expert_report(sqlite3expert *p, int iStmt, int eReport){
+ const char *zRet = 0;
+ IdxStatement *pStmt;
+
+ if( p->bRun==0 ) return 0;
+ for(pStmt=p->pStatement; pStmt && pStmt->iId!=iStmt; pStmt=pStmt->pNext);
+ switch( eReport ){
+ case EXPERT_REPORT_SQL:
+ if( pStmt ) zRet = pStmt->zSql;
+ break;
+ case EXPERT_REPORT_INDEXES:
+ if( pStmt ) zRet = pStmt->zIdx;
+ break;
+ case EXPERT_REPORT_PLAN:
+ if( pStmt ) zRet = pStmt->zEQP;
+ break;
+ case EXPERT_REPORT_CANDIDATES:
+ zRet = p->zCandidates;
+ break;
+ }
+ return zRet;
+}
+
+/*
+** Free an sqlite3expert object.
+*/
+void sqlite3_expert_destroy(sqlite3expert *p){
+ if( p ){
+ sqlite3_close(p->dbm);
+ sqlite3_close(p->dbv);
+ idxScanFree(p->pScan, 0);
+ idxStatementFree(p->pStatement, 0);
+ idxTableFree(p->pTable);
+ idxWriteFree(p->pWrite);
+ idxHashClear(&p->hIdx);
+ sqlite3_free(p->zCandidates);
+ sqlite3_free(p);
+ }
+}
+
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
+/************************* End ../ext/expert/sqlite3expert.c ********************/
+
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+/************************* Begin ../ext/misc/dbdata.c ******************/
+/*
+** 2019-04-17
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an implementation of two eponymous virtual tables,
+** "sqlite_dbdata" and "sqlite_dbptr". Both modules require that the
+** "sqlite_dbpage" eponymous virtual table be available.
+**
+** SQLITE_DBDATA:
+** sqlite_dbdata is used to extract data directly from a database b-tree
+** page and its associated overflow pages, bypassing the b-tree layer.
+** The table schema is equivalent to:
+**
+** CREATE TABLE sqlite_dbdata(
+** pgno INTEGER,
+** cell INTEGER,
+** field INTEGER,
+** value ANY,
+** schema TEXT HIDDEN
+** );
+**
+** IMPORTANT: THE VIRTUAL TABLE SCHEMA ABOVE IS SUBJECT TO CHANGE. IN THE
+** FUTURE NEW NON-HIDDEN COLUMNS MAY BE ADDED BETWEEN "value" AND
+** "schema".
+**
+** Each page of the database is inspected. If it cannot be interpreted as
+** a b-tree page, or if it is a b-tree page containing 0 entries, the
+** sqlite_dbdata table contains no rows for that page. Otherwise, the
+** table contains one row for each field in the record associated with
+** each cell on the page. For intkey b-trees, the key value is stored in
+** field -1.
+**
+** For example, for the database:
+**
+** CREATE TABLE t1(a, b); -- root page is page 2
+** INSERT INTO t1(rowid, a, b) VALUES(5, 'v', 'five');
+** INSERT INTO t1(rowid, a, b) VALUES(10, 'x', 'ten');
+**
+** the sqlite_dbdata table contains, as well as from entries related to
+** page 1, content equivalent to:
+**
+** INSERT INTO sqlite_dbdata(pgno, cell, field, value) VALUES
+** (2, 0, -1, 5 ),
+** (2, 0, 0, 'v' ),
+** (2, 0, 1, 'five'),
+** (2, 1, -1, 10 ),
+** (2, 1, 0, 'x' ),
+** (2, 1, 1, 'ten' );
+**
+** If database corruption is encountered, this module does not report an
+** error. Instead, it attempts to extract as much data as possible and
+** ignores the corruption.
+**
+** SQLITE_DBPTR:
+** The sqlite_dbptr table has the following schema:
+**
+** CREATE TABLE sqlite_dbptr(
+** pgno INTEGER,
+** child INTEGER,
+** schema TEXT HIDDEN
+** );
+**
+** It contains one entry for each b-tree pointer between a parent and
+** child page in the database.
+*/
+#if !defined(SQLITEINT_H)
+/* #include "sqlite3ext.h" */
+
+/* typedef unsigned char u8; */
+
+#endif
+SQLITE_EXTENSION_INIT1
+#include <string.h>
+#include <assert.h>
+
+#define DBDATA_PADDING_BYTES 100
+
+typedef struct DbdataTable DbdataTable;
+typedef struct DbdataCursor DbdataCursor;
+
+/* Cursor object */
+struct DbdataCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ sqlite3_stmt *pStmt; /* For fetching database pages */
+
+ int iPgno; /* Current page number */
+ u8 *aPage; /* Buffer containing page */
+ int nPage; /* Size of aPage[] in bytes */
+ int nCell; /* Number of cells on aPage[] */
+ int iCell; /* Current cell number */
+ int bOnePage; /* True to stop after one page */
+ int szDb;
+ sqlite3_int64 iRowid;
+
+ /* Only for the sqlite_dbdata table */
+ u8 *pRec; /* Buffer containing current record */
+ int nRec; /* Size of pRec[] in bytes */
+ int nHdr; /* Size of header in bytes */
+ int iField; /* Current field number */
+ u8 *pHdrPtr;
+ u8 *pPtr;
+
+ sqlite3_int64 iIntkey; /* Integer key value */
+};
+
+/* Table object */
+struct DbdataTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database connection */
+ sqlite3_stmt *pStmt; /* For fetching database pages */
+ int bPtr; /* True for sqlite3_dbptr table */
+};
+
+/* Column and schema definitions for sqlite_dbdata */
+#define DBDATA_COLUMN_PGNO 0
+#define DBDATA_COLUMN_CELL 1
+#define DBDATA_COLUMN_FIELD 2
+#define DBDATA_COLUMN_VALUE 3
+#define DBDATA_COLUMN_SCHEMA 4
+#define DBDATA_SCHEMA \
+ "CREATE TABLE x(" \
+ " pgno INTEGER," \
+ " cell INTEGER," \
+ " field INTEGER," \
+ " value ANY," \
+ " schema TEXT HIDDEN" \
+ ")"
+
+/* Column and schema definitions for sqlite_dbptr */
+#define DBPTR_COLUMN_PGNO 0
+#define DBPTR_COLUMN_CHILD 1
+#define DBPTR_COLUMN_SCHEMA 2
+#define DBPTR_SCHEMA \
+ "CREATE TABLE x(" \
+ " pgno INTEGER," \
+ " child INTEGER," \
+ " schema TEXT HIDDEN" \
+ ")"
+
+/*
+** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual
+** table.
+*/
+static int dbdataConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ DbdataTable *pTab = 0;
+ int rc = sqlite3_declare_vtab(db, pAux ? DBPTR_SCHEMA : DBDATA_SCHEMA);
+
+ if( rc==SQLITE_OK ){
+ pTab = (DbdataTable*)sqlite3_malloc64(sizeof(DbdataTable));
+ if( pTab==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pTab, 0, sizeof(DbdataTable));
+ pTab->db = db;
+ pTab->bPtr = (pAux!=0);
+ }
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a sqlite_dbdata or sqlite_dbptr virtual table.
+*/
+static int dbdataDisconnect(sqlite3_vtab *pVtab){
+ DbdataTable *pTab = (DbdataTable*)pVtab;
+ if( pTab ){
+ sqlite3_finalize(pTab->pStmt);
+ sqlite3_free(pVtab);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This function interprets two types of constraints:
+**
+** schema=?
+** pgno=?
+**
+** If neither are present, idxNum is set to 0. If schema=? is present,
+** the 0x01 bit in idxNum is set. If pgno=? is present, the 0x02 bit
+** in idxNum is set.
+**
+** If both parameters are present, schema is in position 0 and pgno in
+** position 1.
+*/
+static int dbdataBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdx){
+ DbdataTable *pTab = (DbdataTable*)tab;
+ int i;
+ int iSchema = -1;
+ int iPgno = -1;
+ int colSchema = (pTab->bPtr ? DBPTR_COLUMN_SCHEMA : DBDATA_COLUMN_SCHEMA);
+
+ for(i=0; i<pIdx->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdx->aConstraint[i];
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ if( p->iColumn==colSchema ){
+ if( p->usable==0 ) return SQLITE_CONSTRAINT;
+ iSchema = i;
+ }
+ if( p->iColumn==DBDATA_COLUMN_PGNO && p->usable ){
+ iPgno = i;
+ }
+ }
+ }
+
+ if( iSchema>=0 ){
+ pIdx->aConstraintUsage[iSchema].argvIndex = 1;
+ pIdx->aConstraintUsage[iSchema].omit = 1;
+ }
+ if( iPgno>=0 ){
+ pIdx->aConstraintUsage[iPgno].argvIndex = 1 + (iSchema>=0);
+ pIdx->aConstraintUsage[iPgno].omit = 1;
+ pIdx->estimatedCost = 100;
+ pIdx->estimatedRows = 50;
+
+ if( pTab->bPtr==0 && pIdx->nOrderBy && pIdx->aOrderBy[0].desc==0 ){
+ int iCol = pIdx->aOrderBy[0].iColumn;
+ if( pIdx->nOrderBy==1 ){
+ pIdx->orderByConsumed = (iCol==0 || iCol==1);
+ }else if( pIdx->nOrderBy==2 && pIdx->aOrderBy[1].desc==0 && iCol==0 ){
+ pIdx->orderByConsumed = (pIdx->aOrderBy[1].iColumn==1);
+ }
+ }
+
+ }else{
+ pIdx->estimatedCost = 100000000;
+ pIdx->estimatedRows = 1000000000;
+ }
+ pIdx->idxNum = (iSchema>=0 ? 0x01 : 0x00) | (iPgno>=0 ? 0x02 : 0x00);
+ return SQLITE_OK;
+}
+
+/*
+** Open a new sqlite_dbdata or sqlite_dbptr cursor.
+*/
+static int dbdataOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ DbdataCursor *pCsr;
+
+ pCsr = (DbdataCursor*)sqlite3_malloc64(sizeof(DbdataCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ memset(pCsr, 0, sizeof(DbdataCursor));
+ pCsr->base.pVtab = pVTab;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Restore a cursor object to the state it was in when first allocated
+** by dbdataOpen().
+*/
+static void dbdataResetCursor(DbdataCursor *pCsr){
+ DbdataTable *pTab = (DbdataTable*)(pCsr->base.pVtab);
+ if( pTab->pStmt==0 ){
+ pTab->pStmt = pCsr->pStmt;
+ }else{
+ sqlite3_finalize(pCsr->pStmt);
+ }
+ pCsr->pStmt = 0;
+ pCsr->iPgno = 1;
+ pCsr->iCell = 0;
+ pCsr->iField = 0;
+ pCsr->bOnePage = 0;
+ sqlite3_free(pCsr->aPage);
+ sqlite3_free(pCsr->pRec);
+ pCsr->pRec = 0;
+ pCsr->aPage = 0;
+}
+
+/*
+** Close an sqlite_dbdata or sqlite_dbptr cursor.
+*/
+static int dbdataClose(sqlite3_vtab_cursor *pCursor){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ dbdataResetCursor(pCsr);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Utility methods to decode 16 and 32-bit big-endian unsigned integers.
+*/
+static unsigned int get_uint16(unsigned char *a){
+ return (a[0]<<8)|a[1];
+}
+static unsigned int get_uint32(unsigned char *a){
+ return ((unsigned int)a[0]<<24)
+ | ((unsigned int)a[1]<<16)
+ | ((unsigned int)a[2]<<8)
+ | ((unsigned int)a[3]);
+}
+
+/*
+** Load page pgno from the database via the sqlite_dbpage virtual table.
+** If successful, set (*ppPage) to point to a buffer containing the page
+** data, (*pnPage) to the size of that buffer in bytes and return
+** SQLITE_OK. In this case it is the responsibility of the caller to
+** eventually free the buffer using sqlite3_free().
+**
+** Or, if an error occurs, set both (*ppPage) and (*pnPage) to 0 and
+** return an SQLite error code.
+*/
+static int dbdataLoadPage(
+ DbdataCursor *pCsr, /* Cursor object */
+ unsigned int pgno, /* Page number of page to load */
+ u8 **ppPage, /* OUT: pointer to page buffer */
+ int *pnPage /* OUT: Size of (*ppPage) in bytes */
+){
+ int rc2;
+ int rc = SQLITE_OK;
+ sqlite3_stmt *pStmt = pCsr->pStmt;
+
+ *ppPage = 0;
+ *pnPage = 0;
+ sqlite3_bind_int64(pStmt, 2, pgno);
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int nCopy = sqlite3_column_bytes(pStmt, 0);
+ if( nCopy>0 ){
+ u8 *pPage;
+ pPage = (u8*)sqlite3_malloc64(nCopy + DBDATA_PADDING_BYTES);
+ if( pPage==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ const u8 *pCopy = sqlite3_column_blob(pStmt, 0);
+ memcpy(pPage, pCopy, nCopy);
+ memset(&pPage[nCopy], 0, DBDATA_PADDING_BYTES);
+ }
+ *ppPage = pPage;
+ *pnPage = nCopy;
+ }
+ }
+ rc2 = sqlite3_reset(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+
+ return rc;
+}
+
+/*
+** Read a varint. Put the value in *pVal and return the number of bytes.
+*/
+static int dbdataGetVarint(const u8 *z, sqlite3_int64 *pVal){
+ sqlite3_int64 v = 0;
+ int i;
+ for(i=0; i<8; i++){
+ v = (v<<7) + (z[i]&0x7f);
+ if( (z[i]&0x80)==0 ){ *pVal = v; return i+1; }
+ }
+ v = (v<<8) + (z[i]&0xff);
+ *pVal = v;
+ return 9;
+}
+
+/*
+** Return the number of bytes of space used by an SQLite value of type
+** eType.
+*/
+static int dbdataValueBytes(int eType){
+ switch( eType ){
+ case 0: case 8: case 9:
+ case 10: case 11:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 2;
+ case 3:
+ return 3;
+ case 4:
+ return 4;
+ case 5:
+ return 6;
+ case 6:
+ case 7:
+ return 8;
+ default:
+ if( eType>0 ){
+ return ((eType-12) / 2);
+ }
+ return 0;
+ }
+}
+
+/*
+** Load a value of type eType from buffer pData and use it to set the
+** result of context object pCtx.
+*/
+static void dbdataValue(
+ sqlite3_context *pCtx,
+ int eType,
+ u8 *pData,
+ int nData
+){
+ if( eType>=0 && dbdataValueBytes(eType)<=nData ){
+ switch( eType ){
+ case 0:
+ case 10:
+ case 11:
+ sqlite3_result_null(pCtx);
+ break;
+
+ case 8:
+ sqlite3_result_int(pCtx, 0);
+ break;
+ case 9:
+ sqlite3_result_int(pCtx, 1);
+ break;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
+ sqlite3_uint64 v = (signed char)pData[0];
+ pData++;
+ switch( eType ){
+ case 7:
+ case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
+ case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
+ case 4: v = (v<<8) + pData[0]; pData++;
+ case 3: v = (v<<8) + pData[0]; pData++;
+ case 2: v = (v<<8) + pData[0]; pData++;
+ }
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ break;
+ }
+
+ default: {
+ int n = ((eType-12) / 2);
+ if( eType % 2 ){
+ sqlite3_result_text(pCtx, (const char*)pData, n, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+ }
+ }
+ }
+ }
+}
+
+/*
+** Move an sqlite_dbdata or sqlite_dbptr cursor to the next entry.
+*/
+static int dbdataNext(sqlite3_vtab_cursor *pCursor){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+
+ pCsr->iRowid++;
+ while( 1 ){
+ int rc;
+ int iOff = (pCsr->iPgno==1 ? 100 : 0);
+ int bNextPage = 0;
+
+ if( pCsr->aPage==0 ){
+ while( 1 ){
+ if( pCsr->bOnePage==0 && pCsr->iPgno>pCsr->szDb ) return SQLITE_OK;
+ rc = dbdataLoadPage(pCsr, pCsr->iPgno, &pCsr->aPage, &pCsr->nPage);
+ if( rc!=SQLITE_OK ) return rc;
+ if( pCsr->aPage ) break;
+ pCsr->iPgno++;
+ }
+ pCsr->iCell = pTab->bPtr ? -2 : 0;
+ pCsr->nCell = get_uint16(&pCsr->aPage[iOff+3]);
+ }
+
+ if( pTab->bPtr ){
+ if( pCsr->aPage[iOff]!=0x02 && pCsr->aPage[iOff]!=0x05 ){
+ pCsr->iCell = pCsr->nCell;
+ }
+ pCsr->iCell++;
+ if( pCsr->iCell>=pCsr->nCell ){
+ sqlite3_free(pCsr->aPage);
+ pCsr->aPage = 0;
+ if( pCsr->bOnePage ) return SQLITE_OK;
+ pCsr->iPgno++;
+ }else{
+ return SQLITE_OK;
+ }
+ }else{
+ /* If there is no record loaded, load it now. */
+ if( pCsr->pRec==0 ){
+ int bHasRowid = 0;
+ int nPointer = 0;
+ sqlite3_int64 nPayload = 0;
+ sqlite3_int64 nHdr = 0;
+ int iHdr;
+ int U, X;
+ int nLocal;
+
+ switch( pCsr->aPage[iOff] ){
+ case 0x02:
+ nPointer = 4;
+ break;
+ case 0x0a:
+ break;
+ case 0x0d:
+ bHasRowid = 1;
+ break;
+ default:
+ /* This is not a b-tree page with records on it. Continue. */
+ pCsr->iCell = pCsr->nCell;
+ break;
+ }
+
+ if( pCsr->iCell>=pCsr->nCell ){
+ bNextPage = 1;
+ }else{
+
+ iOff += 8 + nPointer + pCsr->iCell*2;
+ if( iOff>pCsr->nPage ){
+ bNextPage = 1;
+ }else{
+ iOff = get_uint16(&pCsr->aPage[iOff]);
+ }
+
+ /* For an interior node cell, skip past the child-page number */
+ iOff += nPointer;
+
+ /* Load the "byte of payload including overflow" field */
+ if( bNextPage || iOff>pCsr->nPage ){
+ bNextPage = 1;
+ }else{
+ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &nPayload);
+ }
+
+ /* If this is a leaf intkey cell, load the rowid */
+ if( bHasRowid && !bNextPage && iOff<pCsr->nPage ){
+ iOff += dbdataGetVarint(&pCsr->aPage[iOff], &pCsr->iIntkey);
+ }
+
+ /* Figure out how much data to read from the local page */
+ U = pCsr->nPage;
+ if( bHasRowid ){
+ X = U-35;
+ }else{
+ X = ((U-12)*64/255)-23;
+ }
+ if( nPayload<=X ){
+ nLocal = nPayload;
+ }else{
+ int M, K;
+ M = ((U-12)*32/255)-23;
+ K = M+((nPayload-M)%(U-4));
+ if( K<=X ){
+ nLocal = K;
+ }else{
+ nLocal = M;
+ }
+ }
+
+ if( bNextPage || nLocal+iOff>pCsr->nPage ){
+ bNextPage = 1;
+ }else{
+
+ /* Allocate space for payload. And a bit more to catch small buffer
+ ** overruns caused by attempting to read a varint or similar from
+ ** near the end of a corrupt record. */
+ pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES);
+ if( pCsr->pRec==0 ) return SQLITE_NOMEM;
+ memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES);
+ pCsr->nRec = nPayload;
+
+ /* Load the nLocal bytes of payload */
+ memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
+ iOff += nLocal;
+
+ /* Load content from overflow pages */
+ if( nPayload>nLocal ){
+ sqlite3_int64 nRem = nPayload - nLocal;
+ unsigned int pgnoOvfl = get_uint32(&pCsr->aPage[iOff]);
+ while( nRem>0 ){
+ u8 *aOvfl = 0;
+ int nOvfl = 0;
+ int nCopy;
+ rc = dbdataLoadPage(pCsr, pgnoOvfl, &aOvfl, &nOvfl);
+ assert( rc!=SQLITE_OK || aOvfl==0 || nOvfl==pCsr->nPage );
+ if( rc!=SQLITE_OK ) return rc;
+ if( aOvfl==0 ) break;
+
+ nCopy = U-4;
+ if( nCopy>nRem ) nCopy = nRem;
+ memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
+ nRem -= nCopy;
+
+ pgnoOvfl = get_uint32(aOvfl);
+ sqlite3_free(aOvfl);
+ }
+ }
+
+ iHdr = dbdataGetVarint(pCsr->pRec, &nHdr);
+ pCsr->nHdr = nHdr;
+ pCsr->pHdrPtr = &pCsr->pRec[iHdr];
+ pCsr->pPtr = &pCsr->pRec[pCsr->nHdr];
+ pCsr->iField = (bHasRowid ? -1 : 0);
+ }
+ }
+ }else{
+ pCsr->iField++;
+ if( pCsr->iField>0 ){
+ sqlite3_int64 iType;
+ if( pCsr->pHdrPtr>&pCsr->pRec[pCsr->nRec] ){
+ bNextPage = 1;
+ }else{
+ pCsr->pHdrPtr += dbdataGetVarint(pCsr->pHdrPtr, &iType);
+ pCsr->pPtr += dbdataValueBytes(iType);
+ }
+ }
+ }
+
+ if( bNextPage ){
+ sqlite3_free(pCsr->aPage);
+ sqlite3_free(pCsr->pRec);
+ pCsr->aPage = 0;
+ pCsr->pRec = 0;
+ if( pCsr->bOnePage ) return SQLITE_OK;
+ pCsr->iPgno++;
+ }else{
+ if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){
+ return SQLITE_OK;
+ }
+
+ /* Advance to the next cell. The next iteration of the loop will load
+ ** the record and so on. */
+ sqlite3_free(pCsr->pRec);
+ pCsr->pRec = 0;
+ pCsr->iCell++;
+ }
+ }
+ }
+
+ assert( !"can't get here" );
+ return SQLITE_OK;
+}
+
+/*
+** Return true if the cursor is at EOF.
+*/
+static int dbdataEof(sqlite3_vtab_cursor *pCursor){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ return pCsr->aPage==0;
+}
+
+/*
+** Determine the size in pages of database zSchema (where zSchema is
+** "main", "temp" or the name of an attached database) and set
+** pCsr->szDb accordingly. If successful, return SQLITE_OK. Otherwise,
+** an SQLite error code.
+*/
+static int dbdataDbsize(DbdataCursor *pCsr, const char *zSchema){
+ DbdataTable *pTab = (DbdataTable*)pCsr->base.pVtab;
+ char *zSql = 0;
+ int rc, rc2;
+ sqlite3_stmt *pStmt = 0;
+
+ zSql = sqlite3_mprintf("PRAGMA %Q.page_count", zSchema);
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
+ pCsr->szDb = sqlite3_column_int(pStmt, 0);
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ return rc;
+}
+
+/*
+** xFilter method for sqlite_dbdata and sqlite_dbptr.
+*/
+static int dbdataFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+ int rc = SQLITE_OK;
+ const char *zSchema = "main";
+
+ dbdataResetCursor(pCsr);
+ assert( pCsr->iPgno==1 );
+ if( idxNum & 0x01 ){
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ }
+ if( idxNum & 0x02 ){
+ pCsr->iPgno = sqlite3_value_int(argv[(idxNum & 0x01)]);
+ pCsr->bOnePage = 1;
+ }else{
+ pCsr->nPage = dbdataDbsize(pCsr, zSchema);
+ rc = dbdataDbsize(pCsr, zSchema);
+ }
+
+ if( rc==SQLITE_OK ){
+ if( pTab->pStmt ){
+ pCsr->pStmt = pTab->pStmt;
+ pTab->pStmt = 0;
+ }else{
+ rc = sqlite3_prepare_v2(pTab->db,
+ "SELECT data FROM sqlite_dbpage(?) WHERE pgno=?", -1,
+ &pCsr->pStmt, 0
+ );
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_bind_text(pCsr->pStmt, 1, zSchema, -1, SQLITE_TRANSIENT);
+ }else{
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ }
+ if( rc==SQLITE_OK ){
+ rc = dbdataNext(pCursor);
+ }
+ return rc;
+}
+
+/*
+** Return a column for the sqlite_dbdata or sqlite_dbptr table.
+*/
+static int dbdataColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ DbdataTable *pTab = (DbdataTable*)pCursor->pVtab;
+ if( pTab->bPtr ){
+ switch( i ){
+ case DBPTR_COLUMN_PGNO:
+ sqlite3_result_int64(ctx, pCsr->iPgno);
+ break;
+ case DBPTR_COLUMN_CHILD: {
+ int iOff = pCsr->iPgno==1 ? 100 : 0;
+ if( pCsr->iCell<0 ){
+ iOff += 8;
+ }else{
+ iOff += 12 + pCsr->iCell*2;
+ if( iOff>pCsr->nPage ) return SQLITE_OK;
+ iOff = get_uint16(&pCsr->aPage[iOff]);
+ }
+ if( iOff<=pCsr->nPage ){
+ sqlite3_result_int64(ctx, get_uint32(&pCsr->aPage[iOff]));
+ }
+ break;
+ }
+ }
+ }else{
+ switch( i ){
+ case DBDATA_COLUMN_PGNO:
+ sqlite3_result_int64(ctx, pCsr->iPgno);
+ break;
+ case DBDATA_COLUMN_CELL:
+ sqlite3_result_int(ctx, pCsr->iCell);
+ break;
+ case DBDATA_COLUMN_FIELD:
+ sqlite3_result_int(ctx, pCsr->iField);
+ break;
+ case DBDATA_COLUMN_VALUE: {
+ if( pCsr->iField<0 ){
+ sqlite3_result_int64(ctx, pCsr->iIntkey);
+ }else{
+ sqlite3_int64 iType;
+ dbdataGetVarint(pCsr->pHdrPtr, &iType);
+ dbdataValue(
+ ctx, iType, pCsr->pPtr, &pCsr->pRec[pCsr->nRec] - pCsr->pPtr
+ );
+ }
+ break;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for an sqlite_dbdata or sqlite_dptr table.
+*/
+static int dbdataRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ DbdataCursor *pCsr = (DbdataCursor*)pCursor;
+ *pRowid = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+
+/*
+** Invoke this routine to register the "sqlite_dbdata" virtual table module
+*/
+static int sqlite3DbdataRegister(sqlite3 *db){
+ static sqlite3_module dbdata_module = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ dbdataConnect, /* xConnect */
+ dbdataBestIndex, /* xBestIndex */
+ dbdataDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ dbdataOpen, /* xOpen - open a cursor */
+ dbdataClose, /* xClose - close a cursor */
+ dbdataFilter, /* xFilter - configure scan constraints */
+ dbdataNext, /* xNext - advance a cursor */
+ dbdataEof, /* xEof - check for end of scan */
+ dbdataColumn, /* xColumn - read data */
+ dbdataRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+ };
+
+ int rc = sqlite3_create_module(db, "sqlite_dbdata", &dbdata_module, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "sqlite_dbptr", &dbdata_module, (void*)1);
+ }
+ return rc;
+}
+
+#ifdef _WIN32
+
+#endif
+int sqlite3_dbdata_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ return sqlite3DbdataRegister(db);
+}
+
+/************************* End ../ext/misc/dbdata.c ********************/
+#endif
+
#if defined(SQLITE_ENABLE_SESSION)
/*
** State information for a single open session
@@ -591,16 +10638,27 @@ struct OpenSession {
};
#endif
-/*
-** Shell output mode information from before ".explain on",
-** saved so that it can be restored by ".explain off"
-*/
-typedef struct SavedModeInfo SavedModeInfo;
-struct SavedModeInfo {
- int valid; /* Is there legit data in here? */
- int mode; /* Mode prior to ".explain on" */
- int showHeader; /* The ".header" setting prior to ".explain on" */
- int colWidth[100]; /* Column widths prior to ".explain on" */
+typedef struct ExpertInfo ExpertInfo;
+struct ExpertInfo {
+ sqlite3expert *pExpert;
+ int bVerbose;
+};
+
+/* A single line in the EQP output */
+typedef struct EQPGraphRow EQPGraphRow;
+struct EQPGraphRow {
+ int iEqpId; /* ID for this row */
+ int iParentId; /* ID of the parent row */
+ EQPGraphRow *pNext; /* Next row in sequence */
+ char zText[1]; /* Text to display for this row */
+};
+
+/* All EQP output is collected into an instance of the following */
+typedef struct EQPGraph EQPGraph;
+struct EQPGraph {
+ EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */
+ EQPGraphRow *pLast; /* Last element of the pRow list */
+ char zPrefix[100]; /* Graph prefix */
};
/*
@@ -610,31 +10668,48 @@ struct SavedModeInfo {
typedef struct ShellState ShellState;
struct ShellState {
sqlite3 *db; /* The database */
- int echoOn; /* True to echo input commands */
- int autoExplain; /* Automatically turn on .explain mode */
- int autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
- int statsOn; /* True to display memory stats before each finalize */
- int scanstatsOn; /* True to display scan stats before each finalize */
- int countChanges; /* True to display change counts */
- int backslashOn; /* Resolve C-style \x escapes in SQL input text */
+ u8 autoExplain; /* Automatically turn on .explain mode */
+ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */
+ u8 autoEQPtest; /* autoEQP is in test mode */
+ u8 autoEQPtrace; /* autoEQP is in trace mode */
+ u8 statsOn; /* True to display memory stats before each finalize */
+ u8 scanstatsOn; /* True to display scan stats before each finalize */
+ u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
+ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */
+ u8 nEqpLevel; /* Depth of the EQP output graph */
+ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
+ unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */
int outCount; /* Revert to stdout when reaching zero */
int cnt; /* Number of records displayed so far */
+ int lineno; /* Line number of last line read from in */
+ int openFlags; /* Additional flags to open. (SQLITE_OPEN_NOFOLLOW) */
+ FILE *in; /* Read commands from this stream */
FILE *out; /* Write results here */
FILE *traceOut; /* Output for sqlite3_trace() */
int nErr; /* Number of errors seen */
int mode; /* An output mode setting */
+ int modePrior; /* Saved mode */
int cMode; /* temporary output mode for the current query */
int normalMode; /* Output mode before ".explain on" */
int writableSchema; /* True if PRAGMA writable_schema=ON */
int showHeader; /* True to show column names in List or Column mode */
int nCheck; /* Number of ".check" commands run */
+ unsigned nProgress; /* Number of progress callbacks encountered */
+ unsigned mxProgress; /* Maximum progress callbacks before failing */
+ unsigned flgProgress; /* Flags for the progress callback */
unsigned shellFlgs; /* Various flags */
+ unsigned priorShFlgs; /* Saved copy of flags */
+ sqlite3_int64 szMax; /* --maxsize argument to .open */
char *zDestTable; /* Name of destination table when MODE_Insert */
+ char *zTempFile; /* Temporary file that might need deleting */
char zTestcase[30]; /* Name of current test case */
char colSeparator[20]; /* Column separator character for several modes */
char rowSeparator[20]; /* Row separator character for MODE_Ascii */
- int colWidth[100]; /* Requested width of each column when in column mode*/
- int actualWidth[100]; /* Actual width of each column */
+ char colSepPrior[20]; /* Saved column separator */
+ char rowSepPrior[20]; /* Saved row separator */
+ int *colWidth; /* Requested width of each column in columnar modes */
+ int *actualWidth; /* Actual width of each column */
+ int nWidth; /* Number of slots in colWidth[] and actualWidth[] */
char nullValue[20]; /* The text to print when a NULL comes back from
** the database */
char outfile[FILENAME_MAX]; /* Filename for *out */
@@ -646,18 +10721,63 @@ struct ShellState {
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
int iIndent; /* Index of current op in aiIndent[] */
+ EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */
#if defined(SQLITE_ENABLE_SESSION)
int nSession; /* Number of active sessions */
OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */
#endif
+ ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */
};
+
+/* Allowed values for ShellState.autoEQP
+*/
+#define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */
+#define AUTOEQP_on 1 /* Automatic EQP is on */
+#define AUTOEQP_trigger 2 /* On and also show plans for triggers */
+#define AUTOEQP_full 3 /* Show full EXPLAIN */
+
+/* Allowed values for ShellState.openMode
+*/
+#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */
+#define SHELL_OPEN_NORMAL 1 /* Normal database file */
+#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */
+#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */
+#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */
+#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */
+#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */
+
+/* Allowed values for ShellState.eTraceType
+*/
+#define SHELL_TRACE_PLAIN 0 /* Show input SQL text */
+#define SHELL_TRACE_EXPANDED 1 /* Show expanded SQL text */
+#define SHELL_TRACE_NORMALIZED 2 /* Show normalized SQL text */
+
+/* Bits in the ShellState.flgProgress variable */
+#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
+#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progres
+ ** callback limit is reached, and for each
+ ** top-level SQL statement */
+#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
+
/*
** These are the allowed shellFlgs values
*/
-#define SHFLG_Scratch 0x00001 /* The --scratch option is used */
-#define SHFLG_Pagecache 0x00002 /* The --pagecache option is used */
-#define SHFLG_Lookaside 0x00004 /* Lookaside memory is used */
+#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
+#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
+#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
+#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
+#define SHFLG_Newlines 0x00000010 /* .dump --newline flag */
+#define SHFLG_CountChanges 0x00000020 /* .changes setting */
+#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */
+#define SHFLG_HeaderSet 0x00000080 /* .header has been used */
+
+/*
+** Macros for testing and setting shellFlgs
+*/
+#define ShellHasFlag(P,X) (((P)->shellFlgs & (X))!=0)
+#define ShellSetFlag(P,X) ((P)->shellFlgs|=(X))
+#define ShellClearFlag(P,X) ((P)->shellFlgs&=(~(X)))
/*
** These are the allowed modes.
@@ -668,11 +10788,17 @@ struct ShellState {
#define MODE_Semi 3 /* Same as MODE_List but append ";" to each line */
#define MODE_Html 4 /* Generate an XHTML table */
#define MODE_Insert 5 /* Generate SQL "insert" statements */
-#define MODE_Tcl 6 /* Generate ANSI-C or TCL quoted elements */
-#define MODE_Csv 7 /* Quote strings, numbers are plain */
-#define MODE_Explain 8 /* Like MODE_Column, but do not truncate data */
-#define MODE_Ascii 9 /* Use ASCII unit and record separators (0x1F/0x1E) */
-#define MODE_Pretty 10 /* Pretty-print schemas */
+#define MODE_Quote 6 /* Quote values as for SQL */
+#define MODE_Tcl 7 /* Generate ANSI-C or TCL quoted elements */
+#define MODE_Csv 8 /* Quote strings, numbers are plain */
+#define MODE_Explain 9 /* Like MODE_Column, but do not truncate data */
+#define MODE_Ascii 10 /* Use ASCII unit and record separators (0x1F/0x1E) */
+#define MODE_Pretty 11 /* Pretty-print schemas */
+#define MODE_EQP 12 /* Converts EXPLAIN QUERY PLAN output into a graph */
+#define MODE_Json 13 /* Output JSON */
+#define MODE_Markdown 14 /* Markdown formatting */
+#define MODE_Table 15 /* MySQL-style table formatting */
+#define MODE_Box 16 /* Unicode box-drawing characters */
static const char *modeDescr[] = {
"line",
@@ -681,11 +10807,17 @@ static const char *modeDescr[] = {
"semi",
"html",
"insert",
+ "quote",
"tcl",
"csv",
"explain",
"ascii",
"prettyprint",
+ "eqp",
+ "json",
+ "markdown",
+ "table",
+ "box"
};
/*
@@ -702,11 +10834,6 @@ static const char *modeDescr[] = {
#define SEP_Record "\x1E"
/*
-** Number of elements in an array
-*/
-#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
-
-/*
** A callback for the sqlite3_log() interface.
*/
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
@@ -717,6 +10844,183 @@ static void shellLog(void *pArg, int iErrCode, const char *zMsg){
}
/*
+** SQL function: shell_putsnl(X)
+**
+** Write the text X to the screen (or whatever output is being directed)
+** adding a newline at the end, and then return X.
+*/
+static void shellPutsFunc(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
+ (void)nVal;
+ utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
+ sqlite3_result_value(pCtx, apVal[0]);
+}
+
+/*
+** SQL function: edit(VALUE)
+** edit(VALUE,EDITOR)
+**
+** These steps:
+**
+** (1) Write VALUE into a temporary file.
+** (2) Run program EDITOR on that temporary file.
+** (3) Read the temporary file back and return its content as the result.
+** (4) Delete the temporary file
+**
+** If the EDITOR argument is omitted, use the value in the VISUAL
+** environment variable. If still there is no EDITOR, through an error.
+**
+** Also throw an error if the EDITOR program returns a non-zero exit code.
+*/
+#ifndef SQLITE_NOHAVE_SYSTEM
+static void editFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zEditor;
+ char *zTempFile = 0;
+ sqlite3 *db;
+ char *zCmd = 0;
+ int bBin;
+ int rc;
+ int hasCRNL = 0;
+ FILE *f = 0;
+ sqlite3_int64 sz;
+ sqlite3_int64 x;
+ unsigned char *p = 0;
+
+ if( argc==2 ){
+ zEditor = (const char*)sqlite3_value_text(argv[1]);
+ }else{
+ zEditor = getenv("VISUAL");
+ }
+ if( zEditor==0 ){
+ sqlite3_result_error(context, "no editor for edit()", -1);
+ return;
+ }
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ sqlite3_result_error(context, "NULL input to edit()", -1);
+ return;
+ }
+ db = sqlite3_context_db_handle(context);
+ zTempFile = 0;
+ sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile);
+ if( zTempFile==0 ){
+ sqlite3_uint64 r = 0;
+ sqlite3_randomness(sizeof(r), &r);
+ zTempFile = sqlite3_mprintf("temp%llx", r);
+ if( zTempFile==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ }
+ bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
+ /* When writing the file to be edited, do \n to \r\n conversions on systems
+ ** that want \r\n line endings */
+ f = fopen(zTempFile, bBin ? "wb" : "w");
+ if( f==0 ){
+ sqlite3_result_error(context, "edit() cannot open temp file", -1);
+ goto edit_func_end;
+ }
+ sz = sqlite3_value_bytes(argv[0]);
+ if( bBin ){
+ x = fwrite(sqlite3_value_blob(argv[0]), 1, (size_t)sz, f);
+ }else{
+ const char *z = (const char*)sqlite3_value_text(argv[0]);
+ /* Remember whether or not the value originally contained \r\n */
+ if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
+ x = fwrite(sqlite3_value_text(argv[0]), 1, (size_t)sz, f);
+ }
+ fclose(f);
+ f = 0;
+ if( x!=sz ){
+ sqlite3_result_error(context, "edit() could not write the whole file", -1);
+ goto edit_func_end;
+ }
+ zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile);
+ if( zCmd==0 ){
+ sqlite3_result_error_nomem(context);
+ goto edit_func_end;
+ }
+ rc = system(zCmd);
+ sqlite3_free(zCmd);
+ if( rc ){
+ sqlite3_result_error(context, "EDITOR returned non-zero", -1);
+ goto edit_func_end;
+ }
+ f = fopen(zTempFile, "rb");
+ if( f==0 ){
+ sqlite3_result_error(context,
+ "edit() cannot reopen temp file after edit", -1);
+ goto edit_func_end;
+ }
+ fseek(f, 0, SEEK_END);
+ sz = ftell(f);
+ rewind(f);
+ p = sqlite3_malloc64( sz+1 );
+ if( p==0 ){
+ sqlite3_result_error_nomem(context);
+ goto edit_func_end;
+ }
+ x = fread(p, 1, (size_t)sz, f);
+ fclose(f);
+ f = 0;
+ if( x!=sz ){
+ sqlite3_result_error(context, "could not read back the whole file", -1);
+ goto edit_func_end;
+ }
+ if( bBin ){
+ sqlite3_result_blob64(context, p, sz, sqlite3_free);
+ }else{
+ sqlite3_int64 i, j;
+ if( hasCRNL ){
+ /* If the original contains \r\n then do no conversions back to \n */
+ j = sz;
+ }else{
+ /* If the file did not originally contain \r\n then convert any new
+ ** \r\n back into \n */
+ for(i=j=0; i<sz; i++){
+ if( p[i]=='\r' && p[i+1]=='\n' ) i++;
+ p[j++] = p[i];
+ }
+ sz = j;
+ p[sz] = 0;
+ }
+ sqlite3_result_text64(context, (const char*)p, sz,
+ sqlite3_free, SQLITE_UTF8);
+ }
+ p = 0;
+
+edit_func_end:
+ if( f ) fclose(f);
+ unlink(zTempFile);
+ sqlite3_free(zTempFile);
+ sqlite3_free(p);
+}
+#endif /* SQLITE_NOHAVE_SYSTEM */
+
+/*
+** Save or restore the current output mode
+*/
+static void outputModePush(ShellState *p){
+ p->modePrior = p->mode;
+ p->priorShFlgs = p->shellFlgs;
+ memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
+ memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
+}
+static void outputModePop(ShellState *p){
+ p->mode = p->modePrior;
+ p->shellFlgs = p->priorShFlgs;
+ memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
+ memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
+}
+
+/*
** Output the given string as a hex-encoded blob (eg. X'1234' )
*/
static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
@@ -728,33 +11032,124 @@ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
}
/*
+** Find a string that is not found anywhere in z[]. Return a pointer
+** to that string.
+**
+** Try to use zA and zB first. If both of those are already found in z[]
+** then make up some string and store it in the buffer zBuf.
+*/
+static const char *unused_string(
+ const char *z, /* Result must not appear anywhere in z */
+ const char *zA, const char *zB, /* Try these first */
+ char *zBuf /* Space to store a generated string */
+){
+ unsigned i = 0;
+ if( strstr(z, zA)==0 ) return zA;
+ if( strstr(z, zB)==0 ) return zB;
+ do{
+ sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
+ }while( strstr(z,zBuf)!=0 );
+ return zBuf;
+}
+
+/*
** Output the given string as a quoted string using SQL quoting conventions.
+**
+** See also: output_quoted_escaped_string()
*/
static void output_quoted_string(FILE *out, const char *z){
int i;
- int nSingle = 0;
+ char c;
setBinaryMode(out, 1);
- for(i=0; z[i]; i++){
- if( z[i]=='\'' ) nSingle++;
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c==0 ){
+ utf8_printf(out,"'%s'",z);
+ }else{
+ raw_printf(out, "'");
+ while( *z ){
+ for(i=0; (c = z[i])!=0 && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ utf8_printf(out, "%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ raw_printf(out, "'");
+ continue;
+ }
+ if( c==0 ){
+ break;
+ }
+ z++;
+ }
+ raw_printf(out, "'");
}
- if( nSingle==0 ){
+ setTextMode(out, 1);
+}
+
+/*
+** Output the given string as a quoted string using SQL quoting conventions.
+** Additionallly , escape the "\n" and "\r" characters so that they do not
+** get corrupted by end-of-line translation facilities in some operating
+** systems.
+**
+** This is like output_quoted_string() but with the addition of the \r\n
+** escape mechanism.
+*/
+static void output_quoted_escaped_string(FILE *out, const char *z){
+ int i;
+ char c;
+ setBinaryMode(out, 1);
+ for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
+ if( c==0 ){
utf8_printf(out,"'%s'",z);
}else{
- raw_printf(out,"'");
+ const char *zNL = 0;
+ const char *zCR = 0;
+ int nNL = 0;
+ int nCR = 0;
+ char zBuf1[20], zBuf2[20];
+ for(i=0; z[i]; i++){
+ if( z[i]=='\n' ) nNL++;
+ if( z[i]=='\r' ) nCR++;
+ }
+ if( nNL ){
+ raw_printf(out, "replace(");
+ zNL = unused_string(z, "\\n", "\\012", zBuf1);
+ }
+ if( nCR ){
+ raw_printf(out, "replace(");
+ zCR = unused_string(z, "\\r", "\\015", zBuf2);
+ }
+ raw_printf(out, "'");
while( *z ){
- for(i=0; z[i] && z[i]!='\''; i++){}
- if( i==0 ){
- raw_printf(out,"''");
- z++;
- }else if( z[i]=='\'' ){
- utf8_printf(out,"%.*s''",i,z);
- z += i+1;
- }else{
- utf8_printf(out,"%s",z);
+ for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
+ if( c=='\'' ) i++;
+ if( i ){
+ utf8_printf(out, "%.*s", i, z);
+ z += i;
+ }
+ if( c=='\'' ){
+ raw_printf(out, "'");
+ continue;
+ }
+ if( c==0 ){
break;
}
+ z++;
+ if( c=='\n' ){
+ raw_printf(out, "%s", zNL);
+ continue;
+ }
+ raw_printf(out, "%s", zCR);
+ }
+ raw_printf(out, "'");
+ if( nCR ){
+ raw_printf(out, ",'%s',char(13))", zCR);
+ }
+ if( nNL ){
+ raw_printf(out, ",'%s',char(10))", zNL);
}
- raw_printf(out,"'");
}
setTextMode(out, 1);
}
@@ -791,6 +11186,40 @@ static void output_c_string(FILE *out, const char *z){
}
/*
+** Output the given string as a quoted according to JSON quoting rules.
+*/
+static void output_json_string(FILE *out, const char *z, int n){
+ unsigned int c;
+ if( n<0 ) n = (int)strlen(z);
+ fputc('"', out);
+ while( n-- ){
+ c = *(z++);
+ if( c=='\\' || c=='"' ){
+ fputc('\\', out);
+ fputc(c, out);
+ }else if( c<=0x1f ){
+ fputc('\\', out);
+ if( c=='\b' ){
+ fputc('b', out);
+ }else if( c=='\f' ){
+ fputc('f', out);
+ }else if( c=='\n' ){
+ fputc('n', out);
+ }else if( c=='\r' ){
+ fputc('r', out);
+ }else if( c=='\t' ){
+ fputc('t', out);
+ }else{
+ raw_printf(out, "u%04x",c);
+ }
+ }else{
+ fputc(c, out);
+ }
+ }
+ fputc('"', out);
+}
+
+/*
** Output the given string with characters that are special to
** HTML escaped.
*/
@@ -870,12 +11299,9 @@ static void output_csv(ShellState *p, const char *z, int bSep){
}
}
if( i==0 ){
- putc('"', out);
- for(i=0; z[i]; i++){
- if( z[i]=='"' ) putc('"', out);
- putc(z[i], out);
- }
- putc('"', out);
+ char *zQuoted = sqlite3_mprintf("\"%w\"", z);
+ utf8_printf(out, "%s", zQuoted);
+ sqlite3_free(zQuoted);
}else{
utf8_printf(out, "%s", z);
}
@@ -885,7 +11311,6 @@ static void output_csv(ShellState *p, const char *z, int bSep){
}
}
-#ifdef SIGINT
/*
** This routine runs when the user presses Ctrl-C
*/
@@ -895,6 +11320,20 @@ static void interrupt_handler(int NotUsed){
if( seenInterrupt>2 ) exit(1);
if( globalDb ) sqlite3_interrupt(globalDb);
}
+
+#if (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
+/*
+** This routine runs for console events (e.g. Ctrl-C) on Win32
+*/
+static BOOL WINAPI ConsoleCtrlHandler(
+ DWORD dwCtrlType /* One of the CTRL_*_EVENT constants */
+){
+ if( dwCtrlType==CTRL_C_EVENT ){
+ interrupt_handler(0);
+ return TRUE;
+ }
+ return FALSE;
+}
#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -944,6 +11383,184 @@ static int shellAuth(
}
#endif
+/*
+** Print a schema statement. Part of MODE_Semi and MODE_Pretty output.
+**
+** This routine converts some CREATE TABLE statements for shadow tables
+** in FTS3/4/5 into CREATE TABLE IF NOT EXISTS statements.
+*/
+static void printSchemaLine(FILE *out, const char *z, const char *zTail){
+ if( z==0 ) return;
+ if( zTail==0 ) return;
+ if( sqlite3_strglob("CREATE TABLE ['\"]*", z)==0 ){
+ utf8_printf(out, "CREATE TABLE IF NOT EXISTS %s%s", z+13, zTail);
+ }else{
+ utf8_printf(out, "%s%s", z, zTail);
+ }
+}
+static void printSchemaLineN(FILE *out, char *z, int n, const char *zTail){
+ char c = z[n];
+ z[n] = 0;
+ printSchemaLine(out, z, zTail);
+ z[n] = c;
+}
+
+/*
+** Return true if string z[] has nothing but whitespace and comments to the
+** end of the first line.
+*/
+static int wsToEol(const char *z){
+ int i;
+ for(i=0; z[i]; i++){
+ if( z[i]=='\n' ) return 1;
+ if( IsSpace(z[i]) ) continue;
+ if( z[i]=='-' && z[i+1]=='-' ) return 1;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Add a new entry to the EXPLAIN QUERY PLAN data
+*/
+static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){
+ EQPGraphRow *pNew;
+ int nText = strlen30(zText);
+ if( p->autoEQPtest ){
+ utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText);
+ }
+ pNew = sqlite3_malloc64( sizeof(*pNew) + nText );
+ if( pNew==0 ) shell_out_of_memory();
+ pNew->iEqpId = iEqpId;
+ pNew->iParentId = p2;
+ memcpy(pNew->zText, zText, nText+1);
+ pNew->pNext = 0;
+ if( p->sGraph.pLast ){
+ p->sGraph.pLast->pNext = pNew;
+ }else{
+ p->sGraph.pRow = pNew;
+ }
+ p->sGraph.pLast = pNew;
+}
+
+/*
+** Free and reset the EXPLAIN QUERY PLAN data that has been collected
+** in p->sGraph.
+*/
+static void eqp_reset(ShellState *p){
+ EQPGraphRow *pRow, *pNext;
+ for(pRow = p->sGraph.pRow; pRow; pRow = pNext){
+ pNext = pRow->pNext;
+ sqlite3_free(pRow);
+ }
+ memset(&p->sGraph, 0, sizeof(p->sGraph));
+}
+
+/* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after
+** pOld, or return the first such line if pOld is NULL
+*/
+static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){
+ EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow;
+ while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext;
+ return pRow;
+}
+
+/* Render a single level of the graph that has iEqpId as its parent. Called
+** recursively to render sublevels.
+*/
+static void eqp_render_level(ShellState *p, int iEqpId){
+ EQPGraphRow *pRow, *pNext;
+ int n = strlen30(p->sGraph.zPrefix);
+ char *z;
+ for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){
+ pNext = eqp_next_row(p, iEqpId, pRow);
+ z = pRow->zText;
+ utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix,
+ pNext ? "|--" : "`--", z);
+ if( n<(int)sizeof(p->sGraph.zPrefix)-7 ){
+ memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4);
+ eqp_render_level(p, pRow->iEqpId);
+ p->sGraph.zPrefix[n] = 0;
+ }
+ }
+}
+
+/*
+** Display and reset the EXPLAIN QUERY PLAN data
+*/
+static void eqp_render(ShellState *p){
+ EQPGraphRow *pRow = p->sGraph.pRow;
+ if( pRow ){
+ if( pRow->zText[0]=='-' ){
+ if( pRow->pNext==0 ){
+ eqp_reset(p);
+ return;
+ }
+ utf8_printf(p->out, "%s\n", pRow->zText+3);
+ p->sGraph.pRow = pRow->pNext;
+ sqlite3_free(pRow);
+ }else{
+ utf8_printf(p->out, "QUERY PLAN\n");
+ }
+ p->sGraph.zPrefix[0] = 0;
+ eqp_render_level(p, 0);
+ eqp_reset(p);
+ }
+}
+
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+/*
+** Progress handler callback.
+*/
+static int progress_handler(void *pClientData) {
+ ShellState *p = (ShellState*)pClientData;
+ p->nProgress++;
+ if( p->nProgress>=p->mxProgress && p->mxProgress>0 ){
+ raw_printf(p->out, "Progress limit reached (%u)\n", p->nProgress);
+ if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
+ if( p->flgProgress & SHELL_PROGRESS_ONCE ) p->mxProgress = 0;
+ return 1;
+ }
+ if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){
+ raw_printf(p->out, "Progress %u\n", p->nProgress);
+ }
+ return 0;
+}
+#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
+
+/*
+** Print N dashes
+*/
+static void print_dashes(FILE *out, int N){
+ const char zDash[] = "--------------------------------------------------";
+ const int nDash = sizeof(zDash) - 1;
+ while( N>nDash ){
+ fputs(zDash, out);
+ N -= nDash;
+ }
+ raw_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Print a markdown or table-style row separator using ascii-art
+*/
+static void print_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep
+){
+ int i;
+ if( nArg>0 ){
+ fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[0]+2);
+ for(i=1; i<nArg; i++){
+ fputs(zSep, p->out);
+ print_dashes(p->out, p->actualWidth[i]+2);
+ }
+ fputs(zSep, p->out);
+ }
+ fputs("\n", p->out);
+}
/*
** This is the callback routine that the shell
@@ -954,11 +11571,12 @@ static int shell_callback(
int nArg, /* Number of result columns */
char **azArg, /* Text of each result column */
char **azCol, /* Column names */
- int *aiType /* Column types */
+ int *aiType /* Column types. Might be NULL */
){
int i;
ShellState *p = (ShellState*)pArg;
+ if( azArg==0 ) return 0;
switch( p->cMode ){
case MODE_Line: {
int w = 5;
@@ -974,74 +11592,28 @@ static int shell_callback(
}
break;
}
- case MODE_Explain:
- case MODE_Column: {
- static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13};
- const int *colWidth;
- int showHdr;
- char *rowSep;
- if( p->cMode==MODE_Column ){
- colWidth = p->colWidth;
- showHdr = p->showHeader;
- rowSep = p->rowSeparator;
- }else{
- colWidth = aExplainWidths;
- showHdr = 1;
- rowSep = SEP_Row;
+ case MODE_Explain: {
+ static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
+ if( nArg>ArraySize(aExplainWidth) ){
+ nArg = ArraySize(aExplainWidth);
}
if( p->cnt++==0 ){
for(i=0; i<nArg; i++){
- int w, n;
- if( i<ArraySize(p->colWidth) ){
- w = colWidth[i];
- }else{
- w = 0;
- }
- if( w==0 ){
- w = strlen30(azCol[i] ? azCol[i] : "");
- if( w<10 ) w = 10;
- n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
- if( w<n ) w = n;
- }
- if( i<ArraySize(p->actualWidth) ){
- p->actualWidth[i] = w;
- }
- if( showHdr ){
- if( w<0 ){
- utf8_printf(p->out,"%*.*s%s",-w,-w,azCol[i],
- i==nArg-1 ? rowSep : " ");
- }else{
- utf8_printf(p->out,"%-*.*s%s",w,w,azCol[i],
- i==nArg-1 ? rowSep : " ");
- }
- }
+ int w = aExplainWidth[i];
+ utf8_width_print(p->out, w, azCol[i]);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
- if( showHdr ){
- for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- if( w<0 ) w = -w;
- }else{
- w = 10;
- }
- utf8_printf(p->out,"%-*.*s%s",w,w,
- "----------------------------------------------------------"
- "----------------------------------------------------------",
- i==nArg-1 ? rowSep : " ");
- }
+ for(i=0; i<nArg; i++){
+ int w = aExplainWidth[i];
+ print_dashes(p->out, w);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
- int w;
- if( i<ArraySize(p->actualWidth) ){
- w = p->actualWidth[i];
- }else{
- w = 10;
- }
- if( p->cMode==MODE_Explain && azArg[i] && strlen30(azArg[i])>w ){
- w = strlen30(azArg[i]);
+ int w = aExplainWidth[i];
+ if( azArg[i] && strlenChar(azArg[i])>w ){
+ w = strlenChar(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
if( p->iIndent<p->nIndent ){
@@ -1049,20 +11621,13 @@ static int shell_callback(
}
p->iIndent++;
}
- if( w<0 ){
- utf8_printf(p->out,"%*.*s%s",-w,-w,
- azArg[i] ? azArg[i] : p->nullValue,
- i==nArg-1 ? rowSep : " ");
- }else{
- utf8_printf(p->out,"%-*.*s%s",w,w,
- azArg[i] ? azArg[i] : p->nullValue,
- i==nArg-1 ? rowSep : " ");
- }
+ utf8_width_print(p->out, w, azArg[i] ? azArg[i] : p->nullValue);
+ fputs(i==nArg-1 ? "\n" : " ", p->out);
}
break;
}
case MODE_Semi: { /* .schema and .fullschema output */
- utf8_printf(p->out, "%s;\n", azArg[0]);
+ printSchemaLine(p->out, azArg[0], ";\n");
break;
}
case MODE_Pretty: { /* .schema and .fullschema with --indent */
@@ -1085,6 +11650,7 @@ static int shell_callback(
for(i=0; IsSpace(z[i]); i++){}
for(; (c = z[i])!=0; i++){
if( IsSpace(c) ){
+ if( z[j-1]=='\r' ) z[j-1] = '\n';
if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue;
}else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){
j--;
@@ -1094,26 +11660,30 @@ static int shell_callback(
while( j>0 && IsSpace(z[j-1]) ){ j--; }
z[j] = 0;
if( strlen30(z)>=79 ){
- for(i=j=0; (c = z[i])!=0; i++){
+ for(i=j=0; (c = z[i])!=0; i++){ /* Copy from z[i] back to z[j] */
if( c==cEnd ){
cEnd = 0;
}else if( c=='"' || c=='\'' || c=='`' ){
cEnd = c;
}else if( c=='[' ){
cEnd = ']';
+ }else if( c=='-' && z[i+1]=='-' ){
+ cEnd = '\n';
}else if( c=='(' ){
nParen++;
}else if( c==')' ){
nParen--;
if( nLine>0 && nParen==0 && j>0 ){
- utf8_printf(p->out, "%.*s\n", j, z);
+ printSchemaLineN(p->out, z, j, "\n");
j = 0;
}
}
z[j++] = c;
- if( nParen==1 && (c=='(' || c==',' || c=='\n') ){
+ if( nParen==1 && cEnd==0
+ && (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
+ ){
if( c=='\n' ) j--;
- utf8_printf(p->out, "%.*s\n ", j, z);
+ printSchemaLineN(p->out, z, j, "\n ");
j = 0;
nLine++;
while( IsSpace(z[i+1]) ){ i++; }
@@ -1121,7 +11691,7 @@ static int shell_callback(
}
z[j] = 0;
}
- utf8_printf(p->out, "%s;\n", z);
+ printSchemaLine(p->out, z, ";\n");
sqlite3_free(z);
break;
}
@@ -1199,41 +11769,139 @@ static int shell_callback(
break;
}
case MODE_Insert: {
- p->cnt++;
if( azArg==0 ) break;
utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
if( p->showHeader ){
raw_printf(p->out,"(");
for(i=0; i<nArg; i++){
- char *zSep = i>0 ? ",": "";
- utf8_printf(p->out, "%s%s", zSep, azCol[i]);
+ if( i>0 ) raw_printf(p->out, ",");
+ if( quoteChar(azCol[i]) ){
+ char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
+ utf8_printf(p->out, "%s", z);
+ sqlite3_free(z);
+ }else{
+ raw_printf(p->out, "%s", azCol[i]);
+ }
}
raw_printf(p->out,")");
}
- raw_printf(p->out," VALUES(");
+ p->cnt++;
+ for(i=0; i<nArg; i++){
+ raw_printf(p->out, i>0 ? "," : " VALUES(");
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ utf8_printf(p->out,"NULL");
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ if( ShellHasFlag(p, SHFLG_Newlines) ){
+ output_quoted_string(p->out, azArg[i]);
+ }else{
+ output_quoted_escaped_string(p->out, azArg[i]);
+ }
+ }else if( aiType && aiType[i]==SQLITE_INTEGER ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_uint64 ur;
+ memcpy(&ur,&r,sizeof(r));
+ if( ur==0x7ff0000000000000LL ){
+ raw_printf(p->out, "1e999");
+ }else if( ur==0xfff0000000000000LL ){
+ raw_printf(p->out, "-1e999");
+ }else{
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_hex_blob(p->out, pBlob, nBlob);
+ }else if( isNumber(azArg[i], 0) ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( ShellHasFlag(p, SHFLG_Newlines) ){
+ output_quoted_string(p->out, azArg[i]);
+ }else{
+ output_quoted_escaped_string(p->out, azArg[i]);
+ }
+ }
+ raw_printf(p->out,");\n");
+ break;
+ }
+ case MODE_Json: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 ){
+ fputs("[{", p->out);
+ }else{
+ fputs(",\n{", p->out);
+ }
+ p->cnt++;
for(i=0; i<nArg; i++){
- char *zSep = i>0 ? ",": "";
+ output_json_string(p->out, azCol[i], -1);
+ putc(':', p->out);
if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
- utf8_printf(p->out,"%sNULL",zSep);
+ fputs("null",p->out);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_uint64 ur;
+ memcpy(&ur,&r,sizeof(r));
+ if( ur==0x7ff0000000000000LL ){
+ raw_printf(p->out, "1e999");
+ }else if( ur==0xfff0000000000000LL ){
+ raw_printf(p->out, "-1e999");
+ }else{
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
+ }
+ }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
+ const void *pBlob = sqlite3_column_blob(p->pStmt, i);
+ int nBlob = sqlite3_column_bytes(p->pStmt, i);
+ output_json_string(p->out, pBlob, nBlob);
+ }else if( aiType && aiType[i]==SQLITE_TEXT ){
+ output_json_string(p->out, azArg[i], -1);
+ }else{
+ utf8_printf(p->out,"%s", azArg[i]);
+ }
+ if( i<nArg-1 ){
+ putc(',', p->out);
+ }
+ }
+ putc('}', p->out);
+ break;
+ }
+ case MODE_Quote: {
+ if( azArg==0 ) break;
+ if( p->cnt==0 && p->showHeader ){
+ for(i=0; i<nArg; i++){
+ if( i>0 ) fputs(p->colSeparator, p->out);
+ output_quoted_string(p->out, azCol[i]);
+ }
+ fputs(p->rowSeparator, p->out);
+ }
+ p->cnt++;
+ for(i=0; i<nArg; i++){
+ if( i>0 ) fputs(p->colSeparator, p->out);
+ if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
+ utf8_printf(p->out,"NULL");
}else if( aiType && aiType[i]==SQLITE_TEXT ){
- if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
output_quoted_string(p->out, azArg[i]);
- }else if( aiType && (aiType[i]==SQLITE_INTEGER
- || aiType[i]==SQLITE_FLOAT) ){
- utf8_printf(p->out,"%s%s",zSep, azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_INTEGER ){
+ utf8_printf(p->out,"%s", azArg[i]);
+ }else if( aiType && aiType[i]==SQLITE_FLOAT ){
+ char z[50];
+ double r = sqlite3_column_double(p->pStmt, i);
+ sqlite3_snprintf(50,z,"%!.20g", r);
+ raw_printf(p->out, "%s", z);
}else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
const void *pBlob = sqlite3_column_blob(p->pStmt, i);
int nBlob = sqlite3_column_bytes(p->pStmt, i);
- if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
output_hex_blob(p->out, pBlob, nBlob);
}else if( isNumber(azArg[i], 0) ){
- utf8_printf(p->out,"%s%s",zSep, azArg[i]);
+ utf8_printf(p->out,"%s", azArg[i]);
}else{
- if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
output_quoted_string(p->out, azArg[i]);
}
}
- raw_printf(p->out,");\n");
+ fputs(p->rowSeparator, p->out);
break;
}
case MODE_Ascii: {
@@ -1252,6 +11920,10 @@ static int shell_callback(
utf8_printf(p->out, "%s", p->rowSeparator);
break;
}
+ case MODE_EQP: {
+ eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]);
+ break;
+ }
}
return 0;
}
@@ -1266,13 +11938,79 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){
}
/*
+** This is the callback routine from sqlite3_exec() that appends all
+** output onto the end of a ShellText object.
+*/
+static int captureOutputCallback(void *pArg, int nArg, char **azArg, char **az){
+ ShellText *p = (ShellText*)pArg;
+ int i;
+ UNUSED_PARAMETER(az);
+ if( azArg==0 ) return 0;
+ if( p->n ) appendText(p, "|", 0);
+ for(i=0; i<nArg; i++){
+ if( i ) appendText(p, ",", 0);
+ if( azArg[i] ) appendText(p, azArg[i], 0);
+ }
+ return 0;
+}
+
+/*
+** Generate an appropriate SELFTEST table in the main database.
+*/
+static void createSelftestTable(ShellState *p){
+ char *zErrMsg = 0;
+ sqlite3_exec(p->db,
+ "SAVEPOINT selftest_init;\n"
+ "CREATE TABLE IF NOT EXISTS selftest(\n"
+ " tno INTEGER PRIMARY KEY,\n" /* Test number */
+ " op TEXT,\n" /* Operator: memo run */
+ " cmd TEXT,\n" /* Command text */
+ " ans TEXT\n" /* Desired answer */
+ ");"
+ "CREATE TEMP TABLE [_shell$self](op,cmd,ans);\n"
+ "INSERT INTO [_shell$self](rowid,op,cmd)\n"
+ " VALUES(coalesce((SELECT (max(tno)+100)/10 FROM selftest),10),\n"
+ " 'memo','Tests generated by --init');\n"
+ "INSERT INTO [_shell$self]\n"
+ " SELECT 'run',\n"
+ " 'SELECT hex(sha3_query(''SELECT type,name,tbl_name,sql "
+ "FROM sqlite_schema ORDER BY 2'',224))',\n"
+ " hex(sha3_query('SELECT type,name,tbl_name,sql "
+ "FROM sqlite_schema ORDER BY 2',224));\n"
+ "INSERT INTO [_shell$self]\n"
+ " SELECT 'run',"
+ " 'SELECT hex(sha3_query(''SELECT * FROM \"' ||"
+ " printf('%w',name) || '\" NOT INDEXED'',224))',\n"
+ " hex(sha3_query(printf('SELECT * FROM \"%w\" NOT INDEXED',name),224))\n"
+ " FROM (\n"
+ " SELECT name FROM sqlite_schema\n"
+ " WHERE type='table'\n"
+ " AND name<>'selftest'\n"
+ " AND coalesce(rootpage,0)>0\n"
+ " )\n"
+ " ORDER BY name;\n"
+ "INSERT INTO [_shell$self]\n"
+ " VALUES('run','PRAGMA integrity_check','ok');\n"
+ "INSERT INTO selftest(tno,op,cmd,ans)"
+ " SELECT rowid*10,op,cmd,ans FROM [_shell$self];\n"
+ "DROP TABLE [_shell$self];"
+ ,0,0,&zErrMsg);
+ if( zErrMsg ){
+ utf8_printf(stderr, "SELFTEST initialization failure: %s\n", zErrMsg);
+ sqlite3_free(zErrMsg);
+ }
+ sqlite3_exec(p->db, "RELEASE selftest_init",0,0,0);
+}
+
+
+/*
** Set the destination table field of the ShellState structure to
** the name of the table given. Escape any quote characters in the
** table name.
*/
static void set_table_name(ShellState *p, const char *zName){
int i, n;
- int needQuote;
+ char cQuote;
char *z;
if( p->zDestTable ){
@@ -1280,74 +12018,21 @@ static void set_table_name(ShellState *p, const char *zName){
p->zDestTable = 0;
}
if( zName==0 ) return;
- needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
- for(i=n=0; zName[i]; i++, n++){
- if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
- needQuote = 1;
- if( zName[i]=='\'' ) n++;
- }
- }
- if( needQuote ) n += 2;
+ cQuote = quoteChar(zName);
+ n = strlen30(zName);
+ if( cQuote ) n += n+2;
z = p->zDestTable = malloc( n+1 );
- if( z==0 ){
- raw_printf(stderr,"Error: out of memory\n");
- exit(1);
- }
+ if( z==0 ) shell_out_of_memory();
n = 0;
- if( needQuote ) z[n++] = '\'';
+ if( cQuote ) z[n++] = cQuote;
for(i=0; zName[i]; i++){
z[n++] = zName[i];
- if( zName[i]=='\'' ) z[n++] = '\'';
+ if( zName[i]==cQuote ) z[n++] = cQuote;
}
- if( needQuote ) z[n++] = '\'';
+ if( cQuote ) z[n++] = cQuote;
z[n] = 0;
}
-/* zIn is either a pointer to a NULL-terminated string in memory obtained
-** from malloc(), or a NULL pointer. The string pointed to by zAppend is
-** added to zIn, and the result returned in memory obtained from malloc().
-** zIn, if it was not NULL, is freed.
-**
-** If the third argument, quote, is not '\0', then it is used as a
-** quote character for zAppend.
-*/
-static char *appendText(char *zIn, char const *zAppend, char quote){
- int len;
- int i;
- int nAppend = strlen30(zAppend);
- int nIn = (zIn?strlen30(zIn):0);
-
- len = nAppend+nIn+1;
- if( quote ){
- len += 2;
- for(i=0; i<nAppend; i++){
- if( zAppend[i]==quote ) len++;
- }
- }
-
- zIn = (char *)realloc(zIn, len);
- if( !zIn ){
- return 0;
- }
-
- if( quote ){
- char *zCsr = &zIn[nIn];
- *zCsr++ = quote;
- for(i=0; i<nAppend; i++){
- *zCsr++ = zAppend[i];
- if( zAppend[i]==quote ) *zCsr++ = quote;
- }
- *zCsr++ = quote;
- *zCsr++ = '\0';
- assert( (zCsr-zIn)==len );
- }else{
- memcpy(&zIn[nIn], zAppend, nAppend);
- zIn[len-1] = '\0';
- }
-
- return zIn;
-}
-
/*
** Execute a query statement that will generate SQL output. Print
@@ -1361,8 +12046,7 @@ static char *appendText(char *zIn, char const *zAppend, char quote){
*/
static int run_table_dump_query(
ShellState *p, /* Query context */
- const char *zSelect, /* SELECT statement to extract content */
- const char *zFirstRow /* Print before first row, if not NULL */
+ const char *zSelect /* SELECT statement to extract content */
){
sqlite3_stmt *pSelect;
int rc;
@@ -1379,10 +12063,6 @@ static int run_table_dump_query(
rc = sqlite3_step(pSelect);
nResult = sqlite3_column_count(pSelect);
while( rc==SQLITE_ROW ){
- if( zFirstRow ){
- utf8_printf(p->out, "%s", zFirstRow);
- zFirstRow = 0;
- }
z = (const char*)sqlite3_column_text(pSelect, 0);
utf8_printf(p->out, "%s", z);
for(i=1; i<nResult; i++){
@@ -1445,7 +12125,7 @@ static void displayLinuxIoStats(FILE *out){
};
int i;
for(i=0; i<ArraySize(aTrans); i++){
- int n = (int)strlen(aTrans[i].zPattern);
+ int n = strlen30(aTrans[i].zPattern);
if( strncmp(aTrans[i].zPattern, z, n)==0 ){
utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]);
break;
@@ -1456,6 +12136,31 @@ static void displayLinuxIoStats(FILE *out){
}
#endif
+/*
+** Display a single line of status using 64-bit values.
+*/
+static void displayStatLine(
+ ShellState *p, /* The shell context */
+ char *zLabel, /* Label for this one line */
+ char *zFormat, /* Format for the result */
+ int iStatusCtrl, /* Which status to display */
+ int bReset /* True to reset the stats */
+){
+ sqlite3_int64 iCur = -1;
+ sqlite3_int64 iHiwtr = -1;
+ int i, nPercent;
+ char zLine[200];
+ sqlite3_status64(iStatusCtrl, &iCur, &iHiwtr, bReset);
+ for(i=0, nPercent=0; zFormat[i]; i++){
+ if( zFormat[i]=='%' ) nPercent++;
+ }
+ if( nPercent>1 ){
+ sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iCur, iHiwtr);
+ }else{
+ sqlite3_snprintf(sizeof(zLine), zLine, zFormat, iHiwtr);
+ }
+ raw_printf(p->out, "%-36s %s\n", zLabel, zLine);
+}
/*
** Display memory stats.
@@ -1467,63 +12172,54 @@ static int display_stats(
){
int iCur;
int iHiwtr;
+ FILE *out;
+ if( pArg==0 || pArg->out==0 ) return 0;
+ out = pArg->out;
- if( pArg && pArg->out ){
-
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
- "Memory Used: %d (max %d) bytes\n",
- iCur, iHiwtr);
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n",
- iCur, iHiwtr);
- if( pArg->shellFlgs & SHFLG_Pagecache ){
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
- "Number of Pcache Pages Used: %d (max %d) pages\n",
- iCur, iHiwtr);
- }
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
- "Number of Pcache Overflow Bytes: %d (max %d) bytes\n",
- iCur, iHiwtr);
- if( pArg->shellFlgs & SHFLG_Scratch ){
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
- "Number of Scratch Allocations Used: %d (max %d)\n",
- iCur, iHiwtr);
+ if( pArg->pStmt && (pArg->statsOn & 2) ){
+ int nCol, i, x;
+ sqlite3_stmt *pStmt = pArg->pStmt;
+ char z[100];
+ nCol = sqlite3_column_count(pStmt);
+ raw_printf(out, "%-36s %d\n", "Number of output columns:", nCol);
+ for(i=0; i<nCol; i++){
+ sqlite3_snprintf(sizeof(z),z,"Column %d %nname:", i, &x);
+ utf8_printf(out, "%-36s %s\n", z, sqlite3_column_name(pStmt,i));
+#ifndef SQLITE_OMIT_DECLTYPE
+ sqlite3_snprintf(30, z+x, "declared type:");
+ utf8_printf(out, "%-36s %s\n", z, sqlite3_column_decltype(pStmt, i));
+#endif
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ sqlite3_snprintf(30, z+x, "database name:");
+ utf8_printf(out, "%-36s %s\n", z, sqlite3_column_database_name(pStmt,i));
+ sqlite3_snprintf(30, z+x, "table name:");
+ utf8_printf(out, "%-36s %s\n", z, sqlite3_column_table_name(pStmt,i));
+ sqlite3_snprintf(30, z+x, "origin name:");
+ utf8_printf(out, "%-36s %s\n", z, sqlite3_column_origin_name(pStmt,i));
+#endif
}
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out,
- "Number of Scratch Overflow Bytes: %d (max %d) bytes\n",
- iCur, iHiwtr);
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Largest Allocation: %d bytes\n",
- iHiwtr);
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Largest Pcache Allocation: %d bytes\n",
- iHiwtr);
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Largest Scratch Allocation: %d bytes\n",
- iHiwtr);
+ }
+
+ displayStatLine(pArg, "Memory Used:",
+ "%lld (max %lld) bytes", SQLITE_STATUS_MEMORY_USED, bReset);
+ displayStatLine(pArg, "Number of Outstanding Allocations:",
+ "%lld (max %lld)", SQLITE_STATUS_MALLOC_COUNT, bReset);
+ if( pArg->shellFlgs & SHFLG_Pagecache ){
+ displayStatLine(pArg, "Number of Pcache Pages Used:",
+ "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset);
+ }
+ displayStatLine(pArg, "Number of Pcache Overflow Bytes:",
+ "%lld (max %lld) bytes", SQLITE_STATUS_PAGECACHE_OVERFLOW, bReset);
+ displayStatLine(pArg, "Largest Allocation:",
+ "%lld bytes", SQLITE_STATUS_MALLOC_SIZE, bReset);
+ displayStatLine(pArg, "Largest Pcache Allocation:",
+ "%lld bytes", SQLITE_STATUS_PAGECACHE_SIZE, bReset);
#ifdef YYTRACKMAXSTACKDEPTH
- iHiwtr = iCur = -1;
- sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
- raw_printf(pArg->out, "Deepest Parser Stack: %d (max %d)\n",
- iCur, iHiwtr);
+ displayStatLine(pArg, "Deepest Parser Stack:",
+ "%lld (max %lld)", SQLITE_STATUS_PARSER_STACK, bReset);
#endif
- }
- if( pArg && pArg->out && db ){
+ if( db ){
if( pArg->shellFlgs & SHFLG_Lookaside ){
iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
@@ -1558,6 +12254,9 @@ static int display_stats(
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHiwtr, 1);
raw_printf(pArg->out, "Page cache writes: %d\n", iCur);
iHiwtr = iCur = -1;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_SPILL, &iCur, &iHiwtr, 1);
+ raw_printf(pArg->out, "Page cache spills: %d\n", iCur);
+ iHiwtr = iCur = -1;
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
raw_printf(pArg->out, "Schema Heap Usage: %d bytes\n",
iCur);
@@ -1567,7 +12266,7 @@ static int display_stats(
iCur);
}
- if( pArg && pArg->out && db && pArg->pStmt ){
+ if( pArg->pStmt ){
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
bReset);
raw_printf(pArg->out, "Fullscan Steps: %d\n", iCur);
@@ -1577,6 +12276,12 @@ static int display_stats(
raw_printf(pArg->out, "Autoindex Inserts: %d\n", iCur);
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
raw_printf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_REPREPARE,bReset);
+ raw_printf(pArg->out, "Reprepare operations: %d\n", iCur);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_RUN, bReset);
+ raw_printf(pArg->out, "Number of times run: %d\n", iCur);
+ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_MEMUSED, bReset);
+ raw_printf(pArg->out, "Memory used by prepared stmt: %d\n", iCur);
}
#ifdef __linux__
@@ -1675,8 +12380,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
int iOp; /* Index of operation in p->aiIndent[] */
- const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
- "NextIfOpen", "PrevIfOpen", 0 };
+ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
"Rewind", 0 };
const char *azGoto[] = { "Goto", 0 };
@@ -1726,7 +12430,9 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
}
nAlloc += 100;
p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
+ if( p->aiIndent==0 ) shell_out_of_memory();
abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
+ if( abYield==0 ) shell_out_of_memory();
}
abYield[iOp] = str_in_array(zOp, azYield);
p->aiIndent[iOp] = 0;
@@ -1761,7 +12467,7 @@ static void explain_data_delete(ShellState *p){
** Disable and restore .wheretrace and .selecttrace settings.
*/
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
-extern int sqlite3SelectTrace;
+extern unsigned int sqlite3_unsupported_selecttrace;
static int savedSelectTrace;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
@@ -1770,8 +12476,8 @@ static int savedWhereTrace;
#endif
static void disable_debug_trace_modes(void){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- savedSelectTrace = sqlite3SelectTrace;
- sqlite3SelectTrace = 0;
+ savedSelectTrace = sqlite3_unsupported_selecttrace;
+ sqlite3_unsupported_selecttrace = 0;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
savedWhereTrace = sqlite3WhereTrace;
@@ -1780,80 +12486,505 @@ static void disable_debug_trace_modes(void){
}
static void restore_debug_trace_modes(void){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
- sqlite3SelectTrace = savedSelectTrace;
+ sqlite3_unsupported_selecttrace = savedSelectTrace;
#endif
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
sqlite3WhereTrace = savedWhereTrace;
#endif
}
+/* Create the TEMP table used to store parameter bindings */
+static void bind_table_init(ShellState *p){
+ int wrSchema = 0;
+ int defensiveMode = 0;
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, -1, &defensiveMode);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, -1, &wrSchema);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, 1, 0);
+ sqlite3_exec(p->db,
+ "CREATE TABLE IF NOT EXISTS temp.sqlite_parameters(\n"
+ " key TEXT PRIMARY KEY,\n"
+ " value ANY\n"
+ ") WITHOUT ROWID;",
+ 0, 0, 0);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 0);
+ sqlite3_db_config(p->db, SQLITE_DBCONFIG_DEFENSIVE, defensiveMode, 0);
+}
+
+/*
+** Bind parameters on a prepared statement.
+**
+** Parameter bindings are taken from a TEMP table of the form:
+**
+** CREATE TEMP TABLE sqlite_parameters(key TEXT PRIMARY KEY, value)
+** WITHOUT ROWID;
+**
+** No bindings occur if this table does not exist. The name of the table
+** begins with "sqlite_" so that it will not collide with ordinary application
+** tables. The table must be in the TEMP schema.
+*/
+static void bind_prepared_stmt(ShellState *pArg, sqlite3_stmt *pStmt){
+ int nVar;
+ int i;
+ int rc;
+ sqlite3_stmt *pQ = 0;
+
+ nVar = sqlite3_bind_parameter_count(pStmt);
+ if( nVar==0 ) return; /* Nothing to do */
+ if( sqlite3_table_column_metadata(pArg->db, "TEMP", "sqlite_parameters",
+ "key", 0, 0, 0, 0, 0)!=SQLITE_OK ){
+ return; /* Parameter table does not exist */
+ }
+ rc = sqlite3_prepare_v2(pArg->db,
+ "SELECT value FROM temp.sqlite_parameters"
+ " WHERE key=?1", -1, &pQ, 0);
+ if( rc || pQ==0 ) return;
+ for(i=1; i<=nVar; i++){
+ char zNum[30];
+ const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
+ if( zVar==0 ){
+ sqlite3_snprintf(sizeof(zNum),zNum,"?%d",i);
+ zVar = zNum;
+ }
+ sqlite3_bind_text(pQ, 1, zVar, -1, SQLITE_STATIC);
+ if( sqlite3_step(pQ)==SQLITE_ROW ){
+ sqlite3_bind_value(pStmt, i, sqlite3_column_value(pQ, 0));
+ }else{
+ sqlite3_bind_null(pStmt, i);
+ }
+ sqlite3_reset(pQ);
+ }
+ sqlite3_finalize(pQ);
+}
+
+/*
+** UTF8 box-drawing characters. Imagine box lines like this:
+**
+** 1
+** |
+** 4 --+-- 2
+** |
+** 3
+**
+** Each box characters has between 2 and 4 of the lines leading from
+** the center. The characters are here identified by the numbers of
+** their corresponding lines.
+*/
+#define BOX_24 "\342\224\200" /* U+2500 --- */
+#define BOX_13 "\342\224\202" /* U+2502 | */
+#define BOX_23 "\342\224\214" /* U+250c ,- */
+#define BOX_34 "\342\224\220" /* U+2510 -, */
+#define BOX_12 "\342\224\224" /* U+2514 '- */
+#define BOX_14 "\342\224\230" /* U+2518 -' */
+#define BOX_123 "\342\224\234" /* U+251c |- */
+#define BOX_134 "\342\224\244" /* U+2524 -| */
+#define BOX_234 "\342\224\254" /* U+252c -,- */
+#define BOX_124 "\342\224\264" /* U+2534 -'- */
+#define BOX_1234 "\342\224\274" /* U+253c -|- */
+
+/* Draw horizontal line N characters long using unicode box
+** characters
+*/
+static void print_box_line(FILE *out, int N){
+ const char zDash[] =
+ BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24
+ BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24 BOX_24;
+ const int nDash = sizeof(zDash) - 1;
+ N *= 3;
+ while( N>nDash ){
+ utf8_printf(out, zDash);
+ N -= nDash;
+ }
+ utf8_printf(out, "%.*s", N, zDash);
+}
+
+/*
+** Draw a horizontal separator for a MODE_Box table.
+*/
+static void print_box_row_separator(
+ ShellState *p,
+ int nArg,
+ const char *zSep1,
+ const char *zSep2,
+ const char *zSep3
+){
+ int i;
+ if( nArg>0 ){
+ utf8_printf(p->out, "%s", zSep1);
+ print_box_line(p->out, p->actualWidth[0]+2);
+ for(i=1; i<nArg; i++){
+ utf8_printf(p->out, "%s", zSep2);
+ print_box_line(p->out, p->actualWidth[i]+2);
+ }
+ utf8_printf(p->out, "%s", zSep3);
+ }
+ fputs("\n", p->out);
+}
+
+
+
+/*
+** Run a prepared statement and output the result in one of the
+** table-oriented formats: MODE_Column, MODE_Markdown, MODE_Table,
+** or MODE_Box.
+**
+** This is different from ordinary exec_prepared_stmt() in that
+** it has to run the entire query and gather the results into memory
+** first, in order to determine column widths, before providing
+** any output.
+*/
+static void exec_prepared_stmt_columnar(
+ ShellState *p, /* Pointer to ShellState */
+ sqlite3_stmt *pStmt /* Statment to run */
+){
+ sqlite3_int64 nRow = 0;
+ int nColumn = 0;
+ char **azData = 0;
+ sqlite3_int64 nAlloc = 0;
+ const char *z;
+ int rc;
+ sqlite3_int64 i, nData;
+ int j, nTotal, w, n;
+ const char *colSep = 0;
+ const char *rowSep = 0;
+
+ rc = sqlite3_step(pStmt);
+ if( rc!=SQLITE_ROW ) return;
+ nColumn = sqlite3_column_count(pStmt);
+ nAlloc = nColumn*4;
+ azData = sqlite3_malloc64( nAlloc*sizeof(char*) );
+ if( azData==0 ) shell_out_of_memory();
+ for(i=0; i<nColumn; i++){
+ azData[i] = strdup(sqlite3_column_name(pStmt,i));
+ }
+ do{
+ if( (nRow+2)*nColumn >= nAlloc ){
+ nAlloc *= 2;
+ azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
+ if( azData==0 ) shell_out_of_memory();
+ }
+ nRow++;
+ for(i=0; i<nColumn; i++){
+ z = (const char*)sqlite3_column_text(pStmt,i);
+ azData[nRow*nColumn + i] = z ? strdup(z) : 0;
+ }
+ }while( (rc = sqlite3_step(pStmt))==SQLITE_ROW );
+ if( nColumn>p->nWidth ){
+ p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
+ if( p->colWidth==0 ) shell_out_of_memory();
+ for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
+ p->nWidth = nColumn;
+ p->actualWidth = &p->colWidth[nColumn];
+ }
+ memset(p->actualWidth, 0, nColumn*sizeof(int));
+ for(i=0; i<nColumn; i++){
+ w = p->colWidth[i];
+ if( w<0 ) w = -w;
+ p->actualWidth[i] = w;
+ }
+ nTotal = nColumn*(nRow+1);
+ for(i=0; i<nTotal; i++){
+ z = azData[i];
+ if( z==0 ) z = p->nullValue;
+ n = strlenChar(z);
+ j = i%nColumn;
+ if( n>p->actualWidth[j] ) p->actualWidth[j] = n;
+ }
+ if( seenInterrupt ) goto columnar_end;
+ switch( p->cMode ){
+ case MODE_Column: {
+ colSep = " ";
+ rowSep = "\n";
+ if( p->showHeader ){
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ if( p->colWidth[i]<0 ) w = -w;
+ utf8_width_print(p->out, w, azData[i]);
+ fputs(i==nColumn-1?"\n":" ", p->out);
+ }
+ for(i=0; i<nColumn; i++){
+ print_dashes(p->out, p->actualWidth[i]);
+ fputs(i==nColumn-1?"\n":" ", p->out);
+ }
+ }
+ break;
+ }
+ case MODE_Table: {
+ colSep = " | ";
+ rowSep = " |\n";
+ print_row_separator(p, nColumn, "+");
+ fputs("| ", p->out);
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", p->out);
+ }
+ print_row_separator(p, nColumn, "+");
+ break;
+ }
+ case MODE_Markdown: {
+ colSep = " | ";
+ rowSep = " |\n";
+ fputs("| ", p->out);
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s", (w-n)/2, "", azData[i], (w-n+1)/2, "");
+ fputs(i==nColumn-1?" |\n":" | ", p->out);
+ }
+ print_row_separator(p, nColumn, "|");
+ break;
+ }
+ case MODE_Box: {
+ colSep = " " BOX_13 " ";
+ rowSep = " " BOX_13 "\n";
+ print_box_row_separator(p, nColumn, BOX_23, BOX_234, BOX_34);
+ utf8_printf(p->out, BOX_13 " ");
+ for(i=0; i<nColumn; i++){
+ w = p->actualWidth[i];
+ n = strlenChar(azData[i]);
+ utf8_printf(p->out, "%*s%s%*s%s",
+ (w-n)/2, "", azData[i], (w-n+1)/2, "",
+ i==nColumn-1?" "BOX_13"\n":" "BOX_13" ");
+ }
+ print_box_row_separator(p, nColumn, BOX_123, BOX_1234, BOX_134);
+ break;
+ }
+ }
+ for(i=nColumn, j=0; i<nTotal; i++, j++){
+ if( j==0 && p->cMode!=MODE_Column ){
+ utf8_printf(p->out, "%s", p->cMode==MODE_Box?BOX_13" ":"| ");
+ }
+ z = azData[i];
+ if( z==0 ) z = p->nullValue;
+ w = p->actualWidth[j];
+ if( p->colWidth[j]<0 ) w = -w;
+ utf8_width_print(p->out, w, z);
+ if( j==nColumn-1 ){
+ utf8_printf(p->out, "%s", rowSep);
+ j = -1;
+ if( seenInterrupt ) goto columnar_end;
+ }else{
+ utf8_printf(p->out, "%s", colSep);
+ }
+ }
+ if( p->cMode==MODE_Table ){
+ print_row_separator(p, nColumn, "+");
+ }else if( p->cMode==MODE_Box ){
+ print_box_row_separator(p, nColumn, BOX_12, BOX_124, BOX_14);
+ }
+columnar_end:
+ if( seenInterrupt ){
+ utf8_printf(p->out, "Interrupt\n");
+ }
+ nData = (nRow+1)*nColumn;
+ for(i=0; i<nData; i++) free(azData[i]);
+ sqlite3_free(azData);
+}
+
/*
** Run a prepared statement
*/
static void exec_prepared_stmt(
ShellState *pArg, /* Pointer to ShellState */
- sqlite3_stmt *pStmt, /* Statment to run */
- int (*xCallback)(void*,int,char**,char**,int*) /* Callback function */
+ sqlite3_stmt *pStmt /* Statment to run */
){
int rc;
+ if( pArg->cMode==MODE_Column
+ || pArg->cMode==MODE_Table
+ || pArg->cMode==MODE_Box
+ || pArg->cMode==MODE_Markdown
+ ){
+ exec_prepared_stmt_columnar(pArg, pStmt);
+ return;
+ }
+
/* perform the first step. this will tell us if we
** have a result set or not and how wide it is.
*/
rc = sqlite3_step(pStmt);
/* if we have a result set... */
if( SQLITE_ROW == rc ){
- /* if we have a callback... */
- if( xCallback ){
- /* allocate space for col name ptr, value ptr, and type */
- int nCol = sqlite3_column_count(pStmt);
- void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
- if( !pData ){
- rc = SQLITE_NOMEM;
- }else{
- char **azCols = (char **)pData; /* Names of result columns */
- char **azVals = &azCols[nCol]; /* Results */
- int *aiTypes = (int *)&azVals[nCol]; /* Result types */
- int i, x;
- assert(sizeof(int) <= sizeof(char *));
- /* save off ptrs to column names */
+ /* allocate space for col name ptr, value ptr, and type */
+ int nCol = sqlite3_column_count(pStmt);
+ void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
+ if( !pData ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char **azCols = (char **)pData; /* Names of result columns */
+ char **azVals = &azCols[nCol]; /* Results */
+ int *aiTypes = (int *)&azVals[nCol]; /* Result types */
+ int i, x;
+ assert(sizeof(int) <= sizeof(char *));
+ /* save off ptrs to column names */
+ for(i=0; i<nCol; i++){
+ azCols[i] = (char *)sqlite3_column_name(pStmt, i);
+ }
+ do{
+ /* extract the data and data types */
for(i=0; i<nCol; i++){
- azCols[i] = (char *)sqlite3_column_name(pStmt, i);
- }
- do{
- /* extract the data and data types */
- for(i=0; i<nCol; i++){
- aiTypes[i] = x = sqlite3_column_type(pStmt, i);
- if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
- azVals[i] = "";
- }else{
- azVals[i] = (char*)sqlite3_column_text(pStmt, i);
- }
- if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
- rc = SQLITE_NOMEM;
- break; /* from for */
- }
- } /* end for */
+ aiTypes[i] = x = sqlite3_column_type(pStmt, i);
+ if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){
+ azVals[i] = "";
+ }else{
+ azVals[i] = (char*)sqlite3_column_text(pStmt, i);
+ }
+ if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
+ rc = SQLITE_NOMEM;
+ break; /* from for */
+ }
+ } /* end for */
- /* if data and types extracted successfully... */
- if( SQLITE_ROW == rc ){
- /* call the supplied callback with the result row data */
- if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
- rc = SQLITE_ABORT;
- }else{
- rc = sqlite3_step(pStmt);
- }
+ /* if data and types extracted successfully... */
+ if( SQLITE_ROW == rc ){
+ /* call the supplied callback with the result row data */
+ if( shell_callback(pArg, nCol, azVals, azCols, aiTypes) ){
+ rc = SQLITE_ABORT;
+ }else{
+ rc = sqlite3_step(pStmt);
}
- } while( SQLITE_ROW == rc );
- sqlite3_free(pData);
+ }
+ } while( SQLITE_ROW == rc );
+ sqlite3_free(pData);
+ if( pArg->cMode==MODE_Json ){
+ fputs("]\n", pArg->out);
}
+ }
+ }
+}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** This function is called to process SQL if the previous shell command
+** was ".expert". It passes the SQL in the second argument directly to
+** the sqlite3expert object.
+**
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
+** code. In this case, (*pzErr) may be set to point to a buffer containing
+** an English language error message. It is the responsibility of the
+** caller to eventually free this buffer using sqlite3_free().
+*/
+static int expertHandleSQL(
+ ShellState *pState,
+ const char *zSql,
+ char **pzErr
+){
+ assert( pState->expert.pExpert );
+ assert( pzErr==0 || *pzErr==0 );
+ return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr);
+}
+
+/*
+** This function is called either to silently clean up the object
+** created by the ".expert" command (if bCancel==1), or to generate a
+** report from it and then clean it up (if bCancel==0).
+**
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error
+** code. In this case, (*pzErr) may be set to point to a buffer containing
+** an English language error message. It is the responsibility of the
+** caller to eventually free this buffer using sqlite3_free().
+*/
+static int expertFinish(
+ ShellState *pState,
+ int bCancel,
+ char **pzErr
+){
+ int rc = SQLITE_OK;
+ sqlite3expert *p = pState->expert.pExpert;
+ assert( p );
+ assert( bCancel || pzErr==0 || *pzErr==0 );
+ if( bCancel==0 ){
+ FILE *out = pState->out;
+ int bVerbose = pState->expert.bVerbose;
+
+ rc = sqlite3_expert_analyze(p, pzErr);
+ if( rc==SQLITE_OK ){
+ int nQuery = sqlite3_expert_count(p);
+ int i;
+
+ if( bVerbose ){
+ const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
+ raw_printf(out, "-- Candidates -----------------------------\n");
+ raw_printf(out, "%s\n", zCand);
+ }
+ for(i=0; i<nQuery; i++){
+ const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
+ const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
+ const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
+ if( zIdx==0 ) zIdx = "(no new indexes)\n";
+ if( bVerbose ){
+ raw_printf(out, "-- Query %d --------------------------------\n",i+1);
+ raw_printf(out, "%s\n\n", zSql);
+ }
+ raw_printf(out, "%s\n", zIdx);
+ raw_printf(out, "%s\n", zEQP);
+ }
+ }
+ }
+ sqlite3_expert_destroy(p);
+ pState->expert.pExpert = 0;
+ return rc;
+}
+
+/*
+** Implementation of ".expert" dot command.
+*/
+static int expertDotCommand(
+ ShellState *pState, /* Current shell tool state */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+ int i;
+ int iSample = 0;
+
+ assert( pState->expert.pExpert==0 );
+ memset(&pState->expert, 0, sizeof(ExpertInfo));
+
+ for(i=1; rc==SQLITE_OK && i<nArg; i++){
+ char *z = azArg[i];
+ int n;
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ n = strlen30(z);
+ if( n>=2 && 0==strncmp(z, "-verbose", n) ){
+ pState->expert.bVerbose = 1;
+ }
+ else if( n>=2 && 0==strncmp(z, "-sample", n) ){
+ if( i==(nArg-1) ){
+ raw_printf(stderr, "option requires an argument: %s\n", z);
+ rc = SQLITE_ERROR;
+ }else{
+ iSample = (int)integerValue(azArg[++i]);
+ if( iSample<0 || iSample>100 ){
+ raw_printf(stderr, "value out of range: %s\n", azArg[i]);
+ rc = SQLITE_ERROR;
+ }
+ }
+ }
+ else{
+ raw_printf(stderr, "unknown option: %s\n", z);
+ rc = SQLITE_ERROR;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr);
+ if( pState->expert.pExpert==0 ){
+ raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr);
+ rc = SQLITE_ERROR;
}else{
- do{
- rc = sqlite3_step(pStmt);
- } while( rc == SQLITE_ROW );
+ sqlite3_expert_config(
+ pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample
+ );
}
}
+
+ return rc;
}
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
/*
** Execute a statement or set of statements. Print
@@ -1865,22 +12996,27 @@ static void exec_prepared_stmt(
** and callback data argument.
*/
static int shell_exec(
- sqlite3 *db, /* An open database */
- const char *zSql, /* SQL to be evaluated */
- int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */
- /* (not the same as sqlite3_exec) */
ShellState *pArg, /* Pointer to ShellState */
+ const char *zSql, /* SQL to be evaluated */
char **pzErrMsg /* Error msg written here */
){
sqlite3_stmt *pStmt = NULL; /* Statement to execute. */
int rc = SQLITE_OK; /* Return Code */
int rc2;
const char *zLeftover; /* Tail of unprocessed SQL */
+ sqlite3 *db = pArg->db;
if( pzErrMsg ){
*pzErrMsg = NULL;
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pArg->expert.pExpert ){
+ rc = expertHandleSQL(pArg, zSql, pzErrMsg);
+ return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg);
+ }
+#endif
+
while( zSql[0] && (SQLITE_OK == rc) ){
static const char *zStmtSql;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
@@ -1896,6 +13032,7 @@ static int shell_exec(
continue;
}
zStmtSql = sqlite3_sql(pStmt);
+ if( zStmtSql==0 ) zStmtSql = "";
while( IsSpace(zStmtSql[0]) ) zStmtSql++;
/* save off the prepared statment handle and reset row count */
@@ -1905,50 +13042,67 @@ static int shell_exec(
}
/* echo the sql statement if echo on */
- if( pArg && pArg->echoOn ){
+ if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){
utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
}
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
- if( pArg && pArg->autoEQP && sqlite3_strlike("EXPLAIN%",zStmtSql,0)!=0 ){
+ if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){
sqlite3_stmt *pExplain;
char *zEQP;
+ int triggerEQP = 0;
disable_debug_trace_modes();
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, -1, &triggerEQP);
+ if( pArg->autoEQP>=AUTOEQP_trigger ){
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0);
+ }
zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
while( sqlite3_step(pExplain)==SQLITE_ROW ){
- raw_printf(pArg->out,"--EQP-- %d,",sqlite3_column_int(pExplain, 0));
- raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 1));
- raw_printf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
- utf8_printf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
+ const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
+ int iEqpId = sqlite3_column_int(pExplain, 0);
+ int iParentId = sqlite3_column_int(pExplain, 1);
+ if( zEQPLine==0 ) zEQPLine = "";
+ if( zEQPLine[0]=='-' ) eqp_render(pArg);
+ eqp_append(pArg, iEqpId, iParentId, zEQPLine);
}
+ eqp_render(pArg);
}
sqlite3_finalize(pExplain);
sqlite3_free(zEQP);
- if( pArg->autoEQP>=2 ){
+ if( pArg->autoEQP>=AUTOEQP_full ){
/* Also do an EXPLAIN for ".eqp full" mode */
zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql);
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
if( rc==SQLITE_OK ){
pArg->cMode = MODE_Explain;
explain_data_prepare(pArg, pExplain);
- exec_prepared_stmt(pArg, pExplain, xCallback);
+ exec_prepared_stmt(pArg, pExplain);
explain_data_delete(pArg);
}
sqlite3_finalize(pExplain);
sqlite3_free(zEQP);
}
+ if( pArg->autoEQP>=AUTOEQP_trigger && triggerEQP==0 ){
+ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 0, 0);
+ /* Reprepare pStmt before reactiving trace modes */
+ sqlite3_finalize(pStmt);
+ sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ if( pArg ) pArg->pStmt = pStmt;
+ }
restore_debug_trace_modes();
}
if( pArg ){
pArg->cMode = pArg->mode;
- if( pArg->autoExplain
- && sqlite3_column_count(pStmt)==8
- && sqlite3_strlike("EXPLAIN%", zStmtSql,0)==0
- ){
- pArg->cMode = MODE_Explain;
+ if( pArg->autoExplain ){
+ if( sqlite3_stmt_isexplain(pStmt)==1 ){
+ pArg->cMode = MODE_Explain;
+ }
+ if( sqlite3_stmt_isexplain(pStmt)==2 ){
+ pArg->cMode = MODE_EQP;
+ }
}
/* If the shell is currently in ".explain" mode, gather the extra
@@ -1958,8 +13112,10 @@ static int shell_exec(
}
}
- exec_prepared_stmt(pArg, pStmt, xCallback);
+ bind_prepared_stmt(pArg, pStmt);
+ exec_prepared_stmt(pArg, pStmt);
explain_data_delete(pArg);
+ eqp_render(pArg);
/* print usage stats if stats on */
if( pArg && pArg->statsOn ){
@@ -1993,6 +13149,135 @@ static int shell_exec(
return rc;
}
+/*
+** Release memory previously allocated by tableColumnList().
+*/
+static void freeColumnList(char **azCol){
+ int i;
+ for(i=1; azCol[i]; i++){
+ sqlite3_free(azCol[i]);
+ }
+ /* azCol[0] is a static string */
+ sqlite3_free(azCol);
+}
+
+/*
+** Return a list of pointers to strings which are the names of all
+** columns in table zTab. The memory to hold the names is dynamically
+** allocated and must be released by the caller using a subsequent call
+** to freeColumnList().
+**
+** The azCol[0] entry is usually NULL. However, if zTab contains a rowid
+** value that needs to be preserved, then azCol[0] is filled in with the
+** name of the rowid column.
+**
+** The first regular column in the table is azCol[1]. The list is terminated
+** by an entry with azCol[i]==0.
+*/
+static char **tableColumnList(ShellState *p, const char *zTab){
+ char **azCol = 0;
+ sqlite3_stmt *pStmt;
+ char *zSql;
+ int nCol = 0;
+ int nAlloc = 0;
+ int nPK = 0; /* Number of PRIMARY KEY columns seen */
+ int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */
+ int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid);
+ int rc;
+
+ zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ) return 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ if( nCol>=nAlloc-2 ){
+ nAlloc = nAlloc*2 + nCol + 10;
+ azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0]));
+ if( azCol==0 ) shell_out_of_memory();
+ }
+ azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
+ if( sqlite3_column_int(pStmt, 5) ){
+ nPK++;
+ if( nPK==1
+ && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2),
+ "INTEGER")==0
+ ){
+ isIPK = 1;
+ }else{
+ isIPK = 0;
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ if( azCol==0 ) return 0;
+ azCol[0] = 0;
+ azCol[nCol+1] = 0;
+
+ /* The decision of whether or not a rowid really needs to be preserved
+ ** is tricky. We never need to preserve a rowid for a WITHOUT ROWID table
+ ** or a table with an INTEGER PRIMARY KEY. We are unable to preserve
+ ** rowids on tables where the rowid is inaccessible because there are other
+ ** columns in the table named "rowid", "_rowid_", and "oid".
+ */
+ if( preserveRowid && isIPK ){
+ /* If a single PRIMARY KEY column with type INTEGER was seen, then it
+ ** might be an alise for the ROWID. But it might also be a WITHOUT ROWID
+ ** table or a INTEGER PRIMARY KEY DESC column, neither of which are
+ ** ROWID aliases. To distinguish these cases, check to see if
+ ** there is a "pk" entry in "PRAGMA index_list". There will be
+ ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID.
+ */
+ zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)"
+ " WHERE origin='pk'", zTab);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ){
+ freeColumnList(azCol);
+ return 0;
+ }
+ rc = sqlite3_step(pStmt);
+ sqlite3_finalize(pStmt);
+ preserveRowid = rc==SQLITE_ROW;
+ }
+ if( preserveRowid ){
+ /* Only preserve the rowid if we can find a name to use for the
+ ** rowid */
+ static char *azRowid[] = { "rowid", "_rowid_", "oid" };
+ int i, j;
+ for(j=0; j<3; j++){
+ for(i=1; i<=nCol; i++){
+ if( sqlite3_stricmp(azRowid[j],azCol[i])==0 ) break;
+ }
+ if( i>nCol ){
+ /* At this point, we know that azRowid[j] is not the name of any
+ ** ordinary column in the table. Verify that azRowid[j] is a valid
+ ** name for the rowid before adding it to azCol[0]. WITHOUT ROWID
+ ** tables will fail this last check */
+ rc = sqlite3_table_column_metadata(p->db,0,zTab,azRowid[j],0,0,0,0,0);
+ if( rc==SQLITE_OK ) azCol[0] = azRowid[j];
+ break;
+ }
+ }
+ }
+ return azCol;
+}
+
+/*
+** Toggle the reverse_unordered_selects setting.
+*/
+static void toggleSelectOrder(sqlite3 *db){
+ sqlite3_stmt *pStmt = 0;
+ int iSetting = 0;
+ char zStmt[100];
+ sqlite3_prepare_v2(db, "PRAGMA reverse_unordered_selects", -1, &pStmt, 0);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ iSetting = sqlite3_column_int(pStmt, 0);
+ }
+ sqlite3_finalize(pStmt);
+ sqlite3_snprintf(sizeof(zStmt), zStmt,
+ "PRAGMA reverse_unordered_selects(%d)", !iSetting);
+ sqlite3_exec(db, zStmt, 0, 0, 0);
+}
/*
** This is a different callback routine used for dumping the database.
@@ -2000,24 +13285,23 @@ static int shell_exec(
** the table type ("index" or "table") and SQL to create the table.
** This routine should print text sufficient to recreate the table.
*/
-static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
+static int dump_callback(void *pArg, int nArg, char **azArg, char **azNotUsed){
int rc;
const char *zTable;
const char *zType;
const char *zSql;
- const char *zPrepStmt = 0;
ShellState *p = (ShellState *)pArg;
- UNUSED_PARAMETER(azCol);
- if( nArg!=3 ) return 1;
+ UNUSED_PARAMETER(azNotUsed);
+ if( nArg!=3 || azArg==0 ) return 0;
zTable = azArg[0];
zType = azArg[1];
zSql = azArg[2];
if( strcmp(zTable, "sqlite_sequence")==0 ){
- zPrepStmt = "DELETE FROM sqlite_sequence;\n";
+ raw_printf(p->out, "DELETE FROM sqlite_sequence;\n");
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
}else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
@@ -2027,69 +13311,81 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
p->writableSchema = 1;
}
zIns = sqlite3_mprintf(
- "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)"
"VALUES('table','%q','%q',0,'%q');",
zTable, zTable, zSql);
utf8_printf(p->out, "%s\n", zIns);
sqlite3_free(zIns);
return 0;
}else{
- utf8_printf(p->out, "%s;\n", zSql);
+ printSchemaLine(p->out, zSql, ";\n");
}
if( strcmp(zType, "table")==0 ){
- sqlite3_stmt *pTableInfo = 0;
- char *zSelect = 0;
- char *zTableInfo = 0;
- char *zTmp = 0;
- int nRow = 0;
-
- zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
- zTableInfo = appendText(zTableInfo, zTable, '"');
- zTableInfo = appendText(zTableInfo, ");", 0);
-
- rc = sqlite3_prepare_v2(p->db, zTableInfo, -1, &pTableInfo, 0);
- free(zTableInfo);
- if( rc!=SQLITE_OK || !pTableInfo ){
- return 1;
+ ShellText sSelect;
+ ShellText sTable;
+ char **azCol;
+ int i;
+ char *savedDestTable;
+ int savedMode;
+
+ azCol = tableColumnList(p, zTable);
+ if( azCol==0 ){
+ p->nErr++;
+ return 0;
}
- zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
/* Always quote the table name, even if it appears to be pure ascii,
** in case it is a keyword. Ex: INSERT INTO "table" ... */
- zTmp = appendText(zTmp, zTable, '"');
- if( zTmp ){
- zSelect = appendText(zSelect, zTmp, '\'');
- free(zTmp);
- }
- zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
- rc = sqlite3_step(pTableInfo);
- while( rc==SQLITE_ROW ){
- const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
- zSelect = appendText(zSelect, "quote(", 0);
- zSelect = appendText(zSelect, zText, '"');
- rc = sqlite3_step(pTableInfo);
- if( rc==SQLITE_ROW ){
- zSelect = appendText(zSelect, "), ", 0);
- }else{
- zSelect = appendText(zSelect, ") ", 0);
+ initText(&sTable);
+ appendText(&sTable, zTable, quoteChar(zTable));
+ /* If preserving the rowid, add a column list after the table name.
+ ** In other words: "INSERT INTO tab(rowid,a,b,c,...) VALUES(...)"
+ ** instead of the usual "INSERT INTO tab VALUES(...)".
+ */
+ if( azCol[0] ){
+ appendText(&sTable, "(", 0);
+ appendText(&sTable, azCol[0], 0);
+ for(i=1; azCol[i]; i++){
+ appendText(&sTable, ",", 0);
+ appendText(&sTable, azCol[i], quoteChar(azCol[i]));
}
- nRow++;
- }
- rc = sqlite3_finalize(pTableInfo);
- if( rc!=SQLITE_OK || nRow==0 ){
- free(zSelect);
- return 1;
+ appendText(&sTable, ")", 0);
}
- zSelect = appendText(zSelect, "|| ')' FROM ", 0);
- zSelect = appendText(zSelect, zTable, '"');
- rc = run_table_dump_query(p, zSelect, zPrepStmt);
- if( rc==SQLITE_CORRUPT ){
- zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
- run_table_dump_query(p, zSelect, 0);
+ /* Build an appropriate SELECT statement */
+ initText(&sSelect);
+ appendText(&sSelect, "SELECT ", 0);
+ if( azCol[0] ){
+ appendText(&sSelect, azCol[0], 0);
+ appendText(&sSelect, ",", 0);
}
- free(zSelect);
+ for(i=1; azCol[i]; i++){
+ appendText(&sSelect, azCol[i], quoteChar(azCol[i]));
+ if( azCol[i+1] ){
+ appendText(&sSelect, ",", 0);
+ }
+ }
+ freeColumnList(azCol);
+ appendText(&sSelect, " FROM ", 0);
+ appendText(&sSelect, zTable, quoteChar(zTable));
+
+ savedDestTable = p->zDestTable;
+ savedMode = p->mode;
+ p->zDestTable = sTable.z;
+ p->mode = p->cMode = MODE_Insert;
+ rc = shell_exec(p, sSelect.z, 0);
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ raw_printf(p->out, "/****** CORRUPTION ERROR *******/\n");
+ toggleSelectOrder(p->db);
+ shell_exec(p, sSelect.z, 0);
+ toggleSelectOrder(p->db);
+ }
+ p->zDestTable = savedDestTable;
+ p->mode = savedMode;
+ freeText(&sTable);
+ freeText(&sSelect);
+ if( rc ) p->nErr++;
}
return 0;
}
@@ -2133,124 +13429,339 @@ static int run_schema_dump_query(
}
/*
-** Text of a help message
+** Text of help messages.
+**
+** The help text for each individual command begins with a line that starts
+** with ".". Subsequent lines are supplimental information.
+**
+** There must be two or more spaces between the end of the command and the
+** start of the description of what that command does.
*/
-static char zHelp[] =
+static const char *(azHelp[]) = {
+#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
+ ".archive ... Manage SQL archives",
+ " Each command must have exactly one of the following options:",
+ " -c, --create Create a new archive",
+ " -u, --update Add or update files with changed mtime",
+ " -i, --insert Like -u but always add even if unchanged",
+ " -t, --list List contents of archive",
+ " -x, --extract Extract files from archive",
+ " Optional arguments:",
+ " -v, --verbose Print each filename as it is processed",
+ " -f FILE, --file FILE Use archive FILE (default is current db)",
+ " -a FILE, --append FILE Open FILE using the apndvfs VFS",
+ " -C DIR, --directory DIR Read/extract files from directory DIR",
+ " -n, --dryrun Show the SQL that would have occurred",
+ " Examples:",
+ " .ar -cf ARCHIVE foo bar # Create ARCHIVE from files foo and bar",
+ " .ar -tf ARCHIVE # List members of ARCHIVE",
+ " .ar -xvf ARCHIVE # Verbosely extract files from ARCHIVE",
+ " See also:",
+ " http://sqlite.org/cli.html#sqlar_archive_support",
+#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
- ".auth ON|OFF Show authorizer callbacks\n"
-#endif
- ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
- ".bail on|off Stop after hitting an error. Default OFF\n"
- ".binary on|off Turn binary output on or off. Default OFF\n"
- ".changes on|off Show number of rows changed by SQL\n"
- ".check GLOB Fail if output since .testcase does not match\n"
- ".clone NEWDB Clone data into NEWDB from the existing database\n"
- ".databases List names and files of attached databases\n"
- ".dbinfo ?DB? Show status information about the database\n"
- ".dump ?TABLE? ... Dump the database in an SQL text format\n"
- " If TABLE specified, only dump tables matching\n"
- " LIKE pattern TABLE.\n"
- ".echo on|off Turn command echo on or off\n"
- ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n"
- ".exit Exit this program\n"
- ".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"
- ".fullschema ?--indent? Show schema and the content of sqlite_stat tables\n"
- ".headers on|off Turn display of headers on or off\n"
- ".help Show this message\n"
- ".import FILE TABLE Import data from FILE into TABLE\n"
- ".indexes ?TABLE? Show names of all indexes\n"
- " If TABLE specified, only show indexes for tables\n"
- " matching LIKE pattern TABLE.\n"
+ ".auth ON|OFF Show authorizer callbacks",
+#endif
+ ".backup ?DB? FILE Backup DB (default \"main\") to FILE",
+ " --append Use the appendvfs",
+ " --async Write to FILE without journal and fsync()",
+ ".bail on|off Stop after hitting an error. Default OFF",
+ ".binary on|off Turn binary output on or off. Default OFF",
+ ".cd DIRECTORY Change the working directory to DIRECTORY",
+ ".changes on|off Show number of rows changed by SQL",
+ ".check GLOB Fail if output since .testcase does not match",
+ ".clone NEWDB Clone data into NEWDB from the existing database",
+ ".databases List names and files of attached databases",
+ ".dbconfig ?op? ?val? List or change sqlite3_db_config() options",
+ ".dbinfo ?DB? Show status information about the database",
+ ".dump ?TABLE? Render database content as SQL",
+ " Options:",
+ " --preserve-rowids Include ROWID values in the output",
+ " --newlines Allow unescaped newline characters in output",
+ " TABLE is a LIKE pattern for the tables to dump",
+ " Additional LIKE patterns can be given in subsequent arguments",
+ ".echo on|off Turn command echo on or off",
+ ".eqp on|off|full|... Enable or disable automatic EXPLAIN QUERY PLAN",
+ " Other Modes:",
+#ifdef SQLITE_DEBUG
+ " test Show raw EXPLAIN QUERY PLAN output",
+ " trace Like \"full\" but enable \"PRAGMA vdbe_trace\"",
+#endif
+ " trigger Like \"full\" but also show trigger bytecode",
+ ".excel Display the output of next command in spreadsheet",
+ " --bom Put a UTF8 byte-order mark on intermediate file",
+ ".exit ?CODE? Exit this program with return-code CODE",
+ ".expert EXPERIMENTAL. Suggest indexes for queries",
+ ".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
+ ".filectrl CMD ... Run various sqlite3_file_control() operations",
+ " --schema SCHEMA Use SCHEMA instead of \"main\"",
+ " --help Show CMD details",
+ ".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
+ ".headers on|off Turn display of headers on or off",
+ ".help ?-all? ?PATTERN? Show help text for PATTERN",
+ ".import FILE TABLE Import data from FILE into TABLE",
+ " Options:",
+ " --ascii Use \\037 and \\036 as column and row separators",
+ " --csv Use , and \\n as column and row separators",
+ " --skip N Skip the first N rows of input",
+ " -v \"Verbose\" - increase auxiliary output",
+ " Notes:",
+ " * If TABLE does not exist, it is created. The first row of input",
+ " determines the column names.",
+ " * If neither --csv or --ascii are used, the input mode is derived",
+ " from the \".mode\" output mode",
+ " * If FILE begins with \"|\" then it is a command that generates the",
+ " input text.",
+#ifndef SQLITE_OMIT_TEST_CONTROL
+ ".imposter INDEX TABLE Create imposter table TABLE on index INDEX",
+#endif
+ ".indexes ?TABLE? Show names of indexes",
+ " If TABLE is specified, only show indexes for",
+ " tables matching TABLE using the LIKE operator.",
#ifdef SQLITE_ENABLE_IOTRACE
- ".iotrace FILE Enable I/O diagnostic logging to FILE\n"
+ ".iotrace FILE Enable I/O diagnostic logging to FILE",
#endif
- ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT\n"
+ ".limit ?LIMIT? ?VAL? Display or change the value of an SQLITE_LIMIT",
+ ".lint OPTIONS Report potential schema issues.",
+ " Options:",
+ " fkey-indexes Find missing foreign key indexes",
#ifndef SQLITE_OMIT_LOAD_EXTENSION
- ".load FILE ?ENTRY? Load an extension library\n"
-#endif
- ".log FILE|off Turn logging on or off. FILE can be stderr/stdout\n"
- ".mode MODE ?TABLE? Set output mode where MODE is one of:\n"
- " ascii Columns/rows delimited by 0x1F and 0x1E\n"
- " csv Comma-separated values\n"
- " column Left-aligned columns. (See .width)\n"
- " html HTML <table> code\n"
- " insert SQL insert statements for TABLE\n"
- " line One value per line\n"
- " list Values delimited by .separator strings\n"
- " tabs Tab-separated values\n"
- " tcl TCL list elements\n"
- ".nullvalue STRING Use STRING in place of NULL values\n"
- ".once FILENAME Output for the next SQL command only to FILENAME\n"
- ".open ?--new? ?FILE? Close existing database and reopen FILE\n"
- " The --new starts with an empty file\n"
- ".output ?FILENAME? Send output to FILENAME or stdout\n"
- ".print STRING... Print literal STRING\n"
- ".prompt MAIN CONTINUE Replace the standard prompts\n"
- ".quit Exit this program\n"
- ".read FILENAME Execute SQL in FILENAME\n"
- ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
- ".save FILE Write in-memory database into FILE\n"
- ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off\n"
- ".schema ?PATTERN? Show the CREATE statements matching PATTERN\n"
- " Add --indent for pretty-printing\n"
- ".separator COL ?ROW? Change the column separator and optionally the row\n"
- " separator for both the output mode and .import\n"
+ ".load FILE ?ENTRY? Load an extension library",
+#endif
+ ".log FILE|off Turn logging on or off. FILE can be stderr/stdout",
+ ".mode MODE ?TABLE? Set output mode",
+ " MODE is one of:",
+ " ascii Columns/rows delimited by 0x1F and 0x1E",
+ " box Tables using unicode box-drawing characters",
+ " csv Comma-separated values",
+ " column Output in columns. (See .width)",
+ " html HTML <table> code",
+ " insert SQL insert statements for TABLE",
+ " json Results in a JSON array",
+ " line One value per line",
+ " list Values delimited by \"|\"",
+ " markdown Markdown table format",
+ " quote Escape answers as for SQL",
+ " table ASCII-art table",
+ " tabs Tab-separated values",
+ " tcl TCL list elements",
+ ".nullvalue STRING Use STRING in place of NULL values",
+ ".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
+ " If FILE begins with '|' then open as a pipe",
+ " --bom Put a UTF8 byte-order mark at the beginning",
+ " -e Send output to the system text editor",
+ " -x Send output as CSV to a spreadsheet (same as \".excel\")",
+#ifdef SQLITE_DEBUG
+ ".oom ?--repeat M? ?N? Simulate an OOM error on the N-th allocation",
+#endif
+ ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE",
+ " Options:",
+ " --append Use appendvfs to append database to the end of FILE",
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ " --deserialize Load into memory useing sqlite3_deserialize()",
+ " --hexdb Load the output of \"dbtotxt\" as an in-memory db",
+ " --maxsize N Maximum size for --hexdb or --deserialized database",
+#endif
+ " --new Initialize FILE to an empty database",
+ " --nofollow Do not follow symbolic links",
+ " --readonly Open FILE readonly",
+ " --zip FILE is a ZIP archive",
+ ".output ?FILE? Send output to FILE or stdout if FILE is omitted",
+ " If FILE begins with '|' then open it as a pipe.",
+ " Options:",
+ " --bom Prefix output with a UTF8 byte-order mark",
+ " -e Send output to the system text editor",
+ " -x Send output as CSV to a spreadsheet",
+ ".parameter CMD ... Manage SQL parameter bindings",
+ " clear Erase all bindings",
+ " init Initialize the TEMP table that holds bindings",
+ " list List the current parameter bindings",
+ " set PARAMETER VALUE Given SQL parameter PARAMETER a value of VALUE",
+ " PARAMETER should start with one of: $ : @ ?",
+ " unset PARAMETER Remove PARAMETER from the binding table",
+ ".print STRING... Print literal STRING",
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ ".progress N Invoke progress handler after every N opcodes",
+ " --limit N Interrupt after N progress callbacks",
+ " --once Do no more than one progress interrupt",
+ " --quiet|-q No output except at interrupts",
+ " --reset Reset the count for each input and interrupt",
+#endif
+ ".prompt MAIN CONTINUE Replace the standard prompts",
+ ".quit Exit this program",
+ ".read FILE Read input from FILE",
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+ ".recover Recover as much data as possible from corrupt db.",
+ " --freelist-corrupt Assume the freelist is corrupt",
+ " --recovery-db NAME Store recovery metadata in database file NAME",
+ " --lost-and-found TABLE Alternative name for the lost-and-found table",
+ " --no-rowids Do not attempt to recover rowid values",
+ " that are not also INTEGER PRIMARY KEYs",
+#endif
+ ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE",
+ ".save FILE Write in-memory database into FILE",
+ ".scanstats on|off Turn sqlite3_stmt_scanstatus() metrics on or off",
+ ".schema ?PATTERN? Show the CREATE statements matching PATTERN",
+ " Options:",
+ " --indent Try to pretty-print the schema",
+ ".selftest ?OPTIONS? Run tests defined in the SELFTEST table",
+ " Options:",
+ " --init Create a new SELFTEST table",
+ " -v Verbose output",
+ ".separator COL ?ROW? Change the column and row separators",
#if defined(SQLITE_ENABLE_SESSION)
- ".session CMD ... Create or control sessions\n"
-#endif
- ".shell CMD ARGS... Run CMD ARGS... in a system shell\n"
- ".show Show the current values for various settings\n"
- ".stats ?on|off? Show stats or turn stats on or off\n"
- ".system CMD ARGS... Run CMD ARGS... in a system shell\n"
- ".tables ?TABLE? List names of tables\n"
- " If TABLE specified, only list tables matching\n"
- " LIKE pattern TABLE.\n"
- ".testcase NAME Begin redirecting output to 'testcase-out.txt'\n"
- ".timeout MS Try opening locked tables for MS milliseconds\n"
- ".timer on|off Turn SQL timer on or off\n"
- ".trace FILE|off Output each SQL statement as it is run\n"
- ".vfsinfo ?AUX? Information about the top-level VFS\n"
- ".vfslist List all available VFSes\n"
- ".vfsname ?AUX? Print the name of the VFS stack\n"
- ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n"
- " Negative values right-justify\n"
-;
+ ".session ?NAME? CMD ... Create or control sessions",
+ " Subcommands:",
+ " attach TABLE Attach TABLE",
+ " changeset FILE Write a changeset into FILE",
+ " close Close one session",
+ " enable ?BOOLEAN? Set or query the enable bit",
+ " filter GLOB... Reject tables matching GLOBs",
+ " indirect ?BOOLEAN? Mark or query the indirect status",
+ " isempty Query whether the session is empty",
+ " list List currently open session names",
+ " open DB NAME Open a new session on DB",
+ " patchset FILE Write a patchset into FILE",
+ " If ?NAME? is omitted, the first defined session is used.",
+#endif
+ ".sha3sum ... Compute a SHA3 hash of database content",
+ " Options:",
+ " --schema Also hash the sqlite_schema table",
+ " --sha3-224 Use the sha3-224 algorithm",
+ " --sha3-256 Use the sha3-256 algorithm (default)",
+ " --sha3-384 Use the sha3-384 algorithm",
+ " --sha3-512 Use the sha3-512 algorithm",
+ " Any other argument is a LIKE pattern for tables to hash",
+#ifndef SQLITE_NOHAVE_SYSTEM
+ ".shell CMD ARGS... Run CMD ARGS... in a system shell",
+#endif
+ ".show Show the current values for various settings",
+ ".stats ?on|off? Show stats or turn stats on or off",
+#ifndef SQLITE_NOHAVE_SYSTEM
+ ".system CMD ARGS... Run CMD ARGS... in a system shell",
+#endif
+ ".tables ?TABLE? List names of tables matching LIKE pattern TABLE",
+ ".testcase NAME Begin redirecting output to 'testcase-out.txt'",
+ ".testctrl CMD ... Run various sqlite3_test_control() operations",
+ " Run \".testctrl\" with no arguments for details",
+ ".timeout MS Try opening locked tables for MS milliseconds",
+ ".timer on|off Turn SQL timer on or off",
+#ifndef SQLITE_OMIT_TRACE
+ ".trace ?OPTIONS? Output each SQL statement as it is run",
+ " FILE Send output to FILE",
+ " stdout Send output to stdout",
+ " stderr Send output to stderr",
+ " off Disable tracing",
+ " --expanded Expand query parameters",
+#ifdef SQLITE_ENABLE_NORMALIZE
+ " --normalized Normal the SQL statements",
+#endif
+ " --plain Show SQL as it is input",
+ " --stmt Trace statement execution (SQLITE_TRACE_STMT)",
+ " --profile Profile statements (SQLITE_TRACE_PROFILE)",
+ " --row Trace each row (SQLITE_TRACE_ROW)",
+ " --close Trace connection close (SQLITE_TRACE_CLOSE)",
+#endif /* SQLITE_OMIT_TRACE */
+#ifdef SQLITE_DEBUG
+ ".unmodule NAME ... Unregister virtual table modules",
+ " --allexcept Unregister everything except those named",
+#endif
+ ".vfsinfo ?AUX? Information about the top-level VFS",
+ ".vfslist List all available VFSes",
+ ".vfsname ?AUX? Print the name of the VFS stack",
+ ".width NUM1 NUM2 ... Set minimum column widths for columnar output",
+ " Negative values right-justify",
+};
-#if defined(SQLITE_ENABLE_SESSION)
/*
-** Print help information for the ".sessions" command
-*/
-void session_help(ShellState *p){
- raw_printf(p->out,
- ".session ?NAME? SUBCOMMAND ?ARGS...?\n"
- "If ?NAME? is omitted, the first defined session is used.\n"
- "Subcommands:\n"
- " attach TABLE Attach TABLE\n"
- " changeset FILE Write a changeset into FILE\n"
- " close Close one session\n"
- " enable ?BOOLEAN? Set or query the enable bit\n"
- " filter GLOB... Reject tables matching GLOBs\n"
- " indirect ?BOOLEAN? Mark or query the indirect status\n"
- " isempty Query whether the session is empty\n"
- " list List currently open session names\n"
- " open DB NAME Open a new session on DB\n"
- " patchset FILE Write a patchset into FILE\n"
- );
+** Output help text.
+**
+** zPattern describes the set of commands for which help text is provided.
+** If zPattern is NULL, then show all commands, but only give a one-line
+** description of each.
+**
+** Return the number of matches.
+*/
+static int showHelp(FILE *out, const char *zPattern){
+ int i = 0;
+ int j = 0;
+ int n = 0;
+ char *zPat;
+ if( zPattern==0
+ || zPattern[0]=='0'
+ || strcmp(zPattern,"-a")==0
+ || strcmp(zPattern,"-all")==0
+ || strcmp(zPattern,"--all")==0
+ ){
+ /* Show all commands, but only one line per command */
+ if( zPattern==0 ) zPattern = "";
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( azHelp[i][0]=='.' || zPattern[0] ){
+ utf8_printf(out, "%s\n", azHelp[i]);
+ n++;
+ }
+ }
+ }else{
+ /* Look for commands that for which zPattern is an exact prefix */
+ zPat = sqlite3_mprintf(".%s*", zPattern);
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( sqlite3_strglob(zPat, azHelp[i])==0 ){
+ utf8_printf(out, "%s\n", azHelp[i]);
+ j = i+1;
+ n++;
+ }
+ }
+ sqlite3_free(zPat);
+ if( n ){
+ if( n==1 ){
+ /* when zPattern is a prefix of exactly one command, then include the
+ ** details of that command, which should begin at offset j */
+ while( j<ArraySize(azHelp)-1 && azHelp[j][0]!='.' ){
+ utf8_printf(out, "%s\n", azHelp[j]);
+ j++;
+ }
+ }
+ return n;
+ }
+ /* Look for commands that contain zPattern anywhere. Show the complete
+ ** text of all commands that match. */
+ zPat = sqlite3_mprintf("%%%s%%", zPattern);
+ for(i=0; i<ArraySize(azHelp); i++){
+ if( azHelp[i][0]=='.' ) j = i;
+ if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){
+ utf8_printf(out, "%s\n", azHelp[j]);
+ while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){
+ j++;
+ utf8_printf(out, "%s\n", azHelp[j]);
+ }
+ i = j;
+ n++;
+ }
+ }
+ sqlite3_free(zPat);
+ }
+ return n;
}
-#endif
-
/* Forward reference */
-static int process_input(ShellState *p, FILE *in);
-
+static int process_input(ShellState *p);
/*
-** Read the content of a file into memory obtained from sqlite3_malloc64().
-** The caller is responsible for freeing the memory.
+** Read the content of file zName into memory obtained from sqlite3_malloc64()
+** and return a pointer to the buffer. The caller is responsible for freeing
+** the memory.
+**
+** If parameter pnByte is not NULL, (*pnByte) is set to the number of bytes
+** read.
**
-** NULL is returned if any error is encountered.
+** For convenience, a nul-terminator byte is always appended to the data read
+** from the file before the buffer is returned. This byte is not included in
+** the final value of (*pnByte), if applicable.
+**
+** NULL is returned if any error is encountered. The final value of *pnByte
+** is undefined in this case.
*/
-static char *readFile(const char *zName){
+static char *readFile(const char *zName, int *pnByte){
FILE *in = fopen(zName, "rb");
long nIn;
size_t nRead;
@@ -2260,7 +13771,7 @@ static char *readFile(const char *zName){
nIn = ftell(in);
rewind(in);
pBuf = sqlite3_malloc64( nIn+1 );
- if( pBuf==0 ) return 0;
+ if( pBuf==0 ){ fclose(in); return 0; }
nRead = fread(pBuf, nIn, 1, in);
fclose(in);
if( nRead!=1 ){
@@ -2268,60 +13779,10 @@ static char *readFile(const char *zName){
return 0;
}
pBuf[nIn] = 0;
+ if( pnByte ) *pnByte = nIn;
return pBuf;
}
-/*
-** Implementation of the "readfile(X)" SQL function. The entire content
-** of the file named X is read and returned as a BLOB. NULL is returned
-** if the file does not exist or is unreadable.
-*/
-static void readfileFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const char *zName;
- void *pBuf;
-
- UNUSED_PARAMETER(argc);
- zName = (const char*)sqlite3_value_text(argv[0]);
- if( zName==0 ) return;
- pBuf = readFile(zName);
- if( pBuf ) sqlite3_result_blob(context, pBuf, -1, sqlite3_free);
-}
-
-/*
-** Implementation of the "writefile(X,Y)" SQL function. The argument Y
-** is written into file X. The number of bytes written is returned. Or
-** NULL is returned if something goes wrong, such as being unable to open
-** file X for writing.
-*/
-static void writefileFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- FILE *out;
- const char *z;
- sqlite3_int64 rc;
- const char *zFile;
-
- UNUSED_PARAMETER(argc);
- zFile = (const char*)sqlite3_value_text(argv[0]);
- if( zFile==0 ) return;
- out = fopen(zFile, "wb");
- if( out==0 ) return;
- z = (const char*)sqlite3_value_blob(argv[1]);
- if( z==0 ){
- rc = 0;
- }else{
- rc = fwrite(z, 1, sqlite3_value_bytes(argv[1]), out);
- }
- fclose(out);
- sqlite3_result_int64(context, rc);
-}
-
#if defined(SQLITE_ENABLE_SESSION)
/*
** Close a single OpenSession object and release all of its associated
@@ -2370,35 +13831,486 @@ static int session_filter(void *pCtx, const char *zTab){
#endif
/*
+** Try to deduce the type of file for zName based on its content. Return
+** one of the SHELL_OPEN_* constants.
+**
+** If the file does not exist or is empty but its name looks like a ZIP
+** archive and the dfltZip flag is true, then assume it is a ZIP archive.
+** Otherwise, assume an ordinary database regardless of the filename if
+** the type cannot be determined from content.
+*/
+int deduceDatabaseType(const char *zName, int dfltZip){
+ FILE *f = fopen(zName, "rb");
+ size_t n;
+ int rc = SHELL_OPEN_UNSPEC;
+ char zBuf[100];
+ if( f==0 ){
+ if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
+ return SHELL_OPEN_ZIPFILE;
+ }else{
+ return SHELL_OPEN_NORMAL;
+ }
+ }
+ n = fread(zBuf, 16, 1, f);
+ if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){
+ fclose(f);
+ return SHELL_OPEN_NORMAL;
+ }
+ fseek(f, -25, SEEK_END);
+ n = fread(zBuf, 25, 1, f);
+ if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){
+ rc = SHELL_OPEN_APPENDVFS;
+ }else{
+ fseek(f, -22, SEEK_END);
+ n = fread(zBuf, 22, 1, f);
+ if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05
+ && zBuf[3]==0x06 ){
+ rc = SHELL_OPEN_ZIPFILE;
+ }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
+ rc = SHELL_OPEN_ZIPFILE;
+ }
+ }
+ fclose(f);
+ return rc;
+}
+
+#ifdef SQLITE_ENABLE_DESERIALIZE
+/*
+** Reconstruct an in-memory database using the output from the "dbtotxt"
+** program. Read content from the file in p->zDbFilename. If p->zDbFilename
+** is 0, then read from standard input.
+*/
+static unsigned char *readHexDb(ShellState *p, int *pnData){
+ unsigned char *a = 0;
+ int nLine;
+ int n = 0;
+ int pgsz = 0;
+ int iOffset = 0;
+ int j, k;
+ int rc;
+ FILE *in;
+ unsigned int x[16];
+ char zLine[1000];
+ if( p->zDbFilename ){
+ in = fopen(p->zDbFilename, "r");
+ if( in==0 ){
+ utf8_printf(stderr, "cannot open \"%s\" for reading\n", p->zDbFilename);
+ return 0;
+ }
+ nLine = 0;
+ }else{
+ in = p->in;
+ nLine = p->lineno;
+ if( in==0 ) in = stdin;
+ }
+ *pnData = 0;
+ nLine++;
+ if( fgets(zLine, sizeof(zLine), in)==0 ) goto readHexDb_error;
+ rc = sscanf(zLine, "| size %d pagesize %d", &n, &pgsz);
+ if( rc!=2 ) goto readHexDb_error;
+ if( n<0 ) goto readHexDb_error;
+ if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ) goto readHexDb_error;
+ n = (n+pgsz-1)&~(pgsz-1); /* Round n up to the next multiple of pgsz */
+ a = sqlite3_malloc( n ? n : 1 );
+ if( a==0 ){
+ utf8_printf(stderr, "Out of memory!\n");
+ goto readHexDb_error;
+ }
+ memset(a, 0, n);
+ if( pgsz<512 || pgsz>65536 || (pgsz & (pgsz-1))!=0 ){
+ utf8_printf(stderr, "invalid pagesize\n");
+ goto readHexDb_error;
+ }
+ for(nLine++; fgets(zLine, sizeof(zLine), in)!=0; nLine++){
+ rc = sscanf(zLine, "| page %d offset %d", &j, &k);
+ if( rc==2 ){
+ iOffset = k;
+ continue;
+ }
+ if( strncmp(zLine, "| end ", 6)==0 ){
+ break;
+ }
+ rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
+ &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
+ &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
+ if( rc==17 ){
+ k = iOffset+j;
+ if( k+16<=n ){
+ int ii;
+ for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
+ }
+ }
+ }
+ *pnData = n;
+ if( in!=p->in ){
+ fclose(in);
+ }else{
+ p->lineno = nLine;
+ }
+ return a;
+
+readHexDb_error:
+ if( in!=p->in ){
+ fclose(in);
+ }else{
+ while( fgets(zLine, sizeof(zLine), p->in)!=0 ){
+ nLine++;
+ if(strncmp(zLine, "| end ", 6)==0 ) break;
+ }
+ p->lineno = nLine;
+ }
+ sqlite3_free(a);
+ utf8_printf(stderr,"Error on line %d of --hexdb input\n", nLine);
+ return 0;
+}
+#endif /* SQLITE_ENABLE_DESERIALIZE */
+
+/*
+** Scalar function "shell_int32". The first argument to this function
+** must be a blob. The second a non-negative integer. This function
+** reads and returns a 32-bit big-endian integer from byte
+** offset (4*<arg2>) of the blob.
+*/
+static void shellInt32(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *pBlob;
+ int nBlob;
+ int iInt;
+
+ UNUSED_PARAMETER(argc);
+ nBlob = sqlite3_value_bytes(argv[0]);
+ pBlob = (const unsigned char*)sqlite3_value_blob(argv[0]);
+ iInt = sqlite3_value_int(argv[1]);
+
+ if( iInt>=0 && (iInt+1)*4<=nBlob ){
+ const unsigned char *a = &pBlob[iInt*4];
+ sqlite3_int64 iVal = ((sqlite3_int64)a[0]<<24)
+ + ((sqlite3_int64)a[1]<<16)
+ + ((sqlite3_int64)a[2]<< 8)
+ + ((sqlite3_int64)a[3]<< 0);
+ sqlite3_result_int64(context, iVal);
+ }
+}
+
+/*
+** Scalar function "shell_idquote(X)" returns string X quoted as an identifier,
+** using "..." with internal double-quote characters doubled.
+*/
+static void shellIdQuote(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zName = (const char*)sqlite3_value_text(argv[0]);
+ UNUSED_PARAMETER(argc);
+ if( zName ){
+ char *z = sqlite3_mprintf("\"%w\"", zName);
+ sqlite3_result_text(context, z, -1, sqlite3_free);
+ }
+}
+
+/*
+** Scalar function "shell_escape_crnl" used by the .recover command.
+** The argument passed to this function is the output of built-in
+** function quote(). If the first character of the input is "'",
+** indicating that the value passed to quote() was a text value,
+** then this function searches the input for "\n" and "\r" characters
+** and adds a wrapper similar to the following:
+**
+** replace(replace(<input>, '\n', char(10), '\r', char(13));
+**
+** Or, if the first character of the input is not "'", then a copy
+** of the input is returned.
+*/
+static void shellEscapeCrnl(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const char *zText = (const char*)sqlite3_value_text(argv[0]);
+ UNUSED_PARAMETER(argc);
+ if( zText[0]=='\'' ){
+ int nText = sqlite3_value_bytes(argv[0]);
+ int i;
+ char zBuf1[20];
+ char zBuf2[20];
+ const char *zNL = 0;
+ const char *zCR = 0;
+ int nCR = 0;
+ int nNL = 0;
+
+ for(i=0; zText[i]; i++){
+ if( zNL==0 && zText[i]=='\n' ){
+ zNL = unused_string(zText, "\\n", "\\012", zBuf1);
+ nNL = (int)strlen(zNL);
+ }
+ if( zCR==0 && zText[i]=='\r' ){
+ zCR = unused_string(zText, "\\r", "\\015", zBuf2);
+ nCR = (int)strlen(zCR);
+ }
+ }
+
+ if( zNL || zCR ){
+ int iOut = 0;
+ i64 nMax = (nNL > nCR) ? nNL : nCR;
+ i64 nAlloc = nMax * nText + (nMax+64)*2;
+ char *zOut = (char*)sqlite3_malloc64(nAlloc);
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+
+ if( zNL && zCR ){
+ memcpy(&zOut[iOut], "replace(replace(", 16);
+ iOut += 16;
+ }else{
+ memcpy(&zOut[iOut], "replace(", 8);
+ iOut += 8;
+ }
+ for(i=0; zText[i]; i++){
+ if( zText[i]=='\n' ){
+ memcpy(&zOut[iOut], zNL, nNL);
+ iOut += nNL;
+ }else if( zText[i]=='\r' ){
+ memcpy(&zOut[iOut], zCR, nCR);
+ iOut += nCR;
+ }else{
+ zOut[iOut] = zText[i];
+ iOut++;
+ }
+ }
+
+ if( zNL ){
+ memcpy(&zOut[iOut], ",'", 2); iOut += 2;
+ memcpy(&zOut[iOut], zNL, nNL); iOut += nNL;
+ memcpy(&zOut[iOut], "', char(10))", 12); iOut += 12;
+ }
+ if( zCR ){
+ memcpy(&zOut[iOut], ",'", 2); iOut += 2;
+ memcpy(&zOut[iOut], zCR, nCR); iOut += nCR;
+ memcpy(&zOut[iOut], "', char(13))", 12); iOut += 12;
+ }
+
+ sqlite3_result_text(context, zOut, iOut, SQLITE_TRANSIENT);
+ sqlite3_free(zOut);
+ return;
+ }
+ }
+
+ sqlite3_result_value(context, argv[0]);
+}
+
+/* Flags for open_db().
+**
+** The default behavior of open_db() is to exit(1) if the database fails to
+** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
+** but still returns without calling exit.
+**
+** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a
+** ZIP archive if the file does not exist or is empty and its name matches
+** the *.zip pattern.
+*/
+#define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */
+#define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */
+
+/*
** Make sure the database is open. If it is not, then open it. If
** the database fails to open, print an error message and exit.
*/
-static void open_db(ShellState *p, int keepAlive){
+static void open_db(ShellState *p, int openFlags){
if( p->db==0 ){
- sqlite3_initialize();
- sqlite3_open(p->zDbFilename, &p->db);
- globalDb = p->db;
- if( p->db && sqlite3_errcode(p->db)==SQLITE_OK ){
- sqlite3_create_function(p->db, "shellstatic", 0, SQLITE_UTF8, 0,
- shellstaticFunc, 0, 0);
+ if( p->openMode==SHELL_OPEN_UNSPEC ){
+ if( p->zDbFilename==0 || p->zDbFilename[0]==0 ){
+ p->openMode = SHELL_OPEN_NORMAL;
+ }else{
+ p->openMode = (u8)deduceDatabaseType(p->zDbFilename,
+ (openFlags & OPEN_DB_ZIPFILE)!=0);
+ }
}
+ switch( p->openMode ){
+ case SHELL_OPEN_APPENDVFS: {
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, "apndvfs");
+ break;
+ }
+ case SHELL_OPEN_HEXDB:
+ case SHELL_OPEN_DESERIALIZE: {
+ sqlite3_open(0, &p->db);
+ break;
+ }
+ case SHELL_OPEN_ZIPFILE: {
+ sqlite3_open(":memory:", &p->db);
+ break;
+ }
+ case SHELL_OPEN_READONLY: {
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READONLY|p->openFlags, 0);
+ break;
+ }
+ case SHELL_OPEN_UNSPEC:
+ case SHELL_OPEN_NORMAL: {
+ sqlite3_open_v2(p->zDbFilename, &p->db,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|p->openFlags, 0);
+ break;
+ }
+ }
+ globalDb = p->db;
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
p->zDbFilename, sqlite3_errmsg(p->db));
- if( keepAlive ) return;
+ if( openFlags & OPEN_DB_KEEPALIVE ){
+ sqlite3_open(":memory:", &p->db);
+ return;
+ }
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
sqlite3_enable_load_extension(p->db, 1);
#endif
- sqlite3_create_function(p->db, "readfile", 1, SQLITE_UTF8, 0,
- readfileFunc, 0, 0);
- sqlite3_create_function(p->db, "writefile", 2, SQLITE_UTF8, 0,
- writefileFunc, 0, 0);
+ sqlite3_fileio_init(p->db, 0, 0);
+ sqlite3_shathree_init(p->db, 0, 0);
+ sqlite3_completion_init(p->db, 0, 0);
+ sqlite3_uint_init(p->db, 0, 0);
+ sqlite3_decimal_init(p->db, 0, 0);
+ sqlite3_ieee_init(p->db, 0, 0);
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+ sqlite3_dbdata_init(p->db, 0, 0);
+#endif
+#ifdef SQLITE_HAVE_ZLIB
+ sqlite3_zipfile_init(p->db, 0, 0);
+ sqlite3_sqlar_init(p->db, 0, 0);
+#endif
+ sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0,
+ shellAddSchemaName, 0, 0);
+ sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0,
+ shellModuleSchema, 0, 0);
+ sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p,
+ shellPutsFunc, 0, 0);
+ sqlite3_create_function(p->db, "shell_escape_crnl", 1, SQLITE_UTF8, 0,
+ shellEscapeCrnl, 0, 0);
+ sqlite3_create_function(p->db, "shell_int32", 2, SQLITE_UTF8, 0,
+ shellInt32, 0, 0);
+ sqlite3_create_function(p->db, "shell_idquote", 1, SQLITE_UTF8, 0,
+ shellIdQuote, 0, 0);
+#ifndef SQLITE_NOHAVE_SYSTEM
+ sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0,
+ editFunc, 0, 0);
+ sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0,
+ editFunc, 0, 0);
+#endif
+ if( p->openMode==SHELL_OPEN_ZIPFILE ){
+ char *zSql = sqlite3_mprintf(
+ "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename);
+ sqlite3_exec(p->db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+ }
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ else
+ if( p->openMode==SHELL_OPEN_DESERIALIZE || p->openMode==SHELL_OPEN_HEXDB ){
+ int rc;
+ int nData = 0;
+ unsigned char *aData;
+ if( p->openMode==SHELL_OPEN_DESERIALIZE ){
+ aData = (unsigned char*)readFile(p->zDbFilename, &nData);
+ }else{
+ aData = readHexDb(p, &nData);
+ if( aData==0 ){
+ return;
+ }
+ }
+ rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
+ SQLITE_DESERIALIZE_RESIZEABLE |
+ SQLITE_DESERIALIZE_FREEONCLOSE);
+ if( rc ){
+ utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc);
+ }
+ if( p->szMax>0 ){
+ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
+ }
+ }
+#endif
}
}
/*
+** Attempt to close the databaes connection. Report errors.
+*/
+void close_db(sqlite3 *db){
+ int rc = sqlite3_close(db);
+ if( rc ){
+ utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n",
+ rc, sqlite3_errmsg(db));
+ }
+}
+
+#if HAVE_READLINE || HAVE_EDITLINE
+/*
+** Readline completion callbacks
+*/
+static char *readline_completion_generator(const char *text, int state){
+ static sqlite3_stmt *pStmt = 0;
+ char *zRet;
+ if( state==0 ){
+ char *zSql;
+ sqlite3_finalize(pStmt);
+ zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
+ " FROM completion(%Q) ORDER BY 1", text);
+ sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ }
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ zRet = strdup((const char*)sqlite3_column_text(pStmt, 0));
+ }else{
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ zRet = 0;
+ }
+ return zRet;
+}
+static char **readline_completion(const char *zText, int iStart, int iEnd){
+ rl_attempted_completion_over = 1;
+ return rl_completion_matches(zText, readline_completion_generator);
+}
+
+#elif HAVE_LINENOISE
+/*
+** Linenoise completion callback
+*/
+static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){
+ int nLine = strlen30(zLine);
+ int i, iStart;
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ char zBuf[1000];
+
+ if( nLine>sizeof(zBuf)-30 ) return;
+ if( zLine[0]=='.' || zLine[0]=='#') return;
+ for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){}
+ if( i==nLine-1 ) return;
+ iStart = i+1;
+ memcpy(zBuf, zLine, iStart);
+ zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
+ " FROM completion(%Q,%Q) ORDER BY 1",
+ &zLine[iStart], zLine);
+ sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0);
+ int nCompletion = sqlite3_column_bytes(pStmt, 0);
+ if( iStart+nCompletion < sizeof(zBuf)-1 ){
+ memcpy(zBuf+iStart, zCompletion, nCompletion+1);
+ linenoiseAddCompletion(lc, zBuf);
+ }
+ }
+ sqlite3_finalize(pStmt);
+}
+#endif
+
+/*
** Do C-language style dequoting.
**
** \a -> alarm
@@ -2459,67 +14371,10 @@ static void resolve_backslashes(char *z){
}
/*
-** Return the value of a hexadecimal digit. Return -1 if the input
-** is not a hex digit.
-*/
-static int hexDigitValue(char c){
- if( c>='0' && c<='9' ) return c - '0';
- if( c>='a' && c<='f' ) return c - 'a' + 10;
- if( c>='A' && c<='F' ) return c - 'A' + 10;
- return -1;
-}
-
-/*
-** Interpret zArg as an integer value, possibly with suffixes.
-*/
-static sqlite3_int64 integerValue(const char *zArg){
- sqlite3_int64 v = 0;
- static const struct { char *zSuffix; int iMult; } aMult[] = {
- { "KiB", 1024 },
- { "MiB", 1024*1024 },
- { "GiB", 1024*1024*1024 },
- { "KB", 1000 },
- { "MB", 1000000 },
- { "GB", 1000000000 },
- { "K", 1000 },
- { "M", 1000000 },
- { "G", 1000000000 },
- };
- int i;
- int isNeg = 0;
- if( zArg[0]=='-' ){
- isNeg = 1;
- zArg++;
- }else if( zArg[0]=='+' ){
- zArg++;
- }
- if( zArg[0]=='0' && zArg[1]=='x' ){
- int x;
- zArg += 2;
- while( (x = hexDigitValue(zArg[0]))>=0 ){
- v = (v<<4) + x;
- zArg++;
- }
- }else{
- while( IsDigit(zArg[0]) ){
- v = v*10 + zArg[0] - '0';
- zArg++;
- }
- }
- for(i=0; i<ArraySize(aMult); i++){
- if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
- v *= aMult[i].iMult;
- break;
- }
- }
- return isNeg? -v : v;
-}
-
-/*
** Interpret zArg as either an integer or a boolean value. Return 1 or 0
** for TRUE and FALSE. Return the integer value if appropriate.
*/
-static int booleanValue(char *zArg){
+static int booleanValue(const char *zArg){
int i;
if( zArg[0]=='0' && zArg[1]=='x' ){
for(i=2; hexDigitValue(zArg[i])>=0; i++){}
@@ -2539,6 +14394,17 @@ static int booleanValue(char *zArg){
}
/*
+** Set or clear a shell flag according to a boolean value.
+*/
+static void setOrClearFlag(ShellState *p, unsigned mFlag, const char *zArg){
+ if( booleanValue(zArg) ){
+ ShellSetFlag(p, mFlag);
+ }else{
+ ShellClearFlag(p, mFlag);
+ }
+}
+
+/*
** Close an output file, assuming it is not stderr or stdout
*/
static void output_file_close(FILE *f){
@@ -2550,7 +14416,7 @@ static void output_file_close(FILE *f){
** recognized and do the right thing. NULL is returned if the output
** filename is "off".
*/
-static FILE *output_file_open(const char *zFile){
+static FILE *output_file_open(const char *zFile, int bTextMode){
FILE *f;
if( strcmp(zFile,"stdout")==0 ){
f = stdout;
@@ -2559,7 +14425,7 @@ static FILE *output_file_open(const char *zFile){
}else if( strcmp(zFile, "off")==0 ){
f = 0;
}else{
- f = fopen(zFile, "wb");
+ f = fopen(zFile, bTextMode ? "w" : "wb");
if( f==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
}
@@ -2567,26 +14433,64 @@ static FILE *output_file_open(const char *zFile){
return f;
}
+#ifndef SQLITE_OMIT_TRACE
/*
** A routine for handling output from sqlite3_trace().
*/
static int sql_trace_callback(
- unsigned mType,
- void *pArg,
- void *pP,
- void *pX
-){
- FILE *f = (FILE*)pArg;
- UNUSED_PARAMETER(mType);
- UNUSED_PARAMETER(pP);
- if( f ){
- const char *z = (const char*)pX;
- int i = (int)strlen(z);
- while( i>0 && z[i-1]==';' ){ i--; }
- utf8_printf(f, "%.*s;\n", i, z);
+ unsigned mType, /* The trace type */
+ void *pArg, /* The ShellState pointer */
+ void *pP, /* Usually a pointer to sqlite_stmt */
+ void *pX /* Auxiliary output */
+){
+ ShellState *p = (ShellState*)pArg;
+ sqlite3_stmt *pStmt;
+ const char *zSql;
+ int nSql;
+ if( p->traceOut==0 ) return 0;
+ if( mType==SQLITE_TRACE_CLOSE ){
+ utf8_printf(p->traceOut, "-- closing database connection\n");
+ return 0;
+ }
+ if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){
+ zSql = (const char*)pX;
+ }else{
+ pStmt = (sqlite3_stmt*)pP;
+ switch( p->eTraceType ){
+ case SHELL_TRACE_EXPANDED: {
+ zSql = sqlite3_expanded_sql(pStmt);
+ break;
+ }
+#ifdef SQLITE_ENABLE_NORMALIZE
+ case SHELL_TRACE_NORMALIZED: {
+ zSql = sqlite3_normalized_sql(pStmt);
+ break;
+ }
+#endif
+ default: {
+ zSql = sqlite3_sql(pStmt);
+ break;
+ }
+ }
+ }
+ if( zSql==0 ) return 0;
+ nSql = strlen30(zSql);
+ while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; }
+ switch( mType ){
+ case SQLITE_TRACE_ROW:
+ case SQLITE_TRACE_STMT: {
+ utf8_printf(p->traceOut, "%.*s;\n", nSql, zSql);
+ break;
+ }
+ case SQLITE_TRACE_PROFILE: {
+ sqlite3_int64 nNanosec = *(sqlite3_int64*)pX;
+ utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec);
+ break;
+ }
}
return 0;
}
+#endif
/*
** A no-op routine that runs with the ".breakpoint" doc-command. This is
@@ -2604,24 +14508,35 @@ typedef struct ImportCtx ImportCtx;
struct ImportCtx {
const char *zFile; /* Name of the input file */
FILE *in; /* Read the CSV text from this input stream */
+ int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close in */
char *z; /* Accumulated text for a field */
int n; /* Number of bytes in z */
int nAlloc; /* Space allocated for z[] */
int nLine; /* Current line number */
+ int nRow; /* Number of rows imported */
+ int nErr; /* Number of errors encountered */
+ int bNotFirst; /* True if one or more bytes already read */
int cTerm; /* Character that terminated the most recent field */
int cColSep; /* The column separator character. (Usually ",") */
int cRowSep; /* The row separator character. (Usually "\n") */
};
+/* Clean up resourced used by an ImportCtx */
+static void import_cleanup(ImportCtx *p){
+ if( p->in!=0 && p->xCloser!=0 ){
+ p->xCloser(p->in);
+ p->in = 0;
+ }
+ sqlite3_free(p->z);
+ p->z = 0;
+}
+
/* Append a single byte to z[] */
static void import_append_char(ImportCtx *p, int c){
if( p->n+1>=p->nAlloc ){
p->nAlloc += p->nAlloc + 100;
p->z = sqlite3_realloc64(p->z, p->nAlloc);
- if( p->z==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
+ if( p->z==0 ) shell_out_of_memory();
}
p->z[p->n++] = (char)c;
}
@@ -2687,6 +14602,21 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
pc = c;
}
}else{
+ /* If this is the first field being parsed and it begins with the
+ ** UTF-8 BOM (0xEF BB BF) then skip the BOM */
+ if( (c&0xff)==0xef && p->bNotFirst==0 ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ if( (c&0xff)==0xbb ){
+ import_append_char(p, c);
+ c = fgetc(p->in);
+ if( (c&0xff)==0xbf ){
+ p->bNotFirst = 1;
+ p->n = 0;
+ return csv_read_one_field(p);
+ }
+ }
+ }
while( c!=EOF && c!=cSep && c!=rSep ){
import_append_char(p, c);
c = fgetc(p->in);
@@ -2698,6 +14628,7 @@ static char *SQLITE_CDECL csv_read_one_field(ImportCtx *p){
p->cTerm = c;
}
if( p->z ) p->z[p->n] = 0;
+ p->bNotFirst = 1;
return p->z;
}
@@ -2751,7 +14682,7 @@ static void tryToCloneData(
char *zInsert = 0;
int rc;
int i, j, n;
- int nTable = (int)strlen(zTable);
+ int nTable = strlen30(zTable);
int k = 0;
int cnt = 0;
const int spinRate = 10000;
@@ -2766,13 +14697,10 @@ static void tryToCloneData(
}
n = sqlite3_column_count(pQuery);
zInsert = sqlite3_malloc64(200 + nTable + n*3);
- if( zInsert==0 ){
- raw_printf(stderr, "out of memory\n");
- goto end_data_xfer;
- }
+ if( zInsert==0 ) shell_out_of_memory();
sqlite3_snprintf(200+nTable,zInsert,
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
- i = (int)strlen(zInsert);
+ i = strlen30(zInsert);
for(j=1; j<n; j++){
memcpy(zInsert+i, ",?", 2);
i += 2;
@@ -2851,7 +14779,7 @@ end_data_xfer:
** Try to transfer all rows of the schema that match zWhere. For
** each row, invoke xForEach() on the object defined by that row.
** If an error is encountered while moving forward through the
-** sqlite_master table, try again moving backwards.
+** sqlite_schema table, try again moving backwards.
*/
static void tryToCloneSchema(
ShellState *p,
@@ -2866,7 +14794,7 @@ static void tryToCloneSchema(
const unsigned char *zSql;
char *zErrMsg = 0;
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
@@ -2893,7 +14821,7 @@ static void tryToCloneSchema(
if( rc!=SQLITE_DONE ){
sqlite3_finalize(pQuery);
sqlite3_free(zQuery);
- zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
+ zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_schema"
" WHERE %s ORDER BY rowid DESC", zWhere);
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
if( rc ){
@@ -2947,11 +14875,15 @@ static void tryToClone(ShellState *p, const char *zNewDb){
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
}
- sqlite3_close(newDb);
+ close_db(newDb);
}
/*
-** Change the output file back to stdout
+** Change the output file back to stdout.
+**
+** If the p->doXdgOpen flag is set, that means the output was being
+** redirected to a temporary file named by p->zTempFile. In that case,
+** launch start/open/xdg-open on that temporary file.
*/
static void output_reset(ShellState *p){
if( p->outfile[0]=='|' ){
@@ -2960,6 +14892,31 @@ static void output_reset(ShellState *p){
#endif
}else{
output_file_close(p->out);
+#ifndef SQLITE_NOHAVE_SYSTEM
+ if( p->doXdgOpen ){
+ const char *zXdgOpenCmd =
+#if defined(_WIN32)
+ "start";
+#elif defined(__APPLE__)
+ "open";
+#else
+ "xdg-open";
+#endif
+ char *zCmd;
+ zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
+ if( system(zCmd) ){
+ utf8_printf(stderr, "Failed: [%s]\n", zCmd);
+ }else{
+ /* Give the start/open/xdg-open command some time to get
+ ** going before we continue, and potential delete the
+ ** p->zTempFile data file out from under it */
+ sqlite3_sleep(2000);
+ }
+ sqlite3_free(zCmd);
+ outputModePop(p);
+ p->doXdgOpen = 0;
+ }
+#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
}
p->outfile[0] = 0;
p->out = stdout;
@@ -2990,7 +14947,7 @@ static unsigned int get4byteInt(unsigned char *a){
}
/*
-** Implementation of the ".info" command.
+** Implementation of the ".dbinfo" command.
**
** Return 1 on error, 2 to exit, and 0 otherwise.
*/
@@ -3021,20 +14978,31 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
{ "schema size:",
"SELECT total(length(sql)) FROM %s" },
};
- sqlite3_file *pFile = 0;
- int i;
+ int i, rc;
+ unsigned iDataVersion;
char *zSchemaTab;
char *zDb = nArg>=2 ? azArg[1] : "main";
+ sqlite3_stmt *pStmt = 0;
unsigned char aHdr[100];
open_db(p, 0);
if( p->db==0 ) return 1;
- sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_FILE_POINTER, &pFile);
- if( pFile==0 || pFile->pMethods==0 || pFile->pMethods->xRead==0 ){
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
+ -1, &pStmt, 0);
+ if( rc ){
+ utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_finalize(pStmt);
return 1;
}
- i = pFile->pMethods->xRead(pFile, aHdr, 100, 0);
- if( i!=SQLITE_OK ){
+ sqlite3_bind_text(pStmt, 1, zDb, -1, SQLITE_STATIC);
+ if( sqlite3_step(pStmt)==SQLITE_ROW
+ && sqlite3_column_bytes(pStmt,0)>100
+ ){
+ memcpy(aHdr, sqlite3_column_blob(pStmt,0), 100);
+ sqlite3_finalize(pStmt);
+ }else{
raw_printf(stderr, "unable to read database header\n");
+ sqlite3_finalize(pStmt);
return 1;
}
i = get2byteInt(aHdr+16);
@@ -3057,11 +15025,11 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
raw_printf(p->out, "\n");
}
if( zDb==0 ){
- zSchemaTab = sqlite3_mprintf("main.sqlite_master");
+ zSchemaTab = sqlite3_mprintf("main.sqlite_schema");
}else if( strcmp(zDb,"temp")==0 ){
- zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master");
+ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_schema");
}else{
- zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", zDb);
+ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_schema", zDb);
}
for(i=0; i<ArraySize(aQuery); i++){
char *zSql = sqlite3_mprintf(aQuery[i].zSql, zSchemaTab);
@@ -3070,6 +15038,8 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
}
sqlite3_free(zSchemaTab);
+ sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
+ utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
return 0;
}
@@ -3083,14 +15053,6 @@ static int shellDatabaseError(sqlite3 *db){
}
/*
-** Print an out-of-memory message to stderr and return 1.
-*/
-static int shellNomemError(void){
- raw_printf(stderr, "Error: out of memory\n");
- return 1;
-}
-
-/*
** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
** if they match and FALSE (0) if they do not match.
**
@@ -3215,6 +15177,1765 @@ int shellDeleteFile(const char *zFilename){
}
/*
+** Try to delete the temporary file (if there is one) and free the
+** memory used to hold the name of the temp file.
+*/
+static void clearTempFile(ShellState *p){
+ if( p->zTempFile==0 ) return;
+ if( p->doXdgOpen ) return;
+ if( shellDeleteFile(p->zTempFile) ) return;
+ sqlite3_free(p->zTempFile);
+ p->zTempFile = 0;
+}
+
+/*
+** Create a new temp file name with the given suffix.
+*/
+static void newTempFile(ShellState *p, const char *zSuffix){
+ clearTempFile(p);
+ sqlite3_free(p->zTempFile);
+ p->zTempFile = 0;
+ if( p->db ){
+ sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
+ }
+ if( p->zTempFile==0 ){
+ /* If p->db is an in-memory database then the TEMPFILENAME file-control
+ ** will not work and we will need to fallback to guessing */
+ char *zTemp;
+ sqlite3_uint64 r;
+ sqlite3_randomness(sizeof(r), &r);
+ zTemp = getenv("TEMP");
+ if( zTemp==0 ) zTemp = getenv("TMP");
+ if( zTemp==0 ){
+#ifdef _WIN32
+ zTemp = "\\tmp";
+#else
+ zTemp = "/tmp";
+#endif
+ }
+ p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
+ }else{
+ p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
+ }
+ if( p->zTempFile==0 ){
+ raw_printf(stderr, "out of memory\n");
+ exit(1);
+ }
+}
+
+
+/*
+** The implementation of SQL scalar function fkey_collate_clause(), used
+** by the ".lint fkey-indexes" command. This scalar function is always
+** called with four arguments - the parent table name, the parent column name,
+** the child table name and the child column name.
+**
+** fkey_collate_clause('parent-tab', 'parent-col', 'child-tab', 'child-col')
+**
+** If either of the named tables or columns do not exist, this function
+** returns an empty string. An empty string is also returned if both tables
+** and columns exist but have the same default collation sequence. Or,
+** if both exist but the default collation sequences are different, this
+** function returns the string " COLLATE <parent-collation>", where
+** <parent-collation> is the default collation sequence of the parent column.
+*/
+static void shellFkeyCollateClause(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+ const char *zParent;
+ const char *zParentCol;
+ const char *zParentSeq;
+ const char *zChild;
+ const char *zChildCol;
+ const char *zChildSeq = 0; /* Initialize to avoid false-positive warning */
+ int rc;
+
+ assert( nVal==4 );
+ zParent = (const char*)sqlite3_value_text(apVal[0]);
+ zParentCol = (const char*)sqlite3_value_text(apVal[1]);
+ zChild = (const char*)sqlite3_value_text(apVal[2]);
+ zChildCol = (const char*)sqlite3_value_text(apVal[3]);
+
+ sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
+ rc = sqlite3_table_column_metadata(
+ db, "main", zParent, zParentCol, 0, &zParentSeq, 0, 0, 0
+ );
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_table_column_metadata(
+ db, "main", zChild, zChildCol, 0, &zChildSeq, 0, 0, 0
+ );
+ }
+
+ if( rc==SQLITE_OK && sqlite3_stricmp(zParentSeq, zChildSeq) ){
+ char *z = sqlite3_mprintf(" COLLATE %s", zParentSeq);
+ sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
+ sqlite3_free(z);
+ }
+}
+
+
+/*
+** The implementation of dot-command ".lint fkey-indexes".
+*/
+static int lintFkeyIndexes(
+ ShellState *pState, /* Current shell tool state */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ sqlite3 *db = pState->db; /* Database handle to query "main" db of */
+ FILE *out = pState->out; /* Stream to write non-error output to */
+ int bVerbose = 0; /* If -verbose is present */
+ int bGroupByParent = 0; /* If -groupbyparent is present */
+ int i; /* To iterate through azArg[] */
+ const char *zIndent = ""; /* How much to indent CREATE INDEX by */
+ int rc; /* Return code */
+ sqlite3_stmt *pSql = 0; /* Compiled version of SQL statement below */
+
+ /*
+ ** This SELECT statement returns one row for each foreign key constraint
+ ** in the schema of the main database. The column values are:
+ **
+ ** 0. The text of an SQL statement similar to:
+ **
+ ** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
+ **
+ ** This SELECT is similar to the one that the foreign keys implementation
+ ** needs to run internally on child tables. If there is an index that can
+ ** be used to optimize this query, then it can also be used by the FK
+ ** implementation to optimize DELETE or UPDATE statements on the parent
+ ** table.
+ **
+ ** 1. A GLOB pattern suitable for sqlite3_strglob(). If the plan output by
+ ** the EXPLAIN QUERY PLAN command matches this pattern, then the schema
+ ** contains an index that can be used to optimize the query.
+ **
+ ** 2. Human readable text that describes the child table and columns. e.g.
+ **
+ ** "child_table(child_key1, child_key2)"
+ **
+ ** 3. Human readable text that describes the parent table and columns. e.g.
+ **
+ ** "parent_table(parent_key1, parent_key2)"
+ **
+ ** 4. A full CREATE INDEX statement for an index that could be used to
+ ** optimize DELETE or UPDATE statements on the parent table. e.g.
+ **
+ ** "CREATE INDEX child_table_child_key ON child_table(child_key)"
+ **
+ ** 5. The name of the parent table.
+ **
+ ** These six values are used by the C logic below to generate the report.
+ */
+ const char *zSql =
+ "SELECT "
+ " 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
+ " || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
+ " || fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
+ ", "
+ " 'SEARCH TABLE ' || s.name || ' USING COVERING INDEX*('"
+ " || group_concat('*=?', ' AND ') || ')'"
+ ", "
+ " s.name || '(' || group_concat(f.[from], ', ') || ')'"
+ ", "
+ " f.[table] || '(' || group_concat(COALESCE(f.[to], p.[name])) || ')'"
+ ", "
+ " 'CREATE INDEX ' || quote(s.name ||'_'|| group_concat(f.[from], '_'))"
+ " || ' ON ' || quote(s.name) || '('"
+ " || group_concat(quote(f.[from]) ||"
+ " fkey_collate_clause("
+ " f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]), ', ')"
+ " || ');'"
+ ", "
+ " f.[table] "
+ "FROM sqlite_schema AS s, pragma_foreign_key_list(s.name) AS f "
+ "LEFT JOIN pragma_table_info AS p ON (pk-1=seq AND p.arg=f.[table]) "
+ "GROUP BY s.name, f.id "
+ "ORDER BY (CASE WHEN ? THEN f.[table] ELSE s.name END)"
+ ;
+ const char *zGlobIPK = "SEARCH TABLE * USING INTEGER PRIMARY KEY (rowid=?)";
+
+ for(i=2; i<nArg; i++){
+ int n = strlen30(azArg[i]);
+ if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){
+ bVerbose = 1;
+ }
+ else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){
+ bGroupByParent = 1;
+ zIndent = " ";
+ }
+ else{
+ raw_printf(stderr, "Usage: %s %s ?-verbose? ?-groupbyparent?\n",
+ azArg[0], azArg[1]
+ );
+ return SQLITE_ERROR;
+ }
+ }
+
+ /* Register the fkey_collate_clause() SQL function */
+ rc = sqlite3_create_function(db, "fkey_collate_clause", 4, SQLITE_UTF8,
+ 0, shellFkeyCollateClause, 0, 0
+ );
+
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(pSql, 1, bGroupByParent);
+ }
+
+ if( rc==SQLITE_OK ){
+ int rc2;
+ char *zPrev = 0;
+ while( SQLITE_ROW==sqlite3_step(pSql) ){
+ int res = -1;
+ sqlite3_stmt *pExplain = 0;
+ const char *zEQP = (const char*)sqlite3_column_text(pSql, 0);
+ const char *zGlob = (const char*)sqlite3_column_text(pSql, 1);
+ const char *zFrom = (const char*)sqlite3_column_text(pSql, 2);
+ const char *zTarget = (const char*)sqlite3_column_text(pSql, 3);
+ const char *zCI = (const char*)sqlite3_column_text(pSql, 4);
+ const char *zParent = (const char*)sqlite3_column_text(pSql, 5);
+
+ rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
+ if( rc!=SQLITE_OK ) break;
+ if( SQLITE_ROW==sqlite3_step(pExplain) ){
+ const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3);
+ res = (
+ 0==sqlite3_strglob(zGlob, zPlan)
+ || 0==sqlite3_strglob(zGlobIPK, zPlan)
+ );
+ }
+ rc = sqlite3_finalize(pExplain);
+ if( rc!=SQLITE_OK ) break;
+
+ if( res<0 ){
+ raw_printf(stderr, "Error: internal error");
+ break;
+ }else{
+ if( bGroupByParent
+ && (bVerbose || res==0)
+ && (zPrev==0 || sqlite3_stricmp(zParent, zPrev))
+ ){
+ raw_printf(out, "-- Parent table %s\n", zParent);
+ sqlite3_free(zPrev);
+ zPrev = sqlite3_mprintf("%s", zParent);
+ }
+
+ if( res==0 ){
+ raw_printf(out, "%s%s --> %s\n", zIndent, zCI, zTarget);
+ }else if( bVerbose ){
+ raw_printf(out, "%s/* no extra indexes required for %s -> %s */\n",
+ zIndent, zFrom, zTarget
+ );
+ }
+ }
+ }
+ sqlite3_free(zPrev);
+
+ if( rc!=SQLITE_OK ){
+ raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
+ }
+
+ rc2 = sqlite3_finalize(pSql);
+ if( rc==SQLITE_OK && rc2!=SQLITE_OK ){
+ rc = rc2;
+ raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
+ }
+ }else{
+ raw_printf(stderr, "%s\n", sqlite3_errmsg(db));
+ }
+
+ return rc;
+}
+
+/*
+** Implementation of ".lint" dot command.
+*/
+static int lintDotCommand(
+ ShellState *pState, /* Current shell tool state */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ int n;
+ n = (nArg>=2 ? strlen30(azArg[1]) : 0);
+ if( n<1 || sqlite3_strnicmp(azArg[1], "fkey-indexes", n) ) goto usage;
+ return lintFkeyIndexes(pState, azArg, nArg);
+
+ usage:
+ raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]);
+ raw_printf(stderr, "Where sub-commands are:\n");
+ raw_printf(stderr, " fkey-indexes\n");
+ return SQLITE_ERROR;
+}
+
+#if !defined SQLITE_OMIT_VIRTUALTABLE
+static void shellPrepare(
+ sqlite3 *db,
+ int *pRc,
+ const char *zSql,
+ sqlite3_stmt **ppStmt
+){
+ *ppStmt = 0;
+ if( *pRc==SQLITE_OK ){
+ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0);
+ if( rc!=SQLITE_OK ){
+ raw_printf(stderr, "sql error: %s (%d)\n",
+ sqlite3_errmsg(db), sqlite3_errcode(db)
+ );
+ *pRc = rc;
+ }
+ }
+}
+
+/*
+** Create a prepared statement using printf-style arguments for the SQL.
+**
+** This routine is could be marked "static". But it is not always used,
+** depending on compile-time options. By omitting the "static", we avoid
+** nuisance compiler warnings about "defined but not used".
+*/
+void shellPreparePrintf(
+ sqlite3 *db,
+ int *pRc,
+ sqlite3_stmt **ppStmt,
+ const char *zFmt,
+ ...
+){
+ *ppStmt = 0;
+ if( *pRc==SQLITE_OK ){
+ va_list ap;
+ char *z;
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ if( z==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ shellPrepare(db, pRc, z, ppStmt);
+ sqlite3_free(z);
+ }
+ }
+}
+
+/* Finalize the prepared statement created using shellPreparePrintf().
+**
+** This routine is could be marked "static". But it is not always used,
+** depending on compile-time options. By omitting the "static", we avoid
+** nuisance compiler warnings about "defined but not used".
+*/
+void shellFinalize(
+ int *pRc,
+ sqlite3_stmt *pStmt
+){
+ if( pStmt ){
+ sqlite3 *db = sqlite3_db_handle(pStmt);
+ int rc = sqlite3_finalize(pStmt);
+ if( *pRc==SQLITE_OK ){
+ if( rc!=SQLITE_OK ){
+ raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
+ }
+ *pRc = rc;
+ }
+ }
+}
+
+/* Reset the prepared statement created using shellPreparePrintf().
+**
+** This routine is could be marked "static". But it is not always used,
+** depending on compile-time options. By omitting the "static", we avoid
+** nuisance compiler warnings about "defined but not used".
+*/
+void shellReset(
+ int *pRc,
+ sqlite3_stmt *pStmt
+){
+ int rc = sqlite3_reset(pStmt);
+ if( *pRc==SQLITE_OK ){
+ if( rc!=SQLITE_OK ){
+ sqlite3 *db = sqlite3_db_handle(pStmt);
+ raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
+ }
+ *pRc = rc;
+ }
+}
+#endif /* !defined SQLITE_OMIT_VIRTUALTABLE */
+
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
+/******************************************************************************
+** The ".archive" or ".ar" command.
+*/
+/*
+** Structure representing a single ".ar" command.
+*/
+typedef struct ArCommand ArCommand;
+struct ArCommand {
+ u8 eCmd; /* An AR_CMD_* value */
+ u8 bVerbose; /* True if --verbose */
+ u8 bZip; /* True if the archive is a ZIP */
+ u8 bDryRun; /* True if --dry-run */
+ u8 bAppend; /* True if --append */
+ u8 fromCmdLine; /* Run from -A instead of .archive */
+ int nArg; /* Number of command arguments */
+ char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
+ const char *zFile; /* --file argument, or NULL */
+ const char *zDir; /* --directory argument, or NULL */
+ char **azArg; /* Array of command arguments */
+ ShellState *p; /* Shell state */
+ sqlite3 *db; /* Database containing the archive */
+};
+
+/*
+** Print a usage message for the .ar command to stderr and return SQLITE_ERROR.
+*/
+static int arUsage(FILE *f){
+ showHelp(f,"archive");
+ return SQLITE_ERROR;
+}
+
+/*
+** Print an error message for the .ar command to stderr and return
+** SQLITE_ERROR.
+*/
+static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
+ va_list ap;
+ char *z;
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ utf8_printf(stderr, "Error: %s\n", z);
+ if( pAr->fromCmdLine ){
+ utf8_printf(stderr, "Use \"-A\" for more help\n");
+ }else{
+ utf8_printf(stderr, "Use \".archive --help\" for more help\n");
+ }
+ sqlite3_free(z);
+ return SQLITE_ERROR;
+}
+
+/*
+** Values for ArCommand.eCmd.
+*/
+#define AR_CMD_CREATE 1
+#define AR_CMD_UPDATE 2
+#define AR_CMD_INSERT 3
+#define AR_CMD_EXTRACT 4
+#define AR_CMD_LIST 5
+#define AR_CMD_HELP 6
+
+/*
+** Other (non-command) switches.
+*/
+#define AR_SWITCH_VERBOSE 7
+#define AR_SWITCH_FILE 8
+#define AR_SWITCH_DIRECTORY 9
+#define AR_SWITCH_APPEND 10
+#define AR_SWITCH_DRYRUN 11
+
+static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
+ switch( eSwitch ){
+ case AR_CMD_CREATE:
+ case AR_CMD_EXTRACT:
+ case AR_CMD_LIST:
+ case AR_CMD_UPDATE:
+ case AR_CMD_INSERT:
+ case AR_CMD_HELP:
+ if( pAr->eCmd ){
+ return arErrorMsg(pAr, "multiple command options");
+ }
+ pAr->eCmd = eSwitch;
+ break;
+
+ case AR_SWITCH_DRYRUN:
+ pAr->bDryRun = 1;
+ break;
+ case AR_SWITCH_VERBOSE:
+ pAr->bVerbose = 1;
+ break;
+ case AR_SWITCH_APPEND:
+ pAr->bAppend = 1;
+ /* Fall thru into --file */
+ case AR_SWITCH_FILE:
+ pAr->zFile = zArg;
+ break;
+ case AR_SWITCH_DIRECTORY:
+ pAr->zDir = zArg;
+ break;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Parse the command line for an ".ar" command. The results are written into
+** structure (*pAr). SQLITE_OK is returned if the command line is parsed
+** successfully, otherwise an error message is written to stderr and
+** SQLITE_ERROR returned.
+*/
+static int arParseCommand(
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg, /* Number of entries in azArg[] */
+ ArCommand *pAr /* Populate this object */
+){
+ struct ArSwitch {
+ const char *zLong;
+ char cShort;
+ u8 eSwitch;
+ u8 bArg;
+ } aSwitch[] = {
+ { "create", 'c', AR_CMD_CREATE, 0 },
+ { "extract", 'x', AR_CMD_EXTRACT, 0 },
+ { "insert", 'i', AR_CMD_INSERT, 0 },
+ { "list", 't', AR_CMD_LIST, 0 },
+ { "update", 'u', AR_CMD_UPDATE, 0 },
+ { "help", 'h', AR_CMD_HELP, 0 },
+ { "verbose", 'v', AR_SWITCH_VERBOSE, 0 },
+ { "file", 'f', AR_SWITCH_FILE, 1 },
+ { "append", 'a', AR_SWITCH_APPEND, 1 },
+ { "directory", 'C', AR_SWITCH_DIRECTORY, 1 },
+ { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 },
+ };
+ int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch);
+ struct ArSwitch *pEnd = &aSwitch[nSwitch];
+
+ if( nArg<=1 ){
+ utf8_printf(stderr, "Wrong number of arguments. Usage:\n");
+ return arUsage(stderr);
+ }else{
+ char *z = azArg[1];
+ if( z[0]!='-' ){
+ /* Traditional style [tar] invocation */
+ int i;
+ int iArg = 2;
+ for(i=0; z[i]; i++){
+ const char *zArg = 0;
+ struct ArSwitch *pOpt;
+ for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
+ if( z[i]==pOpt->cShort ) break;
+ }
+ if( pOpt==pEnd ){
+ return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
+ }
+ if( pOpt->bArg ){
+ if( iArg>=nArg ){
+ return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
+ }
+ zArg = azArg[iArg++];
+ }
+ if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
+ }
+ pAr->nArg = nArg-iArg;
+ if( pAr->nArg>0 ){
+ pAr->azArg = &azArg[iArg];
+ }
+ }else{
+ /* Non-traditional invocation */
+ int iArg;
+ for(iArg=1; iArg<nArg; iArg++){
+ int n;
+ z = azArg[iArg];
+ if( z[0]!='-' ){
+ /* All remaining command line words are command arguments. */
+ pAr->azArg = &azArg[iArg];
+ pAr->nArg = nArg-iArg;
+ break;
+ }
+ n = strlen30(z);
+
+ if( z[1]!='-' ){
+ int i;
+ /* One or more short options */
+ for(i=1; i<n; i++){
+ const char *zArg = 0;
+ struct ArSwitch *pOpt;
+ for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
+ if( z[i]==pOpt->cShort ) break;
+ }
+ if( pOpt==pEnd ){
+ return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
+ }
+ if( pOpt->bArg ){
+ if( i<(n-1) ){
+ zArg = &z[i+1];
+ i = n;
+ }else{
+ if( iArg>=(nArg-1) ){
+ return arErrorMsg(pAr, "option requires an argument: %c",
+ z[i]);
+ }
+ zArg = azArg[++iArg];
+ }
+ }
+ if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR;
+ }
+ }else if( z[2]=='\0' ){
+ /* A -- option, indicating that all remaining command line words
+ ** are command arguments. */
+ pAr->azArg = &azArg[iArg+1];
+ pAr->nArg = nArg-iArg-1;
+ break;
+ }else{
+ /* A long option */
+ const char *zArg = 0; /* Argument for option, if any */
+ struct ArSwitch *pMatch = 0; /* Matching option */
+ struct ArSwitch *pOpt; /* Iterator */
+ for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){
+ const char *zLong = pOpt->zLong;
+ if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
+ if( pMatch ){
+ return arErrorMsg(pAr, "ambiguous option: %s",z);
+ }else{
+ pMatch = pOpt;
+ }
+ }
+ }
+
+ if( pMatch==0 ){
+ return arErrorMsg(pAr, "unrecognized option: %s", z);
+ }
+ if( pMatch->bArg ){
+ if( iArg>=(nArg-1) ){
+ return arErrorMsg(pAr, "option requires an argument: %s", z);
+ }
+ zArg = azArg[++iArg];
+ }
+ if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR;
+ }
+ }
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** This function assumes that all arguments within the ArCommand.azArg[]
+** array refer to archive members, as for the --extract or --list commands.
+** It checks that each of them are present. If any specified file is not
+** present in the archive, an error is printed to stderr and an error
+** code returned. Otherwise, if all specified arguments are present in
+** the archive, SQLITE_OK is returned.
+**
+** This function strips any trailing '/' characters from each argument.
+** This is consistent with the way the [tar] command seems to work on
+** Linux.
+*/
+static int arCheckEntries(ArCommand *pAr){
+ int rc = SQLITE_OK;
+ if( pAr->nArg ){
+ int i, j;
+ sqlite3_stmt *pTest = 0;
+
+ shellPreparePrintf(pAr->db, &rc, &pTest,
+ "SELECT name FROM %s WHERE name=$name",
+ pAr->zSrcTable
+ );
+ j = sqlite3_bind_parameter_index(pTest, "$name");
+ for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
+ char *z = pAr->azArg[i];
+ int n = strlen30(z);
+ int bOk = 0;
+ while( n>0 && z[n-1]=='/' ) n--;
+ z[n] = '\0';
+ sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pTest) ){
+ bOk = 1;
+ }
+ shellReset(&rc, pTest);
+ if( rc==SQLITE_OK && bOk==0 ){
+ utf8_printf(stderr, "not found in archive: %s\n", z);
+ rc = SQLITE_ERROR;
+ }
+ }
+ shellFinalize(&rc, pTest);
+ }
+ return rc;
+}
+
+/*
+** Format a WHERE clause that can be used against the "sqlar" table to
+** identify all archive members that match the command arguments held
+** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning.
+** The caller is responsible for eventually calling sqlite3_free() on
+** any non-NULL (*pzWhere) value.
+*/
+static void arWhereClause(
+ int *pRc,
+ ArCommand *pAr,
+ char **pzWhere /* OUT: New WHERE clause */
+){
+ char *zWhere = 0;
+ if( *pRc==SQLITE_OK ){
+ if( pAr->nArg==0 ){
+ zWhere = sqlite3_mprintf("1");
+ }else{
+ int i;
+ const char *zSep = "";
+ for(i=0; i<pAr->nArg; i++){
+ const char *z = pAr->azArg[i];
+ zWhere = sqlite3_mprintf(
+ "%z%s name = '%q' OR substr(name,1,%d) = '%q/'",
+ zWhere, zSep, z, strlen30(z)+1, z
+ );
+ if( zWhere==0 ){
+ *pRc = SQLITE_NOMEM;
+ break;
+ }
+ zSep = " OR ";
+ }
+ }
+ }
+ *pzWhere = zWhere;
+}
+
+/*
+** Implementation of .ar "lisT" command.
+*/
+static int arListCommand(ArCommand *pAr){
+ const char *zSql = "SELECT %s FROM %s WHERE %s";
+ const char *azCols[] = {
+ "name",
+ "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name"
+ };
+
+ char *zWhere = 0;
+ sqlite3_stmt *pSql = 0;
+ int rc;
+
+ rc = arCheckEntries(pAr);
+ arWhereClause(&rc, pAr, &zWhere);
+
+ shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose],
+ pAr->zSrcTable, zWhere);
+ if( pAr->bDryRun ){
+ utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
+ }else{
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+ if( pAr->bVerbose ){
+ utf8_printf(pAr->p->out, "%s % 10d %s %s\n",
+ sqlite3_column_text(pSql, 0),
+ sqlite3_column_int(pSql, 1),
+ sqlite3_column_text(pSql, 2),
+ sqlite3_column_text(pSql, 3)
+ );
+ }else{
+ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
+ }
+ }
+ }
+ shellFinalize(&rc, pSql);
+ sqlite3_free(zWhere);
+ return rc;
+}
+
+
+/*
+** Implementation of .ar "eXtract" command.
+*/
+static int arExtractCommand(ArCommand *pAr){
+ const char *zSql1 =
+ "SELECT "
+ " ($dir || name),"
+ " writefile(($dir || name), %s, mode, mtime) "
+ "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"
+ " AND name NOT GLOB '*..[/\\]*'";
+
+ const char *azExtraArg[] = {
+ "sqlar_uncompress(data, sz)",
+ "data"
+ };
+
+ sqlite3_stmt *pSql = 0;
+ int rc = SQLITE_OK;
+ char *zDir = 0;
+ char *zWhere = 0;
+ int i, j;
+
+ /* If arguments are specified, check that they actually exist within
+ ** the archive before proceeding. And formulate a WHERE clause to
+ ** match them. */
+ rc = arCheckEntries(pAr);
+ arWhereClause(&rc, pAr, &zWhere);
+
+ if( rc==SQLITE_OK ){
+ if( pAr->zDir ){
+ zDir = sqlite3_mprintf("%s/", pAr->zDir);
+ }else{
+ zDir = sqlite3_mprintf("");
+ }
+ if( zDir==0 ) rc = SQLITE_NOMEM;
+ }
+
+ shellPreparePrintf(pAr->db, &rc, &pSql, zSql1,
+ azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere
+ );
+
+ if( rc==SQLITE_OK ){
+ j = sqlite3_bind_parameter_index(pSql, "$dir");
+ sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
+
+ /* Run the SELECT statement twice. The first time, writefile() is called
+ ** for all archive members that should be extracted. The second time,
+ ** only for the directories. This is because the timestamps for
+ ** extracted directories must be reset after they are populated (as
+ ** populating them changes the timestamp). */
+ for(i=0; i<2; i++){
+ j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
+ sqlite3_bind_int(pSql, j, i);
+ if( pAr->bDryRun ){
+ utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql));
+ }else{
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+ if( i==0 && pAr->bVerbose ){
+ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0));
+ }
+ }
+ }
+ shellReset(&rc, pSql);
+ }
+ shellFinalize(&rc, pSql);
+ }
+
+ sqlite3_free(zDir);
+ sqlite3_free(zWhere);
+ return rc;
+}
+
+/*
+** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out.
+*/
+static int arExecSql(ArCommand *pAr, const char *zSql){
+ int rc;
+ if( pAr->bDryRun ){
+ utf8_printf(pAr->p->out, "%s\n", zSql);
+ rc = SQLITE_OK;
+ }else{
+ char *zErr = 0;
+ rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr);
+ if( zErr ){
+ utf8_printf(stdout, "ERROR: %s\n", zErr);
+ sqlite3_free(zErr);
+ }
+ }
+ return rc;
+}
+
+
+/*
+** Implementation of .ar "create", "insert", and "update" commands.
+**
+** create -> Create a new SQL archive
+** insert -> Insert or reinsert all files listed
+** update -> Insert files that have changed or that were not
+** previously in the archive
+**
+** Create the "sqlar" table in the database if it does not already exist.
+** Then add each file in the azFile[] array to the archive. Directories
+** are added recursively. If argument bVerbose is non-zero, a message is
+** printed on stdout for each file archived.
+**
+** The create command is the same as update, except that it drops
+** any existing "sqlar" table before beginning. The "insert" command
+** always overwrites every file named on the command-line, where as
+** "update" only overwrites if the size or mtime or mode has changed.
+*/
+static int arCreateOrUpdateCommand(
+ ArCommand *pAr, /* Command arguments and options */
+ int bUpdate, /* true for a --create. */
+ int bOnlyIfChanged /* Only update if file has changed */
+){
+ const char *zCreate =
+ "CREATE TABLE IF NOT EXISTS sqlar(\n"
+ " name TEXT PRIMARY KEY, -- name of the file\n"
+ " mode INT, -- access permissions\n"
+ " mtime INT, -- last modification time\n"
+ " sz INT, -- original file size\n"
+ " data BLOB -- compressed content\n"
+ ")";
+ const char *zDrop = "DROP TABLE IF EXISTS sqlar";
+ const char *zInsertFmt[2] = {
+ "REPLACE INTO %s(name,mode,mtime,sz,data)\n"
+ " SELECT\n"
+ " %s,\n"
+ " mode,\n"
+ " mtime,\n"
+ " CASE substr(lsmode(mode),1,1)\n"
+ " WHEN '-' THEN length(data)\n"
+ " WHEN 'd' THEN 0\n"
+ " ELSE -1 END,\n"
+ " sqlar_compress(data)\n"
+ " FROM fsdir(%Q,%Q) AS disk\n"
+ " WHERE lsmode(mode) NOT LIKE '?%%'%s;"
+ ,
+ "REPLACE INTO %s(name,mode,mtime,data)\n"
+ " SELECT\n"
+ " %s,\n"
+ " mode,\n"
+ " mtime,\n"
+ " data\n"
+ " FROM fsdir(%Q,%Q) AS disk\n"
+ " WHERE lsmode(mode) NOT LIKE '?%%'%s;"
+ };
+ int i; /* For iterating through azFile[] */
+ int rc; /* Return code */
+ const char *zTab = 0; /* SQL table into which to insert */
+ char *zSql;
+ char zTemp[50];
+ char *zExists = 0;
+
+ arExecSql(pAr, "PRAGMA page_size=512");
+ rc = arExecSql(pAr, "SAVEPOINT ar;");
+ if( rc!=SQLITE_OK ) return rc;
+ zTemp[0] = 0;
+ if( pAr->bZip ){
+ /* Initialize the zipfile virtual table, if necessary */
+ if( pAr->zFile ){
+ sqlite3_uint64 r;
+ sqlite3_randomness(sizeof(r),&r);
+ sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r);
+ zTab = zTemp;
+ zSql = sqlite3_mprintf(
+ "CREATE VIRTUAL TABLE temp.%s USING zipfile(%Q)",
+ zTab, pAr->zFile
+ );
+ rc = arExecSql(pAr, zSql);
+ sqlite3_free(zSql);
+ }else{
+ zTab = "zip";
+ }
+ }else{
+ /* Initialize the table for an SQLAR */
+ zTab = "sqlar";
+ if( bUpdate==0 ){
+ rc = arExecSql(pAr, zDrop);
+ if( rc!=SQLITE_OK ) goto end_ar_transaction;
+ }
+ rc = arExecSql(pAr, zCreate);
+ }
+ if( bOnlyIfChanged ){
+ zExists = sqlite3_mprintf(
+ " AND NOT EXISTS("
+ "SELECT 1 FROM %s AS mem"
+ " WHERE mem.name=disk.name"
+ " AND mem.mtime=disk.mtime"
+ " AND mem.mode=disk.mode)", zTab);
+ }else{
+ zExists = sqlite3_mprintf("");
+ }
+ if( zExists==0 ) rc = SQLITE_NOMEM;
+ for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){
+ char *zSql2 = sqlite3_mprintf(zInsertFmt[pAr->bZip], zTab,
+ pAr->bVerbose ? "shell_putsnl(name)" : "name",
+ pAr->azArg[i], pAr->zDir, zExists);
+ rc = arExecSql(pAr, zSql2);
+ sqlite3_free(zSql2);
+ }
+end_ar_transaction:
+ if( rc!=SQLITE_OK ){
+ sqlite3_exec(pAr->db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0);
+ }else{
+ rc = arExecSql(pAr, "RELEASE ar;");
+ if( pAr->bZip && pAr->zFile ){
+ zSql = sqlite3_mprintf("DROP TABLE %s", zTemp);
+ arExecSql(pAr, zSql);
+ sqlite3_free(zSql);
+ }
+ }
+ sqlite3_free(zExists);
+ return rc;
+}
+
+/*
+** Implementation of ".ar" dot command.
+*/
+static int arDotCommand(
+ ShellState *pState, /* Current shell tool state */
+ int fromCmdLine, /* True if -A command-line option, not .ar cmd */
+ char **azArg, /* Array of arguments passed to dot command */
+ int nArg /* Number of entries in azArg[] */
+){
+ ArCommand cmd;
+ int rc;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.fromCmdLine = fromCmdLine;
+ rc = arParseCommand(azArg, nArg, &cmd);
+ if( rc==SQLITE_OK ){
+ int eDbType = SHELL_OPEN_UNSPEC;
+ cmd.p = pState;
+ cmd.db = pState->db;
+ if( cmd.zFile ){
+ eDbType = deduceDatabaseType(cmd.zFile, 1);
+ }else{
+ eDbType = pState->openMode;
+ }
+ if( eDbType==SHELL_OPEN_ZIPFILE ){
+ if( cmd.eCmd==AR_CMD_EXTRACT || cmd.eCmd==AR_CMD_LIST ){
+ if( cmd.zFile==0 ){
+ cmd.zSrcTable = sqlite3_mprintf("zip");
+ }else{
+ cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile);
+ }
+ }
+ cmd.bZip = 1;
+ }else if( cmd.zFile ){
+ int flags;
+ if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS;
+ if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_INSERT
+ || cmd.eCmd==AR_CMD_UPDATE ){
+ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
+ }else{
+ flags = SQLITE_OPEN_READONLY;
+ }
+ cmd.db = 0;
+ if( cmd.bDryRun ){
+ utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile,
+ eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : "");
+ }
+ rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags,
+ eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0);
+ if( rc!=SQLITE_OK ){
+ utf8_printf(stderr, "cannot open file: %s (%s)\n",
+ cmd.zFile, sqlite3_errmsg(cmd.db)
+ );
+ goto end_ar_command;
+ }
+ sqlite3_fileio_init(cmd.db, 0, 0);
+ sqlite3_sqlar_init(cmd.db, 0, 0);
+ sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p,
+ shellPutsFunc, 0, 0);
+
+ }
+ if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
+ if( cmd.eCmd!=AR_CMD_CREATE
+ && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
+ ){
+ utf8_printf(stderr, "database does not contain an 'sqlar' table\n");
+ rc = SQLITE_ERROR;
+ goto end_ar_command;
+ }
+ cmd.zSrcTable = sqlite3_mprintf("sqlar");
+ }
+
+ switch( cmd.eCmd ){
+ case AR_CMD_CREATE:
+ rc = arCreateOrUpdateCommand(&cmd, 0, 0);
+ break;
+
+ case AR_CMD_EXTRACT:
+ rc = arExtractCommand(&cmd);
+ break;
+
+ case AR_CMD_LIST:
+ rc = arListCommand(&cmd);
+ break;
+
+ case AR_CMD_HELP:
+ arUsage(pState->out);
+ break;
+
+ case AR_CMD_INSERT:
+ rc = arCreateOrUpdateCommand(&cmd, 1, 0);
+ break;
+
+ default:
+ assert( cmd.eCmd==AR_CMD_UPDATE );
+ rc = arCreateOrUpdateCommand(&cmd, 1, 1);
+ break;
+ }
+ }
+end_ar_command:
+ if( cmd.db!=pState->db ){
+ close_db(cmd.db);
+ }
+ sqlite3_free(cmd.zSrcTable);
+
+ return rc;
+}
+/* End of the ".archive" or ".ar" command logic
+*******************************************************************************/
+#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */
+
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+/*
+** If (*pRc) is not SQLITE_OK when this function is called, it is a no-op.
+** Otherwise, the SQL statement or statements in zSql are executed using
+** database connection db and the error code written to *pRc before
+** this function returns.
+*/
+static void shellExec(sqlite3 *db, int *pRc, const char *zSql){
+ int rc = *pRc;
+ if( rc==SQLITE_OK ){
+ char *zErr = 0;
+ rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
+ if( rc!=SQLITE_OK ){
+ raw_printf(stderr, "SQL error: %s\n", zErr);
+ }
+ *pRc = rc;
+ }
+}
+
+/*
+** Like shellExec(), except that zFmt is a printf() style format string.
+*/
+static void shellExecPrintf(sqlite3 *db, int *pRc, const char *zFmt, ...){
+ char *z = 0;
+ if( *pRc==SQLITE_OK ){
+ va_list ap;
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ if( z==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ shellExec(db, pRc, z);
+ }
+ sqlite3_free(z);
+ }
+}
+
+/*
+** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
+** Otherwise, an attempt is made to allocate, zero and return a pointer
+** to a buffer nByte bytes in size. If an OOM error occurs, *pRc is set
+** to SQLITE_NOMEM and NULL returned.
+*/
+static void *shellMalloc(int *pRc, sqlite3_int64 nByte){
+ void *pRet = 0;
+ if( *pRc==SQLITE_OK ){
+ pRet = sqlite3_malloc64(nByte);
+ if( pRet==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ memset(pRet, 0, nByte);
+ }
+ }
+ return pRet;
+}
+
+/*
+** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
+** Otherwise, zFmt is treated as a printf() style string. The result of
+** formatting it along with any trailing arguments is written into a
+** buffer obtained from sqlite3_malloc(), and pointer to which is returned.
+** It is the responsibility of the caller to eventually free this buffer
+** using a call to sqlite3_free().
+**
+** If an OOM error occurs, (*pRc) is set to SQLITE_NOMEM and a NULL
+** pointer returned.
+*/
+static char *shellMPrintf(int *pRc, const char *zFmt, ...){
+ char *z = 0;
+ if( *pRc==SQLITE_OK ){
+ va_list ap;
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+ va_end(ap);
+ if( z==0 ){
+ *pRc = SQLITE_NOMEM;
+ }
+ }
+ return z;
+}
+
+/*
+** When running the ".recover" command, each output table, and the special
+** orphaned row table if it is required, is represented by an instance
+** of the following struct.
+*/
+typedef struct RecoverTable RecoverTable;
+struct RecoverTable {
+ char *zQuoted; /* Quoted version of table name */
+ int nCol; /* Number of columns in table */
+ char **azlCol; /* Array of column lists */
+ int iPk; /* Index of IPK column */
+};
+
+/*
+** Free a RecoverTable object allocated by recoverFindTable() or
+** recoverOrphanTable().
+*/
+static void recoverFreeTable(RecoverTable *pTab){
+ if( pTab ){
+ sqlite3_free(pTab->zQuoted);
+ if( pTab->azlCol ){
+ int i;
+ for(i=0; i<=pTab->nCol; i++){
+ sqlite3_free(pTab->azlCol[i]);
+ }
+ sqlite3_free(pTab->azlCol);
+ }
+ sqlite3_free(pTab);
+ }
+}
+
+/*
+** This function is a no-op if (*pRc) is not SQLITE_OK when it is called.
+** Otherwise, it allocates and returns a RecoverTable object based on the
+** final four arguments passed to this function. It is the responsibility
+** of the caller to eventually free the returned object using
+** recoverFreeTable().
+*/
+static RecoverTable *recoverNewTable(
+ int *pRc, /* IN/OUT: Error code */
+ const char *zName, /* Name of table */
+ const char *zSql, /* CREATE TABLE statement */
+ int bIntkey,
+ int nCol
+){
+ sqlite3 *dbtmp = 0; /* sqlite3 handle for testing CREATE TABLE */
+ int rc = *pRc;
+ RecoverTable *pTab = 0;
+
+ pTab = (RecoverTable*)shellMalloc(&rc, sizeof(RecoverTable));
+ if( rc==SQLITE_OK ){
+ int nSqlCol = 0;
+ int bSqlIntkey = 0;
+ sqlite3_stmt *pStmt = 0;
+
+ rc = sqlite3_open("", &dbtmp);
+ if( rc==SQLITE_OK ){
+ sqlite3_create_function(dbtmp, "shell_idquote", 1, SQLITE_UTF8, 0,
+ shellIdQuote, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(dbtmp, "PRAGMA writable_schema = on", 0, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(dbtmp, zSql, 0, 0, 0);
+ if( rc==SQLITE_ERROR ){
+ rc = SQLITE_OK;
+ goto finished;
+ }
+ }
+ shellPreparePrintf(dbtmp, &rc, &pStmt,
+ "SELECT count(*) FROM pragma_table_info(%Q)", zName
+ );
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ nSqlCol = sqlite3_column_int(pStmt, 0);
+ }
+ shellFinalize(&rc, pStmt);
+
+ if( rc!=SQLITE_OK || nSqlCol<nCol ){
+ goto finished;
+ }
+
+ shellPreparePrintf(dbtmp, &rc, &pStmt,
+ "SELECT ("
+ " SELECT substr(data,1,1)==X'0D' FROM sqlite_dbpage WHERE pgno=rootpage"
+ ") FROM sqlite_schema WHERE name = %Q", zName
+ );
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ bSqlIntkey = sqlite3_column_int(pStmt, 0);
+ }
+ shellFinalize(&rc, pStmt);
+
+ if( bIntkey==bSqlIntkey ){
+ int i;
+ const char *zPk = "_rowid_";
+ sqlite3_stmt *pPkFinder = 0;
+
+ /* If this is an intkey table and there is an INTEGER PRIMARY KEY,
+ ** set zPk to the name of the PK column, and pTab->iPk to the index
+ ** of the column, where columns are 0-numbered from left to right.
+ ** Or, if this is a WITHOUT ROWID table or if there is no IPK column,
+ ** leave zPk as "_rowid_" and pTab->iPk at -2. */
+ pTab->iPk = -2;
+ if( bIntkey ){
+ shellPreparePrintf(dbtmp, &rc, &pPkFinder,
+ "SELECT cid, name FROM pragma_table_info(%Q) "
+ " WHERE pk=1 AND type='integer' COLLATE nocase"
+ " AND NOT EXISTS (SELECT cid FROM pragma_table_info(%Q) WHERE pk=2)"
+ , zName, zName
+ );
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPkFinder) ){
+ pTab->iPk = sqlite3_column_int(pPkFinder, 0);
+ zPk = (const char*)sqlite3_column_text(pPkFinder, 1);
+ }
+ }
+
+ pTab->zQuoted = shellMPrintf(&rc, "\"%w\"", zName);
+ pTab->azlCol = (char**)shellMalloc(&rc, sizeof(char*) * (nSqlCol+1));
+ pTab->nCol = nSqlCol;
+
+ if( bIntkey ){
+ pTab->azlCol[0] = shellMPrintf(&rc, "\"%w\"", zPk);
+ }else{
+ pTab->azlCol[0] = shellMPrintf(&rc, "");
+ }
+ i = 1;
+ shellPreparePrintf(dbtmp, &rc, &pStmt,
+ "SELECT %Q || group_concat(shell_idquote(name), ', ') "
+ " FILTER (WHERE cid!=%d) OVER (ORDER BY %s cid) "
+ "FROM pragma_table_info(%Q)",
+ bIntkey ? ", " : "", pTab->iPk,
+ bIntkey ? "" : "(CASE WHEN pk=0 THEN 1000000 ELSE pk END), ",
+ zName
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zText = (const char*)sqlite3_column_text(pStmt, 0);
+ pTab->azlCol[i] = shellMPrintf(&rc, "%s%s", pTab->azlCol[0], zText);
+ i++;
+ }
+ shellFinalize(&rc, pStmt);
+
+ shellFinalize(&rc, pPkFinder);
+ }
+ }
+
+ finished:
+ sqlite3_close(dbtmp);
+ *pRc = rc;
+ if( rc!=SQLITE_OK || (pTab && pTab->zQuoted==0) ){
+ recoverFreeTable(pTab);
+ pTab = 0;
+ }
+ return pTab;
+}
+
+/*
+** This function is called to search the schema recovered from the
+** sqlite_schema table of the (possibly) corrupt database as part
+** of a ".recover" command. Specifically, for a table with root page
+** iRoot and at least nCol columns. Additionally, if bIntkey is 0, the
+** table must be a WITHOUT ROWID table, or if non-zero, not one of
+** those.
+**
+** If a table is found, a (RecoverTable*) object is returned. Or, if
+** no such table is found, but bIntkey is false and iRoot is the
+** root page of an index in the recovered schema, then (*pbNoop) is
+** set to true and NULL returned. Or, if there is no such table or
+** index, NULL is returned and (*pbNoop) set to 0, indicating that
+** the caller should write data to the orphans table.
+*/
+static RecoverTable *recoverFindTable(
+ ShellState *pState, /* Shell state object */
+ int *pRc, /* IN/OUT: Error code */
+ int iRoot, /* Root page of table */
+ int bIntkey, /* True for an intkey table */
+ int nCol, /* Number of columns in table */
+ int *pbNoop /* OUT: True if iRoot is root of index */
+){
+ sqlite3_stmt *pStmt = 0;
+ RecoverTable *pRet = 0;
+ int bNoop = 0;
+ const char *zSql = 0;
+ const char *zName = 0;
+
+ /* Search the recovered schema for an object with root page iRoot. */
+ shellPreparePrintf(pState->db, pRc, &pStmt,
+ "SELECT type, name, sql FROM recovery.schema WHERE rootpage=%d", iRoot
+ );
+ while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zType = (const char*)sqlite3_column_text(pStmt, 0);
+ if( bIntkey==0 && sqlite3_stricmp(zType, "index")==0 ){
+ bNoop = 1;
+ break;
+ }
+ if( sqlite3_stricmp(zType, "table")==0 ){
+ zName = (const char*)sqlite3_column_text(pStmt, 1);
+ zSql = (const char*)sqlite3_column_text(pStmt, 2);
+ pRet = recoverNewTable(pRc, zName, zSql, bIntkey, nCol);
+ break;
+ }
+ }
+
+ shellFinalize(pRc, pStmt);
+ *pbNoop = bNoop;
+ return pRet;
+}
+
+/*
+** Return a RecoverTable object representing the orphans table.
+*/
+static RecoverTable *recoverOrphanTable(
+ ShellState *pState, /* Shell state object */
+ int *pRc, /* IN/OUT: Error code */
+ const char *zLostAndFound, /* Base name for orphans table */
+ int nCol /* Number of user data columns */
+){
+ RecoverTable *pTab = 0;
+ if( nCol>=0 && *pRc==SQLITE_OK ){
+ int i;
+
+ /* This block determines the name of the orphan table. The prefered
+ ** name is zLostAndFound. But if that clashes with another name
+ ** in the recovered schema, try zLostAndFound_0, zLostAndFound_1
+ ** and so on until a non-clashing name is found. */
+ int iTab = 0;
+ char *zTab = shellMPrintf(pRc, "%s", zLostAndFound);
+ sqlite3_stmt *pTest = 0;
+ shellPrepare(pState->db, pRc,
+ "SELECT 1 FROM recovery.schema WHERE name=?", &pTest
+ );
+ if( pTest ) sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
+ while( *pRc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pTest) ){
+ shellReset(pRc, pTest);
+ sqlite3_free(zTab);
+ zTab = shellMPrintf(pRc, "%s_%d", zLostAndFound, iTab++);
+ sqlite3_bind_text(pTest, 1, zTab, -1, SQLITE_TRANSIENT);
+ }
+ shellFinalize(pRc, pTest);
+
+ pTab = (RecoverTable*)shellMalloc(pRc, sizeof(RecoverTable));
+ if( pTab ){
+ pTab->zQuoted = shellMPrintf(pRc, "\"%w\"", zTab);
+ pTab->nCol = nCol;
+ pTab->iPk = -2;
+ if( nCol>0 ){
+ pTab->azlCol = (char**)shellMalloc(pRc, sizeof(char*) * (nCol+1));
+ if( pTab->azlCol ){
+ pTab->azlCol[nCol] = shellMPrintf(pRc, "");
+ for(i=nCol-1; i>=0; i--){
+ pTab->azlCol[i] = shellMPrintf(pRc, "%s, NULL", pTab->azlCol[i+1]);
+ }
+ }
+ }
+
+ if( *pRc!=SQLITE_OK ){
+ recoverFreeTable(pTab);
+ pTab = 0;
+ }else{
+ raw_printf(pState->out,
+ "CREATE TABLE %s(rootpgno INTEGER, "
+ "pgno INTEGER, nfield INTEGER, id INTEGER", pTab->zQuoted
+ );
+ for(i=0; i<nCol; i++){
+ raw_printf(pState->out, ", c%d", i);
+ }
+ raw_printf(pState->out, ");\n");
+ }
+ }
+ sqlite3_free(zTab);
+ }
+ return pTab;
+}
+
+/*
+** This function is called to recover data from the database. A script
+** to construct a new database containing all recovered data is output
+** on stream pState->out.
+*/
+static int recoverDatabaseCmd(ShellState *pState, int nArg, char **azArg){
+ int rc = SQLITE_OK;
+ sqlite3_stmt *pLoop = 0; /* Loop through all root pages */
+ sqlite3_stmt *pPages = 0; /* Loop through all pages in a group */
+ sqlite3_stmt *pCells = 0; /* Loop through all cells in a page */
+ const char *zRecoveryDb = ""; /* Name of "recovery" database */
+ const char *zLostAndFound = "lost_and_found";
+ int i;
+ int nOrphan = -1;
+ RecoverTable *pOrphan = 0;
+
+ int bFreelist = 1; /* 0 if --freelist-corrupt is specified */
+ int bRowids = 1; /* 0 if --no-rowids */
+ for(i=1; i<nArg; i++){
+ char *z = azArg[i];
+ int n;
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ n = strlen30(z);
+ if( n<=17 && memcmp("-freelist-corrupt", z, n)==0 ){
+ bFreelist = 0;
+ }else
+ if( n<=12 && memcmp("-recovery-db", z, n)==0 && i<(nArg-1) ){
+ i++;
+ zRecoveryDb = azArg[i];
+ }else
+ if( n<=15 && memcmp("-lost-and-found", z, n)==0 && i<(nArg-1) ){
+ i++;
+ zLostAndFound = azArg[i];
+ }else
+ if( n<=10 && memcmp("-no-rowids", z, n)==0 ){
+ bRowids = 0;
+ }
+ else{
+ utf8_printf(stderr, "unexpected option: %s\n", azArg[i]);
+ showHelp(pState->out, azArg[0]);
+ return 1;
+ }
+ }
+
+ shellExecPrintf(pState->db, &rc,
+ /* Attach an in-memory database named 'recovery'. Create an indexed
+ ** cache of the sqlite_dbptr virtual table. */
+ "PRAGMA writable_schema = on;"
+ "ATTACH %Q AS recovery;"
+ "DROP TABLE IF EXISTS recovery.dbptr;"
+ "DROP TABLE IF EXISTS recovery.freelist;"
+ "DROP TABLE IF EXISTS recovery.map;"
+ "DROP TABLE IF EXISTS recovery.schema;"
+ "CREATE TABLE recovery.freelist(pgno INTEGER PRIMARY KEY);", zRecoveryDb
+ );
+
+ if( bFreelist ){
+ shellExec(pState->db, &rc,
+ "WITH trunk(pgno) AS ("
+ " SELECT shell_int32("
+ " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 8) AS x "
+ " WHERE x>0"
+ " UNION"
+ " SELECT shell_int32("
+ " (SELECT data FROM sqlite_dbpage WHERE pgno=trunk.pgno), 0) AS x "
+ " FROM trunk WHERE x>0"
+ "),"
+ "freelist(data, n, freepgno) AS ("
+ " SELECT data, min(16384, shell_int32(data, 1)-1), t.pgno "
+ " FROM trunk t, sqlite_dbpage s WHERE s.pgno=t.pgno"
+ " UNION ALL"
+ " SELECT data, n-1, shell_int32(data, 2+n) "
+ " FROM freelist WHERE n>=0"
+ ")"
+ "REPLACE INTO recovery.freelist SELECT freepgno FROM freelist;"
+ );
+ }
+
+ /* If this is an auto-vacuum database, add all pointer-map pages to
+ ** the freelist table. Do this regardless of whether or not
+ ** --freelist-corrupt was specified. */
+ shellExec(pState->db, &rc,
+ "WITH ptrmap(pgno) AS ("
+ " SELECT 2 WHERE shell_int32("
+ " (SELECT data FROM sqlite_dbpage WHERE pgno=1), 13"
+ " )"
+ " UNION ALL "
+ " SELECT pgno+1+(SELECT page_size FROM pragma_page_size)/5 AS pp "
+ " FROM ptrmap WHERE pp<=(SELECT page_count FROM pragma_page_count)"
+ ")"
+ "REPLACE INTO recovery.freelist SELECT pgno FROM ptrmap"
+ );
+
+ shellExec(pState->db, &rc,
+ "CREATE TABLE recovery.dbptr("
+ " pgno, child, PRIMARY KEY(child, pgno)"
+ ") WITHOUT ROWID;"
+ "INSERT OR IGNORE INTO recovery.dbptr(pgno, child) "
+ " SELECT * FROM sqlite_dbptr"
+ " WHERE pgno NOT IN freelist AND child NOT IN freelist;"
+
+ /* Delete any pointer to page 1. This ensures that page 1 is considered
+ ** a root page, regardless of how corrupt the db is. */
+ "DELETE FROM recovery.dbptr WHERE child = 1;"
+
+ /* Delete all pointers to any pages that have more than one pointer
+ ** to them. Such pages will be treated as root pages when recovering
+ ** data. */
+ "DELETE FROM recovery.dbptr WHERE child IN ("
+ " SELECT child FROM recovery.dbptr GROUP BY child HAVING count(*)>1"
+ ");"
+
+ /* Create the "map" table that will (eventually) contain instructions
+ ** for dealing with each page in the db that contains one or more
+ ** records. */
+ "CREATE TABLE recovery.map("
+ "pgno INTEGER PRIMARY KEY, maxlen INT, intkey, root INT"
+ ");"
+
+ /* Populate table [map]. If there are circular loops of pages in the
+ ** database, the following adds all pages in such a loop to the map
+ ** as individual root pages. This could be handled better. */
+ "WITH pages(i, maxlen) AS ("
+ " SELECT page_count, ("
+ " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=page_count"
+ " ) FROM pragma_page_count WHERE page_count>0"
+ " UNION ALL"
+ " SELECT i-1, ("
+ " SELECT max(field+1) FROM sqlite_dbdata WHERE pgno=i-1"
+ " ) FROM pages WHERE i>=2"
+ ")"
+ "INSERT INTO recovery.map(pgno, maxlen, intkey, root) "
+ " SELECT i, maxlen, NULL, ("
+ " WITH p(orig, pgno, parent) AS ("
+ " SELECT 0, i, (SELECT pgno FROM recovery.dbptr WHERE child=i)"
+ " UNION "
+ " SELECT i, p.parent, "
+ " (SELECT pgno FROM recovery.dbptr WHERE child=p.parent) FROM p"
+ " )"
+ " SELECT pgno FROM p WHERE (parent IS NULL OR pgno = orig)"
+ ") "
+ "FROM pages WHERE maxlen IS NOT NULL AND i NOT IN freelist;"
+ "UPDATE recovery.map AS o SET intkey = ("
+ " SELECT substr(data, 1, 1)==X'0D' FROM sqlite_dbpage WHERE pgno=o.pgno"
+ ");"
+
+ /* Extract data from page 1 and any linked pages into table
+ ** recovery.schema. With the same schema as an sqlite_schema table. */
+ "CREATE TABLE recovery.schema(type, name, tbl_name, rootpage, sql);"
+ "INSERT INTO recovery.schema SELECT "
+ " max(CASE WHEN field=0 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=1 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=2 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=3 THEN value ELSE NULL END),"
+ " max(CASE WHEN field=4 THEN value ELSE NULL END)"
+ "FROM sqlite_dbdata WHERE pgno IN ("
+ " SELECT pgno FROM recovery.map WHERE root=1"
+ ")"
+ "GROUP BY pgno, cell;"
+ "CREATE INDEX recovery.schema_rootpage ON schema(rootpage);"
+ );
+
+ /* Open a transaction, then print out all non-virtual, non-"sqlite_%"
+ ** CREATE TABLE statements that extracted from the existing schema. */
+ if( rc==SQLITE_OK ){
+ sqlite3_stmt *pStmt = 0;
+ /* ".recover" might output content in an order which causes immediate
+ ** foreign key constraints to be violated. So disable foreign-key
+ ** constraint enforcement to prevent problems when running the output
+ ** script. */
+ raw_printf(pState->out, "PRAGMA foreign_keys=OFF;\n");
+ raw_printf(pState->out, "BEGIN;\n");
+ raw_printf(pState->out, "PRAGMA writable_schema = on;\n");
+ shellPrepare(pState->db, &rc,
+ "SELECT sql FROM recovery.schema "
+ "WHERE type='table' AND sql LIKE 'create table%'", &pStmt
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zCreateTable = (const char*)sqlite3_column_text(pStmt, 0);
+ raw_printf(pState->out, "CREATE TABLE IF NOT EXISTS %s;\n",
+ &zCreateTable[12]
+ );
+ }
+ shellFinalize(&rc, pStmt);
+ }
+
+ /* Figure out if an orphan table will be required. And if so, how many
+ ** user columns it should contain */
+ shellPrepare(pState->db, &rc,
+ "SELECT coalesce(max(maxlen), -2) FROM recovery.map WHERE root>1"
+ , &pLoop
+ );
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
+ nOrphan = sqlite3_column_int(pLoop, 0);
+ }
+ shellFinalize(&rc, pLoop);
+ pLoop = 0;
+
+ shellPrepare(pState->db, &rc,
+ "SELECT pgno FROM recovery.map WHERE root=?", &pPages
+ );
+
+ shellPrepare(pState->db, &rc,
+ "SELECT max(field), group_concat(shell_escape_crnl(quote"
+ "(case when (? AND field<0) then NULL else value end)"
+ "), ', ')"
+ ", min(field) "
+ "FROM sqlite_dbdata WHERE pgno = ? AND field != ?"
+ "GROUP BY cell", &pCells
+ );
+
+ /* Loop through each root page. */
+ shellPrepare(pState->db, &rc,
+ "SELECT root, intkey, max(maxlen) FROM recovery.map"
+ " WHERE root>1 GROUP BY root, intkey ORDER BY root=("
+ " SELECT rootpage FROM recovery.schema WHERE name='sqlite_sequence'"
+ ")", &pLoop
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pLoop) ){
+ int iRoot = sqlite3_column_int(pLoop, 0);
+ int bIntkey = sqlite3_column_int(pLoop, 1);
+ int nCol = sqlite3_column_int(pLoop, 2);
+ int bNoop = 0;
+ RecoverTable *pTab;
+
+ assert( bIntkey==0 || bIntkey==1 );
+ pTab = recoverFindTable(pState, &rc, iRoot, bIntkey, nCol, &bNoop);
+ if( bNoop || rc ) continue;
+ if( pTab==0 ){
+ if( pOrphan==0 ){
+ pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
+ }
+ pTab = pOrphan;
+ if( pTab==0 ) break;
+ }
+
+ if( 0==sqlite3_stricmp(pTab->zQuoted, "\"sqlite_sequence\"") ){
+ raw_printf(pState->out, "DELETE FROM sqlite_sequence;\n");
+ }
+ sqlite3_bind_int(pPages, 1, iRoot);
+ if( bRowids==0 && pTab->iPk<0 ){
+ sqlite3_bind_int(pCells, 1, 1);
+ }else{
+ sqlite3_bind_int(pCells, 1, 0);
+ }
+ sqlite3_bind_int(pCells, 3, pTab->iPk);
+
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPages) ){
+ int iPgno = sqlite3_column_int(pPages, 0);
+ sqlite3_bind_int(pCells, 2, iPgno);
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pCells) ){
+ int nField = sqlite3_column_int(pCells, 0);
+ int iMin = sqlite3_column_int(pCells, 2);
+ const char *zVal = (const char*)sqlite3_column_text(pCells, 1);
+
+ RecoverTable *pTab2 = pTab;
+ if( pTab!=pOrphan && (iMin<0)!=bIntkey ){
+ if( pOrphan==0 ){
+ pOrphan = recoverOrphanTable(pState, &rc, zLostAndFound, nOrphan);
+ }
+ pTab2 = pOrphan;
+ if( pTab2==0 ) break;
+ }
+
+ nField = nField+1;
+ if( pTab2==pOrphan ){
+ raw_printf(pState->out,
+ "INSERT INTO %s VALUES(%d, %d, %d, %s%s%s);\n",
+ pTab2->zQuoted, iRoot, iPgno, nField,
+ iMin<0 ? "" : "NULL, ", zVal, pTab2->azlCol[nField]
+ );
+ }else{
+ raw_printf(pState->out, "INSERT INTO %s(%s) VALUES( %s );\n",
+ pTab2->zQuoted, pTab2->azlCol[nField], zVal
+ );
+ }
+ }
+ shellReset(&rc, pCells);
+ }
+ shellReset(&rc, pPages);
+ if( pTab!=pOrphan ) recoverFreeTable(pTab);
+ }
+ shellFinalize(&rc, pLoop);
+ shellFinalize(&rc, pPages);
+ shellFinalize(&rc, pCells);
+ recoverFreeTable(pOrphan);
+
+ /* The rest of the schema */
+ if( rc==SQLITE_OK ){
+ sqlite3_stmt *pStmt = 0;
+ shellPrepare(pState->db, &rc,
+ "SELECT sql, name FROM recovery.schema "
+ "WHERE sql NOT LIKE 'create table%'", &pStmt
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
+ if( sqlite3_strnicmp(zSql, "create virt", 11)==0 ){
+ const char *zName = (const char*)sqlite3_column_text(pStmt, 1);
+ char *zPrint = shellMPrintf(&rc,
+ "INSERT INTO sqlite_schema VALUES('table', %Q, %Q, 0, %Q)",
+ zName, zName, zSql
+ );
+ raw_printf(pState->out, "%s;\n", zPrint);
+ sqlite3_free(zPrint);
+ }else{
+ raw_printf(pState->out, "%s;\n", zSql);
+ }
+ }
+ shellFinalize(&rc, pStmt);
+ }
+
+ if( rc==SQLITE_OK ){
+ raw_printf(pState->out, "PRAGMA writable_schema = off;\n");
+ raw_printf(pState->out, "COMMIT;\n");
+ }
+ sqlite3_exec(pState->db, "DETACH recovery", 0, 0, 0);
+ return rc;
+}
+#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
+
+
+/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
@@ -3225,11 +16946,17 @@ static int do_meta_command(char *zLine, ShellState *p){
int nArg = 0;
int n, c;
int rc = 0;
- char *azArg[50];
+ char *azArg[52];
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( p->expert.pExpert ){
+ expertFinish(p, 1, 0);
+ }
+#endif
/* Parse the input line into tokens.
*/
- while( zLine[h] && nArg<ArraySize(azArg) ){
+ while( zLine[h] && nArg<ArraySize(azArg)-1 ){
while( IsSpace(zLine[h]) ){ h++; }
if( zLine[h]==0 ) break;
if( zLine[h]=='\'' || zLine[h]=='"' ){
@@ -3250,12 +16977,14 @@ static int do_meta_command(char *zLine, ShellState *p){
resolve_backslashes(azArg[nArg-1]);
}
}
+ azArg[nArg] = 0;
/* Process the input line.
*/
if( nArg==0 ) return 0; /* no tokens, no error */
n = strlen30(azArg[0]);
c = azArg[0][0];
+ clearTempFile(p);
#ifndef SQLITE_OMIT_AUTHORIZATION
if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){
@@ -3273,6 +17002,13 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
+ if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
+ open_db(p, 0);
+ rc = arDotCommand(p, 0, azArg, nArg);
+ }else
+#endif
+
if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
|| (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
){
@@ -3281,11 +17017,18 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3 *pDest;
sqlite3_backup *pBackup;
int j;
+ int bAsync = 0;
+ const char *zVfs = 0;
for(j=1; j<nArg; j++){
const char *z = azArg[j];
if( z[0]=='-' ){
- while( z[0]=='-' ) z++;
- /* No options to process at this time */
+ if( z[1]=='-' ) z++;
+ if( strcmp(z, "-append")==0 ){
+ zVfs = "apndvfs";
+ }else
+ if( strcmp(z, "-async")==0 ){
+ bAsync = 1;
+ }else
{
utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
return 1;
@@ -3296,7 +17039,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zDb = zDestFile;
zDestFile = azArg[j];
}else{
- raw_printf(stderr, "too many arguments to .backup\n");
+ raw_printf(stderr, "Usage: .backup ?DB? ?OPTIONS? FILENAME\n");
return 1;
}
}
@@ -3305,17 +17048,22 @@ static int do_meta_command(char *zLine, ShellState *p){
return 1;
}
if( zDb==0 ) zDb = "main";
- rc = sqlite3_open(zDestFile, &pDest);
+ rc = sqlite3_open_v2(zDestFile, &pDest,
+ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
if( rc!=SQLITE_OK ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
- sqlite3_close(pDest);
+ close_db(pDest);
return 1;
}
+ if( bAsync ){
+ sqlite3_exec(pDest, "PRAGMA synchronous=OFF; PRAGMA journal_mode=OFF;",
+ 0, 0, 0);
+ }
open_db(p, 0);
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
if( pBackup==0 ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
- sqlite3_close(pDest);
+ close_db(pDest);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
@@ -3326,7 +17074,7 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
rc = 1;
}
- sqlite3_close(pDest);
+ close_db(pDest);
}else
if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
@@ -3351,6 +17099,25 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='c' && strcmp(azArg[0],"cd")==0 ){
+ if( nArg==2 ){
+#if defined(_WIN32) || defined(WIN32)
+ wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
+ rc = !SetCurrentDirectoryW(z);
+ sqlite3_free(z);
+#else
+ rc = chdir(azArg[1]);
+#endif
+ if( rc ){
+ utf8_printf(stderr, "Cannot change to directory \"%s\"\n", azArg[1]);
+ rc = 1;
+ }
+ }else{
+ raw_printf(stderr, "Usage: .cd DIRECTORY\n");
+ rc = 1;
+ }
+ }else
+
/* The undocumented ".breakpoint" command causes a call to the no-op
** routine named test_breakpoint().
*/
@@ -3360,7 +17127,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='c' && n>=3 && strncmp(azArg[0], "changes", n)==0 ){
if( nArg==2 ){
- p->countChanges = booleanValue(azArg[1]);
+ setOrClearFlag(p, SHFLG_CountChanges, azArg[1]);
}else{
raw_printf(stderr, "Usage: .changes on|off\n");
rc = 1;
@@ -3377,14 +17144,14 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg!=2 ){
raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
rc = 2;
- }else if( (zRes = readFile("testcase-out.txt"))==0 ){
+ }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){
raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
rc = 2;
}else if( testcase_glob(azArg[1],zRes)==0 ){
utf8_printf(stderr,
"testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n",
p->zTestcase, azArg[1], zRes);
- rc = 2;
+ rc = 1;
}else{
utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
p->nCheck++;
@@ -3406,13 +17173,12 @@ static int do_meta_command(char *zLine, ShellState *p){
char *zErrMsg = 0;
open_db(p, 0);
memcpy(&data, p, sizeof(data));
- data.showHeader = 1;
- data.cMode = data.mode = MODE_Column;
- data.colWidth[0] = 3;
- data.colWidth[1] = 15;
- data.colWidth[2] = 58;
+ data.showHeader = 0;
+ data.cMode = data.mode = MODE_List;
+ sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": ");
data.cnt = 0;
- sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
+ sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list",
+ callback, &data, &zErrMsg);
if( zErrMsg ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
@@ -3420,67 +17186,142 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
+ if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){
+ static const struct DbConfigChoices {
+ const char *zName;
+ int op;
+ } aDbConfig[] = {
+ { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
+ { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
+ { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
+ { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
+ { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
+ { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER },
+ { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW },
+ { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
+ { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
+ { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
+ { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
+ { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
+ { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE },
+ { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP },
+ { "trusted_schema", SQLITE_DBCONFIG_TRUSTED_SCHEMA },
+ { "writable_schema", SQLITE_DBCONFIG_WRITABLE_SCHEMA },
+ };
+ int ii, v;
+ open_db(p, 0);
+ for(ii=0; ii<ArraySize(aDbConfig); ii++){
+ if( nArg>1 && strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue;
+ if( nArg>=3 ){
+ sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0);
+ }
+ sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v);
+ utf8_printf(p->out, "%19s %s\n", aDbConfig[ii].zName, v ? "on" : "off");
+ if( nArg>1 ) break;
+ }
+ if( nArg>1 && ii==ArraySize(aDbConfig) ){
+ utf8_printf(stderr, "Error: unknown dbconfig \"%s\"\n", azArg[1]);
+ utf8_printf(stderr, "Enter \".dbconfig\" with no arguments for a list\n");
+ }
+ }else
+
+ if( c=='d' && n>=3 && strncmp(azArg[0], "dbinfo", n)==0 ){
rc = shell_dbinfo_command(p, nArg, azArg);
}else
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
+ if( c=='r' && strncmp(azArg[0], "recover", n)==0 ){
+ open_db(p, 0);
+ rc = recoverDatabaseCmd(p, nArg, azArg);
+ }else
+#endif /* !(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) */
+
if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
+ char *zLike = 0;
+ char *zSql;
+ int i;
+ int savedShowHeader = p->showHeader;
+ int savedShellFlags = p->shellFlgs;
+ ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
+ for(i=1; i<nArg; i++){
+ if( azArg[i][0]=='-' ){
+ const char *z = azArg[i]+1;
+ if( z[0]=='-' ) z++;
+ if( strcmp(z,"preserve-rowids")==0 ){
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+ raw_printf(stderr, "The --preserve-rowids option is not compatible"
+ " with SQLITE_OMIT_VIRTUALTABLE\n");
+ rc = 1;
+ sqlite3_free(zLike);
+ goto meta_command_exit;
+#else
+ ShellSetFlag(p, SHFLG_PreserveRowid);
+#endif
+ }else
+ if( strcmp(z,"newlines")==0 ){
+ ShellSetFlag(p, SHFLG_Newlines);
+ }else
+ {
+ raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]);
+ rc = 1;
+ sqlite3_free(zLike);
+ goto meta_command_exit;
+ }
+ }else if( zLike ){
+ zLike = sqlite3_mprintf("%z OR name LIKE %Q ESCAPE '\\'",
+ zLike, azArg[i]);
+ }else{
+ zLike = sqlite3_mprintf("name LIKE %Q ESCAPE '\\'", azArg[i]);
+ }
+ }
+
open_db(p, 0);
+
/* When playing back a "dump", the content might appear in an order
** which causes immediate foreign key constraints to be violated.
** So disable foreign-key constraint enforcement to prevent problems. */
- if( nArg!=1 && nArg!=2 ){
- raw_printf(stderr, "Usage: .dump ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
- }
raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
raw_printf(p->out, "BEGIN TRANSACTION;\n");
p->writableSchema = 0;
+ p->showHeader = 0;
+ /* Set writable_schema=ON since doing so forces SQLite to initialize
+ ** as much of the schema as it can even if the sqlite_schema table is
+ ** corrupt. */
sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
p->nErr = 0;
- if( nArg==1 ){
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
- );
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE name=='sqlite_sequence'"
- );
- run_table_dump_query(p,
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
- );
- }else{
- int i;
- for(i=1; i<nArg; i++){
- zShellStatic = azArg[i];
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE shellstatic() AND type=='table'"
- " AND sql NOT NULL");
- run_table_dump_query(p,
- "SELECT sql FROM sqlite_master "
- "WHERE sql NOT NULL"
- " AND type IN ('index','trigger','view')"
- " AND tbl_name LIKE shellstatic()", 0
- );
- zShellStatic = 0;
- }
- }
+ if( zLike==0 ) zLike = sqlite3_mprintf("true");
+ zSql = sqlite3_mprintf(
+ "SELECT name, type, sql FROM sqlite_schema "
+ "WHERE (%s) AND type=='table'"
+ " AND sql NOT NULL"
+ " ORDER BY tbl_name='sqlite_sequence', rowid",
+ zLike
+ );
+ run_schema_dump_query(p,zSql);
+ sqlite3_free(zSql);
+ zSql = sqlite3_mprintf(
+ "SELECT sql FROM sqlite_schema "
+ "WHERE (%s) AND sql NOT NULL"
+ " AND type IN ('index','trigger','view')",
+ zLike
+ );
+ run_table_dump_query(p, zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(zLike);
if( p->writableSchema ){
raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
p->writableSchema = 0;
}
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
- raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
+ raw_printf(p->out, p->nErr?"ROLLBACK; -- due to errors\n":"COMMIT;\n");
+ p->showHeader = savedShowHeader;
+ p->shellFlgs = savedShellFlags;
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
if( nArg==2 ){
- p->echoOn = booleanValue(azArg[1]);
+ setOrClearFlag(p, SHFLG_Echo, azArg[1]);
}else{
raw_printf(stderr, "Usage: .echo on|off\n");
rc = 1;
@@ -3489,13 +17330,31 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){
if( nArg==2 ){
+ p->autoEQPtest = 0;
+ if( p->autoEQPtrace ){
+ if( p->db ) sqlite3_exec(p->db, "PRAGMA vdbe_trace=OFF;", 0, 0, 0);
+ p->autoEQPtrace = 0;
+ }
if( strcmp(azArg[1],"full")==0 ){
- p->autoEQP = 2;
+ p->autoEQP = AUTOEQP_full;
+ }else if( strcmp(azArg[1],"trigger")==0 ){
+ p->autoEQP = AUTOEQP_trigger;
+#ifdef SQLITE_DEBUG
+ }else if( strcmp(azArg[1],"test")==0 ){
+ p->autoEQP = AUTOEQP_on;
+ p->autoEQPtest = 1;
+ }else if( strcmp(azArg[1],"trace")==0 ){
+ p->autoEQP = AUTOEQP_full;
+ p->autoEQPtrace = 1;
+ open_db(p, 0);
+ sqlite3_exec(p->db, "SELECT name FROM sqlite_schema LIMIT 1", 0, 0, 0);
+ sqlite3_exec(p->db, "PRAGMA vdbe_trace=ON;", 0, 0, 0);
+#endif
}else{
- p->autoEQP = booleanValue(azArg[1]);
+ p->autoEQP = (u8)booleanValue(azArg[1]);
}
}else{
- raw_printf(stderr, "Usage: .eqp on|off|full\n");
+ raw_printf(stderr, "Usage: .eqp off|on|trace|trigger|full\n");
rc = 1;
}
}else
@@ -3505,6 +17364,8 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 2;
}else
+ /* The ".explain" command is automatic now. It is largely pointless. It
+ ** retained purely for backwards compatibility */
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
int val = 1;
if( nArg>=2 ){
@@ -3527,6 +17388,158 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){
+ open_db(p, 0);
+ expertDotCommand(p, azArg, nArg);
+ }else
+#endif
+
+ if( c=='f' && strncmp(azArg[0], "filectrl", n)==0 ){
+ static const struct {
+ const char *zCtrlName; /* Name of a test-control option */
+ int ctrlCode; /* Integer code for that option */
+ const char *zUsage; /* Usage notes */
+ } aCtrl[] = {
+ { "size_limit", SQLITE_FCNTL_SIZE_LIMIT, "[LIMIT]" },
+ { "chunk_size", SQLITE_FCNTL_CHUNK_SIZE, "SIZE" },
+ /* { "win32_av_retry", SQLITE_FCNTL_WIN32_AV_RETRY, "COUNT DELAY" },*/
+ { "persist_wal", SQLITE_FCNTL_PERSIST_WAL, "[BOOLEAN]" },
+ { "psow", SQLITE_FCNTL_POWERSAFE_OVERWRITE, "[BOOLEAN]" },
+ /* { "pragma", SQLITE_FCNTL_PRAGMA, "NAME ARG" },*/
+ { "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
+ { "has_moved", SQLITE_FCNTL_HAS_MOVED, "" },
+ { "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" },
+ { "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" },
+ };
+ int filectrl = -1;
+ int iCtrl = -1;
+ sqlite3_int64 iRes = 0; /* Integer result to display if rc2==1 */
+ int isOk = 0; /* 0: usage 1: %lld 2: no-result */
+ int n2, i;
+ const char *zCmd = 0;
+ const char *zSchema = 0;
+
+ open_db(p, 0);
+ zCmd = nArg>=2 ? azArg[1] : "help";
+
+ if( zCmd[0]=='-'
+ && (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0)
+ && nArg>=4
+ ){
+ zSchema = azArg[2];
+ for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
+ nArg -= 2;
+ zCmd = azArg[1];
+ }
+
+ /* The argument can optionally begin with "-" or "--" */
+ if( zCmd[0]=='-' && zCmd[1] ){
+ zCmd++;
+ if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
+ }
+
+ /* --help lists all file-controls */
+ if( strcmp(zCmd,"help")==0 ){
+ utf8_printf(p->out, "Available file-controls:\n");
+ for(i=0; i<ArraySize(aCtrl); i++){
+ utf8_printf(p->out, " .filectrl %s %s\n",
+ aCtrl[i].zCtrlName, aCtrl[i].zUsage);
+ }
+ rc = 1;
+ goto meta_command_exit;
+ }
+
+ /* convert filectrl text option to value. allow any unique prefix
+ ** of the option name, or a numerical value. */
+ n2 = strlen30(zCmd);
+ for(i=0; i<ArraySize(aCtrl); i++){
+ if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
+ if( filectrl<0 ){
+ filectrl = aCtrl[i].ctrlCode;
+ iCtrl = i;
+ }else{
+ utf8_printf(stderr, "Error: ambiguous file-control: \"%s\"\n"
+ "Use \".filectrl --help\" for help\n", zCmd);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ }
+ if( filectrl<0 ){
+ utf8_printf(stderr,"Error: unknown file-control: %s\n"
+ "Use \".filectrl --help\" for help\n", zCmd);
+ }else{
+ switch(filectrl){
+ case SQLITE_FCNTL_SIZE_LIMIT: {
+ if( nArg!=2 && nArg!=3 ) break;
+ iRes = nArg==3 ? integerValue(azArg[2]) : -1;
+ sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
+ isOk = 1;
+ break;
+ }
+ case SQLITE_FCNTL_LOCK_TIMEOUT:
+ case SQLITE_FCNTL_CHUNK_SIZE: {
+ int x;
+ if( nArg!=3 ) break;
+ x = (int)integerValue(azArg[2]);
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ isOk = 2;
+ break;
+ }
+ case SQLITE_FCNTL_PERSIST_WAL:
+ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
+ int x;
+ if( nArg!=2 && nArg!=3 ) break;
+ x = nArg==3 ? booleanValue(azArg[2]) : -1;
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ iRes = x;
+ isOk = 1;
+ break;
+ }
+ case SQLITE_FCNTL_HAS_MOVED: {
+ int x;
+ if( nArg!=2 ) break;
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ iRes = x;
+ isOk = 1;
+ break;
+ }
+ case SQLITE_FCNTL_TEMPFILENAME: {
+ char *z = 0;
+ if( nArg!=2 ) break;
+ sqlite3_file_control(p->db, zSchema, filectrl, &z);
+ if( z ){
+ utf8_printf(p->out, "%s\n", z);
+ sqlite3_free(z);
+ }
+ isOk = 2;
+ break;
+ }
+ case SQLITE_FCNTL_RESERVE_BYTES: {
+ int x;
+ if( nArg>=3 ){
+ x = atoi(azArg[2]);
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ }
+ x = -1;
+ sqlite3_file_control(p->db, zSchema, filectrl, &x);
+ utf8_printf(p->out,"%d\n", x);
+ isOk = 2;
+ break;
+ }
+ }
+ }
+ if( isOk==0 && iCtrl>=0 ){
+ utf8_printf(p->out, "Usage: .filectrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ rc = 1;
+ }else if( isOk==1 ){
+ char zBuf[100];
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", iRes);
+ raw_printf(p->out, "%s\n", zBuf);
+ }
+ }else
+
if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){
ShellState data;
char *zErrMsg = 0;
@@ -3547,8 +17560,8 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_exec(p->db,
"SELECT sql FROM"
" (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
+ " FROM sqlite_schema UNION ALL"
+ " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_schema) "
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
"ORDER BY rowid",
callback, &data, &zErrMsg
@@ -3556,7 +17569,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc==SQLITE_OK ){
sqlite3_stmt *pStmt;
rc = sqlite3_prepare_v2(p->db,
- "SELECT rowid FROM sqlite_master"
+ "SELECT rowid FROM sqlite_schema"
" WHERE name GLOB 'sqlite_stat[134]'",
-1, &pStmt, 0);
doStats = sqlite3_step(pStmt)==SQLITE_ROW;
@@ -3565,26 +17578,22 @@ static int do_meta_command(char *zLine, ShellState *p){
if( doStats==0 ){
raw_printf(p->out, "/* No STAT tables available */\n");
}else{
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
- sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'",
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
+ sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_schema'",
callback, &data, &zErrMsg);
data.cMode = data.mode = MODE_Insert;
data.zDestTable = "sqlite_stat1";
- shell_exec(p->db, "SELECT * FROM sqlite_stat1",
- shell_callback, &data,&zErrMsg);
- data.zDestTable = "sqlite_stat3";
- shell_exec(p->db, "SELECT * FROM sqlite_stat3",
- shell_callback, &data,&zErrMsg);
+ shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg);
data.zDestTable = "sqlite_stat4";
- shell_exec(p->db, "SELECT * FROM sqlite_stat4",
- shell_callback, &data, &zErrMsg);
- raw_printf(p->out, "ANALYZE sqlite_master;\n");
+ shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg);
+ raw_printf(p->out, "ANALYZE sqlite_schema;\n");
}
}else
if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){
if( nArg==2 ){
p->showHeader = booleanValue(azArg[1]);
+ p->shellFlgs |= SHFLG_HeaderSet;
}else{
raw_printf(stderr, "Usage: .headers on|off\n");
rc = 1;
@@ -3592,12 +17601,19 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
- utf8_printf(p->out, "%s", zHelp);
+ if( nArg>=2 ){
+ n = showHelp(p->out, azArg[1]);
+ if( n==0 ){
+ utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]);
+ }
+ }else{
+ showHelp(p->out, 0);
+ }
}else
if( c=='i' && strncmp(azArg[0], "import", n)==0 ){
- char *zTable; /* Insert data into this table */
- char *zFile; /* Name of file to extra content from */
+ char *zTable = 0; /* Insert data into this table */
+ char *zFile = 0; /* Name of file to extra content from */
sqlite3_stmt *pStmt = NULL; /* A statement */
int nCol; /* Number of columns in the table */
int nByte; /* Number of bytes in an SQL string */
@@ -3607,77 +17623,140 @@ static int do_meta_command(char *zLine, ShellState *p){
char *zSql; /* An SQL statement */
ImportCtx sCtx; /* Reader context */
char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
- int (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */
+ int eVerbose = 0; /* Larger for more console output */
+ int nSkip = 0; /* Initial lines to skip */
+ int useOutputMode = 1; /* Use output mode to determine separators */
- if( nArg!=3 ){
- raw_printf(stderr, "Usage: .import FILE TABLE\n");
- goto meta_command_exit;
- }
- zFile = azArg[1];
- zTable = azArg[2];
- seenInterrupt = 0;
memset(&sCtx, 0, sizeof(sCtx));
- open_db(p, 0);
- nSep = strlen30(p->colSeparator);
- if( nSep==0 ){
- raw_printf(stderr,
- "Error: non-null column separator required for import\n");
- return 1;
+ if( p->mode==MODE_Ascii ){
+ xRead = ascii_read_one_field;
+ }else{
+ xRead = csv_read_one_field;
}
- if( nSep>1 ){
- raw_printf(stderr, "Error: multi-character column separators not allowed"
- " for import\n");
- return 1;
+ for(i=1; i<nArg; i++){
+ char *z = azArg[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( z[0]!='-' ){
+ if( zFile==0 ){
+ zFile = z;
+ }else if( zTable==0 ){
+ zTable = z;
+ }else{
+ utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z);
+ showHelp(p->out, "import");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( strcmp(z,"-v")==0 ){
+ eVerbose++;
+ }else if( strcmp(z,"-skip")==0 && i<nArg-1 ){
+ nSkip = integerValue(azArg[++i]);
+ }else if( strcmp(z,"-ascii")==0 ){
+ sCtx.cColSep = SEP_Unit[0];
+ sCtx.cRowSep = SEP_Record[0];
+ xRead = ascii_read_one_field;
+ useOutputMode = 0;
+ }else if( strcmp(z,"-csv")==0 ){
+ sCtx.cColSep = ',';
+ sCtx.cRowSep = '\n';
+ xRead = csv_read_one_field;
+ useOutputMode = 0;
+ }else{
+ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z);
+ showHelp(p->out, "import");
+ rc = 1;
+ goto meta_command_exit;
+ }
}
- nSep = strlen30(p->rowSeparator);
- if( nSep==0 ){
- raw_printf(stderr, "Error: non-null row separator required for import\n");
- return 1;
+ if( zTable==0 ){
+ utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n",
+ zFile==0 ? "FILE" : "TABLE");
+ showHelp(p->out, "import");
+ rc = 1;
+ goto meta_command_exit;
}
- if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
- /* When importing CSV (only), if the row separator is set to the
- ** default output row separator, change it to the default input
- ** row separator. This avoids having to maintain different input
- ** and output row separators. */
- sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ seenInterrupt = 0;
+ open_db(p, 0);
+ if( useOutputMode ){
+ /* If neither the --csv or --ascii options are specified, then set
+ ** the column and row separator characters from the output mode. */
+ nSep = strlen30(p->colSeparator);
+ if( nSep==0 ){
+ raw_printf(stderr,
+ "Error: non-null column separator required for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( nSep>1 ){
+ raw_printf(stderr,
+ "Error: multi-character column separators not allowed"
+ " for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
nSep = strlen30(p->rowSeparator);
- }
- if( nSep>1 ){
- raw_printf(stderr, "Error: multi-character row separators not allowed"
- " for import\n");
- return 1;
+ if( nSep==0 ){
+ raw_printf(stderr,
+ "Error: non-null row separator required for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){
+ /* When importing CSV (only), if the row separator is set to the
+ ** default output row separator, change it to the default input
+ ** row separator. This avoids having to maintain different input
+ ** and output row separators. */
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
+ nSep = strlen30(p->rowSeparator);
+ }
+ if( nSep>1 ){
+ raw_printf(stderr, "Error: multi-character row separators not allowed"
+ " for import\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ sCtx.cColSep = p->colSeparator[0];
+ sCtx.cRowSep = p->rowSeparator[0];
}
sCtx.zFile = zFile;
sCtx.nLine = 1;
if( sCtx.zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
raw_printf(stderr, "Error: pipes are not supported in this OS\n");
- return 1;
+ rc = 1;
+ goto meta_command_exit;
#else
sCtx.in = popen(sCtx.zFile+1, "r");
sCtx.zFile = "<pipe>";
- xCloser = pclose;
+ sCtx.xCloser = pclose;
#endif
}else{
sCtx.in = fopen(sCtx.zFile, "rb");
- xCloser = fclose;
- }
- if( p->mode==MODE_Ascii ){
- xRead = ascii_read_one_field;
- }else{
- xRead = csv_read_one_field;
+ sCtx.xCloser = fclose;
}
if( sCtx.in==0 ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
+ }
+ if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){
+ char zSep[2];
+ zSep[1] = 0;
+ zSep[0] = sCtx.cColSep;
+ utf8_printf(p->out, "Column separator ");
+ output_c_string(p->out, zSep);
+ utf8_printf(p->out, ", row separator ");
+ zSep[0] = sCtx.cRowSep;
+ output_c_string(p->out, zSep);
+ utf8_printf(p->out, "\n");
+ }
+ while( (nSkip--)>0 ){
+ while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){}
}
- sCtx.cColSep = p->colSeparator[0];
- sCtx.cRowSep = p->rowSeparator[0];
zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
if( zSql==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- xCloser(sCtx.in);
- return 1;
+ import_cleanup(&sCtx);
+ shell_out_of_memory();
}
nByte = strlen30(zSql);
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
@@ -3692,20 +17771,23 @@ static int do_meta_command(char *zLine, ShellState *p){
}
if( cSep=='(' ){
sqlite3_free(zCreate);
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
+ import_cleanup(&sCtx);
utf8_printf(stderr,"%s: empty file\n", sCtx.zFile);
- return 1;
+ rc = 1;
+ goto meta_command_exit;
}
zCreate = sqlite3_mprintf("%z\n)", zCreate);
+ if( eVerbose>=1 ){
+ utf8_printf(p->out, "%s\n", zCreate);
+ }
rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
sqlite3_free(zCreate);
if( rc ){
utf8_printf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
sqlite3_errmsg(p->db));
- sqlite3_free(sCtx.z);
- xCloser(sCtx.in);
- return 1;
+ import_cleanup(&sCtx);
+ rc = 1;
+ goto meta_command_exit;
}
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
}
@@ -3713,8 +17795,9 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc ){
if (pStmt) sqlite3_finalize(pStmt);
utf8_printf(stderr,"Error: %s\n", sqlite3_errmsg(p->db));
- xCloser(sCtx.in);
- return 1;
+ import_cleanup(&sCtx);
+ rc = 1;
+ goto meta_command_exit;
}
nCol = sqlite3_column_count(pStmt);
sqlite3_finalize(pStmt);
@@ -3722,9 +17805,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nCol==0 ) return 0; /* no columns, no error */
zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
if( zSql==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- xCloser(sCtx.in);
- return 1;
+ import_cleanup(&sCtx);
+ shell_out_of_memory();
}
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
j = strlen30(zSql);
@@ -3734,13 +17816,17 @@ static int do_meta_command(char *zLine, ShellState *p){
}
zSql[j++] = ')';
zSql[j] = 0;
+ if( eVerbose>=2 ){
+ utf8_printf(p->out, "Insert using: %s\n", zSql);
+ }
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
if (pStmt) sqlite3_finalize(pStmt);
- xCloser(sCtx.in);
- return 1;
+ import_cleanup(&sCtx);
+ rc = 1;
+ goto meta_command_exit;
}
needCommit = sqlite3_get_autocommit(p->db);
if( needCommit ) sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
@@ -3783,61 +17869,123 @@ static int do_meta_command(char *zLine, ShellState *p){
if( rc!=SQLITE_OK ){
utf8_printf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile,
startLine, sqlite3_errmsg(p->db));
+ sCtx.nErr++;
+ }else{
+ sCtx.nRow++;
}
}
}while( sCtx.cTerm!=EOF );
- xCloser(sCtx.in);
- sqlite3_free(sCtx.z);
+ import_cleanup(&sCtx);
sqlite3_finalize(pStmt);
if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0);
+ if( eVerbose>0 ){
+ utf8_printf(p->out,
+ "Added %d rows with %d errors using %d lines of input\n",
+ sCtx.nRow, sCtx.nErr, sCtx.nLine-1);
+ }
}else
- if( c=='i' && (strncmp(azArg[0], "indices", n)==0
- || strncmp(azArg[0], "indexes", n)==0) ){
- ShellState data;
- char *zErrMsg = 0;
- open_db(p, 0);
- memcpy(&data, p, sizeof(data));
- data.showHeader = 0;
- data.cMode = data.mode = MODE_List;
- if( nArg==1 ){
- rc = sqlite3_exec(p->db,
- "SELECT name FROM sqlite_master "
- "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
- "UNION ALL "
- "SELECT name FROM sqlite_temp_master "
- "WHERE type='index' "
- "ORDER BY 1",
- callback, &data, &zErrMsg
- );
- }else if( nArg==2 ){
- zShellStatic = azArg[1];
- rc = sqlite3_exec(p->db,
- "SELECT name FROM sqlite_master "
- "WHERE type='index' AND tbl_name LIKE shellstatic() "
- "UNION ALL "
- "SELECT name FROM sqlite_temp_master "
- "WHERE type='index' AND tbl_name LIKE shellstatic() "
- "ORDER BY 1",
- callback, &data, &zErrMsg
- );
- zShellStatic = 0;
- }else{
- raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
+#ifndef SQLITE_UNTESTABLE
+ if( c=='i' && strncmp(azArg[0], "imposter", n)==0 ){
+ char *zSql;
+ char *zCollist = 0;
+ sqlite3_stmt *pStmt;
+ int tnum = 0;
+ int isWO = 0; /* True if making an imposter of a WITHOUT ROWID table */
+ int lenPK = 0; /* Length of the PRIMARY KEY string for isWO tables */
+ int i;
+ if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){
+ utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n"
+ " .imposter off\n");
+ /* Also allowed, but not documented:
+ **
+ ** .imposter TABLE IMPOSTER
+ **
+ ** where TABLE is a WITHOUT ROWID table. In that case, the
+ ** imposter is another WITHOUT ROWID table with the columns in
+ ** storage order. */
rc = 1;
goto meta_command_exit;
}
- if( zErrMsg ){
- utf8_printf(stderr,"Error: %s\n", zErrMsg);
- sqlite3_free(zErrMsg);
+ open_db(p, 0);
+ if( nArg==2 ){
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
+ goto meta_command_exit;
+ }
+ zSql = sqlite3_mprintf(
+ "SELECT rootpage, 0 FROM sqlite_schema"
+ " WHERE name='%q' AND type='index'"
+ "UNION ALL "
+ "SELECT rootpage, 1 FROM sqlite_schema"
+ " WHERE name='%q' AND type='table'"
+ " AND sql LIKE '%%without%%rowid%%'",
+ azArg[1], azArg[1]
+ );
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ tnum = sqlite3_column_int(pStmt, 0);
+ isWO = sqlite3_column_int(pStmt, 1);
+ }
+ sqlite3_finalize(pStmt);
+ zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ i = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ char zLabel[20];
+ const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
+ i++;
+ if( zCol==0 ){
+ if( sqlite3_column_int(pStmt,1)==-1 ){
+ zCol = "_ROWID_";
+ }else{
+ sqlite3_snprintf(sizeof(zLabel),zLabel,"expr%d",i);
+ zCol = zLabel;
+ }
+ }
+ if( isWO && lenPK==0 && sqlite3_column_int(pStmt,5)==0 && zCollist ){
+ lenPK = (int)strlen(zCollist);
+ }
+ if( zCollist==0 ){
+ zCollist = sqlite3_mprintf("\"%w\"", zCol);
+ }else{
+ zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol);
+ }
+ }
+ sqlite3_finalize(pStmt);
+ if( i==0 || tnum==0 ){
+ utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]);
rc = 1;
- }else if( rc != SQLITE_OK ){
- raw_printf(stderr,
- "Error: querying sqlite_master and sqlite_temp_master\n");
+ sqlite3_free(zCollist);
+ goto meta_command_exit;
+ }
+ if( lenPK==0 ) lenPK = 100000;
+ zSql = sqlite3_mprintf(
+ "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%.*s))WITHOUT ROWID",
+ azArg[2], zCollist, lenPK, zCollist);
+ sqlite3_free(zCollist);
+ rc = sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(p->db, zSql, 0, 0, 0);
+ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error in [%s]: %s\n", zSql, sqlite3_errmsg(p->db));
+ }else{
+ utf8_printf(stdout, "%s;\n", zSql);
+ raw_printf(stdout,
+ "WARNING: writing to an imposter table will corrupt the \"%s\" %s!\n",
+ azArg[1], isWO ? "table" : "index"
+ );
+ }
+ }else{
+ raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc);
rc = 1;
}
+ sqlite3_free(zSql);
}else
+#endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */
#ifdef SQLITE_ENABLE_IOTRACE
if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
@@ -3861,6 +18009,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
#endif
+
if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){
static const struct {
const char *zLimitName; /* Name of a limit */
@@ -3920,6 +18069,11 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){
+ open_db(p, 0);
+ lintDotCommand(p, azArg, nArg);
+ }else
+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
const char *zFile, *zProc;
@@ -3948,25 +18102,33 @@ static int do_meta_command(char *zLine, ShellState *p){
}else{
const char *zFile = azArg[1];
output_file_close(p->pLog);
- p->pLog = output_file_open(zFile);
+ p->pLog = output_file_open(zFile, 0);
}
}else
if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){
const char *zMode = nArg>=2 ? azArg[1] : "";
- int n2 = (int)strlen(zMode);
+ int n2 = strlen30(zMode);
int c2 = zMode[0];
if( c2=='l' && n2>2 && strncmp(azArg[1],"lines",n2)==0 ){
p->mode = MODE_Line;
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='c' && strncmp(azArg[1],"columns",n2)==0 ){
p->mode = MODE_Column;
+ if( (p->shellFlgs & SHFLG_HeaderSet)==0 ){
+ p->showHeader = 1;
+ }
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
p->mode = MODE_List;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Column);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
p->mode = MODE_Html;
}else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
p->mode = MODE_Tcl;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
p->mode = MODE_Csv;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
@@ -3977,13 +18139,28 @@ static int do_meta_command(char *zLine, ShellState *p){
}else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, nArg>=3 ? azArg[2] : "table");
+ }else if( c2=='q' && strncmp(azArg[1],"quote",n2)==0 ){
+ p->mode = MODE_Quote;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
- }else {
+ }else if( c2=='m' && strncmp(azArg[1],"markdown",n2)==0 ){
+ p->mode = MODE_Markdown;
+ }else if( c2=='t' && strncmp(azArg[1],"table",n2)==0 ){
+ p->mode = MODE_Table;
+ }else if( c2=='b' && strncmp(azArg[1],"box",n2)==0 ){
+ p->mode = MODE_Box;
+ }else if( c2=='j' && strncmp(azArg[1],"json",n2)==0 ){
+ p->mode = MODE_Json;
+ }else if( nArg==1 ){
+ raw_printf(p->out, "current output mode: %s\n", modeDescr[p->mode]);
+ }else{
raw_printf(stderr, "Error: mode should be one of: "
- "ascii column csv html insert line list tabs tcl\n");
+ "ascii box column csv html insert json line list markdown "
+ "quote table tabs tcl\n");
rc = 1;
}
p->cMode = p->mode;
@@ -3999,21 +18176,71 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+#ifdef SQLITE_DEBUG
+ if( c=='o' && strcmp(azArg[0],"oom")==0 ){
+ int i;
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( strcmp(z,"-repeat")==0 ){
+ if( i==nArg-1 ){
+ raw_printf(p->out, "missing argument on \"%s\"\n", azArg[i]);
+ rc = 1;
+ }else{
+ oomRepeat = (int)integerValue(azArg[++i]);
+ }
+ }else if( IsDigit(z[0]) ){
+ oomCounter = (int)integerValue(azArg[i]);
+ }else{
+ raw_printf(p->out, "unknown argument: \"%s\"\n", azArg[i]);
+ raw_printf(p->out, "Usage: .oom [--repeat N] [M]\n");
+ rc = 1;
+ }
+ }
+ if( rc==0 ){
+ raw_printf(p->out, "oomCounter = %d\n", oomCounter);
+ raw_printf(p->out, "oomRepeat = %d\n", oomRepeat);
+ }
+ }else
+#endif /* SQLITE_DEBUG */
+
if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
char *zNewFilename; /* Name of the database file to open */
int iName = 1; /* Index in azArg[] of the filename */
int newFlag = 0; /* True to delete file before opening */
/* Close the existing database */
session_close_all(p);
- sqlite3_close(p->db);
+ close_db(p->db);
p->db = 0;
+ p->zDbFilename = 0;
sqlite3_free(p->zFreeOnClose);
p->zFreeOnClose = 0;
+ p->openMode = SHELL_OPEN_UNSPEC;
+ p->openFlags = 0;
+ p->szMax = 0;
/* Check for command-line arguments */
for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
const char *z = azArg[iName];
if( optionMatch(z,"new") ){
newFlag = 1;
+#ifdef SQLITE_HAVE_ZLIB
+ }else if( optionMatch(z, "zip") ){
+ p->openMode = SHELL_OPEN_ZIPFILE;
+#endif
+ }else if( optionMatch(z, "append") ){
+ p->openMode = SHELL_OPEN_APPENDVFS;
+ }else if( optionMatch(z, "readonly") ){
+ p->openMode = SHELL_OPEN_READONLY;
+ }else if( optionMatch(z, "nofollow") ){
+ p->openFlags |= SQLITE_OPEN_NOFOLLOW;
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ }else if( optionMatch(z, "deserialize") ){
+ p->openMode = SHELL_OPEN_DESERIALIZE;
+ }else if( optionMatch(z, "hexdb") ){
+ p->openMode = SHELL_OPEN_HEXDB;
+ }else if( optionMatch(z, "maxsize") && iName+1<nArg ){
+ p->szMax = integerValue(azArg[++iName]);
+#endif /* SQLITE_ENABLE_DESERIALIZE */
}else if( z[0]=='-' ){
utf8_printf(stderr, "unknown option: %s\n", z);
rc = 1;
@@ -4022,10 +18249,10 @@ static int do_meta_command(char *zLine, ShellState *p){
}
/* If a filename is specified, try to open it first */
zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0;
- if( zNewFilename ){
+ if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
if( newFlag ) shellDeleteFile(zNewFilename);
p->zDbFilename = zNewFilename;
- open_db(p, 1);
+ open_db(p, OPEN_DB_KEEPALIVE);
if( p->db==0 ){
utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
sqlite3_free(zNewFilename);
@@ -4040,26 +18267,76 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='o'
- && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0)
+ if( (c=='o'
+ && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
+ || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
){
- const char *zFile = nArg>=2 ? azArg[1] : "stdout";
- if( nArg>2 ){
- utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]);
- rc = 1;
- goto meta_command_exit;
+ const char *zFile = 0;
+ int bTxtMode = 0;
+ int i;
+ int eMode = 0;
+ int bBOM = 0;
+ int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
+
+ if( c=='e' ){
+ eMode = 'x';
+ bOnce = 2;
+ }else if( strncmp(azArg[0],"once",n)==0 ){
+ bOnce = 1;
}
- if( n>1 && strncmp(azArg[0], "once", n)==0 ){
- if( nArg<2 ){
- raw_printf(stderr, "Usage: .once FILE\n");
+ for(i=1; i<nArg; i++){
+ char *z = azArg[i];
+ if( z[0]=='-' ){
+ if( z[1]=='-' ) z++;
+ if( strcmp(z,"-bom")==0 ){
+ bBOM = 1;
+ }else if( c!='e' && strcmp(z,"-x")==0 ){
+ eMode = 'x'; /* spreadsheet */
+ }else if( c!='e' && strcmp(z,"-e")==0 ){
+ eMode = 'e'; /* text editor */
+ }else{
+ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
+ azArg[i]);
+ showHelp(p->out, azArg[0]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( zFile==0 ){
+ zFile = z;
+ }else{
+ utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n",
+ azArg[i]);
+ showHelp(p->out, azArg[0]);
rc = 1;
goto meta_command_exit;
}
+ }
+ if( zFile==0 ) zFile = "stdout";
+ if( bOnce ){
p->outCount = 2;
}else{
p->outCount = 0;
}
output_reset(p);
+#ifndef SQLITE_NOHAVE_SYSTEM
+ if( eMode=='e' || eMode=='x' ){
+ p->doXdgOpen = 1;
+ outputModePush(p);
+ if( eMode=='x' ){
+ /* spreadsheet mode. Output as CSV. */
+ newTempFile(p, "csv");
+ ShellClearFlag(p, SHFLG_Echo);
+ p->mode = MODE_Csv;
+ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
+ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
+ }else{
+ /* text editor mode */
+ newTempFile(p, "txt");
+ bTxtMode = 1;
+ }
+ zFile = p->zTempFile;
+ }
+#endif /* SQLITE_NOHAVE_SYSTEM */
if( zFile[0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
raw_printf(stderr, "Error: pipes are not supported in this OS\n");
@@ -4072,11 +18349,12 @@ static int do_meta_command(char *zLine, ShellState *p){
p->out = stdout;
rc = 1;
}else{
+ if( bBOM ) fprintf(p->out,"\357\273\277");
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
#endif
}else{
- p->out = output_file_open(zFile);
+ p->out = output_file_open(zFile, bTxtMode);
if( p->out==0 ){
if( strcmp(zFile,"off")!=0 ){
utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile);
@@ -4084,11 +18362,116 @@ static int do_meta_command(char *zLine, ShellState *p){
p->out = stdout;
rc = 1;
} else {
+ if( bBOM ) fprintf(p->out,"\357\273\277");
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
}
}
}else
+ if( c=='p' && n>=3 && strncmp(azArg[0], "parameter", n)==0 ){
+ open_db(p,0);
+ if( nArg<=1 ) goto parameter_syntax_error;
+
+ /* .parameter clear
+ ** Clear all bind parameters by dropping the TEMP table that holds them.
+ */
+ if( nArg==2 && strcmp(azArg[1],"clear")==0 ){
+ sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp.sqlite_parameters;",
+ 0, 0, 0);
+ }else
+
+ /* .parameter list
+ ** List all bind parameters.
+ */
+ if( nArg==2 && strcmp(azArg[1],"list")==0 ){
+ sqlite3_stmt *pStmt = 0;
+ int rx;
+ int len = 0;
+ rx = sqlite3_prepare_v2(p->db,
+ "SELECT max(length(key)) "
+ "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
+ if( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
+ len = sqlite3_column_int(pStmt, 0);
+ if( len>40 ) len = 40;
+ }
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( len ){
+ rx = sqlite3_prepare_v2(p->db,
+ "SELECT key, quote(value) "
+ "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
+ sqlite3_column_text(pStmt,1));
+ }
+ sqlite3_finalize(pStmt);
+ }
+ }else
+
+ /* .parameter init
+ ** Make sure the TEMP table used to hold bind parameters exists.
+ ** Create it if necessary.
+ */
+ if( nArg==2 && strcmp(azArg[1],"init")==0 ){
+ bind_table_init(p);
+ }else
+
+ /* .parameter set NAME VALUE
+ ** Set or reset a bind parameter. NAME should be the full parameter
+ ** name exactly as it appears in the query. (ex: $abc, @def). The
+ ** VALUE can be in either SQL literal notation, or if not it will be
+ ** understood to be a text string.
+ */
+ if( nArg==4 && strcmp(azArg[1],"set")==0 ){
+ int rx;
+ char *zSql;
+ sqlite3_stmt *pStmt;
+ const char *zKey = azArg[2];
+ const char *zValue = azArg[3];
+ bind_table_init(p);
+ zSql = sqlite3_mprintf(
+ "REPLACE INTO temp.sqlite_parameters(key,value)"
+ "VALUES(%Q,%s);", zKey, zValue);
+ if( zSql==0 ) shell_out_of_memory();
+ pStmt = 0;
+ rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rx!=SQLITE_OK ){
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ zSql = sqlite3_mprintf(
+ "REPLACE INTO temp.sqlite_parameters(key,value)"
+ "VALUES(%Q,%Q);", zKey, zValue);
+ if( zSql==0 ) shell_out_of_memory();
+ rx = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rx!=SQLITE_OK ){
+ utf8_printf(p->out, "Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_finalize(pStmt);
+ pStmt = 0;
+ rc = 1;
+ }
+ }
+ sqlite3_step(pStmt);
+ sqlite3_finalize(pStmt);
+ }else
+
+ /* .parameter unset NAME
+ ** Remove the NAME binding from the parameter binding table, if it
+ ** exists.
+ */
+ if( nArg==3 && strcmp(azArg[1],"unset")==0 ){
+ char *zSql = sqlite3_mprintf(
+ "DELETE FROM temp.sqlite_parameters WHERE key=%Q", azArg[2]);
+ if( zSql==0 ) shell_out_of_memory();
+ sqlite3_exec(p->db, zSql, 0, 0, 0);
+ sqlite3_free(zSql);
+ }else
+ /* If no command name matches, show a syntax error */
+ parameter_syntax_error:
+ showHelp(p->out, "parameter");
+ }else
+
if( c=='p' && n>=3 && strncmp(azArg[0], "print", n)==0 ){
int i;
for(i=1; i<nArg; i++){
@@ -4098,6 +18481,52 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(p->out, "\n");
}else
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( c=='p' && n>=3 && strncmp(azArg[0], "progress", n)==0 ){
+ int i;
+ int nn = 0;
+ p->flgProgress = 0;
+ p->mxProgress = 0;
+ p->nProgress = 0;
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' ){
+ z++;
+ if( z[0]=='-' ) z++;
+ if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){
+ p->flgProgress |= SHELL_PROGRESS_QUIET;
+ continue;
+ }
+ if( strcmp(z,"reset")==0 ){
+ p->flgProgress |= SHELL_PROGRESS_RESET;
+ continue;
+ }
+ if( strcmp(z,"once")==0 ){
+ p->flgProgress |= SHELL_PROGRESS_ONCE;
+ continue;
+ }
+ if( strcmp(z,"limit")==0 ){
+ if( i+1>=nArg ){
+ utf8_printf(stderr, "Error: missing argument on --limit\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ p->mxProgress = (int)integerValue(azArg[++i]);
+ }
+ continue;
+ }
+ utf8_printf(stderr, "Error: unknown option: \"%s\"\n", azArg[i]);
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ nn = (int)integerValue(z);
+ }
+ }
+ open_db(p, 0);
+ sqlite3_progress_handler(p->db, nn, progress_handler, p);
+ }else
+#endif /* SQLITE_OMIT_PROGRESS_CALLBACK */
+
if( c=='p' && strncmp(azArg[0], "prompt", n)==0 ){
if( nArg >= 2) {
strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
@@ -4112,20 +18541,24 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
- FILE *alt;
+ FILE *inSaved = p->in;
+ int savedLineno = p->lineno;
if( nArg!=2 ){
raw_printf(stderr, "Usage: .read FILE\n");
rc = 1;
goto meta_command_exit;
}
- alt = fopen(azArg[1], "rb");
- if( alt==0 ){
+ if( notNormalFile(azArg[1])
+ || (p->in = fopen(azArg[1], "rb"))==0
+ ){
utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
rc = 1;
}else{
- rc = process_input(p, alt);
- fclose(alt);
+ rc = process_input(p);
+ fclose(p->in);
}
+ p->in = inSaved;
+ p->lineno = savedLineno;
}else
if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
@@ -4149,14 +18582,14 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
- sqlite3_close(pSrc);
+ close_db(pSrc);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
if( pBackup==0 ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
- sqlite3_close(pSrc);
+ close_db(pSrc);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
@@ -4176,13 +18609,12 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
rc = 1;
}
- sqlite3_close(pSrc);
+ close_db(pSrc);
}else
-
if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
if( nArg==2 ){
- p->scanstatsOn = booleanValue(azArg[1]);
+ p->scanstatsOn = (u8)booleanValue(azArg[1]);
#ifndef SQLITE_ENABLE_STMT_SCANSTATUS
raw_printf(stderr, "Warning: .scanstats not available in this build.\n");
#endif
@@ -4193,75 +18625,122 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){
+ ShellText sSelect;
ShellState data;
char *zErrMsg = 0;
+ const char *zDiv = "(";
+ const char *zName = 0;
+ int iSchema = 0;
+ int bDebug = 0;
+ int ii;
+
open_db(p, 0);
memcpy(&data, p, sizeof(data));
data.showHeader = 0;
data.cMode = data.mode = MODE_Semi;
- if( nArg>=2 && optionMatch(azArg[1], "indent") ){
- data.cMode = data.mode = MODE_Pretty;
- nArg--;
- if( nArg==2 ) azArg[1] = azArg[2];
+ initText(&sSelect);
+ for(ii=1; ii<nArg; ii++){
+ if( optionMatch(azArg[ii],"indent") ){
+ data.cMode = data.mode = MODE_Pretty;
+ }else if( optionMatch(azArg[ii],"debug") ){
+ bDebug = 1;
+ }else if( zName==0 ){
+ zName = azArg[ii];
+ }else{
+ raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
}
- if( nArg==2 && azArg[1][0]!='-' ){
- int i;
- for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
- if( strcmp(azArg[1],"sqlite_master")==0 ){
- char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TABLE sqlite_master (\n"
- " type text,\n"
- " name text,\n"
- " tbl_name text,\n"
- " rootpage integer,\n"
- " sql text\n"
- ")";
- new_argv[1] = 0;
- new_colv[0] = "sql";
- new_colv[1] = 0;
- callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
- }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
+ if( zName!=0 ){
+ int isSchema = sqlite3_strlike(zName, "sqlite_master", '\\')==0
+ || sqlite3_strlike(zName, "sqlite_schema", '\\')==0
+ || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0
+ || sqlite3_strlike(zName,"sqlite_temp_schema", '\\')==0;
+ if( isSchema ){
char *new_argv[2], *new_colv[2];
- new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
+ new_argv[0] = sqlite3_mprintf(
+ "CREATE TABLE %s (\n"
" type text,\n"
" name text,\n"
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
- ")";
+ ")", zName);
new_argv[1] = 0;
new_colv[0] = "sql";
new_colv[1] = 0;
callback(&data, 1, new_argv, new_colv);
- rc = SQLITE_OK;
+ sqlite3_free(new_argv[0]);
+ }
+ }
+ if( zDiv ){
+ sqlite3_stmt *pStmt = 0;
+ rc = sqlite3_prepare_v2(p->db, "SELECT name FROM pragma_database_list",
+ -1, &pStmt, 0);
+ if( rc ){
+ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
+ sqlite3_finalize(pStmt);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ appendText(&sSelect, "SELECT sql FROM", 0);
+ iSchema = 0;
+ while( sqlite3_step(pStmt)==SQLITE_ROW ){
+ const char *zDb = (const char*)sqlite3_column_text(pStmt, 0);
+ char zScNum[30];
+ sqlite3_snprintf(sizeof(zScNum), zScNum, "%d", ++iSchema);
+ appendText(&sSelect, zDiv, 0);
+ zDiv = " UNION ALL ";
+ appendText(&sSelect, "SELECT shell_add_schema(sql,", 0);
+ if( sqlite3_stricmp(zDb, "main")!=0 ){
+ appendText(&sSelect, zDb, '\'');
+ }else{
+ appendText(&sSelect, "NULL", 0);
+ }
+ appendText(&sSelect, ",name) AS sql, type, tbl_name, name, rowid,", 0);
+ appendText(&sSelect, zScNum, 0);
+ appendText(&sSelect, " AS snum, ", 0);
+ appendText(&sSelect, zDb, '\'');
+ appendText(&sSelect, " AS sname FROM ", 0);
+ appendText(&sSelect, zDb, quoteChar(zDb));
+ appendText(&sSelect, ".sqlite_schema", 0);
+ }
+ sqlite3_finalize(pStmt);
+#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
+ if( zName ){
+ appendText(&sSelect,
+ " UNION ALL SELECT shell_module_schema(name),"
+ " 'table', name, name, name, 9e+99, 'main' FROM pragma_module_list",
+ 0);
+ }
+#endif
+ appendText(&sSelect, ") WHERE ", 0);
+ if( zName ){
+ char *zQarg = sqlite3_mprintf("%Q", zName);
+ int bGlob = strchr(zName, '*') != 0 || strchr(zName, '?') != 0 ||
+ strchr(zName, '[') != 0;
+ if( strchr(zName, '.') ){
+ appendText(&sSelect, "lower(printf('%s.%s',sname,tbl_name))", 0);
+ }else{
+ appendText(&sSelect, "lower(tbl_name)", 0);
+ }
+ appendText(&sSelect, bGlob ? " GLOB " : " LIKE ", 0);
+ appendText(&sSelect, zQarg, 0);
+ if( !bGlob ){
+ appendText(&sSelect, " ESCAPE '\\' ", 0);
+ }
+ appendText(&sSelect, " AND ", 0);
+ sqlite3_free(zQarg);
+ }
+ appendText(&sSelect, "type!='meta' AND sql IS NOT NULL"
+ " ORDER BY snum, rowid", 0);
+ if( bDebug ){
+ utf8_printf(p->out, "SQL: %s;\n", sSelect.z);
}else{
- zShellStatic = azArg[1];
- rc = sqlite3_exec(p->db,
- "SELECT sql FROM "
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE lower(tbl_name) LIKE shellstatic()"
- " AND type!='meta' AND sql NOTNULL "
- "ORDER BY rowid",
- callback, &data, &zErrMsg);
- zShellStatic = 0;
+ rc = sqlite3_exec(p->db, sSelect.z, callback, &data, &zErrMsg);
}
- }else if( nArg==1 ){
- rc = sqlite3_exec(p->db,
- "SELECT sql FROM "
- " (SELECT sql sql, type type, tbl_name tbl_name, name name, rowid x"
- " FROM sqlite_master UNION ALL"
- " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) "
- "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' "
- "ORDER BY rowid",
- callback, &data, &zErrMsg
- );
- }else{
- raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n");
- rc = 1;
- goto meta_command_exit;
+ freeText(&sSelect);
}
if( zErrMsg ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
@@ -4277,7 +18756,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
- sqlite3SelectTrace = integerValue(azArg[1]);
+ sqlite3_unsupported_selecttrace = nArg>=2 ? (int)integerValue(azArg[1]) : 0xffff;
}else
#endif
@@ -4332,7 +18811,8 @@ static int do_meta_command(char *zLine, ShellState *p){
if( pSession->p==0 ) goto session_not_open;
out = fopen(azCmd[1], "wb");
if( out==0 ){
- utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n", azCmd[1]);
+ utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
+ azCmd[1]);
}else{
int szChng;
void *pChng;
@@ -4473,7 +18953,7 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
/* If no command name matches, show a syntax error */
session_syntax_error:
- session_help(p);
+ showHelp(p->out, "session");
}else
#endif
@@ -4500,6 +18980,112 @@ static int do_meta_command(char *zLine, ShellState *p){
}else
#endif
+ if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){
+ int bIsInit = 0; /* True to initialize the SELFTEST table */
+ int bVerbose = 0; /* Verbose output */
+ int bSelftestExists; /* True if SELFTEST already exists */
+ int i, k; /* Loop counters */
+ int nTest = 0; /* Number of tests runs */
+ int nErr = 0; /* Number of errors seen */
+ ShellText str; /* Answer for a query */
+ sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */
+
+ open_db(p,0);
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
+ if( strcmp(z,"-init")==0 ){
+ bIsInit = 1;
+ }else
+ if( strcmp(z,"-v")==0 ){
+ bVerbose++;
+ }else
+ {
+ utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
+ azArg[i], azArg[0]);
+ raw_printf(stderr, "Should be one of: --init -v\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }
+ if( sqlite3_table_column_metadata(p->db,"main","selftest",0,0,0,0,0,0)
+ != SQLITE_OK ){
+ bSelftestExists = 0;
+ }else{
+ bSelftestExists = 1;
+ }
+ if( bIsInit ){
+ createSelftestTable(p);
+ bSelftestExists = 1;
+ }
+ initText(&str);
+ appendText(&str, "x", 0);
+ for(k=bSelftestExists; k>=0; k--){
+ if( k==1 ){
+ rc = sqlite3_prepare_v2(p->db,
+ "SELECT tno,op,cmd,ans FROM selftest ORDER BY tno",
+ -1, &pStmt, 0);
+ }else{
+ rc = sqlite3_prepare_v2(p->db,
+ "VALUES(0,'memo','Missing SELFTEST table - default checks only',''),"
+ " (1,'run','PRAGMA integrity_check','ok')",
+ -1, &pStmt, 0);
+ }
+ if( rc ){
+ raw_printf(stderr, "Error querying the selftest table\n");
+ rc = 1;
+ sqlite3_finalize(pStmt);
+ goto meta_command_exit;
+ }
+ for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){
+ int tno = sqlite3_column_int(pStmt, 0);
+ const char *zOp = (const char*)sqlite3_column_text(pStmt, 1);
+ const char *zSql = (const char*)sqlite3_column_text(pStmt, 2);
+ const char *zAns = (const char*)sqlite3_column_text(pStmt, 3);
+
+ k = 0;
+ if( bVerbose>0 ){
+ char *zQuote = sqlite3_mprintf("%q", zSql);
+ printf("%d: %s %s\n", tno, zOp, zSql);
+ sqlite3_free(zQuote);
+ }
+ if( strcmp(zOp,"memo")==0 ){
+ utf8_printf(p->out, "%s\n", zSql);
+ }else
+ if( strcmp(zOp,"run")==0 ){
+ char *zErrMsg = 0;
+ str.n = 0;
+ str.z[0] = 0;
+ rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg);
+ nTest++;
+ if( bVerbose ){
+ utf8_printf(p->out, "Result: %s\n", str.z);
+ }
+ if( rc || zErrMsg ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg);
+ sqlite3_free(zErrMsg);
+ }else if( strcmp(zAns,str.z)!=0 ){
+ nErr++;
+ rc = 1;
+ utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns);
+ utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z);
+ }
+ }else
+ {
+ utf8_printf(stderr,
+ "Unknown operation \"%s\" on selftest line %d\n", zOp, tno);
+ rc = 1;
+ break;
+ }
+ } /* End loop over rows of content from SELFTEST */
+ sqlite3_finalize(pStmt);
+ } /* End loop over k */
+ freeText(&str);
+ utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest);
+ }else
+
if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
if( nArg<2 || nArg>3 ){
raw_printf(stderr, "Usage: .separator COL ?ROW?\n");
@@ -4515,6 +19101,121 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+ if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){
+ const char *zLike = 0; /* Which table to checksum. 0 means everything */
+ int i; /* Loop counter */
+ int bSchema = 0; /* Also hash the schema */
+ int bSeparate = 0; /* Hash each table separately */
+ int iSize = 224; /* Hash algorithm to use */
+ int bDebug = 0; /* Only show the query that would have run */
+ sqlite3_stmt *pStmt; /* For querying tables names */
+ char *zSql; /* SQL to be run */
+ char *zSep; /* Separator */
+ ShellText sSql; /* Complete SQL for the query to run the hash */
+ ShellText sQuery; /* Set of queries used to read all content */
+ open_db(p, 0);
+ for(i=1; i<nArg; i++){
+ const char *z = azArg[i];
+ if( z[0]=='-' ){
+ z++;
+ if( z[0]=='-' ) z++;
+ if( strcmp(z,"schema")==0 ){
+ bSchema = 1;
+ }else
+ if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0
+ || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0
+ ){
+ iSize = atoi(&z[5]);
+ }else
+ if( strcmp(z,"debug")==0 ){
+ bDebug = 1;
+ }else
+ {
+ utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n",
+ azArg[i], azArg[0]);
+ showHelp(p->out, azArg[0]);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else if( zLike ){
+ raw_printf(stderr, "Usage: .sha3sum ?OPTIONS? ?LIKE-PATTERN?\n");
+ rc = 1;
+ goto meta_command_exit;
+ }else{
+ zLike = z;
+ bSeparate = 1;
+ if( sqlite3_strlike("sqlite\\_%", zLike, '\\')==0 ) bSchema = 1;
+ }
+ }
+ if( bSchema ){
+ zSql = "SELECT lower(name) FROM sqlite_schema"
+ " WHERE type='table' AND coalesce(rootpage,0)>1"
+ " UNION ALL SELECT 'sqlite_schema'"
+ " ORDER BY 1 collate nocase";
+ }else{
+ zSql = "SELECT lower(name) FROM sqlite_schema"
+ " WHERE type='table' AND coalesce(rootpage,0)>1"
+ " AND name NOT LIKE 'sqlite_%'"
+ " ORDER BY 1 collate nocase";
+ }
+ sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+ initText(&sQuery);
+ initText(&sSql);
+ appendText(&sSql, "WITH [sha3sum$query](a,b) AS(",0);
+ zSep = "VALUES(";
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ const char *zTab = (const char*)sqlite3_column_text(pStmt,0);
+ if( zLike && sqlite3_strlike(zLike, zTab, 0)!=0 ) continue;
+ if( strncmp(zTab, "sqlite_",7)!=0 ){
+ appendText(&sQuery,"SELECT * FROM ", 0);
+ appendText(&sQuery,zTab,'"');
+ appendText(&sQuery," NOT INDEXED;", 0);
+ }else if( strcmp(zTab, "sqlite_schema")==0 ){
+ appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_schema"
+ " ORDER BY name;", 0);
+ }else if( strcmp(zTab, "sqlite_sequence")==0 ){
+ appendText(&sQuery,"SELECT name,seq FROM sqlite_sequence"
+ " ORDER BY name;", 0);
+ }else if( strcmp(zTab, "sqlite_stat1")==0 ){
+ appendText(&sQuery,"SELECT tbl,idx,stat FROM sqlite_stat1"
+ " ORDER BY tbl,idx;", 0);
+ }else if( strcmp(zTab, "sqlite_stat4")==0 ){
+ appendText(&sQuery, "SELECT * FROM ", 0);
+ appendText(&sQuery, zTab, 0);
+ appendText(&sQuery, " ORDER BY tbl, idx, rowid;\n", 0);
+ }
+ appendText(&sSql, zSep, 0);
+ appendText(&sSql, sQuery.z, '\'');
+ sQuery.n = 0;
+ appendText(&sSql, ",", 0);
+ appendText(&sSql, zTab, '\'');
+ zSep = "),(";
+ }
+ sqlite3_finalize(pStmt);
+ if( bSeparate ){
+ zSql = sqlite3_mprintf(
+ "%s))"
+ " SELECT lower(hex(sha3_query(a,%d))) AS hash, b AS label"
+ " FROM [sha3sum$query]",
+ sSql.z, iSize);
+ }else{
+ zSql = sqlite3_mprintf(
+ "%s))"
+ " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash"
+ " FROM [sha3sum$query]",
+ sSql.z, iSize);
+ }
+ freeText(&sQuery);
+ freeText(&sSql);
+ if( bDebug ){
+ utf8_printf(p->out, "%s\n", zSql);
+ }else{
+ shell_exec(p, zSql, 0);
+ }
+ sqlite3_free(zSql);
+ }else
+
+#ifndef SQLITE_NOHAVE_SYSTEM
if( c=='s'
&& (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
){
@@ -4534,16 +19235,18 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(zCmd);
if( x ) raw_printf(stderr, "System command returns %d\n", x);
}else
+#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
- static const char *azBool[] = { "off", "on", "full", "unk" };
+ static const char *azBool[] = { "off", "on", "trigger", "full"};
int i;
if( nArg!=1 ){
raw_printf(stderr, "Usage: .show\n");
rc = 1;
goto meta_command_exit;
}
- utf8_printf(p->out, "%12.12s: %s\n","echo", azBool[p->echoOn!=0]);
+ utf8_printf(p->out, "%12.12s: %s\n","echo",
+ azBool[ShellHasFlag(p, SHFLG_Echo)]);
utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]);
utf8_printf(p->out, "%12.12s: %s\n","explain",
p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off");
@@ -4562,7 +19265,7 @@ static int do_meta_command(char *zLine, ShellState *p){
raw_printf(p->out, "\n");
utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]);
utf8_printf(p->out, "%12.12s: ", "width");
- for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
+ for (i=0;i<p->nWidth;i++) {
raw_printf(p->out, "%d ", p->colWidth[i]);
}
raw_printf(p->out, "\n");
@@ -4572,7 +19275,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
if( nArg==2 ){
- p->statsOn = booleanValue(azArg[1]);
+ p->statsOn = (u8)booleanValue(azArg[1]);
}else if( nArg==1 ){
display_stats(p->db, p, 0);
}else{
@@ -4581,50 +19284,58 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 ){
+ if( (c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0)
+ || (c=='i' && (strncmp(azArg[0], "indices", n)==0
+ || strncmp(azArg[0], "indexes", n)==0) )
+ ){
sqlite3_stmt *pStmt;
char **azResult;
int nRow, nAlloc;
- char *zSql = 0;
int ii;
+ ShellText s;
+ initText(&s);
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
- if( rc ) return shellDatabaseError(p->db);
+ if( rc ){
+ sqlite3_finalize(pStmt);
+ return shellDatabaseError(p->db);
+ }
- /* Create an SQL statement to query for the list of tables in the
- ** main and all attached databases where the table name matches the
- ** LIKE pattern bound to variable "?1". */
- zSql = sqlite3_mprintf(
- "SELECT name FROM sqlite_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1");
- while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){
+ if( nArg>2 && c=='i' ){
+ /* It is an historical accident that the .indexes command shows an error
+ ** when called with the wrong number of arguments whereas the .tables
+ ** command does not. */
+ raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
+ rc = 1;
+ sqlite3_finalize(pStmt);
+ goto meta_command_exit;
+ }
+ for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
- if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
- if( strcmp(zDbName,"temp")==0 ){
- zSql = sqlite3_mprintf(
- "%z UNION ALL "
- "SELECT 'temp.' || name FROM sqlite_temp_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1", zSql);
+ if( zDbName==0 ) continue;
+ if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0);
+ if( sqlite3_stricmp(zDbName, "main")==0 ){
+ appendText(&s, "SELECT name FROM ", 0);
}else{
- zSql = sqlite3_mprintf(
- "%z UNION ALL "
- "SELECT '%q.' || name FROM \"%w\".sqlite_master"
- " WHERE type IN ('table','view')"
- " AND name NOT LIKE 'sqlite_%%'"
- " AND name LIKE ?1", zSql, zDbName, zDbName);
+ appendText(&s, "SELECT ", 0);
+ appendText(&s, zDbName, '\'');
+ appendText(&s, "||'.'||name FROM ", 0);
+ }
+ appendText(&s, zDbName, '"');
+ appendText(&s, ".sqlite_schema ", 0);
+ if( c=='t' ){
+ appendText(&s," WHERE type IN ('table','view')"
+ " AND name NOT LIKE 'sqlite_%'"
+ " AND name LIKE ?1", 0);
+ }else{
+ appendText(&s," WHERE type='index'"
+ " AND tbl_name LIKE ?1", 0);
}
}
rc = sqlite3_finalize(pStmt);
- if( zSql && rc==SQLITE_OK ){
- zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
- if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- }
- sqlite3_free(zSql);
- if( !zSql ) return shellNomemError();
+ appendText(&s, " ORDER BY 1", 0);
+ rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
+ freeText(&s);
if( rc ) return shellDatabaseError(p->db);
/* Run the SQL statement prepared by the above block. Store the results
@@ -4641,18 +19352,12 @@ static int do_meta_command(char *zLine, ShellState *p){
char **azNew;
int n2 = nAlloc*2 + 10;
azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
- if( azNew==0 ){
- rc = shellNomemError();
- break;
- }
+ if( azNew==0 ) shell_out_of_memory();
nAlloc = n2;
azResult = azNew;
}
azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
- if( 0==azResult[nRow] ){
- rc = shellNomemError();
- break;
- }
+ if( 0==azResult[nRow] ) shell_out_of_memory();
nRow++;
}
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
@@ -4688,9 +19393,9 @@ static int do_meta_command(char *zLine, ShellState *p){
/* Begin redirecting output to the file "testcase-out.txt" */
if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
- p->out = output_file_open("testcase-out.txt");
+ p->out = output_file_open("testcase-out.txt", 0);
if( p->out==0 ){
- utf8_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
+ raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
}
if( nArg>=2 ){
sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]);
@@ -4699,63 +19404,88 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
- if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
+#ifndef SQLITE_UNTESTABLE
+ if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 ){
static const struct {
const char *zCtrlName; /* Name of a test-control option */
int ctrlCode; /* Integer code for that option */
+ const char *zUsage; /* Usage notes */
} aCtrl[] = {
- { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
- { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
- { "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
- { "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
- { "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
- { "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
- { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
- { "assert", SQLITE_TESTCTRL_ASSERT },
- { "always", SQLITE_TESTCTRL_ALWAYS },
- { "reserve", SQLITE_TESTCTRL_RESERVE },
- { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
- { "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
- { "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
- { "byteorder", SQLITE_TESTCTRL_BYTEORDER },
- { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
- { "imposter", SQLITE_TESTCTRL_IMPOSTER },
+ { "always", SQLITE_TESTCTRL_ALWAYS, "BOOLEAN" },
+ { "assert", SQLITE_TESTCTRL_ASSERT, "BOOLEAN" },
+ /*{ "benign_malloc_hooks",SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS, "" },*/
+ /*{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST, "" },*/
+ { "byteorder", SQLITE_TESTCTRL_BYTEORDER, "" },
+ { "extra_schema_checks",SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS,"BOOLEAN" },
+ /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" },*/
+ { "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"},
+ { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "" },
+ { "localtime_fault", SQLITE_TESTCTRL_LOCALTIME_FAULT,"BOOLEAN" },
+ { "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT, "BOOLEAN" },
+ { "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS, "DISABLE-MASK" },
+#ifdef YYCOVERAGE
+ { "parser_coverage", SQLITE_TESTCTRL_PARSER_COVERAGE, "" },
+#endif
+ { "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE, "OFFSET " },
+ { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
+ { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
+ { "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" },
};
int testctrl = -1;
- int rc2 = 0;
+ int iCtrl = -1;
+ int rc2 = 0; /* 0: usage. 1: %d 2: %x 3: no-output */
+ int isOk = 0;
int i, n2;
+ const char *zCmd = 0;
+
open_db(p, 0);
+ zCmd = nArg>=2 ? azArg[1] : "help";
+
+ /* The argument can optionally begin with "-" or "--" */
+ if( zCmd[0]=='-' && zCmd[1] ){
+ zCmd++;
+ if( zCmd[0]=='-' && zCmd[1] ) zCmd++;
+ }
+
+ /* --help lists all test-controls */
+ if( strcmp(zCmd,"help")==0 ){
+ utf8_printf(p->out, "Available test-controls:\n");
+ for(i=0; i<ArraySize(aCtrl); i++){
+ utf8_printf(p->out, " .testctrl %s %s\n",
+ aCtrl[i].zCtrlName, aCtrl[i].zUsage);
+ }
+ rc = 1;
+ goto meta_command_exit;
+ }
/* convert testctrl text option to value. allow any unique prefix
** of the option name, or a numerical value. */
- n2 = strlen30(azArg[1]);
+ n2 = strlen30(zCmd);
for(i=0; i<ArraySize(aCtrl); i++){
- if( strncmp(azArg[1], aCtrl[i].zCtrlName, n2)==0 ){
+ if( strncmp(zCmd, aCtrl[i].zCtrlName, n2)==0 ){
if( testctrl<0 ){
testctrl = aCtrl[i].ctrlCode;
+ iCtrl = i;
}else{
- utf8_printf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
- testctrl = -1;
- break;
+ utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n"
+ "Use \".testctrl --help\" for help\n", zCmd);
+ rc = 1;
+ goto meta_command_exit;
}
}
}
- if( testctrl<0 ) testctrl = (int)integerValue(azArg[1]);
- if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
- utf8_printf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
+ if( testctrl<0 ){
+ utf8_printf(stderr,"Error: unknown test-control: %s\n"
+ "Use \".testctrl --help\" for help\n", zCmd);
}else{
switch(testctrl){
/* sqlite3_test_control(int, db, int) */
case SQLITE_TESTCTRL_OPTIMIZATIONS:
- case SQLITE_TESTCTRL_RESERVE:
if( nArg==3 ){
int opt = (int)strtol(azArg[2], 0, 0);
rc2 = sqlite3_test_control(testctrl, p->db, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
- azArg[1]);
+ isOk = 3;
}
break;
@@ -4766,10 +19496,7 @@ static int do_meta_command(char *zLine, ShellState *p){
case SQLITE_TESTCTRL_BYTEORDER:
if( nArg==2 ){
rc2 = sqlite3_test_control(testctrl);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes no options\n",
- azArg[1]);
+ isOk = testctrl==SQLITE_TESTCTRL_BYTEORDER ? 1 : 3;
}
break;
@@ -4778,41 +19505,56 @@ static int do_meta_command(char *zLine, ShellState *p){
if( nArg==3 ){
unsigned int opt = (unsigned int)integerValue(azArg[2]);
rc2 = sqlite3_test_control(testctrl, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes a single unsigned"
- " int option\n", azArg[1]);
+ isOk = 3;
+ }
+ break;
+
+ /* sqlite3_test_control(int, int, sqlite3*) */
+ case SQLITE_TESTCTRL_PRNG_SEED:
+ if( nArg==3 || nArg==4 ){
+ int ii = (int)integerValue(azArg[2]);
+ sqlite3 *db;
+ if( ii==0 && strcmp(azArg[2],"random")==0 ){
+ sqlite3_randomness(sizeof(ii),&ii);
+ printf("-- random seed: %d\n", ii);
+ }
+ if( nArg==3 ){
+ db = 0;
+ }else{
+ db = p->db;
+ /* Make sure the schema has been loaded */
+ sqlite3_table_column_metadata(db, 0, "x", 0, 0, 0, 0, 0, 0);
+ }
+ rc2 = sqlite3_test_control(testctrl, ii, db);
+ isOk = 3;
}
break;
/* sqlite3_test_control(int, int) */
case SQLITE_TESTCTRL_ASSERT:
case SQLITE_TESTCTRL_ALWAYS:
- case SQLITE_TESTCTRL_NEVER_CORRUPT:
if( nArg==3 ){
int opt = booleanValue(azArg[2]);
rc2 = sqlite3_test_control(testctrl, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,"Error: testctrl %s takes a single int option\n",
- azArg[1]);
+ isOk = 1;
}
break;
- /* sqlite3_test_control(int, char *) */
-#ifdef SQLITE_N_KEYWORD
- case SQLITE_TESTCTRL_ISKEYWORD:
+ /* sqlite3_test_control(int, int) */
+ case SQLITE_TESTCTRL_LOCALTIME_FAULT:
+ case SQLITE_TESTCTRL_NEVER_CORRUPT:
if( nArg==3 ){
- const char *opt = azArg[2];
+ int opt = booleanValue(azArg[2]);
rc2 = sqlite3_test_control(testctrl, opt);
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- } else {
- utf8_printf(stderr,
- "Error: testctrl %s takes a single char * option\n",
- azArg[1]);
+ isOk = 3;
}
break;
-#endif
+
+ /* sqlite3_test_control(sqlite3*) */
+ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
+ rc2 = sqlite3_test_control(testctrl, p->db);
+ isOk = 3;
+ break;
case SQLITE_TESTCTRL_IMPOSTER:
if( nArg==5 ){
@@ -4820,24 +19562,29 @@ static int do_meta_command(char *zLine, ShellState *p){
azArg[2],
integerValue(azArg[3]),
integerValue(azArg[4]));
- raw_printf(p->out, "%d (0x%08x)\n", rc2, rc2);
- }else{
- raw_printf(stderr,"Usage: .testctrl imposter dbName onoff tnum\n");
+ isOk = 3;
}
break;
- case SQLITE_TESTCTRL_BITVEC_TEST:
- case SQLITE_TESTCTRL_FAULT_INSTALL:
- case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
- case SQLITE_TESTCTRL_SCRATCHMALLOC:
- default:
- utf8_printf(stderr,
- "Error: CLI support for testctrl %s not implemented\n",
- azArg[1]);
- break;
+#ifdef YYCOVERAGE
+ case SQLITE_TESTCTRL_PARSER_COVERAGE:
+ if( nArg==2 ){
+ sqlite3_test_control(testctrl, p->out);
+ isOk = 3;
+ }
+#endif
}
}
+ if( isOk==0 && iCtrl>=0 ){
+ utf8_printf(p->out, "Usage: .testctrl %s %s\n", zCmd,aCtrl[iCtrl].zUsage);
+ rc = 1;
+ }else if( isOk==1 ){
+ raw_printf(p->out, "%d\n", rc2);
+ }else if( isOk==2 ){
+ raw_printf(p->out, "0x%08x\n", rc2);
+ }
}else
+#endif /* !defined(SQLITE_UNTESTABLE) */
if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){
open_db(p, 0);
@@ -4857,23 +19604,80 @@ static int do_meta_command(char *zLine, ShellState *p){
}
}else
+#ifndef SQLITE_OMIT_TRACE
if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){
+ int mType = 0;
+ int jj;
open_db(p, 0);
- if( nArg!=2 ){
- raw_printf(stderr, "Usage: .trace FILE|off\n");
- rc = 1;
- goto meta_command_exit;
+ for(jj=1; jj<nArg; jj++){
+ const char *z = azArg[jj];
+ if( z[0]=='-' ){
+ if( optionMatch(z, "expanded") ){
+ p->eTraceType = SHELL_TRACE_EXPANDED;
+ }
+#ifdef SQLITE_ENABLE_NORMALIZE
+ else if( optionMatch(z, "normalized") ){
+ p->eTraceType = SHELL_TRACE_NORMALIZED;
+ }
+#endif
+ else if( optionMatch(z, "plain") ){
+ p->eTraceType = SHELL_TRACE_PLAIN;
+ }
+ else if( optionMatch(z, "profile") ){
+ mType |= SQLITE_TRACE_PROFILE;
+ }
+ else if( optionMatch(z, "row") ){
+ mType |= SQLITE_TRACE_ROW;
+ }
+ else if( optionMatch(z, "stmt") ){
+ mType |= SQLITE_TRACE_STMT;
+ }
+ else if( optionMatch(z, "close") ){
+ mType |= SQLITE_TRACE_CLOSE;
+ }
+ else {
+ raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z);
+ rc = 1;
+ goto meta_command_exit;
+ }
+ }else{
+ output_file_close(p->traceOut);
+ p->traceOut = output_file_open(azArg[1], 0);
+ }
}
- output_file_close(p->traceOut);
- p->traceOut = output_file_open(azArg[1]);
-#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
if( p->traceOut==0 ){
sqlite3_trace_v2(p->db, 0, 0, 0);
}else{
- sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut);
+ if( mType==0 ) mType = SQLITE_TRACE_STMT;
+ sqlite3_trace_v2(p->db, mType, sql_trace_callback, p);
}
-#endif
}else
+#endif /* !defined(SQLITE_OMIT_TRACE) */
+
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_VIRTUALTABLE)
+ if( c=='u' && strncmp(azArg[0], "unmodule", n)==0 ){
+ int ii;
+ int lenOpt;
+ char *zOpt;
+ if( nArg<2 ){
+ raw_printf(stderr, "Usage: .unmodule [--allexcept] NAME ...\n");
+ rc = 1;
+ goto meta_command_exit;
+ }
+ open_db(p, 0);
+ zOpt = azArg[1];
+ if( zOpt[0]=='-' && zOpt[1]=='-' && zOpt[2]!=0 ) zOpt++;
+ lenOpt = (int)strlen(zOpt);
+ if( lenOpt>=3 && strncmp(zOpt, "-allexcept",lenOpt)==0 ){
+ assert( azArg[nArg]==0 );
+ sqlite3_drop_modules(p->db, nArg>2 ? (const char**)(azArg+2) : 0);
+ }else{
+ for(ii=1; ii<nArg; ii++){
+ sqlite3_create_module(p->db, azArg[ii], 0, 0);
+ }
+ }
+ }else
+#endif
#if SQLITE_USER_AUTHENTICATION
if( c=='u' && strncmp(azArg[0], "user", n)==0 ){
@@ -4890,7 +19694,7 @@ static int do_meta_command(char *zLine, ShellState *p){
goto meta_command_exit;
}
rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3],
- (int)strlen(azArg[3]));
+ strlen30(azArg[3]));
if( rc ){
utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]);
rc = 1;
@@ -4901,8 +19705,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
- rc = sqlite3_user_add(p->db, azArg[2],
- azArg[3], (int)strlen(azArg[3]),
+ rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
booleanValue(azArg[4]));
if( rc ){
raw_printf(stderr, "User-Add failed: %d\n", rc);
@@ -4914,8 +19717,7 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = 1;
goto meta_command_exit;
}
- rc = sqlite3_user_change(p->db, azArg[2],
- azArg[3], (int)strlen(azArg[3]),
+ rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]),
booleanValue(azArg[4]));
if( rc ){
raw_printf(stderr, "User-Edit failed: %d\n", rc);
@@ -4943,11 +19745,25 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/,
sqlite3_libversion(), sqlite3_sourceid());
+#if SQLITE_HAVE_ZLIB
+ utf8_printf(p->out, "zlib version %s\n", zlibVersion());
+#endif
+#define CTIMEOPT_VAL_(opt) #opt
+#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
+#if defined(__clang__) && defined(__clang_major__)
+ utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "."
+ CTIMEOPT_VAL(__clang_minor__) "."
+ CTIMEOPT_VAL(__clang_patchlevel__) "\n");
+#elif defined(_MSC_VER)
+ utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n");
+#elif defined(__GNUC__) && defined(__VERSION__)
+ utf8_printf(p->out, "gcc-" __VERSION__ "\n");
+#endif
}else
if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){
const char *zDbName = nArg==2 ? azArg[1] : "main";
- sqlite3_vfs *pVfs;
+ sqlite3_vfs *pVfs = 0;
if( p->db ){
sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs);
if( pVfs ){
@@ -4998,7 +19814,11 @@ static int do_meta_command(char *zLine, ShellState *p){
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
int j;
assert( nArg<=ArraySize(azArg) );
- for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
+ p->nWidth = nArg-1;
+ p->colWidth = realloc(p->colWidth, p->nWidth*sizeof(int)*2);
+ if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
+ if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
+ for(j=1; j<nArg; j++){
p->colWidth[j-1] = (int)integerValue(azArg[j]);
}
}else
@@ -5069,6 +19889,16 @@ static int line_is_command_terminator(const char *zLine){
}
/*
+** We need a default sqlite3_complete() implementation to use in case
+** the shell is compiled with SQLITE_OMIT_COMPLETE. The default assumes
+** any arbitrary text is a complete SQL statement. This is not very
+** user-friendly, but it does seem to work.
+*/
+#ifdef SQLITE_OMIT_COMPLETE
+#define sqlite3_complete(x) 1
+#endif
+
+/*
** Return true if zSql is a complete SQL statement. Return false if it
** ends in the middle of a string literal or C-style comment.
*/
@@ -5083,6 +19913,43 @@ static int line_is_complete(char *zSql, int nSql){
}
/*
+** Run a single line of SQL. Return the number of errors.
+*/
+static int runOneSqlLine(ShellState *p, char *zSql, FILE *in, int startline){
+ int rc;
+ char *zErrMsg = 0;
+
+ open_db(p, 0);
+ if( ShellHasFlag(p,SHFLG_Backslash) ) resolve_backslashes(zSql);
+ if( p->flgProgress & SHELL_PROGRESS_RESET ) p->nProgress = 0;
+ BEGIN_TIMER;
+ rc = shell_exec(p, zSql, &zErrMsg);
+ END_TIMER;
+ if( rc || zErrMsg ){
+ char zPrefix[100];
+ if( in!=0 || !stdin_is_interactive ){
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix,
+ "Error: near line %d:", startline);
+ }else{
+ sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
+ }
+ if( zErrMsg!=0 ){
+ utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
+ sqlite3_free(zErrMsg);
+ zErrMsg = 0;
+ }else{
+ utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
+ }
+ return 1;
+ }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
+ raw_printf(p->out, "changes: %3d total_changes: %d\n",
+ sqlite3_changes(p->db), sqlite3_total_changes(p->db));
+ }
+ return 0;
+}
+
+
+/*
** Read input from *in and process it. If *in==0 then input
** is interactive - the user is typing it it. Otherwise, input
** is coming from a file or device. A prompt is issued and history
@@ -5091,43 +19958,44 @@ static int line_is_complete(char *zSql, int nSql){
**
** Return the number of errors.
*/
-static int process_input(ShellState *p, FILE *in){
+static int process_input(ShellState *p){
char *zLine = 0; /* A single input line */
char *zSql = 0; /* Accumulated SQL text */
int nLine; /* Length of current line */
int nSql = 0; /* Bytes of zSql[] used */
int nAlloc = 0; /* Allocated zSql[] space */
int nSqlPrior = 0; /* Bytes of zSql[] used by prior line */
- char *zErrMsg; /* Error message returned */
int rc; /* Error code */
int errCnt = 0; /* Number of errors seen */
- int lineno = 0; /* Current line number */
int startline = 0; /* Line number for start of current input */
- while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+ p->lineno = 0;
+ while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
fflush(p->out);
- zLine = one_input_line(in, zLine, nSql>0);
+ zLine = one_input_line(p->in, zLine, nSql>0);
if( zLine==0 ){
/* End of input */
- if( in==0 && stdin_is_interactive ) printf("\n");
+ if( p->in==0 && stdin_is_interactive ) printf("\n");
break;
}
if( seenInterrupt ){
- if( in!=0 ) break;
+ if( p->in!=0 ) break;
seenInterrupt = 0;
}
- lineno++;
+ p->lineno++;
if( nSql==0 && _all_whitespace(zLine) ){
- if( p->echoOn ) printf("%s\n", zLine);
+ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
continue;
}
- if( zLine && zLine[0]=='.' && nSql==0 ){
- if( p->echoOn ) printf("%s\n", zLine);
- rc = do_meta_command(zLine, p);
- if( rc==2 ){ /* exit requested */
- break;
- }else if( rc ){
- errCnt++;
+ if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
+ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
+ if( zLine[0]=='.' ){
+ rc = do_meta_command(zLine, p);
+ if( rc==2 ){ /* exit requested */
+ break;
+ }else if( rc ){
+ errCnt++;
+ }
}
continue;
}
@@ -5138,10 +20006,7 @@ static int process_input(ShellState *p, FILE *in){
if( nSql+nLine+2>=nAlloc ){
nAlloc = nSql+nLine+100;
zSql = realloc(zSql, nAlloc);
- if( zSql==0 ){
- raw_printf(stderr, "Error: out of memory\n");
- exit(1);
- }
+ if( zSql==0 ) shell_out_of_memory();
}
nSqlPrior = nSql;
if( nSql==0 ){
@@ -5149,7 +20014,7 @@ static int process_input(ShellState *p, FILE *in){
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
assert( nAlloc>0 && zSql!=0 );
memcpy(zSql, zLine+i, nLine+1-i);
- startline = lineno;
+ startline = p->lineno;
nSql = nLine-i;
}else{
zSql[nSql++] = '\n';
@@ -5158,47 +20023,21 @@ static int process_input(ShellState *p, FILE *in){
}
if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
&& sqlite3_complete(zSql) ){
- p->cnt = 0;
- open_db(p, 0);
- if( p->backslashOn ) resolve_backslashes(zSql);
- BEGIN_TIMER;
- rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
- END_TIMER;
- if( rc || zErrMsg ){
- char zPrefix[100];
- if( in!=0 || !stdin_is_interactive ){
- sqlite3_snprintf(sizeof(zPrefix), zPrefix,
- "Error: near line %d:", startline);
- }else{
- sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
- }
- if( zErrMsg!=0 ){
- utf8_printf(stderr, "%s %s\n", zPrefix, zErrMsg);
- sqlite3_free(zErrMsg);
- zErrMsg = 0;
- }else{
- utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
- }
- errCnt++;
- }else if( p->countChanges ){
- raw_printf(p->out, "changes: %3d total_changes: %d\n",
- sqlite3_changes(p->db), sqlite3_total_changes(p->db));
- }
+ errCnt += runOneSqlLine(p, zSql, p->in, startline);
nSql = 0;
if( p->outCount ){
output_reset(p);
p->outCount = 0;
+ }else{
+ clearTempFile(p);
}
}else if( nSql && _all_whitespace(zSql) ){
- if( p->echoOn ) printf("%s\n", zSql);
+ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
nSql = 0;
}
}
- if( nSql ){
- if( !_all_whitespace(zSql) ){
- utf8_printf(stderr, "Error: incomplete SQL: %s\n", zSql);
- errCnt++;
- }
+ if( nSql && !_all_whitespace(zSql) ){
+ errCnt += runOneSqlLine(p, zSql, p->in, startline);
}
free(zSql);
free(zLine);
@@ -5287,7 +20126,8 @@ static void process_sqliterc(
char *home_dir = NULL;
const char *sqliterc = sqliterc_override;
char *zBuf = 0;
- FILE *in = NULL;
+ FILE *inSaved = p->in;
+ int savedLineno = p->lineno;
if (sqliterc == NULL) {
home_dir = find_home_dir(0);
@@ -5296,18 +20136,19 @@ static void process_sqliterc(
" cannot read ~/.sqliterc\n");
return;
}
- sqlite3_initialize();
zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir);
sqliterc = zBuf;
}
- in = fopen(sqliterc,"rb");
- if( in ){
+ p->in = fopen(sqliterc,"rb");
+ if( p->in ){
if( stdin_is_interactive ){
utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc);
}
- process_input(p,in);
- fclose(in);
+ process_input(p);
+ fclose(p->in);
}
+ p->in = inSaved;
+ p->lineno = savedLineno;
sqlite3_free(zBuf);
}
@@ -5315,12 +20156,20 @@ static void process_sqliterc(
** Show available command line options
*/
static const char zOptions[] =
+#if defined(SQLITE_HAVE_ZLIB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
+ " -A ARGS... run \".archive ARGS\" and exit\n"
+#endif
+ " -append append the database to the end of the file\n"
" -ascii set output mode to 'ascii'\n"
" -bail stop after hitting an error\n"
" -batch force batch I/O\n"
+ " -box set output mode to 'box'\n"
" -column set output mode to 'column'\n"
" -cmd COMMAND run \"COMMAND\" before reading stdin\n"
" -csv set output mode to 'csv'\n"
+#if defined(SQLITE_ENABLE_DESERIALIZE)
+ " -deserialize open the database using sqlite3_deserialize()\n"
+#endif
" -echo print commands before execution\n"
" -init FILENAME read/process named file\n"
" -[no]header turn headers on or off\n"
@@ -5330,24 +20179,39 @@ static const char zOptions[] =
" -help show this message\n"
" -html set output mode to HTML\n"
" -interactive force interactive I/O\n"
+ " -json set output mode to 'json'\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -lookaside SIZE N use N entries of SZ bytes for lookaside memory\n"
+ " -markdown set output mode to 'markdown'\n"
+#if defined(SQLITE_ENABLE_DESERIALIZE)
+ " -maxsize N maximum size for a --deserialize database\n"
+#endif
+ " -memtrace trace all memory allocations and deallocations\n"
" -mmap N default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
" -multiplex enable the multiplexor VFS\n"
#endif
" -newline SEP set output row separator. Default: '\\n'\n"
+ " -nofollow refuse to open symbolic links to database files\n"
" -nullvalue TEXT set text string for NULL values. Default ''\n"
" -pagecache SIZE N use N slots of SZ bytes each for page cache memory\n"
- " -scratch SIZE N use N slots of SZ bytes each for scratch memory\n"
+ " -quote set output mode to 'quote'\n"
+ " -readonly open the database read-only\n"
" -separator SEP set output column separator. Default: '|'\n"
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ " -sorterref SIZE sorter references threshold size\n"
+#endif
" -stats print memory stats before each finalize\n"
+ " -table set output mode to 'table'\n"
" -version show SQLite version\n"
" -vfs NAME use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
" -vfstrace enable tracing of all VFS calls\n"
#endif
+#ifdef SQLITE_HAVE_ZLIB
+ " -zip open the file as a ZIP Archive\n"
+#endif
;
static void usage(int showDetail){
utf8_printf(stderr,
@@ -5363,6 +20227,17 @@ static void usage(int showDetail){
}
/*
+** Internal check: Verify that the SQLite is uninitialized. Print a
+** error message if it is initialized.
+*/
+static void verify_uninitialized(void){
+ if( sqlite3_config(-1)==SQLITE_MISUSE ){
+ utf8_printf(stdout, "WARNING: attempt to configure SQLite after"
+ " initialization.\n");
+ }
+}
+
+/*
** Initialize the state information in data
*/
static void main_init(ShellState *data) {
@@ -5373,6 +20248,7 @@ static void main_init(ShellState *data) {
memcpy(data->rowSeparator,SEP_Row, 2);
data->showHeader = 0;
data->shellFlgs = SHFLG_Lookaside;
+ verify_uninitialized();
sqlite3_config(SQLITE_CONFIG_URI, 1);
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
@@ -5385,14 +20261,18 @@ static void main_init(ShellState *data) {
*/
#ifdef _WIN32
static void printBold(const char *zText){
+#if !SQLITE_OS_WINRT
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
SetConsoleTextAttribute(out,
FOREGROUND_RED|FOREGROUND_INTENSITY
);
+#endif
printf("%s", zText);
+#if !SQLITE_OS_WINRT
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
+#endif
}
#else
static void printBold(const char *zText){
@@ -5436,35 +20316,77 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
int readStdin = 1;
int nCmd = 0;
char **azCmd = 0;
+ const char *zVfs = 0; /* Value of -vfs command-line option */
+#if !SQLITE_SHELL_IS_UTF8
+ char **argvToFree = 0;
+ int argcToFree = 0;
+#endif
setBinaryMode(stdin, 0);
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
stdin_is_interactive = isatty(0);
stdout_is_console = isatty(1);
+#ifdef SQLITE_DEBUG
+ registerOomSimulator();
+#endif
+
+#if !defined(_WIN32_WCE)
+ if( getenv("SQLITE_DEBUG_BREAK") ){
+ if( isatty(0) && isatty(2) ){
+ fprintf(stderr,
+ "attach debugger to process %d and press any key to continue.\n",
+ GETPID());
+ fgetc(stdin);
+ }else{
+#if defined(_WIN32) || defined(WIN32)
+#if SQLITE_OS_WINRT
+ __debugbreak();
+#else
+ DebugBreak();
+#endif
+#elif defined(SIGTRAP)
+ raise(SIGTRAP);
+#endif
+ }
+ }
+#endif
+
#if USE_SYSTEM_SQLITE+0!=1
- if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
+ if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
sqlite3_sourceid(), SQLITE_SOURCE_ID);
exit(1);
}
#endif
main_init(&data);
+
+ /* On Windows, we must translate command-line arguments into UTF-8.
+ ** The SQLite memory allocator subsystem has to be enabled in order to
+ ** do this. But we want to run an sqlite3_shutdown() afterwards so that
+ ** subsequent sqlite3_config() calls will work. So copy all results into
+ ** memory that does not come from the SQLite memory allocator.
+ */
#if !SQLITE_SHELL_IS_UTF8
sqlite3_initialize();
- argv = sqlite3_malloc64(sizeof(argv[0])*argc);
- if( argv==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
+ argvToFree = malloc(sizeof(argv[0])*argc*2);
+ argcToFree = argc;
+ argv = argvToFree + argc;
+ if( argv==0 ) shell_out_of_memory();
for(i=0; i<argc; i++){
- argv[i] = sqlite3_win32_unicode_to_utf8(wargv[i]);
- if( argv[i]==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
+ char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
+ int n;
+ if( z==0 ) shell_out_of_memory();
+ n = (int)strlen(z);
+ argv[i] = malloc( n+1 );
+ if( argv[i]==0 ) shell_out_of_memory();
+ memcpy(argv[i], z, n+1);
+ argvToFree[i] = argv[i];
+ sqlite3_free(z);
}
+ sqlite3_shutdown();
#endif
+
assert( argc>=1 && argv && argv[0] );
Argv0 = argv[0];
@@ -5473,6 +20395,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
*/
#ifdef SIGINT
signal(SIGINT, interrupt_handler);
+#elif (defined(_WIN32) || defined(WIN32)) && !defined(_WIN32_WCE)
+ SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
#endif
#ifdef SQLITE_SHELL_DBNAME_PROC
@@ -5492,6 +20416,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
** the size of the alternative malloc heap,
** and the first command to execute.
*/
+ verify_uninitialized();
for(i=1; i<argc; i++){
char *z;
z = argv[i];
@@ -5504,10 +20429,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
readStdin = 0;
nCmd++;
azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
- if( azCmd==0 ){
- raw_printf(stderr, "out of memory\n");
- exit(1);
- }
+ if( azCmd==0 ) shell_out_of_memory();
azCmd[nCmd-1] = z;
}
}
@@ -5538,16 +20460,6 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#else
(void)cmdline_option_value(argc, argv, ++i);
#endif
- }else if( strcmp(z,"-scratch")==0 ){
- int n, sz;
- sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( sz>400000 ) sz = 400000;
- if( sz<2500 ) sz = 2500;
- n = (int)integerValue(cmdline_option_value(argc,argv,++i));
- if( n>10 ) n = 10;
- if( n<1 ) n = 1;
- sqlite3_config(SQLITE_CONFIG_SCRATCH, malloc(n*sz+1), sz, n);
- data.shellFlgs |= SHFLG_Scratch;
}else if( strcmp(z,"-pagecache")==0 ){
int n, sz;
sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
@@ -5584,16 +20496,67 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( strcmp(z,"-mmap")==0 ){
sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz);
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ }else if( strcmp(z,"-sorterref")==0 ){
+ sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i));
+ sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz);
+#endif
}else if( strcmp(z,"-vfs")==0 ){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
- if( pVfs ){
- sqlite3_vfs_register(pVfs, 1);
- }else{
- utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
- exit(1);
- }
+ zVfs = cmdline_option_value(argc, argv, ++i);
+#ifdef SQLITE_HAVE_ZLIB
+ }else if( strcmp(z,"-zip")==0 ){
+ data.openMode = SHELL_OPEN_ZIPFILE;
+#endif
+ }else if( strcmp(z,"-append")==0 ){
+ data.openMode = SHELL_OPEN_APPENDVFS;
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ }else if( strcmp(z,"-deserialize")==0 ){
+ data.openMode = SHELL_OPEN_DESERIALIZE;
+ }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
+ data.szMax = integerValue(argv[++i]);
+#endif
+ }else if( strcmp(z,"-readonly")==0 ){
+ data.openMode = SHELL_OPEN_READONLY;
+ }else if( strcmp(z,"-nofollow")==0 ){
+ data.openFlags = SQLITE_OPEN_NOFOLLOW;
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
+ }else if( strncmp(z, "-A",2)==0 ){
+ /* All remaining command-line arguments are passed to the ".archive"
+ ** command, so ignore them */
+ break;
+#endif
+ }else if( strcmp(z, "-memtrace")==0 ){
+ sqlite3MemTraceActivate(stderr);
+ }
+ }
+ verify_uninitialized();
+
+
+#ifdef SQLITE_SHELL_INIT_PROC
+ {
+ /* If the SQLITE_SHELL_INIT_PROC macro is defined, then it is the name
+ ** of a C-function that will perform initialization actions on SQLite that
+ ** occur just before or after sqlite3_initialize(). Use this compile-time
+ ** option to embed this shell program in larger applications. */
+ extern void SQLITE_SHELL_INIT_PROC(void);
+ SQLITE_SHELL_INIT_PROC();
+ }
+#else
+ /* All the sqlite3_config() calls have now been made. So it is safe
+ ** to call sqlite3_initialize() and process any command line -vfs option. */
+ sqlite3_initialize();
+#endif
+
+ if( zVfs ){
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs);
+ if( pVfs ){
+ sqlite3_vfs_register(pVfs, 1);
+ }else{
+ utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]);
+ exit(1);
}
}
+
if( data.zDbFilename==0 ){
#ifndef SQLITE_OMIT_MEMORYDB
data.zDbFilename = ":memory:";
@@ -5604,6 +20567,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#endif
}
data.out = stdout;
+ sqlite3_appendvfs_init(0,0,0);
/* Go ahead and open the database file if it already exists. If the
** file does not exist, delay opening it. This prevents empty database
@@ -5635,13 +20599,39 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.mode = MODE_Html;
}else if( strcmp(z,"-list")==0 ){
data.mode = MODE_List;
+ }else if( strcmp(z,"-quote")==0 ){
+ data.mode = MODE_Quote;
}else if( strcmp(z,"-line")==0 ){
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
+ }else if( strcmp(z,"-json")==0 ){
+ data.mode = MODE_Json;
+ }else if( strcmp(z,"-markdown")==0 ){
+ data.mode = MODE_Markdown;
+ }else if( strcmp(z,"-table")==0 ){
+ data.mode = MODE_Table;
+ }else if( strcmp(z,"-box")==0 ){
+ data.mode = MODE_Box;
}else if( strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
+#ifdef SQLITE_HAVE_ZLIB
+ }else if( strcmp(z,"-zip")==0 ){
+ data.openMode = SHELL_OPEN_ZIPFILE;
+#endif
+ }else if( strcmp(z,"-append")==0 ){
+ data.openMode = SHELL_OPEN_APPENDVFS;
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ }else if( strcmp(z,"-deserialize")==0 ){
+ data.openMode = SHELL_OPEN_DESERIALIZE;
+ }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
+ data.szMax = integerValue(argv[++i]);
+#endif
+ }else if( strcmp(z,"-readonly")==0 ){
+ data.openMode = SHELL_OPEN_READONLY;
+ }else if( strcmp(z,"-nofollow")==0 ){
+ data.openFlags |= SQLITE_OPEN_NOFOLLOW;
}else if( strcmp(z,"-ascii")==0 ){
data.mode = MODE_Ascii;
sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
@@ -5662,11 +20652,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( strcmp(z,"-noheader")==0 ){
data.showHeader = 0;
}else if( strcmp(z,"-echo")==0 ){
- data.echoOn = 1;
+ ShellSetFlag(&data, SHFLG_Echo);
}else if( strcmp(z,"-eqp")==0 ){
- data.autoEQP = 1;
+ data.autoEQP = AUTOEQP_on;
}else if( strcmp(z,"-eqpfull")==0 ){
- data.autoEQP = 2;
+ data.autoEQP = AUTOEQP_full;
}else if( strcmp(z,"-stats")==0 ){
data.statsOn = 1;
}else if( strcmp(z,"-scanstats")==0 ){
@@ -5677,7 +20667,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
** prior to sending the SQL into SQLite. Useful for injecting
** crazy bytes in the middle of SQL statements for testing and debugging.
*/
- data.backslashOn = 1;
+ ShellSetFlag(&data, SHFLG_Backslash);
}else if( strcmp(z,"-bail")==0 ){
bail_on_error = 1;
}else if( strcmp(z,"-version")==0 ){
@@ -5689,14 +20679,18 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
i++;
- }else if( strcmp(z,"-scratch")==0 ){
- i+=2;
}else if( strcmp(z,"-pagecache")==0 ){
i+=2;
}else if( strcmp(z,"-lookaside")==0 ){
i+=2;
}else if( strcmp(z,"-mmap")==0 ){
i++;
+ }else if( strcmp(z,"-memtrace")==0 ){
+ i++;
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ }else if( strcmp(z,"-sorterref")==0 ){
+ i++;
+#endif
}else if( strcmp(z,"-vfs")==0 ){
i++;
#ifdef SQLITE_ENABLE_VFSTRACE
@@ -5721,7 +20715,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( rc && bail_on_error ) return rc==2 ? 0 : rc;
}else{
open_db(&data, 0);
- rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
+ rc = shell_exec(&data, z, &zErrMsg);
if( zErrMsg!=0 ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
if( bail_on_error ) return rc!=0 ? rc : 1;
@@ -5730,6 +20724,23 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( bail_on_error ) return rc;
}
}
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
+ }else if( strncmp(z, "-A", 2)==0 ){
+ if( nCmd>0 ){
+ utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands"
+ " with \"%s\"\n", z);
+ return 1;
+ }
+ open_db(&data, OPEN_DB_ZIPFILE);
+ if( z[2] ){
+ argv[i] = &z[2];
+ arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
+ }else{
+ arDotCommand(&data, 1, argv+i, argc-i);
+ }
+ readStdin = 0;
+ break;
+#endif
}else{
utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
raw_printf(stderr,"Use -help for a list of options.\n");
@@ -5749,7 +20760,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
if( rc ) return rc==2 ? 0 : rc;
}else{
open_db(&data, 0);
- rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
+ rc = shell_exec(&data, azCmd[i], &zErrMsg);
if( zErrMsg!=0 ){
utf8_printf(stderr,"Error: %s\n", zErrMsg);
return rc!=0 ? rc : 1;
@@ -5765,7 +20776,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
*/
if( stdin_is_interactive ){
char *zHome;
- char *zHistory = 0;
+ char *zHistory;
int nHistory;
printf(
"SQLite version %s %.19s\n" /*extra-version-info*/
@@ -5778,34 +20789,50 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
printf(".\nUse \".open FILENAME\" to reopen on a "
"persistent database.\n");
}
- zHome = find_home_dir(0);
- if( zHome ){
+ zHistory = getenv("SQLITE_HISTORY");
+ if( zHistory ){
+ zHistory = strdup(zHistory);
+ }else if( (zHome = find_home_dir(0))!=0 ){
nHistory = strlen30(zHome) + 20;
if( (zHistory = malloc(nHistory))!=0 ){
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
}
}
if( zHistory ){ shell_read_history(zHistory); }
- rc = process_input(&data, 0);
+#if HAVE_READLINE || HAVE_EDITLINE
+ rl_attempted_completion_function = readline_completion;
+#elif HAVE_LINENOISE
+ linenoiseSetCompletionCallback(linenoise_completion);
+#endif
+ data.in = 0;
+ rc = process_input(&data);
if( zHistory ){
- shell_stifle_history(100);
+ shell_stifle_history(2000);
shell_write_history(zHistory);
free(zHistory);
}
}else{
- rc = process_input(&data, stdin);
+ data.in = stdin;
+ rc = process_input(&data);
}
}
set_table_name(&data, 0);
if( data.db ){
session_close_all(&data);
- sqlite3_close(data.db);
+ close_db(data.db);
}
sqlite3_free(data.zFreeOnClose);
find_home_dir(1);
+ output_reset(&data);
+ data.doXdgOpen = 0;
+ clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
- for(i=0; i<argc; i++) sqlite3_free(argv[i]);
- sqlite3_free(argv);
+ for(i=0; i<argcToFree; i++) free(argvToFree[i]);
+ free(argvToFree);
#endif
+ free(data.colWidth);
+ /* Clear the global data structure so that valgrind will detect memory
+ ** leaks */
+ memset(&data, 0, sizeof(data));
return rc;
}
diff --git a/3rdparty/sqlite3/sqlite3.c b/3rdparty/sqlite3/sqlite3.c
index 4a87906e121..a82744931c0 100644
--- a/3rdparty/sqlite3/sqlite3.c
+++ b/3rdparty/sqlite3/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.15.1. By combining all the individual C code files into this
+** version 3.33.0. 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
@@ -22,6 +22,771 @@
#ifndef SQLITE_PRIVATE
# define SQLITE_PRIVATE static
#endif
+/************** Begin file ctime.c *******************************************/
+/*
+** 2010 February 23
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements routines used to report what compile-time options
+** SQLite was built with.
+*/
+
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */
+
+/*
+** Include the configuration header output by 'configure' if we're using the
+** autoconf-based build
+*/
+#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
+#include "config.h"
+#define SQLITECONFIG_H 1
+#endif
+
+/* These macros are provided to "stringify" the value of the define
+** for those options in which the value is meaningful. */
+#define CTIMEOPT_VAL_(opt) #opt
+#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
+
+/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This
+** option requires a separate macro because legal values contain a single
+** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */
+#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2
+#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
+
+/*
+** An array of names of all compile-time options. This array should
+** be sorted A-Z.
+**
+** This array looks large, but in a typical installation actually uses
+** only a handful of compile-time options, so most times this array is usually
+** rather short and uses little memory space.
+*/
+static const char * const sqlite3azCompileOpt[] = {
+
+/*
+** BEGIN CODE GENERATED BY tool/mkctime.tcl
+*/
+#if SQLITE_32BIT_ROWID
+ "32BIT_ROWID",
+#endif
+#if SQLITE_4_BYTE_ALIGNED_MALLOC
+ "4_BYTE_ALIGNED_MALLOC",
+#endif
+#if SQLITE_64BIT_STATS
+ "64BIT_STATS",
+#endif
+#if SQLITE_ALLOW_COVERING_INDEX_SCAN
+ "ALLOW_COVERING_INDEX_SCAN",
+#endif
+#if SQLITE_ALLOW_URI_AUTHORITY
+ "ALLOW_URI_AUTHORITY",
+#endif
+#ifdef SQLITE_BITMASK_TYPE
+ "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
+#endif
+#if SQLITE_BUG_COMPATIBLE_20160819
+ "BUG_COMPATIBLE_20160819",
+#endif
+#if SQLITE_CASE_SENSITIVE_LIKE
+ "CASE_SENSITIVE_LIKE",
+#endif
+#if SQLITE_CHECK_PAGES
+ "CHECK_PAGES",
+#endif
+#if defined(__clang__) && defined(__clang_major__)
+ "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
+ CTIMEOPT_VAL(__clang_minor__) "."
+ CTIMEOPT_VAL(__clang_patchlevel__),
+#elif defined(_MSC_VER)
+ "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
+#elif defined(__GNUC__) && defined(__VERSION__)
+ "COMPILER=gcc-" __VERSION__,
+#endif
+#if SQLITE_COVERAGE_TEST
+ "COVERAGE_TEST",
+#endif
+#if SQLITE_DEBUG
+ "DEBUG",
+#endif
+#if SQLITE_DEFAULT_AUTOMATIC_INDEX
+ "DEFAULT_AUTOMATIC_INDEX",
+#endif
+#if SQLITE_DEFAULT_AUTOVACUUM
+ "DEFAULT_AUTOVACUUM",
+#endif
+#ifdef SQLITE_DEFAULT_CACHE_SIZE
+ "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
+#endif
+#if SQLITE_DEFAULT_CKPTFULLFSYNC
+ "DEFAULT_CKPTFULLFSYNC",
+#endif
+#ifdef SQLITE_DEFAULT_FILE_FORMAT
+ "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT),
+#endif
+#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
+ "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
+#endif
+#if SQLITE_DEFAULT_FOREIGN_KEYS
+ "DEFAULT_FOREIGN_KEYS",
+#endif
+#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
+ "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT),
+#endif
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
+ "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
+#endif
+#ifdef SQLITE_DEFAULT_LOOKASIDE
+ "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE),
+#endif
+#if SQLITE_DEFAULT_MEMSTATUS
+ "DEFAULT_MEMSTATUS",
+#endif
+#ifdef SQLITE_DEFAULT_MMAP_SIZE
+ "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
+#endif
+#ifdef SQLITE_DEFAULT_PAGE_SIZE
+ "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE),
+#endif
+#ifdef SQLITE_DEFAULT_PCACHE_INITSZ
+ "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ),
+#endif
+#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
+ "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
+#endif
+#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
+ "DEFAULT_RECURSIVE_TRIGGERS",
+#endif
+#ifdef SQLITE_DEFAULT_ROWEST
+ "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST),
+#endif
+#ifdef SQLITE_DEFAULT_SECTOR_SIZE
+ "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE),
+#endif
+#ifdef SQLITE_DEFAULT_SYNCHRONOUS
+ "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
+#endif
+#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
+ "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT),
+#endif
+#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS
+ "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
+#endif
+#ifdef SQLITE_DEFAULT_WORKER_THREADS
+ "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
+#endif
+#if SQLITE_DIRECT_OVERFLOW_READ
+ "DIRECT_OVERFLOW_READ",
+#endif
+#if SQLITE_DISABLE_DIRSYNC
+ "DISABLE_DIRSYNC",
+#endif
+#if SQLITE_DISABLE_FTS3_UNICODE
+ "DISABLE_FTS3_UNICODE",
+#endif
+#if SQLITE_DISABLE_FTS4_DEFERRED
+ "DISABLE_FTS4_DEFERRED",
+#endif
+#if SQLITE_DISABLE_INTRINSIC
+ "DISABLE_INTRINSIC",
+#endif
+#if SQLITE_DISABLE_LFS
+ "DISABLE_LFS",
+#endif
+#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
+ "DISABLE_PAGECACHE_OVERFLOW_STATS",
+#endif
+#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ "DISABLE_SKIPAHEAD_DISTINCT",
+#endif
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
+#endif
+#if SQLITE_ENABLE_API_ARMOR
+ "ENABLE_API_ARMOR",
+#endif
+#if SQLITE_ENABLE_ATOMIC_WRITE
+ "ENABLE_ATOMIC_WRITE",
+#endif
+#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ "ENABLE_BATCH_ATOMIC_WRITE",
+#endif
+#if SQLITE_ENABLE_BYTECODE_VTAB
+ "ENABLE_BYTECODE_VTAB",
+#endif
+#if SQLITE_ENABLE_CEROD
+ "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
+#endif
+#if SQLITE_ENABLE_COLUMN_METADATA
+ "ENABLE_COLUMN_METADATA",
+#endif
+#if SQLITE_ENABLE_COLUMN_USED_MASK
+ "ENABLE_COLUMN_USED_MASK",
+#endif
+#if SQLITE_ENABLE_COSTMULT
+ "ENABLE_COSTMULT",
+#endif
+#if SQLITE_ENABLE_CURSOR_HINTS
+ "ENABLE_CURSOR_HINTS",
+#endif
+#if SQLITE_ENABLE_DBSTAT_VTAB
+ "ENABLE_DBSTAT_VTAB",
+#endif
+#if SQLITE_ENABLE_EXPENSIVE_ASSERT
+ "ENABLE_EXPENSIVE_ASSERT",
+#endif
+#if SQLITE_ENABLE_FTS1
+ "ENABLE_FTS1",
+#endif
+#if SQLITE_ENABLE_FTS2
+ "ENABLE_FTS2",
+#endif
+#if SQLITE_ENABLE_FTS3
+ "ENABLE_FTS3",
+#endif
+#if SQLITE_ENABLE_FTS3_PARENTHESIS
+ "ENABLE_FTS3_PARENTHESIS",
+#endif
+#if SQLITE_ENABLE_FTS3_TOKENIZER
+ "ENABLE_FTS3_TOKENIZER",
+#endif
+#if SQLITE_ENABLE_FTS4
+ "ENABLE_FTS4",
+#endif
+#if SQLITE_ENABLE_FTS5
+ "ENABLE_FTS5",
+#endif
+#if SQLITE_ENABLE_GEOPOLY
+ "ENABLE_GEOPOLY",
+#endif
+#if SQLITE_ENABLE_HIDDEN_COLUMNS
+ "ENABLE_HIDDEN_COLUMNS",
+#endif
+#if SQLITE_ENABLE_ICU
+ "ENABLE_ICU",
+#endif
+#if SQLITE_ENABLE_IOTRACE
+ "ENABLE_IOTRACE",
+#endif
+#if SQLITE_ENABLE_JSON1
+ "ENABLE_JSON1",
+#endif
+#if SQLITE_ENABLE_LOAD_EXTENSION
+ "ENABLE_LOAD_EXTENSION",
+#endif
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+ "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
+#endif
+#if SQLITE_ENABLE_MEMORY_MANAGEMENT
+ "ENABLE_MEMORY_MANAGEMENT",
+#endif
+#if SQLITE_ENABLE_MEMSYS3
+ "ENABLE_MEMSYS3",
+#endif
+#if SQLITE_ENABLE_MEMSYS5
+ "ENABLE_MEMSYS5",
+#endif
+#if SQLITE_ENABLE_MULTIPLEX
+ "ENABLE_MULTIPLEX",
+#endif
+#if SQLITE_ENABLE_NORMALIZE
+ "ENABLE_NORMALIZE",
+#endif
+#if SQLITE_ENABLE_NULL_TRIM
+ "ENABLE_NULL_TRIM",
+#endif
+#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
+ "ENABLE_OVERSIZE_CELL_CHECK",
+#endif
+#if SQLITE_ENABLE_PREUPDATE_HOOK
+ "ENABLE_PREUPDATE_HOOK",
+#endif
+#if SQLITE_ENABLE_QPSG
+ "ENABLE_QPSG",
+#endif
+#if SQLITE_ENABLE_RBU
+ "ENABLE_RBU",
+#endif
+#if SQLITE_ENABLE_RTREE
+ "ENABLE_RTREE",
+#endif
+#if SQLITE_ENABLE_SELECTTRACE
+ "ENABLE_SELECTTRACE",
+#endif
+#if SQLITE_ENABLE_SESSION
+ "ENABLE_SESSION",
+#endif
+#if SQLITE_ENABLE_SNAPSHOT
+ "ENABLE_SNAPSHOT",
+#endif
+#if SQLITE_ENABLE_SORTER_REFERENCES
+ "ENABLE_SORTER_REFERENCES",
+#endif
+#if SQLITE_ENABLE_SQLLOG
+ "ENABLE_SQLLOG",
+#endif
+#if defined(SQLITE_ENABLE_STAT4)
+ "ENABLE_STAT4",
+#endif
+#if SQLITE_ENABLE_STMTVTAB
+ "ENABLE_STMTVTAB",
+#endif
+#if SQLITE_ENABLE_STMT_SCANSTATUS
+ "ENABLE_STMT_SCANSTATUS",
+#endif
+#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ "ENABLE_UNKNOWN_SQL_FUNCTION",
+#endif
+#if SQLITE_ENABLE_UNLOCK_NOTIFY
+ "ENABLE_UNLOCK_NOTIFY",
+#endif
+#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ "ENABLE_UPDATE_DELETE_LIMIT",
+#endif
+#if SQLITE_ENABLE_URI_00_ERROR
+ "ENABLE_URI_00_ERROR",
+#endif
+#if SQLITE_ENABLE_VFSTRACE
+ "ENABLE_VFSTRACE",
+#endif
+#if SQLITE_ENABLE_WHERETRACE
+ "ENABLE_WHERETRACE",
+#endif
+#if SQLITE_ENABLE_ZIPVFS
+ "ENABLE_ZIPVFS",
+#endif
+#if SQLITE_EXPLAIN_ESTIMATED_ROWS
+ "EXPLAIN_ESTIMATED_ROWS",
+#endif
+#if SQLITE_EXTRA_IFNULLROW
+ "EXTRA_IFNULLROW",
+#endif
+#ifdef SQLITE_EXTRA_INIT
+ "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
+#endif
+#ifdef SQLITE_EXTRA_SHUTDOWN
+ "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
+#endif
+#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
+ "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
+#endif
+#if SQLITE_FTS5_ENABLE_TEST_MI
+ "FTS5_ENABLE_TEST_MI",
+#endif
+#if SQLITE_FTS5_NO_WITHOUT_ROWID
+ "FTS5_NO_WITHOUT_ROWID",
+#endif
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
+ "HAVE_ISNAN",
+#endif
+#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
+ "HOMEGROWN_RECURSIVE_MUTEX",
+#endif
+#if SQLITE_IGNORE_AFP_LOCK_ERRORS
+ "IGNORE_AFP_LOCK_ERRORS",
+#endif
+#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
+ "IGNORE_FLOCK_LOCK_ERRORS",
+#endif
+#if SQLITE_INLINE_MEMCPY
+ "INLINE_MEMCPY",
+#endif
+#if SQLITE_INT64_TYPE
+ "INT64_TYPE",
+#endif
+#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
+ "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
+#endif
+#if SQLITE_LIKE_DOESNT_MATCH_BLOBS
+ "LIKE_DOESNT_MATCH_BLOBS",
+#endif
+#if SQLITE_LOCK_TRACE
+ "LOCK_TRACE",
+#endif
+#if SQLITE_LOG_CACHE_SPILL
+ "LOG_CACHE_SPILL",
+#endif
+#ifdef SQLITE_MALLOC_SOFT_LIMIT
+ "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT),
+#endif
+#ifdef SQLITE_MAX_ATTACHED
+ "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED),
+#endif
+#ifdef SQLITE_MAX_COLUMN
+ "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN),
+#endif
+#ifdef SQLITE_MAX_COMPOUND_SELECT
+ "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT),
+#endif
+#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE
+ "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE),
+#endif
+#ifdef SQLITE_MAX_EXPR_DEPTH
+ "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH),
+#endif
+#ifdef SQLITE_MAX_FUNCTION_ARG
+ "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG),
+#endif
+#ifdef SQLITE_MAX_LENGTH
+ "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH),
+#endif
+#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH
+ "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH),
+#endif
+#ifdef SQLITE_MAX_MEMORY
+ "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY),
+#endif
+#ifdef SQLITE_MAX_MMAP_SIZE
+ "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
+#endif
+#ifdef SQLITE_MAX_MMAP_SIZE_
+ "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_),
+#endif
+#ifdef SQLITE_MAX_PAGE_COUNT
+ "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT),
+#endif
+#ifdef SQLITE_MAX_PAGE_SIZE
+ "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE),
+#endif
+#ifdef SQLITE_MAX_SCHEMA_RETRY
+ "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
+#endif
+#ifdef SQLITE_MAX_SQL_LENGTH
+ "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH),
+#endif
+#ifdef SQLITE_MAX_TRIGGER_DEPTH
+ "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH),
+#endif
+#ifdef SQLITE_MAX_VARIABLE_NUMBER
+ "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER),
+#endif
+#ifdef SQLITE_MAX_VDBE_OP
+ "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP),
+#endif
+#ifdef SQLITE_MAX_WORKER_THREADS
+ "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
+#endif
+#if SQLITE_MEMDEBUG
+ "MEMDEBUG",
+#endif
+#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
+ "MIXED_ENDIAN_64BIT_FLOAT",
+#endif
+#if SQLITE_MMAP_READWRITE
+ "MMAP_READWRITE",
+#endif
+#if SQLITE_MUTEX_NOOP
+ "MUTEX_NOOP",
+#endif
+#if SQLITE_MUTEX_NREF
+ "MUTEX_NREF",
+#endif
+#if SQLITE_MUTEX_OMIT
+ "MUTEX_OMIT",
+#endif
+#if SQLITE_MUTEX_PTHREADS
+ "MUTEX_PTHREADS",
+#endif
+#if SQLITE_MUTEX_W32
+ "MUTEX_W32",
+#endif
+#if SQLITE_NEED_ERR_NAME
+ "NEED_ERR_NAME",
+#endif
+#if SQLITE_NOINLINE
+ "NOINLINE",
+#endif
+#if SQLITE_NO_SYNC
+ "NO_SYNC",
+#endif
+#if SQLITE_OMIT_ALTERTABLE
+ "OMIT_ALTERTABLE",
+#endif
+#if SQLITE_OMIT_ANALYZE
+ "OMIT_ANALYZE",
+#endif
+#if SQLITE_OMIT_ATTACH
+ "OMIT_ATTACH",
+#endif
+#if SQLITE_OMIT_AUTHORIZATION
+ "OMIT_AUTHORIZATION",
+#endif
+#if SQLITE_OMIT_AUTOINCREMENT
+ "OMIT_AUTOINCREMENT",
+#endif
+#if SQLITE_OMIT_AUTOINIT
+ "OMIT_AUTOINIT",
+#endif
+#if SQLITE_OMIT_AUTOMATIC_INDEX
+ "OMIT_AUTOMATIC_INDEX",
+#endif
+#if SQLITE_OMIT_AUTORESET
+ "OMIT_AUTORESET",
+#endif
+#if SQLITE_OMIT_AUTOVACUUM
+ "OMIT_AUTOVACUUM",
+#endif
+#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
+ "OMIT_BETWEEN_OPTIMIZATION",
+#endif
+#if SQLITE_OMIT_BLOB_LITERAL
+ "OMIT_BLOB_LITERAL",
+#endif
+#if SQLITE_OMIT_CAST
+ "OMIT_CAST",
+#endif
+#if SQLITE_OMIT_CHECK
+ "OMIT_CHECK",
+#endif
+#if SQLITE_OMIT_COMPLETE
+ "OMIT_COMPLETE",
+#endif
+#if SQLITE_OMIT_COMPOUND_SELECT
+ "OMIT_COMPOUND_SELECT",
+#endif
+#if SQLITE_OMIT_CONFLICT_CLAUSE
+ "OMIT_CONFLICT_CLAUSE",
+#endif
+#if SQLITE_OMIT_CTE
+ "OMIT_CTE",
+#endif
+#if SQLITE_OMIT_DATETIME_FUNCS
+ "OMIT_DATETIME_FUNCS",
+#endif
+#if SQLITE_OMIT_DECLTYPE
+ "OMIT_DECLTYPE",
+#endif
+#if SQLITE_OMIT_DEPRECATED
+ "OMIT_DEPRECATED",
+#endif
+#if SQLITE_OMIT_DISKIO
+ "OMIT_DISKIO",
+#endif
+#if SQLITE_OMIT_EXPLAIN
+ "OMIT_EXPLAIN",
+#endif
+#if SQLITE_OMIT_FLAG_PRAGMAS
+ "OMIT_FLAG_PRAGMAS",
+#endif
+#if SQLITE_OMIT_FLOATING_POINT
+ "OMIT_FLOATING_POINT",
+#endif
+#if SQLITE_OMIT_FOREIGN_KEY
+ "OMIT_FOREIGN_KEY",
+#endif
+#if SQLITE_OMIT_GET_TABLE
+ "OMIT_GET_TABLE",
+#endif
+#if SQLITE_OMIT_HEX_INTEGER
+ "OMIT_HEX_INTEGER",
+#endif
+#if SQLITE_OMIT_INCRBLOB
+ "OMIT_INCRBLOB",
+#endif
+#if SQLITE_OMIT_INTEGRITY_CHECK
+ "OMIT_INTEGRITY_CHECK",
+#endif
+#if SQLITE_OMIT_LIKE_OPTIMIZATION
+ "OMIT_LIKE_OPTIMIZATION",
+#endif
+#if SQLITE_OMIT_LOAD_EXTENSION
+ "OMIT_LOAD_EXTENSION",
+#endif
+#if SQLITE_OMIT_LOCALTIME
+ "OMIT_LOCALTIME",
+#endif
+#if SQLITE_OMIT_LOOKASIDE
+ "OMIT_LOOKASIDE",
+#endif
+#if SQLITE_OMIT_MEMORYDB
+ "OMIT_MEMORYDB",
+#endif
+#if SQLITE_OMIT_OR_OPTIMIZATION
+ "OMIT_OR_OPTIMIZATION",
+#endif
+#if SQLITE_OMIT_PAGER_PRAGMAS
+ "OMIT_PAGER_PRAGMAS",
+#endif
+#if SQLITE_OMIT_PARSER_TRACE
+ "OMIT_PARSER_TRACE",
+#endif
+#if SQLITE_OMIT_POPEN
+ "OMIT_POPEN",
+#endif
+#if SQLITE_OMIT_PRAGMA
+ "OMIT_PRAGMA",
+#endif
+#if SQLITE_OMIT_PROGRESS_CALLBACK
+ "OMIT_PROGRESS_CALLBACK",
+#endif
+#if SQLITE_OMIT_QUICKBALANCE
+ "OMIT_QUICKBALANCE",
+#endif
+#if SQLITE_OMIT_REINDEX
+ "OMIT_REINDEX",
+#endif
+#if SQLITE_OMIT_SCHEMA_PRAGMAS
+ "OMIT_SCHEMA_PRAGMAS",
+#endif
+#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
+ "OMIT_SCHEMA_VERSION_PRAGMAS",
+#endif
+#if SQLITE_OMIT_SHARED_CACHE
+ "OMIT_SHARED_CACHE",
+#endif
+#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES
+ "OMIT_SHUTDOWN_DIRECTORIES",
+#endif
+#if SQLITE_OMIT_SUBQUERY
+ "OMIT_SUBQUERY",
+#endif
+#if SQLITE_OMIT_TCL_VARIABLE
+ "OMIT_TCL_VARIABLE",
+#endif
+#if SQLITE_OMIT_TEMPDB
+ "OMIT_TEMPDB",
+#endif
+#if SQLITE_OMIT_TEST_CONTROL
+ "OMIT_TEST_CONTROL",
+#endif
+#if SQLITE_OMIT_TRACE
+ "OMIT_TRACE",
+#endif
+#if SQLITE_OMIT_TRIGGER
+ "OMIT_TRIGGER",
+#endif
+#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
+ "OMIT_TRUNCATE_OPTIMIZATION",
+#endif
+#if SQLITE_OMIT_UTF16
+ "OMIT_UTF16",
+#endif
+#if SQLITE_OMIT_VACUUM
+ "OMIT_VACUUM",
+#endif
+#if SQLITE_OMIT_VIEW
+ "OMIT_VIEW",
+#endif
+#if SQLITE_OMIT_VIRTUALTABLE
+ "OMIT_VIRTUALTABLE",
+#endif
+#if SQLITE_OMIT_WAL
+ "OMIT_WAL",
+#endif
+#if SQLITE_OMIT_WSD
+ "OMIT_WSD",
+#endif
+#if SQLITE_OMIT_XFER_OPT
+ "OMIT_XFER_OPT",
+#endif
+#if SQLITE_PCACHE_SEPARATE_HEADER
+ "PCACHE_SEPARATE_HEADER",
+#endif
+#if SQLITE_PERFORMANCE_TRACE
+ "PERFORMANCE_TRACE",
+#endif
+#if SQLITE_POWERSAFE_OVERWRITE
+ "POWERSAFE_OVERWRITE",
+#endif
+#if SQLITE_PREFER_PROXY_LOCKING
+ "PREFER_PROXY_LOCKING",
+#endif
+#if SQLITE_PROXY_DEBUG
+ "PROXY_DEBUG",
+#endif
+#if SQLITE_REVERSE_UNORDERED_SELECTS
+ "REVERSE_UNORDERED_SELECTS",
+#endif
+#if SQLITE_RTREE_INT_ONLY
+ "RTREE_INT_ONLY",
+#endif
+#if SQLITE_SECURE_DELETE
+ "SECURE_DELETE",
+#endif
+#if SQLITE_SMALL_STACK
+ "SMALL_STACK",
+#endif
+#ifdef SQLITE_SORTER_PMASZ
+ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
+#endif
+#if SQLITE_SOUNDEX
+ "SOUNDEX",
+#endif
+#ifdef SQLITE_STAT4_SAMPLES
+ "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES),
+#endif
+#ifdef SQLITE_STMTJRNL_SPILL
+ "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
+#endif
+#if SQLITE_SUBSTR_COMPATIBILITY
+ "SUBSTR_COMPATIBILITY",
+#endif
+#if SQLITE_SYSTEM_MALLOC
+ "SYSTEM_MALLOC",
+#endif
+#if SQLITE_TCL
+ "TCL",
+#endif
+#ifdef SQLITE_TEMP_STORE
+ "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
+#endif
+#if SQLITE_TEST
+ "TEST",
+#endif
+#if defined(SQLITE_THREADSAFE)
+ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
+#elif defined(THREADSAFE)
+ "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
+#else
+ "THREADSAFE=1",
+#endif
+#if SQLITE_UNLINK_AFTER_CLOSE
+ "UNLINK_AFTER_CLOSE",
+#endif
+#if SQLITE_UNTESTABLE
+ "UNTESTABLE",
+#endif
+#if SQLITE_USER_AUTHENTICATION
+ "USER_AUTHENTICATION",
+#endif
+#if SQLITE_USE_ALLOCA
+ "USE_ALLOCA",
+#endif
+#if SQLITE_USE_FCNTL_TRACE
+ "USE_FCNTL_TRACE",
+#endif
+#if SQLITE_USE_URI
+ "USE_URI",
+#endif
+#if SQLITE_VDBE_COVERAGE
+ "VDBE_COVERAGE",
+#endif
+#if SQLITE_WIN32_MALLOC
+ "WIN32_MALLOC",
+#endif
+#if SQLITE_ZERO_MALLOC
+ "ZERO_MALLOC",
+#endif
+/*
+** END CODE GENERATED BY tool/mkctime.tcl
+*/
+};
+
+SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
+ *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);
+ return (const char**)sqlite3azCompileOpt;
+}
+
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
+/************** End of ctime.c ***********************************************/
/************** Begin file sqliteInt.h ***************************************/
/*
** 2001 September 15
@@ -60,10 +825,10 @@
**
** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread
** that would be harmless and undetectable
-** if it did occur.
+** if it did occur.
**
** In all cases, the special comment must be enclosed in the usual
-** slash-asterisk...asterisk-slash comment marks, with no spaces between the
+** slash-asterisk...asterisk-slash comment marks, with no spaces between the
** asterisks and the comment text.
*/
@@ -76,14 +841,6 @@
#endif
/*
-** Make sure that rand_s() is available on Windows systems with MSVC 2005
-** or higher.
-*/
-#if defined(_MSC_VER) && _MSC_VER>=1400
-# define _CRT_RAND_S
-#endif
-
-/*
** Include the header file used to customize the compiler options for MSVC.
** This should be done first so that it can successfully prevent spurious
** compiler warnings due to subsequent content in this file and other files
@@ -126,6 +883,11 @@
#pragma warning(disable : 4706)
#endif /* defined(_MSC_VER) */
+#if defined(_MSC_VER) && !defined(_WIN64)
+#undef SQLITE_4_BYTE_ALIGNED_MALLOC
+#define SQLITE_4_BYTE_ALIGNED_MALLOC
+#endif /* defined(_MSC_VER) && !defined(_WIN64) */
+
#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
@@ -204,12 +966,29 @@
# define _LARGEFILE_SOURCE 1
#endif
-/* What version of GCC is being used. 0 means GCC is not being used */
-#ifdef __GNUC__
+/* The GCC_VERSION and MSVC_VERSION macros are used to
+** conditionally include optimizations for each of these compilers. A
+** value of 0 means that compiler is not being used. The
+** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific
+** optimizations, and hence set all compiler macros to 0
+**
+** There was once also a CLANG_VERSION macro. However, we learn that the
+** version numbers in clang are for "marketing" only and are inconsistent
+** and unreliable. Fortunately, all versions of clang also recognize the
+** gcc version numbers and have reasonable settings for gcc version numbers,
+** so the GCC_VERSION macro will be set to a correct non-zero value even
+** when compiling with clang.
+*/
+#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
#else
# define GCC_VERSION 0
#endif
+#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
+# define MSVC_VERSION _MSC_VER
+#else
+# define MSVC_VERSION 0
+#endif
/* Needed for various definitions... */
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
@@ -221,6 +1000,15 @@
#endif
/*
+** Macro to disable warnings about missing "break" at the end of a "case".
+*/
+#if GCC_VERSION>=7000000
+# define deliberate_fall_through __attribute__((fallthrough));
+#else
+# define deliberate_fall_through
+#endif
+
+/*
** For MinGW, check to see if we can include the header file containing its
** version information, among other things. Normally, this internal MinGW
** header file would [only] be included automatically by other MinGW header
@@ -259,7 +1047,7 @@
/************** Include sqlite3.h in the middle of sqliteInt.h ***************/
/************** Begin file sqlite3.h *****************************************/
/*
-** 2001 September 15
+** 2001-09-15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -368,26 +1156,28 @@ extern "C" {
** be held constant and Z will be incremented or else Y will be incremented
** and Z will be reset to zero.
**
-** Since [version 3.6.18] ([dateof:3.6.18]),
+** Since [version 3.6.18] ([dateof:3.6.18]),
** SQLite source code has been stored in the
** <a href="http://www.fossil-scm.org/">Fossil configuration management
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
-** string contains the date and time of the check-in (UTC) and an SHA1
-** hash of the entire source tree.
+** string contains the date and time of the check-in (UTC) and a SHA1
+** or SHA3-256 hash of the entire source tree. If the source code has
+** been edited in any way since it was last checked in, then the last
+** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.15.1"
-#define SQLITE_VERSION_NUMBER 3015001
-#define SQLITE_SOURCE_ID "2016-11-04 12:08:49 1136863c76576110e710dd5d69ab6bf347c65e36"
+#define SQLITE_VERSION "3.33.0"
+#define SQLITE_VERSION_NUMBER 3033000
+#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version, sqlite3_sourceid
+** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -399,7 +1189,7 @@ extern "C" {
**
** <blockquote><pre>
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** </pre></blockquote>)^
**
@@ -409,9 +1199,11 @@ extern "C" {
** function is provided for use in DLLs since DLL users usually do not have
** direct access to string constants within the DLL. ^The
** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
-** a pointer to a string constant whose value is the same as the
-** [SQLITE_SOURCE_ID] C preprocessor macro.
+** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns
+** a pointer to a string constant whose value is the same as the
+** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built
+** using an edited copy of [the amalgamation], then the last four characters
+** of the hash might be different from [SQLITE_SOURCE_ID].)^
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -423,20 +1215,20 @@ SQLITE_API int sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
**
-** ^The sqlite3_compileoption_used() function returns 0 or 1
-** indicating whether the specified option was defined at
-** compile time. ^The SQLITE_ prefix may be omitted from the
-** option name passed to sqlite3_compileoption_used().
+** ^The sqlite3_compileoption_used() function returns 0 or 1
+** indicating whether the specified option was defined at
+** compile time. ^The SQLITE_ prefix may be omitted from the
+** option name passed to sqlite3_compileoption_used().
**
** ^The sqlite3_compileoption_get() function allows iterating
** over the list of options that were defined at compile time by
** returning the N-th compile time option string. ^If N is out of range,
-** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
-** prefix is omitted from any strings returned by
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
+** prefix is omitted from any strings returned by
** sqlite3_compileoption_get().
**
** ^Support for the diagnostic functions sqlite3_compileoption_used()
-** and sqlite3_compileoption_get() may be omitted by specifying the
+** and sqlite3_compileoption_get() may be omitted by specifying the
** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
**
** See also: SQL functions [sqlite_compileoption_used()] and
@@ -445,6 +1237,9 @@ SQLITE_API int sqlite3_libversion_number(void);
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
SQLITE_API const char *sqlite3_compileoption_get(int N);
+#else
+# define sqlite3_compileoption_used(X) 0
+# define sqlite3_compileoption_get(X) ((void*)0)
#endif
/*
@@ -457,7 +1252,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLite can be compiled with or without mutexes. When
** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
** are enabled and SQLite is threadsafe. When the
-** [SQLITE_THREADSAFE] macro is 0,
+** [SQLITE_THREADSAFE] macro is 0,
** the mutexes are omitted. Without the mutexes, it is not safe
** to use SQLite concurrently from more than one thread.
**
@@ -514,12 +1309,16 @@ typedef struct sqlite3 sqlite3;
**
** ^The sqlite3_int64 and sqlite_int64 types can store integer values
** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
-** sqlite3_uint64 and sqlite_uint64 types can store integer values
+** sqlite3_uint64 and sqlite_uint64 types can store integer values
** between 0 and +18446744073709551615 inclusive.
*/
#ifdef SQLITE_INT64_TYPE
typedef SQLITE_INT64_TYPE sqlite_int64;
- typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
+# ifdef SQLITE_UINT64_TYPE
+ typedef SQLITE_UINT64_TYPE sqlite_uint64;
+# else
+ typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
+# endif
#elif defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 sqlite_int64;
typedef unsigned __int64 sqlite_uint64;
@@ -548,26 +1347,22 @@ typedef sqlite_uint64 sqlite3_uint64;
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
-** ^If the database connection is associated with unfinalized prepared
-** statements or unfinished sqlite3_backup objects then sqlite3_close()
-** will leave the database connection open and return [SQLITE_BUSY].
-** ^If sqlite3_close_v2() is called with unfinalized prepared statements
-** and/or unfinished sqlite3_backups, then the database connection becomes
-** an unusable "zombie" which will automatically be deallocated when the
-** last prepared statement is finalized or the last sqlite3_backup is
-** finished. The sqlite3_close_v2() interface is intended for use with
-** host languages that are garbage collected, and where the order in which
-** destructors are called is arbitrary.
-**
-** Applications should [sqlite3_finalize | finalize] all [prepared statements],
-** [sqlite3_blob_close | close] all [BLOB handles], and
+** Ideally, applications should [sqlite3_finalize | finalize] all
+** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
-** with the [sqlite3] object prior to attempting to close the object. ^If
-** sqlite3_close_v2() is called on a [database connection] that still has
-** outstanding [prepared statements], [BLOB handles], and/or
-** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
-** of resources is deferred until all [prepared statements], [BLOB handles],
-** and [sqlite3_backup] objects are also destroyed.
+** with the [sqlite3] object prior to attempting to close the object.
+** ^If the database connection is associated with unfinalized prepared
+** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
+** sqlite3_close() will leave the database connection open and return
+** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
+** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
+** it returns [SQLITE_OK] regardless, but instead of deallocating the database
+** connection immediately, it marks the database connection as an unusable
+** "zombie" and makes arrangements to automatically deallocate the database
+** connection after all prepared statements are finalized, all BLOB handles
+** are closed, and all backups have finished. The sqlite3_close_v2() interface
+** is intended for use with host languages that are garbage collected, and
+** where the order in which destructors are called is arbitrary.
**
** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back.
@@ -597,7 +1392,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** The sqlite3_exec() interface is a convenience wrapper around
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
** that allows an application to run multiple statements of SQL
-** without having to use a lot of C code.
+** without having to use a lot of C code.
**
** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
** semicolon-separate SQL statements passed into its 2nd argument,
@@ -637,7 +1432,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** from [sqlite3_column_name()].
**
** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
-** to an empty string, or a pointer that contains only whitespace and/or
+** to an empty string, or a pointer that contains only whitespace and/or
** SQL comments, then no SQL statements are evaluated and the database
** is not changed.
**
@@ -673,7 +1468,7 @@ SQLITE_API int sqlite3_exec(
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
-#define SQLITE_ERROR 1 /* SQL error or missing database */
+#define SQLITE_ERROR 1 /* Generic error */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
@@ -688,7 +1483,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Database is empty */
+#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
@@ -696,7 +1491,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
-#define SQLITE_FORMAT 24 /* Auxiliary database format error */
+#define SQLITE_FORMAT 24 /* Not used */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
@@ -722,6 +1517,9 @@ SQLITE_API int sqlite3_exec(
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
+#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8))
+#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8))
+#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8))
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
@@ -750,18 +1548,30 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
+#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
+#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
+#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
+#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
+#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
+#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
+#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
+#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
+#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
+#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
@@ -773,11 +1583,13 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
+#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
+#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -800,14 +1612,18 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
+#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
+#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
+/* Legacy compatibility: */
+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
+
/*
** CAPI3REF: Device Characteristics
@@ -832,10 +1648,15 @@ SQLITE_API int sqlite3_exec(
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
-** flag indicate that a file cannot be deleted when open. The
+** flag indicates that a file cannot be deleted when open. The
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
+**
+** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
+** filesystem supports doing multiple write operations atomically when those
+** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
+** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -851,6 +1672,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
+#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
/*
** CAPI3REF: File Locking Levels
@@ -898,7 +1720,7 @@ SQLITE_API int sqlite3_exec(
/*
** CAPI3REF: OS Interface Open File Handle
**
-** An [sqlite3_file] object represents an open file in the
+** An [sqlite3_file] object represents an open file in the
** [sqlite3_vfs | OS interface layer]. Individual OS interface
** implementations will
** want to subclass this object by appending additional fields
@@ -920,7 +1742,7 @@ struct sqlite3_file {
** This object defines the methods used to perform various operations
** against the open file represented by the [sqlite3_file] object.
**
-** If the [sqlite3_vfs.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 [sqlite3_vfs.xOpen] reported that it failed. The
** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
@@ -982,6 +1804,10 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_ATOMIC64K]
** <li> [SQLITE_IOCAP_SAFE_APPEND]
** <li> [SQLITE_IOCAP_SEQUENTIAL]
+** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
+** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
+** <li> [SQLITE_IOCAP_IMMUTABLE]
+** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1054,10 +1880,19 @@ struct sqlite3_io_methods {
** file space based on this hint in order to help writes to the database
** file run faster.
**
+** <li>[[SQLITE_FCNTL_SIZE_LIMIT]]
+** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that
+** implements [sqlite3_deserialize()] to set an upper bound on the size
+** of the in-memory database. The argument is a pointer to a [sqlite3_int64].
+** If the integer pointed to is negative, then it is filled in with the
+** current limit. Otherwise the limit is set to the larger of the value
+** of the integer pointed to and the current database size. The integer
+** pointed to is set to the new limit.
+**
** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
** extends and truncates the database file in chunks of a size specified
-** by the user. The fourth argument to [sqlite3_file_control()] should
+** by the user. The fourth argument to [sqlite3_file_control()] should
** point to an integer (type int) containing the new chunk-size to use
** for the nominated database. Allocating database file space in large
** chunks (say 1MB at a time), may reduce file-system fragmentation and
@@ -1080,24 +1915,24 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_SYNC]]
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
** sent to the VFS immediately before the xSync method is invoked on a
-** database file descriptor. Or, if the xSync method is not invoked
-** because the user has configured SQLite with
-** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
+** database file descriptor. Or, if the xSync method is not invoked
+** because the user has configured SQLite with
+** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
** of the xSync method. In most cases, the pointer argument passed with
** this file-control is NULL. However, if the database file is being synced
** as part of a multi-database commit, the argument points to a nul-terminated
-** string containing the transactions master-journal file name. VFSes that
-** do not need this signal should silently ignore this opcode. Applications
-** should not call [sqlite3_file_control()] with this opcode as doing so may
-** disrupt the operation of the specialized VFSes that do require it.
+** string containing the transactions super-journal file name. VFSes that
+** do not need this signal should silently ignore this opcode. Applications
+** should not call [sqlite3_file_control()] with this opcode as doing so may
+** disrupt the operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]]
** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite
** and sent to the VFS after a transaction has been committed immediately
** but before the database is unlocked. VFSes that do not need this signal
** should silently ignore this opcode. Applications should not call
-** [sqlite3_file_control()] with this opcode as doing so may disrupt the
-** operation of the specialized VFSes that do require it.
+** [sqlite3_file_control()] with this opcode as doing so may disrupt the
+** operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
@@ -1110,7 +1945,7 @@ struct sqlite3_io_methods {
** opcode allows these two values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
-** integers where the first integer i the new retry count and the second
+** integers where the first integer is the new retry count and the second
** integer is the delay. If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
@@ -1119,7 +1954,8 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_PERSIST_WAL]]
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary
-** write ahead log and shared memory files used for transaction control
+** write ahead log ([WAL file]) and shared memory
+** files used for transaction control
** are automatically deleted when the latest connection to the database
** closes. Setting persistent WAL mode causes those files to persist after
** close. Persisting the files is useful when other processes that do not
@@ -1144,13 +1980,13 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_OVERWRITE]]
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
** a write transaction to indicate that, unless it is rolled back for some
-** reason, the entire database file will be overwritten by the current
+** reason, the entire database file will be overwritten by the current
** transaction. This is used by VACUUM operations.
**
** <li>[[SQLITE_FCNTL_VFSNAME]]
** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
** all [VFSes] in the VFS stack. The names are of all VFS shims and the
-** final bottom-level VFS are written into memory obtained from
+** final bottom-level VFS are written into memory obtained from
** [sqlite3_malloc()] and the result is stored in the char* variable
** that the fourth parameter of [sqlite3_file_control()] points to.
** The caller is responsible for freeing the memory when done. As with
@@ -1169,7 +2005,7 @@ struct sqlite3_io_methods {
** upper-most shim only.
**
** <li>[[SQLITE_FCNTL_PRAGMA]]
-** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
+** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
** file control is sent to the open [sqlite3_file] object corresponding
** to the database file to which the pragma statement refers. ^The argument
** to the [SQLITE_FCNTL_PRAGMA] file control is an array of
@@ -1180,7 +2016,7 @@ struct sqlite3_io_methods {
** of the char** argument point to a string obtained from [sqlite3_mprintf()]
** or the equivalent and that string will become the result of the pragma or
** the error message if the pragma fails. ^If the
-** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
+** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
@@ -1197,16 +2033,16 @@ struct sqlite3_io_methods {
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
-** to the connections busy-handler callback. The argument is of type (void **)
+** to the connection's busy-handler callback. The argument is of type (void**)
** - an array of two (void *) values. The first (void *) actually points
-** to a function of type (int (*)(void *)). In order to invoke the connections
+** to a function of type (int (*)(void *)). In order to invoke the connection's
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
-** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses. The
@@ -1220,7 +2056,7 @@ struct sqlite3_io_methods {
** The argument is a pointer to a value of type sqlite3_int64 that
** is an advisory maximum number of bytes in the file to memory map. The
** pointer is overwritten with the old value. The limit is not changed if
-** the value originally pointed to is negative, and so the current limit
+** the value originally pointed to is negative, and so the current limit
** can be queried by passing in a pointer to a negative number. This
** file-control is used internally to implement [PRAGMA mmap_size].
**
@@ -1264,7 +2100,80 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_RBU]]
** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
-** this opcode.
+** this opcode.
+**
+** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
+** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
+** the file descriptor is placed in "batch write mode", which
+** means all subsequent write operations will be deferred and done
+** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
+** that do not support batch atomic writes will return SQLITE_NOTFOUND.
+** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
+** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
+** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
+** no VFS interface calls on the same [sqlite3_file] file descriptor
+** except for calls to the xWrite method and the xFileControl method
+** with [SQLITE_FCNTL_SIZE_HINT].
+**
+** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
+** operations since the previous successful call to
+** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
+** This file control returns [SQLITE_OK] if and only if the writes were
+** all performed successfully and have been committed to persistent storage.
+** ^Regardless of whether or not it is successful, this file control takes
+** the file descriptor out of batch write mode so that all subsequent
+** write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
+** operations since the previous successful call to
+** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
+** ^This file control takes the file descriptor out of batch write mode
+** so that all subsequent write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
+** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
+** to block for up to M milliseconds before failing when attempting to
+** obtain a file lock using the xLock or xShmLock methods of the VFS.
+** The parameter is a pointer to a 32-bit signed integer that contains
+** the value that M is to be set to. Before returning, the 32-bit signed
+** integer is overwritten with the previous value of M.
+**
+** <li>[[SQLITE_FCNTL_DATA_VERSION]]
+** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
+** a database file. The argument is a pointer to a 32-bit unsigned integer.
+** The "data version" for the pager is written into the pointer. The
+** "data version" changes whenever any change occurs to the corresponding
+** database file, either through SQL statements on the same database
+** connection or through transactions committed by separate database
+** connections possibly in other processes. The [sqlite3_total_changes()]
+** interface can be used to find if any database on the connection has changed,
+** but that interface responds to changes on TEMP as well as MAIN and does
+** not provide a mechanism to detect changes to MAIN only. Also, the
+** [sqlite3_total_changes()] interface responds to internal changes only and
+** omits changes made by other database connections. The
+** [PRAGMA data_version] command provides a mechanism to detect changes to
+** a single attached database that occur due to other database connections,
+** but omits changes implemented by the database connection on which it is
+** called. This file control is the only mechanism to detect changes that
+** happen either internally or externally and that are associated with
+** a particular attached database.
+**
+** <li>[[SQLITE_FCNTL_CKPT_START]]
+** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
+** in wal mode before the client starts to copy pages from the wal
+** file to the database file.
+**
+** <li>[[SQLITE_FCNTL_CKPT_DONE]]
+** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
+** in wal mode after the client has finished copying pages from the wal
+** file to the database file, but before the *-shm file is updated to
+** record the fact that the pages have been checkpointed.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1295,6 +2204,16 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
+#define SQLITE_FCNTL_PDB 30
+#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
+#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
+#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
+#define SQLITE_FCNTL_LOCK_TIMEOUT 34
+#define SQLITE_FCNTL_DATA_VERSION 35
+#define SQLITE_FCNTL_SIZE_LIMIT 36
+#define SQLITE_FCNTL_CKPT_DONE 37
+#define SQLITE_FCNTL_RESERVE_BYTES 38
+#define SQLITE_FCNTL_CKPT_START 39
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1332,12 +2251,18 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** 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
-** object when the iVersion value is increased. Note that the structure
-** of the sqlite3_vfs object changes in the transaction between
-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
-** modified.
+** The VFS interface is sometimes extended by adding new methods onto
+** the end. Each time such an extension occurs, the iVersion field
+** is incremented. The iVersion value started out as 1 in
+** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
+** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
+** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields
+** may be appended to the sqlite3_vfs object and the iVersion value
+** may increase again in future versions of SQLite.
+** Note that due to an oversight, the structure
+** of the sqlite3_vfs object changed in the transition from
+** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
+** and yet the iVersion field was not increased.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS. mxPathname is the maximum length of
@@ -1372,14 +2297,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** the [sqlite3_file] can safely store a pointer to the
** filename if it needs to remember the filename for some reason.
** If the zFilename parameter to xOpen is a NULL pointer then xOpen
-** must invent its own temporary name for the file. ^Whenever the
+** must invent its own temporary name for the file. ^Whenever the
** xFilename parameter is NULL it will also be the case that the
** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
**
** The flags argument to xOpen() includes all bits set in
** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
** or [sqlite3_open16()] is used, then flags includes at least
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
** If xOpen() opens a file read-only then it sets *pOutFlags to
** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
**
@@ -1393,7 +2318,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
** <li> [SQLITE_OPEN_TRANSIENT_DB]
** <li> [SQLITE_OPEN_SUBJOURNAL]
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
+** <li> [SQLITE_OPEN_SUPER_JOURNAL]
** <li> [SQLITE_OPEN_WAL]
** </ul>)^
**
@@ -1421,14 +2346,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
** with the [SQLITE_OPEN_CREATE] flag, which are both directly
** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
-** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
+** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
-** It is <i>not</i> used to indicate the file should be opened
+** It is <i>not</i> used to indicate the file should be opened
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
-** to hold the [sqlite3_file] structure passed as the third
+** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen. The xOpen method does not have to
** allocate the structure; it should just fill it in. Note that
** the xOpen method must set the sqlite3_file.pMethods to either
@@ -1441,8 +2366,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** ^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]
-** to test whether a file is at least readable. The file can be a
-** directory.
+** to test whether a file is at least readable. The SQLITE_ACCESS_READ
+** flag is never actually used and is not implemented in the built-in
+** VFSes of SQLite. The file is named by the second argument and can be a
+** directory. The xAccess method returns [SQLITE_OK] on success or some
+** non-zero error code if there is an I/O error or if the name of
+** the file given in the second argument is illegal. If SQLITE_OK
+** is returned, then non-zero or zero is written into *pResOut to indicate
+** whether or not the file is accessible.
**
** ^SQLite will always allocate at least mxPathname+1 bytes for the
** output buffer xFullPathname. The exact size of the output buffer
@@ -1462,16 +2393,16 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** 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 multiplied by 86400000 (the number of milliseconds in
-** a 24-hour day).
+** 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
+** date and time if that method is available (if iVersion is 2 or
** greater and the function pointer is not NULL) and will fall back
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
**
** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
** are not used by the SQLite core. These optional interfaces are provided
-** by some VFSes to facilitate testing of the VFS code. By overriding
+** by some VFSes to facilitate testing of the VFS code. By overriding
** system calls with functions under its control, a test program can
** simulate faults and error conditions that would otherwise be difficult
** or impossible to induce. The set of system calls that can be overridden
@@ -1518,7 +2449,7 @@ struct sqlite3_vfs {
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
** New fields may be appended in future versions. The iVersion
- ** value will increment whenever this happens.
+ ** value will increment whenever this happens.
*/
};
@@ -1562,7 +2493,7 @@ struct sqlite3_vfs {
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
-** was given on the corresponding lock.
+** was given on the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
@@ -1707,7 +2638,7 @@ SQLITE_API int sqlite3_config(int, ...);
** [database connection] (specified in the first argument).
**
** The second argument to sqlite3_db_config(D,V,...) is the
-** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
+** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
** that indicates what aspect of the [database connection] is being configured.
** Subsequent arguments vary depending on the configuration verb.
**
@@ -1725,7 +2656,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
** This object is used in only one place in the SQLite interface.
** A pointer to an instance of this object is the argument to
** [sqlite3_config()] when the configuration option is
-** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
+** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
** By creating an instance of this object
** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
** during configuration, an application can specify an alternative
@@ -1755,17 +2686,17 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
** allocators round up memory allocations at least to the next multiple
** of 8. Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
-** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
+** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator. For example,
-** it might allocate any require mutexes or initialize internal data
+** it might allocate any required mutexes or initialize internal data
** structures. The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit. The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
+** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe. The
** xShutdown method is only called from [sqlite3_shutdown()] so it does
** not need to be threadsafe either. For all other methods, SQLite
@@ -1813,7 +2744,7 @@ struct sqlite3_mem_methods {
** by a single thread. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** it is not possible to change the [threading mode] from its default
-** value of Single-thread and so [sqlite3_config()] will return
+** value of Single-thread and so [sqlite3_config()] will return
** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
** configuration option.</dd>
**
@@ -1848,7 +2779,7 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
**
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
+** <dd> ^(The SQLITE_CONFIG_MALLOC 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
@@ -1865,12 +2796,23 @@ struct sqlite3_mem_methods {
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
+** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
+** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
+** type int, interpreted as a boolean, which if true provides a hint to
+** SQLite that it should avoid large memory allocations if possible.
+** SQLite will run faster if it is free to make large memory allocations,
+** but some application might prefer to run slower in exchange for
+** guarantees about memory fragmentation that are possible if large
+** allocations are avoided. This hint is normally off.
+** </dd>
+**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
** <dd> ^The SQLITE_CONFIG_MEMSTATUS 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 following SQLite interfaces become non-operational:
** <ul>
+** <li> [sqlite3_hard_heap_limit64()]
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
@@ -1882,32 +2824,14 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
-** that SQLite can use for scratch memory. ^(There are three arguments
-** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
-** aligned memory buffer from which the scratch allocations will be
-** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N).)^
-** The first argument must be a pointer to an 8-byte aligned buffer
-** of at least sz*N bytes of memory.
-** ^SQLite will not use more than one scratch buffers per thread.
-** ^SQLite will never request a scratch buffer that is more than 6
-** times the database page size.
-** ^If SQLite needs needs additional
-** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
-** ^When the application provides any amount of scratch memory using
-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
-** [sqlite3_malloc|heap allocations].
-** This can help [Robson proof|prevent memory allocation failures] due to heap
-** fragmentation in low-memory embedded systems.
+** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
-** cache implementation.
-** This configuration option is a no-op if an application-define page
+** cache implementation.
+** This configuration option is a no-op if an application-defined page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
@@ -1934,10 +2858,9 @@ struct sqlite3_mem_methods {
** additional cache line. </dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
+** <dd> ^The SQLITE_CONFIG_HEAP 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].
+** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
** [SQLITE_ERROR] if invoked otherwise.
@@ -1990,7 +2913,7 @@ struct sqlite3_mem_methods {
** configuration on individual connections.)^ </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
-** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
** the interface to a custom page cache implementation.)^
** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
@@ -2004,7 +2927,7 @@ struct sqlite3_mem_methods {
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
** global [error log].
** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
-** function with a call signature of void(*)(void*,int,const char*),
+** 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
** invoked by [sqlite3_log()] to process each logging event. ^If the
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
@@ -2113,7 +3036,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
-** becomes the [statement journal] spill-to-disk threshold.
+** becomes the [statement journal] spill-to-disk threshold.
** [Statement journals] are held in memory until their size (in bytes)
** exceeds this threshold, at which point they are written to disk.
** Or if the threshold is -1, statement journals are always held
@@ -2123,6 +3046,33 @@ struct sqlite3_mem_methods {
** I/O required to support statement rollback.
** The default value for this setting is controlled by the
** [SQLITE_STMTJRNL_SPILL] compile-time option.
+**
+** [[SQLITE_CONFIG_SORTERREF_SIZE]]
+** <dt>SQLITE_CONFIG_SORTERREF_SIZE
+** <dd>The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter
+** of type (int) - the new value of the sorter-reference size threshold.
+** Usually, when SQLite uses an external sort to order records according
+** to an ORDER BY clause, all fields required by the caller are present in the
+** sorted records. However, if SQLite determines based on the declared type
+** of a table column that its values are likely to be very large - larger
+** than the configured sorter-reference size threshold - then a reference
+** is stored in each sorted record and the required column values loaded
+** from the database as records are returned in sorted order. The default
+** value for this option is to never use this optimization. Specifying a
+** negative value for this option restores the default behaviour.
+** This option is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
+**
+** [[SQLITE_CONFIG_MEMDB_MAXSIZE]]
+** <dt>SQLITE_CONFIG_MEMDB_MAXSIZE
+** <dd>The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter
+** [sqlite3_int64] parameter which is the default maximum size for an in-memory
+** database created using [sqlite3_deserialize()]. This default maximum
+** size can be adjusted up or down for individual databases using the
+** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this
+** configuration setting is never used, then the default maximum is determined
+** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
+** compile-time option is not set, then the default maximum is 1073741824.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2130,13 +3080,13 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
#define SQLITE_CONFIG_PCACHE 14 /* no-op */
#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
@@ -2151,6 +3101,9 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
+#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
+#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
+#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2166,8 +3119,9 @@ struct sqlite3_mem_methods {
** is invoked.
**
** <dl>
+** [[SQLITE_DBCONFIG_LOOKASIDE]]
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
-** <dd> ^This option takes three additional arguments that determine the
+** <dd> ^This option takes three additional arguments that determine the
** [lookaside memory allocator] configuration for the [database connection].
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
** pointer to a memory buffer to use for lookaside memory.
@@ -2185,9 +3139,10 @@ struct sqlite3_mem_methods {
** when the "current value" returned by
** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
** Any attempt to change the lookaside memory configuration when lookaside
-** memory is in use leaves the configuration unchanged and returns
+** memory is in use leaves the configuration unchanged and returns
** [SQLITE_BUSY].)^</dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
** <dd> ^This option is used to enable or disable the enforcement of
** [foreign key constraints]. There should be two additional arguments.
@@ -2198,6 +3153,7 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the FK enforcement setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]]
** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
** There should be two additional arguments.
@@ -2208,9 +3164,21 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
+** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
+** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable views,
+** positive to enable views or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether views are disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the view setting is not reported back. </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
-** <dd> ^This option is used to enable or disable the two-argument
-** version of the [fts3_tokenizer()] function which is part of the
+** <dd> ^This option is used to enable or disable the
+** [fts3_tokenizer()] function which is part of the
** [FTS3] full-text search engine extension.
** There should be two additional arguments.
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
@@ -2221,6 +3189,7 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the new setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]]
** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
** interface independently of the [load_extension()] SQL function.
@@ -2238,7 +3207,7 @@ struct sqlite3_mem_methods {
** be a NULL pointer, in which case the new setting is not reported back.
** </dd>
**
-** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
+** [[SQLITE_DBCONFIG_MAINDBNAME]] <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
** <dd> ^This option is used to change the name of the "main" database
** schema. ^The sole argument is a pointer to a constant UTF8 string
** which will become the new schema name in place of "main". ^SQLite
@@ -2247,6 +3216,162 @@ struct sqlite3_mem_methods {
** until after the database connection closes.
** </dd>
**
+** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
+** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
+** <dd> Usually, when a database in wal mode is closed or detached from a
+** database handle, SQLite checks if this will mean that there are now no
+** connections at all to the database. If so, it performs a checkpoint
+** operation before closing the connection. This option may be used to
+** override this behaviour. The first parameter passed to this operation
+** is an integer - positive to disable checkpoints-on-close, or zero (the
+** default) to enable them, and negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer
+** into which is written 0 or 1 to indicate whether checkpoints-on-close
+** have been disabled - 0 if they are not disabled, 1 if they are.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_QPSG]] <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
+** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
+** the [query planner stability guarantee] (QPSG). When the QPSG is active,
+** a single SQL query statement will always use the same algorithm regardless
+** of values of [bound parameters].)^ The QPSG disables some query optimizations
+** that look at the values of bound parameters, which can make some queries
+** slower. But the QPSG has the advantage of more predictable behavior. With
+** the QPSG active, SQLite will always use the same query plan in the field as
+** was used during testing in the lab.
+** The first argument to this setting is an integer which is 0 to disable
+** the QPSG, positive to enable QPSG, or negative to leave the setting
+** unchanged. The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether the QPSG is disabled or enabled
+** following this call.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_TRIGGER_EQP]] <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
+** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
+** include output for any operations performed by trigger programs. This
+** option is used to set or clear (the default) a flag that governs this
+** behavior. The first parameter passed to this operation is an integer -
+** positive to enable output for trigger programs, or zero to disable it,
+** or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which is written
+** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
+** it is not disabled, 1 if it is.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_RESET_DATABASE]] <dt>SQLITE_DBCONFIG_RESET_DATABASE</dt>
+** <dd> Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run
+** [VACUUM] in order to reset a database back to an empty database
+** with no schema and no content. The following process works even for
+** a badly corrupted database file:
+** <ol>
+** <li> If the database connection is newly opened, make sure it has read the
+** database schema by preparing then discarding some query against the
+** database, or calling sqlite3_table_column_metadata(), ignoring any
+** errors. This step is only necessary if the application desires to keep
+** the database in WAL mode after the reset if it was in WAL mode before
+** the reset.
+** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
+** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
+** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
+** </ol>
+** Because resetting a database is destructive and irreversible, the
+** process requires the use of this obscure API and multiple steps to help
+** ensure that it does not happen by accident.
+**
+** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
+** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
+** "defensive" flag for a database connection. When the defensive
+** flag is enabled, language features that allow ordinary SQL to
+** deliberately corrupt the database file are disabled. The disabled
+** features include but are not limited to the following:
+** <ul>
+** <li> The [PRAGMA writable_schema=ON] statement.
+** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> Writes to the [sqlite_dbpage] virtual table.
+** <li> Direct writes to [shadow tables].
+** </ul>
+** </dd>
+**
+** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]] <dt>SQLITE_DBCONFIG_WRITABLE_SCHEMA</dt>
+** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the
+** "writable_schema" flag. This has the same effect and is logically equivalent
+** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF].
+** The first argument to this setting is an integer which is 0 to disable
+** the writable_schema, positive to enable writable_schema, or negative to
+** leave the setting unchanged. The second parameter is a pointer to an
+** integer into which is written 0 or 1 to indicate whether the writable_schema
+** is enabled or disabled following this call.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]]
+** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt>
+** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates
+** the legacy behavior of the [ALTER TABLE RENAME] command such it
+** behaves as it did prior to [version 3.24.0] (2018-06-04). See the
+** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for
+** additional information. This feature can also be turned on and off
+** using the [PRAGMA legacy_alter_table] statement.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_DQS_DML]]
+** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
+** the legacy [double-quoted string literal] misfeature for DML statements
+** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
+** default value of this setting is determined by the [-DSQLITE_DQS]
+** compile-time option.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_DQS_DDL]]
+** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
+** the legacy [double-quoted string literal] misfeature for DDL statements,
+** such as CREATE TABLE and CREATE INDEX. The
+** default value of this setting is determined by the [-DSQLITE_DQS]
+** compile-time option.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
+** assume that database schemas are untainted by malicious content.
+** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
+** takes additional defensive steps to protect the application from harm
+** including:
+** <ul>
+** <li> Prohibit the use of SQL functions inside triggers, views,
+** CHECK constraints, DEFAULT clauses, expression indexes,
+** partial indexes, or generated columns
+** unless those functions are tagged with [SQLITE_INNOCUOUS].
+** <li> Prohibit the use of virtual tables inside of triggers or views
+** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS].
+** </ul>
+** This setting defaults to "on" for legacy compatibility, however
+** all applications are advised to turn it off if possible. This setting
+** can also be controlled using the [PRAGMA trusted_schema] statement.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
+** the legacy file format flag. When activated, this flag causes all newly
+** created database file to have a schema format version number (the 4-byte
+** integer found at offset 44 into the database header) of 1. This in turn
+** means that the resulting database file will be readable and writable by
+** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
+** newly created databases are generally not understandable by SQLite versions
+** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
+** is now scarcely any need to generated database files that are compatible
+** all the way back to version 3.0.0, and so this setting is of little
+** practical use, but is provided so that SQLite can continue to claim the
+** ability to generate new database files that are compatible with version
+** 3.0.0.
+** <p>Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on,
+** the [VACUUM] command will fail with an obscure error when attempting to
+** process a table with generated columns and a descending index. This is
+** not considered a bug since SQLite versions 3.3.0 and earlier do not support
+** either generated columns or decending indexes.
+** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2255,7 +3380,19 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
-
+#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */
+#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */
+#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */
+#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
+#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */
+#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
+#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
+#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
+#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
+#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2279,20 +3416,30 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
** the table has a column of type [INTEGER PRIMARY KEY] then that column
** is another alias for the rowid.
**
-** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the
-** most recent successful [INSERT] into a rowid table or [virtual table]
-** on database connection D.
-** ^Inserts into [WITHOUT ROWID] tables are not recorded.
-** ^If no successful [INSERT]s into rowid tables
-** have ever occurred on the database connection D,
-** then sqlite3_last_insert_rowid(D) returns zero.
-**
-** ^(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.)^
+** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
+** the most recent successful [INSERT] into a rowid table or [virtual table]
+** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
+** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
+** on the database connection D, then sqlite3_last_insert_rowid(D) returns
+** zero.
+**
+** As well as being set automatically as rows are inserted into database
+** tables, the value returned by this function may be set explicitly by
+** [sqlite3_set_last_insert_rowid()]
+**
+** Some virtual table implementations may INSERT rows into rowid tables as
+** part of committing a transaction (e.g. to flush data accumulated in memory
+** to disk). In this case subsequent calls to this function return the rowid
+** associated with these internal INSERT operations, which leads to
+** unintuitive results. Virtual table implementations that do write to rowid
+** tables in this way can avoid this problem by restoring the original
+** rowid value using [sqlite3_set_last_insert_rowid()] before returning
+** control to the user.
+**
+** ^(If an [INSERT] occurs within a trigger then this routine will
+** return the [rowid] of the inserted row as long as the trigger is
+** running. Once the trigger program ends, the value returned
+** by this routine reverts to what it was before the trigger was fired.)^
**
** ^An [INSERT] that fails due to a constraint violation is not a
** successful [INSERT] and does not change the value returned by this
@@ -2320,6 +3467,16 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
/*
+** CAPI3REF: Set the Last Insert Rowid value.
+** METHOD: sqlite3
+**
+** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
+** set the value returned by calling sqlite3_last_insert_rowid(D) to R
+** without inserting a row into the database.
+*/
+SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
+
+/*
** CAPI3REF: Count The Number Of Rows Modified
** METHOD: sqlite3
**
@@ -2330,45 +3487,50 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** returned by this function.
**
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
-** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
-**
-** Changes to a view that are intercepted by
-** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
-** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
-** DELETE statement run on a view is always zero. Only changes made to real
+**
+** Changes to a view that are intercepted by
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
+** DELETE statement run on a view is always zero. Only changes made to real
** tables are counted.
**
** Things are more complicated if the sqlite3_changes() function is
** executed while a trigger program is running. This may happen if the
** program uses the [changes() SQL function], or if some other callback
** function invokes sqlite3_changes() directly. Essentially:
-**
+**
** <ul>
** <li> ^(Before entering a trigger program the value returned by
-** sqlite3_changes() function is saved. After the trigger program
+** sqlite3_changes() function is saved. After the trigger program
** has finished, the original value is restored.)^
-**
-** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
-** statement sets the value returned by sqlite3_changes()
-** upon completion as normal. Of course, this value will not include
-** any changes performed by sub-triggers, as the sqlite3_changes()
+**
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
+** statement sets the value returned by sqlite3_changes()
+** upon completion as normal. Of course, this value will not include
+** any changes performed by sub-triggers, as the sqlite3_changes()
** value will be saved and restored after each sub-trigger has run.)^
** </ul>
-**
+**
** ^This means that if the changes() SQL function (or similar) is used
-** by the first INSERT, UPDATE or DELETE statement within a trigger, it
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
** returns the value as set when the calling statement began executing.
-** ^If it is used by the second or subsequent such statement within a trigger
-** program, the value returned reflects the number of rows modified by the
+** ^If it is used by the second or subsequent such statement within a trigger
+** program, the value returned reflects the number of rows modified by the
** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
-** See also the [sqlite3_total_changes()] interface, the
-** [count_changes pragma], and the [changes() SQL function].
-**
** If a separate thread makes changes on the same database connection
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_total_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** </ul>
*/
SQLITE_API int sqlite3_changes(sqlite3*);
@@ -2381,18 +3543,31 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** since the database connection was opened, including those executed as
** part of trigger programs. ^Executing any other type of SQL statement
** does not affect the value returned by sqlite3_total_changes().
-**
+**
** ^Changes made as part of [foreign key actions] are included in the
** count, but those made as part of REPLACE constraint resolution are
-** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
** are not counted.
-**
-** See also the [sqlite3_changes()] interface, the
-** [count_changes pragma], and the [total_changes() SQL function].
+**
+** The [sqlite3_total_changes(D)] interface only reports the number
+** of rows that changed due to SQL statement run against database
+** connection D. Any changes by other database connections are ignored.
+** To detect changes against a database file from other database
+** connections use the [PRAGMA data_version] command or the
+** [SQLITE_FCNTL_DATA_VERSION] [file control].
**
** If a separate thread makes changes on the same database connection
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
+** </ul>
*/
SQLITE_API int sqlite3_total_changes(sqlite3*);
@@ -2422,17 +3597,14 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete. ^Any new SQL statements
-** that are started after the sqlite3_interrupt() call and before the
-** running statements reaches zero are interrupted as if they had been
+** that are started after the sqlite3_interrupt() call and before the
+** running statement count reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call. ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
-**
-** If the database connection closes while [sqlite3_interrupt()]
-** is running then bad things will likely happen.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
@@ -2457,7 +3629,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** ^These routines do not parse the SQL statements thus
** will not detect syntactically incorrect SQL.
**
-** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
+** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
** automatically by sqlite3_complete16(). If that initialization fails,
** then the return value from sqlite3_complete16() will be non-zero
@@ -2502,7 +3674,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** The presence of a busy handler does not guarantee that it will be invoked
** when there is lock contention. ^If SQLite determines that invoking the busy
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
-** to the application instead of invoking the
+** to the application instead of invoking the
** busy handler.
** Consider a scenario where one process is holding a read lock that
** it is trying to promote to a reserved lock and
@@ -2527,7 +3699,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** database connection that invoked the busy handler. In other words,
** the busy handler is not reentrant. Any such actions
** result in undefined behavior.
-**
+**
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
@@ -2594,9 +3766,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** Cindy | 21
** </pre></blockquote>
**
-** There are two column (M==2) and three rows (N==3). Thus the
+** There are two columns (M==2) and three rows (N==3). Thus the
** result table has 8 entries. Suppose the result table is stored
-** in an array names azResult. Then azResult holds this content:
+** in an array named azResult. Then azResult holds this content:
**
** <blockquote><pre>
** azResult&#91;0] = "Name";
@@ -2644,16 +3816,16 @@ SQLITE_API void sqlite3_free_table(char **result);
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
-** These routines understand most of the common K&R formatting options,
-** plus some additional non-standard formats, detailed below.
-** Note that some of the more obscure formatting options from recent
-** C-library standards are omitted from this implementation.
+** These routines understand most of the common formatting options from
+** the standard library printf()
+** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
+** See the [built-in printf()] documentation for details.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
-** results into memory obtained from [sqlite3_malloc()].
+** results into memory obtained from [sqlite3_malloc64()].
** The strings returned by these two routines should be
** released by [sqlite3_free()]. ^Both routines return a
-** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
+** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough
** memory to hold the resulting string.
**
** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
@@ -2677,71 +3849,7 @@ SQLITE_API void sqlite3_free_table(char **result);
**
** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
**
-** These routines all implement some additional formatting
-** options that are useful for constructing SQL statements.
-** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", "%w" and "%z" options.
-**
-** ^(The %q option works like %s in that it substitutes a nul-terminated
-** string from the argument list. But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal.)^ By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, assume the string variable zText contains text as follows:
-**
-** <blockquote><pre>
-** char *zText = "It's a happy day!";
-** </pre></blockquote>
-**
-** One can use this text in an SQL statement as follows:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It''s a happy day!')
-** </pre></blockquote>
-**
-** This is correct. Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It's a happy day!');
-** </pre></blockquote>
-**
-** This second example is an SQL syntax error. As a general rule you should
-** always use %q instead of %s when inserting text into a string literal.
-**
-** ^(The %Q option works like %q except it also adds single quotes around
-** the outside of the total string. Additionally, if the parameter in the
-** argument list is a NULL pointer, %Q substitutes the text "NULL" (without
-** single quotes).)^ So, for example, one could say:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** The code above will render a correct SQL statement in the zSQL
-** variable even if the zText variable is a NULL pointer.
-**
-** ^(The "%w" formatting option is like "%q" except that it expects to
-** be contained within double-quotes instead of single quotes, and it
-** escapes the double-quote character instead of the single-quote
-** character.)^ The "%w" formatting option is intended for safely inserting
-** table and column names into a constructed SQL statement.
-**
-** ^(The "%z" formatting option works like "%s" but with the
-** addition that after the string has been read and copied into
-** the result, [sqlite3_free()] is called on the input string.)^
+** See also: [built-in printf()], [printf() SQL function]
*/
SQLITE_API char *sqlite3_mprintf(const char*,...);
SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
@@ -2753,7 +3861,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
-** does not include operating-system specific VFS implementation. The
+** does not include operating-system specific [VFS] implementation. The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
@@ -2814,19 +3922,6 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**
-** In SQLite version 3.5.0 and 3.5.1, it was possible to define
-** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
-** implementation of these routines to be omitted. That capability
-** is no longer provided. Only built-in memory allocators can be used.
-**
-** Prior to SQLite version 3.7.10, the Windows OS interface layer called
-** the system malloc() and free() directly when converting
-** filenames between the UTF-8 encoding used by SQLite
-** and whatever filename encoding is used by the particular Windows
-** installation. Memory allocation errors were detected, but
-** they were reported back as [SQLITE_CANTOPEN] or
-** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
-**
** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
@@ -2875,7 +3970,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID]. The PRNG is also used for
-** the build-in random() and randomblob() SQL functions. This interface allows
+** the built-in random() and randomblob() SQL functions. This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
@@ -2895,12 +3990,14 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
** METHOD: sqlite3
+** KEYWORDS: {authorizer callback}
**
** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
** ^The authorizer callback is invoked as SQL statements are being compiled
** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various
+** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
+** and [sqlite3_prepare16_v3()]. ^At various
** points during the compilation process, as logic is being created
** to perform various actions, the authorizer callback is invoked to
** see if those actions are allowed. ^The authorizer callback should
@@ -2916,14 +4013,16 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** requested is ok. ^When the callback returns [SQLITE_DENY], the
** [sqlite3_prepare_v2()] or equivalent call that triggered the
** authorizer will fail with an error message explaining that
-** access is denied.
+** access is denied.
**
** ^The first parameter to the authorizer callback is a copy of the third
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
** to the callback is an integer [SQLITE_COPY | action code] that specifies
** the particular action to be authorized. ^The third through sixth parameters
-** to the callback are zero-terminated strings that contain additional
-** details about the action to be authorized.
+** to the callback are either NULL pointers or zero-terminated strings
+** that contain additional details about the action to be authorized.
+** Applications must always be prepared to encounter a NULL pointer in any
+** of the third through the sixth parameters of the authorization callback.
**
** ^If the action code is [SQLITE_READ]
** and the callback returns [SQLITE_IGNORE] then the
@@ -2932,6 +4031,10 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
** return can be used to deny an untrusted user access to individual
** columns of a table.
+** ^When a table is referenced by a [SELECT] but no column values are
+** extracted from that table (for example in a query like
+** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
+** is invoked once for that table with a column name that is an empty string.
** ^If the action code is [SQLITE_DELETE] and the callback returns
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
** [truncate optimization] is disabled and all rows are deleted individually.
@@ -2963,7 +4066,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** database connections for the meaning of "modify" in this paragraph.
**
** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
-** statement might be re-prepared during [sqlite3_step()] due to a
+** statement might be re-prepared during [sqlite3_step()] due to a
** schema change. Hence, the application should ensure that the
** correct authorizer callback remains in place during the [sqlite3_step()].
**
@@ -3077,9 +4180,9 @@ SQLITE_API int sqlite3_set_authorizer(
** time is in units of nanoseconds, however the current implementation
** is only capable of millisecond resolution so the six least significant
** digits in the time are meaningless. Future versions of SQLite
-** might provide greater resolution on the profiler callback. The
-** sqlite3_profile() function is considered experimental and is
-** subject to change in future versions of SQLite.
+** might provide greater resolution on the profiler callback. Invoking
+** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the
+** profile callback.
*/
SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
void(*xTrace)(void*,const char*), void*);
@@ -3091,8 +4194,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** KEYWORDS: SQLITE_TRACE
**
** These constants identify classes of events that can be monitored
-** using the [sqlite3_trace_v2()] tracing logic. The third argument
-** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
+** using the [sqlite3_trace_v2()] tracing logic. The M argument
+** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
** the following constants. ^The first argument to the trace callback
** is one of the following constants.
**
@@ -3111,7 +4214,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** execution of the prepared statement, such as at the start of each
** trigger subprogram. ^The P argument is a pointer to the
** [prepared statement]. ^The X argument is a pointer to a string which
-** is the unexpanded SQL text of the prepared statement or an SQL comment
+** is the unexpanded SQL text of the prepared statement or an SQL comment
** that indicates the invocation of a trigger. ^The callback can compute
** the same text that would have been returned by the legacy [sqlite3_trace()]
** interface by using the X argument when X begins with "--" and invoking
@@ -3127,7 +4230,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
-** statement generates a single row of result.
+** statement generates a single row of result.
** ^The P argument is a pointer to the [prepared statement] and the
** X argument is unused.
**
@@ -3154,10 +4257,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
**
-** ^The X callback is invoked whenever any of the events identified by
+** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
** ignored, though this may change in future releases. Callback
** implementations should return zero to ensure future compatibility.
@@ -3189,8 +4292,8 @@ SQLITE_API int sqlite3_trace_v2(
** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
-** ^The parameter P is passed through as the only parameter to the
-** callback function X. ^The parameter N is the approximate number of
+** ^The parameter P is passed through as the only parameter to the
+** callback function X. ^The parameter N is the approximate number of
** [virtual machine instructions] that are evaluated between successive
** invocations of the callback X. ^If N is less than one then the progress
** handler is disabled.
@@ -3217,7 +4320,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** CAPI3REF: Opening A New Database Connection
** CONSTRUCTOR: sqlite3
**
-** ^These routines open an SQLite database file as specified 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
@@ -3241,10 +4344,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection. ^(The flags parameter to
-** sqlite3_open_v2() can take one of
-** the following three values, optionally combined with the
-** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
+** sqlite3_open_v2() must include, at a minimum, one of the following
+** three flag combinations:)^
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
@@ -3262,23 +4363,51 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** sqlite3_open() and sqlite3_open16().</dd>)^
** </dl>
**
+** In addition to the required flags, the following optional flags are
+** also supported:
+**
+** <dl>
+** ^(<dt>[SQLITE_OPEN_URI]</dt>
+** <dd>The filename can be interpreted as a URI if this flag is set.</dd>)^
+**
+** ^(<dt>[SQLITE_OPEN_MEMORY]</dt>
+** <dd>The database will be opened as an in-memory database. The database
+** is named by the "filename" argument for the purposes of cache-sharing,
+** if shared cache mode is enabled, but the "filename" is otherwise ignored.
+** </dd>)^
+**
+** ^(<dt>[SQLITE_OPEN_NOMUTEX]</dt>
+** <dd>The new database connection will use the "multi-thread"
+** [threading mode].)^ This means that separate threads are allowed
+** to use SQLite at the same time, as long as each thread is using
+** a different [database connection].
+**
+** ^(<dt>[SQLITE_OPEN_FULLMUTEX]</dt>
+** <dd>The new database connection will use the "serialized"
+** [threading mode].)^ This means the multiple threads can safely
+** attempt to use the same database connection at the same time.
+** (Mutexes will block any actual concurrency, but in this mode
+** there is no harm in trying.)
+**
+** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt>
+** <dd>The database is opened [shared cache] enabled, overriding
+** the default shared cache setting provided by
+** [sqlite3_enable_shared_cache()].)^
+**
+** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
+** <dd>The database is opened [shared cache] disabled, overriding
+** the default shared cache setting provided by
+** [sqlite3_enable_shared_cache()].)^
+**
+** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
+** <dd>The database filename is not allowed to be a symbolic link</dd>
+** </dl>)^
+**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above optionally combined with other
+** required 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
-** opens in the multi-thread [threading mode] as long as the single-thread
-** mode has not been set at compile-time or start-time. ^If the
-** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
-** in the serialized [threading mode] unless single-thread was
-** previously selected at compile-time or start-time.
-** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
-** eligible to use [shared cache mode], regardless of whether or not shared
-** cache is enabled using [sqlite3_enable_shared_cache()]. ^The
-** [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
@@ -3301,26 +4430,26 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** ^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
+** set in the third 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
+** 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
+** 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
+** 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
+** 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]]
@@ -3340,13 +4469,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw",
** "rwc", or "memory". 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_open_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
+** 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_open_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 the mode option is
** set to "memory" then a pure [in-memory database] that never reads
** or writes from disk is used. ^It is an error to specify a value for
@@ -3356,7 +4485,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** <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
+** 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 behavior requested by setting
@@ -3382,7 +4511,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** property on a database file that does in fact change can result
** in incorrect query results and/or [SQLITE_CORRUPT] errors.
** See also: [SQLITE_IOCAP_IMMUTABLE].
-**
+**
** </ul>
**
** ^Specifying an unknown parameter in the query component of a URI is not an
@@ -3394,36 +4523,36 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** <table border="1" align=center cellpadding=5>
** <tr><th> URI filenames <th> Results
-** <tr><td> file:data.db <td>
+** <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>
+** 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>
+** <tr><td> file://darkstar/home/fred/data.db <td>
** An error. "darkstar" is not a recognized authority.
-** <tr><td style="white-space:nowrap">
+** <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
+** 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>
+** <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-dotfile <td>
** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile"
** that uses dot-files in place of posix advisory locking.
-** <tr><td> file:data.db?mode=readonly <td>
+** <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
+** 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
+** 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.
@@ -3458,17 +4587,27 @@ SQLITE_API int sqlite3_open_v2(
/*
** CAPI3REF: Obtain Values For URI Parameters
**
-** These are utility routines, useful to VFS implementations, that check
-** to see if a database file was a URI that contained a specific query
+** These are utility routines, useful to [VFS|custom VFS implementations],
+** that check if a database file was a URI that contained a specific query
** parameter, and if so obtains the value of that query parameter.
**
-** If F is the database filename pointer passed into the xOpen() method of
-** a VFS implementation when the flags parameter to xOpen() has one or
-** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
-** P is the name of the query parameter, then
+** The first parameter to these interfaces (hereafter referred to
+** as F) must be one of:
+** <ul>
+** <li> A database filename pointer created by the SQLite core and
+** passed into the xOpen() method of a VFS implemention, or
+** <li> A filename obtained from [sqlite3_db_filename()], or
+** <li> A new filename constructed using [sqlite3_create_filename()].
+** </ul>
+** If the F parameter is not one of the above, then the behavior is
+** undefined and probably undesirable. Older versions of SQLite were
+** more tolerant of invalid F parameters than newer versions.
+**
+** If F is a suitable filename (as described in the previous paragraph)
+** and if P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
-** parameter if it exists or a NULL pointer if P does not appear as a
-** query parameter on F. If P is a query parameter of F
+** parameter if it exists or a NULL pointer if P does not appear as a
+** query parameter on F. If P is a query parameter of F and it
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
@@ -3476,44 +4615,176 @@ SQLITE_API int sqlite3_open_v2(
** parameter and returns true (1) or false (0) according to the value
** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
** value of query parameter P is one of "yes", "true", or "on" in any
-** case or if the value begins with a non-zero number. The
+** case or if the value begins with a non-zero number. The
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero. If P is not a query
-** parameter on F or if the value of P is does not match any of the
+** parameter on F or if the value of P does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist. If the value of P is something other than an integer, then
** zero is returned.
-**
+**
+** The sqlite3_uri_key(F,N) returns a pointer to the name (not
+** the value) of the N-th query parameter for filename F, or a NULL
+** pointer if N is less than zero or greater than the number of query
+** parameters minus 1. The N value is zero-based so N should be 0 to obtain
+** the name of the first query parameter, 1 for the second parameter, and
+** so forth.
+**
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
-** is not a database file pathname pointer that SQLite passed into the xOpen
-** VFS method, then the behavior of this routine is undefined and probably
-** undesirable.
+** is not a database file pathname pointer that the SQLite core passed
+** into the xOpen VFS method, then the behavior of this routine is undefined
+** and probably undesirable.
+**
+** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F
+** parameter can also be the name of a rollback journal file or WAL file
+** in addition to the main database file. Prior to version 3.31.0, these
+** routines would only work if F was the name of the main database file.
+** When the F parameter is the name of the rollback journal or WAL file,
+** it has access to all the same query parameters as were found on the
+** main database file.
+**
+** See the [URI filename] documentation for additional information.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
+
+/*
+** CAPI3REF: Translate filenames
+**
+** These routines are available to [VFS|custom VFS implementations] for
+** translating filenames between the main database file, the journal file,
+** and the WAL file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** passed by the SQLite core into the VFS, then sqlite3_filename_database(F)
+** returns the name of the corresponding database file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** passed by the SQLite core into the VFS, or if F is a database filename
+** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F)
+** returns the name of the corresponding rollback journal file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** that was passed by the SQLite core into the VFS, or if F is a database
+** filename obtained from [sqlite3_db_filename()], then
+** sqlite3_filename_wal(F) returns the name of the corresponding
+** WAL file.
+**
+** In all of the above, if F is not the name of a database, journal or WAL
+** filename passed into the VFS from the SQLite core and F is not the
+** return value from [sqlite3_db_filename()], then the result is
+** undefined and is likely a memory access violation.
+*/
+SQLITE_API const char *sqlite3_filename_database(const char*);
+SQLITE_API const char *sqlite3_filename_journal(const char*);
+SQLITE_API const char *sqlite3_filename_wal(const char*);
+
+/*
+** CAPI3REF: Database File Corresponding To A Journal
+**
+** ^If X is the name of a rollback or WAL-mode journal file that is
+** passed into the xOpen method of [sqlite3_vfs], then
+** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file]
+** object that represents the main database file.
+**
+** This routine is intended for use in custom [VFS] implementations
+** only. It is not a general-purpose interface.
+** The argument sqlite3_file_object(X) must be a filename pointer that
+** has been passed into [sqlite3_vfs].xOpen method where the
+** flags parameter to xOpen contains one of the bits
+** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use
+** of this routine results in undefined and probably undesirable
+** behavior.
+*/
+SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
+/*
+** CAPI3REF: Create and Destroy VFS Filenames
+**
+** These interfces are provided for use by [VFS shim] implementations and
+** are not useful outside of that context.
+**
+** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
+** database filename D with corresponding journal file J and WAL file W and
+** with N URI parameters key/values pairs in the array P. The result from
+** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
+** is safe to pass to routines like:
+** <ul>
+** <li> [sqlite3_uri_parameter()],
+** <li> [sqlite3_uri_boolean()],
+** <li> [sqlite3_uri_int64()],
+** <li> [sqlite3_uri_key()],
+** <li> [sqlite3_filename_database()],
+** <li> [sqlite3_filename_journal()], or
+** <li> [sqlite3_filename_wal()].
+** </ul>
+** If a memory allocation error occurs, sqlite3_create_filename() might
+** return a NULL pointer. The memory obtained from sqlite3_create_filename(X)
+** must be released by a corresponding call to sqlite3_free_filename(Y).
+**
+** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
+** of 2*N pointers to strings. Each pair of pointers in this array corresponds
+** to a key and value for a query parameter. The P parameter may be a NULL
+** pointer if N is zero. None of the 2*N pointers in the P array may be
+** NULL pointers and key pointers should not be empty strings.
+** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
+** be NULL pointers, though they can be empty strings.
+**
+** The sqlite3_free_filename(Y) routine releases a memory allocation
+** previously obtained from sqlite3_create_filename(). Invoking
+** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
+**
+** If the Y parameter to sqlite3_free_filename(Y) is anything other
+** than a NULL pointer or a pointer previously acquired from
+** sqlite3_create_filename(), then bad things such as heap
+** corruption or segfaults may occur. The value Y should be
+** used again after sqlite3_free_filename(Y) has been called. This means
+** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
+** then the corresponding [sqlite3_module.xClose() method should also be
+** invoked prior to calling sqlite3_free_filename(Y).
+*/
+SQLITE_API char *sqlite3_create_filename(
+ const char *zDatabase,
+ const char *zJournal,
+ const char *zWal,
+ int nParam,
+ const char **azParam
+);
+SQLITE_API void sqlite3_free_filename(char*);
/*
** CAPI3REF: Error Codes And Messages
** METHOD: sqlite3
**
-** ^If the most recent sqlite3_* API call associated with
+** ^If the most recent sqlite3_* API call associated with
** [database connection] D failed, then the sqlite3_errcode(D) interface
** returns the numeric [result code] or [extended result code] for that
** API call.
-** If the most recent API call was successful,
-** then the return value from sqlite3_errcode() is undefined.
** ^The sqlite3_extended_errcode()
-** interface is the same except that it always returns the
+** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
**
+** The values returned by sqlite3_errcode() and/or
+** sqlite3_extended_errcode() might change with each API call.
+** Except, there are some interfaces that are guaranteed to never
+** change the value of the error code. The error-code preserving
+** interfaces are:
+**
+** <ul>
+** <li> sqlite3_errcode()
+** <li> sqlite3_extended_errcode()
+** <li> sqlite3_errmsg()
+** <li> sqlite3_errmsg16()
+** </ul>
+**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
** text that describes the error, as either UTF-8 or UTF-16 respectively.
** ^(Memory to hold the error message string is managed internally.
@@ -3554,7 +4825,7 @@ SQLITE_API const char *sqlite3_errstr(int);
** has been compiled into binary form and is ready to be evaluated.
**
** Think of each SQL statement as a separate computer program. The
-** original SQL text is source code. A prepared statement object
+** original SQL text is source code. A prepared statement object
** is the compiled object code. All SQL must be converted into a
** prepared statement before it can be run.
**
@@ -3584,7 +4855,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
** new limit for that construct.)^
**
** ^If the new limit is a negative number, the limit is unchanged.
-** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
** [limits | hard upper bound]
** set at compile-time by a C preprocessor macro called
** [limits | SQLITE_MAX_<i>NAME</i>].
@@ -3592,7 +4863,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
** ^Attempts to increase a limit above its hard upper bound are
** silently truncated to the hard upper bound.
**
-** ^Regardless of whether or not the limit was changed, the
+** ^Regardless of whether or not the limit was changed, the
** [sqlite3_limit()] interface returns the prior value of the limit.
** ^Hence, to find the current value of a limit without changing it,
** simply invoke this interface with the third parameter set to -1.
@@ -3643,9 +4914,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** [[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>)^
+** used to implement an SQL statement. If [sqlite3_prepare_v2()] or
+** the equivalent tries to allocate space for more than this many opcodes
+** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
**
** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
** <dd>The maximum number of arguments on a function.</dd>)^
@@ -3684,22 +4955,73 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
#define SQLITE_LIMIT_WORKER_THREADS 11
/*
+** CAPI3REF: Prepare Flags
+**
+** These constants define various flags that can be passed into
+** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
+** [sqlite3_prepare16_v3()] interfaces.
+**
+** New flags may be added in future releases of SQLite.
+**
+** <dl>
+** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt>
+** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
+** that the prepared statement will be retained for a long time and
+** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
+** and [sqlite3_prepare16_v3()] assume that the prepared statement will
+** be used just once or at most a few times and then destroyed using
+** [sqlite3_finalize()] relatively soon. The current implementation acts
+** on this hint by avoiding the use of [lookaside memory] so as not to
+** deplete the limited store of lookaside memory. Future versions of
+** SQLite may act on this hint differently.
+**
+** [[SQLITE_PREPARE_NORMALIZE]] <dt>SQLITE_PREPARE_NORMALIZE</dt>
+** <dd>The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used
+** to be required for any prepared statement that wanted to use the
+** [sqlite3_normalized_sql()] interface. However, the
+** [sqlite3_normalized_sql()] interface is now available to all
+** prepared statements, regardless of whether or not they use this
+** flag.
+**
+** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
+** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
+** to return an error (error code SQLITE_ERROR) if the statement uses
+** any virtual tables.
+** </dl>
+*/
+#define SQLITE_PREPARE_PERSISTENT 0x01
+#define SQLITE_PREPARE_NORMALIZE 0x02
+#define SQLITE_PREPARE_NO_VTAB 0x04
+
+/*
** CAPI3REF: Compiling An SQL Statement
** KEYWORDS: {SQL statement compiler}
** METHOD: sqlite3
** CONSTRUCTOR: sqlite3_stmt
**
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of these routines.
+** To execute an SQL statement, it must first be compiled into a byte-code
+** program using one of these routines. Or, in other words, these routines
+** are constructors for the [prepared statement] object.
+**
+** The preferred routine to use is [sqlite3_prepare_v2()]. The
+** [sqlite3_prepare()] interface is legacy and should be avoided.
+** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used
+** for special purposes.
+**
+** The use of the UTF-8 interfaces is preferred, as SQLite currently
+** does all parsing using UTF-8. The UTF-16 interfaces are provided
+** as a convenience. The UTF-16 interfaces work by converting the
+** input text into UTF-8, then invoking the corresponding UTF-8 interface.
**
** The first argument, "db", is a [database connection] obtained from a
** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
** [sqlite3_open16()]. The database connection must not have been closed.
**
** The second argument, "zSql", is the statement to be compiled, encoded
-** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2()
-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
-** use UTF-16.
+** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(),
+** and sqlite3_prepare_v3()
+** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
+** and sqlite3_prepare16_v3() use UTF-16.
**
** ^If the nByte argument is negative, then zSql is read up to the
** first zero terminator. ^If nByte is positive, then it is the
@@ -3726,10 +5048,11 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
** otherwise an [error code] is returned.
**
-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
-** recommended for all new programs. The two older interfaces are retained
-** for backwards compatibility, but their use is discouraged.
-** ^In the "v2" interfaces, the prepared statement
+** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(),
+** and sqlite3_prepare16_v3() interfaces are recommended for all new programs.
+** The older interfaces (sqlite3_prepare() and sqlite3_prepare16())
+** are retained for backwards compatibility, but their use is discouraged.
+** ^In the "vX" interfaces, the prepared statement
** that is returned (the [sqlite3_stmt] object) contains a copy of the
** original SQL text. This causes the [sqlite3_step()] interface to
** behave differently in three ways:
@@ -3752,17 +5075,23 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
**
** <li>
-** ^If the specific value bound to [parameter | host parameter] in the
+** ^If the specific value bound to a [parameter | host parameter] in the
** WHERE clause might influence the choice of query plan for a statement,
-** then the statement will be automatically recompiled, as if there had been
-** a schema change, on the first [sqlite3_step()] call following any change
-** to the [sqlite3_bind_text | bindings] of that [parameter].
-** ^The specific value of WHERE-clause [parameter] might influence the
+** then the statement will be automatically recompiled, as if there had been
+** a schema change, on the first [sqlite3_step()] call following any change
+** to the [sqlite3_bind_text | bindings] of that [parameter].
+** ^The specific value of a WHERE-clause [parameter] might influence the
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
-** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
+** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
+**
+** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
+** the extra prepFlags parameter, which is a bit array consisting of zero or
+** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The
+** sqlite3_prepare_v2() interface works exactly the same as
+** sqlite3_prepare_v3() with a zero prepFlags parameter.
*/
SQLITE_API int sqlite3_prepare(
sqlite3 *db, /* Database handle */
@@ -3778,6 +5107,14 @@ SQLITE_API int sqlite3_prepare_v2(
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
+SQLITE_API int sqlite3_prepare_v3(
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL statement, UTF-8 encoded */
+ int nByte, /* Maximum length of zSql in bytes. */
+ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
+);
SQLITE_API int sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
@@ -3792,6 +5129,14 @@ SQLITE_API int sqlite3_prepare16_v2(
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
+SQLITE_API int sqlite3_prepare16_v3(
+ sqlite3 *db, /* Database handle */
+ const void *zSql, /* SQL statement, UTF-16 encoded */
+ int nByte, /* Maximum length of zSql in bytes. */
+ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
+);
/*
** CAPI3REF: Retrieving Statement SQL
@@ -3799,10 +5144,16 @@ SQLITE_API int sqlite3_prepare16_v2(
**
** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
** SQL text used to create [prepared statement] P if P was
-** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()],
+** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
** string containing the SQL text of prepared statement P with
** [bound parameters] expanded.
+** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8
+** string containing the normalized SQL text of prepared statement P. The
+** semantics used to normalize a SQL statement are unspecified and subject
+** to change. At a minimum, literal values will be replaced with suitable
+** placeholders.
**
** ^(For example, if a prepared statement is created using the SQL
** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
@@ -3818,14 +5169,16 @@ SQLITE_API int sqlite3_prepare16_v2(
** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
** option causes sqlite3_expanded_sql() to always return NULL.
**
-** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
-** automatically freed when the prepared statement is finalized.
+** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P)
+** are managed by SQLite and are automatically freed when the prepared
+** statement is finalized.
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
** is obtained from [sqlite3_malloc()] and must be free by the application
** by passing it to [sqlite3_free()].
*/
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3836,8 +5189,8 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
** the content of the database file.
**
** Note that [application-defined SQL functions] or
-** [virtual tables] might change the database indirectly as a side effect.
-** ^(For example, if an application defines a function "eval()" that
+** [virtual tables] might change the database indirectly as a side effect.
+** ^(For example, if an application defines a function "eval()" that
** calls [sqlite3_exec()], then the following SQL statement would
** change the database file through side-effects:
**
@@ -3851,31 +5204,47 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
** since the statements themselves do not actually modify the database but
-** rather they control the timing of when other statements modify the
+** rather they control the timing of when other statements modify the
** database. ^The [ATTACH] and [DETACH] statements also cause
** sqlite3_stmt_readonly() to return true since, while those statements
-** change the configuration of a database connection, they do not make
+** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
+** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
+** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
+** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
+** sqlite3_stmt_readonly() returns false for those commands.
*/
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlite3_stmt
+**
+** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the
+** prepared statement S is an EXPLAIN statement, or 2 if the
+** statement S is an EXPLAIN QUERY PLAN.
+** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is
+** an ordinary statement or a NULL pointer.
+*/
+SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
-** [prepared statement] S has been stepped at least once using
+** [prepared statement] S has been stepped at least once using
** [sqlite3_step(S)] but has neither run to completion (returned
** [SQLITE_DONE] from [sqlite3_step(S)]) nor
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
-** interface returns false if S is a NULL pointer. If S is not a
+** interface returns false if S is a NULL pointer. If S is not a
** NULL pointer and is not a pointer to a valid [prepared statement]
** object, then the behavior is undefined and probably undesirable.
**
** This interface can be used in combination [sqlite3_next_stmt()]
-** to locate all prepared statements associated with a database
+** to locate all prepared statements associated with a database
** connection that are in need of being reset. This can be used,
-** for example, in diagnostic routines to search for prepared
+** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
@@ -3894,7 +5263,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** will accept either a protected or an unprotected sqlite3_value.
** Every interface that accepts sqlite3_value arguments specifies
** whether or not it requires a protected sqlite3_value. The
-** [sqlite3_value_dup()] interface can be used to construct a new
+** [sqlite3_value_dup()] interface can be used to construct a new
** protected sqlite3_value from an unprotected sqlite3_value.
**
** The terms "protected" and "unprotected" refer to whether or not
@@ -3902,7 +5271,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** sqlite3_value object but no mutex is held for an unprotected
** sqlite3_value object. If SQLite is compiled to be single-threaded
** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
-** or if SQLite is run in one of reduced mutex modes
+** or if SQLite is run in one of reduced mutex modes
** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
** then there is no distinction between protected and unprotected
** sqlite3_value objects and they can be used interchangeably. However,
@@ -3914,12 +5283,13 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** implementation of [application-defined SQL functions] are protected.
** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected.
-** Unprotected sqlite3_value objects may only be used with
-** [sqlite3_result_value()] and [sqlite3_bind_value()].
+** Unprotected sqlite3_value objects may only be used as arguments
+** to [sqlite3_result_value()], [sqlite3_bind_value()], and
+** [sqlite3_value_dup()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
-typedef struct Mem sqlite3_value;
+typedef struct sqlite3_value sqlite3_value;
/*
** CAPI3REF: SQL Function Context Object
@@ -3970,12 +5340,30 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_bind_parameter_index()] API if desired. ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
-** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
+** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
+** ^If the third parameter to sqlite3_bind_text() is not NULL, then
+** it should be a pointer to well-formed UTF8 text.
+** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
+** it should be a pointer to well-formed UTF16 text.
+** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
+** it should be a pointer to a well-formed unicode string that is
+** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
+** otherwise.
+**
+** [[byte-order determination rules]] ^The byte-order of
+** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
+** found in first character, which is removed, or in the absence of a BOM
+** the byte order is the native byte order of the host
+** machine for sqlite3_bind_text16() or the byte order specified in
+** the 6th parameter for sqlite3_bind_text64().)^
+** ^If UTF16 input text contains invalid unicode
+** characters, then SQLite might change those invalid characters
+** into the unicode replacement character: U+FFFD.
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the
@@ -3989,7 +5377,7 @@ typedef struct sqlite3_context sqlite3_context;
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
-** terminated. If any NUL characters occur at byte offsets less than
+** terminated. If any NUL characters occurs at byte offsets less than
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs. The result of expressions involving strings
** with embedded NULs is undefined.
@@ -3997,7 +5385,9 @@ typedef struct sqlite3_context sqlite3_context;
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it. ^The destructor is called
-** to dispose of the BLOB or string even if the call to bind API fails.
+** to dispose of the BLOB or string even if the call to the bind API fails,
+** except the destructor is not called if the third parameter is a NULL
+** pointer or the fourth parameter is negative.
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
@@ -4021,6 +5411,15 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_blob_open | incremental BLOB I/O] routines.
** ^A negative value for the zeroblob results in a zero-length BLOB.
**
+** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
+** [prepared statement] S to have an SQL value of NULL, but to also be
+** associated with the pointer P of type T. ^D is either a NULL pointer or
+** a pointer to a destructor function for P. ^SQLite will invoke the
+** destructor D with a single argument of P when it is finished using
+** P. The T parameter should be a static string, preferably a string
+** literal. The sqlite3_bind_pointer() routine is part of the
+** [pointer passing interface] added for SQLite 3.20.0.
+**
** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
** for the [prepared statement] or with a prepared statement for which
** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
@@ -4054,6 +5453,7 @@ SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
@@ -4097,8 +5497,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
** ^If the value N is out of range or if the N-th parameter is
** nameless, then NULL is returned. ^The returned string is
** always in UTF-8 encoding even if the named parameter was
-** originally specified as UTF-16 in [sqlite3_prepare16()] or
-** [sqlite3_prepare16_v2()].
+** originally specified as UTF-16 in [sqlite3_prepare16()],
+** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
**
** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and
@@ -4115,7 +5515,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero
** is returned if no matching parameter is found. ^The parameter
** name must be given in UTF-8 even if the original statement
-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
+** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or
+** [sqlite3_prepare16_v3()].
**
** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and
@@ -4138,8 +5539,12 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
** METHOD: sqlite3_stmt
**
** ^Return the number of columns in the result set returned by the
-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
-** statement that does not return data (for example an [UPDATE]).
+** [prepared statement]. ^If this routine returns 0, that means the
+** [prepared statement] returns no data (for example an [UPDATE]).
+** ^However, just because this routine returns a positive number does not
+** mean that one or more rows of data will be returned. ^A SELECT statement
+** will always have a positive sqlite3_column_count() but depending on the
+** WHERE clause constraints and the table content, it might return no rows.
**
** See also: [sqlite3_data_count()]
*/
@@ -4202,7 +5607,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
-** NULL. ^These routine might also return NULL if a memory allocation error
+** NULL. ^These routines might also return NULL if a memory allocation error
** occurs. ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
@@ -4212,10 +5617,6 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**
-** If two or more threads call one or more of these routines against the same
-** prepared statement and column at the same time then the results are
-** undefined.
-**
** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
@@ -4265,16 +5666,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** CAPI3REF: Evaluate An SQL Statement
** METHOD: sqlite3_stmt
**
-** After a [prepared statement] has been prepared using either
-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
+** After a [prepared statement] has been prepared using any of
+** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()],
+** or [sqlite3_prepare16_v3()] or one of the legacy
** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
** must be called one or more times to evaluate the statement.
**
** The details of the behavior of the sqlite3_step() interface depend
-** on whether the statement was prepared using the newer "v2" interface
-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
-** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
-** new "v2" interface is recommended for new applications but the legacy
+** on whether the statement was prepared using the newer "vX" interfaces
+** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()],
+** [sqlite3_prepare16_v2()] or the older legacy
+** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
+** new "vX" interface is recommended for new applications but the legacy
** interface will continue to be supported.
**
** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
@@ -4318,7 +5721,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** For all versions of SQLite up to and including 3.6.23.1, a call to
** [sqlite3_reset()] was required after sqlite3_step() returned anything
** other than [SQLITE_ROW] before any subsequent invocation of
-** sqlite3_step(). Failure to reset the prepared statement using
+** sqlite3_step(). Failure to reset the prepared statement using
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
** sqlite3_step() began
@@ -4335,10 +5738,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** specific [error codes] that better describes the error.
** We admit that this is a goofy design. The problem has been fixed
** with the "v2" interface. If you prepare all of your SQL statements
-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
+** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()]
+** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead
** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
** then the more specific [error codes] are returned directly
-** by sqlite3_step(). The use of the "v2" interface is recommended.
+** by sqlite3_step(). The use of the "vX" interfaces is recommended.
*/
SQLITE_API int sqlite3_step(sqlite3_stmt*);
@@ -4349,7 +5753,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
-** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
+** (via calls to the [sqlite3_column_int | sqlite3_column()] family of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
@@ -4400,6 +5804,28 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** KEYWORDS: {column access functions}
** METHOD: sqlite3_stmt
**
+** <b>Summary:</b>
+** <blockquote><table border=0 cellpadding=0 cellspacing=0>
+** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
+** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
+** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
+** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
+** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
+** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
+** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an
+** [sqlite3_value|unprotected sqlite3_value] object.
+** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
+** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
+** or a UTF-8 TEXT result in bytes
+** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
+** TEXT in bytes
+** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
+** datatype of the result
+** </table></blockquote>
+**
+** <b>Details:</b>
+**
** ^These routines return information about a single column of the current
** result row of a query. ^In every case the first argument is a pointer
** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
@@ -4421,16 +5847,29 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** are called from a different thread while any of these routines
** are pending, then the results are undefined.
**
+** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
+** each return the value of a result column in a specific data format. If
+** the result column is not initially in the requested format (for example,
+** if the query returns an integer but the sqlite3_column_text() interface
+** is used to extract the value) then an automatic type conversion is performed.
+**
** ^The sqlite3_column_type() routine returns the
** [SQLITE_INTEGER | datatype code] for the initial data type
** of the result column. ^The returned value is one of [SQLITE_INTEGER],
-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
-** returned by sqlite3_column_type() is only meaningful if no type
-** conversions have occurred as described below. After a type conversion,
-** the value returned by sqlite3_column_type() is undefined. Future
+** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
+** The return value of sqlite3_column_type() can be used to decide which
+** of the first six interface should be used to extract the column value.
+** The value returned by sqlite3_column_type() is only meaningful if no
+** automatic type conversions have occurred for the value in question.
+** After a type conversion, the result of calling sqlite3_column_type()
+** is undefined, though harmless. Future
** versions of SQLite may change the behavior of sqlite3_column_type()
** following a type conversion.
**
+** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
+** or sqlite3_column_bytes16() interfaces can be used to determine the size
+** of that BLOB or string.
+**
** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
** routine returns the number of bytes in that BLOB or string.
** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
@@ -4449,7 +5888,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** the number of bytes in that string.
** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
**
-** ^The values returned by [sqlite3_column_bytes()] and
+** ^The values returned by [sqlite3_column_bytes()] and
** [sqlite3_column_bytes16()] do not include the zero terminators at the end
** of the string. ^For clarity: the values returned by
** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
@@ -4467,9 +5906,13 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** [sqlite3_column_value()] is used in any other way, including calls
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
** or [sqlite3_value_bytes()], the behavior is not threadsafe.
+** Hence, the sqlite3_column_value() interface
+** is normally only useful within the implementation of
+** [application-defined SQL functions] or [virtual tables], not within
+** top-level application code.
**
-** These routines attempt to convert the value where appropriate. ^For
-** example, if the internal representation is FLOAT and a text result
+** The these routines may attempt to convert the datatype of the result.
+** ^For example, if the internal representation is FLOAT and a text result
** is requested, [sqlite3_snprintf()] is used internally to perform the
** conversion automatically. ^(The following table details the conversions
** that are applied:
@@ -4541,26 +5984,40 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** ^The pointers returned are valid until a type conversion occurs as
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
-** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned
+** and BLOBs is freed automatically. Do not pass the pointers returned
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
-** ^(If a memory allocation error occurs during the evaluation of any
-** of these routines, a default value is returned. The default value
-** is either the integer 0, the floating point number 0.0, or a NULL
-** pointer. Subsequent calls to [sqlite3_errcode()] will return
-** [SQLITE_NOMEM].)^
+** As long as the input parameters are correct, these routines will only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_column_blob()
+** <li> sqlite3_column_text()
+** <li> sqlite3_column_text16()
+** <li> sqlite3_column_bytes()
+** <li> sqlite3_column_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
*/
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@@ -4620,17 +6077,17 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
-** KEYWORDS: {application-defined SQL function}
-** KEYWORDS: {application-defined SQL functions}
** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates. The only differences between
-** these routines are the text encoding expected for
-** the second parameter (the name of the function being created)
-** and the presence or absence of a destructor callback for
-** the application data pointer.
+** of existing SQL functions or aggregates. The only differences between
+** the three "sqlite3_create_function*" routines are the text encoding
+** expected for the second parameter (the name of the function being
+** created) and the presence or absence of a destructor callback for
+** the application data pointer. Function sqlite3_create_window_function()
+** is similar, but allows the user to supply the extra callback functions
+** needed by [aggregate window functions].
**
** ^The first parameter is the [database connection] to which the SQL
** function is to be added. ^If an application uses more than one database
@@ -4640,7 +6097,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** ^The second parameter is the name of the SQL function to be created or
** redefined. ^The length of the name is limited to 255 bytes in a UTF-8
** representation, exclusive of the zero-terminator. ^Note that the name
-** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
** ^Any attempt to create a function with a longer name
** will result in [SQLITE_MISUSE] being returned.
**
@@ -4655,7 +6112,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** ^The fourth parameter, eTextRep, specifies what
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
** its parameters. The application should set this parameter to
-** [SQLITE_UTF16LE] if the function implementation invokes
+** [SQLITE_UTF16LE] if the function implementation invokes
** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
** implementation invokes [sqlite3_value_text16be()] on an input, or
** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
@@ -4673,10 +6130,28 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
+** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
+** flag, which if present prevents the function from being invoked from
+** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
+** index expressions, or the WHERE clause of partial indexes.
+**
+** <span style="background-color:#ffff90;">
+** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
+** all application-defined SQL functions that do not need to be
+** used inside of triggers, view, CHECK constraints, or other elements of
+** the database schema. This flags is especially recommended for SQL
+** functions that have side effects or reveal internal application state.
+** Without this flag, an attacker might be able to modify the schema of
+** a database file to include invocations of the function with parameters
+** chosen by the attacker, which the application will then execute when
+** the database file is opened and read.
+** </span>
+**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
-** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
+** ^The sixth, seventh and eighth parameters passed to the three
+** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
** callback only; NULL pointers must be passed as the xStep and xFinal
@@ -4685,15 +6160,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** SQL function or aggregate, pass NULL pointers for all three function
** callbacks.
**
-** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
-** then it is destructor for the application data pointer.
-** The destructor is invoked when the function is deleted, either by being
-** overloaded or when the database connection closes.)^
-** ^The destructor is also invoked if the call to
-** sqlite3_create_function_v2() fails.
-** ^When the destructor callback of the tenth parameter is invoked, it
-** is passed a single argument which is a copy of the application data
-** pointer which was the fifth parameter to sqlite3_create_function_v2().
+** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
+** and xInverse) passed to sqlite3_create_window_function are pointers to
+** C-language callbacks that implement the new function. xStep and xFinal
+** must both be non-NULL. xValue and xInverse may either both be NULL, in
+** which case a regular aggregate function is created, or must both be
+** non-NULL, in which case the new function may be used as either an aggregate
+** or aggregate window function. More details regarding the implementation
+** of aggregate window functions are
+** [user-defined window functions|available here].
+**
+** ^(If the final parameter to sqlite3_create_function_v2() or
+** sqlite3_create_window_function() is not NULL, then it is destructor for
+** the application data pointer. The destructor is invoked when the function
+** is deleted, either by being overloaded or when the database connection
+** closes.)^ ^The destructor is also invoked if the call to
+** sqlite3_create_function_v2() fails. ^When the destructor callback is
+** invoked, it is passed a single argument which is a copy of the application
+** data pointer which was the fifth parameter to sqlite3_create_function_v2().
**
** ^It is permitted to register multiple implementations of the same
** functions with the same name but with either differing numbers of
@@ -4703,7 +6187,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** nArg parameter is a better match than a function implementation with
** a negative nArg. ^A function where the preferred text encoding
** matches the database encoding is a better
-** match than a function where the encoding is different.
+** match than a function where the encoding is different.
** ^A function where the encoding difference is between UTF16le and UTF16be
** is a closer match than a function where the encoding difference is
** between UTF8 and UTF16.
@@ -4746,6 +6230,18 @@ SQLITE_API int sqlite3_create_function_v2(
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*)
);
+SQLITE_API int sqlite3_create_window_function(
+ sqlite3 *db,
+ const char *zFunctionName,
+ int nArg,
+ int eTextRep,
+ void *pApp,
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+ void (*xFinal)(sqlite3_context*),
+ void (*xValue)(sqlite3_context*),
+ void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
+ void(*xDestroy)(void*)
+);
/*
** CAPI3REF: Text Encodings
@@ -4763,19 +6259,79 @@ SQLITE_API int sqlite3_create_function_v2(
/*
** CAPI3REF: Function Flags
**
-** These constants may be ORed together with the
+** These constants may be ORed together with the
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
+**
+** <dl>
+** [[SQLITE_DETERMINISTIC]] <dt>SQLITE_DETERMINISTIC</dt><dd>
+** The SQLITE_DETERMINISTIC flag means that the new function always gives
+** the same output when the input parameters are the same.
+** The [abs|abs() function] is deterministic, for example, but
+** [randomblob|randomblob()] is not. Functions must
+** be deterministic in order to be used in certain contexts such as
+** with the WHERE clause of [partial indexes] or in [generated columns].
+** SQLite might also optimize deterministic functions by factoring them
+** out of inner loops.
+** </dd>
+**
+** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd>
+** The SQLITE_DIRECTONLY flag means that the function may only be invoked
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
+** schema structures such as [CHECK constraints], [DEFAULT clauses],
+** [expression indexes], [partial indexes], or [generated columns].
+** The SQLITE_DIRECTONLY flags is a security feature which is recommended
+** for all [application-defined SQL functions], and especially for functions
+** that have side-effects or that could potentially leak sensitive
+** information.
+** </dd>
+**
+** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
+** The SQLITE_INNOCUOUS flag means that the function is unlikely
+** to cause problems even if misused. An innocuous function should have
+** no side effects and should not depend on any values other than its
+** input parameters. The [abs|abs() function] is an example of an
+** innocuous function.
+** The [load_extension() SQL function] is not innocuous because of its
+** side effects.
+** <p> SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not
+** exactly the same. The [random|random() function] is an example of a
+** function that is innocuous but not deterministic.
+** <p>Some heightened security settings
+** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF])
+** disable the use of SQL functions inside views and triggers and in
+** schema structures such as [CHECK constraints], [DEFAULT clauses],
+** [expression indexes], [partial indexes], and [generated columns] unless
+** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions
+** are innocuous. Developers are advised to avoid using the
+** SQLITE_INNOCUOUS flag for application-defined functions unless the
+** function has been carefully audited and found to be free of potentially
+** security-adverse side-effects and information-leaks.
+** </dd>
+**
+** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
+** Specifying this flag makes no difference for scalar or aggregate user
+** functions. However, if it is not specified for a user-defined window
+** function, then any sub-types belonging to arguments passed to the window
+** function may be discarded before the window function is called (i.e.
+** sqlite3_value_subtype() will always return 0).
+** </dd>
+** </dl>
*/
-#define SQLITE_DETERMINISTIC 0x800
+#define SQLITE_DETERMINISTIC 0x000000800
+#define SQLITE_DIRECTONLY 0x000080000
+#define SQLITE_SUBTYPE 0x000100000
+#define SQLITE_INNOCUOUS 0x000200000
/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
** These functions are [deprecated]. In order to maintain
-** backwards compatibility with older code, these functions continue
+** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
** the use of these functions. To encourage programmers to avoid
** these functions, we will not explain what they do.
@@ -4794,21 +6350,45 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** CAPI3REF: Obtaining SQL Values
** METHOD: sqlite3_value
**
-** The C-language implementation of SQL functions and aggregates uses
-** this set of interface routines to access the parameter values on
-** the function or aggregate.
-**
-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
-** define callbacks that implement the SQL functions and aggregates.
-** The 3rd parameter to these callbacks is an array of pointers to
-** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
-** each parameter to the SQL function. These routines are used to
-** extract values from the [sqlite3_value] objects.
+** <b>Summary:</b>
+** <blockquote><table border=0 cellpadding=0 cellspacing=0>
+** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
+** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
+** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
+** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
+** <tr><td><b>sqlite3_value_pointer</b><td>&rarr;<td>Pointer value
+** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
+** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
+** the native byteorder
+** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
+** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
+** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
+** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
+** or a UTF-8 TEXT in bytes
+** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
+** TEXT in bytes
+** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
+** datatype of the value
+** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
+** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
+** against a virtual table.
+** <tr><td><b>sqlite3_value_frombind&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
+** </table></blockquote>
+**
+** <b>Details:</b>
+**
+** These routines extract type, size, and content information from
+** [protected sqlite3_value] objects. Protected sqlite3_value objects
+** are used to pass parameter information into the functions that
+** implement [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
-** object results in undefined behavior.
+** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object
@@ -4819,6 +6399,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
** extract UTF-16 strings as big-endian and little-endian respectively.
**
+** ^If [sqlite3_value] object V was initialized
+** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
+** and if X and Y are strings that compare equal according to strcmp(X,Y),
+** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise,
+** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
+**
+** ^(The sqlite3_value_type(V) interface returns the
+** [SQLITE_INTEGER | datatype code] for the initial datatype of the
+** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER],
+** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^
+** Other interfaces might change the datatype for an sqlite3_value object.
+** For example, if the datatype is initially SQLITE_INTEGER and
+** sqlite3_value_text(V) is called to extract a text value for that
+** integer, then subsequent calls to sqlite3_value_type(V) might return
+** SQLITE_TEXT. Whether or not a persistent internal datatype conversion
+** occurs is undefined and may change from one release of SQLite to the next.
+**
** ^(The sqlite3_value_numeric_type() interface attempts to apply
** numeric affinity to the value. This means that an attempt is
** made to convert the value to an integer or floating point. If
@@ -4827,6 +6425,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** then the conversion is performed. Otherwise no conversion occurs.
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
**
+** ^Within the [xUpdate] method of a [virtual table], the
+** sqlite3_value_nochange(X) interface returns true if and only if
+** the column corresponding to X is unchanged by the UPDATE operation
+** that the xUpdate method call was invoked to implement and if
+** and the prior [xColumn] method call that was invoked to extracted
+** the value for that column returned without setting a result (probably
+** because it queried [sqlite3_vtab_nochange()] and found that the column
+** was unchanging). ^Within an [xUpdate] method, any value for which
+** sqlite3_value_nochange(X) is true will in all other respects appear
+** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other
+** than within an [xUpdate] method call for an UPDATE statement, then
+** the return value is arbitrary and meaningless.
+**
+** ^The sqlite3_value_frombind(X) interface returns non-zero if the
+** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
+** interfaces. ^If X comes from an SQL literal value, or a table column,
+** or an expression, then sqlite3_value_frombind(X) returns zero.
+**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
@@ -4835,19 +6451,44 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
**
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
+**
+** As long as the input parameter is correct, these routines can only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_value_blob()
+** <li> sqlite3_value_text()
+** <li> sqlite3_value_text16()
+** <li> sqlite3_value_text16le()
+** <li> sqlite3_value_text16be()
+** <li> sqlite3_value_bytes()
+** <li> sqlite3_value_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
*/
SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
SQLITE_API double sqlite3_value_double(sqlite3_value*);
SQLITE_API int sqlite3_value_int(sqlite3_value*);
SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
+SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*);
SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
SQLITE_API int sqlite3_value_type(sqlite3_value*);
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
+SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
@@ -4858,10 +6499,6 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
-**
-** SQLite makes no use of subtype itself. It merely passes the subtype
-** from the result of one [application-defined SQL function] into the
-** input of another.
*/
SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
@@ -4889,9 +6526,9 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
-** ^The first time the sqlite3_aggregate_context(C,N) routine is called
-** for a particular aggregate function, SQLite
-** allocates N of memory, zeroes out that memory, and returns a pointer
+** ^The first time the sqlite3_aggregate_context(C,N) routine is called
+** for a particular aggregate function, SQLite allocates
+** N bytes of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned. Sqlite3_aggregate_context() is normally
@@ -4902,19 +6539,19 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
-** value of N in subsequent call to sqlite3_aggregate_context() within
+** value of N in any subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^ Within the xFinal callback, it is customary to set
-** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
** pointless memory allocations occur.
**
-** ^SQLite automatically frees the memory allocated by
+** ^SQLite automatically frees the memory allocated by
** sqlite3_aggregate_context() when the aggregate query concludes.
**
** The first parameter must be a copy of the
@@ -4964,15 +6601,16 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** some circumstances the associated metadata may be preserved. An example
** of where this might be useful is in a regular-expression matching
** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** metadata associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function. ^If there is no metadata
-** associated with the function argument, this sqlite3_get_auxdata() interface
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
+** value to the application-defined function. ^N is zero for the left-most
+** function argument. ^If there is no metadata
+** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
@@ -4989,10 +6627,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** SQL statement)^, or
** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
-** <li> ^(during the original sqlite3_set_auxdata() call when a memory
+** <li> ^(during the original sqlite3_set_auxdata() call when a memory
** allocation error occurs.)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last bullet in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
@@ -5003,6 +6641,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
+** The value of the N parameter to these interfaces should be non-negative.
+** Future enhancements may make use of negative N values to define new
+** kinds of function caching behavior.
+**
** These routines must be called from the same thread in which
** the SQL function is running.
*/
@@ -5060,8 +6702,9 @@ typedef void (*sqlite3_destructor_type)(void*);
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message. ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
-** interprets the string from sqlite3_result_error16() as UTF-16 in native
-** byte order. ^If the third parameter to sqlite3_result_error()
+** interprets the string from sqlite3_result_error16() as UTF-16 using
+** the same [byte-order determination rules] as [sqlite3_bind_text16()].
+** ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
@@ -5126,9 +6769,28 @@ typedef void (*sqlite3_destructor_type)(void*);
** when it has finished using that result.
** ^If the 4th parameter to the sqlite3_result_text* interfaces
** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
-** then SQLite makes a copy of the result into space obtained from
+** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.
**
+** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
+** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
+** when the encoding is not UTF8, if the input UTF16 begins with a
+** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
+** string and the rest of the string is interpreted according to the
+** byte-order specified by the BOM. ^The byte-order specified by
+** the BOM at the beginning of the text overrides the byte-order
+** specified by the interface procedure. ^So, for example, if
+** sqlite3_result_text16le() is invoked with text that begins
+** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
+** first two bytes of input are skipped and the remaining input
+** is interpreted as UTF16BE text.
+**
+** ^For UTF16 input text to the sqlite3_result_text16(),
+** sqlite3_result_text16be(), sqlite3_result_text16le(), and
+** sqlite3_result_text64() routines, if the text contains invalid
+** UTF16 characters, the invalid characters might be converted
+** into the unicode replacement character, U+FFFD.
+**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
@@ -5139,6 +6801,17 @@ typedef void (*sqlite3_destructor_type)(void*);
** [unprotected sqlite3_value] object is required, so either
** kind of [sqlite3_value] object can be used with this interface.
**
+** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
+** SQL NULL value, just like [sqlite3_result_null(C)], except that it
+** also associates the host-language pointer P or type T with that
+** NULL value such that the pointer can be retrieved within an
+** [application-defined SQL function] using [sqlite3_value_pointer()].
+** ^If the D parameter is not NULL, then it is a pointer to a destructor
+** for the P parameter. ^SQLite invokes D with P as its only argument
+** when SQLite is finished with P. The T parameter should be a static
+** string and preferably a string literal. The sqlite3_result_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
+**
** If these routines are called from within the different thread
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
@@ -5162,6 +6835,7 @@ SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*
SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
@@ -5171,8 +6845,8 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
** METHOD: sqlite3_context
**
** The sqlite3_result_subtype(C,T) function causes the subtype of
-** the result from the [application-defined SQL function] with
-** [sqlite3_context] C to be the value T. Only the lower 8 bits
+** the result from the [application-defined SQL function] with
+** [sqlite3_context] C to be the value T. Only the lower 8 bits
** of the subtype T are preserved in current versions of SQLite;
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
@@ -5202,7 +6876,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** <li> [SQLITE_UTF16_ALIGNED].
** </ul>)^
** ^The eTextRep argument determines the encoding of strings passed
-** to the collating function callback, xCallback.
+** to the collating function callback, xCompare.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
@@ -5211,18 +6885,19 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
-** ^The fifth argument, xCallback, is a pointer to the collating function.
+** ^The fifth argument, xCompare, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
-** ^If the xCallback argument is NULL then the collating function is
+** ^If the xCompare argument is NULL then the collating function is
** deleted. ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
-** ^The collating function callback is invoked with a copy of the pArg
+** ^The collating function callback is invoked with a copy of the pArg
** application data pointer and with two strings in the encoding specified
-** by the eTextRep argument. The collating function must return an
-** integer that is negative, zero, or positive
+** by the eTextRep argument. The two integer parameters to the collating
+** function callback are the length of the two strings, in bytes. The collating
+** function must return an integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively. A collating function must always return the same answer
** given the same inputs. If two or more collating functions are registered
@@ -5239,7 +6914,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** </ol>
**
** If a collating function fails any of the above constraints and that
-** collating function is registered and used, then the behavior of SQLite
+** collating function is registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
@@ -5249,36 +6924,36 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** calls to the collation creation functions or when the
** [database connection] is closed using [sqlite3_close()].
**
-** ^The xDestroy callback is <u>not</u> called if the
+** ^The xDestroy callback is <u>not</u> called if the
** sqlite3_create_collation_v2() function fails. Applications that invoke
-** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
** check the return code and dispose of the application data pointer
** themselves rather than expecting SQLite to deal with it for them.
-** This is different from every other SQLite interface. The inconsistency
-** is unfortunate but cannot be changed without breaking backwards
+** This is different from every other SQLite interface. The inconsistency
+** is unfortunate but cannot be changed without breaking backwards
** compatibility.
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
SQLITE_API int sqlite3_create_collation(
- sqlite3*,
- const char *zName,
- int eTextRep,
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
SQLITE_API int sqlite3_create_collation_v2(
- sqlite3*,
- const char *zName,
- int eTextRep,
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
SQLITE_API int sqlite3_create_collation16(
- sqlite3*,
+ sqlite3*,
const void *zName,
- int eTextRep,
+ int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
@@ -5311,64 +6986,19 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation_v2()].
*/
SQLITE_API int sqlite3_collation_needed(
- sqlite3*,
- void*,
+ sqlite3*,
+ void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
SQLITE_API int sqlite3_collation_needed16(
- sqlite3*,
+ sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
-#ifdef SQLITE_HAS_CODEC
-/*
-** Specify the key for an encrypted database. This routine should be
-** called right after sqlite3_open().
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-SQLITE_API int sqlite3_key(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The key */
-);
-SQLITE_API int sqlite3_key_v2(
- sqlite3 *db, /* Database to be rekeyed */
- const char *zDbName, /* Name of the database */
- const void *pKey, int nKey /* The key */
-);
-
-/*
-** Change the key on an open database. If the current database is not
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
-** database is decrypted.
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-SQLITE_API int sqlite3_rekey(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The new key */
-);
-SQLITE_API int sqlite3_rekey_v2(
- sqlite3 *db, /* Database to be rekeyed */
- const char *zDbName, /* Name of the database */
- const void *pKey, int nKey /* The new key */
-);
-
-/*
-** Specify the activation key for a SEE database. Unless
-** activated, none of the SEE routines will work.
-*/
-SQLITE_API void sqlite3_activate_see(
- const char *zPassPhrase /* Activation phrase */
-);
-#endif
-
#ifdef SQLITE_ENABLE_CEROD
/*
-** Specify the activation key for a CEROD database. Unless
+** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
@@ -5424,7 +7054,7 @@ SQLITE_API int sqlite3_sleep(int);
** ^The [temp_store_directory pragma] may modify this variable and cause
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
** the [temp_store_directory pragma] always assumes that any string
-** that this variable points to is held in memory obtained from
+** that this variable points to is held in memory obtained from
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
@@ -5481,7 +7111,7 @@ SQLITE_API char *sqlite3_temp_directory;
** ^The [data_store_directory pragma] may modify this variable and cause
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
** the [data_store_directory pragma] always assumes that any string
-** that this variable points to is held in memory obtained from
+** that this variable points to is held in memory obtained from
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
@@ -5491,6 +7121,41 @@ SQLITE_API char *sqlite3_temp_directory;
SQLITE_API char *sqlite3_data_directory;
/*
+** CAPI3REF: Win32 Specific Interface
+**
+** These interfaces are available only on Windows. The
+** [sqlite3_win32_set_directory] interface is used to set the value associated
+** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to
+** zValue, depending on the value of the type parameter. The zValue parameter
+** should be NULL to cause the previous value to be freed via [sqlite3_free];
+** a non-NULL value will be copied into memory obtained from [sqlite3_malloc]
+** prior to being used. The [sqlite3_win32_set_directory] interface returns
+** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported,
+** or [SQLITE_NOMEM] if memory could not be allocated. The value of the
+** [sqlite3_data_directory] variable is intended to act as a replacement for
+** the current directory on the sub-platforms of Win32 where that concept is
+** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and
+** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the
+** sqlite3_win32_set_directory interface except the string parameter must be
+** UTF-8 or UTF-16, respectively.
+*/
+SQLITE_API int sqlite3_win32_set_directory(
+ unsigned long type, /* Identifier for directory being set or reset */
+ void *zValue /* New value for directory being set or reset */
+);
+SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue);
+SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue);
+
+/*
+** CAPI3REF: Win32 Directory Types
+**
+** These macros are only available on Windows. They define the allowed values
+** for the type argument to the [sqlite3_win32_set_directory] interface.
+*/
+#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1
+#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2
+
+/*
** CAPI3REF: Test For Auto-Commit Mode
** KEYWORDS: {autocommit mode}
** METHOD: sqlite3
@@ -5531,16 +7196,31 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
-** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
-** associated with database N of connection D. ^The main database file
-** has the name "main". If there is no attached database N on the database
+** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
+** associated with database N of connection D.
+** ^If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
-** a NULL pointer is returned.
+** this function will return either a NULL pointer or an empty string.
+**
+** ^The string value returned by this routine is owned and managed by
+** the database connection. ^The value will be valid until the database N
+** is [DETACH]-ed or until the database connection closes.
**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS]. ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
+**
+** If the filename pointer returned by this routine is not NULL, then it
+** can be used as the filename input parameter to these routines:
+** <ul>
+** <li> [sqlite3_uri_parameter()]
+** <li> [sqlite3_uri_boolean()]
+** <li> [sqlite3_uri_int64()]
+** <li> [sqlite3_filename_database()]
+** <li> [sqlite3_filename_journal()]
+** <li> [sqlite3_filename_wal()]
+** </ul>
*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
@@ -5644,11 +7324,11 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^In the case of an update, this is the [rowid] after the update takes place.
**
** ^(The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).)^
+** modified (i.e. sqlite_sequence).)^
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
**
** ^In the current implementation, the update hook
-** is not invoked when duplication rows are deleted because of an
+** is not invoked when conflicting rows are deleted because of an
** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook
** invoked when rows are deleted using the [truncate optimization].
** The exceptions defined in this paragraph might change in a future
@@ -5670,7 +7350,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** and [sqlite3_preupdate_hook()] interfaces.
*/
SQLITE_API void *sqlite3_update_hook(
- sqlite3*,
+ sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
);
@@ -5684,25 +7364,29 @@ SQLITE_API void *sqlite3_update_hook(
** and disabled if the argument is false.)^
**
** ^Cache sharing is enabled and disabled for an entire process.
-** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
+** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
-** Existing database connections continue use the sharing mode
+** Existing database connections continue to use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully. An [error code] is returned otherwise.)^
**
-** ^Shared cache is disabled by default. But this might change in
-** future releases of SQLite. Applications that care about shared
-** cache setting should set it explicitly.
+** ^Shared cache is disabled by default. It is recommended that it stay
+** that way. In other words, do not use this routine. This interface
+** continues to be provided for historical compatibility, but its use is
+** discouraged. Any use of shared cache is discouraged. If shared cache
+** must be used, it is recommended that shared cache only be enabled for
+** individual database connections using the [sqlite3_open_v2()] interface
+** with the [SQLITE_OPEN_SHAREDCACHE] flag.
**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
-** and will always return SQLITE_MISUSE. On those systems,
-** shared cache mode should be enabled per-database connection via
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
**
** This interface is threadsafe on processors where writing a
@@ -5745,6 +7429,9 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
**
+** These interfaces impose limits on the amount of heap memory that will be
+** by all database connections within a single process.
+**
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
** soft limit on the amount of heap memory that may be allocated by SQLite.
** ^SQLite strives to keep heap memory utilization below the soft heap
@@ -5752,23 +7439,44 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** as heap memory usages approaches the limit.
** ^The soft heap limit is "soft" because even though SQLite strives to stay
** below the limit, it will exceed the limit rather than generate
-** an [SQLITE_NOMEM] error. In other words, the soft heap limit
+** an [SQLITE_NOMEM] error. In other words, the soft heap limit
** is advisory only.
**
-** ^The return value from sqlite3_soft_heap_limit64() is the size of
-** the soft heap limit prior to the call, or negative in the case of an
-** error. ^If the argument N is negative
-** then no change is made to the soft heap limit. Hence, the current
-** size of the soft heap limit can be determined by invoking
-** sqlite3_soft_heap_limit64() with a negative argument.
-**
-** ^If the argument N is zero then the soft heap limit is disabled.
+** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of
+** N bytes on the amount of memory that will be allocated. ^The
+** sqlite3_hard_heap_limit64(N) interface is similar to
+** sqlite3_soft_heap_limit64(N) except that memory allocations will fail
+** when the hard heap limit is reached.
**
-** ^(The soft heap limit is not enforced in the current implementation
+** ^The return value from both sqlite3_soft_heap_limit64() and
+** sqlite3_hard_heap_limit64() is the size of
+** the heap limit prior to the call, or negative in the case of an
+** error. ^If the argument N is negative
+** then no change is made to the heap limit. Hence, the current
+** size of heap limits can be determined by invoking
+** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1).
+**
+** ^Setting the heap limits to zero disables the heap limiter mechanism.
+**
+** ^The soft heap limit may not be greater than the hard heap limit.
+** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
+** is invoked with a value of N that is greater than the hard heap limit,
+** the the soft heap limit is set to the value of the hard heap limit.
+** ^The soft heap limit is automatically enabled whenever the hard heap
+** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
+** the soft heap limit is outside the range of 1..N, then the soft heap
+** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the
+** hard heap limit is enabled makes the soft heap limit equal to the
+** hard heap limit.
+**
+** The memory allocation limits can also be adjusted using
+** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit].
+**
+** ^(The heap limits are not enforced in the current implementation
** if one or more of following conditions are true:
**
** <ul>
-** <li> The soft heap limit is set to zero.
+** <li> The limit value is set to zero.
** <li> Memory accounting is disabled using a combination of the
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
@@ -5779,21 +7487,11 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** from the heap.
** </ul>)^
**
-** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
-** the soft heap limit is enforced
-** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
-** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
-** the soft heap limit is enforced on every memory allocation. Without
-** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
-** when memory is allocated by the page cache. Testing suggests that because
-** the page cache is the predominate memory user in SQLite, most
-** applications will achieve adequate soft heap limit enforcement without
-** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
-**
-** The circumstances under which SQLite will enforce the soft heap limit may
+** The circumstances under which SQLite will enforce the heap limits may
** changes in future releases of SQLite.
*/
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5817,11 +7515,13 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists. ^The sqlite3_table_column_metadata() interface returns
-** SQLITE_ERROR and if the specified column does not exist.
+** SQLITE_ERROR if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
-** does not.
+** does not. If the table name parameter T in a call to
+** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
+** undefined behavior.
**
** ^The column is identified by the second, third and fourth parameters to
** this function. ^(The second parameter is either the name of the database
@@ -5855,7 +7555,7 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
**
** ^If the specified table is actually a view, an [error code] is returned.
**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
** is not a [WITHOUT ROWID] table and an
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
** parameters are set for the explicitly declared column. ^(If there is no
@@ -5921,7 +7621,7 @@ SQLITE_API int sqlite3_table_column_metadata(
** prior to calling this API,
** otherwise an error will be returned.
**
-** <b>Security warning:</b> It is recommended that the
+** <b>Security warning:</b> It is recommended that the
** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
** interface. The use of the [sqlite3_enable_load_extension()] interface
** should be avoided. This will keep the SQL function [load_extension()]
@@ -5957,7 +7657,7 @@ SQLITE_API int sqlite3_load_extension(
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
-** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
+** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
@@ -6008,7 +7708,7 @@ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
** initialization routine X that was registered using a prior call to
** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
-** routine returns 1 if initialization routine X was successfully
+** routine returns 1 if initialization routine X was successfully
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
@@ -6043,8 +7743,8 @@ typedef struct sqlite3_module sqlite3_module;
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
**
-** This structure, sometimes called a "virtual table module",
-** defines the implementation of a [virtual tables].
+** This structure, sometimes called a "virtual table module",
+** defines the implementation of a [virtual table].
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
@@ -6083,11 +7783,14 @@ struct sqlite3_module {
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
- /* The methods above are in version 1 of the sqlite_module object. Those
+ /* 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);
+ /* The methods above are in versions 1 and 2 of the sqlite_module object.
+ ** Those below are for version 3 and greater. */
+ int (*xShadowName)(const char*);
};
/*
@@ -6130,7 +7833,7 @@ struct sqlite3_module {
** required by SQLite. If the table has at least 64 columns and any column
** to the right of the first 63 is required, then bit 63 of colUsed is also
** set. In other words, column iCol may be required if the expression
-** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
+** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
@@ -6138,7 +7841,13 @@ struct sqlite3_module {
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
-** virtual table and is not checked again by SQLite.)^
+** virtual table and might not be checked again by the byte code.)^ ^(The
+** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
+** is left in its default setting of false, the constraint will always be
+** checked separately in byte code. If the omit flag is change to true, then
+** the constraint may or may not be checked in byte code. In other words,
+** when the omit flag is true there is no guarantee that the constraint will
+** not be checked again using byte code.)^
**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
@@ -6151,17 +7860,17 @@ struct sqlite3_module {
**
** ^The estimatedCost value is an estimate of the cost of a particular
** strategy. A cost of N indicates that the cost of the strategy is similar
-** to a linear scan of an SQLite table with N rows. A cost of log(N)
+** to a linear scan of an SQLite table with N rows. A cost of log(N)
** indicates that the expense of the operation is similar to that of a
** binary search on a unique indexed field of an SQLite table with N rows.
**
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
-** The xBestIndex method may optionally populate the idxFlags field with a
+** The xBestIndex method may optionally populate the idxFlags field with a
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
+** assumes that the strategy may visit at most one row.
**
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as
@@ -6174,14 +7883,14 @@ struct sqlite3_module {
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
-** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
+** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
** If a virtual table extension is
-** used with an SQLite version earlier than 3.8.2, the results of attempting
-** to read or write the estimatedRows field are undefined (but are likely
-** to included crashing the application). The estimatedRows field should
+** used with an SQLite version earlier than 3.8.2, the results of attempting
+** to read or write the estimatedRows field are undefined (but are likely
+** to include crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
-** was added for [version 3.9.0] ([dateof:3.9.0]).
+** was added for [version 3.9.0] ([dateof:3.9.0]).
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
@@ -6220,26 +7929,36 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Virtual Table Scan Flags
+**
+** Virtual table implementations are allowed to set the
+** [sqlite3_index_info].idxFlags field to some combination of
+** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
-** These macros defined the allowed values for the
+** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-#define SQLITE_INDEX_CONSTRAINT_LIKE 65
-#define SQLITE_INDEX_CONSTRAINT_GLOB 66
-#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
+#define SQLITE_INDEX_CONSTRAINT_GT 4
+#define SQLITE_INDEX_CONSTRAINT_LE 8
+#define SQLITE_INDEX_CONSTRAINT_LT 16
+#define SQLITE_INDEX_CONSTRAINT_GE 32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
+#define SQLITE_INDEX_CONSTRAINT_LIKE 65
+#define SQLITE_INDEX_CONSTRAINT_GLOB 66
+#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
+#define SQLITE_INDEX_CONSTRAINT_NE 68
+#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
+#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
+#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
+#define SQLITE_INDEX_CONSTRAINT_IS 72
+#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -6251,7 +7970,7 @@ struct sqlite3_index_info {
** preexisting [virtual table] for the module.
**
** ^The module name is registered on the [database connection] specified
-** by the first parameter. ^The name of the module is given by the
+** by the first parameter. ^The name of the module is given by the
** second parameter. ^The third parameter is a pointer to
** the implementation of the [virtual table module]. ^The fourth
** parameter is an arbitrary client data pointer that is passed through
@@ -6266,6 +7985,12 @@ struct sqlite3_index_info {
** ^The sqlite3_create_module()
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
+**
+** ^If the third parameter (the pointer to the sqlite3_module object) is
+** NULL then no new module is create and any existing modules with the
+** same name are dropped.
+**
+** See also: [sqlite3_drop_modules()]
*/
SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
@@ -6282,6 +8007,23 @@ SQLITE_API int sqlite3_create_module_v2(
);
/*
+** CAPI3REF: Remove Unnecessary Virtual Table Implementations
+** METHOD: sqlite3
+**
+** ^The sqlite3_drop_modules(D,L) interface removes all virtual
+** table modules from database connection D except those named on list L.
+** The L parameter must be either NULL or a pointer to an array of pointers
+** to strings where the array is terminated by a single NULL pointer.
+** ^If the L parameter is NULL, then all virtual table modules are removed.
+**
+** See also: [sqlite3_create_module()]
+*/
+SQLITE_API int sqlite3_drop_modules(
+ sqlite3 *db, /* Remove modules from this connection */
+ const char **azKeep /* Except, do not remove the ones named here */
+);
+
+/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
**
@@ -6343,7 +8085,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** METHOD: sqlite3
**
** ^(Virtual tables can provide alternative implementations of functions
-** using the [xFindFunction] method of the [virtual table module].
+** using the [xFindFunction] method of the [virtual table module].
** But global versions of those functions
** must exist in order to be overloaded.)^
**
@@ -6394,7 +8136,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
-** ^(Parameter zDb is not the filename that contains the database, but
+** ^(Parameter zDb is not the filename that contains the database, but
** rather the symbolic name of the database. For attached databases, this is
** the name that appears after the AS keyword in the [ATTACH] statement.
** For the main database file, the database name is "main". For TEMP
@@ -6407,29 +8149,35 @@ typedef struct sqlite3_blob sqlite3_blob;
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
-** the API is not misused, it is always safe to call [sqlite3_blob_close()]
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
** on *ppBlob after this function it returns.
**
** This function fails with SQLITE_ERROR if any of the following are true:
** <ul>
-** <li> ^(Database zDb does not exist)^,
-** <li> ^(Table zTable does not exist within database zDb)^,
-** <li> ^(Table zTable is a WITHOUT ROWID table)^,
+** <li> ^(Database zDb does not exist)^,
+** <li> ^(Table zTable does not exist within database zDb)^,
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
** <li> ^(Column zColumn does not exist)^,
** <li> ^(Row iRow is not present in the table)^,
** <li> ^(The specified column of row iRow contains a value that is not
** a TEXT or BLOB value)^,
-** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
** constraint and the blob is being opened for read/write access)^,
-** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
** column zColumn is part of a [child key] definition and the blob is
** being opened for read/write access)^.
** </ul>
**
-** ^Unless it returns SQLITE_MISUSE, this function sets the
-** [database connection] error code and message accessible via
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+** ^Unless it returns SQLITE_MISUSE, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
+** A BLOB referenced by sqlite3_blob_open() may be read using the
+** [sqlite3_blob_read()] interface and modified by using
+** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a
+** different row of the same table using the [sqlite3_blob_reopen()]
+** interface. However, the column, table, or database of a [BLOB handle]
+** cannot be changed after the [BLOB handle] is opened.
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -6448,11 +8196,15 @@ typedef struct sqlite3_blob sqlite3_blob;
** blob.
**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function may be used to create a
+** and the built-in [zeroblob] SQL function may be used to create a
** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
+**
+** See also: [sqlite3_blob_close()],
+** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
+** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
*/
SQLITE_API int sqlite3_blob_open(
sqlite3*,
@@ -6468,11 +8220,11 @@ SQLITE_API int sqlite3_blob_open(
** CAPI3REF: Move a BLOB Handle to a New Row
** METHOD: sqlite3_blob
**
-** ^This function is used to move an existing blob handle so that it points
+** ^This function is used to move an existing [BLOB handle] so that it points
** to a different row of the same database table. ^The new row is identified
** by the rowid value passed as the second argument. Only the row can be
** changed. ^The database, table and column on which the blob handle is open
-** remain the same. Moving an existing blob handle to a new row can be
+** remain the same. Moving an existing [BLOB handle] to a new row is
** faster than closing the existing handle and opening a new one.
**
** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
@@ -6494,7 +8246,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** DESTRUCTOR: sqlite3_blob
**
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
-** unconditionally. Even if this routine returns an error code, the
+** unconditionally. Even if this routine returns an error code, the
** handle is still closed.)^
**
** ^If the blob handle being closed was opened for read-write access, and if
@@ -6504,10 +8256,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
-** with a null pointer (such as would be returned by a failed call to
+** open blob handle results in undefined behaviour. ^Calling this routine
+** with a null pointer (such as would be returned by a failed call to
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
-** is passed a valid open blob handle, the values returned by the
+** is passed a valid open blob handle, the values returned by the
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
@@ -6516,7 +8268,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
** CAPI3REF: Return The Size Of An Open BLOB
** METHOD: sqlite3_blob
**
-** ^Returns the size in bytes of the BLOB accessible via the
+** ^Returns the size in bytes of the BLOB accessible via the
** successfully opened [BLOB handle] in its only argument. ^The
** incremental blob I/O routines can only read or overwriting existing
** blob content; they cannot change the size of a blob.
@@ -6567,9 +8319,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
**
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
** Otherwise, an [error code] or an [extended error code] is returned.)^
-** ^Unless SQLITE_MISUSE is returned, this function sets the
-** [database connection] error code and message accessible via
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+** ^Unless SQLITE_MISUSE is returned, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
@@ -6578,9 +8330,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. The size of the
-** BLOB (and hence the maximum value of N+iOffset) can be determined
-** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
+** [SQLITE_ERROR] is returned and no data is written. The size of the
+** BLOB (and hence the maximum value of N+iOffset) can be determined
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
@@ -6674,7 +8426,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
@@ -6732,7 +8484,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable
+** sqlite3_mutex_try() as an optimization so this is acceptable
** behavior.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
@@ -6797,7 +8549,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
-** by this structure are not required to handle this case, the results
+** by this structure are not required to handle this case. The results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
@@ -6876,7 +8628,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
*/
#define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
-#define SQLITE_MUTEX_STATIC_MASTER 2
+#define SQLITE_MUTEX_STATIC_MAIN 2
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
@@ -6891,11 +8643,15 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
+/* Legacy compatibility: */
+#define SQLITE_MUTEX_STATIC_MASTER 2
+
+
/*
** CAPI3REF: Retrieve the mutex for a database connection
** METHOD: sqlite3
**
-** ^This interface returns a pointer the [sqlite3_mutex] object that
+** ^This interface returns a pointer the [sqlite3_mutex] object that
** serializes access to the [database connection] given in the argument
** when the [threading mode] is Serialized.
** ^If the [threading mode] is Single-thread or Multi-thread then this
@@ -6906,6 +8662,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
** METHOD: sqlite3
+** KEYWORDS: {file control}
**
** ^The [sqlite3_file_control()] interface makes a direct call to the
** xFileControl method for the [sqlite3_io_methods] object associated
@@ -6920,11 +8677,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** the xFileControl method. ^The return value of the xFileControl
** method becomes the return value of this routine.
**
-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** A few opcodes for [sqlite3_file_control()] are handled directly
+** by the SQLite core and never invoke the
+** sqlite3_io_methods.xFileControl method.
+** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
** a pointer to the underlying [sqlite3_file] object to be written into
-** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
-** case is a short-circuit path which does not actually invoke the
-** underlying sqlite3_io_methods.xFileControl method.
+** the space pointed to by the 4th parameter. The
+** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
+** the [sqlite3_file] object associated with the journal file instead of
+** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns
+** a pointer to the underlying [sqlite3_vfs] object for the file.
+** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
+** from the pager.
**
** ^If the second parameter (zDbName) does not match the name of any
** open database file, then SQLITE_ERROR is returned. ^This error
@@ -6934,7 +8698,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** an incorrect zDbName and an SQLITE_ERROR return from the underlying
** xFileControl method.
**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
+** See also: [file control opcodes]
*/
SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
@@ -6971,17 +8735,18 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_FIRST 5
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
-#define SQLITE_TESTCTRL_PRNG_RESET 7
+#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
#define SQLITE_TESTCTRL_PENDING_BYTE 11
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
-#define SQLITE_TESTCTRL_RESERVE 14
+#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
-#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
+#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -6991,7 +8756,194 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25
-#define SQLITE_TESTCTRL_LAST 25
+#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
+#define SQLITE_TESTCTRL_RESULT_INTREAL 27
+#define SQLITE_TESTCTRL_PRNG_SEED 28
+#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
+#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
+
+/*
+** CAPI3REF: SQL Keyword Checking
+**
+** These routines provide access to the set of SQL language keywords
+** recognized by SQLite. Applications can uses these routines to determine
+** whether or not a specific identifier needs to be escaped (for example,
+** by enclosing in double-quotes) so as not to confuse the parser.
+**
+** The sqlite3_keyword_count() interface returns the number of distinct
+** keywords understood by SQLite.
+**
+** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** makes *Z point to that keyword expressed as UTF8 and writes the number
+** of bytes in the keyword into *L. The string that *Z points to is not
+** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns
+** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z
+** or L are NULL or invalid pointers then calls to
+** sqlite3_keyword_name(N,Z,L) result in undefined behavior.
+**
+** The sqlite3_keyword_check(Z,L) interface checks to see whether or not
+** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero
+** if it is and zero if not.
+**
+** The parser used by SQLite is forgiving. It is often possible to use
+** a keyword as an identifier as long as such use does not result in a
+** parsing ambiguity. For example, the statement
+** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and
+** creates a new table named "BEGIN" with three columns named
+** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid
+** using keywords as identifiers. Common techniques used to avoid keyword
+** name collisions include:
+** <ul>
+** <li> Put all identifier names inside double-quotes. This is the official
+** SQL way to escape identifier names.
+** <li> Put identifier names inside &#91;...&#93;. This is not standard SQL,
+** but it is what SQL Server does and so lots of programmers use this
+** technique.
+** <li> Begin every identifier with the letter "Z" as no SQL keywords start
+** with "Z".
+** <li> Include a digit somewhere in every identifier name.
+** </ul>
+**
+** Note that the number of keywords understood by SQLite can depend on
+** compile-time options. For example, "VACUUM" is not a keyword if
+** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also,
+** new keywords may be added to future releases of SQLite.
+*/
+SQLITE_API int sqlite3_keyword_count(void);
+SQLITE_API int sqlite3_keyword_name(int,const char**,int*);
+SQLITE_API int sqlite3_keyword_check(const char*,int);
+
+/*
+** CAPI3REF: Dynamic String Object
+** KEYWORDS: {dynamic string}
+**
+** An instance of the sqlite3_str object contains a dynamically-sized
+** string under construction.
+**
+** The lifecycle of an sqlite3_str object is as follows:
+** <ol>
+** <li> ^The sqlite3_str object is created using [sqlite3_str_new()].
+** <li> ^Text is appended to the sqlite3_str object using various
+** methods, such as [sqlite3_str_appendf()].
+** <li> ^The sqlite3_str object is destroyed and the string it created
+** is returned using the [sqlite3_str_finish()] interface.
+** </ol>
+*/
+typedef struct sqlite3_str sqlite3_str;
+
+/*
+** CAPI3REF: Create A New Dynamic String Object
+** CONSTRUCTOR: sqlite3_str
+**
+** ^The [sqlite3_str_new(D)] interface allocates and initializes
+** a new [sqlite3_str] object. To avoid memory leaks, the object returned by
+** [sqlite3_str_new()] must be freed by a subsequent call to
+** [sqlite3_str_finish(X)].
+**
+** ^The [sqlite3_str_new(D)] interface always returns a pointer to a
+** valid [sqlite3_str] object, though in the event of an out-of-memory
+** error the returned object might be a special singleton that will
+** silently reject new text, always return SQLITE_NOMEM from
+** [sqlite3_str_errcode()], always return 0 for
+** [sqlite3_str_length()], and always return NULL from
+** [sqlite3_str_finish(X)]. It is always safe to use the value
+** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter
+** to any of the other [sqlite3_str] methods.
+**
+** The D parameter to [sqlite3_str_new(D)] may be NULL. If the
+** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum
+** length of the string contained in the [sqlite3_str] object will be
+** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead
+** of [SQLITE_MAX_LENGTH].
+*/
+SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*);
+
+/*
+** CAPI3REF: Finalize A Dynamic String
+** DESTRUCTOR: sqlite3_str
+**
+** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X
+** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()]
+** that contains the constructed string. The calling application should
+** pass the returned value to [sqlite3_free()] to avoid a memory leak.
+** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any
+** errors were encountered during construction of the string. ^The
+** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the
+** string in [sqlite3_str] object X is zero bytes long.
+*/
+SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
+
+/*
+** CAPI3REF: Add Content To A Dynamic String
+** METHOD: sqlite3_str
+**
+** These interfaces add content to an sqlite3_str object previously obtained
+** from [sqlite3_str_new()].
+**
+** ^The [sqlite3_str_appendf(X,F,...)] and
+** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf]
+** functionality of SQLite to append formatted text onto the end of
+** [sqlite3_str] object X.
+**
+** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S
+** onto the end of the [sqlite3_str] object X. N must be non-negative.
+** S must contain at least N non-zero bytes of content. To append a
+** zero-terminated string in its entirety, use the [sqlite3_str_appendall()]
+** method instead.
+**
+** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of
+** zero-terminated string S onto the end of [sqlite3_str] object X.
+**
+** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the
+** single-byte character C onto the end of [sqlite3_str] object X.
+** ^This method can be used, for example, to add whitespace indentation.
+**
+** ^The [sqlite3_str_reset(X)] method resets the string under construction
+** inside [sqlite3_str] object X back to zero bytes in length.
+**
+** These methods do not return a result code. ^If an error occurs, that fact
+** is recorded in the [sqlite3_str] object and can be recovered by a
+** subsequent call to [sqlite3_str_errcode(X)].
+*/
+SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...);
+SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list);
+SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N);
+SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn);
+SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C);
+SQLITE_API void sqlite3_str_reset(sqlite3_str*);
+
+/*
+** CAPI3REF: Status Of A Dynamic String
+** METHOD: sqlite3_str
+**
+** These interfaces return the current status of an [sqlite3_str] object.
+**
+** ^If any prior errors have occurred while constructing the dynamic string
+** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return
+** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns
+** [SQLITE_NOMEM] following any out-of-memory error, or
+** [SQLITE_TOOBIG] if the size of the dynamic string exceeds
+** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors.
+**
+** ^The [sqlite3_str_length(X)] method returns the current length, in bytes,
+** of the dynamic string under construction in [sqlite3_str] object X.
+** ^The length returned by [sqlite3_str_length(X)] does not include the
+** zero-termination byte.
+**
+** ^The [sqlite3_str_value(X)] method returns a pointer to the current
+** content of the dynamic string under construction in X. The value
+** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X
+** and might be freed or altered by any subsequent method on the same
+** [sqlite3_str] object. Applications must not used the pointer returned
+** [sqlite3_str_value(X)] after any subsequent method call on the same
+** object. ^Applications may change the content of the string returned
+** by [sqlite3_str_value(X)] as long as they do not write into any bytes
+** outside the range of 0 to [sqlite3_str_length(X)] and do not read or
+** write any byte after any subsequent sqlite3_str method call.
+*/
+SQLITE_API int sqlite3_str_errcode(sqlite3_str*);
+SQLITE_API int sqlite3_str_length(sqlite3_str*);
+SQLITE_API char *sqlite3_str_value(sqlite3_str*);
/*
** CAPI3REF: SQLite Runtime Status
@@ -7040,8 +8992,7 @@ SQLITE_API int sqlite3_status64(
** <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
-** and internal memory usage by the SQLite library. Scratch memory
-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
+** and internal memory usage by the SQLite library. Auxiliary page-cache
** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
** this parameter. The amount returned is the sum of the allocation
** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
@@ -7050,7 +9001,7 @@ SQLITE_API int sqlite3_status64(
** <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.
+** *pHighwater parameter to [sqlite3_status()] is of interest.
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
@@ -7059,11 +9010,11 @@ SQLITE_API int sqlite3_status64(
**
** [[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
+** [pagecache memory allocator] that was configured using
** [SQLITE_CONFIG_PAGECACHE]. The
** value returned is in pages, not in bytes.</dd>)^
**
-** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
+** [[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]
@@ -7075,36 +9026,21 @@ SQLITE_API int sqlite3_status64(
**
** [[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.
+** handed to the [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>)^
**
-** [[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
-** in bytes. Since a single thread may only have one scratch allocation
-** outstanding at time, this parameter also reports the number of threads
-** using scratch memory at the same time.</dd>)^
+** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** <dd>No longer used.</dd>
**
** [[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
-** returned include overflows because the requested allocation was too
-** larger (that is, because the requested allocation was larger than the
-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
-** slots were available.
-** </dd>)^
+** <dd>No longer used.</dd>
**
-** [[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>)^
+** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
-** <dd>The *pHighwater parameter records the deepest parser stack.
+** <dd>The *pHighwater parameter records the deepest parser stack.
** The *pCurrent value is undefined. The *pHighwater value is only
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
** </dl>
@@ -7114,24 +9050,24 @@ SQLITE_API int sqlite3_status64(
#define SQLITE_STATUS_MEMORY_USED 0
#define SQLITE_STATUS_PAGECACHE_USED 1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
-#define SQLITE_STATUS_SCRATCH_USED 3
-#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
+#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */
+#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */
#define SQLITE_STATUS_MALLOC_SIZE 5
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
-#define SQLITE_STATUS_SCRATCH_SIZE 8
+#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */
#define SQLITE_STATUS_MALLOC_COUNT 9
/*
** CAPI3REF: Database Connection Status
** METHOD: sqlite3
**
-** ^This interface is used to retrieve runtime status information
+** ^This interface is used to retrieve runtime status information
** 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 options], that
-** determines the parameter to interrogate. The set of
+** determines the parameter to interrogate. The set of
** [SQLITE_DBSTATUS options] is likely
** to grow in future releases of SQLite.
**
@@ -7166,7 +9102,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** checked out.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
-** <dd>This parameter returns the number malloc attempts that were
+** <dd>This parameter returns the number of malloc attempts that were
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
@@ -7191,7 +9127,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
-** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
+** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
** pager cache is shared between two or more connections the bytes of heap
@@ -7206,7 +9142,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
-** with the connection - main, temp, and any [ATTACH]-ed databases.)^
+** with the connection - main, temp, and any [ATTACH]-ed databases.)^
** ^The full amount of memory used by the schemas is reported, even if the
** schema memory is shared with other database connections due to
** [shared cache mode] being enabled.
@@ -7221,13 +9157,13 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
**
** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(<dt>SQLITE_DBSTATUS_CACHE_HIT</dt>
** <dd>This parameter returns the number of pager cache hits that have
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
** is always 0.
** </dd>
**
** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt>
** <dd>This parameter returns the number of pager cache misses that have
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
** is always 0.
** </dd>
**
@@ -7242,6 +9178,15 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
** </dd>
**
+** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
+** <dd>This parameter returns the number of dirty cache entries that have
+** been written to disk in the middle of a transaction due to the page
+** cache overflowing. Transactions are more efficient if they are written
+** to disk all at once. When pages spill mid-transaction, that introduces
+** additional overhead. This parameter can be used help identify
+** inefficiencies that can be resolved by increasing the cache size.
+** </dd>
+**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
** <dd>This parameter returns zero for the current value if and only if
** all foreign key constraints (deferred or immediate) have been
@@ -7261,7 +9206,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
#define SQLITE_DBSTATUS_CACHE_WRITE 9
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
-#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_SPILL 12
+#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */
/*
@@ -7275,7 +9221,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** statements. For example, if the number of table steps greatly exceeds
** the number of table searches or result rows, that would tend to indicate
** that the prepared statement is using a full table scan rather than
-** an index.
+** an index.
**
** ^(This interface is used to retrieve and reset counter values from
** a [prepared statement]. The first argument is the prepared statement
@@ -7302,7 +9248,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** [[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
+** may indicate opportunities for performance improvement through
** careful use of indices.</dd>
**
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
@@ -7320,10 +9266,28 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
** <dd>^This is the number of virtual machine operations executed
** by the prepared statement if that number is less than or equal
-** to 2147483647. The number of virtual machine operations can be
+** to 2147483647. The number of virtual machine operations can be
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
+**
+** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
+** <dd>^This is the number of times that the prepare statement has been
+** automatically regenerated due to schema changes or changes to
+** [bound parameters] that might affect the query plan.
+**
+** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
+** <dd>^This is the number of times that the prepared statement has
+** been run. A single "run" for the purposes of this counter is one
+** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
+** The counter is incremented on the first [sqlite3_step()] call of each
+** cycle.
+**
+** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
+** <dd>^This is the approximate number of bytes of heap memory
+** used to store the prepared statement. ^This value is not actually
+** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
+** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
** </dd>
** </dl>
*/
@@ -7331,6 +9295,9 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
#define SQLITE_STMTSTATUS_VM_STEP 4
+#define SQLITE_STMTSTATUS_REPREPARE 5
+#define SQLITE_STMTSTATUS_RUN 6
+#define SQLITE_STMTSTATUS_MEMUSED 99
/*
** CAPI3REF: Custom Page Cache Object
@@ -7366,15 +9333,15 @@ struct sqlite3_pcache_page {
** KEYWORDS: {page cache}
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
-** register an alternative page cache implementation by passing in an
+** register an alternative page cache implementation by passing in an
** instance of the sqlite3_pcache_methods2 structure.)^
-** In many applications, most of the heap memory allocated by
+** In many applications, most of the heap memory allocated by
** SQLite is used for the page cache.
-** By implementing a
+** By implementing a
** custom page cache using this API, an application can better control
-** the amount of memory consumed by SQLite, the way in which
-** that memory is allocated and released, and the policies used to
-** determine exactly which parts of a database file are cached and for
+** the amount of memory consumed by SQLite, the way in which
+** that memory is allocated and released, and the policies used to
+** determine exactly which parts of a database file are cached and for
** how long.
**
** The alternative page cache mechanism is an
@@ -7387,19 +9354,19 @@ struct sqlite3_pcache_page {
** [sqlite3_config()] returns.)^
**
** [[the xInit() page cache method]]
-** ^(The xInit() method is called once for each effective
+** ^(The xInit() method is called once for each effective
** call to [sqlite3_initialize()])^
** (usually only once during the lifetime of the process). ^(The xInit()
** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^
-** The intent of the xInit() method is to set up global data structures
-** required by the custom page cache implementation.
-** ^(If the xInit() method is NULL, then the
+** The intent of the xInit() method is to set up global data structures
+** required by the custom page cache implementation.
+** ^(If the xInit() method is NULL, then the
** 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
+** It can be used to clean up
** any outstanding resources before process shutdown, if required.
** ^The xShutdown() method may be NULL.
**
@@ -7418,7 +9385,7 @@ struct sqlite3_pcache_page {
** though this is not guaranteed. ^The
** first parameter, szPage, is the size in bytes of the pages that must
** be allocated by the cache. ^szPage will always a power of two. ^The
-** second parameter szExtra is a number of bytes of extra storage
+** second parameter szExtra is a number of bytes of extra storage
** associated with each page cache entry. ^The szExtra parameter will
** a number less than 250. SQLite will use the
** extra szExtra bytes on each page to store metadata about the underlying
@@ -7431,7 +9398,7 @@ struct sqlite3_pcache_page {
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
** never invoke xUnpin() except to deliberately delete a page.
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
-** false will always have the "discard" flag set to true.
+** false will always have the "discard" flag set to true.
** ^Hence, a cache created with bPurgeable false will
** never contain any unpinned pages.
**
@@ -7446,12 +9413,12 @@ struct sqlite3_pcache_page {
** [[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 xFetch() method locates a page in the cache and returns a pointer to
** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
** The pBuf element of the returned sqlite3_pcache_page object will be a
-** pointer to a buffer of szPage bytes used to store the content of a
+** pointer to a buffer of szPage bytes used to store the content of a
** single database page. The pExtra element of sqlite3_pcache_page will be
** a pointer to the szExtra bytes of extra storage that SQLite has requested
** for each entry in the page cache.
@@ -7477,7 +9444,7 @@ struct sqlite3_pcache_page {
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
-** failed.)^ In between the to xFetch() calls, SQLite may
+** failed.)^ In between the xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
@@ -7490,8 +9457,8 @@ struct sqlite3_pcache_page {
** page cache implementation. ^The page cache implementation
** may choose to evict unpinned pages at any time.
**
-** The cache must not perform any reference counting. A single
-** call to xUnpin() unpins the page regardless of the number of prior calls
+** The cache must not perform any reference counting. A single
+** call to xUnpin() unpins the page regardless of the number of prior calls
** to xFetch().
**
** [[the xRekey() page cache methods]]
@@ -7531,7 +9498,7 @@ struct sqlite3_pcache_methods2 {
int (*xPagecount)(sqlite3_pcache*);
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
- void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
+ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
unsigned oldKey, unsigned newKey);
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
void (*xDestroy)(sqlite3_pcache*);
@@ -7576,7 +9543,7 @@ typedef struct sqlite3_backup sqlite3_backup;
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
-** for copying in-memory databases to or from persistent files.
+** for copying in-memory databases to or from persistent files.
**
** See Also: [Using the SQLite Online Backup API]
**
@@ -7587,36 +9554,36 @@ typedef struct sqlite3_backup sqlite3_backup;
** ^Thus, the backup may be performed on a live source database without
** preventing other database connections from
** reading or writing to the source database while the backup is underway.
-**
-** ^(To perform a backup operation:
+**
+** ^(To perform a backup operation:
** <ol>
** <li><b>sqlite3_backup_init()</b> is called once to initialize the
-** backup,
-** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
+** backup,
+** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
** the data between the two databases, and finally
-** <li><b>sqlite3_backup_finish()</b> is called to release all resources
-** associated with the backup operation.
+** <li><b>sqlite3_backup_finish()</b> is called to release all resources
+** associated with the backup operation.
** </ol>)^
** There should be exactly one call to sqlite3_backup_finish() for each
** successful call to sqlite3_backup_init().
**
** [[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
+** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
+** [database connection] associated with the destination database
** and the database name, respectively.
** ^The database name is "main" for the main database, "temp" for the
** temporary database, or the name specified after the AS keyword in
** an [ATTACH] statement for an attached database.
-** ^The S and M arguments passed to
+** ^The S and M arguments passed to
** sqlite3_backup_init(D,N,S,M) identify the [database connection]
** and database name of the source database, respectively.
** ^The source and destination [database connections] (parameters S and D)
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
-** ^A call to sqlite3_backup_init() will fail, returning NULL, if
-** there is already a read or read-write transaction open on the
+** ^A call to sqlite3_backup_init() will fail, returning NULL, if
+** there is already a read or read-write transaction open on the
** destination database.
**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
@@ -7628,14 +9595,14 @@ typedef struct sqlite3_backup sqlite3_backup;
** ^A successful call to sqlite3_backup_init() returns a pointer to an
** [sqlite3_backup] object.
** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and
-** sqlite3_backup_finish() functions to perform the specified backup
+** sqlite3_backup_finish() functions to perform the specified backup
** operation.
**
** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
**
-** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
+** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
** the source and destination databases specified by [sqlite3_backup] object B.
-** ^If N is negative, all remaining source pages are copied.
+** ^If N is negative, all remaining source pages are copied.
** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
** are still more pages to be copied, then the function returns [SQLITE_OK].
** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
@@ -7657,8 +9624,8 @@ typedef struct sqlite3_backup sqlite3_backup;
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
-** is invoked (if one is specified). ^If the
-** busy-handler returns non-zero before the lock is available, then
+** is invoked (if one is specified). ^If the
+** busy-handler returns non-zero before the lock is available, then
** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
** sqlite3_backup_step() can be retried later. ^If the source
** [database connection]
@@ -7666,15 +9633,15 @@ typedef struct sqlite3_backup sqlite3_backup;
** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this
** case the call to sqlite3_backup_step() can be retried later on. ^(If
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or
-** [SQLITE_READONLY] is returned, then
-** there is no point in retrying the call to sqlite3_backup_step(). These
-** errors are considered fatal.)^ The application must accept
-** that the backup operation has failed and pass the backup operation handle
+** [SQLITE_READONLY] is returned, then
+** there is no point in retrying the call to sqlite3_backup_step(). These
+** errors are considered fatal.)^ The application must accept
+** that the backup operation has failed and pass the backup operation handle
** to the sqlite3_backup_finish() to release associated resources.
**
** ^The first call to sqlite3_backup_step() obtains an exclusive lock
-** on the destination file. ^The exclusive lock is not released until either
-** sqlite3_backup_finish() is called or the backup operation is complete
+** on the destination file. ^The exclusive lock is not released until either
+** sqlite3_backup_finish() is called or the backup operation is complete
** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to
** sqlite3_backup_step() obtains a [shared lock] on the source database that
** lasts for the duration of the sqlite3_backup_step() call.
@@ -7683,18 +9650,18 @@ typedef struct sqlite3_backup sqlite3_backup;
** through the backup process. ^If the source database is modified by an
** external process or via a database connection other than the one being
** used by the backup operation, then the backup will be automatically
-** restarted by the next call to sqlite3_backup_step(). ^If the source
+** restarted by the next call to sqlite3_backup_step(). ^If the source
** database is modified by the using the same database connection as is used
** by the backup operation, then the backup database is automatically
** updated at the same time.
**
** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
**
-** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
+** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
** application wishes to abandon the backup operation, the application
** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish().
** ^The sqlite3_backup_finish() interfaces releases all
-** resources associated with the [sqlite3_backup] object.
+** resources associated with the [sqlite3_backup] object.
** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any
** active write-transaction on the destination database is rolled back.
** The [sqlite3_backup] object is invalid
@@ -7734,8 +9701,8 @@ typedef struct sqlite3_backup sqlite3_backup;
** connections, then the source database connection may be used concurrently
** from within other threads.
**
-** However, the application must guarantee that the destination
-** [database connection] is not passed to any other API (by any thread) after
+** However, the application must guarantee that the destination
+** [database connection] is not passed to any other API (by any thread) after
** sqlite3_backup_init() is called and before the corresponding call to
** sqlite3_backup_finish(). SQLite does not currently check to see
** if the application incorrectly accesses the destination [database connection]
@@ -7746,11 +9713,11 @@ typedef struct sqlite3_backup sqlite3_backup;
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
** is not accessed while the backup is running. In practice this means
-** that the application must guarantee that the disk file being
+** that the application must guarantee that the disk file being
** backed up to is not accessed by any connection within the process,
** not just the specific connection that was passed to sqlite3_backup_init().
**
-** The [sqlite3_backup] object itself is partially threadsafe. Multiple
+** The [sqlite3_backup] object itself is partially threadsafe. Multiple
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
** APIs are not strictly speaking threadsafe. If they are invoked at the
@@ -7775,8 +9742,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
** individual tables within the shared-cache cannot be obtained. See
-** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
-** ^This API may be used to register a callback that SQLite will invoke
+** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
+** ^This API may be used to register a callback that SQLite will invoke
** when the connection currently holding the required lock relinquishes it.
** ^This API is only available if the library was compiled with the
** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined.
@@ -7784,18 +9751,18 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** See Also: [Using the SQLite Unlock Notification Feature].
**
** ^Shared-cache locks are released when a database connection concludes
-** its current transaction, either by committing it or rolling it back.
+** its current transaction, either by committing it or rolling it back.
**
** ^When a connection (known as the blocked connection) fails to obtain a
** shared-cache lock and SQLITE_LOCKED is returned to the caller, the
** identity of the database connection (the blocking connection) that
-** has locked the required resource is stored internally. ^After an
+** has locked the required resource is stored internally. ^After an
** application receives an SQLITE_LOCKED error, it may call the
-** sqlite3_unlock_notify() method with the blocked connection handle as
+** sqlite3_unlock_notify() method with the blocked connection handle as
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
-** call that concludes the blocking connections transaction.
+** call that concludes the blocking connection's transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
@@ -7805,15 +9772,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** ^If the blocked connection is attempting to obtain a write-lock on a
** shared-cache table, and more than one other connection currently holds
-** a read-lock on the same table, then SQLite arbitrarily selects one of
+** a read-lock on the same table, then SQLite arbitrarily selects one of
** the other connections to use as the blocking connection.
**
-** ^(There may be at most one unlock-notify callback registered by a
+** ^(There may be at most one unlock-notify callback registered by a
** blocked connection. If sqlite3_unlock_notify() is called when the
** blocked connection already has a registered unlock-notify callback,
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
** called with a NULL pointer as its second argument, then any existing
-** unlock-notify callback is canceled. ^The blocked connections
+** unlock-notify callback is canceled. ^The blocked connections
** unlock-notify callback may also be canceled by closing the blocked
** connection using [sqlite3_close()].
**
@@ -7826,25 +9793,25 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** <b>Callback Invocation Details</b>
**
-** When an unlock-notify callback is registered, the application provides a
+** When an unlock-notify callback is registered, the application provides a
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
-** When a blocking connections transaction is concluded, there may be
+** When a blocking connection's transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
-** This gives the application an opportunity to prioritize any actions
+** This gives the application an opportunity to prioritize any actions
** related to the set of unblocked database connections.
**
** <b>Deadlock Detection</b>
**
-** Assuming that after registering for an unlock-notify callback a
+** Assuming that after registering for an unlock-notify callback a
** database waits for the callback to be issued before taking any further
** action (a reasonable assumption), then using this API may cause the
** application to deadlock. For example, if connection X is waiting for
@@ -7867,7 +9834,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** <b>The "DROP TABLE" Exception</b>
**
-** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
+** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
** always appropriate to call sqlite3_unlock_notify(). There is however,
** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
** SQLite checks if there are any currently executing SELECT statements
@@ -7880,7 +9847,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** One way around this problem is to check the extended error code returned
** by an sqlite3_step() call. ^(If there is a blocking connection, then the
** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
-** the special "DROP TABLE/INDEX" case, the extended error code is just
+** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
SQLITE_API int sqlite3_unlock_notify(
@@ -7971,8 +9938,8 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** ^The [sqlite3_wal_hook()] function is used to register a callback that
** is invoked each time data is committed to a database in wal mode.
**
-** ^(The callback is invoked by SQLite after the commit has taken place and
-** the associated write-lock on the database released)^, so the implementation
+** ^(The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released)^, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
@@ -7991,7 +9958,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** that does not correspond to any valid SQLite error code, the results
** are undefined.
**
-** A single database handle may have at most a single write-ahead log callback
+** A single database handle may have at most a single write-ahead log callback
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
@@ -7999,7 +9966,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** overwrite any prior [sqlite3_wal_hook()] settings.
*/
SQLITE_API void *sqlite3_wal_hook(
- sqlite3*,
+ sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
);
@@ -8012,7 +9979,7 @@ SQLITE_API void *sqlite3_wal_hook(
** [sqlite3_wal_hook()] that causes any database on [database connection] D
** to automatically [checkpoint]
** after committing a transaction if there are N or
-** more frames in the [write-ahead log] file. ^Passing zero or
+** more frames in the [write-ahead log] file. ^Passing zero or
** a negative value as the nFrame parameter disables automatic
** checkpoints entirely.
**
@@ -8042,7 +10009,7 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
**
-** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
** [write-ahead log] for database X on [database connection] D to be
** transferred into the database file and for the write-ahead log to
** be reset. See the [checkpointing] documentation for addition
@@ -8068,10 +10035,10 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
**
** <dl>
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
-** ^Checkpoint as many frames as possible without waiting for any database
-** readers or writers to finish, then sync the database file if all frames
+** ^Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish, then sync the database file if all frames
** in the log were checkpointed. ^The [busy-handler callback]
-** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
** ^On the other hand, passive mode might leave the checkpoint unfinished
** if there are concurrent readers or writers.
**
@@ -8085,9 +10052,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
-** that after checkpointing the log file it blocks (calls the
+** that after checkpointing the log file it blocks (calls the
** [busy-handler callback])
-** until all readers are reading from the database file only. ^This ensures
+** until all readers are reading from the database file only. ^This ensures
** that the next writer will restart the log file from the beginning.
** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
** database writer attempts while it is pending, but does not impede readers.
@@ -8109,31 +10076,31 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
**
** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
-** any other process is running a checkpoint operation at the same time, the
-** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
+** any other process is running a checkpoint operation at the same time, the
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
** busy-handler configured, it will not be invoked in this case.
**
-** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
** exclusive "writer" lock on the database file. ^If the writer lock cannot be
** obtained immediately, and a busy-handler is configured, it is invoked and
** the writer lock retried until either the busy-handler returns 0 or the lock
** is successfully obtained. ^The busy-handler is also invoked while waiting for
** database readers as described above. ^If the busy-handler returns 0 before
** the writer lock is obtained or while waiting for database readers, the
-** checkpoint operation proceeds from that point in the same way as
-** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
+** checkpoint operation proceeds from that point in the same way as
+** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
** without blocking any further. ^SQLITE_BUSY is returned in this case.
**
** ^If parameter zDb is NULL or points to a zero length string, then the
-** specified operation is attempted on all WAL databases [attached] to
+** specified operation is attempted on all WAL databases [attached] to
** [database connection] db. In this case the
-** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
-** an SQLITE_BUSY error is encountered when processing one or more of the
-** attached WAL databases, the operation is still attempted on any remaining
-** attached databases and SQLITE_BUSY is returned at the end. ^If any other
-** error occurs while processing an attached database, processing is abandoned
-** and the error code is returned to the caller immediately. ^If no error
-** (SQLITE_BUSY or otherwise) is encountered while processing the attached
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
+** an SQLITE_BUSY error is encountered when processing one or more of the
+** attached WAL databases, the operation is still attempted on any remaining
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
+** error occurs while processing an attached database, processing is abandoned
+** and the error code is returned to the caller immediately. ^If no error
+** (SQLITE_BUSY or otherwise) is encountered while processing the attached
** databases, SQLITE_OK is returned.
**
** ^If database zDb is the name of an attached database that is not in WAL
@@ -8181,21 +10148,28 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** 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.
+** In the call sqlite3_vtab_config(D,C,...) the D parameter is the
+** [database connection] in which the virtual table is being created and
+** which is passed in as the first argument to the [xConnect] or [xCreate]
+** method that is invoking sqlite3_vtab_config(). The C parameter is one
+** of the [virtual table configuration options]. The presence and meaning
+** of parameters after C depend on which [virtual table configuration option]
+** is used.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
+** KEYWORDS: {virtual table configuration options}
+** KEYWORDS: {virtual table configuration option}
**
** 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
+** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
+** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT</dt>
** <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
@@ -8209,24 +10183,46 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** 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
+** 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.
+** 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
+** 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
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
** constraint handling.
+** </dd>
+**
+** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** prohibits that virtual table from being used from within triggers and
+** views.
+** </dd>
+**
+** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** identify that virtual table as being safe to use from within triggers
+** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
+** virtual table can do no serious harm even if it is controlled by a
+** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
+** flag unless absolutely necessary.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+#define SQLITE_VTAB_INNOCUOUS 2
+#define SQLITE_VTAB_DIRECTONLY 3
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -8241,6 +10237,40 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
+** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
+**
+** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
+** method of a [virtual table], then it returns true if and only if the
+** column is being fetched as part of an UPDATE operation during which the
+** column value will not change. Applications might use this to substitute
+** a return value that is less expensive to compute and that the corresponding
+** [xUpdate] method understands as a "no-change" value.
+**
+** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
+** the column is not changed by the UPDATE statement, then the xColumn
+** method can optionally return without setting a result, without calling
+** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
+** In that case, [sqlite3_value_nochange(X)] will return true for the
+** same column in the [xUpdate] method.
+*/
+SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
+
+/*
+** CAPI3REF: Determine The Collation For a Virtual Table Constraint
+**
+** This function may only be called from within a call to the [xBestIndex]
+** method of a [virtual table].
+**
+** The first argument must be the sqlite3_index_info object that is the
+** first parameter to the xBestIndex() method. The second argument must be
+** an index into the aConstraint[] array belonging to the sqlite3_index_info
+** structure passed to xBestIndex. This function returns a pointer to a buffer
+** containing the name of the collation sequence for the corresponding
+** constraint.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
+
+/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
**
@@ -8272,15 +10302,15 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
-** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
+** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
-** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
+** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.</dd>
**
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
-** <dd>^The "double" variable pointed to by the T parameter will be set to the
+** <dd>^The "double" variable pointed to by the V parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop. If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
@@ -8288,17 +10318,17 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
-** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
-** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
-** <dd>^The "int" variable pointed to by the T parameter will be set to the
+** <dd>^The "int" variable pointed to by the V parameter will be set to the
** "select-id" for the X-th loop. The select-id identifies which query or
** subquery the loop is part of. The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
@@ -8348,7 +10378,7 @@ SQLITE_API int sqlite3_stmt_scanstatus(
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
-);
+);
/*
** CAPI3REF: Zero Scan-Status Counters
@@ -8366,15 +10396,15 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
**
** ^If a write-transaction is open on [database connection] D when the
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
-** pages in the pager-cache that are not currently in use are written out
+** pages in the pager-cache that are not currently in use are written out
** to disk. A dirty page may be in use if a database cursor created by an
** active SQL statement is reading from it, or if it is page 1 of a database
** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
** interface flushes caches for all schemas - "main", "temp", and
** any [attached] databases.
**
-** ^If this function needs to obtain extra database locks before dirty pages
-** can be flushed to disk, it does so. ^If those locks cannot be obtained
+** ^If this function needs to obtain extra database locks before dirty pages
+** can be flushed to disk, it does so. ^If those locks cannot be obtained
** immediately and there is a busy-handler callback configured, it is invoked
** in the usual manner. ^If the required lock still cannot be obtained, then
** the database is skipped and an attempt made to flush any dirty pages
@@ -8401,7 +10431,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
**
** ^The [sqlite3_preupdate_hook()] interface registers a callback function
** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
-** on a [rowid table].
+** on a database table.
** ^At most one preupdate hook may be registered at a time on a single
** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
** the previous setting.
@@ -8410,9 +10440,9 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
** the first parameter to callbacks.
**
-** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
-** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
-** tables.
+** ^The preupdate hook only fires for changes to real database tables; the
+** preupdate hook is not invoked for changes to [virtual tables] or to
+** system tables like sqlite_sequence or sqlite_stat1.
**
** ^The second parameter to the preupdate callback is a pointer to
** the [database connection] that registered the preupdate hook.
@@ -8421,17 +10451,21 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** kind of update operation that is about to occur.
** ^(The fourth parameter to the preupdate callback is the name of the
** database within the database connection that is being modified. This
-** will be "main" for the main database or "temp" for TEMP tables or
+** will be "main" for the main database or "temp" for TEMP tables or
** the name given after the AS keyword in the [ATTACH] statement for attached
** databases.)^
** ^The fifth parameter to the preupdate callback is the name of the
** table that is being modified.
-** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
-** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
-** undefined for SQLITE_INSERT changes.
-** ^The seventh parameter to the preupdate callback is the final [rowid] of
-** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
-** undefined for SQLITE_DELETE changes.
+**
+** For an UPDATE or DELETE operation on a [rowid table], the sixth
+** parameter passed to the preupdate callback is the initial [rowid] of the
+** row being modified or deleted. For an INSERT operation on a rowid table,
+** or any operation on a WITHOUT ROWID table, the value of the sixth
+** parameter is undefined. For an INSERT or UPDATE on a rowid table the
+** seventh parameter is the final rowid value of the row being inserted
+** or updated. The value of the seventh parameter passed to the callback
+** function is not defined for operations on WITHOUT ROWID tables, or for
+** INSERT operations on rowid tables.
**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
@@ -8465,13 +10499,14 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
**
** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
** callback was invoked as a result of a direct insert, update, or delete
-** operation; or 1 for inserts, updates, or deletes invoked by top-level
+** operation; or 1 for inserts, updates, or deletes invoked by top-level
** triggers; or 2 for changes resulting from triggers called by top-level
** triggers; and so forth.
**
** See also: [sqlite3_update_hook()]
*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
+#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+SQLITE_API void *sqlite3_preupdate_hook(
sqlite3 *db,
void(*xPreUpdate)(
void *pCtx, /* Copy of third arg to preupdate_hook() */
@@ -8484,10 +10519,11 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
),
void*
);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
+SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
+SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
+#endif
/*
** CAPI3REF: Low-level system error code
@@ -8497,14 +10533,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3
** The return value is OS-dependent. For example, on unix systems, after
** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
** called to get back the underlying "errno" that caused the problem, such
-** as ENOSPC, EAUTH, EISDIR, and so forth.
+** as ENOSPC, EAUTH, EISDIR, and so forth.
*/
SQLITE_API int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Database Snapshot
-** KEYWORDS: {snapshot}
-** EXPERIMENTAL
+** KEYWORDS: {snapshot} {sqlite3_snapshot}
**
** An instance of the snapshot object records the state of a [WAL mode]
** database for some specific point in history.
@@ -8521,33 +10556,53 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
** version of the database file so that it is possible to later open a new read
** transaction that sees that historical version of the database rather than
** the most recent version.
-**
-** The constructor for this object is [sqlite3_snapshot_get()]. The
-** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
-** to an historical snapshot (if possible). The destructor for
-** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
*/
-typedef struct sqlite3_snapshot sqlite3_snapshot;
+typedef struct sqlite3_snapshot {
+ unsigned char hidden[48];
+} sqlite3_snapshot;
/*
** CAPI3REF: Record A Database Snapshot
-** EXPERIMENTAL
+** CONSTRUCTOR: sqlite3_snapshot
**
** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
** new [sqlite3_snapshot] object that records the current state of
** schema S in database connection D. ^On success, the
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
-** ^If schema S of [database connection] D is not a [WAL mode] database
-** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
-** leaves the *P value unchanged and returns an appropriate [error code].
+** If there is not already a read-transaction open on schema S when
+** this function is called, one is opened automatically.
+**
+** The following must be true for this function to succeed. If any of
+** the following statements are false when sqlite3_snapshot_get() is
+** called, SQLITE_ERROR is returned. The final value of *P is undefined
+** in this case.
+**
+** <ul>
+** <li> The database handle must not be in [autocommit mode].
+**
+** <li> Schema S of [database connection] D must be a [WAL mode] database.
+**
+** <li> There must not be a write transaction open on schema S of database
+** connection D.
+**
+** <li> One or more transactions must have been written to the current wal
+** file since it was created on disk (by any connection). This means
+** that a snapshot cannot be taken on a wal mode database with no wal
+** file immediately after it is first opened. At least one transaction
+** must be written to it first.
+** </ul>
+**
+** This function may also return SQLITE_NOMEM. If it is called with the
+** database handle in autocommit mode but fails for some other reason,
+** whether or not a read transaction is opened on schema S is undefined.
**
** The [sqlite3_snapshot] object returned from a successful call to
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
** to avoid a memory leak.
**
** The [sqlite3_snapshot_get()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
sqlite3 *db,
@@ -8557,35 +10612,46 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
/*
** CAPI3REF: Start a read transaction on an historical snapshot
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
+**
+** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
+** transaction or upgrades an existing one for schema S of
+** [database connection] D such that the read transaction refers to
+** historical [snapshot] P, rather than the most recent change to the
+** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
+** on success or an appropriate [error code] if it fails.
+**
+** ^In order to succeed, the database connection must not be in
+** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
+** is already a read transaction open on schema S, then the database handle
+** must have no active statements (SELECT statements that have been passed
+** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
+** SQLITE_ERROR is returned if either of these conditions is violated, or
+** if schema S does not exist, or if the snapshot object is invalid.
+**
+** ^A call to sqlite3_snapshot_open() will fail to open if the specified
+** snapshot has been overwritten by a [checkpoint]. In this case
+** SQLITE_ERROR_SNAPSHOT is returned.
+**
+** If there is already a read transaction open when this function is
+** invoked, then the same read transaction remains open (on the same
+** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
+** is returned. If another error code - for example SQLITE_PROTOCOL or an
+** SQLITE_IOERR error code - is returned, then the final state of the
+** read transaction is undefined. If SQLITE_OK is returned, then the
+** read transaction is now open on database snapshot P.
**
-** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
-** read transaction for schema S of
-** [database connection] D such that the read transaction
-** refers to historical [snapshot] P, rather than the most
-** recent change to the database.
-** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
-** or an appropriate [error code] if it fails.
-**
-** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
-** the first operation following the [BEGIN] that takes the schema S
-** out of [autocommit mode].
-** ^In other words, schema S must not currently be in
-** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
-** database connection D must be out of [autocommit mode].
-** ^A [snapshot] will fail to open if it has been overwritten by a
-** [checkpoint].
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
** database connection D does not know that the database file for
** schema S is in [WAL mode]. A database connection might not know
** that the database file is in [WAL mode] if there has been no prior
-** I/O on that database connection, or if the database entered [WAL mode]
+** I/O on that database connection, or if the database entered [WAL mode]
** after the most recent I/O on the database connection.)^
** (Hint: Run "[PRAGMA application_id]" against a newly opened
** database connection in order to make it ready to use snapshots.)
**
** The [sqlite3_snapshot_open()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
sqlite3 *db,
@@ -8595,38 +10661,41 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
/*
** CAPI3REF: Destroy a snapshot
-** EXPERIMENTAL
+** DESTRUCTOR: sqlite3_snapshot
**
** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
** The application must eventually free every [sqlite3_snapshot] object
** using this routine to avoid a memory leak.
**
** The [sqlite3_snapshot_free()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
/*
** CAPI3REF: Compare the ages of two snapshot handles.
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
**
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
-** of two valid snapshot handles.
+** of two valid snapshot handles.
**
-** If the two snapshot handles are not associated with the same database
-** file, the result of the comparison is undefined.
+** If the two snapshot handles are not associated with the same database
+** file, the result of the comparison is undefined.
**
** Additionally, the result of the comparison is only valid if both of the
** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
** last time the wal file was deleted. The wal file is deleted when the
** database is changed back to rollback mode or when the number of database
-** clients drops to zero. If either snapshot handle was obtained before the
-** wal file was last deleted, the value returned by this function
+** clients drops to zero. If either snapshot handle was obtained before the
+** wal file was last deleted, the value returned by this function
** is undefined.
**
** Otherwise, this API returns a negative value if P1 refers to an older
** snapshot than P2, zero if the two handles refer to the same database
** snapshot, and a positive value if P1 is a newer snapshot than P2.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
sqlite3_snapshot *p1,
@@ -8634,6 +10703,153 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
);
/*
+** CAPI3REF: Recover snapshots from a wal file
+** METHOD: sqlite3_snapshot
+**
+** If a [WAL file] remains on disk after all database connections close
+** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control]
+** or because the last process to have the database opened exited without
+** calling [sqlite3_close()]) and a new connection is subsequently opened
+** on that database and [WAL file], the [sqlite3_snapshot_open()] interface
+** will only be able to open the last transaction added to the WAL file
+** even though the WAL file contains other valid transactions.
+**
+** This function attempts to scan the WAL file associated with database zDb
+** of database handle db and make all valid snapshots available to
+** sqlite3_snapshot_open(). It is an error if there is already a read
+** transaction open on the database, or if the database is not a WAL mode
+** database.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
+
+/*
+** CAPI3REF: Serialize a database
+**
+** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
+** that is a serialization of the S database on [database connection] D.
+** If P is not a NULL pointer, then the size of the database in bytes
+** is written into *P.
+**
+** For an ordinary on-disk database file, the serialization is just a
+** copy of the disk file. For an in-memory database or a "TEMP" database,
+** the serialization is the same sequence of bytes which would be written
+** to disk if that database where backed up to disk.
+**
+** The usual case is that sqlite3_serialize() copies the serialization of
+** the database into memory obtained from [sqlite3_malloc64()] and returns
+** a pointer to that memory. The caller is responsible for freeing the
+** returned value to avoid a memory leak. However, if the F argument
+** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
+** are made, and the sqlite3_serialize() function will return a pointer
+** to the contiguous memory representation of the database that SQLite
+** is currently using for that database, or NULL if the no such contiguous
+** memory representation of the database exists. A contiguous memory
+** representation of the database will usually only exist if there has
+** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
+** values of D and S.
+** The size of the database is written into *P even if the
+** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
+** of the database exists.
+**
+** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
+** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
+** allocation error occurs.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_DESERIALIZE] option.
+*/
+SQLITE_API unsigned char *sqlite3_serialize(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */
+ sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */
+ unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_serialize
+**
+** Zero or more of the following constants can be OR-ed together for
+** the F argument to [sqlite3_serialize(D,S,P,F)].
+**
+** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return
+** a pointer to contiguous in-memory database that it is currently using,
+** without making a copy of the database. If SQLite is not currently using
+** a contiguous in-memory database, then this option causes
+** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be
+** using a contiguous in-memory database if it has been initialized by a
+** prior call to [sqlite3_deserialize()].
+*/
+#define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */
+
+/*
+** CAPI3REF: Deserialize a database
+**
+** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
+** [database connection] D to disconnect from database S and then
+** reopen S as an in-memory database based on the serialization contained
+** in P. The serialized database P is N bytes in size. M is the size of
+** the buffer P, which might be larger than N. If M is larger than N, and
+** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is
+** permitted to add content to the in-memory database as long as the total
+** size does not exceed M bytes.
+**
+** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will
+** invoke sqlite3_free() on the serialization buffer when the database
+** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then
+** SQLite will try to increase the buffer size using sqlite3_realloc64()
+** if writes on the database cause it to grow larger than M bytes.
+**
+** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
+** database is currently in a read transaction or is involved in a backup
+** operation.
+**
+** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
+** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
+** [sqlite3_free()] is invoked on argument P prior to returning.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_DESERIALIZE] option.
+*/
+SQLITE_API int sqlite3_deserialize(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which DB to reopen with the deserialization */
+ unsigned char *pData, /* The serialized database content */
+ sqlite3_int64 szDb, /* Number bytes in the deserialization */
+ sqlite3_int64 szBuf, /* Total size of buffer pData[] */
+ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_deserialize()
+**
+** The following are allowed values for 6th argument (the F argument) to
+** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
+**
+** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
+** in the P argument is held in memory obtained from [sqlite3_malloc64()]
+** and that SQLite should take ownership of this memory and automatically
+** free it when it has finished using it. Without this flag, the caller
+** is responsible for freeing any dynamically allocated memory.
+**
+** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
+** grow the size of the database using calls to [sqlite3_realloc64()]. This
+** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used.
+** Without this flag, the deserialized database cannot increase in size beyond
+** the number of bytes specified by the M parameter.
+**
+** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database
+** should be treated as read-only.
+*/
+#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */
+#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */
+#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */
+
+/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
@@ -8707,7 +10923,7 @@ struct sqlite3_rtree_geometry {
};
/*
-** Register a 2nd-generation geometry callback named zScore that can be
+** Register a 2nd-generation geometry callback named zScore that can be
** used as part of an R-Tree geometry query as follows:
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
@@ -8722,7 +10938,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
/*
-** A pointer to a structure of the following type is passed as the
+** A pointer to a structure of the following type is passed as the
** argument to scored geometry callback registered using
** sqlite3_rtree_query_callback().
**
@@ -8744,7 +10960,7 @@ struct sqlite3_rtree_query_info {
sqlite3_int64 iRowid; /* Rowid for current entry */
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
int eParentWithin; /* Visibility of parent node */
- int eWithin; /* OUT: Visiblity */
+ int eWithin; /* OUT: Visibility */
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
/* The following fields are only available in 3.8.11 and later */
sqlite3_value **apSqlParam; /* Original SQL values of parameters */
@@ -8780,16 +10996,23 @@ extern "C" {
/*
** CAPI3REF: Session Object Handle
+**
+** An instance of this object is a [session] that can be used to
+** record changes to a database.
*/
typedef struct sqlite3_session sqlite3_session;
/*
** CAPI3REF: Changeset Iterator Handle
+**
+** An instance of this object acts as a cursor for iterating
+** over the elements of a [changeset] or [patchset].
*/
typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
/*
** CAPI3REF: Create A New Session Object
+** CONSTRUCTOR: sqlite3_session
**
** Create a new session object attached to database handle db. If successful,
** a pointer to the new object is written to *ppSession and SQLITE_OK is
@@ -8810,7 +11033,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
** is not possible for an application to register a pre-update hook on a
** database handle that has one or more session objects attached. Nor is
** it possible to create a session object attached to a database handle for
-** which a pre-update hook is already defined. The results of attempting
+** which a pre-update hook is already defined. The results of attempting
** either of these things are undefined.
**
** The session object will be used to create changesets for tables in
@@ -8818,7 +11041,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
** attached database. It is not an error if database zDb is not attached
** to the database when the session object is created.
*/
-int sqlite3session_create(
+SQLITE_API int sqlite3session_create(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of db (e.g. "main") */
sqlite3_session **ppSession /* OUT: New session object */
@@ -8826,21 +11049,23 @@ int sqlite3session_create(
/*
** CAPI3REF: Delete A Session Object
+** DESTRUCTOR: sqlite3_session
**
-** Delete a session object previously allocated using
+** Delete a session object previously allocated using
** [sqlite3session_create()]. Once a session object has been deleted, the
** results of attempting to use pSession with any other session module
** function are undefined.
**
** Session objects must be deleted before the database handle to which they
-** are attached is closed. Refer to the documentation for
+** are attached is closed. Refer to the documentation for
** [sqlite3session_create()] for details.
*/
-void sqlite3session_delete(sqlite3_session *pSession);
+SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
** CAPI3REF: Enable Or Disable A Session Object
+** METHOD: sqlite3_session
**
** Enable or disable the recording of changes by a session object. When
** enabled, a session object records changes made to the database. When
@@ -8850,16 +11075,17 @@ void sqlite3session_delete(sqlite3_session *pSession);
** the eventual changesets.
**
** Passing zero to this function disables the session. Passing a value
-** greater than zero enables it. Passing a value less than zero is a
+** greater than zero enables it. Passing a value less than zero is a
** no-op, and may be used to query the current state of the session.
**
-** The return value indicates the final state of the session object: 0 if
+** The return value indicates the final state of the session object: 0 if
** the session is disabled, or 1 if it is enabled.
*/
-int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
+SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
/*
** CAPI3REF: Set Or Clear the Indirect Change Flag
+** METHOD: sqlite3_session
**
** Each change recorded by a session object is marked as either direct or
** indirect. A change is marked as indirect if either:
@@ -8867,7 +11093,7 @@ int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
** <ul>
** <li> The session object "indirect" flag is set when the change is
** made, or
-** <li> The change is made by an SQL trigger or foreign key action
+** <li> The change is made by an SQL trigger or foreign key action
** instead of directly as a result of a users SQL statement.
** </ul>
**
@@ -8879,32 +11105,33 @@ int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
** flag. If the second argument passed to this function is zero, then the
** indirect flag is cleared. If it is greater than zero, the indirect flag
** is set. Passing a value less than zero does not modify the current value
-** of the indirect flag, and may be used to query the current state of the
+** of the indirect flag, and may be used to query the current state of the
** indirect flag for the specified session object.
**
-** The return value indicates the final state of the indirect flag: 0 if
+** The return value indicates the final state of the indirect flag: 0 if
** it is clear, or 1 if it is set.
*/
-int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
+SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
/*
** CAPI3REF: Attach A Table To A Session Object
+** METHOD: sqlite3_session
**
** If argument zTab is not NULL, then it is the name of a table to attach
-** to the session object passed as the first argument. All subsequent changes
-** made to the table while the session object is enabled will be recorded. See
+** to the session object passed as the first argument. All subsequent changes
+** made to the table while the session object is enabled will be recorded. See
** documentation for [sqlite3session_changeset()] for further details.
**
** Or, if argument zTab is NULL, then changes are recorded for all tables
-** in the database. If additional tables are added to the database (by
-** executing "CREATE TABLE" statements) after this call is made, changes for
+** in the database. If additional tables are added to the database (by
+** executing "CREATE TABLE" statements) after this call is made, changes for
** the new tables are also recorded.
**
** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
-** defined as part of their CREATE TABLE statement. It does not matter if the
+** defined as part of their CREATE TABLE statement. It does not matter if the
** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
** KEY may consist of a single column, or may be a composite key.
-**
+**
** It is not an error if the named table does not exist in the database. Nor
** is it an error if the named table does not have a PRIMARY KEY. However,
** no changes will be recorded in either of these scenarios.
@@ -8912,24 +11139,54 @@ int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
** Changes are not recorded for individual rows that have NULL values stored
** in one or more of their PRIMARY KEY columns.
**
-** SQLITE_OK is returned if the call completes without error. Or, if an error
+** SQLITE_OK is returned if the call completes without error. Or, if an error
** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
+**
+** <h3>Special sqlite_stat1 Handling</h3>
+**
+** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to
+** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
+** <pre>
+** &nbsp; CREATE TABLE sqlite_stat1(tbl,idx,stat)
+** </pre>
+**
+** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are
+** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes
+** are recorded for rows for which (idx IS NULL) is true. However, for such
+** rows a zero-length blob (SQL value X'') is stored in the changeset or
+** patchset instead of a NULL value. This allows such changesets to be
+** manipulated by legacy implementations of sqlite3changeset_invert(),
+** concat() and similar.
+**
+** The sqlite3changeset_apply() function automatically converts the
+** zero-length blob back to a NULL value when updating the sqlite_stat1
+** table. However, if the application calls sqlite3changeset_new(),
+** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset
+** iterator directly (including on a changeset iterator passed to a
+** conflict-handler callback) then the X'' value is returned. The application
+** must translate X'' to NULL itself if required.
+**
+** Legacy (older than 3.22.0) versions of the sessions module cannot capture
+** changes made to the sqlite_stat1 table. Legacy versions of the
+** sqlite3changeset_apply() function silently ignore any modifications to the
+** sqlite_stat1 table that are part of a changeset or patchset.
*/
-int sqlite3session_attach(
+SQLITE_API int sqlite3session_attach(
sqlite3_session *pSession, /* Session object */
const char *zTab /* Table name */
);
/*
** CAPI3REF: Set a table filter on a Session Object.
+** METHOD: sqlite3_session
**
-** The second argument (xFilter) is the "filter callback". For changes to rows
+** The second argument (xFilter) is the "filter callback". For changes to rows
** in tables that are not attached to the Session object, the filter is called
-** to determine whether changes to the table's rows should be tracked or not.
-** If xFilter returns 0, changes is not tracked. Note that once a table is
+** to determine whether changes to the table's rows should be tracked or not.
+** If xFilter returns 0, changes are not tracked. Note that once a table is
** attached, xFilter will not be called again.
*/
-void sqlite3session_table_filter(
+SQLITE_API void sqlite3session_table_filter(
sqlite3_session *pSession, /* Session object */
int(*xFilter)(
void *pCtx, /* Copy of third arg to _filter_table() */
@@ -8940,10 +11197,11 @@ void sqlite3session_table_filter(
/*
** CAPI3REF: Generate A Changeset From A Session Object
+** METHOD: sqlite3_session
**
-** Obtain a changeset containing changes to the tables attached to the
-** session object passed as the first argument. If successful,
-** set *ppChangeset to point to a buffer containing the changeset
+** Obtain a changeset containing changes to the tables attached to the
+** session object passed as the first argument. If successful,
+** set *ppChangeset to point to a buffer containing the changeset
** and *pnChangeset to the size of the changeset in bytes before returning
** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
** zero and return an SQLite error code.
@@ -8958,7 +11216,7 @@ void sqlite3session_table_filter(
** modifies the values of primary key columns. If such a change is made, it
** is represented in a changeset as a DELETE followed by an INSERT.
**
-** Changes are not recorded for rows that have NULL values stored in one or
+** Changes are not recorded for rows that have NULL values stored in one or
** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
** no corresponding change is present in the changesets returned by this
** function. If an existing row with one or more NULL values stored in
@@ -9011,14 +11269,14 @@ void sqlite3session_table_filter(
** <ul>
** <li> For each record generated by an insert, the database is queried
** for a row with a matching primary key. If one is found, an INSERT
-** change is added to the changeset. If no such row is found, no change
+** change is added to the changeset. If no such row is found, no change
** is added to the changeset.
**
-** <li> For each record generated by an update or delete, the database is
+** <li> For each record generated by an update or delete, the database is
** queried for a row with a matching primary key. If such a row is
** found and one or more of the non-primary key fields have been
-** modified from their original values, an UPDATE change is added to
-** the changeset. Or, if no such row is found in the table, a DELETE
+** modified from their original values, an UPDATE change is added to
+** the changeset. Or, if no such row is found in the table, a DELETE
** change is added to the changeset. If there is a row with a matching
** primary key in the database, but all fields contain their original
** values, no change is added to the changeset.
@@ -9026,7 +11284,7 @@ void sqlite3session_table_filter(
**
** This means, amongst other things, that if a row is inserted and then later
** deleted while a session object is active, neither the insert nor the delete
-** will be present in the changeset. Or if a row is deleted and then later a
+** will be present in the changeset. Or if a row is deleted and then later a
** row with the same primary key values inserted while a session object is
** active, the resulting changeset will contain an UPDATE change instead of
** a DELETE and an INSERT.
@@ -9035,21 +11293,22 @@ void sqlite3session_table_filter(
** it does not accumulate records when rows are inserted, updated or deleted.
** This may appear to have some counter-intuitive effects if a single row
** is written to more than once during a session. For example, if a row
-** is inserted while a session object is enabled, then later deleted while
+** is inserted while a session object is enabled, then later deleted while
** the same session object is disabled, no INSERT record will appear in the
** changeset, even though the delete took place while the session was disabled.
-** Or, if one field of a row is updated while a session is disabled, and
+** Or, if one field of a row is updated while a session is disabled, and
** another field of the same row is updated while the session is enabled, the
** resulting changeset will contain an UPDATE change that updates both fields.
*/
-int sqlite3session_changeset(
+SQLITE_API int sqlite3session_changeset(
sqlite3_session *pSession, /* Session object */
int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
void **ppChangeset /* OUT: Buffer containing changeset */
);
/*
-** CAPI3REF: Load The Difference Between Tables Into A Session
+** CAPI3REF: Load The Difference Between Tables Into A Session
+** METHOD: sqlite3_session
**
** If it is not already attached to the session object passed as the first
** argument, this function attaches table zTbl in the same manner as the
@@ -9058,7 +11317,7 @@ int sqlite3session_changeset(
** an error).
**
** Argument zFromDb must be the name of a database ("main", "temp" etc.)
-** attached to the same database handle as the session object that contains
+** attached to the same database handle as the session object that contains
** a table compatible with the table attached to the session by this function.
** A table is considered compatible if it:
**
@@ -9074,36 +11333,37 @@ int sqlite3session_changeset(
** APIs, tables without PRIMARY KEYs are simply ignored.
**
** This function adds a set of changes to the session object that could be
-** used to update the table in database zFrom (call this the "from-table")
-** so that its content is the same as the table attached to the session
+** used to update the table in database zFrom (call this the "from-table")
+** so that its content is the same as the table attached to the session
** object (call this the "to-table"). Specifically:
**
** <ul>
-** <li> For each row (primary key) that exists in the to-table but not in
+** <li> For each row (primary key) that exists in the to-table but not in
** the from-table, an INSERT record is added to the session object.
**
-** <li> For each row (primary key) that exists in the to-table but not in
+** <li> For each row (primary key) that exists in the to-table but not in
** the from-table, a DELETE record is added to the session object.
**
-** <li> For each row (primary key) that exists in both tables, but features
-** different in each, an UPDATE record is added to the session.
+** <li> For each row (primary key) that exists in both tables, but features
+** different non-PK values in each, an UPDATE record is added to the
+** session.
** </ul>
**
** To clarify, if this function is called and then a changeset constructed
-** using [sqlite3session_changeset()], then after applying that changeset to
-** database zFrom the contents of the two compatible tables would be
+** using [sqlite3session_changeset()], then after applying that changeset to
+** database zFrom the contents of the two compatible tables would be
** identical.
**
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
-** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
+** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
-** may be set to point to a buffer containing an English language error
+** may be set to point to a buffer containing an English language error
** message. It is the responsibility of the caller to free this buffer using
** sqlite3_free().
*/
-int sqlite3session_diff(
+SQLITE_API int sqlite3session_diff(
sqlite3_session *pSession,
const char *zFromDb,
const char *zTbl,
@@ -9113,23 +11373,24 @@ int sqlite3session_diff(
/*
** CAPI3REF: Generate A Patchset From A Session Object
+** METHOD: sqlite3_session
**
** The differences between a patchset and a changeset are that:
**
** <ul>
-** <li> DELETE records consist of the primary key fields only. The
+** <li> DELETE records consist of the primary key fields only. The
** original values of other fields are omitted.
-** <li> The original values of any modified fields are omitted from
+** <li> The original values of any modified fields are omitted from
** UPDATE records.
** </ul>
**
-** A patchset blob may be used with up to date versions of all
-** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
+** A patchset blob may be used with up to date versions of all
+** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
** attempting to use a patchset blob with old versions of the
-** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
+** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
**
-** Because the non-primary key "old.*" fields are omitted, no
+** Because the non-primary key "old.*" fields are omitted, no
** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
** is passed to the sqlite3changeset_apply() API. Other conflict types work
** in the same way as for changesets.
@@ -9139,38 +11400,39 @@ int sqlite3session_diff(
** a single table are grouped together, tables appear in the order in which
** they were attached to the session object).
*/
-int sqlite3session_patchset(
+SQLITE_API int sqlite3session_patchset(
sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
+ int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */
+ void **ppPatchset /* OUT: Buffer containing patchset */
);
/*
** CAPI3REF: Test if a changeset has recorded any changes.
**
-** Return non-zero if no changes to attached tables have been recorded by
-** the session object passed as the first argument. Otherwise, if one or
+** Return non-zero if no changes to attached tables have been recorded by
+** the session object passed as the first argument. Otherwise, if one or
** more changes have been recorded, return zero.
**
** Even if this function returns zero, it is possible that calling
** [sqlite3session_changeset()] on the session handle may still return a
-** changeset that contains no changes. This can happen when a row in
-** an attached table is modified and then later on the original values
+** changeset that contains no changes. This can happen when a row in
+** an attached table is modified and then later on the original values
** are restored. However, if this function returns non-zero, then it is
-** guaranteed that a call to sqlite3session_changeset() will return a
+** guaranteed that a call to sqlite3session_changeset() will return a
** changeset containing zero changes.
*/
-int sqlite3session_isempty(sqlite3_session *pSession);
+SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
/*
-** CAPI3REF: Create An Iterator To Traverse A Changeset
+** CAPI3REF: Create An Iterator To Traverse A Changeset
+** CONSTRUCTOR: sqlite3_changeset_iter
**
** Create an iterator used to iterate through the contents of a changeset.
** If successful, *pp is set to point to the iterator handle and SQLITE_OK
** is returned. Otherwise, if an error occurs, *pp is set to zero and an
** SQLite error code is returned.
**
-** The following functions can be used to advance and query a changeset
+** The following functions can be used to advance and query a changeset
** iterator created by this function:
**
** <ul>
@@ -9187,25 +11449,52 @@ int sqlite3session_isempty(sqlite3_session *pSession);
**
** Assuming the changeset blob was created by one of the
** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
-** [sqlite3changeset_invert()] functions, all changes within the changeset
-** that apply to a single table are grouped together. This means that when
-** an application iterates through a changeset using an iterator created by
-** this function, all changes that relate to a single table are visited
-** consecutively. There is no chance that the iterator will visit a change
-** the applies to table X, then one for table Y, and then later on visit
+** [sqlite3changeset_invert()] functions, all changes within the changeset
+** that apply to a single table are grouped together. This means that when
+** an application iterates through a changeset using an iterator created by
+** this function, all changes that relate to a single table are visited
+** consecutively. There is no chance that the iterator will visit a change
+** the applies to table X, then one for table Y, and then later on visit
** another change for table X.
+**
+** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
+** may be modified by passing a combination of
+** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter.
+**
+** Note that the sqlite3changeset_start_v2() API is still <b>experimental</b>
+** and therefore subject to change.
*/
-int sqlite3changeset_start(
+SQLITE_API int sqlite3changeset_start(
sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
int nChangeset, /* Size of changeset blob in bytes */
void *pChangeset /* Pointer to blob containing changeset */
);
+SQLITE_API int sqlite3changeset_start_v2(
+ sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
+ int nChangeset, /* Size of changeset blob in bytes */
+ void *pChangeset, /* Pointer to blob containing changeset */
+ int flags /* SESSION_CHANGESETSTART_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3changeset_start_v2
+**
+** The following flags may passed via the 4th parameter to
+** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
+**
+** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
+** Invert the changeset while iterating through it. This is equivalent to
+** inverting a changeset using sqlite3changeset_invert() before applying it.
+** It is an error to specify this flag with a patchset.
+*/
+#define SQLITE_CHANGESETSTART_INVERT 0x0002
/*
** CAPI3REF: Advance A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
-** This function may only be used with iterators created by function
+** This function may only be used with iterators created by the function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
@@ -9216,18 +11505,19 @@ int sqlite3changeset_start(
** point to the first change in the changeset. Each subsequent call advances
** the iterator to point to the next change in the changeset (if any). If
** no error occurs and the iterator points to a valid change after a call
-** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
+** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
** Otherwise, if all changes in the changeset have already been visited,
** SQLITE_DONE is returned.
**
-** If an error occurs, an SQLite error code is returned. Possible error
-** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
+** If an error occurs, an SQLite error code is returned. Possible error
+** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
** SQLITE_NOMEM.
*/
-int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
+SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
/*
** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** The pIter argument passed to this function may either be an iterator
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
@@ -9238,21 +11528,21 @@ int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
** If argument pzTab is not NULL, then *pzTab is set to point to a
** nul-terminated utf-8 encoded string containing the name of the table
** affected by the current change. The buffer remains valid until either
-** sqlite3changeset_next() is called on the iterator or until the
-** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
+** sqlite3changeset_next() is called on the iterator or until the
+** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
** set to the number of columns in the table affected by the change. If
-** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
+** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
** is an indirect change, or false (0) otherwise. See the documentation for
** [sqlite3session_indirect()] for a description of direct and indirect
-** changes. Finally, if pOp is not NULL, then *pOp is set to one of
-** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
+** changes. Finally, if pOp is not NULL, then *pOp is set to one of
+** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
** type of change that the iterator currently points to.
**
** If no error occurs, SQLITE_OK is returned. If an error does occur, an
** SQLite error code is returned. The values of the output variables may not
** be trusted in this case.
*/
-int sqlite3changeset_op(
+SQLITE_API int sqlite3changeset_op(
sqlite3_changeset_iter *pIter, /* Iterator object */
const char **pzTab, /* OUT: Pointer to table name */
int *pnCol, /* OUT: Number of columns in table */
@@ -9262,6 +11552,7 @@ int sqlite3changeset_op(
/*
** CAPI3REF: Obtain The Primary Key Definition Of A Table
+** METHOD: sqlite3_changeset_iter
**
** For each modified table, a changeset includes the following:
**
@@ -9285,7 +11576,7 @@ int sqlite3changeset_op(
** SQLITE_OK is returned and the output variables populated as described
** above.
*/
-int sqlite3changeset_pk(
+SQLITE_API int sqlite3changeset_pk(
sqlite3_changeset_iter *pIter, /* Iterator object */
unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
int *pnCol /* OUT: Number of entries in output array */
@@ -9293,11 +11584,12 @@ int sqlite3changeset_pk(
/*
** CAPI3REF: Obtain old.* Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** The pIter argument passed to this function may either be an iterator
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
** Furthermore, it may only be called if the type of change that the iterator
** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
@@ -9307,15 +11599,15 @@ int sqlite3changeset_pk(
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
**
** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
+** sqlite3_value object containing the iVal'th value from the vector of
** original row values stored as part of the UPDATE or DELETE change and
-** returns SQLITE_OK. The name of the function comes from the fact that this
+** returns SQLITE_OK. The name of the function comes from the fact that this
** is similar to the "old.*" columns available to update or delete triggers.
**
** If some other error occurs (e.g. an OOM condition), an SQLite error code
** is returned and *ppValue is set to NULL.
*/
-int sqlite3changeset_old(
+SQLITE_API int sqlite3changeset_old(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int iVal, /* Column number */
sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
@@ -9323,11 +11615,12 @@ int sqlite3changeset_old(
/*
** CAPI3REF: Obtain new.* Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** The pIter argument passed to this function may either be an iterator
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
** Furthermore, it may only be called if the type of change that the iterator
** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
@@ -9337,18 +11630,18 @@ int sqlite3changeset_old(
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
**
** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
+** sqlite3_value object containing the iVal'th value from the vector of
** new row values stored as part of the UPDATE or INSERT change and
** returns SQLITE_OK. If the change is an UPDATE and does not include
-** a new value for the requested column, *ppValue is set to NULL and
-** SQLITE_OK returned. The name of the function comes from the fact that
-** this is similar to the "new.*" columns available to update or delete
+** a new value for the requested column, *ppValue is set to NULL and
+** SQLITE_OK returned. The name of the function comes from the fact that
+** this is similar to the "new.*" columns available to update or delete
** triggers.
**
** If some other error occurs (e.g. an OOM condition), an SQLite error code
** is returned and *ppValue is set to NULL.
*/
-int sqlite3changeset_new(
+SQLITE_API int sqlite3changeset_new(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int iVal, /* Column number */
sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
@@ -9356,6 +11649,7 @@ int sqlite3changeset_new(
/*
** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** This function should only be used with iterator objects passed to a
** conflict-handler callback by [sqlite3changeset_apply()] with either
@@ -9368,14 +11662,14 @@ int sqlite3changeset_new(
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
**
** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the
+** sqlite3_value object containing the iVal'th value from the
** "conflicting row" associated with the current conflict-handler callback
** and returns SQLITE_OK.
**
** If some other error occurs (e.g. an OOM condition), an SQLite error code
** is returned and *ppValue is set to NULL.
*/
-int sqlite3changeset_conflict(
+SQLITE_API int sqlite3changeset_conflict(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int iVal, /* Column number */
sqlite3_value **ppValue /* OUT: Value from conflicting row */
@@ -9383,6 +11677,7 @@ int sqlite3changeset_conflict(
/*
** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
+** METHOD: sqlite3_changeset_iter
**
** This function may only be called with an iterator passed to an
** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
@@ -9391,7 +11686,7 @@ int sqlite3changeset_conflict(
**
** In all other cases this function returns SQLITE_MISUSE.
*/
-int sqlite3changeset_fk_conflicts(
+SQLITE_API int sqlite3changeset_fk_conflicts(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int *pnOut /* OUT: Number of FK violations */
);
@@ -9399,6 +11694,7 @@ int sqlite3changeset_fk_conflicts(
/*
** CAPI3REF: Finalize A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** This function is used to finalize an iterator allocated with
** [sqlite3changeset_start()].
@@ -9410,21 +11706,23 @@ int sqlite3changeset_fk_conflicts(
** call has no effect.
**
** If an error was encountered within a call to an sqlite3changeset_xxx()
-** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
+** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
** to that error is returned by this function. Otherwise, SQLITE_OK is
** returned. This is to allow the following pattern (pseudo-code):
**
+** <pre>
** sqlite3changeset_start();
** while( SQLITE_ROW==sqlite3changeset_next() ){
** // Do something with change.
** }
** rc = sqlite3changeset_finalize();
** if( rc!=SQLITE_OK ){
-** // An error has occurred
+** // An error has occurred
** }
+** </pre>
*/
-int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
+SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
/*
** CAPI3REF: Invert A Changeset
@@ -9448,13 +11746,13 @@ int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
** zeroed and an SQLite error code returned.
**
** It is the responsibility of the caller to eventually call sqlite3_free()
-** on the *ppOut pointer to free the buffer allocation following a successful
+** on the *ppOut pointer to free the buffer allocation following a successful
** call to this function.
**
** WARNING/TODO: This function currently assumes that the input is a valid
** changeset. If it is not, the results are undefined.
*/
-int sqlite3changeset_invert(
+SQLITE_API int sqlite3changeset_invert(
int nIn, const void *pIn, /* Input changeset */
int *pnOut, void **ppOut /* OUT: Inverse of input */
);
@@ -9462,14 +11760,15 @@ int sqlite3changeset_invert(
/*
** CAPI3REF: Concatenate Two Changeset Objects
**
-** This function is used to concatenate two changesets, A and B, into a
+** This function is used to concatenate two changesets, A and B, into a
** single changeset. The result is a changeset equivalent to applying
-** changeset A followed by changeset B.
+** changeset A followed by changeset B.
**
-** This function combines the two input changesets using an
+** This function combines the two input changesets using an
** sqlite3_changegroup object. Calling it produces similar results as the
** following code fragment:
**
+** <pre>
** sqlite3_changegroup *pGrp;
** rc = sqlite3_changegroup_new(&pGrp);
** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
@@ -9480,10 +11779,11 @@ int sqlite3changeset_invert(
** *ppOut = 0;
** *pnOut = 0;
** }
+** </pre>
**
** Refer to the sqlite3_changegroup documentation below for details.
*/
-int sqlite3changeset_concat(
+SQLITE_API int sqlite3changeset_concat(
int nA, /* Number of bytes in buffer pA */
void *pA, /* Pointer to buffer containing changeset A */
int nB, /* Number of bytes in buffer pB */
@@ -9495,11 +11795,15 @@ int sqlite3changeset_concat(
/*
** CAPI3REF: Changegroup Handle
+**
+** A changegroup is an object used to combine two or more
+** [changesets] or [patchsets]
*/
typedef struct sqlite3_changegroup sqlite3_changegroup;
/*
** CAPI3REF: Create A New Changegroup Object
+** CONSTRUCTOR: sqlite3_changegroup
**
** An sqlite3_changegroup object is used to combine two or more changesets
** (or patchsets) into a single changeset (or patchset). A single changegroup
@@ -9508,7 +11812,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
**
** If successful, this function returns SQLITE_OK and populates (*pp) with
** a pointer to a new sqlite3_changegroup object before returning. The caller
-** should eventually free the returned object using a call to
+** should eventually free the returned object using a call to
** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
**
@@ -9520,7 +11824,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
** <li> Zero or more changesets (or patchsets) are added to the object
** by calling sqlite3changegroup_add().
**
-** <li> The result of combining all input changesets together is obtained
+** <li> The result of combining all input changesets together is obtained
** by the application via a call to sqlite3changegroup_output().
**
** <li> The object is deleted using a call to sqlite3changegroup_delete().
@@ -9529,17 +11833,18 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
** Any number of calls to add() and output() may be made between the calls to
** new() and delete(), and in any order.
**
-** As well as the regular sqlite3changegroup_add() and
+** As well as the regular sqlite3changegroup_add() and
** sqlite3changegroup_output() functions, also available are the streaming
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
*/
-int sqlite3changegroup_new(sqlite3_changegroup **pp);
+SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add A Changeset To A Changegroup
+** METHOD: sqlite3_changegroup
**
** Add all changes within the changeset (or patchset) in buffer pData (size
-** nData bytes) to the changegroup.
+** nData bytes) to the changegroup.
**
** If the buffer contains a patchset, then all prior calls to this function
** on the same changegroup object must also have specified patchsets. Or, if
@@ -9566,7 +11871,7 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** changeset was recorded immediately after the changesets already
** added to the changegroup.
** <tr><td>INSERT <td>UPDATE <td>
-** The INSERT change remains in the changegroup. The values in the
+** The INSERT change remains in the changegroup. The values in the
** INSERT change are modified as if the row was inserted by the
** existing change and then updated according to the new change.
** <tr><td>INSERT <td>DELETE <td>
@@ -9577,17 +11882,17 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** changeset was recorded immediately after the changesets already
** added to the changegroup.
** <tr><td>UPDATE <td>UPDATE <td>
-** The existing UPDATE remains within the changegroup. It is amended
-** so that the accompanying values are as if the row was updated once
+** The existing UPDATE remains within the changegroup. It is amended
+** so that the accompanying values are as if the row was updated once
** by the existing change and then again by the new change.
** <tr><td>UPDATE <td>DELETE <td>
** The existing UPDATE is replaced by the new DELETE within the
** changegroup.
** <tr><td>DELETE <td>INSERT <td>
** If one or more of the column values in the row inserted by the
-** new change differ from those in the row deleted by the existing
+** new change differ from those in the row deleted by the existing
** change, the existing DELETE is replaced by an UPDATE within the
-** changegroup. Otherwise, if the inserted row is exactly the same
+** changegroup. Otherwise, if the inserted row is exactly the same
** as the deleted row, the existing DELETE is simply discarded.
** <tr><td>DELETE <td>UPDATE <td>
** The new change is ignored. This case does not occur if the new
@@ -9605,15 +11910,16 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the
-** final contents of the changegroup is undefined.
+** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
+** of the final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
-int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
+SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
+** METHOD: sqlite3_changegroup
**
** Obtain a buffer containing a changeset (or patchset) representing the
** current contents of the changegroup. If the inputs to the changegroup
@@ -9631,12 +11937,12 @@ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
**
** If an error occurs, an SQLite error code is returned and the output
** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
-** is returned and the output variables are set to the size of and a
+** is returned and the output variables are set to the size of and a
** pointer to the output buffer, respectively. In this case it is the
** responsibility of the caller to eventually free the buffer using a
** call to sqlite3_free().
*/
-int sqlite3changegroup_output(
+SQLITE_API int sqlite3changegroup_output(
sqlite3_changegroup*,
int *pnData, /* OUT: Size of output buffer in bytes */
void **ppData /* OUT: Pointer to output buffer */
@@ -9644,36 +11950,36 @@ int sqlite3changegroup_output(
/*
** CAPI3REF: Delete A Changegroup Object
+** DESTRUCTOR: sqlite3_changegroup
*/
-void sqlite3changegroup_delete(sqlite3_changegroup*);
+SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
/*
** CAPI3REF: Apply A Changeset To A Database
**
-** Apply a changeset to a database. This function attempts to update the
-** "main" database attached to handle db with the changes found in the
-** changeset passed via the second and third arguments.
+** Apply a changeset or patchset to a database. These functions attempt to
+** update the "main" database attached to handle db with the changes found in
+** the changeset passed via the second and third arguments.
**
-** The fourth argument (xFilter) passed to this function is the "filter
+** The fourth argument (xFilter) passed to these functions is the "filter
** callback". If it is not NULL, then for each table affected by at least one
** change in the changeset, the filter callback is invoked with
** the table name as the second argument, and a copy of the context pointer
-** passed as the sixth argument to this function as the first. If the "filter
-** callback" returns zero, then no attempt is made to apply any changes to
-** the table. Otherwise, if the return value is non-zero or the xFilter
-** argument to this function is NULL, all changes related to the table are
-** attempted.
-**
-** For each table that is not excluded by the filter callback, this function
-** tests that the target database contains a compatible table. A table is
+** passed as the sixth argument as the first. If the "filter callback"
+** returns zero, then no attempt is made to apply any changes to the table.
+** Otherwise, if the return value is non-zero or the xFilter argument to
+** is NULL, all changes related to the table are attempted.
+**
+** For each table that is not excluded by the filter callback, this function
+** tests that the target database contains a compatible table. A table is
** considered compatible if all of the following are true:
**
** <ul>
-** <li> The table has the same name as the name recorded in the
+** <li> The table has the same name as the name recorded in the
** changeset, and
-** <li> The table has the same number of columns as recorded in the
+** <li> The table has at least as many columns as recorded in the
** changeset, and
-** <li> The table has primary key columns in the same position as
+** <li> The table has primary key columns in the same position as
** recorded in the changeset.
** </ul>
**
@@ -9682,11 +11988,11 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
** one such warning is issued for each table in the changeset.
**
-** For each change for which there is a compatible table, an attempt is made
-** to modify the table contents according to the UPDATE, INSERT or DELETE
-** change. If a change cannot be applied cleanly, the conflict handler
-** function passed as the fifth argument to sqlite3changeset_apply() may be
-** invoked. A description of exactly when the conflict handler is invoked for
+** For each change for which there is a compatible table, an attempt is made
+** to modify the table contents according to the UPDATE, INSERT or DELETE
+** change. If a change cannot be applied cleanly, the conflict handler
+** function passed as the fifth argument to sqlite3changeset_apply() may be
+** invoked. A description of exactly when the conflict handler is invoked for
** each type of change is below.
**
** Unlike the xFilter argument, xConflict may not be passed NULL. The results
@@ -9694,29 +12000,33 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** argument are undefined.
**
** Each time the conflict handler function is invoked, it must return one
-** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
+** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
** if the second argument passed to the conflict handler is either
** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
** returns an illegal value, any changes already made are rolled back and
-** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
+** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
** actions are taken by sqlite3changeset_apply() depending on the value
** returned by each invocation of the conflict-handler function. Refer to
-** the documentation for the three
+** the documentation for the three
** [SQLITE_CHANGESET_OMIT|available return values] for details.
**
** <dl>
** <dt>DELETE Changes<dd>
-** For each DELETE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
+** For each DELETE change, the function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all non-primary key columns also match the values stored in
** the changeset the row is deleted from the target database.
**
** If a row with matching primary key values is found, but one or more of
** the non-primary key fields contains a value different from the original
** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument.
+** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the
+** database table has more columns than are recorded in the changeset,
+** only the values of those non-primary key fields are compared against
+** the current database contents - any trailing database table columns
+** are ignored.
**
** If no row with matching primary key values is found in the database,
** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
@@ -9731,31 +12041,33 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
**
** <dt>INSERT Changes<dd>
** For each INSERT change, an attempt is made to insert the new row into
-** the database.
+** the database. If the changeset row contains fewer fields than the
+** database table, the trailing fields are populated with their default
+** values.
**
-** If the attempt to insert the row fails because the database already
+** If the attempt to insert the row fails because the database already
** contains a row with the same primary key values, the conflict handler
-** function is invoked with the second argument set to
+** function is invoked with the second argument set to
** [SQLITE_CHANGESET_CONFLICT].
**
** If the attempt to insert the row fails because of some other constraint
-** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
+** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
-** This includes the case where the INSERT operation is re-attempted because
-** an earlier call to the conflict handler function returned
+** This includes the case where the INSERT operation is re-attempted because
+** an earlier call to the conflict handler function returned
** [SQLITE_CHANGESET_REPLACE].
**
** <dt>UPDATE Changes<dd>
-** For each UPDATE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
-** the changeset the row is updated within the target database.
+** For each UPDATE change, the function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all modified non-primary key columns also match the values
+** stored in the changeset the row is updated within the target database.
**
** If a row with matching primary key values is found, but one or more of
-** the non-primary key fields contains a value different from an original
-** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
+** the modified non-primary key fields contains a value different from an
+** original row value stored in the changeset, the conflict-handler function
+** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
** UPDATE changes only contain values for non-primary key fields that are
** to be modified, only those fields need to match the original values to
** avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
@@ -9764,26 +12076,43 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
** passed as the second argument.
**
-** If the UPDATE operation is attempted, but SQLite returns
-** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
+** If the UPDATE operation is attempted, but SQLite returns
+** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
-** This includes the case where the UPDATE operation is attempted after
+** This includes the case where the UPDATE operation is attempted after
** an earlier call to the conflict handler function returned
-** [SQLITE_CHANGESET_REPLACE].
+** [SQLITE_CHANGESET_REPLACE].
** </dl>
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
-** This can be used to further customize the applications conflict
+** This can be used to further customize the application's conflict
** resolution strategy.
**
-** All changes made by this function are enclosed in a savepoint transaction.
+** All changes made by these functions are enclosed in a savepoint transaction.
** If any other error (aside from a constraint failure when attempting to
** write to the target database) occurs, then the savepoint transaction is
-** rolled back, restoring the target database to its original state, and an
+** rolled back, restoring the target database to its original state, and an
** SQLite error code returned.
+**
+** If the output parameters (ppRebase) and (pnRebase) are non-NULL and
+** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2()
+** may set (*ppRebase) to point to a "rebase" that may be used with the
+** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase)
+** is set to the size of the buffer in bytes. It is the responsibility of the
+** caller to eventually free any such buffer using sqlite3_free(). The buffer
+** is only allocated and populated if one or more conflicts were encountered
+** while applying the patchset. See comments surrounding the sqlite3_rebaser
+** APIs for further details.
+**
+** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent
+** may be modified by passing a combination of
+** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter.
+**
+** Note that the sqlite3changeset_apply_v2() API is still <b>experimental</b>
+** and therefore subject to change.
*/
-int sqlite3changeset_apply(
+SQLITE_API int sqlite3changeset_apply(
sqlite3 *db, /* Apply change to "main" db of this handle */
int nChangeset, /* Size of changeset in bytes */
void *pChangeset, /* Changeset blob */
@@ -9798,8 +12127,49 @@ int sqlite3changeset_apply(
),
void *pCtx /* First argument passed to xConflict */
);
+SQLITE_API int sqlite3changeset_apply_v2(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int nChangeset, /* Size of changeset in bytes */
+ void *pChangeset, /* Changeset blob */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase, /* OUT: Rebase data */
+ int flags /* SESSION_CHANGESETAPPLY_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3changeset_apply_v2
+**
+** The following flags may passed via the 9th parameter to
+** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]:
+**
+** <dl>
+** <dt>SQLITE_CHANGESETAPPLY_NOSAVEPOINT <dd>
+** Usually, the sessions module encloses all operations performed by
+** a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The
+** SAVEPOINT is committed if the changeset or patchset is successfully
+** applied, or rolled back if an error occurs. Specifying this flag
+** causes the sessions module to omit this savepoint. In this case, if the
+** caller has an open transaction or savepoint when apply_v2() is called,
+** it may revert the partially applied changeset by rolling it back.
+**
+** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
+** Invert the changeset before applying it. This is equivalent to inverting
+** a changeset using sqlite3changeset_invert() before applying it. It is
+** an error to specify this flag with a patchset.
+*/
+#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
+#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
-/*
+/*
** CAPI3REF: Constants Passed To The Conflict Handler
**
** Values that may be passed as the second argument to a conflict-handler.
@@ -9808,32 +12178,32 @@ int sqlite3changeset_apply(
** <dt>SQLITE_CHANGESET_DATA<dd>
** The conflict handler is invoked with CHANGESET_DATA as the second argument
** when processing a DELETE or UPDATE change if a row with the required
-** PRIMARY KEY fields is present in the database, but one or more other
-** (non primary-key) fields modified by the update do not contain the
+** PRIMARY KEY fields is present in the database, but one or more other
+** (non primary-key) fields modified by the update do not contain the
** expected "before" values.
-**
+**
** The conflicting row, in this case, is the database row with the matching
** primary key.
-**
+**
** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
** argument when processing a DELETE or UPDATE change if a row with the
** required PRIMARY KEY fields is not present in the database.
-**
+**
** There is no conflicting row in this case. The results of invoking the
** sqlite3changeset_conflict() API are undefined.
-**
+**
** <dt>SQLITE_CHANGESET_CONFLICT<dd>
** CHANGESET_CONFLICT is passed as the second argument to the conflict
-** handler while processing an INSERT change if the operation would result
+** handler while processing an INSERT change if the operation would result
** in duplicate primary key values.
-**
+**
** The conflicting row in this case is the database row with the matching
** primary key.
**
** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
** If foreign key handling is enabled, and applying a changeset leaves the
-** database in a state containing foreign key violations, the conflict
+** database in a state containing foreign key violations, the conflict
** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
** exactly once before the changeset is committed. If the conflict handler
** returns CHANGESET_OMIT, the changes, including those that caused the
@@ -9843,12 +12213,12 @@ int sqlite3changeset_apply(
** No current or conflicting row information is provided. The only function
** it is possible to call on the supplied sqlite3_changeset_iter handle
** is sqlite3changeset_fk_conflicts().
-**
+**
** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
-** If any other constraint violation occurs while applying a change (i.e.
-** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
+** If any other constraint violation occurs while applying a change (i.e.
+** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
** invoked with CHANGESET_CONSTRAINT as the second argument.
-**
+**
** There is no conflicting row in this case. The results of invoking the
** sqlite3changeset_conflict() API are undefined.
**
@@ -9860,7 +12230,7 @@ int sqlite3changeset_apply(
#define SQLITE_CHANGESET_CONSTRAINT 4
#define SQLITE_CHANGESET_FOREIGN_KEY 5
-/*
+/*
** CAPI3REF: Constants Returned By The Conflict Handler
**
** A conflict handler callback must return one of the following three values.
@@ -9868,13 +12238,13 @@ int sqlite3changeset_apply(
** <dl>
** <dt>SQLITE_CHANGESET_OMIT<dd>
** If a conflict handler returns this value no special action is taken. The
-** change that caused the conflict is not applied. The session module
+** change that caused the conflict is not applied. The session module
** continues to the next change in the changeset.
**
** <dt>SQLITE_CHANGESET_REPLACE<dd>
** This value may only be returned if the second argument to the conflict
** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
-** is not the case, any changes applied so far are rolled back and the
+** is not the case, any changes applied so far are rolled back and the
** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
**
** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
@@ -9887,7 +12257,7 @@ int sqlite3changeset_apply(
** the original row is restored to the database before continuing.
**
** <dt>SQLITE_CHANGESET_ABORT<dd>
-** If this value is returned, any changes applied so far are rolled back
+** If this value is returned, any changes applied so far are rolled back
** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
** </dl>
*/
@@ -9896,26 +12266,182 @@ int sqlite3changeset_apply(
#define SQLITE_CHANGESET_ABORT 2
/*
+** CAPI3REF: Rebasing changesets
+** EXPERIMENTAL
+**
+** Suppose there is a site hosting a database in state S0. And that
+** modifications are made that move that database to state S1 and a
+** changeset recorded (the "local" changeset). Then, a changeset based
+** on S0 is received from another site (the "remote" changeset) and
+** applied to the database. The database is then in state
+** (S1+"remote"), where the exact state depends on any conflict
+** resolution decisions (OMIT or REPLACE) made while applying "remote".
+** Rebasing a changeset is to update it to take those conflict
+** resolution decisions into account, so that the same conflicts
+** do not have to be resolved elsewhere in the network.
+**
+** For example, if both the local and remote changesets contain an
+** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)":
+**
+** local: INSERT INTO t1 VALUES(1, 'v1');
+** remote: INSERT INTO t1 VALUES(1, 'v2');
+**
+** and the conflict resolution is REPLACE, then the INSERT change is
+** removed from the local changeset (it was overridden). Or, if the
+** conflict resolution was "OMIT", then the local changeset is modified
+** to instead contain:
+**
+** UPDATE t1 SET b = 'v2' WHERE a=1;
+**
+** Changes within the local changeset are rebased as follows:
+**
+** <dl>
+** <dt>Local INSERT<dd>
+** This may only conflict with a remote INSERT. If the conflict
+** resolution was OMIT, then add an UPDATE change to the rebased
+** changeset. Or, if the conflict resolution was REPLACE, add
+** nothing to the rebased changeset.
+**
+** <dt>Local DELETE<dd>
+** This may conflict with a remote UPDATE or DELETE. In both cases the
+** only possible resolution is OMIT. If the remote operation was a
+** DELETE, then add no change to the rebased changeset. If the remote
+** operation was an UPDATE, then the old.* fields of change are updated
+** to reflect the new.* values in the UPDATE.
+**
+** <dt>Local UPDATE<dd>
+** This may conflict with a remote UPDATE or DELETE. If it conflicts
+** with a DELETE, and the conflict resolution was OMIT, then the update
+** is changed into an INSERT. Any undefined values in the new.* record
+** from the update change are filled in using the old.* values from
+** the conflicting DELETE. Or, if the conflict resolution was REPLACE,
+** the UPDATE change is simply omitted from the rebased changeset.
+**
+** If conflict is with a remote UPDATE and the resolution is OMIT, then
+** the old.* values are rebased using the new.* values in the remote
+** change. Or, if the resolution is REPLACE, then the change is copied
+** into the rebased changeset with updates to columns also updated by
+** the conflicting remote UPDATE removed. If this means no columns would
+** be updated, the change is omitted.
+** </dl>
+**
+** A local change may be rebased against multiple remote changes
+** simultaneously. If a single key is modified by multiple remote
+** changesets, they are combined as follows before the local changeset
+** is rebased:
+**
+** <ul>
+** <li> If there has been one or more REPLACE resolutions on a
+** key, it is rebased according to a REPLACE.
+**
+** <li> If there have been no REPLACE resolutions on a key, then
+** the local changeset is rebased according to the most recent
+** of the OMIT resolutions.
+** </ul>
+**
+** Note that conflict resolutions from multiple remote changesets are
+** combined on a per-field basis, not per-row. This means that in the
+** case of multiple remote UPDATE operations, some fields of a single
+** local change may be rebased for REPLACE while others are rebased for
+** OMIT.
+**
+** In order to rebase a local changeset, the remote changeset must first
+** be applied to the local database using sqlite3changeset_apply_v2() and
+** the buffer of rebase information captured. Then:
+**
+** <ol>
+** <li> An sqlite3_rebaser object is created by calling
+** sqlite3rebaser_create().
+** <li> The new object is configured with the rebase buffer obtained from
+** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure().
+** If the local changeset is to be rebased against multiple remote
+** changesets, then sqlite3rebaser_configure() should be called
+** multiple times, in the same order that the multiple
+** sqlite3changeset_apply_v2() calls were made.
+** <li> Each local changeset is rebased by calling sqlite3rebaser_rebase().
+** <li> The sqlite3_rebaser object is deleted by calling
+** sqlite3rebaser_delete().
+** </ol>
+*/
+typedef struct sqlite3_rebaser sqlite3_rebaser;
+
+/*
+** CAPI3REF: Create a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Allocate a new changeset rebaser object. If successful, set (*ppNew) to
+** point to the new object and return SQLITE_OK. Otherwise, if an error
+** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew)
+** to NULL.
+*/
+SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
+
+/*
+** CAPI3REF: Configure a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Configure the changeset rebaser object to rebase changesets according
+** to the conflict resolutions described by buffer pRebase (size nRebase
+** bytes), which must have been obtained from a previous call to
+** sqlite3changeset_apply_v2().
+*/
+SQLITE_API int sqlite3rebaser_configure(
+ sqlite3_rebaser*,
+ int nRebase, const void *pRebase
+);
+
+/*
+** CAPI3REF: Rebase a changeset
+** EXPERIMENTAL
+**
+** Argument pIn must point to a buffer containing a changeset nIn bytes
+** in size. This function allocates and populates a buffer with a copy
+** of the changeset rebased according to the configuration of the
+** rebaser object passed as the first argument. If successful, (*ppOut)
+** is set to point to the new buffer containing the rebased changeset and
+** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
+** responsibility of the caller to eventually free the new buffer using
+** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
+** are set to zero and an SQLite error code returned.
+*/
+SQLITE_API int sqlite3rebaser_rebase(
+ sqlite3_rebaser*,
+ int nIn, const void *pIn,
+ int *pnOut, void **ppOut
+);
+
+/*
+** CAPI3REF: Delete a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Delete the changeset rebaser object and all associated resources. There
+** should be one call to this function for each successful invocation
+** of sqlite3rebaser_create().
+*/
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
+
+/*
** CAPI3REF: Streaming Versions of API functions.
**
-** The six streaming API xxx_strm() functions serve similar purposes to the
+** The six streaming API xxx_strm() functions serve similar purposes to the
** corresponding non-streaming API functions:
**
** <table border=1 style="margin-left:8ex;margin-right:8ex">
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
+** <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2]
+** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat]
+** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert]
+** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start]
+** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset]
+** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset]
** </table>
**
** Non-streaming functions that accept changesets (or patchsets) as input
-** require that the entire changeset be stored in a single buffer in memory.
-** Similarly, those that return a changeset or patchset do so by returning
-** a pointer to a single large buffer allocated using sqlite3_malloc().
-** Normally this is convenient. However, if an application running in a
+** require that the entire changeset be stored in a single buffer in memory.
+** Similarly, those that return a changeset or patchset do so by returning
+** a pointer to a single large buffer allocated using sqlite3_malloc().
+** Normally this is convenient. However, if an application running in a
** low-memory environment is required to handle very large changesets, the
** large contiguous memory allocations required can become onerous.
**
@@ -9937,12 +12463,12 @@ int sqlite3changeset_apply(
** </pre>
**
** Each time the xInput callback is invoked by the sessions module, the first
-** argument passed is a copy of the supplied pIn context pointer. The second
-** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
-** error occurs the xInput method should copy up to (*pnData) bytes of data
-** into the buffer and set (*pnData) to the actual number of bytes copied
-** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
-** should be set to zero to indicate this. Or, if an error occurs, an SQLite
+** argument passed is a copy of the supplied pIn context pointer. The second
+** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
+** error occurs the xInput method should copy up to (*pnData) bytes of data
+** into the buffer and set (*pnData) to the actual number of bytes copied
+** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
+** should be set to zero to indicate this. Or, if an error occurs, an SQLite
** error code should be returned. In all cases, if an xInput callback returns
** an error, all processing is abandoned and the streaming API function
** returns a copy of the error code to the caller.
@@ -9950,7 +12476,7 @@ int sqlite3changeset_apply(
** In the case of sqlite3changeset_start_strm(), the xInput callback may be
** invoked by the sessions module at any point during the lifetime of the
** iterator. If such an xInput callback returns an error, the iterator enters
-** an error state, whereby all subsequent calls to iterator functions
+** an error state, whereby all subsequent calls to iterator functions
** immediately fail with the same error code as returned by xInput.
**
** Similarly, streaming API functions that return changesets (or patchsets)
@@ -9980,11 +12506,11 @@ int sqlite3changeset_apply(
** is immediately abandoned and the streaming API function returns a copy
** of the xOutput error code to the application.
**
-** The sessions module never invokes an xOutput callback with the third
+** The sessions module never invokes an xOutput callback with the third
** parameter set to a value less than or equal to zero. Other than this,
** no guarantees are made as to the size of the chunks of data returned.
*/
-int sqlite3changeset_apply_strm(
+SQLITE_API int sqlite3changeset_apply_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
void *pIn, /* First arg for xInput */
@@ -9999,7 +12525,24 @@ int sqlite3changeset_apply_strm(
),
void *pCtx /* First argument passed to xConflict */
);
-int sqlite3changeset_concat_strm(
+SQLITE_API int sqlite3changeset_apply_v2_strm(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+ void *pIn, /* First arg for xInput */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase,
+ int flags
+);
+SQLITE_API int sqlite3changeset_concat_strm(
int (*xInputA)(void *pIn, void *pData, int *pnData),
void *pInA,
int (*xInputB)(void *pIn, void *pData, int *pnData),
@@ -10007,36 +12550,88 @@ int sqlite3changeset_concat_strm(
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changeset_invert_strm(
+SQLITE_API int sqlite3changeset_invert_strm(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changeset_start_strm(
+SQLITE_API int sqlite3changeset_start_strm(
sqlite3_changeset_iter **pp,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
-int sqlite3session_changeset_strm(
+SQLITE_API int sqlite3changeset_start_v2_strm(
+ sqlite3_changeset_iter **pp,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int flags
+);
+SQLITE_API int sqlite3session_changeset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3session_patchset_strm(
+SQLITE_API int sqlite3session_patchset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changegroup_add_strm(sqlite3_changegroup*,
+SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
-int sqlite3changegroup_output_strm(sqlite3_changegroup*,
- int (*xOutput)(void *pOut, const void *pData, int nData),
+SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
+SQLITE_API int sqlite3rebaser_rebase_strm(
+ sqlite3_rebaser *pRebaser,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+
+/*
+** CAPI3REF: Configure global parameters
+**
+** The sqlite3session_config() interface is used to make global configuration
+** changes to the sessions module in order to tune it to the specific needs
+** of the application.
+**
+** The sqlite3session_config() interface is not threadsafe. If it is invoked
+** while any other thread is inside any other sessions method then the
+** results are undefined. Furthermore, if it is invoked after any sessions
+** related objects have been created, the results are also undefined.
+**
+** The first argument to the sqlite3session_config() function must be one
+** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
+** interpretation of the (void*) value passed as the second parameter and
+** the effect of calling this function depends on the value of the first
+** parameter.
+**
+** <dl>
+** <dt>SQLITE_SESSION_CONFIG_STRMSIZE<dd>
+** By default, the sessions module streaming interfaces attempt to input
+** and output data in approximately 1 KiB chunks. This operand may be used
+** to set and query the value of this configuration setting. The pointer
+** passed as the second argument must point to a value of type (int).
+** If this value is greater than 0, it is used as the new streaming data
+** chunk size for both input and output. Before returning, the (int) value
+** pointed to by pArg is set to the final value of the streaming interface
+** chunk size.
+** </dl>
+**
+** This function returns SQLITE_OK if successful, or an SQLite error code
+** otherwise.
+*/
+SQLITE_API int sqlite3session_config(int op, void *pArg);
+/*
+** CAPI3REF: Values for sqlite3session_config().
+*/
+#define SQLITE_SESSION_CONFIG_STRMSIZE 1
/*
** Make sure we can call this stuff from C++.
@@ -10061,7 +12656,7 @@ int sqlite3changegroup_output_strm(sqlite3_changegroup*,
**
******************************************************************************
**
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
+** Interfaces to extend FTS5. Using the interfaces defined in this file,
** FTS5 may be extended with:
**
** * custom tokenizers, and
@@ -10105,19 +12700,19 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
+** Return a copy of the context pointer the extension function was
** registered with.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
** to the total number of tokens in the FTS5 table. Or, if iCol is
** non-negative but less than the number of columns in the table, return
-** the total number of tokens in column iCol, considering all rows in
+** the total number of tokens in column iCol, considering all rows in
** the FTS5 table.
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
+** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** xColumnCount(pFts):
@@ -10131,7 +12726,7 @@ struct Fts5PhraseIter {
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
+** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** This function may be quite inefficient if used with an FTS5 table
@@ -10158,8 +12753,8 @@ struct Fts5PhraseIter {
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
+** "detail=none" or "detail=column" option. If the FTS5 table is created
+** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always returns 0.
**
** xInst:
@@ -10170,15 +12765,11 @@ struct Fts5PhraseIter {
**
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. The exception is if the table was created
-** with the offsets=0 option specified. In this case *piOff is always
-** set to -1.
-**
-** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
-** if an error occurs.
+** first token of the phrase. Returns SQLITE_OK if successful, or an error
+** code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option.
+** "detail=none" or "detail=column" option.
**
** xRowid:
** Returns the rowid of the current row.
@@ -10194,11 +12785,11 @@ struct Fts5PhraseIter {
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
** current query is executed. Any column filter that applies to
-** phrase iPhrase of the current query is included in $p. For each
-** row visited, the callback function passed as the fourth argument
-** is invoked. The context and API objects passed to the callback
+** phrase iPhrase of the current query is included in $p. For each
+** row visited, the callback function passed as the fourth argument
+** is invoked. The context and API objects passed to the callback
** function may be used to access the properties of each matched row.
-** Invoking Api.xUserData() returns a copy of the pointer passed as
+** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
@@ -10213,14 +12804,14 @@ struct Fts5PhraseIter {
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
-** Save the pointer passed as the second argument as the extension functions
+** Save the pointer passed as the second argument as the extension function's
** "auxiliary data". The pointer may then be retrieved by the current or any
** future invocation of the same fts5 extension function made as part of
-** of the same MATCH query using the xGetAuxdata() API.
+** the same MATCH query using the xGetAuxdata() API.
**
** Each extension function is allocated a single auxiliary data slot for
-** each FTS query (MATCH expression). If the extension function is invoked
-** more than once for a single FTS query, then all invocations share a
+** each FTS query (MATCH expression). If the extension function is invoked
+** more than once for a single FTS query, then all invocations share a
** single auxiliary data context.
**
** If there is already an auxiliary data pointer when this function is
@@ -10231,7 +12822,7 @@ struct Fts5PhraseIter {
** The xDelete callback, if one is specified, is also invoked on the
** auxiliary data pointer after the FTS5 query has finished.
**
-** If an error (e.g. an OOM condition) occurs within this function, an
+** If an error (e.g. an OOM condition) occurs within this function,
** the auxiliary data is set to NULL and an error code returned. If the
** xDelete parameter was not NULL, it is invoked on the auxiliary data
** pointer before returning.
@@ -10239,7 +12830,7 @@ struct Fts5PhraseIter {
**
** xGetAuxdata(pFts5, bClear)
**
-** Returns the current auxiliary data pointer for the fts5 extension
+** Returns the current auxiliary data pointer for the fts5 extension
** function. See the xSetAuxdata() method for details.
**
** If the bClear argument is non-zero, then the auxiliary data is cleared
@@ -10259,7 +12850,7 @@ struct Fts5PhraseIter {
** method, to iterate through all instances of a single query phrase within
** the current row. This is the same information as is accessible via the
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
-** to use, this API may be faster under some circumstances. To iterate
+** to use, this API may be faster under some circumstances. To iterate
** through instances of phrase iPhrase, use the following code:
**
** Fts5PhraseIter iter;
@@ -10277,8 +12868,8 @@ struct Fts5PhraseIter {
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
+** "detail=none" or "detail=column" option. If the FTS5 table is created
+** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
@@ -10302,16 +12893,16 @@ struct Fts5PhraseIter {
** }
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" option. If the FTS5 table is created with either
-** "detail=none" "content=" option (i.e. if it is a contentless table),
-** then this API always iterates through an empty set (all calls to
+** "detail=none" option. If the FTS5 table is created with either
+** "detail=none" "content=" option (i.e. if it is a contentless table),
+** then this API always iterates through an empty set (all calls to
** xPhraseFirstColumn() set iCol to -1).
**
** The information accessed using this API and its companion
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
** (or xInst/xInstCount). The chief advantage of this API is that it is
** significantly more efficient than those alternatives when used with
-** "detail=column" tables.
+** "detail=column" tables.
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
@@ -10325,7 +12916,7 @@ struct Fts5ExtensionApi {
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
- int (*xTokenize)(Fts5Context*,
+ int (*xTokenize)(Fts5Context*,
const char *pText, int nText, /* Text to tokenize */
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
@@ -10354,15 +12945,15 @@ struct Fts5ExtensionApi {
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
};
-/*
+/*
** CUSTOM AUXILIARY FUNCTIONS
*************************************************************************/
/*************************************************************************
** CUSTOM TOKENIZERS
**
-** Applications may also register custom tokenizer types. A tokenizer
-** is registered by providing fts5 with a populated instance of the
+** Applications may also register custom tokenizer types. A tokenizer
+** is registered by providing fts5 with a populated instance of the
** following structure. All structure methods must be defined, setting
** any member of the fts5_tokenizer struct to NULL leads to undefined
** behaviour. The structure methods are expected to function as follows:
@@ -10373,16 +12964,16 @@ struct Fts5ExtensionApi {
**
** The first argument passed to this function is a copy of the (void*)
** pointer provided by the application when the fts5_tokenizer object
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
+** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
** to create the FTS5 table.
**
-** The final argument is an output variable. If successful, (*ppOut)
+** The final argument is an output variable. If successful, (*ppOut)
** should be set to point to the new tokenizer handle and SQLITE_OK
** returned. If an error occurs, some value other than SQLITE_OK should
-** be returned. In this case, fts5 assumes that the final value of *ppOut
+** be returned. In this case, fts5 assumes that the final value of *ppOut
** is undefined.
**
** xDelete:
@@ -10391,7 +12982,7 @@ struct Fts5ExtensionApi {
** be invoked exactly once for each successful call to xCreate().
**
** xTokenize:
-** This function is expected to tokenize the nText byte string indicated
+** This function is expected to tokenize the nText byte string indicated
** by argument pText. pText may or may not be nul-terminated. The first
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
@@ -10405,8 +12996,8 @@ struct Fts5ExtensionApi {
** determine the set of tokens to add to (or delete from) the
** FTS index.
**
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
-** against the FTS index. The tokenizer is being called to tokenize
+** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
+** against the FTS index. The tokenizer is being called to tokenize
** a bareword or quoted string specified as part of the query.
**
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
@@ -10414,10 +13005,10 @@ struct Fts5ExtensionApi {
** followed by a "*" character, indicating that the last token
** returned by the tokenizer will be treated as a token prefix.
**
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
+** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
** satisfy an fts5_api.xTokenize() request made by an auxiliary
** function. Or an fts5_api.xColumnSize() request made by the same
-** on a columnsize=0 database.
+** on a columnsize=0 database.
** </ul>
**
** For each token in the input string, the supplied callback xToken() must
@@ -10429,10 +13020,10 @@ struct Fts5ExtensionApi {
** which the token is derived within the input.
**
** The second argument passed to the xToken() callback ("tflags") should
-** normally be set to 0. The exception is if the tokenizer supports
+** normally be set to 0. The exception is if the tokenizer supports
** synonyms. In this case see the discussion below for details.
**
-** FTS5 assumes the xToken() callback is invoked for each token in the
+** FTS5 assumes the xToken() callback is invoked for each token in the
** order that they occur within the input text.
**
** If an xToken() callback returns any value other than SQLITE_OK, then
@@ -10446,7 +13037,7 @@ struct Fts5ExtensionApi {
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
-** user wishes to query for a phrase such as "first place". Using the
+** user wishes to query for a phrase such as "first place". Using the
** built-in tokenizers, the FTS5 query 'first + place' will match instances
** of "first place" within the document set, but not alternative forms
** such as "1st place". In some applications, it would be better to match
@@ -10455,8 +13046,8 @@ struct Fts5ExtensionApi {
**
** There are several ways to approach this in FTS5:
**
-** <ol><li> By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
+** <ol><li> By mapping all synonyms to a single token. In this case, using
+** the above example, this means that the tokenizer returns the
** same token for inputs "first" and "1st". Say that token is in
** fact "first", so that when the user inserts the document "I won
** 1st place" entries are added to the index for tokens "i", "won",
@@ -10464,37 +13055,37 @@ struct Fts5ExtensionApi {
** the tokenizer substitutes "first" for "1st" and the query works
** as expected.
**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
+** <li> By querying the index for all synonyms of each query term
+** separately. In this case, when tokenizing query text, the
+** tokenizer may provide multiple synonyms for a single term
+** within the document. FTS5 then queries the index for each
+** synonym individually. For example, faced with the query:
**
** <codeblock>
** ... MATCH 'first place'</codeblock>
**
** the tokenizer offers both "1st" and "first" as synonyms for the
-** first token in the MATCH query and FTS5 effectively runs a query
+** first token in the MATCH query and FTS5 effectively runs a query
** similar to:
**
** <codeblock>
** ... MATCH '(first OR 1st) place'</codeblock>
**
** except that, for the purposes of auxiliary functions, the query
-** still appears to contain just two phrases - "(first OR 1st)"
+** still appears to contain just two phrases - "(first OR 1st)"
** being treated as a single phrase.
**
** <li> By adding multiple synonyms for a single term to the FTS index.
** Using this method, when tokenizing document text, the tokenizer
-** provides multiple synonyms for each token. So that when a
+** provides multiple synonyms for each token. So that when a
** document such as "I won first place" is tokenized, entries are
** added to the FTS index for "i", "won", "first", "1st" and
** "place".
**
** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
-** inefficient), it doesn't matter if the user queries for
-** 'first + place' or '1st + place', as there are entires in the
+** when tokenizing query text (it should not - to do so would be
+** inefficient), it doesn't matter if the user queries for
+** 'first + place' or '1st + place', as there are entries in the
** FTS index corresponding to both forms of the first token.
** </ol>
**
@@ -10514,15 +13105,15 @@ struct Fts5ExtensionApi {
**
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
** xToken() is called. Multiple synonyms may be specified for a single token
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
+** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
** There is no limit to the number of synonyms that may be provided for a
** single token.
**
-** In many cases, method (1) above is the best approach. It does not add
+** In many cases, method (1) above is the best approach. It does not add
** extra data to the FTS index or require FTS5 to query for multiple terms,
** so it is efficient in terms of disk space and query speed. However, it
** does not support prefix queries very well. If, as suggested above, the
-** token "first" is subsituted for "1st" by the tokenizer, then the query:
+** token "first" is substituted for "1st" by the tokenizer, then the query:
**
** <codeblock>
** ... MATCH '1s*'</codeblock>
@@ -10530,18 +13121,18 @@ struct Fts5ExtensionApi {
** will not match documents that contain the token "1st" (as the tokenizer
** will probably not map "1s" to any prefix of "first").
**
-** For full prefix support, method (3) may be preferred. In this case,
+** For full prefix support, method (3) may be preferred. In this case,
** because the index contains entries for both "first" and "1st", prefix
** queries such as 'fi*' or '1s*' will match correctly. However, because
** extra entries are added to the FTS index, this method uses more space
** within the database.
**
** Method (2) offers a midpoint between (1) and (3). Using this method,
-** a query such as '1s*' will match documents that contain the literal
+** a query such as '1s*' will match documents that contain the literal
** token "1st", but not "first" (assuming the tokenizer is not able to
** provide synonyms for prefixes). However, a non-prefix query like '1st'
** will match against "1st" and "first". This method does not require
-** extra disk space, as no extra entries are added to the FTS index.
+** extra disk space, as no extra entries are added to the FTS index.
** On the other hand, it may require more CPU cycles to run MATCH queries,
** as separate queries of the FTS index are required for each synonym.
**
@@ -10555,10 +13146,10 @@ typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
- int (*xTokenize)(Fts5Tokenizer*,
+ int (*xTokenize)(Fts5Tokenizer*,
void *pCtx,
int flags, /* Mask of FTS5_TOKENIZE_* flags */
- const char *pText, int nText,
+ const char *pText, int nText,
int (*xToken)(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
@@ -10637,8 +13228,9 @@ struct fts5_api {
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
*/
-#ifdef _HAVE_SQLITE_CONFIG_H
-#include "config.h"
+#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
+/* #include "config.h" */
+#define SQLITECONFIG_H 1
#endif
/************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/
@@ -10654,7 +13246,7 @@ struct fts5_api {
** May you share freely, never taking more than you give.
**
*************************************************************************
-**
+**
** This file defines various limits of what SQLite can process.
*/
@@ -10702,9 +13294,9 @@ struct fts5_api {
#endif
/*
-** The maximum depth of an expression tree. This is limited to
-** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
-** want to place more severe limits on the complexity of an
+** The maximum depth of an expression tree. This is limited to
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
+** want to place more severe limits on the complexity of an
** expression.
**
** A value of 0 used to mean that the limit was not enforced.
@@ -10732,7 +13324,7 @@ struct fts5_api {
** Not currently enforced.
*/
#ifndef SQLITE_MAX_VDBE_OP
-# define SQLITE_MAX_VDBE_OP 25000
+# define SQLITE_MAX_VDBE_OP 250000000
#endif
/*
@@ -10776,9 +13368,12 @@ struct fts5_api {
/*
** The maximum value of a ?nnn wildcard that the parser will accept.
+** If the value exceeds 32767 then extra space is required for the Expr
+** structure. But otherwise, we believe that the number can be as large
+** as a signed 32-bit integer can hold.
*/
#ifndef SQLITE_MAX_VARIABLE_NUMBER
-# define SQLITE_MAX_VARIABLE_NUMBER 999
+# define SQLITE_MAX_VARIABLE_NUMBER 32766
#endif
/* Maximum page size. The upper bound on this value is 65536. This a limit
@@ -10786,10 +13381,10 @@ struct fts5_api {
**
** Earlier versions of SQLite allowed the user to change this value at
** compile time. This is no longer permitted, on the grounds that it creates
-** a library that is technically incompatible with an SQLite library
-** compiled with a different limit. If a process operating on a database
-** with a page-size of 65536 bytes crashes, then an instance of SQLite
-** compiled with the default page-size limit will not be able to rollback
+** a library that is technically incompatible with an SQLite library
+** compiled with a different limit. If a process operating on a database
+** with a page-size of 65536 bytes crashes, then an instance of SQLite
+** compiled with the default page-size limit will not be able to rollback
** the aborted transaction. This could lead to database corruption.
*/
#ifdef SQLITE_MAX_PAGE_SIZE
@@ -10848,7 +13443,7 @@ struct fts5_api {
** Maximum depth of recursion for triggers.
**
** A value of 1 means that a trigger program will not be able to itself
-** fire any triggers. A value of 0 means that no trigger programs at all
+** fire any triggers. A value of 0 means that no trigger programs at all
** may be executed.
*/
#ifndef SQLITE_MAX_TRIGGER_DEPTH
@@ -10868,6 +13463,21 @@ struct fts5_api {
#endif
/*
+** WAL mode depends on atomic aligned 32-bit loads and stores in a few
+** places. The following macros try to make this explicit.
+*/
+#ifndef __has_extension
+# define __has_extension(x) 0 /* compatibility with non-clang compilers */
+#endif
+#if GCC_VERSION>=4007000 || __has_extension(c_atomic)
+# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
+# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
+#else
+# define AtomicLoad(PTR) (*(PTR))
+# define AtomicStore(PTR,VAL) (*(PTR) = (VAL))
+#endif
+
+/*
** Include standard header files as necessary
*/
#ifdef HAVE_STDINT_H
@@ -10893,15 +13503,15 @@ struct fts5_api {
** So we have to define the macros in different ways depending on the
** compiler.
*/
-#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
+#if defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
+# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
+# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
+#elif defined(__PTRDIFF_TYPE__) /* This case should work for GCC */
# define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__) /* Works for compilers other than LLVM */
# define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0))
-#elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */
-# define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X))
-# define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X))
#else /* Generates a warning - but it always works */
# define SQLITE_INT_TO_PTR(X) ((void*)(X))
# define SQLITE_PTR_TO_INT(X) ((int)(X))
@@ -10930,6 +13540,7 @@ struct fts5_api {
# include <intrin.h>
# pragma intrinsic(_byteswap_ushort)
# pragma intrinsic(_byteswap_ulong)
+# pragma intrinsic(_byteswap_uint64)
# pragma intrinsic(_ReadWriteBarrier)
# else
# include <cmnintrin.h>
@@ -10947,6 +13558,11 @@ struct fts5_api {
**
** Older versions of SQLite used an optional THREADSAFE macro.
** We support that for legacy.
+**
+** To ensure that the correct value of "THREADSAFE" is reported when querying
+** for compile-time options at runtime (e.g. "PRAGMA compile_options"), this
+** logic is partially replicated in ctime.c. If it is updated here, it should
+** also be updated there.
*/
#if !defined(SQLITE_THREADSAFE)
# if defined(THREADSAFE)
@@ -11122,6 +13738,41 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
+** The harmless(X) macro indicates that expression X is usually false
+** but can be true without causing any problems, but we don't know of
+** any way to cause X to be true.
+**
+** In debugging and testing builds, this macro will abort if X is ever
+** true. In this way, developers are alerted to a possible test case
+** that causes X to be true. If a harmless macro ever fails, that is
+** an opportunity to change the macro into a testcase() and add a new
+** test case to the test suite.
+**
+** For normal production builds, harmless(X) is a no-op, since it does
+** not matter whether expression X is true or false.
+*/
+#ifdef SQLITE_DEBUG
+# define harmless(X) assert(!(X));
+#else
+# define harmless(X)
+#endif
+
+/*
+** Some conditionals are optimizations only. In other words, if the
+** conditionals are replaced with a constant 1 (true) or 0 (false) then
+** the correct answer is still obtained, though perhaps not as quickly.
+**
+** The following macros mark these optimizations conditionals.
+*/
+#if defined(SQLITE_MUTATION_TEST)
+# define OK_IF_ALWAYS_TRUE(X) (1)
+# define OK_IF_ALWAYS_FALSE(X) (0)
+#else
+# define OK_IF_ALWAYS_TRUE(X) (X)
+# define OK_IF_ALWAYS_FALSE(X) (X)
+#endif
+
+/*
** Some malloc failures are only possible if SQLITE_TEST_REALLOC_STRESS is
** defined. We need to defend against those failures when testing with
** SQLITE_TEST_REALLOC_STRESS, but we don't want the unreachable branches
@@ -11225,7 +13876,7 @@ typedef struct HashElem HashElem;
** element pointed to plus the next _ht.count-1 elements in the list.
**
** Hash.htsize and Hash.ht may be zero. In that case lookup is done
-** by a linear search of the global list. For small tables, the
+** by a linear search of the global list. For small tables, the
** Hash.ht table is never allocated because if there are few elements
** in the table, it is faster to do a linear search than to manage
** the hash table.
@@ -11235,12 +13886,12 @@ struct Hash {
unsigned int count; /* Number of entries in this table */
HashElem *first; /* The first element of the array */
struct _ht { /* the hash table */
- int count; /* Number of entries with this hash */
+ unsigned int count; /* Number of entries with this hash */
HashElem *chain; /* Pointer to first entry with this hash */
} *ht;
};
-/* Each element in the hash table is an instance of the following
+/* Each element in the hash table is an instance of the following
** structure. All elements are stored on a single doubly-linked list.
**
** Again, this structure is intended to be opaque, but it can't really
@@ -11315,150 +13966,160 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_AS 24
#define TK_WITHOUT 25
#define TK_COMMA 26
-#define TK_OR 27
-#define TK_AND 28
-#define TK_IS 29
-#define TK_MATCH 30
-#define TK_LIKE_KW 31
-#define TK_BETWEEN 32
-#define TK_IN 33
-#define TK_ISNULL 34
-#define TK_NOTNULL 35
-#define TK_NE 36
-#define TK_EQ 37
-#define TK_GT 38
-#define TK_LE 39
-#define TK_LT 40
-#define TK_GE 41
-#define TK_ESCAPE 42
-#define TK_BITAND 43
-#define TK_BITOR 44
-#define TK_LSHIFT 45
-#define TK_RSHIFT 46
-#define TK_PLUS 47
-#define TK_MINUS 48
-#define TK_STAR 49
-#define TK_SLASH 50
-#define TK_REM 51
-#define TK_CONCAT 52
-#define TK_COLLATE 53
-#define TK_BITNOT 54
-#define TK_ID 55
-#define TK_INDEXED 56
-#define TK_ABORT 57
-#define TK_ACTION 58
-#define TK_AFTER 59
-#define TK_ANALYZE 60
-#define TK_ASC 61
-#define TK_ATTACH 62
-#define TK_BEFORE 63
-#define TK_BY 64
-#define TK_CASCADE 65
-#define TK_CAST 66
-#define TK_COLUMNKW 67
-#define TK_CONFLICT 68
-#define TK_DATABASE 69
-#define TK_DESC 70
-#define TK_DETACH 71
-#define TK_EACH 72
-#define TK_FAIL 73
-#define TK_FOR 74
-#define TK_IGNORE 75
-#define TK_INITIALLY 76
-#define TK_INSTEAD 77
-#define TK_NO 78
-#define TK_KEY 79
-#define TK_OF 80
-#define TK_OFFSET 81
-#define TK_PRAGMA 82
-#define TK_RAISE 83
-#define TK_RECURSIVE 84
-#define TK_REPLACE 85
-#define TK_RESTRICT 86
-#define TK_ROW 87
-#define TK_TRIGGER 88
-#define TK_VACUUM 89
-#define TK_VIEW 90
-#define TK_VIRTUAL 91
-#define TK_WITH 92
-#define TK_REINDEX 93
-#define TK_RENAME 94
-#define TK_CTIME_KW 95
-#define TK_ANY 96
-#define TK_STRING 97
-#define TK_JOIN_KW 98
-#define TK_CONSTRAINT 99
-#define TK_DEFAULT 100
-#define TK_NULL 101
-#define TK_PRIMARY 102
-#define TK_UNIQUE 103
-#define TK_CHECK 104
-#define TK_REFERENCES 105
-#define TK_AUTOINCR 106
-#define TK_ON 107
-#define TK_INSERT 108
-#define TK_DELETE 109
-#define TK_UPDATE 110
-#define TK_SET 111
-#define TK_DEFERRABLE 112
-#define TK_FOREIGN 113
-#define TK_DROP 114
-#define TK_UNION 115
-#define TK_ALL 116
-#define TK_EXCEPT 117
-#define TK_INTERSECT 118
-#define TK_SELECT 119
-#define TK_VALUES 120
-#define TK_DISTINCT 121
-#define TK_DOT 122
-#define TK_FROM 123
-#define TK_JOIN 124
-#define TK_USING 125
-#define TK_ORDER 126
-#define TK_GROUP 127
-#define TK_HAVING 128
-#define TK_LIMIT 129
-#define TK_WHERE 130
-#define TK_INTO 131
-#define TK_FLOAT 132
-#define TK_BLOB 133
-#define TK_INTEGER 134
-#define TK_VARIABLE 135
-#define TK_CASE 136
-#define TK_WHEN 137
-#define TK_THEN 138
-#define TK_ELSE 139
-#define TK_INDEX 140
-#define TK_ALTER 141
-#define TK_ADD 142
-#define TK_TO_TEXT 143
-#define TK_TO_BLOB 144
-#define TK_TO_NUMERIC 145
-#define TK_TO_INT 146
-#define TK_TO_REAL 147
-#define TK_ISNOT 148
-#define TK_END_OF_FILE 149
-#define TK_UNCLOSED_STRING 150
-#define TK_FUNCTION 151
-#define TK_COLUMN 152
-#define TK_AGG_FUNCTION 153
-#define TK_AGG_COLUMN 154
-#define TK_UMINUS 155
-#define TK_UPLUS 156
-#define TK_REGISTER 157
-#define TK_VECTOR 158
-#define TK_SELECT_COLUMN 159
-#define TK_ASTERISK 160
-#define TK_SPAN 161
-#define TK_SPACE 162
-#define TK_ILLEGAL 163
-
-/* The token codes above must all fit in 8 bits */
-#define TKFLG_MASK 0xff
-
-/* Flags that can be added to a token code when it is not
-** being stored in a u8: */
-#define TKFLG_DONTFOLD 0x100 /* Omit constant folding optimizations */
+#define TK_ABORT 27
+#define TK_ACTION 28
+#define TK_AFTER 29
+#define TK_ANALYZE 30
+#define TK_ASC 31
+#define TK_ATTACH 32
+#define TK_BEFORE 33
+#define TK_BY 34
+#define TK_CASCADE 35
+#define TK_CAST 36
+#define TK_CONFLICT 37
+#define TK_DATABASE 38
+#define TK_DESC 39
+#define TK_DETACH 40
+#define TK_EACH 41
+#define TK_FAIL 42
+#define TK_OR 43
+#define TK_AND 44
+#define TK_IS 45
+#define TK_MATCH 46
+#define TK_LIKE_KW 47
+#define TK_BETWEEN 48
+#define TK_IN 49
+#define TK_ISNULL 50
+#define TK_NOTNULL 51
+#define TK_NE 52
+#define TK_EQ 53
+#define TK_GT 54
+#define TK_LE 55
+#define TK_LT 56
+#define TK_GE 57
+#define TK_ESCAPE 58
+#define TK_ID 59
+#define TK_COLUMNKW 60
+#define TK_DO 61
+#define TK_FOR 62
+#define TK_IGNORE 63
+#define TK_INITIALLY 64
+#define TK_INSTEAD 65
+#define TK_NO 66
+#define TK_KEY 67
+#define TK_OF 68
+#define TK_OFFSET 69
+#define TK_PRAGMA 70
+#define TK_RAISE 71
+#define TK_RECURSIVE 72
+#define TK_REPLACE 73
+#define TK_RESTRICT 74
+#define TK_ROW 75
+#define TK_ROWS 76
+#define TK_TRIGGER 77
+#define TK_VACUUM 78
+#define TK_VIEW 79
+#define TK_VIRTUAL 80
+#define TK_WITH 81
+#define TK_NULLS 82
+#define TK_FIRST 83
+#define TK_LAST 84
+#define TK_CURRENT 85
+#define TK_FOLLOWING 86
+#define TK_PARTITION 87
+#define TK_PRECEDING 88
+#define TK_RANGE 89
+#define TK_UNBOUNDED 90
+#define TK_EXCLUDE 91
+#define TK_GROUPS 92
+#define TK_OTHERS 93
+#define TK_TIES 94
+#define TK_GENERATED 95
+#define TK_ALWAYS 96
+#define TK_REINDEX 97
+#define TK_RENAME 98
+#define TK_CTIME_KW 99
+#define TK_ANY 100
+#define TK_BITAND 101
+#define TK_BITOR 102
+#define TK_LSHIFT 103
+#define TK_RSHIFT 104
+#define TK_PLUS 105
+#define TK_MINUS 106
+#define TK_STAR 107
+#define TK_SLASH 108
+#define TK_REM 109
+#define TK_CONCAT 110
+#define TK_COLLATE 111
+#define TK_BITNOT 112
+#define TK_ON 113
+#define TK_INDEXED 114
+#define TK_STRING 115
+#define TK_JOIN_KW 116
+#define TK_CONSTRAINT 117
+#define TK_DEFAULT 118
+#define TK_NULL 119
+#define TK_PRIMARY 120
+#define TK_UNIQUE 121
+#define TK_CHECK 122
+#define TK_REFERENCES 123
+#define TK_AUTOINCR 124
+#define TK_INSERT 125
+#define TK_DELETE 126
+#define TK_UPDATE 127
+#define TK_SET 128
+#define TK_DEFERRABLE 129
+#define TK_FOREIGN 130
+#define TK_DROP 131
+#define TK_UNION 132
+#define TK_ALL 133
+#define TK_EXCEPT 134
+#define TK_INTERSECT 135
+#define TK_SELECT 136
+#define TK_VALUES 137
+#define TK_DISTINCT 138
+#define TK_DOT 139
+#define TK_FROM 140
+#define TK_JOIN 141
+#define TK_USING 142
+#define TK_ORDER 143
+#define TK_GROUP 144
+#define TK_HAVING 145
+#define TK_LIMIT 146
+#define TK_WHERE 147
+#define TK_INTO 148
+#define TK_NOTHING 149
+#define TK_FLOAT 150
+#define TK_BLOB 151
+#define TK_INTEGER 152
+#define TK_VARIABLE 153
+#define TK_CASE 154
+#define TK_WHEN 155
+#define TK_THEN 156
+#define TK_ELSE 157
+#define TK_INDEX 158
+#define TK_ALTER 159
+#define TK_ADD 160
+#define TK_WINDOW 161
+#define TK_OVER 162
+#define TK_FILTER 163
+#define TK_COLUMN 164
+#define TK_AGG_FUNCTION 165
+#define TK_AGG_COLUMN 166
+#define TK_TRUEFALSE 167
+#define TK_ISNOT 168
+#define TK_FUNCTION 169
+#define TK_UMINUS 170
+#define TK_UPLUS 171
+#define TK_TRUTH 172
+#define TK_REGISTER 173
+#define TK_VECTOR 174
+#define TK_SELECT_COLUMN 175
+#define TK_IF_NULL_ROW 176
+#define TK_ASTERISK 177
+#define TK_SPAN 178
+#define TK_SPACE 179
+#define TK_ILLEGAL 180
/************** End of parse.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -11469,6 +14130,18 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#include <stddef.h>
/*
+** Use a macro to replace memcpy() if compiled with SQLITE_INLINE_MEMCPY.
+** This allows better measurements of where memcpy() is used when running
+** cachegrind. But this macro version of memcpy() is very slow so it
+** should not be used in production. This is a performance measurement
+** hack only.
+*/
+#ifdef SQLITE_INLINE_MEMCPY
+# define memcpy(D,S,N) {char*xxd=(char*)(D);const char*xxs=(const char*)(S);\
+ int xxn=(N);while(xxn-->0)*(xxd++)=*(xxs++);}
+#endif
+
+/*
** If compiling for a processor that lacks floating point support,
** substitute integer for floating-point
*/
@@ -11524,7 +14197,6 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
*/
#ifndef SQLITE_TEMP_STORE
# define SQLITE_TEMP_STORE 1
-# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
#endif
/*
@@ -11552,9 +14224,28 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
** pagecaches for each database connection. A positive number is the
** number of pages. A negative number N translations means that a buffer
** of -1024*N bytes is allocated and used for as many pages as it will hold.
+**
+** The default value of "20" was choosen to minimize the run-time of the
+** speedtest1 test program with options: --shrink-memory --reprepare
*/
#ifndef SQLITE_DEFAULT_PCACHE_INITSZ
-# define SQLITE_DEFAULT_PCACHE_INITSZ 100
+# define SQLITE_DEFAULT_PCACHE_INITSZ 20
+#endif
+
+/*
+** Default value for the SQLITE_CONFIG_SORTERREF_SIZE option.
+*/
+#ifndef SQLITE_DEFAULT_SORTERREF_SIZE
+# define SQLITE_DEFAULT_SORTERREF_SIZE 0x7fffffff
+#endif
+
+/*
+** The compile-time options SQLITE_MMAP_READWRITE and
+** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
+** You must choose one or the other (or neither) but not both.
+*/
+#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
#endif
/*
@@ -11695,7 +14386,8 @@ typedef INT16_TYPE LogEst;
# if defined(__SIZEOF_POINTER__)
# define SQLITE_PTRSIZE __SIZEOF_POINTER__
# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(_M_ARM) || defined(__arm__) || defined(__x86)
+ defined(_M_ARM) || defined(__arm__) || defined(__x86) || \
+ (defined(__TOS_AIX__) && !defined(__64BIT__))
# define SQLITE_PTRSIZE 4
# else
# define SQLITE_PTRSIZE 8
@@ -11729,32 +14421,36 @@ typedef INT16_TYPE LogEst;
**
** For best performance, an attempt is made to guess at the byte-order
** using C-preprocessor macros. If that is unsuccessful, or if
-** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
+** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined
** at run-time.
*/
-#if (defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)) && !defined(SQLITE_RUNTIME_BYTEORDER)
-# define SQLITE_BYTEORDER 1234
-# define SQLITE_BIGENDIAN 0
-# define SQLITE_LITTLEENDIAN 1
-# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
+#ifndef SQLITE_BYTEORDER
+# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ppc__) || \
+ defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
+# else
+# define SQLITE_BYTEORDER 0
+# endif
#endif
-#if (defined(sparc) || defined(__ppc__)) \
- && !defined(SQLITE_RUNTIME_BYTEORDER)
-# define SQLITE_BYTEORDER 4321
+#if SQLITE_BYTEORDER==4321
# define SQLITE_BIGENDIAN 1
# define SQLITE_LITTLEENDIAN 0
# define SQLITE_UTF16NATIVE SQLITE_UTF16BE
-#endif
-#if !defined(SQLITE_BYTEORDER)
+#elif SQLITE_BYTEORDER==1234
+# define SQLITE_BIGENDIAN 0
+# define SQLITE_LITTLEENDIAN 1
+# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
+#else
# ifdef SQLITE_AMALGAMATION
const int sqlite3one = 1;
# else
extern const int sqlite3one;
# endif
-# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
@@ -11766,6 +14462,7 @@ typedef INT16_TYPE LogEst;
** compilers.
*/
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
+#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/*
@@ -11819,7 +14516,6 @@ typedef INT16_TYPE LogEst;
# else
# define SQLITE_MAX_MMAP_SIZE 0
# endif
-# define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */
#endif
/*
@@ -11829,7 +14525,6 @@ typedef INT16_TYPE LogEst;
*/
#ifndef SQLITE_DEFAULT_MMAP_SIZE
# define SQLITE_DEFAULT_MMAP_SIZE 0
-# define SQLITE_DEFAULT_MMAP_SIZE_xc 1 /* Exclude from ctime.c */
#endif
#if SQLITE_DEFAULT_MMAP_SIZE>SQLITE_MAX_MMAP_SIZE
# undef SQLITE_DEFAULT_MMAP_SIZE
@@ -11837,26 +14532,22 @@ typedef INT16_TYPE LogEst;
#endif
/*
-** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined.
-** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also
-** define SQLITE_ENABLE_STAT3_OR_STAT4
-*/
-#ifdef SQLITE_ENABLE_STAT4
-# undef SQLITE_ENABLE_STAT3
-# define SQLITE_ENABLE_STAT3_OR_STAT4 1
-#elif SQLITE_ENABLE_STAT3
-# define SQLITE_ENABLE_STAT3_OR_STAT4 1
-#elif SQLITE_ENABLE_STAT3_OR_STAT4
-# undef SQLITE_ENABLE_STAT3_OR_STAT4
-#endif
-
-/*
** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
** the Select query generator tracing logic is turned on.
*/
-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_SELECTTRACE)
+#if defined(SQLITE_ENABLE_SELECTTRACE)
+# define SELECTTRACE_ENABLED 1
+#else
+# define SELECTTRACE_ENABLED 0
+#endif
+#if defined(SQLITE_ENABLE_SELECTTRACE)
# define SELECTTRACE_ENABLED 1
+# define SELECTTRACE(K,P,S,X) \
+ if(sqlite3_unsupported_selecttrace&(K)) \
+ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
+ sqlite3DebugPrintf X
#else
+# define SELECTTRACE(K,P,S,X)
# define SELECTTRACE_ENABLED 0
#endif
@@ -11871,28 +14562,30 @@ typedef INT16_TYPE LogEst;
*/
typedef struct BusyHandler BusyHandler;
struct BusyHandler {
- int (*xFunc)(void *,int); /* The busy callback */
- void *pArg; /* First arg to busy callback */
- int nBusy; /* Incremented with each busy call */
+ int (*xBusyHandler)(void *,int); /* The busy callback */
+ void *pBusyArg; /* First arg to busy callback */
+ int nBusy; /* Incremented with each busy call */
};
/*
-** Name of the master database table. The master database table
-** is a special table that holds the names and attributes of all
-** user tables and indices.
+** Name of table that holds the database schema.
*/
-#define MASTER_NAME "sqlite_master"
-#define TEMP_MASTER_NAME "sqlite_temp_master"
+#define DFLT_SCHEMA_TABLE "sqlite_master"
+#define DFLT_TEMP_SCHEMA_TABLE "sqlite_temp_master"
+#define ALT_SCHEMA_TABLE "sqlite_schema"
+#define ALT_TEMP_SCHEMA_TABLE "sqlite_temp_schema"
+
/*
-** The root-page of the master database table.
+** The root-page of the schema table.
*/
-#define MASTER_ROOT 1
+#define SCHEMA_ROOT 1
/*
-** The name of the schema table.
+** The name of the schema table. The name is different for TEMP.
*/
-#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME)
+#define SCHEMA_TABLE(x) \
+ ((!OMIT_TEMPDB)&&(x==1)?DFLT_TEMP_SCHEMA_TABLE:DFLT_SCHEMA_TABLE)
/*
** A convenience macro that returns the number of elements in
@@ -11913,7 +14606,7 @@ struct BusyHandler {
** pointer will work here as long as it is distinct from SQLITE_STATIC
** and SQLITE_TRANSIENT.
*/
-#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
+#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomFault)
/*
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
@@ -11973,7 +14666,6 @@ typedef struct Db Db;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
-typedef struct ExprSpan ExprSpan;
typedef struct FKey FKey;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
@@ -11990,13 +14682,14 @@ typedef struct NameContext NameContext;
typedef struct Parse Parse;
typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
+typedef struct RenameToken RenameToken;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SQLiteThread SQLiteThread;
typedef struct SelectDest SelectDest;
typedef struct SrcList SrcList;
-typedef struct StrAccum StrAccum;
+typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
typedef struct Table Table;
typedef struct TableLock TableLock;
typedef struct Token Token;
@@ -12005,17 +14698,301 @@ typedef struct Trigger Trigger;
typedef struct TriggerPrg TriggerPrg;
typedef struct TriggerStep TriggerStep;
typedef struct UnpackedRecord UnpackedRecord;
+typedef struct Upsert Upsert;
typedef struct VTable VTable;
typedef struct VtabCtx VtabCtx;
typedef struct Walker Walker;
typedef struct WhereInfo WhereInfo;
+typedef struct Window Window;
typedef struct With With;
+
+/*
+** The bitmask datatype defined below is used for various optimizations.
+**
+** Changing this from a 64-bit to a 32-bit type limits the number of
+** tables in a join to 32 instead of 64. But it also reduces the size
+** of the library by 738 bytes on ix86.
+*/
+#ifdef SQLITE_BITMASK_TYPE
+ typedef SQLITE_BITMASK_TYPE Bitmask;
+#else
+ typedef u64 Bitmask;
+#endif
+
+/*
+** The number of bits in a Bitmask. "BMS" means "BitMask Size".
+*/
+#define BMS ((int)(sizeof(Bitmask)*8))
+
+/*
+** A bit in a Bitmask
+*/
+#define MASKBIT(n) (((Bitmask)1)<<(n))
+#define MASKBIT64(n) (((u64)1)<<(n))
+#define MASKBIT32(n) (((unsigned int)1)<<(n))
+#define ALLBITS ((Bitmask)-1)
+
+/* A VList object records a mapping between parameters/variables/wildcards
+** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
+** variable number associated with that parameter. See the format description
+** on the sqlite3VListAdd() routine for more information. A VList is really
+** just an array of integers.
+*/
+typedef int VList;
+
/*
** Defer sourcing vdbe.h and btree.h until after the "u8" and
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
+/************** Include pager.h in the middle of sqliteInt.h *****************/
+/************** Begin file pager.h *******************************************/
+/*
+** 2001 September 15
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This header file defines the interface that the sqlite page cache
+** subsystem. The page cache subsystem reads and writes a file a page
+** at a time and provides a journal for rollback.
+*/
+
+#ifndef SQLITE_PAGER_H
+#define SQLITE_PAGER_H
+
+/*
+** Default maximum size for persistent journal files. A negative
+** value means no limit. This value may be overridden using the
+** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
+*/
+#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
+ #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
+#endif
+
+/*
+** The type used to represent a page number. The first page in a file
+** is called page 1. 0 is used to represent "not a page".
+*/
+typedef u32 Pgno;
+
+/*
+** Each open file is managed by a separate instance of the "Pager" structure.
+*/
+typedef struct Pager Pager;
+
+/*
+** Handle type for pages.
+*/
+typedef struct PgHdr DbPage;
+
+/*
+** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
+** reserved for working around a windows/posix incompatibility). It is
+** used in the journal to signify that the remainder of the journal file
+** is devoted to storing a super-journal name - there are no more pages to
+** roll back. See comments for function writeSuperJournal() in pager.c
+** for details.
+*/
+#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
+
+/*
+** Allowed values for the flags parameter to sqlite3PagerOpen().
+**
+** NOTE: These values must match the corresponding BTREE_ values in btree.h.
+*/
+#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
+#define PAGER_MEMORY 0x0002 /* In-memory database */
+
+/*
+** Valid values for the second argument to sqlite3PagerLockingMode().
+*/
+#define PAGER_LOCKINGMODE_QUERY -1
+#define PAGER_LOCKINGMODE_NORMAL 0
+#define PAGER_LOCKINGMODE_EXCLUSIVE 1
+
+/*
+** Numeric constants that encode the journalmode.
+**
+** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
+** are exposed in the API via the "PRAGMA journal_mode" command and
+** therefore cannot be changed without a compatibility break.
+*/
+#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
+#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
+#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
+#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
+#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
+#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
+#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
+
+/*
+** Flags that make up the mask passed to sqlite3PagerGet().
+*/
+#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
+#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
+
+/*
+** Flags for sqlite3PagerSetFlags()
+**
+** Value constraints (enforced via assert()):
+** PAGER_FULLFSYNC == SQLITE_FullFSync
+** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
+** PAGER_CACHE_SPILL == SQLITE_CacheSpill
+*/
+#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
+#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
+#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
+#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
+#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
+#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
+#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
+#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
+#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
+
+/*
+** The remainder of this file contains the declarations of the functions
+** that make up the Pager sub-system API. See source code comments for
+** a detailed description of each routine.
+*/
+
+/* Open and close a Pager connection. */
+SQLITE_PRIVATE int sqlite3PagerOpen(
+ sqlite3_vfs*,
+ Pager **ppPager,
+ const char*,
+ int,
+ int,
+ int,
+ void(*)(DbPage*)
+);
+SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
+SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
+
+/* Functions used to configure a Pager object. */
+SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
+SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
+SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
+SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
+SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
+SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
+SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
+SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
+SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
+SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
+SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
+SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
+
+/* Functions used to obtain and release page references. */
+SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
+SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
+SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
+SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
+SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
+SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
+
+/* Operations on page references. */
+SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
+SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
+SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
+SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
+SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
+SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
+
+/* Functions used to manage pager transactions and savepoints. */
+SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
+SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
+SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
+SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
+SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper);
+SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
+SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
+SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
+SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
+SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
+
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
+# ifdef SQLITE_ENABLE_SNAPSHOT
+SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
+# endif
+#endif
+
+#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
+#else
+# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
+# define sqlite3PagerWalDb(x,y)
+#endif
+
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
+SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
+#endif
+
+#ifdef SQLITE_ENABLE_ZIPVFS
+SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
+#endif
+
+/* Functions used to query pager state and configuration. */
+SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
+#endif
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
+SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
+SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
+SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
+SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
+SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
+SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
+SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
+
+/* Functions used to truncate the database file. */
+SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
+
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
+
+/* Functions to support testing and debugging. */
+#if !defined(NDEBUG) || defined(SQLITE_TEST)
+SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
+SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
+#endif
+#ifdef SQLITE_TEST
+SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
+SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
+ void disable_simulated_io_errors(void);
+ void enable_simulated_io_errors(void);
+#else
+# define disable_simulated_io_errors()
+# define enable_simulated_io_errors()
+#endif
+
+#endif /* SQLITE_PAGER_H */
+
+/************** End of pager.h ***********************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include btree.h in the middle of sqliteInt.h *****************/
/************** Begin file btree.h *******************************************/
/*
@@ -12091,20 +15068,20 @@ SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
-SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
-SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
+SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
+SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*);
+SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*);
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
-SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
+SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*);
+SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
-SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
+SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
@@ -12146,7 +15123,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
-** should be one of the following values. The integer values are assigned
+** should be one of the following values. The integer values are assigned
** to constants so that the offset of the corresponding field in an
** SQLite database header may be found using the following formula:
**
@@ -12217,7 +15194,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
-/*
+/*
** Flags passed as the third argument to sqlite3BtreeCursor().
**
** For read-only cursors the wrFlag argument is always zero. For read-write
@@ -12245,11 +15222,12 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree*, /* BTree containing table to open */
- int iTable, /* Index of root page */
+ Pgno iTable, /* Index of root page */
int wrFlag, /* 1 for writing. 0 for read-only */
struct KeyInfo*, /* First argument to compare function */
BtCursor *pCursor /* Space to write cursor structure */
);
+SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void);
SQLITE_PRIVATE int sqlite3BtreeCursorSize(void);
SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor*, unsigned);
@@ -12269,53 +15247,78 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
-/* Allowed flags for the 2nd argument to sqlite3BtreeDelete() */
+/* Allowed flags for sqlite3BtreeDelete() and sqlite3BtreeInsert() */
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
+#define BTREE_APPEND 0x08 /* Insert is likely an append */
/* An instance of the BtreePayload object describes the content of a single
** entry in either an index or table btree.
**
** Index btrees (used for indexes and also WITHOUT ROWID tables) contain
-** an arbitrary key and no data. These btrees have pKey,nKey set to their
-** key and pData,nData,nZero set to zero.
+** an arbitrary key and no data. These btrees have pKey,nKey set to the
+** key and the pData,nData,nZero fields are uninitialized. The aMem,nMem
+** fields give an array of Mem objects that are a decomposition of the key.
+** The nMem field might be zero, indicating that no decomposition is available.
**
** Table btrees (used for rowid tables) contain an integer rowid used as
-** the key and passed in the nKey field. The pKey field is zero.
+** the key and passed in the nKey field. The pKey field is zero.
** pData,nData hold the content of the new entry. nZero extra zero bytes
** are appended to the end of the content when constructing the entry.
+** The aMem,nMem fields are uninitialized for table btrees.
+**
+** Field usage summary:
+**
+** Table BTrees Index Btrees
+**
+** pKey always NULL encoded key
+** nKey the ROWID length of pKey
+** pData data not used
+** aMem not used decomposed key value
+** nMem not used entries in aMem
+** nData length of pData not used
+** nZero extra zeros after pData not used
**
** This object is used to pass information into sqlite3BtreeInsert(). The
** same information used to be passed as five separate parameters. But placing
-** the information into this object helps to keep the interface more
+** the information into this object helps to keep the interface more
** organized and understandable, and it also helps the resulting code to
** run a little faster by using fewer registers for parameter passing.
*/
struct BtreePayload {
const void *pKey; /* Key content for indexes. NULL for tables */
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
- const void *pData; /* Data for tables. NULL for indexes */
+ const void *pData; /* Data for tables. */
+ sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */
+ u16 nMem; /* Number of aMem[] value. Might be zero */
int nData; /* Size of pData. 0 if none. */
int nZero; /* Extra zero data appended after pData,nData */
};
SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
- int bias, int seekResult);
+ int flags, int seekResult);
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes);
+SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes);
+SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
+SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*);
+SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*);
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
+#endif
+SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
+SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
-SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
+SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
+SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
#ifndef SQLITE_OMIT_INCRBLOB
+SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
#endif
@@ -12328,10 +15331,9 @@ SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
+SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*);
-#ifndef SQLITE_OMIT_BTREECOUNT
-SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *);
-#endif
+SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
#ifdef SQLITE_TEST
SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
@@ -12354,7 +15356,7 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*);
#else
-# define sqlite3BtreeEnter(X)
+# define sqlite3BtreeEnter(X)
# define sqlite3BtreeEnterAll(X)
# define sqlite3BtreeSharable(X) 0
# define sqlite3BtreeEnterCursor(X)
@@ -12421,7 +15423,7 @@ typedef struct Vdbe Vdbe;
** The names of the following types declared in vdbeInt.h are required
** for the VdbeOp definition.
*/
-typedef struct Mem Mem;
+typedef struct sqlite3_value Mem;
typedef struct SubProgram SubProgram;
/*
@@ -12432,8 +15434,7 @@ typedef struct SubProgram SubProgram;
struct VdbeOp {
u8 opcode; /* What operation to perform */
signed char p4type; /* One of the P4_xxx constants for p4 */
- u8 notUsed1;
- u8 p5; /* Fifth parameter is an unsigned character */
+ u16 p5; /* Fifth parameter is an unsigned 16-bit integer */
int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */
int p3; /* The third parameter */
@@ -12449,13 +15450,13 @@ struct VdbeOp {
Mem *pMem; /* Used when p4type is P4_MEM */
VTable *pVtab; /* Used when p4type is P4_VTAB */
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
- int *ai; /* Used when p4type is P4_INTARRAY */
+ u32 *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
Table *pTab; /* Used when p4type is P4_TABLE */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
- int (*xAdvance)(BtCursor *, int *);
+ int (*xAdvance)(BtCursor *, int);
} p4;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */
@@ -12465,7 +15466,8 @@ struct VdbeOp {
u64 cycles; /* Total time spent executing this instruction */
#endif
#ifdef SQLITE_VDBE_COVERAGE
- int iSrcLine; /* Source-code line that generated this opcode */
+ u32 iSrcLine; /* Source-code line that generated this opcode
+ ** with flags in the upper 8 bits */
#endif
};
typedef struct VdbeOp VdbeOp;
@@ -12479,6 +15481,7 @@ struct SubProgram {
int nOp; /* Elements in aOp[] */
int nMem; /* Number of memory cells required */
int nCsr; /* Number of cursors required */
+ u8 *aOnce; /* Array of OP_Once flags */
void *token; /* id that may be used to recursive triggers */
SubProgram *pNext; /* Next sub-program already visited */
};
@@ -12498,25 +15501,27 @@ typedef struct VdbeOpList VdbeOpList;
/*
** Allowed values of VdbeOp.p4type
*/
-#define P4_NOTUSED 0 /* The P4 parameter is not used */
-#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
-#define P4_STATIC (-2) /* Pointer to a static string */
-#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
-#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
-#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
-#define P4_EXPR (-7) /* P4 is a pointer to an Expr tree */
-#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
-#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
-#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
-#define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */
-#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
-#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
-#define P4_INT32 (-14) /* P4 is a 32-bit signed integer */
-#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
-#define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */
-#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
-#define P4_TABLE (-20) /* P4 is a pointer to a Table structure */
-#define P4_FUNCCTX (-21) /* P4 is a pointer to an sqlite3_context object */
+#define P4_NOTUSED 0 /* The P4 parameter is not used */
+#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
+#define P4_STATIC (-1) /* Pointer to a static string */
+#define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */
+#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */
+#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */
+#define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */
+#define P4_TABLE (-6) /* P4 is a pointer to a Table structure */
+/* Above do not own any resources. Must free those below */
+#define P4_FREE_IF_LE (-7)
+#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */
+#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */
+#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */
+#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */
+#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */
+#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */
+#define P4_REAL (-13) /* P4 is a 64-bit floating point value */
+#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */
+#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
+#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */
+#define P4_DYNBLOB (-17) /* Pointer to memory from sqliteMalloc() */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -12525,7 +15530,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P5_ConstraintFK 4
/*
-** The Vdbe.aColName array contains 5n Mem structures, where n is the
+** The Vdbe.aColName array contains 5n Mem structures, where n is the
** number of columns of data returned by the statement.
*/
#define COLNAME_NAME 0
@@ -12544,12 +15549,11 @@ typedef struct VdbeOpList VdbeOpList;
#endif
/*
-** The following macro converts a relative address in the p2 field
-** of a VdbeOp structure into a negative number so that
-** sqlite3VdbeAddOpList() knows that the address is relative. Calling
-** the macro again restores the address.
+** The following macro converts a label returned by sqlite3VdbeMakeLabel()
+** into an index into the Parse.aLabel[] array that contains the resolved
+** address of that label.
*/
-#define ADDR(X) (-1-(X))
+#define ADDR(X) (~(X))
/*
** The makefile scans the vdbe.c source file and creates the "opcodes.h"
@@ -12562,166 +15566,179 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Savepoint 0
#define OP_AutoCommit 1
#define OP_Transaction 2
-#define OP_SorterNext 3
-#define OP_PrevIfOpen 4
-#define OP_NextIfOpen 5
-#define OP_Prev 6
-#define OP_Next 7
-#define OP_Checkpoint 8
-#define OP_JournalMode 9
-#define OP_Vacuum 10
-#define OP_VFilter 11 /* synopsis: iplan=r[P3] zplan='P4' */
-#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */
-#define OP_Goto 13
-#define OP_Gosub 14
-#define OP_InitCoroutine 15
-#define OP_Yield 16
-#define OP_MustBeInt 17
-#define OP_Jump 18
+#define OP_SorterNext 3 /* jump */
+#define OP_Prev 4 /* jump */
+#define OP_Next 5 /* jump */
+#define OP_Checkpoint 6
+#define OP_JournalMode 7
+#define OP_Vacuum 8
+#define OP_VFilter 9 /* jump, synopsis: iplan=r[P3] zplan='P4' */
+#define OP_VUpdate 10 /* synopsis: data=r[P3@P2] */
+#define OP_Goto 11 /* jump */
+#define OP_Gosub 12 /* jump */
+#define OP_InitCoroutine 13 /* jump */
+#define OP_Yield 14 /* jump */
+#define OP_MustBeInt 15 /* jump */
+#define OP_Jump 16 /* jump */
+#define OP_Once 17 /* jump */
+#define OP_If 18 /* jump */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_Once 20
-#define OP_If 21
-#define OP_IfNot 22
-#define OP_SeekLT 23 /* synopsis: key=r[P3@P4] */
-#define OP_SeekLE 24 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGE 25 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGT 26 /* synopsis: key=r[P3@P4] */
-#define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
-#define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */
-#define OP_NotFound 30 /* synopsis: key=r[P3@P4] */
-#define OP_Found 31 /* synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 32 /* synopsis: intkey=r[P3] */
-#define OP_NotExists 33 /* synopsis: intkey=r[P3] */
-#define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 36 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */
-#define OP_Eq 37 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */
-#define OP_Gt 38 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */
-#define OP_Le 39 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */
-#define OP_Lt 40 /* same as TK_LT, synopsis: IF r[P3]<r[P1] */
-#define OP_Ge 41 /* same as TK_GE, synopsis: IF r[P3]>=r[P1] */
-#define OP_ElseNotEq 42 /* same as TK_ESCAPE */
-#define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
-#define OP_ShiftRight 46 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
-#define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_Last 53
-#define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
-#define OP_SorterSort 55
-#define OP_Sort 56
-#define OP_Rewind 57
-#define OP_IdxLE 58 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGT 59 /* synopsis: key=r[P3@P4] */
-#define OP_IdxLT 60 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGE 61 /* synopsis: key=r[P3@P4] */
-#define OP_RowSetRead 62 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 63 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 64
-#define OP_FkIfZero 65 /* synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 66 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
-#define OP_IfNotZero 67 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */
-#define OP_DecrJumpZero 68 /* synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 69
-#define OP_VNext 70
-#define OP_Init 71 /* synopsis: Start at P2 */
-#define OP_Return 72
-#define OP_EndCoroutine 73
-#define OP_HaltIfNull 74 /* synopsis: if r[P3]=null halt */
-#define OP_Halt 75
-#define OP_Integer 76 /* synopsis: r[P2]=P1 */
-#define OP_Int64 77 /* synopsis: r[P2]=P4 */
-#define OP_String 78 /* synopsis: r[P2]='P4' (len=P1) */
-#define OP_Null 79 /* synopsis: r[P2..P3]=NULL */
-#define OP_SoftNull 80 /* synopsis: r[P1]=NULL */
-#define OP_Blob 81 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 82 /* synopsis: r[P2]=parameter(P1,P4) */
-#define OP_Move 83 /* synopsis: r[P2@P3]=r[P1@P3] */
-#define OP_Copy 84 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
-#define OP_SCopy 85 /* synopsis: r[P2]=r[P1] */
-#define OP_IntCopy 86 /* synopsis: r[P2]=r[P1] */
-#define OP_ResultRow 87 /* synopsis: output=r[P1@P2] */
-#define OP_CollSeq 88
-#define OP_Function0 89 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_Function 90 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_AddImm 91 /* synopsis: r[P1]=r[P1]+P2 */
-#define OP_RealAffinity 92
-#define OP_Cast 93 /* synopsis: affinity(r[P1]) */
-#define OP_Permutation 94
-#define OP_Compare 95 /* synopsis: r[P1@P3] <-> r[P2@P3] */
-#define OP_Column 96 /* synopsis: r[P3]=PX */
-#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */
-#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
-#define OP_Count 100 /* synopsis: r[P2]=count() */
-#define OP_ReadCookie 101
-#define OP_SetCookie 102
-#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenAutoindex 106 /* synopsis: nColumn=P2 */
-#define OP_OpenEphemeral 107 /* synopsis: nColumn=P2 */
-#define OP_SorterOpen 108
-#define OP_SequenceTest 109 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
-#define OP_OpenPseudo 110 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 111
-#define OP_ColumnsUsed 112
-#define OP_Sequence 113 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NewRowid 114 /* synopsis: r[P2]=rowid */
-#define OP_Insert 115 /* synopsis: intkey=r[P3] data=r[P2] */
-#define OP_InsertInt 116 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_Delete 117
-#define OP_ResetCount 118
-#define OP_SorterCompare 119 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
-#define OP_SorterData 120 /* synopsis: r[P2]=data */
-#define OP_RowKey 121 /* synopsis: r[P2]=key */
-#define OP_RowData 122 /* synopsis: r[P2]=data */
-#define OP_Rowid 123 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 124
-#define OP_SorterInsert 125
-#define OP_IdxInsert 126 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 127 /* synopsis: key=r[P2@P3] */
-#define OP_Seek 128 /* synopsis: Move P3 to P1.rowid */
-#define OP_IdxRowid 129 /* synopsis: r[P2]=rowid */
-#define OP_Destroy 130
-#define OP_Clear 131
-#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_ResetSorter 133
-#define OP_CreateIndex 134 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 135 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_ParseSchema 136
-#define OP_LoadAnalysis 137
-#define OP_DropTable 138
-#define OP_DropIndex 139
-#define OP_DropTrigger 140
-#define OP_IntegrityCk 141
-#define OP_RowSetAdd 142 /* synopsis: rowset(P1)=r[P2] */
-#define OP_Param 143
-#define OP_FkCounter 144 /* synopsis: fkctr[P1]+=P2 */
-#define OP_MemMax 145 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_OffsetLimit 146 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
-#define OP_AggStep0 147 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggStep 148 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggFinal 149 /* synopsis: accum=r[P1] N=P2 */
-#define OP_Expire 150
-#define OP_TableLock 151 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 152
-#define OP_VCreate 153
-#define OP_VDestroy 154
-#define OP_VOpen 155
-#define OP_VColumn 156 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 157
-#define OP_Pagecount 158
-#define OP_MaxPgcnt 159
-#define OP_CursorHint 160
-#define OP_Noop 161
-#define OP_Explain 162
+#define OP_IfNot 20 /* jump */
+#define OP_IfNullRow 21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT 22 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekLE 23 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGE 24 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGT 25 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IfNotOpen 26 /* jump, synopsis: if( !csr[P1] ) goto P2 */
+#define OP_IfNoHope 27 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */
+#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */
+#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */
+#define OP_Last 33 /* jump */
+#define OP_IfSmaller 34 /* jump */
+#define OP_SorterSort 35 /* jump */
+#define OP_Sort 36 /* jump */
+#define OP_Rewind 37 /* jump */
+#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */
+#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */
+#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
+#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
+#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 46 /* jump */
+#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
+#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
+#define OP_Eq 53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
+#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
+#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
+#define OP_ElseNotEq 58 /* jump, same as TK_ESCAPE */
+#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */
+#define OP_IncrVacuum 60 /* jump */
+#define OP_VNext 61 /* jump */
+#define OP_Init 62 /* jump, synopsis: Start at P2 */
+#define OP_PureFunc 63 /* synopsis: r[P3]=func(r[P2@NP]) */
+#define OP_Function 64 /* synopsis: r[P3]=func(r[P2@NP]) */
+#define OP_Return 65
+#define OP_EndCoroutine 66
+#define OP_HaltIfNull 67 /* synopsis: if r[P3]=null halt */
+#define OP_Halt 68
+#define OP_Integer 69 /* synopsis: r[P2]=P1 */
+#define OP_Int64 70 /* synopsis: r[P2]=P4 */
+#define OP_String 71 /* synopsis: r[P2]='P4' (len=P1) */
+#define OP_Null 72 /* synopsis: r[P2..P3]=NULL */
+#define OP_SoftNull 73 /* synopsis: r[P1]=NULL */
+#define OP_Blob 74 /* synopsis: r[P2]=P4 (len=P1) */
+#define OP_Variable 75 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Move 76 /* synopsis: r[P2@P3]=r[P1@P3] */
+#define OP_Copy 77 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
+#define OP_SCopy 78 /* synopsis: r[P2]=r[P1] */
+#define OP_IntCopy 79 /* synopsis: r[P2]=r[P1] */
+#define OP_ResultRow 80 /* synopsis: output=r[P1@P2] */
+#define OP_CollSeq 81
+#define OP_AddImm 82 /* synopsis: r[P1]=r[P1]+P2 */
+#define OP_RealAffinity 83
+#define OP_Cast 84 /* synopsis: affinity(r[P1]) */
+#define OP_Permutation 85
+#define OP_Compare 86 /* synopsis: r[P1@P3] <-> r[P2@P3] */
+#define OP_IsTrue 87 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
+#define OP_Offset 88 /* synopsis: r[P3] = sqlite_offset(P1) */
+#define OP_Column 89 /* synopsis: r[P3]=PX */
+#define OP_Affinity 90 /* synopsis: affinity(r[P1@P2]) */
+#define OP_MakeRecord 91 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
+#define OP_Count 92 /* synopsis: r[P2]=count() */
+#define OP_ReadCookie 93
+#define OP_SetCookie 94
+#define OP_ReopenIdx 95 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 96 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenWrite 97 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenDup 98
+#define OP_OpenAutoindex 99 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 100 /* synopsis: nColumn=P2 */
+#define OP_BitAnd 101 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 102 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 103 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
+#define OP_ShiftRight 104 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
+#define OP_Add 105 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 106 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 107 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 108 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 109 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 110 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
+#define OP_SorterOpen 111
+#define OP_BitNot 112 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
+#define OP_SequenceTest 113 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
+#define OP_OpenPseudo 114 /* synopsis: P3 columns in r[P2] */
+#define OP_String8 115 /* same as TK_STRING, synopsis: r[P2]='P4' */
+#define OP_Close 116
+#define OP_ColumnsUsed 117
+#define OP_SeekHit 118 /* synopsis: seekHit=P2 */
+#define OP_Sequence 119 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NewRowid 120 /* synopsis: r[P2]=rowid */
+#define OP_Insert 121 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_Delete 122
+#define OP_ResetCount 123
+#define OP_SorterCompare 124 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 125 /* synopsis: r[P2]=data */
+#define OP_RowData 126 /* synopsis: r[P2]=data */
+#define OP_Rowid 127 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 128
+#define OP_SeekEnd 129
+#define OP_IdxInsert 130 /* synopsis: key=r[P2] */
+#define OP_SorterInsert 131 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 132 /* synopsis: key=r[P2@P3] */
+#define OP_DeferredSeek 133 /* synopsis: Move P3 to P1.rowid if needed */
+#define OP_IdxRowid 134 /* synopsis: r[P2]=rowid */
+#define OP_FinishSeek 135
+#define OP_Destroy 136
+#define OP_Clear 137
+#define OP_ResetSorter 138
+#define OP_CreateBtree 139 /* synopsis: r[P2]=root iDb=P1 flags=P3 */
+#define OP_SqlExec 140
+#define OP_ParseSchema 141
+#define OP_LoadAnalysis 142
+#define OP_DropTable 143
+#define OP_DropIndex 144
+#define OP_DropTrigger 145
+#define OP_IntegrityCk 146
+#define OP_RowSetAdd 147 /* synopsis: rowset(P1)=r[P2] */
+#define OP_Param 148
+#define OP_FkCounter 149 /* synopsis: fkctr[P1]+=P2 */
+#define OP_Real 150 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
+#define OP_MemMax 151 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_OffsetLimit 152 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggInverse 153 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */
+#define OP_AggStep 154 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_AggStep1 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_AggValue 156 /* synopsis: r[P3]=value N=P2 */
+#define OP_AggFinal 157 /* synopsis: accum=r[P1] N=P2 */
+#define OP_Expire 158
+#define OP_CursorLock 159
+#define OP_CursorUnlock 160
+#define OP_TableLock 161 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 162
+#define OP_VCreate 163
+#define OP_VDestroy 164
+#define OP_VOpen 165
+#define OP_VColumn 166 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 167
+#define OP_Pagecount 168
+#define OP_MaxPgcnt 169
+#define OP_Trace 170
+#define OP_CursorHint 171
+#define OP_ReleaseReg 172 /* synopsis: release r[P1@P2] mask P3 */
+#define OP_Noop 173
+#define OP_Explain 174
+#define OP_Abortable 175
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -12734,27 +15751,29 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
-/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\
-/* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\
-/* 32 */ 0x09, 0x09, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\
-/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b,\
-/* 64 */ 0x01, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01,\
-/* 72 */ 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10,\
-/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,\
-/* 88 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\
-/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
-/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 112 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00,\
-/* 128 */ 0x00, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\
-/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10,\
-/* 144 */ 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\
-/* 160 */ 0x00, 0x00, 0x00,}
+/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
+/* 8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
+/* 16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
+/* 24 */ 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09,\
+/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
+/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
+/* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
+/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00,\
+/* 64 */ 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\
+/* 72 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
+/* 80 */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x12,\
+/* 88 */ 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
+/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0x26,\
+/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
+/* 112 */ 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\
+/* 120 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
+/* 128 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\
+/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
+/* 144 */ 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x10, 0x04,\
+/* 152 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 168 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+}
/* The sqlite3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
@@ -12762,16 +15781,23 @@ typedef struct VdbeOpList VdbeOpList;
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
-#define SQLITE_MX_JUMP_OPCODE 71 /* Maximum JUMP opcode */
+#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
/*
+** Additional non-public SQLITE_PREPARE_* flags
+*/
+#define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */
+#define SQLITE_PREPARE_MASK 0x0f /* Mask of public flags */
+
+/*
** Prototypes for the VDBE interface. See comments on the implementation
** for a description of what each of these routines does.
*/
SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
+SQLITE_PRIVATE Parse *sqlite3VdbeParser(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
@@ -12782,27 +15808,60 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
+SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(Parse*,int,int,int,int,const FuncDef*,int);
SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe*,int);
#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
+SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p);
#else
# define sqlite3VdbeVerifyNoMallocRequired(A,B)
+# define sqlite3VdbeVerifyNoResultRow(A)
+#endif
+#if defined(SQLITE_DEBUG)
+SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int);
+#else
+# define sqlite3VdbeVerifyAbortable(A,B)
+#endif
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
+#ifndef SQLITE_OMIT_EXPLAIN
+SQLITE_PRIVATE void sqlite3VdbeExplain(Parse*,u8,const char*,...);
+SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*);
+SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*);
+# define ExplainQueryPlan(P) sqlite3VdbeExplain P
+# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P)
+# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P)
+#else
+# define ExplainQueryPlan(P)
+# define ExplainQueryPlanPop(P)
+# define ExplainQueryPlanParent(P) 0
+# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
+#endif
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_EXPLAIN)
+SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char*,const char*);
+#else
+# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
#endif
-SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
-SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
-SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
-SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
-SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5);
+SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
+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 sqlite3VdbeChangeP5(Vdbe*, u16 P5);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
+SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask, int);
+#else
+# define sqlite3VdbeReleaseRegisters(P,A,N,M,F)
+#endif
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
+SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
-SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
+SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
@@ -12821,7 +15880,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int);
SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*));
SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*);
SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*);
-SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
+SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe*);
+SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, u8);
+#ifdef SQLITE_ENABLE_NORMALIZE
+SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3*,Vdbe*,const char*);
+SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(Vdbe*,const char*);
+#endif
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
@@ -12830,17 +15894,22 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int);
SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*);
#endif
SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
+SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*);
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
-SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
+SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
-#ifndef SQLITE_OMIT_TRIGGER
SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
+SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*);
+
+SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*);
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*);
#endif
/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
@@ -12883,23 +15952,52 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
**
** VdbeCoverageNeverTaken(v) // Previous branch is never taken
**
+** VdbeCoverageNeverNull(v) // Previous three-way branch is only
+** // taken on the first two ways. The
+** // NULL option is not possible
+**
+** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
+** // in distingishing equal and not-equal.
+**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch()
** routine in vdbe.c, alerting the developer to the missed tag.
+**
+** During testing, the test application will invoke
+** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
+** routine that is invoked as each bytecode branch is taken. The callback
+** contains the sqlite3.c source line number ov the VdbeCoverage macro and
+** flags to indicate whether or not the branch was taken. The test application
+** is responsible for keeping track of this and reporting byte-code branches
+** that are never taken.
+**
+** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the
+** vdbe.c source file for additional information.
*/
#ifdef SQLITE_VDBE_COVERAGE
SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int);
# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__)
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
-# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
-# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
+# define VdbeCoverageAlwaysTaken(v) \
+ sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000);
+# define VdbeCoverageNeverTaken(v) \
+ sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000);
+# define VdbeCoverageNeverNull(v) \
+ sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
+# define VdbeCoverageNeverNullIf(v,x) \
+ if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
+# define VdbeCoverageEqNe(v) \
+ sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000);
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
#else
# define VdbeCoverage(v)
# define VdbeCoverageIf(v,x)
# define VdbeCoverageAlwaysTaken(v)
# define VdbeCoverageNeverTaken(v)
+# define VdbeCoverageNeverNull(v)
+# define VdbeCoverageNeverNullIf(v,x)
+# define VdbeCoverageEqNe(v)
# define VDBE_OFFSET_LINENO(x) 0
#endif
@@ -12909,250 +16007,13 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
# define sqlite3VdbeScanStatus(a,b,c,d,e)
#endif
-#endif /* SQLITE_VDBE_H */
-
-/************** End of vdbe.h ************************************************/
-/************** Continuing where we left off in sqliteInt.h ******************/
-/************** Include pager.h in the middle of sqliteInt.h *****************/
-/************** Begin file pager.h *******************************************/
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the sqlite page cache
-** subsystem. The page cache subsystem reads and writes a file a page
-** at a time and provides a journal for rollback.
-*/
-
-#ifndef SQLITE_PAGER_H
-#define SQLITE_PAGER_H
-
-/*
-** Default maximum size for persistent journal files. A negative
-** value means no limit. This value may be overridden using the
-** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
-*/
-#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
- #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
-#endif
-
-/*
-** The type used to represent a page number. The first page in a file
-** is called page 1. 0 is used to represent "not a page".
-*/
-typedef u32 Pgno;
-
-/*
-** Each open file is managed by a separate instance of the "Pager" structure.
-*/
-typedef struct Pager Pager;
-
-/*
-** Handle type for pages.
-*/
-typedef struct PgHdr DbPage;
-
-/*
-** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
-** reserved for working around a windows/posix incompatibility). It is
-** used in the journal to signify that the remainder of the journal file
-** is devoted to storing a master journal name - there are no more pages to
-** roll back. See comments for function writeMasterJournal() in pager.c
-** for details.
-*/
-#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
-
-/*
-** Allowed values for the flags parameter to sqlite3PagerOpen().
-**
-** NOTE: These values must match the corresponding BTREE_ values in btree.h.
-*/
-#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
-#define PAGER_MEMORY 0x0002 /* In-memory database */
-
-/*
-** Valid values for the second argument to sqlite3PagerLockingMode().
-*/
-#define PAGER_LOCKINGMODE_QUERY -1
-#define PAGER_LOCKINGMODE_NORMAL 0
-#define PAGER_LOCKINGMODE_EXCLUSIVE 1
-
-/*
-** Numeric constants that encode the journalmode.
-**
-** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
-** are exposed in the API via the "PRAGMA journal_mode" command and
-** therefore cannot be changed without a compatibility break.
-*/
-#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
-#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
-#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
-#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
-#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
-#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
-#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
-
-/*
-** Flags that make up the mask passed to sqlite3PagerGet().
-*/
-#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
-#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
-
-/*
-** Flags for sqlite3PagerSetFlags()
-**
-** Value constraints (enforced via assert()):
-** PAGER_FULLFSYNC == SQLITE_FullFSync
-** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
-** PAGER_CACHE_SPILL == SQLITE_CacheSpill
-*/
-#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
-#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
-#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
-#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
-#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
-#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
-#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
-#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
-#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
-
-/*
-** The remainder of this file contains the declarations of the functions
-** that make up the Pager sub-system API. See source code comments for
-** a detailed description of each routine.
-*/
-
-/* Open and close a Pager connection. */
-SQLITE_PRIVATE int sqlite3PagerOpen(
- sqlite3_vfs*,
- Pager **ppPager,
- const char*,
- int,
- int,
- int,
- void(*)(DbPage*)
-);
-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
-
-/* Functions used to configure a Pager object. */
-SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
-SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
-#ifdef SQLITE_HAS_CODEC
-SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
-#endif
-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
-SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
-SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
-SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
-SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
-SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
-SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
-SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
-SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
-SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
-SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
-SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
-SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
-
-/* Functions used to obtain and release page references. */
-SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
-SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
-SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
-SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
-SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
-
-/* Operations on page references. */
-SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
-SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
-SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
-SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
-SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
-SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
-
-/* Functions used to manage pager transactions and savepoints. */
-SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
-SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
-SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
-SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
-SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster);
-SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
-SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
-SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
-SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
-SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
-
-#ifndef SQLITE_OMIT_WAL
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
-SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
-SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager);
-# ifdef SQLITE_ENABLE_SNAPSHOT
-SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
-# endif
-#else
-# define sqlite3PagerUseWal(x) 0
-#endif
-
-#ifdef SQLITE_ENABLE_ZIPVFS
-SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
-#endif
-
-/* Functions used to query pager state and configuration. */
-SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
-SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
-#ifdef SQLITE_DEBUG
-SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
-#endif
-SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
-SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
-SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
-SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
-SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
-SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
-SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
-
-/* Functions used to truncate the database file. */
-SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
-
-SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
-
-#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
-SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
-#endif
-
-/* Functions to support testing and debugging. */
-#if !defined(NDEBUG) || defined(SQLITE_TEST)
-SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
-SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
-#endif
-#ifdef SQLITE_TEST
-SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
-SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
- void disable_simulated_io_errors(void);
- void enable_simulated_io_errors(void);
-#else
-# define disable_simulated_io_errors()
-# define enable_simulated_io_errors()
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
-#endif /* SQLITE_PAGER_H */
+#endif /* SQLITE_VDBE_H */
-/************** End of pager.h ***********************************************/
+/************** End of vdbe.h ************************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include pcache.h in the middle of sqliteInt.h ****************/
/************** Begin file pcache.h ******************************************/
@@ -13168,7 +16029,7 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
-** subsystem.
+** subsystem.
*/
#ifndef _PCACHE_H_
@@ -13184,6 +16045,7 @@ struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
+ PCache *pCache; /* PRIVATE: Cache that owns this page */
PgHdr *pDirty; /* Transient list of dirty sorted by pgno */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
@@ -13193,14 +16055,15 @@ struct PgHdr {
u16 flags; /* PGHDR flags defined below */
/**********************************************************************
- ** Elements above are public. All that follows is private to pcache.c
- ** and should not be accessed by other modules.
+ ** Elements above, except pCache, are public. All that follow are
+ ** private to pcache.c and should not be accessed by other modules.
+ ** pCache is grouped with the public elements for efficiency.
*/
i16 nRef; /* Number of users of this page */
- PCache *pCache; /* Cache that owns this page */
-
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
+ /* NB: pDirtyNext and pDirtyPrev are undefined if the
+ ** PgHdr object is not dirty */
};
/* Bit values for PgHdr.flags */
@@ -13245,7 +16108,7 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int);
SQLITE_PRIVATE int sqlite3PcacheSize(void);
/* One release per successful fetch. Page is pinned until released.
-** Reference counted.
+** Reference counted.
*/
SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag);
SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**);
@@ -13289,7 +16152,7 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/* Iterate through all dirty pages currently stored in the cache. This
-** interface is only available if SQLITE_CHECK_PAGES is defined when the
+** interface is only available if SQLITE_CHECK_PAGES is defined when the
** library is built.
*/
SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
@@ -13339,6 +16202,10 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
/* Number of dirty pages as a percentage of the configured cache size */
SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
+SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache);
+#endif
+
#endif /* _PCACHE_H_ */
/************** End of pcache.h **********************************************/
@@ -13460,10 +16327,10 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
** 2006-10-31: The default prefix used to be "sqlite_". But then
** Mcafee started using SQLite in their anti-virus product and it
** started putting files with the "sqlite" name in the c:/temp folder.
-** This annoyed many windows users. Those users would then do a
+** This annoyed many windows users. Those users would then do a
** Google search for "sqlite", find the telephone numbers of the
** developers and call to wake them up at night and complain.
-** For this reason, the default name prefix is changed to be "sqlite"
+** For this reason, the default name prefix is changed to be "sqlite"
** spelled backwards. So the temp files are still identified, but
** anybody smart enough to figure out the code is also likely smart
** enough to know that calling the developer will not help get rid
@@ -13504,9 +16371,9 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
** UnlockFile().
**
** LockFile() prevents not just writing but also reading by other processes.
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
+** A SHARED_LOCK is obtained by locking a single randomly-chosen
+** byte out of a specific range of bytes. The lock byte is obtained at
+** random so two separate readers can probably access the file at the
** same time, unless they are unlucky and choose the same lock byte.
** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
** There can only be one writer. A RESERVED_LOCK is obtained by locking
@@ -13525,7 +16392,7 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
** The following #defines specify the range of bytes used for locking.
** SHARED_SIZE is the number of bytes available in the pool from which
** a random byte is selected for a shared lock. The pool of bytes for
-** shared locks begins at SHARED_FIRST.
+** shared locks begins at SHARED_FIRST.
**
** The same locking strategy and
** byte ranges are used for Unix. This leaves open the possibility of having
@@ -13541,7 +16408,7 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
** that all locks will fit on a single page even at the minimum page size.
** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
** is set high so that we don't have to allocate an unused page except
-** for very large databases. But one should test the page skipping logic
+** for very large databases. But one should test the page skipping logic
** by setting PENDING_BYTE low and running the entire regression suite.
**
** Changing the value of PENDING_BYTE results in a subtly incompatible
@@ -13565,8 +16432,8 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
*/
SQLITE_PRIVATE int sqlite3OsInit(void);
-/*
-** Functions for accessing sqlite3_file methods
+/*
+** Functions for accessing sqlite3_file methods
*/
SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
@@ -13582,16 +16449,18 @@ SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
+#endif /* SQLITE_OMIT_WAL */
SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
-/*
-** Functions for accessing sqlite3_vfs methods
+/*
+** Functions for accessing sqlite3_vfs methods
*/
SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
@@ -13609,7 +16478,7 @@ SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
-** Convenience functions for opening and closing files using
+** Convenience functions for opening and closing files using
** sqlite3_malloc() to obtain space for the file-handle structure.
*/
SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
@@ -13679,9 +16548,9 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
*/
#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
#define sqlite3_mutex_free(X)
-#define sqlite3_mutex_enter(X)
+#define sqlite3_mutex_enter(X)
#define sqlite3_mutex_try(X) SQLITE_OK
-#define sqlite3_mutex_leave(X)
+#define sqlite3_mutex_leave(X)
#define sqlite3_mutex_held(X) ((void)(X),1)
#define sqlite3_mutex_notheld(X) ((void)(X),1)
#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
@@ -13690,6 +16559,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
#define MUTEX_LOGIC(X)
#else
#define MUTEX_LOGIC(X) X
+SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
#endif /* defined(SQLITE_MUTEX_OMIT) */
/************** End of mutex.h ***********************************************/
@@ -13720,7 +16590,7 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
** and the one-based values are used internally.
*/
#ifndef SQLITE_DEFAULT_SYNCHRONOUS
-# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1)
+# define SQLITE_DEFAULT_SYNCHRONOUS 2
#endif
#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
@@ -13793,7 +16663,7 @@ struct Schema {
*/
#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
#define DB_UnresetViews 0x0002 /* Some views have defined column names */
-#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */
+#define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */
/*
** The number of different kinds of things that can be limited
@@ -13820,15 +16690,47 @@ struct Schema {
** is shared by multiple database connections. Therefore, while parsing
** schema information, the Lookaside.bEnabled flag is cleared so that
** lookaside allocations are not used to construct the schema objects.
+**
+** New lookaside allocations are only allowed if bDisable==0. When
+** bDisable is greater than zero, sz is set to zero which effectively
+** disables lookaside without adding a new test for the bDisable flag
+** in a performance-critical path. sz should be set by to szTrue whenever
+** bDisable changes back to zero.
+**
+** Lookaside buffers are initially held on the pInit list. As they are
+** used and freed, they are added back to the pFree list. New allocations
+** come off of pFree first, then pInit as a fallback. This dual-list
+** allows use to compute a high-water mark - the maximum number of allocations
+** outstanding at any point in the past - by subtracting the number of
+** allocations on the pInit list from the total number of allocations.
+**
+** Enhancement on 2019-12-12: Two-size-lookaside
+** The default lookaside configuration is 100 slots of 1200 bytes each.
+** The larger slot sizes are important for performance, but they waste
+** a lot of space, as most lookaside allocations are less than 128 bytes.
+** The two-size-lookaside enhancement breaks up the lookaside allocation
+** into two pools: One of 128-byte slots and the other of the default size
+** (1200-byte) slots. Allocations are filled from the small-pool first,
+** failing over to the full-size pool if that does not work. Thus more
+** lookaside slots are available while also using less memory.
+** This enhancement can be omitted by compiling with
+** SQLITE_OMIT_TWOSIZE_LOOKASIDE.
*/
struct Lookaside {
u32 bDisable; /* Only operate the lookaside when zero */
u16 sz; /* Size of each buffer in bytes */
+ u16 szTrue; /* True value of sz, even if disabled */
u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */
- int nOut; /* Number of buffers currently checked out */
- int mxOut; /* Highwater mark for nOut */
- int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
+ u32 nSlot; /* Number of lookaside slots allocated */
+ u32 anStat[3]; /* 0: hits. 1: size misses. 2: full misses */
+ LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
+ LookasideSlot *pSmallFree; /* List of available small buffers */
+ void *pMiddle; /* First byte past end of full-size buffers and
+ ** the first byte of LOOKASIDE_SMALL buffers */
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
};
@@ -13836,17 +16738,30 @@ struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
};
+#define DisableLookaside db->lookaside.bDisable++;db->lookaside.sz=0
+#define EnableLookaside db->lookaside.bDisable--;\
+ db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue
+
+/* Size of the smaller allocations in two-size lookside */
+#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+# define LOOKASIDE_SMALL 0
+#else
+# define LOOKASIDE_SMALL 128
+#endif
+
/*
** A hash table for built-in function definitions. (Application-defined
** functions use a regular table table from hash.h.)
**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
-** Collisions are on the FuncDef.u.pHash chain.
+** Collisions are on the FuncDef.u.pHash chain. Use the SQLITE_FUNC_HASH()
+** macro to compute a hash on the function name.
*/
#define SQLITE_FUNC_HASH_SZ 23
struct FuncDefHash {
FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
};
+#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ)
#ifdef SQLITE_USER_AUTHENTICATION
/*
@@ -13890,10 +16805,13 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
** in the style of sqlite3_trace()
*/
-#define SQLITE_TRACE_LEGACY 0x80
+#define SQLITE_TRACE_LEGACY 0x40 /* Use the legacy xTrace */
+#define SQLITE_TRACE_XPROFILE 0x80 /* Use the legacy xProfile */
#else
-#define SQLITE_TRACE_LEGACY 0
+#define SQLITE_TRACE_LEGACY 0
+#define SQLITE_TRACE_XPROFILE 0
#endif /* SQLITE_OMIT_DEPRECATED */
+#define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */
/*
@@ -13902,13 +16820,15 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
struct sqlite3 {
sqlite3_vfs *pVfs; /* OS Interface */
struct Vdbe *pVdbe; /* List of active virtual machines */
- CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
+ CollSeq *pDfltColl; /* BINARY collseq for the database encoding */
sqlite3_mutex *mutex; /* Connection mutex */
Db *aDb; /* All backends */
int nDb; /* Number of backends currently in use */
- int flags; /* Miscellaneous flags. See below */
+ u32 mDbFlags; /* flags recording internal state */
+ u64 flags; /* flags settable by pragmas. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 szMmap; /* Default mmap_size setting */
+ u32 nSchemaLock; /* Do not reset the schema when non-zero */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
@@ -13925,6 +16845,8 @@ struct sqlite3 {
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
u8 mTrace; /* zero or more SQLITE_TRACE flags */
+ u8 noSharedCache; /* True if no shared-cache backends */
+ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
@@ -13932,11 +16854,13 @@ struct sqlite3 {
int aLimit[SQLITE_N_LIMIT]; /* Limits */
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
struct sqlite3InitInfo { /* Information used during initialization */
- int newTnum; /* Rootpage of table being initialized */
+ Pgno newTnum; /* Rootpage of table being initialized */
u8 iDb; /* Which db file is being initialized */
u8 busy; /* TRUE if currently initializing */
- u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
- u8 imposterTable; /* Building an imposter table */
+ unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
+ unsigned imposterTable : 1; /* Building an imposter table */
+ unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
+ char **azInit; /* "type", "name", and "tbl_name" columns */
} init;
int nVdbeActive; /* Number of VDBEs currently running */
int nVdbeRead; /* Number of active VDBEs that read or write */
@@ -13945,16 +16869,22 @@ struct sqlite3 {
int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
- int (*xTrace)(u32,void*,void*,void*); /* Trace function */
+ union {
+ void (*xLegacy)(void*,const char*); /* Legacy trace function */
+ int (*xV2)(u32,void*,void*,void*); /* V2 Trace function */
+ } trace;
void *pTraceArg; /* Argument to the trace function */
+#ifndef SQLITE_OMIT_DEPRECATED
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
+#endif
void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*); /* Invoked at every commit. */
void *pRollbackArg; /* Argument to xRollbackCallback() */
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
+ Parse *pParse; /* Current parse */
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
void *pPreUpdateArg; /* First argument to xPreUpdateCallback */
void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */
@@ -13989,13 +16919,14 @@ struct sqlite3 {
Hash aModule; /* populated by sqlite3_create_module() */
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
- VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
+ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
Hash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
Db aDbStatic[2]; /* Static space for the 2 default backends */
Savepoint *pSavepoint; /* List of active savepoints */
+ int nAnalysisLimit; /* Number of index rows to ANALYZE */
int busyTimeout; /* Busy handler timeout, in msec */
int nSavepoint; /* Number of non-transaction savepoints */
int nStatement; /* Number of nested statement-transactions */
@@ -14003,7 +16934,7 @@ struct sqlite3 {
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
- /* The following variables are all protected by the STATIC_MASTER
+ /* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
@@ -14031,6 +16962,13 @@ struct sqlite3 {
#define ENC(db) ((db)->enc)
/*
+** A u64 constant where the lower 32 bits are all zeros. Only the
+** upper 32 bits are included in the argument. Necessary because some
+** C-compilers still do not accept LL integer literals.
+*/
+#define HI(X) ((u64)(X)<<32)
+
+/*
** Possible values for the sqlite3.flags.
**
** Value constraints (enforced via assert()):
@@ -14038,41 +16976,64 @@ struct sqlite3 {
** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
-#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
-#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
+#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */
+#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync 0x00000010 /* Use full fsync for checkpoint */
#define SQLITE_CacheSpill 0x00000020 /* OK to spill pager cache */
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
-#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
- /* DELETE, or UPDATE and return */
- /* the count using a callback. */
+#define SQLITE_TrustedSchema 0x00000080 /* Allow unsafe functions and
+ ** vtabs in the schema definition */
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
-#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
-#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
-#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
-#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */
-#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */
-#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
-#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */
-#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */
-#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */
-#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */
-#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */
-#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */
-#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
-#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */
-#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */
-#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */
-#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */
-#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */
-#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
+#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */
+#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */
+#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */
+#define SQLITE_ForeignKeys 0x00004000 /* Enforce foreign key constraints */
+#define SQLITE_AutoIndex 0x00008000 /* Enable automatic indexes */
+#define SQLITE_LoadExtension 0x00010000 /* Enable load_extension */
+#define SQLITE_LoadExtFunc 0x00020000 /* Enable load_extension() SQL func */
+#define SQLITE_EnableTrigger 0x00040000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x00080000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x00100000 /* Disable database changes */
+#define SQLITE_CellSizeCk 0x00200000 /* Check btree cell sizes on load */
+#define SQLITE_Fts3Tokenizer 0x00400000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_EnableQPSG 0x00800000 /* Query Planner Stability Guarantee*/
+#define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */
+#define SQLITE_ResetDatabase 0x02000000 /* Reset the database */
+#define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */
+#define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/
+#define SQLITE_Defensive 0x10000000 /* Input SQL is likely hostile */
+#define SQLITE_DqsDDL 0x20000000 /* dbl-quoted strings allowed in DDL*/
+#define SQLITE_DqsDML 0x40000000 /* dbl-quoted strings allowed in DML*/
+#define SQLITE_EnableView 0x80000000 /* Enable the use of views */
+#define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */
+ /* DELETE, or UPDATE and return */
+ /* the count using a callback. */
+
+/* Flags used only if debugging */
+#ifdef SQLITE_DEBUG
+#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */
+#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */
+#define SQLITE_VdbeTrace HI(0x0400000) /* True to trace VDBE execution */
+#define SQLITE_VdbeAddopTrace HI(0x0800000) /* Trace sqlite3VdbeAddOp() calls */
+#define SQLITE_VdbeEQP HI(0x1000000) /* Debug EXPLAIN QUERY PLAN */
+#define SQLITE_ParserTrace HI(0x2000000) /* PRAGMA parser_trace=ON */
+#endif
+/*
+** Allowed values for sqlite3.mDbFlags
+*/
+#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */
+#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */
+#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */
+#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */
+#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */
+#define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */
+#define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */
/*
** Bits of the sqlite3.dbOptFlags field that are used by the
@@ -14080,30 +17041,29 @@ struct sqlite3 {
** selectively disable various optimizations.
*/
#define SQLITE_QueryFlattener 0x0001 /* Query flattening */
-#define SQLITE_ColumnCache 0x0002 /* Column cache */
+#define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */
#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
-/* not used 0x0010 // Was: SQLITE_IdxRealAsInt */
-#define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */
-#define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */
-#define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */
-#define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */
-#define SQLITE_Transitive 0x0200 /* Transitive constraints */
-#define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */
-#define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */
-#define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */
+#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */
+#define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */
+#define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */
+#define SQLITE_Transitive 0x0080 /* Transitive constraints */
+#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */
+#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */
+#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */
+#define SQLITE_Stat4 0x0800 /* Use STAT4 data */
+ /* TH3 expects the Stat4 ^^^^^^ value to be 0x0800. Don't change it */
+#define SQLITE_PushDown 0x1000 /* The push-down optimization */
+#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
+#define SQLITE_SkipScan 0x4000 /* Skip-scans */
+#define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
** Macros for testing whether or not optimizations are enabled or disabled.
*/
-#ifndef SQLITE_OMIT_BUILTIN_TEST
#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0)
#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0)
-#else
-#define OptimizationDisabled(db, mask) 0
-#define OptimizationEnabled(db, mask) 1
-#endif
/*
** Return true if it OK to factor constant expressions into the initialization
@@ -14135,11 +17095,13 @@ struct sqlite3 {
*/
struct FuncDef {
i8 nArg; /* Number of arguments. -1 means unlimited */
- u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
+ u32 funcFlags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
void (*xFinalize)(sqlite3_context*); /* Agg finalizer */
+ void (*xValue)(sqlite3_context*); /* Current agg value */
+ void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */
const char *zName; /* SQL name of the function. */
union {
FuncDef *pHash; /* Next with a different name but the same hash */
@@ -14178,6 +17140,8 @@ struct FuncDestructor {
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
+** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
+** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
*/
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
@@ -14188,12 +17152,29 @@ struct FuncDestructor {
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
+/* 0x0200 -- available for reuse */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
+#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
+#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
+#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
+#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
+#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
+#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
+#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */
+#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */
+
+/* Identifier numbers for each in-line function */
+#define INLINEFUNC_coalesce 0
+#define INLINEFUNC_implies_nonnull_row 1
+#define INLINEFUNC_expr_implies_expr 2
+#define INLINEFUNC_expr_compare 3
+#define INLINEFUNC_affinity 4
+#define INLINEFUNC_iif 5
+#define INLINEFUNC_unlikely 99 /* Default case */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -14209,11 +17190,34 @@ struct FuncDestructor {
** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
**
+** SFUNCTION(zName, nArg, iArg, bNC, xFunc)
+** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
+** adds the SQLITE_DIRECTONLY flag.
+**
+** INLINE_FUNC(zName, nArg, iFuncId, mFlags)
+** zName is the name of a function that is implemented by in-line
+** byte code rather than by the usual callbacks. The iFuncId
+** parameter determines the function id. The mFlags parameter is
+** optional SQLITE_FUNC_ flags for this function.
+**
+** TEST_FUNC(zName, nArg, iFuncId, mFlags)
+** zName is the name of a test-only function implemented by in-line
+** byte code rather than by the usual callbacks. The iFuncId
+** parameter determines the function id. The mFlags parameter is
+** optional SQLITE_FUNC_ flags for this function.
+**
** DFUNCTION(zName, nArg, iArg, bNC, xFunc)
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions
** and functions like sqlite_version() that can change, but not during
-** a single query.
+** a single query. The iArg is ignored. The user-data is always set
+** to a NULL pointer. The bNC parameter is not used.
+**
+** PURE_DATE(zName, nArg, iArg, bNC, xFunc)
+** Used for "pure" date/time functions, this macro is like DFUNCTION
+** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is
+** ignored and the user-data for these functions is set to an
+** arbitrary non-NULL pointer. The bNC parameter is not used.
**
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
** Used to create an aggregate function definition implemented by
@@ -14221,6 +17225,12 @@ struct FuncDestructor {
** are interpreted in the same way as the first 4 parameters to
** FUNCTION().
**
+** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
+** Used to create an aggregate function definition implemented by
+** the C functions xStep and xFinal. The first four parameters
+** are interpreted in the same way as the first 4 parameters to
+** FUNCTION().
+**
** LIKEFUNC(zName, nArg, pArg, flags)
** Used to create a scalar function definition of a function zName
** that accepts nArg arguments and is implemented by a call to C
@@ -14231,28 +17241,42 @@ struct FuncDestructor {
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
+ {nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
+ {nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
+ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
+#define TEST_FUNC(zName, nArg, iArg, mFlags) \
+ {nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
+ SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
+ SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
- {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
+ 0, 0, xFunc, 0, 0, 0, #zName, {0} }
+#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
+ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
+ (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} }
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- pArg, 0, xFunc, 0, #zName, }
+ pArg, 0, xFunc, 0, 0, 0, #zName, }
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
- (void *)arg, 0, likeFunc, 0, #zName, {0} }
-#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
- {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
-#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
- {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
- SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
+ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }
+#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \
+ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
+ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
+#define INTERNAL_FUNCTION(zName, nArg, xFunc) \
+ {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
+ 0, 0, xFunc, 0, 0, 0, #zName, {0} }
+
/*
** All current savepoints are stored in a linked list starting at
@@ -14284,30 +17308,53 @@ struct Savepoint {
struct Module {
const sqlite3_module *pModule; /* Callback pointers */
const char *zName; /* Name passed to create_module() */
+ int nRefModule; /* Number of pointers to this object */
void *pAux; /* pAux passed to create_module() */
void (*xDestroy)(void *); /* Module destructor function */
Table *pEpoTab; /* Eponymous table for this module */
};
/*
-** information about each column of an SQL table is held in an instance
-** of this structure.
+** Information about each column of an SQL table is held in an instance
+** of the Column structure, in the Table.aCol[] array.
+**
+** Definitions:
+**
+** "table column index" This is the index of the column in the
+** Table.aCol[] array, and also the index of
+** the column in the original CREATE TABLE stmt.
+**
+** "storage column index" This is the index of the column in the
+** record BLOB generated by the OP_MakeRecord
+** opcode. The storage column index is less than
+** or equal to the table column index. It is
+** equal if and only if there are no VIRTUAL
+** columns to the left.
*/
struct Column {
char *zName; /* Name of this column, \000, then the type */
- Expr *pDflt; /* Default value of this column */
+ Expr *pDflt; /* Default value or GENERATED ALWAYS AS value */
char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */
- u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */
+ u8 hName; /* Column name hash for faster lookup */
+ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
};
/* Allowed values for Column.colFlags:
*/
-#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
-#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
-#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
+#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
+#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
+#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
+#define COLFLAG_UNIQUE 0x0008 /* Column def contains "UNIQUE" or "PK" */
+#define COLFLAG_SORTERREF 0x0010 /* Use sorter-refs with this column */
+#define COLFLAG_VIRTUAL 0x0020 /* GENERATED ALWAYS AS ... VIRTUAL */
+#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */
+#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */
+#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */
+#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
+#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */
/*
** A "Collating Sequence" is defined by an instance of the following
@@ -14347,11 +17394,12 @@ struct CollSeq {
** Note also that the numeric types are grouped together so that testing
** for a numeric type is a single comparison. And the BLOB type is first.
*/
-#define SQLITE_AFF_BLOB 'A'
-#define SQLITE_AFF_TEXT 'B'
-#define SQLITE_AFF_NUMERIC 'C'
-#define SQLITE_AFF_INTEGER 'D'
-#define SQLITE_AFF_REAL 'E'
+#define SQLITE_AFF_NONE 0x40 /* '@' */
+#define SQLITE_AFF_BLOB 0x41 /* 'A' */
+#define SQLITE_AFF_TEXT 0x42 /* 'B' */
+#define SQLITE_AFF_NUMERIC 0x43 /* 'C' */
+#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
+#define SQLITE_AFF_REAL 0x45 /* 'E' */
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
@@ -14424,10 +17472,17 @@ struct VTable {
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
};
+/* Allowed values for VTable.eVtabRisk
+*/
+#define SQLITE_VTABRISK_Low 0
+#define SQLITE_VTABRISK_Normal 1
+#define SQLITE_VTABRISK_High 2
+
/*
** The schema for each SQL table and view is represented in memory
** by an instance of the following structure.
@@ -14441,16 +17496,17 @@ struct Table {
char *zColAff; /* String defining the affinity of each column */
ExprList *pCheck; /* All CHECK constraints */
/* ... also used as column name list in a VIEW */
- int tnum; /* Root BTree page for this table */
+ Pgno tnum; /* Root BTree page for this table */
+ u32 nTabRef; /* Number of pointers to this Table */
+ u32 tabFlags; /* Mask of TF_* values */
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
i16 nCol; /* Number of columns in this table */
- u16 nRef; /* Number of pointers to this Table */
+ i16 nNVCol; /* Number of columns that are not VIRTUAL */
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
LogEst szTabRow; /* Estimated size of each table row in bytes */
#ifdef SQLITE_ENABLE_COSTMULT
LogEst costMult; /* Cost multiplier for using this table */
#endif
- u8 tabFlags; /* Mask of TF_* values */
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
#ifndef SQLITE_OMIT_ALTERTABLE
int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
@@ -14472,17 +17528,28 @@ struct Table {
** followed by non-hidden columns. Example: "CREATE VIRTUAL TABLE x USING
** vtab1(a HIDDEN, b);". Since "b" is a non-hidden column but "a" is hidden,
** the TF_OOOHidden attribute would apply in this case. Such tables require
-** special handling during INSERT processing.
-*/
-#define TF_Readonly 0x01 /* Read-only system table */
-#define TF_Ephemeral 0x02 /* An ephemeral table */
-#define TF_HasPrimaryKey 0x04 /* Table has a primary key */
-#define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */
-#define TF_Virtual 0x10 /* Is a virtual table */
-#define TF_WithoutRowid 0x20 /* No rowid. PRIMARY KEY is the key */
-#define TF_NoVisibleRowid 0x40 /* No user-visible "rowid" column */
-#define TF_OOOHidden 0x80 /* Out-of-Order hidden columns */
-
+** special handling during INSERT processing. The "OOO" means "Out Of Order".
+**
+** Constraints:
+**
+** TF_HasVirtual == COLFLAG_Virtual
+** TF_HasStored == COLFLAG_Stored
+*/
+#define TF_Readonly 0x0001 /* Read-only system table */
+#define TF_Ephemeral 0x0002 /* An ephemeral table */
+#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */
+#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */
+#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */
+#define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */
+#define TF_HasStored 0x0040 /* Has one or more STORED columns */
+#define TF_HasGenerated 0x0060 /* Combo: HasVirtual + HasStored */
+#define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */
+#define TF_StatsUsed 0x0100 /* Query planner decisions affected by
+ ** Index.aiRowLogEst[] values */
+#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */
+#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
+#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
+#define TF_Shadow 0x1000 /* True for a shadow table */
/*
** Test to see whether or not a table is a virtual table. This is
@@ -14490,9 +17557,12 @@ struct Table {
** table support is omitted from the build.
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
-# define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0)
+# define IsVirtual(X) ((X)->nModuleArg)
+# define ExprIsVtab(X) \
+ ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->nModuleArg)
#else
# define IsVirtual(X) 0
+# define ExprIsVtab(X) 0
#endif
/*
@@ -14593,13 +17663,12 @@ struct FKey {
#define OE_Fail 3 /* Stop the operation but leave all prior changes */
#define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */
#define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */
-
-#define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
-#define OE_SetNull 7 /* Set the foreign key value to NULL */
-#define OE_SetDflt 8 /* Set the foreign key value to its default */
-#define OE_Cascade 9 /* Cascade the changes */
-
-#define OE_Default 10 /* Do whatever the default action is */
+#define OE_Update 6 /* Process as a DO UPDATE in an upsert */
+#define OE_Restrict 7 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */
+#define OE_SetNull 8 /* Set the foreign key value to NULL */
+#define OE_SetDflt 9 /* Set the foreign key value to its default */
+#define OE_Cascade 10 /* Cascade the changes */
+#define OE_Default 11 /* Do whatever the default action is */
/*
@@ -14614,14 +17683,20 @@ struct FKey {
struct KeyInfo {
u32 nRef; /* Number of references to this KeyInfo object */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
- u16 nField; /* Number of key columns in the index */
- u16 nXField; /* Number of columns beyond the key columns */
+ u16 nKeyField; /* Number of key columns in the index */
+ u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
- u8 *aSortOrder; /* Sort order for each column. */
+ u8 *aSortFlags; /* Sort order for each column. */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
};
/*
+** Allowed bit values for entries in the KeyInfo.aSortFlags[] array.
+*/
+#define KEYINFO_ORDER_DESC 0x01 /* DESC sort order */
+#define KEYINFO_ORDER_BIGNULL 0x02 /* NULL is larger than any other value */
+
+/*
** This object holds a record which has been parsed out into individual
** fields, for the purposes of doing a comparison.
**
@@ -14662,8 +17737,8 @@ struct UnpackedRecord {
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
- i8 r1; /* Value to return if (lhs > rhs) */
- i8 r2; /* Value to return if (rhs < lhs) */
+ i8 r1; /* Value to return if (lhs < rhs) */
+ i8 r2; /* Value to return if (lhs > rhs) */
u8 eqSeen; /* True if an equality comparison has been seen */
};
@@ -14695,7 +17770,7 @@ struct UnpackedRecord {
** element.
**
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
-** generate VDBE code (as opposed to parsing one read from an sqlite_master
+** generate VDBE code (as opposed to parsing one read from an sqlite_schema
** table as part of parsing an existing database schema), transient instances
** of this structure may be created. In this case the Index.tnum variable is
** used to store the address of a VDBE instruction, not a database page
@@ -14714,18 +17789,22 @@ struct Index {
const char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
ExprList *aColExpr; /* Column expressions */
- int tnum; /* DB Page containing root of this index */
+ Pgno tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */
u16 nColumn; /* Number of columns stored in the index */
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
- unsigned idxType:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
+ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
unsigned bUnordered:1; /* Use this index for == or IN queries only */
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
unsigned isResized:1; /* True if resizeIndexObject() has been called */
unsigned isCovering:1; /* True if this is a covering index */
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
+ unsigned bNoQuery:1; /* Do not use this index to optimize queries */
+ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
+ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
+#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
@@ -14733,6 +17812,7 @@ struct Index {
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
+ Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */
};
/*
@@ -14741,6 +17821,7 @@ struct Index {
#define SQLITE_IDXTYPE_APPDEF 0 /* Created using CREATE INDEX */
#define SQLITE_IDXTYPE_UNIQUE 1 /* Implements a UNIQUE constraint */
#define SQLITE_IDXTYPE_PRIMARYKEY 2 /* Is the PRIMARY KEY for the table */
+#define SQLITE_IDXTYPE_IPK 3 /* INTEGER PRIMARY KEY index */
/* Return true if index X is a PRIMARY KEY index */
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
@@ -14755,7 +17836,7 @@ struct Index {
#define XN_EXPR (-2) /* Indexed column is an expression */
/*
-** Each sample stored in the sqlite_stat3 table is represented in memory
+** Each sample stored in the sqlite_stat4 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
@@ -14768,12 +17849,20 @@ struct IndexSample {
};
/*
+** Possible values to use within the flags argument to sqlite3GetToken().
+*/
+#define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */
+#define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */
+
+/*
** Each token coming out of the lexer is an instance of
** this structure. Tokens are also used as part of an expression.
**
-** Note if Token.z==0 then Token.dyn and Token.n are undefined and
-** may contain random values. Do not make any assumptions about Token.dyn
-** and Token.n when Token.z==0.
+** The memory that "z" points to is owned by other objects. Take care
+** that the owner of the "z" string does not deallocate the string before
+** the Token goes out of scope! Very often, the "z" points to some place
+** in the middle of the Parse.zSql text. But it might also point to a
+** static string.
*/
struct Token {
const char *z; /* Text of the token. Not NULL-terminated! */
@@ -14785,7 +17874,7 @@ struct Token {
** code for a SELECT that contains aggregate functions.
**
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
-** pointer to this structure. The Expr.iColumn field is the index in
+** pointer to this structure. The Expr.iAgg field is the index in
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
** code for that node.
**
@@ -14805,23 +17894,25 @@ struct AggInfo {
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
+ Expr *pCExpr; /* The original expression */
int iTable; /* Cursor number of the source table */
- int iColumn; /* Column number within the source table */
- int iSorterColumn; /* Column number in the sorting index */
int iMem; /* Memory location that acts as accumulator */
- Expr *pExpr; /* The original expression */
+ i16 iColumn; /* Column number within the source table */
+ i16 iSorterColumn; /* Column number in the sorting index */
} *aCol;
int nColumn; /* Number of used entries in aCol[] */
int nAccumulator; /* Number of columns that show through to the output.
** Additional columns are used only as parameters to
** aggregate functions */
struct AggInfo_func { /* For each aggregate function */
- Expr *pExpr; /* Expression encoding the function */
+ Expr *pFExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
+ u32 selId; /* Select to which this AggInfo belongs */
+ AggInfo *pNext; /* Next in list of them all */
};
/*
@@ -14831,10 +17922,10 @@ struct AggInfo {
** it uses less memory in the Expr object, which is a big memory user
** in systems with lots of prepared statements. And few applications
** need more than about 10 or 20 variables. But some extreme users want
-** to have prepared statements with over 32767 variables, and for them
+** to have prepared statements with over 32766 variables, and for them
** the option is available (at compile-time).
*/
-#if SQLITE_MAX_VARIABLE_NUMBER<=32767
+#if SQLITE_MAX_VARIABLE_NUMBER<32767
typedef i16 ynVar;
#else
typedef int ynVar;
@@ -14905,7 +17996,14 @@ typedef int ynVar;
*/
struct Expr {
u8 op; /* Operation performed by this node */
- char affinity; /* The affinity of the column or 0 if not a column */
+ char affExpr; /* affinity, or RAISE type */
+ u8 op2; /* TK_REGISTER/TK_TRUTH: original value of Expr.op
+ ** TK_COLUMN: the value of p5 for OP_Column
+ ** TK_AGG_FUNCTION: nesting depth
+ ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */
+#ifdef SQLITE_DEBUG
+ u8 vvaFlags; /* Verification flags. */
+#endif
u32 flags; /* Various flags. EP_* See below */
union {
char *zToken; /* Token value. Zero terminated and dequoted */
@@ -14936,51 +18034,71 @@ struct Expr {
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
** EP_Unlikely: 134217728 times likelihood
+ ** TK_IN: ephemerial table holding RHS
+ ** TK_SELECT_COLUMN: Number of columns on the LHS
** TK_SELECT: 1st register of result vector */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
** TK_VARIABLE: variable number (always >= 1).
** TK_SELECT_COLUMN: column of the result vector */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
- u8 op2; /* TK_REGISTER: original value of Expr.op
- ** TK_COLUMN: the value of p5 for OP_Column
- ** TK_AGG_FUNCTION: nesting depth */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
- Table *pTab; /* Table for TK_COLUMN expressions. */
+ union {
+ Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
+ ** for a column of an index on an expression */
+ Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
+ struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
+ int iAddr; /* Subroutine entry address */
+ int regReturn; /* Register used to hold return address */
+ } sub;
+ } y;
};
/*
** The following are the meanings of bits in the Expr.flags field.
-*/
-#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
-#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
-#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
-#define EP_Error 0x000008 /* Expression contains one or more errors */
-#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
-#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
-#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
-#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
-#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
-#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
-#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
-#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
-#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
-#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
-#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
-#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */
-#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
-#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
-#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
-#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
-#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
-#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
-#define EP_Alias 0x400000 /* Is an alias for a result set column */
-#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
-
-/*
-** Combinations of two or more EP_* flags
-*/
-#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
+** Value restrictions:
+**
+** EP_Agg == NC_HasAgg == SF_HasAgg
+** EP_Win == NC_HasWin
+*/
+#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
+#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
+#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
+#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
+#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
+#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
+#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
+#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
+#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
+#define EP_Commuted 0x000200 /* Comparison operator has been commuted */
+#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
+#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
+#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
+#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
+#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
+#define EP_Win 0x008000 /* Contains window functions */
+#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
+ /* 0x020000 // available for reuse */
+#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
+#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
+#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
+#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
+#define EP_Alias 0x400000 /* Is an alias for a result set column */
+#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
+#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
+#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
+#define EP_Quoted 0x4000000 /* TK_ID was originally quoted */
+#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
+#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
+#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
+#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
+ /* 0x80000000 // Available */
+
+/*
+** The EP_Propagate mask is a set of properties that automatically propagate
+** upwards into parent nodes.
+*/
+#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
/*
** These macros can be used to test, set, or clear bits in the
@@ -14990,15 +18108,27 @@ struct Expr {
#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
#define ExprSetProperty(E,P) (E)->flags|=(P)
#define ExprClearProperty(E,P) (E)->flags&=~(P)
+#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue)
+#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse)
+
+
+/* Flags for use with Expr.vvaFlags
+*/
+#define EP_NoReduce 0x01 /* Cannot EXPRDUP_REDUCE this Expr */
+#define EP_Immutable 0x02 /* Do not change this Expr node */
/* The ExprSetVVAProperty() macro is used for Verification, Validation,
** and Accreditation only. It works like ExprSetProperty() during VVA
** processes but is a no-op for delivery.
*/
#ifdef SQLITE_DEBUG
-# define ExprSetVVAProperty(E,P) (E)->flags|=(P)
+# define ExprSetVVAProperty(E,P) (E)->vvaFlags|=(P)
+# define ExprHasVVAProperty(E,P) (((E)->vvaFlags&(P))!=0)
+# define ExprClearVVAProperties(E) (E)->vvaFlags = 0
#else
# define ExprSetVVAProperty(E,P)
+# define ExprHasVVAProperty(E,P) 0
+# define ExprClearVVAProperties(E)
#endif
/*
@@ -15017,6 +18147,18 @@ struct Expr {
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
/*
+** True if the expression passed as an argument was a function with
+** an OVER() clause (a window function).
+*/
+#ifdef SQLITE_OMIT_WINDOWFUNC
+# define IsWindowFunc(p) 0
+#else
+# define IsWindowFunc(p) ( \
+ ExprHasProperty((p), EP_WinFunc) && p->y.pWin->eFrmType!=TK_FILTER \
+ )
+#endif
+
+/*
** A list of expressions. Each expression may optionally have a
** name. An expr/name combination can be used in several ways, such
** as the list of "expr AS ID" fields following a "SELECT" or in the
@@ -15024,24 +18166,31 @@ struct Expr {
** also be used as the argument to a function, in which case the a.zName
** field is not used.
**
-** By default the Expr.zSpan field holds a human-readable description of
-** the expression that is used in the generation of error messages and
-** column labels. In this case, Expr.zSpan is typically the text of a
-** column expression as it exists in a SELECT statement. However, if
-** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name
-** of the result column in the form: DATABASE.TABLE.COLUMN. This later
-** form is used for name resolution with nested FROM clauses.
+** In order to try to keep memory usage down, the Expr.a.zEName field
+** is used for multiple purposes:
+**
+** eEName Usage
+** ---------- -------------------------
+** ENAME_NAME (1) the AS of result set column
+** (2) COLUMN= of an UPDATE
+**
+** ENAME_TAB DB.TABLE.NAME used to resolve names
+** of subqueries
+**
+** ENAME_SPAN Text of the original result set
+** expression.
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
struct ExprList_item { /* For each expression in the list */
- Expr *pExpr; /* The list of expressions */
- char *zName; /* Token associated with this expression */
- char *zSpan; /* Original text of the expression */
- u8 sortOrder; /* 1 for DESC or 0 for ASC */
+ Expr *pExpr; /* The parse tree for this expression */
+ char *zEName; /* Token associated with this expression */
+ u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
+ unsigned eEName :2; /* Meaning of zEName */
unsigned done :1; /* A flag to indicate when processing is finished */
- unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
unsigned reusable :1; /* Constant expression is reusable */
+ unsigned bSorterRef :1; /* Defer evaluation until after sorting */
+ unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
union {
struct {
u16 iOrderByCol; /* For ORDER BY, column number in result set */
@@ -15049,19 +18198,15 @@ struct ExprList {
} x;
int iConstExprReg; /* Register in which Expr value is cached */
} u;
- } *a; /* Alloc a power of two greater or equal to nExpr */
+ } a[1]; /* One slot for each expression in the list */
};
/*
-** An instance of this structure is used by the parser to record both
-** the parse tree for an expression and the span of input text for an
-** expression.
+** Allowed values for Expr.a.eEName
*/
-struct ExprSpan {
- Expr *pExpr; /* The expression parse tree */
- const char *zStart; /* First character of input text */
- const char *zEnd; /* One character past the end of input text */
-};
+#define ENAME_NAME 0 /* The AS clause of a result set */
+#define ENAME_SPAN 1 /* Complete text of the result set expression */
+#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
/*
** An instance of this structure can hold a simple list of identifiers,
@@ -15087,31 +18232,6 @@ struct IdList {
};
/*
-** The bitmask datatype defined below is used for various optimizations.
-**
-** Changing this from a 64-bit to a 32-bit type limits the number of
-** tables in a join to 32 instead of 64. But it also reduces the size
-** of the library by 738 bytes on ix86.
-*/
-#ifdef SQLITE_BITMASK_TYPE
- typedef SQLITE_BITMASK_TYPE Bitmask;
-#else
- typedef u64 Bitmask;
-#endif
-
-/*
-** The number of bits in a Bitmask. "BMS" means "BitMask Size".
-*/
-#define BMS ((int)(sizeof(Bitmask)*8))
-
-/*
-** A bit in a Bitmask
-*/
-#define MASKBIT(n) (((Bitmask)1)<<(n))
-#define MASKBIT32(n) (((unsigned int)1)<<(n))
-#define ALLBITS ((Bitmask)-1)
-
-/*
** The following structure describes the FROM clause of a SELECT statement.
** Each table or subquery in the FROM clause is a separate element of
** the SrcList.a[] array.
@@ -15151,10 +18271,8 @@ struct SrcList {
unsigned isCorrelated :1; /* True if sub-query is correlated */
unsigned viaCoroutine :1; /* Implemented as a co-routine */
unsigned isRecursive :1; /* True for recursive reference in WITH */
+ unsigned fromDDL :1; /* Comes from sqlite_schema */
} fg;
-#ifndef SQLITE_OMIT_EXPLAIN
- u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
-#endif
int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
@@ -15200,7 +18318,7 @@ struct SrcList {
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
- /* 0x1000 not currently used */
+#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */
/* 0x2000 not currently used */
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
/* 0x8000 not currently used */
@@ -15236,40 +18354,82 @@ struct SrcList {
struct NameContext {
Parse *pParse; /* The parser */
SrcList *pSrcList; /* One or more tables used to resolve names */
- ExprList *pEList; /* Optional list of result-set columns */
- AggInfo *pAggInfo; /* Information about aggregates at this level */
+ union {
+ ExprList *pEList; /* Optional list of result-set columns */
+ AggInfo *pAggInfo; /* Information about aggregates at this level */
+ Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */
+ } uNC;
NameContext *pNext; /* Next outer name context. NULL for outermost */
int nRef; /* Number of names resolved by this context */
int nErr; /* Number of errors encountered while resolving names */
- u16 ncFlags; /* Zero or more NC_* flags defined below */
+ int ncFlags; /* Zero or more NC_* flags defined below */
+ Select *pWinSelect; /* SELECT statement for any window functions */
};
/*
** Allowed values for the NameContext, ncFlags field.
**
** Value constraints (all checked via assert()):
-** NC_HasAgg == SF_HasAgg
+** NC_HasAgg == SF_HasAgg == EP_Agg
** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
-**
-*/
-#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
-#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */
-#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
-#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
-#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */
-#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */
-#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */
-#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
+** NC_HasWin == EP_Win
+**
+*/
+#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */
+#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */
+#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */
+#define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */
+#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */
+#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */
+#define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
+#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */
+#define NC_UEList 0x00080 /* True if uNC.pEList is used */
+#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */
+#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */
+#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */
+#define NC_Complex 0x02000 /* True if a function or subquery seen */
+#define NC_AllowWin 0x04000 /* Window functions are allowed here */
+#define NC_HasWin 0x08000 /* One or more window functions seen */
+#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */
+#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */
+#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_schema */
+
+/*
+** An instance of the following object describes a single ON CONFLICT
+** clause in an upsert.
+**
+** The pUpsertTarget field is only set if the ON CONFLICT clause includes
+** conflict-target clause. (In "ON CONFLICT(a,b)" the "(a,b)" is the
+** conflict-target clause.) The pUpsertTargetWhere is the optional
+** WHERE clause used to identify partial unique indexes.
+**
+** pUpsertSet is the list of column=expr terms of the UPDATE statement.
+** The pUpsertSet field is NULL for a ON CONFLICT DO NOTHING. The
+** pUpsertWhere is the WHERE clause for the UPDATE and is NULL if the
+** WHERE clause is omitted.
+*/
+struct Upsert {
+ ExprList *pUpsertTarget; /* Optional description of conflicting index */
+ Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */
+ ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
+ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
+ /* The fields above comprise the parse tree for the upsert clause.
+ ** The fields below are used to transfer information from the INSERT
+ ** processing down into the UPDATE processing while generating code.
+ ** Upsert owns the memory allocated above, but not the memory below. */
+ Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
+ SrcList *pUpsertSrc; /* Table to be updated */
+ int regData; /* First register holding array of VALUES */
+ int iDataCur; /* Index of the data cursor */
+ int iIdxCur; /* Index of the first index cursor */
+};
/*
** An instance of the following structure contains all information
** needed to generate code for a single SELECT statement.
**
-** nLimit is set to -1 if there is no LIMIT clause. nOffset is set to 0.
-** If there is a LIMIT clause, the parser sets nLimit to the value of the
-** limit and nOffset to the value of the offset (or 0 if there is not
-** offset). But later on, nLimit and nOffset become the memory locations
-** in the VDBE that record the limit and offset counters.
+** See the header comment on the computeLimitRegisters() routine for a
+** detailed description of the meaning of the iLimit and iOffset fields.
**
** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes.
** These addresses must be stored so that we can go back and fill in
@@ -15282,15 +18442,13 @@ struct NameContext {
** sequences for the ORDER BY clause.
*/
struct Select {
- ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
LogEst nSelectRow; /* Estimated number of result rows */
u32 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
-#if SELECTTRACE_ENABLED
- char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
-#endif
+ u32 selId; /* Unique identifier number for this SELECT */
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
+ ExprList *pEList; /* The fields of the result */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
@@ -15299,8 +18457,11 @@ struct Select {
Select *pPrior; /* Prior select in a compound select statement */
Select *pNext; /* Next select to the left in a compound */
Expr *pLimit; /* LIMIT expression. NULL means not used. */
- Expr *pOffset; /* OFFSET expression. NULL means not used. */
With *pWith; /* WITH clause attached to this select. Or NULL. */
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ Window *pWin; /* List of window functions */
+ Window *pWinDefn; /* List of named window definitions */
+#endif
};
/*
@@ -15312,25 +18473,30 @@ struct Select {
** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX
** SF_FixedLimit == WHERE_USE_LIMIT
*/
-#define SF_Distinct 0x00001 /* Output should be DISTINCT */
-#define SF_All 0x00002 /* Includes the ALL keyword */
-#define SF_Resolved 0x00004 /* Identifiers have been resolved */
-#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */
-#define SF_HasAgg 0x00010 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */
-#define SF_Compound 0x00100 /* Part of a compound query */
-#define SF_Values 0x00200 /* Synthesized from VALUES clause */
-#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */
-#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */
-#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */
-#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */
-#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */
-#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */
-#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */
-#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */
-
+#define SF_Distinct 0x0000001 /* Output should be DISTINCT */
+#define SF_All 0x0000002 /* Includes the ALL keyword */
+#define SF_Resolved 0x0000004 /* Identifiers have been resolved */
+#define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */
+#define SF_HasAgg 0x0000010 /* Contains aggregate functions */
+#define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */
+#define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */
+#define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */
+#define SF_Compound 0x0000100 /* Part of a compound query */
+#define SF_Values 0x0000200 /* Synthesized from VALUES clause */
+#define SF_MultiValue 0x0000400 /* Single VALUES term with multiple rows */
+#define SF_NestedFrom 0x0000800 /* Part of a parenthesized FROM clause */
+#define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */
+#define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */
+#define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */
+#define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */
+#define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */
+#define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */
+#define SF_ComplexResult 0x0040000 /* Result contains subquery or function */
+#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
+#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
+#define SF_View 0x0200000 /* SELECT statement is a view */
+#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
+#define SF_UpdateFrom 0x0800000 /* Statement is an UPDATE...FROM */
/*
** The results of a SELECT can be distributed in several ways, as defined
@@ -15395,6 +18561,14 @@ struct Select {
** SRT_DistQueue Store results in priority queue pDest->iSDParm only if
** the same record has never been stored before. The
** index at pDest->iSDParm+1 hold all prior stores.
+**
+** SRT_Upfrom Store results in the temporary table already opened by
+** pDest->iSDParm. If (pDest->iSDParm<0), then the temp
+** table is an intkey table - in this case the first
+** column returned by the SELECT is used as the integer
+** key. If (pDest->iSDParm>0), then the table is an index
+** table. (pDest->iSDParm) is the number of key columns in
+** each index record in this case.
*/
#define SRT_Union 1 /* Store result as keys in an index */
#define SRT_Except 2 /* Remove result from a UNION index */
@@ -15414,17 +18588,19 @@ struct Select {
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
#define SRT_Coroutine 13 /* Generate a single row of result */
#define SRT_Table 14 /* Store result as data with an automatic rowid */
+#define SRT_Upfrom 15 /* Store result as data with rowid */
/*
** An instance of this object describes where to put of the results of
** a SELECT statement.
*/
struct SelectDest {
- u8 eDest; /* How to dispose of the results. On of SRT_* above. */
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
+ u8 eDest; /* How to dispose of the results. One of SRT_* above. */
int iSDParm; /* A parameter used by the eDest disposal method */
+ int iSDParm2; /* A second parameter for the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
+ char *zAffSdst; /* Affinity used when eDest==SRT_Set */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
@@ -15445,13 +18621,6 @@ struct AutoincInfo {
};
/*
-** Size of the column cache
-*/
-#ifndef SQLITE_N_COLCACHE
-# define SQLITE_N_COLCACHE 10
-#endif
-
-/*
** At least one instance of the following structure is created for each
** trigger that may be fired while parsing an INSERT, UPDATE or DELETE
** statement. All such objects are stored in the linked list headed at
@@ -15526,19 +18695,17 @@ struct Parse {
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
- u8 nColCache; /* Number of entries in aColCache[] */
+ u8 disableVtab; /* Disable all virtual tables for this parse */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
- int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
- int ckBase; /* Base register of data during check constraints */
- int iSelfTab; /* Table of an index whose exprs are being coded */
- int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
- int iCacheCnt; /* Counter used to generate aColCache[].lru values */
- int nLabel; /* Number of labels used */
+ int iSelfTab; /* Table associated with an index on expr, or negative
+ ** of the base register during check-constraint eval */
+ int nLabel; /* The *negative* of the number of labels used */
+ int nLabelAlloc; /* Number of slots in aLabel */
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
Token constraintName;/* Name of the constraint currently being parsed */
@@ -15547,10 +18714,7 @@ struct Parse {
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
-#if SELECTTRACE_ENABLED
- int nSelect; /* Number of SELECT statements seen */
- int nSelectIndent; /* How far to indent SELECTTRACE() output */
-#endif
+ int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -15558,7 +18722,9 @@ struct Parse {
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
- int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */
+ Parse *pParentParse; /* Parent parser if this parser is nested */
+ AggInfo *pAggList; /* List of all AggInfo objects */
+ int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
@@ -15570,45 +18736,38 @@ struct Parse {
** Fields above must be initialized to zero. The fields that follow,
** down to the beginning of the recursive section, do not need to be
** initialized as they will be set before being used. The boundary is
- ** determined by offsetof(Parse,aColCache).
+ ** determined by offsetof(Parse,aTempReg).
**************************************************************************/
- struct yColCache {
- int iTable; /* Table cursor number */
- i16 iColumn; /* Table column number */
- u8 tempReg; /* iReg is a temp register that needs to be freed */
- int iLevel; /* Nesting level */
- int iReg; /* Reg with value of this column. 0 means none. */
- int lru; /* Least recently used entry has the smallest value */
- } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
int aTempReg[8]; /* Holding area for temporary registers */
Token sNameToken; /* Token with unqualified schema object name */
- Token sLastToken; /* The last token parsed */
/************************************************************************
** Above is constant between recursions. Below is reset before and after
** each recursion. The boundary between these two regions is determined
- ** using offsetof(Parse,nVar) so the nVar field must be the first field
- ** in the recursive region.
+ ** using offsetof(Parse,sLastToken) so the sLastToken field must be the
+ ** first field in the recursive region.
************************************************************************/
+ Token sLastToken; /* The last token parsed */
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
- int nzVar; /* Number of available slots in azVar[] */
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
u8 explain; /* True if the EXPLAIN flag is found on the query */
+ u8 eParseMode; /* PARSE_MODE_XXX constant */
#ifndef SQLITE_OMIT_VIRTUALTABLE
- u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
int nVtabLock; /* Number of virtual tables to lock */
#endif
int nHeight; /* Expression tree height of current sub-select */
#ifndef SQLITE_OMIT_EXPLAIN
- int iSelectId; /* ID of current select for EXPLAIN output */
- int iNextSelectId; /* Next available select ID for EXPLAIN output */
+ int addrExplain; /* Address of current OP_Explain opcode */
#endif
- char **azVar; /* Pointers to names of parameters */
+ VList *pVList; /* Mapping between variable names and numbers */
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
const char *zTail; /* All SQL text past the last semicolon parsed */
Table *pNewTable; /* A table being constructed by CREATE TABLE */
+ Index *pNewIndex; /* An index being constructed by CREATE INDEX.
+ ** Also used to hold redundant UNIQUE constraints
+ ** during a RENAME COLUMN */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -15619,13 +18778,21 @@ struct Parse {
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
With *pWith; /* Current WITH clause, or NULL */
With *pWithToFree; /* Free this WITH object at the end of the parse */
+#ifndef SQLITE_OMIT_ALTERTABLE
+ RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
+#endif
};
+#define PARSE_MODE_NORMAL 0
+#define PARSE_MODE_DECLARE_VTAB 1
+#define PARSE_MODE_RENAME 2
+#define PARSE_MODE_UNMAP 3
+
/*
** Sizes and pointers of various parts of the Parse object.
*/
-#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/
-#define PARSE_RECURSE_SZ offsetof(Parse,nVar) /* Recursive part */
+#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
+#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */
@@ -15635,7 +18802,19 @@ struct Parse {
#ifdef SQLITE_OMIT_VIRTUALTABLE
#define IN_DECLARE_VTAB 0
#else
- #define IN_DECLARE_VTAB (pParse->declareVtab)
+ #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB)
+#endif
+
+#if defined(SQLITE_OMIT_ALTERTABLE)
+ #define IN_RENAME_OBJECT 0
+#else
+ #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME)
+#endif
+
+#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
+ #define IN_SPECIAL_PARSE 0
+#else
+ #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL)
#endif
/*
@@ -15661,14 +18840,13 @@ struct AuthContext {
*/
#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */
/* Also used in P2 (not P5) of OP_Delete */
+#define OPFLAG_NOCHNG 0x01 /* OP_VColumn nochange for UPDATE */
#define OPFLAG_EPHEM 0x01 /* OP_Column: Ephemeral output is ok */
-#define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */
+#define OPFLAG_LASTROWID 0x20 /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
-#endif
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
@@ -15676,8 +18854,9 @@ struct AuthContext {
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
#define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
-#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete: keep cursor position */
+#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */
#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
+#define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -15762,9 +18941,12 @@ struct TriggerStep {
Trigger *pTrig; /* The trigger that this step is a part of */
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
+ SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
- ExprList *pExprList; /* SET clause for UPDATE. */
+ ExprList *pExprList; /* SET clause for UPDATE */
IdList *pIdList; /* Column names for INSERT */
+ Upsert *pUpsert; /* Upsert clauses on an INSERT */
+ char *zSpan; /* Original SQL text of this command */
TriggerStep *pNext; /* Next in the link-list */
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
};
@@ -15778,7 +18960,7 @@ typedef struct DbFixer DbFixer;
struct DbFixer {
Parse *pParse; /* The parsing context. Error messages written here */
Schema *pSchema; /* Fix items to this schema */
- int bVarOnly; /* Check for variable references only */
+ u8 bTemp; /* True for TEMP schema entries */
const char *zDb; /* Make sure all objects are contained in this database */
const char *zType; /* Type of the container - used for error messages */
const Token *pName; /* Name of the container - used for error messages */
@@ -15788,18 +18970,15 @@ struct DbFixer {
** An objected used to accumulate the text of a string where we
** do not necessarily know how big the string will be in the end.
*/
-struct StrAccum {
+struct sqlite3_str {
sqlite3 *db; /* Optional database for lookaside. Can be NULL */
- char *zBase; /* A base allocation. Not from malloc. */
char *zText; /* The string collected so far */
- u32 nChar; /* Length of the string so far */
u32 nAlloc; /* Amount of space allocated in zText */
u32 mxAlloc; /* Maximum allowed allocation. 0 for no malloc usage */
- u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
+ u32 nChar; /* Length of the string so far */
+ u8 accError; /* SQLITE_NOMEM or SQLITE_TOOBIG */
u8 printfFlags; /* SQLITE_PRINTF flags below */
};
-#define STRACCUM_NOMEM 1
-#define STRACCUM_TOOBIG 2
#define SQLITE_PRINTF_INTERNAL 0x01 /* Internal-use-only converters allowed */
#define SQLITE_PRINTF_SQLFUNC 0x02 /* SQL function arguments to VXPrintf */
#define SQLITE_PRINTF_MALLOCED 0x04 /* True if xText is allocated space */
@@ -15816,19 +18995,29 @@ typedef struct {
char **pzErrMsg; /* Error message stored here */
int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
int rc; /* Result code stored here */
+ u32 mInitFlags; /* Flags controlling error messages */
+ u32 nInitRow; /* Number of rows processed */
+ Pgno mxPage; /* Maximum page number. 0 for no limit. */
} InitData;
/*
+** Allowed values for mInitFlags
+*/
+#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */
+
+/*
** Structure containing global configuration data for the SQLite library.
**
** This structure also contains some state information.
*/
struct Sqlite3Config {
int bMemstat; /* True to enable memory status */
- int bCoreMutex; /* True to enable core mutexing */
- int bFullMutex; /* True to enable full mutexing */
- int bOpenUri; /* True to interpret filenames as URIs */
- int bUseCis; /* Use covering indices for full-scans */
+ u8 bCoreMutex; /* True to enable core mutexing */
+ u8 bFullMutex; /* True to enable full mutexing */
+ u8 bOpenUri; /* True to interpret filenames as URIs */
+ u8 bUseCis; /* Use covering indices for full-scans */
+ u8 bSmallMalloc; /* Avoid large memory allocations if true */
+ u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -15842,9 +19031,6 @@ struct Sqlite3Config {
int mnReq, mxReq; /* Min and max heap requests sizes */
sqlite3_int64 szMmap; /* mmap() space per open file */
sqlite3_int64 mxMmap; /* Maximum value for szMmap */
- void *pScratch; /* Scratch memory */
- int szScratch; /* Size of each scratch buffer */
- int nScratch; /* Number of scratch buffers */
void *pPage; /* Page cache memory */
int szPage; /* Size of each page in pPage[] */
int nPage; /* Number of pages in pPage[] */
@@ -15870,14 +19056,19 @@ struct Sqlite3Config {
/* The following callback (if not NULL) is invoked on every VDBE branch
** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE.
*/
- void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
+ void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */
void *pVdbeBranchArg; /* 1st argument */
#endif
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ sqlite3_int64 mxMemdbSize; /* Default max memdb size */
+#endif
+#ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
int bLocaltimeFault; /* True to fail localtime() calls */
int iOnceResetThreshold; /* When to reset OP_Once counters */
+ u32 szSorterRef; /* Min size in bytes to use sorter-refs */
+ unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */
};
/*
@@ -15907,16 +19098,24 @@ struct Walker {
int (*xSelectCallback)(Walker*,Select*); /* Callback for SELECTs */
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
- u8 eCode; /* A small processing code */
+ u16 eCode; /* A small processing code */
union { /* Extra data for callback */
- NameContext *pNC; /* Naming context */
- int n; /* A counter */
- int iCur; /* A cursor number */
- SrcList *pSrcList; /* FROM clause */
- struct SrcCount *pSrcCount; /* Counting column references */
- struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
- int *aiCol; /* array of column indexes */
- struct IdxCover *pIdxCover; /* Check for index coverage */
+ NameContext *pNC; /* Naming context */
+ int n; /* A counter */
+ int iCur; /* A cursor number */
+ SrcList *pSrcList; /* FROM clause */
+ struct SrcCount *pSrcCount; /* Counting column references */
+ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
+ int *aiCol; /* array of column indexes */
+ struct IdxCover *pIdxCover; /* Check for index coverage */
+ struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */
+ ExprList *pGroupBy; /* GROUP BY clause */
+ Select *pSelect; /* HAVING to WHERE clause ctx */
+ struct WindowRewrite *pRewrite; /* Window rewrite context */
+ struct WhereConst *pConst; /* WHERE clause constants */
+ struct RenameCtx *pRename; /* RENAME COLUMN context */
+ struct Table *pTab; /* Table of generated column */
+ struct SrcList_item *pSrcItem; /* A single FROM clause item */
} u;
};
@@ -15927,6 +19126,14 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
+SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
+SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
+SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker*,Select*);
+SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker*,Select*);
+
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
+#endif
/*
** Return code from the parse-tree walking primitives and their
@@ -15963,6 +19170,85 @@ struct TreeView {
#endif /* SQLITE_DEBUG */
/*
+** This object is used in various ways, most (but not all) related to window
+** functions.
+**
+** (1) A single instance of this structure is attached to the
+** the Expr.y.pWin field for each window function in an expression tree.
+** This object holds the information contained in the OVER clause,
+** plus additional fields used during code generation.
+**
+** (2) All window functions in a single SELECT form a linked-list
+** attached to Select.pWin. The Window.pFunc and Window.pExpr
+** fields point back to the expression that is the window function.
+**
+** (3) The terms of the WINDOW clause of a SELECT are instances of this
+** object on a linked list attached to Select.pWinDefn.
+**
+** (4) For an aggregate function with a FILTER clause, an instance
+** of this object is stored in Expr.y.pWin with eFrmType set to
+** TK_FILTER. In this case the only field used is Window.pFilter.
+**
+** The uses (1) and (2) are really the same Window object that just happens
+** to be accessible in two different ways. Use case (3) are separate objects.
+*/
+struct Window {
+ char *zName; /* Name of window (may be NULL) */
+ char *zBase; /* Name of base window for chaining (may be NULL) */
+ ExprList *pPartition; /* PARTITION BY clause */
+ ExprList *pOrderBy; /* ORDER BY clause */
+ u8 eFrmType; /* TK_RANGE, TK_GROUPS, TK_ROWS, or 0 */
+ u8 eStart; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
+ u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
+ u8 bImplicitFrame; /* True if frame was implicitly specified */
+ u8 eExclude; /* TK_NO, TK_CURRENT, TK_TIES, TK_GROUP, or 0 */
+ Expr *pStart; /* Expression for "<expr> PRECEDING" */
+ Expr *pEnd; /* Expression for "<expr> FOLLOWING" */
+ Window **ppThis; /* Pointer to this object in Select.pWin list */
+ Window *pNextWin; /* Next window function belonging to this SELECT */
+ Expr *pFilter; /* The FILTER expression */
+ FuncDef *pFunc; /* The function */
+ int iEphCsr; /* Partition buffer or Peer buffer */
+ int regAccum; /* Accumulator */
+ int regResult; /* Interim result */
+ int csrApp; /* Function cursor (used by min/max) */
+ int regApp; /* Function register (also used by min/max) */
+ int regPart; /* Array of registers for PARTITION BY values */
+ Expr *pOwner; /* Expression object this window is attached to */
+ int nBufferCol; /* Number of columns in buffer table */
+ int iArgCol; /* Offset of first argument for this function */
+ int regOne; /* Register containing constant value 1 */
+ int regStartRowid;
+ int regEndRowid;
+ u8 bExprArgs; /* Defer evaluation of window function arguments
+ ** due to the SQLITE_SUBTYPE flag */
+};
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*);
+SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*);
+SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
+SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
+SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
+SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin);
+SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*, int);
+SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*);
+SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
+SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
+SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
+SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
+SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
+SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
+SQLITE_PRIVATE void sqlite3WindowFunctions(void);
+SQLITE_PRIVATE void sqlite3WindowChain(Parse*, Window*, Window*);
+SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprList*, Token*);
+#else
+# define sqlite3WindowDelete(a,b)
+# define sqlite3WindowFunctions()
+# define sqlite3WindowAttach(a,b,c)
+#endif
+
+/*
** Assuming zIn points to the first byte of a UTF-8 character,
** advance zIn to point to the first byte of the next UTF-8 character.
*/
@@ -15979,6 +19265,7 @@ struct TreeView {
** using sqlite3_log(). The routines also provide a convenient place
** to set a debugger breakpoint.
*/
+SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType);
SQLITE_PRIVATE int sqlite3CorruptError(int);
SQLITE_PRIVATE int sqlite3MisuseError(int);
SQLITE_PRIVATE int sqlite3CantopenError(int);
@@ -15994,6 +19281,12 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
#endif
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
+SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
+#else
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
+#endif
/*
** FTS3 and FTS4 both require virtual table support
@@ -16045,15 +19338,14 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
# define sqlite3Tolower(x) tolower((unsigned char)(x))
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
#endif
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_PRIVATE int sqlite3IsIdChar(u8);
-#endif
/*
** Internal function prototypes
*/
SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*);
SQLITE_PRIVATE int sqlite3Strlen30(const char*);
+#define sqlite3Strlen30NN(C) (strlen(C)&0x3fffffff)
SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*);
#define sqlite3StrNICmp sqlite3_strnicmp
@@ -16066,18 +19358,18 @@ SQLITE_PRIVATE void *sqlite3DbMallocRaw(sqlite3*, u64);
SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3*, u64);
SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3*,const char*);
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
+SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
+SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int);
-SQLITE_PRIVATE void sqlite3ScratchFree(void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
#endif
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
@@ -16129,14 +19421,25 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
SQLITE_PRIVATE void sqlite3StatusUp(int, int);
SQLITE_PRIVATE void sqlite3StatusDown(int, int);
SQLITE_PRIVATE void sqlite3StatusHighwater(int, int);
+SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*);
/* Access to mutexes used by sqlite3_status() */
SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void);
SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void);
+#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT)
+SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*);
+#else
+# define sqlite3MutexWarnOnContention(x)
+#endif
+
#ifndef SQLITE_OMIT_FLOATING_POINT
+# define EXP754 (((u64)0x7ff)<<52)
+# define MAN754 ((((u64)1)<<52)-1)
+# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0)
SQLITE_PRIVATE int sqlite3IsNaN(double);
#else
+# define IsNaN(X) 0
# define sqlite3IsNaN(X) 0
#endif
@@ -16150,8 +19453,6 @@ struct PrintfArguments {
sqlite3_value **apArg; /* The argument values */
};
-SQLITE_PRIVATE void sqlite3VXPrintf(StrAccum*, const char*, va_list);
-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum*, const char*, ...);
SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
@@ -16165,14 +19466,21 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
+SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*);
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
+SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
+#endif
#endif
SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
+SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int);
SQLITE_PRIVATE void sqlite3Dequote(char*);
+SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*);
SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*);
SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int);
SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **);
@@ -16188,33 +19496,48 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
-SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
+SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
-SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
-SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
+SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
+SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
+SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
+SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
+SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
-SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int);
+SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
-SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
+SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
+SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
+SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32);
SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
+#endif
SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
-SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
-SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
+SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
+SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
+SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int);
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
-SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index*, i16);
+SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16);
+#ifdef SQLITE_OMIT_GENERATED_COLUMNS
+# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */
+# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */
+#else
+SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table*, i16);
+SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table*, i16);
+#endif
SQLITE_PRIVATE void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
#if SQLITE_ENABLE_HIDDEN_COLUMNS
SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*);
@@ -16225,14 +19548,16 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*);
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
-SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
+SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
+SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **);
+#define sqlite3CodecQueryParameters(A,B,C) 0
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
-#ifdef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_UNTESTABLE
# define sqlite3FaultSim(X) SQLITE_OK
#else
SQLITE_PRIVATE int sqlite3FaultSim(int);
@@ -16245,12 +19570,13 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
#endif
-SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
-SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*);
+SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*);
+SQLITE_PRIVATE void sqlite3RowSetDelete(void*);
+SQLITE_PRIVATE void sqlite3RowSetClear(void*);
SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64);
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
@@ -16269,6 +19595,7 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask);
SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int);
SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int);
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*);
+SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse);
SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse);
@@ -16276,12 +19603,16 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse);
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
#endif
-SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int);
+SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(Parse*, int, Table*);
+#endif
SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
-SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
+SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
-SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
-SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
+SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
+SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
+SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
Token*, Select*, Expr*, IdList*);
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
@@ -16297,22 +19628,23 @@ SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,i
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
- Expr*,ExprList*,u32,Expr*,Expr*);
+ Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
-SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
+SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
#endif
-SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
-SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
+SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
+SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
+ Upsert*);
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*);
-SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*);
+SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
@@ -16320,28 +19652,25 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
#define ONEPASS_OFF 0 /* Use of ONEPASS not allowed */
#define ONEPASS_SINGLE 1 /* ONEPASS valid for a single row update */
#define ONEPASS_MULTI 2 /* ONEPASS is valid for multiple rows */
+SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo*);
SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
-SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(Parse*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
-SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse*, int, int, int);
-SQLITE_PRIVATE void sqlite3ExprCachePush(Parse*);
-SQLITE_PRIVATE void sqlite3ExprCachePop(Parse*);
-SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse*, int, int);
-SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse*);
-SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse*, int, int);
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int);
+#endif
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
-SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
+SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
-SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
#define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */
+#define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */
SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
@@ -16353,18 +19682,21 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_ite
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
-SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*);
-SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int);
+SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*);
+SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
-SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int);
+SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
+SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int);
-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int);
+SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
+SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int);
+SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3PrngSaveState(void);
SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
#endif
@@ -16372,14 +19704,17 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*,int);
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int);
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb);
SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int);
-SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*);
-SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*);
+SQLITE_PRIVATE void sqlite3EndTransaction(Parse*,int);
SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*);
SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *);
SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3*);
+SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char*);
+SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr*);
+SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
+SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
@@ -16393,8 +19728,14 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int);
+SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(Expr*,int*,int);
SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
- u8,u8,int,int*,int*);
+ u8,u8,int,int*,int*,Upsert*);
+#ifdef SQLITE_ENABLE_NULL_TRIM
+SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe*,Table*);
+#else
+# define sqlite3SetMakeRecordP5(A,B)
+#endif
SQLITE_PRIVATE void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
@@ -16408,11 +19749,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
-#if SELECTTRACE_ENABLED
-SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*);
-#else
-# define sqlite3SelectSetName(A,B)
-#endif
+SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*);
SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
@@ -16423,7 +19760,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
-SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, int);
+SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
#endif
#ifndef SQLITE_OMIT_TRIGGER
@@ -16439,14 +19776,19 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, i
SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int);
void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*);
SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
-SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*);
-SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
- Select*,u8);
-SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8);
-SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*);
+SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
+ const char*,const char*);
+SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
+ Select*,u8,Upsert*,
+ const char*,const char*);
+SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*,
+ Expr*, u8, const char*,const char*);
+SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
+ const char*,const char*);
SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
+SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*);
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
#else
@@ -16460,9 +19802,11 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Tab
# define sqlite3ParseToplevel(p) p
# define sqlite3IsToplevel(p) 1
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
+# define sqlite3TriggerStepSrc(A,B) 0
#endif
SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*);
+SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int);
SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int);
#ifndef SQLITE_OMIT_AUTHORIZATION
@@ -16477,6 +19821,7 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(Parse*, const char *, const char *, int)
# define sqlite3AuthContextPush(a,b,c)
# define sqlite3AuthContextPop(a) ((void)(a))
#endif
+SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName);
SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
@@ -16485,10 +19830,15 @@ SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
+SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
+SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*);
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
+SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
SQLITE_PRIVATE int sqlite3Atoi(const char*);
+#ifndef SQLITE_OMIT_UTF16
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
+#endif
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
@@ -16497,10 +19847,13 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
#endif
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
+ defined(SQLITE_ENABLE_STAT4) || \
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
#endif
+SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
+SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int);
+SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int);
/*
** Routines to read and write variable-length integers. These used to
@@ -16519,6 +19872,8 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
*/
#define getVarint32(A,B) \
(u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
+#define getVarint32NR(A,B) \
+ B=(u32)*(A);if(B>=0x80)sqlite3GetVarint32((A),(u32*)&(B))
#define putVarint32(A,B) \
(u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
sqlite3PutVarint((A),(B)))
@@ -16528,10 +19883,10 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
-SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
-SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
+SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
+SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
-SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
+SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
@@ -16545,16 +19900,26 @@ SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
SQLITE_PRIVATE const char *sqlite3ErrName(int);
#endif
+#ifdef SQLITE_ENABLE_DESERIALIZE
+SQLITE_PRIVATE int sqlite3MemdbInit(void);
+#endif
+
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
+SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
-SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
+SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8);
+SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr);
+SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr);
+SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
+SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
-SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *, const char *);
+SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
+SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
@@ -16573,8 +19938,13 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
+#ifndef SQLITE_UNTESTABLE
+SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*);
+#endif
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
+#ifndef SQLITE_OMIT_UTF16
SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
+#endif
SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
#ifndef SQLITE_AMALGAMATION
@@ -16582,34 +19952,50 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
SQLITE_PRIVATE const char sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
-SQLITE_PRIVATE const Token sqlite3IntTokens[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
+SQLITE_API extern u32 sqlite3_unsupported_selecttrace;
#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte;
#endif
+#endif /* SQLITE_AMALGAMATION */
+#ifdef VDBE_PROFILE
+SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt;
#endif
-SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int);
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno);
SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
SQLITE_PRIVATE void sqlite3AlterFunctions(void);
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
+SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
-SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
-SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int);
+SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int);
+SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
+SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
-SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
+SQLITE_PRIVATE int sqlite3MatchEName(
+ const struct ExprList_item*,
+ const char*,
+ const char*,
+ const char*
+);
+SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*);
+SQLITE_PRIVATE u8 sqlite3StrIHash(const char*);
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
-SQLITE_PRIVATE void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
+SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
+SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*);
+SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
+SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
+SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
-SQLITE_PRIVATE char sqlite3AffinityType(const char*, u8*);
+SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
@@ -16626,25 +20012,28 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int);
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*);
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
+SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
+SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse*, ExprList*);
+
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*);
#endif
SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **),
- void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
+ void (*)(sqlite3_context*,int,sqlite3_value **),
+ void (*)(sqlite3_context*),
+ void (*)(sqlite3_context*),
+ void (*)(sqlite3_context*,int,sqlite3_value **),
FuncDestructor *pDestructor
);
+SQLITE_PRIVATE void sqlite3NoopDestructor(void*);
SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
-SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int);
-SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*);
-SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
-SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*);
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
@@ -16657,8 +20046,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*);
# define sqlite3ExprCheckIN(x,y) SQLITE_OK
#endif
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void);
+#ifdef SQLITE_ENABLE_STAT4
SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*);
SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**);
@@ -16670,9 +20058,12 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int);
/*
** The interface to the LEMON-generated parser
*/
-SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64));
-SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*));
-SQLITE_PRIVATE void sqlite3Parser(void*, int, Token, Parse*);
+#ifndef SQLITE_AMALGAMATION
+SQLITE_PRIVATE void *sqlite3ParserAlloc(void*(*)(u64), Parse*);
+SQLITE_PRIVATE void sqlite3ParserFree(void*, void(*)(void*));
+#endif
+SQLITE_PRIVATE void sqlite3Parser(void*, int, Token);
+SQLITE_PRIVATE int sqlite3ParserFallback(int);
#ifdef YYTRACKMAXSTACKDEPTH
SQLITE_PRIVATE int sqlite3ParserStackPeak(void*);
#endif
@@ -16685,7 +20076,7 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3*);
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
-SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *);
+SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *);
#else
#define sqlite3TableLock(v,w,x,y,z)
#endif
@@ -16702,6 +20093,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*);
# define sqlite3VtabInSync(db) 0
# define sqlite3VtabLock(X)
# define sqlite3VtabUnlock(X)
+# define sqlite3VtabModuleUnref(D,X)
# define sqlite3VtabUnlockList(X)
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
# define sqlite3GetVTable(X,Y) ((VTable*)0)
@@ -16713,12 +20105,28 @@ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db);
SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db);
SQLITE_PRIVATE void sqlite3VtabLock(VTable *);
SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *);
+SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3*,Module*);
SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*);
SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int);
SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
+SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
+ sqlite3*,
+ const char*,
+ const sqlite3_module*,
+ void*,
+ void(*)(void*)
+ );
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
+SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
+SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
+#else
+# define sqlite3ShadowTableName(A,B) 0
+# define sqlite3IsShadowTableOf(A,B,C) 0
+#endif
SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
@@ -16731,14 +20139,17 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*);
SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *);
SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
-SQLITE_PRIVATE void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
SQLITE_PRIVATE void sqlite3ParserReset(Parse*);
+#ifdef SQLITE_ENABLE_NORMALIZE
+SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*);
+#endif
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*);
SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
-SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
+SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*);
+SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const Expr*);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE const char *sqlite3JournalModename(int);
#ifndef SQLITE_OMIT_WAL
@@ -16753,6 +20164,18 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8);
#define sqlite3WithPush(x,y,z)
#define sqlite3WithDelete(x,y)
#endif
+#ifndef SQLITE_OMIT_UPSERT
+SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*);
+SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*);
+SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
+SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
+SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
+#else
+#define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0)
+#define sqlite3UpsertDelete(x,y)
+#define sqlite3UpsertDup(x,y) ((Upsert*)0)
+#endif
+
/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
@@ -16774,6 +20197,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *);
#define sqlite3FkDropTable(a,b,c)
#define sqlite3FkOldmask(a,b) 0
#define sqlite3FkRequired(a,b,c,d) 0
+ #define sqlite3FkReferences(a) 0
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*);
@@ -16792,10 +20216,10 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**);
/*
** The interface to the code in fault.c used for identifying "benign"
-** malloc failures. This is only present if SQLITE_OMIT_BUILTIN_TEST
+** malloc failures. This is only present if SQLITE_UNTESTABLE
** is not defined.
*/
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void);
SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
#else
@@ -16817,11 +20241,12 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
+SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*);
SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *);
#endif
@@ -16853,6 +20278,9 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *);
#endif
+#if defined(YYCOVERAGE)
+SQLITE_PRIVATE int sqlite3ParserCoverage(FILE*);
+#endif
/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable
@@ -16907,8 +20335,7 @@ SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8);
#endif
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
#define MEMTYPE_LOOKASIDE 0x02 /* Heap that might have been lookaside */
-#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
-#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
+#define MEMTYPE_PCACHE 0x04 /* Page cache allocations */
/*
** Threading interface
@@ -16918,6 +20345,9 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif
+#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
+#endif
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
#endif
@@ -16926,6 +20356,11 @@ SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr);
SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
+SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
+
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
+#endif
#endif /* SQLITEINT_H */
@@ -16948,7 +20383,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
/* #include "sqliteInt.h" */
/* An array to map all upper-case characters into their corresponding
-** lower-case character.
+** lower-case character.
**
** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
** handle case conversions for the UTF character set since the tables
@@ -17015,12 +20450,11 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
** array. tolower() is used more often than toupper() by SQLite.
**
-** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
+** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
** non-ASCII UTF character. Hence the test for whether or not a character is
** part of an identifier is 0x46.
*/
-#ifdef SQLITE_ASCII
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00..07 ........ */
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
@@ -17058,7 +20492,6 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */
};
-#endif
/* EVIDENCE-OF: R-02982-34736 In order to maintain full backwards
** compatibility for legacy applications, the URI filename capability is
@@ -17072,15 +20505,22 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
** SQLITE_USE_URI symbol defined.
*/
#ifndef SQLITE_USE_URI
-# define SQLITE_USE_URI 0
+# define SQLITE_USE_URI 0
#endif
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
** that compile-time option is omitted.
*/
-#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+#if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN)
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+#else
+# if !SQLITE_ALLOW_COVERING_INDEX_SCAN
+# error "Compile-time disabling of covering index scan using the\
+ -DSQLITE_ALLOW_COVERING_INDEX_SCAN=0 option is deprecated.\
+ Contact SQLite developers if this is a problem for you, and\
+ delete this #error macro to continue with your build."
+# endif
#endif
/* The minimum PMA size is set to this value multiplied by the database
@@ -17098,11 +20538,40 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
** setting.)
*/
-#ifndef SQLITE_STMTJRNL_SPILL
+#ifndef SQLITE_STMTJRNL_SPILL
# define SQLITE_STMTJRNL_SPILL (64*1024)
#endif
/*
+** The default lookaside-configuration, the format "SZ,N". SZ is the
+** number of bytes in each lookaside slot (should be a multiple of 8)
+** and N is the number of slots. The lookaside-configuration can be
+** changed as start-time using sqlite3_config(SQLITE_CONFIG_LOOKASIDE)
+** or at run-time for an individual database connection using
+** sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE);
+**
+** With the two-size-lookaside enhancement, less lookaside is required.
+** The default configuration of 1200,40 actually provides 30 1200-byte slots
+** and 93 128-byte slots, which is more lookaside than is available
+** using the older 1200,100 configuration without two-size-lookaside.
+*/
+#ifndef SQLITE_DEFAULT_LOOKASIDE
+# ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+# define SQLITE_DEFAULT_LOOKASIDE 1200,100 /* 120KB of memory */
+# else
+# define SQLITE_DEFAULT_LOOKASIDE 1200,40 /* 48KB of memory */
+# endif
+#endif
+
+
+/* The default maximum size of an in-memory database created using
+** sqlite3_deserialize()
+*/
+#ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE
+# define SQLITE_MEMDB_DEFAULT_MAXSIZE 1073741824
+#endif
+
+/*
** The following singleton contains the global configuration for
** the SQLite library.
*/
@@ -17112,10 +20581,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_THREADSAFE==1, /* bFullMutex */
SQLITE_USE_URI, /* bOpenUri */
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
+ 0, /* bSmallMalloc */
+ 1, /* bExtraSchemaChecks */
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
- 128, /* szLookaside */
- 500, /* nLookaside */
+ SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
SQLITE_STMTJRNL_SPILL, /* nStmtSpill */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
@@ -17125,9 +20595,6 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, 0, /* mnHeap, mxHeap */
SQLITE_DEFAULT_MMAP_SIZE, /* szMmap */
SQLITE_MAX_MMAP_SIZE, /* mxMmap */
- (void*)0, /* pScratch */
- 0, /* szScratch */
- 0, /* nScratch */
(void*)0, /* pPage */
0, /* szPage */
SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
@@ -17152,11 +20619,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xVdbeBranch */
0, /* pVbeBranchArg */
#endif
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */
+#endif
+#ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */
#endif
0, /* bLocaltimeFault */
- 0x7ffffffe /* iOnceResetThreshold */
+ 0x7ffffffe, /* iOnceResetThreshold */
+ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
+ 0, /* iPrngSeed */
};
/*
@@ -17166,14 +20638,13 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
*/
SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
+#ifdef VDBE_PROFILE
/*
-** Constant tokens for values 0 and 1.
+** The following performance counter can be used in place of
+** sqlite3Hwtime() for profiling. This is a no-op on standard builds.
*/
-SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
- { "0", 1 },
- { "1", 1 }
-};
-
+SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt = 0;
+#endif
/*
** The value of the "pending" byte must be 0x40000000 (1 byte past the
@@ -17197,12 +20668,17 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
#endif
+/*
+** Flags for select tracing and the ".selecttrace" macro of the CLI
+*/
+SQLITE_API u32 sqlite3_unsupported_selecttrace = 0;
+
/* #include "opcodes.h" */
/*
** Properties of opcodes. The OPFLG_INITIALIZER macro is
** created by mkopcodeh.awk during compilation. Data is obtained
** from the comments following the "case OP_xxxx:" statements in
-** the vdbe.c file.
+** the vdbe.c file.
*/
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
@@ -17212,460 +20688,6 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
/************** End of global.c **********************************************/
-/************** Begin file ctime.c *******************************************/
-/*
-** 2010 February 23
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** This file implements routines used to report what compile-time options
-** SQLite was built with.
-*/
-
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-
-/* #include "sqliteInt.h" */
-
-/*
-** An array of names of all compile-time options. This array should
-** be sorted A-Z.
-**
-** This array looks large, but in a typical installation actually uses
-** only a handful of compile-time options, so most times this array is usually
-** rather short and uses little memory space.
-*/
-static const char * const azCompileOpt[] = {
-
-/* These macros are provided to "stringify" the value of the define
-** for those options in which the value is meaningful. */
-#define CTIMEOPT_VAL_(opt) #opt
-#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
-
-#if SQLITE_32BIT_ROWID
- "32BIT_ROWID",
-#endif
-#if SQLITE_4_BYTE_ALIGNED_MALLOC
- "4_BYTE_ALIGNED_MALLOC",
-#endif
-#if SQLITE_CASE_SENSITIVE_LIKE
- "CASE_SENSITIVE_LIKE",
-#endif
-#if SQLITE_CHECK_PAGES
- "CHECK_PAGES",
-#endif
-#if defined(__clang__) && defined(__clang_major__)
- "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
- CTIMEOPT_VAL(__clang_minor__) "."
- CTIMEOPT_VAL(__clang_patchlevel__),
-#elif defined(_MSC_VER)
- "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
-#elif defined(__GNUC__) && defined(__VERSION__)
- "COMPILER=gcc-" __VERSION__,
-#endif
-#if SQLITE_COVERAGE_TEST
- "COVERAGE_TEST",
-#endif
-#if SQLITE_DEBUG
- "DEBUG",
-#endif
-#if SQLITE_DEFAULT_LOCKING_MODE
- "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
-#endif
-#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
- "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
-#endif
-#if SQLITE_DISABLE_DIRSYNC
- "DISABLE_DIRSYNC",
-#endif
-#if SQLITE_DISABLE_LFS
- "DISABLE_LFS",
-#endif
-#if SQLITE_ENABLE_8_3_NAMES
- "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
-#endif
-#if SQLITE_ENABLE_API_ARMOR
- "ENABLE_API_ARMOR",
-#endif
-#if SQLITE_ENABLE_ATOMIC_WRITE
- "ENABLE_ATOMIC_WRITE",
-#endif
-#if SQLITE_ENABLE_CEROD
- "ENABLE_CEROD",
-#endif
-#if SQLITE_ENABLE_COLUMN_METADATA
- "ENABLE_COLUMN_METADATA",
-#endif
-#if SQLITE_ENABLE_DBSTAT_VTAB
- "ENABLE_DBSTAT_VTAB",
-#endif
-#if SQLITE_ENABLE_EXPENSIVE_ASSERT
- "ENABLE_EXPENSIVE_ASSERT",
-#endif
-#if SQLITE_ENABLE_FTS1
- "ENABLE_FTS1",
-#endif
-#if SQLITE_ENABLE_FTS2
- "ENABLE_FTS2",
-#endif
-#if SQLITE_ENABLE_FTS3
- "ENABLE_FTS3",
-#endif
-#if SQLITE_ENABLE_FTS3_PARENTHESIS
- "ENABLE_FTS3_PARENTHESIS",
-#endif
-#if SQLITE_ENABLE_FTS4
- "ENABLE_FTS4",
-#endif
-#if SQLITE_ENABLE_FTS5
- "ENABLE_FTS5",
-#endif
-#if SQLITE_ENABLE_ICU
- "ENABLE_ICU",
-#endif
-#if SQLITE_ENABLE_IOTRACE
- "ENABLE_IOTRACE",
-#endif
-#if SQLITE_ENABLE_JSON1
- "ENABLE_JSON1",
-#endif
-#if SQLITE_ENABLE_LOAD_EXTENSION
- "ENABLE_LOAD_EXTENSION",
-#endif
-#if SQLITE_ENABLE_LOCKING_STYLE
- "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
-#endif
-#if SQLITE_ENABLE_MEMORY_MANAGEMENT
- "ENABLE_MEMORY_MANAGEMENT",
-#endif
-#if SQLITE_ENABLE_MEMSYS3
- "ENABLE_MEMSYS3",
-#endif
-#if SQLITE_ENABLE_MEMSYS5
- "ENABLE_MEMSYS5",
-#endif
-#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
- "ENABLE_OVERSIZE_CELL_CHECK",
-#endif
-#if SQLITE_ENABLE_RTREE
- "ENABLE_RTREE",
-#endif
-#if defined(SQLITE_ENABLE_STAT4)
- "ENABLE_STAT4",
-#elif defined(SQLITE_ENABLE_STAT3)
- "ENABLE_STAT3",
-#endif
-#if SQLITE_ENABLE_UNLOCK_NOTIFY
- "ENABLE_UNLOCK_NOTIFY",
-#endif
-#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
- "ENABLE_UPDATE_DELETE_LIMIT",
-#endif
-#if SQLITE_HAS_CODEC
- "HAS_CODEC",
-#endif
-#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
- "HAVE_ISNAN",
-#endif
-#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
- "HOMEGROWN_RECURSIVE_MUTEX",
-#endif
-#if SQLITE_IGNORE_AFP_LOCK_ERRORS
- "IGNORE_AFP_LOCK_ERRORS",
-#endif
-#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- "IGNORE_FLOCK_LOCK_ERRORS",
-#endif
-#ifdef SQLITE_INT64_TYPE
- "INT64_TYPE",
-#endif
-#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- "LIKE_DOESNT_MATCH_BLOBS",
-#endif
-#if SQLITE_LOCK_TRACE
- "LOCK_TRACE",
-#endif
-#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
- "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
-#endif
-#ifdef SQLITE_MAX_SCHEMA_RETRY
- "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
-#endif
-#if SQLITE_MEMDEBUG
- "MEMDEBUG",
-#endif
-#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
- "MIXED_ENDIAN_64BIT_FLOAT",
-#endif
-#if SQLITE_NO_SYNC
- "NO_SYNC",
-#endif
-#if SQLITE_OMIT_ALTERTABLE
- "OMIT_ALTERTABLE",
-#endif
-#if SQLITE_OMIT_ANALYZE
- "OMIT_ANALYZE",
-#endif
-#if SQLITE_OMIT_ATTACH
- "OMIT_ATTACH",
-#endif
-#if SQLITE_OMIT_AUTHORIZATION
- "OMIT_AUTHORIZATION",
-#endif
-#if SQLITE_OMIT_AUTOINCREMENT
- "OMIT_AUTOINCREMENT",
-#endif
-#if SQLITE_OMIT_AUTOINIT
- "OMIT_AUTOINIT",
-#endif
-#if SQLITE_OMIT_AUTOMATIC_INDEX
- "OMIT_AUTOMATIC_INDEX",
-#endif
-#if SQLITE_OMIT_AUTORESET
- "OMIT_AUTORESET",
-#endif
-#if SQLITE_OMIT_AUTOVACUUM
- "OMIT_AUTOVACUUM",
-#endif
-#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
- "OMIT_BETWEEN_OPTIMIZATION",
-#endif
-#if SQLITE_OMIT_BLOB_LITERAL
- "OMIT_BLOB_LITERAL",
-#endif
-#if SQLITE_OMIT_BTREECOUNT
- "OMIT_BTREECOUNT",
-#endif
-#if SQLITE_OMIT_BUILTIN_TEST
- "OMIT_BUILTIN_TEST",
-#endif
-#if SQLITE_OMIT_CAST
- "OMIT_CAST",
-#endif
-#if SQLITE_OMIT_CHECK
- "OMIT_CHECK",
-#endif
-#if SQLITE_OMIT_COMPLETE
- "OMIT_COMPLETE",
-#endif
-#if SQLITE_OMIT_COMPOUND_SELECT
- "OMIT_COMPOUND_SELECT",
-#endif
-#if SQLITE_OMIT_CTE
- "OMIT_CTE",
-#endif
-#if SQLITE_OMIT_DATETIME_FUNCS
- "OMIT_DATETIME_FUNCS",
-#endif
-#if SQLITE_OMIT_DECLTYPE
- "OMIT_DECLTYPE",
-#endif
-#if SQLITE_OMIT_DEPRECATED
- "OMIT_DEPRECATED",
-#endif
-#if SQLITE_OMIT_DISKIO
- "OMIT_DISKIO",
-#endif
-#if SQLITE_OMIT_EXPLAIN
- "OMIT_EXPLAIN",
-#endif
-#if SQLITE_OMIT_FLAG_PRAGMAS
- "OMIT_FLAG_PRAGMAS",
-#endif
-#if SQLITE_OMIT_FLOATING_POINT
- "OMIT_FLOATING_POINT",
-#endif
-#if SQLITE_OMIT_FOREIGN_KEY
- "OMIT_FOREIGN_KEY",
-#endif
-#if SQLITE_OMIT_GET_TABLE
- "OMIT_GET_TABLE",
-#endif
-#if SQLITE_OMIT_INCRBLOB
- "OMIT_INCRBLOB",
-#endif
-#if SQLITE_OMIT_INTEGRITY_CHECK
- "OMIT_INTEGRITY_CHECK",
-#endif
-#if SQLITE_OMIT_LIKE_OPTIMIZATION
- "OMIT_LIKE_OPTIMIZATION",
-#endif
-#if SQLITE_OMIT_LOAD_EXTENSION
- "OMIT_LOAD_EXTENSION",
-#endif
-#if SQLITE_OMIT_LOCALTIME
- "OMIT_LOCALTIME",
-#endif
-#if SQLITE_OMIT_LOOKASIDE
- "OMIT_LOOKASIDE",
-#endif
-#if SQLITE_OMIT_MEMORYDB
- "OMIT_MEMORYDB",
-#endif
-#if SQLITE_OMIT_OR_OPTIMIZATION
- "OMIT_OR_OPTIMIZATION",
-#endif
-#if SQLITE_OMIT_PAGER_PRAGMAS
- "OMIT_PAGER_PRAGMAS",
-#endif
-#if SQLITE_OMIT_PRAGMA
- "OMIT_PRAGMA",
-#endif
-#if SQLITE_OMIT_PROGRESS_CALLBACK
- "OMIT_PROGRESS_CALLBACK",
-#endif
-#if SQLITE_OMIT_QUICKBALANCE
- "OMIT_QUICKBALANCE",
-#endif
-#if SQLITE_OMIT_REINDEX
- "OMIT_REINDEX",
-#endif
-#if SQLITE_OMIT_SCHEMA_PRAGMAS
- "OMIT_SCHEMA_PRAGMAS",
-#endif
-#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
- "OMIT_SCHEMA_VERSION_PRAGMAS",
-#endif
-#if SQLITE_OMIT_SHARED_CACHE
- "OMIT_SHARED_CACHE",
-#endif
-#if SQLITE_OMIT_SUBQUERY
- "OMIT_SUBQUERY",
-#endif
-#if SQLITE_OMIT_TCL_VARIABLE
- "OMIT_TCL_VARIABLE",
-#endif
-#if SQLITE_OMIT_TEMPDB
- "OMIT_TEMPDB",
-#endif
-#if SQLITE_OMIT_TRACE
- "OMIT_TRACE",
-#endif
-#if SQLITE_OMIT_TRIGGER
- "OMIT_TRIGGER",
-#endif
-#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
- "OMIT_TRUNCATE_OPTIMIZATION",
-#endif
-#if SQLITE_OMIT_UTF16
- "OMIT_UTF16",
-#endif
-#if SQLITE_OMIT_VACUUM
- "OMIT_VACUUM",
-#endif
-#if SQLITE_OMIT_VIEW
- "OMIT_VIEW",
-#endif
-#if SQLITE_OMIT_VIRTUALTABLE
- "OMIT_VIRTUALTABLE",
-#endif
-#if SQLITE_OMIT_WAL
- "OMIT_WAL",
-#endif
-#if SQLITE_OMIT_WSD
- "OMIT_WSD",
-#endif
-#if SQLITE_OMIT_XFER_OPT
- "OMIT_XFER_OPT",
-#endif
-#if SQLITE_PERFORMANCE_TRACE
- "PERFORMANCE_TRACE",
-#endif
-#if SQLITE_PROXY_DEBUG
- "PROXY_DEBUG",
-#endif
-#if SQLITE_RTREE_INT_ONLY
- "RTREE_INT_ONLY",
-#endif
-#if SQLITE_SECURE_DELETE
- "SECURE_DELETE",
-#endif
-#if SQLITE_SMALL_STACK
- "SMALL_STACK",
-#endif
-#if SQLITE_SOUNDEX
- "SOUNDEX",
-#endif
-#if SQLITE_SYSTEM_MALLOC
- "SYSTEM_MALLOC",
-#endif
-#if SQLITE_TCL
- "TCL",
-#endif
-#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
- "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
-#endif
-#if SQLITE_TEST
- "TEST",
-#endif
-#if defined(SQLITE_THREADSAFE)
- "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
-#endif
-#if SQLITE_USE_ALLOCA
- "USE_ALLOCA",
-#endif
-#if SQLITE_USER_AUTHENTICATION
- "USER_AUTHENTICATION",
-#endif
-#if SQLITE_WIN32_MALLOC
- "WIN32_MALLOC",
-#endif
-#if SQLITE_ZERO_MALLOC
- "ZERO_MALLOC"
-#endif
-};
-
-/*
-** Given the name of a compile-time option, return true if that option
-** was used and false if not.
-**
-** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
-** is not required for a match.
-*/
-SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
- int i, n;
-
-#if SQLITE_ENABLE_API_ARMOR
- if( zOptName==0 ){
- (void)SQLITE_MISUSE_BKPT;
- return 0;
- }
-#endif
- if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
- n = sqlite3Strlen30(zOptName);
-
- /* Since ArraySize(azCompileOpt) is normally in single digits, a
- ** linear search is adequate. No need for a binary search. */
- for(i=0; i<ArraySize(azCompileOpt); i++){
- if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
- && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
- ){
- return 1;
- }
- }
- return 0;
-}
-
-/*
-** Return the N-th compile-time option string. If N is out of range,
-** return a NULL pointer.
-*/
-SQLITE_API const char *sqlite3_compileoption_get(int N){
- if( N>=0 && N<ArraySize(azCompileOpt) ){
- return azCompileOpt[N];
- }
- return 0;
-}
-
-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
-
-/************** End of ctime.c ***********************************************/
/************** Begin file status.c ******************************************/
/*
** 2008 June 18
@@ -17718,7 +20740,8 @@ SQLITE_API const char *sqlite3_compileoption_get(int N){
** "explain" P4 display logic is enabled.
*/
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
- || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
+ || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \
+ || defined(SQLITE_ENABLE_BYTECODE_VTAB)
# define VDBE_DISPLAY_P4 1
#else
# define VDBE_DISPLAY_P4 0
@@ -17760,57 +20783,61 @@ typedef struct AuxData AuxData;
*/
typedef struct VdbeCursor VdbeCursor;
struct VdbeCursor {
- u8 eCurType; /* One of the CURTYPE_* values above */
- i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
- u8 nullRow; /* True if pointing to a row with no data */
- u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
- u8 isTable; /* True for rowid tables. False for indexes */
+ u8 eCurType; /* One of the CURTYPE_* values above */
+ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+ u8 nullRow; /* True if pointing to a row with no data */
+ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
+ u8 isTable; /* True for rowid tables. False for indexes */
#ifdef SQLITE_DEBUG
- u8 seekOp; /* Most recent seek operation on this cursor */
- u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
-#endif
- Bool isEphemeral:1; /* True for an ephemeral table */
- Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
- Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
- Pgno pgnoRoot; /* Root page of the open btree cursor */
- i16 nField; /* Number of fields in the header */
- u16 nHdrParsed; /* Number of header fields parsed so far */
+ u8 seekOp; /* Most recent seek operation on this cursor */
+ u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
+#endif
+ Bool isEphemeral:1; /* True for an ephemeral table */
+ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
+ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
+ Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
+ Btree *pBtx; /* Separate file holding temporary table */
+ i64 seqCount; /* Sequence counter */
+ u32 *aAltMap; /* Mapping from table to index column numbers */
+
+ /* Cached OP_Column parse information is only valid if cacheStatus matches
+ ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
+ ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
+ ** the cache is out of date. */
+ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
+ int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0
+ ** if there have been no prior seeks on the cursor. */
+ /* seekResult does not distinguish between "no seeks have ever occurred
+ ** on this cursor" and "the most recent seek was an exact match".
+ ** For CURTYPE_PSEUDO, seekResult is the register holding the record */
+
+ /* When a new VdbeCursor is allocated, only the fields above are zeroed.
+ ** The fields that follow are uninitialized, and must be individually
+ ** initialized prior to first use. */
+ VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
union {
- BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
- sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
- int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
- VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
+ BtCursor *pCursor; /* CURTYPE_BTREE or _PSEUDO. Btree cursor */
+ sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
+ VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
} uc;
- Btree *pBt; /* Separate file holding temporary table */
- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
- int seekResult; /* Result of previous sqlite3BtreeMoveto() */
- i64 seqCount; /* Sequence counter */
- i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
- int *aAltMap; /* Mapping from table to index column numbers */
+ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
+ u32 iHdrOffset; /* Offset to next unparsed byte of the header */
+ Pgno pgnoRoot; /* Root page of the open btree cursor */
+ i16 nField; /* Number of fields in the header */
+ u16 nHdrParsed; /* Number of header fields parsed so far */
+ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
+ u32 *aOffset; /* Pointer to aType[nField] */
+ const u8 *aRow; /* Data for the current row, if all on one page */
+ u32 payloadSize; /* Total number of bytes in the record */
+ u32 szRow; /* Byte available in aRow */
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
- u64 maskUsed; /* Mask of columns used by this cursor */
+ u64 maskUsed; /* Mask of columns used by this cursor */
#endif
- /* Cached information about the header for the data record that the
- ** cursor is currently pointing to. Only valid if cacheStatus matches
- ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
- ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
- ** the cache is out of date.
- **
- ** aRow might point to (ephemeral) data for the current row, or it might
- ** be NULL.
- */
- u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
- u32 payloadSize; /* Total number of bytes in the record */
- u32 szRow; /* Byte available in aRow */
- u32 iHdrOffset; /* Offset to next unparsed byte of the header */
- const u8 *aRow; /* Data for the current row, if all on one page */
- u32 *aOffset; /* Pointer to aType[nField] */
- u32 aType[1]; /* Type values for all entries in the record */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
** aType[] and nField+1 array slots for aOffset[] */
+ u32 aType[1]; /* Type values record decode. MUST BE LAST */
};
@@ -17823,7 +20850,7 @@ struct VdbeCursor {
** When a sub-program is executed (OP_Program), a structure of this type
** is allocated to store the current value of the program counter, as
** well as the current memory cell array and various other frame specific
-** values stored in the Vdbe struct. When the sub-program is finished,
+** values stored in the Vdbe struct. When the sub-program is finished,
** these values are copied back to the Vdbe from the VdbeFrame structure,
** restoring the state of the VM to as it was before the sub-program
** began executing.
@@ -17848,9 +20875,13 @@ struct VdbeFrame {
i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
+ u8 *aOnce; /* Bitmask used by OP_Once */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
AuxData *pAuxData; /* Linked list of auxdata allocations */
+#if SQLITE_DEBUG
+ u32 iFrameMagic; /* magic number for sanity checking */
+#endif
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
@@ -17861,6 +20892,13 @@ struct VdbeFrame {
int nDbChange; /* Value of db->nChange */
};
+/* Magic number for sanity checking on VdbeFrame objects */
+#define SQLITE_FRAME_MAGIC 0x879fb71e
+
+/*
+** Return a pointer to the array of registers allocated for use
+** by a VdbeFrame.
+*/
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
/*
@@ -17868,14 +20906,13 @@ struct VdbeFrame {
** structures. Each Mem struct may cache multiple representations (string,
** integer etc.) of the same value.
*/
-struct Mem {
+struct sqlite3_value {
union MemValue {
double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */
- int nZero; /* Used when bit MEM_Zero is set in flags */
+ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
+ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
- RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
- VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
} u;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
@@ -17890,7 +20927,7 @@ struct Mem {
void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
#ifdef SQLITE_DEBUG
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
- void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
+ u16 mScopyFlags; /* flags value immediately after the shallow copy */
#endif
};
@@ -17904,25 +20941,26 @@ struct Mem {
** representations of the value stored in the Mem struct.
**
** If the MEM_Null flag is set, then the value is an SQL NULL value.
-** No other flags may be set in this case.
+** For a pointer type created using sqlite3_bind_pointer() or
+** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
**
** If the MEM_Str flag is set then Mem.z points at a string representation.
** Usually this is encoded in the same unicode encoding as the main
** database (see below for exceptions). If the MEM_Term flag is also
-** set, then the string is nul terminated. The MEM_Int and MEM_Real
+** set, then the string is nul terminated. The MEM_Int and MEM_Real
** flags may coexist with the MEM_Str flag.
*/
-#define MEM_Null 0x0001 /* Value is NULL */
+#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */
#define MEM_Str 0x0002 /* Value is a string */
#define MEM_Int 0x0004 /* Value is an integer */
#define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */
-#define MEM_AffMask 0x001f /* Mask of affinity bits */
-#define MEM_RowSet 0x0020 /* Value is a RowSet object */
-#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
+#define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */
+#define MEM_AffMask 0x003f /* Mask of affinity bits */
+#define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
-#define MEM_TypeMask 0x81ff /* Mask of type bits */
+#define MEM_TypeMask 0xc1bf /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of
@@ -17930,7 +20968,7 @@ struct Mem {
** policy for Mem.z. The MEM_Term flag tells us whether or not the
** string is \000 or \u0000 terminated
*/
-#define MEM_Term 0x0200 /* String rep is nul terminated */
+#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */
#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
#define MEM_Static 0x0800 /* Mem.z points to a static string */
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
@@ -17946,7 +20984,7 @@ struct Mem {
** that needs to be deallocated to avoid a leak.
*/
#define VdbeMemDynamic(X) \
- (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
+ (((X)->flags&(MEM_Agg|MEM_Dyn))!=0)
/*
** Clear any existing type flags from a Mem and replace them with f
@@ -17955,6 +20993,13 @@ struct Mem {
((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
/*
+** True if Mem X is a NULL-nochng type.
+*/
+#define MemNullNochng(X) \
+ (((X)->flags&MEM_TypeMask)==(MEM_Null|MEM_Zero) \
+ && (X)->n==0 && (X)->u.nZero==0)
+
+/*
** Return true if a memory cell is not marked as invalid. This macro
** is for use inside assert() statements only.
*/
@@ -17963,18 +21008,18 @@ struct Mem {
#endif
/*
-** Each auxiliary data pointer stored by a user defined function
+** Each auxiliary data pointer stored by a user defined function
** implementation calling sqlite3_set_auxdata() is stored in an instance
** of this structure. All such structures associated with a single VM
** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
** when the VM is halted (if not before).
*/
struct AuxData {
- int iOp; /* Instruction number of OP_Function opcode */
- int iArg; /* Index of function argument. */
+ int iAuxOp; /* Instruction number of OP_Function opcode */
+ int iAuxArg; /* Index of function argument. */
void *pAux; /* Aux data pointer */
- void (*xDelete)(void *); /* Destructor for the aux data */
- AuxData *pNext; /* Next element in list */
+ void (*xDeleteAux)(void*); /* Destructor for the aux data */
+ AuxData *pNextAux; /* Next element in list */
};
/*
@@ -17998,7 +21043,6 @@ struct sqlite3_context {
int iOp; /* Instruction number of OP_Function */
int isError; /* Error code returned by the function. */
u8 skipFlag; /* Skip accumulator loading if true */
- u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
u8 argc; /* Number of arguments */
sqlite3_value *argv[1]; /* Argument set */
};
@@ -18008,6 +21052,9 @@ struct sqlite3_context {
*/
typedef unsigned bft; /* Bit Field Type */
+/* The ScanStatus object holds a single value for the
+** sqlite3_stmt_scanstatus() interface.
+*/
typedef struct ScanStatus ScanStatus;
struct ScanStatus {
int addrExplain; /* OP_Explain for loop */
@@ -18018,6 +21065,19 @@ struct ScanStatus {
char *zName; /* Name of table or index */
};
+/* The DblquoteStr object holds the text of a double-quoted
+** string for a prepared statement. A linked list of these objects
+** is constructed during statement parsing and is held on Vdbe.pDblStr.
+** When computing a normalized SQL statement for an SQL statement, that
+** list is consulted for each double-quoted identifier to see if the
+** identifier should really be a string literal.
+*/
+typedef struct DblquoteStr DblquoteStr;
+struct DblquoteStr {
+ DblquoteStr *pNextStr; /* Next string literal in the list */
+ char z[8]; /* Dequoted value for the string */
+};
+
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
@@ -18030,7 +21090,6 @@ struct Vdbe {
Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
Parse *pParse; /* Parsing context used to create this Vdbe */
ynVar nVar; /* Number of entries in aVar[] */
- ynVar nzVar; /* Number of entries in azVar[] */
u32 magic; /* Magic number for sanity checking */
int nMem; /* Number of memory locations currently allocated */
int nCursor; /* Number of slots in apCsr[] */
@@ -18038,47 +21097,53 @@ struct Vdbe {
int pc; /* The program counter */
int rc; /* Value to return */
int nChange; /* Number of db changes made since last reset */
- int iStatement; /* Statement number (or 0 if has not opened stmt) */
+ int iStatement; /* Statement number (or 0 if has no opened stmt) */
i64 iCurrentTime; /* Value of julianday('now') for this statement */
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
+ Mem *aMem; /* The memory locations */
+ Mem **apArg; /* Arguments to currently executing user function */
+ VdbeCursor **apCsr; /* One element of this array for each open cursor */
+ Mem *aVar; /* Values for the OP_Variable opcode. */
/* When allocating a new Vdbe object, all of the fields below should be
** initialized to zero or NULL */
Op *aOp; /* Space to hold the virtual machine's program */
- Mem *aMem; /* The memory locations */
- Mem **apArg; /* Arguments to currently executing user function */
+ int nOp; /* Number of instructions in the program */
+ int nOpAlloc; /* Slots allocated for aOp[] */
Mem *aColName; /* Column names to return */
Mem *pResultSet; /* Pointer to an array of results */
char *zErrMsg; /* Error message written here */
- VdbeCursor **apCsr; /* One element of this array for each open cursor */
- Mem *aVar; /* Values for the OP_Variable opcode. */
- char **azVar; /* Name of variables */
+ VList *pVList; /* Name of variables */
#ifndef SQLITE_OMIT_TRACE
i64 startTime; /* Time when query started - used for profiling */
#endif
- int nOp; /* Number of instructions in the program */
#ifdef SQLITE_DEBUG
int rcApp; /* errcode set by sqlite3_result_error_code() */
+ u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
- bft expired:1; /* True if the VM needs to be recompiled */
- bft doingRerun:1; /* True if rerunning after an auto-reprepare */
+ u8 prepFlags; /* SQLITE_PREPARE_* flags */
+ u8 doingRerun; /* True if rerunning after an auto-reprepare */
+ bft expired:2; /* 1: recompile VM immediately 2: when convenient */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft changeCntOn:1; /* True to update the change-counter */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
- bft isPrepareV2:1; /* True if prepared with prepare_v2() */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
- u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */
+ u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */
char *zSql; /* Text of the SQL statement that generated this */
+#ifdef SQLITE_ENABLE_NORMALIZE
+ char *zNormSql; /* Normalization of the associated SQL statement */
+ DblquoteStr *pDblStr; /* List of double-quoted string literals */
+#endif
void *pFree; /* Free this when deleting the vdbe */
VdbeFrame *pFrame; /* Parent frame */
VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */
@@ -18103,7 +21168,7 @@ struct Vdbe {
#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */
/*
-** Structure used to store the context required by the
+** Structure used to store the context required by the
** sqlite3_preupdate_*() API functions.
*/
struct PreUpdate {
@@ -18118,7 +21183,8 @@ struct PreUpdate {
i64 iKey1; /* First key value passed to hook */
i64 iKey2; /* Second key value passed to hook */
Mem *aNew; /* Array of new.* values */
- Table *pTab; /* Schema object being upated */
+ Table *pTab; /* Schema object being upated */
+ Index *pPk; /* PK index if pTab is WITHOUT ROWID */
};
/*
@@ -18127,14 +21193,11 @@ struct PreUpdate {
SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
void sqliteVdbePopStack(Vdbe*,int);
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
+SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
+SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, u32*);
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
-SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, Op*);
-#endif
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
-SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
@@ -18143,7 +21206,16 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
+SQLITE_PRIVATE int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**);
+SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3*,Op*);
+#endif
+#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
+SQLITE_PRIVATE char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*);
+#endif
+#if !defined(SQLITE_OMIT_EXPLAIN)
SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
+#endif
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *, int);
SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem*);
@@ -18158,27 +21230,42 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
#else
SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
#endif
+SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
-SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*);
+#endif
+SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
+SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull);
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
-SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
+SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem*,u8,u8);
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
+#endif
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
+#endif
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
-SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame*);
+#endif
+SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */
+SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
@@ -18189,12 +21276,20 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
SQLITE_PRIVATE void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
+SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *);
SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
-#if !defined(SQLITE_OMIT_SHARED_CACHE)
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*);
+SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*);
+#else
+# define sqlite3VdbeIncrWriteCounter(V,C)
+# define sqlite3VdbeAssertAbortable(V)
+#endif
+
+#if !defined(SQLITE_OMIT_SHARED_CACHE)
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
#else
# define sqlite3VdbeEnter(X)
@@ -18217,12 +21312,14 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *, int);
# define sqlite3VdbeCheckFk(p,i) 0
#endif
-SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE void sqlite3VdbePrintSql(Vdbe*);
-SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
+SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr);
+#endif
+#ifndef SQLITE_OMIT_UTF16
+SQLITE_PRIVATE int sqlite3VdbeMemTranslate(Mem*, u8);
+SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
#endif
-SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem);
#ifndef SQLITE_OMIT_INCRBLOB
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
@@ -18343,7 +21440,6 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
: sqlite3MallocMutex()) );
assert( op==SQLITE_STATUS_MALLOC_SIZE
|| op==SQLITE_STATUS_PAGECACHE_SIZE
- || op==SQLITE_STATUS_SCRATCH_SIZE
|| op==SQLITE_STATUS_PARSER_STACK );
if( newValue>wsdStat.mxValue[op] ){
wsdStat.mxValue[op] = newValue;
@@ -18393,6 +21489,32 @@ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetF
}
/*
+** Return the number of LookasideSlot elements on the linked list
+*/
+static u32 countLookasideSlots(LookasideSlot *p){
+ u32 cnt = 0;
+ while( p ){
+ p = p->pNext;
+ cnt++;
+ }
+ return cnt;
+}
+
+/*
+** Count the number of slots of lookaside memory that are outstanding
+*/
+SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
+ u32 nInit = countLookasideSlots(db->lookaside.pInit);
+ u32 nFree = countLookasideSlots(db->lookaside.pFree);
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ nInit += countLookasideSlots(db->lookaside.pSmallInit);
+ nFree += countLookasideSlots(db->lookaside.pSmallFree);
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
+ return db->lookaside.nSlot - (nInit+nFree);
+}
+
+/*
** Query status information for a single database connection
*/
SQLITE_API int sqlite3_db_status(
@@ -18411,10 +21533,24 @@ SQLITE_API int sqlite3_db_status(
sqlite3_mutex_enter(db->mutex);
switch( op ){
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
- *pCurrent = db->lookaside.nOut;
- *pHighwater = db->lookaside.mxOut;
+ *pCurrent = sqlite3LookasideUsed(db, pHighwater);
if( resetFlag ){
- db->lookaside.mxOut = db->lookaside.nOut;
+ LookasideSlot *p = db->lookaside.pFree;
+ if( p ){
+ while( p->pNext ) p = p->pNext;
+ p->pNext = db->lookaside.pInit;
+ db->lookaside.pInit = db->lookaside.pFree;
+ db->lookaside.pFree = 0;
+ }
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ p = db->lookaside.pSmallFree;
+ if( p ){
+ while( p->pNext ) p = p->pNext;
+ p->pNext = db->lookaside.pSmallInit;
+ db->lookaside.pSmallInit = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = 0;
+ }
+#endif
}
break;
}
@@ -18435,7 +21571,7 @@ SQLITE_API int sqlite3_db_status(
break;
}
- /*
+ /*
** Return an approximation for the amount of memory currently used
** by all pagers associated with the given database connection. The
** highwater mark is meaningless and is returned as zero.
@@ -18479,7 +21615,7 @@ SQLITE_API int sqlite3_db_status(
HashElem *p;
nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
- pSchema->tblHash.count
+ pSchema->tblHash.count
+ pSchema->trigHash.count
+ pSchema->idxHash.count
+ pSchema->fkeyHash.count
@@ -18529,9 +21665,12 @@ SQLITE_API int sqlite3_db_status(
/*
** Set *pCurrent to the total cache hits or misses encountered by all
- ** pagers the database handle is connected to. *pHighwater is always set
+ ** pagers the database handle is connected to. *pHighwater is always set
** to zero.
*/
+ case SQLITE_DBSTATUS_CACHE_SPILL:
+ op = SQLITE_DBSTATUS_CACHE_WRITE+1;
+ /* no break */ deliberate_fall_through
case SQLITE_DBSTATUS_CACHE_HIT:
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
@@ -18585,7 +21724,7 @@ SQLITE_API int sqlite3_db_status(
**
*************************************************************************
** This file contains the C functions that implement date and time
-** functions for SQLite.
+** functions for SQLite.
**
** There is only one exported symbol in this file - the function
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
@@ -18594,7 +21733,7 @@ SQLITE_API int sqlite3_db_status(
** SQLite processes all times and dates as julian day numbers. The
** dates and times are stored as the number of days since noon
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
-** calendar system.
+** calendar system.
**
** 1970-01-01 00:00:00 is JD 2440587.5
** 2000-01-01 00:00:00 is JD 2451544.5
@@ -18614,7 +21753,7 @@ SQLITE_API int sqlite3_db_status(
**
** Jean Meeus
** Astronomical Algorithms, 2nd Edition, 1998
-** ISBM 0-943396-61-1
+** ISBN 0-943396-61-1
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
@@ -18640,16 +21779,18 @@ struct tm *__cdecl localtime(const time_t *);
*/
typedef struct DateTime DateTime;
struct DateTime {
- sqlite3_int64 iJD; /* The julian day number times 86400000 */
- int Y, M, D; /* Year, month, and day */
- int h, m; /* Hour and minutes */
- int tz; /* Timezone offset in minutes */
- double s; /* Seconds */
- char validYMD; /* True (1) if Y,M,D are valid */
- char validHMS; /* True (1) if h,m,s are valid */
- char validJD; /* True (1) if iJD is valid */
- char validTZ; /* True (1) if tz is valid */
- char tzSet; /* Timezone was set explicitly */
+ sqlite3_int64 iJD; /* The julian day number times 86400000 */
+ int Y, M, D; /* Year, month, and day */
+ int h, m; /* Hour and minutes */
+ int tz; /* Timezone offset in minutes */
+ double s; /* Seconds */
+ char validJD; /* True (1) if iJD is valid */
+ char rawS; /* Raw numeric value stored in s */
+ char validYMD; /* True (1) if Y,M,D are valid */
+ char validHMS; /* True (1) if h,m,s are valid */
+ char validTZ; /* True (1) if tz is valid */
+ char tzSet; /* Timezone was set explicitly */
+ char isError; /* An overflow has occurred */
};
@@ -18797,6 +21938,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
s = 0;
}
p->validJD = 0;
+ p->rawS = 0;
p->validHMS = 1;
p->h = h;
p->m = m;
@@ -18807,6 +21949,14 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
}
/*
+** Put the DateTime object into its error state.
+*/
+static void datetimeError(DateTime *p){
+ memset(p, 0, sizeof(*p));
+ p->isError = 1;
+}
+
+/*
** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
** that the YYYY-MM-DD is according to the Gregorian calendar.
**
@@ -18825,6 +21975,10 @@ static void computeJD(DateTime *p){
M = 1;
D = 1;
}
+ if( Y<-4713 || Y>9999 || p->rawS ){
+ datetimeError(p);
+ return;
+ }
if( M<=2 ){
Y--;
M += 12;
@@ -18906,13 +22060,28 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
}
/*
+** Input "r" is a numeric quantity which might be a julian day number,
+** or the number of seconds since 1970. If the value if r is within
+** range of a julian day number, install it as such and set validJD.
+** If the value is a valid unix timestamp, put it in p->s and set p->rawS.
+*/
+static void setRawDateNumber(DateTime *p, double r){
+ p->s = r;
+ p->rawS = 1;
+ if( r>=0.0 && r<5373484.5 ){
+ p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
+ p->validJD = 1;
+ }
+}
+
+/*
** Attempt to parse the given string into a julian day number. Return
** the number of errors.
**
** The following are acceptable forms for the input string:
**
** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
-** DDDD.DD
+** DDDD.DD
** now
**
** In the first form, the +/-HH:MM is always optional. The fractional
@@ -18922,8 +22091,8 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
** as there is a year and date.
*/
static int parseDateOrTime(
- sqlite3_context *context,
- const char *zDate,
+ sqlite3_context *context,
+ const char *zDate,
DateTime *p
){
double r;
@@ -18931,16 +22100,33 @@ static int parseDateOrTime(
return 0;
}else if( parseHhMmSs(zDate, p)==0 ){
return 0;
- }else if( sqlite3StrICmp(zDate,"now")==0){
+ }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){
return setDateTimeToCurrent(context, p);
- }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
- p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
- p->validJD = 1;
+ }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
+ setRawDateNumber(p, r);
return 0;
}
return 1;
}
+/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999.
+** Multiplying this by 86400000 gives 464269060799999 as the maximum value
+** for DateTime.iJD.
+**
+** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with
+** such a large integer literal, so we have to encode it.
+*/
+#define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff)
+
+/*
+** Return TRUE if the given julian day number is within range.
+**
+** The input is the JulianDay times 86400000.
+*/
+static int validJulianDay(sqlite3_int64 iJD){
+ return iJD>=0 && iJD<=INT_464269060799999;
+}
+
/*
** Compute the Year, Month, and Day from the julian day number.
*/
@@ -18951,6 +22137,9 @@ static void computeYMD(DateTime *p){
p->Y = 2000;
p->M = 1;
p->D = 1;
+ }else if( !validJulianDay(p->iJD) ){
+ datetimeError(p);
+ return;
}else{
Z = (int)((p->iJD + 43200000)/86400000);
A = (int)((Z - 1867216.25)/36524.25);
@@ -18982,6 +22171,7 @@ static void computeHMS(DateTime *p){
s -= p->h*3600;
p->m = s/60;
p->s += s - p->m*60;
+ p->rawS = 0;
p->validHMS = 1;
}
@@ -19005,14 +22195,14 @@ static void clearYMD_HMS_TZ(DateTime *p){
#ifndef SQLITE_OMIT_LOCALTIME
/*
** 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
+** 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
+** already, check for an MSVC build environment that provides
** localtime_s().
*/
#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
@@ -19039,18 +22229,18 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
struct tm *pX;
#if SQLITE_THREADSAFE>0
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
sqlite3_mutex_enter(mutex);
pX = localtime(t);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
#endif
if( pX ) *pTm = *pX;
sqlite3_mutex_leave(mutex);
rc = pX==0;
#else
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
#endif
#if HAVE_LOCALTIME_R
@@ -19068,7 +22258,7 @@ static int osLocaltime(time_t *t, struct tm *pTm){
/*
** 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.
+** 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.
@@ -19121,7 +22311,9 @@ static sqlite3_int64 localtimeOffset(
y.validYMD = 1;
y.validHMS = 1;
y.validJD = 0;
+ y.rawS = 0;
y.validTZ = 0;
+ y.isError = 0;
computeJD(&y);
*pRc = SQLITE_OK;
return y.iJD - x.iJD;
@@ -19129,6 +22321,29 @@ static sqlite3_int64 localtimeOffset(
#endif /* SQLITE_OMIT_LOCALTIME */
/*
+** The following table defines various date transformations of the form
+**
+** 'NNN days'
+**
+** Where NNN is an arbitrary floating-point number and "days" can be one
+** of several units of time.
+*/
+static const struct {
+ u8 eType; /* Transformation type code */
+ u8 nName; /* Length of th name */
+ char *zName; /* Name of the transformation */
+ double rLimit; /* Maximum NNN value for this transform */
+ double rXform; /* Constant used for this transform */
+} aXformType[] = {
+ { 0, 6, "second", 464269060800.0, 1000.0 },
+ { 0, 6, "minute", 7737817680.0, 60000.0 },
+ { 0, 4, "hour", 128963628.0, 3600000.0 },
+ { 0, 3, "day", 5373485.0, 86400000.0 },
+ { 1, 5, "month", 176546.0, 2592000000.0 },
+ { 2, 4, "year", 14713.0, 31536000000.0 },
+};
+
+/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
**
@@ -19152,17 +22367,15 @@ static sqlite3_int64 localtimeOffset(
** to context pCtx. If the error is an unrecognized modifier, no error is
** written to pCtx.
*/
-static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
+static int parseModifier(
+ sqlite3_context *pCtx, /* Function context */
+ const char *z, /* The text of the modifier */
+ int n, /* Length of zMod in bytes */
+ DateTime *p /* The date/time value to be modified */
+){
int rc = 1;
- int n;
double r;
- char *z, zBuf[30];
- z = zBuf;
- for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
- z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
- }
- z[n] = 0;
- switch( z[0] ){
+ switch(sqlite3UpperToLower[(u8)z[0]] ){
#ifndef SQLITE_OMIT_LOCALTIME
case 'l': {
/* localtime
@@ -19170,7 +22383,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
** show local time.
*/
- if( strcmp(z, "localtime")==0 ){
+ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
computeJD(p);
p->iJD += localtimeOffset(p, pCtx, &rc);
clearYMD_HMS_TZ(p);
@@ -19182,16 +22395,21 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
/*
** unixepoch
**
- ** Treat the current value of p->iJD as the number of
+ ** Treat the current value of p->s as the number of
** seconds since 1970. Convert to a real julian day number.
*/
- if( strcmp(z, "unixepoch")==0 && p->validJD ){
- p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
- clearYMD_HMS_TZ(p);
- rc = 0;
+ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
+ r = p->s*1000.0 + 210866760000000.0;
+ if( r>=0.0 && r<464269060800000.0 ){
+ clearYMD_HMS_TZ(p);
+ p->iJD = (sqlite3_int64)(r + 0.5);
+ p->validJD = 1;
+ p->rawS = 0;
+ rc = 0;
+ }
}
#ifndef SQLITE_OMIT_LOCALTIME
- else if( strcmp(z, "utc")==0 ){
+ else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
if( p->tzSet==0 ){
sqlite3_int64 c1;
computeJD(p);
@@ -19217,8 +22435,8 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
** date is already on the appropriate weekday, this is a no-op.
*/
- if( strncmp(z, "weekday ", 8)==0
- && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
+ if( sqlite3_strnicmp(z, "weekday ", 8)==0
+ && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
&& (n=(int)r)==r && n>=0 && r<7 ){
sqlite3_int64 Z;
computeYMD_HMS(p);
@@ -19240,23 +22458,24 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Move the date backwards to the beginning of the current day,
** or month or year.
*/
- if( strncmp(z, "start of ", 9)!=0 ) break;
+ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
+ if( !p->validJD && !p->validYMD && !p->validHMS ) break;
z += 9;
computeYMD(p);
p->validHMS = 1;
p->h = p->m = 0;
p->s = 0.0;
+ p->rawS = 0;
p->validTZ = 0;
p->validJD = 0;
- if( strcmp(z,"month")==0 ){
+ if( sqlite3_stricmp(z,"month")==0 ){
p->D = 1;
rc = 0;
- }else if( strcmp(z,"year")==0 ){
- computeYMD(p);
+ }else if( sqlite3_stricmp(z,"year")==0 ){
p->M = 1;
p->D = 1;
rc = 0;
- }else if( strcmp(z,"day")==0 ){
+ }else if( sqlite3_stricmp(z,"day")==0 ){
rc = 0;
}
break;
@@ -19274,8 +22493,9 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
case '8':
case '9': {
double rRounder;
+ int i;
for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
- if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
+ if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){
rc = 1;
break;
}
@@ -19302,46 +22522,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
rc = 0;
break;
}
+
+ /* If control reaches this point, it means the transformation is
+ ** one of the forms like "+NNN days". */
z += n;
while( sqlite3Isspace(*z) ) z++;
n = sqlite3Strlen30(z);
if( n>10 || n<3 ) break;
- if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
+ if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p);
- rc = 0;
+ rc = 1;
rRounder = r<0 ? -0.5 : +0.5;
- if( n==3 && strcmp(z,"day")==0 ){
- p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
- }else if( n==4 && strcmp(z,"hour")==0 ){
- p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
- }else if( n==6 && strcmp(z,"minute")==0 ){
- p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
- }else if( n==6 && strcmp(z,"second")==0 ){
- p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
- }else if( n==5 && strcmp(z,"month")==0 ){
- int x, y;
- computeYMD_HMS(p);
- p->M += (int)r;
- x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
- p->Y += x;
- p->M -= x*12;
- p->validJD = 0;
- computeJD(p);
- y = (int)r;
- if( y!=r ){
- p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
- }
- }else if( n==4 && strcmp(z,"year")==0 ){
- int y = (int)r;
- computeYMD_HMS(p);
- p->Y += y;
- p->validJD = 0;
- computeJD(p);
- if( y!=r ){
- p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
+ for(i=0; i<ArraySize(aXformType); i++){
+ if( aXformType[i].nName==n
+ && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
+ && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
+ ){
+ switch( aXformType[i].eType ){
+ case 1: { /* Special processing to add months */
+ int x;
+ computeYMD_HMS(p);
+ p->M += (int)r;
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+ p->Y += x;
+ p->M -= x*12;
+ p->validJD = 0;
+ r -= (int)r;
+ break;
+ }
+ case 2: { /* Special processing to add years */
+ int y = (int)r;
+ computeYMD_HMS(p);
+ p->Y += y;
+ p->validJD = 0;
+ r -= (int)r;
+ break;
+ }
+ }
+ computeJD(p);
+ p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
+ rc = 0;
+ break;
}
- }else{
- rc = 1;
}
clearYMD_HMS_TZ(p);
break;
@@ -19363,12 +22585,12 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** then assume a default value of "now" for argv[0].
*/
static int isDate(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv,
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv,
DateTime *p
){
- int i;
+ int i, n;
const unsigned char *z;
int eType;
memset(p, 0, sizeof(*p));
@@ -19377,8 +22599,7 @@ static int isDate(
}
if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|| eType==SQLITE_INTEGER ){
- p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
- p->validJD = 1;
+ setRawDateNumber(p, sqlite3_value_double(argv[0]));
}else{
z = sqlite3_value_text(argv[0]);
if( !z || parseDateOrTime(context, (char*)z, p) ){
@@ -19387,8 +22608,11 @@ static int isDate(
}
for(i=1; i<argc; i++){
z = sqlite3_value_text(argv[i]);
- if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
+ n = sqlite3_value_bytes(argv[i]);
+ if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
}
+ computeJD(p);
+ if( p->isError || !validJulianDay(p->iJD) ) return 1;
return 0;
}
@@ -19602,8 +22826,8 @@ static void strftimeFunc(
case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
case 's': {
- sqlite3_snprintf(30,&z[j],"%lld",
- (i64)(x.iJD/1000 - 21086676*(i64)10000));
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ sqlite3Int64ToText(iS, &z[j]);
j += sqlite3Strlen30(&z[j]);
break;
}
@@ -19701,10 +22925,10 @@ static void currentTimeFunc(
#if HAVE_GMTIME_R
pTm = gmtime_r(&t, &sNow);
#else
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
pTm = gmtime(&t);
if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
#endif
if( pTm ){
strftime(zBuf, 20, zFormat, &sNow);
@@ -19721,11 +22945,11 @@ static void currentTimeFunc(
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
- DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
- DFUNCTION(date, -1, 0, 0, dateFunc ),
- DFUNCTION(time, -1, 0, 0, timeFunc ),
- DFUNCTION(datetime, -1, 0, 0, datetimeFunc ),
- DFUNCTION(strftime, -1, 0, 0, strftimeFunc ),
+ PURE_DATE(julianday, -1, 0, 0, juliandayFunc ),
+ PURE_DATE(date, -1, 0, 0, dateFunc ),
+ PURE_DATE(time, -1, 0, 0, timeFunc ),
+ PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
+ PURE_DATE(strftime, -1, 0, 0, strftimeFunc ),
DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
@@ -19840,7 +23064,7 @@ SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file *id, i64 size){
}
SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file *id, int flags){
DO_OS_MALLOC_TEST(id);
- return id->pMethods->xSync(id, flags);
+ return flags ? id->pMethods->xSync(id, flags) : SQLITE_OK;
}
SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
DO_OS_MALLOC_TEST(id);
@@ -19867,8 +23091,11 @@ SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
** routine has no return value since the return value would be meaningless.
*/
SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
+ if( id->pMethods==0 ) return SQLITE_NOTFOUND;
#ifdef SQLITE_TEST
- if( op!=SQLITE_FCNTL_COMMIT_PHASETWO ){
+ if( op!=SQLITE_FCNTL_COMMIT_PHASETWO
+ && op!=SQLITE_FCNTL_LOCK_TIMEOUT
+ ){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
@@ -19885,7 +23112,7 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
return id->pMethods->xFileControl(id, op, pArg);
}
SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file *id, int op, void *pArg){
- (void)id->pMethods->xFileControl(id, op, pArg);
+ if( id->pMethods ) (void)id->pMethods->xFileControl(id, op, pArg);
}
SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
@@ -19895,6 +23122,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
+#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
return id->pMethods->xShmLock(id, offset, n, flags);
}
@@ -19914,6 +23142,7 @@ SQLITE_PRIVATE int sqlite3OsShmMap(
DO_OS_MALLOC_TEST(id);
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
}
+#endif /* SQLITE_OMIT_WAL */
#if SQLITE_MAX_MMAP_SIZE>0
/* The real implementation of xFetch and xUnfetch */
@@ -19952,7 +23181,7 @@ SQLITE_PRIVATE int sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
- rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x87f7f, pFlagsOut);
+ rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
}
@@ -19995,7 +23224,15 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *pVfs, void *pHandle){
}
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
- return pVfs->xRandomness(pVfs, nByte, zBufOut);
+ if( sqlite3Config.iPrngSeed ){
+ memset(zBufOut, 0, nByte);
+ if( ALWAYS(nByte>(signed)sizeof(unsigned)) ) nByte = sizeof(unsigned int);
+ memcpy(zBufOut, &sqlite3Config.iPrngSeed, nByte);
+ return SQLITE_OK;
+ }else{
+ return pVfs->xRandomness(pVfs, nByte, zBufOut);
+ }
+
}
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
@@ -20082,7 +23319,7 @@ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
if( rc ) return 0;
#endif
#if SQLITE_THREADSAFE
- mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
sqlite3_mutex_enter(mutex);
for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
@@ -20097,7 +23334,7 @@ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
** Unlink a VFS from the linked list
*/
static void vfsUnlink(sqlite3_vfs *pVfs){
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) );
if( pVfs==0 ){
/* No-op */
}else if( vfsList==pVfs ){
@@ -20128,7 +23365,7 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
#endif
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
if( makeDflt || vfsList==0 ){
@@ -20147,9 +23384,12 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
** Unregister a VFS so that it is no longer accessible.
*/
SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
-#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ MUTEX_LOGIC(sqlite3_mutex *mutex;)
+#ifndef SQLITE_OMIT_AUTOINIT
+ int rc = sqlite3_initialize();
+ if( rc ) return rc;
#endif
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
sqlite3_mutex_enter(mutex);
vfsUnlink(pVfs);
sqlite3_mutex_leave(mutex);
@@ -20170,23 +23410,23 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
**
*************************************************************************
**
-** This file contains code to support the concept of "benign"
+** This file contains code to support the concept of "benign"
** malloc failures (when the xMalloc() or xRealloc() method of the
** sqlite3_mem_methods structure fails to allocate a block of memory
-** and returns 0).
+** and returns 0).
**
** Most malloc failures are non-benign. After they occur, SQLite
** abandons the current operation and returns an error code (usually
** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
-** fatal. For example, if a malloc fails while resizing a hash table, this
-** is completely recoverable simply by not carrying out the resize. The
-** hash table will continue to function normally. So a malloc failure
+** fatal. For example, if a malloc fails while resizing a hash table, this
+** is completely recoverable simply by not carrying out the resize. The
+** hash table will continue to function normally. So a malloc failure
** during a hash table resize is a benign fault.
*/
/* #include "sqliteInt.h" */
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
/*
** Global variables.
@@ -20244,7 +23484,7 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
}
}
-#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
+#endif /* #ifndef SQLITE_UNTESTABLE */
/************** End of fault.c ***********************************************/
/************** Begin file mem0.c ********************************************/
@@ -20369,7 +23609,9 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
*/
#include <sys/sysctl.h>
#include <malloc/malloc.h>
+#ifdef SQLITE_MIGHT_BE_SINGLE_CORE
#include <libkern/OSAtomic.h>
+#endif /* SQLITE_MIGHT_BE_SINGLE_CORE */
static malloc_zone_t* _sqliteZone_;
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
@@ -20380,7 +23622,7 @@ static malloc_zone_t* _sqliteZone_;
#else /* if not __APPLE__ */
/*
-** Use standard C library malloc and free on non-Apple systems.
+** Use standard C library malloc and free on non-Apple systems.
** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined.
*/
#define SQLITE_MALLOC(x) malloc(x)
@@ -20437,7 +23679,9 @@ static malloc_zone_t* _sqliteZone_;
*/
static void *sqlite3MemMalloc(int nByte){
#ifdef SQLITE_MALLOCSIZE
- void *p = SQLITE_MALLOC( nByte );
+ void *p;
+ testcase( ROUND8(nByte)==nByte );
+ p = SQLITE_MALLOC( nByte );
if( p==0 ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte);
@@ -20446,7 +23690,7 @@ static void *sqlite3MemMalloc(int nByte){
#else
sqlite3_int64 *p;
assert( nByte>0 );
- nByte = ROUND8(nByte);
+ testcase( ROUND8(nByte)!=nByte );
p = SQLITE_MALLOC( nByte+8 );
if( p ){
p[0] = nByte;
@@ -20558,21 +23802,12 @@ static int sqlite3MemInit(void *NotUsed){
/* defer MT decisions to system malloc */
_sqliteZone_ = malloc_default_zone();
}else{
- /* only 1 core, use our own zone to contention over global locks,
+ /* only 1 core, use our own zone to contention over global locks,
** e.g. we have our own dedicated locks */
- bool success;
- malloc_zone_t* newzone = malloc_create_zone(4096, 0);
- malloc_set_zone_name(newzone, "Sqlite_Heap");
- do{
- success = OSAtomicCompareAndSwapPtrBarrier(NULL, newzone,
- (void * volatile *)&_sqliteZone_);
- }while(!_sqliteZone_);
- if( !success ){
- /* somebody registered a zone first */
- malloc_destroy_zone(newzone);
- }
+ _sqliteZone_ = malloc_create_zone(4096, 0);
+ malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap");
}
-#endif
+#endif /* defined(__APPLE__) && !defined(SQLITE_WITHOUT_ZONEMALLOC) */
UNUSED_PARAMETER(NotUsed);
return SQLITE_OK;
}
@@ -20691,7 +23926,7 @@ struct MemBlockHdr {
** when this module is combined with other in the amalgamation.
*/
static struct {
-
+
/*
** Mutex to control access to the memory allocation subsystem.
*/
@@ -20702,7 +23937,7 @@ static struct {
*/
struct MemBlockHdr *pFirst;
struct MemBlockHdr *pLast;
-
+
/*
** The number of levels of backtrace to save in new allocations.
*/
@@ -20715,7 +23950,7 @@ static struct {
int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */
char zTitle[100]; /* The title text */
- /*
+ /*
** sqlite3MallocDisallow() increments the following counter.
** sqlite3MallocAllow() decrements it.
*/
@@ -20774,7 +24009,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
pU8 = (u8*)pAllocation;
assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
/* This checks any of the "extra" bytes allocated due
- ** to rounding up to an 8 byte boundary to ensure
+ ** to rounding up to an 8 byte boundary to ensure
** they haven't been overwritten.
*/
while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );
@@ -20903,7 +24138,7 @@ static void *sqlite3MemMalloc(int nByte){
p = (void*)pInt;
}
sqlite3_mutex_leave(mem.mutex);
- return p;
+ return p;
}
/*
@@ -20913,7 +24148,7 @@ static void sqlite3MemFree(void *pPrior){
struct MemBlockHdr *pHdr;
void **pBt;
char *z;
- assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
+ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
|| mem.mutex!=0 );
pHdr = sqlite3MemsysGetHeader(pPrior);
pBt = (void**)pHdr;
@@ -20939,15 +24174,15 @@ static void sqlite3MemFree(void *pPrior){
randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
(int)pHdr->iSize + sizeof(int) + pHdr->nTitle);
free(z);
- sqlite3_mutex_leave(mem.mutex);
+ sqlite3_mutex_leave(mem.mutex);
}
/*
** Change the size of an existing memory allocation.
**
** For this debugging implementation, we *always* make a copy of the
-** allocation into a new place in memory. In this way, if the
-** higher level code is using pointer to the old allocation, it is
+** allocation into a new place in memory. In this way, if the
+** higher level code is using pointer to the old allocation, it is
** much more likely to break and we are much more liking to find
** the error.
*/
@@ -20990,7 +24225,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
** Set the "type" of an allocation.
*/
SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD );
@@ -21009,7 +24244,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
*/
SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
int rc = 1;
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
@@ -21031,7 +24266,7 @@ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
*/
SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
int rc = 1;
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
@@ -21081,7 +24316,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSync(){
}
/*
-** Open the file indicated and write a log of all unfreed memory
+** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
@@ -21098,7 +24333,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
char *z = (char*)pHdr;
z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
- fprintf(out, "**** %lld bytes at %p from %s ****\n",
+ fprintf(out, "**** %lld bytes at %p from %s ****\n",
pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
if( pHdr->nBacktrace ){
fflush(out);
@@ -21111,7 +24346,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
fprintf(out, "COUNTS:\n");
for(i=0; i<NCSIZE-1; i++){
if( mem.nAlloc[i] ){
- fprintf(out, " %5d: %10d %10d %10d\n",
+ fprintf(out, " %5d: %10d %10d %10d\n",
i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]);
}
}
@@ -21152,12 +24387,12 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
**
*************************************************************************
** This file contains the C functions that implement a memory
-** allocation subsystem for use by SQLite.
+** allocation subsystem for use by SQLite.
**
** This version of the memory allocation subsystem omits all
** use of malloc(). The SQLite user supplies a block of memory
** before calling sqlite3_initialize() from which allocations
-** are made and returned by the xMalloc() and xRealloc()
+** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot
** be changed.
@@ -21188,8 +24423,8 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
#define N_HASH 61
/*
-** A memory allocation (also called a "chunk") consists of two or
-** more blocks where each block is 8 bytes. The first 8 bytes are
+** A memory allocation (also called a "chunk") consists of two or
+** more blocks where each block is 8 bytes. The first 8 bytes are
** a header that is not returned to the user.
**
** A chunk is two or more blocks that is either checked out or
@@ -21212,10 +24447,10 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
**
** The second block of free chunks is of the form u.list. The
** two fields form a double-linked list of chunks of related sizes.
-** Pointers to the head of the list are stored in mem3.aiSmall[]
+** Pointers to the head of the list are stored in mem3.aiSmall[]
** for smaller chunks and mem3.aiHash[] for larger chunks.
**
-** The second block of a chunk is user data if the chunk is checked
+** The second block of a chunk is user data if the chunk is checked
** out. If a chunk is checked out, the user data may extend into
** the u.hdr.prevSize value of the following chunk.
*/
@@ -21251,28 +24486,28 @@ static SQLITE_WSD struct Mem3Global {
** True if we are evaluating an out-of-memory callback.
*/
int alarmBusy;
-
+
/*
** Mutex to control access to the memory allocation subsystem.
*/
sqlite3_mutex *mutex;
-
+
/*
** The minimum amount of free space that we have seen.
*/
- u32 mnMaster;
+ u32 mnKeyBlk;
/*
- ** iMaster is the index of the master chunk. Most new allocations
- ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
- ** of the current master. iMaster is 0 if there is not master chunk.
- ** The master chunk is not in either the aiHash[] or aiSmall[].
+ ** iKeyBlk is the index of the key chunk. Most new allocations
+ ** occur off of this chunk. szKeyBlk is the size (in Mem3Blocks)
+ ** of the current key chunk. iKeyBlk is 0 if there is no key chunk.
+ ** The key chunk is not in either the aiHash[] or aiSmall[].
*/
- u32 iMaster;
- u32 szMaster;
+ u32 iKeyBlk;
+ u32 szKeyBlk;
/*
- ** Array of lists of free blocks according to the block size
+ ** Array of lists of free blocks according to the block size
** for smaller chunks, or a hash on the block size for larger
** chunks.
*/
@@ -21303,7 +24538,7 @@ static void memsys3UnlinkFromList(u32 i, u32 *pRoot){
}
/*
-** Unlink the chunk at index i from
+** Unlink the chunk at index i from
** whatever list is currently a member of.
*/
static void memsys3Unlink(u32 i){
@@ -21387,8 +24622,8 @@ static void memsys3OutOfMemory(int nByte){
/*
-** Chunk i is a free chunk that has been unlinked. Adjust its
-** size parameters for check-out and return a pointer to the
+** Chunk i is a free chunk that has been unlinked. Adjust its
+** size parameters for check-out and return a pointer to the
** user portion of the chunk.
*/
static void *memsys3Checkout(u32 i, u32 nBlock){
@@ -21405,34 +24640,34 @@ static void *memsys3Checkout(u32 i, u32 nBlock){
}
/*
-** Carve a piece off of the end of the mem3.iMaster free chunk.
-** Return a pointer to the new allocation. Or, if the master chunk
+** Carve a piece off of the end of the mem3.iKeyBlk free chunk.
+** Return a pointer to the new allocation. Or, if the key chunk
** is not large enough, return 0.
*/
-static void *memsys3FromMaster(u32 nBlock){
+static void *memsys3FromKeyBlk(u32 nBlock){
assert( sqlite3_mutex_held(mem3.mutex) );
- assert( mem3.szMaster>=nBlock );
- if( nBlock>=mem3.szMaster-1 ){
- /* Use the entire master */
- void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
- mem3.iMaster = 0;
- mem3.szMaster = 0;
- mem3.mnMaster = 0;
+ assert( mem3.szKeyBlk>=nBlock );
+ if( nBlock>=mem3.szKeyBlk-1 ){
+ /* Use the entire key chunk */
+ void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk);
+ mem3.iKeyBlk = 0;
+ mem3.szKeyBlk = 0;
+ mem3.mnKeyBlk = 0;
return p;
}else{
- /* Split the master block. Return the tail. */
+ /* Split the key block. Return the tail. */
u32 newi, x;
- newi = mem3.iMaster + mem3.szMaster - nBlock;
- assert( newi > mem3.iMaster+1 );
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
+ newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock;
+ assert( newi > mem3.iKeyBlk+1 );
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2;
mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
- mem3.szMaster -= nBlock;
- mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- if( mem3.szMaster < mem3.mnMaster ){
- mem3.mnMaster = mem3.szMaster;
+ mem3.szKeyBlk -= nBlock;
+ mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk;
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ if( mem3.szKeyBlk < mem3.mnKeyBlk ){
+ mem3.mnKeyBlk = mem3.szKeyBlk;
}
return (void*)&mem3.aPool[newi];
}
@@ -21441,18 +24676,18 @@ static void *memsys3FromMaster(u32 nBlock){
/*
** *pRoot is the head of a list of free chunks of the same size
** or same size hash. In other words, *pRoot is an entry in either
-** mem3.aiSmall[] or mem3.aiHash[].
+** mem3.aiSmall[] or mem3.aiHash[].
**
** This routine examines all entries on the given list and tries
-** to coalesce each entries with adjacent free chunks.
+** to coalesce each entries with adjacent free chunks.
**
-** If it sees a chunk that is larger than mem3.iMaster, it replaces
-** the current mem3.iMaster with the new larger chunk. In order for
-** this mem3.iMaster replacement to work, the master chunk must be
+** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces
+** the current mem3.iKeyBlk with the new larger chunk. In order for
+** this mem3.iKeyBlk replacement to work, the key chunk must be
** linked into the hash tables. That is not the normal state of
-** affairs, of course. The calling routine must link the master
+** affairs, of course. The calling routine must link the key
** chunk before invoking this routine, then must unlink the (possibly
-** changed) master chunk once this routine has finished.
+** changed) key chunk once this routine has finished.
*/
static void memsys3Merge(u32 *pRoot){
u32 iNext, prev, size, i, x;
@@ -21479,9 +24714,9 @@ static void memsys3Merge(u32 *pRoot){
}else{
size /= 4;
}
- if( size>mem3.szMaster ){
- mem3.iMaster = i;
- mem3.szMaster = size;
+ if( size>mem3.szKeyBlk ){
+ mem3.iKeyBlk = i;
+ mem3.szKeyBlk = size;
}
}
}
@@ -21530,26 +24765,26 @@ static void *memsys3MallocUnsafe(int nByte){
/* STEP 2:
** Try to satisfy the allocation by carving a piece off of the end
- ** of the master chunk. This step usually works if step 1 fails.
+ ** of the key chunk. This step usually works if step 1 fails.
*/
- if( mem3.szMaster>=nBlock ){
- return memsys3FromMaster(nBlock);
+ if( mem3.szKeyBlk>=nBlock ){
+ return memsys3FromKeyBlk(nBlock);
}
- /* STEP 3:
+ /* STEP 3:
** Loop through the entire memory pool. Coalesce adjacent free
- ** chunks. Recompute the master chunk as the largest free chunk.
+ ** chunks. Recompute the key chunk as the largest free chunk.
** Then try again to satisfy the allocation by carving a piece off
- ** of the end of the master chunk. This step happens very
+ ** of the end of the key chunk. This step happens very
** rarely (we hope!)
*/
for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
memsys3OutOfMemory(toFree);
- if( mem3.iMaster ){
- memsys3Link(mem3.iMaster);
- mem3.iMaster = 0;
- mem3.szMaster = 0;
+ if( mem3.iKeyBlk ){
+ memsys3Link(mem3.iKeyBlk);
+ mem3.iKeyBlk = 0;
+ mem3.szKeyBlk = 0;
}
for(i=0; i<N_HASH; i++){
memsys3Merge(&mem3.aiHash[i]);
@@ -21557,10 +24792,10 @@ static void *memsys3MallocUnsafe(int nByte){
for(i=0; i<MX_SMALL-1; i++){
memsys3Merge(&mem3.aiSmall[i]);
}
- if( mem3.szMaster ){
- memsys3Unlink(mem3.iMaster);
- if( mem3.szMaster>=nBlock ){
- return memsys3FromMaster(nBlock);
+ if( mem3.szKeyBlk ){
+ memsys3Unlink(mem3.iKeyBlk);
+ if( mem3.szKeyBlk>=nBlock ){
+ return memsys3FromKeyBlk(nBlock);
}
}
}
@@ -21590,23 +24825,23 @@ static void memsys3FreeUnsafe(void *pOld){
mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
memsys3Link(i);
- /* Try to expand the master using the newly freed chunk */
- if( mem3.iMaster ){
- while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
- size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
- mem3.iMaster -= size;
- mem3.szMaster += size;
- memsys3Unlink(mem3.iMaster);
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ /* Try to expand the key using the newly freed chunk */
+ if( mem3.iKeyBlk ){
+ while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){
+ size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize;
+ mem3.iKeyBlk -= size;
+ mem3.szKeyBlk += size;
+ memsys3Unlink(mem3.iKeyBlk);
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
}
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
- while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
- memsys3Unlink(mem3.iMaster+mem3.szMaster);
- mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
+ while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){
+ memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk);
+ mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4;
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
}
}
}
@@ -21644,7 +24879,7 @@ static void *memsys3Malloc(int nBytes){
memsys3Enter();
p = memsys3MallocUnsafe(nBytes);
memsys3Leave();
- return (void*)p;
+ return (void*)p;
}
/*
@@ -21702,11 +24937,11 @@ static int memsys3Init(void *NotUsed){
mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
- /* Initialize the master block. */
- mem3.szMaster = mem3.nPool;
- mem3.mnMaster = mem3.szMaster;
- mem3.iMaster = 1;
- mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
+ /* Initialize the key block. */
+ mem3.szKeyBlk = mem3.nPool;
+ mem3.mnKeyBlk = mem3.szKeyBlk;
+ mem3.iKeyBlk = 1;
+ mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2;
mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
@@ -21725,7 +24960,7 @@ static void memsys3Shutdown(void *NotUsed){
/*
-** Open the file indicated and write a log of all unfreed memory
+** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
@@ -21766,7 +25001,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
}else{
fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
- i==mem3.iMaster ? " **master**" : "");
+ i==mem3.iKeyBlk ? " **key**" : "");
}
}
for(i=0; i<MX_SMALL-1; i++){
@@ -21776,7 +25011,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
fprintf(out, " %p(%d)", &mem3.aPool[j],
(mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
}
- fprintf(out, "\n");
+ fprintf(out, "\n");
}
for(i=0; i<N_HASH; i++){
if( mem3.aiHash[i]==0 ) continue;
@@ -21785,11 +25020,11 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
fprintf(out, " %p(%d)", &mem3.aPool[j],
(mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
}
- fprintf(out, "\n");
+ fprintf(out, "\n");
}
- fprintf(out, "master=%d\n", mem3.iMaster);
- fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
- fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
+ fprintf(out, "key=%d\n", mem3.iKeyBlk);
+ fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8);
+ fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8);
sqlite3_mutex_leave(mem3.mutex);
if( out==stdout ){
fflush(stdout);
@@ -21802,7 +25037,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
}
/*
-** This routine is the only routine in this file with external
+** This routine is the only routine in this file with external
** linkage.
**
** Populate the low-level memory allocation function pointers in
@@ -21842,12 +25077,12 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
**
*************************************************************************
** This file contains the C functions that implement a memory
-** allocation subsystem for use by SQLite.
+** allocation subsystem for use by SQLite.
**
** This version of the memory allocation subsystem omits all
** use of malloc(). The application gives SQLite a block of memory
** before calling sqlite3_initialize() from which allocations
-** are made and returned by the xMalloc() and xRealloc()
+** are made and returned by the xMalloc() and xRealloc()
** implementations. Once sqlite3_initialize() has been called,
** the amount of memory available to SQLite is fixed and cannot
** be changed.
@@ -21867,12 +25102,12 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
** Concerning Dynamic Storage Allocation". Journal of the Association for
** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
-**
+**
** Let n be the size of the largest allocation divided by the minimum
** allocation size (after rounding all sizes up to a power of 2.) Let M
** be the maximum amount of memory ever outstanding at one time. Let
** N be the total amount of memory available for allocation. Robson
-** proved that this memory allocator will never breakdown due to
+** proved that this memory allocator will never breakdown due to
** fragmentation as long as the following constraint holds:
**
** N >= M*(1 + log2(n)/2) - n + 1
@@ -21883,7 +25118,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
/* #include "sqliteInt.h" */
/*
-** This version of the memory allocator is used only when
+** This version of the memory allocator is used only when
** SQLITE_ENABLE_MEMSYS5 is defined.
*/
#ifdef SQLITE_ENABLE_MEMSYS5
@@ -21928,7 +25163,7 @@ static SQLITE_WSD struct Mem5Global {
int szAtom; /* Smallest possible allocation in bytes */
int nBlock; /* Number of szAtom sized blocks in zPool */
u8 *zPool; /* Memory available to be allocated */
-
+
/*
** Mutex to control access to the memory allocation subsystem.
*/
@@ -21947,7 +25182,7 @@ static SQLITE_WSD struct Mem5Global {
u32 maxCount; /* Maximum instantaneous currentCount */
u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
#endif
-
+
/*
** Lists of free blocks. aiFreelist[0] is a list of free blocks of
** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
@@ -22123,7 +25358,7 @@ static void memsys5FreeUnsafe(void *pOld){
u32 size, iLogsize;
int iBlock;
- /* Set iBlock to the index of the block pointed to by pOld in
+ /* Set iBlock to the index of the block pointed to by pOld in
** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
*/
iBlock = (int)(((u8 *)pOld-mem5.zPool)/mem5.szAtom);
@@ -22192,7 +25427,7 @@ static void *memsys5Malloc(int nBytes){
p = memsys5MallocUnsafe(nBytes);
memsys5Leave();
}
- return (void*)p;
+ return (void*)p;
}
/*
@@ -22205,14 +25440,14 @@ static void memsys5Free(void *pPrior){
assert( pPrior!=0 );
memsys5Enter();
memsys5FreeUnsafe(pPrior);
- memsys5Leave();
+ memsys5Leave();
}
/*
** Change the size of an existing memory allocation.
**
** The outer layer memory allocator prevents this routine from
-** being called with pPrior==0.
+** being called with pPrior==0.
**
** nBytes is always a value obtained from a prior call to
** memsys5Round(). Hence nBytes is always a non-negative power
@@ -22345,7 +25580,7 @@ static void memsys5Shutdown(void *NotUsed){
#ifdef SQLITE_TEST
/*
-** Open the file indicated and write a log of all unfreed memory
+** Open the file indicated and write a log of all unfreed memory
** allocations into that log.
*/
SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
@@ -22387,7 +25622,7 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
#endif
/*
-** This routine is the only routine in this file with external
+** This routine is the only routine in this file with external
** linkage. It returns a pointer to a static sqlite3_mem_methods
** struct populated with the memsys5 methods.
*/
@@ -22437,14 +25672,201 @@ static SQLITE_WSD int mutexIsInit = 0;
#ifndef SQLITE_MUTEX_OMIT
+
+#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
+/*
+** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
+** the implementation of a wrapper around the system default mutex
+** implementation (sqlite3DefaultMutex()).
+**
+** Most calls are passed directly through to the underlying default
+** mutex implementation. Except, if a mutex is configured by calling
+** sqlite3MutexWarnOnContention() on it, then if contention is ever
+** encountered within xMutexEnter() a warning is emitted via sqlite3_log().
+**
+** This type of mutex is used as the database handle mutex when testing
+** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
+*/
+
+/*
+** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
+** is defined. Variable CheckMutex.mutex is a pointer to the real mutex
+** allocated by the system mutex implementation. Variable iType is usually set
+** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST
+** or one of the static mutex identifiers. Or, if this is a recursive mutex
+** that has been configured using sqlite3MutexWarnOnContention(), it is
+** set to SQLITE_MUTEX_WARNONCONTENTION.
+*/
+typedef struct CheckMutex CheckMutex;
+struct CheckMutex {
+ int iType;
+ sqlite3_mutex *mutex;
+};
+
+#define SQLITE_MUTEX_WARNONCONTENTION (-1)
+
+/*
+** Pointer to real mutex methods object used by the CheckMutex
+** implementation. Set by checkMutexInit().
+*/
+static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
+
+#ifdef SQLITE_DEBUG
+static int checkMutexHeld(sqlite3_mutex *p){
+ return pGlobalMutexMethods->xMutexHeld(((CheckMutex*)p)->mutex);
+}
+static int checkMutexNotheld(sqlite3_mutex *p){
+ return pGlobalMutexMethods->xMutexNotheld(((CheckMutex*)p)->mutex);
+}
+#endif
+
+/*
+** Initialize and deinitialize the mutex subsystem.
+*/
+static int checkMutexInit(void){
+ pGlobalMutexMethods = sqlite3DefaultMutex();
+ return SQLITE_OK;
+}
+static int checkMutexEnd(void){
+ pGlobalMutexMethods = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Allocate a mutex.
+*/
+static sqlite3_mutex *checkMutexAlloc(int iType){
+ static CheckMutex staticMutexes[] = {
+ {2, 0}, {3, 0}, {4, 0}, {5, 0},
+ {6, 0}, {7, 0}, {8, 0}, {9, 0},
+ {10, 0}, {11, 0}, {12, 0}, {13, 0}
+ };
+ CheckMutex *p = 0;
+
+ assert( SQLITE_MUTEX_RECURSIVE==1 && SQLITE_MUTEX_FAST==0 );
+ if( iType<2 ){
+ p = sqlite3MallocZero(sizeof(CheckMutex));
+ if( p==0 ) return 0;
+ p->iType = iType;
+ }else{
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( iType-2>=ArraySize(staticMutexes) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ p = &staticMutexes[iType-2];
+ }
+
+ if( p->mutex==0 ){
+ p->mutex = pGlobalMutexMethods->xMutexAlloc(iType);
+ if( p->mutex==0 ){
+ if( iType<2 ){
+ sqlite3_free(p);
+ }
+ p = 0;
+ }
+ }
+
+ return (sqlite3_mutex*)p;
+}
+
+/*
+** Free a mutex.
+*/
+static void checkMutexFree(sqlite3_mutex *p){
+ assert( SQLITE_MUTEX_RECURSIVE<2 );
+ assert( SQLITE_MUTEX_FAST<2 );
+ assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
+
+#if SQLITE_ENABLE_API_ARMOR
+ if( ((CheckMutex*)p)->iType<2 )
+#endif
+ {
+ CheckMutex *pCheck = (CheckMutex*)p;
+ pGlobalMutexMethods->xMutexFree(pCheck->mutex);
+ sqlite3_free(pCheck);
+ }
+#ifdef SQLITE_ENABLE_API_ARMOR
+ else{
+ (void)SQLITE_MISUSE_BKPT;
+ }
+#endif
+}
+
+/*
+** Enter the mutex.
+*/
+static void checkMutexEnter(sqlite3_mutex *p){
+ CheckMutex *pCheck = (CheckMutex*)p;
+ if( pCheck->iType==SQLITE_MUTEX_WARNONCONTENTION ){
+ if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
+ return;
+ }
+ sqlite3_log(SQLITE_MISUSE,
+ "illegal multi-threaded access to database connection"
+ );
+ }
+ pGlobalMutexMethods->xMutexEnter(pCheck->mutex);
+}
+
+/*
+** Enter the mutex (do not block).
+*/
+static int checkMutexTry(sqlite3_mutex *p){
+ CheckMutex *pCheck = (CheckMutex*)p;
+ return pGlobalMutexMethods->xMutexTry(pCheck->mutex);
+}
+
+/*
+** Leave the mutex.
+*/
+static void checkMutexLeave(sqlite3_mutex *p){
+ CheckMutex *pCheck = (CheckMutex*)p;
+ pGlobalMutexMethods->xMutexLeave(pCheck->mutex);
+}
+
+sqlite3_mutex_methods const *multiThreadedCheckMutex(void){
+ static const sqlite3_mutex_methods sMutex = {
+ checkMutexInit,
+ checkMutexEnd,
+ checkMutexAlloc,
+ checkMutexFree,
+ checkMutexEnter,
+ checkMutexTry,
+ checkMutexLeave,
+#ifdef SQLITE_DEBUG
+ checkMutexHeld,
+ checkMutexNotheld
+#else
+ 0,
+ 0
+#endif
+ };
+ return &sMutex;
+}
+
+/*
+** Mark the SQLITE_MUTEX_RECURSIVE mutex passed as the only argument as
+** one on which there should be no contention.
+*/
+SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
+ if( sqlite3GlobalConfig.mutex.xMutexAlloc==checkMutexAlloc ){
+ CheckMutex *pCheck = (CheckMutex*)p;
+ assert( pCheck->iType==SQLITE_MUTEX_RECURSIVE );
+ pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION;
+ }
+}
+#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */
+
/*
** Initialize the mutex system.
*/
-SQLITE_PRIVATE int sqlite3MutexInit(void){
+SQLITE_PRIVATE int sqlite3MutexInit(void){
int rc = SQLITE_OK;
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
/* If the xMutexAlloc method has not been set, then the user did not
- ** install a mutex implementation via sqlite3_config() prior to
+ ** install a mutex implementation via sqlite3_config() prior to
** sqlite3_initialize() being called. This block copies pointers to
** the default implementation into the sqlite3GlobalConfig structure.
*/
@@ -22452,7 +25874,11 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
if( sqlite3GlobalConfig.bCoreMutex ){
+#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
+ pFrom = multiThreadedCheckMutex();
+#else
pFrom = sqlite3DefaultMutex();
+#endif
}else{
pFrom = sqlite3NoopMutex();
}
@@ -22474,6 +25900,7 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
GLOBAL(int, mutexIsInit) = 1;
#endif
+ sqlite3MemoryBarrier();
return rc;
}
@@ -22551,7 +25978,7 @@ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
/*
** The sqlite3_mutex_leave() routine exits a mutex that was previously
-** entered by the same thread. The behavior is undefined if the mutex
+** entered by the same thread. The behavior is undefined if the mutex
** is not currently entered. If a NULL pointer is passed as an argument
** this function is a no-op.
*/
@@ -22620,9 +26047,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
*/
static int noopMutexInit(void){ return SQLITE_OK; }
static int noopMutexEnd(void){ return SQLITE_OK; }
-static sqlite3_mutex *noopMutexAlloc(int id){
+static sqlite3_mutex *noopMutexAlloc(int id){
UNUSED_PARAMETER(id);
- return (sqlite3_mutex*)8;
+ return (sqlite3_mutex*)8;
}
static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
@@ -22687,7 +26114,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
/*
** The sqlite3_mutex_alloc() routine allocates a new
** mutex and returns a pointer to it. If it returns NULL
-** that means that a mutex could not be allocated.
+** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1];
@@ -22851,11 +26278,12 @@ struct sqlite3_mutex {
#endif
};
#if SQLITE_MUTEX_NREF
-#define SQLITE3_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER,0,0,(pthread_t)0,0}
+# define SQLITE3_MUTEX_INITIALIZER(id) \
+ {PTHREAD_MUTEX_INITIALIZER,id,0,(pthread_t)0,0}
#elif defined(SQLITE_ENABLE_API_ARMOR)
-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0 }
+# define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER, id }
#else
-#define SQLITE3_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
+#define SQLITE3_MUTEX_INITIALIZER(id) { PTHREAD_MUTEX_INITIALIZER }
#endif
/*
@@ -22864,7 +26292,7 @@ struct sqlite3_mutex {
** there might be race conditions that can cause these routines to
** deliver incorrect results. In particular, if pthread_equal() is
** not an atomic operation, then these routines might delivery
-** incorrect results. On most platforms, pthread_equal() is a
+** incorrect results. On most platforms, pthread_equal() is a
** comparison of two integers and is therefore atomic. But we are
** told that HPUX is not such a platform. If so, then these routines
** will not always work correctly on HPUX.
@@ -22912,7 +26340,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
@@ -22946,24 +26374,24 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
**
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. But for the static
+** returns a different mutex on every call. But for the static
** mutex types, the same mutex is returned on every call that has
** the same type number.
*/
static sqlite3_mutex *pthreadMutexAlloc(int iType){
static sqlite3_mutex staticMutexes[] = {
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER
+ SQLITE3_MUTEX_INITIALIZER(2),
+ SQLITE3_MUTEX_INITIALIZER(3),
+ SQLITE3_MUTEX_INITIALIZER(4),
+ SQLITE3_MUTEX_INITIALIZER(5),
+ SQLITE3_MUTEX_INITIALIZER(6),
+ SQLITE3_MUTEX_INITIALIZER(7),
+ SQLITE3_MUTEX_INITIALIZER(8),
+ SQLITE3_MUTEX_INITIALIZER(9),
+ SQLITE3_MUTEX_INITIALIZER(10),
+ SQLITE3_MUTEX_INITIALIZER(11),
+ SQLITE3_MUTEX_INITIALIZER(12),
+ SQLITE3_MUTEX_INITIALIZER(13)
};
sqlite3_mutex *p;
switch( iType ){
@@ -22982,6 +26410,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
pthread_mutex_init(&p->mutex, &recursiveAttr);
pthread_mutexattr_destroy(&recursiveAttr);
#endif
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
+ p->id = SQLITE_MUTEX_RECURSIVE;
+#endif
}
break;
}
@@ -22989,6 +26420,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
p = sqlite3MallocZero( sizeof(*p) );
if( p ){
pthread_mutex_init(&p->mutex, 0);
+#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
+ p->id = SQLITE_MUTEX_FAST;
+#endif
}
break;
}
@@ -23004,7 +26438,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
}
}
#if SQLITE_MUTEX_NREF || defined(SQLITE_ENABLE_API_ARMOR)
- if( p ) p->id = iType;
+ assert( p==0 || p->id==iType );
#endif
return p;
}
@@ -23051,7 +26485,7 @@ static void pthreadMutexEnter(sqlite3_mutex *p){
** is atomic - that it cannot be deceived into thinking self
** and p->owner are equal if p->owner changes between two values
** that are not equal to self while the comparison is taking place.
- ** This implementation also assumes a coherent cache - that
+ ** This implementation also assumes a coherent cache - that
** separate processes cannot read different values from the same
** address at the same time. If either of these two conditions
** are not met, then the mutexes will fail and problems will result.
@@ -23094,7 +26528,7 @@ static int pthreadMutexTry(sqlite3_mutex *p){
** is atomic - that it cannot be deceived into thinking self
** and p->owner are equal if p->owner changes between two values
** that are not equal to self while the comparison is taking place.
- ** This implementation also assumes a coherent cache - that
+ ** This implementation also assumes a coherent cache - that
** separate processes cannot read different values from the same
** address at the same time. If either of these two conditions
** are not met, then the mutexes will fail and problems will result.
@@ -23266,7 +26700,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
******************************************************************************
**
** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 class CPUs.
+** counters for x86 and x86_64 class CPUs.
*/
#ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H
@@ -23277,8 +26711,9 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
** processor and returns that value. This can be used for high-res
** profiling.
*/
-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
@@ -23299,15 +26734,15 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
#endif
-#elif (defined(__GNUC__) && defined(__x86_64__))
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
-#elif (defined(__GNUC__) && defined(__ppc__))
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
@@ -23324,14 +26759,13 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
#else
- #error Need implementation of sqlite3Hwtime() for your platform.
-
/*
- ** To compile without implementing sqlite3Hwtime() for your platform,
- ** you can remove the above #error and use the following
- ** stub function. You will lose timing support for many
- ** of the debugging and testing utilities, but it should at
- ** least compile and run.
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlite3Hwtime() routine.
+ **
+ ** sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
*/
SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
@@ -23521,7 +26955,7 @@ struct sqlite3_mutex {
#ifdef SQLITE_DEBUG
volatile int nRef; /* Number of enterances */
volatile DWORD owner; /* Thread holding this mutex */
- volatile int trace; /* True to trace changes */
+ volatile LONG trace; /* True to trace changes */
#endif
};
@@ -23533,10 +26967,10 @@ struct sqlite3_mutex {
#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
#ifdef SQLITE_DEBUG
-#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \
+#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id, \
0L, (DWORD)0, 0 }
#else
-#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
+#define SQLITE3_MUTEX_INITIALIZER(id) { SQLITE_W32_MUTEX_INITIALIZER, id }
#endif
#ifdef SQLITE_DEBUG
@@ -23568,8 +27002,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
__sync_synchronize();
-#elif !defined(SQLITE_DISABLE_INTRINSIC) && \
- defined(_MSC_VER) && _MSC_VER>=1300
+#elif MSVC_VERSION>=1300
_ReadWriteBarrier();
#elif defined(MemoryBarrier)
MemoryBarrier();
@@ -23580,18 +27013,18 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[] = {
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER,
- SQLITE3_MUTEX_INITIALIZER
+ SQLITE3_MUTEX_INITIALIZER(2),
+ SQLITE3_MUTEX_INITIALIZER(3),
+ SQLITE3_MUTEX_INITIALIZER(4),
+ SQLITE3_MUTEX_INITIALIZER(5),
+ SQLITE3_MUTEX_INITIALIZER(6),
+ SQLITE3_MUTEX_INITIALIZER(7),
+ SQLITE3_MUTEX_INITIALIZER(8),
+ SQLITE3_MUTEX_INITIALIZER(9),
+ SQLITE3_MUTEX_INITIALIZER(10),
+ SQLITE3_MUTEX_INITIALIZER(11),
+ SQLITE3_MUTEX_INITIALIZER(12),
+ SQLITE3_MUTEX_INITIALIZER(13)
};
static int winMutex_isInit = 0;
@@ -23653,7 +27086,7 @@ static int winMutexEnd(void){
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
@@ -23721,15 +27154,15 @@ static sqlite3_mutex *winMutexAlloc(int iType){
}
#endif
p = &winMutex_staticMutexes[iType-2];
- p->id = iType;
#ifdef SQLITE_DEBUG
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
- p->trace = 1;
+ InterlockedCompareExchange(&p->trace, 1, 0);
#endif
#endif
break;
}
}
+ assert( p==0 || p->id==iType );
return p;
}
@@ -23780,8 +27213,8 @@ static void winMutexEnter(sqlite3_mutex *p){
p->owner = tid;
p->nRef++;
if( p->trace ){
- OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
- tid, p, p->trace, p->nRef));
+ OSTRACE(("ENTER-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
+ tid, p->id, p, p->trace, p->nRef));
}
#endif
}
@@ -23823,8 +27256,8 @@ static int winMutexTry(sqlite3_mutex *p){
#endif
#ifdef SQLITE_DEBUG
if( p->trace ){
- OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
- tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
+ OSTRACE(("TRY-MUTEX tid=%lu, mutex(%d)=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
+ tid, p->id, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
}
#endif
return rc;
@@ -23852,8 +27285,8 @@ static void winMutexLeave(sqlite3_mutex *p){
LeaveCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG
if( p->trace ){
- OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
- tid, p, p->trace, p->nRef));
+ OSTRACE(("LEAVE-MUTEX tid=%lu, mutex(%d)=%p (%d), nRef=%d\n",
+ tid, p->id, p, p->trace, p->nRef));
}
#endif
}
@@ -23917,12 +27350,11 @@ SQLITE_API int sqlite3_release_memory(int n){
}
/*
-** An instance of the following object records the location of
-** each unused scratch buffer.
+** Default value of the hard heap limit. 0 means "no limit".
*/
-typedef struct ScratchFreeslot {
- struct ScratchFreeslot *pNext; /* Next unused scratch buffer */
-} ScratchFreeslot;
+#ifndef SQLITE_MAX_MEMORY
+# define SQLITE_MAX_MEMORY 0
+#endif
/*
** State information local to the memory allocation subsystem.
@@ -23930,23 +27362,14 @@ typedef struct ScratchFreeslot {
static SQLITE_WSD struct Mem0Global {
sqlite3_mutex *mutex; /* Mutex to serialize access */
sqlite3_int64 alarmThreshold; /* The soft heap limit */
-
- /*
- ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
- ** (so that a range test can be used to determine if an allocation
- ** being freed came from pScratch) and a pointer to the list of
- ** unused scratch allocations.
- */
- void *pScratchEnd;
- ScratchFreeslot *pScratchFree;
- u32 nScratchFree;
+ sqlite3_int64 hardLimit; /* The hard upper bound on memory */
/*
** True if heap is nearly "full" where "full" is defined by the
** sqlite3_soft_heap_limit() setting.
*/
int nearlyFull;
-} mem0 = { 0, 0, 0, 0, 0, 0 };
+} mem0 = { 0, SQLITE_MAX_MEMORY, SQLITE_MAX_MEMORY, 0 };
#define mem0 GLOBAL(struct Mem0Global, mem0)
@@ -23976,8 +27399,15 @@ SQLITE_API int sqlite3_memory_alarm(
#endif
/*
-** Set the soft heap-size limit for the library. Passing a zero or
-** negative value indicates no limit.
+** Set the soft heap-size limit for the library. An argument of
+** zero disables the limit. A negative argument is a no-op used to
+** obtain the return value.
+**
+** The return value is the value of the heap limit just before this
+** interface was called.
+**
+** If the hard heap limit is enabled, then the soft heap limit cannot
+** be disabled nor raised above the hard heap limit.
*/
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
@@ -23993,9 +27423,12 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_mutex_leave(mem0.mutex);
return priorLimit;
}
+ if( mem0.hardLimit>0 && (n>mem0.hardLimit || n==0) ){
+ n = mem0.hardLimit;
+ }
mem0.alarmThreshold = n;
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
- mem0.nearlyFull = (n>0 && n<=nUsed);
+ AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed);
sqlite3_mutex_leave(mem0.mutex);
excess = sqlite3_memory_used() - n;
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
@@ -24007,6 +27440,37 @@ SQLITE_API void sqlite3_soft_heap_limit(int n){
}
/*
+** Set the hard heap-size limit for the library. An argument of zero
+** disables the hard heap limit. A negative argument is a no-op used
+** to obtain the return value without affecting the hard heap limit.
+**
+** The return value is the value of the hard heap limit just prior to
+** calling this interface.
+**
+** Setting the hard heap limit will also activate the soft heap limit
+** and constrain the soft heap limit to be no more than the hard heap
+** limit.
+*/
+SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 n){
+ sqlite3_int64 priorLimit;
+#ifndef SQLITE_OMIT_AUTOINIT
+ int rc = sqlite3_initialize();
+ if( rc ) return -1;
+#endif
+ sqlite3_mutex_enter(mem0.mutex);
+ priorLimit = mem0.hardLimit;
+ if( n>=0 ){
+ mem0.hardLimit = n;
+ if( n<mem0.alarmThreshold || mem0.alarmThreshold==0 ){
+ mem0.alarmThreshold = n;
+ }
+ }
+ sqlite3_mutex_leave(mem0.mutex);
+ return priorLimit;
+}
+
+
+/*
** Initialize the memory allocation subsystem.
*/
SQLITE_PRIVATE int sqlite3MallocInit(void){
@@ -24016,28 +27480,6 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
}
memset(&mem0, 0, sizeof(mem0));
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
- if( sqlite3GlobalConfig.pScratch && sqlite3GlobalConfig.szScratch>=100
- && sqlite3GlobalConfig.nScratch>0 ){
- int i, n, sz;
- ScratchFreeslot *pSlot;
- sz = ROUNDDOWN8(sqlite3GlobalConfig.szScratch);
- sqlite3GlobalConfig.szScratch = sz;
- pSlot = (ScratchFreeslot*)sqlite3GlobalConfig.pScratch;
- n = sqlite3GlobalConfig.nScratch;
- mem0.pScratchFree = pSlot;
- mem0.nScratchFree = n;
- for(i=0; i<n-1; i++){
- pSlot->pNext = (ScratchFreeslot*)(sz+(char*)pSlot);
- pSlot = pSlot->pNext;
- }
- pSlot->pNext = 0;
- mem0.pScratchEnd = (void*)&pSlot[1];
- }else{
- mem0.pScratchEnd = 0;
- sqlite3GlobalConfig.pScratch = 0;
- sqlite3GlobalConfig.szScratch = 0;
- sqlite3GlobalConfig.nScratch = 0;
- }
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|| sqlite3GlobalConfig.nPage<=0 ){
sqlite3GlobalConfig.pPage = 0;
@@ -24054,7 +27496,7 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
** sqlite3_soft_heap_limit().
*/
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){
- return mem0.nearlyFull;
+ return AtomicLoad(&mem0.nearlyFull);
}
/*
@@ -24088,7 +27530,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
}
/*
-** Trigger the alarm
+** Trigger the alarm
*/
static void sqlite3MallocAlarm(int nByte){
if( mem0.alarmThreshold<=0 ) return;
@@ -24101,19 +27543,34 @@ static void sqlite3MallocAlarm(int nByte){
** Do a memory allocation with statistics and alarms. Assume the
** lock is already held.
*/
-static int mallocWithAlarm(int n, void **pp){
- int nFull;
+static void mallocWithAlarm(int n, void **pp){
void *p;
+ int nFull;
assert( sqlite3_mutex_held(mem0.mutex) );
+ assert( n>0 );
+
+ /* In Firefox (circa 2017-02-08), xRoundup() is remapped to an internal
+ ** implementation of malloc_good_size(), which must be called in debug
+ ** mode and specifically when the DMD "Dark Matter Detector" is enabled
+ ** or else a crash results. Hence, do not attempt to optimize out the
+ ** following xRoundup() call. */
nFull = sqlite3GlobalConfig.m.xRoundup(n);
+
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n);
if( mem0.alarmThreshold>0 ){
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
if( nUsed >= mem0.alarmThreshold - nFull ){
- mem0.nearlyFull = 1;
+ AtomicStore(&mem0.nearlyFull, 1);
sqlite3MallocAlarm(nFull);
+ if( mem0.hardLimit ){
+ nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+ if( nUsed >= mem0.hardLimit - nFull ){
+ *pp = 0;
+ return;
+ }
+ }
}else{
- mem0.nearlyFull = 0;
+ AtomicStore(&mem0.nearlyFull, 0);
}
}
p = sqlite3GlobalConfig.m.xMalloc(nFull);
@@ -24129,7 +27586,6 @@ static int mallocWithAlarm(int n, void **pp){
sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1);
}
*pp = p;
- return nFull;
}
/*
@@ -24175,105 +27631,6 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
}
/*
-** Each thread may only have a single outstanding allocation from
-** xScratchMalloc(). We verify this constraint in the single-threaded
-** case by setting scratchAllocOut to 1 when an allocation
-** is outstanding clearing it when the allocation is freed.
-*/
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
-static int scratchAllocOut = 0;
-#endif
-
-
-/*
-** Allocate memory that is to be used and released right away.
-** This routine is similar to alloca() in that it is not intended
-** for situations where the memory might be held long-term. This
-** routine is intended to get memory to old large transient data
-** structures that would not normally fit on the stack of an
-** embedded processor.
-*/
-SQLITE_PRIVATE void *sqlite3ScratchMalloc(int n){
- void *p;
- assert( n>0 );
-
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusHighwater(SQLITE_STATUS_SCRATCH_SIZE, n);
- if( mem0.nScratchFree && sqlite3GlobalConfig.szScratch>=n ){
- p = mem0.pScratchFree;
- mem0.pScratchFree = mem0.pScratchFree->pNext;
- mem0.nScratchFree--;
- sqlite3StatusUp(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- sqlite3_mutex_leave(mem0.mutex);
- p = sqlite3Malloc(n);
- if( sqlite3GlobalConfig.bMemstat && p ){
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusUp(SQLITE_STATUS_SCRATCH_OVERFLOW, sqlite3MallocSize(p));
- sqlite3_mutex_leave(mem0.mutex);
- }
- sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
- }
- assert( sqlite3_mutex_notheld(mem0.mutex) );
-
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* EVIDENCE-OF: R-12970-05880 SQLite will not use more than one scratch
- ** buffers per thread.
- **
- ** This can only be checked in single-threaded mode.
- */
- assert( scratchAllocOut==0 );
- if( p ) scratchAllocOut++;
-#endif
-
- return p;
-}
-SQLITE_PRIVATE void sqlite3ScratchFree(void *p){
- if( p ){
-
-#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
- /* Verify that no more than two scratch allocation per thread
- ** is outstanding at one time. (This is only checked in the
- ** single-threaded case since checking in the multi-threaded case
- ** would be much more complicated.) */
- assert( scratchAllocOut>=1 && scratchAllocOut<=2 );
- scratchAllocOut--;
-#endif
-
- if( SQLITE_WITHIN(p, sqlite3GlobalConfig.pScratch, mem0.pScratchEnd) ){
- /* Release memory from the SQLITE_CONFIG_SCRATCH allocation */
- ScratchFreeslot *pSlot;
- pSlot = (ScratchFreeslot*)p;
- sqlite3_mutex_enter(mem0.mutex);
- pSlot->pNext = mem0.pScratchFree;
- mem0.pScratchFree = pSlot;
- mem0.nScratchFree++;
- assert( mem0.nScratchFree <= (u32)sqlite3GlobalConfig.nScratch );
- sqlite3StatusDown(SQLITE_STATUS_SCRATCH_USED, 1);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- /* Release memory back to the heap */
- assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_SCRATCH) );
- sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- if( sqlite3GlobalConfig.bMemstat ){
- int iSize = sqlite3MallocSize(p);
- sqlite3_mutex_enter(mem0.mutex);
- sqlite3StatusDown(SQLITE_STATUS_SCRATCH_OVERFLOW, iSize);
- sqlite3StatusDown(SQLITE_STATUS_MEMORY_USED, iSize);
- sqlite3StatusDown(SQLITE_STATUS_MALLOC_COUNT, 1);
- sqlite3GlobalConfig.m.xFree(p);
- sqlite3_mutex_leave(mem0.mutex);
- }else{
- sqlite3GlobalConfig.m.xFree(p);
- }
- }
- }
-}
-
-/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
@@ -24292,10 +27649,17 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
+static int lookasideMallocSize(sqlite3 *db, void *p){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
+#else
+ return db->lookaside.szTrue;
+#endif
+}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( p!=0 );
+#ifdef SQLITE_DEBUG
if( db==0 || !isLookaside(db,p) ){
-#if SQLITE_DEBUG
if( db==0 ){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
@@ -24303,12 +27667,23 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
+ }
#endif
- return sqlite3GlobalConfig.m.xSize(p);
- }else{
- assert( sqlite3_mutex_held(db->mutex) );
- return db->lookaside.sz;
+ if( db ){
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ assert( sqlite3_mutex_held(db->mutex) );
+ return LOOKASIDE_SMALL;
+ }
+#endif
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ assert( sqlite3_mutex_held(db->mutex) );
+ return db->lookaside.szTrue;
+ }
+ }
}
+ return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
@@ -24344,26 +27719,38 @@ static SQLITE_NOINLINE void measureAllocationSize(sqlite3 *db, void *p){
/*
** Free memory that might be associated with a particular database
-** connection.
+** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op.
+** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL.
*/
-SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
+SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
- if( p==0 ) return;
+ assert( p!=0 );
if( db ){
if( db->pnBytesFreed ){
measureAllocationSize(db, p);
return;
}
- if( isLookaside(db, p) ){
- LookasideSlot *pBuf = (LookasideSlot*)p;
-#if SQLITE_DEBUG
- /* Trash all content in the buffer being freed */
- memset(p, 0xaa, db->lookaside.sz);
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
- pBuf->pNext = db->lookaside.pFree;
- db->lookaside.pFree = pBuf;
- db->lookaside.nOut--;
- return;
+ pBuf->pNext = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = pBuf;
+ return;
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pFree;
+ db->lookaside.pFree = pBuf;
+ return;
+ }
}
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
@@ -24372,6 +27759,10 @@ SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
+SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
+ assert( db==0 || sqlite3_mutex_held(db->mutex) );
+ if( p ) sqlite3DbFreeNN(db, p);
+}
/*
** Change the size of an existing memory allocation
@@ -24403,15 +27794,17 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
nDiff = nNew - nOld;
- if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
+ if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
mem0.alarmThreshold-nDiff ){
sqlite3MallocAlarm(nDiff);
}
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
if( pNew==0 && mem0.alarmThreshold>0 ){
sqlite3MallocAlarm((int)nBytes);
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
}
+#endif
if( pNew ){
nNew = sqlite3MallocSize(pNew);
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
@@ -24445,7 +27838,7 @@ SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
/*
** Allocate and zero memory.
-*/
+*/
SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
void *p = sqlite3Malloc(n);
if( p ){
@@ -24475,13 +27868,13 @@ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
assert( db!=0 );
p = sqlite3Malloc(n);
if( !p ) sqlite3OomFault(db);
- sqlite3MemdebugSetType(p,
+ sqlite3MemdebugSetType(p,
(db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
return p;
}
/*
-** Allocate memory, either lookaside (if possible) or heap.
+** Allocate memory, either lookaside (if possible) or heap.
** If the allocation fails, set the mallocFailed flag in
** the connection pointer.
**
@@ -24515,23 +27908,37 @@ SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
assert( db->pnBytesFreed==0 );
- if( db->lookaside.bDisable==0 ){
- assert( db->mallocFailed==0 );
- if( n>db->lookaside.sz ){
+ if( n>db->lookaside.sz ){
+ if( !db->lookaside.bDisable ){
db->lookaside.anStat[1]++;
- }else if( (pBuf = db->lookaside.pFree)==0 ){
- db->lookaside.anStat[2]++;
- }else{
- db->lookaside.pFree = pBuf->pNext;
- db->lookaside.nOut++;
+ }else if( db->mallocFailed ){
+ return 0;
+ }
+ return dbMallocRawFinish(db, n);
+ }
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( n<=LOOKASIDE_SMALL ){
+ if( (pBuf = db->lookaside.pSmallFree)!=0 ){
+ db->lookaside.pSmallFree = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else if( (pBuf = db->lookaside.pSmallInit)!=0 ){
+ db->lookaside.pSmallInit = pBuf->pNext;
db->lookaside.anStat[0]++;
- if( db->lookaside.nOut>db->lookaside.mxOut ){
- db->lookaside.mxOut = db->lookaside.nOut;
- }
return (void*)pBuf;
}
- }else if( db->mallocFailed ){
- return 0;
+ }
+#endif
+ if( (pBuf = db->lookaside.pFree)!=0 ){
+ db->lookaside.pFree = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else if( (pBuf = db->lookaside.pInit)!=0 ){
+ db->lookaside.pInit = pBuf->pNext;
+ db->lookaside.anStat[0]++;
+ return (void*)pBuf;
+ }else{
+ db->lookaside.anStat[2]++;
}
#else
assert( db!=0 );
@@ -24555,7 +27962,16 @@ SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *db, void *p, u64 n){
assert( db!=0 );
if( p==0 ) return sqlite3DbMallocRawNN(db, n);
assert( sqlite3_mutex_held(db->mutex) );
- if( isLookaside(db,p) && n<=db->lookaside.sz ) return p;
+ if( ((uptr)p)<(uptr)db->lookaside.pEnd ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)db->lookaside.pMiddle ){
+ if( n<=LOOKASIDE_SMALL ) return p;
+ }else
+#endif
+ if( ((uptr)p)>=(uptr)db->lookaside.pStart ){
+ if( n<=db->lookaside.szTrue ) return p;
+ }
+ }
return dbReallocFinish(db, p, n);
}
static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
@@ -24566,14 +27982,14 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
if( isLookaside(db, p) ){
pNew = sqlite3DbMallocRawNN(db, n);
if( pNew ){
- memcpy(pNew, p, db->lookaside.sz);
+ memcpy(pNew, p, lookasideMallocSize(db, p));
sqlite3DbFree(db, p);
}
}else{
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
- pNew = sqlite3_realloc64(p, n);
+ pNew = sqlite3Realloc(p, n);
if( !pNew ){
sqlite3OomFault(db);
}
@@ -24598,9 +28014,9 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){
}
/*
-** Make a copy of a string in memory obtained from sqliteMalloc(). These
+** Make a copy of a string in memory obtained from sqliteMalloc(). These
** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
-** is because when memory debugging is turned on, these two functions are
+** is because when memory debugging is turned on, these two functions are
** called via macros that record the current file and line number in the
** ThreadData structure.
*/
@@ -24610,9 +28026,8 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
if( z==0 ){
return 0;
}
- n = sqlite3Strlen30(z) + 1;
- assert( (n&0x7fffffff)==n );
- zNew = sqlite3DbMallocRaw(db, (int)n);
+ n = strlen(z) + 1;
+ zNew = sqlite3DbMallocRaw(db, n);
if( zNew ){
memcpy(zNew, z, n);
}
@@ -24621,11 +28036,9 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
char *zNew;
assert( db!=0 );
- if( z==0 ){
- return 0;
- }
+ assert( z!=0 || n==0 );
assert( (n&0x7fffffff)==n );
- zNew = sqlite3DbMallocRawNN(db, n+1);
+ zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0;
if( zNew ){
memcpy(zNew, z, (size_t)n);
zNew[n] = 0;
@@ -24634,6 +28047,19 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
}
/*
+** The text between zStart and zEnd represents a phrase within a larger
+** SQL statement. Make a copy of this phrase in space obtained form
+** sqlite3DbMalloc(). Omit leading and trailing whitespace.
+*/
+SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
+ int n;
+ while( sqlite3Isspace(zStart[0]) ) zStart++;
+ n = (int)(zEnd - zStart);
+ while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
+ return sqlite3DbStrNDup(db, zStart, n);
+}
+
+/*
** Free any prior content in *pz and replace it with a copy of zNew.
*/
SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
@@ -24651,9 +28077,12 @@ SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
db->mallocFailed = 1;
if( db->nVdbeExec>0 ){
- db->u1.isInterrupted = 1;
+ AtomicStore(&db->u1.isInterrupted, 1);
+ }
+ DisableLookaside;
+ if( db->pParse ){
+ db->pParse->rc = SQLITE_NOMEM_BKPT;
}
- db->lookaside.bDisable++;
}
}
@@ -24667,9 +28096,9 @@ SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
if( db->mallocFailed && db->nVdbeExec==0 ){
db->mallocFailed = 0;
- db->u1.isInterrupted = 0;
+ AtomicStore(&db->u1.isInterrupted, 0);
assert( db->lookaside.bDisable>0 );
- db->lookaside.bDisable--;
+ EnableLookaside;
}
}
@@ -24683,20 +28112,20 @@ static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
}
/*
-** This function must be called before exiting any API function (i.e.
+** This function must be called before exiting any API function (i.e.
** returning control to the user) that has called sqlite3_malloc or
** sqlite3_realloc.
**
** The returned value is normally a copy of the second argument to this
** function. However, if a malloc() failure has occurred since the previous
-** invocation SQLITE_NOMEM is returned instead.
+** invocation SQLITE_NOMEM is returned instead.
**
** If an OOM as occurred, then the connection error-code (the value
** returned by sqlite3_errcode()) is set to SQLITE_NOMEM.
*/
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
/* If the db handle must hold the connection handle mutex here.
- ** Otherwise the read (and possible write) of db->mallocFailed
+ ** Otherwise the read (and possible write) of db->mallocFailed
** is unsafe, as is the call to sqlite3Error().
*/
assert( db!=0 );
@@ -24711,7 +28140,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
/************** Begin file printf.c ******************************************/
/*
** The "printf" code that follows dates from the 1980's. It is in
-** the public domain.
+** the public domain.
**
**************************************************************************
**
@@ -24726,7 +28155,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
-#define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */
+#define etRADIX 0 /* non-decimal integer types. %x %o */
#define etFLOAT 1 /* Floating point. %f */
#define etEXP 2 /* Exponentional notation. %e and %E */
#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */
@@ -24744,8 +28173,9 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
#define etPOINTER 13 /* The %p conversion */
#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
+#define etDECIMAL 16 /* %d or %u, but not %x, %o */
-#define etINVALID 16 /* Any unrecognized conversion type */
+#define etINVALID 17 /* Any unrecognized conversion type */
/*
@@ -24769,9 +28199,8 @@ typedef struct et_info { /* Information about each format field */
/*
** Allowed values for et_info.flags
*/
-#define FLAG_SIGNED 1 /* True if the value to convert is signed */
-#define FLAG_INTERN 2 /* True if for internal use only */
-#define FLAG_STRING 4 /* Allow infinity precision */
+#define FLAG_SIGNED 1 /* True if the value to convert is signed */
+#define FLAG_STRING 4 /* Allow infinite precision */
/*
@@ -24781,7 +28210,7 @@ typedef struct et_info { /* Information about each format field */
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
- { 'd', 10, 1, etRADIX, 0, 0 },
+ { 'd', 10, 1, etDECIMAL, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
@@ -24790,7 +28219,7 @@ static const et_info fmtinfo[] = {
{ 'w', 0, 4, etSQLESCAPE3, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, 0, 2 },
- { 'u', 10, 0, etRADIX, 0, 0 },
+ { 'u', 10, 0, etDECIMAL, 0, 0 },
{ 'x', 16, 0, etRADIX, 16, 1 },
{ 'X', 16, 0, etRADIX, 0, 4 },
#ifndef SQLITE_OMIT_FLOATING_POINT
@@ -24799,16 +28228,21 @@ static const et_info fmtinfo[] = {
{ 'E', 0, 1, etEXP, 14, 0 },
{ 'G', 0, 1, etGENERIC, 14, 0 },
#endif
- { 'i', 10, 1, etRADIX, 0, 0 },
+ { 'i', 10, 1, etDECIMAL, 0, 0 },
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
{ 'p', 16, 0, etPOINTER, 0, 1 },
-/* All the rest have the FLAG_INTERN bit set and are thus for internal
-** use only */
- { 'T', 0, 2, etTOKEN, 0, 0 },
- { 'S', 0, 2, etSRCLIST, 0, 0 },
- { 'r', 10, 3, etORDINAL, 0, 0 },
+ /* All the rest are undocumented and are for internal use only */
+ { 'T', 0, 0, etTOKEN, 0, 0 },
+ { 'S', 0, 0, etSRCLIST, 0, 0 },
+ { 'r', 10, 1, etORDINAL, 0, 0 },
+};
+
+/* Floating point constants used for rounding */
+static const double arRound[] = {
+ 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
+ 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10,
};
/*
@@ -24846,9 +28280,10 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
- assert( eError==STRACCUM_NOMEM || eError==STRACCUM_TOOBIG );
+ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
p->accError = eError;
- p->nAlloc = 0;
+ if( p->mxAlloc ) sqlite3_str_reset(p);
+ if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError);
}
/*
@@ -24867,6 +28302,28 @@ static char *getTextArg(PrintfArguments *p){
return (char*)sqlite3_value_text(p->apArg[p->nUsed++]);
}
+/*
+** Allocate memory for a temporary buffer needed for printf rendering.
+**
+** If the requested size of the temp buffer is larger than the size
+** of the output buffer in pAccum, then cause an SQLITE_TOOBIG error.
+** Do the size check before the memory allocation to prevent rogue
+** SQL from requesting large allocations using the precision or width
+** field of the printf() function.
+*/
+static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
+ char *z;
+ if( pAccum->accError ) return 0;
+ if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){
+ setStrAccumError(pAccum, SQLITE_TOOBIG);
+ return 0;
+ }
+ z = sqlite3DbMallocRaw(pAccum->db, n);
+ if( z==0 ){
+ setStrAccumError(pAccum, SQLITE_NOMEM);
+ }
+ return z;
+}
/*
** On machines with a small stack size, you can redefine the
@@ -24878,10 +28335,17 @@ static char *getTextArg(PrintfArguments *p){
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
/*
+** Hard limit on the precision of floating-point conversions.
+*/
+#ifndef SQLITE_PRINTF_PRECISION_LIMIT
+# define SQLITE_FP_PRECISION_LIMIT 100000000
+#endif
+
+/*
** Render a string given by "fmt" into the StrAccum object.
*/
-SQLITE_PRIVATE void sqlite3VXPrintf(
- StrAccum *pAccum, /* Accumulate results here */
+SQLITE_API void sqlite3_str_vappendf(
+ sqlite3_str *pAccum, /* Accumulate results here */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
@@ -24892,17 +28356,15 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
int idx; /* A general purpose loop counter */
int width; /* Width of the current field */
etByte flag_leftjustify; /* True if "-" flag is present */
- etByte flag_plussign; /* True if "+" flag is present */
- etByte flag_blanksign; /* True if " " flag is present */
+ etByte flag_prefix; /* '+' or ' ' or 0 for prefix */
etByte flag_alternateform; /* True if "#" flag is present */
etByte flag_altform2; /* True if "!" flag is present */
etByte flag_zeropad; /* True if field width constant starts with zero */
- etByte flag_long; /* True if "l" flag is present */
- etByte flag_longlong; /* True if the "ll" flag is present */
+ etByte flag_long; /* 1 for the "l" flag, 2 for "ll", 0 by default */
etByte done; /* Loop termination flag */
+ etByte cThousand; /* Thousands separator for %d and %u */
etByte xtype = etINVALID; /* Conversion paradigm */
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
- u8 useIntern; /* Ok to use internal conversions (ex: %T) */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
sqlite_uint64 longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
@@ -24920,14 +28382,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
+ /* pAccum never starts out with an empty buffer that was obtained from
+ ** malloc(). This precondition is required by the mprintf("%z...")
+ ** optimization. */
+ assert( pAccum->nChar>0 || (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 );
+
bufpt = 0;
- if( pAccum->printfFlags ){
- if( (bArgList = (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
- pArgList = va_arg(ap, PrintfArguments*);
- }
- useIntern = pAccum->printfFlags & SQLITE_PRINTF_INTERNAL;
+ if( (pAccum->printfFlags & SQLITE_PRINTF_SQLFUNC)!=0 ){
+ pArgList = va_arg(ap, PrintfArguments*);
+ bArgList = 1;
}else{
- bArgList = useIntern = 0;
+ bArgList = 0;
}
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
@@ -24937,113 +28402,124 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
#else
do{ fmt++; }while( *fmt && *fmt != '%' );
#endif
- sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
+ sqlite3_str_append(pAccum, bufpt, (int)(fmt - bufpt));
if( *fmt==0 ) break;
}
if( (c=(*++fmt))==0 ){
- sqlite3StrAccumAppend(pAccum, "%", 1);
+ sqlite3_str_append(pAccum, "%", 1);
break;
}
/* Find out what flags are present */
- flag_leftjustify = flag_plussign = flag_blanksign =
+ flag_leftjustify = flag_prefix = cThousand =
flag_alternateform = flag_altform2 = flag_zeropad = 0;
done = 0;
+ width = 0;
+ flag_long = 0;
+ precision = -1;
do{
switch( c ){
case '-': flag_leftjustify = 1; break;
- case '+': flag_plussign = 1; break;
- case ' ': flag_blanksign = 1; break;
+ case '+': flag_prefix = '+'; break;
+ case ' ': flag_prefix = ' '; break;
case '#': flag_alternateform = 1; break;
case '!': flag_altform2 = 1; break;
case '0': flag_zeropad = 1; break;
+ case ',': cThousand = ','; break;
default: done = 1; break;
- }
- }while( !done && (c=(*++fmt))!=0 );
- /* Get the field width */
- if( c=='*' ){
- if( bArgList ){
- width = (int)getIntArg(pArgList);
- }else{
- width = va_arg(ap,int);
- }
- if( width<0 ){
- flag_leftjustify = 1;
- width = width >= -2147483647 ? -width : 0;
- }
- c = *++fmt;
- }else{
- unsigned wx = 0;
- while( c>='0' && c<='9' ){
- wx = wx*10 + c - '0';
- c = *++fmt;
- }
- testcase( wx>0x7fffffff );
- width = wx & 0x7fffffff;
- }
- assert( width>=0 );
+ case 'l': {
+ flag_long = 1;
+ c = *++fmt;
+ if( c=='l' ){
+ c = *++fmt;
+ flag_long = 2;
+ }
+ done = 1;
+ break;
+ }
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': {
+ unsigned wx = c - '0';
+ while( (c = *++fmt)>='0' && c<='9' ){
+ wx = wx*10 + c - '0';
+ }
+ testcase( wx>0x7fffffff );
+ width = wx & 0x7fffffff;
#ifdef SQLITE_PRINTF_PRECISION_LIMIT
- if( width>SQLITE_PRINTF_PRECISION_LIMIT ){
- width = SQLITE_PRINTF_PRECISION_LIMIT;
- }
+ if( width>SQLITE_PRINTF_PRECISION_LIMIT ){
+ width = SQLITE_PRINTF_PRECISION_LIMIT;
+ }
#endif
-
- /* Get the precision */
- if( c=='.' ){
- c = *++fmt;
- if( c=='*' ){
- if( bArgList ){
- precision = (int)getIntArg(pArgList);
- }else{
- precision = va_arg(ap,int);
+ if( c!='.' && c!='l' ){
+ done = 1;
+ }else{
+ fmt--;
+ }
+ break;
}
- c = *++fmt;
- if( precision<0 ){
- precision = precision >= -2147483647 ? -precision : -1;
+ case '*': {
+ if( bArgList ){
+ width = (int)getIntArg(pArgList);
+ }else{
+ width = va_arg(ap,int);
+ }
+ if( width<0 ){
+ flag_leftjustify = 1;
+ width = width >= -2147483647 ? -width : 0;
+ }
+#ifdef SQLITE_PRINTF_PRECISION_LIMIT
+ if( width>SQLITE_PRINTF_PRECISION_LIMIT ){
+ width = SQLITE_PRINTF_PRECISION_LIMIT;
+ }
+#endif
+ if( (c = fmt[1])!='.' && c!='l' ){
+ c = *++fmt;
+ done = 1;
+ }
+ break;
}
- }else{
- unsigned px = 0;
- while( c>='0' && c<='9' ){
- px = px*10 + c - '0';
+ case '.': {
c = *++fmt;
- }
- testcase( px>0x7fffffff );
- precision = px & 0x7fffffff;
- }
- }else{
- precision = -1;
- }
- assert( precision>=(-1) );
+ if( c=='*' ){
+ if( bArgList ){
+ precision = (int)getIntArg(pArgList);
+ }else{
+ precision = va_arg(ap,int);
+ }
+ if( precision<0 ){
+ precision = precision >= -2147483647 ? -precision : -1;
+ }
+ c = *++fmt;
+ }else{
+ unsigned px = 0;
+ while( c>='0' && c<='9' ){
+ px = px*10 + c - '0';
+ c = *++fmt;
+ }
+ testcase( px>0x7fffffff );
+ precision = px & 0x7fffffff;
+ }
#ifdef SQLITE_PRINTF_PRECISION_LIMIT
- if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){
- precision = SQLITE_PRINTF_PRECISION_LIMIT;
- }
+ if( precision>SQLITE_PRINTF_PRECISION_LIMIT ){
+ precision = SQLITE_PRINTF_PRECISION_LIMIT;
+ }
#endif
-
-
- /* Get the conversion type modifier */
- if( c=='l' ){
- flag_long = 1;
- c = *++fmt;
- if( c=='l' ){
- flag_longlong = 1;
- c = *++fmt;
- }else{
- flag_longlong = 0;
+ if( c=='l' ){
+ --fmt;
+ }else{
+ done = 1;
+ }
+ break;
+ }
}
- }else{
- flag_long = flag_longlong = 0;
- }
+ }while( !done && (c=(*++fmt))!=0 );
+
/* Fetch the info entry for the field */
infop = &fmtinfo[0];
xtype = etINVALID;
for(idx=0; idx<ArraySize(fmtinfo); idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
- if( useIntern || (infop->flags & FLAG_INTERN)==0 ){
- xtype = infop->type;
- }else{
- return;
- }
+ xtype = infop->type;
break;
}
}
@@ -25053,15 +28529,11 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
**
** flag_alternateform TRUE if a '#' is present.
** flag_altform2 TRUE if a '!' is present.
- ** flag_plussign TRUE if a '+' is present.
+ ** flag_prefix '+' or ' ' or zero
** flag_leftjustify TRUE if a '-' is present or if the
** field width was negative.
** flag_zeropad TRUE if the width began with 0.
- ** flag_long TRUE if the letter 'l' (ell) prefixed
- ** the conversion character.
- ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed
- ** the conversion character.
- ** flag_blanksign TRUE if a ' ' is present.
+ ** flag_long 1 for "l", 2 for "ll"
** width The specified field width. This is
** always non-negative. Zero is the default.
** precision The specified precision. The default
@@ -25069,21 +28541,28 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
** xtype The class of the conversion.
** infop Pointer to the appropriate info struct.
*/
+ assert( width>=0 );
+ assert( precision>=(-1) );
switch( xtype ){
case etPOINTER:
- flag_longlong = sizeof(char*)==sizeof(i64);
- flag_long = sizeof(char*)==sizeof(long int);
- /* Fall through into the next case */
+ flag_long = sizeof(char*)==sizeof(i64) ? 2 :
+ sizeof(char*)==sizeof(long int) ? 1 : 0;
+ /* no break */ deliberate_fall_through
case etORDINAL:
case etRADIX:
+ cThousand = 0;
+ /* no break */ deliberate_fall_through
+ case etDECIMAL:
if( infop->flags & FLAG_SIGNED ){
i64 v;
if( bArgList ){
v = getIntArg(pArgList);
- }else if( flag_longlong ){
- v = va_arg(ap,i64);
}else if( flag_long ){
- v = va_arg(ap,long int);
+ if( flag_long==2 ){
+ v = va_arg(ap,i64) ;
+ }else{
+ v = va_arg(ap,long int);
+ }
}else{
v = va_arg(ap,int);
}
@@ -25096,17 +28575,17 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
prefix = '-';
}else{
longvalue = v;
- if( flag_plussign ) prefix = '+';
- else if( flag_blanksign ) prefix = ' ';
- else prefix = 0;
+ prefix = flag_prefix;
}
}else{
if( bArgList ){
longvalue = (u64)getIntArg(pArgList);
- }else if( flag_longlong ){
- longvalue = va_arg(ap,u64);
}else if( flag_long ){
- longvalue = va_arg(ap,unsigned long int);
+ if( flag_long==2 ){
+ longvalue = va_arg(ap,u64);
+ }else{
+ longvalue = va_arg(ap,unsigned long int);
+ }
}else{
longvalue = va_arg(ap,unsigned int);
}
@@ -25116,16 +28595,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( flag_zeropad && precision<width-(prefix!=0) ){
precision = width-(prefix!=0);
}
- if( precision<etBUFSIZE-10 ){
+ if( precision<etBUFSIZE-10-etBUFSIZE/3 ){
nOut = etBUFSIZE;
zOut = buf;
}else{
- nOut = precision + 10;
- zOut = zExtra = sqlite3Malloc( nOut );
- if( zOut==0 ){
- setStrAccumError(pAccum, STRACCUM_NOMEM);
- return;
- }
+ u64 n;
+ n = (u64)precision + 10;
+ if( cThousand ) n += precision/3;
+ zOut = zExtra = printfTempBuf(pAccum, n);
+ if( zOut==0 ) return;
+ nOut = (int)n;
}
bufpt = &zOut[nOut-1];
if( xtype==etORDINAL ){
@@ -25146,8 +28625,23 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}while( longvalue>0 );
}
length = (int)(&zOut[nOut-1]-bufpt);
- for(idx=precision-length; idx>0; idx--){
+ while( precision>length ){
*(--bufpt) = '0'; /* Zero pad */
+ length++;
+ }
+ if( cThousand ){
+ int nn = (length - 1)/3; /* Number of "," to insert */
+ int ix = (length - 1)%3 + 1;
+ bufpt -= nn;
+ for(idx=0; nn>0; idx++){
+ bufpt[idx] = bufpt[idx+nn];
+ ix--;
+ if( ix==0 ){
+ bufpt[++idx] = cThousand;
+ nn--;
+ ix = 3;
+ }
+ }
}
if( prefix ) *(--bufpt) = prefix; /* Add sign */
if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */
@@ -25170,18 +28664,31 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
length = 0;
#else
if( precision<0 ) precision = 6; /* Set default precision */
+#ifdef SQLITE_FP_PRECISION_LIMIT
+ if( precision>SQLITE_FP_PRECISION_LIMIT ){
+ precision = SQLITE_FP_PRECISION_LIMIT;
+ }
+#endif
if( realvalue<0.0 ){
realvalue = -realvalue;
prefix = '-';
}else{
- if( flag_plussign ) prefix = '+';
- else if( flag_blanksign ) prefix = ' ';
- else prefix = 0;
+ prefix = flag_prefix;
}
if( xtype==etGENERIC && precision>0 ) precision--;
testcase( precision>0xfff );
- for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){}
- if( xtype==etFLOAT ) realvalue += rounder;
+ idx = precision & 0xfff;
+ rounder = arRound[idx%10];
+ while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
+ if( xtype==etFLOAT ){
+ double rx = (double)realvalue;
+ sqlite3_uint64 u;
+ int ex;
+ memcpy(&u, &rx, sizeof(u));
+ ex = -1023 + (int)((u>>52)&0x7ff);
+ if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
+ realvalue += rounder;
+ }
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( sqlite3IsNaN((double)realvalue) ){
@@ -25230,12 +28737,12 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
e2 = exp;
}
- if( MAX(e2,0)+(i64)precision+(i64)width > etBUFSIZE - 15 ){
- bufpt = zExtra
- = sqlite3Malloc( MAX(e2,0)+(i64)precision+(i64)width+15 );
- if( bufpt==0 ){
- setStrAccumError(pAccum, STRACCUM_NOMEM);
- return;
+ {
+ i64 szBufNeeded; /* Size of a temporary buffer needed */
+ szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
+ if( szBufNeeded > etBUFSIZE ){
+ bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
+ if( bufpt==0 ) return;
}
}
zOut = bufpt;
@@ -25330,22 +28837,52 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
case etCHARX:
if( bArgList ){
bufpt = getTextArg(pArgList);
- c = bufpt ? bufpt[0] : 0;
+ length = 1;
+ if( bufpt ){
+ buf[0] = c = *(bufpt++);
+ if( (c&0xc0)==0xc0 ){
+ while( length<4 && (bufpt[0]&0xc0)==0x80 ){
+ buf[length++] = *(bufpt++);
+ }
+ }
+ }else{
+ buf[0] = 0;
+ }
}else{
- c = va_arg(ap,int);
+ unsigned int ch = va_arg(ap,unsigned int);
+ if( ch<0x00080 ){
+ buf[0] = ch & 0xff;
+ length = 1;
+ }else if( ch<0x00800 ){
+ buf[0] = 0xc0 + (u8)((ch>>6)&0x1f);
+ buf[1] = 0x80 + (u8)(ch & 0x3f);
+ length = 2;
+ }else if( ch<0x10000 ){
+ buf[0] = 0xe0 + (u8)((ch>>12)&0x0f);
+ buf[1] = 0x80 + (u8)((ch>>6) & 0x3f);
+ buf[2] = 0x80 + (u8)(ch & 0x3f);
+ length = 3;
+ }else{
+ buf[0] = 0xf0 + (u8)((ch>>18) & 0x07);
+ buf[1] = 0x80 + (u8)((ch>>12) & 0x3f);
+ buf[2] = 0x80 + (u8)((ch>>6) & 0x3f);
+ buf[3] = 0x80 + (u8)(ch & 0x3f);
+ length = 4;
+ }
}
if( precision>1 ){
width -= precision-1;
if( width>1 && !flag_leftjustify ){
- sqlite3AppendChar(pAccum, width-1, ' ');
+ sqlite3_str_appendchar(pAccum, width-1, ' ');
width = 0;
}
- sqlite3AppendChar(pAccum, precision-1, c);
+ while( precision-- > 1 ){
+ sqlite3_str_append(pAccum, buf, length);
+ }
}
- length = 1;
- buf[0] = c;
bufpt = buf;
- break;
+ flag_altform2 = 1;
+ goto adjust_width_for_utf8;
case etSTRING:
case etDYNSTRING:
if( bArgList ){
@@ -25357,17 +28894,50 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( bufpt==0 ){
bufpt = "";
}else if( xtype==etDYNSTRING ){
+ if( pAccum->nChar==0
+ && pAccum->mxAlloc
+ && width==0
+ && precision<0
+ && pAccum->accError==0
+ ){
+ /* Special optimization for sqlite3_mprintf("%z..."):
+ ** Extend an existing memory allocation rather than creating
+ ** a new one. */
+ assert( (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 );
+ pAccum->zText = bufpt;
+ pAccum->nAlloc = sqlite3DbMallocSize(pAccum->db, bufpt);
+ pAccum->nChar = 0x7fffffff & (int)strlen(bufpt);
+ pAccum->printfFlags |= SQLITE_PRINTF_MALLOCED;
+ length = 0;
+ break;
+ }
zExtra = bufpt;
}
if( precision>=0 ){
- for(length=0; length<precision && bufpt[length]; length++){}
+ if( flag_altform2 ){
+ /* Set length to the number of bytes needed in order to display
+ ** precision characters */
+ unsigned char *z = (unsigned char*)bufpt;
+ while( precision-- > 0 && z[0] ){
+ SQLITE_SKIP_UTF8(z);
+ }
+ length = (int)(z - (unsigned char*)bufpt);
+ }else{
+ for(length=0; length<precision && bufpt[length]; length++){}
+ }
}else{
- length = sqlite3Strlen30(bufpt);
+ length = 0x7fffffff & (int)strlen(bufpt);
+ }
+ adjust_width_for_utf8:
+ if( flag_altform2 && width>0 ){
+ /* Adjust width to account for extra bytes in UTF-8 characters */
+ int ii = length - 1;
+ while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
}
break;
- case etSQLESCAPE: /* Escape ' characters */
- case etSQLESCAPE2: /* Escape ' and enclose in '...' */
- case etSQLESCAPE3: { /* Escape " characters */
+ case etSQLESCAPE: /* %q: Escape ' characters */
+ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
+ case etSQLESCAPE3: { /* %w: Escape " characters */
int i, j, k, n, isnull;
int needQuote;
char ch;
@@ -25381,18 +28951,23 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}
isnull = escarg==0;
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
+ /* For %q, %Q, and %w, the precision is the number of bytes (or
+ ** characters if the ! flags is present) to use from the input.
+ ** Because of the extra quoting characters inserted, the number
+ ** of output characters may be larger than the precision.
+ */
k = precision;
for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
if( ch==q ) n++;
+ if( flag_altform2 && (ch&0xc0)==0xc0 ){
+ while( (escarg[i+1]&0xc0)==0x80 ){ i++; }
+ }
}
needQuote = !isnull && xtype==etSQLESCAPE2;
n += i + 3;
if( n>etBUFSIZE ){
- bufpt = zExtra = sqlite3Malloc( n );
- if( bufpt==0 ){
- setStrAccumError(pAccum, STRACCUM_NOMEM);
- return;
- }
+ bufpt = zExtra = printfTempBuf(pAccum, n);
+ if( bufpt==0 ) return;
}else{
bufpt = buf;
}
@@ -25406,31 +28981,34 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
if( needQuote ) bufpt[j++] = q;
bufpt[j] = 0;
length = j;
- /* The precision in %q and %Q means how many input characters to
- ** consume, not the length of the output...
- ** if( precision>=0 && precision<length ) length = precision; */
- break;
+ goto adjust_width_for_utf8;
}
case etTOKEN: {
- Token *pToken = va_arg(ap, Token*);
+ Token *pToken;
+ if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
+ pToken = va_arg(ap, Token*);
assert( bArgList==0 );
if( pToken && pToken->n ){
- sqlite3StrAccumAppend(pAccum, (const char*)pToken->z, pToken->n);
+ sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
}
length = width = 0;
break;
}
case etSRCLIST: {
- SrcList *pSrc = va_arg(ap, SrcList*);
- int k = va_arg(ap, int);
- struct SrcList_item *pItem = &pSrc->a[k];
+ SrcList *pSrc;
+ int k;
+ struct SrcList_item *pItem;
+ if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
+ pSrc = va_arg(ap, SrcList*);
+ k = va_arg(ap, int);
+ pItem = &pSrc->a[k];
assert( bArgList==0 );
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase ){
- sqlite3StrAccumAppendAll(pAccum, pItem->zDatabase);
- sqlite3StrAccumAppend(pAccum, ".", 1);
+ sqlite3_str_appendall(pAccum, pItem->zDatabase);
+ sqlite3_str_append(pAccum, ".", 1);
}
- sqlite3StrAccumAppendAll(pAccum, pItem->zName);
+ sqlite3_str_appendall(pAccum, pItem->zName);
length = width = 0;
break;
}
@@ -25442,12 +29020,19 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
- ** the output.
+ ** the output. Both length and width are in bytes, not characters,
+ ** at this point. If the "!" flag was present on string conversions
+ ** indicating that width and precision should be expressed in characters,
+ ** then the values have been translated prior to reaching this point.
*/
width -= length;
- if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
- sqlite3StrAccumAppend(pAccum, bufpt, length);
- if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
+ if( width>0 ){
+ if( !flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' ');
+ sqlite3_str_append(pAccum, bufpt, length);
+ if( flag_leftjustify ) sqlite3_str_appendchar(pAccum, width, ' ');
+ }else{
+ sqlite3_str_append(pAccum, bufpt, length);
+ }
if( zExtra ){
sqlite3DbFree(pAccum->db, zExtra);
@@ -25467,18 +29052,16 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
- testcase(p->accError==STRACCUM_TOOBIG);
- testcase(p->accError==STRACCUM_NOMEM);
+ testcase(p->accError==SQLITE_TOOBIG);
+ testcase(p->accError==SQLITE_NOMEM);
return 0;
}
if( p->mxAlloc==0 ){
- N = p->nAlloc - p->nChar - 1;
- setStrAccumError(p, STRACCUM_TOOBIG);
- return N;
+ setStrAccumError(p, SQLITE_TOOBIG);
+ return p->nAlloc - p->nChar - 1;
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
i64 szNew = p->nChar;
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
szNew += N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
@@ -25486,8 +29069,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
szNew += p->nChar;
}
if( szNew > p->mxAlloc ){
- sqlite3StrAccumReset(p);
- setStrAccumError(p, STRACCUM_TOOBIG);
+ sqlite3_str_reset(p);
+ setStrAccumError(p, SQLITE_TOOBIG);
return 0;
}else{
p->nAlloc = (int)szNew;
@@ -25495,7 +29078,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
if( p->db ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
- zNew = sqlite3_realloc64(zOld, p->nAlloc);
+ zNew = sqlite3Realloc(zOld, p->nAlloc);
}
if( zNew ){
assert( p->zText!=0 || p->nChar==0 );
@@ -25504,8 +29087,8 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
- sqlite3StrAccumReset(p);
- setStrAccumError(p, STRACCUM_NOMEM);
+ sqlite3_str_reset(p);
+ setStrAccumError(p, SQLITE_NOMEM);
return 0;
}
}
@@ -25515,12 +29098,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
/*
** Append N copies of character c to the given string buffer.
*/
-SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
+SQLITE_API void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){
testcase( p->nChar + (i64)N > 0x7fffffff );
if( p->nChar+(i64)N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ){
return;
}
- assert( (p->zText==p->zBase)==!isMalloced(p) );
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
@@ -25528,9 +29110,9 @@ SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
** The StrAccum "p" is not large enough to accept N new bytes of z[].
** So enlarge if first, then do the append.
**
-** This is a helper routine to sqlite3StrAccumAppend() that does special-case
+** This is a helper routine to sqlite3_str_append() that does special-case
** work (enlarging the buffer) using tail recursion, so that the
-** sqlite3StrAccumAppend() routine can use fast calling semantics.
+** sqlite3_str_append() routine can use fast calling semantics.
*/
static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
N = sqlite3StrAccumEnlarge(p, N);
@@ -25538,21 +29120,20 @@ static void SQLITE_NOINLINE enlargeAndAppend(StrAccum *p, const char *z, int N){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
}
/*
** Append N bytes of text from z to the StrAccum object. Increase the
** size of the memory allocation for StrAccum if necessary.
*/
-SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
+SQLITE_API void sqlite3_str_append(sqlite3_str *p, const char *z, int N){
assert( z!=0 || N==0 );
assert( p->zText!=0 || p->nChar==0 || p->accError );
assert( N>=0 );
- assert( p->accError==0 || p->nAlloc==0 );
+ assert( p->accError==0 || p->nAlloc==0 || p->mxAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
- }else{
+ }else if( N ){
assert( p->zText );
p->nChar += N;
memcpy(&p->zText[p->nChar-N], z, N);
@@ -25562,8 +29143,8 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
/*
** Append the complete text of zero-terminated string z[] to the p string.
*/
-SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
- sqlite3StrAccumAppend(p, z, sqlite3Strlen30(z));
+SQLITE_API void sqlite3_str_appendall(sqlite3_str *p, const char *z){
+ sqlite3_str_append(p, z, sqlite3Strlen30(z));
}
@@ -25572,32 +29153,79 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
** Return a pointer to the resulting string. Return a NULL
** pointer if any kind of error was encountered.
*/
+static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
+ char *zText;
+ assert( p->mxAlloc>0 && !isMalloced(p) );
+ zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
+ if( zText ){
+ memcpy(zText, p->zText, p->nChar+1);
+ p->printfFlags |= SQLITE_PRINTF_MALLOCED;
+ }else{
+ setStrAccumError(p, SQLITE_NOMEM);
+ }
+ p->zText = zText;
+ return zText;
+}
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
- assert( (p->zText==p->zBase)==!isMalloced(p) );
p->zText[p->nChar] = 0;
if( p->mxAlloc>0 && !isMalloced(p) ){
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
- if( p->zText ){
- memcpy(p->zText, p->zBase, p->nChar+1);
- p->printfFlags |= SQLITE_PRINTF_MALLOCED;
- }else{
- setStrAccumError(p, STRACCUM_NOMEM);
- }
+ return strAccumFinishRealloc(p);
}
}
return p->zText;
}
/*
+** This singleton is an sqlite3_str object that is returned if
+** sqlite3_malloc() fails to provide space for a real one. This
+** sqlite3_str object accepts no new text and always returns
+** an SQLITE_NOMEM error.
+*/
+static sqlite3_str sqlite3OomStr = {
+ 0, 0, 0, 0, 0, SQLITE_NOMEM, 0
+};
+
+/* Finalize a string created using sqlite3_str_new().
+*/
+SQLITE_API char *sqlite3_str_finish(sqlite3_str *p){
+ char *z;
+ if( p!=0 && p!=&sqlite3OomStr ){
+ z = sqlite3StrAccumFinish(p);
+ sqlite3_free(p);
+ }else{
+ z = 0;
+ }
+ return z;
+}
+
+/* Return any error code associated with p */
+SQLITE_API int sqlite3_str_errcode(sqlite3_str *p){
+ return p ? p->accError : SQLITE_NOMEM;
+}
+
+/* Return the current length of p in bytes */
+SQLITE_API int sqlite3_str_length(sqlite3_str *p){
+ return p ? p->nChar : 0;
+}
+
+/* Return the current value for p */
+SQLITE_API char *sqlite3_str_value(sqlite3_str *p){
+ if( p==0 || p->nChar==0 ) return 0;
+ p->zText[p->nChar] = 0;
+ return p->zText;
+}
+
+/*
** Reset an StrAccum string. Reclaim all malloced memory.
*/
-SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
- assert( (p->zText==0 || p->zText==p->zBase)==!isMalloced(p) );
+SQLITE_API void sqlite3_str_reset(StrAccum *p){
if( isMalloced(p) ){
sqlite3DbFree(p->db, p->zText);
p->printfFlags &= ~SQLITE_PRINTF_MALLOCED;
}
+ p->nAlloc = 0;
+ p->nChar = 0;
p->zText = 0;
}
@@ -25616,15 +29244,27 @@ SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum *p){
** allocations will ever occur.
*/
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum *p, sqlite3 *db, char *zBase, int n, int mx){
- p->zText = p->zBase = zBase;
+ p->zText = zBase;
p->db = db;
- p->nChar = 0;
p->nAlloc = n;
p->mxAlloc = mx;
+ p->nChar = 0;
p->accError = 0;
p->printfFlags = 0;
}
+/* Allocate and initialize a new dynamic string object */
+SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3 *db){
+ sqlite3_str *p = sqlite3_malloc64(sizeof(*p));
+ if( p ){
+ sqlite3StrAccumInit(p, 0, 0, 0,
+ db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH);
+ }else{
+ p = &sqlite3OomStr;
+ }
+ return p;
+}
+
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
@@ -25637,9 +29277,9 @@ SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list a
sqlite3StrAccumInit(&acc, db, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
acc.printfFlags = SQLITE_PRINTF_INTERNAL;
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
- if( acc.accError==STRACCUM_NOMEM ){
+ if( acc.accError==SQLITE_NOMEM ){
sqlite3OomFault(db);
}
return z;
@@ -25667,7 +29307,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
-#ifdef SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( zFormat==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
@@ -25677,7 +29317,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
if( sqlite3_initialize() ) return 0;
#endif
sqlite3StrAccumInit(&acc, 0, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
return z;
}
@@ -25722,8 +29362,9 @@ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_li
}
#endif
sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
- sqlite3VXPrintf(&acc, zFormat, ap);
- return sqlite3StrAccumFinish(&acc);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
+ zBuf[acc.nChar] = 0;
+ return zBuf;
}
SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
@@ -25743,7 +29384,7 @@ SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
** allocate memory because it might be called while the memory allocator
** mutex is held.
**
-** sqlite3VXPrintf() might ask for *temporary* memory allocations for
+** sqlite3_str_vappendf() might ask for *temporary* memory allocations for
** certain format characters (%q) or for very large precisions or widths.
** Care must be taken that any sqlite3_log() calls that occur while the
** memory mutex is held do not use these mechanisms.
@@ -25753,7 +29394,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
char zMsg[SQLITE_PRINT_BUF_SIZE*3]; /* Complete log message */
sqlite3StrAccumInit(&acc, 0, zMsg, sizeof(zMsg), 0);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
sqlite3GlobalConfig.xLog(sqlite3GlobalConfig.pLogArg, iErrCode,
sqlite3StrAccumFinish(&acc));
}
@@ -25779,26 +29420,33 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
va_list ap;
StrAccum acc;
- char zBuf[500];
+ char zBuf[SQLITE_PRINT_BUF_SIZE*10];
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
va_start(ap,zFormat);
- sqlite3VXPrintf(&acc, zFormat, ap);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
sqlite3StrAccumFinish(&acc);
+#ifdef SQLITE_OS_TRACE_PROC
+ {
+ extern void SQLITE_OS_TRACE_PROC(const char *zBuf, int nBuf);
+ SQLITE_OS_TRACE_PROC(zBuf, sizeof(zBuf));
+ }
+#else
fprintf(stdout,"%s", zBuf);
fflush(stdout);
+#endif
}
#endif
/*
-** variable-argument wrapper around sqlite3VXPrintf(). The bFlags argument
+** variable-argument wrapper around sqlite3_str_vappendf(). The bFlags argument
** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats.
*/
-SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
+SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
va_list ap;
va_start(ap,zFormat);
- sqlite3VXPrintf(p, zFormat, ap);
+ sqlite3_str_vappendf(p, zFormat, ap);
va_end(ap);
}
@@ -25818,7 +29466,7 @@ SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, const char *zFormat, ...){
**
** This file contains C code to implement the TreeView debugging routines.
** These routines print a parse tree to standard output for debugging and
-** analysis.
+** analysis.
**
** The interfaces in this file is only available when compiling
** with SQLITE_DEBUG.
@@ -25864,14 +29512,17 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
if( p ){
for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
- sqlite3StrAccumAppend(&acc, p->bLine[i] ? "| " : " ", 4);
+ sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4);
}
- sqlite3StrAccumAppend(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
+ sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
+ }
+ if( zFormat!=0 ){
+ va_start(ap, zFormat);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
+ va_end(ap);
+ assert( acc.nChar>0 || acc.accError );
+ sqlite3_str_append(&acc, "\n", 1);
}
- va_start(ap, zFormat);
- sqlite3VXPrintf(&acc, zFormat, ap);
- va_end(ap);
- if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf);
fflush(stdout);
@@ -25904,17 +29555,17 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
char zLine[1000];
const struct Cte *pCte = &pWith->a[i];
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
- sqlite3XPrintf(&x, "%s", pCte->zName);
+ sqlite3_str_appendf(&x, "%s", pCte->zName);
if( pCte->pCols && pCte->pCols->nExpr>0 ){
char cSep = '(';
int j;
for(j=0; j<pCte->pCols->nExpr; j++){
- sqlite3XPrintf(&x, "%c%s", cSep, pCte->pCols->a[j].zName);
+ sqlite3_str_appendf(&x, "%c%s", cSep, pCte->pCols->a[j].zEName);
cSep = ',';
}
- sqlite3XPrintf(&x, ")");
+ sqlite3_str_appendf(&x, ")");
}
- sqlite3XPrintf(&x, " AS");
+ sqlite3_str_appendf(&x, " AS");
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
@@ -25924,6 +29575,46 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
}
}
+/*
+** Generate a human-readable description of a SrcList object.
+*/
+SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
+ int i;
+ for(i=0; i<pSrc->nSrc; i++){
+ const struct SrcList_item *pItem = &pSrc->a[i];
+ StrAccum x;
+ char zLine[100];
+ sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
+ sqlite3_str_appendf(&x, "{%d:*}", pItem->iCursor);
+ if( pItem->zDatabase ){
+ sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
+ }else if( pItem->zName ){
+ sqlite3_str_appendf(&x, " %s", pItem->zName);
+ }
+ if( pItem->pTab ){
+ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
+ pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
+ }
+ if( pItem->zAlias ){
+ sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias);
+ }
+ if( pItem->fg.jointype & JT_LEFT ){
+ sqlite3_str_appendf(&x, " LEFT-JOIN");
+ }
+ if( pItem->fg.fromDDL ){
+ sqlite3_str_appendf(&x, " DDL");
+ }
+ sqlite3StrAccumFinish(&x);
+ sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
+ if( pItem->pSelect ){
+ sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
+ }
+ if( pItem->fg.isTabFunc ){
+ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
+ }
+ sqlite3TreeViewPop(pView);
+ }
+}
/*
** Generate a human-readable description of a Select object.
@@ -25931,6 +29622,10 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
int n = 0;
int cnt = 0;
+ if( p==0 ){
+ sqlite3TreeViewLine(pView, "nil-SELECT");
+ return;
+ }
pView = sqlite3TreeViewPush(pView, moreToFollow);
if( p->pWith ){
sqlite3TreeViewWith(pView, p->pWith, 1);
@@ -25938,11 +29633,17 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
sqlite3TreeViewPush(pView, 1);
}
do{
- sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
- ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
- ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
- (int)p->nSelectRow
- );
+ if( p->selFlags & SF_WhereBegin ){
+ sqlite3TreeViewLine(pView, "sqlite3WhereBegin()");
+ }else{
+ sqlite3TreeViewLine(pView,
+ "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
+ ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
+ p->selId, p, p->selFlags,
+ (int)p->nSelectRow
+ );
+ }
if( cnt++ ) sqlite3TreeViewPop(pView);
if( p->pPrior ){
n = 1000;
@@ -25954,43 +29655,30 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
if( p->pHaving ) n++;
if( p->pOrderBy ) n++;
if( p->pLimit ) n++;
- if( p->pOffset ) n++;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( p->pWin ) n++;
+ if( p->pWinDefn ) n++;
+#endif
+ }
+ if( p->pEList ){
+ sqlite3TreeViewExprList(pView, p->pEList, n>0, "result-set");
+ }
+ n--;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( p->pWin ){
+ Window *pX;
+ pView = sqlite3TreeViewPush(pView, (n--)>0);
+ sqlite3TreeViewLine(pView, "window-functions");
+ for(pX=p->pWin; pX; pX=pX->pNextWin){
+ sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
+ }
+ sqlite3TreeViewPop(pView);
}
- sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
+#endif
if( p->pSrc && p->pSrc->nSrc ){
- int i;
pView = sqlite3TreeViewPush(pView, (n--)>0);
sqlite3TreeViewLine(pView, "FROM");
- for(i=0; i<p->pSrc->nSrc; i++){
- struct SrcList_item *pItem = &p->pSrc->a[i];
- StrAccum x;
- char zLine[100];
- sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
- sqlite3XPrintf(&x, "{%d,*}", pItem->iCursor);
- if( pItem->zDatabase ){
- sqlite3XPrintf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
- }else if( pItem->zName ){
- sqlite3XPrintf(&x, " %s", pItem->zName);
- }
- if( pItem->pTab ){
- sqlite3XPrintf(&x, " tabname=%Q", pItem->pTab->zName);
- }
- if( pItem->zAlias ){
- sqlite3XPrintf(&x, " (AS %s)", pItem->zAlias);
- }
- if( pItem->fg.jointype & JT_LEFT ){
- sqlite3XPrintf(&x, " LEFT-JOIN");
- }
- sqlite3StrAccumFinish(&x);
- sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1);
- if( pItem->pSelect ){
- sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
- }
- if( pItem->fg.isTabFunc ){
- sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
- }
- sqlite3TreeViewPop(pView);
- }
+ sqlite3TreeViewSrcList(pView, p->pSrc);
sqlite3TreeViewPop(pView);
}
if( p->pWhere ){
@@ -26006,17 +29694,27 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
sqlite3TreeViewExpr(pView, p->pHaving, 0);
sqlite3TreeViewPop(pView);
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( p->pWinDefn ){
+ Window *pX;
+ sqlite3TreeViewItem(pView, "WINDOW", (n--)>0);
+ for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
+ sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
+ }
+ sqlite3TreeViewPop(pView);
+ }
+#endif
if( p->pOrderBy ){
sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
}
if( p->pLimit ){
sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
- sqlite3TreeViewExpr(pView, p->pLimit, 0);
- sqlite3TreeViewPop(pView);
- }
- if( p->pOffset ){
- sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
- sqlite3TreeViewExpr(pView, p->pOffset, 0);
+ sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0);
+ if( p->pLimit->pRight ){
+ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
+ sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
+ sqlite3TreeViewPop(pView);
+ }
sqlite3TreeViewPop(pView);
}
if( p->pPrior ){
@@ -26033,21 +29731,149 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
sqlite3TreeViewPop(pView);
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Generate a description of starting or stopping bounds
+*/
+SQLITE_PRIVATE void sqlite3TreeViewBound(
+ TreeView *pView, /* View context */
+ u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */
+ Expr *pExpr, /* Value for PRECEDING or FOLLOWING */
+ u8 moreToFollow /* True if more to follow */
+){
+ switch( eBound ){
+ case TK_UNBOUNDED: {
+ sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
+ sqlite3TreeViewPop(pView);
+ break;
+ }
+ case TK_CURRENT: {
+ sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
+ sqlite3TreeViewPop(pView);
+ break;
+ }
+ case TK_PRECEDING: {
+ sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
+ sqlite3TreeViewExpr(pView, pExpr, 0);
+ sqlite3TreeViewPop(pView);
+ break;
+ }
+ case TK_FOLLOWING: {
+ sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
+ sqlite3TreeViewExpr(pView, pExpr, 0);
+ sqlite3TreeViewPop(pView);
+ break;
+ }
+ }
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Generate a human-readable explanation for a Window object
+*/
+SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
+ int nElement = 0;
+ if( pWin->pFilter ){
+ sqlite3TreeViewItem(pView, "FILTER", 1);
+ sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ pView = sqlite3TreeViewPush(pView, more);
+ if( pWin->zName ){
+ sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin);
+ }else{
+ sqlite3TreeViewLine(pView, "OVER (%p)", pWin);
+ }
+ if( pWin->zBase ) nElement++;
+ if( pWin->pOrderBy ) nElement++;
+ if( pWin->eFrmType ) nElement++;
+ if( pWin->eExclude ) nElement++;
+ if( pWin->zBase ){
+ sqlite3TreeViewPush(pView, (--nElement)>0);
+ sqlite3TreeViewLine(pView, "window: %s", pWin->zBase);
+ sqlite3TreeViewPop(pView);
+ }
+ if( pWin->pPartition ){
+ sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY");
+ }
+ if( pWin->pOrderBy ){
+ sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY");
+ }
+ if( pWin->eFrmType ){
+ char zBuf[30];
+ const char *zFrmType = "ROWS";
+ if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE";
+ if( pWin->eFrmType==TK_GROUPS ) zFrmType = "GROUPS";
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"%s%s",zFrmType,
+ pWin->bImplicitFrame ? " (implied)" : "");
+ sqlite3TreeViewItem(pView, zBuf, (--nElement)>0);
+ sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
+ sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
+ sqlite3TreeViewPop(pView);
+ }
+ if( pWin->eExclude ){
+ char zBuf[30];
+ const char *zExclude;
+ switch( pWin->eExclude ){
+ case TK_NO: zExclude = "NO OTHERS"; break;
+ case TK_CURRENT: zExclude = "CURRENT ROW"; break;
+ case TK_GROUP: zExclude = "GROUP"; break;
+ case TK_TIES: zExclude = "TIES"; break;
+ default:
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"invalid(%d)", pWin->eExclude);
+ zExclude = zBuf;
+ break;
+ }
+ sqlite3TreeViewPush(pView, 0);
+ sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude);
+ sqlite3TreeViewPop(pView);
+ }
+ sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Generate a human-readable explanation for a Window Function object
+*/
+SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
+ pView = sqlite3TreeViewPush(pView, more);
+ sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
+ pWin->pFunc->zName, pWin->pFunc->nArg);
+ sqlite3TreeViewWindow(pView, pWin, 0);
+ sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
/*
** Generate a human-readable explanation of an expression tree.
*/
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
const char *zBinOp = 0; /* Binary operator */
const char *zUniOp = 0; /* Unary operator */
- char zFlgs[30];
+ char zFlgs[200];
pView = sqlite3TreeViewPush(pView, moreToFollow);
if( pExpr==0 ){
sqlite3TreeViewLine(pView, "nil");
sqlite3TreeViewPop(pView);
return;
}
- if( pExpr->flags ){
- sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags);
+ if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
+ StrAccum x;
+ sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
+ sqlite3_str_appendf(&x, " fg.af=%x.%c",
+ pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
+ if( ExprHasProperty(pExpr, EP_FromJoin) ){
+ sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable);
+ }
+ if( ExprHasProperty(pExpr, EP_FromDDL) ){
+ sqlite3_str_appendf(&x, " DDL");
+ }
+ if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
+ sqlite3_str_appendf(&x, " IMMUTABLE");
+ }
+ sqlite3StrAccumFinish(&x);
}else{
zFlgs[0] = 0;
}
@@ -26060,10 +29886,21 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
case TK_COLUMN: {
if( pExpr->iTable<0 ){
/* This only happens when coding check constraints */
- sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs);
+ char zOp2[16];
+ if( pExpr->op2 ){
+ sqlite3_snprintf(sizeof(zOp2),zOp2," op2=0x%02x",pExpr->op2);
+ }else{
+ zOp2[0] = 0;
+ }
+ sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s",
+ pExpr->iColumn, zFlgs, zOp2);
}else{
- sqlite3TreeViewLine(pView, "{%d:%d}%s",
- pExpr->iTable, pExpr->iColumn, zFlgs);
+ sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s",
+ pExpr->iTable, pExpr->iColumn,
+ pExpr->y.pTab, zFlgs);
+ }
+ if( ExprHasProperty(pExpr, EP_FixedCol) ){
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
}
break;
}
@@ -26089,6 +29926,11 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewLine(pView,"NULL");
break;
}
+ case TK_TRUEFALSE: {
+ sqlite3TreeViewLine(pView,
+ sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE");
+ break;
+ }
#ifndef SQLITE_OMIT_BLOB_LITERAL
case TK_BLOB: {
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
@@ -26137,6 +29979,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
case TK_RSHIFT: zBinOp = "RSHIFT"; break;
case TK_CONCAT: zBinOp = "CONCAT"; break;
case TK_DOT: zBinOp = "DOT"; break;
+ case TK_LIMIT: zBinOp = "LIMIT"; break;
case TK_UMINUS: zUniOp = "UMINUS"; break;
case TK_UPLUS: zUniOp = "UPLUS"; break;
@@ -26145,6 +29988,19 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
case TK_ISNULL: zUniOp = "ISNULL"; break;
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
+ case TK_TRUTH: {
+ int x;
+ const char *azOp[] = {
+ "IS-FALSE", "IS-TRUE", "IS-NOT-FALSE", "IS-NOT-TRUE"
+ };
+ assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
+ assert( pExpr->pRight );
+ assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE );
+ x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight);
+ zUniOp = azOp[x];
+ break;
+ }
+
case TK_SPAN: {
sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
@@ -26152,7 +30008,14 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
}
case TK_COLLATE: {
- sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
+ /* COLLATE operators without the EP_Collate flag are intended to
+ ** emulate collation associated with a table column. These show
+ ** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE
+ ** operators that appear in the original SQL always have the
+ ** EP_Collate bit set and appear in treeview output as just "COLLATE" */
+ sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s",
+ !ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "",
+ pExpr->u.zToken, zFlgs);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
break;
}
@@ -26160,35 +30023,60 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
case TK_AGG_FUNCTION:
case TK_FUNCTION: {
ExprList *pFarg; /* List of function arguments */
+ Window *pWin;
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0;
+ pWin = 0;
}else{
pFarg = pExpr->x.pList;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
+#else
+ pWin = 0;
+#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
- pExpr->op2, pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p",
+ pExpr->op2, pExpr->u.zToken, zFlgs,
+ pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0,
+ pExpr->iAgg, pExpr->pAggInfo);
+ }else if( pExpr->op2!=0 ){
+ const char *zOp2;
+ char zBuf[8];
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"0x%02x",pExpr->op2);
+ zOp2 = zBuf;
+ if( pExpr->op2==NC_IsCheck ) zOp2 = "NC_IsCheck";
+ if( pExpr->op2==NC_IdxExpr ) zOp2 = "NC_IdxExpr";
+ if( pExpr->op2==NC_PartIdx ) zOp2 = "NC_PartIdx";
+ if( pExpr->op2==NC_GenCol ) zOp2 = "NC_GenCol";
+ sqlite3TreeViewLine(pView, "FUNCTION %Q%s op2=%s",
+ pExpr->u.zToken, zFlgs, zOp2);
}else{
- sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
+ sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
- sqlite3TreeViewExprList(pView, pFarg, 0, 0);
+ sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pWin ){
+ sqlite3TreeViewWindow(pView, pWin, 0);
}
+#endif
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: {
- sqlite3TreeViewLine(pView, "EXISTS-expr");
+ sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags);
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
break;
}
case TK_SELECT: {
- sqlite3TreeViewLine(pView, "SELECT-expr");
+ sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags);
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
break;
}
case TK_IN: {
- sqlite3TreeViewLine(pView, "IN");
+ sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
@@ -26228,7 +30116,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
** is set to the column of the pseudo-table to read, or to -1 to
** read the rowid field.
*/
- sqlite3TreeViewLine(pView, "%s(%d)",
+ sqlite3TreeViewLine(pView, "%s(%d)",
pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
break;
}
@@ -26241,7 +30129,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
#ifndef SQLITE_OMIT_TRIGGER
case TK_RAISE: {
const char *zType = "unk";
- switch( pExpr->affinity ){
+ switch( pExpr->affExpr ){
case OE_Rollback: zType = "rollback"; break;
case OE_Abort: zType = "abort"; break;
case OE_Fail: zType = "fail"; break;
@@ -26258,7 +30146,9 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
break;
}
case TK_VECTOR: {
- sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR");
+ char *z = sqlite3_mprintf("VECTOR%s",zFlgs);
+ sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z);
+ sqlite3_free(z);
break;
}
case TK_SELECT_COLUMN: {
@@ -26266,6 +30156,11 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
break;
}
+ case TK_IF_NULL_ROW: {
+ sqlite3TreeViewLine(pView, "IF-NULL-ROW %d", pExpr->iTable);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
+ }
default: {
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
break;
@@ -26277,7 +30172,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
}else if( zUniOp ){
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
- sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
}
sqlite3TreeViewPop(pView);
}
@@ -26299,12 +30194,26 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
- if( j ){
- sqlite3TreeViewPush(pView, 0);
- sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
+ char *zName = pList->a[i].zEName;
+ int moreToFollow = i<pList->nExpr - 1;
+ if( pList->a[i].eEName!=ENAME_NAME ) zName = 0;
+ if( j || zName ){
+ sqlite3TreeViewPush(pView, moreToFollow);
+ moreToFollow = 0;
+ sqlite3TreeViewLine(pView, 0);
+ if( zName ){
+ fprintf(stdout, "AS %s ", zName);
+ }
+ if( j ){
+ fprintf(stdout, "iOrderByCol=%d", j);
+ }
+ fprintf(stdout, "\n");
+ fflush(stdout);
+ }
+ sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
+ if( j || zName ){
+ sqlite3TreeViewPop(pView);
}
- sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
- if( j ) sqlite3TreeViewPop(pView);
}
}
}
@@ -26431,7 +30340,7 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){
sqlite3_mutex_leave(mutex);
}
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
/*
** For testing purposes, we sometimes want to preserve the state of
** PRNG and restore the PRNG to its saved state at a later time, or
@@ -26456,7 +30365,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
sizeof(sqlite3Prng)
);
}
-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+#endif /* SQLITE_UNTESTABLE */
/************** End of random.c **********************************************/
/************** Begin file threads.c *****************************************/
@@ -26529,13 +30438,13 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
memset(p, 0, sizeof(*p));
p->xTask = xTask;
p->pIn = pIn;
- /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
+ /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
** function that returns SQLITE_ERROR when passed the argument 200, that
- ** forces worker threads to run sequentially and deterministically
+ ** forces worker threads to run sequentially and deterministically
** for testing purposes. */
if( sqlite3FaultSim(200) ){
rc = 1;
- }else{
+ }else{
rc = pthread_create(&p->tid, 0, xTask, pIn);
}
if( rc ){
@@ -26617,9 +30526,9 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM_BKPT;
- /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
+ /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
** function that returns SQLITE_ERROR when passed the argument 200, that
- ** forces worker threads to run sequentially and deterministically
+ ** forces worker threads to run sequentially and deterministically
** (via the sqlite3FaultSim() term of the conditional) for testing
** purposes. */
if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){
@@ -26748,7 +30657,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains routines used to translate between UTF-8,
+** This file contains routines used to translate between UTF-8,
** UTF-16, UTF-16BE, and UTF-16LE.
**
** Notes on UTF-8:
@@ -26844,26 +30753,6 @@ static const unsigned char sqlite3Utf8Trans1[] = {
} \
}
-#define READ_UTF16LE(zIn, TERM, c){ \
- c = (*zIn++); \
- c += ((*zIn++)<<8); \
- if( c>=0xD800 && c<0xE000 && TERM ){ \
- int c2 = (*zIn++); \
- c2 += ((*zIn++)<<8); \
- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
- } \
-}
-
-#define READ_UTF16BE(zIn, TERM, c){ \
- c = ((*zIn++)<<8); \
- c += (*zIn++); \
- if( c>=0xD800 && c<0xE000 && TERM ){ \
- int c2 = ((*zIn++)<<8); \
- c2 += (*zIn++); \
- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
- } \
-}
-
/*
** Translate a single UTF-8 character. Return the unicode value.
**
@@ -26929,7 +30818,7 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read(
/*
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
-*/
+*/
/* #define TRANSLATE_TRACE 1 */
#ifndef SQLITE_OMIT_UTF16
@@ -26939,11 +30828,11 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read(
** encoding, or if *pMem does not contain a string value.
*/
SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
- int len; /* Maximum length of output string in bytes */
- unsigned char *zOut; /* Output buffer */
- unsigned char *zIn; /* Input iterator */
- unsigned char *zTerm; /* End of input */
- unsigned char *z; /* Output iterator */
+ sqlite3_int64 len; /* Maximum length of output string in bytes */
+ unsigned char *zOut; /* Output buffer */
+ unsigned char *zIn; /* Input iterator */
+ unsigned char *zTerm; /* End of input */
+ unsigned char *z; /* Output iterator */
unsigned int c;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
@@ -26954,13 +30843,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf);
- fprintf(stderr, "INPUT: %s\n", zBuf);
+ StrAccum acc;
+ char zBuf[1000];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3VdbeMemPrettyPrint(pMem, &acc);
+ fprintf(stderr, "INPUT: %s\n", sqlite3StrAccumFinish(&acc));
}
#endif
- /* If the translation is between UTF-16 little and big endian, then
+ /* If the translation is between UTF-16 little and big endian, then
** all that is required is to swap the byte order. This case is handled
** differently from the others.
*/
@@ -26992,14 +30883,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
** nul-terminator.
*/
pMem->n &= ~1;
- len = pMem->n * 2 + 1;
+ len = 2 * (sqlite3_int64)pMem->n + 1;
}else{
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
** character. Two bytes are required in the output buffer for the
** nul-terminator.
*/
- len = pMem->n * 2 + 2;
+ len = 2 * (sqlite3_int64)pMem->n + 2;
}
/* Set zIn to point at the start of the input buffer and zTerm to point 1
@@ -27038,13 +30929,59 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
if( pMem->enc==SQLITE_UTF16LE ){
/* UTF-16 Little-endian -> UTF-8 */
while( zIn<zTerm ){
- READ_UTF16LE(zIn, zIn<zTerm, c);
+ c = *(zIn++);
+ c += (*(zIn++))<<8;
+ if( c>=0xd800 && c<0xe000 ){
+#ifdef SQLITE_REPLACE_INVALID_UTF
+ if( c>=0xdc00 || zIn>=zTerm ){
+ c = 0xfffd;
+ }else{
+ int c2 = *(zIn++);
+ c2 += (*(zIn++))<<8;
+ if( c2<0xdc00 || c2>=0xe000 ){
+ zIn -= 2;
+ c = 0xfffd;
+ }else{
+ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
+ }
+ }
+#else
+ if( zIn<zTerm ){
+ int c2 = (*zIn++);
+ c2 += ((*zIn++)<<8);
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
+ }
+#endif
+ }
WRITE_UTF8(z, c);
}
}else{
/* UTF-16 Big-endian -> UTF-8 */
while( zIn<zTerm ){
- READ_UTF16BE(zIn, zIn<zTerm, c);
+ c = (*(zIn++))<<8;
+ c += *(zIn++);
+ if( c>=0xd800 && c<0xe000 ){
+#ifdef SQLITE_REPLACE_INVALID_UTF
+ if( c>=0xdc00 || zIn>=zTerm ){
+ c = 0xfffd;
+ }else{
+ int c2 = (*(zIn++))<<8;
+ c2 += *(zIn++);
+ if( c2<0xdc00 || c2>=0xe000 ){
+ zIn -= 2;
+ c = 0xfffd;
+ }else{
+ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
+ }
+ }
+#else
+ if( zIn<zTerm ){
+ int c2 = ((*zIn++)<<8);
+ c2 += (*zIn++);
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
+ }
+#endif
+ }
WRITE_UTF8(z, c);
}
}
@@ -27053,9 +30990,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
*z = 0;
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
- c = pMem->flags;
+ c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype));
sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
+ pMem->flags = c;
pMem->enc = desiredEnc;
pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
@@ -27064,16 +31001,20 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
translate_out:
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
{
- char zBuf[100];
- sqlite3VdbeMemPrettyPrint(pMem, zBuf);
- fprintf(stderr, "OUTPUT: %s\n", zBuf);
+ StrAccum acc;
+ char zBuf[1000];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3VdbeMemPrettyPrint(pMem, &acc);
+ fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc));
}
#endif
return SQLITE_OK;
}
+#endif /* SQLITE_OMIT_UTF16 */
+#ifndef SQLITE_OMIT_UTF16
/*
-** This routine checks for a byte-order mark at the beginning of the
+** This routine checks for a byte-order mark at the beginning of the
** UTF-16 string stored in *pMem. If one is present, it is removed and
** the encoding of the Mem adjusted. This routine does not do any
** byte-swapping, it just sets Mem.enc appropriately.
@@ -27096,7 +31037,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){
bom = SQLITE_UTF16LE;
}
}
-
+
if( bom ){
rc = sqlite3VdbeMemMakeWriteable(pMem);
if( rc==SQLITE_OK ){
@@ -27116,7 +31057,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
** return the number of unicode characters in pZ up to (but not including)
** the first 0x00 byte. If nByte is not less than zero, return the
-** number of unicode characters in the first nByte of pZ (or up to
+** number of unicode characters in the first nByte of pZ (or up to
** the first 0x00, whichever comes first).
*/
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){
@@ -27136,7 +31077,7 @@ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){
return r;
}
-/* This test function is not currently used by the automated test-suite.
+/* This test function is not currently used by the automated test-suite.
** Hence it is only available in debug builds.
*/
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
@@ -27198,19 +31139,16 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
int c;
unsigned char const *z = zIn;
int n = 0;
-
- if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
- while( n<nChar ){
- READ_UTF16BE(z, 1, c);
- n++;
- }
- }else{
- while( n<nChar ){
- READ_UTF16LE(z, 1, c);
- n++;
- }
+
+ if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
+ while( n<nChar ){
+ c = z[0];
+ z += 2;
+ if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
+ n++;
}
- return (int)(z-(unsigned char const *)zIn);
+ return (int)(z-(unsigned char const *)zIn)
+ - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE);
}
#if defined(SQLITE_TEST)
@@ -27240,30 +31178,6 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
assert( c==t );
assert( (z-zBuf)==n );
}
- for(i=0; i<0x00110000; i++){
- if( i>=0xD800 && i<0xE000 ) continue;
- z = zBuf;
- WRITE_UTF16LE(z, i);
- n = (int)(z-zBuf);
- assert( n>0 && n<=4 );
- z[0] = 0;
- z = zBuf;
- READ_UTF16LE(z, 1, c);
- assert( c==i );
- assert( (z-zBuf)==n );
- }
- for(i=0; i<0x00110000; i++){
- if( i>=0xD800 && i<0xE000 ) continue;
- z = zBuf;
- WRITE_UTF16BE(z, i);
- n = (int)(z-zBuf);
- assert( n>0 && n<=4 );
- z[0] = 0;
- z = zBuf;
- READ_UTF16BE(z, 1, c);
- assert( c==i );
- assert( (z-zBuf)==n );
- }
}
#endif /* SQLITE_TEST */
#endif /* SQLITE_OMIT_UTF16 */
@@ -27289,8 +31203,8 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
*/
/* #include "sqliteInt.h" */
/* #include <stdarg.h> */
-#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
-# include <math.h>
+#ifndef SQLITE_OMIT_FLOATING_POINT
+#include <math.h>
#endif
/*
@@ -27304,17 +31218,25 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){
#endif
/*
-** Give a callback to the test harness that can be used to simulate faults
-** in places where it is difficult or expensive to do so purely by means
-** of inputs.
+** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
+** or to bypass normal error detection during testing in order to let
+** execute proceed futher downstream.
+**
+** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The
+** sqlite3FaultSim() function only returns non-zero during testing.
**
-** The intent of the integer argument is to let the fault simulator know
-** which of multiple sqlite3FaultSim() calls has been hit.
+** During testing, if the test harness has set a fault-sim callback using
+** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then
+** each call to sqlite3FaultSim() is relayed to that application-supplied
+** callback and the integer return value form the application-supplied
+** callback is returned by sqlite3FaultSim().
**
-** Return whatever integer value the test callback returns, or return
-** SQLITE_OK if no test callback is installed.
+** The integer argument to sqlite3FaultSim() is a code to identify which
+** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim()
+** should have a unique code. To prevent legacy testing applications from
+** breaking, the codes should not be changed or reused.
*/
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback;
return xCallback ? xCallback(iTest) : SQLITE_OK;
@@ -27324,47 +31246,11 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).
-**
-** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
-** Otherwise, we have our own implementation that works on most systems.
*/
SQLITE_PRIVATE int sqlite3IsNaN(double x){
- int rc; /* The value return */
-#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
- /*
- ** Systems that support the isnan() library function should probably
- ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have
- ** found that many systems do not have a working isnan() function so
- ** this implementation is provided as an alternative.
- **
- ** This NaN test sometimes fails if compiled on GCC with -ffast-math.
- ** On the other hand, the use of -ffast-math comes with the following
- ** warning:
- **
- ** This option [-ffast-math] should never be turned on by any
- ** -O option since it can result in incorrect output for programs
- ** which depend on an exact implementation of IEEE or ISO
- ** rules/specifications for math functions.
- **
- ** Under MSVC, this NaN test may fail if compiled with a floating-
- ** point precision mode other than /fp:precise. From the MSDN
- ** documentation:
- **
- ** The compiler [with /fp:precise] will properly handle comparisons
- ** involving NaN. For example, x != x evaluates to true if x is NaN
- ** ...
- */
-#ifdef __FAST_MATH__
-# error SQLite will not work correctly with the -ffast-math option of GCC.
-#endif
- volatile double y = x;
- volatile double z = y;
- rc = (y!=z);
-#else /* if HAVE_ISNAN */
- rc = isnan(x);
-#endif /* HAVE_ISNAN */
- testcase( rc );
- return rc;
+ u64 y;
+ memcpy(&y,&x,sizeof(y));
+ return IsNaN(y);
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
@@ -27382,7 +31268,7 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
}
/*
-** Return the declared type of a column. Or return zDflt if the column
+** Return the declared type of a column. Or return zDflt if the column
** has no declared type.
**
** The column type is an extra string stored after the zero-terminator on
@@ -27494,10 +31380,24 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
sqlite3DbFree(db, pParse->zErrMsg);
pParse->zErrMsg = zMsg;
pParse->rc = SQLITE_ERROR;
+ pParse->pWith = 0;
}
}
/*
+** If database connection db is currently parsing SQL, then transfer
+** error code errCode to that parser if the parser has not already
+** encountered some other kind of error.
+*/
+SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3 *db, int errCode){
+ Parse *pParse;
+ if( db==0 || (pParse = db->pParse)==0 ) return errCode;
+ pParse->rc = errCode;
+ pParse->nErr++;
+ return errCode;
+}
+
+/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters. The conversion is done in-place. If the
** input does not begin with a quote character, then this routine
@@ -27510,7 +31410,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
** dequoted string, exclusive of the zero terminator, if dequoting does
** occur.
**
-** 2002-Feb-14: This routine is extended to remove MS-Access style
+** 2002-02-14: This routine is extended to remove MS-Access style
** brackets from around identifiers. For example: "[a-b-c]" becomes
** "a-b-c".
*/
@@ -27536,6 +31436,11 @@ SQLITE_PRIVATE void sqlite3Dequote(char *z){
}
z[j] = 0;
}
+SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){
+ assert( sqlite3Isquote(p->u.zToken[0]) );
+ p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted;
+ sqlite3Dequote(p->u.zToken);
+}
/*
** Generate a Token object from a string
@@ -27568,12 +31473,18 @@ SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
}
SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
unsigned char *a, *b;
- int c;
+ int c, x;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
for(;;){
- c = (int)UpperToLower[*a] - (int)UpperToLower[*b];
- if( c || *a==0 ) break;
+ c = *a;
+ x = *b;
+ if( c==x ){
+ if( c==0 ) break;
+ }else{
+ c = (int)UpperToLower[c] - (int)UpperToLower[x];
+ if( c ) break;
+ }
a++;
b++;
}
@@ -27593,6 +31504,58 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
}
/*
+** Compute an 8-bit hash on a string that is insensitive to case differences
+*/
+SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){
+ u8 h = 0;
+ if( z==0 ) return 0;
+ while( z[0] ){
+ h += UpperToLower[(unsigned char)z[0]];
+ z++;
+ }
+ return h;
+}
+
+/*
+** Compute 10 to the E-th power. Examples: E==1 results in 10.
+** E==2 results in 100. E==50 results in 1.0e50.
+**
+** This routine only works for values of E between 1 and 341.
+*/
+static LONGDOUBLE_TYPE sqlite3Pow10(int E){
+#if defined(_MSC_VER)
+ static const LONGDOUBLE_TYPE x[] = {
+ 1.0e+001L,
+ 1.0e+002L,
+ 1.0e+004L,
+ 1.0e+008L,
+ 1.0e+016L,
+ 1.0e+032L,
+ 1.0e+064L,
+ 1.0e+128L,
+ 1.0e+256L
+ };
+ LONGDOUBLE_TYPE r = 1.0;
+ int i;
+ assert( E>=0 && E<=307 );
+ for(i=0; E!=0; i++, E >>=1){
+ if( E & 1 ) r *= x[i];
+ }
+ return r;
+#else
+ LONGDOUBLE_TYPE x = 10.0;
+ LONGDOUBLE_TYPE r = 1.0;
+ while(1){
+ if( E & 1 ) r *= x;
+ E >>= 1;
+ if( E==0 ) break;
+ x *= x;
+ }
+ return r;
+#endif
+}
+
+/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.
**
@@ -27600,8 +31563,15 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
** uses the encoding enc. The string is not necessarily zero-terminated.
**
** Return TRUE if the result is a valid real number (or integer) and FALSE
-** if the string is empty or contains extraneous text. Valid numbers
-** are in one of these formats:
+** if the string is empty or contains extraneous text. More specifically
+** return
+** 1 => The input string is a pure integer
+** 2 or more => The input has a decimal point or eNNN clause
+** 0 or less => The input string is not a valid number
+** -1 => Not a valid number, but has a valid prefix which
+** includes a decimal point and/or an eNNN clause
+**
+** Valid numbers are in one of these formats:
**
** [+-]digits[E[+-]digits]
** [+-]digits.[digits][E[+-]digits]
@@ -27614,10 +31584,13 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
** returns FALSE but it still converts the prefix and writes the result
** into *pResult.
*/
+#if defined(_MSC_VER)
+#pragma warning(disable : 4756)
+#endif
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
int incr;
- const char *zEnd = z + length;
+ const char *zEnd;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
i64 s = 0; /* significand */
@@ -27626,20 +31599,25 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
int e = 0; /* exponent */
int eValid = 1; /* True exponent is either not used or is well-formed */
double result;
- int nDigits = 0;
- int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
+ int nDigit = 0; /* Number of digits processed */
+ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
+ if( length==0 ) return 0;
if( enc==SQLITE_UTF8 ){
incr = 1;
+ zEnd = z + length;
}else{
int i;
incr = 2;
+ length &= ~1;
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+ testcase( enc==SQLITE_UTF16LE );
+ testcase( enc==SQLITE_UTF16BE );
for(i=3-enc; i<length && z[i]==0; i+=2){}
- nonNum = i<length;
+ if( i<length ) eType = -100;
zEnd = &z[i^1];
z += (enc&1);
}
@@ -27657,27 +31635,30 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
}
/* copy max significant digits to significand */
- while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+ while( z<zEnd && sqlite3Isdigit(*z) ){
s = s*10 + (*z - '0');
- z+=incr, nDigits++;
+ z+=incr; nDigit++;
+ if( s>=((LARGEST_INT64-9)/10) ){
+ /* skip non-significant significand digits
+ ** (increase exponent by d to shift decimal left) */
+ while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; d++; }
+ }
}
-
- /* skip non-significant significand digits
- ** (increase exponent by d to shift decimal left) */
- while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
if( z>=zEnd ) goto do_atof_calc;
/* if decimal point is present */
if( *z=='.' ){
z+=incr;
+ eType++;
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
while( z<zEnd && sqlite3Isdigit(*z) ){
if( s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
d--;
+ nDigit++;
}
- z+=incr, nDigits++;
+ z+=incr;
}
}
if( z>=zEnd ) goto do_atof_calc;
@@ -27686,8 +31667,9 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
if( *z=='e' || *z=='E' ){
z+=incr;
eValid = 0;
+ eType++;
- /* This branch is needed to avoid a (harmless) buffer overread. The
+ /* This branch is needed to avoid a (harmless) buffer overread. The
** special comment alerts the mutation tester that the correct answer
** is obtained even if the branch is omitted */
if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/
@@ -27747,11 +31729,10 @@ do_atof_calc:
if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
result = (double)s;
}else{
- LONGDOUBLE_TYPE scale = 1.0;
/* attempt to handle extremely small/large numbers better */
if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+ LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
if( esign<0 ){
result = s / scale;
result /= 1.0e+308;
@@ -27763,14 +31744,15 @@ do_atof_calc:
if( esign<0 ){
result = 0.0*s;
}else{
+#ifdef INFINITY
+ result = INFINITY*s;
+#else
result = 1e308*1e308*s; /* Infinity */
+#endif
}
}
}else{
- /* 1.0e+22 is the largest power of 10 than can be
- ** represented exactly. */
- while( e%22 ) { scale *= 1.0e+1; e -= 1; }
- while( e>0 ) { scale *= 1.0e+22; e -= 22; }
+ LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
if( esign<0 ){
result = s / scale;
}else{
@@ -27784,11 +31766,44 @@ do_atof_calc:
*pResult = result;
/* return true if number and no extra non-whitespace chracters after */
- return z==zEnd && nDigits>0 && eValid && nonNum==0;
+ if( z==zEnd && nDigit>0 && eValid && eType>0 ){
+ return eType;
+ }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){
+ return -1;
+ }else{
+ return 0;
+ }
#else
return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
}
+#if defined(_MSC_VER)
+#pragma warning(default : 4756)
+#endif
+
+/*
+** Render an signed 64-bit integer as text. Store the result in zOut[].
+**
+** The caller must ensure that zOut[] is at least 21 bytes in size.
+*/
+SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){
+ int i;
+ u64 x;
+ char zTemp[22];
+ if( v<0 ){
+ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
+ }else{
+ x = v;
+ }
+ i = sizeof(zTemp)-2;
+ zTemp[sizeof(zTemp)-1] = 0;
+ do{
+ zTemp[i--] = (x%10) + '0';
+ x = x/10;
+ }while( x );
+ if( v<0 ) zTemp[i--] = '-';
+ memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
+}
/*
** Compare the 19-character string zNum against the text representation
@@ -27825,16 +31840,13 @@ static int compare2pow63(const char *zNum, int incr){
** Convert zNum to a 64-bit signed integer. zNum must be decimal. This
** routine does *not* accept hexadecimal notation.
**
-** If the zNum value is representable as a 64-bit twos-complement
-** integer, then write that value into *pNum and return 0.
-**
-** If zNum is exactly 9223372036854775808, return 2. This special
-** case is broken out because while 9223372036854775808 cannot be a
-** signed 64-bit integer, its negative -9223372036854775808 can be.
+** Returns:
**
-** If zNum is too big for a 64-bit integer and is not
-** 9223372036854775808 or if zNum contains any non-numeric text,
-** then return 1.
+** -1 Not even a prefix of the input text looks like an integer
+** 0 Successful transformation. Fits in a 64-bit signed integer.
+** 1 Excess non-space text after the integer value
+** 2 Integer too large for a 64-bit signed integer or is malformed
+** 3 Special case of 9223372036854775808
**
** length is the number of bytes in the string (bytes, not characters).
** The string is not necessarily zero-terminated. The encoding is
@@ -27847,6 +31859,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
int i;
int c = 0;
int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
+ int rc; /* Baseline return code */
const char *zStart;
const char *zEnd = zNum + length;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
@@ -27874,43 +31887,57 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
u = u*10 + c - '0';
}
+ testcase( i==18*incr );
+ testcase( i==19*incr );
+ testcase( i==20*incr );
if( u>LARGEST_INT64 ){
+ /* This test and assignment is needed only to suppress UB warnings
+ ** from clang and -fsanitize=undefined. This test and assignment make
+ ** the code a little larger and slower, and no harm comes from omitting
+ ** them, but we must appaise the undefined-behavior pharisees. */
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
}else{
*pNum = (i64)u;
}
- testcase( i==18 );
- testcase( i==19 );
- testcase( i==20 );
- if( &zNum[i]<zEnd /* Extra bytes at the end */
- || (i==0 && zStart==zNum) /* No digits */
- || i>19*incr /* Too many digits */
- || nonNum /* UTF16 with high-order bytes non-zero */
- ){
- /* zNum is empty or contains non-numeric text or is longer
- ** than 19 digits (thus guaranteeing that it is too large) */
- return 1;
- }else if( i<19*incr ){
+ rc = 0;
+ if( i==0 && zStart==zNum ){ /* No digits */
+ rc = -1;
+ }else if( nonNum ){ /* UTF16 with high-order bytes non-zero */
+ rc = 1;
+ }else if( &zNum[i]<zEnd ){ /* Extra bytes at the end */
+ int jj = i;
+ do{
+ if( !sqlite3Isspace(zNum[jj]) ){
+ rc = 1; /* Extra non-space text after the integer */
+ break;
+ }
+ jj += incr;
+ }while( &zNum[jj]<zEnd );
+ }
+ if( i<19*incr ){
/* Less than 19 digits, so we know that it fits in 64 bits */
assert( u<=LARGEST_INT64 );
- return 0;
+ return rc;
}else{
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
- c = compare2pow63(zNum, incr);
+ c = i>19*incr ? 1 : compare2pow63(zNum, incr);
if( c<0 ){
/* zNum is less than 9223372036854775808 so it fits */
assert( u<=LARGEST_INT64 );
- return 0;
- }else if( c>0 ){
- /* zNum is greater than 9223372036854775808 so it overflows */
- return 1;
+ return rc;
}else{
- /* zNum is exactly 9223372036854775808. Fits if negative. The
- ** special case 2 overflow if positive */
- assert( u-1==LARGEST_INT64 );
- return neg ? 0 : 2;
+ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
+ if( c>0 ){
+ /* zNum is greater than 9223372036854775808 so it overflows */
+ return 2;
+ }else{
+ /* zNum is exactly 9223372036854775808. Fits if negative. The
+ ** special case 2 overflow if positive */
+ assert( u-1==LARGEST_INT64 );
+ return neg ? rc : 3;
+ }
}
}
}
@@ -27923,8 +31950,9 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
** Returns:
**
** 0 Successful transformation. Fits in a 64-bit signed integer.
-** 1 Integer too large for a 64-bit signed integer or is malformed
-** 2 Special case of 9223372036854775808
+** 1 Excess text after the integer value
+** 2 Integer too large for a 64-bit signed integer or is malformed
+** 3 Special case of 9223372036854775808
*/
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
@@ -27938,7 +31966,7 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 1;
+ return (z[k]==0 && k-i<=16) ? 0 : 2;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
@@ -27985,6 +32013,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
}
}
#endif
+ if( !sqlite3Isdigit(zNum[0]) ) return 0;
while( zNum[0]=='0' ) zNum++;
for(i=0; i<11 && (c = zNum[i] - '0')>=0 && c<=9; i++){
v = v*10 + c;
@@ -28016,11 +32045,29 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
*/
SQLITE_PRIVATE int sqlite3Atoi(const char *z){
int x = 0;
- if( z ) sqlite3GetInt32(z, &x);
+ sqlite3GetInt32(z, &x);
return x;
}
/*
+** Try to convert z into an unsigned 32-bit integer. Return true on
+** success and false if there is an error.
+**
+** Only decimal notation is accepted.
+*/
+SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){
+ u64 v = 0;
+ int i;
+ for(i=0; sqlite3Isdigit(z[i]); i++){
+ v = v*10 + z[i] - '0';
+ if( v>4294967296LL ){ *pI = 0; return 0; }
+ }
+ if( i==0 || z[i]!=0 ){ *pI = 0; return 0; }
+ *pI = (u32)v;
+ return 1;
+}
+
+/*
** The variable-length integer encoding is as follows:
**
** KEY:
@@ -28060,7 +32107,7 @@ static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){
v >>= 7;
}
return 9;
- }
+ }
n = 0;
do{
buf[n++] = (u8)((v & 0x7f) | 0x80);
@@ -28106,23 +32153,12 @@ SQLITE_PRIVATE int sqlite3PutVarint(unsigned char *p, u64 v){
SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
u32 a,b,s;
- a = *p;
- /* a: p0 (unmasked) */
- if (!(a&0x80))
- {
- *v = a;
+ if( ((signed char*)p)[0]>=0 ){
+ *v = *p;
return 1;
}
-
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- a &= 0x7f;
- a = a<<7;
- a |= b;
- *v = a;
+ if( ((signed char*)p)[1]>=0 ){
+ *v = ((u32)(p[0]&0x7f)<<7) | p[1];
return 2;
}
@@ -28130,8 +32166,9 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
- p++;
- a = a<<14;
+ a = ((u32)p[0])<<14;
+ b = p[1];
+ p += 2;
a |= *p;
/* a: p0<<14 | p2 (unmasked) */
if (!(a&0x80))
@@ -28270,8 +32307,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned
** integer, then set *v to 0xffffffff.
**
-** A MACRO version, getVarint32, is provided which inlines the
-** single-byte case. All code should use the MACRO version as
+** A MACRO version, getVarint32, is provided which inlines the
+** single-byte case. All code should use the MACRO version as
** this function assumes the single-byte case has already been handled.
*/
SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
@@ -28332,8 +32369,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
u64 v64;
u8 n;
- p -= 2;
- n = sqlite3GetVarint(p, &v64);
+ n = sqlite3GetVarint(p-2, &v64);
assert( n>3 && n<=9 );
if( (v64 & SQLITE_MAX_U32)!=v64 ){
*v = 0xffffffff;
@@ -28412,13 +32448,11 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
u32 x;
memcpy(&x,p,4);
return x;
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(__GNUC__) && GCC_VERSION>=4003000
+#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
u32 x;
memcpy(&x,p,4);
return __builtin_bswap32(x);
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(_MSC_VER) && _MSC_VER>=1300
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
u32 x;
memcpy(&x,p,4);
return _byteswap_ulong(x);
@@ -28430,12 +32464,10 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
#if SQLITE_BYTEORDER==4321
memcpy(p,&v,4);
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(__GNUC__) && GCC_VERSION>=4003000
+#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
u32 x = __builtin_bswap32(v);
memcpy(p,&x,4);
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(_MSC_VER) && _MSC_VER>=1300
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
u32 x = _byteswap_ulong(v);
memcpy(p,&x,4);
#else
@@ -28464,7 +32496,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){
return (u8)(h & 0xf);
}
-#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
+#if !defined(SQLITE_OMIT_BLOB_LITERAL)
/*
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
** value. Return a pointer to its binary value. Space to hold the
@@ -28485,7 +32517,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
}
return zBlob;
}
-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
+#endif /* !SQLITE_OMIT_BLOB_LITERAL */
/*
** Log an error that is an API call on a connection pointer that should
@@ -28493,7 +32525,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
** argument. The zType is a word like "NULL" or "closed" or "invalid".
*/
static void logBadConnection(const char *zType){
- sqlite3_log(SQLITE_MISUSE,
+ sqlite3_log(SQLITE_MISUSE,
"API call with %s database connection pointer",
zType
);
@@ -28551,6 +32583,9 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
** overflow, leave *pA unchanged and return 1.
*/
SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
+ return __builtin_add_overflow(*pA, iB, pA);
+#else
i64 iA = *pA;
testcase( iA==0 ); testcase( iA==1 );
testcase( iB==-1 ); testcase( iB==0 );
@@ -28564,9 +32599,13 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
}
*pA += iB;
- return 0;
+ return 0;
+#endif
}
SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
+ return __builtin_sub_overflow(*pA, iB, pA);
+#else
testcase( iB==SMALLEST_INT64+1 );
if( iB==SMALLEST_INT64 ){
testcase( (*pA)==(-1) ); testcase( (*pA)==0 );
@@ -28576,8 +32615,12 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
}else{
return sqlite3AddInt64(pA, -iB);
}
+#endif
}
SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
+#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER)
+ return __builtin_mul_overflow(*pA, iB, pA);
+#else
i64 iA = *pA;
if( iB>0 ){
if( iA>LARGEST_INT64/iB ) return 1;
@@ -28593,10 +32636,11 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
}
*pA = iA*iB;
return 0;
+#endif
}
/*
-** Compute the absolute value of a 32-bit signed integer, of possible. Or
+** Compute the absolute value of a 32-bit signed integer, of possible. Or
** if the integer has a value of -2147483648, return +2147483647
*/
SQLITE_PRIVATE int sqlite3AbsInt32(int x){
@@ -28636,11 +32680,11 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
}
#endif
-/*
+/*
** Find (an approximate) sum of two LogEst values. This computation is
** not a simple "+" operator because LogEst is stored as a logarithmic
** value.
-**
+**
*/
SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
static const unsigned char x[] = {
@@ -28676,8 +32720,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
+#if GCC_VERSION>=5004000
+ int i = 60 - __builtin_clzll(x);
+ y += i*10;
+ x >>= i;
+#else
while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/
while( x>15 ){ y += 10; x >>= 1; }
+#endif
}
return a[x&7] + y - 10;
}
@@ -28700,7 +32750,7 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
- defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
+ defined(SQLITE_ENABLE_STAT4) || \
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
/*
** Convert a LogEst into an integer.
@@ -28718,7 +32768,7 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
if( x>60 ) return (u64)LARGEST_INT64;
#else
- /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
+ /* If only SQLITE_ENABLE_STAT4 is on, then the largest input
** possible to this routine is 310, resulting in a maximum x of 31 */
assert( x<=60 );
#endif
@@ -28726,6 +32776,109 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
}
#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
+/*
+** Add a new name/number pair to a VList. This might require that the
+** VList object be reallocated, so return the new VList. If an OOM
+** error occurs, the original VList returned and the
+** db->mallocFailed flag is set.
+**
+** A VList is really just an array of integers. To destroy a VList,
+** simply pass it to sqlite3DbFree().
+**
+** The first integer is the number of integers allocated for the whole
+** VList. The second integer is the number of integers actually used.
+** Each name/number pair is encoded by subsequent groups of 3 or more
+** integers.
+**
+** Each name/number pair starts with two integers which are the numeric
+** value for the pair and the size of the name/number pair, respectively.
+** The text name overlays one or more following integers. The text name
+** is always zero-terminated.
+**
+** Conceptually:
+**
+** struct VList {
+** int nAlloc; // Number of allocated slots
+** int nUsed; // Number of used slots
+** struct VListEntry {
+** int iValue; // Value for this entry
+** int nSlot; // Slots used by this entry
+** // ... variable name goes here
+** } a[0];
+** }
+**
+** During code generation, pointers to the variable names within the
+** VList are taken. When that happens, nAlloc is set to zero as an
+** indication that the VList may never again be enlarged, since the
+** accompanying realloc() would invalidate the pointers.
+*/
+SQLITE_PRIVATE VList *sqlite3VListAdd(
+ sqlite3 *db, /* The database connection used for malloc() */
+ VList *pIn, /* The input VList. Might be NULL */
+ const char *zName, /* Name of symbol to add */
+ int nName, /* Bytes of text in zName */
+ int iVal /* Value to associate with zName */
+){
+ int nInt; /* number of sizeof(int) objects needed for zName */
+ char *z; /* Pointer to where zName will be stored */
+ int i; /* Index in pIn[] where zName is stored */
+
+ nInt = nName/4 + 3;
+ assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */
+ if( pIn==0 || pIn[1]+nInt > pIn[0] ){
+ /* Enlarge the allocation */
+ sqlite3_int64 nAlloc = (pIn ? 2*(sqlite3_int64)pIn[0] : 10) + nInt;
+ VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int));
+ if( pOut==0 ) return pIn;
+ if( pIn==0 ) pOut[1] = 2;
+ pIn = pOut;
+ pIn[0] = nAlloc;
+ }
+ i = pIn[1];
+ pIn[i] = iVal;
+ pIn[i+1] = nInt;
+ z = (char*)&pIn[i+2];
+ pIn[1] = i+nInt;
+ assert( pIn[1]<=pIn[0] );
+ memcpy(z, zName, nName);
+ z[nName] = 0;
+ return pIn;
+}
+
+/*
+** Return a pointer to the name of a variable in the given VList that
+** has the value iVal. Or return a NULL if there is no such variable in
+** the list
+*/
+SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){
+ int i, mx;
+ if( pIn==0 ) return 0;
+ mx = pIn[1];
+ i = 2;
+ do{
+ if( pIn[i]==iVal ) return (char*)&pIn[i+2];
+ i += pIn[i+1];
+ }while( i<mx );
+ return 0;
+}
+
+/*
+** Return the number of the variable named zName, if it is in VList.
+** or return 0 if there is no such variable.
+*/
+SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nName){
+ int i, mx;
+ if( pIn==0 ) return 0;
+ mx = pIn[1];
+ i = 2;
+ do{
+ const char *z = (const char*)&pIn[i+2];
+ if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i];
+ i += pIn[i+1];
+ }while( i<mx );
+ return 0;
+}
+
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
/*
@@ -28846,7 +32999,7 @@ static int rehash(Hash *pH, unsigned int new_size){
/* The inability to allocates space for a larger hash table is
** a performance hit but it is not a fatal error. So mark the
- ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of
+ ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of
** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero()
** only zeroes the requested number of bytes whereas this module will
** use the actual amount of space allocated for the hash table (which
@@ -28870,8 +33023,9 @@ static int rehash(Hash *pH, unsigned int new_size){
}
/* This function (for internal use only) locates an element in an
-** hash table that matches the given key. The hash for this key is
-** also computed and returned in the *pH parameter.
+** hash table that matches the given key. If no element is found,
+** a pointer to a static null element with HashElem.data==0 is returned.
+** If pH is not NULL, then the hash for this key is written to *pH.
*/
static HashElem *findElementWithHash(
const Hash *pH, /* The pH to be searched */
@@ -28879,8 +33033,9 @@ static HashElem *findElementWithHash(
unsigned int *pHash /* Write the hash value here */
){
HashElem *elem; /* Used to loop thru the element list */
- int count; /* Number of elements left to test */
+ unsigned int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
+ static HashElem nullElement = { 0, 0, 0, 0 };
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
struct _ht *pEntry;
@@ -28893,15 +33048,15 @@ static HashElem *findElementWithHash(
elem = pH->first;
count = pH->count;
}
- *pHash = h;
+ if( pHash ) *pHash = h;
while( count-- ){
assert( elem!=0 );
- if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
+ if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
}
- return 0;
+ return &nullElement;
}
/* Remove a single entry from the hash table given a pointer to that
@@ -28914,7 +33069,7 @@ static void removeElementGivenHash(
){
struct _ht *pEntry;
if( elem->prev ){
- elem->prev->next = elem->next;
+ elem->prev->next = elem->next;
}else{
pH->first = elem->next;
}
@@ -28926,8 +33081,8 @@ static void removeElementGivenHash(
if( pEntry->chain==elem ){
pEntry->chain = elem->next;
}
+ assert( pEntry->count>0 );
pEntry->count--;
- assert( pEntry->count>=0 );
}
sqlite3_free( elem );
pH->count--;
@@ -28943,13 +33098,9 @@ static void removeElementGivenHash(
** found, or NULL if there is no match.
*/
SQLITE_PRIVATE void *sqlite3HashFind(const Hash *pH, const char *pKey){
- HashElem *elem; /* The element that matches key */
- unsigned int h; /* A hash on key */
-
assert( pH!=0 );
assert( pKey!=0 );
- elem = findElementWithHash(pH, pKey, &h);
- return elem ? elem->data : 0;
+ return findElementWithHash(pH, pKey, 0)->data;
}
/* Insert an element into the hash table pH. The key is pKey
@@ -28974,7 +33125,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
assert( pH!=0 );
assert( pKey!=0 );
elem = findElementWithHash(pH,pKey,&h);
- if( elem ){
+ if( elem->data ){
void *old_data = elem->data;
if( data==0 ){
removeElementGivenHash(pH,elem,h);
@@ -29018,165 +33169,178 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 1 */ "AutoCommit" OpHelp(""),
/* 2 */ "Transaction" OpHelp(""),
/* 3 */ "SorterNext" OpHelp(""),
- /* 4 */ "PrevIfOpen" OpHelp(""),
- /* 5 */ "NextIfOpen" OpHelp(""),
- /* 6 */ "Prev" OpHelp(""),
- /* 7 */ "Next" OpHelp(""),
- /* 8 */ "Checkpoint" OpHelp(""),
- /* 9 */ "JournalMode" OpHelp(""),
- /* 10 */ "Vacuum" OpHelp(""),
- /* 11 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
- /* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"),
- /* 13 */ "Goto" OpHelp(""),
- /* 14 */ "Gosub" OpHelp(""),
- /* 15 */ "InitCoroutine" OpHelp(""),
- /* 16 */ "Yield" OpHelp(""),
- /* 17 */ "MustBeInt" OpHelp(""),
- /* 18 */ "Jump" OpHelp(""),
+ /* 4 */ "Prev" OpHelp(""),
+ /* 5 */ "Next" OpHelp(""),
+ /* 6 */ "Checkpoint" OpHelp(""),
+ /* 7 */ "JournalMode" OpHelp(""),
+ /* 8 */ "Vacuum" OpHelp(""),
+ /* 9 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
+ /* 10 */ "VUpdate" OpHelp("data=r[P3@P2]"),
+ /* 11 */ "Goto" OpHelp(""),
+ /* 12 */ "Gosub" OpHelp(""),
+ /* 13 */ "InitCoroutine" OpHelp(""),
+ /* 14 */ "Yield" OpHelp(""),
+ /* 15 */ "MustBeInt" OpHelp(""),
+ /* 16 */ "Jump" OpHelp(""),
+ /* 17 */ "Once" OpHelp(""),
+ /* 18 */ "If" OpHelp(""),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "Once" OpHelp(""),
- /* 21 */ "If" OpHelp(""),
- /* 22 */ "IfNot" OpHelp(""),
- /* 23 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 24 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 25 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 26 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
- /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 31 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 32 */ "SeekRowid" OpHelp("intkey=r[P3]"),
- /* 33 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 36 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
- /* 37 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
- /* 38 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
- /* 39 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
- /* 40 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
- /* 41 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
- /* 42 */ "ElseNotEq" OpHelp(""),
- /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
- /* 46 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
- /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 53 */ "Last" OpHelp(""),
- /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
- /* 55 */ "SorterSort" OpHelp(""),
- /* 56 */ "Sort" OpHelp(""),
- /* 57 */ "Rewind" OpHelp(""),
- /* 58 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 59 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 60 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 61 */ "IdxGE" OpHelp("key=r[P3@P4]"),
- /* 62 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 63 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 64 */ "Program" OpHelp(""),
- /* 65 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 66 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
- /* 67 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"),
- /* 68 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 69 */ "IncrVacuum" OpHelp(""),
- /* 70 */ "VNext" OpHelp(""),
- /* 71 */ "Init" OpHelp("Start at P2"),
- /* 72 */ "Return" OpHelp(""),
- /* 73 */ "EndCoroutine" OpHelp(""),
- /* 74 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
- /* 75 */ "Halt" OpHelp(""),
- /* 76 */ "Integer" OpHelp("r[P2]=P1"),
- /* 77 */ "Int64" OpHelp("r[P2]=P4"),
- /* 78 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
- /* 79 */ "Null" OpHelp("r[P2..P3]=NULL"),
- /* 80 */ "SoftNull" OpHelp("r[P1]=NULL"),
- /* 81 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 82 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
- /* 83 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
- /* 84 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
- /* 85 */ "SCopy" OpHelp("r[P2]=r[P1]"),
- /* 86 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
- /* 87 */ "ResultRow" OpHelp("output=r[P1@P2]"),
- /* 88 */ "CollSeq" OpHelp(""),
- /* 89 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 90 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 91 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
- /* 92 */ "RealAffinity" OpHelp(""),
- /* 93 */ "Cast" OpHelp("affinity(r[P1])"),
- /* 94 */ "Permutation" OpHelp(""),
- /* 95 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
- /* 96 */ "Column" OpHelp("r[P3]=PX"),
- /* 97 */ "String8" OpHelp("r[P2]='P4'"),
- /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
- /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
- /* 100 */ "Count" OpHelp("r[P2]=count()"),
- /* 101 */ "ReadCookie" OpHelp(""),
- /* 102 */ "SetCookie" OpHelp(""),
- /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
- /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 106 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 107 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 108 */ "SorterOpen" OpHelp(""),
- /* 109 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
- /* 110 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 111 */ "Close" OpHelp(""),
- /* 112 */ "ColumnsUsed" OpHelp(""),
- /* 113 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 114 */ "NewRowid" OpHelp("r[P2]=rowid"),
- /* 115 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
- /* 116 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 117 */ "Delete" OpHelp(""),
- /* 118 */ "ResetCount" OpHelp(""),
- /* 119 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
- /* 120 */ "SorterData" OpHelp("r[P2]=data"),
- /* 121 */ "RowKey" OpHelp("r[P2]=key"),
- /* 122 */ "RowData" OpHelp("r[P2]=data"),
- /* 123 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 124 */ "NullRow" OpHelp(""),
- /* 125 */ "SorterInsert" OpHelp(""),
- /* 126 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 127 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
- /* 128 */ "Seek" OpHelp("Move P3 to P1.rowid"),
- /* 129 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 130 */ "Destroy" OpHelp(""),
- /* 131 */ "Clear" OpHelp(""),
- /* 132 */ "Real" OpHelp("r[P2]=P4"),
- /* 133 */ "ResetSorter" OpHelp(""),
- /* 134 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 135 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
- /* 136 */ "ParseSchema" OpHelp(""),
- /* 137 */ "LoadAnalysis" OpHelp(""),
- /* 138 */ "DropTable" OpHelp(""),
- /* 139 */ "DropIndex" OpHelp(""),
- /* 140 */ "DropTrigger" OpHelp(""),
- /* 141 */ "IntegrityCk" OpHelp(""),
- /* 142 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 143 */ "Param" OpHelp(""),
- /* 144 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 145 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 146 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
- /* 147 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 148 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 149 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 150 */ "Expire" OpHelp(""),
- /* 151 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 152 */ "VBegin" OpHelp(""),
- /* 153 */ "VCreate" OpHelp(""),
- /* 154 */ "VDestroy" OpHelp(""),
- /* 155 */ "VOpen" OpHelp(""),
- /* 156 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 157 */ "VRename" OpHelp(""),
- /* 158 */ "Pagecount" OpHelp(""),
- /* 159 */ "MaxPgcnt" OpHelp(""),
- /* 160 */ "CursorHint" OpHelp(""),
- /* 161 */ "Noop" OpHelp(""),
- /* 162 */ "Explain" OpHelp(""),
+ /* 20 */ "IfNot" OpHelp(""),
+ /* 21 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 22 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 23 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 24 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 25 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 26 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
+ /* 27 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
+ /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 30 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"),
+ /* 32 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 33 */ "Last" OpHelp(""),
+ /* 34 */ "IfSmaller" OpHelp(""),
+ /* 35 */ "SorterSort" OpHelp(""),
+ /* 36 */ "Sort" OpHelp(""),
+ /* 37 */ "Rewind" OpHelp(""),
+ /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"),
+ /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
+ /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
+ /* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 46 */ "Program" OpHelp(""),
+ /* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
+ /* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+ /* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
+ /* 53 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 54 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
+ /* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
+ /* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
+ /* 58 */ "ElseNotEq" OpHelp(""),
+ /* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 60 */ "IncrVacuum" OpHelp(""),
+ /* 61 */ "VNext" OpHelp(""),
+ /* 62 */ "Init" OpHelp("Start at P2"),
+ /* 63 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
+ /* 64 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
+ /* 65 */ "Return" OpHelp(""),
+ /* 66 */ "EndCoroutine" OpHelp(""),
+ /* 67 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
+ /* 68 */ "Halt" OpHelp(""),
+ /* 69 */ "Integer" OpHelp("r[P2]=P1"),
+ /* 70 */ "Int64" OpHelp("r[P2]=P4"),
+ /* 71 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
+ /* 72 */ "Null" OpHelp("r[P2..P3]=NULL"),
+ /* 73 */ "SoftNull" OpHelp("r[P1]=NULL"),
+ /* 74 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
+ /* 75 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 76 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
+ /* 77 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
+ /* 78 */ "SCopy" OpHelp("r[P2]=r[P1]"),
+ /* 79 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
+ /* 80 */ "ResultRow" OpHelp("output=r[P1@P2]"),
+ /* 81 */ "CollSeq" OpHelp(""),
+ /* 82 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
+ /* 83 */ "RealAffinity" OpHelp(""),
+ /* 84 */ "Cast" OpHelp("affinity(r[P1])"),
+ /* 85 */ "Permutation" OpHelp(""),
+ /* 86 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
+ /* 87 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
+ /* 88 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"),
+ /* 89 */ "Column" OpHelp("r[P3]=PX"),
+ /* 90 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
+ /* 91 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
+ /* 92 */ "Count" OpHelp("r[P2]=count()"),
+ /* 93 */ "ReadCookie" OpHelp(""),
+ /* 94 */ "SetCookie" OpHelp(""),
+ /* 95 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
+ /* 96 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 97 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
+ /* 98 */ "OpenDup" OpHelp(""),
+ /* 99 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 100 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 101 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 102 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 103 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
+ /* 104 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
+ /* 105 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 106 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 107 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 108 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 109 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 110 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
+ /* 111 */ "SorterOpen" OpHelp(""),
+ /* 112 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
+ /* 113 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
+ /* 114 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 115 */ "String8" OpHelp("r[P2]='P4'"),
+ /* 116 */ "Close" OpHelp(""),
+ /* 117 */ "ColumnsUsed" OpHelp(""),
+ /* 118 */ "SeekHit" OpHelp("seekHit=P2"),
+ /* 119 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 120 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 121 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 122 */ "Delete" OpHelp(""),
+ /* 123 */ "ResetCount" OpHelp(""),
+ /* 124 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 125 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 126 */ "RowData" OpHelp("r[P2]=data"),
+ /* 127 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 128 */ "NullRow" OpHelp(""),
+ /* 129 */ "SeekEnd" OpHelp(""),
+ /* 130 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 131 */ "SorterInsert" OpHelp("key=r[P2]"),
+ /* 132 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
+ /* 133 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
+ /* 134 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 135 */ "FinishSeek" OpHelp(""),
+ /* 136 */ "Destroy" OpHelp(""),
+ /* 137 */ "Clear" OpHelp(""),
+ /* 138 */ "ResetSorter" OpHelp(""),
+ /* 139 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"),
+ /* 140 */ "SqlExec" OpHelp(""),
+ /* 141 */ "ParseSchema" OpHelp(""),
+ /* 142 */ "LoadAnalysis" OpHelp(""),
+ /* 143 */ "DropTable" OpHelp(""),
+ /* 144 */ "DropIndex" OpHelp(""),
+ /* 145 */ "DropTrigger" OpHelp(""),
+ /* 146 */ "IntegrityCk" OpHelp(""),
+ /* 147 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 148 */ "Param" OpHelp(""),
+ /* 149 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 150 */ "Real" OpHelp("r[P2]=P4"),
+ /* 151 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 152 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+ /* 153 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"),
+ /* 154 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 155 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 156 */ "AggValue" OpHelp("r[P3]=value N=P2"),
+ /* 157 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 158 */ "Expire" OpHelp(""),
+ /* 159 */ "CursorLock" OpHelp(""),
+ /* 160 */ "CursorUnlock" OpHelp(""),
+ /* 161 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 162 */ "VBegin" OpHelp(""),
+ /* 163 */ "VCreate" OpHelp(""),
+ /* 164 */ "VDestroy" OpHelp(""),
+ /* 165 */ "VOpen" OpHelp(""),
+ /* 166 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 167 */ "VRename" OpHelp(""),
+ /* 168 */ "Pagecount" OpHelp(""),
+ /* 169 */ "MaxPgcnt" OpHelp(""),
+ /* 170 */ "Trace" OpHelp(""),
+ /* 171 */ "CursorHint" OpHelp(""),
+ /* 172 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
+ /* 173 */ "Noop" OpHelp(""),
+ /* 174 */ "Explain" OpHelp(""),
+ /* 175 */ "Abortable" OpHelp(""),
};
return azName[i];
}
@@ -29247,7 +33411,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE
** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic
** selection of the appropriate locking style based on the filesystem
-** where the database is located.
+** where the database is located.
*/
#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
# if defined(__APPLE__)
@@ -29276,6 +33440,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
#include <unistd.h>
/* #include <time.h> */
#include <sys/time.h>
@@ -29285,18 +33450,34 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
-# include <sys/ioctl.h>
+/* # include <sys/ioctl.h> */
# include <sys/file.h>
# include <sys/param.h>
#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-#if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
- (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
-# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
- && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
-# define HAVE_GETHOSTUUID 1
-# else
-# warning "gethostuuid() is disabled."
+/*
+** Try to determine if gethostuuid() is available based on standard
+** macros. This might sometimes compute the wrong value for some
+** obscure platforms. For those cases, simply compile with one of
+** the following:
+**
+** -DHAVE_GETHOSTUUID=0
+** -DHAVE_GETHOSTUUID=1
+**
+** None if this matters except when building on Apple products with
+** -DSQLITE_ENABLE_LOCKING_STYLE.
+*/
+#ifndef HAVE_GETHOSTUUID
+# define HAVE_GETHOSTUUID 0
+# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
+ (__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
+# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
+ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
+# undef HAVE_GETHOSTUUID
+# define HAVE_GETHOSTUUID 1
+# else
+# warning "gethostuuid() is disabled."
+# endif
# endif
#endif
@@ -29321,12 +33502,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#define SQLITE_FSFLAGS_IS_MSDOS 0x1
/*
-** If we are to be thread-safe, include the pthreads header and define
-** the SQLITE_UNIX_THREADS macro.
+** If we are to be thread-safe, include the pthreads header.
*/
#if SQLITE_THREADSAFE
/* # include <pthread.h> */
-# define SQLITE_UNIX_THREADS 1
#endif
/*
@@ -29358,7 +33537,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#define osGetpid(X) (pid_t)getpid()
/*
-** Only set the lastErrno if the error code is a real error and not
+** Only set the lastErrno if the error code is a real error and not
** a normal expected return code of SQLITE_BUSY or SQLITE_OK
*/
#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
@@ -29395,7 +33574,7 @@ struct unixFile {
unsigned short int ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */
- UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
+ UnixUnusedFd *pPreallocatedUnused; /* Pre-allocated UnixUnusedFd */
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
@@ -29406,16 +33585,17 @@ struct unixFile {
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
#endif
-#ifdef __QNXNTO__
int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */
-#endif
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
unsigned fsFlags; /* cached details from statfs() */
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ unsigned iBusyTimeout; /* Wait this many millisec on locks */
+#endif
#if OS_VXWORKS
struct vxworksFileId *pId; /* Unique file ID */
#endif
@@ -29425,7 +33605,7 @@ struct unixFile {
** whenever any part of the database changes. An assertion fault will
** occur if a file is updated without also updating the transaction
** counter. This test is made to avoid new problems similar to the
- ** one described by ticket #3584.
+ ** one described by ticket #3584.
*/
unsigned char transCntrChng; /* True if the transaction counter changed */
unsigned char dbUpdate; /* True if any part of database file changed */
@@ -29434,7 +33614,7 @@ struct unixFile {
#endif
#ifdef SQLITE_TEST
- /* In test mode, increase the size of this structure a bit so that
+ /* In test mode, increase the size of this structure a bit so that
** it is larger than the struct CrashFile defined in test6.c.
*/
char aPadding[32];
@@ -29524,7 +33704,7 @@ static pid_t randomnessPid = 0;
******************************************************************************
**
** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 class CPUs.
+** counters for x86 and x86_64 class CPUs.
*/
#ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H
@@ -29535,8 +33715,9 @@ static pid_t randomnessPid = 0;
** processor and returns that value. This can be used for high-res
** profiling.
*/
-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
@@ -29557,15 +33738,15 @@ static pid_t randomnessPid = 0;
#endif
-#elif (defined(__GNUC__) && defined(__x86_64__))
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
-#elif (defined(__GNUC__) && defined(__ppc__))
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
@@ -29582,14 +33763,13 @@ static pid_t randomnessPid = 0;
#else
- #error Need implementation of sqlite3Hwtime() for your platform.
-
/*
- ** To compile without implementing sqlite3Hwtime() for your platform,
- ** you can remove the above #error and use the following
- ** stub function. You will lose timing support for many
- ** of the debugging and testing utilities, but it should at
- ** least compile and run.
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlite3Hwtime() routine.
+ **
+ ** sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
*/
SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
@@ -29712,6 +33892,20 @@ SQLITE_API extern int sqlite3_open_file_count;
# define lseek lseek64
#endif
+#ifdef __linux__
+/*
+** Linux-specific IOCTL magic numbers used for controlling F2FS
+*/
+#define F2FS_IOCTL_MAGIC 0xf5
+#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
+#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
+#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
+#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
+#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
+#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
+#endif /* __linux__ */
+
+
/*
** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...).
@@ -29763,7 +33957,7 @@ static struct unix_syscall {
#ifdef __DJGPP__
{ "fstat", 0, 0 },
#define osFstat(a,b,c) 0
-#else
+#else
{ "fstat", (sqlite3_syscall_ptr)fstat, 0 },
#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
#endif
@@ -29839,7 +34033,11 @@ static struct unix_syscall {
#endif
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
+#if defined(HAVE_FCHOWN)
{ "geteuid", (sqlite3_syscall_ptr)geteuid, 0 },
+#else
+ { "geteuid", (sqlite3_syscall_ptr)0, 0 },
+#endif
#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
@@ -29854,7 +34052,7 @@ static struct unix_syscall {
#else
{ "munmap", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
+#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent)
#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
@@ -29884,6 +34082,18 @@ static struct unix_syscall {
#endif
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+# ifdef __ANDROID__
+ { "ioctl", (sqlite3_syscall_ptr)(int(*)(int, int, ...))ioctl, 0 },
+#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
+# else
+ { "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
+#define osIoctl ((int(*)(int,unsigned long,...))aSyscall[28].pCurrent)
+# endif
+#else
+ { "ioctl", (sqlite3_syscall_ptr)0, 0 },
+#endif
+
}; /* End of the overrideable system calls */
@@ -29985,7 +34195,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
/*
** Do not accept any file descriptor less than this value, in order to avoid
-** opening database file using file descriptors that are commonly used for
+** opening database file using file descriptors that are commonly used for
** standard input, output, and error.
*/
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
@@ -30024,17 +34234,17 @@ static int robust_open(const char *z, int f, mode_t m){
}
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
osClose(fd);
- sqlite3_log(SQLITE_WARNING,
+ sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z, fd);
fd = -1;
- if( osOpen("/dev/null", f, m)<0 ) break;
+ if( osOpen("/dev/null", O_RDONLY, m)<0 ) break;
}
if( fd>=0 ){
if( m!=0 ){
struct stat statbuf;
- if( osFstat(fd, &statbuf)==0
+ if( osFstat(fd, &statbuf)==0
&& statbuf.st_size==0
- && (statbuf.st_mode&0777)!=m
+ && (statbuf.st_mode&0777)!=m
){
osFchmod(fd, m);
}
@@ -30049,26 +34259,40 @@ static int robust_open(const char *z, int f, mode_t m){
/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the unixInodeInfo and
-** vxworksFileId objects used by this file, all of which may be
+** vxworksFileId objects used by this file, all of which may be
** shared by multiple threads.
**
-** Function unixMutexHeld() is used to assert() that the global mutex
-** is held when required. This function is only used as part of assert()
+** Function unixMutexHeld() is used to assert() that the global mutex
+** is held when required. This function is only used as part of assert()
** statements. e.g.
**
** unixEnterMutex()
** assert( unixMutexHeld() );
** unixEnterLeave()
+**
+** To prevent deadlock, the global unixBigLock must must be acquired
+** before the unixInodeInfo.pLockMutex mutex, if both are held. It is
+** OK to get the pLockMutex without holding unixBigLock first, but if
+** that happens, the unixBigLock mutex must not be acquired until after
+** pLockMutex is released.
+**
+** OK: enter(unixBigLock), enter(pLockInfo)
+** OK: enter(unixBigLock)
+** OK: enter(pLockInfo)
+** ERROR: enter(pLockInfo), enter(unixBigLock)
*/
+static sqlite3_mutex *unixBigLock = 0;
static void unixEnterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ assert( sqlite3_mutex_notheld(unixBigLock) ); /* Not a recursive mutex */
+ sqlite3_mutex_enter(unixBigLock);
}
static void unixLeaveMutex(void){
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ assert( sqlite3_mutex_held(unixBigLock) );
+ sqlite3_mutex_leave(unixBigLock);
}
#ifdef SQLITE_DEBUG
static int unixMutexHeld(void) {
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ return sqlite3_mutex_held(unixBigLock);
}
#endif
@@ -30161,7 +34385,7 @@ static int lockTrace(int fd, int op, struct flock *p){
static int robust_ftruncate(int h, sqlite3_int64 sz){
int rc;
#ifdef __ANDROID__
- /* On Android, ftruncate() always uses 32-bit offsets, even if
+ /* On Android, ftruncate() always uses 32-bit offsets, even if
** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to
** truncate a file to any size larger than 2GiB. Silently ignore any
** such attempts. */
@@ -30177,32 +34401,32 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
** This routine translates a standard POSIX errno code into something
** useful to the clients of the sqlite3 functions. Specifically, it is
** intended to translate a variety of "try again" errors into SQLITE_BUSY
-** and a variety of "please close the file descriptor NOW" errors into
+** and a variety of "please close the file descriptor NOW" errors into
** SQLITE_IOERR
-**
+**
** Errors during initialization of locks, or file system support for locks,
** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
*/
static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
- assert( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
+ assert( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
+ (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
(sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) );
switch (posixError) {
- case EACCES:
+ case EACCES:
case EAGAIN:
case ETIMEDOUT:
case EBUSY:
case EINTR:
- case ENOLCK:
- /* random NFS retry error, unless during file system support
+ case ENOLCK:
+ /* random NFS retry error, unless during file system support
* introspection, in which it actually means what it says */
return SQLITE_BUSY;
-
- case EPERM:
+
+ case EPERM:
return SQLITE_PERM;
-
- default:
+
+ default:
return sqliteIOErr;
}
}
@@ -30217,7 +34441,7 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
**
** A pointer to an instance of the following structure can be used as a
** unique file ID in VxWorks. Each instance of this structure contains
-** a copy of the canonical filename. There is also a reference count.
+** a copy of the canonical filename. There is also a reference count.
** The structure is reclaimed when the number of pointers to it drops to
** zero.
**
@@ -30233,7 +34457,7 @@ struct vxworksFileId {
};
#if OS_VXWORKS
-/*
+/*
** All unique filenames are held on a linked list headed by this
** variable:
*/
@@ -30305,7 +34529,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){
*/
unixEnterMutex();
for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){
- if( pCandidate->nName==n
+ if( pCandidate->nName==n
&& memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0
){
sqlite3_free(pNew);
@@ -30398,7 +34622,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** cnt>0 means there are cnt shared locks on the file.
**
** Any attempt to lock or unlock a file first checks the locking
-** structure. The fcntl() system call is only invoked to set a
+** structure. The fcntl() system call is only invoked to set a
** POSIX lock if the internal lock structure transitions between
** a locked and an unlocked state.
**
@@ -30431,7 +34655,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
**
** SQLite used to support LinuxThreads. But support for LinuxThreads
** was dropped beginning with version 3.7.0. SQLite will still work with
-** LinuxThreads provided that (1) there is no more than one connection
+** LinuxThreads provided that (1) there is no more than one connection
** per database file in the same process and (2) database connections
** do not move across threads.
*/
@@ -30445,28 +34669,52 @@ struct unixFileId {
#if OS_VXWORKS
struct vxworksFileId *pId; /* Unique file ID for vxworks. */
#else
- ino_t ino; /* Inode number */
+ /* We are told that some versions of Android contain a bug that
+ ** sizes ino_t at only 32-bits instead of 64-bits. (See
+ ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c)
+ ** To work around this, always allocate 64-bits for the inode number.
+ ** On small machines that only have 32-bit inodes, this wastes 4 bytes,
+ ** but that should not be a big deal. */
+ /* WAS: ino_t ino; */
+ u64 ino; /* Inode number */
#endif
};
/*
** An instance of the following structure is allocated for each open
-** inode. Or, on LinuxThreads, there is one of these structures for
-** each inode opened by each thread.
+** inode.
**
** A single inode can have multiple file descriptors, so each unixFile
** structure contains a pointer to an instance of this object and this
** object keeps a count of the number of unixFile pointing to it.
+**
+** Mutex rules:
+**
+** (1) Only the pLockMutex mutex must be held in order to read or write
+** any of the locking fields:
+** nShared, nLock, eFileLock, bProcessLock, pUnused
+**
+** (2) When nRef>0, then the following fields are unchanging and can
+** be read (but not written) without holding any mutex:
+** fileId, pLockMutex
+**
+** (3) With the exceptions above, all the fields may only be read
+** or written while holding the global unixBigLock mutex.
+**
+** Deadlock prevention: The global unixBigLock mutex may not
+** be acquired while holding the pLockMutex mutex. If both unixBigLock
+** and pLockMutex are needed, then unixBigLock must be acquired first.
*/
struct unixInodeInfo {
struct unixFileId fileId; /* The lookup key */
- int nShared; /* Number of SHARED locks held */
- unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
- unsigned char bProcessLock; /* An exclusive process lock is held */
+ sqlite3_mutex *pLockMutex; /* Hold this mutex for... */
+ int nShared; /* Number of SHARED locks held */
+ int nLock; /* Number of outstanding file locks */
+ unsigned char eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */
+ unsigned char bProcessLock; /* An exclusive process lock is held */
+ UnixUnusedFd *pUnused; /* Unused file descriptors to close */
int nRef; /* Number of pointers to this structure */
unixShmNode *pShmNode; /* Shared memory associated with this inode */
- int nLock; /* Number of outstanding file locks */
- UnixUnusedFd *pUnused; /* Unused file descriptors to close */
unixInodeInfo *pNext; /* List of all unixInodeInfo objects */
unixInodeInfo *pPrev; /* .... doubly linked */
#if SQLITE_ENABLE_LOCKING_STYLE
@@ -30480,8 +34728,26 @@ struct unixInodeInfo {
/*
** A lists of all unixInodeInfo objects.
+**
+** Must hold unixBigLock in order to read or write this variable.
+*/
+static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */
+
+#ifdef SQLITE_DEBUG
+/*
+** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not.
+** This routine is used only within assert() to help verify correct mutex
+** usage.
*/
-static unixInodeInfo *inodeList = 0;
+int unixFileMutexHeld(unixFile *pFile){
+ assert( pFile->pInode );
+ return sqlite3_mutex_held(pFile->pInode->pLockMutex);
+}
+int unixFileMutexNotheld(unixFile *pFile){
+ assert( pFile->pInode );
+ return sqlite3_mutex_notheld(pFile->pInode->pLockMutex);
+}
+#endif
/*
**
@@ -30494,7 +34760,7 @@ static unixInodeInfo *inodeList = 0;
** strerror_r().
**
** 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).
+** 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 (e.g. "unlink", "open") and the associated file-system path,
** if any.
@@ -30512,7 +34778,7 @@ static int unixLogErrorAtLine(
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
** the strerror() function to obtain the human-readable error message
** equivalent to errno. Otherwise, use strerror_r().
- */
+ */
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
char aErr[80];
memset(aErr, 0, sizeof(aErr));
@@ -30520,18 +34786,18 @@ static int unixLogErrorAtLine(
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
** assume that the system provides the GNU version of strerror_r() that
- ** returns a pointer to a buffer containing the error message. That pointer
- ** may point to aErr[], or it may point to some static storage somewhere.
- ** Otherwise, assume that the system provides the POSIX version of
+ ** returns a pointer to a buffer containing the error message. That pointer
+ ** may point to aErr[], or it may point to some static storage somewhere.
+ ** Otherwise, assume that the system provides the POSIX version of
** strerror_r(), which always writes an error message into aErr[].
**
** If the code incorrectly assumes that it is the POSIX version that is
** available, the error message will often be an empty string. Not a
- ** huge problem. Incorrectly concluding that the GNU version is available
+ ** huge problem. Incorrectly concluding that the GNU version is available
** could lead to a segfault though.
*/
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
- zErr =
+ zErr =
# endif
strerror_r(iErrno, aErr, sizeof(aErr)-1);
@@ -30582,11 +34848,12 @@ static void storeLastErrno(unixFile *pFile, int error){
/*
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
-*/
+*/
static void closePendingFds(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
UnixUnusedFd *p;
UnixUnusedFd *pNext;
+ assert( unixFileMutexHeld(pFile) );
for(p=pInode->pUnused; p; p=pNext){
pNext = p->pNext;
robust_close(pFile, p->fd, __LINE__);
@@ -30598,17 +34865,20 @@ static void closePendingFds(unixFile *pFile){
/*
** Release a unixInodeInfo structure previously allocated by findInodeInfo().
**
-** The mutex entered using the unixEnterMutex() function must be held
-** when this function is called.
+** The global mutex must be held when this routine is called, but the mutex
+** on the inode being deleted must NOT be held.
*/
static void releaseInodeInfo(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
assert( unixMutexHeld() );
+ assert( unixFileMutexNotheld(pFile) );
if( ALWAYS(pInode) ){
pInode->nRef--;
if( pInode->nRef==0 ){
assert( pInode->pShmNode==0 );
+ sqlite3_mutex_enter(pInode->pLockMutex);
closePendingFds(pFile);
+ sqlite3_mutex_leave(pInode->pLockMutex);
if( pInode->pPrev ){
assert( pInode->pPrev->pNext==pInode );
pInode->pPrev->pNext = pInode->pNext;
@@ -30620,6 +34890,7 @@ static void releaseInodeInfo(unixFile *pFile){
assert( pInode->pNext->pPrev==pInode );
pInode->pNext->pPrev = pInode->pPrev;
}
+ sqlite3_mutex_free(pInode->pLockMutex);
sqlite3_free(pInode);
}
}
@@ -30630,8 +34901,7 @@ static void releaseInodeInfo(unixFile *pFile){
** describes that file descriptor. Create a new one if necessary. The
** return value might be uninitialized if an error occurs.
**
-** The mutex entered using the unixEnterMutex() function must be held
-** when this function is called.
+** The global mutex must held when calling this routine.
**
** Return an appropriate error code.
*/
@@ -30690,8 +34960,9 @@ static int findInodeInfo(
#if OS_VXWORKS
fileId.pId = pFile->pId;
#else
- fileId.ino = statbuf.st_ino;
+ fileId.ino = (u64)statbuf.st_ino;
#endif
+ assert( unixMutexHeld() );
pInode = inodeList;
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
pInode = pInode->pNext;
@@ -30703,7 +34974,15 @@ static int findInodeInfo(
}
memset(pInode, 0, sizeof(*pInode));
memcpy(&pInode->fileId, &fileId, sizeof(fileId));
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ pInode->pLockMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pInode->pLockMutex==0 ){
+ sqlite3_free(pInode);
+ return SQLITE_NOMEM_BKPT;
+ }
+ }
pInode->nRef = 1;
+ assert( unixMutexHeld() );
pInode->pNext = inodeList;
pInode->pPrev = 0;
if( inodeList ) inodeList->pPrev = pInode;
@@ -30724,7 +35003,8 @@ static int fileHasMoved(unixFile *pFile){
#else
struct stat buf;
return pFile->pInode!=0 &&
- (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
+ (osStat(pFile->zPath, &buf)!=0
+ || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
#endif
}
@@ -30780,7 +35060,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
assert( pFile );
assert( pFile->eFileLock<=SHARED_LOCK );
- unixEnterMutex(); /* Because pFile->pInode is shared across threads */
+ sqlite3_mutex_enter(pFile->pInode->pLockMutex);
/* Check if a thread in this process holds such a lock */
if( pFile->pInode->eFileLock>SHARED_LOCK ){
@@ -30804,8 +35084,8 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
}
}
#endif
-
- unixLeaveMutex();
+
+ sqlite3_mutex_leave(pFile->pInode->pLockMutex);
OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
*pResOut = reserved;
@@ -30813,7 +35093,45 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
}
/*
-** Attempt to set a system-lock on the file pFile. The lock is
+** Set a posix-advisory-lock.
+**
+** There are two versions of this routine. If compiled with
+** SQLITE_ENABLE_SETLK_TIMEOUT then the routine has an extra parameter
+** which is a pointer to a unixFile. If the unixFile->iBusyTimeout
+** value is set, then it is the number of milliseconds to wait before
+** failing the lock. The iBusyTimeout value is always reset back to
+** zero on each call.
+**
+** If SQLITE_ENABLE_SETLK_TIMEOUT is not defined, then do a non-blocking
+** attempt to set the lock.
+*/
+#ifndef SQLITE_ENABLE_SETLK_TIMEOUT
+# define osSetPosixAdvisoryLock(h,x,t) osFcntl(h,F_SETLK,x)
+#else
+static int osSetPosixAdvisoryLock(
+ int h, /* The file descriptor on which to take the lock */
+ struct flock *pLock, /* The description of the lock */
+ unixFile *pFile /* Structure holding timeout value */
+){
+ int tm = pFile->iBusyTimeout;
+ int rc = osFcntl(h,F_SETLK,pLock);
+ while( rc<0 && tm>0 ){
+ /* On systems that support some kind of blocking file lock with a timeout,
+ ** make appropriate changes here to invoke that blocking file lock. On
+ ** generic posix, however, there is no such API. So we simply try the
+ ** lock once every millisecond until either the timeout expires, or until
+ ** the lock is obtained. */
+ usleep(1000);
+ rc = osFcntl(h,F_SETLK,pLock);
+ tm--;
+ }
+ return rc;
+}
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
+
+
+/*
+** Attempt to set a system-lock on the file pFile. The lock is
** described by pLock.
**
** If the pFile was opened read/write from unix-excl, then the only lock
@@ -30834,8 +35152,8 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
static int unixFileLock(unixFile *pFile, struct flock *pLock){
int rc;
unixInodeInfo *pInode = pFile->pInode;
- assert( unixMutexHeld() );
assert( pInode!=0 );
+ assert( sqlite3_mutex_held(pInode->pLockMutex) );
if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
if( pInode->bProcessLock==0 ){
struct flock lock;
@@ -30844,7 +35162,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
lock.l_type = F_WRLCK;
- rc = osFcntl(pFile->h, F_SETLK, &lock);
+ rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile);
if( rc<0 ) return rc;
pInode->bProcessLock = 1;
pInode->nLock++;
@@ -30852,7 +35170,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
rc = 0;
}
}else{
- rc = osFcntl(pFile->h, F_SETLK, pLock);
+ rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile);
}
return rc;
}
@@ -30905,7 +35223,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
**
** A process may only obtain a RESERVED lock after it has a SHARED lock.
** A RESERVED lock is implemented by grabbing a write-lock on the
- ** 'reserved byte'.
+ ** 'reserved byte'.
**
** A process may only obtain a PENDING lock after it has obtained a
** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
@@ -30919,7 +35237,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** implemented by obtaining a write-lock on the entire 'shared byte
** range'. Since all other locks require a read-lock on one of the bytes
** within this range, this ensures that no other locks are held on the
- ** database.
+ ** database.
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -30954,13 +35272,13 @@ static int unixLock(sqlite3_file *id, int eFileLock){
/* This mutex is needed because pFile->pInode is shared across threads
*/
- unixEnterMutex();
pInode = pFile->pInode;
+ sqlite3_mutex_enter(pInode->pLockMutex);
/* If some thread using this PID has a lock via a different unixFile*
** handle that precludes the requested lock, return BUSY.
*/
- if( (pFile->eFileLock!=pInode->eFileLock &&
+ if( (pFile->eFileLock!=pInode->eFileLock &&
(pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
){
rc = SQLITE_BUSY;
@@ -30971,7 +35289,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** has a SHARED or RESERVED lock, then increment reference counts and
** return SQLITE_OK.
*/
- if( eFileLock==SHARED_LOCK &&
+ if( eFileLock==SHARED_LOCK &&
(pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
assert( eFileLock==SHARED_LOCK );
assert( pFile->eFileLock==0 );
@@ -30989,7 +35307,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
*/
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
- if( eFileLock==SHARED_LOCK
+ if( eFileLock==SHARED_LOCK
|| (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
){
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
@@ -31028,7 +35346,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
/* This could happen with a network mount */
tErrno = errno;
- rc = SQLITE_IOERR_UNLOCK;
+ rc = SQLITE_IOERR_UNLOCK;
}
if( rc ){
@@ -31070,7 +35388,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
}
}
}
-
+
#ifdef SQLITE_DEBUG
/* Set up the transaction-counter change checking flags when
@@ -31098,8 +35416,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){
}
end_lock:
- unixLeaveMutex();
- OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
@@ -31110,11 +35428,12 @@ end_lock:
*/
static void setPendingFd(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
- UnixUnusedFd *p = pFile->pUnused;
+ UnixUnusedFd *p = pFile->pPreallocatedUnused;
+ assert( unixFileMutexHeld(pFile) );
p->pNext = pInode->pUnused;
pInode->pUnused = p;
pFile->h = -1;
- pFile->pUnused = 0;
+ pFile->pPreallocatedUnused = 0;
}
/*
@@ -31123,11 +35442,11 @@ static void setPendingFd(unixFile *pFile){
**
** If the locking level of the file descriptor is already at or below
** the requested locking level, this routine is a no-op.
-**
+**
** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
** the byte range is divided into 2 parts and the first part is unlocked then
-** set to a read lock, then the other part is simply unlocked. This works
-** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
+** set to a read lock, then the other part is simply unlocked. This works
+** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
** remove the write lock on a region when a read lock is set.
*/
static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
@@ -31145,8 +35464,8 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- unixEnterMutex();
pInode = pFile->pInode;
+ sqlite3_mutex_enter(pInode->pLockMutex);
assert( pInode->nShared!=0 );
if( pFile->eFileLock>SHARED_LOCK ){
assert( pInode->eFileLock==pFile->eFileLock );
@@ -31165,7 +35484,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
/* downgrading to a shared lock on NFS involves clearing the write lock
** before establishing the readlock - to avoid a race condition we downgrade
- ** the lock in 2 blocks, so that part of the range will be covered by a
+ ** the lock in 2 blocks, so that part of the range will be covered by a
** write lock until the rest is covered by a read lock:
** 1: [WWWWW]
** 2: [....W]
@@ -31181,7 +35500,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
if( handleNFSUnlock ){
int tErrno; /* Error code from system call errors */
off_t divSize = SHARED_SIZE - 1;
-
+
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
@@ -31223,11 +35542,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
lock.l_len = SHARED_SIZE;
if( unixFileLock(pFile, &lock) ){
/* In theory, the call to unixFileLock() cannot fail because another
- ** process is holding an incompatible lock. If it does, this
+ ** process is holding an incompatible lock. If it does, this
** indicates that the other process is not following the locking
** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
- ** SQLITE_BUSY would confuse the upper layer (in practice it causes
- ** an assert to fail). */
+ ** SQLITE_BUSY would confuse the upper layer (in practice it causes
+ ** an assert to fail). */
rc = SQLITE_IOERR_RDLOCK;
storeLastErrno(pFile, errno);
goto end_unlock;
@@ -31272,14 +35591,14 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
*/
pInode->nLock--;
assert( pInode->nLock>=0 );
- if( pInode->nLock==0 ){
- closePendingFds(pFile);
- }
+ if( pInode->nLock==0 ) closePendingFds(pFile);
}
end_unlock:
- unixLeaveMutex();
- if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ if( rc==SQLITE_OK ){
+ pFile->eFileLock = eFileLock;
+ }
return rc;
}
@@ -31303,7 +35622,7 @@ static void unixUnmapfile(unixFile *pFd);
#endif
/*
-** This function performs the parts of the "close file" operation
+** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file
** handles, if they are valid, and sets all fields of the unixFile
** structure to 0.
@@ -31339,7 +35658,7 @@ static int closeUnixFile(sqlite3_file *id){
#endif
OSTRACE(("CLOSE %-3d\n", pFile->h));
OpenCounter(-1);
- sqlite3_free(pFile->pUnused);
+ sqlite3_free(pFile->pPreallocatedUnused);
memset(pFile, 0, sizeof(unixFile));
return SQLITE_OK;
}
@@ -31350,22 +35669,28 @@ static int closeUnixFile(sqlite3_file *id){
static int unixClose(sqlite3_file *id){
int rc = SQLITE_OK;
unixFile *pFile = (unixFile *)id;
+ unixInodeInfo *pInode = pFile->pInode;
+
+ assert( pInode!=0 );
verifyDbFile(pFile);
unixUnlock(id, NO_LOCK);
+ assert( unixFileMutexNotheld(pFile) );
unixEnterMutex();
/* unixFile.pInode is always valid here. Otherwise, a different close
** routine (e.g. nolockClose()) would be called instead.
*/
assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
- if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){
+ sqlite3_mutex_enter(pInode->pLockMutex);
+ if( pInode->nLock ){
/* If there are outstanding locks, do not actually close the file just
** yet because that would clear those locks. Instead, add the file
- ** descriptor to pInode->pUnused list. It will be automatically closed
+ ** descriptor to pInode->pUnused list. It will be automatically closed
** when the last lock is cleared.
*/
setPendingFd(pFile);
}
+ sqlite3_mutex_leave(pInode->pLockMutex);
releaseInodeInfo(pFile);
rc = closeUnixFile(id);
unixLeaveMutex();
@@ -31460,7 +35785,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
unixFile *pFile = (unixFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
-
+
assert( pFile );
reserved = osAccess((const char*)pFile->lockingContext, 0)==0;
OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
@@ -31514,7 +35839,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
#endif
return SQLITE_OK;
}
-
+
/* grab an exclusive lock */
rc = osMkdir(zLockFile, 0777);
if( rc<0 ){
@@ -31529,8 +35854,8 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
}
}
return rc;
- }
-
+ }
+
/* got it, set the type and return ok */
pFile->eFileLock = eFileLock;
return rc;
@@ -31554,7 +35879,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
-
+
/* no-op if possible */
if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
@@ -31567,7 +35892,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
pFile->eFileLock = SHARED_LOCK;
return SQLITE_OK;
}
-
+
/* To fully unlock the database, delete the lock file */
assert( eFileLock==NO_LOCK );
rc = osRmdir(zLockFile);
@@ -31579,7 +35904,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
rc = SQLITE_IOERR_UNLOCK;
storeLastErrno(pFile, tErrno);
}
- return rc;
+ return rc;
}
pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
@@ -31626,7 +35951,7 @@ static int robust_flock(int fd, int op){
#else
# define robust_flock(a,b) flock(a,b)
#endif
-
+
/*
** This routine checks if there is a RESERVED lock held on the specified
@@ -31638,16 +35963,16 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
int rc = SQLITE_OK;
int reserved = 0;
unixFile *pFile = (unixFile*)id;
-
+
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
-
+
assert( pFile );
-
+
/* Check if a thread in this process holds such a lock */
if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
-
+
/* Otherwise see if some other process holds it. */
if( !reserved ){
/* attempt to get the lock */
@@ -31658,7 +35983,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
if ( lrc ) {
int tErrno = errno;
/* unlock failed with an error */
- lrc = SQLITE_IOERR_UNLOCK;
+ lrc = SQLITE_IOERR_UNLOCK;
storeLastErrno(pFile, tErrno);
rc = lrc;
}
@@ -31666,7 +35991,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
int tErrno = errno;
reserved = 1;
/* someone else might have it reserved */
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
+ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
if( IS_LOCK_ERROR(lrc) ){
storeLastErrno(pFile, tErrno);
rc = lrc;
@@ -31676,7 +36001,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
OSTRACE(("TEST WR-LOCK %d %d %d (flock)\n", pFile->h, rc, reserved));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
+ if( (rc & 0xff) == SQLITE_IOERR ){
rc = SQLITE_OK;
reserved=1;
}
@@ -31720,15 +36045,15 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
assert( pFile );
- /* if we already have a lock, it is exclusive.
+ /* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
if (pFile->eFileLock > NO_LOCK) {
pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
-
+
/* grab an exclusive lock */
-
+
if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
int tErrno = errno;
/* didn't get, must be busy */
@@ -31740,10 +36065,10 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
/* got it, set the type and return ok */
pFile->eFileLock = eFileLock;
}
- OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
+ OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
rc==SQLITE_OK ? "ok" : "failed"));
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
- if( (rc & SQLITE_IOERR) == SQLITE_IOERR ){
+ if( (rc & 0xff) == SQLITE_IOERR ){
rc = SQLITE_BUSY;
}
#endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */
@@ -31760,23 +36085,23 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
*/
static int flockUnlock(sqlite3_file *id, int eFileLock) {
unixFile *pFile = (unixFile*)id;
-
+
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
-
+
/* no-op if possible */
if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
-
+
/* shared can just be set because we always have an exclusive */
if (eFileLock==SHARED_LOCK) {
pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
-
+
/* no, really, unlock. */
if( robust_flock(pFile->h, LOCK_UN) ){
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
@@ -31827,14 +36152,14 @@ static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) {
unixFile *pFile = (unixFile*)id;
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
-
+
assert( pFile );
/* Check if a thread in this process holds such a lock */
if( pFile->eFileLock>SHARED_LOCK ){
reserved = 1;
}
-
+
/* Otherwise see if some other process holds it. */
if( !reserved ){
sem_t *pSem = pFile->pInode->pSem;
@@ -31893,14 +36218,14 @@ static int semXLock(sqlite3_file *id, int eFileLock) {
sem_t *pSem = pFile->pInode->pSem;
int rc = SQLITE_OK;
- /* if we already have a lock, it is exclusive.
+ /* if we already have a lock, it is exclusive.
** Just adjust level and punt on outta here. */
if (pFile->eFileLock > NO_LOCK) {
pFile->eFileLock = eFileLock;
rc = SQLITE_OK;
goto sem_end_lock;
}
-
+
/* lock semaphore now but bail out when already locked. */
if( sem_trywait(pSem)==-1 ){
rc = SQLITE_BUSY;
@@ -31930,18 +36255,18 @@ static int semXUnlock(sqlite3_file *id, int eFileLock) {
OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
pFile->eFileLock, osGetpid(0)));
assert( eFileLock<=SHARED_LOCK );
-
+
/* no-op if possible */
if( pFile->eFileLock==eFileLock ){
return SQLITE_OK;
}
-
+
/* shared can just be set because we always have an exclusive */
if (eFileLock==SHARED_LOCK) {
pFile->eFileLock = eFileLock;
return SQLITE_OK;
}
-
+
/* no, really unlock. */
if ( sem_post(pSem)==-1 ) {
int rc, tErrno = errno;
@@ -31949,7 +36274,7 @@ static int semXUnlock(sqlite3_file *id, int eFileLock) {
if( IS_LOCK_ERROR(rc) ){
storeLastErrno(pFile, tErrno);
}
- return rc;
+ return rc;
}
pFile->eFileLock = NO_LOCK;
return SQLITE_OK;
@@ -31963,6 +36288,7 @@ static int semXClose(sqlite3_file *id) {
unixFile *pFile = (unixFile*)id;
semXUnlock(id, NO_LOCK);
assert( pFile );
+ assert( unixFileMutexNotheld(pFile) );
unixEnterMutex();
releaseInodeInfo(pFile);
unixLeaveMutex();
@@ -32014,7 +36340,7 @@ struct ByteRangeLockPB2
/*
** This is a utility for setting or clearing a bit-range lock on an
** AFP filesystem.
-**
+**
** Return SQLITE_OK on success, SQLITE_BUSY on failure.
*/
static int afpSetLock(
@@ -32026,14 +36352,14 @@ static int afpSetLock(
){
struct ByteRangeLockPB2 pb;
int err;
-
+
pb.unLockFlag = setLockFlag ? 0 : 1;
pb.startEndFlag = 0;
pb.offset = offset;
- pb.length = length;
+ pb.length = length;
pb.fd = pFile->h;
-
- OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
+
+ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
(setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
offset, length));
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
@@ -32068,27 +36394,26 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
int reserved = 0;
unixFile *pFile = (unixFile*)id;
afpLockingContext *context;
-
+
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
-
+
assert( pFile );
context = (afpLockingContext *) pFile->lockingContext;
if( context->reserved ){
*pResOut = 1;
return SQLITE_OK;
}
- unixEnterMutex(); /* Because pFile->pInode is shared across threads */
-
+ sqlite3_mutex_enter(pFile->pInode->pLockMutex);
/* Check if a thread in this process holds such a lock */
if( pFile->pInode->eFileLock>SHARED_LOCK ){
reserved = 1;
}
-
+
/* Otherwise see if some other process holds it.
*/
if( !reserved ){
/* lock the RESERVED byte */
- int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
+ int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
if( SQLITE_OK==lrc ){
/* if we succeeded in taking the reserved lock, unlock it to restore
** the original state */
@@ -32101,10 +36426,10 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
rc=lrc;
}
}
-
- unixLeaveMutex();
+
+ sqlite3_mutex_leave(pFile->pInode->pLockMutex);
OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
-
+
*pResOut = reserved;
return rc;
}
@@ -32138,7 +36463,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
unixFile *pFile = (unixFile*)id;
unixInodeInfo *pInode = pFile->pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
-
+
assert( pFile );
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
@@ -32162,27 +36487,27 @@ static int afpLock(sqlite3_file *id, int eFileLock){
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
assert( eFileLock!=PENDING_LOCK );
assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
-
+
/* This mutex is needed because pFile->pInode is shared across threads
*/
- unixEnterMutex();
pInode = pFile->pInode;
+ sqlite3_mutex_enter(pInode->pLockMutex);
/* If some thread using this PID has a lock via a different unixFile*
** handle that precludes the requested lock, return BUSY.
*/
- if( (pFile->eFileLock!=pInode->eFileLock &&
+ if( (pFile->eFileLock!=pInode->eFileLock &&
(pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
){
rc = SQLITE_BUSY;
goto afp_end_lock;
}
-
+
/* If a SHARED lock is requested, and some thread using this PID already
** has a SHARED or RESERVED lock, then increment reference counts and
** return SQLITE_OK.
*/
- if( eFileLock==SHARED_LOCK &&
+ if( eFileLock==SHARED_LOCK &&
(pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
assert( eFileLock==SHARED_LOCK );
assert( pFile->eFileLock==0 );
@@ -32192,12 +36517,12 @@ static int afpLock(sqlite3_file *id, int eFileLock){
pInode->nLock++;
goto afp_end_lock;
}
-
+
/* A PENDING lock is needed before acquiring a SHARED lock and before
** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
** be released.
*/
- if( eFileLock==SHARED_LOCK
+ if( eFileLock==SHARED_LOCK
|| (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
){
int failed;
@@ -32207,30 +36532,30 @@ static int afpLock(sqlite3_file *id, int eFileLock){
goto afp_end_lock;
}
}
-
+
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
if( eFileLock==SHARED_LOCK ){
int lrc1, lrc2, lrc1Errno = 0;
long lk, mask;
-
+
assert( pInode->nShared==0 );
assert( pInode->eFileLock==0 );
-
+
mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff;
/* Now get the read-lock SHARED_LOCK */
/* note that the quality of the randomness doesn't matter that much */
- lk = random();
+ lk = random();
pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
- lrc1 = afpSetLock(context->dbPath, pFile,
+ lrc1 = afpSetLock(context->dbPath, pFile,
SHARED_FIRST+pInode->sharedByte, 1, 1);
if( IS_LOCK_ERROR(lrc1) ){
lrc1Errno = pFile->lastErrno;
}
/* Drop the temporary PENDING lock */
lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
-
+
if( IS_LOCK_ERROR(lrc1) ) {
storeLastErrno(pFile, lrc1Errno);
rc = lrc1;
@@ -32265,34 +36590,34 @@ static int afpLock(sqlite3_file *id, int eFileLock){
}
if (!failed && eFileLock == EXCLUSIVE_LOCK) {
/* Acquire an EXCLUSIVE lock */
-
- /* Remove the shared lock before trying the range. we'll need to
+
+ /* Remove the shared lock before trying the range. we'll need to
** reestablish the shared lock if we can't get the afpUnlock
*/
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
/* now attemmpt to get the exclusive lock range */
- failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
+ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
- if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
+ if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
SHARED_FIRST + pInode->sharedByte, 1, 1)) ){
/* Can't reestablish the shared lock. Sqlite can't deal, this is
** a critical I/O error
*/
- rc = ((failed & SQLITE_IOERR) == SQLITE_IOERR) ? failed2 :
+ rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 :
SQLITE_IOERR_LOCK;
goto afp_end_lock;
- }
+ }
}else{
- rc = failed;
+ rc = failed;
}
}
if( failed ){
rc = failed;
}
}
-
+
if( rc==SQLITE_OK ){
pFile->eFileLock = eFileLock;
pInode->eFileLock = eFileLock;
@@ -32300,10 +36625,10 @@ static int afpLock(sqlite3_file *id, int eFileLock){
pFile->eFileLock = PENDING_LOCK;
pInode->eFileLock = PENDING_LOCK;
}
-
+
afp_end_lock:
- unixLeaveMutex();
- OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
rc==SQLITE_OK ? "ok" : "failed"));
return rc;
}
@@ -32334,15 +36659,15 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
if( pFile->eFileLock<=eFileLock ){
return SQLITE_OK;
}
- unixEnterMutex();
pInode = pFile->pInode;
+ sqlite3_mutex_enter(pInode->pLockMutex);
assert( pInode->nShared!=0 );
if( pFile->eFileLock>SHARED_LOCK ){
assert( pInode->eFileLock==pFile->eFileLock );
SimulateIOErrorBenign(1);
SimulateIOError( h=(-1) )
SimulateIOErrorBenign(0);
-
+
#ifdef SQLITE_DEBUG
/* When reducing a lock such that other processes can start
** reading the database file again, make sure that the
@@ -32357,7 +36682,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|| pFile->transCntrChng==1 );
pFile->inNormalWrite = 0;
#endif
-
+
if( pFile->eFileLock==EXCLUSIVE_LOCK ){
rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
@@ -32370,11 +36695,11 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
}
if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
- }
+ }
if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){
rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
- if( !rc ){
- context->reserved = 0;
+ if( !rc ){
+ context->reserved = 0;
}
}
if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
@@ -32404,33 +36729,39 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
if( rc==SQLITE_OK ){
pInode->nLock--;
assert( pInode->nLock>=0 );
- if( pInode->nLock==0 ){
- closePendingFds(pFile);
- }
+ if( pInode->nLock==0 ) closePendingFds(pFile);
}
}
-
- unixLeaveMutex();
- if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
+
+ sqlite3_mutex_leave(pInode->pLockMutex);
+ if( rc==SQLITE_OK ){
+ pFile->eFileLock = eFileLock;
+ }
return rc;
}
/*
-** Close a file & cleanup AFP specific locking context
+** Close a file & cleanup AFP specific locking context
*/
static int afpClose(sqlite3_file *id) {
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
assert( id!=0 );
afpUnlock(id, NO_LOCK);
+ assert( unixFileMutexNotheld(pFile) );
unixEnterMutex();
- if( pFile->pInode && pFile->pInode->nLock ){
- /* If there are outstanding locks, do not actually close the file just
- ** yet because that would clear those locks. Instead, add the file
- ** descriptor to pInode->aPending. It will be automatically closed when
- ** the last lock is cleared.
- */
- setPendingFd(pFile);
+ if( pFile->pInode ){
+ unixInodeInfo *pInode = pFile->pInode;
+ sqlite3_mutex_enter(pInode->pLockMutex);
+ if( pInode->nLock ){
+ /* If there are outstanding locks, do not actually close the file just
+ ** yet because that would clear those locks. Instead, add the file
+ ** descriptor to pInode->aPending. It will be automatically closed when
+ ** the last lock is cleared.
+ */
+ setPendingFd(pFile);
+ }
+ sqlite3_mutex_leave(pInode->pLockMutex);
}
releaseInodeInfo(pFile);
sqlite3_free(pFile->lockingContext);
@@ -32468,7 +36799,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
/*
** The code above is the NFS lock implementation. The code is specific
** to MacOSX and does not work on other unix platforms. No alternative
-** is available.
+** is available.
**
********************* End of the NFS lock implementation **********************
******************************************************************************/
@@ -32476,7 +36807,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
/******************************************************************************
**************** Non-locking sqlite3_file methods *****************************
**
-** The next division contains implementations for all methods of the
+** The next division contains implementations for all methods of the
** sqlite3_file object other than the locking methods. The locking
** methods were defined in divisions above (one locking method per
** division). Those methods that are common to all locking modes
@@ -32484,7 +36815,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
*/
/*
-** Seek to the offset passed as the second argument, then read cnt
+** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
** NB: If you define USE_PREAD or USE_PREAD64, then it might also
@@ -32546,8 +36877,8 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
** wrong.
*/
static int unixRead(
- sqlite3_file *id,
- void *pBuf,
+ sqlite3_file *id,
+ void *pBuf,
int amt,
sqlite3_int64 offset
){
@@ -32557,12 +36888,12 @@ static int unixRead(
assert( offset>=0 );
assert( amt>0 );
- /* If this is a database file (not a journal, master-journal or temp
+ /* If this is a database file (not a journal, super-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
- assert( pFile->pUnused==0
+ assert( pFile->pPreallocatedUnused==0
|| offset>=PENDING_BYTE+512
- || offset+amt<=PENDING_BYTE
+ || offset+amt<=PENDING_BYTE
);
#endif
@@ -32600,7 +36931,7 @@ static int unixRead(
/*
** Attempt to seek the file-descriptor passed as the first argument to
** absolute offset iOff, then attempt to write nBuf bytes of data from
-** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
+** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
** return the actual number of bytes written (which may be less than
** nBuf).
*/
@@ -32660,22 +36991,22 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
** or some other error code on failure.
*/
static int unixWrite(
- sqlite3_file *id,
- const void *pBuf,
+ sqlite3_file *id,
+ const void *pBuf,
int amt,
- sqlite3_int64 offset
+ sqlite3_int64 offset
){
unixFile *pFile = (unixFile*)id;
int wrote = 0;
assert( id );
assert( amt>0 );
- /* If this is a database file (not a journal, master-journal or temp
+ /* If this is a database file (not a journal, super-journal or temp
** file), the bytes in the locking range should never be read or written. */
#if 0
- assert( pFile->pUnused==0
+ assert( pFile->pPreallocatedUnused==0
|| offset>=PENDING_BYTE+512
- || offset+amt<=PENDING_BYTE
+ || offset+amt<=PENDING_BYTE
);
#endif
@@ -32717,7 +37048,7 @@ static int unixWrite(
}
}
#endif
-
+
while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))<amt && wrote>0 ){
amt -= wrote;
offset += wrote;
@@ -32783,8 +37114,8 @@ SQLITE_API int sqlite3_fullsync_count = 0;
**
** SQLite sets the dataOnly flag if the size of the file is unchanged.
** The idea behind dataOnly is that it should only write the file content
-** to disk, not the inode. We only set dataOnly if the file size is
-** unchanged since the file size is part of the inode. However,
+** to disk, not the inode. We only set dataOnly if the file size is
+** unchanged since the file size is part of the inode. However,
** Ted Ts'o tells us that fdatasync() will also write the inode if the
** file size has changed. The only real difference between fdatasync()
** and fsync(), Ted tells us, is that fdatasync() will not flush the
@@ -32798,7 +37129,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
int rc;
/* The following "ifdef/elif/else/" block has the same structure as
- ** the one below. It is replicated here solely to avoid cluttering
+ ** the one below. It is replicated here solely to avoid cluttering
** up the real code with the UNUSED_PARAMETER() macros.
*/
#ifdef SQLITE_NO_SYNC
@@ -32812,7 +37143,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
UNUSED_PARAMETER(dataOnly);
#endif
- /* Record the number of times that we do a normal fsync() and
+ /* Record the number of times that we do a normal fsync() and
** FULLSYNC. This is used during testing to verify that this procedure
** gets called with the correct arguments.
*/
@@ -32838,11 +37169,11 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
rc = 1;
}
/* If the FULLFSYNC failed, fall back to attempting an fsync().
- ** It shouldn't be possible for fullfsync to fail on the local
+ ** It shouldn't be possible for fullfsync to fail on the local
** file system (on OSX), so failure indicates that FULLFSYNC
- ** isn't supported for this file system. So, attempt an fsync
- ** and (for now) ignore the overhead of a superfluous fcntl call.
- ** It'd be better to detect fullfsync support once and avoid
+ ** isn't supported for this file system. So, attempt an fsync
+ ** and (for now) ignore the overhead of a superfluous fcntl call.
+ ** It'd be better to detect fullfsync support once and avoid
** the fcntl call every time sync is called.
*/
if( rc ) rc = fsync(fd);
@@ -32852,7 +37183,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
** so currently we default to the macro that redefines fdatasync to fsync
*/
rc = fsync(fd);
-#else
+#else
rc = fdatasync(fd);
#if OS_VXWORKS
if( rc==-1 && errno==ENOTSUP ){
@@ -33013,7 +37344,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
#if SQLITE_MAX_MMAP_SIZE>0
/* If the file was just truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
- ** use read() and write() to access data beyond this point from now on.
+ ** use read() and write() to access data beyond this point from now on.
*/
if( nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
@@ -33059,8 +37390,8 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
static int proxyFileControl(sqlite3_file*,int,void*);
#endif
-/*
-** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
+/*
+** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
** file-control operation. Enlarge the database to nBytes in size
** (rounded up to the next chunk-size). If the database is already
** nBytes or larger, this routine is a no-op.
@@ -33069,7 +37400,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
if( pFile->szChunk>0 ){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
-
+
if( osFstat(pFile->h, &buf) ){
return SQLITE_IOERR_FSTAT;
}
@@ -33078,16 +37409,16 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
if( nSize>(i64)buf.st_size ){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
- /* The code below is handling the return value of osFallocate()
- ** correctly. posix_fallocate() is defined to "returns zero on success,
+ /* The code below is handling the return value of osFallocate()
+ ** correctly. posix_fallocate() is defined to "returns zero on success,
** or an error number on failure". See the manpage for details. */
int err;
do{
err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
}while( err==EINTR );
- if( err ) return SQLITE_IOERR_WRITE;
+ if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE;
#else
- /* If the OS does not have posix_fallocate(), fake it. Write a
+ /* If the OS does not have posix_fallocate(), fake it. Write a
** single byte to the last byte in each block that falls entirely
** within the extended region. Then, if required, a single byte
** at offset (nSize-1), to set the size of the file correctly.
@@ -33153,6 +37484,21 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
+ return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK;
+ }
+ case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
+ return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK;
+ }
+ case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
+ int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
+ return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK;
+ }
+#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
@@ -33196,6 +37542,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
*(int*)pArg = fileHasMoved(pFile);
return SQLITE_OK;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ case SQLITE_FCNTL_LOCK_TIMEOUT: {
+ int iOld = pFile->iBusyTimeout;
+ pFile->iBusyTimeout = *(int*)pArg;
+ *(int*)pArg = iOld;
+ return SQLITE_OK;
+ }
+#endif
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
@@ -33203,6 +37557,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
+
+ /* The value of newLimit may be eventually cast to (size_t) and passed
+ ** to mmap(). Restrict its value to 2GB if (size_t) is not at least a
+ ** 64-bit type. */
+ if( newLimit>0 && sizeof(size_t)<8 ){
+ newLimit = (newLimit & 0x7FFFFFFF);
+ }
+
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -33236,38 +37598,49 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
/*
-** Return the sector size in bytes of the underlying block device for
-** the specified file. This is almost always 512 bytes, but may be
-** larger for some devices.
+** If pFd->sectorSize is non-zero when this function is called, it is a
+** no-op. Otherwise, the values of pFd->sectorSize and
+** pFd->deviceCharacteristics are set according to the file-system
+** characteristics.
**
-** SQLite code assumes this function cannot fail. It also assumes that
-** if two files are created in the same file-system directory (i.e.
-** a database and its journal file) that the sector size will be the
-** same for both.
+** There are two versions of this function. One for QNX and one for all
+** other systems.
*/
-#ifndef __QNXNTO__
-static int unixSectorSize(sqlite3_file *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- return SQLITE_DEFAULT_SECTOR_SIZE;
-}
-#endif
+#ifndef __QNXNTO__
+static void setDeviceCharacteristics(unixFile *pFd){
+ assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
+ if( pFd->sectorSize==0 ){
+#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ int res;
+ u32 f = 0;
-/*
-** The following version of unixSectorSize() is optimized for QNX.
-*/
-#ifdef __QNXNTO__
+ /* Check for support for F2FS atomic batch writes. */
+ res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
+ if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
+ pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
+ }
+#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
+ /* Set the POWERSAFE_OVERWRITE flag if requested. */
+ if( pFd->ctrlFlags & UNIXFILE_PSOW ){
+ pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
+ }
+
+ pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
+ }
+}
+#else
#include <sys/dcmd_blk.h>
#include <sys/statvfs.h>
-static int unixSectorSize(sqlite3_file *id){
- unixFile *pFile = (unixFile*)id;
+static void setDeviceCharacteristics(unixFile *pFile){
if( pFile->sectorSize == 0 ){
struct statvfs fsInfo;
-
+
/* Set defaults for non-supported filesystems */
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
pFile->deviceCharacteristics = 0;
if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
- return pFile->sectorSize;
+ return;
}
if( !strcmp(fsInfo.f_basetype, "tmp") ) {
@@ -33328,9 +37701,24 @@ static int unixSectorSize(sqlite3_file *id){
pFile->deviceCharacteristics = 0;
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
- return pFile->sectorSize;
}
-#endif /* __QNXNTO__ */
+#endif
+
+/*
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and its journal file) that the sector size will be the
+** same for both.
+*/
+static int unixSectorSize(sqlite3_file *id){
+ unixFile *pFd = (unixFile*)id;
+ setDeviceCharacteristics(pFd);
+ return pFd->sectorSize;
+}
/*
** Return the device characteristics for the file.
@@ -33346,16 +37734,9 @@ static int unixSectorSize(sqlite3_file *id){
** available to turn it off and URI query parameter available to turn it off.
*/
static int unixDeviceCharacteristics(sqlite3_file *id){
- unixFile *p = (unixFile*)id;
- int rc = 0;
-#ifdef __QNXNTO__
- if( p->sectorSize==0 ) unixSectorSize(id);
- rc = p->deviceCharacteristics;
-#endif
- if( p->ctrlFlags & UNIXFILE_PSOW ){
- rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
- }
- return rc;
+ unixFile *pFd = (unixFile*)id;
+ setDeviceCharacteristics(pFd);
+ return pFd->deviceCharacteristics;
}
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
@@ -33363,7 +37744,7 @@ static int unixDeviceCharacteristics(sqlite3_file *id){
/*
** Return the system page size.
**
-** This function should not be called directly by other code in this file.
+** This function should not be called directly by other code in this file.
** Instead, it should be called via macro osGetpagesize().
*/
static int unixGetpagesize(void){
@@ -33381,7 +37762,7 @@ static int unixGetpagesize(void){
#ifndef SQLITE_OMIT_WAL
/*
-** Object used to represent an shared memory buffer.
+** Object used to represent an shared memory buffer.
**
** When multiple threads all reference the same wal-index, each thread
** has its own unixShm object, but they all point to a single instance
@@ -33401,22 +37782,23 @@ static int unixGetpagesize(void){
** nRef
**
** The following fields are read-only after the object is created:
-**
-** fid
+**
+** hShm
** zFilename
**
-** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and
+** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
*/
struct unixShmNode {
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
- sqlite3_mutex *mutex; /* Mutex to access this object */
+ sqlite3_mutex *pShmMutex; /* Mutex to access this object */
char *zFilename; /* Name of the mmapped file */
- int h; /* Open file descriptor */
+ int hShm; /* Open file descriptor */
int szRegion; /* Size of shared-memory regions */
u16 nRegion; /* Size of array apRegion */
u8 isReadonly; /* True if read-only */
+ u8 isUnlocked; /* True if no DMS lock held */
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 */
@@ -33434,16 +37816,16 @@ struct unixShmNode {
** The following fields are initialized when this object is created and
** are read-only thereafter:
**
-** unixShm.pFile
+** unixShm.pShmNode
** unixShm.id
**
-** All other fields are read/write. The unixShm.pFile->mutex must be held
-** while accessing any read/write fields.
+** All other fields are read/write. The unixShm.pShmNode->pShmMutex must
+** be held while accessing any read/write fields.
*/
struct unixShm {
unixShmNode *pShmNode; /* The underlying unixShmNode object */
unixShm *pNext; /* Next unixShm with the same unixShmNode */
- u8 hasMutex; /* True if holding the unixShmNode mutex */
+ u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */
u8 id; /* Id of this connection within its unixShmNode */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
@@ -33473,7 +37855,8 @@ static int unixShmSystemLock(
/* Access to the unixShmNode object is serialized by the caller */
pShmNode = pFile->pInode->pShmNode;
- assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
+ assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
+ assert( pShmNode->nRef>0 || unixMutexHeld() );
/* Shared locks never span more than one byte */
assert( n==1 || lockType!=F_RDLCK );
@@ -33481,16 +37864,21 @@ static int unixShmSystemLock(
/* Locks are within range */
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
- if( pShmNode->h>=0 ){
+ if( pShmNode->hShm>=0 ){
+ int res;
/* Initialize the locking parameters */
- memset(&f, 0, sizeof(f));
f.l_type = lockType;
f.l_whence = SEEK_SET;
f.l_start = ofst;
f.l_len = n;
-
- rc = osFcntl(pShmNode->h, F_SETLK, &f);
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
+ res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
+ if( res==-1 ){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
+#else
+ rc = SQLITE_BUSY;
+#endif
+ }
}
/* Update the global lock state and do debug tracing */
@@ -33528,7 +37916,7 @@ static int unixShmSystemLock(
}
#endif
- return rc;
+ return rc;
}
/*
@@ -33561,18 +37949,18 @@ static void unixShmPurge(unixFile *pFd){
int nShmPerMap = unixShmRegionPerMap();
int i;
assert( p->pInode==pFd->pInode );
- sqlite3_mutex_free(p->mutex);
+ sqlite3_mutex_free(p->pShmMutex);
for(i=0; i<p->nRegion; i+=nShmPerMap){
- if( p->h>=0 ){
+ if( p->hShm>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
}else{
sqlite3_free(p->apRegion[i]);
}
}
sqlite3_free(p->apRegion);
- if( p->h>=0 ){
- robust_close(pFd, p->h, __LINE__);
- p->h = -1;
+ if( p->hShm>=0 ){
+ robust_close(pFd, p->hShm, __LINE__);
+ p->hShm = -1;
}
p->pInode->pShmNode = 0;
sqlite3_free(p);
@@ -33580,20 +37968,83 @@ static void unixShmPurge(unixFile *pFd){
}
/*
-** Open a shared-memory area associated with open database file pDbFd.
+** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
+** take it now. Return SQLITE_OK if successful, or an SQLite error
+** code otherwise.
+**
+** If the DMS cannot be locked because this is a readonly_shm=1
+** connection and no other process already holds a lock, return
+** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
+*/
+static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
+ struct flock lock;
+ int rc = SQLITE_OK;
+
+ /* Use F_GETLK to determine the locks other processes are holding
+ ** on the DMS byte. If it indicates that another process is holding
+ ** a SHARED lock, then this process may also take a SHARED lock
+ ** and proceed with opening the *-shm file.
+ **
+ ** Or, if no other process is holding any lock, then this process
+ ** is the first to open it. In this case take an EXCLUSIVE lock on the
+ ** DMS byte and truncate the *-shm file to zero bytes in size. Then
+ ** downgrade to a SHARED lock on the DMS byte.
+ **
+ ** If another process is holding an EXCLUSIVE lock on the DMS byte,
+ ** return SQLITE_BUSY to the caller (it will try again). An earlier
+ ** version of this code attempted the SHARED lock at this point. But
+ ** this introduced a subtle race condition: if the process holding
+ ** EXCLUSIVE failed just before truncating the *-shm file, then this
+ ** process might open and use the *-shm file without truncating it.
+ ** And if the *-shm file has been corrupted by a power failure or
+ ** system crash, the database itself may also become corrupt. */
+ lock.l_whence = SEEK_SET;
+ lock.l_start = UNIX_SHM_DMS;
+ lock.l_len = 1;
+ lock.l_type = F_WRLCK;
+ if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) {
+ rc = SQLITE_IOERR_LOCK;
+ }else if( lock.l_type==F_UNLCK ){
+ if( pShmNode->isReadonly ){
+ pShmNode->isUnlocked = 1;
+ rc = SQLITE_READONLY_CANTINIT;
+ }else{
+ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
+ /* The first connection to attach must truncate the -shm file. We
+ ** truncate to 3 bytes (an arbitrary small number, less than the
+ ** -shm header size) rather than 0 as a system debugging aid, to
+ ** help detect if a -shm file truncation is legitimate or is the work
+ ** or a rogue process. */
+ if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){
+ rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename);
+ }
+ }
+ }else if( lock.l_type==F_WRLCK ){
+ rc = SQLITE_BUSY;
+ }
+
+ if( rc==SQLITE_OK ){
+ assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK );
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
+ }
+ return rc;
+}
+
+/*
+** Open a shared-memory area associated with open database file pDbFd.
** This particular implementation uses mmapped files.
**
** The file used to implement shared-memory is in the same directory
** as the open database file and has the same name as the open database
** file with the "-shm" suffix added. For example, if the database file
** is "/home/user1/config.db" then the file that is created and mmapped
-** for shared memory will be called "/home/user1/config.db-shm".
+** for shared memory will be called "/home/user1/config.db-shm".
**
** Another approach to is to use files in /dev/shm or /dev/tmp or an
** some other tmpfs mount. But if a file in a different directory
** from the database file is used, then differing access permissions
** or a chroot() might cause two different processes on the same
-** database to end up using different files for shared memory -
+** database to end up using different files for shared memory -
** meaning that their memory would not really be shared - resulting
** in database corruption. Nevertheless, this tmpfs file usage
** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm"
@@ -33617,9 +38068,9 @@ static void unixShmPurge(unixFile *pFd){
static int unixOpenSharedMemory(unixFile *pDbFd){
struct unixShm *p = 0; /* The connection to be opened */
struct unixShmNode *pShmNode; /* The underlying mmapped file */
- int rc; /* Result code */
+ int rc = SQLITE_OK; /* Result code */
unixInodeInfo *pInode; /* The inode of fd */
- char *zShmFilename; /* Name of the file used for SHM */
+ char *zShm; /* Name of the file used for SHM */
int nShmFilename; /* Size of the SHM filename in bytes */
/* Allocate space for the new unixShm object. */
@@ -33631,6 +38082,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
/* Check to see if a unixShmNode object already exists. Reuse an existing
** one if present. Create a new one if necessary.
*/
+ assert( unixFileMutexNotheld(pDbFd) );
unixEnterMutex();
pInode = pDbFd->pInode;
pShmNode = pInode->pShmNode;
@@ -33660,57 +38112,49 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
goto shm_open_err;
}
memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
- zShmFilename = pShmNode->zFilename = (char*)&pShmNode[1];
+ zShm = pShmNode->zFilename = (char*)&pShmNode[1];
#ifdef SQLITE_SHM_DIRECTORY
- sqlite3_snprintf(nShmFilename, zShmFilename,
+ sqlite3_snprintf(nShmFilename, zShm,
SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
(u32)sStat.st_ino, (u32)sStat.st_dev);
#else
- sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", zBasePath);
- sqlite3FileSuffix3(pDbFd->zPath, zShmFilename);
+ sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath);
+ sqlite3FileSuffix3(pDbFd->zPath, zShm);
#endif
- pShmNode->h = -1;
+ pShmNode->hShm = -1;
pDbFd->pInode->pShmNode = pShmNode;
pShmNode->pInode = pDbFd->pInode;
if( sqlite3GlobalConfig.bCoreMutex ){
- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pShmNode->mutex==0 ){
+ pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->pShmMutex==0 ){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
}
if( pInode->bProcessLock==0 ){
- int openFlags = O_RDWR | O_CREAT;
- if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
- openFlags = O_RDONLY;
- pShmNode->isReadonly = 1;
+ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
+ pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT|O_NOFOLLOW,
+ (sStat.st_mode&0777));
}
- pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
- if( pShmNode->h<0 ){
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
- goto shm_open_err;
+ if( pShmNode->hShm<0 ){
+ pShmNode->hShm = robust_open(zShm, O_RDONLY|O_NOFOLLOW,
+ (sStat.st_mode&0777));
+ if( pShmNode->hShm<0 ){
+ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm);
+ goto shm_open_err;
+ }
+ pShmNode->isReadonly = 1;
}
/* If this process is running as root, make sure that the SHM file
** is owned by the same user that owns the original database. Otherwise,
** the original owner will not be able to connect.
*/
- robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid);
-
- /* Check to see if another process is holding the dead-man switch.
- ** If not, truncate the file to zero length.
- */
- rc = SQLITE_OK;
- if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
- if( robust_ftruncate(pShmNode->h, 0) ){
- rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename);
- }
- }
- if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
- }
- if( rc ) goto shm_open_err;
+ robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid);
+
+ rc = unixLockSharedMemory(pDbFd, pShmNode);
+ if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
}
}
@@ -33727,14 +38171,14 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
** the cover of the unixEnterMutex() mutex and the pointer from the
** new (struct unixShm) object to the pShmNode has been set. All that is
** left to do is to link the new object into the linked list starting
- ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex
- ** mutex.
+ ** at pShmNode->pFirst. This must be done while holding the
+ ** pShmNode->pShmMutex.
*/
- sqlite3_mutex_enter(pShmNode->mutex);
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
- sqlite3_mutex_leave(pShmNode->mutex);
- return SQLITE_OK;
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
+ return rc;
/* Jump here on any error */
shm_open_err:
@@ -33745,22 +38189,22 @@ shm_open_err:
}
/*
-** This function is called to obtain a pointer to region iRegion of the
-** shared-memory associated with the database file fd. Shared-memory regions
-** are numbered starting from zero. Each shared-memory region is szRegion
+** This function is called to obtain a pointer to region iRegion of the
+** shared-memory associated with the database file fd. Shared-memory regions
+** are numbered starting from zero. Each shared-memory region is szRegion
** bytes in size.
**
** If an error occurs, an error code is returned and *pp is set to NULL.
**
** Otherwise, if the bExtend parameter is 0 and the requested shared-memory
** region has not been allocated (by any client, including one running in a
-** separate process), then *pp is set to NULL and SQLITE_OK returned. If
-** bExtend is non-zero and the requested shared-memory region has not yet
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
+** bExtend is non-zero and the requested shared-memory region has not yet
** been allocated, it is allocated by this function.
**
** If the shared-memory region has already been allocated or is allocated by
-** this call as described above, then it is mapped into this processes
-** address space (if it is not already), *pp is set to point to the mapped
+** this call as described above, then it is mapped into this processes
+** address space (if it is not already), *pp is set to point to the mapped
** memory and SQLITE_OK returned.
*/
static int unixShmMap(
@@ -33785,11 +38229,16 @@ static int unixShmMap(
p = pDbFd->pShm;
pShmNode = p->pShmNode;
- sqlite3_mutex_enter(pShmNode->mutex);
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
+ if( pShmNode->isUnlocked ){
+ rc = unixLockSharedMemory(pDbFd, pShmNode);
+ if( rc!=SQLITE_OK ) goto shmpage_out;
+ pShmNode->isUnlocked = 0;
+ }
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
assert( pShmNode->pInode==pDbFd->pInode );
- assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
- assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
+ assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
+ assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
/* Minimum number of regions required to be mapped. */
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
@@ -33801,16 +38250,16 @@ static int unixShmMap(
pShmNode->szRegion = szRegion;
- if( pShmNode->h>=0 ){
+ if( pShmNode->hShm>=0 ){
/* The requested region is not mapped into this processes address space.
** Check to see if it has been allocated (i.e. if the wal-index file is
** large enough to contain the requested region).
*/
- if( osFstat(pShmNode->h, &sStat) ){
+ if( osFstat(pShmNode->hShm, &sStat) ){
rc = SQLITE_IOERR_SHMSIZE;
goto shmpage_out;
}
-
+
if( sStat.st_size<nByte ){
/* The requested memory region does not exist. If bExtend is set to
** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
@@ -33834,7 +38283,7 @@ static int unixShmMap(
assert( (nByte % pgsz)==0 );
for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){
int x = 0;
- if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){
+ if( seekAndWriteFd(pShmNode->hShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){
const char *zFile = pShmNode->zFilename;
rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile);
goto shmpage_out;
@@ -33857,22 +38306,22 @@ static int unixShmMap(
int nMap = szRegion*nShmPerMap;
int i;
void *pMem;
- if( pShmNode->h>=0 ){
+ if( pShmNode->hShm>=0 ){
pMem = osMmap(0, nMap,
- pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
- MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
+ pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
+ MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion
);
if( pMem==MAP_FAILED ){
rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
goto shmpage_out;
}
}else{
- pMem = sqlite3_malloc64(szRegion);
+ pMem = sqlite3_malloc64(nMap);
if( pMem==0 ){
rc = SQLITE_NOMEM_BKPT;
goto shmpage_out;
}
- memset(pMem, 0, szRegion);
+ memset(pMem, 0, nMap);
}
for(i=0; i<nShmPerMap; i++){
@@ -33889,7 +38338,7 @@ shmpage_out:
*pp = 0;
}
if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
- sqlite3_mutex_leave(pShmNode->mutex);
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
return rc;
}
@@ -33923,12 +38372,34 @@ static int unixShmLock(
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
- assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
- assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
+ assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
+ assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
+
+ /* Check that, if this to be a blocking lock, no locks that occur later
+ ** in the following list than the lock being obtained are already held:
+ **
+ ** 1. Checkpointer lock (ofst==1).
+ ** 2. Write lock (ofst==0).
+ ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
+ **
+ ** In other words, if this is a blocking lock, none of the locks that
+ ** occur later in the above list than the lock being obtained may be
+ ** held.
+ **
+ ** It is not permitted to block on the RECOVER lock.
+ */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
+ (ofst!=2) /* not RECOVER */
+ && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
+ && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
+ && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
+ ));
+#endif
mask = (1<<(ofst+n)) - (1<<ofst);
assert( n>1 || mask==(1<<ofst) );
- sqlite3_mutex_enter(pShmNode->mutex);
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
if( flags & SQLITE_SHM_UNLOCK ){
u16 allMask = 0; /* Mask of locks held by siblings */
@@ -33950,7 +38421,7 @@ static int unixShmLock(
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
- }
+ }
}else if( flags & SQLITE_SHM_SHARED ){
u16 allShared = 0; /* Union of locks held by connections other than "p" */
@@ -33989,7 +38460,7 @@ static int unixShmLock(
break;
}
}
-
+
/* Get the exclusive locks at the system level. Then if successful
** also mark the local connection as being locked.
*/
@@ -34001,14 +38472,14 @@ static int unixShmLock(
}
}
}
- sqlite3_mutex_leave(pShmNode->mutex);
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
}
/*
-** Implement a memory barrier or memory fence on shared memory.
+** Implement a memory barrier or memory fence on shared memory.
**
** All loads and stores begun before the barrier must complete before
** any load or store begun after the barrier.
@@ -34018,12 +38489,15 @@ static void unixShmBarrier(
){
UNUSED_PARAMETER(fd);
sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
+ assert( fd->pMethods->xLock==nolockLock
+ || unixFileMutexNotheld((unixFile*)fd)
+ );
unixEnterMutex(); /* Also mutex, for redundancy */
unixLeaveMutex();
}
/*
-** Close a connection to shared-memory. Delete the underlying
+** Close a connection to shared-memory. Delete the underlying
** storage if deleteFlag is true.
**
** If there is no shared memory associated with the connection then this
@@ -34048,22 +38522,23 @@ static int unixShmUnmap(
/* Remove connection p from the set of connections associated
** with pShmNode */
- sqlite3_mutex_enter(pShmNode->mutex);
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){}
*pp = p->pNext;
/* Free the connection p */
sqlite3_free(p);
pDbFd->pShm = 0;
- sqlite3_mutex_leave(pShmNode->mutex);
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
/* If pShmNode->nRef has reached 0, then close the underlying
** shared-memory file, too */
+ assert( unixFileMutexNotheld(pDbFd) );
unixEnterMutex();
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
- if( deleteFlag && pShmNode->h>=0 ){
+ if( deleteFlag && pShmNode->hShm>=0 ){
osUnlink(pShmNode->zFilename);
}
unixShmPurge(pDbFd);
@@ -34096,7 +38571,7 @@ static void unixUnmapfile(unixFile *pFd){
}
/*
-** Attempt to set the size of the memory mapping maintained by file
+** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
**
** If successful, this function sets the following variables:
@@ -34188,14 +38663,14 @@ static void unixRemapfile(
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
-** is already mapped, the existing mapping is replaced by the new). Or, if
-** there already exists a mapping for this file, and there are still
+** is already mapped, the existing mapping is replaced by the new). Or, if
+** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
-** If parameter nByte is non-negative, then it is the requested size of
-** the mapping to create. Otherwise, if nByte is less than zero, then the
+** If parameter nByte is non-negative, then it is the requested size of
+** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
-** created mapping is either the requested size or the value configured
+** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
@@ -34236,7 +38711,7 @@ static int unixMapfile(unixFile *pFd, i64 nMap){
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
-** If this function does return a pointer, the caller must eventually
+** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
@@ -34261,13 +38736,13 @@ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
}
/*
-** If the third argument is non-NULL, then this function releases a
+** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
-** argument that was passed to the unixFetch() invocation.
+** argument that was passed to the unixFetch() invocation.
**
-** Or, if the third argument is NULL, then this function is being called
-** to inform the VFS layer that, according to POSIX, any existing mapping
+** Or, if the third argument is NULL, then this function is being called
+** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
@@ -34275,7 +38750,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
UNUSED_PARAMETER(iOff);
- /* If p==0 (unmap the entire file) then there must be no outstanding
+ /* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
@@ -34385,7 +38860,7 @@ IOMETHODS(
IOMETHODS(
nolockIoFinder, /* Finder function name */
nolockIoMethods, /* sqlite3_io_methods object name */
- 3, /* shared memory is disabled */
+ 3, /* shared memory and mmap are enabled */
nolockClose, /* xClose method */
nolockLock, /* xLock method */
nolockUnlock, /* xUnlock method */
@@ -34483,8 +38958,8 @@ IOMETHODS(
#endif
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
-/*
-** This "finder" function attempts to determine the best locking strategy
+/*
+** This "finder" function attempts to determine the best locking strategy
** for the database file "filePath". It then returns the sqlite3_io_methods
** object that implements that strategy.
**
@@ -34526,8 +39001,8 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
}
/* Default case. Handles, amongst others, "nfs".
- ** Test byte-range lock using fcntl(). If the call succeeds,
- ** assume that the file-system supports POSIX style locks.
+ ** Test byte-range lock using fcntl(). If the call succeeds,
+ ** assume that the file-system supports POSIX style locks.
*/
lockInfo.l_len = 1;
lockInfo.l_start = 0;
@@ -34543,7 +39018,7 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
return &dotlockIoMethods;
}
}
-static const sqlite3_io_methods
+static const sqlite3_io_methods
*(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
@@ -34579,7 +39054,7 @@ static const sqlite3_io_methods *vxworksIoFinderImpl(
return &semIoMethods;
}
}
-static const sqlite3_io_methods
+static const sqlite3_io_methods
*(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl;
#endif /* OS_VXWORKS */
@@ -34613,17 +39088,6 @@ static int fillInUnixFile(
assert( pNew->pInode==NULL );
- /* Usually the path zFilename should not be a relative pathname. The
- ** exception is when opening the proxy "conch" file in builds that
- ** include the special Apple locking styles.
- */
-#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
- assert( zFilename==0 || zFilename[0]=='/'
- || pVfs->pAppData==(void*)&autolockIoFinder );
-#else
- assert( zFilename==0 || zFilename[0]=='/' );
-#endif
-
/* No locking occurs in temporary files */
assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 );
@@ -34718,14 +39182,14 @@ static int fillInUnixFile(
robust_close(pNew, h, __LINE__);
h = -1;
}
- unixLeaveMutex();
+ unixLeaveMutex();
}
}
#endif
else if( pLockingStyle == &dotlockIoMethods ){
/* Dotfile locking uses the file path so it needs to be included in
- ** the dotlockLockingContext
+ ** the dotlockLockingContext
*/
char *zLockFile;
int nFilename;
@@ -34763,7 +39227,7 @@ static int fillInUnixFile(
unixLeaveMutex();
}
#endif
-
+
storeLastErrno(pNew, 0);
#if OS_VXWORKS
if( rc!=SQLITE_OK ){
@@ -34776,7 +39240,7 @@ static int fillInUnixFile(
if( rc!=SQLITE_OK ){
if( h>=0 ) robust_close(pNew, h, __LINE__);
}else{
- pNew->pMethod = pLockingStyle;
+ pId->pMethods = pLockingStyle;
OpenCounter(+1);
verifyDbFile(pNew);
}
@@ -34827,7 +39291,7 @@ static int unixGetTempname(int nBuf, char *zBuf){
/* 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.
+ ** function failing.
*/
zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
@@ -34856,8 +39320,8 @@ static int proxyTransformUnixFile(unixFile*, const char*);
#endif
/*
-** Search for an unused file descriptor that was opened on the database
-** file (not a journal or master-journal file) identified by pathname
+** Search for an unused file descriptor that was opened on the database
+** file (not a journal or super-journal file) identified by pathname
** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
** argument to this function.
**
@@ -34865,7 +39329,7 @@ static int proxyTransformUnixFile(unixFile*, const char*);
** but the associated file descriptor could not be closed because some
** other file descriptor open on the same file is holding a file-lock.
** Refer to comments in the unixClose() function and the lengthy comment
-** describing "Posix Advisory Locking" at the start of this file for
+** describing "Posix Advisory Locking" at the start of this file for
** further details. Also, ticket #4018.
**
** If a suitable file descriptor is found, then it is returned. If no
@@ -34876,12 +39340,14 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
/* Do not search for an unused file descriptor on vxworks. Not because
** vxworks would not benefit from the change (it might, we're not sure),
- ** but because no way to test it is currently available. It is better
- ** not to risk breaking vxworks support for the sake of such an obscure
+ ** but because no way to test it is currently available. It is better
+ ** not to risk breaking vxworks support for the sake of such an obscure
** feature. */
#if !OS_VXWORKS
struct stat sStat; /* Results of stat() call */
+ unixEnterMutex();
+
/* A stat() call may fail for various reasons. If this happens, it is
** almost certain that an open() call on the same path will also fail.
** For this reason, if an error occurs in the stat() call here, it is
@@ -34890,31 +39356,34 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
**
** Even if a subsequent open() call does succeed, the consequences of
** not searching for a reusable file descriptor are not dire. */
- if( 0==osStat(zPath, &sStat) ){
+ if( inodeList!=0 && 0==osStat(zPath, &sStat) ){
unixInodeInfo *pInode;
- unixEnterMutex();
pInode = inodeList;
while( pInode && (pInode->fileId.dev!=sStat.st_dev
- || pInode->fileId.ino!=sStat.st_ino) ){
+ || pInode->fileId.ino!=(u64)sStat.st_ino) ){
pInode = pInode->pNext;
}
if( pInode ){
UnixUnusedFd **pp;
+ assert( sqlite3_mutex_notheld(pInode->pLockMutex) );
+ sqlite3_mutex_enter(pInode->pLockMutex);
+ flags &= (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE);
for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
pUnused = *pp;
if( pUnused ){
*pp = pUnused->pNext;
}
+ sqlite3_mutex_leave(pInode->pLockMutex);
}
- unixLeaveMutex();
}
+ unixLeaveMutex();
#endif /* if !OS_VXWORKS */
return pUnused;
}
/*
-** Find the mode, uid and gid of file zFile.
+** Find the mode, uid and gid of file zFile.
*/
static int getFileMode(
const char *zFile, /* File name */
@@ -34938,22 +39407,22 @@ static int getFileMode(
** This function is called by unixOpen() to determine the unix permissions
** to create new files with. If no error occurs, then SQLITE_OK is returned
** and a value suitable for passing as the third argument to open(2) is
-** written to *pMode. If an IO error occurs, an SQLite error code is
+** written to *pMode. If an IO error occurs, an SQLite error code is
** returned and the value of *pMode is not modified.
**
** In most cases, this routine sets *pMode to 0, which will become
** an indication to robust_open() to create the file using
** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
-** But if the file being opened is a WAL or regular journal file, then
-** this function queries the file-system for the permissions on the
-** corresponding database file and sets *pMode to this value. Whenever
-** possible, WAL and journal files are created using the same permissions
+** But if the file being opened is a WAL or regular journal file, then
+** this function queries the file-system for the permissions on the
+** 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.
+** the default permissions. In 8_3_NAMES mode, leave *pMode set to zero.
*/
static int findCreateFileMode(
const char *zPath, /* Path of file (possibly) being created */
@@ -34979,21 +39448,16 @@ static int findCreateFileMode(
** "<path to db>-journalNN"
** "<path to db>-walNN"
**
- ** where NN is a decimal number. The NN naming schemes are
+ ** where NN is a decimal number. The NN naming schemes are
** used by the test_multiplex.c module.
*/
- nDb = sqlite3Strlen30(zPath) - 1;
+ nDb = sqlite3Strlen30(zPath) - 1;
while( zPath[nDb]!='-' ){
-#ifndef SQLITE_ENABLE_8_3_NAMES
- /* In the normal case (8+3 filenames disabled) the journal filename
- ** is guaranteed to contain a '-' character. */
- assert( nDb>0 );
- assert( sqlite3Isalnum(zPath[nDb]) );
-#else
- /* If 8+3 names are possible, then the journal file might not contain
- ** a '-' character. So check for that case and return early. */
+ /* In normal operation, the journal file name will always contain
+ ** a '-' character. However in 8+3 filename mode, or if a corrupt
+ ** rollback journal specifies a super-journal with a goofy name, then
+ ** the '-' might be missing. */
if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
-#endif
nDb--;
}
memcpy(zDb, zPath, nDb);
@@ -35017,7 +39481,7 @@ static int findCreateFileMode(
/*
** Open the file zPath.
-**
+**
** Previously, the SQLite OS layer used three functions in place of this
** one:
**
@@ -35028,13 +39492,13 @@ static int findCreateFileMode(
** These calls correspond to the following combinations of flags:
**
** ReadWrite() -> (READWRITE | CREATE)
-** ReadOnly() -> (READONLY)
+** ReadOnly() -> (READONLY)
** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
**
** The old OpenExclusive() accepted a boolean argument - "delFlag". If
** true, the file was configured to be automatically deleted when the
-** file handle closed. To achieve the same effect using this new
-** interface, add the DELETEONCLOSE flag to those specified above for
+** file handle closed. To achieve the same effect using this new
+** interface, add the DELETEONCLOSE flag to those specified above for
** OpenExclusive().
*/
static int unixOpen(
@@ -35047,7 +39511,7 @@ static int unixOpen(
unixFile *p = (unixFile *)pFile;
int fd = -1; /* File descriptor returned by open() */
int openFlags = 0; /* Flags to pass to open() */
- int eType = flags&0xFFFFFF00; /* Type of file to open */
+ int eType = flags&0x0FFF00; /* Type of file to open */
int noLock; /* True to omit locking primitives */
int rc = SQLITE_OK; /* Function Return Code */
int ctrlFlags = 0; /* UNIXFILE_* flags */
@@ -35064,13 +39528,13 @@ static int unixOpen(
struct statfs fsInfo;
#endif
- /* If creating a master or main-file journal, this function will open
+ /* If creating a super- or main-file journal, this function will open
** a file-descriptor on the directory too. The first time unixSync()
** is called the directory file descriptor will be fsync()ed and close()d.
*/
- int syncDir = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
- || eType==SQLITE_OPEN_MAIN_JOURNAL
+ int isNewJrnl = (isCreate && (
+ eType==SQLITE_OPEN_SUPER_JOURNAL
+ || eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
@@ -35080,9 +39544,9 @@ static int unixOpen(
char zTmpname[MAX_PATHNAME+2];
const char *zName = zPath;
- /* Check the following statements are true:
+ /* Check the following statements are true:
**
- ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
** (b) if CREATE is set, then READWRITE must also be set, and
** (c) if EXCLUSIVE is set, then CREATE must also be set.
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
@@ -35092,17 +39556,17 @@ static int unixOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and super-journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
- assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
- || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
+ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
@@ -35115,7 +39579,6 @@ static int unixOpen(
randomnessPid = osGetpid(0);
sqlite3_randomness(0,0);
}
-
memset(p, 0, sizeof(unixFile));
if( eType==SQLITE_OPEN_MAIN_DB ){
@@ -35129,7 +39592,7 @@ static int unixOpen(
return SQLITE_NOMEM_BKPT;
}
}
- p->pUnused = pUnused;
+ p->pPreallocatedUnused = pUnused;
/* Database filenames are double-zero terminated if they are not
** URIs with parameters. Hence, they can always be passed into
@@ -35138,7 +39601,7 @@ static int unixOpen(
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
- assert(isDelete && !syncDir);
+ assert(isDelete && !isNewJrnl);
rc = unixGetTempname(pVfs->mxPathname, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
@@ -35152,13 +39615,13 @@ static int unixOpen(
/* Determine the value of the flags parameter passed to POSIX function
** open(). These must be calculated even if open() is not called, as
- ** they may be stored as part of the file handle and used by the
+ ** they may be stored as part of the file handle and used by the
** 'conch file' locking functions later on. */
if( isReadonly ) openFlags |= O_RDONLY;
if( isReadWrite ) openFlags |= O_RDWR;
if( isCreate ) openFlags |= O_CREAT;
if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
- openFlags |= (O_LARGEFILE|O_BINARY);
+ openFlags |= (O_LARGEFILE|O_BINARY|O_NOFOLLOW);
if( fd<0 ){
mode_t openMode; /* Permissions to create file with */
@@ -35166,32 +39629,47 @@ static int unixOpen(
gid_t gid; /* Groupid for the file */
rc = findCreateFileMode(zName, flags, &openMode, &uid, &gid);
if( rc!=SQLITE_OK ){
- assert( !p->pUnused );
+ assert( !p->pPreallocatedUnused );
assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
return rc;
}
fd = robust_open(zName, openFlags, openMode);
OSTRACE(("OPENX %-3d %s 0%o\n", fd, zName, openFlags));
assert( !isExclusive || (openFlags & O_CREAT)!=0 );
- if( fd<0 && errno!=EISDIR && isReadWrite ){
- /* Failed to open the file for read/write access. Try read-only. */
- flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
- openFlags &= ~(O_RDWR|O_CREAT);
- flags |= SQLITE_OPEN_READONLY;
- openFlags |= O_RDONLY;
- isReadonly = 1;
- fd = robust_open(zName, openFlags, openMode);
+ if( fd<0 ){
+ if( isNewJrnl && errno==EACCES && osAccess(zName, F_OK) ){
+ /* If unable to create a journal because the directory is not
+ ** writable, change the error code to indicate that. */
+ rc = SQLITE_READONLY_DIRECTORY;
+ }else if( errno!=EISDIR && isReadWrite ){
+ /* Failed to open the file for read/write access. Try read-only. */
+ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
+ openFlags &= ~(O_RDWR|O_CREAT);
+ flags |= SQLITE_OPEN_READONLY;
+ openFlags |= O_RDONLY;
+ isReadonly = 1;
+ fd = robust_open(zName, openFlags, openMode);
+ }
}
if( fd<0 ){
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
+ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
+ if( rc==SQLITE_OK ) rc = rc2;
goto open_finished;
}
- /* If this process is running as root and if creating a new rollback
- ** journal or WAL file, set the ownership of the journal or WAL to be
- ** the same as the original database.
+ /* The owner of the rollback journal or WAL file should always be the
+ ** same as the owner of the database file. Try to ensure that this is
+ ** the case. The chown() system call will be a no-op if the current
+ ** process lacks root privileges, be we should at least try. Without
+ ** this step, if a root process opens a database file, it can leave
+ ** behinds a journal/WAL that is owned by root and hence make the
+ ** database inaccessible to unprivileged processes.
+ **
+ ** If openMode==0, then that means uid and gid are not set correctly
+ ** (probably because SQLite is configured to use 8+3 filename mode) and
+ ** in that case we do not want to attempt the chown().
*/
- if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
+ if( openMode && (flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL))!=0 ){
robustFchown(fd, uid, gid);
}
}
@@ -35200,9 +39678,10 @@ static int unixOpen(
*pOutFlags = flags;
}
- if( p->pUnused ){
- p->pUnused->fd = fd;
- p->pUnused->flags = flags;
+ if( p->pPreallocatedUnused ){
+ p->pPreallocatedUnused->fd = fd;
+ p->pPreallocatedUnused->flags =
+ flags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE);
}
if( isDelete ){
@@ -35223,7 +39702,7 @@ static int unixOpen(
p->openFlags = openFlags;
}
#endif
-
+
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
if( fstatfs(fd, &fsInfo) == -1 ){
storeLastErrno(p, errno);
@@ -35243,7 +39722,7 @@ static int unixOpen(
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
noLock = eType!=SQLITE_OPEN_MAIN_DB;
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
- if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
+ if( isNewJrnl ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
#if SQLITE_ENABLE_LOCKING_STYLE
@@ -35254,7 +39733,7 @@ static int unixOpen(
char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
int useProxy = 0;
- /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
+ /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
** never use proxy, NULL means use proxy for non-local files only. */
if( envforce!=NULL ){
useProxy = atoi(envforce)>0;
@@ -35266,9 +39745,9 @@ static int unixOpen(
if( rc==SQLITE_OK ){
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
if( rc!=SQLITE_OK ){
- /* Use unixClose to clean up the resources added in fillInUnixFile
- ** and clear all the structure's references. Specifically,
- ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
+ /* Use unixClose to clean up the resources added in fillInUnixFile
+ ** and clear all the structure's references. Specifically,
+ ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
*/
unixClose(pFile);
return rc;
@@ -35278,12 +39757,15 @@ static int unixOpen(
}
}
#endif
-
+
+ assert( zPath==0 || zPath[0]=='/'
+ || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
+ );
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
open_finished:
if( rc!=SQLITE_OK ){
- sqlite3_free(p->pUnused);
+ sqlite3_free(p->pPreallocatedUnused);
}
return rc;
}
@@ -35357,7 +39839,8 @@ static int unixAccess(
if( flags==SQLITE_ACCESS_EXISTS ){
struct stat buf;
- *pResOut = (0==osStat(zPath, &buf) && buf.st_size>0);
+ *pResOut = 0==osStat(zPath, &buf) &&
+ (!S_ISREG(buf.st_mode) || buf.st_size>0);
}else{
*pResOut = osAccess(zPath, W_OK|R_OK)==0;
}
@@ -35394,9 +39877,9 @@ static int mkFullPathname(
/*
** Turn a relative pathname into a full pathname. The relative path
** is stored as a nul-terminated string in the buffer pointed to by
-** zPath.
+** zPath.
**
-** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
+** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
** (in this case, MAX_PATHNAME bytes). The full-path is written to
** this buffer before returning.
*/
@@ -35411,7 +39894,7 @@ static int unixFullPathname(
#else
int rc = SQLITE_OK;
int nByte;
- int nLink = 1; /* Number of symbolic links followed so far */
+ int nLink = 0; /* Number of symbolic links followed so far */
const char *zIn = zPath; /* Input path for each iteration of loop */
char *zDel = 0;
@@ -35440,10 +39923,11 @@ static int unixFullPathname(
}
if( bLink ){
+ nLink++;
if( zDel==0 ){
zDel = sqlite3_malloc(nOut);
if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
- }else if( ++nLink>SQLITE_MAX_SYMLINKS ){
+ }else if( nLink>=SQLITE_MAX_SYMLINKS ){
rc = SQLITE_CANTOPEN_BKPT;
}
@@ -35479,6 +39963,7 @@ static int unixFullPathname(
}while( rc==SQLITE_OK );
sqlite3_free(zDel);
+ if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK;
return rc;
#endif /* HAVE_READLINK && HAVE_LSTAT */
}
@@ -35513,7 +39998,7 @@ static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
unixLeaveMutex();
}
static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
- /*
+ /*
** GCC with -pedantic-errors says that C90 does not allow a void* to be
** cast into a pointer to a function. And yet the library dlsym() routine
** returns a void* which is really a pointer to a function. So how do we
@@ -35523,7 +40008,7 @@ static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
** parameters void* and const char* and returning a pointer to a function.
** We initialize x by assigning it a pointer to the dlsym() function.
** (That assignment requires a cast.) Then we call the function that
- ** x points to.
+ ** x points to.
**
** This work-around is unlikely to work correctly on any system where
** you really cannot cast a function pointer into void*. But then, on the
@@ -35566,7 +40051,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** tests repeatable.
*/
memset(zBuf, 0, nBuf);
- randomnessPid = osGetpid(0);
+ randomnessPid = osGetpid(0);
#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
{
int fd, got;
@@ -35633,7 +40118,7 @@ SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
** proleptic Gregorian calendar.
**
-** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
+** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
** cannot be found.
*/
static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
@@ -35740,7 +40225,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** To address the performance and cache coherency issues, proxy file locking
** changes the way database access is controlled by limiting access to a
** single host at a time and moving file locks off of the database file
-** and onto a proxy file on the local file system.
+** and onto a proxy file on the local file system.
**
**
** Using proxy locks
@@ -35766,19 +40251,19 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** actual proxy file name is generated from the name and path of the
** database file. For example:
**
-** For database path "/Users/me/foo.db"
+** For database path "/Users/me/foo.db"
** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
**
** Once a lock proxy is configured for a database connection, it can not
** be removed, however it may be switched to a different proxy path via
** the above APIs (assuming the conch file is not being held by another
-** connection or process).
+** connection or process).
**
**
** How proxy locking works
** -----------------------
**
-** Proxy file locking relies primarily on two new supporting files:
+** Proxy file locking relies primarily on two new supporting files:
**
** * conch file to limit access to the database file to a single host
** at a time
@@ -35805,11 +40290,11 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** host (the conch ensures that they all use the same local lock file).
**
** Requesting the lock proxy does not immediately take the conch, it is
-** only taken when the first request to lock database file is made.
+** only taken when the first request to lock database file is made.
** This matches the semantics of the traditional locking behavior, where
** opening a connection to a database file does not take a lock on it.
-** The shared lock and an open file descriptor are maintained until
-** the connection to the database is closed.
+** The shared lock and an open file descriptor are maintained until
+** the connection to the database is closed.
**
** The proxy file and the lock file are never deleted so they only need
** to be created the first time they are used.
@@ -35823,7 +40308,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
** automatically configured for proxy locking, lock files are
** named automatically using the same logic as
** PRAGMA lock_proxy_file=":auto:"
-**
+**
** SQLITE_PROXY_DEBUG
**
** Enables the logging of error messages during host id file
@@ -35838,8 +40323,8 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
**
** Permissions to use when creating a directory for storing the
** lock proxy files, only used when LOCKPROXYDIR is not set.
-**
-**
+**
+**
** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
** force proxy locking to be used for every database file opened, and 0
@@ -35849,12 +40334,12 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
*/
/*
-** Proxy locking is only available on MacOSX
+** Proxy locking is only available on MacOSX
*/
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
/*
-** The proxyLockingContext has the path and file structures for the remote
+** The proxyLockingContext has the path and file structures for the remote
** and local proxy files in it
*/
typedef struct proxyLockingContext proxyLockingContext;
@@ -35870,10 +40355,10 @@ struct proxyLockingContext {
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
};
-/*
-** The proxy lock file path for the database at dbPath is written into lPath,
+/*
+** The proxy lock file path for the database at dbPath is written into lPath,
** which must point to valid, writable memory large enough for a maxLen length
-** file path.
+** file path.
*/
static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
int len;
@@ -35890,7 +40375,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
lPath, errno, osGetpid(0)));
return SQLITE_IOERR_LOCK;
}
- len = strlcat(lPath, "sqliteplocks", maxLen);
+ len = strlcat(lPath, "sqliteplocks", maxLen);
}
# else
len = strlcpy(lPath, "/tmp/", maxLen);
@@ -35900,7 +40385,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
if( lPath[len-1]!='/' ){
len = strlcat(lPath, "/", maxLen);
}
-
+
/* transform the db path to a unique cache name */
dbLen = (int)strlen(dbPath);
for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){
@@ -35913,14 +40398,14 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
return SQLITE_OK;
}
-/*
+/*
** Creates the lock file and any missing directories in lockPath
*/
static int proxyCreateLockPath(const char *lockPath){
int i, len;
char buf[MAXPATHLEN];
int start = 0;
-
+
assert(lockPath!=NULL);
/* try to create all the intermediate directories */
len = (int)strlen(lockPath);
@@ -35928,7 +40413,7 @@ static int proxyCreateLockPath(const char *lockPath){
for( i=1; i<len; i++ ){
if( lockPath[i] == '/' && (i - start > 0) ){
/* only mkdir if leaf dir != "." or "/" or ".." */
- if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
+ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
|| (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
buf[i]='\0';
if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
@@ -35964,7 +40449,7 @@ static int proxyCreateUnixFile(
int fd = -1;
unixFile *pNew;
int rc = SQLITE_OK;
- int openFlags = O_RDWR | O_CREAT;
+ int openFlags = O_RDWR | O_CREAT | O_NOFOLLOW;
sqlite3_vfs dummyVfs;
int terrno = 0;
UnixUnusedFd *pUnused = NULL;
@@ -35994,7 +40479,7 @@ static int proxyCreateUnixFile(
}
}
if( fd<0 ){
- openFlags = O_RDONLY;
+ openFlags = O_RDONLY | O_NOFOLLOW;
fd = robust_open(path, openFlags, 0);
terrno = errno;
}
@@ -36005,13 +40490,13 @@ static int proxyCreateUnixFile(
switch (terrno) {
case EACCES:
return SQLITE_PERM;
- case EIO:
+ case EIO:
return SQLITE_IOERR_LOCK; /* even though it is the conch */
default:
return SQLITE_CANTOPEN_BKPT;
}
}
-
+
pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
if( pNew==NULL ){
rc = SQLITE_NOMEM_BKPT;
@@ -36024,14 +40509,14 @@ static int proxyCreateUnixFile(
dummyVfs.zName = "dummy";
pUnused->fd = fd;
pUnused->flags = openFlags;
- pNew->pUnused = pUnused;
-
+ pNew->pPreallocatedUnused = pUnused;
+
rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
if( rc==SQLITE_OK ){
*ppFile = pNew;
return SQLITE_OK;
}
-end_create_proxy:
+end_create_proxy:
robust_close(pNew, fd, __LINE__);
sqlite3_free(pNew);
sqlite3_free(pUnused);
@@ -36045,18 +40530,18 @@ SQLITE_API int sqlite3_hostid_num = 0;
#define PROXY_HOSTIDLEN 16 /* conch file host id length */
-#ifdef HAVE_GETHOSTUUID
+#if HAVE_GETHOSTUUID
/* Not always defined in the headers as it ought to be */
extern int gethostuuid(uuid_t id, const struct timespec *wait);
#endif
-/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
+/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
** bytes of writable memory.
*/
static int proxyGetHostID(unsigned char *pHostID, int *pError){
assert(PROXY_HOSTIDLEN == sizeof(uuid_t));
memset(pHostID, 0, PROXY_HOSTIDLEN);
-#ifdef HAVE_GETHOSTUUID
+#if HAVE_GETHOSTUUID
{
struct timespec timeout = {1, 0}; /* 1 sec timeout */
if( gethostuuid(pHostID, &timeout) ){
@@ -36076,7 +40561,7 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){
pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
}
#endif
-
+
return SQLITE_OK;
}
@@ -36087,14 +40572,14 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){
#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
-/*
-** Takes an open conch file, copies the contents to a new path and then moves
+/*
+** Takes an open conch file, copies the contents to a new path and then moves
** it back. The newly created file's file descriptor is assigned to the
-** conch file structure and finally the original conch file descriptor is
+** conch file structure and finally the original conch file descriptor is
** closed. Returns zero if successful.
*/
static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
unixFile *conchFile = pCtx->conchFile;
char tPath[MAXPATHLEN];
char buf[PROXY_MAXCONCHLEN];
@@ -36108,7 +40593,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
/* create a new path by replace the trailing '-conch' with '-break' */
pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
- if( pathLen>MAXPATHLEN || pathLen<6 ||
+ if( pathLen>MAXPATHLEN || pathLen<6 ||
(strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
goto end_breaklock;
@@ -36120,7 +40605,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
goto end_breaklock;
}
/* write it out to the temporary break file */
- fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL), 0);
+ fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW), 0);
if( fd<0 ){
sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
goto end_breaklock;
@@ -36150,24 +40635,24 @@ end_breaklock:
return rc;
}
-/* Take the requested lock on the conch file and break a stale lock if the
+/* Take the requested lock on the conch file and break a stale lock if the
** host id matches.
*/
static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
unixFile *conchFile = pCtx->conchFile;
int rc = SQLITE_OK;
int nTries = 0;
struct timespec conchModTime;
-
+
memset(&conchModTime, 0, sizeof(conchModTime));
do {
rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
nTries ++;
if( rc==SQLITE_BUSY ){
/* If the lock failed (busy):
- * 1st try: get the mod time of the conch, wait 0.5s and try again.
- * 2nd try: fail if the mod time changed or host id is different, wait
+ * 1st try: get the mod time of the conch, wait 0.5s and try again.
+ * 2nd try: fail if the mod time changed or host id is different, wait
* 10 sec and try again
* 3rd try: break the lock unless the mod time has changed.
*/
@@ -36176,20 +40661,20 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
storeLastErrno(pFile, errno);
return SQLITE_IOERR_LOCK;
}
-
+
if( nTries==1 ){
conchModTime = buf.st_mtimespec;
usleep(500000); /* wait 0.5 sec and try the lock again*/
- continue;
+ continue;
}
assert( nTries>1 );
- if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
+ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
return SQLITE_BUSY;
}
-
- if( nTries==2 ){
+
+ if( nTries==2 ){
char tBuf[PROXY_MAXCONCHLEN];
int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
if( len<0 ){
@@ -36206,9 +40691,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
return SQLITE_BUSY;
}
usleep(10000000); /* wait 10 sec and try the lock again */
- continue;
+ continue;
}
-
+
assert( nTries==3 );
if( 0==proxyBreakConchLock(pFile, myHostID) ){
rc = SQLITE_OK;
@@ -36221,19 +40706,19 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
}
}
} while( rc==SQLITE_BUSY && nTries<3 );
-
+
return rc;
}
-/* Takes the conch by taking a shared lock and read the contents conch, if
-** lockPath is non-NULL, the host ID and lock file path must match. A NULL
-** lockPath means that the lockPath in the conch file will be used if the
-** host IDs match, or a new lock path will be generated automatically
+/* Takes the conch by taking a shared lock and read the contents conch, if
+** lockPath is non-NULL, the host ID and lock file path must match. A NULL
+** lockPath means that the lockPath in the conch file will be used if the
+** host IDs match, or a new lock path will be generated automatically
** and written to the conch file.
*/
static int proxyTakeConch(unixFile *pFile){
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
-
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
+
if( pCtx->conchHeld!=0 ){
return SQLITE_OK;
}else{
@@ -36249,7 +40734,7 @@ static int proxyTakeConch(unixFile *pFile){
int readLen = 0;
int tryOldLockPath = 0;
int forceNewLockPath = 0;
-
+
OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
(pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
osGetpid(0)));
@@ -36270,21 +40755,21 @@ static int proxyTakeConch(unixFile *pFile){
storeLastErrno(pFile, conchFile->lastErrno);
rc = SQLITE_IOERR_READ;
goto end_takeconch;
- }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
+ }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
readBuf[0]!=(char)PROXY_CONCHVERSION ){
- /* a short read or version format mismatch means we need to create a new
- ** conch file.
+ /* a short read or version format mismatch means we need to create a new
+ ** conch file.
*/
createConch = 1;
}
/* if the host id matches and the lock path already exists in the conch
- ** we'll try to use the path there, if we can't open that path, we'll
- ** retry with a new auto-generated path
+ ** we'll try to use the path there, if we can't open that path, we'll
+ ** retry with a new auto-generated path
*/
do { /* in case we need to try again for an :auto: named lock file */
if( !createConch && !forceNewLockPath ){
- hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
+ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
PROXY_HOSTIDLEN);
/* if the conch has data compare the contents */
if( !pCtx->lockProxyPath ){
@@ -36293,7 +40778,7 @@ static int proxyTakeConch(unixFile *pFile){
*/
if( hostIdMatch ){
size_t pathLen = (readLen - PROXY_PATHINDEX);
-
+
if( pathLen>=MAXPATHLEN ){
pathLen=MAXPATHLEN-1;
}
@@ -36309,23 +40794,23 @@ static int proxyTakeConch(unixFile *pFile){
readLen-PROXY_PATHINDEX)
){
/* conch host and lock path match */
- goto end_takeconch;
+ goto end_takeconch;
}
}
-
+
/* if the conch isn't writable and doesn't match, we can't take it */
if( (conchFile->openFlags&O_RDWR) == 0 ){
rc = SQLITE_BUSY;
goto end_takeconch;
}
-
+
/* either the conch didn't match or we need to create a new one */
if( !pCtx->lockProxyPath ){
proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN);
tempLockPath = lockPath;
/* create a copy of the lock path _only_ if the conch is taken */
}
-
+
/* update conch with host and path (this will fail if other process
** has a shared lock already), if the host id matches, use the big
** stick.
@@ -36336,7 +40821,7 @@ static int proxyTakeConch(unixFile *pFile){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
- } else {
+ } else {
rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
}
}else{
@@ -36345,7 +40830,7 @@ static int proxyTakeConch(unixFile *pFile){
if( rc==SQLITE_OK ){
char writeBuffer[PROXY_MAXCONCHLEN];
int writeSize = 0;
-
+
writeBuffer[0] = (char)PROXY_CONCHVERSION;
memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
if( pCtx->lockProxyPath!=NULL ){
@@ -36358,8 +40843,8 @@ static int proxyTakeConch(unixFile *pFile){
robust_ftruncate(conchFile->h, writeSize);
rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
full_fsync(conchFile->h,0,0);
- /* If we created a new conch file (not just updated the contents of a
- ** valid conch file), try to match the permissions of the database
+ /* If we created a new conch file (not just updated the contents of a
+ ** valid conch file), try to match the permissions of the database
*/
if( rc==SQLITE_OK && createConch ){
struct stat buf;
@@ -36383,14 +40868,14 @@ static int proxyTakeConch(unixFile *pFile){
}
}else{
int code = errno;
- fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
+ fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
err, code, strerror(code));
#endif
}
}
}
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
-
+
end_takeconch:
OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
if( rc==SQLITE_OK && pFile->openFlags ){
@@ -36413,7 +40898,7 @@ static int proxyTakeConch(unixFile *pFile){
rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1);
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){
/* we couldn't create the proxy lock file with the old lock file path
- ** so try again via auto-naming
+ ** so try again via auto-naming
*/
forceNewLockPath = 1;
tryOldLockPath = 0;
@@ -36433,7 +40918,7 @@ static int proxyTakeConch(unixFile *pFile){
}
if( rc==SQLITE_OK ){
pCtx->conchHeld = 1;
-
+
if( pCtx->lockProxy->pMethod == &afpIoMethods ){
afpLockingContext *afpCtx;
afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext;
@@ -36445,7 +40930,7 @@ static int proxyTakeConch(unixFile *pFile){
OSTRACE(("TAKECONCH %d %s\n", conchFile->h,
rc==SQLITE_OK?"ok":"failed"));
return rc;
- } while (1); /* in case we need to retry the :auto: lock file -
+ } while (1); /* in case we need to retry the :auto: lock file -
** we should never get here except via the 'continue' call. */
}
}
@@ -36461,7 +40946,7 @@ static int proxyReleaseConch(unixFile *pFile){
pCtx = (proxyLockingContext *)pFile->lockingContext;
conchFile = pCtx->conchFile;
OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
osGetpid(0)));
if( pCtx->conchHeld>0 ){
rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
@@ -36489,13 +40974,13 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
char *conchPath; /* buffer in which to construct conch name */
/* Allocate space for the conch filename and initialize the name to
- ** the name of the original database file. */
+ ** the name of the original database file. */
*pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
if( conchPath==0 ){
return SQLITE_NOMEM_BKPT;
}
memcpy(conchPath, dbPath, len+1);
-
+
/* now insert a "." before the last / character */
for( i=(len-1); i>=0; i-- ){
if( conchPath[i]=='/' ){
@@ -36518,7 +41003,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
/* Takes a fully configured proxy locking-style unix file and switches
-** the local lock file path
+** the local lock file path
*/
static int switchLockProxyPath(unixFile *pFile, const char *path) {
proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
@@ -36527,7 +41012,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
- }
+ }
/* nothing to do if the path is NULL, :auto: or matches the existing path */
if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ||
@@ -36545,7 +41030,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
sqlite3_free(oldPath);
pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
}
-
+
return rc;
}
@@ -36559,7 +41044,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
#if defined(__APPLE__)
if( pFile->pMethod == &afpIoMethods ){
- /* afp style keeps a reference to the db path in the filePath field
+ /* afp style keeps a reference to the db path in the filePath field
** of the struct */
assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath,
@@ -36580,9 +41065,9 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
}
/*
-** Takes an already filled in unix file and alters it so all file locking
+** Takes an already filled in unix file and alters it so all file locking
** will be performed on the local proxy lock file. The following fields
-** are preserved in the locking context so that they can be restored and
+** are preserved in the locking context so that they can be restored and
** the unix structure properly cleaned up at close time:
** ->lockingContext
** ->pMethod
@@ -36592,7 +41077,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
char dbPath[MAXPATHLEN+1]; /* Name of the database file */
char *lockPath=NULL;
int rc = SQLITE_OK;
-
+
if( pFile->eFileLock!=NO_LOCK ){
return SQLITE_BUSY;
}
@@ -36602,7 +41087,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
}else{
lockPath=(char *)path;
}
-
+
OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
(lockPath ? lockPath : ":auto:"), osGetpid(0)));
@@ -36636,7 +41121,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
rc = SQLITE_OK;
}
}
- }
+ }
if( rc==SQLITE_OK && lockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
}
@@ -36648,7 +41133,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
}
}
if( rc==SQLITE_OK ){
- /* all memory is allocated, proxys are created and assigned,
+ /* all memory is allocated, proxys are created and assigned,
** switch the locking context and pMethod then return.
*/
pCtx->oldLockingContext = pFile->lockingContext;
@@ -36656,12 +41141,12 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
pCtx->pOldMethod = pFile->pMethod;
pFile->pMethod = &proxyIoMethods;
}else{
- if( pCtx->conchFile ){
+ if( pCtx->conchFile ){
pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
sqlite3_free(pCtx->conchFile);
}
sqlite3DbFree(0, pCtx->lockProxyPath);
- sqlite3_free(pCtx->conchFilePath);
+ sqlite3_free(pCtx->conchFilePath);
sqlite3_free(pCtx);
}
OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
@@ -36699,7 +41184,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
if( isProxyStyle ){
/* turn off proxy locking - not supported. If support is added for
** switching proxy locking mode off then it will need to fail if
- ** the journal mode is WAL mode.
+ ** the journal mode is WAL mode.
*/
rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
}else{
@@ -36709,9 +41194,9 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
}else{
const char *proxyPath = (const char *)pArg;
if( isProxyStyle ){
- proxyLockingContext *pCtx =
+ proxyLockingContext *pCtx =
(proxyLockingContext*)pFile->lockingContext;
- if( !strcmp(pArg, ":auto:")
+ if( !strcmp(pArg, ":auto:")
|| (pCtx->lockProxyPath &&
!strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN))
){
@@ -36730,7 +41215,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
assert( 0 ); /* The call assures that only valid opcodes are sent */
}
}
- /*NOTREACHED*/
+ /*NOTREACHED*/ assert(0);
return SQLITE_ERROR;
}
@@ -36836,7 +41321,7 @@ static int proxyClose(sqlite3_file *id) {
unixFile *lockProxy = pCtx->lockProxy;
unixFile *conchFile = pCtx->conchFile;
int rc = SQLITE_OK;
-
+
if( lockProxy ){
rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK);
if( rc ) return rc;
@@ -36873,7 +41358,7 @@ static int proxyClose(sqlite3_file *id) {
** The proxy locking style is intended for use with AFP filesystems.
** And since AFP is only supported on MacOSX, the proxy locking is also
** restricted to MacOSX.
-**
+**
**
******************* End of the proxy lock implementation **********************
******************************************************************************/
@@ -36891,8 +41376,8 @@ static int proxyClose(sqlite3_file *id) {
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
-SQLITE_API int sqlite3_os_init(void){
- /*
+SQLITE_API int sqlite3_os_init(void){
+ /*
** The following macro defines an initializer for an sqlite3_vfs object.
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
** to the "finder" function. (pAppData is a pointer to a pointer because
@@ -36908,7 +41393,7 @@ SQLITE_API int sqlite3_os_init(void){
**
** Most finders simply return a pointer to a fixed sqlite3_io_methods
** object. But the "autolockIoFinder" available on MacOSX does a little
- ** more than that; it looks at the filesystem type that hosts the
+ ** more than that; it looks at the filesystem type that hosts the
** database file and tries to choose an locking method appropriate for
** that filesystem time.
*/
@@ -36974,13 +41459,14 @@ SQLITE_API int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
- assert( ArraySize(aSyscall)==28 );
+ assert( ArraySize(aSyscall)==29 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
sqlite3_vfs_register(&aVfs[i], i==0);
}
- return SQLITE_OK;
+ unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
+ return SQLITE_OK;
}
/*
@@ -36990,10 +41476,11 @@ SQLITE_API int sqlite3_os_init(void){
** to release dynamically allocated objects. But not on unix.
** This routine is a no-op for unix.
*/
-SQLITE_API int sqlite3_os_end(void){
- return SQLITE_OK;
+SQLITE_API int sqlite3_os_end(void){
+ unixBigLock = 0;
+ return SQLITE_OK;
}
-
+
#endif /* SQLITE_OS_UNIX */
/************** End of os_unix.c *********************************************/
@@ -37076,7 +41563,7 @@ SQLITE_API int sqlite3_os_end(void){
******************************************************************************
**
** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 class CPUs.
+** counters for x86 and x86_64 class CPUs.
*/
#ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H
@@ -37087,8 +41574,9 @@ SQLITE_API int sqlite3_os_end(void){
** processor and returns that value. This can be used for high-res
** profiling.
*/
-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
@@ -37109,15 +41597,15 @@ SQLITE_API int sqlite3_os_end(void){
#endif
-#elif (defined(__GNUC__) && defined(__x86_64__))
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
-#elif (defined(__GNUC__) && defined(__ppc__))
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
@@ -37134,14 +41622,13 @@ SQLITE_API int sqlite3_os_end(void){
#else
- #error Need implementation of sqlite3Hwtime() for your platform.
-
/*
- ** To compile without implementing sqlite3Hwtime() for your platform,
- ** you can remove the above #error and use the following
- ** stub function. You will lose timing support for many
- ** of the debugging and testing utilities, but it should at
- ** least compile and run.
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlite3Hwtime() routine.
+ **
+ ** sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
*/
SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
@@ -37482,8 +41969,7 @@ struct winFile {
int nFetchOut; /* Number of outstanding xFetch references */
HANDLE hMap; /* Handle for accessing memory mapping */
void *pMapRegion; /* Area memory mapped */
- sqlite3_int64 mmapSize; /* Usable size of mapped region */
- sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
+ sqlite3_int64 mmapSize; /* Size of mapped region */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
#endif
};
@@ -37514,22 +42000,6 @@ struct winVfsAppData {
#endif
/*
- * The value used with sqlite3_win32_set_directory() to specify that
- * the data directory should be changed.
- */
-#ifndef SQLITE_WIN32_DATA_DIRECTORY_TYPE
-# define SQLITE_WIN32_DATA_DIRECTORY_TYPE (1)
-#endif
-
-/*
- * The value used with sqlite3_win32_set_directory() to specify that
- * the temporary directory should be changed.
- */
-#ifndef SQLITE_WIN32_TEMP_DIRECTORY_TYPE
-# define SQLITE_WIN32_TEMP_DIRECTORY_TYPE (2)
-#endif
-
-/*
* If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
* various Win32 API heap functions instead of our own.
*/
@@ -37550,7 +42020,34 @@ struct winVfsAppData {
******************************************************************************
*/
#ifndef SQLITE_WIN32_HEAP_CREATE
-# define SQLITE_WIN32_HEAP_CREATE (TRUE)
+# define SQLITE_WIN32_HEAP_CREATE (TRUE)
+#endif
+
+/*
+ * This is the maximum possible initial size of the Win32-specific heap, in
+ * bytes.
+ */
+#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE
+# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U)
+#endif
+
+/*
+ * This is the extra space for the initial size of the Win32-specific heap,
+ * in bytes. This value may be zero.
+ */
+#ifndef SQLITE_WIN32_HEAP_INIT_EXTRA
+# define SQLITE_WIN32_HEAP_INIT_EXTRA (4194304)
+#endif
+
+/*
+ * Calculate the maximum legal cache size, in pages, based on the maximum
+ * possible initial heap size and the default page size, setting aside the
+ * needed extra space.
+ */
+#ifndef SQLITE_WIN32_MAX_CACHE_SIZE
+# define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \
+ (SQLITE_WIN32_HEAP_INIT_EXTRA)) / \
+ (SQLITE_DEFAULT_PAGE_SIZE))
#endif
/*
@@ -37559,25 +42056,36 @@ struct winVfsAppData {
*/
#ifndef SQLITE_WIN32_CACHE_SIZE
# if SQLITE_DEFAULT_CACHE_SIZE>=0
-# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
+# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
# else
-# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
+# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
# endif
#endif
/*
+ * Make sure that the calculated cache size, in pages, cannot cause the
+ * initial size of the Win32-specific heap to exceed the maximum amount
+ * of memory that can be specified in the call to HeapCreate.
+ */
+#if SQLITE_WIN32_CACHE_SIZE>SQLITE_WIN32_MAX_CACHE_SIZE
+# undef SQLITE_WIN32_CACHE_SIZE
+# define SQLITE_WIN32_CACHE_SIZE (2000)
+#endif
+
+/*
* The initial size of the Win32-specific heap. This value may be zero.
*/
#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
-# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \
- (SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
+# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \
+ (SQLITE_DEFAULT_PAGE_SIZE) + \
+ (SQLITE_WIN32_HEAP_INIT_EXTRA))
#endif
/*
* The maximum size of the Win32-specific heap. This value may be zero.
*/
#ifndef SQLITE_WIN32_HEAP_MAX_SIZE
-# define SQLITE_WIN32_HEAP_MAX_SIZE (0)
+# define SQLITE_WIN32_HEAP_MAX_SIZE (0)
#endif
/*
@@ -37585,7 +42093,7 @@ struct winVfsAppData {
* zero for the default behavior.
*/
#ifndef SQLITE_WIN32_HEAP_FLAGS
-# define SQLITE_WIN32_HEAP_FLAGS (0)
+# define SQLITE_WIN32_HEAP_FLAGS (0)
#endif
@@ -38467,17 +42975,17 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
*/
SQLITE_API int sqlite3_win32_reset_heap(){
int rc;
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
- sqlite3_mutex_enter(pMaster);
+ sqlite3_mutex_enter(pMainMtx);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
/*
** At this point, there should be no outstanding memory allocations on
- ** the heap. Also, since both the master and memsys locks are currently
+ ** the heap. Also, since both the main and memsys locks are currently
** being held by us, no other function (i.e. from another thread) should
** be able to even access the heap. Attempt to destroy and recreate our
** isolated Win32 native heap now.
@@ -38500,7 +43008,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){
rc = SQLITE_BUSY;
}
sqlite3_mutex_leave(pMem);
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
return rc;
}
#endif /* SQLITE_WIN32_MALLOC */
@@ -39087,13 +43595,13 @@ SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
}
/*
-** This function sets the data directory or the temporary directory based on
-** the provided arguments. The type argument must be 1 in order to set the
-** data directory or 2 in order to set the temporary directory. The zValue
-** argument is the name of the directory to use. The return value will be
-** SQLITE_OK if successful.
+** This function is the same as sqlite3_win32_set_directory (below); however,
+** it accepts a UTF-8 string.
*/
-SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
+SQLITE_API int sqlite3_win32_set_directory8(
+ unsigned long type, /* Identifier for directory being set or reset */
+ const char *zValue /* New value for directory being set or reset */
+){
char **ppDirectory = 0;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
@@ -39109,21 +43617,54 @@ SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
);
assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) );
if( ppDirectory ){
- char *zValueUtf8 = 0;
+ char *zCopy = 0;
if( zValue && zValue[0] ){
- zValueUtf8 = winUnicodeToUtf8(zValue);
- if ( zValueUtf8==0 ){
+ zCopy = sqlite3_mprintf("%s", zValue);
+ if ( zCopy==0 ){
return SQLITE_NOMEM_BKPT;
}
}
sqlite3_free(*ppDirectory);
- *ppDirectory = zValueUtf8;
+ *ppDirectory = zCopy;
return SQLITE_OK;
}
return SQLITE_ERROR;
}
/*
+** This function is the same as sqlite3_win32_set_directory (below); however,
+** it accepts a UTF-16 string.
+*/
+SQLITE_API int sqlite3_win32_set_directory16(
+ unsigned long type, /* Identifier for directory being set or reset */
+ const void *zValue /* New value for directory being set or reset */
+){
+ int rc;
+ char *zUtf8 = 0;
+ if( zValue ){
+ zUtf8 = sqlite3_win32_unicode_to_utf8(zValue);
+ if( zUtf8==0 ) return SQLITE_NOMEM_BKPT;
+ }
+ rc = sqlite3_win32_set_directory8(type, zUtf8);
+ if( zUtf8 ) sqlite3_free(zUtf8);
+ return rc;
+}
+
+/*
+** This function sets the data directory or the temporary directory based on
+** the provided arguments. The type argument must be 1 in order to set the
+** data directory or 2 in order to set the temporary directory. The zValue
+** argument is the name of the directory to use. The return value will be
+** SQLITE_OK if successful.
+*/
+SQLITE_API int sqlite3_win32_set_directory(
+ unsigned long type, /* Identifier for directory being set or reset */
+ void *zValue /* New value for directory being set or reset */
+){
+ return sqlite3_win32_set_directory16(type, zValue);
+}
+
+/*
** The return value of winGetLastErrorMsg
** is zero if the error message fits in the buffer, or non-zero
** otherwise (if the message was truncated).
@@ -40047,6 +44588,29 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */
DWORD lastErrno;
+#if SQLITE_MAX_MMAP_SIZE>0
+ sqlite3_int64 oldMmapSize;
+ if( pFile->nFetchOut>0 ){
+ /* File truncation is a no-op if there are outstanding memory mapped
+ ** pages. This is because truncating the file means temporarily unmapping
+ ** the file, and that might delete memory out from under existing cursors.
+ **
+ ** This can result in incremental vacuum not truncating the file,
+ ** if there is an active read cursor when the incremental vacuum occurs.
+ ** No real harm comes of this - the database file is not corrupted,
+ ** though some folks might complain that the file is bigger than it
+ ** needs to be.
+ **
+ ** The only feasible work-around is to defer the truncation until after
+ ** all references to memory-mapped content are closed. That is doable,
+ ** but involves adding a few branches in the common write code path which
+ ** could slow down normal operations slightly. Hence, we have decided for
+ ** now to simply make trancations a no-op if there are pending reads. We
+ ** can maybe revisit this decision in the future.
+ */
+ return SQLITE_OK;
+ }
+#endif
assert( pFile );
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
@@ -40062,6 +44626,15 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
+#if SQLITE_MAX_MMAP_SIZE>0
+ if( pFile->pMapRegion ){
+ oldMmapSize = pFile->mmapSize;
+ }else{
+ oldMmapSize = 0;
+ }
+ winUnmapfile(pFile);
+#endif
+
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( winSeekFile(pFile, nByte) ){
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
@@ -40074,12 +44647,12 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
}
#if SQLITE_MAX_MMAP_SIZE>0
- /* If the file was truncated to a size smaller than the currently
- ** mapped region, reduce the effective mapping size as well. SQLite will
- ** use read() and write() to access data beyond this point from now on.
- */
- if( pFile->pMapRegion && nByte<pFile->mmapSize ){
- pFile->mmapSize = nByte;
+ if( rc==SQLITE_OK && oldMmapSize>0 ){
+ if( oldMmapSize>nByte ){
+ winMapfile(pFile, -1);
+ }else{
+ winMapfile(pFile, oldMmapSize);
+ }
}
#endif
@@ -40614,6 +45187,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
/* Forward references to VFS helper methods used for temporary files */
static int winGetTempname(sqlite3_vfs *, char **);
static int winIsDir(const void *);
+static BOOL winIsLongPathPrefix(const char *);
static BOOL winIsDriveLetterAndColon(const char *);
/*
@@ -40719,6 +45293,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
+
+ /* The value of newLimit may be eventually cast to (SIZE_T) and passed
+ ** to MapViewOfFile(). Restrict its value to 2GB if (SIZE_T) is not at
+ ** least a 64-bit type. */
+ if( newLimit>0 && sizeof(SIZE_T)<8 ){
+ newLimit = (newLimit & 0x7FFFFFFF);
+ }
+
*(i64*)pArg = pFile->mmapSizeMax;
if( newLimit>=0 && newLimit!=pFile->mmapSizeMax && pFile->nFetchOut==0 ){
pFile->mmapSizeMax = newLimit;
@@ -40783,15 +45365,16 @@ static SYSTEM_INFO winSysInfo;
** assert( winShmMutexHeld() );
** winShmLeaveMutex()
*/
+static sqlite3_mutex *winBigLock = 0;
static void winShmEnterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ sqlite3_mutex_enter(winBigLock);
}
static void winShmLeaveMutex(void){
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ sqlite3_mutex_leave(winBigLock);
}
#ifndef NDEBUG
static int winShmMutexHeld(void) {
- return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
+ return sqlite3_mutex_held(winBigLock);
}
#endif
@@ -40825,6 +45408,9 @@ struct winShmNode {
int szRegion; /* Size of shared-memory regions */
int nRegion; /* Size of array apRegion */
+ u8 isReadonly; /* True if read-only */
+ u8 isUnlocked; /* True if no DMS lock held */
+
struct ShmRegion {
HANDLE hMap; /* File handle from CreateFileMapping */
void *pMap;
@@ -40891,7 +45477,7 @@ static int winShmSystemLock(
int rc = 0; /* Result code form Lock/UnlockFileEx() */
/* Access to the winShmNode object is serialized by the caller */
- assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
+ assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
pFile->hFile.h, lockType, ofst, nByte));
@@ -40973,6 +45559,37 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
}
/*
+** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
+** take it now. Return SQLITE_OK if successful, or an SQLite error
+** code otherwise.
+**
+** If the DMS cannot be locked because this is a readonly_shm=1
+** connection and no other process already holds a lock, return
+** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
+*/
+static int winLockSharedMemory(winShmNode *pShmNode){
+ int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
+
+ if( rc==SQLITE_OK ){
+ if( pShmNode->isReadonly ){
+ pShmNode->isUnlocked = 1;
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
+ return SQLITE_READONLY_CANTINIT;
+ }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
+ return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
+ "winLockSharedMemory", pShmNode->zFilename);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
+ }
+
+ return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
+}
+
+/*
** Open the shared-memory area associated with database file pDbFd.
**
** When opening a new shared-memory file, if no other instances of that
@@ -40981,9 +45598,9 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
*/
static int winOpenSharedMemory(winFile *pDbFd){
struct winShm *p; /* The connection to be opened */
- struct winShmNode *pShmNode = 0; /* The underlying mmapped file */
- int rc; /* Result code */
- struct winShmNode *pNew; /* Newly allocated winShmNode */
+ winShmNode *pShmNode = 0; /* The underlying mmapped file */
+ int rc = SQLITE_OK; /* Result code */
+ winShmNode *pNew; /* Newly allocated winShmNode */
int nName; /* Size of zName in bytes */
assert( pDbFd->pShm==0 ); /* Not previously opened */
@@ -41016,6 +45633,9 @@ static int winOpenSharedMemory(winFile *pDbFd){
if( pShmNode ){
sqlite3_free(pNew);
}else{
+ int inFlags = SQLITE_OPEN_WAL;
+ int outFlags = 0;
+
pShmNode = pNew;
pNew = 0;
((winFile*)(&pShmNode->hFile))->h = INVALID_HANDLE_VALUE;
@@ -41030,30 +45650,23 @@ static int winOpenSharedMemory(winFile *pDbFd){
}
}
- rc = winOpen(pDbFd->pVfs,
- pShmNode->zFilename, /* Name of the file (UTF-8) */
- (sqlite3_file*)&pShmNode->hFile, /* File handle here */
- SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
- 0);
- if( SQLITE_OK!=rc ){
+ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
+ inFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
+ }else{
+ inFlags |= SQLITE_OPEN_READONLY;
+ }
+ rc = winOpen(pDbFd->pVfs, pShmNode->zFilename,
+ (sqlite3_file*)&pShmNode->hFile,
+ inFlags, &outFlags);
+ if( rc!=SQLITE_OK ){
+ rc = winLogError(rc, osGetLastError(), "winOpenShm",
+ pShmNode->zFilename);
goto shm_open_err;
}
+ if( outFlags==SQLITE_OPEN_READONLY ) pShmNode->isReadonly = 1;
- /* Check to see if another process is holding the dead-man switch.
- ** If not, truncate the file to zero length.
- */
- if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
- rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
- if( rc!=SQLITE_OK ){
- rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
- "winOpenShm", pDbFd->zPath);
- }
- }
- if( rc==SQLITE_OK ){
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
- rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
- }
- if( rc ) goto shm_open_err;
+ rc = winLockSharedMemory(pShmNode);
+ if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err;
}
/* Make the new connection a child of the winShmNode */
@@ -41076,7 +45689,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
p->pNext = pShmNode->pFirst;
pShmNode->pFirst = p;
sqlite3_mutex_leave(pShmNode->mutex);
- return SQLITE_OK;
+ return rc;
/* Jump here on any error */
shm_open_err:
@@ -41280,16 +45893,24 @@ static int winShmMap(
winFile *pDbFd = (winFile*)fd;
winShm *pShm = pDbFd->pShm;
winShmNode *pShmNode;
+ DWORD protect = PAGE_READWRITE;
+ DWORD flags = FILE_MAP_WRITE | FILE_MAP_READ;
int rc = SQLITE_OK;
if( !pShm ){
rc = winOpenSharedMemory(pDbFd);
if( rc!=SQLITE_OK ) return rc;
pShm = pDbFd->pShm;
+ assert( pShm!=0 );
}
pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
+ if( pShmNode->isUnlocked ){
+ rc = winLockSharedMemory(pShmNode);
+ if( rc!=SQLITE_OK ) goto shmpage_out;
+ pShmNode->isUnlocked = 0;
+ }
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
if( pShmNode->nRegion<=iRegion ){
@@ -41336,21 +45957,26 @@ static int winShmMap(
}
pShmNode->aRegion = apNew;
+ if( pShmNode->isReadonly ){
+ protect = PAGE_READONLY;
+ flags = FILE_MAP_READ;
+ }
+
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(pShmNode->hFile.h,
- NULL, PAGE_READWRITE, nByte, NULL
+ NULL, protect, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_WIDE)
hMap = osCreateFileMappingW(pShmNode->hFile.h,
- NULL, PAGE_READWRITE, 0, nByte, NULL
+ NULL, protect, 0, nByte, NULL
);
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
hMap = osCreateFileMappingA(pShmNode->hFile.h,
- NULL, PAGE_READWRITE, 0, nByte, NULL
+ NULL, protect, 0, nByte, NULL
);
#endif
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
@@ -41360,11 +45986,11 @@ static int winShmMap(
int iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
#if SQLITE_OS_WINRT
- pMap = osMapViewOfFileFromApp(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+ pMap = osMapViewOfFileFromApp(hMap, flags,
iOffset - iOffsetShift, szRegion + iOffsetShift
);
#else
- pMap = osMapViewOfFile(hMap, FILE_MAP_WRITE | FILE_MAP_READ,
+ pMap = osMapViewOfFile(hMap, flags,
0, iOffset - iOffsetShift, szRegion + iOffsetShift
);
#endif
@@ -41395,6 +46021,7 @@ shmpage_out:
}else{
*pp = 0;
}
+ if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY;
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}
@@ -41413,9 +46040,9 @@ shmpage_out:
static int winUnmapfile(winFile *pFile){
assert( pFile!=0 );
OSTRACE(("UNMAP-FILE pid=%lu, pFile=%p, hMap=%p, pMapRegion=%p, "
- "mmapSize=%lld, mmapSizeActual=%lld, mmapSizeMax=%lld\n",
+ "mmapSize=%lld, mmapSizeMax=%lld\n",
osGetCurrentProcessId(), pFile, pFile->hMap, pFile->pMapRegion,
- pFile->mmapSize, pFile->mmapSizeActual, pFile->mmapSizeMax));
+ pFile->mmapSize, pFile->mmapSizeMax));
if( pFile->pMapRegion ){
if( !osUnmapViewOfFile(pFile->pMapRegion) ){
pFile->lastErrno = osGetLastError();
@@ -41427,7 +46054,6 @@ static int winUnmapfile(winFile *pFile){
}
pFile->pMapRegion = 0;
pFile->mmapSize = 0;
- pFile->mmapSizeActual = 0;
}
if( pFile->hMap!=NULL ){
if( !osCloseHandle(pFile->hMap) ){
@@ -41538,7 +46164,6 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
}
pFd->pMapRegion = pNew;
pFd->mmapSize = nMap;
- pFd->mmapSizeActual = nMap;
}
OSTRACE(("MAP-FILE pid=%lu, pFile=%p, rc=SQLITE_OK\n",
@@ -41579,6 +46204,7 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
}
}
if( pFd->mmapSize >= iOff+nAmt ){
+ assert( pFd->pMapRegion!=0 );
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
@@ -42031,6 +46657,14 @@ static int winIsDir(const void *zConverted){
return (attr!=INVALID_FILE_ATTRIBUTES) && (attr&FILE_ATTRIBUTE_DIRECTORY);
}
+/* forward reference */
+static int winAccess(
+ sqlite3_vfs *pVfs, /* Not used on win32 */
+ const char *zFilename, /* Name of file to check */
+ int flags, /* Type of test to make on this file */
+ int *pResOut /* OUT: Result */
+);
+
/*
** Open a file.
*/
@@ -42074,7 +46708,7 @@ static int winOpen(
#ifndef NDEBUG
int isOpenJournal = (isCreate && (
- eType==SQLITE_OPEN_MASTER_JOURNAL
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
));
@@ -42095,17 +46729,17 @@ static int winOpen(
assert(isExclusive==0 || isCreate);
assert(isDelete==0 || isCreate);
- /* The main DB, main journal, WAL file and master journal are never
+ /* The main DB, main journal, WAL file and super-journal are never
** automatically deleted. Nor are they ever temporary files. */
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
/* Assert that the upper layer has set one of the "file-type" flags. */
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
);
@@ -42207,37 +46841,58 @@ static int winOpen(
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extendedParameters.lpSecurityAttributes = NULL;
extendedParameters.hTemplateFile = NULL;
- while( (h = osCreateFile2((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode,
- dwCreationDisposition,
- &extendedParameters))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFile2((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode,
+ dwCreationDisposition,
+ &extendedParameters);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int rc2, isRO = 0;
+ sqlite3BeginBenignMalloc();
+ rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ sqlite3EndBenignMalloc();
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
#else
- while( (h = osCreateFileW((LPCWSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFileW((LPCWSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int rc2, isRO = 0;
+ sqlite3BeginBenignMalloc();
+ rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ sqlite3EndBenignMalloc();
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
#endif
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- while( (h = osCreateFileA((LPCSTR)zConverted,
- dwDesiredAccess,
- dwShareMode, NULL,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- NULL))==INVALID_HANDLE_VALUE &&
- winRetryIoerr(&cnt, &lastErrno) ){
- /* Noop */
- }
+ do{
+ h = osCreateFileA((LPCSTR)zConverted,
+ dwDesiredAccess,
+ dwShareMode, NULL,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ NULL);
+ if( h!=INVALID_HANDLE_VALUE ) break;
+ if( isReadWrite ){
+ int rc2, isRO = 0;
+ sqlite3BeginBenignMalloc();
+ rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ sqlite3EndBenignMalloc();
+ if( rc2==SQLITE_OK && isRO ) break;
+ }
+ }while( winRetryIoerr(&cnt, &lastErrno) );
}
#endif
winLogIoerr(cnt, __LINE__);
@@ -42246,8 +46901,6 @@ static int winOpen(
dwDesiredAccess, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
if( h==INVALID_HANDLE_VALUE ){
- pFile->lastErrno = lastErrno;
- winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
sqlite3_free(zConverted);
sqlite3_free(zTmpname);
if( isReadWrite && !isExclusive ){
@@ -42256,6 +46909,8 @@ static int winOpen(
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
pOutFlags);
}else{
+ pFile->lastErrno = lastErrno;
+ winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name);
return SQLITE_CANTOPEN_BKPT;
}
}
@@ -42296,13 +46951,15 @@ static int winOpen(
}
sqlite3_free(zTmpname);
- pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
+ id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
pFile->pVfs = pVfs;
pFile->h = h;
if( isReadonly ){
pFile->ctrlFlags |= WINFILE_RDONLY;
}
- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
+ if( (flags & SQLITE_OPEN_MAIN_DB)
+ && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
+ ){
pFile->ctrlFlags |= WINFILE_PSOW;
}
pFile->lastErrno = NO_ERROR;
@@ -42311,7 +46968,6 @@ static int winOpen(
pFile->hMap = NULL;
pFile->pMapRegion = 0;
pFile->mmapSize = 0;
- pFile->mmapSizeActual = 0;
pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
#endif
@@ -42514,6 +47170,17 @@ static int winAccess(
}
/*
+** Returns non-zero if the specified path name starts with the "long path"
+** prefix.
+*/
+static BOOL winIsLongPathPrefix(
+ const char *zPathname
+){
+ return ( zPathname[0]=='\\' && zPathname[1]=='\\'
+ && zPathname[2]=='?' && zPathname[3]=='\\' );
+}
+
+/*
** Returns non-zero if the specified path name starts with a drive letter
** followed by a colon character.
*/
@@ -42577,10 +47244,11 @@ static int winFullPathname(
char *zOut;
#endif
- /* If this path name begins with "/X:", where "X" is any alphabetic
- ** character, discard the initial "/" from the pathname.
+ /* If this path name begins with "/X:" or "\\?\", where "X" is any
+ ** alphabetic character, discard the initial "/" from the pathname.
*/
- if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
+ if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
+ || winIsLongPathPrefix(zRelative+1)) ){
zRelative++;
}
@@ -42848,9 +47516,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
EntropyGatherer e;
UNUSED_PARAMETER(pVfs);
memset(zBuf, 0, nBuf);
-#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
- rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
e.a = (unsigned char*)zBuf;
e.na = nBuf;
e.nXor = 0;
@@ -43145,6 +47810,10 @@ SQLITE_API int sqlite3_os_init(void){
sqlite3_vfs_register(&winLongPathNolockVfs, 0);
#endif
+#ifndef SQLITE_OMIT_WAL
+ winBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
+#endif
+
return SQLITE_OK;
}
@@ -43155,12 +47824,644 @@ SQLITE_API int sqlite3_os_end(void){
sleepObj = NULL;
}
#endif
+
+#ifndef SQLITE_OMIT_WAL
+ winBigLock = 0;
+#endif
+
return SQLITE_OK;
}
#endif /* SQLITE_OS_WIN */
/************** End of os_win.c **********************************************/
+/************** Begin file memdb.c *******************************************/
+/*
+** 2016-09-07
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file implements an in-memory VFS. A database is held as a contiguous
+** block of memory.
+**
+** This file also implements interface sqlite3_serialize() and
+** sqlite3_deserialize().
+*/
+/* #include "sqliteInt.h" */
+#ifdef SQLITE_ENABLE_DESERIALIZE
+
+/*
+** Forward declaration of objects used by this utility
+*/
+typedef struct sqlite3_vfs MemVfs;
+typedef struct MemFile MemFile;
+
+/* Access to a lower-level VFS that (might) implement dynamic loading,
+** access to randomness, etc.
+*/
+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
+
+/* An open file */
+struct MemFile {
+ sqlite3_file base; /* IO methods */
+ sqlite3_int64 sz; /* Size of the file */
+ sqlite3_int64 szAlloc; /* Space allocated to aData */
+ sqlite3_int64 szMax; /* Maximum allowed size of the file */
+ unsigned char *aData; /* content of the file */
+ int nMmap; /* Number of memory mapped pages */
+ unsigned mFlags; /* Flags */
+ int eLock; /* Most recent lock against this file */
+};
+
+/*
+** Methods for MemFile
+*/
+static int memdbClose(sqlite3_file*);
+static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
+static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
+static int memdbSync(sqlite3_file*, int flags);
+static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
+static int memdbLock(sqlite3_file*, int);
+/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
+static int memdbFileControl(sqlite3_file*, int op, void *pArg);
+/* static int memdbSectorSize(sqlite3_file*); // not used */
+static int memdbDeviceCharacteristics(sqlite3_file*);
+static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
+static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
+
+/*
+** Methods for MemVfs
+*/
+static int memdbOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+/* static int memdbDelete(sqlite3_vfs*, const char *zName, int syncDir); */
+static int memdbAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int memdbFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *memdbDlOpen(sqlite3_vfs*, const char *zFilename);
+static void memdbDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
+static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
+static void memdbDlClose(sqlite3_vfs*, void*);
+static int memdbRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int memdbSleep(sqlite3_vfs*, int microseconds);
+/* static int memdbCurrentTime(sqlite3_vfs*, double*); */
+static int memdbGetLastError(sqlite3_vfs*, int, char *);
+static int memdbCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+
+static sqlite3_vfs memdb_vfs = {
+ 2, /* iVersion */
+ 0, /* szOsFile (set when registered) */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "memdb", /* zName */
+ 0, /* pAppData (set when registered) */
+ memdbOpen, /* xOpen */
+ 0, /* memdbDelete, */ /* xDelete */
+ memdbAccess, /* xAccess */
+ memdbFullPathname, /* xFullPathname */
+ memdbDlOpen, /* xDlOpen */
+ memdbDlError, /* xDlError */
+ memdbDlSym, /* xDlSym */
+ memdbDlClose, /* xDlClose */
+ memdbRandomness, /* xRandomness */
+ memdbSleep, /* xSleep */
+ 0, /* memdbCurrentTime, */ /* xCurrentTime */
+ memdbGetLastError, /* xGetLastError */
+ memdbCurrentTimeInt64 /* xCurrentTimeInt64 */
+};
+
+static const sqlite3_io_methods memdb_io_methods = {
+ 3, /* iVersion */
+ memdbClose, /* xClose */
+ memdbRead, /* xRead */
+ memdbWrite, /* xWrite */
+ memdbTruncate, /* xTruncate */
+ memdbSync, /* xSync */
+ memdbFileSize, /* xFileSize */
+ memdbLock, /* xLock */
+ memdbLock, /* xUnlock - same as xLock in this case */
+ 0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
+ memdbFileControl, /* xFileControl */
+ 0, /* memdbSectorSize,*/ /* xSectorSize */
+ memdbDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ memdbFetch, /* xFetch */
+ memdbUnfetch /* xUnfetch */
+};
+
+
+
+/*
+** Close an memdb-file.
+**
+** The pData pointer is owned by the application, so there is nothing
+** to free.
+*/
+static int memdbClose(sqlite3_file *pFile){
+ MemFile *p = (MemFile *)pFile;
+ if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData);
+ return SQLITE_OK;
+}
+
+/*
+** Read data from an memdb-file.
+*/
+static int memdbRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ MemFile *p = (MemFile *)pFile;
+ if( iOfst+iAmt>p->sz ){
+ memset(zBuf, 0, iAmt);
+ if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ memcpy(zBuf, p->aData+iOfst, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Try to enlarge the memory allocation to hold at least sz bytes
+*/
+static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
+ unsigned char *pNew;
+ if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){
+ return SQLITE_FULL;
+ }
+ if( newSz>p->szMax ){
+ return SQLITE_FULL;
+ }
+ newSz *= 2;
+ if( newSz>p->szMax ) newSz = p->szMax;
+ pNew = sqlite3Realloc(p->aData, newSz);
+ if( pNew==0 ) return SQLITE_NOMEM;
+ p->aData = pNew;
+ p->szAlloc = newSz;
+ return SQLITE_OK;
+}
+
+/*
+** Write data to an memdb-file.
+*/
+static int memdbWrite(
+ sqlite3_file *pFile,
+ const void *z,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ MemFile *p = (MemFile *)pFile;
+ if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY;
+ if( iOfst+iAmt>p->sz ){
+ int rc;
+ if( iOfst+iAmt>p->szAlloc
+ && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK
+ ){
+ return rc;
+ }
+ if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
+ p->sz = iOfst+iAmt;
+ }
+ memcpy(p->aData+iOfst, z, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Truncate an memdb-file.
+**
+** In rollback mode (which is always the case for memdb, as it does not
+** support WAL mode) the truncate() method is only used to reduce
+** the size of a file, never to increase the size.
+*/
+static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ MemFile *p = (MemFile *)pFile;
+ if( NEVER(size>p->sz) ) return SQLITE_FULL;
+ p->sz = size;
+ return SQLITE_OK;
+}
+
+/*
+** Sync an memdb-file.
+*/
+static int memdbSync(sqlite3_file *pFile, int flags){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current file-size of an memdb-file.
+*/
+static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ MemFile *p = (MemFile *)pFile;
+ *pSize = p->sz;
+ return SQLITE_OK;
+}
+
+/*
+** Lock an memdb-file.
+*/
+static int memdbLock(sqlite3_file *pFile, int eLock){
+ MemFile *p = (MemFile *)pFile;
+ if( eLock>SQLITE_LOCK_SHARED
+ && (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0
+ ){
+ return SQLITE_READONLY;
+ }
+ p->eLock = eLock;
+ return SQLITE_OK;
+}
+
+#if 0 /* Never used because memdbAccess() always returns false */
+/*
+** Check if another file-handle holds a RESERVED lock on an memdb-file.
+*/
+static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+#endif
+
+/*
+** File control method. For custom operations on an memdb-file.
+*/
+static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
+ MemFile *p = (MemFile *)pFile;
+ int rc = SQLITE_NOTFOUND;
+ if( op==SQLITE_FCNTL_VFSNAME ){
+ *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
+ rc = SQLITE_OK;
+ }
+ if( op==SQLITE_FCNTL_SIZE_LIMIT ){
+ sqlite3_int64 iLimit = *(sqlite3_int64*)pArg;
+ if( iLimit<p->sz ){
+ if( iLimit<0 ){
+ iLimit = p->szMax;
+ }else{
+ iLimit = p->sz;
+ }
+ }
+ p->szMax = iLimit;
+ *(sqlite3_int64*)pArg = iLimit;
+ rc = SQLITE_OK;
+ }
+ return rc;
+}
+
+#if 0 /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */
+/*
+** Return the sector-size in bytes for an memdb-file.
+*/
+static int memdbSectorSize(sqlite3_file *pFile){
+ return 1024;
+}
+#endif
+
+/*
+** Return the device characteristic flags supported by an memdb-file.
+*/
+static int memdbDeviceCharacteristics(sqlite3_file *pFile){
+ return SQLITE_IOCAP_ATOMIC |
+ SQLITE_IOCAP_POWERSAFE_OVERWRITE |
+ SQLITE_IOCAP_SAFE_APPEND |
+ SQLITE_IOCAP_SEQUENTIAL;
+}
+
+/* Fetch a page of a memory-mapped file */
+static int memdbFetch(
+ sqlite3_file *pFile,
+ sqlite3_int64 iOfst,
+ int iAmt,
+ void **pp
+){
+ MemFile *p = (MemFile *)pFile;
+ if( iOfst+iAmt>p->sz ){
+ *pp = 0;
+ }else{
+ p->nMmap++;
+ *pp = (void*)(p->aData + iOfst);
+ }
+ return SQLITE_OK;
+}
+
+/* Release a memory-mapped page */
+static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
+ MemFile *p = (MemFile *)pFile;
+ p->nMmap--;
+ return SQLITE_OK;
+}
+
+/*
+** Open an mem file handle.
+*/
+static int memdbOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ MemFile *p = (MemFile*)pFile;
+ if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
+ return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags);
+ }
+ memset(p, 0, sizeof(*p));
+ p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
+ assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
+ *pOutFlags = flags | SQLITE_OPEN_MEMORY;
+ pFile->pMethods = &memdb_io_methods;
+ p->szMax = sqlite3GlobalConfig.mxMemdbSize;
+ return SQLITE_OK;
+}
+
+#if 0 /* Only used to delete rollback journals, super-journals, and WAL
+ ** files, none of which exist in memdb. So this routine is never used */
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ return SQLITE_IOERR_DELETE;
+}
+#endif
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+**
+** With memdb, no files ever exist on disk. So always return false.
+*/
+static int memdbAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int memdbFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ sqlite3_snprintf(nOut, zOut, "%s", zPath);
+ return SQLITE_OK;
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
+}
+
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated
+** with dynamic libraries.
+*/
+static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*memdbDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){
+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
+}
+
+#if 0 /* Never used. Modern cores only call xCurrentTimeInt64() */
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int memdbCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
+}
+#endif
+
+static int memdbGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
+}
+static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
+ return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
+}
+
+/*
+** Translate a database connection pointer and schema name into a
+** MemFile pointer.
+*/
+static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
+ MemFile *p = 0;
+ int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
+ if( rc ) return 0;
+ if( p->base.pMethods!=&memdb_io_methods ) return 0;
+ return p;
+}
+
+/*
+** Return the serialization of a database
+*/
+SQLITE_API unsigned char *sqlite3_serialize(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which database within the connection */
+ sqlite3_int64 *piSize, /* Write size here, if not NULL */
+ unsigned int mFlags /* Maybe SQLITE_SERIALIZE_NOCOPY */
+){
+ MemFile *p;
+ int iDb;
+ Btree *pBt;
+ sqlite3_int64 sz;
+ int szPage = 0;
+ sqlite3_stmt *pStmt = 0;
+ unsigned char *pOut;
+ char *zSql;
+ int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+
+ if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
+ p = memdbFromDbSchema(db, zSchema);
+ iDb = sqlite3FindDbName(db, zSchema);
+ if( piSize ) *piSize = -1;
+ if( iDb<0 ) return 0;
+ if( p ){
+ if( piSize ) *piSize = p->sz;
+ if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
+ pOut = p->aData;
+ }else{
+ pOut = sqlite3_malloc64( p->sz );
+ if( pOut ) memcpy(pOut, p->aData, p->sz);
+ }
+ return pOut;
+ }
+ pBt = db->aDb[iDb].pBt;
+ if( pBt==0 ) return 0;
+ szPage = sqlite3BtreeGetPageSize(pBt);
+ zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema);
+ rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM;
+ sqlite3_free(zSql);
+ if( rc ) return 0;
+ rc = sqlite3_step(pStmt);
+ if( rc!=SQLITE_ROW ){
+ pOut = 0;
+ }else{
+ sz = sqlite3_column_int64(pStmt, 0)*szPage;
+ if( piSize ) *piSize = sz;
+ if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
+ pOut = 0;
+ }else{
+ pOut = sqlite3_malloc64( sz );
+ if( pOut ){
+ int nPage = sqlite3_column_int(pStmt, 0);
+ Pager *pPager = sqlite3BtreePager(pBt);
+ int pgno;
+ for(pgno=1; pgno<=nPage; pgno++){
+ DbPage *pPage = 0;
+ unsigned char *pTo = pOut + szPage*(sqlite3_int64)(pgno-1);
+ rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pPage, 0);
+ if( rc==SQLITE_OK ){
+ memcpy(pTo, sqlite3PagerGetData(pPage), szPage);
+ }else{
+ memset(pTo, 0, szPage);
+ }
+ sqlite3PagerUnref(pPage);
+ }
+ }
+ }
+ }
+ sqlite3_finalize(pStmt);
+ return pOut;
+}
+
+/* Convert zSchema to a MemDB and initialize its content.
+*/
+SQLITE_API int sqlite3_deserialize(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which DB to reopen with the deserialization */
+ unsigned char *pData, /* The serialized database content */
+ sqlite3_int64 szDb, /* Number bytes in the deserialization */
+ sqlite3_int64 szBuf, /* Total size of buffer pData[] */
+ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
+){
+ MemFile *p;
+ char *zSql;
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ int iDb;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+ if( szDb<0 ) return SQLITE_MISUSE_BKPT;
+ if( szBuf<0 ) return SQLITE_MISUSE_BKPT;
+#endif
+
+ sqlite3_mutex_enter(db->mutex);
+ if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
+ iDb = sqlite3FindDbName(db, zSchema);
+ if( iDb<0 ){
+ rc = SQLITE_ERROR;
+ goto end_deserialize;
+ }
+ zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+ sqlite3_free(zSql);
+ if( rc ) goto end_deserialize;
+ db->init.iDb = (u8)iDb;
+ db->init.reopenMemdb = 1;
+ rc = sqlite3_step(pStmt);
+ db->init.reopenMemdb = 0;
+ if( rc!=SQLITE_DONE ){
+ rc = SQLITE_ERROR;
+ goto end_deserialize;
+ }
+ p = memdbFromDbSchema(db, zSchema);
+ if( p==0 ){
+ rc = SQLITE_ERROR;
+ }else{
+ p->aData = pData;
+ p->sz = szDb;
+ p->szAlloc = szBuf;
+ p->szMax = szBuf;
+ if( p->szMax<sqlite3GlobalConfig.mxMemdbSize ){
+ p->szMax = sqlite3GlobalConfig.mxMemdbSize;
+ }
+ p->mFlags = mFlags;
+ rc = SQLITE_OK;
+ }
+
+end_deserialize:
+ sqlite3_finalize(pStmt);
+ sqlite3_mutex_leave(db->mutex);
+ return rc;
+}
+
+/*
+** This routine is called when the extension is loaded.
+** Register the new VFS.
+*/
+SQLITE_PRIVATE int sqlite3MemdbInit(void){
+ sqlite3_vfs *pLower = sqlite3_vfs_find(0);
+ int sz = pLower->szOsFile;
+ memdb_vfs.pAppData = pLower;
+ /* The following conditional can only be true when compiled for
+ ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
+ ** it in, to be safe, but it is marked as NO_TEST since there
+ ** is no way to reach it under most builds. */
+ if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
+ memdb_vfs.szOsFile = sz;
+ return sqlite3_vfs_register(&memdb_vfs, 0);
+}
+#endif /* SQLITE_ENABLE_DESERIALIZE */
+
+/************** End of memdb.c ***********************************************/
/************** Begin file bitvec.c ******************************************/
/*
** 2008 February 16
@@ -43181,8 +48482,8 @@ SQLITE_API int sqlite3_os_end(void){
** property. Usually only a few pages are meet either condition.
** So the bitmap is usually sparse and has low cardinality.
** But sometimes (for example when during a DROP of a large table) most
-** or all of the pages in a database can get journalled. In those cases,
-** the bitmap becomes dense with high cardinality. The algorithm needs
+** or all of the pages in a database can get journalled. In those cases,
+** the bitmap becomes dense with high cardinality. The algorithm needs
** to handle both cases well.
**
** The size of the bitmap is fixed when the object is created.
@@ -43203,13 +48504,13 @@ SQLITE_API int sqlite3_os_end(void){
/* Size of the Bitvec structure in bytes. */
#define BITVEC_SZ 512
-/* Round the union size down to the nearest pointer boundary, since that's how
+/* Round the union size down to the nearest pointer boundary, since that's how
** it will be aligned within the Bitvec struct. */
#define BITVEC_USIZE \
(((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
-/* Type of the array "element" for the bitmap representation.
-** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
+/* Type of the array "element" for the bitmap representation.
+** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
** Setting this to the "natural word" size of your CPU may improve
** performance. */
#define BITVEC_TELEM u8
@@ -43222,12 +48523,12 @@ SQLITE_API int sqlite3_os_end(void){
/* Number of u32 values in hash table. */
#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
-/* Maximum number of entries in hash table before
+/* Maximum number of entries in hash table before
** sub-dividing and re-hashing. */
#define BITVEC_MXHASH (BITVEC_NINT/2)
/* Hashing function for the aHash representation.
-** Empirical testing showed that the *37 multiplier
-** (an arbitrary prime)in the hash function provided
+** Empirical testing showed that the *37 multiplier
+** (an arbitrary prime)in the hash function provided
** no fewer collisions than the no-op *1. */
#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
@@ -43273,7 +48574,7 @@ struct Bitvec {
/*
** Create a new bitmap object able to handle bits between 0 and iSize,
-** inclusive. Return a pointer to the new object. Return NULL if
+** inclusive. Return a pointer to the new object. Return NULL if
** malloc fails.
*/
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
@@ -43457,7 +48758,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
return p->iSize;
}
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
/*
** Let V[] be an array of unsigned characters sufficient to hold
** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
@@ -43529,7 +48830,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
break;
}
case 3:
- case 4:
+ case 4:
default: {
nx = 2;
sqlite3_randomness(sizeof(i), &i);
@@ -43572,7 +48873,7 @@ bitvec_end:
sqlite3BitvecDestroy(pBitvec);
return rc;
}
-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+#endif /* SQLITE_UNTESTABLE */
/************** End of bitvec.c **********************************************/
/************** Begin file pcache.c ******************************************/
@@ -43609,8 +48910,8 @@ bitvec_end:
**
** The PCache.pSynced variable is used to optimize searching for a dirty
** page to eject from the cache mid-transaction. It is better to eject
-** a page that does not require a journal sync than one that does.
-** Therefore, pSynced is maintained to that it *almost* always points
+** a page that does not require a journal sync than one that does.
+** Therefore, pSynced is maintained so that it *almost* always points
** to either the oldest page in the pDirty/pDirtyTail list that has a
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
** (so that the right page to eject can be found by following pDirtyPrev
@@ -43650,7 +48951,7 @@ struct PCache {
sqlite3_pcache_page *pLower;
PgHdr *pPg;
unsigned char *a;
-
+
if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
N = sqlite3PcachePagecount(pCache);
@@ -43682,11 +48983,11 @@ struct PCache {
**
** assert( sqlite3PcachePageSanity(pPg) );
*/
-#if SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
PCache *pCache;
assert( pPg!=0 );
- assert( pPg->pgno>0 ); /* Page number is 1 or more */
+ assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */
pCache = pPg->pCache;
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
@@ -43742,12 +49043,12 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
-
+
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
p->pSynced = pPage->pDirtyPrev;
}
-
+
if( pPage->pDirtyNext ){
pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
}else{
@@ -43757,7 +49058,7 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
- /* If there are now no dirty pages in the cache, set eCreate to 2.
+ /* If there are now no dirty pages in the cache, set eCreate to 2.
** This is an optimization that allows sqlite3PcacheFetch() to skip
** searching for a dirty page to eject from the cache when it might
** otherwise have to. */
@@ -43769,12 +49070,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
p->eCreate = 2;
}
}
- pPage->pDirtyNext = 0;
- pPage->pDirtyPrev = 0;
}
if( addRemove & PCACHE_DIRTYLIST_ADD ){
- assert( pPage->pDirtyNext==0 && pPage->pDirtyPrev==0 && p->pDirty!=pPage );
-
+ pPage->pDirtyPrev = 0;
pPage->pDirtyNext = p->pDirty;
if( pPage->pDirtyNext ){
assert( pPage->pDirtyNext->pDirtyPrev==0 );
@@ -43789,11 +49087,11 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
p->pDirty = pPage;
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
- ** pSynced to point to it. Checking the NEED_SYNC flag is an
+ ** pSynced to point to it. Checking the NEED_SYNC flag is an
** optimization, as if pSynced points to a page with the NEED_SYNC
- ** flag set sqlite3PcacheFetchStress() searches through all newer
+ ** flag set sqlite3PcacheFetchStress() searches through all newer
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
- if( !p->pSynced
+ if( !p->pSynced
&& 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/
){
p->pSynced = pPage;
@@ -43824,16 +49122,17 @@ static int numberOfCachePages(PCache *p){
** suggested cache size is set to N. */
return p->szCache;
}else{
- /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then
- ** the number of cache pages is adjusted to use approximately abs(N*1024)
- ** bytes of memory. */
+ /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
+ ** number of cache pages is adjusted to be a number of pages that would
+ ** use approximately abs(N*1024) bytes of memory based on the current
+ ** page size. */
return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
}
}
/*************************************************** General Interfaces ******
**
-** Initialize and shutdown the page cache subsystem. Neither of these
+** Initialize and shutdown the page cache subsystem. Neither of these
** functions are threadsafe.
*/
SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
@@ -43842,6 +49141,7 @@ SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
** built-in default page cache is used instead of the application defined
** page cache. */
sqlite3PCacheSetDefault();
+ assert( sqlite3GlobalConfig.pcache2.xInit!=0 );
}
return sqlite3GlobalConfig.pcache2.xInit(sqlite3GlobalConfig.pcache2.pArg);
}
@@ -43859,9 +49159,15 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
/*
** Create a new PCache object. Storage space to hold the object
-** has already been allocated and is passed in as the p pointer.
-** The caller discovers how much space needs to be allocated by
+** has already been allocated and is passed in as the p pointer.
+** The caller discovers how much space needs to be allocated by
** calling sqlite3PcacheSize().
+**
+** szExtra is some extra space allocated for each page. The first
+** 8 bytes of the extra space will be zeroed as the page is allocated,
+** but remaining content will be uninitialized. Though it is opaque
+** to this module, the extra space really ends up being the MemPage
+** structure in the pager.
*/
SQLITE_PRIVATE int sqlite3PcacheOpen(
int szPage, /* Size of every page */
@@ -43874,6 +49180,7 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
memset(p, 0, sizeof(PCache));
p->szPage = 1;
p->szExtra = szExtra;
+ assert( szExtra>=8 ); /* First 8 bytes will be zeroed */
p->bPurgeable = bPurgeable;
p->eCreate = 2;
p->xStress = xStress;
@@ -43943,7 +49250,6 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
assert( pCache!=0 );
assert( pCache->pCache!=0 );
assert( createFlag==3 || createFlag==0 );
- assert( pgno>0 );
assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
/* eCreate defines what to do if the page does not exist.
@@ -43966,7 +49272,7 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
** page because no clean pages are available for reuse and the cache
-** size limit has been reached, then this routine can be invoked to
+** size limit has been reached, then this routine can be invoked to
** try harder to allocate a page. This routine might invoke the stress
** callback to spill dirty pages to the journal. It will then try to
** allocate the new page and will only fail to allocate a new page on
@@ -43983,17 +49289,17 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
if( pCache->eCreate==2 ) return 0;
if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){
- /* Find a dirty page to write-out and recycle. First try to find a
+ /* Find a dirty page to write-out and recycle. First try to find a
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
- ** cleared), but if that is not possible settle for any other
+ ** cleared), but if that is not possible settle for any other
** unreferenced dirty page.
**
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
** flag is currently referenced, then the following may leave pSynced
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
** cleared). This is Ok, as pSynced is just an optimization. */
- for(pPg=pCache->pSynced;
- pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
+ for(pPg=pCache->pSynced;
+ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
pPg=pPg->pDirtyPrev
);
pCache->pSynced = pPg;
@@ -44003,10 +49309,10 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
if( pPg ){
int rc;
#ifdef SQLITE_LOG_CACHE_SPILL
- sqlite3_log(SQLITE_FULL,
+ sqlite3_log(SQLITE_FULL,
"spill page %d making room for %d - cache used: %d/%d",
pPg->pgno, pgno,
- sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
+ sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache),
numberOfCachePages(pCache));
#endif
pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
@@ -44043,7 +49349,7 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
pPgHdr->pPage = pPage;
pPgHdr->pData = pPage->pBuf;
pPgHdr->pExtra = (void *)&pPgHdr[1];
- memset(pPgHdr->pExtra, 0, pCache->szExtra);
+ memset(pPgHdr->pExtra, 0, 8);
pPgHdr->pCache = pCache;
pPgHdr->pgno = pgno;
pPgHdr->flags = PGHDR_CLEAN;
@@ -44085,11 +49391,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
- }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* Move the page to the head of the dirty list. If p->pDirtyPrev==0,
- ** then page p is already at the head of the dirty list and the
- ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE
- ** tag above. */
+ }else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -44145,16 +49447,15 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
assert( sqlite3PcachePageSanity(p) );
- if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){
- assert( (p->flags & PGHDR_CLEAN)==0 );
- pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
- p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
- p->flags |= PGHDR_CLEAN;
- pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
- assert( sqlite3PcachePageSanity(p) );
- if( p->nRef==0 ){
- pcacheUnpin(p);
- }
+ assert( (p->flags & PGHDR_DIRTY)!=0 );
+ assert( (p->flags & PGHDR_CLEAN)==0 );
+ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
+ p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
+ p->flags |= PGHDR_CLEAN;
+ pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
+ assert( sqlite3PcachePageSanity(p) );
+ if( p->nRef==0 ){
+ pcacheUnpin(p);
}
}
@@ -44193,7 +49494,7 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
}
/*
-** Change the page number of page p to newPgno.
+** Change the page number of page p to newPgno.
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
@@ -44256,7 +49557,7 @@ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
-/*
+/*
** Discard the contents of the cache.
*/
SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
@@ -44347,7 +49648,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
return pcacheSortDirtyList(pCache->pDirty);
}
-/*
+/*
** Return the total number of references to all pages held by the cache.
**
** This is not the total number of pages referenced, but the sum of the
@@ -44364,7 +49665,7 @@ SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
-/*
+/*
** Return the total number of pages in the cache.
*/
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
@@ -44406,7 +49707,7 @@ SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){
p->szSpill = mxPage;
}
res = numberOfCachePages(p);
- if( res<p->szSpill ) res = p->szSpill;
+ if( res<p->szSpill ) res = p->szSpill;
return res;
}
@@ -44436,6 +49737,15 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){
return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
}
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
+/*
+** Return true if there are one or more dirty pages in the cache. Else false.
+*/
+SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache){
+ return (pCache->pDirty!=0);
+}
+#endif
+
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
** For all dirty pages currently in the cache, invoke the specified
@@ -44517,7 +49827,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
**
** The third case is a chunk of heap memory (defaulting to 100 pages worth)
** that is allocated when the page cache is created. The size of the local
-** bulk allocation can be adjusted using
+** bulk allocation can be adjusted using
**
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
**
@@ -44542,24 +49852,41 @@ typedef struct PgFreeslot PgFreeslot;
typedef struct PGroup PGroup;
/*
-** Each cache entry is represented by an instance of the following
+** Each cache entry is represented by an instance of the following
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
+** PgHdr1.pCache->szPage bytes is allocated directly before this structure
** in memory.
+**
+** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
+** but causes a 2-byte gap in the structure for most architectures (since
+** pointers must be either 4 or 8-byte aligned). As this structure is located
+** in memory directly after the associated page data, if the database is
+** corrupt, code at the b-tree layer may overread the page buffer and
+** read part of this structure before the corruption is detected. This
+** can cause a valgrind error if the unitialized gap is accessed. Using u16
+** ensures there is no such gap, and therefore no bytes of unitialized memory
+** in the structure.
*/
struct PgHdr1 {
sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
unsigned int iKey; /* Key value (page number) */
- u8 isPinned; /* Page in use, not on the LRU list */
- u8 isBulkLocal; /* This page from bulk local storage */
- u8 isAnchor; /* This is the PGroup.lru element */
+ u16 isBulkLocal; /* This page from bulk local storage */
+ u16 isAnchor; /* This is the PGroup.lru element */
PgHdr1 *pNext; /* Next in hash table chain */
PCache1 *pCache; /* Cache that currently owns this page */
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
+ /* NB: pLruPrev is only valid if pLruNext!=0 */
};
-/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
+/*
+** A page is pinned if it is not on the LRU list. To be "pinned" means
+** that the page is in active use and must not be deallocated.
+*/
+#define PAGE_IS_PINNED(p) ((p)->pLruNext==0)
+#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0)
+
+/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
** of one or more PCaches that are able to recycle each other's unpinned
** pages when they are under memory pressure. A PGroup is an instance of
** the following object.
@@ -44586,7 +49913,7 @@ struct PGroup {
unsigned int nMaxPage; /* Sum of nMax for purgeable caches */
unsigned int nMinPage; /* Sum of nMin for purgeable caches */
unsigned int mxPinned; /* nMaxpage + 10 - nMinPage */
- unsigned int nCurrentPage; /* Number of purgeable pages allocated */
+ unsigned int nPurgeable; /* Number of purgeable pages allocated */
PgHdr1 lru; /* The beginning and end of the LRU list */
};
@@ -44595,16 +49922,18 @@ struct PGroup {
** temporary or transient database) has a single page cache which
** is an instance of this object.
**
-** Pointers to structures of this type are cast and returned as
+** Pointers to structures of this type are cast and returned as
** opaque sqlite3_pcache* handles.
*/
struct PCache1 {
/* Cache configuration parameters. Page size (szPage) and the purgeable
- ** flag (bPurgeable) are set when the cache is created. nMax may be
+ ** flag (bPurgeable) and the pnPurgeable pointer are all set when the
+ ** cache is created and are never changed thereafter. nMax may be
** modified at any time by a call to the pcache1Cachesize() method.
** The PGroup mutex must be held when accessing nMax.
*/
PGroup *pGroup; /* PGroup this cache belongs to */
+ unsigned int *pnPurgeable; /* Pointer to pGroup->nPurgeable */
int szPage; /* Size of database content section */
int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
int szAlloc; /* Total size of one pcache line */
@@ -44613,6 +49942,7 @@ struct PCache1 {
unsigned int nMax; /* Configured "cache_size" value */
unsigned int n90pct; /* nMax*9/10 */
unsigned int iMaxKey; /* Largest key seen since xTruncate() */
+ unsigned int nPurgeableDummy; /* pnPurgeable points here when not used*/
/* Hash table of all pages. The following variables may only be accessed
** when the accessor is holding the PGroup mutex.
@@ -44646,7 +49976,7 @@ static SQLITE_WSD struct PCacheGlobal {
*/
int isInit; /* True if initialized */
int separateCache; /* Use a new PGroup for each PCache */
- int nInitPage; /* Initial bulk allocation size */
+ int nInitPage; /* Initial bulk allocation size */
int szSlot; /* Size of each free slot */
int nSlot; /* The number of pcache slots */
int nReserve; /* Try to keep nFreeSlot above this */
@@ -44687,7 +50017,7 @@ static SQLITE_WSD struct PCacheGlobal {
/*
-** This function is called during initialization if a static buffer is
+** This function is called during initialization if a static buffer is
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
** enough to contain 'n' buffers of 'sz' bytes each.
@@ -44699,6 +50029,7 @@ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
if( pcache1.isInit ){
PgFreeslot *p;
if( pBuf==0 ) sz = n = 0;
+ if( n==0 ) sz = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
@@ -44739,25 +50070,25 @@ static int pcache1InitBulk(PCache1 *pCache){
sqlite3EndBenignMalloc();
if( zBulk ){
int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
- int i;
- for(i=0; i<nBulk; i++){
+ do{
PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage];
pX->page.pBuf = zBulk;
pX->page.pExtra = &pX[1];
pX->isBulkLocal = 1;
pX->isAnchor = 0;
pX->pNext = pCache->pFree;
+ pX->pLruPrev = 0; /* Initializing this saves a valgrind error */
pCache->pFree = pX;
zBulk += pCache->szAlloc;
- }
+ }while( --nBulk );
}
return pCache->pFree!=0;
}
/*
** Malloc function used within this file to allocate space from the buffer
-** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
-** such buffer exists or there is no space left in it, this function falls
+** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
+** such buffer exists or there is no space left in it, this function falls
** back to sqlite3Malloc().
**
** Multiple threads can run this routine at the same time. Global variables
@@ -44857,13 +50188,14 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
if( pCache->pFree || (pCache->nPage==0 && pcache1InitBulk(pCache)) ){
+ assert( pCache->pFree!=0 );
p = pCache->pFree;
pCache->pFree = p->pNext;
p->pNext = 0;
}else{
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* The group mutex must be released before pcache1Alloc() is called. This
- ** is because it might call sqlite3_release_memory(), which assumes that
+ ** is because it might call sqlite3_release_memory(), which assumes that
** this mutex is not held. */
assert( pcache1.separateCache==0 );
assert( pCache->pGroup==&pcache1.grp );
@@ -44880,21 +50212,21 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
}
#else
pPg = pcache1Alloc(pCache->szAlloc);
- p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
#endif
if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup);
#endif
if( pPg==0 ) return 0;
+#ifndef SQLITE_PCACHE_SEPARATE_HEADER
+ p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
+#endif
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
p->isBulkLocal = 0;
p->isAnchor = 0;
}
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage++;
- }
+ (*pCache->pnPurgeable)++;
return p;
}
@@ -44915,9 +50247,7 @@ static void pcache1FreePage(PgHdr1 *p){
sqlite3_free(p);
#endif
}
- if( pCache->bPurgeable ){
- pCache->pGroup->nCurrentPage--;
- }
+ (*pCache->pnPurgeable)--;
}
/*
@@ -44926,6 +50256,7 @@ static void pcache1FreePage(PgHdr1 *p){
** exists, this function falls back to sqlite3Malloc().
*/
SQLITE_PRIVATE void *sqlite3PageMalloc(int sz){
+ assert( sz<=65536+8 ); /* These allocations are never very large */
return pcache1Alloc(sz);
}
@@ -45005,35 +50336,32 @@ static void pcache1ResizeHash(PCache1 *p){
}
/*
-** This function is used internally to remove the page pPage from the
+** This function is used internally to remove the page pPage from the
** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
** LRU list, then this function is a no-op.
**
** The PGroup mutex must be held when this function is called.
*/
static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
- PCache1 *pCache;
-
assert( pPage!=0 );
- assert( pPage->isPinned==0 );
- pCache = pPage->pCache;
+ assert( PAGE_IS_UNPINNED(pPage) );
assert( pPage->pLruNext );
assert( pPage->pLruPrev );
- assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
+ assert( sqlite3_mutex_held(pPage->pCache->pGroup->mutex) );
pPage->pLruPrev->pLruNext = pPage->pLruNext;
pPage->pLruNext->pLruPrev = pPage->pLruPrev;
pPage->pLruNext = 0;
- pPage->pLruPrev = 0;
- pPage->isPinned = 1;
+ /* pPage->pLruPrev = 0;
+ ** No need to clear pLruPrev as it is never accessed if pLruNext is 0 */
assert( pPage->isAnchor==0 );
- assert( pCache->pGroup->lru.isAnchor==1 );
- pCache->nRecyclable--;
+ assert( pPage->pCache->pGroup->lru.isAnchor==1 );
+ pPage->pCache->nRecyclable--;
return pPage;
}
/*
-** Remove the page supplied as an argument from the hash table
+** Remove the page supplied as an argument from the hash table
** (PCache1.apHash structure) that it is currently stored in.
** Also free the page if freePage is true.
**
@@ -45061,11 +50389,11 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
PGroup *pGroup = pCache->pGroup;
PgHdr1 *p;
assert( sqlite3_mutex_held(pGroup->mutex) );
- while( pGroup->nCurrentPage>pGroup->nMaxPage
+ while( pGroup->nPurgeable>pGroup->nMaxPage
&& (p=pGroup->lru.pLruPrev)->isAnchor==0
){
assert( p->pCache->pGroup==pGroup );
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -45076,8 +50404,8 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
}
/*
-** Discard all pages from cache pCache with a page number (key value)
-** greater than or equal to iLimit. Any pinned pages that meet this
+** Discard all pages from cache pCache with a page number (key value)
+** greater than or equal to iLimit. Any pinned pages that meet this
** criteria are unpinned before they are discarded.
**
** The PCache mutex must be held when this function is called.
@@ -45109,12 +50437,12 @@ static void pcache1TruncateUnsafe(
PgHdr1 **pp;
PgHdr1 *pPage;
assert( h<pCache->nHash );
- pp = &pCache->apHash[h];
+ pp = &pCache->apHash[h];
while( (pPage = *pp)!=0 ){
if( pPage->iKey>=iLimit ){
pCache->nPage--;
*pp = pPage->pNext;
- if( !pPage->isPinned ) pcache1PinPage(pPage);
+ if( PAGE_IS_UNPINNED(pPage) ) pcache1PinPage(pPage);
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
@@ -45148,7 +50476,7 @@ static int pcache1Init(void *NotUsed){
**
** * Use a unified cache in single-threaded applications that have
** configured a start-time buffer for use as page-cache memory using
- ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
+ ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
** pBuf argument.
**
** * Otherwise use separate caches (mode-1)
@@ -45183,7 +50511,7 @@ static int pcache1Init(void *NotUsed){
/*
** Implementation of the sqlite3_pcache.xShutdown method.
-** Note that the static mutex allocated in xInit does
+** Note that the static mutex allocated in xInit does
** not need to be freed.
*/
static void pcache1Shutdown(void *NotUsed){
@@ -45217,6 +50545,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
}else{
pGroup = &pcache1.grp;
}
+ pcache1EnterMutex(pGroup);
if( pGroup->lru.isAnchor==0 ){
pGroup->lru.isAnchor = 1;
pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru;
@@ -45226,12 +50555,14 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
pCache->szExtra = szExtra;
pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1));
pCache->bPurgeable = (bPurgeable ? 1 : 0);
- pcache1EnterMutex(pGroup);
pcache1ResizeHash(pCache);
if( bPurgeable ){
pCache->nMin = 10;
pGroup->nMinPage += pCache->nMin;
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
+ pCache->pnPurgeable = &pGroup->nPurgeable;
+ }else{
+ pCache->pnPurgeable = &pCache->nPurgeableDummy;
}
pcache1LeaveMutex(pGroup);
if( pCache->nHash==0 ){
@@ -45243,7 +50574,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
}
/*
-** Implementation of the sqlite3_pcache.xCachesize method.
+** Implementation of the sqlite3_pcache.xCachesize method.
**
** Configure the cache_size limit for a cache.
*/
@@ -45262,7 +50593,7 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
}
/*
-** Implementation of the sqlite3_pcache.xShrink method.
+** Implementation of the sqlite3_pcache.xShrink method.
**
** Free up as much memory as possible.
*/
@@ -45281,7 +50612,7 @@ static void pcache1Shrink(sqlite3_pcache *p){
}
/*
-** Implementation of the sqlite3_pcache.xPagecount method.
+** Implementation of the sqlite3_pcache.xPagecount method.
*/
static int pcache1Pagecount(sqlite3_pcache *p){
int n;
@@ -45302,8 +50633,8 @@ static int pcache1Pagecount(sqlite3_pcache *p){
** for these steps, the main pcache1Fetch() procedure can run faster.
*/
static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
- PCache1 *pCache,
- unsigned int iKey,
+ PCache1 *pCache,
+ unsigned int iKey,
int createFlag
){
unsigned int nPinned;
@@ -45333,7 +50664,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
){
PCache1 *pOther;
pPage = pGroup->lru.pLruPrev;
- assert( pPage->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(pPage) );
pcache1RemoveFromHash(pPage, 0);
pcache1PinPage(pPage);
pOther = pPage->pCache;
@@ -45341,12 +50672,12 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pcache1FreePage(pPage);
pPage = 0;
}else{
- pGroup->nCurrentPage -= (pOther->bPurgeable - pCache->bPurgeable);
+ pGroup->nPurgeable -= (pOther->bPurgeable - pCache->bPurgeable);
}
}
- /* Step 5. If a usable page buffer has still not been found,
- ** attempt to allocate a new one.
+ /* Step 5. If a usable page buffer has still not been found,
+ ** attempt to allocate a new one.
*/
if( !pPage ){
pPage = pcache1AllocPage(pCache, createFlag==1);
@@ -45358,9 +50689,9 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
pPage->iKey = iKey;
pPage->pNext = pCache->apHash[h];
pPage->pCache = pCache;
- pPage->pLruPrev = 0;
pPage->pLruNext = 0;
- pPage->isPinned = 1;
+ /* pPage->pLruPrev = 0;
+ ** No need to clear pLruPrev since it is not accessed when pLruNext==0 */
*(void **)pPage->page.pExtra = 0;
pCache->apHash[h] = pPage;
if( iKey>pCache->iMaxKey ){
@@ -45371,13 +50702,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
}
/*
-** Implementation of the sqlite3_pcache.xFetch method.
+** Implementation of the sqlite3_pcache.xFetch method.
**
** Fetch a page by key value.
**
** Whether or not a new page may be allocated by this function depends on
** the value of the createFlag argument. 0 means do not allocate a new
-** page. 1 means allocate a new page if space is easily available. 2
+** page. 1 means allocate a new page if space is easily available. 2
** means to try really hard to allocate a new page.
**
** For a non-purgeable cache (a cache used as the storage for an in-memory
@@ -45388,7 +50719,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** There are three different approaches to obtaining space for a page,
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
**
-** 1. Regardless of the value of createFlag, the cache is searched for a
+** 1. Regardless of the value of createFlag, the cache is searched for a
** copy of the requested page. If one is found, it is returned.
**
** 2. If createFlag==0 and the page is not already in the cache, NULL is
@@ -45402,13 +50733,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** PCache1.nMax, or
**
** (b) the number of pages pinned by the cache is greater than
-** the sum of nMax for all purgeable caches, less the sum of
+** the sum of nMax for all purgeable caches, less the sum of
** nMin for all other purgeable caches, or
**
** 4. If none of the first three conditions apply and the cache is marked
** as purgeable, and if one of the following is true:
**
-** (a) The number of pages allocated for the cache is already
+** (a) The number of pages allocated for the cache is already
** PCache1.nMax, or
**
** (b) The number of pages allocated for all purgeable caches is
@@ -45420,7 +50751,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
**
** then attempt to recycle a page from the LRU list. If it is the right
** size, return the recycled buffer. Otherwise, free the buffer and
-** proceed to step 5.
+** proceed to step 5.
**
** 5. Otherwise, allocate and return a new page buffer.
**
@@ -45430,8 +50761,8 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
** invokes the appropriate routine.
*/
static PgHdr1 *pcache1FetchNoMutex(
- sqlite3_pcache *p,
- unsigned int iKey,
+ sqlite3_pcache *p,
+ unsigned int iKey,
int createFlag
){
PCache1 *pCache = (PCache1 *)p;
@@ -45446,7 +50777,7 @@ static PgHdr1 *pcache1FetchNoMutex(
** Otherwise (page not in hash and createFlag!=0) continue with
** subsequent steps to try to create the page. */
if( pPage ){
- if( !pPage->isPinned ){
+ if( PAGE_IS_UNPINNED(pPage) ){
return pcache1PinPage(pPage);
}else{
return pPage;
@@ -45460,8 +50791,8 @@ static PgHdr1 *pcache1FetchNoMutex(
}
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
static PgHdr1 *pcache1FetchWithMutex(
- sqlite3_pcache *p,
- unsigned int iKey,
+ sqlite3_pcache *p,
+ unsigned int iKey,
int createFlag
){
PCache1 *pCache = (PCache1 *)p;
@@ -45475,8 +50806,8 @@ static PgHdr1 *pcache1FetchWithMutex(
}
#endif
static sqlite3_pcache_page *pcache1Fetch(
- sqlite3_pcache *p,
- unsigned int iKey,
+ sqlite3_pcache *p,
+ unsigned int iKey,
int createFlag
){
#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
@@ -45506,24 +50837,24 @@ static sqlite3_pcache_page *pcache1Fetch(
** Mark a page as unpinned (eligible for asynchronous recycling).
*/
static void pcache1Unpin(
- sqlite3_pcache *p,
- sqlite3_pcache_page *pPg,
+ sqlite3_pcache *p,
+ sqlite3_pcache_page *pPg,
int reuseUnlikely
){
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PGroup *pGroup = pCache->pGroup;
-
+
assert( pPage->pCache==pCache );
pcache1EnterMutex(pGroup);
- /* It is an error to call this function if the page is already
+ /* It is an error to call this function if the page is already
** part of the PGroup LRU list.
*/
- assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
- assert( pPage->isPinned==1 );
+ assert( pPage->pLruNext==0 );
+ assert( PAGE_IS_PINNED(pPage) );
- if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
+ if( reuseUnlikely || pGroup->nPurgeable>pGroup->nMaxPage ){
pcache1RemoveFromHash(pPage, 1);
}else{
/* Add the page to the PGroup LRU list. */
@@ -45532,14 +50863,13 @@ static void pcache1Unpin(
(pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
*ppFirst = pPage;
pCache->nRecyclable++;
- pPage->isPinned = 0;
}
pcache1LeaveMutex(pCache->pGroup);
}
/*
-** Implementation of the sqlite3_pcache.xRekey method.
+** Implementation of the sqlite3_pcache.xRekey method.
*/
static void pcache1Rekey(
sqlite3_pcache *p,
@@ -45550,7 +50880,7 @@ static void pcache1Rekey(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
- unsigned int h;
+ unsigned int h;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
@@ -45575,7 +50905,7 @@ static void pcache1Rekey(
}
/*
-** Implementation of the sqlite3_pcache.xTruncate method.
+** Implementation of the sqlite3_pcache.xTruncate method.
**
** Discard all unpinned pages in the cache with a page number equal to
** or greater than parameter iLimit. Any pinned pages with a page number
@@ -45592,7 +50922,7 @@ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
}
/*
-** Implementation of the sqlite3_pcache.xDestroy method.
+** Implementation of the sqlite3_pcache.xDestroy method.
**
** Destroy a cache allocated using pcache1Create().
*/
@@ -45658,14 +50988,14 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){
** by the current thread may be sqlite3_free()ed.
**
** nReq is the number of bytes of memory required. Once this much has
-** been released, the function returns. The return value is the total number
+** been released, the function returns. The return value is the total number
** of bytes of memory released.
*/
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
int nFree = 0;
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
assert( sqlite3_mutex_notheld(pcache1.mutex) );
- if( sqlite3GlobalConfig.nPage==0 ){
+ if( sqlite3GlobalConfig.pPage==0 ){
PgHdr1 *p;
pcache1EnterMutex(&pcache1.grp);
while( (nReq<0 || nFree<nReq)
@@ -45676,7 +51006,7 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
nFree += sqlite3MemSize(p);
#endif
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
}
@@ -45700,10 +51030,10 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
PgHdr1 *p;
int nRecyclable = 0;
for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
- assert( p->isPinned==0 );
+ assert( PAGE_IS_UNPINNED(p) );
nRecyclable++;
}
- *pnCurrent = pcache1.grp.nCurrentPage;
+ *pnCurrent = pcache1.grp.nPurgeable;
*pnMax = (int)pcache1.grp.nMaxPage;
*pnMin = (int)pcache1.grp.nMinPage;
*pnRecyclable = nRecyclable;
@@ -45749,7 +51079,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** extracts the least value from the RowSet.
**
** The INSERT primitive might allocate additional memory. Memory is
-** allocated in chunks so most INSERTs do no allocation. There is an
+** allocated in chunks so most INSERTs do no allocation. There is an
** upper bound on the size of allocated memory. No memory is freed
** until DESTROY.
**
@@ -45797,7 +51127,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** in the list, pLeft points to the tree, and v is unused. The
** RowSet.pForest value points to the head of this forest list.
*/
-struct RowSetEntry {
+struct RowSetEntry {
i64 v; /* ROWID value for this entry */
struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */
struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */
@@ -45838,30 +51168,23 @@ struct RowSet {
#define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */
/*
-** Turn bulk memory into a RowSet object. N bytes of memory
-** are available at pSpace. The db pointer is used as a memory context
-** for any subsequent allocations that need to occur.
-** Return a pointer to the new RowSet object.
-**
-** It must be the case that N is sufficient to make a Rowset. If not
-** an assertion fault occurs.
-**
-** If N is larger than the minimum, use the surplus as an initial
-** allocation of entries available to be filled.
+** Allocate a RowSet object. Return NULL if a memory allocation
+** error occurs.
*/
-SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){
- RowSet *p;
- assert( N >= ROUND8(sizeof(*p)) );
- p = pSpace;
- p->pChunk = 0;
- p->db = db;
- p->pEntry = 0;
- p->pLast = 0;
- p->pForest = 0;
- p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
- p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
- p->rsFlags = ROWSET_SORTED;
- p->iBatch = 0;
+SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db){
+ RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p));
+ if( p ){
+ int N = sqlite3DbMallocSize(db, p);
+ p->pChunk = 0;
+ p->db = db;
+ p->pEntry = 0;
+ p->pLast = 0;
+ p->pForest = 0;
+ p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p);
+ p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry));
+ p->rsFlags = ROWSET_SORTED;
+ p->iBatch = 0;
+ }
return p;
}
@@ -45870,7 +51193,8 @@ SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int
** the RowSet has allocated over its lifetime. This routine is
** the destructor for the RowSet.
*/
-SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
+SQLITE_PRIVATE void sqlite3RowSetClear(void *pArg){
+ RowSet *p = (RowSet*)pArg;
struct RowSetChunk *pChunk, *pNextChunk;
for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
pNextChunk = pChunk->pNextChunk;
@@ -45885,9 +51209,19 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
}
/*
+** Deallocate all chunks from a RowSet. This frees all memory that
+** the RowSet has allocated over its lifetime. This routine is
+** the destructor for the RowSet.
+*/
+SQLITE_PRIVATE void sqlite3RowSetDelete(void *pArg){
+ sqlite3RowSetClear(pArg);
+ sqlite3DbFree(((RowSet*)pArg)->db, pArg);
+}
+
+/*
** Allocate a new RowSetEntry object that is associated with the
** given RowSet. Return a pointer to the new and completely uninitialized
-** objected.
+** object.
**
** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
** routine returns NULL.
@@ -45945,7 +51279,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
/*
** Merge two lists of RowSetEntry objects. Remove duplicates.
**
-** The input lists are connected via pRight pointers and are
+** The input lists are connected via pRight pointers and are
** assumed to each already be in sorted order.
*/
static struct RowSetEntry *rowSetEntryMerge(
@@ -45982,7 +51316,7 @@ static struct RowSetEntry *rowSetEntryMerge(
/*
** Sort all elements on the list of RowSetEntry objects into order of
** increasing v.
-*/
+*/
static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
unsigned int i;
struct RowSetEntry *pNext, *aBucket[40];
@@ -46055,7 +51389,7 @@ static struct RowSetEntry *rowSetNDeepTree(
struct RowSetEntry *pLeft; /* Left subtree */
if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
/* Prevent unnecessary deep recursion when we run out of entries */
- return 0;
+ return 0;
}
if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/
/* This branch causes a *balanced* tree to be generated. A valid tree
@@ -46163,7 +51497,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
if( p ){
struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
- /* Only sort the current set of entiries if they need it */
+ /* Only sort the current set of entries if they need it */
p = rowSetEntrySort(p);
}
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
@@ -46225,7 +51559,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
**
*************************************************************************
** This is the implementation of the page cache subsystem or "pager".
-**
+**
** The pager is used to access a database disk file. It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file. The pager also implements file
@@ -46248,8 +51582,8 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This header file defines the interface to the write-ahead logging
-** system. Refer to the comments below and the header comment attached to
+** This header file defines the interface to the write-ahead logging
+** system. Refer to the comments below and the header comment attached to
** the implementation of each function in log.c for further details.
*/
@@ -46258,16 +51592,16 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
/* #include "sqliteInt.h" */
-/* Additional values that can be added to the sync_flags argument of
-** sqlite3WalFrames():
+/* Macros for extracting appropriate sync flags for either transaction
+** commits (WAL_SYNC_FLAGS(X)) or for checkpoint ops (CKPT_SYNC_FLAGS(X)):
*/
-#define WAL_SYNC_TRANSACTIONS 0x20 /* Sync at the end of each transaction */
-#define SQLITE_SYNC_MASK 0x13 /* Mask off the SQLITE_SYNC_* values */
+#define WAL_SYNC_FLAGS(X) ((X)&0x03)
+#define CKPT_SYNC_FLAGS(X) (((X)>>2)&0x03)
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
# define sqlite3WalLimit(x,y)
-# define sqlite3WalClose(w,x,y,z) 0
+# define sqlite3WalClose(v,w,x,y,z) 0
# define sqlite3WalBeginReadTransaction(y,z) 0
# define sqlite3WalEndReadTransaction(z)
# define sqlite3WalDbsize(y) 0
@@ -46277,7 +51611,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
# define sqlite3WalSavepoint(y,z)
# define sqlite3WalSavepointUndo(y,z) 0
# define sqlite3WalFrames(u,v,w,x,y,z) 0
-# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
+# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
# define sqlite3WalCallback(z) 0
# define sqlite3WalExclusiveMode(y,z) 0
# define sqlite3WalHeapMemory(z) 0
@@ -46288,19 +51622,19 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
#define WAL_SAVEPOINT_NDATA 4
-/* Connection to a write-ahead log (WAL) file.
-** There is one object of this type for each pager.
+/* Connection to a write-ahead log (WAL) file.
+** There is one object of this type for each pager.
*/
typedef struct Wal Wal;
/* Open and close a connection to a write-ahead log. */
SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
-SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, 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
+/* 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
** preserves the current state even if the other threads or processes
@@ -46335,9 +51669,10 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
/* Write a frame or frames to the log. */
SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
-/* Copy pages from the log to the database file */
+/* Copy pages from the log to the database file */
SQLITE_PRIVATE int sqlite3WalCheckpoint(
Wal *pWal, /* Write-ahead log connection */
+ sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* One of PASSIVE, FULL and RESTART */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
@@ -46362,13 +51697,16 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op);
/* Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
-** WAL module is using shared-memory, return false.
+** WAL module is using shared-memory, return false.
*/
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
#ifdef SQLITE_ENABLE_SNAPSHOT
SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal);
+SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -46381,6 +51719,11 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
/* Return the sqlite3_file object for the WAL file */
SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
+#endif
+
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* SQLITE_WAL_H */
@@ -46401,60 +51744,60 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
**
** Definition: A page of the database file is said to be "overwriteable" if
** one or more of the following are true about the page:
-**
+**
** (a) The original content of the page as it was at the beginning of
** the transaction has been written into the rollback journal and
** synced.
-**
+**
** (b) The page was a freelist leaf page at the start of the transaction.
-**
+**
** (c) The page number is greater than the largest page that existed in
** the database file at the start of the transaction.
-**
+**
** (1) A page of the database file is never overwritten unless one of the
** following are true:
-**
+**
** (a) The page and all other pages on the same sector are overwriteable.
-**
+**
** (b) The atomic page write optimization is enabled, and the entire
** transaction other than the update of the transaction sequence
** number consists of a single page change.
-**
+**
** (2) The content of a page written into the rollback journal exactly matches
** both the content in the database when the rollback journal was written
** and the content in the database at the beginning of the current
** transaction.
-**
+**
** (3) Writes to the database file are an integer multiple of the page size
** in length and are aligned on a page boundary.
-**
+**
** (4) Reads from the database file are either aligned on a page boundary and
** an integer multiple of the page size in length or are taken from the
** first 100 bytes of the database file.
-**
+**
** (5) All writes to the database file are synced prior to the rollback journal
** being deleted, truncated, or zeroed.
-**
-** (6) If a master journal file is used, then all writes to the database file
-** are synced prior to the master journal being deleted.
-**
+**
+** (6) If a super-journal file is used, then all writes to the database file
+** are synced prior to the super-journal being deleted.
+**
** Definition: Two databases (or the same database at two points it time)
** are said to be "logically equivalent" if they give the same answer to
** all queries. Note in particular the content of freelist leaf
** pages can be changed arbitrarily without affecting the logical equivalence
** of the database.
-**
+**
** (7) At any time, if any subset, including the empty set and the total set,
-** of the unsynced changes to a rollback journal are removed and the
+** of the unsynced changes to a rollback journal are removed and the
** journal is rolled back, the resulting database file will be logically
** equivalent to the database file at the beginning of the transaction.
-**
+**
** (8) When a transaction is rolled back, the xTruncate method of the VFS
** is called to restore the database file to the same size it was at
** the beginning of the transaction. (In some VFSes, the xTruncate
** method is a no-op, but that does not change the fact the SQLite will
** invoke it.)
-**
+**
** (9) Whenever the database file is modified, at least one bit in the range
** of bytes from 24 through 39 inclusive will be changed prior to releasing
** the EXCLUSIVE lock, thus signaling other connections on the same
@@ -46487,14 +51830,14 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
/*
** The following two macros are used within the PAGERTRACE() macros above
-** to print out file-descriptors.
+** to print out file-descriptors.
**
** PAGERID() takes a pointer to a Pager struct as its argument. The
** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
** struct as its argument.
*/
-#define PAGERID(p) ((int)(p->fd))
-#define FILEHANDLEID(fd) ((int)fd)
+#define PAGERID(p) (SQLITE_PTR_TO_INT(p->fd))
+#define FILEHANDLEID(fd) (SQLITE_PTR_TO_INT(fd))
/*
** The Pager.eState variable stores the current 'state' of a pager. A
@@ -46508,7 +51851,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** | | |
** | V |
** |<-------WRITER_LOCKED------> ERROR
-** | | ^
+** | | ^
** | V |
** |<------WRITER_CACHEMOD-------->|
** | | |
@@ -46520,7 +51863,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
**
** List of state transitions and the C [function] that performs each:
-**
+**
** OPEN -> READER [sqlite3PagerSharedLock]
** READER -> OPEN [pager_unlock]
**
@@ -46532,7 +51875,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** WRITER_*** -> ERROR [pager_error]
** ERROR -> OPEN [pager_unlock]
-**
+**
**
** OPEN:
**
@@ -46546,9 +51889,9 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** READER:
**
-** In this state all the requirements for reading the database in
+** In this state all the requirements for reading the database in
** rollback (non-WAL) mode are met. Unless the pager is (or recently
-** was) in exclusive-locking mode, a user-level read transaction is
+** was) in exclusive-locking mode, a user-level read transaction is
** open. The database size is known in this state.
**
** A connection running with locking_mode=normal enters this state when
@@ -46558,28 +51901,28 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** this state even after the read-transaction is closed. The only way
** a locking_mode=exclusive connection can transition from READER to OPEN
** is via the ERROR state (see below).
-**
+**
** * A read transaction may be active (but a write-transaction cannot).
** * A SHARED or greater lock is held on the database file.
-** * The dbSize variable may be trusted (even if a user-level read
+** * The dbSize variable may be trusted (even if a user-level read
** transaction is not active). The dbOrigSize and dbFileSize variables
** may not be trusted at this point.
** * If the database is a WAL database, then the WAL connection is open.
-** * Even if a read-transaction is not open, it is guaranteed that
+** * Even if a read-transaction is not open, it is guaranteed that
** there is no hot-journal in the file-system.
**
** WRITER_LOCKED:
**
** The pager moves to this state from READER when a write-transaction
-** is first opened on the database. In WRITER_LOCKED state, all locks
-** required to start a write-transaction are held, but no actual
+** is first opened on the database. In WRITER_LOCKED state, all locks
+** required to start a write-transaction are held, but no actual
** modifications to the cache or database have taken place.
**
-** In rollback mode, a RESERVED or (if the transaction was opened with
+** In rollback mode, a RESERVED or (if the transaction was opened with
** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when
-** moving to this state, but the journal file is not written to or opened
-** to in this state. If the transaction is committed or rolled back while
-** in WRITER_LOCKED state, all that is required is to unlock the database
+** moving to this state, but the journal file is not written to or opened
+** to in this state. If the transaction is committed or rolled back while
+** in WRITER_LOCKED state, all that is required is to unlock the database
** file.
**
** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file.
@@ -46587,7 +51930,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** is made to obtain an EXCLUSIVE lock on the database file.
**
** * A write transaction is active.
-** * If the connection is open in rollback-mode, a RESERVED or greater
+** * If the connection is open in rollback-mode, a RESERVED or greater
** lock is held on the database file.
** * If the connection is open in WAL-mode, a WAL write transaction
** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully
@@ -46606,7 +51949,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** * A write transaction is active.
** * A RESERVED or greater lock is held on the database file.
-** * The journal file is open and the first header has been written
+** * The journal file is open and the first header has been written
** to it, but the header has not been synced to disk.
** * The contents of the page cache have been modified.
**
@@ -46619,7 +51962,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** * A write transaction is active.
** * An EXCLUSIVE or greater lock is held on the database file.
-** * The journal file is open and the first header has been written
+** * The journal file is open and the first header has been written
** and synced to disk.
** * The contents of the page cache have been modified (and possibly
** written to disk).
@@ -46631,8 +51974,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD
** state after the entire transaction has been successfully written into the
** database file. In this state the transaction may be committed simply
-** by finalizing the journal file. Once in WRITER_FINISHED state, it is
-** not possible to modify the database further. At this point, the upper
+** by finalizing the journal file. Once in WRITER_FINISHED state, it is
+** not possible to modify the database further. At this point, the upper
** layer must either commit or rollback the transaction.
**
** * A write transaction is active.
@@ -46640,19 +51983,19 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** * All writing and syncing of journal and database data has finished.
** If no error occurred, all that remains is to finalize the journal to
** commit the transaction. If an error did occur, the caller will need
-** to rollback the transaction.
+** to rollback the transaction.
**
** ERROR:
**
** The ERROR state is entered when an IO or disk-full error (including
-** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
-** difficult to be sure that the in-memory pager state (cache contents,
+** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
+** difficult to be sure that the in-memory pager state (cache contents,
** db size etc.) are consistent with the contents of the file-system.
**
** Temporary pager files may enter the ERROR state, but in-memory pagers
** cannot.
**
-** For example, if an IO error occurs while performing a rollback,
+** For example, if an IO error occurs while performing a rollback,
** the contents of the page-cache may be left in an inconsistent state.
** At this point it would be dangerous to change back to READER state
** (as usually happens after a rollback). Any subsequent readers might
@@ -46662,13 +52005,13 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** instead of READER following such an error.
**
** Once it has entered the ERROR state, any attempt to use the pager
-** to read or write data returns an error. Eventually, once all
+** to read or write data returns an error. Eventually, once all
** outstanding transactions have been abandoned, the pager is able to
-** transition back to OPEN state, discarding the contents of the
+** transition back to OPEN state, discarding the contents of the
** page-cache and any other in-memory state at the same time. Everything
** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
** when a read-transaction is next opened on the pager (transitioning
-** the pager into READER state). At that point the system has recovered
+** the pager into READER state). At that point the system has recovered
** from the error.
**
** Specifically, the pager jumps into the ERROR state if:
@@ -46684,21 +52027,21 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** memory.
**
** In other cases, the error is returned to the b-tree layer. The b-tree
-** layer then attempts a rollback operation. If the error condition
+** layer then attempts a rollback operation. If the error condition
** persists, the pager enters the ERROR state via condition (1) above.
**
** Condition (3) is necessary because it can be triggered by a read-only
** statement executed within a transaction. In this case, if the error
** code were simply returned to the user, the b-tree layer would not
** automatically attempt a rollback, as it assumes that an error in a
-** read-only statement cannot leave the pager in an internally inconsistent
+** read-only statement cannot leave the pager in an internally inconsistent
** state.
**
** * The Pager.errCode variable is set to something other than SQLITE_OK.
** * There are one or more outstanding references to pages (after the
** last reference is dropped the pager should move back to OPEN state).
** * The pager is not an in-memory pager.
-**
+**
**
** Notes:
**
@@ -46708,7 +52051,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** * Normally, a connection open in exclusive mode is never in PAGER_OPEN
** state. There are two exceptions: immediately after exclusive-mode has
-** been turned on (and before any read or write transactions are
+** been turned on (and before any read or write transactions are
** executed), and when the pager is leaving the "error state".
**
** * See also: assert_pager_state().
@@ -46722,7 +52065,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
#define PAGER_ERROR 6
/*
-** The Pager.eLock variable is almost always set to one of the
+** The Pager.eLock variable is almost always set to one of the
** following locking-states, according to the lock currently held on
** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
** This variable is kept up to date as locks are taken and released by
@@ -46737,20 +52080,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** to a less exclusive (lower) value than the lock that is actually held
** at the system level, but it is never set to a more exclusive value.
**
-** This is usually safe. If an xUnlock fails or appears to fail, there may
+** This is usually safe. If an xUnlock fails or appears to fail, there may
** be a few redundant xLock() calls or a lock may be held for longer than
** required, but nothing really goes wrong.
**
** The exception is when the database file is unlocked as the pager moves
-** from ERROR to OPEN state. At this point there may be a hot-journal file
+** from ERROR to OPEN state. At this point there may be a hot-journal file
** in the file-system that needs to be rolled back (as part of an OPEN->SHARED
** transition, by the same pager or any other). If the call to xUnlock()
** fails at this point and the pager is left holding an EXCLUSIVE lock, this
** can confuse the call to xCheckReservedLock() call made later as part
** of hot-journal detection.
**
-** xCheckReservedLock() is defined as returning true "if there is a RESERVED
-** lock held by this process or any others". So xCheckReservedLock may
+** xCheckReservedLock() is defined as returning true "if there is a RESERVED
+** lock held by this process or any others". So xCheckReservedLock may
** return true because the caller itself is holding an EXCLUSIVE lock (but
** doesn't know it because of a previous error in xUnlock). If this happens
** a hot-journal may be mistaken for a journal being created by an active
@@ -46761,32 +52104,18 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It
** is only changed back to a real locking state after a successful call
** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition
-** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
+** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE
** lock on the database file before attempting to roll it back. See function
** PagerSharedLock() for more detail.
**
-** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
+** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
** PAGER_OPEN state.
*/
#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
/*
-** A macro used for invoking the codec if there is one
-*/
-#ifdef SQLITE_HAS_CODEC
-# define CODEC1(P,D,N,X,E) \
- if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
-# define CODEC2(P,D,N,X,E,O) \
- if( P->xCodec==0 ){ O=(char*)D; }else \
- if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
-#else
-# define CODEC1(P,D,N,X,E) /* NO-OP */
-# define CODEC2(P,D,N,X,E,O) O=(char*)D
-#endif
-
-/*
-** The maximum allowed sector size. 64KiB. If the xSectorsize() method
+** The maximum allowed sector size. 64KiB. If the xSectorsize() method
** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
** This could conceivably cause corruption following a power failure on
** such a system. This is currently an undocumented limit.
@@ -46802,7 +52131,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
**
** When a savepoint is created, the PagerSavepoint.iHdrOffset field is
** set to 0. If a journal-header is written into the main journal while
-** the savepoint is active, then iHdrOffset is set to the byte offset
+** the savepoint is active, then iHdrOffset is set to the byte offset
** immediately following the last journal record written into the main
** journal before the journal-header. This is required during savepoint
** rollback (see pagerPlaybackSavepoint()).
@@ -46852,44 +52181,44 @@ struct PagerSavepoint {
**
** changeCountDone
**
-** This boolean variable is used to make sure that the change-counter
-** (the 4-byte header field at byte offset 24 of the database file) is
-** not updated more often than necessary.
+** This boolean variable is used to make sure that the change-counter
+** (the 4-byte header field at byte offset 24 of the database file) is
+** not updated more often than necessary.
**
-** It is set to true when the change-counter field is updated, which
+** It is set to true when the change-counter field is updated, which
** can only happen if an exclusive lock is held on the database file.
-** It is cleared (set to false) whenever an exclusive lock is
+** It is cleared (set to false) whenever an exclusive lock is
** relinquished on the database file. Each time a transaction is committed,
** The changeCountDone flag is inspected. If it is true, the work of
** updating the change-counter is omitted for the current transaction.
**
-** This mechanism means that when running in exclusive mode, a connection
+** This mechanism means that when running in exclusive mode, a connection
** need only update the change-counter once, for the first transaction
** committed.
**
-** setMaster
+** setSuper
**
** When PagerCommitPhaseOne() is called to commit a transaction, it may
-** (or may not) specify a master-journal name to be written into the
+** (or may not) specify a super-journal name to be written into the
** journal file before it is synced to disk.
**
-** Whether or not a journal file contains a master-journal pointer affects
-** the way in which the journal file is finalized after the transaction is
+** Whether or not a journal file contains a super-journal pointer affects
+** the way in which the journal file is finalized after the transaction is
** committed or rolled back when running in "journal_mode=PERSIST" mode.
-** If a journal file does not contain a master-journal pointer, it is
+** If a journal file does not contain a super-journal pointer, it is
** finalized by overwriting the first journal header with zeroes. If
-** it does contain a master-journal pointer the journal file is finalized
-** by truncating it to zero bytes, just as if the connection were
+** it does contain a super-journal pointer the journal file is finalized
+** by truncating it to zero bytes, just as if the connection were
** running in "journal_mode=truncate" mode.
**
-** Journal files that contain master journal pointers cannot be finalized
+** Journal files that contain super-journal pointers cannot be finalized
** simply by overwriting the first journal-header with zeroes, as the
-** master journal pointer could interfere with hot-journal rollback of any
+** super-journal pointer could interfere with hot-journal rollback of any
** subsequently interrupted transaction that reuses the journal file.
**
** The flag is cleared as soon as the journal file is finalized (either
** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
-** journal file from being successfully finalized, the setMaster flag
+** journal file from being successfully finalized, the setSuper flag
** is cleared anyway (and the pager will move to ERROR state).
**
** doNotSpill
@@ -46905,12 +52234,12 @@ struct PagerSavepoint {
** to allocate a new page to prevent the journal file from being written
** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
** case is a user preference.
-**
+**
** If the SPILLFLAG_NOSYNC bit is set, writing to the database from
** pagerStress() is permitted, but syncing the journal file is not.
** This flag is set by sqlite3PagerWrite() when the file-system sector-size
** is larger than the database page-size in order to prevent a journal sync
-** from happening in between the journalling of two pages on the same sector.
+** from happening in between the journalling of two pages on the same sector.
**
** subjInMemory
**
@@ -46918,16 +52247,16 @@ struct PagerSavepoint {
** is opened as an in-memory journal file. If false, then in-memory
** sub-journals are only used for in-memory pager files.
**
-** This variable is updated by the upper layer each time a new
+** This variable is updated by the upper layer each time a new
** write-transaction is opened.
**
** dbSize, dbOrigSize, dbFileSize
**
** Variable dbSize is set to the number of pages in the database file.
** It is valid in PAGER_READER and higher states (all states except for
-** OPEN and ERROR).
+** OPEN and ERROR).
**
-** dbSize is set based on the size of the database file, which may be
+** dbSize is set based on the size of the database file, which may be
** larger than the size of the database (the value stored at offset
** 28 of the database header by the btree). If the size of the file
** is not an integer multiple of the page-size, the value stored in
@@ -46938,10 +52267,10 @@ struct PagerSavepoint {
**
** During a write-transaction, if pages with page-numbers greater than
** dbSize are modified in the cache, dbSize is updated accordingly.
-** Similarly, if the database is truncated using PagerTruncateImage(),
+** Similarly, if the database is truncated using PagerTruncateImage(),
** dbSize is updated.
**
-** Variables dbOrigSize and dbFileSize are valid in states
+** Variables dbOrigSize and dbFileSize are valid in states
** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize
** variable at the start of the transaction. It is used during rollback,
** and to determine whether or not pages need to be journalled before
@@ -46950,12 +52279,12 @@ struct PagerSavepoint {
** Throughout a write-transaction, dbFileSize contains the size of
** the file on disk in pages. It is set to a copy of dbSize when the
** write-transaction is first opened, and updated when VFS calls are made
-** to write or truncate the database file on disk.
+** to write or truncate the database file on disk.
**
-** The only reason the dbFileSize variable is required is to suppress
-** unnecessary calls to xTruncate() after committing a transaction. If,
-** when a transaction is committed, the dbFileSize variable indicates
-** that the database file is larger than the database image (Pager.dbSize),
+** The only reason the dbFileSize variable is required is to suppress
+** unnecessary calls to xTruncate() after committing a transaction. If,
+** when a transaction is committed, the dbFileSize variable indicates
+** that the database file is larger than the database image (Pager.dbSize),
** pager_truncate() is called. The pager_truncate() call uses xFilesize()
** to measure the database file on disk, and then truncates it if required.
** dbFileSize is not used when rolling back a transaction. In this case
@@ -46966,21 +52295,33 @@ struct PagerSavepoint {
** dbHintSize
**
** The dbHintSize variable is used to limit the number of calls made to
-** the VFS xFileControl(FCNTL_SIZE_HINT) method.
+** the VFS xFileControl(FCNTL_SIZE_HINT) method.
**
** dbHintSize is set to a copy of the dbSize variable when a
** write-transaction is opened (at the same time as dbFileSize and
** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called,
** dbHintSize is increased to the number of pages that correspond to the
-** size-hint passed to the method call. See pager_write_pagelist() for
+** size-hint passed to the method call. See pager_write_pagelist() for
** details.
**
** errCode
**
** The Pager.errCode variable is only ever used in PAGER_ERROR state. It
-** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
-** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
+** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
+** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
** sub-codes.
+**
+** syncFlags, walSyncFlags
+**
+** syncFlags is either SQLITE_SYNC_NORMAL (0x02) or SQLITE_SYNC_FULL (0x03).
+** syncFlags is used for rollback mode. walSyncFlags is used for WAL mode
+** and contains the flags used to sync the checkpoint operations in the
+** lower two bits, and sync flags used for transaction commits in the WAL
+** file in bits 0x04 and 0x08. In other words, to get the correct sync flags
+** for checkpoint operations, use (walSyncFlags&0x03) and to get the correct
+** sync flags for transaction commit, use ((walSyncFlags>>2)&0x03). Note
+** that with synchronous=NORMAL in WAL mode, transaction commit is not synced
+** meaning that the 0x04 and 0x08 bits are both zero.
*/
struct Pager {
sqlite3_vfs *pVfs; /* OS functions to use for IO */
@@ -46990,9 +52331,8 @@ struct Pager {
u8 noSync; /* Do not sync the journal if true */
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 extraSync; /* sync directory after journal delete */
- u8 ckptSyncFlags; /* SYNC_NORMAL or SYNC_FULL for checkpoint */
- u8 walSyncFlags; /* SYNC_NORMAL or SYNC_FULL for wal writes */
u8 syncFlags; /* SYNC_NORMAL or SYNC_FULL otherwise */
+ u8 walSyncFlags; /* See description above */
u8 tempFile; /* zFilename is a temporary or immutable file */
u8 noLock; /* Do not lock (except in WAL mode) */
u8 readOnly; /* True for a read-only database */
@@ -47010,7 +52350,7 @@ struct Pager {
u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
u8 eLock; /* Current lock held on database file */
u8 changeCountDone; /* Set after incrementing the change-counter */
- u8 setMaster; /* True if a m-j name has been written to jrnl */
+ u8 setSuper; /* Super-jrnl name is written into jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 subjInMemory; /* True to use in-memory sub-journals */
u8 bUseFetch; /* True to use xFetch() */
@@ -47053,17 +52393,12 @@ struct Pager {
char *zJournal; /* Name of the journal file */
int (*xBusyHandler)(void*); /* Function to call when busy */
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
- int aStat[3]; /* Total cache hits, misses and writes */
+ int aStat[4]; /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
int nRead; /* Database pages read */
#endif
void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
-#ifdef SQLITE_HAS_CODEC
- void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
- void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
- void (*xCodecFree)(void*); /* Destructor for the codec */
- void *pCodec; /* First argument to xCodec... methods */
-#endif
+ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
PCache *pPCache; /* Pointer to page cache object */
#ifndef SQLITE_OMIT_WAL
@@ -47074,12 +52409,13 @@ struct Pager {
/*
** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
-** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
+** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
** or CACHE_WRITE to sqlite3_db_status().
*/
#define PAGER_STAT_HIT 0
#define PAGER_STAT_MISS 1
#define PAGER_STAT_WRITE 2
+#define PAGER_STAT_SPILL 3
/*
** The following global variables hold counters used for
@@ -47131,7 +52467,7 @@ static const unsigned char aJournalMagic[] = {
#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)
/*
-** The journal header size for this pager. This is usually the same
+** The journal header size for this pager. This is usually the same
** size as a single disk sector. See also setSectorSize().
*/
#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)
@@ -47159,11 +52495,6 @@ static const unsigned char aJournalMagic[] = {
#endif
/*
-** The maximum legal page number is (2^31 - 1).
-*/
-#define PAGER_MAX_PGNO 2147483647
-
-/*
** The argument to this macro is a file descriptor (type sqlite3_file*).
** Return 0 if it is not open, or non-zero (but not 1) if it is.
**
@@ -47177,15 +52508,32 @@ static const unsigned char aJournalMagic[] = {
*/
#define isOpen(pFd) ((pFd)->pMethods!=0)
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
/*
-** Return true if this pager uses a write-ahead log instead of the usual
-** rollback journal. Otherwise false.
+** Return true if page pgno can be read directly from the database file
+** by the b-tree layer. This is the case if:
+**
+** * the database file is open,
+** * there are no dirty pages in the cache, and
+** * the desired page is not currently in the wal file.
*/
+SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
+ if( pPager->fd->pMethods==0 ) return 0;
+ if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
#ifndef SQLITE_OMIT_WAL
-SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager){
- return (pPager->pWal!=0);
+ if( pPager->pWal ){
+ u32 iRead = 0;
+ int rc;
+ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
+ return (rc==SQLITE_OK && iRead==0);
+ }
+#endif
+ return 1;
}
-# define pagerUseWal(x) sqlite3PagerUseWal(x)
+#endif
+
+#ifndef SQLITE_OMIT_WAL
+# define pagerUseWal(x) ((x)->pWal!=0)
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
@@ -47194,7 +52542,7 @@ SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager){
# define pagerBeginReadTransaction(z) SQLITE_OK
#endif
-#ifndef NDEBUG
+#ifndef NDEBUG
/*
** Usage:
**
@@ -47223,25 +52571,25 @@ static int assert_pager_state(Pager *p){
assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK );
assert( p->tempFile==0 || pPager->changeCountDone );
- /* If the useJournal flag is clear, the journal-mode must be "OFF".
+ /* If the useJournal flag is clear, the journal-mode must be "OFF".
** And if the journal-mode is "OFF", the journal file must not be open.
*/
assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
- /* Check that MEMDB implies noSync. And an in-memory journal. Since
- ** this means an in-memory pager performs no IO at all, it cannot encounter
- ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
- ** a journal file. (although the in-memory journal implementation may
- ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
- ** is therefore not possible for an in-memory pager to enter the ERROR
+ /* Check that MEMDB implies noSync. And an in-memory journal. Since
+ ** this means an in-memory pager performs no IO at all, it cannot encounter
+ ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
+ ** a journal file. (although the in-memory journal implementation may
+ ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
+ ** is therefore not possible for an in-memory pager to enter the ERROR
** state.
*/
if( MEMDB ){
assert( !isOpen(p->fd) );
assert( p->noSync );
- assert( p->journalMode==PAGER_JOURNALMODE_OFF
- || p->journalMode==PAGER_JOURNALMODE_MEMORY
+ assert( p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_MEMORY
);
assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
assert( pagerUseWal(p)==0 );
@@ -47275,7 +52623,7 @@ static int assert_pager_state(Pager *p){
assert( pPager->dbSize==pPager->dbOrigSize );
assert( pPager->dbOrigSize==pPager->dbFileSize );
assert( pPager->dbOrigSize==pPager->dbHintSize );
- assert( pPager->setMaster==0 );
+ assert( pPager->setSuper==0 );
break;
case PAGER_WRITER_CACHEMOD:
@@ -47288,9 +52636,9 @@ static int assert_pager_state(Pager *p){
** to journal_mode=wal.
*/
assert( p->eLock>=RESERVED_LOCK );
- assert( isOpen(p->jfd)
- || p->journalMode==PAGER_JOURNALMODE_OFF
- || p->journalMode==PAGER_JOURNALMODE_WAL
+ assert( isOpen(p->jfd)
+ || p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_WAL
);
}
assert( pPager->dbOrigSize==pPager->dbFileSize );
@@ -47302,9 +52650,10 @@ static int assert_pager_state(Pager *p){
assert( pPager->errCode==SQLITE_OK );
assert( !pagerUseWal(pPager) );
assert( p->eLock>=EXCLUSIVE_LOCK );
- assert( isOpen(p->jfd)
- || p->journalMode==PAGER_JOURNALMODE_OFF
- || p->journalMode==PAGER_JOURNALMODE_WAL
+ assert( isOpen(p->jfd)
+ || p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_WAL
+ || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
assert( pPager->dbOrigSize<=pPager->dbHintSize );
break;
@@ -47313,9 +52662,10 @@ static int assert_pager_state(Pager *p){
assert( p->eLock==EXCLUSIVE_LOCK );
assert( pPager->errCode==SQLITE_OK );
assert( !pagerUseWal(pPager) );
- assert( isOpen(p->jfd)
- || p->journalMode==PAGER_JOURNALMODE_OFF
- || p->journalMode==PAGER_JOURNALMODE_WAL
+ assert( isOpen(p->jfd)
+ || p->journalMode==PAGER_JOURNALMODE_OFF
+ || p->journalMode==PAGER_JOURNALMODE_WAL
+ || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
break;
@@ -47333,7 +52683,7 @@ static int assert_pager_state(Pager *p){
}
#endif /* ifndef NDEBUG */
-#ifdef SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
/*
** Return a pointer to a human readable string in a static buffer
** containing the state of the Pager object passed as an argument. This
@@ -47341,8 +52691,12 @@ static int assert_pager_state(Pager *p){
** to "print *pPager" in gdb:
**
** (gdb) printf "%s", print_pager_state(pPager)
+**
+** This routine has external linkage in order to suppress compiler warnings
+** about an unused function. It is enclosed within SQLITE_DEBUG and so does
+** not appear in normal builds.
*/
-static char *print_pager_state(Pager *p){
+char *print_pager_state(Pager *p){
static char zRet[1024];
sqlite3_snprintf(1024, zRet,
@@ -47384,6 +52738,29 @@ static char *print_pager_state(Pager *p){
}
#endif
+/* Forward references to the various page getters */
+static int getPageNormal(Pager*,Pgno,DbPage**,int);
+static int getPageError(Pager*,Pgno,DbPage**,int);
+#if SQLITE_MAX_MMAP_SIZE>0
+static int getPageMMap(Pager*,Pgno,DbPage**,int);
+#endif
+
+/*
+** Set the Pager.xGet method for the appropriate routine used to fetch
+** content from the pager.
+*/
+static void setGetterMethod(Pager *pPager){
+ if( pPager->errCode ){
+ pPager->xGet = getPageError;
+#if SQLITE_MAX_MMAP_SIZE>0
+ }else if( USEFETCH(pPager) ){
+ pPager->xGet = getPageMMap;
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+ }else{
+ pPager->xGet = getPageNormal;
+ }
+}
+
/*
** Return true if it is necessary to write page *pPg into the sub-journal.
** A page needs to be written into the sub-journal if there exists one
@@ -47454,7 +52831,7 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
** succeeds, set the Pager.eLock variable to match the (attempted) new lock.
**
** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
-** called, do not modify it. See the comment above the #define of
+** called, do not modify it. See the comment above the #define of
** UNKNOWN_LOCK for an explanation of this.
*/
static int pagerUnlockDb(Pager *pPager, int eLock){
@@ -47471,17 +52848,18 @@ static int pagerUnlockDb(Pager *pPager, int eLock){
}
IOTRACE(("UNLOCK %p %d\n", pPager, eLock))
}
+ pPager->changeCountDone = pPager->tempFile; /* ticket fb3b3024ea238d5c */
return rc;
}
/*
** Lock the database file to level eLock, which must be either SHARED_LOCK,
** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
-** Pager.eLock variable to the new locking state.
+** Pager.eLock variable to the new locking state.
**
-** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
-** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
-** See the comment above the #define of UNKNOWN_LOCK for an explanation
+** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
+** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
+** See the comment above the #define of UNKNOWN_LOCK for an explanation
** of this.
*/
static int pagerLockDb(Pager *pPager, int eLock){
@@ -47499,34 +52877,47 @@ static int pagerLockDb(Pager *pPager, int eLock){
}
/*
-** This function determines whether or not the atomic-write optimization
-** can be used with this pager. The optimization can be used if:
+** This function determines whether or not the atomic-write or
+** atomic-batch-write optimizations can be used with this pager. The
+** atomic-write optimization can be used if:
**
** (a) the value returned by OsDeviceCharacteristics() indicates that
** a database page may be written atomically, and
** (b) the value returned by OsSectorSize() is less than or equal
** to the page size.
**
-** The optimization is also always enabled for temporary files. It is
-** an error to call this function if pPager is opened on an in-memory
-** database.
+** If it can be used, then the value returned is the size of the journal
+** file when it contains rollback data for exactly one page.
+**
+** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
+** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
+** returned in this case.
**
-** If the optimization cannot be used, 0 is returned. If it can be used,
-** then the value returned is the size of the journal file when it
-** contains rollback data for exactly one page.
+** If neither optimization can be used, 0 is returned.
*/
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
static int jrnlBufferSize(Pager *pPager){
assert( !MEMDB );
- if( !pPager->tempFile ){
- int dc; /* Device characteristics */
- int nSector; /* Sector size */
- int szPage; /* Page size */
- assert( isOpen(pPager->fd) );
- dc = sqlite3OsDeviceCharacteristics(pPager->fd);
- nSector = pPager->sectorSize;
- szPage = pPager->pageSize;
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
+ int dc; /* Device characteristics */
+
+ assert( isOpen(pPager->fd) );
+ dc = sqlite3OsDeviceCharacteristics(pPager->fd);
+#else
+ UNUSED_PARAMETER(pPager);
+#endif
+
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( pPager->dbSize>0 && (dc&SQLITE_IOCAP_BATCH_ATOMIC) ){
+ return -1;
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ {
+ int nSector = pPager->sectorSize;
+ int szPage = pPager->pageSize;
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
@@ -47536,11 +52927,11 @@ static int jrnlBufferSize(Pager *pPager){
}
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
-}
-#else
-# define jrnlBufferSize(x) 0
#endif
+ return 0;
+}
+
/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function. This is used for testing
@@ -47586,71 +52977,73 @@ static void checkPage(PgHdr *pPg){
/*
** When this is called the journal file for pager pPager must be open.
-** This function attempts to read a master journal file name from the
-** end of the file and, if successful, copies it into memory supplied
-** by the caller. See comments above writeMasterJournal() for the format
-** used to store a master journal file name at the end of a journal file.
+** This function attempts to read a super-journal file name from the
+** end of the file and, if successful, copies it into memory supplied
+** by the caller. See comments above writeSuperJournal() for the format
+** used to store a super-journal file name at the end of a journal file.
**
-** zMaster must point to a buffer of at least nMaster bytes allocated by
+** zSuper must point to a buffer of at least nSuper bytes allocated by
** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
-** enough space to write the master journal name). If the master journal
-** name in the journal is longer than nMaster bytes (including a
-** nul-terminator), then this is handled as if no master journal name
+** enough space to write the super-journal name). If the super-journal
+** name in the journal is longer than nSuper bytes (including a
+** nul-terminator), then this is handled as if no super-journal name
** were present in the journal.
**
-** If a master journal file name is present at the end of the journal
-** file, then it is copied into the buffer pointed to by zMaster. A
-** nul-terminator byte is appended to the buffer following the master
-** journal file name.
+** If a super-journal file name is present at the end of the journal
+** file, then it is copied into the buffer pointed to by zSuper. A
+** nul-terminator byte is appended to the buffer following the
+** super-journal file name.
**
-** If it is determined that no master journal file name is present
-** zMaster[0] is set to 0 and SQLITE_OK returned.
+** If it is determined that no super-journal file name is present
+** zSuper[0] is set to 0 and SQLITE_OK returned.
**
** If an error occurs while reading from the journal file, an SQLite
** error code is returned.
*/
-static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
+static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){
int rc; /* Return code */
- u32 len; /* Length in bytes of master journal name */
+ u32 len; /* Length in bytes of super-journal name */
i64 szJ; /* Total size in bytes of journal file pJrnl */
u32 cksum; /* MJ checksum value read from journal */
u32 u; /* Unsigned loop counter */
unsigned char aMagic[8]; /* A buffer to hold the magic header */
- zMaster[0] = '\0';
+ zSuper[0] = '\0';
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
|| szJ<16
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
- || len>=nMaster
- || len==0
+ || len>=nSuper
+ || len>szJ-16
+ || len==0
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|| memcmp(aMagic, aJournalMagic, 8)
- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))
+ || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len))
){
return rc;
}
- /* See if the checksum matches the master journal name */
+ /* See if the checksum matches the super-journal name */
for(u=0; u<len; u++){
- cksum -= zMaster[u];
+ cksum -= zSuper[u];
}
if( cksum ){
/* If the checksum doesn't add up, then one or more of the disk sectors
- ** containing the master journal filename is corrupted. This means
+ ** containing the super-journal filename is corrupted. This means
** definitely roll back, so just return SQLITE_OK and report a (nul)
- ** master-journal filename.
+ ** super-journal filename.
*/
len = 0;
}
- zMaster[len] = '\0';
-
+ zSuper[len] = '\0';
+ zSuper[len+1] = '\0';
+
return SQLITE_OK;
}
/*
-** Return the offset of the sector boundary at or immediately
-** following the value in pPager->journalOff, assuming a sector
+** Return the offset of the sector boundary at or immediately
+** following the value in pPager->journalOff, assuming a sector
** size of pPager->sectorSize bytes.
**
** i.e for a sector size of 512:
@@ -47661,7 +53054,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
** 512 512
** 100 512
** 2000 2048
-**
+**
*/
static i64 journalHdrOffset(Pager *pPager){
i64 offset = 0;
@@ -47683,12 +53076,12 @@ static i64 journalHdrOffset(Pager *pPager){
**
** If doTruncate is non-zero or the Pager.journalSizeLimit variable is
** set to 0, then truncate the journal file to zero bytes in size. Otherwise,
-** zero the 28-byte header at the start of the journal file. In either case,
-** if the pager is not in no-sync mode, sync the journal file immediately
+** zero the 28-byte header at the start of the journal file. In either case,
+** if the pager is not in no-sync mode, sync the journal file immediately
** after writing or truncating it.
**
** If Pager.journalSizeLimit is set to a positive, non-zero value, and
-** following the truncation or zeroing described above the size of the
+** following the truncation or zeroing described above the size of the
** journal file in bytes is larger than this value, then truncate the
** journal file to Pager.journalSizeLimit bytes. The journal file does
** not need to be synced following this operation.
@@ -47714,8 +53107,8 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags);
}
- /* At this point the transaction is committed but the write lock
- ** is still held on the file. If there is a size limit configured for
+ /* At this point the transaction is committed but the write lock
+ ** is still held on the file. If there is a size limit configured for
** the persistent journal and the journal file currently consumes more
** space than that limit allows for, truncate it now. There is no need
** to sync the file following this operation.
@@ -47743,7 +53136,7 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
** - 4 bytes: Initial database page count.
** - 4 bytes: Sector size used by the process that wrote this journal.
** - 4 bytes: Database page size.
-**
+**
** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.
*/
static int writeJournalHdr(Pager *pPager){
@@ -47759,8 +53152,8 @@ static int writeJournalHdr(Pager *pPager){
nHeader = JOURNAL_HDR_SZ(pPager);
}
- /* If there are active savepoints and any of them were created
- ** since the most recent journal header was written, update the
+ /* If there are active savepoints and any of them were created
+ ** since the most recent journal header was written, update the
** PagerSavepoint.iHdrOffset fields now.
*/
for(ii=0; ii<pPager->nSavepoint; ii++){
@@ -47771,10 +53164,10 @@ static int writeJournalHdr(Pager *pPager){
pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager);
- /*
+ /*
** Write the nRec Field - the number of page records that follow this
** journal header. Normally, zero is written to this value at this time.
- ** After the records are added to the journal (and the journal synced,
+ ** After the records are added to the journal (and the journal synced,
** if in full-sync mode), the zero is overwritten with the true number
** of records (see syncJournal()).
**
@@ -47793,7 +53186,7 @@ static int writeJournalHdr(Pager *pPager){
*/
assert( isOpen(pPager->fd) || pPager->noSync );
if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY)
- || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
+ || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
){
memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
@@ -47801,7 +53194,7 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
- /* The random check-hash initializer */
+ /* The random check-hash initializer */
sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
/* The initial database size */
@@ -47820,23 +53213,23 @@ static int writeJournalHdr(Pager *pPager){
memset(&zHeader[sizeof(aJournalMagic)+20], 0,
nHeader-(sizeof(aJournalMagic)+20));
- /* In theory, it is only necessary to write the 28 bytes that the
- ** journal header consumes to the journal file here. Then increment the
- ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next
+ /* In theory, it is only necessary to write the 28 bytes that the
+ ** journal header consumes to the journal file here. Then increment the
+ ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next
** record is written to the following sector (leaving a gap in the file
** that will be implicitly filled in by the OS).
**
- ** However it has been discovered that on some systems this pattern can
+ ** However it has been discovered that on some systems this pattern can
** be significantly slower than contiguously writing data to the file,
- ** even if that means explicitly writing data to the block of
+ ** even if that means explicitly writing data to the block of
** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what
- ** is done.
+ ** is done.
**
- ** The loop is required here in case the sector-size is larger than the
+ ** The loop is required here in case the sector-size is larger than the
** database page size. Since the zHeader buffer is only Pager.pageSize
** bytes in size, more than one call to sqlite3OsWrite() may be required
** to populate the entire journal header sector.
- */
+ */
for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){
IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader))
rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
@@ -47934,29 +53327,29 @@ static int readJournalHdr(
/* Check that the values read from the page-size and sector-size fields
** are within range. To be 'in range', both values need to be a power
- ** of two greater than or equal to 512 or 32, and not greater than their
+ ** of two greater than or equal to 512 or 32, and not greater than their
** respective compile time maximum limits.
*/
if( iPageSize<512 || iSectorSize<32
|| iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE
- || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0
+ || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0
){
- /* If the either the page-size or sector-size in the journal-header is
- ** invalid, then the process that wrote the journal-header must have
- ** crashed before the header was synced. In this case stop reading
+ /* If the either the page-size or sector-size in the journal-header is
+ ** invalid, then the process that wrote the journal-header must have
+ ** crashed before the header was synced. In this case stop reading
** the journal file here.
*/
return SQLITE_DONE;
}
- /* Update the page-size to match the value read from the journal.
- ** Use a testcase() macro to make sure that malloc failure within
+ /* Update the page-size to match the value read from the journal.
+ ** Use a testcase() macro to make sure that malloc failure within
** PagerSetPagesize() is tested.
*/
rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1);
testcase( rc!=SQLITE_OK );
- /* Update the assumed sector-size to match the value used by
+ /* Update the assumed sector-size to match the value used by
** the process that created this journal. If this journal was
** created by a process other than this one, then this routine
** is being called from within pager_playback(). The local value
@@ -47971,50 +53364,50 @@ static int readJournalHdr(
/*
-** Write the supplied master journal name into the journal file for pager
-** pPager at the current location. The master journal name must be the last
+** Write the supplied super-journal name into the journal file for pager
+** pPager at the current location. The super-journal name must be the last
** thing written to a journal file. If the pager is in full-sync mode, the
** journal file descriptor is advanced to the next sector boundary before
** anything is written. The format is:
**
** + 4 bytes: PAGER_MJ_PGNO.
-** + N bytes: Master journal filename in utf-8.
-** + 4 bytes: N (length of master journal name in bytes, no nul-terminator).
-** + 4 bytes: Master journal name checksum.
+** + N bytes: super-journal filename in utf-8.
+** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator).
+** + 4 bytes: super-journal name checksum.
** + 8 bytes: aJournalMagic[].
**
-** The master journal page checksum is the sum of the bytes in the master
-** journal name, where each byte is interpreted as a signed 8-bit integer.
+** The super-journal page checksum is the sum of the bytes in thesuper-journal
+** name, where each byte is interpreted as a signed 8-bit integer.
**
-** If zMaster is a NULL pointer (occurs for a single database transaction),
+** If zSuper is a NULL pointer (occurs for a single database transaction),
** this call is a no-op.
*/
-static int writeMasterJournal(Pager *pPager, const char *zMaster){
+static int writeSuperJournal(Pager *pPager, const char *zSuper){
int rc; /* Return code */
- int nMaster; /* Length of string zMaster */
+ int nSuper; /* Length of string zSuper */
i64 iHdrOff; /* Offset of header in journal file */
i64 jrnlSize; /* Size of journal file on disk */
- u32 cksum = 0; /* Checksum of string zMaster */
+ u32 cksum = 0; /* Checksum of string zSuper */
- assert( pPager->setMaster==0 );
+ assert( pPager->setSuper==0 );
assert( !pagerUseWal(pPager) );
- if( !zMaster
- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ if( !zSuper
+ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| !isOpen(pPager->jfd)
){
return SQLITE_OK;
}
- pPager->setMaster = 1;
+ pPager->setSuper = 1;
assert( pPager->journalHdr <= pPager->journalOff );
- /* Calculate the length in bytes and the checksum of zMaster */
- for(nMaster=0; zMaster[nMaster]; nMaster++){
- cksum += zMaster[nMaster];
+ /* Calculate the length in bytes and the checksum of zSuper */
+ for(nSuper=0; zSuper[nSuper]; nSuper++){
+ cksum += zSuper[nSuper];
}
/* If in full-sync mode, advance to the next disk sector before writing
- ** the master journal name. This is in case the previous page written to
+ ** the super-journal name. This is in case the previous page written to
** the journal has already been synced.
*/
if( pPager->fullSync ){
@@ -48022,30 +53415,30 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
}
iHdrOff = pPager->journalOff;
- /* Write the master journal data to the end of the journal file. If
+ /* Write the super-journal data to the end of the journal file. If
** an error occurs, return the error code to the caller.
*/
if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
- || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
+ || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4)))
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper)))
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8,
- iHdrOff+4+nMaster+8)))
+ iHdrOff+4+nSuper+8)))
){
return rc;
}
- pPager->journalOff += (nMaster+20);
+ pPager->journalOff += (nSuper+20);
- /* If the pager is in peristent-journal mode, then the physical
- ** journal-file may extend past the end of the master-journal name
- ** and 8 bytes of magic data just written to the file. This is
+ /* If the pager is in peristent-journal mode, then the physical
+ ** journal-file may extend past the end of the super-journal name
+ ** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
- ** will not be able to find the master-journal name to determine
- ** whether or not the journal is hot.
+ ** will not be able to find the super-journal name to determine
+ ** whether or not the journal is hot.
**
- ** Easiest thing to do in this scenario is to truncate the journal
+ ** Easiest thing to do in this scenario is to truncate the journal
** file to the required size.
- */
+ */
if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))
&& jrnlSize>pPager->journalOff
){
@@ -48067,7 +53460,6 @@ static void pager_reset(Pager *pPager){
** Return the pPager->iDataVersion value
*/
SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
- assert( pPager->eState>PAGER_OPEN );
return pPager->iDataVersion;
}
@@ -48091,7 +53483,7 @@ static void releaseAllSavepoints(Pager *pPager){
}
/*
-** Set the bit number pgno in the PagerSavepoint.pInSavepoint
+** Set the bit number pgno in the PagerSavepoint.pInSavepoint
** bitvecs of all open savepoints. Return SQLITE_OK if successful
** or SQLITE_NOMEM if a malloc failure occurs.
*/
@@ -48120,8 +53512,8 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is
** closed (if it is open).
**
-** If the pager is in ERROR state when this function is called, the
-** contents of the pager cache are discarded before switching back to
+** If the pager is in ERROR state when this function is called, the
+** contents of the pager cache are discarded before switching back to
** the OPEN state. Regardless of whether the pager is in exclusive-mode
** or not, any journal file left in the file-system will be treated
** as a hot-journal and rolled back the next time a read-transaction
@@ -48129,9 +53521,9 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
*/
static void pager_unlock(Pager *pPager){
- assert( pPager->eState==PAGER_READER
- || pPager->eState==PAGER_OPEN
- || pPager->eState==PAGER_ERROR
+ assert( pPager->eState==PAGER_READER
+ || pPager->eState==PAGER_OPEN
+ || pPager->eState==PAGER_ERROR
);
sqlite3BitvecDestroy(pPager->pInJournal);
@@ -48178,7 +53570,6 @@ static void pager_unlock(Pager *pPager){
** code is cleared and the cache reset in the block below.
*/
assert( pPager->errCode || pPager->eState!=PAGER_ERROR );
- pPager->changeCountDone = 0;
pPager->eState = PAGER_OPEN;
}
@@ -48198,27 +53589,28 @@ static void pager_unlock(Pager *pPager){
}
if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
pPager->errCode = SQLITE_OK;
+ setGetterMethod(pPager);
}
pPager->journalOff = 0;
pPager->journalHdr = 0;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
}
/*
** This function is called whenever an IOERR or FULL error that requires
** the pager to transition into the ERROR state may ahve occurred.
-** The first argument is a pointer to the pager structure, the second
-** the error-code about to be returned by a pager API function. The
-** value returned is a copy of the second argument to this function.
+** The first argument is a pointer to the pager structure, the second
+** the error-code about to be returned by a pager API function. The
+** value returned is a copy of the second argument to this function.
**
** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the
** IOERR sub-codes, the pager enters the ERROR state and the error code
** is stored in Pager.errCode. While the pager remains in the ERROR state,
** all major API calls on the Pager will immediately return Pager.errCode.
**
-** The ERROR state indicates that the contents of the pager-cache
-** cannot be trusted. This state can be cleared by completely discarding
+** The ERROR state indicates that the contents of the pager-cache
+** cannot be trusted. This state can be cleared by completely discarding
** the contents of the pager-cache. If a transaction was active when
** the persistent error occurred, then the rollback journal may need
** to be replayed to restore the contents of the database file (as if
@@ -48235,6 +53627,7 @@ static int pager_error(Pager *pPager, int rc){
if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
pPager->errCode = rc;
pPager->eState = PAGER_ERROR;
+ setGetterMethod(pPager);
}
return rc;
}
@@ -48265,27 +53658,27 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
}
/*
-** This routine ends a transaction. A transaction is usually ended by
-** either a COMMIT or a ROLLBACK operation. This routine may be called
+** This routine ends a transaction. A transaction is usually ended by
+** either a COMMIT or a ROLLBACK operation. This routine may be called
** after rollback of a hot-journal, or if an error occurs while opening
** the journal file or writing the very first journal-header of a
** database transaction.
-**
+**
** This routine is never called in PAGER_ERROR state. If it is called
** in PAGER_NONE or PAGER_SHARED state and the lock held is less
** exclusive than a RESERVED lock, it is a no-op.
**
** Otherwise, any active savepoints are released.
**
-** If the journal file is open, then it is "finalized". Once a journal
-** file has been finalized it is not possible to use it to roll back a
+** If the journal file is open, then it is "finalized". Once a journal
+** file has been finalized it is not possible to use it to roll back a
** transaction. Nor will it be considered to be a hot-journal by this
** or any other database connection. Exactly how a journal is finalized
** depends on whether or not the pager is running in exclusive mode and
** the current journal-mode (Pager.journalMode value), as follows:
**
** journalMode==MEMORY
-** Journal file descriptor is simply closed. This destroys an
+** Journal file descriptor is simply closed. This destroys an
** in-memory journal.
**
** journalMode==TRUNCATE
@@ -48305,19 +53698,19 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
** journalMode==PERSIST is used instead.
**
** After the journal is finalized, the pager moves to PAGER_READER state.
-** If running in non-exclusive rollback mode, the lock on the file is
+** If running in non-exclusive rollback mode, the lock on the file is
** downgraded to a SHARED_LOCK.
**
** SQLITE_OK is returned if no error occurs. If an error occurs during
** any of the IO operations to finalize the journal file or unlock the
-** database then the IO error code is returned to the user. If the
+** database then the IO error code is returned to the user. If the
** operation to finalize the journal file fails, then the code still
** tries to unlock the database file if not in exclusive mode. If the
** unlock operation fails as well, then the first error code related
** to the first error encountered (the journal finalization one) is
** returned.
*/
-static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
+static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
int rc = SQLITE_OK; /* Error code from journal finalization operation */
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
@@ -48329,9 +53722,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
** 1. After a successful hot-journal rollback, it is called with
** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK.
**
- ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
+ ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
** lock switches back to locking_mode=normal and then executes a
- ** read-transaction, this function is called with eState==PAGER_READER
+ ** read-transaction, this function is called with eState==PAGER_READER
** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed.
*/
assert( assert_pager_state(pPager) );
@@ -48341,7 +53734,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}
releaseAllSavepoints(pPager);
- assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
+ assert( isOpen(pPager->jfd) || pPager->pInJournal==0
+ || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
+ );
if( isOpen(pPager->jfd) ){
assert( !pagerUseWal(pPager) );
@@ -48367,7 +53762,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
- rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
+ rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile);
pPager->journalOff = 0;
}else{
/* This branch may be executed with Pager.journalMode==MEMORY if
@@ -48377,9 +53772,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
*/
int bDelete = !pPager->tempFile;
assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
- assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
- || pPager->journalMode==PAGER_JOURNALMODE_WAL
+ assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
+ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
);
sqlite3OsClose(pPager->jfd);
if( bDelete ){
@@ -48403,7 +53798,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
pPager->pInJournal = 0;
pPager->nRec = 0;
if( rc==SQLITE_OK ){
- if( pagerFlushOnCommit(pPager, bCommit) ){
+ if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){
sqlite3PcacheCleanAll(pPager->pPCache);
}else{
sqlite3PcacheClearWritable(pPager->pPCache);
@@ -48412,8 +53807,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}
if( pagerUseWal(pPager) ){
- /* Drop the WAL write-lock, if any. Also, if the connection was in
- ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
+ /* Drop the WAL write-lock, if any. Also, if the connection was in
+ ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
** lock held on the database file.
*/
rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
@@ -48421,7 +53816,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
/* This branch is taken when committing a transaction in rollback-journal
** mode if the database file on disk is larger than the database image.
- ** At this point the journal has been finalized and the transaction
+ ** At this point the journal has been finalized and the transaction
** successfully committed, but the EXCLUSIVE lock is still held on the
** file. So it is safe to truncate the database file to its minimum
** required size. */
@@ -48429,37 +53824,36 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
rc = pager_truncate(pPager, pPager->dbSize);
}
- if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
+ if( rc==SQLITE_OK && bCommit ){
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
}
- if( !pPager->exclusiveMode
+ if( !pPager->exclusiveMode
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
){
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
- pPager->changeCountDone = 0;
}
pPager->eState = PAGER_READER;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
return (rc==SQLITE_OK?rc2:rc);
}
/*
-** Execute a rollback if a transaction is active and unlock the
-** database file.
+** Execute a rollback if a transaction is active and unlock the
+** database file.
**
-** If the pager has already entered the ERROR state, do not attempt
+** If the pager has already entered the ERROR state, do not attempt
** the rollback at this time. Instead, pager_unlock() is called. The
** call to pager_unlock() will discard all in-memory pages, unlock
-** the database file and move the pager back to OPEN state. If this
-** means that there is a hot-journal left in the file-system, the next
-** connection to obtain a shared lock on the pager (which may be this one)
+** the database file and move the pager back to OPEN state. If this
+** means that there is a hot-journal left in the file-system, the next
+** connection to obtain a shared lock on the pager (which may be this one)
** will roll it back.
**
** If the pager has not already entered the ERROR state, but an IO or
-** malloc error occurs during a rollback, then this will itself cause
+** malloc error occurs during a rollback, then this will itself cause
** the pager to enter the ERROR state. Which will be cleared by the
** call to pager_unlock(), as described above.
*/
@@ -48480,10 +53874,10 @@ static void pagerUnlockAndRollback(Pager *pPager){
/*
** Parameter aData must point to a buffer of pPager->pageSize bytes
-** of data. Compute and return a checksum based ont the contents of the
+** of data. Compute and return a checksum based ont the contents of the
** page of data and the current value of pPager->cksumInit.
**
-** This is not a real checksum. It is really just the sum of the
+** This is not a real checksum. It is really just the sum of the
** random initial value (pPager->cksumInit) and every 200th byte
** of the page data, starting with byte offset (pPager->pageSize%200).
** Each byte is interpreted as an 8-bit unsigned integer.
@@ -48491,8 +53885,8 @@ static void pagerUnlockAndRollback(Pager *pPager){
** Changing the formula used to compute this checksum results in an
** incompatible journal file format.
**
-** If journal corruption occurs due to a power failure, the most likely
-** scenario is that one end or the other of the record will be changed.
+** If journal corruption occurs due to a power failure, the most likely
+** scenario is that one end or the other of the record will be changed.
** It is much less likely that the two ends of the journal record will be
** correct and the middle be corrupt. Thus, this "checksum" scheme,
** though fast and simple, catches the mostly likely kind of corruption.
@@ -48508,41 +53902,12 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
}
/*
-** Report the current page size and number of reserved bytes back
-** to the codec.
-*/
-#ifdef SQLITE_HAS_CODEC
-static void pagerReportSize(Pager *pPager){
- if( pPager->xCodecSizeChng ){
- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
- (int)pPager->nReserve);
- }
-}
-#else
-# define pagerReportSize(X) /* No-op if we do not support a codec */
-#endif
-
-#ifdef SQLITE_HAS_CODEC
-/*
-** Make sure the number of reserved bits is the same in the destination
-** pager as it is in the source. This comes up when a VACUUM changes the
-** number of reserved bits to the "optimal" amount.
-*/
-SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
- if( pDest->nReserve!=pSrc->nReserve ){
- pDest->nReserve = pSrc->nReserve;
- pagerReportSize(pDest);
- }
-}
-#endif
-
-/*
** Read a single page from either the journal file (if isMainJrnl==1) or
** from the sub-journal (if isMainJrnl==0) and playback that page.
** The page begins at offset *pOffset into the file. The *pOffset
** value is increased to the start of the next page in the journal.
**
-** The main rollback journal uses checksums - the statement journal does
+** The main rollback journal uses checksums - the statement journal does
** not.
**
** If the page number of the page record read from the (sub-)journal file
@@ -48562,7 +53927,7 @@ SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
** is successfully read from the (sub-)journal file but appears to be
** corrupted, SQLITE_DONE is returned. Data is considered corrupted in
** two circumstances:
-**
+**
** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or
** * If the record is being rolled back from the main journal file
** and the checksum field does not match the record content.
@@ -48597,7 +53962,7 @@ static int pager_playback_one_page(
assert( aData ); /* Temp storage must have already been allocated */
assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
- /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction
+ /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction
** or savepoint rollback done at the request of the caller) or this is
** a hot-journal rollback. If it is a hot-journal rollback, the pager
** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback
@@ -48649,7 +54014,6 @@ static int pager_playback_one_page(
*/
if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
pPager->nReserve = ((u8*)aData)[20];
- pagerReportSize(pPager);
}
/* If the pager is in CACHEMOD state, then there must be a copy of this
@@ -48664,7 +54028,7 @@ static int pager_playback_one_page(
** assert()able.
**
** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the
- ** pager cache if it exists and the main file. The page is then marked
+ ** pager cache if it exists and the main file. The page is then marked
** not dirty. Since this code is only executed in PAGER_OPEN state for
** a hot-journal rollback, it is guaranteed that the page-cache is empty
** if the pager is in OPEN state.
@@ -48710,30 +54074,36 @@ static int pager_playback_one_page(
i64 ofst = (pgno-1)*(i64)pPager->pageSize;
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
assert( !pagerUseWal(pPager) );
+
+ /* Write the data read from the journal back into the database file.
+ ** This is usually safe even for an encrypted database - as the data
+ ** was encrypted before it was written to the journal file. The exception
+ ** is if the data was just read from an in-memory sub-journal. In that
+ ** case it must be encrypted here before it is copied into the database
+ ** file. */
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
+
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
if( pPager->pBackup ){
- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
}
}else if( !isMainJrnl && pPg==0 ){
/* If this is a rollback of a savepoint and data was not written to
** the database and the page is not in-memory, there is a potential
- ** problem. When the page is next fetched by the b-tree layer, it
- ** will be read from the database file, which may or may not be
- ** current.
+ ** problem. When the page is next fetched by the b-tree layer, it
+ ** will be read from the database file, which may or may not be
+ ** current.
**
** There are a couple of different ways this can happen. All are quite
- ** obscure. When running in synchronous mode, this can only happen
+ ** obscure. When running in synchronous mode, this can only happen
** if the page is on the free-list at the start of the transaction, then
** populated, then moved using sqlite3PagerMovepage().
**
** The solution is to add an in-memory page to the cache containing
- ** the data just read from the sub-journal. Mark the page as dirty
- ** and if the pager requires a journal-sync, then mark the page as
+ ** the data just read from the sub-journal. Mark the page as dirty
+ ** and if the pager requires a journal-sync, then mark the page as
** requiring a journal-sync before it is written.
*/
assert( isSavepnt );
@@ -48767,162 +54137,164 @@ static int pager_playback_one_page(
if( pgno==1 ){
memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
}
-
- /* Decode the page just read from disk */
- CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3PcacheRelease(pPg);
}
return rc;
}
/*
-** Parameter zMaster is the name of a master journal file. A single journal
-** file that referred to the master journal file has just been rolled back.
-** This routine checks if it is possible to delete the master journal file,
+** Parameter zSuper is the name of a super-journal file. A single journal
+** file that referred to the super-journal file has just been rolled back.
+** This routine checks if it is possible to delete the super-journal file,
** and does so if it is.
**
-** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
+** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not
** available for use within this function.
**
-** When a master journal file is created, it is populated with the names
-** of all of its child journals, one after another, formatted as utf-8
-** encoded text. The end of each child journal file is marked with a
-** nul-terminator byte (0x00). i.e. the entire contents of a master journal
+** When a super-journal file is created, it is populated with the names
+** of all of its child journals, one after another, formatted as utf-8
+** encoded text. The end of each child journal file is marked with a
+** nul-terminator byte (0x00). i.e. the entire contents of a super-journal
** file for a transaction involving two databases might be:
**
** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
**
-** A master journal file may only be deleted once all of its child
+** A super-journal file may only be deleted once all of its child
** journals have been rolled back.
**
-** This function reads the contents of the master-journal file into
+** This function reads the contents of the super-journal file into
** memory and loops through each of the child journal names. For
** each child journal, it checks if:
**
** * if the child journal exists, and if so
-** * if the child journal contains a reference to master journal
-** file zMaster
+** * if the child journal contains a reference to super-journal
+** file zSuper
**
** If a child journal can be found that matches both of the criteria
** above, this function returns without doing anything. Otherwise, if
-** no such child journal can be found, file zMaster is deleted from
+** no such child journal can be found, file zSuper is deleted from
** the file-system using sqlite3OsDelete().
**
** If an IO error within this function, an error code is returned. This
** function allocates memory by calling sqlite3Malloc(). If an allocation
-** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
+** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
** occur, SQLITE_OK is returned.
**
** TODO: This function allocates a single block of memory to load
-** the entire contents of the master journal file. This could be
-** a couple of kilobytes or so - potentially larger than the page
+** the entire contents of the super-journal file. This could be
+** a couple of kilobytes or so - potentially larger than the page
** size.
*/
-static int pager_delmaster(Pager *pPager, const char *zMaster){
+static int pager_delsuper(Pager *pPager, const char *zSuper){
sqlite3_vfs *pVfs = pPager->pVfs;
int rc; /* Return code */
- sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */
+ sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
- char *zMasterJournal = 0; /* Contents of master journal file */
- i64 nMasterJournal; /* Size of master journal file */
+ char *zSuperJournal = 0; /* Contents of super-journal file */
+ i64 nSuperJournal; /* Size of super-journal file */
char *zJournal; /* Pointer to one journal within MJ file */
- char *zMasterPtr; /* Space to hold MJ filename from a journal file */
- int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
+ char *zSuperPtr; /* Space to hold super-journal filename */
+ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
- /* Allocate space for both the pJournal and pMaster file descriptors.
- ** If successful, open the master journal file for reading.
+ /* Allocate space for both the pJournal and pSuper file descriptors.
+ ** If successful, open the super-journal file for reading.
*/
- pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
- pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
- if( !pMaster ){
+ pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
+ if( !pSuper ){
rc = SQLITE_NOMEM_BKPT;
+ pJournal = 0;
}else{
- const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
- rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
+ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
+ rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
+ pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
}
- if( rc!=SQLITE_OK ) goto delmaster_out;
+ if( rc!=SQLITE_OK ) goto delsuper_out;
- /* Load the entire master journal file into space obtained from
- ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
- ** sufficient space (in zMasterPtr) to hold the names of master
- ** journal files extracted from regular rollback-journals.
+ /* Load the entire super-journal file into space obtained from
+ ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
+ ** sufficient space (in zSuperPtr) to hold the names of super-journal
+ ** files extracted from regular rollback-journals.
*/
- rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- nMasterPtr = pVfs->mxPathname+1;
- zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
- if( !zMasterJournal ){
+ rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
+ if( rc!=SQLITE_OK ) goto delsuper_out;
+ nSuperPtr = pVfs->mxPathname+1;
+ zSuperJournal = sqlite3Malloc(nSuperJournal + nSuperPtr + 2);
+ if( !zSuperJournal ){
rc = SQLITE_NOMEM_BKPT;
- goto delmaster_out;
+ goto delsuper_out;
}
- zMasterPtr = &zMasterJournal[nMasterJournal+1];
- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
- if( rc!=SQLITE_OK ) goto delmaster_out;
- zMasterJournal[nMasterJournal] = 0;
+ zSuperPtr = &zSuperJournal[nSuperJournal+2];
+ rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
+ if( rc!=SQLITE_OK ) goto delsuper_out;
+ zSuperJournal[nSuperJournal] = 0;
+ zSuperJournal[nSuperJournal+1] = 0;
- zJournal = zMasterJournal;
- while( (zJournal-zMasterJournal)<nMasterJournal ){
+ zJournal = zSuperJournal;
+ while( (zJournal-zSuperJournal)<nSuperJournal ){
int exists;
rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
if( rc!=SQLITE_OK ){
- goto delmaster_out;
+ goto delsuper_out;
}
if( exists ){
- /* One of the journals pointed to by the master journal exists.
- ** Open it and check if it points at the master journal. If
- ** so, return without deleting the master journal file.
+ /* One of the journals pointed to by the super-journal exists.
+ ** Open it and check if it points at the super-journal. If
+ ** so, return without deleting the super-journal file.
+ ** NB: zJournal is really a MAIN_JOURNAL. But call it a
+ ** SUPER_JOURNAL here so that the VFS will not send the zJournal
+ ** name into sqlite3_database_file_object().
*/
int c;
- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
if( rc!=SQLITE_OK ){
- goto delmaster_out;
+ goto delsuper_out;
}
- rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
+ rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr);
sqlite3OsClose(pJournal);
if( rc!=SQLITE_OK ){
- goto delmaster_out;
+ goto delsuper_out;
}
- c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
+ c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0;
if( c ){
- /* We have a match. Do not delete the master journal file. */
- goto delmaster_out;
+ /* We have a match. Do not delete the super-journal file. */
+ goto delsuper_out;
}
}
zJournal += (sqlite3Strlen30(zJournal)+1);
}
-
- sqlite3OsClose(pMaster);
- rc = sqlite3OsDelete(pVfs, zMaster, 0);
-delmaster_out:
- sqlite3_free(zMasterJournal);
- if( pMaster ){
- sqlite3OsClose(pMaster);
+ sqlite3OsClose(pSuper);
+ rc = sqlite3OsDelete(pVfs, zSuper, 0);
+
+delsuper_out:
+ sqlite3_free(zSuperJournal);
+ if( pSuper ){
+ sqlite3OsClose(pSuper);
assert( !isOpen(pJournal) );
- sqlite3_free(pMaster);
+ sqlite3_free(pSuper);
}
return rc;
}
/*
-** This function is used to change the actual size of the database
+** This function is used to change the actual size of the database
** file in the file-system. This only happens when committing a transaction,
** or rolling back a transaction (including rolling back a hot-journal).
**
** If the main database file is not open, or the pager is not in either
-** DBMOD or OPEN state, this function is a no-op. Otherwise, the size
-** of the file is changed to nPage pages (nPage*pPager->pageSize bytes).
+** DBMOD or OPEN state, this function is a no-op. Otherwise, the size
+** of the file is changed to nPage pages (nPage*pPager->pageSize bytes).
** If the file on disk is currently larger than nPage pages, then use the VFS
** xTruncate() method to truncate it.
**
-** Or, it might be the case that the file on disk is smaller than
-** nPage pages. Some operating system implementations can get confused if
-** you try to truncate a file to some size that is larger than it
-** currently is, so detect this case and write a single zero byte to
+** Or, it might be the case that the file on disk is smaller than
+** nPage pages. Some operating system implementations can get confused if
+** you try to truncate a file to some size that is larger than it
+** currently is, so detect this case and write a single zero byte to
** the end of the new file instead.
**
** If successful, return SQLITE_OK. If an IO error occurs while modifying
@@ -48932,9 +54304,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState!=PAGER_READER );
-
- if( isOpen(pPager->fd)
- && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
+
+ if( isOpen(pPager->fd)
+ && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
){
i64 currentSize, newSize;
int szPage = pPager->pageSize;
@@ -48978,9 +54350,9 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){
/*
** Set the value of the Pager.sectorSize variable for the given
** pager based on the value returned by the xSectorSize method
-** of the open database file. The sector size will be used
-** to determine the size and alignment of journal header and
-** master journal pointers within created journal files.
+** of the open database file. The sector size will be used
+** to determine the size and alignment of journal header and
+** super-journal pointers within created journal files.
**
** For temporary files the effective sector size is always 512 bytes.
**
@@ -49002,7 +54374,7 @@ static void setSectorSize(Pager *pPager){
assert( isOpen(pPager->fd) || pPager->tempFile );
if( pPager->tempFile
- || (sqlite3OsDeviceCharacteristics(pPager->fd) &
+ || (sqlite3OsDeviceCharacteristics(pPager->fd) &
SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
){
/* Sector size doesn't matter for temporary files. Also, the file
@@ -49016,15 +54388,15 @@ static void setSectorSize(Pager *pPager){
/*
** Playback the journal and thus restore the database file to
-** the state it was in before we started making changes.
+** the state it was in before we started making changes.
**
-** The journal file format is as follows:
+** The journal file format is as follows:
**
** (1) 8 byte prefix. A copy of aJournalMagic[].
** (2) 4 byte big-endian integer which is the number of valid page records
** in the journal. If this value is 0xffffffff, then compute the
** number of page records from the journal size.
-** (3) 4 byte big-endian integer which is the initial value for the
+** (3) 4 byte big-endian integer which is the initial value for the
** sanity checksum.
** (4) 4 byte integer which is the number of pages to truncate the
** database to during a rollback.
@@ -49053,7 +54425,7 @@ static void setSectorSize(Pager *pPager){
** from the file size. This value is used when the user selects the
** no-sync option for the journal. A power failure could lead to corruption
** in this case. But for things like temporary table (which will be
-** deleted when the power is restored) we don't care.
+** deleted when the power is restored) we don't care.
**
** If the file opened as the journal file is not a well-formed
** journal file then all pages up to the first corrupted page are rolled
@@ -49065,7 +54437,7 @@ static void setSectorSize(Pager *pPager){
** and an error code is returned.
**
** The isHot parameter indicates that we are trying to rollback a journal
-** that might be a hot journal. Or, it could be that the journal is
+** that might be a hot journal. Or, it could be that the journal is
** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE.
** If the journal really is hot, reset the pager cache prior rolling
** back any content. If the journal is merely persistent, no reset is
@@ -49079,9 +54451,10 @@ static int pager_playback(Pager *pPager, int isHot){
Pgno mxPg = 0; /* Size of the original file in pages */
int rc; /* Result code of a subroutine */
int res = 1; /* Value returned by sqlite3OsAccess() */
- char *zMaster = 0; /* Name of master journal file if any */
+ char *zSuper = 0; /* Name of super-journal file if any */
int needPagerReset; /* True to reset page prior to first page rollback */
int nPlayback = 0; /* Total number of pages restored from journal */
+ u32 savedPageSize = pPager->pageSize;
/* Figure out how many records are in the journal. Abort early if
** the journal is empty.
@@ -49092,8 +54465,8 @@ static int pager_playback(Pager *pPager, int isHot){
goto end_playback;
}
- /* Read the master journal name from the journal, if it is present.
- ** If a master journal file name is specified, but the file is not
+ /* Read the super-journal name from the journal, if it is present.
+ ** If a super-journal file name is specified, but the file is not
** present on disk, then the journal is not hot and does not need to be
** played back.
**
@@ -49103,21 +54476,21 @@ static int pager_playback(Pager *pPager, int isHot){
** mxPathname is 512, which is the same as the minimum allowable value
** for pageSize.
*/
- zMaster = pPager->pTmpSpace;
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
- if( rc==SQLITE_OK && zMaster[0] ){
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ zSuper = pPager->pTmpSpace;
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
+ if( rc==SQLITE_OK && zSuper[0] ){
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}
- zMaster = 0;
+ zSuper = 0;
if( rc!=SQLITE_OK || !res ){
goto end_playback;
}
pPager->journalOff = 0;
needPagerReset = isHot;
- /* This loop terminates either when a readJournalHdr() or
- ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
- ** occurs.
+ /* This loop terminates either when a readJournalHdr() or
+ ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
+ ** occurs.
*/
while( 1 ){
/* Read the next journal header from the journal file. If there are
@@ -49126,7 +54499,7 @@ static int pager_playback(Pager *pPager, int isHot){
** This indicates nothing more needs to be rolled back.
*/
rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg);
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK ){
if( rc==SQLITE_DONE ){
rc = SQLITE_OK;
}
@@ -49154,7 +54527,7 @@ static int pager_playback(Pager *pPager, int isHot){
** chunk of the journal contains zero pages to be rolled back. But
** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in
** the journal, it means that the journal might contain additional
- ** pages that need to be rolled back and that the number of pages
+ ** pages that need to be rolled back and that the number of pages
** should be computed based on the journal file size.
*/
if( nRec==0 && !isHot &&
@@ -49173,7 +54546,7 @@ static int pager_playback(Pager *pPager, int isHot){
pPager->dbSize = mxPg;
}
- /* Copy original pages out of the journal and back into the
+ /* Copy original pages out of the journal and back into the
** database file and/or page cache.
*/
for(u=0; u<nRec; u++){
@@ -49211,21 +54584,22 @@ static int pager_playback(Pager *pPager, int isHot){
assert( 0 );
end_playback:
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSetPagesize(pPager, &savedPageSize, -1);
+ }
/* Following a rollback, the database file should be back in its original
** state prior to the start of the transaction, so invoke the
** SQLITE_FCNTL_DB_UNCHANGED file-control method to disable the
** assertion that the transaction counter was modified.
*/
#ifdef SQLITE_DEBUG
- if( pPager->fd->pMethods ){
- sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
- }
+ sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
#endif
- /* If this playback is happening automatically as a result of an IO or
- ** malloc error that occurred after the change-counter was updated but
- ** before the transaction was committed, then the change-counter
- ** modification may just have been reverted. If this happens in exclusive
+ /* If this playback is happening automatically as a result of an IO or
+ ** malloc error that occurred after the change-counter was updated but
+ ** before the transaction was committed, then the change-counter
+ ** modification may just have been reverted. If this happens in exclusive
** mode, then subsequent transactions performed by the connection will not
** update the change-counter at all. This may lead to cache inconsistency
** problems for other processes at some point in the future. So, just
@@ -49234,8 +54608,8 @@ end_playback:
pPager->changeCountDone = pPager->tempFile;
if( rc==SQLITE_OK ){
- zMaster = pPager->pTmpSpace;
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
+ zSuper = pPager->pTmpSpace;
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
testcase( rc!=SQLITE_OK );
}
if( rc==SQLITE_OK
@@ -49244,14 +54618,14 @@ end_playback:
rc = sqlite3PagerSync(pPager, 0);
}
if( rc==SQLITE_OK ){
- rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
+ rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0);
testcase( rc!=SQLITE_OK );
}
- if( rc==SQLITE_OK && zMaster[0] && res ){
- /* If there was a master journal and this routine will return success,
- ** see if it is possible to delete the master journal.
+ if( rc==SQLITE_OK && zSuper[0] && res ){
+ /* If there was a super-journal and this routine will return success,
+ ** see if it is possible to delete the super-journal.
*/
- rc = pager_delmaster(pPager, zMaster);
+ rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
if( isHot && nPlayback ){
@@ -49269,7 +54643,8 @@ end_playback:
/*
-** Read the content for page pPg out of the database file and into
+** Read the content for page pPg out of the database file (or out of
+** the WAL if that is where the most recent copy if found) into
** pPg->pData. A shared lock or greater must be held on the database
** file before this function is called.
**
@@ -49279,30 +54654,33 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned.
*/
-static int readDbPage(PgHdr *pPg, u32 iFrame){
+static int readDbPage(PgHdr *pPg){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
- Pgno pgno = pPg->pgno; /* Page number to read */
int rc = SQLITE_OK; /* Return code */
- int pgsz = pPager->pageSize; /* Number of bytes to read */
+
+#ifndef SQLITE_OMIT_WAL
+ u32 iFrame = 0; /* Frame of WAL containing pgno */
assert( pPager->eState>=PAGER_READER && !MEMDB );
assert( isOpen(pPager->fd) );
-#ifndef SQLITE_OMIT_WAL
+ if( pagerUseWal(pPager) ){
+ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+ if( rc ) return rc;
+ }
if( iFrame ){
- /* Try to pull the page from the write-ahead log. */
- rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
+ rc = sqlite3WalReadFrame(pPager->pWal, iFrame,pPager->pageSize,pPg->pData);
}else
#endif
{
- i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
- rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
+ i64 iOffset = (pPg->pgno-1)*(i64)pPager->pageSize;
+ rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){
rc = SQLITE_OK;
}
}
- if( pgno==1 ){
+ if( pPg->pgno==1 ){
if( rc ){
/* If the read is unsuccessful, set the dbFileVers[] to something
** that will never be a valid file version. dbFileVers[] is a copy
@@ -49322,13 +54700,11 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
-
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
- IOTRACE(("PGIN %p %d\n", pPager, pgno));
+ IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
PAGERTRACE(("FETCH %d page %d hash(%08x)\n",
- PAGERID(pPager), pgno, pager_pagehash(pPg)));
+ PAGERID(pPager), pPg->pgno, pager_pagehash(pPg)));
return rc;
}
@@ -49357,15 +54733,15 @@ static void pager_write_changecounter(PgHdr *pPg){
#ifndef SQLITE_OMIT_WAL
/*
-** This function is invoked once for each page that has already been
+** This function is invoked once for each page that has already been
** written into the log file when a WAL transaction is rolled back.
-** Parameter iPg is the page number of said page. The pCtx argument
+** Parameter iPg is the page number of said page. The pCtx argument
** is actually a pointer to the Pager structure.
**
** If page iPg is present in the cache, and has no outstanding references,
** it is discarded. Otherwise, if there are one or more outstanding
** references, the page content is reloaded from the database. If the
-** attempt to reload content from the database is required and fails,
+** attempt to reload content from the database is required and fails,
** return an SQLite error code. Otherwise, SQLITE_OK.
*/
static int pagerUndoCallback(void *pCtx, Pgno iPg){
@@ -49379,11 +54755,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg);
}else{
- u32 iFrame = 0;
- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
- if( rc==SQLITE_OK ){
- rc = readDbPage(pPg, iFrame);
- }
+ rc = readDbPage(pPg);
if( rc==SQLITE_OK ){
pPager->xReiniter(pPg);
}
@@ -49395,7 +54767,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
** updated as data is copied out of the rollback journal and into the
** database. This is not generally possible with a WAL database, as
** rollback involves simply truncating the log file. Therefore, if one
- ** or more frames have already been written to the log (and therefore
+ ** or more frames have already been written to the log (and therefore
** also copied into the backup databases) as part of this transaction,
** the backups must be restarted.
*/
@@ -49412,7 +54784,7 @@ static int pagerRollbackWal(Pager *pPager){
PgHdr *pList; /* List of dirty pages to revert */
/* For all pages in the cache that are currently dirty or have already
- ** been written (but not committed) to the log file, do one of the
+ ** been written (but not committed) to the log file, do one of the
** following:
**
** + Discard the cached page (if refcount==0), or
@@ -49434,11 +54806,11 @@ static int pagerRollbackWal(Pager *pPager){
** This function is a wrapper around sqlite3WalFrames(). As well as logging
** the contents of the list of pages headed by pList (connected by pDirty),
** this function notifies any active backup processes that the pages have
-** changed.
+** changed.
**
** The list of pages passed into this routine is always sorted by page number.
** Hence, if page 1 appears anywhere on the list, it will be the first page.
-*/
+*/
static int pagerWalFrames(
Pager *pPager, /* Pager object */
PgHdr *pList, /* List of frames to log */
@@ -49479,7 +54851,7 @@ static int pagerWalFrames(
pPager->aStat[PAGER_STAT_WRITE] += nList;
if( pList->pgno==1 ) pager_write_changecounter(pList);
- rc = sqlite3WalFrames(pPager->pWal,
+ rc = sqlite3WalFrames(pPager->pWal,
pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
);
if( rc==SQLITE_OK && pPager->pBackup ){
@@ -49555,7 +54927,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
nPage = sqlite3WalDbsize(pPager->pWal);
/* If the number of pages in the database is not available from the
- ** WAL sub-system, determine the page counte based on the size of
+ ** WAL sub-system, determine the page count based on the size of
** the database file. If the size of the database file is not an
** integer multiple of the page-size, round up the result.
*/
@@ -49594,9 +54966,9 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
** Return SQLITE_OK or an error code.
**
** The caller must hold a SHARED lock on the database file to call this
-** function. Because an EXCLUSIVE lock on the db file is required to delete
-** a WAL on a none-empty database, this ensures there is no race condition
-** between the xAccess() below and an xDelete() being executed by some
+** function. Because an EXCLUSIVE lock on the db file is required to delete
+** a WAL on a none-empty database, this ensures there is no race condition
+** between the xAccess() below and an xDelete() being executed by some
** other connection.
*/
static int pagerOpenWalIfPresent(Pager *pPager){
@@ -49606,23 +54978,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){
if( !pPager->tempFile ){
int isWal; /* True if WAL file exists */
- Pgno nPage; /* Size of the database file */
-
- rc = pagerPagecount(pPager, &nPage);
- if( rc ) return rc;
- if( nPage==0 ){
- rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
- if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
- isWal = 0;
- }else{
- rc = sqlite3OsAccess(
- pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
- );
- }
+ rc = sqlite3OsAccess(
+ pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &isWal
+ );
if( rc==SQLITE_OK ){
if( isWal ){
- testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
- rc = sqlite3PagerOpenWal(pPager, 0);
+ Pgno nPage; /* Size of the database file */
+
+ rc = pagerPagecount(pPager, &nPage);
+ if( rc ) return rc;
+ if( nPage==0 ){
+ rc = sqlite3OsDelete(pPager->pVfs, pPager->zWal, 0);
+ }else{
+ testcase( sqlite3PcachePagecount(pPager->pPCache)==0 );
+ rc = sqlite3PagerOpenWal(pPager, 0);
+ }
}else if( pPager->journalMode==PAGER_JOURNALMODE_WAL ){
pPager->journalMode = PAGER_JOURNALMODE_DELETE;
}
@@ -49634,21 +55004,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){
/*
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
-** the entire master journal file. The case pSavepoint==NULL occurs when
-** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
+** the entire super-journal file. The case pSavepoint==NULL occurs when
+** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
** savepoint.
**
-** When pSavepoint is not NULL (meaning a non-transaction savepoint is
+** When pSavepoint is not NULL (meaning a non-transaction savepoint is
** being rolled back), then the rollback consists of up to three stages,
** performed in the order specified:
**
** * Pages are played back from the main journal starting at byte
-** offset PagerSavepoint.iOffset and continuing to
+** offset PagerSavepoint.iOffset and continuing to
** PagerSavepoint.iHdrOffset, or to the end of the main journal
** file if PagerSavepoint.iHdrOffset is zero.
**
** * If PagerSavepoint.iHdrOffset is not zero, then pages are played
-** back starting from the journal header immediately following
+** back starting from the journal header immediately following
** PagerSavepoint.iHdrOffset to the end of the main journal file.
**
** * Pages are then played back from the sub-journal file, starting
@@ -49664,7 +55034,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
** journal file. There is no need for a bitvec in this case.
**
** In either case, before playback commences the Pager.dbSize variable
-** is reset to the value that it held at the start of the savepoint
+** is reset to the value that it held at the start of the savepoint
** (or transaction). No page with a page-number greater than this value
** is played back. If one is encountered it is simply skipped.
*/
@@ -49685,7 +55055,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
}
}
- /* Set the database size back to the value it was before the savepoint
+ /* Set the database size back to the value it was before the savepoint
** being reverted was opened.
*/
pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
@@ -49738,7 +55108,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
** test is related to ticket #2565. See the discussion in the
** pager_playback() function for additional information.
*/
- if( nJRec==0
+ if( nJRec==0
&& pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff
){
nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager));
@@ -49802,6 +55172,7 @@ static void pagerFixMaplimit(Pager *pPager){
sqlite3_int64 sz;
sz = pPager->szMmap;
pPager->bUseFetch = (sz>0);
+ setGetterMethod(pPager);
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
}
#endif
@@ -49890,20 +55261,17 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
}
if( pPager->noSync ){
pPager->syncFlags = 0;
- pPager->ckptSyncFlags = 0;
}else if( pgFlags & PAGER_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_FULL;
- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
- }else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
- pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else{
pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
}
- pPager->walSyncFlags = pPager->syncFlags;
+ pPager->walSyncFlags = (pPager->syncFlags<<2);
if( pPager->fullSync ){
- pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
+ pPager->walSyncFlags |= pPager->syncFlags;
+ }
+ if( (pgFlags & PAGER_CKPT_FULLFSYNC) && !pPager->noSync ){
+ pPager->walSyncFlags |= (SQLITE_SYNC_FULL<<2);
}
if( pgFlags & PAGER_CACHESPILL ){
pPager->doNotSpill &= ~SPILLFLAG_OFF;
@@ -49916,7 +55284,7 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
/*
** The following global variable is incremented whenever the library
** attempts to open a temporary file. This information is used for
-** testing and analysis only.
+** testing and analysis only.
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_opentemp_count = 0;
@@ -49925,8 +55293,8 @@ SQLITE_API int sqlite3_opentemp_count = 0;
/*
** Open a temporary file.
**
-** Write the file descriptor into *pFile. Return SQLITE_OK on success
-** or some other error code if we fail. The OS will automatically
+** Write the file descriptor into *pFile. Return SQLITE_OK on success
+** or some other error code if we fail. The OS will automatically
** delete the temporary file when it is closed.
**
** The flags passed to the VFS layer xOpen() call are those specified
@@ -49958,9 +55326,9 @@ static int pagerOpentemp(
/*
** Set the busy handler function.
**
-** The pager invokes the busy-handler if sqlite3OsLock() returns
+** The pager invokes the busy-handler if sqlite3OsLock() returns
** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock,
-** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE
+** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE
** lock. It does *not* invoke the busy handler when upgrading from
** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE
** (which occurs during hot-journal rollback). Summary:
@@ -49972,37 +55340,35 @@ static int pagerOpentemp(
** SHARED_LOCK -> EXCLUSIVE_LOCK | No
** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes
**
-** If the busy-handler callback returns non-zero, the lock is
+** If the busy-handler callback returns non-zero, the lock is
** retried. If it returns zero, then the SQLITE_BUSY error is
** returned to the caller of the pager API function.
*/
-SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(
+SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(
Pager *pPager, /* Pager object */
int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
){
+ void **ap;
pPager->xBusyHandler = xBusyHandler;
pPager->pBusyHandlerArg = pBusyHandlerArg;
-
- if( isOpen(pPager->fd) ){
- void **ap = (void **)&pPager->xBusyHandler;
- assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
- assert( ap[1]==pBusyHandlerArg );
- sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
- }
+ ap = (void **)&pPager->xBusyHandler;
+ assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
+ assert( ap[1]==pBusyHandlerArg );
+ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
}
/*
-** Change the page size used by the Pager object. The new page size
+** Change the page size used by the Pager object. The new page size
** is passed in *pPageSize.
**
** If the pager is in the error state when this function is called, it
-** is a no-op. The value returned is the error state error code (i.e.
+** is a no-op. The value returned is the error state error code (i.e.
** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL).
**
** Otherwise, if all of the following are true:
**
-** * the new page size (value of *pPageSize) is valid (a power
+** * the new page size (value of *pPageSize) is valid (a power
** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and
**
** * there are no outstanding page references, and
@@ -50012,14 +55378,14 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(
**
** then the pager object page size is set to *pPageSize.
**
-** If the page size is changed, then this function uses sqlite3PagerMalloc()
-** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
-** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
+** If the page size is changed, then this function uses sqlite3PagerMalloc()
+** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
+** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
** In all other cases, SQLITE_OK is returned.
**
** If the page size is not changed, either because one of the enumerated
** conditions above is not true, the pager was in error state when this
-** function was called, or because the memory allocation attempt failed,
+** function was called, or because the memory allocation attempt failed,
** then *pPageSize is set to the old, retained page size before returning.
*/
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
@@ -50029,7 +55395,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
** function may be called from within PagerOpen(), before the state
** of the Pager object is internally consistent.
**
- ** At one point this function returned an error if the pager was in
+ ** At one point this function returned an error if the pager was in
** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
** there is at least one outstanding page reference, this function
** is a no-op for that case anyhow.
@@ -50038,8 +55404,8 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
u32 pageSize = *pPageSize;
assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
if( (pPager->memDb==0 || pPager->dbSize==0)
- && sqlite3PcacheRefCount(pPager->pPCache)==0
- && pageSize && pageSize!=(u32)pPager->pageSize
+ && sqlite3PcacheRefCount(pPager->pPCache)==0
+ && pageSize && pageSize!=(u32)pPager->pageSize
){
char *pNew = NULL; /* New temp space */
i64 nByte = 0;
@@ -50048,8 +55414,14 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
rc = sqlite3OsFileSize(pPager->fd, &nByte);
}
if( rc==SQLITE_OK ){
- pNew = (char *)sqlite3PageMalloc(pageSize);
- if( !pNew ) rc = SQLITE_NOMEM_BKPT;
+ /* 8 bytes of zeroed overrun space is sufficient so that the b-tree
+ * cell header parser will never run off the end of the allocation */
+ pNew = (char *)sqlite3PageMalloc(pageSize+8);
+ if( !pNew ){
+ rc = SQLITE_NOMEM_BKPT;
+ }else{
+ memset(pNew+pageSize, 0, 8);
+ }
}
if( rc==SQLITE_OK ){
@@ -50071,7 +55443,6 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
if( nReserve<0 ) nReserve = pPager->nReserve;
assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve;
- pagerReportSize(pPager);
pagerFixMaplimit(pPager);
}
return rc;
@@ -50090,18 +55461,21 @@ SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){
}
/*
-** Attempt to set the maximum database page count if mxPage is positive.
+** Attempt to set the maximum database page count if mxPage is positive.
** Make no changes if mxPage is zero or negative. And never reduce the
** maximum page count below the current size of the database.
**
** Regardless of mxPage, return the current maximum page count.
*/
-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
+SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){
if( mxPage>0 ){
pPager->mxPgno = mxPage;
}
assert( pPager->eState!=PAGER_OPEN ); /* Called only by OP_MaxPgcnt */
- assert( pPager->mxPgno>=pPager->dbSize ); /* OP_MaxPgcnt enforces this */
+ /* assert( pPager->mxPgno>=pPager->dbSize ); */
+ /* OP_MaxPgcnt ensures that the parameter passed to this function is not
+ ** less than the total number of valid pages in the database. But this
+ ** may be less than Pager.dbSize, and so the assert() above is not valid */
return pPager->mxPgno;
}
@@ -50131,11 +55505,11 @@ void enable_simulated_io_errors(void){
/*
** Read the first N bytes from the beginning of the file into memory
-** that pDest points to.
+** that pDest points to.
**
** If the pager was opened on a transient file (zFilename==""), or
** opened on a file less than N bytes in size, the output buffer is
-** zeroed and SQLITE_OK returned. The rationale for this is that this
+** zeroed and SQLITE_OK returned. The rationale for this is that this
** function is used to read database headers, and a new transient or
** zero sized database has a header than consists entirely of zeroes.
**
@@ -50168,7 +55542,7 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned cha
** This function may only be called when a read-transaction is open on
** the pager. It returns the total number of pages in the database.
**
-** However, if the file is between 1 and <page-size> bytes in size, then
+** However, if the file is between 1 and <page-size> bytes in size, then
** this is considered a 1 page file.
*/
SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
@@ -50183,19 +55557,19 @@ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
** a similar or greater lock is already held, this function is a no-op
** (returning SQLITE_OK immediately).
**
-** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
-** the busy callback if the lock is currently not available. Repeat
-** until the busy callback returns false or until the attempt to
+** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
+** the busy callback if the lock is currently not available. Repeat
+** until the busy callback returns false or until the attempt to
** obtain the lock succeeds.
**
** Return SQLITE_OK on success and an error code if we cannot obtain
-** the lock. If the lock is obtained successfully, set the Pager.state
+** the lock. If the lock is obtained successfully, set the Pager.state
** variable to locktype before returning.
*/
static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc; /* Return code */
- /* Check that this is either a no-op (because the requested lock is
+ /* Check that this is either a no-op (because the requested lock is
** already held), or one of the transitions that the busy-handler
** may be invoked during, according to the comment above
** sqlite3PagerSetBusyhandler().
@@ -50212,10 +55586,10 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
}
/*
-** Function assertTruncateConstraint(pPager) checks that one of the
+** Function assertTruncateConstraint(pPager) checks that one of the
** following is true for all dirty pages currently in the page-cache:
**
-** a) The page number is less than or equal to the size of the
+** a) The page number is less than or equal to the size of the
** current database image, in pages, OR
**
** b) if the page content were written at this time, it would not
@@ -50228,9 +55602,9 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
** the database file. If a savepoint transaction were rolled back after
** this happened, the correct behavior would be to restore the current
** content of the page. However, since this content is not present in either
-** the database file or the portion of the rollback journal and
+** the database file or the portion of the rollback journal and
** sub-journal rolled back the content could not be restored and the
-** database image would become corrupt. It is therefore fortunate that
+** database image would become corrupt. It is therefore fortunate that
** this circumstance cannot arise.
*/
#if defined(SQLITE_DEBUG)
@@ -50246,9 +55620,9 @@ static void assertTruncateConstraint(Pager *pPager){
#endif
/*
-** Truncate the in-memory database file image to nPage pages. This
-** function does not actually modify the database file on disk. It
-** just sets the internal state of the pager object so that the
+** Truncate the in-memory database file image to nPage pages. This
+** function does not actually modify the database file on disk. It
+** just sets the internal state of the pager object so that the
** truncation will be done when the current transaction is committed.
**
** This function is only called right before committing a transaction.
@@ -50263,11 +55637,11 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
/* At one point the code here called assertTruncateConstraint() to
** ensure that all pages being truncated away by this operation are,
- ** if one or more savepoints are open, present in the savepoint
+ ** if one or more savepoints are open, present in the savepoint
** journal so that they can be restored if the savepoint is rolled
** back. This is no longer necessary as this function is now only
- ** called right before committing a transaction. So although the
- ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
+ ** called right before committing a transaction. So although the
+ ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
** they cannot be rolled back. So the assertTruncateConstraint() call
** is no longer correct. */
}
@@ -50279,12 +55653,12 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
** size of the journal file so that the pager_playback() routine knows
** that the entire journal file has been synced.
**
-** Syncing a hot-journal to disk before attempting to roll it back ensures
+** Syncing a hot-journal to disk before attempting to roll it back ensures
** that if a power-failure occurs during the rollback, the process that
** attempts rollback following system recovery sees the same journal
** content as this process.
**
-** If everything goes as planned, SQLITE_OK is returned. Otherwise,
+** If everything goes as planned, SQLITE_OK is returned. Otherwise,
** an SQLite error code.
*/
static int pagerSyncHotJournal(Pager *pPager){
@@ -50298,8 +55672,9 @@ static int pagerSyncHotJournal(Pager *pPager){
return rc;
}
+#if SQLITE_MAX_MMAP_SIZE>0
/*
-** Obtain a reference to a memory mapped page object for page number pgno.
+** Obtain a reference to a memory mapped page object for page number pgno.
** The new object will use the pointer pData, obtained from xFetch().
** If successful, set *ppPage to point to the new page reference
** and return SQLITE_OK. Otherwise, return an SQLite error code and set
@@ -50315,12 +55690,13 @@ static int pagerAcquireMapPage(
PgHdr **ppPage /* OUT: Acquired page object */
){
PgHdr *p; /* Memory mapped page to return */
-
+
if( pPager->pMmapFreelist ){
*ppPage = p = pPager->pMmapFreelist;
pPager->pMmapFreelist = p->pDirty;
p->pDirty = 0;
- memset(p->pExtra, 0, pPager->nExtra);
+ assert( pPager->nExtra>=8 );
+ memset(p->pExtra, 0, 8);
}else{
*ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
if( p==0 ){
@@ -50345,9 +55721,10 @@ static int pagerAcquireMapPage(
return SQLITE_OK;
}
+#endif
/*
-** Release a reference to page pPg. pPg must have been returned by an
+** Release a reference to page pPg. pPg must have been returned by an
** earlier call to pagerAcquireMapPage().
*/
static void pagerReleaseMapPage(PgHdr *pPg){
@@ -50372,6 +55749,30 @@ static void pagerFreeMapHdrs(Pager *pPager){
}
}
+/* Verify that the database file has not be deleted or renamed out from
+** under the pager. Return SQLITE_OK if the database is still where it ought
+** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
+** code from sqlite3OsAccess()) if the database has gone missing.
+*/
+static int databaseIsUnmoved(Pager *pPager){
+ int bHasMoved = 0;
+ int rc;
+
+ if( pPager->tempFile ) return SQLITE_OK;
+ if( pPager->dbSize==0 ) return SQLITE_OK;
+ assert( pPager->zFilename && pPager->zFilename[0] );
+ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
+ if( rc==SQLITE_NOTFOUND ){
+ /* If the HAS_MOVED file-control is unimplemented, assume that the file
+ ** has not been moved. That is the historical behavior of SQLite: prior to
+ ** version 3.8.3, it never checked */
+ rc = SQLITE_OK;
+ }else if( rc==SQLITE_OK && bHasMoved ){
+ rc = SQLITE_READONLY_DBMOVED;
+ }
+ return rc;
+}
+
/*
** Shutdown the page cache. Free all memory and close all files.
@@ -50383,13 +55784,13 @@ static void pagerFreeMapHdrs(Pager *pPager){
** result in a coredump.
**
** This function always succeeds. If a transaction is active an attempt
-** is made to roll it back. If an error occurs during the rollback
+** is made to roll it back. If an error occurs during the rollback
** a hot journal may be left in the filesystem but no error is returned
** to the caller.
*/
-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
- u8 *pTmp = (u8 *)pPager->pTmpSpace;
-
+SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
+ u8 *pTmp = (u8*)pPager->pTmpSpace;
+ assert( db || pagerUseWal(pPager)==0 );
assert( assert_pager_state(pPager) );
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
@@ -50397,16 +55798,25 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
- sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
- pPager->pWal = 0;
+ {
+ u8 *a = 0;
+ assert( db || pPager->pWal==0 );
+ if( db && 0==(db->flags & SQLITE_NoCkptOnClose)
+ && SQLITE_OK==databaseIsUnmoved(pPager)
+ ){
+ a = pTmp;
+ }
+ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a);
+ pPager->pWal = 0;
+ }
#endif
pager_reset(pPager);
if( MEMDB ){
pager_unlock(pPager);
}else{
/* If it is open, sync the journal file before calling UnlockAndRollback.
- ** If this is not done, then an unsynced portion of the open journal
- ** file may be played back into the database. If a power failure occurs
+ ** If this is not done, then an unsynced portion of the open journal
+ ** file may be played back into the database. If a power failure occurs
** while this is happening, the database could become corrupt.
**
** If an error occurs while trying to sync the journal, shift the pager
@@ -50428,11 +55838,6 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
sqlite3OsClose(pPager->fd);
sqlite3PageFree(pTmp);
sqlite3PcacheClose(pPager->pPCache);
-
-#ifdef SQLITE_HAS_CODEC
- if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
-#endif
-
assert( !pPager->aSavepoint && !pPager->pInJournal );
assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
@@ -50462,7 +55867,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
** disk and can be restored in the event of a hot-journal rollback.
**
** If the Pager.noSync flag is set, then this function is a no-op.
-** Otherwise, the actions required depend on the journal-mode and the
+** Otherwise, the actions required depend on the journal-mode and the
** device characteristics of the file-system, as follows:
**
** * If the journal file is an in-memory journal file, no action need
@@ -50474,7 +55879,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
** been written following it. If the pager is operating in full-sync
** mode, then the journal file is synced before this field is updated.
**
-** * If the device does not support the SEQUENTIAL property, then
+** * If the device does not support the SEQUENTIAL property, then
** journal file is synced.
**
** Or, in pseudo-code:
@@ -50483,11 +55888,11 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
** if( NOT SAFE_APPEND ){
** if( <full-sync mode> ) xSync(<journal file>);
** <update nRec field>
-** }
+** }
** if( NOT SEQUENTIAL ) xSync(<journal file>);
** }
**
-** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
+** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
** page currently held in memory before returning SQLITE_OK. If an IO
** error is encountered, then the IO error code is returned to the caller.
*/
@@ -50515,10 +55920,10 @@ static int syncJournal(Pager *pPager, int newHdr){
** mode, then the journal file may at this point actually be larger
** than Pager.journalOff bytes. If the next thing in the journal
** file happens to be a journal-header (written as part of the
- ** previous connection's transaction), and a crash or power-failure
- ** occurs after nRec is updated but before this connection writes
- ** anything else to the journal file (or commits/rolls back its
- ** transaction), then SQLite may become confused when doing the
+ ** previous connection's transaction), and a crash or power-failure
+ ** occurs after nRec is updated but before this connection writes
+ ** anything else to the journal file (or commits/rolls back its
+ ** transaction), then SQLite may become confused when doing the
** hot-journal rollback following recovery. It may roll back all
** of this connections data, then proceed to rolling back the old,
** out-of-date data that follows it. Database corruption.
@@ -50528,7 +55933,7 @@ static int syncJournal(Pager *pPager, int newHdr){
** byte to the start of it to prevent it from being recognized.
**
** Variable iNextHdrOffset is set to the offset at which this
- ** problematic header will occur, if it exists. aMagic is used
+ ** problematic header will occur, if it exists. aMagic is used
** as a temporary buffer to inspect the first couple of bytes of
** the potential journal header.
*/
@@ -50555,7 +55960,7 @@ static int syncJournal(Pager *pPager, int newHdr){
** it as a candidate for rollback.
**
** This is not required if the persistent media supports the
- ** SAFE_APPEND property. Because in this case it is not possible
+ ** SAFE_APPEND property. Because in this case it is not possible
** for garbage data to be appended to the file, the nRec field
** is populated with 0xFFFFFFFF when the journal header is written
** and never needs to be updated.
@@ -50575,7 +55980,7 @@ static int syncJournal(Pager *pPager, int newHdr){
if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
IOTRACE(("JSYNC %p\n", pPager))
- rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
+ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
(pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
);
if( rc!=SQLITE_OK ) return rc;
@@ -50592,8 +55997,8 @@ static int syncJournal(Pager *pPager, int newHdr){
}
}
- /* Unless the pager is in noSync mode, the journal file was just
- ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on
+ /* Unless the pager is in noSync mode, the journal file was just
+ ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on
** all pages.
*/
sqlite3PcacheClearSyncFlags(pPager->pPCache);
@@ -50613,9 +56018,9 @@ static int syncJournal(Pager *pPager, int newHdr){
** is called. Before writing anything to the database file, this lock
** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained,
** SQLITE_BUSY is returned and no data is written to the database file.
-**
+**
** If the pager is a temp-file pager and the actual file-system file
-** is not yet open, it is created and opened before any data is
+** is not yet open, it is created and opened before any data is
** written out.
**
** Once the lock has been upgraded and, if necessary, the file opened,
@@ -50630,7 +56035,7 @@ static int syncJournal(Pager *pPager, int newHdr){
** in Pager.dbFileVers[] is updated to match the new value stored in
** the database file.
**
-** If everything is successful, SQLITE_OK is returned. If an IO error
+** If everything is successful, SQLITE_OK is returned. If an IO error
** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot
** be obtained, SQLITE_BUSY is returned.
*/
@@ -50656,7 +56061,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
** file size will be.
*/
assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
- if( rc==SQLITE_OK
+ if( rc==SQLITE_OK
&& pPager->dbHintSize<pPager->dbSize
&& (pList->pDirty || pList->pgno>pPager->dbHintSize)
){
@@ -50678,20 +56083,19 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
*/
if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
- char *pData; /* Data to write */
+ char *pData; /* Data to write */
assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
if( pList->pgno==1 ) pager_write_changecounter(pList);
- /* Encode the database */
- CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
+ pData = pList->pData;
/* Write out the page data. */
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
/* If page 1 was just written, update Pager.dbFileVers to match
- ** the value now stored in the database file. If writing this
- ** page caused the database file to grow, update dbFileSize.
+ ** the value now stored in the database file. If writing this
+ ** page caused the database file to grow, update dbFileSize.
*/
if( pgno==1 ){
memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
@@ -50719,18 +56123,18 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
}
/*
-** Ensure that the sub-journal file is open. If it is already open, this
+** Ensure that the sub-journal file is open. If it is already open, this
** function is a no-op.
**
-** SQLITE_OK is returned if everything goes according to plan. An
-** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
+** SQLITE_OK is returned if everything goes according to plan. An
+** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
** fails.
*/
static int openSubJournal(Pager *pPager){
int rc = SQLITE_OK;
if( !isOpen(pPager->sjfd) ){
- const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
- | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
+ const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
+ | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
| SQLITE_OPEN_DELETEONCLOSE;
int nStmtSpill = sqlite3Config.nStmtSpill;
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
@@ -50742,13 +56146,13 @@ static int openSubJournal(Pager *pPager){
}
/*
-** Append a record of the current state of page pPg to the sub-journal.
+** Append a record of the current state of page pPg to the sub-journal.
**
** If successful, set the bit corresponding to pPg->pgno in the bitvecs
** for all open savepoints before returning.
**
** This function returns SQLITE_OK if everything is successful, an IO
-** error code if the attempt to write to the sub-journal fails, or
+** error code if the attempt to write to the sub-journal fails, or
** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
** bitvec.
*/
@@ -50761,9 +56165,9 @@ static int subjournalPage(PgHdr *pPg){
assert( pPager->useJournal );
assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
- assert( pagerUseWal(pPager)
- || pageInJournal(pPager, pPg)
- || pPg->pgno>pPager->dbOrigSize
+ assert( pagerUseWal(pPager)
+ || pageInJournal(pPager, pPg)
+ || pPg->pgno>pPager->dbOrigSize
);
rc = openSubJournal(pPager);
@@ -50773,8 +56177,7 @@ static int subjournalPage(PgHdr *pPg){
void *pData = pPg->pData;
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2;
-
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
+ pData2 = pData;
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
@@ -50801,14 +56204,14 @@ static int subjournalPageIfRequired(PgHdr *pPg){
** This function is called by the pcache layer when it has reached some
** soft memory limit. The first argument is a pointer to a Pager object
** (cast as a void*). The pager is always 'purgeable' (not an in-memory
-** database). The second argument is a reference to a page that is
+** database). The second argument is a reference to a page that is
** currently dirty but has no outstanding references. The page
-** is always associated with the Pager object passed as the first
+** is always associated with the Pager object passed as the first
** argument.
**
** The job of this function is to make pPg clean by writing its contents
** out to the database file, if possible. This may involve syncing the
-** journal file.
+** journal file.
**
** If successful, sqlite3PcacheMakeClean() is called on the page and
** SQLITE_OK returned. If an IO error occurs while trying to make the
@@ -50833,7 +56236,7 @@ static int pagerStress(void *p, PgHdr *pPg){
** a rollback or by user request, respectively.
**
** Spilling is also prohibited when in an error state since that could
- ** lead to database corruption. In the current implementation it
+ ** lead to database corruption. In the current implementation it
** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
** while in the error state, hence it is impossible for this routine to
** be called in the error state. Nevertheless, we include a NEVER()
@@ -50850,22 +56253,30 @@ static int pagerStress(void *p, PgHdr *pPg){
return SQLITE_OK;
}
+ pPager->aStat[PAGER_STAT_SPILL]++;
pPg->pDirty = 0;
if( pagerUseWal(pPager) ){
/* Write a single frame for this page to the log. */
- rc = subjournalPageIfRequired(pPg);
+ rc = subjournalPageIfRequired(pPg);
if( rc==SQLITE_OK ){
rc = pagerWalFrames(pPager, pPg, 0, 0);
}
}else{
-
+
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( pPager->tempFile==0 ){
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
+ }
+#endif
+
/* Sync the journal file if required. */
- if( pPg->flags&PGHDR_NEED_SYNC
+ if( pPg->flags&PGHDR_NEED_SYNC
|| pPager->eState==PAGER_WRITER_CACHEMOD
){
rc = syncJournal(pPager, 1);
}
-
+
/* Write the contents of the page out to the database file. */
if( rc==SQLITE_OK ){
assert( (pPg->flags&PGHDR_NEED_SYNC)==0 );
@@ -50879,7 +56290,7 @@ static int pagerStress(void *p, PgHdr *pPg){
sqlite3PcacheMakeClean(pPg);
}
- return pager_error(pPager, rc);
+ return pager_error(pPager, rc);
}
/*
@@ -50910,26 +56321,28 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
** The zFilename argument is the path to the database file to open.
** If zFilename is NULL then a randomly-named temporary file is created
** and used as the file to be cached. Temporary files are be deleted
-** automatically when they are closed. If zFilename is ":memory:" then
-** all information is held in cache. It is never written to disk.
+** automatically when they are closed. If zFilename is ":memory:" then
+** all information is held in cache. It is never written to disk.
** This can be used to implement an in-memory database.
**
** The nExtra parameter specifies the number of bytes of space allocated
** along with each page reference. This space is available to the user
-** via the sqlite3PagerGetExtra() API.
+** via the sqlite3PagerGetExtra() API. When a new page is allocated, the
+** first 8 bytes of this space are zeroed but the remainder is uninitialized.
+** (The extra space is used by btree as the MemPage object.)
**
** The flags argument is used to specify properties that affect the
** operation of the pager. It should be passed some bitwise combination
** of the PAGER_* flags.
**
** The vfsFlags parameter is a bitmask to pass to the flags parameter
-** of the xOpen() method of the supplied VFS when opening files.
+** of the xOpen() method of the supplied VFS when opening files.
**
-** If the pager object is allocated and the specified file opened
+** If the pager object is allocated and the specified file opened
** successfully, SQLITE_OK is returned and *ppPager set to point to
** the new pager object. If an error occurs, *ppPager is set to NULL
** and error code returned. This function may return SQLITE_NOMEM
-** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
+** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
** various SQLITE_IO_XXX errors.
*/
SQLITE_PRIVATE int sqlite3PagerOpen(
@@ -50946,6 +56359,11 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ int memJM = 0; /* Memory journal mode */
+#else
+# define memJM 0
+#endif
int readOnly = 0; /* True if this is a read-only file */
int journalFileSize; /* Bytes to allocate for each journal fd */
char *zPathname = 0; /* Full path to database file */
@@ -50954,7 +56372,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
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 */
+ int nUriByte = 1; /* Number of bytes of URI args at *zUri */
+ int nUri = 0; /* Number of URI parameters */
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). */
@@ -50988,14 +56407,24 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
}
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_OK_SYMLINK ){
+ if( vfsFlags & SQLITE_OPEN_NOFOLLOW ){
+ rc = SQLITE_CANTOPEN_SYMLINK;
+ }else{
+ rc = SQLITE_OK;
+ }
+ }
+ }
nPathname = sqlite3Strlen30(zPathname);
z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1];
while( *z ){
- z += sqlite3Strlen30(z)+1;
- z += sqlite3Strlen30(z)+1;
+ z += strlen(z)+1;
+ z += strlen(z)+1;
+ nUri++;
}
- nUri = (int)(&z[1] - zUri);
- assert( nUri>=0 );
+ nUriByte = (int)(&z[1] - zUri);
+ assert( nUriByte>=1 );
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
@@ -51012,7 +56441,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
}
/* Allocate memory for the Pager structure, PCache object, the
- ** three file descriptors, the database file name and the journal
+ ** three file descriptors, the database file name and the journal
** file name. The layout in memory is as follows:
**
** Pager object (sizeof(Pager) bytes)
@@ -51020,50 +56449,111 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
** Database file handle (pVfs->szOsFile bytes)
** Sub-journal file handle (journalFileSize bytes)
** Main journal file handle (journalFileSize bytes)
+ ** Ptr back to the Pager (sizeof(Pager*) bytes)
+ ** \0\0\0\0 database prefix (4 bytes)
** Database file name (nPathname+1 bytes)
- ** Journal file name (nPathname+8+1 bytes)
+ ** URI query parameters (nUriByte bytes)
+ ** Journal filename (nPathname+8+1 bytes)
+ ** WAL filename (nPathname+4+1 bytes)
+ ** \0\0\0 terminator (3 bytes)
+ **
+ ** Some 3rd-party software, over which we have no control, depends on
+ ** the specific order of the filenames and the \0 separators between them
+ ** so that it can (for example) find the database filename given the WAL
+ ** filename without using the sqlite3_filename_database() API. This is a
+ ** misuse of SQLite and a bug in the 3rd-party software, but the 3rd-party
+ ** software is in widespread use, so we try to avoid changing the filename
+ ** order and formatting if possible. In particular, the details of the
+ ** filename format expected by 3rd-party software should be as follows:
+ **
+ ** - Main Database Path
+ ** - \0
+ ** - Multiple URI components consisting of:
+ ** - Key
+ ** - \0
+ ** - Value
+ ** - \0
+ ** - \0
+ ** - Journal Path
+ ** - \0
+ ** - WAL Path (zWALName)
+ ** - \0
+ **
+ ** The sqlite3_create_filename() interface and the databaseFilename() utility
+ ** that is used by sqlite3_filename_database() and kin also depend on the
+ ** specific formatting and order of the various filenames, so if the format
+ ** changes here, be sure to change it there as well.
*/
pPtr = (u8 *)sqlite3MallocZero(
- ROUND8(sizeof(*pPager)) + /* Pager structure */
- ROUND8(pcacheSize) + /* PCache object */
- ROUND8(pVfs->szOsFile) + /* The main db file */
- journalFileSize * 2 + /* The two journal files */
- nPathname + 1 + nUri + /* zFilename */
- nPathname + 8 + 2 /* zJournal */
+ ROUND8(sizeof(*pPager)) + /* Pager structure */
+ ROUND8(pcacheSize) + /* PCache object */
+ ROUND8(pVfs->szOsFile) + /* The main db file */
+ journalFileSize * 2 + /* The two journal files */
+ sizeof(pPager) + /* Space to hold a pointer */
+ 4 + /* Database prefix */
+ nPathname + 1 + /* database filename */
+ nUriByte + /* query parameters */
+ nPathname + 8 + 1 + /* Journal filename */
#ifndef SQLITE_OMIT_WAL
- + nPathname + 4 + 2 /* zWal */
+ nPathname + 4 + 1 + /* WAL filename */
#endif
+ 3 /* Terminator */
);
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
sqlite3DbFree(0, zPathname);
return SQLITE_NOMEM_BKPT;
}
- pPager = (Pager*)(pPtr);
- pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
- pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize));
- pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile));
- pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize);
- pPager->zFilename = (char*)(pPtr += journalFileSize);
+ pPager = (Pager*)pPtr; pPtr += ROUND8(sizeof(*pPager));
+ pPager->pPCache = (PCache*)pPtr; pPtr += ROUND8(pcacheSize);
+ pPager->fd = (sqlite3_file*)pPtr; pPtr += ROUND8(pVfs->szOsFile);
+ pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
+ pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
+ memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
+
+ /* Fill in the Pager.zFilename and pPager.zQueryParam fields */
+ pPtr += 4; /* Skip zero prefix */
+ pPager->zFilename = (char*)pPtr;
+ if( nPathname>0 ){
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname + 1;
+ if( zUri ){
+ memcpy(pPtr, zUri, nUriByte); pPtr += nUriByte;
+ }else{
+ pPtr++;
+ }
+ }
+
+
+ /* Fill in Pager.zJournal */
+ if( nPathname>0 ){
+ pPager->zJournal = (char*)pPtr;
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname;
+ memcpy(pPtr, "-journal",8); pPtr += 8 + 1;
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ sqlite3FileSuffix3(zFilename,pPager->zJournal);
+ pPtr = (u8*)(pPager->zJournal + sqlite3Strlen30(pPager->zJournal)+1);
+#endif
+ }else{
+ pPager->zJournal = 0;
+ }
- /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */
- if( zPathname ){
- assert( nPathname>0 );
- pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri);
- memcpy(pPager->zFilename, zPathname, nPathname);
- if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri);
- memcpy(pPager->zJournal, zPathname, nPathname);
- memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2);
- 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\000", 4+1);
- sqlite3FileSuffix3(pPager->zFilename, pPager->zWal);
+ /* Fill in Pager.zWal */
+ if( nPathname>0 ){
+ pPager->zWal = (char*)pPtr;
+ memcpy(pPtr, zPathname, nPathname); pPtr += nPathname;
+ memcpy(pPtr, "-wal", 4); pPtr += 4 + 1;
+#ifdef SQLITE_ENABLE_8_3_NAMES
+ sqlite3FileSuffix3(zFilename, pPager->zWal);
+ pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1);
#endif
- sqlite3DbFree(0, zPathname);
+ }else{
+ pPager->zWal = 0;
}
+#endif
+
+ if( nPathname ) sqlite3DbFree(0, zPathname);
pPager->pVfs = pVfs;
pPager->vfsFlags = vfsFlags;
@@ -51073,7 +56563,10 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
- readOnly = (fout&SQLITE_OPEN_READONLY);
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
+#endif
+ readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
/* If the file was successfully opened for read/write access,
** choose a default page size in case we have to create the
@@ -51109,9 +56602,9 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
}
#endif
}
- pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0);
+ pPager->noLock = sqlite3_uri_boolean(pPager->zFilename, "nolock", 0);
if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0
- || sqlite3_uri_boolean(zFilename, "immutable", 0) ){
+ || sqlite3_uri_boolean(pPager->zFilename, "immutable", 0) ){
vfsFlags |= SQLITE_OPEN_READONLY;
goto act_like_temp_file;
}
@@ -51126,7 +56619,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
** disk and uses an in-memory rollback journal.
**
** This branch also runs for files marked as immutable.
- */
+ */
act_like_temp_file:
tempFile = 1;
pPager->eState = PAGER_READER; /* Pretend we already have a lock */
@@ -51135,7 +56628,7 @@ act_like_temp_file:
readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
}
- /* The following call to PagerSetPagesize() serves to set the value of
+ /* The following call to PagerSetPagesize() serves to set the value of
** Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
*/
if( rc==SQLITE_OK ){
@@ -51146,8 +56639,8 @@ act_like_temp_file:
/* Initialize the PCache object. */
if( rc==SQLITE_OK ){
- assert( nExtra<1000 );
nExtra = ROUND8(nExtra);
+ assert( nExtra>=8 && nExtra<1000 );
rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
!memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
}
@@ -51175,10 +56668,10 @@ act_like_temp_file:
/* pPager->state = PAGER_UNLOCK; */
/* pPager->errMask = 0; */
pPager->tempFile = (u8)tempFile;
- assert( tempFile==PAGER_LOCKINGMODE_NORMAL
+ assert( tempFile==PAGER_LOCKINGMODE_NORMAL
|| tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
- pPager->exclusiveMode = (u8)tempFile;
+ pPager->exclusiveMode = (u8)tempFile;
pPager->changeCountDone = pPager->tempFile;
pPager->memDb = (u8)memDb;
pPager->readOnly = (u8)readOnly;
@@ -51189,13 +56682,11 @@ act_like_temp_file:
assert( pPager->extraSync==0 );
assert( pPager->syncFlags==0 );
assert( pPager->walSyncFlags==0 );
- assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
pPager->extraSync = 0;
pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
- pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
+ pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
}
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
@@ -51206,12 +56697,13 @@ act_like_temp_file:
setSectorSize(pPager);
if( !useJournal ){
pPager->journalMode = PAGER_JOURNALMODE_OFF;
- }else if( memDb ){
+ }else if( memDb || memJM ){
pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
}
/* pPager->xBusyHandler = 0; */
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
+ setGetterMethod(pPager);
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
/* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
@@ -51219,36 +56711,25 @@ act_like_temp_file:
return SQLITE_OK;
}
-
-/* Verify that the database file has not be deleted or renamed out from
-** under the pager. Return SQLITE_OK if the database is still were it ought
-** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
-** code from sqlite3OsAccess()) if the database has gone missing.
+/*
+** Return the sqlite3_file for the main database given the name
+** of the corresonding WAL or Journal name as passed into
+** xOpen.
*/
-static int databaseIsUnmoved(Pager *pPager){
- int bHasMoved = 0;
- int rc;
-
- if( pPager->tempFile ) return SQLITE_OK;
- if( pPager->dbSize==0 ) return SQLITE_OK;
- assert( pPager->zFilename && pPager->zFilename[0] );
- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
- if( rc==SQLITE_NOTFOUND ){
- /* If the HAS_MOVED file-control is unimplemented, assume that the file
- ** has not been moved. That is the historical behavior of SQLite: prior to
- ** version 3.8.3, it never checked */
- rc = SQLITE_OK;
- }else if( rc==SQLITE_OK && bHasMoved ){
- rc = SQLITE_READONLY_DBMOVED;
+SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){
+ Pager *pPager;
+ while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
+ zName--;
}
- return rc;
+ pPager = *(Pager**)(zName - 4 - sizeof(Pager*));
+ return pPager->fd;
}
/*
** This function is called after transitioning from PAGER_UNLOCK to
** PAGER_SHARED state. It tests if there is a hot journal present in
-** the file-system for the given pager. A hot journal is one that
+** the file-system for the given pager. A hot journal is one that
** needs to be played back. According to this function, a hot-journal
** file exists if the following criteria are met:
**
@@ -51263,14 +56744,14 @@ static int databaseIsUnmoved(Pager *pPager){
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
** is returned.
**
-** This routine does not check if there is a master journal filename
-** at the end of the file. If there is, and that master journal file
+** This routine does not check if there is a super-journal filename
+** at the end of the file. If there is, and that super-journal file
** does not exist, then the journal file is not really hot. In this
** case this routine will return a false-positive. The pager_playback()
-** routine will discover that the journal file is not really hot and
-** will not roll it back.
+** routine will discover that the journal file is not really hot and
+** will not roll it back.
**
-** If a hot-journal file is found to exist, *pExists is set to 1 and
+** If a hot-journal file is found to exist, *pExists is set to 1 and
** SQLITE_OK returned. If no hot-journal file is present, *pExists is
** set to 0 and SQLITE_OK returned. If an IO error occurs while trying
** to determine whether or not a hot-journal file exists, the IO error
@@ -51298,7 +56779,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
int locked = 0; /* True if some process holds a RESERVED lock */
/* Race condition here: Another process might have been holding the
- ** the RESERVED lock and have a journal open at the sqlite3OsAccess()
+ ** the RESERVED lock and have a journal open at the sqlite3OsAccess()
** call above, but then delete the journal and drop the lock before
** we get to the following sqlite3OsCheckReservedLock() call. If that
** is the case, this routine might think there is a hot journal when
@@ -51331,7 +56812,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
/* The journal file exists and no other connection has a reserved
** or greater lock on the database file. Now check that there is
** at least one non-zero bytes at the start of the journal file.
- ** If there is, then we consider this journal to be hot. If not,
+ ** If there is, then we consider this journal to be hot. If not,
** it can be ignored.
*/
if( !jrnlOpen ){
@@ -51381,7 +56862,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
** on the database file), then an attempt is made to obtain a
** SHARED lock on the database file. Immediately after obtaining
** the SHARED lock, the file-system is checked for a hot-journal,
-** which is played back if present. Following any hot-journal
+** which is played back if present. Following any hot-journal
** rollback, the contents of the cache are validated by checking
** the 'change-counter' field of the database file header and
** discarded if they are found to be invalid.
@@ -51392,8 +56873,8 @@ static int hasHotJournal(Pager *pPager, int *pExists){
** the contents of the page cache and rolling back any open journal
** file.
**
-** If everything is successful, SQLITE_OK is returned. If an IO error
-** occurs while locking the database, checking for a hot-journal file or
+** If everything is successful, SQLITE_OK is returned. If an IO error
+** occurs while locking the database, checking for a hot-journal file or
** rolling back a journal file, the IO error code is returned.
*/
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
@@ -51401,7 +56882,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
/* This routine is only called from b-tree and only when there are no
** outstanding pages. This implies that the pager state should either
- ** be OPEN or READER. READER is only possible if the pager is or was in
+ ** be OPEN or READER. READER is only possible if the pager is or was in
** exclusive access mode. */
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
assert( assert_pager_state(pPager) );
@@ -51439,12 +56920,12 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** important that a RESERVED lock is not obtained on the way to the
** EXCLUSIVE lock. If it were, another process might open the
** database file, detect the RESERVED lock, and conclude that the
- ** database is safe to read while this process is still rolling the
+ ** database is safe to read while this process is still rolling the
** hot-journal back.
- **
+ **
** Because the intermediate RESERVED lock is not requested, any
- ** other process attempting to access the database file will get to
- ** this point in the code and fail to obtain its own EXCLUSIVE lock
+ ** other process attempting to access the database file will get to
+ ** this point in the code and fail to obtain its own EXCLUSIVE lock
** on the database file.
**
** Unless the pager is in locking_mode=exclusive mode, the lock is
@@ -51454,17 +56935,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
if( rc!=SQLITE_OK ){
goto failed;
}
-
- /* If it is not already open and the file exists on disk, open the
- ** journal for read/write access. Write access is required because
- ** in exclusive-access mode the file descriptor will be kept open
- ** and possibly used for a transaction later on. Also, write-access
- ** is usually required to finalize the journal in journal_mode=persist
+
+ /* If it is not already open and the file exists on disk, open the
+ ** journal for read/write access. Write access is required because
+ ** in exclusive-access mode the file descriptor will be kept open
+ ** and possibly used for a transaction later on. Also, write-access
+ ** is usually required to finalize the journal in journal_mode=persist
** mode (and also for journal_mode=truncate on some systems).
**
- ** If the journal does not exist, it usually means that some
- ** other connection managed to get in and roll it back before
- ** this connection obtained the exclusive lock above. Or, it
+ ** If the journal does not exist, it usually means that some
+ ** other connection managed to get in and roll it back before
+ ** this connection obtained the exclusive lock above. Or, it
** may mean that the pager was in the error-state when this
** function was called and the journal file does not exist.
*/
@@ -51485,7 +56966,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
}
}
}
-
+
/* Playback and delete the journal. Drop the database write
** lock and reacquire the read lock. Purge the cache before
** playing back the hot-journal so that we don't end up with
@@ -51510,8 +56991,8 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** or roll back a hot-journal while holding an EXCLUSIVE lock. The
** pager_unlock() routine will be called before returning to unlock
** the file. If the unlock attempt fails, then Pager.eLock must be
- ** set to UNKNOWN_LOCK (see the comment above the #define for
- ** UNKNOWN_LOCK above for an explanation).
+ ** set to UNKNOWN_LOCK (see the comment above the #define for
+ ** UNKNOWN_LOCK above for an explanation).
**
** In order to get pager_unlock() to do this, set Pager.eState to
** PAGER_ERROR now. This is not actually counted as a transition
@@ -51519,7 +57000,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** since we know that the same call to pager_unlock() will very
** shortly transition the pager object to the OPEN state. Calling
** assert_pager_state() would fail now, as it should not be possible
- ** to be in ERROR state when there are zero outstanding page
+ ** to be in ERROR state when there are zero outstanding page
** references.
*/
pager_error(pPager, rc);
@@ -51544,24 +57025,19 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** a 32-bit counter that is incremented with each change. The
** other bytes change randomly with each file change when
** a codec is in use.
- **
- ** There is a vanishingly small chance that a change will not be
+ **
+ ** There is a vanishingly small chance that a change will not be
** detected. The chance of an undetected change is so small that
** it can be neglected.
*/
- Pgno nPage = 0;
char dbFileVers[sizeof(pPager->dbFileVers)];
- rc = pagerPagecount(pPager, &nPage);
- if( rc ) goto failed;
-
- if( nPage>0 ){
- IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
- rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
- if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
+ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
+ if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_IOERR_SHORT_READ ){
goto failed;
}
- }else{
memset(dbFileVers, 0, sizeof(dbFileVers));
}
@@ -51617,37 +57093,45 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** Except, in locking_mode=EXCLUSIVE when there is nothing to in
** the rollback journal, the unlock is not performed and there is
** nothing to rollback, so this routine is a no-op.
-*/
+*/
static void pagerUnlockIfUnused(Pager *pPager){
- if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
+ if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
+ assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
pagerUnlockAndRollback(pPager);
}
}
/*
-** Acquire a reference to page number pgno in pager pPager (a page
-** reference has type DbPage*). If the requested reference is
+** The page getter methods each try to acquire a reference to a
+** page with page number pgno. If the requested reference is
** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
**
-** If the requested page is already in the cache, it is returned.
+** There are different implementations of the getter method depending
+** on the current state of the pager.
+**
+** getPageNormal() -- The normal getter
+** getPageError() -- Used if the pager is in an error state
+** getPageMmap() -- Used if memory-mapped I/O is enabled
+**
+** If the requested page is already in the cache, it is returned.
** Otherwise, a new page object is allocated and populated with data
** read from the database file. In some cases, the pcache module may
** choose not to allocate a new page object and may reuse an existing
** object with no outstanding references.
**
-** The extra data appended to a page is always initialized to zeros the
-** first time a page is loaded into memory. If the page requested is
+** The extra data appended to a page is always initialized to zeros the
+** first time a page is loaded into memory. If the page requested is
** already in the cache when this function is called, then the extra
** data is left as it was when the page object was last used.
**
-** If the database image is smaller than the requested page or if a
-** non-zero value is passed as the noContent parameter and the
-** requested page is not already stored in the cache, then no
-** actual disk read occurs. In this case the memory image of the
-** page is initialized to all zeros.
+** If the database image is smaller than the requested page or if
+** the flags parameter contains the PAGER_GET_NOCONTENT bit and the
+** requested page is not already stored in the cache, then no
+** actual disk read occurs. In this case the memory image of the
+** page is initialized to all zeros.
**
-** If noContent is true, it means that we do not care about the contents
-** of the page. This occurs in two scenarios:
+** If PAGER_GET_NOCONTENT is true, it means that we do not care about
+** the contents of the page. This occurs in two scenarios:
**
** a) When reading a free-list leaf page from the database, and
**
@@ -51655,8 +57139,8 @@ static void pagerUnlockIfUnused(Pager *pPager){
** a new page into the cache to be filled with the data read
** from the savepoint journal.
**
-** If noContent is true, then the data returned is zeroed instead of
-** being read from the database. Additionally, the bits corresponding
+** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead
+** of being read from the database. Additionally, the bits corresponding
** to pgno in Pager.pInJournal (bitvec of pages already written to the
** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
** savepoints are set. This means if the page is made writable at any
@@ -51674,126 +57158,60 @@ static void pagerUnlockIfUnused(Pager *pPager){
** Since Lookup() never goes to disk, it never has to deal with locks
** or journal files.
*/
-SQLITE_PRIVATE int sqlite3PagerGet(
+static int getPageNormal(
Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
int rc = SQLITE_OK;
- PgHdr *pPg = 0;
- u32 iFrame = 0; /* Frame to read from WAL file */
- const int noContent = (flags & PAGER_GET_NOCONTENT);
-
- /* It is acceptable to use a read-only (mmap) page for any page except
- ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
- ** flag was specified by the caller. And so long as the db is not a
- ** temporary or in-memory database. */
- const int bMmapOk = (pgno>1 && USEFETCH(pPager)
- && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
-#ifdef SQLITE_HAS_CODEC
- && pPager->xCodec==0
-#endif
- );
+ PgHdr *pPg;
+ u8 noContent; /* True if PAGER_GET_NOCONTENT is set */
+ sqlite3_pcache_page *pBase;
- /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
- ** allows the compiler optimizer to reuse the results of the "pgno>1"
- ** test in the previous statement, and avoid testing pgno==0 in the
- ** common case where pgno is large. */
- if( pgno<=1 && pgno==0 ){
- return SQLITE_CORRUPT_BKPT;
- }
+ assert( pPager->errCode==SQLITE_OK );
assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
- assert( noContent==0 || bMmapOk==0 );
-
assert( pPager->hasHeldSharedLock==1 );
- /* If the pager is in the error state, return an error immediately.
- ** Otherwise, request the page from the PCache layer. */
- if( pPager->errCode!=SQLITE_OK ){
- rc = pPager->errCode;
- }else{
- if( bMmapOk && pagerUseWal(pPager) ){
- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- }
-
- if( bMmapOk && iFrame==0 ){
- void *pData = 0;
-
- rc = sqlite3OsFetch(pPager->fd,
- (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
- );
-
- if( rc==SQLITE_OK && pData ){
- if( pPager->eState>PAGER_READER || pPager->tempFile ){
- pPg = sqlite3PagerLookup(pPager, pgno);
- }
- if( pPg==0 ){
- rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
- }else{
- sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
- }
- if( pPg ){
- assert( rc==SQLITE_OK );
- *ppPage = pPg;
- return SQLITE_OK;
- }
- }
- if( rc!=SQLITE_OK ){
- goto pager_acquire_err;
- }
- }
-
- {
- sqlite3_pcache_page *pBase;
- pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
- if( pBase==0 ){
- rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- if( pBase==0 ){
- pPg = *ppPage = 0;
- rc = SQLITE_NOMEM_BKPT;
- goto pager_acquire_err;
- }
- }
- pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
- assert( pPg!=0 );
- }
- }
-
- if( rc!=SQLITE_OK ){
- /* Either the call to sqlite3PcacheFetch() returned an error or the
- ** pager was already in the error-state when this function was called.
- ** Set pPg to 0 and jump to the exception handler. */
+ if( pgno==0 ) return SQLITE_CORRUPT_BKPT;
+ pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
+ if( pBase==0 ){
pPg = 0;
- goto pager_acquire_err;
+ rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
+ if( rc!=SQLITE_OK ) goto pager_acquire_err;
+ if( pBase==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto pager_acquire_err;
+ }
}
+ pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
assert( pPg==(*ppPage) );
assert( pPg->pgno==pgno );
assert( pPg->pPager==pPager || pPg->pPager==0 );
+ noContent = (flags & PAGER_GET_NOCONTENT)!=0;
if( pPg->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
- assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
+ assert( pgno!=PAGER_MJ_PGNO(pPager) );
pPager->aStat[PAGER_STAT_HIT]++;
return SQLITE_OK;
}else{
- /* The pager cache has created a new page. Its content needs to
- ** be initialized. */
-
- pPg->pPager = pPager;
-
- /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
- ** number greater than this, or the unused locking-page, is requested. */
- if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
+ /* The pager cache has created a new page. Its content needs to
+ ** be initialized. But first some error checks:
+ **
+ ** (*) obsolete. Was: maximum page number is 2^31
+ ** (2) Never try to fetch the locking page
+ */
+ if( pgno==PAGER_MJ_PGNO(pPager) ){
rc = SQLITE_CORRUPT_BKPT;
goto pager_acquire_err;
}
+ pPg->pPager = pPager;
+
assert( !isOpen(pPager->fd) || !MEMDB );
if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
@@ -51802,9 +57220,9 @@ SQLITE_PRIVATE int sqlite3PagerGet(
}
if( noContent ){
/* Failure to set the bits in the InJournal bit-vectors is benign.
- ** It merely means that we might do some extra work to journal a
- ** page that does not need to be journaled. Nevertheless, be sure
- ** to test the case where a malloc error occurs while trying to set
+ ** It merely means that we might do some extra work to journal a
+ ** page that does not need to be journaled. Nevertheless, be sure
+ ** to test the case where a malloc error occurs while trying to set
** a bit in a bit vector.
*/
sqlite3BeginBenignMalloc();
@@ -51819,20 +57237,15 @@ SQLITE_PRIVATE int sqlite3PagerGet(
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
- if( pagerUseWal(pPager) && bMmapOk==0 ){
- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- }
assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++;
- rc = readDbPage(pPg, iFrame);
+ rc = readDbPage(pPg);
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
}
pager_set_pagehash(pPg);
}
-
return SQLITE_OK;
pager_acquire_err:
@@ -51841,20 +57254,115 @@ pager_acquire_err:
sqlite3PcacheDrop(pPg);
}
pagerUnlockIfUnused(pPager);
-
*ppPage = 0;
return rc;
}
+#if SQLITE_MAX_MMAP_SIZE>0
+/* The page getter for when memory-mapped I/O is enabled */
+static int getPageMMap(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int flags /* PAGER_GET_XXX flags */
+){
+ int rc = SQLITE_OK;
+ PgHdr *pPg = 0;
+ u32 iFrame = 0; /* Frame to read from WAL file */
+
+ /* It is acceptable to use a read-only (mmap) page for any page except
+ ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
+ ** flag was specified by the caller. And so long as the db is not a
+ ** temporary or in-memory database. */
+ const int bMmapOk = (pgno>1
+ && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
+ );
+
+ assert( USEFETCH(pPager) );
+
+ /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
+ ** allows the compiler optimizer to reuse the results of the "pgno>1"
+ ** test in the previous statement, and avoid testing pgno==0 in the
+ ** common case where pgno is large. */
+ if( pgno<=1 && pgno==0 ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ assert( pPager->eState>=PAGER_READER );
+ assert( assert_pager_state(pPager) );
+ assert( pPager->hasHeldSharedLock==1 );
+ assert( pPager->errCode==SQLITE_OK );
+
+ if( bMmapOk && pagerUseWal(pPager) ){
+ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+ if( rc!=SQLITE_OK ){
+ *ppPage = 0;
+ return rc;
+ }
+ }
+ if( bMmapOk && iFrame==0 ){
+ void *pData = 0;
+ rc = sqlite3OsFetch(pPager->fd,
+ (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
+ );
+ if( rc==SQLITE_OK && pData ){
+ if( pPager->eState>PAGER_READER || pPager->tempFile ){
+ pPg = sqlite3PagerLookup(pPager, pgno);
+ }
+ if( pPg==0 ){
+ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
+ }else{
+ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
+ }
+ if( pPg ){
+ assert( rc==SQLITE_OK );
+ *ppPage = pPg;
+ return SQLITE_OK;
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ *ppPage = 0;
+ return rc;
+ }
+ }
+ return getPageNormal(pPager, pgno, ppPage, flags);
+}
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+/* The page getter method for when the pager is an error state */
+static int getPageError(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int flags /* PAGER_GET_XXX flags */
+){
+ UNUSED_PARAMETER(pgno);
+ UNUSED_PARAMETER(flags);
+ assert( pPager->errCode!=SQLITE_OK );
+ *ppPage = 0;
+ return pPager->errCode;
+}
+
+
+/* Dispatch all page fetch requests to the appropriate getter method.
+*/
+SQLITE_PRIVATE int sqlite3PagerGet(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int flags /* PAGER_GET_XXX flags */
+){
+ return pPager->xGet(pPager, pgno, ppPage, flags);
+}
+
/*
** Acquire a page if it is already in the in-memory cache. Do
** not read the page from disk. Return a pointer to the page,
-** or 0 if the page is not in cache.
+** or 0 if the page is not in cache.
**
** See also sqlite3PagerGet(). The difference between this routine
** and sqlite3PagerGet() is that _get() will go to the disk and read
** in the page if the page is not already in cache. This routine
-** returns NULL if the page is not in cache or if a disk I/O error
+** returns NULL if the page is not in cache or if a disk I/O error
** has ever happened.
*/
SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
@@ -51871,46 +57379,60 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** If the number of references to the page drop to zero, then the
-** page is added to the LRU list. When all references to all pages
-** are released, a rollback occurs and the lock on the database is
-** removed.
+** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
+** used if we know that the page being released is not the last page.
+** The btree layer always holds page1 open until the end, so these first
+** to routines can be used to release any page other than BtShared.pPage1.
+**
+** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
+** checks the total number of outstanding pages and if the number of
+** pages reaches zero it drops the database lock.
*/
SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
- Pager *pPager;
+ TESTONLY( Pager *pPager = pPg->pPager; )
assert( pPg!=0 );
- pPager = pPg->pPager;
if( pPg->flags & PGHDR_MMAP ){
+ assert( pPg->pgno!=1 ); /* Page1 is never memory mapped */
pagerReleaseMapPage(pPg);
}else{
sqlite3PcacheRelease(pPg);
}
- pagerUnlockIfUnused(pPager);
+ /* Do not use this routine to release the last reference to page1 */
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
}
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
}
+SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){
+ Pager *pPager;
+ assert( pPg!=0 );
+ assert( pPg->pgno==1 );
+ assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
+ pPager = pPg->pPager;
+ sqlite3PcacheRelease(pPg);
+ pagerUnlockIfUnused(pPager);
+}
/*
** This function is called at the start of every write transaction.
-** There must already be a RESERVED or EXCLUSIVE lock on the database
+** There must already be a RESERVED or EXCLUSIVE lock on the database
** file when this routine is called.
**
** Open the journal file for pager pPager and write a journal header
** to the start of it. If there are active savepoints, open the sub-journal
-** as well. This function is only used when the journal file is being
-** opened to write a rollback log for a transaction. It is not used
+** as well. This function is only used when the journal file is being
+** opened to write a rollback log for a transaction. It is not used
** when opening a hot journal file to roll it back.
**
** If the journal file is already open (as it may be in exclusive mode),
** then this function just writes a journal header to the start of the
-** already open file.
+** already open file.
**
** Whether or not the journal file is opened by this function, the
** Pager.pInJournal bitvec structure is allocated.
**
-** Return SQLITE_OK if everything is successful. Otherwise, return
-** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
+** Return SQLITE_OK if everything is successful. Otherwise, return
+** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
** an IO error code if opening or writing the journal file fails.
*/
static int pager_open_journal(Pager *pPager){
@@ -51920,7 +57442,7 @@ static int pager_open_journal(Pager *pPager){
assert( pPager->eState==PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) );
assert( pPager->pInJournal==0 );
-
+
/* If already in the error state, this function is a no-op. But on
** the other hand, this routine is never called if we are already in
** an error state. */
@@ -51931,7 +57453,7 @@ static int pager_open_journal(Pager *pPager){
if( pPager->pInJournal==0 ){
return SQLITE_NOMEM_BKPT;
}
-
+
/* Open the journal file if it is not already open. */
if( !isOpen(pPager->jfd) ){
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
@@ -51947,7 +57469,7 @@ static int pager_open_journal(Pager *pPager){
flags |= SQLITE_OPEN_MAIN_JOURNAL;
nSpill = jrnlBufferSize(pPager);
}
-
+
/* Verify that the database still has the same name as it did when
** it was originally opened. */
rc = databaseIsUnmoved(pPager);
@@ -51959,16 +57481,16 @@ static int pager_open_journal(Pager *pPager){
}
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
}
-
-
- /* Write the first journal header to the journal file and open
+
+
+ /* Write the first journal header to the journal file and open
** the sub-journal if necessary.
*/
if( rc==SQLITE_OK ){
/* TODO: Check if all of these are really required. */
pPager->nRec = 0;
pPager->journalOff = 0;
- pPager->setMaster = 0;
+ pPager->setSuper = 0;
pPager->journalHdr = 0;
rc = writeJournalHdr(pPager);
}
@@ -51986,12 +57508,12 @@ static int pager_open_journal(Pager *pPager){
}
/*
-** Begin a write-transaction on the specified pager object. If a
+** Begin a write-transaction on the specified pager object. If a
** write-transaction has already been opened, this function is a no-op.
**
** If the exFlag argument is false, then acquire at least a RESERVED
** lock on the database file. If exFlag is true, then acquire at least
-** an EXCLUSIVE lock. If such a lock is already held, no locking
+** an EXCLUSIVE lock. If such a lock is already held, no locking
** functions need be called.
**
** If the subjInMemory argument is non-zero, then any sub-journal opened
@@ -51999,7 +57521,7 @@ static int pager_open_journal(Pager *pPager){
** has no effect if the sub-journal is already opened (as it may be when
** running in exclusive mode) or if the transaction does not require a
** sub-journal. If the subjInMemory argument is zero, then any required
-** sub-journal is implemented in-memory if pPager is an in-memory database,
+** sub-journal is implemented in-memory if pPager is an in-memory database,
** or using a temporary file otherwise.
*/
SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
@@ -52047,9 +57569,9 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
**
** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD
** when it has an open transaction, but never to DBMOD or FINISHED.
- ** This is because in those states the code to roll back savepoint
- ** transactions may copy data from the sub-journal into the database
- ** file as well as into the page cache. Which would be incorrect in
+ ** This is because in those states the code to roll back savepoint
+ ** transactions may copy data from the sub-journal into the database
+ ** file as well as into the page cache. Which would be incorrect in
** WAL mode.
*/
pPager->eState = PAGER_WRITER_LOCKED;
@@ -52084,7 +57606,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
assert( pPager->journalHdr<=pPager->journalOff );
- CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
+ pData2 = pPg->pData;
cksum = pager_cksum(pPager, (u8*)pData2);
/* Even if an IO or diskfull error occurs while journalling the
@@ -52103,11 +57625,11 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
if( rc!=SQLITE_OK ) return rc;
- IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
+ IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
pPager->journalOff, pPager->pageSize));
PAGER_INCR(sqlite3_pager_writej_count);
PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n",
- PAGERID(pPager), pPg->pgno,
+ PAGERID(pPager), pPg->pgno,
((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)));
pPager->journalOff += 8 + pPager->pageSize;
@@ -52122,9 +57644,9 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
}
/*
-** Mark a single data page as writeable. The page is written into the
+** Mark a single data page as writeable. The page is written into the
** main journal or sub-journal as required. If the page is written into
-** one of the journals, the corresponding bit is set in the
+** one of the journals, the corresponding bit is set in the
** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs
** of any open savepoints as appropriate.
*/
@@ -52132,7 +57654,7 @@ static int pager_write(PgHdr *pPg){
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
- /* This routine is not called unless a write-transaction has already
+ /* This routine is not called unless a write-transaction has already
** been started. The journal file may or may not be open at this point.
** It is never called in the ERROR state.
*/
@@ -52149,7 +57671,7 @@ static int pager_write(PgHdr *pPg){
** obtained the necessary locks to begin the write-transaction, but the
** rollback journal might not yet be open. Open it now if this is the case.
**
- ** This is done before calling sqlite3PcacheMakeDirty() on the page.
+ ** This is done before calling sqlite3PcacheMakeDirty() on the page.
** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then
** an error might occur and the pager would end up in WRITER_LOCKED state
** with pages marked as dirty in the cache.
@@ -52194,7 +57716,7 @@ static int pager_write(PgHdr *pPg){
** PGHDR_WRITEABLE bit that indicates that the page can be safely modified.
*/
pPg->flags |= PGHDR_WRITEABLE;
-
+
/* If the statement journal is open and the page is not in it,
** then write the page into the statement journal.
*/
@@ -52278,7 +57800,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
}
}
- /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
+ /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
** starting at pg1, then it needs to be set for all of them. Because
** writing to any of these nPage pages may damage the others, the
** journal file must contain sync()ed copies of all of them
@@ -52301,9 +57823,9 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
}
/*
-** Mark a data page as writeable. This routine must be called before
-** making changes to a page. The caller must check the return value
-** of this function and be careful not to change any page data unless
+** Mark a data page as writeable. This routine must be called before
+** making changes to a page. The caller must check the return value
+** of this function and be careful not to change any page data unless
** this routine returns SQLITE_OK.
**
** The difference between this function and pager_write() is that this
@@ -52319,11 +57841,11 @@ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) );
- if( pPager->errCode ){
- return pPager->errCode;
- }else if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
+ if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
return SQLITE_OK;
+ }else if( pPager->errCode ){
+ return pPager->errCode;
}else if( pPager->sectorSize > (u32)pPager->pageSize ){
assert( pPager->tempFile==0 );
return pagerWriteLargeSector(pPg);
@@ -52354,13 +57876,13 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
** on the given page is unused. The pager marks the page as clean so
** that it does not get written to disk.
**
-** Tests show that this optimization can quadruple the speed of large
+** Tests show that this optimization can quadruple the speed of large
** DELETE operations.
**
** This optimization cannot be used with a temp-file, as the page may
** have been dirty at the start of the transaction. In that case, if
-** memory pressure forces page pPg out of the cache, the data does need
-** to be written out to disk so that it may be read back in if the
+** memory pressure forces page pPg out of the cache, the data does need
+** to be written out to disk so that it may be read back in if the
** current transaction is rolled back.
*/
SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
@@ -52376,17 +57898,17 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
}
/*
-** This routine is called to increment the value of the database file
-** change-counter, stored as a 4-byte big-endian integer starting at
+** This routine is called to increment the value of the database file
+** change-counter, stored as a 4-byte big-endian integer starting at
** byte offset 24 of the pager file. The secondary change counter at
** 92 is also updated, as is the SQLite version number at offset 96.
**
** But this only happens if the pPager->changeCountDone flag is false.
** To avoid excess churning of page 1, the update only happens once.
-** See also the pager_write_changecounter() routine that does an
+** See also the pager_write_changecounter() routine that does an
** unconditional update of the change counters.
**
-** If the isDirectMode flag is zero, then this is done by calling
+** If the isDirectMode flag is zero, then this is done by calling
** sqlite3PagerWrite() on page 1, then modifying the contents of the
** page data. In this case the file will be updated when the current
** transaction is committed.
@@ -52394,7 +57916,7 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
** The isDirectMode flag may only be non-zero if the library was compiled
** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case,
** if isDirect is non-zero, then the database file is updated directly
-** by writing an updated version of page 1 using a call to the
+** by writing an updated version of page 1 using a call to the
** sqlite3OsWrite() function.
*/
static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
@@ -52433,7 +57955,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
assert( pPgHdr==0 || rc==SQLITE_OK );
/* If page one was fetched successfully, and this function is not
- ** operating in direct-mode, make page 1 writable. When not in
+ ** operating in direct-mode, make page 1 writable. When not in
** direct mode, page 1 is always held in cache and hence the PagerGet()
** above is always successful - hence the ALWAYS on rc==SQLITE_OK.
*/
@@ -52449,7 +57971,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
if( DIRECT_MODE ){
const void *zBuf;
assert( pPager->dbFileSize>0 );
- CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
+ zBuf = pPgHdr->pData;
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
pPager->aStat[PAGER_STAT_WRITE]++;
@@ -52480,14 +58002,11 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
** If successful, or if called on a pager for which it is a no-op, this
** function returns SQLITE_OK. Otherwise, an IO error code is returned.
*/
-SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
+SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper){
int rc = SQLITE_OK;
-
- if( isOpen(pPager->fd) ){
- void *pArg = (void*)zMaster;
- rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
- if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
- }
+ void *pArg = (void*)zSuper;
+ rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
+ if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc==SQLITE_OK && !pPager->noSync ){
assert( !MEMDB );
rc = sqlite3OsSync(pPager->fd, pPager->syncFlags);
@@ -52497,22 +58016,22 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
/*
** This function may only be called while a write-transaction is active in
-** rollback. If the connection is in WAL mode, this call is a no-op.
-** Otherwise, if the connection does not already have an EXCLUSIVE lock on
+** rollback. If the connection is in WAL mode, this call is a no-op.
+** Otherwise, if the connection does not already have an EXCLUSIVE lock on
** the database file, an attempt is made to obtain one.
**
** If the EXCLUSIVE lock is already held or the attempt to obtain it is
** successful, or the connection is in WAL mode, SQLITE_OK is returned.
-** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
+** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
** returned.
*/
SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
int rc = pPager->errCode;
assert( assert_pager_state(pPager) );
if( rc==SQLITE_OK ){
- assert( pPager->eState==PAGER_WRITER_CACHEMOD
- || pPager->eState==PAGER_WRITER_DBMOD
- || pPager->eState==PAGER_WRITER_LOCKED
+ assert( pPager->eState==PAGER_WRITER_CACHEMOD
+ || pPager->eState==PAGER_WRITER_DBMOD
+ || pPager->eState==PAGER_WRITER_LOCKED
);
assert( assert_pager_state(pPager) );
if( 0==pagerUseWal(pPager) ){
@@ -52523,24 +58042,24 @@ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
}
/*
-** Sync the database file for the pager pPager. zMaster points to the name
-** of a master journal file that should be written into the individual
-** journal file. zMaster may be NULL, which is interpreted as no master
-** journal (a single database transaction).
+** Sync the database file for the pager pPager. zSuper points to the name
+** of a super-journal file that should be written into the individual
+** journal file. zSuper may be NULL, which is interpreted as no
+** super-journal (a single database transaction).
**
** This routine ensures that:
**
** * The database file change-counter is updated,
** * the journal is synced (unless the atomic-write optimization is used),
-** * all dirty pages are written to the database file,
+** * all dirty pages are written to the database file,
** * the database file is truncated (if required), and
-** * the database file synced.
+** * the database file synced.
**
-** The only thing that remains to commit the transaction is to finalize
-** (delete, truncate or zero the first part of) the journal file (or
-** delete the master journal file if specified).
+** The only thing that remains to commit the transaction is to finalize
+** (delete, truncate or zero the first part of) the journal file (or
+** delete the super-journal file if specified).
**
-** Note that if zMaster==NULL, this does not overwrite a previous value
+** Note that if zSuper==NULL, this does not overwrite a previous value
** passed to an sqlite3PagerCommitPhaseOne() call.
**
** If the final parameter - noSync - is true, then the database file itself
@@ -52550,7 +58069,7 @@ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
*/
SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
Pager *pPager, /* Pager object */
- const char *zMaster, /* If not NULL, the master journal name */
+ const char *zSuper, /* If not NULL, the super-journal name */
int noSync /* True to omit the xSync on the db file */
){
int rc = SQLITE_OK; /* Return code */
@@ -52568,8 +58087,8 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
/* Provide the ability to easily simulate an I/O error during testing */
if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
- pPager->zFilename, zMaster, pPager->dbSize));
+ PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n",
+ pPager->zFilename, zSuper, pPager->dbSize));
/* If no database changes have been made, return early. */
if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
@@ -52582,9 +58101,10 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
** backup in progress needs to be restarted. */
sqlite3BackupRestart(pPager->pBackup);
}else{
+ PgHdr *pList;
if( pagerUseWal(pPager) ){
- PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
PgHdr *pPageOne = 0;
+ pList = sqlite3PcacheDirtyList(pPager->pPCache);
if( pList==0 ){
/* Must have at least one page for the WAL commit flag.
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
@@ -52601,13 +58121,28 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
sqlite3PcacheCleanAll(pPager->pPCache);
}
}else{
+ /* The bBatch boolean is true if the batch-atomic-write commit method
+ ** should be used. No rollback journal is created if batch-atomic-write
+ ** is enabled.
+ */
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ sqlite3_file *fd = pPager->fd;
+ int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
+ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
+ && !pPager->noSync
+ && sqlite3JournalIsInMemory(pPager->jfd);
+#else
+# define bBatch 0
+#endif
+
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/* The following block updates the change-counter. Exactly how it
** does this depends on whether or not the atomic-update optimization
- ** was enabled at compile time, and if this transaction meets the
- ** runtime criteria to use the operation:
+ ** was enabled at compile time, and if this transaction meets the
+ ** runtime criteria to use the operation:
**
** * The file-system supports the atomic-write property for
- ** blocks of size page-size, and
+ ** blocks of size page-size, and
** * This commit is not part of a multi-file transaction, and
** * Exactly one page has been modified and store in the journal file.
**
@@ -52617,71 +58152,108 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
** is not applicable to this transaction, call sqlite3JournalCreate()
** to make sure the journal file has actually been created, then call
** pager_incr_changecounter() to update the change-counter in indirect
- ** mode.
+ ** mode.
**
** Otherwise, if the optimization is both enabled and applicable,
** then call pager_incr_changecounter() to update the change-counter
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
- #ifdef SQLITE_ENABLE_ATOMIC_WRITE
- PgHdr *pPg;
- assert( isOpen(pPager->jfd)
- || pPager->journalMode==PAGER_JOURNALMODE_OFF
- || pPager->journalMode==PAGER_JOURNALMODE_WAL
- );
- if( !zMaster && isOpen(pPager->jfd)
- && pPager->journalOff==jrnlBufferSize(pPager)
- && pPager->dbSize>=pPager->dbOrigSize
- && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
- ){
- /* Update the db file change counter via the direct-write method. The
- ** following call will modify the in-memory representation of page 1
- ** to include the updated change counter and then write page 1
- ** directly to the database file. Because of the atomic-write
- ** property of the host file-system, this is safe.
- */
- rc = pager_incr_changecounter(pPager, 1);
- }else{
- rc = sqlite3JournalCreate(pPager->jfd);
- if( rc==SQLITE_OK ){
- rc = pager_incr_changecounter(pPager, 0);
+ if( bBatch==0 ){
+ PgHdr *pPg;
+ assert( isOpen(pPager->jfd)
+ || pPager->journalMode==PAGER_JOURNALMODE_OFF
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
+ );
+ if( !zSuper && isOpen(pPager->jfd)
+ && pPager->journalOff==jrnlBufferSize(pPager)
+ && pPager->dbSize>=pPager->dbOrigSize
+ && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
+ ){
+ /* Update the db file change counter via the direct-write method. The
+ ** following call will modify the in-memory representation of page 1
+ ** to include the updated change counter and then write page 1
+ ** directly to the database file. Because of the atomic-write
+ ** property of the host file-system, this is safe.
+ */
+ rc = pager_incr_changecounter(pPager, 1);
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc==SQLITE_OK ){
+ rc = pager_incr_changecounter(pPager, 0);
+ }
}
}
- #else
+#else /* SQLITE_ENABLE_ATOMIC_WRITE */
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( zSuper ){
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+ assert( bBatch==0 );
+ }
+#endif
rc = pager_incr_changecounter(pPager, 0);
- #endif
+#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- /* Write the master journal name into the journal file. If a master
- ** journal file name has already been written to the journal file,
- ** or if zMaster is NULL (no master journal), then this call is a no-op.
+
+ /* Write the super-journal name into the journal file. If a
+ ** super-journal file name has already been written to the journal file,
+ ** or if zSuper is NULL (no super-journal), then this call is a no-op.
*/
- rc = writeMasterJournal(pPager, zMaster);
+ rc = writeSuperJournal(pPager, zSuper);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
+
/* Sync the journal file and write all dirty pages to the database.
- ** If the atomic-update optimization is being used, this sync will not
+ ** If the atomic-update optimization is being used, this sync will not
** create the journal file or perform any real IO.
**
** Because the change-counter page was just modified, unless the
** atomic-update optimization is used it is almost certain that the
** journal requires a sync here. However, in locking_mode=exclusive
- ** on a system under memory pressure it is just possible that this is
+ ** on a system under memory pressure it is just possible that this is
** not the case. In this case it is likely enough that the redundant
- ** xSync() call will be changed to a no-op by the OS anyhow.
+ ** xSync() call will be changed to a no-op by the OS anyhow.
*/
rc = syncJournal(pPager, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-
- rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
+
+ pList = sqlite3PcacheDirtyList(pPager->pPCache);
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ if( bBatch ){
+ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
+ if( rc==SQLITE_OK ){
+ rc = pager_write_pagelist(pPager, pList);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
+ }
+ }
+
+ if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc!=SQLITE_OK ){
+ sqlite3OsClose(pPager->jfd);
+ goto commit_phase_one_exit;
+ }
+ bBatch = 0;
+ }else{
+ sqlite3OsClose(pPager->jfd);
+ }
+ }
+#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
+
+ if( bBatch==0 ){
+ rc = pager_write_pagelist(pPager, pList);
+ }
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
}
sqlite3PcacheCleanAll(pPager->pPCache);
- /* If the file on disk is smaller than the database image, use
+ /* If the file on disk is smaller than the database image, use
** pager_truncate to grow the file here. This can happen if the database
** image was extended as part of the current transaction and then the
** last page in the db image moved to the free-list. In this case the
@@ -52693,10 +58265,10 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
rc = pager_truncate(pPager, nNew);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
}
-
+
/* Finally, sync the database file. */
if( !noSync ){
- rc = sqlite3PagerSync(pPager, zMaster);
+ rc = sqlite3PagerSync(pPager, zSuper);
}
IOTRACE(("DBSYNC %p\n", pPager))
}
@@ -52713,12 +58285,12 @@ commit_phase_one_exit:
/*
** When this function is called, the database file has been completely
** updated to reflect the changes made by the current transaction and
-** synced to disk. The journal file still exists in the file-system
+** synced to disk. The journal file still exists in the file-system
** though, and if a failure occurs at this point it will eventually
** be used as a hot-journal and the current transaction rolled back.
**
-** This function finalizes the journal file, either by deleting,
-** truncating or partially zeroing it, so that it cannot be used
+** This function finalizes the journal file, either by deleting,
+** truncating or partially zeroing it, so that it cannot be used
** for hot-journal rollback. Once this is done the transaction is
** irrevocably committed.
**
@@ -52732,6 +58304,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
** But if (due to a coding error elsewhere in the system) it does get
** called, just return the same error code without doing anything. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
+ pPager->iDataVersion++;
assert( pPager->eState==PAGER_WRITER_LOCKED
|| pPager->eState==PAGER_WRITER_FINISHED
@@ -52743,15 +58316,15 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
** this transaction, the pager is running in exclusive-mode and is
** using persistent journals, then this function is a no-op.
**
- ** The start of the journal file currently contains a single journal
+ ** The start of the journal file currently contains a single journal
** header with the nRec field set to 0. If such a journal is used as
** a hot-journal during hot-journal rollback, 0 changes will be made
- ** to the database file. So there is no need to zero the journal
+ ** to the database file. So there is no need to zero the journal
** header. Since the pager is in exclusive mode, there is no need
** to drop any locks either.
*/
- if( pPager->eState==PAGER_WRITER_LOCKED
- && pPager->exclusiveMode
+ if( pPager->eState==PAGER_WRITER_LOCKED
+ && pPager->exclusiveMode
&& pPager->journalMode==PAGER_JOURNALMODE_PERSIST
){
assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
@@ -52760,13 +58333,12 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
}
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
- pPager->iDataVersion++;
- rc = pager_end_transaction(pPager, pPager->setMaster, 1);
+ rc = pager_end_transaction(pPager, pPager->setSuper, 1);
return pager_error(pPager, rc);
}
/*
-** If a write transaction is open, then all changes made within the
+** If a write transaction is open, then all changes made within the
** transaction are reverted and the current write-transaction is closed.
** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR
** state if an error occurs.
@@ -52776,14 +58348,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
**
** Otherwise, in rollback mode, this function performs two functions:
**
-** 1) It rolls back the journal file, restoring all database file and
+** 1) It rolls back the journal file, restoring all database file and
** in-memory cache pages to the state they were in when the transaction
** was opened, and
**
** 2) It finalizes the journal file, so that it is not used for hot
** rollback at any point in the future.
**
-** Finalization of the journal file (task 2) is only performed if the
+** Finalization of the journal file (task 2) is only performed if the
** rollback is successful.
**
** In WAL mode, all cache-entries containing data modified within the
@@ -52796,7 +58368,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
/* PagerRollback() is a no-op if called in READER or OPEN state. If
- ** the pager is already in the ERROR state, the rollback is not
+ ** the pager is already in the ERROR state, the rollback is not
** attempted here. Instead, the error code is returned to the caller.
*/
assert( assert_pager_state(pPager) );
@@ -52806,18 +58378,19 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
if( pagerUseWal(pPager) ){
int rc2;
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
- rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
+ rc2 = pager_end_transaction(pPager, pPager->setSuper, 0);
if( rc==SQLITE_OK ) rc = rc2;
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
int eState = pPager->eState;
rc = pager_end_transaction(pPager, 0, 0);
if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
- /* This can happen using journal_mode=off. Move the pager to the error
+ /* This can happen using journal_mode=off. Move the pager to the error
** state to indicate that the contents of the cache may not be trusted.
** Any active readers will get SQLITE_ABORT.
*/
pPager->errCode = SQLITE_ABORT;
pPager->eState = PAGER_ERROR;
+ setGetterMethod(pPager);
return rc;
}
}else{
@@ -52826,7 +58399,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
- || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
+ || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
|| rc==SQLITE_CANTOPEN
);
@@ -52894,10 +58467,14 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
#endif
/*
-** Parameter eStat must be either SQLITE_DBSTATUS_CACHE_HIT or
-** SQLITE_DBSTATUS_CACHE_MISS. Before returning, *pnVal is incremented by the
-** current cache hit or miss count, according to the value of eStat. If the
-** reset parameter is non-zero, the cache hit or miss count is zeroed before
+** Parameter eStat must be one of SQLITE_DBSTATUS_CACHE_HIT, _MISS, _WRITE,
+** or _WRITE+1. The SQLITE_DBSTATUS_CACHE_WRITE+1 case is a translation
+** of SQLITE_DBSTATUS_CACHE_SPILL. The _SPILL case is not contiguous because
+** it was added later.
+**
+** Before returning, *pnVal is incremented by the
+** current cache hit or miss count, according to the value of eStat. If the
+** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
*/
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
@@ -52905,15 +58482,18 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
|| eStat==SQLITE_DBSTATUS_CACHE_WRITE
+ || eStat==SQLITE_DBSTATUS_CACHE_WRITE+1
);
assert( SQLITE_DBSTATUS_CACHE_HIT+1==SQLITE_DBSTATUS_CACHE_MISS );
assert( SQLITE_DBSTATUS_CACHE_HIT+2==SQLITE_DBSTATUS_CACHE_WRITE );
- assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1 && PAGER_STAT_WRITE==2 );
+ assert( PAGER_STAT_HIT==0 && PAGER_STAT_MISS==1
+ && PAGER_STAT_WRITE==2 && PAGER_STAT_SPILL==3 );
- *pnVal += pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT];
+ eStat -= SQLITE_DBSTATUS_CACHE_HIT;
+ *pnVal += pPager->aStat[eStat];
if( reset ){
- pPager->aStat[eStat - SQLITE_DBSTATUS_CACHE_HIT] = 0;
+ pPager->aStat[eStat] = 0;
}
}
@@ -52930,7 +58510,7 @@ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
** to make up the difference. If the number of savepoints is already
** equal to nSavepoint, then this function is a no-op.
**
-** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
+** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
** occurs while opening the sub-journal file, then an IO error code is
** returned. Otherwise, SQLITE_OK.
*/
@@ -52945,7 +58525,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
assert( nSavepoint>nCurrent && pPager->useJournal );
/* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
- ** if the allocation fails. Otherwise, zero the new portion in case a
+ ** if the allocation fails. Otherwise, zero the new portion in case a
** malloc failure occurs while populating it in the for(...) loop below.
*/
aNew = (PagerSavepoint *)sqlite3Realloc(
@@ -52993,7 +58573,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
/*
** This function is called to rollback or release (commit) a savepoint.
-** The savepoint to release or rollback need not be the most recently
+** The savepoint to release or rollback need not be the most recently
** created savepoint.
**
** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
@@ -53001,29 +58581,29 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
** that have occurred since the specified savepoint was created.
**
-** The savepoint to rollback or release is identified by parameter
+** The savepoint to rollback or release is identified by parameter
** iSavepoint. A value of 0 means to operate on the outermost savepoint
** (the first created). A value of (Pager.nSavepoint-1) means operate
** on the most recently created savepoint. If iSavepoint is greater than
** (Pager.nSavepoint-1), then this function is a no-op.
**
** If a negative value is passed to this function, then the current
-** transaction is rolled back. This is different to calling
+** transaction is rolled back. This is different to calling
** sqlite3PagerRollback() because this function does not terminate
-** the transaction or unlock the database, it just restores the
-** contents of the database to its original state.
+** the transaction or unlock the database, it just restores the
+** contents of the database to its original state.
**
-** In any case, all savepoints with an index greater than iSavepoint
+** In any case, all savepoints with an index greater than iSavepoint
** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE),
** then savepoint iSavepoint is also destroyed.
**
** This function may return SQLITE_NOMEM if a memory allocation fails,
-** or an IO error code if an IO error occurs while rolling back a
+** or an IO error code if an IO error occurs while rolling back a
** savepoint. If no errors occur, SQLITE_OK is returned.
-*/
+*/
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
int rc = pPager->errCode;
-
+
#ifdef SQLITE_ENABLE_ZIPVFS
if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK;
#endif
@@ -53036,7 +58616,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
int nNew; /* Number of remaining savepoints after this op. */
/* Figure out how many savepoints will still be active after this
- ** operation. Store this value in nNew. Then free resources associated
+ ** operation. Store this value in nNew. Then free resources associated
** with any savepoints that are destroyed by this operation.
*/
nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
@@ -53045,7 +58625,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
}
pPager->nSavepoint = nNew;
- /* If this is a release of the outermost savepoint, truncate
+ /* If this is a release of the outermost savepoint, truncate
** the sub-journal to zero bytes in size. */
if( op==SAVEPOINT_RELEASE ){
if( nNew==0 && isOpen(pPager->sjfd) ){
@@ -53067,18 +58647,19 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
}
-
+
#ifdef SQLITE_ENABLE_ZIPVFS
- /* If the cache has been modified but the savepoint cannot be rolled
+ /* If the cache has been modified but the savepoint cannot be rolled
** back journal_mode=off, put the pager in the error state. This way,
** if the VFS used by this pager includes ZipVFS, the entire transaction
** can be rolled back at the ZipVFS level. */
- else if(
- pPager->journalMode==PAGER_JOURNALMODE_OFF
+ else if(
+ pPager->journalMode==PAGER_JOURNALMODE_OFF
&& pPager->eState>=PAGER_WRITER_CACHEMOD
){
pPager->errCode = SQLITE_ABORT;
pPager->eState = PAGER_ERROR;
+ setGetterMethod(pPager);
}
#endif
}
@@ -53095,9 +58676,13 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
** behavior. But when the Btree needs to know the filename for matching to
** shared cache, it uses nullIfMemDb==0 so that in-memory databases can
** participate in shared-cache.
+**
+** The return value to this routine is always safe to use with
+** sqlite3_uri_parameter() and sqlite3_filename_database() and friends.
*/
-SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){
- return (nullIfMemDb && pPager->memDb) ? "" : pPager->zFilename;
+SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){
+ static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename;
}
/*
@@ -53135,49 +58720,6 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
return pPager->zJournal;
}
-#ifdef SQLITE_HAS_CODEC
-/*
-** Set or retrieve the codec for this pager
-*/
-SQLITE_PRIVATE void sqlite3PagerSetCodec(
- Pager *pPager,
- void *(*xCodec)(void*,void*,Pgno,int),
- void (*xCodecSizeChng)(void*,int,int),
- void (*xCodecFree)(void*),
- void *pCodec
-){
- if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
- pPager->xCodec = pPager->memDb ? 0 : xCodec;
- pPager->xCodecSizeChng = xCodecSizeChng;
- pPager->xCodecFree = xCodecFree;
- pPager->pCodec = pCodec;
- pagerReportSize(pPager);
-}
-SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
- return pPager->pCodec;
-}
-
-/*
-** This function is called by the wal module when writing page content
-** into the log file.
-**
-** This function returns a pointer to a buffer containing the encrypted
-** page content. If a malloc fails, this function may return NULL.
-*/
-SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
- void *aData = 0;
- CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
- return aData;
-}
-
-/*
-** Return the current pager state
-*/
-SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
- return pPager->eState;
-}
-#endif /* SQLITE_HAS_CODEC */
-
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Move the page pPg to location pgno in the file.
@@ -53197,8 +58739,8 @@ SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
** transaction is active).
**
** If the fourth argument, isCommit, is non-zero, then this page is being
-** moved as part of a database reorganization just before the transaction
-** is being committed. In this case, it is guaranteed that the database page
+** moved as part of a database reorganization just before the transaction
+** is being committed. In this case, it is guaranteed that the database page
** pPg refers to will not be written to again within this transaction.
**
** This function may return SQLITE_NOMEM or an IO error code if an error
@@ -53226,7 +58768,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
}
/* If the page being moved is dirty and has not been saved by the latest
- ** savepoint, then save the current contents of the page into the
+ ** savepoint, then save the current contents of the page into the
** sub-journal now. This is required to handle the following scenario:
**
** BEGIN;
@@ -53249,7 +58791,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
return rc;
}
- PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
+ PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
@@ -53257,7 +58799,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** be written to, store pPg->pgno in local variable needSyncPgno.
**
** If the isCommit flag is set, there is no need to remember that
- ** the journal needs to be sync()ed before database page pPg->pgno
+ ** the journal needs to be sync()ed before database page pPg->pgno
** can be written to. The caller has already promised not to write to it.
*/
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
@@ -53268,14 +58810,18 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
}
/* If the cache contains a page with page-number pgno, remove it
- ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
- ** page pgno before the 'move' operation, it needs to be retained
+ ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
+ ** page pgno before the 'move' operation, it needs to be retained
** for the page moved there.
*/
pPg->flags &= ~PGHDR_NEED_SYNC;
pPgOld = sqlite3PagerLookup(pPager, pgno);
- assert( !pPgOld || pPgOld->nRef==1 );
+ assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB );
if( pPgOld ){
+ if( pPgOld->nRef>1 ){
+ sqlite3PagerUnrefNotNull(pPgOld);
+ return SQLITE_CORRUPT_BKPT;
+ }
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
if( pPager->tempFile ){
/* Do not discard pages from an in-memory database since we might
@@ -53300,9 +58846,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
}
if( needSyncPgno ){
- /* If needSyncPgno is non-zero, then the journal file needs to be
+ /* If needSyncPgno is non-zero, then the journal file needs to be
** sync()ed before any data is written to database file page needSyncPgno.
- ** Currently, no such page exists in the page-cache and the
+ ** Currently, no such page exists in the page-cache and the
** "is journaled" bitvec flag has been set. This needs to be remedied by
** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC
** flag.
@@ -53333,9 +58879,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
#endif
/*
-** The page handle passed as the first argument refers to a dirty page
-** with a page number other than iNew. This function changes the page's
-** page number to iNew and sets the value of the PgHdr.flags field to
+** The page handle passed as the first argument refers to a dirty page
+** with a page number other than iNew. This function changes the page's
+** page number to iNew and sets the value of the PgHdr.flags field to
** the value passed as the third parameter.
*/
SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
@@ -53353,7 +58899,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
}
/*
-** Return a pointer to the Pager.nExtra bytes of "extra" space
+** Return a pointer to the Pager.nExtra bytes of "extra" space
** allocated along with the specified page.
*/
SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
@@ -53362,7 +58908,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
/*
** Get/set the locking-mode for this pager. Parameter eMode must be one
-** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
+** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
** the locking-mode is set to the value specified.
**
@@ -53406,19 +58952,12 @@ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){
SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
u8 eOld = pPager->journalMode; /* Prior journalmode */
-#ifdef SQLITE_DEBUG
- /* The print_pager_state() routine is intended to be used by the debugger
- ** only. We invoke it once here to suppress a compiler warning. */
- print_pager_state(pPager);
-#endif
-
-
/* The eMode parameter is always valid */
assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
- || eMode==PAGER_JOURNALMODE_OFF
- || eMode==PAGER_JOURNALMODE_WAL
+ || eMode==PAGER_JOURNALMODE_OFF
+ || eMode==PAGER_JOURNALMODE_WAL
|| eMode==PAGER_JOURNALMODE_MEMORY );
/* This routine is only called from the OP_JournalMode opcode, and
@@ -53560,13 +59099,19 @@ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
**
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
*/
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(
+ Pager *pPager, /* Checkpoint on this pager */
+ sqlite3 *db, /* Db handle used to check for interrupts */
+ int eMode, /* Type of checkpoint */
+ int *pnLog, /* OUT: Final number of frames in log */
+ int *pnCkpt /* OUT: Final number of checkpointed frames */
+){
int rc = SQLITE_OK;
if( pPager->pWal ){
- rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
+ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
- pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
+ pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
pnLog, pnCkpt
);
}
@@ -53597,7 +59142,7 @@ static int pagerExclusiveLock(Pager *pPager){
assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
- /* If the attempt to grab the exclusive lock failed, release the
+ /* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead. */
pagerUnlockDb(pPager, SHARED_LOCK);
}
@@ -53606,7 +59151,7 @@ static int pagerExclusiveLock(Pager *pPager){
}
/*
-** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
+** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
** exclusive-locking mode when this function is called, take an EXCLUSIVE
** lock on the database file and use heap-memory to store the wal-index
** in. Otherwise, use the normal shared-memory.
@@ -53617,8 +59162,8 @@ static int pagerOpenWal(Pager *pPager){
assert( pPager->pWal==0 && pPager->tempFile==0 );
assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
- /* If the pager is already in exclusive-mode, the WAL module will use
- ** heap-memory for the wal-index instead of the VFS shared-memory
+ /* If the pager is already in exclusive-mode, the WAL module will use
+ ** heap-memory for the wal-index instead of the VFS shared-memory
** implementation. Take the exclusive lock now, before opening the WAL
** file, to make sure this is safe.
*/
@@ -53626,7 +59171,7 @@ static int pagerOpenWal(Pager *pPager){
rc = pagerExclusiveLock(pPager);
}
- /* Open the connection to the log file. If this operation fails,
+ /* Open the connection to the log file. If this operation fails,
** (e.g. due to malloc() failure), return an error code.
*/
if( rc==SQLITE_OK ){
@@ -53648,7 +59193,7 @@ static int pagerOpenWal(Pager *pPager){
** If the pager passed as the first argument is open on a real database
** file (not a temp file or an in-memory database), and the WAL file
** is not already open, make an attempt to open it now. If successful,
-** return SQLITE_OK. If an error occurs or the VFS used by the pager does
+** return SQLITE_OK. If an error occurs or the VFS used by the pager does
** not support the xShmXXX() methods, return an error code. *pbOpen is
** not modified in either case.
**
@@ -53690,12 +59235,12 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
** This function is called to close the connection to the log file prior
** to switching from WAL to rollback mode.
**
-** Before closing the log file, this function attempts to take an
+** Before closing the log file, this function attempts to take an
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
** error (SQLITE_BUSY) is returned and the log connection is not closed.
** If successful, the EXCLUSIVE lock is not released before returning.
*/
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
int rc = SQLITE_OK;
assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
@@ -53716,14 +59261,14 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
rc = pagerOpenWal(pPager);
}
}
-
+
/* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
** the database file, the log and log-summary files will be deleted.
*/
if( rc==SQLITE_OK && pPager->pWal ){
rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
- rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
+ rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
@@ -53733,6 +59278,32 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
return rc;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+/*
+** If pager pPager is a wal-mode database not in exclusive locking mode,
+** invoke the sqlite3WalWriteLock() function on the associated Wal object
+** with the same db and bLock parameters as were passed to this function.
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
+*/
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
+ int rc = SQLITE_OK;
+ if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
+ rc = sqlite3WalWriteLock(pPager->pWal, bLock);
+ }
+ return rc;
+}
+
+/*
+** Set the database handle used by the wal layer to determine if
+** blocking locks are required.
+*/
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
+ if( pagerUseWal(pPager) ){
+ sqlite3WalDb(pPager->pWal, db);
+ }
+}
+#endif
+
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
** If this is a WAL database, obtain a snapshot handle for the snapshot
@@ -53748,10 +59319,13 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppS
/*
** If this is a WAL database, store a pointer to pSnapshot. Next time a
-** read transaction is opened, attempt to read from the snapshot it
+** read transaction is opened, attempt to read from the snapshot it
** identifies. If this is not a WAL database, return an error.
*/
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
+ Pager *pPager,
+ sqlite3_snapshot *pSnapshot
+){
int rc = SQLITE_OK;
if( pPager->pWal ){
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
@@ -53760,6 +59334,52 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSn
}
return rc;
}
+
+/*
+** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this
+** is not a WAL database, return an error.
+*/
+SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
+ int rc;
+ if( pPager->pWal ){
+ rc = sqlite3WalSnapshotRecover(pPager->pWal);
+ }else{
+ rc = SQLITE_ERROR;
+ }
+ return rc;
+}
+
+/*
+** The caller currently has a read transaction open on the database.
+** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise,
+** this function takes a SHARED lock on the CHECKPOINTER slot and then
+** checks if the snapshot passed as the second argument is still
+** available. If so, SQLITE_OK is returned.
+**
+** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
+** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
+** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
+** lock is released before returning.
+*/
+SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){
+ int rc;
+ if( pPager->pWal ){
+ rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot);
+ }else{
+ rc = SQLITE_ERROR;
+ }
+ return rc;
+}
+
+/*
+** Release a lock obtained by an earlier successful call to
+** sqlite3PagerSnapshotCheck().
+*/
+SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){
+ assert( pPager->pWal );
+ sqlite3WalSnapshotUnlock(pPager->pWal);
+}
+
#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */
@@ -53793,7 +59413,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
**
*************************************************************************
**
-** This file contains the implementation of a write-ahead log (WAL) used in
+** This file contains the implementation of a write-ahead log (WAL) used in
** "journal_mode=WAL" mode.
**
** WRITE-AHEAD LOG (WAL) FILE FORMAT
@@ -53802,7 +59422,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
** Each frame records the revised content of a single page from the
** database file. All changes to the database are recorded by writing
** frames into the WAL. Transactions commit when a frame is written that
-** contains a commit marker. A single WAL can and usually does record
+** contains a commit marker. A single WAL can and usually does record
** multiple transactions. Periodically, the content of the WAL is
** transferred back into the database file in an operation called a
** "checkpoint".
@@ -53828,11 +59448,11 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
**
** Immediately following the wal-header are zero or more frames. Each
** frame consists of a 24-byte frame-header followed by a <page-size> bytes
-** of page data. The frame-header is six big-endian 32-bit unsigned
+** of page data. The frame-header is six big-endian 32-bit unsigned
** integer values, as follows:
**
** 0: Page number.
-** 4: For commit records, the size of the database image in pages
+** 4: For commit records, the size of the database image in pages
** after the commit. For all other records, zero.
** 8: Salt-1 (copied from the header)
** 12: Salt-2 (copied from the header)
@@ -53858,7 +59478,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
** the checksum. The checksum is computed by interpreting the input as
** an even number of unsigned 32-bit integers: x[0] through x[N]. The
** algorithm used for the checksum is as follows:
-**
+**
** for i from 0 to n-1 step 2:
** s0 += x[i] + s1;
** s1 += x[i+1] + s0;
@@ -53866,7 +59486,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
**
** Note that s0 and s1 are both weighted checksums using fibonacci weights
** in reverse order (the largest fibonacci weight occurs on the first element
-** of the sequence being summed.) The s1 value spans all 32-bit
+** of the sequence being summed.) The s1 value spans all 32-bit
** terms of the sequence whereas s0 omits the final term.
**
** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
@@ -53899,22 +59519,26 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
** multiple concurrent readers to view different versions of the database
** content simultaneously.
**
-** The reader algorithm in the previous paragraphs works correctly, but
+** The reader algorithm in the previous paragraphs works correctly, but
** because frames for page P can appear anywhere within the WAL, the
** reader has to scan the entire WAL looking for page P frames. If the
** WAL is large (multiple megabytes is typical) that scan can be slow,
** and read performance suffers. To overcome this problem, a separate
** data structure called the wal-index is maintained to expedite the
** search for frames of a particular page.
-**
+**
** WAL-INDEX FORMAT
**
** Conceptually, the wal-index is shared memory, though VFS implementations
** might choose to implement the wal-index using a mmapped file. Because
-** the wal-index is shared memory, SQLite does not support journal_mode=WAL
+** the wal-index is shared memory, SQLite does not support journal_mode=WAL
** on a network filesystem. All users of the database must be able to
** share memory.
**
+** In the default unix and windows implementation, the wal-index is a mmapped
+** file whose name is the database name with a "-shm" suffix added. For that
+** reason, the wal-index is sometimes called the "shm" file.
+**
** The wal-index is transient. After a crash, the wal-index can (and should
** be) reconstructed from the original WAL file. In fact, the VFS is required
** to either truncate or zero the header of the wal-index when the last
@@ -53925,28 +59549,28 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
** byte order of the host computer.
**
** The purpose of the wal-index is to answer this question quickly: Given
-** a page number P and a maximum frame index M, return the index of the
+** a page number P and a maximum frame index M, return the index of the
** last frame in the wal before frame M for page P in the WAL, or return
** NULL if there are no frames for page P in the WAL prior to M.
**
** The wal-index consists of a header region, followed by an one or
-** more index blocks.
+** more index blocks.
**
** The wal-index header contains the total number of frames within the WAL
** in the mxFrame field.
**
-** Each index block except for the first contains information on
+** Each index block except for the first contains information on
** HASHTABLE_NPAGE frames. The first index block contains information on
-** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
+** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
** HASHTABLE_NPAGE are selected so that together the wal-index header and
** first index block are the same size as all other index blocks in the
** wal-index.
**
** Each index block contains two sections, a page-mapping that contains the
-** database page number associated with each wal frame, and a hash-table
+** database page number associated with each wal frame, and a hash-table
** that allows readers to query an index block for a specific page number.
** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE
-** for the first index block) 32-bit page numbers. The first entry in the
+** for the first index block) 32-bit page numbers. The first entry in the
** first index-block contains the database page number corresponding to the
** first frame in the WAL file. The first entry in the second index block
** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in
@@ -53967,8 +59591,8 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
**
** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers.
** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the
-** hash table for each page number in the mapping section, so the hash
-** table is never more than half full. The expected number of collisions
+** hash table for each page number in the mapping section, so the hash
+** table is never more than half full. The expected number of collisions
** prior to finding a match is 1. Each entry of the hash table is an
** 1-based index of an entry in the mapping section of the same
** index block. Let K be the 1-based index of the largest entry in
@@ -53987,12 +59611,12 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
** reached) until an unused hash slot is found. Let the first unused slot
** be at index iUnused. (iUnused might be less than iKey if there was
** wrap-around.) Because the hash table is never more than half full,
-** the search is guaranteed to eventually hit an unused entry. Let
+** the search is guaranteed to eventually hit an unused entry. Let
** iMax be the value between iKey and iUnused, closest to iUnused,
** where aHash[iMax]==P. If there is no iMax entry (if there exists
** no hash slot such that aHash[i]==p) then page P is not in the
** current index block. Otherwise the iMax-th mapping entry of the
-** current index block corresponds to the last entry that references
+** current index block corresponds to the last entry that references
** page P.
**
** A hash search begins with the last index block and moves toward the
@@ -54017,7 +59641,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
** if no values greater than K0 had ever been inserted into the hash table
** in the first place - which is what reader one wants. Meanwhile, the
** second reader using K1 will see additional values that were inserted
-** later, which is exactly what reader two wants.
+** later, which is exactly what reader two wants.
**
** When a rollback occurs, the value of K is decreased. Hash table entries
** that correspond to frames greater than the new K value are removed
@@ -54045,7 +59669,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
** values in the wal-header are correct and (b) the version field is not
** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
**
-** Similarly, if a client successfully reads a wal-index header (i.e. the
+** Similarly, if a client successfully reads a wal-index header (i.e. the
** checksum test is successful) and finds that the version field is not
** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
** returns SQLITE_CANTOPEN.
@@ -54054,9 +59678,18 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
#define WALINDEX_MAX_VERSION 3007000
/*
-** Indices of various locking bytes. WAL_NREADER is the number
+** Index numbers for various locking bytes. WAL_NREADER is the number
** of available reader locks and should be at least 3. The default
** is SQLITE_SHM_NLOCK==8 and WAL_NREADER==5.
+**
+** Technically, the various VFSes are free to implement these locks however
+** they see fit. However, compatibility is encouraged so that VFSes can
+** interoperate. The standard implemention used on both unix and windows
+** is for the index number to indicate a byte offset into the
+** WalCkptInfo.aLock[] array in the wal-index header. In other words, all
+** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which
+** should be 120) is the location in the shm file for the first locking
+** byte.
*/
#define WAL_WRITE_LOCK 0
#define WAL_ALL_BUT_WRITE 1
@@ -54083,7 +59716,7 @@ typedef struct WalCkptInfo WalCkptInfo;
**
** The szPage value can be any power of 2 between 512 and 32768, inclusive.
** Or it can be 1 to represent a 65536-byte page. The latter case was
-** added in 3.7.1 when support for 64K pages was added.
+** added in 3.7.1 when support for 64K pages was added.
*/
struct WalIndexHdr {
u32 iVersion; /* Wal-index version */
@@ -54125,7 +59758,7 @@ struct WalIndexHdr {
** There is one entry in aReadMark[] for each reader lock. If a reader
** holds read-lock K, then the value in aReadMark[K] is no greater than
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
-** for any aReadMark[] means that entry is unused. aReadMark[0] is
+** for any aReadMark[] means that entry is unused. aReadMark[0] is
** a special case; its value is never used and it exists as a place-holder
** to avoid having to offset aReadMark[] indexs by one. Readers holding
** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
@@ -54145,7 +59778,7 @@ struct WalIndexHdr {
** previous sentence is when nBackfill equals mxFrame (meaning that everything
** in the WAL has been backfilled into the database) then new readers
** will choose aReadMark[0] which has value 0 and hence such reader will
-** get all their all content directly from the database file and ignore
+** get all their all content directly from the database file and ignore
** the WAL.
**
** Writers normally append new frames to the end of the WAL. However,
@@ -54180,7 +59813,6 @@ struct WalCkptInfo {
#define WAL_FRAME_HDRSIZE 24
/* Size of write ahead log header, including checksum. */
-/* #define WAL_HDRSIZE 24 */
#define WAL_HDRSIZE 32
/* WAL magic value. Either this value, or the same value with the least
@@ -54188,14 +59820,14 @@ struct WalCkptInfo {
** big-endian format in the first 4 bytes of a WAL file.
**
** If the LSB is set, then the checksums for each frame within the WAL
-** file are calculated by treating all data as an array of 32-bit
-** big-endian words. Otherwise, they are calculated by interpreting
+** file are calculated by treating all data as an array of 32-bit
+** big-endian words. Otherwise, they are calculated by interpreting
** all data as 32-bit little-endian words.
*/
#define WAL_MAGIC 0x377f0682
/*
-** Return the offset of frame iFrame in the write-ahead log file,
+** Return the offset of frame iFrame in the write-ahead log file,
** assuming a database page size of szPage bytes. The offset returned
** is to the start of the write-ahead log frame-header.
*/
@@ -54226,6 +59858,7 @@ struct Wal {
u8 truncateOnCommit; /* True to truncate WAL file on commit */
u8 syncHeader; /* Fsync the WAL header if true */
u8 padToSectorBoundary; /* Pad transactions out to the next sector */
+ u8 bShmUnreliable; /* SHM content is read-only and unreliable */
WalIndexHdr hdr; /* Wal-index header for current transaction */
u32 minFrame; /* Ignore wal frames before this one */
u32 iReCksum; /* On commit, recalculate checksums from here */
@@ -54237,13 +59870,16 @@ struct Wal {
#ifdef SQLITE_ENABLE_SNAPSHOT
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlite3 *db;
+#endif
};
/*
** Candidate values for Wal.exclusiveMode.
*/
#define WAL_NORMAL_MODE 0
-#define WAL_EXCLUSIVE_MODE 1
+#define WAL_EXCLUSIVE_MODE 1
#define WAL_HEAPMEMORY_MODE 2
/*
@@ -54262,7 +59898,7 @@ typedef u16 ht_slot;
/*
** This structure is used to implement an iterator that loops through
** all frames in the WAL in database page order. Where two or more frames
-** correspond to the same database page, the iterator visits only the
+** correspond to the same database page, the iterator visits only the
** frame most recently written to the WAL (in other words, the frame with
** the largest index).
**
@@ -54275,7 +59911,7 @@ typedef u16 ht_slot;
** This functionality is used by the checkpoint code (see walCheckpoint()).
*/
struct WalIterator {
- int iPrior; /* Last result returned from the iterator */
+ u32 iPrior; /* Last result returned from the iterator */
int nSegment; /* Number of entries in aSegment[] */
struct WalSegment {
int iNext; /* Next slot in aIndex[] not yet returned */
@@ -54298,7 +59934,7 @@ struct WalIterator {
#define HASHTABLE_HASH_1 383 /* Should be prime */
#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
-/*
+/*
** The block of page numbers associated with the first hash-table in a
** wal-index is smaller than usual. This is so that there is a complete
** hash-table on each aligned 32KB page of the wal-index.
@@ -54315,18 +59951,27 @@ struct WalIterator {
** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
** numbered from zero.
**
+** If the wal-index is currently smaller the iPage pages then the size
+** of the wal-index might be increased, but only if it is safe to do
+** so. It is safe to enlarge the wal-index if pWal->writeLock is true
+** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE.
+**
** If this call is successful, *ppPage is set to point to the wal-index
** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
** then an SQLite error code is returned and *ppPage is set to 0.
*/
-static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
+static SQLITE_NOINLINE int walIndexPageRealloc(
+ Wal *pWal, /* The WAL context */
+ int iPage, /* The page we seek */
+ volatile u32 **ppPage /* Write the page pointer here */
+){
int rc = SQLITE_OK;
/* Enlarge the pWal->apWiData[] array if required */
if( pWal->nWiData<=iPage ){
- int nByte = sizeof(u32*)*(iPage+1);
+ sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
volatile u32 **apNew;
- apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
+ apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
if( !apNew ){
*ppPage = 0;
return SQLITE_NOMEM_BKPT;
@@ -54338,16 +59983,21 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
}
/* Request a pointer to the required page from the VFS */
- if( pWal->apWiData[iPage]==0 ){
- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
- pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
- if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
- }else{
- rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
- pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
- );
+ assert( pWal->apWiData[iPage]==0 );
+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+ pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
+ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
+ }else{
+ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
+ pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+ );
+ assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
+ testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
+ if( rc==SQLITE_OK ){
+ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;
+ }else if( (rc&0xff)==SQLITE_READONLY ){
+ pWal->readOnly |= WAL_SHM_RDONLY;
if( rc==SQLITE_READONLY ){
- pWal->readOnly |= WAL_SHM_RDONLY;
rc = SQLITE_OK;
}
}
@@ -54357,6 +60007,16 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
return rc;
}
+static int walIndexPage(
+ Wal *pWal, /* The WAL context */
+ int iPage, /* The page we seek */
+ volatile u32 **ppPage /* Write the page pointer here */
+){
+ if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){
+ return walIndexPageRealloc(pWal, iPage, ppPage);
+ }
+ return SQLITE_OK;
+}
/*
** Return a pointer to the WalCkptInfo structure in the wal-index.
@@ -54387,7 +60047,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
)
/*
-** Generate or extend an 8 byte checksum based on the data in
+** Generate or extend an 8 byte checksum based on the data in
** array aByte[] and the initial values of aIn[0] and aIn[1] (or
** initial values of 0 and 0 if aIn==NULL).
**
@@ -54415,6 +60075,7 @@ static void walChecksumBytes(
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
+ assert( nByte<=65536 );
if( nativeCksum ){
do {
@@ -54433,6 +60094,10 @@ static void walChecksumBytes(
aOut[1] = s2;
}
+/*
+** If there is the possibility of concurrent access to the SHM file
+** from multiple threads and/or processes, then do a memory barrier.
+*/
static void walShmBarrier(Wal *pWal){
if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
sqlite3OsShmBarrier(pWal->pDbFd);
@@ -54440,11 +60105,24 @@ static void walShmBarrier(Wal *pWal){
}
/*
+** Add the SQLITE_NO_TSAN as part of the return-type of a function
+** definition as a hint that the function contains constructs that
+** might give false-positive TSAN warnings.
+**
+** See tag-20200519-1.
+*/
+#if defined(__clang__) && !defined(SQLITE_NO_TSAN)
+# define SQLITE_NO_TSAN __attribute__((no_sanitize_thread))
+#else
+# define SQLITE_NO_TSAN
+#endif
+
+/*
** Write the header information in pWal->hdr into the wal-index.
**
** The checksum on pWal->hdr is updated before it is written.
*/
-static void walIndexWriteHdr(Wal *pWal){
+static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){
volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
const int nCksum = offsetof(WalIndexHdr, aCksum);
@@ -54452,6 +60130,7 @@ static void walIndexWriteHdr(Wal *pWal){
pWal->hdr.isInit = 1;
pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+ /* Possible TSAN false-positive. See tag-20200519-1 */
memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
walShmBarrier(pWal);
memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
@@ -54459,11 +60138,11 @@ static void walIndexWriteHdr(Wal *pWal){
/*
** This function encodes a single frame header and writes it to a buffer
-** supplied by the caller. A frame-header is made up of a series of
+** supplied by the caller. A frame-header is made up of a series of
** 4-byte big-endian integers, as follows:
**
** 0: Page number.
-** 4: For commit records, the size of the database image in pages
+** 4: For commit records, the size of the database image in pages
** after the commit. For all other records, zero.
** 8: Salt-1 (copied from the wal-header)
** 12: Salt-2 (copied from the wal-header)
@@ -54514,7 +60193,7 @@ static int walDecodeFrame(
assert( WAL_FRAME_HDRSIZE==24 );
/* A frame is only valid if the salt values in the frame-header
- ** match the salt values in the wal-header.
+ ** match the salt values in the wal-header.
*/
if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
return 0;
@@ -54528,15 +60207,15 @@ static int walDecodeFrame(
}
/* A frame is only valid if a checksum of the WAL header,
- ** all prior frams, the first 16 bytes of this frame-header,
- ** and the frame-data matches the checksum in the last 8
+ ** all prior frams, the first 16 bytes of this frame-header,
+ ** and the frame-data matches the checksum in the last 8
** bytes of this frame-header.
*/
nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
- if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
- || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
+ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
+ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
){
/* Checksum failed. */
return 0;
@@ -54571,7 +60250,7 @@ static const char *walLockName(int lockIdx){
}
}
#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
-
+
/*
** Set or release locks on the WAL. Locks are either shared or exclusive.
@@ -54587,7 +60266,7 @@ static int walLockShared(Wal *pWal, int lockIdx){
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
walLockName(lockIdx), rc ? "failed" : "ok"));
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
return rc;
}
static void walUnlockShared(Wal *pWal, int lockIdx){
@@ -54603,7 +60282,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
walLockName(lockIdx), n, rc ? "failed" : "ok"));
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
return rc;
}
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
@@ -54628,48 +60307,51 @@ static int walNextHash(int iPriorHash){
return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
}
-/*
+/*
+** An instance of the WalHashLoc object is used to describe the location
+** of a page hash table in the wal-index. This becomes the return value
+** from walHashGet().
+*/
+typedef struct WalHashLoc WalHashLoc;
+struct WalHashLoc {
+ volatile ht_slot *aHash; /* Start of the wal-index hash table */
+ volatile u32 *aPgno; /* aPgno[1] is the page of first frame indexed */
+ u32 iZero; /* One less than the frame number of first indexed*/
+};
+
+/*
** Return pointers to the hash table and page number array stored on
** page iHash of the wal-index. The wal-index is broken into 32KB pages
** numbered starting from 0.
**
-** Set output variable *paHash to point to the start of the hash table
-** in the wal-index file. Set *piZero to one less than the frame
+** Set output variable pLoc->aHash to point to the start of the hash table
+** in the wal-index file. Set pLoc->iZero to one less than the frame
** number of the first frame indexed by this hash table. If a
-** slot in the hash table is set to N, it refers to frame number
-** (*piZero+N) in the log.
+** slot in the hash table is set to N, it refers to frame number
+** (pLoc->iZero+N) in the log.
**
-** Finally, set *paPgno so that *paPgno[1] is the page number of the
-** first frame indexed by the hash table, frame (*piZero+1).
+** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the
+** first frame indexed by the hash table, frame (pLoc->iZero+1).
*/
static int walHashGet(
Wal *pWal, /* WAL handle */
int iHash, /* Find the iHash'th table */
- volatile ht_slot **paHash, /* OUT: Pointer to hash index */
- volatile u32 **paPgno, /* OUT: Pointer to page number array */
- u32 *piZero /* OUT: Frame associated with *paPgno[0] */
+ WalHashLoc *pLoc /* OUT: Hash table location */
){
int rc; /* Return code */
- volatile u32 *aPgno;
- rc = walIndexPage(pWal, iHash, &aPgno);
+ rc = walIndexPage(pWal, iHash, &pLoc->aPgno);
assert( rc==SQLITE_OK || iHash>0 );
if( rc==SQLITE_OK ){
- u32 iZero;
- volatile ht_slot *aHash;
-
- aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+ pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE];
if( iHash==0 ){
- aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
- iZero = 0;
+ pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+ pLoc->iZero = 0;
}else{
- iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+ pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
}
-
- *paPgno = &aPgno[-1];
- *paHash = aHash;
- *piZero = iZero;
+ pLoc->aPgno = &pLoc->aPgno[-1];
}
return rc;
}
@@ -54677,7 +60359,7 @@ static int walHashGet(
/*
** Return the number of the wal-index page that contains the hash-table
** and page-number array that contain entries corresponding to WAL frame
-** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
** are numbered starting from 0.
*/
static int walFramePage(u32 iFrame){
@@ -54688,6 +60370,7 @@ static int walFramePage(u32 iFrame){
&& (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
&& (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
);
+ assert( iHash>=0 );
return iHash;
}
@@ -54715,12 +60398,11 @@ static u32 walFramePgno(Wal *pWal, u32 iFrame){
** actually needed.
*/
static void walCleanupHash(Wal *pWal){
- volatile ht_slot *aHash = 0; /* Pointer to hash table to clear */
- volatile u32 *aPgno = 0; /* Page number array for hash table */
- u32 iZero = 0; /* frame == (aHash[x]+iZero) */
+ WalHashLoc sLoc; /* Hash table location */
int iLimit = 0; /* Zero values greater than this */
int nByte; /* Number of bytes to zero in aPgno[] */
int i; /* Used to iterate through aHash[] */
+ int rc; /* Return code form walHashGet() */
assert( pWal->writeLock );
testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
@@ -54729,30 +60411,31 @@ static void walCleanupHash(Wal *pWal){
if( pWal->hdr.mxFrame==0 ) return;
- /* Obtain pointers to the hash-table and page-number array containing
+ /* Obtain pointers to the hash-table and page-number array containing
** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
- ** that the page said hash-table and array reside on is already mapped.
+ ** that the page said hash-table and array reside on is already mapped.(1)
*/
assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
- walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+ rc = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
+ if( NEVER(rc) ) return; /* Defense-in-depth, in case (1) above is wrong */
/* Zero all hash-table entries that correspond to frame numbers greater
** than pWal->hdr.mxFrame.
*/
- iLimit = pWal->hdr.mxFrame - iZero;
+ iLimit = pWal->hdr.mxFrame - sLoc.iZero;
assert( iLimit>0 );
for(i=0; i<HASHTABLE_NSLOT; i++){
- if( aHash[i]>iLimit ){
- aHash[i] = 0;
+ if( sLoc.aHash[i]>iLimit ){
+ sLoc.aHash[i] = 0;
}
}
-
+
/* Zero the entries in the aPgno array that correspond to frames with
- ** frame numbers greater than pWal->hdr.mxFrame.
+ ** frame numbers greater than pWal->hdr.mxFrame.
*/
- nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
- memset((void *)&aPgno[iLimit+1], 0, nByte);
+ nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]);
+ memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the every entry in the mapping region is still reachable
@@ -54762,10 +60445,10 @@ static void walCleanupHash(Wal *pWal){
int j; /* Loop counter */
int iKey; /* Hash key */
for(j=1; j<=iLimit; j++){
- for(iKey=walHash(aPgno[j]); aHash[iKey]; iKey=walNextHash(iKey)){
- if( aHash[iKey]==j ) break;
+ for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){
+ if( sLoc.aHash[iKey]==j ) break;
}
- assert( aHash[iKey]==j );
+ assert( sLoc.aHash[iKey]==j );
}
}
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@@ -54778,11 +60461,9 @@ static void walCleanupHash(Wal *pWal){
*/
static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
int rc; /* Return code */
- u32 iZero = 0; /* One less than frame number of aPgno[1] */
- volatile u32 *aPgno = 0; /* Page number array */
- volatile ht_slot *aHash = 0; /* Hash table */
+ WalHashLoc sLoc; /* Wal-index hash table location */
- rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+ rc = walHashGet(pWal, walFramePage(iFrame), &sLoc);
/* Assuming the wal-index file was successfully mapped, populate the
** page number array and hash table entry.
@@ -54792,35 +60473,36 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
int idx; /* Value to write to hash-table slot */
int nCollide; /* Number of hash collisions */
- idx = iFrame - iZero;
+ idx = iFrame - sLoc.iZero;
assert( idx <= HASHTABLE_NSLOT/2 + 1 );
-
+
/* If this is the first entry to be added to this hash-table, zero the
- ** entire hash table and aPgno[] array before proceeding.
+ ** entire hash table and aPgno[] array before proceeding.
*/
if( idx==1 ){
- int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
- memset((void*)&aPgno[1], 0, nByte);
+ int nByte = (int)((u8 *)&sLoc.aHash[HASHTABLE_NSLOT]
+ - (u8 *)&sLoc.aPgno[1]);
+ memset((void*)&sLoc.aPgno[1], 0, nByte);
}
/* If the entry in aPgno[] is already set, then the previous writer
** must have exited unexpectedly in the middle of a transaction (after
- ** writing one or more dirty pages to the WAL to free up memory).
- ** Remove the remnants of that writers uncommitted transaction from
+ ** writing one or more dirty pages to the WAL to free up memory).
+ ** Remove the remnants of that writers uncommitted transaction from
** the hash-table before writing any new entries.
*/
- if( aPgno[idx] ){
+ if( sLoc.aPgno[idx] ){
walCleanupHash(pWal);
- assert( !aPgno[idx] );
+ assert( !sLoc.aPgno[idx] );
}
/* Write the aPgno[] array entry and the hash-table slot. */
nCollide = idx;
- for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+ for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
}
- aPgno[idx] = iPage;
- aHash[iKey] = (ht_slot)idx;
+ sLoc.aPgno[idx] = iPage;
+ AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the number of entries in the hash table exactly equals
@@ -54829,7 +60511,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
{
int i; /* Loop counter */
int nEntry = 0; /* Number of entries in the hash table */
- for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
+ for(i=0; i<HASHTABLE_NSLOT; i++){ if( sLoc.aHash[i] ) nEntry++; }
assert( nEntry==idx );
}
@@ -54841,10 +60523,12 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
if( (idx&0x3ff)==0 ){
int i; /* Loop counter */
for(i=1; i<=idx; i++){
- for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
- if( aHash[iKey]==i ) break;
+ for(iKey=walHash(sLoc.aPgno[i]);
+ sLoc.aHash[iKey];
+ iKey=walNextHash(iKey)){
+ if( sLoc.aHash[iKey]==i ) break;
}
- assert( aHash[iKey]==i );
+ assert( sLoc.aHash[iKey]==i );
}
}
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@@ -54856,7 +60540,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
/*
-** Recover the wal-index by reading the write-ahead log file.
+** Recover the wal-index by reading the write-ahead log file.
**
** This routine first tries to establish an exclusive lock on the
** wal-index to prevent other threads/processes from doing anything
@@ -54870,7 +60554,6 @@ static int walIndexRecover(Wal *pWal){
i64 nSize; /* Size of log file */
u32 aFrameCksum[2] = {0, 0};
int iLock; /* Lock offset to lock for checkpoint */
- int nLock; /* Number of locks to hold */
/* Obtain an exclusive lock on all byte in the locking range not already
** locked by the caller. The caller is guaranteed to have locked the
@@ -54883,11 +60566,11 @@ static int walIndexRecover(Wal *pWal){
assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
assert( pWal->writeLock );
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
- nLock = SQLITE_SHM_NLOCK - iLock;
- rc = walLockExclusive(pWal, iLock, nLock);
+ rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
if( rc ){
return rc;
}
+
WALTRACE(("WAL%p: recovery begin...\n", pWal));
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
@@ -54899,15 +60582,16 @@ static int walIndexRecover(Wal *pWal){
if( nSize>WAL_HDRSIZE ){
u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */
u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
int szFrame; /* Number of bytes in buffer aFrame[] */
u8 *aData; /* Pointer to data part of aFrame buffer */
- int iFrame; /* Index of last frame read */
- i64 iOffset; /* Next offset to read from log file */
int szPage; /* Page size according to the log */
u32 magic; /* Magic value read from WAL header */
u32 version; /* Magic value read from WAL header */
int isValid; /* True if this frame is valid */
+ u32 iPg; /* Current 32KB wal-index page */
+ u32 iLastFrame; /* Last frame in wal, based on nSize alone */
/* Read in the WAL header. */
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
@@ -54916,16 +60600,16 @@ static int walIndexRecover(Wal *pWal){
}
/* If the database page size is not a power of two, or is greater than
- ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
+ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
** data. Similarly, if the 'magic' value is invalid, ignore the whole
** WAL file.
*/
magic = sqlite3Get4byte(&aBuf[0]);
szPage = sqlite3Get4byte(&aBuf[8]);
- if( (magic&0xFFFFFFFE)!=WAL_MAGIC
- || szPage&(szPage-1)
- || szPage>SQLITE_MAX_PAGE_SIZE
- || szPage<512
+ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
+ || szPage&(szPage-1)
+ || szPage>SQLITE_MAX_PAGE_SIZE
+ || szPage<512
){
goto finished;
}
@@ -54935,7 +60619,7 @@ static int walIndexRecover(Wal *pWal){
memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
/* Verify that the WAL header checksum is correct */
- walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
+ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
);
if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
@@ -54954,38 +60638,82 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
- aFrame = (u8 *)sqlite3_malloc64(szFrame);
+ aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
}
aData = &aFrame[WAL_FRAME_HDRSIZE];
+ aPrivate = (u32*)&aData[szPage];
/* Read all frames from the log file. */
- iFrame = 0;
- for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
- u32 pgno; /* Database page number for frame */
- u32 nTruncate; /* dbsize field from frame header */
-
- /* Read and decode the next log frame. */
- iFrame++;
- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
- if( rc!=SQLITE_OK ) break;
- isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
- if( !isValid ) break;
- rc = walIndexAppend(pWal, iFrame, pgno);
- if( rc!=SQLITE_OK ) break;
+ iLastFrame = (nSize - WAL_HDRSIZE) / szFrame;
+ for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){
+ u32 *aShare;
+ u32 iFrame; /* Index of last frame read */
+ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
+ u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE);
+ u32 nHdr, nHdr32;
+ rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
+ if( rc ) break;
+ pWal->apWiData[iPg] = aPrivate;
+
+ for(iFrame=iFirst; iFrame<=iLast; iFrame++){
+ i64 iOffset = walFrameOffset(iFrame, szPage);
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
- /* If nTruncate is non-zero, this is a commit record. */
- if( nTruncate ){
- pWal->hdr.mxFrame = iFrame;
- pWal->hdr.nPage = nTruncate;
- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
- testcase( szPage<=32768 );
- testcase( szPage>=65536 );
- aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ /* Read and decode the next log frame. */
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+ if( !isValid ) break;
+ rc = walIndexAppend(pWal, iFrame, pgno);
+ if( NEVER(rc!=SQLITE_OK) ) break;
+
+ /* If nTruncate is non-zero, this is a commit record. */
+ if( nTruncate ){
+ pWal->hdr.mxFrame = iFrame;
+ pWal->hdr.nPage = nTruncate;
+ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+ testcase( szPage<=32768 );
+ testcase( szPage>=65536 );
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ }
+ }
+ pWal->apWiData[iPg] = aShare;
+ nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
+ nHdr32 = nHdr / sizeof(u32);
+#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
+ /* Memcpy() should work fine here, on all reasonable implementations.
+ ** Technically, memcpy() might change the destination to some
+ ** intermediate value before setting to the final value, and that might
+ ** cause a concurrent reader to malfunction. Memcpy() is allowed to
+ ** do that, according to the spec, but no memcpy() implementation that
+ ** we know of actually does that, which is why we say that memcpy()
+ ** is safe for this. Memcpy() is certainly a lot faster.
+ */
+ memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr);
+#else
+ /* In the event that some platform is found for which memcpy()
+ ** changes the destination to some intermediate value before
+ ** setting the final value, this alternative copy routine is
+ ** provided.
+ */
+ {
+ int i;
+ for(i=nHdr32; i<WALINDEX_PGSZ/sizeof(u32); i++){
+ if( aShare[i]!=aPrivate[i] ){
+ /* Atomic memory operations are not required here because if
+ ** the value needs to be changed, that means it is not being
+ ** accessed concurrently. */
+ aShare[i] = aPrivate[i];
+ }
+ }
}
+#endif
+ if( iFrame<=iLast ) break;
}
sqlite3_free(aFrame);
@@ -54999,16 +60727,27 @@ finished:
pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
walIndexWriteHdr(pWal);
- /* Reset the checkpoint-header. This is safe because this thread is
- ** currently holding locks that exclude all other readers, writers and
- ** checkpointers.
+ /* Reset the checkpoint-header. This is safe because this thread is
+ ** currently holding locks that exclude all other writers and
+ ** checkpointers. Then set the values of read-mark slots 1 through N.
*/
pInfo = walCkptInfo(pWal);
pInfo->nBackfill = 0;
pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
pInfo->aReadMark[0] = 0;
- for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
- if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
+ for(i=1; i<WAL_NREADER; i++){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ if( i==1 && pWal->hdr.mxFrame ){
+ pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+ }else{
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
+ }
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc!=SQLITE_BUSY ){
+ goto recovery_error;
+ }
+ }
/* If more than one frame was recovered from the log file, report an
** event via sqlite3_log(). This is to help with identifying performance
@@ -55025,7 +60764,7 @@ finished:
recovery_error:
WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
- walUnlockExclusive(pWal, iLock, nLock);
+ walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
return rc;
}
@@ -55033,19 +60772,20 @@ recovery_error:
** Close an open wal-index.
*/
static void walIndexClose(Wal *pWal, int isDelete){
- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE || pWal->bShmUnreliable ){
int i;
for(i=0; i<pWal->nWiData; i++){
sqlite3_free((void *)pWal->apWiData[i]);
pWal->apWiData[i] = 0;
}
- }else{
+ }
+ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
}
}
-/*
-** Open a connection to the WAL file zWalName. The database file must
+/*
+** Open a connection to the WAL file zWalName. The database file must
** already be opened on connection pDbFd. The buffer that zWalName points
** to must remain valid for the lifetime of the returned Wal* handle.
**
@@ -55055,7 +60795,7 @@ static void walIndexClose(Wal *pWal, int isDelete){
** were to do this just after this client opened one of these files, the
** system would be badly broken.
**
-** If the log file is successfully opened, SQLITE_OK is returned and
+** If the log file is successfully opened, SQLITE_OK is returned and
** *ppWal is set to point to a new WAL handle. If an error occurs,
** an SQLite error code is returned and *ppWal is left unmodified.
*/
@@ -55219,7 +60959,7 @@ static void walMerge(
ht_slot logpage;
Pgno dbpage;
- if( (iLeft<nLeft)
+ if( (iLeft<nLeft)
&& (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
){
logpage = aLeft[iLeft++];
@@ -55317,7 +61057,7 @@ static void walMergesort(
#endif
}
-/*
+/*
** Free an iterator allocated by walIteratorInit().
*/
static void walIteratorFree(WalIterator *p){
@@ -55325,9 +61065,10 @@ static void walIteratorFree(WalIterator *p){
}
/*
-** Construct a WalInterator object that can be used to loop over all
-** pages in the WAL in ascending order. The caller must hold the checkpoint
-** lock.
+** Construct a WalInterator object that can be used to loop over all
+** pages in the WAL following frame nBackfill in ascending order. Frames
+** nBackfill or earlier may be included - excluding them is an optimization
+** only. The caller must hold the checkpoint lock.
**
** On success, make *pp point to the newly allocated WalInterator object
** return SQLITE_OK. Otherwise, return an error code. If this routine
@@ -55336,11 +61077,11 @@ static void walIteratorFree(WalIterator *p){
** The calling routine should invoke walIteratorFree() to destroy the
** WalIterator object when it has finished with it.
*/
-static int walIteratorInit(Wal *pWal, WalIterator **pp){
+static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
WalIterator *p; /* Return value */
int nSegment; /* Number of segments to merge */
u32 iLast; /* Last frame in log */
- int nByte; /* Number of bytes to allocate */
+ sqlite3_int64 nByte; /* Number of bytes to allocate */
int i; /* Iterator variable */
ht_slot *aTmp; /* Temp space used by merge-sort */
int rc = SQLITE_OK; /* Return Code */
@@ -55353,7 +61094,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
/* Allocate space for the WalIterator object. */
nSegment = walFramePage(iLast) + 1;
- nByte = sizeof(WalIterator)
+ nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
p = (WalIterator *)sqlite3_malloc64(nByte);
@@ -55373,45 +61114,127 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
rc = SQLITE_NOMEM_BKPT;
}
- for(i=0; rc==SQLITE_OK && i<nSegment; i++){
- volatile ht_slot *aHash;
- u32 iZero;
- volatile u32 *aPgno;
+ for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
+ WalHashLoc sLoc;
- rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
+ rc = walHashGet(pWal, i, &sLoc);
if( rc==SQLITE_OK ){
int j; /* Counter variable */
int nEntry; /* Number of entries in this segment */
ht_slot *aIndex; /* Sorted index for this segment */
- aPgno++;
+ sLoc.aPgno++;
if( (i+1)==nSegment ){
- nEntry = (int)(iLast - iZero);
+ nEntry = (int)(iLast - sLoc.iZero);
}else{
- nEntry = (int)((u32*)aHash - (u32*)aPgno);
+ nEntry = (int)((u32*)sLoc.aHash - (u32*)sLoc.aPgno);
}
- aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
- iZero++;
-
+ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero];
+ sLoc.iZero++;
+
for(j=0; j<nEntry; j++){
aIndex[j] = (ht_slot)j;
}
- walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
- p->aSegment[i].iZero = iZero;
+ walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry);
+ p->aSegment[i].iZero = sLoc.iZero;
p->aSegment[i].nEntry = nEntry;
p->aSegment[i].aIndex = aIndex;
- p->aSegment[i].aPgno = (u32 *)aPgno;
+ p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
}
}
sqlite3_free(aTmp);
if( rc!=SQLITE_OK ){
walIteratorFree(p);
+ p = 0;
}
*pp = p;
return rc;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+/*
+** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
+** they are supported by the VFS, and (b) the database handle is configured
+** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
+** or 0 otherwise.
+*/
+static int walEnableBlocking(Wal *pWal){
+ int res = 0;
+ if( pWal->db ){
+ int tmout = pWal->db->busyTimeout;
+ if( tmout ){
+ int rc;
+ rc = sqlite3OsFileControl(
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
+ );
+ res = (rc==SQLITE_OK);
+ }
+ }
+ return res;
+}
+
+/*
+** Disable blocking locks.
+*/
+static void walDisableBlocking(Wal *pWal){
+ int tmout = 0;
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
+}
+
+/*
+** If parameter bLock is true, attempt to enable blocking locks, take
+** the WRITER lock, and then disable blocking locks. If blocking locks
+** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
+** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
+** an error if blocking locks can not be enabled.
+**
+** If the bLock parameter is false and the WRITER lock is held, release it.
+*/
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){
+ int rc = SQLITE_OK;
+ assert( pWal->readLock<0 || bLock==0 );
+ if( bLock ){
+ assert( pWal->db );
+ if( walEnableBlocking(pWal) ){
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ pWal->writeLock = 1;
+ }
+ walDisableBlocking(pWal);
+ }
+ }else if( pWal->writeLock ){
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ pWal->writeLock = 0;
+ }
+ return rc;
+}
+
+/*
+** Set the database handle used to determine if blocking locks are required.
+*/
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
+ pWal->db = db;
+}
+
+/*
+** Take an exclusive WRITE lock. Blocking if so configured.
+*/
+static int walLockWriter(Wal *pWal){
+ int rc;
+ walEnableBlocking(pWal);
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+ walDisableBlocking(pWal);
+ return rc;
+}
+#else
+# define walEnableBlocking(x) 0
+# define walDisableBlocking(x)
+# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
+# define sqlite3WalDb(pWal, db)
+#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
+
+
/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
@@ -55429,6 +61252,12 @@ static int walBusyLock(
do {
rc = walLockExclusive(pWal, lockIdx, n);
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ walDisableBlocking(pWal);
+ rc = SQLITE_BUSY;
+ }
+#endif
return rc;
}
@@ -55453,8 +61282,8 @@ static int walPagesize(Wal *pWal){
** client to write to the database (which may be this one) does so by
** writing frames into the start of the log file.
**
-** The value of parameter salt1 is used as the aSalt[1] value in the
-** new wal-index header. It should be passed a pseudo-random value (i.e.
+** The value of parameter salt1 is used as the aSalt[1] value in the
+** new wal-index header. It should be passed a pseudo-random value (i.e.
** one obtained from sqlite3_randomness()).
*/
static void walRestartHdr(Wal *pWal, u32 salt1){
@@ -55466,7 +61295,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
walIndexWriteHdr(pWal);
- pInfo->nBackfill = 0;
+ AtomicStore(&pInfo->nBackfill, 0);
pInfo->nBackfillAttempted = 0;
pInfo->aReadMark[1] = 0;
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
@@ -55482,8 +61311,8 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
** that a concurrent reader might be using.
**
** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
-** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
-** checkpoints are always run by a background thread or background
+** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
+** checkpoints are always run by a background thread or background
** process, foreground threads will never block on a lengthy fsync call.
**
** Fsync is called on the WAL before writing content out of the WAL and
@@ -55496,7 +61325,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
** database file.
**
** This routine uses and updates the nBackfill field of the wal-index header.
-** This is the only routine that will increase the value of nBackfill.
+** This is the only routine that will increase the value of nBackfill.
** (A WAL reset or recovery will revert nBackfill to zero, but not increase
** its value.)
**
@@ -55506,6 +61335,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
*/
static int walCheckpoint(
Wal *pWal, /* Wal connection */
+ sqlite3 *db, /* Check for interrupts on this handle */
int eMode, /* One of PASSIVE, FULL or RESTART */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
@@ -55528,13 +61358,6 @@ static int walCheckpoint(
pInfo = walCkptInfo(pWal);
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
- /* Allocate the iterator */
- rc = walIteratorInit(pWal, &pIter);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pIter );
-
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
@@ -55547,20 +61370,13 @@ static int walCheckpoint(
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
for(i=1; i<WAL_NREADER; i++){
- /* Thread-sanitizer reports that the following is an unsafe read,
- ** as some other thread may be in the process of updating the value
- ** of the aReadMark[] slot. The assumption here is that if that is
- ** happening, the other client may only be increasing the value,
- ** not decreasing it. So assuming either that either the "old" or
- ** "new" version of the value is read, and not some arbitrary value
- ** that would never be written by a real client, things are still
- ** safe. */
- u32 y = pInfo->aReadMark[i];
+ u32 y = AtomicLoad(pInfo->aReadMark+i);
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ AtomicStore(pInfo->aReadMark+i, iMark);
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc==SQLITE_BUSY ){
mxSafeFrame = y;
@@ -55571,35 +61387,52 @@ static int walCheckpoint(
}
}
- if( pInfo->nBackfill<mxSafeFrame
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
+ /* Allocate the iterator */
+ if( pInfo->nBackfill<mxSafeFrame ){
+ rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter);
+ assert( rc==SQLITE_OK || pIter==0 );
+ }
+
+ if( pIter
+ && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
){
- i64 nSize; /* Current size of database file */
u32 nBackfill = pInfo->nBackfill;
pInfo->nBackfillAttempted = mxSafeFrame;
/* Sync the WAL to disk */
- if( sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
- }
+ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
/* If the database may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer.
*/
if( rc==SQLITE_OK ){
i64 nReq = ((i64)mxPage * szPage);
+ i64 nSize; /* Current size of database file */
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
if( rc==SQLITE_OK && nSize<nReq ){
- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+ if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)<nReq ){
+ /* If the size of the final database is larger than the current
+ ** database plus the amount of data in the wal file, plus the
+ ** maximum size of the pending-byte page (65536 bytes), then
+ ** must be corruption somewhere. */
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
+ }
}
- }
+ }
/* Iterate through the contents of the WAL, copying data to the db file */
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( AtomicLoad(&db->u1.isInterrupted) ){
+ rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
+ break;
+ }
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
continue;
}
@@ -55612,6 +61445,7 @@ static int walCheckpoint(
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
if( rc!=SQLITE_OK ) break;
}
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
/* If work was actually accomplished... */
if( rc==SQLITE_OK ){
@@ -55619,12 +61453,12 @@ static int walCheckpoint(
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
- if( rc==SQLITE_OK && sync_flags ){
- rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags));
}
}
if( rc==SQLITE_OK ){
- pInfo->nBackfill = mxSafeFrame;
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame);
}
}
@@ -55640,8 +61474,8 @@ static int walCheckpoint(
}
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
- ** entire wal file has been copied into the database file, then block
- ** until all readers have finished using the wal file. This ensures that
+ ** entire wal file has been copied into the database file, then block
+ ** until all readers have finished using the wal file. This ensures that
** the next process to write to the database restarts the wal file.
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
@@ -55665,7 +61499,7 @@ static int walCheckpoint(
** writer clients should see that the entire log file has been
** checkpointed and behave accordingly. This seems unsafe though,
** as it would leave the system in a state where the contents of
- ** the wal-index header do not match the contents of the
+ ** the wal-index header do not match the contents of the
** file-system. To avoid this, update the wal-index header to
** indicate that the log file contains zero valid frames. */
walRestartHdr(pWal, salt1);
@@ -55704,6 +61538,7 @@ static void walLimitSize(Wal *pWal, i64 nMax){
*/
SQLITE_PRIVATE int sqlite3WalClose(
Wal *pWal, /* Wal to close */
+ sqlite3 *db, /* For interrupt flag */
int sync_flags, /* Flags to pass to OsSync() (or 0) */
int nBuf,
u8 *zBuf /* Buffer of at least nBuf bytes */
@@ -55720,13 +61555,14 @@ SQLITE_PRIVATE int sqlite3WalClose(
**
** The EXCLUSIVE lock is not released before returning.
*/
- rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
- if( rc==SQLITE_OK ){
+ if( zBuf!=0
+ && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE))
+ ){
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
- rc = sqlite3WalCheckpoint(
- pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+ rc = sqlite3WalCheckpoint(pWal, db,
+ SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
);
if( rc==SQLITE_OK ){
int bPersist = -1;
@@ -55781,7 +61617,7 @@ SQLITE_PRIVATE int sqlite3WalClose(
** If the checksum cannot be verified return non-zero. If the header
** is read successfully and the checksum verified, return zero.
*/
-static int walIndexTryHdr(Wal *pWal, int *pChanged){
+static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
u32 aCksum[2]; /* Checksum on the header content */
WalIndexHdr h1, h2; /* Two copies of the header content */
WalIndexHdr volatile *aHdr; /* Header in shared memory */
@@ -55794,19 +61630,25 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
** meaning it is possible that an inconsistent snapshot is read
** from the file. If this happens, return non-zero.
**
+ ** tag-20200519-1:
** There are two copies of the header at the beginning of the wal-index.
** When reading, read [0] first then [1]. Writes are in the reverse order.
** Memory barriers are used to prevent the compiler or the hardware from
- ** reordering the reads and writes.
+ ** reordering the reads and writes. TSAN and similar tools can sometimes
+ ** give false-positive warnings about these accesses because the tools do not
+ ** account for the double-read and the memory barrier. The use of mutexes
+ ** here would be problematic as the memory being accessed is potentially
+ ** shared among multiple processes and not all mutex implementions work
+ ** reliably in that environment.
*/
aHdr = walIndexHdr(pWal);
- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */
walShmBarrier(pWal);
memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
return 1; /* Dirty read */
- }
+ }
if( h1.isInit==0 ){
return 1; /* Malformed header - probably all zeros */
}
@@ -55828,6 +61670,12 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
}
/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
+*/
+#define WAL_RETRY (-1)
+
+/*
** Read the wal-index header from the wal-index and into pWal->hdr.
** If the wal-header appears to be corrupt, try to reconstruct the
** wal-index from the WAL before returning.
@@ -55836,7 +61684,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
** changed by this operation. If pWal->hdr is unchanged, set *pChanged
** to 0.
**
-** If the wal-index header is successfully read, return SQLITE_OK.
+** If the wal-index header is successfully read, return SQLITE_OK.
** Otherwise an SQLite error code.
*/
static int walIndexReadHdr(Wal *pWal, int *pChanged){
@@ -55844,19 +61692,39 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
int badHdr; /* True if a header read failed */
volatile u32 *page0; /* Chunk of wal-index containing header */
- /* Ensure that page 0 of the wal-index (the page that contains the
+ /* Ensure that page 0 of the wal-index (the page that contains the
** wal-index header) is mapped. Return early if an error occurs here.
*/
assert( pChanged );
rc = walIndexPage(pWal, 0, &page0);
if( rc!=SQLITE_OK ){
- return rc;
- };
- assert( page0 || pWal->writeLock==0 );
+ assert( rc!=SQLITE_READONLY ); /* READONLY changed to OK in walIndexPage */
+ if( rc==SQLITE_READONLY_CANTINIT ){
+ /* The SQLITE_READONLY_CANTINIT return means that the shared-memory
+ ** was openable but is not writable, and this thread is unable to
+ ** confirm that another write-capable connection has the shared-memory
+ ** open, and hence the content of the shared-memory is unreliable,
+ ** since the shared-memory might be inconsistent with the WAL file
+ ** and there is no writer on hand to fix it. */
+ assert( page0==0 );
+ assert( pWal->writeLock==0 );
+ assert( pWal->readOnly & WAL_SHM_RDONLY );
+ pWal->bShmUnreliable = 1;
+ pWal->exclusiveMode = WAL_HEAPMEMORY_MODE;
+ *pChanged = 1;
+ }else{
+ return rc; /* Any other non-OK return is just an error */
+ }
+ }else{
+ /* page0 can be NULL if the SHM is zero bytes in size and pWal->writeLock
+ ** is zero, which prevents the SHM from growing */
+ testcase( page0!=0 );
+ }
+ assert( page0!=0 || pWal->writeLock==0 );
/* If the first page of the wal-index has been mapped, try to read the
** wal-index header immediately, without holding any lock. This usually
- ** works, but may fail if the wal-index header is corrupt or currently
+ ** works, but may fail if the wal-index header is corrupt or currently
** being modified by another thread or process.
*/
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
@@ -55864,28 +61732,32 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
/* If the first attempt failed, it might have been due to a race
** with a writer. So get a WRITE lock and try again.
*/
- assert( badHdr==0 || pWal->writeLock==0 );
if( badHdr ){
- if( pWal->readOnly & WAL_SHM_RDONLY ){
+ if( pWal->bShmUnreliable==0 && (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;
+ }else{
+ int bWriteLock = pWal->writeLock;
+ if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
+ 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( bWriteLock==0 ){
+ pWal->writeLock = 0;
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
}
}
- pWal->writeLock = 0;
- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
}
}
@@ -55896,15 +61768,193 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
rc = SQLITE_CANTOPEN_BKPT;
}
+ if( pWal->bShmUnreliable ){
+ if( rc!=SQLITE_OK ){
+ walIndexClose(pWal, 0);
+ pWal->bShmUnreliable = 0;
+ assert( pWal->nWiData>0 && pWal->apWiData[0]==0 );
+ /* walIndexRecover() might have returned SHORT_READ if a concurrent
+ ** writer truncated the WAL out from under it. If that happens, it
+ ** indicates that a writer has fixed the SHM file for us, so retry */
+ if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
+ }
+ pWal->exclusiveMode = WAL_NORMAL_MODE;
+ }
return rc;
}
/*
-** This is the value that walTryBeginRead returns when it needs to
-** be retried.
+** Open a transaction in a connection where the shared-memory is read-only
+** and where we cannot verify that there is a separate write-capable connection
+** on hand to keep the shared-memory up-to-date with the WAL file.
+**
+** This can happen, for example, when the shared-memory is implemented by
+** memory-mapping a *-shm file, where a prior writer has shut down and
+** left the *-shm file on disk, and now the present connection is trying
+** to use that database but lacks write permission on the *-shm file.
+** Other scenarios are also possible, depending on the VFS implementation.
+**
+** Precondition:
+**
+** The *-wal file has been read and an appropriate wal-index has been
+** constructed in pWal->apWiData[] using heap memory instead of shared
+** memory.
+**
+** If this function returns SQLITE_OK, then the read transaction has
+** been successfully opened. In this case output variable (*pChanged)
+** is set to true before returning if the caller should discard the
+** contents of the page cache before proceeding. Or, if it returns
+** WAL_RETRY, then the heap memory wal-index has been discarded and
+** the caller should retry opening the read transaction from the
+** beginning (including attempting to map the *-shm file).
+**
+** If an error occurs, an SQLite error code is returned.
*/
-#define WAL_RETRY (-1)
+static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
+ i64 szWal; /* Size of wal file on disk in bytes */
+ i64 iOffset; /* Current offset when reading wal file */
+ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
+ int szFrame; /* Number of bytes in buffer aFrame[] */
+ u8 *aData; /* Pointer to data part of aFrame buffer */
+ volatile void *pDummy; /* Dummy argument for xShmMap */
+ int rc; /* Return code */
+ u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */
+
+ assert( pWal->bShmUnreliable );
+ assert( pWal->readOnly & WAL_SHM_RDONLY );
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+
+ /* Take WAL_READ_LOCK(0). This has the effect of preventing any
+ ** writers from running a checkpoint, but does not stop them
+ ** from running recovery. */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_BUSY ) rc = WAL_RETRY;
+ goto begin_unreliable_shm_out;
+ }
+ pWal->readLock = 0;
+
+ /* Check to see if a separate writer has attached to the shared-memory area,
+ ** thus making the shared-memory "reliable" again. Do this by invoking
+ ** the xShmMap() routine of the VFS and looking to see if the return
+ ** is SQLITE_READONLY instead of SQLITE_READONLY_CANTINIT.
+ **
+ ** If the shared-memory is now "reliable" return WAL_RETRY, which will
+ ** cause the heap-memory WAL-index to be discarded and the actual
+ ** shared memory to be used in its place.
+ **
+ ** This step is important because, even though this connection is holding
+ ** the WAL_READ_LOCK(0) which prevents a checkpoint, a writer might
+ ** have already checkpointed the WAL file and, while the current
+ ** is active, wrap the WAL and start overwriting frames that this
+ ** process wants to use.
+ **
+ ** Once sqlite3OsShmMap() has been called for an sqlite3_file and has
+ ** returned any SQLITE_READONLY value, it must return only SQLITE_READONLY
+ ** or SQLITE_READONLY_CANTINIT or some error for all subsequent invocations,
+ ** even if some external agent does a "chmod" to make the shared-memory
+ ** writable by us, until sqlite3OsShmUnmap() has been called.
+ ** This is a requirement on the VFS implementation.
+ */
+ rc = sqlite3OsShmMap(pWal->pDbFd, 0, WALINDEX_PGSZ, 0, &pDummy);
+ assert( rc!=SQLITE_OK ); /* SQLITE_OK not possible for read-only connection */
+ if( rc!=SQLITE_READONLY_CANTINIT ){
+ rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc);
+ goto begin_unreliable_shm_out;
+ }
+
+ /* We reach this point only if the real shared-memory is still unreliable.
+ ** Assume the in-memory WAL-index substitute is correct and load it
+ ** into pWal->hdr.
+ */
+ memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
+ /* Make sure some writer hasn't come in and changed the WAL file out
+ ** from under us, then disconnected, while we were not looking.
+ */
+ rc = sqlite3OsFileSize(pWal->pWalFd, &szWal);
+ if( rc!=SQLITE_OK ){
+ goto begin_unreliable_shm_out;
+ }
+ if( szWal<WAL_HDRSIZE ){
+ /* If the wal file is too small to contain a wal-header and the
+ ** wal-index header has mxFrame==0, then it must be safe to proceed
+ ** reading the database file only. However, the page cache cannot
+ ** be trusted, as a read/write connection may have connected, written
+ ** the db, run a checkpoint, truncated the wal file and disconnected
+ ** since this client's last read transaction. */
+ *pChanged = 1;
+ rc = (pWal->hdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY);
+ goto begin_unreliable_shm_out;
+ }
+
+ /* Check the salt keys at the start of the wal file still match. */
+ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
+ if( rc!=SQLITE_OK ){
+ goto begin_unreliable_shm_out;
+ }
+ if( memcmp(&pWal->hdr.aSalt, &aBuf[16], 8) ){
+ /* Some writer has wrapped the WAL file while we were not looking.
+ ** Return WAL_RETRY which will cause the in-memory WAL-index to be
+ ** rebuilt. */
+ rc = WAL_RETRY;
+ goto begin_unreliable_shm_out;
+ }
+
+ /* Allocate a buffer to read frames into */
+ szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE;
+ aFrame = (u8 *)sqlite3_malloc64(szFrame);
+ if( aFrame==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto begin_unreliable_shm_out;
+ }
+ aData = &aFrame[WAL_FRAME_HDRSIZE];
+
+ /* Check to see if a complete transaction has been appended to the
+ ** wal file since the heap-memory wal-index was created. If so, the
+ ** heap-memory wal-index is discarded and WAL_RETRY returned to
+ ** the caller. */
+ aSaveCksum[0] = pWal->hdr.aFrameCksum[0];
+ aSaveCksum[1] = pWal->hdr.aFrameCksum[1];
+ for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage);
+ iOffset+szFrame<=szWal;
+ iOffset+=szFrame
+ ){
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
+
+ /* Read and decode the next log frame. */
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break;
+
+ /* If nTruncate is non-zero, then a complete transaction has been
+ ** appended to this wal file. Set rc to WAL_RETRY and break out of
+ ** the loop. */
+ if( nTruncate ){
+ rc = WAL_RETRY;
+ break;
+ }
+ }
+ pWal->hdr.aFrameCksum[0] = aSaveCksum[0];
+ pWal->hdr.aFrameCksum[1] = aSaveCksum[1];
+
+ begin_unreliable_shm_out:
+ sqlite3_free(aFrame);
+ if( rc!=SQLITE_OK ){
+ int i;
+ for(i=0; i<pWal->nWiData; i++){
+ sqlite3_free((void*)pWal->apWiData[i]);
+ pWal->apWiData[i] = 0;
+ }
+ pWal->bShmUnreliable = 0;
+ sqlite3WalEndReadTransaction(pWal);
+ *pChanged = 1;
+ }
+ return rc;
+}
/*
** Attempt to start a read transaction. This might fail due to a race or
@@ -55917,10 +61967,10 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
**
** The useWal parameter is true to force the use of the WAL and disable
** the case where the WAL is bypassed because it has been completely
-** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
-** to make a copy of the wal-index header into pWal->hdr. If the
-** wal-index header has changed, *pChanged is set to 1 (as an indication
-** to the caller that the local paget cache is obsolete and needs to be
+** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
+** to make a copy of the wal-index header into pWal->hdr. If the
+** wal-index header has changed, *pChanged is set to 1 (as an indication
+** to the caller that the local page cache is obsolete and needs to be
** flushed.) When useWal==1, the wal-index header is assumed to already
** be loaded and the pChanged parameter is unused.
**
@@ -55935,7 +61985,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
** bad luck when there is lots of contention for the wal-index, but that
** possibility is so small that it can be safely neglected, we believe.
**
-** On success, this routine obtains a read lock on
+** On success, this routine obtains a read lock on
** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
** that means the Wal does not hold any read lock. The reader must not
@@ -55966,20 +62016,23 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->readLock<0 ); /* Not currently locked */
+ /* useWal may only be set for read/write connections */
+ assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 );
+
/* Take steps to avoid spinning forever if there is a protocol error.
**
** Circumstances that cause a RETRY should only last for the briefest
** instances of time. No I/O or other system calls are done while the
- ** locks are held, so the locks should not be held for very long. But
+ ** locks are held, so the locks should not be held for very long. But
** if we are unlucky, another process that is holding a lock might get
- ** paged out or take a page-fault that is time-consuming to resolve,
+ ** paged out or take a page-fault that is time-consuming to resolve,
** during the few nanoseconds that it is holding the lock. In that case,
** it might take longer than normal for the lock to free.
**
** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
** is more of a scheduler yield than an actual delay. But on the 10th
- ** an subsequent retries, the delays start becoming longer and longer,
+ ** an subsequent retries, the delays start becoming longer and longer,
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
** The total delay time before giving up is less than 10 seconds.
*/
@@ -55994,7 +62047,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
if( !useWal ){
- rc = walIndexReadHdr(pWal, pChanged);
+ assert( rc==SQLITE_OK );
+ if( pWal->bShmUnreliable==0 ){
+ rc = walIndexReadHdr(pWal, pChanged);
+ }
if( rc==SQLITE_BUSY ){
/* If there is not a recovery running in another thread or process
** then convert BUSY errors to WAL_RETRY. If recovery is known to
@@ -56007,9 +62063,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
if( pWal->apWiData[0]==0 ){
/* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
** We assume this is a transient condition, so return WAL_RETRY. The
- ** xShmMap() implementation used by the default unix and win32 VFS
- ** modules may return SQLITE_BUSY due to a race condition in the
- ** code that determines whether or not the shared-memory region
+ ** xShmMap() implementation used by the default unix and win32 VFS
+ ** modules may return SQLITE_BUSY due to a race condition in the
+ ** code that determines whether or not the shared-memory region
** must be zeroed before the requested page is returned.
*/
rc = WAL_RETRY;
@@ -56023,13 +62079,17 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
if( rc!=SQLITE_OK ){
return rc;
}
+ else if( pWal->bShmUnreliable ){
+ return walBeginShmUnreliable(pWal, pChanged);
+ }
}
+ assert( pWal->nWiData>0 );
+ assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
+ if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0
- || 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr)))
+ && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
#endif
){
/* The WAL has been completely backfilled (or it is empty).
@@ -56046,7 +62106,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
** happening, this is usually correct.
**
- ** However, if frames have been appended to the log (or if the log
+ ** However, if frames have been appended to the log (or if the log
** is wrapped and written for that matter) before the READ_LOCK(0)
** is obtained, that is not necessarily true. A checkpointer may
** have started to backfill the appended frames but crashed before
@@ -56076,7 +62136,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
#endif
for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = pInfo->aReadMark[i];
+ u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
if( mxReadMark<=thisMark && thisMark<=mxFrame ){
assert( thisMark!=READMARK_NOT_USED );
mxReadMark = thisMark;
@@ -56089,7 +62149,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
for(i=1; i<WAL_NREADER; i++){
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
- mxReadMark = pInfo->aReadMark[i] = mxFrame;
+ AtomicStore(pInfo->aReadMark+i,mxFrame);
+ mxReadMark = mxFrame;
mxI = i;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
break;
@@ -56100,7 +62161,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
if( mxI==0 ){
assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
- return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
+ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
}
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
@@ -56127,9 +62188,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** to read any frames earlier than minFrame from the wal file - they
** can be safely read directly from the database file.
**
- ** Because a ShmBarrier() call is made between taking the copy of
+ ** Because a ShmBarrier() call is made between taking the copy of
** nBackfill and checking that the wal-header in shared-memory still
- ** matches the one cached in pWal->hdr, it is guaranteed that the
+ ** matches the one cached in pWal->hdr, it is guaranteed that the
** checkpointer that set nBackfill was not working with a wal-index
** header newer than that cached in pWal->hdr. If it were, that could
** cause a problem. The checkpointer could omit to checkpoint
@@ -56141,9 +62202,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** we can guarantee that the checkpointer that set nBackfill could not
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
*/
- pWal->minFrame = pInfo->nBackfill+1;
+ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
walShmBarrier(pWal);
- if( pInfo->aReadMark[mxI]!=mxReadMark
+ if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
){
walUnlockShared(pWal, WAL_READ_LOCK(mxI));
@@ -56155,6 +62216,82 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return rc;
}
+#ifdef SQLITE_ENABLE_SNAPSHOT
+/*
+** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
+** variable so that older snapshots can be accessed. To do this, loop
+** through all wal frames from nBackfillAttempted to (nBackfill+1),
+** comparing their content to the corresponding page with the database
+** file, if any. Set nBackfillAttempted to the frame number of the
+** first frame for which the wal file content matches the db file.
+**
+** This is only really safe if the file-system is such that any page
+** writes made by earlier checkpointers were atomic operations, which
+** is not always true. It is also possible that nBackfillAttempted
+** may be left set to a value larger than expected, if a wal frame
+** contains content that duplicate of an earlier version of the same
+** page.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code if an
+** error occurs. It is not an error if nBackfillAttempted cannot be
+** decreased at all.
+*/
+SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
+ int rc;
+
+ assert( pWal->readLock>=0 );
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ int szPage = (int)pWal->szPage;
+ i64 szDb; /* Size of db file in bytes */
+
+ rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
+ if( rc==SQLITE_OK ){
+ void *pBuf1 = sqlite3_malloc(szPage);
+ void *pBuf2 = sqlite3_malloc(szPage);
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
+ WalHashLoc sLoc; /* Hash table location */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+
+ rc = walHashGet(pWal, walFramePage(i), &sLoc);
+ if( rc!=SQLITE_OK ) break;
+ pgno = sLoc.aPgno[i-sLoc.iZero];
+ iDbOff = (i64)(pgno-1) * szPage;
+
+ if( iDbOff+szPage<=szDb ){
+ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
+ }
+
+ if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
+ break;
+ }
+ }
+
+ pInfo->nBackfillAttempted = i-1;
+ }
+ }
+
+ sqlite3_free(pBuf1);
+ sqlite3_free(pBuf2);
+ }
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ }
+
+ return rc;
+}
+#endif /* SQLITE_ENABLE_SNAPSHOT */
+
/*
** Begin a read transaction on the database.
**
@@ -56166,18 +62303,41 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
**
** If the database contents have changes since the previous read
** transaction, then *pChanged is set to 1 before returning. The
-** Pager layer will use this to know that is cache is stale and
+** Pager layer will use this to know that its cache is stale and
** needs to be flushed.
*/
SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
-
#ifdef SQLITE_ENABLE_SNAPSHOT
int bChanged = 0;
WalIndexHdr *pSnapshot = pWal->pSnapshot;
- if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
- bChanged = 1;
+#endif
+
+ assert( pWal->ckptLock==0 );
+
+#ifdef SQLITE_ENABLE_SNAPSHOT
+ if( pSnapshot ){
+ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
+ bChanged = 1;
+ }
+
+ /* It is possible that there is a checkpointer thread running
+ ** concurrent with this code. If this is the case, it may be that the
+ ** checkpointer has already determined that it will checkpoint
+ ** snapshot X, where X is later in the wal file than pSnapshot, but
+ ** has not yet set the pInfo->nBackfillAttempted variable to indicate
+ ** its intent. To avoid the race condition this leads to, ensure that
+ ** there is no checkpointer process by taking a shared CKPT lock
+ ** before checking pInfo->nBackfillAttempted. */
+ (void)walEnableBlocking(pWal);
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ walDisableBlocking(pWal);
+
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ pWal->ckptLock = 1;
}
#endif
@@ -56210,43 +62370,42 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
- /* It is possible that there is a checkpointer thread running
- ** concurrent with this code. If this is the case, it may be that the
- ** checkpointer has already determined that it will checkpoint
- ** snapshot X, where X is later in the wal file than pSnapshot, but
- ** has not yet set the pInfo->nBackfillAttempted variable to indicate
- ** its intent. To avoid the race condition this leads to, ensure that
- ** there is no checkpointer process by taking a shared CKPT lock
- ** before checking pInfo->nBackfillAttempted. */
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
-
- if( rc==SQLITE_OK ){
- /* Check that the wal file has not been wrapped. Assuming that it has
- ** not, also check that no checkpointer has attempted to checkpoint any
- ** frames beyond pSnapshot->mxFrame. If either of these conditions are
- ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr
- ** with *pSnapshot and set *pChanged as appropriate for opening the
- ** snapshot. */
- if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
- ){
- assert( pWal->readLock>0 );
- memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
- *pChanged = bChanged;
- }else{
- rc = SQLITE_BUSY_SNAPSHOT;
- }
-
- /* Release the shared CKPT lock obtained above. */
- walUnlockShared(pWal, WAL_CKPT_LOCK);
+ /* Check that the wal file has not been wrapped. Assuming that it has
+ ** not, also check that no checkpointer has attempted to checkpoint any
+ ** frames beyond pSnapshot->mxFrame. If either of these conditions are
+ ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
+ ** with *pSnapshot and set *pChanged as appropriate for opening the
+ ** snapshot. */
+ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
+ ){
+ assert( pWal->readLock>0 );
+ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
+ *pChanged = bChanged;
+ }else{
+ rc = SQLITE_ERROR_SNAPSHOT;
}
+ /* A client using a non-current snapshot may not ignore any frames
+ ** from the start of the wal file. This is because, for a system
+ ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
+ ** have omitted to checkpoint a frame earlier than minFrame in
+ ** the file because there exists a frame after iSnapshot that
+ ** is the same database page. */
+ pWal->minFrame = 1;
if( rc!=SQLITE_OK ){
sqlite3WalEndReadTransaction(pWal);
}
}
}
+
+ /* Release the shared CKPT lock obtained above. */
+ if( pWal->ckptLock ){
+ assert( pSnapshot );
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ pWal->ckptLock = 0;
+ }
#endif
return rc;
}
@@ -56286,11 +62445,11 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
/* If the "last page" field of the wal-index header snapshot is 0, then
** no data will be read from the wal under any circumstances. Return early
- ** in this case as an optimization. Likewise, if pWal->readLock==0,
- ** then the WAL is ignored by the reader so return early, as if the
+ ** in this case as an optimization. Likewise, if pWal->readLock==0,
+ ** then the WAL is ignored by the reader so return early, as if the
** WAL were empty.
*/
- if( iLast==0 || pWal->readLock==0 ){
+ if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){
*piRead = 0;
return SQLITE_OK;
}
@@ -56300,9 +62459,9 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
**
** This code might run concurrently to the code in walIndexAppend()
- ** that adds entries to the wal-index (and possibly to this hash
- ** table). This means the value just read from the hash
- ** slot (aHash[iKey]) may have been added before or after the
+ ** that adds entries to the wal-index (and possibly to this hash
+ ** table). This means the value just read from the hash
+ ** slot (aHash[iKey]) may have been added before or after the
** current read transaction was opened. Values added after the
** read transaction was opened may have been written incorrectly -
** i.e. these slots may contain garbage data. However, we assume
@@ -56310,40 +62469,42 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
** opened remain unmodified.
**
** For the reasons above, the if(...) condition featured in the inner
- ** loop of the following block is more stringent that would be required
+ ** loop of the following block is more stringent that would be required
** if we had exclusive access to the hash-table:
**
- ** (aPgno[iFrame]==pgno):
+ ** (aPgno[iFrame]==pgno):
** This condition filters out normal hash-table collisions.
**
- ** (iFrame<=iLast):
+ ** (iFrame<=iLast):
** This condition filters out entries that were added to the hash
** table after the current read-transaction had started.
*/
iMinHash = walFramePage(pWal->minFrame);
- for(iHash=walFramePage(iLast); iHash>=iMinHash && iRead==0; iHash--){
- volatile ht_slot *aHash; /* Pointer to hash table */
- volatile u32 *aPgno; /* Pointer to array of page numbers */
- u32 iZero; /* Frame number corresponding to aPgno[0] */
+ for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){
+ WalHashLoc sLoc; /* Hash table location */
int iKey; /* Hash slot index */
int nCollide; /* Number of hash collisions remaining */
int rc; /* Error code */
+ u32 iH;
- rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+ rc = walHashGet(pWal, iHash, &sLoc);
if( rc!=SQLITE_OK ){
return rc;
}
nCollide = HASHTABLE_NSLOT;
- for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
- u32 iFrame = aHash[iKey] + iZero;
- if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){
+ iKey = walHash(pgno);
+ while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
+ u32 iFrame = iH + sLoc.iZero;
+ if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){
assert( iFrame>iRead || CORRUPT_DB );
iRead = iFrame;
}
if( (nCollide--)==0 ){
return SQLITE_CORRUPT_BKPT;
}
+ iKey = walNextHash(iKey);
}
+ if( iRead ) break;
}
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
@@ -56353,8 +62514,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
{
u32 iRead2 = 0;
u32 iTest;
- assert( pWal->minFrame>0 );
- for(iTest=iLast; iTest>=pWal->minFrame; iTest--){
+ assert( pWal->bShmUnreliable || pWal->minFrame>0 );
+ for(iTest=iLast; iTest>=pWal->minFrame && iTest>0; iTest--){
if( walFramePgno(pWal, iTest)==pgno ){
iRead2 = iTest;
break;
@@ -56390,7 +62551,7 @@ SQLITE_PRIVATE int sqlite3WalReadFrame(
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
-/*
+/*
** Return the size of the database in pages (or zero, if unknown).
*/
SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
@@ -56401,7 +62562,7 @@ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
}
-/*
+/*
** This function starts a write transaction on the WAL.
**
** A read transaction must have already been started by a prior call
@@ -56417,6 +62578,16 @@ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
int rc;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* If the write-lock is already held, then it was obtained before the
+ ** read-transaction was even opened, making this call a no-op.
+ ** Return early. */
+ if( pWal->writeLock ){
+ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
+ return SQLITE_OK;
+ }
+#endif
+
/* Cannot start a write transaction without first holding a read
** transaction. */
assert( pWal->readLock>=0 );
@@ -56479,18 +62650,18 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
if( ALWAYS(pWal->writeLock) ){
Pgno iMax = pWal->hdr.mxFrame;
Pgno iFrame;
-
+
/* Restore the clients cache of the wal-index header to the state it
- ** was in before the client began writing to the database.
+ ** was in before the client began writing to the database.
*/
memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
- for(iFrame=pWal->hdr.mxFrame+1;
- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+ for(iFrame=pWal->hdr.mxFrame+1;
+ ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
iFrame++
){
/* This call cannot fail. Unless the page for which the page number
- ** is passed as the second argument is (a) in the cache and
+ ** is passed as the second argument is (a) in the cache and
** (b) has an outstanding reference, then xUndo is either a no-op
** (if (a) is false) or simply expels the page from the cache (if (b)
** is false).
@@ -56508,10 +62679,10 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
return rc;
}
-/*
-** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
-** values. This function populates the array with values required to
-** "rollback" the write position of the WAL handle back to the current
+/*
+** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
+** values. This function populates the array with values required to
+** "rollback" the write position of the WAL handle back to the current
** point in the event of a savepoint rollback (via WalSavepointUndo()).
*/
SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
@@ -56522,7 +62693,7 @@ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
aWalData[3] = pWal->nCkpt;
}
-/*
+/*
** Move the write position of the WAL back to the point identified by
** the values in the aWalData[] array. aWalData must point to an array
** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
@@ -56642,8 +62813,8 @@ static int walWriteToLog(
iOffset += iFirstAmt;
iAmt -= iFirstAmt;
pContent = (void*)(iFirstAmt + (char*)pContent);
- assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
- rc = sqlite3OsSync(p->pFd, p->syncFlags & SQLITE_SYNC_MASK);
+ assert( WAL_SYNC_FLAGS(p->syncFlags)!=0 );
+ rc = sqlite3OsSync(p->pFd, WAL_SYNC_FLAGS(p->syncFlags));
if( iAmt==0 || rc ) return rc;
}
rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
@@ -56662,11 +62833,7 @@ static int walWriteOneFrame(
int rc; /* Result code from subfunctions */
void *pData; /* Data actually written */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
-#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
-#else
pData = pPage->pData;
-#endif
walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
if( rc ) return rc;
@@ -56728,7 +62895,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
return rc;
}
-/*
+/*
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
*/
@@ -56795,7 +62962,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
-
+
pWal->szPage = szPage;
pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
pWal->hdr.aFrameCksum[0] = aCksum[0];
@@ -56813,10 +62980,10 @@ SQLITE_PRIVATE int sqlite3WalFrames(
** an out-of-order write following a WAL restart could result in
** database corruption. See the ticket:
**
- ** http://localhost:591/sqlite/info/ff5be73dee
+ ** https://sqlite.org/src/info/ff5be73dee
*/
- if( pWal->syncHeader && sync_flags ){
- rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+ if( pWal->syncHeader ){
+ rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
if( rc ) return rc;
}
}
@@ -56837,7 +63004,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
/* Check if this page has already been written into the wal file by
** the current transaction. If so, overwrite the existing frame and
- ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
+ ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
** checksums must be recomputed when the transaction is committed. */
if( iFirst && (p->pDirty || isCommit==0) ){
u32 iWrite = 0;
@@ -56849,11 +63016,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
pWal->iReCksum = iWrite;
}
-#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
-#else
pData = p->pData;
-#endif
rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
if( rc ) return rc;
p->flags &= ~PGHDR_WAL_APPEND;
@@ -56891,7 +63054,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
** sector boundary is synced; the part of the last frame that extends
** past the sector boundary is written after the sync.
*/
- if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+ if( isCommit && WAL_SYNC_FLAGS(sync_flags)!=0 ){
int bSync = 1;
if( pWal->padToSectorBoundary ){
int sectorSize = sqlite3SectorSize(pWal->pWalFd);
@@ -56903,11 +63066,12 @@ SQLITE_PRIVATE int sqlite3WalFrames(
if( rc ) return rc;
iOffset += szFrame;
nExtra++;
+ assert( pLast!=0 );
}
}
if( bSync ){
assert( rc==SQLITE_OK );
- rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
+ rc = sqlite3OsSync(w.pFd, WAL_SYNC_FLAGS(sync_flags));
}
}
@@ -56924,7 +63088,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
pWal->truncateOnCommit = 0;
}
- /* Append data to the wal-index. It is not necessary to lock the
+ /* Append data to the wal-index. It is not necessary to lock the
** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
** guarantees that there are no other writers, and no data that may
** be in use by existing readers is being overwritten.
@@ -56935,6 +63099,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
iFrame++;
rc = walIndexAppend(pWal, iFrame, p->pgno);
}
+ assert( pLast!=0 || nExtra==0 );
while( rc==SQLITE_OK && nExtra>0 ){
iFrame++;
nExtra--;
@@ -56962,7 +63127,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
return rc;
}
-/*
+/*
** This routine is called to implement sqlite3_wal_checkpoint() and
** related interfaces.
**
@@ -56974,6 +63139,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
*/
SQLITE_PRIVATE int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */
+ sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
@@ -56998,45 +63164,52 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
- /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
- ** "checkpoint" lock on the database file. */
- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
- if( rc ){
- /* EVIDENCE-OF: R-10421-19736 If any other process is running a
- ** checkpoint operation at the same time, the lock cannot be obtained and
- ** SQLITE_BUSY is returned.
- ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
- ** it will not be invoked in this case.
- */
- testcase( rc==SQLITE_BUSY );
- testcase( xBusy!=0 );
- return rc;
- }
- pWal->ckptLock = 1;
+ /* Enable blocking locks, if possible. If blocking locks are successfully
+ ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
+ sqlite3WalDb(pWal, db);
+ (void)walEnableBlocking(pWal);
- /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
- ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
- ** file.
- **
- ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
- ** immediately, and a busy-handler is configured, it is invoked and the
- ** writer lock retried until either the busy-handler returns 0 or the
- ** lock is successfully obtained.
+ /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
+ ** "checkpoint" lock on the database file.
+ ** EVIDENCE-OF: R-10421-19736 If any other process is running a
+ ** checkpoint operation at the same time, the lock cannot be obtained and
+ ** SQLITE_BUSY is returned.
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
+ ** it will not be invoked in this case.
*/
- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
- if( rc==SQLITE_OK ){
- pWal->writeLock = 1;
- }else if( rc==SQLITE_BUSY ){
- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
- xBusy2 = 0;
- rc = SQLITE_OK;
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ testcase( rc==SQLITE_BUSY );
+ testcase( rc!=SQLITE_OK && xBusy2!=0 );
+ if( rc==SQLITE_OK ){
+ pWal->ckptLock = 1;
+
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
+ ** file.
+ **
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
+ ** immediately, and a busy-handler is configured, it is invoked and the
+ ** writer lock retried until either the busy-handler returns 0 or the
+ ** lock is successfully obtained.
+ */
+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ pWal->writeLock = 1;
+ }else if( rc==SQLITE_BUSY ){
+ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+ xBusy2 = 0;
+ rc = SQLITE_OK;
+ }
}
}
+
/* Read the wal-index header. */
if( rc==SQLITE_OK ){
+ walDisableBlocking(pWal);
rc = walIndexReadHdr(pWal, &isChanged);
+ (void)walEnableBlocking(pWal);
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
}
@@ -57048,7 +63221,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
}
/* If no error occurred, set the output variables. */
@@ -57059,7 +63232,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
}
if( isChanged ){
- /* If a new wal-index header was loaded before the checkpoint was
+ /* If a new wal-index header was loaded before the checkpoint was
** performed, then the pager-cache associated with pWal is now
** out of date. So zero the cached wal-index header to ensure that
** next time the pager opens a snapshot on this database it knows that
@@ -57068,11 +63241,19 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
}
+ walDisableBlocking(pWal);
+ sqlite3WalDb(pWal, 0);
+
/* Release the locks. */
sqlite3WalEndWriteTransaction(pWal);
- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
- pWal->ckptLock = 0;
+ if( pWal->ckptLock ){
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ pWal->ckptLock = 0;
+ }
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
+#endif
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
}
@@ -57102,7 +63283,7 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
** operation must occur while the pager is still holding the exclusive
** lock on the main database file.
**
-** If op is one, then change from locking_mode=NORMAL into
+** If op is one, then change from locking_mode=NORMAL into
** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
** be released. Return 1 if the transition is made and 0 if the
** WAL is already in exclusive-locking mode - meaning that this
@@ -57119,8 +63300,8 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
assert( pWal->writeLock==0 );
assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
- /* pWal->readLock is usually set, but might be -1 if there was a
- ** prior error while attempting to acquire are read-lock. This cannot
+ /* pWal->readLock is usually set, but might be -1 if there was a
+ ** prior error while attempting to acquire are read-lock. This cannot
** happen if the connection is actually in exclusive mode (as no xShmLock
** locks are taken in this case). Nor should the pager attempt to
** upgrade to exclusive-mode following such an error.
@@ -57129,32 +63310,32 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
if( op==0 ){
- if( pWal->exclusiveMode ){
- pWal->exclusiveMode = 0;
+ if( pWal->exclusiveMode!=WAL_NORMAL_MODE ){
+ pWal->exclusiveMode = WAL_NORMAL_MODE;
if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
- pWal->exclusiveMode = 1;
+ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
- rc = pWal->exclusiveMode==0;
+ rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
}else{
/* Already in locking_mode=NORMAL */
rc = 0;
}
}else if( op>0 ){
- assert( pWal->exclusiveMode==0 );
+ assert( pWal->exclusiveMode==WAL_NORMAL_MODE );
assert( pWal->readLock>=0 );
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
- pWal->exclusiveMode = 1;
+ pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
rc = 1;
}else{
- rc = pWal->exclusiveMode==0;
+ rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
}
return rc;
}
-/*
+/*
** Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
-** WAL module is using shared-memory, return false.
+** WAL module is using shared-memory, return false.
*/
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
@@ -57168,9 +63349,14 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
int rc = SQLITE_OK;
WalIndexHdr *pRet;
+ static const u32 aZero[4] = { 0, 0, 0, 0 };
assert( pWal->readLock>=0 && pWal->writeLock==0 );
+ if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){
+ *ppSnapshot = 0;
+ return SQLITE_ERROR;
+ }
pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
if( pRet==0 ){
rc = SQLITE_NOMEM_BKPT;
@@ -57184,11 +63370,14 @@ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapsho
/* Try to open on pSnapshot when the next read-transaction starts
*/
-SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
+SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
+ Wal *pWal,
+ sqlite3_snapshot *pSnapshot
+){
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
}
-/*
+/*
** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
*/
@@ -57204,6 +63393,43 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
return 0;
}
+
+/*
+** The caller currently has a read transaction open on the database.
+** This function takes a SHARED lock on the CHECKPOINTER slot and then
+** checks if the snapshot passed as the second argument is still
+** available. If so, SQLITE_OK is returned.
+**
+** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
+** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
+** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
+** lock is released before returning.
+*/
+SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
+ int rc;
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ if( rc==SQLITE_OK ){
+ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
+ if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
+ ){
+ rc = SQLITE_ERROR_SNAPSHOT;
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ }
+ }
+ return rc;
+}
+
+/*
+** Release a lock obtained by an earlier successful call to
+** sqlite3WalSnapshotCheck().
+*/
+SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal){
+ assert( pWal );
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+}
+
+
#endif /* SQLITE_ENABLE_SNAPSHOT */
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -57278,16 +63504,16 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** on Ptr(N) and its subpages have values greater than Key(N-1). And
** so forth.
**
-** Finding a particular key requires reading O(log(M)) pages from the
+** Finding a particular key requires reading O(log(M)) pages from the
** disk where M is the number of entries in the tree.
**
-** In this implementation, a single file can hold one or more separate
+** In this implementation, a single file can hold one or more separate
** BTrees. Each BTree is identified by the index of its root page. The
** key and data for any entry are combined to form the "payload". A
** fixed amount of payload can be carried directly on the database
** page. If the payload is larger than the preset amount then surplus
** bytes are stored on overflow pages. The payload for an entry
-** and the preceding pointer are combined to form a "Cell". Each
+** and the preceding pointer are combined to form a "Cell". Each
** page has a small header which contains the Ptr(N) pointer and other
** information such as the size of key and data.
**
@@ -57417,7 +63643,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** contiguous or in order, but cell pointers are contiguous and in order.
**
** Cell content makes use of variable length integers. A variable
-** length integer is 1 to 9 bytes where the lower 7 bits of each
+** length integer is 1 to 9 bytes where the lower 7 bits of each
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
@@ -57490,7 +63716,7 @@ typedef struct CellInfo CellInfo;
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long. If you change
-** the header, then your custom library will not be able to read
+** the header, then your custom library will not be able to read
** databases generated by the standard tools and the standard tools
** will not be able to read databases created by your custom library.
*/
@@ -57508,37 +63734,39 @@ typedef struct CellInfo CellInfo;
#define PTF_LEAF 0x08
/*
-** As each page of the file is loaded into memory, an instance of the following
-** structure is appended and initialized to zero. This structure stores
-** information about the page that is decoded from the raw file page.
+** An instance of this object stores information about each a single database
+** page that has been loaded into memory. The information in this object
+** is derived from the raw on-disk page content.
**
-** The pParent field points back to the parent page. This allows us to
-** walk up the BTree from any leaf to the root. Care must be taken to
-** unref() the parent page pointer when this page is no longer referenced.
-** The pageDestructor() routine handles that chore.
+** As each database page is loaded into memory, the pager allocats an
+** instance of this object and zeros the first 8 bytes. (This is the
+** "extra" information associated with each page of the pager.)
**
** Access to all fields of this structure is controlled by the mutex
** stored in MemPage.pBt->mutex.
*/
struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
- u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
+ u8 bBusy; /* Prevent endless loops on corrupt database files */
u8 intKey; /* True if table b-trees. False for index b-trees */
u8 intKeyLeaf; /* True if the leaf of an intKey table */
+ Pgno pgno; /* Page number for this page */
+ /* Only the first 8 bytes (above) are zeroed by pager.c when a new page
+ ** is allocated. All fields that follow must be initialized before use */
u8 leaf; /* True if a leaf page */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u8 max1bytePayload; /* min(maxLocal,127) */
- u8 bBusy; /* Prevent endless loops on corrupt database files */
+ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
- u16 nFree; /* Number of free bytes on the page */
+ int nFree; /* Number of free bytes on the page. -1 for unknown */
u16 nCell; /* Number of cells on this page, local and ovfl */
u16 maskPage; /* Mask for page offset */
- u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th
+ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th
** non-overflow cell */
- u8 *apOvfl[5]; /* Pointers to the body of overflow cells */
+ u8 *apOvfl[4]; /* Pointers to the body of overflow cells */
BtShared *pBt; /* Pointer to BtShared that this page is part of */
u8 *aData; /* Pointer to disk image of the page data */
u8 *aDataEnd; /* One byte past the end of usable data */
@@ -57547,19 +63775,11 @@ struct MemPage {
DbPage *pDbPage; /* Pager page handle */
u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
- Pgno pgno; /* Page number for this page */
};
/*
-** The in-memory image of a disk page has the auxiliary information appended
-** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
-** that extra information.
-*/
-#define EXTRA_SIZE sizeof(MemPage)
-
-/*
** A linked list of the following structures is stored at BtShared.pLock.
-** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
+** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
** from this list when a transaction is committed or rolled back, or when
** a btree handle is closed.
@@ -57583,7 +63803,7 @@ struct BtLock {
** see the internals of this structure and only deals with pointers to
** this structure.
**
-** For some database files, the same underlying database cache might be
+** For some database files, the same underlying database cache might be
** shared between multiple connections. In that case, each connection
** has it own instance of this object. But each instance of this object
** points to the same BtShared object. The database cache and the
@@ -57591,7 +63811,7 @@ struct BtLock {
** the BtShared object.
**
** All fields in this structure are accessed under sqlite3.mutex.
-** The pBt pointer itself may not be changed while there exists cursors
+** The pBt pointer itself may not be changed while there exists cursors
** in the referenced BtShared that point back to this Btree since those
** cursors have to go through this Btree to find their BtShared and
** they often do so without holding sqlite3.mutex.
@@ -57626,7 +63846,7 @@ struct Btree {
/*
** An instance of this object represents a single database file.
-**
+**
** A single database file can be in use at the same time by two
** or more database connections. When two or more connections are
** sharing the same database file, each connection has it own
@@ -57636,7 +63856,7 @@ struct Btree {
**
** Fields in this structure are accessed under the BtShared.mutex
** mutex, except for nRef and pNext which are accessed under the
-** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
+** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field
** may not be modified once it is initially set as long as nRef>0.
** The pSchema field may be set once under BtShared.mutex and
** thereafter is unchanged as long as nRef>0.
@@ -57672,9 +63892,7 @@ struct BtShared {
#endif
u8 inTransaction; /* Transaction state */
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
-#ifdef SQLITE_HAS_CODEC
- u8 optimalReserve; /* Desired amount of reserved space per page */
-#endif
+ u8 nReserveWanted; /* Desired number of extra bytes per page */
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
@@ -57703,10 +63921,12 @@ struct BtShared {
#define BTS_READ_ONLY 0x0001 /* Underlying file is readonly */
#define BTS_PAGESIZE_FIXED 0x0002 /* Page size can no longer be changed */
#define BTS_SECURE_DELETE 0x0004 /* PRAGMA secure_delete is enabled */
-#define BTS_INITIALLY_EMPTY 0x0008 /* Database was empty at trans start */
-#define BTS_NO_WAL 0x0010 /* Do not open write-ahead-log files */
-#define BTS_EXCLUSIVE 0x0020 /* pWriter has an exclusive lock */
-#define BTS_PENDING 0x0040 /* Waiting for read-locks to clear */
+#define BTS_OVERWRITE 0x0008 /* Overwrite deleted content with zeros */
+#define BTS_FAST_SECURE 0x000c /* Combination of the previous two */
+#define BTS_INITIALLY_EMPTY 0x0010 /* Database was empty at trans start */
+#define BTS_NO_WAL 0x0020 /* Do not open write-ahead-log files */
+#define BTS_EXCLUSIVE 0x0040 /* pWriter has an exclusive lock */
+#define BTS_PENDING 0x0080 /* Waiting for read-locks to clear */
/*
** An instance of the following structure is used to hold information
@@ -57744,38 +63964,46 @@ struct CellInfo {
** particular database connection identified BtCursor.pBtree.db.
**
** Fields in this structure are accessed under the BtShared.mutex
-** found at self->pBt->mutex.
+** found at self->pBt->mutex.
**
** skipNext meaning:
-** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
-** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
-** eState==FAULT: Cursor fault with skipNext as error code.
+** The meaning of skipNext depends on the value of eState:
+**
+** eState Meaning of skipNext
+** VALID skipNext is meaningless and is ignored
+** INVALID skipNext is meaningless and is ignored
+** SKIPNEXT sqlite3BtreeNext() is a no-op if skipNext>0 and
+** sqlite3BtreePrevious() is no-op if skipNext<0.
+** REQUIRESEEK restoreCursorPosition() restores the cursor to
+** eState=SKIPNEXT if skipNext!=0
+** FAULT skipNext holds the cursor fault error code.
*/
struct BtCursor {
- Btree *pBtree; /* The Btree to which this cursor belongs */
- BtShared *pBt; /* The BtShared this cursor points to */
- BtCursor *pNext; /* Forms a linked list of all cursors */
- Pgno *aOverflow; /* Cache of overflow page locations */
- CellInfo info; /* A parse of the cell we are pointing at */
- i64 nKey; /* Size of pKey, or last integer key */
- void *pKey; /* Saved key that was cursor last known position */
- Pgno pgnoRoot; /* The root page of this tree */
- int nOvflAlloc; /* Allocated size of aOverflow[] array */
- int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
- ** Error code if eState==CURSOR_FAULT */
+ u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 curFlags; /* zero or more BTCF_* flags defined below */
u8 curPagerFlags; /* Flags to send to sqlite3PagerGet() */
- u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 hints; /* As configured by CursorSetHints() */
+ int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
+ ** Error code if eState==CURSOR_FAULT */
+ Btree *pBtree; /* The Btree to which this cursor belongs */
+ Pgno *aOverflow; /* Cache of overflow page locations */
+ void *pKey; /* Saved key that was cursor last known position */
/* All fields above are zeroed when the cursor is allocated. See
** sqlite3BtreeCursorZero(). Fields that follow must be manually
** initialized. */
+#define BTCURSOR_FIRST_UNINIT pBt /* Name of first uninitialized field */
+ BtShared *pBt; /* The BtShared this cursor points to */
+ BtCursor *pNext; /* Forms a linked list of all cursors */
+ CellInfo info; /* A parse of the cell we are pointing at */
+ i64 nKey; /* Size of pKey, or last integer key */
+ Pgno pgnoRoot; /* The root page of this tree */
i8 iPage; /* Index of current page in apPage */
u8 curIntKey; /* Value of apPage[0]->intKey */
- struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
- void *padding1; /* Make object size a multiple of 16 */
- u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */
- MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */
+ u16 ix; /* Current index for apPage[iPage] */
+ u16 aiIdx[BTCURSOR_MAX_DEPTH-1]; /* Current index in apPage[i] */
+ struct KeyInfo *pKeyInfo; /* Arg passed to comparison function */
+ MemPage *pPage; /* Current page */
+ MemPage *apPage[BTCURSOR_MAX_DEPTH-1]; /* Stack of parents of current page */
};
/*
@@ -57787,12 +64015,13 @@ struct BtCursor {
#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
+#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
/*
** Potential values for BtCursor.eState.
**
** CURSOR_INVALID:
-** Cursor does not point to a valid entry. This can happen (for example)
+** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
**
@@ -57805,9 +64034,9 @@ struct BtCursor {
** operation should be a no-op.
**
** CURSOR_REQUIRESEEK:
-** The table that this cursor was opened on still exists, but has been
+** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved
-** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
+** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreCursorPosition() can be called to attempt to
** seek the cursor to the saved position.
**
@@ -57818,19 +64047,19 @@ struct BtCursor {
** Do nothing else with this cursor. Any attempt to use the cursor
** should return the error code stored in BtCursor.skipNext
*/
-#define CURSOR_INVALID 0
-#define CURSOR_VALID 1
+#define CURSOR_VALID 0
+#define CURSOR_INVALID 1
#define CURSOR_SKIPNEXT 2
#define CURSOR_REQUIRESEEK 3
#define CURSOR_FAULT 4
-/*
+/*
** The database page the PENDING_BYTE occupies. This page is never used.
*/
# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
/*
-** These macros define the location of the pointer-map entry for a
+** These macros define the location of the pointer-map entry for a
** database page. The first argument to each is the number of usable
** bytes on each page of the database (often 1024). The second is the
** page number to look up in the pointer map.
@@ -57865,10 +64094,10 @@ struct BtCursor {
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
** used in this case.
**
-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
+** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
** is not used in this case.
**
-** PTRMAP_OVERFLOW1: The database page is the first page in a list of
+** PTRMAP_OVERFLOW1: The database page is the first page in a list of
** overflow pages. The page number identifies the page that
** contains the cell with a pointer to this overflow page.
**
@@ -57890,13 +64119,13 @@ struct BtCursor {
*/
#define btreeIntegrity(p) \
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
- assert( p->pBt->inTransaction>=p->inTrans );
+ assert( p->pBt->inTransaction>=p->inTrans );
/*
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
** if the database supports auto-vacuum or not. Because it is used
-** within an expression that is an argument to another macro
+** within an expression that is an argument to another macro
** (sqliteMallocRaw), it is not possible to use conditional compilation.
** So, this macro is defined instead.
*/
@@ -57913,8 +64142,8 @@ struct BtCursor {
**
** The aRef[] array is allocated so that there is 1 bit for each page in
** the database. As the integrity-check proceeds, for each page used in
-** the database the corresponding bit is set. This allows integrity-check to
-** detect pages that are used twice and orphaned pages (both of which
+** the database the corresponding bit is set. This allows integrity-check to
+** detect pages that are used twice and orphaned pages (both of which
** indicate corruption).
*/
typedef struct IntegrityCk IntegrityCk;
@@ -57925,11 +64154,13 @@ struct IntegrityCk {
Pgno nPage; /* Number of pages in the database */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
- int mallocFailed; /* A memory allocation error has occurred */
+ int bOomFault; /* A memory allocation error has occurred */
const char *zPfx; /* Error message prefix */
- int v1, v2; /* Values for up to two %d fields in zPfx */
+ Pgno v1; /* Value for first %u substitution in zPfx */
+ int v2; /* Value for second %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
+ sqlite3 *db; /* Database connection running the check */
};
/*
@@ -57947,11 +64178,9 @@ struct IntegrityCk {
*/
#if SQLITE_BYTEORDER==4321
# define get2byteAligned(x) (*(u16*)(x))
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && GCC_VERSION>=4008000
+#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000
# define get2byteAligned(x) __builtin_bswap16(*(u16*)(x))
-#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
- && defined(_MSC_VER) && _MSC_VER>=1300
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
# define get2byteAligned(x) _byteswap_ushort(*(u16*)(x))
#else
# define get2byteAligned(x) ((x)[0]<<8 | (x)[1])
@@ -58126,16 +64355,24 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
** two or more btrees in common both try to lock all their btrees
** at the same instant.
*/
-SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
+static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
int i;
+ int skipOk = 1;
Btree *p;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb; i++){
p = db->aDb[i].pBt;
- if( p ) sqlite3BtreeEnter(p);
+ if( p && p->sharable ){
+ sqlite3BtreeEnter(p);
+ skipOk = 0;
+ }
}
+ db->noSharedCache = skipOk;
}
-SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
+SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
+ if( db->noSharedCache==0 ) btreeEnterAll(db);
+}
+static void SQLITE_NOINLINE btreeLeaveAll(sqlite3 *db){
int i;
Btree *p;
assert( sqlite3_mutex_held(db->mutex) );
@@ -58144,6 +64381,9 @@ SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
if( p ) sqlite3BtreeLeave(p);
}
}
+SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3 *db){
+ if( db->noSharedCache==0 ) btreeLeaveAll(db);
+}
#ifndef NDEBUG
/*
@@ -58221,10 +64461,10 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
#ifndef SQLITE_OMIT_INCRBLOB
/*
-** Enter a mutex on a Btree given a cursor owned by that Btree.
+** Enter a mutex on a Btree given a cursor owned by that Btree.
**
-** These entry points are used by incremental I/O only. Enter() is required
-** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
+** These entry points are used by incremental I/O only. Enter() is required
+** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
** the build is threadsafe. Leave() is only required by threadsafe builds.
*/
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
@@ -58294,7 +64534,7 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
/*
-** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
+** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
** defined, or 0 if it is. For example:
**
** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
@@ -58309,10 +64549,10 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
/*
** A list of BtShared objects that are eligible for participation
** in shared cache. This variable has file scope during normal builds,
-** but the test harness needs to access it so we make it global for
+** but the test harness needs to access it so we make it global for
** test builds.
**
-** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
+** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN.
*/
#ifdef SQLITE_TEST
SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
@@ -58344,7 +64584,7 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){
** manipulate entries in the BtShared.pLock linked list used to store
** shared-cache table level locks. If the library is compiled with the
** shared-cache feature disabled, then there is only ever one user
- ** of each BtShared structure and so this locking is not necessary.
+ ** of each BtShared structure and so this locking is not necessary.
** So define the lock related functions as no-ops.
*/
#define querySharedCacheTableLock(a,b,c) SQLITE_OK
@@ -58355,21 +64595,49 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){
#define hasReadConflicts(a, b) 0
#endif
+/*
+** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
+** (MemPage*) as an argument. The (MemPage*) must not be NULL.
+**
+** If SQLITE_DEBUG is not defined, then this macro is equivalent to
+** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
+** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
+** with the page number and filename associated with the (MemPage*).
+*/
+#ifdef SQLITE_DEBUG
+int corruptPageError(int lineno, MemPage *p){
+ char *zMsg;
+ sqlite3BeginBenignMalloc();
+ zMsg = sqlite3_mprintf("database corruption page %d of %s",
+ (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
+ );
+ sqlite3EndBenignMalloc();
+ if( zMsg ){
+ sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
+ }
+ sqlite3_free(zMsg);
+ return SQLITE_CORRUPT_BKPT;
+}
+# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
+#else
+# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
+#endif
+
#ifndef SQLITE_OMIT_SHARED_CACHE
#ifdef SQLITE_DEBUG
/*
**** This function is only used as part of an assert() statement. ***
**
-** Check to see if pBtree holds the required locks to read or write to the
+** Check to see if pBtree holds the required locks to read or write to the
** table with root page iRoot. Return 1 if it does and 0 if not.
**
-** For example, when writing to a table with root-page iRoot via
+** For example, when writing to a table with root-page iRoot via
** Btree connection pBtree:
**
** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) );
**
-** When writing to an index that resides in a sharable database, the
+** When writing to an index that resides in a sharable database, the
** caller should have first obtained a lock specifying the root page of
** the corresponding table. This makes things a bit more complicated,
** as this module treats each table as a separate structure. To determine
@@ -58391,11 +64659,11 @@ static int hasSharedCacheTableLock(
BtLock *pLock;
/* If this database is not shareable, or if the client is reading
- ** and has the read-uncommitted flag set, then no lock is required.
+ ** and has the read-uncommitted flag set, then no lock is required.
** Return true immediately.
*/
if( (pBtree->sharable==0)
- || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted))
+ || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommit))
){
return 1;
}
@@ -58415,29 +64683,31 @@ static int hasSharedCacheTableLock(
** table. */
if( isIndex ){
HashElem *p;
+ int bSeen = 0;
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
Index *pIdx = (Index *)sqliteHashData(p);
if( pIdx->tnum==(int)iRoot ){
- if( iTab ){
+ if( bSeen ){
/* Two or more indexes share the same root page. There must
** be imposter tables. So just return true. The assert is not
** useful in that case. */
return 1;
}
iTab = pIdx->pTable->tnum;
+ bSeen = 1;
}
}
}else{
iTab = iRoot;
}
- /* Search for the required lock. Either a write-lock on root-page iTab, a
+ /* Search for the required lock. Either a write-lock on root-page iTab, a
** write-lock on the schema table, or (if the client is reading) a
** read-lock on iTab will suffice. Return 1 if any of these are found. */
for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){
- if( pLock->pBtree==pBtree
+ if( pLock->pBtree==pBtree
&& (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1))
- && pLock->eLock>=eLockType
+ && pLock->eLock>=eLockType
){
return 1;
}
@@ -58470,9 +64740,9 @@ static int hasSharedCacheTableLock(
static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
BtCursor *p;
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- if( p->pgnoRoot==iRoot
+ if( p->pgnoRoot==iRoot
&& p->pBtree!=pBtree
- && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted)
+ && 0==(p->pBtree->db->flags & SQLITE_ReadUncommit)
){
return 1;
}
@@ -58482,7 +64752,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
#endif /* #ifdef SQLITE_DEBUG */
/*
-** Query to see if Btree handle p may obtain a lock of type eLock
+** Query to see if Btree handle p may obtain a lock of type eLock
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
** SQLITE_OK if the lock may be obtained (by calling
** setSharedCacheTableLock()), or SQLITE_LOCKED if not.
@@ -58494,15 +64764,15 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
assert( sqlite3BtreeHoldsMutex(p) );
assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
assert( p->db!=0 );
- assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 );
-
+ assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 );
+
/* If requesting a write-lock, then the Btree must have an open write
- ** transaction on this file. And, obviously, for this to be so there
+ ** transaction on this file. And, obviously, for this to be so there
** must be an open write transaction on the file itself.
*/
assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) );
assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE );
-
+
/* This routine is a no-op if the shared-cache is not enabled */
if( !p->sharable ){
return SQLITE_OK;
@@ -58517,7 +64787,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
}
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
- /* The condition (pIter->eLock!=eLock) in the following if(...)
+ /* The condition (pIter->eLock!=eLock) in the following if(...)
** statement is a simplification of:
**
** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK)
@@ -58544,7 +64814,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** Add a lock on the table with root-page iTable to the shared-btree used
-** by Btree handle p. Parameter eLock must be either READ_LOCK or
+** by Btree handle p. Parameter eLock must be either READ_LOCK or
** WRITE_LOCK.
**
** This function assumes the following:
@@ -58556,7 +64826,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
** with the requested lock (i.e. querySharedCacheTableLock() has
** already been called and returned SQLITE_OK).
**
-** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
+** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
** is returned if a malloc attempt fails.
*/
static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
@@ -58570,11 +64840,11 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
/* A connection with the read-uncommitted flag set will never try to
** obtain a read-lock using this function. The only read-lock obtained
- ** by a connection in read-uncommitted mode is on the sqlite_master
+ ** by a connection in read-uncommitted mode is on the sqlite_schema
** table, and that lock is obtained in BtreeBeginTrans(). */
- assert( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK );
+ assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
- /* This function should only be called on a sharable b-tree after it
+ /* This function should only be called on a sharable b-tree after it
** has been determined that no other b-tree holds a conflicting lock. */
assert( p->sharable );
assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) );
@@ -58619,7 +64889,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
** Release all the table locks (locks obtained via calls to
** the setSharedCacheTableLock() procedure) held by Btree object p.
**
-** This function assumes that Btree p has an open read or write
+** This function assumes that Btree p has an open read or write
** transaction. If it does not, then the BTS_PENDING flag
** may be incorrectly cleared.
*/
@@ -58651,7 +64921,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){
pBt->pWriter = 0;
pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
}else if( pBt->nTransaction==2 ){
- /* This function is called when Btree p is concluding its
+ /* This function is called when Btree p is concluding its
** transaction. If there currently exists a writer, and p is not
** that writer, then the number of locks held by connections other
** than the writer must be about to drop to zero. In this case
@@ -58682,7 +64952,9 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
#endif /* SQLITE_OMIT_SHARED_CACHE */
-static void releasePage(MemPage *pPage); /* Forward reference */
+static void releasePage(MemPage *pPage); /* Forward reference */
+static void releasePageOne(MemPage *pPage); /* Forward reference */
+static void releasePageNotNull(MemPage *pPage); /* Forward reference */
/*
***** This routine is used inside of assert() only ****
@@ -58695,7 +64967,7 @@ static int cursorHoldsMutex(BtCursor *p){
}
/* Verify that the cursor and the BtShared agree about what is the current
-** database connetion. This is important in shared-cache mode. If the database
+** database connetion. This is important in shared-cache mode. If the database
** connection pointers get out-of-sync, it is possible for routines like
** btreeInitPage() to reference an stale connection pointer that references a
** a connection that has already closed. This routine is used inside assert()
@@ -58742,6 +65014,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
*/
static void invalidateIncrblobCursors(
Btree *pBtree, /* The database file to check */
+ Pgno pgnoRoot, /* The table that might be changing */
i64 iRow, /* The rowid that might be changing */
int isClearTable /* True if all rows are being deleted */
){
@@ -58752,7 +65025,7 @@ static void invalidateIncrblobCursors(
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
if( (p->curFlags & BTCF_Incrblob)!=0 ){
pBtree->hasIncrblobCur = 1;
- if( isClearTable || p->info.nKey==iRow ){
+ if( p->pgnoRoot==pgnoRoot && (isClearTable || p->info.nKey==iRow) ){
p->eState = CURSOR_INVALID;
}
}
@@ -58761,12 +65034,12 @@ static void invalidateIncrblobCursors(
#else
/* Stub function when INCRBLOB is omitted */
- #define invalidateIncrblobCursors(x,y,z)
+ #define invalidateIncrblobCursors(w,x,y,z)
#endif /* SQLITE_OMIT_INCRBLOB */
/*
-** Set bit pgno of the BtShared.pHasContent bitvec. This is called
-** when a page that previously contained data becomes a free-list leaf
+** Set bit pgno of the BtShared.pHasContent bitvec. This is called
+** when a page that previously contained data becomes a free-list leaf
** page.
**
** The BtShared.pHasContent bitvec exists to work around an obscure
@@ -58792,7 +65065,7 @@ static void invalidateIncrblobCursors(
** may be lost. In the event of a rollback, it may not be possible
** to restore the database to its original configuration.
**
-** The solution is the BtShared.pHasContent bitvec. Whenever a page is
+** The solution is the BtShared.pHasContent bitvec. Whenever a page is
** moved to become a free-list leaf page, the corresponding bit is
** set in the bitvec. Whenever a leaf page is extracted from the free-list,
** optimization 2 above is omitted if the corresponding bit is already
@@ -58823,7 +65096,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
*/
static int btreeGetHasContent(BtShared *pBt, Pgno pgno){
Bitvec *p = pBt->pHasContent;
- return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno)));
+ return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno));
}
/*
@@ -58840,24 +65113,26 @@ static void btreeClearHasContent(BtShared *pBt){
*/
static void btreeReleaseAllCursorPages(BtCursor *pCur){
int i;
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- pCur->apPage[i] = 0;
+ if( pCur->iPage>=0 ){
+ for(i=0; i<pCur->iPage; i++){
+ releasePageNotNull(pCur->apPage[i]);
+ }
+ releasePageNotNull(pCur->pPage);
+ pCur->iPage = -1;
}
- pCur->iPage = -1;
}
/*
** The cursor passed as the only argument must point to a valid entry
** when this function is called (i.e. have eState==CURSOR_VALID). This
** function saves the current cursor key in variables pCur->nKey and
-** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error
+** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error
** code otherwise.
**
** If the cursor is open on an intkey table, then the integer key
** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to
-** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is
-** set to point to a malloced buffer pCur->nKey bytes in size containing
+** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is
+** set to point to a malloced buffer pCur->nKey bytes in size containing
** the key.
*/
static int saveCursorKey(BtCursor *pCur){
@@ -58870,13 +65145,19 @@ static int saveCursorKey(BtCursor *pCur){
/* Only the rowid is required for a table btree */
pCur->nKey = sqlite3BtreeIntegerKey(pCur);
}else{
- /* For an index btree, save the complete key content */
+ /* For an index btree, save the complete key content. It is possible
+ ** that the current key is corrupt. In that case, it is possible that
+ ** the sqlite3VdbeRecordUnpack() function may overread the buffer by
+ ** up to the size of 1 varint plus 1 8-byte value when the cursor
+ ** position is restored. Hence the 17 bytes of padding allocated
+ ** below. */
void *pKey;
pCur->nKey = sqlite3BtreePayloadSize(pCur);
- pKey = sqlite3Malloc( pCur->nKey );
+ pKey = sqlite3Malloc( pCur->nKey + 9 + 8 );
if( pKey ){
- rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
+ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
+ memset(((u8*)pKey)+pCur->nKey, 0, 9+8);
pCur->pKey = pKey;
}else{
sqlite3_free(pKey);
@@ -58890,11 +65171,11 @@ static int saveCursorKey(BtCursor *pCur){
}
/*
-** Save the current cursor position in the variables BtCursor.nKey
+** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
**
** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
-** prior to calling this routine.
+** prior to calling this routine.
*/
static int saveCursorPosition(BtCursor *pCur){
int rc;
@@ -58903,6 +65184,9 @@ static int saveCursorPosition(BtCursor *pCur){
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
+ if( pCur->curFlags & BTCF_Pinned ){
+ return SQLITE_CONSTRAINT_PINNED;
+ }
if( pCur->eState==CURSOR_SKIPNEXT ){
pCur->eState = CURSOR_VALID;
}else{
@@ -58930,7 +65214,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*);
** routine is called just before cursor pExcept is used to modify the
** table, for example in BtreeDelete() or BtreeInsert().
**
-** If there are two or more cursors on the same btree, then all such
+** If there are two or more cursors on the same btree, then all such
** cursors should have their BTCF_Multiple flag set. The btreeCursor()
** routine enforces that rule. This routine only needs to be called in
** the uncommon case when pExpect has the BTCF_Multiple flag set.
@@ -58973,7 +65257,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(
return rc;
}
}else{
- testcase( p->iPage>0 );
+ testcase( p->iPage>=0 );
btreeReleaseAllCursorPages(p);
}
}
@@ -59006,52 +65290,54 @@ static int btreeMoveto(
){
int rc; /* Status code */
UnpackedRecord *pIdxKey; /* Unpacked index key */
- char aSpace[384]; /* Temp space for pIdxKey - to avoid a malloc */
- char *pFree = 0;
if( pKey ){
+ KeyInfo *pKeyInfo = pCur->pKeyInfo;
assert( nKey==(i64)(int)nKey );
- pIdxKey = sqlite3VdbeAllocUnpackedRecord(
- pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
- );
+ pIdxKey = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
- sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
- if( pIdxKey->nField==0 ){
- sqlite3DbFree(pCur->pKeyInfo->db, pFree);
- return SQLITE_CORRUPT_BKPT;
+ sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
+ if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto moveto_done;
}
}else{
pIdxKey = 0;
}
rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
- if( pFree ){
- sqlite3DbFree(pCur->pKeyInfo->db, pFree);
+moveto_done:
+ if( pIdxKey ){
+ sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
}
return rc;
}
/*
** Restore the cursor to the position it was in (or as close to as possible)
-** when saveCursorPosition() was called. Note that this call deletes the
+** when saveCursorPosition() was called. Note that this call deletes the
** saved position info stored by saveCursorPosition(), so there can be
-** at most one effective restoreCursorPosition() call after each
+** at most one effective restoreCursorPosition() call after each
** saveCursorPosition().
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
- int skipNext;
+ int skipNext = 0;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
}
pCur->eState = CURSOR_INVALID;
- rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
+ if( sqlite3FaultSim(410) ){
+ rc = SQLITE_IOERR;
+ }else{
+ rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
+ }
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
- pCur->skipNext |= skipNext;
+ if( skipNext ) pCur->skipNext = skipNext;
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
pCur->eState = CURSOR_SKIPNEXT;
}
@@ -59077,13 +65363,28 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
** back to where it ought to be if this routine returns true.
*/
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
- return pCur->eState!=CURSOR_VALID;
+ assert( EIGHT_BYTE_ALIGNMENT(pCur)
+ || pCur==sqlite3BtreeFakeValidCursor() );
+ assert( offsetof(BtCursor, eState)==0 );
+ assert( sizeof(pCur->eState)==1 );
+ return CURSOR_VALID != *(u8*)pCur;
+}
+
+/*
+** Return a pointer to a fake BtCursor object that will always answer
+** false to the sqlite3BtreeCursorHasMoved() routine above. The fake
+** cursor returned must not be used with any other Btree interface.
+*/
+SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){
+ static u8 fakeCursor = CURSOR_VALID;
+ assert( offsetof(BtCursor, eState)==0 );
+ return (BtCursor*)&fakeCursor;
}
/*
** This routine restores a cursor back to its original position after it
** has been moved by some outside activity (such as a btree rebalance or
-** a row having been deleted out from under the cursor).
+** a row having been deleted out from under the cursor).
**
** On success, the *pDifferentRow parameter is false if the cursor is left
** pointing at exactly the same row. *pDifferntRow is the row the cursor
@@ -59106,7 +65407,6 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
if( pCur->eState!=CURSOR_VALID ){
*pDifferentRow = 1;
}else{
- assert( pCur->skipNext==0 );
*pDifferentRow = 0;
}
return SQLITE_OK;
@@ -59149,7 +65449,7 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
if( pgno<2 ) return 0;
nPagesPerMapPage = (pBt->usableSize/5)+1;
iPtrMap = (pgno-2)/nPagesPerMapPage;
- ret = (iPtrMap*nPagesPerMapPage) + 2;
+ ret = (iPtrMap*nPagesPerMapPage) + 2;
if( ret==PENDING_BYTE_PAGE(pBt) ){
ret++;
}
@@ -59176,7 +65476,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
if( *pRC ) return;
assert( sqlite3_mutex_held(pBt->mutex) );
- /* The master-journal page number must never be used as a pointer map page */
+ /* The super-journal page number must never be used as a pointer map page */
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
assert( pBt->autoVacuum );
@@ -59190,6 +65490,13 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
*pRC = rc;
return;
}
+ if( ((char*)sqlite3PagerGetExtra(pDbPage))[0]!=0 ){
+ /* The first byte of the extra data is the MemPage.isInit byte.
+ ** If that byte is set, it means this page is also being used
+ ** as a btree page. */
+ *pRC = SQLITE_CORRUPT_BKPT;
+ goto ptrmap_exit;
+ }
offset = PTRMAP_PTROFFSET(iPtrmap, key);
if( offset<0 ){
*pRC = SQLITE_CORRUPT_BKPT;
@@ -59245,14 +65552,14 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3PagerUnref(pDbPage);
- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
+ if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap);
return SQLITE_OK;
}
#else /* if defined SQLITE_OMIT_AUTOVACUUM */
#define ptrmapPut(w,x,y,z,rc)
#define ptrmapGet(w,x,y,z) SQLITE_OK
- #define ptrmapPutOvflPtr(x, y, rc)
+ #define ptrmapPutOvflPtr(x, y, z, rc)
#endif
/*
@@ -59488,7 +65795,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
}
pIter++;
if( pPage->intKey ){
- /* pIter now points at the 64-bit integer key value, a variable length
+ /* pIter now points at the 64-bit integer key value, a variable length
** integer. The following block moves pIter to point at the first byte
** past the end of the key value. */
pEnd = &pIter[9];
@@ -59545,17 +65852,24 @@ static u16 cellSize(MemPage *pPage, int iCell){
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
-** If the cell pCell, part of page pPage contains a pointer
-** to an overflow page, insert an entry into the pointer-map
-** for the overflow page.
+** The cell pCell is currently part of page pSrc but will ultimately be part
+** of pPage. (pSrc and pPager are often the same.) If pCell contains a
+** pointer to an overflow page, insert an entry into the pointer-map for
+** the overflow page that will be valid after pCell has been moved to pPage.
*/
-static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
+static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
CellInfo info;
if( *pRC ) return;
assert( pCell!=0 );
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocal<info.nPayload ){
- Pgno ovfl = get4byte(&pCell[info.nSize-4]);
+ Pgno ovfl;
+ if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
+ testcase( pSrc!=pPage );
+ *pRC = SQLITE_CORRUPT_BKPT;
+ return;
+ }
+ ovfl = get4byte(&pCell[info.nSize-4]);
ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC);
}
}
@@ -59563,17 +65877,18 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
/*
-** Defragment the page given. All Cells are moved to the
-** end of the page and all free space is collected into one
-** big FreeBlk that occurs in between the header and cell
-** pointer array and the cell content area.
+** Defragment the page given. This routine reorganizes cells within the
+** page so that there are no free-blocks on the free-block list.
+**
+** Parameter nMaxFrag is the maximum amount of fragmented space that may be
+** present in the page after this routine returns.
**
** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
** b-tree page so that there are no freeblocks or fragment bytes, all
** unused bytes are contained in the unallocated space region, and all
** cells are packed tightly at the end of the page.
*/
-static int defragmentPage(MemPage *pPage){
+static int defragmentPage(MemPage *pPage, int nMaxFrag){
int i; /* Loop counter */
int pc; /* Address of the i-th cell */
int hdr; /* Offset to the page header */
@@ -59588,7 +65903,6 @@ static int defragmentPage(MemPage *pPage){
int iCellFirst; /* First allowable cell index */
int iCellLast; /* Last possible cell index */
-
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt!=0 );
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
@@ -59599,10 +65913,54 @@ static int defragmentPage(MemPage *pPage){
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
nCell = pPage->nCell;
- assert( nCell==get2byte(&data[hdr+3]) );
+ assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB );
+ iCellFirst = cellOffset + 2*nCell;
usableSize = pPage->pBt->usableSize;
+
+ /* This block handles pages with two or fewer free blocks and nMaxFrag
+ ** or fewer fragmented bytes. In this case it is faster to move the
+ ** two (or one) blocks of cells using memmove() and add the required
+ ** offsets to each pointer in the cell-pointer array than it is to
+ ** reconstruct the entire page. */
+ if( (int)data[hdr+7]<=nMaxFrag ){
+ int iFree = get2byte(&data[hdr+1]);
+ if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iFree ){
+ int iFree2 = get2byte(&data[iFree]);
+ if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
+ u8 *pEnd = &data[cellOffset + nCell*2];
+ u8 *pAddr;
+ int sz2 = 0;
+ int sz = get2byte(&data[iFree+2]);
+ int top = get2byte(&data[hdr+5]);
+ if( top>=iFree ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ if( iFree2 ){
+ if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
+ sz2 = get2byte(&data[iFree2+2]);
+ if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
+ memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
+ sz += sz2;
+ }else if( NEVER(iFree+sz>usableSize) ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+
+ cbrk = top+sz;
+ assert( cbrk+(iFree-top) <= usableSize );
+ memmove(&data[cbrk], &data[top], iFree-top);
+ for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
+ pc = get2byte(pAddr);
+ if( pc<iFree ){ put2byte(pAddr, pc+sz); }
+ else if( pc<iFree2 ){ put2byte(pAddr, pc+sz2); }
+ }
+ goto defragment_out;
+ }
+ }
+ }
+
cbrk = usableSize;
- iCellFirst = cellOffset + 2*nCell;
iCellLast = usableSize - 4;
for(i=0; i<nCell; i++){
u8 *pAddr; /* The i-th cell pointer */
@@ -59614,13 +65972,13 @@ static int defragmentPage(MemPage *pPage){
** if PRAGMA cell_size_check=ON.
*/
if( pc<iCellFirst || pc>iCellLast ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
assert( pc>=iCellFirst && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrk<iCellFirst || pc+size>usableSize ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
testcase( cbrk+size==usableSize );
@@ -59636,16 +65994,19 @@ static int defragmentPage(MemPage *pPage){
}
memcpy(&data[cbrk], &src[pc], size);
}
+ data[hdr+7] = 0;
+
+ defragment_out:
+ assert( pPage->nFree>=0 );
+ if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
data[hdr+1] = 0;
data[hdr+2] = 0;
- data[hdr+7] = 0;
memset(&data[iCellFirst], 0, cbrk-iCellFirst);
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
- if( cbrk-iCellFirst!=pPage->nFree ){
- return SQLITE_CORRUPT_BKPT;
- }
return SQLITE_OK;
}
@@ -59664,22 +66025,16 @@ static int defragmentPage(MemPage *pPage){
** causes the fragmentation count to exceed 60.
*/
static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
- const int hdr = pPg->hdrOffset;
- u8 * const aData = pPg->aData;
- int iAddr = hdr + 1;
- int pc = get2byte(&aData[iAddr]);
- int x;
- int usableSize = pPg->pBt->usableSize;
+ const int hdr = pPg->hdrOffset; /* Offset to page header */
+ u8 * const aData = pPg->aData; /* Page data */
+ int iAddr = hdr + 1; /* Address of ptr to pc */
+ int pc = get2byte(&aData[iAddr]); /* Address of a free slot */
+ int x; /* Excess size of the slot */
+ int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */
+ int size; /* Size of the free slot */
assert( pc>0 );
- do{
- int size; /* Size of the free slot */
- /* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
- ** increasing offset. */
- if( pc>usableSize-4 || pc<iAddr+4 ){
- *pRc = SQLITE_CORRUPT_BKPT;
- return 0;
- }
+ while( pc<=maxPC ){
/* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
** freeblock form a big-endian integer which is the size of the freeblock
** in bytes, including the 4-byte header. */
@@ -59687,10 +66042,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
if( (x = size - nByte)>=0 ){
testcase( x==4 );
testcase( x==3 );
- if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){
- *pRc = SQLITE_CORRUPT_BKPT;
- return 0;
- }else if( x<4 ){
+ if( x<4 ){
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
** number of bytes in fragments may not exceed 60. */
if( aData[hdr+7]>57 ) return 0;
@@ -59699,17 +66051,31 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x;
+ }else if( x+pc > maxPC ){
+ /* This slot extends off the end of the usable part of the page */
+ *pRc = SQLITE_CORRUPT_PAGE(pPg);
+ return 0;
}else{
/* The slot remains on the free-list. Reduce its size to account
- ** for the portion used by the new allocation. */
+ ** for the portion used by the new allocation. */
put2byte(&aData[pc+2], x);
}
return &aData[pc + x];
}
iAddr = pc;
pc = get2byte(&aData[pc]);
- }while( pc );
-
+ if( pc<=iAddr+size ){
+ if( pc ){
+ /* The next slot in the chain is not past the end of the current slot */
+ *pRc = SQLITE_CORRUPT_PAGE(pPg);
+ }
+ return 0;
+ }
+ }
+ if( pc>maxPC+nByte-4 ){
+ /* The free slot chain extends off the end of the page */
+ *pRc = SQLITE_CORRUPT_PAGE(pPg);
+ }
return 0;
}
@@ -59732,7 +66098,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
int top; /* First byte of cell content area */
int rc = SQLITE_OK; /* Integer return code */
int gap; /* First byte of gap between cell pointers and cell content */
-
+
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
@@ -59750,18 +66116,18 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** However, that integer is too large to be stored in a 2-byte unsigned
** integer, so a value of 0 is used in its place. */
top = get2byte(&data[hdr+5]);
- assert( top<=(int)pPage->pBt->usableSize ); /* Prevent by getAndInitPage() */
+ assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
}
- /* If there is enough space between gap and top for one more cell pointer
- ** array entry offset, and if the freelist is not empty, then search the
- ** freelist looking for a free slot big enough to satisfy the request.
+ /* If there is enough space between gap and top for one more cell pointer,
+ ** and if the freelist is not empty, then search the
+ ** freelist looking for a slot big enough to satisfy the request.
*/
testcase( gap+2==top );
testcase( gap+1==top );
@@ -59769,9 +66135,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
if( (data[hdr+2] || data[hdr+1]) && gap+2<=top ){
u8 *pSpace = pageFindSlot(pPage, nByte, &rc);
if( pSpace ){
- assert( pSpace>=data && (pSpace - data)<65536 );
- *pIdx = (int)(pSpace - data);
- return SQLITE_OK;
+ int g2;
+ assert( pSpace+nByte<=data+pPage->pBt->usableSize );
+ *pIdx = g2 = (int)(pSpace-data);
+ if( NEVER(g2<=gap) ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }else{
+ return SQLITE_OK;
+ }
}else if( rc ){
return rc;
}
@@ -59783,15 +66154,16 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
testcase( gap+2+nByte==top );
if( gap+2+nByte>top ){
assert( pPage->nCell>0 || CORRUPT_DB );
- rc = defragmentPage(pPage);
+ assert( pPage->nFree>=0 );
+ rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte)));
if( rc ) return rc;
top = get2byteNotZero(&data[hdr+5]);
- assert( gap+nByte<=top );
+ assert( gap+2+nByte<=top );
}
/* Allocate memory from the gap in between the cell pointer array
- ** and the cell content area. The btreeInitPage() call has already
+ ** and the cell content area. The btreeComputeFreeSpace() call has already
** validated the freelist. Given that the freelist is valid, there
** is no way that the allocation can extend off the end of the page.
** The assert() below verifies the previous sentence.
@@ -59810,7 +66182,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
**
** Adjacent freeblocks are coalesced.
**
-** Note that even though the freeblock list was checked by btreeInitPage(),
+** Even though the freeblock list was checked by btreeComputeFreeSpace(),
** that routine will not detect overlap between cells or freeblocks. Nor
** does it detect cells or freeblocks that encrouch into the reserved bytes
** at the end of the page. So do additional corruption checks inside this
@@ -59822,7 +66194,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
u8 hdr; /* Page header size. 0 or 100 */
u8 nFrag = 0; /* Reduction in fragmentation */
u16 iOrigSize = iSize; /* Original value of iSize */
- u32 iLast = pPage->pBt->usableSize-4; /* Largest possible freeblock offset */
+ u16 x; /* Offset to cell content area */
u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
unsigned char *data = pPage->aData; /* Page content */
@@ -59832,15 +66204,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=iLast );
-
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- if( pPage->pBt->btsFlags & BTS_SECURE_DELETE ){
- memset(&data[iStart], 0, iSize);
- }
+ assert( iStart<=pPage->pBt->usableSize-4 );
- /* The list of freeblocks must be in ascending order. Find the
+ /* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
*/
hdr = pPage->hdrOffset;
@@ -59850,14 +66216,16 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
if( iFreeBlk<iPtr+4 ){
- if( iFreeBlk==0 ) break;
- return SQLITE_CORRUPT_BKPT;
+ if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
+ return SQLITE_CORRUPT_PAGE(pPage);
}
iPtr = iFreeBlk;
}
- if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
+ if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
assert( iFreeBlk>iPtr || iFreeBlk==0 );
-
+
/* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none
** iPtr: The address of a pointer to iFreeBlk
@@ -59866,13 +66234,15 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
*/
if( iFreeBlk && iEnd+3>=iFreeBlk ){
nFrag = iFreeBlk - iEnd;
- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_BKPT;
+ if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
- if( iEnd > pPage->pBt->usableSize ) return SQLITE_CORRUPT_BKPT;
+ if( iEnd > pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
}
-
+
/* If iPtr is another freeblock (that is, if iPtr is not the freelist
** pointer in the page header) then check to see if iStart should be
** coalesced onto the end of iPtr.
@@ -59880,28 +66250,35 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
if( iPtr>hdr+1 ){
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
if( iPtrEnd+3>=iStart ){
- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_BKPT;
+ if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
nFrag += iStart - iPtrEnd;
iSize = iEnd - iPtr;
iStart = iPtr;
}
}
- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_BKPT;
+ if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
data[hdr+7] -= nFrag;
}
- if( iStart==get2byte(&data[hdr+5]) ){
+ x = get2byte(&data[hdr+5]);
+ if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
** freelist entry */
- if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_BKPT;
+ if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
}
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -59961,22 +66338,25 @@ static int decodeFlags(MemPage *pPage, int flagByte){
}else{
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
** an error. */
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
/*
-** Initialize the auxiliary information for a disk block.
-**
-** Return SQLITE_OK on success. If we see that the page does
-** not contain a well-formed database page, then return
-** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
-** guarantee that the page is well-formed. It only shows that
-** we failed to detect any corruption.
+** Compute the amount of freespace on the page. In other words, fill
+** in the pPage->nFree field.
*/
-static int btreeInitPage(MemPage *pPage){
+static int btreeComputeFreeSpace(MemPage *pPage){
+ int pc; /* Address of a freeblock within pPage->aData[] */
+ u8 hdr; /* Offset to beginning of page header */
+ u8 *data; /* Equal to pPage->aData */
+ int usableSize; /* Amount of usable space on each page */
+ int nFree; /* Number of unused bytes on the page */
+ int top; /* First byte of the cell content area */
+ int iCellFirst; /* First allowable cell or freeblock offset */
+ int iCellLast; /* Last possible cell or freeblock offset */
assert( pPage->pBt!=0 );
assert( pPage->pBt->db!=0 );
@@ -59984,121 +66364,158 @@ static int btreeInitPage(MemPage *pPage){
assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
+ assert( pPage->isInit==1 );
+ assert( pPage->nFree<0 );
- if( !pPage->isInit ){
- u16 pc; /* Address of a freeblock within pPage->aData[] */
- u8 hdr; /* Offset to beginning of page header */
- u8 *data; /* Equal to pPage->aData */
- BtShared *pBt; /* The main btree structure */
- int usableSize; /* Amount of usable space on each page */
- u16 cellOffset; /* Offset from start of page to first cell pointer */
- int nFree; /* Number of unused bytes on the page */
- int top; /* First byte of the cell content area */
- int iCellFirst; /* First allowable cell or freeblock offset */
- int iCellLast; /* Last possible cell or freeblock offset */
-
- pBt = pPage->pBt;
-
- hdr = pPage->hdrOffset;
- data = pPage->aData;
- /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
- ** the b-tree page type. */
- if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
- assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
- pPage->maskPage = (u16)(pBt->pageSize - 1);
- pPage->nOverflow = 0;
- usableSize = pBt->usableSize;
- pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
- pPage->aDataEnd = &data[usableSize];
- pPage->aCellIdx = &data[cellOffset];
- pPage->aDataOfst = &data[pPage->childPtrSize];
- /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
- ** the start of the cell content area. A zero value for this integer is
- ** interpreted as 65536. */
- top = get2byteNotZero(&data[hdr+5]);
- /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
- ** number of cells on the page. */
- pPage->nCell = get2byte(&data[hdr+3]);
- if( pPage->nCell>MX_CELL(pBt) ){
- /* To many cells for a single page. The page must be corrupt */
- return SQLITE_CORRUPT_BKPT;
- }
- testcase( pPage->nCell==MX_CELL(pBt) );
- /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
- ** possible for a root page of a table that contains no rows) then the
- ** offset to the cell content area will equal the page size minus the
- ** bytes of reserved space. */
- assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
+ usableSize = pPage->pBt->usableSize;
+ hdr = pPage->hdrOffset;
+ data = pPage->aData;
+ /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
+ ** the start of the cell content area. A zero value for this integer is
+ ** interpreted as 65536. */
+ top = get2byteNotZero(&data[hdr+5]);
+ iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell;
+ iCellLast = usableSize - 4;
- /* A malformed database page might cause us to read past the end
- ** of page when parsing a cell.
- **
- ** The following block of code checks early to see if a cell extends
- ** past the end of a page boundary and causes SQLITE_CORRUPT to be
- ** returned if it does.
- */
- iCellFirst = cellOffset + 2*pPage->nCell;
- iCellLast = usableSize - 4;
- if( pBt->db->flags & SQLITE_CellSizeCk ){
- int i; /* Index into the cell pointer array */
- int sz; /* Size of a cell */
-
- if( !pPage->leaf ) iCellLast--;
- for(i=0; i<pPage->nCell; i++){
- pc = get2byteAligned(&data[cellOffset+i*2]);
- testcase( pc==iCellFirst );
- testcase( pc==iCellLast );
- if( pc<iCellFirst || pc>iCellLast ){
- return SQLITE_CORRUPT_BKPT;
- }
- sz = pPage->xCellSize(pPage, &data[pc]);
- testcase( pc+sz==usableSize );
- if( pc+sz>usableSize ){
- return SQLITE_CORRUPT_BKPT;
- }
- }
- if( !pPage->leaf ) iCellLast++;
- }
-
- /* Compute the total free space on the page
- ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
- ** start of the first freeblock on the page, or is zero if there are no
- ** freeblocks. */
- pc = get2byte(&data[hdr+1]);
- nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
- while( pc>0 ){
- u16 next, size;
- if( pc<iCellFirst || pc>iCellLast ){
- /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
- ** always be at least one cell before the first freeblock.
- **
- ** Or, the freeblock is off the end of the page
- */
- return SQLITE_CORRUPT_BKPT;
+ /* Compute the total free space on the page
+ ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
+ ** start of the first freeblock on the page, or is zero if there are no
+ ** freeblocks. */
+ pc = get2byte(&data[hdr+1]);
+ nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
+ if( pc>0 ){
+ u32 next, size;
+ if( pc<top ){
+ /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
+ ** always be at least one cell before the first freeblock.
+ */
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ while( 1 ){
+ if( pc>iCellLast ){
+ /* Freeblock off the end of the page */
+ return SQLITE_CORRUPT_PAGE(pPage);
}
next = get2byte(&data[pc]);
size = get2byte(&data[pc+2]);
- if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){
- /* Free blocks must be in ascending order. And the last byte of
- ** the free-block must lie on the database page. */
- return SQLITE_CORRUPT_BKPT;
- }
nFree = nFree + size;
+ if( next<=pc+size+3 ) break;
pc = next;
}
+ if( next>0 ){
+ /* Freeblock not in ascending order */
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ if( pc+size>(unsigned int)usableSize ){
+ /* Last freeblock extends past page end */
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ }
- /* At this point, nFree contains the sum of the offset to the start
- ** of the cell-content area plus the number of free bytes within
- ** the cell-content area. If this is greater than the usable-size
- ** of the page, then the page must be corrupted. This check also
- ** serves to verify that the offset to the start of the cell-content
- ** area, according to the page header, lies within the page.
- */
- if( nFree>usableSize ){
- return SQLITE_CORRUPT_BKPT;
+ /* At this point, nFree contains the sum of the offset to the start
+ ** of the cell-content area plus the number of free bytes within
+ ** the cell-content area. If this is greater than the usable-size
+ ** of the page, then the page must be corrupted. This check also
+ ** serves to verify that the offset to the start of the cell-content
+ ** area, according to the page header, lies within the page.
+ */
+ if( nFree>usableSize || nFree<iCellFirst ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ pPage->nFree = (u16)(nFree - iCellFirst);
+ return SQLITE_OK;
+}
+
+/*
+** Do additional sanity check after btreeInitPage() if
+** PRAGMA cell_size_check=ON
+*/
+static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){
+ int iCellFirst; /* First allowable cell or freeblock offset */
+ int iCellLast; /* Last possible cell or freeblock offset */
+ int i; /* Index into the cell pointer array */
+ int sz; /* Size of a cell */
+ int pc; /* Address of a freeblock within pPage->aData[] */
+ u8 *data; /* Equal to pPage->aData */
+ int usableSize; /* Maximum usable space on the page */
+ int cellOffset; /* Start of cell content area */
+
+ iCellFirst = pPage->cellOffset + 2*pPage->nCell;
+ usableSize = pPage->pBt->usableSize;
+ iCellLast = usableSize - 4;
+ data = pPage->aData;
+ cellOffset = pPage->cellOffset;
+ if( !pPage->leaf ) iCellLast--;
+ for(i=0; i<pPage->nCell; i++){
+ pc = get2byteAligned(&data[cellOffset+i*2]);
+ testcase( pc==iCellFirst );
+ testcase( pc==iCellLast );
+ if( pc<iCellFirst || pc>iCellLast ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ sz = pPage->xCellSize(pPage, &data[pc]);
+ testcase( pc+sz==usableSize );
+ if( pc+sz>usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
- pPage->nFree = (u16)(nFree - iCellFirst);
- pPage->isInit = 1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Initialize the auxiliary information for a disk block.
+**
+** Return SQLITE_OK on success. If we see that the page does
+** not contain a well-formed database page, then return
+** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
+** guarantee that the page is well-formed. It only shows that
+** we failed to detect any corruption.
+*/
+static int btreeInitPage(MemPage *pPage){
+ u8 *data; /* Equal to pPage->aData */
+ BtShared *pBt; /* The main btree structure */
+
+ assert( pPage->pBt!=0 );
+ assert( pPage->pBt->db!=0 );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
+ assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
+ assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
+ assert( pPage->isInit==0 );
+
+ pBt = pPage->pBt;
+ data = pPage->aData + pPage->hdrOffset;
+ /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
+ ** the b-tree page type. */
+ if( decodeFlags(pPage, data[0]) ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
+ pPage->maskPage = (u16)(pBt->pageSize - 1);
+ pPage->nOverflow = 0;
+ pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize;
+ pPage->aCellIdx = data + pPage->childPtrSize + 8;
+ pPage->aDataEnd = pPage->aData + pBt->usableSize;
+ pPage->aDataOfst = pPage->aData + pPage->childPtrSize;
+ /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
+ ** number of cells on the page. */
+ pPage->nCell = get2byte(&data[3]);
+ if( pPage->nCell>MX_CELL(pBt) ){
+ /* To many cells for a single page. The page must be corrupt */
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ testcase( pPage->nCell==MX_CELL(pBt) );
+ /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
+ ** possible for a root page of a table that contains no rows) then the
+ ** offset to the cell content area will equal the page size minus the
+ ** bytes of reserved space. */
+ assert( pPage->nCell>0
+ || get2byteNotZero(&data[5])==(int)pBt->usableSize
+ || CORRUPT_DB );
+ pPage->nFree = -1; /* Indicate that this value is yet uncomputed */
+ pPage->isInit = 1;
+ if( pBt->db->flags & SQLITE_CellSizeCk ){
+ return btreeCellSizeCheck(pPage);
}
return SQLITE_OK;
}
@@ -60118,7 +66535,7 @@ static void zeroPage(MemPage *pPage, int flags){
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pBt->mutex) );
- if( pBt->btsFlags & BTS_SECURE_DELETE ){
+ if( pBt->btsFlags & BTS_FAST_SECURE ){
memset(&data[hdr], 0, pBt->usableSize - hdr);
}
data[hdr] = (char)flags;
@@ -60154,7 +66571,7 @@ static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){
pPage->hdrOffset = pgno==1 ? 100 : 0;
}
assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
- return pPage;
+ return pPage;
}
/*
@@ -60207,9 +66624,8 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
static Pgno btreePagecount(BtShared *pBt){
return pBt->nPage;
}
-SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
+SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
- assert( ((p->pBt->nPage)&0x8000000)==0 );
return btreePagecount(p->pBt);
}
@@ -60236,25 +66652,24 @@ static int getAndInitPage(
int rc;
DbPage *pDbPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->apPage[pCur->iPage] );
+ assert( pCur==0 || ppPage==&pCur->pPage );
assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
assert( pCur==0 || pCur->iPage>0 );
if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT;
- goto getAndInitPage_error;
+ goto getAndInitPage_error1;
}
rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
if( rc ){
- goto getAndInitPage_error;
+ goto getAndInitPage_error1;
}
*ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
if( (*ppPage)->isInit==0 ){
btreePageFromDbPage(pDbPage, pgno, pBt);
rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){
- releasePage(*ppPage);
- goto getAndInitPage_error;
+ goto getAndInitPage_error2;
}
}
assert( (*ppPage)->pgno==pgno );
@@ -60263,14 +66678,18 @@ static int getAndInitPage(
/* If obtaining a child page for a cursor, we must verify that the page is
** compatible with the root page. */
if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_BKPT;
- releasePage(*ppPage);
- goto getAndInitPage_error;
+ rc = SQLITE_CORRUPT_PGNO(pgno);
+ goto getAndInitPage_error2;
}
return SQLITE_OK;
-getAndInitPage_error:
- if( pCur ) pCur->iPage--;
+getAndInitPage_error2:
+ releasePage(*ppPage);
+getAndInitPage_error1:
+ if( pCur ){
+ pCur->iPage--;
+ pCur->pPage = pCur->apPage[pCur->iPage];
+ }
testcase( pgno==0 );
assert( pgno!=0 || rc==SQLITE_CORRUPT );
return rc;
@@ -60279,6 +66698,8 @@ getAndInitPage_error:
/*
** Release a MemPage. This should be called once for each prior
** call to btreeGetPage.
+**
+** Page1 is a special case and must be released using releasePageOne().
*/
static void releasePageNotNull(MemPage *pPage){
assert( pPage->aData );
@@ -60292,6 +66713,16 @@ static void releasePageNotNull(MemPage *pPage){
static void releasePage(MemPage *pPage){
if( pPage ) releasePageNotNull(pPage);
}
+static void releasePageOne(MemPage *pPage){
+ assert( pPage!=0 );
+ assert( pPage->aData );
+ assert( pPage->pBt );
+ assert( pPage->pDbPage!=0 );
+ assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
+ assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ sqlite3PagerUnrefPageOne(pPage->pDbPage);
+}
/*
** Get an unused page.
@@ -60362,11 +66793,11 @@ static int btreeInvokeBusyHandler(void *pArg){
/*
** Open a database file.
-**
+**
** zFilename is the name of the database file. If zFilename is NULL
** then an ephemeral database is created. The ephemeral database might
** be exclusively in memory, or it might use a disk-based memory cache.
-** Either way, the ephemeral database will be automatically deleted
+** Either way, the ephemeral database will be automatically deleted
** when sqlite3BtreeClose() is called.
**
** If zFilename is ":memory:" then an in-memory database is created
@@ -60399,7 +66830,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
/* True if opening an ephemeral, temporary database */
const int isTempDb = zFilename==0 || zFilename[0]==0;
- /* Set the variable isMemdb to true for an in-memory database, or
+ /* Set the variable isMemdb to true for an in-memory database, or
** false for a file-based database.
*/
#ifdef SQLITE_OMIT_MEMORYDB
@@ -60461,15 +66892,19 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
rc = sqlite3OsFullPathname(pVfs, zFilename,
nFullPathname, zFullPathname);
if( rc ){
- sqlite3_free(zFullPathname);
- sqlite3_free(p);
- return rc;
+ if( rc==SQLITE_OK_SYMLINK ){
+ rc = SQLITE_OK;
+ }else{
+ sqlite3_free(zFullPathname);
+ sqlite3_free(p);
+ return rc;
+ }
}
}
#if SQLITE_THREADSAFE
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
sqlite3_mutex_enter(mutexOpen);
- mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
sqlite3_mutex_enter(mutexShared);
#endif
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
@@ -60518,14 +66953,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
assert( sizeof(u32)==4 );
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
-
+
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM_BKPT;
goto btree_open_out;
}
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
- EXTRA_SIZE, flags, vfsFlags, pageReinit);
+ sizeof(MemPage), flags, vfsFlags, pageReinit);
if( rc==SQLITE_OK ){
sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
@@ -60535,14 +66970,16 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
}
pBt->openFlags = (u8)flags;
pBt->db = db;
- sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
+ sqlite3PagerSetBusyHandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
p->pBt = pBt;
-
+
pBt->pCursor = 0;
pBt->pPage1 = 0;
if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY;
-#ifdef SQLITE_SECURE_DELETE
+#if defined(SQLITE_SECURE_DELETE)
pBt->btsFlags |= BTS_SECURE_DELETE;
+#elif defined(SQLITE_FAST_SECURE_DELETE)
+ pBt->btsFlags |= BTS_OVERWRITE;
#endif
/* EVIDENCE-OF: R-51873-39618 The page size for a database file is
** determined by the 2-byte integer located at an offset of 16 bytes from
@@ -60579,14 +67016,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
if( rc ) goto btree_open_out;
pBt->usableSize = pBt->pageSize - nReserve;
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
-
+
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
/* Add the new BtShared object to the linked list sharable BtShareds.
*/
pBt->nRef = 1;
if( p->sharable ){
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
- MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
+ MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);)
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
@@ -60638,12 +67075,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
btree_open_out:
if( rc!=SQLITE_OK ){
if( pBt && pBt->pPager ){
- sqlite3PagerClose(pBt->pPager);
+ sqlite3PagerClose(pBt->pPager, 0);
}
sqlite3_free(pBt);
sqlite3_free(p);
*ppBtree = 0;
}else{
+ sqlite3_file *pFile;
+
/* If the B-Tree was successfully opened, set the pager-cache size to the
** default value. Except, when opening on an existing shared pager-cache,
** do not change the pager-cache size.
@@ -60651,6 +67090,11 @@ btree_open_out:
if( sqlite3BtreeSchema(p, 0, 0)==0 ){
sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
}
+
+ pFile = sqlite3PagerFile(pBt->pPager);
+ if( pFile->pMethods ){
+ sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db);
+ }
}
if( mutexOpen ){
assert( sqlite3_mutex_held(mutexOpen) );
@@ -60668,13 +67112,13 @@ btree_open_out:
*/
static int removeFromSharingList(BtShared *pBt){
#ifndef SQLITE_OMIT_SHARED_CACHE
- MUTEX_LOGIC( sqlite3_mutex *pMaster; )
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; )
BtShared *pList;
int removed = 0;
assert( sqlite3_mutex_notheld(pBt->mutex) );
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- sqlite3_mutex_enter(pMaster);
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
+ sqlite3_mutex_enter(pMainMtx);
pBt->nRef--;
if( pBt->nRef<=0 ){
if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){
@@ -60693,7 +67137,7 @@ static int removeFromSharingList(BtShared *pBt){
}
removed = 1;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
return removed;
#else
return 1;
@@ -60701,7 +67145,7 @@ static int removeFromSharingList(BtShared *pBt){
}
/*
-** Make sure pBt->pTmpSpace points to an allocation of
+** Make sure pBt->pTmpSpace points to an allocation of
** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child
** pointer.
*/
@@ -60716,7 +67160,7 @@ static void allocateTempSpace(BtShared *pBt){
** can mean that fillInCell() only initializes the first 2 or 3
** bytes of pTmpSpace, but that the first 4 bytes are copied from
** it into a database page. This is not actually a problem, but it
- ** does cause a valgrind error when the 1 or 2 bytes of unitialized
+ ** does cause a valgrind error when the 1 or 2 bytes of unitialized
** data is passed to system call write(). So to avoid this error,
** zero the first 4 bytes of temp space here.
**
@@ -60769,7 +67213,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
sqlite3BtreeLeave(p);
/* If there are still other outstanding references to the shared-btree
- ** structure, return now. The remainder of this procedure cleans
+ ** structure, return now. The remainder of this procedure cleans
** up the shared-btree.
*/
assert( p->wantToLock==0 && p->locked==0 );
@@ -60780,7 +67224,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
** Clean out and delete the BtShared object.
*/
assert( !pBt->pCursor );
- sqlite3PagerClose(pBt->pPager);
+ sqlite3PagerClose(pBt->pPager, p->db);
if( pBt->xFreeSchema && pBt->pSchema ){
pBt->xFreeSchema(pBt->pSchema);
}
@@ -60875,7 +67319,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
/*
** Change the default pages size and the number of reserved bytes per page.
-** Or, if the page size has already been fixed, return SQLITE_READONLY
+** Or, if the page size has already been fixed, return SQLITE_READONLY
** without changing anything.
**
** The page size must be a power of 2 between 512 and 65536. If the page
@@ -60895,19 +67339,17 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
*/
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
int rc = SQLITE_OK;
+ int x;
BtShared *pBt = p->pBt;
- assert( nReserve>=-1 && nReserve<=255 );
+ assert( nReserve>=0 && nReserve<=255 );
sqlite3BtreeEnter(p);
-#if SQLITE_HAS_CODEC
- if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
-#endif
+ pBt->nReserveWanted = nReserve;
+ x = pBt->pageSize - pBt->usableSize;
+ if( nReserve<x ) nReserve = x;
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
}
- if( nReserve<0 ){
- nReserve = pBt->pageSize - pBt->usableSize;
- }
assert( nReserve>=0 && nReserve<=255 );
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
((pageSize-1)&pageSize)==0 ){
@@ -60936,7 +67378,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
** held.
**
** This is useful in one special case in the backup API code where it is
-** known that the shared b-tree mutex is held, but the mutex on the
+** known that the shared b-tree mutex is held, but the mutex on the
** database handle that owns *p is not. In this case if sqlite3BtreeEnter()
** were to be called, it might collide with some other operation on the
** database handle that owns *p, causing undefined behavior.
@@ -60953,19 +67395,17 @@ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
** are intentually left unused. This is the "reserved" space that is
** sometimes used by extensions.
**
-** If SQLITE_HAS_MUTEX is defined then the number returned is the
-** greater of the current reserved space and the maximum requested
-** reserve space.
+** The value returned is the larger of the current reserve size and
+** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
+** The amount of reserve can only grow - never shrink.
*/
-SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
- int n;
+SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
+ int n1, n2;
sqlite3BtreeEnter(p);
- n = sqlite3BtreeGetReserveNoMutex(p);
-#ifdef SQLITE_HAS_CODEC
- if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
-#endif
+ n1 = (int)p->pBt->nReserveWanted;
+ n2 = sqlite3BtreeGetReserveNoMutex(p);
sqlite3BtreeLeave(p);
- return n;
+ return n1>n2 ? n1 : n2;
}
@@ -60974,8 +67414,8 @@ SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
** No changes are made if mxPage is 0 or negative.
** Regardless of the value of mxPage, return the maximum page count.
*/
-SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
- int n;
+SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){
+ Pgno n;
sqlite3BtreeEnter(p);
n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
sqlite3BtreeLeave(p);
@@ -60983,19 +67423,34 @@ SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
}
/*
-** Set the BTS_SECURE_DELETE flag if newFlag is 0 or 1. If newFlag is -1,
-** then make no changes. Always return the value of the BTS_SECURE_DELETE
-** setting after the change.
+** Change the values for the BTS_SECURE_DELETE and BTS_OVERWRITE flags:
+**
+** newFlag==0 Both BTS_SECURE_DELETE and BTS_OVERWRITE are cleared
+** newFlag==1 BTS_SECURE_DELETE set and BTS_OVERWRITE is cleared
+** newFlag==2 BTS_SECURE_DELETE cleared and BTS_OVERWRITE is set
+** newFlag==(-1) No changes
+**
+** This routine acts as a query if newFlag is less than zero
+**
+** With BTS_OVERWRITE set, deleted content is overwritten by zeros, but
+** freelist leaf pages are not written back to the database. Thus in-page
+** deleted content is cleared, but freelist deleted content is not.
+**
+** With BTS_SECURE_DELETE, operation is like BTS_OVERWRITE with the addition
+** that freelist leaf pages are written back into the database, increasing
+** the amount of disk I/O.
*/
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
int b;
if( p==0 ) return 0;
sqlite3BtreeEnter(p);
+ assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 );
+ assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
if( newFlag>=0 ){
- p->pBt->btsFlags &= ~BTS_SECURE_DELETE;
- if( newFlag ) p->pBt->btsFlags |= BTS_SECURE_DELETE;
- }
- b = (p->pBt->btsFlags & BTS_SECURE_DELETE)!=0;
+ p->pBt->btsFlags &= ~BTS_FAST_SECURE;
+ p->pBt->btsFlags |= BTS_SECURE_DELETE*newFlag;
+ }
+ b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE;
sqlite3BtreeLeave(p);
return b;
}
@@ -61003,7 +67458,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
/*
** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it
-** is disabled. The default value for the auto-vacuum property is
+** is disabled. The default value for the auto-vacuum property is
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
*/
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
@@ -61027,7 +67482,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
}
/*
-** Return the value of the 'auto-vacuum' property. If auto-vacuum is
+** Return the value of the 'auto-vacuum' property. If auto-vacuum is
** enabled 1 is returned. Otherwise 0.
*/
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
@@ -61046,6 +67501,36 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
#endif
}
+/*
+** If the user has not set the safety-level for this database connection
+** using "PRAGMA synchronous", and if the safety-level is not already
+** set to the value passed to this function as the second parameter,
+** set it so.
+*/
+#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS \
+ && !defined(SQLITE_OMIT_WAL)
+static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
+ sqlite3 *db;
+ Db *pDb;
+ if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
+ while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
+ if( pDb->bSyncSet==0
+ && pDb->safety_level!=safety_level
+ && pDb!=&db->aDb[1]
+ ){
+ pDb->safety_level = safety_level;
+ sqlite3PagerSetFlags(pBt->pPager,
+ pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
+ }
+ }
+}
+#else
+# define setDefaultSyncFlag(pBt,safety_level)
+#endif
+
+/* Forward declaration */
+static int newDatabase(BtShared*);
+
/*
** Get a reference to pPage1 of the database file. This will
@@ -61054,14 +67539,14 @@ SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
** SQLITE_OK is returned on success. If the file is not a
** well-formed database file, then SQLITE_CORRUPT is returned.
** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
-** is returned if we run out of memory.
+** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
int rc; /* Result code from subfunctions */
MemPage *pPage1; /* Page 1 of the database file */
- int nPage; /* Number of pages in the database */
- int nPageFile = 0; /* Number of pages in the database file */
- int nPageHeader; /* Number of pages in the database according to hdr */
+ u32 nPage; /* Number of pages in the database */
+ u32 nPageFile = 0; /* Number of pages in the database file */
+ u32 nPageHeader; /* Number of pages in the database according to hdr */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pBt->pPage1==0 );
@@ -61071,13 +67556,16 @@ static int lockBtree(BtShared *pBt){
if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is
- ** a valid database file.
+ ** a valid database file.
*/
nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
- sqlite3PagerPagecount(pBt->pPager, &nPageFile);
+ sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile);
if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
nPage = nPageFile;
}
+ if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){
+ nPage = 0;
+ }
if( nPage>0 ){
u32 pageSize;
u32 usableSize;
@@ -61106,7 +67594,7 @@ static int lockBtree(BtShared *pBt){
}
/* If the write version is set to 2, this database should be accessed
- ** in WAL mode. If the log is not already open, open it now. Then
+ ** in WAL mode. If the log is not already open, open it now. Then
** return SQLITE_OK and return without populating BtShared.pPage1.
** The caller detects this and calls this function again. This is
** required as the version of page 1 currently in the page1 buffer
@@ -61119,26 +67607,15 @@ static int lockBtree(BtShared *pBt){
if( rc!=SQLITE_OK ){
goto page1_init_failed;
}else{
-#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
- sqlite3 *db;
- Db *pDb;
- if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
- while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
- if( pDb->bSyncSet==0
- && pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
- ){
- pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
- sqlite3PagerSetFlags(pBt->pPager,
- pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
- }
- }
-#endif
+ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_WAL_SYNCHRONOUS+1);
if( isOpen==0 ){
- releasePage(pPage1);
+ releasePageOne(pPage1);
return SQLITE_OK;
}
}
rc = SQLITE_NOTADB;
+ }else{
+ setDefaultSyncFlag(pBt, SQLITE_DEFAULT_SYNCHRONOUS+1);
}
#endif
@@ -61158,15 +67635,16 @@ static int lockBtree(BtShared *pBt){
/* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two
** between 512 and 65536 inclusive. */
if( ((pageSize-1)&pageSize)!=0
- || pageSize>SQLITE_MAX_PAGE_SIZE
- || pageSize<=256
+ || pageSize>SQLITE_MAX_PAGE_SIZE
+ || pageSize<=256
){
goto page1_init_failed;
}
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
assert( (pageSize & 7)==0 );
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
** integer at offset 20 is the number of bytes of space at the end of
- ** each page to reserve for extensions.
+ ** each page to reserve for extensions.
**
** EVIDENCE-OF: R-37497-42412 The size of the reserved region is
** determined by the one-byte unsigned integer found at an offset of 20
@@ -61179,7 +67657,7 @@ static int lockBtree(BtShared *pBt){
** zero and return SQLITE_OK. The caller will call this function
** again with the correct page-size.
*/
- releasePage(pPage1);
+ releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
freeTempSpace(pBt);
@@ -61187,7 +67665,7 @@ static int lockBtree(BtShared *pBt){
pageSize-usableSize);
return rc;
}
- if( (pBt->db->flags & SQLITE_RecoveryMode)==0 && nPage>nPageFile ){
+ if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
@@ -61233,7 +67711,7 @@ static int lockBtree(BtShared *pBt){
return SQLITE_OK;
page1_init_failed:
- releasePage(pPage1);
+ releasePageOne(pPage1);
pBt->pPage1 = 0;
return rc;
}
@@ -61256,7 +67734,7 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
int r = 0;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
- && pCur->eState!=CURSOR_FAULT ) r++;
+ && pCur->eState!=CURSOR_FAULT ) r++;
}
return r;
}
@@ -61265,7 +67743,7 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
/*
** If there are no outstanding cursors and we are not in the middle
** of a transaction but there is a read lock on the database, then
-** this routine unrefs the first page of the database file which
+** this routine unrefs the first page of the database file which
** has the effect of releasing the read lock.
**
** If there is a transaction in progress, this routine is a no-op.
@@ -61278,7 +67756,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){
assert( pPage1->aData );
assert( sqlite3PagerRefcount(pBt->pPager)==1 );
pBt->pPage1 = 0;
- releasePageNotNull(pPage1);
+ releasePageOne(pPage1);
}
}
@@ -61349,8 +67827,8 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
** upgraded to exclusive by calling this routine a second time - the
** exclusivity flag only works for a new transaction.
**
-** A write-transaction must be started before attempting any
-** changes to the database. None of the following routines
+** A write-transaction must be started before attempting any
+** changes to the database. None of the following routines
** will work unless a transaction is started first:
**
** sqlite3BtreeCreateTable()
@@ -61364,7 +67842,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
** If an initial attempt to acquire the lock fails because of lock contention
** and the database was previously unlocked, then invoke the busy handler
** if there is one. But if there was previously a read-lock, do not
-** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
+** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
** returned when there is already a read-lock in order to avoid a deadlock.
**
** Suppose there are two processes A and B. A has a read lock and B has
@@ -61375,8 +67853,9 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
** when A already has a read lock, we encourage A to give up and let B
** proceed.
*/
-SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
+SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
BtShared *pBt = p->pBt;
+ Pager *pPager = pBt->pPager;
int rc = SQLITE_OK;
sqlite3BtreeEnter(p);
@@ -61391,6 +67870,12 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
+ if( (p->db->flags & SQLITE_ResetDatabase)
+ && sqlite3PagerIsreadonly(pPager)==0
+ ){
+ pBt->btsFlags &= ~BTS_READ_ONLY;
+ }
+
/* Write transactions are not possible on a read-only database */
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
rc = SQLITE_READONLY;
@@ -61400,7 +67885,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
#ifndef SQLITE_OMIT_SHARED_CACHE
{
sqlite3 *pBlock = 0;
- /* If another database handle has already opened a write transaction
+ /* If another database handle has already opened a write transaction
** on this shared-btree structure and a second write transaction is
** requested, return SQLITE_LOCKED.
*/
@@ -61425,19 +67910,31 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
#endif
- /* Any read-only or read-write transaction implies a read-lock on
- ** page 1. So if some other shared-cache client already has a write-lock
+ /* Any read-only or read-write transaction implies a read-lock on
+ ** page 1. So if some other shared-cache client already has a write-lock
** on page 1, the transaction cannot be opened. */
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
do {
+ sqlite3PagerWalDb(pPager, p->db);
+
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* If transitioning from no transaction directly to a write transaction,
+ ** block for the WRITER lock first if possible. */
+ if( pBt->pPage1==0 && wrflag ){
+ assert( pBt->inTransaction==TRANS_NONE );
+ rc = sqlite3PagerWalWriteLock(pPager, 1);
+ if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
+ }
+#endif
+
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
- ** reading page 1 it discovers that the page-size of the database
+ ** reading page 1 it discovers that the page-size of the database
** file is not pBt->pageSize. In this case lockBtree() will update
** pBt->pageSize to the page-size of the file on disk.
*/
@@ -61447,18 +67944,28 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
rc = SQLITE_READONLY;
}else{
- rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
+ rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
+ }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
+ /* if there was no transaction opened when this function was
+ ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
+ ** code to SQLITE_BUSY. */
+ rc = SQLITE_BUSY;
}
}
}
-
+
if( rc!=SQLITE_OK ){
+ (void)sqlite3PagerWalWriteLock(pPager, 0);
unlockBtreeIfUnused(pBt);
}
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
btreeInvokeBusyHandler(pBt) );
+ sqlite3PagerWalDb(pPager, 0);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
+#endif
if( rc==SQLITE_OK ){
if( p->inTrans==TRANS_NONE ){
@@ -61487,7 +67994,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
/* If the db-size header field is incorrect (as it may be if an old
** client has been writing the database file), update it now. Doing
- ** this sooner rather than later means the database size can safely
+ ** this sooner rather than later means the database size can safely
** re-read the database size from page 1 if a savepoint or transaction
** rollback occurs within the transaction.
*/
@@ -61500,14 +68007,18 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
}
-
trans_begun:
- if( rc==SQLITE_OK && wrflag ){
- /* This call makes sure that the pager has the correct number of
- ** open savepoints. If the second parameter is greater than 0 and
- ** the sub-journal is not already open, then it will be opened here.
- */
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+ if( rc==SQLITE_OK ){
+ if( pSchemaVersion ){
+ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]);
+ }
+ if( wrflag ){
+ /* This call makes sure that the pager has the correct number of
+ ** open savepoints. If the second parameter is greater than 0 and
+ ** the sub-journal is not already open, then it will be opened here.
+ */
+ rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
+ }
}
btreeIntegrity(p);
@@ -61527,20 +68038,17 @@ static int setChildPtrmaps(MemPage *pPage){
int nCell; /* Number of cells in page pPage */
int rc; /* Return code */
BtShared *pBt = pPage->pBt;
- u8 isInitOrig = pPage->isInit;
Pgno pgno = pPage->pgno;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- rc = btreeInitPage(pPage);
- if( rc!=SQLITE_OK ){
- goto set_child_ptrmaps_out;
- }
+ rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
+ if( rc!=SQLITE_OK ) return rc;
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
u8 *pCell = findCell(pPage, i);
- ptrmapPutOvflPtr(pPage, pCell, &rc);
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc);
if( !pPage->leaf ){
Pgno childPgno = get4byte(pCell);
@@ -61553,8 +68061,6 @@ static int setChildPtrmaps(MemPage *pPage){
ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc);
}
-set_child_ptrmaps_out:
- pPage->isInit = isInitOrig;
return rc;
}
@@ -61563,7 +68069,7 @@ set_child_ptrmaps_out:
** that it points to iTo. Parameter eType describes the type of pointer to
** be modified, as follows:
**
-** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child
+** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child
** page of pPage.
**
** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow
@@ -61578,16 +68084,15 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( eType==PTRMAP_OVERFLOW2 ){
/* The pointer is always the first 4 bytes of the page in this case. */
if( get4byte(pPage->aData)!=iFrom ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
put4byte(pPage->aData, iTo);
}else{
- u8 isInitOrig = pPage->isInit;
int i;
int nCell;
int rc;
- rc = btreeInitPage(pPage);
+ rc = pPage->isInit ? SQLITE_OK : btreeInitPage(pPage);
if( rc ) return rc;
nCell = pPage->nCell;
@@ -61596,12 +68101,14 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( eType==PTRMAP_OVERFLOW1 ){
CellInfo info;
pPage->xParseCell(pPage, pCell, &info);
- if( info.nLocal<info.nPayload
- && pCell+info.nSize-1<=pPage->aData+pPage->maskPage
- && iFrom==get4byte(pCell+info.nSize-4)
- ){
- put4byte(pCell+info.nSize-4, iTo);
- break;
+ if( info.nLocal<info.nPayload ){
+ if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ if( iFrom==get4byte(pCell+info.nSize-4) ){
+ put4byte(pCell+info.nSize-4, iTo);
+ break;
+ }
}
}else{
if( get4byte(pCell)==iFrom ){
@@ -61610,27 +68117,25 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
}
}
-
+
if( i==nCell ){
- if( eType!=PTRMAP_BTREE ||
+ if( eType!=PTRMAP_BTREE ||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
}
-
- pPage->isInit = isInitOrig;
}
return SQLITE_OK;
}
/*
-** Move the open database page pDbPage to location iFreePage in the
+** Move the open database page pDbPage to location iFreePage in the
** database. The pDbPage reference remains valid.
**
** The isCommit flag indicates that there is no need to remember that
-** the journal needs to be sync()ed before database page pDbPage->pgno
+** the journal needs to be sync()ed before database page pDbPage->pgno
** can be written to. The caller has already promised not to write to that
** page.
*/
@@ -61647,13 +68152,14 @@ static int relocatePage(
Pager *pPager = pBt->pPager;
int rc;
- assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
+ assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pDbPage->pBt==pBt );
+ if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -61712,19 +68218,19 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
/*
** Perform a single step of an incremental-vacuum. If successful, return
-** SQLITE_OK. If there is no work to do (and therefore no point in
-** calling this function again), return SQLITE_DONE. Or, if an error
+** SQLITE_OK. If there is no work to do (and therefore no point in
+** calling this function again), return SQLITE_DONE. Or, if an error
** occurs, return some other error code.
**
-** More specifically, this function attempts to re-organize the database so
+** More specifically, this function attempts to re-organize the database so
** that the last page of the file currently in use is no longer in use.
**
** Parameter nFin is the number of pages that this database would contain
** were this function called until it returns SQLITE_DONE.
**
-** If the bCommit parameter is non-zero, this function assumes that the
-** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
-** or an error. bCommit is passed true for an auto-vacuum-on-commit
+** If the bCommit parameter is non-zero, this function assumes that the
+** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
+** or an error. bCommit is passed true for an auto-vacuum-on-commit
** operation, or false for an incremental vacuum.
*/
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
@@ -61755,7 +68261,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
if( bCommit==0 ){
/* Remove the page from the files free-list. This is not required
** if bCommit is non-zero. In that case, the free-list will be
- ** truncated to zero after this function returns, so it doesn't
+ ** truncated to zero after this function returns, so it doesn't
** matter if it still contains some garbage entries.
*/
Pgno iFreePg;
@@ -61799,7 +68305,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
releasePage(pFreePg);
}while( bCommit && iFreePg>nFin );
assert( iFreePg<iLastPg );
-
+
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit);
releasePage(pLastPg);
if( rc!=SQLITE_OK ){
@@ -61820,7 +68326,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
/*
** The database opened by the first argument is an auto-vacuum database
-** nOrig pages in size containing nFree free pages. Return the expected
+** nOrig pages in size containing nFree free pages. Return the expected
** size of the database in pages following an auto-vacuum operation.
*/
static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
@@ -61847,7 +68353,7 @@ static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
**
** If the incremental vacuum is finished after this function has run,
** SQLITE_DONE is returned. If it is not finished, but no error occurred,
-** SQLITE_OK is returned. Otherwise an SQLite error code.
+** SQLITE_OK is returned. Otherwise an SQLite error code.
*/
SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
int rc;
@@ -61862,7 +68368,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
Pgno nFin = finalDbSize(pBt, nOrig, nFree);
- if( nOrig<nFin ){
+ if( nOrig<nFin || nFree>=nOrig ){
rc = SQLITE_CORRUPT_BKPT;
}else if( nFree>0 ){
rc = saveAllCursors(pBt, 0, 0);
@@ -61887,7 +68393,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
** is committed for an auto-vacuum database.
**
** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
-** the database file should be truncated to during the commit process.
+** the database file should be truncated to during the commit process.
** i.e. the database has been reorganized so that only the first *pnTrunc
** pages are in use.
*/
@@ -61959,18 +68465,18 @@ static int autoVacuumCommit(BtShared *pBt){
**
** This call is a no-op if no write-transaction is currently active on pBt.
**
-** Otherwise, sync the database file for the btree pBt. zMaster points to
-** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
+** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to
+** the name of a super-journal file that should be written into the
+** individual journal file, or is NULL, indicating no super-journal file
** (single database transaction).
**
-** When this is called, the master journal should already have been
+** When this is called, the super-journal should already have been
** created, populated with this journal pointer and synced to disk.
**
** Once this is routine has returned, the only thing required to commit
** the write-transaction for this database file is to delete the journal.
*/
-SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
+SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){
int rc = SQLITE_OK;
if( p->inTrans==TRANS_WRITE ){
BtShared *pBt = p->pBt;
@@ -61987,7 +68493,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
}
#endif
- rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
+ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0);
sqlite3BtreeLeave(p);
}
return rc;
@@ -62012,8 +68518,8 @@ static void btreeEndTransaction(Btree *p){
downgradeAllSharedCacheTableLocks(p);
p->inTrans = TRANS_READ;
}else{
- /* If the handle had any kind of transaction open, decrement the
- ** transaction count of the shared btree. If the transaction count
+ /* If the handle had any kind of transaction open, decrement the
+ ** transaction count of the shared btree. If the transaction count
** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused()
** call below will unlock the pager. */
if( p->inTrans!=TRANS_NONE ){
@@ -62024,7 +68530,7 @@ static void btreeEndTransaction(Btree *p){
}
}
- /* Set the current transaction state to TRANS_NONE and unlock the
+ /* Set the current transaction state to TRANS_NONE and unlock the
** pager if this call closed the only read or write transaction. */
p->inTrans = TRANS_NONE;
unlockBtreeIfUnused(pBt);
@@ -62045,12 +68551,12 @@ static void btreeEndTransaction(Btree *p){
** the rollback journal (which causes the transaction to commit) and
** drop locks.
**
-** Normally, if an error occurs while the pager layer is attempting to
+** Normally, if an error occurs while the pager layer is attempting to
** finalize the underlying journal file, this function returns an error and
** the upper layer will attempt a rollback. However, if the second argument
-** is non-zero then this b-tree transaction is part of a multi-file
-** transaction. In this case, the transaction has already been committed
-** (by deleting a master journal file) and the caller will ignore this
+** is non-zero then this b-tree transaction is part of a multi-file
+** transaction. In this case, the transaction has already been committed
+** (by deleting a super-journal file) and the caller will ignore this
** functions return code. So, even if an error occurs in the pager layer,
** reset the b-tree objects internal state to indicate that the write
** transaction has been closed. This is quite safe, as the pager will have
@@ -62065,7 +68571,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
sqlite3BtreeEnter(p);
btreeIntegrity(p);
- /* If the handle has a write-transaction open, commit the shared-btrees
+ /* If the handle has a write-transaction open, commit the shared-btrees
** transaction and set the shared state to TRANS_READ.
*/
if( p->inTrans==TRANS_WRITE ){
@@ -62114,15 +68620,15 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
**
** This routine gets called when a rollback occurs. If the writeOnly
** flag is true, then only write-cursors need be tripped - read-only
-** cursors save their current positions so that they may continue
-** following the rollback. Or, if writeOnly is false, all cursors are
+** cursors save their current positions so that they may continue
+** following the rollback. Or, if writeOnly is false, all cursors are
** tripped. In general, writeOnly is false if the transaction being
** rolled back modified the database schema. In this case b-tree root
** pages may be moved or deleted from the database altogether, making
** it unsafe for read cursors to continue.
**
-** If the writeOnly flag is true and an error is encountered while
-** saving the current position of a read-only cursor, all cursors,
+** If the writeOnly flag is true and an error is encountered while
+** saving the current position of a read-only cursor, all cursors,
** including all read-cursors are tripped.
**
** SQLITE_OK is returned if successful, or if an error occurs while
@@ -62136,7 +68642,6 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
if( pBtree ){
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
- int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
if( p->eState==CURSOR_VALID || p->eState==CURSOR_SKIPNEXT ){
rc = saveCursorPosition(p);
@@ -62150,10 +68655,7 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
}
- for(i=0; i<=p->iPage; i++){
- releasePage(p->apPage[i]);
- p->apPage[i] = 0;
- }
+ btreeReleaseAllCursorPages(p);
}
sqlite3BtreeLeave(pBtree);
}
@@ -62161,6 +68663,18 @@ SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int wr
}
/*
+** Set the pBt->nPage field correctly, according to the current
+** state of the database. Assume pBt->pPage1 is valid.
+*/
+static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){
+ int nPage = get4byte(&pPage1->aData[28]);
+ testcase( nPage==0 );
+ if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
+ testcase( pBt->nPage!=nPage );
+ pBt->nPage = nPage;
+}
+
+/*
** Rollback the transaction in progress.
**
** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped).
@@ -62205,12 +68719,8 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
- int nPage = get4byte(28+(u8*)pPage1->aData);
- testcase( nPage==0 );
- if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
- testcase( pBt->nPage!=nPage );
- pBt->nPage = nPage;
- releasePage(pPage1);
+ btreeSetNPage(pBt, pPage1);
+ releasePageOne(pPage1);
}
assert( countValidCursors(pBt, 1)==0 );
pBt->inTransaction = TRANS_READ;
@@ -62224,8 +68734,8 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
/*
** Start a statement subtransaction. The subtransaction can be rolled
-** back independently of the main transaction. You must start a transaction
-** before starting a subtransaction. The subtransaction is ended automatically
+** back independently of the main transaction. You must start a transaction
+** before starting a subtransaction. The subtransaction is ended automatically
** if the main transaction commits or rolls back.
**
** Statement subtransactions are used around individual SQL statements
@@ -62262,11 +68772,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
/*
** The second argument to this function, op, is always SAVEPOINT_ROLLBACK
** or SAVEPOINT_RELEASE. This function either releases or rolls back the
-** savepoint identified by parameter iSavepoint, depending on the value
+** savepoint identified by parameter iSavepoint, depending on the value
** of op.
**
** Normally, iSavepoint is greater than or equal to zero. However, if op is
-** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
+** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
** contents of the entire transaction are rolled back. This is different
** from a normal transaction rollback, as no locks are released and the
** transaction remains open.
@@ -62278,18 +68788,22 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
assert( iSavepoint>=0 || (iSavepoint==-1 && op==SAVEPOINT_ROLLBACK) );
sqlite3BtreeEnter(p);
- rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
+ if( op==SAVEPOINT_ROLLBACK ){
+ rc = saveAllCursors(pBt, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
+ }
if( rc==SQLITE_OK ){
if( iSavepoint<0 && (pBt->btsFlags & BTS_INITIALLY_EMPTY)!=0 ){
pBt->nPage = 0;
}
rc = newDatabase(pBt);
- pBt->nPage = get4byte(28 + pBt->pPage1->aData);
+ btreeSetNPage(pBt, pBt->pPage1);
- /* The database size was written into the offset 28 of the header
- ** when the transaction started, so we know that the value at offset
- ** 28 is nonzero. */
- assert( pBt->nPage>0 );
+ /* pBt->nPage might be zero if the database was corrupt when
+ ** the transaction was started. Otherwise, it must be at least 1. */
+ assert( CORRUPT_DB || pBt->nPage>0 );
}
sqlite3BtreeLeave(p);
}
@@ -62325,10 +68839,10 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
** is set. If FORDELETE is set, that is a hint to the implementation that
** this cursor will only be used to seek to and delete entries of an index
** as part of a larger DELETE statement. The FORDELETE hint is not used by
-** this implementation. But in a hypothetical alternative storage engine
+** this implementation. But in a hypothetical alternative storage engine
** in which index entries are automatically deleted when corresponding table
** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE
-** operations on this cursor can be no-ops and all READ operations can
+** operations on this cursor can be no-ops and all READ operations can
** return a null row (2-bytes: 0x01 0x00).
**
** No checking is done to make sure that page iTable really is the
@@ -62340,7 +68854,7 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
*/
static int btreeCursor(
Btree *p, /* The btree */
- int iTable, /* Root page of table to open */
+ Pgno iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
BtCursor *pCur /* Space for new cursor */
@@ -62349,16 +68863,17 @@ static int btreeCursor(
BtCursor *pX; /* Looping over other all cursors */
assert( sqlite3BtreeHoldsMutex(p) );
- assert( wrFlag==0
- || wrFlag==BTREE_WRCSR
- || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE)
+ assert( wrFlag==0
+ || wrFlag==BTREE_WRCSR
+ || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE)
);
- /* The following assert statements verify that if this is a sharable
- ** b-tree database, the connection is holding the required table locks,
- ** and that no other connection has any open cursor that conflicts with
- ** this lock. */
- assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) );
+ /* The following assert statements verify that if this is a sharable
+ ** b-tree database, the connection is holding the required table locks,
+ ** and that no other connection has any open cursor that conflicts with
+ ** this lock. The iTable<1 term disables the check for corrupt schemas. */
+ assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1))
+ || iTable<1 );
assert( wrFlag==0 || !hasReadConflicts(p, iTable) );
/* Assert that the caller has opened the required transaction. */
@@ -62371,14 +68886,18 @@ static int btreeCursor(
allocateTempSpace(pBt);
if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
}
- if( iTable==1 && btreePagecount(pBt)==0 ){
- assert( wrFlag==0 );
- iTable = 0;
+ if( iTable<=1 ){
+ if( iTable<1 ){
+ return SQLITE_CORRUPT_BKPT;
+ }else if( btreePagecount(pBt)==0 ){
+ assert( wrFlag==0 );
+ iTable = 0;
+ }
}
/* Now that no other errors can occur, finish filling in the BtCursor
** variables and link the cursor into the BtShared list. */
- pCur->pgnoRoot = (Pgno)iTable;
+ pCur->pgnoRoot = iTable;
pCur->iPage = -1;
pCur->pKeyInfo = pKeyInfo;
pCur->pBtree = p;
@@ -62388,7 +68907,7 @@ static int btreeCursor(
/* If there are two or more cursors on the same btree, then all such
** cursors *must* have the BTCF_Multiple flag set. */
for(pX=pBt->pCursor; pX; pX=pX->pNext){
- if( pX->pgnoRoot==(Pgno)iTable ){
+ if( pX->pgnoRoot==iTable ){
pX->curFlags |= BTCF_Multiple;
pCur->curFlags |= BTCF_Multiple;
}
@@ -62398,22 +68917,31 @@ static int btreeCursor(
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}
+static int btreeCursorWithLock(
+ Btree *p, /* The btree */
+ Pgno iTable, /* Root page of table to open */
+ int wrFlag, /* 1 to write. 0 read-only */
+ struct KeyInfo *pKeyInfo, /* First arg to comparison function */
+ BtCursor *pCur /* Space for new cursor */
+){
+ int rc;
+ sqlite3BtreeEnter(p);
+ rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
+ sqlite3BtreeLeave(p);
+ return rc;
+}
SQLITE_PRIVATE int sqlite3BtreeCursor(
Btree *p, /* The btree */
- int iTable, /* Root page of table to open */
+ Pgno iTable, /* Root page of table to open */
int wrFlag, /* 1 to write. 0 read-only */
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
BtCursor *pCur /* Write new cursor here */
){
- int rc;
- if( iTable<1 ){
- rc = SQLITE_CORRUPT_BKPT;
+ if( p->sharable ){
+ return btreeCursorWithLock(p, iTable, wrFlag, pKeyInfo, pCur);
}else{
- sqlite3BtreeEnter(p);
- rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
- sqlite3BtreeLeave(p);
+ return btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur);
}
- return rc;
}
/*
@@ -62437,7 +68965,7 @@ SQLITE_PRIVATE int sqlite3BtreeCursorSize(void){
** of run-time by skipping the initialization of those elements.
*/
SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){
- memset(p, 0, offsetof(BtCursor, iPage));
+ memset(p, 0, offsetof(BtCursor, BTCURSOR_FIRST_UNINIT));
}
/*
@@ -62447,10 +68975,8 @@ SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor *p){
SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
Btree *pBtree = pCur->pBtree;
if( pBtree ){
- int i;
BtShared *pBt = pCur->pBt;
sqlite3BtreeEnter(pBtree);
- sqlite3BtreeClearCursor(pCur);
assert( pBt->pCursor!=0 );
if( pBt->pCursor==pCur ){
pBt->pCursor = pCur->pNext;
@@ -62464,13 +68990,12 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
pPrev = pPrev->pNext;
}while( ALWAYS(pPrev) );
}
- for(i=0; i<=pCur->iPage; i++){
- releasePage(pCur->apPage[i]);
- }
+ btreeReleaseAllCursorPages(pCur);
unlockBtreeIfUnused(pBt);
sqlite3_free(pCur->aOverflow);
- /* sqlite3_free(pCur); */
+ sqlite3_free(pCur->pKey);
sqlite3BtreeLeave(pBtree);
+ pCur->pBtree = 0;
}
return SQLITE_OK;
}
@@ -62484,21 +69009,27 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
** Using this cache reduces the number of calls to btreeParseCell().
*/
#ifndef NDEBUG
+ static int cellInfoEqual(CellInfo *a, CellInfo *b){
+ if( a->nKey!=b->nKey ) return 0;
+ if( a->pPayload!=b->pPayload ) return 0;
+ if( a->nPayload!=b->nPayload ) return 0;
+ if( a->nLocal!=b->nLocal ) return 0;
+ if( a->nSize!=b->nSize ) return 0;
+ return 1;
+ }
static void assertCellInfo(BtCursor *pCur){
CellInfo info;
- int iPage = pCur->iPage;
memset(&info, 0, sizeof(info));
- btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info);
- assert( CORRUPT_DB || memcmp(&info, &pCur->info, sizeof(info))==0 );
+ btreeParseCell(pCur->pPage, pCur->ix, &info);
+ assert( CORRUPT_DB || cellInfoEqual(&info, &pCur->info) );
}
#else
#define assertCellInfo(x)
#endif
static SQLITE_NOINLINE void getCellInfo(BtCursor *pCur){
if( pCur->info.nSize==0 ){
- int iPage = pCur->iPage;
pCur->curFlags |= BTCF_ValidNKey;
- btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info);
+ btreeParseCell(pCur->pPage,pCur->ix,&pCur->info);
}else{
assertCellInfo(pCur);
}
@@ -62514,6 +69045,10 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
return pCur && pCur->eState==CURSOR_VALID;
}
#endif /* NDEBUG */
+SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){
+ assert( pCur!=0 );
+ return pCur->eState==CURSOR_VALID;
+}
/*
** Return the value of the integer key or "rowid" for a table btree.
@@ -62530,6 +69065,32 @@ SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
}
/*
+** Pin or unpin a cursor.
+*/
+SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor *pCur){
+ assert( (pCur->curFlags & BTCF_Pinned)==0 );
+ pCur->curFlags |= BTCF_Pinned;
+}
+SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *pCur){
+ assert( (pCur->curFlags & BTCF_Pinned)!=0 );
+ pCur->curFlags &= ~BTCF_Pinned;
+}
+
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+/*
+** Return the offset into the database file for the start of the
+** payload to which the cursor is pointing.
+*/
+SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ assert( pCur->eState==CURSOR_VALID );
+ getCellInfo(pCur);
+ return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
+ (i64)(pCur->info.pPayload - pCur->pPage->aData);
+}
+#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
+
+/*
** Return the number of bytes of payload for the entry that pCur is
** currently pointing to. For table btrees, this will be the amount
** of data. For index btrees, this will be the size of the key.
@@ -62546,16 +69107,35 @@ SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){
}
/*
+** Return an upper bound on the size of any record for the table
+** that the cursor is pointing into.
+**
+** This is an optimization. Everything will still work if this
+** routine always returns 2147483647 (which is the largest record
+** that SQLite can handle) or more. But returning a smaller value might
+** prevent large memory allocations when trying to interpret a
+** corrupt datrabase.
+**
+** The current implementation merely returns the size of the underlying
+** database file.
+*/
+SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
+ assert( pCur->eState==CURSOR_VALID );
+ return pCur->pBt->pageSize * (sqlite3_int64)pCur->pBt->nPage;
+}
+
+/*
** Given the page number of an overflow page in the database (parameter
-** ovfl), this function finds the page number of the next page in the
+** ovfl), this function finds the page number of the next page in the
** linked list of overflow pages. If possible, it uses the auto-vacuum
-** pointer-map data instead of reading the content of page ovfl to do so.
+** pointer-map data instead of reading the content of page ovfl to do so.
**
** If an error occurs an SQLite error code is returned. Otherwise:
**
-** The page number of the next overflow page in the linked list is
-** written to *pPgnoNext. If page ovfl is the last page in its linked
-** list, *pPgnoNext is set to zero.
+** The page number of the next overflow page in the linked list is
+** written to *pPgnoNext. If page ovfl is the last page in its linked
+** list, *pPgnoNext is set to zero.
**
** If ppPage is not NULL, and a reference to the MemPage object corresponding
** to page number pOvfl was obtained, then *ppPage is set to point to that
@@ -62579,9 +69159,9 @@ static int getOverflowPage(
#ifndef SQLITE_OMIT_AUTOVACUUM
/* Try to find the next page in the overflow list using the
- ** autovacuum pointer-map pages. Guess that the next page in
- ** the overflow list is page number (ovfl+1). If that guess turns
- ** out to be wrong, fall back to loading the data of page
+ ** autovacuum pointer-map pages. Guess that the next page in
+ ** the overflow list is page number (ovfl+1). If that guess turns
+ ** out to be wrong, fall back to loading the data of page
** number ovfl to determine the next page number.
*/
if( pBt->autoVacuum ){
@@ -62660,7 +69240,6 @@ static int copyPayload(
**
** 0: The operation is a read. Populate the overflow cache.
** 1: The operation is a write. Populate the overflow cache.
-** 2: The operation is a read. Do not populate the overflow cache.
**
** A total of "amt" bytes are read or written beginning at "offset".
** Data is read to or from the buffer pBuf.
@@ -62668,13 +69247,13 @@ static int copyPayload(
** The content being read or written might appear on the main page
** or be scattered out on multiple overflow pages.
**
-** If the current cursor entry uses one or more overflow pages and the
-** eOp argument is not 2, this function may allocate space for and lazily
-** populates the overflow page-list cache array (BtCursor.aOverflow).
-** Subsequent calls use this cache to make seeking to the supplied offset
+** If the current cursor entry uses one or more overflow pages
+** this function may allocate space for and lazily populate
+** the overflow page-list cache array (BtCursor.aOverflow).
+** Subsequent calls use this cache to make seeking to the supplied offset
** more efficient.
**
-** Once an overflow page-list cache has been allocated, it may be
+** Once an overflow page-list cache has been allocated, it must be
** invalidated if some other cursor writes to the same table, or if
** the cursor is moved to a different row. Additionally, in auto-vacuum
** mode, the following events may invalidate an overflow page-list cache.
@@ -62687,30 +69266,26 @@ static int accessPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
u32 offset, /* Begin reading this far into payload */
u32 amt, /* Read this many bytes */
- unsigned char *pBuf, /* Write the bytes into this buffer */
+ unsigned char *pBuf, /* Write the bytes into this buffer */
int eOp /* zero to read. non-zero to write. */
){
unsigned char *aPayload;
int rc = SQLITE_OK;
int iIdx = 0;
- MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */
+ MemPage *pPage = pCur->pPage; /* Btree page of current entry */
BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */
#ifdef SQLITE_DIRECT_OVERFLOW_READ
- unsigned char * const pBufStart = pBuf;
- int bEnd; /* True if reading to end of data */
+ unsigned char * const pBufStart = pBuf; /* Start of original out buffer */
#endif
assert( pPage );
+ assert( eOp==0 || eOp==1 );
assert( pCur->eState==CURSOR_VALID );
- assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
+ assert( pCur->ix<pPage->nCell );
assert( cursorHoldsMutex(pCur) );
- assert( eOp!=2 || offset==0 ); /* Always start from beginning for eOp==2 */
getCellInfo(pCur);
aPayload = pCur->info.pPayload;
-#ifdef SQLITE_DIRECT_OVERFLOW_READ
- bEnd = offset+amt==pCur->info.nPayload;
-#endif
assert( offset+amt <= pCur->info.nPayload );
assert( aPayload > pPage->aData );
@@ -62720,7 +69295,7 @@ static int accessPayload(
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
** but is recast into its current form to avoid integer overflow problems
*/
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* Check if data must be read/written to/from the btree page itself. */
@@ -62729,7 +69304,7 @@ static int accessPayload(
if( a+offset>pCur->info.nLocal ){
a = pCur->info.nLocal - offset;
}
- rc = copyPayload(&aPayload[offset], pBuf, a, (eOp & 0x01), pPage->pDbPage);
+ rc = copyPayload(&aPayload[offset], pBuf, a, eOp, pPage->pDbPage);
offset = 0;
pBuf += a;
amt -= a;
@@ -62745,53 +69320,48 @@ static int accessPayload(
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
/* If the BtCursor.aOverflow[] has not been allocated, allocate it now.
- ** Except, do not allocate aOverflow[] for eOp==2.
**
** The aOverflow[] array is sized at one entry for each overflow page
** in the overflow chain. The page number of the first overflow page is
** stored in aOverflow[0], etc. A value of 0 in the aOverflow[] array
** means "not yet known" (the cache is lazily populated).
*/
- if( eOp!=2 && (pCur->curFlags & BTCF_ValidOvfl)==0 ){
+ if( (pCur->curFlags & BTCF_ValidOvfl)==0 ){
int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
- if( nOvfl>pCur->nOvflAlloc ){
+ if( pCur->aOverflow==0
+ || nOvfl*(int)sizeof(Pgno) > sqlite3MallocSize(pCur->aOverflow)
+ ){
Pgno *aNew = (Pgno*)sqlite3Realloc(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
- rc = SQLITE_NOMEM_BKPT;
+ return SQLITE_NOMEM_BKPT;
}else{
- pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
}
}
- if( rc==SQLITE_OK ){
- memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
- pCur->curFlags |= BTCF_ValidOvfl;
+ memset(pCur->aOverflow, 0, nOvfl*sizeof(Pgno));
+ pCur->curFlags |= BTCF_ValidOvfl;
+ }else{
+ /* If the overflow page-list cache has been allocated and the
+ ** entry for the first required overflow page is valid, skip
+ ** directly to it.
+ */
+ if( pCur->aOverflow[offset/ovflSize] ){
+ iIdx = (offset/ovflSize);
+ nextPage = pCur->aOverflow[iIdx];
+ offset = (offset%ovflSize);
}
}
- /* If the overflow page-list cache has been allocated and the
- ** entry for the first required overflow page is valid, skip
- ** directly to it.
- */
- if( (pCur->curFlags & BTCF_ValidOvfl)!=0
- && pCur->aOverflow[offset/ovflSize]
- ){
- iIdx = (offset/ovflSize);
- nextPage = pCur->aOverflow[iIdx];
- offset = (offset%ovflSize);
- }
-
- for( ; rc==SQLITE_OK && amt>0 && nextPage; iIdx++){
-
+ assert( rc==SQLITE_OK && amt>0 );
+ while( nextPage ){
/* If required, populate the overflow page-list cache. */
- if( (pCur->curFlags & BTCF_ValidOvfl)!=0 ){
- assert( pCur->aOverflow[iIdx]==0
- || pCur->aOverflow[iIdx]==nextPage
- || CORRUPT_DB );
- pCur->aOverflow[iIdx] = nextPage;
- }
+ if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
+ assert( pCur->aOverflow[iIdx]==0
+ || pCur->aOverflow[iIdx]==nextPage
+ || CORRUPT_DB );
+ pCur->aOverflow[iIdx] = nextPage;
if( offset>=ovflSize ){
/* The only reason to read this page is to obtain the page
@@ -62799,11 +69369,7 @@ static int accessPayload(
** data is not required. So first try to lookup the overflow
** page-list cache, if any, then fall back to the getOverflowPage()
** function.
- **
- ** Note that the aOverflow[] array must be allocated because eOp!=2
- ** here. If eOp==2, then offset==0 and this branch is never taken.
*/
- assert( eOp!=2 );
assert( pCur->curFlags & BTCF_ValidOvfl );
assert( pCur->pBtree->db==pBt->db );
if( pCur->aOverflow[iIdx+1] ){
@@ -62816,9 +69382,6 @@ static int accessPayload(
/* Need to read this page properly. It contains some of the
** range of data that is being read (eOp==0) or written (eOp!=0).
*/
-#ifdef SQLITE_DIRECT_OVERFLOW_READ
- sqlite3_file *fd;
-#endif
int a = amt;
if( a + offset > ovflSize ){
a = ovflSize - offset;
@@ -62827,31 +69390,29 @@ static int accessPayload(
#ifdef SQLITE_DIRECT_OVERFLOW_READ
/* If all the following are true:
**
- ** 1) this is a read operation, and
+ ** 1) this is a read operation, and
** 2) data is required from the start of this overflow page, and
- ** 3) the database is file-backed, and
- ** 4) there is no open write-transaction, and
- ** 5) the database is not a WAL database,
- ** 6) all data from the page is being read.
- ** 7) at least 4 bytes have already been read into the output buffer
+ ** 3) there are no dirty pages in the page-cache
+ ** 4) the database is file-backed, and
+ ** 5) the page is not in the WAL file
+ ** 6) at least 4 bytes have already been read into the output buffer
**
** then data can be read directly from the database file into the
** output buffer, bypassing the page-cache altogether. This speeds
** up loading large records that span many overflow pages.
*/
- if( (eOp&0x01)==0 /* (1) */
+ if( eOp==0 /* (1) */
&& offset==0 /* (2) */
- && (bEnd || a==ovflSize) /* (6) */
- && pBt->inTransaction==TRANS_READ /* (4) */
- && (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
- && 0==sqlite3PagerUseWal(pBt->pPager) /* (5) */
- && &pBuf[-4]>=pBufStart /* (7) */
+ && sqlite3PagerDirectReadOk(pBt->pPager, nextPage) /* (3,4,5) */
+ && &pBuf[-4]>=pBufStart /* (6) */
){
+ sqlite3_file *fd = sqlite3PagerFile(pBt->pPager);
u8 aSave[4];
u8 *aWrite = &pBuf[-4];
- assert( aWrite>=pBufStart ); /* hence (7) */
+ assert( aWrite>=pBufStart ); /* due to (6) */
memcpy(aSave, aWrite, 4);
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
+ if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
@@ -62860,79 +69421,89 @@ static int accessPayload(
{
DbPage *pDbPage;
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage,
- ((eOp&0x01)==0 ? PAGER_GET_READONLY : 0)
+ (eOp==0 ? PAGER_GET_READONLY : 0)
);
if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload);
- rc = copyPayload(&aPayload[offset+4], pBuf, a, (eOp&0x01), pDbPage);
+ rc = copyPayload(&aPayload[offset+4], pBuf, a, eOp, pDbPage);
sqlite3PagerUnref(pDbPage);
offset = 0;
}
}
amt -= a;
+ if( amt==0 ) return rc;
pBuf += a;
}
+ if( rc ) break;
+ iIdx++;
}
}
if( rc==SQLITE_OK && amt>0 ){
- return SQLITE_CORRUPT_BKPT;
+ /* Overflow chain ends prematurely */
+ return SQLITE_CORRUPT_PAGE(pPage);
}
return rc;
}
/*
-** Read part of the key associated with cursor pCur. Exactly
-** "amt" bytes will be transferred into pBuf[]. The transfer
+** Read part of the payload for the row at which that cursor pCur is currently
+** pointing. "amt" bytes will be transferred into pBuf[]. The transfer
** begins at "offset".
**
-** The caller must ensure that pCur is pointing to a valid row
-** in the table.
+** pCur can be pointing to either a table or an index b-tree.
+** If pointing to a table btree, then the content section is read. If
+** pCur is pointing to an index b-tree then the key section is read.
+**
+** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing
+** to a valid row in the table. For sqlite3BtreePayloadChecked(), the
+** cursor might be invalid or might need to be restored before being read.
**
** Return SQLITE_OK on success or an error code if anything goes
** wrong. An error is returned if "offset+amt" is larger than
** the available payload.
*/
-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
+SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
- assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->iPage>=0 && pCur->pPage );
+ assert( pCur->ix<pCur->pPage->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
/*
-** Read part of the data associated with cursor pCur. Exactly
-** "amt" bytes will be transfered into pBuf[]. The transfer
-** begins at "offset".
-**
-** Return SQLITE_OK on success or an error code if anything goes
-** wrong. An error is returned if "offset+amt" is larger than
-** the available payload.
+** This variant of sqlite3BtreePayload() works even if the cursor has not
+** in the CURSOR_VALID state. It is only used by the sqlite3_blob_read()
+** interface.
*/
-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- int rc;
-
#ifndef SQLITE_OMIT_INCRBLOB
+static SQLITE_NOINLINE int accessPayloadChecked(
+ BtCursor *pCur,
+ u32 offset,
+ u32 amt,
+ void *pBuf
+){
+ int rc;
if ( pCur->eState==CURSOR_INVALID ){
return SQLITE_ABORT;
}
-#endif
-
assert( cursorOwnsBtShared(pCur) );
- rc = restoreCursorPosition(pCur);
- if( rc==SQLITE_OK ){
- assert( pCur->eState==CURSOR_VALID );
- assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
- assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
- rc = accessPayload(pCur, offset, amt, pBuf, 0);
+ rc = btreeRestoreCursorPosition(pCur);
+ return rc ? rc : accessPayload(pCur, offset, amt, pBuf, 0);
+}
+SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
+ if( pCur->eState==CURSOR_VALID ){
+ assert( cursorOwnsBtShared(pCur) );
+ return accessPayload(pCur, offset, amt, pBuf, 0);
+ }else{
+ return accessPayloadChecked(pCur, offset, amt, pBuf);
}
- return rc;
}
+#endif /* SQLITE_OMIT_INCRBLOB */
/*
-** Return a pointer to payload information from the entry that the
+** Return a pointer to payload information from the entry that the
** pCur cursor is pointing to. The pointer is to the beginning of
** the key if index btrees (pPage->intKey==0) and is the data for
** table btrees (pPage->intKey==1). The number of bytes of available
@@ -62954,18 +69525,23 @@ static const void *fetchPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
u32 *pAmt /* Write the number of available bytes here */
){
- u32 amt;
- assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]);
+ int amt;
+ assert( pCur!=0 && pCur->iPage>=0 && pCur->pPage);
assert( pCur->eState==CURSOR_VALID );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorOwnsBtShared(pCur) );
- assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
+ assert( pCur->ix<pCur->pPage->nCell );
assert( pCur->info.nSize>0 );
- assert( pCur->info.pPayload>pCur->apPage[pCur->iPage]->aData || CORRUPT_DB );
- assert( pCur->info.pPayload<pCur->apPage[pCur->iPage]->aDataEnd ||CORRUPT_DB);
- amt = (int)(pCur->apPage[pCur->iPage]->aDataEnd - pCur->info.pPayload);
- if( pCur->info.nLocal<amt ) amt = pCur->info.nLocal;
- *pAmt = amt;
+ assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
+ assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
+ amt = pCur->info.nLocal;
+ if( amt>(int)(pCur->pPage->aDataEnd - pCur->info.pPayload) ){
+ /* There is too little space on the page for the expected amount
+ ** of local content. Database must be corrupt. */
+ assert( CORRUPT_DB );
+ amt = MAX(0, (int)(pCur->pPage->aDataEnd - pCur->info.pPayload));
+ }
+ *pAmt = (u32)amt;
return (void*)pCur->info.pPayload;
}
@@ -63010,15 +69586,16 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
}
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ pCur->aiIdx[pCur->iPage] = pCur->ix;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
+ pCur->ix = 0;
pCur->iPage++;
- pCur->aiIdx[pCur->iPage] = 0;
- return getAndInitPage(pBt, newPgno, &pCur->apPage[pCur->iPage],
- pCur, pCur->curPagerFlags);
+ return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
}
-#if SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
/*
-** Page pParent is an internal (non-leaf) tree page. This function
+** Page pParent is an internal (non-leaf) tree page. This function
** asserts that page number iChild is the left-child if the iIdx'th
** cell in page pParent. Or, if iIdx is equal to the total number of
** cells in pParent, that page number iChild is the right-child of
@@ -63035,7 +69612,7 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
}
}
#else
-# define assertParentIndex(x,y,z)
+# define assertParentIndex(x,y,z)
#endif
/*
@@ -63047,19 +69624,23 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
+ MemPage *pLeaf;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>0 );
- assert( pCur->apPage[pCur->iPage] );
+ assert( pCur->pPage );
assertParentIndex(
- pCur->apPage[pCur->iPage-1],
- pCur->aiIdx[pCur->iPage-1],
- pCur->apPage[pCur->iPage]->pgno
+ pCur->apPage[pCur->iPage-1],
+ pCur->aiIdx[pCur->iPage-1],
+ pCur->pPage->pgno
);
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
+ pCur->ix = pCur->aiIdx[pCur->iPage-1];
+ pLeaf = pCur->pPage;
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ releasePageNotNull(pLeaf);
}
/*
@@ -63067,19 +69648,19 @@ static void moveToParent(BtCursor *pCur){
**
** If the table has a virtual root page, then the cursor is moved to point
** to the virtual root page instead of the actual root page. A table has a
-** virtual root page when the actual root page contains no cells and a
+** virtual root page when the actual root page contains no cells and a
** single child page. This can only happen with the table rooted at page 1.
**
-** If the b-tree structure is empty, the cursor state is set to
-** CURSOR_INVALID. Otherwise, the cursor is set to point to the first
-** cell located on the root (or virtual root) page and the cursor state
-** is set to CURSOR_VALID.
+** If the b-tree structure is empty, the cursor state is set to
+** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise,
+** the cursor is set to point to the first cell located on the root
+** (or virtual root) page and the cursor state is set to CURSOR_VALID.
**
** If this function returns successfully, it may be assumed that the
-** page-header flags indicate that the [virtual] root-page is the expected
+** page-header flags indicate that the [virtual] root-page is the expected
** kind of b-tree page (i.e. if when opening the cursor the caller did not
** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D,
-** indicating a table b-tree, or if the caller did specify a KeyInfo
+** indicating a table b-tree, or if the caller did specify a KeyInfo
** structure the flags byte is set to 0x02 or 0x0A, indicating an index
** b-tree).
*/
@@ -63091,55 +69672,63 @@ static int moveToRoot(BtCursor *pCur){
assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
assert( CURSOR_VALID < CURSOR_REQUIRESEEK );
assert( CURSOR_FAULT > CURSOR_REQUIRESEEK );
- if( pCur->eState>=CURSOR_REQUIRESEEK ){
- if( pCur->eState==CURSOR_FAULT ){
- assert( pCur->skipNext!=SQLITE_OK );
- return pCur->skipNext;
- }
- sqlite3BtreeClearCursor(pCur);
- }
+ assert( pCur->eState < CURSOR_REQUIRESEEK || pCur->iPage<0 );
+ assert( pCur->pgnoRoot>0 || pCur->iPage<0 );
if( pCur->iPage>=0 ){
- while( pCur->iPage ){
- assert( pCur->apPage[pCur->iPage]!=0 );
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
+ if( pCur->iPage ){
+ releasePageNotNull(pCur->pPage);
+ while( --pCur->iPage ){
+ releasePageNotNull(pCur->apPage[pCur->iPage]);
+ }
+ pCur->pPage = pCur->apPage[0];
+ goto skip_init;
}
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
- return SQLITE_OK;
+ return SQLITE_EMPTY;
}else{
assert( pCur->iPage==(-1) );
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->apPage[0],
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
+ if( pCur->eState==CURSOR_FAULT ){
+ assert( pCur->skipNext!=SQLITE_OK );
+ return pCur->skipNext;
+ }
+ sqlite3BtreeClearCursor(pCur);
+ }
+ rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
}
pCur->iPage = 0;
- pCur->curIntKey = pCur->apPage[0]->intKey;
+ pCur->curIntKey = pCur->pPage->intKey;
}
- pRoot = pCur->apPage[0];
+ pRoot = pCur->pPage;
assert( pRoot->pgno==pCur->pgnoRoot );
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
** expected to open it on an index b-tree. Otherwise, if pKeyInfo is
** NULL, the caller expects a table b-tree. If this is not the case,
- ** return an SQLITE_CORRUPT error.
+ ** return an SQLITE_CORRUPT error.
**
** Earlier versions of SQLite assumed that this test could not fail
** if the root page was already loaded when this function was called (i.e.
- ** if pCur->iPage>=0). But this is not so if the database is corrupted
- ** in such a way that page pRoot is linked into a second b-tree table
+ ** if pCur->iPage>=0). But this is not so if the database is corrupted
+ ** in such a way that page pRoot is linked into a second b-tree table
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_PAGE(pCur->pPage);
}
- pCur->aiIdx[0] = 0;
+skip_init:
+ pCur->ix = 0;
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
+ pRoot = pCur->pPage;
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
@@ -63150,6 +69739,7 @@ static int moveToRoot(BtCursor *pCur){
rc = moveToChild(pCur, subpage);
}else{
pCur->eState = CURSOR_INVALID;
+ rc = SQLITE_EMPTY;
}
return rc;
}
@@ -63168,9 +69758,9 @@ static int moveToLeftmost(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( rc==SQLITE_OK && !(pPage = pCur->apPage[pCur->iPage])->leaf ){
- assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
- pgno = get4byte(findCell(pPage, pCur->aiIdx[pCur->iPage]));
+ while( rc==SQLITE_OK && !(pPage = pCur->pPage)->leaf ){
+ assert( pCur->ix<pPage->nCell );
+ pgno = get4byte(findCell(pPage, pCur->ix));
rc = moveToChild(pCur, pgno);
}
return rc;
@@ -63193,13 +69783,13 @@ static int moveToRightmost(BtCursor *pCur){
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
- while( !(pPage = pCur->apPage[pCur->iPage])->leaf ){
+ while( !(pPage = pCur->pPage)->leaf ){
pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- pCur->aiIdx[pCur->iPage] = pPage->nCell;
+ pCur->ix = pPage->nCell;
rc = moveToChild(pCur, pgno);
if( rc ) return rc;
}
- pCur->aiIdx[pCur->iPage] = pPage->nCell-1;
+ pCur->ix = pPage->nCell-1;
assert( pCur->info.nSize==0 );
assert( (pCur->curFlags & BTCF_ValidNKey)==0 );
return SQLITE_OK;
@@ -63216,14 +69806,13 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
- if( pCur->eState==CURSOR_INVALID ){
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- *pRes = 1;
- }else{
- assert( pCur->apPage[pCur->iPage]->nCell>0 );
- *pRes = 0;
- rc = moveToLeftmost(pCur);
- }
+ assert( pCur->pPage->nCell>0 );
+ *pRes = 0;
+ rc = moveToLeftmost(pCur);
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
}
return rc;
}
@@ -63234,49 +69823,48 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*/
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
int rc;
-
+
assert( cursorOwnsBtShared(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
/* If the cursor already points to the last entry, this is a no-op. */
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
#ifdef SQLITE_DEBUG
- /* This block serves to assert() that the cursor really does point
+ /* This block serves to assert() that the cursor really does point
** to the last entry in the b-tree. */
int ii;
for(ii=0; ii<pCur->iPage; ii++){
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
}
- assert( pCur->aiIdx[pCur->iPage]==pCur->apPage[pCur->iPage]->nCell-1 );
- assert( pCur->apPage[pCur->iPage]->leaf );
+ assert( pCur->ix==pCur->pPage->nCell-1 );
+ assert( pCur->pPage->leaf );
#endif
+ *pRes = 0;
return SQLITE_OK;
}
rc = moveToRoot(pCur);
if( rc==SQLITE_OK ){
- if( CURSOR_INVALID==pCur->eState ){
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- *pRes = 1;
+ assert( pCur->eState==CURSOR_VALID );
+ *pRes = 0;
+ rc = moveToRightmost(pCur);
+ if( rc==SQLITE_OK ){
+ pCur->curFlags |= BTCF_AtLast;
}else{
- assert( pCur->eState==CURSOR_VALID );
- *pRes = 0;
- rc = moveToRightmost(pCur);
- if( rc==SQLITE_OK ){
- pCur->curFlags |= BTCF_AtLast;
- }else{
- pCur->curFlags &= ~BTCF_AtLast;
- }
-
+ pCur->curFlags &= ~BTCF_AtLast;
}
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
}
return rc;
}
-/* Move the cursor so that it points to an entry near the key
+/* Move the cursor so that it points to an entry near the key
** specified by pIdxKey or intKey. Return a success code.
**
-** For INTKEY tables, the intKey parameter is used. pIdxKey
+** For INTKEY tables, the intKey parameter is used. pIdxKey
** must be NULL. For index tables, pIdxKey is used and intKey
** is ignored.
**
@@ -63286,7 +69874,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
** before or after the key.
**
** An integer is written into *pRes which is the result of
-** comparing the key with the entry to which the cursor is
+** comparing the key with the entry to which the cursor is
** pointing. The meaning of the integer written into
** *pRes is as follows:
**
@@ -63301,7 +69889,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
** is larger than intKey/pIdxKey.
**
** For index tables, the pIdxKey->eqSeen field is set to 1 if there
-** exists an entry in the table that exactly matches pIdxKey.
+** exists an entry in the table that exactly matches pIdxKey.
*/
SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
BtCursor *pCur, /* The cursor to be moved */
@@ -63328,17 +69916,37 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
*pRes = 0;
return SQLITE_OK;
}
- if( (pCur->curFlags & BTCF_AtLast)!=0 && pCur->info.nKey<intKey ){
- *pRes = -1;
- return SQLITE_OK;
+ if( pCur->info.nKey<intKey ){
+ if( (pCur->curFlags & BTCF_AtLast)!=0 ){
+ *pRes = -1;
+ return SQLITE_OK;
+ }
+ /* If the requested key is one more than the previous key, then
+ ** try to get there using sqlite3BtreeNext() rather than a full
+ ** binary search. This is an optimization only. The correct answer
+ ** is still obtained without this case, only a little more slowely */
+ if( pCur->info.nKey+1==intKey ){
+ *pRes = 0;
+ rc = sqlite3BtreeNext(pCur, 0);
+ if( rc==SQLITE_OK ){
+ getCellInfo(pCur);
+ if( pCur->info.nKey==intKey ){
+ return SQLITE_OK;
+ }
+ }else if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ }else{
+ return rc;
+ }
+ }
}
}
if( pIdxKey ){
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
pIdxKey->errCode = 0;
- assert( pIdxKey->default_rc==1
- || pIdxKey->default_rc==0
+ assert( pIdxKey->default_rc==1
+ || pIdxKey->default_rc==0
|| pIdxKey->default_rc==-1
);
}else{
@@ -63347,22 +69955,23 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
rc = moveToRoot(pCur);
if( rc ){
+ if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = -1;
+ return SQLITE_OK;
+ }
return rc;
}
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage] );
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->isInit );
- assert( pCur->eState==CURSOR_INVALID || pCur->apPage[pCur->iPage]->nCell>0 );
- if( pCur->eState==CURSOR_INVALID ){
- *pRes = -1;
- assert( pCur->pgnoRoot==0 || pCur->apPage[pCur->iPage]->nCell==0 );
- return SQLITE_OK;
- }
- assert( pCur->apPage[0]->intKey==pCur->curIntKey );
+ assert( pCur->pPage );
+ assert( pCur->pPage->isInit );
+ assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->pPage->nCell > 0 );
+ assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
assert( pCur->curIntKey || pIdxKey );
for(;;){
int lwr, upr, idx, c;
Pgno chldPg;
- MemPage *pPage = pCur->apPage[pCur->iPage];
+ MemPage *pPage = pCur->pPage;
u8 *pCell; /* Pointer to current cell in pPage */
/* pPage->nCell must be greater than zero. If this is the root-page
@@ -63377,14 +69986,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
upr = pPage->nCell-1;
assert( biasRight==0 || biasRight==1 );
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ pCur->ix = (u16)idx;
if( xRecordCompare==0 ){
for(;;){
i64 nCellKey;
pCell = findCellPastPtr(pPage, idx);
if( pPage->intKeyLeaf ){
while( 0x80 <= *(pCell++) ){
- if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
+ if( pCell>=pPage->aDataEnd ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
}
}
getVarint(pCell, (u64*)&nCellKey);
@@ -63396,16 +70007,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
if( lwr>upr ){ c = +1; break; }
}else{
assert( nCellKey==intKey );
- pCur->curFlags |= BTCF_ValidNKey;
- pCur->info.nKey = nCellKey;
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ pCur->ix = (u16)idx;
if( !pPage->leaf ){
lwr = idx;
goto moveto_next_layer;
}else{
+ pCur->curFlags |= BTCF_ValidNKey;
+ pCur->info.nKey = nCellKey;
+ pCur->info.nSize = 0;
*pRes = 0;
- rc = SQLITE_OK;
- goto moveto_finish;
+ return SQLITE_OK;
}
}
assert( lwr+upr>=0 );
@@ -63419,9 +70030,9 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
/* The maximum supported page-size is 65536 bytes. This means that
** the maximum number of record bytes stored on an index B-Tree
** page is less than 16384 bytes and may be stored as a 2-byte
- ** varint. This information is used to attempt to avoid parsing
- ** the entire cell by checking for the cases where the record is
- ** stored entirely within the b-tree page by inspecting the first
+ ** varint. This information is used to attempt to avoid parsing
+ ** the entire cell by checking for the cases where the record is
+ ** stored entirely within the b-tree page by inspecting the first
** 2 bytes of the cell.
*/
nCell = pCell[0];
@@ -63431,10 +70042,10 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
** b-tree page. */
testcase( pCell+nCell+1==pPage->aDataEnd );
c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
- }else if( !(pCell[1] & 0x80)
+ }else if( !(pCell[1] & 0x80)
&& (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
){
- /* The record-size field is a 2 byte varint and the record
+ /* The record-size field is a 2 byte varint and the record
** fits entirely on the main b-tree page. */
testcase( pCell+nCell+2==pPage->aDataEnd );
c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
@@ -63442,39 +70053,42 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
/* The record flows over onto one or more overflow pages. In
** this case the whole cell needs to be parsed, a buffer allocated
** and accessPayload() used to retrieve the record into the
- ** buffer before VdbeRecordCompare() can be called.
+ ** buffer before VdbeRecordCompare() can be called.
**
** If the record is corrupt, the xRecordCompare routine may read
- ** up to two varints past the end of the buffer. An extra 18
+ ** up to two varints past the end of the buffer. An extra 18
** bytes of padding is allocated at the end of the buffer in
** case this happens. */
void *pCellKey;
u8 * const pCellBody = pCell - pPage->childPtrSize;
+ const int nOverrun = 18; /* Size of the overrun padding */
pPage->xParseCell(pPage, pCellBody, &pCur->info);
nCell = (int)pCur->info.nKey;
testcase( nCell<0 ); /* True if key size is 2^32 or more */
testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
testcase( nCell==2 ); /* Minimum legal index key size */
- if( nCell<2 ){
- rc = SQLITE_CORRUPT_BKPT;
+ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
+ rc = SQLITE_CORRUPT_PAGE(pPage);
goto moveto_finish;
}
- pCellKey = sqlite3Malloc( nCell+18 );
+ pCellKey = sqlite3Malloc( nCell+nOverrun );
if( pCellKey==0 ){
rc = SQLITE_NOMEM_BKPT;
goto moveto_finish;
}
- pCur->aiIdx[pCur->iPage] = (u16)idx;
- rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 2);
+ pCur->ix = (u16)idx;
+ rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
+ memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
+ pCur->curFlags &= ~BTCF_ValidOvfl;
if( rc ){
sqlite3_free(pCellKey);
goto moveto_finish;
}
- c = xRecordCompare(nCell, pCellKey, pIdxKey);
+ c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
sqlite3_free(pCellKey);
}
- assert(
+ assert(
(pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
&& (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
);
@@ -63486,8 +70100,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
assert( c==0 );
*pRes = 0;
rc = SQLITE_OK;
- pCur->aiIdx[pCur->iPage] = (u16)idx;
- if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
+ pCur->ix = (u16)idx;
+ if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
goto moveto_finish;
}
if( lwr>upr ) break;
@@ -63498,8 +70112,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
- assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
- pCur->aiIdx[pCur->iPage] = (u16)idx;
+ assert( pCur->ix<pCur->pPage->nCell );
+ pCur->ix = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
goto moveto_finish;
@@ -63510,13 +70124,13 @@ moveto_next_layer:
}else{
chldPg = get4byte(findCell(pPage, lwr));
}
- pCur->aiIdx[pCur->iPage] = (u16)lwr;
+ pCur->ix = (u16)lwr;
rc = moveToChild(pCur, chldPg);
if( rc ) break;
}
moveto_finish:
pCur->info.nSize = 0;
- pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
return rc;
}
@@ -63537,10 +70151,37 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
}
/*
-** Advance the cursor to the next entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the last entry in the database before
-** this routine was called, then set *pRes=1.
+** Return an estimate for the number of rows in the table that pCur is
+** pointing to. Return a negative number if no estimate is currently
+** available.
+*/
+SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
+ i64 n;
+ u8 i;
+
+ assert( cursorOwnsBtShared(pCur) );
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
+
+ /* Currently this interface is only called by the OP_IfSmaller
+ ** opcode, and it that case the cursor will always be valid and
+ ** will always point to a leaf node. */
+ if( NEVER(pCur->eState!=CURSOR_VALID) ) return -1;
+ if( NEVER(pCur->pPage->leaf==0) ) return -1;
+
+ n = pCur->pPage->nCell;
+ for(i=0; i<pCur->iPage; i++){
+ n *= pCur->apPage[i]->nCell;
+ }
+ return n;
+}
+
+/*
+** Advance the cursor to the next entry in the database.
+** Return value:
+**
+** SQLITE_OK success
+** SQLITE_DONE cursor is already pointing at the last element
+** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreeNext(). That routine is optimized
** for the common case of merely incrementing the cell counter BtCursor.aiIdx
@@ -63548,23 +70189,18 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
** routine is called when it is necessary to move to a different page or
** to restore the cursor.
**
-** The calling function will set *pRes to 0 or 1. The initial *pRes value
-** will be 1 if the cursor being stepped corresponds to an SQL index and
-** if this routine could have been skipped if that SQL index had been
-** a unique index. Otherwise the caller will have set *pRes to zero.
-** Zero is the common case. The btree implementation is free to use the
-** initial *pRes value as a hint to improve performance, but the current
-** SQLite btree implementation does not. (Note that the comdb2 btree
-** implementation does use this hint, however.)
+** If bit 0x01 of the F argument in sqlite3BtreeNext(C,F) is 1, then the
+** cursor corresponds to an SQL index and this routine could have been
+** skipped if the SQL index had been a unique index. The F argument
+** is a hint to the implement. SQLite btree implementation does not use
+** this hint, but COMDB2 does.
*/
-static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
int rc;
int idx;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
- assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- assert( *pRes==0 );
if( pCur->eState!=CURSOR_VALID ){
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
rc = restoreCursorPosition(pCur);
@@ -63572,30 +70208,36 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
- if( pCur->skipNext ){
- assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
+ if( pCur->eState==CURSOR_SKIPNEXT ){
pCur->eState = CURSOR_VALID;
- if( pCur->skipNext>0 ){
- pCur->skipNext = 0;
- return SQLITE_OK;
- }
- pCur->skipNext = 0;
+ if( pCur->skipNext>0 ) return SQLITE_OK;
}
}
- pPage = pCur->apPage[pCur->iPage];
- idx = ++pCur->aiIdx[pCur->iPage];
- assert( pPage->isInit );
+ pPage = pCur->pPage;
+ idx = ++pCur->ix;
+ if( !pPage->isInit ){
+ /* The only known way for this to happen is for there to be a
+ ** recursive SQL function that does a DELETE operation as part of a
+ ** SELECT which deletes content out from under an active cursor
+ ** in a corrupt database file where the table being DELETE-ed from
+ ** has pages in common with the table being queried. See TH3
+ ** module cov1/btree78.test testcase 220 (2018-06-08) for an
+ ** example. */
+ return SQLITE_CORRUPT_BKPT;
+ }
- /* If the database file is corrupt, it is possible for the value of idx
+ /* If the database file is corrupt, it is possible for the value of idx
** to be invalid here. This can only occur if a second cursor modifies
** the page while cursor pCur is holding a reference to it. Which can
** only happen if the database is corrupt in such a way as to link the
- ** page into more than one b-tree structure. */
- testcase( idx>pPage->nCell );
+ ** page into more than one b-tree structure.
+ **
+ ** Update 2019-12-23: appears to long longer be possible after the
+ ** addition of anotherValidCursor() condition on balance_deeper(). */
+ harmless( idx>pPage->nCell );
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
@@ -63605,15 +70247,14 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
}
do{
if( pCur->iPage==0 ){
- *pRes = 1;
pCur->eState = CURSOR_INVALID;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
moveToParent(pCur);
- pPage = pCur->apPage[pCur->iPage];
- }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell );
+ pPage = pCur->pPage;
+ }while( pCur->ix>=pPage->nCell );
if( pPage->intKey ){
- return sqlite3BtreeNext(pCur, pRes);
+ return sqlite3BtreeNext(pCur, 0);
}else{
return SQLITE_OK;
}
@@ -63624,20 +70265,18 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur, int *pRes){
return moveToLeftmost(pCur);
}
}
-SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
+SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int flags){
MemPage *pPage;
+ UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
- assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
+ assert( flags==0 || flags==1 );
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
- *pRes = 0;
- if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur, pRes);
- pPage = pCur->apPage[pCur->iPage];
- if( (++pCur->aiIdx[pCur->iPage])>=pPage->nCell ){
- pCur->aiIdx[pCur->iPage]--;
- return btreeNext(pCur, pRes);
+ if( pCur->eState!=CURSOR_VALID ) return btreeNext(pCur);
+ pPage = pCur->pPage;
+ if( (++pCur->ix)>=pPage->nCell ){
+ pCur->ix--;
+ return btreeNext(pCur);
}
if( pPage->leaf ){
return SQLITE_OK;
@@ -63647,10 +70286,12 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
}
/*
-** Step the cursor to the back to the previous entry in the database. If
-** successful then set *pRes=0. If the cursor
-** was already pointing to the first entry in the database before
-** this routine was called, then set *pRes=1.
+** Step the cursor to the back to the previous entry in the database.
+** Return values:
+**
+** SQLITE_OK success
+** SQLITE_DONE the cursor is already on the first element of the table
+** otherwise some kind of error occurred
**
** The main entry point is sqlite3BtreePrevious(). That routine is optimized
** for the common case of merely decrementing the cell counter BtCursor.aiIdx
@@ -63658,23 +70299,17 @@ SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
** helper routine is called when it is necessary to move to a different page
** or to restore the cursor.
**
-** The calling function will set *pRes to 0 or 1. The initial *pRes value
-** will be 1 if the cursor being stepped corresponds to an SQL index and
-** if this routine could have been skipped if that SQL index had been
-** a unique index. Otherwise the caller will have set *pRes to zero.
-** Zero is the common case. The btree implementation is free to use the
-** initial *pRes value as a hint to improve performance, but the current
-** SQLite btree implementation does not. (Note that the comdb2 btree
-** implementation does use this hint, however.)
+** If bit 0x01 of the F argument to sqlite3BtreePrevious(C,F) is 1, then
+** the cursor corresponds to an SQL index and this routine could have been
+** skipped if the SQL index had been a unique index. The F argument is a
+** hint to the implement. The native SQLite btree implementation does not
+** use this hint, but COMDB2 does.
*/
-static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
+static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
int rc;
MemPage *pPage;
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 );
- assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
assert( (pCur->curFlags & (BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey))==0 );
assert( pCur->info.nSize==0 );
if( pCur->eState!=CURSOR_VALID ){
@@ -63683,64 +70318,55 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
- if( pCur->skipNext ){
- assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
+ if( CURSOR_SKIPNEXT==pCur->eState ){
pCur->eState = CURSOR_VALID;
- if( pCur->skipNext<0 ){
- pCur->skipNext = 0;
- return SQLITE_OK;
- }
- pCur->skipNext = 0;
+ if( pCur->skipNext<0 ) return SQLITE_OK;
}
}
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
assert( pPage->isInit );
if( !pPage->leaf ){
- int idx = pCur->aiIdx[pCur->iPage];
+ int idx = pCur->ix;
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
if( rc ) return rc;
rc = moveToRightmost(pCur);
}else{
- while( pCur->aiIdx[pCur->iPage]==0 ){
+ while( pCur->ix==0 ){
if( pCur->iPage==0 ){
pCur->eState = CURSOR_INVALID;
- *pRes = 1;
- return SQLITE_OK;
+ return SQLITE_DONE;
}
moveToParent(pCur);
}
assert( pCur->info.nSize==0 );
- assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
+ assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
- pCur->aiIdx[pCur->iPage]--;
- pPage = pCur->apPage[pCur->iPage];
+ pCur->ix--;
+ pPage = pCur->pPage;
if( pPage->intKey && !pPage->leaf ){
- rc = sqlite3BtreePrevious(pCur, pRes);
+ rc = sqlite3BtreePrevious(pCur, 0);
}else{
rc = SQLITE_OK;
}
}
return rc;
}
-SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
+SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){
assert( cursorOwnsBtShared(pCur) );
- assert( pRes!=0 );
- assert( *pRes==0 || *pRes==1 );
- assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
- *pRes = 0;
+ assert( flags==0 || flags==1 );
+ UNUSED_PARAMETER( flags ); /* Used in COMDB2 but not native SQLite */
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidOvfl|BTCF_ValidNKey);
pCur->info.nSize = 0;
if( pCur->eState!=CURSOR_VALID
- || pCur->aiIdx[pCur->iPage]==0
- || pCur->apPage[pCur->iPage]->leaf==0
+ || pCur->ix==0
+ || pCur->pPage->leaf==0
){
- return btreePrevious(pCur, pRes);
+ return btreePrevious(pCur);
}
- pCur->aiIdx[pCur->iPage]--;
+ pCur->ix--;
return SQLITE_OK;
}
@@ -63755,7 +70381,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
** SQLITE_OK is returned on success. Any other return value indicates
** an error. *ppPage is set to NULL in the event of an error.
**
-** If the "nearby" parameter is not 0, then an effort is made to
+** If the "nearby" parameter is not 0, then an effort is made to
** locate a page close to the page number "nearby". This can be used in an
** attempt to keep related pages close to each other in the database file,
** which in turn can make database access faster.
@@ -63797,7 +70423,7 @@ static int allocateBtreePage(
Pgno iTrunk;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
u32 nSearch = 0; /* Count of the number of search attempts */
-
+
/* If eMode==BTALLOC_EXACT and a query of the pointer-map
** shows that the page 'nearby' is somewhere on the free-list, then
** the entire-list will be searched for that page.
@@ -63846,7 +70472,7 @@ static int allocateBtreePage(
}
testcase( iTrunk==mxPage );
if( iTrunk>mxPage || nSearch++ > n ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1);
}else{
rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
}
@@ -63860,8 +70486,8 @@ static int allocateBtreePage(
** is the number of leaf page pointers to follow. */
k = get4byte(&pTrunk->aData[4]);
if( k==0 && !searchList ){
- /* The trunk has no leaves and the list is not being searched.
- ** So extract the trunk page itself and use it as the newly
+ /* The trunk has no leaves and the list is not being searched.
+ ** So extract the trunk page itself and use it as the newly
** allocated page */
assert( pPrevTrunk==0 );
rc = sqlite3PagerWrite(pTrunk->pDbPage);
@@ -63875,11 +70501,11 @@ static int allocateBtreePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
- }else if( searchList
- && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
+ }else if( searchList
+ && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
){
/* The list is being searched and this trunk page is the page
** to allocate, regardless of whether it has leaves.
@@ -63902,14 +70528,14 @@ static int allocateBtreePage(
memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4);
}
}else{
- /* The trunk page is required by the caller but it contains
+ /* The trunk page is required by the caller but it contains
** pointers to free-list leaves. The first leaf becomes a trunk
** page in this case.
*/
MemPage *pNewTrunk;
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
- if( iNewTrunk>mxPage ){
- rc = SQLITE_CORRUPT_BKPT;
+ if( iNewTrunk>mxPage ){
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
@@ -63974,12 +70600,12 @@ static int allocateBtreePage(
iPage = get4byte(&aData[8+closest*4]);
testcase( iPage==mxPage );
if( iPage>mxPage ){
- rc = SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_PGNO(iTrunk);
goto end_allocate_page;
}
testcase( iPage==mxPage );
- if( !searchList
- || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
+ if( !searchList
+ || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
){
int noContent;
*pPgno = iPage;
@@ -64020,7 +70646,7 @@ static int allocateBtreePage(
** not set the no-content flag. This causes the pager to load and journal
** the current page content before overwriting it.
**
- ** Note that the pager will not actually attempt to load or journal
+ ** Note that the pager will not actually attempt to load or journal
** content for any page that really does lie past the end of the database
** file on disk. So the effects of disabling the no-content optimization
** here are confined to those pages that lie between the end of the
@@ -64066,7 +70692,7 @@ static int allocateBtreePage(
TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
}
- assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
+ assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
end_allocate_page:
releasePage(pTrunk);
@@ -64077,12 +70703,12 @@ end_allocate_page:
}
/*
-** This function is used to add page iPage to the database file free-list.
+** This function is used to add page iPage to the database file free-list.
** It is assumed that the page is not already a part of the free-list.
**
** The value passed as the second argument to this function is optional.
-** If the caller happens to have a pointer to the MemPage object
-** corresponding to page iPage handy, it may pass it as the second value.
+** If the caller happens to have a pointer to the MemPage object
+** corresponding to page iPage handy, it may pass it as the second value.
** Otherwise, it may pass NULL.
**
** If a pointer to a MemPage object is passed as the second argument,
@@ -64090,17 +70716,19 @@ end_allocate_page:
*/
static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
MemPage *pTrunk = 0; /* Free-list trunk page */
- Pgno iTrunk = 0; /* Page number of free-list trunk page */
+ Pgno iTrunk = 0; /* Page number of free-list trunk page */
MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */
MemPage *pPage; /* Page being freed. May be NULL. */
int rc; /* Return Code */
- int nFree; /* Initial number of pages on free-list */
+ u32 nFree; /* Initial number of pages on free-list */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( CORRUPT_DB || iPage>1 );
assert( !pMemPage || pMemPage->pgno==iPage );
- if( iPage<2 ) return SQLITE_CORRUPT_BKPT;
+ if( iPage<2 || iPage>pBt->nPage ){
+ return SQLITE_CORRUPT_BKPT;
+ }
if( pMemPage ){
pPage = pMemPage;
sqlite3PagerRef(pPage->pDbPage);
@@ -64145,6 +70773,10 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]);
+ if( iTrunk>btreePagecount(pBt) ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto freepage_out;
+ }
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
if( rc!=SQLITE_OK ){
goto freepage_out;
@@ -64192,7 +70824,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If control flows to this point, then it was not possible to add the
** the page being freed as a leaf page of the first trunk in the free-list.
- ** Possibly because the free-list is empty, or possibly because the
+ ** Possibly because the free-list is empty, or possibly because the
** first trunk in the free-list is full. Either way, the page being freed
** will become the new first trunk page in the free-list.
*/
@@ -64223,44 +70855,45 @@ static void freePage(MemPage *pPage, int *pRC){
}
/*
-** Free any overflow pages associated with the given Cell. Write the
-** local Cell size (the number of bytes on the original page, omitting
-** overflow) into *pnSize.
+** Free any overflow pages associated with the given Cell. Store
+** size information about the cell in pInfo.
*/
static int clearCell(
MemPage *pPage, /* The page that contains the Cell */
unsigned char *pCell, /* First byte of the Cell */
- u16 *pnSize /* Write the size of the Cell here */
+ CellInfo *pInfo /* Size information about the cell */
){
- BtShared *pBt = pPage->pBt;
- CellInfo info;
+ BtShared *pBt;
Pgno ovflPgno;
int rc;
int nOvfl;
u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- pPage->xParseCell(pPage, pCell, &info);
- *pnSize = info.nSize;
- if( info.nLocal==info.nPayload ){
+ pPage->xParseCell(pPage, pCell, pInfo);
+ if( pInfo->nLocal==pInfo->nPayload ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
- if( pCell+info.nSize-1 > pPage->aData+pPage->maskPage ){
- return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
+ testcase( pCell + pInfo->nSize == pPage->aDataEnd );
+ testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd );
+ if( pCell + pInfo->nSize > pPage->aDataEnd ){
+ /* Cell extends past end of page */
+ return SQLITE_CORRUPT_PAGE(pPage);
}
- ovflPgno = get4byte(pCell + info.nSize - 4);
+ ovflPgno = get4byte(pCell + pInfo->nSize - 4);
+ pBt = pPage->pBt;
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
- nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
- assert( nOvfl>0 ||
- (CORRUPT_DB && (info.nPayload + ovflPageSize)<ovflPageSize)
+ nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
+ assert( nOvfl>0 ||
+ (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)<ovflPageSize)
);
while( nOvfl-- ){
Pgno iNext = 0;
MemPage *pOvfl = 0;
if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
- /* 0 is not a legal page number and page 1 cannot be an
- ** overflow page. Therefore if ovflPgno<2 or past the end of the
+ /* 0 is not a legal page number and page 1 cannot be an
+ ** overflow page. Therefore if ovflPgno<2 or past the end of the
** file the database must be corrupt. */
return SQLITE_CORRUPT_BKPT;
}
@@ -64272,11 +70905,11 @@ static int clearCell(
if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) )
&& sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1
){
- /* There is no reason any cursor should have an outstanding reference
+ /* There is no reason any cursor should have an outstanding reference
** to an overflow page belonging to a cell that is being deleted/updated.
- ** So if there exists more than one reference to this page, then it
- ** must not really be an overflow page and the database must be corrupt.
- ** It is helpful to detect this before calling freePage2(), as
+ ** So if there exists more than one reference to this page, then it
+ ** must not really be an overflow page and the database must be corrupt.
+ ** It is helpful to detect this before calling freePage2(), as
** freePage2() may zero the page contents if secure-delete mode is
** enabled. If this 'overflow' page happens to be a page that the
** caller is iterating through or using in some other way, this
@@ -64316,21 +70949,20 @@ static int fillInCell(
){
int nPayload;
const u8 *pSrc;
- int nSrc, n, rc;
+ int nSrc, n, rc, mn;
int spaceLeft;
- MemPage *pOvfl = 0;
- MemPage *pToRelease = 0;
+ MemPage *pToRelease;
unsigned char *pPrior;
unsigned char *pPayload;
- BtShared *pBt = pPage->pBt;
- Pgno pgnoOvfl = 0;
+ BtShared *pBt;
+ Pgno pgnoOvfl;
int nHeader;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
/* pPage is not necessarily writeable since pCell might be auxiliary
** buffer space that is separate from the pPage buffer area */
- assert( pCell<pPage->aData || pCell>=&pPage->aData[pBt->pageSize]
+ assert( pCell<pPage->aData || pCell>=&pPage->aData[pPage->pBt->pageSize]
|| sqlite3PagerIswriteable(pPage->pDbPage) );
/* Fill in the header. */
@@ -64348,27 +70980,38 @@ static int fillInCell(
pSrc = pX->pKey;
nHeader += putVarint32(&pCell[nHeader], nPayload);
}
-
+
/* Fill in the payload */
+ pPayload = &pCell[nHeader];
if( nPayload<=pPage->maxLocal ){
+ /* This is the common case where everything fits on the btree page
+ ** and no overflow pages are required. */
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
if( n<4 ) n = 4;
*pnSize = n;
- spaceLeft = nPayload;
- pPrior = pCell;
- }else{
- int mn = pPage->minLocal;
- n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
- testcase( n==pPage->maxLocal );
- testcase( n==pPage->maxLocal+1 );
- if( n > pPage->maxLocal ) n = mn;
- spaceLeft = n;
- *pnSize = n + nHeader + 4;
- pPrior = &pCell[nHeader+n];
+ assert( nSrc<=nPayload );
+ testcase( nSrc<nPayload );
+ memcpy(pPayload, pSrc, nSrc);
+ memset(pPayload+nSrc, 0, nPayload-nSrc);
+ return SQLITE_OK;
}
- pPayload = &pCell[nHeader];
+
+ /* If we reach this point, it means that some of the content will need
+ ** to spill onto overflow pages.
+ */
+ mn = pPage->minLocal;
+ n = mn + (nPayload - mn) % (pPage->pBt->usableSize - 4);
+ testcase( n==pPage->maxLocal );
+ testcase( n==pPage->maxLocal+1 );
+ if( n > pPage->maxLocal ) n = mn;
+ spaceLeft = n;
+ *pnSize = n + nHeader + 4;
+ pPrior = &pCell[nHeader+n];
+ pToRelease = 0;
+ pgnoOvfl = 0;
+ pBt = pPage->pBt;
/* At this point variables should be set as follows:
**
@@ -64382,7 +71025,7 @@ static int fillInCell(
** Use a call to btreeParseCellPtr() to verify that the values above
** were computed correctly.
*/
-#if SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
{
CellInfo info;
pPage->xParseCell(pPage, pCell, &info);
@@ -64394,15 +71037,42 @@ static int fillInCell(
#endif
/* Write the payload into the local Cell and any extra into overflow pages */
- while( nPayload>0 ){
+ while( 1 ){
+ n = nPayload;
+ if( n>spaceLeft ) n = spaceLeft;
+
+ /* If pToRelease is not zero than pPayload points into the data area
+ ** of pToRelease. Make sure pToRelease is still writeable. */
+ assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
+
+ /* If pPayload is part of the data area of pPage, then make sure pPage
+ ** is still writeable */
+ assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
+ || sqlite3PagerIswriteable(pPage->pDbPage) );
+
+ if( nSrc>=n ){
+ memcpy(pPayload, pSrc, n);
+ }else if( nSrc>0 ){
+ n = nSrc;
+ memcpy(pPayload, pSrc, n);
+ }else{
+ memset(pPayload, 0, n);
+ }
+ nPayload -= n;
+ if( nPayload<=0 ) break;
+ pPayload += n;
+ pSrc += n;
+ nSrc -= n;
+ spaceLeft -= n;
if( spaceLeft==0 ){
+ MemPage *pOvfl = 0;
#ifndef SQLITE_OMIT_AUTOVACUUM
Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
if( pBt->autoVacuum ){
do{
pgnoOvfl++;
- } while(
- PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
+ } while(
+ PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
);
}
#endif
@@ -64410,9 +71080,9 @@ static int fillInCell(
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If the database supports auto-vacuum, and the second or subsequent
** overflow page is being allocated, add an entry to the pointer-map
- ** for that page now.
+ ** for that page now.
**
- ** If this is the first overflow page, then write a partial entry
+ ** If this is the first overflow page, then write a partial entry
** to the pointer-map. If we write nothing to this pointer-map slot,
** then the optimistic overflow chain processing in clearCell()
** may misinterpret the uninitialized values and delete the
@@ -64448,30 +71118,6 @@ static int fillInCell(
pPayload = &pOvfl->aData[4];
spaceLeft = pBt->usableSize - 4;
}
- n = nPayload;
- if( n>spaceLeft ) n = spaceLeft;
-
- /* If pToRelease is not zero than pPayload points into the data area
- ** of pToRelease. Make sure pToRelease is still writeable. */
- assert( pToRelease==0 || sqlite3PagerIswriteable(pToRelease->pDbPage) );
-
- /* If pPayload is part of the data area of pPage, then make sure pPage
- ** is still writeable */
- assert( pPayload<pPage->aData || pPayload>=&pPage->aData[pBt->pageSize]
- || sqlite3PagerIswriteable(pPage->pDbPage) );
-
- if( nSrc>0 ){
- if( n>nSrc ) n = nSrc;
- assert( pSrc );
- memcpy(pPayload, pSrc, n);
- }else{
- memset(pPayload, 0, n);
- }
- nPayload -= n;
- pPayload += n;
- pSrc += n;
- nSrc -= n;
- spaceLeft -= n;
}
releasePage(pToRelease);
return SQLITE_OK;
@@ -64493,18 +71139,18 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
if( *pRC ) return;
-
assert( idx>=0 && idx<pPage->nCell );
assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( pPage->nFree>=0 );
data = pPage->aData;
ptr = &pPage->aCellIdx[2*idx];
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
testcase( pc==get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
- if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
+ if( pc+sz > pPage->pBt->usableSize ){
*pRC = SQLITE_CORRUPT_BKPT;
return;
}
@@ -64535,8 +71181,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** will not fit, then make a copy of the cell content into pTemp if
** pTemp is not null. Regardless of pTemp, allocate a new entry
** in pPage->apOvfl[] and make it point to the cell content (either
-** in pTemp or the original pCell) and also record its index.
-** Allocating a new entry in pPage->aCell[] implies that
+** in pTemp or the original pCell) and also record its index.
+** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
**
** *pRC must be SQLITE_OK when this routine is called.
@@ -64562,12 +71208,8 @@ static void insertCell(
assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- /* The cell should normally be sized correctly. However, when moving a
- ** malformed cell from a leaf page to an interior page, if the cell size
- ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
- ** might be less than 8 (leaf-size + pointer) on the interior node. Hence
- ** the term after the || in the following assert(). */
- assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) );
+ assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
+ assert( pPage->nFree>=0 );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
@@ -64577,7 +71219,10 @@ static void insertCell(
put4byte(pCell, iChild);
}
j = pPage->nOverflow++;
- assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
+ /* Comparison against ArraySize-1 since we hold back one extra slot
+ ** as a contingency. In other words, never need more than 3 overflow
+ ** slots but 4 are allocated, just to be safe. */
+ assert( j < ArraySize(pPage->apOvfl)-1 );
pPage->apOvfl[j] = pCell;
pPage->aiOvfl[j] = (u16)i;
@@ -64605,9 +71250,16 @@ static void insertCell(
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nFree -= (u16)(2 + sz);
- memcpy(&data[idx], pCell, sz);
if( iChild ){
+ /* In a corrupt database where an entry in the cell index section of
+ ** a btree page has a value of 3 or less, the pCell value might point
+ ** as many as 4 bytes in front of the start of the aData buffer for
+ ** the source page. Make sure this does not cause problems by not
+ ** reading the first 4 bytes */
+ memcpy(&data[idx+4], pCell+4, sz-4);
put4byte(&data[idx], iChild);
+ }else{
+ memcpy(&data[idx], pCell, sz);
}
pIns = pPage->aCellIdx + i*2;
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
@@ -64615,21 +71267,100 @@ static void insertCell(
pPage->nCell++;
/* increment the cell count */
if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
- assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell );
+ assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
/* The cell may contain a pointer to an overflow page. If so, write
** the entry for the overflow page into the pointer map.
*/
- ptrmapPutOvflPtr(pPage, pCell, pRC);
+ ptrmapPutOvflPtr(pPage, pPage, pCell, pRC);
}
#endif
}
}
/*
+** The following parameters determine how many adjacent pages get involved
+** in a balancing operation. NN is the number of neighbors on either side
+** of the page that participate in the balancing operation. NB is the
+** total number of pages that participate, including the target page and
+** NN neighbors on either side.
+**
+** The minimum value of NN is 1 (of course). Increasing NN above 1
+** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
+** in exchange for a larger degradation in INSERT and UPDATE performance.
+** The value of NN appears to give the best results overall.
+**
+** (Later:) The description above makes it seem as if these values are
+** tunable - as if you could change them and recompile and it would all work.
+** But that is unlikely. NB has been 3 since the inception of SQLite and
+** we have never tested any other value.
+*/
+#define NN 1 /* Number of neighbors on either side of pPage */
+#define NB 3 /* (NN*2+1): Total pages involved in the balance */
+
+/*
** A CellArray object contains a cache of pointers and sizes for a
** consecutive sequence of cells that might be held on multiple pages.
+**
+** The cells in this array are the divider cell or cells from the pParent
+** page plus up to three child pages. There are a total of nCell cells.
+**
+** pRef is a pointer to one of the pages that contributes cells. This is
+** used to access information such as MemPage.intKey and MemPage.pBt->pageSize
+** which should be common to all pages that contribute cells to this array.
+**
+** apCell[] and szCell[] hold, respectively, pointers to the start of each
+** cell and the size of each cell. Some of the apCell[] pointers might refer
+** to overflow cells. In other words, some apCel[] pointers might not point
+** to content area of the pages.
+**
+** A szCell[] of zero means the size of that cell has not yet been computed.
+**
+** The cells come from as many as four different pages:
+**
+** -----------
+** | Parent |
+** -----------
+** / | \
+** / | \
+** --------- --------- ---------
+** |Child-1| |Child-2| |Child-3|
+** --------- --------- ---------
+**
+** The order of cells is in the array is for an index btree is:
+**
+** 1. All cells from Child-1 in order
+** 2. The first divider cell from Parent
+** 3. All cells from Child-2 in order
+** 4. The second divider cell from Parent
+** 5. All cells from Child-3 in order
+**
+** For a table-btree (with rowids) the items 2 and 4 are empty because
+** content exists only in leaves and there are no divider cells.
+**
+** For an index btree, the apEnd[] array holds pointer to the end of page
+** for Child-1, the Parent, Child-2, the Parent (again), and Child-3,
+** respectively. The ixNx[] array holds the number of cells contained in
+** each of these 5 stages, and all stages to the left. Hence:
+**
+** ixNx[0] = Number of cells in Child-1.
+** ixNx[1] = Number of cells in Child-1 plus 1 for first divider.
+** ixNx[2] = Number of cells in Child-1 and Child-2 + 1 for 1st divider.
+** ixNx[3] = Number of cells in Child-1 and Child-2 + both divider cells
+** ixNx[4] = Total number of cells.
+**
+** For a table-btree, the concept is similar, except only apEnd[0]..apEnd[2]
+** are used and they point to the leaf pages only, and the ixNx value are:
+**
+** ixNx[0] = Number of cells in Child-1.
+** ixNx[1] = Number of cells in Child-1 and Child-2.
+** ixNx[2] = Total number of cells.
+**
+** Sometimes when deleting, a child page can have zero cells. In those
+** cases, ixNx[] entries with higher indexes, and the corresponding apEnd[]
+** entries, shift down. The end result is that each ixNx[] entry should
+** be larger than the previous
*/
typedef struct CellArray CellArray;
struct CellArray {
@@ -64637,6 +71368,8 @@ struct CellArray {
MemPage *pRef; /* Reference page */
u8 **apCell; /* All cells begin balanced */
u16 *szCell; /* Local size of all cells in apCell[] */
+ u8 *apEnd[NB*2]; /* MemPage.aDataEnd values */
+ int ixNx[NB*2]; /* Index of at which we move to the next apEnd[] */
};
/*
@@ -64674,49 +71407,72 @@ static u16 cachedCellSize(CellArray *p, int N){
}
/*
-** Array apCell[] contains pointers to nCell b-tree page cells. The
+** Array apCell[] contains pointers to nCell b-tree page cells. The
** szCell[] array contains the size in bytes of each cell. This function
** replaces the current contents of page pPg with the contents of the cell
** array.
**
** Some of the cells in apCell[] may currently be stored in pPg. This
-** function works around problems caused by this by making a copy of any
+** function works around problems caused by this by making a copy of any
** such cells before overwriting the page data.
**
-** The MemPage.nFree field is invalidated by this function. It is the
+** The MemPage.nFree field is invalidated by this function. It is the
** responsibility of the caller to set it correctly.
*/
static int rebuildPage(
- MemPage *pPg, /* Edit this page */
+ CellArray *pCArray, /* Content to be added to page pPg */
+ int iFirst, /* First cell in pCArray to use */
int nCell, /* Final number of cells on page */
- u8 **apCell, /* Array of cells */
- u16 *szCell /* Array of cell sizes */
+ MemPage *pPg /* The page to be reconstructed */
){
const int hdr = pPg->hdrOffset; /* Offset of header on pPg */
u8 * const aData = pPg->aData; /* Pointer to data for pPg */
const int usableSize = pPg->pBt->usableSize;
u8 * const pEnd = &aData[usableSize];
- int i;
+ int i = iFirst; /* Which cell to copy from pCArray*/
+ u32 j; /* Start of cell content area */
+ int iEnd = i+nCell; /* Loop terminator */
u8 *pCellptr = pPg->aCellIdx;
u8 *pTmp = sqlite3PagerTempSpace(pPg->pBt->pPager);
u8 *pData;
+ int k; /* Current slot in pCArray->apEnd[] */
+ u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
+
+ assert( i<iEnd );
+ j = get2byte(&aData[hdr+5]);
+ if( NEVER(j>(u32)usableSize) ){ j = 0; }
+ memcpy(&pTmp[j], &aData[j], usableSize - j);
- i = get2byte(&aData[hdr+5]);
- memcpy(&pTmp[i], &aData[i], usableSize - i);
+ for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ pSrcEnd = pCArray->apEnd[k];
pData = pEnd;
- for(i=0; i<nCell; i++){
- u8 *pCell = apCell[i];
+ while( 1/*exit by break*/ ){
+ u8 *pCell = pCArray->apCell[i];
+ u16 sz = pCArray->szCell[i];
+ assert( sz>0 );
if( SQLITE_WITHIN(pCell,aData,pEnd) ){
+ if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT;
pCell = &pTmp[pCell - aData];
+ }else if( (uptr)(pCell+sz)>(uptr)pSrcEnd
+ && (uptr)(pCell)<(uptr)pSrcEnd
+ ){
+ return SQLITE_CORRUPT_BKPT;
}
- pData -= szCell[i];
+
+ pData -= sz;
put2byte(pCellptr, (pData - aData));
pCellptr += 2;
if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
- memcpy(pData, pCell, szCell[i]);
- assert( szCell[i]==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
- testcase( szCell[i]!=pPg->xCellSize(pPg,pCell) );
+ memcpy(pData, pCell, sz);
+ assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
+ testcase( sz!=pPg->xCellSize(pPg,pCell) )
+ i++;
+ if( i>=iEnd ) break;
+ if( pCArray->ixNx[k]<=i ){
+ k++;
+ pSrcEnd = pCArray->apEnd[k];
+ }
}
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
@@ -64731,12 +71487,11 @@ static int rebuildPage(
}
/*
-** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
-** contains the size in bytes of each such cell. This function attempts to
-** add the cells stored in the array to page pPg. If it cannot (because
-** the page needs to be defragmented before the cells will fit), non-zero
-** is returned. Otherwise, if the cells are added successfully, zero is
-** returned.
+** The pCArray objects contains pointers to b-tree cells and the cell sizes.
+** This function attempts to add the cells stored in the array to page pPg.
+** If it cannot (because the page needs to be defragmented before the cells
+** will fit), non-zero is returned. Otherwise, if the cells are added
+** successfully, zero is returned.
**
** Argument pCellptr points to the first entry in the cell-pointer array
** (part of page pPg) to populate. After cell apCell[0] is written to the
@@ -64744,7 +71499,7 @@ static int rebuildPage(
** cell in the array. It is the responsibility of the caller to ensure
** that it is safe to overwrite this part of the cell-pointer array.
**
-** When this function is called, *ppData points to the start of the
+** When this function is called, *ppData points to the start of the
** content area on page pPg. If the size of the content area is extended,
** *ppData is updated to point to the new start of the content area
** before returning.
@@ -64758,21 +71513,27 @@ static int rebuildPage(
static int pageInsertArray(
MemPage *pPg, /* Page to add cells to */
u8 *pBegin, /* End of cell-pointer array */
- u8 **ppData, /* IN/OUT: Page content -area pointer */
+ u8 **ppData, /* IN/OUT: Page content-area pointer */
u8 *pCellptr, /* Pointer to cell-pointer area */
int iFirst, /* Index of first cell to add */
int nCell, /* Number of cells to add to pPg */
CellArray *pCArray /* Array of cells */
){
- int i;
- u8 *aData = pPg->aData;
- u8 *pData = *ppData;
- int iEnd = iFirst + nCell;
+ int i = iFirst; /* Loop counter - cell index to insert */
+ u8 *aData = pPg->aData; /* Complete page */
+ u8 *pData = *ppData; /* Content area. A subset of aData[] */
+ int iEnd = iFirst + nCell; /* End of loop. One past last cell to ins */
+ int k; /* Current slot in pCArray->apEnd[] */
+ u8 *pEnd; /* Maximum extent of cell data */
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
- for(i=iFirst; i<iEnd; i++){
+ if( iEnd<=iFirst ) return 0;
+ for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ pEnd = pCArray->apEnd[k];
+ while( 1 /*Exit by break*/ ){
int sz, rc;
u8 *pSlot;
- sz = cachedCellSize(pCArray, i);
+ assert( pCArray->szCell[i]!=0 );
+ sz = pCArray->szCell[i];
if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
if( (pData - pBegin)<sz ) return 1;
pData -= sz;
@@ -64784,20 +71545,33 @@ static int pageInsertArray(
assert( (pSlot+sz)<=pCArray->apCell[i]
|| pSlot>=(pCArray->apCell[i]+sz)
|| CORRUPT_DB );
+ if( (uptr)(pCArray->apCell[i]+sz)>(uptr)pEnd
+ && (uptr)(pCArray->apCell[i])<(uptr)pEnd
+ ){
+ assert( CORRUPT_DB );
+ (void)SQLITE_CORRUPT_BKPT;
+ return 1;
+ }
memmove(pSlot, pCArray->apCell[i], sz);
put2byte(pCellptr, (pSlot - aData));
pCellptr += 2;
+ i++;
+ if( i>=iEnd ) break;
+ if( pCArray->ixNx[k]<=i ){
+ k++;
+ pEnd = pCArray->apEnd[k];
+ }
}
*ppData = pData;
return 0;
}
/*
-** Array apCell[] contains nCell pointers to b-tree cells. Array szCell
-** contains the size in bytes of each such cell. This function adds the
-** space associated with each cell in the array that is currently stored
-** within the body of pPg to the pPg free-list. The cell-pointers and other
-** fields of the page are not updated.
+** The pCArray object contains pointers to b-tree cells and their sizes.
+**
+** This function adds the space associated with each cell in the array
+** that is currently stored within the body of pPg to the pPg free-list.
+** The cell-pointers and other fields of the page are not updated.
**
** This function returns the total number of cells added to the free-list.
*/
@@ -64847,9 +71621,9 @@ static int pageFreeArray(
}
/*
-** apCell[] and szCell[] contains pointers to and sizes of all cells in the
-** pages being balanced. The current page, pPg, has pPg->nCell cells starting
-** with apCell[iOld]. After balancing, this page should hold nNew cells
+** pCArray contains pointers to and sizes of all cells in the page being
+** balanced. The current page, pPg, has pPg->nCell cells starting with
+** pCArray->apCell[iOld]. After balancing, this page should hold nNew cells
** starting at apCell[iNew].
**
** This routine makes the necessary adjustments to pPg so that it contains
@@ -64881,13 +71655,17 @@ static int editPage(
#endif
/* Remove cells from the start and end of the page */
+ assert( nCell>=0 );
if( iOld<iNew ){
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
+ if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
nCell -= nShift;
}
if( iNewEnd < iOldEnd ){
- nCell -= pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
+ int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
+ assert( nCell>=nTail );
+ nCell -= nTail;
}
pData = &aData[get2byteNotZero(&aData[hdr+5])];
@@ -64897,6 +71675,7 @@ static int editPage(
if( iNew<iOld ){
int nAdd = MIN(nNew,iOld-iNew);
assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
+ assert( nAdd>=0 );
pCellptr = pPg->aCellIdx;
memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
if( pageInsertArray(
@@ -64911,8 +71690,11 @@ static int editPage(
int iCell = (iOld + pPg->aiOvfl[i]) - iNew;
if( iCell>=0 && iCell<nNew ){
pCellptr = &pPg->aCellIdx[iCell * 2];
- memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+ if( nCell>iCell ){
+ memmove(&pCellptr[2], pCellptr, (nCell - iCell) * 2);
+ }
nCell++;
+ cachedCellSize(pCArray, iCell+iNew);
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
iCell+iNew, 1, pCArray
@@ -64921,6 +71703,7 @@ static int editPage(
}
/* Append cells to the end of the page */
+ assert( nCell>=0 );
pCellptr = &pPg->aCellIdx[nCell*2];
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
@@ -64949,24 +71732,9 @@ static int editPage(
editpage_fail:
/* Unable to edit this page. Rebuild it from scratch instead. */
populateCellCache(pCArray, iNew, nNew);
- return rebuildPage(pPg, nNew, &pCArray->apCell[iNew], &pCArray->szCell[iNew]);
+ return rebuildPage(pCArray, iNew, nNew, pPg);
}
-/*
-** The following parameters determine how many adjacent pages get involved
-** in a balancing operation. NN is the number of neighbors on either side
-** of the page that participate in the balancing operation. NB is the
-** total number of pages that participate, including the target page and
-** NN neighbors on either side.
-**
-** The minimum value of NN is 1 (of course). Increasing NN above 1
-** (to 2 or 3) gives a modest improvement in SELECT and DELETE performance
-** in exchange for a larger degradation in INSERT and UPDATE performance.
-** The value of NN appears to give the best results overall.
-*/
-#define NN 1 /* Number of neighbors on either side of pPage */
-#define NB (NN*2+1) /* Total pages involved in the balance */
-
#ifndef SQLITE_OMIT_QUICKBALANCE
/*
@@ -65002,10 +71770,11 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
assert( pPage->nOverflow==1 );
- /* This error condition is now caught prior to reaching this function */
- if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT;
+ if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */
+ assert( pPage->nFree>=0 );
+ assert( pParent->nFree>=0 );
- /* Allocate a new page. This page will become the right-sibling of
+ /* Allocate a new page. This page will become the right-sibling of
** pPage. Make the parent page writable, so that the new divider cell
** may be inserted. If both these operations are successful, proceed.
*/
@@ -65017,16 +71786,26 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
u8 *pCell = pPage->apOvfl[0];
u16 szCell = pPage->xCellSize(pPage, pCell);
u8 *pStop;
+ CellArray b;
assert( sqlite3PagerIswriteable(pNew->pDbPage) );
- assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
+ assert( CORRUPT_DB || pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
- rc = rebuildPage(pNew, 1, &pCell, &szCell);
- if( NEVER(rc) ) return rc;
+ b.nCell = 1;
+ b.pRef = pPage;
+ b.apCell = &pCell;
+ b.szCell = &szCell;
+ b.apEnd[0] = pPage->aDataEnd;
+ b.ixNx[0] = 2;
+ rc = rebuildPage(&b, 0, 1, pNew);
+ if( NEVER(rc) ){
+ releasePage(pNew);
+ return rc;
+ }
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
/* If this is an auto-vacuum database, update the pointer map
- ** with entries for the new page, and any pointer from the
+ ** with entries for the new page, and any pointer from the
** cell on the page to an overflow page. If either of these
** operations fails, the return code is set, but the contents
** of the parent page are still manipulated by thh code below.
@@ -65037,17 +71816,17 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
if( ISAUTOVACUUM ){
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
if( szCell>pNew->minLocal ){
- ptrmapPutOvflPtr(pNew, pCell, &rc);
+ ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
}
}
-
+
/* Create a divider cell to insert into pParent. The divider cell
** consists of a 4-byte page number (the page number of pPage) and
** a variable length key value (which must be the same value as the
** largest key on pPage).
**
- ** To find the largest key value on pPage, first find the right-most
- ** cell on pPage. The first two fields of this cell are the
+ ** To find the largest key value on pPage, first find the right-most
+ ** cell on pPage. The first two fields of this cell are the
** record-length (a variable length integer at most 32-bits in size)
** and the key value (a variable length integer, may have any value).
** The first of the while(...) loops below skips over the record-length
@@ -65068,7 +71847,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
/* Set the right-child pointer of pParent to point to the new page. */
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
-
+
/* Release the reference to the new page. */
releasePage(pNew);
}
@@ -65080,7 +71859,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
#if 0
/*
** This function does not contribute anything to the operation of SQLite.
-** it is sometimes activated temporarily while debugging code responsible
+** it is sometimes activated temporarily while debugging code responsible
** for setting pointer-map entries.
*/
static int ptrmapCheckPages(MemPage **apPage, int nPage){
@@ -65095,7 +71874,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
for(j=0; j<pPage->nCell; j++){
CellInfo info;
u8 *z;
-
+
z = findCell(pPage, j);
pPage->xParseCell(pPage, z, &info);
if( info.nLocal<info.nPayload ){
@@ -65120,7 +71899,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
#endif
/*
-** This function is used to copy the contents of the b-tree node stored
+** This function is used to copy the contents of the b-tree node stored
** on page pFrom to page pTo. If page pFrom was not a leaf page, then
** the pointer-map entries for each child page are updated so that the
** parent page stored in the pointer map is page pTo. If pFrom contained
@@ -65128,11 +71907,11 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
** map entries are also updated so that the parent page is page pTo.
**
** If pFrom is currently carrying any overflow cells (entries in the
-** MemPage.apOvfl[] array), they are not copied to pTo.
+** MemPage.apOvfl[] array), they are not copied to pTo.
**
** Before returning, page pTo is reinitialized using btreeInitPage().
**
-** The performance of this function is not critical. It is only used by
+** The performance of this function is not critical. It is only used by
** the balance_shallower() and balance_deeper() procedures, neither of
** which are called often under normal circumstances.
*/
@@ -65145,29 +71924,30 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
int const iToHdr = ((pTo->pgno==1) ? 100 : 0);
int rc;
int iData;
-
-
+
+
assert( pFrom->isInit );
assert( pFrom->nFree>=iToHdr );
assert( get2byte(&aFrom[iFromHdr+5]) <= (int)pBt->usableSize );
-
+
/* Copy the b-tree node content from page pFrom to page pTo. */
iData = get2byte(&aFrom[iFromHdr+5]);
memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData);
memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell);
-
+
/* Reinitialize page pTo so that the contents of the MemPage structure
** match the new data. The initialization of pTo can actually fail under
- ** fairly obscure circumstances, even though it is a copy of initialized
+ ** fairly obscure circumstances, even though it is a copy of initialized
** page pFrom.
*/
pTo->isInit = 0;
rc = btreeInitPage(pTo);
+ if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo);
if( rc!=SQLITE_OK ){
*pRC = rc;
return;
}
-
+
/* If this is an auto-vacuum database, update the pointer-map entries
** for any b-tree or overflow pages that pTo now contains the pointers to.
*/
@@ -65182,13 +71962,13 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** (hereafter "the page") and up to 2 siblings so that all pages have about the
** same amount of free space. Usually a single sibling on either side of the
** page are used in the balancing, though both siblings might come from one
-** side if the page is the first or last child of its parent. If the page
+** side if the page is the first or last child of its parent. If the page
** has fewer than 2 siblings (something which can only happen if the page
** is a root page or a child of a root page) then all available siblings
** participate in the balancing.
**
-** The number of siblings of the page might be increased or decreased by
-** one or two in an effort to keep pages nearly full but not over full.
+** The number of siblings of the page might be increased or decreased by
+** one or two in an effort to keep pages nearly full but not over full.
**
** Note that when this routine is called, some of the cells on the page
** might not actually be stored in MemPage.aData[]. This can happen
@@ -65199,7 +71979,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** inserted into or removed from the parent page (pParent). Doing so
** may cause the parent page to become overfull or underfull. If this
** happens, it is the responsibility of the caller to invoke the correct
-** balancing routine to fix this problem (see the balance() routine).
+** balancing routine to fix this problem (see the balance() routine).
**
** If this routine fails for any reason, it might leave the database
** in a corrupted state. So if this routine fails, the database should
@@ -65214,7 +71994,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
** of the page-size, the aOvflSpace[] buffer is guaranteed to be large
** enough for all overflow cells.
**
-** If aOvflSpace is set to a null pointer, this function returns
+** If aOvflSpace is set to a null pointer, this function returns
** SQLITE_NOMEM.
*/
static int balance_nonroot(
@@ -65260,12 +72040,8 @@ static int balance_nonroot(
assert( sqlite3_mutex_held(pBt->mutex) );
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
-#if 0
- TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
-#endif
-
/* At this point pParent may have at most one overflow cell. And if
- ** this overflow cell is present, it must be the cell with
+ ** this overflow cell is present, it must be the cell with
** index iParentIdx. This scenario comes about when this function
** is called (indirectly) from sqlite3BtreeDelete().
*/
@@ -65275,12 +72051,13 @@ static int balance_nonroot(
if( !aOvflSpace ){
return SQLITE_NOMEM_BKPT;
}
+ assert( pParent->nFree>=0 );
- /* Find the sibling pages to balance. Also locate the cells in pParent
- ** that divide the siblings. An attempt is made to find NN siblings on
- ** either side of pPage. More siblings are taken from one side, however,
+ /* Find the sibling pages to balance. Also locate the cells in pParent
+ ** that divide the siblings. An attempt is made to find NN siblings on
+ ** either side of pPage. More siblings are taken from one side, however,
** if there are fewer than NN siblings on the other side. If pParent
- ** has NB or fewer children then all children of pParent are taken.
+ ** has NB or fewer children then all children of pParent are taken.
**
** This loop also drops the divider cells from the parent page. This
** way, the remainder of the function does not have to deal with any
@@ -65292,7 +72069,7 @@ static int balance_nonroot(
nxDiv = 0;
}else{
assert( bBulk==0 || bBulk==1 );
- if( iParentIdx==0 ){
+ if( iParentIdx==0 ){
nxDiv = 0;
}else if( iParentIdx==i ){
nxDiv = i-2+bBulk;
@@ -65314,10 +72091,16 @@ static int balance_nonroot(
memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup;
}
- nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
+ if( apOld[i]->nFree<0 ){
+ rc = btreeComputeFreeSpace(apOld[i]);
+ if( rc ){
+ memset(apOld, 0, (i)*sizeof(MemPage*));
+ goto balance_cleanup;
+ }
+ }
if( (i--)==0 ) break;
- if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
+ if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){
apDiv[i] = pParent->apOvfl[0];
pgno = get4byte(apDiv[i]);
szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
@@ -65332,14 +72115,14 @@ static int balance_nonroot(
** This is safe because dropping a cell only overwrites the first
** four bytes of it, and this function does not need the first
** four bytes of the divider cell. So the pointer is safe to use
- ** later on.
+ ** later on.
**
** But not if we are in secure-delete mode. In secure-delete mode,
** the dropCell() routine will overwrite the entire cell with zeroes.
** In this case, temporarily copy the cell into the aOvflSpace[]
** buffer. It will be copied out again as soon as the aSpace[] buffer
** is allocated. */
- if( pBt->btsFlags & BTS_SECURE_DELETE ){
+ if( pBt->btsFlags & BTS_FAST_SECURE ){
int iOff;
iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
@@ -65358,6 +72141,7 @@ static int balance_nonroot(
/* Make nMaxCells a multiple of 4 in order to preserve 8-byte
** alignment */
+ nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl));
nMaxCells = (nMaxCells + 3)&~3;
/*
@@ -65368,10 +72152,8 @@ static int balance_nonroot(
+ nMaxCells*sizeof(u16) /* b.szCell */
+ pBt->pageSize; /* aSpace1 */
- /* EVIDENCE-OF: R-28375-38319 SQLite will never request a scratch buffer
- ** that is more than 6 times the database page size. */
- assert( szScratch<=6*(int)pBt->pageSize );
- b.apCell = sqlite3ScratchMalloc( szScratch );
+ assert( szScratch<=7*(int)pBt->pageSize );
+ b.apCell = sqlite3StackAllocRaw(0, szScratch );
if( b.apCell==0 ){
rc = SQLITE_NOMEM_BKPT;
goto balance_cleanup;
@@ -65406,6 +72188,7 @@ static int balance_nonroot(
u16 maskPage = pOld->maskPage;
u8 *piCell = aData + pOld->cellOffset;
u8 *piEnd;
+ VVA_ONLY( int nCellAtStart = b.nCell; )
/* Verify that all sibling pages are of the same "type" (table-leaf,
** table-interior, index-leaf, or index-interior).
@@ -65416,7 +72199,7 @@ static int balance_nonroot(
}
/* Load b.apCell[] with pointers to all cells in pOld. If pOld
- ** constains overflow cells, include them in the b.apCell[] array
+ ** contains overflow cells, include them in the b.apCell[] array
** in the correct spot.
**
** Note that when there are multiple overflow cells, it is always the
@@ -65434,6 +72217,10 @@ static int balance_nonroot(
*/
memset(&b.szCell[b.nCell], 0, sizeof(b.szCell[0])*(limit+pOld->nOverflow));
if( pOld->nOverflow>0 ){
+ if( NEVER(limit<pOld->aiOvfl[0]) ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto balance_cleanup;
+ }
limit = pOld->aiOvfl[0];
for(j=0; j<limit; j++){
b.apCell[b.nCell] = aData + (maskPage & get2byteAligned(piCell));
@@ -65453,6 +72240,7 @@ static int balance_nonroot(
piCell += 2;
b.nCell++;
}
+ assert( (b.nCell-nCellAtStart)==(pOld->nCell+pOld->nOverflow) );
cntOld[i] = b.nCell;
if( i<nOld-1 && !leafData){
@@ -65493,7 +72281,7 @@ static int balance_nonroot(
** Figure out the number of pages needed to hold all b.nCell cells.
** Store this number in "k". Also compute szNew[] which is the total
** size of all cells on the i-th page and cntNew[] which is the index
- ** in b.apCell[] of the cell that divides page i from page i+1.
+ ** in b.apCell[] of the cell that divides page i from page i+1.
** cntNew[k] should equal b.nCell.
**
** Values computed by this block:
@@ -65503,13 +72291,23 @@ static int balance_nonroot(
** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to
** the right of the i-th sibling page.
** usableSpace: Number of bytes of space available on each sibling.
- **
+ **
*/
usableSpace = pBt->usableSize - 12 + leafCorrection;
- for(i=0; i<nOld; i++){
+ for(i=k=0; i<nOld; i++, k++){
MemPage *p = apOld[i];
+ b.apEnd[k] = p->aDataEnd;
+ b.ixNx[k] = cntOld[i];
+ if( k && b.ixNx[k]==b.ixNx[k-1] ){
+ k--; /* Omit b.ixNx[] entry for child pages with no cells */
+ }
+ if( !leafData ){
+ k++;
+ b.apEnd[k] = pParent->aDataEnd;
+ b.ixNx[k] = cntOld[i]+1;
+ }
+ assert( p->nFree>=0 );
szNew[i] = usableSpace - p->nFree;
- if( szNew[i]<0 ){ rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; }
for(j=0; j<p->nOverflow; j++){
szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]);
}
@@ -65647,15 +72445,15 @@ static int balance_nonroot(
}
/*
- ** Reassign page numbers so that the new pages are in ascending order.
+ ** Reassign page numbers so that the new pages are in ascending order.
** This helps to keep entries in the disk file in order so that a scan
- ** of the table is closer to a linear scan through the file. That in turn
+ ** of the table is closer to a linear scan through the file. That in turn
** helps the operating system to deliver pages from the disk more rapidly.
**
- ** An O(n^2) insertion sort algorithm is used, but since n is never more
+ ** An O(n^2) insertion sort algorithm is used, but since n is never more
** than (NB+2) (a small constant), that should not be a problem.
**
- ** When NB==3, this one optimization makes the database about 25% faster
+ ** When NB==3, this one optimization makes the database about 25% faster
** for large insertions and deletions.
*/
for(i=0; i<nNew; i++){
@@ -65664,7 +72462,7 @@ static int balance_nonroot(
for(j=0; j<i; j++){
if( aPgno[j]==aPgno[i] ){
/* This branch is taken if the set of sibling pages somehow contains
- ** duplicate entries. This can happen if the database is corrupt.
+ ** duplicate entries. This can happen if the database is corrupt.
** It would be simpler to detect this as part of the loop below, but
** we do the detection here in order to avoid populating the pager
** cache with two separate objects associated with the same
@@ -65705,17 +72503,19 @@ static int balance_nonroot(
));
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
+ assert( nNew>=1 && nNew<=ArraySize(apNew) );
+ assert( apNew[nNew-1]!=0 );
put4byte(pRight, apNew[nNew-1]->pgno);
/* If the sibling pages are not leaves, ensure that the right-child pointer
- ** of the right-most new sibling page is set to the value that was
+ ** of the right-most new sibling page is set to the value that was
** originally in the same field of the right-most old sibling page. */
if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){
MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1];
memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4);
}
- /* Make any required updates to pointer map entries associated with
+ /* Make any required updates to pointer map entries associated with
** cells stored on sibling pages following the balance operation. Pointer
** map entries associated with divider cells are set by the insertCell()
** routine. The associated pointer map entries are:
@@ -65726,25 +72526,26 @@ static int balance_nonroot(
** b) if the sibling pages are not leaves, the child page associated
** with the cell.
**
- ** If the sibling pages are not leaves, then the pointer map entry
- ** associated with the right-child of each sibling may also need to be
- ** updated. This happens below, after the sibling pages have been
+ ** If the sibling pages are not leaves, then the pointer map entry
+ ** associated with the right-child of each sibling may also need to be
+ ** updated. This happens below, after the sibling pages have been
** populated, not here.
*/
if( ISAUTOVACUUM ){
- MemPage *pNew = apNew[0];
- u8 *aOld = pNew->aData;
+ MemPage *pOld;
+ MemPage *pNew = pOld = apNew[0];
int cntOldNext = pNew->nCell + pNew->nOverflow;
- int usableSize = pBt->usableSize;
int iNew = 0;
int iOld = 0;
for(i=0; i<b.nCell; i++){
u8 *pCell = b.apCell[i];
- if( i==cntOldNext ){
- MemPage *pOld = (++iOld)<nNew ? apNew[iOld] : apOld[iOld];
+ while( i==cntOldNext ){
+ iOld++;
+ assert( iOld<nNew || iOld<nOld );
+ assert( iOld>=0 && iOld<NB );
+ pOld = iOld<nNew ? apNew[iOld] : apOld[iOld];
cntOldNext += pOld->nCell + pOld->nOverflow + !leafData;
- aOld = pOld->aData;
}
if( i==cntNew[iNew] ){
pNew = apNew[++iNew];
@@ -65752,20 +72553,20 @@ static int balance_nonroot(
}
/* Cell pCell is destined for new sibling page pNew. Originally, it
- ** was either part of sibling page iOld (possibly an overflow cell),
+ ** was either part of sibling page iOld (possibly an overflow cell),
** or else the divider cell to the left of sibling page iOld. So,
** if sibling page iOld had the same page number as pNew, and if
** pCell really was a part of sibling page iOld (not a divider or
** overflow cell), we can skip updating the pointer map entries. */
if( iOld>=nNew
|| pNew->pgno!=aPgno[iOld]
- || !SQLITE_WITHIN(pCell,aOld,&aOld[usableSize])
+ || !SQLITE_WITHIN(pCell,pOld->aData,pOld->aDataEnd)
){
if( !leafCorrection ){
ptrmapPut(pBt, get4byte(pCell), PTRMAP_BTREE, pNew->pgno, &rc);
}
if( cachedCellSize(&b,i)>pNew->minLocal ){
- ptrmapPutOvflPtr(pNew, pCell, &rc);
+ ptrmapPutOvflPtr(pNew, pOld, pCell, &rc);
}
if( rc ) goto balance_cleanup;
}
@@ -65788,9 +72589,9 @@ static int balance_nonroot(
if( !pNew->leaf ){
memcpy(&pNew->aData[8], pCell, 4);
}else if( leafData ){
- /* If the tree is a leaf-data tree, and the siblings are leaves,
- ** then there is no divider cell in b.apCell[]. Instead, the divider
- ** cell consists of the integer key for the right-most cell of
+ /* If the tree is a leaf-data tree, and the siblings are leaves,
+ ** then there is no divider cell in b.apCell[]. Instead, the divider
+ ** cell consists of the integer key for the right-most cell of
** the sibling-page assembled above only.
*/
CellInfo info;
@@ -65803,9 +72604,9 @@ static int balance_nonroot(
pCell -= 4;
/* Obscure case for non-leaf-data trees: If the cell at pCell was
** previously stored on a leaf node, and its reported size was 4
- ** bytes, then it may actually be smaller than this
+ ** bytes, then it may actually be smaller than this
** (see btreeParseCellPtr(), 4 bytes is the minimum size of
- ** any cell). But it is important to pass the correct size to
+ ** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
@@ -65897,8 +72698,8 @@ static int balance_nonroot(
** b-tree structure by one. This is described as the "balance-shallower"
** sub-algorithm in some documentation.
**
- ** If this is an auto-vacuum database, the call to copyNodeContent()
- ** sets all pointer-map entries corresponding to database image pages
+ ** If this is an auto-vacuum database, the call to copyNodeContent()
+ ** sets all pointer-map entries corresponding to database image pages
** for which the pointer is stored within the content being copied.
**
** It is critical that the child page be defragmented before being
@@ -65907,10 +72708,11 @@ static int balance_nonroot(
** free space needs to be up front.
*/
assert( nNew==1 || CORRUPT_DB );
- rc = defragmentPage(apNew[0]);
+ rc = defragmentPage(apNew[0], -1);
testcase( rc!=SQLITE_OK );
- assert( apNew[0]->nFree ==
- (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2)
+ assert( apNew[0]->nFree ==
+ (get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset
+ - apNew[0]->nCell*2)
|| rc!=SQLITE_OK
);
copyNodeContent(apNew[0], pParent, &rc);
@@ -65938,7 +72740,7 @@ static int balance_nonroot(
#if 0
if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
/* The ptrmapCheckPages() contains assert() statements that verify that
- ** all pointer map pages are set correctly. This is helpful while
+ ** all pointer map pages are set correctly. This is helpful while
** debugging. This is usually disabled because a corrupt database may
** cause an assert() statement to fail. */
ptrmapCheckPages(apNew, nNew);
@@ -65950,7 +72752,7 @@ static int balance_nonroot(
** Cleanup before returning.
*/
balance_cleanup:
- sqlite3ScratchFree(b.apCell);
+ sqlite3StackFree(0, b.apCell);
for(i=0; i<nOld; i++){
releasePage(apOld[i]);
}
@@ -65968,15 +72770,15 @@ balance_cleanup:
**
** A new child page is allocated and the contents of the current root
** page, including overflow cells, are copied into the child. The root
-** page is then overwritten to make it an empty page with the right-child
+** page is then overwritten to make it an empty page with the right-child
** pointer pointing to the new page.
**
-** Before returning, all pointer-map entries corresponding to pages
+** Before returning, all pointer-map entries corresponding to pages
** that the new child-page now contains pointers to are updated. The
** entry corresponding to the new right-child pointer of the root
** page is also updated.
**
-** If successful, *ppChild is set to contain a reference to the child
+** If successful, *ppChild is set to contain a reference to the child
** page and SQLITE_OK is returned. In this case the caller is required
** to call releasePage() on *ppChild exactly once. If an error occurs,
** an error code is returned and *ppChild is set to 0.
@@ -65990,7 +72792,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
assert( pRoot->nOverflow>0 );
assert( sqlite3_mutex_held(pBt->mutex) );
- /* Make pRoot, the root page of the b-tree, writable. Allocate a new
+ /* Make pRoot, the root page of the b-tree, writable. Allocate a new
** page that will become the new right-child of pPage. Copy the contents
** of the node stored on pRoot into the new child page.
*/
@@ -66009,7 +72811,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
}
assert( sqlite3PagerIswriteable(pChild->pDbPage) );
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
- assert( pChild->nCell==pRoot->nCell );
+ assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
@@ -66029,9 +72831,33 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
}
/*
+** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
+** on the same B-tree as pCur.
+**
+** This can if a database is corrupt with two or more SQL tables
+** pointing to the same b-tree. If an insert occurs on one SQL table
+** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
+** table linked to the same b-tree. If the secondary insert causes a
+** rebalance, that can change content out from under the cursor on the
+** first SQL table, violating invariants on the first insert.
+*/
+static int anotherValidCursor(BtCursor *pCur){
+ BtCursor *pOther;
+ for(pOther=pCur->pBt->pCursor; pOther; pOther=pOther->pNext){
+ if( pOther!=pCur
+ && pOther->eState==CURSOR_VALID
+ && pOther->pPage==pCur->pPage
+ ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
** The page that pCur currently points to has just been modified in
** some way. This function figures out if this modification means the
-** tree needs to be balanced, and if so calls the appropriate balancing
+** tree needs to be balanced, and if so calls the appropriate balancing
** routine. Balancing routines are:
**
** balance_quick()
@@ -66048,35 +72874,41 @@ static int balance(BtCursor *pCur){
VVA_ONLY( int balance_deeper_called = 0 );
do {
- int iPage = pCur->iPage;
- MemPage *pPage = pCur->apPage[iPage];
+ int iPage;
+ MemPage *pPage = pCur->pPage;
- if( iPage==0 ){
- if( pPage->nOverflow ){
+ if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
+ if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
+ break;
+ }else if( (iPage = pCur->iPage)==0 ){
+ if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
/* The root page of the b-tree is overfull. In this case call the
** balance_deeper() function to create a new child for the root-page
** and copy the current contents of the root-page to it. The
** next iteration of the do-loop will balance the child page.
- */
+ */
assert( balance_deeper_called==0 );
VVA_ONLY( balance_deeper_called++ );
rc = balance_deeper(pPage, &pCur->apPage[1]);
if( rc==SQLITE_OK ){
pCur->iPage = 1;
+ pCur->ix = 0;
pCur->aiIdx[0] = 0;
- pCur->aiIdx[1] = 0;
- assert( pCur->apPage[1]->nOverflow );
+ pCur->apPage[0] = pPage;
+ pCur->pPage = pCur->apPage[1];
+ assert( pCur->pPage->nOverflow );
}
}else{
break;
}
- }else if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
- break;
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
rc = sqlite3PagerWrite(pParent->pDbPage);
+ if( rc==SQLITE_OK && pParent->nFree<0 ){
+ rc = btreeComputeFreeSpace(pParent);
+ }
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
if( pPage->intKeyLeaf
@@ -66088,17 +72920,17 @@ static int balance(BtCursor *pCur){
/* Call balance_quick() to create a new sibling of pPage on which
** to store the overflow cell. balance_quick() inserts a new cell
** into pParent, which may cause pParent overflow. If this
- ** happens, the next iteration of the do-loop will balance pParent
+ ** happens, the next iteration of the do-loop will balance pParent
** use either balance_nonroot() or balance_deeper(). Until this
** happens, the overflow cell is stored in the aBalanceQuickSpace[]
- ** buffer.
+ ** buffer.
**
** The purpose of the following assert() is to check that only a
** single call to balance_quick() is made for each call to this
** function. If this were not verified, a subtle bug involving reuse
** of the aBalanceQuickSpace[] might sneak in.
*/
- assert( balance_quick_called==0 );
+ assert( balance_quick_called==0 );
VVA_ONLY( balance_quick_called++ );
rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
}else
@@ -66109,15 +72941,15 @@ static int balance(BtCursor *pCur){
** modifying the contents of pParent, which may cause pParent to
** become overfull or underfull. The next iteration of the do-loop
** will balance the parent page to correct this.
- **
+ **
** If the parent page becomes overfull, the overflow cell or cells
- ** are stored in the pSpace buffer allocated immediately below.
+ ** are stored in the pSpace buffer allocated immediately below.
** A subsequent iteration of the do-loop will deal with this by
** calling balance_nonroot() (balance_deeper() may be called first,
** but it doesn't deal with overflow cells - just moves them to a
- ** different page). Once this subsequent call to balance_nonroot()
+ ** different page). Once this subsequent call to balance_nonroot()
** has completed, it is safe to release the pSpace buffer used by
- ** the previous call, as the overflow cell data will have been
+ ** the previous call, as the overflow cell data will have been
** copied either into the body of a database page or into the new
** pSpace buffer passed to the latter call to balance_nonroot().
*/
@@ -66125,9 +72957,9 @@ static int balance(BtCursor *pCur){
rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1,
pCur->hints&BTREE_BULKLOAD);
if( pFree ){
- /* If pFree is not NULL, it points to the pSpace buffer used
+ /* If pFree is not NULL, it points to the pSpace buffer used
** by a previous call to balance_nonroot(). Its contents are
- ** now stored either on real database pages or within the
+ ** now stored either on real database pages or within the
** new pSpace buffer, so it may be safely freed here. */
sqlite3PageFree(pFree);
}
@@ -66145,6 +72977,7 @@ static int balance(BtCursor *pCur){
releasePage(pPage);
pCur->iPage--;
assert( pCur->iPage>=0 );
+ pCur->pPage = pCur->apPage[pCur->iPage];
}
}while( rc==SQLITE_OK );
@@ -66154,6 +72987,100 @@ static int balance(BtCursor *pCur){
return rc;
}
+/* Overwrite content from pX into pDest. Only do the write if the
+** content is different from what is already there.
+*/
+static int btreeOverwriteContent(
+ MemPage *pPage, /* MemPage on which writing will occur */
+ u8 *pDest, /* Pointer to the place to start writing */
+ const BtreePayload *pX, /* Source of data to write */
+ int iOffset, /* Offset of first byte to write */
+ int iAmt /* Number of bytes to be written */
+){
+ int nData = pX->nData - iOffset;
+ if( nData<=0 ){
+ /* Overwritting with zeros */
+ int i;
+ for(i=0; i<iAmt && pDest[i]==0; i++){}
+ if( i<iAmt ){
+ int rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( rc ) return rc;
+ memset(pDest + i, 0, iAmt - i);
+ }
+ }else{
+ if( nData<iAmt ){
+ /* Mixed read data and zeros at the end. Make a recursive call
+ ** to write the zeros then fall through to write the real data */
+ int rc = btreeOverwriteContent(pPage, pDest+nData, pX, iOffset+nData,
+ iAmt-nData);
+ if( rc ) return rc;
+ iAmt = nData;
+ }
+ if( memcmp(pDest, ((u8*)pX->pData) + iOffset, iAmt)!=0 ){
+ int rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( rc ) return rc;
+ /* In a corrupt database, it is possible for the source and destination
+ ** buffers to overlap. This is harmless since the database is already
+ ** corrupt but it does cause valgrind and ASAN warnings. So use
+ ** memmove(). */
+ memmove(pDest, ((u8*)pX->pData) + iOffset, iAmt);
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Overwrite the cell that cursor pCur is pointing to with fresh content
+** contained in pX.
+*/
+static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
+ int iOffset; /* Next byte of pX->pData to write */
+ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
+ int rc; /* Return code */
+ MemPage *pPage = pCur->pPage; /* Page being written */
+ BtShared *pBt; /* Btree */
+ Pgno ovflPgno; /* Next overflow page to write */
+ u32 ovflPageSize; /* Size to write on overflow page */
+
+ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
+ || pCur->info.pPayload < pPage->aData + pPage->cellOffset
+ ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ /* Overwrite the local portion first */
+ rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
+ 0, pCur->info.nLocal);
+ if( rc ) return rc;
+ if( pCur->info.nLocal==nTotal ) return SQLITE_OK;
+
+ /* Now overwrite the overflow pages */
+ iOffset = pCur->info.nLocal;
+ assert( nTotal>=0 );
+ assert( iOffset>=0 );
+ ovflPgno = get4byte(pCur->info.pPayload + iOffset);
+ pBt = pPage->pBt;
+ ovflPageSize = pBt->usableSize - 4;
+ do{
+ rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
+ if( rc ) return rc;
+ if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ if( iOffset+ovflPageSize<(u32)nTotal ){
+ ovflPgno = get4byte(pPage->aData);
+ }else{
+ ovflPageSize = nTotal - iOffset;
+ }
+ rc = btreeOverwriteContent(pPage, pPage->aData+4, pX,
+ iOffset, ovflPageSize);
+ }
+ sqlite3PagerUnref(pPage->pDbPage);
+ if( rc ) return rc;
+ iOffset += ovflPageSize;
+ }while( iOffset<nTotal );
+ return SQLITE_OK;
+}
+
/*
** Insert a new record into the BTree. The content of the new record
@@ -66167,26 +73094,28 @@ static int balance(BtCursor *pCur){
** hold the content of the row.
**
** For an index btree (used for indexes and WITHOUT ROWID tables), the
-** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
+** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
** pX.pData,nData,nZero fields must be zero.
**
** If the seekResult parameter is non-zero, then a successful call to
-** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
-** been performed. seekResult is the search result returned (a negative
-** number if pCur points at an entry that is smaller than (pKey, nKey), or
-** a positive value if pCur points at an entry that is larger than
-** (pKey, nKey)).
-**
-** If the seekResult parameter is non-zero, then the caller guarantees that
-** cursor pCur is pointing at the existing copy of a row that is to be
-** overwritten. If the seekResult parameter is 0, then cursor pCur may
-** point to any entry or to no entry at all and so this function has to seek
-** the cursor before the new key can be inserted.
+** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already
+** been performed. In other words, if seekResult!=0 then the cursor
+** is currently pointing to a cell that will be adjacent to the cell
+** to be inserted. If seekResult<0 then pCur points to a cell that is
+** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell
+** that is larger than (pKey,nKey).
+**
+** If seekResult==0, that means pCur is pointing at some unknown location.
+** In that case, this routine must seek the cursor to the correct insertion
+** point for (pKey,nKey) before doing the insertion. For index btrees,
+** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked
+** key values and pX->aMem can be used instead of pX->pKey to avoid having
+** to decode the key.
*/
SQLITE_PRIVATE int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
const BtreePayload *pX, /* Content of the row to be inserted */
- int appendBias, /* True if this is likely an append */
+ int flags, /* True if this is likely an append */
int seekResult /* Result of prior MovetoUnpacked() call */
){
int rc;
@@ -66199,6 +73128,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
unsigned char *oldCell;
unsigned char *newCell = 0;
+ assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags );
+
if( pCur->eState==CURSOR_FAULT ){
assert( pCur->skipNext!=SQLITE_OK );
return pCur->skipNext;
@@ -66221,8 +73152,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
**
** In some cases, the call to btreeMoveto() below is a no-op. For
** example, when inserting data into a table with auto-generated integer
- ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
- ** integer key to use. It then calls this function to actually insert the
+ ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
+ ** integer key to use. It then calls this function to actually insert the
** data into the intkey B-Tree. In this case btreeMoveto() recognizes
** that the cursor is already where it needs to be and returns without
** doing any work. To avoid thwarting these optimizations, it is important
@@ -66235,29 +73166,106 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( pCur->pKeyInfo==0 ){
assert( pX->pKey==0 );
- /* If this is an insert into a table b-tree, invalidate any incrblob
+ /* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
- invalidateIncrblobCursors(p, pX->nKey, 0);
-
- /* If the cursor is currently on the last row and we are appending a
- ** new row onto the end, set the "loc" to avoid an unnecessary
- ** btreeMoveto() call */
- if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
- && pCur->info.nKey==pX->nKey-1 ){
- loc = -1;
+ invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
+
+ /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
+ ** to a row with the same key as the new entry being inserted.
+ */
+#ifdef SQLITE_DEBUG
+ if( flags & BTREE_SAVEPOSITION ){
+ assert( pCur->curFlags & BTCF_ValidNKey );
+ assert( pX->nKey==pCur->info.nKey );
+ assert( loc==0 );
+ }
+#endif
+
+ /* On the other hand, BTREE_SAVEPOSITION==0 does not imply
+ ** that the cursor is not pointing to a row to be overwritten.
+ ** So do a complete check.
+ */
+ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
+ /* The cursor is pointing to the entry that is to be
+ ** overwritten */
+ assert( pX->nData>=0 && pX->nZero>=0 );
+ if( pCur->info.nSize!=0
+ && pCur->info.nPayload==(u32)pX->nData+pX->nZero
+ ){
+ /* New entry is the same size as the old. Do an overwrite */
+ return btreeOverwriteCell(pCur, pX);
+ }
+ assert( loc==0 );
}else if( loc==0 ){
- rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, appendBias, &loc);
+ /* The cursor is *not* pointing to the cell to be overwritten, nor
+ ** to an adjacent cell. Move the cursor so that it is pointing either
+ ** to the cell to be overwritten or an adjacent cell.
+ */
+ rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
if( rc ) return rc;
}
- }else if( loc==0 ){
- rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc);
- if( rc ) return rc;
+ }else{
+ /* This is an index or a WITHOUT ROWID table */
+
+ /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
+ ** to a row with the same key as the new entry being inserted.
+ */
+ assert( (flags & BTREE_SAVEPOSITION)==0 || loc==0 );
+
+ /* If the cursor is not already pointing either to the cell to be
+ ** overwritten, or if a new cell is being inserted, if the cursor is
+ ** not pointing to an immediately adjacent cell, then move the cursor
+ ** so that it does.
+ */
+ if( loc==0 && (flags & BTREE_SAVEPOSITION)==0 ){
+ if( pX->nMem ){
+ UnpackedRecord r;
+ r.pKeyInfo = pCur->pKeyInfo;
+ r.aMem = pX->aMem;
+ r.nField = pX->nMem;
+ r.default_rc = 0;
+ r.errCode = 0;
+ r.r1 = 0;
+ r.r2 = 0;
+ r.eqSeen = 0;
+ rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc);
+ }else{
+ rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc);
+ }
+ if( rc ) return rc;
+ }
+
+ /* If the cursor is currently pointing to an entry to be overwritten
+ ** and the new content is the same as as the old, then use the
+ ** overwrite optimization.
+ */
+ if( loc==0 ){
+ getCellInfo(pCur);
+ if( pCur->info.nKey==pX->nKey ){
+ BtreePayload x2;
+ x2.pData = pX->pKey;
+ x2.nData = pX->nKey;
+ x2.nZero = 0;
+ return btreeOverwriteCell(pCur, &x2);
+ }
+ }
+
}
- assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
+ assert( pCur->eState==CURSOR_VALID
+ || (pCur->eState==CURSOR_INVALID && loc)
+ || CORRUPT_DB );
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
+ if( pPage->nFree<0 ){
+ if( pCur->eState>CURSOR_INVALID ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = btreeComputeFreeSpace(pPage);
+ }
+ if( rc ) return rc;
+ }
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
@@ -66269,9 +73277,9 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) );
- idx = pCur->aiIdx[pCur->iPage];
+ idx = pCur->ix;
if( loc==0 ){
- u16 szOld;
+ CellInfo info;
assert( idx<pPage->nCell );
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ){
@@ -66281,12 +73289,37 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( !pPage->leaf ){
memcpy(newCell, oldCell, 4);
}
- rc = clearCell(pPage, oldCell, &szOld);
- dropCell(pPage, idx, szOld, &rc);
+ rc = clearCell(pPage, oldCell, &info);
+ testcase( pCur->curFlags & BTCF_ValidOvfl );
+ invalidateOverflowCache(pCur);
+ if( info.nSize==szNew && info.nLocal==info.nPayload
+ && (!ISAUTOVACUUM || szNew<pPage->minLocal)
+ ){
+ /* Overwrite the old cell with the new if they are the same size.
+ ** We could also try to do this if the old cell is smaller, then add
+ ** the leftover space to the free list. But experiments show that
+ ** doing that is no faster then skipping this optimization and just
+ ** calling dropCell() and insertCell().
+ **
+ ** This optimization cannot be used on an autovacuum database if the
+ ** new entry uses overflow pages, as the insertCell() call below is
+ ** necessary to add the PTRMAP_OVERFLOW1 pointer-map entry. */
+ assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
+ if( oldCell < pPage->aData+pPage->hdrOffset+10 ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ if( oldCell+szNew > pPage->aDataEnd ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ memcpy(oldCell, newCell, szNew);
+ return SQLITE_OK;
+ }
+ dropCell(pPage, idx, info.nSize, &rc);
if( rc ) goto end_insert;
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
- idx = ++pCur->aiIdx[pCur->iPage];
+ idx = ++pCur->ix;
+ pCur->curFlags &= ~BTCF_ValidNKey;
}else{
assert( pPage->leaf );
}
@@ -66294,7 +73327,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
- /* If no error has occurred and pPage has an overflow cell, call balance()
+ /* If no error has occurred and pPage has an overflow cell, call balance()
** to redistribute the cells within the tree. Since balance() may move
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
** variables.
@@ -66321,20 +73354,34 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
- ** fails. Internal data structure corruption will result otherwise.
+ ** fails. Internal data structure corruption will result otherwise.
** Also, set the cursor state to invalid. This stops saveCursorPosition()
** from trying to save the current position of the cursor. */
- pCur->apPage[pCur->iPage]->nOverflow = 0;
+ pCur->pPage->nOverflow = 0;
pCur->eState = CURSOR_INVALID;
+ if( (flags & BTREE_SAVEPOSITION) && rc==SQLITE_OK ){
+ btreeReleaseAllCursorPages(pCur);
+ if( pCur->pKeyInfo ){
+ assert( pCur->pKey==0 );
+ pCur->pKey = sqlite3Malloc( pX->nKey );
+ if( pCur->pKey==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memcpy(pCur->pKey, pX->pKey, pX->nKey);
+ }
+ }
+ pCur->eState = CURSOR_REQUIRESEEK;
+ pCur->nKey = pX->nKey;
+ }
}
- assert( pCur->apPage[pCur->iPage]->nOverflow==0 );
+ assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 );
end_insert:
return rc;
}
/*
-** Delete the entry that the cursor is pointing to.
+** Delete the entry that the cursor is pointing to.
**
** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
** the cursor is left pointing at an arbitrary location after the delete.
@@ -66352,13 +73399,13 @@ end_insert:
*/
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
Btree *p = pCur->pBtree;
- BtShared *pBt = p->pBt;
+ BtShared *pBt = p->pBt;
int rc; /* Return code */
MemPage *pPage; /* Page to delete cell from */
unsigned char *pCell; /* Pointer to cell to delete */
int iCellIdx; /* Index of cell to delete */
- int iCellDepth; /* Depth of node containing pCell */
- u16 szCell; /* Size of the cell being deleted */
+ int iCellDepth; /* Depth of node containing pCell */
+ CellInfo info; /* Size of the cell being deleted */
int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */
@@ -66368,27 +73415,32 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( pCur->curFlags & BTCF_WriteFlag );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
- assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
- assert( pCur->eState==CURSOR_VALID );
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
+ if( pCur->eState==CURSOR_REQUIRESEEK ){
+ rc = btreeRestoreCursorPosition(pCur);
+ if( rc ) return rc;
+ }
+ assert( pCur->eState==CURSOR_VALID );
iCellDepth = pCur->iPage;
- iCellIdx = pCur->aiIdx[iCellDepth];
- pPage = pCur->apPage[iCellDepth];
+ iCellIdx = pCur->ix;
+ pPage = pCur->pPage;
pCell = findCell(pPage, iCellIdx);
+ if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT;
/* If the bPreserve flag is set to true, then the cursor position must
** be preserved following this delete operation. If the current delete
** will cause a b-tree rebalance, then this is done by saving the cursor
- ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
- ** returning.
+ ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
+ ** returning.
**
** Or, if the current delete will not cause a rebalance, then the cursor
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
** before or after the deleted entry. In this case set bSkipnext to true. */
if( bPreserve ){
- if( !pPage->leaf
+ if( !pPage->leaf
|| (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
+ || pPage->nCell==1 /* See dbfuzz001.test for a test case */
){
/* A b-tree rebalance will be required after deleting this entry.
** Save the cursor key. */
@@ -66407,8 +73459,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** sub-tree headed by the child page of the cell being deleted. This makes
** balancing the tree following the delete operation easier. */
if( !pPage->leaf ){
- int notUsed = 0;
- rc = sqlite3BtreePrevious(pCur, &notUsed);
+ rc = sqlite3BtreePrevious(pCur, 0);
+ assert( rc!=SQLITE_DONE );
if( rc ) return rc;
}
@@ -66422,7 +73474,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
/* If this is a delete operation to remove a row from a table b-tree,
** invalidate any incrblob cursors open on the row being deleted. */
if( pCur->pKeyInfo==0 ){
- invalidateIncrblobCursors(p, pCur->info.nKey, 0);
+ invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
}
/* Make the page containing the entry to be deleted writable. Then free any
@@ -66430,8 +73482,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** itself from within the page. */
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
- rc = clearCell(pPage, pCell, &szCell);
- dropCell(pPage, iCellIdx, szCell, &rc);
+ rc = clearCell(pPage, pCell, &info);
+ dropCell(pPage, iCellIdx, info.nSize, &rc);
if( rc ) return rc;
/* If the cell deleted was not located on a leaf page, then the cursor
@@ -66440,11 +73492,20 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** node. The cell from the leaf node needs to be moved to the internal
** node to replace the deleted cell. */
if( !pPage->leaf ){
- MemPage *pLeaf = pCur->apPage[pCur->iPage];
+ MemPage *pLeaf = pCur->pPage;
int nCell;
- Pgno n = pCur->apPage[iCellDepth+1]->pgno;
+ Pgno n;
unsigned char *pTmp;
+ if( pLeaf->nFree<0 ){
+ rc = btreeComputeFreeSpace(pLeaf);
+ if( rc ) return rc;
+ }
+ if( iCellDepth<pCur->iPage-1 ){
+ n = pCur->apPage[iCellDepth+1]->pgno;
+ }else{
+ n = pCur->pPage->pgno;
+ }
pCell = findCell(pLeaf, pLeaf->nCell-1);
if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT;
nCell = pLeaf->xCellSize(pLeaf, pCell);
@@ -66472,33 +73533,38 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** on the leaf node first. If the balance proceeds far enough up the
** tree that we can be sure that any problem in the internal node has
** been corrected, so be it. Otherwise, after balancing the leaf node,
- ** walk the cursor up the tree to the internal node and balance it as
+ ** walk the cursor up the tree to the internal node and balance it as
** well. */
rc = balance(pCur);
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
+ releasePageNotNull(pCur->pPage);
+ pCur->iPage--;
while( pCur->iPage>iCellDepth ){
releasePage(pCur->apPage[pCur->iPage--]);
}
+ pCur->pPage = pCur->apPage[pCur->iPage];
rc = balance(pCur);
}
if( rc==SQLITE_OK ){
if( bSkipnext ){
assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
- assert( pPage==pCur->apPage[pCur->iPage] || CORRUPT_DB );
+ assert( pPage==pCur->pPage || CORRUPT_DB );
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
pCur->eState = CURSOR_SKIPNEXT;
if( iCellIdx>=pPage->nCell ){
pCur->skipNext = -1;
- pCur->aiIdx[iCellDepth] = pPage->nCell-1;
+ pCur->ix = pPage->nCell-1;
}else{
pCur->skipNext = 1;
}
}else{
rc = moveToRoot(pCur);
if( bPreserve ){
+ btreeReleaseAllCursorPages(pCur);
pCur->eState = CURSOR_REQUIRESEEK;
}
+ if( rc==SQLITE_EMPTY ) rc = SQLITE_OK;
}
}
return rc;
@@ -66515,7 +73581,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
** BTREE_ZERODATA Used for SQL indices
*/
-static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
+static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
BtShared *pBt = p->pBt;
MemPage *pRoot;
Pgno pgnoRoot;
@@ -66548,6 +73614,9 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
** created so far, so the new root-page is (meta[3]+1).
*/
sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
+ if( pgnoRoot>btreePagecount(pBt) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
pgnoRoot++;
/* The new root-page may not be allocated on a pointer-map page, or the
@@ -66557,8 +73626,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
pgnoRoot++;
}
- assert( pgnoRoot>=3 || CORRUPT_DB );
- testcase( pgnoRoot<3 );
+ assert( pgnoRoot>=3 );
/* Allocate a page. The page that currently resides at pgnoRoot will
** be moved to the allocated page (unless the allocated page happens
@@ -66621,7 +73689,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
}
}else{
pRoot = pPageMove;
- }
+ }
/* Update the pointer-map and meta-data with the new root-page number. */
ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc);
@@ -66655,10 +73723,10 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
zeroPage(pRoot, ptfFlags);
sqlite3PagerUnref(pRoot->pDbPage);
assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
- *piTable = (int)pgnoRoot;
+ *piTable = pgnoRoot;
return SQLITE_OK;
}
-SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
+SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){
int rc;
sqlite3BtreeEnter(p);
rc = btreeCreateTable(p, piTable, flags);
@@ -66681,7 +73749,7 @@ static int clearDatabasePage(
unsigned char *pCell;
int i;
int hdr;
- u16 szCell;
+ CellInfo info;
assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno>btreePagecount(pBt) ){
@@ -66701,7 +73769,7 @@ static int clearDatabasePage(
rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
if( rc ) goto cleardatabasepage_out;
}
- rc = clearCell(pPage, pCell, &szCell);
+ rc = clearCell(pPage, pCell, &info);
if( rc ) goto cleardatabasepage_out;
}
if( !pPage->leaf ){
@@ -66749,7 +73817,7 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
** is the root of a table b-tree - if it is not, the following call is
** a no-op). */
- invalidateIncrblobCursors(p, 0, 1);
+ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
}
sqlite3BtreeLeave(p);
@@ -66774,12 +73842,12 @@ SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
** cursors on the table.
**
** If AUTOVACUUM is enabled and the page at iTable is not the last
-** root page in the database file, then the last root page
+** root page in the database file, then the last root page
** in the database file is moved into the slot formerly occupied by
** iTable and that last slot formerly occupied by the last root page
** is added to the freelist instead of iTable. In this say, all
** root pages are kept at the beginning of the database file, which
-** is necessary for AUTOVACUUM to work right. *piMoved is set to the
+** is necessary for AUTOVACUUM to work right. *piMoved is set to the
** page number that used to be the last root page in the file before
** the move. If no page gets moved, *piMoved is set to 0.
** The last root page is recorded in meta[3] and the value of
@@ -66792,25 +73860,8 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
assert( sqlite3BtreeHoldsMutex(p) );
assert( p->inTrans==TRANS_WRITE );
-
- /* It is illegal to drop a table if any cursors are open on the
- ** database. This is because in auto-vacuum mode the backend may
- ** need to move another root-page to fill a gap left by the deleted
- ** root page. If an open cursor was using this page a problem would
- ** occur.
- **
- ** This error is caught long before control reaches this point.
- */
- if( NEVER(pBt->pCursor) ){
- sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
- return SQLITE_LOCKED_SHAREDCACHE;
- }
-
- /*
- ** It is illegal to drop the sqlite_master table on page 1. But again,
- ** this error is caught long before reaching this point.
- */
- if( NEVER(iTable<2) ){
+ assert( iTable>=2 );
+ if( iTable>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -66834,7 +73885,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
if( iTable==maxRootPgno ){
/* If the table being dropped is the table with the largest root-page
- ** number in the database, put the root page on the free list.
+ ** number in the database, put the root page on the free list.
*/
freePage(pPage, &rc);
releasePage(pPage);
@@ -66843,7 +73894,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
}
}else{
/* The table being dropped does not have the largest root-page
- ** number in the database. So move the page that does into the
+ ** number in the database. So move the page that does into the
** gap left by the deleted root-page.
*/
MemPage *pMove;
@@ -66885,7 +73936,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
releasePage(pPage);
}
#endif
- return rc;
+ return rc;
}
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
int rc;
@@ -66904,7 +73955,7 @@ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
** is the number of free pages currently in the database. Meta[1]
** through meta[15] are available for use by higher layers. Meta[0]
** is read-only, the others are read/write.
-**
+**
** The schema layer numbers meta values differently. At the schema
** layer (and the SetCookie and ReadCookie opcodes) the number of
** free pages is not visible. So Cookie[0] is the same as Meta[1].
@@ -66921,7 +73972,7 @@ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE );
- assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
+ assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
assert( pBt->pPage1 );
assert( idx>=0 && idx<=15 );
@@ -66970,42 +74021,41 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
return rc;
}
-#ifndef SQLITE_OMIT_BTREECOUNT
/*
** The first argument, pCur, is a cursor opened on some b-tree. Count the
** number of entries in the b-tree and write the result to *pnEntry.
**
-** SQLITE_OK is returned if the operation is successfully executed.
+** SQLITE_OK is returned if the operation is successfully executed.
** Otherwise, if an error is encountered (i.e. an IO error or database
** corruption) an SQLite error code is returned.
*/
-SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
+SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
i64 nEntry = 0; /* Value to return in *pnEntry */
int rc; /* Return code */
- if( pCur->pgnoRoot==0 ){
+ rc = moveToRoot(pCur);
+ if( rc==SQLITE_EMPTY ){
*pnEntry = 0;
return SQLITE_OK;
}
- rc = moveToRoot(pCur);
/* Unless an error occurs, the following loop runs one iteration for each
- ** page in the B-Tree structure (not including overflow pages).
+ ** page in the B-Tree structure (not including overflow pages).
*/
- while( rc==SQLITE_OK ){
+ while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){
int iIdx; /* Index of child node in parent */
MemPage *pPage; /* Current page of the b-tree */
- /* If this is a leaf page or the tree is not an int-key tree, then
+ /* If this is a leaf page or the tree is not an int-key tree, then
** this page contains countable entries. Increment the entry counter
** accordingly.
*/
- pPage = pCur->apPage[pCur->iPage];
+ pPage = pCur->pPage;
if( pPage->leaf || !pPage->intKey ){
nEntry += pPage->nCell;
}
- /* pPage is a leaf node. This loop navigates the cursor so that it
+ /* pPage is a leaf node. This loop navigates the cursor so that it
** points to the first interior cell that it points to the parent of
** the next page in the tree that has not yet been visited. The
** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell
@@ -67023,16 +74073,16 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
return moveToRoot(pCur);
}
moveToParent(pCur);
- }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell );
+ }while ( pCur->ix>=pCur->pPage->nCell );
- pCur->aiIdx[pCur->iPage]++;
- pPage = pCur->apPage[pCur->iPage];
+ pCur->ix++;
+ pPage = pCur->pPage;
}
- /* Descend to the child node of the cell that the cursor currently
+ /* Descend to the child node of the cell that the cursor currently
** points at. This is the right-child if (iIdx==pPage->nCell).
*/
- iIdx = pCur->aiIdx[pCur->iPage];
+ iIdx = pCur->ix;
if( iIdx==pPage->nCell ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
}else{
@@ -67043,7 +74093,6 @@ SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *pCur, i64 *pnEntry){
/* An error has occurred. Return an error code. */
return rc;
}
-#endif
/*
** Return the pager associated with a BTree. This routine is used for
@@ -67068,15 +74117,15 @@ static void checkAppendMsg(
pCheck->nErr++;
va_start(ap, zFormat);
if( pCheck->errMsg.nChar ){
- sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
+ sqlite3_str_append(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- sqlite3XPrintf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
}
- sqlite3VXPrintf(&pCheck->errMsg, zFormat, ap);
+ sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
- if( pCheck->errMsg.accError==STRACCUM_NOMEM ){
- pCheck->mallocFailed = 1;
+ if( pCheck->errMsg.accError==SQLITE_NOMEM ){
+ pCheck->bOomFault = 1;
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -67110,8 +74159,7 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
- if( iPage==0 ) return 1;
- if( iPage>pCheck->nPage ){
+ if( iPage>pCheck->nPage || iPage==0 ){
checkAppendMsg(pCheck, "invalid page number %d", iPage);
return 1;
}
@@ -67119,13 +74167,14 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage){
checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
return 1;
}
+ if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1;
setPageReferenced(pCheck, iPage);
return 0;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
-** Check that the entry in the pointer-map for page iChild maps to
+** Check that the entry in the pointer-map for page iChild maps to
** page iParent, pointer type ptrType. If not, append an error message
** to pCheck.
*/
@@ -67141,14 +74190,14 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1;
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1;
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
checkAppendMsg(pCheck,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -67161,40 +74210,35 @@ static void checkPtrmap(
static void checkList(
IntegrityCk *pCheck, /* Integrity checking context */
int isFreeList, /* True for a freelist. False for overflow page list */
- int iPage, /* Page number for first page in the list */
- int N /* Expected number of pages in the list */
+ Pgno iPage, /* Page number for first page in the list */
+ u32 N /* Expected number of pages in the list */
){
int i;
- int expected = N;
- int iFirst = iPage;
- while( N-- > 0 && pCheck->mxErr ){
+ u32 expected = N;
+ int nErrAtStart = pCheck->nErr;
+ while( iPage!=0 && pCheck->mxErr ){
DbPage *pOvflPage;
unsigned char *pOvflData;
- if( iPage<1 ){
- checkAppendMsg(pCheck,
- "%d of %d pages missing from overflow list starting at %d",
- N+1, expected, iFirst);
- break;
- }
if( checkRef(pCheck, iPage) ) break;
+ N--;
if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
checkAppendMsg(pCheck, "failed to get page %d", iPage);
break;
}
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
if( isFreeList ){
- int n = get4byte(&pOvflData[4]);
+ u32 n = (u32)get4byte(&pOvflData[4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0);
}
#endif
- if( n>(int)pCheck->pBt->usableSize/4-2 ){
+ if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
"freelist leaf count too big on page %d", iPage);
N--;
}else{
- for(i=0; i<n; i++){
+ for(i=0; i<(int)n; i++){
Pgno iFreePage = get4byte(&pOvflData[8+i*4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
@@ -67220,10 +74264,12 @@ static void checkList(
#endif
iPage = get4byte(pOvflData);
sqlite3PagerUnref(pOvflPage);
-
- if( isFreeList && N<(iPage!=0) ){
- checkAppendMsg(pCheck, "free-page count in header is too small");
- }
+ }
+ if( N && nErrAtStart==pCheck->nErr ){
+ checkAppendMsg(pCheck,
+ "%s is %d but should be %d",
+ isFreeList ? "size" : "overflow list length",
+ expected-N, expected);
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -67246,7 +74292,7 @@ static void checkList(
** property.
**
** This heap is used for cell overlap and coverage testing. Each u32
-** entry represents the span of a cell or freeblock on a btree page.
+** entry represents the span of a cell or freeblock on a btree page.
** The upper 16 bits are the index of the first byte of a range and the
** lower 16 bits are the index of the last byte of that range.
*/
@@ -67276,7 +74322,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
aHeap[j] = x;
i = j;
}
- return 1;
+ return 1;
}
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
@@ -67284,7 +74330,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
** Do various sanity checks on a single page of a tree. Return
** the tree depth. Root pages return 0. Parents of root pages
** return 1, and so forth.
-**
+**
** These checks are done:
**
** 1. Make sure that cells and freeblocks do not overlap
@@ -67296,7 +74342,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
*/
static int checkTreePage(
IntegrityCk *pCheck, /* Context for the sanity check */
- int iPage, /* Page number of the page to check */
+ Pgno iPage, /* Page number of the page to check */
i64 *piMinKey, /* Write minimum integer primary key here */
i64 maxKey /* Error if integer primary key greater than this */
){
@@ -67332,9 +74378,9 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %d: ";
+ pCheck->zPfx = "Page %u: ";
pCheck->v1 = iPage;
- if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
+ if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
goto end_of_check;
@@ -67350,11 +74396,16 @@ static int checkTreePage(
"btreeInitPage() returns error code %d", rc);
goto end_of_check;
}
+ if( (rc = btreeComputeFreeSpace(pPage))!=0 ){
+ assert( rc==SQLITE_CORRUPT );
+ checkAppendMsg(pCheck, "free space corruption", rc);
+ goto end_of_check;
+ }
data = pPage->aData;
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %d cell %d: ";
+ pCheck->zPfx = "On tree page %u cell %d: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -67374,7 +74425,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %d at right child: ";
+ pCheck->zPfx = "On page %u at right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -67417,11 +74468,12 @@ static int checkTreePage(
checkAppendMsg(pCheck, "Rowid %lld out of order", info.nKey);
}
maxKey = info.nKey;
+ keyCanBeEqual = 0; /* Only the first key on the page may ==maxKey */
}
/* Check the content overflow list */
if( info.nPayload>info.nLocal ){
- int nPage; /* Number of pages on the overflow chain */
+ u32 nPage; /* Number of pages on the overflow chain */
Pgno pgnoOvfl; /* First page of the overflow chain */
assert( pc + info.nSize - 4 <= usableSize );
nPage = (info.nPayload - info.nLocal + usableSize - 5)/(usableSize - 4);
@@ -67476,14 +74528,14 @@ static int checkTreePage(
**
** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
** is the offset of the first freeblock, or zero if there are no
- ** freeblocks on the page.
+ ** freeblocks on the page.
*/
i = get2byte(&data[hdr+1]);
while( i>0 ){
int size, j;
- assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */
+ assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */
size = get2byte(&data[i+2]);
- assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */
+ assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */
btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1));
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
** big-endian integer which is the offset in the b-tree page of the next
@@ -67492,17 +74544,17 @@ static int checkTreePage(
j = get2byte(&data[i]);
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
** increasing offset. */
- assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */
- assert( (u32)j<=usableSize-4 ); /* Enforced by btreeInitPage() */
+ assert( j==0 || j>i+size ); /* Enforced by btreeComputeFreeSpace() */
+ assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */
i = j;
}
- /* Analyze the min-heap looking for overlap between cells and/or
+ /* Analyze the min-heap looking for overlap between cells and/or
** freeblocks, and counting the number of untracked bytes in nFrag.
- **
+ **
** Each min-heap entry is of the form: (start_address<<16)|end_address.
** There is an implied first entry the covers the page header, the cell
** pointer index, and the gap between the cell pointer index and the start
- ** of cell content.
+ ** of cell content.
**
** The loop below pulls entries from the min-heap in order and compares
** the start_address against the previous end_address. If there is an
@@ -67514,7 +74566,7 @@ static int checkTreePage(
while( btreeHeapPull(heap,&x) ){
if( (prev&0xffff)>=(x>>16) ){
checkAppendMsg(pCheck,
- "Multiple uses for byte %u of page %d", x>>16, iPage);
+ "Multiple uses for byte %u of page %u", x>>16, iPage);
break;
}else{
nFrag += (x>>16) - (prev&0xffff) - 1;
@@ -67529,7 +74581,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %d",
+ "Fragmentation of %d bytes reported as %d on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -67557,10 +74609,20 @@ end_of_check:
** allocation errors, an error message held in memory obtained from
** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
** returned. If a memory allocation error occurs, NULL is returned.
+**
+** If the first entry in aRoot[] is 0, that indicates that the list of
+** root pages is incomplete. This is a "partial integrity-check". This
+** happens when performing an integrity check on a single table. The
+** zero is skipped, of course. But in addition, the freelist checks
+** and the checks to make sure every page is referenced are also skipped,
+** since obviously it is not possible to know which pages are covered by
+** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
+** checks are still performed.
*/
SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
+ sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
- int *aRoot, /* An array of root pages numbers for individual trees */
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
int *pnErr /* Write number of errors seen to this variable */
@@ -67568,20 +74630,31 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
Pgno i;
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
- int savedDbFlags = pBt->db->flags;
+ u64 savedDbFlags = pBt->db->flags;
char zErr[100];
+ int bPartial = 0; /* True if not checking all btrees */
+ int bCkFreelist = 1; /* True to scan the freelist */
VVA_ONLY( int nRef );
+ assert( nRoot>0 );
+
+ /* aRoot[0]==0 means this is a partial check */
+ if( aRoot[0]==0 ){
+ assert( nRoot>1 );
+ bPartial = 1;
+ if( aRoot[1]!=1 ) bCkFreelist = 0;
+ }
sqlite3BtreeEnter(p);
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
assert( nRef>=0 );
+ sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
- sCheck.mallocFailed = 0;
+ sCheck.bOomFault = 0;
sCheck.zPfx = 0;
sCheck.v1 = 0;
sCheck.v2 = 0;
@@ -67595,12 +74668,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
- sCheck.mallocFailed = 1;
+ sCheck.bOomFault = 1;
goto integrity_ck_cleanup;
}
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
if( sCheck.heap==0 ){
- sCheck.mallocFailed = 1;
+ sCheck.bOomFault = 1;
goto integrity_ck_cleanup;
}
@@ -67609,20 +74682,42 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
/* Check the integrity of the freelist
*/
- sCheck.zPfx = "Main freelist: ";
- checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
- get4byte(&pBt->pPage1->aData[36]));
- sCheck.zPfx = 0;
+ if( bCkFreelist ){
+ sCheck.zPfx = "Main freelist: ";
+ checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
+ get4byte(&pBt->pPage1->aData[36]));
+ sCheck.zPfx = 0;
+ }
/* Check all the tables.
*/
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( !bPartial ){
+ if( pBt->autoVacuum ){
+ Pgno mx = 0;
+ Pgno mxInHdr;
+ for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
+ mxInHdr = get4byte(&pBt->pPage1->aData[52]);
+ if( mx!=mxInHdr ){
+ checkAppendMsg(&sCheck,
+ "max rootpage (%d) disagrees with header (%d)",
+ mx, mxInHdr
+ );
+ }
+ }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
+ checkAppendMsg(&sCheck,
+ "incremental_vacuum enabled with a max rootpage of zero"
+ );
+ }
+ }
+#endif
testcase( pBt->db->flags & SQLITE_CellSizeCk );
- pBt->db->flags &= ~SQLITE_CellSizeCk;
+ pBt->db->flags &= ~(u64)SQLITE_CellSizeCk;
for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
i64 notUsed;
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum && aRoot[i]>1 ){
+ if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
@@ -67632,24 +74727,26 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
/* Make sure every page in the file is referenced
*/
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
+ if( !bPartial ){
+ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
- if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
- }
+ if( getPageReferenced(&sCheck, i)==0 ){
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
+ }
#else
- /* If the database supports auto-vacuum, make sure no tables contain
- ** references to pointer-map pages.
- */
- if( getPageReferenced(&sCheck, i)==0 &&
- (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
- }
- if( getPageReferenced(&sCheck, i)!=0 &&
- (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
- }
+ /* If the database supports auto-vacuum, make sure no tables contain
+ ** references to pointer-map pages.
+ */
+ if( getPageReferenced(&sCheck, i)==0 &&
+ (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
+ }
+ if( getPageReferenced(&sCheck, i)!=0 &&
+ (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
+ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ }
#endif
+ }
}
/* Clean up and report errors.
@@ -67657,12 +74754,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
integrity_ck_cleanup:
sqlite3PageFree(sCheck.heap);
sqlite3_free(sCheck.aPgRef);
- if( sCheck.mallocFailed ){
- sqlite3StrAccumReset(&sCheck.errMsg);
+ if( sCheck.bOomFault ){
+ sqlite3_str_reset(&sCheck.errMsg);
sCheck.nErr++;
}
*pnErr = sCheck.nErr;
- if( sCheck.nErr==0 ) sqlite3StrAccumReset(&sCheck.errMsg);
+ if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg);
/* Make sure this analysis did not leave any unref() pages. */
assert( nRef==sqlite3PagerRefcount(pBt->pPager) );
sqlite3BtreeLeave(p);
@@ -67707,7 +74804,7 @@ SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){
/*
** Run a checkpoint on the Btree passed as the first argument.
**
-** Return SQLITE_LOCKED if this or any other connection has an open
+** Return SQLITE_LOCKED if this or any other connection has an open
** transaction on the shared-cache the argument Btree is connected to.
**
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
@@ -67720,7 +74817,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *
if( pBt->inTransaction!=TRANS_NONE ){
rc = SQLITE_LOCKED;
}else{
- rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
+ rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
}
sqlite3BtreeLeave(p);
}
@@ -67746,20 +74843,20 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){
/*
** This function returns a pointer to a blob of memory associated with
** a single shared-btree. The memory is used by client code for its own
-** purposes (for example, to store a high-level schema associated with
+** purposes (for example, to store a high-level schema associated with
** the shared-btree). The btree layer manages reference counting issues.
**
** The first time this is called on a shared-btree, nBytes bytes of memory
-** are allocated, zeroed, and returned to the caller. For each subsequent
+** are allocated, zeroed, and returned to the caller. For each subsequent
** call the nBytes parameter is ignored and a pointer to the same blob
-** of memory returned.
+** of memory returned.
**
** If the nBytes parameter is 0 and the blob of memory has not yet been
** allocated, a null pointer is returned. If the blob has already been
** allocated, it is returned as normal.
**
-** Just before the shared-btree is closed, the function passed as the
-** xFree argument when the memory allocation was made is invoked on the
+** Just before the shared-btree is closed, the function passed as the
+** xFree argument when the memory allocation was made is invoked on the
** blob of allocated memory. The xFree function should not call sqlite3_free()
** on the memory, the btree layer does that.
*/
@@ -67775,15 +74872,15 @@ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void
}
/*
-** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
-** btree as the argument handle holds an exclusive lock on the
-** sqlite_master table. Otherwise SQLITE_OK.
+** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
+** btree as the argument handle holds an exclusive lock on the
+** sqlite_schema table. Otherwise SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){
int rc;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE );
sqlite3BtreeLeave(p);
return rc;
@@ -67817,11 +74914,11 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
#ifndef SQLITE_OMIT_INCRBLOB
/*
-** Argument pCsr must be a cursor opened for writing on an
-** INTKEY table currently pointing at a valid table entry.
+** Argument pCsr must be a cursor opened for writing on an
+** INTKEY table currently pointing at a valid table entry.
** This function modifies the data stored as part of that entry.
**
-** Only the data content may only be modified, it is not possible to
+** Only the data content may only be modified, it is not possible to
** change the length of the data stored. If this function is called with
** parameters that attempt to write past the end of the existing data,
** no modifications are made and SQLITE_CORRUPT is returned.
@@ -67852,7 +74949,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr);
assert( rc==SQLITE_OK );
- /* Check some assumptions:
+ /* Check some assumptions:
** (a) the cursor is open for writing,
** (b) there is a read/write transaction open,
** (c) the connection holds a write-lock on the table (if required),
@@ -67866,12 +74963,12 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
&& pCsr->pBt->inTransaction==TRANS_WRITE );
assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) );
assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) );
- assert( pCsr->apPage[pCsr->iPage]->intKey );
+ assert( pCsr->pPage->intKey );
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
}
-/*
+/*
** Mark this cursor as an incremental blob cursor.
*/
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
@@ -67881,14 +74978,14 @@ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
#endif
/*
-** Set both the "read version" (single byte at byte offset 18) and
+** Set both the "read version" (single byte at byte offset 18) and
** "write version" (single byte at byte offset 19) fields in the database
** header to iVersion.
*/
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
BtShared *pBt = pBtree->pBt;
int rc; /* Return code */
-
+
assert( iVersion==1 || iVersion==2 );
/* If setting the version fields to 1, do not automatically open the
@@ -67897,11 +74994,11 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
pBt->btsFlags &= ~BTS_NO_WAL;
if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL;
- rc = sqlite3BtreeBeginTrans(pBtree, 0);
+ rc = sqlite3BtreeBeginTrans(pBtree, 0, 0);
if( rc==SQLITE_OK ){
u8 *aData = pBt->pPage1->aData;
if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
- rc = sqlite3BtreeBeginTrans(pBtree, 2);
+ rc = sqlite3BtreeBeginTrans(pBtree, 2, 0);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc==SQLITE_OK ){
@@ -67946,7 +75043,7 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
/*
** Return the number of connections to the BtShared object accessed by
-** the Btree handle passed as the only argument. For private caches
+** the Btree handle passed as the only argument. For private caches
** this is always 1. For shared caches it may be 1 or greater.
*/
SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
@@ -67968,7 +75065,7 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains the implementation of the sqlite3_backup_XXX()
+** This file contains the implementation of the sqlite3_backup_XXX()
** API functions and the related features.
*/
/* #include "sqliteInt.h" */
@@ -68005,15 +75102,15 @@ struct sqlite3_backup {
** Once it has been created using backup_init(), a single sqlite3_backup
** structure may be accessed via two groups of thread-safe entry points:
**
-** * Via the sqlite3_backup_XXX() API function backup_step() and
+** * Via the sqlite3_backup_XXX() API function backup_step() and
** backup_finish(). Both these functions obtain the source database
-** handle mutex and the mutex associated with the source BtShared
+** handle mutex and the mutex associated with the source BtShared
** structure, in that order.
**
** * Via the BackupUpdate() and BackupRestart() functions, which are
** invoked by the pager layer to report various state changes in
** the page cache associated with the source database. The mutex
-** associated with the source database BtShared structure will always
+** associated with the source database BtShared structure will always
** be held when either of these functions are invoked.
**
** The other sqlite3_backup_XXX() API functions, backup_remaining() and
@@ -68034,8 +75131,8 @@ struct sqlite3_backup {
** in connection handle pDb. If such a database cannot be found, return
** a NULL pointer and write an error message to pErrorDb.
**
-** If the "temp" database is requested, it may need to be opened by this
-** function. If an error occurs while doing so, return 0 and write an
+** If the "temp" database is requested, it may need to be opened by this
+** function. If an error occurs while doing so, return 0 and write an
** error message to pErrorDb.
*/
static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
@@ -68071,14 +75168,14 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
*/
static int setDestPgsz(sqlite3_backup *p){
int rc;
- rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
+ rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
return rc;
}
/*
** Check that there is no open read-transaction on the b-tree passed as the
** second argument. If there is not, return SQLITE_OK. Otherwise, if there
-** is an open read-transaction, return SQLITE_ERROR and leave an error
+** is an open read-transaction, return SQLITE_ERROR and leave an error
** message in database handle db.
*/
static int checkReadTransaction(sqlite3 *db, Btree *p){
@@ -68148,13 +75245,13 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
p->iNext = 1;
p->isAttached = 0;
- if( 0==p->pSrc || 0==p->pDest
- || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
+ if( 0==p->pSrc || 0==p->pDest
+ || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
){
/* One (or both) of the named databases did not exist or an OOM
** error was hit. Or there is a transaction open on the destination
- ** database. The error has already been written into the pDestDb
- ** handle. All that is left to do here is free the sqlite3_backup
+ ** database. The error has already been written into the pDestDb
+ ** handle. All that is left to do here is free the sqlite3_backup
** structure. */
sqlite3_free(p);
p = 0;
@@ -68170,7 +75267,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
}
/*
-** Argument rc is an SQLite error code. Return true if this error is
+** Argument rc is an SQLite error code. Return true if this error is
** considered fatal if encountered during a backup operation. All errors
** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED.
*/
@@ -68179,8 +75276,8 @@ static int isFatalError(int rc){
}
/*
-** Parameter zSrcData points to a buffer containing the data for
-** page iSrcPg from the source database. Copy this data into the
+** Parameter zSrcData points to a buffer containing the data for
+** page iSrcPg from the source database. Copy this data into the
** destination database.
*/
static int backupOnePage(
@@ -68194,13 +75291,6 @@ static int backupOnePage(
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
const int nCopy = MIN(nSrcPgsz, nDestPgsz);
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
-#ifdef SQLITE_HAS_CODEC
- /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
- ** guaranteed that the shared-mutex is held by this thread, handle
- ** p->pSrc may not actually be the owner. */
- int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
- int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
-#endif
int rc = SQLITE_OK;
i64 iOff;
@@ -68211,33 +75301,13 @@ static int backupOnePage(
assert( zSrcData );
/* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
+ ** page sizes of the source and destination differ.
*/
if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
rc = SQLITE_READONLY;
}
-#ifdef SQLITE_HAS_CODEC
- /* Backup is not possible if the page size of the destination is changing
- ** and a codec is in use.
- */
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
- rc = SQLITE_READONLY;
- }
-
- /* Backup is not possible if the number of bytes of reserve space differ
- ** between source and destination. If there is a difference, try to
- ** fix the destination to agree with the source. If that is not possible,
- ** then the backup cannot proceed.
- */
- if( nSrcReserve!=nDestReserve ){
- u32 newPgsz = nSrcPgsz;
- rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
- if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY;
- }
-#endif
-
- /* This loop runs once for each destination page spanned by the source
+ /* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
** of the destination page.
*/
@@ -68256,7 +75326,7 @@ static int backupOnePage(
** Then clear the Btree layer MemPage.isInit flag. Both this module
** and the pager code use this trick (clearing the first byte
** of the page 'extra' space to invalidate the Btree layers
- ** cached parse of the page). MemPage.isInit is marked
+ ** cached parse of the page). MemPage.isInit is marked
** "MUST BE FIRST" for this purpose.
*/
memcpy(zOut, zIn, nCopy);
@@ -68276,7 +75346,7 @@ static int backupOnePage(
** exactly iSize bytes. If pFile is not larger than iSize bytes, then
** this function is a no-op.
**
-** Return SQLITE_OK if everything is successful, or an SQLite error
+** Return SQLITE_OK if everything is successful, or an SQLite error
** code if an error occurs.
*/
static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
@@ -68341,7 +75411,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** before this function exits.
*/
if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){
- rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
+ rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
bCloseTrans = 1;
}
@@ -68357,10 +75427,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/* Lock the destination database, if it is not locked already. */
if( SQLITE_OK==rc && p->bDestLocked==0
- && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
+ && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2,
+ (int*)&p->iDestSchema))
){
p->bDestLocked = 1;
- sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
}
/* Do not allow backup if the destination database is in WAL mode
@@ -68371,7 +75441,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
rc = SQLITE_READONLY;
}
-
+
/* Now that there is a read-lock on the source database, query the
** source pager for the number of pages in the database.
*/
@@ -68398,7 +75468,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
attachBackupObject(p);
}
}
-
+
/* Update the schema version field in the destination database. This
** is to make sure that the schema-version really does change in
** the case where the source and destination databases have the
@@ -68424,12 +75494,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int nDestTruncate;
/* Set nDestTruncate to the final number of pages in the destination
** database. The complication here is that the destination page
- ** size may be different to the source page size.
+ ** size may be different to the source page size.
**
- ** If the source page size is smaller than the destination page size,
+ ** If the source page size is smaller than the destination page size,
** round up. In this case the call to sqlite3OsTruncate() below will
** fix the size of the file. However it is important to call
- ** sqlite3PagerTruncateImage() here so that any pages in the
+ ** sqlite3PagerTruncateImage() here so that any pages in the
** destination file that lie beyond the nDestTruncate page mark are
** journalled by PagerCommitPhaseOne() before they are destroyed
** by the file truncation.
@@ -68453,7 +75523,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
**
** * The destination may need to be truncated, and
**
- ** * Data stored on the pages immediately following the
+ ** * Data stored on the pages immediately following the
** pending-byte page in the source database may need to be
** copied into the destination database.
*/
@@ -68465,7 +75535,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
i64 iEnd;
assert( pFile );
- assert( nDestTruncate==0
+ assert( nDestTruncate==0
|| (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
@@ -68475,7 +75545,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** database has been stored in the journal for pDestPager and the
** journal synced to disk. So at this point we may safely modify
** the database file in any way, knowing that if a power failure
- ** occurs, the original database will be reconstructed from the
+ ** occurs, the original database will be reconstructed from the
** journal file. */
sqlite3PagerPagecount(pDestPager, &nDstPage);
for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
@@ -68495,8 +75565,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/* Write the extra pages and truncate the database file as required */
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
for(
- iOff=PENDING_BYTE+pgszSrc;
- rc==SQLITE_OK && iOff<iEnd;
+ iOff=PENDING_BYTE+pgszSrc;
+ rc==SQLITE_OK && iOff<iEnd;
iOff+=pgszSrc
){
PgHdr *pSrcPg = 0;
@@ -68520,7 +75590,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
}
-
+
/* Finish committing the transaction to the destination database. */
if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
@@ -68529,7 +75599,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
}
}
}
-
+
/* If bCloseTrans is true, then this function opened a read transaction
** on the source database. Close the read transaction here. There is
** no need to check the return values of the btree methods here, as
@@ -68541,7 +75611,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
assert( rc2==SQLITE_OK );
}
-
+
if( rc==SQLITE_IOERR_NOMEM ){
rc = SQLITE_NOMEM_BKPT;
}
@@ -68578,8 +75648,10 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
}
if( p->isAttached ){
pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
+ assert( pp!=0 );
while( *pp!=p ){
pp = &(*pp)->pNext;
+ assert( pp!=0 );
}
*pp = p->pNext;
}
@@ -68621,7 +75693,7 @@ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
}
/*
-** Return the total number of pages in the source database as of the most
+** Return the total number of pages in the source database as of the most
** recent call to sqlite3_backup_step().
*/
SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
@@ -68636,7 +75708,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
/*
** This function is called after the contents of page iPage of the
-** source database have been modified. If page iPage has already been
+** source database have been modified. If page iPage has already been
** copied into the destination database, then the data written to the
** destination is now invalidated. The destination copy of iPage needs
** to be updated with the new data before the backup operation is
@@ -68679,7 +75751,7 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, con
** Restart the backup process. This is called when the pager layer
** detects that the database has been modified by an external database
** connection. In this case there is no way of knowing which of the
-** pages that have been copied into the destination database are still
+** pages that have been copied into the destination database are still
** valid and which are not, so the entire process needs to be restarted.
**
** It is assumed that the mutex associated with the BtShared object
@@ -68699,8 +75771,8 @@ SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){
** Copy the complete content of pBtFrom into pBtTo. A transaction
** must be active for both files.
**
-** The size of file pTo may be reduced by this operation. If anything
-** goes wrong, the transaction on pTo is rolled back. If successful, the
+** The size of file pTo may be reduced by this operation. If anything
+** goes wrong, the transaction on pTo is rolled back. If successful, the
** transaction is committed before returning.
*/
SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
@@ -68730,15 +75802,11 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
b.pDest = pTo;
b.iNext = 1;
-#ifdef SQLITE_HAS_CODEC
- sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
-#endif
-
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
** file. By passing this as the number of pages to copy to
- ** sqlite3_backup_step(), we can guarantee that the copy finishes
+ ** sqlite3_backup_step(), we can guarantee that the copy finishes
** within a single call (unless an error occurs). The assert() statement
- ** checks this assumption - (p->rc) should be set to either SQLITE_DONE
+ ** checks this assumption - (p->rc) should be set to either SQLITE_DONE
** or an error code. */
sqlite3_backup_step(&b, 0x7FFFFFFF);
assert( b.rc!=SQLITE_OK );
@@ -68780,6 +75848,11 @@ copy_finished:
/* #include "sqliteInt.h" */
/* #include "vdbeInt.h" */
+/* True if X is a power of two. 0 is considered a power of two here.
+** In other words, return true if X has at most one bit set.
+*/
+#define ISPOWEROF2(X) (((X)&((X)-1))==0)
+
#ifdef SQLITE_DEBUG
/*
** Check invariants on a Mem object.
@@ -68788,8 +75861,8 @@ copy_finished:
** this: assert( sqlite3VdbeCheckMemInvariants(pMem) );
*/
SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
- /* If MEM_Dyn is set then Mem.xDel!=0.
- ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
+ /* If MEM_Dyn is set then Mem.xDel!=0.
+ ** Mem.xDel might not be initialized if MEM_Dyn is clear.
*/
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
@@ -68799,8 +75872,36 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
** That saves a few cycles in inner loops. */
assert( (p->flags & MEM_Dyn)==0 || p->szMalloc==0 );
- /* Cannot be both MEM_Int and MEM_Real at the same time */
- assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
+ /* Cannot have more than one of MEM_Int, MEM_Real, or MEM_IntReal */
+ assert( ISPOWEROF2(p->flags & (MEM_Int|MEM_Real|MEM_IntReal)) );
+
+ if( p->flags & MEM_Null ){
+ /* Cannot be both MEM_Null and some other type */
+ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 );
+
+ /* If MEM_Null is set, then either the value is a pure NULL (the usual
+ ** case) or it is a pointer set using sqlite3_bind_pointer() or
+ ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be
+ ** set.
+ */
+ if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){
+ /* This is a pointer type. There may be a flag to indicate what to
+ ** do with the pointer. */
+ assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
+ ((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
+ ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 );
+
+ /* No other bits set */
+ assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype|MEM_FromBind
+ |MEM_Dyn|MEM_Ephem|MEM_Static))==0 );
+ }else{
+ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn,
+ ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */
+ }
+ }else{
+ /* The MEM_Cleared bit is only allowed on NULLs */
+ assert( (p->flags & MEM_Cleared)==0 );
+ }
/* The szMalloc field holds the correct memory allocation size */
assert( p->szMalloc==0
@@ -68815,7 +75916,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
** (4) A static string or blob
*/
if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){
- assert(
+ assert(
((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) +
((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
@@ -68826,6 +75927,89 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
}
#endif
+/*
+** Render a Mem object which is one of MEM_Int, MEM_Real, or MEM_IntReal
+** into a buffer.
+*/
+static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
+ StrAccum acc;
+ assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
+ assert( sz>22 );
+ if( p->flags & MEM_Int ){
+#if GCC_VERSION>=7000000
+ /* Work-around for GCC bug
+ ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
+ i64 x;
+ assert( (p->flags&MEM_Int)*2==sizeof(x) );
+ memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
+ sqlite3Int64ToText(x, zBuf);
+#else
+ sqlite3Int64ToText(p->u.i, zBuf);
+#endif
+ }else{
+ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
+ sqlite3_str_appendf(&acc, "%!.15g",
+ (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
+ assert( acc.zText==zBuf && acc.mxAlloc<=0 );
+ zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
+ }
+}
+
+#ifdef SQLITE_DEBUG
+/*
+** Validity checks on pMem. pMem holds a string.
+**
+** (1) Check that string value of pMem agrees with its integer or real value.
+** (2) Check that the string is correctly zero terminated
+**
+** A single int or real value always converts to the same strings. But
+** many different strings can be converted into the same int or real.
+** If a table contains a numeric value and an index is based on the
+** corresponding string value, then it is important that the string be
+** derived from the numeric value, not the other way around, to ensure
+** that the index and table are consistent. See ticket
+** https://www.sqlite.org/src/info/343634942dd54ab (2018-01-31) for
+** an example.
+**
+** This routine looks at pMem to verify that if it has both a numeric
+** representation and a string representation then the string rep has
+** been derived from the numeric and not the other way around. It returns
+** true if everything is ok and false if there is a problem.
+**
+** This routine is for use inside of assert() statements only.
+*/
+SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
+ char zBuf[100];
+ char *z;
+ int i, j, incr;
+ if( (p->flags & MEM_Str)==0 ) return 1;
+ if( p->flags & MEM_Term ){
+ /* Insure that the string is properly zero-terminated. Pay particular
+ ** attention to the case where p->n is odd */
+ if( p->szMalloc>0 && p->z==p->zMalloc ){
+ assert( p->enc==SQLITE_UTF8 || p->szMalloc >= ((p->n+1)&~1)+2 );
+ assert( p->enc!=SQLITE_UTF8 || p->szMalloc >= p->n+1 );
+ }
+ assert( p->z[p->n]==0 );
+ assert( p->enc==SQLITE_UTF8 || p->z[(p->n+1)&~1]==0 );
+ assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 );
+ }
+ if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1;
+ vdbeMemRenderNum(sizeof(zBuf), zBuf, p);
+ z = p->z;
+ i = j = 0;
+ incr = 1;
+ if( p->enc!=SQLITE_UTF8 ){
+ incr = 2;
+ if( p->enc==SQLITE_UTF16BE ) z++;
+ }
+ while( zBuf[j] ){
+ if( zBuf[j++]!=z[i] ) return 0;
+ i += incr;
+ }
+ return 1;
+}
+#endif /* SQLITE_DEBUG */
/*
** If pMem is an object with a valid string representation, this routine
@@ -68844,7 +76028,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifndef SQLITE_OMIT_UTF16
int rc;
#endif
- assert( (pMem->flags&MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|| desiredEnc==SQLITE_UTF16BE );
if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
@@ -68867,8 +76051,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
}
/*
-** Make sure pMem->z points to a writable allocation of at least
-** min(n,32) bytes.
+** Make sure pMem->z points to a writable allocation of at least n bytes.
**
** If the bPreserve argument is true, then copy of the content of
** pMem->z into the new allocation. pMem must be either a string or
@@ -68877,7 +76060,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
*/
SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( sqlite3VdbeCheckMemInvariants(pMem) );
- assert( (pMem->flags&MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
testcase( pMem->db==0 );
/* If the bPreserve flag is set to true, then the memory cell must already
@@ -68887,26 +76070,30 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
assert( pMem->szMalloc==0
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
- if( pMem->szMalloc<n ){
- if( n<32 ) n = 32;
- if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
+ if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
+ if( pMem->db ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
- bPreserve = 0;
}else{
- if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
- pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
- }
- if( pMem->zMalloc==0 ){
- sqlite3VdbeMemSetNull(pMem);
- pMem->z = 0;
- pMem->szMalloc = 0;
- return SQLITE_NOMEM_BKPT;
- }else{
- pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
+ pMem->zMalloc = sqlite3Realloc(pMem->z, n);
+ if( pMem->zMalloc==0 ) sqlite3_free(pMem->z);
+ pMem->z = pMem->zMalloc;
}
+ bPreserve = 0;
+ }else{
+ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
+ pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
+ }
+ if( pMem->zMalloc==0 ){
+ sqlite3VdbeMemSetNull(pMem);
+ pMem->z = 0;
+ pMem->szMalloc = 0;
+ return SQLITE_NOMEM_BKPT;
+ }else{
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
- if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
+ if( bPreserve && pMem->z ){
+ assert( pMem->z!=pMem->zMalloc );
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){
@@ -68926,21 +76113,41 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
**
** Any prior string or blob content in the pMem object may be discarded.
** The pMem->xDel destructor is called, if it exists. Though MEM_Str
-** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, and MEM_Null
-** values are preserved.
+** and MEM_Blob values may be discarded, MEM_Int, MEM_Real, MEM_IntReal,
+** and MEM_Null values are preserved.
**
** Return SQLITE_OK on success or an error code (probably SQLITE_NOMEM)
** if unable to complete the resizing.
*/
SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
- assert( szNew>0 );
+ assert( CORRUPT_DB || szNew>0 );
assert( (pMem->flags & MEM_Dyn)==0 || pMem->szMalloc==0 );
if( pMem->szMalloc<szNew ){
return sqlite3VdbeMemGrow(pMem, szNew, 0);
}
assert( (pMem->flags & MEM_Dyn)==0 );
pMem->z = pMem->zMalloc;
- pMem->flags &= (MEM_Null|MEM_Int|MEM_Real);
+ pMem->flags &= (MEM_Null|MEM_Int|MEM_Real|MEM_IntReal);
+ return SQLITE_OK;
+}
+
+/*
+** It is already known that pMem contains an unterminated string.
+** Add the zero terminator.
+**
+** Three bytes of zero are added. In this way, there is guaranteed
+** to be a double-zero byte at an even byte boundary in order to
+** terminate a UTF16 string, even if the initial size of the buffer
+** is an odd number of bytes.
+*/
+static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
+ if( sqlite3VdbeMemGrow(pMem, pMem->n+3, 1) ){
+ return SQLITE_NOMEM_BKPT;
+ }
+ pMem->z[pMem->n] = 0;
+ pMem->z[pMem->n+1] = 0;
+ pMem->z[pMem->n+2] = 0;
+ pMem->flags |= MEM_Term;
return SQLITE_OK;
}
@@ -68952,16 +76159,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
*/
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- assert( (pMem->flags&MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
- if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
- return SQLITE_NOMEM_BKPT;
- }
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
+ int rc = vdbeMemAddTerminator(pMem);
+ if( rc ) return rc;
}
}
pMem->flags &= ~MEM_Ephem;
@@ -68980,13 +76183,15 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
int nByte;
assert( pMem->flags & MEM_Zero );
- assert( pMem->flags&MEM_Blob );
- assert( (pMem->flags&MEM_RowSet)==0 );
+ assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) );
+ testcase( sqlite3_value_nochange(pMem) );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
/* Set nByte to the number of bytes required to store the expanded blob. */
nByte = pMem->n + pMem->u.nZero;
if( nByte<=0 ){
+ if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK;
nByte = 1;
}
if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
@@ -69001,20 +76206,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
#endif
/*
-** It is already known that pMem contains an unterminated string.
-** Add the zero terminator.
-*/
-static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
- if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
- return SQLITE_NOMEM_BKPT;
- }
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
- return SQLITE_OK;
-}
-
-/*
** Make sure the given Mem is \u0000 terminated.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
@@ -69029,12 +76220,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
}
/*
-** Add MEM_Str to the set of representations for the given Mem. Numbers
-** are converted using sqlite3_snprintf(). Converting a BLOB to a string
-** is a no-op.
+** Add MEM_Str to the set of representations for the given Mem. This
+** routine is only called if pMem is a number of some kind, not a NULL
+** or a BLOB.
**
-** Existing representations MEM_Int and MEM_Real are invalidated if
-** bForce is true but are retained if bForce is false.
+** Existing representations MEM_Int, MEM_Real, or MEM_IntReal are invalidated
+** if bForce is true but are retained if bForce is false.
**
** A MEM_Null value will never be passed to this function. This function is
** used for converting values to text for returning to the user (i.e. via
@@ -69043,14 +76234,13 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
** user and the latter is an internal programming error.
*/
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
- int fg = pMem->flags;
const int nByte = 32;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- assert( !(fg&MEM_Zero) );
- assert( !(fg&(MEM_Str|MEM_Blob)) );
- assert( fg&(MEM_Int|MEM_Real) );
- assert( (pMem->flags&MEM_RowSet)==0 );
+ assert( !(pMem->flags&MEM_Zero) );
+ assert( !(pMem->flags&(MEM_Str|MEM_Blob)) );
+ assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@@ -69059,22 +76249,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
return SQLITE_NOMEM_BKPT;
}
- /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
- ** string representation of the value. Then, if the required encoding
- ** is UTF-16le or UTF-16be do a translation.
- **
- ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
- */
- if( fg & MEM_Int ){
- sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
- }else{
- assert( fg & MEM_Real );
- sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
- }
- pMem->n = sqlite3Strlen30(pMem->z);
+ vdbeMemRenderNum(nByte, pMem->z, pMem);
+ assert( pMem->z!=0 );
+ pMem->n = sqlite3Strlen30NN(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
- if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real);
+ if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
sqlite3VdbeChangeEncoding(pMem, enc);
return SQLITE_OK;
}
@@ -69088,27 +76268,50 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
** otherwise.
*/
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
- int rc = SQLITE_OK;
- if( ALWAYS(pFunc && pFunc->xFinalize) ){
- sqlite3_context ctx;
- Mem t;
- assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
- assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- memset(&ctx, 0, sizeof(ctx));
- memset(&t, 0, sizeof(t));
- t.flags = MEM_Null;
- t.db = pMem->db;
- ctx.pOut = &t;
- ctx.pMem = pMem;
- ctx.pFunc = pFunc;
- pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
- assert( (pMem->flags & MEM_Dyn)==0 );
- if( pMem->szMalloc>0 ) sqlite3DbFree(pMem->db, pMem->zMalloc);
- memcpy(pMem, &t, sizeof(t));
- rc = ctx.isError;
- }
- return rc;
+ sqlite3_context ctx;
+ Mem t;
+ assert( pFunc!=0 );
+ assert( pFunc->xFinalize!=0 );
+ assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
+ memset(&ctx, 0, sizeof(ctx));
+ memset(&t, 0, sizeof(t));
+ t.flags = MEM_Null;
+ t.db = pMem->db;
+ ctx.pOut = &t;
+ ctx.pMem = pMem;
+ ctx.pFunc = pFunc;
+ pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
+ assert( (pMem->flags & MEM_Dyn)==0 );
+ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
+ memcpy(pMem, &t, sizeof(t));
+ return ctx.isError;
+}
+
+/*
+** Memory cell pAccum contains the context of an aggregate function.
+** This routine calls the xValue method for that function and stores
+** the results in memory cell pMem.
+**
+** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK
+** otherwise.
+*/
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
+ sqlite3_context ctx;
+ assert( pFunc!=0 );
+ assert( pFunc->xValue!=0 );
+ assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
+ assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
+ memset(&ctx, 0, sizeof(ctx));
+ sqlite3VdbeMemSetNull(pOut);
+ ctx.pOut = pOut;
+ ctx.pMem = pAccum;
+ ctx.pFunc = pFunc;
+ pFunc->xValue(&ctx);
+ return ctx.isError;
}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** If the memory cell contains a value that must be freed by
@@ -69128,15 +76331,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
testcase( p->flags & MEM_Dyn );
}
if( p->flags&MEM_Dyn ){
- assert( (p->flags&MEM_RowSet)==0 );
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
p->xDel((void *)p->z);
- }else if( p->flags&MEM_RowSet ){
- sqlite3RowSetClear(p->u.pRowSet);
- }else if( p->flags&MEM_Frame ){
- VdbeFrame *pFrame = p->u.pFrame;
- pFrame->pParent = pFrame->v->pDelFrame;
- pFrame->v->pDelFrame = pFrame;
}
p->flags = MEM_Null;
}
@@ -69154,7 +76350,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){
vdbeMemClearExternAndSetNull(p);
}
if( p->szMalloc ){
- sqlite3DbFree(p->db, p->zMalloc);
+ sqlite3DbFreeNN(p->db, p->zMalloc);
p->szMalloc = 0;
}
p->z = 0;
@@ -69182,7 +76378,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
** If the double is out of range of a 64-bit signed integer then
** return the closest available 64-bit signed integer.
*/
-static i64 doubleToInt64(double r){
+static SQLITE_NOINLINE i64 doubleToInt64(double r){
#ifdef SQLITE_OMIT_FLOATING_POINT
/* When floating-point is omitted, double and int64 are the same thing */
return r;
@@ -69218,20 +76414,23 @@ static i64 doubleToInt64(double r){
**
** If pMem represents a string value, its encoding might be changed.
*/
+static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
+ i64 value = 0;
+ sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
+ return value;
+}
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
int flags;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
flags = pMem->flags;
- if( flags & MEM_Int ){
+ if( flags & (MEM_Int|MEM_IntReal) ){
+ testcase( flags & MEM_IntReal );
return pMem->u.i;
}else if( flags & MEM_Real ){
return doubleToInt64(pMem->u.r);
- }else if( flags & (MEM_Str|MEM_Blob) ){
- i64 value = 0;
- assert( pMem->z || pMem->n==0 );
- sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
- return value;
+ }else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
+ return memIntValue(pMem);
}else{
return 0;
}
@@ -69243,18 +76442,22 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
** value. If it is a string or blob, try to convert it to a double.
** If it is a NULL, return 0.0.
*/
+static SQLITE_NOINLINE double memRealValue(Mem *pMem){
+ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
+ double val = (double)0;
+ sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
+ return val;
+}
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
if( pMem->flags & MEM_Real ){
return pMem->u.r;
- }else if( pMem->flags & MEM_Int ){
+ }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){
+ testcase( pMem->flags & MEM_IntReal );
return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- double val = (double)0;
- sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
- return val;
+ return memRealValue(pMem);
}else{
/* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
return (double)0;
@@ -69262,13 +76465,24 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
}
/*
+** Return 1 if pMem represents true, and return 0 if pMem represents false.
+** Return the value ifNull if pMem is NULL.
+*/
+SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
+ testcase( pMem->flags & MEM_IntReal );
+ if( pMem->flags & (MEM_Int|MEM_IntReal) ) return pMem->u.i!=0;
+ if( pMem->flags & MEM_Null ) return ifNull;
+ return sqlite3VdbeRealValue(pMem)!=0.0;
+}
+
+/*
** The MEM structure is already a MEM_Real. Try to also make it a
** MEM_Int if we can.
*/
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
i64 ix;
assert( pMem->flags & MEM_Real );
- assert( (pMem->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
@@ -69295,7 +76509,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
*/
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- assert( (pMem->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
pMem->u.i = sqlite3VdbeIntValue(pMem);
@@ -69316,8 +76530,24 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
return SQLITE_OK;
}
+/* Compare a floating point value to an integer. Return true if the two
+** values are the same within the precision of the floating point value.
+**
+** This function assumes that i was obtained by assignment from r1.
+**
+** For some versions of GCC on 32-bit machines, if you do the more obvious
+** comparison of "r1==(double)i" you sometimes get an answer of false even
+** though the r1 and (double)i values are bit-for-bit the same.
+*/
+SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
+ double r2 = (double)i;
+ return r1==0.0
+ || (memcmp(&r1, &r2, sizeof(r1))==0
+ && i >= -2251799813685248LL && i < 2251799813685248LL);
+}
+
/*
-** Convert pMem so that it has types MEM_Real or MEM_Int or both.
+** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
@@ -69325,18 +76555,26 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
- if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
+ testcase( pMem->flags & MEM_Int );
+ testcase( pMem->flags & MEM_Real );
+ testcase( pMem->flags & MEM_IntReal );
+ testcase( pMem->flags & MEM_Null );
+ if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){
+ int rc;
+ sqlite3_int64 ix;
assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
+ rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
+ if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
+ || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r))
+ ){
+ pMem->u.i = ix;
MemSetTypeFlag(pMem, MEM_Int);
}else{
- pMem->u.r = sqlite3VdbeRealValue(pMem);
MemSetTypeFlag(pMem, MEM_Real);
- sqlite3VdbeIntegerAffinity(pMem);
}
}
- assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
+ assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))!=0 );
pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero);
return SQLITE_OK;
}
@@ -69348,8 +76586,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
** affinity even if that results in loss of data. This routine is
** used (for example) to implement the SQL "cast()" operator.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
- if( pMem->flags & MEM_Null ) return;
+SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
+ if( pMem->flags & MEM_Null ) return SQLITE_OK;
switch( aff ){
case SQLITE_AFF_BLOB: { /* Really a cast to BLOB */
if( (pMem->flags & MEM_Blob)==0 ){
@@ -69379,10 +76617,11 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
- pMem->flags &= ~(MEM_Int|MEM_Real|MEM_Blob|MEM_Zero);
- break;
+ pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
+ return sqlite3VdbeChangeEncoding(pMem, encoding);
}
}
+ return SQLITE_OK;
}
/*
@@ -69418,7 +76657,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
}
}
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){
- sqlite3VdbeMemSetNull((Mem*)p);
+ sqlite3VdbeMemSetNull((Mem*)p);
}
/*
@@ -69459,6 +76698,27 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
}
+/* A no-op destructor */
+SQLITE_PRIVATE void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
+
+/*
+** Set the value stored in *pMem should already be a NULL.
+** Also store a pointer to go with it.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(
+ Mem *pMem,
+ void *pPtr,
+ const char *zPType,
+ void (*xDestructor)(void*)
+){
+ assert( pMem->flags==MEM_Null );
+ pMem->u.zPType = zPType ? zPType : "";
+ pMem->z = pPtr;
+ pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term;
+ pMem->eSubtype = 'p';
+ pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor;
+}
+
#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Delete any previous value and set the value stored in *pMem to val,
@@ -69473,26 +76733,36 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
}
#endif
+#ifdef SQLITE_DEBUG
+/*
+** Return true if the Mem holds a RowSet object. This routine is intended
+** for use inside of assert() statements.
+*/
+SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem *pMem){
+ return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn)
+ && pMem->xDel==sqlite3RowSetDelete;
+}
+#endif
+
/*
** Delete any previous value and set the value of pMem to be an
** empty boolean index.
+**
+** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation
+** error occurs.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
+SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem *pMem){
sqlite3 *db = pMem->db;
+ RowSet *p;
assert( db!=0 );
- assert( (pMem->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
sqlite3VdbeMemRelease(pMem);
- pMem->zMalloc = sqlite3DbMallocRawNN(db, 64);
- if( db->mallocFailed ){
- pMem->flags = MEM_Null;
- pMem->szMalloc = 0;
- }else{
- assert( pMem->zMalloc );
- pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc);
- pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc);
- assert( pMem->u.pRowSet!=0 );
- pMem->flags = MEM_RowSet;
- }
+ p = sqlite3RowSetInit(db);
+ if( p==0 ) return SQLITE_NOMEM;
+ pMem->z = (char*)p;
+ pMem->flags = MEM_Blob|MEM_Dyn;
+ pMem->xDel = sqlite3RowSetDelete;
+ return SQLITE_OK;
}
/*
@@ -69508,7 +76778,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
}
return n>p->db->aLimit[SQLITE_LIMIT_LENGTH];
}
- return 0;
+ return 0;
}
#ifdef SQLITE_DEBUG
@@ -69517,15 +76787,31 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
** its link to a shallow copy and by marking any current shallow
** copies of this cell as invalid.
**
-** This is used for testing and debugging only - to make sure shallow
-** copies are not misused.
+** This is used for testing and debugging only - to help ensure that shallow
+** copies (created by OP_SCopy) are not misused.
*/
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
- for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
+ for(i=1, pX=pVdbe->aMem+1; i<pVdbe->nMem; i++, pX++){
if( pX->pScopyFrom==pMem ){
- pX->flags |= MEM_Undefined;
+ u16 mFlags;
+ if( pVdbe->db->flags & SQLITE_VdbeTrace ){
+ sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n",
+ (int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem));
+ }
+ /* If pX is marked as a shallow copy of pMem, then try to verify that
+ ** no significant changes have been made to pX since the OP_SCopy.
+ ** A significant change would indicated a missed call to this
+ ** function for pX. Minor changes, such as adding or removing a
+ ** dual type, are allowed, as long as the underlying value is the
+ ** same. */
+ mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
+ assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
+
+ /* pMem is the register that is changing. But also mark pX as
+ ** undefined so that we can quickly detect the shallow-copy error */
+ pX->flags = MEM_Undefined;
pX->pScopyFrom = 0;
}
}
@@ -69533,7 +76819,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
}
#endif /* SQLITE_DEBUG */
-
/*
** Make an shallow copy of pFrom into pTo. Prior contents of
** pTo are freed. The pFrom->z field is not duplicated. If
@@ -69546,7 +76831,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){
sqlite3VdbeMemShallowCopy(pTo, pFrom, eType);
}
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
- assert( (pFrom->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pFrom) );
assert( pTo->db==pFrom->db );
if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
memcpy(pTo, pFrom, MEMCELLSIZE);
@@ -69564,7 +76849,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
- assert( (pFrom->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pFrom) );
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
@@ -69599,8 +76884,8 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
** Change the value of a Mem to be a string or a BLOB.
**
** The memory management strategy depends on the value of the xDel
-** parameter. If the value passed is SQLITE_TRANSIENT, then the
-** string is copied into a (possibly existing) buffer managed by the
+** parameter. If the value passed is SQLITE_TRANSIENT, then the
+** string is copied into a (possibly existing) buffer managed by the
** Mem structure. Otherwise, any existing buffer is freed and the
** pointer copied.
**
@@ -69622,7 +76907,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
u16 flags = 0; /* New value for pMem->flags */
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- assert( (pMem->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
if( !z ){
@@ -69639,8 +76924,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
if( nByte<0 ){
assert( enc!=0 );
if( enc==SQLITE_UTF8 ){
- nByte = sqlite3Strlen30(z);
- if( nByte>iLimit ) nByte = iLimit+1;
+ nByte = 0x7fffffff & (int)strlen(z);
}else{
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
}
@@ -69652,37 +76936,47 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
** management (one of MEM_Dyn or MEM_Static).
*/
if( xDel==SQLITE_TRANSIENT ){
- int nAlloc = nByte;
+ u32 nAlloc = nByte;
if( flags&MEM_Term ){
nAlloc += (enc==SQLITE_UTF8?1:2);
}
if( nByte>iLimit ){
- return SQLITE_TOOBIG;
+ return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
}
testcase( nAlloc==0 );
testcase( nAlloc==31 );
testcase( nAlloc==32 );
- if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
+ if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){
return SQLITE_NOMEM_BKPT;
}
memcpy(pMem->z, z, nAlloc);
- }else if( xDel==SQLITE_DYNAMIC ){
- sqlite3VdbeMemRelease(pMem);
- pMem->zMalloc = pMem->z = (char *)z;
- pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}else{
sqlite3VdbeMemRelease(pMem);
pMem->z = (char *)z;
- pMem->xDel = xDel;
- flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
+ if( xDel==SQLITE_DYNAMIC ){
+ pMem->zMalloc = pMem->z;
+ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
+ }else{
+ pMem->xDel = xDel;
+ flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn);
+ }
}
pMem->n = nByte;
pMem->flags = flags;
- pMem->enc = (enc==0 ? SQLITE_UTF8 : enc);
+ if( enc ){
+ pMem->enc = enc;
+#ifdef SQLITE_ENABLE_SESSION
+ }else if( pMem->db==0 ){
+ pMem->enc = SQLITE_UTF8;
+#endif
+ }else{
+ assert( pMem->db!=0 );
+ pMem->enc = ENC(pMem->db);
+ }
#ifndef SQLITE_OMIT_UTF16
- if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
+ if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
return SQLITE_NOMEM_BKPT;
}
#endif
@@ -69696,10 +76990,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
/*
** Move data out of a btree key or data field and into a Mem structure.
-** The data or key is taken from the entry that pCur is currently pointing
+** The data is payload from the entry that pCur is currently pointing
** to. offset and amt determine what portion of the data or key to retrieve.
-** key is true to get the key or false to get data. The result is written
-** into the pMem element.
+** The result is written into the pMem element.
**
** The pMem object must have been initialized. This routine will use
** pMem->zMalloc to hold the content from the btree, if possible. New
@@ -69710,25 +77003,22 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
-static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
u32 offset, /* Offset from the start of data to return bytes from. */
u32 amt, /* Number of bytes to return. */
- int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
int rc;
pMem->flags = MEM_Null;
- if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
- if( key ){
- rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
- }else{
- rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
- }
+ if( sqlite3BtreeMaxRecordSize(pCur)<offset+amt ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){
+ rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
if( rc==SQLITE_OK ){
- pMem->z[amt] = 0;
- pMem->z[amt+1] = 0;
- pMem->flags = MEM_Blob|MEM_Term;
+ pMem->z[amt] = 0; /* Overrun area used when reading malformed records */
+ pMem->flags = MEM_Blob;
pMem->n = (int)amt;
}else{
sqlite3VdbeMemRelease(pMem);
@@ -69736,32 +77026,28 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
}
return rc;
}
-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
- u32 offset, /* Offset from the start of data to return bytes from. */
u32 amt, /* Number of bytes to return. */
- int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
- char *zData; /* Data from the btree layer */
u32 available = 0; /* Number of bytes available on the local btree page */
int rc = SQLITE_OK; /* Return code */
assert( sqlite3BtreeCursorIsValid(pCur) );
assert( !VdbeMemDynamic(pMem) );
- /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
+ /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
- assert( (pMem->flags & MEM_RowSet)==0 );
- zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
- assert( zData!=0 );
+ assert( !sqlite3VdbeMemIsRowSet(pMem) );
+ pMem->z = (char *)sqlite3BtreePayloadFetch(pCur, &available);
+ assert( pMem->z!=0 );
- if( offset+amt<=available ){
- pMem->z = &zData[offset];
+ if( amt<=available ){
pMem->flags = MEM_Blob|MEM_Ephem;
pMem->n = (int)amt;
}else{
- rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, amt, pMem);
}
return rc;
@@ -69776,9 +77062,10 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
assert( pVal!=0 );
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
- assert( (pVal->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pVal) );
assert( (pVal->flags & (MEM_Null))==0 );
if( pVal->flags & (MEM_Blob|MEM_Str) ){
+ if( ExpandBlob(pVal) ) return 0;
pVal->flags |= MEM_Str;
if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
@@ -69797,6 +77084,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0
|| pVal->db->mallocFailed );
if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
+ assert( sqlite3VdbeMemValidStrRep(pVal) );
return pVal->z;
}else{
return 0;
@@ -69817,8 +77105,9 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
if( !pVal ) return 0;
assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) );
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
- assert( (pVal->flags & MEM_RowSet)==0 );
+ assert( !sqlite3VdbeMemIsRowSet(pVal) );
if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){
+ assert( sqlite3VdbeMemValidStrRep(pVal) );
return pVal->z;
}
if( pVal->flags&MEM_Null ){
@@ -69840,7 +77129,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){
}
/*
-** Context object passed by sqlite3Stat4ProbeSetValue() through to
+** Context object passed by sqlite3Stat4ProbeSetValue() through to
** valueNew(). See comments above valueNew() for details.
*/
struct ValueNewStat4Ctx {
@@ -69855,14 +77144,14 @@ struct ValueNewStat4Ctx {
** the second argument to this function is NULL, the object is allocated
** by calling sqlite3ValueNew().
**
-** Otherwise, if the second argument is non-zero, then this function is
+** Otherwise, if the second argument is non-zero, then this function is
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
-** already been allocated, allocate the UnpackedRecord structure that
+** already been allocated, allocate the UnpackedRecord structure that
** that function will return to its caller here. Then return a pointer to
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
if( p ){
UnpackedRecord *pRec = p->ppRec[0];
@@ -69871,13 +77160,13 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
int nByte; /* Bytes of space to allocate */
int i; /* Counter variable */
int nCol = pIdx->nColumn; /* Number of index columns including rowid */
-
+
nByte = sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord));
pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
if( pRec ){
pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
if( pRec->pKeyInfo ){
- assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
+ assert( pRec->pKeyInfo->nAllField==nCol );
assert( pRec->pKeyInfo->enc==ENC(db) );
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
for(i=0; i<nCol; i++){
@@ -69885,20 +77174,20 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
pRec->aMem[i].db = db;
}
}else{
- sqlite3DbFree(db, pRec);
+ sqlite3DbFreeNN(db, pRec);
pRec = 0;
}
}
if( pRec==0 ) return 0;
p->ppRec[0] = pRec;
}
-
+
pRec->nField = p->iVal+1;
return &pRec->aMem[p->iVal];
}
#else
UNUSED_PARAMETER(p);
-#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
+#endif /* defined(SQLITE_ENABLE_STAT4) */
return sqlite3ValueNew(db);
}
@@ -69911,18 +77200,18 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
**
** then this routine attempts to invoke the SQL function. Assuming no
-** error occurs, output parameter (*ppVal) is set to point to a value
+** error occurs, output parameter (*ppVal) is set to point to a value
** object containing the result before returning SQLITE_OK.
**
** Affinity aff is applied to the result of the function before returning.
-** If the result is a text value, the sqlite3_value object uses encoding
+** If the result is a text value, the sqlite3_value object uses encoding
** enc.
**
** If the conditions above are not met, this function returns SQLITE_OK
** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
** NULL and an SQLite error code returned.
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
static int valueFromFunction(
sqlite3 *db, /* The database connection */
Expr *p, /* The expression to evaluate */
@@ -69946,7 +77235,7 @@ static int valueFromFunction(
if( pList ) nVal = pList->nExpr;
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
assert( pFunc );
- if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
+ if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
){
return SQLITE_OK;
@@ -69997,7 +77286,7 @@ static int valueFromFunction(
for(i=0; i<nVal; i++){
sqlite3ValueFree(apVal[i]);
}
- sqlite3DbFree(db, apVal);
+ sqlite3DbFreeNN(db, apVal);
}
*ppVal = pVal;
@@ -70005,7 +77294,7 @@ static int valueFromFunction(
}
#else
# define valueFromFunction(a,b,c,d,e,f) SQLITE_OK
-#endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */
+#endif /* defined(SQLITE_ENABLE_STAT4) */
/*
** Extract a value from the supplied expression in the manner described
@@ -70034,7 +77323,11 @@ static int valueFromExpr(
assert( pExpr!=0 );
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
+#if defined(SQLITE_ENABLE_STAT4)
+ if( op==TK_REGISTER ) op = pExpr->op2;
+#else
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
+#endif
/* Compressed expressions only appear when parsing the DEFAULT clause
** on a table column definition, and hence only when pCtx==0. This
@@ -70079,20 +77372,29 @@ static int valueFromExpr(
}else{
sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
}
- if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
+ assert( (pVal->flags & MEM_IntReal)==0 );
+ if( pVal->flags & (MEM_Int|MEM_IntReal|MEM_Real) ){
+ testcase( pVal->flags & MEM_Int );
+ testcase( pVal->flags & MEM_Real );
+ pVal->flags &= ~MEM_Str;
+ }
if( enc!=SQLITE_UTF8 ){
rc = sqlite3VdbeChangeEncoding(pVal, enc);
}
}else if( op==TK_UMINUS ) {
/* This branch happens for multiple negative signs. Ex: -(-5) */
- if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal)
+ if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx)
&& pVal!=0
){
sqlite3VdbeMemNumerify(pVal);
if( pVal->flags & MEM_Real ){
pVal->u.r = -pVal->u.r;
}else if( pVal->u.i==SMALLEST_INT64 ){
+#ifndef SQLITE_OMIT_FLOATING_POINT
pVal->u.r = -(double)SMALLEST_INT64;
+#else
+ pVal->u.r = LARGEST_INT64;
+#endif
MemSetTypeFlag(pVal, MEM_Real);
}else{
pVal->u.i = -pVal->u.i;
@@ -70102,6 +77404,7 @@ static int valueFromExpr(
}else if( op==TK_NULL ){
pVal = valueNew(db, pCtx);
if( pVal==0 ) goto no_mem;
+ sqlite3VdbeMemSetNull(pVal);
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
else if( op==TK_BLOB ){
@@ -70117,21 +77420,30 @@ static int valueFromExpr(
0, SQLITE_DYNAMIC);
}
#endif
-
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
else if( op==TK_FUNCTION && pCtx!=0 ){
rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx);
}
#endif
+ else if( op==TK_TRUEFALSE ){
+ pVal = valueNew(db, pCtx);
+ if( pVal ){
+ pVal->flags = MEM_Int;
+ pVal->u.i = pExpr->u.zToken[4]==0;
+ }
+ }
*ppVal = pVal;
return rc;
no_mem:
- sqlite3OomFault(db);
+#ifdef SQLITE_ENABLE_STAT4
+ if( pCtx==0 || pCtx->pParse->nErr==0 )
+#endif
+ sqlite3OomFault(db);
sqlite3DbFree(db, zVal);
assert( *ppVal==0 );
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
if( pCtx==0 ) sqlite3ValueFree(pVal);
#else
assert( pCtx==0 ); sqlite3ValueFree(pVal);
@@ -70159,56 +77471,7 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-/*
-** The implementation of the sqlite_record() function. This function accepts
-** a single argument of any type. The return value is a formatted database
-** record (a blob) containing the argument value.
-**
-** This is used to convert the value stored in the 'sample' column of the
-** sqlite_stat3 table to the record format SQLite uses internally.
-*/
-static void recordFunc(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- const int file_format = 1;
- u32 iSerial; /* Serial type */
- int nSerial; /* Bytes of space for iSerial as varint */
- u32 nVal; /* Bytes of space required for argv[0] */
- int nRet;
- sqlite3 *db;
- u8 *aRet;
-
- UNUSED_PARAMETER( argc );
- iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal);
- nSerial = sqlite3VarintLen(iSerial);
- db = sqlite3_context_db_handle(context);
-
- nRet = 1 + nSerial + nVal;
- aRet = sqlite3DbMallocRawNN(db, nRet);
- if( aRet==0 ){
- sqlite3_result_error_nomem(context);
- }else{
- aRet[0] = nSerial+1;
- putVarint32(&aRet[1], iSerial);
- sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial);
- sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
- sqlite3DbFree(db, aRet);
- }
-}
-
-/*
-** Register built-in functions used to help read ANALYZE data.
-*/
-SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){
- static FuncDef aAnalyzeTableFuncs[] = {
- FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
- };
- sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
-}
-
+#ifdef SQLITE_ENABLE_STAT4
/*
** Attempt to extract a value from pExpr and use it to construct *ppVal.
**
@@ -70241,14 +77504,13 @@ static int stat4ValueFromExpr(
/* Skip over any TK_COLLATE nodes */
pExpr = sqlite3ExprSkipCollate(pExpr);
+ assert( pExpr==0 || pExpr->op!=TK_REGISTER || pExpr->op2!=TK_VARIABLE );
if( !pExpr ){
pVal = valueNew(db, pAlloc);
if( pVal ){
sqlite3VdbeMemSetNull((Mem*)pVal);
}
- }else if( pExpr->op==TK_VARIABLE
- || NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
- ){
+ }else if( pExpr->op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
Vdbe *v;
int iBindVar = pExpr->iColumn;
sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
@@ -70256,9 +77518,7 @@ static int stat4ValueFromExpr(
pVal = valueNew(db, pAlloc);
if( pVal ){
rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
- if( rc==SQLITE_OK ){
- sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
- }
+ sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
pVal->db = pParse->db;
}
}
@@ -70272,8 +77532,8 @@ static int stat4ValueFromExpr(
}
/*
-** This function is used to allocate and populate UnpackedRecord
-** structures intended to be compared against sample index keys stored
+** This function is used to allocate and populate UnpackedRecord
+** structures intended to be compared against sample index keys stored
** in the sqlite_stat4 table.
**
** A single call to this function populates zero or more fields of the
@@ -70284,14 +77544,14 @@ static int stat4ValueFromExpr(
**
** * The expression is a bound variable, and this is a reprepare, or
**
-** * The sqlite3ValueFromExpr() function is able to extract a value
+** * The sqlite3ValueFromExpr() function is able to extract a value
** from the expression (i.e. the expression is a literal value).
**
** Or, if pExpr is a TK_VECTOR, one field is populated for each of the
** vector components that match either of the two latter criteria listed
** above.
**
-** Before any value is appended to the record, the affinity of the
+** Before any value is appended to the record, the affinity of the
** corresponding column within index pIdx is applied to it. Before
** this function returns, output parameter *pnExtract is set to the
** number of values appended to the record.
@@ -70342,9 +77602,9 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
/*
** Attempt to extract a value from expression pExpr using the methods
-** as described for sqlite3Stat4ProbeSetValue() above.
+** as described for sqlite3Stat4ProbeSetValue() above.
**
-** If successful, set *ppVal to point to a new value object and return
+** If successful, set *ppVal to point to a new value object and return
** SQLITE_OK. If no value can be extracted, but no other error occurs
** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error
** does occur, return an SQLite error code. The final value of *ppVal
@@ -70364,7 +77624,7 @@ SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(
** the column value into *ppVal. If *ppVal is initially NULL then a new
** sqlite3_value object is allocated.
**
-** If *ppVal is initially NULL then the caller is responsible for
+** If *ppVal is initially NULL then the caller is responsible for
** ensuring that the value written into *ppVal is eventually freed.
*/
SQLITE_PRIVATE int sqlite3Stat4Column(
@@ -70374,11 +77634,11 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
int iCol, /* Column to extract */
sqlite3_value **ppVal /* OUT: Extracted value */
){
- u32 t; /* a column type code */
+ u32 t = 0; /* a column type code */
int nHdr; /* Size of the header in the record */
int iHdr; /* Next unread header byte */
int iField; /* Next unread data byte */
- int szField; /* Size of the current data field */
+ int szField = 0; /* Size of the current data field */
int i; /* Column index */
u8 *a = (u8*)pRec; /* Typecast byte array */
Mem *pMem = *ppVal; /* Write result into this Mem object */
@@ -70415,14 +77675,14 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
if( pRec ){
int i;
- int nCol = pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField;
+ int nCol = pRec->pKeyInfo->nAllField;
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for(i=0; i<nCol; i++){
sqlite3VdbeMemRelease(&aMem[i]);
}
sqlite3KeyInfoUnref(pRec->pKeyInfo);
- sqlite3DbFree(db, pRec);
+ sqlite3DbFreeNN(db, pRec);
}
}
#endif /* ifdef SQLITE_ENABLE_STAT4 */
@@ -70446,7 +77706,7 @@ SQLITE_PRIVATE void sqlite3ValueSetStr(
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value *v){
if( !v ) return;
sqlite3VdbeMemRelease((Mem *)v);
- sqlite3DbFree(((Mem*)v)->db, v);
+ sqlite3DbFreeNN(((Mem*)v)->db, v);
}
/*
@@ -70488,11 +77748,15 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
-** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
+** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
*/
/* #include "sqliteInt.h" */
/* #include "vdbeInt.h" */
+/* Forward references */
+static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef);
+static void vdbeFreeOpArray(sqlite3 *, Op *, int);
+
/*
** Create a new virtual database engine.
*/
@@ -70511,14 +77775,23 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
db->pVdbe = p;
p->magic = VDBE_MAGIC_INIT;
p->pParse = pParse;
+ pParse->pVdbe = p;
assert( pParse->aLabel==0 );
assert( pParse->nLabel==0 );
- assert( pParse->nOpAlloc==0 );
+ assert( p->nOpAlloc==0 );
assert( pParse->szOpAlloc==0 );
+ sqlite3VdbeAddOp2(p, OP_Init, 0, 1);
return p;
}
/*
+** Return the Parse object that owns a Vdbe object.
+*/
+SQLITE_PRIVATE Parse *sqlite3VdbeParser(Vdbe *p){
+ return p->pParse;
+}
+
+/*
** Change the error string stored in Vdbe.zErrMsg
*/
SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
@@ -70532,17 +77805,53 @@ SQLITE_PRIVATE void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){
/*
** Remember the SQL string for a prepared statement.
*/
-SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
- assert( isPrepareV2==1 || isPrepareV2==0 );
+SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){
if( p==0 ) return;
-#if defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_ENABLE_SQLLOG)
- if( !isPrepareV2 ) return;
-#endif
+ p->prepFlags = prepFlags;
+ if( (prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
+ p->expmask = 0;
+ }
assert( p->zSql==0 );
p->zSql = sqlite3DbStrNDup(p->db, z, n);
- p->isPrepareV2 = (u8)isPrepareV2;
}
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** Add a new element to the Vdbe->pDblStr list.
+*/
+SQLITE_PRIVATE void sqlite3VdbeAddDblquoteStr(sqlite3 *db, Vdbe *p, const char *z){
+ if( p ){
+ int n = sqlite3Strlen30(z);
+ DblquoteStr *pStr = sqlite3DbMallocRawNN(db,
+ sizeof(*pStr)+n+1-sizeof(pStr->z));
+ if( pStr ){
+ pStr->pNextStr = p->pDblStr;
+ p->pDblStr = pStr;
+ memcpy(pStr->z, z, n+1);
+ }
+ }
+}
+#endif
+
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** zId of length nId is a double-quoted identifier. Check to see if
+** that identifier is really used as a string literal.
+*/
+SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(
+ Vdbe *pVdbe, /* The prepared statement */
+ const char *zId /* The double-quoted identifier, already dequoted */
+){
+ DblquoteStr *pStr;
+ assert( zId!=0 );
+ if( pVdbe->pDblStr==0 ) return 0;
+ for(pStr=pVdbe->pDblStr; pStr; pStr=pStr->pNextStr){
+ if( strcmp(zId, pStr->z)==0 ) return 1;
+ }
+ return 0;
+}
+#endif
+
/*
** Swap all content between two VDBE structures.
*/
@@ -70562,17 +77871,25 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
- pB->isPrepareV2 = pA->isPrepareV2;
+#ifdef SQLITE_ENABLE_NORMALIZE
+ zTmp = pA->zNormSql;
+ pA->zNormSql = pB->zNormSql;
+ pB->zNormSql = zTmp;
+#endif
+ pB->expmask = pA->expmask;
+ pB->prepFlags = pA->prepFlags;
+ memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter));
+ pB->aCounter[SQLITE_STMTSTATUS_REPREPARE]++;
}
/*
-** Resize the Vdbe.aOp array so that it is at least nOp elements larger
+** Resize the Vdbe.aOp array so that it is at least nOp elements larger
** than its current size. nOp is guaranteed to be less than or equal
** to 1024/sizeof(Op).
**
** If an out-of-memory error occurs while resizing the array, return
-** SQLITE_NOMEM. In this case Vdbe.aOp and Parse.nOpAlloc remain
-** unchanged (this is so that any opcodes already allocated can be
+** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
+** unchanged (this is so that any opcodes already allocated can be
** correctly deallocated along with the rest of the Vdbe).
*/
static int growOpArray(Vdbe *v, int nOp){
@@ -70580,25 +77897,33 @@ static int growOpArray(Vdbe *v, int nOp){
Parse *p = v->pParse;
/* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force
- ** more frequent reallocs and hence provide more opportunities for
+ ** more frequent reallocs and hence provide more opportunities for
** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used
** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array
** by the minimum* amount required until the size reaches 512. Normal
** operation (without SQLITE_TEST_REALLOC_STRESS) is to double the current
** size of the op array or add 1KB of space, whichever is smaller. */
#ifdef SQLITE_TEST_REALLOC_STRESS
- int nNew = (p->nOpAlloc>=512 ? p->nOpAlloc*2 : p->nOpAlloc+nOp);
+ sqlite3_int64 nNew = (v->nOpAlloc>=512 ? 2*(sqlite3_int64)v->nOpAlloc
+ : (sqlite3_int64)v->nOpAlloc+nOp);
#else
- int nNew = (p->nOpAlloc ? p->nOpAlloc*2 : (int)(1024/sizeof(Op)));
+ sqlite3_int64 nNew = (v->nOpAlloc ? 2*(sqlite3_int64)v->nOpAlloc
+ : (sqlite3_int64)(1024/sizeof(Op)));
UNUSED_PARAMETER(nOp);
#endif
+ /* Ensure that the size of a VDBE does not grow too large */
+ if( nNew > p->db->aLimit[SQLITE_LIMIT_VDBE_OP] ){
+ sqlite3OomFault(p->db);
+ return SQLITE_NOMEM;
+ }
+
assert( nOp<=(1024/sizeof(Op)) );
- assert( nNew>=(p->nOpAlloc+nOp) );
+ assert( nNew>=(v->nOpAlloc+nOp) );
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
if( pNew ){
p->szOpAlloc = sqlite3DbMallocSize(p->db, pNew);
- p->nOpAlloc = p->szOpAlloc/sizeof(Op);
+ v->nOpAlloc = p->szOpAlloc/sizeof(Op);
v->aOp = pNew;
}
return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
@@ -70607,9 +77932,16 @@ static int growOpArray(Vdbe *v, int nOp){
#ifdef SQLITE_DEBUG
/* This routine is just a convenient place to set a breakpoint that will
** fire after each opcode is inserted and displayed using
-** "PRAGMA vdbe_addoptrace=on".
+** "PRAGMA vdbe_addoptrace=on". Parameters "pc" (program counter) and
+** pOp are available to make the breakpoint conditional.
+**
+** Other useful labels for breakpoints include:
+** test_trace_breakpoint(pc,pOp)
+** sqlite3CorruptError(lineno)
+** sqlite3MisuseError(lineno)
+** sqlite3CantopenError(lineno)
*/
-static void test_addop_breakpoint(void){
+static void test_addop_breakpoint(int pc, Op *pOp){
static int n = 0;
n++;
}
@@ -70632,9 +77964,9 @@ static void test_addop_breakpoint(void){
** operand.
*/
static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
- assert( p->pParse->nOpAlloc<=p->nOp );
+ assert( p->nOpAlloc<=p->nOp );
if( growOpArray(p, 1) ) return 1;
- assert( p->pParse->nOpAlloc>p->nOp );
+ assert( p->nOpAlloc>p->nOp );
return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
}
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
@@ -70644,7 +77976,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
i = p->nOp;
assert( p->magic==VDBE_MAGIC_INIT );
assert( op>=0 && op<0xff );
- if( p->pParse->nOpAlloc<=i ){
+ if( p->nOpAlloc<=i ){
return growOp3(p, op, p1, p2, p3);
}
p->nOp++;
@@ -70661,16 +77993,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
#endif
#ifdef SQLITE_DEBUG
if( p->db->flags & SQLITE_VdbeAddopTrace ){
- int jj, kk;
- Parse *pParse = p->pParse;
- for(jj=kk=0; jj<pParse->nColCache; jj++){
- struct yColCache *x = pParse->aColCache + jj;
- printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
- kk++;
- }
- if( kk ) printf("\n");
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
- test_addop_breakpoint();
+ test_addop_breakpoint(i, &p->aOp[i]);
}
#endif
#ifdef VDBE_PROFILE
@@ -70712,6 +78036,9 @@ SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){
** "s" character in zTypes[], the register is a string if the argument is
** not NULL, or OP_Null if the value is a null pointer. For each "i" character
** in zTypes[], the register is initialized to an integer.
+**
+** If the input string does not end with "X" then an OP_ResultRow instruction
+** is generated for the values inserted.
*/
SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){
va_list ap;
@@ -70721,12 +78048,15 @@ SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes,
for(i=0; (c = zTypes[i])!=0; i++){
if( c=='s' ){
const char *z = va_arg(ap, const char*);
- sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest++, 0, z, 0);
+ sqlite3VdbeAddOp4(p, z==0 ? OP_Null : OP_String8, 0, iDest+i, 0, z, 0);
+ }else if( c=='i' ){
+ sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest+i);
}else{
- assert( c=='i' );
- sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
+ goto skip_op_resultrow;
}
}
+ sqlite3VdbeAddOp2(p, OP_ResultRow, iDest, i);
+skip_op_resultrow:
va_end(ap);
}
@@ -70748,6 +78078,49 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4(
}
/*
+** Add an OP_Function or OP_PureFunc opcode.
+**
+** The eCallCtx argument is information (typically taken from Expr.op2)
+** that describes the calling context of the function. 0 means a general
+** function call. NC_IsCheck means called by a check constraint,
+** NC_IdxExpr means called as part of an index expression. NC_PartIdx
+** means in the WHERE clause of a partial index. NC_GenCol means called
+** while computing a generated column value. 0 is the usual case.
+*/
+SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(
+ Parse *pParse, /* Parsing context */
+ int p1, /* Constant argument mask */
+ int p2, /* First argument register */
+ int p3, /* Register into which results are written */
+ int nArg, /* Number of argument */
+ const FuncDef *pFunc, /* The function to be invoked */
+ int eCallCtx /* Calling context */
+){
+ Vdbe *v = pParse->pVdbe;
+ int nByte;
+ int addr;
+ sqlite3_context *pCtx;
+ assert( v );
+ nByte = sizeof(*pCtx) + (nArg-1)*sizeof(sqlite3_value*);
+ pCtx = sqlite3DbMallocRawNN(pParse->db, nByte);
+ if( pCtx==0 ){
+ assert( pParse->db->mallocFailed );
+ freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
+ return 0;
+ }
+ pCtx->pOut = 0;
+ pCtx->pFunc = (FuncDef*)pFunc;
+ pCtx->pVdbe = 0;
+ pCtx->isError = 0;
+ pCtx->argc = nArg;
+ pCtx->iOp = sqlite3VdbeCurrentAddr(v);
+ addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
+ p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
+ sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
+ return addr;
+}
+
+/*
** Add an opcode that includes the p4 value with a P4_INT64 or
** P4_REAL type.
*/
@@ -70765,6 +78138,69 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type);
}
+#ifndef SQLITE_OMIT_EXPLAIN
+/*
+** Return the address of the current EXPLAIN QUERY PLAN baseline.
+** 0 means "none".
+*/
+SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse *pParse){
+ VdbeOp *pOp;
+ if( pParse->addrExplain==0 ) return 0;
+ pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain);
+ return pOp->p2;
+}
+
+/*
+** Set a debugger breakpoint on the following routine in order to
+** monitor the EXPLAIN QUERY PLAN code generation.
+*/
+#if defined(SQLITE_DEBUG)
+SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
+ (void)z1;
+ (void)z2;
+}
+#endif
+
+/*
+** Add a new OP_Explain opcode.
+**
+** If the bPush flag is true, then make this opcode the parent for
+** subsequent Explains until sqlite3VdbeExplainPop() is called.
+*/
+SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
+#ifndef SQLITE_DEBUG
+ /* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
+ ** But omit them (for performance) during production builds */
+ if( pParse->explain==2 )
+#endif
+ {
+ char *zMsg;
+ Vdbe *v;
+ va_list ap;
+ int iThis;
+ va_start(ap, zFmt);
+ zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap);
+ va_end(ap);
+ v = pParse->pVdbe;
+ iThis = v->nOp;
+ sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
+ zMsg, P4_DYNAMIC);
+ sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z);
+ if( bPush){
+ pParse->addrExplain = iThis;
+ }
+ }
+}
+
+/*
+** Pop the EXPLAIN QUERY PLAN stack one level.
+*/
+SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){
+ sqlite3ExplainBreakpoint("POP", 0);
+ pParse->addrExplain = sqlite3VdbeExplainParent(pParse);
+}
+#endif /* SQLITE_OMIT_EXPLAIN */
+
/*
** Add an OP_ParseSchema opcode. This routine is broken out from
** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees
@@ -70791,7 +78227,11 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
int p4 /* The P4 operand as an integer */
){
int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
- sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
+ if( p->db->mallocFailed==0 ){
+ VdbeOp *pOp = &p->aOp[addr];
+ pOp->p4type = P4_INT32;
+ pOp->p4.i = p4;
+ }
return addr;
}
@@ -70821,21 +78261,22 @@ SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
** The VDBE knows that a P2 value is a label because labels are
** always negative and P2 values are suppose to be non-negative.
** Hence, a negative P2 value is a label that has yet to be resolved.
+** (Later:) This is only true for opcodes that have the OPFLG_JUMP
+** property.
+**
+** Variable usage notes:
**
-** Zero is returned if a malloc() fails.
+** Parse.aLabel[x] Stores the address that the x-th label resolves
+** into. For testing (SQLITE_DEBUG), unresolved
+** labels stores -1, but that is not required.
+** Parse.nLabelAlloc Number of slots allocated to Parse.aLabel[]
+** Parse.nLabel The *negative* of the number of labels that have
+** been issued. The negative is stored because
+** that gives a performance improvement over storing
+** the equivalent positive value.
*/
-SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
- Parse *p = v->pParse;
- int i = p->nLabel++;
- assert( v->magic==VDBE_MAGIC_INIT );
- if( (i & (i-1))==0 ){
- p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
- (i*2+1)*sizeof(p->aLabel[0]));
- }
- if( p->aLabel ){
- p->aLabel[i] = -1;
- }
- return ADDR(i);
+SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse *pParse){
+ return --pParse->nLabel;
}
/*
@@ -70843,13 +78284,36 @@ SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *v){
** be inserted. The parameter "x" must have been obtained from
** a prior call to sqlite3VdbeMakeLabel().
*/
+static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
+ int nNewSize = 10 - p->nLabel;
+ p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
+ nNewSize*sizeof(p->aLabel[0]));
+ if( p->aLabel==0 ){
+ p->nLabelAlloc = 0;
+ }else{
+#ifdef SQLITE_DEBUG
+ int i;
+ for(i=p->nLabelAlloc; i<nNewSize; i++) p->aLabel[i] = -1;
+#endif
+ p->nLabelAlloc = nNewSize;
+ p->aLabel[j] = v->nOp;
+ }
+}
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
Parse *p = v->pParse;
int j = ADDR(x);
assert( v->magic==VDBE_MAGIC_INIT );
- assert( j<p->nLabel );
+ assert( j<-p->nLabel );
assert( j>=0 );
- if( p->aLabel ){
+#ifdef SQLITE_DEBUG
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("RESOLVE LABEL %d to %d\n", x, v->nOp);
+ }
+#endif
+ if( p->nLabelAlloc + p->nLabel < 0 ){
+ resizeResolveLabel(p,v,j);
+ }else{
+ assert( p->aLabel[j]==(-1) ); /* Labels may only be resolved once */
p->aLabel[j] = v->nOp;
}
}
@@ -70872,19 +78336,19 @@ SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){
/*
** The following type and function are used to iterate through all opcodes
-** in a Vdbe main program and each of the sub-programs (triggers) it may
+** in a Vdbe main program and each of the sub-programs (triggers) it may
** invoke directly or indirectly. It should be used as follows:
**
** Op *pOp;
** VdbeOpIter sIter;
**
** memset(&sIter, 0, sizeof(sIter));
-** sIter.v = v; // v is of type Vdbe*
+** sIter.v = v; // v is of type Vdbe*
** while( (pOp = opIterNext(&sIter)) ){
** // Do something with pOp
** }
** sqlite3DbFree(v->db, sIter.apSub);
-**
+**
*/
typedef struct VdbeOpIter VdbeOpIter;
struct VdbeOpIter {
@@ -70917,7 +78381,7 @@ static Op *opIterNext(VdbeOpIter *p){
p->iSub++;
p->iAddr = 0;
}
-
+
if( pRet->p4type==P4_SUBPROGRAM ){
int nByte = (p->nSub+1)*sizeof(SubProgram*);
int j;
@@ -70948,9 +78412,11 @@ static Op *opIterNext(VdbeOpIter *p){
** * OP_HaltIfNull with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
** * OP_Destroy
** * OP_VUpdate
+** * OP_VCreate
** * OP_VRename
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
-** * OP_CreateTable and OP_InitCoroutine (for CREATE TABLE AS SELECT ...)
+** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine
+** (for CREATE TABLE AS SELECT ...)
**
** Then check that the value of Parse.mayAbort is true if an
** ABORT may be thrown, or false otherwise. Return true if it does
@@ -70963,6 +78429,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
int hasAbort = 0;
int hasFkCounter = 0;
int hasCreateTable = 0;
+ int hasCreateIndex = 0;
int hasInitCoroutine = 0;
Op *pOp;
VdbeOpIter sIter;
@@ -70971,14 +78438,25 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
while( (pOp = opIterNext(&sIter))!=0 ){
int opcode = pOp->opcode;
- if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
- || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
- && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
+ if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
+ || opcode==OP_VDestroy
+ || opcode==OP_VCreate
+ || (opcode==OP_ParseSchema && pOp->p4.z==0)
+ || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
+ && ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
hasAbort = 1;
break;
}
- if( opcode==OP_CreateTable ) hasCreateTable = 1;
+ if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
+ if( mayAbort ){
+ /* hasCreateIndex may also be set for some DELETE statements that use
+ ** OP_Clear. So this routine may end up returning true in the case
+ ** where a "DELETE FROM tbl" has a statement-journal but does not
+ ** require one. This is not so bad - it is an inefficiency, not a bug. */
+ if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1;
+ if( opcode==OP_Clear ) hasCreateIndex = 1;
+ }
if( opcode==OP_InitCoroutine ) hasInitCoroutine = 1;
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1 ){
@@ -70994,10 +78472,37 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** true for this case to prevent the assert() in the callers frame
** from failing. */
return ( v->db->mallocFailed || hasAbort==mayAbort || hasFkCounter
- || (hasCreateTable && hasInitCoroutine) );
+ || (hasCreateTable && hasInitCoroutine) || hasCreateIndex
+ );
}
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
+#ifdef SQLITE_DEBUG
+/*
+** Increment the nWrite counter in the VDBE if the cursor is not an
+** ephemeral cursor, or if the cursor argument is NULL.
+*/
+SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe *p, VdbeCursor *pC){
+ if( pC==0
+ || (pC->eCurType!=CURTYPE_SORTER
+ && pC->eCurType!=CURTYPE_PSEUDO
+ && !pC->isEphemeral)
+ ){
+ p->nWrite++;
+ }
+}
+#endif
+
+#ifdef SQLITE_DEBUG
+/*
+** Assert if an Abort at this point in time might result in a corrupt
+** database.
+*/
+SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){
+ assert( p->nWrite==0 || p->usesStmtJournal );
+}
+#endif
+
/*
** This routine is called after all opcodes have been inserted. It loops
** through all the opcodes and fixes up some details.
@@ -71041,7 +78546,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
switch( pOp->opcode ){
case OP_Transaction: {
if( pOp->p2!=0 ) p->readOnly = 0;
- /* fall thru */
+ /* no break */ deliberate_fall_through
}
case OP_AutoCommit:
case OP_Savepoint: {
@@ -71057,6 +78562,25 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->bIsReader = 1;
break;
}
+ case OP_Next:
+ case OP_SorterNext: {
+ pOp->p4.xAdvance = sqlite3BtreeNext;
+ pOp->p4type = P4_ADVANCE;
+ /* The code generator never codes any of these opcodes as a jump
+ ** to a label. They are always coded as a jump backwards to a
+ ** known address */
+ assert( pOp->p2>=0 );
+ break;
+ }
+ case OP_Prev: {
+ pOp->p4.xAdvance = sqlite3BtreePrevious;
+ pOp->p4type = P4_ADVANCE;
+ /* The code generator never codes any of these opcodes as a jump
+ ** to a label. They are always coded as a jump backwards to a
+ ** known address */
+ assert( pOp->p2>=0 );
+ break;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -71068,27 +78592,26 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
assert( pOp[-1].opcode==OP_Integer );
n = pOp[-1].p1;
if( n>nMaxArgs ) nMaxArgs = n;
- break;
+ /* Fall through into the default case */
+ /* no break */ deliberate_fall_through
}
#endif
- case OP_Next:
- case OP_NextIfOpen:
- case OP_SorterNext: {
- pOp->p4.xAdvance = sqlite3BtreeNext;
- pOp->p4type = P4_ADVANCE;
- break;
- }
- case OP_Prev:
- case OP_PrevIfOpen: {
- pOp->p4.xAdvance = sqlite3BtreePrevious;
- pOp->p4type = P4_ADVANCE;
+ default: {
+ if( pOp->p2<0 ){
+ /* The mkopcodeh.tcl script has so arranged things that the only
+ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
+ ** have non-negative values for P2. */
+ assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
+ assert( ADDR(pOp->p2)<-pParse->nLabel );
+ pOp->p2 = aLabel[ADDR(pOp->p2)];
+ }
break;
}
}
- if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
- assert( ADDR(pOp->p2)<pParse->nLabel );
- pOp->p2 = aLabel[ADDR(pOp->p2)];
- }
+ /* The mkopcodeh.tcl script has so arranged things that the only
+ ** non-jump opcodes less than SQLITE_MX_JUMP_CODE are guaranteed to
+ ** have non-negative values for P2. */
+ assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
if( pOp==p->aOp ) break;
pOp--;
@@ -71118,19 +78641,46 @@ SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
*/
#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
SQLITE_PRIVATE void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N){
- assert( p->nOp + N <= p->pParse->nOpAlloc );
+ assert( p->nOp + N <= p->nOpAlloc );
+}
+#endif
+
+/*
+** Verify that the VM passed as the only argument does not contain
+** an OP_ResultRow opcode. Fail an assert() if it does. This is used
+** by code in pragma.c to ensure that the implementation of certain
+** pragmas comports with the flags specified in the mkpragmatab.tcl
+** script.
+*/
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
+SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p){
+ int i;
+ for(i=0; i<p->nOp; i++){
+ assert( p->aOp[i].opcode!=OP_ResultRow );
+ }
+}
+#endif
+
+/*
+** Generate code (a single OP_Abortable opcode) that will
+** verify that the VDBE program can safely call Abort in the current
+** context.
+*/
+#if defined(SQLITE_DEBUG)
+SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){
+ if( onError==OE_Abort ) sqlite3VdbeAddOp0(p, OP_Abortable);
}
#endif
/*
** This function returns a pointer to the array of opcodes associated with
** the Vdbe passed as the first argument. It is the callers responsibility
-** to arrange for the returned array to be eventually freed using the
+** to arrange for the returned array to be eventually freed using the
** vdbeFreeOpArray() function.
**
** Before returning, *pnOp is set to the number of entries in the returned
-** array. Also, *pnMaxArg is set to the larger of its current value and
-** the number of entries in the Vdbe.apArg[] array required to execute the
+** array. Also, *pnMaxArg is set to the larger of its current value and
+** the number of entries in the Vdbe.apArg[] array required to execute the
** returned program.
*/
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
@@ -71163,7 +78713,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
VdbeOp *pOut, *pFirst;
assert( nOp>0 );
assert( p->magic==VDBE_MAGIC_INIT );
- if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
+ if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){
return 0;
}
pFirst = pOut = &p->aOp[p->nOp];
@@ -71204,12 +78754,12 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
SQLITE_PRIVATE void sqlite3VdbeScanStatus(
Vdbe *p, /* VM to add scanstatus() to */
int addrExplain, /* Address of OP_Explain (or 0) */
- int addrLoop, /* Address of loop counter */
+ int addrLoop, /* Address of loop counter */
int addrVisit, /* Address of rows visited counter */
LogEst nEst, /* Estimated number of output rows */
const char *zName /* Name of table or index being scanned */
){
- int nByte = (p->nScan+1) * sizeof(ScanStatus);
+ sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
ScanStatus *aNew;
aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
if( aNew ){
@@ -71229,19 +78779,19 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
** Change the value of the opcode, or P1, P2, P3, or P5 operands
** for a specific instruction.
*/
-SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){
+SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
}
-SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
+SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
sqlite3VdbeGetOp(p,addr)->p1 = val;
}
-SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
+SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
sqlite3VdbeGetOp(p,addr)->p2 = val;
}
-SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
+SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
sqlite3VdbeGetOp(p,addr)->p3 = val;
}
-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
+SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
assert( p->nOp>0 || p->db->mallocFailed );
if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
}
@@ -71254,6 +78804,34 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
sqlite3VdbeChangeP2(p, addr, p->nOp);
}
+/*
+** Change the P2 operand of the jump instruction at addr so that
+** the jump lands on the next opcode. Or if the jump instruction was
+** the previous opcode (and is thus a no-op) then simply back up
+** the next instruction counter by one slot so that the jump is
+** overwritten by the next inserted opcode.
+**
+** This routine is an optimization of sqlite3VdbeJumpHere() that
+** strives to omit useless byte-code like this:
+**
+** 7 Once 0 8 0
+** 8 ...
+*/
+SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
+ if( addr==p->nOp-1 ){
+ assert( p->aOp[addr].opcode==OP_Once
+ || p->aOp[addr].opcode==OP_If
+ || p->aOp[addr].opcode==OP_FkIfZero );
+ assert( p->aOp[addr].p4type==0 );
+#ifdef SQLITE_VDBE_COVERAGE
+ sqlite3VdbeGetOp(p,-1)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
+#endif
+ p->nOp--;
+ }else{
+ sqlite3VdbeChangeP2(p, addr, p->nOp);
+ }
+}
+
/*
** If the input FuncDef structure is ephemeral, then free it. If
@@ -71261,22 +78839,20 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
- sqlite3DbFree(db, pDef);
+ sqlite3DbFreeNN(db, pDef);
}
}
-static void vdbeFreeOpArray(sqlite3 *, Op *, int);
-
/*
** Delete a P4 value if necessary.
*/
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
freeEphemeralFunction(db, p->pFunc);
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
@@ -71288,6 +78864,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
case P4_REAL:
case P4_INT64:
case P4_DYNAMIC:
+ case P4_DYNBLOB:
case P4_INTARRAY: {
sqlite3DbFree(db, p4);
break;
@@ -71302,10 +78879,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
break;
}
#endif
- case P4_MPRINTF: {
- if( db->pnBytesFreed==0 ) sqlite3_free(p4);
- break;
- }
case P4_FUNCDEF: {
freeEphemeralFunction(db, (FuncDef*)p4);
break;
@@ -71327,20 +78900,20 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
/*
** Free the space allocated for aOp and any p4 values allocated for the
-** opcodes contained within. If aOp is not NULL it is assumed to contain
-** nOp entries.
+** opcodes contained within. If aOp is not NULL it is assumed to contain
+** nOp entries.
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( aOp ){
Op *pOp;
- for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
- if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
+ for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
+ if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);
-#endif
+#endif
}
+ sqlite3DbFreeNN(db, aOp);
}
- sqlite3DbFree(db, aOp);
}
/*
@@ -71354,6 +78927,13 @@ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
}
/*
+** Return true if the given Vdbe has any SubPrograms.
+*/
+SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe *pVdbe){
+ return pVdbe->pProgram!=0;
+}
+
+/*
** Change the opcode at addr into OP_Noop
*/
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
@@ -71380,6 +78960,41 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
}
}
+#ifdef SQLITE_DEBUG
+/*
+** Generate an OP_ReleaseReg opcode to indicate that a range of
+** registers, except any identified by mask, are no longer in use.
+*/
+SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(
+ Parse *pParse, /* Parsing context */
+ int iFirst, /* Index of first register to be released */
+ int N, /* Number of registers to release */
+ u32 mask, /* Mask of registers to NOT release */
+ int bUndefine /* If true, mark registers as undefined */
+){
+ if( N==0 ) return;
+ assert( pParse->pVdbe );
+ assert( iFirst>=1 );
+ assert( iFirst+N-1<=pParse->nMem );
+ if( N<=31 && mask!=0 ){
+ while( N>0 && (mask&1)!=0 ){
+ mask >>= 1;
+ iFirst++;
+ N--;
+ }
+ while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){
+ mask &= ~MASKBIT32(N-1);
+ N--;
+ }
+ }
+ if( N>0 ){
+ sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask);
+ if( bUndefine ) sqlite3VdbeChangeP5(pParse->pVdbe, 1);
+ }
+}
+#endif /* SQLITE_DEBUG */
+
+
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -71390,7 +79005,7 @@ SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
** the string is made into memory obtained from sqlite3_malloc().
** A value of n==0 means copy bytes of zP4 up to and including the
** first null byte. If n>0 then copy n+1 bytes of zP4.
-**
+**
** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points
** to a string or structure that is guaranteed to exist for the lifetime of
** the Vdbe. In these cases we can just copy the pointer.
@@ -71451,15 +79066,41 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
}
/*
+** Change the P4 operand of the most recently coded instruction
+** to the value defined by the arguments. This is a high-speed
+** version of sqlite3VdbeChangeP4().
+**
+** The P4 operand must not have been previously defined. And the new
+** P4 must not be P4_INT32. Use sqlite3VdbeChangeP4() in either of
+** those cases.
+*/
+SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
+ VdbeOp *pOp;
+ assert( n!=P4_INT32 && n!=P4_VTAB );
+ assert( n<=0 );
+ if( p->db->mallocFailed ){
+ freeP4(p->db, n, pP4);
+ }else{
+ assert( pP4!=0 );
+ assert( p->nOp>0 );
+ pOp = &p->aOp[p->nOp-1];
+ assert( pOp->p4type==P4_NOTUSED );
+ pOp->p4type = n;
+ pOp->p4.p = pP4;
+ }
+}
+
+/*
** Set the P4 on the most recently added opcode to the KeyInfo for the
** index given.
*/
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
Vdbe *v = pParse->pVdbe;
+ KeyInfo *pKeyInfo;
assert( v!=0 );
assert( pIdx!=0 );
- sqlite3VdbeChangeP4(v, -1, (char*)sqlite3KeyInfoOfIndex(pParse, pIdx),
- P4_KEYINFO);
+ pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx);
+ if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
}
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -71471,7 +79112,8 @@ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
*/
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
assert( p->nOp>0 || p->aOp==0 );
- assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed );
+ assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed
+ || p->pParse->nErr>0 );
if( p->nOp ){
assert( p->aOp );
sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
@@ -71514,7 +79156,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
** is readable but not writable, though it is cast to a writable value.
** The return of a dummy opcode allows the call to continue functioning
-** after an OOM fault without having to check to see if the return from
+** after an OOM fault without having to check to see if the return from
** this routine is a valid pointer. But because the dummy.opcode is 0,
** dummy will never be written to. This is verified by code inspection and
** by running with Valgrind.
@@ -71561,17 +79203,19 @@ static int translateP(char c, const Op *pOp){
** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
*/
-static int displayComment(
+SQLITE_PRIVATE char *sqlite3VdbeDisplayComment(
+ sqlite3 *db, /* Optional - Oom error reporting only */
const Op *pOp, /* The opcode to be commented */
- const char *zP4, /* Previously obtained value for P4 */
- char *zTemp, /* Write result here */
- int nTemp /* Space available in zTemp[] */
+ const char *zP4 /* Previously obtained value for P4 */
){
const char *zOpName;
const char *zSynopsis;
int nOpName;
- int ii, jj;
+ int ii;
char zAlt[50];
+ StrAccum x;
+
+ sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
zOpName = sqlite3OpcodeName(pOp->opcode);
nOpName = sqlite3Strlen30(zOpName);
if( zOpName[nOpName+1] ){
@@ -71586,53 +79230,64 @@ static int displayComment(
}
zSynopsis = zAlt;
}
- for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){
+ for(ii=0; (c = zSynopsis[ii])!=0; ii++){
if( c=='P' ){
c = zSynopsis[++ii];
if( c=='4' ){
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", zP4);
+ sqlite3_str_appendall(&x, zP4);
}else if( c=='X' ){
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", pOp->zComment);
+ sqlite3_str_appendall(&x, pOp->zComment);
seenCom = 1;
}else{
int v1 = translateP(c, pOp);
int v2;
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
ii += 3;
- jj += sqlite3Strlen30(zTemp+jj);
v2 = translateP(zSynopsis[ii], pOp);
if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
ii += 2;
v2++;
}
- if( v2>1 ){
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
+ if( v2<2 ){
+ sqlite3_str_appendf(&x, "%d", v1);
+ }else{
+ sqlite3_str_appendf(&x, "%d..%d", v1, v1+v2-1);
+ }
+ }else if( strncmp(zSynopsis+ii+1, "@NP", 3)==0 ){
+ sqlite3_context *pCtx = pOp->p4.pCtx;
+ if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){
+ sqlite3_str_appendf(&x, "%d", v1);
+ }else if( pCtx->argc>1 ){
+ sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
+ }else{
+ assert( x.nChar>2 );
+ x.nChar -= 2;
+ ii++;
+ }
+ ii += 3;
+ }else{
+ sqlite3_str_appendf(&x, "%d", v1);
+ if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
+ ii += 4;
}
- }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
- ii += 4;
}
}
- jj += sqlite3Strlen30(zTemp+jj);
}else{
- zTemp[jj++] = c;
+ sqlite3_str_appendchar(&x, 1, c);
}
}
- if( !seenCom && jj<nTemp-5 && pOp->zComment ){
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "; %s", pOp->zComment);
- jj += sqlite3Strlen30(zTemp+jj);
+ if( !seenCom && pOp->zComment ){
+ sqlite3_str_appendf(&x, "; %s", pOp->zComment);
}
- if( jj<nTemp ) zTemp[jj] = 0;
}else if( pOp->zComment ){
- sqlite3_snprintf(nTemp, zTemp, "%s", pOp->zComment);
- jj = sqlite3Strlen30(zTemp);
- }else{
- zTemp[0] = 0;
- jj = 0;
+ sqlite3_str_appendall(&x, pOp->zComment);
}
- return jj;
+ if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){
+ sqlite3OomFault(db);
+ }
+ return sqlite3StrAccumFinish(&x);
}
-#endif /* SQLITE_DEBUG */
+#endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */
#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
/*
@@ -71643,23 +79298,23 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
const char *zOp = 0;
switch( pExpr->op ){
case TK_STRING:
- sqlite3XPrintf(p, "%Q", pExpr->u.zToken);
+ sqlite3_str_appendf(p, "%Q", pExpr->u.zToken);
break;
case TK_INTEGER:
- sqlite3XPrintf(p, "%d", pExpr->u.iValue);
+ sqlite3_str_appendf(p, "%d", pExpr->u.iValue);
break;
case TK_NULL:
- sqlite3XPrintf(p, "NULL");
+ sqlite3_str_appendf(p, "NULL");
break;
case TK_REGISTER: {
- sqlite3XPrintf(p, "r[%d]", pExpr->iTable);
+ sqlite3_str_appendf(p, "r[%d]", pExpr->iTable);
break;
}
case TK_COLUMN: {
if( pExpr->iColumn<0 ){
- sqlite3XPrintf(p, "rowid");
+ sqlite3_str_appendf(p, "rowid");
}else{
- sqlite3XPrintf(p, "c%d", (int)pExpr->iColumn);
+ sqlite3_str_appendf(p, "c%d", (int)pExpr->iColumn);
}
break;
}
@@ -71691,18 +79346,18 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
case TK_NOTNULL: zOp = "NOTNULL"; break;
default:
- sqlite3XPrintf(p, "%s", "expr");
+ sqlite3_str_appendf(p, "%s", "expr");
break;
}
if( zOp ){
- sqlite3XPrintf(p, "%s(", zOp);
+ sqlite3_str_appendf(p, "%s(", zOp);
displayP4Expr(p, pExpr->pLeft);
if( pExpr->pRight ){
- sqlite3StrAccumAppend(p, ",", 1);
+ sqlite3_str_append(p, ",", 1);
displayP4Expr(p, pExpr->pRight);
}
- sqlite3StrAccumAppend(p, ")", 1);
+ sqlite3_str_append(p, ")", 1);
}
}
#endif /* VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS) */
@@ -71713,24 +79368,27 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
** Compute a string that describes the P4 parameter for an opcode.
** Use zTemp for any required temporary buffer space.
*/
-static char *displayP4(Op *pOp, char *zTemp, int nTemp){
- char *zP4 = zTemp;
+SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
+ char *zP4 = 0;
StrAccum x;
- assert( nTemp>=20 );
- sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
+
+ sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
switch( pOp->p4type ){
case P4_KEYINFO: {
int j;
KeyInfo *pKeyInfo = pOp->p4.pKeyInfo;
- assert( pKeyInfo->aSortOrder!=0 );
- sqlite3XPrintf(&x, "k(%d", pKeyInfo->nField);
- for(j=0; j<pKeyInfo->nField; j++){
+ assert( pKeyInfo->aSortFlags!=0 );
+ sqlite3_str_appendf(&x, "k(%d", pKeyInfo->nKeyField);
+ for(j=0; j<pKeyInfo->nKeyField; j++){
CollSeq *pColl = pKeyInfo->aColl[j];
const char *zColl = pColl ? pColl->zName : "";
if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
- sqlite3XPrintf(&x, ",%s%s", pKeyInfo->aSortOrder[j] ? "-" : "", zColl);
+ sqlite3_str_appendf(&x, ",%s%s%s",
+ (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "",
+ (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "",
+ zColl);
}
- sqlite3StrAccumAppend(&x, ")", 1);
+ sqlite3_str_append(&x, ")", 1);
break;
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -71740,42 +79398,43 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
}
#endif
case P4_COLLSEQ: {
+ static const char *const encnames[] = {"?", "8", "16LE", "16BE"};
CollSeq *pColl = pOp->p4.pColl;
- sqlite3XPrintf(&x, "(%.20s)", pColl->zName);
+ assert( pColl->enc>=0 && pColl->enc<4 );
+ sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName,
+ encnames[pColl->enc]);
break;
}
case P4_FUNCDEF: {
FuncDef *pDef = pOp->p4.pFunc;
- sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
+ sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#ifdef SQLITE_DEBUG
case P4_FUNCCTX: {
FuncDef *pDef = pOp->p4.pCtx->pFunc;
- sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
+ sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#endif
case P4_INT64: {
- sqlite3XPrintf(&x, "%lld", *pOp->p4.pI64);
+ sqlite3_str_appendf(&x, "%lld", *pOp->p4.pI64);
break;
}
case P4_INT32: {
- sqlite3XPrintf(&x, "%d", pOp->p4.i);
+ sqlite3_str_appendf(&x, "%d", pOp->p4.i);
break;
}
case P4_REAL: {
- sqlite3XPrintf(&x, "%.16g", *pOp->p4.pReal);
+ sqlite3_str_appendf(&x, "%.16g", *pOp->p4.pReal);
break;
}
case P4_MEM: {
Mem *pMem = pOp->p4.pMem;
if( pMem->flags & MEM_Str ){
zP4 = pMem->z;
- }else if( pMem->flags & MEM_Int ){
- sqlite3XPrintf(&x, "%lld", pMem->u.i);
+ }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){
+ sqlite3_str_appendf(&x, "%lld", pMem->u.i);
}else if( pMem->flags & MEM_Real ){
- sqlite3XPrintf(&x, "%.16g", pMem->u.r);
+ sqlite3_str_appendf(&x, "%.16g", pMem->u.r);
}else if( pMem->flags & MEM_Null ){
zP4 = "NULL";
}else{
@@ -71787,45 +79446,42 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
#ifndef SQLITE_OMIT_VIRTUALTABLE
case P4_VTAB: {
sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab;
- sqlite3XPrintf(&x, "vtab:%p", pVtab);
+ sqlite3_str_appendf(&x, "vtab:%p", pVtab);
break;
}
#endif
case P4_INTARRAY: {
- int i;
- int *ai = pOp->p4.ai;
- int n = ai[0]; /* The first element of an INTARRAY is always the
+ u32 i;
+ u32 *ai = pOp->p4.ai;
+ u32 n = ai[0]; /* The first element of an INTARRAY is always the
** count of the number of elements to follow */
- for(i=1; i<n; i++){
- sqlite3XPrintf(&x, ",%d", ai[i]);
+ for(i=1; i<=n; i++){
+ sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]);
}
- zTemp[0] = '[';
- sqlite3StrAccumAppend(&x, "]", 1);
+ sqlite3_str_append(&x, "]", 1);
break;
}
case P4_SUBPROGRAM: {
- sqlite3XPrintf(&x, "program");
+ zP4 = "program";
break;
}
+ case P4_DYNBLOB:
case P4_ADVANCE: {
- zTemp[0] = 0;
break;
}
case P4_TABLE: {
- sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
+ zP4 = pOp->p4.pTab->zName;
break;
}
default: {
zP4 = pOp->p4.z;
- if( zP4==0 ){
- zP4 = zTemp;
- zTemp[0] = 0;
- }
}
}
- sqlite3StrAccumFinish(&x);
- assert( zP4!=0 );
- return zP4;
+ if( zP4 ) sqlite3_str_appendall(&x, zP4);
+ if( (x.accError & SQLITE_NOMEM)!=0 ){
+ sqlite3OomFault(db);
+ }
+ return sqlite3StrAccumFinish(&x);
}
#endif /* VDBE_DISPLAY_P4 */
@@ -71856,13 +79512,13 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
**
** If SQLite is not threadsafe but does support shared-cache mode, then
** sqlite3BtreeEnter() is invoked to set the BtShared.db variables
-** of all of BtShared structures accessible via the database handle
+** of all of BtShared structures accessible via the database handle
** associated with the VM.
**
** If SQLite is not threadsafe and does not support shared-cache mode, this
** function is a no-op.
**
-** The p->btreeMask field is a bitmask of all btrees that the prepared
+** The p->btreeMask field is a bitmask of all btrees that the prepared
** statement p will ever use. Let N be the number of bits in p->btreeMask
** corresponding to btrees that use shared cache. Then the runtime of
** this routine is N*N. But as N is rarely more than 1, this should not
@@ -71913,26 +79569,32 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
/*
** Print a single opcode. This routine is used for debugging only.
*/
-SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
+SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
char *zP4;
- char zPtr[50];
- char zCom[100];
+ char *zCom;
+ sqlite3 dummyDb;
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
if( pOut==0 ) pOut = stdout;
- zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
+ sqlite3BeginBenignMalloc();
+ dummyDb.mallocFailed = 1;
+ zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- displayComment(pOp, zP4, zCom, sizeof(zCom));
+ zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
#else
- zCom[0] = 0;
+ zCom = 0;
#endif
/* NB: The sqlite3OpcodeName() function is implemented by code created
** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
** information from the vdbe.c source text */
- fprintf(pOut, zFormat1, pc,
- sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
- zCom
+ fprintf(pOut, zFormat1, pc,
+ sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3,
+ zP4 ? zP4 : "", pOp->p5,
+ zCom ? zCom : ""
);
fflush(pOut);
+ sqlite3_free(zP4);
+ sqlite3_free(zCom);
+ sqlite3EndBenignMalloc();
}
#endif
@@ -71969,25 +79631,24 @@ static void releaseMemArray(Mem *p, int N){
assert( sqlite3VdbeCheckMemInvariants(p) );
/* This block is really an inlined version of sqlite3VdbeMemRelease()
- ** that takes advantage of the fact that the memory cell value is
+ ** that takes advantage of the fact that the memory cell value is
** being set to NULL after releasing any dynamic resources.
**
- ** The justification for duplicating code is that according to
- ** callgrind, this causes a certain test case to hit the CPU 4.7
- ** percent less (x86 linux, gcc version 4.1.2, -O6) than if
+ ** The justification for duplicating code is that according to
+ ** callgrind, this causes a certain test case to hit the CPU 4.7
+ ** percent less (x86 linux, gcc version 4.1.2, -O6) than if
** sqlite3MemRelease() were called from here. With -O2, this jumps
- ** to 6.6 percent. The test case is inserting 1000 rows into a table
- ** with no indexes using a single prepared INSERT statement, bind()
+ ** to 6.6 percent. The test case is inserting 1000 rows into a table
+ ** with no indexes using a single prepared INSERT statement, bind()
** and reset(). Inserts are grouped into a transaction.
*/
testcase( p->flags & MEM_Agg );
testcase( p->flags & MEM_Dyn );
- testcase( p->flags & MEM_Frame );
- testcase( p->flags & MEM_RowSet );
- if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){
+ testcase( p->xDel==sqlite3VdbeFrameMemDel );
+ if( p->flags&(MEM_Agg|MEM_Dyn) ){
sqlite3VdbeMemRelease(p);
}else if( p->szMalloc ){
- sqlite3DbFree(db, p->zMalloc);
+ sqlite3DbFreeNN(db, p->zMalloc);
p->szMalloc = 0;
}
@@ -71996,6 +79657,150 @@ static void releaseMemArray(Mem *p, int N){
}
}
+#ifdef SQLITE_DEBUG
+/*
+** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is
+** and false if something is wrong.
+**
+** This routine is intended for use inside of assert() statements only.
+*/
+SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){
+ if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0;
+ return 1;
+}
+#endif
+
+
+/*
+** This is a destructor on a Mem object (which is really an sqlite3_value)
+** that deletes the Frame object that is attached to it as a blob.
+**
+** This routine does not delete the Frame right away. It merely adds the
+** frame to a list of frames to be deleted when the Vdbe halts.
+*/
+SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void *pArg){
+ VdbeFrame *pFrame = (VdbeFrame*)pArg;
+ assert( sqlite3VdbeFrameIsValid(pFrame) );
+ pFrame->pParent = pFrame->v->pDelFrame;
+ pFrame->v->pDelFrame = pFrame;
+}
+
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN)
+/*
+** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN
+** QUERY PLAN output.
+**
+** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no
+** more opcodes to be displayed.
+*/
+SQLITE_PRIVATE int sqlite3VdbeNextOpcode(
+ Vdbe *p, /* The statement being explained */
+ Mem *pSub, /* Storage for keeping track of subprogram nesting */
+ int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */
+ int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */
+ int *piAddr, /* OUT: Write index into (*paOp)[] here */
+ Op **paOp /* OUT: Write the opcode array here */
+){
+ int nRow; /* Stop when row count reaches this */
+ int nSub = 0; /* Number of sub-vdbes seen so far */
+ SubProgram **apSub = 0; /* Array of sub-vdbes */
+ int i; /* Next instruction address */
+ int rc = SQLITE_OK; /* Result code */
+ Op *aOp = 0; /* Opcode array */
+ int iPc; /* Rowid. Copy of value in *piPc */
+
+ /* When the number of output rows reaches nRow, that means the
+ ** listing has finished and sqlite3_step() should return SQLITE_DONE.
+ ** nRow is the sum of the number of rows in the main program, plus
+ ** the sum of the number of rows in all trigger subprograms encountered
+ ** so far. The nRow value will increase as new trigger subprograms are
+ ** encountered, but p->pc will eventually catch up to nRow.
+ */
+ nRow = p->nOp;
+ if( pSub!=0 ){
+ if( pSub->flags&MEM_Blob ){
+ /* pSub is initiallly NULL. It is initialized to a BLOB by
+ ** the P4_SUBPROGRAM processing logic below */
+ nSub = pSub->n/sizeof(Vdbe*);
+ apSub = (SubProgram **)pSub->z;
+ }
+ for(i=0; i<nSub; i++){
+ nRow += apSub[i]->nOp;
+ }
+ }
+ iPc = *piPc;
+ while(1){ /* Loop exits via break */
+ i = iPc++;
+ if( i>=nRow ){
+ p->rc = SQLITE_OK;
+ rc = SQLITE_DONE;
+ break;
+ }
+ if( i<p->nOp ){
+ /* The rowid is small enough that we are still in the
+ ** main program. */
+ aOp = p->aOp;
+ }else{
+ /* We are currently listing subprograms. Figure out which one and
+ ** pick up the appropriate opcode. */
+ int j;
+ i -= p->nOp;
+ assert( apSub!=0 );
+ assert( nSub>0 );
+ for(j=0; i>=apSub[j]->nOp; j++){
+ i -= apSub[j]->nOp;
+ assert( i<apSub[j]->nOp || j+1<nSub );
+ }
+ aOp = apSub[j]->aOp;
+ }
+
+ /* When an OP_Program opcode is encounter (the only opcode that has
+ ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
+ ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
+ ** has not already been seen.
+ */
+ if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){
+ int nByte = (nSub+1)*sizeof(SubProgram*);
+ int j;
+ for(j=0; j<nSub; j++){
+ if( apSub[j]==aOp[i].p4.pProgram ) break;
+ }
+ if( j==nSub ){
+ p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ break;
+ }
+ apSub = (SubProgram **)pSub->z;
+ apSub[nSub++] = aOp[i].p4.pProgram;
+ MemSetTypeFlag(pSub, MEM_Blob);
+ pSub->n = nSub*sizeof(SubProgram*);
+ nRow += aOp[i].p4.pProgram->nOp;
+ }
+ }
+ if( eMode==0 ) break;
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
+ if( eMode==2 ){
+ Op *pOp = aOp + i;
+ if( pOp->opcode==OP_OpenRead ) break;
+ if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break;
+ if( pOp->opcode==OP_ReopenIdx ) break;
+ }else
+#endif
+ {
+ assert( eMode==1 );
+ if( aOp[i].opcode==OP_Explain ) break;
+ if( aOp[i].opcode==OP_Init && iPc>1 ) break;
+ }
+ }
+ *piPc = iPc;
+ *piAddr = i;
+ *paOp = aOp;
+ return rc;
+}
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */
+
+
/*
** Delete a VdbeFrame object and its contents. VdbeFrame objects are
** allocated by the OP_Program opcode in sqlite3VdbeExec().
@@ -72004,6 +79809,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
int i;
Mem *aMem = VdbeFrameMem(p);
VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem];
+ assert( sqlite3VdbeFrameIsValid(p) );
for(i=0; i<p->nChildCsr; i++){
sqlite3VdbeFreeCursor(p->v, apCsr[i]);
}
@@ -72024,6 +79830,9 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
** p->explain==2, only OP_Explain instructions are listed and these
** are shown in a different format. p->explain==2 is used to implement
** EXPLAIN QUERY PLAN.
+** 2018-04-24: In p->explain==2 mode, the OP_Init opcodes of triggers
+** are also shown, so that the boundaries between the main program and
+** each trigger are clear.
**
** When p->explain==1, first the main program is listed, then each of
** the trigger subprograms are listed one by one.
@@ -72031,14 +79840,14 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
SQLITE_PRIVATE int sqlite3VdbeList(
Vdbe *p /* The VDBE */
){
- int nRow; /* Stop when row count reaches this */
- int nSub = 0; /* Number of sub-vdbes seen so far */
- SubProgram **apSub = 0; /* Array of sub-vdbes */
Mem *pSub = 0; /* Memory cell hold array of subprogs */
sqlite3 *db = p->db; /* The database connection */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
+ int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
+ Op *aOp; /* Array of opcodes */
+ Op *pOp; /* Current opcode */
assert( p->explain );
assert( p->magic==VDBE_MAGIC_RUN );
@@ -72051,154 +79860,70 @@ SQLITE_PRIVATE int sqlite3VdbeList(
releaseMemArray(pMem, 8);
p->pResultSet = 0;
- if( p->rc==SQLITE_NOMEM_BKPT ){
+ if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
sqlite3OomFault(db);
return SQLITE_ERROR;
}
- /* When the number of output rows reaches nRow, that means the
- ** listing has finished and sqlite3_step() should return SQLITE_DONE.
- ** nRow is the sum of the number of rows in the main program, plus
- ** the sum of the number of rows in all trigger subprograms encountered
- ** so far. The nRow value will increase as new trigger subprograms are
- ** encountered, but p->pc will eventually catch up to nRow.
- */
- nRow = p->nOp;
- if( p->explain==1 ){
+ if( bListSubprogs ){
/* The first 8 memory cells are used for the result set. So we will
** commandeer the 9th cell to use as storage for an array of pointers
** to trigger subprograms. The VDBE is guaranteed to have at least 9
** cells. */
assert( p->nMem>9 );
pSub = &p->aMem[9];
- if( pSub->flags&MEM_Blob ){
- /* On the first call to sqlite3_step(), pSub will hold a NULL. It is
- ** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
- nSub = pSub->n/sizeof(Vdbe*);
- apSub = (SubProgram **)pSub->z;
- }
- for(i=0; i<nSub; i++){
- nRow += apSub[i]->nOp;
- }
- }
-
- do{
- i = p->pc++;
- }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
- if( i>=nRow ){
- p->rc = SQLITE_OK;
- rc = SQLITE_DONE;
- }else if( db->u1.isInterrupted ){
- p->rc = SQLITE_INTERRUPT;
- rc = SQLITE_ERROR;
- sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
}else{
- char *zP4;
- Op *pOp;
- if( i<p->nOp ){
- /* The output line number is small enough that we are still in the
- ** main program. */
- pOp = &p->aOp[i];
- }else{
- /* We are currently listing subprograms. Figure out which one and
- ** pick up the appropriate opcode. */
- int j;
- i -= p->nOp;
- for(j=0; i>=apSub[j]->nOp; j++){
- i -= apSub[j]->nOp;
- }
- pOp = &apSub[j]->aOp[i];
- }
- if( p->explain==1 ){
- pMem->flags = MEM_Int;
- pMem->u.i = i; /* Program counter */
- pMem++;
-
- pMem->flags = MEM_Static|MEM_Str|MEM_Term;
- pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
- assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30(pMem->z);
- pMem->enc = SQLITE_UTF8;
- pMem++;
-
- /* When an OP_Program opcode is encounter (the only opcode that has
- ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
- ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
- ** has not already been seen.
- */
- if( pOp->p4type==P4_SUBPROGRAM ){
- int nByte = (nSub+1)*sizeof(SubProgram*);
- int j;
- for(j=0; j<nSub; j++){
- if( apSub[j]==pOp->p4.pProgram ) break;
- }
- if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
- apSub = (SubProgram **)pSub->z;
- apSub[nSub++] = pOp->p4.pProgram;
- pSub->flags |= MEM_Blob;
- pSub->n = nSub*sizeof(SubProgram*);
- }
- }
- }
-
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p1; /* P1 */
- pMem++;
-
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p2; /* P2 */
- pMem++;
-
- pMem->flags = MEM_Int;
- pMem->u.i = pOp->p3; /* P3 */
- pMem++;
+ pSub = 0;
+ }
- if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
- if( zP4!=pMem->z ){
- pMem->n = 0;
- sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
- }else{
- assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30(pMem->z);
- pMem->enc = SQLITE_UTF8;
- }
- pMem++;
+ /* Figure out which opcode is next to display */
+ rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp);
- if( p->explain==1 ){
- if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- pMem->n = 2;
- sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
- pMem->enc = SQLITE_UTF8;
- pMem++;
-
+ if( rc==SQLITE_OK ){
+ pOp = aOp + i;
+ if( AtomicLoad(&db->u1.isInterrupted) ){
+ p->rc = SQLITE_INTERRUPT;
+ rc = SQLITE_ERROR;
+ sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
+ }else{
+ char *zP4 = sqlite3VdbeDisplayP4(db, pOp);
+ if( p->explain==2 ){
+ sqlite3VdbeMemSetInt64(pMem, pOp->p1);
+ sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
+ sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
+ sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);
+ p->nResColumn = 4;
+ }else{
+ sqlite3VdbeMemSetInt64(pMem+0, i);
+ sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),
+ -1, SQLITE_UTF8, SQLITE_STATIC);
+ sqlite3VdbeMemSetInt64(pMem+2, pOp->p1);
+ sqlite3VdbeMemSetInt64(pMem+3, pOp->p2);
+ sqlite3VdbeMemSetInt64(pMem+4, pOp->p3);
+ /* pMem+5 for p4 is done last */
+ sqlite3VdbeMemSetInt64(pMem+6, pOp->p5);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
- if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
- assert( p->db->mallocFailed );
- return SQLITE_ERROR;
- }
- pMem->flags = MEM_Str|MEM_Term;
- pMem->n = displayComment(pOp, zP4, pMem->z, 500);
- pMem->enc = SQLITE_UTF8;
+ {
+ char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4);
+ sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free);
+ }
#else
- pMem->flags = MEM_Null; /* Comment */
+ sqlite3VdbeMemSetNull(pMem+7);
#endif
+ sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
+ p->nResColumn = 8;
+ }
+ p->pResultSet = pMem;
+ if( db->mallocFailed ){
+ p->rc = SQLITE_NOMEM;
+ rc = SQLITE_ERROR;
+ }else{
+ p->rc = SQLITE_OK;
+ rc = SQLITE_ROW;
+ }
}
-
- p->nResColumn = 8 - 4*(p->explain-1);
- p->pResultSet = &p->aMem[1];
- p->rc = SQLITE_OK;
- rc = SQLITE_ROW;
}
return rc;
}
@@ -72258,9 +79983,9 @@ SQLITE_PRIVATE void sqlite3VdbeIOTraceSql(Vdbe *p){
** of a ReusableSpace object by the allocSpace() routine below.
*/
struct ReusableSpace {
- u8 *pSpace; /* Available memory */
- int nFree; /* Bytes of available memory */
- int nNeeded; /* Total bytes that could not be allocated */
+ u8 *pSpace; /* Available memory */
+ sqlite3_int64 nFree; /* Bytes of available memory */
+ sqlite3_int64 nNeeded; /* Total bytes that could not be allocated */
};
/* Try to allocate nByte bytes of 8-byte aligned bulk memory for pBuf
@@ -72280,7 +80005,7 @@ struct ReusableSpace {
static void *allocSpace(
struct ReusableSpace *p, /* Bulk memory available for allocation */
void *pBuf, /* Pointer to a prior allocation */
- int nByte /* Bytes of memory needed */
+ sqlite3_int64 nByte /* Bytes of memory needed */
){
assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
if( pBuf==0 ){
@@ -72340,11 +80065,11 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
** creating the virtual machine. This involves things such
** as allocating registers and initializing the program counter.
** After the VDBE has be prepped, it can be executed by one or more
-** calls to sqlite3VdbeExec().
+** calls to sqlite3VdbeExec().
**
** This function may be called exactly once on each virtual machine.
** After this routine is called the VM has been "packaged" and is ready
-** to run. After this routine is called, further calls to
+** to run. After this routine is called, further 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
@@ -72376,7 +80101,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
nMem = pParse->nMem;
nCursor = pParse->nTab;
nArg = pParse->nMaxArg;
-
+
/* Each cursor uses a memory cell. The first cursor (cursor 0) can
** use aMem[0] which is not otherwise used by the VDBE program. Allocate
** space at the end of aMem[] for cursors 1 and greater.
@@ -72398,40 +80123,64 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
- if( pParse->explain && nMem<10 ){
- nMem = 10;
+ if( pParse->explain ){
+ static const char * const azColName[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
+ "id", "parent", "notused", "detail"
+ };
+ int iFirst, mx, i;
+ if( nMem<10 ) nMem = 10;
+ p->explain = pParse->explain;
+ if( pParse->explain==2 ){
+ sqlite3VdbeSetNumCols(p, 4);
+ iFirst = 8;
+ mx = 12;
+ }else{
+ sqlite3VdbeSetNumCols(p, 8);
+ iFirst = 0;
+ mx = 8;
+ }
+ for(i=iFirst; i<mx; i++){
+ sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME,
+ azColName[i], SQLITE_STATIC);
+ }
}
p->expired = 0;
/* Memory for registers, parameters, cursor, etc, is allocated in one or two
- ** passes. On the first pass, we try to reuse unused memory at the
+ ** passes. On the first pass, we try to reuse unused memory 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 remainder using a fresh memory allocation.
+ ** pass will fill in the remainder using a fresh memory allocation.
**
** This two-pass approach that reuses as much memory as possible from
** the leftover memory at the end of the opcode array. This can significantly
** reduce the amount of memory held by a prepared statement.
*/
- do {
- x.nNeeded = 0;
- p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
- p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
- p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
- p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
+ x.nNeeded = 0;
+ p->aMem = allocSpace(&x, 0, nMem*sizeof(Mem));
+ p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem));
+ p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*));
+ p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*));
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
+ p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64));
#endif
- if( x.nNeeded==0 ) break;
+ if( x.nNeeded ){
x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded);
x.nFree = x.nNeeded;
- }while( !db->mallocFailed );
+ if( !db->mallocFailed ){
+ p->aMem = allocSpace(&x, p->aMem, nMem*sizeof(Mem));
+ p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
+ p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
+ p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
+#endif
+ }
+ }
- p->nzVar = pParse->nzVar;
- p->azVar = pParse->azVar;
- pParse->nzVar = 0;
- pParse->azVar = 0;
- p->explain = pParse->explain;
+ p->pVList = pParse->pVList;
+ pParse->pVList = 0;
if( db->mallocFailed ){
p->nVar = 0;
p->nCursor = 0;
@@ -72451,22 +80200,22 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
}
/*
-** Close a VDBE cursor and release all the resources that cursor
+** Close a VDBE cursor and release all the resources that cursor
** happens to hold.
*/
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
- assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE );
+ assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlite3VdbeSorterClose(p->db, pCx);
break;
}
case CURTYPE_BTREE: {
- if( pCx->pBt ){
- sqlite3BtreeClose(pCx->pBt);
+ if( pCx->isEphemeral ){
+ if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
/* The pCx->pCursor will be close automatically, if it exists, by
** the call above. */
}else{
@@ -72533,7 +80282,7 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
/*
** Close all cursors.
**
-** Also release any dynamic memory held by the VM in the Vdbe.aMem memory
+** Also release any dynamic memory held by the VM in the Vdbe.aMem memory
** cell array. This is necessary as the memory cell array may contain
** pointers to VdbeFrame objects, which may in turn contain pointers to
** open cursors.
@@ -72563,44 +80312,24 @@ static void closeAllCursors(Vdbe *p){
}
/*
-** Clean up the VM after a single run.
-*/
-static void Cleanup(Vdbe *p){
- sqlite3 *db = p->db;
-
-#ifdef SQLITE_DEBUG
- /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
- ** Vdbe.aMem[] arrays have already been cleaned up. */
- int i;
- if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
- if( p->aMem ){
- for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
- }
-#endif
-
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
- p->pResultSet = 0;
-}
-
-/*
** Set the number of result columns that will be returned by this SQL
** statement. This is now set at compile time, rather than during
** execution of the vdbe program so that sqlite3_column_count() can
** be called on an SQL statement before sqlite3_step().
*/
SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
- Mem *pColName;
int n;
sqlite3 *db = p->db;
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqlite3DbFree(db, p->aColName);
+ if( p->nResColumn ){
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ sqlite3DbFree(db, p->aColName);
+ }
n = nResColumn*COLNAME_N;
p->nResColumn = (u16)nResColumn;
- p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
+ p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
- initMemArray(p->aColName, n, p->db, MEM_Null);
+ initMemArray(p->aColName, n, db, MEM_Null);
}
/*
@@ -72639,43 +80368,43 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
** A read or write transaction may or may not be active on database handle
** db. If a transaction is active, commit it. If there is a
** write-transaction spanning more than one database file, this routine
-** takes care of the master journal trickery.
+** takes care of the super-journal trickery.
*/
static int vdbeCommit(sqlite3 *db, Vdbe *p){
int i;
int nTrans = 0; /* Number of databases with an active write-transaction
** that are candidates for a two-phase commit using a
- ** master-journal */
+ ** super-journal */
int rc = SQLITE_OK;
int needXcommit = 0;
#ifdef SQLITE_OMIT_VIRTUALTABLE
- /* With this option, sqlite3VtabSync() is defined to be simply
- ** SQLITE_OK so p is not used.
+ /* With this option, sqlite3VtabSync() is defined to be simply
+ ** SQLITE_OK so p is not used.
*/
UNUSED_PARAMETER(p);
#endif
/* Before doing anything else, call the xSync() callback for any
** virtual module tables written in this transaction. This has to
- ** be done before determining whether a master journal file is
+ ** be done before determining whether a super-journal file is
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
rc = sqlite3VtabSync(db, p);
/* This loop determines (a) if the commit hook should be invoked and
- ** (b) how many database files have open write transactions, not
- ** including the temp database. (b) is important because if more than
- ** one database file has an open write transaction, a master journal
+ ** (b) how many database files have open write transactions, not
+ ** including the temp database. (b) is important because if more than
+ ** one database file has an open write transaction, a super-journal
** file is required for an atomic commit.
- */
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ */
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
- /* Whether or not a database might need a master journal depends upon
+ /* Whether or not a database might need a super-journal depends upon
** its journal mode (among other things). This matrix determines which
- ** journal modes use a master journal and which do not */
+ ** journal modes use a super-journal and which do not */
static const u8 aMJNeeded[] = {
/* DELETE */ 1,
/* PERSIST */ 1,
@@ -72690,7 +80419,8 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
pPager = sqlite3BtreePager(pBt);
if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
&& aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
- ){
+ && sqlite3PagerIsMemdb(pPager)==0
+ ){
assert( i!=1 );
nTrans++;
}
@@ -72712,11 +80442,11 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* The simple case - no more than one database file (not counting the
** TEMP database) has a transaction active. There is no need for the
- ** master-journal.
+ ** super-journal.
**
** If the return value of sqlite3BtreeGetFilename() is a zero length
- ** string, it means the main database is :memory: or a temp file. In
- ** that case we do not support atomic multi-file commits, so use the
+ ** string, it means the main database is :memory: or a temp file. In
+ ** that case we do not support atomic multi-file commits, so use the
** simple case then too.
*/
if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt))
@@ -72729,7 +80459,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
}
}
- /* Do the commit only if all databases successfully complete phase 1.
+ /* Do the commit only if all databases successfully complete phase 1.
** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
** IO error while deleting or truncating a journal file. It is unlikely,
** but could happen. In this case abandon processing and return the error.
@@ -72746,61 +80476,62 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
}
/* The complex case - There is a multi-file write-transaction active.
- ** This requires a master journal file to ensure the transaction is
+ ** This requires a super-journal file to ensure the transaction is
** committed atomically.
*/
#ifndef SQLITE_OMIT_DISKIO
else{
sqlite3_vfs *pVfs = db->pVfs;
- char *zMaster = 0; /* File-name for the master journal */
+ char *zSuper = 0; /* File-name for the super-journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
- sqlite3_file *pMaster = 0;
+ sqlite3_file *pSuperJrnl = 0;
i64 offset = 0;
int res;
int retryCount = 0;
int nMainFile;
- /* Select a master journal file name */
+ /* Select a super-journal file name */
nMainFile = sqlite3Strlen30(zMainFile);
- zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
- if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
+ zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0);
+ if( zSuper==0 ) return SQLITE_NOMEM_BKPT;
+ zSuper += 4;
do {
u32 iRandom;
if( retryCount ){
if( retryCount>100 ){
- sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
+ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper);
+ sqlite3OsDelete(pVfs, zSuper, 0);
break;
}else if( retryCount==1 ){
- sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster);
+ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper);
}
}
retryCount++;
sqlite3_randomness(sizeof(iRandom), &iRandom);
- sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
+ sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X",
(iRandom>>8)&0xffffff, iRandom&0xff);
- /* The antipenultimate character of the master journal name must
+ /* The antipenultimate character of the super-journal name must
** be "9" to avoid name collisions when using 8+3 filenames. */
- assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
- sqlite3FileSuffix3(zMainFile, zMaster);
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
+ assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' );
+ sqlite3FileSuffix3(zMainFile, zSuper);
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
}while( rc==SQLITE_OK && res );
if( rc==SQLITE_OK ){
- /* Open the master journal. */
- rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
+ /* Open the super-journal. */
+ rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
- SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0
+ SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0
);
}
if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, zMaster);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
-
+
/* Write the name of each database file in the transaction into the new
- ** master journal file. If an error occurs at this point close
- ** and delete the master journal file. All the individual journal files
- ** still have 'null' as the master journal pointer, so they will roll
+ ** super-journal file. If an error occurs at this point close
+ ** and delete the super-journal file. All the individual journal files
+ ** still have 'null' as the super-journal pointer, so they will roll
** back independently if a failure occurs.
*/
for(i=0; i<db->nDb; i++){
@@ -72811,59 +80542,59 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
continue; /* Ignore TEMP and :memory: databases */
}
assert( zFile[0]!=0 );
- rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
+ rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset);
offset += sqlite3Strlen30(zFile)+1;
if( rc!=SQLITE_OK ){
- sqlite3OsCloseFree(pMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
- sqlite3DbFree(db, zMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
+ sqlite3OsDelete(pVfs, zSuper, 0);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
}
}
- /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
+ /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device
** flag is set this is not required.
*/
- if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
- && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
+ if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL)
+ && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL))
){
- sqlite3OsCloseFree(pMaster);
- sqlite3OsDelete(pVfs, zMaster, 0);
- sqlite3DbFree(db, zMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
+ sqlite3OsDelete(pVfs, zSuper, 0);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
/* Sync all the db files involved in the transaction. The same call
- ** sets the master journal pointer in each individual journal. If
- ** an error occurs here, do not delete the master journal file.
+ ** sets the super-journal pointer in each individual journal. If
+ ** an error occurs here, do not delete the super-journal file.
**
** If the error occurs during the first call to
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
- ** master journal file will be orphaned. But we cannot delete it,
- ** in case the master journal file name was written into the journal
+ ** super-journal file will be orphaned. But we cannot delete it,
+ ** in case the super-journal file name was written into the journal
** file before the failure occurred.
*/
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
+ rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper);
}
}
- sqlite3OsCloseFree(pMaster);
+ sqlite3OsCloseFree(pSuperJrnl);
assert( rc!=SQLITE_BUSY );
if( rc!=SQLITE_OK ){
- sqlite3DbFree(db, zMaster);
+ sqlite3DbFree(db, zSuper-4);
return rc;
}
- /* Delete the master journal file. This commits the transaction. After
+ /* Delete the super-journal file. This commits the transaction. After
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
- sqlite3DbFree(db, zMaster);
- zMaster = 0;
+ rc = sqlite3OsDelete(pVfs, zSuper, 1);
+ sqlite3DbFree(db, zSuper-4);
+ zSuper = 0;
if( rc ){
return rc;
}
@@ -72877,7 +80608,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
*/
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
- for(i=0; i<db->nDb; i++){
+ for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
sqlite3BtreeCommitPhaseTwo(pBt, 1);
@@ -72893,7 +80624,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
return rc;
}
-/*
+/*
** This routine checks that the sqlite3.nVdbeActive count variable
** matches the number of vdbe's in the list sqlite3.pVdbe that are
** currently active. An assertion fails if the two counts do not match.
@@ -72929,82 +80660,81 @@ static void checkActiveVdbeCnt(sqlite3 *db){
** If the Vdbe passed as the first argument opened a statement-transaction,
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
-** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
+** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
** statement transaction is committed.
**
-** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
+** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
** Otherwise SQLITE_OK.
*/
-SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
+static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
sqlite3 *const db = p->db;
int rc = SQLITE_OK;
+ int i;
+ const int iSavepoint = p->iStatement-1;
- /* If p->iStatement is greater than zero, then this Vdbe opened a
- ** statement transaction that should be closed here. The only exception
- ** is that an IO error may have occurred, causing an emergency rollback.
- ** In this case (db->nStatement==0), and there is nothing to do.
- */
- if( db->nStatement && p->iStatement ){
- int i;
- const int iSavepoint = p->iStatement-1;
-
- assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
- assert( db->nStatement>0 );
- assert( p->iStatement==(db->nStatement+db->nSavepoint) );
-
- for(i=0; i<db->nDb; i++){
- int rc2 = SQLITE_OK;
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- if( eOp==SAVEPOINT_ROLLBACK ){
- rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
- }
- if( rc2==SQLITE_OK ){
- rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
- }
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }
- }
- db->nStatement--;
- p->iStatement = 0;
+ assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE);
+ assert( db->nStatement>0 );
+ assert( p->iStatement==(db->nStatement+db->nSavepoint) );
- if( rc==SQLITE_OK ){
+ for(i=0; i<db->nDb; i++){
+ int rc2 = SQLITE_OK;
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
if( eOp==SAVEPOINT_ROLLBACK ){
- rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint);
+ rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, iSavepoint);
+ }
+ if( rc2==SQLITE_OK ){
+ rc2 = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, iSavepoint);
}
if( rc==SQLITE_OK ){
- rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint);
+ rc = rc2;
}
}
+ }
+ db->nStatement--;
+ p->iStatement = 0;
- /* 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. */
+ if( rc==SQLITE_OK ){
if( eOp==SAVEPOINT_ROLLBACK ){
- db->nDeferredCons = p->nStmtDefCons;
- db->nDeferredImmCons = p->nStmtDefImmCons;
+ 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. */
+ if( eOp==SAVEPOINT_ROLLBACK ){
+ db->nDeferredCons = p->nStmtDefCons;
+ db->nDeferredImmCons = p->nStmtDefImmCons;
}
return rc;
}
+SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
+ if( p->db->nStatement && p->iStatement ){
+ return vdbeCloseStatement(p, eOp);
+ }
+ return SQLITE_OK;
+}
+
/*
-** This function is called when a transaction opened by the database
-** handle associated with the VM passed as an argument is about to be
+** This function is called when a transaction opened by the database
+** handle associated with the VM passed as an argument is about to be
** committed. If there are outstanding deferred foreign key constraint
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
**
-** If there are outstanding FK violations and this function returns
+** If there are outstanding FK violations and this function returns
** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
** and write an error message to it. Then return SQLITE_ERROR.
*/
#ifndef SQLITE_OMIT_FOREIGN_KEY
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
sqlite3 *db = p->db;
- if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
- || (!deferred && p->nFkConstraint>0)
+ if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
+ || (!deferred && p->nFkConstraint>0)
){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
@@ -73034,7 +80764,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
/* This function contains the logic that determines if a statement or
** transaction will be committed or rolled back as a result of the
- ** execution of this virtual machine.
+ ** execution of this virtual machine.
**
** If any of the following errors occur:
**
@@ -73048,13 +80778,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
** one, or the complete transaction if there is no statement transaction.
*/
+ if( p->magic!=VDBE_MAGIC_RUN ){
+ return SQLITE_OK;
+ }
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM_BKPT;
}
closeAllCursors(p);
- if( p->magic!=VDBE_MAGIC_RUN ){
- return SQLITE_OK;
- }
checkActiveVdbeCnt(db);
/* No commit or rollback needed if the program never started or if the
@@ -73072,16 +80802,16 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
if( isSpecialError ){
- /* If the query was read-only and the error code is SQLITE_INTERRUPT,
- ** no rollback is necessary. Otherwise, at least a savepoint
- ** transaction must be rolled back to restore the database to a
+ /* If the query was read-only and the error code is SQLITE_INTERRUPT,
+ ** no rollback is necessary. Otherwise, at least a savepoint
+ ** transaction must be rolled back to restore the database to a
** consistent state.
**
** Even if the statement is read-only, it is important to perform
- ** a statement or transaction rollback operation. If the error
+ ** a statement or transaction rollback operation. If the error
** occurred while writing to the journal, sub-journal or database
** file as part of an effort to free up cache space (see function
- ** pagerStress() in pager.c), the rollback is required to restore
+ ** pagerStress() in pager.c), the rollback is required to restore
** the pager to a consistent state.
*/
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
@@ -73100,19 +80830,19 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
/* Check for immediate foreign key violations. */
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
sqlite3VdbeCheckFk(p, 0);
}
-
- /* If the auto-commit flag is set and this is the only active writer
- ** VM, then we do either a commit or rollback of the current transaction.
+
+ /* If the auto-commit flag is set and this is the only active writer
+ ** VM, then we do either a commit or rollback of the current transaction.
**
- ** Note: This block also runs if one of the special errors handled
- ** above has occurred.
+ ** Note: This block also runs if one of the special errors handled
+ ** above has occurred.
*/
- if( !sqlite3VtabInSync(db)
- && db->autoCommit
- && db->nVdbeWrite==(p->readOnly==0)
+ if( !sqlite3VtabInSync(db)
+ && db->autoCommit
+ && db->nVdbeWrite==(p->readOnly==0)
){
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
rc = sqlite3VdbeCheckFk(p, 1);
@@ -73122,10 +80852,10 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
return SQLITE_ERROR;
}
rc = SQLITE_CONSTRAINT_FOREIGNKEY;
- }else{
- /* The auto-commit flag is true, the vdbe program was successful
+ }else{
+ /* The auto-commit flag is true, the vdbe program was successful
** or hit an 'OR FAIL' constraint and there are no deferred foreign
- ** key constraints to hold up the transaction. This means a commit
+ ** key constraints to hold up the transaction. This means a commit
** is required. */
rc = vdbeCommit(db, p);
}
@@ -73139,7 +80869,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}else{
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
- db->flags &= ~SQLITE_DeferFKs;
+ db->flags &= ~(u64)SQLITE_DeferFKs;
sqlite3CommitInternalChanges(db);
}
}else{
@@ -73159,7 +80889,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
p->nChange = 0;
}
}
-
+
/* If eStatementOp is non-zero, then a statement transaction needs to
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
** do so. If this operation returns an error, and the current statement
@@ -73180,9 +80910,9 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
p->nChange = 0;
}
}
-
+
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
- ** has been rolled back, update the database connection change-counter.
+ ** has been rolled back, update the database connection change-counter.
*/
if( p->changeCntOn ){
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
@@ -73213,7 +80943,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
}
/* If the auto-commit flag is set to true, then any locks that were held
- ** by connection db have now been released. Call sqlite3ConnectionUnlocked()
+ ** by connection db have now been released. Call sqlite3ConnectionUnlocked()
** to invoke any required unlock-notify callbacks.
*/
if( db->autoCommit ){
@@ -73235,7 +80965,7 @@ SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){
/*
** Copy the error code and error message belonging to the VDBE passed
-** as the first argument to its database handle (so that they will be
+** as the first argument to its database handle (so that they will be
** returned by calls to sqlite3_errcode() and sqlite3_errmsg()).
**
** This function does not clear the VDBE error code or message, just
@@ -73251,16 +80981,16 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
db->bBenignMalloc--;
- db->errCode = rc;
- }else{
- sqlite3Error(db, rc);
+ }else if( db->pErr ){
+ sqlite3ValueSetNull(db->pErr);
}
+ db->errCode = rc;
return rc;
}
#ifdef SQLITE_ENABLE_SQLLOG
/*
-** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run,
+** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run,
** invoke it.
*/
static void vdbeInvokeSqllog(Vdbe *v){
@@ -73291,6 +81021,10 @@ static void vdbeInvokeSqllog(Vdbe *v){
** VDBE_MAGIC_INIT.
*/
SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+ int i;
+#endif
+
sqlite3 *db;
db = p->db;
@@ -73300,16 +81034,18 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
*/
sqlite3VdbeHalt(p);
- /* If the VDBE has be run even partially, then transfer the error code
+ /* If the VDBE has been run even partially, then transfer the error code
** and error message from the VDBE into the main database structure. But
** if the VDBE has just been set to run but has not actually executed any
** instructions yet, leave the main database error information unchanged.
*/
if( p->pc>=0 ){
vdbeInvokeSqllog(p);
- sqlite3VdbeTransferError(p);
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
+ if( db->pErr || p->zErrMsg ){
+ sqlite3VdbeTransferError(p);
+ }else{
+ db->errCode = p->rc;
+ }
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
@@ -73317,13 +81053,26 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
** called), set the database error in this case as well.
*/
sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
- sqlite3DbFree(db, p->zErrMsg);
- p->zErrMsg = 0;
}
- /* Reclaim all memory used by the VDBE
+ /* Reset register contents and reclaim error message memory.
*/
- Cleanup(p);
+#ifdef SQLITE_DEBUG
+ /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
+ ** Vdbe.aMem[] arrays have already been cleaned up. */
+ if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
+ if( p->aMem ){
+ for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
+ }
+#endif
+ if( p->zErrMsg ){
+ sqlite3DbFree(db, p->zErrMsg);
+ p->zErrMsg = 0;
+ }
+ p->pResultSet = 0;
+#ifdef SQLITE_DEBUG
+ p->nWrite = 0;
+#endif
/* Save profiling information from this VDBE run.
*/
@@ -73331,7 +81080,6 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
{
FILE *out = fopen("vdbe_profile.out", "a");
if( out ){
- int i;
fprintf(out, "---- ");
for(i=0; i<p->nOp; i++){
fprintf(out, "%02x", p->aOp[i].opcode);
@@ -73361,11 +81109,10 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
}
}
#endif
- p->iCurrentTime = 0;
p->magic = VDBE_MAGIC_RESET;
return p->rc & db->errMask;
}
-
+
/*
** Clean up and delete a VDBE after execution. Return an integer which is
** the result code. Write any error message text into *pzErrMsg.
@@ -73386,8 +81133,8 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
** the first argument.
**
** Or, if iOp is greater than or equal to zero, then the destructor is
-** only invoked for those auxiliary data pointers created by the user
-** function invoked by the OP_Function opcode at instruction iOp of
+** only invoked for those auxiliary data pointers created by the user
+** function invoked by the OP_Function opcode at instruction iOp of
** VM pVdbe, and only then if:
**
** * the associated function parameter is the 32nd or later (counting
@@ -73400,16 +81147,18 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp,
while( *pp ){
AuxData *pAux = *pp;
if( (iOp<0)
- || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & MASKBIT32(pAux->iArg))))
+ || (pAux->iAuxOp==iOp
+ && pAux->iAuxArg>=0
+ && (pAux->iAuxArg>31 || !(mask & MASKBIT32(pAux->iAuxArg))))
){
- testcase( pAux->iArg==31 );
- if( pAux->xDelete ){
- pAux->xDelete(pAux->pAux);
+ testcase( pAux->iAuxArg==31 );
+ if( pAux->xDeleteAux ){
+ pAux->xDeleteAux(pAux->pAux);
}
- *pp = pAux->pNext;
+ *pp = pAux->pNextAux;
sqlite3DbFree(db, pAux);
}else{
- pp= &pAux->pNext;
+ pp= &pAux->pNextAux;
}
}
}
@@ -73424,7 +81173,6 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp,
*/
SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
- int i;
assert( p->db==0 || p->db==db );
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
for(pSub=p->pProgram; pSub; pSub=pNext){
@@ -73434,18 +81182,30 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
}
if( p->magic!=VDBE_MAGIC_INIT ){
releaseMemArray(p->aVar, p->nVar);
- for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
- sqlite3DbFree(db, p->azVar);
+ sqlite3DbFree(db, p->pVList);
sqlite3DbFree(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
+#ifdef SQLITE_ENABLE_NORMALIZE
+ sqlite3DbFree(db, p->zNormSql);
+ {
+ DblquoteStr *pThis, *pNext;
+ for(pThis=p->pDblStr; pThis; pThis=pNext){
+ pNext = pThis->pNextStr;
+ sqlite3DbFree(db, pThis);
+ }
+ }
+#endif
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- for(i=0; i<p->nScan; i++){
- sqlite3DbFree(db, p->aScan[i].zName);
+ {
+ int i;
+ for(i=0; i<p->nScan; i++){
+ sqlite3DbFree(db, p->aScan[i].zName);
+ }
+ sqlite3DbFree(db, p->aScan);
}
- sqlite3DbFree(db, p->aScan);
#endif
}
@@ -73455,7 +81215,7 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
sqlite3 *db;
- if( NEVER(p==0) ) return;
+ assert( p!=0 );
db = p->db;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3VdbeClearObject(db, p);
@@ -73470,7 +81230,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
}
p->magic = VDBE_MAGIC_DEAD;
p->db = 0;
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
/*
@@ -73478,7 +81238,7 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
** carried out. Seek the cursor now. If an error occurs, return
** the appropriate error code.
*/
-static int SQLITE_NOINLINE handleDeferredMoveto(VdbeCursor *p){
+SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
int res, rc;
#ifdef SQLITE_TEST
extern int sqlite3_search_count;
@@ -73540,21 +81300,20 @@ SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
** If the cursor is already pointing to the correct row and that row has
** not been deleted out from under the cursor, then this routine is a no-op.
*/
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
+SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, u32 *piCol){
VdbeCursor *p = *pp;
- if( p->eCurType==CURTYPE_BTREE ){
- if( p->deferredMoveto ){
- int iMap;
- if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
- *pp = p->pAltCursor;
- *piCol = iMap - 1;
- return SQLITE_OK;
- }
- return handleDeferredMoveto(p);
- }
- if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
- return handleMovedCursor(p);
+ assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
+ if( p->deferredMoveto ){
+ u32 iMap;
+ if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 && !p->nullRow ){
+ *pp = p->pAltCursor;
+ *piCol = iMap - 1;
+ return SQLITE_OK;
}
+ return sqlite3VdbeFinishMoveto(p);
+ }
+ if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
+ return handleMovedCursor(p);
}
return SQLITE_OK;
}
@@ -73601,8 +81360,17 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
** of SQLite will not understand those serial types.
*/
+#if 0 /* Inlined into the OP_MakeRecord opcode */
/*
** Return the serial-type for the value stored in pMem.
+**
+** This routine might convert a large MEM_IntReal value into MEM_Real.
+**
+** 2019-07-11: The primary user of this subroutine was the OP_MakeRecord
+** opcode in the byte-code engine. But by moving this routine in-line, we
+** can omit some redundant tests and make that opcode a lot faster. So
+** this routine is now only used by the STAT3 logic and STAT3 support has
+** ended. The code is kept here for historical reference only.
*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
int flags = pMem->flags;
@@ -73613,11 +81381,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
*pLen = 0;
return 0;
}
- if( flags&MEM_Int ){
+ if( flags&(MEM_Int|MEM_IntReal) ){
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00008000)<<32)-1)
i64 i = pMem->u.i;
u64 u;
+ testcase( flags & MEM_Int );
+ testcase( flags & MEM_IntReal );
if( i<0 ){
u = ~i;
}else{
@@ -73637,6 +81407,15 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
if( u<=2147483647 ){ *pLen = 4; return 4; }
if( u<=MAX_6BYTE ){ *pLen = 6; return 5; }
*pLen = 8;
+ if( flags&MEM_IntReal ){
+ /* If the value is IntReal and is going to take up 8 bytes to store
+ ** as an integer, then we might as well make it an 8-byte floating
+ ** point value */
+ pMem->u.r = (double)pMem->u.i;
+ pMem->flags &= ~MEM_IntReal;
+ pMem->flags |= MEM_Real;
+ return 7;
+ }
return 6;
}
if( flags&MEM_Real ){
@@ -73652,12 +81431,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
*pLen = n;
return ((n*2) + 12 + ((flags&MEM_Str)!=0));
}
+#endif /* inlined into OP_MakeRecord */
/*
** The sizes for serial types less than 128
*/
static const u8 sqlite3SmallTypeSizes[] = {
- /* 0 1 2 3 4 5 6 7 8 9 */
+ /* 0 1 2 3 4 5 6 7 8 9 */
/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0,
/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
/* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
@@ -73680,19 +81460,19 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
if( serial_type>=128 ){
return (serial_type-12)/2;
}else{
- assert( serial_type<12
+ assert( serial_type<12
|| sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 );
return sqlite3SmallTypeSizes[serial_type];
}
}
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
assert( serial_type<128 );
- return sqlite3SmallTypeSizes[serial_type];
+ return sqlite3SmallTypeSizes[serial_type];
}
/*
-** If we are on an architecture with mixed-endian floating
-** points (ex: ARM7) then swap the lower 4 bytes with the
+** If we are on an architecture with mixed-endian floating
+** points (ex: ARM7) then swap the lower 4 bytes with the
** upper 4 bytes. Return the result.
**
** For most architectures, this is a no-op.
@@ -73714,7 +81494,7 @@ SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
** (2007-08-30) Frank van Vugt has studied this problem closely
** and has send his findings to the SQLite developers. Frank
** writes that some Linux kernels offer floating point hardware
-** emulation that uses only 32-bit mantissas instead of a full
+** emulation that uses only 32-bit mantissas instead of a full
** 48-bits as required by the IEEE standard. (This is the
** CONFIG_FPE_FASTFPE option.) On such systems, floating point
** byte swapping becomes very complicated. To avoid problems,
@@ -73744,7 +81524,7 @@ static u64 floatSwap(u64 in){
#endif
/*
-** Write the serialized data blob for the value stored in pMem into
+** Write the serialized data blob for the value stored in pMem into
** buf. It is assumed that the caller has allocated sufficient space.
** Return the number of bytes written.
**
@@ -73755,7 +81535,7 @@ static u64 floatSwap(u64 in){
** Return the number of bytes actually written into buf[]. The number
** of bytes in the zero-filled tail is included in the return value only
** if those bytes were zeroed in buf[].
-*/
+*/
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
u32 len;
@@ -73809,8 +81589,8 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
** The few cases that require local variables are broken out into a separate
** routine so that in most cases the overhead of moving the stack pointer
** is avoided.
-*/
-static u32 SQLITE_NOINLINE serialGet(
+*/
+static u32 serialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
Mem *pMem /* Memory cell to write value into */
@@ -73842,7 +81622,7 @@ static u32 SQLITE_NOINLINE serialGet(
assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
swapMixedEndianFloat(x);
memcpy(&pMem->u.r, &x, sizeof(x));
- pMem->flags = sqlite3IsNaN(pMem->u.r) ? MEM_Null : MEM_Real;
+ pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
}
return 8;
}
@@ -73852,7 +81632,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
Mem *pMem /* Memory cell to write value into */
){
switch( serial_type ){
- case 10: /* Reserved for future use */
+ case 10: { /* Internal use only: NULL with virtual table
+ ** UPDATE no-change flag set */
+ pMem->flags = MEM_Null|MEM_Zero;
+ pMem->n = 0;
+ pMem->u.nZero = 0;
+ break;
+ }
case 11: /* Reserved for future use */
case 0: { /* Null */
/* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
@@ -73887,7 +81673,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
/* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
** twos-complement integer. */
pMem->u.i = FOUR_BYTE_INT(buf);
-#ifdef __HP_cc
+#ifdef __HP_cc
/* Work around a sign-extension bug in the HP compiler for HP/UX */
if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL;
#endif
@@ -73939,49 +81725,32 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
** The space is either allocated using sqlite3DbMallocRaw() or from within
** the unaligned buffer passed via the second and third arguments (presumably
** stack space). If the former, then *ppFree is set to a pointer that should
-** be eventually freed by the caller using sqlite3DbFree(). Or, if the
+** be eventually freed by the caller using sqlite3DbFree(). Or, if the
** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL
** before returning.
**
** If an OOM error occurs, NULL is returned.
*/
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
- KeyInfo *pKeyInfo, /* Description of the record */
- char *pSpace, /* Unaligned space available */
- int szSpace, /* Size of pSpace[] in bytes */
- char **ppFree /* OUT: Caller should free this pointer */
+ KeyInfo *pKeyInfo /* Description of the record */
){
UnpackedRecord *p; /* Unpacked record to return */
- int nOff; /* Increment pSpace by nOff to align it */
int nByte; /* Number of bytes required for *p */
-
- /* We want to shift the pointer pSpace up such that it is 8-byte aligned.
- ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift
- ** it by. If pSpace is already 8-byte aligned, nOff should be zero.
- */
- nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
- nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
- if( nByte>szSpace+nOff ){
- p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
- *ppFree = (char *)p;
- if( !p ) return 0;
- }else{
- p = (UnpackedRecord*)&pSpace[nOff];
- *ppFree = 0;
- }
-
+ nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
+ p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
+ if( !p ) return 0;
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
- assert( pKeyInfo->aSortOrder!=0 );
+ assert( pKeyInfo->aSortFlags!=0 );
p->pKeyInfo = pKeyInfo;
- p->nField = pKeyInfo->nField + 1;
+ p->nField = pKeyInfo->nKeyField + 1;
return p;
}
/*
-** Given the nKey-byte encoding of a record in pKey[], populate the
+** Given the nKey-byte encoding of a record in pKey[], populate the
** UnpackedRecord structure indicated by the fourth argument with the
** contents of the decoded record.
-*/
+*/
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
KeyInfo *pKeyInfo, /* Information about the record format */
int nKey, /* Size of the binary record */
@@ -73989,7 +81758,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
UnpackedRecord *p /* Populate this structure before returning. */
){
const unsigned char *aKey = (const unsigned char *)pKey;
- int d;
+ u32 d;
u32 idx; /* Offset in aKey[] to read from */
u16 u; /* Unsigned loop counter */
u32 szHdr;
@@ -74000,7 +81769,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
idx = getVarint32(aKey, szHdr);
d = szHdr;
u = 0;
- while( idx<szHdr && d<=nKey ){
+ while( idx<szHdr && d<=(u32)nKey ){
u32 serial_type;
idx += getVarint32(&aKey[idx], serial_type);
@@ -74013,11 +81782,18 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
pMem++;
if( (++u)>=p->nField ) break;
}
- assert( u<=pKeyInfo->nField + 1 );
+ if( d>(u32)nKey && u ){
+ assert( CORRUPT_DB );
+ /* In a corrupt record entry, the last pMem might have been set up using
+ ** uninitialized memory. Overwrite its value with NULL, to prevent
+ ** warnings from MSAN. */
+ sqlite3VdbeMemSetNull(pMem-1);
+ }
+ assert( u<=pKeyInfo->nKeyField + 1 );
p->nField = u;
}
-#if SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
/*
** This function compares two index or table record keys in the same way
** as the sqlite3VdbeRecordCompare() routine. Unlike VdbeRecordCompare(),
@@ -74052,19 +81828,19 @@ static int vdbeRecordCompareDebug(
/* 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 uninitialized, 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.
*/
/* mem1.u.i = 0; // not needed, here to silence compiler warning */
-
+
idx1 = getVarint32(aKey1, szHdr1);
if( szHdr1>98307 ) return SQLITE_CORRUPT;
d1 = szHdr1;
- assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
- assert( pKeyInfo->aSortOrder!=0 );
- assert( pKeyInfo->nField>0 );
+ assert( pKeyInfo->nAllField>=pPKey2->nField || CORRUPT_DB );
+ assert( pKeyInfo->aSortFlags!=0 );
+ assert( pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
do{
u32 serial_type1;
@@ -74078,8 +81854,8 @@ static int vdbeRecordCompareDebug(
** Use that approximation to avoid the more expensive call to
** sqlite3VdbeSerialTypeLen() in the common case.
*/
- if( d1+serial_type1+2>(u32)nKey1
- && d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1
+ if( d1+(u64)serial_type1+2>(u64)nKey1
+ && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
){
break;
}
@@ -74090,10 +81866,16 @@ static int vdbeRecordCompareDebug(
/* Do the comparison
*/
- rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]);
+ rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
+ pKeyInfo->nAllField>i ? pKeyInfo->aColl[i] : 0);
if( rc!=0 ){
assert( mem1.szMalloc==0 ); /* See comment below */
- if( pKeyInfo->aSortOrder[i] ){
+ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
+ && ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null))
+ ){
+ rc = -rc;
+ }
+ if( pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC ){
rc = -rc; /* Invert the result for DESC sort order. */
}
goto debugCompareEnd;
@@ -74122,20 +81904,20 @@ debugCompareEnd:
}
#endif
-#if SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
/*
** Count the number of fields (a.k.a. columns) in the record given by
** pKey,nKey. The verify that this count is less than or equal to the
-** limit given by pKeyInfo->nField + pKeyInfo->nXField.
+** limit given by pKeyInfo->nAllField.
**
** If this constraint is not satisfied, it means that the high-speed
** vdbeRecordCompareInt() and vdbeRecordCompareString() routines will
** not work correctly. If this assert() ever fires, it probably means
-** that the KeyInfo.nField or KeyInfo.nXField values were computed
+** that the KeyInfo.nKeyField or KeyInfo.nAllField values were computed
** incorrectly.
*/
static void vdbeAssertFieldCountWithinLimits(
- int nKey, const void *pKey, /* The record to verify */
+ int nKey, const void *pKey, /* The record to verify */
const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
){
int nField = 0;
@@ -74152,7 +81934,7 @@ static void vdbeAssertFieldCountWithinLimits(
idx += getVarint32(aKey+idx, notUsed);
nField++;
}
- assert( nField <= pKeyInfo->nField+pKeyInfo->nXField );
+ assert( nField <= pKeyInfo->nAllField );
}
#else
# define vdbeAssertFieldCountWithinLimits(A,B,C)
@@ -74161,7 +81943,7 @@ static void vdbeAssertFieldCountWithinLimits(
/*
** Both *pMem1 and *pMem2 contain string values. Compare the two values
** using the collation sequence pColl. As usual, return a negative , zero
-** or positive value if *pMem1 is less than, equal to or greater than
+** or positive value if *pMem1 is less than, equal to or greater than
** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
*/
static int vdbeCompareMemString(
@@ -74177,7 +81959,6 @@ static int vdbeCompareMemString(
}else{
int rc;
const void *v1, *v2;
- int n1, n2;
Mem c1;
Mem c2;
sqlite3VdbeMemInit(&c1, pMem1->db, MEM_Null);
@@ -74185,11 +81966,13 @@ static int vdbeCompareMemString(
sqlite3VdbeMemShallowCopy(&c1, pMem1, MEM_Ephem);
sqlite3VdbeMemShallowCopy(&c2, pMem2, MEM_Ephem);
v1 = sqlite3ValueText((sqlite3_value*)&c1, pColl->enc);
- n1 = v1==0 ? 0 : c1.n;
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
- n2 = v2==0 ? 0 : c2.n;
- rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
+ if( (v1==0 || v2==0) ){
+ if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
+ rc = 0;
+ }else{
+ rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
+ }
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
return rc;
@@ -74213,7 +81996,7 @@ static int isAllZero(const char *z, int n){
** is less than, equal to, or greater than the second, respectively.
** If one blob is a prefix of the other, then the shorter is the lessor.
*/
-static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
int c;
int n1 = pB1->n;
int n2 = pB2->n;
@@ -74256,13 +82039,10 @@ static int sqlite3IntFloatCompare(i64 i, double r){
i64 y;
double s;
if( r<-9223372036854775808.0 ) return +1;
- if( r>9223372036854775807.0 ) return -1;
+ if( r>=9223372036854775808.0 ) return -1;
y = (i64)r;
if( i<y ) return -1;
- if( i>y ){
- if( y==SMALLEST_INT64 && r>0.0 ) return -1;
- return +1;
- }
+ if( i>y ) return +1;
s = (double)i;
if( s<r ) return -1;
if( s>r ) return +1;
@@ -74286,8 +82066,8 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
f1 = pMem1->flags;
f2 = pMem2->flags;
combined_flags = f1|f2;
- assert( (combined_flags & MEM_RowSet)==0 );
-
+ assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) );
+
/* If one value is NULL, it is less than the other. If both values
** are NULL, return 0.
*/
@@ -74297,8 +82077,13 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
/* At least one of the two values is a number
*/
- if( combined_flags&(MEM_Int|MEM_Real) ){
- if( (f1 & f2 & MEM_Int)!=0 ){
+ if( combined_flags&(MEM_Int|MEM_Real|MEM_IntReal) ){
+ testcase( combined_flags & MEM_Int );
+ testcase( combined_flags & MEM_Real );
+ testcase( combined_flags & MEM_IntReal );
+ if( (f1 & f2 & (MEM_Int|MEM_IntReal))!=0 ){
+ testcase( f1 & f2 & MEM_Int );
+ testcase( f1 & f2 & MEM_IntReal );
if( pMem1->u.i < pMem2->u.i ) return -1;
if( pMem1->u.i > pMem2->u.i ) return +1;
return 0;
@@ -74308,15 +82093,23 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
if( pMem1->u.r > pMem2->u.r ) return +1;
return 0;
}
- if( (f1&MEM_Int)!=0 ){
+ if( (f1&(MEM_Int|MEM_IntReal))!=0 ){
+ testcase( f1 & MEM_Int );
+ testcase( f1 & MEM_IntReal );
if( (f2&MEM_Real)!=0 ){
return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r);
+ }else if( (f2&(MEM_Int|MEM_IntReal))!=0 ){
+ if( pMem1->u.i < pMem2->u.i ) return -1;
+ if( pMem1->u.i > pMem2->u.i ) return +1;
+ return 0;
}else{
return -1;
}
}
if( (f1&MEM_Real)!=0 ){
- if( (f2&MEM_Int)!=0 ){
+ if( (f2&(MEM_Int|MEM_IntReal))!=0 ){
+ testcase( f2 & MEM_Int );
+ testcase( f2 & MEM_IntReal );
return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r);
}else{
return -1;
@@ -74337,7 +82130,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
}
assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed );
- assert( pMem1->enc==SQLITE_UTF8 ||
+ assert( pMem1->enc==SQLITE_UTF8 ||
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
/* The collation sequence must be defined at this point, even if
@@ -74352,7 +82145,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
/* If a NULL pointer was passed as the collate function, fall through
** to the blob case and use memcmp(). */
}
-
+
/* Both values must be blobs. Compare using memcmp(). */
return sqlite3BlobCompare(pMem1, pMem2);
}
@@ -74360,7 +82153,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
/*
** The first argument passed to this function is a serial-type that
-** corresponds to an integer - all values between 1 and 9 inclusive
+** corresponds to an integer - all values between 1 and 9 inclusive
** except 7. The second points to a buffer containing an integer value
** serialized according to serial_type. This function deserializes
** and returns the value.
@@ -74402,7 +82195,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
/*
** This function compares the two table rows or index records
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
-** or positive integer if key1 is less than, equal to or
+** or positive integer if key1 is less than, equal to or
** greater than key2. The {nKey1, pKey1} key must be a blob
** created by the OP_MakeRecord opcode of the VDBE. The pPKey2
** key must be a parsed key such as obtained from
@@ -74411,12 +82204,12 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
** If argument bSkip is non-zero, it is assumed that the caller has already
** determined that the first fields of the keys are equal.
**
-** Key1 and Key2 do not have to contain the same number of fields. If all
-** fields that appear in both keys are equal, then pPKey2->default_rc is
+** Key1 and Key2 do not have to contain the same number of fields. If all
+** fields that appear in both keys are equal, then pPKey2->default_rc is
** returned.
**
-** If database corruption is discovered, set pPKey2->errCode to
-** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
+** If database corruption is discovered, set pPKey2->errCode to
+** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
*/
@@ -74431,7 +82224,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
u32 idx1; /* Offset of first type in header */
int rc = 0; /* Return value */
Mem *pRhs = pPKey2->aMem; /* Next field of pPKey2 to compare */
- KeyInfo *pKeyInfo = pPKey2->pKeyInfo;
+ KeyInfo *pKeyInfo;
const unsigned char *aKey1 = (const unsigned char *)pKey1;
Mem mem1;
@@ -74448,24 +82241,26 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
}else{
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
- if( d1>(unsigned)nKey1 ){
- pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
- return 0; /* Corruption */
- }
i = 0;
}
+ if( d1>(unsigned)nKey1 ){
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
+ return 0; /* Corruption */
+ }
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
- assert( pPKey2->pKeyInfo->nField+pPKey2->pKeyInfo->nXField>=pPKey2->nField
+ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|| CORRUPT_DB );
- assert( pPKey2->pKeyInfo->aSortOrder!=0 );
- assert( pPKey2->pKeyInfo->nField>0 );
+ assert( pPKey2->pKeyInfo->aSortFlags!=0 );
+ assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
do{
u32 serial_type;
/* RHS is an integer */
- if( pRhs->flags & MEM_Int ){
+ if( pRhs->flags & (MEM_Int|MEM_IntReal) ){
+ testcase( pRhs->flags & MEM_Int );
+ testcase( pRhs->flags & MEM_IntReal );
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
@@ -74491,7 +82286,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
serial_type = aKey1[idx1];
if( serial_type>=10 ){
/* Serial types 12 or greater are strings and blobs (greater than
- ** numbers). Types 10 and 11 are currently "reserved for future
+ ** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
** them to numberic values are. */
rc = +1;
@@ -74513,7 +82308,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is a string */
else if( pRhs->flags & MEM_Str ){
- getVarint32(&aKey1[idx1], serial_type);
+ getVarint32NR(&aKey1[idx1], serial_type);
testcase( serial_type==12 );
if( serial_type<12 ){
rc = -1;
@@ -74523,7 +82318,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
mem1.n = (serial_type - 12) / 2;
testcase( (d1+mem1.n)==(unsigned)nKey1 );
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
- if( (d1+mem1.n) > (unsigned)nKey1 ){
+ if( (d1+mem1.n) > (unsigned)nKey1
+ || (pKeyInfo = pPKey2->pKeyInfo)->nAllField<=i
+ ){
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else if( pKeyInfo->aColl[i] ){
@@ -74537,7 +82334,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
}else{
int nCmp = MIN(mem1.n, pRhs->n);
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
- if( rc==0 ) rc = mem1.n - pRhs->n;
+ if( rc==0 ) rc = mem1.n - pRhs->n;
}
}
}
@@ -74545,7 +82342,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is a blob */
else if( pRhs->flags & MEM_Blob ){
assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
- getVarint32(&aKey1[idx1], serial_type);
+ getVarint32NR(&aKey1[idx1], serial_type);
testcase( serial_type==12 );
if( serial_type<12 || (serial_type & 0x01) ){
rc = -1;
@@ -74577,8 +82374,14 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
}
if( rc!=0 ){
- if( pKeyInfo->aSortOrder[i] ){
- rc = -rc;
+ int sortFlags = pPKey2->pKeyInfo->aSortFlags[i];
+ if( sortFlags ){
+ if( (sortFlags & KEYINFO_ORDER_BIGNULL)==0
+ || ((sortFlags & KEYINFO_ORDER_DESC)
+ !=(serial_type==0 || (pRhs->flags&MEM_Null)))
+ ){
+ rc = -rc;
+ }
}
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
assert( mem1.szMalloc==0 ); /* See comment below */
@@ -74586,10 +82389,11 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
}
i++;
+ if( i==pPKey2->nField ) break;
pRhs++;
d1 += sqlite3VdbeSerialTypeLen(serial_type);
idx1 += sqlite3VarintLen(serial_type);
- }while( idx1<(unsigned)szHdr1 && i<pPKey2->nField && d1<=(unsigned)nKey1 );
+ }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 );
/* No memory allocation is ever used on mem1. Prove this using
** the following assert(). If the assert() fails, it indicates a
@@ -74599,9 +82403,9 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* rc==0 here means that one or both of the keys ran out of fields and
** all the fields up to that point were equal. Return the default_rc
** value. */
- assert( CORRUPT_DB
- || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
- || pKeyInfo->db->mallocFailed
+ assert( CORRUPT_DB
+ || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
+ || pPKey2->pKeyInfo->db->mallocFailed
);
pPKey2->eqSeen = 1;
return pPKey2->default_rc;
@@ -74615,8 +82419,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
/*
-** This function is an optimized version of sqlite3VdbeRecordCompare()
-** that (a) the first field of pPKey2 is an integer, and (b) the
+** This function is an optimized version of sqlite3VdbeRecordCompare()
+** that (a) the first field of pPKey2 is an integer, and (b) the
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
** byte (i.e. is less than 128).
**
@@ -74671,7 +82475,7 @@ static int vdbeRecordCompareInt(
testcase( lhs<0 );
break;
}
- case 8:
+ case 8:
lhs = 0;
break;
case 9:
@@ -74679,11 +82483,11 @@ static int vdbeRecordCompareInt(
break;
/* This case could be removed without changing the results of running
- ** this code. Including it causes gcc to generate a faster switch
+ ** this code. Including it causes gcc to generate a faster switch
** statement (since the range of switch targets now starts at zero and
** is contiguous) but does not cause any duplicate code to be generated
- ** (as gcc is clever enough to combine the two like cases). Other
- ** compilers might be similar. */
+ ** (as gcc is clever enough to combine the two like cases). Other
+ ** compilers might be similar. */
case 0: case 7:
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
@@ -74697,7 +82501,7 @@ static int vdbeRecordCompareInt(
}else if( v<lhs ){
res = pPKey2->r2;
}else if( pPKey2->nField>1 ){
- /* The first fields of the two keys are equal. Compare the trailing
+ /* The first fields of the two keys are equal. Compare the trailing
** fields. */
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
}else{
@@ -74712,9 +82516,9 @@ static int vdbeRecordCompareInt(
}
/*
-** This function is an optimized version of sqlite3VdbeRecordCompare()
+** This function is an optimized version of sqlite3VdbeRecordCompare()
** that (a) the first field of pPKey2 is a string, that (b) the first field
-** uses the collation sequence BINARY and (c) that the size-of-header varint
+** uses the collation sequence BINARY and (c) that the size-of-header varint
** at the start of (pKey1/nKey1) fits in a single byte.
*/
static int vdbeRecordCompareString(
@@ -74727,10 +82531,13 @@ static int vdbeRecordCompareString(
assert( pPKey2->aMem[0].flags & MEM_Str );
vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
- getVarint32(&aKey1[1], serial_type);
+ serial_type = (u8)(aKey1[1]);
+ if( serial_type >= 0x80 ){
+ sqlite3GetVarint32(&aKey1[1], (u32*)&serial_type);
+ }
if( serial_type<12 ){
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
- }else if( !(serial_type & 0x01) ){
+ }else if( !(serial_type & 0x01) ){
res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
}else{
int nCmp;
@@ -74745,7 +82552,11 @@ static int vdbeRecordCompareString(
nCmp = MIN( pPKey2->aMem[0].n, nStr );
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
- if( res==0 ){
+ if( res>0 ){
+ res = pPKey2->r2;
+ }else if( res<0 ){
+ res = pPKey2->r1;
+ }else{
res = nStr - pPKey2->aMem[0].n;
if( res==0 ){
if( pPKey2->nField>1 ){
@@ -74759,10 +82570,6 @@ static int vdbeRecordCompareString(
}else{
res = pPKey2->r1;
}
- }else if( res>0 ){
- res = pPKey2->r2;
- }else{
- res = pPKey2->r1;
}
}
@@ -74782,7 +82589,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
/* varintRecordCompareInt() and varintRecordCompareString() both assume
** that the size-of-header varint that occurs at the start of each record
** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt()
- ** also assumes that it is safe to overread a buffer by at least the
+ ** also assumes that it is safe to overread a buffer by at least the
** maximum possible legal header size plus 8 bytes. Because there is
** guaranteed to be at least 74 (but not 136) bytes of padding following each
** buffer passed to varintRecordCompareInt() this makes it convenient to
@@ -74792,9 +82599,12 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
** The easiest way to enforce this limit is to consider only records with
** 13 fields or less. If the first field is an integer, the maximum legal
** header size is (12*5 + 1 + 1) bytes. */
- if( (p->pKeyInfo->nField + p->pKeyInfo->nXField)<=13 ){
+ if( p->pKeyInfo->nAllField<=13 ){
int flags = p->aMem[0].flags;
- if( p->pKeyInfo->aSortOrder[0] ){
+ if( p->pKeyInfo->aSortFlags[0] ){
+ if( p->pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL ){
+ return sqlite3VdbeRecordCompare;
+ }
p->r1 = 1;
p->r2 = -1;
}else{
@@ -74807,7 +82617,9 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
testcase( flags & MEM_Real );
testcase( flags & MEM_Null );
testcase( flags & MEM_Blob );
- if( (flags & (MEM_Real|MEM_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){
+ if( (flags & (MEM_Real|MEM_IntReal|MEM_Null|MEM_Blob))==0
+ && p->pKeyInfo->aColl[0]==0
+ ){
assert( flags & MEM_Str );
return vdbeRecordCompareString;
}
@@ -74835,7 +82647,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
/* Get the size of the index entry. Only indices entries of less
** than 2GiB are support - anything large must be database corruption.
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
- ** this code can safely assume that nCellKey is 32-bits
+ ** this code can safely assume that nCellKey is 32-bits
*/
assert( sqlite3BtreeCursorIsValid(pCur) );
nCellKey = sqlite3BtreePayloadSize(pCur);
@@ -74843,22 +82655,24 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
/* Read in the complete content of the index entry */
sqlite3VdbeMemInit(&m, db, 0);
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
if( rc ){
return rc;
}
/* The index entry must begin with a header size */
- (void)getVarint32((u8*)m.z, szHdr);
+ getVarint32NR((u8*)m.z, szHdr);
testcase( szHdr==3 );
testcase( szHdr==m.n );
- if( unlikely(szHdr<3 || (int)szHdr>m.n) ){
+ testcase( szHdr>0x7fffffff );
+ assert( m.n>=0 );
+ if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
goto idx_rowid_corruption;
}
/* The last field of the index should be an integer - the ROWID.
** Verify that the last entry really is an integer. */
- (void)getVarint32((u8*)&m.z[szHdr-1], typeRowid);
+ getVarint32NR((u8*)&m.z[szHdr-1], typeRowid);
testcase( typeRowid==1 );
testcase( typeRowid==2 );
testcase( typeRowid==3 );
@@ -74898,7 +82712,7 @@ idx_rowid_corruption:
**
** pUnpacked is either created without a rowid or is truncated so that it
** omits the rowid at the end. The rowid at the end of the index entry
-** is ignored as well. Hence, this routine only compares the prefixes
+** is ignored as well. Hence, this routine only compares the prefixes
** of the keys prior to the final rowid, not the entire key.
*/
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
@@ -74923,18 +82737,18 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
return SQLITE_CORRUPT_BKPT;
}
sqlite3VdbeMemInit(&m, db, 0);
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
if( rc ){
return rc;
}
- *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
+ *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0);
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
}
/*
** This routine sets the value to be returned by subsequent calls to
-** sqlite3_changes() on the database handle 'db'.
+** sqlite3_changes() on the database handle 'db'.
*/
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
assert( sqlite3_mutex_held(db->mutex) );
@@ -74959,11 +82773,19 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){
** programs obsolete. Removing user-defined functions or collating
** sequences, or changing an authorization function are the types of
** things that make prepared statements obsolete.
+**
+** If iCode is 1, then expiration is advisory. The statement should
+** be reprepared before being restarted, but if it is already running
+** it is allowed to run to completion.
+**
+** Internally, this function just sets the Vdbe.expired flag on all
+** prepared statements. The flag is set to 1 for an immediate expiration
+** and set to 2 for an advisory expiration.
*/
-SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){
+SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
Vdbe *p;
for(p = db->pVdbe; p; p=p->pNext){
- p->expired = 1;
+ p->expired = iCode+1;
}
}
@@ -74975,8 +82797,15 @@ SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe *v){
}
/*
+** Return the SQLITE_PREPARE flags for a Vdbe.
+*/
+SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){
+ return v->prepFlags;
+}
+
+/*
** Return a pointer to an sqlite3_value structure containing the value bound
-** parameter iVar of VM v. Except, if the value is an SQL NULL, return
+** parameter iVar of VM v. Except, if the value is an SQL NULL, return
** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_*
** constants) to the value before returning it.
**
@@ -74986,6 +82815,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
assert( iVar>0 );
if( v ){
Mem *pMem = &v->aVar[iVar-1];
+ assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
if( 0==(pMem->flags & MEM_Null) ){
sqlite3_value *pRet = sqlite3ValueNew(v->db);
if( pRet ){
@@ -75005,13 +82835,48 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
*/
SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
assert( iVar>0 );
- if( iVar>32 ){
- v->expmask = 0xffffffff;
+ assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
+ if( iVar>=32 ){
+ v->expmask |= 0x80000000;
}else{
v->expmask |= ((u32)1 << (iVar-1));
}
}
+/*
+** Cause a function to throw an error if it was call from OP_PureFunc
+** rather than OP_Function.
+**
+** OP_PureFunc means that the function must be deterministic, and should
+** throw an error if it is given inputs that would make it non-deterministic.
+** This routine is invoked by date/time functions that use non-deterministic
+** features such as 'now'.
+*/
+SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){
+ const VdbeOp *pOp;
+#ifdef SQLITE_ENABLE_STAT4
+ if( pCtx->pVdbe==0 ) return 1;
+#endif
+ pOp = pCtx->pVdbe->aOp + pCtx->iOp;
+ if( pOp->opcode==OP_PureFunc ){
+ const char *zContext;
+ char *zMsg;
+ if( pOp->p5 & NC_IsCheck ){
+ zContext = "a CHECK constraint";
+ }else if( pOp->p5 & NC_GenCol ){
+ zContext = "a generated column";
+ }else{
+ zContext = "an index";
+ }
+ zMsg = sqlite3_mprintf("non-deterministic use of %s() in %s",
+ pCtx->pFunc->zName, zContext);
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+ return 0;
+ }
+ return 1;
+}
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
@@ -75032,21 +82897,21 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
-** If the second argument is not NULL, release any allocations associated
+** If the second argument is not NULL, release any allocations associated
** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
** structure itself, using sqlite3DbFree().
**
** This function is used to free UnpackedRecord structures allocated by
** the vdbeUnpackRecord() function found in vdbeapi.c.
*/
-static void vdbeFreeUnpacked(sqlite3 *db, UnpackedRecord *p){
+static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
if( p ){
int i;
- for(i=0; i<p->nField; i++){
+ for(i=0; i<nField; i++){
Mem *pMem = &p->aMem[i];
if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
}
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -75075,13 +82940,18 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
- if( op==SQLITE_UPDATE ){
- iKey2 = v->aMem[iReg].u.i;
+ if( HasRowid(pTab)==0 ){
+ iKey1 = iKey2 = 0;
+ preupdate.pPk = sqlite3PrimaryKeyIndex(pTab);
}else{
- iKey2 = iKey1;
+ if( op==SQLITE_UPDATE ){
+ iKey2 = v->aMem[iReg].u.i;
+ }else{
+ iKey2 = iKey1;
+ }
}
- assert( pCsr->nField==pTab->nCol
+ assert( pCsr->nField==pTab->nCol
|| (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
);
@@ -75091,8 +82961,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
preupdate.iNewReg = iReg;
preupdate.keyinfo.db = db;
preupdate.keyinfo.enc = ENC(db);
- preupdate.keyinfo.nField = pTab->nCol;
- preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
+ preupdate.keyinfo.nKeyField = pTab->nCol;
+ preupdate.keyinfo.aSortFlags = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
preupdate.pTab = pTab;
@@ -75101,14 +82971,14 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
db->pPreUpdate = 0;
sqlite3DbFree(db, preupdate.aRecord);
- vdbeFreeUnpacked(db, preupdate.pUnpacked);
- vdbeFreeUnpacked(db, preupdate.pNewUnpacked);
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pUnpacked);
+ vdbeFreeUnpacked(db, preupdate.keyinfo.nKeyField+1, preupdate.pNewUnpacked);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
- sqlite3DbFree(db, preupdate.aNew);
+ sqlite3DbFreeNN(db, preupdate.aNew);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -75179,16 +83049,18 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
sqlite3_int64 iNow;
sqlite3_int64 iElapse;
assert( p->startTime>0 );
- assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 );
+ assert( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 );
assert( db->init.busy==0 );
assert( p->zSql!=0 );
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
iElapse = (iNow - p->startTime)*1000000;
+#ifndef SQLITE_OMIT_DEPRECATED
if( db->xProfile ){
db->xProfile(db->pProfileArg, p->zSql, iElapse);
}
+#endif
if( db->mTrace & SQLITE_TRACE_PROFILE ){
- db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
+ db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
}
p->startTime = 0;
}
@@ -75271,7 +83143,8 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
sqlite3VdbeMemRelease(&p->aVar[i]);
p->aVar[i].flags = MEM_Null;
}
- if( p->isPrepareV2 && p->expmask ){
+ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
+ if( p->expmask ){
p->expired = 1;
}
sqlite3_mutex_leave(mutex);
@@ -75315,6 +83188,19 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
Mem *pMem = (Mem*)pVal;
return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0);
}
+SQLITE_API void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){
+ Mem *p = (Mem*)pVal;
+ if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
+ (MEM_Null|MEM_Term|MEM_Subtype)
+ && zPType!=0
+ && p->eSubtype=='p'
+ && strcmp(p->u.zPType, zPType)==0
+ ){
+ return (void*)p->z;
+ }else{
+ return 0;
+ }
+}
SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
@@ -75335,42 +83221,99 @@ SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){
*/
SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
static const u8 aType[] = {
- SQLITE_BLOB, /* 0x00 */
- SQLITE_NULL, /* 0x01 */
- SQLITE_TEXT, /* 0x02 */
- SQLITE_NULL, /* 0x03 */
- SQLITE_INTEGER, /* 0x04 */
- SQLITE_NULL, /* 0x05 */
- SQLITE_INTEGER, /* 0x06 */
- SQLITE_NULL, /* 0x07 */
- SQLITE_FLOAT, /* 0x08 */
- SQLITE_NULL, /* 0x09 */
- SQLITE_FLOAT, /* 0x0a */
- SQLITE_NULL, /* 0x0b */
- SQLITE_INTEGER, /* 0x0c */
- SQLITE_NULL, /* 0x0d */
- SQLITE_INTEGER, /* 0x0e */
- SQLITE_NULL, /* 0x0f */
- SQLITE_BLOB, /* 0x10 */
- SQLITE_NULL, /* 0x11 */
- SQLITE_TEXT, /* 0x12 */
- SQLITE_NULL, /* 0x13 */
- SQLITE_INTEGER, /* 0x14 */
- SQLITE_NULL, /* 0x15 */
- SQLITE_INTEGER, /* 0x16 */
- SQLITE_NULL, /* 0x17 */
- SQLITE_FLOAT, /* 0x18 */
- SQLITE_NULL, /* 0x19 */
- SQLITE_FLOAT, /* 0x1a */
- SQLITE_NULL, /* 0x1b */
- SQLITE_INTEGER, /* 0x1c */
- SQLITE_NULL, /* 0x1d */
- SQLITE_INTEGER, /* 0x1e */
- SQLITE_NULL, /* 0x1f */
+ SQLITE_BLOB, /* 0x00 (not possible) */
+ SQLITE_NULL, /* 0x01 NULL */
+ SQLITE_TEXT, /* 0x02 TEXT */
+ SQLITE_NULL, /* 0x03 (not possible) */
+ SQLITE_INTEGER, /* 0x04 INTEGER */
+ SQLITE_NULL, /* 0x05 (not possible) */
+ SQLITE_INTEGER, /* 0x06 INTEGER + TEXT */
+ SQLITE_NULL, /* 0x07 (not possible) */
+ SQLITE_FLOAT, /* 0x08 FLOAT */
+ SQLITE_NULL, /* 0x09 (not possible) */
+ SQLITE_FLOAT, /* 0x0a FLOAT + TEXT */
+ SQLITE_NULL, /* 0x0b (not possible) */
+ SQLITE_INTEGER, /* 0x0c (not possible) */
+ SQLITE_NULL, /* 0x0d (not possible) */
+ SQLITE_INTEGER, /* 0x0e (not possible) */
+ SQLITE_NULL, /* 0x0f (not possible) */
+ SQLITE_BLOB, /* 0x10 BLOB */
+ SQLITE_NULL, /* 0x11 (not possible) */
+ SQLITE_TEXT, /* 0x12 (not possible) */
+ SQLITE_NULL, /* 0x13 (not possible) */
+ SQLITE_INTEGER, /* 0x14 INTEGER + BLOB */
+ SQLITE_NULL, /* 0x15 (not possible) */
+ SQLITE_INTEGER, /* 0x16 (not possible) */
+ SQLITE_NULL, /* 0x17 (not possible) */
+ SQLITE_FLOAT, /* 0x18 FLOAT + BLOB */
+ SQLITE_NULL, /* 0x19 (not possible) */
+ SQLITE_FLOAT, /* 0x1a (not possible) */
+ SQLITE_NULL, /* 0x1b (not possible) */
+ SQLITE_INTEGER, /* 0x1c (not possible) */
+ SQLITE_NULL, /* 0x1d (not possible) */
+ SQLITE_INTEGER, /* 0x1e (not possible) */
+ SQLITE_NULL, /* 0x1f (not possible) */
+ SQLITE_FLOAT, /* 0x20 INTREAL */
+ SQLITE_NULL, /* 0x21 (not possible) */
+ SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
+ SQLITE_NULL, /* 0x23 (not possible) */
+ SQLITE_FLOAT, /* 0x24 (not possible) */
+ SQLITE_NULL, /* 0x25 (not possible) */
+ SQLITE_FLOAT, /* 0x26 (not possible) */
+ SQLITE_NULL, /* 0x27 (not possible) */
+ SQLITE_FLOAT, /* 0x28 (not possible) */
+ SQLITE_NULL, /* 0x29 (not possible) */
+ SQLITE_FLOAT, /* 0x2a (not possible) */
+ SQLITE_NULL, /* 0x2b (not possible) */
+ SQLITE_FLOAT, /* 0x2c (not possible) */
+ SQLITE_NULL, /* 0x2d (not possible) */
+ SQLITE_FLOAT, /* 0x2e (not possible) */
+ SQLITE_NULL, /* 0x2f (not possible) */
+ SQLITE_BLOB, /* 0x30 (not possible) */
+ SQLITE_NULL, /* 0x31 (not possible) */
+ SQLITE_TEXT, /* 0x32 (not possible) */
+ SQLITE_NULL, /* 0x33 (not possible) */
+ SQLITE_FLOAT, /* 0x34 (not possible) */
+ SQLITE_NULL, /* 0x35 (not possible) */
+ SQLITE_FLOAT, /* 0x36 (not possible) */
+ SQLITE_NULL, /* 0x37 (not possible) */
+ SQLITE_FLOAT, /* 0x38 (not possible) */
+ SQLITE_NULL, /* 0x39 (not possible) */
+ SQLITE_FLOAT, /* 0x3a (not possible) */
+ SQLITE_NULL, /* 0x3b (not possible) */
+ SQLITE_FLOAT, /* 0x3c (not possible) */
+ SQLITE_NULL, /* 0x3d (not possible) */
+ SQLITE_FLOAT, /* 0x3e (not possible) */
+ SQLITE_NULL, /* 0x3f (not possible) */
};
+#ifdef SQLITE_DEBUG
+ {
+ int eType = SQLITE_BLOB;
+ if( pVal->flags & MEM_Null ){
+ eType = SQLITE_NULL;
+ }else if( pVal->flags & (MEM_Real|MEM_IntReal) ){
+ eType = SQLITE_FLOAT;
+ }else if( pVal->flags & MEM_Int ){
+ eType = SQLITE_INTEGER;
+ }else if( pVal->flags & MEM_Str ){
+ eType = SQLITE_TEXT;
+ }
+ assert( eType == aType[pVal->flags&MEM_AffMask] );
+ }
+#endif
return aType[pVal->flags&MEM_AffMask];
}
+/* Return true if a parameter to xUpdate represents an unchanged column */
+SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
+ return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero);
+}
+
+/* Return true if a parameter value originated from an sqlite3_bind() */
+SQLITE_API int sqlite3_value_frombind(sqlite3_value *pVal){
+ return (pVal->flags&MEM_FromBind)!=0;
+}
+
/* Make a copy of an sqlite3_value object
*/
SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
@@ -75399,7 +83342,7 @@ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
sqlite3ValueFree(pOld);
}
-
+
/**************************** sqlite3_result_ *******************************
** The following routines are used by user-defined functions to specify
@@ -75440,9 +83383,9 @@ static int invokeValueDestructor(
return SQLITE_TOOBIG;
}
SQLITE_API void sqlite3_result_blob(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( n>=0 );
@@ -75450,8 +83393,8 @@ SQLITE_API void sqlite3_result_blob(
setResultStrOrError(pCtx, z, n, 0, xDel);
}
SQLITE_API void sqlite3_result_blob64(
- sqlite3_context *pCtx,
- const void *z,
+ sqlite3_context *pCtx,
+ const void *z,
sqlite3_uint64 n,
void (*xDel)(void *)
){
@@ -75470,14 +83413,12 @@ SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
- pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
- pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
@@ -75493,6 +83434,18 @@ SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
+SQLITE_API void sqlite3_result_pointer(
+ sqlite3_context *pCtx,
+ void *pPtr,
+ const char *zPType,
+ void (*xDestructor)(void*)
+){
+ Mem *pOut = pCtx->pOut;
+ assert( sqlite3_mutex_held(pOut->db->mutex) );
+ sqlite3VdbeMemRelease(pOut);
+ pOut->flags = MEM_Null;
+ sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
+}
SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
@@ -75500,8 +83453,8 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubt
pOut->flags |= MEM_Subtype;
}
SQLITE_API void sqlite3_result_text(
- sqlite3_context *pCtx,
- const char *z,
+ sqlite3_context *pCtx,
+ const char *z,
int n,
void (*xDel)(void *)
){
@@ -75509,8 +83462,8 @@ SQLITE_API void sqlite3_result_text(
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
SQLITE_API void sqlite3_result_text64(
- sqlite3_context *pCtx,
- const char *z,
+ sqlite3_context *pCtx,
+ const char *z,
sqlite3_uint64 n,
void (*xDel)(void *),
unsigned char enc
@@ -75526,27 +83479,27 @@ SQLITE_API void sqlite3_result_text64(
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void sqlite3_result_text16(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
}
SQLITE_API void sqlite3_result_text16be(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
}
SQLITE_API void sqlite3_result_text16le(
- sqlite3_context *pCtx,
- const void *z,
- int n,
+ sqlite3_context *pCtx,
+ const void *z,
+ int n,
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
@@ -75571,13 +83524,12 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
return SQLITE_OK;
}
SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
- pCtx->isError = errCode;
- pCtx->fErrorOrAux = 1;
+ pCtx->isError = errCode ? errCode : -1;
#ifdef SQLITE_DEBUG
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
#endif
if( pCtx->pOut->flags & MEM_Null ){
- sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
+ sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
}
}
@@ -75586,8 +83538,7 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
- pCtx->fErrorOrAux = 1;
- sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
+ sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
SQLITE_UTF8, SQLITE_STATIC);
}
@@ -75596,12 +83547,26 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM_BKPT;
- pCtx->fErrorOrAux = 1;
sqlite3OomFault(pCtx->pOut->db);
}
+#ifndef SQLITE_UNTESTABLE
+/* Force the INT64 value currently stored as the result to be
+** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL
+** test-control.
+*/
+SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+ if( pCtx->pOut->flags & MEM_Int ){
+ pCtx->pOut->flags &= ~MEM_Int;
+ pCtx->pOut->flags |= MEM_IntReal;
+ }
+}
+#endif
+
+
/*
-** This function is called after a transaction has been committed. It
+** This function is called after a transaction has been committed. It
** invokes callbacks registered with sqlite3_wal_hook() as required.
*/
static int doWalCallbacks(sqlite3 *db){
@@ -75615,7 +83580,7 @@ static int doWalCallbacks(sqlite3 *db){
sqlite3BtreeEnter(pBt);
nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
- if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
+ if( nEntry>0 && db->xWalCallback && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
}
}
@@ -75630,7 +83595,7 @@ static int doWalCallbacks(sqlite3 *db){
** statement is completely executed or an error occurs.
**
** This routine implements the bulk of the logic behind the sqlite_step()
-** API. The only thing omitted is the automatic recompile if a
+** API. The only thing omitted is the automatic recompile if a
** schema change has occurred. That detail is handled by the
** outer sqlite3_step() wrapper procedure.
*/
@@ -75644,15 +83609,15 @@ static int sqlite3Step(Vdbe *p){
** sqlite3_step() after any error or after SQLITE_DONE. But beginning
** with version 3.7.0, we changed this so that sqlite3_reset() would
** be called automatically instead of throwing the SQLITE_MISUSE error.
- ** This "automatic-reset" change is not technically an incompatibility,
+ ** This "automatic-reset" change is not technically an incompatibility,
** since any application that receives an SQLITE_MISUSE is broken by
** definition.
**
** Nevertheless, some published applications that were originally written
- ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
+ ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
** returns, and those were broken by the automatic-reset change. As a
** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
- ** legacy behavior of returning SQLITE_MISUSE for cases where the
+ ** legacy behavior of returning SQLITE_MISUSE for cases where the
** previous sqlite3_step() returned something other than a SQLITE_LOCKED
** or SQLITE_BUSY error.
*/
@@ -75674,9 +83639,16 @@ static int sqlite3Step(Vdbe *p){
return SQLITE_NOMEM_BKPT;
}
- if( p->pc<=0 && p->expired ){
+ if( p->pc<0 && p->expired ){
p->rc = SQLITE_SCHEMA;
rc = SQLITE_ERROR;
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
+ /* If this statement was prepared using saved SQL and an
+ ** error has occurred, then return the error code in p->rc to the
+ ** caller. Set the error code in the database handle to the same value.
+ */
+ rc = sqlite3VdbeTransferError(p);
+ }
goto end_of_step;
}
if( p->pc<0 ){
@@ -75685,15 +83657,15 @@ static int sqlite3Step(Vdbe *p){
** from interrupting a statement that has not yet started.
*/
if( db->nVdbeActive==0 ){
- db->u1.isInterrupted = 0;
+ AtomicStore(&db->u1.isInterrupted, 0);
}
- assert( db->nVdbeWrite>0 || db->autoCommit==0
+ assert( db->nVdbeWrite>0 || db->autoCommit==0
|| (db->nDeferredCons==0 && db->nDeferredImmCons==0)
);
#ifndef SQLITE_OMIT_TRACE
- if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0)
+ if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
&& !db->init.busy && p->zSql ){
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}else{
@@ -75720,42 +83692,39 @@ static int sqlite3Step(Vdbe *p){
db->nVdbeExec--;
}
+ if( rc!=SQLITE_ROW ){
#ifndef SQLITE_OMIT_TRACE
- /* If the statement completed successfully, invoke the profile callback */
- if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
+ /* If the statement completed successfully, invoke the profile callback */
+ checkProfileCallback(db, p);
#endif
- if( rc==SQLITE_DONE ){
- assert( p->rc==SQLITE_OK );
- p->rc = doWalCallbacks(db);
- if( p->rc!=SQLITE_OK ){
- rc = SQLITE_ERROR;
+ if( rc==SQLITE_DONE && db->autoCommit ){
+ assert( p->rc==SQLITE_OK );
+ p->rc = doWalCallbacks(db);
+ if( p->rc!=SQLITE_OK ){
+ rc = SQLITE_ERROR;
+ }
+ }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
+ /* If this statement was prepared using saved SQL and an
+ ** error has occurred, then return the error code in p->rc to the
+ ** caller. Set the error code in the database handle to the same value.
+ */
+ rc = sqlite3VdbeTransferError(p);
}
}
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM_BKPT;
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc;
}
end_of_step:
- /* At this point local variable rc holds the value that should be
- ** returned if this statement was compiled using the legacy
- ** sqlite3_prepare() interface. According to the docs, this can only
- ** be one of the values in the first assert() below. Variable p->rc
- ** contains the value that would be returned if sqlite3_finalize()
- ** were called on statement p.
- */
- assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
+ /* There are only a limited number of result codes allowed from the
+ ** statements prepared using the legacy sqlite3_prepare() interface */
+ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
+ || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|| (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
);
- assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
- if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
- /* If this statement was prepared using sqlite3_prepare_v2(), and an
- ** error has occurred, then return the error code in p->rc to the
- ** caller. Set the error code in the database handle to the same value.
- */
- rc = sqlite3VdbeTransferError(p);
- }
return (rc&db->errMask);
}
@@ -75766,7 +83735,6 @@ end_of_step:
*/
SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_OK; /* Result from sqlite3Step() */
- int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
int cnt = 0; /* Counter to prevent infinite loop of reprepares */
sqlite3 *db; /* The database connection */
@@ -75780,32 +83748,31 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
int savedPc = v->pc;
- rc2 = rc = sqlite3Reprepare(v);
- if( rc!=SQLITE_OK) break;
+ rc = sqlite3Reprepare(v);
+ if( rc!=SQLITE_OK ){
+ /* This case occurs after failing to recompile an sql statement.
+ ** The error message from the SQL compiler has already been loaded
+ ** into the database handle. This block copies the error message
+ ** from the database handle into the statement and sets the statement
+ ** program counter to 0 to ensure that when the statement is
+ ** finalized or reset the parser error message is available via
+ ** sqlite3_errmsg() and sqlite3_errcode().
+ */
+ const char *zErr = (const char *)sqlite3_value_text(db->pErr);
+ sqlite3DbFree(db, v->zErrMsg);
+ if( !db->mallocFailed ){
+ v->zErrMsg = sqlite3DbStrDup(db, zErr);
+ v->rc = rc = sqlite3ApiExit(db, rc);
+ } else {
+ v->zErrMsg = 0;
+ v->rc = rc = SQLITE_NOMEM_BKPT;
+ }
+ break;
+ }
sqlite3_reset(pStmt);
if( savedPc>=0 ) v->doingRerun = 1;
assert( v->expired==0 );
}
- if( rc2!=SQLITE_OK ){
- /* This case occurs after failing to recompile an sql statement.
- ** The error message from the SQL compiler has already been loaded
- ** into the database handle. This block copies the error message
- ** from the database handle into the statement and sets the statement
- ** program counter to 0 to ensure that when the statement is
- ** finalized or reset the parser error message is available via
- ** sqlite3_errmsg() and sqlite3_errcode().
- */
- const char *zErr = (const char *)sqlite3_value_text(db->pErr);
- sqlite3DbFree(db, v->zErrMsg);
- if( !db->mallocFailed ){
- v->zErrMsg = sqlite3DbStrDup(db, zErr);
- v->rc = rc2;
- } else {
- v->zErrMsg = 0;
- v->rc = rc = SQLITE_NOMEM_BKPT;
- }
- }
- rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -75836,6 +83803,25 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
}
/*
+** If this routine is invoked from within an xColumn method of a virtual
+** table, then it returns true if and only if the the call is during an
+** UPDATE operation and the value of the column will not be modified
+** by the UPDATE.
+**
+** If this routine is called from any context other than within the
+** xColumn method of a virtual table, then the return value is meaningless
+** and arbitrary.
+**
+** Virtual table implements might use this routine to optimize their
+** performance by substituting a NULL result, or some other light-weight
+** value, as a signal to the xUpdate routine that the column is unchanged.
+*/
+SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
+ assert( p );
+ return sqlite3_value_nochange(p->pOut);
+}
+
+/*
** Return the current time for a statement. If the current time
** is requested more than once within the same run of a single prepared
** statement, the exact same time is returned for each invocation regardless
@@ -75844,7 +83830,7 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
*/
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
int rc;
-#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifndef SQLITE_ENABLE_STAT4
sqlite3_int64 *piTime = &p->pVdbe->iCurrentTime;
assert( p->pVdbe!=0 );
#else
@@ -75859,28 +83845,6 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
}
/*
-** The following is the implementation of an SQL function that always
-** fails with an error message stating that the function is used in the
-** wrong context. The sqlite3_overload_function() API might construct
-** SQL function that use this routine so that the functions will exist
-** for name resolution but are actually overloaded by the xFindFunction
-** method of virtual tables.
-*/
-SQLITE_PRIVATE void sqlite3InvalidFunction(
- sqlite3_context *context, /* The function calling context */
- int NotUsed, /* Number of arguments to the function */
- sqlite3_value **NotUsed2 /* Value of each argument */
-){
- const char *zName = context->pFunc->zName;
- char *zErr;
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
- zErr = sqlite3_mprintf(
- "unable to use function %s in the requested context", zName);
- sqlite3_result_error(context, zErr, -1);
- sqlite3_free(zErr);
-}
-
-/*
** Create a new aggregate context for p and return a pointer to
** its pMem->z element.
*/
@@ -75920,65 +83884,76 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
/*
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
+**
+** The left-most argument is 0.
+**
+** Undocumented behavior: If iArg is negative then access a cache of
+** auxiliary data pointers that is available to all functions within a
+** single prepared statement. The iArg values must match.
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
-#if SQLITE_ENABLE_STAT3_OR_STAT4
+#if SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 0;
#else
assert( pCtx->pVdbe!=0 );
#endif
- for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
- if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
+ for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
+ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
+ return pAuxData->pAux;
+ }
}
-
- return (pAuxData ? pAuxData->pAux : 0);
+ return 0;
}
/*
** Set the auxiliary data pointer and delete function, for the iArg'th
** argument to the user-function defined by pCtx. Any previous value is
** deleted by calling the delete function specified when it was set.
+**
+** The left-most argument is 0.
+**
+** Undocumented behavior: If iArg is negative then make the data available
+** to all functions within the current prepared statement using iArg as an
+** access code.
*/
SQLITE_API void sqlite3_set_auxdata(
- sqlite3_context *pCtx,
- int iArg,
- void *pAux,
+ sqlite3_context *pCtx,
+ int iArg,
+ void *pAux,
void (*xDelete)(void*)
){
AuxData *pAuxData;
Vdbe *pVdbe = pCtx->pVdbe;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- if( iArg<0 ) goto failed;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
if( pVdbe==0 ) goto failed;
#else
assert( pVdbe!=0 );
#endif
- for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
- if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
+ for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNextAux){
+ if( pAuxData->iAuxArg==iArg && (pAuxData->iAuxOp==pCtx->iOp || iArg<0) ){
+ break;
+ }
}
if( pAuxData==0 ){
pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
if( !pAuxData ) goto failed;
- pAuxData->iOp = pCtx->iOp;
- pAuxData->iArg = iArg;
- pAuxData->pNext = pVdbe->pAuxData;
+ pAuxData->iAuxOp = pCtx->iOp;
+ pAuxData->iAuxArg = iArg;
+ pAuxData->pNextAux = pVdbe->pAuxData;
pVdbe->pAuxData = pAuxData;
- if( pCtx->fErrorOrAux==0 ){
- pCtx->isError = 0;
- pCtx->fErrorOrAux = 1;
- }
- }else if( pAuxData->xDelete ){
- pAuxData->xDelete(pAuxData->pAux);
+ if( pCtx->isError==0 ) pCtx->isError = -1;
+ }else if( pAuxData->xDeleteAux ){
+ pAuxData->xDeleteAux(pAuxData->pAux);
}
pAuxData->pAux = pAux;
- pAuxData->xDelete = xDelete;
+ pAuxData->xDeleteAux = xDelete;
return;
failed:
@@ -75989,7 +83964,7 @@ failed:
#ifndef SQLITE_OMIT_DEPRECATED
/*
-** Return the number of times the Step function of an aggregate has been
+** Return the number of times the Step function of an aggregate has been
** called.
**
** This function is deprecated. Do not use it for new code. It is
@@ -76034,9 +84009,9 @@ static const Mem *columnNullValue(void){
** these assert()s from failing, when building with SQLITE_DEBUG defined
** using gcc, we force nullMem to be 8-byte aligned using the magical
** __attribute__((aligned(8))) macro. */
- static const Mem nullMem
+ static const Mem nullMem
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
- __attribute__((aligned(8)))
+ __attribute__((aligned(8)))
#endif
= {
/* .u = */ {0},
@@ -76052,7 +84027,7 @@ static const Mem *columnNullValue(void){
/* .xDel = */ (void(*)(void*))0,
#ifdef SQLITE_DEBUG
/* .pScopyFrom = */ (Mem*)0,
- /* .pFiller = */ (void*)0,
+ /* .mScopyFlags= */ 0,
#endif
};
return &nullMem;
@@ -76082,9 +84057,9 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
}
/*
-** This function is called after invoking an sqlite3_value_XXX function on a
+** This function is called after invoking an sqlite3_value_XXX function on a
** column value (i.e. a value returned by evaluating an SQL expression in the
-** select list of a SELECT statement) that may cause a malloc() failure. If
+** select list of a SELECT statement) that may cause a malloc() failure. If
** malloc() has failed, the threads mallocFailed flag is cleared and the result
** code of statement pStmt set to SQLITE_NOMEM.
**
@@ -76123,8 +84098,8 @@ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
/* Even though there is no encoding conversion, value_blob() might
- ** need to call malloc() to expand the result of a zeroblob()
- ** expression.
+ ** need to call malloc() to expand the result of a zeroblob()
+ ** expression.
*/
columnMallocFailure(pStmt);
return val;
@@ -76198,10 +84173,10 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
** or a constant) then useTypes 2, 3, and 4 return NULL.
*/
static const void *columnName(
- sqlite3_stmt *pStmt,
- int N,
- const void *(*xFunc)(Mem*),
- int useType
+ sqlite3_stmt *pStmt, /* The statement */
+ int N, /* Which column to get the name for */
+ int useUtf16, /* True to return the name as UTF16 */
+ int useType /* What type of name */
){
const void *ret;
Vdbe *p;
@@ -76222,8 +84197,15 @@ static const void *columnName(
N += useType*n;
sqlite3_mutex_enter(db->mutex);
assert( db->mallocFailed==0 );
- ret = xFunc(&p->aColName[N]);
- /* A malloc may have failed inside of the xFunc() call. If this
+#ifndef SQLITE_OMIT_UTF16
+ if( useUtf16 ){
+ ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]);
+ }else
+#endif
+ {
+ ret = sqlite3_value_text((sqlite3_value*)&p->aColName[N]);
+ }
+ /* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
if( db->mallocFailed ){
@@ -76240,13 +84222,11 @@ static const void *columnName(
** statement pStmt.
*/
SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
+ return columnName(pStmt, N, 0, COLNAME_NAME);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
+ return columnName(pStmt, N, 1, COLNAME_NAME);
}
#endif
@@ -76265,13 +84245,11 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
** of the result set of SQL statement pStmt.
*/
SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
+ return columnName(pStmt, N, 0, COLNAME_DECLTYPE);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
+ return columnName(pStmt, N, 1, COLNAME_DECLTYPE);
}
#endif /* SQLITE_OMIT_UTF16 */
#endif /* SQLITE_OMIT_DECLTYPE */
@@ -76283,13 +84261,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
** anything else which is not an unambiguous reference to a database column.
*/
SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
+ return columnName(pStmt, N, 0, COLNAME_DATABASE);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
+ return columnName(pStmt, N, 1, COLNAME_DATABASE);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -76299,13 +84275,11 @@ SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N
** anything else which is not an unambiguous reference to a database column.
*/
SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
+ return columnName(pStmt, N, 0, COLNAME_TABLE);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
+ return columnName(pStmt, N, 1, COLNAME_TABLE);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -76315,24 +84289,22 @@ SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
** anything else which is not an unambiguous reference to a database column.
*/
SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
+ return columnName(pStmt, N, 0, COLNAME_COLUMN);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
- return columnName(
- pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
+ return columnName(pStmt, N, 1, COLNAME_COLUMN);
}
#endif /* SQLITE_OMIT_UTF16 */
#endif /* SQLITE_ENABLE_COLUMN_METADATA */
/******************************* sqlite3_bind_ ***************************
-**
+**
** Routines used to attach values to wildcards in a compiled SQL statement.
*/
/*
-** Unbind the value bound to variable i in virtual machine p. This is the
+** Unbind the value bound to variable i in virtual machine p. This is the
** the same as binding a NULL value to the column. If the "i" parameter is
** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
**
@@ -76351,7 +84323,7 @@ static int vdbeUnbind(Vdbe *p, int i){
if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
sqlite3Error(p->db, SQLITE_MISUSE);
sqlite3_mutex_leave(p->db->mutex);
- sqlite3_log(SQLITE_MISUSE,
+ sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
@@ -76364,20 +84336,19 @@ static int vdbeUnbind(Vdbe *p, int i){
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
- sqlite3Error(p->db, SQLITE_OK);
+ p->db->errCode = SQLITE_OK;
- /* If the bit corresponding to this variable in Vdbe.expmask is set, then
+ /* If the bit corresponding to this variable in Vdbe.expmask is set, then
** binding a new value to this variable invalidates the current query plan.
**
- ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
+ ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host
** parameter in the WHERE clause might influence the choice of query plan
** for a statement, then the statement will be automatically recompiled,
** as if there had been a schema change, on the first sqlite3_step() call
** following any change to the bindings of that parameter.
*/
- if( p->isPrepareV2 &&
- ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff)
- ){
+ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || p->expmask==0 );
+ if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){
p->expired = 1;
}
return SQLITE_OK;
@@ -76406,8 +84377,10 @@ static int bindText(
if( rc==SQLITE_OK && encoding!=0 ){
rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db));
}
- sqlite3Error(p->db, rc);
- rc = sqlite3ApiExit(p->db, rc);
+ if( rc ){
+ sqlite3Error(p->db, rc);
+ rc = sqlite3ApiExit(p->db, rc);
+ }
}
sqlite3_mutex_leave(p->db->mutex);
}else if( xDel!=SQLITE_STATIC && xDel!=SQLITE_TRANSIENT ){
@@ -76421,10 +84394,10 @@ static int bindText(
** Bind a blob value to an SQL statement variable.
*/
SQLITE_API int sqlite3_bind_blob(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
+ sqlite3_stmt *pStmt,
+ int i,
+ const void *zData,
+ int nData,
void (*xDel)(void*)
){
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -76433,10 +84406,10 @@ SQLITE_API int sqlite3_bind_blob(
return bindText(pStmt, i, zData, nData, xDel, 0);
}
SQLITE_API int sqlite3_bind_blob64(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- sqlite3_uint64 nData,
+ sqlite3_stmt *pStmt,
+ int i,
+ const void *zData,
+ sqlite3_uint64 nData,
void (*xDel)(void*)
){
assert( xDel!=SQLITE_DYNAMIC );
@@ -76478,20 +84451,38 @@ SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-SQLITE_API int sqlite3_bind_text(
- sqlite3_stmt *pStmt,
- int i,
- const char *zData,
- int nData,
+SQLITE_API int sqlite3_bind_pointer(
+ sqlite3_stmt *pStmt,
+ int i,
+ void *pPtr,
+ const char *zPTtype,
+ void (*xDestructor)(void*)
+){
+ int rc;
+ Vdbe *p = (Vdbe*)pStmt;
+ rc = vdbeUnbind(p, i);
+ if( rc==SQLITE_OK ){
+ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
+ sqlite3_mutex_leave(p->db->mutex);
+ }else if( xDestructor ){
+ xDestructor(pPtr);
+ }
+ return rc;
+}
+SQLITE_API int sqlite3_bind_text(
+ sqlite3_stmt *pStmt,
+ int i,
+ const char *zData,
+ int nData,
void (*xDel)(void*)
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
-SQLITE_API int sqlite3_bind_text64(
- sqlite3_stmt *pStmt,
- int i,
- const char *zData,
- sqlite3_uint64 nData,
+SQLITE_API int sqlite3_bind_text64(
+ sqlite3_stmt *pStmt,
+ int i,
+ const char *zData,
+ sqlite3_uint64 nData,
void (*xDel)(void*),
unsigned char enc
){
@@ -76505,10 +84496,10 @@ SQLITE_API int sqlite3_bind_text64(
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API int sqlite3_bind_text16(
- sqlite3_stmt *pStmt,
- int i,
- const void *zData,
- int nData,
+ sqlite3_stmt *pStmt,
+ int i,
+ const void *zData,
+ int nData,
void (*xDel)(void*)
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
@@ -76572,7 +84563,7 @@ SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint6
/*
** Return the number of wildcards that can be potentially bound to.
-** This routine is added to support DBD::SQLite.
+** This routine is added to support DBD::SQLite.
*/
SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
@@ -76587,10 +84578,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
*/
SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
- if( p==0 || i<1 || i>p->nzVar ){
- return 0;
- }
- return p->azVar[i-1];
+ if( p==0 ) return 0;
+ return sqlite3VListNumToName(p->pVList, i);
}
/*
@@ -76599,19 +84588,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
** return 0.
*/
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
- int i;
- if( p==0 ){
- return 0;
- }
- if( zName ){
- for(i=0; i<p->nzVar; i++){
- const char *z = p->azVar[i];
- if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
- return i+1;
- }
- }
- }
- return 0;
+ if( p==0 || zName==0 ) return 0;
+ return sqlite3VListNameToNum(p->pVList, zName, nName);
}
SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
@@ -76653,10 +84631,12 @@ SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *
if( pFrom->nVar!=pTo->nVar ){
return SQLITE_ERROR;
}
- if( pTo->isPrepareV2 && pTo->expmask ){
+ assert( (pTo->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pTo->expmask==0 );
+ if( pTo->expmask ){
pTo->expired = 1;
}
- if( pFrom->isPrepareV2 && pFrom->expmask ){
+ assert( (pFrom->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 || pFrom->expmask==0 );
+ if( pFrom->expmask ){
pFrom->expired = 1;
}
return sqlite3TransferBindings(pFromStmt, pToStmt);
@@ -76682,6 +84662,14 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
}
/*
+** Return 1 if the statement is an EXPLAIN and return 2 if the
+** statement is an EXPLAIN QUERY PLAN
+*/
+SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
+ return pStmt ? ((Vdbe*)pStmt)->explain : 0;
+}
+
+/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
@@ -76720,13 +84708,26 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
u32 v;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !pStmt ){
+ if( !pStmt
+ || (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter)))
+ ){
(void)SQLITE_MISUSE_BKPT;
return 0;
}
#endif
- v = pVdbe->aCounter[op];
- if( resetFlag ) pVdbe->aCounter[op] = 0;
+ if( op==SQLITE_STMTSTATUS_MEMUSED ){
+ sqlite3 *db = pVdbe->db;
+ sqlite3_mutex_enter(db->mutex);
+ v = 0;
+ db->pnBytesFreed = (int*)&v;
+ sqlite3VdbeClearObject(db, pVdbe);
+ sqlite3DbFree(db, pVdbe);
+ db->pnBytesFreed = 0;
+ sqlite3_mutex_leave(db->mutex);
+ }else{
+ v = pVdbe->aCounter[op];
+ if( resetFlag ) pVdbe->aCounter[op] = 0;
+ }
return (int)v;
}
@@ -76763,6 +84764,22 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
#endif
}
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** Return the normalized SQL associated with a prepared statement.
+*/
+SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){
+ Vdbe *p = (Vdbe *)pStmt;
+ if( p==0 ) return 0;
+ if( p->zNormSql==0 && ALWAYS(p->zSql!=0) ){
+ sqlite3_mutex_enter(p->db->mutex);
+ p->zNormSql = sqlite3Normalize(p, p->zSql);
+ sqlite3_mutex_leave(p->db->mutex);
+ }
+ return p->zNormSql;
+}
+#endif /* SQLITE_ENABLE_NORMALIZE */
+
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
** Allocate and populate an UnpackedRecord structure based on the serialized
@@ -76770,16 +84787,15 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
** if successful, or a NULL pointer if an OOM error is encountered.
*/
static UnpackedRecord *vdbeUnpackRecord(
- KeyInfo *pKeyInfo,
- int nKey,
+ KeyInfo *pKeyInfo,
+ int nKey,
const void *pKey
){
- char *dummy; /* Dummy argument for AllocUnpackedRecord() */
UnpackedRecord *pRet; /* Return value */
- pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo, 0, 0, &dummy);
+ pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( pRet ){
- memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
+ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nKeyField+1));
sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
}
return pRet;
@@ -76791,6 +84807,7 @@ static UnpackedRecord *vdbeUnpackRecord(
*/
SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
PreUpdate *p = db->pPreUpdate;
+ Mem *pMem;
int rc = SQLITE_OK;
/* Test that this call is being made from within an SQLITE_DELETE or
@@ -76799,6 +84816,9 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
rc = SQLITE_MISUSE_BKPT;
goto preupdate_old_out;
}
+ if( p->pPk ){
+ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ }
if( iIdx>=p->pCsr->nField || iIdx<0 ){
rc = SQLITE_RANGE;
goto preupdate_old_out;
@@ -76812,7 +84832,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
aRec = sqlite3DbMallocRaw(db, nRec);
if( !aRec ) goto preupdate_old_out;
- rc = sqlite3BtreeData(p->pCsr->uc.pCursor, 0, nRec, aRec);
+ rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
if( rc==SQLITE_OK ){
p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
if( !p->pUnpacked ) rc = SQLITE_NOMEM;
@@ -76824,17 +84844,16 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
p->aRecord = aRec;
}
- if( iIdx>=p->pUnpacked->nField ){
+ pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
+ if( iIdx==p->pTab->iPKey ){
+ sqlite3VdbeMemSetInt64(pMem, p->iKey1);
+ }else if( iIdx>=p->pUnpacked->nField ){
*ppValue = (sqlite3_value *)columnNullValue();
- }else{
- Mem *pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
- *ppValue = &p->pUnpacked->aMem[iIdx];
- if( iIdx==p->pTab->iPKey ){
- sqlite3VdbeMemSetInt64(pMem, p->iKey1);
- }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
- if( pMem->flags & MEM_Int ){
- sqlite3VdbeMemRealify(pMem);
- }
+ }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
+ if( pMem->flags & (MEM_Int|MEM_IntReal) ){
+ testcase( pMem->flags & MEM_Int );
+ testcase( pMem->flags & MEM_IntReal );
+ sqlite3VdbeMemRealify(pMem);
}
}
@@ -76851,7 +84870,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
*/
SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
PreUpdate *p = db->pPreUpdate;
- return (p ? p->keyinfo.nField : 0);
+ return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -76861,7 +84880,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
** only. It returns zero if the change that caused the callback was made
** immediately by a user SQL statement. Or, if the change was made by a
** trigger program, it returns the number of trigger programs currently
-** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
+** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
** top-level trigger etc.).
**
** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
@@ -76887,6 +84906,9 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
rc = SQLITE_MISUSE_BKPT;
goto preupdate_new_out;
}
+ if( p->pPk && p->op!=SQLITE_UPDATE ){
+ iIdx = sqlite3TableColumnToIndex(p->pPk, iIdx);
+ }
if( iIdx>=p->pCsr->nField || iIdx<0 ){
rc = SQLITE_RANGE;
goto preupdate_new_out;
@@ -76907,13 +84929,11 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
}
p->pNewUnpacked = pUnpack;
}
- if( iIdx>=pUnpack->nField ){
+ pMem = &pUnpack->aMem[iIdx];
+ if( iIdx==p->pTab->iPKey ){
+ sqlite3VdbeMemSetInt64(pMem, p->iKey2);
+ }else if( iIdx>=pUnpack->nField ){
pMem = (sqlite3_value *)columnNullValue();
- }else{
- pMem = &pUnpack->aMem[iIdx];
- if( iIdx==p->pTab->iPKey ){
- sqlite3VdbeMemSetInt64(pMem, p->iKey2);
- }
}
}else{
/* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
@@ -77069,8 +85089,8 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
/*
** This function returns a pointer to a nul-terminated string in memory
** obtained from sqlite3DbMalloc(). If sqlite3.nVdbeExec is 1, then the
-** string contains a copy of zRawSql but with host parameters expanded to
-** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1,
+** string contains a copy of zRawSql but with host parameters expanded to
+** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1,
** then the returned string holds a copy of zRawSql with "-- " prepended
** to each line of text.
**
@@ -77103,28 +85123,28 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
Mem *pVar; /* Value of a host parameter */
StrAccum out; /* Accumulate the output here */
#ifndef SQLITE_OMIT_UTF16
- Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
+ Mem utf8; /* Used to convert UTF16 into UTF8 for display */
#endif
char zBase[100]; /* Initial working space */
db = p->db;
- sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
+ sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
if( db->nVdbeExec>1 ){
while( *zRawSql ){
const char *zStart = zRawSql;
while( *(zRawSql++)!='\n' && *zRawSql );
- sqlite3StrAccumAppend(&out, "-- ", 3);
+ sqlite3_str_append(&out, "-- ", 3);
assert( (zRawSql - zStart) > 0 );
- sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
+ sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart));
}
}else if( p->nVar==0 ){
- sqlite3StrAccumAppend(&out, zRawSql, sqlite3Strlen30(zRawSql));
+ sqlite3_str_append(&out, zRawSql, sqlite3Strlen30(zRawSql));
}else{
while( zRawSql[0] ){
n = findNextHostParameter(zRawSql, &nToken);
assert( n>0 );
- sqlite3StrAccumAppend(&out, zRawSql, n);
+ sqlite3_str_append(&out, zRawSql, n);
zRawSql += n;
assert( zRawSql[0] || nToken==0 );
if( nToken==0 ) break;
@@ -77150,11 +85170,11 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
assert( idx>0 && idx<=p->nVar );
pVar = &p->aVar[idx-1];
if( pVar->flags & MEM_Null ){
- sqlite3StrAccumAppend(&out, "NULL", 4);
- }else if( pVar->flags & MEM_Int ){
- sqlite3XPrintf(&out, "%lld", pVar->u.i);
+ sqlite3_str_append(&out, "NULL", 4);
+ }else if( pVar->flags & (MEM_Int|MEM_IntReal) ){
+ sqlite3_str_appendf(&out, "%lld", pVar->u.i);
}else if( pVar->flags & MEM_Real ){
- sqlite3XPrintf(&out, "%!.15g", pVar->u.r);
+ sqlite3_str_appendf(&out, "%!.15g", pVar->u.r);
}else if( pVar->flags & MEM_Str ){
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
@@ -77164,7 +85184,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
utf8.db = db;
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
- out.accError = STRACCUM_NOMEM;
+ out.accError = SQLITE_NOMEM;
out.nAlloc = 0;
}
pVar = &utf8;
@@ -77176,39 +85196,39 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
nOut = SQLITE_TRACE_SIZE_LIMIT;
while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
}
-#endif
- sqlite3XPrintf(&out, "'%.*q'", nOut, pVar->z);
+#endif
+ sqlite3_str_appendf(&out, "'%.*q'", nOut, pVar->z);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ){
- sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+ sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut);
}
#endif
#ifndef SQLITE_OMIT_UTF16
if( enc!=SQLITE_UTF8 ) sqlite3VdbeMemRelease(&utf8);
#endif
}else if( pVar->flags & MEM_Zero ){
- sqlite3XPrintf(&out, "zeroblob(%d)", pVar->u.nZero);
+ sqlite3_str_appendf(&out, "zeroblob(%d)", pVar->u.nZero);
}else{
int nOut; /* Number of bytes of the blob to include in output */
assert( pVar->flags & MEM_Blob );
- sqlite3StrAccumAppend(&out, "x'", 2);
+ sqlite3_str_append(&out, "x'", 2);
nOut = pVar->n;
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut>SQLITE_TRACE_SIZE_LIMIT ) nOut = SQLITE_TRACE_SIZE_LIMIT;
#endif
for(i=0; i<nOut; i++){
- sqlite3XPrintf(&out, "%02x", pVar->z[i]&0xff);
+ sqlite3_str_appendf(&out, "%02x", pVar->z[i]&0xff);
}
- sqlite3StrAccumAppend(&out, "'", 1);
+ sqlite3_str_append(&out, "'", 1);
#ifdef SQLITE_TRACE_SIZE_LIMIT
if( nOut<pVar->n ){
- sqlite3XPrintf(&out, "/*+%d bytes*/", pVar->n-nOut);
+ sqlite3_str_appendf(&out, "/*+%d bytes*/", pVar->n-nOut);
}
#endif
}
}
}
- if( out.accError ) sqlite3StrAccumReset(&out);
+ if( out.accError ) sqlite3_str_reset(&out);
return sqlite3StrAccumFinish(&out);
}
@@ -77329,55 +85349,111 @@ SQLITE_API int sqlite3_found_count = 0;
** Test a register to see if it exceeds the current maximum blob size.
** If it does, record the new maximum blob size.
*/
-#if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST)
+#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE)
# define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P)
#else
# define UPDATE_MAX_BLOBSIZE(P)
#endif
+#ifdef SQLITE_DEBUG
+/* This routine provides a convenient place to set a breakpoint during
+** tracing with PRAGMA vdbe_trace=on. The breakpoint fires right after
+** each opcode is printed. Variables "pc" (program counter) and pOp are
+** available to add conditionals to the breakpoint. GDB example:
+**
+** break test_trace_breakpoint if pc=22
+**
+** Other useful labels for breakpoints include:
+** test_addop_breakpoint(pc,pOp)
+** sqlite3CorruptError(lineno)
+** sqlite3MisuseError(lineno)
+** sqlite3CantopenError(lineno)
+*/
+static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
+ static int n = 0;
+ n++;
+}
+#endif
+
/*
** Invoke the VDBE coverage callback, if that callback is defined. This
** feature is used for test suite validation only and does not appear an
** production builds.
**
-** M is an integer, 2 or 3, that indices how many different ways the
-** branch can go. It is usually 2. "I" is the direction the branch
-** goes. 0 means falls through. 1 means branch is taken. 2 means the
-** second alternative branch is taken.
+** M is the type of branch. I is the direction taken for this instance of
+** the branch.
+**
+** M: 2 - two-way branch (I=0: fall-thru 1: jump )
+** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL )
+** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3)
+**
+** In other words, if M is 2, then I is either 0 (for fall-through) or
+** 1 (for when the branch is taken). If M is 3, the I is 0 for an
+** ordinary fall-through, I is 1 if the branch was taken, and I is 2
+** if the result of comparison is NULL. For M=3, I=2 the jump may or
+** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5.
+** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2
+** depending on if the operands are less than, equal, or greater than.
**
** iSrcLine is the source code line (from the __LINE__ macro) that
-** generated the VDBE instruction. This instrumentation assumes that all
-** source code is in a single file (the amalgamation). Special values 1
-** and 2 for the iSrcLine parameter mean that this particular branch is
-** always taken or never taken, respectively.
+** generated the VDBE instruction combined with flag bits. The source
+** code line number is in the lower 24 bits of iSrcLine and the upper
+** 8 bytes are flags. The lower three bits of the flags indicate
+** values for I that should never occur. For example, if the branch is
+** always taken, the flags should be 0x05 since the fall-through and
+** alternate branch are never taken. If a branch is never taken then
+** flags should be 0x06 since only the fall-through approach is allowed.
+**
+** Bit 0x08 of the flags indicates an OP_Jump opcode that is only
+** interested in equal or not-equal. In other words, I==0 and I==2
+** should be treated as equivalent
+**
+** Since only a line number is retained, not the filename, this macro
+** only works for amalgamation builds. But that is ok, since these macros
+** should be no-ops except for special builds used to measure test coverage.
*/
#if !defined(SQLITE_VDBE_COVERAGE)
# define VdbeBranchTaken(I,M)
#else
# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M)
- static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){
- if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){
- M = iSrcLine;
- /* Assert the truth of VdbeCoverageAlwaysTaken() and
- ** VdbeCoverageNeverTaken() */
- assert( (M & I)==I );
- }else{
- if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
- sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
- iSrcLine,I,M);
+ static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){
+ u8 mNever;
+ assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */
+ assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */
+ assert( I<M ); /* I can only be 2 if M is 3 or 4 */
+ /* Transform I from a integer [0,1,2] into a bitmask of [1,2,4] */
+ I = 1<<I;
+ /* The upper 8 bits of iSrcLine are flags. The lower three bits of
+ ** the flags indicate directions that the branch can never go. If
+ ** a branch really does go in one of those directions, assert right
+ ** away. */
+ mNever = iSrcLine >> 24;
+ assert( (I & mNever)==0 );
+ if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
+ /* Invoke the branch coverage callback with three arguments:
+ ** iSrcLine - the line number of the VdbeCoverage() macro, with
+ ** flags removed.
+ ** I - Mask of bits 0x07 indicating which cases are are
+ ** fulfilled by this instance of the jump. 0x01 means
+ ** fall-thru, 0x02 means taken, 0x04 means NULL. Any
+ ** impossible cases (ex: if the comparison is never NULL)
+ ** are filled in automatically so that the coverage
+ ** measurement logic does not flag those impossible cases
+ ** as missed coverage.
+ ** M - Type of jump. Same as M argument above
+ */
+ I |= mNever;
+ if( M==2 ) I |= 0x04;
+ if( M==4 ){
+ I |= 0x08;
+ if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/
}
+ sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
+ iSrcLine&0xffffff, I, M);
}
#endif
/*
-** Convert the given register into a string if it isn't one
-** already. Return non-zero if a malloc() fails.
-*/
-#define Stringify(P, enc) \
- if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \
- { goto no_mem; }
-
-/*
** An ephemeral string value (signified by the MEM_Ephem flag) contains
** a pointer to a dynamically allocated string where some other entity
** is responsible for deallocating that string. Because the register
@@ -77407,7 +85483,7 @@ static VdbeCursor *allocateCursor(
u8 eCurType /* Type of the new cursor */
){
/* Find the memory cell that will be used to store the blob of memory
- ** required for this VdbeCursor structure. It is convenient to use a
+ ** required for this VdbeCursor structure. It is convenient to use a
** vdbe memory cell to manage the memory allocation required for a
** VdbeCursor structure for the following reasons:
**
@@ -77428,18 +85504,23 @@ static VdbeCursor *allocateCursor(
int nByte;
VdbeCursor *pCx = 0;
- nByte =
- ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
+ nByte =
+ ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
assert( iCur>=0 && iCur<p->nCursor );
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
+ /* Before calling sqlite3VdbeFreeCursor(), ensure the isEphemeral flag
+ ** is clear. Otherwise, if this is an ephemeral cursor created by
+ ** OP_OpenDup, the cursor will not be closed and will still be part
+ ** of a BtShared.pCursor list. */
+ if( p->apCsr[iCur]->pBtx==0 ) p->apCsr[iCur]->isEphemeral = 0;
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
p->apCsr[iCur] = 0;
}
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
- memset(pCx, 0, sizeof(VdbeCursor));
+ memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
pCx->eCurType = eCurType;
pCx->iDb = iDb;
pCx->nField = nField;
@@ -77454,6 +85535,21 @@ static VdbeCursor *allocateCursor(
}
/*
+** The string in pRec is known to look like an integer and to have a
+** floating point value of rValue. Return true and set *piValue to the
+** integer value if the string is in range to be an integer. Otherwise,
+** return false.
+*/
+static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
+ i64 iValue = (double)rValue;
+ if( sqlite3RealSameAsInt(rValue,iValue) ){
+ *piValue = iValue;
+ return 1;
+ }
+ return 0==sqlite3Atoi64(pRec->z, piValue, pRec->n, pRec->enc);
+}
+
+/*
** Try to convert a value into a numeric representation if we can
** do so without loss of information. In other words, if the string
** looks like a number, convert it into a number. If it does not
@@ -77470,18 +85566,23 @@ static VdbeCursor *allocateCursor(
*/
static void applyNumericAffinity(Mem *pRec, int bTryForInt){
double rValue;
- i64 iValue;
u8 enc = pRec->enc;
- assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str );
- if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
- if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
- pRec->u.i = iValue;
+ int rc;
+ assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str );
+ rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc);
+ if( rc<=0 ) return;
+ if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){
pRec->flags |= MEM_Int;
}else{
pRec->u.r = rValue;
pRec->flags |= MEM_Real;
if( bTryForInt ) sqlite3VdbeIntegerAffinity(pRec);
}
+ /* TEXT->NUMERIC is many->one. Hence, it is important to invalidate the
+ ** string representation after computing a numeric equivalent, because the
+ ** string representation might not be the canonical representation for the
+ ** numeric value. Ticket [343634942dd54ab57b7024] 2018-01-31. */
+ pRec->flags &= ~MEM_Str;
}
/*
@@ -77490,7 +85591,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
** SQLITE_AFF_INTEGER:
** SQLITE_AFF_REAL:
** SQLITE_AFF_NUMERIC:
-** Try to convert pRec to an integer representation or a
+** Try to convert pRec to an integer representation or a
** floating-point representation if an integer representation
** is not possible. Note that the integer representation is
** always preferred, even if the affinity is REAL, because
@@ -77500,6 +85601,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
** Convert pRec to a text representation.
**
** SQLITE_AFF_BLOB:
+** SQLITE_AFF_NONE:
** No-op. pRec is unchanged.
*/
static void applyAffinity(
@@ -77520,15 +85622,18 @@ static void applyAffinity(
}else if( affinity==SQLITE_AFF_TEXT ){
/* Only attempt the conversion to TEXT if there is an integer or real
** representation (blob and NULL do not get converted) but no string
- ** representation. It would be harmless to repeat the conversion if
+ ** representation. It would be harmless to repeat the conversion if
** there is already a string rep, but it is pointless to waste those
** CPU cycles. */
if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
- if( (pRec->flags&(MEM_Real|MEM_Int)) ){
+ if( (pRec->flags&(MEM_Real|MEM_Int|MEM_IntReal)) ){
+ testcase( pRec->flags & MEM_Int );
+ testcase( pRec->flags & MEM_Real );
+ testcase( pRec->flags & MEM_IntReal );
sqlite3VdbeMemStringify(pRec, enc, 1);
}
}
- pRec->flags &= ~(MEM_Real|MEM_Int);
+ pRec->flags &= ~(MEM_Real|MEM_Int|MEM_IntReal);
}
}
@@ -77549,12 +85654,12 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
}
/*
-** Exported version of applyAffinity(). This one works on sqlite3_value*,
+** Exported version of applyAffinity(). This one works on sqlite3_value*,
** not the internal Mem* type.
*/
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
- sqlite3_value *pVal,
- u8 affinity,
+ sqlite3_value *pVal,
+ u8 affinity,
u8 enc
){
applyAffinity((Mem *)pVal, affinity, enc);
@@ -77567,12 +85672,21 @@ SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
** accordingly.
*/
static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
- assert( (pMem->flags & (MEM_Int|MEM_Real))==0 );
+ int rc;
+ sqlite3_int64 ix;
+ assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 );
assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 );
- if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){
- return 0;
- }
- if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
+ ExpandBlob(pMem);
+ rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
+ if( rc<=0 ){
+ if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
+ pMem->u.i = ix;
+ return MEM_Int;
+ }else{
+ return MEM_Real;
+ }
+ }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){
+ pMem->u.i = ix;
return MEM_Int;
}
return MEM_Real;
@@ -77580,16 +85694,21 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
/*
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
-** none.
+** none.
**
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
- if( pMem->flags & (MEM_Int|MEM_Real) ){
- return pMem->flags & (MEM_Int|MEM_Real);
+ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){
+ testcase( pMem->flags & MEM_Int );
+ testcase( pMem->flags & MEM_Real );
+ testcase( pMem->flags & MEM_IntReal );
+ return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal);
}
if( pMem->flags & (MEM_Str|MEM_Blob) ){
+ testcase( pMem->flags & MEM_Str );
+ testcase( pMem->flags & MEM_Blob );
return computeNumericType(pMem);
}
return 0;
@@ -77600,12 +85719,9 @@ static u16 numericType(Mem *pMem){
** Write a nice string representation of the contents of cell pMem
** into buffer zBuf, length nBuf.
*/
-SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
- char *zCsr = zBuf;
+SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
int f = pMem->flags;
-
static const char *const encnames[] = {"(X)", "(8)", "(16LE)", "(16BE)"};
-
if( f&MEM_Blob ){
int i;
char c;
@@ -77621,59 +85737,40 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
}else{
c = 's';
}
-
- sqlite3_snprintf(100, zCsr, "%c", c);
- zCsr += sqlite3Strlen30(zCsr);
- sqlite3_snprintf(100, zCsr, "%d[", pMem->n);
- zCsr += sqlite3Strlen30(zCsr);
- for(i=0; i<16 && i<pMem->n; i++){
- sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
- zCsr += sqlite3Strlen30(zCsr);
+ sqlite3_str_appendf(pStr, "%cx[", c);
+ for(i=0; i<25 && i<pMem->n; i++){
+ sqlite3_str_appendf(pStr, "%02X", ((int)pMem->z[i] & 0xFF));
}
- for(i=0; i<16 && i<pMem->n; i++){
+ sqlite3_str_appendf(pStr, "|");
+ for(i=0; i<25 && i<pMem->n; i++){
char z = pMem->z[i];
- if( z<32 || z>126 ) *zCsr++ = '.';
- else *zCsr++ = z;
+ sqlite3_str_appendchar(pStr, 1, (z<32||z>126)?'.':z);
}
-
- sqlite3_snprintf(100, zCsr, "]%s", encnames[pMem->enc]);
- zCsr += sqlite3Strlen30(zCsr);
+ sqlite3_str_appendf(pStr,"]");
if( f & MEM_Zero ){
- sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero);
- zCsr += sqlite3Strlen30(zCsr);
+ sqlite3_str_appendf(pStr, "+%dz",pMem->u.nZero);
}
- *zCsr = '\0';
}else if( f & MEM_Str ){
- int j, k;
- zBuf[0] = ' ';
+ int j;
+ u8 c;
if( f & MEM_Dyn ){
- zBuf[1] = 'z';
+ c = 'z';
assert( (f & (MEM_Static|MEM_Ephem))==0 );
}else if( f & MEM_Static ){
- zBuf[1] = 't';
+ c = 't';
assert( (f & (MEM_Dyn|MEM_Ephem))==0 );
}else if( f & MEM_Ephem ){
- zBuf[1] = 'e';
+ c = 'e';
assert( (f & (MEM_Static|MEM_Dyn))==0 );
}else{
- zBuf[1] = 's';
+ c = 's';
}
- k = 2;
- sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n);
- k += sqlite3Strlen30(&zBuf[k]);
- zBuf[k++] = '[';
- for(j=0; j<15 && j<pMem->n; j++){
- u8 c = pMem->z[j];
- if( c>=0x20 && c<0x7f ){
- zBuf[k++] = c;
- }else{
- zBuf[k++] = '.';
- }
+ sqlite3_str_appendf(pStr, " %c%d[", c, pMem->n);
+ for(j=0; j<25 && j<pMem->n; j++){
+ c = pMem->z[j];
+ sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
}
- zBuf[k++] = ']';
- sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]);
- k += sqlite3Strlen30(&zBuf[k]);
- zBuf[k++] = 0;
+ sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
}
}
#endif
@@ -77686,32 +85783,52 @@ static void memTracePrint(Mem *p){
if( p->flags & MEM_Undefined ){
printf(" undefined");
}else if( p->flags & MEM_Null ){
- printf(" NULL");
+ printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL");
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
printf(" si:%lld", p->u.i);
+ }else if( (p->flags & (MEM_IntReal))!=0 ){
+ printf(" ir:%lld", p->u.i);
}else if( p->flags & MEM_Int ){
printf(" i:%lld", p->u.i);
#ifndef SQLITE_OMIT_FLOATING_POINT
}else if( p->flags & MEM_Real ){
- printf(" r:%g", p->u.r);
+ printf(" r:%.17g", p->u.r);
#endif
- }else if( p->flags & MEM_RowSet ){
+ }else if( sqlite3VdbeMemIsRowSet(p) ){
printf(" (rowset)");
}else{
- char zBuf[200];
- sqlite3VdbeMemPrettyPrint(p, zBuf);
- printf(" %s", zBuf);
+ StrAccum acc;
+ char zBuf[1000];
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3VdbeMemPrettyPrint(p, &acc);
+ printf(" %s", sqlite3StrAccumFinish(&acc));
}
if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype);
}
static void registerTrace(int iReg, Mem *p){
- printf("REG[%d] = ", iReg);
+ printf("R[%d] = ", iReg);
memTracePrint(p);
+ if( p->pScopyFrom ){
+ printf(" <== R[%d]", (int)(p->pScopyFrom - &p[-iReg]));
+ }
printf("\n");
+ sqlite3VdbeCheckMemInvariants(p);
}
#endif
#ifdef SQLITE_DEBUG
+/*
+** Show the values of all registers in the virtual machine. Used for
+** interactive debugging.
+*/
+SQLITE_PRIVATE void sqlite3VdbeRegisterDump(Vdbe *v){
+ int i;
+ for(i=1; i<v->nMem; i++) registerTrace(i, v->aMem+i);
+}
+#endif /* SQLITE_DEBUG */
+
+
+#ifdef SQLITE_DEBUG
# define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M)
#else
# define REGISTER_TRACE(R,M)
@@ -77720,8 +85837,8 @@ static void registerTrace(int iReg, Mem *p){
#ifdef VDBE_PROFILE
-/*
-** hwtime.h contains inline assembler code for implementing
+/*
+** hwtime.h contains inline assembler code for implementing
** high-performance timing routines.
*/
/************** Include hwtime.h in the middle of vdbe.c *********************/
@@ -77739,7 +85856,7 @@ static void registerTrace(int iReg, Mem *p){
******************************************************************************
**
** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 class CPUs.
+** counters for x86 and x86_64 class CPUs.
*/
#ifndef SQLITE_HWTIME_H
#define SQLITE_HWTIME_H
@@ -77750,8 +85867,9 @@ static void registerTrace(int iReg, Mem *p){
** processor and returns that value. This can be used for high-res
** profiling.
*/
-#if (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
#if defined(__GNUC__)
@@ -77772,15 +85890,15 @@ static void registerTrace(int iReg, Mem *p){
#endif
-#elif (defined(__GNUC__) && defined(__x86_64__))
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long val;
__asm__ __volatile__ ("rdtsc" : "=A" (val));
return val;
}
-
-#elif (defined(__GNUC__) && defined(__ppc__))
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
__inline__ sqlite_uint64 sqlite3Hwtime(void){
unsigned long long retval;
@@ -77797,14 +85915,13 @@ static void registerTrace(int iReg, Mem *p){
#else
- #error Need implementation of sqlite3Hwtime() for your platform.
-
/*
- ** To compile without implementing sqlite3Hwtime() for your platform,
- ** you can remove the above #error and use the following
- ** stub function. You will lose timing support for many
- ** of the debugging and testing utilities, but it should at
- ** least compile and run.
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlite3Hwtime() routine.
+ **
+ ** sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
*/
SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
@@ -77821,9 +85938,9 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
/*
** This function is only called from within an assert() expression. It
** checks that the sqlite3.nTransaction variable is correctly set to
-** the number of non-transaction savepoints currently in the
+** the number of non-transaction savepoints currently in the
** linked list starting at sqlite3.pSavepoint.
-**
+**
** Usage:
**
** assert( checkSavepointCount(db) );
@@ -77863,7 +85980,7 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
/*
** Execute as much of a VDBE program as we can.
-** This is the core of sqlite3_step().
+** This is the core of sqlite3_step().
*/
SQLITE_PRIVATE int sqlite3VdbeExec(
Vdbe *p /* The VDBE */
@@ -77881,17 +85998,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
int iCompare = 0; /* Result of last comparison */
- unsigned nVmStep = 0; /* Number of virtual machine steps */
+ u64 nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
+ u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
Mem *pOut = 0; /* Output operand */
- 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 */
#endif
@@ -77899,27 +86014,30 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
sqlite3VdbeEnter(p);
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( db->xProgress ){
+ u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
+ assert( 0 < db->nProgressOps );
+ nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
+ }else{
+ nProgressLimit = LARGEST_UINT64;
+ }
+#endif
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
goto no_mem;
}
assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
- assert( p->bIsReader || p->readOnly!=0 );
+ testcase( p->rc!=SQLITE_OK );
p->rc = SQLITE_OK;
+ assert( p->bIsReader || p->readOnly!=0 );
p->iCurrentTime = 0;
assert( p->explain==0 );
p->pResultSet = 0;
db->busyHandler.nBusy = 0;
- if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
+ if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
sqlite3VdbeIOTraceSql(p);
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- if( db->xProgress ){
- u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
- assert( 0 < db->nProgressOps );
- nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
- }
-#endif
#ifdef SQLITE_DEBUG
sqlite3BeginBenignMalloc();
if( p->pc==0
@@ -77954,7 +86072,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
#ifdef VDBE_PROFILE
- start = sqlite3Hwtime();
+ start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
#endif
nVmStep++;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -77966,9 +86084,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
sqlite3VdbePrintOp(stdout, (int)(pOp - aOp), pOp);
+ test_trace_breakpoint((int)(pOp - aOp),pOp,p);
}
#endif
-
+
/* Check to see if we need to simulate an interrupt. This only happens
** if we have a special test build.
@@ -78022,7 +86141,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
pOrigOp = pOp;
#endif
-
+
switch( pOp->opcode ){
/*****************************************************************************
@@ -78063,7 +86182,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
/* Opcode: Goto * P2 * * *
**
** An unconditional jump to address P2.
-** The next instruction executed will be
+** The next instruction executed will be
** the one at index P2 from the beginning of
** the program.
**
@@ -78073,13 +86192,27 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
** to the current line should be indented for EXPLAIN output.
*/
case OP_Goto: { /* jump */
+
+#ifdef SQLITE_DEBUG
+ /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
+ ** means we should really jump back to the preceeding OP_ReleaseReg
+ ** instruction. */
+ if( pOp->p5 ){
+ assert( pOp->p2 < (int)(pOp - aOp) );
+ assert( pOp->p2 > 1 );
+ pOp = &aOp[pOp->p2 - 2];
+ assert( pOp[1].opcode==OP_ReleaseReg );
+ goto check_for_interrupt;
+ }
+#endif
+
jump_to_p2_and_check_for_interrupt:
pOp = &aOp[pOp->p2 - 1];
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
- ** OP_VNext, OP_RowSetNext, or OP_SorterNext) all jump here upon
+ ** OP_VNext, or OP_SorterNext) all jump here upon
** completion. Check to see if sqlite3_interrupt() has been called
- ** or if the progress callback needs to be invoked.
+ ** or if the progress callback needs to be invoked.
**
** This code uses unstructured "goto" statements and does not look clean.
** But that is not due to sloppy coding habits. The code is written this
@@ -78087,7 +86220,7 @@ jump_to_p2_and_check_for_interrupt:
** checks on every opcode. This helps sqlite3_step() to run about 1.5%
** faster according to "valgrind --tool=cachegrind" */
check_for_interrupt:
- if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
+ if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
/* Call the progress callback if it is configured and the required number
** of VDBE ops have been executed (either since this invocation of
@@ -78095,16 +86228,17 @@ check_for_interrupt:
** If the progress callback returns non-zero, exit the virtual machine with
** a return code SQLITE_ABORT.
*/
- if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
+ while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
assert( db->nProgressOps!=0 );
- nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
+ nProgressLimit += db->nProgressOps;
if( db->xProgress(db->pProgressArg) ){
+ nProgressLimit = LARGEST_UINT64;
rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
}
#endif
-
+
break;
}
@@ -78221,8 +86355,12 @@ case OP_Yield: { /* in1, jump */
*/
case OP_HaltIfNull: { /* in3 */
pIn3 = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+ if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
+#endif
if( (pIn3->flags & MEM_Null)==0 ) break;
/* Fall through into OP_Halt */
+ /* no break */ deliberate_fall_through
}
/* Opcode: Halt P1 P2 * P4 P5
@@ -78236,7 +86374,7 @@ case OP_HaltIfNull: { /* in3 */
** whether or not to rollback the current transaction. Do not rollback
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort,
** then back out all changes that have occurred during this execution of the
-** VDBE, but do not rollback the transaction.
+** VDBE, but do not rollback the transaction.
**
** If P4 is not null then it is an error message string.
**
@@ -78260,6 +86398,9 @@ case OP_Halt: {
int pcx;
pcx = (int)(pOp - aOp);
+#ifdef SQLITE_DEBUG
+ if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
+#endif
if( pOp->p1==SQLITE_OK && p->pFrame ){
/* Halt the sub-program. Return control to the parent frame. */
pFrame = p->pFrame;
@@ -78267,9 +86408,8 @@ case OP_Halt: {
p->nFrame--;
sqlite3VdbeSetChanges(db, p->nChange);
pcx = sqlite3VdbeFrameRestore(pFrame);
- lastRowid = db->lastRowid;
if( pOp->p2==OE_Ignore ){
- /* Instruction pcx is the OP_Program that invoked the sub-program
+ /* Instruction pcx is the OP_Program that invoked the sub-program
** currently being halted. If the p2 instruction of this OP_Halt
** instruction is set to OE_Ignore, then the sub-program is throwing
** an IGNORE exception. In this case jump to the address specified
@@ -78284,7 +86424,7 @@ case OP_Halt: {
p->rc = pOp->p1;
p->errorAction = (u8)pOp->p2;
p->pc = pcx;
- assert( pOp->p5>=0 && pOp->p5<=4 );
+ assert( pOp->p5<=4 );
if( p->rc ){
if( pOp->p5 ){
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
@@ -78357,7 +86497,7 @@ case OP_Real: { /* same as TK_FLOAT, out2 */
/* Opcode: String8 * P2 * P4 *
** Synopsis: r[P2]='P4'
**
-** P4 points to a nul terminated UTF-8 string. This opcode is transformed
+** P4 points to a nul terminated UTF-8 string. This opcode is transformed
** into a String opcode before it is executed for the first time. During
** this transformation, the length of string P4 is computed and stored
** as the P1 parameter.
@@ -78365,13 +86505,13 @@ case OP_Real: { /* same as TK_FLOAT, out2 */
case OP_String8: { /* same as TK_STRING, out2 */
assert( pOp->p4.z!=0 );
pOut = out2Prerelease(p, pOp);
- pOp->opcode = OP_String;
pOp->p1 = sqlite3Strlen30(pOp->p4.z);
#ifndef SQLITE_OMIT_UTF16
if( encoding!=SQLITE_UTF8 ){
rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG );
+ if( rc ) goto too_big;
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
assert( VdbeMemDynamic(pOut)==0 );
@@ -78384,15 +86524,16 @@ case OP_String8: { /* same as TK_STRING, out2 */
pOp->p4.z = pOut->z;
pOp->p1 = pOut->n;
}
- testcase( rc==SQLITE_TOOBIG );
#endif
if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
+ pOp->opcode = OP_String;
assert( rc==SQLITE_OK );
/* Fall through to the next case, OP_String */
+ /* no break */ deliberate_fall_through
}
-
+
/* Opcode: String P1 P2 P3 P4 P5
** Synopsis: r[P2]='P4' (len=P1)
**
@@ -78444,6 +86585,9 @@ case OP_Null: { /* out2 */
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
pOut->n = 0;
+#ifdef SQLITE_DEBUG
+ pOut->uTemp = 0;
+#endif
while( cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
@@ -78466,7 +86610,7 @@ case OP_Null: { /* out2 */
case OP_SoftNull: {
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
pOut = &aMem[pOp->p1];
- pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
+ pOut->flags = (pOut->flags&~(MEM_Undefined|MEM_AffMask))|MEM_Null;
break;
}
@@ -78497,13 +86641,16 @@ case OP_Variable: { /* out2 */
Mem *pVar; /* Value being transferred */
assert( pOp->p1>0 && pOp->p1<=p->nVar );
- assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
+ assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) );
pVar = &p->aVar[pOp->p1 - 1];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
}
- pOut = out2Prerelease(p, pOp);
- sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
+ pOut = &aMem[pOp->p2];
+ if( VdbeMemDynamic(pOut) ) sqlite3VdbeMemSetNull(pOut);
+ memcpy(pOut, pVar, MEMCELLSIZE);
+ pOut->flags &= ~(MEM_Dyn|MEM_Ephem);
+ pOut->flags |= MEM_Static|MEM_FromBind;
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -78537,8 +86684,13 @@ case OP_Move: {
memAboutToChange(p, pOut);
sqlite3VdbeMemMove(pOut, pIn1);
#ifdef SQLITE_DEBUG
- if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<pOut ){
- pOut->pScopyFrom += pOp->p2 - p1;
+ pIn1->pScopyFrom = 0;
+ { int i;
+ for(i=1; i<p->nMem; i++){
+ if( aMem[i].pScopyFrom==pIn1 ){
+ aMem[i].pScopyFrom = pOut;
+ }
+ }
}
#endif
Deephemeralize(pOut);
@@ -78565,6 +86717,7 @@ case OP_Copy: {
pOut = &aMem[pOp->p2];
assert( pOut!=pIn1 );
while( 1 ){
+ memAboutToChange(p, pOut);
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
Deephemeralize(pOut);
#ifdef SQLITE_DEBUG
@@ -78597,7 +86750,8 @@ case OP_SCopy: { /* out2 */
assert( pOut!=pIn1 );
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
#ifdef SQLITE_DEBUG
- if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
+ pOut->pScopyFrom = pIn1;
+ pOut->mScopyFlags = pIn1->flags;
#endif
break;
}
@@ -78634,18 +86788,6 @@ case OP_ResultRow: {
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- /* Run the progress counter just before returning.
- */
- if( db->xProgress!=0
- && nVmStep>=nProgressLimit
- && db->xProgress(db->pProgressArg)!=0
- ){
- rc = SQLITE_INTERRUPT;
- goto abort_due_to_error;
- }
-#endif
-
/* If this statement has violated immediate foreign key constraints, do
** not return the number of rows modified. And do not RELEASE the statement
** transaction. It needs to be rolled back. */
@@ -78655,8 +86797,8 @@ case OP_ResultRow: {
goto abort_due_to_error;
}
- /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
- ** DML statements invoke this opcode to return the number of rows
+ /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
+ ** DML statements invoke this opcode to return the number of rows
** modified to the user. This is the only way that a VM that
** opens a statement transaction may invoke this opcode.
**
@@ -78689,13 +86831,22 @@ case OP_ResultRow: {
|| (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
sqlite3VdbeMemNulTerminate(&pMem[i]);
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
+#ifdef SQLITE_DEBUG
+ /* The registers in the result will not be used again when the
+ ** prepared statement restarts. This is because sqlite3_column()
+ ** APIs might have caused type conversions of made other changes to
+ ** the register values. Therefore, we can go ahead and break any
+ ** OP_SCopy dependencies. */
+ pMem[i].pScopyFrom = 0;
+#endif
}
if( db->mallocFailed ) goto no_mem;
if( db->mTrace & SQLITE_TRACE_ROW ){
- db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
+ db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
}
+
/* Return SQLITE_ROW
*/
p->pc = (int)(pOp - aOp) + 1;
@@ -78717,33 +86868,56 @@ case OP_ResultRow: {
** to avoid a memcpy().
*/
case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
- i64 nByte;
+ i64 nByte; /* Total size of the output string or blob */
+ u16 flags1; /* Initial flags for P1 */
+ u16 flags2; /* Initial flags for P2 */
pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2];
pOut = &aMem[pOp->p3];
+ testcase( pOut==pIn2 );
assert( pIn1!=pOut );
- if( (pIn1->flags | pIn2->flags) & MEM_Null ){
+ flags1 = pIn1->flags;
+ testcase( flags1 & MEM_Null );
+ testcase( pIn2->flags & MEM_Null );
+ if( (flags1 | pIn2->flags) & MEM_Null ){
sqlite3VdbeMemSetNull(pOut);
break;
}
- if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem;
- Stringify(pIn1, encoding);
- Stringify(pIn2, encoding);
+ if( (flags1 & (MEM_Str|MEM_Blob))==0 ){
+ if( sqlite3VdbeMemStringify(pIn1,encoding,0) ) goto no_mem;
+ flags1 = pIn1->flags & ~MEM_Str;
+ }else if( (flags1 & MEM_Zero)!=0 ){
+ if( sqlite3VdbeMemExpandBlob(pIn1) ) goto no_mem;
+ flags1 = pIn1->flags & ~MEM_Str;
+ }
+ flags2 = pIn2->flags;
+ if( (flags2 & (MEM_Str|MEM_Blob))==0 ){
+ if( sqlite3VdbeMemStringify(pIn2,encoding,0) ) goto no_mem;
+ flags2 = pIn2->flags & ~MEM_Str;
+ }else if( (flags2 & MEM_Zero)!=0 ){
+ if( sqlite3VdbeMemExpandBlob(pIn2) ) goto no_mem;
+ flags2 = pIn2->flags & ~MEM_Str;
+ }
nByte = pIn1->n + pIn2->n;
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
- if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){
+ if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){
goto no_mem;
}
MemSetTypeFlag(pOut, MEM_Str);
if( pOut!=pIn2 ){
memcpy(pOut->z, pIn2->z, pIn2->n);
+ assert( (pIn2->flags & MEM_Dyn) == (flags2 & MEM_Dyn) );
+ pIn2->flags = flags2;
}
memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n);
+ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
+ pIn1->flags = flags1;
pOut->z[nByte]=0;
pOut->z[nByte+1] = 0;
+ pOut->z[nByte+2] = 0;
pOut->flags |= MEM_Term;
pOut->n = (int)nByte;
pOut->enc = encoding;
@@ -78777,15 +86951,15 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
** Synopsis: r[P3]=r[P2]/r[P1]
**
** Divide the value in register P1 by the value in register P2
-** and store the result in register P3 (P3=P2/P1). If the value in
-** register P1 is zero, then the result is NULL. If either input is
+** and store the result in register P3 (P3=P2/P1). If the value in
+** register P1 is zero, then the result is NULL. If either input is
** NULL, the result is NULL.
*/
/* Opcode: Remainder P1 P2 P3 * *
** Synopsis: r[P3]=r[P2]%r[P1]
**
-** Compute the remainder after integer register P2 is divided by
-** register P1 and store the result in register P3.
+** Compute the remainder after integer register P2 is divided by
+** register P1 and store the result in register P3.
** If the value in register P1 is zero the result is NULL.
** If either operand is NULL, the result is NULL.
*/
@@ -78794,7 +86968,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
- char bIntint; /* Started out as two integer operands */
u16 flags; /* Combined MEM_* flags from both inputs */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
@@ -78809,11 +86982,9 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
type2 = numericType(pIn2);
pOut = &aMem[pOp->p3];
flags = pIn1->flags | pIn2->flags;
- if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (type1 & type2 & MEM_Int)!=0 ){
iA = pIn1->u.i;
iB = pIn2->u.i;
- bIntint = 1;
switch( pOp->opcode ){
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
@@ -78833,8 +87004,9 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
+ }else if( (flags & MEM_Null)!=0 ){
+ goto arithmetic_result_is_null;
}else{
- bIntint = 0;
fp_math:
rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2);
@@ -78849,8 +87021,8 @@ fp_math:
break;
}
default: {
- iA = (i64)rA;
- iB = (i64)rB;
+ iA = sqlite3VdbeIntValue(pIn1);
+ iB = sqlite3VdbeIntValue(pIn2);
if( iA==0 ) goto arithmetic_result_is_null;
if( iA==-1 ) iA = 1;
rB = (double)(iB % iA);
@@ -78866,9 +87038,6 @@ fp_math:
}
pOut->u.r = rB;
MemSetTypeFlag(pOut, MEM_Real);
- if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
- sqlite3VdbeIntegerAffinity(pOut);
- }
#endif
}
break;
@@ -78880,7 +87049,7 @@ arithmetic_result_is_null:
/* Opcode: CollSeq P1 * * P4
**
-** P4 is a pointer to a CollSeq struct. If the next call to a user function
+** P4 is a pointer to a CollSeq object. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** functions.
@@ -78901,119 +87070,6 @@ case OP_CollSeq: {
break;
}
-/* Opcode: Function0 P1 P2 P3 P4 P5
-** Synopsis: r[P3]=func(r[P2@P5])
-**
-** Invoke a user function (P4 is a pointer to a FuncDef object that
-** defines the function) with P5 arguments taken from register P2 and
-** successors. The result of the function is stored in register P3.
-** Register P3 must not be one of the function inputs.
-**
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
-** function was determined to be constant at compile time. If the first
-** argument was constant then bit 0 of P1 is set. This is used to determine
-** whether meta data associated with a user function argument using the
-** sqlite3_set_auxdata() API may be safely retained until the next
-** invocation of this opcode.
-**
-** See also: Function, AggStep, AggFinal
-*/
-/* Opcode: Function P1 P2 P3 P4 P5
-** Synopsis: r[P3]=func(r[P2@P5])
-**
-** Invoke a user function (P4 is a pointer to an sqlite3_context object that
-** contains a pointer to the function to be run) with P5 arguments taken
-** from register P2 and successors. The result of the function is stored
-** in register P3. Register P3 must not be one of the function inputs.
-**
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
-** function was determined to be constant at compile time. If the first
-** argument was constant then bit 0 of P1 is set. This is used to determine
-** whether meta data associated with a user function argument using the
-** sqlite3_set_auxdata() API may be safely retained until the next
-** invocation of this opcode.
-**
-** SQL functions are initially coded as OP_Function0 with P4 pointing
-** to a FuncDef object. But on first evaluation, the P4 operand is
-** automatically converted into an sqlite3_context object and the operation
-** changed to this OP_Function opcode. In this way, the initialization of
-** the sqlite3_context object occurs only once, rather than once for each
-** evaluation of the function.
-**
-** See also: Function0, AggStep, AggFinal
-*/
-case OP_Function0: {
- int n;
- sqlite3_context *pCtx;
-
- assert( pOp->p4type==P4_FUNCDEF );
- n = pOp->p5;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
- assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
- pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
- if( pCtx==0 ) goto no_mem;
- pCtx->pOut = 0;
- pCtx->pFunc = pOp->p4.pFunc;
- pCtx->iOp = (int)(pOp - aOp);
- pCtx->pVdbe = p;
- pCtx->argc = n;
- pOp->p4type = P4_FUNCCTX;
- pOp->p4.pCtx = pCtx;
- pOp->opcode = OP_Function;
- /* Fall through into OP_Function */
-}
-case OP_Function: {
- int i;
- sqlite3_context *pCtx;
-
- assert( pOp->p4type==P4_FUNCCTX );
- pCtx = pOp->p4.pCtx;
-
- /* If this function is inside of a trigger, the register array in aMem[]
- ** might change from one evaluation to the next. The next block of code
- ** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
- pOut = &aMem[pOp->p3];
- if( pCtx->pOut != pOut ){
- pCtx->pOut = pOut;
- for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
- }
-
- memAboutToChange(p, pCtx->pOut);
-#ifdef SQLITE_DEBUG
- for(i=0; i<pCtx->argc; i++){
- assert( memIsValid(pCtx->argv[i]) );
- REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
- }
-#endif
- MemSetTypeFlag(pCtx->pOut, MEM_Null);
- pCtx->fErrorOrAux = 0;
- db->lastRowid = lastRowid;
- (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
- lastRowid = db->lastRowid; /* Remember rowid changes made by xSFunc */
-
- /* If the function returned an error, throw an exception */
- if( pCtx->fErrorOrAux ){
- if( pCtx->isError ){
- sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
- rc = pCtx->isError;
- }
- sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
- if( rc ) goto abort_due_to_error;
- }
-
- /* Copy the result of the function into register P3 */
- if( pOut->flags & (MEM_Str|MEM_Blob) ){
- sqlite3VdbeChangeEncoding(pCtx->pOut, encoding);
- if( sqlite3VdbeMemTooBig(pCtx->pOut) ) goto too_big;
- }
-
- REGISTER_TRACE(pOp->p3, pCtx->pOut);
- UPDATE_MAX_BLOBSIZE(pCtx->pOut);
- break;
-}
-
/* Opcode: BitAnd P1 P2 P3 * *
** Synopsis: r[P3]=r[P1]&r[P2]
**
@@ -79098,7 +87154,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
/* Opcode: AddImm P1 P2 * * *
** Synopsis: r[P1]=r[P1]+P2
-**
+**
** Add the constant P2 to the value in register P1.
** The result is always an integer.
**
@@ -79113,7 +87169,7 @@ case OP_AddImm: { /* in1 */
}
/* Opcode: MustBeInt P1 P2 * * *
-**
+**
** Force the value in register P1 to be an integer. If the value
** in P1 is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
@@ -79123,8 +87179,8 @@ case OP_MustBeInt: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_Int)==0 ){
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
- VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2);
if( (pIn1->flags & MEM_Int)==0 ){
+ VdbeBranchTaken(1, 2);
if( pOp->p2==0 ){
rc = SQLITE_MISMATCH;
goto abort_due_to_error;
@@ -79133,6 +87189,7 @@ case OP_MustBeInt: { /* jump, in1 */
}
}
}
+ VdbeBranchTaken(0, 2);
MemSetTypeFlag(pIn1, MEM_Int);
break;
}
@@ -79149,8 +87206,11 @@ case OP_MustBeInt: { /* jump, in1 */
*/
case OP_RealAffinity: { /* in1 */
pIn1 = &aMem[pOp->p1];
- if( pIn1->flags & MEM_Int ){
+ if( pIn1->flags & (MEM_Int|MEM_IntReal) ){
+ testcase( pIn1->flags & MEM_Int );
+ testcase( pIn1->flags & MEM_IntReal );
sqlite3VdbeMemRealify(pIn1);
+ REGISTER_TRACE(pOp->p1, pIn1);
}
break;
}
@@ -79161,13 +87221,13 @@ case OP_RealAffinity: { /* in1 */
** Synopsis: affinity(r[P1])
**
** Force the value in register P1 to be the type defined by P2.
-**
+**
** <ul>
-** <li value="97"> TEXT
-** <li value="98"> BLOB
-** <li value="99"> NUMERIC
-** <li value="100"> INTEGER
-** <li value="101"> REAL
+** <li> P2=='A' &rarr; BLOB
+** <li> P2=='B' &rarr; TEXT
+** <li> P2=='C' &rarr; NUMERIC
+** <li> P2=='D' &rarr; INTEGER
+** <li> P2=='E' &rarr; REAL
** </ul>
**
** A NULL value is not changed by this routine. It remains NULL.
@@ -79182,9 +87242,11 @@ case OP_Cast: { /* in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
rc = ExpandBlob(pIn1);
- sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
- UPDATE_MAX_BLOBSIZE(pIn1);
if( rc ) goto abort_due_to_error;
+ rc = sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
+ if( rc ) goto abort_due_to_error;
+ UPDATE_MAX_BLOBSIZE(pIn1);
+ REGISTER_TRACE(pOp->p1, pIn1);
break;
}
#endif /* SQLITE_OMIT_CAST */
@@ -79197,14 +87259,14 @@ case OP_Cast: { /* in1 */
** store the result of comparison in register P2.
**
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
-** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
+** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
** to coerce both inputs according to this affinity before the
** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
** affinity is used. Note that the affinity conversions are stored
** back into the input registers P1 and P3. So this opcode can cause
** persistent changes to registers P1 and P3.
**
-** Once any conversions have taken place, and neither value is NULL,
+** Once any conversions have taken place, and neither value is NULL,
** the values are compared. If both values are blobs then memcmp() is
** used to determine the results of the comparison. If both values
** are text, then the appropriate collating function specified in
@@ -79243,18 +87305,18 @@ case OP_Cast: { /* in1 */
** the result of comparison (0 or 1 or NULL) into register P2.
**
** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
-** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL
+** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL
** bit is clear then fall through if either operand is NULL.
**
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
-** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
+** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
** to coerce both inputs according to this affinity before the
** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
** affinity is used. Note that the affinity conversions are stored
** back into the input registers P1 and P3. So this opcode can cause
** persistent changes to registers P1 and P3.
**
-** Once any conversions have taken place, and neither value is NULL,
+** Once any conversions have taken place, and neither value is NULL,
** the values are compared. If both values are blobs then memcmp() is
** used to determine the results of the comparison. If both values
** are text, then the appropriate collating function specified in
@@ -79307,16 +87369,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** OP_Eq or OP_Ne) then take the jump or not depending on whether
** or not both operands are null.
*/
- assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
assert( (flags1 & MEM_Cleared)==0 );
- assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 );
- if( (flags1&MEM_Null)!=0
- && (flags3&MEM_Null)!=0
+ assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 || CORRUPT_DB );
+ testcase( (pOp->p5 & SQLITE_JUMPIFNULL)!=0 );
+ if( (flags1&flags3&MEM_Null)!=0
&& (flags3&MEM_Cleared)==0
){
res = 0; /* Operands are equal */
}else{
- res = 1; /* Operands are not equal */
+ res = ((flags3 & MEM_Null) ? -1 : +1); /* Operands are not equal */
}
}else{
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
@@ -79342,12 +87403,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
affinity = pOp->p5 & SQLITE_AFF_MASK;
if( affinity>=SQLITE_AFF_NUMERIC ){
if( (flags1 | flags3)&MEM_Str ){
- if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn1,0);
- testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */
+ testcase( flags3==pIn3->flags );
flags3 = pIn3->flags;
}
- if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn3,0);
}
}
@@ -79360,17 +87421,19 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
goto compare_op;
}
}else if( affinity==SQLITE_AFF_TEXT ){
- if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){
+ if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
+ testcase( pIn1->flags & MEM_IntReal );
sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
- assert( pIn1!=pIn3 );
+ if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
}
- if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
+ if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
+ testcase( pIn3->flags & MEM_IntReal );
sqlite3VdbeMemStringify(pIn3, encoding, 1);
testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn) );
flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
@@ -79380,25 +87443,34 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
compare_op:
- switch( pOp->opcode ){
- case OP_Eq: res2 = res==0; break;
- case OP_Ne: res2 = res; break;
- case OP_Lt: res2 = res<0; break;
- case OP_Le: res2 = res<=0; break;
- case OP_Gt: res2 = res>0; break;
- default: res2 = res>=0; break;
+ /* At this point, res is negative, zero, or positive if reg[P1] is
+ ** less than, equal to, or greater than reg[P3], respectively. Compute
+ ** the answer to this operator in res2, depending on what the comparison
+ ** operator actually is. The next block of code depends on the fact
+ ** that the 6 comparison operators are consecutive integers in this
+ ** order: NE, EQ, GT, LE, LT, GE */
+ assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 );
+ assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 );
+ if( res<0 ){ /* ne, eq, gt, le, lt, ge */
+ static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 };
+ res2 = aLTb[pOp->opcode - OP_Ne];
+ }else if( res==0 ){
+ static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 };
+ res2 = aEQb[pOp->opcode - OP_Ne];
+ }else{
+ static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 };
+ res2 = aGTb[pOp->opcode - OP_Ne];
}
/* Undo any changes made by applyAffinity() to the input registers. */
- assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
- pIn1->flags = flags1;
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
pIn3->flags = flags3;
+ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
+ pIn1->flags = flags1;
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
iCompare = res;
- res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */
if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
** and prevents OP_Ne from overwriting NULL with 0. This flag
@@ -79420,7 +87492,7 @@ compare_op:
pOut->u.i = res2;
REGISTER_TRACE(pOp->p2, pOut);
}else{
- VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
+ VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
if( res2 ){
goto jump_to_p2;
}
@@ -79430,16 +87502,31 @@ compare_op:
/* Opcode: ElseNotEq * P2 * * *
**
-** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator.
-** If result of an OP_Eq comparison on the same two operands
-** would have be NULL or false (0), then then jump to P2.
-** If the result of an OP_Eq comparison on the two previous operands
-** would have been true (1), then fall through.
+** This opcode must follow an OP_Lt or OP_Gt comparison operator. There
+** can be zero or more OP_ReleaseReg opcodes intervening, but no other
+** opcodes are allowed to occur between this instruction and the previous
+** OP_Lt or OP_Gt. Furthermore, the prior OP_Lt or OP_Gt must have the
+** SQLITE_STOREP2 bit set in the P5 field.
+**
+** If result of an OP_Eq comparison on the same two operands as the
+** prior OP_Lt or OP_Gt would have been NULL or false (0), then then
+** jump to P2. If the result of an OP_Eq comparison on the two previous
+** operands would have been true (1), then fall through.
*/
case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
- assert( pOp>aOp );
- assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt );
- assert( pOp[-1].p5 & SQLITE_STOREP2 );
+
+#ifdef SQLITE_DEBUG
+ /* Verify the preconditions of this opcode - that it follows an OP_Lt or
+ ** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening
+ ** OP_ReleaseReg opcodes */
+ int iAddr;
+ for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){
+ if( aOp[iAddr].opcode==OP_ReleaseReg ) continue;
+ assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt );
+ assert( aOp[iAddr].p5 & SQLITE_STOREP2 );
+ break;
+ }
+#endif /* SQLITE_DEBUG */
VdbeBranchTaken(iCompare!=0, 2);
if( iCompare!=0 ) goto jump_to_p2;
break;
@@ -79448,11 +87535,11 @@ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
/* Opcode: Permutation * * * P4 *
**
-** Set the permutation used by the OP_Compare operator to be the array
-** of integers in P4.
+** Set the permutation used by the OP_Compare operator in the next
+** instruction. The permutation is stored in the P4 operand.
**
** The permutation is only valid until the next OP_Compare that has
-** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
+** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
** occur immediately prior to the OP_Compare.
**
** The first integer in the P4 integer array is the length of the array
@@ -79461,7 +87548,8 @@ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
case OP_Permutation: {
assert( pOp->p4type==P4_INTARRAY );
assert( pOp->p4.ai );
- aPermute = pOp->p4.ai + 1;
+ assert( pOp[1].opcode==OP_Compare );
+ assert( pOp[1].p5 & OPFLAG_PERMUTE );
break;
}
@@ -79491,21 +87579,30 @@ case OP_Compare: {
int p1;
int p2;
const KeyInfo *pKeyInfo;
- int idx;
+ u32 idx;
CollSeq *pColl; /* Collating sequence to use on this term */
int bRev; /* True for DESCENDING sort order */
+ u32 *aPermute; /* The permutation */
- if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
+ if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
+ aPermute = 0;
+ }else{
+ assert( pOp>aOp );
+ assert( pOp[-1].opcode==OP_Permutation );
+ assert( pOp[-1].p4type==P4_INTARRAY );
+ aPermute = pOp[-1].p4.ai + 1;
+ assert( aPermute!=0 );
+ }
n = pOp->p3;
pKeyInfo = pOp->p4.pKeyInfo;
assert( n>0 );
assert( pKeyInfo!=0 );
p1 = pOp->p1;
p2 = pOp->p2;
-#if SQLITE_DEBUG
+#ifdef SQLITE_DEBUG
if( aPermute ){
int k, mx = 0;
- for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
+ for(k=0; k<n; k++) if( aPermute[k]>(u32)mx ) mx = aPermute[k];
assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
}else{
@@ -79514,21 +87611,25 @@ case OP_Compare: {
}
#endif /* SQLITE_DEBUG */
for(i=0; i<n; i++){
- idx = aPermute ? aPermute[i] : i;
+ idx = aPermute ? aPermute[i] : (u32)i;
assert( memIsValid(&aMem[p1+idx]) );
assert( memIsValid(&aMem[p2+idx]) );
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
- assert( i<pKeyInfo->nField );
+ assert( i<pKeyInfo->nKeyField );
pColl = pKeyInfo->aColl[i];
- bRev = pKeyInfo->aSortOrder[i];
+ bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC);
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
if( iCompare ){
+ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
+ && ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null))
+ ){
+ iCompare = -iCompare;
+ }
if( bRev ) iCompare = -iCompare;
break;
}
}
- aPermute = 0;
break;
}
@@ -79540,11 +87641,11 @@ case OP_Compare: {
*/
case OP_Jump: { /* jump */
if( iCompare<0 ){
- VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1];
+ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
}else if( iCompare==0 ){
- VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1];
+ VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1];
}else{
- VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1];
+ VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1];
}
break;
}
@@ -79574,18 +87675,8 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
int v1; /* Left operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
int v2; /* Right operand: 0==FALSE, 1==TRUE, 2==UNKNOWN or NULL */
- pIn1 = &aMem[pOp->p1];
- if( pIn1->flags & MEM_Null ){
- v1 = 2;
- }else{
- v1 = sqlite3VdbeIntValue(pIn1)!=0;
- }
- pIn2 = &aMem[pOp->p2];
- if( pIn2->flags & MEM_Null ){
- v2 = 2;
- }else{
- v2 = sqlite3VdbeIntValue(pIn2)!=0;
- }
+ v1 = sqlite3VdbeBooleanValue(&aMem[pOp->p1], 2);
+ v2 = sqlite3VdbeBooleanValue(&aMem[pOp->p2], 2);
if( pOp->opcode==OP_And ){
static const unsigned char and_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 };
v1 = and_logic[v1*3+v2];
@@ -79603,26 +87694,55 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
break;
}
+/* Opcode: IsTrue P1 P2 P3 P4 *
+** Synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4
+**
+** This opcode implements the IS TRUE, IS FALSE, IS NOT TRUE, and
+** IS NOT FALSE operators.
+**
+** Interpret the value in register P1 as a boolean value. Store that
+** boolean (a 0 or 1) in register P2. Or if the value in register P1 is
+** NULL, then the P3 is stored in register P2. Invert the answer if P4
+** is 1.
+**
+** The logic is summarized like this:
+**
+** <ul>
+** <li> If P3==0 and P4==0 then r[P2] := r[P1] IS TRUE
+** <li> If P3==1 and P4==1 then r[P2] := r[P1] IS FALSE
+** <li> If P3==0 and P4==1 then r[P2] := r[P1] IS NOT TRUE
+** <li> If P3==1 and P4==0 then r[P2] := r[P1] IS NOT FALSE
+** </ul>
+*/
+case OP_IsTrue: { /* in1, out2 */
+ assert( pOp->p4type==P4_INT32 );
+ assert( pOp->p4.i==0 || pOp->p4.i==1 );
+ assert( pOp->p3==0 || pOp->p3==1 );
+ sqlite3VdbeMemSetInt64(&aMem[pOp->p2],
+ sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3) ^ pOp->p4.i);
+ break;
+}
+
/* Opcode: Not P1 P2 * * *
** Synopsis: r[P2]= !r[P1]
**
** Interpret the value in register P1 as a boolean value. Store the
-** boolean complement in register P2. If the value in register P1 is
+** boolean complement in register P2. If the value in register P1 is
** NULL, then a NULL is stored in P2.
*/
case OP_Not: { /* same as TK_NOT, in1, out2 */
pIn1 = &aMem[pOp->p1];
pOut = &aMem[pOp->p2];
- sqlite3VdbeMemSetNull(pOut);
if( (pIn1->flags & MEM_Null)==0 ){
- pOut->flags = MEM_Int;
- pOut->u.i = !sqlite3VdbeIntValue(pIn1);
+ sqlite3VdbeMemSetInt64(pOut, !sqlite3VdbeBooleanValue(pIn1,0));
+ }else{
+ sqlite3VdbeMemSetNull(pOut);
}
break;
}
/* Opcode: BitNot P1 P2 * * *
-** Synopsis: r[P1]= ~r[P1]
+** Synopsis: r[P2]= ~r[P1]
**
** Interpret the content of register P1 as an integer. Store the
** ones-complement of the P1 value into register P2. If P1 holds
@@ -79641,19 +87761,39 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
/* Opcode: Once P1 P2 * * *
**
-** If the P1 value is equal to the P1 value on the OP_Init opcode at
-** instruction 0, then jump to P2. If the two P1 values differ, then
-** set the P1 value on this opcode to equal the P1 value on the OP_Init
-** and fall through.
+** Fall through to the next instruction the first time this opcode is
+** encountered on each invocation of the byte-code program. Jump to P2
+** on the second and all subsequent encounters during the same invocation.
+**
+** Top-level programs determine first invocation by comparing the P1
+** operand against the P1 operand on the OP_Init opcode at the beginning
+** of the program. If the P1 values differ, then fall through and make
+** the P1 of this opcode equal to the P1 of OP_Init. If P1 values are
+** the same then take the jump.
+**
+** For subprograms, there is a bitmask in the VdbeFrame that determines
+** whether or not the jump should be taken. The bitmask is necessary
+** because the self-altering code trick does not work for recursive
+** triggers.
*/
case OP_Once: { /* jump */
+ u32 iAddr; /* Address of this instruction */
assert( p->aOp[0].opcode==OP_Init );
- VdbeBranchTaken(p->aOp[0].p1==pOp->p1, 2);
- if( p->aOp[0].p1==pOp->p1 ){
- goto jump_to_p2;
+ if( p->pFrame ){
+ iAddr = (int)(pOp - p->aOp);
+ if( (p->pFrame->aOnce[iAddr/8] & (1<<(iAddr & 7)))!=0 ){
+ VdbeBranchTaken(1, 2);
+ goto jump_to_p2;
+ }
+ p->pFrame->aOnce[iAddr/8] |= 1<<(iAddr & 7);
}else{
- pOp->p1 = p->aOp[0].p1;
+ if( p->aOp[0].p1==pOp->p1 ){
+ VdbeBranchTaken(1, 2);
+ goto jump_to_p2;
+ }
}
+ VdbeBranchTaken(0, 2);
+ pOp->p1 = p->aOp[0].p1;
break;
}
@@ -79663,30 +87803,25 @@ case OP_Once: { /* jump */
** is considered true if it is numeric and non-zero. If the value
** in P1 is NULL then take the jump if and only if P3 is non-zero.
*/
+case OP_If: { /* jump, in1 */
+ int c;
+ c = sqlite3VdbeBooleanValue(&aMem[pOp->p1], pOp->p3);
+ VdbeBranchTaken(c!=0, 2);
+ if( c ) goto jump_to_p2;
+ break;
+}
+
/* Opcode: IfNot P1 P2 P3 * *
**
** Jump to P2 if the value in register P1 is False. The value
** is considered false if it has a numeric value of zero. If the value
** in P1 is NULL then take the jump if and only if P3 is non-zero.
*/
-case OP_If: /* jump, in1 */
case OP_IfNot: { /* jump, in1 */
int c;
- pIn1 = &aMem[pOp->p1];
- if( pIn1->flags & MEM_Null ){
- c = pOp->p3;
- }else{
-#ifdef SQLITE_OMIT_FLOATING_POINT
- c = sqlite3VdbeIntValue(pIn1)!=0;
-#else
- c = sqlite3VdbeRealValue(pIn1)!=0.0;
-#endif
- if( pOp->opcode==OP_IfNot ) c = !c;
- }
+ c = !sqlite3VdbeBooleanValue(&aMem[pOp->p1], !pOp->p3);
VdbeBranchTaken(c!=0, 2);
- if( c ){
- goto jump_to_p2;
- }
+ if( c ) goto jump_to_p2;
break;
}
@@ -79707,7 +87842,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
/* Opcode: NotNull P1 P2 * * *
** Synopsis: if r[P1]!=NULL goto P2
**
-** Jump to P2 if the value in register P1 is not NULL.
+** Jump to P2 if the value in register P1 is not NULL.
*/
case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
pIn1 = &aMem[pOp->p1];
@@ -79718,33 +87853,76 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
break;
}
+/* Opcode: IfNullRow P1 P2 P3 * *
+** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2
+**
+** Check the cursor P1 to see if it is currently pointing at a NULL row.
+** If it is, then set register P3 to NULL and jump immediately to P2.
+** If P1 is not on a NULL row, then fall through without making any
+** changes.
+*/
+case OP_IfNullRow: { /* jump */
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( p->apCsr[pOp->p1]!=0 );
+ if( p->apCsr[pOp->p1]->nullRow ){
+ sqlite3VdbeMemSetNull(aMem + pOp->p3);
+ goto jump_to_p2;
+ }
+ break;
+}
+
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+/* Opcode: Offset P1 P2 P3 * *
+** Synopsis: r[P3] = sqlite_offset(P1)
+**
+** Store in register r[P3] the byte offset into the database file that is the
+** start of the payload for the record at which that cursor P1 is currently
+** pointing.
+**
+** P2 is the column number for the argument to the sqlite_offset() function.
+** This opcode does not use P2 itself, but the P2 value is used by the
+** code generator. The P1, P2, and P3 operands to this opcode are the
+** same as for OP_Column.
+**
+** This opcode is only available if SQLite is compiled with the
+** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option.
+*/
+case OP_Offset: { /* out3 */
+ VdbeCursor *pC; /* The VDBE cursor */
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ pOut = &p->aMem[pOp->p3];
+ if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
+ sqlite3VdbeMemSetNull(pOut);
+ }else{
+ sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
+ }
+ break;
+}
+#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
+
/* Opcode: Column P1 P2 P3 P4 P5
** Synopsis: r[P3]=PX
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
-** from this record. If there are less that (P2+1)
+** from this record. If there are less that (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
**
-** If the column contains fewer than P2 fields, then extract a NULL. Or,
+** If the record contains fewer than P2 fields, then extract a NULL. Or,
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
-** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor,
-** then the cache of the cursor is reset prior to extracting the column.
-** The first OP_Column against a pseudo-table after the value of the content
-** register has changed should have this bit set.
-**
-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 when
+** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
** the result is guaranteed to only be used as the argument of a length()
** or typeof() function, respectively. The loading of large blobs can be
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
- int p2; /* column number to retrieve */
+ u32 p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The BTree cursor */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
@@ -79755,66 +87933,65 @@ case OP_Column: {
const u8 *zData; /* Part of the record being decoded */
const u8 *zHdr; /* Next unparsed byte of the header */
const u8 *zEndHdr; /* Pointer to first byte after the header */
- u32 offset; /* Offset into the data */
u64 offset64; /* 64-bit offset */
- u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- p2 = pOp->p2;
+ assert( pC!=0 );
+ p2 = (u32)pOp->p2;
- /* If the cursor cache is stale, bring it up-to-date */
+ /* If the cursor cache is stale (meaning it is not currently point at
+ ** the correct row) then bring it up-to-date by doing the necessary
+ ** B-Tree seek. */
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
if( rc ) goto abort_due_to_error;
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
- assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pC!=0 );
- assert( p2<pC->nField );
+ assert( p2<(u32)pC->nField );
aOffset = pC->aOffset;
assert( pC->eCurType!=CURTYPE_VTAB );
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
assert( pC->eCurType!=CURTYPE_SORTER );
- pCrsr = pC->uc.pCursor;
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
if( pC->nullRow ){
if( pC->eCurType==CURTYPE_PSEUDO ){
- assert( pC->uc.pseudoTableReg>0 );
- pReg = &aMem[pC->uc.pseudoTableReg];
+ /* For the special case of as pseudo-cursor, the seekResult field
+ ** identifies the register that holds the record */
+ assert( pC->seekResult>0 );
+ pReg = &aMem[pC->seekResult];
assert( pReg->flags & MEM_Blob );
assert( memIsValid(pReg) );
- pC->payloadSize = pC->szRow = avail = pReg->n;
+ pC->payloadSize = pC->szRow = pReg->n;
pC->aRow = (u8*)pReg->z;
}else{
sqlite3VdbeMemSetNull(pDest);
goto op_column_out;
}
}else{
+ pCrsr = pC->uc.pCursor;
assert( pC->eCurType==CURTYPE_BTREE );
assert( pCrsr );
assert( sqlite3BtreeCursorIsValid(pCrsr) );
pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
- pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail);
- assert( avail<=65536 ); /* Maximum page size is 64KiB */
- if( pC->payloadSize <= (u32)avail ){
- pC->szRow = pC->payloadSize;
- }else if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow);
+ assert( pC->szRow<=pC->payloadSize );
+ assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */
+ if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
- }else{
- pC->szRow = avail;
}
}
pC->cacheStatus = p->cacheCtr;
- pC->iHdrOffset = getVarint32(pC->aRow, offset);
+ pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
pC->nHdrParsed = 0;
- aOffset[0] = offset;
- if( avail<offset ){ /*OPTIMIZATION-IF-FALSE*/
+ if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/
/* pC->aRow does not have to hold the entire row, but it does at least
** need to cover the header of the record. If pC->aRow does not contain
** the complete header, then set it to zero, forcing the header to be
@@ -79831,17 +88008,26 @@ case OP_Column: {
** 3-byte type for each of the maximum of 32768 columns plus three
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
*/
- if( offset > 98307 || offset > pC->payloadSize ){
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ if( aOffset[0] > 98307 || aOffset[0] > pC->payloadSize ){
+ goto op_column_corrupt;
}
- }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/
- /* The following goto is an optimization. It can be omitted and
- ** everything will still work. But OP_Column is measurably faster
- ** by skipping the subsequent conditional, which is always true.
+ }else{
+ /* This is an optimization. By skipping over the first few tests
+ ** (ex: pC->nHdrParsed<=p2) in the next section, we achieve a
+ ** measurable performance gain.
+ **
+ ** This branch is taken even if aOffset[0]==0. Such a record is never
+ ** generated by SQLite, and could be considered corruption, but we
+ ** accept it for historical reasons. When aOffset[0]==0, the code this
+ ** branch jumps to reads past the end of the record, but never more
+ ** than a few bytes. Even if the record occurs at the end of the page
+ ** content area, the "page header" comes after the page content and so
+ ** this overread is harmless. Similar overreads can occur for a corrupt
+ ** database file.
*/
zData = pC->aRow;
assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
+ testcase( aOffset[0]==0 );
goto op_column_read_header;
}
}
@@ -79851,36 +88037,37 @@ case OP_Column: {
*/
if( pC->nHdrParsed<=p2 ){
/* If there is more header available for parsing in the record, try
- ** to extract additional fields up through the p2+1-th field
+ ** to extract additional fields up through the p2+1-th field
*/
if( pC->iHdrOffset<aOffset[0] ){
/* Make sure zData points to enough of the record to cover the header. */
if( pC->aRow==0 ){
memset(&sMem, 0, sizeof(sMem));
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem);
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pC->uc.pCursor,aOffset[0],&sMem);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
zData = (u8*)sMem.z;
}else{
zData = pC->aRow;
}
-
+
/* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
op_column_read_header:
i = pC->nHdrParsed;
offset64 = aOffset[i];
zHdr = zData + pC->iHdrOffset;
zEndHdr = zData + aOffset[0];
+ testcase( zHdr>=zEndHdr );
do{
- if( (t = zHdr[0])<0x80 ){
+ if( (pC->aType[i] = t = zHdr[0])<0x80 ){
zHdr++;
offset64 += sqlite3VdbeOneByteSerialTypeLen(t);
}else{
zHdr += sqlite3GetVarint32(zHdr, &t);
+ pC->aType[i] = t;
offset64 += sqlite3VdbeSerialTypeLen(t);
}
- pC->aType[i++] = t;
- aOffset[i] = (u32)(offset64 & 0xffffffff);
- }while( i<=p2 && zHdr<zEndHdr );
+ aOffset[++i] = (u32)(offset64 & 0xffffffff);
+ }while( (u32)i<=p2 && zHdr<zEndHdr );
/* The record is corrupt if any of the following are true:
** (1) the bytes of the header extend past the declared header size
@@ -79890,9 +88077,13 @@ case OP_Column: {
if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
|| (offset64 > pC->payloadSize)
){
- if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
+ if( aOffset[0]==0 ){
+ i = 0;
+ zHdr = zEndHdr;
+ }else{
+ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
+ goto op_column_corrupt;
+ }
}
pC->nHdrParsed = i;
@@ -79966,12 +88157,17 @@ case OP_Column: {
** 2. the length(X) function if X is a blob, and
** 3. if the content length is zero.
** So we might as well use bogus content rather than reading
- ** content from disk. */
- static u8 aZero[8]; /* This is the bogus content */
- sqlite3VdbeSerialGet(aZero, t, pDest);
+ ** content from disk.
+ **
+ ** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
+ ** buffer passed to it, debugging function VdbeMemPrettyPrint() may
+ ** read more. Use the global constant sqlite3CtypeMap[] as the array,
+ ** as that array is 256 bytes long (plenty for VdbeMemPrettyPrint())
+ ** and it begins with a bunch of zeros.
+ */
+ sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest);
}else{
- rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
- pDest);
+ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
pDest->flags &= ~MEM_Ephem;
@@ -79982,6 +88178,15 @@ op_column_out:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
+
+op_column_corrupt:
+ if( aOp[0].p3>0 ){
+ pOp = &aOp[aOp[0].p3-1];
+ break;
+ }else{
+ rc = SQLITE_CORRUPT_BKPT;
+ goto abort_due_to_error;
+ }
}
/* Opcode: Affinity P1 P2 * P4 *
@@ -79989,22 +88194,43 @@ op_column_out:
**
** Apply affinities to a range of P2 registers starting with P1.
**
-** P4 is a string that is P2 characters long. The nth character of the
-** string indicates the column affinity that should be used for the nth
+** P4 is a string that is P2 characters long. The N-th character of the
+** string indicates the column affinity that should be used for the N-th
** memory cell in the range.
*/
case OP_Affinity: {
const char *zAffinity; /* The affinity to be applied */
- char cAff; /* A single character of affinity */
zAffinity = pOp->p4.z;
assert( zAffinity!=0 );
+ assert( pOp->p2>0 );
assert( zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
- while( (cAff = *(zAffinity++))!=0 ){
+ while( 1 /*exit-by-break*/ ){
assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
- assert( memIsValid(pIn1) );
- applyAffinity(pIn1, cAff, encoding);
+ assert( zAffinity[0]==SQLITE_AFF_NONE || memIsValid(pIn1) );
+ applyAffinity(pIn1, zAffinity[0], encoding);
+ if( zAffinity[0]==SQLITE_AFF_REAL && (pIn1->flags & MEM_Int)!=0 ){
+ /* When applying REAL affinity, if the result is still an MEM_Int
+ ** that will fit in 6 bytes, then change the type to MEM_IntReal
+ ** so that we keep the high-resolution integer value but know that
+ ** the type really wants to be REAL. */
+ testcase( pIn1->u.i==140737488355328LL );
+ testcase( pIn1->u.i==140737488355327LL );
+ testcase( pIn1->u.i==-140737488355328LL );
+ testcase( pIn1->u.i==-140737488355329LL );
+ if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL ){
+ pIn1->flags |= MEM_IntReal;
+ pIn1->flags &= ~MEM_Int;
+ }else{
+ pIn1->u.r = (double)pIn1->u.i;
+ pIn1->flags |= MEM_Real;
+ pIn1->flags &= ~MEM_Int;
+ }
+ }
+ REGISTER_TRACE((int)(pIn1-aMem), pIn1);
+ zAffinity++;
+ if( zAffinity[0]==0 ) break;
pIn1++;
}
break;
@@ -80017,17 +88243,27 @@ case OP_Affinity: {
** use as a data record in a database table or as a key
** in an index. The OP_Column opcode can decode the record later.
**
-** P4 may be a string that is P2 characters long. The nth character of the
-** string indicates the column affinity that should be used for the nth
+** P4 may be a string that is P2 characters long. The N-th character of the
+** string indicates the column affinity that should be used for the N-th
** field of the index key.
**
** The mapping from character to affinity is given by the SQLITE_AFF_
** macros defined in sqliteInt.h.
**
** If P4 is NULL then all index fields have the affinity BLOB.
+**
+** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM
+** compile-time option is enabled:
+**
+** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index
+** of the right-most table that can be null-trimmed.
+**
+** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value
+** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to
+** accept no-change records with serial_type 10. This value is
+** only used inside an assert() and does not affect the end result.
*/
case OP_MakeRecord: {
- u8 *zNewRecord; /* A buffer to hold the data for the new record */
Mem *pRec; /* The new record */
u64 nData; /* Number of bytes of data space */
int nHdr; /* Number of bytes of header space */
@@ -80040,21 +88276,21 @@ case OP_MakeRecord: {
int nField; /* Number of fields in the record */
char *zAffinity; /* The affinity string for the record */
int file_format; /* File format to use for encoding */
- int i; /* Space used in zNewRecord[] header */
- int j; /* Space used in zNewRecord[] content */
u32 len; /* Length of a field */
+ u8 *zHdr; /* Where to write next byte of the header */
+ u8 *zPayload; /* Where to write next byte of the payload */
/* Assuming the record contains N fields, the record format looks
** like this:
**
** ------------------------------------------------------------------------
- ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
+ ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
** ------------------------------------------------------------------------
**
** Data(0) is taken from register P1. Data(1) comes from register P1+1
** and so forth.
**
- ** Each type field is a varint representing the serial type of the
+ ** Each type field is a varint representing the serial type of the
** corresponding data element (see sqlite3VdbeSerialType()). The
** hdr-size field is also a varint which is the offset from the beginning
** of the record to data0.
@@ -80081,30 +88317,149 @@ case OP_MakeRecord: {
if( zAffinity ){
pRec = pData0;
do{
- applyAffinity(pRec++, *(zAffinity++), encoding);
+ applyAffinity(pRec, zAffinity[0], encoding);
+ if( zAffinity[0]==SQLITE_AFF_REAL && (pRec->flags & MEM_Int) ){
+ pRec->flags |= MEM_IntReal;
+ pRec->flags &= ~(MEM_Int);
+ }
+ REGISTER_TRACE((int)(pRec-aMem), pRec);
+ zAffinity++;
+ pRec++;
assert( zAffinity[0]==0 || pRec<=pLast );
}while( zAffinity[0] );
}
+#ifdef SQLITE_ENABLE_NULL_TRIM
+ /* NULLs can be safely trimmed from the end of the record, as long as
+ ** as the schema format is 2 or more and none of the omitted columns
+ ** have a non-NULL default value. Also, the record must be left with
+ ** at least one field. If P5>0 then it will be one more than the
+ ** index of the right-most column with a non-NULL default value */
+ if( pOp->p5 ){
+ while( (pLast->flags & MEM_Null)!=0 && nField>pOp->p5 ){
+ pLast--;
+ nField--;
+ }
+ }
+#endif
+
/* Loop through the elements that will make up the record to figure
- ** out how much space is required for the new record.
+ ** out how much space is required for the new record. After this loop,
+ ** the Mem.uTemp field of each term should hold the serial-type that will
+ ** be used for that term in the generated record:
+ **
+ ** Mem.uTemp value type
+ ** --------------- ---------------
+ ** 0 NULL
+ ** 1 1-byte signed integer
+ ** 2 2-byte signed integer
+ ** 3 3-byte signed integer
+ ** 4 4-byte signed integer
+ ** 5 6-byte signed integer
+ ** 6 8-byte signed integer
+ ** 7 IEEE float
+ ** 8 Integer constant 0
+ ** 9 Integer constant 1
+ ** 10,11 reserved for expansion
+ ** N>=12 and even BLOB
+ ** N>=13 and odd text
+ **
+ ** The following additional values are computed:
+ ** nHdr Number of bytes needed for the record header
+ ** nData Number of bytes of data space needed for the record
+ ** nZero Zero bytes at the end of the record
*/
pRec = pLast;
do{
assert( memIsValid(pRec) );
- pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len);
- if( pRec->flags & MEM_Zero ){
- if( nData ){
- if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
+ if( pRec->flags & MEM_Null ){
+ if( pRec->flags & MEM_Zero ){
+ /* Values with MEM_Null and MEM_Zero are created by xColumn virtual
+ ** table methods that never invoke sqlite3_result_xxxxx() while
+ ** computing an unchanging column value in an UPDATE statement.
+ ** Give such values a special internal-use-only serial-type of 10
+ ** so that they can be passed through to xUpdate and have
+ ** a true sqlite3_value_nochange(). */
+#ifndef SQLITE_ENABLE_NULL_TRIM
+ assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
+#endif
+ pRec->uTemp = 10;
}else{
- nZero += pRec->u.nZero;
- len -= pRec->u.nZero;
+ pRec->uTemp = 0;
+ }
+ nHdr++;
+ }else if( pRec->flags & (MEM_Int|MEM_IntReal) ){
+ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
+ i64 i = pRec->u.i;
+ u64 uu;
+ testcase( pRec->flags & MEM_Int );
+ testcase( pRec->flags & MEM_IntReal );
+ if( i<0 ){
+ uu = ~i;
+ }else{
+ uu = i;
+ }
+ nHdr++;
+ testcase( uu==127 ); testcase( uu==128 );
+ testcase( uu==32767 ); testcase( uu==32768 );
+ testcase( uu==8388607 ); testcase( uu==8388608 );
+ testcase( uu==2147483647 ); testcase( uu==2147483648 );
+ testcase( uu==140737488355327LL ); testcase( uu==140737488355328LL );
+ if( uu<=127 ){
+ if( (i&1)==i && file_format>=4 ){
+ pRec->uTemp = 8+(u32)uu;
+ }else{
+ nData++;
+ pRec->uTemp = 1;
+ }
+ }else if( uu<=32767 ){
+ nData += 2;
+ pRec->uTemp = 2;
+ }else if( uu<=8388607 ){
+ nData += 3;
+ pRec->uTemp = 3;
+ }else if( uu<=2147483647 ){
+ nData += 4;
+ pRec->uTemp = 4;
+ }else if( uu<=140737488355327LL ){
+ nData += 6;
+ pRec->uTemp = 5;
+ }else{
+ nData += 8;
+ if( pRec->flags & MEM_IntReal ){
+ /* If the value is IntReal and is going to take up 8 bytes to store
+ ** as an integer, then we might as well make it an 8-byte floating
+ ** point value */
+ pRec->u.r = (double)pRec->u.i;
+ pRec->flags &= ~MEM_IntReal;
+ pRec->flags |= MEM_Real;
+ pRec->uTemp = 7;
+ }else{
+ pRec->uTemp = 6;
+ }
+ }
+ }else if( pRec->flags & MEM_Real ){
+ nHdr++;
+ nData += 8;
+ pRec->uTemp = 7;
+ }else{
+ assert( db->mallocFailed || pRec->flags&(MEM_Str|MEM_Blob) );
+ assert( pRec->n>=0 );
+ len = (u32)pRec->n;
+ serial_type = (len*2) + 12 + ((pRec->flags & MEM_Str)!=0);
+ if( pRec->flags & MEM_Zero ){
+ serial_type += pRec->u.nZero*2;
+ if( nData ){
+ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem;
+ len += pRec->u.nZero;
+ }else{
+ nZero += pRec->u.nZero;
+ }
}
+ nData += len;
+ nHdr += sqlite3VarintLen(serial_type);
+ pRec->uTemp = serial_type;
}
- nData += len;
- testcase( serial_type==127 );
- testcase( serial_type==128 );
- nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
if( pRec==pData0 ) break;
pRec--;
}while(1);
@@ -80125,57 +88480,67 @@ case OP_MakeRecord: {
if( nVarint<sqlite3VarintLen(nHdr) ) nHdr++;
}
nByte = nHdr+nData;
- if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){
- goto too_big;
- }
- /* Make sure the output register has a buffer large enough to store
+ /* Make sure the output register has a buffer large enough to store
** the new record. The output register (pOp->p3) is not allowed to
** be one of the input registers (because the following call to
** sqlite3VdbeMemClearAndResize() could clobber the value before it is used).
*/
- if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){
- goto no_mem;
+ if( nByte+nZero<=pOut->szMalloc ){
+ /* The output register is already large enough to hold the record.
+ ** No error checks or buffer enlargement is required */
+ pOut->z = pOut->zMalloc;
+ }else{
+ /* Need to make sure that the output is not too big and then enlarge
+ ** the output register to hold the full result */
+ if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ goto too_big;
+ }
+ if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){
+ goto no_mem;
+ }
+ }
+ pOut->n = (int)nByte;
+ pOut->flags = MEM_Blob;
+ if( nZero ){
+ pOut->u.nZero = nZero;
+ pOut->flags |= MEM_Zero;
}
- zNewRecord = (u8 *)pOut->z;
+ UPDATE_MAX_BLOBSIZE(pOut);
+ zHdr = (u8 *)pOut->z;
+ zPayload = zHdr + nHdr;
/* Write the record */
- i = putVarint32(zNewRecord, nHdr);
- j = nHdr;
+ zHdr += putVarint32(zHdr, nHdr);
assert( pData0<=pLast );
pRec = pData0;
do{
serial_type = pRec->uTemp;
/* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
** additional varints, one per column. */
- i += putVarint32(&zNewRecord[i], serial_type); /* serial type */
+ zHdr += putVarint32(zHdr, serial_type); /* serial type */
/* EVIDENCE-OF: R-64536-51728 The values for each column in the record
** immediately follow the header. */
- j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
+ zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */
}while( (++pRec)<=pLast );
- assert( i==nHdr );
- assert( j==nByte );
+ assert( nHdr==(int)(zHdr - (u8*)pOut->z) );
+ assert( nByte==(int)(zPayload - (u8*)pOut->z) );
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
- pOut->n = (int)nByte;
- pOut->flags = MEM_Blob;
- if( nZero ){
- pOut->u.nZero = nZero;
- pOut->flags |= MEM_Zero;
- }
- pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */
REGISTER_TRACE(pOp->p3, pOut);
- UPDATE_MAX_BLOBSIZE(pOut);
break;
}
-/* Opcode: Count P1 P2 * * *
+/* Opcode: Count P1 P2 p3 * *
** Synopsis: r[P2]=count()
**
-** Store the number of entries (an integer value) in the table or index
-** opened by cursor P1 in register P2
+** Store the number of entries (an integer value) in the table or index
+** opened by cursor P1 in register P2.
+**
+** If P3==0, then an exact count is obtained, which involves visiting
+** every btree page of the table. But if P3 is non-zero, an estimate
+** is returned based on the current cursor position.
*/
-#ifndef SQLITE_OMIT_BTREECOUNT
case OP_Count: { /* out2 */
i64 nEntry;
BtCursor *pCrsr;
@@ -80183,20 +88548,24 @@ case OP_Count: { /* out2 */
assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
assert( pCrsr );
- nEntry = 0; /* Not needed. Only used to silence a warning. */
- rc = sqlite3BtreeCount(pCrsr, &nEntry);
- if( rc ) goto abort_due_to_error;
+ if( pOp->p3 ){
+ nEntry = sqlite3BtreeRowCountEst(pCrsr);
+ }else{
+ nEntry = 0; /* Not needed. Only used to silence a warning. */
+ rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
+ if( rc ) goto abort_due_to_error;
+ }
pOut = out2Prerelease(p, pOp);
pOut->u.i = nEntry;
- break;
+ goto check_for_interrupt;
}
-#endif
/* Opcode: Savepoint P1 * * P4 *
**
** Open, release or rollback the savepoint named by parameter P4, depending
-** on the value of P1. To open a new savepoint, P1==0. To release (commit) an
-** existing savepoint, P1==1, or to rollback an existing savepoint P1==2.
+** on the value of P1. To open a new savepoint set P1==0 (SAVEPOINT_BEGIN).
+** To release (commit) an existing savepoint set P1==1 (SAVEPOINT_RELEASE).
+** To rollback an existing savepoint set P1==2 (SAVEPOINT_ROLLBACK).
*/
case OP_Savepoint: {
int p1; /* Value of P1 operand */
@@ -80212,7 +88581,7 @@ case OP_Savepoint: {
zName = pOp->p4.z;
/* Assert that the p1 parameter is valid. Also that if there is no open
- ** transaction, then there cannot be any savepoints.
+ ** transaction, then there cannot be any savepoints.
*/
assert( db->pSavepoint==0 || db->autoCommit==0 );
assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK );
@@ -80222,7 +88591,7 @@ case OP_Savepoint: {
if( p1==SAVEPOINT_BEGIN ){
if( db->nVdbeWrite>0 ){
- /* A new savepoint cannot be created if there are active write
+ /* A new savepoint cannot be created if there are active write
** statements (i.e. open read/write incremental blob handles).
*/
sqlite3VdbeError(p, "cannot open savepoint - SQL statements in progress");
@@ -80246,7 +88615,7 @@ case OP_Savepoint: {
if( pNew ){
pNew->zName = (char *)&pNew[1];
memcpy(pNew->zName, zName, nName+1);
-
+
/* If there is no open transaction, then mark this as a special
** "transaction savepoint". */
if( db->autoCommit ){
@@ -80264,12 +88633,13 @@ case OP_Savepoint: {
}
}
}else{
+ assert( p1==SAVEPOINT_RELEASE || p1==SAVEPOINT_ROLLBACK );
iSavepoint = 0;
/* Find the named savepoint. If there is no such savepoint, then an
** an error is returned to the user. */
for(
- pSavepoint = db->pSavepoint;
+ pSavepoint = db->pSavepoint;
pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName);
pSavepoint = pSavepoint->pNext
){
@@ -80279,7 +88649,7 @@ case OP_Savepoint: {
sqlite3VdbeError(p, "no such savepoint: %s", zName);
rc = SQLITE_ERROR;
}else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){
- /* It is not possible to release (commit) a savepoint if there are
+ /* It is not possible to release (commit) a savepoint if there are
** active write statements.
*/
sqlite3VdbeError(p, "cannot release savepoint - "
@@ -80288,8 +88658,8 @@ case OP_Savepoint: {
}else{
/* Determine whether or not this is a transaction savepoint. If so,
- ** and this is a RELEASE command, then the current transaction
- ** is committed.
+ ** and this is a RELEASE command, then the current transaction
+ ** is committed.
*/
int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
if( isTransaction && p1==SAVEPOINT_RELEASE ){
@@ -80303,13 +88673,17 @@ case OP_Savepoint: {
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
- db->isTransactionSavepoint = 0;
rc = p->rc;
+ if( rc ){
+ db->autoCommit = 0;
+ }else{
+ db->isTransactionSavepoint = 0;
+ }
}else{
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
- isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
+ isSchemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0;
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
SQLITE_ABORT_ROLLBACK,
@@ -80317,6 +88691,7 @@ case OP_Savepoint: {
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}else{
+ assert( p1==SAVEPOINT_RELEASE );
isSchemaChange = 0;
}
for(ii=0; ii<db->nDb; ii++){
@@ -80326,13 +88701,14 @@ case OP_Savepoint: {
}
}
if( isSchemaChange ){
- sqlite3ExpirePreparedStatements(db);
+ sqlite3ExpirePreparedStatements(db, 0);
sqlite3ResetAllSchemasOfConnection(db);
- db->flags = (db->flags | SQLITE_InternChanges);
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
-
- /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
+ if( rc ) goto abort_due_to_error;
+
+ /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
** savepoints nested inside of the savepoint being operated on. */
while( db->pSavepoint!=pSavepoint ){
pTmp = db->pSavepoint;
@@ -80341,8 +88717,8 @@ case OP_Savepoint: {
db->nSavepoint--;
}
- /* If it is a RELEASE, then destroy the savepoint being operated on
- ** too. If it is a ROLLBACK TO, then set the number of deferred
+ /* If it is a RELEASE, then destroy the savepoint being operated on
+ ** too. If it is a ROLLBACK TO, then set the number of deferred
** constraint violations present in the database to the value stored
** when the savepoint was created. */
if( p1==SAVEPOINT_RELEASE ){
@@ -80353,6 +88729,7 @@ case OP_Savepoint: {
db->nSavepoint--;
}
}else{
+ assert( p1==SAVEPOINT_ROLLBACK );
db->nDeferredCons = pSavepoint->nDeferredCons;
db->nDeferredImmCons = pSavepoint->nDeferredImmCons;
}
@@ -80395,7 +88772,7 @@ case OP_AutoCommit: {
db->autoCommit = 1;
}else if( desiredAutoCommit && db->nVdbeWrite>0 ){
/* If this instruction implements a COMMIT and other VMs are writing
- ** return an error indicating that the other VMs must complete first.
+ ** return an error indicating that the other VMs must complete first.
*/
sqlite3VdbeError(p, "cannot commit transaction - "
"SQL statements in progress");
@@ -80412,7 +88789,6 @@ case OP_AutoCommit: {
p->rc = rc = SQLITE_BUSY;
goto vdbe_return;
}
- assert( db->nStatement==0 );
sqlite3CloseSavepoints(db);
if( p->rc==SQLITE_OK ){
rc = SQLITE_DONE;
@@ -80425,18 +88801,18 @@ case OP_AutoCommit: {
(!desiredAutoCommit)?"cannot start a transaction within a transaction":(
(iRollback)?"cannot rollback - no transaction is active":
"cannot commit - no transaction is active"));
-
+
rc = SQLITE_ERROR;
goto abort_due_to_error;
}
- break;
+ /*NOTREACHED*/ assert(0);
}
/* Opcode: Transaction P1 P2 P3 P4 P5
**
** Begin a transaction on database P1 if a transaction is not already
** active.
-** If P2 is non-zero, then a write-transaction is started, or if a
+** If P2 is non-zero, then a write-transaction is started, or if a
** read-transaction is already active, it is upgraded to a write-transaction.
** If P2 is zero, then a read-transaction is started.
**
@@ -80468,8 +88844,7 @@ case OP_AutoCommit: {
*/
case OP_Transaction: {
Btree *pBt;
- int iMeta;
- int iGen;
+ int iMeta = 0;
assert( p->bIsReader );
assert( p->readOnly==0 || pOp->p2==0 );
@@ -80482,7 +88857,7 @@ case OP_Transaction: {
pBt = db->aDb[pOp->p1].pBt;
if( pBt ){
- rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
+ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta);
testcase( rc==SQLITE_BUSY_SNAPSHOT );
testcase( rc==SQLITE_BUSY_RECOVERY );
if( rc!=SQLITE_OK ){
@@ -80494,13 +88869,14 @@ case OP_Transaction: {
goto abort_due_to_error;
}
- if( pOp->p2 && p->usesStmtJournal
- && (db->autoCommit==0 || db->nVdbeRead>1)
+ if( p->usesStmtJournal
+ && pOp->p2
+ && (db->autoCommit==0 || db->nVdbeRead>1)
){
assert( sqlite3BtreeIsInTrans(pBt) );
if( p->iStatement==0 ){
assert( db->nStatement>=0 && db->nSavepoint>=0 );
- db->nStatement++;
+ db->nStatement++;
p->iStatement = db->nSavepoint + db->nStatement;
}
@@ -80515,22 +88891,20 @@ case OP_Transaction: {
p->nStmtDefCons = db->nDeferredCons;
p->nStmtDefImmCons = db->nDeferredImmCons;
}
-
- /* Gather the schema version number for checking:
+ }
+ assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
+ if( pOp->p5
+ && (iMeta!=pOp->p3
+ || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
+ ){
+ /*
** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
** version is checked to ensure that the schema has not changed since the
** SQL statement was prepared.
*/
- sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
- iGen = db->aDb[pOp->p1].pSchema->iGeneration;
- }else{
- iGen = iMeta = 0;
- }
- assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
- if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
- /* If the schema-cookie from the database file matches the cookie
+ /* If the schema-cookie from the database file matches the cookie
** stored with the in-memory representation of the schema, do
** not reload the schema from the database file.
**
@@ -80540,7 +88914,7 @@ case OP_Transaction: {
** prepared queries. If such a query is out-of-date, we do not want to
** discard the database schema, as the user code implementing the
** v-table would have to be ready for the sqlite3_vtab structure itself
- ** to be invalidated whenever sqlite3_step() is called from within
+ ** to be invalidated whenever sqlite3_step() is called from within
** a v-table method.
*/
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
@@ -80584,18 +88958,25 @@ case OP_ReadCookie: { /* out2 */
break;
}
-/* Opcode: SetCookie P1 P2 P3 * *
+/* Opcode: SetCookie P1 P2 P3 * P5
**
** Write the integer value P3 into cookie number P2 of database P1.
** P2==1 is the schema version. P2==2 is the database format.
-** P2==3 is the recommended pager cache
-** size, and so forth. P1==0 is the main database file and P1==1 is the
+** P2==3 is the recommended pager cache
+** size, and so forth. P1==0 is the main database file and P1==1 is the
** database file used to store temporary tables.
**
** A transaction must be started before executing this opcode.
+**
+** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal
+** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement
+** has P5 set to 1, so that the internal schema version will be different
+** from the database schema version, resulting in a schema reset.
*/
case OP_SetCookie: {
Db *pDb;
+
+ sqlite3VdbeIncrWriteCounter(p, 0);
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
@@ -80607,8 +88988,8 @@ case OP_SetCookie: {
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
if( pOp->p2==BTREE_SCHEMA_VERSION ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->pSchema->schema_cookie = pOp->p3;
- db->flags |= SQLITE_InternChanges;
+ pDb->pSchema->schema_cookie = pOp->p3 - pOp->p5;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}else if( pOp->p2==BTREE_FILE_FORMAT ){
/* Record changes in the file format */
pDb->pSchema->file_format = pOp->p3;
@@ -80616,7 +88997,7 @@ case OP_SetCookie: {
if( pOp->p1==1 ){
/* Invalidate all prepared statements whenever the TEMP database
** schema is changed. Ticket #1644 */
- sqlite3ExpirePreparedStatements(db);
+ sqlite3ExpirePreparedStatements(db, 0);
p->expired = 0;
}
if( rc ) goto abort_due_to_error;
@@ -80627,71 +89008,90 @@ case OP_SetCookie: {
** Synopsis: root=P2 iDb=P3
**
** Open a read-only cursor for the database table whose root page is
-** P2 in a database file. The database file is determined by P3.
-** P3==0 means the main database, P3==1 means the database used for
+** P2 in a database file. The database file is determined by P3.
+** P3==0 means the main database, P3==1 means the database used for
** temporary tables, and P3>1 means used the corresponding attached
** database. Give the new cursor an identifier of P1. The P1
** values need not be contiguous but all P1 values should be small integers.
** It is an error for P1 to be negative.
**
-** If P5!=0 then use the content of register P2 as the root page, not
-** the value of P2 itself.
-**
-** There will be a read lock on the database whenever there is an
-** open cursor. If the database was unlocked prior to this instruction
-** then a read lock is acquired as part of this instruction. A read
-** lock allows other processes to read the database but prohibits
-** any other process from modifying the database. The read lock is
-** released when all cursors are closed. If this instruction attempts
-** to get a read lock but fails, the script terminates with an
-** SQLITE_BUSY error code.
+** Allowed P5 bits:
+** <ul>
+** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
+** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
+** of OP_SeekLE/OP_IdxLT)
+** </ul>
**
** The P4 value may be either an integer (P4_INT32) or a pointer to
-** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
-** structure, then said structure defines the content and collating
-** sequence of the index being opened. Otherwise, if P4 is an integer
-** value, it is set to the number of columns in the table.
+** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
+** object, then table being opened must be an [index b-tree] where the
+** KeyInfo object defines the content and collating
+** sequence of that index b-tree. Otherwise, if P4 is an integer
+** value, then the table being opened must be a [table b-tree] with a
+** number of columns no less than the value of P4.
**
** See also: OpenWrite, ReopenIdx
*/
/* Opcode: ReopenIdx P1 P2 P3 P4 P5
** Synopsis: root=P2 iDb=P3
**
-** The ReopenIdx opcode works exactly like ReadOpen except that it first
-** checks to see if the cursor on P1 is already open with a root page
-** number of P2 and if it is this opcode becomes a no-op. In other words,
+** The ReopenIdx opcode works like OP_OpenRead except that it first
+** checks to see if the cursor on P1 is already open on the same
+** b-tree and if it is this opcode becomes a no-op. In other words,
** if the cursor is already open, do not reopen it.
**
-** The ReopenIdx opcode may only be used with P5==0 and with P4 being
-** a P4_KEYINFO object. Furthermore, the P3 value must be the same as
-** every other ReopenIdx or OpenRead for the same cursor number.
+** The ReopenIdx opcode may only be used with P5==0 or P5==OPFLAG_SEEKEQ
+** and with P4 being a P4_KEYINFO object. Furthermore, the P3 value must
+** be the same as every other ReopenIdx or OpenRead for the same cursor
+** number.
+**
+** Allowed P5 bits:
+** <ul>
+** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
+** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
+** of OP_SeekLE/OP_IdxLT)
+** </ul>
**
-** See the OpenRead opcode documentation for additional information.
+** See also: OP_OpenRead, OP_OpenWrite
*/
/* Opcode: OpenWrite P1 P2 P3 P4 P5
** Synopsis: root=P2 iDb=P3
**
** Open a read/write cursor named P1 on the table or index whose root
-** page is P2. Or if P5!=0 use the content of register P2 to find the
-** root page.
+** page is P2 (or whose root page is held in register P2 if the
+** OPFLAG_P2ISREG bit is set in P5 - see below).
**
** The P4 value may be either an integer (P4_INT32) or a pointer to
-** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
-** structure, then said structure defines the content and collating
-** sequence of the index being opened. Otherwise, if P4 is an integer
-** value, it is set to the number of columns in the table, or to the
-** largest index of any column of the table that is actually used.
+** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
+** object, then table being opened must be an [index b-tree] where the
+** KeyInfo object defines the content and collating
+** sequence of that index b-tree. Otherwise, if P4 is an integer
+** value, then the table being opened must be a [table b-tree] with a
+** number of columns no less than the value of P4.
+**
+** Allowed P5 bits:
+** <ul>
+** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
+** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
+** of OP_SeekLE/OP_IdxLT)
+** <li> <b>0x08 OPFLAG_FORDELETE</b>: This cursor is used only to seek
+** and subsequently delete entries in an index btree. This is a
+** hint to the storage engine that the storage engine is allowed to
+** ignore. The hint is not used by the official SQLite b*tree storage
+** engine, but is used by COMDB2.
+** <li> <b>0x10 OPFLAG_P2ISREG</b>: Use the content of register P2
+** as the root page, not the value of P2 itself.
+** </ul>
**
-** This instruction works just like OpenRead except that it opens the cursor
-** in read/write mode. For a given table, there can be one or more read-only
-** cursors or a single read/write cursor but not both.
+** This instruction works like OpenRead except that it opens the cursor
+** in read/write mode.
**
-** See also OpenRead.
+** See also: OP_OpenRead, OP_ReopenIdx
*/
case OP_ReopenIdx: {
int nField;
KeyInfo *pKeyInfo;
- int p2;
+ u32 p2;
int iDb;
int wrFlag;
Btree *pX;
@@ -80715,14 +89115,14 @@ case OP_OpenWrite:
assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
|| p->readOnly==0 );
- if( p->expired ){
+ if( p->expired==1 ){
rc = SQLITE_ABORT_ROLLBACK;
goto abort_due_to_error;
}
nField = 0;
pKeyInfo = 0;
- p2 = pOp->p2;
+ p2 = (u32)pOp->p2;
iDb = pOp->p3;
assert( iDb>=0 && iDb<db->nDb );
assert( DbMaskTest(p->btreeMask, iDb) );
@@ -80741,13 +89141,14 @@ case OP_OpenWrite:
}
if( pOp->p5 & OPFLAG_P2ISREG ){
assert( p2>0 );
- assert( p2<=(p->nMem+1 - p->nCursor) );
+ assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
+ assert( pOp->opcode==OP_OpenWrite );
pIn2 = &aMem[p2];
assert( memIsValid(pIn2) );
assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
p2 = (int)pIn2->u.i;
- /* The p2 value always comes from a prior OP_CreateTable opcode and
+ /* The p2 value always comes from a prior OP_CreateBtree opcode and
** that opcode will always set the p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
@@ -80757,7 +89158,7 @@ case OP_OpenWrite:
pKeyInfo = pOp->p4.pKeyInfo;
assert( pKeyInfo->enc==ENC(db) );
assert( pKeyInfo->db==db );
- nField = pKeyInfo->nField+pKeyInfo->nXField;
+ nField = pKeyInfo->nAllField;
}else if( pOp->p4type==P4_INT32 ){
nField = pOp->p4.i;
}
@@ -80777,30 +89178,65 @@ case OP_OpenWrite:
/* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point
** and report database corruption if they were not, but this check has
- ** since moved into the btree layer. */
+ ** since moved into the btree layer. */
pCur->isTable = pOp->p4type!=P4_KEYINFO;
open_cursor_set_hints:
assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
testcase( pOp->p5 & OPFLAG_BULKCSR );
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
testcase( pOp->p2 & OPFLAG_SEEKEQ );
-#endif
sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
(pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
if( rc ) goto abort_due_to_error;
break;
}
+/* Opcode: OpenDup P1 P2 * * *
+**
+** Open a new cursor P1 that points to the same ephemeral table as
+** cursor P2. The P2 cursor must have been opened by a prior OP_OpenEphemeral
+** opcode. Only ephemeral cursors may be duplicated.
+**
+** Duplicate ephemeral cursors are used for self-joins of materialized views.
+*/
+case OP_OpenDup: {
+ VdbeCursor *pOrig; /* The original cursor to be duplicated */
+ VdbeCursor *pCx; /* The new cursor */
+
+ pOrig = p->apCsr[pOp->p2];
+ assert( pOrig );
+ assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
+
+ pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
+ if( pCx==0 ) goto no_mem;
+ pCx->nullRow = 1;
+ pCx->isEphemeral = 1;
+ pCx->pKeyInfo = pOrig->pKeyInfo;
+ pCx->isTable = pOrig->isTable;
+ pCx->pgnoRoot = pOrig->pgnoRoot;
+ pCx->isOrdered = pOrig->isOrdered;
+ rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
+ pCx->pKeyInfo, pCx->uc.pCursor);
+ /* The sqlite3BtreeCursor() routine can only fail for the first cursor
+ ** opened for a database. Since there is already an open cursor when this
+ ** opcode is run, the sqlite3BtreeCursor() cannot fail */
+ assert( rc==SQLITE_OK );
+ break;
+}
+
+
/* Opcode: OpenEphemeral P1 P2 * P4 P5
** Synopsis: nColumn=P2
**
** Open a new cursor P1 to a transient table.
-** The cursor is always opened read/write even if
+** The cursor is always opened read/write even if
** the main database is read-only. The ephemeral
** table is deleted automatically when the cursor is closed.
**
+** If the cursor P1 is already opened on an ephemeral table, the table
+** is cleared (all content is erased).
+**
** P2 is the number of columns in the ephemeral table.
** The cursor points to a BTree table if P4==0 and to a BTree index
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
@@ -80819,12 +89255,12 @@ open_cursor_set_hints:
** by this opcode will be used for automatically created transient
** indices in joins.
*/
-case OP_OpenAutoindex:
+case OP_OpenAutoindex:
case OP_OpenEphemeral: {
VdbeCursor *pCx;
KeyInfo *pKeyInfo;
- static const int vfsFlags =
+ static const int vfsFlags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
SQLITE_OPEN_EXCLUSIVE |
@@ -80832,42 +89268,53 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
assert( pOp->p2>=0 );
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
- if( pCx==0 ) goto no_mem;
- pCx->nullRow = 1;
- pCx->isEphemeral = 1;
- rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
- BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
- if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
- }
- if( rc==SQLITE_OK ){
- /* If a transient index is required, create it by calling
- ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
- ** opening it. If a transient table is required, just use the
- ** automatically created table with root-page 1 (an BLOB_INTKEY table).
- */
- if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
- int pgno;
- assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
- if( rc==SQLITE_OK ){
- assert( pgno==MASTER_ROOT+1 );
- assert( pKeyInfo->db==db );
- assert( pKeyInfo->enc==ENC(db) );
- pCx->pKeyInfo = pKeyInfo;
- rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR,
- pKeyInfo, pCx->uc.pCursor);
+ pCx = p->apCsr[pOp->p1];
+ if( pCx && pCx->pBtx ){
+ /* If the ephermeral table is already open, erase all existing content
+ ** so that the table is empty again, rather than creating a new table. */
+ assert( pCx->isEphemeral );
+ pCx->seqCount = 0;
+ pCx->cacheStatus = CACHE_STALE;
+ rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
+ }else{
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
+ if( pCx==0 ) goto no_mem;
+ pCx->isEphemeral = 1;
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
+ BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
+ vfsFlags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
+ }
+ if( rc==SQLITE_OK ){
+ /* If a transient index is required, create it by calling
+ ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
+ ** opening it. If a transient table is required, just use the
+ ** automatically created table with root-page 1 (an BLOB_INTKEY table).
+ */
+ if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
+ assert( pOp->p4type==P4_KEYINFO );
+ rc = sqlite3BtreeCreateTable(pCx->pBtx, &pCx->pgnoRoot,
+ BTREE_BLOBKEY | pOp->p5);
+ if( rc==SQLITE_OK ){
+ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
+ assert( pKeyInfo->db==db );
+ assert( pKeyInfo->enc==ENC(db) );
+ rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
+ pKeyInfo, pCx->uc.pCursor);
+ }
+ pCx->isTable = 0;
+ }else{
+ pCx->pgnoRoot = SCHEMA_ROOT;
+ rc = sqlite3BtreeCursor(pCx->pBtx, SCHEMA_ROOT, BTREE_WRCSR,
+ 0, pCx->uc.pCursor);
+ pCx->isTable = 1;
}
- pCx->isTable = 0;
- }else{
- rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR,
- 0, pCx->uc.pCursor);
- pCx->isTable = 1;
}
+ pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
}
if( rc ) goto abort_due_to_error;
- pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
+ pCx->nullRow = 1;
break;
}
@@ -80919,7 +89366,7 @@ case OP_SequenceTest: {
**
** Open a new cursor that points to a fake table that contains a single
** row of data. The content of that one row is the content of memory
-** register P2. In other words, cursor P1 becomes an alias for the
+** register P2. In other words, cursor P1 becomes an alias for the
** MEM_Blob content contained in register P2.
**
** A pseudo-table created by this opcode is used to hold a single
@@ -80938,8 +89385,13 @@ case OP_OpenPseudo: {
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
- pCx->uc.pseudoTableReg = pOp->p2;
+ pCx->seekResult = pOp->p2;
pCx->isTable = 1;
+ /* Give this pseudo-cursor a fake BtCursor pointer so that pCx
+ ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test
+ ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto()
+ ** which is a performance optimization */
+ pCx->uc.pCursor = sqlite3BtreeFakeValidCursor();
assert( pOp->p5==0 );
break;
}
@@ -80979,21 +89431,23 @@ case OP_ColumnsUsed: {
/* Opcode: SeekGE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
-** use the value in register P3 as the key. If cursor P1 refers
-** to an SQL index, then P3 is the first in an array of P4 registers
-** that are used as an unpacked index key.
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
+** use the value in register P3 as the key. If cursor P1 refers
+** to an SQL index, then P3 is the first in an array of P4 registers
+** that are used as an unpacked index key.
**
-** Reposition cursor P1 so that it points to the smallest entry that
-** is greater than or equal to the key value. If there are no records
+** Reposition cursor P1 so that it points to the smallest entry that
+** is greater than or equal to the key value. If there are no records
** greater than or equal to the key and P2 is not zero, then jump to P2.
**
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
-** opcode will always land on a record that equally equals the key, or
-** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this
-** opcode must be followed by an IdxLE opcode with the same arguments.
-** The IdxLE opcode will be skipped if this opcode succeeds, but the
-** IdxLE opcode will be used on subsequent loop iterations.
+** opcode will either land on a record that exactly matches the key, or
+** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ,
+** this opcode must be followed by an IdxLE opcode with the same arguments.
+** The IdxGT opcode will be skipped if this opcode succeeds, but the
+** IdxGT opcode will be used on subsequent loop iterations. The
+** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
+** is an equality search.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
@@ -81004,13 +89458,13 @@ case OP_ColumnsUsed: {
/* Opcode: SeekGT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
-** use the value in register P3 as a key. If cursor P1 refers
-** to an SQL index, then P3 is the first in an array of P4 registers
-** that are used as an unpacked index key.
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
+** use the value in register P3 as a key. If cursor P1 refers
+** to an SQL index, then P3 is the first in an array of P4 registers
+** that are used as an unpacked index key.
**
-** Reposition cursor P1 so that it points to the smallest entry that
-** is greater than the key value. If there are no records greater than
+** Reposition cursor P1 so that it points to the smallest entry that
+** is greater than the key value. If there are no records greater than
** the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in forward order,
@@ -81019,16 +89473,16 @@ case OP_ColumnsUsed: {
**
** See also: Found, NotFound, SeekLt, SeekGe, SeekLe
*/
-/* Opcode: SeekLT P1 P2 P3 P4 *
+/* Opcode: SeekLT P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
-** use the value in register P3 as a key. If cursor P1 refers
-** to an SQL index, then P3 is the first in an array of P4 registers
-** that are used as an unpacked index key.
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
+** use the value in register P3 as a key. If cursor P1 refers
+** to an SQL index, then P3 is the first in an array of P4 registers
+** that are used as an unpacked index key.
**
-** Reposition cursor P1 so that it points to the largest entry that
-** is less than the key value. If there are no records less than
+** Reposition cursor P1 so that it points to the largest entry that
+** is less than the key value. If there are no records less than
** the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in reverse order,
@@ -81040,13 +89494,13 @@ case OP_ColumnsUsed: {
/* Opcode: SeekLE P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
-** use the value in register P3 as a key. If cursor P1 refers
-** to an SQL index, then P3 is the first in an array of P4 registers
-** that are used as an unpacked index key.
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
+** use the value in register P3 as a key. If cursor P1 refers
+** to an SQL index, then P3 is the first in an array of P4 registers
+** that are used as an unpacked index key.
**
-** Reposition cursor P1 so that it points to the largest entry that
-** is less than or equal to the key value. If there are no records
+** Reposition cursor P1 so that it points to the largest entry that
+** is less than or equal to the key value. If there are no records
** less than or equal to the key and P2 is not zero, then jump to P2.
**
** This opcode leaves the cursor configured to move in reverse order,
@@ -81054,18 +89508,20 @@ case OP_ColumnsUsed: {
** configured to use Prev, not Next.
**
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
-** opcode will always land on a record that equally equals the key, or
-** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this
-** opcode must be followed by an IdxGE opcode with the same arguments.
+** opcode will either land on a record that exactly matches the key, or
+** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ,
+** this opcode must be followed by an IdxLE opcode with the same arguments.
** The IdxGE opcode will be skipped if this opcode succeeds, but the
-** IdxGE opcode will be used on subsequent loop iterations.
+** IdxGE opcode will be used on subsequent loop iterations. The
+** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
+** is an equality search.
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
-case OP_SeekLT: /* jump, in3 */
-case OP_SeekLE: /* jump, in3 */
-case OP_SeekGE: /* jump, in3 */
-case OP_SeekGT: { /* jump, in3 */
+case OP_SeekLT: /* jump, in3, group */
+case OP_SeekLE: /* jump, in3, group */
+case OP_SeekGE: /* jump, in3, group */
+case OP_SeekGT: { /* jump, in3, group */
int res; /* Comparison result */
int oc; /* Opcode */
VdbeCursor *pC; /* The cursor to seek */
@@ -81091,28 +89547,39 @@ case OP_SeekGT: { /* jump, in3 */
pC->seekOp = pOp->opcode;
#endif
+ pC->deferredMoveto = 0;
+ pC->cacheStatus = CACHE_STALE;
if( pC->isTable ){
- /* The BTREE_SEEK_EQ flag is only set on index cursors */
- assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 );
+ u16 flags3, newType;
+ /* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */
+ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
+ || CORRUPT_DB );
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
** the seek, so convert it. */
pIn3 = &aMem[pOp->p3];
- if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ flags3 = pIn3->flags;
+ if( (flags3 & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn3, 0);
}
- iKey = sqlite3VdbeIntValue(pIn3);
+ iKey = sqlite3VdbeIntValue(pIn3); /* Get the integer key value */
+ newType = pIn3->flags; /* Record the type after applying numeric affinity */
+ pIn3->flags = flags3; /* But convert the type back to its original */
/* If the P3 value could not be converted into an integer without
** loss of information, then special processing is required... */
- if( (pIn3->flags & MEM_Int)==0 ){
- if( (pIn3->flags & MEM_Real)==0 ){
- /* If the P3 value cannot be converted into any kind of a number,
- ** then the seek is not possible, so jump to P2 */
- VdbeBranchTaken(1,2); goto jump_to_p2;
- break;
- }
+ if( (newType & (MEM_Int|MEM_IntReal))==0 ){
+ if( (newType & MEM_Real)==0 ){
+ if( (newType & MEM_Null) || oc>=OP_SeekGE ){
+ VdbeBranchTaken(1,2);
+ goto jump_to_p2;
+ }else{
+ rc = sqlite3BtreeLast(pC->uc.pCursor, &res);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ goto seek_not_found;
+ }
+ }else
/* If the approximation iKey is larger than the actual real search
** term, substitute >= for > and < for <=. e.g. if the search term
@@ -81136,21 +89603,24 @@ case OP_SeekGT: { /* jump, in3 */
assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) );
if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
}
- }
+ }
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
pC->movetoTarget = iKey; /* Used by OP_Delete */
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
}else{
- /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
- ** OP_SeekLE opcodes are allowed, and these must be immediately followed
- ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
+ /* For a cursor with the OPFLAG_SEEKEQ/BTREE_SEEK_EQ hint, only the
+ ** OP_SeekGE and OP_SeekLE opcodes are allowed, and these must be
+ ** immediately followed by an OP_IdxGT or OP_IdxLT opcode, respectively,
+ ** with the same key.
*/
if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
eqOnly = 1;
assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
+ assert( pOp->opcode==OP_SeekGE || pOp[1].opcode==OP_IdxLT );
+ assert( pOp->opcode==OP_SeekLE || pOp[1].opcode==OP_IdxGT );
assert( pOp[1].p1==pOp[0].p1 );
assert( pOp[1].p2==pOp[0].p2 );
assert( pOp[1].p3==pOp[0].p3 );
@@ -81190,16 +89660,21 @@ case OP_SeekGT: { /* jump, in3 */
goto seek_not_found;
}
}
- pC->deferredMoveto = 0;
- pC->cacheStatus = CACHE_STALE;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
if( oc>=OP_SeekGE ){ assert( oc==OP_SeekGE || oc==OP_SeekGT );
if( res<0 || (res==0 && oc==OP_SeekGT) ){
res = 0;
- rc = sqlite3BtreeNext(pC->uc.pCursor, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ res = 1;
+ }else{
+ goto abort_due_to_error;
+ }
+ }
}else{
res = 0;
}
@@ -81207,8 +89682,15 @@ case OP_SeekGT: { /* jump, in3 */
assert( oc==OP_SeekLT || oc==OP_SeekLE );
if( res>0 || (res==0 && oc==OP_SeekLT) ){
res = 0;
- rc = sqlite3BtreePrevious(pC->uc.pCursor, &res);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ rc = sqlite3BtreePrevious(pC->uc.pCursor, 0);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_DONE ){
+ rc = SQLITE_OK;
+ res = 1;
+ }else{
+ goto abort_due_to_error;
+ }
+ }
}else{
/* res might be negative because the table is empty. Check to
** see if this is the case.
@@ -81228,6 +89710,39 @@ seek_not_found:
break;
}
+/* Opcode: SeekHit P1 P2 * * *
+** Synopsis: seekHit=P2
+**
+** Set the seekHit flag on cursor P1 to the value in P2.
+** The seekHit flag is used by the IfNoHope opcode.
+**
+** P1 must be a valid b-tree cursor. P2 must be a boolean value,
+** either 0 or 1.
+*/
+case OP_SeekHit: {
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pOp->p2==0 || pOp->p2==1 );
+ pC->seekHit = pOp->p2 & 1;
+ break;
+}
+
+/* Opcode: IfNotOpen P1 P2 * * *
+** Synopsis: if( !csr[P1] ) goto P2
+**
+** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
+*/
+case OP_IfNotOpen: { /* jump */
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
+ if( !p->apCsr[pOp->p1] ){
+ goto jump_to_p2_and_check_for_interrupt;
+ }
+ break;
+}
+
/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
**
@@ -81251,9 +89766,9 @@ seek_not_found:
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
-**
+**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
-** is not the prefix of any entry in P1 then a jump is made to P2. If P1
+** is not the prefix of any entry in P1 then a jump is made to P2. If P1
** does contain an entry whose prefix matches the P3/P4 record then control
** falls through to the next instruction and P1 is left pointing at the
** matching entry.
@@ -81262,7 +89777,34 @@ seek_not_found:
** advanced in either direction. In other words, the Next and Prev
** opcodes do not work after this operation.
**
-** See also: Found, NotExists, NoConflict
+** See also: Found, NotExists, NoConflict, IfNoHope
+*/
+/* Opcode: IfNoHope P1 P2 P3 P4 *
+** Synopsis: key=r[P3@P4]
+**
+** Register P3 is the first of P4 registers that form an unpacked
+** record.
+**
+** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then
+** this opcode is a no-op. But if the seekHit flag of P1 is clear, then
+** check to see if there is any entry in P1 that matches the
+** prefix identified by P3 and P4. If no entry matches the prefix,
+** jump to P2. Otherwise fall through.
+**
+** This opcode behaves like OP_NotFound if the seekHit
+** flag is clear and it behaves like OP_Noop if the seekHit flag is set.
+**
+** This opcode is used in IN clause processing for a multi-column key.
+** If an IN clause is attached to an element of the key other than the
+** left-most element, and if there are no matches on the most recent
+** seek over the whole key, then it might be that one of the key element
+** to the left is prohibiting a match, and hence there is "no hope" of
+** any match regardless of how many IN clause elements are checked.
+** In such a case, we abandon the IN clause search early, using this
+** opcode. The opcode name comes from the fact that the
+** jump is taken if there is "no hope" of achieving a match.
+**
+** See also: NotFound, SeekHit
*/
/* Opcode: NoConflict P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
@@ -81270,7 +89812,7 @@ seek_not_found:
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
** P4>0 then register P3 is the first of P4 registers that form an unpacked
** record.
-**
+**
** Cursor P1 is on an index btree. If the record identified by P3 and P4
** contains any NULL value, jump immediately to P2. If all terms of the
** record are not-NULL then a check is done to determine if any row in the
@@ -81287,6 +89829,15 @@ seek_not_found:
**
** See also: NotFound, Found, NotExists
*/
+case OP_IfNoHope: { /* jump, in3 */
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ if( pC->seekHit ) break;
+ /* Fall through into OP_NotFound */
+ /* no break */ deliberate_fall_through
+}
case OP_NoConflict: /* jump, in3 */
case OP_NotFound: /* jump, in3 */
case OP_Found: { /* jump, in3 */
@@ -81295,10 +89846,9 @@ case OP_Found: { /* jump, in3 */
int ii;
VdbeCursor *pC;
int res;
- char *pFree;
+ UnpackedRecord *pFree;
UnpackedRecord *pIdxKey;
UnpackedRecord r;
- char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*4 + 7];
#ifdef SQLITE_TEST
if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
@@ -81315,7 +89865,6 @@ case OP_Found: { /* jump, in3 */
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 );
- pFree = 0;
if( pOp->p4.i>0 ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
@@ -81328,13 +89877,14 @@ case OP_Found: { /* jump, in3 */
}
#endif
pIdxKey = &r;
+ pFree = 0;
}else{
- pIdxKey = sqlite3VdbeAllocUnpackedRecord(
- pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
- );
- if( pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
- (void)ExpandBlob(pIn3);
+ rc = ExpandBlob(pIn3);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc ) goto no_mem;
+ pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
+ if( pIdxKey==0 ) goto no_mem;
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
}
pIdxKey->default_rc = 0;
@@ -81351,7 +89901,7 @@ case OP_Found: { /* jump, in3 */
}
}
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
- sqlite3DbFree(db, pFree);
+ if( pFree ) sqlite3DbFreeNN(db, pFree);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
@@ -81375,9 +89925,9 @@ case OP_Found: { /* jump, in3 */
**
** P1 is the index of a cursor open on an SQL table btree (with integer
** keys). If register P3 does not contain an integer or if P1 does not
-** contain a record with rowid P3 then jump immediately to P2.
+** contain a record with rowid P3 then jump immediately to P2.
** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain
-** a record with rowid P3 then
+** a record with rowid P3 then
** leave the cursor pointing at that record and fall through to the next
** instruction.
**
@@ -81400,7 +89950,7 @@ case OP_Found: { /* jump, in3 */
** P1 is the index of a cursor open on an SQL table btree (with integer
** keys). P3 is an integer rowid. If P1 does not contain a record with
** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an
-** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then
+** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then
** leave the cursor pointing at that record and fall through to the next
** instruction.
**
@@ -81424,26 +89974,40 @@ case OP_SeekRowid: { /* jump, in3 */
u64 iKey;
pIn3 = &aMem[pOp->p3];
- if( (pIn3->flags & MEM_Int)==0 ){
- applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
- if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2;
+ testcase( pIn3->flags & MEM_Int );
+ testcase( pIn3->flags & MEM_IntReal );
+ testcase( pIn3->flags & MEM_Real );
+ testcase( (pIn3->flags & (MEM_Str|MEM_Int))==MEM_Str );
+ if( (pIn3->flags & (MEM_Int|MEM_IntReal))==0 ){
+ /* If pIn3->u.i does not contain an integer, compute iKey as the
+ ** integer value of pIn3. Jump to P2 if pIn3 cannot be converted
+ ** into an integer without loss of information. Take care to avoid
+ ** changing the datatype of pIn3, however, as it is used by other
+ ** parts of the prepared statement. */
+ Mem x = pIn3[0];
+ applyAffinity(&x, SQLITE_AFF_NUMERIC, encoding);
+ if( (x.flags & MEM_Int)==0 ) goto jump_to_p2;
+ iKey = x.u.i;
+ goto notExistsWithKey;
}
/* Fall through into OP_NotExists */
+ /* no break */ deliberate_fall_through
case OP_NotExists: /* jump, in3 */
pIn3 = &aMem[pOp->p3];
- assert( pIn3->flags & MEM_Int );
+ assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ iKey = pIn3->u.i;
+notExistsWithKey:
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
#ifdef SQLITE_DEBUG
- pC->seekOp = 0;
+ if( pOp->opcode==OP_SeekRowid ) pC->seekOp = OP_SeekRowid;
#endif
assert( pC->isTable );
assert( pC->eCurType==CURTYPE_BTREE );
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
res = 0;
- iKey = pIn3->u.i;
rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
assert( rc==SQLITE_OK || res==0 );
pC->movetoTarget = iKey; /* Used by OP_Delete */
@@ -81470,7 +90034,7 @@ case OP_NotExists: /* jump, in3 */
** Find the next available sequence number for cursor P1.
** Write the sequence number into register P2.
** The sequence number on the cursor is incremented after this
-** instruction.
+** instruction.
*/
case OP_Sequence: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
@@ -81490,9 +90054,9 @@ case OP_Sequence: { /* out2 */
** table that cursor P1 points to. The new record number is written
** written to register P2.
**
-** If P3>0 then P3 is a register in the root frame of this VDBE that holds
+** 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,
+** allowed to be less than this value. When this value reaches its maximum,
** 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.
@@ -81511,6 +90075,7 @@ case OP_NewRowid: { /* out2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
+ assert( pC->isTable );
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
{
@@ -81578,7 +90143,7 @@ case OP_NewRowid: { /* out2 */
sqlite3VdbeMemIntegerify(pMem);
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
- rc = SQLITE_FULL; /* IMP: R-12275-61338 */
+ rc = SQLITE_FULL; /* IMP: R-17817-00630 */
goto abort_due_to_error;
}
if( v<pMem->u.i+1 ){
@@ -81630,23 +90195,18 @@ case OP_NewRowid: { /* out2 */
** then rowid is stored for subsequent return by the
** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
**
-** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of
-** the last seek operation (OP_NotExists or OP_SeekRowid) was a success,
-** then this
-** operation will not attempt to find the appropriate row before doing
-** the insert but will instead overwrite the row that the cursor is
-** currently pointing to. Presumably, the prior OP_NotExists or
-** OP_SeekRowid opcode
-** has already positioned the cursor correctly. This is an optimization
-** that boosts performance by avoiding redundant seeks.
+** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
+** run faster by avoiding an unnecessary seek on cursor P1. However,
+** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
+** seeks on the cursor or if the most recent seek used a key equal to P3.
**
** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
** UPDATE operation. Otherwise (if the flag is clear) then this opcode
** is part of an INSERT operation. The difference is only important to
** the update hook.
**
-** Parameter P4 may point to a Table structure, or may be NULL. If it is
-** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked
+** Parameter P4 may point to a Table structure, or may be NULL. If it is
+** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked
** following a successful insert.
**
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
@@ -81658,78 +90218,63 @@ case OP_NewRowid: { /* out2 */
** This instruction only works on tables. The equivalent instruction
** for indices is OP_IdxInsert.
*/
-/* Opcode: InsertInt P1 P2 P3 P4 P5
-** Synopsis: intkey=P3 data=r[P2]
-**
-** This works exactly like OP_Insert except that the key is the
-** integer value P3, not the value of the integer stored in register P3.
-*/
-case OP_Insert:
-case OP_InsertInt: {
+case OP_Insert: {
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
VdbeCursor *pC; /* Cursor to table into which insert is written */
int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */
const char *zDb; /* database name - used by the update hook */
Table *pTab; /* Table structure - used by update and pre-update hooks */
- int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
BtreePayload x; /* Payload to be inserted */
- op = 0;
pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( memIsValid(pData) );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
+ assert( pC->deferredMoveto==0 );
assert( pC->uc.pCursor!=0 );
- assert( pC->isTable );
+ assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
REGISTER_TRACE(pOp->p2, pData);
+ sqlite3VdbeIncrWriteCounter(p, pC);
- if( pOp->opcode==OP_Insert ){
- pKey = &aMem[pOp->p3];
- assert( pKey->flags & MEM_Int );
- assert( memIsValid(pKey) );
- REGISTER_TRACE(pOp->p3, pKey);
- x.nKey = pKey->u.i;
- }else{
- assert( pOp->opcode==OP_InsertInt );
- x.nKey = pOp->p3;
- }
+ pKey = &aMem[pOp->p3];
+ assert( pKey->flags & MEM_Int );
+ assert( memIsValid(pKey) );
+ REGISTER_TRACE(pOp->p3, pKey);
+ x.nKey = pKey->u.i;
if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
- assert( pC->isTable );
assert( pC->iDb>=0 );
zDb = db->aDb[pC->iDb].zDbSName;
pTab = pOp->p4.pTab;
- assert( HasRowid(pTab) );
- op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
+ assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
}else{
- pTab = 0; /* Not needed. Silence a comiler warning. */
+ pTab = 0;
zDb = 0; /* Not needed. Silence a compiler warning. */
}
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/* Invoke the pre-update hook, if any */
- if( db->xPreUpdateCallback
- && pOp->p4type==P4_TABLE
- && !(pOp->p5 & OPFLAG_ISUPDATE)
- ){
- sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2);
+ if( pTab ){
+ if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){
+ sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2);
+ }
+ if( db->xUpdateCallback==0 || pTab->aCol==0 ){
+ /* Prevent post-update hook from running in cases when it should not */
+ pTab = 0;
+ }
}
+ if( pOp->p5 & OPFLAG_ISNOOP ) break;
#endif
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = x.nKey;
- if( pData->flags & MEM_Null ){
- x.pData = 0;
- x.nData = 0;
- }else{
- assert( pData->flags & (MEM_Blob|MEM_Str) );
- x.pData = pData->z;
- x.nData = pData->n;
- }
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
+ assert( pData->flags & (MEM_Blob|MEM_Str) );
+ x.pData = pData->z;
+ x.nData = pData->n;
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
if( pData->flags & MEM_Zero ){
x.nZero = pData->u.nZero;
@@ -81738,15 +90283,19 @@ case OP_InsertInt: {
}
x.pKey = 0;
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
- (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
+ (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
if( rc ) goto abort_due_to_error;
- if( db->xUpdateCallback && op ){
- db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey);
+ if( pTab ){
+ assert( db->xUpdateCallback!=0 );
+ assert( pTab->aCol!=0 );
+ db->xUpdateCallback(db->pUpdateArg,
+ (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT,
+ zDb, pTab->zName, x.nKey);
}
break;
}
@@ -81759,7 +90308,7 @@ case OP_InsertInt: {
** the cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
** the next Next instruction will be a no-op. As a result, in this case
-** it is ok to delete a record from within a Next loop. If
+** it is ok to delete a record from within a Next loop. If
** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
** left in an undefined state.
**
@@ -81775,11 +90324,11 @@ case OP_InsertInt: {
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
**
-** If P4 is not NULL then it points to a Table object. In this case either
+** If P4 is not NULL then it points to a Table object. In this case either
** the update or pre-update hook, or both, may be invoked. The P1 cursor must
-** have been positioned using OP_NotFound prior to invoking this opcode in
-** this case. Specifically, if one is configured, the pre-update hook is
-** invoked if P4 is not NULL. The update-hook is invoked if one is configured,
+** have been positioned using OP_NotFound prior to invoking this opcode in
+** this case. Specifically, if one is configured, the pre-update hook is
+** invoked if P4 is not NULL. The update-hook is invoked if one is configured,
** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
**
** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
@@ -81799,21 +90348,26 @@ case OP_Delete: {
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->deferredMoveto==0 );
+ sqlite3VdbeIncrWriteCounter(p, pC);
#ifdef SQLITE_DEBUG
- if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
+ if( pOp->p4type==P4_TABLE
+ && HasRowid(pOp->p4.pTab)
+ && pOp->p5==0
+ && sqlite3BtreeCursorIsValidNN(pC->uc.pCursor)
+ ){
/* If p5 is zero, the seek operation that positioned the cursor prior to
** OP_Delete will have also set the pC->movetoTarget field to the rowid of
** the row that is being deleted */
i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
- assert( pC->movetoTarget==iKey );
+ assert( CORRUPT_DB || pC->movetoTarget==iKey );
}
#endif
/* If the update-hook or pre-update-hook will be invoked, set zDb to
** the name of the db to pass as to it. Also set local pTab to a copy
** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
- ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set
+ ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set
** VdbeCursor.movetoTarget to the current rowid. */
if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
assert( pC->iDb>=0 );
@@ -81830,18 +90384,21 @@ case OP_Delete: {
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/* Invoke the pre-update-hook if required. */
- if( db->xPreUpdateCallback && pOp->p4.pTab && HasRowid(pTab) ){
- assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
+ if( db->xPreUpdateCallback && pOp->p4.pTab ){
+ assert( !(opflags & OPFLAG_ISUPDATE)
+ || HasRowid(pTab)==0
+ || (aMem[pOp->p3].flags & MEM_Int)
+ );
sqlite3VdbePreUpdateHook(p, pC,
- (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
+ (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
zDb, pTab, pC->movetoTarget,
pOp->p3
);
}
if( opflags & OPFLAG_ISNOOP ) break;
#endif
-
- /* Only flags that can be set are SAVEPOISTION and AUXDELETE */
+
+ /* Only flags that can be set are SAVEPOISTION and AUXDELETE */
assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
@@ -81862,6 +90419,7 @@ case OP_Delete: {
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
+ pC->seekResult = 0;
if( rc ) goto abort_due_to_error;
/* Invoke the update-hook if required. */
@@ -81893,7 +90451,7 @@ case OP_ResetCount: {
** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
**
** P1 is a sorter cursor. This instruction compares a prefix of the
-** record blob in register P3 against a prefix of the entry that
+** record blob in register P3 against a prefix of the entry that
** the sorter cursor currently points to. Only the first P4 fields
** of r[P3] and the sorter record are compared.
**
@@ -81948,50 +90506,51 @@ case OP_SorterData: {
break;
}
-/* Opcode: RowData P1 P2 * * *
+/* Opcode: RowData P1 P2 P3 * *
** Synopsis: r[P2]=data
**
-** Write into register P2 the complete row data for cursor P1.
-** There is no interpretation of the data.
-** It is just copied onto the P2 register exactly as
+** Write into register P2 the complete row content for the row at
+** which cursor P1 is currently pointing.
+** There is no interpretation of the data.
+** It is just copied onto the P2 register exactly as
** it is found in the database file.
**
+** If cursor P1 is an index, then the content is the key of the row.
+** If cursor P2 is a table, then the content extracted is the data.
+**
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
-*/
-/* Opcode: RowKey P1 P2 * * *
-** Synopsis: r[P2]=key
**
-** Write into register P2 the complete row key for cursor P1.
-** There is no interpretation of the data.
-** The key is copied onto the P2 register exactly as
-** it is found in the database file.
+** If P3!=0 then this opcode is allowed to make an ephemeral pointer
+** into the database page. That means that the content of the output
+** register will be invalidated as soon as the cursor moves - including
+** moves caused by other cursors that "save" the current cursors
+** position in order that they can write to the same table. If P3==0
+** then a copy of the data is made into memory. P3!=0 is faster, but
+** P3==0 is safer.
**
-** If the P1 cursor must be pointing to a valid row (not a NULL row)
-** of a real table, not a pseudo-table.
+** If P3!=0 then the content of the P2 register is unsuitable for use
+** in OP_Result and any OP_Result will invalidate the P2 register content.
+** The P2 register content is invalidated by opcodes like OP_Function or
+** by any use of another cursor pointing to the same table.
*/
-case OP_RowKey:
case OP_RowData: {
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
- pOut = &aMem[pOp->p2];
- memAboutToChange(p, pOut);
+ pOut = out2Prerelease(p, pOp);
- /* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( isSorter(pC)==0 );
- assert( pC->isTable || pOp->opcode!=OP_RowData );
- assert( pC->isTable==0 || pOp->opcode==OP_RowData );
assert( pC->nullRow==0 );
assert( pC->uc.pCursor!=0 );
pCrsr = pC->uc.pCursor;
- /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
+ /* The OP_RowData opcodes always follow OP_NotExists or
** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions
** that might invalidate the cursor.
** If this where not the case, on of the following assert()s
@@ -82001,28 +90560,15 @@ case OP_RowData: {
*/
assert( pC->deferredMoveto==0 );
assert( sqlite3BtreeCursorIsValid(pCrsr) );
-#if 0 /* Not required due to the previous to assert() statements */
- rc = sqlite3VdbeCursorMoveto(pC);
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
-#endif
n = sqlite3BtreePayloadSize(pCrsr);
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
testcase( n==0 );
- if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
- goto no_mem;
- }
- pOut->n = n;
- MemSetTypeFlag(pOut, MEM_Blob);
- if( pC->isTable==0 ){
- rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
- }else{
- rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
- }
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCrsr, n, pOut);
if( rc ) goto abort_due_to_error;
- pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
+ if( !pOp->p3 ) Deephemeralize(pOut);
UPDATE_MAX_BLOBSIZE(pOut);
REGISTER_TRACE(pOp->p2, pOut);
break;
@@ -82097,12 +90643,25 @@ case OP_NullRow: {
assert( pC->uc.pCursor!=0 );
sqlite3BtreeClearCursor(pC->uc.pCursor);
}
+#ifdef SQLITE_DEBUG
+ if( pC->seekOp==0 ) pC->seekOp = OP_NullRow;
+#endif
break;
}
-/* Opcode: Last P1 P2 P3 * *
+/* Opcode: SeekEnd P1 * * * *
**
-** The next use of the Rowid or Column or Prev instruction for P1
+** Position cursor P1 at the end of the btree for the purpose of
+** appending a new entry onto the btree.
+**
+** It is assumed that the cursor is used only for appending and so
+** if the cursor is valid, then the cursor must already be pointing
+** at the end of the btree and so no changes are made to
+** the cursor.
+*/
+/* Opcode: Last P1 P2 * * *
+**
+** The next use of the Rowid or Column or Prev instruction for P1
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
@@ -82112,6 +90671,7 @@ case OP_NullRow: {
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
*/
+case OP_SeekEnd:
case OP_Last: { /* jump */
VdbeCursor *pC;
BtCursor *pCrsr;
@@ -82124,14 +90684,20 @@ case OP_Last: { /* jump */
pCrsr = pC->uc.pCursor;
res = 0;
assert( pCrsr!=0 );
+#ifdef SQLITE_DEBUG
+ pC->seekOp = pOp->opcode;
+#endif
+ if( pOp->opcode==OP_SeekEnd ){
+ assert( pOp->p2==0 );
+ pC->seekResult = -1;
+ if( sqlite3BtreeCursorIsValidNN(pCrsr) ){
+ break;
+ }
+ }
rc = sqlite3BtreeLast(pCrsr, &res);
pC->nullRow = (u8)res;
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
- pC->seekResult = pOp->p3;
-#ifdef SQLITE_DEBUG
- pC->seekOp = OP_Last;
-#endif
if( rc ) goto abort_due_to_error;
if( pOp->p2>0 ){
VdbeBranchTaken(res!=0,2);
@@ -82140,7 +90706,43 @@ case OP_Last: { /* jump */
break;
}
+/* Opcode: IfSmaller P1 P2 P3 * *
+**
+** Estimate the number of rows in the table P1. Jump to P2 if that
+** estimate is less than approximately 2**(0.1*P3).
+*/
+case OP_IfSmaller: { /* jump */
+ VdbeCursor *pC;
+ BtCursor *pCrsr;
+ int res;
+ i64 sz;
+
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ pCrsr = pC->uc.pCursor;
+ assert( pCrsr );
+ rc = sqlite3BtreeFirst(pCrsr, &res);
+ if( rc ) goto abort_due_to_error;
+ if( res==0 ){
+ sz = sqlite3BtreeRowCountEst(pCrsr);
+ if( ALWAYS(sz>=0) && sqlite3LogEst((u64)sz)<pOp->p3 ) res = 1;
+ }
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
+ break;
+}
+
+/* Opcode: SorterSort P1 P2 * * *
+**
+** After all records have been inserted into the Sorter object
+** identified by P1, invoke this opcode to actually do the sorting.
+** Jump to P2 if there are no records to be sorted.
+**
+** This opcode is an alias for OP_Sort and OP_Rewind that is used
+** for Sorter objects.
+*/
/* Opcode: Sort P1 P2 * * *
**
** This opcode does exactly the same thing as OP_Rewind except that
@@ -82161,13 +90763,14 @@ case OP_Sort: { /* jump */
#endif
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
/* Fall through into OP_Rewind */
+ /* no break */ deliberate_fall_through
}
/* Opcode: Rewind P1 P2 * * *
**
-** The next use of the Rowid or Column or Next instruction for P1
+** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
** If the table or index is empty, jump immediately to P2.
-** If the table or index is not empty, fall through to the following
+** If the table or index is not empty, fall through to the following
** instruction.
**
** This opcode leaves the cursor configured to move in forward order,
@@ -82180,6 +90783,7 @@ case OP_Rewind: { /* jump */
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( pOp->p5==0 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
@@ -82230,12 +90834,7 @@ case OP_Rewind: { /* jump */
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
**
-** See also: Prev, NextIfOpen
-*/
-/* Opcode: NextIfOpen P1 P2 P3 P4 P5
-**
-** This opcode works just like Next except that if cursor P1 is not
-** open it behaves a no-op.
+** See also: Prev
*/
/* Opcode: Prev P1 P2 P3 P4 P5
**
@@ -82263,125 +90862,157 @@ case OP_Rewind: { /* jump */
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
-/* Opcode: PrevIfOpen P1 P2 P3 P4 P5
+/* Opcode: SorterNext P1 P2 * * P5
**
-** This opcode works just like Prev except that if cursor P1 is not
-** open it behaves a no-op.
+** This opcode works just like OP_Next except that P1 must be a
+** sorter object for which the OP_SorterSort opcode has been
+** invoked. This opcode advances the cursor to the next sorted
+** record, or jumps to P2 if there are no more sorted records.
*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
- int res;
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
- res = 0;
- rc = sqlite3VdbeSorterNext(db, pC, &res);
+ rc = sqlite3VdbeSorterNext(db, pC);
goto next_tail;
-case OP_PrevIfOpen: /* jump */
-case OP_NextIfOpen: /* jump */
- if( p->apCsr[pOp->p1]==0 ) break;
- /* Fall through */
case OP_Prev: /* jump */
case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<ArraySize(p->aCounter) );
pC = p->apCsr[pOp->p1];
- res = pOp->p3;
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
assert( pC->eCurType==CURTYPE_BTREE );
- assert( res==0 || (res==1 && pC->isTable==0) );
- testcase( res==1 );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
- assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
- assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
- /* The Next opcode is only used after SeekGT, SeekGE, and Rewind.
+ /* The Next opcode is only used after SeekGT, SeekGE, Rewind, and Found.
** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
- assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen
+ assert( pOp->opcode!=OP_Next
|| pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
- || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found);
- assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
+ || pC->seekOp==OP_Rewind || pC->seekOp==OP_Found
+ || pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid
+ || pC->seekOp==OP_IfNoHope);
+ assert( pOp->opcode!=OP_Prev
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
- || pC->seekOp==OP_Last );
+ || pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope
+ || pC->seekOp==OP_NullRow);
- rc = pOp->p4.xAdvance(pC->uc.pCursor, &res);
+ rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
next_tail:
pC->cacheStatus = CACHE_STALE;
- VdbeBranchTaken(res==0,2);
- if( rc ) goto abort_due_to_error;
- if( res==0 ){
+ VdbeBranchTaken(rc==SQLITE_OK,2);
+ if( rc==SQLITE_OK ){
pC->nullRow = 0;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
goto jump_to_p2_and_check_for_interrupt;
- }else{
- pC->nullRow = 1;
}
+ if( rc!=SQLITE_DONE ) goto abort_due_to_error;
+ rc = SQLITE_OK;
+ pC->nullRow = 1;
goto check_for_interrupt;
}
-/* Opcode: IdxInsert P1 P2 P3 * P5
+/* Opcode: IdxInsert P1 P2 P3 P4 P5
** Synopsis: key=r[P2]
**
** 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.
**
-** P3 is a flag that provides a hint to the b-tree layer that this
-** insert is likely to be an append.
+** If P4 is not zero, then it is the number of values in the unpacked
+** key of reg(P2). In that case, P3 is the index of the first register
+** for the unpacked key. The availability of the unpacked key can sometimes
+** be an optimization.
+**
+** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer
+** that this insert is likely to be an append.
**
** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear,
** then the change counter is unchanged.
**
-** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
-** just done a seek to the spot where the new entry is to be inserted.
-** This flag avoids doing an extra seek.
+** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
+** run faster by avoiding an unnecessary seek on cursor P1. However,
+** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
+** seeks on the cursor or if the most recent seek used a key equivalent
+** to P2.
**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
*/
-case OP_SorterInsert: /* in2 */
case OP_IdxInsert: { /* in2 */
VdbeCursor *pC;
BtreePayload x;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
+ sqlite3VdbeIncrWriteCounter(p, pC);
assert( pC!=0 );
- assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
+ assert( !isSorter(pC) );
pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob );
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
+ assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->isTable==0 );
rc = ExpandBlob(pIn2);
if( rc ) goto abort_due_to_error;
- if( pOp->opcode==OP_SorterInsert ){
- rc = sqlite3VdbeSorterWrite(pC, pIn2);
- }else{
- x.nKey = pIn2->n;
- x.pKey = pIn2->z;
- rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, pOp->p3,
- ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
- );
- assert( pC->deferredMoveto==0 );
- pC->cacheStatus = CACHE_STALE;
- }
+ x.nKey = pIn2->n;
+ x.pKey = pIn2->z;
+ x.aMem = aMem + pOp->p3;
+ x.nMem = (u16)pOp->p4.i;
+ rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
+ (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)),
+ ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
+ );
+ assert( pC->deferredMoveto==0 );
+ pC->cacheStatus = CACHE_STALE;
+ if( rc) goto abort_due_to_error;
+ break;
+}
+
+/* Opcode: SorterInsert P1 P2 * * *
+** Synopsis: key=r[P2]
+**
+** Register P2 holds an SQL index key made using the
+** MakeRecord instructions. This opcode writes that key
+** into the sorter P1. Data for the entry is nil.
+*/
+case OP_SorterInsert: { /* in2 */
+ VdbeCursor *pC;
+
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ sqlite3VdbeIncrWriteCounter(p, pC);
+ assert( pC!=0 );
+ assert( isSorter(pC) );
+ pIn2 = &aMem[pOp->p2];
+ assert( pIn2->flags & MEM_Blob );
+ assert( pC->isTable==0 );
+ rc = ExpandBlob(pIn2);
+ if( rc ) goto abort_due_to_error;
+ rc = sqlite3VdbeSorterWrite(pC, pIn2);
if( rc) goto abort_due_to_error;
break;
}
-/* Opcode: IdxDelete P1 P2 P3 * *
+/* Opcode: IdxDelete P1 P2 P3 * P5
** Synopsis: key=r[P2@P3]
**
** The content of P3 registers starting at register P2 form
-** an unpacked index key. This opcode removes that entry from the
+** an unpacked index key. This opcode removes that entry from the
** index opened by cursor P1.
+**
+** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
+** if no matching index entry is found. This happens when running
+** an UPDATE or DELETE statement and the index entry to be updated
+** or deleted is not found. For some uses of IdxDelete
+** (example: the EXCEPT operator) it does not matter that no matching
+** entry is found. For those cases, P5 is zero.
*/
case OP_IdxDelete: {
VdbeCursor *pC;
@@ -82395,9 +91026,9 @@ case OP_IdxDelete: {
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
+ sqlite3VdbeIncrWriteCounter(p, pC);
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
- assert( pOp->p5==0 );
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p3;
r.default_rc = 0;
@@ -82407,14 +91038,18 @@ case OP_IdxDelete: {
if( res==0 ){
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
if( rc ) goto abort_due_to_error;
+ }else if( pOp->p5 ){
+ rc = SQLITE_CORRUPT_INDEX;
+ goto abort_due_to_error;
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
+ pC->seekResult = 0;
break;
}
-/* Opcode: Seek P1 * P3 P4 *
-** Synopsis: Move P3 to P1.rowid
+/* Opcode: DeferredSeek P1 * P3 P4 *
+** Synopsis: Move P3 to P1.rowid if needed
**
** P1 is an open index cursor and P3 is a cursor on the corresponding
** table. This opcode does a deferred seek of the P3 table cursor
@@ -82426,8 +91061,8 @@ case OP_IdxDelete: {
**
** P4 may be an array of integers (type P4_INTARRAY) containing
** one entry for each column in the P3 table. If array entry a(i)
-** is non-zero, then reading column a(i)-1 from cursor P3 is
-** equivalent to performing the deferred seek and then reading column i
+** is non-zero, then reading column a(i)-1 from cursor P3 is
+** equivalent to performing the deferred seek and then reading column i
** from P1. This information is stored in P3 and used to redirect
** reads against P3 over to P1, thus possibly avoiding the need to
** seek and read cursor P3.
@@ -82441,11 +91076,11 @@ case OP_IdxDelete: {
**
** See also: Rowid, MakeRecord.
*/
-case OP_Seek:
-case OP_IdxRowid: { /* out2 */
- VdbeCursor *pC; /* The P1 index cursor */
- VdbeCursor *pTabCur; /* The P2 table cursor (OP_Seek only) */
- i64 rowid; /* Rowid that P1 current points to */
+case OP_DeferredSeek:
+case OP_IdxRowid: { /* out2 */
+ VdbeCursor *pC; /* The P1 index cursor */
+ VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */
+ i64 rowid; /* Rowid that P1 current points to */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -82471,7 +91106,7 @@ case OP_IdxRowid: { /* out2 */
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- if( pOp->opcode==OP_Seek ){
+ if( pOp->opcode==OP_DeferredSeek ){
assert( pOp->p3>=0 && pOp->p3<p->nCursor );
pTabCur = p->apCsr[pOp->p3];
assert( pTabCur!=0 );
@@ -82487,7 +91122,6 @@ case OP_IdxRowid: { /* out2 */
}else{
pOut = out2Prerelease(p, pOp);
pOut->u.i = rowid;
- pOut->flags = MEM_Int;
}
}else{
assert( pOp->opcode==OP_IdxRowid );
@@ -82496,12 +91130,30 @@ case OP_IdxRowid: { /* out2 */
break;
}
+/* Opcode: FinishSeek P1 * * * *
+**
+** If cursor P1 was previously moved via OP_DeferredSeek, complete that
+** seek operation now, without further delay. If the cursor seek has
+** already occurred, this instruction is a no-op.
+*/
+case OP_FinishSeek: {
+ VdbeCursor *pC; /* The P1 index cursor */
+
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ if( pC->deferredMoveto ){
+ rc = sqlite3VdbeFinishMoveto(pC);
+ if( rc ) goto abort_due_to_error;
+ }
+ break;
+}
+
/* Opcode: IdxGE P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
-** The P4 register values beginning with P3 form an unpacked index
-** key that omits the PRIMARY KEY. Compare this key value against the index
-** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
+** The P4 register values beginning with P3 form an unpacked index
+** key that omits the PRIMARY KEY. Compare this key value against the index
+** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
** fields at the end.
**
** If the P1 index entry is greater than or equal to the key value
@@ -82510,9 +91162,9 @@ case OP_IdxRowid: { /* out2 */
/* Opcode: IdxGT P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
-** The P4 register values beginning with P3 form an unpacked index
-** key that omits the PRIMARY KEY. Compare this key value against the index
-** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
+** The P4 register values beginning with P3 form an unpacked index
+** key that omits the PRIMARY KEY. Compare this key value against the index
+** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
** fields at the end.
**
** If the P1 index entry is greater than the key value
@@ -82521,7 +91173,7 @@ case OP_IdxRowid: { /* out2 */
/* Opcode: IdxLT P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
-** The P4 register values beginning with P3 form an unpacked index
+** The P4 register values beginning with P3 form an unpacked index
** key that omits the PRIMARY KEY or ROWID. Compare this key value against
** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or
** ROWID on the P1 index.
@@ -82532,7 +91184,7 @@ case OP_IdxRowid: { /* out2 */
/* Opcode: IdxLE P1 P2 P3 P4 P5
** Synopsis: key=r[P3@P4]
**
-** The P4 register values beginning with P3 form an unpacked index
+** The P4 register values beginning with P3 form an unpacked index
** key that omits the PRIMARY KEY or ROWID. Compare this key value against
** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or
** ROWID on the P1 index.
@@ -82568,7 +91220,13 @@ case OP_IdxGE: { /* jump */
}
r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+ {
+ int i;
+ for(i=0; i<r.nField; i++){
+ assert( memIsValid(&r.aMem[i]) );
+ REGISTER_TRACE(pOp->p3+i, &aMem[pOp->p3+i]);
+ }
+ }
#endif
res = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
@@ -82599,10 +91257,17 @@ case OP_IdxGE: { /* jump */
** might be moved into the newly deleted root page in order to keep all
** root pages contiguous at the beginning of the database. The former
** value of the root page that moved - its value before the move occurred -
-** is stored in register P2. If no page
-** movement was required (because the table being dropped was already
-** the last one in the database) then a zero is stored in register P2.
-** If AUTOVACUUM is disabled then a zero is stored in register P2.
+** is stored in register P2. If no page movement was required (because the
+** table being dropped was already the last one in the database) then a
+** zero is stored in register P2. If AUTOVACUUM is disabled then a zero
+** is stored in register P2.
+**
+** This opcode throws an error if there are any active reader VMs when
+** it is invoked. This is done to avoid the difficulty associated with
+** updating existing cursors when a root page is moved in an AUTOVACUUM
+** database. This error is thrown even if the database is not an AUTOVACUUM
+** db in order to avoid introducing an incompatibility between autovacuum
+** and non-autovacuum modes.
**
** See also: Clear
*/
@@ -82610,6 +91275,7 @@ case OP_Destroy: { /* out2 */
int iMoved;
int iDb;
+ sqlite3VdbeIncrWriteCounter(p, 0);
assert( p->readOnly==0 );
assert( pOp->p1>1 );
pOut = out2Prerelease(p, pOp);
@@ -82649,8 +91315,8 @@ case OP_Destroy: { /* out2 */
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the table referred to must be an
-** intkey table (an SQL table, not an index). In this case the row change
-** count is incremented by the number of rows in the table being cleared.
+** intkey table (an SQL table, not an index). In this case the row change
+** count is incremented by the number of rows in the table being cleared.
** If P3 is greater than zero, then the value stored in register P3 is
** also incremented by the number of rows in the table being cleared.
**
@@ -82658,12 +91324,13 @@ case OP_Destroy: { /* out2 */
*/
case OP_Clear: {
int nChange;
-
+
+ sqlite3VdbeIncrWriteCounter(p, 0);
nChange = 0;
assert( p->readOnly==0 );
assert( DbMaskTest(p->btreeMask, pOp->p2) );
rc = sqlite3BtreeClearTable(
- db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
+ db->aDb[pOp->p2].pBt, (u32)pOp->p1, (pOp->p3 ? &nChange : 0)
);
if( pOp->p3 ){
p->nChange += nChange;
@@ -82687,7 +91354,7 @@ case OP_Clear: {
*/
case OP_ResetSorter: {
VdbeCursor *pC;
-
+
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
@@ -82702,71 +91369,64 @@ case OP_ResetSorter: {
break;
}
-/* Opcode: CreateTable P1 P2 * * *
-** Synopsis: r[P2]=root iDb=P1
-**
-** Allocate a new table in the main database file if P1==0 or in the
-** auxiliary database file if P1==1 or in an attached database if
-** P1>1. Write the root page number of the new table into
-** register P2
+/* Opcode: CreateBtree P1 P2 P3 * *
+** Synopsis: r[P2]=root iDb=P1 flags=P3
**
-** The difference between a table and an index is this: A table must
-** have a 4-byte integer key and can have arbitrary data. An index
-** has an arbitrary key but no data.
-**
-** See also: CreateIndex
-*/
-/* Opcode: CreateIndex P1 P2 * * *
-** Synopsis: r[P2]=root iDb=P1
-**
-** Allocate a new index in the main database file if P1==0 or in the
-** auxiliary database file if P1==1 or in an attached database if
-** P1>1. Write the root page number of the new table into
-** register P2.
-**
-** See documentation on OP_CreateTable for additional information.
+** Allocate a new b-tree in the main database file if P1==0 or in the
+** TEMP database file if P1==1 or in an attached database if
+** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
+** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table.
+** The root page number of the new b-tree is stored in register P2.
*/
-case OP_CreateIndex: /* out2 */
-case OP_CreateTable: { /* out2 */
- int pgno;
- int flags;
+case OP_CreateBtree: { /* out2 */
+ Pgno pgno;
Db *pDb;
+ sqlite3VdbeIncrWriteCounter(p, 0);
pOut = out2Prerelease(p, pOp);
pgno = 0;
+ assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
assert( p->readOnly==0 );
pDb = &db->aDb[pOp->p1];
assert( pDb->pBt!=0 );
- if( pOp->opcode==OP_CreateTable ){
- /* flags = BTREE_INTKEY; */
- flags = BTREE_INTKEY;
- }else{
- flags = BTREE_BLOBKEY;
- }
- rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
+ rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, pOp->p3);
if( rc ) goto abort_due_to_error;
pOut->u.i = pgno;
break;
}
+/* Opcode: SqlExec * * * P4 *
+**
+** Run the SQL statement or statements specified in the P4 string.
+*/
+case OP_SqlExec: {
+ sqlite3VdbeIncrWriteCounter(p, 0);
+ db->nSqlExec++;
+ rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
+ db->nSqlExec--;
+ if( rc ) goto abort_due_to_error;
+ break;
+}
+
/* Opcode: ParseSchema P1 * * P4 *
**
-** Read and parse all entries from the SQLITE_MASTER table of database P1
-** that match the WHERE clause P4.
+** Read and parse all entries from the schema table of database P1
+** that match the WHERE clause P4. If P4 is a NULL pointer, then the
+** entire schema for P1 is reparsed.
**
** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a re-entrant opcode.
*/
case OP_ParseSchema: {
int iDb;
- const char *zMaster;
+ const char *zSchema;
char *zSql;
InitData initData;
/* Any prepared statement that invokes this opcode will hold mutexes
- ** on every btree. This is a prerequisite for invoking
+ ** on every btree. This is a prerequisite for invoking
** sqlite3InitCallback().
*/
#ifdef SQLITE_DEBUG
@@ -82778,24 +91438,43 @@ case OP_ParseSchema: {
iDb = pOp->p1;
assert( iDb>=0 && iDb<db->nDb );
assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
- /* Used to be a conditional */ {
- zMaster = SCHEMA_TABLE(iDb);
+
+#ifndef SQLITE_OMIT_ALTERTABLE
+ if( pOp->p4.z==0 ){
+ sqlite3SchemaClear(db->aDb[iDb].pSchema);
+ db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
+ rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
+ db->mDbFlags |= DBFLAG_SchemaChange;
+ p->expired = 0;
+ }else
+#endif
+ {
+ zSchema = DFLT_SCHEMA_TABLE;
initData.db = db;
- initData.iDb = pOp->p1;
+ initData.iDb = iDb;
initData.pzErrMsg = &p->zErrMsg;
+ initData.mInitFlags = 0;
+ initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt);
zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
- db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
+ "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
+ db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
assert( db->init.busy==0 );
db->init.busy = 1;
initData.rc = SQLITE_OK;
+ initData.nInitRow = 0;
assert( !db->mallocFailed );
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_OK ) rc = initData.rc;
- sqlite3DbFree(db, zSql);
+ if( rc==SQLITE_OK && initData.nInitRow==0 ){
+ /* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
+ ** at least one SQL statement. Any less than that indicates that
+ ** the sqlite_schema table is corrupt. */
+ rc = SQLITE_CORRUPT_BKPT;
+ }
+ sqlite3DbFreeNN(db, zSql);
db->init.busy = 0;
}
}
@@ -82806,7 +91485,7 @@ case OP_ParseSchema: {
}
goto abort_due_to_error;
}
- break;
+ break;
}
#if !defined(SQLITE_OMIT_ANALYZE)
@@ -82820,7 +91499,7 @@ case OP_LoadAnalysis: {
assert( pOp->p1>=0 && pOp->p1<db->nDb );
rc = sqlite3AnalysisLoad(db, pOp->p1);
if( rc ) goto abort_due_to_error;
- break;
+ break;
}
#endif /* !defined(SQLITE_OMIT_ANALYZE) */
@@ -82828,11 +91507,12 @@ case OP_LoadAnalysis: {
**
** Remove the internal (in-memory) data structures that describe
** the table named P4 in database P1. This is called after a table
-** is dropped from disk (using the Destroy opcode) in order to keep
+** is dropped from disk (using the Destroy opcode) in order to keep
** the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropTable: {
+ sqlite3VdbeIncrWriteCounter(p, 0);
sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z);
break;
}
@@ -82846,6 +91526,7 @@ case OP_DropTable: {
** schema consistent with what is on disk.
*/
case OP_DropIndex: {
+ sqlite3VdbeIncrWriteCounter(p, 0);
sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z);
break;
}
@@ -82854,11 +91535,12 @@ case OP_DropIndex: {
**
** Remove the internal (in-memory) data structures that describe
** the trigger named P4 in database P1. This is called after a trigger
-** is dropped from disk (using the Destroy opcode) in order to keep
+** is dropped from disk (using the Destroy opcode) in order to keep
** the internal representation of the
** schema consistent with what is on disk.
*/
case OP_DropTrigger: {
+ sqlite3VdbeIncrWriteCounter(p, 0);
sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z);
break;
}
@@ -82871,9 +91553,9 @@ case OP_DropTrigger: {
** register P1 the text of an error message describing any problems.
** If no problems are found, store a NULL in register P1.
**
-** The register P3 contains the maximum number of allowed errors.
+** The register P3 contains one less than the maximum number of allowed errors.
** At most reg(P3) errors will be reported.
-** In other words, the analysis stops as soon as reg(P1) errors are
+** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
** The root page numbers of all tables in the database are integers
@@ -82886,7 +91568,7 @@ case OP_DropTrigger: {
*/
case OP_IntegrityCk: {
int nRoot; /* Number of tables to check. (Number of root pages.) */
- int *aRoot; /* Array of rootpage numbers for tables to be checked */
+ Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
@@ -82895,7 +91577,7 @@ case OP_IntegrityCk: {
nRoot = pOp->p2;
aRoot = pOp->p4.ai;
assert( nRoot>0 );
- assert( aRoot[nRoot]==0 );
+ assert( aRoot[0]==(Pgno)nRoot );
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( (pnErr->flags & MEM_Int)!=0 );
@@ -82903,27 +91585,27 @@ case OP_IntegrityCk: {
pIn1 = &aMem[pOp->p1];
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
- z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
- (int)pnErr->u.i, &nErr);
- pnErr->u.i -= nErr;
+ z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
+ (int)pnErr->u.i+1, &nErr);
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
}else if( z==0 ){
goto no_mem;
}else{
+ pnErr->u.i -= nErr-1;
sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
}
UPDATE_MAX_BLOBSIZE(pIn1);
sqlite3VdbeChangeEncoding(pIn1, encoding);
- break;
+ goto check_for_interrupt;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/* Opcode: RowSetAdd P1 P2 * * *
** Synopsis: rowset(P1)=r[P2]
**
-** Insert the integer value held by register P2 into a boolean index
+** Insert the integer value held by register P2 into a RowSet object
** held in register P1.
**
** An assertion fails if P2 is not an integer.
@@ -82932,27 +91614,29 @@ case OP_RowSetAdd: { /* in1, in2 */
pIn1 = &aMem[pOp->p1];
pIn2 = &aMem[pOp->p2];
assert( (pIn2->flags & MEM_Int)!=0 );
- if( (pIn1->flags & MEM_RowSet)==0 ){
- sqlite3VdbeMemSetRowSet(pIn1);
- if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
+ if( (pIn1->flags & MEM_Blob)==0 ){
+ if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem;
}
- sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i);
+ assert( sqlite3VdbeMemIsRowSet(pIn1) );
+ sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i);
break;
}
/* Opcode: RowSetRead P1 P2 P3 * *
** Synopsis: r[P3]=rowset(P1)
**
-** Extract the smallest value from boolean index P1 and put that value into
-** register P3. Or, if boolean index P1 is initially empty, leave P3
+** Extract the smallest value from the RowSet object in P1
+** and put that value into register P3.
+** Or, if RowSet object P1 is initially empty, leave P3
** unchanged and jump to instruction P2.
*/
case OP_RowSetRead: { /* jump, in1, out3 */
i64 val;
pIn1 = &aMem[pOp->p1];
- if( (pIn1->flags & MEM_RowSet)==0
- || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0
+ assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) );
+ if( (pIn1->flags & MEM_Blob)==0
+ || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0
){
/* The boolean index is empty */
sqlite3VdbeMemSetNull(pIn1);
@@ -82975,15 +91659,14 @@ case OP_RowSetRead: { /* jump, in1, out3 */
** integer in P3 into the RowSet and continue on to the
** next opcode.
**
-** The RowSet object is optimized for the case where successive sets
-** of integers, where each set contains no duplicates. Each set
-** of values is identified by a unique P4 value. The first set
-** must have P4==0, the final set P4=-1. P4 must be either -1 or
-** non-negative. For non-negative values of P4 only the lower 4
-** bits are significant.
+** The RowSet object is optimized for the case where sets of integers
+** are inserted in distinct phases, which each set contains no duplicates.
+** Each set is identified by a unique P4 value. The first set
+** must have P4==0, the final set must have P4==-1, and for all other sets
+** must have P4>0.
**
** This allows optimizations: (a) when P4==0 there is no need to test
-** the rowset object for P3, as it is guaranteed not to contain it,
+** the RowSet object for P3, as it is guaranteed not to contain it,
** (b) when P4==-1 there is no need to insert the value, as it will
** never be tested for, and (c) when a value that is part of set X is
** inserted, there is no need to search to see if the same value was
@@ -83002,20 +91685,19 @@ case OP_RowSetTest: { /* jump, in1, in3 */
/* If there is anything other than a rowset object in memory cell P1,
** delete it now and initialize P1 with an empty rowset
*/
- if( (pIn1->flags & MEM_RowSet)==0 ){
- sqlite3VdbeMemSetRowSet(pIn1);
- if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem;
+ if( (pIn1->flags & MEM_Blob)==0 ){
+ if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem;
}
-
+ assert( sqlite3VdbeMemIsRowSet(pIn1) );
assert( pOp->p4type==P4_INT32 );
assert( iSet==-1 || iSet>=0 );
if( iSet ){
- exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
+ exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i);
VdbeBranchTaken(exists!=0,2);
if( exists ) goto jump_to_p2;
}
if( iSet>=0 ){
- sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
+ sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i);
}
break;
}
@@ -83025,13 +91707,13 @@ case OP_RowSetTest: { /* jump, in1, in3 */
/* Opcode: Program P1 P2 P3 P4 P5
**
-** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
+** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
**
-** P1 contains the address of the memory cell that contains the first memory
-** cell in an array of values used as arguments to the sub-program. P2
-** contains the address to jump to if the sub-program throws an IGNORE
-** exception using the RAISE() function. Register P3 contains the address
-** of a memory cell in this (the parent) VM that is used to allocate the
+** P1 contains the address of the memory cell that contains the first memory
+** cell in an array of values used as arguments to the sub-program. P2
+** contains the address to jump to if the sub-program throws an IGNORE
+** exception using the RAISE() function. Register P3 contains the address
+** of a memory cell in this (the parent) VM that is used to allocate the
** memory required by the sub-vdbe at runtime.
**
** P4 is a pointer to the VM containing the trigger program.
@@ -83051,17 +91733,17 @@ case OP_Program: { /* jump */
pProgram = pOp->p4.pProgram;
pRt = &aMem[pOp->p3];
assert( pProgram->nOp>0 );
-
- /* If the p5 flag is clear, then recursive invocation of triggers is
+
+ /* If the p5 flag is clear, then recursive invocation of triggers is
** disabled for backwards compatibility (p5 is set if this sub-program
** is really a trigger, not a foreign key action, and the flag set
** and cleared by the "PRAGMA recursive_triggers" command is clear).
- **
- ** It is recursive invocation of triggers, at the SQL level, that is
- ** disabled. In some cases a single trigger may generate more than one
- ** SubProgram (if the trigger may be executed with more than one different
+ **
+ ** It is recursive invocation of triggers, at the SQL level, that is
+ ** disabled. In some cases a single trigger may generate more than one
+ ** SubProgram (if the trigger may be executed with more than one different
** ON CONFLICT algorithm). SubProgram structures associated with a
- ** single trigger all have the same value for the SubProgram.token
+ ** single trigger all have the same value for the SubProgram.token
** variable. */
if( pOp->p5 ){
t = pProgram->token;
@@ -83077,10 +91759,10 @@ case OP_Program: { /* jump */
/* Register pRt is used to store the memory required to save the state
** of the current program, and the memory required at runtime to execute
- ** the trigger program. If this trigger has been fired before, then pRt
+ ** the trigger program. If this trigger has been fired before, then pRt
** is already allocated. Otherwise, it must be initialized. */
- if( (pRt->flags&MEM_Frame)==0 ){
- /* SubProgram.nMem is set to the number of memory cells used by the
+ if( (pRt->flags&MEM_Blob)==0 ){
+ /* SubProgram.nMem is set to the number of memory cells used by the
** program stored in SubProgram.aOp. As well as these, one memory
** cell is required for each cursor used by the program. Set local
** variable nMem (and later, VdbeFrame.nChildMem) to this value.
@@ -83090,14 +91772,17 @@ case OP_Program: { /* jump */
if( pProgram->nCsr==0 ) nMem++;
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
- + pProgram->nCsr * sizeof(VdbeCursor *);
+ + pProgram->nCsr * sizeof(VdbeCursor*)
+ + (pProgram->nOp + 7)/8;
pFrame = sqlite3DbMallocZero(db, nByte);
if( !pFrame ){
goto no_mem;
}
sqlite3VdbeMemRelease(pRt);
- pRt->flags = MEM_Frame;
- pRt->u.pFrame = pFrame;
+ pRt->flags = MEM_Blob|MEM_Dyn;
+ pRt->z = (char*)pFrame;
+ pRt->n = nByte;
+ pRt->xDel = sqlite3VdbeFrameMemDel;
pFrame->v = p;
pFrame->nChildMem = nMem;
@@ -83113,6 +91798,9 @@ case OP_Program: { /* jump */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
pFrame->anExec = p->anExec;
#endif
+#ifdef SQLITE_DEBUG
+ pFrame->iFrameMagic = SQLITE_FRAME_MAGIC;
+#endif
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
@@ -83120,8 +91808,9 @@ case OP_Program: { /* jump */
pMem->db = db;
}
}else{
- pFrame = pRt->u.pFrame;
- assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
+ pFrame = (VdbeFrame*)pRt->z;
+ assert( pRt->xDel==sqlite3VdbeFrameMemDel );
+ assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
|| (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
assert( pProgram->nCsr==pFrame->nChildCsr );
assert( (int)(pOp - aOp)==pFrame->pc );
@@ -83129,7 +91818,7 @@ case OP_Program: { /* jump */
p->nFrame++;
pFrame->pParent = p->pFrame;
- pFrame->lastRowid = lastRowid;
+ pFrame->lastRowid = db->lastRowid;
pFrame->nChange = p->nChange;
pFrame->nDbChange = p->db->nChange;
assert( pFrame->pAuxData==0 );
@@ -83141,22 +91830,34 @@ case OP_Program: { /* jump */
p->nMem = pFrame->nChildMem;
p->nCursor = (u16)pFrame->nChildCsr;
p->apCsr = (VdbeCursor **)&aMem[p->nMem];
+ pFrame->aOnce = (u8*)&p->apCsr[pProgram->nCsr];
+ memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
p->anExec = 0;
#endif
+#ifdef SQLITE_DEBUG
+ /* Verify that second and subsequent executions of the same trigger do not
+ ** try to reuse register values from the first use. */
+ {
+ int i;
+ for(i=0; i<p->nMem; i++){
+ aMem[i].pScopyFrom = 0; /* Prevent false-positive AboutToChange() errs */
+ MemSetTypeFlag(&aMem[i], MEM_Undefined); /* Fault if this reg is reused */
+ }
+ }
+#endif
pOp = &aOp[-1];
-
- break;
+ goto check_for_interrupt;
}
/* Opcode: Param P1 P2 * * *
**
-** This opcode is only ever present in sub-programs called via the
-** OP_Program instruction. Copy a value currently stored in a memory
-** cell of the calling (parent) frame to cell P2 in the current frames
-** address space. This is used by trigger programs to access the new.*
+** This opcode is only ever present in sub-programs called via the
+** OP_Program instruction. Copy a value currently stored in a memory
+** cell of the calling (parent) frame to cell P2 in the current frames
+** address space. This is used by trigger programs to access the new.*
** and old.* values.
**
** The address of the cell in the parent frame is determined by adding
@@ -83168,7 +91869,7 @@ case OP_Param: { /* out2 */
Mem *pIn;
pOut = out2Prerelease(p, pOp);
pFrame = p->pFrame;
- pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
+ pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
break;
}
@@ -83180,8 +91881,8 @@ case OP_Param: { /* out2 */
** Synopsis: fkctr[P1]+=P2
**
** Increment a "constraint counter" by P2 (P2 may be negative or positive).
-** If P1 is non-zero, the database constraint counter is incremented
-** (deferred foreign key constraints). Otherwise, if P1 is zero, the
+** If P1 is non-zero, the database constraint counter is incremented
+** (deferred foreign key constraints). Otherwise, if P1 is zero, the
** statement counter is incremented (immediate foreign key constraints).
*/
case OP_FkCounter: {
@@ -83199,7 +91900,7 @@ case OP_FkCounter: {
** Synopsis: if fkctr[P1]==0 goto P2
**
** This opcode tests if a foreign key constraint-counter is currently zero.
-** If so, jump to instruction P2. Otherwise, fall through to the next
+** If so, jump to instruction P2. Otherwise, fall through to the next
** instruction.
**
** If P1 is non-zero, then the jump is taken if the database constraint-counter
@@ -83225,7 +91926,7 @@ case OP_FkIfZero: { /* jump */
**
** P1 is a register in the root frame of this VM (the root frame is
** different from the current frame if this instruction is being executed
-** within a sub-program). Set the value of register P1 to the maximum of
+** within a sub-program). Set the value of register P1 to the maximum of
** its current value and the value in register P2.
**
** This instruction throws an error if the memory cell is not initially
@@ -83285,34 +91986,47 @@ case OP_IfPos: { /* jump, in1 */
** and r[P2] is set to be the value of the LIMIT, r[P1].
**
** if r[P1] is zero or negative, that means there is no LIMIT
-** and r[P2] is set to -1.
+** and r[P2] is set to -1.
**
** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
*/
case OP_OffsetLimit: { /* in1, out2, in3 */
+ i64 x;
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
pOut = out2Prerelease(p, pOp);
assert( pIn1->flags & MEM_Int );
assert( pIn3->flags & MEM_Int );
- pOut->u.i = pIn1->u.i<=0 ? -1 : pIn1->u.i+(pIn3->u.i>0?pIn3->u.i:0);
+ x = pIn1->u.i;
+ if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){
+ /* If the LIMIT is less than or equal to zero, loop forever. This
+ ** is documented. But also, if the LIMIT+OFFSET exceeds 2^63 then
+ ** also loop forever. This is undocumented. In fact, one could argue
+ ** that the loop should terminate. But assuming 1 billion iterations
+ ** per second (far exceeding the capabilities of any current hardware)
+ ** it would take nearly 300 years to actually reach the limit. So
+ ** looping forever is a reasonable approximation. */
+ pOut->u.i = -1;
+ }else{
+ pOut->u.i = x;
+ }
break;
}
-/* Opcode: IfNotZero P1 P2 P3 * *
-** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
+/* Opcode: IfNotZero P1 P2 * * *
+** Synopsis: if r[P1]!=0 then r[P1]--, goto P2
**
** Register P1 must contain an integer. If the content of register P1 is
-** initially nonzero, then subtract P3 from the value in register P1 and
-** jump to P2. If register P1 is initially zero, leave it unchanged
-** and fall through.
+** initially greater than zero, then decrement the value in register P1.
+** If it is non-zero (negative or positive) and then also jump to P2.
+** If register P1 is initially zero, leave it unchanged and fall through.
*/
case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i ){
- pIn1->u.i -= pOp->p3;
+ if( pIn1->u.i>0 ) pIn1->u.i--;
goto jump_to_p2;
}
break;
@@ -83321,37 +92035,48 @@ case OP_IfNotZero: { /* jump, in1 */
/* Opcode: DecrJumpZero P1 P2 * * *
** Synopsis: if (--r[P1])==0 goto P2
**
-** Register P1 must hold an integer. Decrement the value in register P1
-** then jump to P2 if the new value is exactly zero.
+** Register P1 must hold an integer. Decrement the value in P1
+** and jump to P2 if the new value is exactly zero.
*/
case OP_DecrJumpZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
- pIn1->u.i--;
+ if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--;
VdbeBranchTaken(pIn1->u.i==0, 2);
if( pIn1->u.i==0 ) goto jump_to_p2;
break;
}
-/* Opcode: AggStep0 * P2 P3 P4 P5
+/* Opcode: AggStep * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
-** Execute the step function for an aggregate. The
-** function has P5 arguments. P4 is a pointer to the FuncDef
-** structure that specifies the function. Register P3 is the
+** Execute the xStep function for an aggregate.
+** The function has P5 arguments. P4 is a pointer to the
+** FuncDef structure that specifies the function. Register P3 is the
** accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
*/
-/* Opcode: AggStep * P2 P3 P4 P5
+/* Opcode: AggInverse * P2 P3 P4 P5
+** Synopsis: accum=r[P3] inverse(r[P2@P5])
+**
+** Execute the xInverse function for an aggregate.
+** The function has P5 arguments. P4 is a pointer to the
+** FuncDef structure that specifies the function. Register P3 is the
+** accumulator.
+**
+** The P5 arguments are taken from register P2 and its
+** successors.
+*/
+/* Opcode: AggStep1 P1 P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
-** Execute the step function for an aggregate. The
-** function has P5 arguments. P4 is a pointer to an sqlite3_context
-** object that is used to run the function. Register P3 is
-** as the accumulator.
+** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
+** aggregate. The function has P5 arguments. P4 is a pointer to the
+** FuncDef structure that specifies the function. Register P3 is the
+** accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
@@ -83362,7 +92087,8 @@ case OP_DecrJumpZero: { /* jump, in1 */
** sqlite3_context only happens once, instead of on each call to the
** step function.
*/
-case OP_AggStep0: {
+case OP_AggInverse:
+case OP_AggStep: {
int n;
sqlite3_context *pCtx;
@@ -83371,28 +92097,48 @@ case OP_AggStep0: {
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
- pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
+ pCtx = sqlite3DbMallocRawNN(db, n*sizeof(sqlite3_value*) +
+ (sizeof(pCtx[0]) + sizeof(Mem) - sizeof(sqlite3_value*)));
if( pCtx==0 ) goto no_mem;
pCtx->pMem = 0;
+ pCtx->pOut = (Mem*)&(pCtx->argv[n]);
+ sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null);
pCtx->pFunc = pOp->p4.pFunc;
pCtx->iOp = (int)(pOp - aOp);
pCtx->pVdbe = p;
+ pCtx->skipFlag = 0;
+ pCtx->isError = 0;
pCtx->argc = n;
pOp->p4type = P4_FUNCCTX;
pOp->p4.pCtx = pCtx;
- pOp->opcode = OP_AggStep;
+
+ /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
+ assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
+
+ pOp->opcode = OP_AggStep1;
/* Fall through into OP_AggStep */
+ /* no break */ deliberate_fall_through
}
-case OP_AggStep: {
+case OP_AggStep1: {
int i;
sqlite3_context *pCtx;
Mem *pMem;
- Mem t;
assert( pOp->p4type==P4_FUNCCTX );
pCtx = pOp->p4.pCtx;
pMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+ if( pOp->p1 ){
+ /* This is an OP_AggInverse call. Verify that xStep has always
+ ** been called at least once prior to any xInverse call. */
+ assert( pMem->uTemp==0x1122e0e3 );
+ }else{
+ /* This is an OP_AggStep call. Mark it as such. */
+ pMem->uTemp = 0x1122e0e3;
+ }
+#endif
+
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
@@ -83410,48 +92156,81 @@ case OP_AggStep: {
#endif
pMem->n++;
- sqlite3VdbeMemInit(&t, db, MEM_Null);
- pCtx->pOut = &t;
- pCtx->fErrorOrAux = 0;
- pCtx->skipFlag = 0;
+ assert( pCtx->pOut->flags==MEM_Null );
+ assert( pCtx->isError==0 );
+ assert( pCtx->skipFlag==0 );
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pOp->p1 ){
+ (pCtx->pFunc->xInverse)(pCtx,pCtx->argc,pCtx->argv);
+ }else
+#endif
(pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
- if( pCtx->fErrorOrAux ){
- if( pCtx->isError ){
- sqlite3VdbeError(p, "%s", sqlite3_value_text(&t));
+
+ if( pCtx->isError ){
+ if( pCtx->isError>0 ){
+ sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
rc = pCtx->isError;
}
- sqlite3VdbeMemRelease(&t);
+ if( pCtx->skipFlag ){
+ assert( pOp[-1].opcode==OP_CollSeq );
+ i = pOp[-1].p1;
+ if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);
+ pCtx->skipFlag = 0;
+ }
+ sqlite3VdbeMemRelease(pCtx->pOut);
+ pCtx->pOut->flags = MEM_Null;
+ pCtx->isError = 0;
if( rc ) goto abort_due_to_error;
- }else{
- assert( t.flags==MEM_Null );
- }
- if( pCtx->skipFlag ){
- assert( pOp[-1].opcode==OP_CollSeq );
- i = pOp[-1].p1;
- if( i ) sqlite3VdbeMemSetInt64(&aMem[i], 1);
}
+ assert( pCtx->pOut->flags==MEM_Null );
+ assert( pCtx->skipFlag==0 );
break;
}
/* Opcode: AggFinal P1 P2 * P4 *
** Synopsis: accum=r[P1] N=P2
**
-** Execute the finalizer function for an aggregate. P1 is
-** the memory location that is the accumulator for the aggregate.
+** P1 is the memory location that is the accumulator for an aggregate
+** or window function. Execute the finalizer function
+** for an aggregate and store the result in P1.
**
** P2 is the number of arguments that the step function takes and
** P4 is a pointer to the FuncDef for this function. The P2
** argument is not used by this opcode. It is only there to disambiguate
** functions that can take varying numbers of arguments. The
-** P4 argument is only needed for the degenerate case where
+** P4 argument is only needed for the case where
** the step function was not previously called.
*/
+/* Opcode: AggValue * P2 P3 P4 *
+** Synopsis: r[P3]=value N=P2
+**
+** Invoke the xValue() function and store the result in register P3.
+**
+** P2 is the number of arguments that the step function takes and
+** P4 is a pointer to the FuncDef for this function. The P2
+** argument is not used by this opcode. It is only there to disambiguate
+** functions that can take varying numbers of arguments. The
+** P4 argument is only needed for the case where
+** the step function was not previously called.
+*/
+case OP_AggValue:
case OP_AggFinal: {
Mem *pMem;
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+ assert( pOp->p3==0 || pOp->opcode==OP_AggValue );
pMem = &aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
- rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pOp->p3 ){
+ memAboutToChange(p, &aMem[pOp->p3]);
+ rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc);
+ pMem = &aMem[pOp->p3];
+ }else
+#endif
+ {
+ rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
+ }
+
if( rc ){
sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
goto abort_due_to_error;
@@ -83497,9 +92276,9 @@ case OP_Checkpoint: {
}
for(i=0, pMem = &aMem[pOp->p3]; i<3; i++, pMem++){
sqlite3VdbeMemSetInt64(pMem, (i64)aRes[i]);
- }
+ }
break;
-};
+};
#endif
#ifndef SQLITE_OMIT_PRAGMA
@@ -83525,9 +92304,9 @@ case OP_JournalMode: { /* out2 */
pOut = out2Prerelease(p, pOp);
eNew = pOp->p3;
- assert( eNew==PAGER_JOURNALMODE_DELETE
- || eNew==PAGER_JOURNALMODE_TRUNCATE
- || eNew==PAGER_JOURNALMODE_PERSIST
+ assert( eNew==PAGER_JOURNALMODE_DELETE
+ || eNew==PAGER_JOURNALMODE_TRUNCATE
+ || eNew==PAGER_JOURNALMODE_PERSIST
|| eNew==PAGER_JOURNALMODE_OFF
|| eNew==PAGER_JOURNALMODE_MEMORY
|| eNew==PAGER_JOURNALMODE_WAL
@@ -83546,7 +92325,7 @@ case OP_JournalMode: { /* out2 */
zFilename = sqlite3PagerFilename(pPager, 1);
/* Do not allow a transition to journal_mode=WAL for a database
- ** in temporary storage or if the VFS does not support shared memory
+ ** in temporary storage or if the VFS does not support shared memory
*/
if( eNew==PAGER_JOURNALMODE_WAL
&& (sqlite3Strlen30(zFilename)==0 /* Temp file */
@@ -83566,14 +92345,14 @@ case OP_JournalMode: { /* out2 */
);
goto abort_due_to_error;
}else{
-
+
if( eOld==PAGER_JOURNALMODE_WAL ){
/* If leaving WAL mode, close the log file. If successful, the call
- ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
- ** file. An EXCLUSIVE lock may still be held on the database file
- ** after a successful return.
+ ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
+ ** file. An EXCLUSIVE lock may still be held on the database file
+ ** after a successful return.
*/
- rc = sqlite3PagerCloseWal(pPager);
+ rc = sqlite3PagerCloseWal(pPager, db);
if( rc==SQLITE_OK ){
sqlite3PagerSetJournalMode(pPager, eNew);
}
@@ -83582,7 +92361,7 @@ case OP_JournalMode: { /* out2 */
** as an intermediate */
sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF);
}
-
+
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
@@ -83608,14 +92387,19 @@ case OP_JournalMode: { /* out2 */
#endif /* SQLITE_OMIT_PRAGMA */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
-/* Opcode: Vacuum P1 * * * *
+/* Opcode: Vacuum P1 P2 * * *
**
** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more
** for an attached database. The "temp" database may not be vacuumed.
+**
+** If P2 is not zero, then it is a register holding a string which is
+** the file into which the result of vacuum should be written. When
+** P2 is zero, the vacuum overwrites the original database.
*/
case OP_Vacuum: {
assert( p->readOnly==0 );
- rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1);
+ rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1,
+ pOp->p2 ? &aMem[pOp->p2] : 0);
if( rc ) goto abort_due_to_error;
break;
}
@@ -83646,31 +92430,68 @@ case OP_IncrVacuum: { /* jump */
}
#endif
-/* Opcode: Expire P1 * * * *
+/* Opcode: Expire P1 P2 * * *
**
** Cause precompiled statements to expire. When an expired statement
** is executed using sqlite3_step() it will either automatically
** reprepare itself (if it was originally created using sqlite3_prepare_v2())
** or it will fail with SQLITE_SCHEMA.
-**
+**
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
** then only the currently executing statement is expired.
+**
+** If P2 is 0, then SQL statements are expired immediately. If P2 is 1,
+** then running SQL statements are allowed to continue to run to completion.
+** The P2==1 case occurs when a CREATE INDEX or similar schema change happens
+** that might help the statement run faster but which does not affect the
+** correctness of operation.
*/
case OP_Expire: {
+ assert( pOp->p2==0 || pOp->p2==1 );
if( !pOp->p1 ){
- sqlite3ExpirePreparedStatements(db);
+ sqlite3ExpirePreparedStatements(db, pOp->p2);
}else{
- p->expired = 1;
+ p->expired = pOp->p2+1;
}
break;
}
+/* Opcode: CursorLock P1 * * * *
+**
+** Lock the btree to which cursor P1 is pointing so that the btree cannot be
+** written by an other cursor.
+*/
+case OP_CursorLock: {
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pC->eCurType==CURTYPE_BTREE );
+ sqlite3BtreeCursorPin(pC->uc.pCursor);
+ break;
+}
+
+/* Opcode: CursorUnlock P1 * * * *
+**
+** Unlock the btree to which cursor P1 is pointing so that it can be
+** written by other cursors.
+*/
+case OP_CursorUnlock: {
+ VdbeCursor *pC;
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pC->eCurType==CURTYPE_BTREE );
+ sqlite3BtreeCursorUnpin(pC->uc.pCursor);
+ break;
+}
+
#ifndef SQLITE_OMIT_SHARED_CACHE
/* Opcode: TableLock P1 P2 P3 P4 *
** Synopsis: iDb=P1 root=P2 write=P3
**
** Obtain a lock on a particular table. This instruction is only used when
-** the shared-cache feature is enabled.
+** the shared-cache feature is enabled.
**
** P1 is the index of the database in sqlite3.aDb[] of the database
** on which the lock is acquired. A readlock is obtained if P3==0 or
@@ -83683,8 +92504,8 @@ case OP_Expire: {
*/
case OP_TableLock: {
u8 isWriteLock = (u8)pOp->p3;
- if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){
- int p1 = pOp->p1;
+ if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){
+ int p1 = pOp->p1;
assert( p1>=0 && p1<db->nDb );
assert( DbMaskTest(p->btreeMask, p1) );
assert( isWriteLock==0 || isWriteLock==1 );
@@ -83704,7 +92525,7 @@ case OP_TableLock: {
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VBegin * * * P4 *
**
-** P4 may be a pointer to an sqlite3_vtab structure. If so, call the
+** P4 may be a pointer to an sqlite3_vtab structure. If so, call the
** xBegin method for that table.
**
** Also, whether or not P4 is set, check that this is not being called from
@@ -83724,7 +92545,7 @@ case OP_VBegin: {
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VCreate P1 P2 * * *
**
-** P2 is a register that holds the name of a virtual table in database
+** P2 is a register that holds the name of a virtual table in database
** P1. Call the xCreate method for that table.
*/
case OP_VCreate: {
@@ -83760,6 +92581,7 @@ case OP_VDestroy: {
db->nVDestroy++;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
db->nVDestroy--;
+ assert( p->errorAction==OE_Abort && p->usesStmtJournal );
if( rc ) goto abort_due_to_error;
break;
}
@@ -83874,12 +92696,19 @@ case OP_VFilter: { /* jump */
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
-/* Opcode: VColumn P1 P2 P3 * *
+/* Opcode: VColumn P1 P2 P3 * P5
** Synopsis: r[P3]=vcolumn(P2)
**
-** Store the value of the P2-th column of
-** the row of the virtual-table that the
-** P1 cursor is pointing to into register P3.
+** Store in register P3 the value of the P2-th column of
+** the current row of the virtual-table of cursor P1.
+**
+** If the VColumn opcode is being used to fetch the value of
+** an unchanging column during an UPDATE operation, then the P5
+** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange()
+** function to return true inside the xColumn method of the virtual
+** table implementation. The P5 column might also contain other
+** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are
+** unused by OP_VColumn.
*/
case OP_VColumn: {
sqlite3_vtab *pVtab;
@@ -83901,10 +92730,18 @@ case OP_VColumn: {
assert( pModule->xColumn );
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
- MemSetTypeFlag(pDest, MEM_Null);
+ assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
+ if( pOp->p5 & OPFLAG_NOCHNG ){
+ sqlite3VdbeMemSetNull(pDest);
+ pDest->flags = MEM_Null|MEM_Zero;
+ pDest->u.nZero = 0;
+ }else{
+ MemSetTypeFlag(pDest, MEM_Null);
+ }
rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2);
sqlite3VtabImportErrmsg(p, pVtab);
- if( sContext.isError ){
+ if( sContext.isError>0 ){
+ sqlite3VdbeError(p, "%s", sqlite3_value_text(pDest));
rc = sContext.isError;
}
sqlite3VdbeChangeEncoding(pDest, encoding);
@@ -83944,7 +92781,7 @@ case OP_VNext: { /* jump */
/* Invoke the xNext() method of the module. There is no way for the
** underlying implementation to return an error if one occurs during
- ** xNext(). Instead, if an error occurs, true is returned (indicating that
+ ** xNext(). Instead, if an error occurs, true is returned (indicating that
** data is available) and the error code returned when xColumn or
** some other method is next invoked on the save virtual table cursor.
*/
@@ -83971,7 +92808,10 @@ case OP_VNext: { /* jump */
case OP_VRename: {
sqlite3_vtab *pVtab;
Mem *pName;
+ int isLegacy;
+ isLegacy = (db->flags & SQLITE_LegacyAlter);
+ db->flags |= SQLITE_LegacyAlter;
pVtab = pOp->p4.pVtab->pVtab;
pName = &aMem[pOp->p1];
assert( pVtab->pModule->xRename );
@@ -83985,6 +92825,7 @@ case OP_VRename: {
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
if( rc ) goto abort_due_to_error;
rc = pVtab->pModule->xRename(pVtab, pName->z);
+ if( isLegacy==0 ) db->flags &= ~(u64)SQLITE_LegacyAlter;
sqlite3VtabImportErrmsg(p, pVtab);
p->expired = 0;
if( rc ) goto abort_due_to_error;
@@ -83998,23 +92839,23 @@ case OP_VRename: {
**
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
** This opcode invokes the corresponding xUpdate method. P2 values
-** are contiguous memory cells starting at P3 to pass to the xUpdate
-** invocation. The value in register (P3+P2-1) corresponds to the
+** are contiguous memory cells starting at P3 to pass to the xUpdate
+** invocation. The value in register (P3+P2-1) corresponds to the
** p2th element of the argv array passed to xUpdate.
**
** The xUpdate method will do a DELETE or an INSERT or both.
** The argv[0] element (which corresponds to memory cell P3)
-** is the rowid of a row to delete. If argv[0] is NULL then no
-** deletion occurs. The argv[1] element is the rowid of the new
-** row. This can be NULL to have the virtual table select the new
-** rowid for itself. The subsequent elements in the array are
+** is the rowid of a row to delete. If argv[0] is NULL then no
+** deletion occurs. The argv[1] element is the rowid of the new
+** row. This can be NULL to have the virtual table select the new
+** rowid for itself. The subsequent elements in the array are
** the values of columns in the new row.
**
** If P2==1 then no insert is performed. argv[0] is the rowid of
** a row to delete.
**
** P1 is a boolean flag. If it is set to true and the xUpdate call
-** is successful, then the value returned by sqlite3_last_insert_rowid()
+** is successful, then the value returned by sqlite3_last_insert_rowid()
** is set to the value of the rowid for the row just inserted.
**
** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to
@@ -84029,10 +92870,12 @@ case OP_VUpdate: {
Mem **apArg;
Mem *pX;
- assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
+ assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
);
assert( p->readOnly==0 );
+ if( db->mallocFailed ) goto no_mem;
+ sqlite3VdbeIncrWriteCounter(p, 0);
pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED;
@@ -84057,7 +92900,7 @@ case OP_VUpdate: {
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK && pOp->p1 ){
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
- db->lastRowid = lastRowid = rowid;
+ db->lastRowid = rowid;
}
if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
if( pOp->p5==OE_Ignore ){
@@ -84112,8 +92955,113 @@ case OP_MaxPgcnt: { /* out2 */
}
#endif
+/* Opcode: Function P1 P2 P3 P4 *
+** Synopsis: r[P3]=func(r[P2@NP])
+**
+** Invoke a user function (P4 is a pointer to an sqlite3_context object that
+** contains a pointer to the function to be run) with arguments taken
+** from register P2 and successors. The number of arguments is in
+** the sqlite3_context object that P4 points to.
+** The result of the function is stored
+** in register P3. Register P3 must not be one of the function inputs.
+**
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
+** function was determined to be constant at compile time. If the first
+** argument was constant then bit 0 of P1 is set. This is used to determine
+** whether meta data associated with a user function argument using the
+** sqlite3_set_auxdata() API may be safely retained until the next
+** invocation of this opcode.
+**
+** See also: AggStep, AggFinal, PureFunc
+*/
+/* Opcode: PureFunc P1 P2 P3 P4 *
+** Synopsis: r[P3]=func(r[P2@NP])
+**
+** Invoke a user function (P4 is a pointer to an sqlite3_context object that
+** contains a pointer to the function to be run) with arguments taken
+** from register P2 and successors. The number of arguments is in
+** the sqlite3_context object that P4 points to.
+** The result of the function is stored
+** in register P3. Register P3 must not be one of the function inputs.
+**
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
+** function was determined to be constant at compile time. If the first
+** argument was constant then bit 0 of P1 is set. This is used to determine
+** whether meta data associated with a user function argument using the
+** sqlite3_set_auxdata() API may be safely retained until the next
+** invocation of this opcode.
+**
+** This opcode works exactly like OP_Function. The only difference is in
+** its name. This opcode is used in places where the function must be
+** purely non-deterministic. Some built-in date/time functions can be
+** either determinitic of non-deterministic, depending on their arguments.
+** When those function are used in a non-deterministic way, they will check
+** to see if they were called using OP_PureFunc instead of OP_Function, and
+** if they were, they throw an error.
+**
+** See also: AggStep, AggFinal, Function
+*/
+case OP_PureFunc: /* group */
+case OP_Function: { /* group */
+ int i;
+ sqlite3_context *pCtx;
+
+ assert( pOp->p4type==P4_FUNCCTX );
+ pCtx = pOp->p4.pCtx;
+
+ /* If this function is inside of a trigger, the register array in aMem[]
+ ** might change from one evaluation to the next. The next block of code
+ ** checks to see if the register array has changed, and if so it
+ ** reinitializes the relavant parts of the sqlite3_context object */
+ pOut = &aMem[pOp->p3];
+ if( pCtx->pOut != pOut ){
+ pCtx->pVdbe = p;
+ pCtx->pOut = pOut;
+ for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
+ }
+ assert( pCtx->pVdbe==p );
+
+ memAboutToChange(p, pOut);
+#ifdef SQLITE_DEBUG
+ for(i=0; i<pCtx->argc; i++){
+ assert( memIsValid(pCtx->argv[i]) );
+ REGISTER_TRACE(pOp->p2+i, pCtx->argv[i]);
+ }
+#endif
+ MemSetTypeFlag(pOut, MEM_Null);
+ assert( pCtx->isError==0 );
+ (*pCtx->pFunc->xSFunc)(pCtx, pCtx->argc, pCtx->argv);/* IMP: R-24505-23230 */
+
+ /* If the function returned an error, throw an exception */
+ if( pCtx->isError ){
+ if( pCtx->isError>0 ){
+ sqlite3VdbeError(p, "%s", sqlite3_value_text(pOut));
+ rc = pCtx->isError;
+ }
+ sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
+ pCtx->isError = 0;
+ if( rc ) goto abort_due_to_error;
+ }
+
+ /* Copy the result of the function into register P3 */
+ if( pOut->flags & (MEM_Str|MEM_Blob) ){
+ sqlite3VdbeChangeEncoding(pOut, encoding);
+ if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
+ }
+
+ REGISTER_TRACE(pOp->p3, pOut);
+ UPDATE_MAX_BLOBSIZE(pOut);
+ break;
+}
-/* Opcode: Init P1 P2 * P4 *
+/* Opcode: Trace P1 P2 * P4 *
+**
+** Write P4 on the statement trace output if statement tracing is
+** enabled.
+**
+** Operand P1 must be 0x7fffffff and P2 must positive.
+*/
+/* Opcode: Init P1 P2 P3 P4 *
** Synopsis: Start at P2
**
** Programs contain a single instance of this opcode as the very first
@@ -84127,10 +93075,16 @@ case OP_MaxPgcnt: { /* out2 */
**
** Increment the value of P1 so that OP_Once opcodes will jump the
** first time they are evaluated for this run.
+**
+** If P3 is not zero, then it is an address to jump to if an SQLITE_CORRUPT
+** error is encountered.
*/
+case OP_Trace:
case OP_Init: { /* jump */
- char *zTrace;
int i;
+#ifndef SQLITE_OMIT_TRACE
+ char *zTrace;
+#endif
/* If the P4 argument is not NULL, then it must be an SQL comment string.
** The "--" string is broken up to prevent false-positives with srcck1.c.
@@ -84142,7 +93096,9 @@ case OP_Init: { /* jump */
** sqlite3_expanded_sql(P) otherwise.
*/
assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
- assert( pOp==p->aOp ); /* Always instruction 0 */
+
+ /* OP_Init is always instruction 0 */
+ assert( pOp==p->aOp || pOp->opcode==OP_Trace );
#ifndef SQLITE_OMIT_TRACE
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
@@ -84151,14 +93107,17 @@ case OP_Init: { /* jump */
){
#ifndef SQLITE_OMIT_DEPRECATED
if( db->mTrace & SQLITE_TRACE_LEGACY ){
- void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
char *z = sqlite3VdbeExpandSql(p, zTrace);
- x(db->pTraceArg, z);
+ db->trace.xLegacy(db->pTraceArg, z);
sqlite3_free(z);
}else
#endif
- {
- (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
+ if( db->nVdbeExec>1 ){
+ char *z = sqlite3MPrintf(db, "-- %s", zTrace);
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
+ sqlite3DbFree(db, z);
+ }else{
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
}
}
#ifdef SQLITE_USE_FCNTL_TRACE
@@ -84181,12 +93140,14 @@ case OP_Init: { /* jump */
#endif /* SQLITE_OMIT_TRACE */
assert( pOp->p2>0 );
if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
+ if( pOp->opcode==OP_Trace ) break;
for(i=1; i<p->nOp; i++){
if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
}
pOp->p1 = 0;
}
pOp->p1++;
+ p->aCounter[SQLITE_STMTSTATUS_RUN]++;
goto jump_to_p2;
}
@@ -84213,6 +93174,71 @@ case OP_CursorHint: {
}
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
+#ifdef SQLITE_DEBUG
+/* Opcode: Abortable * * * * *
+**
+** Verify that an Abort can happen. Assert if an Abort at this point
+** might cause database corruption. This opcode only appears in debugging
+** builds.
+**
+** An Abort is safe if either there have been no writes, or if there is
+** an active statement journal.
+*/
+case OP_Abortable: {
+ sqlite3VdbeAssertAbortable(p);
+ break;
+}
+#endif
+
+#ifdef SQLITE_DEBUG
+/* Opcode: ReleaseReg P1 P2 P3 * P5
+** Synopsis: release r[P1@P2] mask P3
+**
+** Release registers from service. Any content that was in the
+** the registers is unreliable after this opcode completes.
+**
+** The registers released will be the P2 registers starting at P1,
+** except if bit ii of P3 set, then do not release register P1+ii.
+** In other words, P3 is a mask of registers to preserve.
+**
+** Releasing a register clears the Mem.pScopyFrom pointer. That means
+** that if the content of the released register was set using OP_SCopy,
+** a change to the value of the source register for the OP_SCopy will no longer
+** generate an assertion fault in sqlite3VdbeMemAboutToChange().
+**
+** If P5 is set, then all released registers have their type set
+** to MEM_Undefined so that any subsequent attempt to read the released
+** register (before it is reinitialized) will generate an assertion fault.
+**
+** P5 ought to be set on every call to this opcode.
+** However, there are places in the code generator will release registers
+** before their are used, under the (valid) assumption that the registers
+** will not be reallocated for some other purpose before they are used and
+** hence are safe to release.
+**
+** This opcode is only available in testing and debugging builds. It is
+** not generated for release builds. The purpose of this opcode is to help
+** validate the generated bytecode. This opcode does not actually contribute
+** to computing an answer.
+*/
+case OP_ReleaseReg: {
+ Mem *pMem;
+ int i;
+ u32 constMask;
+ assert( pOp->p1>0 );
+ assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
+ pMem = &aMem[pOp->p1];
+ constMask = pOp->p3;
+ for(i=0; i<pOp->p2; i++, pMem++){
+ if( i>=32 || (constMask & MASKBIT32(i))==0 ){
+ pMem->pScopyFrom = 0;
+ if( i<32 && pOp->p5 ) MemSetTypeFlag(pMem, MEM_Undefined);
+ }
+ }
+ break;
+}
+#endif
+
/* Opcode: Noop * * * * *
**
** Do nothing. This instruction is often useful as a jump
@@ -84224,8 +93250,9 @@ case OP_CursorHint: {
** This opcode records information from the optimizer. It is the
** the same as a no-op. This opcodesnever appears in a real VM program.
*/
-default: { /* This is really OP_Noop and OP_Explain */
+default: { /* This is really OP_Noop, OP_Explain */
assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
+
break;
}
@@ -84239,7 +93266,7 @@ default: { /* This is really OP_Noop and OP_Explain */
#ifdef VDBE_PROFILE
{
- u64 endTime = sqlite3Hwtime();
+ u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
if( endTime>start ) pOrigOp->cycles += endTime - start;
pOrigOp->cnt++;
}
@@ -84263,6 +93290,12 @@ default: { /* This is really OP_Noop and OP_Explain */
if( opProperty & OPFLG_OUT3 ){
registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
}
+ if( opProperty==0xff ){
+ /* Never happens. This code exists to avoid a harmless linkage
+ ** warning aboud sqlite3VdbeRegisterDump() being defined but not
+ ** used. */
+ sqlite3VdbeRegisterDump(p);
+ }
}
#endif /* SQLITE_DEBUG */
#endif /* NDEBUG */
@@ -84280,7 +93313,7 @@ abort_due_to_error:
p->rc = rc;
sqlite3SystemError(db, rc);
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(rc, "statement aborts at %d: [%s] %s",
+ sqlite3_log(rc, "statement aborts at %d: [%s] %s",
(int)(pOp - aOp), p->zSql, p->zErrMsg);
sqlite3VdbeHalt(p);
if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
@@ -84293,12 +93326,20 @@ abort_due_to_error:
** release the mutexes on btrees that were acquired at the
** top. */
vdbe_return:
- db->lastRowid = lastRowid;
- testcase( nVmStep>0 );
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
+ nProgressLimit += db->nProgressOps;
+ if( db->xProgress(db->pProgressArg) ){
+ nProgressLimit = LARGEST_UINT64;
+ rc = SQLITE_INTERRUPT;
+ goto abort_due_to_error;
+ }
+ }
+#endif
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
sqlite3VdbeLeave(p);
- assert( rc!=SQLITE_OK || nExtraDelete==0
- || sqlite3_strlike("DELETE%",p->zSql,0)!=0
+ assert( rc!=SQLITE_OK || nExtraDelete==0
+ || sqlite3_strlike("DELETE%",p->zSql,0)!=0
);
return rc;
@@ -84322,10 +93363,8 @@ no_mem:
** flag.
*/
abort_due_to_interrupt:
- assert( db->u1.isInterrupted );
- rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
- p->rc = rc;
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
+ assert( AtomicLoad(&db->u1.isInterrupted) );
+ rc = SQLITE_INTERRUPT;
goto abort_due_to_error;
}
@@ -84357,10 +93396,9 @@ abort_due_to_interrupt:
*/
typedef struct Incrblob Incrblob;
struct Incrblob {
- int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
int nByte; /* Size of open blob, in bytes */
int iOffset; /* Byte offset of blob in cursor data */
- int iCol; /* Table column this handle is open on */
+ u16 iCol; /* Table column this handle is open on */
BtCursor *pCsr; /* Cursor pointing at blob row */
sqlite3_stmt *pStmt; /* Statement holding cursor open */
sqlite3 *db; /* The associated database */
@@ -84383,7 +93421,7 @@ struct Incrblob {
** sqlite3DbFree().
**
** If an error does occur, then the b-tree cursor is closed. All subsequent
-** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will
+** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will
** immediately return SQLITE_ABORT.
*/
static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
@@ -84391,17 +93429,28 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
char *zErr = 0; /* Error message */
Vdbe *v = (Vdbe *)p->pStmt;
- /* Set the value of the SQL statements only variable to integer iRow.
- ** This is done directly instead of using sqlite3_bind_int64() to avoid
- ** triggering asserts related to mutexes.
+ /* Set the value of register r[1] in the SQL statement to integer iRow.
+ ** This is done directly as a performance optimization
*/
- assert( v->aVar[0].flags&MEM_Int );
- v->aVar[0].u.i = iRow;
+ v->aMem[1].flags = MEM_Int;
+ v->aMem[1].u.i = iRow;
- rc = sqlite3_step(p->pStmt);
+ /* If the statement has been run before (and is paused at the OP_ResultRow)
+ ** then back it up to the point where it does the OP_NotExists. This could
+ ** have been down with an extra OP_Goto, but simply setting the program
+ ** counter is faster. */
+ if( v->pc>4 ){
+ v->pc = 4;
+ assert( v->aOp[v->pc].opcode==OP_NotExists );
+ rc = sqlite3VdbeExec(v);
+ }else{
+ rc = sqlite3_step(p->pStmt);
+ }
if( rc==SQLITE_ROW ){
VdbeCursor *pC = v->apCsr[0];
- u32 type = pC->aType[p->iCol];
+ u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0;
+ testcase( pC->nHdrParsed==p->iCol );
+ testcase( pC->nHdrParsed==p->iCol+1 );
if( type<12 ){
zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
type==0?"null": type==7?"real": "integer"
@@ -84446,7 +93495,7 @@ SQLITE_API int sqlite3_blob_open(
const char *zTable, /* The table containing the blob */
const char *zColumn, /* The column containing the blob */
sqlite_int64 iRow, /* The row containing the glob */
- int flags, /* True -> read/write access, false -> read-only */
+ int wrFlag, /* True -> read/write access, false -> read-only */
sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
){
int nAttempt = 0;
@@ -84454,8 +93503,8 @@ SQLITE_API int sqlite3_blob_open(
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
- Parse *pParse = 0;
Incrblob *pBlob = 0;
+ Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppBlob==0 ){
@@ -84468,42 +93517,39 @@ SQLITE_API int sqlite3_blob_open(
return SQLITE_MISUSE_BKPT;
}
#endif
- flags = !!flags; /* flags = (flags ? 1 : 0); */
+ wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */
sqlite3_mutex_enter(db->mutex);
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
- if( !pBlob ) goto blob_open_out;
- pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
- if( !pParse ) goto blob_open_out;
-
do {
- memset(pParse, 0, sizeof(Parse));
- pParse->db = db;
+ memset(&sParse, 0, sizeof(Parse));
+ if( !pBlob ) goto blob_open_out;
+ sParse.db = db;
sqlite3DbFree(db, zErr);
zErr = 0;
sqlite3BtreeEnterAll(db);
- pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
+ pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb);
if( pTab && IsVirtual(pTab) ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open virtual table: %s", zTable);
}
if( pTab && !HasRowid(pTab) ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && pTab->pSelect ){
pTab = 0;
- sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
+ sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
if( !pTab ){
- if( pParse->zErrMsg ){
+ if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
- zErr = pParse->zErrMsg;
- pParse->zErrMsg = 0;
+ zErr = sParse.zErrMsg;
+ sParse.zErrMsg = 0;
}
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
@@ -84527,17 +93573,16 @@ SQLITE_API int sqlite3_blob_open(
}
/* If the value is being opened for writing, check that the
- ** column is not indexed, and that it is not part of a foreign key.
- ** It is against the rules to open a column to which either of these
- ** descriptions applies for writing. */
- if( flags ){
+ ** column is not indexed, and that it is not part of a foreign key.
+ */
+ if( wrFlag ){
const char *zFault = 0;
Index *pIdx;
#ifndef SQLITE_OMIT_FOREIGN_KEY
if( db->flags&SQLITE_ForeignKeys ){
/* Check that the column is not part of an FK child key definition. It
** is not necessary to check if it is part of a parent key, as parent
- ** key columns must be indexed. The check below will pick up this
+ ** key columns must be indexed. The check below will pick up this
** case. */
FKey *pFKey;
for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
@@ -84568,11 +93613,11 @@ SQLITE_API int sqlite3_blob_open(
}
}
- pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
+ pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
-
- /* This VDBE program seeks a btree cursor to the identified
+
+ /* This VDBE program seeks a btree cursor to the identified
** db/table/row entry. The reason for using a vdbe program instead
** of writing code to use the b-tree layer directly is that the
** vdbe program will take advantage of the various transaction,
@@ -84580,37 +93625,36 @@ SQLITE_API int sqlite3_blob_open(
**
** After seeking the cursor, the vdbe executes an OP_ResultRow.
** Code external to the Vdbe then "borrows" the b-tree cursor and
- ** uses it to implement the blob_read(), blob_write() and
+ ** uses it to implement the blob_read(), blob_write() and
** blob_bytes() functions.
**
** The sqlite3_blob_close() function finalizes the vdbe program,
- ** which closes the b-tree cursor and (possibly) commits the
+ ** which closes the b-tree cursor and (possibly) commits the
** transaction.
*/
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList openBlob[] = {
{OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */
{OP_OpenRead, 0, 0, 0}, /* 1: Open a cursor */
- {OP_Variable, 1, 1, 0}, /* 2: Move ?1 into reg[1] */
- {OP_NotExists, 0, 7, 1}, /* 3: Seek the cursor */
- {OP_Column, 0, 0, 1}, /* 4 */
- {OP_ResultRow, 1, 0, 0}, /* 5 */
- {OP_Goto, 0, 2, 0}, /* 6 */
- {OP_Close, 0, 0, 0}, /* 7 */
- {OP_Halt, 0, 0, 0}, /* 8 */
+ /* blobSeekToRow() will initialize r[1] to the desired rowid */
+ {OP_NotExists, 0, 5, 1}, /* 2: Seek the cursor to rowid=r[1] */
+ {OP_Column, 0, 0, 1}, /* 3 */
+ {OP_ResultRow, 1, 0, 0}, /* 4 */
+ {OP_Halt, 0, 0, 0}, /* 5 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
VdbeOp *aOp;
- sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
+ sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
- sqlite3VdbeChangeP5(v, 1);
+ sqlite3VdbeChangeP5(v, 1);
+ assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
/* Make sure a mutex is held on the table to be accessed */
- sqlite3VdbeUsesBtree(v, iDb);
+ sqlite3VdbeUsesBtree(v, iDb);
if( db->mallocFailed==0 ){
assert( aOp!=0 );
@@ -84620,44 +93664,42 @@ SQLITE_API int sqlite3_blob_open(
#else
aOp[0].p1 = iDb;
aOp[0].p2 = pTab->tnum;
- aOp[0].p3 = flags;
- sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
+ aOp[0].p3 = wrFlag;
+ sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
}
if( db->mallocFailed==0 ){
#endif
- /* Remove either the OP_OpenWrite or OpenRead. Set the P2
+ /* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */
- if( flags ) aOp[1].opcode = OP_OpenWrite;
+ if( wrFlag ) aOp[1].opcode = OP_OpenWrite;
aOp[1].p2 = pTab->tnum;
- aOp[1].p3 = iDb;
+ aOp[1].p3 = iDb;
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
- ** we can invoke OP_Column to fill in the vdbe cursors type
+ ** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
aOp[1].p4type = P4_INT32;
aOp[1].p4.i = pTab->nCol+1;
- aOp[4].p2 = pTab->nCol;
+ aOp[3].p2 = pTab->nCol;
- pParse->nVar = 1;
- pParse->nMem = 1;
- pParse->nTab = 1;
- sqlite3VdbeMakeReady(v, pParse);
+ sParse.nVar = 0;
+ sParse.nMem = 1;
+ sParse.nTab = 1;
+ sqlite3VdbeMakeReady(v, &sParse);
}
}
-
- pBlob->flags = flags;
+
pBlob->iCol = iCol;
pBlob->db = db;
sqlite3BtreeLeaveAll(db);
if( db->mallocFailed ){
goto blob_open_out;
}
- sqlite3_bind_int64(pBlob->pStmt, 1, iRow);
rc = blobSeekToRow(pBlob, iRow, &zErr);
} while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
@@ -84670,8 +93712,7 @@ blob_open_out:
}
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -84687,11 +93728,12 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
sqlite3 *db;
if( p ){
+ sqlite3_stmt *pStmt = p->pStmt;
db = p->db;
sqlite3_mutex_enter(db->mutex);
- rc = sqlite3_finalize(p->pStmt);
sqlite3DbFree(db, p);
sqlite3_mutex_leave(db->mutex);
+ rc = sqlite3_finalize(pStmt);
}else{
rc = SQLITE_OK;
}
@@ -84702,10 +93744,10 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
** Perform a read or write operation on a blob
*/
static int blobReadWrite(
- sqlite3_blob *pBlob,
- void *z,
- int n,
- int iOffset,
+ sqlite3_blob *pBlob,
+ void *z,
+ int n,
+ int iOffset,
int (*xCall)(BtCursor*, u32, u32, void*)
){
int rc;
@@ -84735,14 +93777,14 @@ static int blobReadWrite(
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){
- /* If a pre-update hook is registered and this is a write cursor,
- ** invoke it here.
- **
+ /* If a pre-update hook is registered and this is a write cursor,
+ ** invoke it here.
+ **
** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
** operation should really be an SQLITE_UPDATE. This is probably
- ** incorrect, but is convenient because at this point the new.* values
- ** are not easily obtainable. And for the sessions module, an
- ** SQLITE_UPDATE where the PK columns do not change is handled in the
+ ** incorrect, but is convenient because at this point the new.* values
+ ** are not easily obtainable. And for the sessions module, an
+ ** SQLITE_UPDATE where the PK columns do not change is handled in the
** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
** slightly more efficient). Since you cannot write to a PK column
** using the incremental-blob API, this works. For the sessions module
@@ -84775,7 +93817,7 @@ static int blobReadWrite(
** Read data from a blob handle.
*/
SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
- return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
+ return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked);
}
/*
@@ -84802,8 +93844,8 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
**
** If an error occurs, or if the specified row does not exist or does not
** contain a blob or text value, then an error code is returned and the
-** database handle error code and message set. If this happens, then all
-** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
+** database handle error code and message set. If this happens, then all
+** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
** immediately return SQLITE_ABORT.
*/
SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
@@ -84897,7 +93939,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** is like Close() followed by Init() only
** much faster.
**
-** The interfaces above must be called in a particular order. Write() can
+** The interfaces above must be called in a particular order. Write() can
** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and
** Compare() can only occur in between Rewind() and Close()/Reset(). i.e.
**
@@ -84905,16 +93947,16 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** for each record: Write()
** Rewind()
** Rowkey()/Compare()
-** Next()
+** Next()
** Close()
**
** Algorithm:
**
-** Records passed to the sorter via calls to Write() are initially held
+** Records passed to the sorter via calls to Write() are initially held
** unsorted in main memory. Assuming the amount of memory used never exceeds
** a threshold, when Rewind() is called the set of records is sorted using
** an in-memory merge sort. In this case, no temporary files are required
-** and subsequent calls to Rowkey(), Next() and Compare() read records
+** and subsequent calls to Rowkey(), Next() and Compare() read records
** directly from main memory.
**
** If the amount of space used to store records in main memory exceeds the
@@ -84924,10 +93966,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** of PMAs may be created by merging existing PMAs together - for example
** merging two or more level-0 PMAs together creates a level-1 PMA.
**
-** The threshold for the amount of main memory to use before flushing
+** The threshold for the amount of main memory to use before flushing
** records to a PMA is roughly the same as the limit configured for the
-** page-cache of the main database. Specifically, the threshold is set to
-** the value returned by "PRAGMA main.page_size" multipled by
+** page-cache of the main database. Specifically, the threshold is set to
+** the value returned by "PRAGMA main.page_size" multipled by
** that returned by "PRAGMA main.cache_size", in bytes.
**
** If the sorter is running in single-threaded mode, then all PMAs generated
@@ -84944,7 +93986,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** than zero, and (b) worker threads have been enabled at runtime by calling
** "PRAGMA threads=N" with some value of N greater than 0.
**
-** When Rewind() is called, any data remaining in memory is flushed to a
+** When Rewind() is called, any data remaining in memory is flushed to a
** final PMA. So at this point the data is stored in some number of sorted
** PMAs within temporary files on disk.
**
@@ -84956,16 +93998,16 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
**
** Or, if running in multi-threaded mode, then a background thread is
** launched to merge the existing PMAs. Once the background thread has
-** merged T bytes of data into a single sorted PMA, the main thread
+** merged T bytes of data into a single sorted PMA, the main thread
** begins reading keys from that PMA while the background thread proceeds
** with merging the next T bytes of data. And so on.
**
-** Parameter T is set to half the value of the memory threshold used
+** Parameter T is set to half the value of the memory threshold used
** by Write() above to determine when to create a new PMA.
**
-** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when
-** Rewind() is called, then a hierarchy of incremental-merges is used.
-** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on
+** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when
+** Rewind() is called, then a hierarchy of incremental-merges is used.
+** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on
** disk are merged together. Then T bytes of data from the second set, and
** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT
** PMAs at a time. This done is to improve locality.
@@ -84980,7 +94022,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
/* #include "sqliteInt.h" */
/* #include "vdbeInt.h" */
-/*
+/*
** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various
** messages to stderr that may be helpful in understanding the performance
** characteristics of the sorter in multi-threaded mode.
@@ -85009,7 +94051,7 @@ typedef struct SorterList SorterList; /* In-memory list of records */
typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */
/*
-** A container for a temp file handle and the current amount of data
+** A container for a temp file handle and the current amount of data
** stored in the file.
*/
struct SorterFile {
@@ -85049,17 +94091,17 @@ struct SorterList {
** the MergeEngine.nTree variable.
**
** The final (N/2) elements of aTree[] contain the results of comparing
-** pairs of PMA keys together. Element i contains the result of
+** pairs of PMA keys together. Element i contains the result of
** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the
-** aTree element is set to the index of it.
+** aTree element is set to the index of it.
**
** For the purposes of this comparison, EOF is considered greater than any
** other key value. If the keys are equal (only possible with two EOF
** values), it doesn't matter which index is stored.
**
-** The (N/4) elements of aTree[] that precede the final (N/2) described
+** The (N/4) elements of aTree[] that precede the final (N/2) described
** above contains the index of the smallest of each block of 4 PmaReaders
-** And so on. So that aTree[1] contains the index of the PmaReader that
+** And so on. So that aTree[1] contains the index of the PmaReader that
** currently points to the smallest key value. aTree[0] is unused.
**
** Example:
@@ -85075,7 +94117,7 @@ struct SorterList {
**
** aTree[] = { X, 5 0, 5 0, 3, 5, 6 }
**
-** The current element is "Apple" (the value of the key indicated by
+** The current element is "Apple" (the value of the key indicated by
** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will
** be advanced to the next key in its segment. Say the next key is
** "Eggplant":
@@ -85116,8 +94158,8 @@ struct MergeEngine {
** each thread requries its own UnpackedRecord object to unpack records in
** as part of comparison operations.
**
-** Before a background thread is launched, variable bDone is set to 0. Then,
-** right before it exits, the thread itself sets bDone to 1. This is used for
+** Before a background thread is launched, variable bDone is set to 0. Then,
+** right before it exits, the thread itself sets bDone to 1. This is used for
** two purposes:
**
** 1. When flushing the contents of memory to a level-0 PMA on disk, to
@@ -85148,7 +94190,7 @@ struct SortSubtask {
/*
-** Main sorter structure. A single instance of this is allocated for each
+** Main sorter structure. A single instance of this is allocated for each
** sorter cursor created by the VDBE.
**
** mxKeysize:
@@ -85204,21 +94246,21 @@ struct PmaReader {
};
/*
-** Normally, a PmaReader object iterates through an existing PMA stored
+** Normally, a PmaReader object iterates through an existing PMA stored
** within a temp file. However, if the PmaReader.pIncr variable points to
** an object of the following type, it may be used to iterate/merge through
** multiple PMAs simultaneously.
**
-** There are two types of IncrMerger object - single (bUseThread==0) and
-** multi-threaded (bUseThread==1).
+** There are two types of IncrMerger object - single (bUseThread==0) and
+** multi-threaded (bUseThread==1).
**
-** A multi-threaded IncrMerger object uses two temporary files - aFile[0]
-** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in
-** size. When the IncrMerger is initialized, it reads enough data from
-** pMerger to populate aFile[0]. It then sets variables within the
-** corresponding PmaReader object to read from that file and kicks off
-** a background thread to populate aFile[1] with the next mxSz bytes of
-** sorted record data from pMerger.
+** A multi-threaded IncrMerger object uses two temporary files - aFile[0]
+** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in
+** size. When the IncrMerger is initialized, it reads enough data from
+** pMerger to populate aFile[0]. It then sets variables within the
+** corresponding PmaReader object to read from that file and kicks off
+** a background thread to populate aFile[1] with the next mxSz bytes of
+** sorted record data from pMerger.
**
** When the PmaReader reaches the end of aFile[0], it blocks until the
** background thread has finished populating aFile[1]. It then exchanges
@@ -85229,7 +94271,7 @@ struct PmaReader {
**
** A single-threaded IncrMerger does not open any temporary files of its
** own. Instead, it has exclusive access to mxSz bytes of space beginning
-** at offset iStartOff of file pTask->file2. And instead of using a
+** at offset iStartOff of file pTask->file2. And instead of using a
** background thread to prepare data for the PmaReader, with a single
** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with
** keys from pMerger by the calling thread whenever the PmaReader runs out
@@ -85341,7 +94383,7 @@ static int vdbePmaReadBlob(
assert( p->aBuffer );
- /* If there is no more data to be read from the buffer, read the next
+ /* If there is no more data to be read from the buffer, read the next
** p->nBuffer bytes of data from the file into it. Or, if there are less
** than p->nBuffer bytes remaining in the PMA, read all remaining data. */
iBuf = p->iReadOff % p->nBuffer;
@@ -85362,11 +94404,11 @@ static int vdbePmaReadBlob(
assert( rc!=SQLITE_IOERR_SHORT_READ );
if( rc!=SQLITE_OK ) return rc;
}
- nAvail = p->nBuffer - iBuf;
+ nAvail = p->nBuffer - iBuf;
if( nByte<=nAvail ){
/* The requested data is available in the in-memory buffer. In this
- ** case there is no need to make a copy of the data, just return a
+ ** case there is no need to make a copy of the data, just return a
** pointer into the buffer to the caller. */
*ppOut = &p->aBuffer[iBuf];
p->iReadOff += nByte;
@@ -85379,7 +94421,7 @@ static int vdbePmaReadBlob(
/* Extend the p->aAlloc[] allocation if required. */
if( p->nAlloc<nByte ){
u8 *aNew;
- int nNew = MAX(128, p->nAlloc*2);
+ sqlite3_int64 nNew = MAX(128, 2*(sqlite3_int64)p->nAlloc);
while( nByte>nNew ) nNew = nNew*2;
aNew = sqlite3Realloc(p->aAlloc, nNew);
if( !aNew ) return SQLITE_NOMEM_BKPT;
@@ -85445,7 +94487,7 @@ static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){
/*
** Attempt to memory map file pFile. If successful, set *pp to point to the
-** new mapping and return SQLITE_OK. If the mapping is not attempted
+** new mapping and return SQLITE_OK. If the mapping is not attempted
** (because the file is too large or the VFS layer is configured not to use
** mmap), return SQLITE_OK and set *pp to NULL.
**
@@ -85466,7 +94508,7 @@ static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){
/*
** Attach PmaReader pReadr to file pFile (if it is not already attached to
-** that file) and seek it to offset iOff within the file. Return SQLITE_OK
+** that file) and seek it to offset iOff within the file. Return SQLITE_OK
** if successful, or an SQLite error code if an error occurs.
*/
static int vdbePmaReaderSeek(
@@ -85556,11 +94598,11 @@ static int vdbePmaReaderNext(PmaReader *pReadr){
/*
** Initialize PmaReader pReadr to scan through the PMA stored in file pFile
-** starting at offset iStart and ending at offset iEof-1. This function
-** leaves the PmaReader pointing to the first key in the PMA (or EOF if the
+** starting at offset iStart and ending at offset iEof-1. This function
+** leaves the PmaReader pointing to the first key in the PMA (or EOF if the
** PMA is empty).
**
-** If the pnByte parameter is NULL, then it is assumed that the file
+** If the pnByte parameter is NULL, then it is assumed that the file
** contains a single PMA, and that that PMA omits the initial length varint.
*/
static int vdbePmaReaderInit(
@@ -85593,7 +94635,7 @@ static int vdbePmaReaderInit(
/*
** A version of vdbeSorterCompare() that assumes that it has already been
-** determined that the first field of key1 is equal to the first field of
+** determined that the first field of key1 is equal to the first field of
** key2.
*/
static int vdbeSorterCompareTail(
@@ -85611,7 +94653,7 @@ static int vdbeSorterCompareTail(
}
/*
-** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
+** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences
** used by the comparison. Return the result of the comparison.
**
@@ -85657,21 +94699,22 @@ static int vdbeSorterCompareText(
int n2;
int res;
- getVarint32(&p1[1], n1); n1 = (n1 - 13) / 2;
- getVarint32(&p2[1], n2); n2 = (n2 - 13) / 2;
- res = memcmp(v1, v2, MIN(n1, n2));
+ getVarint32NR(&p1[1], n1);
+ getVarint32NR(&p2[1], n2);
+ res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
if( res==0 ){
res = n1 - n2;
}
if( res==0 ){
- if( pTask->pSorter->pKeyInfo->nField>1 ){
+ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
}
}else{
- if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
+ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
+ if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
res = res * -1;
}
}
@@ -85700,47 +94743,47 @@ static int vdbeSorterCompareInt(
assert( (s1>0 && s1<7) || s1==8 || s1==9 );
assert( (s2>0 && s2<7) || s2==8 || s2==9 );
- if( s1>7 && s2>7 ){
- res = s1 - s2;
- }else{
- if( s1==s2 ){
- if( (*v1 ^ *v2) & 0x80 ){
- /* The two values have different signs */
- res = (*v1 & 0x80) ? -1 : +1;
- }else{
- /* The two values have the same sign. Compare using memcmp(). */
- static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8 };
- int i;
- res = 0;
- for(i=0; i<aLen[s1]; i++){
- if( (res = v1[i] - v2[i]) ) break;
+ if( s1==s2 ){
+ /* The two values have the same sign. Compare using memcmp(). */
+ static const u8 aLen[] = {0, 1, 2, 3, 4, 6, 8, 0, 0, 0 };
+ const u8 n = aLen[s1];
+ int i;
+ res = 0;
+ for(i=0; i<n; i++){
+ if( (res = v1[i] - v2[i])!=0 ){
+ if( ((v1[0] ^ v2[0]) & 0x80)!=0 ){
+ res = v1[0] & 0x80 ? -1 : +1;
}
+ break;
}
+ }
+ }else if( s1>7 && s2>7 ){
+ res = s1 - s2;
+ }else{
+ if( s2>7 ){
+ res = +1;
+ }else if( s1>7 ){
+ res = -1;
}else{
- if( s2>7 ){
- res = +1;
- }else if( s1>7 ){
- res = -1;
- }else{
- res = s1 - s2;
- }
- assert( res!=0 );
+ res = s1 - s2;
+ }
+ assert( res!=0 );
- if( res>0 ){
- if( *v1 & 0x80 ) res = -1;
- }else{
- if( *v2 & 0x80 ) res = +1;
- }
+ if( res>0 ){
+ if( *v1 & 0x80 ) res = -1;
+ }else{
+ if( *v2 & 0x80 ) res = +1;
}
}
if( res==0 ){
- if( pTask->pSorter->pKeyInfo->nField>1 ){
+ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){
res = vdbeSorterCompareTail(
pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2
);
}
- }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){
+ }else if( pTask->pSorter->pKeyInfo->aSortFlags[0] ){
+ assert( !(pTask->pSorter->pKeyInfo->aSortFlags[0]&KEYINFO_ORDER_BIGNULL) );
res = res * -1;
}
@@ -85750,13 +94793,13 @@ static int vdbeSorterCompareInt(
/*
** Initialize the temporary index cursor just opened as a sorter cursor.
**
-** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nField)
+** Usually, the sorter module uses the value of (pCsr->pKeyInfo->nKeyField)
** to determine the number of fields that should be compared from the
** records being sorted. However, if the value passed as argument nField
** is non-zero and the sorter is able to guarantee a stable sort, nField
** is used instead. This is used when sorting records for a CREATE INDEX
** statement. In this case, keys are always delivered to the sorter in
-** order of the primary key, which happens to be make up the final part
+** order of the primary key, which happens to be make up the final part
** of the records being sorted. So if the sort is stable, there is never
** any reason to compare PK fields and they can be ignored for a small
** performance boost.
@@ -85801,9 +94844,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
#endif
- assert( pCsr->pKeyInfo && pCsr->pBt==0 );
+ assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
assert( pCsr->eCurType==CURTYPE_SORTER );
- szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
+ szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
@@ -85815,8 +94858,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
pKeyInfo->db = 0;
if( nField && nWorker==0 ){
- pKeyInfo->nXField += (pKeyInfo->nField - nField);
- pKeyInfo->nField = nField;
+ pKeyInfo->nKeyField = nField;
}
pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
pSorter->nTask = nWorker + 1;
@@ -85844,11 +94886,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
- /* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
- ** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
- ** large heap allocations.
- */
- if( sqlite3GlobalConfig.pScratch==0 ){
+ /* Avoid large memory allocations if the application has requested
+ ** SQLITE_CONFIG_SMALL_MALLOC. */
+ if( sqlite3GlobalConfig.bSmallMalloc==0 ){
assert( pSorter->iMemory==0 );
pSorter->nMemory = pgsz;
pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
@@ -85856,8 +94896,9 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
}
- if( (pKeyInfo->nField+pKeyInfo->nXField)<13
+ if( pKeyInfo->nAllField<13
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
+ && (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0
){
pSorter->typeMask = SORTER_TYPE_INTEGER | SORTER_TYPE_TEXT;
}
@@ -85880,7 +94921,7 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
}
/*
-** Free all resources owned by the object indicated by argument pTask. All
+** Free all resources owned by the object indicated by argument pTask. All
** fields of *pTask are zeroed before returning.
*/
static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){
@@ -85979,7 +95020,7 @@ static int vdbeSorterCreateThread(
}
/*
-** Join all outstanding threads launched by SorterWrite() to create
+** Join all outstanding threads launched by SorterWrite() to create
** level-0 PMAs.
*/
static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){
@@ -85988,10 +95029,10 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){
/* This function is always called by the main user thread.
**
- ** If this function is being called after SorterRewind() has been called,
+ ** If this function is being called after SorterRewind() has been called,
** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread
** is currently attempt to join one of the other threads. To avoid a race
- ** condition where this thread also attempts to join the same object, join
+ ** condition where this thread also attempts to join the same object, join
** thread pSorter->aTask[pSorter->nTask-1].pThread first. */
for(i=pSorter->nTask-1; i>=0; i--){
SortSubtask *pTask = &pSorter->aTask[i];
@@ -86163,19 +95204,15 @@ static int vdbeSorterOpenTempFile(
}
/*
-** If it has not already been allocated, allocate the UnpackedRecord
-** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or
+** If it has not already been allocated, allocate the UnpackedRecord
+** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or
** if no allocation was required), or SQLITE_NOMEM otherwise.
*/
static int vdbeSortAllocUnpacked(SortSubtask *pTask){
if( pTask->pUnpacked==0 ){
- char *pFree;
- pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(
- pTask->pSorter->pKeyInfo, 0, 0, &pFree
- );
- assert( pTask->pUnpacked==(UnpackedRecord*)pFree );
- if( pFree==0 ) return SQLITE_NOMEM_BKPT;
- pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
+ pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
+ if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
+ pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nKeyField;
pTask->pUnpacked->errCode = 0;
}
return SQLITE_OK;
@@ -86231,32 +95268,28 @@ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){
if( p->typeMask==SORTER_TYPE_INTEGER ){
return vdbeSorterCompareInt;
}else if( p->typeMask==SORTER_TYPE_TEXT ){
- return vdbeSorterCompareText;
+ return vdbeSorterCompareText;
}
return vdbeSorterCompare;
}
/*
-** Sort the linked list of records headed at pTask->pList. Return
-** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
+** Sort the linked list of records headed at pTask->pList. Return
+** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
** an error occurs.
*/
static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
int i;
- SorterRecord **aSlot;
SorterRecord *p;
int rc;
+ SorterRecord *aSlot[64];
rc = vdbeSortAllocUnpacked(pTask);
if( rc!=SQLITE_OK ) return rc;
p = pList->pList;
pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter);
-
- aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
- if( !aSlot ){
- return SQLITE_NOMEM_BKPT;
- }
+ memset(aSlot, 0, sizeof(aSlot));
while( p ){
SorterRecord *pNext;
@@ -86281,15 +95314,14 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
}
p = 0;
- for(i=0; i<64; i++){
+ for(i=0; i<ArraySize(aSlot); i++){
if( aSlot[i]==0 ) continue;
p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i];
}
pList->pList = p;
- sqlite3_free(aSlot);
- assert( pTask->pUnpacked->errCode==SQLITE_OK
- || pTask->pUnpacked->errCode==SQLITE_NOMEM
+ assert( pTask->pUnpacked->errCode==SQLITE_OK
+ || pTask->pUnpacked->errCode==SQLITE_NOMEM
);
return pTask->pUnpacked->errCode;
}
@@ -86330,8 +95362,8 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy);
p->iBufEnd += nCopy;
if( p->iBufEnd==p->nBuffer ){
- p->eFWErr = sqlite3OsWrite(p->pFd,
- &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
+ p->eFWErr = sqlite3OsWrite(p->pFd,
+ &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
p->iWriteOff + p->iBufStart
);
p->iBufStart = p->iBufEnd = 0;
@@ -86346,7 +95378,7 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
/*
** Flush any buffered data to disk and clean up the PMA-writer object.
** The results of using the PMA-writer after this call are undefined.
-** Return SQLITE_OK if flushing the buffered data succeeds or is not
+** Return SQLITE_OK if flushing the buffered data succeeds or is not
** required. Otherwise, return an SQLite error code.
**
** Before returning, set *piEof to the offset immediately following the
@@ -86355,8 +95387,8 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){
int rc;
if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){
- p->eFWErr = sqlite3OsWrite(p->pFd,
- &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
+ p->eFWErr = sqlite3OsWrite(p->pFd,
+ &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
p->iWriteOff + p->iBufStart
);
}
@@ -86368,11 +95400,11 @@ static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){
}
/*
-** Write value iVal encoded as a varint to the PMA. Return
+** Write value iVal encoded as a varint to the PMA. Return
** SQLITE_OK if successful, or an SQLite error code if an error occurs.
*/
static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
- int nByte;
+ int nByte;
u8 aByte[10];
nByte = sqlite3PutVarint(aByte, iVal);
vdbePmaWriteBlob(p, aByte, nByte);
@@ -86380,7 +95412,7 @@ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
/*
** Write the current contents of in-memory linked-list pList to a level-0
-** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if
+** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if
** successful, or an SQLite error code otherwise.
**
** The format of a PMA is:
@@ -86388,8 +95420,8 @@ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
** * A varint. This varint contains the total number of bytes of content
** in the PMA (not including the varint itself).
**
-** * One or more records packed end-to-end in order of ascending keys.
-** Each record consists of a varint followed by a blob of data (the
+** * One or more records packed end-to-end in order of ascending keys.
+** Each record consists of a varint followed by a blob of data (the
** key). The varint is the number of bytes in the blob of data.
*/
static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){
@@ -86398,7 +95430,7 @@ static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){
PmaWriter writer; /* Object used to write to the file */
#ifdef SQLITE_DEBUG
- /* Set iSz to the expected size of file pTask->file after writing the PMA.
+ /* Set iSz to the expected size of file pTask->file after writing the PMA.
** This is used by an assert() statement at the end of this function. */
i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof;
#endif
@@ -86551,7 +95583,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
SortSubtask *pTask = 0; /* Thread context used to create new PMA */
int nWorker = (pSorter->nTask-1);
- /* Set the flag to indicate that at least one PMA has been written.
+ /* Set the flag to indicate that at least one PMA has been written.
** Or will be, anyhow. */
pSorter->bUsePMA = 1;
@@ -86561,7 +95593,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
** the background thread from a sub-tasks previous turn is still running,
** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
** fall back to using the final sub-task. The first (pSorter->nTask-1)
- ** sub-tasks are prefered as they use background threads - the final
+ ** sub-tasks are prefered as they use background threads - the final
** sub-task uses the main thread. */
for(i=0; i<nWorker; i++){
int iTest = (pSorter->iPrev + i + 1) % nWorker;
@@ -86578,13 +95610,16 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker], &pSorter->list);
}else{
/* Launch a background thread for this operation */
- u8 *aMem = pTask->list.aMemory;
- void *pCtx = (void*)pTask;
+ u8 *aMem;
+ void *pCtx;
+ assert( pTask!=0 );
assert( pTask->pThread==0 && pTask->bDone==0 );
assert( pTask->list.pList==0 );
assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 );
+ aMem = pTask->list.aMemory;
+ pCtx = (void*)pTask;
pSorter->iPrev = (u8)(pTask - pSorter->aTask);
pTask->list = pSorter->list;
pSorter->list.pList = 0;
@@ -86622,7 +95657,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
assert( pCsr->eCurType==CURTYPE_SORTER );
pSorter = pCsr->uc.pSorter;
- getVarint32((const u8*)&pVal->z[1], t);
+ getVarint32NR((const u8*)&pVal->z[1], t);
if( t>0 && t<10 && t!=7 ){
pSorter->typeMask &= SORTER_TYPE_INTEGER;
}else if( t>10 && (t & 0x01) ){
@@ -86639,14 +95674,14 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
** If using the single large allocation mode (pSorter->aMemory!=0), then
** flush the contents of memory to a new PMA if (a) at least one value is
** already in memory and (b) the new value will not fit in memory.
- **
+ **
** Or, if using separate allocations for each record, flush the contents
** of memory to a PMA if either of the following are true:
**
- ** * The total memory allocated for the in-memory list is greater
+ ** * The total memory allocated for the in-memory list is greater
** than (page-size * cache-size), or
**
- ** * The total memory allocated for the in-memory list is greater
+ ** * The total memory allocated for the in-memory list is greater
** than (page-size * 10) and sqlite3HeapNearlyFull() returns true.
*/
nReq = pVal->n + sizeof(SorterRecord);
@@ -86678,15 +95713,19 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
if( nMin>pSorter->nMemory ){
u8 *aNew;
- int iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory;
- int nNew = pSorter->nMemory * 2;
+ sqlite3_int64 nNew = 2 * (sqlite3_int64)pSorter->nMemory;
+ int iListOff = -1;
+ if( pSorter->list.pList ){
+ iListOff = (u8*)pSorter->list.pList - pSorter->list.aMemory;
+ }
while( nNew < nMin ) nNew = nNew*2;
if( nNew > pSorter->mxPmaSize ) nNew = pSorter->mxPmaSize;
if( nNew < nMin ) nNew = nMin;
-
aNew = sqlite3Realloc(pSorter->list.aMemory, nNew);
if( !aNew ) return SQLITE_NOMEM_BKPT;
- pSorter->list.pList = (SorterRecord*)&aNew[iListOff];
+ if( iListOff>=0 ){
+ pSorter->list.pList = (SorterRecord*)&aNew[iListOff];
+ }
pSorter->list.aMemory = aNew;
pSorter->nMemory = nNew;
}
@@ -86781,11 +95820,11 @@ static int vdbeIncrBgPopulate(IncrMerger *pIncr){
** aFile[0] such that the PmaReader should start rereading it from the
** beginning.
**
-** For single-threaded objects, this is accomplished by literally reading
-** keys from pIncr->pMerger and repopulating aFile[0].
+** For single-threaded objects, this is accomplished by literally reading
+** keys from pIncr->pMerger and repopulating aFile[0].
**
-** For multi-threaded objects, all that is required is to wait until the
-** background thread is finished (if it is not already) and then swap
+** For multi-threaded objects, all that is required is to wait until the
+** background thread is finished (if it is not already) and then swap
** aFile[0] and aFile[1] in place. If the contents of pMerger have not
** been exhausted, this function also launches a new background thread
** to populate the new aFile[1].
@@ -86925,7 +95964,7 @@ static void vdbeMergeEngineCompare(
#define INCRINIT_TASK 1
#define INCRINIT_ROOT 2
-/*
+/*
** Forward reference required as the vdbeIncrMergeInit() and
** vdbePmaReaderIncrInit() routines are called mutually recursively when
** building a merge tree.
@@ -86934,7 +95973,7 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode);
/*
** Initialize the MergeEngine object passed as the second argument. Once this
-** function returns, the first key of merged data may be read from the
+** function returns, the first key of merged data may be read from the
** MergeEngine object in the usual fashion.
**
** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge
@@ -86944,8 +95983,8 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode);
** required is to call vdbePmaReaderNext() on each PmaReader to point it at
** its first key.
**
-** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
-** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
+** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
+** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
** to pMerger.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
@@ -86957,7 +95996,11 @@ static int vdbeMergeEngineInit(
){
int rc = SQLITE_OK; /* Return code */
int i; /* For looping over PmaReader objects */
- int nTree = pMerger->nTree;
+ int nTree; /* Number of subtrees to merge */
+
+ /* Failure to allocate the merge would have been detected prior to
+ ** invoking this routine */
+ assert( pMerger!=0 );
/* eMode is always INCRINIT_NORMAL in single-threaded mode */
assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
@@ -86966,6 +96009,7 @@ static int vdbeMergeEngineInit(
assert( pMerger->pTask==0 );
pMerger->pTask = pTask;
+ nTree = pMerger->nTree;
for(i=0; i<nTree; i++){
if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){
/* PmaReaders should be normally initialized in order, as if they are
@@ -86995,19 +96039,19 @@ static int vdbeMergeEngineInit(
** object at (pReadr->pIncr).
**
** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders
-** in the sub-tree headed by pReadr are also initialized. Data is then
-** loaded into the buffers belonging to pReadr and it is set to point to
+** in the sub-tree headed by pReadr are also initialized. Data is then
+** loaded into the buffers belonging to pReadr and it is set to point to
** the first key in its range.
**
** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed
** to be a multi-threaded PmaReader and this function is being called in a
-** background thread. In this case all PmaReaders in the sub-tree are
+** background thread. In this case all PmaReaders in the sub-tree are
** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to
** pReadr is populated. However, pReadr itself is not set up to point
** to its first key. A call to vdbePmaReaderNext() is still required to do
-** that.
+** that.
**
-** The reason this function does not call vdbePmaReaderNext() immediately
+** The reason this function does not call vdbePmaReaderNext() immediately
** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has
** to block on thread (pTask->thread) before accessing aFile[1]. But, since
** this entire function is being run by thread (pTask->thread), that will
@@ -87063,12 +96107,12 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
if( rc==SQLITE_OK && pIncr->bUseThread ){
/* Use the current thread to populate aFile[1], even though this
** PmaReader is multi-threaded. If this is an INCRINIT_TASK object,
- ** then this function is already running in background thread
- ** pIncr->pTask->thread.
+ ** then this function is already running in background thread
+ ** pIncr->pTask->thread.
**
- ** If this is the INCRINIT_ROOT object, then it is running in the
+ ** If this is the INCRINIT_ROOT object, then it is running in the
** main VDBE thread. But that is Ok, as that thread cannot return
- ** control to the VDBE or proceed with anything useful until the
+ ** control to the VDBE or proceed with anything useful until the
** first results are ready from this merger object anyway.
*/
assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK );
@@ -87085,7 +96129,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
#if SQLITE_MAX_WORKER_THREADS>0
/*
-** The main routine for vdbePmaReaderIncrMergeInit() operations run in
+** The main routine for vdbePmaReaderIncrMergeInit() operations run in
** background threads.
*/
static void *vdbePmaReaderBgIncrInit(void *pCtx){
@@ -87103,8 +96147,8 @@ static void *vdbePmaReaderBgIncrInit(void *pCtx){
** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes
** the vdbePmaReaderIncrMergeInit() function with the parameters passed to
** this routine to initialize the incremental merge.
-**
-** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1),
+**
+** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1),
** then a background thread is launched to call vdbePmaReaderIncrMergeInit().
** Or, if the IncrMerger is single threaded, the same function is called
** using the current thread.
@@ -87134,7 +96178,7 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){
** to NULL and return an SQLite error code.
**
** When this function is called, *piOffset is set to the offset of the
-** first PMA to read from pTask->file. Assuming no error occurs, it is
+** first PMA to read from pTask->file. Assuming no error occurs, it is
** set to the offset immediately following the last byte of the last
** PMA before returning. If an error does occur, then the final value of
** *piOffset is undefined.
@@ -87244,12 +96288,12 @@ static int vdbeSorterAddToTree(
/*
** This function is called as part of a SorterRewind() operation on a sorter
** that has already written two or more level-0 PMAs to one or more temp
-** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that
+** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that
** can be used to incrementally merge all PMAs on disk.
**
** If successful, SQLITE_OK is returned and *ppOut set to point to the
** MergeEngine object at the root of the tree before returning. Or, if an
-** error occurs, an SQLite error code is returned and the final value
+** error occurs, an SQLite error code is returned and the final value
** of *ppOut is undefined.
*/
static int vdbeSorterMergeTreeBuild(
@@ -87261,8 +96305,8 @@ static int vdbeSorterMergeTreeBuild(
int iTask;
#if SQLITE_MAX_WORKER_THREADS>0
- /* If the sorter uses more than one task, then create the top-level
- ** MergeEngine here. This MergeEngine will read data from exactly
+ /* If the sorter uses more than one task, then create the top-level
+ ** MergeEngine here. This MergeEngine will read data from exactly
** one PmaReader per sub-task. */
assert( pSorter->bUseThreads || pSorter->nTask==1 );
if( pSorter->nTask>1 ){
@@ -87371,7 +96415,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
}
for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
/* Check that:
- **
+ **
** a) The incremental merge object is configured to use the
** right task, and
** b) If it is using task (nTask-1), it is configured to run
@@ -87434,7 +96478,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
return rc;
}
- /* Write the current in-memory list to a PMA. When the VdbeSorterWrite()
+ /* Write the current in-memory list to a PMA. When the VdbeSorterWrite()
** function flushes the contents of memory to disk, it immediately always
** creates a new list consisting of a single key immediately afterwards.
** So the list is never empty at this point. */
@@ -87446,7 +96490,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
vdbeSorterRewindDebug("rewind");
- /* Assuming no errors have occurred, set up a merger structure to
+ /* Assuming no errors have occurred, set up a merger structure to
** incrementally read and merge all remaining PMAs. */
assert( pSorter->pReader==0 );
if( rc==SQLITE_OK ){
@@ -87459,9 +96503,13 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
}
/*
-** Advance to the next element in the sorter.
+** Advance to the next element in the sorter. Return value:
+**
+** SQLITE_OK success
+** SQLITE_DONE end of data
+** otherwise some kind of error.
*/
-SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
+SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
VdbeSorter *pSorter;
int rc; /* Return code */
@@ -87475,27 +96523,28 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, in
#if SQLITE_MAX_WORKER_THREADS>0
if( pSorter->bUseThreads ){
rc = vdbePmaReaderNext(pSorter->pReader);
- *pbEof = (pSorter->pReader->pFd==0);
+ if( rc==SQLITE_OK && pSorter->pReader->pFd==0 ) rc = SQLITE_DONE;
}else
#endif
/*if( !pSorter->bUseThreads )*/ {
+ int res = 0;
assert( pSorter->pMerger!=0 );
assert( pSorter->pMerger->pTask==(&pSorter->aTask[0]) );
- rc = vdbeMergeEngineStep(pSorter->pMerger, pbEof);
+ rc = vdbeMergeEngineStep(pSorter->pMerger, &res);
+ if( rc==SQLITE_OK && res ) rc = SQLITE_DONE;
}
}else{
SorterRecord *pFree = pSorter->list.pList;
pSorter->list.pList = pFree->u.pNext;
pFree->u.pNext = 0;
if( pSorter->list.aMemory==0 ) vdbeSorterRecordFree(db, pFree);
- *pbEof = !pSorter->list.pList;
- rc = SQLITE_OK;
+ rc = pSorter->list.pList ? SQLITE_OK : SQLITE_DONE;
}
return rc;
}
/*
-** Return a pointer to a buffer owned by the sorter that contains the
+** Return a pointer to a buffer owned by the sorter that contains the
** current key.
*/
static void *vdbeSorterRowkey(
@@ -87575,9 +96624,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
r2 = pSorter->pUnpacked;
pKeyInfo = pCsr->pKeyInfo;
if( r2==0 ){
- char *p;
- r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
- assert( pSorter->pUnpacked==(UnpackedRecord*)p );
+ r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
if( r2==0 ) return SQLITE_NOMEM_BKPT;
r2->nField = nKeyCol;
}
@@ -87597,6 +96644,433 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
}
/************** End of vdbesort.c ********************************************/
+/************** Begin file vdbevtab.c ****************************************/
+/*
+** 2020-03-23
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements virtual-tables for examining the bytecode content
+** of a prepared statement.
+*/
+/* #include "sqliteInt.h" */
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
+/* #include "vdbeInt.h" */
+
+/* An instance of the bytecode() table-valued function.
+*/
+typedef struct bytecodevtab bytecodevtab;
+struct bytecodevtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection */
+ int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
+};
+
+/* A cursor for scanning through the bytecode
+*/
+typedef struct bytecodevtab_cursor bytecodevtab_cursor;
+struct bytecodevtab_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */
+ int iRowid; /* The rowid of the output table */
+ int iAddr; /* Address */
+ int needFinalize; /* Cursors owns pStmt and must finalize it */
+ int showSubprograms; /* Provide a listing of subprograms */
+ Op *aOp; /* Operand array */
+ char *zP4; /* Rendered P4 value */
+ const char *zType; /* tables_used.type */
+ const char *zSchema; /* tables_used.schema */
+ const char *zName; /* tables_used.name */
+ Mem sub; /* Subprograms */
+};
+
+/*
+** Create a new bytecode() table-valued function.
+*/
+static int bytecodevtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ bytecodevtab *pNew;
+ int rc;
+ int isTabUsed = pAux!=0;
+ const char *azSchema[2] = {
+ /* bytecode() schema */
+ "CREATE TABLE x("
+ "addr INT,"
+ "opcode TEXT,"
+ "p1 INT,"
+ "p2 INT,"
+ "p3 INT,"
+ "p4 TEXT,"
+ "p5 INT,"
+ "comment TEXT,"
+ "subprog TEXT,"
+ "stmt HIDDEN"
+ ");",
+
+ /* Tables_used() schema */
+ "CREATE TABLE x("
+ "type TEXT,"
+ "schema TEXT,"
+ "name TEXT,"
+ "wr INT,"
+ "subprog TEXT,"
+ "stmt HIDDEN"
+ ");"
+ };
+
+ rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ pNew->bTablesUsed = isTabUsed*2;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for bytecodevtab objects.
+*/
+static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
+ bytecodevtab *p = (bytecodevtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new bytecodevtab_cursor object.
+*/
+static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ bytecodevtab *pVTab = (bytecodevtab*)p;
+ bytecodevtab_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Clear all internal content from a bytecodevtab cursor.
+*/
+static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
+ sqlite3_free(pCur->zP4);
+ pCur->zP4 = 0;
+ sqlite3VdbeMemRelease(&pCur->sub);
+ sqlite3VdbeMemSetNull(&pCur->sub);
+ if( pCur->needFinalize ){
+ sqlite3_finalize(pCur->pStmt);
+ }
+ pCur->pStmt = 0;
+ pCur->needFinalize = 0;
+ pCur->zType = 0;
+ pCur->zSchema = 0;
+ pCur->zName = 0;
+}
+
+/*
+** Destructor for a bytecodevtab_cursor.
+*/
+static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ bytecodevtabCursorClear(pCur);
+ sqlite3_free(pCur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a bytecodevtab_cursor to its next row of output.
+*/
+static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
+ int rc;
+ if( pCur->zP4 ){
+ sqlite3_free(pCur->zP4);
+ pCur->zP4 = 0;
+ }
+ if( pCur->zName ){
+ pCur->zName = 0;
+ pCur->zType = 0;
+ pCur->zSchema = 0;
+ }
+ rc = sqlite3VdbeNextOpcode(
+ (Vdbe*)pCur->pStmt,
+ pCur->showSubprograms ? &pCur->sub : 0,
+ pTab->bTablesUsed,
+ &pCur->iRowid,
+ &pCur->iAddr,
+ &pCur->aOp);
+ if( rc!=SQLITE_OK ){
+ sqlite3VdbeMemSetNull(&pCur->sub);
+ pCur->aOp = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ return pCur->aOp==0;
+}
+
+/*
+** Return values of columns for the row at which the bytecodevtab_cursor
+** is currently pointing.
+*/
+static int bytecodevtabColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
+ Op *pOp = pCur->aOp + pCur->iAddr;
+ if( pVTab->bTablesUsed ){
+ if( i==4 ){
+ i = 8;
+ }else{
+ if( i<=2 && pCur->zType==0 ){
+ Schema *pSchema;
+ HashElem *k;
+ int iDb = pOp->p3;
+ Pgno iRoot = (Pgno)pOp->p2;
+ sqlite3 *db = pVTab->db;
+ pSchema = db->aDb[iDb].pSchema;
+ pCur->zSchema = db->aDb[iDb].zDbSName;
+ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
+ Table *pTab = (Table*)sqliteHashData(k);
+ if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
+ pCur->zName = pTab->zName;
+ pCur->zType = "table";
+ break;
+ }
+ }
+ if( pCur->zName==0 ){
+ for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
+ Index *pIdx = (Index*)sqliteHashData(k);
+ if( pIdx->tnum==iRoot ){
+ pCur->zName = pIdx->zName;
+ pCur->zType = "index";
+ }
+ }
+ }
+ }
+ i += 10;
+ }
+ }
+ switch( i ){
+ case 0: /* addr */
+ sqlite3_result_int(ctx, pCur->iAddr);
+ break;
+ case 1: /* opcode */
+ sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
+ -1, SQLITE_STATIC);
+ break;
+ case 2: /* p1 */
+ sqlite3_result_int(ctx, pOp->p1);
+ break;
+ case 3: /* p2 */
+ sqlite3_result_int(ctx, pOp->p2);
+ break;
+ case 4: /* p3 */
+ sqlite3_result_int(ctx, pOp->p3);
+ break;
+ case 5: /* p4 */
+ case 7: /* comment */
+ if( pCur->zP4==0 ){
+ pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
+ }
+ if( i==5 ){
+ sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
+ }else{
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
+ sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
+#endif
+ }
+ break;
+ case 6: /* p5 */
+ sqlite3_result_int(ctx, pOp->p5);
+ break;
+ case 8: { /* subprog */
+ Op *aOp = pCur->aOp;
+ assert( aOp[0].opcode==OP_Init );
+ assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
+ if( pCur->iRowid==pCur->iAddr+1 ){
+ break; /* Result is NULL for the main program */
+ }else if( aOp[0].p4.z!=0 ){
+ sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
+ }else{
+ sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
+ }
+ break;
+ }
+ case 10: /* tables_used.type */
+ sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
+ break;
+ case 11: /* tables_used.schema */
+ sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
+ break;
+ case 12: /* tables_used.name */
+ sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
+ break;
+ case 13: /* tables_used.wr */
+ sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Initialize a cursor.
+**
+** idxNum==0 means show all subprograms
+** idxNum==1 means show only the main bytecode and omit subprograms.
+*/
+static int bytecodevtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
+ bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
+ int rc = SQLITE_OK;
+
+ bytecodevtabCursorClear(pCur);
+ pCur->iRowid = 0;
+ pCur->iAddr = 0;
+ pCur->showSubprograms = idxNum==0;
+ assert( argc==1 );
+ if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
+ pCur->needFinalize = 1;
+ }
+ }else{
+ pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
+ }
+ if( pCur->pStmt==0 ){
+ pVTab->base.zErrMsg = sqlite3_mprintf(
+ "argument to %s() is not a valid SQL statement",
+ pVTab->bTablesUsed ? "tables_used" : "bytecode"
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ bytecodevtabNext(pVtabCursor);
+ }
+ return rc;
+}
+
+/*
+** We must have a single stmt=? constraint that will be passed through
+** into the xFilter method. If there is no valid stmt=? constraint,
+** then return an SQLITE_CONSTRAINT error.
+*/
+static int bytecodevtabBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int rc = SQLITE_CONSTRAINT;
+ struct sqlite3_index_constraint *p;
+ bytecodevtab *pVTab = (bytecodevtab*)tab;
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
+ pIdxInfo->estimatedCost = (double)100;
+ pIdxInfo->estimatedRows = 100;
+ pIdxInfo->idxNum = 0;
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
+ if( p->usable==0 ) continue;
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
+ rc = SQLITE_OK;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ }
+ if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->idxNum = 1;
+ }
+ }
+ return rc;
+}
+
+/*
+** This following structure defines all the methods for the
+** virtual table.
+*/
+static sqlite3_module bytecodevtabModule = {
+ /* iVersion */ 0,
+ /* xCreate */ 0,
+ /* xConnect */ bytecodevtabConnect,
+ /* xBestIndex */ bytecodevtabBestIndex,
+ /* xDisconnect */ bytecodevtabDisconnect,
+ /* xDestroy */ 0,
+ /* xOpen */ bytecodevtabOpen,
+ /* xClose */ bytecodevtabClose,
+ /* xFilter */ bytecodevtabFilter,
+ /* xNext */ bytecodevtabNext,
+ /* xEof */ bytecodevtabEof,
+ /* xColumn */ bytecodevtabColumn,
+ /* xRowid */ bytecodevtabRowid,
+ /* xUpdate */ 0,
+ /* xBegin */ 0,
+ /* xSync */ 0,
+ /* xCommit */ 0,
+ /* xRollback */ 0,
+ /* xFindMethod */ 0,
+ /* xRename */ 0,
+ /* xSavepoint */ 0,
+ /* xRelease */ 0,
+ /* xRollbackTo */ 0,
+ /* xShadowName */ 0
+};
+
+
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
+ int rc;
+ rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
+ }
+ return rc;
+}
+#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB */
+
+/************** End of vdbevtab.c ********************************************/
/************** Begin file memjournal.c **************************************/
/*
** 2008 October 7
@@ -87696,17 +97170,13 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
-#endif
-
- assert( (iAmt+iOfst)<=p->endpoint.iOffset );
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
- for(pChunk=p->pFirst;
+ for(pChunk=p->pFirst;
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
pChunk=pChunk->pNext
){
@@ -87741,7 +97211,7 @@ static void memjrnlFreeChunks(MemJournal *p){
for(pIter=p->pFirst; pIter; pIter=pNext){
pNext = pIter->pNext;
sqlite3_free(pIter);
- }
+ }
p->pFirst = 0;
}
@@ -87813,9 +97283,10 @@ static int memjrnlWrite(
** access writes are not required. The only exception to this is when
** the in-memory journal is being used by a connection using the
** atomic-write optimization. In this case the first 28 bytes of the
- ** journal file may be written as part of committing the transaction. */
+ ** journal file may be written as part of committing the transaction. */
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
@@ -87863,7 +97334,7 @@ static int memjrnlWrite(
**
** If the journal file is already on disk, truncate it there. Or, if it
** is still in main memory but is being truncated to zero bytes in size,
-** ignore
+** ignore
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
@@ -87890,8 +97361,8 @@ static int memjrnlClose(sqlite3_file *pJfd){
/*
** Sync the file.
**
-** If the real file has been created, call its xSync method. Otherwise,
-** syncing an in-memory journal is a no-op.
+** If the real file has been created, call its xSync method. Otherwise,
+** syncing an in-memory journal is a no-op.
*/
static int memjrnlSync(sqlite3_file *pJfd, int flags){
UNUSED_PARAMETER2(pJfd, flags);
@@ -87932,11 +97403,11 @@ static const struct sqlite3_io_methods MemJournalMethods = {
0 /* xUnfetch */
};
-/*
-** Open a journal file.
+/*
+** Open a journal file.
**
-** The behaviour of the journal file depends on the value of parameter
-** nSpill. If nSpill is 0, then the journal file is always create and
+** The behaviour of the journal file depends on the value of parameter
+** nSpill. If nSpill is 0, then the journal file is always create and
** accessed using the underlying VFS. If nSpill is less than zero, then
** all content is always stored in main-memory. Finally, if nSpill is a
** positive value, then the journal file is initially created in-memory
@@ -87969,7 +97440,7 @@ SQLITE_PRIVATE int sqlite3JournalOpen(
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
}
- p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
+ pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
p->nSpill = nSpill;
p->flags = flags;
p->zJournal = zName;
@@ -87984,17 +97455,31 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
+ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
/*
-** If the argument p points to a MemJournal structure that is not an
+** If the argument p points to a MemJournal structure that is not an
** in-memory-only journal file (i.e. is one that was opened with a +ve
-** nSpill parameter), and the underlying file has not yet been created,
-** create it now.
+** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
+** file has not yet been created, create it now.
*/
-SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
+SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
int rc = SQLITE_OK;
- if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
- rc = memjrnlCreateFile((MemJournal*)p);
+ MemJournal *p = (MemJournal*)pJfd;
+ if( pJfd->pMethods==&MemJournalMethods && (
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ p->nSpill>0
+#else
+ /* While this appears to not be possible without ATOMIC_WRITE, the
+ ** paths are complex, so it seems prudent to leave the test in as
+ ** a NEVER(), in case our analysis is subtly flawed. */
+ NEVER(p->nSpill>0)
+#endif
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
+ || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
+#endif
+ )){
+ rc = memjrnlCreateFile(p);
}
return rc;
}
@@ -88009,7 +97494,7 @@ SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){
return p->pMethods==&MemJournalMethods;
}
-/*
+/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
*/
@@ -88038,6 +97523,35 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
/* #include <string.h> */
+#if !defined(SQLITE_OMIT_WINDOWFUNC)
+/*
+** Walk all expressions linked into the list of Window objects passed
+** as the second argument.
+*/
+static int walkWindowList(Walker *pWalker, Window *pList){
+ Window *pWin;
+ for(pWin=pList; pWin; pWin=pWin->pNextWin){
+ int rc;
+ rc = sqlite3WalkExprList(pWalker, pWin->pOrderBy);
+ if( rc ) return WRC_Abort;
+ rc = sqlite3WalkExprList(pWalker, pWin->pPartition);
+ if( rc ) return WRC_Abort;
+ rc = sqlite3WalkExpr(pWalker, pWin->pFilter);
+ if( rc ) return WRC_Abort;
+
+ /* The next two are purely for calls to sqlite3RenameExprUnmap()
+ ** within sqlite3WindowOffsetExpr(). Because of constraints imposed
+ ** by sqlite3WindowOffsetExpr(), they can never fail. The results do
+ ** not matter anyhow. */
+ rc = sqlite3WalkExpr(pWalker, pWin->pStart);
+ if( NEVER(rc) ) return WRC_Abort;
+ rc = sqlite3WalkExpr(pWalker, pWin->pEnd);
+ if( NEVER(rc) ) return WRC_Abort;
+ }
+ return WRC_Continue;
+}
+#endif
+
/*
** Walk an expression tree. Invoke the callback once for each node
** of the expression, while descending. (In other words, the callback
@@ -88048,11 +97562,11 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
**
** WRC_Continue Continue descending down the tree.
**
-** WRC_Prune Do not descend into child nodes. But allow
+** WRC_Prune Do not descend into child nodes, but allow
** the walk to continue with sibling nodes.
**
** WRC_Abort Do no more callbacks. Unwind the stack and
-** return the top-level walk call.
+** return from the top-level walk call.
**
** The return value from this routine is WRC_Abort to abandon the tree walk
** and WRC_Continue to continue.
@@ -88061,16 +97575,31 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
- rc = pWalker->xExprCallback(pWalker, pExpr);
- if( rc || ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
- return rc & WRC_Abort;
- }
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
- if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
- }else if( pExpr->x.pList ){
- if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ while(1){
+ rc = pWalker->xExprCallback(pWalker, pExpr);
+ if( rc ) return rc & WRC_Abort;
+ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
+ assert( pExpr->x.pList==0 || pExpr->pRight==0 );
+ if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ if( pExpr->pRight ){
+ assert( !ExprHasProperty(pExpr, EP_WinFunc) );
+ pExpr = pExpr->pRight;
+ continue;
+ }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ assert( !ExprHasProperty(pExpr, EP_WinFunc) );
+ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
+ }else{
+ if( pExpr->x.pList ){
+ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort;
+ }
+#endif
+ }
+ }
+ break;
}
return WRC_Continue;
}
@@ -88106,7 +97635,17 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort;
if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort;
- if( sqlite3WalkExpr(pWalker, p->pOffset) ) return WRC_Abort;
+#if !defined(SQLITE_OMIT_WINDOWFUNC) && !defined(SQLITE_OMIT_ALTERTABLE)
+ {
+ Parse *pParse = pWalker->pParse;
+ if( pParse && IN_RENAME_OBJECT ){
+ /* The following may return WRC_Abort if there are unresolvable
+ ** symbols (e.g. a table that does not exist) in a window definition. */
+ int rc = walkWindowList(pWalker, p->pWinDefn);
+ return rc;
+ }
+ }
+#endif
return WRC_Continue;
}
@@ -88114,7 +97653,7 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
** Walk the parse trees associated with all subqueries in the
** FROM clause of SELECT statement p. Do not invoke the select
** callback on p, but do invoke it on each FROM clause subquery
-** and on any subqueries further down in the tree. Return
+** and on any subqueries further down in the tree. Return
** WRC_Abort or WRC_Continue;
*/
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
@@ -88123,9 +97662,9 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
struct SrcList_item *pItem;
pSrc = p->pSrc;
- if( ALWAYS(pSrc) ){
+ if( pSrc ){
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
+ if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
return WRC_Abort;
}
if( pItem->fg.isTabFunc
@@ -88136,17 +97675,18 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
}
}
return WRC_Continue;
-}
+}
/*
** Call sqlite3WalkExpr() for every expression in Select statement p.
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
-** on the compound select chain, p->pPrior.
+** on the compound select chain, p->pPrior.
**
** If it is not NULL, the xSelectCallback() callback is invoked before
** the walk of the expressions and FROM clause. The xSelectCallback2()
-** method, if it is not NULL, is invoked following the walk of the
-** expressions and FROM clause.
+** method is invoked following the walk of the expressions and FROM clause,
+** but only if both xSelectCallback and xSelectCallback2 are both non-NULL
+** and if the expressions and FROM clause both return WRC_Continue;
**
** Return WRC_Continue under normal conditions. Return WRC_Abort if
** there is an abort request.
@@ -88156,29 +97696,59 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
*/
SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
int rc;
- if( p==0 || (pWalker->xSelectCallback==0 && pWalker->xSelectCallback2==0) ){
- return WRC_Continue;
- }
- rc = WRC_Continue;
- pWalker->walkerDepth++;
- while( p ){
- if( pWalker->xSelectCallback ){
- rc = pWalker->xSelectCallback(pWalker, p);
- if( rc ) break;
- }
+ if( p==0 ) return WRC_Continue;
+ if( pWalker->xSelectCallback==0 ) return WRC_Continue;
+ do{
+ rc = pWalker->xSelectCallback(pWalker, p);
+ if( rc ) return rc & WRC_Abort;
if( sqlite3WalkSelectExpr(pWalker, p)
|| sqlite3WalkSelectFrom(pWalker, p)
){
- pWalker->walkerDepth--;
return WRC_Abort;
}
if( pWalker->xSelectCallback2 ){
pWalker->xSelectCallback2(pWalker, p);
}
p = p->pPrior;
- }
+ }while( p!=0 );
+ return WRC_Continue;
+}
+
+/* Increase the walkerDepth when entering a subquery, and
+** descrease when leaving the subquery.
+*/
+SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
+ UNUSED_PARAMETER(pSelect);
+ pWalker->walkerDepth++;
+ return WRC_Continue;
+}
+SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){
+ UNUSED_PARAMETER(pSelect);
pWalker->walkerDepth--;
- return rc & WRC_Abort;
+}
+
+
+/*
+** No-op routine for the parse-tree walker.
+**
+** When this routine is the Walker.xExprCallback then expression trees
+** are walked without any actions being taken at each node. Presumably,
+** when this routine is used for Walker.xExprCallback then
+** Walker.xSelectCallback is set to do something useful for every
+** subquery in the parser tree.
+*/
+SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return WRC_Continue;
+}
+
+/*
+** No-op routine for the parse-tree walker for SELECT statements.
+** subquery in the parser tree.
+*/
+SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ return WRC_Continue;
}
/************** End of walker.c **********************************************/
@@ -88200,8 +97770,11 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
** table and column.
*/
/* #include "sqliteInt.h" */
-/* #include <stdlib.h> */
-/* #include <string.h> */
+
+/*
+** Magic table number to mean the EXCLUDED table in an UPSERT statement.
+*/
+#define EXCLUDED_TABLE_NUMBER 2
/*
** Walk the expression tree pExpr and increase the aggregate function
@@ -88211,6 +97784,8 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
**
** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
** is a helper function - a callback for the tree walker.
+**
+** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
*/
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
@@ -88262,29 +97837,37 @@ static void resolveAlias(
assert( pOrig!=0 );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
- if( pDup==0 ) return;
- if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
- if( pExpr->op==TK_COLLATE ){
- pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
- }
- ExprSetProperty(pDup, EP_Alias);
+ if( pDup!=0 ){
+ if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
+ if( pExpr->op==TK_COLLATE ){
+ pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
+ }
- /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
- ** prevents ExprDelete() from deleting the Expr structure itself,
- ** allowing it to be repopulated by the memcpy() on the following line.
- ** The pExpr->u.zToken might point into memory that will be freed by the
- ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
- ** make a copy of the token before doing the sqlite3DbFree().
- */
- ExprSetProperty(pExpr, EP_Static);
- sqlite3ExprDelete(db, pExpr);
- memcpy(pExpr, pDup, sizeof(*pExpr));
- if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
- assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
- pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
- pExpr->flags |= EP_MemToken;
+ /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
+ ** prevents ExprDelete() from deleting the Expr structure itself,
+ ** allowing it to be repopulated by the memcpy() on the following line.
+ ** The pExpr->u.zToken might point into memory that will be freed by the
+ ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
+ ** make a copy of the token before doing the sqlite3DbFree().
+ */
+ ExprSetProperty(pExpr, EP_Static);
+ sqlite3ExprDelete(db, pExpr);
+ memcpy(pExpr, pDup, sizeof(*pExpr));
+ if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
+ assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
+ pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
+ pExpr->flags |= EP_MemToken;
+ }
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ if( pExpr->y.pWin!=0 ){
+ pExpr->y.pWin->pOwner = pExpr;
+ }else{
+ assert( db->mallocFailed );
+ }
+ }
+ sqlite3DbFree(db, pDup);
}
- sqlite3DbFree(db, pDup);
+ ExprSetProperty(pExpr, EP_Alias);
}
@@ -88311,13 +97894,16 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
** match anything.
*/
-SQLITE_PRIVATE int sqlite3MatchSpanName(
- const char *zSpan,
+SQLITE_PRIVATE int sqlite3MatchEName(
+ const struct ExprList_item *pItem,
const char *zCol,
const char *zTab,
const char *zDb
){
int n;
+ const char *zSpan;
+ if( pItem->eEName!=ENAME_TAB ) return 0;
+ zSpan = pItem->zEName;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
return 0;
@@ -88335,8 +97921,50 @@ SQLITE_PRIVATE int sqlite3MatchSpanName(
}
/*
+** Return TRUE if the double-quoted string mis-feature should be supported.
+*/
+static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){
+ if( db->init.busy ) return 1; /* Always support for legacy schemas */
+ if( pTopNC->ncFlags & NC_IsDDL ){
+ /* Currently parsing a DDL statement */
+ if( sqlite3WritableSchema(db) && (db->flags & SQLITE_DqsDML)!=0 ){
+ return 1;
+ }
+ return (db->flags & SQLITE_DqsDDL)!=0;
+ }else{
+ /* Currently parsing a DML statement */
+ return (db->flags & SQLITE_DqsDML)!=0;
+ }
+}
+
+/*
+** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN.
+** return the appropriate colUsed mask.
+*/
+SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr *pExpr){
+ int n;
+ Table *pExTab;
+
+ n = pExpr->iColumn;
+ pExTab = pExpr->y.pTab;
+ assert( pExTab!=0 );
+ if( (pExTab->tabFlags & TF_HasGenerated)!=0
+ && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
+ ){
+ testcase( pExTab->nCol==BMS-1 );
+ testcase( pExTab->nCol==BMS );
+ return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
+ }else{
+ testcase( n==BMS-1 );
+ testcase( n==BMS );
+ if( n>=BMS ) n = BMS-1;
+ return ((Bitmask)1)<<n;
+ }
+}
+
+/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
-** that name in the set of source tables in pSrcList and make the pExpr
+** that name in the set of source tables in pSrcList and make the pExpr
** expression node refer back to that source column. The following changes
** are made to pExpr:
**
@@ -88344,7 +97972,7 @@ SQLITE_PRIVATE int sqlite3MatchSpanName(
** (even if X is implied).
** pExpr->iTable Set to the cursor number for the table obtained
** from pSrcList.
-** pExpr->pTab Points to the Table structure of X.Y (even if
+** pExpr->y.pTab Points to the Table structure of X.Y (even if
** X and/or Y are implied.)
** pExpr->iColumn Set to the column number within the table.
** pExpr->op Set to TK_COLUMN.
@@ -88378,7 +98006,7 @@ static int lookupName(
struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
NameContext *pTopNC = pNC; /* First namecontext in the list */
Schema *pSchema = 0; /* Schema of the expression */
- int isTrigger = 0; /* True if resolved to a trigger column */
+ int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
Table *pTab = 0; /* Table hold the row */
Column *pCol; /* A column of pTab */
@@ -88388,7 +98016,6 @@ static int lookupName(
/* Initialize the node to no-match */
pExpr->iTable = -1;
- pExpr->pTab = 0;
ExprSetVVAProperty(pExpr, EP_NoReduce);
/* Translate the schema name in zDb into a pointer to the corresponding
@@ -88412,16 +98039,24 @@ static int lookupName(
break;
}
}
+ if( i==db->nDb && sqlite3StrICmp("main", zDb)==0 ){
+ /* This branch is taken when the main database has been renamed
+ ** using SQLITE_DBCONFIG_MAINDBNAME. */
+ pSchema = db->aDb[0].pSchema;
+ zDb = db->aDb[0].zDbSName;
+ }
}
}
/* Start at the inner-most context and move outward until a match is found */
- while( pNC && cnt==0 ){
+ assert( pNC && cnt==0 );
+ do{
ExprList *pEList;
SrcList *pSrcList = pNC->pSrcList;
if( pSrcList ){
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
+ u8 hCol;
pTab = pItem->pTab;
assert( pTab!=0 && pTab->zName!=0 );
assert( pTab->nCol>0 );
@@ -88429,7 +98064,7 @@ static int lookupName(
int hit = 0;
pEList = pItem->pSelect->pEList;
for(j=0; j<pEList->nExpr; j++){
- if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){
+ if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
cnt++;
cntTab = 2;
pMatch = pItem;
@@ -88448,14 +98083,18 @@ static int lookupName(
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
continue;
}
+ if( IN_RENAME_OBJECT && pItem->zAlias ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
+ }
}
if( 0==(cntTab++) ){
pMatch = pItem;
}
+ hCol = sqlite3StrIHash(zCol);
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
+ if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){
/* If there has been exactly one prior match and this match
- ** is for the right-hand table of a NATURAL JOIN or is in a
+ ** is for the right-hand table of a NATURAL JOIN or is in a
** USING clause, then skip this match.
*/
if( cnt==1 ){
@@ -88472,39 +98111,53 @@ static int lookupName(
}
if( pMatch ){
pExpr->iTable = pMatch->iCursor;
- pExpr->pTab = pMatch->pTab;
+ pExpr->y.pTab = pMatch->pTab;
/* RIGHT JOIN not (yet) supported */
assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
ExprSetProperty(pExpr, EP_CanBeNull);
}
- pSchema = pExpr->pTab->pSchema;
+ pSchema = pExpr->y.pTab->pSchema;
}
} /* if( pSrcList ) */
-#ifndef SQLITE_OMIT_TRIGGER
- /* If we have not already resolved the name, then maybe
- ** it is a new.* or old.* trigger argument reference
+#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT)
+ /* If we have not already resolved the name, then maybe
+ ** it is a new.* or old.* trigger argument reference. Or
+ ** maybe it is an excluded.* from an upsert.
*/
- if( zDb==0 && zTab!=0 && cntTab==0 && pParse->pTriggerTab!=0 ){
- int op = pParse->eTriggerOp;
- assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
- if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
- pExpr->iTable = 1;
- pTab = pParse->pTriggerTab;
- }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
- pExpr->iTable = 0;
- pTab = pParse->pTriggerTab;
- }else{
- pTab = 0;
+ if( zDb==0 && zTab!=0 && cntTab==0 ){
+ pTab = 0;
+#ifndef SQLITE_OMIT_TRIGGER
+ if( pParse->pTriggerTab!=0 ){
+ int op = pParse->eTriggerOp;
+ assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
+ if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
+ pExpr->iTable = 1;
+ pTab = pParse->pTriggerTab;
+ }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
+ pExpr->iTable = 0;
+ pTab = pParse->pTriggerTab;
+ }
+ }
+#endif /* SQLITE_OMIT_TRIGGER */
+#ifndef SQLITE_OMIT_UPSERT
+ if( (pNC->ncFlags & NC_UUpsert)!=0 ){
+ Upsert *pUpsert = pNC->uNC.pUpsert;
+ if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
+ pTab = pUpsert->pUpsertSrc->a[0].pTab;
+ pExpr->iTable = EXCLUDED_TABLE_NUMBER;
+ }
}
+#endif /* SQLITE_OMIT_UPSERT */
- if( pTab ){
+ if( pTab ){
int iCol;
+ u8 hCol = sqlite3StrIHash(zCol);
pSchema = pTab->pSchema;
cntTab++;
for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
+ if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){
if( iCol==pTab->iPKey ){
iCol = -1;
}
@@ -88517,24 +98170,43 @@ static int lookupName(
}
if( iCol<pTab->nCol ){
cnt++;
- if( iCol<0 ){
- pExpr->affinity = SQLITE_AFF_INTEGER;
- }else if( pExpr->iTable==0 ){
- testcase( iCol==31 );
- testcase( iCol==32 );
- pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
- }else{
- testcase( iCol==31 );
- testcase( iCol==32 );
- pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
+#ifndef SQLITE_OMIT_UPSERT
+ if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){
+ testcase( iCol==(-1) );
+ if( IN_RENAME_OBJECT ){
+ pExpr->iColumn = iCol;
+ pExpr->y.pTab = pTab;
+ eNewExprOp = TK_COLUMN;
+ }else{
+ pExpr->iTable = pNC->uNC.pUpsert->regData +
+ sqlite3TableColumnToStorage(pTab, iCol);
+ eNewExprOp = TK_REGISTER;
+ ExprSetProperty(pExpr, EP_Alias);
+ }
+ }else
+#endif /* SQLITE_OMIT_UPSERT */
+ {
+#ifndef SQLITE_OMIT_TRIGGER
+ if( iCol<0 ){
+ pExpr->affExpr = SQLITE_AFF_INTEGER;
+ }else if( pExpr->iTable==0 ){
+ testcase( iCol==31 );
+ testcase( iCol==32 );
+ pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
+ }else{
+ testcase( iCol==31 );
+ testcase( iCol==32 );
+ pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
+ }
+ pExpr->y.pTab = pTab;
+ pExpr->iColumn = (i16)iCol;
+ eNewExprOp = TK_TRIGGER;
+#endif /* SQLITE_OMIT_TRIGGER */
}
- pExpr->iColumn = (i16)iCol;
- pExpr->pTab = pTab;
- isTrigger = 1;
}
}
}
-#endif /* !defined(SQLITE_OMIT_TRIGGER) */
+#endif /* !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT) */
/*
** Perhaps the name is a reference to the ROWID
@@ -88542,13 +98214,13 @@ static int lookupName(
if( cnt==0
&& cntTab==1
&& pMatch
- && (pNC->ncFlags & NC_IdxExpr)==0
+ && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlite3IsRowid(zCol)
&& VisibleRowid(pMatch->pTab)
){
cnt = 1;
pExpr->iColumn = -1;
- pExpr->affinity = SQLITE_AFF_INTEGER;
+ pExpr->affExpr = SQLITE_AFF_INTEGER;
}
/*
@@ -88569,13 +98241,17 @@ static int lookupName(
** is supported for backwards compatibility only. Hence, we issue a warning
** on sqlite3_log() whenever the capability is used.
*/
- if( (pEList = pNC->pEList)!=0
- && zTab==0
+ if( (pNC->ncFlags & NC_UEList)!=0
&& cnt==0
+ && zTab==0
){
+ pEList = pNC->uNC.pEList;
+ assert( pEList!=0 );
for(j=0; j<pEList->nExpr; j++){
- char *zAs = pEList->a[j].zName;
- if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+ char *zAs = pEList->a[j].zEName;
+ if( pEList->a[j].eEName==ENAME_NAME
+ && sqlite3_stricmp(zAs, zCol)==0
+ ){
Expr *pOrig;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
assert( pExpr->x.pList==0 );
@@ -88585,23 +98261,36 @@ static int lookupName(
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
return WRC_Abort;
}
+ if( ExprHasProperty(pOrig, EP_Win)
+ && ((pNC->ncFlags&NC_AllowWin)==0 || pNC!=pTopNC )
+ ){
+ sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs);
+ return WRC_Abort;
+ }
+ if( sqlite3ExprVectorSize(pOrig)!=1 ){
+ sqlite3ErrorMsg(pParse, "row value misused");
+ return WRC_Abort;
+ }
resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
cnt = 1;
pMatch = 0;
assert( zTab==0 && zDb==0 );
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
+ }
goto lookupname_end;
}
- }
+ }
}
/* Advance to the next name context. The loop will exit when either
** we have a match (cnt>0) or when we run out of name contexts.
*/
- if( cnt==0 ){
- pNC = pNC->pNext;
- nSubquery++;
- }
- }
+ if( cnt ) break;
+ pNC = pNC->pNext;
+ nSubquery++;
+ }while( pNC );
+
/*
** If X and Y are NULL (in other words if only the column name Z is
@@ -88613,10 +98302,37 @@ static int lookupName(
** Because no reference was made to outer contexts, the pNC->nRef
** fields are not changed in any context.
*/
- if( cnt==0 && zTab==0 && ExprHasProperty(pExpr,EP_DblQuoted) ){
- pExpr->op = TK_STRING;
- pExpr->pTab = 0;
- return WRC_Prune;
+ if( cnt==0 && zTab==0 ){
+ assert( pExpr->op==TK_ID );
+ if( ExprHasProperty(pExpr,EP_DblQuoted)
+ && areDoubleQuotedStringsEnabled(db, pTopNC)
+ ){
+ /* If a double-quoted identifier does not match any known column name,
+ ** then treat it as a string.
+ **
+ ** This hack was added in the early days of SQLite in a misguided attempt
+ ** to be compatible with MySQL 3.x, which used double-quotes for strings.
+ ** I now sorely regret putting in this hack. The effect of this hack is
+ ** that misspelled identifier names are silently converted into strings
+ ** rather than causing an error, to the frustration of countless
+ ** programmers. To all those frustrated programmers, my apologies.
+ **
+ ** Someday, I hope to get rid of this hack. Unfortunately there is
+ ** a huge amount of legacy SQL that uses it. So for now, we just
+ ** issue a warning.
+ */
+ sqlite3_log(SQLITE_WARNING,
+ "double-quoted string literal: \"%w\"", zCol);
+#ifdef SQLITE_ENABLE_NORMALIZE
+ sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol);
+#endif
+ pExpr->op = TK_STRING;
+ pExpr->y.pTab = 0;
+ return WRC_Prune;
+ }
+ if( sqlite3ExprIdToTrueFalse(pExpr) ){
+ return WRC_Prune;
+ }
}
/*
@@ -88639,18 +98355,20 @@ static int lookupName(
/* If a column from a table in pSrcList is referenced, then record
** this fact in the pSrcList.a[].colUsed bitmask. Column 0 causes
- ** bit 0 to be set. Column 1 sets bit 1. And so forth. If the
- ** column number is greater than the number of bits in the bitmask
- ** then set the high-order bit of the bitmask.
+ ** bit 0 to be set. Column 1 sets bit 1. And so forth. Bit 63 is
+ ** set if the 63rd or any subsequent column is used.
+ **
+ ** The colUsed mask is an optimization used to help determine if an
+ ** index is a covering index. The correct answer is still obtained
+ ** if the mask contains extra set bits. However, it is important to
+ ** avoid setting bits beyond the maximum column number of the table.
+ ** (See ticket [b92e5e8ec2cdbaa1]).
+ **
+ ** If a generated column is referenced, set bits for every column
+ ** of the table.
*/
if( pExpr->iColumn>=0 && pMatch!=0 ){
- int n = pExpr->iColumn;
- testcase( n==BMS-1 );
- if( n>=BMS ){
- n = BMS-1;
- }
- assert( pMatch->iCursor==pExpr->iTable );
- pMatch->colUsed |= ((Bitmask)1)<<n;
+ pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
}
/* Clean up and return
@@ -88659,7 +98377,8 @@ static int lookupName(
pExpr->pLeft = 0;
sqlite3ExprDelete(db, pExpr->pRight);
pExpr->pRight = 0;
- pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN);
+ pExpr->op = eNewExprOp;
+ ExprSetProperty(pExpr, EP_Leaf);
lookupname_end:
if( cnt==1 ){
assert( pNC!=0 );
@@ -88688,17 +98407,24 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
if( p ){
struct SrcList_item *pItem = &pSrc->a[iSrc];
- p->pTab = pItem->pTab;
+ Table *pTab = p->y.pTab = pItem->pTab;
p->iTable = pItem->iCursor;
- if( p->pTab->iPKey==iCol ){
+ if( p->y.pTab->iPKey==iCol ){
p->iColumn = -1;
}else{
p->iColumn = (ynVar)iCol;
- testcase( iCol==BMS );
- testcase( iCol==BMS-1 );
- pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ if( (pTab->tabFlags & TF_HasGenerated)!=0
+ && (pTab->aCol[iCol].colFlags & COLFLAG_GENERATED)!=0
+ ){
+ testcase( pTab->nCol==63 );
+ testcase( pTab->nCol==64 );
+ pItem->colUsed = pTab->nCol>=64 ? ALLBITS : MASKBIT(pTab->nCol)-1;
+ }else{
+ testcase( iCol==BMS );
+ testcase( iCol==BMS-1 );
+ pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ }
}
- ExprSetProperty(p, EP_Resolved);
}
return p;
}
@@ -88706,23 +98432,39 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
/*
** Report an error that an expression is not valid for some set of
** pNC->ncFlags values determined by validMask.
-*/
-static void notValid(
- Parse *pParse, /* Leave error message here */
- NameContext *pNC, /* The name context */
- const char *zMsg, /* Type of error */
- int validMask /* Set of contexts for which prohibited */
-){
- assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 );
- if( (pNC->ncFlags & validMask)!=0 ){
- const char *zIn = "partial index WHERE clauses";
- if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
+**
+** static void notValid(
+** Parse *pParse, // Leave error message here
+** NameContext *pNC, // The name context
+** const char *zMsg, // Type of error
+** int validMask, // Set of contexts for which prohibited
+** Expr *pExpr // Invalidate this expression on error
+** ){...}
+**
+** As an optimization, since the conditional is almost always false
+** (because errors are rare), the conditional is moved outside of the
+** function call using a macro.
+*/
+static void notValidImpl(
+ Parse *pParse, /* Leave error message here */
+ NameContext *pNC, /* The name context */
+ const char *zMsg, /* Type of error */
+ Expr *pExpr /* Invalidate this expression on error */
+){
+ const char *zIn = "partial index WHERE clauses";
+ if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
#ifndef SQLITE_OMIT_CHECK
- else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
+ else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
#endif
- sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
- }
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ else if( pNC->ncFlags & NC_GenCol ) zIn = "generated columns";
+#endif
+ sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
+ if( pExpr ) pExpr->op = TK_NULL;
}
+#define sqlite3ResolveNotValid(P,N,M,X,E) \
+ assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \
+ if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E);
/*
** Expression p should encode a floating point value between 1.0 and 0.0.
@@ -88758,8 +98500,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pParse = pNC->pParse;
assert( pParse==pWalker->pParse );
- if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune;
- ExprSetProperty(pExpr, EP_Resolved);
#ifndef NDEBUG
if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
SrcList *pSrcList = pNC->pSrcList;
@@ -88771,53 +98511,64 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
switch( pExpr->op ){
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
/* The special operator TK_ROW means use the rowid for the first
** column in the FROM clause. This is used by the LIMIT and ORDER BY
- ** clause processing on UPDATE and DELETE statements.
+ ** clause processing on UPDATE and DELETE statements, and by
+ ** UPDATE ... FROM statement processing.
*/
case TK_ROW: {
SrcList *pSrcList = pNC->pSrcList;
struct SrcList_item *pItem;
- assert( pSrcList && pSrcList->nSrc==1 );
- pItem = pSrcList->a;
+ assert( pSrcList && pSrcList->nSrc>=1 );
+ pItem = pSrcList->a;
pExpr->op = TK_COLUMN;
- pExpr->pTab = pItem->pTab;
+ pExpr->y.pTab = pItem->pTab;
pExpr->iTable = pItem->iCursor;
- pExpr->iColumn = -1;
- pExpr->affinity = SQLITE_AFF_INTEGER;
+ pExpr->iColumn--;
+ pExpr->affExpr = SQLITE_AFF_INTEGER;
break;
}
-#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
- && !defined(SQLITE_OMIT_SUBQUERY) */
- /* A lone identifier is the name of a column.
- */
- case TK_ID: {
- return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
- }
-
- /* A table name and column name: ID.ID
+ /* A column name: ID
+ ** Or table name and column name: ID.ID
** Or a database, table and column: ID.ID.ID
+ **
+ ** The TK_ID and TK_OUT cases are combined so that there will only
+ ** be one call to lookupName(). Then the compiler will in-line
+ ** lookupName() for a size reduction and performance increase.
*/
+ case TK_ID:
case TK_DOT: {
const char *zColumn;
const char *zTable;
const char *zDb;
Expr *pRight;
- /* if( pSrcList==0 ) break; */
- notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
- pRight = pExpr->pRight;
- if( pRight->op==TK_ID ){
+ if( pExpr->op==TK_ID ){
zDb = 0;
- zTable = pExpr->pLeft->u.zToken;
- zColumn = pRight->u.zToken;
+ zTable = 0;
+ zColumn = pExpr->u.zToken;
}else{
- assert( pRight->op==TK_DOT );
- zDb = pExpr->pLeft->u.zToken;
- zTable = pRight->pLeft->u.zToken;
- zColumn = pRight->pRight->u.zToken;
+ Expr *pLeft = pExpr->pLeft;
+ testcase( pNC->ncFlags & NC_IdxExpr );
+ testcase( pNC->ncFlags & NC_GenCol );
+ sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator",
+ NC_IdxExpr|NC_GenCol, 0);
+ pRight = pExpr->pRight;
+ if( pRight->op==TK_ID ){
+ zDb = 0;
+ }else{
+ assert( pRight->op==TK_DOT );
+ zDb = pLeft->u.zToken;
+ pLeft = pRight->pLeft;
+ pRight = pRight->pRight;
+ }
+ zTable = pLeft->u.zToken;
+ zColumn = pRight->u.zToken;
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
+ sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft);
+ }
}
return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
}
@@ -88834,7 +98585,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
-
+ int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin));
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
+#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
@@ -88849,7 +98603,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}else{
is_agg = pDef->xFinalize!=0;
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
- ExprSetProperty(pExpr, EP_Unlikely|EP_Skip);
+ ExprSetProperty(pExpr, EP_Unlikely);
if( n==2 ){
pExpr->iTable = exprProbability(pList->a[1].pExpr);
if( pExpr->iTable<0 ){
@@ -88869,7 +98623,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** to likelihood(X,0.9375). */
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120;
- }
+ }
}
#ifndef SQLITE_OMIT_AUTHORIZATION
{
@@ -88888,54 +98642,153 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
/* For the purposes of the EP_ConstFunc flag, date and time
** functions and other functions that change slowly are considered
- ** constant because they are constant for the duration of one query */
+ ** constant because they are constant for the duration of one query.
+ ** This allows them to be factored out of inner loops. */
ExprSetProperty(pExpr,EP_ConstFunc);
}
if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
- /* Date/time functions that use 'now', and other functions like
+ /* Clearly non-deterministic functions like random(), but also
+ ** date/time functions that use 'now', and other functions like
** sqlite_version() that might change over time cannot be used
- ** in an index. */
- notValid(pParse, pNC, "non-deterministic functions",
- NC_IdxExpr|NC_PartIdx);
+ ** in an index or generated column. Curiously, they can be used
+ ** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all
+ ** all this. */
+ sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions",
+ NC_IdxExpr|NC_PartIdx|NC_GenCol, 0);
+ }else{
+ assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
+ pExpr->op2 = pNC->ncFlags & NC_SelfRef;
+ if( pNC->ncFlags & NC_FromDDL ) ExprSetProperty(pExpr, EP_FromDDL);
+ }
+ if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0
+ && pParse->nested==0
+ && (pParse->db->mDbFlags & DBFLAG_InternalFunc)==0
+ ){
+ /* Internal-use-only functions are disallowed unless the
+ ** SQL is being compiled using sqlite3NestedParse() or
+ ** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be
+ ** used to activate internal functionsn for testing purposes */
+ no_such_func = 1;
+ pDef = 0;
+ }else
+ if( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0
+ && !IN_RENAME_OBJECT
+ ){
+ sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
}
}
- if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
- sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
- pNC->nErr++;
- is_agg = 0;
- }else if( no_such_func && pParse->db->init.busy==0
+
+ if( 0==IN_RENAME_OBJECT ){
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
+ || (pDef->xValue==0 && pDef->xInverse==0)
+ || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
+ );
+ if( pDef && pDef->xValue==0 && pWin ){
+ sqlite3ErrorMsg(pParse,
+ "%.*s() may not be used as a window function", nId, zId
+ );
+ pNC->nErr++;
+ }else if(
+ (is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
+ || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin)
+ || (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0)
+ ){
+ const char *zType;
+ if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pWin ){
+ zType = "window";
+ }else{
+ zType = "aggregate";
+ }
+ sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
+ pNC->nErr++;
+ is_agg = 0;
+ }
+#else
+ if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
+ sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId);
+ pNC->nErr++;
+ is_agg = 0;
+ }
+#endif
+ else if( no_such_func && pParse->db->init.busy==0
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
- && pParse->explain==0
+ && pParse->explain==0
+#endif
+ ){
+ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
+ pNC->nErr++;
+ }else if( wrong_num_args ){
+ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
+ nId, zId);
+ pNC->nErr++;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlite3ErrorMsg(pParse,
+ "FILTER may not be used with non-aggregate %.*s()",
+ nId, zId
+ );
+ pNC->nErr++;
+ }
+#endif
+ if( is_agg ){
+ /* Window functions may not be arguments of aggregate functions.
+ ** Or arguments of other window functions. But aggregate functions
+ ** may be arguments for window functions. */
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ pNC->ncFlags &= ~(NC_AllowWin | (!pWin ? NC_AllowAgg : 0));
+#else
+ pNC->ncFlags &= ~NC_AllowAgg;
+#endif
+ }
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ else if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ is_agg = 1;
+ }
#endif
- ){
- sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
- pNC->nErr++;
- }else if( wrong_num_args ){
- sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
- nId, zId);
- pNC->nErr++;
- }
- if( is_agg ) pNC->ncFlags &= ~NC_AllowAgg;
sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
- NameContext *pNC2 = pNC;
- pExpr->op = TK_AGG_FUNCTION;
- pExpr->op2 = 0;
- while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
- pExpr->op2++;
- pNC2 = pNC2->pNext;
- }
- assert( pDef!=0 );
- if( pNC2 ){
- assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
- testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
- pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pWin ){
+ Select *pSel = pNC->pWinSelect;
+ assert( pWin==pExpr->y.pWin );
+ if( IN_RENAME_OBJECT==0 ){
+ sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
+ }
+ sqlite3WalkExprList(pWalker, pWin->pPartition);
+ sqlite3WalkExprList(pWalker, pWin->pOrderBy);
+ sqlite3WalkExpr(pWalker, pWin->pFilter);
+ sqlite3WindowLink(pSel, pWin);
+ pNC->ncFlags |= NC_HasWin;
+ }else
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+ {
+ NameContext *pNC2 = pNC;
+ pExpr->op = TK_AGG_FUNCTION;
+ pExpr->op2 = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
+ }
+#endif
+ while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
+ pExpr->op2++;
+ pNC2 = pNC2->pNext;
+ }
+ assert( pDef!=0 || IN_RENAME_OBJECT );
+ if( pNC2 && pDef ){
+ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
+ testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
+ pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
+ }
}
- pNC->ncFlags |= NC_AllowAgg;
+ pNC->ncFlags |= savedAllowFlags;
}
/* FIX ME: Compute pExpr->affinity based on the expected return
- ** type of the function
+ ** type of the function
*/
return WRC_Prune;
}
@@ -88947,7 +98800,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_IN );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef;
- notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
+ testcase( pNC->ncFlags & NC_IsCheck );
+ testcase( pNC->ncFlags & NC_PartIdx );
+ testcase( pNC->ncFlags & NC_IdxExpr );
+ testcase( pNC->ncFlags & NC_GenCol );
+ sqlite3ResolveNotValid(pParse, pNC, "subqueries",
+ NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
@@ -88958,23 +98816,51 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
break;
}
case TK_VARIABLE: {
- notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
+ testcase( pNC->ncFlags & NC_IsCheck );
+ testcase( pNC->ncFlags & NC_PartIdx );
+ testcase( pNC->ncFlags & NC_IdxExpr );
+ testcase( pNC->ncFlags & NC_GenCol );
+ sqlite3ResolveNotValid(pParse, pNC, "parameters",
+ NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
break;
}
+ case TK_IS:
+ case TK_ISNOT: {
+ Expr *pRight = sqlite3ExprSkipCollateAndLikely(pExpr->pRight);
+ assert( !ExprHasProperty(pExpr, EP_Reduced) );
+ /* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
+ ** and "x IS NOT FALSE". */
+ if( pRight && pRight->op==TK_ID ){
+ int rc = resolveExprStep(pWalker, pRight);
+ if( rc==WRC_Abort ) return WRC_Abort;
+ if( pRight->op==TK_TRUEFALSE ){
+ pExpr->op2 = pExpr->op;
+ pExpr->op = TK_TRUTH;
+ return WRC_Continue;
+ }
+ }
+ /* no break */ deliberate_fall_through
+ }
+ case TK_BETWEEN:
case TK_EQ:
case TK_NE:
case TK_LT:
case TK_LE:
case TK_GT:
- case TK_GE:
- case TK_IS:
- case TK_ISNOT: {
+ case TK_GE: {
int nLeft, nRight;
if( pParse->db->mallocFailed ) break;
- assert( pExpr->pRight!=0 );
assert( pExpr->pLeft!=0 );
nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
- nRight = sqlite3ExprVectorSize(pExpr->pRight);
+ if( pExpr->op==TK_BETWEEN ){
+ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
+ if( nRight==nLeft ){
+ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
+ }
+ }else{
+ assert( pExpr->pRight!=0 );
+ nRight = sqlite3ExprVectorSize(pExpr->pRight);
+ }
if( nLeft!=nRight ){
testcase( pExpr->op==TK_EQ );
testcase( pExpr->op==TK_NE );
@@ -88984,9 +98870,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_GE );
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_ISNOT );
+ testcase( pExpr->op==TK_BETWEEN );
sqlite3ErrorMsg(pParse, "row value misused");
}
- break;
+ break;
}
}
return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
@@ -89016,8 +98903,9 @@ static int resolveAsName(
if( pE->op==TK_ID ){
char *zCol = pE->u.zToken;
for(i=0; i<pEList->nExpr; i++){
- char *zAs = pEList->a[i].zName;
- if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){
+ if( pEList->a[i].eEName==ENAME_NAME
+ && sqlite3_stricmp(pEList->a[i].zEName, zCol)==0
+ ){
return i+1;
}
}
@@ -89063,12 +98951,12 @@ static int resolveOrderByTermToExprList(
memset(&nc, 0, sizeof(nc));
nc.pParse = pParse;
nc.pSrcList = pSelect->pSrc;
- nc.pEList = pEList;
- nc.ncFlags = NC_AllowAgg;
+ nc.uNC.pEList = pEList;
+ nc.ncFlags = NC_AllowAgg|NC_UEList;
nc.nErr = 0;
db = pParse->db;
savedSuppErr = db->suppressErr;
- db->suppressErr = 1;
+ if( IN_RENAME_OBJECT==0 ) db->suppressErr = 1;
rc = sqlite3ResolveExprNames(&nc, pE);
db->suppressErr = savedSuppErr;
if( rc ) return 0;
@@ -89078,7 +98966,7 @@ static int resolveOrderByTermToExprList(
** result-set entry.
*/
for(i=0; i<pEList->nExpr; i++){
- if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){
+ if( sqlite3ExprCompare(0, pEList->a[i].pExpr, pE, -1)<2 ){
return i+1;
}
}
@@ -89096,7 +98984,7 @@ static void resolveOutOfRangeError(
int i, /* The index (1-based) of the term out of range */
int mx /* Largest permissible value of i */
){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"%r %s BY term out of range - should be "
"between 1 and %d", i, zType, mx);
}
@@ -89129,12 +99017,10 @@ static int resolveCompoundOrderBy(
pOrderBy = pSelect->pOrderBy;
if( pOrderBy==0 ) return 0;
db = pParse->db;
-#if SQLITE_MAX_COLUMN
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause");
return 1;
}
-#endif
for(i=0; i<pOrderBy->nExpr; i++){
pOrderBy->a[i].done = 0;
}
@@ -89152,7 +99038,7 @@ static int resolveCompoundOrderBy(
int iCol = -1;
Expr *pE, *pDup;
if( pItem->done ) continue;
- pE = sqlite3ExprSkipCollate(pItem->pExpr);
+ pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol<=0 || iCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
@@ -89161,32 +99047,53 @@ static int resolveCompoundOrderBy(
}else{
iCol = resolveAsName(pParse, pEList, pE);
if( iCol==0 ){
- pDup = sqlite3ExprDup(db, pE, 0);
+ /* Now test if expression pE matches one of the values returned
+ ** by pSelect. In the usual case this is done by duplicating the
+ ** expression, resolving any symbols in it, and then comparing
+ ** it against each expression returned by the SELECT statement.
+ ** Once the comparisons are finished, the duplicate expression
+ ** is deleted.
+ **
+ ** Or, if this is running as part of an ALTER TABLE operation,
+ ** resolve the symbols in the actual expression, not a duplicate.
+ ** And, if one of the comparisons is successful, leave the expression
+ ** as is instead of transforming it to an integer as in the usual
+ ** case. This allows the code in alter.c to modify column
+ ** refererences within the ORDER BY expression as required. */
+ if( IN_RENAME_OBJECT ){
+ pDup = pE;
+ }else{
+ pDup = sqlite3ExprDup(db, pE, 0);
+ }
if( !db->mallocFailed ){
assert(pDup);
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);
}
- sqlite3ExprDelete(db, pDup);
+ if( !IN_RENAME_OBJECT ){
+ sqlite3ExprDelete(db, pDup);
+ }
}
}
if( iCol>0 ){
/* Convert the ORDER BY term into an integer column number iCol,
** taking care to preserve the COLLATE clause if it exists */
- Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
- if( pNew==0 ) return 1;
- pNew->flags |= EP_IntValue;
- pNew->u.iValue = iCol;
- if( pItem->pExpr==pE ){
- pItem->pExpr = pNew;
- }else{
- Expr *pParent = pItem->pExpr;
- assert( pParent->op==TK_COLLATE );
- while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft;
- assert( pParent->pLeft==pE );
- pParent->pLeft = pNew;
+ if( !IN_RENAME_OBJECT ){
+ Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
+ if( pNew==0 ) return 1;
+ pNew->flags |= EP_IntValue;
+ pNew->u.iValue = iCol;
+ if( pItem->pExpr==pE ){
+ pItem->pExpr = pNew;
+ }else{
+ Expr *pParent = pItem->pExpr;
+ assert( pParent->op==TK_COLLATE );
+ while( pParent->pLeft->op==TK_COLLATE ) pParent = pParent->pLeft;
+ assert( pParent->pLeft==pE );
+ pParent->pLeft = pNew;
+ }
+ sqlite3ExprDelete(db, pE);
+ pItem->u.x.iOrderByCol = (u16)iCol;
}
- sqlite3ExprDelete(db, pE);
- pItem->u.x.iOrderByCol = (u16)iCol;
pItem->done = 1;
}else{
moreToDo = 1;
@@ -89225,13 +99132,11 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
ExprList *pEList;
struct ExprList_item *pItem;
- if( pOrderBy==0 || pParse->db->mallocFailed ) return 0;
-#if SQLITE_MAX_COLUMN
+ if( pOrderBy==0 || pParse->db->mallocFailed || IN_RENAME_OBJECT ) return 0;
if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many terms in %s BY clause", zType);
return 1;
}
-#endif
pEList = pSelect->pEList;
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
@@ -89247,6 +99152,36 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
return 0;
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Walker callback for windowRemoveExprFromSelect().
+*/
+static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){
+ UNUSED_PARAMETER(pWalker);
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ Window *pWin = pExpr->y.pWin;
+ sqlite3WindowUnlinkFromSelect(pWin);
+ }
+ return WRC_Continue;
+}
+
+/*
+** Remove any Window objects owned by the expression pExpr from the
+** Select.pWin list of Select object pSelect.
+*/
+static void windowRemoveExprFromSelect(Select *pSelect, Expr *pExpr){
+ if( pSelect->pWin ){
+ Walker sWalker;
+ memset(&sWalker, 0, sizeof(Walker));
+ sWalker.xExprCallback = resolveRemoveWindowsCb;
+ sWalker.u.pSelect = pSelect;
+ sqlite3WalkExpr(&sWalker, pExpr);
+ }
+}
+#else
+# define windowRemoveExprFromSelect(a, b)
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
/*
** pOrderBy is an ORDER BY or GROUP BY clause in SELECT statement pSelect.
** The Name context of the SELECT statement is pNC. zType is either
@@ -89282,7 +99217,7 @@ static int resolveOrderGroupBy(
pParse = pNC->pParse;
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
Expr *pE = pItem->pExpr;
- Expr *pE2 = sqlite3ExprSkipCollate(pE);
+ Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
if( zType[0]!='G' ){
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
if( iCol>0 ){
@@ -89312,7 +99247,11 @@ static int resolveOrderGroupBy(
return 1;
}
for(j=0; j<pSelect->pEList->nExpr; j++){
- if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
+ if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
+ /* Since this expresion is being changed into a reference
+ ** to an identical expression in the result set, remove all Window
+ ** objects belonging to the expression from the Select.pWin list. */
+ windowRemoveExprFromSelect(pSelect, pE);
pItem->u.x.iOrderByCol = j+1;
}
}
@@ -89333,7 +99272,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
ExprList *pGroupBy; /* The GROUP BY clause */
Select *pLeftmost; /* Left-most of SELECT of a compound */
sqlite3 *db; /* Database connection */
-
+
assert( p!=0 );
if( p->selFlags & SF_Resolved ){
@@ -89369,8 +99308,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
*/
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
- if( sqlite3ResolveExprNames(&sNC, p->pLimit) ||
- sqlite3ResolveExprNames(&sNC, p->pOffset) ){
+ sNC.pWinSelect = p;
+ if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){
return WRC_Abort;
}
@@ -89387,12 +99326,12 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
pSub->pOrderBy = p->pOrderBy;
p->pOrderBy = 0;
}
-
+
/* Recursively resolve names in all subqueries
*/
for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i];
- if( pItem->pSelect ){
+ if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
NameContext *pNC; /* Used to iterate name contexts */
int nRef = 0; /* Refcount for pOuterNC and outer contexts */
const char *zSavedContext = pParse->zAuthContext;
@@ -89414,18 +99353,19 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
pItem->fg.isCorrelated = (nRef!=0);
}
}
-
+
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
*/
- sNC.ncFlags = NC_AllowAgg;
+ sNC.ncFlags = NC_AllowAgg|NC_AllowWin;
sNC.pSrcList = p->pSrc;
sNC.pNext = pOuterNC;
-
+
/* Resolve names in the result set. */
if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort;
-
- /* If there are no aggregate functions in the result-set, and no GROUP BY
+ sNC.ncFlags &= ~NC_AllowWin;
+
+ /* If there are no aggregate functions in the result-set, and no GROUP BY
** expression, do not allow aggregates in any of the other expressions.
*/
assert( (p->selFlags & SF_Aggregate)==0 );
@@ -89436,14 +99376,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}else{
sNC.ncFlags &= ~NC_AllowAgg;
}
-
+
/* If a HAVING clause is present, then there must be a GROUP BY clause.
*/
if( p->pHaving && !pGroupBy ){
sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
return WRC_Abort;
}
-
+
/* Add the output column list to the name-context before parsing the
** other expressions in the SELECT statement. This is so that
** expressions in the WHERE clause (etc.) can refer to expressions by
@@ -89452,7 +99392,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** Minor point: If this is the case, then the expression will be
** re-evaluated for each reference to it.
*/
- sNC.pEList = p->pEList;
+ assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert))==0 );
+ sNC.uNC.pEList = p->pEList;
+ sNC.ncFlags |= NC_UEList;
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
@@ -89460,19 +99402,19 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
for(i=0; i<p->pSrc->nSrc; i++){
struct SrcList_item *pItem = &p->pSrc->a[i];
if( pItem->fg.isTabFunc
- && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
+ && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
){
return WRC_Abort;
}
}
/* The ORDER BY and GROUP BY clauses may not refer to terms in
- ** outer queries
+ ** outer queries
*/
sNC.pNext = 0;
- sNC.ncFlags |= NC_AllowAgg;
+ sNC.ncFlags |= NC_AllowAgg|NC_AllowWin;
- /* If this is a converted compound query, move the ORDER BY clause from
+ /* If this is a converted compound query, move the ORDER BY clause from
** the sub-query back to the parent query. At this point each term
** within the ORDER BY clause has been transformed to an integer value.
** These integers will be replaced by copies of the corresponding result
@@ -89501,13 +99443,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
if( db->mallocFailed ){
return WRC_Abort;
}
-
- /* Resolve the GROUP BY clause. At the same time, make sure
+ sNC.ncFlags &= ~NC_AllowWin;
+
+ /* Resolve the GROUP BY clause. At the same time, make sure
** the GROUP BY clause does not contain aggregate functions.
*/
if( pGroupBy ){
struct ExprList_item *pItem;
-
+
if( resolveOrderGroupBy(&sNC, p, pGroupBy, "GROUP") || db->mallocFailed ){
return WRC_Abort;
}
@@ -89520,6 +99463,19 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( IN_RENAME_OBJECT ){
+ Window *pWin;
+ for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){
+ if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy)
+ || sqlite3ResolveExprListNames(&sNC, pWin->pPartition)
+ ){
+ return WRC_Abort;
+ }
+ }
+ }
+#endif
+
/* If this is part of a compound SELECT, check that it has the right
** number of expressions in the select list. */
if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){
@@ -89549,7 +99505,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** checking on function usage and set a flag if any aggregate functions
** are seen.
**
-** To resolve table columns references we look for nodes (or subtrees) of the
+** To resolve table columns references we look for nodes (or subtrees) of the
** form X.Y.Z or Y.Z or just Z where
**
** X: The name of a database. Ex: "main" or "temp" or
@@ -89581,7 +99537,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
**
** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY a+b;
**
-** Function calls are checked to make sure that the function is
+** Function calls are checked to make sure that the function is
** defined and that the correct number of arguments are specified.
** If the function is an aggregate function, then the NC_HasAgg flag is
** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION.
@@ -89591,44 +99547,38 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** An error message is left in pParse if anything is amiss. The number
** if errors is returned.
*/
-SQLITE_PRIVATE int sqlite3ResolveExprNames(
+SQLITE_PRIVATE int sqlite3ResolveExprNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
Expr *pExpr /* The expression to be analyzed. */
){
- u16 savedHasAgg;
+ int savedHasAgg;
Walker w;
- if( pExpr==0 ) return 0;
-#if SQLITE_MAX_EXPR_DEPTH>0
- {
- Parse *pParse = pNC->pParse;
- if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){
- return 1;
- }
- pParse->nHeight += pExpr->nHeight;
- }
-#endif
- savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
- pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
+ if( pExpr==0 ) return SQLITE_OK;
+ savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
w.pParse = pNC->pParse;
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
w.xSelectCallback2 = 0;
- w.walkerDepth = 0;
- w.eCode = 0;
w.u.pNC = pNC;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ w.pParse->nHeight += pExpr->nHeight;
+ if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
+ return SQLITE_ERROR;
+ }
+#endif
sqlite3WalkExpr(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
- pNC->pParse->nHeight -= pExpr->nHeight;
+ w.pParse->nHeight -= pExpr->nHeight;
#endif
- if( pNC->nErr>0 || w.pParse->nErr>0 ){
- ExprSetProperty(pExpr, EP_Error);
- }
- if( pNC->ncFlags & NC_HasAgg ){
- ExprSetProperty(pExpr, EP_Agg);
- }
+ assert( EP_Agg==NC_HasAgg );
+ assert( EP_Win==NC_HasWin );
+ testcase( pNC->ncFlags & NC_HasAgg );
+ testcase( pNC->ncFlags & NC_HasWin );
+ ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
pNC->ncFlags |= savedHasAgg;
- return ExprHasProperty(pExpr, EP_Error);
+ return pNC->nErr>0 || w.pParse->nErr>0;
}
/*
@@ -89636,16 +99586,46 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
** just like sqlite3ResolveExprNames() except that it works for an expression
** list rather than a single expression.
*/
-SQLITE_PRIVATE int sqlite3ResolveExprListNames(
+SQLITE_PRIVATE int sqlite3ResolveExprListNames(
NameContext *pNC, /* Namespace to resolve expressions in. */
ExprList *pList /* The expression list to be analyzed. */
){
int i;
- if( pList ){
- for(i=0; i<pList->nExpr; i++){
- if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
+ int savedHasAgg = 0;
+ Walker w;
+ if( pList==0 ) return WRC_Continue;
+ w.pParse = pNC->pParse;
+ w.xExprCallback = resolveExprStep;
+ w.xSelectCallback = resolveSelectStep;
+ w.xSelectCallback2 = 0;
+ w.u.pNC = pNC;
+ savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ if( pExpr==0 ) continue;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ w.pParse->nHeight += pExpr->nHeight;
+ if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
+ return WRC_Abort;
+ }
+#endif
+ sqlite3WalkExpr(&w, pExpr);
+#if SQLITE_MAX_EXPR_DEPTH>0
+ w.pParse->nHeight -= pExpr->nHeight;
+#endif
+ assert( EP_Agg==NC_HasAgg );
+ assert( EP_Win==NC_HasWin );
+ testcase( pNC->ncFlags & NC_HasAgg );
+ testcase( pNC->ncFlags & NC_HasWin );
+ if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin) ){
+ ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
+ savedHasAgg |= pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
}
+ if( pNC->nErr>0 || w.pParse->nErr>0 ) return WRC_Abort;
}
+ pNC->ncFlags |= savedHasAgg;
return WRC_Continue;
}
@@ -89669,47 +99649,65 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
Walker w;
assert( p!=0 );
- memset(&w, 0, sizeof(w));
w.xExprCallback = resolveExprStep;
w.xSelectCallback = resolveSelectStep;
+ w.xSelectCallback2 = 0;
w.pParse = pParse;
w.u.pNC = pOuterNC;
sqlite3WalkSelect(&w, p);
}
/*
-** Resolve names in expressions that can only reference a single table:
+** Resolve names in expressions that can only reference a single table
+** or which cannot reference any tables at all. Examples:
**
-** * CHECK constraints
-** * WHERE clauses on partial indices
+** "type" flag
+** ------------
+** (1) CHECK constraints NC_IsCheck
+** (2) WHERE clauses on partial indices NC_PartIdx
+** (3) Expressions in indexes on expressions NC_IdxExpr
+** (4) Expression arguments to VACUUM INTO. 0
+** (5) GENERATED ALWAYS as expressions NC_GenCol
**
-** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression
-** is set to -1 and the Expr.iColumn value is set to the column number.
+** In all cases except (4), the Expr.iTable value for Expr.op==TK_COLUMN
+** nodes of the expression is set to -1 and the Expr.iColumn value is
+** set to the column number. In case (4), TK_COLUMN nodes cause an error.
**
** Any errors cause an error message to be set in pParse.
*/
-SQLITE_PRIVATE void sqlite3ResolveSelfReference(
- Parse *pParse, /* Parsing context */
- Table *pTab, /* The table being referenced */
- int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */
- Expr *pExpr, /* Expression to resolve. May be NULL. */
- ExprList *pList /* Expression list to resolve. May be NUL. */
+SQLITE_PRIVATE int sqlite3ResolveSelfReference(
+ Parse *pParse, /* Parsing context */
+ Table *pTab, /* The table being referenced, or NULL */
+ int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */
+ Expr *pExpr, /* Expression to resolve. May be NULL. */
+ ExprList *pList /* Expression list to resolve. May be NULL. */
){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
+ int rc;
- assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr );
+ assert( type==0 || pTab!=0 );
+ assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr
+ || type==NC_GenCol || pTab==0 );
memset(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc));
- sSrc.nSrc = 1;
- sSrc.a[0].zName = pTab->zName;
- sSrc.a[0].pTab = pTab;
- sSrc.a[0].iCursor = -1;
+ if( pTab ){
+ sSrc.nSrc = 1;
+ sSrc.a[0].zName = pTab->zName;
+ sSrc.a[0].pTab = pTab;
+ sSrc.a[0].iCursor = -1;
+ if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
+ /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
+ ** schema elements */
+ type |= NC_FromDDL;
+ }
+ }
sNC.pParse = pParse;
sNC.pSrcList = &sSrc;
- sNC.ncFlags = type;
- if( sqlite3ResolveExprNames(&sNC, pExpr) ) return;
- if( pList ) sqlite3ResolveExprListNames(&sNC, pList);
+ sNC.ncFlags = type | NC_IsDDL;
+ if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
+ if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
+ return rc;
}
/************** End of resolve.c *********************************************/
@@ -89746,7 +99744,7 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
** Return the 'affinity' of the expression pExpr if any.
**
** If pExpr is a column, a reference to a column via an 'AS' alias,
-** or a sub-select with a column as the return value, then the
+** or a sub-select with a column as the return value, then the
** affinity of that column is returned. Otherwise, 0x00 is returned,
** indicating no affinity for the expression.
**
@@ -89758,13 +99756,19 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
** SELECT a AS b FROM t1 WHERE b;
** SELECT * FROM t1 WHERE (select a from t1);
*/
-SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
+SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
int op;
- pExpr = sqlite3ExprSkipCollate(pExpr);
- if( pExpr->flags & EP_Generic ) return 0;
+ while( ExprHasProperty(pExpr, EP_Skip) ){
+ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
+ pExpr = pExpr->pLeft;
+ assert( pExpr!=0 );
+ }
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
+ assert( pExpr->x.pSelect!=0 );
+ assert( pExpr->x.pSelect->pEList!=0 );
+ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
if( op==TK_REGISTER ) op = pExpr->op2;
@@ -89774,8 +99778,8 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
return sqlite3AffinityType(pExpr->u.zToken, 0);
}
#endif
- if( op==TK_AGG_COLUMN || op==TK_COLUMN ){
- return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){
+ return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
}
if( op==TK_SELECT_COLUMN ){
assert( pExpr->pLeft->flags&EP_xIsSelect );
@@ -89783,7 +99787,10 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
);
}
- return pExpr->affinity;
+ if( op==TK_VECTOR ){
+ return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
+ }
+ return pExpr->affExpr;
}
/*
@@ -89818,21 +99825,33 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con
}
/*
-** Skip over any TK_COLLATE operators and any unlikely()
-** or likelihood() function at the root of an expression.
+** Skip over any TK_COLLATE operators.
*/
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
+ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
+ pExpr = pExpr->pLeft;
+ }
+ return pExpr;
+}
+
+/*
+** Skip over any TK_COLLATE operators and/or any unlikely()
+** or likelihood() or likely() functions at the root of an
+** expression.
+*/
+SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
+ while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){
if( ExprHasProperty(pExpr, EP_Unlikely) ){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
assert( pExpr->x.pList->nExpr>0 );
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
}else{
- assert( pExpr->op==TK_COLLATE );
+ assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
pExpr = pExpr->pLeft;
}
- }
+ }
return pExpr;
}
@@ -89840,39 +99859,47 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return NULL.
**
+** See also: sqlite3ExprNNCollSeq()
+**
+** The sqlite3ExprNNCollSeq() works the same exact that it returns the
+** default collation if pExpr has no defined collation.
+**
** The collating sequence might be determined by a COLLATE operator
** or by the presence of a column with a defined collating sequence.
** COLLATE operators take first precedence. Left operands take
** precedence over right operands.
*/
-SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
+SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
sqlite3 *db = pParse->db;
CollSeq *pColl = 0;
- Expr *p = pExpr;
+ const Expr *p = pExpr;
while( p ){
int op = p->op;
- if( p->flags & EP_Generic ) break;
- if( op==TK_CAST || op==TK_UPLUS ){
- p = p->pLeft;
- continue;
- }
- if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
- pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
- break;
- }
- if( (op==TK_AGG_COLUMN || op==TK_COLUMN
- || op==TK_REGISTER || op==TK_TRIGGER)
- && p->pTab!=0
+ if( op==TK_REGISTER ) op = p->op2;
+ if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
+ && p->y.pTab!=0
){
- /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
+ /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
** a TK_COLUMN but was previously evaluated and cached in a register */
int j = p->iColumn;
if( j>=0 ){
- const char *zColl = p->pTab->aCol[j].zColl;
+ const char *zColl = p->y.pTab->aCol[j].zColl;
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
}
break;
}
+ if( op==TK_CAST || op==TK_UPLUS ){
+ p = p->pLeft;
+ continue;
+ }
+ if( op==TK_VECTOR ){
+ p = p->x.pList->a[0].pExpr;
+ continue;
+ }
+ if( op==TK_COLLATE ){
+ pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
+ break;
+ }
if( p->flags & EP_Collate ){
if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
p = p->pLeft;
@@ -89880,10 +99907,10 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
- /* p->flags holds EP_Collate and p->pLeft->flags does not. And
- ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at
- ** least one EP_Collate. Thus the following two ALWAYS. */
- if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){
+ if( p->x.pList!=0
+ && !db->mallocFailed
+ && ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
+ ){
int i;
for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
@@ -89898,20 +99925,46 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
break;
}
}
- if( sqlite3CheckCollSeq(pParse, pColl) ){
+ if( sqlite3CheckCollSeq(pParse, pColl) ){
pColl = 0;
}
return pColl;
}
/*
+** Return the collation sequence for the expression pExpr. If
+** there is no defined collating sequence, return a pointer to the
+** defautl collation sequence.
+**
+** See also: sqlite3ExprCollSeq()
+**
+** The sqlite3ExprCollSeq() routine works the same except that it
+** returns NULL if there is no defined collation.
+*/
+SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){
+ CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
+ if( p==0 ) p = pParse->db->pDfltColl;
+ assert( p!=0 );
+ return p;
+}
+
+/*
+** Return TRUE if the two expressions have equivalent collating sequences.
+*/
+SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){
+ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
+ CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
+ return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
+}
+
+/*
** pExpr is an operand of a comparison operator. aff2 is the
** type affinity of the other operand. This routine returns the
** type affinity that should be used for the comparison operator.
*/
-SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
+SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2){
char aff1 = sqlite3ExprAffinity(pExpr);
- if( aff1 && aff2 ){
+ if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){
/* Both sides of the comparison are columns. If one has numeric
** affinity, use that. Otherwise use no affinity.
*/
@@ -89920,15 +99973,10 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
}else{
return SQLITE_AFF_BLOB;
}
- }else if( !aff1 && !aff2 ){
- /* Neither side of the comparison is a column. Compare the
- ** results directly.
- */
- return SQLITE_AFF_BLOB;
}else{
/* One side is a column, the other is not. Use the columns affinity. */
- assert( aff1==0 || aff2==0 );
- return (aff1 + aff2);
+ assert( aff1<=SQLITE_AFF_NONE || aff2<=SQLITE_AFF_NONE );
+ return (aff1<=SQLITE_AFF_NONE ? aff2 : aff1) | SQLITE_AFF_NONE;
}
}
@@ -89936,7 +99984,7 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
** pExpr is a comparison operator. Return the type affinity that should
** be applied to both operands prior to doing the comparison.
*/
-static char comparisonAffinity(Expr *pExpr){
+static char comparisonAffinity(const Expr *pExpr){
char aff;
assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
@@ -89947,7 +99995,7 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
- }else if( NEVER(aff==0) ){
+ }else if( aff==0 ){
aff = SQLITE_AFF_BLOB;
}
return aff;
@@ -89959,23 +100007,26 @@ static char comparisonAffinity(Expr *pExpr){
** if the index with affinity idx_affinity may be used to implement
** the comparison in pExpr.
*/
-SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
+SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){
char aff = comparisonAffinity(pExpr);
- switch( aff ){
- case SQLITE_AFF_BLOB:
- return 1;
- case SQLITE_AFF_TEXT:
- return idx_affinity==SQLITE_AFF_TEXT;
- default:
- return sqlite3IsNumericAffinity(idx_affinity);
+ if( aff<SQLITE_AFF_TEXT ){
+ return 1;
+ }
+ if( aff==SQLITE_AFF_TEXT ){
+ return idx_affinity==SQLITE_AFF_TEXT;
}
+ return sqlite3IsNumericAffinity(idx_affinity);
}
/*
** Return the P5 value that should be used for a binary comparison
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
*/
-static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
+static u8 binaryCompareP5(
+ const Expr *pExpr1, /* Left operand */
+ const Expr *pExpr2, /* Right operand */
+ int jumpIfNull /* Extra flags added to P5 */
+){
u8 aff = (char)sqlite3ExprAffinity(pExpr2);
aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull;
return aff;
@@ -89994,9 +100045,9 @@ static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
** it is not considered.
*/
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
- Parse *pParse,
- Expr *pLeft,
- Expr *pRight
+ Parse *pParse,
+ const Expr *pLeft,
+ const Expr *pRight
){
CollSeq *pColl;
assert( pLeft );
@@ -90013,6 +100064,22 @@ SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
return pColl;
}
+/* Expresssion p is a comparison operator. Return a collation sequence
+** appropriate for the comparison operator.
+**
+** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
+** However, if the OP_Commuted flag is set, then the order of the operands
+** is reversed in the sqlite3BinaryCompareCollSeq() call so that the
+** correct collating sequence is found.
+*/
+SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, const Expr *p){
+ if( ExprHasProperty(p, EP_Commuted) ){
+ return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft);
+ }else{
+ return sqlite3BinaryCompareCollSeq(pParse, p->pLeft, p->pRight);
+ }
+}
+
/*
** Generate code for a comparison operator.
*/
@@ -90023,13 +100090,19 @@ static int codeCompare(
int opcode, /* The comparison opcode */
int in1, int in2, /* Register holding operands */
int dest, /* Jump here if true. */
- int jumpIfNull /* If true, jump if either operand is NULL */
+ int jumpIfNull, /* If true, jump if either operand is NULL */
+ int isCommuted /* The comparison has been commuted */
){
int p5;
int addr;
CollSeq *p4;
- p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
+ if( pParse->nErr ) return 0;
+ if( isCommuted ){
+ p4 = sqlite3BinaryCompareCollSeq(pParse, pRight, pLeft);
+ }else{
+ p4 = sqlite3BinaryCompareCollSeq(pParse, pLeft, pRight);
+ }
p5 = binaryCompareP5(pLeft, pRight, jumpIfNull);
addr = sqlite3VdbeAddOp4(pParse->pVdbe, opcode, in2, dest, in1,
(void*)p4, P4_COLLSEQ);
@@ -90051,7 +100124,7 @@ SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){
}
/*
-** If the expression passed as the only argument is of type TK_VECTOR
+** If the expression passed as the only argument is of type TK_VECTOR
** return the number of expressions in the vector. Or, if the expression
** is a sub-select, return the number of columns in the sub-select. For
** any other type of expression, return 1.
@@ -90068,7 +100141,6 @@ SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
}
}
-#ifndef SQLITE_OMIT_SUBQUERY
/*
** Return a pointer to a subexpression of pVector that is the i-th
** column of the vector (numbered starting with 0). The caller must
@@ -90096,15 +100168,13 @@ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
}
return pVector;
}
-#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
-#ifndef SQLITE_OMIT_SUBQUERY
/*
** Compute and return a new Expr object which when passed to
** sqlite3ExprCode() will generate all necessary code to compute
** the iField-th column of the vector expression pVector.
**
-** It is ok for pVector to be a scalar (as long as iField==0).
+** It is ok for pVector to be a scalar (as long as iField==0).
** In that case, this routine works like sqlite3ExprDup().
**
** The caller owns the returned Expr object and is responsible for
@@ -90130,9 +100200,10 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
assert( pVector->flags & EP_xIsSelect );
/* The TK_SELECT_COLUMN Expr node:
**
- ** pLeft: pVector containing TK_SELECT
+ ** pLeft: pVector containing TK_SELECT. Not deleted.
** pRight: not used. But recursively deleted.
** iColumn: Index of a column in pVector
+ ** iTable: 0 or the number of columns on the LHS of an assignment
** pLeft->iTable: First in an array of register holding result, or 0
** if the result is not yet computed.
**
@@ -90143,7 +100214,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
** with the same pLeft pointer to the pVector, but only one of them
** will own the pVector.
*/
- pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0, 0);
+ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
if( pRet ){
pRet->iColumn = iField;
pRet->pLeft = pVector;
@@ -90152,14 +100223,14 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
}else{
if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
pRet = sqlite3ExprDup(pParse->db, pVector, 0);
+ sqlite3RenameTokenRemap(pParse, pRet, pVector);
}
return pRet;
}
-#endif /* !define(SQLITE_OMIT_SUBQUERY) */
/*
** If expression pExpr is of type TK_SELECT, generate code to evaluate
-** it. Return the register in which the result is stored (or, if the
+** it. Return the register in which the result is stored (or, if the
** sub-select returns more than one column, the first in an array
** of registers in which the result is stored).
**
@@ -90169,7 +100240,7 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
int reg = 0;
#ifndef SQLITE_OMIT_SUBQUERY
if( pExpr->op==TK_SELECT ){
- reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ reg = sqlite3CodeSubselect(pParse, pExpr);
}
#endif
return reg;
@@ -90181,10 +100252,10 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
** the register number of a register that contains the value of
** element iField of the vector.
**
-** If pVector is a TK_SELECT expression, then code for it must have
+** If pVector is a TK_SELECT expression, then code for it must have
** already been generated using the exprCodeSubselect() routine. In this
** case parameter regSelect should be the first in an array of registers
-** containing the results of the sub-select.
+** containing the results of the sub-select.
**
** If pVector is of type TK_VECTOR, then code for the requested field
** is generated. In this case (*pRegFree) may be set to the number of
@@ -90241,13 +100312,19 @@ static void codeVectorCompare(
int regLeft = 0;
int regRight = 0;
u8 opx = op;
- int addrDone = sqlite3VdbeMakeLabel(v);
+ int addrDone = sqlite3VdbeMakeLabel(pParse);
+ int isCommuted = ExprHasProperty(pExpr,EP_Commuted);
- assert( nLeft==sqlite3ExprVectorSize(pRight) );
- assert( pExpr->op==TK_EQ || pExpr->op==TK_NE
- || pExpr->op==TK_IS || pExpr->op==TK_ISNOT
- || pExpr->op==TK_LT || pExpr->op==TK_GT
- || pExpr->op==TK_LE || pExpr->op==TK_GE
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
+ if( pParse->nErr ) return;
+ if( nLeft!=sqlite3ExprVectorSize(pRight) ){
+ sqlite3ErrorMsg(pParse, "row value misused");
+ return;
+ }
+ assert( pExpr->op==TK_EQ || pExpr->op==TK_NE
+ || pExpr->op==TK_IS || pExpr->op==TK_ISNOT
+ || pExpr->op==TK_LT || pExpr->op==TK_GT
+ || pExpr->op==TK_LE || pExpr->op==TK_GE
);
assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ)
|| (pExpr->op==TK_ISNOT && op==TK_NE) );
@@ -90263,13 +100340,12 @@ static void codeVectorCompare(
for(i=0; 1 /*Loop exits by "break"*/; i++){
int regFree1 = 0, regFree2 = 0;
- Expr *pL, *pR;
+ Expr *pL, *pR;
int r1, r2;
assert( i>=0 && i<nLeft );
- if( i>0 ) sqlite3ExprCachePush(pParse);
r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, &regFree1);
r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, &regFree2);
- codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5);
+ codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5, isCommuted);
testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -90278,7 +100354,6 @@ static void codeVectorCompare(
testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
sqlite3ReleaseTempReg(pParse, regFree1);
sqlite3ReleaseTempReg(pParse, regFree2);
- if( i>0 ) sqlite3ExprCachePop(pParse);
if( i==nLeft-1 ){
break;
}
@@ -90311,7 +100386,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){
int rc = SQLITE_OK;
int mxHeight = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH];
if( nHeight>mxHeight ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"Expression tree is too large (maximum depth %d)", mxHeight
);
rc = SQLITE_ERROR;
@@ -90343,24 +100418,23 @@ static void heightOfExprList(ExprList *p, int *pnHeight){
}
}
}
-static void heightOfSelect(Select *p, int *pnHeight){
- if( p ){
+static void heightOfSelect(Select *pSelect, int *pnHeight){
+ Select *p;
+ for(p=pSelect; p; p=p->pPrior){
heightOfExpr(p->pWhere, pnHeight);
heightOfExpr(p->pHaving, pnHeight);
heightOfExpr(p->pLimit, pnHeight);
- heightOfExpr(p->pOffset, pnHeight);
heightOfExprList(p->pEList, pnHeight);
heightOfExprList(p->pGroupBy, pnHeight);
heightOfExprList(p->pOrderBy, pnHeight);
- heightOfSelect(p->pPrior, pnHeight);
}
}
/*
-** Set the Expr.nHeight variable in the structure passed as an
-** argument. An expression with no children, Expr.pList or
+** Set the Expr.nHeight variable in the structure passed as an
+** argument. An expression with no children, Expr.pList or
** Expr.pSelect member has a height of 1. Any other expression
-** has a height equal to the maximum height of any other
+** has a height equal to the maximum height of any other
** referenced Expr plus one.
**
** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
@@ -90385,7 +100459,7 @@ static void exprSetHeight(Expr *p){
** leave an error in pParse.
**
** Also propagate all EP_Propagate flags from the Expr.x.pList into
-** Expr.flags.
+** Expr.flags.
*/
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
if( pParse->nErr ) return;
@@ -90405,7 +100479,7 @@ SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){
#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */
/*
** Propagate all EP_Propagate flags from the Expr.x.pList into
-** Expr.flags.
+** Expr.flags.
*/
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
@@ -90460,7 +100534,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
pNew->iAgg = -1;
if( pToken ){
if( nExtra==0 ){
- pNew->flags |= EP_IntValue;
+ pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse);
pNew->u.iValue = iValue;
}else{
pNew->u.zToken = (char*)&pNew[1];
@@ -90468,14 +100542,13 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
pNew->u.zToken[pToken->n] = 0;
if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
- if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
- sqlite3Dequote(pNew->u.zToken);
+ sqlite3DequoteExpr(pNew);
}
}
}
#if SQLITE_MAX_EXPR_DEPTH>0
pNew->nHeight = 1;
-#endif
+#endif
}
return pNew;
}
@@ -90491,7 +100564,7 @@ SQLITE_PRIVATE Expr *sqlite3Expr(
){
Token x;
x.z = zToken;
- x.n = zToken ? sqlite3Strlen30(zToken) : 0;
+ x.n = sqlite3Strlen30(zToken);
return sqlite3ExprAlloc(db, op, &x, 0);
}
@@ -90535,19 +100608,19 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
Parse *pParse, /* Parsing context */
int op, /* Expression opcode */
Expr *pLeft, /* Left operand */
- Expr *pRight, /* Right operand */
- const Token *pToken /* Argument token */
+ Expr *pRight /* Right operand */
){
Expr *p;
- if( op==TK_AND && pParse->nErr==0 ){
- /* Take advantage of short-circuit false optimization for AND */
- p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
- }else{
- p = sqlite3ExprAlloc(pParse->db, op & TKFLG_MASK, pToken, 1);
+ p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr));
+ if( p ){
+ memset(p, 0, sizeof(Expr));
+ p->op = op & 0xff;
+ p->iAgg = -1;
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
- }
- if( p ) {
sqlite3ExprCheckHeight(pParse, p->nHeight);
+ }else{
+ sqlite3ExprDelete(pParse->db, pLeft);
+ sqlite3ExprDelete(pParse->db, pRight);
}
return p;
}
@@ -90569,33 +100642,6 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pS
/*
-** If the expression is always either TRUE or FALSE (respectively),
-** then return 1. If one cannot determine the truth value of the
-** expression at compile-time return 0.
-**
-** This is an optimization. If is OK to return 0 here even if
-** the expression really is always false or false (a false negative).
-** But it is a bug to return 1 if the expression might have different
-** boolean values in different circumstances (a false positive.)
-**
-** Note that if the expression is part of conditional for a
-** LEFT JOIN, then we cannot determine at compile-time whether or not
-** is it true or false, so always return 0.
-*/
-static int exprAlwaysTrue(Expr *p){
- int v = 0;
- if( ExprHasProperty(p, EP_FromJoin) ) return 0;
- if( !sqlite3ExprIsInteger(p, &v) ) return 0;
- return v!=0;
-}
-static int exprAlwaysFalse(Expr *p){
- int v = 0;
- if( ExprHasProperty(p, EP_FromJoin) ) return 0;
- if( !sqlite3ExprIsInteger(p, &v) ) return 0;
- return v==0;
-}
-
-/*
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
**
@@ -90603,19 +100649,20 @@ static int exprAlwaysFalse(Expr *p){
** of returning an AND expression, just return a constant expression with
** a value of false.
*/
-SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
- if( pLeft==0 ){
+SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
+ sqlite3 *db = pParse->db;
+ if( pLeft==0 ){
return pRight;
}else if( pRight==0 ){
return pLeft;
- }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){
+ }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
+ && !IN_RENAME_OBJECT
+ ){
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
- return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0);
+ return sqlite3Expr(db, TK_INTEGER, "0");
}else{
- Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0);
- sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight);
- return pNew;
+ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
}
}
@@ -90623,7 +100670,12 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
** Construct a new expression node for a function with multiple
** arguments.
*/
-SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
+SQLITE_PRIVATE Expr *sqlite3ExprFunction(
+ Parse *pParse, /* Parsing context */
+ ExprList *pList, /* Argument list */
+ Token *pToken, /* Name of the function */
+ int eDistinct /* SF_Distinct or SF_ALL or 0 */
+){
Expr *pNew;
sqlite3 *db = pParse->db;
assert( pToken );
@@ -90632,21 +100684,60 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
return 0;
}
+ if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
+ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
+ }
pNew->x.pList = pList;
+ ExprSetProperty(pNew, EP_HasFunc);
assert( !ExprHasProperty(pNew, EP_xIsSelect) );
sqlite3ExprSetHeightAndFlags(pParse, pNew);
+ if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
return pNew;
}
/*
+** Check to see if a function is usable according to current access
+** rules:
+**
+** SQLITE_FUNC_DIRECT - Only usable from top-level SQL
+**
+** SQLITE_FUNC_UNSAFE - Usable if TRUSTED_SCHEMA or from
+** top-level SQL
+**
+** If the function is not usable, create an error.
+*/
+SQLITE_PRIVATE void sqlite3ExprFunctionUsable(
+ Parse *pParse, /* Parsing and code generating context */
+ Expr *pExpr, /* The function invocation */
+ FuncDef *pDef /* The function being invoked */
+){
+ assert( !IN_RENAME_OBJECT );
+ assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
+ if( ExprHasProperty(pExpr, EP_FromDDL) ){
+ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
+ || (pParse->db->flags & SQLITE_TrustedSchema)==0
+ ){
+ /* Functions prohibited in triggers and views if:
+ ** (1) tagged with SQLITE_DIRECTONLY
+ ** (2) not tagged with SQLITE_INNOCUOUS (which means it
+ ** is tagged with SQLITE_FUNC_UNSAFE) and
+ ** SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning
+ ** that the schema is possibly tainted).
+ */
+ sqlite3ErrorMsg(pParse, "unsafe use of %s()", pDef->zName);
+ }
+ }
+}
+
+/*
** Assign a variable number to an expression that encodes a wildcard
-** in the original SQL statement.
+** in the original SQL statement.
**
** Wildcards consisting of a single "?" are assigned the next sequential
** variable number.
**
** Wildcards of the form "?nnn" are assigned the number "nnn". We make
-** sure "nnn" is not too be to avoid a denial of service attack when
+** sure "nnn" is not too big to avoid a denial of service attack when
** the SQL statement comes from an external source.
**
** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number
@@ -90657,25 +100748,31 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
sqlite3 *db = pParse->db;
const char *z;
+ ynVar x;
if( pExpr==0 ) return;
assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
z = pExpr->u.zToken;
assert( z!=0 );
assert( z[0]!=0 );
- assert( n==sqlite3Strlen30(z) );
+ assert( n==(u32)sqlite3Strlen30(z) );
if( z[1]==0 ){
/* Wildcard of the form "?". Assign the next variable number */
assert( z[0]=='?' );
- pExpr->iColumn = (ynVar)(++pParse->nVar);
+ x = (ynVar)(++pParse->nVar);
}else{
- ynVar x;
+ int doAdd = 0;
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);
- x = (ynVar)i;
+ int bOk;
+ if( n==2 ){ /*OPTIMIZATION-IF-TRUE*/
+ i = z[1]-'0'; /* The common case of ?N for a single digit N */
+ bOk = 1;
+ }else{
+ bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
+ }
testcase( i==0 );
testcase( i==1 );
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
@@ -90685,40 +100782,30 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
return;
}
- if( i>pParse->nVar ){
- pParse->nVar = (int)i;
+ x = (ynVar)i;
+ if( x>pParse->nVar ){
+ pParse->nVar = (int)x;
+ doAdd = 1;
+ }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){
+ doAdd = 1;
}
}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=x=0; i<pParse->nzVar; i++){
- if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
- x = (ynVar)i+1;
- break;
- }
- }
- if( x==0 ) x = (ynVar)(++pParse->nVar);
- }
- pExpr->iColumn = x;
- if( x>pParse->nzVar ){
- char **a;
- a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
- if( a==0 ){
- assert( db->mallocFailed ); /* Error reported through mallocFailed */
- return;
+ x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n);
+ if( x==0 ){
+ x = (ynVar)(++pParse->nVar);
+ doAdd = 1;
}
- pParse->azVar = a;
- memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
- pParse->nzVar = x;
}
- if( pParse->azVar[x-1]==0 ){
- pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
+ if( doAdd ){
+ pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x);
}
- }
- if( pParse->nVar>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
+ }
+ pExpr->iColumn = x;
+ if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
sqlite3ErrorMsg(pParse, "too many SQL variables");
}
}
@@ -90730,6 +100817,10 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
assert( p!=0 );
/* Sanity check: Assert that the IntValue is non-negative if it exists */
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
+
+ assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed );
+ assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced)
+ || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) );
#ifdef SQLITE_DEBUG
if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
assert( p->pLeft==0 );
@@ -90741,24 +100832,44 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
- sqlite3ExprDelete(db, p->pRight);
- if( ExprHasProperty(p, EP_xIsSelect) ){
+ if( p->pRight ){
+ assert( !ExprHasProperty(p, EP_WinFunc) );
+ sqlite3ExprDeleteNN(db, p->pRight);
+ }else if( ExprHasProperty(p, EP_xIsSelect) ){
+ assert( !ExprHasProperty(p, EP_WinFunc) );
sqlite3SelectDelete(db, p->x.pSelect);
}else{
sqlite3ExprListDelete(db, p->x.pList);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(p, EP_WinFunc) ){
+ sqlite3WindowDelete(db, p->y.pWin);
+ }
+#endif
}
}
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
if( !ExprHasProperty(p, EP_Static) ){
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
}
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p ) sqlite3ExprDeleteNN(db, p);
}
+/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
+** expression.
+*/
+SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){
+ if( p ){
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameExprUnmap(pParse, p);
+ }
+ sqlite3ExprDeleteNN(pParse->db, p);
+ }
+}
+
/*
-** Return the number of bytes allocated for the expression structure
+** Return the number of bytes allocated for the expression structure
** passed as the first argument. This is always one of EXPR_FULLSIZE,
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
@@ -90773,14 +100884,14 @@ static int exprStructSize(Expr *p){
** to store a copy of an expression or expression tree. They differ in
** how much of the tree is measured.
**
-** dupedExprStructSize() Size of only the Expr structure
+** dupedExprStructSize() Size of only the Expr structure
** dupedExprNodeSize() Size of Expr + space for token
** dupedExprSize() Expr + token + subtree components
**
***************************************************************************
**
-** The dupedExprStructSize() function returns two values OR-ed together:
-** (1) the space required for a copy of the Expr structure only and
+** The dupedExprStructSize() function returns two values OR-ed together:
+** (1) the space required for a copy of the Expr structure only and
** (2) the EP_xxx flags that indicate what the structure size should be.
** The return values is always one of:
**
@@ -90795,7 +100906,7 @@ static int exprStructSize(Expr *p){
** Note that with flags==EXPRDUP_REDUCE, this routines works on full-size
** (unreduced) Expr objects as they or originally constructed by the parser.
** During expression analysis, extra information is computed and moved into
-** later parts of teh Expr object and that extra information might get chopped
+** later parts of the Expr object and that extra information might get chopped
** off if the expression is reduced. Note also that it does not work to
** make an EXPRDUP_REDUCE copy of a reduced expression. It is only legal
** to reduce a pristine expression tree from the parser. The implementation
@@ -90807,13 +100918,17 @@ static int dupedExprStructSize(Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==flags ){
+ if( 0==flags || p->op==TK_SELECT_COLUMN
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ || ExprHasProperty(p, EP_WinFunc)
+#endif
+ ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
- assert( !ExprHasProperty(p, EP_FromJoin) );
+ assert( !ExprHasProperty(p, EP_FromJoin) );
assert( !ExprHasProperty(p, EP_MemToken) );
- assert( !ExprHasProperty(p, EP_NoReduce) );
+ assert( !ExprHasVVAProperty(p, EP_NoReduce) );
if( p->pLeft || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
}else{
@@ -90825,29 +100940,29 @@ static int dupedExprStructSize(Expr *p, int flags){
}
/*
-** This function returns the space in bytes required to store the copy
+** This function returns the space in bytes required to store the copy
** of the Expr structure and a copy of the Expr.u.zToken string (if that
** string is defined.)
*/
static int dupedExprNodeSize(Expr *p, int flags){
int nByte = dupedExprStructSize(p, flags) & 0xfff;
if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- nByte += sqlite3Strlen30(p->u.zToken)+1;
+ nByte += sqlite3Strlen30NN(p->u.zToken)+1;
}
return ROUND8(nByte);
}
/*
-** Return the number of bytes required to create a duplicate of the
+** Return the number of bytes required to create a duplicate of the
** expression passed as the first argument. The second argument is a
** mask containing EXPRDUP_XXX flags.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
-** If the EXPRDUP_REDUCE flag is set, then the return value includes
-** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
-** and Expr.pRight variables (but not for any structures pointed to or
+** If the EXPRDUP_REDUCE flag is set, then the return value includes
+** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
+** and Expr.pRight variables (but not for any structures pointed to or
** descended from the Expr.x.pList or Expr.x.pSelect variables).
*/
static int dupedExprSize(Expr *p, int flags){
@@ -90862,8 +100977,8 @@ static int dupedExprSize(Expr *p, int flags){
}
/*
-** This function is similar to sqlite3ExprDup(), except that if pzBuffer
-** is not NULL then *pzBuffer is assumed to point to a buffer large enough
+** This function is similar to sqlite3ExprDup(), except that if pzBuffer
+** is not NULL then *pzBuffer is assumed to point to a buffer large enough
** to store the copy of expression p, the copies of p->u.zToken
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
** if any. Before returning, *pzBuffer is set to the first byte past the
@@ -90909,7 +101024,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
}else{
u32 nSize = (u32)exprStructSize(p);
memcpy(zAlloc, p, nSize);
- if( nSize<EXPR_FULLSIZE ){
+ if( nSize<EXPR_FULLSIZE ){
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
}
@@ -90918,6 +101033,10 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
pNew->flags |= staticFlag;
+ ExprClearVVAProperties(pNew);
+ if( dupFlags ){
+ ExprSetVVAProperty(pNew, EP_Immutable);
+ }
/* Copy the p->u.zToken string, if any. */
if( nToken ){
@@ -90935,7 +101054,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
}
/* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
+ if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){
zAlloc += dupedExprNodeSize(p, dupFlags);
if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
pNew->pLeft = p->pLeft ?
@@ -90943,6 +101062,12 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
pNew->pRight = p->pRight ?
exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(p, EP_WinFunc) ){
+ pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin);
+ assert( ExprHasProperty(pNew, EP_WinFunc) );
+ }
+#endif /* SQLITE_OMIT_WINDOWFUNC */
if( pzBuffer ){
*pzBuffer = zAlloc;
}
@@ -90950,6 +101075,8 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
if( pNew->op==TK_SELECT_COLUMN ){
pNew->pLeft = p->pLeft;
+ assert( p->iColumn==0 || p->pRight==0 );
+ assert( p->pRight==0 || p->pRight==p->pLeft );
}else{
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
}
@@ -90961,7 +101088,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
}
/*
-** Create and return a deep copy of the object passed as the second
+** Create and return a deep copy of the object passed as the second
** argument. If an OOM condition is encountered, NULL is returned
** and the db->mallocFailed flag set.
*/
@@ -90969,7 +101096,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
static With *withDup(sqlite3 *db, With *p){
With *pRet = 0;
if( p ){
- int nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
+ sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
pRet = sqlite3DbMallocZero(db, nByte);
if( pRet ){
int i;
@@ -90987,6 +101114,39 @@ static With *withDup(sqlite3 *db, With *p){
# define withDup(x,y) 0
#endif
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** The gatherSelectWindows() procedure and its helper routine
+** gatherSelectWindowsCallback() are used to scan all the expressions
+** an a newly duplicated SELECT statement and gather all of the Window
+** objects found there, assembling them onto the linked list at Select->pWin.
+*/
+static int gatherSelectWindowsCallback(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_WinFunc) ){
+ Select *pSelect = pWalker->u.pSelect;
+ Window *pWin = pExpr->y.pWin;
+ assert( pWin );
+ assert( IsWindowFunc(pExpr) );
+ assert( pWin->ppThis==0 );
+ sqlite3WindowLink(pSelect, pWin);
+ }
+ return WRC_Continue;
+}
+static int gatherSelectWindowsSelectCallback(Walker *pWalker, Select *p){
+ return p==pWalker->u.pSelect ? WRC_Continue : WRC_Prune;
+}
+static void gatherSelectWindows(Select *p){
+ Walker w;
+ w.xExprCallback = gatherSelectWindowsCallback;
+ w.xSelectCallback = gatherSelectWindowsSelectCallback;
+ w.xSelectCallback2 = 0;
+ w.pParse = 0;
+ w.u.pSelect = p;
+ sqlite3WalkSelect(&w, p);
+}
+#endif
+
+
/*
** The following group of routines make deep copies of expressions,
** expression lists, ID lists, and select statements. The copies can
@@ -90994,7 +101154,7 @@ static With *withDup(sqlite3 *db, With *p){
** without effecting the originals.
**
** The expression list, ID, and source lists return by sqlite3ExprListDup(),
-** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded
+** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded
** by subsequent calls to sqlite*ListAppend() routines.
**
** Any tables that the SrcList might point to are not duplicated.
@@ -91012,26 +101172,40 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
+ Expr *pPriorSelectCol = 0;
assert( db!=0 );
if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
if( pNew==0 ) return 0;
- pNew->nExpr = i = p->nExpr;
- if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
- pNew->a = pItem = sqlite3DbMallocRawNN(db, i*sizeof(p->a[0]) );
- if( pItem==0 ){
- sqlite3DbFree(db, pNew);
- return 0;
- }
+ pNew->nExpr = p->nExpr;
+ pItem = pNew->a;
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
Expr *pOldExpr = pOldItem->pExpr;
+ Expr *pNewExpr;
pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
- pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
- pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
- pItem->sortOrder = pOldItem->sortOrder;
+ if( pOldExpr
+ && pOldExpr->op==TK_SELECT_COLUMN
+ && (pNewExpr = pItem->pExpr)!=0
+ ){
+ assert( pNewExpr->iColumn==0 || i>0 );
+ if( pNewExpr->iColumn==0 ){
+ assert( pOldExpr->pLeft==pOldExpr->pRight );
+ pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
+ }else{
+ assert( i>0 );
+ assert( pItem[-1].pExpr!=0 );
+ assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
+ assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
+ pNewExpr->pLeft = pPriorSelectCol;
+ }
+ }
+ pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
+ pItem->sortFlags = pOldItem->sortFlags;
+ pItem->eEName = pOldItem->eEName;
pItem->done = 0;
- pItem->bSpanIsTab = pOldItem->bSpanIsTab;
+ pItem->bNulls = pOldItem->bNulls;
+ pItem->bSorterRef = pOldItem->bSorterRef;
pItem->u = pOldItem->u;
}
return pNew;
@@ -91039,7 +101213,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
/*
** If cursors, triggers, views and subqueries are all omitted from
-** the build, then none of the following routines, except for
+** the build, then none of the following routines, except for
** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
** called with a NULL argument.
*/
@@ -91072,12 +101246,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
}
pNewItem->pIBIndex = pOldItem->pIBIndex;
if( pNewItem->fg.isTabFunc ){
- pNewItem->u1.pFuncArg =
+ pNewItem->u1.pFuncArg =
sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
}
pTab = pNewItem->pTab = pOldItem->pTab;
if( pTab ){
- pTab->nRef++;
+ pTab->nTabRef++;
}
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
@@ -91096,7 +101270,7 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
pNew->nId = p->nId;
pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ){
- sqlite3DbFree(db, pNew);
+ sqlite3DbFreeNN(db, pNew);
return 0;
}
/* Note that because the size of the allocation for p->a[] is not
@@ -91110,33 +101284,45 @@ SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
}
return pNew;
}
-SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
- Select *pNew, *pPrior;
+SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
+ Select *pRet = 0;
+ Select *pNext = 0;
+ Select **pp = &pRet;
+ Select *p;
+
assert( db!=0 );
- if( p==0 ) return 0;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
- if( pNew==0 ) return 0;
- pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
- pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
- pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
- pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
- pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
- pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
- pNew->op = p->op;
- pNew->pPrior = pPrior = sqlite3SelectDup(db, p->pPrior, flags);
- if( pPrior ) pPrior->pNext = pNew;
- pNew->pNext = 0;
- pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
- pNew->pOffset = sqlite3ExprDup(db, p->pOffset, flags);
- pNew->iLimit = 0;
- pNew->iOffset = 0;
- pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
- pNew->addrOpenEphm[0] = -1;
- pNew->addrOpenEphm[1] = -1;
- pNew->nSelectRow = p->nSelectRow;
- pNew->pWith = withDup(db, p->pWith);
- sqlite3SelectSetName(pNew, p->zSelName);
- return pNew;
+ for(p=pDup; p; p=p->pPrior){
+ Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
+ if( pNew==0 ) break;
+ pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
+ pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
+ pNew->pWhere = sqlite3ExprDup(db, p->pWhere, flags);
+ pNew->pGroupBy = sqlite3ExprListDup(db, p->pGroupBy, flags);
+ pNew->pHaving = sqlite3ExprDup(db, p->pHaving, flags);
+ pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
+ pNew->op = p->op;
+ pNew->pNext = pNext;
+ pNew->pPrior = 0;
+ pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
+ pNew->iLimit = 0;
+ pNew->iOffset = 0;
+ pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
+ pNew->addrOpenEphm[0] = -1;
+ pNew->addrOpenEphm[1] = -1;
+ pNew->nSelectRow = p->nSelectRow;
+ pNew->pWith = withDup(db, p->pWith);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ pNew->pWin = 0;
+ pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
+ if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
+#endif
+ pNew->selId = p->selId;
+ *pp = pNew;
+ pp = &pNew->pPrior;
+ pNext = pNew;
+ }
+
+ return pRet;
}
#else
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
@@ -91150,6 +101336,13 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
** Add a new element to the end of an expression list. If pList is
** initially NULL, then create a new expression list.
**
+** The pList argument must be either NULL or a pointer to an ExprList
+** obtained from a prior call to sqlite3ExprListAppend(). This routine
+** may not be used with an ExprList obtained from sqlite3ExprListDup().
+** Reason: This routine assumes that the number of slots in pList->a[]
+** is a power of two. That is true for sqlite3ExprListAppend() returns
+** but is not necessarily true from the return value of sqlite3ExprListDup().
+**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
** that the new entry was successfully appended.
@@ -91159,6 +101352,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
ExprList *pList, /* List to which to append. Might be NULL */
Expr *pExpr /* Expression to be appended. Might be NULL */
){
+ struct ExprList_item *pItem;
sqlite3 *db = pParse->db;
assert( db!=0 );
if( pList==0 ){
@@ -91167,26 +101361,23 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
goto no_mem;
}
pList->nExpr = 0;
- pList->a = sqlite3DbMallocRawNN(db, sizeof(pList->a[0]));
- if( pList->a==0 ) goto no_mem;
}else if( (pList->nExpr & (pList->nExpr-1))==0 ){
- struct ExprList_item *a;
- assert( pList->nExpr>0 );
- a = sqlite3DbRealloc(db, pList->a, pList->nExpr*2*sizeof(pList->a[0]));
- if( a==0 ){
+ ExprList *pNew;
+ pNew = sqlite3DbRealloc(db, pList,
+ sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0]));
+ if( pNew==0 ){
goto no_mem;
}
- pList->a = a;
- }
- assert( pList->a!=0 );
- if( 1 ){
- struct ExprList_item *pItem = &pList->a[pList->nExpr++];
- memset(pItem, 0, sizeof(*pItem));
- pItem->pExpr = pExpr;
+ pList = pNew;
}
+ pItem = &pList->a[pList->nExpr++];
+ assert( offsetof(struct ExprList_item,zEName)==sizeof(pItem->pExpr) );
+ assert( offsetof(struct ExprList_item,pExpr)==0 );
+ memset(&pItem->zEName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zEName));
+ pItem->pExpr = pExpr;
return pList;
-no_mem:
+no_mem:
/* Avoid leaking memory if malloc has failed. */
sqlite3ExprDelete(db, pExpr);
sqlite3ExprListDelete(db, pList);
@@ -91201,7 +101392,7 @@ no_mem:
** Or: (a,b,c) = (SELECT x,y,z FROM ....)
**
** For each term of the vector assignment, append new entries to the
-** expression list pList. In the case of a subquery on the LHS, append
+** expression list pList. In the case of a subquery on the RHS, append
** TK_SELECT_COLUMN expressions.
*/
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
@@ -91218,31 +101409,49 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
** exit prior to this routine being invoked */
if( NEVER(pColumns==0) ) goto vector_append_error;
if( pExpr==0 ) goto vector_append_error;
- n = sqlite3ExprVectorSize(pExpr);
- if( pColumns->nId!=n ){
+
+ /* If the RHS is a vector, then we can immediately check to see that
+ ** the size of the RHS and LHS match. But if the RHS is a SELECT,
+ ** wildcards ("*") in the result set of the SELECT must be expanded before
+ ** we can do the size check, so defer the size check until code generation.
+ */
+ if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
pColumns->nId, n);
goto vector_append_error;
}
- for(i=0; i<n; i++){
+
+ for(i=0; i<pColumns->nId; i++){
Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
+ assert( pSubExpr!=0 || db->mallocFailed );
+ assert( pSubExpr==0 || pSubExpr->iTable==0 );
+ if( pSubExpr==0 ) continue;
+ pSubExpr->iTable = pColumns->nId;
pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
if( pList ){
assert( pList->nExpr==iFirst+i+1 );
- pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
+ pList->a[pList->nExpr-1].zEName = pColumns->a[i].zName;
pColumns->a[i].zName = 0;
}
}
- if( pExpr->op==TK_SELECT ){
- if( pList && pList->a[iFirst].pExpr ){
- assert( pList->a[iFirst].pExpr->op==TK_SELECT_COLUMN );
- pList->a[iFirst].pExpr->pRight = pExpr;
- pExpr = 0;
- }
+
+ if( !db->mallocFailed && pExpr->op==TK_SELECT && ALWAYS(pList!=0) ){
+ Expr *pFirst = pList->a[iFirst].pExpr;
+ assert( pFirst!=0 );
+ assert( pFirst->op==TK_SELECT_COLUMN );
+
+ /* Store the SELECT statement in pRight so it will be deleted when
+ ** sqlite3ExprListDelete() is called */
+ pFirst->pRight = pExpr;
+ pExpr = 0;
+
+ /* Remember the size of the LHS in iTable so that we can check that
+ ** the RHS and LHS sizes match during code generation. */
+ pFirst->iTable = pColumns->nId;
}
vector_append_error:
- sqlite3ExprDelete(db, pExpr);
+ sqlite3ExprUnmapAndDelete(pParse, pExpr);
sqlite3IdListDelete(db, pColumns);
return pList;
}
@@ -91250,19 +101459,38 @@ vector_append_error:
/*
** Set the sort order for the last element on the given ExprList.
*/
-SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
+SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int eNulls){
+ struct ExprList_item *pItem;
if( p==0 ) return;
- assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 );
assert( p->nExpr>0 );
- if( iSortOrder<0 ){
- assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC );
- return;
+
+ assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 );
+ assert( iSortOrder==SQLITE_SO_UNDEFINED
+ || iSortOrder==SQLITE_SO_ASC
+ || iSortOrder==SQLITE_SO_DESC
+ );
+ assert( eNulls==SQLITE_SO_UNDEFINED
+ || eNulls==SQLITE_SO_ASC
+ || eNulls==SQLITE_SO_DESC
+ );
+
+ pItem = &p->a[p->nExpr-1];
+ assert( pItem->bNulls==0 );
+ if( iSortOrder==SQLITE_SO_UNDEFINED ){
+ iSortOrder = SQLITE_SO_ASC;
+ }
+ pItem->sortFlags = (u8)iSortOrder;
+
+ if( eNulls!=SQLITE_SO_UNDEFINED ){
+ pItem->bNulls = 1;
+ if( iSortOrder!=eNulls ){
+ pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
+ }
}
- p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
}
/*
-** Set the ExprList.a[].zName element of the most recently added item
+** Set the ExprList.a[].zEName element of the most recently added item
** on the expression list.
**
** pList might be NULL following an OOM error. But pName should never be
@@ -91276,13 +101504,23 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
int dequote /* True to cause the name to be dequoted */
){
assert( pList!=0 || pParse->db->mallocFailed!=0 );
+ assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 );
if( pList ){
struct ExprList_item *pItem;
assert( pList->nExpr>0 );
pItem = &pList->a[pList->nExpr-1];
- assert( pItem->zName==0 );
- pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
- if( dequote ) sqlite3Dequote(pItem->zName);
+ assert( pItem->zEName==0 );
+ assert( pItem->eEName==ENAME_NAME );
+ pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
+ if( dequote ){
+ /* If dequote==0, then pName->z does not point to part of a DDL
+ ** statement handled by the parser. And so no token need be added
+ ** to the token-map. */
+ sqlite3Dequote(pItem->zEName);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)pItem->zEName, pName);
+ }
+ }
}
}
@@ -91297,17 +101535,18 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
SQLITE_PRIVATE void sqlite3ExprListSetSpan(
Parse *pParse, /* Parsing context */
ExprList *pList, /* List to which to add the span. */
- ExprSpan *pSpan /* The span to be added */
+ const char *zStart, /* Start of the span */
+ const char *zEnd /* End of the span */
){
sqlite3 *db = pParse->db;
assert( pList!=0 || db->mallocFailed!=0 );
if( pList ){
struct ExprList_item *pItem = &pList->a[pList->nExpr-1];
assert( pList->nExpr>0 );
- assert( db->mallocFailed || pItem->pExpr==pSpan->pExpr );
- sqlite3DbFree(db, pItem->zSpan);
- pItem->zSpan = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
+ if( pItem->zEName==0 ){
+ pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd);
+ pItem->eEName = ENAME_SPAN;
+ }
}
}
@@ -91332,16 +101571,15 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(
** Delete an entire expression list.
*/
static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
- int i;
- struct ExprList_item *pItem;
- assert( pList->a!=0 || pList->nExpr==0 );
- for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
+ int i = pList->nExpr;
+ struct ExprList_item *pItem = pList->a;
+ assert( pList->nExpr>0 );
+ do{
sqlite3ExprDelete(db, pItem->pExpr);
- sqlite3DbFree(db, pItem->zName);
- sqlite3DbFree(db, pItem->zSpan);
- }
- sqlite3DbFree(db, pList->a);
- sqlite3DbFree(db, pList);
+ sqlite3DbFree(db, pItem->zEName);
+ pItem++;
+ }while( --i>0 );
+ sqlite3DbFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
@@ -91354,17 +101592,102 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
int i;
u32 m = 0;
- if( pList ){
- for(i=0; i<pList->nExpr; i++){
- Expr *pExpr = pList->a[i].pExpr;
- assert( pExpr!=0 );
- m |= pExpr->flags;
- }
+ assert( pList!=0 );
+ for(i=0; i<pList->nExpr; i++){
+ Expr *pExpr = pList->a[i].pExpr;
+ assert( pExpr!=0 );
+ m |= pExpr->flags;
}
return m;
}
/*
+** This is a SELECT-node callback for the expression walker that
+** always "fails". By "fail" in this case, we mean set
+** pWalker->eCode to zero and abort.
+**
+** This callback is used by multiple expression walkers.
+*/
+SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){
+ UNUSED_PARAMETER(NotUsed);
+ pWalker->eCode = 0;
+ return WRC_Abort;
+}
+
+/*
+** Check the input string to see if it is "true" or "false" (in any case).
+**
+** If the string is.... Return
+** "true" EP_IsTrue
+** "false" EP_IsFalse
+** anything else 0
+*/
+SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char *zIn){
+ if( sqlite3StrICmp(zIn, "true")==0 ) return EP_IsTrue;
+ if( sqlite3StrICmp(zIn, "false")==0 ) return EP_IsFalse;
+ return 0;
+}
+
+
+/*
+** If the input expression is an ID with the name "true" or "false"
+** then convert it into an TK_TRUEFALSE term. Return non-zero if
+** the conversion happened, and zero if the expression is unaltered.
+*/
+SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){
+ u32 v;
+ assert( pExpr->op==TK_ID || pExpr->op==TK_STRING );
+ if( !ExprHasProperty(pExpr, EP_Quoted)
+ && (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0
+ ){
+ pExpr->op = TK_TRUEFALSE;
+ ExprSetProperty(pExpr, v);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+** The argument must be a TK_TRUEFALSE Expr node. Return 1 if it is TRUE
+** and 0 if it is FALSE.
+*/
+SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){
+ pExpr = sqlite3ExprSkipCollate((Expr*)pExpr);
+ assert( pExpr->op==TK_TRUEFALSE );
+ assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0
+ || sqlite3StrICmp(pExpr->u.zToken,"false")==0 );
+ return pExpr->u.zToken[4]==0;
+}
+
+/*
+** If pExpr is an AND or OR expression, try to simplify it by eliminating
+** terms that are always true or false. Return the simplified expression.
+** Or return the original expression if no simplification is possible.
+**
+** Examples:
+**
+** (x<10) AND true => (x<10)
+** (x<10) AND false => false
+** (x<10) AND (y=22 OR false) => (x<10) AND (y=22)
+** (x<10) AND (y=22 OR true) => (x<10)
+** (y=22) OR true => true
+*/
+SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
+ assert( pExpr!=0 );
+ if( pExpr->op==TK_AND || pExpr->op==TK_OR ){
+ Expr *pRight = sqlite3ExprSimplifiedAndOr(pExpr->pRight);
+ Expr *pLeft = sqlite3ExprSimplifiedAndOr(pExpr->pLeft);
+ if( ExprAlwaysTrue(pLeft) || ExprAlwaysFalse(pRight) ){
+ pExpr = pExpr->op==TK_AND ? pRight : pLeft;
+ }else if( ExprAlwaysTrue(pRight) || ExprAlwaysFalse(pLeft) ){
+ pExpr = pExpr->op==TK_AND ? pLeft : pRight;
+ }
+ }
+ return pExpr;
+}
+
+
+/*
** These routines are Walker callbacks used to check expressions to
** see if they are "constant" for some definition of constant. The
** Walker.eCode value determines the type of "constant" we are looking
@@ -91380,11 +101703,12 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
** In all cases, the callbacks set Walker.eCode=0 and abort if the expression
** is found to not be a constant.
**
-** The sqlite3ExprIsConstantOrFunction() is used for evaluating expressions
-** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing
-** an existing schema and 4 when processing a new statement. A bound
-** parameter raises an error for new statements, but is silently converted
-** to NULL for existing schemas. This allows sqlite_master tables that
+** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT
+** expressions in a CREATE TABLE statement. The Walker.eCode value is 5
+** when parsing an existing schema out of the sqlite_schema table and 4
+** when processing a new CREATE TABLE statement. A bound parameter raises
+** an error for new statements, but is silently converted
+** to NULL for existing schemas. This allows sqlite_schema tables that
** contain a bound parameter because they were generated by older versions
** of SQLite to be parsed by newer versions of SQLite without raising a
** malformed schema error.
@@ -91404,13 +101728,22 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
** and either pWalker->eCode==4 or 5 or the function has the
** SQLITE_FUNC_CONST flag. */
case TK_FUNCTION:
- if( pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc) ){
+ if( (pWalker->eCode>=4 || ExprHasProperty(pExpr,EP_ConstFunc))
+ && !ExprHasProperty(pExpr, EP_WinFunc)
+ ){
+ if( pWalker->eCode==5 ) ExprSetProperty(pExpr, EP_FromDDL);
return WRC_Continue;
}else{
pWalker->eCode = 0;
return WRC_Abort;
}
case TK_ID:
+ /* Convert "true" or "false" in a DEFAULT clause into the
+ ** appropriate TK_TRUEFALSE operator */
+ if( sqlite3ExprIdToTrueFalse(pExpr) ){
+ return WRC_Prune;
+ }
+ /* no break */ deliberate_fall_through
case TK_COLUMN:
case TK_AGG_FUNCTION:
case TK_AGG_COLUMN:
@@ -91418,17 +101751,26 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
testcase( pExpr->op==TK_AGG_COLUMN );
+ if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){
+ return WRC_Continue;
+ }
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
return WRC_Continue;
- }else{
- pWalker->eCode = 0;
- return WRC_Abort;
}
+ /* no break */ deliberate_fall_through
+ case TK_IF_NULL_ROW:
+ case TK_REGISTER:
+ case TK_DOT:
+ testcase( pExpr->op==TK_REGISTER );
+ testcase( pExpr->op==TK_IF_NULL_ROW );
+ testcase( pExpr->op==TK_DOT );
+ pWalker->eCode = 0;
+ return WRC_Abort;
case TK_VARIABLE:
if( pWalker->eCode==5 ){
/* Silently convert bound parameters that appear inside of CREATE
** statements into a NULL when parsing the CREATE statement text out
- ** of the sqlite_master table */
+ ** of the sqlite_schema table */
pExpr->op = TK_NULL;
}else if( pWalker->eCode==4 ){
/* A bound parameter in a CREATE statement that originates from
@@ -91436,24 +101778,21 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
pWalker->eCode = 0;
return WRC_Abort;
}
- /* Fall through */
+ /* no break */ deliberate_fall_through
default:
- testcase( pExpr->op==TK_SELECT ); /* selectNodeIsConstant will disallow */
- testcase( pExpr->op==TK_EXISTS ); /* selectNodeIsConstant will disallow */
+ testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
+ testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
return WRC_Continue;
}
}
-static int selectNodeIsConstant(Walker *pWalker, Select *NotUsed){
- UNUSED_PARAMETER(NotUsed);
- pWalker->eCode = 0;
- return WRC_Abort;
-}
static int exprIsConst(Expr *p, int initFlag, int iCur){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = initFlag;
w.xExprCallback = exprNodeIsConstant;
- w.xSelectCallback = selectNodeIsConstant;
+ w.xSelectCallback = sqlite3SelectWalkFail;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlite3SelectWalkAssert2;
+#endif
w.u.iCur = iCur;
sqlite3WalkExpr(&w, p);
return w.eCode;
@@ -91472,10 +101811,17 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){
}
/*
-** Walk an expression tree. Return non-zero if the expression is constant
-** that does no originate from the ON or USING clauses of a join.
-** Return 0 if it involves variables or function calls or terms from
-** an ON or USING clause.
+** Walk an expression tree. Return non-zero if
+**
+** (1) the expression is constant, and
+** (2) the expression does originate in the ON or USING clause
+** of a LEFT JOIN, and
+** (3) the expression does not contain any EP_FixedCol TK_COLUMN
+** operands created by the constant propagation optimization.
+**
+** When this routine returns true, it indicates that the expression
+** can be added to the pParse->pConstExpr list and evaluated once when
+** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce().
*/
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
return exprIsConst(p, 2, 0);
@@ -91491,10 +101837,81 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
return exprIsConst(p, 3, iCur);
}
+
/*
-** Walk an expression tree. Return non-zero if the expression is constant
-** or a function call with constant arguments. Return and 0 if there
-** are any variables.
+** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
+*/
+static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
+ ExprList *pGroupBy = pWalker->u.pGroupBy;
+ int i;
+
+ /* Check if pExpr is identical to any GROUP BY term. If so, consider
+ ** it constant. */
+ for(i=0; i<pGroupBy->nExpr; i++){
+ Expr *p = pGroupBy->a[i].pExpr;
+ if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
+ CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
+ if( sqlite3IsBinary(pColl) ){
+ return WRC_Prune;
+ }
+ }
+ }
+
+ /* Check if pExpr is a sub-select. If so, consider it variable. */
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+
+ return exprNodeIsConstant(pWalker, pExpr);
+}
+
+/*
+** Walk the expression tree passed as the first argument. Return non-zero
+** if the expression consists entirely of constants or copies of terms
+** in pGroupBy that sort with the BINARY collation sequence.
+**
+** This routine is used to determine if a term of the HAVING clause can
+** be promoted into the WHERE clause. In order for such a promotion to work,
+** the value of the HAVING clause term must be the same for all members of
+** a "group". The requirement that the GROUP BY term must be BINARY
+** assumes that no other collating sequence will have a finer-grained
+** grouping than binary. In other words (A=B COLLATE binary) implies
+** A=B in every other collating sequence. The requirement that the
+** GROUP BY be BINARY is stricter than necessary. It would also work
+** to promote HAVING clauses that use the same alternative collating
+** sequence as the GROUP BY term, but that is much harder to check,
+** alternative collating sequences are uncommon, and this is only an
+** optimization, so we take the easy way out and simply require the
+** GROUP BY to use the BINARY collating sequence.
+*/
+SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprList *pGroupBy){
+ Walker w;
+ w.eCode = 1;
+ w.xExprCallback = exprNodeIsConstantOrGroupBy;
+ w.xSelectCallback = 0;
+ w.u.pGroupBy = pGroupBy;
+ w.pParse = pParse;
+ sqlite3WalkExpr(&w, p);
+ return w.eCode;
+}
+
+/*
+** Walk an expression tree for the DEFAULT field of a column definition
+** in a CREATE TABLE statement. Return non-zero if the expression is
+** acceptable for use as a DEFAULT. That is to say, return non-zero if
+** the expression is constant or a function call with constant arguments.
+** Return and 0 if there are any variables.
+**
+** isInit is true when parsing from sqlite_schema. isInit is false when
+** processing a new CREATE TABLE statement. When isInit is true, parameters
+** (such as ? or $abc) in the expression are converted into NULL. When
+** isInit is false, parameters raise an error. Parameters should not be
+** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
+** allowed it, so we need to support it when reading sqlite_schema for
+** backwards compatibility.
+**
+** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
**
** For the purposes of this function, a double-quoted string (ex: "abc")
** is considered a variable but a single-quoted string (ex: 'abc') is
@@ -91512,10 +101929,12 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr *p, u8 isInit){
*/
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
Walker w;
- memset(&w, 0, sizeof(w));
w.eCode = 1;
w.xExprCallback = sqlite3ExprWalkNoop;
- w.xSelectCallback = selectNodeIsConstant;
+ w.xSelectCallback = sqlite3SelectWalkFail;
+#ifdef SQLITE_DEBUG
+ w.xSelectCallback2 = sqlite3SelectWalkAssert2;
+#endif
sqlite3WalkExpr(&w, p);
return w.eCode==0;
}
@@ -91529,6 +101948,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
*/
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
int rc = 0;
+ if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */
/* If an expression is an integer literal that fits in a signed 32-bit
** integer, then the EP_IntValue flag will have already been set */
@@ -91562,7 +101982,7 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
** Return FALSE if there is no chance that the expression can be NULL.
**
** If the expression might be NULL or if the expression is too complex
-** to tell return TRUE.
+** to tell return TRUE.
**
** This routine is used as an optimization, to skip OP_IsNull opcodes
** when we know that a value cannot be NULL. Hence, a false positive
@@ -91574,7 +101994,9 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
*/
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
u8 op;
- while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; }
+ while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
+ p = p->pLeft;
+ }
op = p->op;
if( op==TK_REGISTER ) op = p->op2;
switch( op ){
@@ -91584,9 +102006,11 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
case TK_BLOB:
return 0;
case TK_COLUMN:
- assert( p->pTab!=0 );
return ExprHasProperty(p, EP_CanBeNull) ||
- (p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
+ p->y.pTab==0 || /* Reference to column of index on expression */
+ (p->iColumn>=0
+ && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */
+ && p->y.pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
}
@@ -91604,27 +102028,30 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
*/
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){
u8 op;
+ int unaryMinus = 0;
if( aff==SQLITE_AFF_BLOB ) return 1;
- while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; }
+ while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
+ if( p->op==TK_UMINUS ) unaryMinus = 1;
+ p = p->pLeft;
+ }
op = p->op;
if( op==TK_REGISTER ) op = p->op2;
switch( op ){
case TK_INTEGER: {
- return aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC;
+ return aff>=SQLITE_AFF_NUMERIC;
}
case TK_FLOAT: {
- return aff==SQLITE_AFF_REAL || aff==SQLITE_AFF_NUMERIC;
+ return aff>=SQLITE_AFF_NUMERIC;
}
case TK_STRING: {
- return aff==SQLITE_AFF_TEXT;
+ return !unaryMinus && aff==SQLITE_AFF_TEXT;
}
case TK_BLOB: {
- return 1;
+ return !unaryMinus;
}
case TK_COLUMN: {
assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */
- return p->iColumn<0
- && (aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC);
+ return aff>=SQLITE_AFF_NUMERIC && p->iColumn<0;
}
default: {
return 0;
@@ -91643,7 +102070,7 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
}
/*
-** pX is the RHS of an IN operator. If pX is a SELECT statement
+** pX is the RHS of an IN operator. If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement. If pX is not a SELECT statement,
** or if the SELECT statement needs to be manifested into a transient
@@ -91667,7 +102094,6 @@ static Select *isCandidateForInOpt(Expr *pX){
}
assert( p->pGroupBy==0 ); /* Has no GROUP BY clause */
if( p->pLimit ) return 0; /* Has no LIMIT clause */
- assert( p->pOffset==0 ); /* No LIMIT means no OFFSET */
if( p->pWhere ) return 0; /* Has no WHERE clause */
pSrc = p->pSrc;
assert( pSrc!=0 );
@@ -91710,7 +102136,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
#ifndef SQLITE_OMIT_SUBQUERY
/*
-** The argument is an IN operator with a list (not a subquery) on the
+** The argument is an IN operator with a list (not a subquery) on the
** right-hand side. Return TRUE if that list is constant.
*/
static int sqlite3InRhsIsConstant(Expr *pIn){
@@ -91757,22 +102183,21 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** pX->iTable made to point to the ephemeral table instead of an
** existing table.
**
-** The inFlags parameter must contain exactly one of the bits
-** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains
-** IN_INDEX_MEMBERSHIP, then the generated table will be used for a
-** fast membership test. When the IN_INDEX_LOOP bit is set, the
-** IN index will be used to loop over all values of the RHS of the
-** IN operator.
+** The inFlags parameter must contain, at a minimum, one of the bits
+** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains
+** IN_INDEX_MEMBERSHIP, then the generated table will be used for a fast
+** membership test. When the IN_INDEX_LOOP bit is set, the IN index will
+** be used to loop over all values of the RHS of the IN operator.
**
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
** through the set members) then the b-tree must not contain duplicates.
-** An epheremal table must be used unless the selected columns are guaranteed
+** An epheremal table will be created unless the selected columns are guaranteed
** to be unique - either because it is an INTEGER PRIMARY KEY or due to
** a UNIQUE constraint or index.
**
-** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
-** for fast set membership tests) then an epheremal table must
-** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
+** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
+** for fast set membership tests) then an epheremal table must
+** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
** index can be found with the specified <columns> as its left-most.
**
** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and
@@ -91784,7 +102209,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
**
** When the b-tree is being used for membership tests, the calling function
** might need to know whether or not the RHS side of the IN operator
-** contains a NULL. If prRhsHasNull is not a NULL pointer and
+** contains a NULL. If prRhsHasNull is not a NULL pointer and
** if there is any chance that the (...) might contain a NULL value at
** runtime, then a register is allocated and the register number written
** to *prRhsHasNull. If there is no chance that the (...) contains a
@@ -91809,10 +102234,11 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3FindInIndex(
Parse *pParse, /* Parsing context */
- Expr *pX, /* The right-hand side (RHS) of the IN operator */
+ Expr *pX, /* The IN expression */
u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
int *prRhsHasNull, /* Register holding NULL status. See notes */
- int *aiMap /* Mapping from Index fields to RHS fields */
+ int *aiMap, /* Mapping from Index fields to RHS fields */
+ int *piTab /* OUT: index to use */
){
Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */
@@ -91823,9 +102249,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
assert( pX->op==TK_IN );
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
- /* If the RHS of this IN(...) operator is a SELECT, and if it matters
+ /* If the RHS of this IN(...) operator is a SELECT, and if it matters
** whether or not the SELECT result contains NULL values, check whether
- ** or not NULL is actually possible (it may not be, for example, due
+ ** or not NULL is actually possible (it may not be, for example, due
** to NOT NULL constraints in the schema). If no NULL values are possible,
** set prRhsHasNull to 0 before continuing. */
if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
@@ -91840,12 +102266,12 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
}
/* Check to see if an existing table or index can be used to
- ** satisfy the query. This is preferable to generating a new
+ ** satisfy the query. This is preferable to generating a new
** ephemeral table. */
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
- i16 iDb; /* Database idx for pTab */
+ int iDb; /* Database idx for pTab */
ExprList *pEList = p->pEList;
int nExpr = pEList->nExpr;
@@ -91856,6 +102282,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iDb>=0 && iDb<SQLITE_MAX_ATTACHED );
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
@@ -91867,14 +102294,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
eType = IN_INDEX_ROWID;
-
+ ExplainQueryPlan((pParse, 0,
+ "USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName));
sqlite3VdbeJumpHere(v, iAddr);
}else{
Index *pIdx; /* Iterator variable */
int affinity_ok = 1;
int i;
- /* Check that the affinity that will be used to perform each
+ /* Check that the affinity that will be used to perform each
** comparison is the same as the affinity of each column in table
** on the RHS of the IN operator. If it not, it is not possible to
** use any index of the RHS table. */
@@ -91906,6 +102334,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
Bitmask colUsed; /* Columns of the index used */
Bitmask mCol; /* Mask for the current column */
if( pIdx->nColumn<nExpr ) continue;
+ if( pIdx->pPartIdxWhere!=0 ) continue;
/* Maximum nColumn is BMS-2, not BMS-1, so that we can compute
** BITMASK(nExpr) without overflowing */
testcase( pIdx->nColumn==BMS-2 );
@@ -91918,14 +102347,14 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
continue; /* This index is not unique over the IN RHS columns */
}
}
-
+
colUsed = 0; /* Columns of index used so far */
for(i=0; i<nExpr; i++){
Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
Expr *pRhs = pEList->a[i].pExpr;
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
int j;
-
+
assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
for(j=0; j<nExpr; j++){
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
@@ -91941,26 +102370,23 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
colUsed |= mCol;
if( aiMap ) aiMap[i] = j;
}
-
+
assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
if( colUsed==(MASKBIT(nExpr)-1) ){
/* If we reach this point, that means the index pIdx is usable */
int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
-#ifndef SQLITE_OMIT_EXPLAIN
- sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0,
- sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName),
- P4_DYNAMIC);
-#endif
+ ExplainQueryPlan((pParse, 0,
+ "USING INDEX %s FOR IN-OPERATOR",pIdx->zName));
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "%s", pIdx->zName));
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
-
+
if( prRhsHasNull ){
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
i64 mask = (1<<nExpr)-1;
- sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
+ sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
iTab, 0, 0, (u8*)&mask, P4_INT64);
#endif
*prRhsHasNull = ++pParse->nMem;
@@ -91999,16 +102425,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
eType = IN_INDEX_EPH;
if( inFlags & IN_INDEX_LOOP ){
pParse->nQueryLoop = 0;
- if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
- eType = IN_INDEX_ROWID;
- }
}else if( prRhsHasNull ){
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
}
- sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
+ assert( pX->op==TK_IN );
+ sqlite3CodeRhsOfIN(pParse, pX, iTab);
+ if( rMayHaveNull ){
+ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull);
+ }
pParse->nQueryLoop = savedNQueryLoop;
- }else{
- pX->iTable = iTab;
}
if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
@@ -92016,14 +102441,15 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
n = sqlite3ExprVectorSize(pX->pLeft);
for(i=0; i<n; i++) aiMap[i] = i;
}
+ *piTab = iTab;
return eType;
}
#endif
#ifndef SQLITE_OMIT_SUBQUERY
/*
-** Argument pExpr is an (?, ?...) IN(...) expression. This
-** function allocates and returns a nul-terminated string containing
+** Argument pExpr is an (?, ?...) IN(...) expression. This
+** function allocates and returns a nul-terminated string containing
** the affinities to be used for each column of the comparison.
**
** It is the responsibility of the caller to ensure that the returned
@@ -92036,7 +102462,7 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
char *zRet;
assert( pExpr->op==TK_IN );
- zRet = sqlite3DbMallocZero(pParse->db, nVal+1);
+ zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);
if( zRet ){
int i;
for(i=0; i<nVal; i++){
@@ -92056,279 +102482,355 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
#ifndef SQLITE_OMIT_SUBQUERY
/*
-** Load the Parse object passed as the first argument with an error
+** Load the Parse object passed as the first argument with an error
** message of the form:
**
** "sub-select returns N columns - expected M"
-*/
+*/
SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
- const char *zFmt = "sub-select returns %d columns - expected %d";
- sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
+ if( pParse->nErr==0 ){
+ const char *zFmt = "sub-select returns %d columns - expected %d";
+ sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
+ }
}
#endif
/*
-** Generate code for scalar subqueries used as a subquery expression, EXISTS,
-** or IN operators. Examples:
-**
-** (SELECT a FROM b) -- subquery
-** EXISTS (SELECT a FROM b) -- EXISTS subquery
-** x IN (4,5,11) -- IN operator with list on right-hand side
-** x IN (SELECT a FROM b) -- IN operator with subquery on the right
-**
-** The pExpr parameter describes the expression that contains the IN
-** operator or subquery.
+** Expression pExpr is a vector that has been used in a context where
+** it is not permitted. If pExpr is a sub-select vector, this routine
+** loads the Parse object with a message of the form:
**
-** If parameter isRowid is non-zero, then expression pExpr is guaranteed
-** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference
-** to some integer key column of a table B-Tree. In this case, use an
-** intkey B-Tree to store the set of IN(...) values instead of the usual
-** (slower) variable length keys B-Tree.
+** "sub-select returns N columns - expected 1"
**
-** If rMayHaveNull is non-zero, that means that the operation is an IN
-** (not a SELECT or EXISTS) and that the RHS might contains NULLs.
-** All this routine does is initialize the register given by rMayHaveNull
-** to NULL. Calling routines will take care of changing this register
-** value to non-NULL if the RHS is NULL-free.
+** Or, if it is a regular scalar vector:
**
-** For a SELECT or EXISTS operator, return the register that holds the
-** result. For a multi-column SELECT, the result is stored in a contiguous
-** array of registers and the return value is the register of the left-most
-** result column. Return 0 for IN operators or if an error occurs.
+** "row value misused"
*/
+SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( pExpr->flags & EP_xIsSelect ){
+ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1);
+ }else
+#endif
+ {
+ sqlite3ErrorMsg(pParse, "row value misused");
+ }
+}
+
#ifndef SQLITE_OMIT_SUBQUERY
-SQLITE_PRIVATE int sqlite3CodeSubselect(
+/*
+** Generate code that will construct an ephemeral table containing all terms
+** in the RHS of an IN operator. The IN operator can be in either of two
+** forms:
+**
+** x IN (4,5,11) -- IN operator with list on right-hand side
+** x IN (SELECT a FROM b) -- IN operator with subquery on the right
+**
+** The pExpr parameter is the IN operator. The cursor number for the
+** constructed ephermeral table is returned. The first time the ephemeral
+** table is computed, the cursor number is also stored in pExpr->iTable,
+** however the cursor number returned might not be the same, as it might
+** have been duplicated using OP_OpenDup.
+**
+** If the LHS expression ("x" in the examples) is a column value, or
+** the SELECT statement returns a column value, then the affinity of that
+** column is used to build the index keys. If both 'x' and the
+** SELECT... statement are columns, then numeric affinity is used
+** if either column has NUMERIC or INTEGER affinity. If neither
+** 'x' nor the SELECT... statement are columns, then numeric affinity
+** is used.
+*/
+SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
Parse *pParse, /* Parsing context */
- Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
- int rHasNullFlag, /* Register that records whether NULLs exist in RHS */
- int isRowid /* If true, LHS of IN operator is a rowid */
+ Expr *pExpr, /* The IN operator */
+ int iTab /* Use this cursor number */
){
- int jmpIfDynamic = -1; /* One-time test address */
- int rReg = 0; /* Register storing resulting */
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( NEVER(v==0) ) return 0;
- sqlite3ExprCachePush(pParse);
+ int addrOnce = 0; /* Address of the OP_Once instruction at top */
+ int addr; /* Address of OP_OpenEphemeral instruction */
+ Expr *pLeft; /* the LHS of the IN operator */
+ KeyInfo *pKeyInfo = 0; /* Key information */
+ int nVal; /* Size of vector pLeft */
+ Vdbe *v; /* The prepared statement under construction */
+
+ v = pParse->pVdbe;
+ assert( v!=0 );
- /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it
+ /* The evaluation of the IN must be repeated every time it
** is encountered if any of the following is true:
**
** * The right-hand side is a correlated subquery
** * The right-hand side is an expression list containing variables
** * We are inside a trigger
**
- ** If all of the above are false, then we can run this code just once
- ** save the results, and reuse the same result on subsequent invocations.
+ ** If all of the above are false, then we can compute the RHS just once
+ ** and reuse it many names.
*/
- if( !ExprHasProperty(pExpr, EP_VarSelect) ){
- jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){
+ /* Reuse of the RHS is allowed */
+ /* If this routine has already been coded, but the previous code
+ ** might not have been invoked yet, so invoke it now as a subroutine.
+ */
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
+ pExpr->x.pSelect->selId));
+ }
+ sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
+ pExpr->y.sub.iAddr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
+ sqlite3VdbeJumpHere(v, addrOnce);
+ return;
+ }
+
+ /* Begin coding the subroutine */
+ ExprSetProperty(pExpr, EP_Subrtn);
+ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
+ pExpr->y.sub.regReturn = ++pParse->nMem;
+ pExpr->y.sub.iAddr =
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
+ VdbeComment((v, "return address"));
+
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
-#ifndef SQLITE_OMIT_EXPLAIN
- if( pParse->explain==2 ){
- char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %s%s SUBQUERY %d",
- jmpIfDynamic>=0?"":"CORRELATED ",
- pExpr->op==TK_IN?"LIST":"SCALAR",
- pParse->iNextSelectId
- );
- sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
+ /* Check to see if this is a vector IN operator */
+ pLeft = pExpr->pLeft;
+ nVal = sqlite3ExprVectorSize(pLeft);
+
+ /* Construct the ephemeral table that will contain the content of
+ ** RHS of the IN operator.
+ */
+ pExpr->iTable = iTab;
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal);
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId));
+ }else{
+ VdbeComment((v, "RHS of IN operator"));
}
#endif
+ pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
- switch( pExpr->op ){
- case TK_IN: {
- int addr; /* Address of OP_OpenEphemeral instruction */
- Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
- KeyInfo *pKeyInfo = 0; /* Key information */
- int nVal; /* Size of vector pLeft */
-
- nVal = sqlite3ExprVectorSize(pLeft);
- assert( !isRowid || nVal==1 );
-
- /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
- ** expression it is handled the same way. An ephemeral table is
- ** filled with index keys representing the results from the
- ** SELECT or the <exprlist>.
- **
- ** If the 'x' expression is a column value, or the SELECT...
- ** statement returns a column value, then the affinity of that
- ** column is used to build the index keys. If both 'x' and the
- ** SELECT... statement are columns, then numeric affinity is used
- ** if either column has NUMERIC or INTEGER affinity. If neither
- ** 'x' nor the SELECT... statement are columns, then numeric affinity
- ** is used.
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ /* Case 1: expr IN (SELECT ...)
+ **
+ ** Generate code to write the results of the select into the temporary
+ ** table allocated and opened above.
+ */
+ Select *pSelect = pExpr->x.pSelect;
+ ExprList *pEList = pSelect->pEList;
+
+ ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d",
+ addrOnce?"":"CORRELATED ", pSelect->selId
+ ));
+ /* If the LHS and RHS of the IN operator do not match, that
+ ** error will have been caught long before we reach this point. */
+ if( ALWAYS(pEList->nExpr==nVal) ){
+ SelectDest dest;
+ int i;
+ sqlite3SelectDestInit(&dest, SRT_Set, iTab);
+ dest.zAffSdst = exprINAffinity(pParse, pExpr);
+ pSelect->iLimit = 0;
+ testcase( pSelect->selFlags & SF_Distinct );
+ testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
+ if( sqlite3Select(pParse, pSelect, &dest) ){
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
+ sqlite3KeyInfoUnref(pKeyInfo);
+ return;
+ }
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
+ assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
+ assert( pEList!=0 );
+ assert( pEList->nExpr>0 );
+ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
+ for(i=0; i<nVal; i++){
+ Expr *p = sqlite3VectorFieldSubexpr(pLeft, i);
+ pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
+ pParse, p, pEList->a[i].pExpr
+ );
+ }
+ }
+ }else if( ALWAYS(pExpr->x.pList!=0) ){
+ /* Case 2: expr IN (exprlist)
+ **
+ ** For each expression, build an index key from the evaluation and
+ ** store it in the temporary table. If <expr> is a column, then use
+ ** that columns affinity when building index keys. If <expr> is not
+ ** a column, use numeric affinity.
+ */
+ char affinity; /* Affinity of the LHS of the IN */
+ int i;
+ ExprList *pList = pExpr->x.pList;
+ struct ExprList_item *pItem;
+ int r1, r2;
+ affinity = sqlite3ExprAffinity(pLeft);
+ if( affinity<=SQLITE_AFF_NONE ){
+ affinity = SQLITE_AFF_BLOB;
+ }else if( affinity==SQLITE_AFF_REAL ){
+ affinity = SQLITE_AFF_NUMERIC;
+ }
+ if( pKeyInfo ){
+ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
+ pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
+ }
+
+ /* Loop through each expression in <exprlist>. */
+ r1 = sqlite3GetTempReg(pParse);
+ r2 = sqlite3GetTempReg(pParse);
+ for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
+ Expr *pE2 = pItem->pExpr;
+
+ /* If the expression is not constant then we will need to
+ ** disable the test that was generated above that makes sure
+ ** this code only executes once. Because for a non-constant
+ ** expression we need to rerun this code each time.
*/
- pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral,
- pExpr->iTable, (isRowid?0:nVal));
- pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
+ if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
+ sqlite3VdbeChangeToNoop(v, addrOnce);
+ ExprClearProperty(pExpr, EP_Subrtn);
+ addrOnce = 0;
+ }
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- /* Case 1: expr IN (SELECT ...)
- **
- ** Generate code to write the results of the select into the temporary
- ** table allocated and opened above.
- */
- Select *pSelect = pExpr->x.pSelect;
- ExprList *pEList = pSelect->pEList;
-
- assert( !isRowid );
- /* If the LHS and RHS of the IN operator do not match, that
- ** error will have been caught long before we reach this point. */
- if( ALWAYS(pEList->nExpr==nVal) ){
- SelectDest dest;
- int i;
- sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
- dest.zAffSdst = exprINAffinity(pParse, pExpr);
- assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- pSelect->iLimit = 0;
- testcase( pSelect->selFlags & SF_Distinct );
- testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
- if( sqlite3Select(pParse, pSelect, &dest) ){
- sqlite3DbFree(pParse->db, dest.zAffSdst);
- sqlite3KeyInfoUnref(pKeyInfo);
- return 0;
- }
- sqlite3DbFree(pParse->db, dest.zAffSdst);
- assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
- assert( pEList!=0 );
- assert( pEList->nExpr>0 );
- assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
- for(i=0; i<nVal; i++){
- Expr *p = sqlite3VectorFieldSubexpr(pLeft, i);
- pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
- pParse, p, pEList->a[i].pExpr
- );
- }
- }
- }else if( ALWAYS(pExpr->x.pList!=0) ){
- /* Case 2: expr IN (exprlist)
- **
- ** For each expression, build an index key from the evaluation and
- ** store it in the temporary table. If <expr> is a column, then use
- ** that columns affinity when building index keys. If <expr> is not
- ** a column, use numeric affinity.
- */
- char affinity; /* Affinity of the LHS of the IN */
- int i;
- ExprList *pList = pExpr->x.pList;
- struct ExprList_item *pItem;
- int r1, r2, r3;
+ /* Evaluate the expression and insert it into the temp table */
+ sqlite3ExprCode(pParse, pE2, r1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r1, 1);
+ }
+ sqlite3ReleaseTempReg(pParse, r1);
+ sqlite3ReleaseTempReg(pParse, r2);
+ }
+ if( pKeyInfo ){
+ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
+ }
+ if( addrOnce ){
+ sqlite3VdbeJumpHere(v, addrOnce);
+ /* Subroutine return */
+ sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
+ sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
+ sqlite3ClearTempRegCache(pParse);
+ }
+}
+#endif /* SQLITE_OMIT_SUBQUERY */
- affinity = sqlite3ExprAffinity(pLeft);
- if( !affinity ){
- affinity = SQLITE_AFF_BLOB;
- }
- if( pKeyInfo ){
- assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
- pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- }
+/*
+** Generate code for scalar subqueries used as a subquery expression
+** or EXISTS operator:
+**
+** (SELECT a FROM b) -- subquery
+** EXISTS (SELECT a FROM b) -- EXISTS subquery
+**
+** The pExpr parameter is the SELECT or EXISTS operator to be coded.
+**
+** Return the register that holds the result. For a multi-column SELECT,
+** the result is stored in a contiguous array of registers and the
+** return value is the register of the left-most result column.
+** Return 0 if an error occurs.
+*/
+#ifndef SQLITE_OMIT_SUBQUERY
+SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
+ int addrOnce = 0; /* Address of OP_Once at top of subroutine */
+ int rReg = 0; /* Register storing resulting */
+ Select *pSel; /* SELECT statement to encode */
+ SelectDest dest; /* How to deal with SELECT result */
+ int nReg; /* Registers to allocate */
+ Expr *pLimit; /* New limit expression */
- /* Loop through each expression in <exprlist>. */
- r1 = sqlite3GetTempReg(pParse);
- r2 = sqlite3GetTempReg(pParse);
- if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
- for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
- Expr *pE2 = pItem->pExpr;
- int iValToIns;
-
- /* If the expression is not constant then we will need to
- ** disable the test that was generated above that makes sure
- ** this code only executes once. Because for a non-constant
- ** expression we need to rerun this code each time.
- */
- if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
- sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
- jmpIfDynamic = -1;
- }
+ Vdbe *v = pParse->pVdbe;
+ assert( v!=0 );
+ testcase( pExpr->op==TK_EXISTS );
+ testcase( pExpr->op==TK_SELECT );
+ assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
+ assert( ExprHasProperty(pExpr, EP_xIsSelect) );
+ pSel = pExpr->x.pSelect;
- /* Evaluate the expression and insert it into the temp table */
- if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
- sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
- }else{
- r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
- if( isRowid ){
- sqlite3VdbeAddOp2(v, OP_MustBeInt, r3,
- sqlite3VdbeCurrentAddr(v)+2);
- VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
- }else{
- sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
- sqlite3ExprCacheAffinityChange(pParse, r3, 1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
- }
- }
- }
- sqlite3ReleaseTempReg(pParse, r1);
- sqlite3ReleaseTempReg(pParse, r2);
- }
- if( pKeyInfo ){
- sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
- }
- break;
+ /* The evaluation of the EXISTS/SELECT must be repeated every time it
+ ** is encountered if any of the following is true:
+ **
+ ** * The right-hand side is a correlated subquery
+ ** * The right-hand side is an expression list containing variables
+ ** * We are inside a trigger
+ **
+ ** If all of the above are false, then we can run this code just once
+ ** save the results, and reuse the same result on subsequent invocations.
+ */
+ if( !ExprHasProperty(pExpr, EP_VarSelect) ){
+ /* If this routine has already been coded, then invoke it as a
+ ** subroutine. */
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
+ ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId));
+ sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
+ pExpr->y.sub.iAddr);
+ return pExpr->iTable;
}
- case TK_EXISTS:
- case TK_SELECT:
- default: {
- /* Case 3: (SELECT ... FROM ...)
- ** or: EXISTS(SELECT ... FROM ...)
- **
- ** For a SELECT, generate code to put the values for all columns of
- ** the first row into an array of registers and return the index of
- ** the first register.
- **
- ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists)
- ** into a register and return that register number.
- **
- ** In both cases, the query is augmented with "LIMIT 1". Any
- ** preexisting limit is discarded in place of the new LIMIT 1.
- */
- Select *pSel; /* SELECT statement to encode */
- SelectDest dest; /* How to deal with SELECT result */
- int nReg; /* Registers to allocate */
+ /* Begin coding the subroutine */
+ ExprSetProperty(pExpr, EP_Subrtn);
+ pExpr->y.sub.regReturn = ++pParse->nMem;
+ pExpr->y.sub.iAddr =
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
+ VdbeComment((v, "return address"));
- testcase( pExpr->op==TK_EXISTS );
- testcase( pExpr->op==TK_SELECT );
- assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
- assert( ExprHasProperty(pExpr, EP_xIsSelect) );
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ }
- pSel = pExpr->x.pSelect;
- nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
- sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
- pParse->nMem += nReg;
- if( pExpr->op==TK_SELECT ){
- dest.eDest = SRT_Mem;
- dest.iSdst = dest.iSDParm;
- dest.nSdst = nReg;
- sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
- VdbeComment((v, "Init subquery result"));
- }else{
- dest.eDest = SRT_Exists;
- sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
- VdbeComment((v, "Init EXISTS result"));
- }
- sqlite3ExprDelete(pParse->db, pSel->pLimit);
- pSel->pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,
- &sqlite3IntTokens[1], 0);
- pSel->iLimit = 0;
- pSel->selFlags &= ~SF_MultiValue;
- if( sqlite3Select(pParse, pSel, &dest) ){
- return 0;
- }
- rReg = dest.iSDParm;
- ExprSetVVAProperty(pExpr, EP_NoReduce);
- break;
+ /* For a SELECT, generate code to put the values for all columns of
+ ** the first row into an array of registers and return the index of
+ ** the first register.
+ **
+ ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists)
+ ** into a register and return that register number.
+ **
+ ** In both cases, the query is augmented with "LIMIT 1". Any
+ ** preexisting limit is discarded in place of the new LIMIT 1.
+ */
+ ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d",
+ addrOnce?"":"CORRELATED ", pSel->selId));
+ nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
+ sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
+ pParse->nMem += nReg;
+ if( pExpr->op==TK_SELECT ){
+ dest.eDest = SRT_Mem;
+ dest.iSdst = dest.iSDParm;
+ dest.nSdst = nReg;
+ sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
+ VdbeComment((v, "Init subquery result"));
+ }else{
+ dest.eDest = SRT_Exists;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
+ VdbeComment((v, "Init EXISTS result"));
+ }
+ if( pSel->pLimit ){
+ /* The subquery already has a limit. If the pre-existing limit is X
+ ** then make the new limit X<>0 so that the new limit is either 1 or 0 */
+ sqlite3 *db = pParse->db;
+ pLimit = sqlite3Expr(db, TK_INTEGER, "0");
+ if( pLimit ){
+ pLimit->affExpr = SQLITE_AFF_NUMERIC;
+ pLimit = sqlite3PExpr(pParse, TK_NE,
+ sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
}
+ sqlite3ExprDelete(db, pSel->pLimit->pLeft);
+ pSel->pLimit->pLeft = pLimit;
+ }else{
+ /* If there is no pre-existing limit add a limit of 1 */
+ pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1");
+ pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0);
}
-
- if( rHasNullFlag ){
- sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag);
+ pSel->iLimit = 0;
+ if( sqlite3Select(pParse, pSel, &dest) ){
+ return 0;
}
+ pExpr->iTable = rReg = dest.iSDParm;
+ ExprSetVVAProperty(pExpr, EP_NoReduce);
+ if( addrOnce ){
+ sqlite3VdbeJumpHere(v, addrOnce);
- if( jmpIfDynamic>=0 ){
- sqlite3VdbeJumpHere(v, jmpIfDynamic);
+ /* Subroutine return */
+ sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
+ sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
+ sqlite3ClearTempRegCache(pParse);
}
- sqlite3ExprCachePop(pParse);
return rReg;
}
@@ -92336,9 +102838,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
#ifndef SQLITE_OMIT_SUBQUERY
/*
-** Expr pIn is an IN(...) expression. This function checks that the
-** sub-select on the RHS of the IN() operator has the same number of
-** columns as the vector on the LHS. Or, if the RHS of the IN() is not
+** Expr pIn is an IN(...) expression. This function checks that the
+** sub-select on the RHS of the IN() operator has the same number of
+** columns as the vector on the LHS. Or, if the RHS of the IN() is not
** a sub-query, that the LHS is a vector of size 1.
*/
SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
@@ -92349,11 +102851,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
return 1;
}
}else if( nVector!=1 ){
- if( (pIn->pLeft->flags & EP_xIsSelect) ){
- sqlite3SubselectError(pParse, nVector, 1);
- }else{
- sqlite3ErrorMsg(pParse, "row value misused");
- }
+ sqlite3VectorErrorMsg(pParse, pIn->pLeft);
return 1;
}
return 0;
@@ -92367,18 +102865,18 @@ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
** x IN (SELECT ...)
** x IN (value, value, ...)
**
-** The left-hand side (LHS) is a scalar or vector expression. The
+** The left-hand side (LHS) is a scalar or vector expression. The
** right-hand side (RHS) is an array of zero or more scalar values, or a
** subquery. If the RHS is a subquery, the number of result columns must
** match the number of columns in the vector on the LHS. If the RHS is
-** a list of values, the LHS must be a scalar.
+** a list of values, the LHS must be a scalar.
**
** The IN operator is true if the LHS value is contained within the RHS.
-** The result is false if the LHS is definitely not in the RHS. The
-** result is NULL if the presence of the LHS in the RHS cannot be
+** The result is false if the LHS is definitely not in the RHS. The
+** result is NULL if the presence of the LHS in the RHS cannot be
** determined due to NULLs.
**
-** This routine generates code that jumps to destIfFalse if the LHS is not
+** This routine generates code that jumps to destIfFalse if the LHS is not
** contained within the RHS. If due to NULLs we cannot determine if the LHS
** is contained in the RHS then jump to destIfNull. If the LHS is contained
** within the RHS then fall through.
@@ -92407,8 +102905,11 @@ static void sqlite3ExprCodeIN(
int destStep6 = 0; /* Start of code for Step 6 */
int addrTruthOp; /* Address of opcode that determines the IN is true */
int destNotNull; /* Jump here if a comparison is not true in step 6 */
- int addrTop; /* Top of the step-6 loop */
+ int addrTop; /* Top of the step-6 loop */
+ int iTab = 0; /* Index to use */
+ u8 okConstFactor = pParse->okConstFactor;
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
pLeft = pExpr->pLeft;
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
zAff = exprINAffinity(pParse, pExpr);
@@ -92419,7 +102920,7 @@ static void sqlite3ExprCodeIN(
if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
/* Attempt to compute the RHS. After this step, if anything other than
- ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable
+ ** IN_INDEX_NOOP is returned, the table opened with cursor iTab
** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
** the RHS has not yet been coded. */
v = pParse->pVdbe;
@@ -92427,10 +102928,11 @@ static void sqlite3ExprCodeIN(
VdbeNoopComment((v, "begin IN expr"));
eType = sqlite3FindInIndex(pParse, pExpr,
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
- destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
+ destIfFalse==destIfNull ? 0 : &rRhsHasNull,
+ aiMap, &iTab);
assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
- || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
+ || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
);
#ifdef SQLITE_DEBUG
/* Confirm that aiMap[] contains nVector integer values between 0 and
@@ -92442,17 +102944,22 @@ static void sqlite3ExprCodeIN(
}
#endif
- /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
- ** vector, then it is stored in an array of nVector registers starting
+ /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
+ ** vector, then it is stored in an array of nVector registers starting
** at r1.
**
** sqlite3FindInIndex() might have reordered the fields of the LHS vector
** so that the fields are in the same order as an existing index. The
** aiMap[] array contains a mapping from the original LHS field order to
** the field order that matches the RHS index.
- */
- sqlite3ExprCachePush(pParse);
+ **
+ ** Avoid factoring the LHS of the IN(...) expression out of the loop,
+ ** even if it is constant, as OP_Affinity may be used on the register
+ ** by code generated below. */
+ assert( pParse->okConstFactor==okConstFactor );
+ pParse->okConstFactor = 0;
rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);
+ pParse->okConstFactor = okConstFactor;
for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
if( i==nVector ){
/* LHS fields are not reordered */
@@ -92474,7 +102981,7 @@ static void sqlite3ExprCodeIN(
if( eType==IN_INDEX_NOOP ){
ExprList *pList = pExpr->x.pList;
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- int labelOk = sqlite3VdbeMakeLabel(v);
+ int labelOk = sqlite3VdbeMakeLabel(pParse);
int r2, regToFree;
int regCkNull = 0;
int ii;
@@ -92488,19 +102995,25 @@ static void sqlite3ExprCodeIN(
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
}
+ sqlite3ReleaseTempReg(pParse, regToFree);
if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
- sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2,
+ int op = rLhs!=r2 ? OP_Eq : OP_NotNull;
+ sqlite3VdbeAddOp4(v, op, rLhs, labelOk, r2,
(void*)pColl, P4_COLLSEQ);
- VdbeCoverageIf(v, ii<pList->nExpr-1);
- VdbeCoverageIf(v, ii==pList->nExpr-1);
+ VdbeCoverageIf(v, ii<pList->nExpr-1 && op==OP_Eq);
+ VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_Eq);
+ VdbeCoverageIf(v, ii<pList->nExpr-1 && op==OP_NotNull);
+ VdbeCoverageIf(v, ii==pList->nExpr-1 && op==OP_NotNull);
sqlite3VdbeChangeP5(v, zAff[0]);
}else{
+ int op = rLhs!=r2 ? OP_Ne : OP_IsNull;
assert( destIfNull==destIfFalse );
- sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2,
- (void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
+ sqlite3VdbeAddOp4(v, op, rLhs, destIfFalse, r2,
+ (void*)pColl, P4_COLLSEQ);
+ VdbeCoverageIf(v, op==OP_Ne);
+ VdbeCoverageIf(v, op==OP_IsNull);
sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
}
- sqlite3ReleaseTempReg(pParse, regToFree);
}
if( regCkNull ){
sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
@@ -92518,8 +103031,9 @@ static void sqlite3ExprCodeIN(
if( destIfNull==destIfFalse ){
destStep2 = destIfFalse;
}else{
- destStep2 = destStep6 = sqlite3VdbeMakeLabel(v);
+ destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse);
}
+ if( pParse->nErr ) goto sqlite3ExprCodeIN_finished;
for(i=0; i<nVector; i++){
Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
if( sqlite3ExprCanBeNull(p) ){
@@ -92536,19 +103050,19 @@ static void sqlite3ExprCodeIN(
/* In this case, the RHS is the ROWID of table b-tree and so we also
** know that the RHS is non-NULL. Hence, we combine steps 3 and 4
** into a single opcode. */
- sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iTab, destIfFalse, rLhs);
VdbeCoverage(v);
addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */
}else{
sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
if( destIfFalse==destIfNull ){
/* Combine Step 3 and Step 5 into a single opcode */
- sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse,
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iTab, destIfFalse,
rLhs, nVector); VdbeCoverage(v);
goto sqlite3ExprCodeIN_finished;
}
/* Ordinary Step 3, for the case where FALSE and NULL are distinct */
- addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0,
+ addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, iTab, 0,
rLhs, nVector); VdbeCoverage(v);
}
@@ -92561,7 +103075,7 @@ static void sqlite3ExprCodeIN(
}
/* Step 5. If we do not care about the difference between NULL and
- ** FALSE, then just return false.
+ ** FALSE, then just return false.
*/
if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse);
@@ -92573,10 +103087,10 @@ static void sqlite3ExprCodeIN(
** of the RHS.
*/
if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
- addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, destIfFalse);
VdbeCoverage(v);
if( nVector>1 ){
- destNotNull = sqlite3VdbeMakeLabel(v);
+ destNotNull = sqlite3VdbeMakeLabel(pParse);
}else{
/* For nVector==1, combine steps 6 and 7 by immediately returning
** FALSE if the first comparison is not NULL */
@@ -92588,7 +103102,7 @@ static void sqlite3ExprCodeIN(
int r3 = sqlite3GetTempReg(pParse);
p = sqlite3VectorFieldSubexpr(pLeft, i);
pColl = sqlite3ExprCollSeq(pParse, p);
- sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3);
+ sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3);
sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
(void*)pColl, P4_COLLSEQ);
VdbeCoverage(v);
@@ -92597,7 +103111,7 @@ static void sqlite3ExprCodeIN(
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
if( nVector>1 ){
sqlite3VdbeResolveLabel(v, destNotNull);
- sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1);
+ sqlite3VdbeAddOp2(v, OP_Next, iTab, addrTop+1);
VdbeCoverage(v);
/* Step 7: If we reach this point, we know that the result must
@@ -92610,7 +103124,6 @@ static void sqlite3ExprCodeIN(
sqlite3ExprCodeIN_finished:
if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs);
- sqlite3ExprCachePop(pParse);
VdbeComment((v, "end IN expr"));
sqlite3ExprCodeIN_oom_error:
sqlite3DbFree(pParse->db, aiMap);
@@ -92623,7 +103136,7 @@ sqlite3ExprCodeIN_oom_error:
** Generate an instruction that will put the floating point
** value described by z[0..n-1] into register iMem.
**
-** The z[] string will probably not be zero-terminated. But the
+** The z[] string will probably not be zero-terminated. But the
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
@@ -92658,165 +103171,26 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
const char *z = pExpr->u.zToken;
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
- if( c==0 || (c==2 && negFlag) ){
- if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
- sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
- }else{
+ if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
#ifndef SQLITE_OMIT_HEX_INTEGER
if( sqlite3_strnicmp(z,"0x",2)==0 ){
- sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
+ sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z);
}else
#endif
{
codeReal(v, z, negFlag, iMem);
}
#endif
- }
- }
-}
-
-/*
-** Erase column-cache entry number i
-*/
-static void cacheEntryClear(Parse *pParse, int i){
- if( pParse->aColCache[i].tempReg ){
- if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
- pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
- }
- }
- pParse->nColCache--;
- if( i<pParse->nColCache ){
- pParse->aColCache[i] = pParse->aColCache[pParse->nColCache];
- }
-}
-
-
-/*
-** Record in the column cache that a particular column from a
-** particular table is stored in a particular register.
-*/
-SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
- int i;
- int minLru;
- int idxLru;
- struct yColCache *p;
-
- /* Unless an error has occurred, register numbers are always positive. */
- assert( iReg>0 || pParse->nErr || pParse->db->mallocFailed );
- assert( iCol>=-1 && iCol<32768 ); /* Finite column numbers */
-
- /* The SQLITE_ColumnCache flag disables the column cache. This is used
- ** for testing only - to verify that SQLite always gets the same answer
- ** with and without the column cache.
- */
- if( OptimizationDisabled(pParse->db, SQLITE_ColumnCache) ) return;
-
- /* First replace any existing entry.
- **
- ** Actually, the way the column cache is currently used, we are guaranteed
- ** that the object will never already be in cache. Verify this guarantee.
- */
-#ifndef NDEBUG
- for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
- assert( p->iTable!=iTab || p->iColumn!=iCol );
- }
-#endif
-
- /* If the cache is already full, delete the least recently used entry */
- if( pParse->nColCache>=SQLITE_N_COLCACHE ){
- minLru = 0x7fffffff;
- idxLru = -1;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- if( p->lru<minLru ){
- idxLru = i;
- minLru = p->lru;
- }
- }
- p = &pParse->aColCache[idxLru];
- }else{
- p = &pParse->aColCache[pParse->nColCache++];
- }
-
- /* Add the new entry to the end of the cache */
- p->iLevel = pParse->iCacheLevel;
- p->iTable = iTab;
- p->iColumn = iCol;
- p->iReg = iReg;
- p->tempReg = 0;
- p->lru = pParse->iCacheCnt++;
-}
-
-/*
-** Indicate that registers between iReg..iReg+nReg-1 are being overwritten.
-** Purge the range of registers from the column cache.
-*/
-SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
- int i = 0;
- while( i<pParse->nColCache ){
- struct yColCache *p = &pParse->aColCache[i];
- if( p->iReg >= iReg && p->iReg < iReg+nReg ){
- cacheEntryClear(pParse, i);
- }else{
- i++;
- }
- }
-}
-
-/*
-** Remember the current column cache context. Any new entries added
-** added to the column cache after this call are removed when the
-** corresponding pop occurs.
-*/
-SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
- pParse->iCacheLevel++;
-#ifdef SQLITE_DEBUG
- if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
- printf("PUSH to %d\n", pParse->iCacheLevel);
- }
-#endif
-}
-
-/*
-** Remove from the column cache any entries that were added since the
-** the previous sqlite3ExprCachePush operation. In other words, restore
-** the cache to the state it was in prior the most recent Push.
-*/
-SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
- int i = 0;
- assert( pParse->iCacheLevel>=1 );
- pParse->iCacheLevel--;
-#ifdef SQLITE_DEBUG
- if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
- printf("POP to %d\n", pParse->iCacheLevel);
- }
-#endif
- while( i<pParse->nColCache ){
- if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){
- cacheEntryClear(pParse, i);
}else{
- i++;
+ if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; }
+ sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
}
}
}
-/*
-** When a cached column is reused, make sure that its register is
-** no longer available as a temp register. ticket #3879: that same
-** register might be in the cache in multiple places, so be sure to
-** get them all.
-*/
-static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
- int i;
- struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
- if( p->iReg==iReg ){
- p->tempReg = 0;
- }
- }
-}
/* Generate code that will load into register regOut a value that is
** appropriate for the iIdxCol-th column of index pIdx.
@@ -92832,47 +103206,98 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(
if( iTabCol==XN_EXPR ){
assert( pIdx->aColExpr );
assert( pIdx->aColExpr->nExpr>iIdxCol );
- pParse->iSelfTab = iTabCur;
+ pParse->iSelfTab = iTabCur + 1;
sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
+ pParse->iSelfTab = 0;
}else{
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
iTabCol, regOut);
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/*
+** Generate code that will compute the value of generated column pCol
+** and store the result in register regOut
+*/
+SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
+ Parse *pParse,
+ Column *pCol,
+ int regOut
+){
+ int iAddr;
+ Vdbe *v = pParse->pVdbe;
+ assert( v!=0 );
+ assert( pParse->iSelfTab!=0 );
+ if( pParse->iSelfTab>0 ){
+ iAddr = sqlite3VdbeAddOp3(v, OP_IfNullRow, pParse->iSelfTab-1, 0, regOut);
+ }else{
+ iAddr = 0;
+ }
+ sqlite3ExprCodeCopy(pParse, pCol->pDflt, regOut);
+ if( pCol->affinity>=SQLITE_AFF_TEXT ){
+ sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
+ }
+ if( iAddr ) sqlite3VdbeJumpHere(v, iAddr);
+}
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+
/*
** Generate code to extract the value of the iCol-th column of a table.
*/
SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
- Vdbe *v, /* The VDBE under construction */
+ Vdbe *v, /* Parsing context */
Table *pTab, /* The table containing the value */
int iTabCur, /* The table cursor. Or the PK cursor for WITHOUT ROWID */
int iCol, /* Index of the column to extract */
int regOut /* Extract the value into this register */
){
+ Column *pCol;
+ assert( v!=0 );
+ if( pTab==0 ){
+ sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
+ return;
+ }
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
}else{
- int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
- int x = iCol;
- if( !HasRowid(pTab) && !IsVirtual(pTab) ){
- x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
+ int op;
+ int x;
+ if( IsVirtual(pTab) ){
+ op = OP_VColumn;
+ x = iCol;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){
+ Parse *pParse = sqlite3VdbeParser(v);
+ if( pCol->colFlags & COLFLAG_BUSY ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName);
+ }else{
+ int savedSelfTab = pParse->iSelfTab;
+ pCol->colFlags |= COLFLAG_BUSY;
+ pParse->iSelfTab = iTabCur+1;
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, regOut);
+ pParse->iSelfTab = savedSelfTab;
+ pCol->colFlags &= ~COLFLAG_BUSY;
+ }
+ return;
+#endif
+ }else if( !HasRowid(pTab) ){
+ testcase( iCol!=sqlite3TableColumnToStorage(pTab, iCol) );
+ x = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
+ op = OP_Column;
+ }else{
+ x = sqlite3TableColumnToStorage(pTab,iCol);
+ testcase( x!=iCol );
+ op = OP_Column;
}
sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut);
- }
- if( iCol>=0 ){
sqlite3ColumnDefault(v, pTab, iCol, regOut);
}
}
/*
** Generate code that will extract the iColumn-th column from
-** table pTab and store the column value in a register.
-**
-** An effort is made to store the column value in register iReg. This
-** is not garanteeed for GetColumn() - the result can be stored in
-** any register. But the result is guaranteed to land in register iReg
-** for GetColumnToReg().
+** table pTab and store the column value in register iReg.
**
** There must be an open cursor to pTab in iTable when this routine
** is called. If iColumn<0 then code is generated that extracts the rowid.
@@ -92885,103 +103310,30 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
int iReg, /* Store results here */
u8 p5 /* P5 value for OP_Column + FLAGS */
){
- Vdbe *v = pParse->pVdbe;
- int i;
- struct yColCache *p;
-
- for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
- if( p->iTable==iTable && p->iColumn==iColumn ){
- p->lru = pParse->iCacheCnt++;
- sqlite3ExprCachePinRegister(pParse, p->iReg);
- return p->iReg;
- }
- }
- assert( v!=0 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg);
+ assert( pParse->pVdbe!=0 );
+ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
- sqlite3VdbeChangeP5(v, p5);
- }else{
- sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg);
+ VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ if( pOp->opcode==OP_Column ) pOp->p5 = p5;
}
return iReg;
}
-SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(
- Parse *pParse, /* Parsing and code generating context */
- Table *pTab, /* Description of the table we are reading from */
- int iColumn, /* Index of the table column */
- int iTable, /* The cursor pointing to the table */
- int iReg /* Store results here */
-){
- int r1 = sqlite3ExprCodeGetColumn(pParse, pTab, iColumn, iTable, iReg, 0);
- if( r1!=iReg ) sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, r1, iReg);
-}
-
-
-/*
-** Clear all column cache entries.
-*/
-SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
- int i;
-
-#if SQLITE_DEBUG
- if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
- printf("CLEAR\n");
- }
-#endif
- for(i=0; i<pParse->nColCache; i++){
- if( pParse->aColCache[i].tempReg
- && pParse->nTempReg<ArraySize(pParse->aTempReg)
- ){
- pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
- }
- }
- pParse->nColCache = 0;
-}
-
-/*
-** Record the fact that an affinity change has occurred on iCount
-** registers starting with iStart.
-*/
-SQLITE_PRIVATE void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){
- sqlite3ExprCacheRemove(pParse, iStart, iCount);
-}
/*
** Generate code to move content from registers iFrom...iFrom+nReg-1
-** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.
+** over to iTo..iTo+nReg-1.
*/
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
- assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
- sqlite3ExprCacheRemove(pParse, iFrom, nReg);
-}
-
-#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
-/*
-** Return true if any register in the range iFrom..iTo (inclusive)
-** is used as part of the column cache.
-**
-** This routine is used within assert() and testcase() macros only
-** and does not appear in a normal build.
-*/
-static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
- int i;
- struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
- int r = p->iReg;
- if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/
- }
- return 0;
}
-#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
-
/*
** Convert a scalar expression node to a TK_REGISTER referencing
** register iReg. The caller must ensure that iReg already contains
** the correct value for the expression.
*/
-static void exprToRegister(Expr *p, int iReg){
+static void exprToRegister(Expr *pExpr, int iReg){
+ Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
p->op2 = p->op;
p->op = TK_REGISTER;
p->iTable = iReg;
@@ -93006,19 +103358,141 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
}else{
*piFreeable = 0;
if( p->op==TK_SELECT ){
- iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
+#if SQLITE_OMIT_SUBQUERY
+ iResult = 0;
+#else
+ iResult = sqlite3CodeSubselect(pParse, p);
+#endif
}else{
int i;
iResult = pParse->nMem+1;
pParse->nMem += nResult;
for(i=0; i<nResult; i++){
- sqlite3ExprCode(pParse, p->x.pList->a[i].pExpr, i+iResult);
+ sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
}
}
}
return iResult;
}
+/*
+** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5)
+** so that a subsequent copy will not be merged into this one.
+*/
+static void setDoNotMergeFlagOnCopy(Vdbe *v){
+ if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
+ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
+ }
+}
+
+/*
+** Generate code to implement special SQL functions that are implemented
+** in-line rather than by using the usual callbacks.
+*/
+static int exprCodeInlineFunction(
+ Parse *pParse, /* Parsing context */
+ ExprList *pFarg, /* List of function arguments */
+ int iFuncId, /* Function ID. One of the INTFUNC_... values */
+ int target /* Store function result in this register */
+){
+ int nFarg;
+ Vdbe *v = pParse->pVdbe;
+ assert( v!=0 );
+ assert( pFarg!=0 );
+ nFarg = pFarg->nExpr;
+ assert( nFarg>0 ); /* All in-line functions have at least one argument */
+ switch( iFuncId ){
+ case INLINEFUNC_coalesce: {
+ /* Attempt a direct implementation of the built-in COALESCE() and
+ ** IFNULL() functions. This avoids unnecessary evaluation of
+ ** arguments past the first non-NULL argument.
+ */
+ int endCoalesce = sqlite3VdbeMakeLabel(pParse);
+ int i;
+ assert( nFarg>=2 );
+ sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
+ for(i=1; i<nFarg; i++){
+ sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
+ VdbeCoverage(v);
+ sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
+ }
+ setDoNotMergeFlagOnCopy(v);
+ sqlite3VdbeResolveLabel(v, endCoalesce);
+ break;
+ }
+ case INLINEFUNC_iif: {
+ Expr caseExpr;
+ memset(&caseExpr, 0, sizeof(caseExpr));
+ caseExpr.op = TK_CASE;
+ caseExpr.x.pList = pFarg;
+ return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
+ }
+
+ default: {
+ /* The UNLIKELY() function is a no-op. The result is the value
+ ** of the first argument.
+ */
+ assert( nFarg==1 || nFarg==2 );
+ target = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
+ break;
+ }
+
+ /***********************************************************************
+ ** Test-only SQL functions that are only usable if enabled
+ ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
+ */
+ case INLINEFUNC_expr_compare: {
+ /* Compare two expressions using sqlite3ExprCompare() */
+ assert( nFarg==2 );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
+ target);
+ break;
+ }
+
+ case INLINEFUNC_expr_implies_expr: {
+ /* Compare two expressions using sqlite3ExprImpliesExpr() */
+ assert( nFarg==2 );
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
+ target);
+ break;
+ }
+
+ case INLINEFUNC_implies_nonnull_row: {
+ /* REsult of sqlite3ExprImpliesNonNullRow() */
+ Expr *pA1;
+ assert( nFarg==2 );
+ pA1 = pFarg->a[1].pExpr;
+ if( pA1->op==TK_COLUMN ){
+ sqlite3VdbeAddOp2(v, OP_Integer,
+ sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
+ target);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+ }
+ break;
+ }
+
+#ifdef SQLITE_DEBUG
+ case INLINEFUNC_affinity: {
+ /* The AFFINITY() function evaluates to a string that describes
+ ** the type affinity of the argument. This is used for testing of
+ ** the SQLite type logic.
+ */
+ const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
+ char aff;
+ assert( nFarg==1 );
+ aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
+ sqlite3VdbeLoadString(v, target,
+ (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
+ break;
+ }
+#endif
+ }
+ return target;
+}
+
/*
** Generate code into the current Vdbe to evaluate the given
@@ -93042,50 +103516,133 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
int p5 = 0;
assert( target>0 && target<=pParse->nMem );
- if( v==0 ){
- assert( pParse->db->mallocFailed );
- return 0;
- }
+ assert( v!=0 );
+expr_code_doover:
if( pExpr==0 ){
op = TK_NULL;
}else{
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
- struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
+ struct AggInfo_col *pCol;
+ assert( pAggInfo!=0 );
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
return pCol->iMem;
}else if( pAggInfo->useSortingIdx ){
+ Table *pTab = pCol->pTab;
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
+ if( pCol->iColumn<0 ){
+ VdbeComment((v,"%s.rowid",pTab->zName));
+ }else{
+ VdbeComment((v,"%s.%s",pTab->zName,pTab->aCol[pCol->iColumn].zName));
+ if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
+ }
+ }
return target;
}
/* Otherwise, fall thru into the TK_COLUMN case */
+ /* no break */ deliberate_fall_through
}
case TK_COLUMN: {
int iTab = pExpr->iTable;
+ int iReg;
+ if( ExprHasProperty(pExpr, EP_FixedCol) ){
+ /* This COLUMN expression is really a constant due to WHERE clause
+ ** constraints, and that constant is coded by the pExpr->pLeft
+ ** expresssion. However, make sure the constant has the correct
+ ** datatype by applying the Affinity of the table column to the
+ ** constant.
+ */
+ int aff;
+ iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
+ if( pExpr->y.pTab ){
+ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
+ }else{
+ aff = pExpr->affExpr;
+ }
+ if( aff>SQLITE_AFF_BLOB ){
+ static const char zAff[] = "B\000C\000D\000E";
+ assert( SQLITE_AFF_BLOB=='A' );
+ assert( SQLITE_AFF_TEXT=='B' );
+ sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
+ &zAff[(aff-'B')*2], P4_STATIC);
+ }
+ return iReg;
+ }
if( iTab<0 ){
- if( pParse->ckBase>0 ){
- /* Generating CHECK constraints or inserting into partial index */
- return pExpr->iColumn + pParse->ckBase;
+ if( pParse->iSelfTab<0 ){
+ /* Other columns in the same row for CHECK constraints or
+ ** generated columns or for inserting into partial index.
+ ** The row is unpacked into registers beginning at
+ ** 0-(pParse->iSelfTab). The rowid (if any) is in a register
+ ** immediately prior to the first column.
+ */
+ Column *pCol;
+ Table *pTab = pExpr->y.pTab;
+ int iSrc;
+ int iCol = pExpr->iColumn;
+ assert( pTab!=0 );
+ assert( iCol>=XN_ROWID );
+ assert( iCol<pTab->nCol );
+ if( iCol<0 ){
+ return -1-pParse->iSelfTab;
+ }
+ pCol = pTab->aCol + iCol;
+ testcase( iCol!=sqlite3TableColumnToStorage(pTab,iCol) );
+ iSrc = sqlite3TableColumnToStorage(pTab, iCol) - pParse->iSelfTab;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pCol->colFlags & COLFLAG_GENERATED ){
+ if( pCol->colFlags & COLFLAG_BUSY ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"",
+ pCol->zName);
+ return 0;
+ }
+ pCol->colFlags |= COLFLAG_BUSY;
+ if( pCol->colFlags & COLFLAG_NOTAVAIL ){
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc);
+ }
+ pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL);
+ return iSrc;
+ }else
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+ if( pCol->affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target);
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
+ return target;
+ }else{
+ return iSrc;
+ }
}else{
/* Coding an expression that is part of an index where column names
** in the index refer to the table to which the index belongs */
- iTab = pParse->iSelfTab;
+ iTab = pParse->iSelfTab - 1;
}
}
- return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
+ iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
+ if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
+ }
+ return iReg;
}
case TK_INTEGER: {
codeInteger(pParse, pExpr, 0, target);
return target;
}
+ case TK_TRUEFALSE: {
+ sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target);
+ return target;
+ }
#ifndef SQLITE_OMIT_FLOATING_POINT
case TK_FLOAT: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
@@ -93098,7 +103655,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
return target;
}
- case TK_NULL: {
+ default: {
+ /* Make NULL the default case so that if a bug causes an illegal
+ ** Expr node to be passed into this function, it will be handled
+ ** sanely and not crash. But keep the assert() to bring the problem
+ ** to the attention of the developers. */
+ assert( op==TK_NULL );
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
return target;
}
@@ -93124,9 +103686,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( pExpr->u.zToken[0]!=0 );
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
if( pExpr->u.zToken[1]!=0 ){
- 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);
+ const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
+ assert( pExpr->u.zToken[0]=='?' || (z && !strcmp(pExpr->u.zToken, z)) );
+ pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
+ sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
}
return target;
}
@@ -93143,8 +103706,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
}
sqlite3VdbeAddOp2(v, OP_Cast, target,
sqlite3AffinityType(pExpr->u.zToken, 0));
- testcase( usedAsColumnCache(pParse, inReg, inReg) );
- sqlite3ExprCacheAffinityChange(pParse, inReg, 1);
return inReg;
}
#endif /* SQLITE_OMIT_CAST */
@@ -93166,7 +103727,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pLeft, pExpr->pRight, op,
- r1, r2, inReg, SQLITE_STOREP2 | p5);
+ r1, r2, inReg, SQLITE_STOREP2 | p5,
+ ExprHasProperty(pExpr,EP_Commuted));
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -93188,7 +103750,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
case TK_BITOR:
case TK_SLASH:
case TK_LSHIFT:
- case TK_RSHIFT:
+ case TK_RSHIFT:
case TK_CONCAT: {
assert( TK_AND==OP_And ); testcase( op==TK_AND );
assert( TK_OR==OP_Or ); testcase( op==TK_OR );
@@ -93224,6 +103786,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
tempX.op = TK_INTEGER;
tempX.flags = EP_IntValue|EP_TokenOnly;
tempX.u.iValue = 0;
+ ExprClearVVAProperties(&tempX);
r1 = sqlite3ExprCodeTemp(pParse, &tempX, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree2);
sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
@@ -93240,6 +103803,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3VdbeAddOp2(v, op, r1, inReg);
break;
}
+ case TK_TRUTH: {
+ int isTrue; /* IS TRUE or IS NOT TRUE */
+ int bNormal; /* IS TRUE or IS FALSE */
+ r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ testcase( regFree1==0 );
+ isTrue = sqlite3ExprTruthValue(pExpr->pRight);
+ bNormal = pExpr->op2==TK_IS;
+ testcase( isTrue && bNormal);
+ testcase( !isTrue && bNormal);
+ sqlite3VdbeAddOp4Int(v, OP_IsTrue, r1, inReg, !isTrue, isTrue ^ bNormal);
+ break;
+ }
case TK_ISNULL:
case TK_NOTNULL: {
int addr;
@@ -93257,7 +103832,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
}
case TK_AGG_FUNCTION: {
AggInfo *pInfo = pExpr->pAggInfo;
- if( pInfo==0 ){
+ if( pInfo==0
+ || NEVER(pExpr->iAgg<0)
+ || NEVER(pExpr->iAgg>=pInfo->nFunc)
+ ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
}else{
@@ -93276,12 +103854,20 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
u8 enc = ENC(db); /* The text encoding used by this database */
CollSeq *pColl = 0; /* A collating sequence */
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- if( ExprHasProperty(pExpr, EP_TokenOnly) ){
- pFarg = 0;
- }else{
- pFarg = pExpr->x.pList;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ return pExpr->y.pWin->regResult;
+ }
+#endif
+
+ if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
+ /* SQL functions can be expensive. So try to avoid running them
+ ** multiple times if we know they always give the same result */
+ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
}
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
+ assert( !ExprHasProperty(pExpr, EP_TokenOnly) );
+ pFarg = pExpr->x.pList;
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
@@ -93295,33 +103881,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
break;
}
-
- /* Attempt a direct implementation of the built-in COALESCE() and
- ** IFNULL() functions. This avoids unnecessary evaluation of
- ** arguments past the first non-NULL argument.
- */
- if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
- int endCoalesce = sqlite3VdbeMakeLabel(v);
- assert( nFarg>=2 );
- sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
- for(i=1; i<nFarg; i++){
- sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
- VdbeCoverage(v);
- sqlite3ExprCacheRemove(pParse, target, 1);
- sqlite3ExprCachePush(pParse);
- sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
- sqlite3ExprCachePop(pParse);
- }
- sqlite3VdbeResolveLabel(v, endCoalesce);
- break;
- }
-
- /* The UNLIKELY() function is a no-op. The result is the value
- ** of the first argument.
- */
- if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
- assert( nFarg>=1 );
- return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
+ if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
+ assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );
+ assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );
+ return exprCodeInlineFunction(pParse, pFarg,
+ SQLITE_PTR_TO_INT(pDef->pUserData), target);
+ }else if( pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE) ){
+ sqlite3ExprFunctionUsable(pParse, pExpr, pDef);
}
for(i=0; i<nFarg; i++){
@@ -93355,15 +103921,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
- pFarg->a[0].pExpr->op2 =
+ pFarg->a[0].pExpr->op2 =
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
}
}
- sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
- sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */
}else{
r1 = 0;
}
@@ -93376,25 +103940,40 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
** see if it is a column in a virtual table. This is done because
** the left operand of infix functions (the operand we want to
** control overloading) ends up as the second argument to the
- ** function. The expression "A glob B" is equivalent to
+ ** function. The expression "A glob B" is equivalent to
** "glob(B,A). We want to use the A in "A glob B" to test
** for function overloading. But we use the B term in "glob(B,A)".
*/
- if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){
+ if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr);
}else if( nFarg>0 ){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr);
}
#endif
if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- if( !pColl ) pColl = db->pDfltColl;
+ if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, OP_Function0, constMask, r1, target,
- (char*)pDef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nFarg);
- if( nFarg && constMask==0 ){
- sqlite3ReleaseTempRange(pParse, r1, nFarg);
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
+ Expr *pArg = pFarg->a[0].pExpr;
+ if( pArg->op==TK_COLUMN ){
+ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+ }
+ }else
+#endif
+ {
+ sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
+ pDef, pExpr->op2);
+ }
+ if( nFarg ){
+ if( constMask==0 ){
+ sqlite3ReleaseTempRange(pParse, r1, nFarg);
+ }else{
+ sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask, 1);
+ }
}
return target;
}
@@ -93404,22 +103983,32 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
int nCol;
testcase( op==TK_EXISTS );
testcase( op==TK_SELECT );
- if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
+ if( pParse->db->mallocFailed ){
+ return 0;
+ }else if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
sqlite3SubselectError(pParse, nCol, 1);
}else{
- return sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ return sqlite3CodeSubselect(pParse, pExpr);
}
break;
}
case TK_SELECT_COLUMN: {
+ int n;
if( pExpr->pLeft->iTable==0 ){
- pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0);
+ pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft);
+ }
+ assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
+ if( pExpr->iTable!=0
+ && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
+ ){
+ sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
+ pExpr->iTable, n);
}
return pExpr->pLeft->iTable + pExpr->iColumn;
}
case TK_IN: {
- int destIfFalse = sqlite3VdbeMakeLabel(v);
- int destIfNull = sqlite3VdbeMakeLabel(v);
+ int destIfFalse = sqlite3VdbeMakeLabel(pParse);
+ int destIfNull = sqlite3VdbeMakeLabel(pParse);
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull);
sqlite3VdbeAddOp2(v, OP_Integer, 1, target);
@@ -93447,9 +104036,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
return target;
}
case TK_SPAN:
- case TK_COLLATE:
+ case TK_COLLATE:
case TK_UPLUS: {
- return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ pExpr = pExpr->pLeft;
+ goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */
}
case TK_TRIGGER: {
@@ -93462,7 +104052,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
**
** The expression is implemented using an OP_Param opcode. The p1
** parameter is set to 0 for an old.rowid reference, or to (i+1)
- ** to reference another column of the old.* pseudo-table, where
+ ** to reference another column of the old.* pseudo-table, where
** i is the index of the column. For a new.rowid reference, p1 is
** set to (n+1), where n is the number of columns in each pseudo-table.
** For a reference to any other column in the new.* pseudo-table, p1
@@ -93476,21 +104066,22 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
**
** p1==0 -> old.rowid p1==3 -> new.rowid
** p1==1 -> old.a p1==4 -> new.a
- ** p1==2 -> old.b p1==5 -> new.b
+ ** p1==2 -> old.b p1==5 -> new.b
*/
- Table *pTab = pExpr->pTab;
- int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn;
+ Table *pTab = pExpr->y.pTab;
+ int iCol = pExpr->iColumn;
+ int p1 = pExpr->iTable * (pTab->nCol+1) + 1
+ + sqlite3TableColumnToStorage(pTab, iCol);
assert( pExpr->iTable==0 || pExpr->iTable==1 );
- assert( pExpr->iColumn>=-1 && pExpr->iColumn<pTab->nCol );
- assert( pTab->iPKey<0 || pExpr->iColumn!=pTab->iPKey );
+ assert( iCol>=-1 && iCol<pTab->nCol );
+ assert( pTab->iPKey<0 || iCol!=pTab->iPKey );
assert( p1>=0 && p1<(pTab->nCol*2+2) );
sqlite3VdbeAddOp2(v, OP_Param, p1, target);
- VdbeComment((v, "%s.%s -> $%d",
+ VdbeComment((v, "r[%d]=%s.%s", target,
(pExpr->iTable ? "new" : "old"),
- (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName),
- target
+ (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zName)
));
#ifndef SQLITE_OMIT_FLOATING_POINT
@@ -93499,9 +104090,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
**
** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to
** floating point when extracting it from the record. */
- if( pExpr->iColumn>=0
- && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
- ){
+ if( iCol>=0 && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
}
#endif
@@ -93513,6 +104102,28 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
break;
}
+ /* TK_IF_NULL_ROW Expr nodes are inserted ahead of expressions
+ ** that derive from the right-hand table of a LEFT JOIN. The
+ ** Expr.iTable value is the table number for the right-hand table.
+ ** The expression is only evaluated if that table is not currently
+ ** on a LEFT JOIN NULL row.
+ */
+ case TK_IF_NULL_ROW: {
+ int addrINR;
+ u8 okConstFactor = pParse->okConstFactor;
+ addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
+ /* Temporarily disable factoring of constant expressions, since
+ ** even though expressions may appear to be constant, they are not
+ ** really constant because they originate from the right-hand side
+ ** of a LEFT JOIN. */
+ pParse->okConstFactor = 0;
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ pParse->okConstFactor = okConstFactor;
+ sqlite3VdbeJumpHere(v, addrINR);
+ sqlite3VdbeChangeP3(v, addrINR, inReg);
+ break;
+ }
+
/*
** Form A:
** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END
@@ -93534,7 +104145,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
** or if there is no matching Ei, the ELSE term Y, or if there is
** no ELSE term, NULL.
*/
- default: assert( op==TK_CASE ); {
+ case TK_CASE: {
int endLabel; /* GOTO label for end of CASE stmt */
int nextCase; /* GOTO label for next WHEN clause */
int nExpr; /* 2x number of WHEN terms */
@@ -93544,22 +104155,27 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
Expr opCompare; /* The X==Ei expression */
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
- VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; )
+ Expr *pDel = 0;
+ sqlite3 *db = pParse->db;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
assert(pExpr->x.pList->nExpr > 0);
pEList = pExpr->x.pList;
aListelem = pEList->a;
nExpr = pEList->nExpr;
- endLabel = sqlite3VdbeMakeLabel(v);
+ endLabel = sqlite3VdbeMakeLabel(pParse);
if( (pX = pExpr->pLeft)!=0 ){
- tempX = *pX;
+ pDel = sqlite3ExprDup(db, pX, 0);
+ if( db->mallocFailed ){
+ sqlite3ExprDelete(db, pDel);
+ break;
+ }
testcase( pX->op==TK_COLUMN );
- exprToRegister(&tempX, exprCodeVector(pParse, &tempX, &regFree1));
+ exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
testcase( regFree1==0 );
memset(&opCompare, 0, sizeof(opCompare));
opCompare.op = TK_EQ;
- opCompare.pLeft = &tempX;
+ opCompare.pLeft = pDel;
pTest = &opCompare;
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
** The value in regFree1 might get SCopy-ed into the file result.
@@ -93568,57 +104184,54 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
regFree1 = 0;
}
for(i=0; i<nExpr-1; i=i+2){
- sqlite3ExprCachePush(pParse);
if( pX ){
assert( pTest!=0 );
opCompare.pRight = aListelem[i].pExpr;
}else{
pTest = aListelem[i].pExpr;
}
- nextCase = sqlite3VdbeMakeLabel(v);
+ nextCase = sqlite3VdbeMakeLabel(pParse);
testcase( pTest->op==TK_COLUMN );
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
sqlite3VdbeGoto(v, endLabel);
- sqlite3ExprCachePop(pParse);
sqlite3VdbeResolveLabel(v, nextCase);
}
if( (nExpr&1)!=0 ){
- sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
- sqlite3ExprCachePop(pParse);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
}
- assert( pParse->db->mallocFailed || pParse->nErr>0
- || pParse->iCacheLevel==iCacheLevel );
+ sqlite3ExprDelete(db, pDel);
+ setDoNotMergeFlagOnCopy(v);
sqlite3VdbeResolveLabel(v, endLabel);
break;
}
#ifndef SQLITE_OMIT_TRIGGER
case TK_RAISE: {
- assert( pExpr->affinity==OE_Rollback
- || pExpr->affinity==OE_Abort
- || pExpr->affinity==OE_Fail
- || pExpr->affinity==OE_Ignore
+ assert( pExpr->affExpr==OE_Rollback
+ || pExpr->affExpr==OE_Abort
+ || pExpr->affExpr==OE_Fail
+ || pExpr->affExpr==OE_Ignore
);
- if( !pParse->pTriggerTab ){
+ if( !pParse->pTriggerTab && !pParse->nested ){
sqlite3ErrorMsg(pParse,
"RAISE() may only be used within a trigger-program");
return 0;
}
- if( pExpr->affinity==OE_Abort ){
+ if( pExpr->affExpr==OE_Abort ){
sqlite3MayAbort(pParse);
}
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- if( pExpr->affinity==OE_Ignore ){
+ if( pExpr->affExpr==OE_Ignore ){
sqlite3VdbeAddOp4(
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
VdbeCoverage(v);
}else{
- sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
- pExpr->affinity, pExpr->u.zToken, 0, 0);
+ sqlite3HaltConstraint(pParse,
+ pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
+ pExpr->affExpr, pExpr->u.zToken, 0, 0);
}
break;
@@ -93631,25 +104244,64 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
}
/*
-** Factor out the code of the given expression to initialization time.
+** Generate code that will evaluate expression pExpr just one time
+** per prepared statement execution.
+**
+** If the expression uses functions (that might throw an exception) then
+** guard them with an OP_Once opcode to ensure that the code is only executed
+** once. If no functions are involved, then factor the code out and put it at
+** the end of the prepared statement in the initialization section.
+**
+** If regDest>=0 then the result is always stored in that register and the
+** result is not reusable. If regDest<0 then this routine is free to
+** store the value whereever it wants. The register where the expression
+** is stored is returned. When regDest<0, two identical expressions might
+** code to the same register, if they do not contain function calls and hence
+** are factored out into the initialization section at the end of the
+** prepared statement.
*/
-SQLITE_PRIVATE void sqlite3ExprCodeAtInit(
+SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The expression to code when the VDBE initializes */
- int regDest, /* Store the value in this register */
- u8 reusable /* True if this expression is reusable */
+ int regDest /* Store the value in this register */
){
ExprList *p;
assert( ConstFactorOk(pParse) );
p = pParse->pConstExpr;
+ if( regDest<0 && p ){
+ struct ExprList_item *pItem;
+ int i;
+ for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
+ if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
+ return pItem->u.iConstExprReg;
+ }
+ }
+ }
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
- p = sqlite3ExprListAppend(pParse, p, pExpr);
- if( p ){
- struct ExprList_item *pItem = &p->a[p->nExpr-1];
- pItem->u.iConstExprReg = regDest;
- pItem->reusable = reusable;
+ if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){
+ Vdbe *v = pParse->pVdbe;
+ int addr;
+ assert( v );
+ addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ pParse->okConstFactor = 0;
+ if( !pParse->db->mallocFailed ){
+ if( regDest<0 ) regDest = ++pParse->nMem;
+ sqlite3ExprCode(pParse, pExpr, regDest);
+ }
+ pParse->okConstFactor = 1;
+ sqlite3ExprDelete(pParse->db, pExpr);
+ sqlite3VdbeJumpHere(v, addr);
+ }else{
+ p = sqlite3ExprListAppend(pParse, p, pExpr);
+ if( p ){
+ struct ExprList_item *pItem = &p->a[p->nExpr-1];
+ pItem->reusable = regDest<0;
+ if( regDest<0 ) regDest = ++pParse->nMem;
+ pItem->u.iConstExprReg = regDest;
+ }
+ pParse->pConstExpr = p;
}
- pParse->pConstExpr = p;
+ return regDest;
}
/*
@@ -93667,24 +104319,13 @@ SQLITE_PRIVATE void sqlite3ExprCodeAtInit(
*/
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
int r2;
- pExpr = sqlite3ExprSkipCollate(pExpr);
+ pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
if( ConstFactorOk(pParse)
&& pExpr->op!=TK_REGISTER
&& sqlite3ExprIsConstantNotJoin(pExpr)
){
- ExprList *p = pParse->pConstExpr;
- int i;
*pReg = 0;
- if( p ){
- struct ExprList_item *pItem;
- for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
- if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){
- return pItem->u.iConstExprReg;
- }
- }
- }
- r2 = ++pParse->nMem;
- sqlite3ExprCodeAtInit(pParse, pExpr, r2, 1);
+ r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
}else{
int r1 = sqlite3GetTempReg(pParse);
r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
@@ -93706,15 +104347,19 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
int inReg;
+ assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
assert( target>0 && target<=pParse->nMem );
- if( pExpr && pExpr->op==TK_REGISTER ){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
- }else{
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
- if( inReg!=target && pParse->pVdbe ){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
+ if( pParse->pVdbe==0 ) return;
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ if( inReg!=target ){
+ u8 op;
+ if( ExprHasProperty(pExpr,EP_Subquery) ){
+ op = OP_Copy;
+ }else{
+ op = OP_SCopy;
}
+ sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
}
}
@@ -93737,42 +104382,20 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
** might choose to code the expression at initialization time.
*/
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
- if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){
- sqlite3ExprCodeAtInit(pParse, pExpr, target, 0);
+ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
+ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
}else{
- sqlite3ExprCode(pParse, pExpr, target);
+ sqlite3ExprCodeCopy(pParse, pExpr, target);
}
}
/*
-** Generate code that evaluates the given expression and puts the result
-** in register target.
-**
-** Also make a copy of the expression results into another "cache" register
-** and modify the expression so that the next time it is evaluated,
-** the result is a copy of the cache register.
-**
-** This routine is used for expressions that are used multiple
-** times. They are evaluated once and the results of the expression
-** are reused.
-*/
-SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
- Vdbe *v = pParse->pVdbe;
- int iMem;
-
- assert( target>0 );
- assert( pExpr->op!=TK_REGISTER );
- sqlite3ExprCode(pParse, pExpr, target);
- iMem = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Copy, target, iMem);
- exprToRegister(pExpr, iMem);
-}
-
-/*
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
**
-** Return the number of elements evaluated.
+** Return the number of elements evaluated. The number returned will
+** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF
+** is defined.
**
** The SQLITE_ECEL_DUP flag prevents the arguments from being
** filled using OP_SCopy. OP_Copy must be used instead.
@@ -93783,6 +104406,8 @@ SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int targ
** The SQLITE_ECEL_REF flag means that expressions in the list with
** ExprList.a[].u.x.iOrderByCol>0 have already been evaluated and stored
** in registers at srcReg, and so the value can be copied from there.
+** If SQLITE_ECEL_OMITREF is also set, then the values with u.x.iOrderByCol>0
+** are simply omitted rather than being copied from srcReg.
*/
SQLITE_PRIVATE int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
@@ -93802,10 +104427,23 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
- if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
- sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
- }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
- sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( pItem->bSorterRef ){
+ i--;
+ n--;
+ }else
+#endif
+ if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){
+ if( flags & SQLITE_ECEL_OMITREF ){
+ i--;
+ n--;
+ }else{
+ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
+ }
+ }else if( (flags & SQLITE_ECEL_FACTOR)!=0
+ && sqlite3ExprIsConstantNotJoin(pExpr)
+ ){
+ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
}else{
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
if( inReg!=target+i ){
@@ -93814,6 +104452,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
&& (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
+ && pOp->p5==0 /* The do-not-merge flag must be clear */
){
pOp->p3++;
}else{
@@ -93830,7 +104469,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
**
** x BETWEEN y AND z
**
-** The above is equivalent to
+** The above is equivalent to
**
** x>=y AND x<=z
**
@@ -93852,36 +104491,44 @@ static void exprCodeBetween(
void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
){
- Expr exprAnd; /* The AND operator in x>=y AND x<=z */
+ Expr exprAnd; /* The AND operator in x>=y AND x<=z */
Expr compLeft; /* The x>=y term */
Expr compRight; /* The x<=z term */
- Expr exprX; /* The x subexpression */
int regFree1 = 0; /* Temporary use register */
-
+ Expr *pDel = 0;
+ sqlite3 *db = pParse->db;
memset(&compLeft, 0, sizeof(Expr));
memset(&compRight, 0, sizeof(Expr));
memset(&exprAnd, 0, sizeof(Expr));
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- exprX = *pExpr->pLeft;
- exprAnd.op = TK_AND;
- exprAnd.pLeft = &compLeft;
- exprAnd.pRight = &compRight;
- compLeft.op = TK_GE;
- compLeft.pLeft = &exprX;
- compLeft.pRight = pExpr->x.pList->a[0].pExpr;
- compRight.op = TK_LE;
- compRight.pLeft = &exprX;
- compRight.pRight = pExpr->x.pList->a[1].pExpr;
- exprToRegister(&exprX, exprCodeVector(pParse, &exprX, &regFree1));
- if( xJump ){
- xJump(pParse, &exprAnd, dest, jumpIfNull);
- }else{
- exprX.flags |= EP_FromJoin;
- sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
+ pDel = sqlite3ExprDup(db, pExpr->pLeft, 0);
+ if( db->mallocFailed==0 ){
+ exprAnd.op = TK_AND;
+ exprAnd.pLeft = &compLeft;
+ exprAnd.pRight = &compRight;
+ compLeft.op = TK_GE;
+ compLeft.pLeft = pDel;
+ compLeft.pRight = pExpr->x.pList->a[0].pExpr;
+ compRight.op = TK_LE;
+ compRight.pLeft = pDel;
+ compRight.pRight = pExpr->x.pList->a[1].pExpr;
+ exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
+ if( xJump ){
+ xJump(pParse, &exprAnd, dest, jumpIfNull);
+ }else{
+ /* Mark the expression is being from the ON or USING clause of a join
+ ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
+ ** it into the Parse.pConstExpr list. We should use a new bit for this,
+ ** for clarity, but we are out of bits in the Expr.flags field so we
+ ** have to reuse the EP_FromJoin bit. Bummer. */
+ pDel->flags |= EP_FromJoin;
+ sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
+ }
+ sqlite3ReleaseTempReg(pParse, regFree1);
}
- sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ExprDelete(db, pDel);
/* Ensure adequate test coverage */
testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 );
@@ -93919,24 +104566,26 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
if( NEVER(pExpr==0) ) return; /* No way this can happen */
+ assert( !ExprHasVVAProperty(pExpr, EP_Immutable) );
op = pExpr->op;
switch( op ){
- case TK_AND: {
- int d2 = sqlite3VdbeMakeLabel(v);
- testcase( jumpIfNull==0 );
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL);
- sqlite3ExprCachePush(pParse);
- sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3VdbeResolveLabel(v, d2);
- sqlite3ExprCachePop(pParse);
- break;
- }
+ case TK_AND:
case TK_OR: {
- testcase( jumpIfNull==0 );
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
- sqlite3ExprCachePush(pParse);
- sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3ExprCachePop(pParse);
+ Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
+ if( pAlt!=pExpr ){
+ sqlite3ExprIfTrue(pParse, pAlt, dest, jumpIfNull);
+ }else if( op==TK_AND ){
+ int d2 = sqlite3VdbeMakeLabel(pParse);
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,
+ jumpIfNull^SQLITE_JUMPIFNULL);
+ sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
+ sqlite3VdbeResolveLabel(v, d2);
+ }else{
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
+ sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull);
+ }
break;
}
case TK_NOT: {
@@ -93944,13 +104593,30 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
+ case TK_TRUTH: {
+ int isNot; /* IS NOT TRUE or IS NOT FALSE */
+ int isTrue; /* IS TRUE or IS NOT TRUE */
+ testcase( jumpIfNull==0 );
+ isNot = pExpr->op2==TK_ISNOT;
+ isTrue = sqlite3ExprTruthValue(pExpr->pRight);
+ testcase( isTrue && isNot );
+ testcase( !isTrue && isNot );
+ if( isTrue ^ isNot ){
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest,
+ isNot ? SQLITE_JUMPIFNULL : 0);
+ }else{
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest,
+ isNot ? SQLITE_JUMPIFNULL : 0);
+ }
+ break;
+ }
case TK_IS:
case TK_ISNOT:
testcase( op==TK_IS );
testcase( op==TK_ISNOT );
op = (op==TK_IS) ? TK_EQ : TK_NE;
jumpIfNull = SQLITE_NULLEQ;
- /* Fall thru */
+ /* no break */ deliberate_fall_through
case TK_LT:
case TK_LE:
case TK_GT:
@@ -93962,7 +104628,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, dest, jumpIfNull);
+ r1, r2, dest, jumpIfNull, ExprHasProperty(pExpr,EP_Commuted));
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -93995,7 +104661,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_IN: {
- int destIfFalse = sqlite3VdbeMakeLabel(v);
+ int destIfFalse = sqlite3VdbeMakeLabel(pParse);
int destIfNull = jumpIfNull ? dest : destIfFalse;
sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull);
sqlite3VdbeGoto(v, dest);
@@ -94005,9 +104671,9 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
#endif
default: {
default_expr:
- if( exprAlwaysTrue(pExpr) ){
+ if( ExprAlwaysTrue(pExpr) ){
sqlite3VdbeGoto(v, dest);
- }else if( exprAlwaysFalse(pExpr) ){
+ }else if( ExprAlwaysFalse(pExpr) ){
/* No-op */
}else{
r1 = sqlite3ExprCodeTemp(pParse, pExpr, &regFree1);
@@ -94020,7 +104686,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
}
}
sqlite3ReleaseTempReg(pParse, regFree1);
- sqlite3ReleaseTempReg(pParse, regFree2);
+ sqlite3ReleaseTempReg(pParse, regFree2);
}
/*
@@ -94042,6 +104708,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
if( pExpr==0 ) return;
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
/* The value of pExpr->op and op are related as follows:
**
@@ -94075,22 +104742,23 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
assert( pExpr->op!=TK_GE || op==OP_Lt );
switch( pExpr->op ){
- case TK_AND: {
- testcase( jumpIfNull==0 );
- sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
- sqlite3ExprCachePush(pParse);
- sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3ExprCachePop(pParse);
- break;
- }
+ case TK_AND:
case TK_OR: {
- int d2 = sqlite3VdbeMakeLabel(v);
- testcase( jumpIfNull==0 );
- sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2, jumpIfNull^SQLITE_JUMPIFNULL);
- sqlite3ExprCachePush(pParse);
- sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
- sqlite3VdbeResolveLabel(v, d2);
- sqlite3ExprCachePop(pParse);
+ Expr *pAlt = sqlite3ExprSimplifiedAndOr(pExpr);
+ if( pAlt!=pExpr ){
+ sqlite3ExprIfFalse(pParse, pAlt, dest, jumpIfNull);
+ }else if( pExpr->op==TK_AND ){
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
+ sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
+ }else{
+ int d2 = sqlite3VdbeMakeLabel(pParse);
+ testcase( jumpIfNull==0 );
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, d2,
+ jumpIfNull^SQLITE_JUMPIFNULL);
+ sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull);
+ sqlite3VdbeResolveLabel(v, d2);
+ }
break;
}
case TK_NOT: {
@@ -94098,13 +104766,33 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
+ case TK_TRUTH: {
+ int isNot; /* IS NOT TRUE or IS NOT FALSE */
+ int isTrue; /* IS TRUE or IS NOT TRUE */
+ testcase( jumpIfNull==0 );
+ isNot = pExpr->op2==TK_ISNOT;
+ isTrue = sqlite3ExprTruthValue(pExpr->pRight);
+ testcase( isTrue && isNot );
+ testcase( !isTrue && isNot );
+ if( isTrue ^ isNot ){
+ /* IS TRUE and IS NOT FALSE */
+ sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest,
+ isNot ? 0 : SQLITE_JUMPIFNULL);
+
+ }else{
+ /* IS FALSE and IS NOT TRUE */
+ sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest,
+ isNot ? 0 : SQLITE_JUMPIFNULL);
+ }
+ break;
+ }
case TK_IS:
case TK_ISNOT:
testcase( pExpr->op==TK_IS );
testcase( pExpr->op==TK_ISNOT );
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
jumpIfNull = SQLITE_NULLEQ;
- /* Fall thru */
+ /* no break */ deliberate_fall_through
case TK_LT:
case TK_LE:
case TK_GT:
@@ -94116,7 +104804,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, dest, jumpIfNull);
+ r1, r2, dest, jumpIfNull,ExprHasProperty(pExpr,EP_Commuted));
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
@@ -94150,7 +104838,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
if( jumpIfNull ){
sqlite3ExprCodeIN(pParse, pExpr, dest, dest);
}else{
- int destIfNull = sqlite3VdbeMakeLabel(v);
+ int destIfNull = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprCodeIN(pParse, pExpr, dest, destIfNull);
sqlite3VdbeResolveLabel(v, destIfNull);
}
@@ -94158,10 +104846,10 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
}
#endif
default: {
- default_expr:
- if( exprAlwaysFalse(pExpr) ){
+ default_expr:
+ if( ExprAlwaysFalse(pExpr) ){
sqlite3VdbeGoto(v, dest);
- }else if( exprAlwaysTrue(pExpr) ){
+ }else if( ExprAlwaysTrue(pExpr) ){
/* no-op */
}else{
r1 = sqlite3ExprCodeTemp(pParse, pExpr, &regFree1);
@@ -94191,6 +104879,41 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
sqlite3ExprDelete(db, pCopy);
}
+/*
+** Expression pVar is guaranteed to be an SQL variable. pExpr may be any
+** type of expression.
+**
+** If pExpr is a simple SQL value - an integer, real, string, blob
+** or NULL value - then the VDBE currently being prepared is configured
+** to re-prepare each time a new value is bound to variable pVar.
+**
+** Additionally, if pExpr is a simple SQL value and the value is the
+** same as that currently bound to variable pVar, non-zero is returned.
+** Otherwise, if the values are not the same or if pExpr is not a simple
+** SQL value, zero is returned.
+*/
+static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){
+ int res = 0;
+ int iVar;
+ sqlite3_value *pL, *pR = 0;
+
+ sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
+ if( pR ){
+ iVar = pVar->iColumn;
+ sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
+ pL = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, SQLITE_AFF_BLOB);
+ if( pL ){
+ if( sqlite3_value_type(pL)==SQLITE_TEXT ){
+ sqlite3_value_text(pL); /* Make sure the encoding is UTF-8 */
+ }
+ res = 0==sqlite3MemCompare(pL, pR, 0);
+ }
+ sqlite3ValueFree(pR);
+ sqlite3ValueFree(pL);
+ }
+
+ return res;
+}
/*
** Do a deep comparison of two expression trees. Return 0 if the two
@@ -94213,12 +104936,22 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
** this routine is used, it does not hurt to get an extra 2 - that
** just might result in some slightly slower code. But returning
** an incorrect 0 or 1 could lead to a malfunction.
+**
+** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
+** pParse->pReprepare can be matched against literals in pB. The
+** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
+** If pParse is NULL (the normal case) then any TK_VARIABLE term in
+** Argument pParse should normally be NULL. If it is not NULL and pA or
+** pB causes a return value of 2.
*/
-SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
+SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
u32 combinedFlags;
if( pA==0 || pB==0 ){
return pB==pA ? 0 : 2;
}
+ if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
+ return 0;
+ }
combinedFlags = pA->flags | pB->flags;
if( combinedFlags & EP_IntValue ){
if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
@@ -94226,40 +104959,63 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
}
return 2;
}
- if( pA->op!=pB->op ){
- if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){
+ if( pA->op!=pB->op || pA->op==TK_RAISE ){
+ if( pA->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA->pLeft,pB,iTab)<2 ){
return 1;
}
- if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){
+ if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
return 1;
}
return 2;
}
if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
- if( pA->op==TK_FUNCTION ){
+ if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
- }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
- return pA->op==TK_COLLATE ? 1 : 2;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ assert( pA->op==pB->op );
+ if( ExprHasProperty(pA,EP_WinFunc)!=ExprHasProperty(pB,EP_WinFunc) ){
+ return 2;
+ }
+ if( ExprHasProperty(pA,EP_WinFunc) ){
+ if( sqlite3WindowCompare(pParse, pA->y.pWin, pB->y.pWin, 1)!=0 ){
+ return 2;
+ }
+ }
+#endif
+ }else if( pA->op==TK_NULL ){
+ return 0;
+ }else if( pA->op==TK_COLLATE ){
+ if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
+ }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
+ return 2;
}
}
- if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
+ if( (pA->flags & (EP_Distinct|EP_Commuted))
+ != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2;
if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
if( combinedFlags & EP_xIsSelect ) return 2;
- if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
- if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
+ if( (combinedFlags & EP_FixedCol)==0
+ && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
+ if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
- if( ALWAYS((combinedFlags & EP_Reduced)==0) && pA->op!=TK_STRING ){
+ if( pA->op!=TK_STRING
+ && pA->op!=TK_TRUEFALSE
+ && ALWAYS((combinedFlags & EP_Reduced)==0)
+ ){
if( pA->iColumn!=pB->iColumn ) return 2;
- if( pA->iTable!=pB->iTable
- && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
+ if( pA->op2!=pB->op2 && pA->op==TK_TRUTH ) return 2;
+ if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){
+ return 2;
+ }
}
}
return 0;
}
/*
-** Compare two ExprList objects. Return 0 if they are identical and
-** non-zero if they differ in any way.
+** Compare two ExprList objects. Return 0 if they are identical, 1
+** if they are certainly different, or 2 if it is not possible to
+** determine if they are identical or not.
**
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
@@ -94278,10 +105034,99 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
if( pA==0 || pB==0 ) return 1;
if( pA->nExpr!=pB->nExpr ) return 1;
for(i=0; i<pA->nExpr; i++){
+ int res;
Expr *pExprA = pA->a[i].pExpr;
Expr *pExprB = pB->a[i].pExpr;
- if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
- if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1;
+ if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
+ if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
+ }
+ return 0;
+}
+
+/*
+** Like sqlite3ExprCompare() except COLLATE operators at the top-level
+** are ignored.
+*/
+SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
+ return sqlite3ExprCompare(0,
+ sqlite3ExprSkipCollateAndLikely(pA),
+ sqlite3ExprSkipCollateAndLikely(pB),
+ iTab);
+}
+
+/*
+** Return non-zero if Expr p can only be true if pNN is not NULL.
+**
+** Or if seenNot is true, return non-zero if Expr p can only be
+** non-NULL if pNN is not NULL
+*/
+static int exprImpliesNotNull(
+ Parse *pParse, /* Parsing context */
+ Expr *p, /* The expression to be checked */
+ Expr *pNN, /* The expression that is NOT NULL */
+ int iTab, /* Table being evaluated */
+ int seenNot /* Return true only if p can be any non-NULL value */
+){
+ assert( p );
+ assert( pNN );
+ if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){
+ return pNN->op!=TK_NULL;
+ }
+ switch( p->op ){
+ case TK_IN: {
+ if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0;
+ assert( ExprHasProperty(p,EP_xIsSelect)
+ || (p->x.pList!=0 && p->x.pList->nExpr>0) );
+ return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
+ }
+ case TK_BETWEEN: {
+ ExprList *pList = p->x.pList;
+ assert( pList!=0 );
+ assert( pList->nExpr==2 );
+ if( seenNot ) return 0;
+ if( exprImpliesNotNull(pParse, pList->a[0].pExpr, pNN, iTab, 1)
+ || exprImpliesNotNull(pParse, pList->a[1].pExpr, pNN, iTab, 1)
+ ){
+ return 1;
+ }
+ return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
+ }
+ case TK_EQ:
+ case TK_NE:
+ case TK_LT:
+ case TK_LE:
+ case TK_GT:
+ case TK_GE:
+ case TK_PLUS:
+ case TK_MINUS:
+ case TK_BITOR:
+ case TK_LSHIFT:
+ case TK_RSHIFT:
+ case TK_CONCAT:
+ seenNot = 1;
+ /* no break */ deliberate_fall_through
+ case TK_STAR:
+ case TK_REM:
+ case TK_BITAND:
+ case TK_SLASH: {
+ if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
+ /* no break */ deliberate_fall_through
+ }
+ case TK_SPAN:
+ case TK_COLLATE:
+ case TK_UPLUS:
+ case TK_UMINUS: {
+ return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, seenNot);
+ }
+ case TK_TRUTH: {
+ if( seenNot ) return 0;
+ if( p->op2!=TK_IS ) return 0;
+ return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
+ }
+ case TK_BITNOT:
+ case TK_NOT: {
+ return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
+ }
}
return 0;
}
@@ -94302,23 +105147,27 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
**
+** If pParse is not NULL, then the values of bound variables in pE1 are
+** compared against literal values in pE2 and pParse->pVdbe->expmask is
+** modified to record which bound variables are referenced. If pParse
+** is NULL, then false will be returned if pE1 contains any bound variables.
+**
** When in doubt, return false. Returning true might give a performance
** improvement. Returning false might cause a performance reduction, but
** it will always give the correct answer and is hence always safe.
*/
-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
- if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){
+SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
+ if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
return 1;
}
if( pE2->op==TK_OR
- && (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab)
- || sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) )
+ && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab)
+ || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) )
){
return 1;
}
if( pE2->op==TK_NOTNULL
- && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0
- && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS)
+ && exprImpliesNotNull(pParse, pE1, pE2->pLeft, iTab, 0)
){
return 1;
}
@@ -94326,6 +105175,141 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
}
/*
+** This is the Expr node callback for sqlite3ExprImpliesNonNullRow().
+** If the expression node requires that the table at pWalker->iCur
+** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
+**
+** This routine controls an optimization. False positives (setting
+** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
+** (never setting pWalker->eCode) is a harmless missed optimization.
+*/
+static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
+ testcase( pExpr->op==TK_AGG_COLUMN );
+ testcase( pExpr->op==TK_AGG_FUNCTION );
+ if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
+ switch( pExpr->op ){
+ case TK_ISNOT:
+ case TK_ISNULL:
+ case TK_NOTNULL:
+ case TK_IS:
+ case TK_OR:
+ case TK_VECTOR:
+ case TK_CASE:
+ case TK_IN:
+ case TK_FUNCTION:
+ case TK_TRUTH:
+ testcase( pExpr->op==TK_ISNOT );
+ testcase( pExpr->op==TK_ISNULL );
+ testcase( pExpr->op==TK_NOTNULL );
+ testcase( pExpr->op==TK_IS );
+ testcase( pExpr->op==TK_OR );
+ testcase( pExpr->op==TK_VECTOR );
+ testcase( pExpr->op==TK_CASE );
+ testcase( pExpr->op==TK_IN );
+ testcase( pExpr->op==TK_FUNCTION );
+ testcase( pExpr->op==TK_TRUTH );
+ return WRC_Prune;
+ case TK_COLUMN:
+ if( pWalker->u.iCur==pExpr->iTable ){
+ pWalker->eCode = 1;
+ return WRC_Abort;
+ }
+ return WRC_Prune;
+
+ case TK_AND:
+ if( pWalker->eCode==0 ){
+ sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ if( pWalker->eCode ){
+ pWalker->eCode = 0;
+ sqlite3WalkExpr(pWalker, pExpr->pRight);
+ }
+ }
+ return WRC_Prune;
+
+ case TK_BETWEEN:
+ if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
+ assert( pWalker->eCode );
+ return WRC_Abort;
+ }
+ return WRC_Prune;
+
+ /* Virtual tables are allowed to use constraints like x=NULL. So
+ ** a term of the form x=y does not prove that y is not null if x
+ ** is the column of a virtual table */
+ case TK_EQ:
+ case TK_NE:
+ case TK_LT:
+ case TK_LE:
+ case TK_GT:
+ case TK_GE: {
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ testcase( pExpr->op==TK_EQ );
+ testcase( pExpr->op==TK_NE );
+ testcase( pExpr->op==TK_LT );
+ testcase( pExpr->op==TK_LE );
+ testcase( pExpr->op==TK_GT );
+ testcase( pExpr->op==TK_GE );
+ /* The y.pTab=0 assignment in wherecode.c always happens after the
+ ** impliesNotNullRow() test */
+ if( (pLeft->op==TK_COLUMN && ALWAYS(pLeft->y.pTab!=0)
+ && IsVirtual(pLeft->y.pTab))
+ || (pRight->op==TK_COLUMN && ALWAYS(pRight->y.pTab!=0)
+ && IsVirtual(pRight->y.pTab))
+ ){
+ return WRC_Prune;
+ }
+ /* no break */ deliberate_fall_through
+ }
+ default:
+ return WRC_Continue;
+ }
+}
+
+/*
+** Return true (non-zero) if expression p can only be true if at least
+** one column of table iTab is non-null. In other words, return true
+** if expression p will always be NULL or false if every column of iTab
+** is NULL.
+**
+** False negatives are acceptable. In other words, it is ok to return
+** zero even if expression p will never be true of every column of iTab
+** is NULL. A false negative is merely a missed optimization opportunity.
+**
+** False positives are not allowed, however. A false positive may result
+** in an incorrect answer.
+**
+** Terms of p that are marked with EP_FromJoin (and hence that come from
+** the ON or USING clauses of LEFT JOINS) are excluded from the analysis.
+**
+** This routine is used to check if a LEFT JOIN can be converted into
+** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE
+** clause requires that some column of the right table of the LEFT JOIN
+** be non-NULL, then the LEFT JOIN can be safely converted into an
+** ordinary join.
+*/
+SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
+ Walker w;
+ p = sqlite3ExprSkipCollateAndLikely(p);
+ if( p==0 ) return 0;
+ if( p->op==TK_NOTNULL ){
+ p = p->pLeft;
+ }else{
+ while( p->op==TK_AND ){
+ if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
+ p = p->pRight;
+ }
+ }
+ w.xExprCallback = impliesNotNullRow;
+ w.xSelectCallback = 0;
+ w.xSelectCallback2 = 0;
+ w.eCode = 0;
+ w.u.iCur = iTab;
+ sqlite3WalkExpr(&w, p);
+ return w.eCode;
+}
+
+/*
** An instance of the following structure is used by the tree walker
** to determine if an expression can be evaluated by reference to the
** index only, without having to do a search for the corresponding
@@ -94338,14 +105322,14 @@ struct IdxCover {
};
/*
-** Check to see if there are references to columns in table
+** Check to see if there are references to columns in table
** pWalker->u.pIdxCover->iCur can be satisfied using the index
** pWalker->u.pIdxCover->pIdx.
*/
static int exprIdxCover(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN
&& pExpr->iTable==pWalker->u.pIdxCover->iCur
- && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
+ && sqlite3TableColumnToIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
){
pWalker->eCode = 1;
return WRC_Abort;
@@ -94382,26 +105366,42 @@ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
/*
** An instance of the following structure is used by the tree walker
-** to count references to table columns in the arguments of an
+** to count references to table columns in the arguments of an
** aggregate function, in order to implement the
** sqlite3FunctionThisSrc() routine.
*/
struct SrcCount {
SrcList *pSrc; /* One particular FROM clause in a nested query */
+ int iSrcInner; /* Smallest cursor number in this context */
int nThis; /* Number of references to columns in pSrcList */
int nOther; /* Number of references to columns in other FROM clauses */
};
/*
+** xSelect callback for sqlite3FunctionUsesThisSrc(). If this is the first
+** SELECT with a FROM clause encountered during this iteration, set
+** SrcCount.iSrcInner to the cursor number of the leftmost object in
+** the FROM cause.
+*/
+static int selectSrcCount(Walker *pWalker, Select *pSel){
+ struct SrcCount *p = pWalker->u.pSrcCount;
+ if( p->iSrcInner==0x7FFFFFFF && ALWAYS(pSel->pSrc) && pSel->pSrc->nSrc ){
+ pWalker->u.pSrcCount->iSrcInner = pSel->pSrc->a[0].iCursor;
+ }
+ return WRC_Continue;
+}
+
+/*
** Count the number of references to columns.
*/
static int exprSrcCount(Walker *pWalker, Expr *pExpr){
- /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc()
- ** is always called before sqlite3ExprAnalyzeAggregates() and so the
- ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN. If
- ** sqlite3FunctionUsesThisSrc() is used differently in the future, the
- ** NEVER() will need to be removed. */
- if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){
+ /* There was once a NEVER() on the second term on the grounds that
+ ** sqlite3FunctionUsesThisSrc() was always called before
+ ** sqlite3ExprAnalyzeAggregates() and so the TK_COLUMNs have not yet
+ ** been converted into TK_AGG_COLUMN. But this is no longer true due
+ ** to window functions - sqlite3WindowRewrite() may now indirectly call
+ ** FunctionUsesThisSrc() when creating a new sub-select. */
+ if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
int i;
struct SrcCount *p = pWalker->u.pSrcCount;
SrcList *pSrc = p->pSrc;
@@ -94411,7 +105411,10 @@ static int exprSrcCount(Walker *pWalker, Expr *pExpr){
}
if( i<nSrc ){
p->nThis++;
- }else{
+ }else if( pExpr->iTable<p->iSrcInner ){
+ /* In a well-formed parse tree (no name resolution errors),
+ ** TK_COLUMN nodes with smaller Expr.iTable values are in an
+ ** outer context. Those are the only ones to count as "other" */
p->nOther++;
}
}
@@ -94430,15 +105433,80 @@ SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
assert( pExpr->op==TK_AGG_FUNCTION );
memset(&w, 0, sizeof(w));
w.xExprCallback = exprSrcCount;
+ w.xSelectCallback = selectSrcCount;
w.u.pSrcCount = &cnt;
cnt.pSrc = pSrcList;
+ cnt.iSrcInner = (pSrcList&&pSrcList->nSrc)?pSrcList->a[0].iCursor:0x7FFFFFFF;
cnt.nThis = 0;
cnt.nOther = 0;
sqlite3WalkExprList(&w, pExpr->x.pList);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
+ }
+#endif
return cnt.nThis>0 || cnt.nOther==0;
}
/*
+** This is a Walker expression node callback.
+**
+** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
+** object that is referenced does not refer directly to the Expr. If
+** it does, make a copy. This is done because the pExpr argument is
+** subject to change.
+**
+** The copy is stored on pParse->pConstExpr with a register number of 0.
+** This will cause the expression to be deleted automatically when the
+** Parse object is destroyed, but the zero register number means that it
+** will not generate any code in the preamble.
+*/
+static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
+ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
+ && pExpr->pAggInfo!=0
+ ){
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ int iAgg = pExpr->iAgg;
+ Parse *pParse = pWalker->pParse;
+ sqlite3 *db = pParse->db;
+ assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
+ if( pExpr->op==TK_AGG_COLUMN ){
+ assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
+ if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aCol[iAgg].pCExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }else{
+ assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
+ if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
+ if( pExpr ){
+ pAggInfo->aFunc[iAgg].pFExpr = pExpr;
+ pParse->pConstExpr =
+ sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ }
+ }
+ }
+ }
+ return WRC_Continue;
+}
+
+/*
+** Initialize a Walker object so that will persist AggInfo entries referenced
+** by the tree that is walked.
+*/
+SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
+ memset(pWalker, 0, sizeof(*pWalker));
+ pWalker->pParse = pParse;
+ pWalker->xExprCallback = agginfoPersistExprCb;
+ pWalker->xSelectCallback = sqlite3SelectWalkNoop;
+}
+
+/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
** the new element. Return a negative number if malloc fails.
*/
@@ -94452,7 +105520,7 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
&i
);
return i;
-}
+}
/*
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
@@ -94461,14 +105529,14 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
int i;
pInfo->aFunc = sqlite3ArrayAllocate(
- db,
+ db,
pInfo->aFunc,
sizeof(pInfo->aFunc[0]),
&pInfo->nFunc,
&i
);
return i;
-}
+}
/*
** This is the xExprCallback for a tree walker. It is used to
@@ -94480,8 +105548,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
NameContext *pNC = pWalker->u.pNC;
Parse *pParse = pNC->pParse;
SrcList *pSrcList = pNC->pSrcList;
- AggInfo *pAggInfo = pNC->pAggInfo;
+ AggInfo *pAggInfo = pNC->uNC.pAggInfo;
+ assert( pNC->ncFlags & NC_UAggInfo );
switch( pExpr->op ){
case TK_AGG_COLUMN:
case TK_COLUMN: {
@@ -94496,7 +105565,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
/* If we reach this point, it means that pExpr refers to a table
- ** that is in the FROM clause of the aggregate query.
+ ** that is in the FROM clause of the aggregate query.
**
** Make an entry for the column in pAggInfo->aCol[] if there
** is not an entry there already.
@@ -94510,15 +105579,15 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
}
if( (k>=pAggInfo->nColumn)
- && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
+ && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
){
pCol = &pAggInfo->aCol[k];
- pCol->pTab = pExpr->pTab;
+ pCol->pTab = pExpr->y.pTab;
pCol->iTable = pExpr->iTable;
pCol->iColumn = pExpr->iColumn;
pCol->iMem = ++pParse->nMem;
pCol->iSorterColumn = -1;
- pCol->pExpr = pExpr;
+ pCol->pCExpr = pExpr;
if( pAggInfo->pGroupBy ){
int j, n;
ExprList *pGB = pAggInfo->pGroupBy;
@@ -94556,12 +105625,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
if( (pNC->ncFlags & NC_InAggFunc)==0
&& pWalker->walkerDepth==pExpr->op2
){
- /* Check to see if pExpr is a duplicate of another aggregate
+ /* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){
+ if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
}
@@ -94573,11 +105642,11 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
if( i>=0 ){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
- pItem->pExpr = pExpr;
+ pItem->pFExpr = pExpr;
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->u.zToken,
+ pExpr->u.zToken,
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
@@ -94600,11 +105669,6 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
return WRC_Continue;
}
-static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
- UNUSED_PARAMETER(pWalker);
- UNUSED_PARAMETER(pSelect);
- return WRC_Continue;
-}
/*
** Analyze the pExpr expression looking for aggregate functions and
@@ -94617,10 +105681,12 @@ static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
*/
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
Walker w;
- memset(&w, 0, sizeof(w));
w.xExprCallback = analyzeAggregate;
- w.xSelectCallback = analyzeAggregatesInSelect;
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
+ w.walkerDepth = 0;
w.u.pNC = pNC;
+ w.pParse = 0;
assert( pNC->pSrcList!=0 );
sqlite3WalkExpr(&w, pExpr);
}
@@ -94654,22 +105720,13 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){
/*
** Deallocate a register, making available for reuse for some other
** purpose.
-**
-** If a register is currently being used by the column cache, then
-** the deallocation is deferred until the column cache line that uses
-** the register becomes stale.
*/
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
- if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
- int i;
- struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
- if( p->iReg==iReg ){
- p->tempReg = 1;
- return;
- }
+ if( iReg ){
+ sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0, 0);
+ if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
+ pParse->aTempReg[pParse->nTempReg++] = iReg;
}
- pParse->aTempReg[pParse->nTempReg++] = iReg;
}
}
@@ -94682,7 +105739,6 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
i = pParse->iRangeReg;
n = pParse->nRangeReg;
if( nReg<=n ){
- assert( !usedAsColumnCache(pParse, i, i+n-1) );
pParse->iRangeReg += nReg;
pParse->nRangeReg -= nReg;
}else{
@@ -94696,7 +105752,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
sqlite3ReleaseTempReg(pParse, iReg);
return;
}
- sqlite3ExprCacheRemove(pParse, iReg, nReg);
+ sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0, 0);
if( nReg>pParse->nRangeReg ){
pParse->nRangeReg = nReg;
pParse->iRangeReg = iReg;
@@ -94705,6 +105761,11 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
/*
** Mark all temporary registers as being unavailable for reuse.
+**
+** Always invoke this procedure after coding a subroutine or co-routine
+** that might be invoked from other parts of the code, to ensure that
+** the sub/co-routine does not use registers in common with the code that
+** invokes the sub/co-routine.
*/
SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
pParse->nTempReg = 0;
@@ -94720,8 +105781,8 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
int i;
if( pParse->nRangeReg>0
- && pParse->iRangeReg+pParse->nRangeReg<iLast
- && pParse->iRangeReg>=iFirst
+ && pParse->iRangeReg+pParse->nRangeReg > iFirst
+ && pParse->iRangeReg <= iLast
){
return 0;
}
@@ -94758,371 +105819,74 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
*/
#ifndef SQLITE_OMIT_ALTERTABLE
-
-/*
-** This function is used by SQL generated to implement the
-** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
-** CREATE INDEX command. The second is a table name. The table name in
-** the CREATE TABLE or CREATE INDEX statement is replaced with the third
-** argument and the result returned. Examples:
-**
-** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
-** -> 'CREATE TABLE def(a, b, c)'
-**
-** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def')
-** -> 'CREATE INDEX i ON def(a, b, c)'
-*/
-static void renameTableFunc(
- sqlite3_context *context,
- int NotUsed,
- sqlite3_value **argv
-){
- unsigned char const *zSql = sqlite3_value_text(argv[0]);
- unsigned char const *zTableName = sqlite3_value_text(argv[1]);
-
- int token;
- Token tname;
- unsigned char const *zCsr = zSql;
- int len = 0;
- char *zRet;
-
- sqlite3 *db = sqlite3_context_db_handle(context);
-
- UNUSED_PARAMETER(NotUsed);
-
- /* The principle used to locate the table name in the CREATE TABLE
- ** statement is that the table name is the first non-space token that
- ** is immediately followed by a TK_LP or TK_USING token.
- */
- if( zSql ){
- do {
- if( !*zCsr ){
- /* Ran out of input before finding an opening bracket. Return NULL. */
- return;
- }
-
- /* Store the token that zCsr points to in tname. */
- tname.z = (char*)zCsr;
- tname.n = len;
-
- /* Advance zCsr to the next token. Store that token type in 'token',
- ** and its length in 'len' (to be used next iteration of this loop).
- */
- do {
- zCsr += len;
- len = sqlite3GetToken(zCsr, &token);
- } while( token==TK_SPACE );
- assert( len>0 );
- } while( token!=TK_LP && token!=TK_USING );
-
- zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql),
- zSql, zTableName, tname.z+tname.n);
- sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
- }
-}
-
/*
-** This C function implements an SQL user function that is used by SQL code
-** generated by the ALTER TABLE ... RENAME command to modify the definition
-** of any foreign key constraints that use the table being renamed as the
-** parent table. It is passed three arguments:
-**
-** 1) The complete text of the CREATE TABLE statement being modified,
-** 2) The old name of the table being renamed, and
-** 3) The new name of the table being renamed.
-**
-** It returns the new CREATE TABLE statement. For example:
-**
-** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3')
-** -> 'CREATE TABLE t1(a REFERENCES t3)'
-*/
-#ifndef SQLITE_OMIT_FOREIGN_KEY
-static void renameParentFunc(
- sqlite3_context *context,
- int NotUsed,
- sqlite3_value **argv
-){
- sqlite3 *db = sqlite3_context_db_handle(context);
- char *zOutput = 0;
- char *zResult;
- unsigned char const *zInput = sqlite3_value_text(argv[0]);
- unsigned char const *zOld = sqlite3_value_text(argv[1]);
- unsigned char const *zNew = sqlite3_value_text(argv[2]);
-
- unsigned const char *z; /* Pointer to token */
- int n; /* Length of token z */
- int token; /* Type of token */
-
- UNUSED_PARAMETER(NotUsed);
- if( zInput==0 || zOld==0 ) return;
- for(z=zInput; *z; z=z+n){
- n = sqlite3GetToken(z, &token);
- if( token==TK_REFERENCES ){
- char *zParent;
- do {
- z += n;
- n = sqlite3GetToken(z, &token);
- }while( token==TK_SPACE );
-
- if( token==TK_ILLEGAL ) break;
- zParent = sqlite3DbStrNDup(db, (const char *)z, n);
- if( zParent==0 ) break;
- sqlite3Dequote(zParent);
- if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){
- char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"",
- (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew
- );
- sqlite3DbFree(db, zOutput);
- zOutput = zOut;
- zInput = &z[n];
- }
- sqlite3DbFree(db, zParent);
- }
- }
-
- zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput),
- sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC);
- sqlite3DbFree(db, zOutput);
-}
-#endif
-
-#ifndef SQLITE_OMIT_TRIGGER
-/* This function is used by SQL generated to implement the
-** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
-** statement. The second is a table name. The table name in the CREATE
-** TRIGGER statement is replaced with the third argument and the result
-** returned. This is analagous to renameTableFunc() above, except for CREATE
-** TRIGGER, not CREATE INDEX and CREATE TABLE.
-*/
-static void renameTriggerFunc(
- sqlite3_context *context,
- int NotUsed,
- sqlite3_value **argv
-){
- unsigned char const *zSql = sqlite3_value_text(argv[0]);
- unsigned char const *zTableName = sqlite3_value_text(argv[1]);
-
- int token;
- Token tname;
- int dist = 3;
- unsigned char const *zCsr = zSql;
- int len = 0;
- char *zRet;
- sqlite3 *db = sqlite3_context_db_handle(context);
-
- UNUSED_PARAMETER(NotUsed);
-
- /* The principle used to locate the table name in the CREATE TRIGGER
- ** statement is that the table name is the first token that is immediately
- ** preceded by either TK_ON or TK_DOT and immediately followed by one
- ** of TK_WHEN, TK_BEGIN or TK_FOR.
- */
- if( zSql ){
- do {
-
- if( !*zCsr ){
- /* Ran out of input before finding the table name. Return NULL. */
- return;
- }
-
- /* Store the token that zCsr points to in tname. */
- tname.z = (char*)zCsr;
- tname.n = len;
-
- /* Advance zCsr to the next token. Store that token type in 'token',
- ** and its length in 'len' (to be used next iteration of this loop).
- */
- do {
- zCsr += len;
- len = sqlite3GetToken(zCsr, &token);
- }while( token==TK_SPACE );
- assert( len>0 );
-
- /* Variable 'dist' stores the number of tokens read since the most
- ** recent TK_DOT or TK_ON. This means that when a WHEN, FOR or BEGIN
- ** token is read and 'dist' equals 2, the condition stated above
- ** to be met.
- **
- ** Note that ON cannot be a database, table or column name, so
- ** there is no need to worry about syntax like
- ** "CREATE TRIGGER ... ON ON.ON BEGIN ..." etc.
- */
- dist++;
- if( token==TK_DOT || token==TK_ON ){
- dist = 0;
- }
- } while( dist!=2 || (token!=TK_WHEN && token!=TK_FOR && token!=TK_BEGIN) );
-
- /* Variable tname now contains the token that is the old table-name
- ** in the CREATE TRIGGER statement.
- */
- zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", (int)(((u8*)tname.z) - zSql),
- zSql, zTableName, tname.z+tname.n);
- sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC);
- }
-}
-#endif /* !SQLITE_OMIT_TRIGGER */
-
-/*
-** Register built-in functions used to help implement ALTER TABLE
-*/
-SQLITE_PRIVATE void sqlite3AlterFunctions(void){
- static FuncDef aAlterTableFuncs[] = {
- FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
-#ifndef SQLITE_OMIT_TRIGGER
- FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
-#endif
-#ifndef SQLITE_OMIT_FOREIGN_KEY
- FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
-#endif
- };
- sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
-}
-
-/*
-** This function is used to create the text of expressions of the form:
-**
-** name=<constant1> OR name=<constant2> OR ...
-**
-** If argument zWhere is NULL, then a pointer string containing the text
-** "name=<constant>" is returned, where <constant> is the quoted version
-** of the string passed as argument zConstant. The returned buffer is
-** allocated using sqlite3DbMalloc(). It is the responsibility of the
-** caller to ensure that it is eventually freed.
+** Parameter zName is the name of a table that is about to be altered
+** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN).
+** If the table is a system table, this function leaves an error message
+** in pParse->zErr (system tables may not be altered) and returns non-zero.
**
-** If argument zWhere is not NULL, then the string returned is
-** "<where> OR name=<constant>", where <where> is the contents of zWhere.
-** In this case zWhere is passed to sqlite3DbFree() before returning.
-**
-*/
-static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){
- char *zNew;
- if( !zWhere ){
- zNew = sqlite3MPrintf(db, "name=%Q", zConstant);
- }else{
- zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant);
- sqlite3DbFree(db, zWhere);
- }
- return zNew;
-}
-
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
-/*
-** Generate the text of a WHERE expression which can be used to select all
-** tables that have foreign key constraints that refer to table pTab (i.e.
-** constraints for which pTab is the parent table) from the sqlite_master
-** table.
+** Or, if zName is not a system table, zero is returned.
*/
-static char *whereForeignKeys(Parse *pParse, Table *pTab){
- FKey *p;
- char *zWhere = 0;
- for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
- zWhere = whereOrName(pParse->db, zWhere, p->pFrom->zName);
- }
- return zWhere;
-}
+static int isAlterableTable(Parse *pParse, Table *pTab){
+ if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ || ( (pTab->tabFlags & TF_Shadow)!=0
+ && sqlite3ReadOnlyShadowTables(pParse->db)
+ )
#endif
-
-/*
-** Generate the text of a WHERE expression which can be used to select all
-** temporary triggers on table pTab from the sqlite_temp_master table. If
-** table pTab has no temporary triggers, or is itself stored in the
-** temporary database, NULL is returned.
-*/
-static char *whereTempTriggers(Parse *pParse, Table *pTab){
- Trigger *pTrig;
- char *zWhere = 0;
- const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */
-
- /* If the table is not located in the temp-db (in which case NULL is
- ** returned, loop through the tables list of triggers. For each trigger
- ** that is not part of the temp-db schema, add a clause to the WHERE
- ** expression being built up in zWhere.
- */
- if( pTab->pSchema!=pTempSchema ){
- sqlite3 *db = pParse->db;
- for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
- if( pTrig->pSchema==pTempSchema ){
- zWhere = whereOrName(db, zWhere, pTrig->zName);
- }
- }
- }
- if( zWhere ){
- char *zNew = sqlite3MPrintf(pParse->db, "type='trigger' AND (%s)", zWhere);
- sqlite3DbFree(pParse->db, zWhere);
- zWhere = zNew;
+ ){
+ sqlite3ErrorMsg(pParse, "table %s may not be altered", pTab->zName);
+ return 1;
}
- return zWhere;
+ return 0;
}
/*
-** Generate code to drop and reload the internal representation of table
-** pTab from the database, including triggers and temporary triggers.
-** Argument zName is the name of the table in the database schema at
-** the time the generated code is executed. This can be different from
-** pTab->zName if this function is being called to code part of an
-** "ALTER TABLE RENAME TO" statement.
+** Generate code to verify that the schemas of database zDb and, if
+** bTemp is not true, database "temp", can still be parsed. This is
+** called at the end of the generation of an ALTER TABLE ... RENAME ...
+** statement to ensure that the operation has not rendered any schema
+** objects unusable.
*/
-static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){
- Vdbe *v;
- char *zWhere;
- int iDb; /* Index of database containing pTab */
-#ifndef SQLITE_OMIT_TRIGGER
- Trigger *pTrig;
-#endif
-
- v = sqlite3GetVdbe(pParse);
- if( NEVER(v==0) ) return;
- assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
- iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
- assert( iDb>=0 );
-
-#ifndef SQLITE_OMIT_TRIGGER
- /* Drop any table triggers from the internal schema. */
- for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){
- int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema);
- assert( iTrigDb==iDb || iTrigDb==1 );
- sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->zName, 0);
- }
-#endif
-
- /* Drop the table and index from the internal schema. */
- sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
-
- /* Reload the table, index and permanent trigger schemas. */
- zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName);
- if( !zWhere ) return;
- sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
+static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
+ sqlite3NestedParse(pParse,
+ "SELECT 1 "
+ "FROM \"%w\"." DFLT_SCHEMA_TABLE " "
+ "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
+ " AND sql NOT LIKE 'create virtual%%'"
+ " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
+ zDb,
+ zDb, bTemp
+ );
-#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 ){
- sqlite3VdbeAddParseSchemaOp(v, 1, zWhere);
+ if( bTemp==0 ){
+ sqlite3NestedParse(pParse,
+ "SELECT 1 "
+ "FROM temp." DFLT_SCHEMA_TABLE " "
+ "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
+ " AND sql NOT LIKE 'create virtual%%'"
+ " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
+ zDb
+ );
}
-#endif
}
/*
-** Parameter zName is the name of a table that is about to be altered
-** (either with ALTER TABLE ... RENAME TO or ALTER TABLE ... ADD COLUMN).
-** If the table is a system table, this function leaves an error message
-** in pParse->zErr (system tables may not be altered) and returns non-zero.
-**
-** Or, if zName is not a system table, zero is returned.
+** Generate code to reload the schema for database iDb. And, if iDb!=1, for
+** the temp database as well.
*/
-static int isSystemTable(Parse *pParse, const char *zName){
- if( sqlite3Strlen30(zName)>6 && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
- sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
- return 1;
+static void renameReloadSchema(Parse *pParse, int iDb){
+ Vdbe *v = pParse->pVdbe;
+ if( v ){
+ sqlite3ChangeCookie(pParse, iDb);
+ sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
+ if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
}
- return 0;
}
/*
-** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
-** command.
+** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
+** command.
*/
SQLITE_PRIVATE void sqlite3AlterRenameTable(
Parse *pParse, /* Parser context. */
@@ -95132,18 +105896,15 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
int iDb; /* Database that contains the table */
char *zDb; /* Name of database iDb */
Table *pTab; /* Table being renamed */
- char *zName = 0; /* NULL-terminated version of pName */
+ char *zName = 0; /* NULL-terminated version of pName */
sqlite3 *db = pParse->db; /* Database connection */
int nTabName; /* Number of UTF-8 characters in zTabName */
const char *zTabName; /* Original name of the table */
Vdbe *v;
-#ifndef SQLITE_OMIT_TRIGGER
- char *zWhere = 0; /* Where clause to locate temp triggers */
-#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
- int savedDbFlags; /* Saved value of db->flags */
+ u32 savedDbFlags; /* Saved value of db->mDbFlags */
- savedDbFlags = db->flags;
+ savedDbFlags = db->mDbFlags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -95152,7 +105913,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zDbSName;
- db->flags |= SQLITE_PreferBuiltin;
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -95161,8 +105922,11 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
/* Check that a table or index named 'zName' does not already exist
** in database iDb. If so, this is an error.
*/
- if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
- sqlite3ErrorMsg(pParse,
+ if( sqlite3FindTable(db, zName, zDb)
+ || sqlite3FindIndex(db, zName, zDb)
+ || sqlite3IsShadowTableOf(db, pTab, zName)
+ ){
+ sqlite3ErrorMsg(pParse,
"there is already another table or index with this name: %s", zName);
goto exit_rename_table;
}
@@ -95170,11 +105934,11 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
/* Make sure it is not a system table being altered, or a reserved name
** that the table is being renamed to.
*/
- if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
goto exit_rename_table;
}
- if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto
- exit_rename_table;
+ if( SQLITE_OK!=sqlite3CheckObjectName(pParse,zName,"table",zName) ){
+ goto exit_rename_table;
}
#ifndef SQLITE_OMIT_VIEW
@@ -95203,78 +105967,50 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
}
#endif
- /* Begin a transaction for database iDb.
- ** Then modify the schema cookie (since the ALTER TABLE modifies the
- ** schema). Open a statement transaction if the table is a virtual
- ** table.
- */
+ /* Begin a transaction for database iDb. Then modify the schema cookie
+ ** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(),
+ ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the
+ ** nested SQL may raise an exception. */
v = sqlite3GetVdbe(pParse);
if( v==0 ){
goto exit_rename_table;
}
- sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb);
- sqlite3ChangeCookie(pParse, iDb);
-
- /* If this is a virtual table, invoke the xRename() function if
- ** one is defined. The xRename() callback will modify the names
- ** of any resources used by the v-table implementation (including other
- ** SQLite tables) that are identified by the name of the virtual table.
- */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( pVTab ){
- int i = ++pParse->nMem;
- sqlite3VdbeLoadString(v, i, zName);
- sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
- sqlite3MayAbort(pParse);
- }
-#endif
+ sqlite3MayAbort(pParse);
/* figure out how many UTF-8 characters are in zName */
zTabName = pTab->zName;
nTabName = sqlite3Utf8CharLen(zTabName, -1);
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- if( db->flags&SQLITE_ForeignKeys ){
- /* If foreign-key support is enabled, rewrite the CREATE TABLE
- ** statements corresponding to all child tables of foreign key constraints
- ** for which the renamed table is the parent table. */
- if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){
- sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
- "sql = sqlite_rename_parent(sql, %Q, %Q) "
- "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
- sqlite3DbFree(db, zWhere);
- }
- }
-#endif
+ /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
+ ** the schema to use the new table name. */
+ sqlite3NestedParse(pParse,
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
+ "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) "
+ "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
+ "AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
+ , zDb, zDb, zTabName, zName, (iDb==1), zTabName
+ );
- /* Modify the sqlite_master table to use the new table name. */
+ /* Update the tbl_name and name columns of the sqlite_schema table
+ ** as required. */
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET "
-#ifdef SQLITE_OMIT_TRIGGER
- "sql = sqlite_rename_table(sql, %Q), "
-#else
- "sql = CASE "
- "WHEN type = 'trigger' THEN sqlite_rename_trigger(sql, %Q)"
- "ELSE sqlite_rename_table(sql, %Q) END, "
-#endif
+ "UPDATE %Q." DFLT_SCHEMA_TABLE " SET "
"tbl_name = %Q, "
"name = CASE "
"WHEN type='table' THEN %Q "
- "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
+ "WHEN name LIKE 'sqliteX_autoindex%%' ESCAPE 'X' "
+ " AND type='index' THEN "
"'sqlite_autoindex_' || %Q || substr(name,%d+18) "
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
- "(type='table' OR type='index' OR type='trigger');",
- zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
-#ifndef SQLITE_OMIT_TRIGGER
- zName,
-#endif
- zName, nTabName, zTabName
+ "(type='table' OR type='index' OR type='trigger');",
+ zDb,
+ zName, zName, zName,
+ nTabName, zTabName
);
#ifndef SQLITE_OMIT_AUTOINCREMENT
- /* If the sqlite_sequence table exists in this database, then update
+ /* If the sqlite_sequence table exists in this database, then update
** it with the new table name.
*/
if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
@@ -95284,40 +106020,57 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
}
#endif
-#ifndef SQLITE_OMIT_TRIGGER
- /* If there are TEMP triggers on this table, modify the sqlite_temp_master
- ** table. Don't do this if the table being ALTERed is itself located in
- ** the temp database.
- */
- if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){
- sqlite3NestedParse(pParse,
- "UPDATE sqlite_temp_master SET "
- "sql = sqlite_rename_trigger(sql, %Q), "
- "tbl_name = %Q "
- "WHERE %s;", zName, zName, zWhere);
- sqlite3DbFree(db, zWhere);
+ /* If the table being renamed is not itself part of the temp database,
+ ** edit view and trigger definitions within the temp database
+ ** as required. */
+ if( iDb!=1 ){
+ sqlite3NestedParse(pParse,
+ "UPDATE sqlite_temp_schema SET "
+ "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
+ "tbl_name = "
+ "CASE WHEN tbl_name=%Q COLLATE nocase AND "
+ " sqlite_rename_test(%Q, sql, type, name, 1) "
+ "THEN %Q ELSE tbl_name END "
+ "WHERE type IN ('view', 'trigger')"
+ , zDb, zTabName, zName, zTabName, zDb, zName);
}
-#endif
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- if( db->flags&SQLITE_ForeignKeys ){
- FKey *p;
- for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
- Table *pFrom = p->pFrom;
- if( pFrom!=pTab ){
- reloadTableSchema(pParse, p->pFrom, pFrom->zName);
- }
- }
+ /* If this is a virtual table, invoke the xRename() function if
+ ** one is defined. The xRename() callback will modify the names
+ ** of any resources used by the v-table implementation (including other
+ ** SQLite tables) that are identified by the name of the virtual table.
+ */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pVTab ){
+ int i = ++pParse->nMem;
+ sqlite3VdbeLoadString(v, i, zName);
+ sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
}
#endif
- /* Drop and reload the internal table schema. */
- reloadTableSchema(pParse, pTab, zName);
+ renameReloadSchema(pParse, iDb);
+ renameTestSchema(pParse, zDb, iDb==1);
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
+}
+
+/*
+** Write code that will raise an error if the table described by
+** zDb and zTab is not empty.
+*/
+static void sqlite3ErrorIfNotEmpty(
+ Parse *pParse, /* Parsing context */
+ const char *zDb, /* Schema holding the table */
+ const char *zTab, /* Table to check for empty */
+ const char *zErr /* Error message text */
+){
+ sqlite3NestedParse(pParse,
+ "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
+ zErr, zDb, zTab
+ );
}
/*
@@ -95338,12 +106091,11 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
Column *pCol; /* The new column */
Expr *pDflt; /* Default value for the new column */
sqlite3 *db; /* The database connection; */
- Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
+ Vdbe *v; /* The prepared statement under construction */
int r1; /* Temporary registers */
db = pParse->db;
if( pParse->nErr || db->mallocFailed ) return;
- assert( v!=0 );
pNew = pParse->pNewTable;
assert( pNew );
@@ -95363,14 +106115,6 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
}
#endif
- /* If the default value for the new column was specified with a
- ** literal NULL, then set pDflt to 0. This simplifies checking
- ** for an SQL NULL default below.
- */
- assert( pDflt==0 || pDflt->op==TK_SPAN );
- if( pDflt && pDflt->pLeft->op==TK_NULL ){
- pDflt = 0;
- }
/* Check that the new column is not specified as PRIMARY KEY or UNIQUE.
** If there is a NOT NULL constraint, then the default value for the
@@ -95381,86 +106125,102 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
return;
}
if( pNew->pIndex ){
- sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
- return;
- }
- if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
- sqlite3ErrorMsg(pParse,
- "Cannot add a REFERENCES column with non-NULL default value");
- return;
- }
- if( pCol->notNull && !pDflt ){
- sqlite3ErrorMsg(pParse,
- "Cannot add a NOT NULL column with default value NULL");
+ sqlite3ErrorMsg(pParse,
+ "Cannot add a UNIQUE column");
return;
}
-
- /* Ensure the default expression is something that sqlite3ValueFromExpr()
- ** can handle (i.e. not CURRENT_TIME etc.)
- */
- if( pDflt ){
- sqlite3_value *pVal = 0;
- int rc;
- rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
- assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
- if( rc!=SQLITE_OK ){
- assert( db->mallocFailed == 1 );
- return;
+ if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
+ /* If the default value for the new column was specified with a
+ ** literal NULL, then set pDflt to 0. This simplifies checking
+ ** for an SQL NULL default below.
+ */
+ assert( pDflt==0 || pDflt->op==TK_SPAN );
+ if( pDflt && pDflt->pLeft->op==TK_NULL ){
+ pDflt = 0;
}
- if( !pVal ){
- sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default");
- return;
+ if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
+ "Cannot add a REFERENCES column with non-NULL default value");
+ }
+ if( pCol->notNull && !pDflt ){
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
+ "Cannot add a NOT NULL column with default value NULL");
+ }
+
+
+ /* Ensure the default expression is something that sqlite3ValueFromExpr()
+ ** can handle (i.e. not CURRENT_TIME etc.)
+ */
+ if( pDflt ){
+ sqlite3_value *pVal = 0;
+ int rc;
+ rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal);
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
+ if( rc!=SQLITE_OK ){
+ assert( db->mallocFailed == 1 );
+ return;
+ }
+ if( !pVal ){
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
+ "Cannot add a column with non-constant default");
+ }
+ sqlite3ValueFree(pVal);
}
- sqlite3ValueFree(pVal);
+ }else if( pCol->colFlags & COLFLAG_STORED ){
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
}
+
/* Modify the CREATE TABLE statement. */
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
- int savedDbFlags = db->flags;
+ u32 savedDbFlags = db->mDbFlags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
- db->flags |= SQLITE_PreferBuiltin;
- sqlite3NestedParse(pParse,
- "UPDATE \"%w\".%s SET "
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
+ sqlite3NestedParse(pParse,
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
- "WHERE type = 'table' AND name = %Q",
- zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
+ "WHERE type = 'table' AND name = %Q",
+ zDb, pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
sqlite3DbFree(db, zCol);
- db->flags = savedDbFlags;
+ db->mDbFlags = savedDbFlags;
}
/* Make sure the schema version is at least 3. But do not upgrade
** from less than 3 to 4, as that will corrupt any preexisting DESC
** index.
*/
- r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
- sqlite3VdbeUsesBtree(v, iDb);
- sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
- sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
- VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
- sqlite3ReleaseTempReg(pParse, r1);
+ v = sqlite3GetVdbe(pParse);
+ if( v ){
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
+ sqlite3VdbeUsesBtree(v, iDb);
+ sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
+ sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
+ sqlite3ReleaseTempReg(pParse, r1);
+ }
- /* Reload the schema of the modified table. */
- reloadTableSchema(pParse, pTab, pTab->zName);
+ /* Reload the table definition */
+ renameReloadSchema(pParse, iDb);
}
/*
** This function is called by the parser after the table-name in
-** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
+** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
** pSrc is the full-name of the table being altered.
**
** This routine makes a (partial) copy of the Table structure
** for the table being altered and sets Parse.pNewTable to point
** to it. Routines called by the parser as the column definition
-** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
-** the copy. The copy of the Table structure is deleted by tokenize.c
+** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
+** the copy. The copy of the Table structure is deleted by tokenize.c
** after parsing is finished.
**
** Routine sqlite3AlterFinishAddColumn() will be called to complete
@@ -95469,7 +106229,6 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
Table *pNew;
Table *pTab;
- Vdbe *v;
int iDb;
int i;
int nAlloc;
@@ -95494,10 +106253,11 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
goto exit_begin_add_column;
}
- if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ){
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ){
goto exit_begin_add_column;
}
+ sqlite3MayAbort(pParse);
assert( pTab->addColOffset>0 );
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -95511,7 +106271,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
- pNew->nRef = 1;
+ pNew->nTabRef = 1;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;
@@ -95526,23 +106286,1263 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
+ pCol->hName = sqlite3StrIHash(pCol->zName);
pCol->zColl = 0;
pCol->pDflt = 0;
}
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
- pNew->nRef = 1;
-
- /* Begin a transaction and increment the schema cookie. */
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- v = sqlite3GetVdbe(pParse);
- if( !v ) goto exit_begin_add_column;
- sqlite3ChangeCookie(pParse, iDb);
+ pNew->nTabRef = 1;
exit_begin_add_column:
sqlite3SrcListDelete(db, pSrc);
return;
}
+
+/*
+** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN
+** command. This function checks if the table is a view or virtual
+** table (columns of views or virtual tables may not be renamed). If so,
+** it loads an error message into pParse and returns non-zero.
+**
+** Or, if pTab is not a view or virtual table, zero is returned.
+*/
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
+static int isRealTable(Parse *pParse, Table *pTab){
+ const char *zType = 0;
+#ifndef SQLITE_OMIT_VIEW
+ if( pTab->pSelect ){
+ zType = "view";
+ }
+#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab) ){
+ zType = "virtual table";
+ }
+#endif
+ if( zType ){
+ sqlite3ErrorMsg(
+ pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName
+ );
+ return 1;
+ }
+ return 0;
+}
+#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
+# define isRealTable(x,y) (0)
+#endif
+
+/*
+** Handles the following parser reduction:
+**
+** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew
+*/
+SQLITE_PRIVATE void sqlite3AlterRenameColumn(
+ Parse *pParse, /* Parsing context */
+ SrcList *pSrc, /* Table being altered. pSrc->nSrc==1 */
+ Token *pOld, /* Name of column being changed */
+ Token *pNew /* New column name */
+){
+ sqlite3 *db = pParse->db; /* Database connection */
+ Table *pTab; /* Table being updated */
+ int iCol; /* Index of column being renamed */
+ char *zOld = 0; /* Old column name */
+ char *zNew = 0; /* New column name */
+ const char *zDb; /* Name of schema containing the table */
+ int iSchema; /* Index of the schema */
+ int bQuote; /* True to quote the new name */
+
+ /* Locate the table to be altered */
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
+ if( !pTab ) goto exit_rename_column;
+
+ /* Cannot alter a system table */
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
+ if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
+
+ /* Which schema holds the table to be altered */
+ iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
+ assert( iSchema>=0 );
+ zDb = db->aDb[iSchema].zDbSName;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ /* Invoke the authorization callback. */
+ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
+ goto exit_rename_column;
+ }
+#endif
+
+ /* Make sure the old name really is a column name in the table to be
+ ** altered. Set iCol to be the index of the column being renamed */
+ zOld = sqlite3NameFromToken(db, pOld);
+ if( !zOld ) goto exit_rename_column;
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break;
+ }
+ if( iCol==pTab->nCol ){
+ sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
+ goto exit_rename_column;
+ }
+
+ /* Do the rename operation using a recursive UPDATE statement that
+ ** uses the sqlite_rename_column() SQL function to compute the new
+ ** CREATE statement text for the sqlite_schema table.
+ */
+ sqlite3MayAbort(pParse);
+ zNew = sqlite3NameFromToken(db, pNew);
+ if( !zNew ) goto exit_rename_column;
+ assert( pNew->n>0 );
+ bQuote = sqlite3Isquote(pNew->z[0]);
+ sqlite3NestedParse(pParse,
+ "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
+ "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
+ "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
+ " AND (type != 'index' OR tbl_name = %Q)"
+ " AND sql NOT LIKE 'create virtual%%'",
+ zDb,
+ zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
+ pTab->zName
+ );
+
+ sqlite3NestedParse(pParse,
+ "UPDATE temp." DFLT_SCHEMA_TABLE " SET "
+ "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) "
+ "WHERE type IN ('trigger', 'view')",
+ zDb, pTab->zName, iCol, zNew, bQuote
+ );
+
+ /* Drop and reload the database schema. */
+ renameReloadSchema(pParse, iSchema);
+ renameTestSchema(pParse, zDb, iSchema==1);
+
+ exit_rename_column:
+ sqlite3SrcListDelete(db, pSrc);
+ sqlite3DbFree(db, zOld);
+ sqlite3DbFree(db, zNew);
+ return;
+}
+
+/*
+** Each RenameToken object maps an element of the parse tree into
+** the token that generated that element. The parse tree element
+** might be one of:
+**
+** * A pointer to an Expr that represents an ID
+** * The name of a table column in Column.zName
+**
+** A list of RenameToken objects can be constructed during parsing.
+** Each new object is created by sqlite3RenameTokenMap().
+** As the parse tree is transformed, the sqlite3RenameTokenRemap()
+** routine is used to keep the mapping current.
+**
+** After the parse finishes, renameTokenFind() routine can be used
+** to look up the actual token value that created some element in
+** the parse tree.
+*/
+struct RenameToken {
+ void *p; /* Parse tree element created by token t */
+ Token t; /* The token that created parse tree element p */
+ RenameToken *pNext; /* Next is a list of all RenameToken objects */
+};
+
+/*
+** The context of an ALTER TABLE RENAME COLUMN operation that gets passed
+** down into the Walker.
+*/
+typedef struct RenameCtx RenameCtx;
+struct RenameCtx {
+ RenameToken *pList; /* List of tokens to overwrite */
+ int nList; /* Number of tokens in pList */
+ int iCol; /* Index of column being renamed */
+ Table *pTab; /* Table being ALTERed */
+ const char *zOld; /* Old column name */
+};
+
+#ifdef SQLITE_DEBUG
+/*
+** This function is only for debugging. It performs two tasks:
+**
+** 1. Checks that pointer pPtr does not already appear in the
+** rename-token list.
+**
+** 2. Dereferences each pointer in the rename-token list.
+**
+** The second is most effective when debugging under valgrind or
+** address-sanitizer or similar. If any of these pointers no longer
+** point to valid objects, an exception is raised by the memory-checking
+** tool.
+**
+** The point of this is to prevent comparisons of invalid pointer values.
+** Even though this always seems to work, it is undefined according to the
+** C standard. Example of undefined comparison:
+**
+** sqlite3_free(x);
+** if( x==y ) ...
+**
+** Technically, as x no longer points into a valid object or to the byte
+** following a valid object, it may not be used in comparison operations.
+*/
+static void renameTokenCheckAll(Parse *pParse, void *pPtr){
+ if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){
+ RenameToken *p;
+ u8 i = 0;
+ for(p=pParse->pRename; p; p=p->pNext){
+ if( p->p ){
+ assert( p->p!=pPtr );
+ i += *(u8*)(p->p);
+ }
+ }
+ }
+}
+#else
+# define renameTokenCheckAll(x,y)
+#endif
+
+/*
+** Remember that the parser tree element pPtr was created using
+** the token pToken.
+**
+** In other words, construct a new RenameToken object and add it
+** to the list of RenameToken objects currently being built up
+** in pParse->pRename.
+**
+** The pPtr argument is returned so that this routine can be used
+** with tail recursion in tokenExpr() routine, for a small performance
+** improvement.
+*/
+SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
+ RenameToken *pNew;
+ assert( pPtr || pParse->db->mallocFailed );
+ renameTokenCheckAll(pParse, pPtr);
+ if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
+ pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
+ if( pNew ){
+ pNew->p = pPtr;
+ pNew->t = *pToken;
+ pNew->pNext = pParse->pRename;
+ pParse->pRename = pNew;
+ }
+ }
+
+ return pPtr;
+}
+
+/*
+** It is assumed that there is already a RenameToken object associated
+** with parse tree element pFrom. This function remaps the associated token
+** to parse tree element pTo.
+*/
+SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){
+ RenameToken *p;
+ renameTokenCheckAll(pParse, pTo);
+ for(p=pParse->pRename; p; p=p->pNext){
+ if( p->p==pFrom ){
+ p->p = pTo;
+ break;
+ }
+ }
+}
+
+/*
+** Walker callback used by sqlite3RenameExprUnmap().
+*/
+static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
+ Parse *pParse = pWalker->pParse;
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
+ return WRC_Continue;
+}
+
+/*
+** Iterate through the Select objects that are part of WITH clauses attached
+** to select statement pSelect.
+*/
+static void renameWalkWith(Walker *pWalker, Select *pSelect){
+ With *pWith = pSelect->pWith;
+ if( pWith ){
+ int i;
+ for(i=0; i<pWith->nCte; i++){
+ Select *p = pWith->a[i].pSelect;
+ NameContext sNC;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pWalker->pParse;
+ sqlite3SelectPrep(sNC.pParse, p, &sNC);
+ sqlite3WalkSelect(pWalker, p);
+ sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
+ }
+ }
+}
+
+/*
+** Unmap all tokens in the IdList object passed as the second argument.
+*/
+static void unmapColumnIdlistNames(
+ Parse *pParse,
+ IdList *pIdList
+){
+ if( pIdList ){
+ int ii;
+ for(ii=0; ii<pIdList->nId; ii++){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName);
+ }
+ }
+}
+
+/*
+** Walker callback used by sqlite3RenameExprUnmap().
+*/
+static int renameUnmapSelectCb(Walker *pWalker, Select *p){
+ Parse *pParse = pWalker->pParse;
+ int i;
+ if( pParse->nErr ) return WRC_Abort;
+ if( NEVER(p->selFlags & SF_View) ) return WRC_Prune;
+ if( ALWAYS(p->pEList) ){
+ ExprList *pList = p->pEList;
+ for(i=0; i<pList->nExpr; i++){
+ if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
+ }
+ }
+ }
+ if( ALWAYS(p->pSrc) ){ /* Every Select as a SrcList, even if it is empty */
+ SrcList *pSrc = p->pSrc;
+ for(i=0; i<pSrc->nSrc; i++){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
+ if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
+ unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
+ }
+ }
+
+ renameWalkWith(pWalker, p);
+ return WRC_Continue;
+}
+
+/*
+** Remove all nodes that are part of expression pExpr from the rename list.
+*/
+SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){
+ u8 eMode = pParse->eParseMode;
+ Walker sWalker;
+ memset(&sWalker, 0, sizeof(Walker));
+ sWalker.pParse = pParse;
+ sWalker.xExprCallback = renameUnmapExprCb;
+ sWalker.xSelectCallback = renameUnmapSelectCb;
+ pParse->eParseMode = PARSE_MODE_UNMAP;
+ sqlite3WalkExpr(&sWalker, pExpr);
+ pParse->eParseMode = eMode;
+}
+
+/*
+** Remove all nodes that are part of expression-list pEList from the
+** rename list.
+*/
+SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
+ if( pEList ){
+ int i;
+ Walker sWalker;
+ memset(&sWalker, 0, sizeof(Walker));
+ sWalker.pParse = pParse;
+ sWalker.xExprCallback = renameUnmapExprCb;
+ sqlite3WalkExprList(&sWalker, pEList);
+ for(i=0; i<pEList->nExpr; i++){
+ if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
+ sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
+ }
+ }
+ }
+}
+
+/*
+** Free the list of RenameToken objects given in the second argument
+*/
+static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
+ RenameToken *pNext;
+ RenameToken *p;
+ for(p=pToken; p; p=pNext){
+ pNext = p->pNext;
+ sqlite3DbFree(db, p);
+ }
+}
+
+/*
+** Search the Parse object passed as the first argument for a RenameToken
+** object associated with parse tree element pPtr. If found, remove it
+** from the Parse object and add it to the list maintained by the
+** RenameCtx object passed as the second argument.
+*/
+static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
+ RenameToken **pp;
+ assert( pPtr!=0 );
+ for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
+ if( (*pp)->p==pPtr ){
+ RenameToken *pToken = *pp;
+ *pp = pToken->pNext;
+ pToken->pNext = pCtx->pList;
+ pCtx->pList = pToken;
+ pCtx->nList++;
+ break;
+ }
+ }
+}
+
+/*
+** This is a Walker select callback. It does nothing. It is only required
+** because without a dummy callback, sqlite3WalkExpr() and similar do not
+** descend into sub-select statements.
+*/
+static int renameColumnSelectCb(Walker *pWalker, Select *p){
+ if( p->selFlags & SF_View ) return WRC_Prune;
+ renameWalkWith(pWalker, p);
+ return WRC_Continue;
+}
+
+/*
+** This is a Walker expression callback.
+**
+** For every TK_COLUMN node in the expression tree, search to see
+** if the column being references is the column being renamed by an
+** ALTER TABLE statement. If it is, then attach its associated
+** RenameToken object to the list of RenameToken objects being
+** constructed in RenameCtx object at pWalker->u.pRename.
+*/
+static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
+ RenameCtx *p = pWalker->u.pRename;
+ if( pExpr->op==TK_TRIGGER
+ && pExpr->iColumn==p->iCol
+ && pWalker->pParse->pTriggerTab==p->pTab
+ ){
+ renameTokenFind(pWalker->pParse, p, (void*)pExpr);
+ }else if( pExpr->op==TK_COLUMN
+ && pExpr->iColumn==p->iCol
+ && p->pTab==pExpr->y.pTab
+ ){
+ renameTokenFind(pWalker->pParse, p, (void*)pExpr);
+ }
+ return WRC_Continue;
+}
+
+/*
+** The RenameCtx contains a list of tokens that reference a column that
+** is being renamed by an ALTER TABLE statement. Return the "last"
+** RenameToken in the RenameCtx and remove that RenameToken from the
+** RenameContext. "Last" means the last RenameToken encountered when
+** the input SQL is parsed from left to right. Repeated calls to this routine
+** return all column name tokens in the order that they are encountered
+** in the SQL statement.
+*/
+static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
+ RenameToken *pBest = pCtx->pList;
+ RenameToken *pToken;
+ RenameToken **pp;
+
+ for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){
+ if( pToken->t.z>pBest->t.z ) pBest = pToken;
+ }
+ for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext);
+ *pp = pBest->pNext;
+
+ return pBest;
+}
+
+/*
+** An error occured while parsing or otherwise processing a database
+** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
+** ALTER TABLE RENAME COLUMN program. The error message emitted by the
+** sub-routine is currently stored in pParse->zErrMsg. This function
+** adds context to the error message and then stores it in pCtx.
+*/
+static void renameColumnParseError(
+ sqlite3_context *pCtx,
+ int bPost,
+ sqlite3_value *pType,
+ sqlite3_value *pObject,
+ Parse *pParse
+){
+ const char *zT = (const char*)sqlite3_value_text(pType);
+ const char *zN = (const char*)sqlite3_value_text(pObject);
+ char *zErr;
+
+ zErr = sqlite3_mprintf("error in %s %s%s: %s",
+ zT, zN, (bPost ? " after rename" : ""),
+ pParse->zErrMsg
+ );
+ sqlite3_result_error(pCtx, zErr, -1);
+ sqlite3_free(zErr);
+}
+
+/*
+** For each name in the the expression-list pEList (i.e. each
+** pEList->a[i].zName) that matches the string in zOld, extract the
+** corresponding rename-token from Parse object pParse and add it
+** to the RenameCtx pCtx.
+*/
+static void renameColumnElistNames(
+ Parse *pParse,
+ RenameCtx *pCtx,
+ ExprList *pEList,
+ const char *zOld
+){
+ if( pEList ){
+ int i;
+ for(i=0; i<pEList->nExpr; i++){
+ char *zName = pEList->a[i].zEName;
+ if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
+ && ALWAYS(zName!=0)
+ && 0==sqlite3_stricmp(zName, zOld)
+ ){
+ renameTokenFind(pParse, pCtx, (void*)zName);
+ }
+ }
+ }
+}
+
+/*
+** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName)
+** that matches the string in zOld, extract the corresponding rename-token
+** from Parse object pParse and add it to the RenameCtx pCtx.
+*/
+static void renameColumnIdlistNames(
+ Parse *pParse,
+ RenameCtx *pCtx,
+ IdList *pIdList,
+ const char *zOld
+){
+ if( pIdList ){
+ int i;
+ for(i=0; i<pIdList->nId; i++){
+ char *zName = pIdList->a[i].zName;
+ if( 0==sqlite3_stricmp(zName, zOld) ){
+ renameTokenFind(pParse, pCtx, (void*)zName);
+ }
+ }
+ }
+}
+
+
+/*
+** Parse the SQL statement zSql using Parse object (*p). The Parse object
+** is initialized by this function before it is used.
+*/
+static int renameParseSql(
+ Parse *p, /* Memory to use for Parse object */
+ const char *zDb, /* Name of schema SQL belongs to */
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL to parse */
+ int bTemp /* True if SQL is from temp schema */
+){
+ int rc;
+ char *zErr = 0;
+
+ db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
+
+ /* Parse the SQL statement passed as the first argument. If no error
+ ** occurs and the parse does not result in a new table, index or
+ ** trigger object, the database must be corrupt. */
+ memset(p, 0, sizeof(Parse));
+ p->eParseMode = PARSE_MODE_RENAME;
+ p->db = db;
+ p->nQueryLoop = 1;
+ rc = sqlite3RunParser(p, zSql, &zErr);
+ assert( p->zErrMsg==0 );
+ assert( rc!=SQLITE_OK || zErr==0 );
+ p->zErrMsg = zErr;
+ if( db->mallocFailed ) rc = SQLITE_NOMEM;
+ if( rc==SQLITE_OK
+ && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0
+ ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }
+
+#ifdef SQLITE_DEBUG
+ /* Ensure that all mappings in the Parse.pRename list really do map to
+ ** a part of the input string. */
+ if( rc==SQLITE_OK ){
+ int nSql = sqlite3Strlen30(zSql);
+ RenameToken *pToken;
+ for(pToken=p->pRename; pToken; pToken=pToken->pNext){
+ assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
+ }
+ }
+#endif
+
+ db->init.iDb = 0;
+ return rc;
+}
+
+/*
+** This function edits SQL statement zSql, replacing each token identified
+** by the linked list pRename with the text of zNew. If argument bQuote is
+** true, then zNew is always quoted first. If no error occurs, the result
+** is loaded into context object pCtx as the result.
+**
+** Or, if an error occurs (i.e. an OOM condition), an error is left in
+** pCtx and an SQLite error code returned.
+*/
+static int renameEditSql(
+ sqlite3_context *pCtx, /* Return result here */
+ RenameCtx *pRename, /* Rename context */
+ const char *zSql, /* SQL statement to edit */
+ const char *zNew, /* New token text */
+ int bQuote /* True to always quote token */
+){
+ int nNew = sqlite3Strlen30(zNew);
+ int nSql = sqlite3Strlen30(zSql);
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+ int rc = SQLITE_OK;
+ char *zQuot;
+ char *zOut;
+ int nQuot;
+
+ /* Set zQuot to point to a buffer containing a quoted copy of the
+ ** identifier zNew. If the corresponding identifier in the original
+ ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to
+ ** point to zQuot so that all substitutions are made using the
+ ** quoted version of the new column name. */
+ zQuot = sqlite3MPrintf(db, "\"%w\"", zNew);
+ if( zQuot==0 ){
+ return SQLITE_NOMEM;
+ }else{
+ nQuot = sqlite3Strlen30(zQuot);
+ }
+ if( bQuote ){
+ zNew = zQuot;
+ nNew = nQuot;
+ }
+
+ /* At this point pRename->pList contains a list of RenameToken objects
+ ** corresponding to all tokens in the input SQL that must be replaced
+ ** with the new column name. All that remains is to construct and
+ ** return the edited SQL string. */
+ assert( nQuot>=nNew );
+ zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
+ if( zOut ){
+ int nOut = nSql;
+ memcpy(zOut, zSql, nSql);
+ while( pRename->pList ){
+ int iOff; /* Offset of token to replace in zOut */
+ RenameToken *pBest = renameColumnTokenNext(pRename);
+
+ u32 nReplace;
+ const char *zReplace;
+ if( sqlite3IsIdChar(*pBest->t.z) ){
+ nReplace = nNew;
+ zReplace = zNew;
+ }else{
+ nReplace = nQuot;
+ zReplace = zQuot;
+ }
+
+ iOff = pBest->t.z - zSql;
+ if( pBest->t.n!=nReplace ){
+ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
+ nOut - (iOff + pBest->t.n)
+ );
+ nOut += nReplace - pBest->t.n;
+ zOut[nOut] = '\0';
+ }
+ memcpy(&zOut[iOff], zReplace, nReplace);
+ sqlite3DbFree(db, pBest);
+ }
+
+ sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT);
+ sqlite3DbFree(db, zOut);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+
+ sqlite3_free(zQuot);
+ return rc;
+}
+
+/*
+** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
+** it was read from the schema of database zDb. Return SQLITE_OK if
+** successful. Otherwise, return an SQLite error code and leave an error
+** message in the Parse object.
+*/
+static int renameResolveTrigger(Parse *pParse){
+ sqlite3 *db = pParse->db;
+ Trigger *pNew = pParse->pNewTrigger;
+ TriggerStep *pStep;
+ NameContext sNC;
+ int rc = SQLITE_OK;
+
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
+ assert( pNew->pTabSchema );
+ pParse->pTriggerTab = sqlite3FindTable(db, pNew->table,
+ db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
+ );
+ pParse->eTriggerOp = pNew->op;
+ /* ALWAYS() because if the table of the trigger does not exist, the
+ ** error would have been hit before this point */
+ if( ALWAYS(pParse->pTriggerTab) ){
+ rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
+ }
+
+ /* Resolve symbols in WHEN clause */
+ if( rc==SQLITE_OK && pNew->pWhen ){
+ rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen);
+ }
+
+ for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){
+ if( pStep->pSelect ){
+ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
+ if( pParse->nErr ) rc = pParse->rc;
+ }
+ if( rc==SQLITE_OK && pStep->zTarget ){
+ SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
+ if( pSrc ){
+ int i;
+ for(i=0; i<pSrc->nSrc && rc==SQLITE_OK; i++){
+ struct SrcList_item *p = &pSrc->a[i];
+ p->pTab = sqlite3LocateTableItem(pParse, 0, p);
+ p->iCursor = pParse->nTab++;
+ if( p->pTab==0 ){
+ rc = SQLITE_ERROR;
+ }else{
+ p->pTab->nTabRef++;
+ rc = sqlite3ViewGetColumnNames(pParse, p->pTab);
+ }
+ }
+ sNC.pSrcList = pSrc;
+ if( rc==SQLITE_OK && pStep->pWhere ){
+ rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
+ }
+ assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
+ if( pStep->pUpsert ){
+ Upsert *pUpsert = pStep->pUpsert;
+ assert( rc==SQLITE_OK );
+ pUpsert->pUpsertSrc = pSrc;
+ sNC.uNC.pUpsert = pUpsert;
+ sNC.ncFlags = NC_UUpsert;
+ rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
+ if( rc==SQLITE_OK ){
+ ExprList *pUpsertSet = pUpsert->pUpsertSet;
+ rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
+ }
+ sNC.ncFlags = 0;
+ }
+ sNC.pSrcList = 0;
+ sqlite3SrcListDelete(db, pSrc);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+** Invoke sqlite3WalkExpr() or sqlite3WalkSelect() on all Select or Expr
+** objects that are part of the trigger passed as the second argument.
+*/
+static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
+ TriggerStep *pStep;
+
+ /* Find tokens to edit in WHEN clause */
+ sqlite3WalkExpr(pWalker, pTrigger->pWhen);
+
+ /* Find tokens to edit in trigger steps */
+ for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
+ sqlite3WalkSelect(pWalker, pStep->pSelect);
+ sqlite3WalkExpr(pWalker, pStep->pWhere);
+ sqlite3WalkExprList(pWalker, pStep->pExprList);
+ if( pStep->pUpsert ){
+ Upsert *pUpsert = pStep->pUpsert;
+ sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget);
+ sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet);
+ sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
+ sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
+ }
+ }
+}
+
+/*
+** Free the contents of Parse object (*pParse). Do not free the memory
+** occupied by the Parse object itself.
+*/
+static void renameParseCleanup(Parse *pParse){
+ sqlite3 *db = pParse->db;
+ Index *pIdx;
+ if( pParse->pVdbe ){
+ sqlite3VdbeFinalize(pParse->pVdbe);
+ }
+ sqlite3DeleteTable(db, pParse->pNewTable);
+ while( (pIdx = pParse->pNewIndex)!=0 ){
+ pParse->pNewIndex = pIdx->pNext;
+ sqlite3FreeIndex(db, pIdx);
+ }
+ sqlite3DeleteTrigger(db, pParse->pNewTrigger);
+ sqlite3DbFree(db, pParse->zErrMsg);
+ renameTokenFree(db, pParse->pRename);
+ sqlite3ParserReset(pParse);
+}
+
+/*
+** SQL function:
+**
+** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
+**
+** 0. zSql: SQL statement to rewrite
+** 1. type: Type of object ("table", "view" etc.)
+** 2. object: Name of object
+** 3. Database: Database name (e.g. "main")
+** 4. Table: Table name
+** 5. iCol: Index of column to rename
+** 6. zNew: New column name
+** 7. bQuote: Non-zero if the new column name should be quoted.
+** 8. bTemp: True if zSql comes from temp schema
+**
+** Do a column rename operation on the CREATE statement given in zSql.
+** The iCol-th column (left-most is 0) of table zTable is renamed from zCol
+** into zNew. The name should be quoted if bQuote is true.
+**
+** This function is used internally by the ALTER TABLE RENAME COLUMN command.
+** It is only accessible to SQL created using sqlite3NestedParse(). It is
+** not reachable from ordinary SQL passed into sqlite3_prepare().
+*/
+static void renameColumnFunc(
+ sqlite3_context *context,
+ int NotUsed,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ RenameCtx sCtx;
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+ const char *zDb = (const char*)sqlite3_value_text(argv[3]);
+ const char *zTable = (const char*)sqlite3_value_text(argv[4]);
+ int iCol = sqlite3_value_int(argv[5]);
+ const char *zNew = (const char*)sqlite3_value_text(argv[6]);
+ int bQuote = sqlite3_value_int(argv[7]);
+ int bTemp = sqlite3_value_int(argv[8]);
+ const char *zOld;
+ int rc;
+ Parse sParse;
+ Walker sWalker;
+ Index *pIdx;
+ int i;
+ Table *pTab;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlite3_xauth xAuth = db->xAuth;
+#endif
+
+ UNUSED_PARAMETER(NotUsed);
+ if( zSql==0 ) return;
+ if( zTable==0 ) return;
+ if( zNew==0 ) return;
+ if( iCol<0 ) return;
+ sqlite3BtreeEnterAll(db);
+ pTab = sqlite3FindTable(db, zTable, zDb);
+ if( pTab==0 || iCol>=pTab->nCol ){
+ sqlite3BtreeLeaveAll(db);
+ return;
+ }
+ zOld = pTab->aCol[iCol].zName;
+ memset(&sCtx, 0, sizeof(sCtx));
+ sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = 0;
+#endif
+ rc = renameParseSql(&sParse, zDb, db, zSql, bTemp);
+
+ /* Find tokens that need to be replaced. */
+ memset(&sWalker, 0, sizeof(Walker));
+ sWalker.pParse = &sParse;
+ sWalker.xExprCallback = renameColumnExprCb;
+ sWalker.xSelectCallback = renameColumnSelectCb;
+ sWalker.u.pRename = &sCtx;
+
+ sCtx.pTab = pTab;
+ if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+ if( sParse.pNewTable ){
+ Select *pSelect = sParse.pNewTable->pSelect;
+ if( pSelect ){
+ pSelect->selFlags &= ~SF_View;
+ sParse.rc = SQLITE_OK;
+ sqlite3SelectPrep(&sParse, pSelect, 0);
+ rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
+ if( rc==SQLITE_OK ){
+ sqlite3WalkSelect(&sWalker, pSelect);
+ }
+ if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+ }else{
+ /* A regular table */
+ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
+ FKey *pFKey;
+ assert( sParse.pNewTable->pSelect==0 );
+ sCtx.pTab = sParse.pNewTable;
+ if( bFKOnly==0 ){
+ renameTokenFind(
+ &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName
+ );
+ if( sCtx.iCol<0 ){
+ renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
+ }
+ sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
+ for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
+ sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
+ }
+ for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){
+ sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
+ }
+ }
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ for(i=0; i<sParse.pNewTable->nCol; i++){
+ sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
+ }
+#endif
+
+ for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+ for(i=0; i<pFKey->nCol; i++){
+ if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){
+ renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
+ }
+ if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
+ && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
+ ){
+ renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
+ }
+ }
+ }
+ }
+ }else if( sParse.pNewIndex ){
+ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
+ sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
+ }else{
+ /* A trigger */
+ TriggerStep *pStep;
+ rc = renameResolveTrigger(&sParse);
+ if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+
+ for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
+ if( pStep->zTarget ){
+ Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb);
+ if( pTarget==pTab ){
+ if( pStep->pUpsert ){
+ ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet;
+ renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld);
+ }
+ renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld);
+ renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld);
+ }
+ }
+ }
+
+
+ /* Find tokens to edit in UPDATE OF clause */
+ if( sParse.pTriggerTab==pTab ){
+ renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld);
+ }
+
+ /* Find tokens to edit in various expressions and selects */
+ renameWalkTrigger(&sWalker, sParse.pNewTrigger);
+ }
+
+ assert( rc==SQLITE_OK );
+ rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote);
+
+renameColumnFunc_done:
+ if( rc!=SQLITE_OK ){
+ if( sParse.zErrMsg ){
+ renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
+ }else{
+ sqlite3_result_error_code(context, rc);
+ }
+ }
+
+ renameParseCleanup(&sParse);
+ renameTokenFree(db, sCtx.pList);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ sqlite3BtreeLeaveAll(db);
+}
+
+/*
+** Walker expression callback used by "RENAME TABLE".
+*/
+static int renameTableExprCb(Walker *pWalker, Expr *pExpr){
+ RenameCtx *p = pWalker->u.pRename;
+ if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){
+ renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab);
+ }
+ return WRC_Continue;
+}
+
+/*
+** Walker select callback used by "RENAME TABLE".
+*/
+static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
+ int i;
+ RenameCtx *p = pWalker->u.pRename;
+ SrcList *pSrc = pSelect->pSrc;
+ if( pSelect->selFlags & SF_View ) return WRC_Prune;
+ if( pSrc==0 ){
+ assert( pWalker->pParse->db->mallocFailed );
+ return WRC_Abort;
+ }
+ for(i=0; i<pSrc->nSrc; i++){
+ struct SrcList_item *pItem = &pSrc->a[i];
+ if( pItem->pTab==p->pTab ){
+ renameTokenFind(pWalker->pParse, p, pItem->zName);
+ }
+ }
+ renameWalkWith(pWalker, pSelect);
+
+ return WRC_Continue;
+}
+
+
+/*
+** This C function implements an SQL user function that is used by SQL code
+** generated by the ALTER TABLE ... RENAME command to modify the definition
+** of any foreign key constraints that use the table being renamed as the
+** parent table. It is passed three arguments:
+**
+** 0: The database containing the table being renamed.
+** 1. type: Type of object ("table", "view" etc.)
+** 2. object: Name of object
+** 3: The complete text of the schema statement being modified,
+** 4: The old name of the table being renamed, and
+** 5: The new name of the table being renamed.
+** 6: True if the schema statement comes from the temp db.
+**
+** It returns the new schema statement. For example:
+**
+** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0)
+** -> 'CREATE TABLE t1(a REFERENCES t3)'
+*/
+static void renameTableFunc(
+ sqlite3_context *context,
+ int NotUsed,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ const char *zDb = (const char*)sqlite3_value_text(argv[0]);
+ const char *zInput = (const char*)sqlite3_value_text(argv[3]);
+ const char *zOld = (const char*)sqlite3_value_text(argv[4]);
+ const char *zNew = (const char*)sqlite3_value_text(argv[5]);
+ int bTemp = sqlite3_value_int(argv[6]);
+ UNUSED_PARAMETER(NotUsed);
+
+ if( zInput && zOld && zNew ){
+ Parse sParse;
+ int rc;
+ int bQuote = 1;
+ RenameCtx sCtx;
+ Walker sWalker;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlite3_xauth xAuth = db->xAuth;
+ db->xAuth = 0;
+#endif
+
+ sqlite3BtreeEnterAll(db);
+
+ memset(&sCtx, 0, sizeof(RenameCtx));
+ sCtx.pTab = sqlite3FindTable(db, zOld, zDb);
+ memset(&sWalker, 0, sizeof(Walker));
+ sWalker.pParse = &sParse;
+ sWalker.xExprCallback = renameTableExprCb;
+ sWalker.xSelectCallback = renameTableSelectCb;
+ sWalker.u.pRename = &sCtx;
+
+ rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
+
+ if( rc==SQLITE_OK ){
+ int isLegacy = (db->flags & SQLITE_LegacyAlter);
+ if( sParse.pNewTable ){
+ Table *pTab = sParse.pNewTable;
+
+ if( pTab->pSelect ){
+ if( isLegacy==0 ){
+ Select *pSelect = pTab->pSelect;
+ NameContext sNC;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = &sParse;
+
+ assert( pSelect->selFlags & SF_View );
+ pSelect->selFlags &= ~SF_View;
+ sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
+ if( sParse.nErr ){
+ rc = sParse.rc;
+ }else{
+ sqlite3WalkSelect(&sWalker, pTab->pSelect);
+ }
+ }
+ }else{
+ /* Modify any FK definitions to point to the new table. */
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+ if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){
+ FKey *pFKey;
+ for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){
+ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo);
+ }
+ }
+ }
+#endif
+
+ /* If this is the table being altered, fix any table refs in CHECK
+ ** expressions. Also update the name that appears right after the
+ ** "CREATE [VIRTUAL] TABLE" bit. */
+ if( sqlite3_stricmp(zOld, pTab->zName)==0 ){
+ sCtx.pTab = pTab;
+ if( isLegacy==0 ){
+ sqlite3WalkExprList(&sWalker, pTab->pCheck);
+ }
+ renameTokenFind(&sParse, &sCtx, pTab->zName);
+ }
+ }
+ }
+
+ else if( sParse.pNewIndex ){
+ renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName);
+ if( isLegacy==0 ){
+ sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
+ }
+ }
+
+#ifndef SQLITE_OMIT_TRIGGER
+ else{
+ Trigger *pTrigger = sParse.pNewTrigger;
+ TriggerStep *pStep;
+ if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld)
+ && sCtx.pTab->pSchema==pTrigger->pTabSchema
+ ){
+ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table);
+ }
+
+ if( isLegacy==0 ){
+ rc = renameResolveTrigger(&sParse);
+ if( rc==SQLITE_OK ){
+ renameWalkTrigger(&sWalker, pTrigger);
+ for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
+ if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
+ renameTokenFind(&sParse, &sCtx, pStep->zTarget);
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote);
+ }
+ if( rc!=SQLITE_OK ){
+ if( sParse.zErrMsg ){
+ renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
+ }else{
+ sqlite3_result_error_code(context, rc);
+ }
+ }
+
+ renameParseCleanup(&sParse);
+ renameTokenFree(db, sCtx.pList);
+ sqlite3BtreeLeaveAll(db);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ }
+
+ return;
+}
+
+/*
+** An SQL user function that checks that there are no parse or symbol
+** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement.
+** After an ALTER TABLE .. RENAME operation is performed and the schema
+** reloaded, this function is called on each SQL statement in the schema
+** to ensure that it is still usable.
+**
+** 0: Database name ("main", "temp" etc.).
+** 1: SQL statement.
+** 2: Object type ("view", "table", "trigger" or "index").
+** 3: Object name.
+** 4: True if object is from temp schema.
+**
+** Unless it finds an error, this function normally returns NULL. However, it
+** returns integer value 1 if:
+**
+** * the SQL argument creates a trigger, and
+** * the table that the trigger is attached to is in database zDb.
+*/
+static void renameTableTest(
+ sqlite3_context *context,
+ int NotUsed,
+ sqlite3_value **argv
+){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ char const *zDb = (const char*)sqlite3_value_text(argv[0]);
+ char const *zInput = (const char*)sqlite3_value_text(argv[1]);
+ int bTemp = sqlite3_value_int(argv[4]);
+ int isLegacy = (db->flags & SQLITE_LegacyAlter);
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlite3_xauth xAuth = db->xAuth;
+ db->xAuth = 0;
+#endif
+
+ UNUSED_PARAMETER(NotUsed);
+ if( zDb && zInput ){
+ int rc;
+ Parse sParse;
+ rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
+ if( rc==SQLITE_OK ){
+ if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
+ NameContext sNC;
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = &sParse;
+ sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC);
+ if( sParse.nErr ) rc = sParse.rc;
+ }
+
+ else if( sParse.pNewTrigger ){
+ if( isLegacy==0 ){
+ rc = renameResolveTrigger(&sParse);
+ }
+ if( rc==SQLITE_OK ){
+ int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
+ int i2 = sqlite3FindDbName(db, zDb);
+ if( i1==i2 ) sqlite3_result_int(context, 1);
+ }
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ renameColumnParseError(context, 1, argv[2], argv[3], &sParse);
+ }
+ renameParseCleanup(&sParse);
+ }
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+}
+
+/*
+** Register built-in functions used to help implement ALTER TABLE
+*/
+SQLITE_PRIVATE void sqlite3AlterFunctions(void){
+ static FuncDef aAlterTableFuncs[] = {
+ INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc),
+ INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc),
+ INTERNAL_FUNCTION(sqlite_rename_test, 5, renameTableTest),
+ };
+ sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
+}
#endif /* SQLITE_ALTER_TABLE */
/************** End of alter.c ***********************************************/
@@ -95576,13 +107576,13 @@ exit_begin_add_column:
** is between 3.6.18 and 3.7.8, inclusive, and unless SQLite is compiled
** with SQLITE_ENABLE_STAT2. The sqlite_stat2 table is deprecated.
** The sqlite_stat2 table is superseded by sqlite_stat3, which is only
-** created and used by SQLite versions 3.7.9 and later and with
+** created and used by SQLite versions 3.7.9 through 3.29.0 when
** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3
-** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced
-** version of sqlite_stat3 and is only available when compiled with
-** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.1 and later. It is
-** not possible to enable both STAT3 and STAT4 at the same time. If they
-** are both enabled, then STAT4 takes precedence.
+** is a superset of sqlite_stat2 and is also now deprecated. The
+** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only
+** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite
+** versions 3.8.1 and later. STAT4 is the only variant that is still
+** supported.
**
** For most applications, sqlite_stat1 provides all the statistics required
** for the query planner to make good choices.
@@ -95598,7 +107598,7 @@ exit_begin_add_column:
** integer is the average number of rows in the index that have the same
** value in the first column of the index. The third integer is the average
** number of rows in the index that have the same value for the first two
-** columns. The N-th integer (for N>1) is the average number of rows in
+** columns. The N-th integer (for N>1) is the average number of rows in
** the index which have the same value for the first N-1 columns. For
** a K-column index, there will be K+1 integers in the stat column. If
** the index is unique, then the last integer will be 1.
@@ -95608,7 +107608,7 @@ exit_begin_add_column:
** must be separated from the last integer by a single space. If the
** "unordered" keyword is present, then the query planner assumes that
** the index is unordered and will not use the index for a range query.
-**
+**
** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat
** column contains a single integer which is the (estimated) number of
** rows in the table identified by sqlite_stat1.tbl.
@@ -95666,9 +107666,9 @@ exit_begin_add_column:
** number of entries that are strictly less than the sample. The first
** integer in nLt contains the number of entries in the index where the
** left-most column is less than the left-most column of the sample.
-** The K-th integer in the nLt entry is the number of index entries
+** The K-th integer in the nLt entry is the number of index entries
** where the first K columns are less than the first K columns of the
-** sample. The nDLt column is like nLt except that it contains the
+** sample. The nDLt column is like nLt except that it contains the
** number of distinct entries in the index that are less than the
** sample.
**
@@ -95693,17 +107693,11 @@ exit_begin_add_column:
#if defined(SQLITE_ENABLE_STAT4)
# define IsStat4 1
-# define IsStat3 0
-#elif defined(SQLITE_ENABLE_STAT3)
-# define IsStat4 0
-# define IsStat3 1
#else
# define IsStat4 0
-# define IsStat3 0
# undef SQLITE_STAT4_SAMPLES
# define SQLITE_STAT4_SAMPLES 1
#endif
-#define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */
/*
** This routine generates code that opens the sqlite_statN tables.
@@ -95732,21 +107726,22 @@ static void openStatTable(
{ "sqlite_stat1", "tbl,idx,stat" },
#if defined(SQLITE_ENABLE_STAT4)
{ "sqlite_stat4", "tbl,idx,neq,nlt,ndlt,sample" },
- { "sqlite_stat3", 0 },
-#elif defined(SQLITE_ENABLE_STAT3)
- { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" },
- { "sqlite_stat4", 0 },
#else
- { "sqlite_stat3", 0 },
{ "sqlite_stat4", 0 },
#endif
+ { "sqlite_stat3", 0 },
};
int i;
sqlite3 *db = pParse->db;
Db *pDb;
Vdbe *v = sqlite3GetVdbe(pParse);
- int aRoot[ArraySize(aTable)];
+ u32 aRoot[ArraySize(aTable)];
u8 aCreateTbl[ArraySize(aTable)];
+#ifdef SQLITE_ENABLE_STAT4
+ const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
+#else
+ const int nToOpen = 1;
+#endif
if( v==0 ) return;
assert( sqlite3BtreeHoldsAllMutexes(db) );
@@ -95759,41 +107754,45 @@ static void openStatTable(
for(i=0; i<ArraySize(aTable); i++){
const char *zTab = aTable[i].zName;
Table *pStat;
+ aCreateTbl[i] = 0;
if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
- if( aTable[i].zCols ){
- /* The sqlite_statN table does not exist. Create it. Note that a
- ** side-effect of the CREATE TABLE statement is to leave the rootpage
- ** of the new table in register pParse->regRoot. This is important
+ if( i<nToOpen ){
+ /* The sqlite_statN table does not exist. Create it. Note that a
+ ** side-effect of the CREATE TABLE statement is to leave the rootpage
+ ** of the new table in register pParse->regRoot. This is important
** because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
- aRoot[i] = pParse->regRoot;
+ aRoot[i] = (u32)pParse->regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
}
}else{
- /* The table already exists. If zWhere is not NULL, delete all entries
+ /* The table already exists. If zWhere is not NULL, delete all entries
** associated with the table zWhere. If zWhere is NULL, delete the
** entire contents of the table. */
aRoot[i] = pStat->tnum;
- aCreateTbl[i] = 0;
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
if( zWhere ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE %s=%Q",
pDb->zDbSName, zTab, zWhereType, zWhere
);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ }else if( db->xPreUpdateCallback ){
+ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab);
+#endif
}else{
/* The sqlite_stat[134] table already exists. Delete all rows. */
- sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
+ sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
}
}
}
/* Open the sqlite_stat[134] tables for writing. */
- for(i=0; aTable[i].zCols; i++){
+ for(i=0; i<nToOpen; i++){
assert( i<ArraySize(aTable) );
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
VdbeComment((v, aTable[i].zName));
}
@@ -95811,12 +107810,12 @@ static void openStatTable(
** share an instance of the following structure to hold their state
** information.
*/
-typedef struct Stat4Accum Stat4Accum;
-typedef struct Stat4Sample Stat4Sample;
-struct Stat4Sample {
+typedef struct StatAccum StatAccum;
+typedef struct StatSample StatSample;
+struct StatSample {
tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
tRowcnt *anLt; /* sqlite_stat4.nLt */
union {
i64 iRowid; /* Rowid in main table of the key */
@@ -95827,27 +107826,33 @@ struct Stat4Sample {
int iCol; /* If !isPSample, the reason for inclusion */
u32 iHash; /* Tiebreaker hash */
#endif
-};
-struct Stat4Accum {
- tRowcnt nRow; /* Number of rows in the entire table */
- tRowcnt nPSample; /* How often to do a periodic sample */
+};
+struct StatAccum {
+ sqlite3 *db; /* Database connection, for malloc() */
+ tRowcnt nEst; /* Estimated number of rows */
+ tRowcnt nRow; /* Number of rows visited so far */
+ int nLimit; /* Analysis row-scan limit */
int nCol; /* Number of columns in index + pk/rowid */
int nKeyCol; /* Number of index columns w/o the pk/rowid */
+ u8 nSkipAhead; /* Number of times of skip-ahead */
+ StatSample current; /* Current row as a StatSample */
+#ifdef SQLITE_ENABLE_STAT4
+ tRowcnt nPSample; /* How often to do a periodic sample */
int mxSample; /* Maximum number of samples to accumulate */
- Stat4Sample current; /* Current row as a Stat4Sample */
u32 iPrn; /* Pseudo-random number used for sampling */
- Stat4Sample *aBest; /* Array of nCol best samples */
+ StatSample *aBest; /* Array of nCol best samples */
int iMin; /* Index in a[] of entry with minimum score */
int nSample; /* Current number of samples */
+ int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */
int iGet; /* Index of current sample accessed by stat_get() */
- Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
- sqlite3 *db; /* Database connection, for malloc() */
+ StatSample *a; /* Array of mxSample StatSample objects */
+#endif
};
-/* Reclaim memory used by a Stat4Sample
+/* Reclaim memory used by a StatSample
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-static void sampleClear(sqlite3 *db, Stat4Sample *p){
+#ifdef SQLITE_ENABLE_STAT4
+static void sampleClear(sqlite3 *db, StatSample *p){
assert( db!=0 );
if( p->nRowid ){
sqlite3DbFree(db, p->u.aRowid);
@@ -95858,8 +107863,8 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
/* Initialize the BLOB value of a ROWID
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
+#ifdef SQLITE_ENABLE_STAT4
+static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){
assert( db!=0 );
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
@@ -95874,8 +107879,8 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
/* Initialize the INTEGER value of a ROWID.
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
+#ifdef SQLITE_ENABLE_STAT4
+static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){
assert( db!=0 );
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
p->nRowid = 0;
@@ -95887,8 +107892,8 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
/*
** Copy the contents of object (*pFrom) into (*pTo).
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
+#ifdef SQLITE_ENABLE_STAT4
+static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
pTo->isPSample = pFrom->isPSample;
pTo->iCol = pFrom->iCol;
pTo->iHash = pFrom->iHash;
@@ -95904,40 +107909,41 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
#endif
/*
-** Reclaim all memory of a Stat4Accum structure.
+** Reclaim all memory of a StatAccum structure.
*/
-static void stat4Destructor(void *pOld){
- Stat4Accum *p = (Stat4Accum*)pOld;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- int i;
- for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
- for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
- sampleClear(p->db, &p->current);
+static void statAccumDestructor(void *pOld){
+ StatAccum *p = (StatAccum*)pOld;
+#ifdef SQLITE_ENABLE_STAT4
+ if( p->mxSample ){
+ int i;
+ for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
+ for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
+ sampleClear(p->db, &p->current);
+ }
#endif
sqlite3DbFree(p->db, p);
}
/*
-** Implementation of the stat_init(N,K,C) SQL function. The three parameters
+** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters
** are:
** N: The number of columns in the index including the rowid/pk (note 1)
** K: The number of columns in the index excluding the rowid/pk.
-** C: The number of rows in the index (note 2)
+** C: Estimated number of rows in the index
+** L: A limit on the number of rows to scan, or 0 for no-limit
**
** Note 1: In the special case of the covering index that implements a
** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
** total number of columns in the table.
**
-** Note 2: C is only used for STAT3 and STAT4.
-**
** For indexes on ordinary rowid tables, N==K+1. But for indexes on
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
** PRIMARY KEY of the table. The covering index that implements the
** original WITHOUT ROWID table as N==K as a special case.
**
-** This routine allocates the Stat4Accum object in heap memory. The return
-** value is a pointer to the Stat4Accum object. The datatype of the
-** return value is BLOB, but it is really just a pointer to the Stat4Accum
+** This routine allocates the StatAccum object in heap memory. The return
+** value is a pointer to the StatAccum object. The datatype of the
+** return value is BLOB, but it is really just a pointer to the StatAccum
** object.
*/
static void statInit(
@@ -95945,14 +107951,15 @@ static void statInit(
int argc,
sqlite3_value **argv
){
- Stat4Accum *p;
+ StatAccum *p;
int nCol; /* Number of columns in index being sampled */
int nKeyCol; /* Number of key columns */
int nColUp; /* nCol rounded up for alignment */
int n; /* Bytes of space to allocate */
- sqlite3 *db; /* Database connection */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- int mxSample = SQLITE_STAT4_SAMPLES;
+ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */
+#ifdef SQLITE_ENABLE_STAT4
+ /* Maximum number of samples. 0 if STAT4 data is not collected */
+ int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0;
#endif
/* Decode the three function arguments */
@@ -95964,16 +107971,17 @@ static void statInit(
assert( nKeyCol<=nCol );
assert( nKeyCol>0 );
- /* Allocate the space required for the Stat4Accum object */
- n = sizeof(*p)
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
- + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
- + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
+ /* Allocate the space required for the StatAccum object */
+ n = sizeof(*p)
+ + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
+#ifdef SQLITE_ENABLE_STAT4
+ if( mxSample ){
+ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
+ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
+ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
+ }
#endif
- ;
db = sqlite3_context_db_handle(context);
p = sqlite3DbMallocZero(db, n);
if( p==0 ){
@@ -95982,25 +107990,28 @@ static void statInit(
}
p->db = db;
+ p->nEst = sqlite3_value_int64(argv[2]);
p->nRow = 0;
+ p->nLimit = sqlite3_value_int64(argv[3]);
p->nCol = nCol;
p->nKeyCol = nKeyCol;
+ p->nSkipAhead = 0;
p->current.anDLt = (tRowcnt*)&p[1];
p->current.anEq = &p->current.anDLt[nColUp];
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- {
+#ifdef SQLITE_ENABLE_STAT4
+ p->mxSample = p->nLimit==0 ? mxSample : 0;
+ if( mxSample ){
u8 *pSpace; /* Allocated space not yet assigned */
int i; /* Used to iterate through p->aSample[] */
p->iGet = -1;
- p->mxSample = mxSample;
- p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
+ p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
p->current.anLt = &p->current.anEq[nColUp];
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
-
- /* Set up the Stat4Accum.a[] and aBest[] arrays */
- p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
+
+ /* Set up the StatAccum.a[] and aBest[] arrays */
+ p->a = (struct StatSample*)&p->current.anLt[nColUp];
p->aBest = &p->a[mxSample];
pSpace = (u8*)(&p->a[mxSample+nCol]);
for(i=0; i<(mxSample+nCol); i++){
@@ -96009,7 +108020,7 @@ static void statInit(
p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
}
assert( (pSpace - (u8*)p)==n );
-
+
for(i=0; i<nCol; i++){
p->aBest[i].iCol = i;
}
@@ -96020,35 +108031,36 @@ static void statInit(
** only the pointer (the 2nd parameter) matters. The size of the object
** (given by the 3rd parameter) is never used and can be any positive
** value. */
- sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
+ sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
}
static const FuncDef statInitFuncdef = {
- 2+IsStat34, /* nArg */
+ 4, /* nArg */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statInit, /* xSFunc */
0, /* xFinalize */
+ 0, 0, /* xValue, xInverse */
"stat_init", /* zName */
{0}
};
#ifdef SQLITE_ENABLE_STAT4
/*
-** pNew and pOld are both candidate non-periodic samples selected for
-** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
+** pNew and pOld are both candidate non-periodic samples selected for
+** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
** considering only any trailing columns and the sample hash value, this
** function returns true if sample pNew is to be preferred over pOld.
** In other words, if we assume that the cardinalities of the selected
** column for pNew and pOld are equal, is pNew to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
-** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
+** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
*/
static int sampleIsBetterPost(
- Stat4Accum *pAccum,
- Stat4Sample *pNew,
- Stat4Sample *pOld
+ StatAccum *pAccum,
+ StatSample *pNew,
+ StatSample *pOld
){
int nCol = pAccum->nCol;
int i;
@@ -96062,17 +108074,17 @@ static int sampleIsBetterPost(
}
#endif
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
/*
** Return true if pNew is to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
-** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
+** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
*/
static int sampleIsBetter(
- Stat4Accum *pAccum,
- Stat4Sample *pNew,
- Stat4Sample *pOld
+ StatAccum *pAccum,
+ StatSample *pNew,
+ StatSample *pOld
){
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
@@ -96081,39 +108093,41 @@ static int sampleIsBetter(
assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );
if( (nEqNew>nEqOld) ) return 1;
-#ifdef SQLITE_ENABLE_STAT4
if( nEqNew==nEqOld ){
if( pNew->iCol<pOld->iCol ) return 1;
return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
}
return 0;
-#else
- return (nEqNew==nEqOld && pNew->iHash>pOld->iHash);
-#endif
}
/*
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
** remove the least desirable sample from p->a[] to make room.
*/
-static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
- Stat4Sample *pSample = 0;
+static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){
+ StatSample *pSample = 0;
int i;
assert( IsStat4 || nEqZero==0 );
-#ifdef SQLITE_ENABLE_STAT4
+ /* StatAccum.nMaxEqZero is set to the maximum number of leading 0
+ ** values in the anEq[] array of any sample in StatAccum.a[]. In
+ ** other words, if nMaxEqZero is n, then it is guaranteed that there
+ ** are no samples with StatSample.anEq[m]==0 for (m>=n). */
+ if( nEqZero>p->nMaxEqZero ){
+ p->nMaxEqZero = nEqZero;
+ }
if( pNew->isPSample==0 ){
- Stat4Sample *pUpgrade = 0;
+ StatSample *pUpgrade = 0;
assert( pNew->anEq[pNew->iCol]>0 );
- /* This sample is being added because the prefix that ends in column
+ /* This sample is being added because the prefix that ends in column
** iCol occurs many times in the table. However, if we have already
** added a sample that shares this prefix, there is no need to add
** this one. Instead, upgrade the priority of the highest priority
** existing sample that shares this prefix. */
for(i=p->nSample-1; i>=0; i--){
- Stat4Sample *pOld = &p->a[i];
+ StatSample *pOld = &p->a[i];
if( pOld->anEq[pNew->iCol]==0 ){
if( pOld->isPSample ) return;
assert( pOld->iCol>pNew->iCol );
@@ -96129,11 +108143,10 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
goto find_new_min;
}
}
-#endif
/* If necessary, remove sample iMin to make room for the new sample. */
if( p->nSample>=p->mxSample ){
- Stat4Sample *pMin = &p->a[p->iMin];
+ StatSample *pMin = &p->a[p->iMin];
tRowcnt *anEq = pMin->anEq;
tRowcnt *anLt = pMin->anLt;
tRowcnt *anDLt = pMin->anDLt;
@@ -96150,10 +108163,8 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
/* The "rows less-than" for the rowid column must be greater than that
** for the last sample in the p->a[] array. Otherwise, the samples would
** be out of order. */
-#ifdef SQLITE_ENABLE_STAT4
- assert( p->nSample==0
+ assert( p->nSample==0
|| pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] );
-#endif
/* Insert the new sample */
pSample = &p->a[p->nSample];
@@ -96163,9 +108174,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
/* Zero the first nEqZero entries in the anEq[] array. */
memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero);
-#ifdef SQLITE_ENABLE_STAT4
- find_new_min:
-#endif
+find_new_min:
if( p->nSample>=p->mxSample ){
int iMin = -1;
for(i=0; i<p->mxSample; i++){
@@ -96178,79 +108187,66 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
p->iMin = iMin;
}
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
+#ifdef SQLITE_ENABLE_STAT4
/*
** Field iChng of the index being scanned has changed. So at this point
** p->current contains a sample that reflects the previous row of the
** index. The value of anEq[iChng] and subsequent anEq[] elements are
** correct at this point.
*/
-static void samplePushPrevious(Stat4Accum *p, int iChng){
-#ifdef SQLITE_ENABLE_STAT4
+static void samplePushPrevious(StatAccum *p, int iChng){
int i;
/* Check if any samples from the aBest[] array should be pushed
** into IndexSample.a[] at this point. */
for(i=(p->nCol-2); i>=iChng; i--){
- Stat4Sample *pBest = &p->aBest[i];
+ StatSample *pBest = &p->aBest[i];
pBest->anEq[i] = p->current.anEq[i];
if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
sampleInsert(p, pBest, i);
}
}
- /* Update the anEq[] fields of any samples already collected. */
+ /* Check that no sample contains an anEq[] entry with an index of
+ ** p->nMaxEqZero or greater set to zero. */
for(i=p->nSample-1; i>=0; i--){
int j;
- for(j=iChng; j<p->nCol; j++){
- if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
- }
+ for(j=p->nMaxEqZero; j<p->nCol; j++) assert( p->a[i].anEq[j]>0 );
}
-#endif
-
-#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
- if( iChng==0 ){
- tRowcnt nLt = p->current.anLt[0];
- tRowcnt nEq = p->current.anEq[0];
-
- /* Check if this is to be a periodic sample. If so, add it. */
- if( (nLt/p->nPSample)!=(nLt+nEq)/p->nPSample ){
- p->current.isPSample = 1;
- sampleInsert(p, &p->current, 0);
- p->current.isPSample = 0;
- }else
- /* Or if it is a non-periodic sample. Add it in this case too. */
- if( p->nSample<p->mxSample
- || sampleIsBetter(p, &p->current, &p->a[p->iMin])
- ){
- sampleInsert(p, &p->current, 0);
+ /* Update the anEq[] fields of any samples already collected. */
+ if( iChng<p->nMaxEqZero ){
+ for(i=p->nSample-1; i>=0; i--){
+ int j;
+ for(j=iChng; j<p->nCol; j++){
+ if( p->a[i].anEq[j]==0 ) p->a[i].anEq[j] = p->current.anEq[j];
+ }
}
+ p->nMaxEqZero = iChng;
}
-#endif
-
-#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
- UNUSED_PARAMETER( p );
- UNUSED_PARAMETER( iChng );
-#endif
}
+#endif /* SQLITE_ENABLE_STAT4 */
/*
** Implementation of the stat_push SQL function: stat_push(P,C,R)
** Arguments:
**
-** P Pointer to the Stat4Accum object created by stat_init()
+** P Pointer to the StatAccum object created by stat_init()
** C Index of left-most column to differ from previous row
** R Rowid for the current row. Might be a key record for
** WITHOUT ROWID tables.
**
-** This SQL function always returns NULL. It's purpose it to accumulate
-** statistical data and/or samples in the Stat4Accum object about the
-** index being analyzed. The stat_get() SQL function will later be used to
-** extract relevant information for constructing the sqlite_statN tables.
+** The purpose of this routine is to collect statistical data and/or
+** samples from the index being analyzed into the StatAccum object.
+** The stat_get() SQL function will be used afterwards to
+** retrieve the information gathered.
**
-** The R parameter is only used for STAT3 and STAT4
+** This SQL function usually returns NULL, but might return an integer
+** if it wants the byte-code to do special processing.
+**
+** The R parameter is only used for STAT4
*/
static void statPush(
sqlite3_context *context,
@@ -96260,7 +108256,7 @@ static void statPush(
int i;
/* The three function arguments */
- Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
+ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
int iChng = sqlite3_value_int(argv[1]);
UNUSED_PARAMETER( argc );
@@ -96273,7 +108269,9 @@ static void statPush(
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
}else{
/* Second and subsequent calls get processed here */
- samplePushPrevious(p, iChng);
+#ifdef SQLITE_ENABLE_STAT4
+ if( p->mxSample ) samplePushPrevious(p, iChng);
+#endif
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
** to the current row of the index. */
@@ -96282,27 +108280,26 @@ static void statPush(
}
for(i=iChng; i<p->nCol; i++){
p->current.anDLt[i]++;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- p->current.anLt[i] += p->current.anEq[i];
+#ifdef SQLITE_ENABLE_STAT4
+ if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
#endif
p->current.anEq[i] = 1;
}
}
- p->nRow++;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
- sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
- }else{
- sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
- sqlite3_value_blob(argv[2]));
- }
- p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
-#endif
+ p->nRow++;
#ifdef SQLITE_ENABLE_STAT4
- {
- tRowcnt nLt = p->current.anLt[p->nCol-1];
+ if( p->mxSample ){
+ tRowcnt nLt;
+ if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
+ sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
+ }else{
+ sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
+ sqlite3_value_blob(argv[2]));
+ }
+ p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
+ nLt = p->current.anLt[p->nCol-1];
/* Check if this is to be a periodic sample. If so, add it. */
if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){
p->current.isPSample = 1;
@@ -96318,16 +108315,22 @@ static void statPush(
sampleCopy(p, &p->aBest[i], &p->current);
}
}
- }
+ }else
#endif
+ if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){
+ p->nSkipAhead++;
+ sqlite3_result_int(context, p->current.anDLt[0]>0);
+ }
}
+
static const FuncDef statPushFuncdef = {
- 2+IsStat34, /* nArg */
+ 2+IsStat4, /* nArg */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statPush, /* xSFunc */
0, /* xFinalize */
+ 0, 0, /* xValue, xInverse */
"stat_push", /* zName */
{0}
};
@@ -96341,12 +108344,18 @@ static const FuncDef statPushFuncdef = {
/*
** Implementation of the stat_get(P,J) SQL function. This routine is
** used to query statistical information that has been gathered into
-** the Stat4Accum object by prior calls to stat_push(). The P parameter
-** has type BLOB but it is really just a pointer to the Stat4Accum object.
+** the StatAccum object by prior calls to stat_push(). The P parameter
+** has type BLOB but it is really just a pointer to the StatAccum object.
** The content to returned is determined by the parameter J
** which is one of the STAT_GET_xxxx values defined above.
**
-** If neither STAT3 nor STAT4 are enabled, then J is always
+** The stat_get(P,J) function is not available to generic SQL. It is
+** inserted as part of a manually constructed bytecode program. (See
+** the callStatGet() routine below.) It is guaranteed that the P
+** parameter will always be a pointer to a StatAccum object, never a
+** NULL.
+**
+** If STAT4 is not enabled, then J is always
** STAT_GET_STAT1 and is hence omitted and this routine becomes
** a one-parameter function, stat_get(P), that always returns the
** stat1 table entry information.
@@ -96356,15 +108365,16 @@ static void statGet(
int argc,
sqlite3_value **argv
){
- Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- /* STAT3 and STAT4 have a parameter on this routine. */
+ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
+#ifdef SQLITE_ENABLE_STAT4
+ /* STAT4 has a parameter on this routine. */
int eCall = sqlite3_value_int(argv[1]);
assert( argc==2 );
- assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ
+ assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ
|| eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
- || eCall==STAT_GET_NDLT
+ || eCall==STAT_GET_NDLT
);
+ assert( eCall==STAT_GET_STAT1 || p->mxSample );
if( eCall==STAT_GET_STAT1 )
#else
assert( argc==1 );
@@ -96373,20 +108383,20 @@ static void statGet(
/* Return the value to store in the "stat" column of the sqlite_stat1
** table for this index.
**
- ** The value is a string composed of a list of integers describing
- ** the index. The first integer in the list is the total number of
- ** entries in the index. There is one additional integer in the list
+ ** The value is a string composed of a list of integers describing
+ ** the index. The first integer in the list is the total number of
+ ** entries in the index. There is one additional integer in the list
** for each indexed column. This additional integer is an estimate of
- ** the number of rows matched by a stabbing query on the index using
+ ** the number of rows matched by a equality query on the index using
** a key with the corresponding number of fields. In other words,
- ** if the index is on columns (a,b) and the sqlite_stat1 value is
+ ** if the index is on columns (a,b) and the sqlite_stat1 value is
** "100 10 2", then SQLite estimates that:
**
** * the index contains 100 rows,
** * "WHERE a=?" matches 10 rows, and
** * "WHERE a=? AND b=?" matches 2 rows.
**
- ** If D is the count of distinct values and K is the total number of
+ ** If D is the count of distinct values and K is the total number of
** rows, then each estimate is computed as:
**
** I = (K+D-1)/D
@@ -96400,7 +108410,8 @@ static void statGet(
return;
}
- sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
+ sqlite3_snprintf(24, zRet, "%llu",
+ p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
z = zRet + sqlite3Strlen30(zRet);
for(i=0; i<p->nKeyCol; i++){
u64 nDistinct = p->current.anDLt[i] + 1;
@@ -96413,14 +108424,14 @@ static void statGet(
sqlite3_result_text(context, zRet, -1, sqlite3_free);
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
else if( eCall==STAT_GET_ROWID ){
if( p->iGet<0 ){
samplePushPrevious(p, 0);
p->iGet = 0;
}
if( p->iGet<p->nSample ){
- Stat4Sample *pS = p->a + p->iGet;
+ StatSample *pS = p->a + p->iGet;
if( pS->nRowid==0 ){
sqlite3_result_int64(context, pS->u.iRowid);
}else{
@@ -96436,15 +108447,13 @@ static void statGet(
case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break;
case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break;
default: {
- aCnt = p->a[p->iGet].anDLt;
+ aCnt = p->a[p->iGet].anDLt;
p->iGet++;
break;
}
}
- if( IsStat3 ){
- sqlite3_result_int64(context, (i64)aCnt[0]);
- }else{
+ {
char *zRet = sqlite3MallocZero(p->nCol * 25);
if( zRet==0 ){
sqlite3_result_error_nomem(context);
@@ -96461,35 +108470,59 @@ static void statGet(
}
}
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
#ifndef SQLITE_DEBUG
UNUSED_PARAMETER( argc );
#endif
}
static const FuncDef statGetFuncdef = {
- 1+IsStat34, /* nArg */
+ 1+IsStat4, /* nArg */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
statGet, /* xSFunc */
0, /* xFinalize */
+ 0, 0, /* xValue, xInverse */
"stat_get", /* zName */
{0}
};
-static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
- assert( regOut!=regStat4 && regOut!=regStat4+1 );
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1);
+static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
+#ifdef SQLITE_ENABLE_STAT4
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1);
#elif SQLITE_DEBUG
assert( iParam==STAT_GET_STAT1 );
#else
UNUSED_PARAMETER( iParam );
#endif
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut,
- (char*)&statGetFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 1 + IsStat34);
+ assert( regOut!=regStat && regOut!=regStat+1 );
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4,
+ &statGetFuncdef, 0);
+}
+
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+/* Add a comment to the most recent VDBE opcode that is the name
+** of the k-th column of the pIdx index.
+*/
+static void analyzeVdbeCommentIndexWithColumnName(
+ Vdbe *v, /* Prepared statement under construction */
+ Index *pIdx, /* Index whose column is being loaded */
+ int k /* Which column index */
+){
+ int i; /* Index of column in the table */
+ assert( k>=0 && k<pIdx->nColumn );
+ i = pIdx->aiColumn[k];
+ if( NEVER(i==XN_ROWID) ){
+ VdbeComment((v,"%s.rowid",pIdx->zName));
+ }else if( i==XN_EXPR ){
+ VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
+ }else{
+ VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zName));
+ }
}
+#else
+# define analyzeVdbeCommentIndexWithColumnName(a,b,c)
+#endif /* SQLITE_DEBUG */
/*
** Generate code to do an analysis of all indices associated with
@@ -96513,16 +108546,18 @@ static void analyzeOneTable(
int iDb; /* Index of database containing pTab */
u8 needTableCnt = 1; /* True to count the table */
int regNewRowid = iMem++; /* Rowid for the inserted record */
- int regStat4 = iMem++; /* Register to hold Stat4Accum object */
+ int regStat = iMem++; /* Register to hold StatAccum object */
int regChng = iMem++; /* Index of changed index field */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
-#endif
int regTemp = iMem++; /* Temporary use register */
+ int regTemp2 = iMem++; /* Second temporary use register */
int regTabname = iMem++; /* Register containing table name */
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ Table *pStat1 = 0;
+#endif
pParse->nMem = MAX(pParse->nMem, iMem);
v = sqlite3GetVdbe(pParse);
@@ -96533,7 +108568,7 @@ static void analyzeOneTable(
/* Do not gather statistics on views or virtual tables */
return;
}
- if( sqlite3_strlike("sqlite_%", pTab->zName, 0)==0 ){
+ if( sqlite3_strlike("sqlite\\_%", pTab->zName, '\\')==0 ){
/* Do not gather statistics on system tables */
return;
}
@@ -96548,7 +108583,19 @@ static void analyzeOneTable(
}
#endif
- /* Establish a read-lock on the table at the shared-cache level.
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ if( db->xPreUpdateCallback ){
+ pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13);
+ if( pStat1==0 ) return;
+ pStat1->zName = (char*)&pStat1[1];
+ memcpy(pStat1->zName, "sqlite_stat1", 13);
+ pStat1->nCol = 3;
+ pStat1->iPKey = -1;
+ sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
+ }
+#endif
+
+ /* Establish a read-lock on the table at the shared-cache level.
** Open a read-only cursor on the table. Also allocate a cursor number
** to use for scanning indexes (iIdxCur). No index cursor is opened at
** this time though. */
@@ -96614,9 +108661,9 @@ static void analyzeOneTable(
** end_of_scan:
*/
- /* Make sure there are enough memory cells allocated to accommodate
+ /* Make sure there are enough memory cells allocated to accommodate
** the regPrev array and a trailing rowid (the rowid slot is required
- ** when building a record to insert into the sample column of
+ ** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
@@ -96627,23 +108674,31 @@ static void analyzeOneTable(
VdbeComment((v, "%s", pIdx->zName));
/* Invoke the stat_init() function. The arguments are:
- **
+ **
** (1) the number of columns in the index including the rowid
** (or for a WITHOUT ROWID table, the number of PK columns),
** (2) the number of columns in the key without the rowid/pk
- ** (3) the number of rows in the index,
- **
- **
- ** The third argument is only used for STAT3 and STAT4
+ ** (3) estimated number of rows in the index,
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
+ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
+ assert( regRowid==regStat+2 );
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
+#ifdef SQLITE_ENABLE_STAT4
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
+ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+ VdbeCoverage(v);
+ }else
#endif
- sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4,
- (char*)&statInitFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 2+IsStat34);
+ {
+ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
+ }
+ assert( regTemp2==regStat+4 );
+ sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
+ &statInitFuncdef, 0);
/* Implementation of the following:
**
@@ -96653,13 +108708,11 @@ static void analyzeOneTable(
** goto next_push_0;
**
*/
- addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
- VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
addrNextRow = sqlite3VdbeCurrentAddr(v);
if( nColTest>0 ){
- int endDistinctTest = sqlite3VdbeMakeLabel(v);
+ int endDistinctTest = sqlite3VdbeMakeLabel(pParse);
int *aGotoChng; /* Array of jump instruction addresses */
aGotoChng = sqlite3DbMallocRawNN(db, sizeof(int)*nColTest);
if( aGotoChng==0 ) continue;
@@ -96678,7 +108731,7 @@ static void analyzeOneTable(
addrNextRow = sqlite3VdbeCurrentAddr(v);
if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){
/* For a single-column UNIQUE index, once we have found a non-NULL
- ** row, we know that all the rest will be distinct, so skip
+ ** row, we know that all the rest will be distinct, so skip
** subsequent distinctness tests. */
sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest);
VdbeCoverage(v);
@@ -96687,15 +108740,16 @@ static void analyzeOneTable(
char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
- aGotoChng[i] =
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
+ aGotoChng[i] =
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
sqlite3VdbeGoto(v, endDistinctTest);
-
-
+
+
/*
** chng_addr_0:
** regPrev(0) = idx(0)
@@ -96707,53 +108761,72 @@ static void analyzeOneTable(
for(i=0; i<nColTest; i++){
sqlite3VdbeJumpHere(v, aGotoChng[i]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
}
sqlite3VdbeResolveLabel(v, endDistinctTest);
sqlite3DbFree(db, aGotoChng);
}
-
+
/*
** chng_addr_N:
- ** regRowid = idx(rowid) // STAT34 only
- ** stat_push(P, regChng, regRowid) // 3rd parameter STAT34 only
+ ** regRowid = idx(rowid) // STAT4 only
+ ** stat_push(P, regChng, regRowid) // 3rd parameter STAT4 only
** Next csr
** if !eof(csr) goto next_row;
*/
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- assert( regRowid==(regStat4+2) );
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
- }else{
- Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
- int j, k, regKey;
- regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
- for(j=0; j<pPk->nKeyCol; j++){
- k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
- assert( k>=0 && k<pTab->nCol );
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
- VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
+#ifdef SQLITE_ENABLE_STAT4
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
+ assert( regRowid==(regStat+2) );
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
+ }else{
+ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
+ int j, k, regKey;
+ regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
+ for(j=0; j<pPk->nKeyCol; j++){
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
+ assert( k>=0 && k<pIdx->nColumn );
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,k);
+ }
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
+ sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
}
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
- sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
}
#endif
- assert( regChng==(regStat4+1) );
- sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp,
- (char*)&statPushFuncdef, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, 2+IsStat34);
- sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
+ assert( regChng==(regStat+1) );
+ {
+ sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4,
+ &statPushFuncdef, 0);
+ if( db->nAnalysisLimit ){
+ int j1, j2, j3;
+ j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v);
+ j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v);
+ j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1);
+ VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, j1);
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, j2);
+ sqlite3VdbeJumpHere(v, j3);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
+ }
+ }
/* Add the entry to the stat1 table. */
- callStatGet(v, regStat4, STAT_GET_STAT1, regStat1);
+ callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
assert( "BBB"[0]==SQLITE_AFF_TEXT );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
+#endif
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
- /* Add the entries to the stat3 or stat4 table. */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- {
+ /* Add the entries to the stat4 table. */
+#ifdef SQLITE_ENABLE_STAT4
+ if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){
int regEq = regStat1;
int regLt = regStat1+1;
int regDLt = regStat1+2;
@@ -96767,32 +108840,25 @@ static void analyzeOneTable(
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
addrNext = sqlite3VdbeCurrentAddr(v);
- callStatGet(v, regStat4, STAT_GET_ROWID, regSampleRowid);
+ callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
VdbeCoverage(v);
- callStatGet(v, regStat4, STAT_GET_NEQ, regEq);
- callStatGet(v, regStat4, STAT_GET_NLT, regLt);
- callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
+ callStatGet(pParse, regStat, STAT_GET_NEQ, regEq);
+ callStatGet(pParse, regStat, STAT_GET_NLT, regLt);
+ callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
- /* We know that the regSampleRowid row exists because it was read by
- ** the previous loop. Thus the not-found jump of seekOp will never
- ** be taken */
- VdbeCoverageNeverTaken(v);
-#ifdef SQLITE_ENABLE_STAT3
- sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
-#else
+ VdbeCoverage(v);
for(i=0; i<nCol; i++){
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
-#endif
sqlite3VdbeAddOp3(v, OP_MakeRecord, regTabname, 6, regTemp);
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid);
sqlite3VdbeAddOp2(v, OP_Goto, 1, addrNext); /* P1==1 for end-of-loop */
sqlite3VdbeJumpHere(v, addrIsNull);
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
/* End of analysis */
sqlite3VdbeJumpHere(v, addrRewind);
@@ -96812,6 +108878,9 @@ static void analyzeOneTable(
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE);
+#endif
sqlite3VdbeJumpHere(v, jZeroRows);
}
}
@@ -96913,27 +108982,14 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
if( i==1 ) continue; /* Do not analyze the TEMP database */
analyzeDatabase(pParse, i);
}
- }else if( pName2->n==0 ){
- /* Form 2: Analyze the database or table named */
- iDb = sqlite3FindDb(db, pName1);
- if( iDb>=0 ){
- analyzeDatabase(pParse, iDb);
- }else{
- z = sqlite3NameFromToken(db, pName1);
- if( z ){
- if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){
- analyzeTable(pParse, pIdx->pTable, pIdx);
- }else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){
- analyzeTable(pParse, pTab, 0);
- }
- sqlite3DbFree(db, z);
- }
- }
+ }else if( pName2->n==0 && (iDb = sqlite3FindDb(db, pName1))>=0 ){
+ /* Analyze the schema named as the argument */
+ analyzeDatabase(pParse, iDb);
}else{
- /* Form 3: Analyze the fully qualified table name */
+ /* Form 3: Analyze the table or index named as an argument */
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
if( iDb>=0 ){
- zDb = db->aDb[iDb].zDbSName;
+ zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
z = sqlite3NameFromToken(db, pTableName);
if( z ){
if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
@@ -96943,10 +108999,11 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
}
sqlite3DbFree(db, z);
}
- }
+ }
+ }
+ if( db->nSqlExec==0 && (v = sqlite3GetVdbe(pParse))!=0 ){
+ sqlite3VdbeAddOp0(v, OP_Expire);
}
- v = sqlite3GetVdbe(pParse);
- if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
}
/*
@@ -96976,7 +109033,7 @@ static void decodeIntArray(
int i;
tRowcnt v;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
if( z==0 ) z = "";
#else
assert( z!=0 );
@@ -96987,7 +109044,7 @@ static void decodeIntArray(
v = v*10 + c - '0';
z++;
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
if( aOut ) aOut[i] = v;
if( aLog ) aLog[i] = sqlite3LogEst(v);
#else
@@ -96998,7 +109055,7 @@ static void decodeIntArray(
#endif
if( *z==' ' ) z++;
}
-#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifndef SQLITE_ENABLE_STAT4
assert( pIndex!=0 ); {
#else
if( pIndex ){
@@ -97009,7 +109066,9 @@ static void decodeIntArray(
if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ int sz = sqlite3Atoi(z+3);
+ if( sz<2 ) sz = 2;
+ pIndex->szIdxRow = sqlite3LogEst(sz);
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
pIndex->noSkipScan = 1;
}
@@ -97026,7 +109085,7 @@ static void decodeIntArray(
/*
** This callback is invoked once for each index when reading the
-** sqlite_stat1 table.
+** sqlite_stat1 table.
**
** argv[0] = name of the table
** argv[1] = name of the index (might be NULL)
@@ -97063,8 +109122,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
if( pIndex ){
tRowcnt *aiRowEst = 0;
int nCol = pIndex->nKeyCol+1;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- /* Index.aiRowEst may already be set here if there are duplicate
+#ifdef SQLITE_ENABLE_STAT4
+ /* Index.aiRowEst may already be set here if there are duplicate
** sqlite_stat1 entries for this index. In that case just clobber
** the old data with the new instead of allocating a new array. */
if( pIndex->aiRowEst==0 ){
@@ -97075,7 +109134,11 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
#endif
pIndex->bUnordered = 0;
decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex);
- if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
+ pIndex->hasStat1 = 1;
+ if( pIndex->pPartIdxWhere==0 ){
+ pTable->nRowLogEst = pIndex->aiRowLogEst[0];
+ pTable->tabFlags |= TF_HasStat1;
+ }
}else{
Index fakeIdx;
fakeIdx.szIdxRow = pTable->szTabRow;
@@ -97084,6 +109147,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
#endif
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
pTable->szTabRow = fakeIdx.szIdxRow;
+ pTable->tabFlags |= TF_HasStat1;
}
return 0;
@@ -97094,7 +109158,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** and its contents.
*/
SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
if( pIdx->aSample ){
int j;
for(j=0; j<pIdx->nSample; j++){
@@ -97110,13 +109174,13 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
#else
UNUSED_PARAMETER(db);
UNUSED_PARAMETER(pIdx);
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
/*
** Populate the pIdx->aAvgEq[] array based on the samples currently
-** stored in pIdx->aSample[].
+** stored in pIdx->aSample[].
*/
static void initAvgEq(Index *pIdx){
if( pIdx ){
@@ -97152,19 +109216,19 @@ static void initAvgEq(Index *pIdx){
pIdx->nRowEst0 = nRow;
/* Set nSum to the number of distinct (iCol+1) field prefixes that
- ** occur in the stat4 table for this index. Set sumEq to the sum of
- ** the nEq values for column iCol for the same set (adding the value
+ ** occur in the stat4 table for this index. Set sumEq to the sum of
+ ** the nEq values for column iCol for the same set (adding the value
** only once where there exist duplicate prefixes). */
for(i=0; i<nSample; i++){
if( i==(pIdx->nSample-1)
- || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
+ || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
){
sumEq += aSample[i].anEq[iCol];
nSum100 += 100;
}
}
- if( nDist100>nSum100 ){
+ if( nDist100>nSum100 && sumEq<nRow ){
avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
}
if( avgEq==0 ) avgEq = 1;
@@ -97191,12 +109255,11 @@ static Index *findIndexOrPrimaryKey(
}
/*
-** Load the content from either the sqlite_stat4 or sqlite_stat3 table
+** Load the content from either the sqlite_stat4
** into the relevant Index.aSample[] arrays.
**
** Arguments zSql1 and zSql2 must point to SQL statements that return
-** data equivalent to the following (statements are different for stat3,
-** see the caller of this function for details):
+** data equivalent to the following:
**
** zSql1: SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx
** zSql2: SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4
@@ -97205,7 +109268,6 @@ static Index *findIndexOrPrimaryKey(
*/
static int loadStatTbl(
sqlite3 *db, /* Database handle */
- int bStat3, /* Assume single column records only */
const char *zSql1, /* SQL statement 1 (see above) */
const char *zSql2, /* SQL statement 2 (see above) */
const char *zDb /* Database name (e.g. "main") */
@@ -97239,17 +109301,13 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
nSample = sqlite3_column_int(pStmt, 1);
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
- assert( pIdx==0 || bStat3 || pIdx->nSample==0 );
- /* Index.nSample is non-zero at this point if data has already been
- ** loaded from the stat4 table. In this case ignore stat3 data. */
- if( pIdx==0 || pIdx->nSample ) continue;
- if( bStat3==0 ){
- assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
- if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
- nIdxCol = pIdx->nKeyCol;
- }else{
- nIdxCol = pIdx->nColumn;
- }
+ assert( pIdx==0 || pIdx->nSample==0 );
+ if( pIdx==0 ) continue;
+ assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
+ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
+ nIdxCol = pIdx->nKeyCol;
+ }else{
+ nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
nByte = sizeof(IndexSample) * nSample;
@@ -97290,10 +109348,9 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
- /* This next condition is true if data has already been loaded from
- ** the sqlite_stat4 table. In this case ignore stat3 data. */
+ /* This next condition is true if data has already been loaded from
+ ** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
- if( bStat3 && nCol>1 ) continue;
if( pIdx!=pPrevIdx ){
initAvgEq(pPrevIdx);
pPrevIdx = pIdx;
@@ -97315,7 +109372,9 @@ static int loadStatTbl(
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
}
- memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
+ if( pSample->n ){
+ memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
+ }
pIdx->nSample++;
}
rc = sqlite3_finalize(pStmt);
@@ -97324,7 +109383,7 @@ static int loadStatTbl(
}
/*
-** Load content from the sqlite_stat4 and sqlite_stat3 tables into
+** Load content from the sqlite_stat4 table into
** the Index.aSample[] arrays of all indices.
*/
static int loadStat4(sqlite3 *db, const char *zDb){
@@ -97332,37 +109391,28 @@ static int loadStat4(sqlite3 *db, const char *zDb){
assert( db->lookaside.bDisable );
if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
- rc = loadStatTbl(db, 0,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
+ rc = loadStatTbl(db,
+ "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);
}
-
- if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){
- rc = loadStatTbl(db, 1,
- "SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx",
- "SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3",
- zDb
- );
- }
-
return rc;
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
/*
-** Load the content of the sqlite_stat1 and sqlite_stat3/4 tables. The
+** Load the content of the sqlite_stat1 and sqlite_stat4 tables. The
** contents of sqlite_stat1 are used to populate the Index.aiRowEst[]
-** arrays. The contents of sqlite_stat3/4 are used to populate the
+** arrays. The contents of sqlite_stat4 are used to populate the
** Index.aSample[] arrays.
**
** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
-** is returned. In this case, even if SQLITE_ENABLE_STAT3/4 was defined
-** during compilation and the sqlite_stat3/4 table is present, no data is
+** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined
+** during compilation and the sqlite_stat4 table is present, no data is
** read from it.
**
-** If SQLITE_ENABLE_STAT3/4 was defined during compilation and the
+** If SQLITE_ENABLE_STAT4 was defined during compilation and the
** sqlite_stat4 table is not present in the database, SQLITE_ERROR is
** returned. However, in this case, data is read from the sqlite_stat1
** table (if it is present) before returning.
@@ -97376,16 +109426,21 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
HashElem *i;
char *zSql;
int rc = SQLITE_OK;
+ Schema *pSchema = db->aDb[iDb].pSchema;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
/* Clear any prior statistics */
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
+ for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){
+ Table *pTab = sqliteHashData(i);
+ pTab->tabFlags &= ~TF_HasStat1;
+ }
+ for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
- pIdx->aiRowLogEst[0] = 0;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ pIdx->hasStat1 = 0;
+#ifdef SQLITE_ENABLE_STAT4
sqlite3DeleteIndexSamples(db, pIdx);
pIdx->aSample = 0;
#endif
@@ -97395,7 +109450,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
sInfo.db = db;
sInfo.zDatabase = db->aDb[iDb].zDbSName;
if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
- zSql = sqlite3MPrintf(db,
+ zSql = sqlite3MPrintf(db,
"SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
if( zSql==0 ){
rc = SQLITE_NOMEM_BKPT;
@@ -97407,19 +109462,19 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
/* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
+ for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
- if( pIdx->aiRowLogEst[0]==0 ) sqlite3DefaultRowEst(pIdx);
+ if( !pIdx->hasStat1 ) sqlite3DefaultRowEst(pIdx);
}
/* Load the statistics from the sqlite_stat4 table. */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
- db->lookaside.bDisable++;
+#ifdef SQLITE_ENABLE_STAT4
+ if( rc==SQLITE_OK ){
+ DisableLookaside;
rc = loadStat4(db, sInfo.zDatabase);
- db->lookaside.bDisable--;
+ EnableLookaside;
}
- for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
+ for(i=sqliteHashFirst(&pSchema->idxHash); i; i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
sqlite3_free(pIdx->aiRowEst);
pIdx->aiRowEst = 0;
@@ -97485,6 +109540,17 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
}
/*
+** Return true if zName points to a name that may be used to refer to
+** database iDb attached to handle db.
+*/
+SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){
+ return (
+ sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0
+ || (iDb==0 && sqlite3StrICmp("main", zName)==0)
+ );
+}
+
+/*
** An SQL user-function registered to do the work of an ATTACH statement. The
** three arguments to the function come directly from an attach statement:
**
@@ -97494,6 +109560,10 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
**
** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the
** third argument.
+**
+** If the db->init.reopenMemdb flags is set, then instead of attaching a
+** new database, close the database on db->init.iDb and reopen it as an
+** empty MemDB.
*/
static void attachFunc(
sqlite3_context *context,
@@ -97508,149 +109578,138 @@ static void attachFunc(
char *zPath = 0;
char *zErr = 0;
unsigned int flags;
- Db *aNew;
+ Db *aNew; /* New array of Db pointers */
+ Db *pNew; /* Db object for the newly attached database */
char *zErrDyn = 0;
sqlite3_vfs *pVfs;
UNUSED_PARAMETER(NotUsed);
-
zFile = (const char *)sqlite3_value_text(argv[0]);
zName = (const char *)sqlite3_value_text(argv[1]);
if( zFile==0 ) zFile = "";
if( zName==0 ) zName = "";
- /* Check for the following errors:
- **
- ** * Too many attached databases,
- ** * Transaction currently open
- ** * Specified database name already being used.
- */
- if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
- zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
- db->aLimit[SQLITE_LIMIT_ATTACHED]
- );
- goto attach_error;
- }
- if( !db->autoCommit ){
- zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction");
- goto attach_error;
- }
- for(i=0; i<db->nDb; i++){
- char *z = db->aDb[i].zDbSName;
- assert( z && zName );
- if( sqlite3StrICmp(z, zName)==0 ){
- zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
+#ifdef SQLITE_ENABLE_DESERIALIZE
+# define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb)
+#else
+# define REOPEN_AS_MEMDB(db) (0)
+#endif
+
+ if( REOPEN_AS_MEMDB(db) ){
+ /* This is not a real ATTACH. Instead, this routine is being called
+ ** from sqlite3_deserialize() to close database db->init.iDb and
+ ** reopen it as a MemDB */
+ pVfs = sqlite3_vfs_find("memdb");
+ if( pVfs==0 ) return;
+ pNew = &db->aDb[db->init.iDb];
+ if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt);
+ pNew->pBt = 0;
+ pNew->pSchema = 0;
+ rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
+ }else{
+ /* This is a real ATTACH
+ **
+ ** Check for the following errors:
+ **
+ ** * Too many attached databases,
+ ** * Transaction currently open
+ ** * Specified database name already being used.
+ */
+ if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
+ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
+ db->aLimit[SQLITE_LIMIT_ATTACHED]
+ );
goto attach_error;
}
- }
+ for(i=0; i<db->nDb; i++){
+ assert( zName );
+ if( sqlite3DbIsNamed(db, i, zName) ){
+ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
+ goto attach_error;
+ }
+ }
- /* Allocate the new entry in the db->aDb[] array and initialize the schema
- ** hash tables.
- */
- if( db->aDb==db->aDbStatic ){
- aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
- if( aNew==0 ) return;
- memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
- }else{
- aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
- if( aNew==0 ) return;
- }
- db->aDb = aNew;
- aNew = &db->aDb[db->nDb];
- memset(aNew, 0, sizeof(*aNew));
+ /* Allocate the new entry in the db->aDb[] array and initialize the schema
+ ** hash tables.
+ */
+ if( db->aDb==db->aDbStatic ){
+ aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 );
+ if( aNew==0 ) return;
+ memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
+ }else{
+ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
+ if( aNew==0 ) return;
+ }
+ db->aDb = aNew;
+ pNew = &db->aDb[db->nDb];
+ memset(pNew, 0, sizeof(*pNew));
- /* Open the database file. If the btree is successfully opened, use
- ** it to obtain the database schema. At this point the schema may
- ** or may not be initialized.
- */
- flags = db->openFlags;
- rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
- if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
- sqlite3_result_error(context, zErr, -1);
- sqlite3_free(zErr);
- return;
+ /* Open the database file. If the btree is successfully opened, use
+ ** it to obtain the database schema. At this point the schema may
+ ** or may not be initialized.
+ */
+ flags = db->openFlags;
+ rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
+ sqlite3_result_error(context, zErr, -1);
+ sqlite3_free(zErr);
+ return;
+ }
+ assert( pVfs );
+ flags |= SQLITE_OPEN_MAIN_DB;
+ rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags);
+ db->nDb++;
+ pNew->zDbSName = sqlite3DbStrDup(db, zName);
}
- assert( pVfs );
- flags |= SQLITE_OPEN_MAIN_DB;
- rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags);
- sqlite3_free( zPath );
- db->nDb++;
+ db->noSharedCache = 0;
if( rc==SQLITE_CONSTRAINT ){
rc = SQLITE_ERROR;
zErrDyn = sqlite3MPrintf(db, "database is already attached");
}else if( rc==SQLITE_OK ){
Pager *pPager;
- aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
- if( !aNew->pSchema ){
+ pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt);
+ if( !pNew->pSchema ){
rc = SQLITE_NOMEM_BKPT;
- }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
- zErrDyn = sqlite3MPrintf(db,
+ }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){
+ zErrDyn = sqlite3MPrintf(db,
"attached databases must use the same text encoding as main database");
rc = SQLITE_ERROR;
}
- sqlite3BtreeEnter(aNew->pBt);
- pPager = sqlite3BtreePager(aNew->pBt);
+ sqlite3BtreeEnter(pNew->pBt);
+ pPager = sqlite3BtreePager(pNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
- sqlite3BtreeSecureDelete(aNew->pBt,
+ sqlite3BtreeSecureDelete(pNew->pBt,
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
- sqlite3BtreeSetPagerFlags(aNew->pBt,
+ sqlite3BtreeSetPagerFlags(pNew->pBt,
PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK));
#endif
- sqlite3BtreeLeave(aNew->pBt);
+ sqlite3BtreeLeave(pNew->pBt);
}
- aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
- aNew->zDbSName = sqlite3DbStrDup(db, zName);
- if( rc==SQLITE_OK && aNew->zDbSName==0 ){
+ pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
+ if( rc==SQLITE_OK && pNew->zDbSName==0 ){
rc = SQLITE_NOMEM_BKPT;
}
-
-
-#ifdef SQLITE_HAS_CODEC
- if( rc==SQLITE_OK ){
- extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
- extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
- int nKey;
- char *zKey;
- int t = sqlite3_value_type(argv[2]);
- switch( t ){
- case SQLITE_INTEGER:
- case SQLITE_FLOAT:
- zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
- rc = SQLITE_ERROR;
- break;
-
- case SQLITE_TEXT:
- case SQLITE_BLOB:
- nKey = sqlite3_value_bytes(argv[2]);
- zKey = (char *)sqlite3_value_blob(argv[2]);
- rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
- break;
-
- case SQLITE_NULL:
- /* No key specified. Use the key from the main database */
- sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
- rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
- }
- break;
- }
- }
-#endif
+ sqlite3_free_filename( zPath );
/* If the file was opened successfully, read the schema for the new database.
- ** If this fails, or if opening the file failed, then close the file and
- ** remove the entry from the db->aDb[] array. i.e. put everything back the way
- ** we found it.
+ ** If this fails, or if opening the file failed, then close the file and
+ ** remove the entry from the db->aDb[] array. i.e. put everything back the
+ ** way we found it.
*/
if( rc==SQLITE_OK ){
sqlite3BtreeEnterAll(db);
- rc = sqlite3Init(db, &zErrDyn);
+ db->init.iDb = 0;
+ db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
+ if( !REOPEN_AS_MEMDB(db) ){
+ rc = sqlite3Init(db, &zErrDyn);
+ }
sqlite3BtreeLeaveAll(db);
+ assert( zErrDyn==0 || rc!=SQLITE_OK );
}
#ifdef SQLITE_USER_AUTHENTICATION
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){
u8 newAuth = 0;
rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth);
if( newAuth<db->auth.authLevel ){
@@ -97659,25 +109718,27 @@ static void attachFunc(
}
#endif
if( rc ){
- int iDb = db->nDb - 1;
- assert( iDb>=2 );
- if( db->aDb[iDb].pBt ){
- sqlite3BtreeClose(db->aDb[iDb].pBt);
- db->aDb[iDb].pBt = 0;
- db->aDb[iDb].pSchema = 0;
- }
- sqlite3ResetAllSchemasOfConnection(db);
- db->nDb = iDb;
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
- sqlite3DbFree(db, zErrDyn);
- zErrDyn = sqlite3MPrintf(db, "out of memory");
- }else if( zErrDyn==0 ){
- zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
+ if( !REOPEN_AS_MEMDB(db) ){
+ int iDb = db->nDb - 1;
+ assert( iDb>=2 );
+ if( db->aDb[iDb].pBt ){
+ sqlite3BtreeClose(db->aDb[iDb].pBt);
+ db->aDb[iDb].pBt = 0;
+ db->aDb[iDb].pSchema = 0;
+ }
+ sqlite3ResetAllSchemasOfConnection(db);
+ db->nDb = iDb;
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ sqlite3OomFault(db);
+ sqlite3DbFree(db, zErrDyn);
+ zErrDyn = sqlite3MPrintf(db, "out of memory");
+ }else if( zErrDyn==0 ){
+ zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile);
+ }
}
goto attach_error;
}
-
+
return;
attach_error:
@@ -97706,6 +109767,7 @@ static void detachFunc(
sqlite3 *db = sqlite3_context_db_handle(context);
int i;
Db *pDb = 0;
+ HashElem *pEntry;
char zErr[128];
UNUSED_PARAMETER(NotUsed);
@@ -97714,7 +109776,7 @@ static void detachFunc(
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
- if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
+ if( sqlite3DbIsNamed(db, i, zName) ) break;
}
if( i>=db->nDb ){
@@ -97725,16 +109787,23 @@ static void detachFunc(
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
goto detach_error;
}
- if( !db->autoCommit ){
- sqlite3_snprintf(sizeof(zErr), zErr,
- "cannot DETACH database within transaction");
- goto detach_error;
- }
if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
goto detach_error;
}
+ /* If any TEMP triggers reference the schema being detached, move those
+ ** triggers to reference the TEMP schema itself. */
+ assert( db->aDb[1].pSchema );
+ pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash);
+ while( pEntry ){
+ Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
+ if( pTrig->pTabSchema==pDb->pSchema ){
+ pTrig->pTabSchema = pTrig->pSchema;
+ }
+ pEntry = sqliteHashNext(pEntry);
+ }
+
sqlite3BtreeClose(pDb->pBt);
pDb->pBt = 0;
pDb->pSchema = 0;
@@ -97764,10 +109833,11 @@ static void codeAttach(
sqlite3* db = pParse->db;
int regArgs;
+ if( pParse->nErr ) goto attach_end;
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
- if(
+ if(
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
@@ -97799,18 +109869,15 @@ static void codeAttach(
assert( v || db->mallocFailed );
if( v ){
- sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3,
- (char *)pFunc, P4_FUNCDEF);
- assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg );
- sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
-
+ sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3,
+ pFunc->nArg, pFunc, 0);
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
*/
sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
}
-
+
attach_end:
sqlite3ExprDelete(db, pFilename);
sqlite3ExprDelete(db, pDbname);
@@ -97830,6 +109897,7 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
0, /* pNext */
detachFunc, /* xSFunc */
0, /* xFinalize */
+ 0, 0, /* xValue, xInverse */
"sqlite_detach", /* zName */
{0}
};
@@ -97849,6 +109917,7 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
0, /* pNext */
attachFunc, /* xSFunc */
0, /* xFinalize */
+ 0, 0, /* xValue, xInverse */
"sqlite_attach", /* zName */
{0}
};
@@ -97876,7 +109945,7 @@ SQLITE_PRIVATE void sqlite3FixInit(
pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
- pFix->bVarOnly = (iDb==1);
+ pFix->bTemp = (iDb==1);
}
/*
@@ -97898,27 +109967,32 @@ SQLITE_PRIVATE int sqlite3FixSrcList(
SrcList *pList /* The Source list to check and modify */
){
int i;
- const char *zDb;
struct SrcList_item *pItem;
+ sqlite3 *db = pFix->pParse->db;
+ int iDb = sqlite3FindDbName(db, pFix->zDb);
if( NEVER(pList==0) ) return 0;
- zDb = pFix->zDb;
+
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
- if( pFix->bVarOnly==0 ){
- if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
+ if( pFix->bTemp==0 ){
+ if( pItem->zDatabase && iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
sqlite3ErrorMsg(pFix->pParse,
"%s %T cannot reference objects in database %s",
pFix->zType, pFix->pName, pItem->zDatabase);
return 1;
}
- sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
+ sqlite3DbFree(db, pItem->zDatabase);
pItem->zDatabase = 0;
pItem->pSchema = pFix->pSchema;
+ pItem->fg.fromDDL = 1;
}
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
#endif
+ if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
+ return 1;
+ }
}
return 0;
}
@@ -97949,8 +110023,13 @@ SQLITE_PRIVATE int sqlite3FixSelect(
if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
return 1;
}
- if( sqlite3FixExpr(pFix, pSelect->pOffset) ){
- return 1;
+ if( pSelect->pWith ){
+ int i;
+ for(i=0; i<pSelect->pWith->nCte; i++){
+ if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){
+ return 1;
+ }
+ }
}
pSelect = pSelect->pPrior;
}
@@ -97961,6 +110040,7 @@ SQLITE_PRIVATE int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
+ if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
if( pExpr->op==TK_VARIABLE ){
if( pFix->pParse->db->init.busy ){
pExpr->op = TK_NULL;
@@ -98013,6 +110093,21 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
if( sqlite3FixExprList(pFix, pStep->pExprList) ){
return 1;
}
+ if( pStep->pFrom && sqlite3FixSrcList(pFix, pStep->pFrom) ){
+ return 1;
+ }
+#ifndef SQLITE_OMIT_UPSERT
+ if( pStep->pUpsert ){
+ Upsert *pUp = pStep->pUpsert;
+ if( sqlite3FixExprList(pFix, pUp->pUpsertTarget)
+ || sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere)
+ || sqlite3FixExprList(pFix, pUp->pUpsertSet)
+ || sqlite3FixExpr(pFix, pUp->pUpsertWhere)
+ ){
+ return 1;
+ }
+ }
+#endif
pStep = pStep->pNext;
}
return 0;
@@ -98101,7 +110196,7 @@ SQLITE_API int sqlite3_set_authorizer(
sqlite3_mutex_enter(db->mutex);
db->xAuth = (sqlite3_xauth)xAuth;
db->pAuthArg = pArg;
- sqlite3ExpirePreparedStatements(db);
+ if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1);
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
@@ -98141,11 +110236,9 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
#endif
);
if( rc==SQLITE_DENY ){
- if( db->nDb>2 || iDb!=0 ){
- sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol);
- }else{
- sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol);
- }
+ char *z = sqlite3_mprintf("%s.%s", zTab, zCol);
+ if( db->nDb>2 || iDb!=0 ) z = sqlite3_mprintf("%s.%z", zDb, z);
+ sqlite3ErrorMsg(pParse, "access to %z is prohibited", z);
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){
sqliteAuthBadReturnCode(pParse);
@@ -98155,10 +110248,10 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
/*
** The pExpr should be a TK_COLUMN expression. The table referred to
-** is in pTabList or else it is the NEW or OLD table of a trigger.
+** is in pTabList or else it is the NEW or OLD table of a trigger.
** Check to see if it is OK to read this particular column.
**
-** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
+** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
** then generate an error.
*/
@@ -98175,6 +110268,8 @@ SQLITE_PRIVATE void sqlite3AuthRead(
int iDb; /* The index of the database the expression refers to */
int iCol; /* Index of column in table */
+ assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
+ assert( !IN_RENAME_OBJECT || db->xAuth==0 );
if( db->xAuth==0 ) return;
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
if( iDb<0 ){
@@ -98183,7 +110278,6 @@ SQLITE_PRIVATE void sqlite3AuthRead(
return;
}
- assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
if( pExpr->op==TK_TRIGGER ){
pTab = pParse->pTriggerTab;
}else{
@@ -98232,13 +110326,26 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
/* Don't do any authorization checks if the database is initialising
** or if the parser is being invoked from within sqlite3_declare_vtab.
*/
- if( db->init.busy || IN_DECLARE_VTAB ){
+ assert( !IN_RENAME_OBJECT || db->xAuth==0 );
+ if( db->init.busy || IN_SPECIAL_PARSE ){
return SQLITE_OK;
}
if( db->xAuth==0 ){
return SQLITE_OK;
}
+
+ /* EVIDENCE-OF: R-43249-19882 The third through sixth parameters to the
+ ** callback are either NULL pointers or zero-terminated strings that
+ ** contain additional details about the action to be authorized.
+ **
+ ** The following testcase() macros show that any of the 3rd through 6th
+ ** parameters can be either NULL or a string. */
+ testcase( zArg1==0 );
+ testcase( zArg2==0 );
+ testcase( zArg3==0 );
+ testcase( pParse->zAuthContext==0 );
+
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext
#ifdef SQLITE_USER_AUTHENTICATION
,db->auth.zAuthUser
@@ -98261,7 +110368,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
*/
SQLITE_PRIVATE void sqlite3AuthContextPush(
Parse *pParse,
- AuthContext *pContext,
+ AuthContext *pContext,
const char *zContext
){
assert( pParse );
@@ -98317,14 +110424,14 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
** codeTableLocks() functions.
*/
struct TableLock {
- int iDb; /* The database containing the table to be locked */
- int iTab; /* The root page of the table to be locked */
- u8 isWriteLock; /* True for write lock. False for a read lock */
- const char *zName; /* Name of the table */
+ int iDb; /* The database containing the table to be locked */
+ Pgno iTab; /* The root page of the table to be locked */
+ u8 isWriteLock; /* True for write lock. False for a read lock */
+ const char *zLockName; /* Name of the table */
};
/*
-** Record the fact that we want to lock a table at run-time.
+** Record the fact that we want to lock a table at run-time.
**
** The table to be locked has root page iTab and is found in database iDb.
** A read or a write lock can be taken depending on isWritelock.
@@ -98336,7 +110443,7 @@ struct TableLock {
SQLITE_PRIVATE void sqlite3TableLock(
Parse *pParse, /* Parsing context */
int iDb, /* Index of the database containing the table to lock */
- int iTab, /* Root page number of the table to be locked */
+ Pgno iTab, /* Root page number of the table to be locked */
u8 isWriteLock, /* True for a write lock */
const char *zName /* Name of the table to be locked */
){
@@ -98346,6 +110453,8 @@ SQLITE_PRIVATE void sqlite3TableLock(
TableLock *p;
assert( iDb>=0 );
+ if( iDb==1 ) return;
+ if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
for(i=0; i<pToplevel->nTableLock; i++){
p = &pToplevel->aTableLock[i];
if( p->iDb==iDb && p->iTab==iTab ){
@@ -98362,7 +110471,7 @@ SQLITE_PRIVATE void sqlite3TableLock(
p->iDb = iDb;
p->iTab = iTab;
p->isWriteLock = isWriteLock;
- p->zName = zName;
+ p->zLockName = zName;
}else{
pToplevel->nTableLock = 0;
sqlite3OomFault(pToplevel->db);
@@ -98375,7 +110484,7 @@ SQLITE_PRIVATE void sqlite3TableLock(
*/
static void codeTableLocks(Parse *pParse){
int i;
- Vdbe *pVdbe;
+ Vdbe *pVdbe;
pVdbe = sqlite3GetVdbe(pParse);
assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */
@@ -98384,7 +110493,7 @@ static void codeTableLocks(Parse *pParse){
TableLock *p = &pParse->aTableLock[i];
int p1 = p->iDb;
sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock,
- p->zName, P4_STATIC);
+ p->zLockName, P4_STATIC);
}
}
#else
@@ -98430,7 +110539,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
** vdbe program
*/
v = sqlite3GetVdbe(pParse);
- assert( !pParse->isMultiWrite
+ assert( !pParse->isMultiWrite
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
sqlite3VdbeAddOp0(v, OP_Halt);
@@ -98452,7 +110561,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
- if( db->mallocFailed==0
+ if( db->mallocFailed==0
&& (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
){
int iDb, i;
@@ -98482,8 +110591,8 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
pParse->nVtabLock = 0;
#endif
- /* Once all the cookies have been verified and transactions opened,
- ** obtain the required table-locks. This is a no-op unless the
+ /* Once all the cookies have been verified and transactions opened,
+ ** obtain the required table-locks. This is a no-op unless the
** shared-cache feature is enabled.
*/
codeTableLocks(pParse);
@@ -98492,12 +110601,21 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
*/
sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops */
+ /* Code constant expressions that where factored out of inner loops.
+ **
+ ** The pConstExpr list might also contain expressions that we simply
+ ** want to keep around until the Parse object is deleted. Such
+ ** expressions have iConstExprReg==0. Do not generate code for
+ ** those expressions, of course.
+ */
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; i<pEL->nExpr; i++){
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
+ int iReg = pEL->a[i].u.iConstExprReg;
+ if( iReg>0 ){
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
+ }
}
}
@@ -98510,10 +110628,9 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
/* Get the VDBE program ready for execution
*/
if( v && pParse->nErr==0 && !db->mallocFailed ){
- assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */
/* A minimum of one cursor is required if autoincrement is used
* See ticket [a696379c1f08866] */
- if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1;
+ assert( pParse->pAinc==0 || pParse->nTab>0 );
sqlite3VdbeMakeReady(v, pParse);
pParse->rc = SQLITE_DONE;
}else{
@@ -98530,7 +110647,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
** outermost parser.
**
** Not everything is nestable. This facility is designed to permit
-** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
+** INSERT, UPDATE, and DELETE operations against the schema table. Use
** care if you decide to try to use this routine for some other purposes.
*/
SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
@@ -98546,7 +110663,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
zSql = sqlite3VMPrintf(db, zFormat, ap);
va_end(ap);
if( zSql==0 ){
- return; /* A malloc must have failed */
+ /* This can result either from an OOM or because the formatted string
+ ** exceeds SQLITE_LIMIT_LENGTH. In the latter case, we need to set
+ ** an error */
+ if( !db->mallocFailed ) pParse->rc = SQLITE_TOOBIG;
+ pParse->nErr++;
+ return;
}
pParse->nested++;
memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
@@ -98593,13 +110715,57 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
return 0;
}
#endif
- for(i=OMIT_TEMPDB; i<db->nDb; i++){
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
- assert( sqlite3SchemaMutexHeld(db, j, 0) );
- p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
+ if( zDatabase ){
+ for(i=0; i<db->nDb; i++){
+ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
+ }
+ if( i>=db->nDb ){
+ /* No match against the official names. But always match "main"
+ ** to schema 0 as a legacy fallback. */
+ if( sqlite3StrICmp(zDatabase,"main")==0 ){
+ i = 0;
+ }else{
+ return 0;
+ }
+ }
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
+ if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
+ if( i==1 ){
+ if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0
+ || sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0
+ || sqlite3StrICmp(zName+7, &DFLT_SCHEMA_TABLE[7])==0
+ ){
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
+ DFLT_TEMP_SCHEMA_TABLE);
+ }
+ }else{
+ if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
+ DFLT_SCHEMA_TABLE);
+ }
+ }
+ }
+ }else{
+ /* Match against TEMP first */
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
+ if( p ) return p;
+ /* The main database is second */
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
+ if( p ) return p;
+ /* Attached databases are in order of attachment */
+ for(i=2; i<db->nDb; i++){
+ assert( sqlite3SchemaMutexHeld(db, i, 0) );
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
if( p ) break;
}
+ if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
+ if( sqlite3StrICmp(zName+7, &ALT_SCHEMA_TABLE[7])==0 ){
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, DFLT_SCHEMA_TABLE);
+ }else if( sqlite3StrICmp(zName+7, &ALT_TEMP_SCHEMA_TABLE[7])==0 ){
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
+ DFLT_TEMP_SCHEMA_TABLE);
+ }
+ }
}
return p;
}
@@ -98621,34 +110787,44 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
const char *zDbase /* Name of the database. Might be NULL */
){
Table *p;
+ sqlite3 *db = pParse->db;
/* Read the database schema. If an error occurs, leave an error message
** and code in pParse and return NULL. */
- if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
+ if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0
+ && SQLITE_OK!=sqlite3ReadSchema(pParse)
+ ){
return 0;
}
- p = sqlite3FindTable(pParse->db, zName, zDbase);
+ p = sqlite3FindTable(db, zName, zDbase);
if( p==0 ){
- const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
- /* If zName is the not the name of a table in the schema created using
- ** CREATE, then check to see if it is the name of an virtual table that
- ** can be an eponymous virtual table. */
- Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
+ /* If zName is the not the name of a table in the schema created using
+ ** CREATE, then check to see if it is the name of an virtual table that
+ ** can be an eponymous virtual table. */
+ if( pParse->disableVtab==0 ){
+ Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
+ if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
+ pMod = sqlite3PragmaVtabRegister(db, zName);
+ }
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
return pMod->pEpoTab;
}
}
#endif
- if( (flags & LOCATE_NOERR)==0 ){
- if( zDbase ){
- sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
- }else{
- sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
- }
- pParse->checkSchema = 1;
+ if( flags & LOCATE_NOERR ) return 0;
+ pParse->checkSchema = 1;
+ }else if( IsVirtual(p) && pParse->disableVtab ){
+ p = 0;
+ }
+
+ if( p==0 ){
+ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
+ if( zDbase ){
+ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
+ }else{
+ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
}
}
@@ -98665,7 +110841,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
** sqlite3FixSrcList() for details.
*/
SQLITE_PRIVATE Table *sqlite3LocateTableItem(
- Parse *pParse,
+ Parse *pParse,
u32 flags,
struct SrcList_item *p
){
@@ -98681,7 +110857,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(
}
/*
-** Locate the in-memory structure that describes
+** Locate the in-memory structure that describes
** a particular index given the name of that index
** and the name of the database that contains the index.
** Return NULL if not found.
@@ -98701,7 +110877,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
Schema *pSchema = db->aDb[j].pSchema;
assert( pSchema );
- if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
+ if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&pSchema->idxHash, zName);
if( p ) break;
@@ -98712,7 +110888,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
/*
** Reclaim the memory used by an index
*/
-static void freeIndex(sqlite3 *db, Index *p){
+SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3 *db, Index *p){
#ifndef SQLITE_OMIT_ANALYZE
sqlite3DeleteIndexSamples(db, p);
#endif
@@ -98720,7 +110896,7 @@ static void freeIndex(sqlite3 *db, Index *p){
sqlite3ExprListDelete(db, p->aColExpr);
sqlite3DbFree(db, p->zColAff);
if( p->isResized ) sqlite3DbFree(db, (void *)p->azColl);
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
sqlite3_free(p->aiRowEst);
#endif
sqlite3DbFree(db, p);
@@ -98752,9 +110928,9 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char
p->pNext = pIndex->pNext;
}
}
- freeIndex(db, pIndex);
+ sqlite3FreeIndex(db, pIndex);
}
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -98789,28 +110965,27 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
/*
** Reset the schema for the database at index iDb. Also reset the
-** TEMP schema.
+** TEMP schema. The reset is deferred if db->nSchemaLock is not zero.
+** Deferred resets may be run by calling with iDb<0.
*/
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3 *db, int iDb){
- Db *pDb;
+ int i;
assert( iDb<db->nDb );
- /* Case 1: Reset the single schema identified by iDb */
- pDb = &db->aDb[iDb];
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- assert( pDb->pSchema!=0 );
- sqlite3SchemaClear(pDb->pSchema);
+ if( iDb>=0 ){
+ assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ DbSetProperty(db, iDb, DB_ResetWanted);
+ DbSetProperty(db, 1, DB_ResetWanted);
+ db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
+ }
- /* If any database other than TEMP is reset, then also reset TEMP
- ** since TEMP might be holding triggers that reference tables in the
- ** other database.
- */
- if( iDb!=1 ){
- pDb = &db->aDb[1];
- assert( pDb->pSchema!=0 );
- sqlite3SchemaClear(pDb->pSchema);
+ if( db->nSchemaLock==0 ){
+ for(i=0; i<db->nDb; i++){
+ if( DbHasProperty(db, i, DB_ResetWanted) ){
+ sqlite3SchemaClear(db->aDb[i].pSchema);
+ }
+ }
}
- return;
}
/*
@@ -98823,20 +110998,26 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3 *db){
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
if( pDb->pSchema ){
- sqlite3SchemaClear(pDb->pSchema);
+ if( db->nSchemaLock==0 ){
+ sqlite3SchemaClear(pDb->pSchema);
+ }else{
+ DbSetProperty(db, i, DB_ResetWanted);
+ }
}
}
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~(DBFLAG_SchemaChange|DBFLAG_SchemaKnownOk);
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
- sqlite3CollapseDatabaseArray(db);
+ if( db->nSchemaLock==0 ){
+ sqlite3CollapseDatabaseArray(db);
+ }
}
/*
** This routine is called when a commit occurs.
*/
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
- db->flags &= ~SQLITE_InternChanges;
+ db->mDbFlags &= ~DBFLAG_SchemaChange;
}
/*
@@ -98849,6 +111030,7 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
assert( pTable!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
+ assert( pCol->zName==0 || pCol->hName==sqlite3StrIHash(pCol->zName) );
sqlite3DbFree(db, pCol->zName);
sqlite3ExprDelete(db, pCol->pDflt);
sqlite3DbFree(db, pCol->zColl);
@@ -98863,10 +111045,10 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
**
** This routine just deletes the data structure. It does not unlink
** the table data structure from the hash table. But it does destroy
-** memory structures of the indices and foreign keys associated with
+** memory structures of the indices and foreign keys associated with
** the table.
**
-** The db parameter is optional. It is needed if the Table object
+** The db parameter is optional. It is needed if the Table object
** contains lookaside memory. (Table objects in the schema do not use
** lookaside memory, but some ephemeral Table objects do.) Or the
** db parameter can be used with db->pnBytesFreed to measure the memory
@@ -98874,13 +111056,20 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
*/
static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
- TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
+#ifdef SQLITE_DEBUG
/* Record the number of outstanding lookaside allocations in schema Tables
- ** prior to doing any free() operations. Since schema Tables do not use
- ** lookaside, this number should not change. */
- TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
- db->lookaside.nOut : 0 );
+ ** prior to doing any free() operations. Since schema Tables do not use
+ ** lookaside, this number should not change.
+ **
+ ** If malloc has already failed, it may be that it failed while allocating
+ ** a Table object that was going to be marked ephemeral. So do not check
+ ** that no lookaside memory is used in this case either. */
+ int nLookaside = 0;
+ if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
+ nLookaside = sqlite3LookasideUsed(db, 0);
+ }
+#endif
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
@@ -98888,14 +111077,14 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
assert( pIndex->pSchema==pTable->pSchema
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
- char *zName = pIndex->zName;
+ char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
);
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
assert( pOld==pIndex || pOld==0 );
}
- freeIndex(db, pIndex);
+ sqlite3FreeIndex(db, pIndex);
}
/* Delete any foreign keys attached to this table. */
@@ -98914,12 +111103,12 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
sqlite3DbFree(db, pTable);
/* Verify that no lookaside memory was used by schema tables */
- assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
+ assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
}
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
if( !pTable ) return;
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
+ if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
deleteTable(db, pTable);
}
@@ -98940,7 +111129,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
pDb = &db->aDb[iDb];
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, 0);
sqlite3DeleteTable(db, p);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
/*
@@ -98968,13 +111157,13 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
}
/*
-** Open the sqlite_master table stored in database number iDb for
+** Open the sqlite_schema table stored in database number iDb for
** writing. The table is opened using cursor 0.
*/
-SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
+SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
- sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
+ sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, DFLT_SCHEMA_TABLE);
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5);
if( p->nTab==0 ){
p->nTab = 1;
}
@@ -98991,7 +111180,10 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
if( zName ){
Db *pDb;
for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
- if( 0==sqlite3StrICmp(pDb->zDbSName, zName) ) break;
+ if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break;
+ /* "main" is always an acceptable alias for the primary database
+ ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */
+ if( i==0 && 0==sqlite3_stricmp("main", zName) ) break;
}
}
return i;
@@ -99000,7 +111192,7 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
/*
** The token *pName contains the name of a database (either "main" or
** "temp" or the name of an attached db). This routine returns the
-** index of the named database in db->aDb[], or -1 if the named db
+** index of the named database in db->aDb[], or -1 if the named db
** does not exist.
*/
SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){
@@ -99016,7 +111208,7 @@ SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){
** pName1 and pName2. If the table name was fully qualified, for example:
**
** CREATE TABLE xxx.yyy (...);
-**
+**
** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
** the table name is not fully qualified, i.e.:
**
@@ -99050,7 +111242,8 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
return -1;
}
}else{
- assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
+ assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT
+ || (db->mDbFlags & DBFLAG_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
}
@@ -99058,18 +111251,61 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
}
/*
+** True if PRAGMA writable_schema is ON
+*/
+SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3 *db){
+ testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==0 );
+ testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==
+ SQLITE_WriteSchema );
+ testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==
+ SQLITE_Defensive );
+ testcase( (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==
+ (SQLITE_WriteSchema|SQLITE_Defensive) );
+ return (db->flags&(SQLITE_WriteSchema|SQLITE_Defensive))==SQLITE_WriteSchema;
+}
+
+/*
** This routine is used to check if the UTF-8 string zName is a legal
** unqualified name for a new schema object (table, index, view or
** trigger). All names are legal except those that begin with the string
** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
** is reserved for internal use.
+**
+** When parsing the sqlite_schema table, this routine also checks to
+** make sure the "type", "name", and "tbl_name" columns are consistent
+** with the SQL.
*/
-SQLITE_PRIVATE int sqlite3CheckObjectName(Parse *pParse, const char *zName){
- if( !pParse->db->init.busy && pParse->nested==0
- && (pParse->db->flags & SQLITE_WriteSchema)==0
- && 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
- sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s", zName);
- return SQLITE_ERROR;
+SQLITE_PRIVATE int sqlite3CheckObjectName(
+ Parse *pParse, /* Parsing context */
+ const char *zName, /* Name of the object to check */
+ const char *zType, /* Type of this object */
+ const char *zTblName /* Parent table name for triggers and indexes */
+){
+ sqlite3 *db = pParse->db;
+ if( sqlite3WritableSchema(db)
+ || db->init.imposterTable
+ || !sqlite3Config.bExtraSchemaChecks
+ ){
+ /* Skip these error checks for writable_schema=ON */
+ return SQLITE_OK;
+ }
+ if( db->init.busy ){
+ if( sqlite3_stricmp(zType, db->init.azInit[0])
+ || sqlite3_stricmp(zName, db->init.azInit[1])
+ || sqlite3_stricmp(zTblName, db->init.azInit[2])
+ ){
+ sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
+ return SQLITE_ERROR;
+ }
+ }else{
+ if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
+ || (sqlite3ReadOnlyShadowTables(db) && sqlite3ShadowTableName(db, zName))
+ ){
+ sqlite3ErrorMsg(pParse, "object name reserved for internal use: %s",
+ zName);
+ return SQLITE_ERROR;
+ }
+
}
return SQLITE_OK;
}
@@ -99084,10 +111320,12 @@ SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table *pTab){
}
/*
-** Return the column of index pIdx that corresponds to table
-** column iCol. Return -1 if not found.
+** Convert an table column number into a index column number. That is,
+** for the column iCol in the table (as defined by the CREATE TABLE statement)
+** find the (first) offset of that column in index pIdx. Or return -1
+** if column iCol is not used in index pIdx.
*/
-SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
+SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index *pIdx, i16 iCol){
int i;
for(i=0; i<pIdx->nColumn; i++){
if( iCol==pIdx->aiColumn[i] ) return i;
@@ -99095,6 +111333,84 @@ SQLITE_PRIVATE i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){
return -1;
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/* Convert a storage column number into a table column number.
+**
+** The storage column number (0,1,2,....) is the index of the value
+** as it appears in the record on disk. The true column number
+** is the index (0,1,2,...) of the column in the CREATE TABLE statement.
+**
+** The storage column number is less than the table column number if
+** and only there are VIRTUAL columns to the left.
+**
+** If SQLITE_OMIT_GENERATED_COLUMNS, this routine is a no-op macro.
+*/
+SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){
+ if( pTab->tabFlags & TF_HasVirtual ){
+ int i;
+ for(i=0; i<=iCol; i++){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) iCol++;
+ }
+ }
+ return iCol;
+}
+#endif
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/* Convert a table column number into a storage column number.
+**
+** The storage column number (0,1,2,....) is the index of the value
+** as it appears in the record on disk. Or, if the input column is
+** the N-th virtual column (zero-based) then the storage number is
+** the number of non-virtual columns in the table plus N.
+**
+** The true column number is the index (0,1,2,...) of the column in
+** the CREATE TABLE statement.
+**
+** If the input column is a VIRTUAL column, then it should not appear
+** in storage. But the value sometimes is cached in registers that
+** follow the range of registers used to construct storage. This
+** avoids computing the same VIRTUAL column multiple times, and provides
+** values for use by OP_Param opcodes in triggers. Hence, if the
+** input column is a VIRTUAL table, put it after all the other columns.
+**
+** In the following, N means "normal column", S means STORED, and
+** V means VIRTUAL. Suppose the CREATE TABLE has columns like this:
+**
+** CREATE TABLE ex(N,S,V,N,S,V,N,S,V);
+** -- 0 1 2 3 4 5 6 7 8
+**
+** Then the mapping from this function is as follows:
+**
+** INPUTS: 0 1 2 3 4 5 6 7 8
+** OUTPUTS: 0 1 6 2 3 7 4 5 8
+**
+** So, in other words, this routine shifts all the virtual columns to
+** the end.
+**
+** If SQLITE_OMIT_GENERATED_COLUMNS then there are no virtual columns and
+** this routine is a no-op macro. If the pTab does not have any virtual
+** columns, then this routine is no-op that always return iCol. If iCol
+** is negative (indicating the ROWID column) then this routine return iCol.
+*/
+SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
+ int i;
+ i16 n;
+ assert( iCol<pTab->nCol );
+ if( (pTab->tabFlags & TF_HasVirtual)==0 || iCol<0 ) return iCol;
+ for(i=0, n=0; i<iCol; i++){
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) n++;
+ }
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ){
+ /* iCol is a virtual column itself */
+ return pTab->nNVCol + i - n;
+ }else{
+ /* iCol is a normal or stored column */
+ return n;
+ }
+}
+#endif
+
/*
** Begin constructing a new table representation in memory. This is
** the first of several action routines that get called in response
@@ -99128,7 +111444,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
Token *pName; /* Unqualified name of the table to create */
if( db->init.busy && db->init.newTnum==1 ){
- /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
+ /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */
iDb = db->init.iDb;
zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
pName = pName1;
@@ -99137,17 +111453,20 @@ SQLITE_PRIVATE void sqlite3StartTable(
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
if( iDb<0 ) return;
if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
- /* If creating a temp table, the name may not be qualified. Unless
+ /* If creating a temp table, the name may not be qualified. Unless
** the database name is "temp" anyway. */
sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
return;
}
if( !OMIT_TEMPDB && isTemp ) iDb = 1;
zName = sqlite3NameFromToken(db, pName);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)zName, pName);
+ }
}
pParse->sNameToken = *pName;
if( zName==0 ) return;
- if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
+ if( sqlite3CheckObjectName(pParse, zName, isView?"view":"table", zName) ){
goto begin_table_error;
}
if( db->init.iDb==1 ) isTemp = 1;
@@ -99179,7 +111498,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
** and types will be used, so there is no need to test for namespace
** collisions.
*/
- if( !IN_DECLARE_VTAB ){
+ if( !IN_SPECIAL_PARSE ){
char *zDb = db->aDb[iDb].zDbSName;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto begin_table_error;
@@ -99210,8 +111529,12 @@ SQLITE_PRIVATE void sqlite3StartTable(
pTable->zName = zName;
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
- pTable->nRef = 1;
+ pTable->nTabRef = 1;
+#ifdef SQLITE_DEFAULT_ROWEST
+ pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST);
+#else
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
+#endif
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
@@ -99227,10 +111550,10 @@ SQLITE_PRIVATE void sqlite3StartTable(
#endif
/* Begin generating the code that will insert the table record into
- ** the SQLITE_MASTER table. Note in particular that we must go ahead
+ ** the schema table. Note in particular that we must go ahead
** and allocate the record number for the table entry now. Before any
** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
- ** indices to be created and the table record must come before the
+ ** indices to be created and the table record must come before the
** indices. Hence, the record number for the table must be allocated
** now.
*/
@@ -99248,7 +111571,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
}
#endif
- /* If the file format and encoding in the database have not been set,
+ /* If the file format and encoding in the database have not been set,
** set them now.
*/
reg1 = pParse->regRowid = ++pParse->nMem;
@@ -99263,7 +111586,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
sqlite3VdbeJumpHere(v, addr1);
- /* This just creates a place-holder record in the sqlite_master table.
+ /* This just creates a place-holder record in the sqlite_schema table.
** The record created does not contain anything yet. It will be replaced
** by the real entry in code generated at sqlite3EndTable().
**
@@ -99278,9 +111601,10 @@ SQLITE_PRIVATE void sqlite3StartTable(
}else
#endif
{
- pParse->addrCrTab = sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
+ pParse->addrCrTab =
+ sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
}
- sqlite3OpenMasterTable(pParse, iDb);
+ sqlite3OpenSchemaTable(pParse, iDb);
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
@@ -99327,14 +111651,13 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
-#if SQLITE_MAX_COLUMN
if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
return;
}
-#endif
z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
if( z==0 ) return;
+ if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName);
memcpy(z, pName->z, pName->n);
z[pName->n] = 0;
sqlite3Dequote(z);
@@ -99357,22 +111680,29 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
pCol = &p->aCol[p->nCol];
memset(pCol, 0, sizeof(p->aCol[0]));
pCol->zName = z;
+ pCol->hName = sqlite3StrIHash(z);
sqlite3ColumnPropertiesFromName(p, pCol);
-
+
if( pType->n==0 ){
/* If there is no type specified, columns have the default affinity
- ** 'BLOB'. */
+ ** 'BLOB' with a default size of 4 bytes. */
pCol->affinity = SQLITE_AFF_BLOB;
pCol->szEst = 1;
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( 4>=sqlite3GlobalConfig.szSorterRef ){
+ pCol->colFlags |= COLFLAG_SORTERREF;
+ }
+#endif
}else{
zType = z + sqlite3Strlen30(z) + 1;
memcpy(zType, pType->z, pType->n);
zType[pType->n] = 0;
sqlite3Dequote(zType);
- pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
+ pCol->affinity = sqlite3AffinityType(zType, pCol);
pCol->colFlags |= COLFLAG_HASTYPE;
}
p->nCol++;
+ p->nNVCol++;
pParse->constraintName.n = 0;
}
@@ -99384,20 +111714,35 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
*/
SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
Table *p;
+ Column *pCol;
p = pParse->pNewTable;
if( p==0 || NEVER(p->nCol<1) ) return;
- p->aCol[p->nCol-1].notNull = (u8)onError;
+ pCol = &p->aCol[p->nCol-1];
+ pCol->notNull = (u8)onError;
+ p->tabFlags |= TF_HasNotNull;
+
+ /* Set the uniqNotNull flag on any UNIQUE or PK indexes already created
+ ** on this column. */
+ if( pCol->colFlags & COLFLAG_UNIQUE ){
+ Index *pIdx;
+ for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
+ assert( pIdx->nKeyCol==1 && pIdx->onError!=OE_None );
+ if( pIdx->aiColumn[0]==p->nCol-1 ){
+ pIdx->uniqNotNull = 1;
+ }
+ }
+ }
}
/*
** Scan the column type name zType (length nType) and return the
** associated affinity type.
**
-** This routine does a case-independent search of zType for the
+** This routine does a case-independent search of zType for the
** substrings in the following table. If one of the substrings is
** found, the corresponding affinity is returned. If zType contains
-** more than one of the substrings, entries toward the top of
-** the table take priority. For example, if zType is 'BLOBINT',
+** more than one of the substrings, entries toward the top of
+** the table take priority. For example, if zType is 'BLOBINT',
** SQLITE_AFF_INTEGER is returned.
**
** Substring | Affinity
@@ -99414,7 +111759,7 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
** If none of the substrings in the above table are found,
** SQLITE_AFF_NUMERIC is returned.
*/
-SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
+SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, Column *pCol){
u32 h = 0;
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
@@ -99451,27 +111796,32 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
}
}
- /* If pszEst is not NULL, store an estimate of the field size. The
+ /* If pCol is not NULL, store an estimate of the field size. The
** estimate is scaled so that the size of an integer is 1. */
- if( pszEst ){
- *pszEst = 1; /* default size is approx 4 bytes */
+ if( pCol ){
+ int v = 0; /* default size is approx 4 bytes */
if( aff<SQLITE_AFF_NUMERIC ){
if( zChar ){
while( zChar[0] ){
if( sqlite3Isdigit(zChar[0]) ){
- int v = 0;
+ /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
sqlite3GetInt32(zChar, &v);
- v = v/4 + 1;
- if( v>255 ) v = 255;
- *pszEst = v; /* BLOB(k), VARCHAR(k), CHAR(k) -> r=(k/4+1) */
break;
}
zChar++;
}
}else{
- *pszEst = 5; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
+ v = 16; /* BLOB, TEXT, CLOB -> r=5 (approx 20 bytes)*/
}
}
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( v>=sqlite3GlobalConfig.szSorterRef ){
+ pCol->colFlags |= COLFLAG_SORTERREF;
+ }
+#endif
+ v = v/4 + 1;
+ if( v>255 ) v = 255;
+ pCol->szEst = v;
}
return aff;
}
@@ -99486,39 +111836,52 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
** This routine is called by the parser while in the middle of
** parsing a CREATE TABLE statement.
*/
-SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
+SQLITE_PRIVATE void sqlite3AddDefaultValue(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The parsed expression of the default value */
+ const char *zStart, /* Start of the default value text */
+ const char *zEnd /* First character past end of defaut value text */
+){
Table *p;
Column *pCol;
sqlite3 *db = pParse->db;
p = pParse->pNewTable;
if( p!=0 ){
+ int isInit = db->init.busy && db->init.iDb!=1;
pCol = &(p->aCol[p->nCol-1]);
- if( !sqlite3ExprIsConstantOrFunction(pSpan->pExpr, db->init.busy) ){
+ if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse, "cannot use DEFAULT on a generated column");
+#endif
}else{
/* A copy of pExpr is used instead of the original, as pExpr contains
- ** tokens that point to volatile memory. The 'span' of the expression
- ** is required by pragma table_info.
+ ** tokens that point to volatile memory.
*/
Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
memset(&x, 0, sizeof(x));
x.op = TK_SPAN;
- x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
- x.pLeft = pSpan->pExpr;
+ x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd);
+ x.pLeft = pExpr;
x.flags = EP_Skip;
pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
sqlite3DbFree(db, x.u.zToken);
}
}
- sqlite3ExprDelete(db, pSpan->pExpr);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameExprUnmap(pParse, pExpr);
+ }
+ sqlite3ExprDelete(db, pExpr);
}
/*
** Backwards Compatibility Hack:
-**
+**
** Historical versions of SQLite accepted strings as column names in
** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
**
@@ -99529,7 +111892,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
** accept it. This routine does the necessary conversion. It converts
** the expression given in its argument from a TK_STRING into a TK_ID
** if the expression is just a TK_STRING with an optional COLLATE clause.
-** If the epxression is anything other than TK_STRING, the expression is
+** If the expression is anything other than TK_STRING, the expression is
** unchanged.
*/
static void sqlite3StringToId(Expr *p){
@@ -99541,7 +111904,22 @@ static void sqlite3StringToId(Expr *p){
}
/*
-** Designate the PRIMARY KEY for the table. pList is a list of names
+** Tag the given column as being part of the PRIMARY KEY
+*/
+static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){
+ pCol->colFlags |= COLFLAG_PRIMKEY;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse,
+ "generated columns cannot be part of the PRIMARY KEY");
+ }
+#endif
+}
+
+/*
+** Designate the PRIMARY KEY for the table. pList is a list of names
** of columns that form the primary key. If pList is NULL, then the
** most recently added column of the table is the primary key.
**
@@ -99571,7 +111949,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
int nTerm;
if( pTab==0 ) goto primary_key_exit;
if( pTab->tabFlags & TF_HasPrimaryKey ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
goto primary_key_exit;
}
@@ -99579,7 +111957,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
if( pList==0 ){
iCol = pTab->nCol - 1;
pCol = &pTab->aCol[iCol];
- pCol->colFlags |= COLFLAG_PRIMKEY;
+ makeColumnPartOfPrimaryKey(pParse, pCol);
nTerm = 1;
}else{
nTerm = pList->nExpr;
@@ -99592,7 +111970,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
for(iCol=0; iCol<pTab->nCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
pCol = &pTab->aCol[iCol];
- pCol->colFlags |= COLFLAG_PRIMKEY;
+ makeColumnPartOfPrimaryKey(pParse, pCol);
break;
}
}
@@ -99604,11 +111982,16 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
&& sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
&& sortOrder!=SQLITE_SO_DESC
){
+ if( IN_RENAME_OBJECT && pList ){
+ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr);
+ sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr);
+ }
pTab->iPKey = iCol;
pTab->keyConf = (u8)onError;
assert( autoInc==0 || autoInc==1 );
pTab->tabFlags |= autoInc*TF_Autoincrement;
- if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder;
+ if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
+ (void)sqlite3HasExplicitNulls(pParse, pList);
}else if( autoInc ){
#ifndef SQLITE_OMIT_AUTOINCREMENT
sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
@@ -99669,7 +112052,7 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){
Index *pIdx;
sqlite3DbFree(db, p->aCol[i].zColl);
p->aCol[i].zColl = zColl;
-
+
/* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
** then an index may have been created on this column before the
** collation type was added. Correct this if it is the case.
@@ -99685,41 +112068,58 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){
}
}
-/*
-** This function returns the collation sequence for database native text
-** encoding identified by the string zName, length nName.
-**
-** If the requested collation sequence is not available, or not available
-** in the database native encoding, the collation factory is invoked to
-** request it. If the collation factory does not supply such a sequence,
-** and the sequence is available in another text encoding, then that is
-** returned instead.
-**
-** If no versions of the requested collations sequence are available, or
-** another error occurs, NULL is returned and an error message written into
-** pParse.
-**
-** This routine is a wrapper around sqlite3FindCollSeq(). This routine
-** invokes the collation factory if the named collation cannot be found
-** and generates an error message.
-**
-** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
+/* Change the most recently parsed column to be a GENERATED ALWAYS AS
+** column.
*/
-SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
- sqlite3 *db = pParse->db;
- u8 enc = ENC(db);
- u8 initbusy = db->init.busy;
- CollSeq *pColl;
-
- pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
- if( !initbusy && (!pColl || !pColl->xCmp) ){
- pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
+SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType){
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ u8 eType = COLFLAG_VIRTUAL;
+ Table *pTab = pParse->pNewTable;
+ Column *pCol;
+ if( pTab==0 ){
+ /* generated column in an CREATE TABLE IF NOT EXISTS that already exists */
+ goto generated_done;
+ }
+ pCol = &(pTab->aCol[pTab->nCol-1]);
+ if( IN_DECLARE_VTAB ){
+ sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns");
+ goto generated_done;
+ }
+ if( pCol->pDflt ) goto generated_error;
+ if( pType ){
+ if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){
+ /* no-op */
+ }else if( pType->n==6 && sqlite3StrNICmp("stored",pType->z,6)==0 ){
+ eType = COLFLAG_STORED;
+ }else{
+ goto generated_error;
+ }
+ }
+ if( eType==COLFLAG_VIRTUAL ) pTab->nNVCol--;
+ pCol->colFlags |= eType;
+ assert( TF_HasVirtual==COLFLAG_VIRTUAL );
+ assert( TF_HasStored==COLFLAG_STORED );
+ pTab->tabFlags |= eType;
+ if( pCol->colFlags & COLFLAG_PRIMKEY ){
+ makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */
}
+ pCol->pDflt = pExpr;
+ pExpr = 0;
+ goto generated_done;
- return pColl;
+generated_error:
+ sqlite3ErrorMsg(pParse, "error in generated column \"%s\"",
+ pCol->zName);
+generated_done:
+ sqlite3ExprDelete(pParse->db, pExpr);
+#else
+ /* Throw and error for the GENERATED ALWAYS AS clause if the
+ ** SQLITE_OMIT_GENERATED_COLUMNS compile-time option is used. */
+ sqlite3ErrorMsg(pParse, "generated columns not supported");
+ sqlite3ExprDelete(pParse->db, pExpr);
+#endif
}
-
/*
** Generate code that will increment the schema cookie.
**
@@ -99743,8 +112143,8 @@ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION,
- db->aDb[iDb].pSchema->schema_cookie+1);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION,
+ (int)(1+(unsigned)db->aDb[iDb].pSchema->schema_cookie));
}
/*
@@ -99764,13 +112164,13 @@ static int identLength(const char *z){
}
/*
-** The first parameter is a pointer to an output buffer. The second
+** The first parameter is a pointer to an output buffer. The second
** parameter is a pointer to an integer that contains the offset at
** which to write into the output buffer. This function copies the
** nul-terminated string pointed to by the third parameter, zSignedIdent,
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
-**
+**
** If the string zSignedIdent consists entirely of alpha-numeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
@@ -99814,7 +112214,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
n += identLength(pCol->zName) + 5;
}
n += identLength(p->zName);
- if( n<50 ){
+ if( n<50 ){
zSep = "";
zSep2 = ",";
zEnd = ")";
@@ -99855,10 +112255,10 @@ static char *createTableStmt(sqlite3 *db, Table *p){
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
testcase( pCol->affinity==SQLITE_AFF_REAL );
-
+
zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
len = sqlite3Strlen30(zType);
- assert( pCol->affinity==SQLITE_AFF_BLOB
+ assert( pCol->affinity==SQLITE_AFF_BLOB
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
memcpy(&zStmt[k], zType, len);
k += len;
@@ -99922,14 +112322,89 @@ static void estimateIndexWidth(Index *pIdx){
pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
}
-/* Return true if value x is found any of the first nCol entries of aiCol[]
+/* Return true if column number x is any of the first nCol entries of aiCol[].
+** This is used to determine if the column number x appears in any of the
+** first nCol entries of an index.
*/
static int hasColumn(const i16 *aiCol, int nCol, int x){
- while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1;
+ while( nCol-- > 0 ){
+ assert( aiCol[0]>=0 );
+ if( x==*(aiCol++) ){
+ return 1;
+ }
+ }
return 0;
}
/*
+** Return true if any of the first nKey entries of index pIdx exactly
+** match the iCol-th entry of pPk. pPk is always a WITHOUT ROWID
+** PRIMARY KEY index. pIdx is an index on the same table. pIdx may
+** or may not be the same index as pPk.
+**
+** The first nKey entries of pIdx are guaranteed to be ordinary columns,
+** not a rowid or expression.
+**
+** This routine differs from hasColumn() in that both the column and the
+** collating sequence must match for this routine, but for hasColumn() only
+** the column name must match.
+*/
+static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
+ int i, j;
+ assert( nKey<=pIdx->nColumn );
+ assert( iCol<MAX(pPk->nColumn,pPk->nKeyCol) );
+ assert( pPk->idxType==SQLITE_IDXTYPE_PRIMARYKEY );
+ assert( pPk->pTable->tabFlags & TF_WithoutRowid );
+ assert( pPk->pTable==pIdx->pTable );
+ testcase( pPk==pIdx );
+ j = pPk->aiColumn[iCol];
+ assert( j!=XN_ROWID && j!=XN_EXPR );
+ for(i=0; i<nKey; i++){
+ assert( pIdx->aiColumn[i]>=0 || j>=0 );
+ if( pIdx->aiColumn[i]==j
+ && sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Recompute the colNotIdxed field of the Index.
+**
+** colNotIdxed is a bitmask that has a 0 bit representing each indexed
+** columns that are within the first 63 columns of the table. The
+** high-order bit of colNotIdxed is always 1. All unindexed columns
+** of the table have a 1.
+**
+** 2019-10-24: For the purpose of this computation, virtual columns are
+** not considered to be covered by the index, even if they are in the
+** index, because we do not trust the logic in whereIndexExprTrans() to be
+** able to find all instances of a reference to the indexed table column
+** and convert them into references to the index. Hence we always want
+** the actual table at hand in order to recompute the virtual column, if
+** necessary.
+**
+** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
+** to determine if the index is covering index.
+*/
+static void recomputeColumnsNotIndexed(Index *pIdx){
+ Bitmask m = 0;
+ int j;
+ Table *pTab = pIdx->pTable;
+ for(j=pIdx->nColumn-1; j>=0; j--){
+ int x = pIdx->aiColumn[j];
+ if( x>=0 && (pTab->aCol[x].colFlags & COLFLAG_VIRTUAL)==0 ){
+ testcase( x==BMS-1 );
+ testcase( x==BMS-2 );
+ if( x<BMS-1 ) m |= MASKBIT(x);
+ }
+ }
+ pIdx->colNotIdxed = ~m;
+ assert( (pIdx->colNotIdxed>>63)==1 );
+}
+
+/*
** This routine runs at the end of parsing a CREATE TABLE statement that
** has a WITHOUT ROWID clause. The job of this routine is to convert both
** internal schema data structures and the generated VDBE code so that they
@@ -99937,17 +112412,16 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** Changes include:
**
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
-** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is
-** no rowid btree for a WITHOUT ROWID. Instead, the canonical
-** data storage is a covering index btree.
-** (3) Bypass the creation of the sqlite_master table entry
+** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
+** into BTREE_BLOBKEY.
+** (3) Bypass the creation of the sqlite_schema table entry
** for the PRIMARY KEY as the primary key index is now
-** identified by the sqlite_master table entry of the table itself.
+** identified by the sqlite_schema table entry of the table itself.
** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
** schema to the rootpage from the main table.
** (5) Add all table columns to the PRIMARY KEY Index object
** so that the PRIMARY KEY is a covering index. The surplus
-** columns are part of KeyInfo.nXField and are not used for
+** columns are part of KeyInfo.nAllField and are not used for
** sorting or lookup or uniqueness checks.
** (6) Replace the rowid tail on all automatically generated UNIQUE
** indices with the PRIMARY KEY columns.
@@ -99958,6 +112432,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
Index *pIdx;
Index *pPk;
int nPk;
+ int nExtra;
int i, j;
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
@@ -99970,49 +112445,41 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
pTab->aCol[i].notNull = OE_Abort;
}
}
+ pTab->tabFlags |= TF_HasNotNull;
}
- /* The remaining transformations only apply to b-tree tables, not to
- ** virtual tables */
- if( IN_DECLARE_VTAB ) return;
-
- /* Convert the OP_CreateTable opcode that would normally create the
- ** root-page for the table into an OP_CreateIndex opcode. The index
- ** created will become the PRIMARY KEY index.
+ /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
+ ** into BTREE_BLOBKEY.
*/
if( pParse->addrCrTab ){
assert( v );
- sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
+ sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
}
/* Locate the PRIMARY KEY index. Or, if this table was originally
- ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
+ ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
*/
if( pTab->iPKey>=0 ){
ExprList *pList;
Token ipkToken;
sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName);
- pList = sqlite3ExprListAppend(pParse, 0,
+ pList = sqlite3ExprListAppend(pParse, 0,
sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
if( pList==0 ) return;
- pList->a[0].sortOrder = pParse->iPkSortOrder;
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey);
+ }
+ pList->a[0].sortFlags = pParse->iPkSortOrder;
assert( pParse->pNewTable==pTab );
+ pTab->iPKey = -1;
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
SQLITE_IDXTYPE_PRIMARYKEY);
- if( db->mallocFailed ) return;
+ if( db->mallocFailed || pParse->nErr ) return;
pPk = sqlite3PrimaryKeyIndex(pTab);
- pTab->iPKey = -1;
+ assert( pPk->nKeyCol==1 );
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
-
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
- ** table entry. This is only required if currently generating VDBE
- ** code for a CREATE TABLE (not when parsing one as part of reading
- ** a database schema). */
- if( v ){
- assert( db->init.busy==0 );
- sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
- }
+ assert( pPk!=0 );
/*
** Remove all redundant columns from the PRIMARY KEY. For example, change
@@ -100020,9 +112487,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** code assumes the PRIMARY KEY contains no repeated columns.
*/
for(i=j=1; i<pPk->nKeyCol; i++){
- if( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){
+ if( isDupColumn(pPk, j, pPk, i) ){
pPk->nColumn--;
}else{
+ testcase( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) );
+ pPk->azColl[j] = pPk->azColl[i];
+ pPk->aSortOrder[j] = pPk->aSortOrder[i];
pPk->aiColumn[j++] = pPk->aiColumn[i];
}
}
@@ -100031,7 +112501,16 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
assert( pPk!=0 );
pPk->isCovering = 1;
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
- nPk = pPk->nKeyCol;
+ nPk = pPk->nColumn = pPk->nKeyCol;
+
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema
+ ** table entry. This is only required if currently generating VDBE
+ ** code for a CREATE TABLE (not when parsing one as part of reading
+ ** a database schema). */
+ if( v && pPk->tnum>0 ){
+ assert( db->init.busy==0 );
+ sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto);
+ }
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
@@ -100043,7 +112522,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
int n;
if( IsPrimaryKeyIndex(pIdx) ) continue;
for(i=n=0; i<nPk; i++){
- if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++;
+ if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){
+ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) );
+ n++;
+ }
}
if( n==0 ){
/* This index is a superset of the primary key */
@@ -100052,9 +112534,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
}
if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return;
for(i=0, j=pIdx->nKeyCol; i<nPk; i++){
- if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){
+ if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){
+ testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) );
pIdx->aiColumn[j] = pPk->aiColumn[i];
pIdx->azColl[j] = pPk->azColl[i];
+ if( pPk->aSortOrder[i] ){
+ /* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */
+ pIdx->bAscKeyBug = 1;
+ }
j++;
}
}
@@ -100064,22 +112551,97 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
/* Add all table columns to the PRIMARY KEY index
*/
- if( nPk<pTab->nCol ){
- if( resizeIndexObject(db, pPk, pTab->nCol) ) return;
- for(i=0, j=nPk; i<pTab->nCol; i++){
- if( !hasColumn(pPk->aiColumn, j, i) ){
- assert( j<pPk->nColumn );
- pPk->aiColumn[j] = i;
- pPk->azColl[j] = sqlite3StrBINARY;
- j++;
- }
+ nExtra = 0;
+ for(i=0; i<pTab->nCol; i++){
+ if( !hasColumn(pPk->aiColumn, nPk, i)
+ && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
+ }
+ if( resizeIndexObject(db, pPk, nPk+nExtra) ) return;
+ for(i=0, j=nPk; i<pTab->nCol; i++){
+ if( !hasColumn(pPk->aiColumn, j, i)
+ && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
+ ){
+ assert( j<pPk->nColumn );
+ pPk->aiColumn[j] = i;
+ pPk->azColl[j] = sqlite3StrBINARY;
+ j++;
}
- assert( pPk->nColumn==j );
- assert( pTab->nCol==j );
- }else{
- pPk->nColumn = pTab->nCol;
+ }
+ assert( pPk->nColumn==j );
+ assert( pTab->nNVCol<=j );
+ recomputeColumnsNotIndexed(pPk);
+}
+
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Return true if pTab is a virtual table and zName is a shadow table name
+** for that virtual table.
+*/
+SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
+ int nName; /* Length of zName */
+ Module *pMod; /* Module for the virtual table */
+
+ if( !IsVirtual(pTab) ) return 0;
+ nName = sqlite3Strlen30(pTab->zName);
+ if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
+ if( zName[nName]!='_' ) return 0;
+ pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
+ if( pMod==0 ) return 0;
+ if( pMod->pModule->iVersion<3 ) return 0;
+ if( pMod->pModule->xShadowName==0 ) return 0;
+ return pMod->pModule->xShadowName(zName+nName+1);
+}
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*
+** Return true if zName is a shadow table name in the current database
+** connection.
+**
+** zName is temporarily modified while this routine is running, but is
+** restored to its original value prior to this routine returning.
+*/
+SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
+ char *zTail; /* Pointer to the last "_" in zName */
+ Table *pTab; /* Table that zName is a shadow of */
+ zTail = strrchr(zName, '_');
+ if( zTail==0 ) return 0;
+ *zTail = 0;
+ pTab = sqlite3FindTable(db, zName, 0);
+ *zTail = '_';
+ if( pTab==0 ) return 0;
+ if( !IsVirtual(pTab) ) return 0;
+ return sqlite3IsShadowTableOf(db, pTab, zName);
+}
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
+
+
+#ifdef SQLITE_DEBUG
+/*
+** Mark all nodes of an expression as EP_Immutable, indicating that
+** they should not be changed. Expressions attached to a table or
+** index definition are tagged this way to help ensure that we do
+** not pass them into code generator routines by mistake.
+*/
+static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){
+ ExprSetVVAProperty(pExpr, EP_Immutable);
+ return WRC_Continue;
+}
+static void markExprListImmutable(ExprList *pList){
+ if( pList ){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = markImmutableExprStep;
+ w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.xSelectCallback2 = 0;
+ sqlite3WalkExprList(&w, pList);
}
}
+#else
+#define markExprListImmutable(X) /* no-op */
+#endif /* SQLITE_DEBUG */
+
/*
** This routine is called to report the final ")" that terminates
@@ -100089,15 +112651,15 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
** is added to the internal hash tables, assuming no errors have
** occurred.
**
-** An entry for the table is made in the master table on disk, unless
+** An entry for the table is made in the schema table on disk, unless
** this is a temporary table or db->init.busy==1. When db->init.busy==1
-** it means we are reading the sqlite_master table because we just
-** connected to the database or because the sqlite_master table has
+** it means we are reading the sqlite_schema table because we just
+** connected to the database or because the sqlite_schema table has
** recently changed, so the entry for this table already exists in
-** the sqlite_master table. We do not want to create it again.
+** the sqlite_schema table. We do not want to create it again.
**
** If the pSelect argument is not NULL, it means that this routine
-** was called to create a table generated from a
+** was called to create a table generated from a
** "CREATE TABLE ... AS SELECT ..." statement. The column names of
** the new table will match the result set of the SELECT.
*/
@@ -100120,22 +112682,33 @@ SQLITE_PRIVATE void sqlite3EndTable(
p = pParse->pNewTable;
if( p==0 ) return;
- assert( !db->init.busy || !pSelect );
+ if( pSelect==0 && sqlite3ShadowTableName(db, p->zName) ){
+ p->tabFlags |= TF_Shadow;
+ }
/* If the db->init.busy is 1 it means we are reading the SQL off the
- ** "sqlite_master" or "sqlite_temp_master" table on the disk.
+ ** "sqlite_schema" or "sqlite_temp_schema" table on the disk.
** So do not write to the disk again. Extract the root page number
** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.)
**
- ** If the root page number is 1, that means this is the sqlite_master
+ ** If the root page number is 1, that means this is the sqlite_schema
** table itself. So mark it read-only.
*/
if( db->init.busy ){
+ if( pSelect ){
+ sqlite3ErrorMsg(pParse, "");
+ return;
+ }
p->tnum = db->init.newTnum;
if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
}
+ assert( (p->tabFlags & TF_HasPrimaryKey)==0
+ || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 );
+ assert( (p->tabFlags & TF_HasPrimaryKey)!=0
+ || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) );
+
/* Special processing for WITHOUT ROWID Tables */
if( tabOpts & TF_WithoutRowid ){
if( (p->tabFlags & TF_Autoincrement) ){
@@ -100145,12 +112718,11 @@ SQLITE_PRIVATE void sqlite3EndTable(
}
if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
sqlite3ErrorMsg(pParse, "PRIMARY KEY missing on table %s", p->zName);
- }else{
- p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
- convertToWithoutRowidTable(pParse, p);
+ return;
}
+ p->tabFlags |= TF_WithoutRowid | TF_NoVisibleRowid;
+ convertToWithoutRowidTable(pParse, p);
}
-
iDb = sqlite3SchemaToIndex(db, p->pSchema);
#ifndef SQLITE_OMIT_CHECK
@@ -100158,8 +112730,47 @@ SQLITE_PRIVATE void sqlite3EndTable(
*/
if( p->pCheck ){
sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
+ if( pParse->nErr ){
+ /* If errors are seen, delete the CHECK constraints now, else they might
+ ** actually be used if PRAGMA writable_schema=ON is set. */
+ sqlite3ExprListDelete(db, p->pCheck);
+ p->pCheck = 0;
+ }else{
+ markExprListImmutable(p->pCheck);
+ }
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( p->tabFlags & TF_HasGenerated ){
+ int ii, nNG = 0;
+ testcase( p->tabFlags & TF_HasVirtual );
+ testcase( p->tabFlags & TF_HasStored );
+ for(ii=0; ii<p->nCol; ii++){
+ u32 colFlags = p->aCol[ii].colFlags;
+ if( (colFlags & COLFLAG_GENERATED)!=0 ){
+ Expr *pX = p->aCol[ii].pDflt;
+ testcase( colFlags & COLFLAG_VIRTUAL );
+ testcase( colFlags & COLFLAG_STORED );
+ if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){
+ /* If there are errors in resolving the expression, change the
+ ** expression to a NULL. This prevents code generators that operate
+ ** on the expression from inserting extra parts into the expression
+ ** tree that have been allocated from lookaside memory, which is
+ ** illegal in a schema and will lead to errors or heap corruption
+ ** when the database connection closes. */
+ sqlite3ExprDelete(db, pX);
+ p->aCol[ii].pDflt = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
+ }
+ }else{
+ nNG++;
+ }
+ }
+ if( nNG==0 ){
+ sqlite3ErrorMsg(pParse, "must have at least one non-generated column");
+ return;
+ }
+ }
+#endif
/* Estimate the average row size for the table and for all implied indices */
estimateTableWidth(p);
@@ -100168,7 +112779,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
}
/* If not initializing, then create a record for the new table
- ** in the SQLITE_MASTER table of the database.
+ ** in the schema table of the database.
**
** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file.
@@ -100185,7 +112796,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
sqlite3VdbeAddOp1(v, OP_Close, 0);
- /*
+ /*
** Initialize zType for the new view or table.
*/
if( p->pSelect==0 ){
@@ -100232,19 +112843,20 @@ SQLITE_PRIVATE void sqlite3EndTable(
pParse->nTab = 2;
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
- sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
- sqlite3Select(pParse, pSelect, &dest);
- sqlite3VdbeEndCoroutine(v, regYield);
- sqlite3VdbeJumpHere(v, addrTop - 1);
if( pParse->nErr ) return;
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect);
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSelect, SQLITE_AFF_BLOB);
if( pSelTab==0 ) return;
assert( p->aCol==0 );
- p->nCol = pSelTab->nCol;
+ p->nCol = p->nNVCol = pSelTab->nCol;
p->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab);
+ sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
+ sqlite3Select(pParse, pSelect, &dest);
+ if( pParse->nErr ) return;
+ sqlite3VdbeEndCoroutine(v, regYield);
+ sqlite3VdbeJumpHere(v, addrTop - 1);
addrInsLoop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_MakeRecord, dest.iSdst, dest.nSdst, regRec);
@@ -100263,20 +112875,20 @@ SQLITE_PRIVATE void sqlite3EndTable(
Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd;
n = (int)(pEnd2->z - pParse->sNameToken.z);
if( pEnd2->z[0]!=';' ) n += pEnd2->n;
- zStmt = sqlite3MPrintf(db,
+ zStmt = sqlite3MPrintf(db,
"CREATE %s %.*s", zType2, n, pParse->sNameToken.z
);
}
- /* A slot for the record has already been allocated in the
- ** SQLITE_MASTER table. We just need to update that slot with all
+ /* A slot for the record has already been allocated in the
+ ** schema table. We just need to update that slot with all
** the information we've collected.
*/
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s "
- "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
- "WHERE rowid=#%d",
- db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb),
+ "UPDATE %Q." DFLT_SCHEMA_TABLE
+ " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
+ " WHERE rowid=#%d",
+ db->aDb[iDb].zDbSName,
zType,
p->zName,
p->zName,
@@ -100308,7 +112920,6 @@ SQLITE_PRIVATE void sqlite3EndTable(
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName));
}
-
/* Add the table to the in-memory representation of the database.
*/
if( db->init.busy ){
@@ -100322,7 +112933,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
return;
}
pParse->pNewTable = 0;
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
#ifndef SQLITE_OMIT_ALTERTABLE
if( !p->pSelect ){
@@ -100379,7 +112990,13 @@ SQLITE_PRIVATE void sqlite3CreateView(
** allocated rather than point to the input string - which means that
** they will persist after the current sqlite3_exec() call returns.
*/
- p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+ pSelect->selFlags |= SF_View;
+ if( IN_RENAME_OBJECT ){
+ p->pSelect = pSelect;
+ pSelect = 0;
+ }else{
+ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+ }
p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
if( db->mallocFailed ) goto create_view_fail;
@@ -100387,7 +113004,7 @@ SQLITE_PRIVATE void sqlite3CreateView(
** the end.
*/
sEnd = pParse->sLastToken;
- assert( sEnd.z[0]!=0 );
+ assert( sEnd.z[0]!=0 || sEnd.n==0 );
if( sEnd.z[0]!=';' ){
sEnd.z += sEnd.n;
}
@@ -100399,11 +113016,14 @@ SQLITE_PRIVATE void sqlite3CreateView(
sEnd.z = &z[n-1];
sEnd.n = 1;
- /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
+ /* Use sqlite3EndTable() to add the view to the schema table */
sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
create_view_fail:
sqlite3SelectDelete(db, pSelect);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameExprlistUnmap(pParse, pCNames);
+ }
sqlite3ExprListDelete(db, pCNames);
return;
}
@@ -100421,6 +113041,9 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ int rc;
+#endif
#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth; /* Saved xAuth pointer */
#endif
@@ -100428,8 +113051,11 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( sqlite3VtabCallConnect(pParse, pTable) ){
- return SQLITE_ERROR;
+ db->nSchemaLock++;
+ rc = sqlite3VtabCallConnect(pParse, pTable);
+ db->nSchemaLock--;
+ if( rc ){
+ return 1;
}
if( IsVirtual(pTable) ) return 0;
#endif
@@ -100450,7 +113076,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** Actually, the error above is now caught prior to reaching this point.
** But the following test is still important as it does come up
** in the following:
- **
+ **
** CREATE TABLE main.ex1(a);
** CREATE TEMP VIEW ex1 AS SELECT a FROM ex1;
** SELECT * FROM temp.ex1;
@@ -100471,35 +113097,41 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
assert( pTable->pSelect );
pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
if( pSel ){
+ u8 eParseMode = pParse->eParseMode;
+ pParse->eParseMode = PARSE_MODE_NORMAL;
n = pParse->nTab;
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
pTable->nCol = -1;
- db->lookaside.bDisable++;
+ DisableLookaside;
#ifndef SQLITE_OMIT_AUTHORIZATION
xAuth = db->xAuth;
db->xAuth = 0;
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
db->xAuth = xAuth;
#else
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
#endif
pParse->nTab = n;
- if( pTable->pCheck ){
+ if( pSelTab==0 ){
+ pTable->nCol = 0;
+ nErr++;
+ }else if( pTable->pCheck ){
/* CREATE VIEW name(arglist) AS ...
** The names of the columns in the table are taken from
** arglist which is stored in pTable->pCheck. The pCheck field
** normally holds CHECK constraints on an ordinary table, but for
** a VIEW it holds the list of column names.
*/
- sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
+ sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
&pTable->nCol, &pTable->aCol);
- if( db->mallocFailed==0
+ if( db->mallocFailed==0
&& pParse->nErr==0
&& pTable->nCol==pSel->pEList->nExpr
){
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
+ sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
+ SQLITE_AFF_NONE);
}
- }else if( pSelTab ){
+ }else{
/* CREATE VIEW name AS... without an argument list. Construct
** the column names from the SELECT statement that defines the view.
*/
@@ -100509,19 +113141,23 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSelTab->nCol = 0;
pSelTab->aCol = 0;
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
- }else{
- pTable->nCol = 0;
- nErr++;
}
+ pTable->nNVCol = pTable->nCol;
sqlite3DeleteTable(db, pSelTab);
sqlite3SelectDelete(db, pSel);
- db->lookaside.bDisable--;
+ EnableLookaside;
+ pParse->eParseMode = eParseMode;
} else {
nErr++;
}
pTable->pSchema->schemaFlags |= DB_UnresetViews;
+ if( db->mallocFailed ){
+ sqlite3DeleteColumnNames(db, pTable);
+ pTable->aCol = 0;
+ pTable->nCol = 0;
+ }
#endif /* SQLITE_OMIT_VIEW */
- return nErr;
+ return nErr;
}
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
@@ -100557,7 +113193,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
** on tables and/or indices that are the process of being deleted.
** If you are unlucky, one of those deleted indices or tables might
** have the same rootpage number as the real table or index that is
-** being moved. So we cannot stop searching after the first match
+** being moved. So we cannot stop searching after the first match
** because the first match might be for one of the deleted indices
** or tables and not the table/index that is actually being moved.
** We must continue looping until all tables and indices with
@@ -100565,7 +113201,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
** in order to be certain that we got the right one.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
-SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
HashElem *pElem;
Hash *pHash;
Db *pDb;
@@ -100591,51 +113227,44 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT
/*
** Write code to erase the table with root-page iTable from database iDb.
-** Also write code to modify the sqlite_master table and internal schema
+** Also write code to modify the sqlite_schema table and internal schema
** if a root-page of another table is moved by the btree-layer whilst
** erasing iTable (this can happen with an auto-vacuum database).
-*/
+*/
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
Vdbe *v = sqlite3GetVdbe(pParse);
int r1 = sqlite3GetTempReg(pParse);
- assert( iTable>1 );
+ if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema");
sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb);
sqlite3MayAbort(pParse);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* OP_Destroy stores an in integer r1. If this integer
** is non-zero, then it is the root page number of a table moved to
- ** location iTable. The following code modifies the sqlite_master table to
+ ** location iTable. The following code modifies the sqlite_schema table to
** reflect this.
**
** The "#NNN" in the SQL is a special constant that means whatever value
** is in register NNN. See grammar rules associated with the TK_REGISTER
** token for additional information.
*/
- sqlite3NestedParse(pParse,
- "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
- pParse->db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), iTable, r1, r1);
+ sqlite3NestedParse(pParse,
+ "UPDATE %Q." DFLT_SCHEMA_TABLE
+ " SET rootpage=%d WHERE #%d AND rootpage=#%d",
+ pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
}
/*
** Write VDBE code to erase table pTab and all associated indices on disk.
-** Code to update the sqlite_master tables and internal schema definitions
+** Code to update the sqlite_schema tables and internal schema definitions
** in case a root-page belonging to another table is moved by the btree layer
** is also added (this can happen with an auto-vacuum database).
*/
static void destroyTable(Parse *pParse, Table *pTab){
-#ifdef SQLITE_OMIT_AUTOVACUUM
- Index *pIdx;
- int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
- destroyRootPage(pParse, pTab->tnum, iDb);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- destroyRootPage(pParse, pIdx->tnum, iDb);
- }
-#else
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
** is not defined), then it is important to call OP_Destroy on the
- ** table and index root-pages in order, starting with the numerically
+ ** table and index root-pages in order, starting with the numerically
** largest root-page number. This guarantees that none of the root-pages
** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
** following were coded:
@@ -100645,22 +113274,22 @@ static void destroyTable(Parse *pParse, Table *pTab){
** OP_Destroy 5 0
**
** and root page 5 happened to be the largest root-page number in the
- ** database, then root page 5 would be moved to page 4 by the
+ ** database, then root page 5 would be moved to page 4 by the
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
** a free-list page.
*/
- int iTab = pTab->tnum;
- int iDestroyed = 0;
+ Pgno iTab = pTab->tnum;
+ Pgno iDestroyed = 0;
while( 1 ){
Index *pIdx;
- int iLargest = 0;
+ Pgno iLargest = 0;
if( iDestroyed==0 || iTab<iDestroyed ){
iLargest = iTab;
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- int iIdx = pIdx->tnum;
+ Pgno iIdx = pIdx->tnum;
assert( pIdx->pSchema==pTab->pSchema );
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
iLargest = iIdx;
@@ -100675,7 +113304,6 @@ static void destroyTable(Parse *pParse, Table *pTab){
iDestroyed = iLargest;
}
}
-#endif
}
/*
@@ -100722,12 +113350,12 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
#endif
/* Drop all triggers associated with the table being dropped. Code
- ** is generated to remove entries from sqlite_master and/or
- ** sqlite_temp_master if required.
+ ** is generated to remove entries from sqlite_schema and/or
+ ** sqlite_temp_schema if required.
*/
pTrigger = sqlite3TriggerList(pParse, pTab);
while( pTrigger ){
- assert( pTrigger->pSchema==pTab->pSchema ||
+ assert( pTrigger->pSchema==pTab->pSchema ||
pTrigger->pSchema==db->aDb[1].pSchema );
sqlite3DropTriggerPtr(pParse, pTrigger);
pTrigger = pTrigger->pNext;
@@ -100747,16 +113375,17 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
}
#endif
- /* Drop all SQLITE_MASTER table and index entries that refer to the
- ** table. The program name loops through the master table and deletes
+ /* Drop all entries in the schema table that refer to the
+ ** table. The program name loops through the schema table and deletes
** every row that refers to a table of the same name as the one being
** dropped. Triggers are handled separately because a trigger can be
** created in the temp database that refers to a table in another
** database.
*/
- sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
- pDb->zDbSName, SCHEMA_TABLE(iDb), pTab->zName);
+ sqlite3NestedParse(pParse,
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE
+ " WHERE tbl_name=%Q and type!='trigger'",
+ pDb->zDbSName, pTab->zName);
if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
@@ -100766,6 +113395,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
*/
if( IsVirtual(pTab) ){
sqlite3VdbeAddOp4(v, OP_VDestroy, iDb, 0, 0, pTab->zName, 0);
+ sqlite3MayAbort(pParse);
}
sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0);
sqlite3ChangeCookie(pParse, iDb);
@@ -100773,6 +113403,37 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
}
/*
+** Return TRUE if shadow tables should be read-only in the current
+** context.
+*/
+SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( (db->flags & SQLITE_Defensive)!=0
+ && db->pVtabCtx==0
+ && db->nVdbeExec==0
+ ){
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/*
+** Return true if it is not allowed to drop the given table
+*/
+static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
+ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){
+ if( sqlite3StrNICmp(pTab->zName+7, "stat", 4)==0 ) return 0;
+ if( sqlite3StrNICmp(pTab->zName+7, "parameters", 10)==0 ) return 0;
+ return 1;
+ }
+ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
+ return 1;
+ }
+ return 0;
+}
+
+/*
** This routine is called to do the work of a DROP TABLE statement.
** pName is the name of the table to be dropped.
*/
@@ -100841,8 +113502,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
}
}
#endif
- if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
- && sqlite3StrNICmp(pTab->zName, "sqlite_stat", 11)!=0 ){
+ if( tableMayNotBeDropped(db, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName);
goto exit_drop_table;
}
@@ -100861,14 +113521,16 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
}
#endif
- /* Generate code to remove the table from the master table
+ /* Generate code to remove the table from the schema table
** on disk.
*/
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3BeginWriteOperation(pParse, 1, iDb);
- sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
- sqlite3FkDropTable(pParse, pName, pTab);
+ if( !isView ){
+ sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
+ sqlite3FkDropTable(pParse, pName, pTab);
+ }
sqlite3CodeDropTable(pParse, pTab, iDb, isView);
}
@@ -100932,7 +113594,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
nByte = sizeof(*pFKey) + (nCol-1)*sizeof(pFKey->aCol[0]) + pTo->n + 1;
if( pToCol ){
for(i=0; i<pToCol->nExpr; i++){
- nByte += sqlite3Strlen30(pToCol->a[i].zName) + 1;
+ nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
}
}
pFKey = sqlite3DbMallocZero(db, nByte );
@@ -100943,6 +113605,9 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
pFKey->pNextFrom = p->pFKey;
z = (char*)&pFKey->aCol[nCol];
pFKey->zTo = z;
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)z, pTo);
+ }
memcpy(z, pTo->z, pTo->n);
z[pTo->n] = 0;
sqlite3Dequote(z);
@@ -100954,24 +113619,30 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
for(i=0; i<nCol; i++){
int j;
for(j=0; j<p->nCol; j++){
- if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zName)==0 ){
+ if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zEName)==0 ){
pFKey->aCol[i].iFrom = j;
break;
}
}
if( j>=p->nCol ){
- sqlite3ErrorMsg(pParse,
- "unknown column \"%s\" in foreign key definition",
- pFromCol->a[i].zName);
+ sqlite3ErrorMsg(pParse,
+ "unknown column \"%s\" in foreign key definition",
+ pFromCol->a[i].zEName);
goto fk_end;
}
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zEName);
+ }
}
}
if( pToCol ){
for(i=0; i<nCol; i++){
- int n = sqlite3Strlen30(pToCol->a[i].zName);
+ int n = sqlite3Strlen30(pToCol->a[i].zEName);
pFKey->aCol[i].zCol = z;
- memcpy(z, pToCol->a[i].zName, n);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zEName);
+ }
+ memcpy(z, pToCol->a[i].zEName, n);
z[n] = 0;
z += n+1;
}
@@ -100981,7 +113652,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */
assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
- pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
+ pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
pFKey->zTo, (void *)pFKey
);
if( pNextTo==pFKey ){
@@ -101041,7 +113712,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
int iSorter; /* Cursor opened by OpenSorter (if in use) */
int addr1; /* Address of top of loop */
int addr2; /* Address to jump to for next iteration */
- int tnum; /* Root page of index */
+ Pgno tnum; /* Root page of index */
int iPartIdxLabel; /* Jump to this label to skip a row */
Vdbe *v; /* Generate code into this virtual machine */
KeyInfo *pKey; /* KeyInfo for index */
@@ -101062,7 +113733,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
if( memRootPage>=0 ){
- tnum = memRootPage;
+ tnum = (Pgno)memRootPage;
}else{
tnum = pIndex->tnum;
}
@@ -101079,6 +113750,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
regRecord = sqlite3GetTempReg(pParse);
+ sqlite3MultiWrite(pParse);
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
@@ -101086,24 +113758,42 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
- sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb,
(char *)pKey, P4_KEYINFO);
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
if( IsUniqueIndex(pIndex) ){
- int j2 = sqlite3VdbeCurrentAddr(v) + 3;
- sqlite3VdbeGoto(v, j2);
+ int j2 = sqlite3VdbeGoto(v, 1);
addr2 = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeVerifyAbortable(v, OE_Abort);
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
pIndex->nKeyCol); VdbeCoverage(v);
sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
- }else{
+ sqlite3VdbeJumpHere(v, j2);
+ }else{
+ /* Most CREATE INDEX and REINDEX statements that are not UNIQUE can not
+ ** abort. The exception is if one of the indexed expressions contains a
+ ** user function that throws an exception when it is evaluated. But the
+ ** overhead of adding a statement journal to a CREATE INDEX statement is
+ ** very small (since most of the pages written do not contain content that
+ ** needs to be restored if the statement aborts), so we call
+ ** sqlite3MayAbort() for all CREATE INDEX statements. */
+ sqlite3MayAbort(pParse);
addr2 = sqlite3VdbeCurrentAddr(v);
}
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
- sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
+ if( !pIndex->bAscKeyBug ){
+ /* This OP_SeekEnd opcode makes index insert for a REINDEX go much
+ ** faster by avoiding unnecessary seeks. But the optimization does
+ ** not work for UNIQUE constraint indexes on WITHOUT ROWID tables
+ ** with DESC primary keys, since those indexes have there keys in
+ ** a different order from the main table.
+ ** See ticket: https://www.sqlite.org/src/info/bba7b69f9849b5bf
+ */
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iIdx);
+ }
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
@@ -101150,8 +113840,29 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
}
/*
-** Create a new index for an SQL table. pName1.pName2 is the name of the index
-** and pTblList is the name of the table that is to be indexed. Both will
+** If expression list pList contains an expression that was parsed with
+** an explicit "NULLS FIRST" or "NULLS LAST" clause, leave an error in
+** pParse and return non-zero. Otherwise, return zero.
+*/
+SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
+ if( pList ){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ if( pList->a[i].bNulls ){
+ u8 sf = pList->a[i].sortFlags;
+ sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
+ (sf==0 || sf==3) ? "FIRST" : "LAST"
+ );
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+** Create a new index for an SQL table. pName1.pName2 is the name of the index
+** and pTblList is the name of the table that is to be indexed. Both will
** be NULL for a primary key or an index that is created to satisfy a
** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
** as the table to be indexed. pParse->pNewTable is a table that is
@@ -101159,7 +113870,7 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
**
** pList is a list of columns to be indexed. pList will be NULL if this
** is a primary key or unique-constraint on the most recent column added
-** to the table currently under construction.
+** to the table currently under construction.
*/
SQLITE_PRIVATE void sqlite3CreateIndex(
Parse *pParse, /* All information about this parse */
@@ -101200,13 +113911,16 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto exit_create_index;
}
+ if( sqlite3HasExplicitNulls(pParse, pList) ){
+ goto exit_create_index;
+ }
/*
** Find the table that is to be indexed. Return early if not found.
*/
if( pTblName!=0 ){
- /* Use the two-part index name to determine the database
+ /* Use the two-part index name to determine the database
** to search for the table. 'Fix' the table name to this db
** before looking up the table.
*/
@@ -101238,7 +113952,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
assert( db->mallocFailed==0 || pTab==0 );
if( pTab==0 ) goto exit_create_index;
if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"cannot create a TEMP index on non-TEMP table \"%s\"",
pTab->zName);
goto exit_create_index;
@@ -101255,12 +113969,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
assert( pTab!=0 );
assert( pParse->nErr==0 );
- if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
+ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
&& db->init.busy==0
+ && pTblName!=0
#if SQLITE_USER_AUTHENTICATION
&& sqlite3UserAuthTable(pTab->zName)==0
#endif
- && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
+ ){
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
}
@@ -101279,10 +113994,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
/*
** Find the name of the index. Make sure there is not already another
- ** index or table with the same name.
+ ** index or table with the same name.
**
** Exception: If we are reading the names of permanent indices from the
- ** sqlite_master table (because some other process changed the schema) and
+ ** sqlite_schema table (because some other process changed the schema) and
** one of the index names collides with the name of a temporary table or
** index, then we will continue to process this index.
**
@@ -101294,23 +114009,25 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
zName = sqlite3NameFromToken(db, pName);
if( zName==0 ) goto exit_create_index;
assert( pName->z!=0 );
- if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
+ if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName,"index",pTab->zName) ){
goto exit_create_index;
}
- if( !db->init.busy ){
- if( sqlite3FindTable(db, zName, 0)!=0 ){
- sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
- goto exit_create_index;
+ if( !IN_RENAME_OBJECT ){
+ if( !db->init.busy ){
+ if( sqlite3FindTable(db, zName, 0)!=0 ){
+ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
+ goto exit_create_index;
+ }
}
- }
- if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
- if( !ifNotExist ){
- sqlite3ErrorMsg(pParse, "index %s already exists", zName);
- }else{
- assert( !db->init.busy );
- sqlite3CodeVerifySchema(pParse, iDb);
+ if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
+ if( !ifNotExist ){
+ sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ }else{
+ assert( !db->init.busy );
+ sqlite3CodeVerifySchema(pParse, iDb);
+ }
+ goto exit_create_index;
}
- goto exit_create_index;
}
}else{
int n;
@@ -101326,13 +114043,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
** The following statement converts "sqlite3_autoindex..." into
** "sqlite3_butoindex..." in order to make the names distinct.
** The "vtab_err.test" test demonstrates the need of this statement. */
- if( IN_DECLARE_VTAB ) zName[7]++;
+ if( IN_SPECIAL_PARSE ) zName[7]++;
}
/* Check for authorization to create an index.
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
- {
+ if( !IN_RENAME_OBJECT ){
const char *zDb = pDb->zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
goto exit_create_index;
@@ -101351,14 +114068,17 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
*/
if( pList==0 ){
Token prevCol;
- sqlite3TokenInit(&prevCol, pTab->aCol[pTab->nCol-1].zName);
+ Column *pCol = &pTab->aCol[pTab->nCol-1];
+ pCol->colFlags |= COLFLAG_UNIQUE;
+ sqlite3TokenInit(&prevCol, pCol->zName);
pList = sqlite3ExprListAppend(pParse, 0,
sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
if( pList==0 ) goto exit_create_index;
assert( pList->nExpr==1 );
- sqlite3ExprListSetSortOrder(pList, sortOrder);
+ sqlite3ExprListSetSortOrder(pList, sortOrder, SQLITE_SO_UNDEFINED);
}else{
sqlite3ExprListCheckLength(pParse, pList, "index");
+ if( pParse->nErr ) goto exit_create_index;
}
/* Figure out how many bytes of space are required to store explicitly
@@ -101372,11 +114092,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
}
}
- /*
- ** Allocate the index structure.
+ /*
+ ** Allocate the index structure.
*/
nName = sqlite3Strlen30(zName);
nExtraCol = pPk ? pPk->nKeyCol : 1;
+ assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ );
pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol,
nName + nExtra + 1, &zExtra);
if( db->mallocFailed ){
@@ -101417,7 +114138,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
** TODO: Issue a warning if the table primary key is used as part of the
** index key.
*/
- for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
+ pListItem = pList->a;
+ if( IN_RENAME_OBJECT ){
+ pIndex->aColExpr = pList;
+ pList = 0;
+ }
+ for(i=0; i<pIndex->nKeyCol; i++, pListItem++){
Expr *pCExpr; /* The i-th index expression */
int requestedSortOrder; /* ASC or DESC on the i-th expression */
const char *zColl; /* Collation sequence name */
@@ -101433,12 +114159,8 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
goto exit_create_index;
}
if( pIndex->aColExpr==0 ){
- ExprList *pCopy = sqlite3ExprListDup(db, pList, 0);
- pIndex->aColExpr = pCopy;
- if( !db->mallocFailed ){
- assert( pCopy!=0 );
- pListItem = &pCopy->a[i];
- }
+ pIndex->aColExpr = pList;
+ pList = 0;
}
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
@@ -101448,8 +114170,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
assert( j<=0x7fff );
if( j<0 ){
j = pTab->iPKey;
- }else if( pTab->aCol[j].notNull==0 ){
- pIndex->uniqNotNull = 0;
+ }else{
+ if( pTab->aCol[j].notNull==0 ){
+ pIndex->uniqNotNull = 0;
+ }
+ if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
+ pIndex->bHasVCol = 1;
+ }
}
pIndex->aiColumn[i] = (i16)j;
}
@@ -101471,7 +114198,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
goto exit_create_index;
}
pIndex->azColl[i] = zColl;
- requestedSortOrder = pListItem->sortOrder & sortOrderMask;
+ requestedSortOrder = pListItem->sortFlags & sortOrderMask;
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
}
@@ -101483,9 +114210,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
for(j=0; j<pPk->nKeyCol; j++){
int x = pPk->aiColumn[j];
assert( x>=0 );
- if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
- pIndex->nColumn--;
+ if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){
+ pIndex->nColumn--;
}else{
+ testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) );
pIndex->aiColumn[i] = x;
pIndex->azColl[i] = pPk->azColl[j];
pIndex->aSortOrder[i] = pPk->aSortOrder[j];
@@ -101502,13 +114230,14 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
/* If this index contains every column of its table, then mark
** it as a covering index */
- assert( HasRowid(pTab)
- || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
+ assert( HasRowid(pTab)
+ || pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 );
+ recomputeColumnsNotIndexed(pIndex);
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
pIndex->isCovering = 1;
for(j=0; j<pTab->nCol; j++){
if( j==pTab->iPKey ) continue;
- if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
+ if( sqlite3TableColumnToIndex(pIndex,j)>=0 ) continue;
pIndex->isCovering = 0;
break;
}
@@ -101557,13 +114286,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
if( pIdx->onError!=pIndex->onError ){
/* This constraint creates the same index as a previous
** constraint specified somewhere in the CREATE TABLE statement.
- ** However the ON CONFLICT clauses are different. If both this
+ ** However the ON CONFLICT clauses are different. If both this
** constraint and the previous equivalent constraint have explicit
** ON CONFLICT clauses this is an error. Otherwise, use the
** explicitly specified behavior for the index.
*/
if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"conflicting ON CONFLICT clauses specified", 0);
}
if( pIdx->onError==OE_Default ){
@@ -101571,130 +114300,147 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
}
}
if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType;
+ if( IN_RENAME_OBJECT ){
+ pIndex->pNext = pParse->pNewIndex;
+ pParse->pNewIndex = pIndex;
+ pIndex = 0;
+ }
goto exit_create_index;
}
}
}
- /* Link the new Index structure to its table and to the other
- ** in-memory database structures.
- */
- assert( pParse->nErr==0 );
- if( db->init.busy ){
- Index *p;
- assert( !IN_DECLARE_VTAB );
- assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
- p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
- pIndex->zName, pIndex);
- if( p ){
- assert( p==pIndex ); /* Malloc must have failed */
- sqlite3OomFault(db);
- goto exit_create_index;
- }
- db->flags |= SQLITE_InternChanges;
- if( pTblName!=0 ){
- pIndex->tnum = db->init.newTnum;
- }
- }
-
- /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
- ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
- ** emit code to allocate the index rootpage on disk and make an entry for
- ** the index in the sqlite_master table and populate the index with
- ** content. But, do not do this if we are simply reading the sqlite_master
- ** table to parse the schema, or if this index is the PRIMARY KEY index
- ** of a WITHOUT ROWID table.
- **
- ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY
- ** or UNIQUE index in a CREATE TABLE statement. Since the table
- ** has just been created, it contains no data and the index initialization
- ** step can be skipped.
- */
- else if( HasRowid(pTab) || pTblName!=0 ){
- Vdbe *v;
- char *zStmt;
- int iMem = ++pParse->nMem;
-
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto exit_create_index;
-
- sqlite3BeginWriteOperation(pParse, 1, iDb);
+ if( !IN_RENAME_OBJECT ){
- /* Create the rootpage for the index using CreateIndex. But before
- ** doing so, code a Noop instruction and store its address in
- ** Index.tnum. This is required in case this index is actually a
- ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
- ** that case the convertToWithoutRowidTable() routine will replace
- ** the Noop with a Goto to jump over the VDBE code generated below. */
- pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
- sqlite3VdbeAddOp2(v, OP_CreateIndex, iDb, iMem);
-
- /* Gather the complete text of the CREATE INDEX statement into
- ** the zStmt variable
+ /* Link the new Index structure to its table and to the other
+ ** in-memory database structures.
*/
- if( pStart ){
- int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
- if( pName->z[n-1]==';' ) n--;
- /* A named index with an explicit CREATE INDEX statement */
- zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
- onError==OE_None ? "" : " UNIQUE", n, pName->z);
- }else{
- /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
- /* zStmt = sqlite3MPrintf(""); */
- zStmt = 0;
+ assert( pParse->nErr==0 );
+ if( db->init.busy ){
+ Index *p;
+ assert( !IN_SPECIAL_PARSE );
+ assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
+ if( pTblName!=0 ){
+ pIndex->tnum = db->init.newTnum;
+ if( sqlite3IndexHasDuplicateRootPage(pIndex) ){
+ sqlite3ErrorMsg(pParse, "invalid rootpage");
+ pParse->rc = SQLITE_CORRUPT_BKPT;
+ goto exit_create_index;
+ }
+ }
+ p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
+ pIndex->zName, pIndex);
+ if( p ){
+ assert( p==pIndex ); /* Malloc must have failed */
+ sqlite3OomFault(db);
+ goto exit_create_index;
+ }
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
- /* Add an entry in sqlite_master for this index
+ /* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
+ ** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
+ ** emit code to allocate the index rootpage on disk and make an entry for
+ ** the index in the sqlite_schema table and populate the index with
+ ** content. But, do not do this if we are simply reading the sqlite_schema
+ ** table to parse the schema, or if this index is the PRIMARY KEY index
+ ** of a WITHOUT ROWID table.
+ **
+ ** If pTblName==0 it means this index is generated as an implied PRIMARY KEY
+ ** or UNIQUE index in a CREATE TABLE statement. Since the table
+ ** has just been created, it contains no data and the index initialization
+ ** step can be skipped.
*/
- sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
- db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb),
- pIndex->zName,
- pTab->zName,
- iMem,
- zStmt
- );
- sqlite3DbFree(db, zStmt);
+ else if( HasRowid(pTab) || pTblName!=0 ){
+ Vdbe *v;
+ char *zStmt;
+ int iMem = ++pParse->nMem;
- /* Fill the index with data and reparse the schema. Code an OP_Expire
- ** to invalidate all pre-compiled statements.
- */
- if( pTblName ){
- sqlite3RefillIndex(pParse, pIndex, iMem);
- sqlite3ChangeCookie(pParse, iDb);
- sqlite3VdbeAddParseSchemaOp(v, iDb,
- sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
- sqlite3VdbeAddOp0(v, OP_Expire);
- }
+ v = sqlite3GetVdbe(pParse);
+ if( v==0 ) goto exit_create_index;
- sqlite3VdbeJumpHere(v, pIndex->tnum);
- }
+ sqlite3BeginWriteOperation(pParse, 1, iDb);
- /* When adding an index to the list of indices for a table, make
- ** sure all indices labeled OE_Replace come after all those labeled
- ** OE_Ignore. This is necessary for the correct constraint check
- ** processing (in sqlite3GenerateConstraintChecks()) as part of
- ** UPDATE and INSERT statements.
- */
- if( db->init.busy || pTblName==0 ){
- if( onError!=OE_Replace || pTab->pIndex==0
- || pTab->pIndex->onError==OE_Replace){
- pIndex->pNext = pTab->pIndex;
- pTab->pIndex = pIndex;
- }else{
- Index *pOther = pTab->pIndex;
- while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){
- pOther = pOther->pNext;
+ /* Create the rootpage for the index using CreateIndex. But before
+ ** doing so, code a Noop instruction and store its address in
+ ** Index.tnum. This is required in case this index is actually a
+ ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
+ ** that case the convertToWithoutRowidTable() routine will replace
+ ** the Noop with a Goto to jump over the VDBE code generated below. */
+ pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop);
+ sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
+
+ /* Gather the complete text of the CREATE INDEX statement into
+ ** the zStmt variable
+ */
+ assert( pName!=0 || pStart==0 );
+ if( pStart ){
+ int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
+ if( pName->z[n-1]==';' ) n--;
+ /* A named index with an explicit CREATE INDEX statement */
+ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
+ onError==OE_None ? "" : " UNIQUE", n, pName->z);
+ }else{
+ /* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
+ /* zStmt = sqlite3MPrintf(""); */
+ zStmt = 0;
+ }
+
+ /* Add an entry in sqlite_schema for this index
+ */
+ sqlite3NestedParse(pParse,
+ "INSERT INTO %Q." DFLT_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);",
+ db->aDb[iDb].zDbSName,
+ pIndex->zName,
+ pTab->zName,
+ iMem,
+ zStmt
+ );
+ sqlite3DbFree(db, zStmt);
+
+ /* Fill the index with data and reparse the schema. Code an OP_Expire
+ ** to invalidate all pre-compiled statements.
+ */
+ if( pTblName ){
+ sqlite3RefillIndex(pParse, pIndex, iMem);
+ sqlite3ChangeCookie(pParse, iDb);
+ sqlite3VdbeAddParseSchemaOp(v, iDb,
+ sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
+ sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
}
- pIndex->pNext = pOther->pNext;
- pOther->pNext = pIndex;
+
+ sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
}
+ }
+ if( db->init.busy || pTblName==0 ){
+ pIndex->pNext = pTab->pIndex;
+ pTab->pIndex = pIndex;
+ pIndex = 0;
+ }
+ else if( IN_RENAME_OBJECT ){
+ assert( pParse->pNewIndex==0 );
+ pParse->pNewIndex = pIndex;
pIndex = 0;
}
/* Clean up before exiting */
exit_create_index:
- if( pIndex ) freeIndex(db, pIndex);
+ if( pIndex ) sqlite3FreeIndex(db, pIndex);
+ if( pTab ){ /* Ensure all REPLACE indexes are at the end of the list */
+ Index **ppFrom = &pTab->pIndex;
+ Index *pThis;
+ for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
+ Index *pNext;
+ if( pThis->onError!=OE_Replace ) continue;
+ while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){
+ *ppFrom = pNext;
+ pThis->pNext = pNext->pNext;
+ pNext->pNext = pThis;
+ ppFrom = &pNext->pNext;
+ }
+ break;
+ }
+ }
sqlite3ExprDelete(db, pPIWhere);
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);
@@ -101720,18 +114466,33 @@ exit_create_index:
** are based on typical values found in actual indices.
*/
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
- /* 10, 9, 8, 7, 6 */
- LogEst aVal[] = { 33, 32, 30, 28, 26 };
+ /* 10, 9, 8, 7, 6 */
+ static const LogEst aVal[] = { 33, 32, 30, 28, 26 };
LogEst *a = pIdx->aiRowLogEst;
+ LogEst x;
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
int i;
- /* Set the first entry (number of rows in the index) to the estimated
+ /* Indexes with default row estimates should not have stat1 data */
+ assert( !pIdx->hasStat1 );
+
+ /* Set the first entry (number of rows in the index) to the estimated
** number of rows in the table, or half the number of rows in the table
- ** for a partial index. But do not let the estimate drop below 10. */
- a[0] = pIdx->pTable->nRowLogEst;
- if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
- if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
+ ** for a partial index.
+ **
+ ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
+ ** table but other parts we are having to guess at, then do not let the
+ ** estimated number of rows in the table be less than 1000 (LogEst 99).
+ ** Failure to do this can cause the indexes for which we do not have
+ ** stat1 data to be ignored by the query planner.
+ */
+ x = pIdx->pTable->nRowLogEst;
+ assert( 99==sqlite3LogEst(1000) );
+ if( x<99 ){
+ pIdx->pTable->nRowLogEst = x = 99;
+ }
+ if( pIdx->pPartIdxWhere!=0 ) x -= 10; assert( 10==sqlite3LogEst(2) );
+ a[0] = x;
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
** 6 and each subsequent value (if any) is 5. */
@@ -101794,13 +114555,13 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
}
#endif
- /* Generate code to remove the index and from the master table */
+ /* Generate code to remove the index and from the schema table */
v = sqlite3GetVdbe(pParse);
if( v ){
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
- db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pIndex->zName
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
+ db->aDb[iDb].zDbSName, pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
sqlite3ChangeCookie(pParse, iDb);
@@ -101837,9 +114598,9 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate(
int *pIdx /* Write the index of a new slot here */
){
char *z;
- int n = *pnEntry;
+ sqlite3_int64 n = *pIdx = *pnEntry;
if( (n & (n-1))==0 ){
- int sz = (n==0) ? 1 : 2*n;
+ sqlite3_int64 sz = (n==0) ? 1 : 2*n;
void *pNew = sqlite3DbRealloc(db, pArray, sz*szEntry);
if( pNew==0 ){
*pIdx = -1;
@@ -101849,7 +114610,6 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate(
}
z = (char*)pArray;
memset(&z[n * szEntry], 0, szEntry);
- *pIdx = n;
++*pnEntry;
return pArray;
}
@@ -101860,7 +114620,8 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate(
**
** A new IdList is returned, or NULL if malloc() fails.
*/
-SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
+SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
+ sqlite3 *db = pParse->db;
int i;
if( pList==0 ){
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
@@ -101878,6 +114639,9 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pT
return 0;
}
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
+ if( IN_RENAME_OBJECT && pList->a[i].zName ){
+ sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
+ }
return pList;
}
@@ -101891,7 +114655,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
sqlite3DbFree(db, pList->a[i].zName);
}
sqlite3DbFree(db, pList->a);
- sqlite3DbFree(db, pList);
+ sqlite3DbFreeNN(db, pList);
}
/*
@@ -101908,6 +114672,18 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){
}
/*
+** Maximum size of a SrcList object.
+** The SrcList object is used to represent the FROM clause of a
+** SELECT statement, and the query planner cannot deal with more
+** than 64 tables in a join. So any value larger than 64 here
+** is sufficient for most uses. Smaller values, like say 10, are
+** appropriate for small and memory-limited applications.
+*/
+#ifndef SQLITE_MAX_SRCLIST
+# define SQLITE_MAX_SRCLIST 200
+#endif
+
+/*
** Expand the space allocated for the given SrcList object by
** creating nExtra new slots beginning at iStart. iStart is zero based.
** New slots are zeroed.
@@ -101923,11 +114699,12 @@ SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){
** the iStart value would be 0. The result then would
** be: nil, nil, nil, A, B.
**
-** If a memory allocation fails the SrcList is unchanged. The
-** db->mallocFailed flag will be set to true.
+** If a memory allocation fails or the SrcList becomes too large, leave
+** the original SrcList unchanged, return NULL, and leave an error message
+** in pParse.
*/
SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
- sqlite3 *db, /* Database connection to notify of OOM errors */
+ Parse *pParse, /* Parsing context into which errors are reported */
SrcList *pSrc, /* The SrcList to be enlarged */
int nExtra, /* Number of new slots to add to pSrc->a[] */
int iStart /* Index in pSrc->a[] of first new slot */
@@ -101943,17 +114720,23 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
/* Allocate additional space if needed */
if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
SrcList *pNew;
- int nAlloc = pSrc->nSrc+nExtra;
- int nGot;
+ sqlite3_int64 nAlloc = 2*(sqlite3_int64)pSrc->nSrc+nExtra;
+ sqlite3 *db = pParse->db;
+
+ if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){
+ sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d",
+ SQLITE_MAX_SRCLIST);
+ return 0;
+ }
+ if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
pNew = sqlite3DbRealloc(db, pSrc,
sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
if( pNew==0 ){
assert( db->mallocFailed );
- return pSrc;
+ return 0;
}
pSrc = pNew;
- nGot = (sqlite3DbMallocSize(db, pNew) - sizeof(*pSrc))/sizeof(pSrc->a[0])+1;
- pSrc->nAlloc = nGot;
+ pSrc->nAlloc = nAlloc;
}
/* Move existing slots that come after the newly inserted slots
@@ -101978,7 +114761,8 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
** Append a new table name to the given SrcList. Create a new SrcList if
** need be. A new entry is created in the SrcList even if pTable is NULL.
**
-** A SrcList is returned, or NULL if there is an OOM error. The returned
+** A SrcList is returned, or NULL if there is an OOM error or if the
+** SrcList grows to large. The returned
** SrcList might be the same as the SrcList that was input or it might be
** a new one. If an OOM error does occurs, then the prior value of pList
** that is input to this routine is automatically freed.
@@ -101987,7 +114771,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
** database name prefix. Like this: "database.table". The pDatabase
** points to the table name and the pTable points to the database name.
** The SrcList.a[].zName field is filled with the table name which might
-** come from pTable (if pDatabase is NULL) or from pDatabase.
+** come from pTable (if pDatabase is NULL) or from pDatabase.
** SrcList.a[].zDatabase is filled with the database name from pTable,
** or with NULL if no database is specified.
**
@@ -102009,36 +114793,44 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
** before being added to the SrcList.
*/
SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
- sqlite3 *db, /* Connection to notify of malloc failures */
+ Parse *pParse, /* Parsing context, in which errors are reported */
SrcList *pList, /* Append to this SrcList. NULL creates a new SrcList */
Token *pTable, /* Table to append */
Token *pDatabase /* Database of the table */
){
struct SrcList_item *pItem;
+ sqlite3 *db;
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
- assert( db!=0 );
+ assert( pParse!=0 );
+ assert( pParse->db!=0 );
+ db = pParse->db;
if( pList==0 ){
- pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
+ pList = sqlite3DbMallocRawNN(pParse->db, sizeof(SrcList) );
if( pList==0 ) return 0;
pList->nAlloc = 1;
- pList->nSrc = 0;
- }
- pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
- if( db->mallocFailed ){
- sqlite3SrcListDelete(db, pList);
- return 0;
+ pList->nSrc = 1;
+ memset(&pList->a[0], 0, sizeof(pList->a[0]));
+ pList->a[0].iCursor = -1;
+ }else{
+ SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc);
+ if( pNew==0 ){
+ sqlite3SrcListDelete(db, pList);
+ return 0;
+ }else{
+ pList = pNew;
+ }
}
pItem = &pList->a[pList->nSrc-1];
if( pDatabase && pDatabase->z==0 ){
pDatabase = 0;
}
if( pDatabase ){
- Token *pTemp = pDatabase;
- pDatabase = pTable;
- pTable = pTemp;
+ pItem->zName = sqlite3NameFromToken(db, pDatabase);
+ pItem->zDatabase = sqlite3NameFromToken(db, pTable);
+ }else{
+ pItem->zName = sqlite3NameFromToken(db, pTable);
+ pItem->zDatabase = 0;
}
- pItem->zName = sqlite3NameFromToken(db, pTable);
- pItem->zDatabase = sqlite3NameFromToken(db, pDatabase);
return pList;
}
@@ -102078,7 +114870,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
sqlite3ExprDelete(db, pItem->pOn);
sqlite3IdListDelete(db, pItem->pUsing);
}
- sqlite3DbFree(db, pList);
+ sqlite3DbFreeNN(db, pList);
}
/*
@@ -102110,16 +114902,23 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
struct SrcList_item *pItem;
sqlite3 *db = pParse->db;
if( !p && (pOn || pUsing) ){
- sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
+ sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
(pOn ? "ON" : "USING")
);
goto append_from_error;
}
- p = sqlite3SrcListAppend(db, p, pTable, pDatabase);
- if( p==0 || NEVER(p->nSrc==0) ){
+ p = sqlite3SrcListAppend(pParse, p, pTable, pDatabase);
+ if( p==0 ){
goto append_from_error;
}
+ assert( p->nSrc>0 );
pItem = &p->a[p->nSrc-1];
+ assert( (pTable==0)==(pDatabase==0) );
+ assert( pItem->zName==0 || pDatabase!=0 );
+ if( IN_RENAME_OBJECT && pItem->zName ){
+ Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable;
+ sqlite3RenameTokenMap(pParse, pItem->zName, pToken);
+ }
assert( pAlias!=0 );
if( pAlias->n ){
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
@@ -102138,25 +114937,47 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
}
/*
-** Add an INDEXED BY or NOT INDEXED clause to the most recently added
+** Add an INDEXED BY or NOT INDEXED clause to the most recently added
** element of the source-list passed as the second argument.
*/
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
assert( pIndexedBy!=0 );
- if( p && ALWAYS(p->nSrc>0) ){
- struct SrcList_item *pItem = &p->a[p->nSrc-1];
+ if( p && pIndexedBy->n>0 ){
+ struct SrcList_item *pItem;
+ assert( p->nSrc>0 );
+ pItem = &p->a[p->nSrc-1];
assert( pItem->fg.notIndexed==0 );
assert( pItem->fg.isIndexedBy==0 );
assert( pItem->fg.isTabFunc==0 );
if( pIndexedBy->n==1 && !pIndexedBy->z ){
- /* A "NOT INDEXED" clause was supplied. See parse.y
+ /* A "NOT INDEXED" clause was supplied. See parse.y
** construct "indexed_opt" for details. */
pItem->fg.notIndexed = 1;
}else{
pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
- pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
+ pItem->fg.isIndexedBy = 1;
+ }
+ }
+}
+
+/*
+** Append the contents of SrcList p2 to SrcList p1 and return the resulting
+** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2
+** are deleted by this function.
+*/
+SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
+ assert( p1 && p1->nSrc==1 );
+ if( p2 ){
+ SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1);
+ if( pNew==0 ){
+ sqlite3SrcListDelete(pParse->db, p2);
+ }else{
+ p1 = pNew;
+ memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(struct SrcList_item));
+ sqlite3DbFree(pParse->db, p2);
}
}
+ return p1;
}
/*
@@ -102227,42 +115048,31 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
}
/*
-** Generate VDBE code for a COMMIT statement.
-*/
-SQLITE_PRIVATE void sqlite3CommitTransaction(Parse *pParse){
- Vdbe *v;
-
- assert( pParse!=0 );
- assert( pParse->db!=0 );
- if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ){
- return;
- }
- v = sqlite3GetVdbe(pParse);
- if( v ){
- sqlite3VdbeAddOp1(v, OP_AutoCommit, 1);
- }
-}
-
-/*
-** Generate VDBE code for a ROLLBACK statement.
+** Generate VDBE code for a COMMIT or ROLLBACK statement.
+** Code for ROLLBACK is generated if eType==TK_ROLLBACK. Otherwise
+** code is generated for a COMMIT.
*/
-SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse *pParse){
+SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){
Vdbe *v;
+ int isRollback;
assert( pParse!=0 );
assert( pParse->db!=0 );
- if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ){
+ assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK );
+ isRollback = eType==TK_ROLLBACK;
+ if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION,
+ isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){
return;
}
v = sqlite3GetVdbe(pParse);
if( v ){
- sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, 1);
+ sqlite3VdbeAddOp2(v, OP_AutoCommit, 1, isRollback);
}
}
/*
** This function is called by the parser when it parses a command to create,
-** release or rollback an SQL savepoint.
+** release or rollback an SQL savepoint.
*/
SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){
char *zName = sqlite3NameFromToken(pParse->db, pName);
@@ -102289,7 +115099,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
if( db->aDb[1].pBt==0 && !pParse->explain ){
int rc;
Btree *pBt;
- static const int flags =
+ static const int flags =
SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE |
SQLITE_OPEN_EXCLUSIVE |
@@ -102305,7 +115115,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
}
db->aDb[1].pBt = pBt;
assert( db->aDb[1].pSchema );
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
sqlite3OomFault(db);
return 1;
}
@@ -102335,7 +115145,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
}
/*
-** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
+** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
** attached database. Otherwise, invoke it for the database named zDb only.
*/
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
@@ -102381,9 +115191,9 @@ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){
pToplevel->isMultiWrite = 1;
}
-/*
+/*
** The code generator calls this routine if is discovers that it is
-** possible to abort a statement prior to completion. In order to
+** possible to abort a statement prior to completion. In order to
** perform this abort without corrupting the database, we need to make
** sure that the statement is protected by a statement transaction.
**
@@ -102392,7 +115202,7 @@ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){
** such that the abort must occur after the multiwrite. This makes
** some statements involving the REPLACE conflict resolution algorithm
** go a little faster. But taking advantage of this time dependency
-** makes it more difficult to prove that the code is correct (in
+** makes it more difficult to prove that the code is correct (in
** particular, it prevents us from writing an effective
** implementation of sqlite3AssertMayAbort()) and so we have chosen
** to take the safe route and skip the optimization.
@@ -102416,7 +115226,7 @@ SQLITE_PRIVATE void sqlite3HaltConstraint(
u8 p5Errmsg /* P5_ErrMsg type */
){
Vdbe *v = sqlite3GetVdbe(pParse);
- assert( (errCode&0xff)==SQLITE_CONSTRAINT );
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
if( onError==OE_Abort ){
sqlite3MayAbort(pParse);
}
@@ -102437,21 +115247,24 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
StrAccum errMsg;
Table *pTab = pIdx->pTable;
- sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
+ sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0,
+ pParse->db->aLimit[SQLITE_LIMIT_LENGTH]);
if( pIdx->aColExpr ){
- sqlite3XPrintf(&errMsg, "index '%q'", pIdx->zName);
+ sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName);
}else{
for(j=0; j<pIdx->nKeyCol; j++){
char *zCol;
assert( pIdx->aiColumn[j]>=0 );
zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
- if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
- sqlite3XPrintf(&errMsg, "%s.%s", pTab->zName, zCol);
+ if( j ) sqlite3_str_append(&errMsg, ", ", 2);
+ sqlite3_str_appendall(&errMsg, pTab->zName);
+ sqlite3_str_append(&errMsg, ".", 1);
+ sqlite3_str_appendall(&errMsg, zCol);
}
}
zErr = sqlite3StrAccumFinish(&errMsg);
- sqlite3HaltConstraint(pParse,
- IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
+ sqlite3HaltConstraint(pParse,
+ IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
: SQLITE_CONSTRAINT_UNIQUE,
onError, zErr, P4_DYNAMIC, P5_ConstraintUnique);
}
@@ -102463,7 +115276,7 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
SQLITE_PRIVATE void sqlite3RowidConstraint(
Parse *pParse, /* Parsing context */
int onError, /* Conflict resolution algorithm */
- Table *pTab /* The table with the non-unique rowid */
+ Table *pTab /* The table with the non-unique rowid */
){
char *zMsg;
int rc;
@@ -102504,13 +115317,15 @@ static int collationMatch(const char *zColl, Index *pIndex){
*/
#ifndef SQLITE_OMIT_REINDEX
static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){
- Index *pIndex; /* An index associated with pTab */
+ if( !IsVirtual(pTab) ){
+ Index *pIndex; /* An index associated with pTab */
- for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
- if( zColl==0 || collationMatch(zColl, pIndex) ){
- int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
- sqlite3BeginWriteOperation(pParse, 0, iDb);
- sqlite3RefillIndex(pParse, pIndex, -1);
+ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){
+ if( zColl==0 || collationMatch(zColl, pIndex) ){
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ sqlite3BeginWriteOperation(pParse, 0, iDb);
+ sqlite3RefillIndex(pParse, pIndex, -1);
+ }
}
}
}
@@ -102631,9 +115446,22 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
const char *zColl = pIdx->azColl[i];
pKey->aColl[i] = zColl==sqlite3StrBINARY ? 0 :
sqlite3LocateCollSeq(pParse, zColl);
- pKey->aSortOrder[i] = pIdx->aSortOrder[i];
+ pKey->aSortFlags[i] = pIdx->aSortOrder[i];
+ assert( 0==(pKey->aSortFlags[i] & KEYINFO_ORDER_BIGNULL) );
}
if( pParse->nErr ){
+ assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );
+ if( pIdx->bNoQuery==0 ){
+ /* Deactivate the index because it contains an unknown collating
+ ** sequence. The only way to reactive the index is to reload the
+ ** schema. Adding the missing collating sequence later does not
+ ** reactive the index. The application had the chance to register
+ ** the missing index using the collation-needed callback. For
+ ** simplicity, SQLite will not give the application a second chance.
+ */
+ pIdx->bNoQuery = 1;
+ pParse->rc = SQLITE_ERROR_RETRY;
+ }
sqlite3KeyInfoUnref(pKey);
pKey = 0;
}
@@ -102642,9 +115470,9 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
}
#ifndef SQLITE_OMIT_CTE
-/*
-** This routine is invoked once per CTE by the parser while parsing a
-** WITH clause.
+/*
+** This routine is invoked once per CTE by the parser while parsing a
+** WITH clause.
*/
SQLITE_PRIVATE With *sqlite3WithAdd(
Parse *pParse, /* Parsing context */
@@ -102670,7 +115498,7 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
}
if( pWith ){
- int nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
+ sqlite3_int64 nByte = sizeof(*pWith) + (sizeof(pWith->a[1]) * pWith->nCte);
pNew = sqlite3DbRealloc(db, pWith, nByte);
}else{
pNew = sqlite3DbMallocZero(db, sizeof(*pWith));
@@ -102713,7 +115541,7 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){
/************** End of build.c ***********************************************/
/************** Begin file callback.c ****************************************/
/*
-** 2005 May 23
+** 2005 May 23
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -102780,62 +115608,18 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
}
/*
-** This function is responsible for invoking the collation factory callback
-** or substituting a collation sequence of a different encoding when the
-** requested collation sequence is not available in the desired encoding.
-**
-** If it is not NULL, then pColl must point to the database native encoding
-** collation sequence with name zName, length nName.
-**
-** The return value is either the collation sequence to be used in database
-** db for collation type name zName, length nName, or NULL, if no collation
-** sequence can be found. If no collation is found, leave an error message.
-**
-** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
-*/
-SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
- Parse *pParse, /* Parsing context */
- u8 enc, /* The desired encoding for the collating sequence */
- CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
- const char *zName /* Collating sequence name */
-){
- CollSeq *p;
- sqlite3 *db = pParse->db;
-
- p = pColl;
- if( !p ){
- p = sqlite3FindCollSeq(db, enc, zName, 0);
- }
- if( !p || !p->xCmp ){
- /* No collation sequence of this type for this encoding is registered.
- ** Call the collation factory to see if it can supply us with one.
- */
- callCollNeeded(db, enc, zName);
- p = sqlite3FindCollSeq(db, enc, zName, 0);
- }
- if( p && !p->xCmp && synthCollSeq(db, p) ){
- p = 0;
- }
- assert( !p || p->xCmp );
- if( p==0 ){
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
- }
- return p;
-}
-
-/*
** This routine is called on a collation sequence before it is used to
** check that it is defined. An undefined collation sequence exists when
** a database is loaded that contains references to collation sequences
** that have not been defined by sqlite3_create_collation() etc.
**
** If required, this routine calls the 'collation needed' callback to
-** request a definition of the collating sequence. If this doesn't work,
+** request a definition of the collating sequence. If this doesn't work,
** an equivalent collating sequence that uses a text encoding different
** from the main database is substituted, if one is available.
*/
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
- if( pColl ){
+ if( pColl && pColl->xCmp==0 ){
const char *zName = pColl->zName;
sqlite3 *db = pParse->db;
CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
@@ -102871,8 +115655,8 @@ static CollSeq *findCollSeqEntry(
pColl = sqlite3HashFind(&db->aCollSeq, zName);
if( 0==pColl && create ){
- int nName = sqlite3Strlen30(zName);
- pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName + 1);
+ int nName = sqlite3Strlen30(zName) + 1;
+ pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName);
if( pColl ){
CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3];
@@ -102882,10 +115666,9 @@ static CollSeq *findCollSeqEntry(
pColl[2].zName = (char*)&pColl[3];
pColl[2].enc = SQLITE_UTF16BE;
memcpy(pColl[0].zName, zName, nName);
- pColl[0].zName[nName] = 0;
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
- /* If a malloc() failure occurred in sqlite3HashInsert(), it will
+ /* If a malloc() failure occurred in sqlite3HashInsert(), it will
** return the pColl pointer to be deleted (because it wasn't added
** to the hash table).
*/
@@ -102916,20 +115699,112 @@ static CollSeq *findCollSeqEntry(
** See also: sqlite3LocateCollSeq(), sqlite3GetCollSeq()
*/
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
- sqlite3 *db,
- u8 enc,
- const char *zName,
- int create
+ sqlite3 *db, /* Database connection to search */
+ u8 enc, /* Desired text encoding */
+ const char *zName, /* Name of the collating sequence. Might be NULL */
+ int create /* True to create CollSeq if doesn't already exist */
){
CollSeq *pColl;
+ assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
+ assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
if( zName ){
pColl = findCollSeqEntry(db, zName, create);
+ if( pColl ) pColl += enc-1;
}else{
pColl = db->pDfltColl;
}
- assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
- assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
- if( pColl ) pColl += enc-1;
+ return pColl;
+}
+
+/*
+** Change the text encoding for a database connection. This means that
+** the pDfltColl must change as well.
+*/
+SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
+ db->enc = enc;
+ /* EVIDENCE-OF: R-08308-17224 The default collating function for all
+ ** strings is BINARY.
+ */
+ db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
+}
+
+/*
+** This function is responsible for invoking the collation factory callback
+** or substituting a collation sequence of a different encoding when the
+** requested collation sequence is not available in the desired encoding.
+**
+** If it is not NULL, then pColl must point to the database native encoding
+** collation sequence with name zName, length nName.
+**
+** The return value is either the collation sequence to be used in database
+** db for collation type name zName, length nName, or NULL, if no collation
+** sequence can be found. If no collation is found, leave an error message.
+**
+** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
+*/
+SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
+ Parse *pParse, /* Parsing context */
+ u8 enc, /* The desired encoding for the collating sequence */
+ CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
+ const char *zName /* Collating sequence name */
+){
+ CollSeq *p;
+ sqlite3 *db = pParse->db;
+
+ p = pColl;
+ if( !p ){
+ p = sqlite3FindCollSeq(db, enc, zName, 0);
+ }
+ if( !p || !p->xCmp ){
+ /* No collation sequence of this type for this encoding is registered.
+ ** Call the collation factory to see if it can supply us with one.
+ */
+ callCollNeeded(db, enc, zName);
+ p = sqlite3FindCollSeq(db, enc, zName, 0);
+ }
+ if( p && !p->xCmp && synthCollSeq(db, p) ){
+ p = 0;
+ }
+ assert( !p || p->xCmp );
+ if( p==0 ){
+ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
+ pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
+ }
+ return p;
+}
+
+/*
+** This function returns the collation sequence for database native text
+** encoding identified by the string zName.
+**
+** If the requested collation sequence is not available, or not available
+** in the database native encoding, the collation factory is invoked to
+** request it. If the collation factory does not supply such a sequence,
+** and the sequence is available in another text encoding, then that is
+** returned instead.
+**
+** If no versions of the requested collations sequence are available, or
+** another error occurs, NULL is returned and an error message written into
+** pParse.
+**
+** This routine is a wrapper around sqlite3FindCollSeq(). This routine
+** invokes the collation factory if the named collation cannot be found
+** and generates an error message.
+**
+** See also: sqlite3FindCollSeq(), sqlite3GetCollSeq()
+*/
+SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
+ sqlite3 *db = pParse->db;
+ u8 enc = ENC(db);
+ u8 initbusy = db->init.busy;
+ CollSeq *pColl;
+
+ pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
+ if( !initbusy && (!pColl || !pColl->xCmp) ){
+ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
+ }
+
return pColl;
}
@@ -102943,7 +115818,7 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
** is also -1. In other words, we are searching for a function that
** takes a variable number of arguments.
**
-** If nArg is -2 that means that we are searching for any function
+** If nArg is -2 that means that we are searching for any function
** regardless of the number of arguments it uses, so return a positive
** match score for any
**
@@ -102968,12 +115843,13 @@ static int matchQuality(
u8 enc /* Desired text encoding */
){
int match;
-
- /* nArg of -2 is a special case */
- if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ assert( p->nArg>=-1 );
/* Wrong number of arguments means "no match" */
- if( p->nArg!=nArg && p->nArg>=0 ) return 0;
+ if( p->nArg!=nArg ){
+ if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
+ if( p->nArg>=0 ) return 0;
+ }
/* Give a better score to a function with a specific number of arguments
** than to function that accepts any number of arguments. */
@@ -102997,7 +115873,7 @@ static int matchQuality(
** Search a FuncDefHash for a function with the given name. Return
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
-static FuncDef *functionSearch(
+SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(
int h, /* Hash of the name */
const char *zFunc /* Name of function */
){
@@ -103022,8 +115898,9 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
FuncDef *pOther;
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
- int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
- pOther = functionSearch(h, zName);
+ int h = SQLITE_FUNC_HASH(zName[0], nName);
+ assert( zName[0]>='a' && zName[0]<='z' );
+ pOther = sqlite3FunctionSearch(h, zName);
if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
aDef[i].pNext = pOther->pNext;
@@ -103035,8 +115912,8 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
}
}
}
-
-
+
+
/*
** Locate a user function given a name, a number of arguments and a flag
@@ -103088,7 +115965,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
/* If no match is found, search the built-in functions.
**
- ** If the SQLITE_PreferBuiltin flag is set, then search the built-in
+ ** If the DBFLAG_PreferBuiltin flag is set, then search the built-in
** functions even if a prior app-defined function was found. And give
** priority to built-in functions.
**
@@ -103097,11 +115974,11 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** have fields overwritten with new information appropriate for the
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
- */
- if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
+ */
+ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
bestScore = 0;
- h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
- p = functionSearch(h, zName);
+ h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName);
+ p = sqlite3FunctionSearch(h, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -103116,13 +115993,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** exact match for the name, number of arguments and encoding, then add a
** new entry to the hash table and return it.
*/
- if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
+ if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
FuncDef *pOther;
+ u8 *z;
pBest->zName = (const char*)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy((char*)&pBest[1], zName, nName+1);
+ for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z];
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
@@ -103141,7 +116020,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
/*
** Free all resources held by the schema structure. The void* argument points
-** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
+** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
** pointer itself, it just cleans up subsidiary resources (i.e. the contents
** of the schema hash tables).
**
@@ -103171,8 +116050,8 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
- pSchema->schemaFlags &= ~DB_SchemaLoaded;
}
+ pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}
/*
@@ -103221,7 +116100,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
** (as in the FROM clause of a SELECT statement) in this case it contains
** the name of a single table, as one might find in an INSERT, DELETE,
** or UPDATE statement. Look up that table in the symbol table and
-** return a pointer. Set an error message and return NULL if the table
+** return a pointer. Set an error message and return NULL if the table
** name is not found or if any other error occurs.
**
** The following fields are initialized appropriate in pSrc:
@@ -103233,12 +116112,12 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
struct SrcList_item *pItem = pSrc->a;
Table *pTab;
- assert( pItem && pSrc->nSrc==1 );
+ assert( pItem && pSrc->nSrc>=1 );
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
- pTab->nRef++;
+ pTab->nTabRef++;
}
if( sqlite3IndexedByLookup(pParse, pItem) ){
pTab = 0;
@@ -103246,32 +116125,45 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
return pTab;
}
+/* Return true if table pTab is read-only.
+**
+** A table is read-only if any of the following are true:
+**
+** 1) It is a virtual table and no implementation of the xUpdate method
+** has been provided
+**
+** 2) It is a system table (i.e. sqlite_schema), this call is not
+** part of a nested parse and writable_schema pragma has not
+** been specified
+**
+** 3) The table is a shadow table, the database connection is in
+** defensive mode, and the current sqlite3_prepare()
+** is for a top-level SQL statement.
+*/
+static int tabIsReadOnly(Parse *pParse, Table *pTab){
+ sqlite3 *db;
+ if( IsVirtual(pTab) ){
+ return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
+ }
+ if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
+ db = pParse->db;
+ if( (pTab->tabFlags & TF_Readonly)!=0 ){
+ return sqlite3WritableSchema(db)==0 && pParse->nested==0;
+ }
+ assert( pTab->tabFlags & TF_Shadow );
+ return sqlite3ReadOnlyShadowTables(db);
+}
+
/*
** Check to make sure the given table is writable. If it is not
** writable, generate an error message and return 1. If it is
** writable return 0;
*/
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
- /* A table is not writable under the following circumstances:
- **
- ** 1) It is a virtual table and no implementation of the xUpdate method
- ** has been provided, or
- ** 2) It is a system table (i.e. sqlite_master), this call is not
- ** part of a nested parse and writable_schema pragma has not
- ** been specified.
- **
- ** In either case leave an error message in pParse and return non-zero.
- */
- if( ( IsVirtual(pTab)
- && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 )
- || ( (pTab->tabFlags & TF_Readonly)!=0
- && (pParse->db->flags & SQLITE_WriteSchema)==0
- && pParse->nested==0 )
- ){
+ if( tabIsReadOnly(pParse, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
-
#ifndef SQLITE_OMIT_VIEW
if( !viewOk && pTab->pSelect ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
@@ -103292,6 +116184,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
Parse *pParse, /* Parsing context */
Table *pView, /* View definition */
Expr *pWhere, /* Optional WHERE clause to be added */
+ ExprList *pOrderBy, /* Optional ORDER BY clause */
+ Expr *pLimit, /* Optional LIMIT clause */
int iCur /* Cursor number for ephemeral table */
){
SelectDest dest;
@@ -103300,7 +116194,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
sqlite3 *db = pParse->db;
int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
pWhere = sqlite3ExprDup(db, pWhere, 0);
- pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
+ pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
@@ -103308,8 +116202,8 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
}
- pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0,
- SF_IncludeHidden, 0, 0);
+ pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
+ SF_IncludeHidden, pLimit);
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
sqlite3Select(pParse, pSel, &dest);
sqlite3SelectDelete(db, pSel);
@@ -103331,71 +116225,82 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
Expr *pWhere, /* The WHERE clause. May be null */
ExprList *pOrderBy, /* The ORDER BY clause. May be null */
Expr *pLimit, /* The LIMIT clause. May be null */
- Expr *pOffset, /* The OFFSET clause. May be null */
char *zStmtType /* Either DELETE or UPDATE. For err msgs. */
){
- Expr *pWhereRowid = NULL; /* WHERE rowid .. */
+ sqlite3 *db = pParse->db;
+ Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
- Expr *pSelectRowid = NULL; /* SELECT rowid ... */
ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
+ Table *pTab;
/* Check that there isn't an ORDER BY without a LIMIT clause.
*/
- if( pOrderBy && (pLimit == 0) ) {
+ if( pOrderBy && pLimit==0 ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
- goto limit_where_cleanup;
+ sqlite3ExprDelete(pParse->db, pWhere);
+ sqlite3ExprListDelete(pParse->db, pOrderBy);
+ return 0;
}
/* We only need to generate a select expression if there
** is a limit/offset term to enforce.
*/
if( pLimit == 0 ) {
- /* if pLimit is null, pOffset will always be null as well. */
- assert( pOffset == 0 );
return pWhere;
}
- /* Generate a select expression tree to enforce the limit/offset
+ /* Generate a select expression tree to enforce the limit/offset
** term for the DELETE or UPDATE statement. For example:
** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
** becomes:
- ** DELETE FROM table_a WHERE rowid IN (
+ ** DELETE FROM table_a WHERE rowid IN (
** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
** );
*/
- pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
- if( pSelectRowid == 0 ) goto limit_where_cleanup;
- pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
- if( pEList == 0 ) goto limit_where_cleanup;
+ pTab = pSrc->a[0].pTab;
+ if( HasRowid(pTab) ){
+ pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0);
+ pEList = sqlite3ExprListAppend(
+ pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0)
+ );
+ }else{
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ if( pPk->nKeyCol==1 ){
+ const char *zName = pTab->aCol[pPk->aiColumn[0]].zName;
+ pLhs = sqlite3Expr(db, TK_ID, zName);
+ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
+ }else{
+ int i;
+ for(i=0; i<pPk->nKeyCol; i++){
+ Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
+ pEList = sqlite3ExprListAppend(pParse, pEList, p);
+ }
+ pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( pLhs ){
+ pLhs->x.pList = sqlite3ExprListDup(db, pEList, 0);
+ }
+ }
+ }
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
+ pSrc->a[0].pTab = 0;
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
- if( pSelectSrc == 0 ) {
- sqlite3ExprListDelete(pParse->db, pEList);
- goto limit_where_cleanup;
- }
+ pSrc->a[0].pTab = pTab;
+ pSrc->a[0].pIBIndex = 0;
/* generate the SELECT expression tree. */
- pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0,
- pOrderBy,0,pLimit,pOffset);
- if( pSelect == 0 ) return 0;
+ pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
+ pOrderBy,0,pLimit
+ );
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
- pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
- pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0) : 0;
+ pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
-
-limit_where_cleanup:
- sqlite3ExprDelete(pParse->db, pWhere);
- sqlite3ExprListDelete(pParse->db, pOrderBy);
- sqlite3ExprDelete(pParse->db, pLimit);
- sqlite3ExprDelete(pParse->db, pOffset);
- return 0;
}
#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) */
/* && !defined(SQLITE_OMIT_SUBQUERY) */
@@ -103410,7 +116315,9 @@ limit_where_cleanup:
SQLITE_PRIVATE void sqlite3DeleteFrom(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table from which we should delete things */
- Expr *pWhere /* The WHERE clause. May be null */
+ Expr *pWhere, /* The WHERE clause. May be null */
+ ExprList *pOrderBy, /* ORDER BY clause. May be null */
+ Expr *pLimit /* LIMIT clause. May be null */
){
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
@@ -103425,7 +116332,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
AuthContext sContext; /* Authorization context */
NameContext sNC; /* Name context to resolve expressions in */
int iDb; /* Database number */
- int memCnt = -1; /* Memory cell used for change counting */
+ int memCnt = 0; /* Memory cell used for change counting */
int rcauth; /* Value returned by authorization callback */
int eOnePass; /* ONEPASS_OFF or _SINGLE or _MULTI */
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
@@ -103442,7 +116349,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
int bComplex; /* True if there are triggers or FKs or
** subqueries in the WHERE clause */
-
+
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
Trigger *pTrigger; /* List of table triggers, if required */
@@ -103455,6 +116362,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
assert( pTabList->nSrc==1 );
+
/* Locate the table which we want to delete. This table has to be
** put in an SrcList structure because some of the subroutines we
** will be calling are designed to work with multiple tables and expect
@@ -103469,16 +116377,26 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0;
- bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#else
# define pTrigger 0
# define isView 0
#endif
+ bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
#endif
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( !isView ){
+ pWhere = sqlite3LimitWhere(
+ pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE"
+ );
+ pOrderBy = 0;
+ pLimit = 0;
+ }
+#endif
+
/* If pTab is really a view, make sure it has been initialized.
*/
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
@@ -103490,7 +116408,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
- rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
+ rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
db->aDb[iDb].zDbSName);
assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
if( rcauth==SQLITE_DENY ){
@@ -103519,15 +116437,19 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, 1, iDb);
+ sqlite3BeginWriteOperation(pParse, bComplex, iDb);
/* If we are trying to delete from a view, realize that view into
** an ephemeral table.
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
if( isView ){
- sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
+ sqlite3MaterializeView(pParse, pTab,
+ pWhere, pOrderBy, pLimit, iTabCur
+ );
iDataCur = iIdxCur = iTabCur;
+ pOrderBy = 0;
+ pLimit = 0;
}
#endif
@@ -103543,7 +116465,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
/* Initialize the counter of the number of rows deleted, if
** we are counting rows.
*/
- if( db->flags & SQLITE_CountRows ){
+ if( (db->flags & SQLITE_CountRows)!=0
+ && !pParse->nested
+ && !pParse->pTriggerTab
+ ){
memCnt = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
}
@@ -103551,8 +116476,15 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
/* Special case: A DELETE without a WHERE clause deletes everything.
** It is easier just to erase the whole table. Prior to version 3.6.5,
- ** this optimization caused the row change count (the value returned by
- ** API function sqlite3_count_changes) to be set incorrectly. */
+ ** this optimization caused the row change count (the value returned by
+ ** API function sqlite3_count_changes) to be set incorrectly.
+ **
+ ** The "rcauth==SQLITE_OK" terms is the
+ ** IMPLEMENTATION-OF: R-17228-37124 If the action code is SQLITE_DELETE and
+ ** the callback returns SQLITE_IGNORE then the DELETE operation proceeds but
+ ** the truncate optimization is disabled and all rows are deleted
+ ** individually.
+ */
if( rcauth==SQLITE_OK
&& pWhere==0
&& !bComplex
@@ -103564,7 +116496,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
assert( !isView );
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
if( HasRowid(pTab) ){
- sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt,
+ sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt ? memCnt : -1,
pTab->zName, P4_STATIC);
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
@@ -103595,7 +116527,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk);
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
}
-
+
/* Construct a query to find the rowid or primary key for every row
** to be deleted, based on the WHERE clause. Set variable eOnePass
** to indicate the strategy used to implement this delete:
@@ -103609,12 +116541,13 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
-
+ if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse);
+
/* Keep track of the number of rows to be deleted */
- if( db->flags & SQLITE_CountRows ){
+ if( memCnt ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
-
+
/* Extract the rowid or primary key for the current row */
if( pPk ){
for(i=0; i<nPk; i++){
@@ -103624,11 +116557,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
iKey = iPk;
}else{
- iKey = pParse->nMem + 1;
- iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
- if( iKey>pParse->nMem ) pParse->nMem = iKey;
+ iKey = ++pParse->nMem;
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey);
}
-
+
if( eOnePass!=ONEPASS_OFF ){
/* For ONEPASS, no need to store the rowid/primary-key. There is only
** one, so just keep it in its register(s) and fall through to the
@@ -103651,25 +116583,25 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
nKey = 0; /* Zero tells OP_Found to use a composite key */
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
}else{
/* Add the rowid of the row to be deleted to the RowSet */
- nKey = 1; /* OP_Seek always uses a single rowid */
+ nKey = 1; /* OP_DeferredSeek always uses a single rowid */
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
}
}
-
- /* If this DELETE cannot use the ONEPASS strategy, this is the
+
+ /* If this DELETE cannot use the ONEPASS strategy, this is the
** end of the WHERE loop */
if( eOnePass!=ONEPASS_OFF ){
- addrBypass = sqlite3VdbeMakeLabel(v);
+ addrBypass = sqlite3VdbeMakeLabel(pParse);
}else{
sqlite3WhereEnd(pWInfo);
}
-
- /* Unless this is a view, open cursors for the table we are
+
+ /* Unless this is a view, open cursors for the table we are
** deleting from and all its indices. If this is a view, then the
- ** only effect this statement has is to fire the INSTEAD OF
+ ** only effect this statement has is to fire the INSTEAD OF
** triggers.
*/
if( !isView ){
@@ -103682,9 +116614,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
iTabCur, aToOpen, &iDataCur, &iIdxCur);
assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
- if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
+ if( eOnePass==ONEPASS_MULTI ){
+ sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce);
+ }
}
-
+
/* Set up a loop over the rowids/primary-keys that were found in the
** where-clause loop above.
*/
@@ -103697,38 +116631,41 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
}else if( pPk ){
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
+ if( IsVirtual(pTab) ){
+ sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
+ }
assert( nKey==0 ); /* OP_Found will use a composite key */
}else{
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
VdbeCoverage(v);
assert( nKey==1 );
- }
-
+ }
+
/* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
- sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
- sqlite3VdbeChangeP5(v, OE_Abort);
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
sqlite3MayAbort(pParse);
- if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
- pParse->isMultiWrite = 0;
+ if( eOnePass==ONEPASS_SINGLE ){
+ sqlite3VdbeAddOp1(v, OP_Close, iTabCur);
+ if( sqlite3IsToplevel(pParse) ){
+ pParse->isMultiWrite = 0;
+ }
}
+ sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
+ sqlite3VdbeChangeP5(v, OE_Abort);
}else
#endif
{
int count = (pParse->nested==0); /* True to count changes */
- int iIdxNoSeek = -1;
- if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
- iIdxNoSeek = aiCurOnePass[1];
- }
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
+ iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
}
-
+
/* End of the loop over all rowids/primary-keys. */
if( eOnePass!=ONEPASS_OFF ){
sqlite3VdbeResolveLabel(v, addrBypass);
@@ -103739,14 +116676,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}else{
sqlite3VdbeGoto(v, addrLoop);
sqlite3VdbeJumpHere(v, addrLoop);
- }
-
- /* Close the cursors open on the table and its indexes. */
- if( !isView && !IsVirtual(pTab) ){
- if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
- for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
- }
}
} /* End non-truncate path */
@@ -103758,11 +116687,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
sqlite3AutoincrementEnd(pParse);
}
- /* Return the number of rows that were deleted. If this routine is
+ /* Return the number of rows that were deleted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
- if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
+ if( memCnt ){
sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
@@ -103772,6 +116701,10 @@ delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprDelete(db, pWhere);
+#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
+ sqlite3ExprListDelete(db, pOrderBy);
+ sqlite3ExprDelete(db, pLimit);
+#endif
sqlite3DbFree(db, aToOpen);
return;
}
@@ -103813,16 +116746,18 @@ delete_from_cleanup:
** and nPk before reading from it.
**
** If eMode is ONEPASS_MULTI, then this call is being made as part
-** of a ONEPASS delete that affects multiple rows. In this case, if
-** iIdxNoSeek is a valid cursor number (>=0), then its position should
-** be preserved following the delete operation. Or, if iIdxNoSeek is not
-** a valid cursor number, the position of iDataCur should be preserved
-** instead.
+** of a ONEPASS delete that affects multiple rows. In this case, if
+** iIdxNoSeek is a valid cursor number (>=0) and is not the same as
+** iDataCur, then its position should be preserved following the delete
+** operation. Or, if iIdxNoSeek is not a valid cursor number, the
+** position of iDataCur should be preserved instead.
**
** iIdxNoSeek:
-** If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
-** index cursor (from within array of cursors starting at iIdxCur) that
-** already points to the index entry to be deleted.
+** If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur,
+** then it identifies an index cursor (from within array of cursors
+** starting at iIdxCur) that already points to the index entry to be deleted.
+** Except, this optimization is disabled if there are BEFORE triggers since
+** the trigger body might have moved the cursor.
*/
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
Parse *pParse, /* Parsing context */
@@ -103847,17 +116782,17 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)",
iDataCur, iIdxCur, iPk, (int)nPk));
- /* Seek cursor iCur to the row to delete. If this row no longer exists
+ /* Seek cursor iCur to the row to delete. If this row no longer exists
** (this can happen if a trigger program has already deleted it), do
** not attempt to delete it or fire any DELETE triggers. */
- iLabel = sqlite3VdbeMakeLabel(v);
+ iLabel = sqlite3VdbeMakeLabel(pParse);
opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
if( eMode==ONEPASS_OFF ){
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
VdbeCoverageIf(v, opSeek==OP_NotExists);
VdbeCoverageIf(v, opSeek==OP_NotFound);
}
-
+
/* If there are any triggers to fire, allocate a range of registers to
** use for the old.* references in the triggers. */
if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){
@@ -103874,59 +116809,67 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
iOld = pParse->nMem+1;
pParse->nMem += (1 + pTab->nCol);
- /* Populate the OLD.* pseudo-table register array. These values will be
+ /* Populate the OLD.* pseudo-table register array. These values will be
** used by any BEFORE and AFTER triggers that exist. */
sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
for(iCol=0; iCol<pTab->nCol; iCol++){
testcase( mask!=0xffffffff && iCol==31 );
testcase( mask!=0xffffffff && iCol==32 );
if( mask==0xffffffff || (iCol<=31 && (mask & MASKBIT32(iCol))!=0) ){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
+ int kk = sqlite3TableColumnToStorage(pTab, iCol);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+kk+1);
}
}
/* Invoke BEFORE DELETE trigger programs. */
addrStart = sqlite3VdbeCurrentAddr(v);
- sqlite3CodeRowTrigger(pParse, pTrigger,
+ sqlite3CodeRowTrigger(pParse, pTrigger,
TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
);
- /* If any BEFORE triggers were coded, then seek the cursor to the
+ /* If any BEFORE triggers were coded, then seek the cursor to the
** row to be deleted again. It may be that the BEFORE triggers moved
- ** the cursor or of already deleted the row that the cursor was
+ ** the cursor or already deleted the row that the cursor was
** pointing to.
+ **
+ ** Also disable the iIdxNoSeek optimization since the BEFORE trigger
+ ** may have moved that cursor.
*/
if( addrStart<sqlite3VdbeCurrentAddr(v) ){
sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
VdbeCoverageIf(v, opSeek==OP_NotExists);
VdbeCoverageIf(v, opSeek==OP_NotFound);
+ testcase( iIdxNoSeek>=0 );
+ iIdxNoSeek = -1;
}
/* Do FK processing. This call checks that any FK constraints that
- ** refer to this table (i.e. constraints attached to other tables)
+ ** refer to this table (i.e. constraints attached to other tables)
** are not violated by deleting this row. */
sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
}
/* Delete the index and table entries. Skip this step if pTab is really
** a view (in which case the only effect of the DELETE statement is to
- ** fire the INSTEAD OF triggers).
+ ** fire the INSTEAD OF triggers).
**
** If variable 'count' is non-zero, then this OP_Delete instruction should
** invoke the update-hook. The pre-update-hook, on the other hand should
** be invoked unless table pTab is a system table. The difference is that
- ** the update-hook is not invoked for rows removed by REPLACE, but the
+ ** the update-hook is not invoked for rows removed by REPLACE, but the
** pre-update-hook is.
- */
+ */
if( pTab->pSelect==0 ){
u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
- sqlite3VdbeChangeP4(v, -1, (char*)pTab, P4_TABLE);
+ if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){
+ sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
+ }
if( eMode!=ONEPASS_OFF ){
sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
}
- if( iIdxNoSeek>=0 ){
+ if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){
sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
}
if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION;
@@ -103935,16 +116878,16 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
** handle rows (possibly in other tables) that refer via a foreign key
- ** to the row just deleted. */
+ ** to the row just deleted. */
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
- sqlite3CodeRowTrigger(pParse, pTrigger,
+ sqlite3CodeRowTrigger(pParse, pTrigger,
TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
);
/* Jump here if the row had already been deleted before any BEFORE
- ** trigger programs were invoked. Or if a trigger program throws a
+ ** trigger programs were invoked. Or if a trigger program throws a
** RAISE(IGNORE) exception. */
sqlite3VdbeResolveLabel(v, iLabel);
VdbeModuleComment((v, "END: GenRowDel()"));
@@ -103996,6 +116939,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
&iPartIdxLabel, pPrior, r1);
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
+ sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
pPrior = pIdx;
}
@@ -104028,7 +116972,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
** its key into the same sequence of registers and if pPrior and pIdx share
** a column in common, then the register corresponding to that column already
** holds the correct value and the loading of that register is skipped.
-** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK
+** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK
** on a table with multiple indices, and especially with the ROWID or
** PRIMARY KEY columns of the index.
*/
@@ -104049,11 +116993,13 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){
- *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
- pParse->iSelfTab = iDataCur;
- sqlite3ExprCachePush(pParse);
- sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
+ *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse);
+ pParse->iSelfTab = iDataCur + 1;
+ sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL);
+ pParse->iSelfTab = 0;
+ pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02;
+ ** pPartIdxWhere may have corrupted regPrior registers */
}else{
*piPartIdxLabel = 0;
}
@@ -104080,6 +117026,10 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
}
if( regOut ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
+ if( pIdx->pTable->pSelect ){
+ const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx);
+ sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
+ }
}
sqlite3ReleaseTempRange(pParse, regBase, nCol);
return regBase;
@@ -104093,7 +117043,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
if( iLabel ){
sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
- sqlite3ExprCachePop(pParse);
}
}
@@ -104117,6 +117066,9 @@ SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
/* #include "sqliteInt.h" */
/* #include <stdlib.h> */
/* #include <assert.h> */
+#ifndef SQLITE_OMIT_FLOATING_POINT
+/* #include <math.h> */
+#endif
/* #include "vdbeInt.h" */
/*
@@ -104136,6 +117088,8 @@ static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
** iteration of the aggregate loop.
*/
static void sqlite3SkipAccumulatorLoad(sqlite3_context *context){
+ assert( context->isError<=0 );
+ context->isError = -1;
context->skipFlag = 1;
}
@@ -104177,16 +117131,20 @@ static void typeofFunc(
int NotUsed,
sqlite3_value **argv
){
- const char *z = 0;
+ static const char *azType[] = { "integer", "real", "text", "blob", "null" };
+ int i = sqlite3_value_type(argv[0]) - 1;
UNUSED_PARAMETER(NotUsed);
- switch( sqlite3_value_type(argv[0]) ){
- case SQLITE_INTEGER: z = "integer"; break;
- case SQLITE_TEXT: z = "text"; break;
- case SQLITE_FLOAT: z = "real"; break;
- case SQLITE_BLOB: z = "blob"; break;
- default: z = "null"; break;
- }
- sqlite3_result_text(context, z, -1, SQLITE_STATIC);
+ assert( i>=0 && i<ArraySize(azType) );
+ assert( SQLITE_INTEGER==1 );
+ assert( SQLITE_FLOAT==2 );
+ assert( SQLITE_TEXT==3 );
+ assert( SQLITE_BLOB==4 );
+ assert( SQLITE_NULL==5 );
+ /* EVIDENCE-OF: R-01470-60482 The sqlite3_value_type(V) interface returns
+ ** the datatype code for the initial datatype of the sqlite3_value object
+ ** V. The returned value is one of SQLITE_INTEGER, SQLITE_FLOAT,
+ ** SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL. */
+ sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
}
@@ -104198,8 +117156,6 @@ static void lengthFunc(
int argc,
sqlite3_value **argv
){
- int len;
-
assert( argc==1 );
UNUSED_PARAMETER(argc);
switch( sqlite3_value_type(argv[0]) ){
@@ -104211,13 +117167,17 @@ static void lengthFunc(
}
case SQLITE_TEXT: {
const unsigned char *z = sqlite3_value_text(argv[0]);
+ const unsigned char *z0;
+ unsigned char c;
if( z==0 ) return;
- len = 0;
- while( *z ){
- len++;
- SQLITE_SKIP_UTF8(z);
+ z0 = z;
+ while( (c = *z)!=0 ){
+ z++;
+ if( c>=0xc0 ){
+ while( (*z & 0xc0)==0x80 ){ z++; z0++; }
+ }
}
- sqlite3_result_int(context, len);
+ sqlite3_result_int(context, (int)(z-z0));
break;
}
default: {
@@ -104231,7 +117191,7 @@ static void lengthFunc(
** Implementation of the abs() function.
**
** IMP: R-23979-26855 The abs(X) function returns the absolute value of
-** the numeric argument X.
+** the numeric argument X.
*/
static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
assert( argc==1 );
@@ -104248,7 +117208,7 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
return;
}
iVal = -iVal;
- }
+ }
sqlite3_result_int64(context, iVal);
break;
}
@@ -104294,6 +117254,9 @@ static void instrFunc(
int typeHaystack, typeNeedle;
int N = 1;
int isText;
+ unsigned char firstChar;
+ sqlite3_value *pC1 = 0;
+ sqlite3_value *pC2 = 0;
UNUSED_PARAMETER(argc);
typeHaystack = sqlite3_value_type(argv[0]);
@@ -104301,24 +117264,47 @@ static void instrFunc(
if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
nHaystack = sqlite3_value_bytes(argv[0]);
nNeedle = sqlite3_value_bytes(argv[1]);
- if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
- zHaystack = sqlite3_value_blob(argv[0]);
- zNeedle = sqlite3_value_blob(argv[1]);
- isText = 0;
- }else{
- zHaystack = sqlite3_value_text(argv[0]);
- zNeedle = sqlite3_value_text(argv[1]);
- isText = 1;
- }
- while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
- N++;
- do{
- nHaystack--;
- zHaystack++;
- }while( isText && (zHaystack[0]&0xc0)==0x80 );
+ if( nNeedle>0 ){
+ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
+ zHaystack = sqlite3_value_blob(argv[0]);
+ zNeedle = sqlite3_value_blob(argv[1]);
+ isText = 0;
+ }else if( typeHaystack!=SQLITE_BLOB && typeNeedle!=SQLITE_BLOB ){
+ zHaystack = sqlite3_value_text(argv[0]);
+ zNeedle = sqlite3_value_text(argv[1]);
+ isText = 1;
+ }else{
+ pC1 = sqlite3_value_dup(argv[0]);
+ zHaystack = sqlite3_value_text(pC1);
+ if( zHaystack==0 ) goto endInstrOOM;
+ nHaystack = sqlite3_value_bytes(pC1);
+ pC2 = sqlite3_value_dup(argv[1]);
+ zNeedle = sqlite3_value_text(pC2);
+ if( zNeedle==0 ) goto endInstrOOM;
+ nNeedle = sqlite3_value_bytes(pC2);
+ isText = 1;
+ }
+ if( zNeedle==0 || (nHaystack && zHaystack==0) ) goto endInstrOOM;
+ firstChar = zNeedle[0];
+ while( nNeedle<=nHaystack
+ && (zHaystack[0]!=firstChar || memcmp(zHaystack, zNeedle, nNeedle)!=0)
+ ){
+ N++;
+ do{
+ nHaystack--;
+ zHaystack++;
+ }while( isText && (zHaystack[0]&0xc0)==0x80 );
+ }
+ if( nNeedle>nHaystack ) N = 0;
}
- if( nNeedle>nHaystack ) N = 0;
sqlite3_result_int(context, N);
+endInstr:
+ sqlite3_value_free(pC1);
+ sqlite3_value_free(pC2);
+ return;
+endInstrOOM:
+ sqlite3_result_error_nomem(context);
+ goto endInstr;
}
/*
@@ -104341,7 +117327,7 @@ static void printfFunc(
x.apArg = argv+1;
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
str.printfFlags = SQLITE_PRINTF_SQLFUNC;
- sqlite3XPrintf(&str, zFormat, &x);
+ sqlite3_str_appendf(&str, zFormat, &x);
n = str.nChar;
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n,
SQLITE_DYNAMIC);
@@ -104472,10 +117458,10 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
** handle the rounding directly,
** otherwise use printf.
*/
- if( n==0 && r>=0 && r<LARGEST_INT64-1 ){
- r = (double)((sqlite_int64)(r+0.5));
- }else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){
- r = -(double)((sqlite_int64)((-r)+0.5));
+ if( r<-4503599627370496.0 || r>+4503599627370496.0 ){
+ /* The value has no fractional part so there is nothing to round */
+ }else if( n==0 ){
+ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
zBuf = sqlite3_mprintf("%.*f",n,r);
if( zBuf==0 ){
@@ -104567,7 +117553,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
#define noopFunc versionFunc /* Substitute function - never called */
/*
-** Implementation of random(). Return a random integer.
+** Implementation of random(). Return a random integer.
*/
static void randomFunc(
sqlite3_context *context,
@@ -104578,11 +117564,11 @@ static void randomFunc(
UNUSED_PARAMETER2(NotUsed, NotUsed2);
sqlite3_randomness(sizeof(r), &r);
if( r<0 ){
- /* We need to prevent a random number of 0x8000000000000000
+ /* We need to prevent a random number of 0x8000000000000000
** (or -9223372036854775808) since when you do abs() of that
** number of you get the same value back again. To do this
** in a way that is testable, mask the sign bit off of negative
- ** values, resulting in a positive value. Then take the
+ ** values, resulting in a positive value. Then take the
** 2s complement of that positive value. The end result can
** therefore be no less than -9223372036854775807.
*/
@@ -104600,11 +117586,11 @@ static void randomBlob(
int argc,
sqlite3_value **argv
){
- int n;
+ sqlite3_int64 n;
unsigned char *p;
assert( argc==1 );
UNUSED_PARAMETER(argc);
- n = sqlite3_value_int(argv[0]);
+ n = sqlite3_value_int64(argv[0]);
if( n<1 ){
n = 1;
}
@@ -104620,8 +117606,8 @@ static void randomBlob(
** value is the same as the sqlite3_last_insert_rowid() API function.
*/
static void last_insert_rowid(
- sqlite3_context *context,
- int NotUsed,
+ sqlite3_context *context,
+ int NotUsed,
sqlite3_value **NotUsed2
){
sqlite3 *db = sqlite3_context_db_handle(context);
@@ -104697,9 +117683,19 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
-** Compare two UTF-8 strings for equality where the first string can
-** potentially be a "glob" or "like" expression. Return true (1) if they
-** are the same and false (0) if they are different.
+** Possible error returns from patternMatch()
+*/
+#define SQLITE_MATCH 0
+#define SQLITE_NOMATCH 1
+#define SQLITE_NOWILDCARDMATCH 2
+
+/*
+** Compare two UTF-8 strings for equality where the first string is
+** a GLOB or LIKE expression. Return values:
+**
+** SQLITE_MATCH: Match
+** SQLITE_NOMATCH: No match
+** SQLITE_NOWILDCARDMATCH: No match in spite of having * or % wildcards.
**
** Globbing rules:
**
@@ -104719,7 +117715,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
** it the last character in the list.
**
** Like matching rules:
-**
+**
** '%' Matches any sequence of zero or more characters
**
*** '_' Matches any one character
@@ -104742,7 +117738,7 @@ static int patternCompare(
u32 matchAll = pInfo->matchAll; /* "*" or "%" */
u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
const u8 *zEscaped = 0; /* One past the last escaped input char */
-
+
while( (c = Utf8Read(zPattern))!=0 ){
if( c==matchAll ){ /* Match "*" */
/* Skip over multiple "*" characters in the pattern. If there
@@ -104750,30 +117746,31 @@ static int patternCompare(
** single character of the input string for each "?" skipped */
while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
- return 0;
+ return SQLITE_NOWILDCARDMATCH;
}
}
if( c==0 ){
- return 1; /* "*" at the end of the pattern matches */
+ return SQLITE_MATCH; /* "*" at the end of the pattern matches */
}else if( c==matchOther ){
if( pInfo->matchSet==0 ){
c = sqlite3Utf8Read(&zPattern);
- if( c==0 ) return 0;
+ if( c==0 ) return SQLITE_NOWILDCARDMATCH;
}else{
/* "[...]" immediately follows the "*". We have to do a slow
** recursive search in this case, but it is an unusual case. */
assert( matchOther<0x80 ); /* '[' is a single-byte character */
- while( *zString
- && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){
+ while( *zString ){
+ int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther);
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch;
SQLITE_SKIP_UTF8(zString);
}
- return *zString!=0;
+ return SQLITE_NOWILDCARDMATCH;
}
}
/* At this point variable c contains the first character of the
** pattern string past the "*". Search in the input string for the
- ** first matching character and recursively contine the match from
+ ** first matching character and recursively continue the match from
** that point.
**
** For a case-insensitive search, set variable cx to be the same as
@@ -104781,36 +117778,44 @@ static int patternCompare(
** c or cx.
*/
if( c<=0x80 ){
- u32 cx;
+ char zStop[3];
+ int bMatch;
if( noCase ){
- cx = sqlite3Toupper(c);
- c = sqlite3Tolower(c);
+ zStop[0] = sqlite3Toupper(c);
+ zStop[1] = sqlite3Tolower(c);
+ zStop[2] = 0;
}else{
- cx = c;
+ zStop[0] = c;
+ zStop[1] = 0;
}
- while( (c2 = *(zString++))!=0 ){
- if( c2!=c && c2!=cx ) continue;
- if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
+ while(1){
+ zString += strcspn((const char*)zString, zStop);
+ if( zString[0]==0 ) break;
+ zString++;
+ bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch;
}
}else{
+ int bMatch;
while( (c2 = Utf8Read(zString))!=0 ){
if( c2!=c ) continue;
- if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
+ bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch;
}
}
- return 0;
+ return SQLITE_NOWILDCARDMATCH;
}
if( c==matchOther ){
if( pInfo->matchSet==0 ){
c = sqlite3Utf8Read(&zPattern);
- if( c==0 ) return 0;
+ if( c==0 ) return SQLITE_NOMATCH;
zEscaped = zPattern;
}else{
u32 prior_c = 0;
int seen = 0;
int invert = 0;
c = sqlite3Utf8Read(&zString);
- if( c==0 ) return 0;
+ if( c==0 ) return SQLITE_NOMATCH;
c2 = sqlite3Utf8Read(&zPattern);
if( c2=='^' ){
invert = 1;
@@ -104834,7 +117839,7 @@ static int patternCompare(
c2 = sqlite3Utf8Read(&zPattern);
}
if( c2==0 || (seen ^ invert)==0 ){
- return 0;
+ return SQLITE_NOMATCH;
}
continue;
}
@@ -104845,23 +117850,25 @@ static int patternCompare(
continue;
}
if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
- return 0;
+ return SQLITE_NOMATCH;
}
- return *zString==0;
+ return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH;
}
/*
-** The sqlite3_strglob() interface.
+** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and
+** non-zero if there is no match.
*/
SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0;
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
}
/*
-** The sqlite3_strlike() interface.
+** The sqlite3_strlike() interface. Return 0 on a match and non-zero for
+** a miss - like strcmp().
*/
SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0;
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
}
/*
@@ -104887,8 +117894,8 @@ SQLITE_API int sqlite3_like_count = 0;
** the GLOB operator.
*/
static void likeFunc(
- sqlite3_context *context,
- int argc,
+ sqlite3_context *context,
+ int argc,
sqlite3_value **argv
){
const unsigned char *zA, *zB;
@@ -104896,6 +117903,7 @@ static void likeFunc(
int nPat;
sqlite3 *db = sqlite3_context_db_handle(context);
struct compareInfo *pInfo = sqlite3_user_data(context);
+ struct compareInfo backupInfo;
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
@@ -104908,8 +117916,6 @@ static void likeFunc(
return;
}
#endif
- zB = sqlite3_value_text(argv[0]);
- zA = sqlite3_value_text(argv[1]);
/* Limit the length of the LIKE or GLOB pattern to avoid problems
** of deep recursion and N*N behavior in patternCompare().
@@ -104921,8 +117927,6 @@ static void likeFunc(
sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
return;
}
- assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */
-
if( argc==3 ){
/* The escape character string must consist of a single UTF-8 character.
** Otherwise, return an error.
@@ -104930,19 +117934,28 @@ static void likeFunc(
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
if( zEsc==0 ) return;
if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
- sqlite3_result_error(context,
+ sqlite3_result_error(context,
"ESCAPE expression must be a single character", -1);
return;
}
escape = sqlite3Utf8Read(&zEsc);
+ if( escape==pInfo->matchAll || escape==pInfo->matchOne ){
+ memcpy(&backupInfo, pInfo, sizeof(backupInfo));
+ pInfo = &backupInfo;
+ if( escape==pInfo->matchAll ) pInfo->matchAll = 0;
+ if( escape==pInfo->matchOne ) pInfo->matchOne = 0;
+ }
}else{
escape = pInfo->matchSet;
}
+ zB = sqlite3_value_text(argv[0]);
+ zA = sqlite3_value_text(argv[1]);
if( zA && zB ){
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
- sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
+ sqlite3_result_int(context,
+ patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
}
}
@@ -105034,8 +118047,8 @@ static void compileoptionusedFunc(
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
/*
-** Implementation of the sqlite_compileoption_get() function.
-** The result is a string that identifies the compiler options
+** Implementation of the sqlite_compileoption_get() function.
+** The result is a string that identifies the compiler options
** used to build SQLite.
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
@@ -105059,7 +118072,7 @@ static void compileoptiongetFunc(
** digits. */
static const char hexdigits[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
/*
@@ -105094,7 +118107,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
char const *zBlob = sqlite3_value_blob(argv[0]);
int nBlob = sqlite3_value_bytes(argv[0]);
assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
- zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4);
+ zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4);
if( zText ){
int i;
for(i=0; i<nBlob; i++){
@@ -105143,7 +118156,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
/*
** The unicode() function. Return the integer unicode code-point value
-** for the first character of the input string.
+** for the first character of the input string.
*/
static void unicodeFunc(
sqlite3_context *context,
@@ -105267,6 +118280,8 @@ static void replaceFunc(
i64 nOut; /* Maximum size of zOut */
int loopLimit; /* Last zStr[] that might match zPattern[] */
int i, j; /* Loop counters */
+ unsigned cntExpand; /* Number zOut expansions */
+ sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==3 );
UNUSED_PARAMETER(argc);
@@ -105297,34 +118312,41 @@ static void replaceFunc(
if( zOut==0 ){
return;
}
- loopLimit = nStr - nPattern;
+ loopLimit = nStr - nPattern;
+ cntExpand = 0;
for(i=j=0; i<=loopLimit; i++){
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
zOut[j++] = zStr[i];
}else{
- u8 *zOld;
- sqlite3 *db = sqlite3_context_db_handle(context);
- nOut += nRep - nPattern;
- testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
- testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
- if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
- sqlite3_result_error_toobig(context);
- sqlite3_free(zOut);
- return;
- }
- zOld = zOut;
- zOut = sqlite3_realloc64(zOut, (int)nOut);
- if( zOut==0 ){
- sqlite3_result_error_nomem(context);
- sqlite3_free(zOld);
- return;
+ if( nRep>nPattern ){
+ nOut += nRep - nPattern;
+ testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
+ testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
+ if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ sqlite3_result_error_toobig(context);
+ sqlite3_free(zOut);
+ return;
+ }
+ cntExpand++;
+ if( (cntExpand&(cntExpand-1))==0 ){
+ /* Grow the size of the output buffer only on substitutions
+ ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
+ u8 *zOld;
+ zOld = zOut;
+ zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ sqlite3_free(zOld);
+ return;
+ }
+ }
}
memcpy(&zOut[j], zRep, nRep);
j += nRep;
i += nPattern-1;
}
}
- assert( j+nStr-i+1==nOut );
+ assert( j+nStr-i+1<=nOut );
memcpy(&zOut[j], &zStr[i], nStr-i);
j += nStr - i;
assert( j<=nOut );
@@ -105446,7 +118468,7 @@ static void unknownFunc(
** Compute the soundex encoding of a word.
**
** IMP: R-59782-00072 The soundex(X) function returns a string that is the
-** soundex encoding of the string X.
+** soundex encoding of the string X.
*/
static void soundexFunc(
sqlite3_context *context,
@@ -105535,7 +118557,7 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
typedef struct SumCtx SumCtx;
struct SumCtx {
double rSum; /* Floating point sum */
- i64 iSum; /* Integer sum */
+ i64 iSum; /* Integer sum */
i64 cnt; /* Number of elements summed */
u8 overflow; /* True if integer overflow seen */
u8 approx; /* True if non-integer value was input to the sum */
@@ -105564,7 +118586,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
i64 v = sqlite3_value_int64(argv[0]);
p->rSum += v;
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
- p->overflow = 1;
+ p->approx = p->overflow = 1;
}
}else{
p->rSum += sqlite3_value_double(argv[0]);
@@ -105572,6 +118594,32 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
+ SumCtx *p;
+ int type;
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ p = sqlite3_aggregate_context(context, sizeof(*p));
+ type = sqlite3_value_numeric_type(argv[0]);
+ /* p is always non-NULL because sumStep() will have been called first
+ ** to initialize it */
+ if( ALWAYS(p) && type!=SQLITE_NULL ){
+ assert( p->cnt>0 );
+ p->cnt--;
+ assert( type==SQLITE_INTEGER || p->approx );
+ if( type==SQLITE_INTEGER && p->approx==0 ){
+ i64 v = sqlite3_value_int64(argv[0]);
+ p->rSum -= v;
+ p->iSum -= v;
+ }else{
+ p->rSum -= sqlite3_value_double(argv[0]);
+ }
+ }
+}
+#else
+# define sumInverse 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
static void sumFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
@@ -105606,6 +118654,9 @@ static void totalFinalize(sqlite3_context *context){
typedef struct CountCtx CountCtx;
struct CountCtx {
i64 n;
+#ifdef SQLITE_DEBUG
+ int bInverse; /* True if xInverse() ever called */
+#endif
};
/*
@@ -105620,25 +118671,40 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
#ifndef SQLITE_OMIT_DEPRECATED
/* The sqlite3_aggregate_count() function is deprecated. But just to make
- ** sure it still operates correctly, verify that its count agrees with our
+ ** sure it still operates correctly, verify that its count agrees with our
** internal count when using count(*) and when the total count can be
** expressed as a 32-bit integer. */
- assert( argc==1 || p==0 || p->n>0x7fffffff
+ assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse
|| p->n==sqlite3_aggregate_count(context) );
#endif
-}
+}
static void countFinalize(sqlite3_context *context){
CountCtx *p;
p = sqlite3_aggregate_context(context, 0);
sqlite3_result_int64(context, p ? p->n : 0);
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
+ CountCtx *p;
+ p = sqlite3_aggregate_context(ctx, sizeof(*p));
+ /* p is always non-NULL since countStep() will have been called first */
+ if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){
+ p->n--;
+#ifdef SQLITE_DEBUG
+ p->bInverse = 1;
+#endif
+ }
+}
+#else
+# define countInverse 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Routines to implement min() and max() aggregate functions.
*/
static void minmaxStep(
- sqlite3_context *context,
- int NotUsed,
+ sqlite3_context *context,
+ int NotUsed,
sqlite3_value **argv
){
Mem *pArg = (Mem *)argv[0];
@@ -105648,7 +118714,7 @@ static void minmaxStep(
pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
if( !pBest ) return;
- if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ if( sqlite3_value_type(pArg)==SQLITE_NULL ){
if( pBest->flags ) sqlite3SkipAccumulatorLoad(context);
}else if( pBest->flags ){
int max;
@@ -105674,16 +118740,26 @@ static void minmaxStep(
sqlite3VdbeMemCopy(pBest, pArg);
}
}
-static void minMaxFinalize(sqlite3_context *context){
+static void minMaxValueFinalize(sqlite3_context *context, int bValue){
sqlite3_value *pRes;
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
if( pRes ){
if( pRes->flags ){
sqlite3_result_value(context, pRes);
}
- sqlite3VdbeMemRelease(pRes);
+ if( bValue==0 ) sqlite3VdbeMemRelease(pRes);
}
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void minMaxValue(sqlite3_context *context){
+ minMaxValueFinalize(context, 1);
+}
+#else
+# define minMaxValue 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+static void minMaxFinalize(sqlite3_context *context){
+ minMaxValueFinalize(context, 0);
+}
/*
** group_concat(EXPR, ?SEPARATOR?)
@@ -105713,27 +118789,77 @@ static void groupConcatStep(
zSep = ",";
nSep = 1;
}
- if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
+ if( zSep ) sqlite3_str_append(pAccum, zSep, nSep);
}
zVal = (char*)sqlite3_value_text(argv[0]);
nVal = sqlite3_value_bytes(argv[0]);
- if( zVal ) sqlite3StrAccumAppend(pAccum, zVal, nVal);
+ if( zVal ) sqlite3_str_append(pAccum, zVal, nVal);
+ }
+}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void groupConcatInverse(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int n;
+ StrAccum *pAccum;
+ assert( argc==1 || argc==2 );
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
+ /* pAccum is always non-NULL since groupConcatStep() will have always
+ ** run frist to initialize it */
+ if( ALWAYS(pAccum) ){
+ n = sqlite3_value_bytes(argv[0]);
+ if( argc==2 ){
+ n += sqlite3_value_bytes(argv[1]);
+ }else{
+ n++;
+ }
+ if( n>=(int)pAccum->nChar ){
+ pAccum->nChar = 0;
+ }else{
+ pAccum->nChar -= n;
+ memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
+ }
+ if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
}
}
+#else
+# define groupConcatInverse 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
StrAccum *pAccum;
pAccum = sqlite3_aggregate_context(context, 0);
if( pAccum ){
- if( pAccum->accError==STRACCUM_TOOBIG ){
+ if( pAccum->accError==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(context);
- }else if( pAccum->accError==STRACCUM_NOMEM ){
+ }else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
- }else{
- sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
+ }else{
+ sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
sqlite3_free);
}
}
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void groupConcatValue(sqlite3_context *context){
+ sqlite3_str *pAccum;
+ pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0);
+ if( pAccum ){
+ if( pAccum->accError==SQLITE_TOOBIG ){
+ sqlite3_result_error_toobig(context);
+ }else if( pAccum->accError==SQLITE_NOMEM ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ const char *zText = sqlite3_str_value(pAccum);
+ sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
+ }
+ }
+}
+#else
+# define groupConcatValue 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** This routine does per-connection function registration. Most
@@ -105749,43 +118875,37 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
}
/*
-** Set the LIKEOPT flag on the 2-argument function with the given name.
-*/
-static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
- FuncDef *pDef;
- pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
- if( ALWAYS(pDef) ){
- pDef->funcFlags |= flagVal;
- }
-}
-
-/*
-** Register the built-in LIKE and GLOB functions. The caseSensitive
+** Re-register the built-in LIKE functions. The caseSensitive
** parameter determines whether or not the LIKE operator is case
-** sensitive. GLOB is always case sensitive.
+** sensitive.
*/
SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
struct compareInfo *pInfo;
+ int flags;
if( caseSensitive ){
pInfo = (struct compareInfo*)&likeInfoAlt;
+ flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE;
}else{
pInfo = (struct compareInfo*)&likeInfoNorm;
+ flags = SQLITE_FUNC_LIKE;
}
- sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
- sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0);
- sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8,
- (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
- setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
- setLikeOptFlag(db, "like",
- caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
+ sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
+ sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
+ sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags;
+ sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags;
}
/*
** pExpr points to an expression which implements a function. If
** it is appropriate to apply the LIKE optimization to that function
-** then set aWc[0] through aWc[2] to the wildcard characters and
-** return TRUE. If the function is not a LIKE-style function then
-** return FALSE.
+** then set aWc[0] through aWc[2] to the wildcard characters and the
+** escape character and then return TRUE. If the function is not a
+** LIKE-style function then return FALSE.
+**
+** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
+** operator if c is a string literal that is exactly one byte in length.
+** That one byte is stored in aWc[3]. aWc[3] is set to zero if there is
+** no ESCAPE clause.
**
** *pIsNocase is set to true if uppercase and lowercase are equivalent for
** the function (default for LIKE). If the function makes the distinction
@@ -105794,14 +118914,16 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
*/
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
FuncDef *pDef;
- if( pExpr->op!=TK_FUNCTION
- || !pExpr->x.pList
- || pExpr->x.pList->nExpr!=2
- ){
+ int nExpr;
+ if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
+ nExpr = pExpr->x.pList->nExpr;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pDef==0 ) return 0;
+#endif
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@@ -105814,6 +118936,20 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
+
+ if( nExpr<3 ){
+ aWc[3] = 0;
+ }else{
+ Expr *pEscape = pExpr->x.pList->a[2].pExpr;
+ char *zEscape;
+ if( pEscape->op!=TK_STRING ) return 0;
+ zEscape = pEscape->u.zToken;
+ if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
+ if( zEscape[0]==aWc[0] ) return 0;
+ if( zEscape[0]==aWc[1] ) return 0;
+ aWc[3] = zEscape[0];
+ }
+
*pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
return 1;
}
@@ -105837,12 +118973,20 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** For peak efficiency, put the most frequently used function last.
*/
static FuncDef aBuiltinFunc[] = {
+/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
+ TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
+ TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0),
+ TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0),
+#ifdef SQLITE_DEBUG
+ TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
+#endif
+/***** Regular functions *****/
#ifdef SQLITE_SOUNDEX
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
- VFUNCTION(load_extension, 1, 0, 0, loadExt ),
- VFUNCTION(load_extension, 2, 0, 0, loadExt ),
+ SFUNCTION(load_extension, 1, 0, 0, loadExt ),
+ SFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif
#if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
@@ -105851,9 +118995,13 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
- FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ INLINE_FUNC(unlikely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
+ INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
+ INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
+ SQLITE_FUNC_TYPEOF),
+#endif
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
@@ -105862,11 +119010,11 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(trim, 2, 3, 0, trimFunc ),
FUNCTION(min, -1, 0, 1, minmaxFunc ),
FUNCTION(min, 0, 0, 1, 0 ),
- AGGREGATE2(min, 1, 0, 1, minmaxStep, minMaxFinalize,
+ WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX ),
FUNCTION(max, -1, 1, 1, minmaxFunc ),
FUNCTION(max, 0, 1, 1, 0 ),
- AGGREGATE2(max, 1, 1, 1, minmaxStep, minMaxFinalize,
+ WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
SQLITE_FUNC_MINMAX ),
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
@@ -105882,7 +119030,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(hex, 1, 0, 0, hexFunc ),
- FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
+ INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
@@ -105897,15 +119045,18 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
- AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
- AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
- AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
- AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
- SQLITE_FUNC_COUNT ),
- AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
- AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
- AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
-
+ WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
+ WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
+ WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
+ WAGGREGATE(count, 0,0,0, countStep,
+ countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
+ WAGGREGATE(count, 1,0,0, countStep,
+ countFinalize, countFinalize, countInverse, 0 ),
+ WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
+ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+ WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
+ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
@@ -105919,14 +119070,13 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
- FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
+ INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
+ INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
-#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
- sqlite3AnalyzeFunctions();
-#endif
+ sqlite3WindowFunctions();
sqlite3RegisterDateTimeFunctions();
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
@@ -105974,25 +119124,25 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** Foreign keys in SQLite come in two flavours: deferred and immediate.
** If an immediate foreign key constraint is violated,
** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current
-** statement transaction rolled back. If a
-** deferred foreign key constraint is violated, no action is taken
-** immediately. However if the application attempts to commit the
+** statement transaction rolled back. If a
+** deferred foreign key constraint is violated, no action is taken
+** immediately. However if the application attempts to commit the
** transaction before fixing the constraint violation, the attempt fails.
**
** Deferred constraints are implemented using a simple counter associated
-** with the database handle. The counter is set to zero each time a
-** database transaction is opened. Each time a statement is executed
+** with the database handle. The counter is set to zero each time a
+** database transaction is opened. Each time a statement is executed
** that causes a foreign key violation, the counter is incremented. Each
** time a statement is executed that removes an existing violation from
** the database, the counter is decremented. When the transaction is
** committed, the commit fails if the current value of the counter is
** greater than zero. This scheme has two big drawbacks:
**
-** * When a commit fails due to a deferred foreign key constraint,
+** * When a commit fails due to a deferred foreign key constraint,
** there is no way to tell which foreign constraint is not satisfied,
** or which row it is not satisfied for.
**
-** * If the database contains foreign key violations when the
+** * If the database contains foreign key violations when the
** transaction is opened, this may cause the mechanism to malfunction.
**
** Despite these problems, this approach is adopted as it seems simpler
@@ -106004,26 +119154,26 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** the parent table for a match. If none is found increment the
** constraint counter.
**
-** I.2) For each FK for which the table is the parent table,
+** I.2) For each FK for which the table is the parent table,
** search the child table for rows that correspond to the new
** row in the parent table. Decrement the counter for each row
** found (as the constraint is now satisfied).
**
** DELETE operations:
**
-** D.1) For each FK for which the table is the child table,
-** search the parent table for a row that corresponds to the
-** deleted row in the child table. If such a row is not found,
+** D.1) For each FK for which the table is the child table,
+** search the parent table for a row that corresponds to the
+** deleted row in the child table. If such a row is not found,
** decrement the counter.
**
-** D.2) For each FK for which the table is the parent table, search
-** the child table for rows that correspond to the deleted row
+** D.2) For each FK for which the table is the parent table, search
+** the child table for rows that correspond to the deleted row
** in the parent table. For each found increment the counter.
**
** UPDATE operations:
**
** An UPDATE command requires that all 4 steps above are taken, but only
-** for FK constraints for which the affected columns are actually
+** for FK constraints for which the affected columns are actually
** modified (values must be compared at runtime).
**
** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2.
@@ -106032,10 +119182,10 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** For the purposes of immediate FK constraints, the OR REPLACE conflict
** resolution is considered to delete rows before the new row is inserted.
** If a delete caused by OR REPLACE violates an FK constraint, an exception
-** is thrown, even if the FK constraint would be satisfied after the new
+** is thrown, even if the FK constraint would be satisfied after the new
** row is inserted.
**
-** Immediate constraints are usually handled similarly. The only difference
+** Immediate constraints are usually handled similarly. The only difference
** is that the counter used is stored as part of each individual statement
** object (struct Vdbe). If, after the statement has run, its immediate
** constraint counter is greater than zero,
@@ -106046,7 +119196,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** INSERT violates a foreign key constraint. This is necessary as such
** an INSERT does not open a statement transaction.
**
-** TODO: How should dropping a table be handled? How should renaming a
+** TODO: How should dropping a table be handled? How should renaming a
** table be handled?
**
**
@@ -106057,7 +119207,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** for those two operations needs to know whether or not the operation
** requires any FK processing and, if so, which columns of the original
** row are required by the FK processing VDBE code (i.e. if FKs were
-** implemented using triggers, which of the old.* columns would be
+** implemented using triggers, which of the old.* columns would be
** accessed). No information is required by the code-generator before
** coding an INSERT operation. The functions used by the UPDATE/DELETE
** generation code to query for this information are:
@@ -106094,13 +119244,13 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
/*
** A foreign key constraint requires that the key columns in the parent
** table are collectively subject to a UNIQUE or PRIMARY KEY constraint.
-** Given that pParent is the parent table for foreign key constraint pFKey,
-** search the schema for a unique index on the parent key columns.
+** Given that pParent is the parent table for foreign key constraint pFKey,
+** search the schema for a unique index on the parent key columns.
+**
+** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
+** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
+** is set to point to the unique index.
**
-** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
-** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
-** is set to point to the unique index.
-**
** If the parent key consists of a single column (the foreign key constraint
** is not a composite foreign key), output variable *paiCol is set to NULL.
** Otherwise, it is set to point to an allocated array of size N, where
@@ -106123,8 +119273,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
** PRIMARY KEY, or
**
** 4) No parent key columns were provided explicitly as part of the
-** foreign key definition, and the PRIMARY KEY of the parent table
-** consists of a different number of columns to the child key in
+** foreign key definition, and the PRIMARY KEY of the parent table
+** consists of a different number of columns to the child key in
** the child table.
**
** then non-zero is returned, and a "foreign key mismatch" error loaded
@@ -106148,9 +119298,9 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
assert( !paiCol || *paiCol==0 );
assert( pParse );
- /* If this is a non-composite (single column) foreign key, check if it
- ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx
- ** and *paiCol set to zero and return early.
+ /* If this is a non-composite (single column) foreign key, check if it
+ ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx
+ ** and *paiCol set to zero and return early.
**
** Otherwise, for a composite foreign key (more than one column), allocate
** space for the aiCol array (returned via output parameter *paiCol).
@@ -106159,7 +119309,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
if( nCol==1 ){
/* The FK maps to the IPK if any of the following are true:
**
- ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly
+ ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly
** mapped to the primary key of table pParent, or
** 2) The FK is explicitly mapped to a column declared as INTEGER
** PRIMARY KEY.
@@ -106176,14 +119326,14 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
}
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){
+ if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){
/* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
** of columns. If each indexed column corresponds to a foreign key
** column of pFKey, then this index is a winner. */
if( zKey==0 ){
- /* If zKey is NULL, then this foreign key is implicitly mapped to
- ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
+ /* If zKey is NULL, then this foreign key is implicitly mapped to
+ ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
** identified by the test. */
if( IsPrimaryKeyIndex(pIdx) ){
if( aiCol ){
@@ -106241,15 +119391,15 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
}
/*
-** This function is called when a row is inserted into or deleted from the
-** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
+** This function is called when a row is inserted into or deleted from the
+** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
** on the child table of pFKey, this function is invoked twice for each row
** affected - once to "delete" the old row, and then again to "insert" the
** new row.
**
** Each time it is called, this function generates VDBE code to locate the
-** row in the parent table that corresponds to the row being inserted into
-** or deleted from the child table. If the parent row can be found, no
+** row in the parent table that corresponds to the row being inserted into
+** or deleted from the child table. If the parent row can be found, no
** special action is taken. Otherwise, if the parent row can *not* be
** found in the parent table:
**
@@ -106263,7 +119413,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
**
** DELETE deferred Decrement the "deferred constraint counter".
**
-** These operations are identified in the comment at the top of this file
+** These operations are identified in the comment at the top of this file
** (fkey.c) as "I.1" and "D.1".
*/
static void fkLookupParent(
@@ -106280,21 +119430,27 @@ static void fkLookupParent(
int i; /* Iterator variable */
Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */
int iCur = pParse->nTab - 1; /* Cursor number to use */
- int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */
+ int iOk = sqlite3VdbeMakeLabel(pParse); /* jump here if parent key found */
+
+ sqlite3VdbeVerifyAbortable(v,
+ (!pFKey->isDeferred
+ && !(pParse->db->flags & SQLITE_DeferFKs)
+ && !pParse->pToplevel
+ && !pParse->isMultiWrite) ? OE_Abort : OE_Ignore);
/* If nIncr is less than zero, then check at runtime if there are any
** outstanding constraints to resolve. If there are not, there is no need
** to check if deleting this row resolves any outstanding violations.
**
- ** Check if any of the key columns in the child table row are NULL. If
- ** any are, then the constraint is considered satisfied. No need to
+ ** Check if any of the key columns in the child table row are NULL. If
+ ** any are, then the constraint is considered satisfied. No need to
** search for a matching row in the parent table. */
if( nIncr<0 ){
sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk);
VdbeCoverage(v);
}
for(i=0; i<pFKey->nCol; i++){
- int iReg = aiCol[i] + regData + 1;
+ int iReg = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i]) + regData + 1;
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); VdbeCoverage(v);
}
@@ -106304,16 +119460,17 @@ static void fkLookupParent(
** column of the parent table (table pTab). */
int iMustBeInt; /* Address of MustBeInt instruction */
int regTemp = sqlite3GetTempReg(pParse);
-
- /* Invoke MustBeInt to coerce the child key value to an integer (i.e.
+
+ /* Invoke MustBeInt to coerce the child key value to an integer (i.e.
** apply the affinity of the parent key). If this fails, then there
** is no matching parent key. Before using MustBeInt, make a copy of
** the value. Otherwise, the value inserted into the child key column
** will have INTEGER affinity applied to it, which may not be correct. */
- sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[0]+1+regData, regTemp);
+ sqlite3VdbeAddOp2(v, OP_SCopy,
+ sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp);
iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
VdbeCoverage(v);
-
+
/* 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
@@ -106322,7 +119479,7 @@ static void fkLookupParent(
sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
}
-
+
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v);
sqlite3VdbeGoto(v, iOk);
@@ -106333,19 +119490,21 @@ static void fkLookupParent(
int nCol = pFKey->nCol;
int regTemp = sqlite3GetTempRange(pParse, nCol);
int regRec = sqlite3GetTempReg(pParse);
-
+
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
+ sqlite3VdbeAddOp2(v, OP_Copy,
+ sqlite3TableColumnToStorage(pFKey->pFrom, aiCol[i])+1+regData,
+ regTemp+i);
}
-
+
/* 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
+ ** 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).
@@ -106353,8 +119512,11 @@ static void fkLookupParent(
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;
+ int iChild = sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[i])
+ +1+regData;
+ int iParent = 1+regData;
+ iParent += sqlite3TableColumnToStorage(pIdx->pTable,
+ pIdx->aiColumn[i]);
assert( pIdx->aiColumn[i]>=0 );
assert( aiCol[i]!=pTab->iPKey );
if( pIdx->aiColumn[i]==pTab->iPKey ){
@@ -106366,19 +119528,19 @@ static void fkLookupParent(
}
sqlite3VdbeGoto(v, iOk);
}
-
+
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
-
+
sqlite3ReleaseTempReg(pParse, regRec);
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
}
}
if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs)
- && !pParse->pToplevel
- && !pParse->isMultiWrite
+ && !pParse->pToplevel
+ && !pParse->isMultiWrite
){
/* Special case: If this is an INSERT statement that will insert exactly
** one row into the table, raise a constraint immediately instead of
@@ -106422,14 +119584,14 @@ static Expr *exprTableRegister(
if( pExpr ){
if( iCol>=0 && iCol!=pTab->iPKey ){
pCol = &pTab->aCol[iCol];
- pExpr->iTable = regBase + iCol + 1;
- pExpr->affinity = pCol->affinity;
+ pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1;
+ pExpr->affExpr = pCol->affinity;
zColl = pCol->zColl;
if( zColl==0 ) zColl = db->pDfltColl->zName;
pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl);
}else{
pExpr->iTable = regBase;
- pExpr->affinity = SQLITE_AFF_INTEGER;
+ pExpr->affExpr = SQLITE_AFF_INTEGER;
}
}
return pExpr;
@@ -106447,7 +119609,7 @@ static Expr *exprTableColumn(
){
Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0);
if( pExpr ){
- pExpr->pTab = pTab;
+ pExpr->y.pTab = pTab;
pExpr->iTable = iCursor;
pExpr->iColumn = iCol;
}
@@ -106456,7 +119618,7 @@ static Expr *exprTableColumn(
/*
** This function is called to generate code executed when a row is deleted
-** from the parent table of foreign key constraint pFKey and, if pFKey is
+** from the parent table of foreign key constraint pFKey and, if pFKey is
** deferred, when a row is inserted into the same table. When generating
** code for an SQL UPDATE operation, this function may be called twice -
** once to "delete" the old row and once to "insert" the new row.
@@ -106483,7 +119645,7 @@ static Expr *exprTableColumn(
**
** INSERT deferred Decrement the "deferred constraint counter".
**
-** These operations are identified in the comment at the top of this file
+** These operations are identified in the comment at the top of this file
** (fkey.c) as "I.2" and "D.2".
*/
static void fkScanChildren(
@@ -106526,7 +119688,7 @@ static void fkScanChildren(
Expr *pLeft; /* Value from parent table row */
Expr *pRight; /* Column ref to child table */
Expr *pEq; /* Expression (pLeft = pRight) */
- i16 iCol; /* Index of column in child table */
+ i16 iCol; /* Index of column in child table */
const char *zCol; /* Name of column in child table */
iCol = pIdx ? pIdx->aiColumn[i] : -1;
@@ -106535,8 +119697,8 @@ static void fkScanChildren(
assert( iCol>=0 );
zCol = pFKey->pFrom->aCol[iCol].zName;
pRight = sqlite3Expr(db, TK_ID, zCol);
- pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
- pWhere = sqlite3ExprAnd(db, pWhere, pEq);
+ pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
+ pWhere = sqlite3ExprAnd(pParse, pWhere, pEq);
}
/* If the child table is the same as the parent table, then add terms
@@ -106547,8 +119709,11 @@ static void fkScanChildren(
** NOT( $current_a==a AND $current_b==b AND ... )
**
** The first form is used for rowid tables. The second form is used
- ** for WITHOUT ROWID tables. In the second form, the primary key is
- ** (a,b,...)
+ ** for WITHOUT ROWID tables. In the second form, the *parent* key is
+ ** (a,b,...). Either the parent or primary key could be used to
+ ** uniquely identify the current row, but the parent key is more convenient
+ ** as the required values have already been loaded into registers
+ ** by the caller.
*/
if( pTab==pFKey->pFrom && nIncr>0 ){
Expr *pNe; /* Expression (pLeft != pRight) */
@@ -106557,22 +119722,21 @@ static void fkScanChildren(
if( HasRowid(pTab) ){
pLeft = exprTableRegister(pParse, pTab, regData, -1);
pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1);
- pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0);
+ pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight);
}else{
Expr *pEq, *pAll = 0;
- Index *pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pIdx!=0 );
- for(i=0; i<pPk->nKeyCol; i++){
+ for(i=0; i<pIdx->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
assert( iCol>=0 );
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
- pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
- pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
- pAll = sqlite3ExprAnd(db, pAll, pEq);
+ pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName);
+ pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight);
+ pAll = sqlite3ExprAnd(pParse, pAll, pEq);
}
- pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0);
+ pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0);
}
- pWhere = sqlite3ExprAnd(db, pWhere, pNe);
+ pWhere = sqlite3ExprAnd(pParse, pWhere, pNe);
}
/* Resolve the references in the WHERE clause. */
@@ -106584,16 +119748,18 @@ static void fkScanChildren(
/* Create VDBE to loop through the entries in pSrc that match the WHERE
** clause. For each row found, increment either the deferred or immediate
** foreign key constraint counter. */
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
- sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
- if( pWInfo ){
- sqlite3WhereEnd(pWInfo);
+ if( pParse->nErr==0 ){
+ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
+ if( pWInfo ){
+ sqlite3WhereEnd(pWInfo);
+ }
}
/* Clean up the WHERE clause constructed above. */
sqlite3ExprDelete(db, pWhere);
if( iFkIfZero ){
- sqlite3VdbeJumpHere(v, iFkIfZero);
+ sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero);
}
}
@@ -106616,7 +119782,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){
}
/*
-** The second argument is a Trigger structure allocated by the
+** The second argument is a Trigger structure allocated by the
** fkActionTrigger() routine. This function deletes the Trigger structure
** and all of its sub-components.
**
@@ -106644,7 +119810,7 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
**
** (a) The table is the parent table of a FK constraint, or
** (b) The table is the child table of a deferred FK constraint and it is
-** determined at runtime that there are outstanding deferred FK
+** determined at runtime that there are outstanding deferred FK
** constraint violations in the database,
**
** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
@@ -106653,14 +119819,15 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
*/
SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
sqlite3 *db = pParse->db;
- if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){
+ if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){
int iSkip = 0;
Vdbe *v = sqlite3GetVdbe(pParse);
assert( v ); /* VDBE has already been allocated */
+ assert( pTab->pSelect==0 ); /* Not a view */
if( sqlite3FkReferences(pTab)==0 ){
/* Search for a deferred foreign key constraint for which this table
- ** is the child table. If one cannot be found, return without
+ ** is the child table. If one cannot be found, return without
** generating any VDBE code. If one can be found, then jump over
** the entire DELETE if there are no outstanding deferred constraints
** when this statement is run. */
@@ -106669,24 +119836,25 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break;
}
if( !p ) return;
- iSkip = sqlite3VdbeMakeLabel(v);
+ iSkip = sqlite3VdbeMakeLabel(pParse);
sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); VdbeCoverage(v);
}
pParse->disableTriggers = 1;
- sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0);
+ sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
pParse->disableTriggers = 0;
- /* If the DELETE has generated immediate foreign key constraint
+ /* If the DELETE has generated immediate foreign key constraint
** violations, halt the VDBE and return an error at this point, before
** any modifications to the schema are made. This is because statement
- ** transactions are not able to rollback schema changes.
+ ** transactions are not able to rollback schema changes.
**
** If the SQLITE_DeferFKs flag is set, then this is not required, as
** the statement transaction will not be rolled back even if FK
** constraints are violated.
*/
if( (db->flags & SQLITE_DeferFKs)==0 ){
+ sqlite3VdbeVerifyAbortable(v, OE_Abort);
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
@@ -106703,7 +119871,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
/*
** The second argument points to an FKey object representing a foreign key
** for which pTab is the child table. An UPDATE statement against pTab
-** is currently being processed. For each column of the table that is
+** is currently being processed. For each column of the table that is
** actually updated, the corresponding element in the aChange[] array
** is zero or greater (if a column is unmodified the corresponding element
** is set to -1). If the rowid column is modified by the UPDATE statement
@@ -106730,7 +119898,7 @@ static int fkChildIsModified(
/*
** The second argument points to an FKey object representing a foreign key
** for which pTab is the parent table. An UPDATE statement against pTab
-** is currently being processed. For each column of the table that is
+** is currently being processed. For each column of the table that is
** actually updated, the corresponding element in the aChange[] array
** is zero or greater (if a column is unmodified the corresponding element
** is set to -1). If the rowid column is modified by the UPDATE statement
@@ -106740,9 +119908,9 @@ static int fkChildIsModified(
** parent key for FK constraint *p are modified.
*/
static int fkParentIsModified(
- Table *pTab,
- FKey *p,
- int *aChange,
+ Table *pTab,
+ FKey *p,
+ int *aChange,
int bChngRowid
){
int i;
@@ -106783,7 +119951,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
/*
** This function is called when inserting, deleting or updating a row of
-** table pTab to generate VDBE code to perform foreign key constraint
+** table pTab to generate VDBE code to perform foreign key constraint
** processing for the operation.
**
** For a DELETE operation, parameter regOld is passed the index of the
@@ -106799,11 +119967,11 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
** For an UPDATE operation, this function is called twice. Once before
** the original record is deleted from the table using the calling convention
** described for DELETE. Then again after the original record is deleted
-** but before the new record is inserted using the INSERT convention.
+** but before the new record is inserted using the INSERT convention.
*/
SQLITE_PRIVATE void sqlite3FkCheck(
Parse *pParse, /* Parse context */
- Table *pTab, /* Row is being deleted from this table */
+ Table *pTab, /* Row is being deleted from this table */
int regOld, /* Previous row data is stored here */
int regNew, /* New row data is stored here */
int *aChange, /* Array indicating UPDATEd columns (or 0) */
@@ -106835,16 +120003,16 @@ SQLITE_PRIVATE void sqlite3FkCheck(
int i;
int bIgnore = 0;
- if( aChange
+ if( aChange
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
- && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
+ && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
){
continue;
}
- /* Find the parent table of this foreign key. Also find a unique index
- ** on the parent key columns in the parent table. If either of these
- ** schema items cannot be located, set an error in pParse and return
+ /* Find the parent table of this foreign key. Also find a unique index
+ ** on the parent key columns in the parent table. If either of these
+ ** schema items cannot be located, set an error in pParse and return
** early. */
if( pParse->disableTriggers ){
pTo = sqlite3FindTable(db, pFKey->zTo, zDb);
@@ -106865,7 +120033,9 @@ SQLITE_PRIVATE void sqlite3FkCheck(
Vdbe *v = sqlite3GetVdbe(pParse);
int iJump = sqlite3VdbeCurrentAddr(v) + pFKey->nCol + 1;
for(i=0; i<pFKey->nCol; i++){
- int iReg = pFKey->aCol[i].iFrom + regOld + 1;
+ int iFromCol, iReg;
+ iFromCol = pFKey->aCol[i].iFrom;
+ iReg = sqlite3TableColumnToStorage(pFKey->pFrom,iFromCol) + regOld+1;
sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1);
@@ -106886,7 +120056,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
}
assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
#ifndef SQLITE_OMIT_AUTHORIZATION
- /* Request permission to read the parent key columns. If the
+ /* Request permission to read the parent key columns. If the
** authorization callback returns SQLITE_IGNORE, behave as if any
** values read from the parent table are NULL. */
if( db->xAuth ){
@@ -106898,24 +120068,24 @@ SQLITE_PRIVATE void sqlite3FkCheck(
#endif
}
- /* Take a shared-cache advisory read-lock on the parent table. Allocate
- ** a cursor to use to search the unique index on the parent key columns
+ /* Take a shared-cache advisory read-lock on the parent table. Allocate
+ ** a cursor to use to search the unique index on the parent key columns
** in the parent table. */
sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName);
pParse->nTab++;
if( regOld!=0 ){
/* A row is being removed from the child table. Search for the parent.
- ** If the parent does not exist, removing the child row resolves an
+ ** If the parent does not exist, removing the child row resolves an
** outstanding foreign key constraint violation. */
fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
}
if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
/* A row is being added to the child table. If a parent row cannot
- ** be found, adding the child row has violated the FK constraint.
+ ** be found, adding the child row has violated the FK constraint.
**
** If this operation is being performed as part of a trigger program
- ** that is actually a "SET NULL" action belonging to this very
+ ** that is actually a "SET NULL" action belonging to this very
** foreign key, then omit this scan altogether. As all child key
** values are guaranteed to be NULL, it is not possible for adding
** this row to cause an FK violation. */
@@ -106936,8 +120106,8 @@ SQLITE_PRIVATE void sqlite3FkCheck(
continue;
}
- if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
- && !pParse->pToplevel && !pParse->isMultiWrite
+ if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
+ && !pParse->pToplevel && !pParse->isMultiWrite
){
assert( regOld==0 && regNew!=0 );
/* Inserting a single row into a parent table cannot cause (or fix)
@@ -106953,14 +120123,14 @@ SQLITE_PRIVATE void sqlite3FkCheck(
/* Create a SrcList structure containing the child table. We need the
** child table as a SrcList for sqlite3WhereBegin() */
- pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
+ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
if( pSrc ){
struct SrcList_item *pItem = pSrc->a;
pItem->pTab = pFKey->pFrom;
pItem->zName = pFKey->pFrom->zName;
- pItem->pTab->nRef++;
+ pItem->pTab->nTabRef++;
pItem->iCursor = pParse->nTab++;
-
+
if( regNew!=0 ){
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
}
@@ -106979,10 +120149,10 @@ SQLITE_PRIVATE void sqlite3FkCheck(
**
** Note 2: At first glance it may seem like SQLite could simply omit
** all OP_FkCounter related scans when either CASCADE or SET NULL
- ** applies. The trouble starts if the CASCADE or SET NULL action
- ** trigger causes other triggers or action rules attached to the
+ ** applies. The trouble starts if the CASCADE or SET NULL action
+ ** trigger causes other triggers or action rules attached to the
** child table to fire. In these cases the fk constraint counters
- ** might be set incorrectly if any OP_FkCounter related scans are
+ ** might be set incorrectly if any OP_FkCounter related scans are
** omitted. */
if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
sqlite3MayAbort(pParse);
@@ -106998,7 +120168,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
#define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x)))
/*
-** This function is called before generating code to update or delete a
+** This function is called before generating code to update or delete a
** row contained in table pTab.
*/
SQLITE_PRIVATE u32 sqlite3FkOldmask(
@@ -107028,18 +120198,26 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
/*
-** This function is called before generating code to update or delete a
+** This function is called before generating code to update or delete a
** row contained in table pTab. If the operation is a DELETE, then
** parameter aChange is passed a NULL value. For an UPDATE, aChange points
** to an array of size N, where N is the number of columns in table pTab.
-** If the i'th column is not modified by the UPDATE, then the corresponding
+** If the i'th column is not modified by the UPDATE, then the corresponding
** entry in the aChange[] array is set to -1. If the column is modified,
** the value is 0 or greater. Parameter chngRowid is set to true if the
** UPDATE statement modifies the rowid fields of the table.
**
** If any foreign key processing will be required, this function returns
-** true. If there is no foreign key related processing, this function
-** returns false.
+** non-zero. If there is no foreign key related processing, this function
+** returns zero.
+**
+** For an UPDATE, this function returns 2 if:
+**
+** * There are any FKs for which pTab is the child and the parent table, or
+** * the UPDATE modifies one or more parent keys for which the action is
+** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
+**
+** Or, assuming some other foreign key processing is required, 1.
*/
SQLITE_PRIVATE int sqlite3FkRequired(
Parse *pParse, /* Parse context */
@@ -107047,12 +120225,13 @@ SQLITE_PRIVATE int sqlite3FkRequired(
int *aChange, /* Non-NULL for UPDATE operations */
int chngRowid /* True for UPDATE that affects rowid */
){
+ int eRet = 0;
if( pParse->db->flags&SQLITE_ForeignKeys ){
if( !aChange ){
- /* A DELETE operation. Foreign key processing is required if the
- ** table in question is either the child or parent table for any
+ /* A DELETE operation. Foreign key processing is required if the
+ ** table in question is either the child or parent table for any
** foreign key constraint. */
- return (sqlite3FkReferences(pTab) || pTab->pFKey);
+ eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
}else{
/* This is an UPDATE. Foreign key processing is only required if the
** operation modifies one or more child or parent key columns. */
@@ -107060,20 +120239,26 @@ SQLITE_PRIVATE int sqlite3FkRequired(
/* Check if any child key columns are being modified. */
for(p=pTab->pFKey; p; p=p->pNextFrom){
- if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
+ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
+ if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
+ eRet = 1;
+ }
}
/* Check if any parent key columns are being modified. */
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
- if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
+ if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
+ if( p->aAction[1]!=OE_None ) return 2;
+ eRet = 1;
+ }
}
}
}
- return 0;
+ return eRet;
}
/*
-** This function is called when an UPDATE or DELETE operation is being
+** This function is called when an UPDATE or DELETE operation is being
** compiled on table pTab, which is the parent table of foreign-key pFKey.
** If the current operation is an UPDATE, then the pChanges parameter is
** passed a pointer to the list of columns being modified. If it is a
@@ -107085,7 +120270,7 @@ SQLITE_PRIVATE int sqlite3FkRequired(
** returned (these actions require no special handling by the triggers
** sub-system, code for them is created by fkScanChildren()).
**
-** For example, if pFKey is the foreign key and pTab is table "p" in
+** For example, if pFKey is the foreign key and pTab is table "p" in
** the following schema:
**
** CREATE TABLE p(pk PRIMARY KEY);
@@ -107098,7 +120283,7 @@ SQLITE_PRIVATE int sqlite3FkRequired(
** END;
**
** The returned pointer is cached as part of the foreign key object. It
-** is eventually freed along with the rest of the foreign key object by
+** is eventually freed along with the rest of the foreign key object by
** sqlite3FkDelete().
*/
static Trigger *fkActionTrigger(
@@ -107154,13 +120339,12 @@ static Trigger *fkActionTrigger(
** that the affinity and collation sequence associated with the
** parent table are used for the comparison. */
pEq = sqlite3PExpr(pParse, TK_EQ,
- sqlite3PExpr(pParse, TK_DOT,
+ sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
- , 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
- , 0);
- pWhere = sqlite3ExprAnd(db, pWhere, pEq);
+ );
+ pWhere = sqlite3ExprAnd(pParse, pWhere, pEq);
/* For ON UPDATE, construct the next term of the WHEN clause.
** The final WHEN clause will be like this:
@@ -107169,27 +120353,32 @@ static Trigger *fkActionTrigger(
*/
if( pChanges ){
pEq = sqlite3PExpr(pParse, TK_IS,
- sqlite3PExpr(pParse, TK_DOT,
+ sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
- 0),
- sqlite3PExpr(pParse, TK_DOT,
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
+ sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
- 0),
- 0);
- pWhen = sqlite3ExprAnd(db, pWhen, pEq);
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0))
+ );
+ pWhen = sqlite3ExprAnd(pParse, pWhen, pEq);
}
-
+
if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){
Expr *pNew;
if( action==OE_Cascade ){
- pNew = sqlite3PExpr(pParse, TK_DOT,
+ pNew = sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
- , 0);
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
}else if( action==OE_SetDflt ){
- Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
+ Column *pCol = pFKey->pFrom->aCol + iFromCol;
+ Expr *pDflt;
+ if( pCol->colFlags & COLFLAG_GENERATED ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ pDflt = 0;
+ }else{
+ pDflt = pCol->pDflt;
+ }
if( pDflt ){
pNew = sqlite3ExprDup(db, pDflt, 0);
}else{
@@ -107209,27 +120398,27 @@ static Trigger *fkActionTrigger(
if( action==OE_Restrict ){
Token tFrom;
- Expr *pRaise;
+ Expr *pRaise;
tFrom.z = zFrom;
tFrom.n = nFrom;
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){
- pRaise->affinity = OE_Abort;
+ pRaise->affExpr = OE_Abort;
}
- pSelect = sqlite3SelectNew(pParse,
+ pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
- sqlite3SrcListAppend(db, 0, &tFrom, 0),
+ sqlite3SrcListAppend(pParse, 0, &tFrom, 0),
pWhere,
- 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0
);
pWhere = 0;
}
/* Disable lookaside memory allocation */
- db->lookaside.bDisable++;
+ DisableLookaside;
- pTrigger = (Trigger *)sqlite3DbMallocZero(db,
+ pTrigger = (Trigger *)sqlite3DbMallocZero(db,
sizeof(Trigger) + /* struct Trigger */
sizeof(TriggerStep) + /* Single step in trigger program */
nFrom + 1 /* Space for pStep->zTarget */
@@ -107238,18 +120427,18 @@ static Trigger *fkActionTrigger(
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
pStep->zTarget = (char *)&pStep[1];
memcpy((char *)pStep->zTarget, zFrom, nFrom);
-
+
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
if( pWhen ){
- pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0);
+ pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0);
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
}
}
/* Re-enable the lookaside buffer, if it was disabled earlier. */
- db->lookaside.bDisable--;
+ EnableLookaside;
sqlite3ExprDelete(db, pWhere);
sqlite3ExprDelete(db, pWhen);
@@ -107260,16 +120449,18 @@ static Trigger *fkActionTrigger(
return 0;
}
assert( pStep!=0 );
+ assert( pTrigger!=0 );
switch( action ){
case OE_Restrict:
- pStep->op = TK_SELECT;
+ pStep->op = TK_SELECT;
break;
- case OE_Cascade:
- if( !pChanges ){
- pStep->op = TK_DELETE;
- break;
+ case OE_Cascade:
+ if( !pChanges ){
+ pStep->op = TK_DELETE;
+ break;
}
+ /* no break */ deliberate_fall_through
default:
pStep->op = TK_UPDATE;
}
@@ -107295,9 +120486,9 @@ SQLITE_PRIVATE void sqlite3FkActions(
int *aChange, /* Array indicating UPDATEd columns (or 0) */
int bChngRowid /* True if rowid is UPDATEd */
){
- /* If foreign-key support is enabled, iterate through all FKs that
- ** refer to table pTab. If there is an action associated with the FK
- ** for this operation (either update or delete), invoke the associated
+ /* If foreign-key support is enabled, iterate through all FKs that
+ ** refer to table pTab. If there is an action associated with the FK
+ ** for this operation (either update or delete), invoke the associated
** trigger sub-program. */
if( pParse->db->flags&SQLITE_ForeignKeys ){
FKey *pFKey; /* Iterator variable */
@@ -107377,7 +120568,7 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
/* #include "sqliteInt.h" */
/*
-** Generate code that will
+** Generate code that will
**
** (1) acquire a lock for table pTab then
** (2) open pTab as cursor iCur.
@@ -107396,10 +120587,10 @@ SQLITE_PRIVATE void sqlite3OpenTable(
assert( !IsVirtual(pTab) );
v = sqlite3GetVdbe(pParse);
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
- sqlite3TableLock(pParse, iDb, pTab->tnum,
+ sqlite3TableLock(pParse, iDb, pTab->tnum,
(opcode==OP_OpenWrite)?1:0, pTab->zName);
if( HasRowid(pTab) ){
- sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol);
+ sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -107413,7 +120604,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
/*
** Return a pointer to the column affinity string associated with index
-** pIdx. A column affinity string has one character for each column in
+** pIdx. A column affinity string has one character for each column in
** the table, according to the affinity of the column:
**
** Character Column affinity
@@ -107450,22 +120641,23 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
}
for(n=0; n<pIdx->nColumn; n++){
i16 x = pIdx->aiColumn[n];
+ char aff;
if( x>=0 ){
- pIdx->zColAff[n] = pTab->aCol[x].affinity;
+ aff = pTab->aCol[x].affinity;
}else if( x==XN_ROWID ){
- pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
+ aff = SQLITE_AFF_INTEGER;
}else{
- char aff;
assert( x==XN_EXPR );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
- if( aff==0 ) aff = SQLITE_AFF_BLOB;
- pIdx->zColAff[n] = aff;
}
+ if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
+ if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
+ pIdx->zColAff[n] = aff;
}
pIdx->zColAff[n] = 0;
}
-
+
return pIdx->zColAff;
}
@@ -107490,7 +120682,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
** 'E' REAL
*/
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
- int i;
+ int i, j;
char *zColAff = pTab->zColAff;
if( zColAff==0 ){
sqlite3 *db = sqlite3VdbeDb(v);
@@ -107500,15 +120692,19 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
return;
}
- for(i=0; i<pTab->nCol; i++){
- zColAff[i] = pTab->aCol[i].affinity;
+ for(i=j=0; i<pTab->nCol; i++){
+ assert( pTab->aCol[i].affinity!=0 );
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ zColAff[j++] = pTab->aCol[i].affinity;
+ }
}
do{
- zColAff[i--] = 0;
- }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB );
+ zColAff[j--] = 0;
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
pTab->zColAff = zColAff;
}
- i = sqlite3Strlen30(zColAff);
+ assert( zColAff!=0 );
+ i = sqlite3Strlen30NN(zColAff);
if( i ){
if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
@@ -107520,9 +120716,9 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
/*
** Return non-zero if the table pTab in database iDb or any of its indices
-** have been opened at any point in the VDBE program. This is used to see if
-** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
-** run without using a temporary table for the results of the SELECT.
+** have been opened at any point in the VDBE program. This is used to see if
+** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
+** run without using a temporary table for the results of the SELECT.
*/
static int readsTable(Parse *p, int iDb, Table *pTab){
Vdbe *v = sqlite3GetVdbe(p);
@@ -107537,7 +120733,7 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
assert( pOp!=0 );
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
Index *pIndex;
- int tnum = pOp->p2;
+ Pgno tnum = pOp->p2;
if( tnum==pTab->tnum ){
return 1;
}
@@ -107558,6 +120754,119 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
return 0;
}
+/* This walker callback will compute the union of colFlags flags for all
+** referenced columns in a CHECK constraint or generated column expression.
+*/
+static int exprColumnFlagUnion(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 ){
+ assert( pExpr->iColumn < pWalker->u.pTab->nCol );
+ pWalker->eCode |= pWalker->u.pTab->aCol[pExpr->iColumn].colFlags;
+ }
+ return WRC_Continue;
+}
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/*
+** All regular columns for table pTab have been puts into registers
+** starting with iRegStore. The registers that correspond to STORED
+** or VIRTUAL columns have not yet been initialized. This routine goes
+** back and computes the values for those columns based on the previously
+** computed normal columns.
+*/
+SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(
+ Parse *pParse, /* Parsing context */
+ int iRegStore, /* Register holding the first column */
+ Table *pTab /* The table */
+){
+ int i;
+ Walker w;
+ Column *pRedo;
+ int eProgress;
+ VdbeOp *pOp;
+
+ assert( pTab->tabFlags & TF_HasGenerated );
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+
+ /* Before computing generated columns, first go through and make sure
+ ** that appropriate affinity has been applied to the regular columns
+ */
+ sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
+ if( (pTab->tabFlags & TF_HasStored)!=0
+ && (pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1))->opcode==OP_Affinity
+ ){
+ /* Change the OP_Affinity argument to '@' (NONE) for all stored
+ ** columns. '@' is the no-op affinity and those columns have not
+ ** yet been computed. */
+ int ii, jj;
+ char *zP4 = pOp->p4.z;
+ assert( zP4!=0 );
+ assert( pOp->p4type==P4_DYNAMIC );
+ for(ii=jj=0; zP4[jj]; ii++){
+ if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
+ continue;
+ }
+ if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
+ zP4[jj] = SQLITE_AFF_NONE;
+ }
+ jj++;
+ }
+ }
+
+ /* Because there can be multiple generated columns that refer to one another,
+ ** this is a two-pass algorithm. On the first pass, mark all generated
+ ** columns as "not available".
+ */
+ for(i=0; i<pTab->nCol; i++){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
+ pTab->aCol[i].colFlags |= COLFLAG_NOTAVAIL;
+ }
+ }
+
+ w.u.pTab = pTab;
+ w.xExprCallback = exprColumnFlagUnion;
+ w.xSelectCallback = 0;
+ w.xSelectCallback2 = 0;
+
+ /* On the second pass, compute the value of each NOT-AVAILABLE column.
+ ** Companion code in the TK_COLUMN case of sqlite3ExprCodeTarget() will
+ ** compute dependencies and mark remove the COLSPAN_NOTAVAIL mark, as
+ ** they are needed.
+ */
+ pParse->iSelfTab = -iRegStore;
+ do{
+ eProgress = 0;
+ pRedo = 0;
+ for(i=0; i<pTab->nCol; i++){
+ Column *pCol = pTab->aCol + i;
+ if( (pCol->colFlags & COLFLAG_NOTAVAIL)!=0 ){
+ int x;
+ pCol->colFlags |= COLFLAG_BUSY;
+ w.eCode = 0;
+ sqlite3WalkExpr(&w, pCol->pDflt);
+ pCol->colFlags &= ~COLFLAG_BUSY;
+ if( w.eCode & COLFLAG_NOTAVAIL ){
+ pRedo = pCol;
+ continue;
+ }
+ eProgress = 1;
+ assert( pCol->colFlags & COLFLAG_GENERATED );
+ x = sqlite3TableColumnToStorage(pTab, i) + iRegStore;
+ sqlite3ExprCodeGeneratedColumn(pParse, pCol, x);
+ pCol->colFlags &= ~COLFLAG_NOTAVAIL;
+ }
+ }
+ }while( pRedo && eProgress );
+ if( pRedo ){
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zName);
+ }
+ pParse->iSelfTab = 0;
+}
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+
+
#ifndef SQLITE_OMIT_AUTOINCREMENT
/*
** Locate or create an AutoincInfo structure associated with table pTab
@@ -107572,11 +120881,12 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
** first use of table pTab. On 2nd and subsequent uses, the original
** AutoincInfo structure is used.
**
-** Three memory locations are allocated:
+** Four consecutive registers are allocated:
**
-** (1) Register to hold the name of the pTab table.
-** (2) Register to hold the maximum ROWID of pTab.
-** (3) Register to hold the rowid in sqlite_sequence of pTab
+** (1) The name of the pTab table.
+** (2) The maximum ROWID of pTab.
+** (3) The rowid in sqlite_sequence of pTab
+** (4) The original value of the max ROWID in pTab, or NULL if none
**
** The 2nd register is the one that is returned. That is all the
** insert routine needs to know about.
@@ -107587,11 +120897,26 @@ static int autoIncBegin(
Table *pTab /* The table we are writing to */
){
int memId = 0; /* Register holding maximum rowid */
+ assert( pParse->db->aDb[iDb].pSchema!=0 );
if( (pTab->tabFlags & TF_Autoincrement)!=0
- && (pParse->db->flags & SQLITE_Vacuum)==0
+ && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
+ Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab;
+
+ /* Verify that the sqlite_sequence table exists and is an ordinary
+ ** rowid table with exactly two columns.
+ ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
+ if( pSeqTab==0
+ || !HasRowid(pSeqTab)
+ || IsVirtual(pSeqTab)
+ || pSeqTab->nCol!=2
+ ){
+ pParse->nErr++;
+ pParse->rc = SQLITE_CORRUPT_SEQUENCE;
+ return 0;
+ }
pInfo = pToplevel->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
@@ -107604,7 +120929,7 @@ static int autoIncBegin(
pInfo->iDb = iDb;
pToplevel->nMem++; /* Register to hold name of table */
pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */
- pToplevel->nMem++; /* Rowid in sqlite_sequence */
+ pToplevel->nMem +=2; /* Rowid in sqlite_sequence + orig max val */
}
memId = pInfo->regCtr;
}
@@ -107613,7 +120938,7 @@ static int autoIncBegin(
/*
** This routine generates code that will initialize all of the
-** register used by the autoincrement tracker.
+** register used by the autoincrement tracker.
*/
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
AutoincInfo *p; /* Information about an AUTOINCREMENT */
@@ -107632,15 +120957,17 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList autoInc[] = {
/* 0 */ {OP_Null, 0, 0, 0},
- /* 1 */ {OP_Rewind, 0, 9, 0},
+ /* 1 */ {OP_Rewind, 0, 10, 0},
/* 2 */ {OP_Column, 0, 0, 0},
- /* 3 */ {OP_Ne, 0, 7, 0},
+ /* 3 */ {OP_Ne, 0, 9, 0},
/* 4 */ {OP_Rowid, 0, 0, 0},
/* 5 */ {OP_Column, 0, 1, 0},
- /* 6 */ {OP_Goto, 0, 9, 0},
- /* 7 */ {OP_Next, 0, 2, 0},
- /* 8 */ {OP_Integer, 0, 0, 0},
- /* 9 */ {OP_Close, 0, 0, 0}
+ /* 6 */ {OP_AddImm, 0, 0, 0},
+ /* 7 */ {OP_Copy, 0, 0, 0},
+ /* 8 */ {OP_Goto, 0, 11, 0},
+ /* 9 */ {OP_Next, 0, 2, 0},
+ /* 10 */ {OP_Integer, 0, 0, 0},
+ /* 11 */ {OP_Close, 0, 0, 0}
};
VdbeOp *aOp;
pDb = &db->aDb[p->iDb];
@@ -107651,14 +120978,18 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn);
if( aOp==0 ) break;
aOp[0].p2 = memId;
- aOp[0].p3 = memId+1;
+ aOp[0].p3 = memId+2;
aOp[2].p3 = memId;
aOp[3].p1 = memId-1;
aOp[3].p3 = memId;
aOp[3].p5 = SQLITE_JUMPIFNULL;
aOp[4].p2 = memId+1;
aOp[5].p3 = memId;
- aOp[8].p2 = memId;
+ aOp[6].p1 = memId;
+ aOp[7].p2 = memId+2;
+ aOp[7].p1 = memId;
+ aOp[10].p2 = memId;
+ if( pParse->nTab==0 ) pParse->nTab = 1;
}
}
@@ -107705,6 +121036,8 @@ static SQLITE_NOINLINE void autoIncrementEnd(Parse *pParse){
iRec = sqlite3GetTempReg(pParse);
assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
+ sqlite3VdbeAddOp3(v, OP_Le, memId+2, sqlite3VdbeCurrentAddr(v)+7, memId);
+ VdbeCoverage(v);
sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn);
if( aOp==0 ) break;
@@ -107841,13 +121174,13 @@ SQLITE_PRIVATE void sqlite3Insert(
Parse *pParse, /* Parser context */
SrcList *pTabList, /* Name of table into which we are inserting */
Select *pSelect, /* A SELECT statement to use as the data source */
- IdList *pColumn, /* Column names corresponding to IDLIST. */
- int onError /* How to handle constraint errors */
+ IdList *pColumn, /* Column names corresponding to IDLIST, or NULL. */
+ int onError, /* How to handle constraint errors */
+ Upsert *pUpsert /* ON CONFLICT clauses for upsert, or NULL */
){
sqlite3 *db; /* The main database structure */
Table *pTab; /* The table to insert into. aka TABLE */
- char *zTab; /* Name of the table into which we are inserting */
- int i, j, idx; /* Loop counters */
+ int i, j; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
int nColumn; /* Number of columns in the data */
@@ -107866,6 +121199,7 @@ SQLITE_PRIVATE void sqlite3Insert(
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
u8 bIdListInOrder; /* True if IDLIST is in table order */
ExprList *pList = 0; /* List of VALUES() to be inserted */
+ int iRegStore; /* Register in which to store next column */
/* Register allocations */
int regFromSelect = 0;/* Base register for data coming from SELECT */
@@ -107883,10 +121217,10 @@ SQLITE_PRIVATE void sqlite3Insert(
#endif
db = pParse->db;
- memset(&dest, 0, sizeof(dest));
if( pParse->nErr || db->mallocFailed ){
goto insert_cleanup;
}
+ dest.iSDParm = 0; /* Suppress a harmless compiler warning */
/* If the Select object is really just a simple VALUES() list with a
** single row (the common case) then keep that one row of values
@@ -107902,8 +121236,6 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Locate the table into which we will be inserting new information.
*/
assert( pTabList->nSrc==1 );
- zTab = pTabList->a[0].zName;
- if( NEVER(zTab==0) ) goto insert_cleanup;
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ){
goto insert_cleanup;
@@ -107975,8 +121307,8 @@ SQLITE_PRIVATE void sqlite3Insert(
*/
regAutoinc = autoIncBegin(pParse, iDb, pTab);
- /* Allocate registers for holding the rowid of the new row,
- ** the content of the new row, and the assembled row record.
+ /* Allocate a block registers to hold the rowid and the values
+ ** for all columns of the new row.
*/
regRowid = regIns = pParse->nMem+1;
pParse->nMem += pTab->nCol + 1;
@@ -107987,7 +121319,7 @@ SQLITE_PRIVATE void sqlite3Insert(
regData = regRowid+1;
/* If the INSERT statement included an IDLIST term, then make sure
- ** all elements of the IDLIST really are columns of the table and
+ ** all elements of the IDLIST really are columns of the table and
** remember the column indices.
**
** If the table has an INTEGER PRIMARY KEY column and that column
@@ -107995,9 +121327,17 @@ SQLITE_PRIVATE void sqlite3Insert(
** the index into IDLIST of the primary key column. ipkColumn is
** the index of the primary key as it appears in IDLIST, not as
** is appears in the original table. (The index of the INTEGER
- ** PRIMARY KEY in the original table is pTab->iPKey.)
+ ** PRIMARY KEY in the original table is pTab->iPKey.) After this
+ ** loop, if ipkColumn==(-1), that means that integer primary key
+ ** is unspecified, and hence the table is either WITHOUT ROWID or
+ ** it will automatically generated an integer primary key.
+ **
+ ** bIdListInOrder is true if the columns in IDLIST are in storage
+ ** order. This enables an optimization that avoids shuffling the
+ ** columns into storage order. False negatives are harmless,
+ ** but false positives will cause database corruption.
*/
- bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==0;
+ bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
if( pColumn ){
for(i=0; i<pColumn->nId; i++){
pColumn->a[i].idx = -1;
@@ -108010,6 +121350,14 @@ SQLITE_PRIVATE void sqlite3Insert(
if( j==pTab->iPKey ){
ipkColumn = i; assert( !withoutRowid );
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
+ sqlite3ErrorMsg(pParse,
+ "cannot INSERT into generated column \"%s\"",
+ pTab->aCol[j].zName);
+ goto insert_cleanup;
+ }
+#endif
break;
}
}
@@ -108059,7 +121407,7 @@ SQLITE_PRIVATE void sqlite3Insert(
** the destination table (template 3).
**
** A temp table must be used if the table being updated is also one
- ** of the tables being read by the SELECT statement. Also use a
+ ** of the tables being read by the SELECT statement. Also use a
** temp table in the case of row triggers.
*/
if( pTrigger || readsTable(pParse, iDb, pTab) ){
@@ -108095,7 +121443,7 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3ReleaseTempReg(pParse, regTempRowid);
}
}else{
- /* This is the case if the data for the INSERT is coming from a
+ /* This is the case if the data for the INSERT is coming from a
** single-row VALUES clause
*/
NameContext sNC;
@@ -108114,21 +121462,34 @@ SQLITE_PRIVATE void sqlite3Insert(
}
/* If there is no IDLIST term but the table has an integer primary
- ** key, the set the ipkColumn variable to the integer primary key
+ ** key, the set the ipkColumn variable to the integer primary key
** column index in the original table definition.
*/
if( pColumn==0 && nColumn>0 ){
ipkColumn = pTab->iPKey;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( ipkColumn>=0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ for(i=ipkColumn-1; i>=0; i--){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[i].colFlags & COLFLAG_STORED );
+ ipkColumn--;
+ }
+ }
+ }
+#endif
}
/* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table.
*/
for(i=0; i<pTab->nCol; i++){
- nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0);
+ if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
}
if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"table %S has %d columns but %d values were supplied",
pTabList, 0, pTab->nCol-nHidden, nColumn);
goto insert_cleanup;
@@ -108137,10 +121498,13 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
goto insert_cleanup;
}
-
+
/* Initialize the count of rows to be inserted
*/
- if( db->flags & SQLITE_CountRows ){
+ if( (db->flags & SQLITE_CountRows)!=0
+ && !pParse->nested
+ && !pParse->pTriggerTab
+ ){
regRowCount = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
@@ -108150,14 +121514,42 @@ SQLITE_PRIVATE void sqlite3Insert(
int nIdx;
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
&iDataCur, &iIdxCur);
- aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
+ aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+2));
if( aRegIdx==0 ){
goto insert_cleanup;
}
- for(i=0; i<nIdx; i++){
+ for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
+ assert( pIdx );
aRegIdx[i] = ++pParse->nMem;
+ pParse->nMem += pIdx->nColumn;
+ }
+ aRegIdx[i] = ++pParse->nMem; /* Register to store the table record */
+ }
+#ifndef SQLITE_OMIT_UPSERT
+ if( pUpsert ){
+ if( IsVirtual(pTab) ){
+ sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
+ pTab->zName);
+ goto insert_cleanup;
+ }
+ if( pTab->pSelect ){
+ sqlite3ErrorMsg(pParse, "cannot UPSERT a view");
+ goto insert_cleanup;
+ }
+ if( sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget) ){
+ goto insert_cleanup;
+ }
+ pTabList->a[0].iCursor = iDataCur;
+ pUpsert->pUpsertSrc = pTabList;
+ pUpsert->regData = regData;
+ pUpsert->iDataCur = iDataCur;
+ pUpsert->iIdxCur = iIdxCur;
+ if( pUpsert->pUpsertTarget ){
+ sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert);
}
}
+#endif
+
/* This is the top of the main insertion loop */
if( useTempTable ){
@@ -108181,13 +121573,94 @@ SQLITE_PRIVATE void sqlite3Insert(
** goto C
** D: ...
*/
+ sqlite3VdbeReleaseRegisters(pParse, regData, pTab->nCol, 0, 0);
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
VdbeCoverage(v);
+ if( ipkColumn>=0 ){
+ /* tag-20191021-001: If the INTEGER PRIMARY KEY is being generated by the
+ ** SELECT, go ahead and copy the value into the rowid slot now, so that
+ ** the value does not get overwritten by a NULL at tag-20191021-002. */
+ sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
+ }
+ }
+
+ /* Compute data for ordinary columns of the new entry. Values
+ ** are written in storage order into registers starting with regData.
+ ** Only ordinary columns are computed in this loop. The rowid
+ ** (if there is one) is computed later and generated columns are
+ ** computed after the rowid since they might depend on the value
+ ** of the rowid.
+ */
+ nHidden = 0;
+ iRegStore = regData; assert( regData==regRowid+1 );
+ for(i=0; i<pTab->nCol; i++, iRegStore++){
+ int k;
+ u32 colFlags;
+ assert( i>=nHidden );
+ if( i==pTab->iPKey ){
+ /* tag-20191021-002: References to the INTEGER PRIMARY KEY are filled
+ ** using the rowid. So put a NULL in the IPK slot of the record to avoid
+ ** using excess space. The file format definition requires this extra
+ ** NULL - we cannot optimize further by skipping the column completely */
+ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
+ continue;
+ }
+ if( ((colFlags = pTab->aCol[i].colFlags) & COLFLAG_NOINSERT)!=0 ){
+ nHidden++;
+ if( (colFlags & COLFLAG_VIRTUAL)!=0 ){
+ /* Virtual columns do not participate in OP_MakeRecord. So back up
+ ** iRegStore by one slot to compensate for the iRegStore++ in the
+ ** outer for() loop */
+ iRegStore--;
+ continue;
+ }else if( (colFlags & COLFLAG_STORED)!=0 ){
+ /* Stored columns are computed later. But if there are BEFORE
+ ** triggers, the slots used for stored columns will be OP_Copy-ed
+ ** to a second block of registers, so the register needs to be
+ ** initialized to NULL to avoid an uninitialized register read */
+ if( tmask & TRIGGER_BEFORE ){
+ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
+ }
+ continue;
+ }else if( pColumn==0 ){
+ /* Hidden columns that are not explicitly named in the INSERT
+ ** get there default value */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }
+ }
+ if( pColumn ){
+ for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){}
+ if( j>=pColumn->nId ){
+ /* A column not named in the insert column list gets its
+ ** default value */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }
+ k = j;
+ }else if( nColumn==0 ){
+ /* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */
+ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
+ continue;
+ }else{
+ k = i - nHidden;
+ }
+
+ if( useTempTable ){
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
+ }else if( pSelect ){
+ if( regFromSelect!=regData ){
+ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
+ }
+ }else{
+ sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
+ }
}
+
/* Run the BEFORE and INSTEAD OF triggers, if there are any
*/
- endOfLoop = sqlite3VdbeMakeLabel(v);
+ endOfLoop = sqlite3VdbeMakeLabel(pParse);
if( tmask & TRIGGER_BEFORE ){
int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1);
@@ -108219,25 +121692,21 @@ SQLITE_PRIVATE void sqlite3Insert(
*/
assert( !IsVirtual(pTab) );
- /* Create the new column data
- */
- for(i=j=0; i<pTab->nCol; i++){
- if( pColumn ){
- for(j=0; j<pColumn->nId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
- }
- if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId)
- || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
- }else if( useTempTable ){
- sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
- }else{
- assert( pSelect==0 ); /* Otherwise useTempTable is true */
- sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1);
- }
- if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++;
+ /* Copy the new data already generated. */
+ assert( pTab->nNVCol>0 );
+ sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Compute the new value for generated columns after all other
+ ** columns have already been computed. This must be done after
+ ** computing the ROWID in case one of the generated columns
+ ** refers to the ROWID. */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regCols+1, pTab);
}
+#endif
/* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
** do not attempt any conversions before assembling the record.
@@ -108249,35 +121718,30 @@ SQLITE_PRIVATE void sqlite3Insert(
}
/* Fire BEFORE or INSTEAD OF triggers */
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
pTab, regCols-pTab->nCol-1, onError, endOfLoop);
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
}
- /* Compute the content of the next row to insert into a range of
- ** registers beginning at regIns.
- */
if( !isView ){
if( IsVirtual(pTab) ){
/* The row that the VUpdate opcode will delete: none */
sqlite3VdbeAddOp2(v, OP_Null, 0, regIns);
}
if( ipkColumn>=0 ){
+ /* Compute the new rowid */
if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid);
}else if( pSelect ){
- sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid);
+ /* Rowid already initialized at tag-20191021-001 */
}else{
- VdbeOp *pOp;
- sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
- pOp = sqlite3VdbeGetOp(v, -1);
- if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
+ Expr *pIpk = pList->a[ipkColumn].pExpr;
+ if( pIpk->op==TK_NULL && !IsVirtual(pTab) ){
+ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
appendFlag = 1;
- pOp->opcode = OP_NewRowid;
- pOp->p1 = iDataCur;
- pOp->p2 = regRowid;
- pOp->p3 = regAutoinc;
+ }else{
+ sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regRowid);
}
}
/* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
@@ -108303,45 +121767,15 @@ SQLITE_PRIVATE void sqlite3Insert(
}
autoIncStep(pParse, regAutoinc, regRowid);
- /* Compute data for all columns of the new entry, beginning
- ** with the first column.
- */
- nHidden = 0;
- for(i=0; i<pTab->nCol; i++){
- int iRegStore = regRowid+1+i;
- if( i==pTab->iPKey ){
- /* The value of the INTEGER PRIMARY KEY column is always a NULL.
- ** Whenever this column is read, the rowid will be substituted
- ** in its place. Hence, fill this column with a NULL to avoid
- ** taking up data space with information that will never be used.
- ** As there may be shallow copies of this value, make it a soft-NULL */
- sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore);
- continue;
- }
- if( pColumn==0 ){
- if( IsHiddenColumn(&pTab->aCol[i]) ){
- j = -1;
- nHidden++;
- }else{
- j = i - nHidden;
- }
- }else{
- for(j=0; j<pColumn->nId; j++){
- if( pColumn->a[j].idx==i ) break;
- }
- }
- if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){
- sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
- }else if( useTempTable ){
- sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore);
- }else if( pSelect ){
- if( regFromSelect!=regData ){
- sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore);
- }
- }else{
- sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore);
- }
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Compute the new value for generated columns after all other
+ ** columns have already been computed. This must be done after
+ ** computing the ROWID in case one of the generated columns
+ ** is derived from the INTEGER PRIMARY KEY. */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ sqlite3ComputeGeneratedColumns(pParse, regRowid+1, pTab);
}
+#endif
/* Generate code to check constraints and generate index keys and
** do the insertion.
@@ -108357,24 +121791,36 @@ SQLITE_PRIVATE void sqlite3Insert(
#endif
{
int isReplace; /* Set to true if constraints may cause a replace */
+ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
- regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
+ regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+
+ /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
+ ** constraints or (b) there are no triggers and this table is not a
+ ** parent table in a foreign key constraint. It is safe to set the
+ ** flag in the second case as if any REPLACE constraint is hit, an
+ ** OP_Delete or OP_IdxDelete instruction will be executed on each
+ ** cursor that is disturbed. And these instructions both clear the
+ ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
+ ** functionality. */
+ bUseSeek = (isReplace==0 || !sqlite3VdbeHasSubProgram(v));
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
- regIns, aRegIdx, 0, appendFlag, isReplace==0);
+ regIns, aRegIdx, 0, appendFlag, bUseSeek
+ );
}
}
/* Update the count of rows that are inserted
*/
- if( (db->flags & SQLITE_CountRows)!=0 ){
+ if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
if( pTrigger ){
/* Code AFTER triggers */
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
pTab, regData-2-pTab->nCol, onError, endOfLoop);
}
@@ -108388,15 +121834,16 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3VdbeAddOp1(v, OP_Close, srcTab);
}else if( pSelect ){
sqlite3VdbeGoto(v, addrCont);
- sqlite3VdbeJumpHere(v, addrInsTop);
- }
-
- if( !IsVirtual(pTab) && !isView ){
- /* Close all tables opened */
- if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
- for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
+#ifdef SQLITE_DEBUG
+ /* If we are jumping back to an OP_Yield that is preceded by an
+ ** OP_ReleaseReg, set the p5 flag on the OP_Goto so that the
+ ** OP_ReleaseReg will be included in the loop. */
+ if( sqlite3VdbeGetOp(v, addrCont-1)->opcode==OP_ReleaseReg ){
+ assert( sqlite3VdbeGetOp(v, addrCont)->opcode==OP_Yield );
+ sqlite3VdbeChangeP5(v, 1);
}
+#endif
+ sqlite3VdbeJumpHere(v, addrInsTop);
}
insert_end:
@@ -108409,11 +121856,11 @@ insert_end:
}
/*
- ** Return the number of rows inserted. If this routine is
+ ** Return the number of rows inserted. If this routine is
** generating code because of a call to sqlite3NestedParse(), do not
** invoke the callback function.
*/
- if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){
+ if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC);
@@ -108422,6 +121869,7 @@ insert_end:
insert_cleanup:
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pList);
+ sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn);
sqlite3DbFree(db, aRegIdx);
@@ -108441,14 +121889,15 @@ insert_cleanup:
#endif
/*
-** Meanings of bits in of pWalker->eCode for checkConstraintUnchanged()
+** Meanings of bits in of pWalker->eCode for
+** sqlite3ExprReferencesUpdatedColumn()
*/
#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */
#define CKCNSTRNT_ROWID 0x02 /* CHECK constraint references the ROWID */
-/* This is the Walker callback from checkConstraintUnchanged(). Set
-** bit 0x01 of pWalker->eCode if
-** pWalker->eCode to 0 if this expression node references any of the
+/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn().
+* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
+** expression node references any of the
** columns that are being modifed by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
@@ -108470,12 +121919,21 @@ static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
** only columns that are modified by the UPDATE are those for which
** aiChng[i]>=0, and also the ROWID is modified if chngRowid is true.
**
-** Return true if CHECK constraint pExpr does not use any of the
+** Return true if CHECK constraint pExpr uses any of the
** changing columns (or the rowid if it is changing). In other words,
-** return true if this CHECK constraint can be skipped when validating
+** return true if this CHECK constraint must be validated for
** the new row in the UPDATE statement.
+**
+** 2018-09-15: pExpr might also be an expression for an index-on-expressions.
+** The operation of this routine is the same - return true if an only if
+** the expression uses one or more of columns identified by the second and
+** third arguments.
*/
-static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
+SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(
+ Expr *pExpr, /* The expression to be checked */
+ int *aiChng, /* aiChng[x]>=0 if column x changed by the UPDATE */
+ int chngRowid /* True if UPDATE changes the rowid */
+){
Walker w;
memset(&w, 0, sizeof(w));
w.eCode = 0;
@@ -108490,7 +121948,7 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
testcase( w.eCode==CKCNSTRNT_COLUMN );
testcase( w.eCode==CKCNSTRNT_ROWID );
testcase( w.eCode==(CKCNSTRNT_ROWID|CKCNSTRNT_COLUMN) );
- return !w.eCode;
+ return w.eCode!=0;
}
/*
@@ -108528,6 +121986,14 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
** the same as the order of indices on the linked list of indices
** at pTab->pIndex.
**
+** (2019-05-07) The generated code also creates a new record for the
+** main table, if pTab is a rowid table, and stores that record in the
+** register identified by aRegIdx[nIdx] - in other words in the first
+** entry of aRegIdx[] past the last index. It is important that the
+** record be generated during constraint checks to avoid affinity changes
+** to the register content that occur after constraint checks but before
+** the new record is inserted.
+**
** The caller must have already opened writeable cursors on the main
** table and all applicable indices (that is to say, all indices for which
** aRegIdx[] is not zero). iDataCur is the cursor for the main table when
@@ -108588,7 +122054,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
u8 overrideError, /* Override onError to this if not OE_Default */
int ignoreDest, /* Jump to this label on an OE_Ignore resolution */
int *pbMayReplace, /* OUT: Set to true if constraint may cause a replace */
- int *aiChng /* column i is unchanged if aiChng[i]<0 */
+ int *aiChng, /* column i is unchanged if aiChng[i]<0 */
+ Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */
){
Vdbe *v; /* VDBE under constrution */
Index *pIdx; /* Pointer to one of the indices */
@@ -108598,14 +122065,22 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int ix; /* Index loop counter */
int nCol; /* Number of columns */
int onError; /* Conflict resolution strategy */
- int addr1; /* Address of jump instruction */
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
- int ipkTop = 0; /* Top of the rowid change constraint check */
- int ipkBottom = 0; /* Bottom of the rowid change constraint check */
+ Index *pUpIdx = 0; /* Index to which to apply the upsert */
u8 isUpdate; /* True if this is an UPDATE operation */
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
- int regRowid = -1; /* Register holding ROWID value */
+ int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
+ int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
+ int ipkTop = 0; /* Top of the IPK uniqueness check */
+ int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
+ /* Variables associated with retesting uniqueness constraints after
+ ** replace triggers fire have run */
+ int regTrigCnt; /* Register used to count replace trigger invocations */
+ int addrRecheck = 0; /* Jump here to recheck all uniqueness constraints */
+ int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */
+ Trigger *pTrigger; /* List of DELETE triggers on the table pTab */
+ int nReplaceTrig = 0; /* Number of replace triggers coded */
isUpdate = regOldData!=0;
db = pParse->db;
@@ -108613,9 +122088,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
nCol = pTab->nCol;
-
+
/* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
- ** normal rowid tables. nPkField is the number of key fields in the
+ ** normal rowid tables. nPkField is the number of key fields in the
** pPk index or 1 for a rowid table. In other words, nPkField is the
** number of fields in the true primary key of the table. */
if( HasRowid(pTab) ){
@@ -108632,89 +122107,242 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
/* Test all NOT NULL constraints.
*/
- for(i=0; i<nCol; i++){
- if( i==pTab->iPKey ){
- continue; /* ROWID is never NULL */
- }
- if( aiChng && aiChng[i]<0 ){
- /* Don't bother checking for NOT NULL on columns that do not change */
- continue;
- }
- onError = pTab->aCol[i].notNull;
- if( onError==OE_None ) continue; /* This column is allowed to be NULL */
- if( overrideError!=OE_Default ){
- onError = overrideError;
- }else if( onError==OE_Default ){
- onError = OE_Abort;
- }
- if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){
- onError = OE_Abort;
- }
- assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
- || onError==OE_Ignore || onError==OE_Replace );
- switch( onError ){
- case OE_Abort:
- sqlite3MayAbort(pParse);
- /* Fall through */
- case OE_Rollback:
- case OE_Fail: {
- char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
- pTab->aCol[i].zName);
- sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
- regNewData+1+i, zMsg, P4_DYNAMIC);
- sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
- VdbeCoverage(v);
- break;
- }
- case OE_Ignore: {
- sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest);
- VdbeCoverage(v);
+ if( pTab->tabFlags & TF_HasNotNull ){
+ int b2ndPass = 0; /* True if currently running 2nd pass */
+ int nSeenReplace = 0; /* Number of ON CONFLICT REPLACE operations */
+ int nGenerated = 0; /* Number of generated columns with NOT NULL */
+ while(1){ /* Make 2 passes over columns. Exit loop via "break" */
+ for(i=0; i<nCol; i++){
+ int iReg; /* Register holding column value */
+ Column *pCol = &pTab->aCol[i]; /* The column to check for NOT NULL */
+ int isGenerated; /* non-zero if column is generated */
+ onError = pCol->notNull;
+ if( onError==OE_None ) continue; /* No NOT NULL on this column */
+ if( i==pTab->iPKey ){
+ continue; /* ROWID is never NULL */
+ }
+ isGenerated = pCol->colFlags & COLFLAG_GENERATED;
+ if( isGenerated && !b2ndPass ){
+ nGenerated++;
+ continue; /* Generated columns processed on 2nd pass */
+ }
+ if( aiChng && aiChng[i]<0 && !isGenerated ){
+ /* Do not check NOT NULL on columns that do not change */
+ continue;
+ }
+ if( overrideError!=OE_Default ){
+ onError = overrideError;
+ }else if( onError==OE_Default ){
+ onError = OE_Abort;
+ }
+ if( onError==OE_Replace ){
+ if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */
+ || pCol->pDflt==0 /* REPLACE is ABORT if no DEFAULT value */
+ ){
+ testcase( pCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pCol->colFlags & COLFLAG_STORED );
+ testcase( pCol->colFlags & COLFLAG_GENERATED );
+ onError = OE_Abort;
+ }else{
+ assert( !isGenerated );
+ }
+ }else if( b2ndPass && !isGenerated ){
+ continue;
+ }
+ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
+ || onError==OE_Ignore || onError==OE_Replace );
+ testcase( i!=sqlite3TableColumnToStorage(pTab, i) );
+ iReg = sqlite3TableColumnToStorage(pTab, i) + regNewData + 1;
+ switch( onError ){
+ case OE_Replace: {
+ int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, iReg);
+ VdbeCoverage(v);
+ assert( (pCol->colFlags & COLFLAG_GENERATED)==0 );
+ nSeenReplace++;
+ sqlite3ExprCodeCopy(pParse, pCol->pDflt, iReg);
+ sqlite3VdbeJumpHere(v, addr1);
+ break;
+ }
+ case OE_Abort:
+ sqlite3MayAbort(pParse);
+ /* no break */ deliberate_fall_through
+ case OE_Rollback:
+ case OE_Fail: {
+ char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
+ pCol->zName);
+ sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
+ onError, iReg);
+ sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
+ sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
+ VdbeCoverage(v);
+ break;
+ }
+ default: {
+ assert( onError==OE_Ignore );
+ sqlite3VdbeAddOp2(v, OP_IsNull, iReg, ignoreDest);
+ VdbeCoverage(v);
+ break;
+ }
+ } /* end switch(onError) */
+ } /* end loop i over columns */
+ if( nGenerated==0 && nSeenReplace==0 ){
+ /* If there are no generated columns with NOT NULL constraints
+ ** and no NOT NULL ON CONFLICT REPLACE constraints, then a single
+ ** pass is sufficient */
break;
}
- default: {
- assert( onError==OE_Replace );
- addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
- VdbeCoverage(v);
- sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
- sqlite3VdbeJumpHere(v, addr1);
- break;
+ if( b2ndPass ) break; /* Never need more than 2 passes */
+ b2ndPass = 1;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( nSeenReplace>0 && (pTab->tabFlags & TF_HasGenerated)!=0 ){
+ /* If any NOT NULL ON CONFLICT REPLACE constraints fired on the
+ ** first pass, recomputed values for all generated columns, as
+ ** those values might depend on columns affected by the REPLACE.
+ */
+ sqlite3ComputeGeneratedColumns(pParse, regNewData+1, pTab);
}
- }
- }
+#endif
+ } /* end of 2-pass loop */
+ } /* end if( has-not-null-constraints ) */
/* Test all CHECK constraints
*/
#ifndef SQLITE_OMIT_CHECK
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
ExprList *pCheck = pTab->pCheck;
- pParse->ckBase = regNewData+1;
+ pParse->iSelfTab = -(regNewData+1);
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
for(i=0; i<pCheck->nExpr; i++){
int allOk;
+ Expr *pCopy;
Expr *pExpr = pCheck->a[i].pExpr;
- if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
- allOk = sqlite3VdbeMakeLabel(v);
- sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
+ if( aiChng
+ && !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng)
+ ){
+ /* The check constraints do not reference any of the columns being
+ ** updated so there is no point it verifying the check constraint */
+ continue;
+ }
+ if( bAffinityDone==0 ){
+ sqlite3TableAffinity(v, pTab, regNewData+1);
+ bAffinityDone = 1;
+ }
+ allOk = sqlite3VdbeMakeLabel(pParse);
+ sqlite3VdbeVerifyAbortable(v, onError);
+ pCopy = sqlite3ExprDup(db, pExpr, 0);
+ if( !db->mallocFailed ){
+ sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL);
+ }
+ sqlite3ExprDelete(db, pCopy);
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
}else{
- char *zName = pCheck->a[i].zName;
+ char *zName = pCheck->a[i].zEName;
if( zName==0 ) zName = pTab->zName;
- if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
+ if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
onError, zName, P4_TRANSIENT,
P5_ConstraintCheck);
}
sqlite3VdbeResolveLabel(v, allOk);
}
+ pParse->iSelfTab = 0;
}
#endif /* !defined(SQLITE_OMIT_CHECK) */
+ /* UNIQUE and PRIMARY KEY constraints should be handled in the following
+ ** order:
+ **
+ ** (1) OE_Update
+ ** (2) OE_Abort, OE_Fail, OE_Rollback, OE_Ignore
+ ** (3) OE_Replace
+ **
+ ** OE_Fail and OE_Ignore must happen before any changes are made.
+ ** OE_Update guarantees that only a single row will change, so it
+ ** must happen before OE_Replace. Technically, OE_Abort and OE_Rollback
+ ** could happen in any order, but they are grouped up front for
+ ** convenience.
+ **
+ ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
+ ** The order of constraints used to have OE_Update as (2) and OE_Abort
+ ** and so forth as (1). But apparently PostgreSQL checks the OE_Update
+ ** constraint before any others, so it had to be moved.
+ **
+ ** Constraint checking code is generated in this order:
+ ** (A) The rowid constraint
+ ** (B) Unique index constraints that do not have OE_Replace as their
+ ** default conflict resolution strategy
+ ** (C) Unique index that do use OE_Replace by default.
+ **
+ ** The ordering of (2) and (3) is accomplished by making sure the linked
+ ** list of indexes attached to a table puts all OE_Replace indexes last
+ ** in the list. See sqlite3CreateIndex() for where that happens.
+ */
+
+ if( pUpsert ){
+ if( pUpsert->pUpsertTarget==0 ){
+ /* An ON CONFLICT DO NOTHING clause, without a constraint-target.
+ ** Make all unique constraint resolution be OE_Ignore */
+ assert( pUpsert->pUpsertSet==0 );
+ overrideError = OE_Ignore;
+ pUpsert = 0;
+ }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
+ /* If the constraint-target uniqueness check must be run first.
+ ** Jump to that uniqueness check now */
+ upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
+ VdbeComment((v, "UPSERT constraint goes first"));
+ }
+ }
+
+ /* Determine if it is possible that triggers (either explicitly coded
+ ** triggers or FK resolution actions) might run as a result of deletes
+ ** that happen when OE_Replace conflict resolution occurs. (Call these
+ ** "replace triggers".) If any replace triggers run, we will need to
+ ** recheck all of the uniqueness constraints after they have all run.
+ ** But on the recheck, the resolution is OE_Abort instead of OE_Replace.
+ **
+ ** If replace triggers are a possibility, then
+ **
+ ** (1) Allocate register regTrigCnt and initialize it to zero.
+ ** That register will count the number of replace triggers that
+ ** fire. Constraint recheck only occurs if the number is positive.
+ ** (2) Initialize pTrigger to the list of all DELETE triggers on pTab.
+ ** (3) Initialize addrRecheck and lblRecheckOk
+ **
+ ** The uniqueness rechecking code will create a series of tests to run
+ ** in a second pass. The addrRecheck and lblRecheckOk variables are
+ ** used to link together these tests which are separated from each other
+ ** in the generate bytecode.
+ */
+ if( (db->flags & (SQLITE_RecTriggers|SQLITE_ForeignKeys))==0 ){
+ /* There are not DELETE triggers nor FK constraints. No constraint
+ ** rechecks are needed. */
+ pTrigger = 0;
+ regTrigCnt = 0;
+ }else{
+ if( db->flags&SQLITE_RecTriggers ){
+ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
+ regTrigCnt = pTrigger!=0 || sqlite3FkRequired(pParse, pTab, 0, 0);
+ }else{
+ pTrigger = 0;
+ regTrigCnt = sqlite3FkRequired(pParse, pTab, 0, 0);
+ }
+ if( regTrigCnt ){
+ /* Replace triggers might exist. Allocate the counter and
+ ** initialize it to zero. */
+ regTrigCnt = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regTrigCnt);
+ VdbeComment((v, "trigger count"));
+ lblRecheckOk = sqlite3VdbeMakeLabel(pParse);
+ addrRecheck = lblRecheckOk;
+ }
+ }
+
/* If rowid is changing, make sure the new rowid does not previously
** exist in the table.
*/
if( pkChng && pPk==0 ){
- int addrRowidOk = sqlite3VdbeMakeLabel(v);
+ int addrRowidOk = sqlite3VdbeMakeLabel(pParse);
/* Figure out what action to take in case of a rowid collision */
onError = pTab->keyConf;
@@ -108724,13 +122352,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
onError = OE_Abort;
}
- if( isUpdate ){
- /* pkChng!=0 does not mean that the rowid has change, only that
- ** it might have changed. Skip the conflict logic below if the rowid
- ** is unchanged. */
- sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
- sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
- VdbeCoverage(v);
+ /* figure out whether or not upsert applies in this case */
+ if( pUpsert && pUpsert->pUpsertIdx==0 ){
+ if( pUpsert->pUpsertSet==0 ){
+ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
+ }else{
+ onError = OE_Update; /* DO UPDATE */
+ }
}
/* If the response to a rowid conflict is REPLACE but the response
@@ -108738,29 +122366,41 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
** to defer the running of the rowid conflict checking until after
** the UNIQUE constraints have run.
*/
- if( onError==OE_Replace && overrideError!=OE_Replace ){
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_Ignore || pIdx->onError==OE_Fail ){
- ipkTop = sqlite3VdbeAddOp0(v, OP_Goto);
- break;
- }
- }
+ if( onError==OE_Replace /* IPK rule is REPLACE */
+ && onError!=overrideError /* Rules for other contraints are different */
+ && pTab->pIndex /* There exist other constraints */
+ ){
+ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
+ VdbeComment((v, "defer IPK REPLACE until last"));
+ }
+
+ if( isUpdate ){
+ /* pkChng!=0 does not mean that the rowid has changed, only that
+ ** it might have changed. Skip the conflict logic below if the rowid
+ ** is unchanged. */
+ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
+ sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
+ VdbeCoverage(v);
}
/* Check to see if the new rowid already exists in the table. Skip
** the following conflict logic if it does not. */
+ VdbeNoopComment((v, "uniqueness check for ROWID"));
+ sqlite3VdbeVerifyAbortable(v, onError);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
VdbeCoverage(v);
- /* Generate code that deals with a rowid collision */
switch( onError ){
default: {
onError = OE_Abort;
- /* Fall thru into the next case */
+ /* no break */ deliberate_fall_through
}
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
+ testcase( onError==OE_Rollback );
+ testcase( onError==OE_Abort );
+ testcase( onError==OE_Fail );
sqlite3RowidConstraint(pParse, onError, pTab);
break;
}
@@ -108771,10 +122411,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
** the triggers and remove both the table and index b-tree entries.
**
** Otherwise, if there are no triggers or the recursive-triggers
- ** flag is not set, but the table has one or more indexes, call
- ** GenerateRowIndexDelete(). This removes the index b-tree entries
- ** only. The table b-tree entry will be replaced by the new entry
- ** when it is inserted.
+ ** flag is not set, but the table has one or more indexes, call
+ ** GenerateRowIndexDelete(). This removes the index b-tree entries
+ ** only. The table b-tree entry will be replaced by the new entry
+ ** when it is inserted.
**
** If either GenerateRowDelete() or GenerateRowIndexDelete() is called,
** also invoke MultiWrite() to indicate that this VDBE may require
@@ -108787,24 +122427,21 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
** to run without a statement journal if there are no indexes on the
** table.
*/
- Trigger *pTrigger = 0;
- if( db->flags&SQLITE_RecTriggers ){
- pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
- }
- if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
+ if( regTrigCnt ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regNewData, 1, 0, OE_Replace, 1, -1);
+ sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */
+ nReplaceTrig++;
}else{
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- if( HasRowid(pTab) ){
- /* This OP_Delete opcode fires the pre-update-hook only. It does
- ** not modify the b-tree. It is more efficient to let the coming
- ** OP_Insert replace the existing entry than it is to delete the
- ** existing entry and then insert a new one. */
- sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
- sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
- }
+ assert( HasRowid(pTab) );
+ /* This OP_Delete opcode fires the pre-update-hook only. It does
+ ** not modify the b-tree. It is more efficient to let the coming
+ ** OP_Insert replace the existing entry than it is to delete the
+ ** existing entry and then insert a new one. */
+ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
if( pTab->pIndex ){
sqlite3MultiWrite(pParse);
@@ -108814,8 +122451,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
seenReplace = 1;
break;
}
+#ifndef SQLITE_OMIT_UPSERT
+ case OE_Update: {
+ sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
+ /* no break */ deliberate_fall_through
+ }
+#endif
case OE_Ignore: {
- /*assert( seenReplace==0 );*/
+ testcase( onError==OE_Ignore );
sqlite3VdbeGoto(v, ignoreDest);
break;
}
@@ -108823,7 +122466,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
sqlite3VdbeResolveLabel(v, addrRowidOk);
if( ipkTop ){
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
- sqlite3VdbeJumpHere(v, ipkTop);
+ sqlite3VdbeJumpHere(v, ipkTop-1);
}
}
@@ -108839,53 +122482,67 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int regR; /* Range of registers holding conflicting PK */
int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
+ int addrConflictCk; /* First opcode in the conflict check logic */
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
- if( bAffinityDone==0 ){
+ if( pUpIdx==pIdx ){
+ addrUniqueOk = upsertJump+1;
+ upsertBypass = sqlite3VdbeGoto(v, 0);
+ VdbeComment((v, "Skip upsert subroutine"));
+ sqlite3VdbeJumpHere(v, upsertJump);
+ }else{
+ addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
+ }
+ if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
+ VdbeNoopComment((v, "prep index %s", pIdx->zName));
iThisCur = iIdxCur+ix;
- addrUniqueOk = sqlite3VdbeMakeLabel(v);
+
/* Skip partial indices for which the WHERE clause is not true */
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
- pParse->ckBase = regNewData+1;
+ pParse->iSelfTab = -(regNewData+1);
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
SQLITE_JUMPIFNULL);
- pParse->ckBase = 0;
+ pParse->iSelfTab = 0;
}
/* Create a record for this index entry as it should appear after
** the insert or update. Store that record in the aRegIdx[ix] register
*/
- regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
+ regIdx = aRegIdx[ix]+1;
for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i];
int x;
if( iField==XN_EXPR ){
- pParse->ckBase = regNewData+1;
+ pParse->iSelfTab = -(regNewData+1);
sqlite3ExprCodeCopy(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
- pParse->ckBase = 0;
+ pParse->iSelfTab = 0;
VdbeComment((v, "%s column %d", pIdx->zName, i));
+ }else if( iField==XN_ROWID || iField==pTab->iPKey ){
+ x = regNewData;
+ sqlite3VdbeAddOp2(v, OP_IntCopy, x, regIdx+i);
+ VdbeComment((v, "rowid"));
}else{
- if( iField==XN_ROWID || iField==pTab->iPKey ){
- if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
- x = regNewData;
- regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
- }else{
- x = iField + regNewData + 1;
- }
- sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i);
- VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
+ testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField );
+ x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1;
+ sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
+ VdbeComment((v, "%s", pTab->aCol[iField].zName));
}
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
VdbeComment((v, "for %s", pIdx->zName));
- sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
+#ifdef SQLITE_ENABLE_NULL_TRIM
+ if( pIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
+ sqlite3SetMakeRecordP5(v, pIdx->pTable);
+ }
+#endif
+ sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0);
- /* In an UPDATE operation, if this index is the PRIMARY KEY index
+ /* In an UPDATE operation, if this index is the PRIMARY KEY index
** of a WITHOUT ROWID table and there has been no change the
** primary key, then no collision is possible. The collision detection
** logic below can all be skipped. */
@@ -108896,8 +122553,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
/* Find out what action to take in case there is a uniqueness conflict */
onError = pIdx->onError;
- if( onError==OE_None ){
- sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
+ if( onError==OE_None ){
sqlite3VdbeResolveLabel(v, addrUniqueOk);
continue; /* pIdx is not a UNIQUE index */
}
@@ -108906,10 +122562,45 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}else if( onError==OE_Default ){
onError = OE_Abort;
}
-
+
+ /* Figure out if the upsert clause applies to this index */
+ if( pUpIdx==pIdx ){
+ if( pUpsert->pUpsertSet==0 ){
+ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
+ }else{
+ onError = OE_Update; /* DO UPDATE */
+ }
+ }
+
+ /* Collision detection may be omitted if all of the following are true:
+ ** (1) The conflict resolution algorithm is REPLACE
+ ** (2) The table is a WITHOUT ROWID table
+ ** (3) There are no secondary indexes on the table
+ ** (4) No delete triggers need to be fired if there is a conflict
+ ** (5) No FK constraint counters need to be updated if a conflict occurs.
+ **
+ ** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row
+ ** must be explicitly deleted in order to ensure any pre-update hook
+ ** is invoked. */
+#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
+ if( (ix==0 && pIdx->pNext==0) /* Condition 3 */
+ && pPk==pIdx /* Condition 2 */
+ && onError==OE_Replace /* Condition 1 */
+ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */
+ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
+ && ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */
+ (0==pTab->pFKey && 0==sqlite3FkReferences(pTab)))
+ ){
+ sqlite3VdbeResolveLabel(v, addrUniqueOk);
+ continue;
+ }
+#endif /* ifndef SQLITE_ENABLE_PREUPDATE_HOOK */
+
/* Check to see if the new index entry will be unique */
- sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
- regIdx, pIdx->nKeyCol); VdbeCoverage(v);
+ sqlite3VdbeVerifyAbortable(v, onError);
+ addrConflictCk =
+ sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
+ regIdx, pIdx->nKeyCol); VdbeCoverage(v);
/* Generate code to handle collisions */
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
@@ -108930,14 +122621,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
if( pIdx!=pPk ){
for(i=0; i<pPk->nKeyCol; i++){
assert( pPk->aiColumn[i]>=0 );
- x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
+ x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
VdbeComment((v, "%s.%s", pTab->zName,
pTab->aCol[pPk->aiColumn[i]].zName));
}
}
if( isUpdate ){
- /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
+ /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
** table, only conflict if the new PRIMARY KEY values are actually
** different from the old.
**
@@ -108947,7 +122638,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
int op = OP_Ne;
int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR);
-
+
for(i=0; i<pPk->nKeyCol; i++){
char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
x = pPk->aiColumn[i];
@@ -108956,7 +122647,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
addrJump = addrUniqueOk;
op = OP_Eq;
}
- sqlite3VdbeAddOp4(v, op,
+ x = sqlite3TableColumnToStorage(pTab, x);
+ sqlite3VdbeAddOp4(v, op,
regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
);
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
@@ -108969,45 +122661,172 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
/* Generate code that executes if the new index entry is not unique */
assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
- || onError==OE_Ignore || onError==OE_Replace );
+ || onError==OE_Ignore || onError==OE_Replace || onError==OE_Update );
switch( onError ){
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
+ testcase( onError==OE_Rollback );
+ testcase( onError==OE_Abort );
+ testcase( onError==OE_Fail );
sqlite3UniqueConstraint(pParse, onError, pIdx);
break;
}
+#ifndef SQLITE_OMIT_UPSERT
+ case OE_Update: {
+ sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
+ /* no break */ deliberate_fall_through
+ }
+#endif
case OE_Ignore: {
+ testcase( onError==OE_Ignore );
sqlite3VdbeGoto(v, ignoreDest);
break;
}
default: {
- Trigger *pTrigger = 0;
+ int nConflictCk; /* Number of opcodes in conflict check logic */
+
assert( onError==OE_Replace );
- sqlite3MultiWrite(pParse);
- if( db->flags&SQLITE_RecTriggers ){
- pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
+ nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
+ assert( nConflictCk>0 );
+ testcase( nConflictCk>1 );
+ if( regTrigCnt ){
+ sqlite3MultiWrite(pParse);
+ nReplaceTrig++;
+ }
+ if( pTrigger && isUpdate ){
+ sqlite3VdbeAddOp1(v, OP_CursorLock, iDataCur);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regR, nPkField, 0, OE_Replace,
- (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
+ (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
+ if( pTrigger && isUpdate ){
+ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur);
+ }
+ if( regTrigCnt ){
+ int addrBypass; /* Jump destination to bypass recheck logic */
+
+ sqlite3VdbeAddOp2(v, OP_AddImm, regTrigCnt, 1); /* incr trigger cnt */
+ addrBypass = sqlite3VdbeAddOp0(v, OP_Goto); /* Bypass recheck */
+ VdbeComment((v, "bypass recheck"));
+
+ /* Here we insert code that will be invoked after all constraint
+ ** checks have run, if and only if one or more replace triggers
+ ** fired. */
+ sqlite3VdbeResolveLabel(v, lblRecheckOk);
+ lblRecheckOk = sqlite3VdbeMakeLabel(pParse);
+ if( pIdx->pPartIdxWhere ){
+ /* Bypass the recheck if this partial index is not defined
+ ** for the current row */
+ sqlite3VdbeAddOp2(v, OP_IsNull, regIdx-1, lblRecheckOk);
+ VdbeCoverage(v);
+ }
+ /* Copy the constraint check code from above, except change
+ ** the constraint-ok jump destination to be the address of
+ ** the next retest block */
+ while( nConflictCk>0 ){
+ VdbeOp x; /* Conflict check opcode to copy */
+ /* The sqlite3VdbeAddOp4() call might reallocate the opcode array.
+ ** Hence, make a complete copy of the opcode, rather than using
+ ** a pointer to the opcode. */
+ x = *sqlite3VdbeGetOp(v, addrConflictCk);
+ if( x.opcode!=OP_IdxRowid ){
+ int p2; /* New P2 value for copied conflict check opcode */
+ const char *zP4;
+ if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){
+ p2 = lblRecheckOk;
+ }else{
+ p2 = x.p2;
+ }
+ zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z;
+ sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type);
+ sqlite3VdbeChangeP5(v, x.p5);
+ VdbeCoverageIf(v, p2!=x.p2);
+ }
+ nConflictCk--;
+ addrConflictCk++;
+ }
+ /* If the retest fails, issue an abort */
+ sqlite3UniqueConstraint(pParse, OE_Abort, pIdx);
+
+ sqlite3VdbeJumpHere(v, addrBypass); /* Terminate the recheck bypass */
+ }
seenReplace = 1;
break;
}
}
- sqlite3VdbeResolveLabel(v, addrUniqueOk);
- sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
+ if( pUpIdx==pIdx ){
+ sqlite3VdbeGoto(v, upsertJump+1);
+ sqlite3VdbeJumpHere(v, upsertBypass);
+ }else{
+ sqlite3VdbeResolveLabel(v, addrUniqueOk);
+ }
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
+
+ /* If the IPK constraint is a REPLACE, run it last */
if( ipkTop ){
- sqlite3VdbeGoto(v, ipkTop+1);
+ sqlite3VdbeGoto(v, ipkTop);
+ VdbeComment((v, "Do IPK REPLACE"));
sqlite3VdbeJumpHere(v, ipkBottom);
}
-
+
+ /* Recheck all uniqueness constraints after replace triggers have run */
+ testcase( regTrigCnt!=0 && nReplaceTrig==0 );
+ assert( regTrigCnt!=0 || nReplaceTrig==0 );
+ if( nReplaceTrig ){
+ sqlite3VdbeAddOp2(v, OP_IfNot, regTrigCnt, lblRecheckOk);VdbeCoverage(v);
+ if( !pPk ){
+ if( isUpdate ){
+ sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRecheck, regOldData);
+ sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
+ VdbeCoverage(v);
+ }
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRecheck, regNewData);
+ VdbeCoverage(v);
+ sqlite3RowidConstraint(pParse, OE_Abort, pTab);
+ }else{
+ sqlite3VdbeGoto(v, addrRecheck);
+ }
+ sqlite3VdbeResolveLabel(v, lblRecheckOk);
+ }
+
+ /* Generate the table record */
+ if( HasRowid(pTab) ){
+ int regRec = aRegIdx[ix];
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regNewData+1, pTab->nNVCol, regRec);
+ sqlite3SetMakeRecordP5(v, pTab);
+ if( !bAffinityDone ){
+ sqlite3TableAffinity(v, pTab, 0);
+ }
+ }
+
*pbMayReplace = seenReplace;
VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
}
+#ifdef SQLITE_ENABLE_NULL_TRIM
+/*
+** Change the P5 operand on the last opcode (which should be an OP_MakeRecord)
+** to be the number of columns in table pTab that must not be NULL-trimmed.
+**
+** Or if no columns of pTab may be NULL-trimmed, leave P5 at zero.
+*/
+SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
+ u16 i;
+
+ /* Records with omitted columns are only allowed for schema format
+ ** version 2 and later (SQLite version 3.1.4, 2005-02-20). */
+ if( pTab->pSchema->file_format<2 ) return;
+
+ for(i=pTab->nCol-1; i>0; i--){
+ if( pTab->aCol[i].pDflt!=0 ) break;
+ if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break;
+ }
+ sqlite3VdbeChangeP5(v, i+1);
+}
+#endif
+
/*
** This routine generates code to finish the INSERT or UPDATE operation
** that was started by a prior call to sqlite3GenerateConstraintChecks.
@@ -109024,48 +122843,61 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
int iIdxCur, /* First index cursor */
int regNewData, /* Range of content */
int *aRegIdx, /* Register used by each index. 0 for unused indices */
- int isUpdate, /* True for UPDATE, False for INSERT */
+ int update_flags, /* True for UPDATE, False for INSERT */
int appendBias, /* True if this is likely to be an append */
int useSeekResult /* True to set the USESEEKRESULT flag on OP_[Idx]Insert */
){
Vdbe *v; /* Prepared statements under construction */
Index *pIdx; /* An index being inserted or updated */
u8 pik_flags; /* flag values passed to the btree insert */
- int regData; /* Content registers (after the rowid) */
- int regRec; /* Register holding assembled record for the table */
int i; /* Loop counter */
- u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */
+
+ assert( update_flags==0
+ || update_flags==OPFLAG_ISUPDATE
+ || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
+ );
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+ /* All REPLACE indexes are at the end of the list */
+ assert( pIdx->onError!=OE_Replace
+ || pIdx->pNext==0
+ || pIdx->pNext->onError==OE_Replace );
if( aRegIdx[i]==0 ) continue;
- bAffinityDone = 1;
if( pIdx->pPartIdxWhere ){
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
}
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
- pik_flags = 0;
- if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
+ pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
assert( pParse->nested==0 );
pik_flags |= OPFLAG_NCHANGE;
+ pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ if( update_flags==0 ){
+ int r = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
+ sqlite3VdbeAddOp4(v, OP_Insert,
+ iIdxCur+i, aRegIdx[i], r, (char*)pTab, P4_TABLE
+ );
+ sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
+ sqlite3ReleaseTempReg(pParse, r);
+ }
+#endif
}
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
+ aRegIdx[i]+1,
+ pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
sqlite3VdbeChangeP5(v, pik_flags);
}
if( !HasRowid(pTab) ) return;
- regData = regNewData + 1;
- regRec = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
- if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
- sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
if( pParse->nested ){
pik_flags = 0;
}else{
pik_flags = OPFLAG_NCHANGE;
- pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
+ pik_flags |= (update_flags?update_flags:OPFLAG_LASTROWID);
}
if( appendBias ){
pik_flags |= OPFLAG_APPEND;
@@ -109073,9 +122905,9 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
if( useSeekResult ){
pik_flags |= OPFLAG_USESEEKRESULT;
}
- sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
+ sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, aRegIdx[i], regNewData);
if( !pParse->nested ){
- sqlite3VdbeChangeP4(v, -1, (char *)pTab, P4_TABLE);
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
@@ -109183,7 +123015,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
int i;
assert( pDest && pSrc );
assert( pDest->pTable!=pSrc->pTable );
- if( pDest->nKeyCol!=pSrc->nKeyCol ){
+ if( pDest->nKeyCol!=pSrc->nKeyCol || pDest->nColumn!=pSrc->nColumn ){
return 0; /* Different number of columns */
}
if( pDest->onError!=pSrc->onError ){
@@ -109195,7 +123027,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
}
if( pSrc->aiColumn[i]==XN_EXPR ){
assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
- if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
+ if( sqlite3ExprCompare(0, pSrc->aColExpr->a[i].pExpr,
pDest->aColExpr->a[i].pExpr, -1)!=0 ){
return 0; /* Different expressions in the index */
}
@@ -109207,7 +123039,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
return 0; /* Different collating sequences */
}
}
- if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
+ if( sqlite3ExprCompare(0, pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
return 0; /* Different WHERE clauses */
}
@@ -109220,7 +123052,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
**
** INSERT INTO tab1 SELECT * FROM tab2;
**
-** The xfer optimization transfers raw records from tab2 over to tab1.
+** The xfer optimization transfers raw records from tab2 over to tab1.
** Columns are not decoded and reassembled, which greatly improves
** performance. Raw index records are transferred in the same way.
**
@@ -109276,7 +123108,7 @@ static int xferOptimization(
return 0; /* tab1 must not have triggers */
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( pDest->tabFlags & TF_Virtual ){
+ if( IsVirtual(pDest) ){
return 0; /* tab1 must not be a virtual table */
}
#endif
@@ -109305,7 +123137,6 @@ static int xferOptimization(
if( pSelect->pLimit ){
return 0; /* SELECT may not have a LIMIT clause */
}
- assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */
if( pSelect->pPrior ){
return 0; /* SELECT may not be a compound query */
}
@@ -109331,14 +123162,15 @@ static int xferOptimization(
if( pSrc==0 ){
return 0; /* FROM clause does not contain a real table */
}
- if( pSrc==pDest ){
+ if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){
+ testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */
return 0; /* tab1 and tab2 may not be the same table */
}
if( HasRowid(pDest)!=HasRowid(pSrc) ){
return 0; /* source and destination must both be WITHOUT ROWID or not */
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- if( pSrc->tabFlags & TF_Virtual ){
+ if( IsVirtual(pSrc) ){
return 0; /* tab2 must not be a virtual table */
}
#endif
@@ -109355,12 +123187,45 @@ static int xferOptimization(
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
- if( (db->flags & SQLITE_Vacuum)==0
- && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0
+ && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
){
return 0; /* Neither table may have __hidden__ columns */
}
#endif
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Even if tables t1 and t2 have identical schemas, if they contain
+ ** generated columns, then this statement is semantically incorrect:
+ **
+ ** INSERT INTO t2 SELECT * FROM t1;
+ **
+ ** The reason is that generated column values are returned by the
+ ** the SELECT statement on the right but the INSERT statement on the
+ ** left wants them to be omitted.
+ **
+ ** Nevertheless, this is a useful notational shorthand to tell SQLite
+ ** to do a bulk transfer all of the content from t1 over to t2.
+ **
+ ** We could, in theory, disable this (except for internal use by the
+ ** VACUUM command where it is actually needed). But why do that? It
+ ** seems harmless enough, and provides a useful service.
+ */
+ if( (pDestCol->colFlags & COLFLAG_GENERATED) !=
+ (pSrcCol->colFlags & COLFLAG_GENERATED) ){
+ return 0; /* Both columns have the same generated-column type */
+ }
+ /* But the transfer is only allowed if both the source and destination
+ ** tables have the exact same expressions for generated columns.
+ ** This requirement could be relaxed for VIRTUAL columns, I suppose.
+ */
+ if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){
+ if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){
+ testcase( pDestCol->colFlags & COLFLAG_VIRTUAL );
+ testcase( pDestCol->colFlags & COLFLAG_STORED );
+ return 0; /* Different generator expressions */
+ }
+ }
+#endif
if( pDestCol->affinity!=pSrcCol->affinity ){
return 0; /* Affinity must be the same on all columns */
}
@@ -109371,10 +123236,10 @@ static int xferOptimization(
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
- if( i>0 ){
+ if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){
assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
- if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
+ if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
|| (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
pSrcCol->pDflt->u.zToken)!=0)
){
@@ -109392,6 +123257,13 @@ static int xferOptimization(
if( pSrcIdx==0 ){
return 0; /* pDestIdx has no corresponding index in pSrc */
}
+ if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema
+ && sqlite3FaultSim(411)==SQLITE_OK ){
+ /* The sqlite3FaultSim() call allows this corruption test to be
+ ** bypassed during testing, in order to exercise other corruption tests
+ ** further downstream. */
+ return 0; /* Corrupt schema - two indexes on the same btree */
+ }
}
#ifndef SQLITE_OMIT_CHECK
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
@@ -109401,7 +123273,7 @@ static int xferOptimization(
#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
+ ** 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]
@@ -109431,15 +123303,15 @@ static int xferOptimization(
regRowid = sqlite3GetTempReg(pParse);
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
assert( HasRowid(pDest) || destHasUniqueIdx );
- if( (db->flags & SQLITE_Vacuum)==0 && (
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 && (
(pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */
|| destHasUniqueIdx /* (2) */
|| (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */
)){
/* In some circumstances, we are able to run the xfer optimization
** only if the destination table is initially empty. Unless the
- ** SQLITE_Vacuum flag is set, this block generates code to make
- ** that determination. If SQLITE_Vacuum is set, then the destination
+ ** DBFLAG_Vacuum flag is set, this block generates code to make
+ ** that determination. If DBFLAG_Vacuum is set, then the destination
** table is always empty.
**
** Conditions under which the destination must be empty:
@@ -109448,7 +123320,7 @@ static int xferOptimization(
** (If the destination is not initially empty, the rowid fields
** of index entries might need to change.)
**
- ** (2) The destination has a unique index. (The xfer optimization
+ ** (2) The destination has a unique index. (The xfer optimization
** is unable to test uniqueness.)
**
** (3) onError is something other than OE_Abort and OE_Rollback.
@@ -109458,25 +123330,33 @@ static int xferOptimization(
sqlite3VdbeJumpHere(v, addr1);
}
if( HasRowid(pSrc) ){
+ u8 insFlags;
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
if( pDest->iPKey>=0 ){
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
+ sqlite3VdbeVerifyAbortable(v, onError);
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
VdbeCoverage(v);
sqlite3RowidConstraint(pParse, onError, pDest);
sqlite3VdbeJumpHere(v, addr2);
autoIncStep(pParse, regAutoinc, regRowid);
- }else if( pDest->pIndex==0 ){
+ }else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
}else{
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
- sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
+ if( db->mDbFlags & DBFLAG_Vacuum ){
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
+ insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
+ }else{
+ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
+ }
+ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
(char*)pDest, P4_TABLE);
- sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
+ sqlite3VdbeChangeP5(v, insFlags);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
@@ -109498,38 +123378,35 @@ static int xferOptimization(
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
- if( db->flags & SQLITE_Vacuum ){
+ if( db->mDbFlags & DBFLAG_Vacuum ){
/* This INSERT command is part of a VACUUM operation, which guarantees
** that the destination table is empty. If all indexed columns use
** collation sequence BINARY, then it can also be assumed that the
- ** index will be populated by inserting keys in strictly sorted
+ ** index will be populated by inserting keys in strictly sorted
** order. In this case, instead of seeking within the b-tree as part
- ** of every OP_IdxInsert opcode, an OP_Last is added before the
- ** OP_IdxInsert to seek to the point within the b-tree where each key
+ ** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
+ ** OP_IdxInsert to seek to the point within the b-tree where each key
** should be inserted. This is faster.
**
** If any of the indexed columns use a collation sequence other than
- ** BINARY, this optimization is disabled. This is because the user
+ ** BINARY, this optimization is disabled. This is because the user
** might change the definition of a collation sequence and then run
** a VACUUM command. In that case keys may not be written in strictly
** sorted order. */
for(i=0; i<pSrcIdx->nColumn; i++){
const char *zColl = pSrcIdx->azColl[i];
- assert( sqlite3_stricmp(sqlite3StrBINARY, zColl)!=0
- || sqlite3StrBINARY==zColl );
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
}
if( i==pSrcIdx->nColumn ){
idxInsFlags = OPFLAG_USESEEKRESULT;
- sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
}
- }
- if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
+ }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
idxInsFlags |= OPFLAG_NCHANGE;
}
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
- sqlite3VdbeChangeP5(v, idxInsFlags);
+ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
+ sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
@@ -109600,7 +123477,7 @@ SQLITE_API int sqlite3_exec(
sqlite3_mutex_enter(db->mutex);
sqlite3Error(db, SQLITE_OK);
while( rc==SQLITE_OK && zSql[0] ){
- int nCol;
+ int nCol = 0;
char **azVals = 0;
pStmt = 0;
@@ -109614,20 +123491,19 @@ SQLITE_API int sqlite3_exec(
zSql = zLeftover;
continue;
}
-
callbackIsInit = 0;
- nCol = sqlite3_column_count(pStmt);
while( 1 ){
int i;
rc = sqlite3_step(pStmt);
/* Invoke the callback function if required */
- if( xCallback && (SQLITE_ROW==rc ||
+ if( xCallback && (SQLITE_ROW==rc ||
(SQLITE_DONE==rc && !callbackIsInit
&& db->flags&SQLITE_NullCallback)) ){
if( !callbackIsInit ){
- azCols = sqlite3DbMallocZero(db, 2*nCol*sizeof(const char*) + 1);
+ nCol = sqlite3_column_count(pStmt);
+ azCols = sqlite3DbMallocRaw(db, (2*nCol+1)*sizeof(const char*));
if( azCols==0 ){
goto exec_out;
}
@@ -109648,6 +123524,7 @@ SQLITE_API int sqlite3_exec(
goto exec_out;
}
}
+ azVals[i] = 0;
}
if( xCallback(pArg, nCol, azVals, azCols) ){
/* EVIDENCE-OF: R-38229-40159 If the callback function to
@@ -109680,11 +123557,8 @@ exec_out:
rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && pzErrMsg ){
- int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db));
- *pzErrMsg = sqlite3Malloc(nErrMsg);
- if( *pzErrMsg ){
- memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
- }else{
+ *pzErrMsg = sqlite3DbStrDup(0, sqlite3_errmsg(db));
+ if( *pzErrMsg==0 ){
rc = SQLITE_NOMEM_BKPT;
sqlite3Error(db, SQLITE_NOMEM);
}
@@ -109733,7 +123607,7 @@ exec_out:
** This header file defines the SQLite interface for use by
** shared libraries that want to be imported as extensions into
** an SQLite instance. Shared libraries that intend to be loaded
-** as extensions by SQLite should #include this file instead of
+** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef SQLITE3EXT_H
@@ -109855,7 +123729,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
- char * (*snprintf)(int,char*,const char*,...);
+ char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -109967,7 +123841,7 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
- char *(*vsnprintf)(int,char*,const char*,va_list);
+ char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
@@ -110003,6 +123877,59 @@ struct sqlite3_api_routines {
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
+ /* Version 3.18.0 and later */
+ void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
+ /* Version 3.20.0 and later */
+ int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
+ sqlite3_stmt**,const char**);
+ int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
+ sqlite3_stmt**,const void**);
+ int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
+ void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
+ void *(*value_pointer)(sqlite3_value*,const char*);
+ int (*vtab_nochange)(sqlite3_context*);
+ int (*value_nochange)(sqlite3_value*);
+ const char *(*vtab_collation)(sqlite3_index_info*,int);
+ /* Version 3.24.0 and later */
+ int (*keyword_count)(void);
+ int (*keyword_name)(int,const char**,int*);
+ int (*keyword_check)(const char*,int);
+ sqlite3_str *(*str_new)(sqlite3*);
+ char *(*str_finish)(sqlite3_str*);
+ void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
+ void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
+ void (*str_append)(sqlite3_str*, const char *zIn, int N);
+ void (*str_appendall)(sqlite3_str*, const char *zIn);
+ void (*str_appendchar)(sqlite3_str*, int N, char C);
+ void (*str_reset)(sqlite3_str*);
+ int (*str_errcode)(sqlite3_str*);
+ int (*str_length)(sqlite3_str*);
+ char *(*str_value)(sqlite3_str*);
+ /* Version 3.25.0 and later */
+ int (*create_window_function)(sqlite3*,const char*,int,int,void*,
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+ void (*xFinal)(sqlite3_context*),
+ void (*xValue)(sqlite3_context*),
+ void (*xInv)(sqlite3_context*,int,sqlite3_value**),
+ void(*xDestroy)(void*));
+ /* Version 3.26.0 and later */
+ const char *(*normalized_sql)(sqlite3_stmt*);
+ /* Version 3.28.0 and later */
+ int (*stmt_isexplain)(sqlite3_stmt*);
+ int (*value_frombind)(sqlite3_value*);
+ /* Version 3.30.0 and later */
+ int (*drop_modules)(sqlite3*,const char**);
+ /* Version 3.31.0 and later */
+ sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
+ const char *(*uri_key)(const char*,int);
+ const char *(*filename_database)(const char*);
+ const char *(*filename_journal)(const char*);
+ const char *(*filename_wal)(const char*);
+ /* Version 3.32.0 and later */
+ char *(*create_filename)(const char*,const char*,const char*,
+ int,const char**);
+ void (*free_filename)(char*);
+ sqlite3_file *(*database_file_object)(const char*);
};
/*
@@ -110129,7 +124056,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
-#define sqlite3_snprintf sqlite3_api->snprintf
+#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -110153,7 +124080,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
-#define sqlite3_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -110229,7 +124156,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
-#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
@@ -110261,17 +124188,63 @@ typedef int (*sqlite3_loadext_entry)(
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
+/* Version 3.18.0 and later */
+#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
+/* Version 3.20.0 and later */
+#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
+#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
+#define sqlite3_bind_pointer sqlite3_api->bind_pointer
+#define sqlite3_result_pointer sqlite3_api->result_pointer
+#define sqlite3_value_pointer sqlite3_api->value_pointer
+/* Version 3.22.0 and later */
+#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
+#define sqlite3_value_nochange sqlite3_api->value_nochange
+#define sqlite3_vtab_collation sqlite3_api->vtab_collation
+/* Version 3.24.0 and later */
+#define sqlite3_keyword_count sqlite3_api->keyword_count
+#define sqlite3_keyword_name sqlite3_api->keyword_name
+#define sqlite3_keyword_check sqlite3_api->keyword_check
+#define sqlite3_str_new sqlite3_api->str_new
+#define sqlite3_str_finish sqlite3_api->str_finish
+#define sqlite3_str_appendf sqlite3_api->str_appendf
+#define sqlite3_str_vappendf sqlite3_api->str_vappendf
+#define sqlite3_str_append sqlite3_api->str_append
+#define sqlite3_str_appendall sqlite3_api->str_appendall
+#define sqlite3_str_appendchar sqlite3_api->str_appendchar
+#define sqlite3_str_reset sqlite3_api->str_reset
+#define sqlite3_str_errcode sqlite3_api->str_errcode
+#define sqlite3_str_length sqlite3_api->str_length
+#define sqlite3_str_value sqlite3_api->str_value
+/* Version 3.25.0 and later */
+#define sqlite3_create_window_function sqlite3_api->create_window_function
+/* Version 3.26.0 and later */
+#define sqlite3_normalized_sql sqlite3_api->normalized_sql
+/* Version 3.28.0 and later */
+#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
+#define sqlite3_value_frombind sqlite3_api->value_frombind
+/* Version 3.30.0 and later */
+#define sqlite3_drop_modules sqlite3_api->drop_modules
+/* Version 3.31.0 and later */
+#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
+#define sqlite3_uri_key sqlite3_api->uri_key
+#define sqlite3_filename_database sqlite3_api->filename_database
+#define sqlite3_filename_journal sqlite3_api->filename_journal
+#define sqlite3_filename_wal sqlite3_api->filename_wal
+/* Version 3.32.0 and later */
+#define sqlite3_create_filename sqlite3_api->create_filename
+#define sqlite3_free_filename sqlite3_api->free_filename
+#define sqlite3_database_file_object sqlite3_api->database_file_object
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
- /* This case when the file really is being compiled as a loadable
+ /* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
# define SQLITE_EXTENSION_INIT3 \
extern const sqlite3_api_routines *sqlite3_api;
#else
- /* This case when the file is being statically linked into the
+ /* This case when the file is being statically linked into the
** application */
# define SQLITE_EXTENSION_INIT1 /*no-op*/
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
@@ -110283,7 +124256,6 @@ typedef int (*sqlite3_loadext_entry)(
/************** End of sqlite3ext.h ******************************************/
/************** Continuing where we left off in loadext.c ********************/
/* #include "sqliteInt.h" */
-/* #include <string.h> */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
@@ -110317,6 +124289,7 @@ typedef int (*sqlite3_loadext_entry)(
# define sqlite3_open16 0
# define sqlite3_prepare16 0
# define sqlite3_prepare16_v2 0
+# define sqlite3_prepare16_v3 0
# define sqlite3_result_error16 0
# define sqlite3_result_text16 0
# define sqlite3_result_text16be 0
@@ -110349,6 +124322,7 @@ typedef int (*sqlite3_loadext_entry)(
# define sqlite3_declare_vtab 0
# define sqlite3_vtab_config 0
# define sqlite3_vtab_on_conflict 0
+# define sqlite3_vtab_collation 0
#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
@@ -110562,8 +124536,8 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_memory_highwater,
sqlite3_memory_used,
#ifdef SQLITE_MUTEX_OMIT
- 0,
- 0,
+ 0,
+ 0,
0,
0,
0,
@@ -110687,9 +124661,71 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_system_errno,
/* Version 3.14.0 and later */
sqlite3_trace_v2,
- sqlite3_expanded_sql
+ sqlite3_expanded_sql,
+ /* Version 3.18.0 and later */
+ sqlite3_set_last_insert_rowid,
+ /* Version 3.20.0 and later */
+ sqlite3_prepare_v3,
+ sqlite3_prepare16_v3,
+ sqlite3_bind_pointer,
+ sqlite3_result_pointer,
+ sqlite3_value_pointer,
+ /* Version 3.22.0 and later */
+ sqlite3_vtab_nochange,
+ sqlite3_value_nochange,
+ sqlite3_vtab_collation,
+ /* Version 3.24.0 and later */
+ sqlite3_keyword_count,
+ sqlite3_keyword_name,
+ sqlite3_keyword_check,
+ sqlite3_str_new,
+ sqlite3_str_finish,
+ sqlite3_str_appendf,
+ sqlite3_str_vappendf,
+ sqlite3_str_append,
+ sqlite3_str_appendall,
+ sqlite3_str_appendchar,
+ sqlite3_str_reset,
+ sqlite3_str_errcode,
+ sqlite3_str_length,
+ sqlite3_str_value,
+ /* Version 3.25.0 and later */
+ sqlite3_create_window_function,
+ /* Version 3.26.0 and later */
+#ifdef SQLITE_ENABLE_NORMALIZE
+ sqlite3_normalized_sql,
+#else
+ 0,
+#endif
+ /* Version 3.28.0 and later */
+ sqlite3_stmt_isexplain,
+ sqlite3_value_frombind,
+ /* Version 3.30.0 and later */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3_drop_modules,
+#else
+ 0,
+#endif
+ /* Version 3.31.0 and later */
+ sqlite3_hard_heap_limit64,
+ sqlite3_uri_key,
+ sqlite3_filename_database,
+ sqlite3_filename_journal,
+ sqlite3_filename_wal,
+ /* Version 3.32.0 and later */
+ sqlite3_create_filename,
+ sqlite3_free_filename,
+ sqlite3_database_file_object,
};
+/* True if x is the directory separator character
+*/
+#if SQLITE_OS_WIN
+# define DirSep(X) ((X)=='/'||(X)=='\\')
+#else
+# define DirSep(X) ((X)=='/')
+#endif
+
/*
** Attempt to load an SQLite extension library contained in the file
** zFile. The entry point is zProc. zProc may be 0 in which case a
@@ -110698,7 +124734,7 @@ static const sqlite3_api_routines sqlite3Apis = {
**
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
**
-** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
+** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
** error message text. The calling function should free this memory
** by calling sqlite3DbFree(db, ).
*/
@@ -110722,7 +124758,7 @@ static int sqlite3LoadExtension(
/* Shared library endings to try if zFile cannot be loaded as written */
static const char *azEndings[] = {
#if SQLITE_OS_WIN
- "dll"
+ "dll"
#elif defined(__APPLE__)
"dylib"
#else
@@ -110762,7 +124798,7 @@ static int sqlite3LoadExtension(
if( pzErrMsg ){
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
if( zErrmsg ){
- sqlite3_snprintf(nMsg, zErrmsg,
+ sqlite3_snprintf(nMsg, zErrmsg,
"unable to open shared library [%s]", zFile);
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
}
@@ -110774,9 +124810,9 @@ static int sqlite3LoadExtension(
/* If no entry point was specified and the default legacy
** entry point name "sqlite3_extension_init" was not found, then
** construct an entry point name "sqlite3_X_init" where the X is
- ** replaced by the lowercase value of every ASCII alphabetic
+ ** replaced by the lowercase value of every ASCII alphabetic
** character in the filename after the last "/" upto the first ".",
- ** and eliding the first three characters if they are "lib".
+ ** and eliding the first three characters if they are "lib".
** Examples:
**
** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init
@@ -110791,7 +124827,7 @@ static int sqlite3LoadExtension(
return SQLITE_NOMEM_BKPT;
}
memcpy(zAltEntry, "sqlite3_", 8);
- for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
+ for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){}
iFile++;
if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
@@ -110879,7 +124915,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
if( onoff ){
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
}else{
- db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
+ db->flags &= ~(u64)(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
}
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -110891,12 +124927,12 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
** The following object holds the list of automatically loaded
** extensions.
**
-** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
+** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN
** mutex must be held while accessing this list.
*/
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
static SQLITE_WSD struct sqlite3AutoExtList {
- u32 nExt; /* Number of entries in aExt[] */
+ u32 nExt; /* Number of entries in aExt[] */
void (**aExt)(void); /* Pointers to the extension init functions */
} sqlite3Autoext = { 0, 0 };
@@ -110933,7 +124969,7 @@ SQLITE_API int sqlite3_auto_extension(
{
u32 i;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
@@ -110971,7 +125007,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(
void (*xInit)(void)
){
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
int i;
int n = 0;
@@ -110998,7 +125034,7 @@ SQLITE_API void sqlite3_reset_auto_extension(void){
#endif
{
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
wsdAutoextInit;
sqlite3_mutex_enter(mutex);
@@ -111028,7 +125064,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
for(i=0; go; i++){
char *zErrmsg;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
#endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
const sqlite3_api_routines *pThunk = 0;
@@ -111083,7 +125119,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
** that includes the PragType_XXXX macro definitions and the aPragmaName[]
** object. This ensures that the aPragmaName[] table is arranged in
** lexicographical order to facility a binary search of the pragma name.
-** Do not edit pragma.h directly. Edit and rerun the script in at
+** Do not edit pragma.h directly. Edit and rerun the script in at
** ../tool/mkpragmatab.tcl. */
/************** Include pragma.h in the middle of pragma.c *******************/
/************** Begin file pragma.h ******************************************/
@@ -111092,472 +125128,656 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
** that script and rerun it.
*/
-#define PragTyp_HEADER_VALUE 0
-#define PragTyp_AUTO_VACUUM 1
-#define PragTyp_FLAG 2
-#define PragTyp_BUSY_TIMEOUT 3
-#define PragTyp_CACHE_SIZE 4
-#define PragTyp_CACHE_SPILL 5
-#define PragTyp_CASE_SENSITIVE_LIKE 6
-#define PragTyp_COLLATION_LIST 7
-#define PragTyp_COMPILE_OPTIONS 8
-#define PragTyp_DATA_STORE_DIRECTORY 9
-#define PragTyp_DATABASE_LIST 10
-#define PragTyp_DEFAULT_CACHE_SIZE 11
-#define PragTyp_ENCODING 12
-#define PragTyp_FOREIGN_KEY_CHECK 13
-#define PragTyp_FOREIGN_KEY_LIST 14
-#define PragTyp_INCREMENTAL_VACUUM 15
-#define PragTyp_INDEX_INFO 16
-#define PragTyp_INDEX_LIST 17
-#define PragTyp_INTEGRITY_CHECK 18
-#define PragTyp_JOURNAL_MODE 19
-#define PragTyp_JOURNAL_SIZE_LIMIT 20
-#define PragTyp_LOCK_PROXY_FILE 21
-#define PragTyp_LOCKING_MODE 22
-#define PragTyp_PAGE_COUNT 23
-#define PragTyp_MMAP_SIZE 24
-#define PragTyp_PAGE_SIZE 25
-#define PragTyp_SECURE_DELETE 26
-#define PragTyp_SHRINK_MEMORY 27
-#define PragTyp_SOFT_HEAP_LIMIT 28
-#define PragTyp_STATS 29
-#define PragTyp_SYNCHRONOUS 30
-#define PragTyp_TABLE_INFO 31
-#define PragTyp_TEMP_STORE 32
-#define PragTyp_TEMP_STORE_DIRECTORY 33
-#define PragTyp_THREADS 34
-#define PragTyp_WAL_AUTOCHECKPOINT 35
-#define PragTyp_WAL_CHECKPOINT 36
-#define PragTyp_ACTIVATE_EXTENSIONS 37
-#define PragTyp_HEXKEY 38
-#define PragTyp_KEY 39
-#define PragTyp_REKEY 40
-#define PragTyp_LOCK_STATUS 41
-#define PragTyp_PARSER_TRACE 42
-#define PragFlag_NeedSchema 0x01
-#define PragFlag_ReadOnly 0x02
-static const struct sPragmaNames {
- const char *const zName; /* Name of pragma */
- u8 ePragTyp; /* PragTyp_XXX value */
- u8 mPragFlag; /* Zero or more PragFlag_XXX values */
- u32 iArg; /* Extra argument */
-} aPragmaNames[] = {
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
- { /* zName: */ "activate_extensions",
- /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
+
+/* The various pragma types */
+#define PragTyp_ACTIVATE_EXTENSIONS 0
+#define PragTyp_ANALYSIS_LIMIT 1
+#define PragTyp_HEADER_VALUE 2
+#define PragTyp_AUTO_VACUUM 3
+#define PragTyp_FLAG 4
+#define PragTyp_BUSY_TIMEOUT 5
+#define PragTyp_CACHE_SIZE 6
+#define PragTyp_CACHE_SPILL 7
+#define PragTyp_CASE_SENSITIVE_LIKE 8
+#define PragTyp_COLLATION_LIST 9
+#define PragTyp_COMPILE_OPTIONS 10
+#define PragTyp_DATA_STORE_DIRECTORY 11
+#define PragTyp_DATABASE_LIST 12
+#define PragTyp_DEFAULT_CACHE_SIZE 13
+#define PragTyp_ENCODING 14
+#define PragTyp_FOREIGN_KEY_CHECK 15
+#define PragTyp_FOREIGN_KEY_LIST 16
+#define PragTyp_FUNCTION_LIST 17
+#define PragTyp_HARD_HEAP_LIMIT 18
+#define PragTyp_INCREMENTAL_VACUUM 19
+#define PragTyp_INDEX_INFO 20
+#define PragTyp_INDEX_LIST 21
+#define PragTyp_INTEGRITY_CHECK 22
+#define PragTyp_JOURNAL_MODE 23
+#define PragTyp_JOURNAL_SIZE_LIMIT 24
+#define PragTyp_LOCK_PROXY_FILE 25
+#define PragTyp_LOCKING_MODE 26
+#define PragTyp_PAGE_COUNT 27
+#define PragTyp_MMAP_SIZE 28
+#define PragTyp_MODULE_LIST 29
+#define PragTyp_OPTIMIZE 30
+#define PragTyp_PAGE_SIZE 31
+#define PragTyp_PRAGMA_LIST 32
+#define PragTyp_SECURE_DELETE 33
+#define PragTyp_SHRINK_MEMORY 34
+#define PragTyp_SOFT_HEAP_LIMIT 35
+#define PragTyp_SYNCHRONOUS 36
+#define PragTyp_TABLE_INFO 37
+#define PragTyp_TEMP_STORE 38
+#define PragTyp_TEMP_STORE_DIRECTORY 39
+#define PragTyp_THREADS 40
+#define PragTyp_WAL_AUTOCHECKPOINT 41
+#define PragTyp_WAL_CHECKPOINT 42
+#define PragTyp_LOCK_STATUS 43
+#define PragTyp_STATS 44
+
+/* Property flags associated with various pragma. */
+#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
+#define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */
+#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
+#define PragFlg_ReadOnly 0x08 /* Read-only HEADER_VALUE */
+#define PragFlg_Result0 0x10 /* Acts as query when no argument */
+#define PragFlg_Result1 0x20 /* Acts as query when has one argument */
+#define PragFlg_SchemaOpt 0x40 /* Schema restricts name search if present */
+#define PragFlg_SchemaReq 0x80 /* Schema required - "main" is default */
+
+/* Names of columns for pragmas that return multi-column result
+** or that return single-column results where the name of the
+** result column is different from the name of the pragma
+*/
+static const char *const pragCName[] = {
+ /* 0 */ "id", /* Used by: foreign_key_list */
+ /* 1 */ "seq",
+ /* 2 */ "table",
+ /* 3 */ "from",
+ /* 4 */ "to",
+ /* 5 */ "on_update",
+ /* 6 */ "on_delete",
+ /* 7 */ "match",
+ /* 8 */ "cid", /* Used by: table_xinfo */
+ /* 9 */ "name",
+ /* 10 */ "type",
+ /* 11 */ "notnull",
+ /* 12 */ "dflt_value",
+ /* 13 */ "pk",
+ /* 14 */ "hidden",
+ /* table_info reuses 8 */
+ /* 15 */ "seqno", /* Used by: index_xinfo */
+ /* 16 */ "cid",
+ /* 17 */ "name",
+ /* 18 */ "desc",
+ /* 19 */ "coll",
+ /* 20 */ "key",
+ /* 21 */ "name", /* Used by: function_list */
+ /* 22 */ "builtin",
+ /* 23 */ "type",
+ /* 24 */ "enc",
+ /* 25 */ "narg",
+ /* 26 */ "flags",
+ /* 27 */ "tbl", /* Used by: stats */
+ /* 28 */ "idx",
+ /* 29 */ "wdth",
+ /* 30 */ "hght",
+ /* 31 */ "flgs",
+ /* 32 */ "seq", /* Used by: index_list */
+ /* 33 */ "name",
+ /* 34 */ "unique",
+ /* 35 */ "origin",
+ /* 36 */ "partial",
+ /* 37 */ "table", /* Used by: foreign_key_check */
+ /* 38 */ "rowid",
+ /* 39 */ "parent",
+ /* 40 */ "fkid",
+ /* index_info reuses 15 */
+ /* 41 */ "seq", /* Used by: database_list */
+ /* 42 */ "name",
+ /* 43 */ "file",
+ /* 44 */ "busy", /* Used by: wal_checkpoint */
+ /* 45 */ "log",
+ /* 46 */ "checkpointed",
+ /* collation_list reuses 32 */
+ /* 47 */ "database", /* Used by: lock_status */
+ /* 48 */ "status",
+ /* 49 */ "cache_size", /* Used by: default_cache_size */
+ /* module_list pragma_list reuses 9 */
+ /* 50 */ "timeout", /* Used by: busy_timeout */
+};
+
+/* Definitions of all built-in pragmas */
+typedef struct PragmaName {
+ const char *const zName; /* Name of pragma */
+ u8 ePragTyp; /* PragTyp_XXX value */
+ u8 mPragFlg; /* Zero or more PragFlg_XXX values */
+ u8 iPragCName; /* Start of column names in pragCName[] */
+ u8 nPragCName; /* Num of col names. 0 means use pragma name */
+ u64 iArg; /* Extra argument */
+} PragmaName;
+static const PragmaName aPragmaName[] = {
+#if defined(SQLITE_ENABLE_CEROD)
+ {/* zName: */ "activate_extensions",
+ /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+ {/* zName: */ "analysis_limit",
+ /* ePragTyp: */ PragTyp_ANALYSIS_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "application_id",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_APPLICATION_ID },
+ {/* zName: */ "application_id",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_APPLICATION_ID },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
- { /* zName: */ "auto_vacuum",
- /* ePragTyp: */ PragTyp_AUTO_VACUUM,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "auto_vacuum",
+ /* ePragTyp: */ PragTyp_AUTO_VACUUM,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
- { /* zName: */ "automatic_index",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_AutoIndex },
-#endif
-#endif
- { /* zName: */ "busy_timeout",
- /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "automatic_index",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_AutoIndex },
+#endif
+#endif
+ {/* zName: */ "busy_timeout",
+ /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 50, 1,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "cache_size",
- /* ePragTyp: */ PragTyp_CACHE_SIZE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "cache_size",
+ /* ePragTyp: */ PragTyp_CACHE_SIZE,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "cache_spill",
- /* ePragTyp: */ PragTyp_CACHE_SPILL,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
- { /* zName: */ "case_sensitive_like",
- /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "cell_size_check",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CellSizeCk },
+ {/* zName: */ "cache_spill",
+ /* ePragTyp: */ PragTyp_CACHE_SPILL,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA)
+ {/* zName: */ "case_sensitive_like",
+ /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
+ /* ePragFlg: */ PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+ {/* zName: */ "cell_size_check",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_CellSizeCk },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "checkpoint_fullfsync",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CkptFullFSync },
+ {/* zName: */ "checkpoint_fullfsync",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "collation_list",
- /* ePragTyp: */ PragTyp_COLLATION_LIST,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "collation_list",
+ /* ePragTyp: */ PragTyp_COLLATION_LIST,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 32, 2,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
- { /* zName: */ "compile_options",
- /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "compile_options",
+ /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "count_changes",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CountRows },
+ {/* zName: */ "count_changes",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_CountRows },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
- { /* zName: */ "data_store_directory",
- /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "data_store_directory",
+ /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
+ /* ePragFlg: */ PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "data_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ PragFlag_ReadOnly,
- /* iArg: */ BTREE_DATA_VERSION },
+ {/* zName: */ "data_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "database_list",
- /* ePragTyp: */ PragTyp_DATABASE_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "database_list",
+ /* ePragTyp: */ PragTyp_DATABASE_LIST,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
+ /* ColNames: */ 41, 3,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
- { /* zName: */ "default_cache_size",
- /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "default_cache_size",
+ /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 49, 1,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "defer_foreign_keys",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_DeferFKs },
+ {/* zName: */ "defer_foreign_keys",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_DeferFKs },
#endif
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "empty_result_callbacks",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_NullCallback },
+ {/* zName: */ "empty_result_callbacks",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_NullCallback },
#endif
#if !defined(SQLITE_OMIT_UTF16)
- { /* zName: */ "encoding",
- /* ePragTyp: */ PragTyp_ENCODING,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "encoding",
+ /* ePragTyp: */ PragTyp_ENCODING,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "foreign_key_check",
- /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "foreign_key_check",
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 37, 4,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
- { /* zName: */ "foreign_key_list",
- /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "foreign_key_list",
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 0, 8,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "foreign_keys",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ForeignKeys },
+ {/* zName: */ "foreign_keys",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ForeignKeys },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "freelist_count",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ PragFlag_ReadOnly,
- /* iArg: */ BTREE_FREE_PAGE_COUNT },
+ {/* zName: */ "freelist_count",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_FREE_PAGE_COUNT },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "full_column_names",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_FullColNames },
- { /* zName: */ "fullfsync",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_FullFSync },
-#endif
-#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "hexkey",
- /* ePragTyp: */ PragTyp_HEXKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "hexrekey",
- /* ePragTyp: */ PragTyp_HEXKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "full_column_names",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_FullColNames },
+ {/* zName: */ "fullfsync",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_FullFSync },
#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
+ {/* zName: */ "function_list",
+ /* ePragTyp: */ PragTyp_FUNCTION_LIST,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 21, 6,
+ /* iArg: */ 0 },
+#endif
+#endif
+ {/* zName: */ "hard_heap_limit",
+ /* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_CHECK)
- { /* zName: */ "ignore_check_constraints",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_IgnoreChecks },
+ {/* zName: */ "ignore_check_constraints",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_IgnoreChecks },
#endif
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
- { /* zName: */ "incremental_vacuum",
- /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "incremental_vacuum",
+ /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "index_info",
- /* ePragTyp: */ PragTyp_INDEX_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "index_list",
- /* ePragTyp: */ PragTyp_INDEX_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "index_xinfo",
- /* ePragTyp: */ PragTyp_INDEX_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 1 },
+ {/* zName: */ "index_info",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 15, 3,
+ /* iArg: */ 0 },
+ {/* zName: */ "index_list",
+ /* ePragTyp: */ PragTyp_INDEX_LIST,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 32, 5,
+ /* iArg: */ 0 },
+ {/* zName: */ "index_xinfo",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 15, 6,
+ /* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
- { /* zName: */ "integrity_check",
- /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "integrity_check",
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "journal_mode",
- /* ePragTyp: */ PragTyp_JOURNAL_MODE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "journal_size_limit",
- /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "key",
- /* ePragTyp: */ PragTyp_KEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "journal_mode",
+ /* ePragTyp: */ PragTyp_JOURNAL_MODE,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "journal_size_limit",
+ /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "legacy_file_format",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_LegacyFileFmt },
+ {/* zName: */ "legacy_alter_table",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_LegacyAlter },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
- { /* zName: */ "lock_proxy_file",
- /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "lock_proxy_file",
+ /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
+ /* ePragFlg: */ PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- { /* zName: */ "lock_status",
- /* ePragTyp: */ PragTyp_LOCK_STATUS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "lock_status",
+ /* ePragTyp: */ PragTyp_LOCK_STATUS,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 47, 2,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
+ {/* zName: */ "locking_mode",
+ /* ePragTyp: */ PragTyp_LOCKING_MODE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "max_page_count",
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "mmap_size",
+ /* ePragTyp: */ PragTyp_MMAP_SIZE,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
+#if !defined(SQLITE_OMIT_VIRTUALTABLE)
+#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
+ {/* zName: */ "module_list",
+ /* ePragTyp: */ PragTyp_MODULE_LIST,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 9, 1,
+ /* iArg: */ 0 },
#endif
+#endif
+#endif
+ {/* zName: */ "optimize",
+ /* ePragTyp: */ PragTyp_OPTIMIZE,
+ /* ePragFlg: */ PragFlg_Result1|PragFlg_NeedSchema,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "locking_mode",
- /* ePragTyp: */ PragTyp_LOCKING_MODE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "max_page_count",
- /* ePragTyp: */ PragTyp_PAGE_COUNT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "mmap_size",
- /* ePragTyp: */ PragTyp_MMAP_SIZE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "page_count",
- /* ePragTyp: */ PragTyp_PAGE_COUNT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "page_size",
- /* ePragTyp: */ PragTyp_PAGE_SIZE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
-#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
- { /* zName: */ "parser_trace",
- /* ePragTyp: */ PragTyp_PARSER_TRACE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "page_count",
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "page_size",
+ /* ePragTyp: */ PragTyp_PAGE_SIZE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "query_only",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_QueryOnly },
+#if defined(SQLITE_DEBUG)
+ {/* zName: */ "parser_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ParserTrace },
#endif
-#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
- { /* zName: */ "quick_check",
- /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+#endif
+#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
+ {/* zName: */ "pragma_list",
+ /* ePragTyp: */ PragTyp_PRAGMA_LIST,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 9, 1,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "read_uncommitted",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ReadUncommitted },
- { /* zName: */ "recursive_triggers",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_RecTriggers },
-#endif
-#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "rekey",
- /* ePragTyp: */ PragTyp_REKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "query_only",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_QueryOnly },
+#endif
+#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
+ {/* zName: */ "quick_check",
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "reverse_unordered_selects",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ReverseOrder },
+ {/* zName: */ "read_uncommitted",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ReadUncommit },
+ {/* zName: */ "recursive_triggers",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_RecTriggers },
+ {/* zName: */ "reverse_unordered_selects",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ReverseOrder },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "schema_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_SCHEMA_VERSION },
+ {/* zName: */ "schema_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_SCHEMA_VERSION },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "secure_delete",
- /* ePragTyp: */ PragTyp_SECURE_DELETE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "secure_delete",
+ /* ePragTyp: */ PragTyp_SECURE_DELETE,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "short_column_names",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ShortColNames },
-#endif
- { /* zName: */ "shrink_memory",
- /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "soft_heap_limit",
- /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "short_column_names",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ShortColNames },
+#endif
+ {/* zName: */ "shrink_memory",
+ /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
+ /* ePragFlg: */ PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "soft_heap_limit",
+ /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if defined(SQLITE_DEBUG)
- { /* zName: */ "sql_trace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_SqlTrace },
+ {/* zName: */ "sql_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_SqlTrace },
#endif
#endif
-#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "stats",
- /* ePragTyp: */ PragTyp_STATS,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
+ {/* zName: */ "stats",
+ /* ePragTyp: */ PragTyp_STATS,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 27, 5,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "synchronous",
- /* ePragTyp: */ PragTyp_SYNCHRONOUS,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "synchronous",
+ /* ePragTyp: */ PragTyp_SYNCHRONOUS,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "table_info",
- /* ePragTyp: */ PragTyp_TABLE_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "table_info",
+ /* ePragTyp: */ PragTyp_TABLE_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 8, 6,
+ /* iArg: */ 0 },
+ {/* zName: */ "table_xinfo",
+ /* ePragTyp: */ PragTyp_TABLE_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 8, 7,
+ /* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "temp_store",
- /* ePragTyp: */ PragTyp_TEMP_STORE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "temp_store_directory",
- /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
- { /* zName: */ "threads",
- /* ePragTyp: */ PragTyp_THREADS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "temp_store",
+ /* ePragTyp: */ PragTyp_TEMP_STORE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "temp_store_directory",
+ /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
+ /* ePragFlg: */ PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+ {/* zName: */ "threads",
+ /* ePragTyp: */ PragTyp_THREADS,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
+ {/* zName: */ "trusted_schema",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_TrustedSchema },
+#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "user_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_USER_VERSION },
+ {/* zName: */ "user_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_NoColumns1|PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_USER_VERSION },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if defined(SQLITE_DEBUG)
- { /* zName: */ "vdbe_addoptrace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeAddopTrace },
- { /* zName: */ "vdbe_debug",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
- { /* zName: */ "vdbe_eqp",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeEQP },
- { /* zName: */ "vdbe_listing",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeListing },
- { /* zName: */ "vdbe_trace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeTrace },
+ {/* zName: */ "vdbe_addoptrace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeAddopTrace },
+ {/* zName: */ "vdbe_debug",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
+ {/* zName: */ "vdbe_eqp",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeEQP },
+ {/* zName: */ "vdbe_listing",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeListing },
+ {/* zName: */ "vdbe_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_WAL)
- { /* zName: */ "wal_autocheckpoint",
- /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "wal_checkpoint",
- /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "wal_autocheckpoint",
+ /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "wal_checkpoint",
+ /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
+ /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ColNames: */ 44, 3,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "writable_schema",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
+ {/* zName: */ "writable_schema",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
-/* Number of pragmas: 60 on by default, 73 total. */
+/* Number of pragmas: 67 on by default, 77 total. */
/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/
/*
** Interpret the given string as a safety level. Return 0 for OFF,
-** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
+** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
** unrecognized string argument. The FULL and EXTRA option is disallowed
** if the omitFull parameter it 1.
**
@@ -111616,7 +125836,7 @@ static int getLockingMode(const char *z){
/*
** Interpret the given string as an auto-vacuum mode value.
**
-** The following strings, "none", "full" and "incremental" are
+** The following strings, "none", "full" and "incremental" are
** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
*/
static int getAutoVacuum(const char *z){
@@ -111688,29 +125908,29 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
#endif /* SQLITE_PAGER_PRAGMAS */
/*
-** Set the names of the first N columns to the values in azCol[]
+** Set result column names for a pragma.
*/
-static void setAllColumnNames(
- Vdbe *v, /* The query under construction */
- int N, /* Number of columns */
- const char **azCol /* Names of columns */
+static void setPragmaResultColumnNames(
+ Vdbe *v, /* The query under construction */
+ const PragmaName *pPragma /* The pragma */
){
- int i;
- sqlite3VdbeSetNumCols(v, N);
- for(i=0; i<N; i++){
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
+ u8 n = pPragma->nPragCName;
+ sqlite3VdbeSetNumCols(v, n==0 ? 1 : n);
+ if( n==0 ){
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC);
+ }else{
+ int i, j;
+ for(i=0, j=pPragma->iPragCName; i<n; i++, j++){
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j], SQLITE_STATIC);
+ }
}
}
-static void setOneColumnName(Vdbe *v, const char *z){
- setAllColumnNames(v, 1, &z);
-}
/*
** Generate code to return a single integer value.
*/
-static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
+static void returnSingleInt(Vdbe *v, i64 value){
sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
- setOneColumnName(v, zLabel);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
@@ -111719,12 +125939,10 @@ static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
*/
static void returnSingleText(
Vdbe *v, /* Prepared statement under construction */
- const char *zLabel, /* Name of the result column */
const char *zValue /* Value to be returned */
){
if( zValue ){
sqlite3VdbeLoadString(v, 1, (const char*)zValue);
- setOneColumnName(v, zLabel);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
@@ -111770,7 +125988,7 @@ static const char *actionName(u8 action){
case OE_SetDflt: zName = "SET DEFAULT"; break;
case OE_Cascade: zName = "CASCADE"; break;
case OE_Restrict: zName = "RESTRICT"; break;
- default: zName = "NO ACTION";
+ default: zName = "NO ACTION";
assert( action==OE_None ); break;
}
return zName;
@@ -111803,7 +126021,92 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
}
/*
-** Process a pragma statement.
+** Locate a pragma in the aPragmaName[] array.
+*/
+static const PragmaName *pragmaLocate(const char *zName){
+ int upr, lwr, mid = 0, rc;
+ lwr = 0;
+ upr = ArraySize(aPragmaName)-1;
+ while( lwr<=upr ){
+ mid = (lwr+upr)/2;
+ rc = sqlite3_stricmp(zName, aPragmaName[mid].zName);
+ if( rc==0 ) break;
+ if( rc<0 ){
+ upr = mid - 1;
+ }else{
+ lwr = mid + 1;
+ }
+ }
+ return lwr>upr ? 0 : &aPragmaName[mid];
+}
+
+/*
+** Create zero or more entries in the output for the SQL functions
+** defined by FuncDef p.
+*/
+static void pragmaFunclistLine(
+ Vdbe *v, /* The prepared statement being created */
+ FuncDef *p, /* A particular function definition */
+ int isBuiltin, /* True if this is a built-in function */
+ int showInternFuncs /* True if showing internal functions */
+){
+ for(; p; p=p->pNext){
+ const char *zType;
+ static const u32 mask =
+ SQLITE_DETERMINISTIC |
+ SQLITE_DIRECTONLY |
+ SQLITE_SUBTYPE |
+ SQLITE_INNOCUOUS |
+ SQLITE_FUNC_INTERNAL
+ ;
+ static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" };
+
+ assert( SQLITE_FUNC_ENCMASK==0x3 );
+ assert( strcmp(azEnc[SQLITE_UTF8],"utf8")==0 );
+ assert( strcmp(azEnc[SQLITE_UTF16LE],"utf16le")==0 );
+ assert( strcmp(azEnc[SQLITE_UTF16BE],"utf16be")==0 );
+
+ if( p->xSFunc==0 ) continue;
+ if( (p->funcFlags & SQLITE_FUNC_INTERNAL)!=0
+ && showInternFuncs==0
+ ){
+ continue;
+ }
+ if( p->xValue!=0 ){
+ zType = "w";
+ }else if( p->xFinalize!=0 ){
+ zType = "a";
+ }else{
+ zType = "s";
+ }
+ sqlite3VdbeMultiLoad(v, 1, "sissii",
+ p->zName, isBuiltin,
+ zType, azEnc[p->funcFlags&SQLITE_FUNC_ENCMASK],
+ p->nArg,
+ (p->funcFlags & mask) ^ SQLITE_INNOCUOUS
+ );
+ }
+}
+
+
+/*
+** Helper subroutine for PRAGMA integrity_check:
+**
+** Generate code to output a single-column result row with a value of the
+** string held in register 3. Decrement the result count in register 1
+** and halt if the maximum number of result rows have been issued.
+*/
+static int integrityCheckResultRow(Vdbe *v){
+ int addr;
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
+ addr = sqlite3VdbeAddOp3(v, OP_IfPos, 1, sqlite3VdbeCurrentAddr(v)+2, 1);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp0(v, OP_Halt);
+ return addr;
+}
+
+/*
+** Process a pragma statement.
**
** Pragmas are of this form:
**
@@ -111818,7 +126121,7 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
** id and pId2 is any empty string.
*/
SQLITE_PRIVATE void sqlite3Pragma(
- Parse *pParse,
+ Parse *pParse,
Token *pId1, /* First part of [schema.]id field */
Token *pId2, /* Second part of [schema.]id field, or NULL */
Token *pValue, /* Token for <value>, or NULL */
@@ -111830,12 +126133,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
Token *pId; /* Pointer to <id> token */
char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
int iDb; /* Database index for <database> */
- int lwr, upr, mid = 0; /* Binary search bounds */
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
- const struct sPragmaNames *pPragma;
+ const PragmaName *pPragma; /* The pragma */
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
@@ -111847,8 +126149,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iDb<0 ) return;
pDb = &db->aDb[iDb];
- /* If the temp database has been explicitly named as part of the
- ** pragma, make sure it is open.
+ /* If the temp database has been explicitly named as part of the
+ ** pragma, make sure it is open.
*/
if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
return;
@@ -111890,7 +126192,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
db->busyHandler.nBusy = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
- returnSingleText(v, "result", aFcntl[0]);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT);
+ returnSingleText(v, aFcntl[0]);
sqlite3_free(aFcntl[0]);
goto pragma_out;
}
@@ -111905,29 +126209,24 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
/* Locate the pragma in the lookup table */
- lwr = 0;
- upr = ArraySize(aPragmaNames)-1;
- while( lwr<=upr ){
- mid = (lwr+upr)/2;
- rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName);
- if( rc==0 ) break;
- if( rc<0 ){
- upr = mid - 1;
- }else{
- lwr = mid + 1;
- }
- }
- if( lwr>upr ) goto pragma_out;
- pPragma = &aPragmaNames[mid];
+ pPragma = pragmaLocate(zLeft);
+ if( pPragma==0 ) goto pragma_out;
/* Make sure the database schema is loaded if the pragma requires that */
- if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
+ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
}
+ /* Register the result column names for pragmas that return results */
+ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0
+ && ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
+ ){
+ setPragmaResultColumnNames(v, pPragma);
+ }
+
/* Jump to the appropriate pragma handler */
switch( pPragma->ePragTyp ){
-
+
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
/*
** PRAGMA [schema.]default_cache_size
@@ -111961,7 +126260,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
VdbeOp *aOp;
sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
- setOneColumnName(v, "cache_size");
pParse->nMem += 2;
sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
@@ -111996,13 +126294,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( pBt!=0 );
if( !zRight ){
int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
- returnSingleInt(v, "page_size", size);
+ returnSingleInt(v, size);
}else{
/* Malloc may fail when setting the page-size, as there is an internal
** buffer that the pager module resizes using sqlite3_realloc().
*/
db->nextPagesize = sqlite3Atoi(zRight);
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
sqlite3OomFault(db);
}
}
@@ -112011,18 +126309,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
/*
** PRAGMA [schema.]secure_delete
- ** PRAGMA [schema.]secure_delete=ON/OFF
+ ** PRAGMA [schema.]secure_delete=ON/OFF/FAST
**
** The first form reports the current setting for the
** secure_delete flag. The second form changes the secure_delete
- ** flag setting and reports thenew value.
+ ** flag setting and reports the new value.
*/
case PragTyp_SECURE_DELETE: {
Btree *pBt = pDb->pBt;
int b = -1;
assert( pBt!=0 );
if( zRight ){
- b = sqlite3GetBoolean(zRight, 0);
+ if( sqlite3_stricmp(zRight, "fast")==0 ){
+ b = 2;
+ }else{
+ b = sqlite3GetBoolean(zRight, 0);
+ }
}
if( pId2->n==0 && b>=0 ){
int ii;
@@ -112031,7 +126333,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
b = sqlite3BtreeSecureDelete(pBt, b);
- returnSingleInt(v, "secure_delete", b);
+ returnSingleInt(v, b);
break;
}
@@ -112040,7 +126342,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** PRAGMA [schema.]max_page_count=N
**
** The first form reports the current setting for the
- ** maximum number of pages in the database file. The
+ ** maximum number of pages in the database file. The
** second form attempts to change this setting. Both
** forms return the current setting.
**
@@ -112054,17 +126356,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_PAGE_COUNT: {
int iReg;
+ i64 x = 0;
sqlite3CodeVerifySchema(pParse, iDb);
iReg = ++pParse->nMem;
if( sqlite3Tolower(zLeft[0])=='p' ){
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
}else{
- sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
- sqlite3AbsInt32(sqlite3Atoi(zRight)));
+ if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){
+ if( x<0 ) x = 0;
+ else if( x>0xfffffffe ) x = 0xfffffffe;
+ }else{
+ x = 0;
+ }
+ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x);
}
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
break;
}
@@ -112110,7 +126416,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
zRet = "exclusive";
}
- returnSingleText(v, "locking_mode", zRet);
+ returnSingleText(v, zRet);
break;
}
@@ -112123,7 +126429,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
int ii; /* Loop counter */
- setOneColumnName(v, "journal_mode");
if( zRight==0 ){
/* If there is no "=MODE" part of the pragma, do a query for the
** current mode */
@@ -112139,6 +126444,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
** then do a query */
eMode = PAGER_JOURNALMODE_QUERY;
}
+ if( eMode==PAGER_JOURNALMODE_OFF && (db->flags & SQLITE_Defensive)!=0 ){
+ /* Do not allow journal-mode "OFF" in defensive since the database
+ ** can become corrupted using ordinary SQL when the journal is off */
+ eMode = PAGER_JOURNALMODE_QUERY;
+ }
}
if( eMode==PAGER_JOURNALMODE_QUERY && pId2->n==0 ){
/* Convert "PRAGMA journal_mode" into "PRAGMA main.journal_mode" */
@@ -112169,7 +126479,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
- returnSingleInt(v, "journal_size_limit", iLimit);
+ returnSingleInt(v, iLimit);
break;
}
@@ -112187,7 +126497,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Btree *pBt = pDb->pBt;
assert( pBt!=0 );
if( !zRight ){
- returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
+ returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt));
}else{
int eAuto = getAutoVacuum(zRight);
assert( eAuto>=0 && eAuto<=2 );
@@ -112199,7 +126509,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
- /* When setting the auto_vacuum mode to either "full" or
+ /* When setting the auto_vacuum mode to either "full" or
** "incremental", write the value of meta[6] in the database
** file. Before writing to meta[6], check that meta[3] indicates
** that this really is an auto-vacuum capable database.
@@ -112266,7 +126576,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_CACHE_SIZE: {
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){
- returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
+ returnSingleInt(v, pDb->pSchema->cache_size);
}else{
int size = sqlite3Atoi(zRight);
pDb->pSchema->cache_size = size;
@@ -112300,8 +126610,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_CACHE_SPILL: {
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){
- returnSingleInt(v, "cache_spill",
- (db->flags & SQLITE_CacheSpill)==0 ? 0 :
+ returnSingleInt(v,
+ (db->flags & SQLITE_CacheSpill)==0 ? 0 :
sqlite3BtreeSetSpillSize(pDb->pBt,0));
}else{
int size = 1;
@@ -112311,7 +126621,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( sqlite3GetBoolean(zRight, size!=0) ){
db->flags |= SQLITE_CacheSpill;
}else{
- db->flags &= ~SQLITE_CacheSpill;
+ db->flags &= ~(u64)SQLITE_CacheSpill;
}
setAllPagerFlags(db);
}
@@ -112354,7 +126664,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = SQLITE_OK;
#endif
if( rc==SQLITE_OK ){
- returnSingleInt(v, "mmap_size", sz);
+ returnSingleInt(v, sz);
}else if( rc!=SQLITE_NOTFOUND ){
pParse->nErr++;
pParse->rc = rc;
@@ -112375,7 +126685,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TEMP_STORE: {
if( !zRight ){
- returnSingleInt(v, "temp_store", db->temp_store);
+ returnSingleInt(v, db->temp_store);
}else{
changeTempStorage(pParse, zRight);
}
@@ -112394,7 +126704,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
if( !zRight ){
- returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
+ returnSingleText(v, sqlite3_temp_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
@@ -112438,7 +126748,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_DATA_STORE_DIRECTORY: {
if( !zRight ){
- returnSingleText(v, "data_store_directory", sqlite3_data_directory);
+ returnSingleText(v, sqlite3_data_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
@@ -112475,18 +126785,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
Pager *pPager = sqlite3BtreePager(pDb->pBt);
char *proxy_file_path = NULL;
sqlite3_file *pFile = sqlite3PagerFile(pPager);
- sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
+ sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
&proxy_file_path);
- returnSingleText(v, "lock_proxy_file", proxy_file_path);
+ returnSingleText(v, proxy_file_path);
}else{
Pager *pPager = sqlite3BtreePager(pDb->pBt);
sqlite3_file *pFile = sqlite3PagerFile(pPager);
int res;
if( zRight[0] ){
- res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
+ res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
zRight);
} else {
- res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
+ res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
NULL);
}
if( res!=SQLITE_OK ){
@@ -112496,8 +126806,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
break;
}
-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
-
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
/*
** PRAGMA [schema.]synchronous
** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA
@@ -112509,12 +126819,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_SYNCHRONOUS: {
if( !zRight ){
- returnSingleInt(v, "synchronous", pDb->safety_level-1);
+ returnSingleInt(v, pDb->safety_level-1);
}else{
if( !db->autoCommit ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"Safety level may not be changed inside a transaction");
- }else{
+ }else if( iDb!=1 ){
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
if( iLevel==0 ) iLevel = 1;
pDb->safety_level = iLevel;
@@ -112529,9 +126839,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
case PragTyp_FLAG: {
if( zRight==0 ){
- returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
+ setPragmaResultColumnNames(v, pPragma);
+ returnSingleInt(v, (db->flags & pPragma->iArg)!=0 );
}else{
- int mask = pPragma->iArg; /* Mask of bits to set or clear. */
+ u64 mask = pPragma->iArg; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
/* Foreign key support may not be enabled or disabled while not
** in auto-commit mode. */
@@ -112551,7 +126862,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
}
- /* Many of the flag-pragmas modify the code generated by the SQL
+ /* Many of the flag-pragmas modify the code generated by the SQL
** compiler (eg. count_changes). So add an opcode to expire all
** compiled SQL statements after modifying a pragma value.
*/
@@ -112574,26 +126885,33 @@ SQLITE_PRIVATE void sqlite3Pragma(
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
+ ** pk: Non-zero for PK fields.
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
+ sqlite3CodeVerifyNamedSchema(pParse, zDb);
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
if( pTab ){
- static const char *azCol[] = {
- "cid", "name", "type", "notnull", "dflt_value", "pk"
- };
int i, k;
int nHidden = 0;
Column *pCol;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
- pParse->nMem = 6;
- sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
+ pParse->nMem = 7;
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
- if( IsHiddenColumn(pCol) ){
- nHidden++;
- continue;
+ int isHidden = 0;
+ if( pCol->colFlags & COLFLAG_NOINSERT ){
+ if( pPragma->iArg==0 ){
+ nHidden++;
+ continue;
+ }
+ if( pCol->colFlags & COLFLAG_VIRTUAL ){
+ isHidden = 2; /* GENERATED ALWAYS AS ... VIRTUAL */
+ }else if( pCol->colFlags & COLFLAG_STORED ){
+ isHidden = 3; /* GENERATED ALWAYS AS ... STORED */
+ }else{ assert( pCol->colFlags & COLFLAG_HIDDEN );
+ isHidden = 1; /* HIDDEN */
+ }
}
if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
k = 0;
@@ -112602,55 +126920,62 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else{
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
}
- assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
- sqlite3VdbeMultiLoad(v, 1, "issisi",
+ assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN || isHidden>=2 );
+ sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi",
i-nHidden,
pCol->zName,
sqlite3ColumnType(pCol,""),
pCol->notNull ? 1 : 0,
- pCol->pDflt ? pCol->pDflt->u.zToken : 0,
- k);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
+ pCol->pDflt && isHidden<2 ? pCol->pDflt->u.zToken : 0,
+ k,
+ isHidden);
}
}
}
break;
+#ifdef SQLITE_DEBUG
case PragTyp_STATS: {
- static const char *azCol[] = { "table", "index", "width", "height" };
Index *pIdx;
HashElem *i;
- v = sqlite3GetVdbe(pParse);
- pParse->nMem = 4;
+ pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
- sqlite3VdbeMultiLoad(v, 1, "ssii",
+ sqlite3VdbeMultiLoad(v, 1, "ssiii",
pTab->zName,
0,
pTab->szTabRow,
- pTab->nRowLogEst);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+ pTab->nRowLogEst,
+ pTab->tabFlags);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeMultiLoad(v, 2, "sii",
+ sqlite3VdbeMultiLoad(v, 2, "siiiX",
pIdx->zName,
pIdx->szIdxRow,
- pIdx->aiRowLogEst[0]);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
+ pIdx->aiRowLogEst[0],
+ pIdx->hasStat1);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
}
}
break;
+#endif
case PragTyp_INDEX_INFO: if( zRight ){
Index *pIdx;
Table *pTab;
pIdx = sqlite3FindIndex(db, zRight, zDb);
+ if( pIdx==0 ){
+ /* If there is no index named zRight, check to see if there is a
+ ** WITHOUT ROWID table named zRight, and if there is, show the
+ ** structure of the PRIMARY KEY index for that table. */
+ pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
+ if( pTab && !HasRowid(pTab) ){
+ pIdx = sqlite3PrimaryKeyIndex(pTab);
+ }
+ }
if( pIdx ){
- static const char *azCol[] = {
- "seqno", "cid", "name", "desc", "coll", "key"
- };
+ int iIdxDb = sqlite3SchemaToIndex(db, pIdx->pSchema);
int i;
int mx;
if( pPragma->iArg ){
@@ -112663,15 +126988,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
pParse->nMem = 3;
}
pTab = pIdx->pTable;
- sqlite3CodeVerifySchema(pParse, iDb);
- assert( pParse->nMem<=ArraySize(azCol) );
- setAllColumnNames(v, pParse->nMem, azCol);
+ sqlite3CodeVerifySchema(pParse, iIdxDb);
+ assert( pParse->nMem<=pPragma->nPragCName );
for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i];
- sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
+ sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum,
cnum<0 ? 0 : pTab->aCol[cnum].zName);
if( pPragma->iArg ){
- sqlite3VdbeMultiLoad(v, 4, "isi",
+ sqlite3VdbeMultiLoad(v, 4, "isiX",
pIdx->aSortOrder[i],
pIdx->azColl[i],
i<pIdx->nKeyCol);
@@ -112688,13 +127012,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- static const char *azCol[] = {
- "seq", "name", "unique", "origin", "partial"
- };
- v = sqlite3GetVdbe(pParse);
+ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
pParse->nMem = 5;
- sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 5, azCol); assert( 5==ArraySize(azCol) );
+ sqlite3CodeVerifySchema(pParse, iTabDb);
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
const char *azOrigin[] = { "c", "u", "pk" };
sqlite3VdbeMultiLoad(v, 1, "isisi",
@@ -112703,17 +127023,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
IsUniqueIndex(pIdx),
azOrigin[pIdx->idxType],
pIdx->pPartIdxWhere!=0);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
}
}
}
break;
case PragTyp_DATABASE_LIST: {
- static const char *azCol[] = { "seq", "name", "file" };
int i;
pParse->nMem = 3;
- setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zDbSName!=0 );
@@ -112721,24 +127038,61 @@ SQLITE_PRIVATE void sqlite3Pragma(
i,
db->aDb[i].zDbSName,
sqlite3BtreeGetFilename(db->aDb[i].pBt));
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
}
break;
case PragTyp_COLLATION_LIST: {
- static const char *azCol[] = { "seq", "name" };
int i = 0;
HashElem *p;
pParse->nMem = 2;
- setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
}
break;
+
+#ifndef SQLITE_OMIT_INTROSPECTION_PRAGMAS
+ case PragTyp_FUNCTION_LIST: {
+ int i;
+ HashElem *j;
+ FuncDef *p;
+ int showInternFunc = (db->mDbFlags & DBFLAG_InternalFunc)!=0;
+ pParse->nMem = 6;
+ for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
+ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
+ pragmaFunclistLine(v, p, 1, showInternFunc);
+ }
+ }
+ for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
+ p = (FuncDef*)sqliteHashData(j);
+ pragmaFunclistLine(v, p, 0, showInternFunc);
+ }
+ }
+ break;
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ case PragTyp_MODULE_LIST: {
+ HashElem *j;
+ pParse->nMem = 1;
+ for(j=sqliteHashFirst(&db->aModule); j; j=sqliteHashNext(j)){
+ Module *pMod = (Module*)sqliteHashData(j);
+ sqlite3VdbeMultiLoad(v, 1, "s", pMod->zName);
+ }
+ }
+ break;
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+ case PragTyp_PRAGMA_LIST: {
+ int i;
+ for(i=0; i<ArraySize(aPragmaName); i++){
+ sqlite3VdbeMultiLoad(v, 1, "s", aPragmaName[i].zName);
+ }
+ }
+ break;
+#endif /* SQLITE_INTROSPECTION_PRAGMAS */
+
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
#ifndef SQLITE_OMIT_FOREIGN_KEY
@@ -112747,17 +127101,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
Table *pTab;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- v = sqlite3GetVdbe(pParse);
pFK = pTab->pFKey;
if( pFK ){
- static const char *azCol[] = {
- "id", "seq", "table", "from", "to", "on_update", "on_delete",
- "match"
- };
- int i = 0;
+ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ int i = 0;
pParse->nMem = 8;
- sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
+ sqlite3CodeVerifySchema(pParse, iTabDb);
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
@@ -112770,7 +127119,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
actionName(pFK->aAction[1]), /* ON UPDATE */
actionName(pFK->aAction[0]), /* ON DELETE */
"NONE");
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
}
++i;
pFK = pFK->pNextFrom;
@@ -112798,15 +127146,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
int addrTop; /* Top of a loop checking foreign keys */
int addrOk; /* Jump here if the key is OK */
int *aiCols; /* child to parent column mapping */
- static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
regResult = pParse->nMem+1;
pParse->nMem += 4;
regKey = ++pParse->nMem;
regRow = ++pParse->nMem;
- v = sqlite3GetVdbe(pParse);
- setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
- sqlite3CodeVerifySchema(pParse, iDb);
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
if( zRight ){
@@ -112817,6 +127161,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
k = sqliteHashNext(k);
}
if( pTab==0 || pTab->pFKey==0 ) continue;
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
+ zDb = db->aDb[iDb].zDbSName;
+ sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
@@ -112851,35 +127198,39 @@ SQLITE_PRIVATE void sqlite3Pragma(
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
assert( x==0 );
}
- addrOk = sqlite3VdbeMakeLabel(v);
- if( pParent && pIdx==0 ){
- int iKey = pFK->aCol[0].iFrom;
- assert( iKey>=0 && iKey<pTab->nCol );
- if( iKey!=pTab->iPKey ){
- sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
- sqlite3ColumnDefault(v, pTab, iKey, regRow);
- sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
- }else{
- sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
- }
- sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
+ addrOk = sqlite3VdbeMakeLabel(pParse);
+
+ /* Generate code to read the child key values into registers
+ ** regRow..regRow+n. If any of the child key values are NULL, this
+ ** row cannot cause an FK violation. Jump directly to addrOk in
+ ** this case. */
+ for(j=0; j<pFK->nCol; j++){
+ int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
+ sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
+ }
+
+ /* Generate code to query the parent index for a matching parent
+ ** key. If a match is found, jump to addrOk. */
+ if( pIdx ){
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
+ sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
+ sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
+ VdbeCoverage(v);
+ }else if( pParent ){
+ int jmp = sqlite3VdbeCurrentAddr(v)+2;
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
sqlite3VdbeGoto(v, addrOk);
- sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+ assert( pFK->nCol==1 );
+ }
+
+ /* Generate code to report an FK violation to the caller. */
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
}else{
- for(j=0; j<pFK->nCol; j++){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
- aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
- sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
- }
- if( pParent ){
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
- sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
- sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
- VdbeCoverage(v);
- }
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
}
- sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
- sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
+ sqlite3VdbeMultiLoad(v, regResult+2, "siX", pFK->zTo, i-1);
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
sqlite3VdbeResolveLabel(v, addrOk);
sqlite3DbFree(db, aiCols);
@@ -112892,19 +127243,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
#endif /* !defined(SQLITE_OMIT_TRIGGER) */
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
-#ifndef NDEBUG
- case PragTyp_PARSER_TRACE: {
- if( zRight ){
- if( sqlite3GetBoolean(zRight, 0) ){
- sqlite3ParserTrace(stdout, "parser: ");
- }else{
- sqlite3ParserTrace(0, 0);
- }
- }
- }
- break;
-#endif
-
+#ifndef SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA
/* Reinstall the LIKE and GLOB functions. The variant of LIKE
** used will be case sensitive or not depending on the RHS.
*/
@@ -112914,18 +127253,40 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
break;
+#endif /* SQLITE_OMIT_CASE_SENSITIVE_LIKE_PRAGMA */
#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
- /* Pragma "quick_check" is reduced version of
+ /* PRAGMA integrity_check
+ ** PRAGMA integrity_check(N)
+ ** PRAGMA quick_check
+ ** PRAGMA quick_check(N)
+ **
+ ** Verify the integrity of the database.
+ **
+ ** The "quick_check" is reduced version of
** integrity_check designed to detect most database corruption
- ** without most of the overhead of a full integrity-check.
+ ** without the overhead of cross-checking indexes. Quick_check
+ ** is linear time wherease integrity_check is O(NlogN).
+ **
+ ** The maximum nubmer of errors is 100 by default. A different default
+ ** can be specified using a numeric parameter N.
+ **
+ ** Or, the parameter N can be the name of a table. In that case, only
+ ** the one table named is verified. The freelist is only verified if
+ ** the named table is "sqlite_schema" (or one of its aliases).
+ **
+ ** All schemas are checked by default. To check just a single
+ ** schema, use the form:
+ **
+ ** PRAGMA schema.integrity_check;
*/
case PragTyp_INTEGRITY_CHECK: {
int i, j, addr, mxErr;
+ Table *pObjTab = 0; /* Check only this one table, if not NULL */
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
@@ -112944,35 +127305,33 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Initialize the VDBE program */
pParse->nMem = 6;
- setOneColumnName(v, "integrity_check");
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
if( zRight ){
- sqlite3GetInt32(zRight, &mxErr);
- if( mxErr<=0 ){
- mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ if( sqlite3GetInt32(zRight, &mxErr) ){
+ if( mxErr<=0 ){
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ }
+ }else{
+ pObjTab = sqlite3LocateTable(pParse, 0, zRight,
+ iDb>=0 ? db->aDb[iDb].zDbSName : 0);
}
}
- sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1); /* reg[1] holds errors left */
+ sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
- HashElem *x;
- Hash *pTbls;
- int *aRoot;
- int cnt = 0;
- int mxIdx = 0;
- int nIdx;
+ HashElem *x; /* For looping over tables in the schema */
+ Hash *pTbls; /* Set of all tables in the schema */
+ int *aRoot; /* Array of root page numbers of all btrees */
+ int cnt = 0; /* Number of entries in aRoot[] */
+ int mxIdx = 0; /* Maximum number of indexes for any table */
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
sqlite3CodeVerifySchema(pParse, i);
- addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Halt if out of errors */
- VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
- sqlite3VdbeJumpHere(v, addr);
/* Do an integrity check of the B-Tree
**
@@ -112982,26 +127341,34 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
- Table *pTab = sqliteHashData(x);
- Index *pIdx;
+ Table *pTab = sqliteHashData(x); /* Current table */
+ Index *pIdx; /* An index on pTab */
+ int nIdx; /* Number of indexes on pTab */
+ if( pObjTab && pObjTab!=pTab ) continue;
if( HasRowid(pTab) ) cnt++;
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
if( nIdx>mxIdx ) mxIdx = nIdx;
}
+ if( cnt==0 ) continue;
+ if( pObjTab ) cnt++;
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
if( aRoot==0 ) break;
- for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ cnt = 0;
+ if( pObjTab ) aRoot[++cnt] = 0;
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
- if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
+ if( pObjTab && pObjTab!=pTab ) continue;
+ if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- aRoot[cnt++] = pIdx->tnum;
+ aRoot[++cnt] = pIdx->tnum;
}
}
- aRoot[cnt] = 0;
+ aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
@@ -113010,14 +127377,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
P4_DYNAMIC);
- sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
+ sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 3);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
- for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk;
Index *pPrior = 0;
@@ -113025,15 +127391,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
int iDataCur, iIdxCur;
int r1 = -1;
- if( pTab->pIndex==0 ) continue;
+ if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
+ if( pObjTab && pObjTab!=pTab ) continue;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
- addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
- VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
- sqlite3VdbeJumpHere(v, addr);
- sqlite3ExprCacheClear(pParse);
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
+ /* reg[7] counts the number of entries in the table.
+ ** reg[8+i] counts the number of entries in the i-th index
+ */
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
@@ -113042,111 +127407,139 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
+ if( !isQuick ){
+ /* Sanity check on record header decoding */
+ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ }
/* Verify that all NOT NULL columns really are NOT NULL */
for(j=0; j<pTab->nCol; j++){
char *zErr;
- int jmp2, jmp3;
+ int jmp2;
if( j==pTab->iPKey ) continue;
if( pTab->aCol[j].notNull==0 ) continue;
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
+ sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ }
jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pTab->aCol[j].zName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
- jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
- sqlite3VdbeAddOp0(v, OP_Halt);
+ integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
- sqlite3VdbeJumpHere(v, jmp3);
}
- /* Validate index entries for the current row */
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- int jmp2, jmp3, jmp4, jmp5;
- int ckUniq = sqlite3VdbeMakeLabel(v);
- if( pPk==pIdx ) continue;
- r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
- pPrior, r1);
- pPrior = pIdx;
- sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
- /* Verify that an index entry exists for the current table row */
- jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
- pIdx->nColumn); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
- sqlite3VdbeLoadString(v, 3, "row ");
- sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
- sqlite3VdbeLoadString(v, 4, " missing from index ");
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
- sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
- jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
- sqlite3VdbeAddOp0(v, OP_Halt);
- sqlite3VdbeJumpHere(v, jmp2);
- /* For UNIQUE indexes, verify that only one entry exists with the
- ** current key. The entry is unique if (1) any column is NULL
- ** or (2) the next entry has a different key */
- if( IsUniqueIndex(pIdx) ){
- int uniqOk = sqlite3VdbeMakeLabel(v);
- int jmp6;
- int kk;
- for(kk=0; kk<pIdx->nKeyCol; kk++){
- int iCol = pIdx->aiColumn[kk];
- assert( iCol!=XN_ROWID && iCol<pTab->nCol );
- if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
- sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
- VdbeCoverage(v);
+ /* Verify CHECK constraints */
+ if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
+ ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
+ if( db->mallocFailed==0 ){
+ int addrCkFault = sqlite3VdbeMakeLabel(pParse);
+ int addrCkOk = sqlite3VdbeMakeLabel(pParse);
+ char *zErr;
+ int k;
+ pParse->iSelfTab = iDataCur + 1;
+ for(k=pCheck->nExpr-1; k>0; k--){
+ sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
+ }
+ sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
+ SQLITE_JUMPIFNULL);
+ sqlite3VdbeResolveLabel(v, addrCkFault);
+ pParse->iSelfTab = 0;
+ zErr = sqlite3MPrintf(db, "CHECK constraint failed in %s",
+ pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ integrityCheckResultRow(v);
+ sqlite3VdbeResolveLabel(v, addrCkOk);
+ }
+ sqlite3ExprListDelete(db, pCheck);
+ }
+ if( !isQuick ){ /* Omit the remaining tests for quick_check */
+ /* Validate index entries for the current row */
+ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ int jmp2, jmp3, jmp4, jmp5;
+ int ckUniq = sqlite3VdbeMakeLabel(pParse);
+ if( pPk==pIdx ) continue;
+ r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
+ pPrior, r1);
+ pPrior = pIdx;
+ sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */
+ /* Verify that an index entry exists for the current table row */
+ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
+ pIdx->nColumn); VdbeCoverage(v);
+ sqlite3VdbeLoadString(v, 3, "row ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlite3VdbeLoadString(v, 4, " missing from index ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
+ jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
+ jmp4 = integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, jmp2);
+ /* For UNIQUE indexes, verify that only one entry exists with the
+ ** current key. The entry is unique if (1) any column is NULL
+ ** or (2) the next entry has a different key */
+ if( IsUniqueIndex(pIdx) ){
+ int uniqOk = sqlite3VdbeMakeLabel(pParse);
+ int jmp6;
+ int kk;
+ for(kk=0; kk<pIdx->nKeyCol; kk++){
+ int iCol = pIdx->aiColumn[kk];
+ assert( iCol!=XN_ROWID && iCol<pTab->nCol );
+ if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
+ sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
+ VdbeCoverage(v);
+ }
+ jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
+ sqlite3VdbeGoto(v, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp6);
+ sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
+ pIdx->nKeyCol); VdbeCoverage(v);
+ sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
+ sqlite3VdbeGoto(v, jmp5);
+ sqlite3VdbeResolveLabel(v, uniqOk);
}
- jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
- sqlite3VdbeGoto(v, uniqOk);
- sqlite3VdbeJumpHere(v, jmp6);
- sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
- pIdx->nKeyCol); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
- sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
- sqlite3VdbeGoto(v, jmp5);
- sqlite3VdbeResolveLabel(v, uniqOk);
+ sqlite3VdbeJumpHere(v, jmp4);
+ sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
- sqlite3VdbeJumpHere(v, jmp4);
- sqlite3ResolvePartIdxLabel(pParse, jmp3);
}
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, loopTop-1);
-#ifndef SQLITE_OMIT_BTREECOUNT
- sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- if( pPk==pIdx ) continue;
- addr = sqlite3VdbeCurrentAddr(v);
- sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
- sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
- sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
- sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
- sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
- sqlite3VdbeLoadString(v, 3, pIdx->zName);
- sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
+ if( !isQuick ){
+ sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
+ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ if( pPk==pIdx ) continue;
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
+ addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+j, 0, 3); VdbeCoverage(v);
+ sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
+ sqlite3VdbeLoadString(v, 4, pIdx->zName);
+ sqlite3VdbeAddOp3(v, OP_Concat, 4, 2, 3);
+ integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, addr);
+ }
}
-#endif /* SQLITE_OMIT_BTREECOUNT */
- }
+ }
}
{
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
{ OP_AddImm, 1, 0, 0}, /* 0 */
- { OP_If, 1, 4, 0}, /* 1 */
+ { OP_IfNotZero, 1, 4, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0}, /* 3 */
+ { OP_Halt, 0, 0, 0}, /* 4 */
+ { OP_String8, 0, 3, 0}, /* 5 */
+ { OP_Goto, 0, 3, 0}, /* 6 */
};
VdbeOp *aOp;
aOp = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
if( aOp ){
- aOp[0].p2 = -mxErr;
+ aOp[0].p2 = 1-mxErr;
aOp[2].p4type = P4_STATIC;
aOp[2].p4.z = "ok";
+ aOp[5].p4type = P4_STATIC;
+ aOp[5].p4.z = (char*)sqlite3ErrStr(SQLITE_CORRUPT);
}
+ sqlite3VdbeChangeP3(v, 0, sqlite3VdbeCurrentAddr(v)-2);
}
}
break;
@@ -113165,7 +127558,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** encoding that will be used for the main database file if a new file
** is created. If an existing main database file is opened, then the
** default text encoding for the existing database is used.
- **
+ **
** In all cases new databases created using the ATTACH command are
** created to use the same default text encoding as the main database. If
** the main database has not been initialized and/or created when ATTACH
@@ -113196,21 +127589,19 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
- returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
+ returnSingleText(v, encnames[ENC(pParse->db)].zName);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
** will be overwritten when the schema is next loaded. If it does not
** already exists, it will be created to use the new encoding value.
*/
- if(
- !(DbHasProperty(db, 0, DB_SchemaLoaded)) ||
- DbHasProperty(db, 0, DB_Empty)
- ){
+ if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
- SCHEMA_ENC(db) = ENC(db) =
- pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
+ u8 enc = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
+ SCHEMA_ENC(db) = enc;
+ sqlite3SetTextEncoding(db, enc);
break;
}
}
@@ -113259,7 +127650,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_HEADER_VALUE: {
int iCookie = pPragma->iArg; /* Which cookie to read or write */
sqlite3VdbeUsesBtree(v, iDb);
- if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
+ if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
@@ -113273,6 +127664,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
aOp[1].p1 = iDb;
aOp[1].p2 = iCookie;
aOp[1].p3 = sqlite3Atoi(zRight);
+ aOp[1].p5 = 1;
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
@@ -113287,8 +127679,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
aOp[0].p1 = iDb;
aOp[1].p1 = iDb;
aOp[1].p3 = iCookie;
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
sqlite3VdbeReusable(v);
}
}
@@ -113306,7 +127696,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i = 0;
const char *zOpt;
pParse->nMem = 1;
- setOneColumnName(v, "compile_option");
while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
sqlite3VdbeLoadString(v, 1, zOpt);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
@@ -113323,7 +127712,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
** Checkpoint the database.
*/
case PragTyp_WAL_CHECKPOINT: {
- static const char *azCol[] = { "busy", "log", "checkpointed" };
int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
int eMode = SQLITE_CHECKPOINT_PASSIVE;
if( zRight ){
@@ -113335,7 +127723,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
eMode = SQLITE_CHECKPOINT_TRUNCATE;
}
}
- setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
pParse->nMem = 3;
sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
@@ -113354,8 +127741,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight ){
sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
}
- returnSingleInt(v, "wal_autocheckpoint",
- db->xWalCallback==sqlite3WalDefaultHook ?
+ returnSingleInt(v,
+ db->xWalCallback==sqlite3WalDefaultHook ?
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
}
break;
@@ -113374,6 +127761,119 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
/*
+ ** PRAGMA optimize
+ ** PRAGMA optimize(MASK)
+ ** PRAGMA schema.optimize
+ ** PRAGMA schema.optimize(MASK)
+ **
+ ** Attempt to optimize the database. All schemas are optimized in the first
+ ** two forms, and only the specified schema is optimized in the latter two.
+ **
+ ** The details of optimizations performed by this pragma are expected
+ ** to change and improve over time. Applications should anticipate that
+ ** this pragma will perform new optimizations in future releases.
+ **
+ ** The optional argument is a bitmask of optimizations to perform:
+ **
+ ** 0x0001 Debugging mode. Do not actually perform any optimizations
+ ** but instead return one line of text for each optimization
+ ** that would have been done. Off by default.
+ **
+ ** 0x0002 Run ANALYZE on tables that might benefit. On by default.
+ ** See below for additional information.
+ **
+ ** 0x0004 (Not yet implemented) Record usage and performance
+ ** information from the current session in the
+ ** database file so that it will be available to "optimize"
+ ** pragmas run by future database connections.
+ **
+ ** 0x0008 (Not yet implemented) Create indexes that might have
+ ** been helpful to recent queries
+ **
+ ** The default MASK is and always shall be 0xfffe. 0xfffe means perform all
+ ** of the optimizations listed above except Debug Mode, including new
+ ** optimizations that have not yet been invented. If new optimizations are
+ ** ever added that should be off by default, those off-by-default
+ ** optimizations will have bitmasks of 0x10000 or larger.
+ **
+ ** DETERMINATION OF WHEN TO RUN ANALYZE
+ **
+ ** In the current implementation, a table is analyzed if only if all of
+ ** the following are true:
+ **
+ ** (1) MASK bit 0x02 is set.
+ **
+ ** (2) The query planner used sqlite_stat1-style statistics for one or
+ ** more indexes of the table at some point during the lifetime of
+ ** the current connection.
+ **
+ ** (3) One or more indexes of the table are currently unanalyzed OR
+ ** the number of rows in the table has increased by 25 times or more
+ ** since the last time ANALYZE was run.
+ **
+ ** The rules for when tables are analyzed are likely to change in
+ ** future releases.
+ */
+ case PragTyp_OPTIMIZE: {
+ int iDbLast; /* Loop termination point for the schema loop */
+ int iTabCur; /* Cursor for a table whose size needs checking */
+ HashElem *k; /* Loop over tables of a schema */
+ Schema *pSchema; /* The current schema */
+ Table *pTab; /* A table in the schema */
+ Index *pIdx; /* An index of the table */
+ LogEst szThreshold; /* Size threshold above which reanalysis is needd */
+ char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
+ u32 opMask; /* Mask of operations to perform */
+
+ if( zRight ){
+ opMask = (u32)sqlite3Atoi(zRight);
+ if( (opMask & 0x02)==0 ) break;
+ }else{
+ opMask = 0xfffe;
+ }
+ iTabCur = pParse->nTab++;
+ for(iDbLast = zDb?iDb:db->nDb-1; iDb<=iDbLast; iDb++){
+ if( iDb==1 ) continue;
+ sqlite3CodeVerifySchema(pParse, iDb);
+ pSchema = db->aDb[iDb].pSchema;
+ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
+ pTab = (Table*)sqliteHashData(k);
+
+ /* If table pTab has not been used in a way that would benefit from
+ ** having analysis statistics during the current session, then skip it.
+ ** This also has the effect of skipping virtual tables and views */
+ if( (pTab->tabFlags & TF_StatsUsed)==0 ) continue;
+
+ /* Reanalyze if the table is 25 times larger than the last analysis */
+ szThreshold = pTab->nRowLogEst + 46; assert( sqlite3LogEst(25)==46 );
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( !pIdx->hasStat1 ){
+ szThreshold = 0; /* Always analyze if any index lacks statistics */
+ break;
+ }
+ }
+ if( szThreshold ){
+ sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
+ sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
+ sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
+ VdbeCoverage(v);
+ }
+ zSubSql = sqlite3MPrintf(db, "ANALYZE \"%w\".\"%w\"",
+ db->aDb[iDb].zDbSName, pTab->zName);
+ if( opMask & 0x01 ){
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, r1, 0, zSubSql, P4_DYNAMIC);
+ sqlite3VdbeAddOp2(v, OP_ResultRow, r1, 1);
+ }else{
+ sqlite3VdbeAddOp4(v, OP_SqlExec, 0, 0, 0, zSubSql, P4_DYNAMIC);
+ }
+ }
+ }
+ sqlite3VdbeAddOp0(v, OP_Expire);
+ break;
+ }
+
+ /*
** PRAGMA busy_timeout
** PRAGMA busy_timeout = N
**
@@ -113387,7 +127887,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight ){
sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
}
- returnSingleInt(v, "timeout", db->busyTimeout);
+ returnSingleInt(v, db->busyTimeout);
break;
}
@@ -113407,7 +127907,28 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
sqlite3_soft_heap_limit64(N);
}
- returnSingleInt(v, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
+ returnSingleInt(v, sqlite3_soft_heap_limit64(-1));
+ break;
+ }
+
+ /*
+ ** PRAGMA hard_heap_limit
+ ** PRAGMA hard_heap_limit = N
+ **
+ ** Invoke sqlite3_hard_heap_limit64() to query or set the hard heap
+ ** limit. The hard heap limit can be activated or lowered by this
+ ** pragma, but not raised or deactivated. Only the
+ ** sqlite3_hard_heap_limit64() C-language API can raise or deactivate
+ ** the hard heap limit. This allows an application to set a heap limit
+ ** constraint that cannot be relaxed by an untrusted SQL script.
+ */
+ case PragTyp_HARD_HEAP_LIMIT: {
+ sqlite3_int64 N;
+ if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
+ sqlite3_int64 iPrior = sqlite3_hard_heap_limit64(-1);
+ if( N>0 && (iPrior==0 || iPrior>N) ) sqlite3_hard_heap_limit64(N);
+ }
+ returnSingleInt(v, sqlite3_hard_heap_limit64(-1));
break;
}
@@ -113426,8 +127947,26 @@ SQLITE_PRIVATE void sqlite3Pragma(
){
sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
}
- returnSingleInt(v, "threads",
- sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
+ returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
+ break;
+ }
+
+ /*
+ ** PRAGMA analysis_limit
+ ** PRAGMA analysis_limit = N
+ **
+ ** Configure the maximum number of rows that ANALYZE will examine
+ ** in each index that it looks at. Return the new limit.
+ */
+ case PragTyp_ANALYSIS_LIMIT: {
+ sqlite3_int64 N;
+ if( zRight
+ && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK
+ && N>=0
+ ){
+ db->nAnalysisLimit = (int)(N&0x7fffffff);
+ }
+ returnSingleInt(v, db->nAnalysisLimit);
break;
}
@@ -113439,9 +127978,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
static const char *const azLockName[] = {
"unlocked", "shared", "reserved", "pending", "exclusive"
};
- static const char *azCol[] = { "database", "status" };
int i;
- setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
pParse->nMem = 2;
for(i=0; i<db->nDb; i++){
Btree *pBt;
@@ -113451,66 +127988,350 @@ SQLITE_PRIVATE void sqlite3Pragma(
pBt = db->aDb[i].pBt;
if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
zState = "closed";
- }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
+ }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
zState = azLockName[j];
}
sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
break;
}
#endif
-#ifdef SQLITE_HAS_CODEC
- case PragTyp_KEY: {
- if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
- break;
- }
- case PragTyp_REKEY: {
- if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight));
- break;
- }
- case PragTyp_HEXKEY: {
- if( zRight ){
- u8 iByte;
- int i;
- char zKey[40];
- for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){
- iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
- if( (i&1)!=0 ) zKey[i/2] = iByte;
- }
- if( (zLeft[3] & 0xf)==0xb ){
- sqlite3_key_v2(db, zDb, zKey, i/2);
- }else{
- sqlite3_rekey_v2(db, zDb, zKey, i/2);
- }
- }
- break;
- }
-#endif
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
+#if defined(SQLITE_ENABLE_CEROD)
case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){
-#ifdef SQLITE_HAS_CODEC
- if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
- sqlite3_activate_see(&zRight[4]);
- }
-#endif
-#ifdef SQLITE_ENABLE_CEROD
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
sqlite3_activate_cerod(&zRight[6]);
}
-#endif
}
break;
#endif
} /* End of the PRAGMA switch */
+ /* The following block is a no-op unless SQLITE_DEBUG is defined. Its only
+ ** purpose is to execute assert() statements to verify that if the
+ ** PragFlg_NoColumns1 flag is set and the caller specified an argument
+ ** to the PRAGMA, the implementation has not added any OP_ResultRow
+ ** instructions to the VM. */
+ if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){
+ sqlite3VdbeVerifyNoResultRow(v);
+ }
+
pragma_out:
sqlite3DbFree(db, zLeft);
sqlite3DbFree(db, zRight);
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*****************************************************************************
+** Implementation of an eponymous virtual table that runs a pragma.
+**
+*/
+typedef struct PragmaVtab PragmaVtab;
+typedef struct PragmaVtabCursor PragmaVtabCursor;
+struct PragmaVtab {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database connection to which it belongs */
+ const PragmaName *pName; /* Name of the pragma */
+ u8 nHidden; /* Number of hidden columns */
+ u8 iHidden; /* Index of the first hidden column */
+};
+struct PragmaVtabCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ sqlite3_stmt *pPragma; /* The pragma statement to run */
+ sqlite_int64 iRowid; /* Current rowid */
+ char *azArg[2]; /* Value of the argument and schema */
+};
+
+/*
+** Pragma virtual table module xConnect method.
+*/
+static int pragmaVtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ const PragmaName *pPragma = (const PragmaName*)pAux;
+ PragmaVtab *pTab = 0;
+ int rc;
+ int i, j;
+ char cSep = '(';
+ StrAccum acc;
+ char zBuf[200];
+
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3_str_appendall(&acc, "CREATE TABLE x");
+ for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){
+ sqlite3_str_appendf(&acc, "%c\"%s\"", cSep, pragCName[j]);
+ cSep = ',';
+ }
+ if( i==0 ){
+ sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName);
+ i++;
+ }
+ j = 0;
+ if( pPragma->mPragFlg & PragFlg_Result1 ){
+ sqlite3_str_appendall(&acc, ",arg HIDDEN");
+ j++;
+ }
+ if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){
+ sqlite3_str_appendall(&acc, ",schema HIDDEN");
+ j++;
+ }
+ sqlite3_str_append(&acc, ")", 1);
+ sqlite3StrAccumFinish(&acc);
+ assert( strlen(zBuf) < sizeof(zBuf)-1 );
+ rc = sqlite3_declare_vtab(db, zBuf);
+ if( rc==SQLITE_OK ){
+ pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab));
+ if( pTab==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pTab, 0, sizeof(PragmaVtab));
+ pTab->pName = pPragma;
+ pTab->db = db;
+ pTab->iHidden = i;
+ pTab->nHidden = j;
+ }
+ }else{
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Pragma virtual table module xDisconnect method.
+*/
+static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){
+ PragmaVtab *pTab = (PragmaVtab*)pVtab;
+ sqlite3_free(pTab);
+ return SQLITE_OK;
+}
+
+/* Figure out the best index to use to search a pragma virtual table.
+**
+** There are not really any index choices. But we want to encourage the
+** query planner to give == constraints on as many hidden parameters as
+** possible, and especially on the first hidden parameter. So return a
+** high cost if hidden parameters are unconstrained.
+*/
+static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ PragmaVtab *pTab = (PragmaVtab*)tab;
+ const struct sqlite3_index_constraint *pConstraint;
+ int i, j;
+ int seen[2];
+
+ pIdxInfo->estimatedCost = (double)1;
+ if( pTab->nHidden==0 ){ return SQLITE_OK; }
+ pConstraint = pIdxInfo->aConstraint;
+ seen[0] = 0;
+ seen[1] = 0;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( pConstraint->iColumn < pTab->iHidden ) continue;
+ j = pConstraint->iColumn - pTab->iHidden;
+ assert( j < 2 );
+ seen[j] = i+1;
+ }
+ if( seen[0]==0 ){
+ pIdxInfo->estimatedCost = (double)2147483647;
+ pIdxInfo->estimatedRows = 2147483647;
+ return SQLITE_OK;
+ }
+ j = seen[0]-1;
+ pIdxInfo->aConstraintUsage[j].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[j].omit = 1;
+ if( seen[1]==0 ) return SQLITE_OK;
+ pIdxInfo->estimatedCost = (double)20;
+ pIdxInfo->estimatedRows = 20;
+ j = seen[1]-1;
+ pIdxInfo->aConstraintUsage[j].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[j].omit = 1;
+ return SQLITE_OK;
+}
+
+/* Create a new cursor for the pragma virtual table */
+static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
+ PragmaVtabCursor *pCsr;
+ pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr));
+ if( pCsr==0 ) return SQLITE_NOMEM;
+ memset(pCsr, 0, sizeof(PragmaVtabCursor));
+ pCsr->base.pVtab = pVtab;
+ *ppCursor = &pCsr->base;
+ return SQLITE_OK;
+}
+
+/* Clear all content from pragma virtual table cursor. */
+static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
+ int i;
+ sqlite3_finalize(pCsr->pPragma);
+ pCsr->pPragma = 0;
+ for(i=0; i<ArraySize(pCsr->azArg); i++){
+ sqlite3_free(pCsr->azArg[i]);
+ pCsr->azArg[i] = 0;
+ }
+}
+
+/* Close a pragma virtual table cursor */
+static int pragmaVtabClose(sqlite3_vtab_cursor *cur){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur;
+ pragmaVtabCursorClear(pCsr);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/* Advance the pragma virtual table cursor to the next row */
+static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ int rc = SQLITE_OK;
+
+ /* Increment the xRowid value */
+ pCsr->iRowid++;
+ assert( pCsr->pPragma );
+ if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){
+ rc = sqlite3_finalize(pCsr->pPragma);
+ pCsr->pPragma = 0;
+ pragmaVtabCursorClear(pCsr);
+ }
+ return rc;
+}
+
+/*
+** Pragma virtual table module xFilter method.
+*/
+static int pragmaVtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
+ int rc;
+ int i, j;
+ StrAccum acc;
+ char *zSql;
+
+ UNUSED_PARAMETER(idxNum);
+ UNUSED_PARAMETER(idxStr);
+ pragmaVtabCursorClear(pCsr);
+ j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1;
+ for(i=0; i<argc; i++, j++){
+ const char *zText = (const char*)sqlite3_value_text(argv[i]);
+ assert( j<ArraySize(pCsr->azArg) );
+ assert( pCsr->azArg[j]==0 );
+ if( zText ){
+ pCsr->azArg[j] = sqlite3_mprintf("%s", zText);
+ if( pCsr->azArg[j]==0 ){
+ return SQLITE_NOMEM;
+ }
+ }
+ }
+ sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]);
+ sqlite3_str_appendall(&acc, "PRAGMA ");
+ if( pCsr->azArg[1] ){
+ sqlite3_str_appendf(&acc, "%Q.", pCsr->azArg[1]);
+ }
+ sqlite3_str_appendall(&acc, pTab->pName->zName);
+ if( pCsr->azArg[0] ){
+ sqlite3_str_appendf(&acc, "=%Q", pCsr->azArg[0]);
+ }
+ zSql = sqlite3StrAccumFinish(&acc);
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0);
+ sqlite3_free(zSql);
+ if( rc!=SQLITE_OK ){
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ return rc;
+ }
+ return pragmaVtabNext(pVtabCursor);
+}
+
+/*
+** Pragma virtual table module xEof method.
+*/
+static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ return (pCsr->pPragma==0);
+}
+
+/* The xColumn method simply returns the corresponding column from
+** the PRAGMA.
+*/
+static int pragmaVtabColumn(
+ sqlite3_vtab_cursor *pVtabCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
+ if( i<pTab->iHidden ){
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i));
+ }else{
+ sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Pragma virtual table module xRowid method.
+*/
+static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ *p = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+/* The pragma virtual table object */
+static const sqlite3_module pragmaVtabModule = {
+ 0, /* iVersion */
+ 0, /* xCreate - create a table */
+ pragmaVtabConnect, /* xConnect - connect to an existing table */
+ pragmaVtabBestIndex, /* xBestIndex - Determine search strategy */
+ pragmaVtabDisconnect, /* xDisconnect - Disconnect from a table */
+ 0, /* xDestroy - Drop a table */
+ pragmaVtabOpen, /* xOpen - open a cursor */
+ pragmaVtabClose, /* xClose - close a cursor */
+ pragmaVtabFilter, /* xFilter - configure scan constraints */
+ pragmaVtabNext, /* xNext - advance a cursor */
+ pragmaVtabEof, /* xEof */
+ pragmaVtabColumn, /* xColumn - read data */
+ pragmaVtabRowid, /* xRowid - read data */
+ 0, /* xUpdate - write data */
+ 0, /* xBegin - begin transaction */
+ 0, /* xSync - sync transaction */
+ 0, /* xCommit - commit transaction */
+ 0, /* xRollback - rollback transaction */
+ 0, /* xFindFunction - function overloading */
+ 0, /* xRename - rename the table */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+/*
+** Check to see if zTabName is really the name of a pragma. If it is,
+** then register an eponymous virtual table for that pragma and return
+** a pointer to the Module object for the new virtual table.
+*/
+SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){
+ const PragmaName *pName;
+ assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 );
+ pName = pragmaLocate(zName+7);
+ if( pName==0 ) return 0;
+ if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0;
+ assert( sqlite3HashFind(&db->aModule, zName)==0 );
+ return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0);
+}
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
#endif /* SQLITE_OMIT_PRAGMA */
@@ -113543,17 +128364,50 @@ static void corruptSchema(
const char *zExtra /* Error information */
){
sqlite3 *db = pData->db;
- if( !db->mallocFailed && (db->flags & SQLITE_RecoveryMode)==0 ){
+ if( db->mallocFailed ){
+ pData->rc = SQLITE_NOMEM_BKPT;
+ }else if( pData->pzErrMsg[0]!=0 ){
+ /* A error message has already been generated. Do not overwrite it */
+ }else if( pData->mInitFlags & INITFLAG_AlterTable ){
+ *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
+ pData->rc = SQLITE_ERROR;
+ }else if( db->flags & SQLITE_WriteSchema ){
+ pData->rc = SQLITE_CORRUPT_BKPT;
+ }else{
char *z;
if( zObj==0 ) zObj = "?";
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
- if( zExtra ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
- sqlite3DbFree(db, *pData->pzErrMsg);
+ if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
*pData->pzErrMsg = z;
+ pData->rc = SQLITE_CORRUPT_BKPT;
+ }
+}
+
+/*
+** Check to see if any sibling index (another index on the same table)
+** of pIndex has the same root page number, and if it does, return true.
+** This would indicate a corrupt schema.
+*/
+SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index *pIndex){
+ Index *p;
+ for(p=pIndex->pTable->pIndex; p; p=p->pNext){
+ if( p->tnum==pIndex->tnum && p!=pIndex ) return 1;
}
- pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
+ return 0;
}
+/* forward declaration */
+static int sqlite3Prepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
+ Vdbe *pReprepare, /* VM being reprepared */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+);
+
+
/*
** This is the callback routine for the code that initializes the
** database. See sqlite3Init() below for additional information.
@@ -113561,9 +128415,11 @@ static void corruptSchema(
**
** Each callback contains the following information:
**
-** argv[0] = name of thing being created
-** argv[1] = root page number for table or index. 0 for trigger or view.
-** argv[2] = SQL text for the CREATE statement.
+** argv[0] = type of object: "table", "index", "trigger", or "view".
+** argv[1] = name of thing being created
+** argv[2] = associated table if an index or trigger
+** argv[3] = root page number for table or index. 0 for trigger or view.
+** argv[4] = SQL text for the CREATE statement.
**
*/
SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
@@ -113571,20 +128427,21 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
sqlite3 *db = pData->db;
int iDb = pData->iDb;
- assert( argc==3 );
+ assert( argc==5 );
UNUSED_PARAMETER2(NotUsed, argc);
assert( sqlite3_mutex_held(db->mutex) );
- DbClearProperty(db, iDb, DB_Empty);
+ db->mDbFlags |= DBFLAG_EncodingFixed;
+ pData->nInitRow++;
if( db->mallocFailed ){
- corruptSchema(pData, argv[0], 0);
+ corruptSchema(pData, argv[1], 0);
return 1;
}
assert( iDb>=0 && iDb<db->nDb );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
- if( argv[1]==0 ){
- corruptSchema(pData, argv[0], 0);
- }else if( sqlite3_strnicmp(argv[2],"create ",7)==0 ){
+ if( argv[3]==0 ){
+ corruptSchema(pData, argv[1], 0);
+ }else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data
@@ -113597,28 +128454,36 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
assert( db->init.busy );
db->init.iDb = iDb;
- db->init.newTnum = sqlite3Atoi(argv[1]);
+ if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0
+ || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
+ ){
+ if( sqlite3Config.bExtraSchemaChecks ){
+ corruptSchema(pData, argv[1], "invalid rootpage");
+ }
+ }
db->init.orphanTrigger = 0;
- TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
+ db->init.azInit = argv;
+ pStmt = 0;
+ TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
db->init.iDb = saved_iDb;
- assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
+ /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
}else{
- pData->rc = rc;
+ if( rc > pData->rc ) pData->rc = rc;
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
- corruptSchema(pData, argv[0], sqlite3_errmsg(db));
+ corruptSchema(pData, argv[1], sqlite3_errmsg(db));
}
}
}
sqlite3_finalize(pStmt);
- }else if( argv[0]==0 || (argv[2]!=0 && argv[2][0]!=0) ){
- corruptSchema(pData, argv[0], 0);
+ }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
+ corruptSchema(pData, argv[1], 0);
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -113627,16 +128492,18 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
** to do here is record the root page number for that index.
*/
Index *pIndex;
- pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
+ pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
if( pIndex==0 ){
- /* This can occur if there exists an index on a TEMP table which
- ** has the same name as another index on a permanent index. Since
- ** the permanent table is hidden by the TEMP table, we can also
- ** safely ignore the index on the permanent table.
- */
- /* Do Nothing */;
- }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){
- corruptSchema(pData, argv[0], "invalid rootpage");
+ corruptSchema(pData, argv[1], "orphan index");
+ }else
+ if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
+ || pIndex->tnum<2
+ || pIndex->tnum>pData->mxPage
+ || sqlite3IndexHasDuplicateRootPage(pIndex)
+ ){
+ if( sqlite3Config.bExtraSchemaChecks ){
+ corruptSchema(pData, argv[1], "invalid rootpage");
+ }
}
}
return 0;
@@ -113650,39 +128517,49 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
** auxiliary databases. Return one of the SQLITE_ error codes to
** indicate success or failure.
*/
-static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
+SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
int rc;
int i;
#ifndef SQLITE_OMIT_DEPRECATED
int size;
#endif
Db *pDb;
- char const *azArg[4];
+ char const *azArg[6];
int meta[5];
InitData initData;
- const char *zMasterName;
+ const char *zSchemaTabName;
int openedTransaction = 0;
+ int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);
+ assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pSchema );
assert( sqlite3_mutex_held(db->mutex) );
assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
- /* Construct the in-memory representation schema tables (sqlite_master or
- ** sqlite_temp_master) by invoking the parser directly. The appropriate
+ db->init.busy = 1;
+
+ /* Construct the in-memory representation schema tables (sqlite_schema or
+ ** sqlite_temp_schema) by invoking the parser directly. The appropriate
** table name will be inserted automatically by the parser so we can just
** use the abbreviation "x" here. The parser will also automatically tag
** the schema table as read-only. */
- azArg[0] = zMasterName = SCHEMA_TABLE(iDb);
- azArg[1] = "1";
- azArg[2] = "CREATE TABLE x(type text,name text,tbl_name text,"
- "rootpage integer,sql text)";
- azArg[3] = 0;
+ azArg[0] = "table";
+ azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb);
+ azArg[2] = azArg[1];
+ azArg[3] = "1";
+ azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text,"
+ "rootpage int,sql text)";
+ azArg[5] = 0;
initData.db = db;
initData.iDb = iDb;
initData.rc = SQLITE_OK;
initData.pzErrMsg = pzErrMsg;
- sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
+ initData.mInitFlags = mFlags;
+ initData.nInitRow = 0;
+ initData.mxPage = 0;
+ sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
+ db->mDbFlags &= mask;
if( initData.rc ){
rc = initData.rc;
goto error_out;
@@ -113692,18 +128569,18 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
*/
pDb = &db->aDb[iDb];
if( pDb->pBt==0 ){
- if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
- DbSetProperty(db, 1, DB_SchemaLoaded);
- }
- return SQLITE_OK;
+ assert( iDb==1 );
+ DbSetProperty(db, 1, DB_SchemaLoaded);
+ rc = SQLITE_OK;
+ goto error_out;
}
/* If there is not already a read-only (or read-write) transaction opened
- ** on the b-tree database, open one now. If a transaction is opened, it
+ ** on the b-tree database, open one now. If a transaction is opened, it
** will be closed before this function returns. */
sqlite3BtreeEnter(pDb->pBt);
if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
- rc = sqlite3BtreeBeginTrans(pDb->pBt, 0);
+ rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0);
if( rc!=SQLITE_OK ){
sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
goto initone_error_out;
@@ -113731,6 +128608,9 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
for(i=0; i<ArraySize(meta); i++){
sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]);
}
+ if( (db->flags & SQLITE_ResetDatabase)!=0 ){
+ memset(meta, 0, sizeof(meta));
+ }
pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1];
/* If opening a non-empty database, check the text encoding. For the
@@ -113739,27 +128619,25 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** as sqlite3.enc.
*/
if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
- if( iDb==0 ){
-#ifndef SQLITE_OMIT_UTF16
+ if( iDb==0 && (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){
u8 encoding;
+#ifndef SQLITE_OMIT_UTF16
/* If opening the main database, set ENC(db). */
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
if( encoding==0 ) encoding = SQLITE_UTF8;
- ENC(db) = encoding;
#else
- ENC(db) = SQLITE_UTF8;
+ encoding = SQLITE_UTF8;
#endif
+ sqlite3SetTextEncoding(db, encoding);
}else{
/* If opening an attached database, the encoding much match ENC(db) */
- if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
+ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
" text encoding as main database");
rc = SQLITE_ERROR;
goto initone_error_out;
}
}
- }else{
- DbSetProperty(db, iDb, DB_Empty);
}
pDb->pSchema->enc = ENC(db);
@@ -113796,17 +128674,18 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
** indices that the user might have created.
*/
if( iDb==0 && meta[BTREE_FILE_FORMAT-1]>=4 ){
- db->flags &= ~SQLITE_LegacyFileFmt;
+ db->flags &= ~(u64)SQLITE_LegacyFileFmt;
}
/* Read the schema information out of the schema tables
*/
assert( db->init.busy );
+ initData.mxPage = sqlite3BtreeLastPage(pDb->pBt);
{
char *zSql;
- zSql = sqlite3MPrintf(db,
- "SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
- db->aDb[iDb].zDbSName, zMasterName);
+ zSql = sqlite3MPrintf(db,
+ "SELECT*FROM\"%w\".%s ORDER BY rowid",
+ db->aDb[iDb].zDbSName, zSchemaTabName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
sqlite3_xauth xAuth;
@@ -113830,13 +128709,13 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = SQLITE_NOMEM_BKPT;
sqlite3ResetAllSchemasOfConnection(db);
}
- if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
- /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
- ** the schema loaded, even if errors occurred. In this situation the
+ if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
+ /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider
+ ** the schema loaded, even if errors occurred. In this situation the
** current sqlite3_prepare() operation will fail, but the following one
** will attempt to compile the supplied statement against whatever subset
** of the schema was loaded before the error occurred. The primary
- ** purpose of this is to allow access to the sqlite_master table
+ ** purpose of this is to allow access to the sqlite_schema table
** even when its contents have been corrupted.
*/
DbSetProperty(db, iDb, DB_SchemaLoaded);
@@ -113854,9 +128733,13 @@ initone_error_out:
sqlite3BtreeLeave(pDb->pBt);
error_out:
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
- sqlite3OomFault(db);
+ if( rc ){
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
+ sqlite3OomFault(db);
+ }
+ sqlite3ResetOneSchema(db, iDb);
}
+ db->init.busy = 0;
return rc;
}
@@ -113867,47 +128750,34 @@ error_out:
** error occurs, write an error message into *pzErrMsg.
**
** After a database is initialized, the DB_SchemaLoaded bit is set
-** bit is set in the flags field of the Db structure. If the database
-** file was of zero-length, then the DB_Empty flag is also set.
+** bit is set in the flags field of the Db structure.
*/
SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
int i, rc;
- int commit_internal = !(db->flags&SQLITE_InternChanges);
-
+ int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
+
assert( sqlite3_mutex_held(db->mutex) );
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
assert( db->init.busy==0 );
- rc = SQLITE_OK;
- db->init.busy = 1;
ENC(db) = SCHEMA_ENC(db);
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
- if( DbHasProperty(db, i, DB_SchemaLoaded) || i==1 ) continue;
- rc = sqlite3InitOne(db, i, pzErrMsg);
- if( rc ){
- sqlite3ResetOneSchema(db, i);
- }
+ assert( db->nDb>0 );
+ /* Do the main schema first */
+ if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
+ rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
+ if( rc ) return rc;
}
-
- /* Once all the other databases have been initialized, load the schema
- ** for the TEMP database. This is loaded last, as the TEMP database
- ** schema may contain references to objects in other databases.
- */
-#ifndef SQLITE_OMIT_TEMPDB
- assert( db->nDb>1 );
- if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
- rc = sqlite3InitOne(db, 1, pzErrMsg);
- if( rc ){
- sqlite3ResetOneSchema(db, 1);
+ /* All other schemas after the main schema. The "temp" schema must be last */
+ for(i=db->nDb-1; i>0; i--){
+ assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
+ if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
+ rc = sqlite3InitOne(db, i, pzErrMsg, 0);
+ if( rc ) return rc;
}
}
-#endif
-
- db->init.busy = 0;
- if( rc==SQLITE_OK && commit_internal ){
+ if( commit_internal ){
sqlite3CommitInternalChanges(db);
}
-
- return rc;
+ return SQLITE_OK;
}
/*
@@ -113920,10 +128790,12 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse){
assert( sqlite3_mutex_held(db->mutex) );
if( !db->init.busy ){
rc = sqlite3Init(db, &pParse->zErrMsg);
- }
- if( rc!=SQLITE_OK ){
- pParse->rc = rc;
- pParse->nErr++;
+ if( rc!=SQLITE_OK ){
+ pParse->rc = rc;
+ pParse->nErr++;
+ }else if( db->noSharedCache ){
+ db->mDbFlags |= DBFLAG_SchemaKnownOk;
+ }
}
return rc;
}
@@ -113948,10 +128820,10 @@ static void schemaIsValid(Parse *pParse){
if( pBt==0 ) continue;
/* If there is not already a read-only (or read-write) transaction opened
- ** on the b-tree database, open one now. If a transaction is opened, it
+ ** on the b-tree database, open one now. If a transaction is opened, it
** will be closed immediately after reading the meta-value. */
if( !sqlite3BtreeIsInReadTrans(pBt) ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
+ rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
sqlite3OomFault(db);
}
@@ -113959,7 +128831,7 @@ static void schemaIsValid(Parse *pParse){
openedTransaction = 1;
}
- /* Read the schema cookie from the database. If it does not match the
+ /* Read the schema cookie from the database. If it does not match the
** value stored as part of the in-memory schema representation,
** set Parse.rc to SQLITE_SCHEMA. */
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
@@ -113984,21 +128856,23 @@ static void schemaIsValid(Parse *pParse){
** attached database is returned.
*/
SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
- int i = -1000000;
+ int i = -32768;
- /* If pSchema is NULL, then return -1000000. This happens when code in
+ /* If pSchema is NULL, then return -32768. This happens when code in
** expr.c is trying to resolve a reference to a transient table (i.e. one
- ** created by a sub-select). In this case the return value of this
+ ** created by a sub-select). In this case the return value of this
** function should never be used.
**
- ** We return -1000000 instead of the more usual -1 simply because using
- ** -1000000 as the incorrect index into db->aDb[] is much
+ ** We return -32768 instead of the more usual -1 simply because using
+ ** -32768 as the incorrect index into db->aDb[] is much
** more likely to cause a segfault than -1 (of course there are assert()
- ** statements too, but it never hurts to play the odds).
+ ** statements too, but it never hurts to play the odds) and
+ ** -32768 will still fit into a 16-bit signed integer.
*/
assert( sqlite3_mutex_held(db->mutex) );
if( pSchema ){
- for(i=0; ALWAYS(i<db->nDb); i++){
+ for(i=0; 1; i++){
+ assert( i<db->nDb );
if( db->aDb[i].pSchema==pSchema ){
break;
}
@@ -114009,19 +128883,33 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
}
/*
+** Deallocate a single AggInfo object
+*/
+static void agginfoFree(sqlite3 *db, AggInfo *p){
+ sqlite3DbFree(db, p->aCol);
+ sqlite3DbFree(db, p->aFunc);
+ sqlite3DbFree(db, p);
+}
+
+/*
** Free all memory allocations in the pParse object
*/
SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
- if( pParse ){
- sqlite3 *db = pParse->db;
- sqlite3DbFree(db, pParse->aLabel);
- sqlite3ExprListDelete(db, pParse->pConstExpr);
- if( db ){
- assert( db->lookaside.bDisable >= pParse->disableLookaside );
- db->lookaside.bDisable -= pParse->disableLookaside;
- }
- pParse->disableLookaside = 0;
+ sqlite3 *db = pParse->db;
+ AggInfo *pThis = pParse->pAggList;
+ while( pThis ){
+ AggInfo *pNext = pThis->pNext;
+ agginfoFree(db, pThis);
+ pThis = pNext;
+ }
+ sqlite3DbFree(db, pParse->aLabel);
+ sqlite3ExprListDelete(db, pParse->pConstExpr);
+ if( db ){
+ assert( db->lookaside.bDisable >= pParse->disableLookaside );
+ db->lookaside.bDisable -= pParse->disableLookaside;
+ db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
}
+ pParse->disableLookaside = 0;
}
/*
@@ -114031,7 +128919,7 @@ static int sqlite3Prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
- int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
+ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
Vdbe *pReprepare, /* VM being reprepared */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
@@ -114048,6 +128936,15 @@ static int sqlite3Prepare(
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
assert( sqlite3_mutex_held(db->mutex) );
+ /* For a long-term use prepared statement avoid the use of
+ ** lookaside memory.
+ */
+ if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
+ sParse.disableLookaside++;
+ DisableLookaside;
+ }
+ sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0;
+
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
** some other database connection is holding a write-lock, which in
@@ -114063,24 +128960,26 @@ static int sqlite3Prepare(
** This thread is currently holding mutexes on all Btrees (because
** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
** is not possible for another thread to start a new schema change
- ** while this routine is running. Hence, we do not need to hold
- ** locks on the schema, we just need to make sure nobody else is
+ ** while this routine is running. Hence, we do not need to hold
+ ** locks on the schema, we just need to make sure nobody else is
** holding them.
**
** Note that setting READ_UNCOMMITTED overrides most lock detection,
** but it does *not* override schema lock detection, so this all still
** works even if READ_UNCOMMITTED is set.
*/
- for(i=0; i<db->nDb; i++) {
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- assert( sqlite3BtreeHoldsMutex(pBt) );
- rc = sqlite3BtreeSchemaLocked(pBt);
- if( rc ){
- const char *zDb = db->aDb[i].zDbSName;
- sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
- testcase( db->flags & SQLITE_ReadUncommitted );
- goto end_prepare;
+ if( !db->noSharedCache ){
+ for(i=0; i<db->nDb; i++) {
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ assert( sqlite3BtreeHoldsMutex(pBt) );
+ rc = sqlite3BtreeSchemaLocked(pBt);
+ if( rc ){
+ const char *zDb = db->aDb[i].zDbSName;
+ sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
+ testcase( db->flags & SQLITE_ReadUncommit );
+ goto end_prepare;
+ }
}
}
}
@@ -114111,47 +129010,25 @@ static int sqlite3Prepare(
}
assert( 0==sParse.nQueryLoop );
- if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
+ if( sParse.rc==SQLITE_DONE ){
+ sParse.rc = SQLITE_OK;
+ }
if( sParse.checkSchema ){
schemaIsValid(&sParse);
}
- if( db->mallocFailed ){
- sParse.rc = SQLITE_NOMEM_BKPT;
- }
if( pzTail ){
*pzTail = sParse.zTail;
}
- rc = sParse.rc;
-
-#ifndef SQLITE_OMIT_EXPLAIN
- if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
- static const char * const azColName[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "selectid", "order", "from", "detail"
- };
- int iFirst, mx;
- if( sParse.explain==2 ){
- sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
- iFirst = 8;
- mx = 12;
- }else{
- sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
- iFirst = 0;
- mx = 8;
- }
- for(i=iFirst; i<mx; i++){
- sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME,
- azColName[i], SQLITE_STATIC);
- }
- }
-#endif
if( db->init.busy==0 ){
- Vdbe *pVdbe = sParse.pVdbe;
- sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
+ sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
}
- if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
- sqlite3VdbeFinalize(sParse.pVdbe);
+ if( db->mallocFailed ){
+ sParse.rc = SQLITE_NOMEM_BKPT;
+ }
+ rc = sParse.rc;
+ if( rc!=SQLITE_OK ){
+ if( sParse.pVdbe ) sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
@@ -114174,20 +129051,19 @@ static int sqlite3Prepare(
end_prepare:
sqlite3ParserReset(&sParse);
- rc = sqlite3ApiExit(db, rc);
- assert( (rc&db->errMask)==rc );
return rc;
}
static int sqlite3LockAndPrepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
- int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
+ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
Vdbe *pOld, /* VM being reprepared */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
int rc;
+ int cnt = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
@@ -114198,23 +129074,28 @@ static int sqlite3LockAndPrepare(
}
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
- rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
- if( rc==SQLITE_SCHEMA ){
- sqlite3_finalize(*ppStmt);
- rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
- }
+ do{
+ /* Make multiple attempts to compile the SQL, until it either succeeds
+ ** or encounters a permanent error. A schema problem after one schema
+ ** reset is considered a permanent error. */
+ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
+ assert( rc==SQLITE_OK || *ppStmt==0 );
+ }while( rc==SQLITE_ERROR_RETRY
+ || (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
sqlite3BtreeLeaveAll(db);
+ rc = sqlite3ApiExit(db, rc);
+ assert( (rc&db->errMask)==rc );
sqlite3_mutex_leave(db->mutex);
- assert( rc==SQLITE_OK || *ppStmt==0 );
return rc;
}
+
/*
** Rerun the compilation of a statement after a schema change.
**
** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
** if the statement cannot be recompiled because another connection has
-** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
+** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error
** occurs, return SQLITE_SCHEMA.
*/
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
@@ -114222,13 +129103,15 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
sqlite3_stmt *pNew;
const char *zSql;
sqlite3 *db;
+ u8 prepFlags;
assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) );
zSql = sqlite3_sql((sqlite3_stmt *)p);
assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */
db = sqlite3VdbeDb(p);
assert( sqlite3_mutex_held(db->mutex) );
- rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0);
+ prepFlags = sqlite3VdbePrepareFlags(p);
+ rc = sqlite3LockAndPrepare(db, zSql, -1, prepFlags, p, &pNew, 0);
if( rc ){
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(db);
@@ -114274,8 +129157,36 @@ SQLITE_API int sqlite3_prepare_v2(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
- rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail);
- assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
+ /* EVIDENCE-OF: R-37923-12173 The sqlite3_prepare_v2() interface works
+ ** exactly the same as sqlite3_prepare_v3() with a zero prepFlags
+ ** parameter.
+ **
+ ** Proof in that the 5th parameter to sqlite3LockAndPrepare is 0 */
+ rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0,
+ ppStmt,pzTail);
+ assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
+ return rc;
+}
+SQLITE_API int sqlite3_prepare_v3(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ int rc;
+ /* EVIDENCE-OF: R-56861-42673 sqlite3_prepare_v3() differs from
+ ** sqlite3_prepare_v2() only in having the extra prepFlags parameter,
+ ** which is a bit array consisting of zero or more of the
+ ** SQLITE_PREPARE_* flags.
+ **
+ ** Proof by comparison to the implementation of sqlite3_prepare_v2()
+ ** directly above. */
+ rc = sqlite3LockAndPrepare(db,zSql,nBytes,
+ SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
+ 0,ppStmt,pzTail);
+ assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
return rc;
}
@@ -114285,10 +129196,10 @@ SQLITE_API int sqlite3_prepare_v2(
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
*/
static int sqlite3Prepare16(
- sqlite3 *db, /* Database handle. */
+ sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
- int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
+ u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
@@ -114316,7 +129227,7 @@ static int sqlite3Prepare16(
sqlite3_mutex_enter(db->mutex);
zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
if( zSql8 ){
- rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
+ rc = sqlite3LockAndPrepare(db, zSql8, -1, prepFlags, 0, ppStmt, &zTail8);
}
if( zTail8 && pzTail ){
@@ -114328,7 +129239,7 @@ static int sqlite3Prepare16(
int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
*pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
}
- sqlite3DbFree(db, zSql8);
+ sqlite3DbFree(db, zSql8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
@@ -114343,7 +129254,7 @@ static int sqlite3Prepare16(
** occurs.
*/
SQLITE_API int sqlite3_prepare16(
- sqlite3 *db, /* Database handle. */
+ sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
@@ -114355,14 +129266,29 @@ SQLITE_API int sqlite3_prepare16(
return rc;
}
SQLITE_API int sqlite3_prepare16_v2(
- sqlite3 *db, /* Database handle. */
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-16 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ int rc;
+ rc = sqlite3Prepare16(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,ppStmt,pzTail);
+ assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
+ return rc;
+}
+SQLITE_API int sqlite3_prepare16_v3(
+ sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
int rc;
- rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
+ rc = sqlite3Prepare16(db,zSql,nBytes,
+ SQLITE_PREPARE_SAVESQL|(prepFlags&SQLITE_PREPARE_MASK),
+ ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
@@ -114388,21 +129314,6 @@ SQLITE_API int sqlite3_prepare16_v2(
/* #include "sqliteInt.h" */
/*
-** Trace output macros
-*/
-#if SELECTTRACE_ENABLED
-/***/ int sqlite3SelectTrace = 0;
-# define SELECTTRACE(K,P,S,X) \
- if(sqlite3SelectTrace&(K)) \
- sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\
- (S)->zSelName,(S)),\
- sqlite3DebugPrintf X
-#else
-# define SELECTTRACE(K,P,S,X)
-#endif
-
-
-/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
@@ -114418,6 +129329,20 @@ struct DistinctCtx {
/*
** An instance of the following object is used to record information about
** the ORDER BY (or GROUP BY) clause of query is being coded.
+**
+** The aDefer[] array is used by the sorter-references optimization. For
+** example, assuming there is no index that can be used for the ORDER BY,
+** for the query:
+**
+** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10;
+**
+** it may be more efficient to add just the "a" values to the sorter, and
+** retrieve the associated "bigblob" values directly from table t1 as the
+** 10 smallest "a" values are extracted from the sorter.
+**
+** When the sorter-reference optimization is used, there is one entry in the
+** aDefer[] array for each database table that may be read as values are
+** extracted from the sorter.
*/
typedef struct SortCtx SortCtx;
struct SortCtx {
@@ -114428,14 +129353,26 @@ struct SortCtx {
int labelBkOut; /* Start label for the block-output subroutine */
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
int labelDone; /* Jump here when done, ex: LIMIT reached */
+ int labelOBLopt; /* Jump here when sorter is full */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
- u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ u8 nDefer; /* Number of valid entries in aDefer[] */
+ struct DeferredCsr {
+ Table *pTab; /* Table definition */
+ int iCsr; /* Cursor number for table */
+ int nKey; /* Number of PK columns for table pTab (>=1) */
+ } aDefer[4];
+#endif
+ struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
/*
** Delete all the content of a Select structure. Deallocate the structure
-** itself only if bFree is true.
+** itself depending on the value of bFree
+**
+** If bFree==1, call sqlite3DbFree() on the p object.
+** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
while( p ){
@@ -114447,9 +129384,13 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3ExprDelete(db, p->pHaving);
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
- sqlite3ExprDelete(db, p->pOffset);
- if( p->pWith ) sqlite3WithDelete(db, p->pWith);
- if( bFree ) sqlite3DbFree(db, p);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
+ sqlite3WindowListDelete(db, p->pWinDefn);
+ }
+#endif
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
+ if( bFree ) sqlite3DbFreeNN(db, p);
p = pPrior;
bFree = 1;
}
@@ -114461,6 +129402,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
pDest->eDest = (u8)eDest;
pDest->iSDParm = iParm;
+ pDest->iSDParm2 = 0;
pDest->zAffSdst = 0;
pDest->iSdst = 0;
pDest->nSdst = 0;
@@ -114480,32 +129422,29 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, /* the ORDER BY clause */
u32 selFlags, /* Flag parameters, such as SF_Distinct */
- Expr *pLimit, /* LIMIT value. NULL means not used */
- Expr *pOffset /* OFFSET value. NULL means no offset */
+ Expr *pLimit /* LIMIT value. NULL means not used */
){
- Select *pNew;
+ Select *pNew, *pAllocated;
Select standin;
- sqlite3 *db = pParse->db;
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
+ pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
if( pNew==0 ){
- assert( db->mallocFailed );
+ assert( pParse->db->mallocFailed );
pNew = &standin;
}
if( pEList==0 ){
- pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
+ pEList = sqlite3ExprListAppend(pParse, 0,
+ sqlite3Expr(pParse->db,TK_ASTERISK,0));
}
pNew->pEList = pEList;
pNew->op = TK_SELECT;
pNew->selFlags = selFlags;
pNew->iLimit = 0;
pNew->iOffset = 0;
-#if SELECTTRACE_ENABLED
- pNew->zSelName[0] = 0;
-#endif
+ pNew->selId = ++pParse->nSelect;
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = 0;
- if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
+ if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
@@ -114514,36 +129453,26 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
pNew->pPrior = 0;
pNew->pNext = 0;
pNew->pLimit = pLimit;
- pNew->pOffset = pOffset;
pNew->pWith = 0;
- assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
- if( db->mallocFailed ) {
- clearSelect(db, pNew, pNew!=&standin);
- pNew = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ pNew->pWin = 0;
+ pNew->pWinDefn = 0;
+#endif
+ if( pParse->db->mallocFailed ) {
+ clearSelect(pParse->db, pNew, pNew!=&standin);
+ pAllocated = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
}
- assert( pNew!=&standin );
- return pNew;
-}
-
-#if SELECTTRACE_ENABLED
-/*
-** Set the name of a Select object
-*/
-SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
- if( p && zName ){
- sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
- }
+ return pAllocated;
}
-#endif
/*
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
- if( p ) clearSelect(db, p, 1);
+ if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
/*
@@ -114597,7 +129526,7 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
for(i=0; i<3 && apAll[i]; i++){
p = apAll[i];
for(j=0; j<ArraySize(aKeyword); j++){
- if( p->n==aKeyword[j].nChar
+ if( p->n==aKeyword[j].nChar
&& sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){
jointype |= aKeyword[j].code;
break;
@@ -114619,9 +129548,9 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
sqlite3ErrorMsg(pParse, "unknown or unsupported join type: "
"%T %T%s%T", pA, pB, zSp, pC);
jointype = JT_INNER;
- }else if( (jointype & JT_OUTER)!=0
+ }else if( (jointype & JT_OUTER)!=0
&& (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"RIGHT and FULL OUTER JOINs are not currently supported");
jointype = JT_INNER;
}
@@ -114634,15 +129563,17 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
*/
static int columnIndex(Table *pTab, const char *zCol){
int i;
- for(i=0; i<pTab->nCol; i++){
- if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
+ u8 h = sqlite3StrIHash(zCol);
+ Column *pCol;
+ for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
+ if( pCol->hName==h && sqlite3StrICmp(pCol->zName, zCol)==0 ) return i;
}
return -1;
}
/*
** Search the first N tables in pSrc, from left to right, looking for a
-** table that has a column named zCol.
+** table that has a column named zCol.
**
** When found, set *piTab and *piCol to the table index and column index
** of the matching column and return TRUE.
@@ -114654,7 +129585,8 @@ static int tableAndColumnIndex(
int N, /* Number of tables in pSrc->a[] to search */
const char *zCol, /* Name of the column we are looking for */
int *piTab, /* Write index of pSrc->a[] here */
- int *piCol /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
+ int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
+ int bIgnoreHidden /* True to ignore hidden columns */
){
int i; /* For looping over tables in pSrc */
int iCol; /* Index of column matching zCol */
@@ -114662,7 +129594,9 @@ static int tableAndColumnIndex(
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
for(i=0; i<N; i++){
iCol = columnIndex(pSrc->a[i].pTab, zCol);
- if( iCol>=0 ){
+ if( iCol>=0
+ && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
+ ){
if( piTab ){
*piTab = i;
*piCol = iCol;
@@ -114680,7 +129614,7 @@ static int tableAndColumnIndex(
**
** (tab1.col1 = tab2.col2)
**
-** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the
+** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the
** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is
** column iColRight of tab2.
*/
@@ -114707,14 +129641,14 @@ static void addWhereTerm(
pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
- pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
+ pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
if( pEq && isOuterJoin ){
ExprSetProperty(pEq, EP_FromJoin);
assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
ExprSetVVAProperty(pEq, EP_NoReduce);
pEq->iRightJoinTable = (i16)pE2->iTable;
}
- *ppWhere = sqlite3ExprAnd(db, *ppWhere, pEq);
+ *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq);
}
/*
@@ -114743,7 +129677,7 @@ static void addWhereTerm(
** after the t1 loop and rows with t1.x!=5 will never appear in
** the output, which is incorrect.
*/
-static void setJoinExpr(Expr *p, int iTable){
+SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -114752,12 +129686,35 @@ static void setJoinExpr(Expr *p, int iTable){
if( p->op==TK_FUNCTION && p->x.pList ){
int i;
for(i=0; i<p->x.pList->nExpr; i++){
- setJoinExpr(p->x.pList->a[i].pExpr, iTable);
+ sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable);
+ }
+ }
+ sqlite3SetJoinExpr(p->pLeft, iTable);
+ p = p->pRight;
+ }
+}
+
+/* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every
+** term that is marked with EP_FromJoin and iRightJoinTable==iTable into
+** an ordinary term that omits the EP_FromJoin mark.
+**
+** This happens when a LEFT JOIN is simplified into an ordinary JOIN.
+*/
+static void unsetJoinExpr(Expr *p, int iTable){
+ while( p ){
+ if( ExprHasProperty(p, EP_FromJoin)
+ && (iTable<0 || p->iRightJoinTable==iTable) ){
+ ExprClearProperty(p, EP_FromJoin);
+ }
+ if( p->op==TK_FUNCTION && p->x.pList ){
+ int i;
+ for(i=0; i<p->x.pList->nExpr; i++){
+ unsetJoinExpr(p->x.pList->a[i].pExpr, iTable);
}
}
- setJoinExpr(p->pLeft, iTable);
+ unsetJoinExpr(p->pLeft, iTable);
p = p->pRight;
- }
+ }
}
/*
@@ -114784,11 +129741,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
pLeft = &pSrc->a[0];
pRight = &pLeft[1];
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
- Table *pLeftTab = pLeft->pTab;
Table *pRightTab = pRight->pTab;
int isOuter;
- if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
+ if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
/* When the NATURAL keyword is present, add WHERE clause terms for
@@ -114805,10 +129761,11 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
int iLeft; /* Matching left table */
int iLeftCol; /* Matching column in the left table */
+ if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue;
zName = pRightTab->aCol[j].zName;
- if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){
+ if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){
addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
- isOuter, &p->pWhere);
+ isOuter, &p->pWhere);
}
}
}
@@ -114825,13 +129782,13 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** an AND operator.
*/
if( pRight->pOn ){
- if( isOuter ) setJoinExpr(pRight->pOn, pRight->iCursor);
- p->pWhere = sqlite3ExprAnd(pParse->db, p->pWhere, pRight->pOn);
+ if( isOuter ) sqlite3SetJoinExpr(pRight->pOn, pRight->iCursor);
+ p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn);
pRight->pOn = 0;
}
/* Create extra terms on the WHERE clause for each column named
- ** in the USING clause. Example: If the two tables to be joined are
+ ** in the USING clause. Example: If the two tables to be joined are
** A and B and the USING clause names X, Y, and Z, then add this
** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
** Report an error if any column mentioned in the USING clause is
@@ -114848,7 +129805,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
zName = pList->a[j].zName;
iRightCol = columnIndex(pRightTab, zName);
if( iRightCol<0
- || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol)
+ || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0)
){
sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
"not present in both tables", zName);
@@ -114862,13 +129819,61 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
return 0;
}
-/* Forward reference */
-static KeyInfo *keyInfoFromExprList(
- Parse *pParse, /* Parsing context */
- ExprList *pList, /* Form the KeyInfo object from this ExprList */
- int iStart, /* Begin with this column of pList */
- int nExtra /* Add this many extra columns to the end */
-);
+/*
+** An instance of this object holds information (beyond pParse and pSelect)
+** needed to load the next result row that is to be added to the sorter.
+*/
+typedef struct RowLoadInfo RowLoadInfo;
+struct RowLoadInfo {
+ int regResult; /* Store results in array of registers here */
+ u8 ecelFlags; /* Flag argument to ExprCodeExprList() */
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ ExprList *pExtra; /* Extra columns needed by sorter refs */
+ int regExtraResult; /* Where to load the extra columns */
+#endif
+};
+
+/*
+** This routine does the work of loading query data into an array of
+** registers so that it can be added to the sorter.
+*/
+static void innerLoopLoadRow(
+ Parse *pParse, /* Statement under construction */
+ Select *pSelect, /* The query being coded */
+ RowLoadInfo *pInfo /* Info needed to complete the row load */
+){
+ sqlite3ExprCodeExprList(pParse, pSelect->pEList, pInfo->regResult,
+ 0, pInfo->ecelFlags);
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( pInfo->pExtra ){
+ sqlite3ExprCodeExprList(pParse, pInfo->pExtra, pInfo->regExtraResult, 0, 0);
+ sqlite3ExprListDelete(pParse->db, pInfo->pExtra);
+ }
+#endif
+}
+
+/*
+** Code the OP_MakeRecord instruction that generates the entry to be
+** added into the sorter.
+**
+** Return the register in which the result is stored.
+*/
+static int makeSorterRecord(
+ Parse *pParse,
+ SortCtx *pSort,
+ Select *pSelect,
+ int regBase,
+ int nBase
+){
+ int nOBSat = pSort->nOBSat;
+ Vdbe *v = pParse->pVdbe;
+ int regOut = ++pParse->nMem;
+ if( pSort->pDeferredRowLoad ){
+ innerLoopLoadRow(pParse, pSelect, pSort->pDeferredRowLoad);
+ }
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regOut);
+ return regOut;
+}
/*
** Generate code that will push the record in registers regData
@@ -114880,7 +129885,7 @@ static void pushOntoSorter(
Select *pSelect, /* The whole SELECT statement */
int regData, /* First register holding data to be sorted */
int regOrigData, /* First register holding data before packing */
- int nData, /* Number of elements in the data array */
+ int nData, /* Number of elements in the regData data array */
int nPrefixReg /* No. of reg prior to regData available for use */
){
Vdbe *v = pParse->pVdbe; /* Stmt under construction */
@@ -114888,32 +129893,47 @@ static void pushOntoSorter(
int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */
int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
int regBase; /* Regs for sorter record */
- int regRecord = ++pParse->nMem; /* Assembled sorter record */
+ int regRecord = 0; /* Assembled sorter record */
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
int op; /* Opcode to add sorter record to sorter */
int iLimit; /* LIMIT counter */
+ int iSkip = 0; /* End of the sorter insert loop */
assert( bSeq==0 || bSeq==1 );
- assert( nData==1 || regData==regOrigData );
+
+ /* Three cases:
+ ** (1) The data to be sorted has already been packed into a Record
+ ** by a prior OP_MakeRecord. In this case nData==1 and regData
+ ** will be completely unrelated to regOrigData.
+ ** (2) All output columns are included in the sort record. In that
+ ** case regData==regOrigData.
+ ** (3) Some output columns are omitted from the sort record due to
+ ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the
+ ** SQLITE_ECEL_OMITREF optimization, or due to the
+ ** SortCtx.pDeferredRowLoad optimiation. In any of these cases
+ ** regOrigData is 0 to prevent this routine from trying to copy
+ ** values that might not yet exist.
+ */
+ assert( nData==1 || regData==regOrigData || regOrigData==0 );
+
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
- regBase = regData - nExpr - bSeq;
+ regBase = regData - nPrefixReg;
}else{
regBase = pParse->nMem + 1;
pParse->nMem += nBase;
}
assert( pSelect->iOffset==0 || pSelect->iLimit!=0 );
iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
- pSort->labelDone = sqlite3VdbeMakeLabel(v);
+ pSort->labelDone = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
- SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
+ SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0));
if( bSeq ){
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
}
- if( nPrefixReg==0 ){
+ if( nPrefixReg==0 && nData>0 ){
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
}
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
if( nOBSat>0 ){
int regPrevKey; /* The first nOBSat columns of the previous row */
int addrFirst; /* Address of the OP_IfNot opcode */
@@ -114922,11 +129942,12 @@ static void pushOntoSorter(
int nKey; /* Number of sorting key columns, including OP_Sequence */
KeyInfo *pKI; /* Original KeyInfo on the sorter table */
+ regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase);
regPrevKey = pParse->nMem+1;
pParse->nMem += pSort->nOBSat;
nKey = nExpr - pSort->nOBSat + bSeq;
if( bSeq ){
- addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
+ addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
}else{
addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor);
}
@@ -114936,14 +129957,15 @@ static void pushOntoSorter(
if( pParse->db->mallocFailed ) return;
pOp->p2 = nKey + nData;
pKI = pOp->p4.pKeyInfo;
- memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
+ memset(pKI->aSortFlags, 0, pKI->nKeyField); /* Makes OP_Jump testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
- testcase( pKI->nXField>2 );
- pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
- pKI->nXField-1);
+ testcase( pKI->nAllField > pKI->nKeyField+2 );
+ pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
+ pKI->nAllField-pKI->nKeyField-1);
+ pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
- pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
+ pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse);
pSort->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
@@ -114955,39 +129977,44 @@ static void pushOntoSorter(
sqlite3ExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
sqlite3VdbeJumpHere(v, addrJmp);
}
+ if( iLimit ){
+ /* At this point the values for the new sorter entry are stored
+ ** in an array of registers. They need to be composed into a record
+ ** and inserted into the sorter if either (a) there are currently
+ ** less than LIMIT+OFFSET items or (b) the new record is smaller than
+ ** the largest record currently in the sorter. If (b) is true and there
+ ** are already LIMIT+OFFSET items in the sorter, delete the largest
+ ** entry before inserting the new one. This way there are never more
+ ** than LIMIT+OFFSET items in the sorter.
+ **
+ ** If the new record does not need to be inserted into the sorter,
+ ** jump to the next iteration of the loop. If the pSort->labelOBLopt
+ ** value is not zero, then it is a label of where to jump. Otherwise,
+ ** just bypass the row insert logic. See the header comment on the
+ ** sqlite3WhereOrderByLimitOptLabel() function for additional info.
+ */
+ int iCsr = pSort->iECursor;
+ sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Last, iCsr, 0);
+ iSkip = sqlite3VdbeAddOp4Int(v, OP_IdxLE,
+ iCsr, 0, regBase+nOBSat, nExpr-nOBSat);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp1(v, OP_Delete, iCsr);
+ }
+ if( regRecord==0 ){
+ regRecord = makeSorterRecord(pParse, pSort, pSelect, regBase, nBase);
+ }
if( pSort->sortFlags & SORTFLAG_UseSorter ){
op = OP_SorterInsert;
}else{
op = OP_IdxInsert;
}
- sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
- if( iLimit ){
- int addr;
- int r1 = 0;
- /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit
- ** register is initialized with value of LIMIT+OFFSET.) After the sorter
- ** fills up, delete the least entry in the sorter after each insert.
- ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
- addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
- sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
- if( pSort->bOrderedInnerLoop ){
- r1 = ++pParse->nMem;
- sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
- VdbeComment((v, "seq"));
- }
- sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
- if( pSort->bOrderedInnerLoop ){
- /* If the inner loop is driven by an index such that values from
- ** the same iteration of the inner loop are in sorted order, then
- ** immediately jump to the next iteration of an inner loop if the
- ** entry from the current iteration does not fit into the top
- ** LIMIT+OFFSET entries of the sorter. */
- int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
- sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
- sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
- VdbeCoverage(v);
- }
- sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
+ regBase+nOBSat, nBase-nOBSat);
+ if( iSkip ){
+ sqlite3VdbeChangeP2(v, iSkip,
+ pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v));
}
}
@@ -115028,24 +130055,105 @@ static void codeDistinct(
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
+ sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3ReleaseTempReg(pParse, r1);
}
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+/*
+** This function is called as part of inner-loop generation for a SELECT
+** statement with an ORDER BY that is not optimized by an index. It
+** determines the expressions, if any, that the sorter-reference
+** optimization should be used for. The sorter-reference optimization
+** is used for SELECT queries like:
+**
+** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10
+**
+** If the optimization is used for expression "bigblob", then instead of
+** storing values read from that column in the sorter records, the PK of
+** the row from table t1 is stored instead. Then, as records are extracted from
+** the sorter to return to the user, the required value of bigblob is
+** retrieved directly from table t1. If the values are very large, this
+** can be more efficient than storing them directly in the sorter records.
+**
+** The ExprList_item.bSorterRef flag is set for each expression in pEList
+** for which the sorter-reference optimization should be enabled.
+** Additionally, the pSort->aDefer[] array is populated with entries
+** for all cursors required to evaluate all selected expressions. Finally.
+** output variable (*ppExtra) is set to an expression list containing
+** expressions for all extra PK values that should be stored in the
+** sorter records.
+*/
+static void selectExprDefer(
+ Parse *pParse, /* Leave any error here */
+ SortCtx *pSort, /* Sorter context */
+ ExprList *pEList, /* Expressions destined for sorter */
+ ExprList **ppExtra /* Expressions to append to sorter record */
+){
+ int i;
+ int nDefer = 0;
+ ExprList *pExtra = 0;
+ for(i=0; i<pEList->nExpr; i++){
+ struct ExprList_item *pItem = &pEList->a[i];
+ if( pItem->u.x.iOrderByCol==0 ){
+ Expr *pExpr = pItem->pExpr;
+ Table *pTab = pExpr->y.pTab;
+ if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab)
+ && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)
+ ){
+ int j;
+ for(j=0; j<nDefer; j++){
+ if( pSort->aDefer[j].iCsr==pExpr->iTable ) break;
+ }
+ if( j==nDefer ){
+ if( nDefer==ArraySize(pSort->aDefer) ){
+ continue;
+ }else{
+ int nKey = 1;
+ int k;
+ Index *pPk = 0;
+ if( !HasRowid(pTab) ){
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ nKey = pPk->nKeyCol;
+ }
+ for(k=0; k<nKey; k++){
+ Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0);
+ if( pNew ){
+ pNew->iTable = pExpr->iTable;
+ pNew->y.pTab = pExpr->y.pTab;
+ pNew->iColumn = pPk ? pPk->aiColumn[k] : -1;
+ pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew);
+ }
+ }
+ pSort->aDefer[nDefer].pTab = pExpr->y.pTab;
+ pSort->aDefer[nDefer].iCsr = pExpr->iTable;
+ pSort->aDefer[nDefer].nKey = nKey;
+ nDefer++;
+ }
+ }
+ pItem->bSorterRef = 1;
+ }
+ }
+ }
+ pSort->nDefer = (u8)nDefer;
+ *ppExtra = pExtra;
+}
+#endif
+
/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
**
-** If srcTab is negative, then the pEList expressions
+** If srcTab is negative, then the p->pEList expressions
** are evaluated in order to get the data for this row. If srcTab is
-** zero or more, then data is pulled from srcTab and pEList is used only
-** to get number columns and the datatype for each column.
+** zero or more, then data is pulled from srcTab and p->pEList is used only
+** to get the number of columns and the collation sequence for each column.
*/
static void selectInnerLoop(
Parse *pParse, /* The parser context */
Select *p, /* The complete select statement being coded */
- ExprList *pEList, /* List of values being extracted */
- int srcTab, /* Pull data from this table */
+ int srcTab, /* Pull data from this table if non-negative */
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
@@ -115054,15 +130162,23 @@ static void selectInnerLoop(
){
Vdbe *v = pParse->pVdbe;
int i;
- int hasDistinct; /* True if the DISTINCT keyword is present */
- int regResult; /* Start of memory holding result set */
+ int hasDistinct; /* True if the DISTINCT keyword is present */
int eDest = pDest->eDest; /* How to dispose of results */
int iParm = pDest->iSDParm; /* First argument to disposal method */
int nResultCol; /* Number of result columns */
int nPrefixReg = 0; /* Number of extra registers before regResult */
+ RowLoadInfo sRowLoadInfo; /* Info for deferred row loading */
+
+ /* Usually, regResult is the first cell in an array of memory cells
+ ** containing the current result row. In this case regOrig is set to the
+ ** same value. However, if the results are being sent to the sorter, the
+ ** values for any expressions that are also part of the sort-key are omitted
+ ** from this array. In this case regOrig is set to zero. */
+ int regResult; /* Start of memory holding current results */
+ int regOrig; /* Start of memory holding full result (or 0) */
assert( v );
- assert( pEList!=0 );
+ assert( p->pEList!=0 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
if( pSort==0 && !hasDistinct ){
@@ -115072,7 +130188,7 @@ static void selectInnerLoop(
/* Pull the requested columns.
*/
- nResultCol = pEList->nExpr;
+ nResultCol = p->pEList->nExpr;
if( pDest->iSdst==0 ){
if( pSort ){
@@ -115091,23 +130207,97 @@ static void selectInnerLoop(
pParse->nMem += nResultCol;
}
pDest->nSdst = nResultCol;
- regResult = pDest->iSdst;
+ regOrig = regResult = pDest->iSdst;
if( srcTab>=0 ){
for(i=0; i<nResultCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
- VdbeComment((v, "%s", pEList->a[i].zName));
+ VdbeComment((v, "%s", p->pEList->a[i].zEName));
}
}else if( eDest!=SRT_Exists ){
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ ExprList *pExtra = 0;
+#endif
/* If the destination is an EXISTS(...) expression, the actual
** values returned by the SELECT are not required.
*/
- u8 ecelFlags;
+ u8 ecelFlags; /* "ecel" is an abbreviation of "ExprCodeExprList" */
+ ExprList *pEList;
if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){
ecelFlags = SQLITE_ECEL_DUP;
}else{
ecelFlags = 0;
}
- sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
+ if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
+ /* For each expression in p->pEList that is a copy of an expression in
+ ** the ORDER BY clause (pSort->pOrderBy), set the associated
+ ** iOrderByCol value to one more than the index of the ORDER BY
+ ** expression within the sort-key that pushOntoSorter() will generate.
+ ** This allows the p->pEList field to be omitted from the sorted record,
+ ** saving space and CPU cycles. */
+ ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
+
+ for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
+ int j;
+ if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
+ p->pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
+ }
+ }
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ selectExprDefer(pParse, pSort, p->pEList, &pExtra);
+ if( pExtra && pParse->db->mallocFailed==0 ){
+ /* If there are any extra PK columns to add to the sorter records,
+ ** allocate extra memory cells and adjust the OpenEphemeral
+ ** instruction to account for the larger records. This is only
+ ** required if there are one or more WITHOUT ROWID tables with
+ ** composite primary keys in the SortCtx.aDefer[] array. */
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
+ pOp->p2 += (pExtra->nExpr - pSort->nDefer);
+ pOp->p4.pKeyInfo->nAllField += (pExtra->nExpr - pSort->nDefer);
+ pParse->nMem += pExtra->nExpr;
+ }
+#endif
+
+ /* Adjust nResultCol to account for columns that are omitted
+ ** from the sorter by the optimizations in this branch */
+ pEList = p->pEList;
+ for(i=0; i<pEList->nExpr; i++){
+ if( pEList->a[i].u.x.iOrderByCol>0
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ || pEList->a[i].bSorterRef
+#endif
+ ){
+ nResultCol--;
+ regOrig = 0;
+ }
+ }
+
+ testcase( regOrig );
+ testcase( eDest==SRT_Set );
+ testcase( eDest==SRT_Mem );
+ testcase( eDest==SRT_Coroutine );
+ testcase( eDest==SRT_Output );
+ assert( eDest==SRT_Set || eDest==SRT_Mem
+ || eDest==SRT_Coroutine || eDest==SRT_Output
+ || eDest==SRT_Upfrom );
+ }
+ sRowLoadInfo.regResult = regResult;
+ sRowLoadInfo.ecelFlags = ecelFlags;
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ sRowLoadInfo.pExtra = pExtra;
+ sRowLoadInfo.regExtraResult = regResult + nResultCol;
+ if( pExtra ) nResultCol += pExtra->nExpr;
+#endif
+ if( p->iLimit
+ && (ecelFlags & SQLITE_ECEL_OMITREF)!=0
+ && nPrefixReg>0
+ ){
+ assert( pSort!=0 );
+ assert( hasDistinct==0 );
+ pSort->pDeferredRowLoad = &sRowLoadInfo;
+ regOrig = 0;
+ }else{
+ innerLoopLoadRow(pParse, p, &sRowLoadInfo);
+ }
}
/* If the DISTINCT keyword was present on the SELECT statement
@@ -115136,10 +130326,11 @@ static void selectInnerLoop(
pOp->opcode = OP_Null;
pOp->p1 = 1;
pOp->p2 = regPrev;
+ pOp = 0; /* Ensure pOp is not used after sqlite3VdbeAddOp() */
iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
for(i=0; i<nResultCol; i++){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
if( i<nResultCol-1 ){
sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
VdbeCoverage(v);
@@ -115181,7 +130372,7 @@ static void selectInnerLoop(
int r1;
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -115218,12 +130409,13 @@ static void selectInnerLoop(
int addr = sqlite3VdbeCurrentAddr(v) + 4;
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol);
assert( pSort==0 );
}
#endif
if( pSort ){
- pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg);
+ assert( regResult==regOrig );
+ pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, regOrig, 1, nPrefixReg);
}else{
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
@@ -115235,6 +130427,30 @@ static void selectInnerLoop(
break;
}
+ case SRT_Upfrom: {
+ if( pSort ){
+ pushOntoSorter(
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
+ }else{
+ int i2 = pDest->iSDParm2;
+ int r1 = sqlite3GetTempReg(pParse);
+
+ /* If the UPDATE FROM join is an aggregate that matches no rows, it
+ ** might still be trying to return one row, because that is what
+ ** aggregates do. Don't record that empty row in the output table. */
+ sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v);
+
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,
+ regResult+(i2<0), nResultCol-(i2<0), r1);
+ if( i2<0 ){
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
+ }else{
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
+ }
+ }
+ break;
+ }
+
#ifndef SQLITE_OMIT_SUBQUERY
/* If we are creating a set for an "expr IN (SELECT ...)" construct,
** then there should be a single item on the stack. Write this
@@ -115247,19 +130463,19 @@ static void selectInnerLoop(
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
pushOntoSorter(
- pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
r1, pDest->zAffSdst, nResultCol);
- sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
sqlite3ReleaseTempReg(pParse, r1);
}
break;
}
+
/* If any row exist in the result set, record that fact and abort.
*/
case SRT_Exists: {
@@ -115269,15 +130485,16 @@ static void selectInnerLoop(
}
/* If this is a scalar select that is part of an expression, then
- ** store the results in the appropriate memory cell or array of
+ ** store the results in the appropriate memory cell or array of
** memory cells and break out of the scan loop.
*/
case SRT_Mem: {
- assert( nResultCol==pDest->nSdst );
if( pSort ){
+ assert( nResultCol<=pDest->nSdst );
pushOntoSorter(
- pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
}else{
+ assert( nResultCol==pDest->nSdst );
assert( regResult==iParm );
/* The LIMIT clause will jump out of the loop for us */
}
@@ -115290,13 +130507,12 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
- pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
+ pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol,
nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}else{
sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
- sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
}
break;
}
@@ -115324,7 +130540,7 @@ static void selectInnerLoop(
/* If the destination is DistQueue, then cursor (iParm+1) is open
** on a second ephemeral index that holds all values every previously
** added to the queue. */
- addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0,
+ addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0,
regResult, nResultCol);
VdbeCoverage(v);
}
@@ -115340,7 +130556,7 @@ static void selectInnerLoop(
}
sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempRange(pParse, r2, nKey+2);
@@ -115377,12 +130593,12 @@ static void selectInnerLoop(
** X extra columns.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
- int nExtra = (N+X)*(sizeof(CollSeq*)+1);
+ int nExtra = (N+X)*(sizeof(CollSeq*)+1) - sizeof(CollSeq*);
KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
- p->aSortOrder = (u8*)&p->aColl[N+X];
- p->nField = (u16)N;
- p->nXField = (u16)X;
+ p->aSortFlags = (u8*)&p->aColl[N+X];
+ p->nKeyField = (u16)N;
+ p->nAllField = (u16)(N+X);
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
@@ -115400,7 +130616,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
assert( p->nRef>0 );
p->nRef--;
- if( p->nRef==0 ) sqlite3DbFree(p->db, p);
+ if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
}
}
@@ -115439,7 +130655,7 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
** function is responsible for seeing that this structure is eventually
** freed.
*/
-static KeyInfo *keyInfoFromExprList(
+SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* Form the KeyInfo object from this ExprList */
int iStart, /* Begin with this column of pList */
@@ -115456,11 +130672,8 @@ static KeyInfo *keyInfoFromExprList(
if( pInfo ){
assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
- CollSeq *pColl;
- pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- pInfo->aColl[i-iStart] = pColl;
- pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
+ pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
+ pInfo->aSortFlags[i-iStart] = pItem->sortFlags;
}
}
return pInfo;
@@ -115492,11 +130705,7 @@ static const char *selectOpName(int id){
** is determined by the zUsage argument.
*/
static void explainTempTable(Parse *pParse, const char *zUsage){
- if( pParse->explain==2 ){
- Vdbe *v = pParse->pVdbe;
- char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage);
- sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
- }
+ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s", zUsage));
}
/*
@@ -115514,42 +130723,6 @@ static void explainTempTable(Parse *pParse, const char *zUsage){
# define explainSetInteger(y,z)
#endif
-#if !defined(SQLITE_OMIT_EXPLAIN) && !defined(SQLITE_OMIT_COMPOUND_SELECT)
-/*
-** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
-** is a no-op. Otherwise, it adds a single row of output to the EQP result,
-** where the caption is of one of the two forms:
-**
-** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)"
-** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)"
-**
-** where iSub1 and iSub2 are the integers passed as the corresponding
-** function parameters, and op is the text representation of the parameter
-** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT,
-** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is
-** false, or the second form if it is true.
-*/
-static void explainComposite(
- Parse *pParse, /* Parse context */
- int op, /* One of TK_UNION, TK_EXCEPT etc. */
- int iSub1, /* Subquery id 1 */
- int iSub2, /* Subquery id 2 */
- int bUseTmp /* True if a temp table was used */
-){
- assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL );
- if( pParse->explain==2 ){
- Vdbe *v = pParse->pVdbe;
- char *zMsg = sqlite3MPrintf(
- pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2,
- bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op)
- );
- sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
- }
-}
-#else
-/* No-op versions of the explainXXX() functions and macros. */
-# define explainComposite(v,w,x,y,z)
-#endif
/*
** If the inner loop was generated using a non-null pOrderBy argument,
@@ -115566,8 +130739,8 @@ static void generateSortTail(
){
Vdbe *v = pParse->pVdbe; /* The prepared statement */
int addrBreak = pSort->labelDone; /* Jump here to exit loop */
- int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
- int addr;
+ int addrContinue = sqlite3VdbeMakeLabel(pParse);/* Jump here for next cycle */
+ int addr; /* Top of output loop. Jump for Next. */
int addrOnce = 0;
int iTab;
ExprList *pOrderBy = pSort->pOrderBy;
@@ -115575,14 +130748,13 @@ static void generateSortTail(
int iParm = pDest->iSDParm;
int regRow;
int regRowid;
- int nKey;
+ int iCol;
+ int nKey; /* Number of key columns in sorter record */
int iSortTab; /* Sorter cursor to read from */
- int nSortData; /* Trailing values to read from sorter */
int i;
int bSeq; /* True if sorter record includes seq. no. */
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ int nRefKey = 0;
struct ExprList_item *aOutEx = p->pEList->a;
-#endif
assert( addrBreak<0 );
if( pSort->labelBkOut ){
@@ -115590,15 +130762,29 @@ static void generateSortTail(
sqlite3VdbeGoto(v, addrBreak);
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
}
+
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ /* Open any cursors needed for sorter-reference expressions */
+ for(i=0; i<pSort->nDefer; i++){
+ Table *pTab = pSort->aDefer[i].pTab;
+ int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
+ sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead);
+ nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey);
+ }
+#endif
+
iTab = pSort->iECursor;
if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
regRowid = 0;
regRow = pDest->iSdst;
- nSortData = nColumn;
}else{
regRowid = sqlite3GetTempReg(pParse);
- regRow = sqlite3GetTempRange(pParse, nColumn);
- nSortData = nColumn;
+ if( eDest==SRT_EphemTab || eDest==SRT_Table ){
+ regRow = sqlite3GetTempReg(pParse);
+ nColumn = 0;
+ }else{
+ regRow = sqlite3GetTempRange(pParse, nColumn);
+ }
}
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
@@ -115607,7 +130793,8 @@ static void generateSortTail(
if( pSort->labelBkOut ){
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
- sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
+ sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut,
+ nKey+1+nColumn+nRefKey);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
@@ -115620,12 +130807,64 @@ static void generateSortTail(
iSortTab = iTab;
bSeq = 1;
}
- for(i=0; i<nSortData; i++){
- sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
- VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
+ for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( aOutEx[i].bSorterRef ) continue;
+#endif
+ if( aOutEx[i].u.x.iOrderByCol==0 ) iCol++;
+ }
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( pSort->nDefer ){
+ int iKey = iCol+1;
+ int regKey = sqlite3GetTempRange(pParse, nRefKey);
+
+ for(i=0; i<pSort->nDefer; i++){
+ int iCsr = pSort->aDefer[i].iCsr;
+ Table *pTab = pSort->aDefer[i].pTab;
+ int nKey = pSort->aDefer[i].nKey;
+
+ sqlite3VdbeAddOp1(v, OP_NullRow, iCsr);
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iKey++, regKey);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iCsr,
+ sqlite3VdbeCurrentAddr(v)+1, regKey);
+ }else{
+ int k;
+ int iJmp;
+ assert( sqlite3PrimaryKeyIndex(pTab)->nKeyCol==nKey );
+ for(k=0; k<nKey; k++){
+ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iKey++, regKey+k);
+ }
+ iJmp = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp4Int(v, OP_SeekGE, iCsr, iJmp+2, regKey, nKey);
+ sqlite3VdbeAddOp4Int(v, OP_IdxLE, iCsr, iJmp+3, regKey, nKey);
+ sqlite3VdbeAddOp1(v, OP_NullRow, iCsr);
+ }
+ }
+ sqlite3ReleaseTempRange(pParse, regKey, nRefKey);
+ }
+#endif
+ for(i=nColumn-1; i>=0; i--){
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ if( aOutEx[i].bSorterRef ){
+ sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i);
+ }else
+#endif
+ {
+ int iRead;
+ if( aOutEx[i].u.x.iOrderByCol ){
+ iRead = aOutEx[i].u.x.iOrderByCol-1;
+ }else{
+ iRead = iCol--;
+ }
+ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
+ VdbeComment((v, "%s", aOutEx[i].zEName));
+ }
}
switch( eDest ){
+ case SRT_Table:
case SRT_EphemTab: {
+ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq, regRow);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, iParm, regRow, regRowid);
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -115636,8 +130875,7 @@ static void generateSortTail(
assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
pDest->zAffSdst, nColumn);
- sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
break;
}
case SRT_Mem: {
@@ -115645,13 +130883,23 @@ static void generateSortTail(
break;
}
#endif
+ case SRT_Upfrom: {
+ int i2 = pDest->iSDParm2;
+ int r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
+ if( i2<0 ){
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow);
+ }else{
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
+ }
+ break;
+ }
default: {
- assert( eDest==SRT_Output || eDest==SRT_Coroutine );
+ assert( eDest==SRT_Output || eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
testcase( eDest==SRT_Coroutine );
if( eDest==SRT_Output ){
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn);
- sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn);
}else{
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}
@@ -115689,37 +130937,37 @@ static void generateSortTail(
** original CREATE TABLE statement if the expression is a column. The
** declaration type for a ROWID field is INTEGER. Exactly when an expression
** is considered a column can be complex in the presence of subqueries. The
-** result-set expression in all of the following SELECT statements is
+** result-set expression in all of the following SELECT statements is
** considered a column by this function.
**
** SELECT col FROM tbl;
** SELECT (SELECT col FROM tbl;
** SELECT (SELECT col FROM tbl);
** SELECT abc FROM (SELECT col AS abc FROM tbl);
-**
+**
** The declaration type for any expression other than a column is NULL.
**
** This routine has either 3 or 6 parameters depending on whether or not
** the SQLITE_ENABLE_COLUMN_METADATA compile-time option is used.
*/
#ifdef SQLITE_ENABLE_COLUMN_METADATA
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F)
+# define columnType(A,B,C,D,E) columnTypeImpl(A,B,C,D,E)
#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */
-# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F)
+# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
#endif
static const char *columnTypeImpl(
- NameContext *pNC,
+ NameContext *pNC,
+#ifndef SQLITE_ENABLE_COLUMN_METADATA
+ Expr *pExpr
+#else
Expr *pExpr,
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
const char **pzOrigDb,
const char **pzOrigTab,
- const char **pzOrigCol,
+ const char **pzOrigCol
#endif
- u8 *pEstWidth
){
char const *zType = 0;
int j;
- u8 estWidth = 1;
#ifdef SQLITE_ENABLE_COLUMN_METADATA
char const *zOrigDb = 0;
char const *zOrigTab = 0;
@@ -115729,7 +130977,6 @@ static const char *columnTypeImpl(
assert( pExpr!=0 );
assert( pNC->pSrcList!=0 );
switch( pExpr->op ){
- case TK_AGG_COLUMN:
case TK_COLUMN: {
/* The expression is a column. Locate the table the column is being
** extracted from in NameContext.pSrcList. This table may be real
@@ -115738,8 +130985,6 @@ static const char *columnTypeImpl(
Table *pTab = 0; /* Table structure column is extracted from */
Select *pS = 0; /* Select the column is extracted from */
int iCol = pExpr->iColumn; /* Index of column in pTab */
- testcase( pExpr->op==TK_AGG_COLUMN );
- testcase( pExpr->op==TK_COLUMN );
while( pNC && !pTab ){
SrcList *pTabList = pNC->pSrcList;
for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++);
@@ -115754,70 +130999,66 @@ static const char *columnTypeImpl(
if( pTab==0 ){
/* At one time, code such as "SELECT new.x" within a trigger would
** cause this condition to run. Since then, we have restructured how
- ** trigger code is generated and so this condition is no longer
+ ** trigger code is generated and so this condition is no longer
** possible. However, it can still be true for statements like
** the following:
**
** CREATE TABLE t1(col INTEGER);
** SELECT (SELECT t1.col) FROM FROM t1;
**
- ** when columnType() is called on the expression "t1.col" in the
+ ** when columnType() is called on the expression "t1.col" in the
** sub-select. In this case, set the column type to NULL, even
** though it should really be "INTEGER".
**
** This is not a problem, as the column type of "t1.col" is never
- ** used. When columnType() is called on the expression
+ ** used. When columnType() is called on the expression
** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT
** branch below. */
break;
}
- assert( pTab && pExpr->pTab==pTab );
+ assert( pTab && pExpr->y.pTab==pTab );
if( pS ){
/* The "table" is actually a sub-select or a view in the FROM clause
** of the SELECT statement. Return the declaration type and origin
** data for the result-set column of the sub-select.
*/
- if( iCol>=0 && ALWAYS(iCol<pS->pEList->nExpr) ){
+ if( iCol>=0 && iCol<pS->pEList->nExpr ){
/* If iCol is less than zero, then the expression requests the
- ** rowid of the sub-select or view. This expression is legal (see
+ ** rowid of the sub-select or view. This expression is legal (see
** test case misc2.2.2) - it always evaluates to NULL.
- **
- ** The ALWAYS() is because iCol>=pS->pEList->nExpr will have been
- ** caught already by name resolution.
*/
NameContext sNC;
Expr *p = pS->pEList->a[iCol].pExpr;
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
- zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol, &estWidth);
+ zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol);
}
- }else if( pTab->pSchema ){
- /* A real table */
+ }else{
+ /* A real table or a CTE table */
assert( !pS );
- if( iCol<0 ) iCol = pTab->iPKey;
- assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
#ifdef SQLITE_ENABLE_COLUMN_METADATA
+ if( iCol<0 ) iCol = pTab->iPKey;
+ assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zType = "INTEGER";
zOrigCol = "rowid";
}else{
zOrigCol = pTab->aCol[iCol].zName;
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
- estWidth = pTab->aCol[iCol].szEst;
}
zOrigTab = pTab->zName;
- if( pNC->pParse ){
+ if( pNC->pParse && pTab->pSchema ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
}
#else
+ assert( iCol==XN_ROWID || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zType = "INTEGER";
}else{
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
- estWidth = pTab->aCol[iCol].szEst;
}
#endif
}
@@ -115836,13 +131077,13 @@ static const char *columnTypeImpl(
sNC.pSrcList = pS->pSrc;
sNC.pNext = pNC;
sNC.pParse = pNC->pParse;
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, &estWidth);
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
break;
}
#endif
}
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
if( pzOrigDb ){
assert( pzOrigTab && pzOrigCol );
*pzOrigDb = zOrigDb;
@@ -115850,7 +131091,6 @@ static const char *columnTypeImpl(
*pzOrigCol = zOrigCol;
}
#endif
- if( pEstWidth ) *pEstWidth = estWidth;
return zType;
}
@@ -115869,6 +131109,7 @@ static void generateColumnTypes(
NameContext sNC;
sNC.pSrcList = pTabList;
sNC.pParse = pParse;
+ sNC.pNext = 0;
for(i=0; i<pEList->nExpr; i++){
Expr *p = pEList->a[i].pExpr;
const char *zType;
@@ -115876,9 +131117,9 @@ static void generateColumnTypes(
const char *zOrigDb = 0;
const char *zOrigTab = 0;
const char *zOrigCol = 0;
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol, 0);
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
- /* The vdbe must make its own copy of the column-type and other
+ /* The vdbe must make its own copy of the column-type and other
** column specific strings, in case the schema is reset before this
** virtual machine is deleted.
*/
@@ -115886,27 +131127,56 @@ static void generateColumnTypes(
sqlite3VdbeSetColName(v, i, COLNAME_TABLE, zOrigTab, SQLITE_TRANSIENT);
sqlite3VdbeSetColName(v, i, COLNAME_COLUMN, zOrigCol, SQLITE_TRANSIENT);
#else
- zType = columnType(&sNC, p, 0, 0, 0, 0);
+ zType = columnType(&sNC, p, 0, 0, 0);
#endif
sqlite3VdbeSetColName(v, i, COLNAME_DECLTYPE, zType, SQLITE_TRANSIENT);
}
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
}
+
/*
-** Generate code that will tell the VDBE the names of columns
-** in the result set. This information is used to provide the
-** azCol[] values in the callback.
+** Compute the column names for a SELECT statement.
+**
+** The only guarantee that SQLite makes about column names is that if the
+** column has an AS clause assigning it a name, that will be the name used.
+** That is the only documented guarantee. However, countless applications
+** developed over the years have made baseless assumptions about column names
+** and will break if those assumptions changes. Hence, use extreme caution
+** when modifying this routine to avoid breaking legacy.
+**
+** See Also: sqlite3ColumnsFromExprList()
+**
+** The PRAGMA short_column_names and PRAGMA full_column_names settings are
+** deprecated. The default setting is short=ON, full=OFF. 99.9% of all
+** applications should operate this way. Nevertheless, we need to support the
+** other modes for legacy:
+**
+** short=OFF, full=OFF: Column name is the text of the expression has it
+** originally appears in the SELECT statement. In
+** other words, the zSpan of the result expression.
+**
+** short=ON, full=OFF: (This is the default setting). If the result
+** refers directly to a table column, then the
+** result column name is just the table column
+** name: COLUMN. Otherwise use zSpan.
+**
+** full=ON, short=ANY: If the result refers directly to a table column,
+** then the result column name with the table name
+** prefix, ex: TABLE.COLUMN. Otherwise use zSpan.
*/
static void generateColumnNames(
Parse *pParse, /* Parser context */
- SrcList *pTabList, /* List of tables */
- ExprList *pEList /* Expressions defining the result set */
+ Select *pSelect /* Generate column names for this SELECT statement */
){
Vdbe *v = pParse->pVdbe;
- int i, j;
+ int i;
+ Table *pTab;
+ SrcList *pTabList;
+ ExprList *pEList;
sqlite3 *db = pParse->db;
- int fullNames, shortNames;
+ int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
+ int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
#ifndef SQLITE_OMIT_EXPLAIN
/* If this is an EXPLAIN, skip this step */
@@ -115915,29 +131185,33 @@ static void generateColumnNames(
}
#endif
- if( pParse->colNamesSet || db->mallocFailed ) return;
+ if( pParse->colNamesSet ) return;
+ /* Column names are determined by the left-most term of a compound select */
+ while( pSelect->pPrior ) pSelect = pSelect->pPrior;
+ SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
+ pTabList = pSelect->pSrc;
+ pEList = pSelect->pEList;
assert( v!=0 );
assert( pTabList!=0 );
pParse->colNamesSet = 1;
- fullNames = (db->flags & SQLITE_FullColNames)!=0;
- shortNames = (db->flags & SQLITE_ShortColNames)!=0;
+ fullName = (db->flags & SQLITE_FullColNames)!=0;
+ srcName = (db->flags & SQLITE_ShortColNames)!=0 || fullName;
sqlite3VdbeSetNumCols(v, pEList->nExpr);
for(i=0; i<pEList->nExpr; i++){
- Expr *p;
- p = pEList->a[i].pExpr;
- if( NEVER(p==0) ) continue;
- if( pEList->a[i].zName ){
- char *zName = pEList->a[i].zName;
+ Expr *p = pEList->a[i].pExpr;
+
+ assert( p!=0 );
+ assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
+ assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */
+ if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){
+ /* An AS clause always takes first priority */
+ char *zName = pEList->a[i].zEName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
- }else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
- Table *pTab;
+ }else if( srcName && p->op==TK_COLUMN ){
char *zCol;
int iCol = p->iColumn;
- for(j=0; ALWAYS(j<pTabList->nSrc); j++){
- if( pTabList->a[j].iCursor==p->iTable ) break;
- }
- assert( j<pTabList->nSrc );
- pTab = pTabList->a[j].pTab;
+ pTab = p->y.pTab;
+ assert( pTab!=0 );
if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
@@ -115945,10 +131219,7 @@ static void generateColumnNames(
}else{
zCol = pTab->aCol[iCol].zName;
}
- if( !shortNames && !fullNames ){
- sqlite3VdbeSetColName(v, i, COLNAME_NAME,
- sqlite3DbStrDup(db, pEList->a[i].zSpan), SQLITE_DYNAMIC);
- }else if( fullNames ){
+ if( fullName ){
char *zName = 0;
zName = sqlite3MPrintf(db, "%s.%s", pTab->zName, zCol);
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_DYNAMIC);
@@ -115956,7 +131227,7 @@ static void generateColumnNames(
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zCol, SQLITE_TRANSIENT);
}
}else{
- const char *z = pEList->a[i].zSpan;
+ const char *z = pEList->a[i].zEName;
z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z);
sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC);
}
@@ -115976,6 +131247,15 @@ static void generateColumnNames(
**
** Return SQLITE_OK on success. If a memory allocation error occurs,
** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM.
+**
+** The only guarantee that SQLite makes about column names is that if the
+** column has an AS clause assigning it a name, that will be the name used.
+** That is the only documented guarantee. However, countless applications
+** developed over the years have made baseless assumptions about column names
+** and will break if those assumptions changes. Hence, use extreme caution
+** when modifying this routine to avoid breaking legacy.
+**
+** See Also: generateColumnNames()
*/
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
Parse *pParse, /* Parsing context */
@@ -115988,7 +131268,6 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
u32 cnt; /* Index added to make the name unique */
Column *aCol, *pCol; /* For looping over result columns */
int nCol; /* Number of columns in the result set */
- Expr *p; /* Expression for a single result column */
char *zName; /* Column name */
int nName; /* Size of name in zName[] */
Hash ht; /* Hash table of column names */
@@ -115998,6 +131277,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
nCol = pEList->nExpr;
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
testcase( aCol==0 );
+ if( nCol>32767 ) nCol = 32767;
}else{
nCol = 0;
aCol = 0;
@@ -116009,20 +131289,19 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
/* Get an appropriate name for the column
*/
- p = sqlite3ExprSkipCollate(pEList->a[i].pExpr);
- if( (zName = pEList->a[i].zName)!=0 ){
+ if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
/* If the column contains an "AS <name>" phrase, use <name> as the name */
}else{
- Expr *pColExpr = p; /* The expression that is the result column name */
- Table *pTab; /* Table associated with this expression */
+ Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
while( pColExpr->op==TK_DOT ){
pColExpr = pColExpr->pRight;
assert( pColExpr!=0 );
}
- if( pColExpr->op==TK_COLUMN && ALWAYS(pColExpr->pTab!=0) ){
+ if( pColExpr->op==TK_COLUMN ){
/* For columns use the column name name */
int iCol = pColExpr->iColumn;
- pTab = pColExpr->pTab;
+ Table *pTab = pColExpr->y.pTab;
+ assert( pTab!=0 );
if( iCol<0 ) iCol = pTab->iPKey;
zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
}else if( pColExpr->op==TK_ID ){
@@ -116030,10 +131309,14 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
zName = pColExpr->u.zToken;
}else{
/* Use the original text of the column expression as its name */
- zName = pEList->a[i].zSpan;
+ zName = pEList->a[i].zEName;
}
}
- zName = sqlite3MPrintf(db, "%s", zName);
+ if( zName && !sqlite3IsTrueOrFalse(zName) ){
+ zName = sqlite3DbStrDup(db, zName);
+ }else{
+ zName = sqlite3MPrintf(db,"column%d",i+1);
+ }
/* Make sure the column name is unique. If the name is not unique,
** append an integer to the name so that it becomes unique.
@@ -116049,6 +131332,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
}
pCol->zName = zName;
+ pCol->hName = sqlite3StrIHash(zName);
sqlite3ColumnPropertiesFromName(0, pCol);
if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
sqlite3OomFault(db);
@@ -116070,7 +131354,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
/*
** Add type and collation information to a column list based on
** a SELECT statement.
-**
+**
** The column list presumably came from selectColumnNamesFromExprList().
** The column list has only names, not types or collations. This
** routine goes through and adds the types and collations.
@@ -116081,7 +131365,8 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
Parse *pParse, /* Parsing contexts */
Table *pTab, /* Add column type information to this table */
- Select *pSelect /* SELECT used to determine types and collations */
+ Select *pSelect, /* SELECT used to determine types and collations */
+ char aff /* Default affinity for columns */
){
sqlite3 *db = pParse->db;
NameContext sNC;
@@ -116090,7 +131375,6 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
int i;
Expr *p;
struct ExprList_item *a;
- u64 szAll = 0;
assert( pSelect!=0 );
assert( (pSelect->selFlags & SF_Resolved)!=0 );
@@ -116103,10 +131387,11 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
const char *zType;
int n, m;
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
- szAll += pCol->szEst;
+ zType = columnType(&sNC, p, 0, 0, 0);
+ /* pCol->szEst = ... // Column size est for SELECT tables never used */
pCol->affinity = sqlite3ExprAffinity(p);
- if( zType && (m = sqlite3Strlen30(zType))>0 ){
+ if( zType ){
+ m = sqlite3Strlen30(zType);
n = sqlite3Strlen30(pCol->zName);
pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
if( pCol->zName ){
@@ -116114,43 +131399,40 @@ SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
pCol->colFlags |= COLFLAG_HASTYPE;
}
}
- if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
+ if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl && pCol->zColl==0 ){
pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
}
}
- pTab->szTabRow = sqlite3LogEst(szAll*4);
+ pTab->szTabRow = 1; /* Any non-zero value works */
}
/*
** Given a SELECT statement, generate a Table structure that describes
** the result set of that SELECT.
*/
-SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
+SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, char aff){
Table *pTab;
sqlite3 *db = pParse->db;
- int savedFlags;
+ u64 savedFlags;
savedFlags = db->flags;
- db->flags &= ~SQLITE_FullColNames;
+ db->flags &= ~(u64)SQLITE_FullColNames;
db->flags |= SQLITE_ShortColNames;
sqlite3SelectPrep(pParse, pSelect, 0);
+ db->flags = savedFlags;
if( pParse->nErr ) return 0;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
- db->flags = savedFlags;
pTab = sqlite3DbMallocZero(db, sizeof(Table) );
if( pTab==0 ){
return 0;
}
- /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
- ** is disabled */
- assert( db->lookaside.bDisable );
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
+ sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@@ -116163,41 +131445,38 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
-static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
- if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1);
+SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
+ if( pParse->pVdbe ){
+ return pParse->pVdbe;
+ }
if( pParse->pToplevel==0
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
){
pParse->okConstFactor = 1;
}
- return v;
-}
-SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe;
- return v ? v : allocVdbe(pParse);
+ return sqlite3VdbeCreate(pParse);
}
/*
** Compute the iLimit and iOffset fields of the SELECT based on the
-** pLimit and pOffset expressions. pLimit and pOffset hold the expressions
+** pLimit expressions. pLimit->pLeft and pLimit->pRight hold the expressions
** that appear in the original SQL statement after the LIMIT and OFFSET
-** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
-** are the integer memory register numbers for counters used to compute
-** the limit and offset. If there is no limit and/or offset, then
+** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
+** are the integer memory register numbers for counters used to compute
+** the limit and offset. If there is no limit and/or offset, then
** iLimit and iOffset are negative.
**
** This routine changes the values of iLimit and iOffset only if
-** a limit or offset is defined by pLimit and pOffset. iLimit and
-** iOffset should have been preset to appropriate default values (zero)
+** a limit or offset is defined by pLimit->pLeft and pLimit->pRight. iLimit
+** and iOffset should have been preset to appropriate default values (zero)
** prior to calling this routine.
**
** The iOffset register (if it exists) is initialized to the value
** of the OFFSET. The iLimit register is initialized to LIMIT. Register
** iOffset+1 is initialized to LIMIT+OFFSET.
**
-** Only if pLimit!=0 or pOffset!=0 do the limit registers get
+** Only if pLimit->pLeft!=0 do the limit registers get
** redefined. The UNION ALL operator uses this property to force
** the reuse of the same limit and offset registers across multiple
** SELECT statements.
@@ -116207,21 +131486,23 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
int iLimit = 0;
int iOffset;
int n;
+ Expr *pLimit = p->pLimit;
+
if( p->iLimit ) return;
- /*
+ /*
** "LIMIT -1" always shows all rows. There is some
** controversy about what the correct behavior should be.
** The current implementation interprets "LIMIT 0" to mean
** no rows.
*/
- sqlite3ExprCacheClear(pParse);
- assert( p->pOffset==0 || p->pLimit!=0 );
- if( p->pLimit ){
+ if( pLimit ){
+ assert( pLimit->op==TK_LIMIT );
+ assert( pLimit->pLeft!=0 );
p->iLimit = iLimit = ++pParse->nMem;
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
- if( sqlite3ExprIsInteger(p->pLimit, &n) ){
+ if( sqlite3ExprIsInteger(pLimit->pLeft, &n) ){
sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
@@ -116231,15 +131512,15 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
p->selFlags |= SF_FixedLimit;
}
}else{
- sqlite3ExprCode(pParse, p->pLimit, iLimit);
+ sqlite3ExprCode(pParse, pLimit->pLeft, iLimit);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iLimit); VdbeCoverage(v);
VdbeComment((v, "LIMIT counter"));
sqlite3VdbeAddOp2(v, OP_IfNot, iLimit, iBreak); VdbeCoverage(v);
}
- if( p->pOffset ){
+ if( pLimit->pRight ){
p->iOffset = iOffset = ++pParse->nMem;
pParse->nMem++; /* Allocate an extra register for limit+offset */
- sqlite3ExprCode(pParse, p->pOffset, iOffset);
+ sqlite3ExprCode(pParse, pLimit->pRight, iOffset);
sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
VdbeComment((v, "OFFSET counter"));
sqlite3VdbeAddOp3(v, OP_OffsetLimit, iLimit, iOffset+1, iOffset);
@@ -116305,7 +131586,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
}
assert( sqlite3KeyInfoIsWriteable(pRet) );
pRet->aColl[i] = pColl;
- pRet->aSortOrder[i] = pOrderBy->a[i].sortOrder;
+ pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags;
}
}
@@ -116337,7 +131618,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
** inserted into the Queue table. The iDistinct table keeps a copy of all rows
** that have ever been inserted into Queue and causes duplicates to be
** discarded. If the operator is UNION ALL, then duplicates are allowed.
-**
+**
** If the query has an ORDER BY, then entries in the Queue table are kept in
** ORDER BY order and the first entry is extracted for each cycle. Without
** an ORDER BY, the Queue table is just a FIFO.
@@ -116369,20 +131650,27 @@ static void generateWithRecursiveQuery(
int i; /* Loop counter */
int rc; /* Result code */
ExprList *pOrderBy; /* The ORDER BY clause */
- Expr *pLimit, *pOffset; /* Saved LIMIT and OFFSET */
+ Expr *pLimit; /* Saved LIMIT and OFFSET */
int regLimit, regOffset; /* Registers used by LIMIT and OFFSET */
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( p->pWin ){
+ sqlite3ErrorMsg(pParse, "cannot use window functions in recursive queries");
+ return;
+ }
+#endif
+
/* Obtain authorization to do a recursive query */
if( sqlite3AuthCheck(pParse, SQLITE_RECURSIVE, 0, 0, 0) ) return;
/* Process the LIMIT and OFFSET clauses, if they exist */
- addrBreak = sqlite3VdbeMakeLabel(v);
+ addrBreak = sqlite3VdbeMakeLabel(pParse);
+ p->nSelectRow = 320; /* 4 billion rows */
computeLimitRegisters(pParse, p, addrBreak);
pLimit = p->pLimit;
- pOffset = p->pOffset;
regLimit = p->iLimit;
regOffset = p->iOffset;
- p->pLimit = p->pOffset = 0;
+ p->pLimit = 0;
p->iLimit = p->iOffset = 0;
pOrderBy = p->pOrderBy;
@@ -116428,6 +131716,7 @@ static void generateWithRecursiveQuery(
/* Store the results of the setup-query in Queue. */
pSetup->pNext = 0;
+ ExplainQueryPlan((pParse, 1, "SETUP"));
rc = sqlite3Select(pParse, pSetup, &destQueue);
pSetup->pNext = p;
if( rc ) goto end_of_recursive_query;
@@ -116445,9 +131734,9 @@ static void generateWithRecursiveQuery(
sqlite3VdbeAddOp1(v, OP_Delete, iQueue);
/* Output the single row in Current */
- addrCont = sqlite3VdbeMakeLabel(v);
+ addrCont = sqlite3VdbeMakeLabel(pParse);
codeOffset(v, regOffset, addrCont);
- selectInnerLoop(pParse, p, p->pEList, iCurrent,
+ selectInnerLoop(pParse, p, iCurrent,
0, 0, pDest, addrCont, addrBreak);
if( regLimit ){
sqlite3VdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
@@ -116462,6 +131751,7 @@ static void generateWithRecursiveQuery(
sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
}else{
p->pPrior = 0;
+ ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));
sqlite3Select(pParse, p, &destQueue);
assert( p->pPrior==0 );
p->pPrior = pSetup;
@@ -116475,7 +131765,6 @@ end_of_recursive_query:
sqlite3ExprListDelete(pParse->db, p->pOrderBy);
p->pOrderBy = pOrderBy;
p->pLimit = pLimit;
- p->pOffset = pOffset;
return;
}
#endif /* SQLITE_OMIT_CTE */
@@ -116494,36 +131783,41 @@ static int multiSelectOrderBy(
** on a VALUES clause.
**
** Because the Select object originates from a VALUES clause:
-** (1) It has no LIMIT or OFFSET
+** (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1
** (2) All terms are UNION ALL
** (3) There is no ORDER BY clause
+**
+** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES
+** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))").
+** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case.
+** Since the limit is exactly 1, we only need to evalutes the left-most VALUES.
*/
static int multiSelectValues(
Parse *pParse, /* Parsing context */
Select *p, /* The right-most of SELECTs to be coded */
SelectDest *pDest /* What to do with query results */
){
- Select *pPrior;
int nRow = 1;
int rc = 0;
+ int bShowAll = p->pLimit==0;
assert( p->selFlags & SF_MultiValue );
do{
assert( p->selFlags & SF_Values );
assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) );
- assert( p->pLimit==0 );
- assert( p->pOffset==0 );
assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr );
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( p->pWin ) return -1;
+#endif
if( p->pPrior==0 ) break;
assert( p->pPrior->pNext==p );
p = p->pPrior;
- nRow++;
+ nRow += bShowAll;
}while(1);
+ ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow,
+ nRow==1 ? "" : "S"));
while( p ){
- pPrior = p->pPrior;
- p->pPrior = 0;
- rc = sqlite3Select(pParse, p, pDest);
- p->pPrior = pPrior;
- if( rc ) break;
+ selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1);
+ if( !bShowAll ) break;
p->nSelectRow = nRow;
p = p->pNext;
}
@@ -116537,7 +131831,7 @@ static int multiSelectValues(
**
** "p" points to the right-most of the two queries. the query on the
** left is p->pPrior. The left query could also be a compound query
-** in which case this routine will be called recursively.
+** in which case this routine will be called recursively.
**
** The results of the total query are to be written into a destination
** of type eDest with parameter iParm.
@@ -116572,28 +131866,19 @@ static int multiSelect(
SelectDest dest; /* Alternative data destination */
Select *pDelete = 0; /* Chain of simple selects to delete */
sqlite3 *db; /* Database connection */
-#ifndef SQLITE_OMIT_EXPLAIN
- int iSub1 = 0; /* EQP id of left-hand query */
- int iSub2 = 0; /* EQP id of right-hand query */
-#endif
/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only
** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
*/
assert( p && p->pPrior ); /* Calling function guarantees this much */
assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION );
+ assert( p->selFlags & SF_Compound );
db = pParse->db;
pPrior = p->pPrior;
dest = *pDest;
- if( pPrior->pOrderBy ){
- sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
- selectOpName(p->op));
- rc = 1;
- goto multi_select_end;
- }
- if( pPrior->pLimit ){
- sqlite3ErrorMsg(pParse,"LIMIT clause should come after %s not before",
- selectOpName(p->op));
+ if( pPrior->pOrderBy || pPrior->pLimit ){
+ sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
+ pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op));
rc = 1;
goto multi_select_end;
}
@@ -116613,7 +131898,8 @@ static int multiSelect(
*/
if( p->selFlags & SF_MultiValue ){
rc = multiSelectValues(pParse, p, &dest);
- goto multi_select_end;
+ if( rc>=0 ) goto multi_select_end;
+ rc = SQLITE_OK;
}
/* Make sure all SELECTs in the statement have the same number of elements
@@ -116632,237 +131918,232 @@ static int multiSelect(
*/
if( p->pOrderBy ){
return multiSelectOrderBy(pParse, p, pDest);
- }else
+ }else{
- /* Generate code for the left and right SELECT statements.
- */
- switch( p->op ){
- case TK_ALL: {
- int addr = 0;
- int nLimit;
- assert( !pPrior->pLimit );
- pPrior->iLimit = p->iLimit;
- pPrior->iOffset = p->iOffset;
- pPrior->pLimit = p->pLimit;
- pPrior->pOffset = p->pOffset;
- explainSetInteger(iSub1, pParse->iNextSelectId);
- rc = sqlite3Select(pParse, pPrior, &dest);
- p->pLimit = 0;
- p->pOffset = 0;
- if( rc ){
- goto multi_select_end;
- }
- p->pPrior = 0;
- p->iLimit = pPrior->iLimit;
- p->iOffset = pPrior->iOffset;
- if( p->iLimit ){
- addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
- VdbeComment((v, "Jump ahead if LIMIT reached"));
- if( p->iOffset ){
- sqlite3VdbeAddOp3(v, OP_OffsetLimit,
- p->iLimit, p->iOffset+1, p->iOffset);
+#ifndef SQLITE_OMIT_EXPLAIN
+ if( pPrior->pPrior==0 ){
+ ExplainQueryPlan((pParse, 1, "COMPOUND QUERY"));
+ ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY"));
+ }
+#endif
+
+ /* Generate code for the left and right SELECT statements.
+ */
+ switch( p->op ){
+ case TK_ALL: {
+ int addr = 0;
+ int nLimit;
+ assert( !pPrior->pLimit );
+ pPrior->iLimit = p->iLimit;
+ pPrior->iOffset = p->iOffset;
+ pPrior->pLimit = p->pLimit;
+ rc = sqlite3Select(pParse, pPrior, &dest);
+ p->pLimit = 0;
+ if( rc ){
+ goto multi_select_end;
+ }
+ p->pPrior = 0;
+ p->iLimit = pPrior->iLimit;
+ p->iOffset = pPrior->iOffset;
+ if( p->iLimit ){
+ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
+ VdbeComment((v, "Jump ahead if LIMIT reached"));
+ if( p->iOffset ){
+ sqlite3VdbeAddOp3(v, OP_OffsetLimit,
+ p->iLimit, p->iOffset+1, p->iOffset);
+ }
}
+ ExplainQueryPlan((pParse, 1, "UNION ALL"));
+ rc = sqlite3Select(pParse, p, &dest);
+ testcase( rc!=SQLITE_OK );
+ pDelete = p->pPrior;
+ p->pPrior = pPrior;
+ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
+ if( pPrior->pLimit
+ && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
+ && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
+ ){
+ p->nSelectRow = sqlite3LogEst((u64)nLimit);
+ }
+ if( addr ){
+ sqlite3VdbeJumpHere(v, addr);
+ }
+ break;
}
- explainSetInteger(iSub2, pParse->iNextSelectId);
- rc = sqlite3Select(pParse, p, &dest);
- testcase( rc!=SQLITE_OK );
- pDelete = p->pPrior;
- p->pPrior = pPrior;
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
- if( pPrior->pLimit
- && sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
- && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
- ){
- p->nSelectRow = sqlite3LogEst((u64)nLimit);
- }
- if( addr ){
- sqlite3VdbeJumpHere(v, addr);
- }
- break;
- }
- case TK_EXCEPT:
- case TK_UNION: {
- int unionTab; /* Cursor number of the temporary table holding result */
- u8 op = 0; /* One of the SRT_ operations to apply to self */
- int priorOp; /* The SRT_ operation to apply to prior selects */
- Expr *pLimit, *pOffset; /* Saved values of p->nLimit and p->nOffset */
- int addr;
- SelectDest uniondest;
-
- testcase( p->op==TK_EXCEPT );
- testcase( p->op==TK_UNION );
- priorOp = SRT_Union;
- if( dest.eDest==priorOp ){
- /* We can reuse a temporary table generated by a SELECT to our
- ** right.
+ case TK_EXCEPT:
+ case TK_UNION: {
+ int unionTab; /* Cursor number of the temp table holding result */
+ u8 op = 0; /* One of the SRT_ operations to apply to self */
+ int priorOp; /* The SRT_ operation to apply to prior selects */
+ Expr *pLimit; /* Saved values of p->nLimit */
+ int addr;
+ SelectDest uniondest;
+
+ testcase( p->op==TK_EXCEPT );
+ testcase( p->op==TK_UNION );
+ priorOp = SRT_Union;
+ if( dest.eDest==priorOp ){
+ /* We can reuse a temporary table generated by a SELECT to our
+ ** right.
+ */
+ assert( p->pLimit==0 ); /* Not allowed on leftward elements */
+ unionTab = dest.iSDParm;
+ }else{
+ /* We will need to create our own temporary table to hold the
+ ** intermediate results.
+ */
+ unionTab = pParse->nTab++;
+ assert( p->pOrderBy==0 );
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
+ assert( p->addrOpenEphm[0] == -1 );
+ p->addrOpenEphm[0] = addr;
+ findRightmost(p)->selFlags |= SF_UsesEphemeral;
+ assert( p->pEList );
+ }
+
+ /* Code the SELECT statements to our left
*/
- assert( p->pLimit==0 ); /* Not allowed on leftward elements */
- assert( p->pOffset==0 ); /* Not allowed on leftward elements */
- unionTab = dest.iSDParm;
- }else{
- /* We will need to create our own temporary table to hold the
- ** intermediate results.
+ assert( !pPrior->pOrderBy );
+ sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
+ rc = sqlite3Select(pParse, pPrior, &uniondest);
+ if( rc ){
+ goto multi_select_end;
+ }
+
+ /* Code the current SELECT statement
+ */
+ if( p->op==TK_EXCEPT ){
+ op = SRT_Except;
+ }else{
+ assert( p->op==TK_UNION );
+ op = SRT_Union;
+ }
+ p->pPrior = 0;
+ pLimit = p->pLimit;
+ p->pLimit = 0;
+ uniondest.eDest = op;
+ ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
+ selectOpName(p->op)));
+ rc = sqlite3Select(pParse, p, &uniondest);
+ testcase( rc!=SQLITE_OK );
+ assert( p->pOrderBy==0 );
+ pDelete = p->pPrior;
+ p->pPrior = pPrior;
+ p->pOrderBy = 0;
+ if( p->op==TK_UNION ){
+ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
+ }
+ sqlite3ExprDelete(db, p->pLimit);
+ p->pLimit = pLimit;
+ p->iLimit = 0;
+ p->iOffset = 0;
+
+ /* Convert the data in the temporary table into whatever form
+ ** it is that we currently need.
+ */
+ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
+ assert( p->pEList || db->mallocFailed );
+ if( dest.eDest!=priorOp && db->mallocFailed==0 ){
+ int iCont, iBreak, iStart;
+ iBreak = sqlite3VdbeMakeLabel(pParse);
+ iCont = sqlite3VdbeMakeLabel(pParse);
+ computeLimitRegisters(pParse, p, iBreak);
+ sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
+ iStart = sqlite3VdbeCurrentAddr(v);
+ selectInnerLoop(pParse, p, unionTab,
+ 0, 0, &dest, iCont, iBreak);
+ sqlite3VdbeResolveLabel(v, iCont);
+ sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
+ sqlite3VdbeResolveLabel(v, iBreak);
+ sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
+ }
+ break;
+ }
+ default: assert( p->op==TK_INTERSECT ); {
+ int tab1, tab2;
+ int iCont, iBreak, iStart;
+ Expr *pLimit;
+ int addr;
+ SelectDest intersectdest;
+ int r1;
+
+ /* INTERSECT is different from the others since it requires
+ ** two temporary tables. Hence it has its own case. Begin
+ ** by allocating the tables we will need.
*/
- unionTab = pParse->nTab++;
+ tab1 = pParse->nTab++;
+ tab2 = pParse->nTab++;
assert( p->pOrderBy==0 );
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
+
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
assert( p->addrOpenEphm[0] == -1 );
p->addrOpenEphm[0] = addr;
findRightmost(p)->selFlags |= SF_UsesEphemeral;
assert( p->pEList );
- }
-
- /* Code the SELECT statements to our left
- */
- assert( !pPrior->pOrderBy );
- sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
- explainSetInteger(iSub1, pParse->iNextSelectId);
- rc = sqlite3Select(pParse, pPrior, &uniondest);
- if( rc ){
- goto multi_select_end;
- }
- /* Code the current SELECT statement
- */
- if( p->op==TK_EXCEPT ){
- op = SRT_Except;
- }else{
- assert( p->op==TK_UNION );
- op = SRT_Union;
- }
- p->pPrior = 0;
- pLimit = p->pLimit;
- p->pLimit = 0;
- pOffset = p->pOffset;
- p->pOffset = 0;
- uniondest.eDest = op;
- explainSetInteger(iSub2, pParse->iNextSelectId);
- rc = sqlite3Select(pParse, p, &uniondest);
- testcase( rc!=SQLITE_OK );
- /* Query flattening in sqlite3Select() might refill p->pOrderBy.
- ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
- sqlite3ExprListDelete(db, p->pOrderBy);
- pDelete = p->pPrior;
- p->pPrior = pPrior;
- p->pOrderBy = 0;
- if( p->op==TK_UNION ){
- p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
- }
- sqlite3ExprDelete(db, p->pLimit);
- p->pLimit = pLimit;
- p->pOffset = pOffset;
- p->iLimit = 0;
- p->iOffset = 0;
+ /* Code the SELECTs to our left into temporary table "tab1".
+ */
+ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
+ rc = sqlite3Select(pParse, pPrior, &intersectdest);
+ if( rc ){
+ goto multi_select_end;
+ }
- /* Convert the data in the temporary table into whatever form
- ** it is that we currently need.
- */
- assert( unionTab==dest.iSDParm || dest.eDest!=priorOp );
- if( dest.eDest!=priorOp ){
- int iCont, iBreak, iStart;
+ /* Code the current SELECT into temporary table "tab2"
+ */
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
+ assert( p->addrOpenEphm[1] == -1 );
+ p->addrOpenEphm[1] = addr;
+ p->pPrior = 0;
+ pLimit = p->pLimit;
+ p->pLimit = 0;
+ intersectdest.iSDParm = tab2;
+ ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
+ selectOpName(p->op)));
+ rc = sqlite3Select(pParse, p, &intersectdest);
+ testcase( rc!=SQLITE_OK );
+ pDelete = p->pPrior;
+ p->pPrior = pPrior;
+ if( p->nSelectRow>pPrior->nSelectRow ){
+ p->nSelectRow = pPrior->nSelectRow;
+ }
+ sqlite3ExprDelete(db, p->pLimit);
+ p->pLimit = pLimit;
+
+ /* Generate code to take the intersection of the two temporary
+ ** tables.
+ */
+ if( rc ) break;
assert( p->pEList );
- if( dest.eDest==SRT_Output ){
- Select *pFirst = p;
- while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
- }
- iBreak = sqlite3VdbeMakeLabel(v);
- iCont = sqlite3VdbeMakeLabel(v);
+ iBreak = sqlite3VdbeMakeLabel(pParse);
+ iCont = sqlite3VdbeMakeLabel(pParse);
computeLimitRegisters(pParse, p, iBreak);
- sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v);
- iStart = sqlite3VdbeCurrentAddr(v);
- selectInnerLoop(pParse, p, p->pEList, unionTab,
+ sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
+ r1 = sqlite3GetTempReg(pParse);
+ iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0);
+ VdbeCoverage(v);
+ sqlite3ReleaseTempReg(pParse, r1);
+ selectInnerLoop(pParse, p, tab1,
0, 0, &dest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v);
+ sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
+ sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
+ break;
}
- break;
}
- default: assert( p->op==TK_INTERSECT ); {
- int tab1, tab2;
- int iCont, iBreak, iStart;
- Expr *pLimit, *pOffset;
- int addr;
- SelectDest intersectdest;
- int r1;
-
- /* INTERSECT is different from the others since it requires
- ** two temporary tables. Hence it has its own case. Begin
- ** by allocating the tables we will need.
- */
- tab1 = pParse->nTab++;
- tab2 = pParse->nTab++;
- assert( p->pOrderBy==0 );
-
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
- assert( p->addrOpenEphm[0] == -1 );
- p->addrOpenEphm[0] = addr;
- findRightmost(p)->selFlags |= SF_UsesEphemeral;
- assert( p->pEList );
-
- /* Code the SELECTs to our left into temporary table "tab1".
- */
- sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
- explainSetInteger(iSub1, pParse->iNextSelectId);
- rc = sqlite3Select(pParse, pPrior, &intersectdest);
- if( rc ){
- goto multi_select_end;
- }
-
- /* Code the current SELECT into temporary table "tab2"
- */
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
- assert( p->addrOpenEphm[1] == -1 );
- p->addrOpenEphm[1] = addr;
- p->pPrior = 0;
- pLimit = p->pLimit;
- p->pLimit = 0;
- pOffset = p->pOffset;
- p->pOffset = 0;
- intersectdest.iSDParm = tab2;
- explainSetInteger(iSub2, pParse->iNextSelectId);
- rc = sqlite3Select(pParse, p, &intersectdest);
- testcase( rc!=SQLITE_OK );
- pDelete = p->pPrior;
- p->pPrior = pPrior;
- if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
- sqlite3ExprDelete(db, p->pLimit);
- p->pLimit = pLimit;
- p->pOffset = pOffset;
- /* Generate code to take the intersection of the two temporary
- ** tables.
- */
- assert( p->pEList );
- if( dest.eDest==SRT_Output ){
- Select *pFirst = p;
- while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
- }
- iBreak = sqlite3VdbeMakeLabel(v);
- iCont = sqlite3VdbeMakeLabel(v);
- computeLimitRegisters(pParse, p, iBreak);
- sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
- r1 = sqlite3GetTempReg(pParse);
- iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
- sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
- sqlite3ReleaseTempReg(pParse, r1);
- selectInnerLoop(pParse, p, p->pEList, tab1,
- 0, 0, &dest, iCont, iBreak);
- sqlite3VdbeResolveLabel(v, iCont);
- sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v);
- sqlite3VdbeResolveLabel(v, iBreak);
- sqlite3VdbeAddOp2(v, OP_Close, tab2, 0);
- sqlite3VdbeAddOp2(v, OP_Close, tab1, 0);
- break;
+ #ifndef SQLITE_OMIT_EXPLAIN
+ if( p->pNext==0 ){
+ ExplainQueryPlanPop(pParse);
}
+ #endif
}
+ if( pParse->nErr ) goto multi_select_end;
- explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL);
-
- /* Compute collating sequences used by
+ /* Compute collating sequences used by
** temporary tables needed to implement the compound select.
** Attach the KeyInfo structure to all temporary tables.
**
@@ -116966,9 +132247,9 @@ static int generateOutputSubroutine(
int addr;
addr = sqlite3VdbeCurrentAddr(v);
- iContinue = sqlite3VdbeMakeLabel(v);
+ iContinue = sqlite3VdbeMakeLabel(pParse);
- /* Suppress duplicates for UNION, EXCEPT, and INTERSECT
+ /* Suppress duplicates for UNION, EXCEPT, and INTERSECT
*/
if( regPrev ){
int addr1, addr2;
@@ -117010,21 +132291,24 @@ static int generateOutputSubroutine(
int r1;
testcase( pIn->nSdst>1 );
r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
r1, pDest->zAffSdst, pIn->nSdst);
- sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
+ pIn->iSdst, pIn->nSdst);
sqlite3ReleaseTempReg(pParse, r1);
break;
}
/* If this is a scalar select that is part of an expression, then
** store the results in the appropriate memory cell and break out
- ** of the scan loop.
+ ** of the scan loop. Note that the select might return multiple columns
+ ** if it is the RHS of a row-value IN operator.
*/
case SRT_Mem: {
- assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 );
- sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1);
+ if( pParse->nErr==0 ){
+ testcase( pIn->nSdst>1 );
+ sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst);
+ }
/* The LIMIT clause will jump out of the loop for us */
break;
}
@@ -117047,14 +132331,13 @@ static int generateOutputSubroutine(
** SRT_Output. This routine is never called with any other
** destination other than the ones handled above or SRT_Output.
**
- ** For SRT_Output, results are stored in a sequence of registers.
+ ** For SRT_Output, results are stored in a sequence of registers.
** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
** return the next row of result.
*/
default: {
assert( pDest->eDest==SRT_Output );
sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst);
- sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
break;
}
}
@@ -117105,7 +132388,7 @@ static int generateOutputSubroutine(
**
** EofB: Called when data is exhausted from selectB.
**
-** The implementation of the latter five subroutines depend on which
+** The implementation of the latter five subroutines depend on which
** <operator> is used:
**
**
@@ -117197,24 +132480,20 @@ static int multiSelectOrderBy(
sqlite3 *db; /* Database connection */
ExprList *pOrderBy; /* The ORDER BY clause */
int nOrderBy; /* Number of terms in the ORDER BY clause */
- int *aPermute; /* Mapping from ORDER BY terms to result set columns */
-#ifndef SQLITE_OMIT_EXPLAIN
- int iSub1; /* EQP id of left-hand query */
- int iSub2; /* EQP id of right-hand query */
-#endif
+ u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */
assert( p->pOrderBy!=0 );
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
db = pParse->db;
v = pParse->pVdbe;
assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */
- labelEnd = sqlite3VdbeMakeLabel(v);
- labelCmpr = sqlite3VdbeMakeLabel(v);
+ labelEnd = sqlite3VdbeMakeLabel(pParse);
+ labelCmpr = sqlite3VdbeMakeLabel(pParse);
/* Patch up the ORDER BY clause
*/
- op = p->op;
+ op = p->op;
pPrior = p->pPrior;
assert( pPrior->pOrderBy==0 );
pOrderBy = p->pOrderBy;
@@ -117237,7 +132516,7 @@ static int multiSelectOrderBy(
if( pNew==0 ) return SQLITE_NOMEM_BKPT;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
- pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
+ p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
}
}
@@ -117250,7 +132529,7 @@ static int multiSelectOrderBy(
** to the right and the left are evaluated, they use the correct
** collation.
*/
- aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
+ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
if( aPermute ){
struct ExprList_item *pItem;
aPermute[0] = nOrderBy;
@@ -117286,11 +132565,11 @@ static int multiSelectOrderBy(
assert( sqlite3KeyInfoIsWriteable(pKeyDup) );
for(i=0; i<nExpr; i++){
pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
- pKeyDup->aSortOrder[i] = 0;
+ pKeyDup->aSortFlags[i] = 0;
}
}
}
-
+
/* Separate the left and the right query from one another
*/
p->pPrior = 0;
@@ -117313,8 +132592,6 @@ static int multiSelectOrderBy(
}
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = 0;
- sqlite3ExprDelete(db, p->pOffset);
- p->pOffset = 0;
regAddrA = ++pParse->nMem;
regAddrB = ++pParse->nMem;
@@ -117323,6 +132600,8 @@ static int multiSelectOrderBy(
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
+ ExplainQueryPlan((pParse, 1, "MERGE (%s)", selectOpName(p->op)));
+
/* Generate a coroutine to evaluate the SELECT statement to the
** left of the compound operator - the "A" select.
*/
@@ -117330,12 +132609,12 @@ static int multiSelectOrderBy(
addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
VdbeComment((v, "left SELECT"));
pPrior->iLimit = regLimitA;
- explainSetInteger(iSub1, pParse->iNextSelectId);
+ ExplainQueryPlan((pParse, 1, "LEFT"));
sqlite3Select(pParse, pPrior, &destA);
sqlite3VdbeEndCoroutine(v, regAddrA);
sqlite3VdbeJumpHere(v, addr1);
- /* Generate a coroutine to evaluate the SELECT statement on
+ /* Generate a coroutine to evaluate the SELECT statement on
** the right - the "B" select
*/
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
@@ -117344,8 +132623,8 @@ static int multiSelectOrderBy(
savedLimit = p->iLimit;
savedOffset = p->iOffset;
p->iLimit = regLimitB;
- p->iOffset = 0;
- explainSetInteger(iSub2, pParse->iNextSelectId);
+ p->iOffset = 0;
+ ExplainQueryPlan((pParse, 1, "RIGHT"));
sqlite3Select(pParse, p, &destB);
p->iLimit = savedLimit;
p->iOffset = savedOffset;
@@ -117358,7 +132637,7 @@ static int multiSelectOrderBy(
addrOutA = generateOutputSubroutine(pParse,
p, &destA, pDest, regOutA,
regPrev, pKeyDup, labelEnd);
-
+
/* Generate a subroutine that outputs the current row of the B
** select as the next output row of the compound select.
*/
@@ -117375,7 +132654,7 @@ static int multiSelectOrderBy(
*/
if( op==TK_EXCEPT || op==TK_INTERSECT ){
addrEofA_noB = addrEofA = labelEnd;
- }else{
+ }else{
VdbeNoopComment((v, "eof-A subroutine"));
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
@@ -117390,7 +132669,7 @@ static int multiSelectOrderBy(
if( op==TK_INTERSECT ){
addrEofB = addrEofA;
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
- }else{
+ }else{
VdbeNoopComment((v, "eof-B subroutine"));
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v);
@@ -117447,14 +132726,6 @@ static int multiSelectOrderBy(
*/
sqlite3VdbeResolveLabel(v, labelEnd);
- /* Set the number of output columns
- */
- if( pDest->eDest==SRT_Output ){
- Select *pFirst = pPrior;
- while( pFirst->pPrior ) pFirst = pFirst->pPrior;
- generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
- }
-
/* Reassembly the compound query so that it will be freed correctly
** by the calling function */
if( p->pPrior ){
@@ -117465,93 +132736,156 @@ static int multiSelectOrderBy(
/*** TBD: Insert subroutine calls to close cursors on incomplete
**** subqueries ****/
- explainComposite(pParse, p->op, iSub1, iSub2, 0);
+ ExplainQueryPlanPop(pParse);
return pParse->nErr!=0;
}
#endif
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+
+/* An instance of the SubstContext object describes an substitution edit
+** to be performed on a parse tree.
+**
+** All references to columns in table iTable are to be replaced by corresponding
+** expressions in pEList.
+*/
+typedef struct SubstContext {
+ Parse *pParse; /* The parsing context */
+ int iTable; /* Replace references to this table */
+ int iNewTable; /* New table number */
+ int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
+ ExprList *pEList; /* Replacement expressions */
+} SubstContext;
+
/* Forward Declarations */
-static void substExprList(sqlite3*, ExprList*, int, ExprList*);
-static void substSelect(sqlite3*, Select *, int, ExprList*, int);
+static void substExprList(SubstContext*, ExprList*);
+static void substSelect(SubstContext*, Select*, int);
/*
** Scan through the expression pExpr. Replace every reference to
** a column in table number iTable with a copy of the iColumn-th
-** entry in pEList. (But leave references to the ROWID column
+** entry in pEList. (But leave references to the ROWID column
** unchanged.)
**
** This routine is part of the flattening procedure. A subquery
** whose result set is defined by pEList appears as entry in the
** FROM clause of a SELECT such that the VDBE cursor assigned to that
-** FORM clause entry is iTable. This routine make the necessary
+** FORM clause entry is iTable. This routine makes the necessary
** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery.
*/
static Expr *substExpr(
- sqlite3 *db, /* Report malloc errors to this connection */
- Expr *pExpr, /* Expr in which substitution occurs */
- int iTable, /* Table to be substituted */
- ExprList *pEList /* Substitute expressions */
+ SubstContext *pSubst, /* Description of the substitution */
+ Expr *pExpr /* Expr in which substitution occurs */
){
if( pExpr==0 ) return 0;
- if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
+ if( ExprHasProperty(pExpr, EP_FromJoin)
+ && pExpr->iRightJoinTable==pSubst->iTable
+ ){
+ pExpr->iRightJoinTable = pSubst->iNewTable;
+ }
+ if( pExpr->op==TK_COLUMN
+ && pExpr->iTable==pSubst->iTable
+ && !ExprHasProperty(pExpr, EP_FixedCol)
+ ){
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
}else{
Expr *pNew;
- assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
- assert( pExpr->pLeft==0 && pExpr->pRight==0 );
- pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
- sqlite3ExprDelete(db, pExpr);
- pExpr = pNew;
+ Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
+ Expr ifNullRow;
+ assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
+ assert( pExpr->pRight==0 );
+ if( sqlite3ExprIsVector(pCopy) ){
+ sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
+ }else{
+ sqlite3 *db = pSubst->pParse->db;
+ if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
+ memset(&ifNullRow, 0, sizeof(ifNullRow));
+ ifNullRow.op = TK_IF_NULL_ROW;
+ ifNullRow.pLeft = pCopy;
+ ifNullRow.iTable = pSubst->iNewTable;
+ ifNullRow.flags = EP_Skip;
+ pCopy = &ifNullRow;
+ }
+ testcase( ExprHasProperty(pCopy, EP_Subquery) );
+ pNew = sqlite3ExprDup(db, pCopy, 0);
+ if( pNew && pSubst->isLeftJoin ){
+ ExprSetProperty(pNew, EP_CanBeNull);
+ }
+ if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){
+ pNew->iRightJoinTable = pExpr->iRightJoinTable;
+ ExprSetProperty(pNew, EP_FromJoin);
+ }
+ sqlite3ExprDelete(db, pExpr);
+ pExpr = pNew;
+
+ /* Ensure that the expression now has an implicit collation sequence,
+ ** just as it did when it was a column of a view or sub-query. */
+ if( pExpr ){
+ if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
+ CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
+ pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
+ (pColl ? pColl->zName : "BINARY")
+ );
+ }
+ ExprClearProperty(pExpr, EP_Collate);
+ }
+ }
}
}else{
- pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
- pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
+ if( pExpr->op==TK_IF_NULL_ROW && pExpr->iTable==pSubst->iTable ){
+ pExpr->iTable = pSubst->iNewTable;
+ }
+ pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
+ pExpr->pRight = substExpr(pSubst, pExpr->pRight);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
+ substSelect(pSubst, pExpr->x.pSelect, 1);
}else{
- substExprList(db, pExpr->x.pList, iTable, pEList);
+ substExprList(pSubst, pExpr->x.pList);
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ Window *pWin = pExpr->y.pWin;
+ pWin->pFilter = substExpr(pSubst, pWin->pFilter);
+ substExprList(pSubst, pWin->pPartition);
+ substExprList(pSubst, pWin->pOrderBy);
}
+#endif
}
return pExpr;
}
static void substExprList(
- sqlite3 *db, /* Report malloc errors here */
- ExprList *pList, /* List to scan and in which to make substitutes */
- int iTable, /* Table to be substituted */
- ExprList *pEList /* Substitute values */
+ SubstContext *pSubst, /* Description of the substitution */
+ ExprList *pList /* List to scan and in which to make substitutes */
){
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
- pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
+ pList->a[i].pExpr = substExpr(pSubst, pList->a[i].pExpr);
}
}
static void substSelect(
- sqlite3 *db, /* Report malloc errors here */
- Select *p, /* SELECT statement in which to make substitutions */
- int iTable, /* Table to be replaced */
- ExprList *pEList, /* Substitute values */
- int doPrior /* Do substitutes on p->pPrior too */
+ SubstContext *pSubst, /* Description of the substitution */
+ Select *p, /* SELECT statement in which to make substitutions */
+ int doPrior /* Do substitutes on p->pPrior too */
){
SrcList *pSrc;
struct SrcList_item *pItem;
int i;
if( !p ) return;
do{
- substExprList(db, p->pEList, iTable, pEList);
- substExprList(db, p->pGroupBy, iTable, pEList);
- substExprList(db, p->pOrderBy, iTable, pEList);
- p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
- p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
+ substExprList(pSubst, p->pEList);
+ substExprList(pSubst, p->pGroupBy);
+ substExprList(pSubst, p->pOrderBy);
+ p->pHaving = substExpr(pSubst, p->pHaving);
+ p->pWhere = substExpr(pSubst, p->pWhere);
pSrc = p->pSrc;
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- substSelect(db, pItem->pSelect, iTable, pEList, 1);
+ substSelect(pSubst, pItem->pSelect, 1);
if( pItem->fg.isTabFunc ){
- substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
+ substExprList(pSubst, pItem->u1.pFuncArg);
}
}
}while( doPrior && (p = p->pPrior)!=0 );
@@ -117560,6 +132894,38 @@ static void substSelect(
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
+** pSelect is a SELECT statement and pSrcItem is one item in the FROM
+** clause of that SELECT.
+**
+** This routine scans the entire SELECT statement and recomputes the
+** pSrcItem->colUsed mask.
+*/
+static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){
+ struct SrcList_item *pItem;
+ if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
+ pItem = pWalker->u.pSrcItem;
+ if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue;
+ if( pExpr->iColumn<0 ) return WRC_Continue;
+ pItem->colUsed |= sqlite3ExprColUsed(pExpr);
+ return WRC_Continue;
+}
+static void recomputeColumnsUsed(
+ Select *pSelect, /* The complete SELECT statement */
+ struct SrcList_item *pSrcItem /* Which FROM clause item to recompute */
+){
+ Walker w;
+ if( NEVER(pSrcItem->pTab==0) ) return;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = recomputeColumnsUsedExpr;
+ w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.u.pSrcItem = pSrcItem;
+ pSrcItem->colUsed = 0;
+ sqlite3WalkSelect(&w, pSelect);
+}
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+/*
** This routine attempts to flatten subqueries as a performance optimization.
** This routine returns 1 if it makes changes and 0 if no flattening occurs.
**
@@ -117581,70 +132947,80 @@ static void substSelect(
** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
**
** The code generated for this simplification gives the same result
-** but only has to scan the data once. And because indices might
+** but only has to scan the data once. And because indices might
** exist on the table t1, a complete scan of the data might be
** avoided.
**
-** Flattening is only attempted if all of the following are true:
+** Flattening is subject to the following constraints:
**
-** (1) The subquery and the outer query do not both use aggregates.
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** The subquery and the outer query cannot both be aggregates.
**
-** (2) The subquery is not an aggregate or (2a) the outer query is not a join
-** and (2b) the outer query does not use subqueries other than the one
-** FROM-clause subquery that is a candidate for flattening. (2b is
-** due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** (2) If the subquery is an aggregate then
+** (2a) the outer query must not be a join and
+** (2b) the outer query must not use subqueries
+** other than the one FROM-clause subquery that is a candidate
+** for flattening. (This is due to ticket [2f7170d73bf9abf80]
+** from 2015-02-09.)
**
-** (3) The subquery is not the right operand of a left outer join
-** (Originally ticket #306. Strengthened by ticket #3300)
+** (3) If the subquery is the right operand of a LEFT JOIN then
+** (3a) the subquery may not be a join and
+** (3b) the FROM clause of the subquery may not contain a virtual
+** table and
+** (3c) the outer query may not be an aggregate.
+** (3d) the outer query may not be DISTINCT.
**
-** (4) The subquery is not DISTINCT.
+** (4) The subquery can not be DISTINCT.
**
** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
-** sub-queries that were excluded from this optimization. Restriction
+** sub-queries that were excluded from this optimization. Restriction
** (4) has since been expanded to exclude all DISTINCT subqueries.
**
-** (6) The subquery does not use aggregates or the outer query is not
-** DISTINCT.
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** If the subquery is aggregate, the outer query may not be DISTINCT.
**
-** (7) The subquery has a FROM clause. TODO: For subqueries without
-** A FROM clause, consider adding a FROM close with the special
+** (7) The subquery must have a FROM clause. TODO: For subqueries without
+** A FROM clause, consider adding a FROM clause with the special
** table sqlite_once that consists of a single row containing a
** single NULL.
**
-** (8) The subquery does not use LIMIT or the outer query is not a join.
+** (8) If the subquery uses LIMIT then the outer query may not be a join.
**
-** (9) The subquery does not use LIMIT or the outer query does not use
-** aggregates.
+** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
** accidently carried the comment forward until 2014-09-15. Original
-** text: "The subquery does not use aggregates or the outer query
-** does not use LIMIT."
+** constraint: "If the subquery is aggregate then the outer query
+** may not use LIMIT."
**
-** (11) The subquery and the outer query do not both have ORDER BY clauses.
+** (11) The subquery and the outer query may not both have ORDER BY clauses.
**
** (**) Not implemented. Subsumed into restriction (3). Was previously
** a separate restriction deriving from ticket #350.
**
-** (13) The subquery and outer query do not both use LIMIT.
+** (13) The subquery and outer query may not both use LIMIT.
**
-** (14) The subquery does not use OFFSET.
+** (14) The subquery may not use OFFSET.
**
-** (15) The outer query is not part of a compound select or the
-** subquery does not have a LIMIT clause.
+** (15) If the outer query is part of a compound select, then the
+** subquery may not use LIMIT.
** (See ticket #2339 and ticket [02a8e81d44]).
**
-** (16) The outer query is not an aggregate or the subquery does
-** not contain ORDER BY. (Ticket #2942) This used to not matter
-** until we introduced the group_concat() function.
-**
-** (17) The sub-query is not a compound select, or it is a UNION ALL
-** compound clause made up entirely of non-aggregate queries, and
-** the parent query:
-**
-** * is not itself part of a compound select,
-** * is not an aggregate or DISTINCT query, and
-** * is not a join
+** (16) If the outer query is aggregate, then the subquery may not
+** use ORDER BY. (Ticket #2942) This used to not matter
+** until we introduced the group_concat() function.
+**
+** (17) If the subquery is a compound select, then
+** (17a) all compound operators must be a UNION ALL, and
+** (17b) no terms within the subquery compound may be aggregate
+** or DISTINCT, and
+** (17c) every term within the subquery compound must have a FROM clause
+** (17d) the outer query may not be
+** (17d1) aggregate, or
+** (17d2) DISTINCT, or
+** (17d3) a join.
+** (17e) the subquery may not contain window functions
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -117660,10 +133036,10 @@ static void substSelect(
** syntax error and return a detailed message.
**
** (18) If the sub-query is a compound select, then all terms of the
-** ORDER by clause of the parent must be simple references to
+** ORDER BY clause of the parent must be simple references to
** columns of the sub-query.
**
-** (19) The subquery does not use LIMIT or the outer query does not
+** (19) If the subquery uses LIMIT then the outer query may not
** have a WHERE clause.
**
** (20) If the sub-query is a compound select, then it must not use
@@ -117672,25 +133048,31 @@ static void substSelect(
** appear as unmodified result columns in the outer query. But we
** have other optimizations in mind to deal with that case.
**
-** (21) The subquery does not use LIMIT or the outer query is not
+** (21) If the subquery uses LIMIT then the outer query may not be
** DISTINCT. (See ticket [752e1646fc]).
**
-** (22) The subquery is not a recursive CTE.
+** (22) The subquery may not be a recursive CTE.
**
-** (23) The parent is not a recursive CTE, or the sub-query is not a
-** compound query. This restriction is because transforming the
+** (**) Subsumed into restriction (17d3). Was: If the outer query is
+** a recursive CTE, then the sub-query may not be a compound query.
+** This restriction is because transforming the
** parent to a compound query confuses the code that handles
** recursive queries in multiSelect().
**
-** (24) The subquery is not an aggregate that uses the built-in min() or
+** (**) We no longer attempt to flatten aggregate subqueries. Was:
+** The subquery may not be an aggregate that uses the built-in min() or
** or max() functions. (Without this restriction, a query like:
** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
** return the value X for which Y was maximal.)
**
+** (25) If either the subquery or the parent query contains a window
+** function in the select list or ORDER BY clause, flattening
+** is not attempted.
+**
**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
-** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
+** uses aggregates.
**
** If flattening is not attempted, this routine is a no-op and returns 0.
** If flattening is attempted this routine returns 1.
@@ -117702,8 +133084,7 @@ static int flattenSubquery(
Parse *pParse, /* Parsing context */
Select *p, /* The parent or outer SELECT statement */
int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
- int isAgg, /* True if outer SELECT uses aggregate functions */
- int subqueryIsAgg /* True if the subquery uses aggregate functions */
+ int isAgg /* True if outer SELECT uses aggregate functions */
){
const char *zSavedAuthContext = pParse->zAuthContext;
Select *pParent; /* Current UNION ALL term of the other query */
@@ -117711,17 +133092,19 @@ static int flattenSubquery(
Select *pSub1; /* Pointer to the rightmost select in sub-query */
SrcList *pSrc; /* The FROM clause of the outer query */
SrcList *pSubSrc; /* The FROM clause of the subquery */
- ExprList *pList; /* The result set of the outer query */
int iParent; /* VDBE cursor number of the pSub result set temp table */
+ int iNewParent = -1;/* Replacement table for iParent */
+ int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
int i; /* Loop counter */
Expr *pWhere; /* The WHERE clause */
struct SrcList_item *pSubitem; /* The subquery */
sqlite3 *db = pParse->db;
+ Walker w; /* Walker to persist agginfo data */
/* Check to see if flattening is permitted. Return 0 if not.
*/
assert( p!=0 );
- assert( p->pPrior==0 ); /* Unable to flatten compound queries */
+ assert( p->pPrior==0 );
if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0;
pSrc = p->pSrc;
assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );
@@ -117729,17 +133112,11 @@ static int flattenSubquery(
iParent = pSubitem->iCursor;
pSub = pSubitem->pSelect;
assert( pSub!=0 );
- if( subqueryIsAgg ){
- if( isAgg ) return 0; /* Restriction (1) */
- if( pSrc->nSrc>1 ) return 0; /* Restriction (2a) */
- if( (p->pWhere && ExprHasProperty(p->pWhere,EP_Subquery))
- || (sqlite3ExprListFlags(p->pEList) & EP_Subquery)!=0
- || (sqlite3ExprListFlags(p->pOrderBy) & EP_Subquery)!=0
- ){
- return 0; /* Restriction (2b) */
- }
- }
-
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */
+#endif
+
pSubSrc = pSub->pSrc;
assert( pSubSrc );
/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
@@ -117748,18 +133125,15 @@ static int flattenSubquery(
** became arbitrary expressions, we were forced to add restrictions (13)
** and (14). */
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
- if( pSub->pOffset ) return 0; /* Restriction (14) */
+ if( pSub->pLimit && pSub->pLimit->pRight ) return 0; /* Restriction (14) */
if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
return 0; /* Restriction (15) */
}
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
- if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */
+ if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (4) */
if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
return 0; /* Restrictions (8)(9) */
}
- if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
- return 0; /* Restriction (6) */
- }
if( p->pOrderBy && pSub->pOrderBy ){
return 0; /* Restriction (11) */
}
@@ -117768,19 +133142,14 @@ static int flattenSubquery(
if( pSub->pLimit && (p->selFlags & SF_Distinct)!=0 ){
return 0; /* Restriction (21) */
}
- testcase( pSub->selFlags & SF_Recursive );
- testcase( pSub->selFlags & SF_MinMaxAgg );
- if( pSub->selFlags & (SF_Recursive|SF_MinMaxAgg) ){
- return 0; /* Restrictions (22) and (24) */
- }
- if( (p->selFlags & SF_Recursive) && pSub->pPrior ){
- return 0; /* Restriction (23) */
+ if( pSub->selFlags & (SF_Recursive) ){
+ return 0; /* Restrictions (22) */
}
- /* OBSOLETE COMMENT 1:
- ** Restriction 3: If the subquery is a join, make sure the subquery is
- ** not used as the right operand of an outer join. Examples of why this
- ** is not allowed:
+ /*
+ ** If the subquery is the right operand of a LEFT JOIN, then the
+ ** subquery may not be a join itself (3a). Example of why this is not
+ ** allowed:
**
** t1 LEFT OUTER JOIN (t2 JOIN t3)
**
@@ -117790,56 +133159,63 @@ static int flattenSubquery(
**
** which is not at all the same thing.
**
- ** OBSOLETE COMMENT 2:
- ** Restriction 12: If the subquery is the right operand of a left outer
- ** join, make sure the subquery has no WHERE clause.
- ** An examples of why this is not allowed:
- **
- ** t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
+ ** If the subquery is the right operand of a LEFT JOIN, then the outer
+ ** query cannot be an aggregate. (3c) This is an artifact of the way
+ ** aggregates are processed - there is no mechanism to determine if
+ ** the LEFT JOIN table should be all-NULL.
**
- ** If we flatten the above, we would get
- **
- ** (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
- **
- ** But the t2.x>0 test will always fail on a NULL row of t2, which
- ** effectively converts the OUTER JOIN into an INNER JOIN.
- **
- ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
- ** Ticket #3300 shows that flattening the right term of a LEFT JOIN
- ** is fraught with danger. Best to avoid the whole thing. If the
- ** subquery is the right term of a LEFT JOIN, then do not flatten.
+ ** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
- return 0;
+ isLeftJoin = 1;
+ if( pSubSrc->nSrc>1 /* (3a) */
+ || isAgg /* (3b) */
+ || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */
+ || (p->selFlags & SF_Distinct)!=0 /* (3d) */
+ ){
+ return 0;
+ }
+ }
+#ifdef SQLITE_EXTRA_IFNULLROW
+ else if( iFrom>0 && !isAgg ){
+ /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
+ ** every reference to any result column from subquery in a join, even
+ ** though they are not necessary. This will stress-test the OP_IfNullRow
+ ** opcode. */
+ isLeftJoin = -1;
}
+#endif
- /* Restriction 17: If the sub-query is a compound SELECT, then it must
+ /* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if( pSub->pPrior ){
if( pSub->pOrderBy ){
- return 0; /* Restriction 20 */
+ return 0; /* Restriction (20) */
}
if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
- return 0;
+ return 0; /* (17d1), (17d2), or (17d3) */
}
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
assert( pSub->pSrc!=0 );
assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
- if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0
- || (pSub1->pPrior && pSub1->op!=TK_ALL)
- || pSub1->pSrc->nSrc<1
+ if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
+ || (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
+ || pSub1->pSrc->nSrc<1 /* (17c) */
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ || pSub1->pWin /* (17e) */
+#endif
){
return 0;
}
testcase( pSub1->pSrc->nSrc>1 );
}
- /* Restriction 18. */
+ /* Restriction (18). */
if( p->pOrderBy ){
int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
@@ -117848,9 +133224,17 @@ static int flattenSubquery(
}
}
+ /* Ex-restriction (23):
+ ** The only way that the recursive part of a CTE can contain a compound
+ ** subquery is for the subquery to be one term of a join. But if the
+ ** subquery is a join, then the flattening has already been stopped by
+ ** restriction (17d3)
+ */
+ assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
+
/***** If we reach this point, flattening is permitted. *****/
- SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
- pSub->zSelName, pSub, iFrom));
+ SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
+ pSub->selId, pSub, iFrom));
/* Authorize the subquery */
pParse->zAuthContext = pSubitem->zName;
@@ -117859,13 +133243,13 @@ static int flattenSubquery(
pParse->zAuthContext = zSavedAuthContext;
/* If the sub-query is a compound SELECT statement, then (by restrictions
- ** 17 and 18 above) it must be a UNION ALL and the parent query must
+ ** 17 and 18 above) it must be a UNION ALL and the parent query must
** be of the form:
**
- ** SELECT <expr-list> FROM (<sub-query>) <where-clause>
+ ** SELECT <expr-list> FROM (<sub-query>) <where-clause>
**
** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block
- ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or
+ ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or
** OFFSET clauses and joins them to the left-hand-side of the original
** using UNION ALL operators. In this case N is the number of simple
** select statements in the compound sub-query.
@@ -117895,16 +133279,12 @@ static int flattenSubquery(
Select *pNew;
ExprList *pOrderBy = p->pOrderBy;
Expr *pLimit = p->pLimit;
- Expr *pOffset = p->pOffset;
Select *pPrior = p->pPrior;
p->pOrderBy = 0;
p->pSrc = 0;
p->pPrior = 0;
p->pLimit = 0;
- p->pOffset = 0;
pNew = sqlite3SelectDup(db, p, 0);
- sqlite3SelectSetName(pNew, pSub->zSelName);
- p->pOffset = pOffset;
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->pSrc = pSrc;
@@ -117916,14 +133296,13 @@ static int flattenSubquery(
if( pPrior ) pPrior->pNext = pNew;
pNew->pNext = p;
p->pPrior = pNew;
- SELECTTRACE(2,pParse,p,
- ("compound-subquery flattener creates %s.%p as peer\n",
- pNew->zSelName, pNew));
+ SELECTTRACE(2,pParse,p,("compound-subquery flattener"
+ " creates %u as peer\n",pNew->selId));
}
if( db->mallocFailed ) return 1;
}
- /* Begin flattening the iFrom-th entry of the FROM clause
+ /* Begin flattening the iFrom-th entry of the FROM clause
** in the outer query.
*/
pSub = pSub1 = pSubitem->pSelect;
@@ -117948,12 +133327,12 @@ static int flattenSubquery(
*/
if( ALWAYS(pSubitem->pTab!=0) ){
Table *pTabToDel = pSubitem->pTab;
- if( pTabToDel->nRef==1 ){
+ if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
pTabToDel->pNextZombie = pToplevel->pZombieTab;
pToplevel->pZombieTab = pTabToDel;
}else{
- pTabToDel->nRef--;
+ pTabToDel->nTabRef--;
}
pSubitem->pTab = 0;
}
@@ -117974,6 +133353,7 @@ static int flattenSubquery(
for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
int nSubSrc;
u8 jointype = 0;
+ assert( pSub!=0 );
pSubSrc = pSub->pSrc; /* FROM clause of subquery */
nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */
pSrc = pParent->pSrc; /* FROM clause of the outer query */
@@ -117983,11 +133363,9 @@ static int flattenSubquery(
jointype = pSubitem->fg.jointype;
}else{
assert( pParent!=p ); /* 2nd and subsequent times through the loop */
- pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
- if( pSrc==0 ){
- assert( db->mallocFailed );
- break;
- }
+ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( pSrc==0 ) break;
+ pParent->pSrc = pSrc;
}
/* The subquery uses a single slot of the FROM clause of the outer
@@ -118006,10 +133384,9 @@ static int flattenSubquery(
** for the two elements in the FROM clause of the subquery.
*/
if( nSubSrc>1 ){
- pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1);
- if( db->mallocFailed ){
- break;
- }
+ pSrc = sqlite3SrcListEnlarge(pParse, pSrc, nSubSrc-1,iFrom+1);
+ if( pSrc==0 ) break;
+ pParent->pSrc = pSrc;
}
/* Transfer the FROM clause terms from the subquery into the
@@ -118019,13 +133396,14 @@ static int flattenSubquery(
sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
pSrc->a[i+iFrom] = pSubSrc->a[i];
+ iNewParent = pSubSrc->a[i].iCursor;
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
pSrc->a[iFrom].fg.jointype = jointype;
-
- /* Now begin substituting subquery result set expressions for
+
+ /* Now begin substituting subquery result set expressions for
** references to the iParent in the outer query.
- **
+ **
** Example:
**
** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
@@ -118035,15 +133413,7 @@ static int flattenSubquery(
** We look at every expression in the outer query and every place we see
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
*/
- pList = pParent->pEList;
- for(i=0; i<pList->nExpr; i++){
- if( pList->a[i].zName==0 ){
- char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
- sqlite3Dequote(zName);
- pList->a[i].zName = zName;
- }
- }
- if( pSub->pOrderBy ){
+ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){
/* At this point, any non-zero iOrderByCol values indicate that the
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
@@ -118059,30 +133429,36 @@ static int flattenSubquery(
pOrderBy->a[i].u.x.iOrderByCol = 0;
}
assert( pParent->pOrderBy==0 );
- assert( pSub->pPrior==0 );
pParent->pOrderBy = pOrderBy;
pSub->pOrderBy = 0;
}
- pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
- if( subqueryIsAgg ){
- assert( pParent->pHaving==0 );
- pParent->pHaving = pParent->pWhere;
- pParent->pWhere = pWhere;
- pParent->pHaving = sqlite3ExprAnd(db,
- sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
- );
- assert( pParent->pGroupBy==0 );
- pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
- }else{
- pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
+ pWhere = pSub->pWhere;
+ pSub->pWhere = 0;
+ if( isLeftJoin>0 ){
+ sqlite3SetJoinExpr(pWhere, iNewParent);
}
- substSelect(db, pParent, iParent, pSub->pEList, 0);
-
- /* The flattened query is distinct if either the inner or the
- ** outer query is distinct.
- */
- pParent->selFlags |= pSub->selFlags & SF_Distinct;
-
+ if( pWhere ){
+ if( pParent->pWhere ){
+ pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
+ }else{
+ pParent->pWhere = pWhere;
+ }
+ }
+ if( db->mallocFailed==0 ){
+ SubstContext x;
+ x.pParse = pParse;
+ x.iTable = iParent;
+ x.iNewTable = iNewParent;
+ x.isLeftJoin = isLeftJoin;
+ x.pEList = pSub->pEList;
+ substSelect(&x, pParent, 0);
+ }
+
+ /* The flattened query is a compound if either the inner or the
+ ** outer query is a compound. */
+ pParent->selFlags |= pSub->selFlags & SF_Compound;
+ assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */
+
/*
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
**
@@ -118093,15 +133469,23 @@ static int flattenSubquery(
pParent->pLimit = pSub->pLimit;
pSub->pLimit = 0;
}
+
+ /* Recompute the SrcList_item.colUsed masks for the flattened
+ ** tables. */
+ for(i=0; i<nSubSrc; i++){
+ recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
+ }
}
/* Finially, delete what is left of the subquery and return
** success.
*/
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
+ sqlite3WalkSelect(&w,pSub1);
sqlite3SelectDelete(db, pSub1);
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -118111,7 +133495,189 @@ static int flattenSubquery(
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+/*
+** A structure to keep track of all of the column values that are fixed to
+** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
+*/
+typedef struct WhereConst WhereConst;
+struct WhereConst {
+ Parse *pParse; /* Parsing context */
+ int nConst; /* Number for COLUMN=CONSTANT terms */
+ int nChng; /* Number of times a constant is propagated */
+ Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
+};
+
+/*
+** Add a new entry to the pConst object. Except, do not add duplicate
+** pColumn entires. Also, do not add if doing so would not be appropriate.
+**
+** The caller guarantees the pColumn is a column and pValue is a constant.
+** This routine has to do some additional checks before completing the
+** insert.
+*/
+static void constInsert(
+ WhereConst *pConst, /* The WhereConst into which we are inserting */
+ Expr *pColumn, /* The COLUMN part of the constraint */
+ Expr *pValue, /* The VALUE part of the constraint */
+ Expr *pExpr /* Overall expression: COLUMN=VALUE or VALUE=COLUMN */
+){
+ int i;
+ assert( pColumn->op==TK_COLUMN );
+ assert( sqlite3ExprIsConstant(pValue) );
+
+ if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
+ if( sqlite3ExprAffinity(pValue)!=0 ) return;
+ if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){
+ return;
+ }
+
+ /* 2018-10-25 ticket [cf5ed20f]
+ ** Make sure the same pColumn is not inserted more than once */
+ for(i=0; i<pConst->nConst; i++){
+ const Expr *pE2 = pConst->apExpr[i*2];
+ assert( pE2->op==TK_COLUMN );
+ if( pE2->iTable==pColumn->iTable
+ && pE2->iColumn==pColumn->iColumn
+ ){
+ return; /* Already present. Return without doing anything. */
+ }
+ }
+
+ pConst->nConst++;
+ pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
+ pConst->nConst*2*sizeof(Expr*));
+ if( pConst->apExpr==0 ){
+ pConst->nConst = 0;
+ }else{
+ pConst->apExpr[pConst->nConst*2-2] = pColumn;
+ pConst->apExpr[pConst->nConst*2-1] = pValue;
+ }
+}
+
+/*
+** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE
+** is a constant expression and where the term must be true because it
+** is part of the AND-connected terms of the expression. For each term
+** found, add it to the pConst structure.
+*/
+static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
+ Expr *pRight, *pLeft;
+ if( pExpr==0 ) return;
+ if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
+ if( pExpr->op==TK_AND ){
+ findConstInWhere(pConst, pExpr->pRight);
+ findConstInWhere(pConst, pExpr->pLeft);
+ return;
+ }
+ if( pExpr->op!=TK_EQ ) return;
+ pRight = pExpr->pRight;
+ pLeft = pExpr->pLeft;
+ assert( pRight!=0 );
+ assert( pLeft!=0 );
+ if( pRight->op==TK_COLUMN && sqlite3ExprIsConstant(pLeft) ){
+ constInsert(pConst,pRight,pLeft,pExpr);
+ }
+ if( pLeft->op==TK_COLUMN && sqlite3ExprIsConstant(pRight) ){
+ constInsert(pConst,pLeft,pRight,pExpr);
+ }
+}
+
+/*
+** This is a Walker expression callback. pExpr is a candidate expression
+** to be replaced by a value. If pExpr is equivalent to one of the
+** columns named in pWalker->u.pConst, then overwrite it with its
+** corresponding value.
+*/
+static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
+ int i;
+ WhereConst *pConst;
+ if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
+ if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
+ testcase( ExprHasProperty(pExpr, EP_FixedCol) );
+ testcase( ExprHasProperty(pExpr, EP_FromJoin) );
+ return WRC_Continue;
+ }
+ pConst = pWalker->u.pConst;
+ for(i=0; i<pConst->nConst; i++){
+ Expr *pColumn = pConst->apExpr[i*2];
+ if( pColumn==pExpr ) continue;
+ if( pColumn->iTable!=pExpr->iTable ) continue;
+ if( pColumn->iColumn!=pExpr->iColumn ) continue;
+ /* A match is found. Add the EP_FixedCol property */
+ pConst->nChng++;
+ ExprClearProperty(pExpr, EP_Leaf);
+ ExprSetProperty(pExpr, EP_FixedCol);
+ assert( pExpr->pLeft==0 );
+ pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
+ break;
+ }
+ return WRC_Prune;
+}
+/*
+** The WHERE-clause constant propagation optimization.
+**
+** If the WHERE clause contains terms of the form COLUMN=CONSTANT or
+** CONSTANT=COLUMN that are top-level AND-connected terms that are not
+** part of a ON clause from a LEFT JOIN, then throughout the query
+** replace all other occurrences of COLUMN with CONSTANT.
+**
+** For example, the query:
+**
+** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b
+**
+** Is transformed into
+**
+** SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39
+**
+** Return true if any transformations where made and false if not.
+**
+** Implementation note: Constant propagation is tricky due to affinity
+** and collating sequence interactions. Consider this example:
+**
+** CREATE TABLE t1(a INT,b TEXT);
+** INSERT INTO t1 VALUES(123,'0123');
+** SELECT * FROM t1 WHERE a=123 AND b=a;
+** SELECT * FROM t1 WHERE a=123 AND b=123;
+**
+** The two SELECT statements above should return different answers. b=a
+** is alway true because the comparison uses numeric affinity, but b=123
+** is false because it uses text affinity and '0123' is not the same as '123'.
+** To work around this, the expression tree is not actually changed from
+** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
+** and the "123" value is hung off of the pLeft pointer. Code generator
+** routines know to generate the constant "123" instead of looking up the
+** column value. Also, to avoid collation problems, this optimization is
+** only attempted if the "a=123" term uses the default BINARY collation.
+*/
+static int propagateConstants(
+ Parse *pParse, /* The parsing context */
+ Select *p /* The query in which to propagate constants */
+){
+ WhereConst x;
+ Walker w;
+ int nChng = 0;
+ x.pParse = pParse;
+ do{
+ x.nConst = 0;
+ x.nChng = 0;
+ x.apExpr = 0;
+ findConstInWhere(&x, p->pWhere);
+ if( x.nConst ){
+ memset(&w, 0, sizeof(w));
+ w.pParse = pParse;
+ w.xExprCallback = propagateConstantExprRewrite;
+ w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.xSelectCallback2 = 0;
+ w.walkerDepth = 0;
+ w.u.pConst = &x;
+ sqlite3WalkExpr(&w, p->pWhere);
+ sqlite3DbFree(x.pParse->db, x.apExpr);
+ nChng += x.nChng;
+ }
+ }while( x.nChng );
+ return nChng;
+}
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
@@ -118130,57 +133696,109 @@ static int flattenSubquery(
**
** Do not attempt this optimization if:
**
-** (1) The inner query is an aggregate. (In that case, we'd really want
-** to copy the outer WHERE-clause terms onto the HAVING clause of the
-** inner query. But they probably won't help there so do not bother.)
+** (1) (** This restriction was removed on 2017-09-29. We used to
+** disallow this optimization for aggregate subqueries, but now
+** it is allowed by putting the extra terms on the HAVING clause.
+** The added HAVING clause is pointless if the subquery lacks
+** a GROUP BY clause. But such a HAVING clause is also harmless
+** so there does not appear to be any reason to add extra logic
+** to suppress it. **)
**
** (2) The inner query is the recursive part of a common table expression.
**
** (3) The inner query has a LIMIT clause (since the changes to the WHERE
-** close would change the meaning of the LIMIT).
+** clause would change the meaning of the LIMIT).
**
-** (4) The inner query is the right operand of a LEFT JOIN. (The caller
-** enforces this restriction since this routine does not have enough
-** information to know.)
+** (4) The inner query is the right operand of a LEFT JOIN and the
+** expression to be pushed down does not come from the ON clause
+** on that LEFT JOIN.
**
** (5) The WHERE clause expression originates in the ON or USING clause
-** of a LEFT JOIN.
+** of a LEFT JOIN where iCursor is not the right-hand table of that
+** left join. An example:
+**
+** SELECT *
+** FROM (SELECT 1 AS a1 UNION ALL SELECT 2) AS aa
+** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2)
+** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2);
+**
+** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9).
+** But if the (b2=2) term were to be pushed down into the bb subquery,
+** then the (1,1,NULL) row would be suppressed.
+**
+** (6) The inner query features one or more window-functions (since
+** changes to the WHERE clause of the inner query could change the
+** window over which window functions are calculated).
**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
static int pushDownWhereTerms(
- sqlite3 *db, /* The database connection (for malloc()) */
+ Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
- int iCursor /* Cursor number of the subquery */
+ int iCursor, /* Cursor number of the subquery */
+ int isLeftJoin /* True if pSubq is the right term of a LEFT JOIN */
){
Expr *pNew;
int nChng = 0;
- Select *pX; /* For looping over compound SELECTs in pSubq */
+ Select *pSel;
if( pWhere==0 ) return 0;
- for(pX=pSubq; pX; pX=pX->pPrior){
- if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
- testcase( pX->selFlags & SF_Aggregate );
- testcase( pX->selFlags & SF_Recursive );
- testcase( pX!=pSubq );
- return 0; /* restrictions (1) and (2) */
+ if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ if( pSel->pWin ) return 0; /* restriction (6) */
+ }
+#endif
+
+#ifdef SQLITE_DEBUG
+ /* Only the first term of a compound can have a WITH clause. But make
+ ** sure no other terms are marked SF_Recursive in case something changes
+ ** in the future.
+ */
+ {
+ Select *pX;
+ for(pX=pSubq; pX; pX=pX->pPrior){
+ assert( (pX->selFlags & (SF_Recursive))==0 );
}
}
+#endif
+
if( pSubq->pLimit!=0 ){
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight,
+ iCursor, isLeftJoin);
pWhere = pWhere->pLeft;
}
- if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
+ if( isLeftJoin
+ && (ExprHasProperty(pWhere,EP_FromJoin)==0
+ || pWhere->iRightJoinTable!=iCursor)
+ ){
+ return 0; /* restriction (4) */
+ }
+ if( ExprHasProperty(pWhere,EP_FromJoin) && pWhere->iRightJoinTable!=iCursor ){
+ return 0; /* restriction (5) */
+ }
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
nChng++;
while( pSubq ){
- pNew = sqlite3ExprDup(db, pWhere, 0);
- pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
- pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
+ SubstContext x;
+ pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
+ unsetJoinExpr(pNew, -1);
+ x.pParse = pParse;
+ x.iTable = iCursor;
+ x.iNewTable = iCursor;
+ x.isLeftJoin = 0;
+ x.pEList = pSubq->pEList;
+ pNew = substExpr(&x, pNew);
+ if( pSubq->selFlags & SF_Aggregate ){
+ pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew);
+ }else{
+ pSubq->pWhere = sqlite3ExprAnd(pParse, pSubq->pWhere, pNew);
+ }
pSubq = pSubq->pPrior;
}
}
@@ -118189,48 +133807,55 @@ static int pushDownWhereTerms(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
-** Based on the contents of the AggInfo structure indicated by the first
-** argument, this function checks if the following are true:
+** The pFunc is the only aggregate function in the query. Check to see
+** if the query is a candidate for the min/max optimization.
**
-** * the query contains just a single aggregate function,
-** * the aggregate function is either min() or max(), and
-** * the argument to the aggregate function is a column value.
+** If the query is a candidate for the min/max optimization, then set
+** *ppMinMax to be an ORDER BY clause to be used for the optimization
+** and return either WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX depending on
+** whether pFunc is a min() or max() function.
**
-** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
-** is returned as appropriate. Also, *ppMinMax is set to point to the
-** list of arguments passed to the aggregate before returning.
+** If the query is not a candidate for the min/max optimization, return
+** WHERE_ORDERBY_NORMAL (which must be zero).
**
-** Or, if the conditions above are not met, *ppMinMax is set to 0 and
-** WHERE_ORDERBY_NORMAL is returned.
+** This routine must be called after aggregate functions have been
+** located but before their arguments have been subjected to aggregate
+** analysis.
*/
-static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
- int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
-
- *ppMinMax = 0;
- if( pAggInfo->nFunc==1 ){
- Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */
- ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */
+static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
+ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
+ ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */
+ const char *zFunc; /* Name of aggregate function pFunc */
+ ExprList *pOrderBy;
+ u8 sortFlags = 0;
- assert( pExpr->op==TK_AGG_FUNCTION );
- if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){
- const char *zFunc = pExpr->u.zToken;
- if( sqlite3StrICmp(zFunc, "min")==0 ){
- eRet = WHERE_ORDERBY_MIN;
- *ppMinMax = pEList;
- }else if( sqlite3StrICmp(zFunc, "max")==0 ){
- eRet = WHERE_ORDERBY_MAX;
- *ppMinMax = pEList;
- }
+ assert( *ppMinMax==0 );
+ assert( pFunc->op==TK_AGG_FUNCTION );
+ assert( !IsWindowFunc(pFunc) );
+ if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
+ return eRet;
+ }
+ zFunc = pFunc->u.zToken;
+ if( sqlite3StrICmp(zFunc, "min")==0 ){
+ eRet = WHERE_ORDERBY_MIN;
+ if( sqlite3ExprCanBeNull(pEList->a[0].pExpr) ){
+ sortFlags = KEYINFO_ORDER_BIGNULL;
}
+ }else if( sqlite3StrICmp(zFunc, "max")==0 ){
+ eRet = WHERE_ORDERBY_MAX;
+ sortFlags = KEYINFO_ORDER_DESC;
+ }else{
+ return eRet;
}
-
- assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
+ *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
+ assert( pOrderBy!=0 || db->mallocFailed );
+ if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags;
return eRet;
}
/*
** The select statement passed as the first argument is an aggregate query.
-** The second argument is the associated aggregate-info object. This
+** The second argument is the associated aggregate-info object. This
** function tests if the SELECT is of the form:
**
** SELECT count(*) FROM <tbl>
@@ -118245,7 +133870,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
assert( !p->pGroupBy );
- if( p->pWhere || p->pEList->nExpr!=1
+ if( p->pWhere || p->pEList->nExpr!=1
|| p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect
){
return 0;
@@ -118258,7 +133883,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( NEVER(pAggInfo->nFunc==0) ) return 0;
if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
- if( pExpr->flags&EP_Distinct ) return 0;
+ if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0;
return pTab;
}
@@ -118266,8 +133891,8 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
/*
** If the source-list item passed as an argument was augmented with an
** INDEXED BY clause, then try to locate the specified index. If there
-** was such a clause and the named index cannot be found, return
-** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
+** was such a clause and the named index cannot be found, return
+** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
** pFrom->pIndex and return SQLITE_OK.
*/
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
@@ -118275,8 +133900,8 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pF
Table *pTab = pFrom->pTab;
char *zIndexedBy = pFrom->u1.zIndexedBy;
Index *pIdx;
- for(pIdx=pTab->pIndex;
- pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
+ for(pIdx=pTab->pIndex;
+ pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
pIdx=pIdx->pNext
);
if( !pIdx ){
@@ -118289,7 +133914,7 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pF
return SQLITE_OK;
}
/*
-** Detect compound SELECT statements that use an ORDER BY clause with
+** Detect compound SELECT statements that use an ORDER BY clause with
** an alternative collating sequence.
**
** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ...
@@ -118324,6 +133949,14 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
if( pX==0 ) return WRC_Continue;
a = p->pOrderBy->a;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ /* If iOrderByCol is already non-zero, then it has already been matched
+ ** to a result column of the SELECT statement. This occurs when the
+ ** SELECT is rewritten for window-functions processing and then passed
+ ** to sqlite3SelectPrep() and similar a second time. The rewriting done
+ ** by this function is not required in this case. */
+ if( a[0].u.x.iOrderByCol ) return WRC_Continue;
+#endif
for(i=p->pOrderBy->nExpr-1; i>=0; i--){
if( a[i].pExpr->flags & EP_Collate ) break;
}
@@ -118349,13 +133982,15 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
p->pPrior = 0;
p->pNext = 0;
p->pWith = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ p->pWinDefn = 0;
+#endif
p->selFlags &= ~SF_Compound;
assert( (p->selFlags & SF_Converted)==0 );
p->selFlags |= SF_Converted;
assert( pNew->pPrior!=0 );
pNew->pPrior->pNext = pNew;
pNew->pLimit = 0;
- pNew->pOffset = 0;
return WRC_Continue;
}
@@ -118374,9 +134009,9 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
#ifndef SQLITE_OMIT_CTE
/*
-** Argument pWith (which may be NULL) points to a linked list of nested
-** WITH contexts, from inner to outermost. If the table identified by
-** FROM clause element pItem is really a common-table-expression (CTE)
+** Argument pWith (which may be NULL) points to a linked list of nested
+** WITH contexts, from inner to outermost. If the table identified by
+** FROM clause element pItem is really a common-table-expression (CTE)
** then return a pointer to the CTE definition for that table. Otherwise
** return NULL.
**
@@ -118411,7 +134046,7 @@ static struct Cte *searchWith(
** onto the top of the stack. If argument bFree is true, then this
** WITH clause will never be popped from the stack. In this case it
** should be freed along with the Parse object. In other cases, when
-** bFree==0, the With object will be freed along with the SELECT
+** bFree==0, the With object will be freed along with the SELECT
** statement with which it is associated.
*/
SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
@@ -118425,7 +134060,7 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
}
/*
-** This function checks if argument pFrom refers to a CTE declared by
+** This function checks if argument pFrom refers to a CTE declared by
** a WITH clause on the stack currently maintained by the parser. And,
** if currently processing a CTE expression, if it is a recursive
** reference to the current CTE.
@@ -118440,7 +134075,7 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
** parser and some error code other than SQLITE_OK returned.
*/
static int withExpand(
- Walker *pWalker,
+ Walker *pWalker,
struct SrcList_item *pFrom
){
Parse *pParse = pWalker->pParse;
@@ -118449,6 +134084,9 @@ static int withExpand(
With *pWith; /* WITH clause that pCte belongs to */
assert( pFrom->pTab==0 );
+ if( pParse->nErr ){
+ return SQLITE_ERROR;
+ }
pCte = searchWith(pParse->pWith, pFrom, &pWith);
if( pCte ){
@@ -118472,7 +134110,7 @@ static int withExpand(
assert( pFrom->pTab==0 );
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
@@ -118489,31 +134127,40 @@ static int withExpand(
SrcList *pSrc = pFrom->pSelect->pSrc;
for(i=0; i<pSrc->nSrc; i++){
struct SrcList_item *pItem = &pSrc->a[i];
- if( pItem->zDatabase==0
- && pItem->zName!=0
+ if( pItem->zDatabase==0
+ && pItem->zName!=0
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
){
pItem->pTab = pTab;
pItem->fg.isRecursive = 1;
- pTab->nRef++;
+ pTab->nTabRef++;
pSel->selFlags |= SF_Recursive;
}
}
}
- /* Only one recursive reference is permitted. */
- if( pTab->nRef>2 ){
+ /* Only one recursive reference is permitted. */
+ if( pTab->nTabRef>2 ){
sqlite3ErrorMsg(
pParse, "multiple references to recursive table: %s", pCte->zName
);
return SQLITE_ERROR;
}
- assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
+ assert( pTab->nTabRef==1 ||
+ ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
pCte->zCteErr = "circular reference: %s";
pSavedWith = pParse->pWith;
pParse->pWith = pWith;
- sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
+ if( bMayRecursive ){
+ Select *pPrior = pSel->pPrior;
+ assert( pPrior->pWith==0 );
+ pPrior->pWith = pSel->pWith;
+ sqlite3WalkSelect(pWalker, pPrior);
+ pPrior->pWith = 0;
+ }else{
+ sqlite3WalkSelect(pWalker, pSel);
+ }
pParse->pWith = pWith;
for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior);
@@ -118548,19 +134195,21 @@ static int withExpand(
#ifndef SQLITE_OMIT_CTE
/*
-** If the SELECT passed as the second argument has an associated WITH
+** If the SELECT passed as the second argument has an associated WITH
** clause, pop it from the stack stored as part of the Parse object.
**
** This function is used as the xSelectCallback2() callback by
** sqlite3SelectExpand() when walking a SELECT tree to resolve table
-** names and other FROM clause elements.
+** names and other FROM clause elements.
*/
static void selectPopWith(Walker *pWalker, Select *p){
Parse *pParse = pWalker->pParse;
- With *pWith = findRightmost(p)->pWith;
- if( pWith!=0 ){
- assert( pParse->pWith==pWith );
- pParse->pWith = pWith->pOuter;
+ if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
+ With *pWith = findRightmost(p)->pWith;
+ if( pWith!=0 ){
+ assert( pParse->pWith==pWith || pParse->nErr );
+ pParse->pWith = pWith->pOuter;
+ }
}
}
#else
@@ -118568,13 +134217,42 @@ static void selectPopWith(Walker *pWalker, Select *p){
#endif
/*
+** The SrcList_item structure passed as the second argument represents a
+** sub-query in the FROM clause of a SELECT statement. This function
+** allocates and populates the SrcList_item.pTab object. If successful,
+** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
+** SQLITE_NOMEM.
+*/
+SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
+ Select *pSel = pFrom->pSelect;
+ Table *pTab;
+
+ assert( pSel );
+ pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
+ if( pTab==0 ) return SQLITE_NOMEM;
+ pTab->nTabRef = 1;
+ if( pFrom->zAlias ){
+ pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
+ }else{
+ pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId);
+ }
+ while( pSel->pPrior ){ pSel = pSel->pPrior; }
+ sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
+ pTab->iPKey = -1;
+ pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
+ pTab->tabFlags |= TF_Ephemeral;
+
+ return pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
+}
+
+/*
** This routine is a Walker callback for "expanding" a SELECT statement.
** "Expanding" means to do the following:
**
** (1) Make sure VDBE cursor numbers have been assigned to every
** element of the FROM clause.
**
-** (2) Fill in the pTabList->a[].pTab fields in the SrcList that
+** (2) Fill in the pTabList->a[].pTab fields in the SrcList that
** defines FROM clause. When views appear in the FROM clause,
** fill pTabList->a[].pSelect with a copy of the SELECT statement
** that implements the view. A copy is made of the view's SELECT
@@ -118600,19 +134278,23 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3 *db = pParse->db;
Expr *pE, *pRight, *pExpr;
u16 selFlags = p->selFlags;
+ u32 elistFlags = 0;
p->selFlags |= SF_Expanded;
if( db->mallocFailed ){
return WRC_Abort;
}
- if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
+ assert( p->pSrc!=0 );
+ if( (selFlags & SF_Expanded)!=0 ){
return WRC_Prune;
}
+ if( pWalker->eCode ){
+ /* Renumber selId because it has been copied from a view */
+ p->selId = ++pParse->nSelect;
+ }
pTabList = p->pSrc;
pEList = p->pEList;
- if( pWalker->xSelectCallback2==selectPopWith ){
- sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
- }
+ sqlite3WithPush(pParse, p->pWith, 0);
/* Make sure cursor numbers have been assigned to all entries in
** the FROM clause of the SELECT statement.
@@ -118626,8 +134308,8 @@ static int selectExpander(Walker *pWalker, Select *p){
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab;
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
- if( pFrom->fg.isRecursive ) continue;
- assert( pFrom->pTab==0 );
+ if( pFrom->pTab ) continue;
+ assert( pFrom->fg.isRecursive==0 );
#ifndef SQLITE_OMIT_CTE
if( withExpand(pWalker, pFrom) ) return WRC_Abort;
if( pFrom->pTab ) {} else
@@ -118639,41 +134321,49 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( pSel!=0 );
assert( pFrom->pTab==0 );
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
- pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
- if( pTab==0 ) return WRC_Abort;
- pTab->nRef = 1;
- pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
- while( pSel->pPrior ){ pSel = pSel->pPrior; }
- sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
- pTab->iPKey = -1;
- pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
- pTab->tabFlags |= TF_Ephemeral;
+ if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
#endif
}else{
/* An ordinary table or view name in the FROM clause */
assert( pFrom->pTab==0 );
pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort;
- if( pTab->nRef==0xffff ){
+ if( pTab->nTabRef>=0xffff ){
sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
pTab->zName);
pFrom->pTab = 0;
return WRC_Abort;
}
- pTab->nRef++;
+ pTab->nTabRef++;
if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
return WRC_Abort;
}
-#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
if( IsVirtual(pTab) || pTab->pSelect ){
i16 nCol;
+ u8 eCodeOrig = pWalker->eCode;
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
+ if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
+ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
+ pTab->zName);
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( IsVirtual(pTab)
+ && pFrom->fg.fromDDL
+ && ALWAYS(pTab->pVTable!=0)
+ && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
+ ){
+ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
+ pTab->zName);
+ }
+#endif
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
- sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
nCol = pTab->nCol;
pTab->nCol = -1;
+ pWalker->eCode = 1; /* Turn on Select.selId renumbering */
sqlite3WalkSelect(pWalker, pFrom->pSelect);
+ pWalker->eCode = eCodeOrig;
pTab->nCol = nCol;
}
#endif
@@ -118687,7 +134377,7 @@ static int selectExpander(Walker *pWalker, Select *p){
/* Process NATURAL keywords, and ON and USING clauses of joins.
*/
- if( db->mallocFailed || sqliteProcessJoin(pParse, p) ){
+ if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){
return WRC_Abort;
}
@@ -118708,6 +134398,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( pE->op!=TK_DOT || pE->pRight!=0 );
assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) );
if( pE->op==TK_DOT && pE->pRight->op==TK_ASTERISK ) break;
+ elistFlags |= pE->flags;
}
if( k<pEList->nExpr ){
/*
@@ -118723,6 +134414,7 @@ static int selectExpander(Walker *pWalker, Select *p){
for(k=0; k<pEList->nExpr; k++){
pE = a[k].pExpr;
+ elistFlags |= pE->flags;
pRight = pE->pRight;
assert( pE->op!=TK_DOT || pRight!=0 );
if( pE->op!=TK_ASTERISK
@@ -118732,10 +134424,9 @@ static int selectExpander(Walker *pWalker, Select *p){
*/
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
if( pNew ){
- pNew->a[pNew->nExpr-1].zName = a[k].zName;
- pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan;
- a[k].zName = 0;
- a[k].zSpan = 0;
+ pNew->a[pNew->nExpr-1].zEName = a[k].zEName;
+ pNew->a[pNew->nExpr-1].eEName = a[k].eEName;
+ a[k].zEName = 0;
}
a[k].pExpr = 0;
}else{
@@ -118774,7 +134465,7 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( zName );
if( zTName && pSub
- && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0
+ && sqlite3MatchEName(&pSub->pEList->a[j], 0, zTName, 0)==0
){
continue;
}
@@ -118784,7 +134475,7 @@ static int selectExpander(Walker *pWalker, Select *p){
** bit set.
*/
if( (p->selFlags & SF_IncludeHidden)==0
- && IsHiddenColumn(&pTab->aCol[j])
+ && IsHiddenColumn(&pTab->aCol[j])
){
continue;
}
@@ -118792,9 +134483,9 @@ static int selectExpander(Walker *pWalker, Select *p){
if( i>0 && zTName==0 ){
if( (pFrom->fg.jointype & JT_NATURAL)!=0
- && tableAndColumnIndex(pTabList, i, zName, 0, 0)
+ && tableAndColumnIndex(pTabList, i, zName, 0, 0, 1)
){
- /* In a NATURAL join, omit the join columns from the
+ /* In a NATURAL join, omit the join columns from the
** table to the right of the join */
continue;
}
@@ -118810,10 +134501,10 @@ static int selectExpander(Walker *pWalker, Select *p){
if( longNames || pTabList->nSrc>1 ){
Expr *pLeft;
pLeft = sqlite3Expr(db, TK_ID, zTabName);
- pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
if( zSchemaName ){
pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
- pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr);
}
if( longNames ){
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
@@ -118825,17 +134516,18 @@ static int selectExpander(Walker *pWalker, Select *p){
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
sqlite3TokenInit(&sColname, zColname);
sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
- if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
+ if( pNew && (p->selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
+ sqlite3DbFree(db, pX->zEName);
if( pSub ){
- pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan);
- testcase( pX->zSpan==0 );
+ pX->zEName = sqlite3DbStrDup(db, pSub->pEList->a[j].zEName);
+ testcase( pX->zEName==0 );
}else{
- pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s",
+ pX->zEName = sqlite3MPrintf(db, "%s.%s.%s",
zSchemaName, zTabName, zColname);
- testcase( pX->zSpan==0 );
+ testcase( pX->zEName==0 );
}
- pX->bSpanIsTab = 1;
+ pX->eEName = ENAME_TAB;
}
sqlite3DbFree(db, zToFree);
}
@@ -118852,29 +134544,28 @@ static int selectExpander(Walker *pWalker, Select *p){
sqlite3ExprListDelete(db, pEList);
p->pEList = pNew;
}
-#if SQLITE_MAX_COLUMN
- if( p->pEList && p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
- sqlite3ErrorMsg(pParse, "too many columns in result set");
- return WRC_Abort;
+ if( p->pEList ){
+ if( p->pEList->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){
+ sqlite3ErrorMsg(pParse, "too many columns in result set");
+ return WRC_Abort;
+ }
+ if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){
+ p->selFlags |= SF_ComplexResult;
+ }
}
-#endif
return WRC_Continue;
}
+#if SQLITE_DEBUG
/*
-** No-op routine for the parse-tree walker.
-**
-** When this routine is the Walker.xExprCallback then expression trees
-** are walked without any actions being taken at each node. Presumably,
-** when this routine is used for Walker.xExprCallback then
-** Walker.xSelectCallback is set to do something useful for every
-** subquery in the parser tree.
+** Always assert. This xSelectCallback2 implementation proves that the
+** xSelectCallback2 is never invoked.
*/
-SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
+SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker *NotUsed, Select *NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
- return WRC_Continue;
+ assert( 0 );
}
-
+#endif
/*
** This routine "expands" a SELECT statement and all of its subqueries.
** For additional information on what it means to "expand" a SELECT
@@ -118890,17 +134581,16 @@ SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
*/
static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
Walker w;
- memset(&w, 0, sizeof(w));
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
- if( pParse->hasCompound ){
+ if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){
w.xSelectCallback = convertCompoundSelectToSubquery;
+ w.xSelectCallback2 = 0;
sqlite3WalkSelect(&w, pSelect);
}
w.xSelectCallback = selectExpander;
- if( (pSelect->selFlags & SF_MultiValue)==0 ){
- w.xSelectCallback2 = selectPopWith;
- }
+ w.xSelectCallback2 = selectPopWith;
+ w.eCode = 0;
sqlite3WalkSelect(&w, pSelect);
}
@@ -118926,7 +134616,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
struct SrcList_item *pFrom;
assert( p->selFlags & SF_Resolved );
- assert( (p->selFlags & SF_HasTypeInfo)==0 );
+ if( p->selFlags & SF_HasTypeInfo ) return;
p->selFlags |= SF_HasTypeInfo;
pParse = pWalker->pParse;
pTabList = p->pSrc;
@@ -118938,7 +134628,8 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Select *pSel = pFrom->pSelect;
if( pSel ){
while( pSel->pPrior ) pSel = pSel->pPrior;
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
+ sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel,
+ SQLITE_AFF_NONE);
}
}
}
@@ -118956,7 +134647,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
static void sqlite3SelectAddTypeInfo(Parse *pParse, Select *pSelect){
#ifndef SQLITE_OMIT_SUBQUERY
Walker w;
- memset(&w, 0, sizeof(w));
+ w.xSelectCallback = sqlite3SelectWalkNoop;
w.xSelectCallback2 = selectAddSubqueryTypeInfo;
w.xExprCallback = sqlite3ExprWalkNoop;
w.pParse = pParse;
@@ -118982,15 +134673,13 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
Select *p, /* The SELECT statement being coded. */
NameContext *pOuterNC /* Name context for container */
){
- sqlite3 *db;
- if( NEVER(p==0) ) return;
- db = pParse->db;
- if( db->mallocFailed ) return;
+ assert( p!=0 || pParse->db->mallocFailed );
+ if( pParse->db->mallocFailed ) return;
if( p->selFlags & SF_HasTypeInfo ) return;
sqlite3SelectExpand(pParse, p);
- if( pParse->nErr || db->mallocFailed ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
- if( pParse->nErr || db->mallocFailed ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
sqlite3SelectAddTypeInfo(pParse, p);
}
@@ -119008,6 +134697,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
struct AggInfo_func *pFunc;
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
if( nReg==0 ) return;
+ if( pParse->nErr || pParse->db->mallocFailed ) return;
#ifdef SQLITE_DEBUG
/* Verify that all AggInfo registers are within the range specified by
** AggInfo.mnReg..AggInfo.mxReg */
@@ -119024,14 +134714,14 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
if( pFunc->iDistinct>=0 ){
- Expr *pE = pFunc->pExpr;
+ Expr *pE = pFunc->pFExpr;
assert( !ExprHasProperty(pE, EP_xIsSelect) );
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
"argument");
pFunc->iDistinct = -1;
}else{
- KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO);
}
@@ -119048,18 +134738,24 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pF;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
- ExprList *pList = pF->pExpr->x.pList;
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
- sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
- (void*)pF->pFunc, P4_FUNCDEF);
+ ExprList *pList = pF->pFExpr->x.pList;
+ assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) );
+ sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
+
/*
** Update the accumulator memory cells for an aggregate based on
** the current cursor position.
+**
+** If regAcc is non-zero and there are no min() or max() aggregates
+** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
+** registers if register regAcc contains 0. The caller will take care
+** of setting and clearing regAcc.
*/
-static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
+static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
Vdbe *v = pParse->pVdbe;
int i;
int regHit = 0;
@@ -119072,8 +134768,31 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
int nArg;
int addrNext = 0;
int regAgg;
- ExprList *pList = pF->pExpr->x.pList;
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
+ ExprList *pList = pF->pFExpr->x.pList;
+ assert( !ExprHasProperty(pF->pFExpr, EP_xIsSelect) );
+ assert( !IsWindowFunc(pF->pFExpr) );
+ if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
+ Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
+ if( pAggInfo->nAccumulator
+ && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ && regAcc
+ ){
+ /* If regAcc==0, there there exists some min() or max() function
+ ** without a FILTER clause that will ensure the magnet registers
+ ** are populated. */
+ if( regHit==0 ) regHit = ++pParse->nMem;
+ /* If this is the first row of the group (regAcc contains 0), clear the
+ ** "magnet" register regHit so that the accumulator registers
+ ** are populated if the FILTER clause jumps over the the
+ ** invocation of min() or max() altogether. Or, if this is not
+ ** the first row (regAcc contains 1), set the magnet register so that
+ ** the accumulators are not populated unless the min()/max() is invoked
+ ** and indicates that they should be. */
+ sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
+ }
+ addrNext = sqlite3VdbeMakeLabel(pParse);
+ sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
+ }
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
@@ -119083,7 +134802,9 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
regAgg = 0;
}
if( pF->iDistinct>=0 ){
- addrNext = sqlite3VdbeMakeLabel(v);
+ if( addrNext==0 ){
+ addrNext = sqlite3VdbeMakeLabel(pParse);
+ }
testcase( nArg==0 ); /* Error condition */
testcase( nArg>1 ); /* Also an error */
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
@@ -119102,38 +134823,27 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
- (void*)pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem);
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
- sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
sqlite3VdbeResolveLabel(v, addrNext);
- sqlite3ExprCacheClear(pParse);
}
}
-
- /* Before populating the accumulator registers, clear the column cache.
- ** Otherwise, if any of the required column values are already present
- ** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value
- ** to pC->iMem. But by the time the value is used, the original register
- ** may have been used, invalidating the underlying buffer holding the
- ** text or blob value. See ticket [883034dcb5].
- **
- ** Another solution would be to change the OP_SCopy used to copy cached
- ** values to an OP_Copy.
- */
+ if( regHit==0 && pAggInfo->nAccumulator ){
+ regHit = regAcc;
+ }
if( regHit ){
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
}
- sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
- sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
+ sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem);
}
+
pAggInfo->directMode = 0;
- sqlite3ExprCacheClear(pParse);
if( addrHitTest ){
- sqlite3VdbeJumpHere(v, addrHitTest);
+ sqlite3VdbeJumpHereOrPopInst(v, addrHitTest);
}
}
@@ -119149,14 +134859,11 @@ static void explainSimpleCount(
){
if( pParse->explain==2 ){
int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx)));
- char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s",
+ sqlite3VdbeExplain(pParse, 0, "SCAN TABLE %s%s%s",
pTab->zName,
bCover ? " USING COVERING INDEX " : "",
bCover ? pIdx->zName : ""
);
- sqlite3VdbeAddOp4(
- pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC
- );
}
}
#else
@@ -119164,7 +134871,191 @@ static void explainSimpleCount(
#endif
/*
-** Generate code for the SELECT statement given in the p argument.
+** sqlite3WalkExpr() callback used by havingToWhere().
+**
+** If the node passed to the callback is a TK_AND node, return
+** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
+**
+** Otherwise, return WRC_Prune. In this case, also check if the
+** sub-expression matches the criteria for being moved to the WHERE
+** clause. If so, add it to the WHERE clause and replace the sub-expression
+** within the HAVING expression with a constant "1".
+*/
+static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op!=TK_AND ){
+ Select *pS = pWalker->u.pSelect;
+ if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){
+ sqlite3 *db = pWalker->pParse->db;
+ Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1");
+ if( pNew ){
+ Expr *pWhere = pS->pWhere;
+ SWAP(Expr, *pNew, *pExpr);
+ pNew = sqlite3ExprAnd(pWalker->pParse, pWhere, pNew);
+ pS->pWhere = pNew;
+ pWalker->eCode = 1;
+ }
+ }
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Transfer eligible terms from the HAVING clause of a query, which is
+** processed after grouping, to the WHERE clause, which is processed before
+** grouping. For example, the query:
+**
+** SELECT * FROM <tables> WHERE a=? GROUP BY b HAVING b=? AND c=?
+**
+** can be rewritten as:
+**
+** SELECT * FROM <tables> WHERE a=? AND b=? GROUP BY b HAVING c=?
+**
+** A term of the HAVING expression is eligible for transfer if it consists
+** entirely of constants and expressions that are also GROUP BY terms that
+** use the "BINARY" collation sequence.
+*/
+static void havingToWhere(Parse *pParse, Select *p){
+ Walker sWalker;
+ memset(&sWalker, 0, sizeof(sWalker));
+ sWalker.pParse = pParse;
+ sWalker.xExprCallback = havingToWhereExprCb;
+ sWalker.u.pSelect = p;
+ sqlite3WalkExpr(&sWalker, p->pHaving);
+#if SELECTTRACE_ENABLED
+ if( sWalker.eCode && (sqlite3_unsupported_selecttrace & 0x100)!=0 ){
+ SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+}
+
+/*
+** Check to see if the pThis entry of pTabList is a self-join of a prior view.
+** If it is, then return the SrcList_item for the prior view. If it is not,
+** then return 0.
+*/
+static struct SrcList_item *isSelfJoinView(
+ SrcList *pTabList, /* Search for self-joins in this FROM clause */
+ struct SrcList_item *pThis /* Search for prior reference to this subquery */
+){
+ struct SrcList_item *pItem;
+ for(pItem = pTabList->a; pItem<pThis; pItem++){
+ Select *pS1;
+ if( pItem->pSelect==0 ) continue;
+ if( pItem->fg.viaCoroutine ) continue;
+ if( pItem->zName==0 ) continue;
+ assert( pItem->pTab!=0 );
+ assert( pThis->pTab!=0 );
+ if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue;
+ if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue;
+ pS1 = pItem->pSelect;
+ if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){
+ /* The query flattener left two different CTE tables with identical
+ ** names in the same FROM clause. */
+ continue;
+ }
+ if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1)
+ || sqlite3ExprCompare(0, pThis->pSelect->pHaving, pS1->pHaving, -1)
+ ){
+ /* The view was modified by some other optimization such as
+ ** pushDownWhereTerms() */
+ continue;
+ }
+ return pItem;
+ }
+ return 0;
+}
+
+#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
+/*
+** Attempt to transform a query of the form
+**
+** SELECT count(*) FROM (SELECT x FROM t1 UNION ALL SELECT y FROM t2)
+**
+** Into this:
+**
+** SELECT (SELECT count(*) FROM t1)+(SELECT count(*) FROM t2)
+**
+** The transformation only works if all of the following are true:
+**
+** * The subquery is a UNION ALL of two or more terms
+** * The subquery does not have a LIMIT clause
+** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
+** * The outer query is a simple count(*) with no WHERE clause or other
+** extraneous syntax.
+**
+** Return TRUE if the optimization is undertaken.
+*/
+static int countOfViewOptimization(Parse *pParse, Select *p){
+ Select *pSub, *pPrior;
+ Expr *pExpr;
+ Expr *pCount;
+ sqlite3 *db;
+ if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
+ if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
+ if( p->pWhere ) return 0;
+ if( p->pGroupBy ) return 0;
+ pExpr = p->pEList->a[0].pExpr;
+ if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
+ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
+ if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
+ if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
+ pSub = p->pSrc->a[0].pSelect;
+ if( pSub==0 ) return 0; /* The FROM is a subquery */
+ if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
+ do{
+ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
+ if( pSub->pWhere ) return 0; /* No WHERE clause */
+ if( pSub->pLimit ) return 0; /* No LIMIT clause */
+ if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
+ pSub = pSub->pPrior; /* Repeat over compound */
+ }while( pSub );
+
+ /* If we reach this point then it is OK to perform the transformation */
+
+ db = pParse->db;
+ pCount = pExpr;
+ pExpr = 0;
+ pSub = p->pSrc->a[0].pSelect;
+ p->pSrc->a[0].pSelect = 0;
+ sqlite3SrcListDelete(db, p->pSrc);
+ p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc));
+ while( pSub ){
+ Expr *pTerm;
+ pPrior = pSub->pPrior;
+ pSub->pPrior = 0;
+ pSub->pNext = 0;
+ pSub->selFlags |= SF_Aggregate;
+ pSub->selFlags &= ~SF_Compound;
+ pSub->nSelectRow = 0;
+ sqlite3ExprListDelete(db, pSub->pEList);
+ pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
+ pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
+ pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, pTerm, pSub);
+ if( pExpr==0 ){
+ pExpr = pTerm;
+ }else{
+ pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr);
+ }
+ pSub = pPrior;
+ }
+ p->pEList->a[0].pExpr = pExpr;
+ p->selFlags &= ~SF_Aggregate;
+
+#if SELECTTRACE_ENABLED
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
+ SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+ return 1;
+}
+#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
+
+/*
+** Generate code for the SELECT statement given in the p argument.
**
** The results are returned according to the SelectDest structure.
** See comments in sqliteInt.h for further information.
@@ -119190,28 +135081,24 @@ SQLITE_PRIVATE int sqlite3Select(
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
+ AggInfo *pAggInfo = 0; /* Aggregate information */
int rc = 1; /* Value to return from this function */
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
SortCtx sSort; /* Info on how to code the ORDER BY clause */
- AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
-
-#ifndef SQLITE_OMIT_EXPLAIN
- int iRestoreSelectId = pParse->iSelectId;
- pParse->iSelectId = pParse->iNextSelectId++;
-#endif
+ ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
+ u8 minMaxFlag; /* Flag for min/max queries */
db = pParse->db;
+ v = sqlite3GetVdbe(pParse);
if( p==0 || db->mallocFailed || pParse->nErr ){
return 1;
}
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
- memset(&sAggInfo, 0, sizeof(sAggInfo));
#if SELECTTRACE_ENABLED
- pParse->nSelectIndent++;
- SELECTTRACE(1,pParse,p, ("begin processing:\n"));
- if( sqlite3SelectTrace & 0x100 ){
+ SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -119221,7 +135108,7 @@ SQLITE_PRIVATE int sqlite3Select(
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
if( IgnorableOrderby(pDest) ){
- assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
+ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
@@ -119230,31 +135117,88 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3ExprListDelete(db, p->pOrderBy);
p->pOrderBy = 0;
p->selFlags &= ~SF_Distinct;
+ p->selFlags |= SF_NoopOrderBy;
}
sqlite3SelectPrep(pParse, p, 0);
- memset(&sSort, 0, sizeof(sSort));
- sSort.pOrderBy = p->pOrderBy;
- pTabList = p->pSrc;
if( pParse->nErr || db->mallocFailed ){
goto select_end;
}
assert( p->pEList!=0 );
- isAgg = (p->selFlags & SF_Aggregate)!=0;
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p, ("after name resolution:\n"));
+ if( sqlite3_unsupported_selecttrace & 0x104 ){
+ SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+
+ /* If the SF_UpdateFrom flag is set, then this function is being called
+ ** as part of populating the temp table for an UPDATE...FROM statement.
+ ** In this case, it is an error if the target object (pSrc->a[0]) name
+ ** or alias is duplicated within FROM clause (pSrc->a[1..n]). */
+ if( p->selFlags & SF_UpdateFrom ){
+ struct SrcList_item *p0 = &p->pSrc->a[0];
+ for(i=1; i<p->pSrc->nSrc; i++){
+ struct SrcList_item *p1 = &p->pSrc->a[i];
+ if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
+ sqlite3ErrorMsg(pParse,
+ "target object/alias may not appear in FROM clause: %s",
+ p0->zAlias ? p0->zAlias : p0->pTab->zName
+ );
+ goto select_end;
+ }
+ }
+ }
+
+ if( pDest->eDest==SRT_Output ){
+ generateColumnNames(pParse, p);
+ }
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ rc = sqlite3WindowRewrite(pParse, p);
+ if( rc ){
+ assert( db->mallocFailed || pParse->nErr>0 );
+ goto select_end;
+ }
+#if SELECTTRACE_ENABLED
+ if( p->pWin && (sqlite3_unsupported_selecttrace & 0x108)!=0 ){
+ SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+ pTabList = p->pSrc;
+ isAgg = (p->selFlags & SF_Aggregate)!=0;
+ memset(&sSort, 0, sizeof(sSort));
+ sSort.pOrderBy = p->pOrderBy;
- /* Try to flatten subqueries in the FROM clause up into the main query
+ /* Try to do various optimizations (flattening subqueries, and strength
+ ** reduction of join operators) in the FROM clause up into the main query
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
Select *pSub = pItem->pSelect;
- int isAggSub;
Table *pTab = pItem->pTab;
+
+ /* The expander should have already created transient Table objects
+ ** even for FROM clause elements such as subqueries that do not correspond
+ ** to a real table */
+ assert( pTab!=0 );
+
+ /* Convert LEFT JOIN into JOIN if there are terms of the right table
+ ** of the LEFT JOIN used in the WHERE clause.
+ */
+ if( (pItem->fg.jointype & JT_LEFT)!=0
+ && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
+ && OptimizationEnabled(db, SQLITE_SimplifyJoin)
+ ){
+ SELECTTRACE(0x100,pParse,p,
+ ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pItem->iCursor);
+ }
+
+ /* No futher action if this term of the FROM clause is no a subquery */
if( pSub==0 ) continue;
/* Catch mismatch in the declared columns of a view and the number of
@@ -119265,13 +135209,46 @@ SQLITE_PRIVATE int sqlite3Select(
goto select_end;
}
- isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
- if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
+ /* Do not try to flatten an aggregate subquery.
+ **
+ ** Flattening an aggregate subquery is only possible if the outer query
+ ** is not a join. But if the outer query is not a join, then the subquery
+ ** will be implemented as a co-routine and there is no advantage to
+ ** flattening in that case.
+ */
+ if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
+ assert( pSub->pGroupBy==0 );
+
+ /* If the outer query contains a "complex" result set (that is,
+ ** if the result set of the outer query uses functions or subqueries)
+ ** and if the subquery contains an ORDER BY clause and if
+ ** it will be implemented as a co-routine, then do not flatten. This
+ ** restriction allows SQL constructs like this:
+ **
+ ** SELECT expensive_function(x)
+ ** FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
+ **
+ ** The expensive_function() is only computed on the 10 rows that
+ ** are output, rather than every row of the table.
+ **
+ ** The requirement that the outer query have a complex result set
+ ** means that flattening does occur on simpler SQL constraints without
+ ** the expensive_function() like:
+ **
+ ** SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10);
+ */
+ if( pSub->pOrderBy!=0
+ && i==0
+ && (p->selFlags & SF_ComplexResult)!=0
+ && (pTabList->nSrc==1
+ || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
+ ){
+ continue;
+ }
+
+ if( flattenSubquery(pParse, p, i, isAgg) ){
+ if( pParse->nErr ) goto select_end;
/* This subquery can be absorbed into its parent. */
- if( isAggSub ){
- isAgg = 1;
- p->selFlags |= SF_Aggregate;
- }
i = -1;
}
pTabList = p->pSrc;
@@ -119282,48 +135259,104 @@ SQLITE_PRIVATE int sqlite3Select(
}
#endif
- /* Get a pointer the VDBE under construction, allocating a new VDBE if one
- ** does not already exist */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto select_end;
-
#ifndef SQLITE_OMIT_COMPOUND_SELECT
/* Handle compound SELECT statements using the separate multiSelect()
** procedure.
*/
if( p->pPrior ){
rc = multiSelect(pParse, p, pDest);
- explainSetInteger(pParse->iSelectId, iRestoreSelectId);
#if SELECTTRACE_ENABLED
- SELECTTRACE(1,pParse,p,("end compound-select processing\n"));
- pParse->nSelectIndent--;
+ SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
+ if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ sqlite3TreeViewSelect(0, p, 0);
+ }
#endif
+ if( p->pNext==0 ) ExplainQueryPlanPop(pParse);
return rc;
}
#endif
- /* Generate code for all sub-queries in the FROM clause
+ /* Do the WHERE-clause constant propagation optimization if this is
+ ** a join. No need to speed time on this operation for non-join queries
+ ** as the equivalent optimization will be handled by query planner in
+ ** sqlite3WhereBegin().
+ */
+ if( pTabList->nSrc>1
+ && OptimizationEnabled(db, SQLITE_PropagateConst)
+ && propagateConstants(pParse, p)
+ ){
+#if SELECTTRACE_ENABLED
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
+ SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+ }else{
+ SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n"));
+ }
+
+#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
+ if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
+ && countOfViewOptimization(pParse, p)
+ ){
+ if( db->mallocFailed ) goto select_end;
+ pEList = p->pEList;
+ pTabList = p->pSrc;
+ }
+#endif
+
+ /* For each term in the FROM clause, do two things:
+ ** (1) Authorized unreferenced tables
+ ** (2) Generate code for all sub-queries
*/
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
for(i=0; i<pTabList->nSrc; i++){
struct SrcList_item *pItem = &pTabList->a[i];
SelectDest dest;
- Select *pSub = pItem->pSelect;
- if( pSub==0 ) continue;
+ Select *pSub;
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+ const char *zSavedAuthContext;
+#endif
- /* Sometimes the code for a subquery will be generated more than
- ** once, if the subquery is part of the WHERE clause in a LEFT JOIN,
- ** for example. In that case, do not regenerate the code to manifest
- ** a view or the co-routine to implement a view. The first instance
- ** is sufficient, though the subroutine to manifest the view does need
- ** to be invoked again. */
- if( pItem->addrFillSub ){
- if( pItem->fg.viaCoroutine==0 ){
- sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
- }
- continue;
+ /* Issue SQLITE_READ authorizations with a fake column name for any
+ ** tables that are referenced but from which no values are extracted.
+ ** Examples of where these kinds of null SQLITE_READ authorizations
+ ** would occur:
+ **
+ ** SELECT count(*) FROM t1; -- SQLITE_READ t1.""
+ ** SELECT t1.* FROM t1, t2; -- SQLITE_READ t2.""
+ **
+ ** The fake column name is an empty string. It is possible for a table to
+ ** have a column named by the empty string, in which case there is no way to
+ ** distinguish between an unreferenced table and an actual reference to the
+ ** "" column. The original design was for the fake column name to be a NULL,
+ ** which would be unambiguous. But legacy authorization callbacks might
+ ** assume the column name is non-NULL and segfault. The use of an empty
+ ** string for the fake column name seems safer.
+ */
+ if( pItem->colUsed==0 && pItem->zName!=0 ){
+ sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase);
}
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+ /* Generate code for all sub-queries in the FROM clause
+ */
+ pSub = pItem->pSelect;
+ if( pSub==0 ) continue;
+
+ /* The code for a subquery should only be generated once, though it is
+ ** technically harmless for it to be generated multiple times. The
+ ** following assert() will detect if something changes to cause
+ ** the same subquery to be coded multiple times, as a signal to the
+ ** developers to try to optimize the situation.
+ **
+ ** Update 2019-07-24:
+ ** See ticket https://sqlite.org/src/tktview/c52b09c7f38903b1311cec40.
+ ** The dbsqlfuzz fuzzer found a case where the same subquery gets
+ ** coded twice. So this assert() now becomes a testcase(). It should
+ ** be very rare, though.
+ */
+ testcase( pItem->addrFillSub!=0 );
+
/* Increment Parse.nHeight by the height of the largest expression
** tree referred to by this, the parent select. The child select
** may contain expression trees of at most
@@ -119336,27 +135369,29 @@ SQLITE_PRIVATE int sqlite3Select(
/* Make copies of constant WHERE-clause terms in the outer query down
** inside the subquery. This can help the subquery to run more efficiently.
*/
- if( (pItem->fg.jointype & JT_OUTER)==0
- && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
+ if( OptimizationEnabled(db, SQLITE_PushDown)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
+ (pItem->fg.jointype & JT_OUTER)!=0)
){
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
+ if( sqlite3_unsupported_selecttrace & 0x100 ){
+ SELECTTRACE(0x100,pParse,p,
+ ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
+ }else{
+ SELECTTRACE(0x100,pParse,p,("Push-down not possible\n"));
}
+ zSavedAuthContext = pParse->zAuthContext;
+ pParse->zAuthContext = pItem->zName;
+
/* Generate code to implement the subquery
**
- ** The subquery is implemented as a co-routine if all of these are true:
- ** (1) The subquery is guaranteed to be the outer loop (so that it
- ** does not need to be computed more than once)
- ** (2) The ALL keyword after SELECT is omitted. (Applications are
- ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
- ** the use of co-routines.)
- ** (3) Co-routines are not disabled using sqlite3_test_control()
- ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
+ ** The subquery is implemented as a co-routine if the subquery is
+ ** guaranteed to be the outer loop (so that it does not need to be
+ ** computed more than once)
**
** TODO: Are there other reasons beside (1) to use a co-routine
** implementation?
@@ -119364,19 +135399,18 @@ SQLITE_PRIVATE int sqlite3Select(
if( i==0
&& (pTabList->nSrc==1
|| (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
- && (p->selFlags & SF_All)==0 /* (2) */
- && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
*/
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
+
pItem->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
VdbeComment((v, "%s", pItem->pTab->zName));
pItem->addrFillSub = addrTop;
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
- explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
+ ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId));
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1;
@@ -119393,7 +135427,9 @@ SQLITE_PRIVATE int sqlite3Select(
int topAddr;
int onceAddr = 0;
int retAddr;
- assert( pItem->addrFillSub==0 );
+ struct SrcList_item *pPrior;
+
+ testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
pItem->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
pItem->addrFillSub = topAddr+1;
@@ -119406,9 +135442,16 @@ SQLITE_PRIVATE int sqlite3Select(
}else{
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
}
- sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
- explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
- sqlite3Select(pParse, pSub, &dest);
+ pPrior = isSelfJoinView(pTabList, pItem);
+ if( pPrior ){
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
+ assert( pPrior->pSelect!=0 );
+ pSub->nSelectRow = pPrior->pSelect->nSelectRow;
+ }else{
+ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
+ ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
+ sqlite3Select(pParse, pSub, &dest);
+ }
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
@@ -119418,8 +135461,9 @@ SQLITE_PRIVATE int sqlite3Select(
}
if( db->mallocFailed ) goto select_end;
pParse->nHeight -= sqlite3SelectExprHeight(p);
- }
+ pParse->zAuthContext = zSavedAuthContext;
#endif
+ }
/* Various elements of the SELECT copied into local variables for
** convenience */
@@ -119430,13 +135474,13 @@ SQLITE_PRIVATE int sqlite3Select(
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
- /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
+ /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
** if the select-list is the same as the ORDER BY list, then this query
** can be rewritten as a GROUP BY. In other words, this:
**
@@ -119446,23 +135490,27 @@ SQLITE_PRIVATE int sqlite3Select(
**
** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
**
- ** The second form is preferred as a single index (or temp-table) may be
- ** used for both the ORDER BY and DISTINCT processing. As originally
- ** written the query must use a temp-table for at least one of the ORDER
+ ** The second form is preferred as a single index (or temp-table) may be
+ ** used for both the ORDER BY and DISTINCT processing. As originally
+ ** written the query must use a temp-table for at least one of the ORDER
** BY and DISTINCT, and an index or separate temp-table for the other.
*/
- if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
+ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ && p->pWin==0
+#endif
){
p->selFlags &= ~SF_Distinct;
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
+ p->selFlags |= SF_Aggregate;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
assert( sDistinct.isTnct );
#if SELECTTRACE_ENABLED
- if( sqlite3SelectTrace & 0x400 ){
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
@@ -119479,7 +135527,8 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
- pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
+ pKeyInfo = sqlite3KeyInfoFromExprList(
+ pParse, sSort.pOrderBy, 0, pEList->nExpr);
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
@@ -119498,8 +135547,10 @@ SQLITE_PRIVATE int sqlite3Select(
/* Set the limiter.
*/
- iEnd = sqlite3VdbeMakeLabel(v);
- p->nSelectRow = 320; /* 4 billion rows */
+ iEnd = sqlite3VdbeMakeLabel(pParse);
+ if( (p->selFlags & SF_FixedLimit)==0 ){
+ p->nSelectRow = 320; /* 4 billion rows */
+ }
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
@@ -119511,9 +135562,9 @@ SQLITE_PRIVATE int sqlite3Select(
if( p->selFlags & SF_Distinct ){
sDistinct.tabTnct = pParse->nTab++;
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
- sDistinct.tabTnct, 0, 0,
- (char*)keyInfoFromExprList(pParse, p->pEList,0,0),
- P4_KEYINFO);
+ sDistinct.tabTnct, 0, 0,
+ (char*)sqlite3KeyInfoFromExprList(pParse, p->pEList,0,0),
+ P4_KEYINFO);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
}else{
@@ -119522,11 +135573,19 @@ SQLITE_PRIVATE int sqlite3Select(
if( !isAgg && pGroupBy==0 ){
/* No aggregate functions and no GROUP BY clause */
- u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
+ u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
+ | (p->selFlags & SF_FixedLimit);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ Window *pWin = p->pWin; /* Main window object (or NULL) */
+ if( pWin ){
+ sqlite3WindowCodeInit(pParse, p);
+ }
+#endif
assert( WHERE_USE_LIMIT==SF_FixedLimit );
- wctrlFlags |= p->selFlags & SF_FixedLimit;
+
/* Begin the database scan. */
+ SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, wctrlFlags, p->nSelectRow);
if( pWInfo==0 ) goto select_end;
@@ -119538,13 +135597,13 @@ SQLITE_PRIVATE int sqlite3Select(
}
if( sSort.pOrderBy ){
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
- sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
+ sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo);
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
sSort.pOrderBy = 0;
}
}
- /* If sorting index that was created by a prior OP_OpenEphemeral
+ /* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
** into an OP_Noop.
*/
@@ -119552,14 +135611,37 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
}
- /* Use the standard inner loop. */
- selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
- sqlite3WhereContinueLabel(pWInfo),
- sqlite3WhereBreakLabel(pWInfo));
+ assert( p->pEList==pEList );
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pWin ){
+ int addrGosub = sqlite3VdbeMakeLabel(pParse);
+ int iCont = sqlite3VdbeMakeLabel(pParse);
+ int iBreak = sqlite3VdbeMakeLabel(pParse);
+ int regGosub = ++pParse->nMem;
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
+ sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub);
+
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+ sqlite3VdbeResolveLabel(v, addrGosub);
+ VdbeNoopComment((v, "inner-loop subroutine"));
+ sSort.labelOBLopt = 0;
+ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak);
+ sqlite3VdbeResolveLabel(v, iCont);
+ sqlite3VdbeAddOp1(v, OP_Return, regGosub);
+ VdbeComment((v, "end inner-loop subroutine"));
+ sqlite3VdbeResolveLabel(v, iBreak);
+ }else
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+ {
+ /* Use the standard inner loop. */
+ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
+ sqlite3WhereContinueLabel(pWInfo),
+ sqlite3WhereBreakLabel(pWInfo));
+
+ /* End the database scan loop.
+ */
+ sqlite3WhereEnd(pWInfo);
+ }
}else{
/* This case when there exist aggregate functions or a GROUP BY clause
** or both */
@@ -119591,51 +135673,108 @@ SQLITE_PRIVATE int sqlite3Select(
}
assert( 66==sqlite3LogEst(100) );
if( p->nSelectRow>66 ) p->nSelectRow = 66;
+
+ /* If there is both a GROUP BY and an ORDER BY clause and they are
+ ** identical, then it may be possible to disable the ORDER BY clause
+ ** on the grounds that the GROUP BY will cause elements to come out
+ ** in the correct order. It also may not - the GROUP BY might use a
+ ** database index that causes rows to be grouped together as required
+ ** but not actually sorted. Either way, record the fact that the
+ ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
+ ** variable. */
+ if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){
+ int ii;
+ /* The GROUP BY processing doesn't care whether rows are delivered in
+ ** ASC or DESC order - only that each group is returned contiguously.
+ ** So set the ASC/DESC flags in the GROUP BY to match those in the
+ ** ORDER BY to maximize the chances of rows being delivered in an
+ ** order that makes the ORDER BY redundant. */
+ for(ii=0; ii<pGroupBy->nExpr; ii++){
+ u8 sortFlags = sSort.pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_DESC;
+ pGroupBy->a[ii].sortFlags = sortFlags;
+ }
+ if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
+ orderByGrp = 1;
+ }
+ }
}else{
assert( 0==sqlite3LogEst(1) );
p->nSelectRow = 0;
}
- /* If there is both a GROUP BY and an ORDER BY clause and they are
- ** identical, then it may be possible to disable the ORDER BY clause
- ** on the grounds that the GROUP BY will cause elements to come out
- ** in the correct order. It also may not - the GROUP BY might use a
- ** database index that causes rows to be grouped together as required
- ** but not actually sorted. Either way, record the fact that the
- ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
- ** variable. */
- if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
- orderByGrp = 1;
- }
-
/* Create a label to jump to when we want to abort the query */
- addrEnd = sqlite3VdbeMakeLabel(v);
+ addrEnd = sqlite3VdbeMakeLabel(pParse);
/* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
** SELECT statement.
*/
+ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
+ if( pAggInfo==0 ){
+ goto select_end;
+ }
+ pAggInfo->pNext = pParse->pAggList;
+ pParse->pAggList = pAggInfo;
+ pAggInfo->selId = p->selId;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
- sNC.pAggInfo = &sAggInfo;
- sAggInfo.mnReg = pParse->nMem+1;
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
- sAggInfo.pGroupBy = pGroupBy;
+ sNC.uNC.pAggInfo = pAggInfo;
+ VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
+ pAggInfo->mnReg = pParse->nMem+1;
+ pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
+ pAggInfo->pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
if( pHaving ){
+ if( pGroupBy ){
+ assert( pWhere==p->pWhere );
+ assert( pHaving==p->pHaving );
+ assert( pGroupBy==p->pGroupBy );
+ havingToWhere(pParse, p);
+ pWhere = p->pWhere;
+ }
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
- sAggInfo.nAccumulator = sAggInfo.nColumn;
- for(i=0; i<sAggInfo.nFunc; i++){
- assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) );
+ pAggInfo->nAccumulator = pAggInfo->nColumn;
+ if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
+ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy);
+ }else{
+ minMaxFlag = WHERE_ORDERBY_NORMAL;
+ }
+ for(i=0; i<pAggInfo->nFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
sNC.ncFlags |= NC_InAggFunc;
- sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList);
+ sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ assert( !IsWindowFunc(pExpr) );
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter);
+ }
+#endif
sNC.ncFlags &= ~NC_InAggFunc;
}
- sAggInfo.mxReg = pParse->nMem;
+ pAggInfo->mxReg = pParse->nMem;
if( db->mallocFailed ) goto select_end;
+#if SELECTTRACE_ENABLED
+ if( sqlite3_unsupported_selecttrace & 0x400 ){
+ int ii;
+ SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
+ sqlite3TreeViewSelect(0, p, 0);
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
+ sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
+ ii, pAggInfo->aCol[ii].iMem);
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
+ }
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
+ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
+ ii, pAggInfo->aFunc[ii].iMem);
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
+ }
+ }
+#endif
+
/* Processing for aggregates with GROUP BY is very different and
** much more complex than aggregates without a GROUP BY.
@@ -119654,12 +135793,13 @@ SQLITE_PRIVATE int sqlite3Select(
/* If there is a GROUP BY clause we might need a sorting index to
** implement it. Allocate that sorting index now. If it turns out
** that we do not need it after all, the OP_SorterOpen instruction
- ** will be converted into a Noop.
+ ** will be converted into a Noop.
*/
- sAggInfo.sortingIdx = pParse->nTab++;
- pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
- addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
- sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
+ pAggInfo->sortingIdx = pParse->nTab++;
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
+ 0, pAggInfo->nColumn);
+ addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
+ pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
/* Initialize memory locations used by GROUP BY aggregate processing
@@ -119667,17 +135807,15 @@ SQLITE_PRIVATE int sqlite3Select(
iUseFlag = ++pParse->nMem;
iAbortFlag = ++pParse->nMem;
regOutputRow = ++pParse->nMem;
- addrOutputRow = sqlite3VdbeMakeLabel(v);
+ addrOutputRow = sqlite3VdbeMakeLabel(pParse);
regReset = ++pParse->nMem;
- addrReset = sqlite3VdbeMakeLabel(v);
+ addrReset = sqlite3VdbeMakeLabel(pParse);
iAMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
iBMem = pParse->nMem + 1;
pParse->nMem += pGroupBy->nExpr;
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
VdbeComment((v, "clear abort flag"));
- sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
- VdbeComment((v, "indicate accumulator empty"));
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
/* Begin a loop that will extract all source rows in GROUP BY order.
@@ -119686,6 +135824,7 @@ SQLITE_PRIVATE int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
+ SELECTTRACE(1,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0
);
@@ -119707,7 +135846,7 @@ SQLITE_PRIVATE int sqlite3Select(
int nCol;
int nGroupBy;
- explainTempTable(pParse,
+ explainTempTable(pParse,
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
"DISTINCT" : "GROUP BY");
@@ -119715,39 +135854,36 @@ SQLITE_PRIVATE int sqlite3Select(
nGroupBy = pGroupBy->nExpr;
nCol = nGroupBy;
j = nGroupBy;
- for(i=0; i<sAggInfo.nColumn; i++){
- if( sAggInfo.aCol[i].iSorterColumn>=j ){
+ for(i=0; i<pAggInfo->nColumn; i++){
+ if( pAggInfo->aCol[i].iSorterColumn>=j ){
nCol++;
j++;
}
}
regBase = sqlite3GetTempRange(pParse, nCol);
- sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
- for(i=0; i<sAggInfo.nColumn; i++){
- struct AggInfo_col *pCol = &sAggInfo.aCol[i];
+ for(i=0; i<pAggInfo->nColumn; i++){
+ struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
int r1 = j + regBase;
- sqlite3ExprCodeGetColumnToReg(pParse,
- pCol->pTab, pCol->iColumn, pCol->iTable, r1);
+ sqlite3ExprCodeGetColumnOfTable(v,
+ pCol->pTab, pCol->iTable, pCol->iColumn, r1);
j++;
}
}
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
- sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
+ sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
sqlite3WhereEnd(pWInfo);
- sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
+ pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
- sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
+ sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
- sAggInfo.useSortingIdx = 1;
- sqlite3ExprCacheClear(pParse);
-
+ pAggInfo->useSortingIdx = 1;
}
/* If the index or temporary table used by the GROUP BY sort
@@ -119755,9 +135891,9 @@ SQLITE_PRIVATE int sqlite3Select(
** clause, cancel the ephemeral table open coded earlier.
**
** This is an optimization - the correct answer should result regardless.
- ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
+ ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
** disable this optimization for testing purposes. */
- if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
+ if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
&& (groupBySort || sqlite3WhereIsSorted(pWInfo))
){
sSort.pOrderBy = 0;
@@ -119770,16 +135906,15 @@ SQLITE_PRIVATE int sqlite3Select(
** from the previous row currently stored in a0, a1, a2...
*/
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
- sqlite3ExprCacheClear(pParse);
if( groupBySort ){
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
+ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
sortOut, sortPTab);
}
for(j=0; j<pGroupBy->nExpr; j++){
if( groupBySort ){
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
}else{
- sAggInfo.directMode = 1;
+ pAggInfo->directMode = 1;
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
}
}
@@ -119809,14 +135944,14 @@ SQLITE_PRIVATE int sqlite3Select(
** the current row
*/
sqlite3VdbeJumpHere(v, addr1);
- updateAccumulator(pParse, &sAggInfo);
+ updateAccumulator(pParse, iUseFlag, pAggInfo);
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
VdbeComment((v, "indicate data in accumulator"));
/* End of the loop
*/
if( groupBySort ){
- sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
+ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx, addrTopOfLoop);
VdbeCoverage(v);
}else{
sqlite3WhereEnd(pWInfo);
@@ -119849,9 +135984,9 @@ SQLITE_PRIVATE int sqlite3Select(
VdbeCoverage(v);
VdbeComment((v, "Groupby result generator entry point"));
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
- finalizeAggFunctions(pParse, &sAggInfo);
+ finalizeAggFunctions(pParse, pAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
+ selectInnerLoop(pParse, p, -1, &sSort,
&sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
@@ -119860,15 +135995,15 @@ SQLITE_PRIVATE int sqlite3Select(
/* Generate a subroutine that will reset the group-by accumulator
*/
sqlite3VdbeResolveLabel(v, addrReset);
- resetAccumulator(pParse, &sAggInfo);
+ resetAccumulator(pParse, pAggInfo);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
+ VdbeComment((v, "indicate accumulator empty"));
sqlite3VdbeAddOp1(v, OP_Return, regReset);
-
+
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
else {
- ExprList *pDel = 0;
-#ifndef SQLITE_OMIT_BTREECOUNT
Table *pTab;
- if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
+ if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
/* If isSimpleCount() returns a pointer to a Table structure, then
** the SQL statement is of the form:
**
@@ -119887,7 +136022,7 @@ SQLITE_PRIVATE int sqlite3Select(
Index *pIdx; /* Iterator variable */
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
Index *pBest = 0; /* Best index found so far */
- int iRoot = pTab->tnum; /* Root page of scanned b-tree */
+ Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
@@ -119898,17 +136033,19 @@ SQLITE_PRIVATE int sqlite3Select(
**
** (2013-10-03) Do not count the entries in a partial index.
**
- ** In practice the KeyInfo structure will not be used. It is only
+ ** In practice the KeyInfo structure will not be used. It is only
** passed to keep OP_OpenRead happy.
*/
if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->bUnordered==0
- && pIdx->szIdxRow<pTab->szTabRow
- && pIdx->pPartIdxWhere==0
- && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
- ){
- pBest = pIdx;
+ if( !p->pSrc->a[0].fg.notIndexed ){
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->bUnordered==0
+ && pIdx->szIdxRow<pTab->szTabRow
+ && pIdx->pPartIdxWhere==0
+ && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
+ ){
+ pBest = pIdx;
+ }
}
}
if( pBest ){
@@ -119917,90 +136054,79 @@ SQLITE_PRIVATE int sqlite3Select(
}
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
- sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
+ sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1);
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
}
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
- }else
-#endif /* SQLITE_OMIT_BTREECOUNT */
- {
- /* Check if the query is of one of the following forms:
- **
- ** SELECT min(x) FROM ...
- ** SELECT max(x) FROM ...
- **
- ** If it is, then ask the code in where.c to attempt to sort results
- ** as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
- ** If where.c is able to produce results sorted in this order, then
- ** add vdbe code to break out of the processing loop after the
- ** first iteration (since the first iteration of the loop is
- ** guaranteed to operate on the row with the minimum or maximum
- ** value of x, the only row required).
- **
- ** A special flag must be passed to sqlite3WhereBegin() to slightly
- ** modify behavior as follows:
- **
- ** + If the query is a "SELECT min(x)", then the loop coded by
- ** where.c should not iterate over any values with a NULL value
- ** for x.
- **
- ** + The optimizer code in where.c (the thing that decides which
- ** index or indices to use) should place a different priority on
- ** satisfying the 'ORDER BY' clause than it does in other cases.
- ** Refer to code and comments in where.c for details.
- */
- ExprList *pMinMax = 0;
- u8 flag = WHERE_ORDERBY_NORMAL;
-
- assert( p->pGroupBy==0 );
- assert( flag==0 );
- if( p->pHaving==0 ){
- flag = minMaxQuery(&sAggInfo, &pMinMax);
- }
- assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) );
-
- if( flag ){
- pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
- pDel = pMinMax;
- assert( db->mallocFailed || pMinMax!=0 );
- if( !db->mallocFailed ){
- pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
- pMinMax->a[0].pExpr->op = TK_COLUMN;
+ }else{
+ int regAcc = 0; /* "populate accumulators" flag */
+ int addrSkip;
+
+ /* If there are accumulator registers but no min() or max() functions
+ ** without FILTER clauses, allocate register regAcc. Register regAcc
+ ** will contain 0 the first time the inner loop runs, and 1 thereafter.
+ ** The code generated by updateAccumulator() uses this to ensure
+ ** that the accumulator registers are (a) updated only once if
+ ** there are no min() or max functions or (b) always updated for the
+ ** first row visited by the aggregate, so that they are updated at
+ ** least once even if the FILTER clause means the min() or max()
+ ** function visits zero rows. */
+ if( pAggInfo->nAccumulator ){
+ for(i=0; i<pAggInfo->nFunc; i++){
+ if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){
+ continue;
+ }
+ if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
+ break;
+ }
+ }
+ if( i==pAggInfo->nFunc ){
+ regAcc = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
}
}
-
+
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
** of output.
*/
- resetAccumulator(pParse, &sAggInfo);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMax,0,flag,0);
+ assert( p->pGroupBy==0 );
+ resetAccumulator(pParse, pAggInfo);
+
+ /* If this query is a candidate for the min/max optimization, then
+ ** minMaxFlag will have been previously set to either
+ ** WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX and pMinMaxOrderBy will
+ ** be an appropriate ORDER BY expression for the optimization.
+ */
+ assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
+ assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
+
+ SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
+ 0, minMaxFlag, 0);
if( pWInfo==0 ){
- sqlite3ExprListDelete(db, pDel);
goto select_end;
}
- updateAccumulator(pParse, &sAggInfo);
- assert( pMinMax==0 || pMinMax->nExpr==1 );
- if( sqlite3WhereIsOrdered(pWInfo)>0 ){
- sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
- VdbeComment((v, "%s() by index",
- (flag==WHERE_ORDERBY_MIN?"min":"max")));
+ updateAccumulator(pParse, regAcc, pAggInfo);
+ if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
+ addrSkip = sqlite3WhereOrderByLimitOptLabel(pWInfo);
+ if( addrSkip!=sqlite3WhereContinueLabel(pWInfo) ){
+ sqlite3VdbeGoto(v, addrSkip);
}
sqlite3WhereEnd(pWInfo);
- finalizeAggFunctions(pParse, &sAggInfo);
+ finalizeAggFunctions(pParse, pAggInfo);
}
sSort.pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
- selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
+ selectInnerLoop(pParse, p, -1, 0, 0,
pDest, addrEnd, addrEnd);
- sqlite3ExprListDelete(db, pDel);
}
sqlite3VdbeResolveLabel(v, addrEnd);
-
+
} /* endif aggregate query */
if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
@@ -120013,6 +136139,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( sSort.pOrderBy ){
explainTempTable(pParse,
sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
+ assert( p->pEList==pEList );
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
}
@@ -120028,20 +136155,33 @@ SQLITE_PRIVATE int sqlite3Select(
** successful coding of the SELECT.
*/
select_end:
- explainSetInteger(pParse->iSelectId, iRestoreSelectId);
-
- /* Identify column names if results of the SELECT are to be output.
- */
- if( rc==SQLITE_OK && pDest->eDest==SRT_Output ){
- generateColumnNames(pParse, pTabList, pEList);
+ sqlite3ExprListDelete(db, pMinMaxOrderBy);
+#ifdef SQLITE_DEBUG
+ if( pAggInfo && !db->mallocFailed ){
+ for(i=0; i<pAggInfo->nColumn; i++){
+ Expr *pExpr = pAggInfo->aCol[i].pCExpr;
+ assert( pExpr!=0 || db->mallocFailed );
+ if( pExpr==0 ) continue;
+ assert( pExpr->pAggInfo==pAggInfo );
+ assert( pExpr->iAgg==i );
+ }
+ for(i=0; i<pAggInfo->nFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr!=0 || db->mallocFailed );
+ if( pExpr==0 ) continue;
+ assert( pExpr->pAggInfo==pAggInfo );
+ assert( pExpr->iAgg==i );
+ }
}
+#endif
- sqlite3DbFree(db, sAggInfo.aCol);
- sqlite3DbFree(db, sAggInfo.aFunc);
#if SELECTTRACE_ENABLED
- SELECTTRACE(1,pParse,p,("end processing\n"));
- pParse->nSelectIndent--;
+ SELECTTRACE(0x1,pParse,p,("end processing\n"));
+ if( (sqlite3_unsupported_selecttrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ sqlite3TreeViewSelect(0, p, 0);
+ }
#endif
+ ExplainQueryPlanPop(pParse);
return rc;
}
@@ -120066,8 +136206,6 @@ select_end:
** if they are not used.
*/
/* #include "sqliteInt.h" */
-/* #include <stdlib.h> */
-/* #include <string.h> */
#ifndef SQLITE_OMIT_GET_TABLE
@@ -120107,7 +136245,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
if( p->nData + need > p->nAlloc ){
char **azNew;
p->nAlloc = p->nAlloc*2 + need;
- azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
+ azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
if( azNew==0 ) goto malloc_failed;
p->azResult = azNew;
}
@@ -120160,7 +136298,7 @@ malloc_failed:
** at the conclusion of the call.
**
** The result that is written to ***pazResult is held in memory obtained
-** from malloc(). But the caller cannot free this memory directly.
+** from malloc(). But the caller cannot free this memory directly.
** Instead, the entire table should be passed to sqlite3_free_table() when
** the calling procedure is finished using it.
*/
@@ -120216,7 +136354,7 @@ SQLITE_API int sqlite3_get_table(
}
if( res.nAlloc>res.nData ){
char **azNew;
- azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
+ azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
@@ -120277,13 +136415,16 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS
sqlite3ExprListDelete(db, pTmp->pExprList);
sqlite3SelectDelete(db, pTmp->pSelect);
sqlite3IdListDelete(db, pTmp->pIdList);
+ sqlite3UpsertDelete(db, pTmp->pUpsert);
+ sqlite3SrcListDelete(db, pTmp->pFrom);
+ sqlite3DbFree(db, pTmp->zSpan);
sqlite3DbFree(db, pTmp);
}
}
/*
-** Given table pTab, return a list of all the triggers attached to
+** Given table pTab, return a list of all the triggers attached to
** the table. The list is connected by Trigger.pNext pointers.
**
** All of the triggers on pTab that are in the same database as pTab
@@ -120310,7 +136451,7 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
Trigger *pTrig = (Trigger *)sqliteHashData(p);
if( pTrig->pTabSchema==pTab->pSchema
- && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
+ && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
){
pTrig->pNext = (pList ? pList : pTab->pTrigger);
pList = pTrig;
@@ -120378,7 +136519,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
** ^^^^^^^^
**
** To maintain backwards compatibility, ignore the database
- ** name on pTableName if we are reparsing out of SQLITE_MASTER.
+ ** name on pTableName if we are reparsing out of the schema table
*/
if( db->init.busy && iDb!=1 ){
sqlite3DbFree(db, pTableName->a[0].zDatabase);
@@ -120427,18 +136568,24 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
zName = sqlite3NameFromToken(db, pName);
- if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
+ if( zName==0 ){
+ assert( db->mallocFailed );
+ goto trigger_cleanup;
+ }
+ if( sqlite3CheckObjectName(pParse, zName, "trigger", pTab->zName) ){
goto trigger_cleanup;
}
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
- if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
- if( !noErr ){
- sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
- }else{
- assert( !db->init.busy );
- sqlite3CodeVerifySchema(pParse, iDb);
+ if( !IN_RENAME_OBJECT ){
+ if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash),zName) ){
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+ }else{
+ assert( !db->init.busy );
+ sqlite3CodeVerifySchema(pParse, iDb);
+ }
+ goto trigger_cleanup;
}
- goto trigger_cleanup;
}
/* Do not create a trigger on a system table */
@@ -120451,7 +136598,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
** of triggers.
*/
if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
- sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
+ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
(tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
goto trigger_cleanup;
}
@@ -120462,7 +136609,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
}
#ifndef SQLITE_OMIT_AUTHORIZATION
- {
+ if( !IN_RENAME_OBJECT ){
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int code = SQLITE_CREATE_TRIGGER;
const char *zDb = db->aDb[iTabDb].zDbSName;
@@ -120496,8 +136643,15 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
pTrigger->pTabSchema = pTab->pSchema;
pTrigger->op = (u8)op;
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
- pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
- pTrigger->pColumns = sqlite3IdListDup(db, pColumns);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
+ pTrigger->pWhen = pWhen;
+ pWhen = 0;
+ }else{
+ pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
+ }
+ pTrigger->pColumns = pColumns;
+ pColumns = 0;
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
@@ -120540,27 +136694,37 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
}
sqlite3TokenInit(&nameToken, pTrig->zName);
sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
- if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
- || sqlite3FixExpr(&sFix, pTrig->pWhen)
+ if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
+ || sqlite3FixExpr(&sFix, pTrig->pWhen)
){
goto triggerfinish_cleanup;
}
+#ifndef SQLITE_OMIT_ALTERTABLE
+ if( IN_RENAME_OBJECT ){
+ assert( !db->init.busy );
+ pParse->pNewTrigger = pTrig;
+ pTrig = 0;
+ }else
+#endif
+
/* if we are not initializing,
- ** build the sqlite_master entry
+ ** build the sqlite_schema entry
*/
if( !db->init.busy ){
Vdbe *v;
char *z;
- /* Make an entry in the sqlite_master table */
+ /* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
sqlite3BeginWriteOperation(pParse, 0, iDb);
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
+ testcase( z==0 );
sqlite3NestedParse(pParse,
- "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
- db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), zName,
+ "INSERT INTO %Q." DFLT_SCHEMA_TABLE
+ " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
+ db->aDb[iDb].zDbSName, zName,
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
@@ -120572,6 +136736,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
Trigger *pLink = pTrig;
Hash *pHash = &db->aDb[iDb].pSchema->trigHash;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ assert( pLink!=0 );
pTrig = sqlite3HashInsert(pHash, zName, pTrig);
if( pTrig ){
sqlite3OomFault(db);
@@ -120586,18 +136751,34 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
triggerfinish_cleanup:
sqlite3DeleteTrigger(db, pTrig);
- assert( !pParse->pNewTrigger );
+ assert( IN_RENAME_OBJECT || !pParse->pNewTrigger );
sqlite3DeleteTriggerStep(db, pStepList);
}
/*
+** Duplicate a range of text from an SQL statement, then convert all
+** whitespace characters into ordinary space characters.
+*/
+static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
+ char *z = sqlite3DbSpanDup(db, zStart, zEnd);
+ int i;
+ if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
+ return z;
+}
+
+/*
** Turn a SELECT statement (that the pSelect parameter points to) into
** a trigger step. Return a pointer to a TriggerStep structure.
**
** The parser calls this routine when it finds a SELECT statement in
-** body of a TRIGGER.
+** body of a TRIGGER.
*/
-SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelect){
+SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(
+ sqlite3 *db, /* Database connection */
+ Select *pSelect, /* The SELECT statement */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
+){
TriggerStep *pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep));
if( pTriggerStep==0 ) {
sqlite3SelectDelete(db, pSelect);
@@ -120606,6 +136787,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec
pTriggerStep->op = TK_SELECT;
pTriggerStep->pSelect = pSelect;
pTriggerStep->orconf = OE_Default;
+ pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
return pTriggerStep;
}
@@ -120616,10 +136798,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3 *db, Select *pSelec
** If an OOM error occurs, NULL is returned and db->mallocFailed is set.
*/
static TriggerStep *triggerStepAllocate(
- sqlite3 *db, /* Database connection */
+ Parse *pParse, /* Parser context */
u8 op, /* Trigger opcode */
- Token *pName /* The target name */
+ Token *pName, /* The target name */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
+ sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
@@ -120629,6 +136814,10 @@ static TriggerStep *triggerStepAllocate(
sqlite3Dequote(z);
pTriggerStep->zTarget = z;
pTriggerStep->op = op;
+ pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName);
+ }
}
return pTriggerStep;
}
@@ -120641,23 +136830,39 @@ static TriggerStep *triggerStepAllocate(
** body of a trigger.
*/
SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
- sqlite3 *db, /* The database connection */
+ Parse *pParse, /* Parser */
Token *pTableName, /* Name of the table into which we insert */
IdList *pColumn, /* List of columns in pTableName to insert into */
Select *pSelect, /* A SELECT statement that supplies values */
- u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
+ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */
+ Upsert *pUpsert, /* ON CONFLICT clauses for upsert */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
+ sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
assert(pSelect != 0 || db->mallocFailed);
- pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName);
+ pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd);
if( pTriggerStep ){
- pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+ if( IN_RENAME_OBJECT ){
+ pTriggerStep->pSelect = pSelect;
+ pSelect = 0;
+ }else{
+ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+ }
pTriggerStep->pIdList = pColumn;
+ pTriggerStep->pUpsert = pUpsert;
pTriggerStep->orconf = orconf;
+ if( pUpsert ){
+ sqlite3HasExplicitNulls(pParse, pUpsert->pUpsertTarget);
+ }
}else{
+ testcase( pColumn );
sqlite3IdListDelete(db, pColumn);
+ testcase( pUpsert );
+ sqlite3UpsertDelete(db, pUpsert);
}
sqlite3SelectDelete(db, pSelect);
@@ -120670,22 +136875,37 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
** sees an UPDATE statement inside the body of a CREATE TRIGGER.
*/
SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
- sqlite3 *db, /* The database connection */
+ Parse *pParse, /* Parser */
Token *pTableName, /* Name of the table to be updated */
+ SrcList *pFrom,
ExprList *pEList, /* The SET clause: list of column and new values */
Expr *pWhere, /* The WHERE clause */
- u8 orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
+ sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName);
+ pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
if( pTriggerStep ){
- pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
- pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ if( IN_RENAME_OBJECT ){
+ pTriggerStep->pExprList = pEList;
+ pTriggerStep->pWhere = pWhere;
+ pTriggerStep->pFrom = pFrom;
+ pEList = 0;
+ pWhere = 0;
+ pFrom = 0;
+ }else{
+ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
+ pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE);
+ }
pTriggerStep->orconf = orconf;
}
sqlite3ExprListDelete(db, pEList);
sqlite3ExprDelete(db, pWhere);
+ sqlite3SrcListDelete(db, pFrom);
return pTriggerStep;
}
@@ -120695,22 +136915,30 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
** sees a DELETE statement inside the body of a CREATE TRIGGER.
*/
SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(
- sqlite3 *db, /* Database connection */
+ Parse *pParse, /* Parser */
Token *pTableName, /* The table from which rows are deleted */
- Expr *pWhere /* The WHERE clause */
+ Expr *pWhere, /* The WHERE clause */
+ const char *zStart, /* Start of SQL text */
+ const char *zEnd /* End of SQL text */
){
+ sqlite3 *db = pParse->db;
TriggerStep *pTriggerStep;
- pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName);
+ pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd);
if( pTriggerStep ){
- pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ if( IN_RENAME_OBJECT ){
+ pTriggerStep->pWhere = pWhere;
+ pWhere = 0;
+ }else{
+ pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+ }
pTriggerStep->orconf = OE_Default;
}
sqlite3ExprDelete(db, pWhere);
return pTriggerStep;
}
-/*
+/*
** Recursively delete a Trigger structure
*/
SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
@@ -120724,7 +136952,7 @@ SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
}
/*
-** This function is called to drop a trigger from the database schema.
+** This function is called to drop a trigger from the database schema.
**
** This may be called directly from the parser and therefore identifies
** the trigger by name. The sqlite3DropTriggerPtr() routine does the
@@ -120749,7 +136977,7 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue;
+ if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
if( pTrigger ) break;
@@ -120779,7 +137007,7 @@ static Table *tableOfTrigger(Trigger *pTrigger){
/*
-** Drop a trigger given a pointer to that trigger.
+** Drop a trigger given a pointer to that trigger.
*/
SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
Table *pTable;
@@ -120790,10 +137018,9 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
assert( iDb>=0 && iDb<db->nDb );
pTable = tableOfTrigger(pTrigger);
- assert( pTable );
- assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
+ assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
#ifndef SQLITE_OMIT_AUTHORIZATION
- {
+ if( pTable ){
int code = SQLITE_DROP_TRIGGER;
const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
@@ -120807,11 +137034,10 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
/* Generate code to destroy the database record of the trigger.
*/
- assert( pTable!=0 );
if( (v = sqlite3GetVdbe(pParse))!=0 ){
sqlite3NestedParse(pParse,
- "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
- db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb), pTrigger->zName
+ "DELETE FROM %Q." DFLT_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
+ db->aDb[iDb].zDbSName, pTrigger->zName
);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
@@ -120831,12 +137057,18 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const ch
if( ALWAYS(pTrigger) ){
if( pTrigger->pSchema==pTrigger->pTabSchema ){
Table *pTab = tableOfTrigger(pTrigger);
- Trigger **pp;
- for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
- *pp = (*pp)->pNext;
+ if( pTab ){
+ Trigger **pp;
+ for(pp=&pTab->pTrigger; *pp; pp=&((*pp)->pNext)){
+ if( *pp==pTrigger ){
+ *pp = (*pp)->pNext;
+ break;
+ }
+ }
+ }
}
sqlite3DeleteTrigger(db, pTrigger);
- db->flags |= SQLITE_InternChanges;
+ db->mDbFlags |= DBFLAG_SchemaChange;
}
}
@@ -120853,14 +137085,14 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
int e;
if( pIdList==0 || NEVER(pEList==0) ) return 1;
for(e=0; e<pEList->nExpr; e++){
- if( sqlite3IdListIndex(pIdList, pEList->a[e].zName)>=0 ) return 1;
+ if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1;
}
- return 0;
+ return 0;
}
/*
** Return a list of all triggers on table pTab if there exists at least
-** one trigger that must be fired when an operation of type 'op' is
+** one trigger that must be fired when an operation of type 'op' is
** performed on the table, and, if that operation is an UPDATE, if at
** least one of the columns in pChanges is being modified.
*/
@@ -120900,37 +137132,40 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist(
** trigger is in TEMP in which case it can refer to any other database it
** wants.
*/
-static SrcList *targetSrcList(
+SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(
Parse *pParse, /* The parsing context */
TriggerStep *pStep /* The trigger containing the target token */
){
sqlite3 *db = pParse->db;
- int iDb; /* Index of the database to use */
- SrcList *pSrc; /* SrcList to be returned */
-
- pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
+ SrcList *pSrc; /* SrcList to be returned */
+ char *zName = sqlite3DbStrDup(db, pStep->zTarget);
+ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ assert( pSrc==0 || pSrc->nSrc==1 );
+ assert( zName || pSrc==0 );
if( pSrc ){
- assert( pSrc->nSrc>0 );
- pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
- iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
- if( iDb==0 || iDb>=2 ){
- const char *zDb;
- assert( iDb<db->nDb );
- zDb = db->aDb[iDb].zDbSName;
- pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb);
+ Schema *pSchema = pStep->pTrig->pSchema;
+ pSrc->a[0].zName = zName;
+ if( pSchema!=db->aDb[1].pSchema ){
+ pSrc->a[0].pSchema = pSchema;
+ }
+ if( pStep->pFrom ){
+ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
+ pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
}
+ }else{
+ sqlite3DbFree(db, zName);
}
return pSrc;
}
/*
-** Generate VDBE code for the statements inside the body of a single
+** Generate VDBE code for the statements inside the body of a single
** trigger.
*/
static int codeTriggerProgram(
Parse *pParse, /* The parser context */
TriggerStep *pStepList, /* List of statements inside the trigger body */
- int orconf /* Conflict algorithm. (OE_Abort, etc) */
+ int orconf /* Conflict algorithm. (OE_Abort, etc) */
){
TriggerStep *pStep;
Vdbe *v = pParse->pVdbe;
@@ -120956,29 +137191,38 @@ static int codeTriggerProgram(
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
assert( pParse->okConstFactor==0 );
+#ifndef SQLITE_OMIT_TRACE
+ if( pStep->zSpan ){
+ sqlite3VdbeAddOp4(v, OP_Trace, 0x7fffffff, 1, 0,
+ sqlite3MPrintf(db, "-- %s", pStep->zSpan),
+ P4_DYNAMIC);
+ }
+#endif
+
switch( pStep->op ){
case TK_UPDATE: {
- sqlite3Update(pParse,
- targetSrcList(pParse, pStep),
- sqlite3ExprListDup(db, pStep->pExprList, 0),
- sqlite3ExprDup(db, pStep->pWhere, 0),
- pParse->eOrconf
+ sqlite3Update(pParse,
+ sqlite3TriggerStepSrc(pParse, pStep),
+ sqlite3ExprListDup(db, pStep->pExprList, 0),
+ sqlite3ExprDup(db, pStep->pWhere, 0),
+ pParse->eOrconf, 0, 0, 0
);
break;
}
case TK_INSERT: {
- sqlite3Insert(pParse,
- targetSrcList(pParse, pStep),
- sqlite3SelectDup(db, pStep->pSelect, 0),
- sqlite3IdListDup(db, pStep->pIdList),
- pParse->eOrconf
+ sqlite3Insert(pParse,
+ sqlite3TriggerStepSrc(pParse, pStep),
+ sqlite3SelectDup(db, pStep->pSelect, 0),
+ sqlite3IdListDup(db, pStep->pIdList),
+ pParse->eOrconf,
+ sqlite3UpsertDup(db, pStep->pUpsert)
);
break;
}
case TK_DELETE: {
- sqlite3DeleteFrom(pParse,
- targetSrcList(pParse, pStep),
- sqlite3ExprDup(db, pStep->pWhere, 0)
+ sqlite3DeleteFrom(pParse,
+ sqlite3TriggerStepSrc(pParse, pStep),
+ sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
);
break;
}
@@ -120990,7 +137234,7 @@ static int codeTriggerProgram(
sqlite3SelectDelete(db, pSelect);
break;
}
- }
+ }
if( pStep->op!=TK_SELECT ){
sqlite3VdbeAddOp0(v, OP_ResetCount);
}
@@ -121035,7 +137279,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){
}
/*
-** Create and populate a new TriggerPrg object with a sub-program
+** Create and populate a new TriggerPrg object with a sub-program
** implementing trigger pTrigger with ON CONFLICT policy orconf.
*/
static TriggerPrg *codeRowTrigger(
@@ -121058,7 +137302,7 @@ static TriggerPrg *codeRowTrigger(
assert( pTop->pVdbe );
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
- ** are freed if an error occurs, link them into the Parse.pTriggerPrg
+ ** are freed if an error occurs, link them into the Parse.pTriggerPrg
** list of the top-level Parse object sooner rather than later. */
pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg));
if( !pPrg ) return 0;
@@ -121072,7 +137316,7 @@ static TriggerPrg *codeRowTrigger(
pPrg->aColmask[0] = 0xffffffff;
pPrg->aColmask[1] = 0xffffffff;
- /* Allocate and populate a new Parse context to use for coding the
+ /* Allocate and populate a new Parse context to use for coding the
** trigger sub-program. */
pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
if( !pSubParse ) return 0;
@@ -121084,10 +137328,11 @@ static TriggerPrg *codeRowTrigger(
pSubParse->zAuthContext = pTrigger->zName;
pSubParse->eTriggerOp = pTrigger->op;
pSubParse->nQueryLoop = pParse->nQueryLoop;
+ pSubParse->disableVtab = pParse->disableVtab;
v = sqlite3GetVdbe(pSubParse);
if( v ){
- VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
+ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
pTrigger->zName, onErrorText(orconf),
(pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
(pTrigger->op==TK_UPDATE ? "UPDATE" : ""),
@@ -121096,20 +137341,22 @@ static TriggerPrg *codeRowTrigger(
pTab->zName
));
#ifndef SQLITE_OMIT_TRACE
- sqlite3VdbeChangeP4(v, -1,
- sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
- );
+ if( pTrigger->zName ){
+ sqlite3VdbeChangeP4(v, -1,
+ sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
+ );
+ }
#endif
/* If one was specified, code the WHEN clause. If it evaluates to false
- ** (or NULL) the sub-vdbe is immediately halted by jumping to the
+ ** (or NULL) the sub-vdbe is immediately halted by jumping to the
** OP_Halt inserted at the end of the program. */
if( pTrigger->pWhen ){
pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
- if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
- && db->mallocFailed==0
+ if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
+ && db->mallocFailed==0
){
- iEndTrigger = sqlite3VdbeMakeLabel(v);
+ iEndTrigger = sqlite3VdbeMakeLabel(pSubParse);
sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
}
sqlite3ExprDelete(db, pWhen);
@@ -121126,7 +137373,7 @@ static TriggerPrg *codeRowTrigger(
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
transferParseError(pParse, pSubParse);
- if( db->mallocFailed==0 ){
+ if( db->mallocFailed==0 && pParse->nErr==0 ){
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
}
pProgram->nMem = pSubParse->nMem;
@@ -121144,7 +137391,7 @@ static TriggerPrg *codeRowTrigger(
return pPrg;
}
-
+
/*
** Return a pointer to a TriggerPrg object containing the sub-program for
** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such
@@ -121166,8 +137413,8 @@ static TriggerPrg *getRowTrigger(
** process of being coded). If this is the case, then an entry with
** a matching TriggerPrg.pTrigger field will be present somewhere
** in the Parse.pTriggerPrg list. Search for such an entry. */
- for(pPrg=pRoot->pTriggerPrg;
- pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf);
+ for(pPrg=pRoot->pTriggerPrg;
+ pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf);
pPrg=pPrg->pNext
);
@@ -121180,7 +137427,7 @@ static TriggerPrg *getRowTrigger(
}
/*
-** Generate code for the trigger program associated with trigger p on
+** Generate code for the trigger program associated with trigger p on
** table pTab. The reg, orconf and ignoreJump parameters passed to this
** function are the same as those described in the header function for
** sqlite3CodeRowTrigger()
@@ -121198,7 +137445,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
pPrg = getRowTrigger(pParse, p, pTab, orconf);
assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
- /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
+ /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
** is a pointer to the sub-vdbe containing the trigger program. */
if( pPrg ){
int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
@@ -121227,7 +137474,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
** If there are no triggers that fire at the specified time for the specified
** operation on pTab, this function is a no-op.
**
-** The reg argument is the address of the first in an array of registers
+** The reg argument is the address of the first in an array of registers
** that contain the values substituted for the new.* and old.* references
** in the trigger program. If N is the number of columns in table pTab
** (a copy of pTab->nCol), then registers are populated as follows:
@@ -121244,12 +137491,12 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
** reg+N+N+1 NEW.* value of right-most column of pTab
**
** For ON DELETE triggers, the registers containing the NEW.* values will
-** never be accessed by the trigger program, so they are not allocated or
-** populated by the caller (there is no data to populate them with anyway).
+** never be accessed by the trigger program, so they are not allocated or
+** populated by the caller (there is no data to populate them with anyway).
** Similarly, for ON INSERT triggers the values stored in the OLD.* registers
** are never accessed, and so are not allocated by the caller. So, for an
** ON INSERT trigger, the value passed to this function as parameter reg
-** is not a readable register, although registers (reg+N) through
+** is not a readable register, although registers (reg+N) through
** (reg+N+N+1) are.
**
** Parameter orconf is the default conflict resolution algorithm for the
@@ -121281,12 +137528,12 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(
** or else it must be a TEMP trigger. */
assert( p->pSchema!=0 );
assert( p->pTabSchema!=0 );
- assert( p->pSchema==p->pTabSchema
+ assert( p->pSchema==p->pTabSchema
|| p->pSchema==pParse->db->aDb[1].pSchema );
/* Determine whether we should code this trigger */
- if( p->op==op
- && p->tr_tm==tr_tm
+ if( p->op==op
+ && p->tr_tm==tr_tm
&& checkColumnOverlap(p->pColumns, pChanges)
){
sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
@@ -121295,9 +137542,9 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(
}
/*
-** Triggers may access values stored in the old.* or new.* pseudo-table.
-** This function returns a 32-bit bitmask indicating which columns of the
-** old.* or new.* tables actually are used by triggers. This information
+** Triggers may access values stored in the old.* or new.* pseudo-table.
+** This function returns a 32-bit bitmask indicating which columns of the
+** old.* or new.* tables actually are used by triggers. This information
** may be used by the caller, for example, to avoid having to load the entire
** old.* record into memory when executing an UPDATE or DELETE command.
**
@@ -121307,7 +137554,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(
** are more than 32 columns in the table, and at least one of the columns
** with an index greater than 32 may be accessed, 0xffffffff is returned.
**
-** It is not possible to determine if the old.rowid or new.rowid column is
+** It is not possible to determine if the old.rowid or new.rowid column is
** accessed by triggers. The caller must always assume that it is.
**
** Parameter isNew must be either 1 or 0. If it is 0, then the mask returned
@@ -121384,10 +137631,10 @@ static void updateVirtualTable(
/*
** The most recently coded instruction was an OP_Column to retrieve the
-** i-th column of table pTab. This routine sets the P4 parameter of the
+** i-th column of table pTab. This routine sets the P4 parameter of the
** OP_Column to the default value, if any.
**
-** The default value of a column is specified by a DEFAULT clause in the
+** The default value of a column is specified by a DEFAULT clause in the
** column definition. This was either supplied by the user when the table
** was created, or added later to the table definition by an ALTER TABLE
** command. If the latter, then the row-records in the table btree on disk
@@ -121396,21 +137643,21 @@ static void updateVirtualTable(
** If the former, then all row-records are guaranteed to include a value
** for the column and the P4 value is not required.
**
-** Column definitions created by an ALTER TABLE command may only have
+** Column definitions created by an ALTER TABLE command may only have
** literal default values specified: a number, null or a string. (If a more
-** complicated default expression value was provided, it is evaluated
+** complicated default expression value was provided, it is evaluated
** when the ALTER TABLE is executed and one of the literal values written
-** into the sqlite_master table.)
+** into the sqlite_schema table.)
**
** Therefore, the P4 parameter is only required if the default value for
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
** function is capable of transforming these types of expressions into
** sqlite3_value objects.
**
-** If parameter iReg is not negative, code an OP_RealAffinity instruction
-** on register iReg. This is used when an equivalent integer value is
-** stored in place of an 8-byte floating point value in order to save
-** space.
+** If column as REAL affinity and the table is an ordinary b-tree table
+** (not a virtual table) then the value might have been stored as an
+** integer. In that case, add an OP_RealAffinity opcode to make sure
+** it has been converted into REAL.
*/
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
assert( pTab!=0 );
@@ -121420,46 +137667,238 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
Column *pCol = &pTab->aCol[i];
VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
assert( i<pTab->nCol );
- sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
+ sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
pCol->affinity, &pValue);
if( pValue ){
- sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
+ sqlite3VdbeAppendP4(v, pValue, P4_MEM);
}
+ }
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
- sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
+ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
+ }
+#endif
+}
+
+/*
+** Check to see if column iCol of index pIdx references any of the
+** columns defined by aXRef and chngRowid. Return true if it does
+** and false if not. This is an optimization. False-positives are a
+** performance degradation, but false-negatives can result in a corrupt
+** index and incorrect answers.
+**
+** aXRef[j] will be non-negative if column j of the original table is
+** being updated. chngRowid will be true if the rowid of the table is
+** being updated.
+*/
+static int indexColumnIsBeingUpdated(
+ Index *pIdx, /* The index to check */
+ int iCol, /* Which column of the index to check */
+ int *aXRef, /* aXRef[j]>=0 if column j is being updated */
+ int chngRowid /* true if the rowid is being updated */
+){
+ i16 iIdxCol = pIdx->aiColumn[iCol];
+ assert( iIdxCol!=XN_ROWID ); /* Cannot index rowid */
+ if( iIdxCol>=0 ){
+ return aXRef[iIdxCol]>=0;
+ }
+ assert( iIdxCol==XN_EXPR );
+ assert( pIdx->aColExpr!=0 );
+ assert( pIdx->aColExpr->a[iCol].pExpr!=0 );
+ return sqlite3ExprReferencesUpdatedColumn(pIdx->aColExpr->a[iCol].pExpr,
+ aXRef,chngRowid);
+}
+
+/*
+** Check to see if index pIdx is a partial index whose conditional
+** expression might change values due to an UPDATE. Return true if
+** the index is subject to change and false if the index is guaranteed
+** to be unchanged. This is an optimization. False-positives are a
+** performance degradation, but false-negatives can result in a corrupt
+** index and incorrect answers.
+**
+** aXRef[j] will be non-negative if column j of the original table is
+** being updated. chngRowid will be true if the rowid of the table is
+** being updated.
+*/
+static int indexWhereClauseMightChange(
+ Index *pIdx, /* The index to check */
+ int *aXRef, /* aXRef[j]>=0 if column j is being updated */
+ int chngRowid /* true if the rowid is being updated */
+){
+ if( pIdx->pPartIdxWhere==0 ) return 0;
+ return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere,
+ aXRef, chngRowid);
+}
+
+/*
+** Allocate and return a pointer to an expression of type TK_ROW with
+** Expr.iColumn set to value (iCol+1). The resolver will modify the
+** expression to be a TK_COLUMN reading column iCol of the first
+** table in the source-list (pSrc->a[0]).
+*/
+static Expr *exprRowColumn(Parse *pParse, int iCol){
+ Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0);
+ if( pRet ) pRet->iColumn = iCol+1;
+ return pRet;
+}
+
+/*
+** Assuming both the pLimit and pOrderBy parameters are NULL, this function
+** generates VM code to run the query:
+**
+** SELECT <other-columns>, pChanges FROM pTabList WHERE pWhere
+**
+** and write the results to the ephemeral table already opened as cursor
+** iEph. None of pChanges, pTabList or pWhere are modified or consumed by
+** this function, they must be deleted by the caller.
+**
+** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view:
+**
+** SELECT <other-columns>, pChanges FROM pTabList
+** WHERE pWhere
+** GROUP BY <other-columns>
+** ORDER BY pOrderBy LIMIT pLimit
+**
+** If pTab is a view, the GROUP BY clause is omitted.
+**
+** Exactly how results are written to table iEph, and exactly what
+** the <other-columns> in the query above are is determined by the type
+** of table pTabList->a[0].pTab.
+**
+** If the table is a WITHOUT ROWID table, then argument pPk must be its
+** PRIMARY KEY. In this case <other-columns> are the primary key columns
+** of the table, in order. The results of the query are written to ephemeral
+** table iEph as index keys, using OP_IdxInsert.
+**
+** If the table is actually a view, then <other-columns> are all columns of
+** the view. The results are written to the ephemeral table iEph as records
+** with automatically assigned integer keys.
+**
+** If the table is a virtual or ordinary intkey table, then <other-columns>
+** is its rowid. For a virtual table, the results are written to iEph as
+** records with automatically assigned integer keys For intkey tables, the
+** rowid value in <other-columns> is used as the integer key, and the
+** remaining fields make up the table record.
+*/
+static void updateFromSelect(
+ Parse *pParse, /* Parse context */
+ int iEph, /* Cursor for open eph. table */
+ Index *pPk, /* PK if table 0 is WITHOUT ROWID */
+ ExprList *pChanges, /* List of expressions to return */
+ SrcList *pTabList, /* List of tables to select from */
+ Expr *pWhere, /* WHERE clause for query */
+ ExprList *pOrderBy, /* ORDER BY clause */
+ Expr *pLimit /* LIMIT clause */
+){
+ int i;
+ SelectDest dest;
+ Select *pSelect = 0;
+ ExprList *pList = 0;
+ ExprList *pGrp = 0;
+ Expr *pLimit2 = 0;
+ ExprList *pOrderBy2 = 0;
+ sqlite3 *db = pParse->db;
+ Table *pTab = pTabList->a[0].pTab;
+ SrcList *pSrc;
+ Expr *pWhere2;
+ int eDest;
+
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( pOrderBy && pLimit==0 ) {
+ sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE");
+ return;
+ }
+ pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0);
+ pLimit2 = sqlite3ExprDup(db, pLimit, 0);
+#else
+ UNUSED_PARAMETER(pOrderBy);
+ UNUSED_PARAMETER(pLimit);
+#endif
+
+ pSrc = sqlite3SrcListDup(db, pTabList, 0);
+ pWhere2 = sqlite3ExprDup(db, pWhere, 0);
+
+ assert( pTabList->nSrc>1 );
+ if( pSrc ){
+ pSrc->a[0].iCursor = -1;
+ pSrc->a[0].pTab->nTabRef--;
+ pSrc->a[0].pTab = 0;
+ }
+ if( pPk ){
+ for(i=0; i<pPk->nKeyCol; i++){
+ Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( pLimit ){
+ pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0));
+ }
+#endif
+ pList = sqlite3ExprListAppend(pParse, pList, pNew);
+ }
+ eDest = SRT_Upfrom;
+ }else if( pTab->pSelect ){
+ for(i=0; i<pTab->nCol; i++){
+ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ }
+ eDest = SRT_Table;
+ }else{
+ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom;
+ pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( pLimit ){
+ pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
}
#endif
}
+ if( ALWAYS(pChanges) ){
+ for(i=0; i<pChanges->nExpr; i++){
+ pList = sqlite3ExprListAppend(pParse, pList,
+ sqlite3ExprDup(db, pChanges->a[i].pExpr, 0)
+ );
+ }
+ }
+ pSelect = sqlite3SelectNew(pParse, pList,
+ pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UpdateFrom|SF_IncludeHidden, pLimit2
+ );
+ sqlite3SelectDestInit(&dest, eDest, iEph);
+ dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1);
+ sqlite3Select(pParse, pSelect, &dest);
+ sqlite3SelectDelete(db, pSelect);
}
/*
** Process an UPDATE statement.
**
-** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
-** \_______/ \________/ \______/ \________________/
-* onError pTabList pChanges pWhere
+** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL;
+** \_______/ \_/ \______/ \_____/ \________________/
+** onError | pChanges | pWhere
+** \_______________________/
+** pTabList
*/
SQLITE_PRIVATE void sqlite3Update(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* The table in which we should change things */
ExprList *pChanges, /* Things to be changed */
Expr *pWhere, /* The WHERE clause. May be null */
- int onError /* How to handle constraint errors */
+ int onError, /* How to handle constraint errors */
+ ExprList *pOrderBy, /* ORDER BY clause. May be null */
+ Expr *pLimit, /* LIMIT clause. May be null */
+ Upsert *pUpsert /* ON CONFLICT clause, or null */
){
- int i, j; /* Loop counters */
+ int i, j, k; /* Loop counters */
Table *pTab; /* The table to be updated */
int addrTop = 0; /* VDBE instruction address of the start of the loop */
- WhereInfo *pWInfo; /* Information about the WHERE clause */
+ WhereInfo *pWInfo = 0; /* Information about the WHERE clause */
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */
int nIdx; /* Number of indices that need updating */
+ int nAllIdx; /* Total number of indexes */
int iBaseCur; /* Base cursor number */
int iDataCur; /* Cursor for the canonical data btree */
int iIdxCur; /* Cursor for the first index */
sqlite3 *db; /* The database structure */
- int *aRegIdx = 0; /* One register assigned to each index to be updated */
+ int *aRegIdx = 0; /* Registers for to each index and the main table */
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
@@ -121468,13 +137907,15 @@ SQLITE_PRIVATE void sqlite3Update(
u8 chngRowid; /* Rowid changed in a normal table */
u8 chngKey; /* Either chngPk or chngRowid */
Expr *pRowidExpr = 0; /* Expression defining the new record number */
+ int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */
- int okOnePass; /* True for one-pass algorithm without the FIFO */
+ int eOnePass; /* ONEPASS_XXX value from where.c */
int hasFK; /* True if foreign key processing is required */
int labelBreak; /* Jump here to break out of UPDATE loop */
int labelContinue; /* Jump here to continue next step of UPDATE loop */
+ int flags; /* Flags for sqlite3WhereBegin() */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True when updating a view (INSTEAD OF trigger) */
@@ -121485,6 +137926,12 @@ SQLITE_PRIVATE void sqlite3Update(
int iEph = 0; /* Ephemeral table holding all primary key values */
int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
+ int addrOpen = 0; /* Address of OP_OpenEphemeral */
+ int iPk = 0; /* First of nPk cells holding PRIMARY KEY value */
+ i16 nPk = 0; /* Number of components of the PRIMARY KEY */
+ int bReplace = 0; /* True if REPLACE conflict resolution might happen */
+ int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */
+ int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */
/* Register Allocations */
int regRowCount = 0; /* A count of rows changed */
@@ -121500,9 +137947,8 @@ SQLITE_PRIVATE void sqlite3Update(
if( pParse->nErr || db->mallocFailed ){
goto update_cleanup;
}
- assert( pTabList->nSrc==1 );
- /* Locate the table which we want to update.
+ /* Locate the table which we want to update.
*/
pTab = sqlite3SrcListLookup(pParse, pTabList);
if( pTab==0 ) goto update_cleanup;
@@ -121525,6 +137971,23 @@ SQLITE_PRIVATE void sqlite3Update(
# define isView 0
#endif
+ /* If there was a FROM clause, set nChangeFrom to the number of expressions
+ ** in the change-list. Otherwise, set it to 0. There cannot be a FROM
+ ** clause if this function is being called to generate code for part of
+ ** an UPSERT statement. */
+ nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0;
+ assert( nChangeFrom==0 || pUpsert==0 );
+
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
+ if( !isView && nChangeFrom==0 ){
+ pWhere = sqlite3LimitWhere(
+ pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
+ );
+ pOrderBy = 0;
+ pLimit = 0;
+ }
+#endif
+
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
@@ -121537,24 +138000,31 @@ SQLITE_PRIVATE void sqlite3Update(
** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case.
*/
- pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++;
+ iBaseCur = iDataCur = pParse->nTab++;
iIdxCur = iDataCur+1;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
+ testcase( pPk!=0 && pPk!=pTab->pIndex );
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
- if( IsPrimaryKeyIndex(pIdx) && pPk!=0 ){
+ if( pPk==pIdx ){
iDataCur = pParse->nTab;
- pTabList->a[0].iCursor = iDataCur;
}
pParse->nTab++;
}
+ if( pUpsert ){
+ /* On an UPSERT, reuse the same cursors already opened by INSERT */
+ iDataCur = pUpsert->iDataCur;
+ iIdxCur = pUpsert->iIdxCur;
+ pParse->nTab = iBaseCur;
+ }
+ pTabList->a[0].iCursor = iDataCur;
- /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
+ /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
** Initialize aXRef[] and aToOpen[] to their default values.
*/
- aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
+ aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 );
if( aXRef==0 ) goto update_cleanup;
aRegIdx = aXRef+pTab->nCol;
- aToOpen = (u8*)(aRegIdx+nIdx);
+ aToOpen = (u8*)(aRegIdx+nIdx+1);
memset(aToOpen, 1, nIdx+1);
aToOpen[nIdx+1] = 0;
for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
@@ -121563,6 +138033,12 @@ SQLITE_PRIVATE void sqlite3Update(
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
+ sNC.uNC.pUpsert = pUpsert;
+ sNC.ncFlags = NC_UUpsert;
+
+ /* Begin generating code. */
+ v = sqlite3GetVdbe(pParse);
+ if( v==0 ) goto update_cleanup;
/* Resolve the column names in all the expressions of the
** of the UPDATE statement. Also find the column index
@@ -121572,28 +138048,42 @@ SQLITE_PRIVATE void sqlite3Update(
*/
chngRowid = chngPk = 0;
for(i=0; i<pChanges->nExpr; i++){
- if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
+ /* If this is an UPDATE with a FROM clause, do not resolve expressions
+ ** here. The call to sqlite3Select() below will do that. */
+ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
goto update_cleanup;
}
for(j=0; j<pTab->nCol; j++){
- if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){
+ if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zEName)==0 ){
if( j==pTab->iPKey ){
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
+ iRowidExpr = i;
}else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
chngPk = 1;
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
+ testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
+ testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
+ sqlite3ErrorMsg(pParse,
+ "cannot UPDATE generated column \"%s\"",
+ pTab->aCol[j].zName);
+ goto update_cleanup;
+ }
+#endif
aXRef[j] = i;
break;
}
}
if( j>=pTab->nCol ){
- if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){
+ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zEName) ){
j = -1;
chngRowid = 1;
pRowidExpr = pChanges->a[i].pExpr;
+ iRowidExpr = i;
}else{
- sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName);
+ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName);
pParse->checkSchema = 1;
goto update_cleanup;
}
@@ -121617,7 +138107,34 @@ SQLITE_PRIVATE void sqlite3Update(
assert( chngPk==0 || chngPk==1 );
chngKey = chngRowid + chngPk;
- /* The SET expressions are not actually used inside the WHERE loop.
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ /* Mark generated columns as changing if their generator expressions
+ ** reference any changing column. The actual aXRef[] value for
+ ** generated expressions is not used, other than to check to see that it
+ ** is non-negative, so the value of aXRef[] for generated columns can be
+ ** set to any non-negative number. We use 99999 so that the value is
+ ** obvious when looking at aXRef[] in a symbolic debugger.
+ */
+ if( pTab->tabFlags & TF_HasGenerated ){
+ int bProgress;
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ do{
+ bProgress = 0;
+ for(i=0; i<pTab->nCol; i++){
+ if( aXRef[i]>=0 ) continue;
+ if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue;
+ if( sqlite3ExprReferencesUpdatedColumn(pTab->aCol[i].pDflt,
+ aXRef, chngRowid) ){
+ aXRef[i] = 99999;
+ bProgress = 1;
+ }
+ }
+ }while( bProgress );
+ }
+#endif
+
+ /* The SET expressions are not actually used inside the WHERE loop.
** So reset the colUsed mask. Unless this is a virtual table. In that
** case, set all bits of the colUsed mask (to ensure that the virtual
** table implementation makes all columns available).
@@ -121629,36 +138146,50 @@ SQLITE_PRIVATE void sqlite3Update(
/* There is one entry in the aRegIdx[] array for each index on the table
** being updated. Fill in aRegIdx[] with a register number that will hold
** the key for accessing each index.
- **
- ** FIXME: Be smarter about omitting indexes that use expressions.
*/
- for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
+ if( onError==OE_Replace ) bReplace = 1;
+ for(nAllIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nAllIdx++){
int reg;
- if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
+ if( chngKey || hasFK>1 || pIdx==pPk
+ || indexWhereClauseMightChange(pIdx,aXRef,chngRowid)
+ ){
reg = ++pParse->nMem;
+ pParse->nMem += pIdx->nColumn;
}else{
reg = 0;
for(i=0; i<pIdx->nKeyCol; i++){
- i16 iIdxCol = pIdx->aiColumn[i];
- if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
+ if( indexColumnIsBeingUpdated(pIdx, i, aXRef, chngRowid) ){
reg = ++pParse->nMem;
+ pParse->nMem += pIdx->nColumn;
+ if( onError==OE_Default && pIdx->onError==OE_Replace ){
+ bReplace = 1;
+ }
break;
}
}
}
- if( reg==0 ) aToOpen[j+1] = 0;
- aRegIdx[j] = reg;
+ if( reg==0 ) aToOpen[nAllIdx+1] = 0;
+ aRegIdx[nAllIdx] = reg;
+ }
+ aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */
+ if( bReplace ){
+ /* If REPLACE conflict resolution might be invoked, open cursors on all
+ ** indexes in case they are needed to delete records. */
+ memset(aToOpen, 1, nIdx+1);
}
- /* Begin generating code. */
- v = sqlite3GetVdbe(pParse);
- if( v==0 ) goto update_cleanup;
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
- sqlite3BeginWriteOperation(pParse, 1, iDb);
+ sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb);
/* Allocate required registers. */
if( !IsVirtual(pTab) ){
- regRowSet = ++pParse->nMem;
+ /* For now, regRowSet and aRegIdx[nAllIdx] share the same register.
+ ** If regRowSet turns out to be needed, then aRegIdx[nAllIdx] will be
+ ** reallocated. aRegIdx[nAllIdx] is the register in which the main
+ ** table record is written. regRowSet holds the RowSet for the
+ ** two-pass update algorithm. */
+ assert( aRegIdx[nAllIdx]==pParse->nMem );
+ regRowSet = aRegIdx[nAllIdx];
regOldRowid = regNewRowid = ++pParse->nMem;
if( chngPk || pTrigger || hasFK ){
regOld = pParse->nMem + 1;
@@ -121680,15 +138211,19 @@ SQLITE_PRIVATE void sqlite3Update(
** an ephemeral table.
*/
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
- if( isView ){
- sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
+ if( nChangeFrom==0 && isView ){
+ sqlite3MaterializeView(pParse, pTab,
+ pWhere, pOrderBy, pLimit, iDataCur
+ );
+ pOrderBy = 0;
+ pLimit = 0;
}
#endif
/* Resolve the column names in all the expressions in the
** WHERE clause.
*/
- if( sqlite3ResolveExprNames(&sNC, pWhere) ){
+ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){
goto update_cleanup;
}
@@ -121701,127 +138236,223 @@ SQLITE_PRIVATE void sqlite3Update(
}
#endif
- /* Begin the database scan
- */
- if( HasRowid(pTab) ){
+ /* Jump to labelBreak to abandon further processing of this UPDATE */
+ labelContinue = labelBreak = sqlite3VdbeMakeLabel(pParse);
+
+ /* Not an UPSERT. Normal processing. Begin by
+ ** initialize the count of updated rows */
+ if( (db->flags&SQLITE_CountRows)!=0
+ && !pParse->pTriggerTab
+ && !pParse->nested
+ && pUpsert==0
+ ){
+ regRowCount = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
+ }
+
+ if( nChangeFrom==0 && HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
- pWInfo = sqlite3WhereBegin(
- pParse, pTabList, pWhere, 0, 0,
- WHERE_ONEPASS_DESIRED | WHERE_SEEK_TABLE, iIdxCur
- );
- if( pWInfo==0 ) goto update_cleanup;
- okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
-
- /* Remember the rowid of every item to be updated.
- */
- sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
- if( !okOnePass ){
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
- }
-
- /* End the database scan loop.
- */
- sqlite3WhereEnd(pWInfo);
}else{
- int iPk; /* First of nPk memory cells holding PRIMARY KEY value */
- i16 nPk; /* Number of components of the PRIMARY KEY */
- int addrOpen; /* Address of the OpenEphemeral instruction */
-
- assert( pPk!=0 );
- nPk = pPk->nKeyCol;
+ assert( pPk!=0 || HasRowid(pTab) );
+ nPk = pPk ? pPk->nKeyCol : 0;
iPk = pParse->nMem+1;
pParse->nMem += nPk;
+ pParse->nMem += nChangeFrom;
regKey = ++pParse->nMem;
- iEph = pParse->nTab++;
- sqlite3VdbeAddOp2(v, OP_Null, 0, iPk);
- addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
- WHERE_ONEPASS_DESIRED, iIdxCur);
- if( pWInfo==0 ) goto update_cleanup;
- okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
- for(i=0; i<nPk; i++){
- assert( pPk->aiColumn[i]>=0 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
- iPk+i);
- }
- if( okOnePass ){
- sqlite3VdbeChangeToNoop(v, addrOpen);
- nKey = nPk;
- regKey = iPk;
- }else{
- sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
- sqlite3IndexAffinityStr(db, pPk), nPk);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
+ if( pUpsert==0 ){
+ int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0);
+ iEph = pParse->nTab++;
+ if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
+ addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol);
+ if( pPk ){
+ KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk);
+ if( pKeyInfo ){
+ pKeyInfo->nAllField = nEphCol;
+ sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
+ }
+ }
+ if( nChangeFrom ){
+ updateFromSelect(
+ pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit
+ );
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( isView ) iDataCur = iEph;
+#endif
+ }
}
- sqlite3WhereEnd(pWInfo);
- }
-
- /* Initialize the count of updated rows
- */
- if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){
- regRowCount = ++pParse->nMem;
- sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
}
- labelBreak = sqlite3VdbeMakeLabel(v);
- if( !isView ){
- /*
- ** Open every index that needs updating. Note that if any
- ** index could potentially invoke a REPLACE conflict resolution
- ** action, then we need to open all indices because we might need
- ** to be deleting some records.
- */
- if( onError==OE_Replace ){
- memset(aToOpen, 1, nIdx+1);
+ if( nChangeFrom ){
+ sqlite3MultiWrite(pParse);
+ eOnePass = ONEPASS_OFF;
+ nKey = nPk;
+ regKey = iPk;
+ }else{
+ if( pUpsert ){
+ /* If this is an UPSERT, then all cursors have already been opened by
+ ** the outer INSERT and the data cursor should be pointing at the row
+ ** that is to be updated. So bypass the code that searches for the
+ ** row(s) to be updated.
+ */
+ pWInfo = 0;
+ eOnePass = ONEPASS_SINGLE;
+ sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
+ bFinishSeek = 0;
}else{
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->onError==OE_Replace ){
- memset(aToOpen, 1, nIdx+1);
- break;
+ /* Begin the database scan.
+ **
+ ** Do not consider a single-pass strategy for a multi-row update if
+ ** there are any triggers or foreign keys to process, or rows may
+ ** be deleted as a result of REPLACE conflict handling. Any of these
+ ** things might disturb a cursor being used to scan through the table
+ ** or index, causing a single-pass approach to malfunction. */
+ flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
+ if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+ flags |= WHERE_ONEPASS_MULTIROW;
+ }
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags,iIdxCur);
+ if( pWInfo==0 ) goto update_cleanup;
+
+ /* A one-pass strategy that might update more than one row may not
+ ** be used if any column of the index used for the scan is being
+ ** updated. Otherwise, if there is an index on "b", statements like
+ ** the following could create an infinite loop:
+ **
+ ** UPDATE t1 SET b=b+1 WHERE b>?
+ **
+ ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
+ ** strategy that uses an index for which one or more columns are being
+ ** updated. */
+ eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
+ bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
+ if( eOnePass!=ONEPASS_SINGLE ){
+ sqlite3MultiWrite(pParse);
+ if( eOnePass==ONEPASS_MULTI ){
+ int iCur = aiCurOnePass[1];
+ if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
+ eOnePass = ONEPASS_OFF;
+ }
+ assert( iCur!=iDataCur || !HasRowid(pTab) );
}
}
}
- if( okOnePass ){
- if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
- if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
+
+ if( HasRowid(pTab) ){
+ /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
+ ** mode, write the rowid into the FIFO. In either of the one-pass modes,
+ ** leave it in register regOldRowid. */
+ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
+ if( eOnePass==ONEPASS_OFF ){
+ /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
+ aRegIdx[nAllIdx] = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
+ }
+ }else{
+ /* Read the PK of the current row into an array of registers. In
+ ** ONEPASS_OFF mode, serialize the array into a record and store it in
+ ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
+ ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
+ ** is not required) and leave the PK fields in the array of registers. */
+ for(i=0; i<nPk; i++){
+ assert( pPk->aiColumn[i]>=0 );
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
+ pPk->aiColumn[i], iPk+i);
+ }
+ if( eOnePass ){
+ if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
+ nKey = nPk;
+ regKey = iPk;
+ }else{
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
+ sqlite3IndexAffinityStr(db, pPk), nPk);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
+ }
}
- sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen,
- 0, 0);
}
- /* Top of the update loop */
- if( okOnePass ){
- if( aToOpen[iDataCur-iBaseCur] && !isView ){
- assert( pPk );
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
- VdbeCoverageNeverTaken(v);
+ if( pUpsert==0 ){
+ if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){
+ sqlite3WhereEnd(pWInfo);
+ }
+
+ if( !isView ){
+ int addrOnce = 0;
+
+ /* Open every index that needs updating. */
+ if( eOnePass!=ONEPASS_OFF ){
+ if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
+ if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
+ }
+
+ if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+ }
+ sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
+ aToOpen, 0, 0);
+ if( addrOnce ){
+ sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
+ }
+ }
+
+ /* Top of the update loop */
+ if( eOnePass!=ONEPASS_OFF ){
+ if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
+ assert( pPk );
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
+ VdbeCoverage(v);
+ }
+ if( eOnePass!=ONEPASS_SINGLE ){
+ labelContinue = sqlite3VdbeMakeLabel(pParse);
+ }
+ sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
+ VdbeCoverageIf(v, pPk==0);
+ VdbeCoverageIf(v, pPk!=0);
+ }else if( pPk || nChangeFrom ){
+ labelContinue = sqlite3VdbeMakeLabel(pParse);
+ sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
+ addrTop = sqlite3VdbeCurrentAddr(v);
+ if( nChangeFrom ){
+ if( !isView ){
+ if( pPk ){
+ for(i=0; i<nPk; i++){
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, i, iPk+i);
+ }
+ sqlite3VdbeAddOp4Int(
+ v, OP_NotFound, iDataCur, labelContinue, iPk, nPk
+ ); VdbeCoverage(v);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
+ sqlite3VdbeAddOp3(
+ v, OP_NotExists, iDataCur, labelContinue, regOldRowid
+ ); VdbeCoverage(v);
+ }
+ }
+ }else{
+ sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0);
+ VdbeCoverage(v);
+ }
+ }else{
+ labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
+ regOldRowid);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
+ VdbeCoverage(v);
}
- labelContinue = labelBreak;
- sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
- VdbeCoverageIf(v, pPk==0);
- VdbeCoverageIf(v, pPk!=0);
- }else if( pPk ){
- labelContinue = sqlite3VdbeMakeLabel(v);
- sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
- addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
- VdbeCoverage(v);
- }else{
- labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, labelBreak,
- regOldRowid);
- VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
- VdbeCoverage(v);
}
- /* If the record number will change, set register regNewRowid to
- ** contain the new value. If the record number is not being modified,
+ /* If the rowid value will change, set register regNewRowid to
+ ** contain the new value. If the rowid is not being modified,
** then regNewRowid is the same register as regOldRowid, which is
** already populated. */
assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid );
if( chngRowid ){
- sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
+ assert( iRowidExpr>=0 );
+ if( nChangeFrom==0 ){
+ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid);
+ }
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v);
}
@@ -121829,18 +138460,20 @@ SQLITE_PRIVATE void sqlite3Update(
** information is needed */
if( chngPk || hasFK || pTrigger ){
u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
- oldmask |= sqlite3TriggerColmask(pParse,
+ oldmask |= sqlite3TriggerColmask(pParse,
pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
);
for(i=0; i<pTab->nCol; i++){
+ u32 colFlags = pTab->aCol[i].colFlags;
+ k = sqlite3TableColumnToStorage(pTab, i) + regOld;
if( oldmask==0xffffffff
|| (i<32 && (oldmask & MASKBIT32(i))!=0)
- || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0
+ || (colFlags & COLFLAG_PRIMKEY)!=0
){
testcase( oldmask!=0xffffffff && i==31 );
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
}else{
- sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, k);
}
}
if( chngRowid==0 && pPk==0 ){
@@ -121856,101 +138489,142 @@ SQLITE_PRIVATE void sqlite3Update(
** If there are one or more BEFORE triggers, then do not populate the
** registers associated with columns that are (a) not modified by
** this UPDATE statement and (b) not accessed by new.* references. The
- ** values for registers not modified by the UPDATE must be reloaded from
- ** the database after the BEFORE triggers are fired anyway (as the trigger
+ ** values for registers not modified by the UPDATE must be reloaded from
+ ** the database after the BEFORE triggers are fired anyway (as the trigger
** may have modified them). So not loading those that are not going to
** be used eliminates some redundant opcodes.
*/
newmask = sqlite3TriggerColmask(
pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
);
- for(i=0; i<pTab->nCol; i++){
+ for(i=0, k=regNew; i<pTab->nCol; i++, k++){
if( i==pTab->iPKey ){
- sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, k);
+ }else if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)!=0 ){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
}else{
j = aXRef[i];
if( j>=0 ){
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i);
+ if( nChangeFrom ){
+ int nOff = (isView ? pTab->nCol : nPk);
+ assert( eOnePass==ONEPASS_OFF );
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k);
+ }else{
+ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
+ }
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
- /* This branch loads the value of a column that will not be changed
+ /* This branch loads the value of a column that will not be changed
** into a register. This is done if there are no BEFORE triggers, or
** if there are one or more BEFORE triggers that use this value via
** a new.* reference in a trigger program.
*/
testcase( i==31 );
testcase( i==32 );
- sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
+ bFinishSeek = 0;
}else{
- sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, k);
}
}
}
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
+ }
+#endif
/* Fire any BEFORE UPDATE triggers. This happens before constraints are
** verified. One could argue that this is wrong.
*/
if( tmask&TRIGGER_BEFORE ){
sqlite3TableAffinity(v, pTab, regNew);
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue);
- /* The row-trigger may have deleted the row being updated. In this
- ** case, jump to the next row. No updates or AFTER triggers are
- ** required. This behavior - what happens when the row being updated
- ** is deleted or renamed by a BEFORE trigger - is left undefined in the
- ** documentation.
- */
- if( pPk ){
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
- VdbeCoverage(v);
- }else{
- sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
- VdbeCoverage(v);
- }
+ if( !isView ){
+ /* The row-trigger may have deleted the row being updated. In this
+ ** case, jump to the next row. No updates or AFTER triggers are
+ ** required. This behavior - what happens when the row being updated
+ ** is deleted or renamed by a BEFORE trigger - is left undefined in the
+ ** documentation.
+ */
+ if( pPk ){
+ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey);
+ VdbeCoverage(v);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
+ VdbeCoverage(v);
+ }
- /* If it did not delete it, the row-trigger may still have modified
- ** some of the columns of the row being updated. Load the values for
- ** all columns not modified by the update statement into their
- ** registers in case this has happened.
- */
- for(i=0; i<pTab->nCol; i++){
- if( aXRef[i]<0 && i!=pTab->iPKey ){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
+ /* After-BEFORE-trigger-reload-loop:
+ ** If it did not delete it, the BEFORE trigger may still have modified
+ ** some of the columns of the row being updated. Load the values for
+ ** all columns not modified by the update statement into their registers
+ ** in case this has happened. Only unmodified columns are reloaded.
+ ** The values computed for modified columns use the values before the
+ ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
+ ** for an example.
+ */
+ for(i=0, k=regNew; i<pTab->nCol; i++, k++){
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
+ }else if( aXRef[i]<0 && i!=pTab->iPKey ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
+ }
+ }
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ if( pTab->tabFlags & TF_HasGenerated ){
+ testcase( pTab->tabFlags & TF_HasVirtual );
+ testcase( pTab->tabFlags & TF_HasStored );
+ sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
}
+#endif
}
}
if( !isView ){
- int addr1 = 0; /* Address of jump instruction */
- int bReplace = 0; /* True if REPLACE conflict resolution might happen */
-
/* Do constraint checks. */
assert( regOldRowid>0 );
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace,
- aXRef);
-
- /* Do FK constraint checks. */
- if( hasFK ){
- sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
- }
+ aXRef, 0);
- /* Delete the index entries associated with the current record. */
+ /* If REPLACE conflict handling may have been used, or if the PK of the
+ ** row is changing, then the GenerateConstraintChecks() above may have
+ ** moved cursor iDataCur. Reseek it. */
if( bReplace || chngKey ){
if( pPk ){
- addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
+ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey);
}else{
- addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
}
VdbeCoverageNeverTaken(v);
}
+
+ /* Do FK constraint checks. */
+ if( hasFK ){
+ sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey);
+ }
+
+ /* Delete the index entries associated with the current record. */
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
+ /* We must run the OP_FinishSeek opcode to resolve a prior
+ ** OP_DeferredSeek if there is any possibility that there have been
+ ** no OP_Column opcodes since the OP_DeferredSeek was issued. But
+ ** we want to avoid the OP_FinishSeek if possible, as running it
+ ** costs CPU cycles. */
+ if( bFinishSeek ){
+ sqlite3VdbeAddOp1(v, OP_FinishSeek, iDataCur);
+ }
+
/* If changing the rowid value, or if there are foreign key constraints
** to process, delete the old record. Otherwise, add a noop OP_Delete
** to invoke the pre-update hook.
**
- ** That (regNew==regnewRowid+1) is true is also important for the
+ ** That (regNew==regnewRowid+1) is true is also important for the
** pre-update hook. If the caller invokes preupdate_new(), the returned
** value is copied from memory cell (regNewRowid+1+iCol), where iCol
** is the column index supplied by the user.
@@ -121958,52 +138632,59 @@ SQLITE_PRIVATE void sqlite3Update(
assert( regNew==regNewRowid+1 );
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
- OPFLAG_ISUPDATE | ((hasFK || chngKey || pPk!=0) ? 0 : OPFLAG_ISNOOP),
+ OPFLAG_ISUPDATE | ((hasFK>1 || chngKey) ? 0 : OPFLAG_ISNOOP),
regNewRowid
);
+ if( eOnePass==ONEPASS_MULTI ){
+ assert( hasFK==0 && chngKey==0 );
+ sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
+ }
if( !pParse->nested ){
- sqlite3VdbeChangeP4(v, -1, (char*)pTab, P4_TABLE);
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
#else
- if( hasFK || chngKey || pPk!=0 ){
+ if( hasFK>1 || chngKey ){
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
}
#endif
- if( bReplace || chngKey ){
- sqlite3VdbeJumpHere(v, addr1);
- }
if( hasFK ){
sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey);
}
-
+
/* Insert the new index entries and the new record. */
- sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
- regNewRowid, aRegIdx, 1, 0, 0);
+ sqlite3CompleteInsertion(
+ pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx,
+ OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0),
+ 0, 0
+ );
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
** handle rows (possibly in other tables) that refer via a foreign key
- ** to the row just updated. */
+ ** to the row just updated. */
if( hasFK ){
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey);
}
}
- /* Increment the row counter
+ /* Increment the row counter
*/
- if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){
+ if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
*/
- if( okOnePass ){
+ if( eOnePass==ONEPASS_SINGLE ){
/* Nothing to do at end-of-loop for a single-pass */
- }else if( pPk ){
+ }else if( eOnePass==ONEPASS_MULTI ){
+ sqlite3VdbeResolveLabel(v, labelContinue);
+ sqlite3WhereEnd(pWInfo);
+ }else if( pPk || nChangeFrom ){
sqlite3VdbeResolveLabel(v, labelContinue);
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
}else{
@@ -122011,29 +138692,19 @@ SQLITE_PRIVATE void sqlite3Update(
}
sqlite3VdbeResolveLabel(v, labelBreak);
- /* Close all tables */
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- assert( aRegIdx );
- if( aToOpen[i+1] ){
- sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0);
- }
- }
- if( iDataCur<iIdxCur ) sqlite3VdbeAddOp2(v, OP_Close, iDataCur, 0);
-
/* Update the sqlite_sequence table by storing the content of the
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
*/
- if( pParse->nested==0 && pParse->pTriggerTab==0 ){
+ if( pParse->nested==0 && pParse->pTriggerTab==0 && pUpsert==0 ){
sqlite3AutoincrementEnd(pParse);
}
/*
- ** Return the number of rows that were changed. If this routine is
- ** generating code because of a call to sqlite3NestedParse(), do not
- ** invoke the callback function.
+ ** Return the number of rows that were changed, if we are tracking
+ ** that information.
*/
- if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){
+ if( regRowCount ){
sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
@@ -122045,6 +138716,10 @@ update_cleanup:
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pChanges);
sqlite3ExprDelete(db, pWhere);
+#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
+ sqlite3ExprListDelete(db, pOrderBy);
+ sqlite3ExprDelete(db, pLimit);
+#endif
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -122061,8 +138736,8 @@ update_cleanup:
/*
** Generate code for an UPDATE of a virtual table.
**
-** There are two possible strategies - the default and the special
-** "onepass" strategy. Onepass is only used if the virtual table
+** There are two possible strategies - the default and the special
+** "onepass" strategy. Onepass is only used if the virtual table
** implementation indicates that pWhere may match at most one row.
**
** The default strategy is to create an ephemeral table that contains
@@ -122094,17 +138769,17 @@ static void updateVirtualTable(
int i; /* Loop counter */
sqlite3 *db = pParse->db; /* Database connection */
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
- WhereInfo *pWInfo;
+ WhereInfo *pWInfo = 0;
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
int regRowid; /* Register for ephem table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
- int bOnePass; /* True to use onepass strategy */
+ int eOnePass; /* True to use onepass strategy */
int addr; /* Address of OP_OpenEphemeral */
- /* Allocate nArg registers to martial the arguments to VUpdate. Then
+ /* Allocate nArg registers in which to gather the arguments for VUpdate. Then
** create and open the ephemeral table in which the records created from
** these arguments will be temporarily stored. */
assert( v );
@@ -122112,55 +138787,101 @@ static void updateVirtualTable(
addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
regArg = pParse->nMem + 1;
pParse->nMem += nArg;
- regRec = ++pParse->nMem;
- regRowid = ++pParse->nMem;
+ if( pSrc->nSrc>1 ){
+ Expr *pRow;
+ ExprList *pList;
+ if( pRowid ){
+ pRow = sqlite3ExprDup(db, pRowid, 0);
+ }else{
+ pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0);
+ }
+ pList = sqlite3ExprListAppend(pParse, 0, pRow);
- /* Start scanning the virtual table */
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
- if( pWInfo==0 ) return;
+ for(i=0; i<pTab->nCol; i++){
+ if( aXRef[i]>=0 ){
+ pList = sqlite3ExprListAppend(pParse, pList,
+ sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
+ );
+ }else{
+ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ }
+ }
- /* Populate the argument registers. */
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
- if( pRowid ){
- sqlite3ExprCode(pParse, pRowid, regArg+1);
+ updateFromSelect(pParse, ephemTab, 0, pList, pSrc, pWhere, 0, 0);
+ sqlite3ExprListDelete(db, pList);
+ eOnePass = ONEPASS_OFF;
}else{
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
- }
- for(i=0; i<pTab->nCol; i++){
- if( aXRef[i]>=0 ){
- sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
+ regRec = ++pParse->nMem;
+ regRowid = ++pParse->nMem;
+
+ /* Start scanning the virtual table */
+ pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,WHERE_ONEPASS_DESIRED,0);
+ if( pWInfo==0 ) return;
+
+ /* Populate the argument registers. */
+ for(i=0; i<pTab->nCol; i++){
+ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
+ if( aXRef[i]>=0 ){
+ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */
+ }
+ }
+ if( HasRowid(pTab) ){
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
+ if( pRowid ){
+ sqlite3ExprCode(pParse, pRowid, regArg+1);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
+ }
}else{
- sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
+ Index *pPk; /* PRIMARY KEY index */
+ i16 iPk; /* PRIMARY KEY column */
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ assert( pPk->nKeyCol==1 );
+ iPk = pPk->aiColumn[0];
+ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
}
- }
- bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
+ eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
- if( bOnePass ){
- /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
- ** above. Also, if this is a top-level parse (not a trigger), clear the
- ** multi-write flag so that the VM does not open a statement journal */
- sqlite3VdbeChangeToNoop(v, addr);
- if( sqlite3IsToplevel(pParse) ){
- pParse->isMultiWrite = 0;
+ /* There is no ONEPASS_MULTI on virtual tables */
+ assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
+
+ if( eOnePass ){
+ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
+ ** above. */
+ sqlite3VdbeChangeToNoop(v, addr);
+ sqlite3VdbeAddOp1(v, OP_Close, iCsr);
+ }else{
+ /* Create a record from the argument register contents and insert it into
+ ** the ephemeral table. */
+ sqlite3MultiWrite(pParse);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM)
+ /* Signal an assert() within OP_MakeRecord that it is allowed to
+ ** accept no-change records with serial_type 10 */
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
+#endif
+ sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
}
- }else{
- /* Create a record from the argument register contents and insert it into
- ** the ephemeral table. */
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
- sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
- sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
}
- if( bOnePass==0 ){
+ if( eOnePass==ONEPASS_OFF ){
/* End the virtual table scan */
- sqlite3WhereEnd(pWInfo);
+ if( pSrc->nSrc==1 ){
+ sqlite3WhereEnd(pWInfo);
+ }
/* Begin scannning through the ephemeral table. */
addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
- /* Extract arguments from the current row of the ephemeral table and
+ /* Extract arguments from the current row of the ephemeral table and
** invoke the VUpdate method. */
for(i=0; i<nArg; i++){
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i);
@@ -122173,7 +138894,7 @@ static void updateVirtualTable(
/* End of the ephemeral table scan. Or, if using the onepass strategy,
** jump to here if the scan visited zero rows. */
- if( bOnePass==0 ){
+ if( eOnePass==ONEPASS_OFF ){
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
@@ -122184,6 +138905,268 @@ static void updateVirtualTable(
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/************** End of update.c **********************************************/
+/************** Begin file upsert.c ******************************************/
+/*
+** 2018-04-12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file contains code to implement various aspects of UPSERT
+** processing and handling of the Upsert object.
+*/
+/* #include "sqliteInt.h" */
+
+#ifndef SQLITE_OMIT_UPSERT
+/*
+** Free a list of Upsert objects
+*/
+SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
+ if( p ){
+ sqlite3ExprListDelete(db, p->pUpsertTarget);
+ sqlite3ExprDelete(db, p->pUpsertTargetWhere);
+ sqlite3ExprListDelete(db, p->pUpsertSet);
+ sqlite3ExprDelete(db, p->pUpsertWhere);
+ sqlite3DbFree(db, p);
+ }
+}
+
+/*
+** Duplicate an Upsert object.
+*/
+SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
+ if( p==0 ) return 0;
+ return sqlite3UpsertNew(db,
+ sqlite3ExprListDup(db, p->pUpsertTarget, 0),
+ sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
+ sqlite3ExprListDup(db, p->pUpsertSet, 0),
+ sqlite3ExprDup(db, p->pUpsertWhere, 0)
+ );
+}
+
+/*
+** Create a new Upsert object.
+*/
+SQLITE_PRIVATE Upsert *sqlite3UpsertNew(
+ sqlite3 *db, /* Determines which memory allocator to use */
+ ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
+ Expr *pTargetWhere, /* Optional WHERE clause on the target */
+ ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
+ Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */
+){
+ Upsert *pNew;
+ pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
+ if( pNew==0 ){
+ sqlite3ExprListDelete(db, pTarget);
+ sqlite3ExprDelete(db, pTargetWhere);
+ sqlite3ExprListDelete(db, pSet);
+ sqlite3ExprDelete(db, pWhere);
+ return 0;
+ }else{
+ pNew->pUpsertTarget = pTarget;
+ pNew->pUpsertTargetWhere = pTargetWhere;
+ pNew->pUpsertSet = pSet;
+ pNew->pUpsertWhere = pWhere;
+ pNew->pUpsertIdx = 0;
+ }
+ return pNew;
+}
+
+/*
+** Analyze the ON CONFLICT clause described by pUpsert. Resolve all
+** symbols in the conflict-target.
+**
+** Return SQLITE_OK if everything works, or an error code is something
+** is wrong.
+*/
+SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
+ Parse *pParse, /* The parsing context */
+ SrcList *pTabList, /* Table into which we are inserting */
+ Upsert *pUpsert /* The ON CONFLICT clauses */
+){
+ Table *pTab; /* That table into which we are inserting */
+ int rc; /* Result code */
+ int iCursor; /* Cursor used by pTab */
+ Index *pIdx; /* One of the indexes of pTab */
+ ExprList *pTarget; /* The conflict-target clause */
+ Expr *pTerm; /* One term of the conflict-target clause */
+ NameContext sNC; /* Context for resolving symbolic names */
+ Expr sCol[2]; /* Index column converted into an Expr */
+
+ assert( pTabList->nSrc==1 );
+ assert( pTabList->a[0].pTab!=0 );
+ assert( pUpsert!=0 );
+ assert( pUpsert->pUpsertTarget!=0 );
+
+ /* Resolve all symbolic names in the conflict-target clause, which
+ ** includes both the list of columns and the optional partial-index
+ ** WHERE clause.
+ */
+ memset(&sNC, 0, sizeof(sNC));
+ sNC.pParse = pParse;
+ sNC.pSrcList = pTabList;
+ rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
+ if( rc ) return rc;
+ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
+ if( rc ) return rc;
+
+ /* Check to see if the conflict target matches the rowid. */
+ pTab = pTabList->a[0].pTab;
+ pTarget = pUpsert->pUpsertTarget;
+ iCursor = pTabList->a[0].iCursor;
+ if( HasRowid(pTab)
+ && pTarget->nExpr==1
+ && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
+ && pTerm->iColumn==XN_ROWID
+ ){
+ /* The conflict-target is the rowid of the primary table */
+ assert( pUpsert->pUpsertIdx==0 );
+ return SQLITE_OK;
+ }
+
+ /* Initialize sCol[0..1] to be an expression parse tree for a
+ ** single column of an index. The sCol[0] node will be the TK_COLLATE
+ ** operator and sCol[1] will be the TK_COLUMN operator. Code below
+ ** will populate the specific collation and column number values
+ ** prior to comparing against the conflict-target expression.
+ */
+ memset(sCol, 0, sizeof(sCol));
+ sCol[0].op = TK_COLLATE;
+ sCol[0].pLeft = &sCol[1];
+ sCol[1].op = TK_COLUMN;
+ sCol[1].iTable = pTabList->a[0].iCursor;
+
+ /* Check for matches against other indexes */
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ int ii, jj, nn;
+ if( !IsUniqueIndex(pIdx) ) continue;
+ if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
+ if( pIdx->pPartIdxWhere ){
+ if( pUpsert->pUpsertTargetWhere==0 ) continue;
+ if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
+ pIdx->pPartIdxWhere, iCursor)!=0 ){
+ continue;
+ }
+ }
+ nn = pIdx->nKeyCol;
+ for(ii=0; ii<nn; ii++){
+ Expr *pExpr;
+ sCol[0].u.zToken = (char*)pIdx->azColl[ii];
+ if( pIdx->aiColumn[ii]==XN_EXPR ){
+ assert( pIdx->aColExpr!=0 );
+ assert( pIdx->aColExpr->nExpr>ii );
+ pExpr = pIdx->aColExpr->a[ii].pExpr;
+ if( pExpr->op!=TK_COLLATE ){
+ sCol[0].pLeft = pExpr;
+ pExpr = &sCol[0];
+ }
+ }else{
+ sCol[0].pLeft = &sCol[1];
+ sCol[1].iColumn = pIdx->aiColumn[ii];
+ pExpr = &sCol[0];
+ }
+ for(jj=0; jj<nn; jj++){
+ if( sqlite3ExprCompare(pParse, pTarget->a[jj].pExpr, pExpr,iCursor)<2 ){
+ break; /* Column ii of the index matches column jj of target */
+ }
+ }
+ if( jj>=nn ){
+ /* The target contains no match for column jj of the index */
+ break;
+ }
+ }
+ if( ii<nn ){
+ /* Column ii of the index did not match any term of the conflict target.
+ ** Continue the search with the next index. */
+ continue;
+ }
+ pUpsert->pUpsertIdx = pIdx;
+ return SQLITE_OK;
+ }
+ sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any "
+ "PRIMARY KEY or UNIQUE constraint");
+ return SQLITE_ERROR;
+}
+
+/*
+** Generate bytecode that does an UPDATE as part of an upsert.
+**
+** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK.
+** In this case parameter iCur is a cursor open on the table b-tree that
+** currently points to the conflicting table row. Otherwise, if pIdx
+** is not NULL, then pIdx is the constraint that failed and iCur is a
+** cursor points to the conflicting row.
+*/
+SQLITE_PRIVATE void sqlite3UpsertDoUpdate(
+ Parse *pParse, /* The parsing and code-generating context */
+ Upsert *pUpsert, /* The ON CONFLICT clause for the upsert */
+ Table *pTab, /* The table being updated */
+ Index *pIdx, /* The UNIQUE constraint that failed */
+ int iCur /* Cursor for pIdx (or pTab if pIdx==NULL) */
+){
+ Vdbe *v = pParse->pVdbe;
+ sqlite3 *db = pParse->db;
+ SrcList *pSrc; /* FROM clause for the UPDATE */
+ int iDataCur;
+ int i;
+
+ assert( v!=0 );
+ assert( pUpsert!=0 );
+ VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
+ iDataCur = pUpsert->iDataCur;
+ if( pIdx && iCur!=iDataCur ){
+ if( HasRowid(pTab) ){
+ int regRowid = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
+ VdbeCoverage(v);
+ sqlite3ReleaseTempReg(pParse, regRowid);
+ }else{
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ int nPk = pPk->nKeyCol;
+ int iPk = pParse->nMem+1;
+ pParse->nMem += nPk;
+ for(i=0; i<nPk; i++){
+ int k;
+ assert( pPk->aiColumn[i]>=0 );
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
+ VdbeComment((v, "%s.%s", pIdx->zName,
+ pTab->aCol[pPk->aiColumn[i]].zName));
+ }
+ sqlite3VdbeVerifyAbortable(v, OE_Abort);
+ i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
+ "corrupt database", P4_STATIC);
+ sqlite3MayAbort(pParse);
+ sqlite3VdbeJumpHere(v, i);
+ }
+ }
+ /* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
+ ** we have to make a copy before passing it down into sqlite3Update() */
+ pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
+ /* excluded.* columns of type REAL need to be converted to a hard real */
+ for(i=0; i<pTab->nCol; i++){
+ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, pUpsert->regData+i);
+ }
+ }
+ sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
+ pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
+ pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
+ pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */
+ VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
+}
+
+#endif /* SQLITE_OMIT_UPSERT */
+
+/************** End of upsert.c **********************************************/
/************** Begin file vacuum.c ******************************************/
/*
** 2003 April 6
@@ -122226,8 +139209,14 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
- if( zSubSql ){
- assert( zSubSql[0]!='S' );
+ /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX,
+ ** or INSERT. Historically there have been attacks that first
+ ** corrupt the sqlite_schema.sql field with other kinds of statements
+ ** then run VACUUM to get those statements to execute at inappropriate
+ ** times. */
+ if( zSubSql
+ && (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0)
+ ){
rc = execSql(db, pzErrMsg, zSubSql);
if( rc!=SQLITE_OK ) break;
}
@@ -122283,52 +139272,99 @@ static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
** transient would cause the database file to appear to be deleted
** following reboot.
*/
-SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){
+SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
Vdbe *v = sqlite3GetVdbe(pParse);
- int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0;
- if( v && (iDb>=2 || iDb==0) ){
- sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
+ int iDb = 0;
+ if( v==0 ) goto build_vacuum_end;
+ if( pParse->nErr ) goto build_vacuum_end;
+ if( pNm ){
+#ifndef SQLITE_BUG_COMPATIBLE_20160819
+ /* Default behavior: Report an error if the argument to VACUUM is
+ ** not recognized */
+ iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm);
+ if( iDb<0 ) goto build_vacuum_end;
+#else
+ /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
+ ** to VACUUM are silently ignored. This is a back-out of a bug fix that
+ ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270).
+ ** The buggy behavior is required for binary compatibility with some
+ ** legacy applications. */
+ iDb = sqlite3FindDb(pParse->db, pNm);
+ if( iDb<0 ) iDb = 0;
+#endif
+ }
+ if( iDb!=1 ){
+ int iIntoReg = 0;
+ if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){
+ iIntoReg = ++pParse->nMem;
+ sqlite3ExprCode(pParse, pInto, iIntoReg);
+ }
+ sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg);
sqlite3VdbeUsesBtree(v, iDb);
}
+build_vacuum_end:
+ sqlite3ExprDelete(pParse->db, pInto);
return;
}
/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
-SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
+ char **pzErrMsg, /* Write error message here */
+ sqlite3 *db, /* Database connection */
+ int iDb, /* Which attached DB to vacuum */
+ sqlite3_value *pOut /* Write results here, if not NULL. VACUUM INTO */
+){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
- int saved_flags; /* Saved value of the db->flags */
+ u32 saved_mDbFlags; /* Saved value of db->mDbFlags */
+ u64 saved_flags; /* Saved value of db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
+ u32 saved_openFlags; /* Saved value of db->openFlags */
u8 saved_mTrace; /* Saved trace settings */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes; /* Bytes of reserved space at the end of each page */
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
+ const char *zOut; /* Name of output file */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
- return SQLITE_ERROR;
+ return SQLITE_ERROR; /* IMP: R-12218-18073 */
}
if( db->nVdbeActive>1 ){
sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
- return SQLITE_ERROR;
+ return SQLITE_ERROR; /* IMP: R-15610-35227 */
+ }
+ saved_openFlags = db->openFlags;
+ if( pOut ){
+ if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){
+ sqlite3SetString(pzErrMsg, db, "non-text filename");
+ return SQLITE_ERROR;
+ }
+ zOut = (const char*)sqlite3_value_text(pOut);
+ db->openFlags &= ~SQLITE_OPEN_READONLY;
+ db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
+ }else{
+ zOut = "";
}
- /* Save the current value of the database flags so that it can be
+ /* Save the current value of the database flags so that it can be
** restored before returning. Then set the writable-schema flag, and
** disable CHECK and foreign key constraints. */
saved_flags = db->flags;
+ saved_mDbFlags = db->mDbFlags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
- db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
- | SQLITE_PreferBuiltin | SQLITE_Vacuum);
- db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
+ db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
+ db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
+ db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
+ | SQLITE_Defensive | SQLITE_CountRows);
db->mTrace = 0;
zDbMain = db->aDb[iDb].zDbSName;
@@ -122350,31 +139386,24 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
** to write the journal header file.
*/
nDb = db->nDb;
- rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
+ rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
+ db->openFlags = saved_openFlags;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
assert( (db->nDb-1)==nDb );
pDb = &db->aDb[nDb];
assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
pTemp = pDb->pBt;
-
- /* The call to execSql() to attach the temp database has left the file
- ** locked (as there was more than one active statement when the transaction
- ** to read the schema was concluded. Unlock it here so that this doesn't
- ** cause problems for the call to BtreeSetPageSize() below. */
- sqlite3BtreeCommit(pTemp);
-
- nRes = sqlite3BtreeGetOptimalReserve(pMain);
-
- /* A VACUUM cannot change the pagesize of an encrypted database. */
-#ifdef SQLITE_HAS_CODEC
- if( db->nextPagesize ){
- extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
- int nKey;
- char *zKey;
- sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- if( nKey ) db->nextPagesize = 0;
+ if( pOut ){
+ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
+ i64 sz = 0;
+ if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
+ rc = SQLITE_ERROR;
+ sqlite3SetString(pzErrMsg, db, "output file already exists");
+ goto end_of_vacuum;
+ }
+ db->mDbFlags |= DBFLAG_VacuumInto;
}
-#endif
+ nRes = sqlite3BtreeGetRequestedReserve(pMain);
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
@@ -122386,7 +139415,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
*/
rc = execSql(db, pzErrMsg, "BEGIN");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = sqlite3BtreeBeginTrans(pMain, 2);
+ rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Do not attempt to change the page size for a WAL database */
@@ -122413,15 +139442,15 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
*/
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
+ "SELECT sql FROM \"%w\".sqlite_schema"
" WHERE type='table'AND name<>'sqlite_sequence'"
" AND coalesce(rootpage,1)>0",
zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execSqlF(db, pzErrMsg,
- "SELECT sql FROM \"%w\".sqlite_master"
- " WHERE type='index' AND length(sql)>10",
+ "SELECT sql FROM \"%w\".sqlite_schema"
+ " WHERE type='index'",
zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
@@ -122434,29 +139463,29 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
rc = execSqlF(db, pzErrMsg,
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
"||' SELECT*FROM\"%w\".'||quote(name)"
- "FROM vacuum_db.sqlite_master "
+ "FROM vacuum_db.sqlite_schema "
"WHERE type='table'AND coalesce(rootpage,1)>0",
zDbMain
);
- assert( (db->flags & SQLITE_Vacuum)!=0 );
- db->flags &= ~SQLITE_Vacuum;
+ assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
+ db->mDbFlags &= ~DBFLAG_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Copy the triggers, views, and virtual tables from the main database
** over to the temporary database. None of these objects has any
** associated storage, so all we have to do is copy their entries
- ** from the SQLITE_MASTER table.
+ ** from the schema table.
*/
rc = execSqlF(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_master"
- " SELECT*FROM \"%w\".sqlite_master"
+ "INSERT INTO vacuum_db.sqlite_schema"
+ " SELECT*FROM \"%w\".sqlite_schema"
" WHERE type IN('view','trigger')"
" OR(type='table'AND rootpage=0)",
zDbMain
);
if( rc ) goto end_of_vacuum;
- /* At this point, there is a write transaction open on both the
+ /* At this point, there is a write transaction open on both the
** vacuum database and the main database. Assuming no error occurs,
** both transactions are closed by this block - the main database
** transaction by sqlite3BtreeCopyFile() and the other by an explicit
@@ -122481,7 +139510,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
};
assert( 1==sqlite3BtreeIsInTrans(pTemp) );
- assert( 1==sqlite3BtreeIsInTrans(pMain) );
+ assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
/* Copy Btree meta values */
for(i=0; i<ArraySize(aCopy); i+=2){
@@ -122492,26 +139521,33 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum;
}
- rc = sqlite3BtreeCopyFile(pMain, pTemp);
+ if( pOut==0 ){
+ rc = sqlite3BtreeCopyFile(pMain, pTemp);
+ }
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeCommit(pTemp);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
#ifndef SQLITE_OMIT_AUTOVACUUM
- sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
+ if( pOut==0 ){
+ sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
+ }
#endif
}
assert( rc==SQLITE_OK );
- rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
+ if( pOut==0 ){
+ rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
+ }
end_of_vacuum:
/* Restore the original value of db->flags */
db->init.iDb = 0;
+ db->mDbFlags = saved_mDbFlags;
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
db->mTrace = saved_mTrace;
- sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
+ sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
@@ -122529,7 +139565,7 @@ end_of_vacuum:
}
/* This both clears the schemas and reduces the size of the db->aDb[]
- ** array. */
+ ** array. */
sqlite3ResetAllSchemasOfConnection(db);
return rc;
@@ -122558,7 +139594,7 @@ end_of_vacuum:
/*
** 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
+** 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.
*/
@@ -122570,6 +139606,57 @@ struct VtabCtx {
};
/*
+** Construct and install a Module object for a virtual table. When this
+** routine is called, it is guaranteed that all appropriate locks are held
+** and the module is not already part of the connection.
+**
+** If there already exists a module with zName, replace it with the new one.
+** If pModule==0, then delete the module zName if it exists.
+*/
+SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
+ sqlite3 *db, /* Database in which module is registered */
+ const char *zName, /* Name assigned to this module */
+ const sqlite3_module *pModule, /* The definition of the module */
+ void *pAux, /* Context pointer for xCreate/xConnect */
+ void (*xDestroy)(void *) /* Module destructor function */
+){
+ Module *pMod;
+ Module *pDel;
+ char *zCopy;
+ if( pModule==0 ){
+ zCopy = (char*)zName;
+ pMod = 0;
+ }else{
+ int nName = sqlite3Strlen30(zName);
+ pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1);
+ if( pMod==0 ){
+ sqlite3OomFault(db);
+ return 0;
+ }
+ zCopy = (char *)(&pMod[1]);
+ memcpy(zCopy, zName, nName+1);
+ pMod->zName = zCopy;
+ pMod->pModule = pModule;
+ pMod->pAux = pAux;
+ pMod->xDestroy = xDestroy;
+ pMod->pEpoTab = 0;
+ pMod->nRefModule = 1;
+ }
+ pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
+ if( pDel ){
+ if( pDel==pMod ){
+ sqlite3OomFault(db);
+ sqlite3DbFree(db, pDel);
+ pMod = 0;
+ }else{
+ sqlite3VtabEponymousTableClear(db, pDel);
+ sqlite3VtabModuleUnref(db, pDel);
+ }
+ }
+ return pMod;
+}
+
+/*
** The actual function that does the work of creating a new module.
** This function implements the sqlite3_create_module() and
** sqlite3_create_module_v2() interfaces.
@@ -122582,35 +139669,11 @@ static int createModule(
void (*xDestroy)(void *) /* Module destructor function */
){
int rc = SQLITE_OK;
- int nName;
sqlite3_mutex_enter(db->mutex);
- nName = sqlite3Strlen30(zName);
- if( sqlite3HashFind(&db->aModule, zName) ){
- rc = SQLITE_MISUSE_BKPT;
- }else{
- Module *pMod;
- pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
- if( pMod ){
- Module *pDel;
- char *zCopy = (char *)(&pMod[1]);
- memcpy(zCopy, zName, nName+1);
- pMod->zName = zCopy;
- pMod->pModule = pModule;
- pMod->pAux = pAux;
- pMod->xDestroy = xDestroy;
- pMod->pEpoTab = 0;
- pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
- assert( pDel==0 || pDel==pMod );
- if( pDel ){
- sqlite3OomFault(db);
- sqlite3DbFree(db, pDel);
- }
- }
- }
+ (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
-
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -122648,9 +139711,47 @@ SQLITE_API int sqlite3_create_module_v2(
}
/*
+** External API to drop all virtual-table modules, except those named
+** on the azNames list.
+*/
+SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){
+ HashElem *pThis, *pNext;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+ for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){
+ Module *pMod = (Module*)sqliteHashData(pThis);
+ pNext = sqliteHashNext(pThis);
+ if( azNames ){
+ int ii;
+ for(ii=0; azNames[ii]!=0 && strcmp(azNames[ii],pMod->zName)!=0; ii++){}
+ if( azNames[ii]!=0 ) continue;
+ }
+ createModule(db, pMod->zName, 0, 0, 0);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Decrement the reference count on a Module object. Destroy the
+** module when the reference count reaches zero.
+*/
+SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){
+ assert( pMod->nRefModule>0 );
+ pMod->nRefModule--;
+ if( pMod->nRefModule==0 ){
+ if( pMod->xDestroy ){
+ pMod->xDestroy(pMod->pAux);
+ }
+ assert( pMod->pEpoTab==0 );
+ sqlite3DbFree(db, pMod);
+ }
+}
+
+/*
** Lock the virtual table so that it cannot be disconnected.
** Locks nest. Every lock should have a corresponding unlock.
-** If an unlock is omitted, resources leaks will occur.
+** If an unlock is omitted, resources leaks will occur.
**
** If a disconnect is attempted while a virtual table is locked,
** the disconnect is deferred until all locks have been removed.
@@ -122662,7 +139763,7 @@ SQLITE_PRIVATE void sqlite3VtabLock(VTable *pVTab){
/*
** pTab is a pointer to a Table structure representing a virtual-table.
-** Return a pointer to the VTable object used by connection db to access
+** Return a pointer to the VTable object used by connection db to access
** this virtual-table, if one has been created, or NULL otherwise.
*/
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
@@ -122686,6 +139787,7 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){
pVTab->nRef--;
if( pVTab->nRef==0 ){
sqlite3_vtab *p = pVTab->pVtab;
+ sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
if( p ){
p->pModule->xDisconnect(p);
}
@@ -122696,7 +139798,7 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){
/*
** Table p is a virtual table. This function moves all elements in the
** p->pVTable list to the sqlite3.pDisconnect lists of their associated
-** database connections to be disconnected at the next opportunity.
+** database connections to be disconnected at the next opportunity.
** Except, if argument db is not NULL, then the entry associated with
** connection db is left in the p->pVTable list.
*/
@@ -122705,8 +139807,8 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
VTable *pVTable = p->pVTable;
p->pVTable = 0;
- /* Assert that the mutex (if any) associated with the BtShared database
- ** that contains table p is held by the caller. See header comments
+ /* Assert that the mutex (if any) associated with the BtShared database
+ ** that contains table p is held by the caller. See header comments
** above function sqlite3VtabUnlockList() for an explanation of why
** this makes it safe to access the sqlite3.pDisconnect list of any
** database connection that may have an entry in the p->pVTable list.
@@ -122762,7 +139864,7 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
**
** This function may only be called when the mutexes associated with all
-** shared b-tree databases opened using connection db are held by the
+** shared b-tree databases opened using connection db are held by the
** caller. This is done to protect the sqlite3.pDisconnect list. The
** sqlite3.pDisconnect list is accessed only as follows:
**
@@ -122775,18 +139877,18 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
** or, if the virtual table is stored in a non-sharable database, then
** the database handle mutex is held.
**
-** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
+** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
** by multiple threads. It is thread-safe.
*/
SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
VTable *p = db->pDisconnect;
- db->pDisconnect = 0;
assert( sqlite3BtreeHoldsAllMutexes(db) );
assert( sqlite3_mutex_held(db->mutex) );
if( p ){
- sqlite3ExpirePreparedStatements(db);
+ db->pDisconnect = 0;
+ sqlite3ExpirePreparedStatements(db, 0);
do {
VTable *pNext = p->pNext;
sqlite3VtabUnlock(p);
@@ -122801,12 +139903,12 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
** record.
**
** Since it is a virtual-table, the Table structure contains a pointer
-** to the head of a linked list of VTable structures. Each VTable
+** to the head of a linked list of VTable structures. Each VTable
** structure is associated with a single sqlite3* user of the schema.
-** The reference count of the VTable structure associated with database
-** connection db is decremented immediately (which may lead to the
+** The reference count of the VTable structure associated with database
+** connection db is decremented immediately (which may lead to the
** structure being xDisconnected and free). Any other VTable structures
-** in the list are moved to the sqlite3.pDisconnect list of the associated
+** in the list are moved to the sqlite3.pDisconnect list of the associated
** database connection.
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
@@ -122826,9 +139928,13 @@ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
** string will be freed automatically when the table is
** deleted.
*/
-static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
- int nBytes = sizeof(char *)*(2+pTable->nModuleArg);
+static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){
+ sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->nModuleArg);
char **azModuleArg;
+ sqlite3 *db = pParse->db;
+ if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){
+ sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName);
+ }
azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
if( azModuleArg==0 ){
sqlite3DbFree(db, zArg);
@@ -122852,7 +139958,6 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
Token *pModuleName, /* Name of the module for the virtual table */
int ifNotExists /* No error if the table already exists */
){
- int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */
sqlite3 *db; /* Database connection */
@@ -122862,14 +139967,11 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
assert( 0==pTable->pIndex );
db = pParse->db;
- iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
- assert( iDb>=0 );
- pTable->tabFlags |= TF_Virtual;
- pTable->nModuleArg = 0;
- addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
- addModuleArgument(db, pTable, 0);
- addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
+ assert( pTable->nModuleArg==0 );
+ addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName));
+ addModuleArgument(pParse, pTable, 0);
+ addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName));
assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0)
|| (pParse->sNameToken.z==pName1->z && pName2->z==0)
);
@@ -122880,11 +139982,13 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
#ifndef SQLITE_OMIT_AUTHORIZATION
/* Creating a virtual table invokes the authorization callback twice.
** The first invocation, to obtain permission to INSERT a row into the
- ** sqlite_master table, has already been made by sqlite3StartTable().
+ ** sqlite_schema table, has already been made by sqlite3StartTable().
** The second call, to obtain permission to create the table, is made now.
*/
if( pTable->azModuleArg ){
- sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
+ int iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
+ assert( iDb>=0 ); /* The database the table is being created in */
+ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
}
#endif
@@ -122900,7 +140004,7 @@ static void addArgumentToVtab(Parse *pParse){
const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
sqlite3 *db = pParse->db;
- addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
+ addModuleArgument(pParse, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
}
}
@@ -122916,12 +140020,12 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
addArgumentToVtab(pParse);
pParse->sArg.z = 0;
if( pTab->nModuleArg<1 ) return;
-
+
/* If the CREATE VIRTUAL TABLE statement is being entered for the
** first time (in other words if the virtual table is actually being
- ** created now instead of just being read out of sqlite_master) then
+ ** created now instead of just being read out of sqlite_schema) then
** do additional initialization work and store the statement text
- ** in the sqlite_master table.
+ ** in the sqlite_schema table.
*/
if( !db->init.busy ){
char *zStmt;
@@ -122930,45 +140034,47 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
int iReg;
Vdbe *v;
+ sqlite3MayAbort(pParse);
+
/* Compute the complete text of the CREATE VIRTUAL TABLE statement */
if( pEnd ){
pParse->sNameToken.n = (int)(pEnd->z - pParse->sNameToken.z) + pEnd->n;
}
zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
- /* A slot for the record has already been allocated in the
- ** SQLITE_MASTER table. We just need to update that slot with all
- ** the information we've collected.
+ /* A slot for the record has already been allocated in the
+ ** schema table. We just need to update that slot with all
+ ** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_master table tht was created for this vtab
+ ** entry in the sqlite_schema table tht was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3NestedParse(pParse,
- "UPDATE %Q.%s "
+ "UPDATE %Q." DFLT_SCHEMA_TABLE " "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#%d",
- db->aDb[iDb].zDbSName, SCHEMA_TABLE(iDb),
+ db->aDb[iDb].zDbSName,
pTab->zName,
pTab->zName,
zStmt,
pParse->regRowid
);
- sqlite3DbFree(db, zStmt);
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp0(v, OP_Expire);
- zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
+ zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
+ sqlite3DbFree(db, zStmt);
iReg = ++pParse->nMem;
sqlite3VdbeLoadString(v, iReg, pTab->zName);
sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
}
- /* If we are rereading the sqlite_master table create the in-memory
+ /* If we are rereading the sqlite_schema table create the in-memory
** record of the table. The xConnect() method is not called until
** the first time the virtual table is used in an SQL statement. This
** allows a schema that contains virtual tables to be loaded before
@@ -123019,7 +140125,7 @@ SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){
** to this procedure.
*/
static int vtabCallConstructor(
- sqlite3 *db,
+ sqlite3 *db,
Table *pTab,
Module *pMod,
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
@@ -123038,25 +140144,27 @@ static int vtabCallConstructor(
/* Check that the virtual-table is not already being initialized */
for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
if( pCtx->pTab==pTab ){
- *pzErr = sqlite3MPrintf(db,
+ *pzErr = sqlite3MPrintf(db,
"vtable constructor called recursively: %s", pTab->zName
);
return SQLITE_LOCKED;
}
}
- zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
+ zModuleName = sqlite3DbStrDup(db, pTab->zName);
if( !zModuleName ){
return SQLITE_NOMEM_BKPT;
}
- pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
+ pVTable = sqlite3MallocZero(sizeof(VTable));
if( !pVTable ){
+ sqlite3OomFault(db);
sqlite3DbFree(db, zModuleName);
return SQLITE_NOMEM_BKPT;
}
pVTable->db = db;
pVTable->pMod = pMod;
+ pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
@@ -123087,6 +140195,7 @@ static int vtabCallConstructor(
** the sqlite3_vtab object if successful. */
memset(pVTable->pVtab, 0, sizeof(pVTable->pVtab[0]));
pVTable->pVtab->pModule = pMod->pModule;
+ pMod->nRefModule++;
pVTable->nRef = 1;
if( sCtx.bDeclared==0 ){
const char *zFormat = "vtable constructor did not declare schema: %s";
@@ -123095,9 +140204,9 @@ static int vtabCallConstructor(
rc = SQLITE_ERROR;
}else{
int iCol;
- u8 oooHidden = 0;
+ u16 oooHidden = 0;
/* If everything went according to plan, link the new VTable structure
- ** into the linked list headed by pTab->pVTable. Then loop through the
+ ** into the linked list headed by pTab->pVTable. Then loop through the
** columns of the table to see if any of them contain the token "hidden".
** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
** the type string. */
@@ -123142,7 +140251,7 @@ static int vtabCallConstructor(
/*
** This function is invoked by the parser to call the xConnect() method
-** of the virtual table pTab. If an error occurs, an error code is returned
+** of the virtual table pTab. If an error occurs, an error code is returned
** and an error left in pParse.
**
** This call is a no-op if table pTab is not a virtual table.
@@ -123154,7 +140263,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
int rc;
assert( pTab );
- if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){
+ if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
return SQLITE_OK;
}
@@ -123171,6 +140280,7 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xConnect, &zErr);
if( rc!=SQLITE_OK ){
sqlite3ErrorMsg(pParse, "%s", zErr);
+ pParse->rc = rc;
}
sqlite3DbFree(db, zErr);
}
@@ -123187,7 +140297,8 @@ static int growVTrans(sqlite3 *db){
/* Grow the sqlite3.aVTrans array if required */
if( (db->nVTrans%ARRAY_INCR)==0 ){
VTable **aVTrans;
- int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
+ sqlite3_int64 nBytes = sizeof(sqlite3_vtab*)*
+ ((sqlite3_int64)db->nVTrans + ARRAY_INCR);
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
if( !aVTrans ){
return SQLITE_NOMEM_BKPT;
@@ -123211,7 +140322,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){
/*
** This function is invoked by the vdbe to call the xCreate method
-** of the virtual table named zTab in database iDb.
+** of the virtual table named zTab in database iDb.
**
** If an error occurs, *pzErr is set to point to an English language
** description of the error and an SQLITE_XXX error code is returned.
@@ -123224,14 +140335,14 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
const char *zMod;
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
- assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable );
+ assert( pTab && IsVirtual(pTab) && !pTab->pVTable );
/* Locate the required virtual table module */
zMod = pTab->azModuleArg[0];
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
- /* If the module has been registered and includes a Create method,
- ** invoke it now. If the module has not been registered, return an
+ /* If the module has been registered and includes a Create method,
+ ** invoke it now. If the module has not been registered, return an
** error. Otherwise, do nothing.
*/
if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){
@@ -123260,10 +140371,10 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
*/
SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
VtabCtx *pCtx;
- Parse *pParse;
int rc = SQLITE_OK;
Table *pTab;
char *zErr = 0;
+ Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
@@ -123278,57 +140389,57 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
return SQLITE_MISUSE_BKPT;
}
pTab = pCtx->pTab;
- assert( (pTab->tabFlags & TF_Virtual)!=0 );
+ assert( IsVirtual(pTab) );
- pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
- if( pParse==0 ){
- rc = SQLITE_NOMEM_BKPT;
- }else{
- pParse->declareVtab = 1;
- pParse->db = db;
- pParse->nQueryLoop = 1;
-
- if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
- && pParse->pNewTable
- && !db->mallocFailed
- && !pParse->pNewTable->pSelect
- && (pParse->pNewTable->tabFlags & TF_Virtual)==0
- ){
- if( !pTab->aCol ){
- Table *pNew = pParse->pNewTable;
- Index *pIdx;
- pTab->aCol = pNew->aCol;
- pTab->nCol = pNew->nCol;
- pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
- pNew->nCol = 0;
- pNew->aCol = 0;
- assert( pTab->pIndex==0 );
- if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
- rc = SQLITE_ERROR;
- }
- pIdx = pNew->pIndex;
- if( pIdx ){
- assert( pIdx->pNext==0 );
- pTab->pIndex = pIdx;
- pNew->pIndex = 0;
- pIdx->pTable = pTab;
- }
+ memset(&sParse, 0, sizeof(sParse));
+ sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
+ sParse.db = db;
+ sParse.nQueryLoop = 1;
+ if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
+ && sParse.pNewTable
+ && !db->mallocFailed
+ && !sParse.pNewTable->pSelect
+ && !IsVirtual(sParse.pNewTable)
+ ){
+ if( !pTab->aCol ){
+ Table *pNew = sParse.pNewTable;
+ Index *pIdx;
+ pTab->aCol = pNew->aCol;
+ pTab->nCol = pNew->nCol;
+ pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
+ pNew->nCol = 0;
+ pNew->aCol = 0;
+ assert( pTab->pIndex==0 );
+ assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
+ if( !HasRowid(pNew)
+ && pCtx->pVTable->pMod->pModule->xUpdate!=0
+ && sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
+ ){
+ /* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
+ ** or else must have a single-column PRIMARY KEY */
+ rc = SQLITE_ERROR;
+ }
+ pIdx = pNew->pIndex;
+ if( pIdx ){
+ assert( pIdx->pNext==0 );
+ pTab->pIndex = pIdx;
+ pNew->pIndex = 0;
+ pIdx->pTable = pTab;
}
- pCtx->bDeclared = 1;
- }else{
- sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
- sqlite3DbFree(db, zErr);
- rc = SQLITE_ERROR;
- }
- pParse->declareVtab = 0;
-
- if( pParse->pVdbe ){
- sqlite3VdbeFinalize(pParse->pVdbe);
}
- sqlite3DeleteTable(db, pParse->pNewTable);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ pCtx->bDeclared = 1;
+ }else{
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
+ sqlite3DbFree(db, zErr);
+ rc = SQLITE_ERROR;
+ }
+ sParse.eParseMode = PARSE_MODE_NORMAL;
+
+ if( sParse.pVdbe ){
+ sqlite3VdbeFinalize(sParse.pVdbe);
}
+ sqlite3DeleteTable(db, sParse.pNewTable);
+ sqlite3ParserReset(&sParse);
assert( (rc&0xff)==rc );
rc = sqlite3ApiExit(db, rc);
@@ -123359,7 +140470,9 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
}
p = vtabDisconnectAll(db, pTab);
xDestroy = p->pMod->pModule->xDestroy;
- assert( xDestroy!=0 ); /* Checked before the virtual table is created */
+ if( xDestroy==0 ) xDestroy = p->pMod->pModule->xDisconnect;
+ assert( xDestroy!=0 );
+ pTab->nTabRef++;
rc = xDestroy(p->pVtab);
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
if( rc==SQLITE_OK ){
@@ -123368,6 +140481,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
pTab->pVTable = 0;
sqlite3VtabUnlock(p);
}
+ sqlite3DeleteTable(db, pTab);
}
return rc;
@@ -123379,7 +140493,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
** called is identified by the second argument, "offset", which is
** the offset of the method to call in the sqlite3_module structure.
**
-** The array is cleared after invoking the callbacks.
+** The array is cleared after invoking the callbacks.
*/
static void callFinaliser(sqlite3 *db, int offset){
int i;
@@ -123428,7 +140542,7 @@ SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe *p){
}
/*
-** Invoke the xRollback method of all virtual tables in the
+** Invoke the xRollback method of all virtual tables in the
** sqlite3.aVTrans array. Then clear the array itself.
*/
SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){
@@ -123437,7 +140551,7 @@ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){
}
/*
-** Invoke the xCommit method of all virtual tables in the
+** Invoke the xCommit method of all virtual tables in the
** sqlite3.aVTrans array. Then clear the array itself.
*/
SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){
@@ -123459,7 +140573,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
** than zero, then this function is being called from within a
- ** virtual module xSync() callback. It is illegal to write to
+ ** virtual module xSync() callback. It is illegal to write to
** virtual module tables in this case, so return SQLITE_LOCKED.
*/
if( sqlite3VtabInSync(db) ){
@@ -123467,7 +140581,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
}
if( !pVTab ){
return SQLITE_OK;
- }
+ }
pModule = pVTab->pVtab->pModule;
if( pModule->xBegin ){
@@ -123480,7 +140594,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
}
}
- /* Invoke the xBegin method. If successful, add the vtab to the
+ /* Invoke the xBegin method. If successful, add the vtab to the
** sqlite3.aVTrans[] array. */
rc = growVTrans(db);
if( rc==SQLITE_OK ){
@@ -123504,11 +140618,11 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
** 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_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,
+** 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.
@@ -123525,6 +140639,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
const sqlite3_module *pMod = pVTab->pMod->pModule;
if( pVTab->pVtab && pMod->iVersion>=2 ){
int (*xMethod)(sqlite3_vtab *, int);
+ sqlite3VtabLock(pVTab);
switch( op ){
case SAVEPOINT_BEGIN:
xMethod = pMod->xSavepoint;
@@ -123540,6 +140655,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
if( xMethod && pVTab->iSavepoint>iSavepoint ){
rc = xMethod(pVTab->pVtab, iSavepoint);
}
+ sqlite3VtabUnlock(pVTab);
}
}
}
@@ -123555,7 +140671,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
** This routine is used to allow virtual table implementations to
** overload MATCH, LIKE, GLOB, and REGEXP operators.
**
-** Return either the pDef argument (indicating no change) or a
+** Return either the pDef argument (indicating no change) or a
** new FuncDef structure that is marked as ephemeral using the
** SQLITE_FUNC_EPHEM flag.
*/
@@ -123572,33 +140688,36 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
void *pArg = 0;
FuncDef *pNew;
int rc = 0;
- char *zLowerName;
- unsigned char *z;
-
/* Check to see the left operand is a column in a virtual table */
if( NEVER(pExpr==0) ) return pDef;
if( pExpr->op!=TK_COLUMN ) return pDef;
- pTab = pExpr->pTab;
- if( NEVER(pTab==0) ) return pDef;
- if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef;
+ pTab = pExpr->y.pTab;
+ if( pTab==0 ) return pDef;
+ if( !IsVirtual(pTab) ) return pDef;
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
assert( pVtab!=0 );
assert( pVtab->pModule!=0 );
pMod = (sqlite3_module *)pVtab->pModule;
if( pMod->xFindFunction==0 ) return pDef;
-
+
/* Call the xFindFunction method on the virtual table implementation
- ** to see if the implementation wants to overload this function
+ ** to see if the implementation wants to overload this function.
+ **
+ ** Though undocumented, we have historically always invoked xFindFunction
+ ** with an all lower-case function name. Continue in this tradition to
+ ** avoid any chance of an incompatibility.
*/
- zLowerName = sqlite3DbStrDup(db, pDef->zName);
- if( zLowerName ){
- for(z=(unsigned char*)zLowerName; *z; z++){
- *z = sqlite3UpperToLower[*z];
+#ifdef SQLITE_DEBUG
+ {
+ int i;
+ for(i=0; pDef->zName[i]; i++){
+ unsigned char x = (unsigned char)pDef->zName[i];
+ assert( x==sqlite3UpperToLower[x] );
}
- rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
- sqlite3DbFree(db, zLowerName);
}
+#endif
+ rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg);
if( rc==0 ){
return pDef;
}
@@ -123635,7 +140754,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
if( pTab==pToplevel->apVtabLock[i] ) return;
}
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
- apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
+ apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n);
if( apVtabLock ){
pToplevel->apVtabLock = apVtabLock;
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
@@ -123674,14 +140793,13 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
return 0;
}
pMod->pEpoTab = pTab;
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->pSchema = db->aDb[0].pSchema;
- pTab->tabFlags |= TF_Virtual;
- pTab->nModuleArg = 0;
+ assert( pTab->nModuleArg==0 );
pTab->iPKey = -1;
- addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
- addModuleArgument(db, pTab, 0);
- addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
+ addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
+ addModuleArgument(pParse, pTab, 0);
+ addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
if( rc ){
sqlite3ErrorMsg(pParse, "%s", zErr);
@@ -123700,7 +140818,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
Table *pTab = pMod->pEpoTab;
if( pTab!=0 ){
/* Mark the table as Ephemeral prior to deleting it, so that the
- ** sqlite3DeleteTable() routine will know that it is not stored in
+ ** sqlite3DeleteTable() routine will know that it is not stored in
** the schema. */
pTab->tabFlags |= TF_Ephemeral;
sqlite3DeleteTable(db, pTab);
@@ -123716,8 +140834,8 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
** 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
+ static const unsigned char aMap[] = {
+ SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
};
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
@@ -123729,35 +140847,45 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
}
/*
-** Call from within the xCreate() or xConnect() methods to provide
+** 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;
+ VtabCtx *p;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
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 = db->pVtabCtx;
+ if( !p ){
+ rc = SQLITE_MISUSE_BKPT;
+ }else{
+ assert( p->pTab==0 || IsVirtual(p->pTab) );
+ va_start(ap, op);
+ switch( op ){
+ case SQLITE_VTAB_CONSTRAINT_SUPPORT: {
p->pVTable->bConstraint = (u8)va_arg(ap, int);
+ break;
+ }
+ case SQLITE_VTAB_INNOCUOUS: {
+ p->pVTable->eVtabRisk = SQLITE_VTABRISK_Low;
+ break;
+ }
+ case SQLITE_VTAB_DIRECTONLY: {
+ p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
+ break;
+ }
+ default: {
+ rc = SQLITE_MISUSE_BKPT;
+ break;
}
- break;
}
- default:
- rc = SQLITE_MISUSE_BKPT;
- break;
+ va_end(ap);
}
- va_end(ap);
if( rc!=SQLITE_OK ) sqlite3Error(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -123806,12 +140934,14 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
** planner logic in "where.c". These definitions are broken out into
** a separate source file for easier editing.
*/
+#ifndef SQLITE_WHEREINT_H
+#define SQLITE_WHEREINT_H
/*
** Trace output macros
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
-/***/ int sqlite3WhereTrace;
+/***/ extern int sqlite3WhereTrace;
#endif
#if defined(SQLITE_DEBUG) \
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
@@ -123861,19 +140991,23 @@ struct WhereLevel {
int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
+ int regBignull; /* big-null flag reg. True if a NULL-scan is needed */
+ int addrBignull; /* Jump here for next part of big-null scan */
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
int addrLikeRep; /* LIKE range processing address */
#endif
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
- int p1, p2; /* Operands of the opcode used to ends the loop */
+ int p1, p2; /* Operands of the opcode used to end the loop */
union { /* Information that depends on pWLoop->wsFlags */
struct {
int nIn; /* Number of entries in aInLoop[] */
struct InLoop {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
+ int iBase; /* Base register of multi-key index record */
+ int nPrefix; /* Number of prior entires in the key */
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */
@@ -123916,6 +141050,7 @@ struct WhereLoop {
u16 nEq; /* Number of equality constraints */
u16 nBtm; /* Size of BTM vector */
u16 nTop; /* Size of TOP vector */
+ u16 nDistinctCol; /* Index columns used to sort for DISTINCT */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
@@ -123939,7 +141074,7 @@ struct WhereLoop {
/* This object holds the prerequisites and the cost of running a
** subquery on one operand of an OR operator in the WHERE clause.
-** See WhereOrSet for additional information
+** See WhereOrSet for additional information
*/
struct WhereOrCost {
Bitmask prereq; /* Prerequisites */
@@ -123991,7 +141126,7 @@ struct WherePath {
** clause subexpression is separated from the others by AND operators,
** usually, or sometimes subexpressions separated by OR.
**
-** All WhereTerms are collected into a single WhereClause structure.
+** All WhereTerms are collected into a single WhereClause structure.
** The following identity holds:
**
** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm
@@ -124059,22 +141194,29 @@ struct WhereTerm {
/*
** Allowed values of WhereTerm.wtFlags
*/
-#define TERM_DYNAMIC 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */
-#define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */
-#define TERM_CODED 0x04 /* This term is already coded */
-#define TERM_COPIED 0x08 /* Has a child */
-#define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */
-#define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */
-#define TERM_OR_OK 0x40 /* Used during OR-clause processing */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */
+#define TERM_DYNAMIC 0x0001 /* Need to call sqlite3ExprDelete(db, pExpr) */
+#define TERM_VIRTUAL 0x0002 /* Added by the optimizer. Do not code */
+#define TERM_CODED 0x0004 /* This term is already coded */
+#define TERM_COPIED 0x0008 /* Has a child */
+#define TERM_ORINFO 0x0010 /* Need to free the WhereTerm.u.pOrInfo object */
+#define TERM_ANDINFO 0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */
+#define TERM_OR_OK 0x0040 /* Used during OR-clause processing */
+#ifdef SQLITE_ENABLE_STAT4
+# define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */
+#else
+# define TERM_VNULL 0x0000 /* Disabled if not using stat4 */
+#endif
+#define TERM_LIKEOPT 0x0100 /* Virtual terms from the LIKE optimization */
+#define TERM_LIKECOND 0x0200 /* Conditionally this LIKE operator term */
+#define TERM_LIKE 0x0400 /* The original LIKE operator */
+#define TERM_IS 0x0800 /* Term.pExpr is an IS operator */
+#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */
+#define TERM_HEURTRUTH 0x2000 /* Heuristic truthProb used */
+#ifdef SQLITE_ENABLE_STAT4
+# define TERM_HIGHTRUTH 0x4000 /* Term excludes few rows */
#else
-# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
+# define TERM_HIGHTRUTH 0 /* Only used with STAT4 */
#endif
-#define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */
-#define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */
-#define TERM_LIKE 0x400 /* The original LIKE operator */
-#define TERM_IS 0x800 /* Term.pExpr is an IS operator */
/*
** An instance of the WhereScan object is used as an iterator for locating
@@ -124110,6 +141252,7 @@ struct WhereClause {
WhereInfo *pWInfo; /* WHERE clause processing context */
WhereClause *pOuter; /* Outer conjunction */
u8 op; /* Split operator. TK_AND or TK_OR */
+ u8 hasOr; /* True if any a[].eOperator is WO_OR */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
@@ -124141,8 +141284,8 @@ struct WhereAndInfo {
** An instance of the following structure keeps track of a mapping
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
**
-** The VDBE cursor numbers are small integers contained in
-** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
+** The VDBE cursor numbers are small integers contained in
+** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
** clause, the cursor numbers might not begin with 0 and they might
** contain gaps in the numbering sequence. But we want to make maximum
** use of the bits in our bitmasks. This structure provides a mapping
@@ -124164,6 +141307,7 @@ struct WhereAndInfo {
** no gaps.
*/
struct WhereMaskSet {
+ int bVarSelect; /* Used by sqlite3WhereExprUsage() */
int n; /* Number of assigned cursor values */
int ix[BMS]; /* Cursor assigned to each bit */
};
@@ -124183,10 +141327,53 @@ struct WhereLoopBuilder {
ExprList *pOrderBy; /* ORDER BY clause */
WhereLoop *pNew; /* Template WhereLoop */
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
UnpackedRecord *pRec; /* Probe for stat4 (if required) */
int nRecValid; /* Number of valid fields currently in pRec */
#endif
+ unsigned char bldFlags1; /* First set of SQLITE_BLDF_* flags */
+ unsigned char bldFlags2; /* Second set of SQLITE_BLDF_* flags */
+ unsigned int iPlanLimit; /* Search limiter */
+};
+
+/* Allowed values for WhereLoopBuider.bldFlags */
+#define SQLITE_BLDF1_INDEXED 0x0001 /* An index is used */
+#define SQLITE_BLDF1_UNIQUE 0x0002 /* All keys of a UNIQUE index used */
+
+#define SQLITE_BLDF2_2NDPASS 0x0004 /* Second builder pass needed */
+
+/* The WhereLoopBuilder.iPlanLimit is used to limit the number of
+** index+constraint combinations the query planner will consider for a
+** particular query. If this parameter is unlimited, then certain
+** pathological queries can spend excess time in the sqlite3WhereBegin()
+** routine. The limit is high enough that is should not impact real-world
+** queries.
+**
+** SQLITE_QUERY_PLANNER_LIMIT is the baseline limit. The limit is
+** increased by SQLITE_QUERY_PLANNER_LIMIT_INCR before each term of the FROM
+** clause is processed, so that every table in a join is guaranteed to be
+** able to propose a some index+constraint combinations even if the initial
+** baseline limit was exhausted by prior tables of the join.
+*/
+#ifndef SQLITE_QUERY_PLANNER_LIMIT
+# define SQLITE_QUERY_PLANNER_LIMIT 20000
+#endif
+#ifndef SQLITE_QUERY_PLANNER_LIMIT_INCR
+# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
+#endif
+
+/*
+** Each instance of this object records a change to a single node
+** in an expression tree to cause that node to point to a column
+** of an index rather than an expression or a virtual column. All
+** such transformations need to be undone at the end of WHERE clause
+** processing.
+*/
+typedef struct WhereExprMod WhereExprMod;
+struct WhereExprMod {
+ WhereExprMod *pNext; /* Next translation on a list of them all */
+ Expr *pExpr; /* The Expr node that was transformed */
+ Expr orig; /* Original value of the Expr node */
};
/*
@@ -124203,24 +141390,27 @@ struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
- ExprList *pDistinctSet; /* DISTINCT over all these values */
- LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
+ ExprList *pResultSet; /* Result set of the query */
+ Expr *pWhere; /* The complete WHERE clause */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
+ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
u8 nLevel; /* Number of nested loop */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
- u8 sorted; /* True if really sorted (not just grouped) */
u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
- u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values */
- u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */
+ unsigned bDeferredSeek :1; /* Uses OP_DeferredSeek */
+ unsigned untestedTerms :1; /* Not all WHERE terms resolved by outer loop */
+ unsigned bOrderedInnerLoop:1;/* True if only the inner-most loop is ordered */
+ unsigned sorted :1; /* True if really sorted (not just grouped) */
+ LogEst nRowOut; /* Estimated number of output rows */
int iTop; /* The very beginning of the WHERE loop */
WhereLoop *pLoops; /* List of all WhereLoop objects */
+ WhereExprMod *pExprMods; /* Expression modifications */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
- LogEst nRowOut; /* Estimated number of output rows */
WhereClause sWC; /* Decomposition of the WHERE clause */
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
@@ -124234,6 +141424,8 @@ struct WhereInfo {
SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);
+SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
+SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
#endif
SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
@@ -124250,12 +141442,10 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
Parse *pParse, /* Parse context */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
- int iLevel, /* Value for "level" column of output */
- int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
);
#else
-# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0
+# define sqlite3WhereExplainOneScan(u,v,w,x) 0
#endif /* SQLITE_OMIT_EXPLAIN */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
@@ -124268,8 +141458,11 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
# define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d)
#endif
SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
+ Parse *pParse, /* Parsing context */
+ Vdbe *v, /* Prepared statement under construction */
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
+ WhereLevel *pLevel, /* The current level pointer */
Bitmask notReady /* Which tables are currently available */
);
@@ -124278,6 +141471,7 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*);
SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8);
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
+SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
@@ -124298,7 +141492,6 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
** WO_LE == SQLITE_INDEX_CONSTRAINT_LE
** WO_GT == SQLITE_INDEX_CONSTRAINT_GT
** WO_GE == SQLITE_INDEX_CONSTRAINT_GE
-** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH
*/
#define WO_IN 0x0001
#define WO_EQ 0x0002
@@ -124306,7 +141499,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
#define WO_LE (WO_EQ<<(TK_LE-TK_EQ))
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
-#define WO_MATCH 0x0040
+#define WO_AUX 0x0040 /* Op useful to virtual tables only */
#define WO_IS 0x0080
#define WO_ISNULL 0x0100
#define WO_OR 0x0200 /* Two or more OR-connected terms */
@@ -124341,6 +141534,10 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
+#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */
+#define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */
+
+#endif /* !defined(SQLITE_WHEREINT_H) */
/************** End of whereInt.h ********************************************/
/************** Continuing where we left off in wherecode.c ******************/
@@ -124376,27 +141573,27 @@ static void explainAppendTerm(
int i;
assert( nTerm>=1 );
- if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+ if( bAnd ) sqlite3_str_append(pStr, " AND ", 5);
- if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
+ if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1);
for(i=0; i<nTerm; i++){
- if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
- sqlite3StrAccumAppendAll(pStr, explainIndexColumnName(pIdx, iTerm+i));
+ if( i ) sqlite3_str_append(pStr, ",", 1);
+ sqlite3_str_appendall(pStr, explainIndexColumnName(pIdx, iTerm+i));
}
- if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
+ if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1);
- sqlite3StrAccumAppend(pStr, zOp, 1);
+ sqlite3_str_append(pStr, zOp, 1);
- if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
+ if( nTerm>1 ) sqlite3_str_append(pStr, "(", 1);
for(i=0; i<nTerm; i++){
- if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
- sqlite3StrAccumAppend(pStr, "?", 1);
+ if( i ) sqlite3_str_append(pStr, ",", 1);
+ sqlite3_str_append(pStr, "?", 1);
}
- if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
+ if( nTerm>1 ) sqlite3_str_append(pStr, ")", 1);
}
/*
-** Argument pLevel describes a strategy for scanning table pTab. This
+** Argument pLevel describes a strategy for scanning table pTab. This
** function appends text to pStr that describes the subset of table
** rows scanned by the strategy in the form of an SQL expression.
**
@@ -124416,11 +141613,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
int i, j;
if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
- sqlite3StrAccumAppend(pStr, " (", 2);
+ sqlite3_str_append(pStr, " (", 2);
for(i=0; i<nEq; i++){
const char *z = explainIndexColumnName(pIndex, i);
- if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
- sqlite3XPrintf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
+ if( i ) sqlite3_str_append(pStr, " AND ", 5);
+ sqlite3_str_appendf(pStr, i>=nSkip ? "%s=?" : "ANY(%s)", z);
}
j = i;
@@ -124431,13 +141628,13 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<");
}
- sqlite3StrAccumAppend(pStr, ")", 1);
+ sqlite3_str_append(pStr, ")", 1);
}
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
+** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
** is added to the output to describe the table scan strategy in pLevel.
**
** If an OP_Explain opcode is added to the VM, its address is returned.
@@ -124447,19 +141644,16 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
Parse *pParse, /* Parse context */
SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
- int iLevel, /* Value for "level" column of output */
- int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
int ret = 0;
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( pParse->explain==2 )
+ if( sqlite3ParseToplevel(pParse)->explain==2 )
#endif
{
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
Vdbe *v = pParse->pVdbe; /* VM being constructed */
sqlite3 *db = pParse->db; /* Database handle */
- int iId = pParse->iSelectId; /* Select id (left-most output column) */
int isSearch; /* True for a SEARCH. False for SCAN. */
WhereLoop *pLoop; /* The controlling WhereLoop object */
u32 flags; /* Flags that describe this loop */
@@ -124476,15 +141670,15 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
- sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN");
+ sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN");
if( pItem->pSelect ){
- sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId);
+ sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId);
}else{
- sqlite3XPrintf(&str, " TABLE %s", pItem->zName);
+ sqlite3_str_appendf(&str, " TABLE %s", pItem->zName);
}
if( pItem->zAlias ){
- sqlite3XPrintf(&str, " AS %s", pItem->zAlias);
+ sqlite3_str_appendf(&str, " AS %s", pItem->zAlias);
}
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
const char *zFmt = 0;
@@ -124507,8 +141701,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
zFmt = "INDEX %s";
}
if( zFmt ){
- sqlite3StrAccumAppend(&str, " USING ", 7);
- sqlite3XPrintf(&str, zFmt, pIdx->zName);
+ sqlite3_str_append(&str, " USING ", 7);
+ sqlite3_str_appendf(&str, zFmt, pIdx->zName);
explainIndexRange(&str, pLoop);
}
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
@@ -124523,23 +141717,27 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
assert( flags&WHERE_TOP_LIMIT);
zRangeOp = "<";
}
- sqlite3XPrintf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
+ sqlite3_str_appendf(&str,
+ " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
- sqlite3XPrintf(&str, " VIRTUAL TABLE INDEX %d:%s",
+ sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s",
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
}
#endif
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
if( pLoop->nOut>=10 ){
- sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut));
+ sqlite3_str_appendf(&str, " (~%llu rows)",
+ sqlite3LogEstToInt(pLoop->nOut));
}else{
- sqlite3StrAccumAppend(&str, " (~1 row)", 9);
+ sqlite3_str_append(&str, " (~1 row)", 9);
}
#endif
zMsg = sqlite3StrAccumFinish(&str);
- ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC);
+ sqlite3ExplainBreakpoint("",zMsg);
+ ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
+ pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
}
return ret;
}
@@ -124548,11 +141746,11 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
/*
** Configure the VM passed as the first argument with an
-** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
-** implement level pLvl. Argument pSrclist is a pointer to the FROM
+** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
+** implement level pLvl. Argument pSrclist is a pointer to the FROM
** clause that the scan reads data from.
**
-** If argument addrExplain is not 0, it must be the address of an
+** If argument addrExplain is not 0, it must be the address of an
** OP_Explain instruction that describes the same loop.
*/
SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
@@ -124608,7 +141806,7 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
**
** Only the parent term was in the original WHERE clause. The child1
** and child2 terms were added by the LIKE optimization. If both of
-** the virtual child terms are valid, then testing of the parent can be
+** the virtual child terms are valid, then testing of the parent can be
** skipped.
**
** Usually the parent term is marked as TERM_CODED. But if the parent
@@ -124619,8 +141817,8 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
int nLoop = 0;
- while( ALWAYS(pTerm!=0)
- && (pTerm->wtFlags & TERM_CODED)==0
+ assert( pTerm!=0 );
+ while( (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
@@ -124631,6 +141829,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
}
if( pTerm->iParent<0 ) break;
pTerm = &pTerm->pWC->a[pTerm->iParent];
+ assert( pTerm!=0 );
pTerm->nChild--;
if( pTerm->nChild!=0 ) break;
nLoop++;
@@ -124639,11 +141838,11 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
/*
** Code an OP_Affinity opcode to apply the column affinity string zAff
-** to the n registers starting at base.
+** to the n registers starting at base.
**
-** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the
-** beginning and end of zAff are ignored. If all entries in zAff are
-** SQLITE_AFF_BLOB, then no code gets generated.
+** As an optimization, SQLITE_AFF_BLOB and SQLITE_AFF_NONE entries (which
+** are no-ops) at the beginning and end of zAff are ignored. If all entries
+** in zAff are SQLITE_AFF_BLOB or SQLITE_AFF_NONE, then no code gets generated.
**
** This routine makes its own copy of zAff so that the caller is free
** to modify zAff after this routine returns.
@@ -124656,27 +141855,27 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
}
assert( v!=0 );
- /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning
- ** and end of the affinity string.
+ /* Adjust base and n to skip over SQLITE_AFF_BLOB and SQLITE_AFF_NONE
+ ** entries at the beginning and end of the affinity string.
*/
- while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){
+ assert( SQLITE_AFF_NONE<SQLITE_AFF_BLOB );
+ while( n>0 && zAff[0]<=SQLITE_AFF_BLOB ){
n--;
base++;
zAff++;
}
- while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){
+ while( n>1 && zAff[n-1]<=SQLITE_AFF_BLOB ){
n--;
}
/* Code the OP_Affinity opcode if there is anything left to do. */
if( n>0 ){
sqlite3VdbeAddOp4(v, OP_Affinity, base, n, 0, zAff, n);
- sqlite3ExprCacheAffinityChange(pParse, base, n);
}
}
/*
-** Expression pRight, which is the RHS of a comparison operation, is
+** Expression pRight, which is the RHS of a comparison operation, is
** either a vector of n elements or, if n==1, a scalar expression.
** Before the comparison operation, affinity zAff is to be applied
** to the pRight values. This function modifies characters within the
@@ -124701,9 +141900,106 @@ static void updateRangeAffinityStr(
}
}
+
+/*
+** pX is an expression of the form: (vector) IN (SELECT ...)
+** In other words, it is a vector IN operator with a SELECT clause on the
+** LHS. But not all terms in the vector are indexable and the terms might
+** not be in the correct order for indexing.
+**
+** This routine makes a copy of the input pX expression and then adjusts
+** the vector on the LHS with corresponding changes to the SELECT so that
+** the vector contains only index terms and those terms are in the correct
+** order. The modified IN expression is returned. The caller is responsible
+** for deleting the returned expression.
+**
+** Example:
+**
+** CREATE TABLE t1(a,b,c,d,e,f);
+** CREATE INDEX t1x1 ON t1(e,c);
+** SELECT * FROM t1 WHERE (a,b,c,d,e) IN (SELECT v,w,x,y,z FROM t2)
+** \_______________________________________/
+** The pX expression
+**
+** Since only columns e and c can be used with the index, in that order,
+** the modified IN expression that is returned will be:
+**
+** (e,c) IN (SELECT z,x FROM t2)
+**
+** The reduced pX is different from the original (obviously) and thus is
+** only used for indexing, to improve performance. The original unaltered
+** IN expression must also be run on each output row for correctness.
+*/
+static Expr *removeUnindexableInClauseTerms(
+ Parse *pParse, /* The parsing context */
+ int iEq, /* Look at loop terms starting here */
+ WhereLoop *pLoop, /* The current loop */
+ Expr *pX /* The IN expression to be reduced */
+){
+ sqlite3 *db = pParse->db;
+ Expr *pNew;
+ pNew = sqlite3ExprDup(db, pX, 0);
+ if( db->mallocFailed==0 ){
+ ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */
+ ExprList *pOrigLhs = pNew->pLeft->x.pList; /* Original unmodified LHS */
+ ExprList *pRhs = 0; /* New RHS after modifications */
+ ExprList *pLhs = 0; /* New LHS after mods */
+ int i; /* Loop counter */
+ Select *pSelect; /* Pointer to the SELECT on the RHS */
+
+ for(i=iEq; i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iField = pLoop->aLTerm[i]->iField - 1;
+ if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
+ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
+ pOrigRhs->a[iField].pExpr = 0;
+ assert( pOrigLhs->a[iField].pExpr!=0 );
+ pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
+ pOrigLhs->a[iField].pExpr = 0;
+ }
+ }
+ sqlite3ExprListDelete(db, pOrigRhs);
+ sqlite3ExprListDelete(db, pOrigLhs);
+ pNew->pLeft->x.pList = pLhs;
+ pNew->x.pSelect->pEList = pRhs;
+ if( pLhs && pLhs->nExpr==1 ){
+ /* Take care here not to generate a TK_VECTOR containing only a
+ ** single value. Since the parser never creates such a vector, some
+ ** of the subroutines do not handle this case. */
+ Expr *p = pLhs->a[0].pExpr;
+ pLhs->a[0].pExpr = 0;
+ sqlite3ExprDelete(db, pNew->pLeft);
+ pNew->pLeft = p;
+ }
+ pSelect = pNew->x.pSelect;
+ if( pSelect->pOrderBy ){
+ /* If the SELECT statement has an ORDER BY clause, zero the
+ ** iOrderByCol variables. These are set to non-zero when an
+ ** ORDER BY term exactly matches one of the terms of the
+ ** result-set. Since the result-set of the SELECT statement may
+ ** have been modified or reordered, these variables are no longer
+ ** set correctly. Since setting them is just an optimization,
+ ** it's easiest just to zero them here. */
+ ExprList *pOrderBy = pSelect->pOrderBy;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
+ }
+
+#if 0
+ printf("For indexing, change the IN expr:\n");
+ sqlite3TreeViewExpr(0, pX, 0);
+ printf("Into:\n");
+ sqlite3TreeViewExpr(0, pNew, 0);
+#endif
+ }
+ return pNew;
+}
+
+
/*
** Generate code for a single equality term of the WHERE clause. An equality
-** term can be either X=expr or X IN (...). pTerm is the term to be
+** term can be either X=expr or X IN (...). pTerm is the term to be
** coded.
**
** The current value for the constraint is left in a register, the index
@@ -124763,72 +142059,30 @@ static int codeEqualityTerm(
}
}
for(i=iEq;i<pLoop->nLTerm; i++){
- if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++;
+ assert( pLoop->aLTerm[i]!=0 );
+ if( pLoop->aLTerm[i]->pExpr==pX ) nEq++;
}
+ iTab = 0;
if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
}else{
- Select *pSelect = pX->x.pSelect;
sqlite3 *db = pParse->db;
- ExprList *pOrigRhs = pSelect->pEList;
- ExprList *pOrigLhs = pX->pLeft->x.pList;
- ExprList *pRhs = 0; /* New Select.pEList for RHS */
- ExprList *pLhs = 0; /* New pX->pLeft vector */
+ pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
- for(i=iEq;i<pLoop->nLTerm; i++){
- if( pLoop->aLTerm[i]->pExpr==pX ){
- int iField = pLoop->aLTerm[i]->iField - 1;
- Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0);
- Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0);
-
- pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs);
- pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs);
- }
- }
if( !db->mallocFailed ){
- Expr *pLeft = pX->pLeft;
-
- if( pSelect->pOrderBy ){
- /* If the SELECT statement has an ORDER BY clause, zero the
- ** iOrderByCol variables. These are set to non-zero when an
- ** ORDER BY term exactly matches one of the terms of the
- ** result-set. Since the result-set of the SELECT statement may
- ** have been modified or reordered, these variables are no longer
- ** set correctly. Since setting them is just an optimization,
- ** it's easiest just to zero them here. */
- ExprList *pOrderBy = pSelect->pOrderBy;
- for(i=0; i<pOrderBy->nExpr; i++){
- pOrderBy->a[i].u.x.iOrderByCol = 0;
- }
- }
-
- /* Take care here not to generate a TK_VECTOR containing only a
- ** single value. Since the parser never creates such a vector, some
- ** of the subroutines do not handle this case. */
- if( pLhs->nExpr==1 ){
- pX->pLeft = pLhs->a[0].pExpr;
- }else{
- pLeft->x.pList = pLhs;
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq);
- testcase( aiMap==0 );
- }
- pSelect->pEList = pRhs;
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
- testcase( aiMap!=0 && aiMap[0]!=0 );
- pSelect->pEList = pOrigRhs;
- pLeft->x.pList = pOrigLhs;
- pX->pLeft = pLeft;
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
+ pTerm->pExpr->iTable = iTab;
}
- sqlite3ExprListDelete(pParse->db, pLhs);
- sqlite3ExprListDelete(pParse->db, pRhs);
+ sqlite3ExprDelete(db, pX);
+ pX = pTerm->pExpr;
}
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
}
- iTab = pX->iTable;
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
@@ -124836,7 +142090,7 @@ static int codeEqualityTerm(
pLoop->wsFlags |= WHERE_IN_ABLE;
if( pLevel->u.in.nIn==0 ){
- pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
+ pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
}
i = pLevel->u.in.nIn;
@@ -124852,7 +142106,6 @@ static int codeEqualityTerm(
if( pLoop->aLTerm[i]->pExpr==pX ){
int iOut = iReg + i - iEq;
if( eType==IN_INDEX_ROWID ){
- testcase( nEq>1 ); /* Happens with a UNIQUE index on ROWID */
pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
}else{
int iCol = aiMap ? aiMap[iMap++] : 0;
@@ -124861,7 +142114,14 @@ static int codeEqualityTerm(
sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
if( i==iEq ){
pIn->iCur = iTab;
- pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
+ pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
+ if( iEq>0 ){
+ pIn->iBase = iReg - i;
+ pIn->nPrefix = i;
+ pLoop->wsFlags |= WHERE_IN_EARLYOUT;
+ }else{
+ pIn->nPrefix = 0;
+ }
}else{
pIn->eEndLoopOp = OP_Noop;
}
@@ -124885,7 +142145,7 @@ static int codeEqualityTerm(
** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c).
** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10
** The index has as many as three equality constraints, but in this
-** example, the third "c" value is an inequality. So only two
+** example, the third "c" value is an inequality. So only two
** constraints are coded. This routine will generate code to evaluate
** a==5 and b IN (1,2,3). The current values for a and b will be stored
** in consecutive registers and the index of the first register is returned.
@@ -124975,7 +142235,7 @@ static int codeAllEqualityTerms(
testcase( pIdx->aiColumn[j]==XN_EXPR );
VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));
}
- }
+ }
/* Evaluate the equality constraints
*/
@@ -124984,7 +142244,7 @@ static int codeAllEqualityTerms(
int r1;
pTerm = pLoop->aLTerm[j];
assert( pTerm!=0 );
- /* The following testcase is true for indices with redundant columns.
+ /* The following testcase is true for indices with redundant columns.
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
@@ -125000,8 +142260,8 @@ static int codeAllEqualityTerms(
if( pTerm->eOperator & WO_IN ){
if( pTerm->pExpr->flags & EP_xIsSelect ){
/* No affinity ever needs to be (or should be) applied to a value
- ** from the RHS of an "? IN (SELECT ...)" expression. The
- ** sqlite3FindInIndex() routine has already ensured that the
+ ** from the RHS of an "? IN (SELECT ...)" expression. The
+ ** sqlite3FindInIndex() routine has already ensured that the
** affinity of the comparison has been applied to the value. */
if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
}
@@ -125028,7 +142288,7 @@ static int codeAllEqualityTerms(
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
/*
** If the most recently coded instruction is a constant range constraint
-** (a string literal) that originated from the LIKE optimization, then
+** (a string literal) that originated from the LIKE optimization, then
** set P3 and P5 on the OP_String opcode so that the string will be cast
** to a BLOB at appropriate times.
**
@@ -125053,7 +142313,7 @@ static void whereLikeOptimizationStringFixup(
assert( pLevel->iLikeRepCntr>0 );
pOp = sqlite3VdbeGetOp(v, -1);
assert( pOp!=0 );
- assert( pOp->opcode==OP_String8
+ assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */
pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */
@@ -125086,7 +142346,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
assert( pHint->pIdx!=0 );
if( pExpr->op==TK_COLUMN
&& pExpr->iTable==pHint->iTabCur
- && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0
+ && sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn)<0
){
pWalker->eCode = 1;
}
@@ -125096,7 +142356,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
/*
** Test whether or not expression pExpr, which was part of a WHERE clause,
** should be included in the cursor-hint for a table that is on the rhs
-** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
+** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
** expression is not suitable.
**
** An expression is unsuitable if it might evaluate to non NULL even if
@@ -125109,14 +142369,14 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
** CASE WHEN col THEN 0 ELSE 1 END
*/
static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
- if( pExpr->op==TK_IS
- || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
- || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
+ if( pExpr->op==TK_IS
+ || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
+ || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
){
pWalker->eCode = 1;
}else if( pExpr->op==TK_FUNCTION ){
int d1;
- char d2[3];
+ char d2[4];
if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
pWalker->eCode = 1;
}
@@ -125132,10 +142392,10 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
** that accesses any table other than the one identified by
** CCurHint.iTabCur, then do the following:
**
-** 1) allocate a register and code an OP_Column instruction to read
+** 1) allocate a register and code an OP_Column instruction to read
** the specified column into the new register, and
**
-** 2) transform the expression node to a TK_REGISTER node that reads
+** 2) transform the expression node to a TK_REGISTER node that reads
** from the newly populated register.
**
** Also, if the node is a TK_COLUMN that does access the table idenified
@@ -125148,16 +142408,13 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
- Vdbe *v = pWalker->pParse->pVdbe;
int reg = ++pWalker->pParse->nMem; /* Register for column value */
- sqlite3ExprCodeGetColumnOfTable(
- v, pExpr->pTab, pExpr->iTable, pExpr->iColumn, reg
- );
+ sqlite3ExprCode(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
pExpr->iTable = pHint->iIdxCur;
- pExpr->iColumn = sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn);
+ pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
}else if( pExpr->op==TK_AGG_FUNCTION ){
@@ -125166,7 +142423,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
** the parent context. Do not walk the function arguments in this case.
**
** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
+ ** expression, as the result of the expression must be stored in a
** register at this point. The same holds for TK_AGG_COLUMN nodes. */
rc = WRC_Prune;
}
@@ -125209,18 +142466,18 @@ static void codeCursorHint(
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->prereqAll & pLevel->notReady ) continue;
- /* Any terms specified as part of the ON(...) clause for any LEFT
+ /* Any terms specified as part of the ON(...) clause for any LEFT
** JOIN for which the current table is not the rhs are omitted
- ** from the cursor-hint.
+ ** from the cursor-hint.
**
- ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
+ ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
** that were specified as part of the WHERE clause must be excluded.
** This is to address the following:
**
** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
**
** Say there is a single row in t2 that matches (t1.a=t2.b), but its
- ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
+ ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
** pushed down to the cursor, this row is filtered out, causing
** SQLite to synthesize a row of NULL values. Which does match the
** WHERE clause, and so the query returns a row. Which is incorrect.
@@ -125233,7 +142490,7 @@ static void codeCursorHint(
*/
if( pTabItem->fg.jointype & JT_LEFT ){
Expr *pExpr = pTerm->pExpr;
- if( !ExprHasProperty(pExpr, EP_FromJoin)
+ if( !ExprHasProperty(pExpr, EP_FromJoin)
|| pExpr->iRightJoinTable!=pTabItem->iCursor
){
sWalker.eCode = 0;
@@ -125266,12 +142523,12 @@ static void codeCursorHint(
}
/* If we survive all prior tests, that means this term is worth hinting */
- pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
+ pExpr = sqlite3ExprAnd(pParse, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0));
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
sqlite3WalkExpr(&sWalker, pExpr);
- sqlite3VdbeAddOp4(v, OP_CursorHint,
+ sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
}
@@ -125283,18 +142540,18 @@ static void codeCursorHint(
/*
** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
** a rowid value just read from cursor iIdxCur, open on index pIdx. This
-** function generates code to do a deferred seek of cursor iCur to the
+** function generates code to do a deferred seek of cursor iCur to the
** rowid stored in register iRowid.
**
** Normally, this is just:
**
-** OP_Seek $iCur $iRowid
+** OP_DeferredSeek $iCur $iRowid
**
** However, if the scan currently being coded is a branch of an OR-loop and
-** the statement currently being coded is a SELECT, then P3 of the OP_Seek
+** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek
** is set to iIdxCur and P4 is set to point to an array of integers
-** containing one entry for each column of the table cursor iCur is open
-** on. For each table column, if the column is the i'th column of the
+** containing one entry for each column of the table cursor iCur is open
+** on. For each table column, if the column is the i'th column of the
** index, then the corresponding array entry is set to (i+1). If the column
** does not appear in the index at all, the array entry is set to 0.
*/
@@ -125309,19 +142566,24 @@ static void codeDeferredSeek(
assert( iIdxCur>0 );
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
-
- sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
+
+ pWInfo->bDeferredSeek = 1;
+ sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
){
int i;
Table *pTab = pIdx->pTable;
- int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
+ u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
if( ai ){
ai[0] = pTab->nCol;
for(i=0; i<pIdx->nColumn-1; i++){
+ int x1, x2;
assert( pIdx->aiColumn[i]<pTab->nCol );
- if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
+ x1 = pIdx->aiColumn[i];
+ x2 = sqlite3TableColumnToStorage(pTab, x1);
+ testcase( x1!=x2 );
+ if( x1>=0 ) ai[x2+1] = i+1;
}
sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
}
@@ -125339,11 +142601,13 @@ static void codeDeferredSeek(
*/
static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
assert( nReg>0 );
- if( sqlite3ExprIsVector(p) ){
+ if( p && sqlite3ExprIsVector(p) ){
#ifndef SQLITE_OMIT_SUBQUERY
if( (p->flags & EP_xIsSelect) ){
Vdbe *v = pParse->pVdbe;
- int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0);
+ int iSelect;
+ assert( p->op==TK_SELECT );
+ iSelect = sqlite3CodeSubselect(pParse, p);
sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
}else
#endif
@@ -125361,46 +142625,222 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
}
}
+/* An instance of the IdxExprTrans object carries information about a
+** mapping from an expression on table columns into a column in an index
+** down through the Walker.
+*/
+typedef struct IdxExprTrans {
+ Expr *pIdxExpr; /* The index expression */
+ int iTabCur; /* The cursor of the corresponding table */
+ int iIdxCur; /* The cursor for the index */
+ int iIdxCol; /* The column for the index */
+ int iTabCol; /* The column for the table */
+ WhereInfo *pWInfo; /* Complete WHERE clause information */
+ sqlite3 *db; /* Database connection (for malloc()) */
+} IdxExprTrans;
+
+/*
+** Preserve pExpr on the WhereETrans list of the WhereInfo.
+*/
+static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
+ WhereExprMod *pNew;
+ pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
+ if( pNew==0 ) return;
+ pNew->pNext = pTrans->pWInfo->pExprMods;
+ pTrans->pWInfo->pExprMods = pNew;
+ pNew->pExpr = pExpr;
+ memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
+}
+
+/* The walker node callback used to transform matching expressions into
+** a reference to an index column for an index on an expression.
+**
+** If pExpr matches, then transform it into a reference to the index column
+** that contains the value of pExpr.
+*/
+static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
+ IdxExprTrans *pX = p->u.pIdxTrans;
+ if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
+ preserveExpr(pX, pExpr);
+ pExpr->affExpr = sqlite3ExprAffinity(pExpr);
+ pExpr->op = TK_COLUMN;
+ pExpr->iTable = pX->iIdxCur;
+ pExpr->iColumn = pX->iIdxCol;
+ pExpr->y.pTab = 0;
+ testcase( ExprHasProperty(pExpr, EP_Skip) );
+ testcase( ExprHasProperty(pExpr, EP_Unlikely) );
+ ExprClearProperty(pExpr, EP_Skip|EP_Unlikely);
+ return WRC_Prune;
+ }else{
+ return WRC_Continue;
+ }
+}
+
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+/* A walker node callback that translates a column reference to a table
+** into a corresponding column reference of an index.
+*/
+static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN ){
+ IdxExprTrans *pX = p->u.pIdxTrans;
+ if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
+ assert( pExpr->y.pTab!=0 );
+ preserveExpr(pX, pExpr);
+ pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
+ pExpr->iTable = pX->iIdxCur;
+ pExpr->iColumn = pX->iIdxCol;
+ pExpr->y.pTab = 0;
+ }
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+
+/*
+** For an indexes on expression X, locate every instance of expression X
+** in pExpr and change that subexpression into a reference to the appropriate
+** column of the index.
+**
+** 2019-10-24: Updated to also translate references to a VIRTUAL column in
+** the table into references to the corresponding (stored) column of the
+** index.
+*/
+static void whereIndexExprTrans(
+ Index *pIdx, /* The Index */
+ int iTabCur, /* Cursor of the table that is being indexed */
+ int iIdxCur, /* Cursor of the index itself */
+ WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
+){
+ int iIdxCol; /* Column number of the index */
+ ExprList *aColExpr; /* Expressions that are indexed */
+ Table *pTab;
+ Walker w;
+ IdxExprTrans x;
+ aColExpr = pIdx->aColExpr;
+ if( aColExpr==0 && !pIdx->bHasVCol ){
+ /* The index does not reference any expressions or virtual columns
+ ** so no translations are needed. */
+ return;
+ }
+ pTab = pIdx->pTable;
+ memset(&w, 0, sizeof(w));
+ w.u.pIdxTrans = &x;
+ x.iTabCur = iTabCur;
+ x.iIdxCur = iIdxCur;
+ x.pWInfo = pWInfo;
+ x.db = pWInfo->pParse->db;
+ for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
+ i16 iRef = pIdx->aiColumn[iIdxCol];
+ if( iRef==XN_EXPR ){
+ assert( aColExpr->a[iIdxCol].pExpr!=0 );
+ x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
+ if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
+ w.xExprCallback = whereIndexExprTransNode;
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
+ }else if( iRef>=0
+ && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
+ && (pTab->aCol[iRef].zColl==0
+ || sqlite3StrICmp(pTab->aCol[iRef].zColl, sqlite3StrBINARY)==0)
+ ){
+ /* Check to see if there are direct references to generated columns
+ ** that are contained in the index. Pulling the generated column
+ ** out of the index is an optimization only - the main table is always
+ ** available if the index cannot be used. To avoid unnecessary
+ ** complication, omit this optimization if the collating sequence for
+ ** the column is non-standard */
+ x.iTabCol = iRef;
+ w.xExprCallback = whereIndexExprTransColumn;
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
+ }else{
+ continue;
+ }
+ x.iIdxCol = iIdxCol;
+ sqlite3WalkExpr(&w, pWInfo->pWhere);
+ sqlite3WalkExprList(&w, pWInfo->pOrderBy);
+ sqlite3WalkExprList(&w, pWInfo->pResultSet);
+ }
+}
+
+/*
+** The pTruth expression is always true because it is the WHERE clause
+** a partial index that is driving a query loop. Look through all of the
+** WHERE clause terms on the query, and if any of those terms must be
+** true because pTruth is true, then mark those WHERE clause terms as
+** coded.
+*/
+static void whereApplyPartialIndexConstraints(
+ Expr *pTruth,
+ int iTabCur,
+ WhereClause *pWC
+){
+ int i;
+ WhereTerm *pTerm;
+ while( pTruth->op==TK_AND ){
+ whereApplyPartialIndexConstraints(pTruth->pLeft, iTabCur, pWC);
+ pTruth = pTruth->pRight;
+ }
+ for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+ Expr *pExpr;
+ if( pTerm->wtFlags & TERM_CODED ) continue;
+ pExpr = pTerm->pExpr;
+ if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){
+ pTerm->wtFlags |= TERM_CODED;
+ }
+ }
+}
+
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
+ Parse *pParse, /* Parsing context */
+ Vdbe *v, /* Prepared statement under construction */
WhereInfo *pWInfo, /* Complete information about the WHERE clause */
int iLevel, /* Which level of pWInfo->a[] should be coded */
+ WhereLevel *pLevel, /* The current level pointer */
Bitmask notReady /* Which tables are currently available */
){
int j, k; /* Loop counters */
int iCur; /* The VDBE cursor for the table */
int addrNxt; /* Where to jump to continue with the next IN case */
- int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
- WhereLevel *pLevel; /* The where level to be coded */
WhereLoop *pLoop; /* The WhereLoop object being coded */
WhereClause *pWC; /* Decomposition of the entire WHERE clause */
WhereTerm *pTerm; /* A WHERE clause term */
- Parse *pParse; /* Parsing context */
sqlite3 *db; /* Database connection */
- Vdbe *v; /* The prepared stmt under constructions */
struct SrcList_item *pTabItem; /* FROM clause term being coded */
int addrBrk; /* Jump here to break out of the loop */
+ int addrHalt; /* addrBrk for the outermost loop */
int addrCont; /* Jump here to continue with next cycle */
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
int iReleaseReg = 0; /* Temp register to free before returning */
+ Index *pIdx = 0; /* Index used by loop (if any) */
+ int iLoop; /* Iteration of constraint generator loop */
- pParse = pWInfo->pParse;
- v = pParse->pVdbe;
pWC = &pWInfo->sWC;
db = pParse->db;
- pLevel = &pWInfo->a[iLevel];
pLoop = pLevel->pWLoop;
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
- omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
+#if WHERETRACE_ENABLED /* 0x20800 */
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
+ iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
+ sqlite3WhereLoopPrint(pLoop, pWC);
+ }
+ if( sqlite3WhereTrace & 0x20000 ){
+ if( iLevel==0 ){
+ sqlite3DebugPrintf("WHERE clause being coded:\n");
+ sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
+ }
+ sqlite3DebugPrintf("All WHERE-clause terms before coding:\n");
+ sqlite3WhereClausePrint(pWC);
+ }
+#endif
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
@@ -125412,26 +142852,34 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** there are no IN operators in the constraints, the "addrNxt" label
** is the same as "addrBrk".
*/
- addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
- addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v);
+ addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
+ addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(pParse);
/* If this is the right table of a LEFT OUTER JOIN, allocate and
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
+ assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
+ || pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0
+ );
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
pLevel->iLeftJoin = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
VdbeComment((v, "init LEFT JOIN no-match flag"));
}
+ /* Compute a safe address to jump to if we discover that the table for
+ ** this loop is empty and can never contribute content. */
+ for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
+ addrHalt = pWInfo->a[j].addrBrk;
+
/* Special case of a FROM clause subquery implemented as a co-routine */
if( pTabItem->fg.viaCoroutine ){
int regYield = pTabItem->regReturn;
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeCoverage(v);
- VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
pLevel->op = OP_Goto;
}else
@@ -125445,7 +142893,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int nConstraint = pLoop->nLTerm;
int iIn; /* Counter for IN constraints */
- sqlite3ExprCachePush(pParse);
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
addrNotFound = pLevel->addrBrk;
for(j=0; j<nConstraint; j++){
@@ -125464,7 +142911,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
pLoop->u.vtab.idxStr,
- pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
+ pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
VdbeCoverage(v);
pLoop->u.vtab.needFree = 0;
pLevel->p1 = iCur;
@@ -125473,9 +142920,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
iIn = pLevel->u.in.nIn;
for(j=nConstraint-1; j>=0; j--){
pTerm = pLoop->aLTerm[j];
+ if( (pTerm->eOperator & WO_IN)!=0 ) iIn--;
if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
disableTerm(pLevel, pTerm);
- }else if( (pTerm->eOperator & WO_IN)!=0 ){
+ }else if( (pTerm->eOperator & WO_IN)!=0
+ && sqlite3ExprVectorSize(pTerm->pExpr->pLeft)==1
+ ){
Expr *pCompare; /* The comparison operator */
Expr *pRight; /* RHS of the comparison */
VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
@@ -125486,8 +142936,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** encoding of the value in the register, so it *must* be reloaded. */
assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
if( !db->mallocFailed ){
- assert( iIn>0 );
- pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
+ assert( iIn>=0 && iIn<pLevel->u.in.nIn );
+ pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop);
assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
@@ -125495,22 +142945,25 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
}
- /* Generate code that will continue to the next row if
+ /* Generate code that will continue to the next row if
** the IN constraint is not satisfied */
- pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0, 0);
+ pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
assert( pCompare!=0 || db->mallocFailed );
if( pCompare ){
pCompare->pLeft = pTerm->pExpr->pLeft;
pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
if( pRight ){
pRight->iTable = iReg+j+2;
- sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
+ sqlite3ExprIfFalse(
+ pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL
+ );
}
pCompare->pLeft = 0;
sqlite3ExprDelete(db, pCompare);
}
}
}
+ assert( iIn==0 || db->mallocFailed );
/* These registers need to be preserved in case there is an IN operator
** loop. So we could deallocate the registers here (and potentially
** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems
@@ -125518,7 +142971,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
**
** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
*/
- sqlite3ExprCachePop(pParse);
}else
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -125534,7 +142986,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->pExpr!=0 );
- assert( omitTable==0 );
testcase( pTerm->wtFlags & TERM_VIRTUAL );
iReleaseReg = ++pParse->nMem;
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
@@ -125542,10 +142993,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
addrNxt = pLevel->addrNxt;
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
- sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
- VdbeComment((v, "pk"));
pLevel->op = OP_Noop;
+ if( (pTerm->prereqAll & pLevel->notReady)==0 ){
+ pTerm->wtFlags |= TERM_CODED;
+ }
}else if( (pLoop->wsFlags & WHERE_IPK)!=0
&& (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
){
@@ -125556,7 +143007,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int memEndValue = 0;
WhereTerm *pStart, *pEnd;
- assert( omitTable==0 );
j = 0;
pStart = pEnd = 0;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++];
@@ -125573,7 +143023,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int r1, rTemp; /* Registers for holding the start boundary */
int op; /* Cursor seek operation */
- /* The following constant maps TK_xx codes into corresponding
+ /* The following constant maps TK_xx codes into corresponding
** seek opcodes. It depends on a particular ordering of TK_xx
*/
const u8 aMoveOp[] = {
@@ -125594,7 +143044,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( sqlite3ExprIsVector(pX->pRight) ){
r1 = rTemp = sqlite3GetTempReg(pParse);
codeExprOrVector(pParse, pX->pRight, r1, 1);
- op = aMoveOp[(pX->op - TK_GT) | 0x0001];
+ testcase( pX->op==TK_GT );
+ testcase( pX->op==TK_GE );
+ testcase( pX->op==TK_LT );
+ testcase( pX->op==TK_LE );
+ op = aMoveOp[((pX->op - TK_GT - 1) & 0x3) | 0x1];
+ assert( pX->op!=TK_GT || op==OP_SeekGE );
+ assert( pX->op!=TK_GE || op==OP_SeekGE );
+ assert( pX->op!=TK_LT || op==OP_SeekLE );
+ assert( pX->op!=TK_LE || op==OP_SeekLE );
}else{
r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
disableTerm(pLevel, pStart);
@@ -125606,10 +143064,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverageIf(v, pX->op==TK_LE);
VdbeCoverageIf(v, pX->op==TK_LT);
VdbeCoverageIf(v, pX->op==TK_GE);
- sqlite3ExprCacheAffinityChange(pParse, r1, 1);
sqlite3ReleaseTempReg(pParse, rTemp);
}else{
- sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
+ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrHalt);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
}
@@ -125622,8 +143079,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
testcase( pEnd->wtFlags & TERM_VIRTUAL );
memEndValue = ++pParse->nMem;
codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
- if( 0==sqlite3ExprIsVector(pX->pRight)
- && (pX->op==TK_LT || pX->op==TK_GT)
+ if( 0==sqlite3ExprIsVector(pX->pRight)
+ && (pX->op==TK_LT || pX->op==TK_GT)
){
testOp = bRev ? OP_Le : OP_Ge;
}else{
@@ -125641,7 +143098,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( testOp!=OP_Noop ){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg);
VdbeCoverageIf(v, testOp==OP_Le);
VdbeCoverageIf(v, testOp==OP_Lt);
@@ -125652,14 +143108,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}else if( pLoop->wsFlags & WHERE_INDEXED ){
/* Case 4: A scan using an index.
**
- ** The WHERE clause may contain zero or more equality
+ ** The WHERE clause may contain zero or more equality
** terms ("==" or "IN" operators) that refer to the N
** left-most columns of the index. It may also contain
** inequality constraints (>, <, >= or <=) on the indexed
- ** column that immediately follows the N equalities. Only
+ ** column that immediately follows the N equalities. Only
** the right-most column can be an inequality - the rest must
- ** use the "==" and "IN" operators. For example, if the
- ** index is on (x,y,z), then the following clauses are all
+ ** use the "==" and "IN" operators. For example, if the
+ ** index is on (x,y,z), then the following clauses are all
** optimized:
**
** x=5
@@ -125680,7 +143136,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** This case is also used when there are no WHERE clause
** constraints but an index is selected anyway, in order
** to force the output order to conform to an ORDER BY.
- */
+ */
static const u8 aStartOp[] = {
0,
0,
@@ -125707,7 +143163,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int endEq; /* True if range end uses ==, >= or <= */
int start_constraints; /* Start of range is constrained */
int nConstraint; /* Number of constraint terms */
- Index *pIdx; /* The index we will be using */
int iIdxCur; /* The VDBE cursor for the index */
int nExtraReg = 0; /* Number of extra registers needed */
int op; /* Instruction opcode */
@@ -125715,40 +143170,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
char *zEndAff = 0; /* Affinity for end of range constraint */
u8 bSeekPastNull = 0; /* True to seek past initial nulls */
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
+ int omitTable; /* True if we use the index only */
+ int regBignull = 0; /* big-null flag register */
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
assert( nEq>=pLoop->nSkip );
- /* If this loop satisfies a sort order (pOrderBy) request that
- ** was passed to this function to implement a "SELECT min(x) ..."
- ** query, then the caller will only allow the loop to run for
- ** a single iteration. This means that the first row returned
- ** should not have a NULL value stored in 'x'. If column 'x' is
- ** the first one after the nEq equality constraints in the index,
- ** this requires some special handling.
- */
- assert( pWInfo->pOrderBy==0
- || pWInfo->pOrderBy->nExpr==1
- || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
- if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
- && pWInfo->nOBSat>0
- && (pIdx->nKeyCol>nEq)
- ){
- assert( pLoop->nSkip==0 );
- bSeekPastNull = 1;
- nExtraReg = 1;
- }
-
- /* Find any inequality constraint terms for the start and end
- ** of the range.
+ /* Find any inequality constraint terms for the start and end
+ ** of the range.
*/
j = nEq;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
/* Like optimization range constraints always occur in pairs */
- assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
+ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
(pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
@@ -125780,8 +143217,30 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
+ /* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses
+ ** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS
+ ** FIRST). In both cases separate ordered scans are made of those
+ ** index entries for which the column is null and for those for which
+ ** it is not. For an ASC sort, the non-NULL entries are scanned first.
+ ** For DESC, NULL entries are scanned first.
+ */
+ if( (pLoop->wsFlags & (WHERE_TOP_LIMIT|WHERE_BTM_LIMIT))==0
+ && (pLoop->wsFlags & WHERE_BIGNULL_SORT)!=0
+ ){
+ assert( bSeekPastNull==0 && nExtraReg==0 && nBtm==0 && nTop==0 );
+ assert( pRangeEnd==0 && pRangeStart==0 );
+ testcase( pLoop->nSkip>0 );
+ nExtraReg = 1;
+ bSeekPastNull = 1;
+ pLevel->regBignull = regBignull = ++pParse->nMem;
+ if( pLevel->iLeftJoin ){
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull);
+ }
+ pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
+ }
+
/* If we are doing a reverse order scan on an ascending index, or
- ** a forward order scan on a descending index, interchange the
+ ** a forward order scan on a descending index, interchange the
** start and end terms (pRangeStart and pRangeEnd).
*/
if( (nEq<pIdx->nKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
@@ -125802,7 +143261,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( zStartAff && nTop ){
zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
}
- addrNxt = pLevel->addrNxt;
+ addrNxt = (regBignull ? pLevel->addrBignull : pLevel->addrNxt);
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 );
@@ -125826,7 +143285,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
if( zStartAff ){
updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]);
- }
+ }
nConstraint += nBtm;
testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
if( sqlite3ExprIsVector(pRight)==0 ){
@@ -125836,10 +143295,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
bSeekPastNull = 0;
}else if( bSeekPastNull ){
+ startEq = 0;
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
+ start_constraints = 1;
nConstraint++;
- startEq = 0;
+ }else if( regBignull ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
start_constraints = 1;
+ nConstraint++;
}
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
@@ -125847,6 +143310,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** above has already left the cursor sitting on the correct row,
** so no further seeking is needed */
}else{
+ if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
+ sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
+ }
+ if( regBignull ){
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
+ VdbeComment((v, "NULL-scan pass ctr"));
+ }
+
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
assert( op!=0 );
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -125857,6 +143328,23 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
+
+ assert( bSeekPastNull==0 || bStopAtNull==0 );
+ if( regBignull ){
+ assert( bSeekPastNull==1 || bStopAtNull==1 );
+ assert( bSeekPastNull==!bStopAtNull );
+ assert( bStopAtNull==startEq );
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
+ op = aStartOp[(nConstraint>1)*4 + 2 + bRev];
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
+ nConstraint-startEq);
+ VdbeCoverage(v);
+ VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
+ VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
+ VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
+ VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
+ assert( op==OP_Rewind || op==OP_Last || op==OP_SeekGE || op==OP_SeekLE);
+ }
}
/* Load the value for the inequality constraint at the end of the
@@ -125865,7 +143353,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
nConstraint = nEq;
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
- sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -125889,8 +143376,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
endEq = 1;
}
}else if( bStopAtNull ){
- sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
- endEq = 0;
+ if( regBignull==0 ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
+ endEq = 0;
+ }
nConstraint++;
}
sqlite3DbFree(db, zStartAff);
@@ -125901,6 +143390,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
+ if( regBignull ){
+ /* Except, skip the end-of-range check while doing the NULL-scan */
+ sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3);
+ VdbeComment((v, "If NULL-scan 2nd pass"));
+ VdbeCoverage(v);
+ }
op = aEndOp[bRev*2 + endEq];
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
@@ -125908,15 +143403,40 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
}
+ if( regBignull ){
+ /* During a NULL-scan, check to see if we have reached the end of
+ ** the NULLs */
+ assert( bSeekPastNull==!bStopAtNull );
+ assert( bSeekPastNull+bStopAtNull==1 );
+ assert( nConstraint+bSeekPastNull>0 );
+ sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2);
+ VdbeComment((v, "If NULL-scan 1st pass"));
+ VdbeCoverage(v);
+ op = aEndOp[bRev*2 + bSeekPastNull];
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
+ nConstraint+bSeekPastNull);
+ testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT );
+ testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
+ testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
+ testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
+ }
+
+ if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
+ sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1);
+ }
/* Seek the table cursor, if required */
+ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
- if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)!=0 ){
+ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)
+ || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)!=0
+ && (pWInfo->eOnePass==ONEPASS_SINGLE || pLoop->nLTerm==0) )
+ ){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
- sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
VdbeCoverage(v);
}else{
@@ -125926,13 +143446,53 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; j<pPk->nKeyCol; j++){
- k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j);
}
sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont,
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
+ if( pLevel->iLeftJoin==0 ){
+ /* If pIdx is an index on one or more expressions, then look through
+ ** all the expressions in pWInfo and try to transform matching expressions
+ ** into reference to index columns. Also attempt to translate references
+ ** to virtual columns in the table into references to (stored) columns
+ ** of the index.
+ **
+ ** Do not do this for the RHS of a LEFT JOIN. This is because the
+ ** expression may be evaluated after OP_NullRow has been executed on
+ ** the cursor. In this case it is important to do the full evaluation,
+ ** as the result of the expression may not be NULL, even if all table
+ ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
+ **
+ ** Also, do not do this when processing one index an a multi-index
+ ** OR clause, since the transformation will become invalid once we
+ ** move forward to the next index.
+ ** https://sqlite.org/src/info/4e8e4857d32d401f
+ */
+ if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
+ whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
+ }
+
+ /* If a partial index is driving the loop, try to eliminate WHERE clause
+ ** terms from the query that must be true due to the WHERE clause of
+ ** the partial index.
+ **
+ ** 2019-11-02 ticket 623eff57e76d45f6: This optimization does not work
+ ** for a LEFT JOIN.
+ */
+ if( pIdx->pPartIdxWhere ){
+ whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC);
+ }
+ }else{
+ testcase( pIdx->pPartIdxWhere );
+ /* The following assert() is not a requirement, merely an observation:
+ ** The OR-optimization doesn't work for the right hand table of
+ ** a LEFT JOIN: */
+ assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 );
+ }
+
/* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;
@@ -125948,6 +143508,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}else{
assert( pLevel->p5==0 );
}
+ if( omitTable ) pIdx = 0;
}else
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
@@ -126003,7 +143564,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
int regRowset = 0; /* Register for RowSet object */
int regRowid = 0; /* Register holding rowid */
- int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */
+ int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */
int iRetInit; /* Address of regReturn init */
int untestedTerms = 0; /* Some terms not completely tested */
int ii; /* Loop counter */
@@ -126041,15 +143602,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pOrTab = pWInfo->pTabList;
}
- /* Initialize the rowset register to contain NULL. An SQL NULL is
+ /* Initialize the rowset register to contain NULL. An SQL NULL is
** equivalent to an empty rowset. Or, create an ephemeral index
** capable of holding primary keys in the case of a WITHOUT ROWID.
**
- ** Also initialize regReturn to contain the address of the instruction
+ ** Also initialize regReturn to contain the address of the instruction
** immediately following the OP_Return at the bottom of the loop. This
** is required in a few obscure LEFT JOIN cases where control jumps
- ** over the top of the loop into the body of it. In this case the
- ** correct response for the end-of-loop code (the OP_Return) is to
+ ** over the top of the loop into the body of it. In this case the
+ ** correct response for the end-of-loop code (the OP_Return) is to
** fall through to the next instruction, just as an OP_Next does if
** called on an uninitialized cursor.
*/
@@ -126074,7 +143635,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
**
** Actually, each subexpression is converted to "xN AND w" where w is
** the "interesting" terms of z - terms that did not originate in the
- ** ON or USING clause of a LEFT JOIN, and terms that are usable as
+ ** ON or USING clause of a LEFT JOIN, and terms that are usable as
** indices.
**
** This optimization also only applies if the (x1 OR x2 OR ...) term
@@ -126086,17 +143647,21 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
Expr *pExpr = pWC->a[iTerm].pExpr;
if( &pWC->a[iTerm] == pTerm ) continue;
- if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
pExpr = sqlite3ExprDup(db, pExpr, 0);
- pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
+ pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr);
}
if( pAndExpr ){
- pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr, 0);
+ /* The extra 0x10000 bit on the opcode is masked off and does not
+ ** become part of the new Expr.op. However, it does make the
+ ** op==TK_AND comparison inside of sqlite3PExpr() false, and this
+ ** prevents sqlite3PExpr() from implementing AND short-circuit
+ ** optimization, which we do not want here. */
+ pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr);
}
}
@@ -126105,17 +143670,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
+ ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR"));
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
int jmp1 = 0; /* Address of jump operation */
- if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
+ testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
+ && !ExprHasProperty(pOrExpr, EP_FromJoin)
+ ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
+ if( pAndExpr ){
pAndExpr->pLeft = pOrExpr;
pOrExpr = pAndExpr;
}
/* Loop through table entries that match term pOrTerm. */
+ ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
wctrlFlags, iCovCur);
@@ -126123,7 +143693,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( pSubWInfo ){
WhereLoop *pSubLoop;
int addrExplain = sqlite3WhereExplainOneScan(
- pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
+ pParse, pOrTab, &pSubWInfo->a[0], 0
);
sqlite3WhereAddScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain);
@@ -126133,23 +143703,23 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** row will be skipped in subsequent sub-WHERE clauses.
*/
if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
- int r;
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
if( HasRowid(pTab) ){
- r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid);
jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
- r,iSet);
+ regRowid, iSet);
VdbeCoverage(v);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
int nPk = pPk->nKeyCol;
int iPk;
+ int r;
/* Read the PK into an array of temp registers. */
r = sqlite3GetTempRange(pParse, nPk);
for(iPk=0; iPk<nPk; iPk++){
int iCol = pPk->aiColumn[iPk];
- sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk);
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
}
/* Check if the temp table already contains this key. If so,
@@ -126160,16 +143730,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
**
** Use some of the same optimizations as OP_RowSetTest: If iSet
** is zero, assume that the key cannot already be present in
- ** the temp table. And if iSet is -1, assume that there is no
- ** need to insert the key into the temp table, as it will never
- ** be tested for. */
+ ** the temp table. And if iSet is -1, assume that there is no
+ ** need to insert the key into the temp table, as it will never
+ ** be tested for. */
if( iSet ){
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
VdbeCoverage(v);
}
if( iSet>=0 ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
- sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid,
+ r, nPk);
if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
}
@@ -126200,8 +143771,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** If the call to sqlite3WhereBegin() above resulted in a scan that
** uses an index, and this is either the first OR-connected term
** processed or the index is the same as that used by all previous
- ** terms, set pCov to the candidate covering index. Otherwise, set
- ** pCov to NULL to indicate that no candidate covering index will
+ ** terms, set pCov to the candidate covering index. Otherwise, set
+ ** pCov to NULL to indicate that no candidate covering index will
** be available.
*/
pSubLoop = pSubWInfo->a[0].pWLoop;
@@ -126218,9 +143789,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
/* Finish the loop through table entries that match term pOrTerm. */
sqlite3WhereEnd(pSubWInfo);
+ ExplainQueryPlanPop(pParse);
}
}
}
+ ExplainQueryPlanPop(pParse);
pLevel->u.pCovidx = pCov;
if( pCov ) pLevel->iIdxCur = iCovCur;
if( pAndExpr ){
@@ -126231,7 +143804,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeGoto(v, pLevel->addrBrk);
sqlite3VdbeResolveLabel(v, iLoopBody);
- if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab);
+ if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -126251,7 +143824,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
codeCursorHint(pTabItem, pWInfo, pLevel, 0);
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
- pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
+ pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrHalt);
VdbeCoverageIf(v, bRev==0);
VdbeCoverageIf(v, bRev!=0);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
@@ -126264,43 +143837,81 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
+ **
+ ** This loop may run between one and three times, depending on the
+ ** constraints to be generated. The value of stack variable iLoop
+ ** determines the constraints coded by each iteration, as follows:
+ **
+ ** iLoop==1: Code only expressions that are entirely covered by pIdx.
+ ** iLoop==2: Code remaining expressions that do not contain correlated
+ ** sub-queries.
+ ** iLoop==3: Code all remaining expressions.
+ **
+ ** An effort is made to skip unnecessary iterations of the loop.
*/
- for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
- Expr *pE;
- int skipLikeAddr = 0;
- testcase( pTerm->wtFlags & TERM_VIRTUAL );
- testcase( pTerm->wtFlags & TERM_CODED );
- if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
- if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
- testcase( pWInfo->untestedTerms==0
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
- pWInfo->untestedTerms = 1;
- continue;
- }
- pE = pTerm->pExpr;
- assert( pE!=0 );
- if( pLevel->iLeftJoin && !ExprHasProperty(pE, EP_FromJoin) ){
- continue;
- }
- if( pTerm->wtFlags & TERM_LIKECOND ){
- /* If the TERM_LIKECOND flag is set, that means that the range search
- ** is sufficient to guarantee that the LIKE operator is true, so we
- ** can skip the call to the like(A,B) function. But this only works
- ** for strings. So do not skip the call to the function on the pass
- ** that compares BLOBs. */
+ iLoop = (pIdx ? 1 : 2);
+ do{
+ int iNext = 0; /* Next value for iLoop */
+ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
+ Expr *pE;
+ int skipLikeAddr = 0;
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
+ testcase( pTerm->wtFlags & TERM_CODED );
+ if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
+ if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
+ testcase( pWInfo->untestedTerms==0
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
+ pWInfo->untestedTerms = 1;
+ continue;
+ }
+ pE = pTerm->pExpr;
+ assert( pE!=0 );
+ if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){
+ continue;
+ }
+
+ if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
+ iNext = 2;
+ continue;
+ }
+ if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){
+ if( iNext==0 ) iNext = 3;
+ continue;
+ }
+
+ if( (pTerm->wtFlags & TERM_LIKECOND)!=0 ){
+ /* If the TERM_LIKECOND flag is set, that means that the range search
+ ** is sufficient to guarantee that the LIKE operator is true, so we
+ ** can skip the call to the like(A,B) function. But this only works
+ ** for strings. So do not skip the call to the function on the pass
+ ** that compares BLOBs. */
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- continue;
+ continue;
#else
- u32 x = pLevel->iLikeRepCntr;
- assert( x>0 );
- skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
- VdbeCoverage(v);
+ u32 x = pLevel->iLikeRepCntr;
+ if( x>0 ){
+ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1));
+ VdbeCoverageIf(v, (x&1)==1);
+ VdbeCoverageIf(v, (x&1)==0);
+ }
+#endif
+ }
+#ifdef WHERETRACE_ENABLED /* 0xffff */
+ if( sqlite3WhereTrace ){
+ VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
+ pWC->nTerm-j, pTerm, iLoop));
+ }
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("Coding auxiliary constraint:\n");
+ sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
+ }
#endif
+ sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
+ if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
+ pTerm->wtFlags |= TERM_CODED;
}
- sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
- if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr);
- pTerm->wtFlags |= TERM_CODED;
- }
+ iLoop = iNext;
+ }while( iLoop>0 );
/* Insert code to test for implied constraints based on transitivity
** of the "==" operator.
@@ -126317,14 +143928,26 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
if( pTerm->leftCursor!=iCur ) continue;
- if( pLevel->iLeftJoin ) continue;
+ if( pTabItem->fg.jointype & JT_LEFT ) continue;
pE = pTerm->pExpr;
+#ifdef WHERETRACE_ENABLED /* 0x800 */
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("Coding transitive constraint:\n");
+ sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
+ }
+#endif
assert( !ExprHasProperty(pE, EP_FromJoin) );
assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
WO_EQ|WO_IN|WO_IS, 0);
if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
+ if( (pAlt->eOperator & WO_IN)
+ && (pAlt->pExpr->flags & EP_xIsSelect)
+ && (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
+ ){
+ continue;
+ }
testcase( pAlt->eOperator & WO_EQ );
testcase( pAlt->eOperator & WO_IS );
testcase( pAlt->eOperator & WO_IN );
@@ -126335,13 +143958,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
/* For a LEFT OUTER JOIN, generate code that will record the fact that
- ** at least one row of the right table has matched the left table.
+ ** at least one row of the right table has matched the left table.
*/
if( pLevel->iLeftJoin ){
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
VdbeComment((v, "record LEFT JOIN hit"));
- sqlite3ExprCacheClear(pParse);
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
@@ -126356,6 +143978,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
}
+#if WHERETRACE_ENABLED /* 0x20800 */
+ if( sqlite3WhereTrace & 0x20000 ){
+ sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
+ iLevel);
+ sqlite3WhereClausePrint(pWC);
+ }
+ if( sqlite3WhereTrace & 0x800 ){
+ sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n",
+ iLevel, (u64)pLevel->notReady);
+ }
+#endif
return pLevel->notReady;
}
@@ -126447,7 +144080,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
}else{
pTerm->truthProb = 1;
}
- pTerm->pExpr = sqlite3ExprSkipCollate(p);
+ pTerm->pExpr = sqlite3ExprSkipCollateAndLikely(p);
pTerm->wtFlags = wtFlags;
pTerm->pWC = pWC;
pTerm->iParent = -1;
@@ -126472,31 +144105,14 @@ static int allowedOp(int op){
/*
** Commute a comparison operator. Expressions of the form "X op Y"
** are converted into "Y op X".
-**
-** If left/right precedence rules come into play when determining the
-** collating sequence, then COLLATE operators are adjusted to ensure
-** that the collating sequence does not change. For example:
-** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on
-** the left hand side of a comparison overrides any collation sequence
-** attached to the right. For the same reason the EP_Collate flag
-** is not commuted.
-*/
-static void exprCommute(Parse *pParse, Expr *pExpr){
- u16 expRight = (pExpr->pRight->flags & EP_Collate);
- u16 expLeft = (pExpr->pLeft->flags & EP_Collate);
- assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN );
- if( expRight==expLeft ){
- /* Either X and Y both have COLLATE operator or neither do */
- if( expRight ){
- /* Both X and Y have COLLATE operators. Make sure X is always
- ** used by clearing the EP_Collate flag from Y. */
- pExpr->pRight->flags &= ~EP_Collate;
- }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){
- /* Neither X nor Y have COLLATE operators, but X has a non-default
- ** collating sequence. So add the EP_Collate marker on X to cause
- ** it to be searched first. */
- pExpr->pLeft->flags |= EP_Collate;
- }
+*/
+static u16 exprCommute(Parse *pParse, Expr *pExpr){
+ if( pExpr->pLeft->op==TK_VECTOR
+ || pExpr->pRight->op==TK_VECTOR
+ || sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight) !=
+ sqlite3BinaryCompareCollSeq(pParse, pExpr->pRight, pExpr->pLeft)
+ ){
+ pExpr->flags ^= EP_Commuted;
}
SWAP(Expr*,pExpr->pRight,pExpr->pLeft);
if( pExpr->op>=TK_GT ){
@@ -126507,6 +144123,7 @@ static void exprCommute(Parse *pParse, Expr *pExpr){
assert( pExpr->op>=TK_GT && pExpr->op<=TK_GE );
pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT;
}
+ return 0;
}
/*
@@ -126557,18 +144174,18 @@ static int isLikeOrGlob(
int *pisComplete, /* True if the only wildcard is % in the last character */
int *pnoCase /* True if uppercase is equivalent to lowercase */
){
- const char *z = 0; /* String on RHS of LIKE operator */
+ const u8 *z = 0; /* String on RHS of LIKE operator */
Expr *pRight, *pLeft; /* Right and left size of LIKE operator */
ExprList *pList; /* List of operands to the LIKE operator */
- int c; /* One character in z[] */
+ u8 c; /* One character in z[] */
int cnt; /* Number of non-wildcard prefix characters */
- char wc[3]; /* Wildcard characters */
+ u8 wc[4]; /* Wildcard characters */
sqlite3 *db = pParse->db; /* Database connection */
sqlite3_value *pVal = 0;
int op; /* Opcode of pRight */
int rc; /* Result code to return */
- if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){
+ if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){
return 0;
}
#ifdef SQLITE_EBCDIC
@@ -126576,41 +144193,97 @@ static int isLikeOrGlob(
#endif
pList = pExpr->x.pList;
pLeft = pList->a[1].pExpr;
- if( pLeft->op!=TK_COLUMN
- || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
- || IsVirtual(pLeft->pTab) /* Value might be numeric */
- ){
- /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must
- ** be the name of an indexed column with TEXT affinity. */
- return 0;
- }
- assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr);
op = pRight->op;
- if( op==TK_VARIABLE ){
+ if( op==TK_VARIABLE && (db->flags & SQLITE_EnableQPSG)==0 ){
Vdbe *pReprepare = pParse->pReprepare;
int iCol = pRight->iColumn;
pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB);
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
- z = (char *)sqlite3_value_text(pVal);
+ z = sqlite3_value_text(pVal);
}
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
}else if( op==TK_STRING ){
- z = pRight->u.zToken;
+ z = (u8*)pRight->u.zToken;
}
if( z ){
+
+ /* Count the number of prefix characters prior to the first wildcard */
cnt = 0;
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
cnt++;
- }
- if( cnt!=0 && 255!=(u8)z[cnt-1] ){
+ if( c==wc[3] && z[cnt]!=0 ) cnt++;
+ }
+
+ /* The optimization is possible only if (1) the pattern does not begin
+ ** with a wildcard and if (2) the non-wildcard prefix does not end with
+ ** an (illegal 0xff) character, or (3) the pattern does not consist of
+ ** a single escape character. The second condition is necessary so
+ ** that we can increment the prefix key to find an upper bound for the
+ ** range search. The third is because the caller assumes that the pattern
+ ** consists of at least one character after all escapes have been
+ ** removed. */
+ if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
Expr *pPrefix;
+
+ /* A "complete" match if the pattern ends with "*" or "%" */
*pisComplete = c==wc[0] && z[cnt+1]==0;
- pPrefix = sqlite3Expr(db, TK_STRING, z);
- if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
+
+ /* Get the pattern prefix. Remove all escapes from the prefix. */
+ pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
+ if( pPrefix ){
+ int iFrom, iTo;
+ char *zNew = pPrefix->u.zToken;
+ zNew[cnt] = 0;
+ for(iFrom=iTo=0; iFrom<cnt; iFrom++){
+ if( zNew[iFrom]==wc[3] ) iFrom++;
+ zNew[iTo++] = zNew[iFrom];
+ }
+ zNew[iTo] = 0;
+ assert( iTo>0 );
+
+ /* If the LHS is not an ordinary column with TEXT affinity, then the
+ ** pattern prefix boundaries (both the start and end boundaries) must
+ ** not look like a number. Otherwise the pattern might be treated as
+ ** a number, which will invalidate the LIKE optimization.
+ **
+ ** Getting this right has been a persistent source of bugs in the
+ ** LIKE optimization. See, for example:
+ ** 2018-09-10 https://sqlite.org/src/info/c94369cae9b561b1
+ ** 2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28
+ ** 2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
+ ** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
+ ** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
+ */
+ if( pLeft->op!=TK_COLUMN
+ || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
+ || IsVirtual(pLeft->y.pTab) /* Value might be numeric */
+ ){
+ int isNum;
+ double rDummy;
+ isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
+ if( isNum<=0 ){
+ if( iTo==1 && zNew[0]=='-' ){
+ isNum = +1;
+ }else{
+ zNew[iTo-1]++;
+ isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
+ zNew[iTo-1]--;
+ }
+ }
+ if( isNum>0 ){
+ sqlite3ExprDelete(db, pPrefix);
+ sqlite3ValueFree(pVal);
+ return 0;
+ }
+ }
+ }
*ppPrefix = pPrefix;
+
+ /* If the RHS pattern is a bound parameter, make arrangements to
+ ** reprepare the statement when that parameter is rebound */
if( op==TK_VARIABLE ){
Vdbe *v = pParse->pVdbe;
sqlite3VdbeSetVarmask(v, pRight->iColumn);
@@ -126620,7 +144293,7 @@ static int isLikeOrGlob(
** function, then no OP_Variable will be added to the program.
** This causes problems for the sqlite3_bind_parameter_name()
** API. To work around them, add a dummy OP_Variable here.
- */
+ */
int r1 = sqlite3GetTempReg(pParse);
sqlite3ExprCodeTarget(pParse, pRight, r1);
sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0);
@@ -126641,48 +144314,127 @@ static int isLikeOrGlob(
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
-** Check to see if the given expression is of the form
-**
-** column OP expr
-**
-** where OP is one of MATCH, GLOB, LIKE or REGEXP and "column" is a
-** column of a virtual table.
-**
-** If it is then return TRUE. If not, return FALSE.
-*/
-static int isMatchOfColumn(
+** Check to see if the pExpr expression is a form that needs to be passed
+** to the xBestIndex method of virtual tables. Forms of interest include:
+**
+** Expression Virtual Table Operator
+** ----------------------- ---------------------------------
+** 1. column MATCH expr SQLITE_INDEX_CONSTRAINT_MATCH
+** 2. column GLOB expr SQLITE_INDEX_CONSTRAINT_GLOB
+** 3. column LIKE expr SQLITE_INDEX_CONSTRAINT_LIKE
+** 4. column REGEXP expr SQLITE_INDEX_CONSTRAINT_REGEXP
+** 5. column != expr SQLITE_INDEX_CONSTRAINT_NE
+** 6. expr != column SQLITE_INDEX_CONSTRAINT_NE
+** 7. column IS NOT expr SQLITE_INDEX_CONSTRAINT_ISNOT
+** 8. expr IS NOT column SQLITE_INDEX_CONSTRAINT_ISNOT
+** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL
+**
+** In every case, "column" must be a column of a virtual table. If there
+** is a match, set *ppLeft to the "column" expression, set *ppRight to the
+** "expr" expression (even though in forms (6) and (8) the column is on the
+** right and the expression is on the left). Also set *peOp2 to the
+** appropriate virtual table operator. The return value is 1 or 2 if there
+** is a match. The usual return is 1, but if the RHS is also a column
+** of virtual table in forms (5) or (7) then return 2.
+**
+** If the expression matches none of the patterns above, return 0.
+*/
+static int isAuxiliaryVtabOperator(
+ sqlite3 *db, /* Parsing context */
Expr *pExpr, /* Test this expression */
- unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
-){
- static const struct Op2 {
- const char *zOp;
- unsigned char eOp2;
- } aOp[] = {
- { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
- { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
- { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
- { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
- };
- ExprList *pList;
- Expr *pCol; /* Column reference */
- int i;
+ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */
+ Expr **ppLeft, /* Column expression to left of MATCH/op2 */
+ Expr **ppRight /* Expression to left of MATCH/op2 */
+){
+ if( pExpr->op==TK_FUNCTION ){
+ static const struct Op2 {
+ const char *zOp;
+ unsigned char eOp2;
+ } aOp[] = {
+ { "match", SQLITE_INDEX_CONSTRAINT_MATCH },
+ { "glob", SQLITE_INDEX_CONSTRAINT_GLOB },
+ { "like", SQLITE_INDEX_CONSTRAINT_LIKE },
+ { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP }
+ };
+ ExprList *pList;
+ Expr *pCol; /* Column reference */
+ int i;
- if( pExpr->op!=TK_FUNCTION ){
- return 0;
- }
- pList = pExpr->x.pList;
- if( pList==0 || pList->nExpr!=2 ){
- return 0;
- }
- pCol = pList->a[1].pExpr;
- if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
- return 0;
- }
- for(i=0; i<ArraySize(aOp); i++){
- if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
- *peOp2 = aOp[i].eOp2;
- return 1;
+ pList = pExpr->x.pList;
+ if( pList==0 || pList->nExpr!=2 ){
+ return 0;
}
+
+ /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a
+ ** virtual table on their second argument, which is the same as
+ ** the left-hand side operand in their in-fix form.
+ **
+ ** vtab_column MATCH expression
+ ** MATCH(expression,vtab_column)
+ */
+ pCol = pList->a[1].pExpr;
+ testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ if( ExprIsVtab(pCol) ){
+ for(i=0; i<ArraySize(aOp); i++){
+ if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
+ *peOp2 = aOp[i].eOp2;
+ *ppRight = pList->a[0].pExpr;
+ *ppLeft = pCol;
+ return 1;
+ }
+ }
+ }
+
+ /* We can also match against the first column of overloaded
+ ** functions where xFindFunction returns a value of at least
+ ** SQLITE_INDEX_CONSTRAINT_FUNCTION.
+ **
+ ** OVERLOADED(vtab_column,expression)
+ **
+ ** Historically, xFindFunction expected to see lower-case function
+ ** names. But for this use case, xFindFunction is expected to deal
+ ** with function names in an arbitrary case.
+ */
+ pCol = pList->a[0].pExpr;
+ testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ if( ExprIsVtab(pCol) ){
+ sqlite3_vtab *pVtab;
+ sqlite3_module *pMod;
+ void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
+ void *pNotUsed;
+ pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
+ assert( pVtab!=0 );
+ assert( pVtab->pModule!=0 );
+ pMod = (sqlite3_module *)pVtab->pModule;
+ if( pMod->xFindFunction!=0 ){
+ i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed);
+ if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
+ *peOp2 = i;
+ *ppRight = pList->a[1].pExpr;
+ *ppLeft = pCol;
+ return 1;
+ }
+ }
+ }
+ }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
+ int res = 0;
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 );
+ if( ExprIsVtab(pLeft) ){
+ res++;
+ }
+ testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 );
+ if( pRight && ExprIsVtab(pRight) ){
+ res++;
+ SWAP(Expr*, pLeft, pRight);
+ }
+ *ppLeft = pLeft;
+ *ppRight = pRight;
+ if( pExpr->op==TK_NE ) *peOp2 = SQLITE_INDEX_CONSTRAINT_NE;
+ if( pExpr->op==TK_ISNOT ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOT;
+ if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
+ return res;
}
return 0;
}
@@ -126741,7 +144493,7 @@ static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){
**
** The following is NOT generated:
**
-** x<y OR x>y --> x!=y
+** x<y OR x>y --> x!=y
*/
static void whereCombineDisjuncts(
SrcList *pSrc, /* the FROM clause */
@@ -126761,8 +144513,8 @@ static void whereCombineDisjuncts(
&& (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return;
assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 );
assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 );
- if( sqlite3ExprCompare(pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
- if( sqlite3ExprCompare(pOne->pExpr->pRight, pTwo->pExpr->pRight, -1) )return;
+ if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return;
+ if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return;
/* If we reach this point, it means the two subterms can be combined */
if( (eOp & (eOp-1))!=0 ){
if( eOp & (WO_LT|WO_LE) ){
@@ -126838,10 +144590,10 @@ static void whereCombineDisjuncts(
** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T
**
** A subterm is "indexable" if it is of the form
-** "T.C <op> <expr>" where C is any column of table T and
+** "T.C <op> <expr>" where C is any column of table T and
** <op> is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN".
** A subterm is also indexable if it is an AND of two or more
-** subsubterms at least one of which is indexable. Indexable AND
+** subsubterms at least one of which is indexable. Indexable AND
** subterms have their eOperator set to WO_AND and they have
** u.pAndInfo set to a dynamically allocated WhereAndTerm object.
**
@@ -126932,8 +144684,8 @@ static void exprAnalyzeOrTerm(
if( !db->mallocFailed ){
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );
- if( allowedOp(pAndTerm->pExpr->op)
- || pAndTerm->eOperator==WO_MATCH
+ if( allowedOp(pAndTerm->pExpr->op)
+ || pAndTerm->eOperator==WO_AUX
){
b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
}
@@ -126965,7 +144717,12 @@ static void exprAnalyzeOrTerm(
** empty.
*/
pOrInfo->indexable = indexable;
- pTerm->eOperator = indexable==0 ? 0 : WO_OR;
+ if( indexable ){
+ pTerm->eOperator = WO_OR;
+ pWC->hasOr = 1;
+ }else{
+ pTerm->eOperator = WO_OR;
+ }
/* For a two-way OR, attempt to implementation case 2.
*/
@@ -127015,6 +144772,7 @@ static void exprAnalyzeOrTerm(
** and column is found but leave okToChngToIN false if not found.
*/
for(j=0; j<2 && !okToChngToIN; j++){
+ Expr *pLeft = 0;
pOrTerm = pOrWc->a;
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
assert( pOrTerm->eOperator & WO_EQ );
@@ -127029,7 +144787,7 @@ static void exprAnalyzeOrTerm(
pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceded
- ** or follwed by an inverted copy (t2.b==t1.a). Skip this term
+ ** or follwed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
@@ -127038,6 +144796,7 @@ static void exprAnalyzeOrTerm(
}
iColumn = pOrTerm->u.leftColumn;
iCursor = pOrTerm->leftCursor;
+ pLeft = pOrTerm->pExpr->pLeft;
break;
}
if( i<0 ){
@@ -127057,7 +144816,9 @@ static void exprAnalyzeOrTerm(
assert( pOrTerm->eOperator & WO_EQ );
if( pOrTerm->leftCursor!=iCursor ){
pOrTerm->wtFlags &= ~TERM_OR_OK;
- }else if( pOrTerm->u.leftColumn!=iColumn ){
+ }else if( pOrTerm->u.leftColumn!=iColumn || (iColumn==XN_EXPR
+ && sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1)
+ )){
okToChngToIN = 0;
}else{
int affLeft, affRight;
@@ -127077,7 +144838,7 @@ static void exprAnalyzeOrTerm(
}
/* At this point, okToChngToIN is true if original pTerm satisfies
- ** case 1. In that case, construct a new virtual term that is
+ ** case 1. In that case, construct a new virtual term that is
** pTerm converted into an IN operator.
*/
if( okToChngToIN ){
@@ -127097,7 +144858,7 @@ static void exprAnalyzeOrTerm(
}
assert( pLeft!=0 );
pDup = sqlite3ExprDup(db, pLeft, 0);
- pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0);
+ pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
@@ -127106,12 +144867,11 @@ static void exprAnalyzeOrTerm(
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
- pTerm = &pWC->a[idxTerm];
+ /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */
markTermAsChild(pWC, idxNew, idxTerm);
}else{
sqlite3ExprListDelete(db, pList);
}
- pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */
}
}
}
@@ -127135,7 +144895,6 @@ static void exprAnalyzeOrTerm(
static int termIsEquivalence(Parse *pParse, Expr *pExpr){
char aff1, aff2;
CollSeq *pColl;
- const char *zColl1, *zColl2;
if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
@@ -127146,13 +144905,9 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
){
return 0;
}
- pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
- if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- zColl1 = pColl ? pColl->zName : 0;
- pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- zColl2 = pColl ? pColl->zName : 0;
- return sqlite3_stricmp(zColl1, zColl2)==0;
+ pColl = sqlite3ExprCompareCollSeq(pParse, pExpr);
+ if( sqlite3IsBinary(pColl) ) return 1;
+ return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
}
/*
@@ -127174,6 +144929,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
for(i=0; i<pSrc->nSrc; i++){
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
+ if( pSrc->a[i].fg.isTabFunc ){
+ mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
+ }
}
}
pS = pS->pPrior;
@@ -127185,8 +144943,8 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
** Expression pExpr is one operand of a comparison operator that might
** be useful for indexing. This routine checks to see if pExpr appears
** in any index. Return TRUE (1) if pExpr is an indexed term and return
-** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
-** number of the table that is indexed and *piColumn to the column number
+** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor
+** number of the table that is indexed and aiCurCol[1] to the column number
** of the column that is indexed, or XN_EXPR (-2) if an expression is being
** indexed.
**
@@ -127194,20 +144952,39 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
** true even if that particular column is not indexed, because the column
** might be added to an automatic index later.
*/
-static int exprMightBeIndexed(
+static SQLITE_NOINLINE int exprMightBeIndexed2(
SrcList *pFrom, /* The FROM clause */
- int op, /* The specific comparison operator */
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
- Expr *pExpr, /* An operand of a comparison operator */
- int *piCur, /* Write the referenced table cursor number here */
- int *piColumn /* Write the referenced table column number here */
+ int *aiCurCol, /* Write the referenced table cursor and column here */
+ Expr *pExpr /* An operand of a comparison operator */
){
Index *pIdx;
int i;
int iCur;
-
- /* If this expression is a vector to the left or right of a
- ** inequality constraint (>, <, >= or <=), perform the processing
+ for(i=0; mPrereq>1; i++, mPrereq>>=1){}
+ iCur = pFrom->a[i].iCursor;
+ for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->aColExpr==0 ) continue;
+ for(i=0; i<pIdx->nKeyCol; i++){
+ if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
+ if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
+ aiCurCol[0] = iCur;
+ aiCurCol[1] = XN_EXPR;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+static int exprMightBeIndexed(
+ SrcList *pFrom, /* The FROM clause */
+ Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
+ int *aiCurCol, /* Write the referenced table cursor & column here */
+ Expr *pExpr, /* An operand of a comparison operator */
+ int op /* The specific comparison operator */
+){
+ /* If this expression is a vector to the left or right of a
+ ** inequality constraint (>, <, >= or <=), perform the processing
** on the first element of the vector. */
assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE );
@@ -127217,26 +144994,13 @@ static int exprMightBeIndexed(
}
if( pExpr->op==TK_COLUMN ){
- *piCur = pExpr->iTable;
- *piColumn = pExpr->iColumn;
+ aiCurCol[0] = pExpr->iTable;
+ aiCurCol[1] = pExpr->iColumn;
return 1;
}
if( mPrereq==0 ) return 0; /* No table references */
if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
- for(i=0; mPrereq>1; i++, mPrereq>>=1){}
- iCur = pFrom->a[i].iCursor;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->aColExpr==0 ) continue;
- for(i=0; i<pIdx->nKeyCol; i++){
- if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
- if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
- *piCur = iCur;
- *piColumn = XN_EXPR;
- return 1;
- }
- }
- }
- return 0;
+ return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
}
/*
@@ -127275,7 +145039,8 @@ static void exprAnalyze(
int op; /* Top-level operator. pExpr->op */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection */
- unsigned char eOp2; /* op2 value for LIKE/REGEXP/GLOB */
+ unsigned char eOp2 = 0; /* op2 value for LIKE/REGEXP/GLOB */
+ int nLeft; /* Number of elements on left side vector */
if( db->mallocFailed ){
return;
@@ -127299,19 +145064,25 @@ static void exprAnalyze(
}else{
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
}
- prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
+ pMaskSet->bVarSelect = 0;
+ prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
+ if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
if( ExprHasProperty(pExpr, EP_FromJoin) ){
Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
prereqAll |= x;
extraRight = x-1; /* ON clause terms may not be used with an index
** on left table of a LEFT JOIN. Ticket #3015 */
+ if( (prereqAll>>1)>=x ){
+ sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
+ return;
+ }
}
pTerm->prereqAll = prereqAll;
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
if( allowedOp(op) ){
- int iCur, iColumn;
+ int aiCurCol[2];
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
@@ -127322,14 +145093,14 @@ static void exprAnalyze(
pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
}
- if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
- pTerm->leftCursor = iCur;
- pTerm->u.leftColumn = iColumn;
+ if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
+ pTerm->leftCursor = aiCurCol[0];
+ pTerm->u.leftColumn = aiCurCol[1];
pTerm->eOperator = operatorMask(op) & opMask;
}
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
- if( pRight
- && exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn)
+ if( pRight
+ && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
){
WhereTerm *pNew;
Expr *pDup;
@@ -127358,9 +145129,9 @@ static void exprAnalyze(
pDup = pExpr;
pNew = pTerm;
}
- exprCommute(pParse, pDup);
- pNew->leftCursor = iCur;
- pNew->u.leftColumn = iColumn;
+ pNew->wtFlags |= exprCommute(pParse, pDup);
+ pNew->leftCursor = aiCurCol[0];
+ pNew->u.leftColumn = aiCurCol[1];
testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
@@ -127393,9 +145164,9 @@ static void exprAnalyze(
for(i=0; i<2; i++){
Expr *pNewExpr;
int idxNew;
- pNewExpr = sqlite3PExpr(pParse, ops[i],
+ pNewExpr = sqlite3PExpr(pParse, ops[i],
sqlite3ExprDup(db, pExpr->pLeft, 0),
- sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
+ sqlite3ExprDup(db, pList->a[i].pExpr, 0));
transferJoinMarkings(pNewExpr, pExpr);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
@@ -127431,7 +145202,7 @@ static void exprAnalyze(
** bound is made all lowercase so that the bounds also work when comparing
** BLOBs.
*/
- if( pWC->op==TK_AND
+ if( pWC->op==TK_AND
&& isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
){
Expr *pLeft; /* LHS of LIKE/GLOB operator */
@@ -127467,7 +145238,7 @@ static void exprAnalyze(
if( noCase ){
/* The point is to increment the last character before the first
** wildcard. But if we increment '@', that will push it into the
- ** alphabetic range where case conversions will mess up the
+ ** alphabetic range where case conversions will mess up the
** inequality. To avoid this, make sure to also run the full
** LIKE on all candidate expressions by clearing the isComplete flag
*/
@@ -127476,11 +145247,11 @@ static void exprAnalyze(
}
*pC = c + 1;
}
- zCollSeqName = noCase ? "NOCASE" : "BINARY";
+ zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
- pStr1, 0);
+ pStr1);
transferJoinMarkings(pNewExpr1, pExpr);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
@@ -127488,7 +145259,7 @@ static void exprAnalyze(
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
- pStr2, 0);
+ pStr2);
transferJoinMarkings(pNewExpr2, pExpr);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
@@ -127502,38 +145273,47 @@ static void exprAnalyze(
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
#ifndef SQLITE_OMIT_VIRTUALTABLE
- /* Add a WO_MATCH auxiliary term to the constraint set if the
- ** current expression is of the form: column MATCH expr.
+ /* Add a WO_AUX auxiliary term to the constraint set if the
+ ** current expression is of the form "column OP expr" where OP
+ ** is an operator that gets passed into virtual tables but which is
+ ** not normally optimized for ordinary tables. In other words, OP
+ ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL.
** This information is used by the xBestIndex methods of
** virtual tables. The native query optimizer does not attempt
** to do anything with MATCH functions.
*/
- if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){
- int idxNew;
- Expr *pRight, *pLeft;
- WhereTerm *pNewTerm;
- Bitmask prereqColumn, prereqExpr;
-
- pRight = pExpr->x.pList->a[0].pExpr;
- pLeft = pExpr->x.pList->a[1].pExpr;
- prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
- prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
- if( (prereqExpr & prereqColumn)==0 ){
- Expr *pNewExpr;
- pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
- 0, sqlite3ExprDup(db, pRight, 0), 0);
- idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
- testcase( idxNew==0 );
- pNewTerm = &pWC->a[idxNew];
- pNewTerm->prereqRight = prereqExpr;
- pNewTerm->leftCursor = pLeft->iTable;
- pNewTerm->u.leftColumn = pLeft->iColumn;
- pNewTerm->eOperator = WO_MATCH;
- pNewTerm->eMatchOp = eOp2;
- markTermAsChild(pWC, idxNew, idxTerm);
- pTerm = &pWC->a[idxTerm];
- pTerm->wtFlags |= TERM_COPIED;
- pNewTerm->prereqAll = pTerm->prereqAll;
+ if( pWC->op==TK_AND ){
+ Expr *pRight = 0, *pLeft = 0;
+ int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight);
+ while( res-- > 0 ){
+ int idxNew;
+ WhereTerm *pNewTerm;
+ Bitmask prereqColumn, prereqExpr;
+
+ prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
+ prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
+ if( (prereqExpr & prereqColumn)==0 ){
+ Expr *pNewExpr;
+ pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
+ 0, sqlite3ExprDup(db, pRight, 0));
+ if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
+ ExprSetProperty(pNewExpr, EP_FromJoin);
+ pNewExpr->iRightJoinTable = pExpr->iRightJoinTable;
+ }
+ idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
+ testcase( idxNew==0 );
+ pNewTerm = &pWC->a[idxNew];
+ pNewTerm->prereqRight = prereqExpr;
+ pNewTerm->leftCursor = pLeft->iTable;
+ pNewTerm->u.leftColumn = pLeft->iColumn;
+ pNewTerm->eOperator = WO_AUX;
+ pNewTerm->eMatchOp = eOp2;
+ markTermAsChild(pWC, idxNew, idxTerm);
+ pTerm = &pWC->a[idxTerm];
+ pTerm->wtFlags |= TERM_COPIED;
+ pNewTerm->prereqAll = pTerm->prereqAll;
+ }
+ SWAP(Expr*, pLeft, pRight);
}
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -127545,42 +145325,45 @@ static void exprAnalyze(
**
** This is only required if at least one side of the comparison operation
** is not a sub-select. */
- if( pWC->op==TK_AND
+ if( pWC->op==TK_AND
&& (pExpr->op==TK_EQ || pExpr->op==TK_IS)
- && sqlite3ExprIsVector(pExpr->pLeft)
- && ( (pExpr->pLeft->flags & EP_xIsSelect)==0
- || (pExpr->pRight->flags & EP_xIsSelect)==0
- )){
- int nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
+ && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
+ && sqlite3ExprVectorSize(pExpr->pRight)==nLeft
+ && ( (pExpr->pLeft->flags & EP_xIsSelect)==0
+ || (pExpr->pRight->flags & EP_xIsSelect)==0)
+ ){
int i;
- assert( nLeft==sqlite3ExprVectorSize(pExpr->pRight) );
for(i=0; i<nLeft; i++){
int idxNew;
Expr *pNew;
Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
- pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight, 0);
+ pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
transferJoinMarkings(pNew, pExpr);
idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
exprAnalyze(pSrc, pWC, idxNew);
}
pTerm = &pWC->a[idxTerm];
- pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */
+ pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */
pTerm->eOperator = 0;
}
/* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
** a virtual term for each vector component. The expression object
- ** used by each such virtual term is pExpr (the full vector IN(...)
+ ** used by each such virtual term is pExpr (the full vector IN(...)
** expression). The WhereTerm.iField variable identifies the index within
** the vector on the LHS that the virtual term represents.
**
- ** This only works if the RHS is a simple SELECT, not a compound
+ ** This only works if the RHS is a simple SELECT (not a compound) that does
+ ** not use window functions.
*/
if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
&& pExpr->pLeft->op==TK_VECTOR
&& pExpr->x.pSelect->pPrior==0
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ && pExpr->x.pSelect->pWin==0
+#endif
){
int i;
for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
@@ -127592,8 +145375,8 @@ static void exprAnalyze(
}
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
- /* When sqlite_stat3 histogram data is available an operator of the
+#ifdef SQLITE_ENABLE_STAT4
+ /* When sqlite_stat4 histogram data is available an operator of the
** form "x IS NOT NULL" can sometimes be evaluated more efficiently
** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
** virtual term of that form.
@@ -127603,7 +145386,8 @@ static void exprAnalyze(
if( pExpr->op==TK_NOTNULL
&& pExpr->pLeft->op==TK_COLUMN
&& pExpr->pLeft->iColumn>=0
- && OptimizationEnabled(db, SQLITE_Stat34)
+ && !ExprHasProperty(pExpr, EP_FromJoin)
+ && OptimizationEnabled(db, SQLITE_Stat4)
){
Expr *pNewExpr;
Expr *pLeft = pExpr->pLeft;
@@ -127612,7 +145396,7 @@ static void exprAnalyze(
pNewExpr = sqlite3PExpr(pParse, TK_GT,
sqlite3ExprDup(db, pLeft, 0),
- sqlite3ExprAlloc(db, TK_NULL, 0, 0), 0);
+ sqlite3ExprAlloc(db, TK_NULL, 0, 0));
idxNew = whereClauseInsert(pWC, pNewExpr,
TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
@@ -127628,11 +145412,13 @@ static void exprAnalyze(
pNewTerm->prereqAll = pTerm->prereqAll;
}
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
/* Prevent ON clause terms of a LEFT JOIN from being used to drive
** an index for tables to the left of the join.
*/
+ testcase( pTerm!=&pWC->a[idxTerm] );
+ pTerm = &pWC->a[idxTerm];
pTerm->prereqRight |= extraRight;
}
@@ -127659,7 +145445,7 @@ static void exprAnalyze(
** all terms of the WHERE clause.
*/
SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
- Expr *pE2 = sqlite3ExprSkipCollate(pExpr);
+ Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr);
pWC->op = op;
if( pE2==0 ) return;
if( pE2->op!=op ){
@@ -127678,6 +145464,7 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(
WhereInfo *pWInfo /* The WHERE processing context */
){
pWC->pWInfo = pWInfo;
+ pWC->hasOr = 0;
pWC->pOuter = 0;
pWC->nTerm = 0;
pWC->nSlot = ArraySize(pWC->aStatic);
@@ -127714,23 +145501,37 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
** a bitmask indicating which tables are used in that expression
** tree.
*/
-SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
+SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
Bitmask mask;
- if( p==0 ) return 0;
- if( p->op==TK_COLUMN ){
- mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
- return mask;
+ if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
+ return sqlite3WhereGetMask(pMaskSet, p->iTable);
+ }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
+ assert( p->op!=TK_IF_NULL_ROW );
+ return 0;
}
- assert( !ExprHasProperty(p, EP_TokenOnly) );
- mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0;
- if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
- if( ExprHasProperty(p, EP_xIsSelect) ){
+ mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
+ if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
+ if( p->pRight ){
+ mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight);
+ assert( p->x.pList==0 );
+ }else if( ExprHasProperty(p, EP_xIsSelect) ){
+ if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
}else if( p->x.pList ){
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && p->y.pWin ){
+ mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition);
+ mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy);
+ mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter);
+ }
+#endif
return mask;
}
+SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
+ return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
+}
SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){
int i;
Bitmask mask = 0;
@@ -127744,7 +145545,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprLis
/*
-** Call exprAnalyze on all terms in a WHERE clause.
+** Call exprAnalyze on all terms in a WHERE clause.
**
** Note that exprAnalyze() might add new virtual terms onto the
** end of the WHERE clause. We do not want to analyze these new
@@ -127763,7 +145564,7 @@ SQLITE_PRIVATE void sqlite3WhereExprAnalyze(
/*
** For table-valued-functions, transform the function arguments into
-** new WHERE clause terms.
+** new WHERE clause terms.
**
** Each function argument translates into an equality constraint against
** a HIDDEN column in the table.
@@ -127784,6 +145585,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
pArgs = pItem->u1.pFuncArg;
if( pArgs==0 ) return;
for(j=k=0; j<pArgs->nExpr; j++){
+ Expr *pRhs;
while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
if( k>=pTab->nCol ){
sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
@@ -127794,9 +145596,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
if( pColRef==0 ) return;
pColRef->iTable = pItem->iCursor;
pColRef->iColumn = k++;
- pColRef->pTab = pTab;
- pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
- sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
+ pColRef->y.pTab = pTab;
+ pRhs = sqlite3PExpr(pParse, TK_UPLUS,
+ sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
+ pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
+ if( pItem->fg.jointype & JT_LEFT ){
+ sqlite3SetJoinExpr(pTerm, pItem->iCursor);
+ }
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
}
}
@@ -127824,6 +145630,21 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
/* #include "sqliteInt.h" */
/* #include "whereInt.h" */
+/*
+** Extra information appended to the end of sqlite3_index_info but not
+** visible to the xBestIndex function, at least not directly. The
+** sqlite3_vtab_collation() interface knows how to reach it, however.
+**
+** This object is not an API and can be changed from one release to the
+** next. As long as allocateIndexInfo() and sqlite3_vtab_collation()
+** agree on the structure, all will be well.
+*/
+typedef struct HiddenIndexInfo HiddenIndexInfo;
+struct HiddenIndexInfo {
+ WhereClause *pWC; /* The Where clause being analyzed */
+ Parse *pParse; /* The parsing context */
+};
+
/* Forward declaration of methods */
static int whereLoopResize(sqlite3*, WhereLoop*, int);
@@ -127849,23 +145670,50 @@ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
}
/*
-** Return TRUE if the WHERE clause returns rows in ORDER BY order.
-** Return FALSE if the output needs to be sorted.
+** Return the number of ORDER BY terms that are satisfied by the
+** WHERE clause. A return of 0 means that the output must be
+** completely sorted. A return equal to the number of ORDER BY
+** terms means that no sorting is needed at all. A return that
+** is positive but less than the number of ORDER BY terms means that
+** block sorting is required.
*/
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
return pWInfo->nOBSat;
}
/*
-** Return TRUE if the innermost loop of the WHERE clause implementation
-** returns rows in ORDER BY order for complete run of the inner loop.
+** In the ORDER BY LIMIT optimization, if the inner-most loop is known
+** to emit rows in increasing order, and if the last row emitted by the
+** inner-most loop did not fit within the sorter, then we can skip all
+** subsequent rows for the current iteration of the inner loop (because they
+** will not fit in the sorter either) and continue with the second inner
+** loop - the loop immediately outside the inner-most.
+**
+** When a row does not fit in the sorter (because the sorter already
+** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the
+** label returned by this function.
+**
+** If the ORDER BY LIMIT optimization applies, the jump destination should
+** be the continuation for the second-inner-most loop. If the ORDER BY
+** LIMIT optimization does not apply, then the jump destination should
+** be the continuation for the inner-most loop.
**
-** Across multiple iterations of outer loops, the output rows need not be
-** sorted. As long as rows are sorted for just the innermost loop, this
-** routine can return TRUE.
+** It is always safe for this routine to return the continuation of the
+** inner-most loop, in the sense that a correct answer will result.
+** Returning the continuation the second inner loop is an optimization
+** that might make the code run a little faster, but should not change
+** the final answer.
*/
-SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
- return pWInfo->bOrderedInnerLoop;
+SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
+ WhereLevel *pInner;
+ if( !pWInfo->bOrderedInnerLoop ){
+ /* The ORDER BY LIMIT optimization does not apply. Jump to the
+ ** continuation of the inner-most loop. */
+ return pWInfo->iContinue;
+ }
+ pInner = &pWInfo->a[pWInfo->nLevel-1];
+ assert( pInner->addrNxt!=0 );
+ return pInner->addrNxt;
}
/*
@@ -127887,10 +145735,10 @@ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
/*
** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
-** operate directly on the rowis returned by a WHERE clause. Return
+** operate directly on the rowids returned by a WHERE clause. Return
** ONEPASS_SINGLE (1) if the statement can operation directly because only
** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass
-** optimization can be used on multiple
+** optimization can be used on multiple
**
** If the ONEPASS optimization is used (if this routine returns true)
** then also write the indices of open cursors used by ONEPASS
@@ -127915,6 +145763,14 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
}
/*
+** Return TRUE if the WHERE loop uses the OP_DeferredSeek opcode to move
+** the data cursor to the row selected by the index cursor.
+*/
+SQLITE_PRIVATE int sqlite3WhereUsesDeferredSeek(WhereInfo *pWInfo){
+ return pWInfo->bDeferredSeek;
+}
+
+/*
** Move the content of pSrc into pDest
*/
static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
@@ -128003,21 +145859,25 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
WhereTerm *pTerm; /* The term being tested */
int k = pScan->k; /* Where to start scanning */
- while( pScan->iEquiv<=pScan->nEquiv ){
- iCur = pScan->aiCur[pScan->iEquiv-1];
+ assert( pScan->iEquiv<=pScan->nEquiv );
+ pWC = pScan->pWC;
+ while(1){
iColumn = pScan->aiColumn[pScan->iEquiv-1];
- if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
- while( (pWC = pScan->pWC)!=0 ){
+ iCur = pScan->aiCur[pScan->iEquiv-1];
+ assert( pWC!=0 );
+ do{
for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
if( pTerm->leftCursor==iCur
&& pTerm->u.leftColumn==iColumn
&& (iColumn!=XN_EXPR
- || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
+ || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
+ pScan->pIdxExpr,iCur)==0)
&& (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){
if( (pTerm->eOperator & WO_EQUIV)!=0
&& pScan->nEquiv<ArraySize(pScan->aiCur)
- && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN
+ && (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op
+ ==TK_COLUMN
){
int j;
for(j=0; j<pScan->nEquiv; j++){
@@ -128042,8 +145902,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
continue;
}
assert(pX->pLeft);
- pColl = sqlite3BinaryCompareCollSeq(pParse,
- pX->pLeft, pX->pRight);
+ pColl = sqlite3ExprCompareCollSeq(pParse, pX);
if( pColl==0 ) pColl = pParse->db->pDfltColl;
if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
continue;
@@ -128057,15 +145916,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
testcase( pTerm->eOperator & WO_IS );
continue;
}
+ pScan->pWC = pWC;
pScan->k = k+1;
return pTerm;
}
}
}
- pScan->pWC = pScan->pWC->pOuter;
+ pWC = pWC->pOuter;
k = 0;
- }
- pScan->pWC = pScan->pOrigWC;
+ }while( pWC!=0 );
+ if( pScan->iEquiv>=pScan->nEquiv ) break;
+ pWC = pScan->pOrigWC;
k = 0;
pScan->iEquiv++;
}
@@ -128073,6 +145934,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
}
/*
+** This is whereScanInit() for the case of an index on an expression.
+** It is factored out into a separate tail-recursion subroutine so that
+** the normal whereScanInit() routine, which is a high-runner, does not
+** need to push registers onto the stack as part of its prologue.
+*/
+static SQLITE_NOINLINE WhereTerm *whereScanInitIndexExpr(WhereScan *pScan){
+ pScan->idxaff = sqlite3ExprAffinity(pScan->pIdxExpr);
+ return whereScanNext(pScan);
+}
+
+/*
** Initialize a WHERE clause scanner object. Return a pointer to the
** first match. Return NULL if there are no matches.
**
@@ -128099,31 +145971,34 @@ static WhereTerm *whereScanInit(
u32 opMask, /* Operator(s) to scan for */
Index *pIdx /* Must be compatible with this index */
){
- int j = 0;
-
- /* memset(pScan, 0, sizeof(*pScan)); */
pScan->pOrigWC = pWC;
pScan->pWC = pWC;
pScan->pIdxExpr = 0;
- if( pIdx ){
- j = iColumn;
- iColumn = pIdx->aiColumn[j];
- if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
- if( iColumn==pIdx->pTable->iPKey ) iColumn = XN_ROWID;
- }
- if( pIdx && iColumn>=0 ){
- pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
- pScan->zCollName = pIdx->azColl[j];
- }else{
- pScan->idxaff = 0;
- pScan->zCollName = 0;
- }
+ pScan->idxaff = 0;
+ pScan->zCollName = 0;
pScan->opMask = opMask;
pScan->k = 0;
pScan->aiCur[0] = iCur;
- pScan->aiColumn[0] = iColumn;
pScan->nEquiv = 1;
pScan->iEquiv = 1;
+ if( pIdx ){
+ int j = iColumn;
+ iColumn = pIdx->aiColumn[j];
+ if( iColumn==XN_EXPR ){
+ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
+ pScan->zCollName = pIdx->azColl[j];
+ pScan->aiColumn[0] = XN_EXPR;
+ return whereScanInitIndexExpr(pScan);
+ }else if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = XN_ROWID;
+ }else if( iColumn>=0 ){
+ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
+ pScan->zCollName = pIdx->azColl[j];
+ }
+ }else if( iColumn==XN_EXPR ){
+ return 0;
+ }
+ pScan->aiColumn[0] = iColumn;
return whereScanNext(pScan);
}
@@ -128133,7 +146008,7 @@ static WhereTerm *whereScanInit(
** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
** the op parameter. Return a pointer to the term. Return 0 if not found.
**
-** If pIdx!=0 then it must be one of the indexes of table iCur.
+** If pIdx!=0 then it must be one of the indexes of table iCur.
** Search for terms matching the iColumn-th column of pIdx
** rather than the iColumn-th column of table iCur.
**
@@ -128197,13 +146072,13 @@ static int findIndexCol(
const char *zColl = pIdx->azColl[iCol];
for(i=0; i<pList->nExpr; i++){
- Expr *p = sqlite3ExprSkipCollate(pList->a[i].pExpr);
+ Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr);
if( p->op==TK_COLUMN
&& p->iColumn==pIdx->aiColumn[iCol]
&& p->iTable==iBase
){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
- if( pColl && 0==sqlite3StrICmp(pColl->zName, zColl) ){
+ CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr);
+ if( 0==sqlite3StrICmp(pColl->zName, zColl) ){
return i;
}
}
@@ -128246,22 +146121,22 @@ static int isDistinctRedundant(
){
Table *pTab;
Index *pIdx;
- int i;
+ int i;
int iBase;
/* If there is more than one table or sub-select in the FROM clause of
- ** this query, then it will not be possible to show that the DISTINCT
+ ** this query, then it will not be possible to show that the DISTINCT
** clause is redundant. */
if( pTabList->nSrc!=1 ) return 0;
iBase = pTabList->a[0].iCursor;
pTab = pTabList->a[0].pTab;
- /* If any of the expressions is an IPK column on table iBase, then return
+ /* If any of the expressions is an IPK column on table iBase, then return
** true. Note: The (p->iTable==iBase) part of this test may be false if the
** current SELECT is a correlated sub-query.
*/
for(i=0; i<pDistinct->nExpr; i++){
- Expr *p = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr);
+ Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr);
if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
}
@@ -128307,23 +146182,25 @@ static LogEst estLog(LogEst N){
** Convert OP_Column opcodes to OP_Copy in previously generated code.
**
** This routine runs over generated VDBE code and translates OP_Column
-** opcodes into OP_Copy when the table is being accessed via co-routine
+** opcodes into OP_Copy when the table is being accessed via co-routine
** instead of via table lookup.
**
-** If the bIncrRowid parameter is 0, then any OP_Rowid instructions on
-** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero,
-** then each OP_Rowid is transformed into an instruction to increment the
-** value stored in its output register.
+** If the iAutoidxCur is not zero, then any OP_Rowid instructions on
+** cursor iTabCur are transformed into OP_Sequence opcode for the
+** iAutoidxCur cursor, in order to generate unique rowids for the
+** automatic index being generated.
*/
static void translateColumnToCopy(
- Vdbe *v, /* The VDBE containing code to translate */
+ Parse *pParse, /* Parsing context */
int iStart, /* Translate from this opcode to the end */
int iTabCur, /* OP_Column/OP_Rowid references to this table */
int iRegister, /* The first column is in this register */
- int bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */
+ int iAutoidxCur /* If non-zero, cursor of autoindex being generated */
){
+ Vdbe *v = pParse->pVdbe;
VdbeOp *pOp = sqlite3VdbeGetOp(v, iStart);
int iEnd = sqlite3VdbeCurrentAddr(v);
+ if( pParse->db->mallocFailed ) return;
for(; iStart<iEnd; iStart++, pOp++){
if( pOp->p1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
@@ -128332,11 +146209,9 @@ static void translateColumnToCopy(
pOp->p2 = pOp->p3;
pOp->p3 = 0;
}else if( pOp->opcode==OP_Rowid ){
- if( bIncrRowid ){
- /* Increment the value stored in the P2 operand of the OP_Rowid. */
- pOp->opcode = OP_AddImm;
- pOp->p1 = pOp->p2;
- pOp->p2 = 1;
+ if( iAutoidxCur ){
+ pOp->opcode = OP_Sequence;
+ pOp->p1 = iAutoidxCur;
}else{
pOp->opcode = OP_Null;
pOp->p1 = 0;
@@ -128353,7 +146228,7 @@ static void translateColumnToCopy(
** are no-ops.
*/
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
-static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
+static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
int i;
if( !sqlite3WhereTrace ) return;
for(i=0; i<p->nConstraint; i++){
@@ -128371,7 +146246,7 @@ static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
p->aOrderBy[i].desc);
}
}
-static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
+static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
int i;
if( !sqlite3WhereTrace ) return;
for(i=0; i<p->nConstraint; i++){
@@ -128387,8 +146262,8 @@ static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){
sqlite3DebugPrintf(" estimatedRows=%lld\n", p->estimatedRows);
}
#else
-#define TRACE_IDX_INPUTS(A)
-#define TRACE_IDX_OUTPUTS(A)
+#define whereTraceIndexInfoInputs(A)
+#define whereTraceIndexInfoOutputs(A)
#endif
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -128405,6 +146280,15 @@ static int termCanDriveIndex(
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
+ if( (pSrc->fg.jointype & JT_LEFT)
+ && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+ && (pTerm->eOperator & WO_IS)
+ ){
+ /* Cannot use an IS term from the WHERE clause as an index driver for
+ ** the RHS of a LEFT JOIN. Such a term can only be used if it is from
+ ** the ON clause. */
+ return 0;
+ }
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
if( pTerm->u.leftColumn<0 ) return 0;
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
@@ -128474,7 +146358,7 @@ static void constructAutomaticIndex(
&& (pTerm->wtFlags & TERM_VIRTUAL)==0
&& !ExprHasProperty(pExpr, EP_FromJoin)
&& sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){
- pPartial = sqlite3ExprAnd(pParse->db, pPartial,
+ pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
}
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
@@ -128539,7 +146423,8 @@ static void constructAutomaticIndex(
Expr *pX = pTerm->pExpr;
idxCols |= cMask;
pIdx->aiColumn[n] = pTerm->u.leftColumn;
- pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
+ pColl = sqlite3ExprCompareCollSeq(pParse, pX);
+ assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
n++;
}
@@ -128575,7 +146460,6 @@ static void constructAutomaticIndex(
VdbeComment((v, "for %s", pTable->zName));
/* Fill the automatic index with content */
- sqlite3ExprCachePush(pParse);
pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
if( pTabItem->fg.viaCoroutine ){
int regYield = pTabItem->regReturn;
@@ -128583,12 +146467,12 @@ static void constructAutomaticIndex(
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
}else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
if( pPartial ){
- iContinue = sqlite3VdbeMakeLabel(v);
+ iContinue = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL);
pLoop->wsFlags |= WHERE_PARTIALIDX;
}
@@ -128601,17 +146485,19 @@ static void constructAutomaticIndex(
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
if( pTabItem->fg.viaCoroutine ){
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
- translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult, 1);
+ testcase( pParse->db->mallocFailed );
+ assert( pLevel->iIdxCur>0 );
+ translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
+ pTabItem->regResult, pLevel->iIdxCur);
sqlite3VdbeGoto(v, addrTop);
pTabItem->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
+ sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
}
- sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
- sqlite3ExprCachePop(pParse);
-
+
/* Jump here when skipping the initialization */
sqlite3VdbeJumpHere(v, addrInit);
@@ -128622,16 +146508,16 @@ end_auto_index_create:
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
-** Allocate and populate an sqlite3_index_info structure. It is the
+** Allocate and populate an sqlite3_index_info structure. It is the
** responsibility of the caller to eventually release the structure
** by passing the pointer returned by this function to sqlite3_free().
*/
static sqlite3_index_info *allocateIndexInfo(
- Parse *pParse,
- WhereClause *pWC,
+ Parse *pParse, /* The parsing context */
+ WhereClause *pWC, /* The WHERE clause being analyzed */
Bitmask mUnusable, /* Ignore terms with these prereqs */
- struct SrcList_item *pSrc,
- ExprList *pOrderBy,
+ struct SrcList_item *pSrc, /* The FROM clause term that is the vtab */
+ ExprList *pOrderBy, /* The ORDER BY clause */
u16 *pmNoOmit /* Mask of terms not to omit */
){
int i, j;
@@ -128639,6 +146525,7 @@ static sqlite3_index_info *allocateIndexInfo(
struct sqlite3_index_constraint *pIdxCons;
struct sqlite3_index_orderby *pIdxOrderBy;
struct sqlite3_index_constraint_usage *pUsage;
+ struct HiddenIndexInfo *pHidden;
WhereTerm *pTerm;
int nOrderBy;
sqlite3_index_info *pIdxInfo;
@@ -128654,13 +146541,13 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
nTerm++;
}
- /* If the ORDER BY clause contains only columns in the current
+ /* If the ORDER BY clause contains only columns in the current
** virtual table then allocate space for the aOrderBy part of
** the sqlite3_index_info structure.
*/
@@ -128670,6 +146557,7 @@ static sqlite3_index_info *allocateIndexInfo(
for(i=0; i<n; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
+ if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
}
if( i==n){
nOrderBy = n;
@@ -128680,29 +146568,23 @@ static sqlite3_index_info *allocateIndexInfo(
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
- + sizeof(*pIdxOrderBy)*nOrderBy );
+ + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
}
-
- /* Initialize the structure. The sqlite3_index_info structure contains
- ** many fields that are declared "const" to prevent xBestIndex from
- ** changing them. We have to do some funky casting in order to
- ** initialize those fields.
- */
- pIdxCons = (struct sqlite3_index_constraint*)&pIdxInfo[1];
+ pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
+ pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
- *(int*)&pIdxInfo->nConstraint = nTerm;
- *(int*)&pIdxInfo->nOrderBy = nOrderBy;
- *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons;
- *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy;
- *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage =
- pUsage;
-
+ pIdxInfo->nOrderBy = nOrderBy;
+ pIdxInfo->aConstraint = pIdxCons;
+ pIdxInfo->aOrderBy = pIdxOrderBy;
+ pIdxInfo->aConstraintUsage = pUsage;
+ pHidden->pWC = pWC;
+ pHidden->pParse = pParse;
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- u8 op;
+ u16 op;
if( pTerm->leftCursor != pSrc->iCursor ) continue;
if( pTerm->prereqRight & mUnusable ) continue;
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
@@ -128710,42 +146592,59 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_IS );
testcase( pTerm->eOperator & WO_ISNULL );
testcase( pTerm->eOperator & WO_ALL );
- if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
+ if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue;
+
+ /* tag-20191211-002: WHERE-clause constraints are not useful to the
+ ** right-hand table of a LEFT JOIN. See tag-20191211-001 for the
+ ** equivalent restriction for ordinary tables. */
+ if( (pSrc->fg.jointype & JT_LEFT)!=0
+ && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+ ){
+ continue;
+ }
assert( pTerm->u.leftColumn>=(-1) );
pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i;
- op = (u8)pTerm->eOperator & WO_ALL;
+ op = pTerm->eOperator & WO_ALL;
if( op==WO_IN ) op = WO_EQ;
- if( op==WO_MATCH ){
- op = pTerm->eMatchOp;
- }
- pIdxCons[j].op = op;
- /* The direct assignment in the previous line is possible only because
- ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
- ** following asserts verify this fact. */
- assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
- assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
- assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
- assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
- assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
- assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
- assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
-
- if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
- && sqlite3ExprIsVector(pTerm->pExpr->pRight)
- ){
- if( i<16 ) mNoOmit |= (1 << i);
- if( op==WO_LT ) pIdxCons[j].op = WO_LE;
- if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ if( op==WO_AUX ){
+ pIdxCons[j].op = pTerm->eMatchOp;
+ }else if( op & (WO_ISNULL|WO_IS) ){
+ if( op==WO_ISNULL ){
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL;
+ }else{
+ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS;
+ }
+ }else{
+ pIdxCons[j].op = (u8)op;
+ /* The direct assignment in the previous line is possible only because
+ ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The
+ ** following asserts verify this fact. */
+ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ );
+ assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT );
+ assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE );
+ assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT );
+ assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
+ assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
+
+ if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
+ && sqlite3ExprIsVector(pTerm->pExpr->pRight)
+ ){
+ testcase( j!=i );
+ if( j<16 ) mNoOmit |= (1 << j);
+ if( op==WO_LT ) pIdxCons[j].op = WO_LE;
+ if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ }
}
j++;
}
+ pIdxInfo->nConstraint = j;
for(i=0; i<nOrderBy; i++){
Expr *pExpr = pOrderBy->a[i].pExpr;
pIdxOrderBy[i].iColumn = pExpr->iColumn;
- pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
+ pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
}
*pmNoOmit = mNoOmit;
@@ -128758,9 +146657,11 @@ static sqlite3_index_info *allocateIndexInfo(
** method of the virtual table with the sqlite3_index_info object that
** comes in as the 3rd argument to this function.
**
-** If an error occurs, pParse is populated with an error message and a
-** non-zero value is returned. Otherwise, 0 is returned and the output
-** part of the sqlite3_index_info structure is left populated.
+** If an error occurs, pParse is populated with an error message and an
+** appropriate error code is returned. A return of SQLITE_CONSTRAINT from
+** xBestIndex is not considered an error. SQLITE_CONSTRAINT indicates that
+** the current configuration of "unusable" flags in sqlite3_index_info can
+** not result in a valid plan.
**
** Whether or not an error is returned, it is the responsibility of the
** caller to eventually free p->idxStr if p->needToFreeIdxStr indicates
@@ -128770,11 +146671,11 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
int rc;
- TRACE_IDX_INPUTS(p);
+ whereTraceIndexInfoInputs(p);
rc = pVtab->pModule->xBestIndex(pVtab, p);
- TRACE_IDX_OUTPUTS(p);
+ whereTraceIndexInfoOutputs(p);
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
if( rc==SQLITE_NOMEM ){
sqlite3OomFault(pParse->db);
}else if( !pVtab->zErrMsg ){
@@ -128785,23 +146686,11 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
}
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
-
-#if 0
- /* This error is now caught by the caller.
- ** Search for "xBestIndex malfunction" below */
- for(i=0; i<p->nConstraint; i++){
- if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){
- sqlite3ErrorMsg(pParse,
- "table %s: xBestIndex returned an invalid plan", pTab->zName);
- }
- }
-#endif
-
- return pParse->nErr;
+ return rc;
}
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
/*
** Estimate the location of a particular key among all keys in an
** index. Store the results in aStat as follows:
@@ -128812,8 +146701,8 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
** Return the index of the sample that is the smallest sample that
** is greater than or equal to pRec. Note that this index is not an index
** into the aSample[] array - it is an index into a virtual set of samples
-** based on the contents of aSample[] and the number of fields in record
-** pRec.
+** based on the contents of aSample[] and the number of fields in record
+** pRec.
*/
static int whereKeyStats(
Parse *pParse, /* Database connection */
@@ -128849,38 +146738,38 @@ static int whereKeyStats(
** consider prefixes of those samples. For example, if the set of samples
** in aSample is:
**
- ** aSample[0] = (a, 5)
- ** aSample[1] = (a, 10)
- ** aSample[2] = (b, 5)
- ** aSample[3] = (c, 100)
+ ** aSample[0] = (a, 5)
+ ** aSample[1] = (a, 10)
+ ** aSample[2] = (b, 5)
+ ** aSample[3] = (c, 100)
** aSample[4] = (c, 105)
**
- ** Then the search space should ideally be the samples above and the
- ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
+ ** Then the search space should ideally be the samples above and the
+ ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
** the code actually searches this set:
**
- ** 0: (a)
- ** 1: (a, 5)
- ** 2: (a, 10)
- ** 3: (a, 10)
- ** 4: (b)
- ** 5: (b, 5)
- ** 6: (c)
- ** 7: (c, 100)
+ ** 0: (a)
+ ** 1: (a, 5)
+ ** 2: (a, 10)
+ ** 3: (a, 10)
+ ** 4: (b)
+ ** 5: (b, 5)
+ ** 6: (c)
+ ** 7: (c, 100)
** 8: (c, 105)
** 9: (c, 105)
**
** For each sample in the aSample[] array, N samples are present in the
- ** effective sample array. In the above, samples 0 and 1 are based on
+ ** effective sample array. In the above, samples 0 and 1 are based on
** sample aSample[0]. Samples 2 and 3 on aSample[1] etc.
**
** Often, sample i of each block of N effective samples has (i+1) fields.
** Except, each sample may be extended to ensure that it is greater than or
- ** equal to the previous sample in the array. For example, in the above,
- ** sample 2 is the first sample of a block of N samples, so at first it
- ** appears that it should be 1 field in size. However, that would make it
- ** smaller than sample 1, so the binary search would not work. As a result,
- ** it is extended to two fields. The duplicates that this creates do not
+ ** equal to the previous sample in the array. For example, in the above,
+ ** sample 2 is the first sample of a block of N samples, so at first it
+ ** appears that it should be 1 field in size. However, that would make it
+ ** smaller than sample 1, so the binary search would not work. As a result,
+ ** it is extended to two fields. The duplicates that this creates do not
** cause any problems.
*/
nField = pRec->nField;
@@ -128894,7 +146783,7 @@ static int whereKeyStats(
iSamp = iTest / nField;
if( iSamp>0 ){
/* The proposed effective sample is a prefix of sample aSample[iSamp].
- ** Specifically, the shortest prefix of at least (1 + iTest%nField)
+ ** Specifically, the shortest prefix of at least (1 + iTest%nField)
** fields that is greater than the previous effective sample. */
for(n=(iTest % nField) + 1; n<nField; n++){
if( aSample[iSamp-1].anLt[n-1]!=aSample[iSamp].anLt[n-1] ) break;
@@ -128929,8 +146818,8 @@ static int whereKeyStats(
assert( i<pIdx->nSample );
assert( iCol==nField-1 );
pRec->nField = nField;
- assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
- || pParse->db->mallocFailed
+ assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
+ || pParse->db->mallocFailed
);
}else{
/* Unless i==pIdx->nSample, indicating that pRec is larger than
@@ -128938,7 +146827,7 @@ static int whereKeyStats(
** (iCol+1) field prefix of sample i. */
assert( i<=pIdx->nSample && i>=0 );
pRec->nField = iCol+1;
- assert( i==pIdx->nSample
+ assert( i==pIdx->nSample
|| sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
|| pParse->db->mallocFailed );
@@ -128966,7 +146855,7 @@ static int whereKeyStats(
aStat[0] = aSample[i].anLt[iCol];
aStat[1] = aSample[i].anEq[iCol];
}else{
- /* At this point, the (iCol+1) field prefix of aSample[i] is the first
+ /* At this point, the (iCol+1) field prefix of aSample[i] is the first
** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
** is larger than all samples in the array. */
tRowcnt iUpper, iGap;
@@ -128987,18 +146876,18 @@ static int whereKeyStats(
iGap = iGap/3;
}
aStat[0] = iLower + iGap;
- aStat[1] = pIdx->aAvgEq[iCol];
+ aStat[1] = pIdx->aAvgEq[nField-1];
}
/* Restore the pRec->nField value before returning. */
pRec->nField = nField;
return i;
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
/*
** If it is not NULL, pTerm is a term that provides an upper or lower
-** bound on a range scan. Without considering pTerm, it is estimated
+** bound on a range scan. Without considering pTerm, it is estimated
** that the scan will visit nNew rows. This function returns the number
** estimated to be visited after taking pTerm into account.
**
@@ -129020,7 +146909,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
/*
** Return the affinity for a single column of an index.
*/
@@ -129029,24 +146918,25 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo
if( !pIdx->zColAff ){
if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
}
+ assert( pIdx->zColAff[iCol]!=0 );
return pIdx->zColAff[iCol];
}
#endif
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-/*
+#ifdef SQLITE_ENABLE_STAT4
+/*
** This function is called to estimate the number of rows visited by a
** range-scan on a skip-scan index. For example:
**
** CREATE INDEX i1 ON t1(a, b, c);
** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?;
**
-** Value pLoop->nOut is currently set to the estimated number of rows
-** visited for scanning (a=? AND b=?). This function reduces that estimate
+** Value pLoop->nOut is currently set to the estimated number of rows
+** visited for scanning (a=? AND b=?). This function reduces that estimate
** by some factor to account for the (c BETWEEN ? AND ?) expression based
-** on the stat4 data for the index. this scan will be peformed multiple
-** times (once for each (a,b) combination that matches a=?) is dealt with
+** on the stat4 data for the index. this scan will be peformed multiple
+** times (once for each (a,b) combination that matches a=?) is dealt with
** by the caller.
**
** It does this by scanning through all stat4 samples, comparing values
@@ -129067,7 +146957,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo
** estimate of the number of rows delivered remains unchanged), *pbDone
** is left as is.
**
-** If an error occurs, an SQLite error code is returned. Otherwise,
+** If an error occurs, an SQLite error code is returned. Otherwise,
** SQLITE_OK.
*/
static int whereRangeSkipScanEst(
@@ -129085,7 +146975,7 @@ static int whereRangeSkipScanEst(
int rc = SQLITE_OK;
u8 aff = sqlite3IndexColumnAffinity(db, p, nEq);
CollSeq *pColl;
-
+
sqlite3_value *p1 = 0; /* Value extracted from pLower */
sqlite3_value *p2 = 0; /* Value extracted from pUpper */
sqlite3_value *pVal = 0; /* Value extracted from record */
@@ -129117,7 +147007,7 @@ static int whereRangeSkipScanEst(
nDiff = (nUpper - nLower);
if( nDiff<=0 ) nDiff = 1;
- /* If there is both an upper and lower bound specified, and the
+ /* If there is both an upper and lower bound specified, and the
** comparisons indicate that they are close together, use the fallback
** method (assume that the scan visits 1/64 of the rows) for estimating
** the number of rows visited. Otherwise, estimate the number of rows
@@ -129140,7 +147030,7 @@ static int whereRangeSkipScanEst(
return rc;
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
/*
** This function is used to estimate the number of rows that will be visited
@@ -129164,7 +147054,7 @@ static int whereRangeSkipScanEst(
**
** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ...
**
-** then nEq is set to 1 (as the range restricted column, b, is the second
+** then nEq is set to 1 (as the range restricted column, b, is the second
** left-most column of the index). Or, if the query is:
**
** ... FROM t1 WHERE a > ? AND a < ? ...
@@ -129172,13 +147062,13 @@ static int whereRangeSkipScanEst(
** then nEq is set to 0.
**
** When this function is called, *pnOut is set to the sqlite3LogEst() of the
-** number of rows that the index scan is expected to visit without
-** considering the range constraints. If nEq is 0, then *pnOut is the number of
+** number of rows that the index scan is expected to visit without
+** considering the range constraints. If nEq is 0, then *pnOut is the number of
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
** to account for the range constraints pLower and pUpper.
-**
+**
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
-** used, a single range inequality reduces the search space by a factor of 4.
+** used, a single range inequality reduces the search space by a factor of 4.
** and a pair of constraints (x>? AND x<?) reduces the expected number of
** rows visited by a factor of 64.
*/
@@ -129193,18 +147083,20 @@ static int whereRangeScanEst(
int nOut = pLoop->nOut;
LogEst nNew;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
Index *p = pLoop->u.btree.pIndex;
int nEq = pLoop->u.btree.nEq;
- if( p->nSample>0 && nEq<p->nSampleCol ){
+ if( p->nSample>0 && ALWAYS(nEq<p->nSampleCol)
+ && OptimizationEnabled(pParse->db, SQLITE_Stat4)
+ ){
if( nEq==pBuilder->nRecValid ){
UnpackedRecord *pRec = pBuilder->pRec;
tRowcnt a[2];
int nBtm = pLoop->u.btree.nBtm;
int nTop = pLoop->u.btree.nTop;
- /* Variable iLower will be set to the estimate of the number of rows in
+ /* Variable iLower will be set to the estimate of the number of rows in
** the index that are less than the lower bound of the range query. The
** lower bound being the concatenation of $P and $L, where $P is the
** key-prefix formed by the nEq values matched against the nEq left-most
@@ -129213,7 +147105,7 @@ static int whereRangeScanEst(
** Or, if pLower is NULL or $L cannot be extracted from it (because it
** is not a simple variable or literal value), the lower bound of the
** range is $P. Due to a quirk in the way whereKeyStats() works, even
- ** if $L is available, whereKeyStats() is called for both ($P) and
+ ** if $L is available, whereKeyStats() is called for both ($P) and
** ($P:$L) and the larger of the two returned values is used.
**
** Similarly, iUpper is to be set to the estimate of the number of rows
@@ -129237,7 +147129,7 @@ static int whereRangeScanEst(
iLower = 0;
iUpper = p->nRowEst0;
}else{
- /* Note: this call could be optimized away - since the same values must
+ /* Note: this call could be optimized away - since the same values must
** have been requested when testing key $P in whereEqualScanEst(). */
whereKeyStats(pParse, p, pRec, 0, a);
iLower = a[0];
@@ -129294,7 +147186,7 @@ static int whereRangeScanEst(
/* TUNING: If both iUpper and iLower are derived from the same
** sample, then assume they are 4x more selective. This brings
** the estimated selectivity more in line with what it would be
- ** if estimated without the use of STAT3/4 tables. */
+ ** if estimated without the use of STAT4 tables. */
if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) );
}else{
nNew = 10; assert( 10==sqlite3LogEst(2) );
@@ -129325,7 +147217,7 @@ static int whereRangeScanEst(
** reduced by an additional 75%. This means that, by default, an open-ended
** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the
** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to
- ** match 1/64 of the index. */
+ ** match 1/64 of the index. */
if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){
nNew -= 20;
}
@@ -129343,16 +147235,16 @@ static int whereRangeScanEst(
return rc;
}
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
/*
** Estimate the number of rows that will be returned based on
** an equality constraint x=VALUE and where that VALUE occurs in
** the histogram data. This only works when x is the left-most
-** column of an index and sqlite_stat3 histogram data is available
+** column of an index and sqlite_stat4 histogram data is available
** for that index. When pExpr==NULL that means the constraint is
** "x IS NULL" instead of "x=VALUE".
**
-** Write the estimated row count into *pnRow and return SQLITE_OK.
+** Write the estimated row count into *pnRow and return SQLITE_OK.
** If unable to make an estimate, leave *pnRow unchanged and return
** non-zero.
**
@@ -129403,12 +147295,12 @@ static int whereEqualScanEst(
WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
p->zName, nEq-1, (int)a[1]));
*pnRow = a[1];
-
+
return rc;
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
/*
** Estimate the number of rows that will be returned based on
** an IN constraint where the right-hand side of the IN operator
@@ -129416,7 +147308,7 @@ static int whereEqualScanEst(
**
** WHERE x IN (1,2,3,4)
**
-** Write the estimated row count into *pnRow and return SQLITE_OK.
+** Write the estimated row count into *pnRow and return SQLITE_OK.
** If unable to make an estimate, leave *pnRow unchanged and return
** non-zero.
**
@@ -129455,41 +147347,49 @@ static int whereInScanEst(
assert( pBuilder->nRecValid==nRecValid );
return rc;
}
-#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
+#endif /* SQLITE_ENABLE_STAT4 */
#ifdef WHERETRACE_ENABLED
/*
** Print the content of a WhereTerm object
*/
-static void whereTermPrint(WhereTerm *pTerm, int iTerm){
+SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
if( pTerm==0 ){
sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
}else{
- char zType[4];
+ char zType[8];
char zLeft[50];
- memcpy(zType, "...", 4);
+ memcpy(zType, "....", 5);
if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
+ if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C';
if( pTerm->eOperator & WO_SINGLE ){
sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
pTerm->leftCursor, pTerm->u.leftColumn);
}else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
- sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld",
+ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld",
pTerm->u.pOrInfo->indexable);
}else{
sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
}
sqlite3DebugPrintf(
- "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x",
- iTerm, pTerm, zType, zLeft, pTerm->truthProb,
- pTerm->eOperator, pTerm->wtFlags);
+ "TERM-%-3d %p %s %-12s op=%03x wtFlags=%04x",
+ iTerm, pTerm, zType, zLeft, pTerm->eOperator, pTerm->wtFlags);
+ /* The 0x10000 .wheretrace flag causes extra information to be
+ ** shown about each Term */
+ if( sqlite3WhereTrace & 0x10000 ){
+ sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx",
+ pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight);
+ }
if( pTerm->iField ){
- sqlite3DebugPrintf(" iField=%d\n", pTerm->iField);
- }else{
- sqlite3DebugPrintf("\n");
+ sqlite3DebugPrintf(" iField=%d", pTerm->iField);
+ }
+ if( pTerm->iParent>=0 ){
+ sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
}
+ sqlite3DebugPrintf("\n");
sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
}
}
@@ -129502,7 +147402,7 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
int i;
for(i=0; i<pWC->nTerm; i++){
- whereTermPrint(&pWC->a[i], i);
+ sqlite3WhereTermPrint(&pWC->a[i], i);
}
}
#endif
@@ -129511,7 +147411,7 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
/*
** Print a WhereLoop object for debugging purposes
*/
-static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
+SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
WhereInfo *pWInfo = pWC->pWInfo;
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
@@ -129536,7 +147436,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
}else{
char *z;
if( p->u.vtab.idxStr ){
- z = sqlite3_mprintf("(%d,\"%s\",%x)",
+ z = sqlite3_mprintf("(%d,\"%s\",%#x)",
p->u.vtab.idxNum, p->u.vtab.idxStr, p->u.vtab.omitMask);
}else{
z = sqlite3_mprintf("(%d,%x)", p->u.vtab.idxNum, p->u.vtab.omitMask);
@@ -129553,7 +147453,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
int i;
for(i=0; i<p->nLTerm; i++){
- whereTermPrint(p->aLTerm[i], i);
+ sqlite3WhereTermPrint(p->aLTerm[i], i);
}
}
}
@@ -129581,7 +147481,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
p->u.vtab.idxStr = 0;
}else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){
sqlite3DbFree(db, p->u.btree.pIndex->zColAff);
- sqlite3DbFree(db, p->u.btree.pIndex);
+ sqlite3DbFreeNN(db, p->u.btree.pIndex);
p->u.btree.pIndex = 0;
}
}
@@ -129591,7 +147491,7 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
** Deallocate internal memory used by a WhereLoop object
*/
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
whereLoopClearUnion(db, p);
whereLoopInit(p);
}
@@ -129606,7 +147506,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
if( paNew==0 ) return SQLITE_NOMEM_BKPT;
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
p->aLTerm = paNew;
p->nLSlot = n;
return SQLITE_OK;
@@ -129636,47 +147536,48 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
*/
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
whereLoopClear(db, p);
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
/*
** Free a WhereInfo structure
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
- if( ALWAYS(pWInfo) ){
- int i;
- for(i=0; i<pWInfo->nLevel; i++){
- WhereLevel *pLevel = &pWInfo->a[i];
- if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
- sqlite3DbFree(db, pLevel->u.in.aInLoop);
- }
- }
- sqlite3WhereClauseClear(&pWInfo->sWC);
- while( pWInfo->pLoops ){
- WhereLoop *p = pWInfo->pLoops;
- pWInfo->pLoops = p->pNextLoop;
- whereLoopDelete(db, p);
+ int i;
+ assert( pWInfo!=0 );
+ for(i=0; i<pWInfo->nLevel; i++){
+ WhereLevel *pLevel = &pWInfo->a[i];
+ if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
+ sqlite3DbFree(db, pLevel->u.in.aInLoop);
}
- sqlite3DbFree(db, pWInfo);
}
+ sqlite3WhereClauseClear(&pWInfo->sWC);
+ while( pWInfo->pLoops ){
+ WhereLoop *p = pWInfo->pLoops;
+ pWInfo->pLoops = p->pNextLoop;
+ whereLoopDelete(db, p);
+ }
+ assert( pWInfo->pExprMods==0 );
+ sqlite3DbFreeNN(db, pWInfo);
}
/*
** Return TRUE if all of the following are true:
**
** (1) X has the same or lower cost that Y
-** (2) X is a proper subset of Y
-** (3) X skips at least as many columns as Y
-**
-** By "proper subset" we mean that X uses fewer WHERE clause terms
-** than Y and that every WHERE clause term used by X is also used
-** by Y.
+** (2) X uses fewer WHERE clause terms than Y
+** (3) Every WHERE clause term used by X is also used by Y
+** (4) X skips at least as many columns as Y
+** (5) If X is a covering index, than Y is too
**
+** Conditions (2) and (3) mean that X is a "proper subset" of Y.
** If X is a proper subset of Y then Y is a better choice and ought
-** to have a lower cost. This routine returns TRUE when that cost
-** relationship is inverted and needs to be adjusted. The third rule
+** to have a lower cost. This routine returns TRUE when that cost
+** relationship is inverted and needs to be adjusted. Constraint (4)
** was added because if X uses skip-scan less than Y it still might
-** deserve a lower cost even if it is a proper subset of Y.
+** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
+** was added because a covering index probably deserves to have a lower cost
+** than a non-covering index even if it is a proper subset.
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
@@ -129698,6 +147599,10 @@ static int whereLoopCheaperProperSubset(
}
if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
}
+ if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
+ && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
+ return 0; /* Constraint (5) */
+ }
return 1; /* All conditions meet */
}
@@ -129721,7 +147626,7 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
if( whereLoopCheaperProperSubset(p, pTemplate) ){
- /* Adjust pTemplate cost downward so that it is cheaper than its
+ /* Adjust pTemplate cost downward so that it is cheaper than its
** subset p. */
WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1));
@@ -129740,16 +147645,17 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
-** supplanted by pTemplate.
+** replaced by pTemplate.
**
-** Return NULL if the WhereLoop list contains an entry that can supplant
-** pTemplate, in other words if pTemplate does not belong on the list.
+** Return NULL if pTemplate does not belong on the WhereLoop list.
+** In other words if pTemplate ought to be dropped from further consideration.
**
-** If pX is a WhereLoop that pTemplate can supplant, then return the
+** If pX is a WhereLoop that pTemplate can replace, then return the
** link that points to pX.
**
-** If pTemplate cannot supplant any existing element of the list but needs
-** to be added to the list, then return a pointer to the tail of the list.
+** If pTemplate cannot replace any existing element of the list but needs
+** to be added to the list as a new entry, then return a pointer to the
+** tail of the list.
*/
static WhereLoop **whereLoopFindLesser(
WhereLoop **ppPrev,
@@ -129766,7 +147672,7 @@ static WhereLoop **whereLoopFindLesser(
/* In the current implementation, the rSetup value is either zero
** or the cost of building an automatic index (NlogN) and the NlogN
** is the same for compatible WhereLoops. */
- assert( p->rSetup==0 || pTemplate->rSetup==0
+ assert( p->rSetup==0 || pTemplate->rSetup==0
|| p->rSetup==pTemplate->rSetup );
/* whereLoopAddBtree() always generates and inserts the automatic index
@@ -129831,7 +147737,7 @@ static WhereLoop **whereLoopFindLesser(
**
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
** still might overwrite similar loops with the new template if the
-** new template is better. Loops may be overwritten if the following
+** new template is better. Loops may be overwritten if the following
** conditions are met:
**
** (1) They have the same iTab.
@@ -129845,6 +147751,16 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
sqlite3 *db = pWInfo->pParse->db;
int rc;
+ /* Stop the search once we hit the query planner search limit */
+ if( pBuilder->iPlanLimit==0 ){
+ WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n"));
+ if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0;
+ return SQLITE_DONE;
+ }
+ pBuilder->iPlanLimit--;
+
+ whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
+
/* If pBuilder->pOrSet is defined, then only keep track of the costs
** and prereqs.
*/
@@ -129859,7 +147775,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
- whereLoopPrint(pTemplate, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
}
@@ -129868,7 +147784,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
/* Look for an existing WhereLoop to replace with pTemplate
*/
- whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
if( ppPrev==0 ){
@@ -129877,10 +147792,10 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf(" skip: ");
- whereLoopPrint(pTemplate, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
- return SQLITE_OK;
+ return SQLITE_OK;
}else{
p = *ppPrev;
}
@@ -129893,10 +147808,12 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
if( sqlite3WhereTrace & 0x8 ){
if( p!=0 ){
sqlite3DebugPrintf("replace: ");
- whereLoopPrint(p, pBuilder->pWC);
+ sqlite3WhereLoopPrint(p, pBuilder->pWC);
+ sqlite3DebugPrintf(" with: ");
+ }else{
+ sqlite3DebugPrintf(" add: ");
}
- sqlite3DebugPrintf(" add: ");
- whereLoopPrint(pTemplate, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
if( p==0 ){
@@ -129920,7 +147837,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf(" delete: ");
- whereLoopPrint(pToDel, pBuilder->pWC);
+ sqlite3WhereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
whereLoopDelete(db, pToDel);
@@ -129929,7 +147846,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
rc = whereLoopXfer(db, p, pTemplate);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex;
- if( pIndex && pIndex->tnum==0 ){
+ if( pIndex && pIndex->idxType==SQLITE_IDXTYPE_IPK ){
p->u.btree.pIndex = 0;
}
}
@@ -129972,11 +147889,12 @@ static void whereLoopOutputAdjust(
){
WhereTerm *pTerm, *pX;
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
- int i, j, k;
+ int i, j;
LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
+ assert( pTerm!=0 );
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
if( (pTerm->prereqAll & notAllowed)!=0 ) continue;
@@ -129995,15 +147913,21 @@ static void whereLoopOutputAdjust(
/* In the absence of explicit truth probabilities, use heuristics to
** guess a reasonable truth probability. */
pLoop->nOut--;
- if( pTerm->eOperator&(WO_EQ|WO_IS) ){
+ if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0
+ && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */
+ ){
Expr *pRight = pTerm->pExpr->pRight;
+ int k = 0;
testcase( pTerm->pExpr->op==TK_IS );
if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
k = 10;
}else{
k = 20;
}
- if( iReduce<k ) iReduce = k;
+ if( iReduce<k ){
+ pTerm->wtFlags |= TERM_HEURTRUTH;
+ iReduce = k;
+ }
}
}
}
@@ -130011,7 +147935,7 @@ static void whereLoopOutputAdjust(
if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
}
-/*
+/*
** Term pTerm is a vector range comparison operation. The first comparison
** in the vector can be optimized using column nEq of the index. This
** function returns the total number of vector elements that can be used
@@ -130040,7 +147964,7 @@ static int whereRangeVectorLen(
nCmp = MIN(nCmp, (pIdx->nColumn - nEq));
for(i=1; i<nCmp; i++){
- /* Test if comparison i of pTerm is compatible with column (i+nEq)
+ /* Test if comparison i of pTerm is compatible with column (i+nEq)
** of the index. If not, exit the loop. */
char aff; /* Comparison affinity */
char idxaff = 0; /* Indexed columns affinity */
@@ -130057,9 +147981,9 @@ static int whereRangeVectorLen(
** the right column of the right source table. And that the sort
** order of the index column is the same as the sort order of the
** leftmost index column. */
- if( pLhs->op!=TK_COLUMN
- || pLhs->iTable!=iCur
- || pLhs->iColumn!=pIdx->aiColumn[i+nEq]
+ if( pLhs->op!=TK_COLUMN
+ || pLhs->iTable!=iCur
+ || pLhs->iColumn!=pIdx->aiColumn[i+nEq]
|| pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq]
){
break;
@@ -130088,16 +148012,16 @@ static int whereRangeVectorLen(
#endif
/*
-** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
+** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
** index pIndex. Try to match one more.
**
-** When this function is called, pBuilder->pNew->nOut contains the
-** number of rows expected to be visited by filtering using the nEq
-** terms only. If it is modified, this value is restored before this
+** When this function is called, pBuilder->pNew->nOut contains the
+** number of rows expected to be visited by filtering using the nEq
+** terms only. If it is modified, this value is restored before this
** function returns.
**
-** If pProbe->tnum==0, that means pIndex is a fake index used for the
-** INTEGER PRIMARY KEY.
+** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is
+** a fake index used for the INTEGER PRIMARY KEY.
*/
static int whereLoopAddBtreeIndex(
WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
@@ -130127,8 +148051,9 @@ static int whereLoopAddBtreeIndex(
pNew = pBuilder->pNew;
if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
- WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n",
- pProbe->zName, pNew->u.btree.nEq));
+ WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n",
+ pProbe->pTable->zName,pProbe->zName,
+ pNew->u.btree.nEq, pNew->nSkip));
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
@@ -130160,7 +148085,7 @@ static int whereLoopAddBtreeIndex(
LogEst rCostIdx;
LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */
int nIn = 0;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
int nRecValid = pBuilder->nRecValid;
#endif
if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
@@ -130174,18 +148099,20 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
- /* Do not allow IS constraints from the WHERE clause to be used by the
- ** right table of a LEFT JOIN. Only constraints in the ON clause are
- ** allowed */
+ /* tag-20191211-001: Do not allow constraints from the WHERE clause to
+ ** be used by the right table of a LEFT JOIN. Only constraints in the
+ ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */
if( (pSrc->fg.jointype & JT_LEFT)!=0
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
- && (eOp & (WO_IS|WO_ISNULL))!=0
){
- testcase( eOp & WO_IS );
- testcase( eOp & WO_ISNULL );
continue;
}
+ if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
+ pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
+ }else{
+ pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED;
+ }
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->u.btree.nBtm = saved_nBtm;
@@ -130196,14 +148123,13 @@ static int whereLoopAddBtreeIndex(
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
assert( nInMul==0
- || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0
- || (pNew->wsFlags & WHERE_COLUMN_IN)!=0
- || (pNew->wsFlags & WHERE_SKIPSCAN)!=0
+ || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0
+ || (pNew->wsFlags & WHERE_COLUMN_IN)!=0
+ || (pNew->wsFlags & WHERE_SKIPSCAN)!=0
);
if( eOp & WO_IN ){
Expr *pExpr = pTerm->pExpr;
- pNew->wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
int i;
@@ -130220,20 +148146,56 @@ static int whereLoopAddBtreeIndex(
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
/* "x IN (value, value, ...)" */
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
- assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
- ** changes "x IN (?)" into "x=?". */
}
+ if( pProbe->hasStat1 ){
+ LogEst M, logK, safetyMargin;
+ /* Let:
+ ** N = the total number of rows in the table
+ ** K = the number of entries on the RHS of the IN operator
+ ** M = the number of rows in the table that match terms to the
+ ** to the left in the same index. If the IN operator is on
+ ** the left-most index column, M==N.
+ **
+ ** Given the definitions above, it is better to omit the IN operator
+ ** from the index lookup and instead do a scan of the M elements,
+ ** testing each scanned row against the IN operator separately, if:
+ **
+ ** M*log(K) < K*log(N)
+ **
+ ** Our estimates for M, K, and N might be inaccurate, so we build in
+ ** a safety margin of 2 (LogEst: 10) that favors using the IN operator
+ ** with the index, as using an index has better worst-case behavior.
+ ** If we do not have real sqlite_stat1 data, always prefer to use
+ ** the index.
+ */
+ M = pProbe->aiRowLogEst[saved_nEq];
+ logK = estLog(nIn);
+ safetyMargin = 10; /* TUNING: extra weight for indexed IN */
+ if( M + logK + safetyMargin < nIn + rLogSize ){
+ WHERETRACE(0x40,
+ ("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n",
+ saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
+ continue;
+ }else{
+ WHERETRACE(0x40,
+ ("IN operator preferred on column %d of \"%s\" (%d>=%d)\n",
+ saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
+ }
+ }
+ pNew->wsFlags |= WHERE_COLUMN_IN;
}else if( eOp & (WO_EQ|WO_IS) ){
int iCol = pProbe->aiColumn[saved_nEq];
pNew->wsFlags |= WHERE_COLUMN_EQ;
assert( saved_nEq==pNew->u.btree.nEq );
- if( iCol==XN_ROWID
- || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
+ if( iCol==XN_ROWID
+ || (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
){
- if( iCol>=0 && pProbe->uniqNotNull==0 ){
- pNew->wsFlags |= WHERE_UNQ_WANTED;
- }else{
+ if( iCol==XN_ROWID || pProbe->uniqNotNull
+ || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ)
+ ){
pNew->wsFlags |= WHERE_ONEROW;
+ }else{
+ pNew->wsFlags |= WHERE_UNQ_WANTED;
}
}
}else if( eOp & WO_ISNULL ){
@@ -130274,12 +148236,12 @@ static int whereLoopAddBtreeIndex(
/* At this point pNew->nOut is set to the number of rows expected to
** be visited by the index scan before considering term pTerm, or the
- ** values of nIn and nInMul. In other words, assuming that all
+ ** values of nIn and nInMul. In other words, assuming that all
** "x IN(...)" terms are replaced with "x = ?". This block updates
** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */
assert( pNew->nOut==saved_nOut );
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
- /* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4
+ /* Adjust nOut using stat4 data. Or, if there is no stat4
** data, using some other estimate. */
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
}else{
@@ -130293,12 +148255,13 @@ static int whereLoopAddBtreeIndex(
pNew->nOut += pTerm->truthProb;
pNew->nOut -= nIn;
}else{
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
tRowcnt nOut = 0;
- if( nInMul==0
- && pProbe->nSample
+ if( nInMul==0
+ && pProbe->nSample
&& pNew->u.btree.nEq<=pProbe->nSampleCol
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
+ && OptimizationEnabled(db, SQLITE_Stat4)
){
Expr *pExpr = pTerm->pExpr;
if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){
@@ -130313,6 +148276,27 @@ static int whereLoopAddBtreeIndex(
if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */
if( nOut ){
pNew->nOut = sqlite3LogEst(nOut);
+ if( nEq==1
+ /* TUNING: Mark terms as "low selectivity" if they seem likely
+ ** to be true for half or more of the rows in the table.
+ ** See tag-202002240-1 */
+ && pNew->nOut+10 > pProbe->aiRowLogEst[0]
+ ){
+#if WHERETRACE_ENABLED /* 0x01 */
+ if( sqlite3WhereTrace & 0x01 ){
+ sqlite3DebugPrintf(
+ "STAT4 determines term has low selectivity:\n");
+ sqlite3WhereTermPrint(pTerm, 999);
+ }
+#endif
+ pTerm->wtFlags |= TERM_HIGHTRUTH;
+ if( pTerm->wtFlags & TERM_HEURTRUTH ){
+ /* If the term has previously been used with an assumption of
+ ** higher selectivity, then set the flag to rerun the
+ ** loop computations. */
+ pBuilder->bldFlags2 |= SQLITE_BLDF2_2NDPASS;
+ }
+ }
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
pNew->nOut -= nIn;
}
@@ -130322,8 +148306,8 @@ static int whereLoopAddBtreeIndex(
{
pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]);
if( eOp & WO_ISNULL ){
- /* TUNING: If there is no likelihood() value, assume that a
- ** "col IS NULL" expression matches twice as many rows
+ /* TUNING: If there is no likelihood() value, assume that a
+ ** "col IS NULL" expression matches twice as many rows
** as (col=?). */
pNew->nOut += 10;
}
@@ -130335,6 +148319,7 @@ static int whereLoopAddBtreeIndex(
** it to pNew->rRun, which is currently set to the cost of the index
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
+ assert( pSrc->pTab->szTabRow>0 );
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
@@ -130360,7 +148345,7 @@ static int whereLoopAddBtreeIndex(
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
}
pNew->nOut = saved_nOut;
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+#ifdef SQLITE_ENABLE_STAT4
pBuilder->nRecValid = nRecValid;
#endif
}
@@ -130375,18 +148360,21 @@ static int whereLoopAddBtreeIndex(
/* Consider using a skip-scan if there are no WHERE clause constraints
** available for the left-most terms of the index, and if the average
- ** number of repeats in the left-most terms is at least 18.
+ ** number of repeats in the left-most terms is at least 18.
**
** The magic number 18 is selected on the basis that scanning 17 rows
** is almost always quicker than an index seek (even though if the index
** contains fewer than 2^17 rows we assume otherwise in other parts of
- ** the code). And, even if it is not, it should not be too much slower.
+ ** the code). And, even if it is not, it should not be too much slower.
** On the other hand, the extra seeks could end up being significantly
** more expensive. */
assert( 42==sqlite3LogEst(18) );
if( saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
+ && saved_nEq==pNew->nLTerm
&& pProbe->noSkipScan==0
+ && pProbe->hasStat1!=0
+ && OptimizationEnabled(db, SQLITE_SkipScan)
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
){
@@ -130407,8 +148395,8 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags = saved_wsFlags;
}
- WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n",
- pProbe->zName, saved_nEq, rc));
+ WHERETRACE(0x800, ("END %s.addBtreeIdx(%s), nEq=%d, rc=%d\n",
+ pProbe->pTable->zName, pProbe->zName, saved_nEq, rc));
return rc;
}
@@ -130432,7 +148420,7 @@ static int indexMightHelpWithOrderBy(
if( pIndex->bUnordered ) return 0;
if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
for(ii=0; ii<pOB->nExpr; ii++){
- Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr);
+ Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
if( pExpr->iColumn<0 ) return 1;
for(jj=0; jj<pIndex->nKeyCol; jj++){
@@ -130441,7 +148429,7 @@ static int indexMightHelpWithOrderBy(
}else if( (aColExpr = pIndex->aColExpr)!=0 ){
for(jj=0; jj<pIndex->nKeyCol; jj++){
if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
- if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
+ if( sqlite3ExprCompareSkip(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
return 1;
}
}
@@ -130450,38 +148438,29 @@ static int indexMightHelpWithOrderBy(
return 0;
}
-/*
-** Return a bitmask where 1s indicate that the corresponding column of
-** the table is used by an index. Only the first 63 columns are considered.
-*/
-static Bitmask columnsInIndex(Index *pIdx){
- Bitmask m = 0;
- int j;
- for(j=pIdx->nColumn-1; j>=0; j--){
- int x = pIdx->aiColumn[j];
- if( x>=0 ){
- testcase( x==BMS-1 );
- testcase( x==BMS-2 );
- if( x<BMS-1 ) m |= MASKBIT(x);
- }
- }
- return m;
-}
-
/* Check to see if a partial index with pPartIndexWhere can be used
** in the current query. Return true if it can be and false if not.
*/
-static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
+static int whereUsablePartialIndex(
+ int iTab, /* The table for which we want an index */
+ int isLeft, /* True if iTab is the right table of a LEFT JOIN */
+ WhereClause *pWC, /* The WHERE clause of the query */
+ Expr *pWhere /* The WHERE clause from the partial index */
+){
int i;
WhereTerm *pTerm;
+ Parse *pParse = pWC->pWInfo->pParse;
while( pWhere->op==TK_AND ){
- if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
+ if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0;
pWhere = pWhere->pRight;
}
+ if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
- Expr *pExpr = pTerm->pExpr;
- if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab)
- && (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
+ Expr *pExpr;
+ pExpr = pTerm->pExpr;
+ if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
+ && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
+ && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
){
return 1;
}
@@ -130503,18 +148482,18 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
** cost = nRow * K // scan of covering index
** cost = nRow * (K+3.0) // scan of non-covering index
**
-** where K is a value between 1.1 and 3.0 set based on the relative
+** where K is a value between 1.1 and 3.0 set based on the relative
** estimated average size of the index and table records.
**
** For an index scan, where nVisit is the number of index rows visited
-** by the scan, and nSeek is the number of seek operations required on
+** by the scan, and nSeek is the number of seek operations required on
** the index b-tree:
**
** cost = nSeek * (log(nRow) + K * nVisit) // covering index
** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
**
-** Normally, nSeek is 1. nSeek values greater than 1 come about if the
-** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
+** Normally, nSeek is 1. nSeek values greater than 1 come about if the
+** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
**
** The estimated values (nRow, nVisit, nSeek) often contain a large amount
@@ -130544,7 +148523,7 @@ static int whereLoopAddBtree(
LogEst rLogSize; /* Logarithm of the number of rows in the table */
WhereClause *pWC; /* The parsed WHERE clause */
Table *pTab; /* Table being queried */
-
+
pNew = pBuilder->pNew;
pWInfo = pBuilder->pWInfo;
pTabList = pWInfo->pTabList;
@@ -130572,6 +148551,7 @@ static int whereLoopAddBtree(
sPk.onError = OE_Replace;
sPk.pTable = pTab;
sPk.szIdxRow = pTab->szTabRow;
+ sPk.idxType = SQLITE_IDXTYPE_IPK;
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
pFirst = pSrc->pTab->pIndex;
@@ -130610,14 +148590,16 @@ static int whereLoopAddBtree(
/* TUNING: One-time cost for computing the automatic index is
** estimated to be X*N*log2(N) where N is the number of rows in
** the table being indexed and where X is 7 (LogEst=28) for normal
- ** tables or 1.375 (LogEst=4) for views and subqueries. The value
+ ** tables or 0.5 (LogEst=-10) for views and subqueries. The value
** of X is smaller for views and subqueries so that the query planner
** will be more aggressive about generating automatic indexes for
** those objects, since there is no opportunity to add schema
** indexes on subqueries and views. */
- pNew->rSetup = rLogSize + rSize + 4;
+ pNew->rSetup = rLogSize + rSize;
if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){
- pNew->rSetup += 24;
+ pNew->rSetup += 28;
+ }else{
+ pNew->rSetup -= 10;
}
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
if( pNew->rSetup<0 ) pNew->rSetup = 0;
@@ -130635,14 +148617,20 @@ static int whereLoopAddBtree(
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
- /* Loop over all indices
- */
- for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){
+ /* Loop over all indices. If there was an INDEXED BY clause, then only
+ ** consider index pProbe. */
+ for(; rc==SQLITE_OK && pProbe;
+ pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
+ ){
+ int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0;
if( pProbe->pPartIdxWhere!=0
- && !whereUsablePartialIndex(pSrc->iCursor, pWC, pProbe->pPartIdxWhere) ){
+ && !whereUsablePartialIndex(pSrc->iCursor, isLeft, pWC,
+ pProbe->pPartIdxWhere)
+ ){
testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */
continue; /* Partial index inappropriate for this query */
}
+ if( pProbe->bNoQuery ) continue;
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
pNew->u.btree.nBtm = 0;
@@ -130655,9 +148643,10 @@ static int whereLoopAddBtree(
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
+
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
- if( pProbe->tnum<=0 ){
+ if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* Integer primary key index */
pNew->wsFlags = WHERE_IPK;
@@ -130676,7 +148665,7 @@ static int whereLoopAddBtree(
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
m = 0;
}else{
- m = pSrc->colUsed & ~columnsInIndex(pProbe);
+ m = pSrc->colUsed & pProbe->colNotIdxed;
pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
}
@@ -130684,6 +148673,7 @@ static int whereLoopAddBtree(
if( b
|| !HasRowid(pTab)
|| pProbe->pPartIdxWhere!=0
+ || pSrc->fg.isIndexedBy
|| ( m==0
&& pProbe->bUnordered==0
&& (pProbe->szIdxRow<pTab->szTabRow)
@@ -130722,7 +148712,7 @@ static int whereLoopAddBtree(
if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19;
}
}
-
+
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
}
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
@@ -130733,16 +148723,20 @@ static int whereLoopAddBtree(
}
}
+ pBuilder->bldFlags1 = 0;
rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
-#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+ if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){
+ /* If a non-unique index is used, or if a prefix of the key for
+ ** unique index is used (making the index functionally non-unique)
+ ** then the sqlite_stat1 data becomes important for scoring the
+ ** plan */
+ pTab->tabFlags |= TF_StatsUsed;
+ }
+#ifdef SQLITE_ENABLE_STAT4
sqlite3Stat4ProbeFree(pBuilder->pRec);
pBuilder->nRecValid = 0;
pBuilder->pRec = 0;
#endif
-
- /* If there was an INDEXED BY clause, then only that one index is
- ** considered. */
- if( pSrc->pIBIndex ) break;
}
return rc;
}
@@ -130793,13 +148787,13 @@ static int whereLoopAddVirtualOne(
*pbIn = 0;
pNew->prereq = mPrereq;
- /* Set the usable flag on the subset of constraints identified by
+ /* Set the usable flag on the subset of constraints identified by
** arguments mUsable and mExclude. */
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
for(i=0; i<nConstraint; i++, pIdxCons++){
WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
pIdxCons->usable = 0;
- if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
+ if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
&& (pTerm->eOperator & mExclude)==0
){
pIdxCons->usable = 1;
@@ -130819,7 +148813,17 @@ static int whereLoopAddVirtualOne(
/* Invoke the virtual table xBestIndex() method */
rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
- if( rc ) return rc;
+ if( rc ){
+ if( rc==SQLITE_CONSTRAINT ){
+ /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means
+ ** that the particular combination of parameters provided is unusable.
+ ** Make no entries in the loop table.
+ */
+ WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n"));
+ return SQLITE_OK;
+ }
+ return rc;
+ }
mxTerm = -1;
assert( pNew->nLSlot>=nConstraint );
@@ -130837,9 +148841,9 @@ static int whereLoopAddVirtualOne(
|| pNew->aLTerm[iTerm]!=0
|| pIdxCons->usable==0
){
- rc = SQLITE_ERROR;
sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
- return rc;
+ testcase( pIdxInfo->needToFreeIdxStr );
+ return SQLITE_ERROR;
}
testcase( iTerm==nConstraint-1 );
testcase( j==0 );
@@ -130851,7 +148855,14 @@ static int whereLoopAddVirtualOne(
if( iTerm>mxTerm ) mxTerm = iTerm;
testcase( iTerm==15 );
testcase( iTerm==16 );
- if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
+ if( pUsage[i].omit ){
+ if( i<16 && ((1<<i)&mNoOmit)==0 ){
+ testcase( i!=iTerm );
+ pNew->u.vtab.omitMask |= 1<<iTerm;
+ }else{
+ testcase( i!=iTerm );
+ }
+ }
if( (pTerm->eOperator & WO_IN)!=0 ){
/* A virtual table that is constrained by an IN clause may not
** consume the ORDER BY clause because (1) the order of IN terms
@@ -130864,9 +148875,17 @@ static int whereLoopAddVirtualOne(
}
}
}
- pNew->u.vtab.omitMask &= ~mNoOmit;
pNew->nLTerm = mxTerm+1;
+ for(i=0; i<=mxTerm; i++){
+ if( pNew->aLTerm[i]==0 ){
+ /* The non-zero argvIdx values must be contiguous. Raise an
+ ** error if they are not */
+ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
+ testcase( pIdxInfo->needToFreeIdxStr );
+ return SQLITE_ERROR;
+ }
+ }
assert( pNew->nLTerm<=pNew->nLSlot );
pNew->u.vtab.idxNum = pIdxInfo->idxNum;
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
@@ -130897,6 +148916,27 @@ static int whereLoopAddVirtualOne(
return rc;
}
+/*
+** If this function is invoked from within an xBestIndex() callback, it
+** returns a pointer to a buffer containing the name of the collation
+** sequence associated with element iCons of the sqlite3_index_info.aConstraint
+** array. Or, if iCons is out of range or there is no active xBestIndex
+** call, return NULL.
+*/
+SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
+ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
+ const char *zRet = 0;
+ if( iCons>=0 && iCons<pIdxInfo->nConstraint ){
+ CollSeq *pC = 0;
+ int iTerm = pIdxInfo->aConstraint[iCons].iTermOffset;
+ Expr *pX = pHidden->pWC->a[iTerm].pExpr;
+ if( pX->pLeft ){
+ pC = sqlite3ExprCompareCollSeq(pHidden->pParse, pX);
+ }
+ zRet = (pC ? pC->zName : sqlite3StrBINARY);
+ }
+ return zRet;
+}
/*
** Add all WhereLoop objects for a table of the join identified by
@@ -130907,8 +148947,8 @@ static int whereLoopAddVirtualOne(
** entries that occur before the virtual table in the FROM clause and are
** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
** mUnusable mask contains all FROM clause entries that occur after the
-** virtual table and are separated from it by at least one LEFT or
-** CROSS JOIN.
+** virtual table and are separated from it by at least one LEFT or
+** CROSS JOIN.
**
** For example, if the query were:
**
@@ -130916,9 +148956,9 @@ static int whereLoopAddVirtualOne(
**
** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
**
-** All the tables in mPrereq must be scanned before the current virtual
-** table. So any terms for which all prerequisites are satisfied by
-** mPrereq may be specified as "usable" in all calls to xBestIndex.
+** All the tables in mPrereq must be scanned before the current virtual
+** table. So any terms for which all prerequisites are satisfied by
+** mPrereq may be specified as "usable" in all calls to xBestIndex.
** Conversely, all tables in mUnusable must be scanned after the current
** virtual table, so any terms for which the prerequisites overlap with
** mUnusable should always be configured as "not-usable" for xBestIndex.
@@ -130947,7 +148987,7 @@ static int whereLoopAddVirtual(
pNew = pBuilder->pNew;
pSrc = &pWInfo->pTabList->a[pNew->iTab];
assert( IsVirtual(pSrc->pTab) );
- p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy,
+ p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy,
&mNoOmit);
if( p==0 ) return SQLITE_NOMEM_BKPT;
pNew->rSetup = 0;
@@ -130961,15 +149001,16 @@ static int whereLoopAddVirtual(
}
/* First call xBestIndex() with all constraints usable. */
+ WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
WHERETRACE(0x40, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
/* If the call to xBestIndex() with all terms enabled produced a plan
- ** that does not require any source tables (IOW: a plan with mBest==0),
- ** then there is no point in making any further calls to xBestIndex()
- ** since they will all return the same result (if the xBestIndex()
- ** implementation is sane). */
- if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
+ ** that does not require any source tables (IOW: a plan with mBest==0)
+ ** and does not use an IN(...) operator, then there is no point in making
+ ** any further calls to xBestIndex() since they will all return the same
+ ** result (if the xBestIndex() implementation is sane). */
+ if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){
int seenZero = 0; /* True if a plan with no prereqs seen */
int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */
Bitmask mPrev = 0;
@@ -130989,7 +149030,7 @@ static int whereLoopAddVirtual(
}
}
- /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
+ /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
** in the set of terms that apply to the current virtual table. */
while( rc==SQLITE_OK ){
int i;
@@ -131035,7 +149076,8 @@ static int whereLoopAddVirtual(
}
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
- sqlite3DbFree(pParse->db, p);
+ sqlite3DbFreeNN(pParse->db, p);
+ WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -131045,8 +149087,8 @@ static int whereLoopAddVirtual(
** btrees or virtual tables.
*/
static int whereLoopAddOr(
- WhereLoopBuilder *pBuilder,
- Bitmask mPrereq,
+ WhereLoopBuilder *pBuilder,
+ Bitmask mPrereq,
Bitmask mUnusable
){
WhereInfo *pWInfo = pBuilder->pWInfo;
@@ -131059,7 +149101,7 @@ static int whereLoopAddOr(
WhereLoopBuilder sSubBuild;
WhereOrSet sSum, sCur;
struct SrcList_item *pItem;
-
+
pWC = pBuilder->pWC;
pWCEnd = pWC->a + pWC->nTerm;
pNew = pBuilder->pNew;
@@ -131069,14 +149111,14 @@ static int whereLoopAddOr(
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
if( (pTerm->eOperator & WO_OR)!=0
- && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
+ && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
){
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
WhereTerm *pOrTerm;
int once = 1;
int i, j;
-
+
sSubBuild = *pBuilder;
sSubBuild.pOrderBy = 0;
sSubBuild.pOrSet = &sCur;
@@ -131097,7 +149139,7 @@ static int whereLoopAddOr(
}
sCur.n = 0;
#ifdef WHERETRACE_ENABLED
- WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
+ WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
(int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
if( sqlite3WhereTrace & 0x400 ){
sqlite3WhereClausePrint(sSubBuild.pWC);
@@ -131114,7 +149156,8 @@ static int whereLoopAddOr(
if( rc==SQLITE_OK ){
rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
}
- assert( rc==SQLITE_OK || sCur.n==0 );
+ assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 );
+ testcase( rc==SQLITE_DONE );
if( sCur.n==0 ){
sSum.n = 0;
break;
@@ -131144,8 +149187,8 @@ static int whereLoopAddOr(
/* TUNING: Currently sSum.a[i].rRun is set to the sum of the costs
** of all sub-scans required by the OR-scan. However, due to rounding
** errors, it may be that the cost of the OR-scan is equal to its
- ** most expensive sub-scan. Add the smallest possible penalty
- ** (equivalent to multiplying the cost by 1.07) to ensure that
+ ** most expensive sub-scan. Add the smallest possible penalty
+ ** (equivalent to multiplying the cost by 1.07) to ensure that
** this does not happen. Otherwise, for WHERE clauses such as the
** following where there is an index on "y":
**
@@ -131165,7 +149208,7 @@ static int whereLoopAddOr(
}
/*
-** Add all WhereLoop objects for all tables
+** Add all WhereLoop objects for all tables
*/
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
WhereInfo *pWInfo = pBuilder->pWInfo;
@@ -131178,21 +149221,23 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
sqlite3 *db = pWInfo->pParse->db;
int rc = SQLITE_OK;
WhereLoop *pNew;
- u8 priorJointype = 0;
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
whereLoopInit(pNew);
+ pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
Bitmask mUnusable = 0;
pNew->iTab = iTab;
+ pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
- if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
+ if( (pItem->fg.jointype & (JT_LEFT|JT_CROSS))!=0 ){
/* This condition is true when pItem is the FROM clause term on the
** right-hand-side of a LEFT or CROSS JOIN. */
mPrereq = mPrior;
+ }else{
+ mPrereq = 0;
}
- priorJointype = pItem->fg.jointype;
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){
struct SrcList_item *p;
@@ -131207,11 +149252,19 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
{
rc = whereLoopAddBtree(pBuilder, mPrereq);
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){
rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
}
mPrior |= pNew->maskSelf;
- if( rc || db->mallocFailed ) break;
+ if( rc || db->mallocFailed ){
+ if( rc==SQLITE_DONE ){
+ /* We hit the query planner search limit set by iPlanLimit */
+ sqlite3_log(SQLITE_WARNING, "abbreviated query algorithm search");
+ rc = SQLITE_OK;
+ }else{
+ break;
+ }
+ }
}
whereLoopClear(db, pNew);
@@ -131219,20 +149272,20 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
}
/*
-** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
+** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
** parameters) to see if it outputs rows in the requested ORDER BY
** (or GROUP BY) without requiring a separate sort operation. Return N:
-**
+**
** N>0: N terms of the ORDER BY clause are satisfied
** N==0: No terms of the ORDER BY clause are satisfied
-** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
+** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
**
** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
** strict. With GROUP BY and DISTINCT the only requirement is that
** equivalent rows appear immediately adjacent to one another. GROUP BY
** and DISTINCT do not require rows to appear in any particular order as long
** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT
-** the pOrderBy terms can be matched in any order. With ORDER BY, the
+** the pOrderBy terms can be matched in any order. With ORDER BY, the
** pOrderBy terms must be matched in strict left-to-right order.
*/
static i8 wherePathSatisfiesOrderBy(
@@ -131282,7 +149335,7 @@ static i8 wherePathSatisfiesOrderBy(
** row of the WhereLoop. Every one-row WhereLoop is automatically
** order-distinct. A WhereLoop that has no columns in the ORDER BY clause
** is not order-distinct. To be order-distinct is not quite the same as being
- ** UNIQUE since a UNIQUE column or index can have multiple rows that
+ ** UNIQUE since a UNIQUE column or index can have multiple rows that
** are NULL and NULL values are equivalent for the purpose of order-distinct.
** To be order-distinct, the columns must be UNIQUE and NOT NULL.
**
@@ -131302,7 +149355,9 @@ static i8 wherePathSatisfiesOrderBy(
orderDistinctMask = 0;
ready = 0;
eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
- if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
+ if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){
+ eqOpMask |= WO_IN;
+ }
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
if( iLoop>0 ) ready |= pLoop->maskSelf;
if( iLoop<nLoop ){
@@ -131312,8 +149367,12 @@ static i8 wherePathSatisfiesOrderBy(
pLoop = pLast;
}
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
- if( pLoop->u.vtab.isOrdered ) obSat = obDone;
+ if( pLoop->u.vtab.isOrdered && (wctrlFlags & WHERE_DISTINCTBY)==0 ){
+ obSat = obDone;
+ }
break;
+ }else if( wctrlFlags & WHERE_DISTINCTBY ){
+ pLoop->u.btree.nDistinctCol = 0;
}
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
@@ -131324,29 +149383,29 @@ static i8 wherePathSatisfiesOrderBy(
*/
for(i=0; i<nOrderBy; i++){
if( MASKBIT(i) & obSat ) continue;
- pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
+ pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
if( pOBExpr->op!=TK_COLUMN ) continue;
if( pOBExpr->iTable!=iCur ) continue;
pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
~ready, eqOpMask, 0);
if( pTerm==0 ) continue;
if( pTerm->eOperator==WO_IN ){
- /* IN terms are only valid for sorting in the ORDER BY LIMIT
+ /* IN terms are only valid for sorting in the ORDER BY LIMIT
** optimization, and then only if they are actually used
** by the query plan */
- assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
+ assert( wctrlFlags &
+ (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) );
for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
if( j>=pLoop->nLTerm ) continue;
}
if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
- const char *z1, *z2;
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- z1 = pColl->zName;
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pTerm->pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- z2 = pColl->zName;
- if( sqlite3StrICmp(z1, z2)!=0 ) continue;
+ Parse *pParse = pWInfo->pParse;
+ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr);
+ CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr);
+ assert( pColl1 );
+ if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){
+ continue;
+ }
testcase( pTerm->pExpr->op==TK_IS );
}
obSat |= MASKBIT(i);
@@ -131365,7 +149424,8 @@ static i8 wherePathSatisfiesOrderBy(
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
|| !HasRowid(pIndex->pTable));
- isOrderDistinct = IsUniqueIndex(pIndex);
+ isOrderDistinct = IsUniqueIndex(pIndex)
+ && (pLoop->wsFlags & WHERE_SKIPSCAN)==0;
}
/* Loop through all columns of the index and deal with the ones
@@ -131376,26 +149436,32 @@ static i8 wherePathSatisfiesOrderBy(
for(j=0; j<nColumn; j++){
u8 bOnce = 1; /* True to run the ORDER BY search loop */
- assert( j>=pLoop->u.btree.nEq
+ assert( j>=pLoop->u.btree.nEq
|| (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip)
);
if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){
u16 eOp = pLoop->aLTerm[j]->eOperator;
/* Skip over == and IS and ISNULL terms. (Also skip IN terms when
- ** doing WHERE_ORDERBY_LIMIT processing).
+ ** doing WHERE_ORDERBY_LIMIT processing). Except, IS and ISNULL
+ ** terms imply that the index is not UNIQUE NOT NULL in which case
+ ** the loop need to be marked as not order-distinct because it can
+ ** have repeated NULL rows.
**
- ** If the current term is a column of an ((?,?) IN (SELECT...))
+ ** If the current term is a column of an ((?,?) IN (SELECT...))
** expression for which the SELECT returns more than one column,
** check that it is the only column used by this loop. Otherwise,
** if it is one of two or more, none of the columns can be
- ** considered to match an ORDER BY term. */
+ ** considered to match an ORDER BY term.
+ */
if( (eOp & eqOpMask)!=0 ){
- if( eOp & WO_ISNULL ){
+ if( eOp & (WO_ISNULL|WO_IS) ){
+ testcase( eOp & WO_ISNULL );
+ testcase( eOp & WO_IS );
testcase( isOrderDistinct );
isOrderDistinct = 0;
}
- continue;
+ continue;
}else if( ALWAYS(eOp & WO_IN) ){
/* ALWAYS() justification: eOp is an equality operator due to the
** j<pLoop->u.btree.nEq constraint above. Any equality other
@@ -131417,8 +149483,8 @@ static i8 wherePathSatisfiesOrderBy(
*/
if( pIndex ){
iColumn = pIndex->aiColumn[j];
- revIdx = pIndex->aSortOrder[j];
- if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
+ revIdx = pIndex->aSortOrder[j] & KEYINFO_ORDER_DESC;
+ if( iColumn==pIndex->pTable->iPKey ) iColumn = XN_ROWID;
}else{
iColumn = XN_ROWID;
revIdx = 0;
@@ -131436,29 +149502,32 @@ static i8 wherePathSatisfiesOrderBy(
}
/* Find the ORDER BY term that corresponds to the j-th column
- ** of the index and mark that ORDER BY term off
+ ** of the index and mark that ORDER BY term off
*/
isMatch = 0;
for(i=0; bOnce && i<nOrderBy; i++){
if( MASKBIT(i) & obSat ) continue;
- pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr);
+ pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
testcase( wctrlFlags & WHERE_GROUPBY );
testcase( wctrlFlags & WHERE_DISTINCTBY );
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
- if( iColumn>=(-1) ){
+ if( iColumn>=XN_ROWID ){
if( pOBExpr->op!=TK_COLUMN ) continue;
if( pOBExpr->iTable!=iCur ) continue;
if( pOBExpr->iColumn!=iColumn ) continue;
}else{
- if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
+ Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
+ if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
continue;
}
}
- if( iColumn>=0 ){
- pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
- if( !pColl ) pColl = db->pDfltColl;
+ if( iColumn!=XN_ROWID ){
+ pColl = sqlite3ExprNNCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) continue;
}
+ if( wctrlFlags & WHERE_DISTINCTBY ){
+ pLoop->u.btree.nDistinctCol = j+1;
+ }
isMatch = 1;
break;
}
@@ -131466,13 +149535,22 @@ static i8 wherePathSatisfiesOrderBy(
/* Make sure the sort order is compatible in an ORDER BY clause.
** Sort order is irrelevant for a GROUP BY clause. */
if( revSet ){
- if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
+ if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){
+ isMatch = 0;
+ }
}else{
- rev = revIdx ^ pOrderBy->a[i].sortOrder;
+ rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC);
if( rev ) *pRevMask |= MASKBIT(iLoop);
revSet = 1;
}
}
+ if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){
+ if( j==pLoop->u.btree.nEq ){
+ pLoop->wsFlags |= WHERE_BIGNULL_SORT;
+ }else{
+ isMatch = 0;
+ }
+ }
if( isMatch ){
if( iColumn==XN_ROWID ){
testcase( distinctColumns==0 );
@@ -131564,7 +149642,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
#endif
/*
-** Return the cost of sorting nRow rows, assuming that the keys have
+** Return the cost of sorting nRow rows, assuming that the keys have
** nOrderby columns and that the first nSorted columns are already in
** order.
*/
@@ -131574,13 +149652,13 @@ static LogEst whereSortingCost(
int nOrderBy,
int nSorted
){
- /* TUNING: Estimated cost of a full external sort, where N is
+ /* TUNING: Estimated cost of a full external sort, where N is
** the number of rows to sort is:
**
** cost = (3.0 * N * log(N)).
- **
- ** Or, if the order-by clause has X terms but only the last Y
- ** terms are out of order, then block-sorting will reduce the
+ **
+ ** Or, if the order-by clause has X terms but only the last Y
+ ** terms are out of order, then block-sorting will reduce the
** sorting cost to:
**
** cost = (3.0 * N * log(N)) * (Y/X)
@@ -131673,7 +149751,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** space for the aSortCost[] array. Each element of the aSortCost array
** is either zero - meaning it has not yet been initialized - or the
** cost of sorting nRowEst rows of data where the first X terms of
- ** the ORDER BY clause are already in order, where X is the array
+ ** the ORDER BY clause are already in order, where X is the array
** index. */
aSortCost = (LogEst*)pX;
memset(aSortCost, 0, sizeof(LogEst) * nOrderBy);
@@ -131694,7 +149772,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** in this case the query may return a maximum of one row, the results
** are already in the requested order. Set isOrdered to nOrderBy to
** indicate this. Or, if nLoop is greater than zero, set isOrdered to
- ** -1, indicating that the result set may or may not be ordered,
+ ** -1, indicating that the result set may or may not be ordered,
** depending on the loops added to the current plan. */
aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy;
}
@@ -131715,13 +149793,16 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
- if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){
+ if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){
/* Do not use an automatic index if the this loop is expected
- ** to run less than 2 times. */
+ ** to run less than 1.25 times. It is tempting to also exclude
+ ** automatic index usage on an outer loop, but sometimes an automatic
+ ** index is useful in the outer loop of a correlated subquery. */
assert( 10==sqlite3LogEst(2) );
continue;
}
- /* At this point, pWLoop is a candidate to be the next loop.
+
+ /* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
@@ -131740,14 +149821,19 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo, nRowEst, nOrderBy, isOrdered
);
}
- rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]);
+ /* TUNING: Add a small extra penalty (5) to sorting as an
+ ** extra encouragment to the query planner to select a plan
+ ** where the rows emerge in the correct order without any sorting
+ ** required. */
+ rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5;
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
- aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
+ aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
rUnsorted, rCost));
}else{
rCost = rUnsorted;
+ rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
/* Check to see if pWLoop should be added to the set of
@@ -131779,8 +149865,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** this candidate as not viable. */
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
- sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ sqlite3DebugPrintf("Skip %s cost=%-3d,%3d,%3d order=%c\n",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
@@ -131798,26 +149884,36 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pTo = &aTo[jj];
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
- sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ sqlite3DebugPrintf("New %s cost=%-3d,%3d,%3d order=%c\n",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
}else{
/* Control reaches here if best-so-far path pTo=aTo[jj] covers the
- ** same set of loops and has the sam isOrdered setting as the
+ ** same set of loops and has the same isOrdered setting as the
** candidate path. Check to see if the candidate should replace
- ** pTo or if the candidate should be skipped */
- if( pTo->rCost<rCost || (pTo->rCost==rCost && pTo->nRow<=nOut) ){
+ ** pTo or if the candidate should be skipped.
+ **
+ ** The conditional is an expanded vector comparison equivalent to:
+ ** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
+ */
+ if( pTo->rCost<rCost
+ || (pTo->rCost==rCost
+ && (pTo->nRow<nOut
+ || (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
+ )
+ )
+ ){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
- "Skip %s cost=%-3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ "Skip %s cost=%-3d,%3d,%3d order=%c",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
- sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
+ sqlite3DebugPrintf(" vs %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
/* Discard the candidate path from further consideration */
@@ -131830,12 +149926,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
#ifdef WHERETRACE_ENABLED /* 0x4 */
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf(
- "Update %s cost=%-3d,%3d order=%c",
- wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
+ "Update %s cost=%-3d,%3d,%3d order=%c",
+ wherePathName(pFrom, iLoop, pWLoop), rCost, nOut, rUnsorted,
isOrdered>=0 ? isOrdered+'0' : '?');
- sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
+ sqlite3DebugPrintf(" was %s cost=%-3d,%3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
- pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
+ pTo->rUnsorted, pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
@@ -131853,8 +149949,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
mxCost = aTo[0].rCost;
mxUnsorted = aTo[0].nRow;
for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){
- if( pTo->rCost>mxCost
- || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
+ if( pTo->rCost>mxCost
+ || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
){
mxCost = pTo->rCost;
mxUnsorted = pTo->rUnsorted;
@@ -131890,10 +149986,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( nFrom==0 ){
sqlite3ErrorMsg(pParse, "no query solution");
- sqlite3DbFree(db, pSpace);
+ sqlite3DbFreeNN(db, pSpace);
return SQLITE_ERROR;
}
-
+
/* Find the lowest cost path. pFrom will be left pointing to that path */
pFrom = aFrom;
for(ii=1; ii<nFrom; ii++){
@@ -131913,12 +150009,13 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
&& nRowEst
){
Bitmask notUsed;
- int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinctSet, pFrom,
+ int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
- if( rc==pWInfo->pDistinctSet->nExpr ){
+ if( rc==pWInfo->pResultSet->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}
+ pWInfo->bOrderedInnerLoop = 0;
if( pWInfo->pOrderBy ){
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
@@ -131931,7 +150028,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo->nOBSat = 0;
if( nLoop>0 ){
u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags;
- if( (wsFlags & WHERE_ONEROW)==0
+ if( (wsFlags & WHERE_ONEROW)==0
&& (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN)
){
Bitmask m = 0;
@@ -131945,13 +150042,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
}
}
+ }else if( nLoop
+ && pWInfo->nOBSat==1
+ && (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0
+ ){
+ pWInfo->bOrderedInnerLoop = 1;
}
}
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
){
Bitmask revMask = 0;
- int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
+ int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask
);
assert( pWInfo->sorted==0 );
@@ -131966,7 +150068,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
- sqlite3DbFree(db, pSpace);
+ sqlite3DbFreeNN(db, pSpace);
return SQLITE_OK;
}
@@ -131978,7 +150080,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** times for the common case.
**
** Return non-zero on success, if this query can be handled by this
-** no-frills query planner. Return zero if this query needs the
+** no-frills query planner. Return zero if this query needs the
** general-purpose query planner.
*/
static int whereShortCut(WhereLoopBuilder *pBuilder){
@@ -132018,8 +150120,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
int opMask;
assert( pLoop->aLTermSpace==pLoop->aLTerm );
if( !IsUniqueIndex(pIdx)
- || pIdx->pPartIdxWhere!=0
- || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
+ || pIdx->pPartIdxWhere!=0
+ || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue;
opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
for(j=0; j<pIdx->nKeyCol; j++){
@@ -132030,7 +150132,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
}
if( j!=pIdx->nKeyCol ) continue;
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED;
- if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){
+ if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){
pLoop->wsFlags |= WHERE_IDX_ONLY;
}
pLoop->nLTerm = j;
@@ -132044,7 +150146,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
if( pLoop->wsFlags ){
pLoop->nOut = (LogEst)1;
pWInfo->a[0].pWLoop = pLoop;
- pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
+ assert( pWInfo->sMaskSet.n==1 && iCur==pWInfo->sMaskSet.ix[0] );
+ pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
pWInfo->a[0].iTabCur = iCur;
pWInfo->nRowOut = 1;
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
@@ -132060,6 +150163,54 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
}
/*
+** Helper function for exprIsDeterministic().
+*/
+static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_FUNCTION && ExprHasProperty(pExpr, EP_ConstFunc)==0 ){
+ pWalker->eCode = 0;
+ return WRC_Abort;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Return true if the expression contains no non-deterministic SQL
+** functions. Do not consider non-deterministic SQL functions that are
+** part of sub-select statements.
+*/
+static int exprIsDeterministic(Expr *p){
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.eCode = 1;
+ w.xExprCallback = exprNodeIsDeterministic;
+ w.xSelectCallback = sqlite3SelectWalkFail;
+ sqlite3WalkExpr(&w, p);
+ return w.eCode;
+}
+
+
+#ifdef WHERETRACE_ENABLED
+/*
+** Display all WhereLoops in pWInfo
+*/
+static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
+ if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */
+ WhereLoop *p;
+ int i;
+ static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
+ "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
+ for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
+ p->cId = zLabel[i%(sizeof(zLabel)-1)];
+ sqlite3WhereLoopPrint(p, pWC);
+ }
+ }
+}
+# define WHERETRACE_ALL_LOOPS(W,C) showAllWhereLoops(W,C)
+#else
+# define WHERETRACE_ALL_LOOPS(W,C)
+#endif
+
+/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
@@ -132139,7 +150290,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
** if there is one. If there is no ORDER BY clause or if this routine
** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
**
-** The iIdxCur parameter is the cursor number of an index. If
+** The iIdxCur parameter is the cursor number of an index. If
** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index
** to use for OR clause processing. The WHERE clause should use this
** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is
@@ -132152,7 +150303,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
- ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */
+ ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
** If WHERE_USE_LIMIT, then the limit amount */
@@ -132172,8 +150323,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */
assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
- (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
- && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
+ (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
));
/* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */
@@ -132196,7 +150347,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
/* The number of tables in the FROM clause is limited by the number of
- ** bits in a Bitmask
+ ** bits in a Bitmask
*/
testcase( pTabList->nSrc==BMS );
if( pTabList->nSrc>BMS ){
@@ -132204,7 +150355,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
return 0;
}
- /* This function normally generates a nested loop for all tables in
+ /* This function normally generates a nested loop for all tables in
** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should
** only generate code for the first table in pTabList and assume that
** any cursors associated with subsequent tables are uninitialized.
@@ -132228,14 +150379,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
- pWInfo->pDistinctSet = pDistinctSet;
+ pWInfo->pWhere = pWhere;
+ pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
- pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
+ pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(pParse);
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
- memset(&pWInfo->nOBSat, 0,
+ memset(&pWInfo->nOBSat, 0,
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */
@@ -132255,17 +150407,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
initMaskSet(pMaskSet);
sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
-
- /* Special case: a WHERE clause that is constant. Evaluate the
- ** expression and either jump over all of the code or fall thru.
- */
- for(ii=0; ii<sWLB.pWC->nTerm; ii++){
- if( nTabList==0 || sqlite3ExprIsConstantNotJoin(sWLB.pWC->a[ii].pExpr) ){
- sqlite3ExprIfFalse(pParse, sWLB.pWC->a[ii].pExpr, pWInfo->iBreak,
- SQLITE_JUMPIFNULL);
- sWLB.pWC->a[ii].wtFlags |= TERM_CODED;
- }
- }
/* Special case: No FROM clause
*/
@@ -132274,45 +150415,71 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
+ ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
+ }else{
+ /* Assign a bit from the bitmask to every term in the FROM clause.
+ **
+ ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
+ **
+ ** The rule of the previous sentence ensures thta if X is the bitmask for
+ ** a table T, then X-1 is the bitmask for all other tables to the left of T.
+ ** Knowing the bitmask for all tables to the left of a left join is
+ ** important. Ticket #3015.
+ **
+ ** Note that bitmasks are created for all pTabList->nSrc tables in
+ ** pTabList, not just the first nTabList tables. nTabList is normally
+ ** equal to pTabList->nSrc but might be shortened to 1 if the
+ ** WHERE_OR_SUBCLAUSE flag is set.
+ */
+ ii = 0;
+ do{
+ createMask(pMaskSet, pTabList->a[ii].iCursor);
+ sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
+ }while( (++ii)<pTabList->nSrc );
+ #ifdef SQLITE_DEBUG
+ {
+ Bitmask mx = 0;
+ for(ii=0; ii<pTabList->nSrc; ii++){
+ Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
+ assert( m>=mx );
+ mx = m;
+ }
+ }
+ #endif
}
- /* Assign a bit from the bitmask to every term in the FROM clause.
- **
- ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
+ /* Analyze all of the subexpressions. */
+ sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
+ if( db->mallocFailed ) goto whereBeginError;
+
+ /* Special case: WHERE terms that do not refer to any tables in the join
+ ** (constant expressions). Evaluate each such term, and jump over all the
+ ** generated code if the result is not true.
**
- ** The rule of the previous sentence ensures thta if X is the bitmask for
- ** a table T, then X-1 is the bitmask for all other tables to the left of T.
- ** Knowing the bitmask for all tables to the left of a left join is
- ** important. Ticket #3015.
+ ** Do not do this if the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not strictly required, but
+ ** preserves SQLite's legacy behaviour in the following two cases:
**
- ** Note that bitmasks are created for all pTabList->nSrc tables in
- ** pTabList, not just the first nTabList tables. nTabList is normally
- ** equal to pTabList->nSrc but might be shortened to 1 if the
- ** WHERE_OR_SUBCLAUSE flag is set.
+ ** FROM ... WHERE random()>0; -- eval random() once per row
+ ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
*/
- for(ii=0; ii<pTabList->nSrc; ii++){
- createMask(pMaskSet, pTabList->a[ii].iCursor);
- sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
- }
-#ifdef SQLITE_DEBUG
- for(ii=0; ii<pTabList->nSrc; ii++){
- Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
- assert( m==MASKBIT(ii) );
+ for(ii=0; ii<sWLB.pWC->nTerm; ii++){
+ WhereTerm *pT = &sWLB.pWC->a[ii];
+ if( pT->wtFlags & TERM_VIRTUAL ) continue;
+ if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
+ sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pT->wtFlags |= TERM_CODED;
+ }
}
-#endif
-
- /* Analyze all of the subexpressions. */
- sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
- if( db->mallocFailed ) goto whereBeginError;
if( wctrlFlags & WHERE_WANT_DISTINCT ){
- if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pDistinctSet) ){
+ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
/* The DISTINCT marking is pointless. Ignore it. */
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}else if( pOrderBy==0 ){
/* Try to ORDER BY the result set to make distinct processing easier */
pWInfo->wctrlFlags |= WHERE_DISTINCTBY;
- pWInfo->pOrderBy = pDistinctSet;
+ pWInfo->pOrderBy = pResultSet;
}
}
@@ -132324,8 +150491,19 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3DebugPrintf(", limit: %d", iAuxArg);
}
sqlite3DebugPrintf(")\n");
+ if( sqlite3WhereTrace & 0x100 ){
+ Select sSelect;
+ memset(&sSelect, 0, sizeof(sSelect));
+ sSelect.selFlags = SF_WhereBegin;
+ sSelect.pSrc = pTabList;
+ sSelect.pWhere = pWhere;
+ sSelect.pOrderBy = pOrderBy;
+ sSelect.pEList = pResultSet;
+ sqlite3TreeViewSelect(0, &sSelect, 0);
+ }
}
if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
sqlite3WhereClausePrint(sWLB.pWC);
}
#endif
@@ -132333,20 +150511,29 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( nTabList!=1 || whereShortCut(&sWLB)==0 ){
rc = whereLoopAddAll(&sWLB);
if( rc ) goto whereBeginError;
-
-#ifdef WHERETRACE_ENABLED
- if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */
- WhereLoop *p;
- int i;
- static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
- "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
- for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
- p->cId = zLabel[i%sizeof(zLabel)];
- whereLoopPrint(p, sWLB.pWC);
- }
- }
-#endif
-
+
+#ifdef SQLITE_ENABLE_STAT4
+ /* If one or more WhereTerm.truthProb values were used in estimating
+ ** loop parameters, but then those truthProb values were subsequently
+ ** changed based on STAT4 information while computing subsequent loops,
+ ** then we need to rerun the whole loop building process so that all
+ ** loops will be built using the revised truthProb values. */
+ if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){
+ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
+ WHERETRACE(0xffff,
+ ("**** Redo all loop computations due to"
+ " TERM_HIGHTRUTH changes ****\n"));
+ while( pWInfo->pLoops ){
+ WhereLoop *p = pWInfo->pLoops;
+ pWInfo->pLoops = p->pNextLoop;
+ whereLoopDelete(db, p);
+ }
+ rc = whereLoopAddAll(&sWLB);
+ if( rc ) goto whereBeginError;
+ }
+#endif
+ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
+
wherePathSolver(pWInfo, 0);
if( db->mallocFailed ) goto whereBeginError;
if( pWInfo->pOrderBy ){
@@ -132382,57 +150569,126 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
sqlite3DebugPrintf("\n");
for(ii=0; ii<pWInfo->nLevel; ii++){
- whereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC);
+ sqlite3WhereLoopPrint(pWInfo->a[ii].pWLoop, sWLB.pWC);
}
}
#endif
- /* Attempt to omit tables from the join that do not effect the result */
+
+ /* Attempt to omit tables from the join that do not affect the result.
+ ** For a table to not affect the result, the following must be true:
+ **
+ ** 1) The query must not be an aggregate.
+ ** 2) The table must be the RHS of a LEFT JOIN.
+ ** 3) Either the query must be DISTINCT, or else the ON or USING clause
+ ** must contain a constraint that limits the scan of the table to
+ ** at most a single row.
+ ** 4) The table must not be referenced by any part of the query apart
+ ** from its own USING or ON clause.
+ **
+ ** For example, given:
+ **
+ ** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
+ ** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
+ ** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
+ **
+ ** then table t2 can be omitted from the following:
+ **
+ ** SELECT v1, v3 FROM t1
+ ** LEFT JOIN t2 ON (t1.ipk=t2.ipk)
+ ** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
+ **
+ ** or from:
+ **
+ ** SELECT DISTINCT v1, v3 FROM t1
+ ** LEFT JOIN t2
+ ** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
+ */
+ notReady = ~(Bitmask)0;
if( pWInfo->nLevel>=2
- && pDistinctSet!=0
+ && pResultSet!=0 /* guarantees condition (1) above */
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
){
- Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pDistinctSet);
+ int i;
+ Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
if( sWLB.pOrderBy ){
tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
}
- while( pWInfo->nLevel>=2 ){
+ for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd;
- pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
- if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
+ struct SrcList_item *pItem;
+ pLoop = pWInfo->a[i].pWLoop;
+ pItem = &pWInfo->pTabList->a[pLoop->iTab];
+ if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
&& (pLoop->wsFlags & WHERE_ONEROW)==0
){
- break;
+ continue;
}
- if( (tabUsed & pLoop->maskSelf)!=0 ) break;
+ if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
- if( (pTerm->prereqAll & pLoop->maskSelf)!=0
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
- ){
- break;
+ if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
+ if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+ || pTerm->pExpr->iRightJoinTable!=pItem->iCursor
+ ){
+ break;
+ }
}
}
- if( pTerm<pEnd ) break;
+ if( pTerm<pEnd ) continue;
WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
+ notReady &= ~pLoop->maskSelf;
+ for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
+ if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
+ pTerm->wtFlags |= TERM_CODED;
+ }
+ }
+ if( i!=pWInfo->nLevel-1 ){
+ int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
+ memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
+ }
pWInfo->nLevel--;
nTabList--;
}
}
+#if defined(WHERETRACE_ENABLED)
+ if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
+ sqlite3WhereClausePrint(sWLB.pWC);
+ }
WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
+#endif
pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
/* If the caller is an UPDATE or DELETE statement that is requesting
** to use a one-pass algorithm, determine if this is appropriate.
+ **
+ ** A one-pass approach can be used if the caller has requested one
+ ** and either (a) the scan visits at most one row or (b) each
+ ** of the following are true:
+ **
+ ** * the caller has indicated that a one-pass approach can be used
+ ** with multiple rows (by setting WHERE_ONEPASS_MULTIROW), and
+ ** * the table is not a virtual table, and
+ ** * either the scan does not use the OR optimization or the caller
+ ** is a DELETE operation (WHERE_DUPLICATES_OK is only specified
+ ** for DELETE).
+ **
+ ** The last qualification is because an UPDATE statement uses
+ ** WhereInfo.aiCurOnePass[1] to determine whether or not it really can
+ ** use a one-pass approach, and this is not set accurately for scans
+ ** that use the OR optimization.
*/
assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
- if( bOnerow
- || ((wctrlFlags & WHERE_ONEPASS_MULTIROW)!=0
- && 0==(wsFlags & WHERE_VIRTUALTABLE))
- ){
+ assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) );
+ if( bOnerow || (
+ 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
+ && !IsVirtual(pTabList->a[0].pTab)
+ && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
+ )){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){
@@ -132478,7 +150734,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
assert( pTabItem->iCursor==pLevel->iTabCur );
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 );
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
- if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){
+ if( pWInfo->eOnePass==ONEPASS_OFF
+ && pTab->nCol<BMS
+ && (pTab->tabFlags & (TF_HasGenerated|TF_WithoutRowid))==0
+ ){
+ /* If we know that only a prefix of the record will be used,
+ ** it is advantageous to reduce the "column count" field in
+ ** the P4 operand of the OP_OpenRead/Write opcode. */
Bitmask b = pTabItem->colUsed;
int n = 0;
for(; b; b=b>>1, n++){}
@@ -132504,7 +150766,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Index *pIx = pLoop->u.btree.pIndex;
int iIndexCur;
int op = OP_OpenRead;
- /* iAuxArg is always set if to a positive value if ONEPASS is possible */
+ /* iAuxArg is always set to a positive value if ONEPASS is possible */
assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
&& (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0
@@ -132537,9 +150799,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
+ && (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
+ && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
){
- sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
+ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);
}
VdbeComment((v, "%s", pIx->zName));
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
@@ -132568,7 +150832,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** loop below generates code for a single nested loop of the VM
** program.
*/
- notReady = ~(Bitmask)0;
for(ii=0; ii<nTabList; ii++){
int addrExplain;
int wsFlags;
@@ -132582,10 +150845,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
#endif
addrExplain = sqlite3WhereExplainOneScan(
- pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags
+ pParse, pTabList, pLevel, wctrlFlags
);
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
- notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady);
+ notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady);
pWInfo->iContinue = pLevel->addrCont;
if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){
sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain);
@@ -132606,7 +150869,27 @@ whereBeginError:
}
/*
-** Generate the end of the WHERE loop. See comments on
+** Part of sqlite3WhereEnd() will rewrite opcodes to reference the
+** index rather than the main table. In SQLITE_DEBUG mode, we want
+** to trace those changes if PRAGMA vdbe_addoptrace=on. This routine
+** does that.
+*/
+#ifndef SQLITE_DEBUG
+# define OpcodeRewriteTrace(D,K,P) /* no-op */
+#else
+# define OpcodeRewriteTrace(D,K,P) sqlite3WhereOpcodeRewriteTrace(D,K,P)
+ static void sqlite3WhereOpcodeRewriteTrace(
+ sqlite3 *db,
+ int pc,
+ VdbeOp *pOp
+ ){
+ if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
+ sqlite3VdbePrintOp(0, pc, pOp);
+ }
+#endif
+
+/*
+** Generate the end of the WHERE loop. See comments on
** sqlite3WhereBegin() for additional information.
*/
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
@@ -132621,19 +150904,53 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Generate loop termination code.
*/
VdbeModuleComment((v, "End WHERE-core"));
- sqlite3ExprCacheClear(pParse);
for(i=pWInfo->nLevel-1; i>=0; i--){
int addr;
pLevel = &pWInfo->a[i];
pLoop = pLevel->pWLoop;
- sqlite3VdbeResolveLabel(v, pLevel->addrCont);
if( pLevel->op!=OP_Noop ){
+#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ int addrSeek = 0;
+ Index *pIdx;
+ int n;
+ if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
+ && i==pWInfo->nLevel-1 /* Ticket [ef9318757b152e3] 2017-10-21 */
+ && (pLoop->wsFlags & WHERE_INDEXED)!=0
+ && (pIdx = pLoop->u.btree.pIndex)->hasStat1
+ && (n = pLoop->u.btree.nDistinctCol)>0
+ && pIdx->aiRowLogEst[n]>=36
+ ){
+ int r1 = pParse->nMem+1;
+ int j, op;
+ for(j=0; j<n; j++){
+ sqlite3VdbeAddOp3(v, OP_Column, pLevel->iIdxCur, j, r1+j);
+ }
+ pParse->nMem += n+1;
+ op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT;
+ addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n);
+ VdbeCoverageIf(v, op==OP_SeekLT);
+ VdbeCoverageIf(v, op==OP_SeekGT);
+ sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
+ }
+#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
+ /* The common case: Advance to the next row */
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
sqlite3VdbeChangeP5(v, pLevel->p5);
VdbeCoverage(v);
VdbeCoverageIf(v, pLevel->op==OP_Next);
VdbeCoverageIf(v, pLevel->op==OP_Prev);
VdbeCoverageIf(v, pLevel->op==OP_VNext);
+ if( pLevel->regBignull ){
+ sqlite3VdbeResolveLabel(v, pLevel->addrBignull);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, pLevel->regBignull, pLevel->p2-1);
+ VdbeCoverage(v);
+ }
+#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
+ if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
+#endif
+ }else{
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
}
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
struct InLoop *pIn;
@@ -132642,10 +150959,34 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
if( pIn->eEndLoopOp!=OP_Noop ){
+ if( pIn->nPrefix ){
+ assert( pLoop->wsFlags & WHERE_IN_EARLYOUT );
+ if( pLevel->iLeftJoin ){
+ /* For LEFT JOIN queries, cursor pIn->iCur may not have been
+ ** opened yet. This occurs for WHERE clauses such as
+ ** "a = ? AND b IN (...)", where the index is on (a, b). If
+ ** the RHS of the (a=?) is NULL, then the "b IN (...)" may
+ ** never have been coded, but the body of the loop run to
+ ** return the null-row. So, if the cursor is not open yet,
+ ** jump over the OP_Next or OP_Prev instruction about to
+ ** be coded. */
+ sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur,
+ sqlite3VdbeCurrentAddr(v) + 2 +
+ ((pLoop->wsFlags & WHERE_VIRTUALTABLE)==0)
+ );
+ VdbeCoverage(v);
+ }
+ if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
+ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
+ sqlite3VdbeCurrentAddr(v)+2,
+ pIn->iBase, pIn->nPrefix);
+ VdbeCoverage(v);
+ }
+ }
sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
VdbeCoverage(v);
- VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
- VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
+ VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev);
+ VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next);
}
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
}
@@ -132669,10 +151010,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
if( (ws & WHERE_IDX_ONLY)==0 ){
- sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
+ assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
+ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
}
- if( (ws & WHERE_INDEXED)
- || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)
+ if( (ws & WHERE_INDEXED)
+ || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)
){
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
}
@@ -132706,12 +151048,14 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
** the co-routine into OP_Copy of result contained in a register.
** OP_Rowid becomes OP_Null.
*/
- if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
- translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
+ if( pTabItem->fg.viaCoroutine ){
+ testcase( pParse->db->mallocFailed );
+ translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur,
pTabItem->regResult, 0);
continue;
}
+#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE
/* Close all of the cursors that were opened by sqlite3WhereBegin.
** Except, do not close cursors that will be reused by the OR optimization
** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors
@@ -132726,18 +151070,19 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( (ws & WHERE_INDEXED)!=0
- && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
+ && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
&& pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
){
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
}
+#endif
/* If this scan uses an index, make VDBE code substitutions to read data
** from the index instead of from the table where possible. In some cases
** this optimization prevents the table from ever being read, which can
** yield a significant performance boost.
- **
+ **
** Calls to the code generator in between sqlite3WhereBegin and
** sqlite3WhereEnd will have created code that references the table
** directly. This loop scans all that code looking for opcodes
@@ -132755,31 +151100,60 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
){
last = sqlite3VdbeCurrentAddr(v);
k = pLevel->addrBody;
+#ifdef SQLITE_DEBUG
+ if( db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+ }
+#endif
pOp = sqlite3VdbeGetOp(v, k);
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
- if( pOp->opcode==OP_Column ){
+ if( pOp->opcode==OP_Column
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
+ || pOp->opcode==OP_Offset
+#endif
+ ){
int x = pOp->p2;
assert( pIdx->pTable==pTab );
if( !HasRowid(pTab) ){
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
x = pPk->aiColumn[x];
assert( x>=0 );
+ }else{
+ testcase( x!=sqlite3StorageColumnToTable(pTab,x) );
+ x = sqlite3StorageColumnToTable(pTab,x);
}
- x = sqlite3ColumnOfIndex(pIdx, x);
+ x = sqlite3TableColumnToIndex(pIdx, x);
if( x>=0 ){
pOp->p2 = x;
pOp->p1 = pLevel->iIdxCur;
+ OpcodeRewriteTrace(db, k, pOp);
}
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 );
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0
+ || pWInfo->eOnePass );
}else if( pOp->opcode==OP_Rowid ){
pOp->p1 = pLevel->iIdxCur;
pOp->opcode = OP_IdxRowid;
+ OpcodeRewriteTrace(db, k, pOp);
+ }else if( pOp->opcode==OP_IfNullRow ){
+ pOp->p1 = pLevel->iIdxCur;
+ OpcodeRewriteTrace(db, k, pOp);
}
}
+#ifdef SQLITE_DEBUG
+ if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n");
+#endif
}
}
+ /* Undo all Expr node modifications */
+ while( pWInfo->pExprMods ){
+ WhereExprMod *p = pWInfo->pExprMods;
+ pWInfo->pExprMods = p->pNext;
+ memcpy(p->pExpr, &p->orig, sizeof(p->orig));
+ sqlite3DbFree(db, p);
+ }
+
/* Final cleanup
*/
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
@@ -132788,6 +151162,3051 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}
/************** End of where.c ***********************************************/
+/************** Begin file window.c ******************************************/
+/*
+** 2018 May 08
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+*/
+/* #include "sqliteInt.h" */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+
+/*
+** SELECT REWRITING
+**
+** Any SELECT statement that contains one or more window functions in
+** either the select list or ORDER BY clause (the only two places window
+** functions may be used) is transformed by function sqlite3WindowRewrite()
+** in order to support window function processing. For example, with the
+** schema:
+**
+** CREATE TABLE t1(a, b, c, d, e, f, g);
+**
+** the statement:
+**
+** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM t1 ORDER BY e;
+**
+** is transformed to:
+**
+** SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM (
+** SELECT a, e, c, d, b FROM t1 ORDER BY c, d
+** ) ORDER BY e;
+**
+** The flattening optimization is disabled when processing this transformed
+** SELECT statement. This allows the implementation of the window function
+** (in this case max()) to process rows sorted in order of (c, d), which
+** makes things easier for obvious reasons. More generally:
+**
+** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to
+** the sub-query.
+**
+** * ORDER BY, LIMIT and OFFSET remain part of the parent query.
+**
+** * Terminals from each of the expression trees that make up the
+** select-list and ORDER BY expressions in the parent query are
+** selected by the sub-query. For the purposes of the transformation,
+** terminals are column references and aggregate functions.
+**
+** If there is more than one window function in the SELECT that uses
+** the same window declaration (the OVER bit), then a single scan may
+** be used to process more than one window function. For example:
+**
+** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
+** min(e) OVER (PARTITION BY c ORDER BY d)
+** FROM t1;
+**
+** is transformed in the same way as the example above. However:
+**
+** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
+** min(e) OVER (PARTITION BY a ORDER BY b)
+** FROM t1;
+**
+** Must be transformed to:
+**
+** SELECT max(b) OVER (PARTITION BY c ORDER BY d) FROM (
+** SELECT e, min(e) OVER (PARTITION BY a ORDER BY b), c, d, b FROM
+** SELECT a, e, c, d, b FROM t1 ORDER BY a, b
+** ) ORDER BY c, d
+** ) ORDER BY e;
+**
+** so that both min() and max() may process rows in the order defined by
+** their respective window declarations.
+**
+** INTERFACE WITH SELECT.C
+**
+** When processing the rewritten SELECT statement, code in select.c calls
+** sqlite3WhereBegin() to begin iterating through the results of the
+** sub-query, which is always implemented as a co-routine. It then calls
+** sqlite3WindowCodeStep() to process rows and finish the scan by calling
+** sqlite3WhereEnd().
+**
+** sqlite3WindowCodeStep() generates VM code so that, for each row returned
+** by the sub-query a sub-routine (OP_Gosub) coded by select.c is invoked.
+** When the sub-routine is invoked:
+**
+** * The results of all window-functions for the row are stored
+** in the associated Window.regResult registers.
+**
+** * The required terminal values are stored in the current row of
+** temp table Window.iEphCsr.
+**
+** In some cases, depending on the window frame and the specific window
+** functions invoked, sqlite3WindowCodeStep() caches each entire partition
+** in a temp table before returning any rows. In other cases it does not.
+** This detail is encapsulated within this file, the code generated by
+** select.c is the same in either case.
+**
+** BUILT-IN WINDOW FUNCTIONS
+**
+** This implementation features the following built-in window functions:
+**
+** row_number()
+** rank()
+** dense_rank()
+** percent_rank()
+** cume_dist()
+** ntile(N)
+** lead(expr [, offset [, default]])
+** lag(expr [, offset [, default]])
+** first_value(expr)
+** last_value(expr)
+** nth_value(expr, N)
+**
+** These are the same built-in window functions supported by Postgres.
+** Although the behaviour of aggregate window functions (functions that
+** can be used as either aggregates or window funtions) allows them to
+** be implemented using an API, built-in window functions are much more
+** esoteric. Additionally, some window functions (e.g. nth_value())
+** may only be implemented by caching the entire partition in memory.
+** As such, some built-in window functions use the same API as aggregate
+** window functions and some are implemented directly using VDBE
+** instructions. Additionally, for those functions that use the API, the
+** window frame is sometimes modified before the SELECT statement is
+** rewritten. For example, regardless of the specified window frame, the
+** row_number() function always uses:
+**
+** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+**
+** See sqlite3WindowUpdate() for details.
+**
+** As well as some of the built-in window functions, aggregate window
+** functions min() and max() are implemented using VDBE instructions if
+** the start of the window frame is declared as anything other than
+** UNBOUNDED PRECEDING.
+*/
+
+/*
+** Implementation of built-in window function row_number(). Assumes that the
+** window frame has been coerced to:
+**
+** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+*/
+static void row_numberStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ) (*p)++;
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+}
+static void row_numberValueFunc(sqlite3_context *pCtx){
+ i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ sqlite3_result_int64(pCtx, (p ? *p : 0));
+}
+
+/*
+** Context object type used by rank(), dense_rank(), percent_rank() and
+** cume_dist().
+*/
+struct CallCount {
+ i64 nValue;
+ i64 nStep;
+ i64 nTotal;
+};
+
+/*
+** Implementation of built-in window function dense_rank(). Assumes that
+** the window frame has been set to:
+**
+** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+*/
+static void dense_rankStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct CallCount *p;
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ) p->nStep = 1;
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+}
+static void dense_rankValueFunc(sqlite3_context *pCtx){
+ struct CallCount *p;
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ if( p->nStep ){
+ p->nValue++;
+ p->nStep = 0;
+ }
+ sqlite3_result_int64(pCtx, p->nValue);
+ }
+}
+
+/*
+** Implementation of built-in window function nth_value(). This
+** implementation is used in "slow mode" only - when the EXCLUDE clause
+** is not set to the default value "NO OTHERS".
+*/
+struct NthValueCtx {
+ i64 nStep;
+ sqlite3_value *pValue;
+};
+static void nth_valueStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct NthValueCtx *p;
+ p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ i64 iVal;
+ switch( sqlite3_value_numeric_type(apArg[1]) ){
+ case SQLITE_INTEGER:
+ iVal = sqlite3_value_int64(apArg[1]);
+ break;
+ case SQLITE_FLOAT: {
+ double fVal = sqlite3_value_double(apArg[1]);
+ if( ((i64)fVal)!=fVal ) goto error_out;
+ iVal = (i64)fVal;
+ break;
+ }
+ default:
+ goto error_out;
+ }
+ if( iVal<=0 ) goto error_out;
+
+ p->nStep++;
+ if( iVal==p->nStep ){
+ p->pValue = sqlite3_value_dup(apArg[0]);
+ if( !p->pValue ){
+ sqlite3_result_error_nomem(pCtx);
+ }
+ }
+ }
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+ return;
+
+ error_out:
+ sqlite3_result_error(
+ pCtx, "second argument to nth_value must be a positive integer", -1
+ );
+}
+static void nth_valueFinalizeFunc(sqlite3_context *pCtx){
+ struct NthValueCtx *p;
+ p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, 0);
+ if( p && p->pValue ){
+ sqlite3_result_value(pCtx, p->pValue);
+ sqlite3_value_free(p->pValue);
+ p->pValue = 0;
+ }
+}
+#define nth_valueInvFunc noopStepFunc
+#define nth_valueValueFunc noopValueFunc
+
+static void first_valueStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct NthValueCtx *p;
+ p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p && p->pValue==0 ){
+ p->pValue = sqlite3_value_dup(apArg[0]);
+ if( !p->pValue ){
+ sqlite3_result_error_nomem(pCtx);
+ }
+ }
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+}
+static void first_valueFinalizeFunc(sqlite3_context *pCtx){
+ struct NthValueCtx *p;
+ p = (struct NthValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p && p->pValue ){
+ sqlite3_result_value(pCtx, p->pValue);
+ sqlite3_value_free(p->pValue);
+ p->pValue = 0;
+ }
+}
+#define first_valueInvFunc noopStepFunc
+#define first_valueValueFunc noopValueFunc
+
+/*
+** Implementation of built-in window function rank(). Assumes that
+** the window frame has been set to:
+**
+** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+*/
+static void rankStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct CallCount *p;
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ p->nStep++;
+ if( p->nValue==0 ){
+ p->nValue = p->nStep;
+ }
+ }
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+}
+static void rankValueFunc(sqlite3_context *pCtx){
+ struct CallCount *p;
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ sqlite3_result_int64(pCtx, p->nValue);
+ p->nValue = 0;
+ }
+}
+
+/*
+** Implementation of built-in window function percent_rank(). Assumes that
+** the window frame has been set to:
+**
+** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+*/
+static void percent_rankStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct CallCount *p;
+ UNUSED_PARAMETER(nArg); assert( nArg==0 );
+ UNUSED_PARAMETER(apArg);
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ p->nTotal++;
+ }
+}
+static void percent_rankInvFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct CallCount *p;
+ UNUSED_PARAMETER(nArg); assert( nArg==0 );
+ UNUSED_PARAMETER(apArg);
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ p->nStep++;
+}
+static void percent_rankValueFunc(sqlite3_context *pCtx){
+ struct CallCount *p;
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ p->nValue = p->nStep;
+ if( p->nTotal>1 ){
+ double r = (double)p->nValue / (double)(p->nTotal-1);
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_double(pCtx, 0.0);
+ }
+ }
+}
+#define percent_rankFinalizeFunc percent_rankValueFunc
+
+/*
+** Implementation of built-in window function cume_dist(). Assumes that
+** the window frame has been set to:
+**
+** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
+*/
+static void cume_distStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct CallCount *p;
+ UNUSED_PARAMETER(nArg); assert( nArg==0 );
+ UNUSED_PARAMETER(apArg);
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ p->nTotal++;
+ }
+}
+static void cume_distInvFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct CallCount *p;
+ UNUSED_PARAMETER(nArg); assert( nArg==0 );
+ UNUSED_PARAMETER(apArg);
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ p->nStep++;
+}
+static void cume_distValueFunc(sqlite3_context *pCtx){
+ struct CallCount *p;
+ p = (struct CallCount*)sqlite3_aggregate_context(pCtx, 0);
+ if( p ){
+ double r = (double)(p->nStep) / (double)(p->nTotal);
+ sqlite3_result_double(pCtx, r);
+ }
+}
+#define cume_distFinalizeFunc cume_distValueFunc
+
+/*
+** Context object for ntile() window function.
+*/
+struct NtileCtx {
+ i64 nTotal; /* Total rows in partition */
+ i64 nParam; /* Parameter passed to ntile(N) */
+ i64 iRow; /* Current row */
+};
+
+/*
+** Implementation of ntile(). This assumes that the window frame has
+** been coerced to:
+**
+** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING
+*/
+static void ntileStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct NtileCtx *p;
+ assert( nArg==1 ); UNUSED_PARAMETER(nArg);
+ p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ if( p->nTotal==0 ){
+ p->nParam = sqlite3_value_int64(apArg[0]);
+ if( p->nParam<=0 ){
+ sqlite3_result_error(
+ pCtx, "argument of ntile must be a positive integer", -1
+ );
+ }
+ }
+ p->nTotal++;
+ }
+}
+static void ntileInvFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct NtileCtx *p;
+ assert( nArg==1 ); UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+ p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ p->iRow++;
+}
+static void ntileValueFunc(sqlite3_context *pCtx){
+ struct NtileCtx *p;
+ p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p && p->nParam>0 ){
+ int nSize = (p->nTotal / p->nParam);
+ if( nSize==0 ){
+ sqlite3_result_int64(pCtx, p->iRow+1);
+ }else{
+ i64 nLarge = p->nTotal - p->nParam*nSize;
+ i64 iSmall = nLarge*(nSize+1);
+ i64 iRow = p->iRow;
+
+ assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal );
+
+ if( iRow<iSmall ){
+ sqlite3_result_int64(pCtx, 1 + iRow/(nSize+1));
+ }else{
+ sqlite3_result_int64(pCtx, 1 + nLarge + (iRow-iSmall)/nSize);
+ }
+ }
+ }
+}
+#define ntileFinalizeFunc ntileValueFunc
+
+/*
+** Context object for last_value() window function.
+*/
+struct LastValueCtx {
+ sqlite3_value *pVal;
+ int nVal;
+};
+
+/*
+** Implementation of last_value().
+*/
+static void last_valueStepFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct LastValueCtx *p;
+ UNUSED_PARAMETER(nArg);
+ p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p ){
+ sqlite3_value_free(p->pVal);
+ p->pVal = sqlite3_value_dup(apArg[0]);
+ if( p->pVal==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ p->nVal++;
+ }
+ }
+}
+static void last_valueInvFunc(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ struct LastValueCtx *p;
+ UNUSED_PARAMETER(nArg);
+ UNUSED_PARAMETER(apArg);
+ p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( ALWAYS(p) ){
+ p->nVal--;
+ if( p->nVal==0 ){
+ sqlite3_value_free(p->pVal);
+ p->pVal = 0;
+ }
+ }
+}
+static void last_valueValueFunc(sqlite3_context *pCtx){
+ struct LastValueCtx *p;
+ p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, 0);
+ if( p && p->pVal ){
+ sqlite3_result_value(pCtx, p->pVal);
+ }
+}
+static void last_valueFinalizeFunc(sqlite3_context *pCtx){
+ struct LastValueCtx *p;
+ p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+ if( p && p->pVal ){
+ sqlite3_result_value(pCtx, p->pVal);
+ sqlite3_value_free(p->pVal);
+ p->pVal = 0;
+ }
+}
+
+/*
+** Static names for the built-in window function names. These static
+** names are used, rather than string literals, so that FuncDef objects
+** can be associated with a particular window function by direct
+** comparison of the zName pointer. Example:
+**
+** if( pFuncDef->zName==row_valueName ){ ... }
+*/
+static const char row_numberName[] = "row_number";
+static const char dense_rankName[] = "dense_rank";
+static const char rankName[] = "rank";
+static const char percent_rankName[] = "percent_rank";
+static const char cume_distName[] = "cume_dist";
+static const char ntileName[] = "ntile";
+static const char last_valueName[] = "last_value";
+static const char nth_valueName[] = "nth_value";
+static const char first_valueName[] = "first_value";
+static const char leadName[] = "lead";
+static const char lagName[] = "lag";
+
+/*
+** No-op implementations of xStep() and xFinalize(). Used as place-holders
+** for built-in window functions that never call those interfaces.
+**
+** The noopValueFunc() is called but is expected to do nothing. The
+** noopStepFunc() is never called, and so it is marked with NO_TEST to
+** let the test coverage routine know not to expect this function to be
+** invoked.
+*/
+static void noopStepFunc( /*NO_TEST*/
+ sqlite3_context *p, /*NO_TEST*/
+ int n, /*NO_TEST*/
+ sqlite3_value **a /*NO_TEST*/
+){ /*NO_TEST*/
+ UNUSED_PARAMETER(p); /*NO_TEST*/
+ UNUSED_PARAMETER(n); /*NO_TEST*/
+ UNUSED_PARAMETER(a); /*NO_TEST*/
+ assert(0); /*NO_TEST*/
+} /*NO_TEST*/
+static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
+
+/* Window functions that use all window interfaces: xStep, xFinal,
+** xValue, and xInverse */
+#define WINDOWFUNCALL(name,nArg,extra) { \
+ nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
+ name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \
+ name ## InvFunc, name ## Name, {0} \
+}
+
+/* Window functions that are implemented using bytecode and thus have
+** no-op routines for their methods */
+#define WINDOWFUNCNOOP(name,nArg,extra) { \
+ nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
+ noopStepFunc, noopValueFunc, noopValueFunc, \
+ noopStepFunc, name ## Name, {0} \
+}
+
+/* Window functions that use all window interfaces: xStep, the
+** same routine for xFinalize and xValue and which never call
+** xInverse. */
+#define WINDOWFUNCX(name,nArg,extra) { \
+ nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
+ name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
+ noopStepFunc, name ## Name, {0} \
+}
+
+
+/*
+** Register those built-in window functions that are not also aggregates.
+*/
+SQLITE_PRIVATE void sqlite3WindowFunctions(void){
+ static FuncDef aWindowFuncs[] = {
+ WINDOWFUNCX(row_number, 0, 0),
+ WINDOWFUNCX(dense_rank, 0, 0),
+ WINDOWFUNCX(rank, 0, 0),
+ WINDOWFUNCALL(percent_rank, 0, 0),
+ WINDOWFUNCALL(cume_dist, 0, 0),
+ WINDOWFUNCALL(ntile, 1, 0),
+ WINDOWFUNCALL(last_value, 1, 0),
+ WINDOWFUNCALL(nth_value, 2, 0),
+ WINDOWFUNCALL(first_value, 1, 0),
+ WINDOWFUNCNOOP(lead, 1, 0),
+ WINDOWFUNCNOOP(lead, 2, 0),
+ WINDOWFUNCNOOP(lead, 3, 0),
+ WINDOWFUNCNOOP(lag, 1, 0),
+ WINDOWFUNCNOOP(lag, 2, 0),
+ WINDOWFUNCNOOP(lag, 3, 0),
+ };
+ sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs));
+}
+
+static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
+ Window *p;
+ for(p=pList; p; p=p->pNextWin){
+ if( sqlite3StrICmp(p->zName, zName)==0 ) break;
+ }
+ if( p==0 ){
+ sqlite3ErrorMsg(pParse, "no such window: %s", zName);
+ }
+ return p;
+}
+
+/*
+** This function is called immediately after resolving the function name
+** for a window function within a SELECT statement. Argument pList is a
+** linked list of WINDOW definitions for the current SELECT statement.
+** Argument pFunc is the function definition just resolved and pWin
+** is the Window object representing the associated OVER clause. This
+** function updates the contents of pWin as follows:
+**
+** * If the OVER clause refered to a named window (as in "max(x) OVER win"),
+** search list pList for a matching WINDOW definition, and update pWin
+** accordingly. If no such WINDOW clause can be found, leave an error
+** in pParse.
+**
+** * If the function is a built-in window function that requires the
+** window to be coerced (see "BUILT-IN WINDOW FUNCTIONS" at the top
+** of this file), pWin is updated here.
+*/
+SQLITE_PRIVATE void sqlite3WindowUpdate(
+ Parse *pParse,
+ Window *pList, /* List of named windows for this SELECT */
+ Window *pWin, /* Window frame to update */
+ FuncDef *pFunc /* Window function definition */
+){
+ if( pWin->zName && pWin->eFrmType==0 ){
+ Window *p = windowFind(pParse, pList, pWin->zName);
+ if( p==0 ) return;
+ pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0);
+ pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0);
+ pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0);
+ pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0);
+ pWin->eStart = p->eStart;
+ pWin->eEnd = p->eEnd;
+ pWin->eFrmType = p->eFrmType;
+ pWin->eExclude = p->eExclude;
+ }else{
+ sqlite3WindowChain(pParse, pWin, pList);
+ }
+ if( (pWin->eFrmType==TK_RANGE)
+ && (pWin->pStart || pWin->pEnd)
+ && (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1)
+ ){
+ sqlite3ErrorMsg(pParse,
+ "RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression"
+ );
+ }else
+ if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){
+ sqlite3 *db = pParse->db;
+ if( pWin->pFilter ){
+ sqlite3ErrorMsg(pParse,
+ "FILTER clause may only be used with aggregate window functions"
+ );
+ }else{
+ struct WindowUpdate {
+ const char *zFunc;
+ int eFrmType;
+ int eStart;
+ int eEnd;
+ } aUp[] = {
+ { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
+ { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
+ { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
+ { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED },
+ { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED },
+ { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED },
+ { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED },
+ { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
+ };
+ int i;
+ for(i=0; i<ArraySize(aUp); i++){
+ if( pFunc->zName==aUp[i].zFunc ){
+ sqlite3ExprDelete(db, pWin->pStart);
+ sqlite3ExprDelete(db, pWin->pEnd);
+ pWin->pEnd = pWin->pStart = 0;
+ pWin->eFrmType = aUp[i].eFrmType;
+ pWin->eStart = aUp[i].eStart;
+ pWin->eEnd = aUp[i].eEnd;
+ pWin->eExclude = 0;
+ if( pWin->eStart==TK_FOLLOWING ){
+ pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1");
+ }
+ break;
+ }
+ }
+ }
+ }
+ pWin->pFunc = pFunc;
+}
+
+/*
+** Context object passed through sqlite3WalkExprList() to
+** selectWindowRewriteExprCb() by selectWindowRewriteEList().
+*/
+typedef struct WindowRewrite WindowRewrite;
+struct WindowRewrite {
+ Window *pWin;
+ SrcList *pSrc;
+ ExprList *pSub;
+ Table *pTab;
+ Select *pSubSelect; /* Current sub-select, if any */
+};
+
+/*
+** Callback function used by selectWindowRewriteEList(). If necessary,
+** this function appends to the output expression-list and updates
+** expression (*ppExpr) in place.
+*/
+static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
+ struct WindowRewrite *p = pWalker->u.pRewrite;
+ Parse *pParse = pWalker->pParse;
+ assert( p!=0 );
+ assert( p->pWin!=0 );
+
+ /* If this function is being called from within a scalar sub-select
+ ** that used by the SELECT statement being processed, only process
+ ** TK_COLUMN expressions that refer to it (the outer SELECT). Do
+ ** not process aggregates or window functions at all, as they belong
+ ** to the scalar sub-select. */
+ if( p->pSubSelect ){
+ if( pExpr->op!=TK_COLUMN ){
+ return WRC_Continue;
+ }else{
+ int nSrc = p->pSrc->nSrc;
+ int i;
+ for(i=0; i<nSrc; i++){
+ if( pExpr->iTable==p->pSrc->a[i].iCursor ) break;
+ }
+ if( i==nSrc ) return WRC_Continue;
+ }
+ }
+
+ switch( pExpr->op ){
+
+ case TK_FUNCTION:
+ if( !ExprHasProperty(pExpr, EP_WinFunc) ){
+ break;
+ }else{
+ Window *pWin;
+ for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){
+ if( pExpr->y.pWin==pWin ){
+ assert( pWin->pOwner==pExpr );
+ return WRC_Prune;
+ }
+ }
+ }
+ /* no break */ deliberate_fall_through
+
+ case TK_AGG_FUNCTION:
+ case TK_COLUMN: {
+ int iCol = -1;
+ if( p->pSub ){
+ int i;
+ for(i=0; i<p->pSub->nExpr; i++){
+ if( 0==sqlite3ExprCompare(0, p->pSub->a[i].pExpr, pExpr, -1) ){
+ iCol = i;
+ break;
+ }
+ }
+ }
+ if( iCol<0 ){
+ Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0);
+ if( pDup && pDup->op==TK_AGG_FUNCTION ) pDup->op = TK_FUNCTION;
+ p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
+ }
+ if( p->pSub ){
+ int f = pExpr->flags & EP_Collate;
+ assert( ExprHasProperty(pExpr, EP_Static)==0 );
+ ExprSetProperty(pExpr, EP_Static);
+ sqlite3ExprDelete(pParse->db, pExpr);
+ ExprClearProperty(pExpr, EP_Static);
+ memset(pExpr, 0, sizeof(Expr));
+
+ pExpr->op = TK_COLUMN;
+ pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
+ pExpr->iTable = p->pWin->iEphCsr;
+ pExpr->y.pTab = p->pTab;
+ pExpr->flags = f;
+ }
+ if( pParse->db->mallocFailed ) return WRC_Abort;
+ break;
+ }
+
+ default: /* no-op */
+ break;
+ }
+
+ return WRC_Continue;
+}
+static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
+ struct WindowRewrite *p = pWalker->u.pRewrite;
+ Select *pSave = p->pSubSelect;
+ if( pSave==pSelect ){
+ return WRC_Continue;
+ }else{
+ p->pSubSelect = pSelect;
+ sqlite3WalkSelect(pWalker, pSelect);
+ p->pSubSelect = pSave;
+ }
+ return WRC_Prune;
+}
+
+
+/*
+** Iterate through each expression in expression-list pEList. For each:
+**
+** * TK_COLUMN,
+** * aggregate function, or
+** * window function with a Window object that is not a member of the
+** Window list passed as the second argument (pWin).
+**
+** Append the node to output expression-list (*ppSub). And replace it
+** with a TK_COLUMN that reads the (N-1)th element of table
+** pWin->iEphCsr, where N is the number of elements in (*ppSub) after
+** appending the new one.
+*/
+static void selectWindowRewriteEList(
+ Parse *pParse,
+ Window *pWin,
+ SrcList *pSrc,
+ ExprList *pEList, /* Rewrite expressions in this list */
+ Table *pTab,
+ ExprList **ppSub /* IN/OUT: Sub-select expression-list */
+){
+ Walker sWalker;
+ WindowRewrite sRewrite;
+
+ assert( pWin!=0 );
+ memset(&sWalker, 0, sizeof(Walker));
+ memset(&sRewrite, 0, sizeof(WindowRewrite));
+
+ sRewrite.pSub = *ppSub;
+ sRewrite.pWin = pWin;
+ sRewrite.pSrc = pSrc;
+ sRewrite.pTab = pTab;
+
+ sWalker.pParse = pParse;
+ sWalker.xExprCallback = selectWindowRewriteExprCb;
+ sWalker.xSelectCallback = selectWindowRewriteSelectCb;
+ sWalker.u.pRewrite = &sRewrite;
+
+ (void)sqlite3WalkExprList(&sWalker, pEList);
+
+ *ppSub = sRewrite.pSub;
+}
+
+/*
+** Append a copy of each expression in expression-list pAppend to
+** expression list pList. Return a pointer to the result list.
+*/
+static ExprList *exprListAppendList(
+ Parse *pParse, /* Parsing context */
+ ExprList *pList, /* List to which to append. Might be NULL */
+ ExprList *pAppend, /* List of values to append. Might be NULL */
+ int bIntToNull
+){
+ if( pAppend ){
+ int i;
+ int nInit = pList ? pList->nExpr : 0;
+ for(i=0; i<pAppend->nExpr; i++){
+ Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
+ assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
+ if( bIntToNull && pDup ){
+ int iDummy;
+ Expr *pSub;
+ for(pSub=pDup; ExprHasProperty(pSub, EP_Skip); pSub=pSub->pLeft){
+ assert( pSub );
+ }
+ if( sqlite3ExprIsInteger(pSub, &iDummy) ){
+ pSub->op = TK_NULL;
+ pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
+ pSub->u.zToken = 0;
+ }
+ }
+ pList = sqlite3ExprListAppend(pParse, pList, pDup);
+ if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
+ }
+ }
+ return pList;
+}
+
+/*
+** When rewriting a query, if the new subquery in the FROM clause
+** contains TK_AGG_FUNCTION nodes that refer to an outer query,
+** then we have to increase the Expr->op2 values of those nodes
+** due to the extra subquery layer that was added.
+**
+** See also the incrAggDepth() routine in resolve.c
+*/
+static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_AGG_FUNCTION
+ && pExpr->op2>=pWalker->walkerDepth
+ ){
+ pExpr->op2++;
+ }
+ return WRC_Continue;
+}
+
+/*
+** If the SELECT statement passed as the second argument does not invoke
+** any SQL window functions, this function is a no-op. Otherwise, it
+** rewrites the SELECT statement so that window function xStep functions
+** are invoked in the correct order as described under "SELECT REWRITING"
+** at the top of this file.
+*/
+SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
+ int rc = SQLITE_OK;
+ if( p->pWin && p->pPrior==0 && (p->selFlags & SF_WinRewrite)==0 ){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ sqlite3 *db = pParse->db;
+ Select *pSub = 0; /* The subquery */
+ SrcList *pSrc = p->pSrc;
+ Expr *pWhere = p->pWhere;
+ ExprList *pGroupBy = p->pGroupBy;
+ Expr *pHaving = p->pHaving;
+ ExprList *pSort = 0;
+
+ ExprList *pSublist = 0; /* Expression list for sub-query */
+ Window *pMWin = p->pWin; /* Main window object */
+ Window *pWin; /* Window object iterator */
+ Table *pTab;
+ Walker w;
+
+ u32 selFlags = p->selFlags;
+
+ pTab = sqlite3DbMallocZero(db, sizeof(Table));
+ if( pTab==0 ){
+ return sqlite3ErrorToParser(db, SQLITE_NOMEM);
+ }
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
+ sqlite3WalkSelect(&w, p);
+
+ p->pSrc = 0;
+ p->pWhere = 0;
+ p->pGroupBy = 0;
+ p->pHaving = 0;
+ p->selFlags &= ~SF_Aggregate;
+ p->selFlags |= SF_WinRewrite;
+
+ /* Create the ORDER BY clause for the sub-select. This is the concatenation
+ ** of the window PARTITION and ORDER BY clauses. Then, if this makes it
+ ** redundant, remove the ORDER BY from the parent SELECT. */
+ pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1);
+ pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1);
+ if( pSort && p->pOrderBy && p->pOrderBy->nExpr<=pSort->nExpr ){
+ int nSave = pSort->nExpr;
+ pSort->nExpr = p->pOrderBy->nExpr;
+ if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){
+ sqlite3ExprListDelete(db, p->pOrderBy);
+ p->pOrderBy = 0;
+ }
+ pSort->nExpr = nSave;
+ }
+
+ /* Assign a cursor number for the ephemeral table used to buffer rows.
+ ** The OpenEphemeral instruction is coded later, after it is known how
+ ** many columns the table will have. */
+ pMWin->iEphCsr = pParse->nTab++;
+ pParse->nTab += 3;
+
+ selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, pTab, &pSublist);
+ selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist);
+ pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
+
+ /* Append the PARTITION BY and ORDER BY expressions to the to the
+ ** sub-select expression list. They are required to figure out where
+ ** boundaries for partitions and sets of peer rows lie. */
+ pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0);
+ pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0);
+
+ /* Append the arguments passed to each window function to the
+ ** sub-select expression list. Also allocate two registers for each
+ ** window function - one for the accumulator, another for interim
+ ** results. */
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ ExprList *pArgs = pWin->pOwner->x.pList;
+ if( pWin->pFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
+ selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist);
+ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
+ pWin->bExprArgs = 1;
+ }else{
+ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
+ pSublist = exprListAppendList(pParse, pSublist, pArgs, 0);
+ }
+ if( pWin->pFilter ){
+ Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0);
+ pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter);
+ }
+ pWin->regAccum = ++pParse->nMem;
+ pWin->regResult = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+ }
+
+ /* If there is no ORDER BY or PARTITION BY clause, and the window
+ ** function accepts zero arguments, and there are no other columns
+ ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible
+ ** that pSublist is still NULL here. Add a constant expression here to
+ ** keep everything legal in this case.
+ */
+ if( pSublist==0 ){
+ pSublist = sqlite3ExprListAppend(pParse, 0,
+ sqlite3Expr(db, TK_INTEGER, "0")
+ );
+ }
+
+ pSub = sqlite3SelectNew(
+ pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
+ );
+ SELECTTRACE(1,pParse,pSub,
+ ("New window-function subquery in FROM clause of (%u/%p)\n",
+ p->selId, p));
+ p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( p->pSrc ){
+ Table *pTab2;
+ p->pSrc->a[0].pSelect = pSub;
+ sqlite3SrcListAssignCursors(pParse, p->pSrc);
+ pSub->selFlags |= SF_Expanded;
+ pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
+ pSub->selFlags |= (selFlags & SF_Aggregate);
+ if( pTab2==0 ){
+ /* Might actually be some other kind of error, but in that case
+ ** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
+ ** the correct error message regardless. */
+ rc = SQLITE_NOMEM;
+ }else{
+ memcpy(pTab, pTab2, sizeof(Table));
+ pTab->tabFlags |= TF_Ephemeral;
+ p->pSrc->a[0].pTab = pTab;
+ pTab = pTab2;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
+ sqlite3WalkSelect(&w, pSub);
+ }
+ }else{
+ sqlite3SelectDelete(db, pSub);
+ }
+ if( db->mallocFailed ) rc = SQLITE_NOMEM;
+ sqlite3DbFree(db, pTab);
+ }
+
+ if( rc ){
+ if( pParse->nErr==0 ){
+ assert( pParse->db->mallocFailed );
+ sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
+ }
+ }
+ return rc;
+}
+
+/*
+** Unlink the Window object from the Select to which it is attached,
+** if it is attached.
+*/
+SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window *p){
+ if( p->ppThis ){
+ *p->ppThis = p->pNextWin;
+ if( p->pNextWin ) p->pNextWin->ppThis = p->ppThis;
+ p->ppThis = 0;
+ }
+}
+
+/*
+** Free the Window object passed as the second argument.
+*/
+SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){
+ if( p ){
+ sqlite3WindowUnlinkFromSelect(p);
+ sqlite3ExprDelete(db, p->pFilter);
+ sqlite3ExprListDelete(db, p->pPartition);
+ sqlite3ExprListDelete(db, p->pOrderBy);
+ sqlite3ExprDelete(db, p->pEnd);
+ sqlite3ExprDelete(db, p->pStart);
+ sqlite3DbFree(db, p->zName);
+ sqlite3DbFree(db, p->zBase);
+ sqlite3DbFree(db, p);
+ }
+}
+
+/*
+** Free the linked list of Window objects starting at the second argument.
+*/
+SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){
+ while( p ){
+ Window *pNext = p->pNextWin;
+ sqlite3WindowDelete(db, p);
+ p = pNext;
+ }
+}
+
+/*
+** The argument expression is an PRECEDING or FOLLOWING offset. The
+** value should be a non-negative integer. If the value is not a
+** constant, change it to NULL. The fact that it is then a non-negative
+** integer will be caught later. But it is important not to leave
+** variable values in the expression tree.
+*/
+static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
+ if( 0==sqlite3ExprIsConstant(pExpr) ){
+ if( IN_RENAME_OBJECT ) sqlite3RenameExprUnmap(pParse, pExpr);
+ sqlite3ExprDelete(pParse->db, pExpr);
+ pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
+ }
+ return pExpr;
+}
+
+/*
+** Allocate and return a new Window object describing a Window Definition.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowAlloc(
+ Parse *pParse, /* Parsing context */
+ int eType, /* Frame type. TK_RANGE, TK_ROWS, TK_GROUPS, or 0 */
+ int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */
+ Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */
+ int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */
+ Expr *pEnd, /* End window size if TK_FOLLOWING or PRECEDING */
+ u8 eExclude /* EXCLUDE clause */
+){
+ Window *pWin = 0;
+ int bImplicitFrame = 0;
+
+ /* Parser assures the following: */
+ assert( eType==0 || eType==TK_RANGE || eType==TK_ROWS || eType==TK_GROUPS );
+ assert( eStart==TK_CURRENT || eStart==TK_PRECEDING
+ || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING );
+ assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING
+ || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING );
+ assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) );
+ assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) );
+
+ if( eType==0 ){
+ bImplicitFrame = 1;
+ eType = TK_RANGE;
+ }
+
+ /* Additionally, the
+ ** starting boundary type may not occur earlier in the following list than
+ ** the ending boundary type:
+ **
+ ** UNBOUNDED PRECEDING
+ ** <expr> PRECEDING
+ ** CURRENT ROW
+ ** <expr> FOLLOWING
+ ** UNBOUNDED FOLLOWING
+ **
+ ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending
+ ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting
+ ** frame boundary.
+ */
+ if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING)
+ || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT))
+ ){
+ sqlite3ErrorMsg(pParse, "unsupported frame specification");
+ goto windowAllocErr;
+ }
+
+ pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( pWin==0 ) goto windowAllocErr;
+ pWin->eFrmType = eType;
+ pWin->eStart = eStart;
+ pWin->eEnd = eEnd;
+ if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){
+ eExclude = TK_NO;
+ }
+ pWin->eExclude = eExclude;
+ pWin->bImplicitFrame = bImplicitFrame;
+ pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd);
+ pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart);
+ return pWin;
+
+windowAllocErr:
+ sqlite3ExprDelete(pParse->db, pEnd);
+ sqlite3ExprDelete(pParse->db, pStart);
+ return 0;
+}
+
+/*
+** Attach PARTITION and ORDER BY clauses pPartition and pOrderBy to window
+** pWin. Also, if parameter pBase is not NULL, set pWin->zBase to the
+** equivalent nul-terminated string.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowAssemble(
+ Parse *pParse,
+ Window *pWin,
+ ExprList *pPartition,
+ ExprList *pOrderBy,
+ Token *pBase
+){
+ if( pWin ){
+ pWin->pPartition = pPartition;
+ pWin->pOrderBy = pOrderBy;
+ if( pBase ){
+ pWin->zBase = sqlite3DbStrNDup(pParse->db, pBase->z, pBase->n);
+ }
+ }else{
+ sqlite3ExprListDelete(pParse->db, pPartition);
+ sqlite3ExprListDelete(pParse->db, pOrderBy);
+ }
+ return pWin;
+}
+
+/*
+** Window *pWin has just been created from a WINDOW clause. Tokne pBase
+** is the base window. Earlier windows from the same WINDOW clause are
+** stored in the linked list starting at pWin->pNextWin. This function
+** either updates *pWin according to the base specification, or else
+** leaves an error in pParse.
+*/
+SQLITE_PRIVATE void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pList){
+ if( pWin->zBase ){
+ sqlite3 *db = pParse->db;
+ Window *pExist = windowFind(pParse, pList, pWin->zBase);
+ if( pExist ){
+ const char *zErr = 0;
+ /* Check for errors */
+ if( pWin->pPartition ){
+ zErr = "PARTITION clause";
+ }else if( pExist->pOrderBy && pWin->pOrderBy ){
+ zErr = "ORDER BY clause";
+ }else if( pExist->bImplicitFrame==0 ){
+ zErr = "frame specification";
+ }
+ if( zErr ){
+ sqlite3ErrorMsg(pParse,
+ "cannot override %s of window: %s", zErr, pWin->zBase
+ );
+ }else{
+ pWin->pPartition = sqlite3ExprListDup(db, pExist->pPartition, 0);
+ if( pExist->pOrderBy ){
+ assert( pWin->pOrderBy==0 );
+ pWin->pOrderBy = sqlite3ExprListDup(db, pExist->pOrderBy, 0);
+ }
+ sqlite3DbFree(db, pWin->zBase);
+ pWin->zBase = 0;
+ }
+ }
+ }
+}
+
+/*
+** Attach window object pWin to expression p.
+*/
+SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
+ if( p ){
+ assert( p->op==TK_FUNCTION );
+ assert( pWin );
+ p->y.pWin = pWin;
+ ExprSetProperty(p, EP_WinFunc);
+ pWin->pOwner = p;
+ if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
+ sqlite3ErrorMsg(pParse,
+ "DISTINCT is not supported for window functions"
+ );
+ }
+ }else{
+ sqlite3WindowDelete(pParse->db, pWin);
+ }
+}
+
+/*
+** Possibly link window pWin into the list at pSel->pWin (window functions
+** to be processed as part of SELECT statement pSel). The window is linked
+** in if either (a) there are no other windows already linked to this
+** SELECT, or (b) the windows already linked use a compatible window frame.
+*/
+SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin){
+ if( pSel!=0
+ && (0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0))
+ ){
+ pWin->pNextWin = pSel->pWin;
+ if( pSel->pWin ){
+ pSel->pWin->ppThis = &pWin->pNextWin;
+ }
+ pSel->pWin = pWin;
+ pWin->ppThis = &pSel->pWin;
+ }
+}
+
+/*
+** Return 0 if the two window objects are identical, 1 if they are
+** different, or 2 if it cannot be determined if the objects are identical
+** or not. Identical window objects can be processed in a single scan.
+*/
+SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
+ int res;
+ if( NEVER(p1==0) || NEVER(p2==0) ) return 1;
+ if( p1->eFrmType!=p2->eFrmType ) return 1;
+ if( p1->eStart!=p2->eStart ) return 1;
+ if( p1->eEnd!=p2->eEnd ) return 1;
+ if( p1->eExclude!=p2->eExclude ) return 1;
+ if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
+ if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
+ if( (res = sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1)) ){
+ return res;
+ }
+ if( (res = sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1)) ){
+ return res;
+ }
+ if( bFilter ){
+ if( (res = sqlite3ExprCompare(pParse, p1->pFilter, p2->pFilter, -1)) ){
+ return res;
+ }
+ }
+ return 0;
+}
+
+
+/*
+** This is called by code in select.c before it calls sqlite3WhereBegin()
+** to begin iterating through the sub-query results. It is used to allocate
+** and initialize registers and cursors used by sqlite3WindowCodeStep().
+*/
+SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
+ int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr;
+ Window *pMWin = pSelect->pWin;
+ Window *pWin;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr);
+
+ /* Allocate registers to use for PARTITION BY values, if any. Initialize
+ ** said registers to NULL. */
+ if( pMWin->pPartition ){
+ int nExpr = pMWin->pPartition->nExpr;
+ pMWin->regPart = pParse->nMem+1;
+ pParse->nMem += nExpr;
+ sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nExpr-1);
+ }
+
+ pMWin->regOne = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regOne);
+
+ if( pMWin->eExclude ){
+ pMWin->regStartRowid = ++pParse->nMem;
+ pMWin->regEndRowid = ++pParse->nMem;
+ pMWin->csrApp = pParse->nTab++;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->csrApp, pMWin->iEphCsr);
+ return;
+ }
+
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ FuncDef *p = pWin->pFunc;
+ if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){
+ /* The inline versions of min() and max() require a single ephemeral
+ ** table and 3 registers. The registers are used as follows:
+ **
+ ** regApp+0: slot to copy min()/max() argument to for MakeRecord
+ ** regApp+1: integer value used to ensure keys are unique
+ ** regApp+2: output of MakeRecord
+ */
+ ExprList *pList = pWin->pOwner->x.pList;
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0);
+ pWin->csrApp = pParse->nTab++;
+ pWin->regApp = pParse->nMem+1;
+ pParse->nMem += 3;
+ if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){
+ assert( pKeyInfo->aSortFlags[0]==0 );
+ pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC;
+ }
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2);
+ sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
+ }
+ else if( p->zName==nth_valueName || p->zName==first_valueName ){
+ /* Allocate two registers at pWin->regApp. These will be used to
+ ** store the start and end index of the current frame. */
+ pWin->regApp = pParse->nMem+1;
+ pWin->csrApp = pParse->nTab++;
+ pParse->nMem += 2;
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
+ }
+ else if( p->zName==leadName || p->zName==lagName ){
+ pWin->csrApp = pParse->nTab++;
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
+ }
+ }
+}
+
+#define WINDOW_STARTING_INT 0
+#define WINDOW_ENDING_INT 1
+#define WINDOW_NTH_VALUE_INT 2
+#define WINDOW_STARTING_NUM 3
+#define WINDOW_ENDING_NUM 4
+
+/*
+** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the
+** value of the second argument to nth_value() (eCond==2) has just been
+** evaluated and the result left in register reg. This function generates VM
+** code to check that the value is a non-negative integer and throws an
+** exception if it is not.
+*/
+static void windowCheckValue(Parse *pParse, int reg, int eCond){
+ static const char *azErr[] = {
+ "frame starting offset must be a non-negative integer",
+ "frame ending offset must be a non-negative integer",
+ "second argument to nth_value must be a positive integer",
+ "frame starting offset must be a non-negative number",
+ "frame ending offset must be a non-negative number",
+ };
+ static int aOp[] = { OP_Ge, OP_Ge, OP_Gt, OP_Ge, OP_Ge };
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ int regZero = sqlite3GetTempReg(pParse);
+ assert( eCond>=0 && eCond<ArraySize(azErr) );
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
+ if( eCond>=WINDOW_STARTING_NUM ){
+ int regString = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC);
+ sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg);
+ sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL);
+ VdbeCoverage(v);
+ assert( eCond==3 || eCond==4 );
+ VdbeCoverageIf(v, eCond==3);
+ VdbeCoverageIf(v, eCond==4);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
+ VdbeCoverage(v);
+ assert( eCond==0 || eCond==1 || eCond==2 );
+ VdbeCoverageIf(v, eCond==0);
+ VdbeCoverageIf(v, eCond==1);
+ VdbeCoverageIf(v, eCond==2);
+ }
+ sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
+ VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */
+ VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */
+ VdbeCoverageNeverNullIf(v, eCond==2);
+ VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */
+ VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */
+ sqlite3MayAbort(pParse);
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
+ sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
+ sqlite3ReleaseTempReg(pParse, regZero);
+}
+
+/*
+** Return the number of arguments passed to the window-function associated
+** with the object passed as the only argument to this function.
+*/
+static int windowArgCount(Window *pWin){
+ ExprList *pList = pWin->pOwner->x.pList;
+ return (pList ? pList->nExpr : 0);
+}
+
+typedef struct WindowCodeArg WindowCodeArg;
+typedef struct WindowCsrAndReg WindowCsrAndReg;
+
+/*
+** See comments above struct WindowCodeArg.
+*/
+struct WindowCsrAndReg {
+ int csr; /* Cursor number */
+ int reg; /* First in array of peer values */
+};
+
+/*
+** A single instance of this structure is allocated on the stack by
+** sqlite3WindowCodeStep() and a pointer to it passed to the various helper
+** routines. This is to reduce the number of arguments required by each
+** helper function.
+**
+** regArg:
+** Each window function requires an accumulator register (just as an
+** ordinary aggregate function does). This variable is set to the first
+** in an array of accumulator registers - one for each window function
+** in the WindowCodeArg.pMWin list.
+**
+** eDelete:
+** The window functions implementation sometimes caches the input rows
+** that it processes in a temporary table. If it is not zero, this
+** variable indicates when rows may be removed from the temp table (in
+** order to reduce memory requirements - it would always be safe just
+** to leave them there). Possible values for eDelete are:
+**
+** WINDOW_RETURN_ROW:
+** An input row can be discarded after it is returned to the caller.
+**
+** WINDOW_AGGINVERSE:
+** An input row can be discarded after the window functions xInverse()
+** callbacks have been invoked in it.
+**
+** WINDOW_AGGSTEP:
+** An input row can be discarded after the window functions xStep()
+** callbacks have been invoked in it.
+**
+** start,current,end
+** Consider a window-frame similar to the following:
+**
+** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
+**
+** The windows functions implmentation caches the input rows in a temp
+** table, sorted by "a, b" (it actually populates the cache lazily, and
+** aggressively removes rows once they are no longer required, but that's
+** a mere detail). It keeps three cursors open on the temp table. One
+** (current) that points to the next row to return to the query engine
+** once its window function values have been calculated. Another (end)
+** points to the next row to call the xStep() method of each window function
+** on (so that it is 2 groups ahead of current). And a third (start) that
+** points to the next row to call the xInverse() method of each window
+** function on.
+**
+** Each cursor (start, current and end) consists of a VDBE cursor
+** (WindowCsrAndReg.csr) and an array of registers (starting at
+** WindowCodeArg.reg) that always contains a copy of the peer values
+** read from the corresponding cursor.
+**
+** Depending on the window-frame in question, all three cursors may not
+** be required. In this case both WindowCodeArg.csr and reg are set to
+** 0.
+*/
+struct WindowCodeArg {
+ Parse *pParse; /* Parse context */
+ Window *pMWin; /* First in list of functions being processed */
+ Vdbe *pVdbe; /* VDBE object */
+ int addrGosub; /* OP_Gosub to this address to return one row */
+ int regGosub; /* Register used with OP_Gosub(addrGosub) */
+ int regArg; /* First in array of accumulator registers */
+ int eDelete; /* See above */
+
+ WindowCsrAndReg start;
+ WindowCsrAndReg current;
+ WindowCsrAndReg end;
+};
+
+/*
+** Generate VM code to read the window frames peer values from cursor csr into
+** an array of registers starting at reg.
+*/
+static void windowReadPeerValues(
+ WindowCodeArg *p,
+ int csr,
+ int reg
+){
+ Window *pMWin = p->pMWin;
+ ExprList *pOrderBy = pMWin->pOrderBy;
+ if( pOrderBy ){
+ Vdbe *v = sqlite3GetVdbe(p->pParse);
+ ExprList *pPart = pMWin->pPartition;
+ int iColOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0);
+ int i;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ sqlite3VdbeAddOp3(v, OP_Column, csr, iColOff+i, reg+i);
+ }
+ }
+}
+
+/*
+** Generate VM code to invoke either xStep() (if bInverse is 0) or
+** xInverse (if bInverse is non-zero) for each window function in the
+** linked list starting at pMWin. Or, for built-in window functions
+** that do not use the standard function API, generate the required
+** inline VM code.
+**
+** If argument csr is greater than or equal to 0, then argument reg is
+** the first register in an array of registers guaranteed to be large
+** enough to hold the array of arguments for each function. In this case
+** the arguments are extracted from the current row of csr into the
+** array of registers before invoking OP_AggStep or OP_AggInverse
+**
+** Or, if csr is less than zero, then the array of registers at reg is
+** already populated with all columns from the current row of the sub-query.
+**
+** If argument regPartSize is non-zero, then it is a register containing the
+** number of rows in the current partition.
+*/
+static void windowAggStep(
+ WindowCodeArg *p,
+ Window *pMWin, /* Linked list of window functions */
+ int csr, /* Read arguments from this cursor */
+ int bInverse, /* True to invoke xInverse instead of xStep */
+ int reg /* Array of registers */
+){
+ Parse *pParse = p->pParse;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ Window *pWin;
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ FuncDef *pFunc = pWin->pFunc;
+ int regArg;
+ int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
+ int i;
+
+ assert( bInverse==0 || pWin->eStart!=TK_UNBOUNDED );
+
+ /* All OVER clauses in the same window function aggregate step must
+ ** be the same. */
+ assert( pWin==pMWin || sqlite3WindowCompare(pParse,pWin,pMWin,0)!=1 );
+
+ for(i=0; i<nArg; i++){
+ if( i!=1 || pFunc->zName!=nth_valueName ){
+ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+i, reg+i);
+ }
+ }
+ regArg = reg;
+
+ if( pMWin->regStartRowid==0
+ && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
+ && (pWin->eStart!=TK_UNBOUNDED)
+ ){
+ int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
+ VdbeCoverage(v);
+ if( bInverse==0 ){
+ sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1);
+ sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp);
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2);
+ }else{
+ sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1);
+ VdbeCoverageNeverTaken(v);
+ sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
+ sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+ }
+ sqlite3VdbeJumpHere(v, addrIsNull);
+ }else if( pWin->regApp ){
+ assert( pFunc->zName==nth_valueName
+ || pFunc->zName==first_valueName
+ );
+ assert( bInverse==0 || bInverse==1 );
+ sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
+ }else if( pFunc->xSFunc!=noopStepFunc ){
+ int addrIf = 0;
+ if( pWin->pFilter ){
+ int regTmp;
+ assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
+ assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
+ regTmp = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
+ addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
+ VdbeCoverage(v);
+ sqlite3ReleaseTempReg(pParse, regTmp);
+ }
+
+ if( pWin->bExprArgs ){
+ int iStart = sqlite3VdbeCurrentAddr(v);
+ VdbeOp *pOp, *pEnd;
+
+ nArg = pWin->pOwner->x.pList->nExpr;
+ regArg = sqlite3GetTempRange(pParse, nArg);
+ sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0);
+
+ pEnd = sqlite3VdbeGetOp(v, -1);
+ for(pOp=sqlite3VdbeGetOp(v, iStart); pOp<=pEnd; pOp++){
+ if( pOp->opcode==OP_Column && pOp->p1==pWin->iEphCsr ){
+ pOp->p1 = csr;
+ }
+ }
+ }
+ if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
+ CollSeq *pColl;
+ assert( nArg>0 );
+ pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr);
+ sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ);
+ }
+ sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
+ bInverse, regArg, pWin->regAccum);
+ sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nArg);
+ if( pWin->bExprArgs ){
+ sqlite3ReleaseTempRange(pParse, regArg, nArg);
+ }
+ if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
+ }
+ }
+}
+
+/*
+** Values that may be passed as the second argument to windowCodeOp().
+*/
+#define WINDOW_RETURN_ROW 1
+#define WINDOW_AGGINVERSE 2
+#define WINDOW_AGGSTEP 3
+
+/*
+** Generate VM code to invoke either xValue() (bFin==0) or xFinalize()
+** (bFin==1) for each window function in the linked list starting at
+** pMWin. Or, for built-in window-functions that do not use the standard
+** API, generate the equivalent VM code.
+*/
+static void windowAggFinal(WindowCodeArg *p, int bFin){
+ Parse *pParse = p->pParse;
+ Window *pMWin = p->pMWin;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ Window *pWin;
+
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ if( pMWin->regStartRowid==0
+ && (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX)
+ && (pWin->eStart!=TK_UNBOUNDED)
+ ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
+ sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult);
+ sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+ }else if( pWin->regApp ){
+ assert( pMWin->regStartRowid==0 );
+ }else{
+ int nArg = windowArgCount(pWin);
+ if( bFin ){
+ sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg);
+ sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+ sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult);
+ sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+ }
+ }
+ }
+}
+
+/*
+** Generate code to calculate the current values of all window functions in the
+** p->pMWin list by doing a full scan of the current window frame. Store the
+** results in the Window.regResult registers, ready to return the upper
+** layer.
+*/
+static void windowFullScan(WindowCodeArg *p){
+ Window *pWin;
+ Parse *pParse = p->pParse;
+ Window *pMWin = p->pMWin;
+ Vdbe *v = p->pVdbe;
+
+ int regCRowid = 0; /* Current rowid value */
+ int regCPeer = 0; /* Current peer values */
+ int regRowid = 0; /* AggStep rowid value */
+ int regPeer = 0; /* AggStep peer values */
+
+ int nPeer;
+ int lblNext;
+ int lblBrk;
+ int addrNext;
+ int csr;
+
+ VdbeModuleComment((v, "windowFullScan begin"));
+
+ assert( pMWin!=0 );
+ csr = pMWin->csrApp;
+ nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0);
+
+ lblNext = sqlite3VdbeMakeLabel(pParse);
+ lblBrk = sqlite3VdbeMakeLabel(pParse);
+
+ regCRowid = sqlite3GetTempReg(pParse);
+ regRowid = sqlite3GetTempReg(pParse);
+ if( nPeer ){
+ regCPeer = sqlite3GetTempRange(pParse, nPeer);
+ regPeer = sqlite3GetTempRange(pParse, nPeer);
+ }
+
+ sqlite3VdbeAddOp2(v, OP_Rowid, pMWin->iEphCsr, regCRowid);
+ windowReadPeerValues(p, pMWin->iEphCsr, regCPeer);
+
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+ }
+
+ sqlite3VdbeAddOp3(v, OP_SeekGE, csr, lblBrk, pMWin->regStartRowid);
+ VdbeCoverage(v);
+ addrNext = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Rowid, csr, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Gt, pMWin->regEndRowid, lblBrk, regRowid);
+ VdbeCoverageNeverNull(v);
+
+ if( pMWin->eExclude==TK_CURRENT ){
+ sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid);
+ VdbeCoverageNeverNull(v);
+ }else if( pMWin->eExclude!=TK_NO ){
+ int addr;
+ int addrEq = 0;
+ KeyInfo *pKeyInfo = 0;
+
+ if( pMWin->pOrderBy ){
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pMWin->pOrderBy, 0, 0);
+ }
+ if( pMWin->eExclude==TK_TIES ){
+ addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid);
+ VdbeCoverageNeverNull(v);
+ }
+ if( pKeyInfo ){
+ windowReadPeerValues(p, csr, regPeer);
+ sqlite3VdbeAddOp3(v, OP_Compare, regPeer, regCPeer, nPeer);
+ sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+ addr = sqlite3VdbeCurrentAddr(v)+1;
+ sqlite3VdbeAddOp3(v, OP_Jump, addr, lblNext, addr);
+ VdbeCoverageEqNe(v);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext);
+ }
+ if( addrEq ) sqlite3VdbeJumpHere(v, addrEq);
+ }
+
+ windowAggStep(p, pMWin, csr, 0, p->regArg);
+
+ sqlite3VdbeResolveLabel(v, lblNext);
+ sqlite3VdbeAddOp2(v, OP_Next, csr, addrNext);
+ VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, addrNext-1);
+ sqlite3VdbeJumpHere(v, addrNext+1);
+ sqlite3ReleaseTempReg(pParse, regRowid);
+ sqlite3ReleaseTempReg(pParse, regCRowid);
+ if( nPeer ){
+ sqlite3ReleaseTempRange(pParse, regPeer, nPeer);
+ sqlite3ReleaseTempRange(pParse, regCPeer, nPeer);
+ }
+
+ windowAggFinal(p, 1);
+ VdbeModuleComment((v, "windowFullScan end"));
+}
+
+/*
+** Invoke the sub-routine at regGosub (generated by code in select.c) to
+** return the current row of Window.iEphCsr. If all window functions are
+** aggregate window functions that use the standard API, a single
+** OP_Gosub instruction is all that this routine generates. Extra VM code
+** for per-row processing is only generated for the following built-in window
+** functions:
+**
+** nth_value()
+** first_value()
+** lag()
+** lead()
+*/
+static void windowReturnOneRow(WindowCodeArg *p){
+ Window *pMWin = p->pMWin;
+ Vdbe *v = p->pVdbe;
+
+ if( pMWin->regStartRowid ){
+ windowFullScan(p);
+ }else{
+ Parse *pParse = p->pParse;
+ Window *pWin;
+
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ FuncDef *pFunc = pWin->pFunc;
+ if( pFunc->zName==nth_valueName
+ || pFunc->zName==first_valueName
+ ){
+ int csr = pWin->csrApp;
+ int lbl = sqlite3VdbeMakeLabel(pParse);
+ int tmpReg = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
+
+ if( pFunc->zName==nth_valueName ){
+ sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg);
+ windowCheckValue(pParse, tmpReg, 2);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg);
+ }
+ sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg);
+ sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg);
+ VdbeCoverageNeverNull(v);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg);
+ VdbeCoverageNeverTaken(v);
+ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
+ sqlite3VdbeResolveLabel(v, lbl);
+ sqlite3ReleaseTempReg(pParse, tmpReg);
+ }
+ else if( pFunc->zName==leadName || pFunc->zName==lagName ){
+ int nArg = pWin->pOwner->x.pList->nExpr;
+ int csr = pWin->csrApp;
+ int lbl = sqlite3VdbeMakeLabel(pParse);
+ int tmpReg = sqlite3GetTempReg(pParse);
+ int iEph = pMWin->iEphCsr;
+
+ if( nArg<3 ){
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Column, iEph,pWin->iArgCol+2,pWin->regResult);
+ }
+ sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg);
+ if( nArg<2 ){
+ int val = (pFunc->zName==leadName ? 1 : -1);
+ sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val);
+ }else{
+ int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract);
+ int tmpReg2 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2);
+ sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg);
+ sqlite3ReleaseTempReg(pParse, tmpReg2);
+ }
+
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
+ sqlite3VdbeResolveLabel(v, lbl);
+ sqlite3ReleaseTempReg(pParse, tmpReg);
+ }
+ }
+ }
+ sqlite3VdbeAddOp2(v, OP_Gosub, p->regGosub, p->addrGosub);
+}
+
+/*
+** Generate code to set the accumulator register for each window function
+** in the linked list passed as the second argument to NULL. And perform
+** any equivalent initialization required by any built-in window functions
+** in the list.
+*/
+static int windowInitAccum(Parse *pParse, Window *pMWin){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ int regArg;
+ int nArg = 0;
+ Window *pWin;
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ FuncDef *pFunc = pWin->pFunc;
+ assert( pWin->regAccum );
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+ nArg = MAX(nArg, windowArgCount(pWin));
+ if( pMWin->regStartRowid==0 ){
+ if( pFunc->zName==nth_valueName || pFunc->zName==first_valueName ){
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
+ }
+
+ if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){
+ assert( pWin->eStart!=TK_UNBOUNDED );
+ sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
+ }
+ }
+ }
+ regArg = pParse->nMem+1;
+ pParse->nMem += nArg;
+ return regArg;
+}
+
+/*
+** Return true if the current frame should be cached in the ephemeral table,
+** even if there are no xInverse() calls required.
+*/
+static int windowCacheFrame(Window *pMWin){
+ Window *pWin;
+ if( pMWin->regStartRowid ) return 1;
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ FuncDef *pFunc = pWin->pFunc;
+ if( (pFunc->zName==nth_valueName)
+ || (pFunc->zName==first_valueName)
+ || (pFunc->zName==leadName)
+ || (pFunc->zName==lagName)
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** regOld and regNew are each the first register in an array of size
+** pOrderBy->nExpr. This function generates code to compare the two
+** arrays of registers using the collation sequences and other comparison
+** parameters specified by pOrderBy.
+**
+** If the two arrays are not equal, the contents of regNew is copied to
+** regOld and control falls through. Otherwise, if the contents of the arrays
+** are equal, an OP_Goto is executed. The address of the OP_Goto is returned.
+*/
+static void windowIfNewPeer(
+ Parse *pParse,
+ ExprList *pOrderBy,
+ int regNew, /* First in array of new values */
+ int regOld, /* First in array of old values */
+ int addr /* Jump here */
+){
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ if( pOrderBy ){
+ int nVal = pOrderBy->nExpr;
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
+ sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal);
+ sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+ sqlite3VdbeAddOp3(v, OP_Jump,
+ sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1
+ );
+ VdbeCoverageEqNe(v);
+ sqlite3VdbeAddOp3(v, OP_Copy, regNew, regOld, nVal-1);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
+ }
+}
+
+/*
+** This function is called as part of generating VM programs for RANGE
+** offset PRECEDING/FOLLOWING frame boundaries. Assuming "ASC" order for
+** the ORDER BY term in the window, and that argument op is OP_Ge, it generates
+** code equivalent to:
+**
+** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl;
+**
+** The value of parameter op may also be OP_Gt or OP_Le. In these cases the
+** operator in the above pseudo-code is replaced with ">" or "<=", respectively.
+**
+** If the sort-order for the ORDER BY term in the window is DESC, then the
+** comparison is reversed. Instead of adding regVal to csr1.peerVal, it is
+** subtracted. And the comparison operator is inverted to - ">=" becomes "<=",
+** ">" becomes "<", and so on. So, with DESC sort order, if the argument op
+** is OP_Ge, the generated code is equivalent to:
+**
+** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl;
+**
+** A special type of arithmetic is used such that if csr1.peerVal is not
+** a numeric type (real or integer), then the result of the addition addition
+** or subtraction is a a copy of csr1.peerVal.
+*/
+static void windowCodeRangeTest(
+ WindowCodeArg *p,
+ int op, /* OP_Ge, OP_Gt, or OP_Le */
+ int csr1, /* Cursor number for cursor 1 */
+ int regVal, /* Register containing non-negative number */
+ int csr2, /* Cursor number for cursor 2 */
+ int lbl /* Jump destination if condition is true */
+){
+ Parse *pParse = p->pParse;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ ExprList *pOrderBy = p->pMWin->pOrderBy; /* ORDER BY clause for window */
+ int reg1 = sqlite3GetTempReg(pParse); /* Reg. for csr1.peerVal+regVal */
+ int reg2 = sqlite3GetTempReg(pParse); /* Reg. for csr2.peerVal */
+ int regString = ++pParse->nMem; /* Reg. for constant value '' */
+ int arith = OP_Add; /* OP_Add or OP_Subtract */
+ int addrGe; /* Jump destination */
+
+ assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
+ assert( pOrderBy && pOrderBy->nExpr==1 );
+ if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){
+ switch( op ){
+ case OP_Ge: op = OP_Le; break;
+ case OP_Gt: op = OP_Lt; break;
+ default: assert( op==OP_Le ); op = OP_Ge; break;
+ }
+ arith = OP_Subtract;
+ }
+
+ /* Read the peer-value from each cursor into a register */
+ windowReadPeerValues(p, csr1, reg1);
+ windowReadPeerValues(p, csr2, reg2);
+
+ VdbeModuleComment((v, "CodeRangeTest: if( R%d %s R%d %s R%d ) goto lbl",
+ reg1, (arith==OP_Add ? "+" : "-"), regVal,
+ ((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2
+ ));
+
+ /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
+ ** This block adds (or subtracts for DESC) the numeric value in regVal
+ ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob),
+ ** then leave reg1 as it is. In pseudo-code, this is implemented as:
+ **
+ ** if( reg1>='' ) goto addrGe;
+ ** reg1 = reg1 +/- regVal
+ ** addrGe:
+ **
+ ** Since all strings and blobs are greater-than-or-equal-to an empty string,
+ ** the add/subtract is skipped for these, as required. If reg1 is a NULL,
+ ** then the arithmetic is performed, but since adding or subtracting from
+ ** NULL is always NULL anyway, this case is handled as required too. */
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC);
+ addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1);
+ sqlite3VdbeJumpHere(v, addrGe);
+
+ /* If the BIGNULL flag is set for the ORDER BY, then it is required to
+ ** consider NULL values to be larger than all other values, instead of
+ ** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this
+ ** (and adding that capability causes a performance regression), so
+ ** instead if the BIGNULL flag is set then cases where either reg1 or
+ ** reg2 are NULL are handled separately in the following block. The code
+ ** generated is equivalent to:
+ **
+ ** if( reg1 IS NULL ){
+ ** if( op==OP_Ge ) goto lbl;
+ ** if( op==OP_Gt && reg2 IS NOT NULL ) goto lbl;
+ ** if( op==OP_Le && reg2 IS NULL ) goto lbl;
+ ** }else if( reg2 IS NULL ){
+ ** if( op==OP_Le ) goto lbl;
+ ** }
+ **
+ ** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
+ ** not taken, control jumps over the comparison operator coded below this
+ ** block. */
+ if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){
+ /* This block runs if reg1 contains a NULL. */
+ int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
+ switch( op ){
+ case OP_Ge:
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl);
+ break;
+ case OP_Gt:
+ sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
+ VdbeCoverage(v);
+ break;
+ case OP_Le:
+ sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
+ VdbeCoverage(v);
+ break;
+ default: assert( op==OP_Lt ); /* no-op */ break;
+ }
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
+
+ /* This block runs if reg1 is not NULL, but reg2 is. */
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
+ if( op==OP_Gt || op==OP_Ge ){
+ sqlite3VdbeChangeP2(v, -1, sqlite3VdbeCurrentAddr(v)+1);
+ }
+ }
+
+ /* Compare registers reg2 and reg1, taking the jump if required. Note that
+ ** control skips over this test if the BIGNULL flag is set and either
+ ** reg1 or reg2 contain a NULL value. */
+ sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
+
+ assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le );
+ testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge);
+ testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt);
+ testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le);
+ testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt);
+ sqlite3ReleaseTempReg(pParse, reg1);
+ sqlite3ReleaseTempReg(pParse, reg2);
+
+ VdbeModuleComment((v, "CodeRangeTest: end"));
+}
+
+/*
+** Helper function for sqlite3WindowCodeStep(). Each call to this function
+** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
+** operation. Refer to the header comment for sqlite3WindowCodeStep() for
+** details.
+*/
+static int windowCodeOp(
+ WindowCodeArg *p, /* Context object */
+ int op, /* WINDOW_RETURN_ROW, AGGSTEP or AGGINVERSE */
+ int regCountdown, /* Register for OP_IfPos countdown */
+ int jumpOnEof /* Jump here if stepped cursor reaches EOF */
+){
+ int csr, reg;
+ Parse *pParse = p->pParse;
+ Window *pMWin = p->pMWin;
+ int ret = 0;
+ Vdbe *v = p->pVdbe;
+ int addrContinue = 0;
+ int bPeer = (pMWin->eFrmType!=TK_ROWS);
+
+ int lblDone = sqlite3VdbeMakeLabel(pParse);
+ int addrNextRange = 0;
+
+ /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame
+ ** starts with UNBOUNDED PRECEDING. */
+ if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){
+ assert( regCountdown==0 && jumpOnEof==0 );
+ return 0;
+ }
+
+ if( regCountdown>0 ){
+ if( pMWin->eFrmType==TK_RANGE ){
+ addrNextRange = sqlite3VdbeCurrentAddr(v);
+ assert( op==WINDOW_AGGINVERSE || op==WINDOW_AGGSTEP );
+ if( op==WINDOW_AGGINVERSE ){
+ if( pMWin->eStart==TK_FOLLOWING ){
+ windowCodeRangeTest(
+ p, OP_Le, p->current.csr, regCountdown, p->start.csr, lblDone
+ );
+ }else{
+ windowCodeRangeTest(
+ p, OP_Ge, p->start.csr, regCountdown, p->current.csr, lblDone
+ );
+ }
+ }else{
+ windowCodeRangeTest(
+ p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone
+ );
+ }
+ }else{
+ sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, lblDone, 1);
+ VdbeCoverage(v);
+ }
+ }
+
+ if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){
+ windowAggFinal(p, 0);
+ }
+ addrContinue = sqlite3VdbeCurrentAddr(v);
+
+ /* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or
+ ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
+ ** start cursor does not advance past the end cursor within the
+ ** temporary table. It otherwise might, if (a>b). */
+ if( pMWin->eStart==pMWin->eEnd && regCountdown
+ && pMWin->eFrmType==TK_RANGE && op==WINDOW_AGGINVERSE
+ ){
+ int regRowid1 = sqlite3GetTempReg(pParse);
+ int regRowid2 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1);
+ sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2);
+ sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1);
+ VdbeCoverage(v);
+ sqlite3ReleaseTempReg(pParse, regRowid1);
+ sqlite3ReleaseTempReg(pParse, regRowid2);
+ assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING );
+ }
+
+ switch( op ){
+ case WINDOW_RETURN_ROW:
+ csr = p->current.csr;
+ reg = p->current.reg;
+ windowReturnOneRow(p);
+ break;
+
+ case WINDOW_AGGINVERSE:
+ csr = p->start.csr;
+ reg = p->start.reg;
+ if( pMWin->regStartRowid ){
+ assert( pMWin->regEndRowid );
+ sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regStartRowid, 1);
+ }else{
+ windowAggStep(p, pMWin, csr, 1, p->regArg);
+ }
+ break;
+
+ default:
+ assert( op==WINDOW_AGGSTEP );
+ csr = p->end.csr;
+ reg = p->end.reg;
+ if( pMWin->regStartRowid ){
+ assert( pMWin->regEndRowid );
+ sqlite3VdbeAddOp2(v, OP_AddImm, pMWin->regEndRowid, 1);
+ }else{
+ windowAggStep(p, pMWin, csr, 0, p->regArg);
+ }
+ break;
+ }
+
+ if( op==p->eDelete ){
+ sqlite3VdbeAddOp1(v, OP_Delete, csr);
+ sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
+ }
+
+ if( jumpOnEof ){
+ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2);
+ VdbeCoverage(v);
+ ret = sqlite3VdbeAddOp0(v, OP_Goto);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1+bPeer);
+ VdbeCoverage(v);
+ if( bPeer ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblDone);
+ }
+ }
+
+ if( bPeer ){
+ int nReg = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0);
+ int regTmp = (nReg ? sqlite3GetTempRange(pParse, nReg) : 0);
+ windowReadPeerValues(p, csr, regTmp);
+ windowIfNewPeer(pParse, pMWin->pOrderBy, regTmp, reg, addrContinue);
+ sqlite3ReleaseTempRange(pParse, regTmp, nReg);
+ }
+
+ if( addrNextRange ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNextRange);
+ }
+ sqlite3VdbeResolveLabel(v, lblDone);
+ return ret;
+}
+
+
+/*
+** Allocate and return a duplicate of the Window object indicated by the
+** third argument. Set the Window.pOwner field of the new object to
+** pOwner.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
+ Window *pNew = 0;
+ if( ALWAYS(p) ){
+ pNew = sqlite3DbMallocZero(db, sizeof(Window));
+ if( pNew ){
+ pNew->zName = sqlite3DbStrDup(db, p->zName);
+ pNew->zBase = sqlite3DbStrDup(db, p->zBase);
+ pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0);
+ pNew->pFunc = p->pFunc;
+ pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
+ pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
+ pNew->eFrmType = p->eFrmType;
+ pNew->eEnd = p->eEnd;
+ pNew->eStart = p->eStart;
+ pNew->eExclude = p->eExclude;
+ pNew->regResult = p->regResult;
+ pNew->regAccum = p->regAccum;
+ pNew->iArgCol = p->iArgCol;
+ pNew->iEphCsr = p->iEphCsr;
+ pNew->bExprArgs = p->bExprArgs;
+ pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
+ pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
+ pNew->pOwner = pOwner;
+ pNew->bImplicitFrame = p->bImplicitFrame;
+ }
+ }
+ return pNew;
+}
+
+/*
+** Return a copy of the linked list of Window objects passed as the
+** second argument.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){
+ Window *pWin;
+ Window *pRet = 0;
+ Window **pp = &pRet;
+
+ for(pWin=p; pWin; pWin=pWin->pNextWin){
+ *pp = sqlite3WindowDup(db, 0, pWin);
+ if( *pp==0 ) break;
+ pp = &((*pp)->pNextWin);
+ }
+
+ return pRet;
+}
+
+/*
+** Return true if it can be determined at compile time that expression
+** pExpr evaluates to a value that, when cast to an integer, is greater
+** than zero. False otherwise.
+**
+** If an OOM error occurs, this function sets the Parse.db.mallocFailed
+** flag and returns zero.
+*/
+static int windowExprGtZero(Parse *pParse, Expr *pExpr){
+ int ret = 0;
+ sqlite3 *db = pParse->db;
+ sqlite3_value *pVal = 0;
+ sqlite3ValueFromExpr(db, pExpr, db->enc, SQLITE_AFF_NUMERIC, &pVal);
+ if( pVal && sqlite3_value_int(pVal)>0 ){
+ ret = 1;
+ }
+ sqlite3ValueFree(pVal);
+ return ret;
+}
+
+/*
+** sqlite3WhereBegin() has already been called for the SELECT statement
+** passed as the second argument when this function is invoked. It generates
+** code to populate the Window.regResult register for each window function
+** and invoke the sub-routine at instruction addrGosub once for each row.
+** sqlite3WhereEnd() is always called before returning.
+**
+** This function handles several different types of window frames, which
+** require slightly different processing. The following pseudo code is
+** used to implement window frames of the form:
+**
+** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
+**
+** Other window frame types use variants of the following:
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+**
+** if( first row of partition ){
+** // Rewind three cursors, all open on the eph table.
+** Rewind(csrEnd);
+** Rewind(csrStart);
+** Rewind(csrCurrent);
+**
+** regEnd = <expr2> // FOLLOWING expression
+** regStart = <expr1> // PRECEDING expression
+** }else{
+** // First time this branch is taken, the eph table contains two
+** // rows. The first row in the partition, which all three cursors
+** // currently point to, and the following row.
+** AGGSTEP
+** if( (regEnd--)<=0 ){
+** RETURN_ROW
+** if( (regStart--)<=0 ){
+** AGGINVERSE
+** }
+** }
+** }
+** }
+** flush:
+** AGGSTEP
+** while( 1 ){
+** RETURN ROW
+** if( csrCurrent is EOF ) break;
+** if( (regStart--)<=0 ){
+** AggInverse(csrStart)
+** Next(csrStart)
+** }
+** }
+**
+** The pseudo-code above uses the following shorthand:
+**
+** AGGSTEP: invoke the aggregate xStep() function for each window function
+** with arguments read from the current row of cursor csrEnd, then
+** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()).
+**
+** RETURN_ROW: return a row to the caller based on the contents of the
+** current row of csrCurrent and the current state of all
+** aggregates. Then step cursor csrCurrent forward one row.
+**
+** AGGINVERSE: invoke the aggregate xInverse() function for each window
+** functions with arguments read from the current row of cursor
+** csrStart. Then step csrStart forward one row.
+**
+** There are two other ROWS window frames that are handled significantly
+** differently from the above - "BETWEEN <expr> PRECEDING AND <expr> PRECEDING"
+** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special
+** cases because they change the order in which the three cursors (csrStart,
+** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that
+** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these
+** three.
+**
+** ROWS BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = <expr1>
+** }else{
+** if( (regEnd--)<=0 ){
+** AGGSTEP
+** }
+** RETURN_ROW
+** if( (regStart--)<=0 ){
+** AGGINVERSE
+** }
+** }
+** }
+** flush:
+** if( (regEnd--)<=0 ){
+** AGGSTEP
+** }
+** RETURN_ROW
+**
+**
+** ROWS BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = regEnd - <expr1>
+** }else{
+** AGGSTEP
+** if( (regEnd--)<=0 ){
+** RETURN_ROW
+** }
+** if( (regStart--)<=0 ){
+** AGGINVERSE
+** }
+** }
+** }
+** flush:
+** AGGSTEP
+** while( 1 ){
+** if( (regEnd--)<=0 ){
+** RETURN_ROW
+** if( eof ) break;
+** }
+** if( (regStart--)<=0 ){
+** AGGINVERSE
+** if( eof ) break
+** }
+** }
+** while( !eof csrCurrent ){
+** RETURN_ROW
+** }
+**
+** For the most part, the patterns above are adapted to support UNBOUNDED by
+** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and
+** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING".
+** This is optimized of course - branches that will never be taken and
+** conditions that are always true are omitted from the VM code. The only
+** exceptional case is:
+**
+** ROWS BETWEEN <expr1> FOLLOWING AND UNBOUNDED FOLLOWING
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regStart = <expr1>
+** }else{
+** AGGSTEP
+** }
+** }
+** flush:
+** AGGSTEP
+** while( 1 ){
+** if( (regStart--)<=0 ){
+** AGGINVERSE
+** if( eof ) break
+** }
+** RETURN_ROW
+** }
+** while( !eof csrCurrent ){
+** RETURN_ROW
+** }
+**
+** Also requiring special handling are the cases:
+**
+** ROWS BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING
+** ROWS BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING
+**
+** when (expr1 < expr2). This is detected at runtime, not by this function.
+** To handle this case, the pseudo-code programs depicted above are modified
+** slightly to be:
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = <expr1>
+** if( regEnd < regStart ){
+** RETURN_ROW
+** delete eph table contents
+** continue
+** }
+** ...
+**
+** The new "continue" statement in the above jumps to the next iteration
+** of the outer loop - the one started by sqlite3WhereBegin().
+**
+** The various GROUPS cases are implemented using the same patterns as
+** ROWS. The VM code is modified slightly so that:
+**
+** 1. The else branch in the main loop is only taken if the row just
+** added to the ephemeral table is the start of a new group. In
+** other words, it becomes:
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = <expr1>
+** }else if( new group ){
+** ...
+** }
+** }
+**
+** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or
+** AGGINVERSE step processes the current row of the relevant cursor and
+** all subsequent rows belonging to the same group.
+**
+** RANGE window frames are a little different again. As for GROUPS, the
+** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE
+** deal in groups instead of rows. As for ROWS and GROUPS, there are three
+** basic cases:
+**
+** RANGE BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = <expr1>
+** }else{
+** AGGSTEP
+** while( (csrCurrent.key + regEnd) < csrEnd.key ){
+** RETURN_ROW
+** while( csrStart.key + regStart) < csrCurrent.key ){
+** AGGINVERSE
+** }
+** }
+** }
+** }
+** flush:
+** AGGSTEP
+** while( 1 ){
+** RETURN ROW
+** if( csrCurrent is EOF ) break;
+** while( csrStart.key + regStart) < csrCurrent.key ){
+** AGGINVERSE
+** }
+** }
+** }
+**
+** In the above notation, "csr.key" means the current value of the ORDER BY
+** expression (there is only ever 1 for a RANGE that uses an <expr> FOLLOWING
+** or <expr PRECEDING) read from cursor csr.
+**
+** RANGE BETWEEN <expr1> PRECEDING AND <expr2> PRECEDING
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = <expr1>
+** }else{
+** while( (csrEnd.key + regEnd) <= csrCurrent.key ){
+** AGGSTEP
+** }
+** while( (csrStart.key + regStart) < csrCurrent.key ){
+** AGGINVERSE
+** }
+** RETURN_ROW
+** }
+** }
+** flush:
+** while( (csrEnd.key + regEnd) <= csrCurrent.key ){
+** AGGSTEP
+** }
+** while( (csrStart.key + regStart) < csrCurrent.key ){
+** AGGINVERSE
+** }
+** RETURN_ROW
+**
+** RANGE BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING
+**
+** ... loop started by sqlite3WhereBegin() ...
+** if( new partition ){
+** Gosub flush
+** }
+** Insert new row into eph table.
+** if( first row of partition ){
+** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent)
+** regEnd = <expr2>
+** regStart = <expr1>
+** }else{
+** AGGSTEP
+** while( (csrCurrent.key + regEnd) < csrEnd.key ){
+** while( (csrCurrent.key + regStart) > csrStart.key ){
+** AGGINVERSE
+** }
+** RETURN_ROW
+** }
+** }
+** }
+** flush:
+** AGGSTEP
+** while( 1 ){
+** while( (csrCurrent.key + regStart) > csrStart.key ){
+** AGGINVERSE
+** if( eof ) break "while( 1 )" loop.
+** }
+** RETURN_ROW
+** }
+** while( !eof csrCurrent ){
+** RETURN_ROW
+** }
+**
+** The text above leaves out many details. Refer to the code and comments
+** below for a more complete picture.
+*/
+SQLITE_PRIVATE void sqlite3WindowCodeStep(
+ Parse *pParse, /* Parse context */
+ Select *p, /* Rewritten SELECT statement */
+ WhereInfo *pWInfo, /* Context returned by sqlite3WhereBegin() */
+ int regGosub, /* Register for OP_Gosub */
+ int addrGosub /* OP_Gosub here to return each row */
+){
+ Window *pMWin = p->pWin;
+ ExprList *pOrderBy = pMWin->pOrderBy;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ int csrWrite; /* Cursor used to write to eph. table */
+ int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
+ int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */
+ int iInput; /* To iterate through sub cols */
+ int addrNe; /* Address of OP_Ne */
+ int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */
+ int addrInteger = 0; /* Address of OP_Integer */
+ int addrEmpty; /* Address of OP_Rewind in flush: */
+ int regNew; /* Array of registers holding new input row */
+ int regRecord; /* regNew array in record form */
+ int regRowid; /* Rowid for regRecord in eph table */
+ int regNewPeer = 0; /* Peer values for new row (part of regNew) */
+ int regPeer = 0; /* Peer values for current row */
+ int regFlushPart = 0; /* Register for "Gosub flush_partition" */
+ WindowCodeArg s; /* Context object for sub-routines */
+ int lblWhereEnd; /* Label just before sqlite3WhereEnd() code */
+ int regStart = 0; /* Value of <expr> PRECEDING */
+ int regEnd = 0; /* Value of <expr> FOLLOWING */
+
+ assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT
+ || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED
+ );
+ assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT
+ || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING
+ );
+ assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT
+ || pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES
+ || pMWin->eExclude==TK_NO
+ );
+
+ lblWhereEnd = sqlite3VdbeMakeLabel(pParse);
+
+ /* Fill in the context object */
+ memset(&s, 0, sizeof(WindowCodeArg));
+ s.pParse = pParse;
+ s.pMWin = pMWin;
+ s.pVdbe = v;
+ s.regGosub = regGosub;
+ s.addrGosub = addrGosub;
+ s.current.csr = pMWin->iEphCsr;
+ csrWrite = s.current.csr+1;
+ s.start.csr = s.current.csr+2;
+ s.end.csr = s.current.csr+3;
+
+ /* Figure out when rows may be deleted from the ephemeral table. There
+ ** are four options - they may never be deleted (eDelete==0), they may
+ ** be deleted as soon as they are no longer part of the window frame
+ ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row
+ ** has been returned to the caller (WINDOW_RETURN_ROW), or they may
+ ** be deleted after they enter the frame (WINDOW_AGGSTEP). */
+ switch( pMWin->eStart ){
+ case TK_FOLLOWING:
+ if( pMWin->eFrmType!=TK_RANGE
+ && windowExprGtZero(pParse, pMWin->pStart)
+ ){
+ s.eDelete = WINDOW_RETURN_ROW;
+ }
+ break;
+ case TK_UNBOUNDED:
+ if( windowCacheFrame(pMWin)==0 ){
+ if( pMWin->eEnd==TK_PRECEDING ){
+ if( pMWin->eFrmType!=TK_RANGE
+ && windowExprGtZero(pParse, pMWin->pEnd)
+ ){
+ s.eDelete = WINDOW_AGGSTEP;
+ }
+ }else{
+ s.eDelete = WINDOW_RETURN_ROW;
+ }
+ }
+ break;
+ default:
+ s.eDelete = WINDOW_AGGINVERSE;
+ break;
+ }
+
+ /* Allocate registers for the array of values from the sub-query, the
+ ** samve values in record form, and the rowid used to insert said record
+ ** into the ephemeral table. */
+ regNew = pParse->nMem+1;
+ pParse->nMem += nInput;
+ regRecord = ++pParse->nMem;
+ regRowid = ++pParse->nMem;
+
+ /* If the window frame contains an "<expr> PRECEDING" or "<expr> FOLLOWING"
+ ** clause, allocate registers to store the results of evaluating each
+ ** <expr>. */
+ if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){
+ regStart = ++pParse->nMem;
+ }
+ if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){
+ regEnd = ++pParse->nMem;
+ }
+
+ /* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of
+ ** registers to store copies of the ORDER BY expressions (peer values)
+ ** for the main loop, and for each cursor (start, current and end). */
+ if( pMWin->eFrmType!=TK_ROWS ){
+ int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
+ regNewPeer = regNew + pMWin->nBufferCol;
+ if( pMWin->pPartition ) regNewPeer += pMWin->pPartition->nExpr;
+ regPeer = pParse->nMem+1; pParse->nMem += nPeer;
+ s.start.reg = pParse->nMem+1; pParse->nMem += nPeer;
+ s.current.reg = pParse->nMem+1; pParse->nMem += nPeer;
+ s.end.reg = pParse->nMem+1; pParse->nMem += nPeer;
+ }
+
+ /* Load the column values for the row returned by the sub-select
+ ** into an array of registers starting at regNew. Assemble them into
+ ** a record in register regRecord. */
+ for(iInput=0; iInput<nInput; iInput++){
+ sqlite3VdbeAddOp3(v, OP_Column, csrInput, iInput, regNew+iInput);
+ }
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, nInput, regRecord);
+
+ /* An input row has just been read into an array of registers starting
+ ** at regNew. If the window has a PARTITION clause, this block generates
+ ** VM code to check if the input row is the start of a new partition.
+ ** If so, it does an OP_Gosub to an address to be filled in later. The
+ ** address of the OP_Gosub is stored in local variable addrGosubFlush. */
+ if( pMWin->pPartition ){
+ int addr;
+ ExprList *pPart = pMWin->pPartition;
+ int nPart = pPart->nExpr;
+ int regNewPart = regNew + pMWin->nBufferCol;
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
+
+ regFlushPart = ++pParse->nMem;
+ addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart, nPart);
+ sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+ sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
+ VdbeCoverageEqNe(v);
+ addrGosubFlush = sqlite3VdbeAddOp1(v, OP_Gosub, regFlushPart);
+ VdbeComment((v, "call flush_partition"));
+ sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1);
+ }
+
+ /* Insert the new row into the ephemeral table */
+ sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid);
+ addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, regRowid);
+ VdbeCoverageNeverNull(v);
+
+ /* This block is run for the first row of each partition */
+ s.regArg = windowInitAccum(pParse, pMWin);
+
+ if( regStart ){
+ sqlite3ExprCode(pParse, pMWin->pStart, regStart);
+ windowCheckValue(pParse, regStart, 0 + (pMWin->eFrmType==TK_RANGE?3:0));
+ }
+ if( regEnd ){
+ sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
+ windowCheckValue(pParse, regEnd, 1 + (pMWin->eFrmType==TK_RANGE?3:0));
+ }
+
+ if( pMWin->eFrmType!=TK_RANGE && pMWin->eStart==pMWin->eEnd && regStart ){
+ int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
+ int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
+ VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */
+ VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */
+ windowAggFinal(&s, 0);
+ sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
+ VdbeCoverageNeverTaken(v);
+ windowReturnOneRow(&s);
+ sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
+ sqlite3VdbeJumpHere(v, addrGe);
+ }
+ if( pMWin->eStart==TK_FOLLOWING && pMWin->eFrmType!=TK_RANGE && regEnd ){
+ assert( pMWin->eEnd==TK_FOLLOWING );
+ sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart);
+ }
+
+ if( pMWin->eStart!=TK_UNBOUNDED ){
+ sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1);
+ VdbeCoverageNeverTaken(v);
+ }
+ sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
+ VdbeCoverageNeverTaken(v);
+ sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1);
+ VdbeCoverageNeverTaken(v);
+ if( regPeer && pOrderBy ){
+ sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1);
+ sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1);
+ sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.current.reg, pOrderBy->nExpr-1);
+ sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.end.reg, pOrderBy->nExpr-1);
+ }
+
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
+
+ sqlite3VdbeJumpHere(v, addrNe);
+
+ /* Beginning of the block executed for the second and subsequent rows. */
+ if( regPeer ){
+ windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd);
+ }
+ if( pMWin->eStart==TK_FOLLOWING ){
+ windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
+ if( pMWin->eEnd!=TK_UNBOUNDED ){
+ if( pMWin->eFrmType==TK_RANGE ){
+ int lbl = sqlite3VdbeMakeLabel(pParse);
+ int addrNext = sqlite3VdbeCurrentAddr(v);
+ windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl);
+ windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
+ sqlite3VdbeResolveLabel(v, lbl);
+ }else{
+ windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 0);
+ windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ }
+ }
+ }else
+ if( pMWin->eEnd==TK_PRECEDING ){
+ int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE);
+ windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0);
+ if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
+ if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ }else{
+ int addr = 0;
+ windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
+ if( pMWin->eEnd!=TK_UNBOUNDED ){
+ if( pMWin->eFrmType==TK_RANGE ){
+ int lbl = 0;
+ addr = sqlite3VdbeCurrentAddr(v);
+ if( regEnd ){
+ lbl = sqlite3VdbeMakeLabel(pParse);
+ windowCodeRangeTest(&s, OP_Ge, s.current.csr, regEnd, s.end.csr, lbl);
+ }
+ windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
+ windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ if( regEnd ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
+ sqlite3VdbeResolveLabel(v, lbl);
+ }
+ }else{
+ if( regEnd ){
+ addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
+ VdbeCoverage(v);
+ }
+ windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
+ windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ if( regEnd ) sqlite3VdbeJumpHere(v, addr);
+ }
+ }
+ }
+
+ /* End of the main input loop */
+ sqlite3VdbeResolveLabel(v, lblWhereEnd);
+ sqlite3WhereEnd(pWInfo);
+
+ /* Fall through */
+ if( pMWin->pPartition ){
+ addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart);
+ sqlite3VdbeJumpHere(v, addrGosubFlush);
+ }
+
+ addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite);
+ VdbeCoverage(v);
+ if( pMWin->eEnd==TK_PRECEDING ){
+ int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE);
+ windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0);
+ if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
+ }else if( pMWin->eStart==TK_FOLLOWING ){
+ int addrStart;
+ int addrBreak1;
+ int addrBreak2;
+ int addrBreak3;
+ windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
+ if( pMWin->eFrmType==TK_RANGE ){
+ addrStart = sqlite3VdbeCurrentAddr(v);
+ addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1);
+ addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1);
+ }else
+ if( pMWin->eEnd==TK_UNBOUNDED ){
+ addrStart = sqlite3VdbeCurrentAddr(v);
+ addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regStart, 1);
+ addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, 0, 1);
+ }else{
+ assert( pMWin->eEnd==TK_FOLLOWING );
+ addrStart = sqlite3VdbeCurrentAddr(v);
+ addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, regEnd, 1);
+ addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 1);
+ }
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart);
+ sqlite3VdbeJumpHere(v, addrBreak2);
+ addrStart = sqlite3VdbeCurrentAddr(v);
+ addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart);
+ sqlite3VdbeJumpHere(v, addrBreak1);
+ sqlite3VdbeJumpHere(v, addrBreak3);
+ }else{
+ int addrBreak;
+ int addrStart;
+ windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
+ addrStart = sqlite3VdbeCurrentAddr(v);
+ addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 1);
+ windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart);
+ sqlite3VdbeJumpHere(v, addrBreak);
+ }
+ sqlite3VdbeJumpHere(v, addrEmpty);
+
+ sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr);
+ if( pMWin->pPartition ){
+ if( pMWin->regStartRowid ){
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regStartRowid);
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regEndRowid);
+ }
+ sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v));
+ sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
+ }
+}
+
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
+/************** End of window.c **********************************************/
/************** Begin file parse.c *******************************************/
/*
** 2000-05-29
@@ -132814,6 +154233,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
** input grammar file:
*/
/* #include <stdio.h> */
+/* #include <assert.h> */
/************ Begin %include sections from the grammar ************************/
/* #include "sqliteInt.h" */
@@ -132836,19 +154256,23 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
#define YYPARSEFREENEVERNULL 1
/*
-** Alternative datatype for the argument to the malloc() routine passed
-** into sqlite3ParserAlloc(). The default is size_t.
+** In the amalgamation, the parse.c file generated by lemon and the
+** tokenize.c file are concatenated. In that case, sqlite3RunParser()
+** has access to the the size of the yyParser object and so the parser
+** engine can be allocated from stack. In that case, only the
+** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked
+** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be
+** omitted.
*/
-#define YYMALLOCARGTYPE u64
+#ifdef SQLITE_AMALGAMATION
+# define sqlite3Parser_ENGINEALWAYSONSTACK 1
+#endif
/*
-** An instance of this structure holds information about the
-** LIMIT clause of a SELECT statement.
+** Alternative datatype for the argument to the malloc() routine passed
+** into sqlite3ParserAlloc(). The default is size_t.
*/
-struct LimitVal {
- Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */
- Expr *pOffset; /* The OFFSET expression. NULL if there is none */
-};
+#define YYMALLOCARGTYPE u64
/*
** An instance of the following structure describes the event of a
@@ -132861,14 +154285,38 @@ struct LimitVal {
*/
struct TrigEvent { int a; IdList * b; };
+struct FrameBound { int eType; Expr *pExpr; };
+
/*
** Disable lookaside memory allocation for objects that might be
** shared across database connections.
*/
static void disableLookaside(Parse *pParse){
+ sqlite3 *db = pParse->db;
pParse->disableLookaside++;
- pParse->db->lookaside.bDisable++;
+ DisableLookaside;
+}
+
+#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \
+ && defined(SQLITE_UDL_CAPABLE_PARSER)
+/*
+** Issue an error message if an ORDER BY or LIMIT clause occurs on an
+** UPDATE or DELETE statement.
+*/
+static void updateDeleteLimitError(
+ Parse *pParse,
+ ExprList *pOrderBy,
+ Expr *pLimit
+){
+ if( pOrderBy ){
+ sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\"");
+ }else{
+ sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\"");
+ }
+ sqlite3ExprListDelete(pParse->db, pOrderBy);
+ sqlite3ExprDelete(pParse->db, pLimit);
}
+#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */
/*
@@ -132877,6 +154325,7 @@ static void disableLookaside(Parse *pParse){
** SQLITE_LIMIT_COMPOUND_SELECT.
*/
static void parserDoubleLinkSelect(Parse *pParse, Select *p){
+ assert( p!=0 );
if( p->pPrior ){
Select *pNext = 0, *pLoop;
int mxSelect, cnt = 0;
@@ -132884,7 +154333,7 @@ static void disableLookaside(Parse *pParse){
pLoop->pNext = pNext;
pLoop->selFlags |= SF_Compound;
}
- if( (p->selFlags & SF_MultiValue)==0 &&
+ if( (p->selFlags & SF_MultiValue)==0 &&
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
cnt>mxSelect
){
@@ -132893,101 +154342,55 @@ static void disableLookaside(Parse *pParse){
}
}
- /* This is a utility routine used to set the ExprSpan.zStart and
- ** ExprSpan.zEnd values of pOut so that the span covers the complete
- ** range of text beginning with pStart and going to the end of pEnd.
- */
- static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
- pOut->zStart = pStart->z;
- pOut->zEnd = &pEnd->z[pEnd->n];
- }
/* Construct a new Expr object from a single identifier. Use the
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
- static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
+ static Expr *tokenExpr(Parse *pParse, int op, Token t){
Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
if( p ){
- memset(p, 0, sizeof(Expr));
+ /* memset(p, 0, sizeof(Expr)); */
p->op = (u8)op;
+ p->affExpr = 0;
p->flags = EP_Leaf;
+ ExprClearVVAProperties(p);
p->iAgg = -1;
+ p->pLeft = p->pRight = 0;
+ p->x.pList = 0;
+ p->pAggInfo = 0;
+ p->y.pTab = 0;
+ p->op2 = 0;
+ p->iTable = 0;
+ p->iColumn = 0;
p->u.zToken = (char*)&p[1];
memcpy(p->u.zToken, t.z, t.n);
p->u.zToken[t.n] = 0;
if( sqlite3Isquote(p->u.zToken[0]) ){
- if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted;
- sqlite3Dequote(p->u.zToken);
+ sqlite3DequoteExpr(p);
}
#if SQLITE_MAX_EXPR_DEPTH>0
p->nHeight = 1;
-#endif
- }
- pOut->pExpr = p;
- pOut->zStart = t.z;
- pOut->zEnd = &t.z[t.n];
- }
-
- /* This routine constructs a binary expression node out of two ExprSpan
- ** objects and uses the result to populate a new ExprSpan object.
- */
- static void spanBinaryExpr(
- Parse *pParse, /* The parsing context. Errors accumulate here */
- int op, /* The binary operation */
- ExprSpan *pLeft, /* The left operand, and output */
- ExprSpan *pRight /* The right operand */
- ){
- pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
- pLeft->zEnd = pRight->zEnd;
- }
-
- /* If doNot is true, then add a TK_NOT Expr-node wrapper around the
- ** outside of *ppExpr.
- */
- static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){
- if( doNot ){
- pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0, 0);
+#endif
+ if( IN_RENAME_OBJECT ){
+ return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t);
+ }
}
+ return p;
}
- /* Construct an expression node for a unary postfix operator
- */
- static void spanUnaryPostfix(
- Parse *pParse, /* Parsing context to record errors */
- int op, /* The operator */
- ExprSpan *pOperand, /* The operand, and output */
- Token *pPostOp /* The operand token for setting the span */
- ){
- pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
- pOperand->zEnd = &pPostOp->z[pPostOp->n];
- }
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a
** unary TK_ISNULL or TK_NOTNULL expression. */
static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){
sqlite3 *db = pParse->db;
- if( pA && pY && pY->op==TK_NULL ){
+ if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){
pA->op = (u8)op;
sqlite3ExprDelete(db, pA->pRight);
pA->pRight = 0;
}
}
- /* Construct an expression node for a unary prefix operator
- */
- static void spanUnaryPrefix(
- ExprSpan *pOut, /* Write the new expression node here */
- Parse *pParse, /* Parsing context to record errors */
- int op, /* The operator */
- ExprSpan *pOperand, /* The operand */
- Token *pPreOp /* The operand token for setting the span */
- ){
- pOut->zStart = pPreOp->z;
- pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
- pOut->zEnd = pOperand->zEnd;
- }
-
/* Add a single new term to an ExprList that is used to store a
** list of identifiers. Report an error if the ID list contains
** a COLLATE clause or an ASC or DESC keyword, except ignore the
@@ -133010,6 +154413,10 @@ static void disableLookaside(Parse *pParse){
sqlite3ExprListSetName(pParse, p, pIdToken, 1);
return p;
}
+
+#if TK_SPAN>255
+# error too many tokens in the grammar
+#endif
/**************** End of %include directives **********************************/
/* These constants specify the various numeric values for terminal symbols
** in a format understandable to "makeheaders". This section is blank unless
@@ -133040,7 +154447,7 @@ static void disableLookaside(Parse *pParse){
** the minor type might be the name of the identifier.
** Each non-terminal can have a different minor type.
** Terminal symbols all have the same minor type, though.
-** This macros defines the minor type for terminal
+** This macros defines the minor type for terminal
** symbols.
** YYMINORTYPE is the data type used for all minor types.
** This is typically a union of many types, one of
@@ -133050,64 +154457,80 @@ static void disableLookaside(Parse *pParse){
** zero the stack is dynamically sized using realloc()
** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument
** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument
+** sqlite3ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter
** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
** sqlite3ParserARG_FETCH Code to extract %extra_argument from yypParser
+** sqlite3ParserCTX_* As sqlite3ParserARG_ except for %extra_context
** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
** YYNSTATE the combined number of states.
** YYNRULE the number of rules in the grammar
+** YYNTOKEN Number of terminal symbols
** YY_MAX_SHIFT Maximum value for shift actions
** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** YY_MIN_REDUCE Maximum value for reduce actions
** YY_ERROR_ACTION The yy_action[] code for syntax error
** YY_ACCEPT_ACTION The yy_action[] code for accept
** YY_NO_ACTION The yy_action[] code for no-op
+** YY_MIN_REDUCE Minimum value for reduce actions
+** YY_MAX_REDUCE Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
-#define YYCODETYPE unsigned char
-#define YYNOCODE 252
+#define YYCODETYPE unsigned short int
+#define YYNOCODE 310
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 96
+#define YYWILDCARD 100
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
- Expr* yy72;
- TriggerStep* yy145;
- ExprList* yy148;
- SrcList* yy185;
- ExprSpan yy190;
- int yy194;
- Select* yy243;
- IdList* yy254;
- With* yy285;
- struct TrigEvent yy332;
- struct LimitVal yy354;
- struct {int value; int mask;} yy497;
+ SrcList* yy47;
+ u8 yy58;
+ struct FrameBound yy77;
+ With* yy131;
+ int yy192;
+ Expr* yy202;
+ struct {int value; int mask;} yy207;
+ struct TrigEvent yy230;
+ ExprList* yy242;
+ Window* yy303;
+ Upsert* yy318;
+ const char* yy436;
+ TriggerStep* yy447;
+ Select* yy539;
+ IdList* yy600;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
-#define sqlite3ParserARG_SDECL Parse *pParse;
-#define sqlite3ParserARG_PDECL ,Parse *pParse
-#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
-#define sqlite3ParserARG_STORE yypParser->pParse = pParse
+#define sqlite3ParserARG_SDECL
+#define sqlite3ParserARG_PDECL
+#define sqlite3ParserARG_PARAM
+#define sqlite3ParserARG_FETCH
+#define sqlite3ParserARG_STORE
+#define sqlite3ParserCTX_SDECL Parse *pParse;
+#define sqlite3ParserCTX_PDECL ,Parse *pParse
+#define sqlite3ParserCTX_PARAM ,pParse
+#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
+#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 456
-#define YYNRULE 332
-#define YY_MAX_SHIFT 455
-#define YY_MIN_SHIFTREDUCE 668
-#define YY_MAX_SHIFTREDUCE 999
-#define YY_MIN_REDUCE 1000
-#define YY_MAX_REDUCE 1331
-#define YY_ERROR_ACTION 1332
-#define YY_ACCEPT_ACTION 1333
-#define YY_NO_ACTION 1334
+#define YYNSTATE 553
+#define YYNRULE 385
+#define YYNRULE_WITH_ACTION 325
+#define YYNTOKEN 181
+#define YY_MAX_SHIFT 552
+#define YY_MIN_SHIFTREDUCE 803
+#define YY_MAX_SHIFTREDUCE 1187
+#define YY_ERROR_ACTION 1188
+#define YY_ACCEPT_ACTION 1189
+#define YY_NO_ACTION 1190
+#define YY_MIN_REDUCE 1191
+#define YY_MAX_REDUCE 1575
/************* End control #defines *******************************************/
+#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
@@ -133125,7 +154548,7 @@ typedef union {
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
-** action integer.
+** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
@@ -133136,9 +154559,6 @@ typedef union {
** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE.
**
-** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
-** and YY_MAX_REDUCE
-**
** N == YY_ERROR_ACTION A syntax error has occurred.
**
** N == YY_ACCEPT_ACTION The parser accepts its input.
@@ -133146,25 +154566,22 @@ typedef union {
** N == YY_NO_ACTION No such action. Denotes unused
** slots in the yy_action[] table.
**
+** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
+** and YY_MAX_REDUCE
+**
** The action table is constructed as a single large table named yy_action[].
** Given state S and lookahead X, the action is computed as either:
**
** (A) N = yy_action[ yy_shift_ofst[S] + X ]
** (B) N = yy_default[S]
**
-** The (A) formula is preferred. The B formula is used instead if:
-** (1) The yy_shift_ofst[S]+X value is out of range, or
-** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
-** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
-** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
-** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
-** Hence only tests (1) and (2) need to be evaluated.)
+** The (A) formula is preferred. The B formula is used instead if
+** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X.
**
** The formulas above are for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the yy_reduce_ofst[] array is used in place of
-** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
-** YY_SHIFT_USE_DFLT.
+** the yy_shift_ofst[] array.
**
** The following are the tables generated in this section:
**
@@ -133178,469 +154595,592 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1567)
+#define YY_ACTTAB_COUNT (1962)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 325, 832, 351, 825, 5, 203, 203, 819, 99, 100,
- /* 10 */ 90, 842, 842, 854, 857, 846, 846, 97, 97, 98,
- /* 20 */ 98, 98, 98, 301, 96, 96, 96, 96, 95, 95,
- /* 30 */ 94, 94, 94, 93, 351, 325, 977, 977, 824, 824,
- /* 40 */ 826, 947, 354, 99, 100, 90, 842, 842, 854, 857,
- /* 50 */ 846, 846, 97, 97, 98, 98, 98, 98, 338, 96,
- /* 60 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
- /* 70 */ 95, 95, 94, 94, 94, 93, 351, 791, 977, 977,
- /* 80 */ 325, 94, 94, 94, 93, 351, 792, 75, 99, 100,
- /* 90 */ 90, 842, 842, 854, 857, 846, 846, 97, 97, 98,
- /* 100 */ 98, 98, 98, 450, 96, 96, 96, 96, 95, 95,
- /* 110 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 325,
- /* 120 */ 275, 146, 132, 52, 52, 93, 351, 99, 100, 90,
- /* 130 */ 842, 842, 854, 857, 846, 846, 97, 97, 98, 98,
- /* 140 */ 98, 98, 101, 96, 96, 96, 96, 95, 95, 94,
- /* 150 */ 94, 94, 93, 351, 958, 958, 325, 268, 428, 413,
- /* 160 */ 411, 61, 752, 752, 99, 100, 90, 842, 842, 854,
- /* 170 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 60,
- /* 180 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 190 */ 351, 325, 270, 329, 273, 277, 959, 960, 250, 99,
- /* 200 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
- /* 210 */ 98, 98, 98, 98, 301, 96, 96, 96, 96, 95,
- /* 220 */ 95, 94, 94, 94, 93, 351, 325, 938, 1326, 698,
- /* 230 */ 706, 1326, 242, 412, 99, 100, 90, 842, 842, 854,
- /* 240 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 347,
- /* 250 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 260 */ 351, 325, 938, 1327, 384, 699, 1327, 381, 379, 99,
- /* 270 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
- /* 280 */ 98, 98, 98, 98, 701, 96, 96, 96, 96, 95,
- /* 290 */ 95, 94, 94, 94, 93, 351, 325, 92, 89, 178,
- /* 300 */ 833, 936, 373, 700, 99, 100, 90, 842, 842, 854,
- /* 310 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 375,
- /* 320 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 330 */ 351, 325, 1276, 947, 354, 818, 936, 739, 739, 99,
- /* 340 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
- /* 350 */ 98, 98, 98, 98, 230, 96, 96, 96, 96, 95,
- /* 360 */ 95, 94, 94, 94, 93, 351, 325, 969, 227, 92,
- /* 370 */ 89, 178, 373, 300, 99, 100, 90, 842, 842, 854,
- /* 380 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 921,
- /* 390 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 400 */ 351, 325, 449, 447, 447, 447, 147, 737, 737, 99,
- /* 410 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
- /* 420 */ 98, 98, 98, 98, 296, 96, 96, 96, 96, 95,
- /* 430 */ 95, 94, 94, 94, 93, 351, 325, 419, 231, 958,
- /* 440 */ 958, 158, 25, 422, 99, 100, 90, 842, 842, 854,
- /* 450 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 450,
- /* 460 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 470 */ 351, 443, 224, 224, 420, 958, 958, 962, 325, 52,
- /* 480 */ 52, 959, 960, 176, 415, 78, 99, 100, 90, 842,
- /* 490 */ 842, 854, 857, 846, 846, 97, 97, 98, 98, 98,
- /* 500 */ 98, 379, 96, 96, 96, 96, 95, 95, 94, 94,
- /* 510 */ 94, 93, 351, 325, 428, 418, 298, 959, 960, 962,
- /* 520 */ 81, 99, 88, 90, 842, 842, 854, 857, 846, 846,
- /* 530 */ 97, 97, 98, 98, 98, 98, 717, 96, 96, 96,
- /* 540 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 843,
- /* 550 */ 843, 855, 858, 996, 318, 343, 379, 100, 90, 842,
- /* 560 */ 842, 854, 857, 846, 846, 97, 97, 98, 98, 98,
- /* 570 */ 98, 450, 96, 96, 96, 96, 95, 95, 94, 94,
- /* 580 */ 94, 93, 351, 325, 350, 350, 350, 260, 377, 340,
- /* 590 */ 929, 52, 52, 90, 842, 842, 854, 857, 846, 846,
- /* 600 */ 97, 97, 98, 98, 98, 98, 361, 96, 96, 96,
- /* 610 */ 96, 95, 95, 94, 94, 94, 93, 351, 86, 445,
- /* 620 */ 847, 3, 1203, 361, 360, 378, 344, 813, 958, 958,
- /* 630 */ 1300, 86, 445, 729, 3, 212, 169, 287, 405, 282,
- /* 640 */ 404, 199, 232, 450, 300, 760, 83, 84, 280, 245,
- /* 650 */ 262, 365, 251, 85, 352, 352, 92, 89, 178, 83,
- /* 660 */ 84, 242, 412, 52, 52, 448, 85, 352, 352, 246,
- /* 670 */ 959, 960, 194, 455, 670, 402, 399, 398, 448, 243,
- /* 680 */ 221, 114, 434, 776, 361, 450, 397, 268, 747, 224,
- /* 690 */ 224, 132, 132, 198, 832, 434, 452, 451, 428, 427,
- /* 700 */ 819, 415, 734, 713, 132, 52, 52, 832, 268, 452,
- /* 710 */ 451, 734, 194, 819, 363, 402, 399, 398, 450, 1271,
- /* 720 */ 1271, 23, 958, 958, 86, 445, 397, 3, 228, 429,
- /* 730 */ 895, 824, 824, 826, 827, 19, 203, 720, 52, 52,
- /* 740 */ 428, 408, 439, 249, 824, 824, 826, 827, 19, 229,
- /* 750 */ 403, 153, 83, 84, 761, 177, 241, 450, 721, 85,
- /* 760 */ 352, 352, 120, 157, 959, 960, 58, 977, 409, 355,
- /* 770 */ 330, 448, 268, 428, 430, 320, 790, 32, 32, 86,
- /* 780 */ 445, 776, 3, 341, 98, 98, 98, 98, 434, 96,
- /* 790 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
- /* 800 */ 832, 120, 452, 451, 813, 887, 819, 83, 84, 977,
- /* 810 */ 813, 132, 410, 920, 85, 352, 352, 132, 407, 789,
- /* 820 */ 958, 958, 92, 89, 178, 917, 448, 262, 370, 261,
- /* 830 */ 82, 914, 80, 262, 370, 261, 776, 824, 824, 826,
- /* 840 */ 827, 19, 934, 434, 96, 96, 96, 96, 95, 95,
- /* 850 */ 94, 94, 94, 93, 351, 832, 74, 452, 451, 958,
- /* 860 */ 958, 819, 959, 960, 120, 92, 89, 178, 945, 2,
- /* 870 */ 918, 965, 268, 1, 976, 76, 445, 762, 3, 708,
- /* 880 */ 901, 901, 387, 958, 958, 757, 919, 371, 740, 778,
- /* 890 */ 756, 257, 824, 824, 826, 827, 19, 417, 741, 450,
- /* 900 */ 24, 959, 960, 83, 84, 369, 958, 958, 177, 226,
- /* 910 */ 85, 352, 352, 885, 315, 314, 313, 215, 311, 10,
- /* 920 */ 10, 683, 448, 349, 348, 959, 960, 909, 777, 157,
- /* 930 */ 120, 958, 958, 337, 776, 416, 711, 310, 450, 434,
- /* 940 */ 450, 321, 450, 791, 103, 200, 175, 450, 959, 960,
- /* 950 */ 908, 832, 792, 452, 451, 9, 9, 819, 10, 10,
- /* 960 */ 52, 52, 51, 51, 180, 716, 248, 10, 10, 171,
- /* 970 */ 170, 167, 339, 959, 960, 247, 984, 702, 702, 450,
- /* 980 */ 715, 233, 686, 982, 889, 983, 182, 914, 824, 824,
- /* 990 */ 826, 827, 19, 183, 256, 423, 132, 181, 394, 10,
- /* 1000 */ 10, 889, 891, 749, 958, 958, 917, 268, 985, 198,
- /* 1010 */ 985, 349, 348, 425, 415, 299, 817, 832, 326, 825,
- /* 1020 */ 120, 332, 133, 819, 268, 98, 98, 98, 98, 91,
- /* 1030 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
- /* 1040 */ 351, 157, 810, 371, 382, 359, 959, 960, 358, 268,
- /* 1050 */ 450, 918, 368, 324, 824, 824, 826, 450, 709, 450,
- /* 1060 */ 264, 380, 889, 450, 877, 746, 253, 919, 255, 433,
- /* 1070 */ 36, 36, 234, 450, 234, 120, 269, 37, 37, 12,
- /* 1080 */ 12, 334, 272, 27, 27, 450, 330, 118, 450, 162,
- /* 1090 */ 742, 280, 450, 38, 38, 450, 985, 356, 985, 450,
- /* 1100 */ 709, 1210, 450, 132, 450, 39, 39, 450, 40, 40,
- /* 1110 */ 450, 362, 41, 41, 450, 42, 42, 450, 254, 28,
- /* 1120 */ 28, 450, 29, 29, 31, 31, 450, 43, 43, 450,
- /* 1130 */ 44, 44, 450, 714, 45, 45, 450, 11, 11, 767,
- /* 1140 */ 450, 46, 46, 450, 268, 450, 105, 105, 450, 47,
- /* 1150 */ 47, 450, 48, 48, 450, 237, 33, 33, 450, 172,
- /* 1160 */ 49, 49, 450, 50, 50, 34, 34, 274, 122, 122,
- /* 1170 */ 450, 123, 123, 450, 124, 124, 450, 898, 56, 56,
- /* 1180 */ 450, 897, 35, 35, 450, 267, 450, 817, 450, 817,
- /* 1190 */ 106, 106, 450, 53, 53, 385, 107, 107, 450, 817,
- /* 1200 */ 108, 108, 817, 450, 104, 104, 121, 121, 119, 119,
- /* 1210 */ 450, 117, 112, 112, 450, 276, 450, 225, 111, 111,
- /* 1220 */ 450, 730, 450, 109, 109, 450, 673, 674, 675, 912,
- /* 1230 */ 110, 110, 317, 998, 55, 55, 57, 57, 692, 331,
- /* 1240 */ 54, 54, 26, 26, 696, 30, 30, 317, 937, 197,
- /* 1250 */ 196, 195, 335, 281, 336, 446, 331, 745, 689, 436,
- /* 1260 */ 440, 444, 120, 72, 386, 223, 175, 345, 757, 933,
- /* 1270 */ 20, 286, 319, 756, 815, 372, 374, 202, 202, 202,
- /* 1280 */ 263, 395, 285, 74, 208, 21, 696, 719, 718, 884,
- /* 1290 */ 120, 120, 120, 120, 120, 754, 278, 828, 77, 74,
- /* 1300 */ 726, 727, 785, 783, 880, 202, 999, 208, 894, 893,
- /* 1310 */ 894, 893, 694, 816, 763, 116, 774, 1290, 431, 432,
- /* 1320 */ 302, 999, 390, 303, 823, 697, 691, 680, 159, 289,
- /* 1330 */ 679, 884, 681, 952, 291, 218, 293, 7, 316, 828,
- /* 1340 */ 173, 805, 259, 364, 252, 911, 376, 713, 295, 435,
- /* 1350 */ 308, 168, 955, 993, 135, 400, 990, 284, 882, 881,
- /* 1360 */ 205, 928, 926, 59, 333, 62, 144, 156, 130, 72,
- /* 1370 */ 802, 366, 367, 393, 137, 185, 189, 160, 139, 383,
- /* 1380 */ 67, 896, 140, 141, 142, 148, 389, 812, 775, 266,
- /* 1390 */ 219, 190, 154, 391, 913, 876, 271, 406, 191, 322,
- /* 1400 */ 682, 733, 192, 342, 732, 724, 731, 711, 723, 421,
- /* 1410 */ 705, 71, 323, 6, 204, 771, 288, 79, 297, 346,
- /* 1420 */ 772, 704, 290, 283, 703, 770, 292, 294, 967, 239,
- /* 1430 */ 769, 102, 862, 438, 426, 240, 424, 442, 73, 213,
- /* 1440 */ 688, 238, 22, 453, 953, 214, 217, 216, 454, 677,
- /* 1450 */ 676, 671, 753, 125, 115, 235, 126, 669, 353, 166,
- /* 1460 */ 127, 244, 179, 357, 306, 304, 305, 307, 113, 892,
- /* 1470 */ 327, 890, 811, 328, 134, 128, 136, 138, 743, 258,
- /* 1480 */ 907, 184, 143, 129, 910, 186, 63, 64, 145, 187,
- /* 1490 */ 906, 65, 8, 66, 13, 188, 202, 899, 265, 149,
- /* 1500 */ 987, 388, 150, 685, 161, 392, 285, 193, 279, 396,
- /* 1510 */ 151, 401, 68, 14, 15, 722, 69, 236, 831, 131,
- /* 1520 */ 830, 860, 70, 751, 16, 414, 755, 4, 174, 220,
- /* 1530 */ 222, 784, 201, 152, 779, 77, 74, 17, 18, 875,
- /* 1540 */ 861, 859, 916, 864, 915, 207, 206, 942, 163, 437,
- /* 1550 */ 948, 943, 164, 209, 1002, 441, 863, 165, 210, 829,
- /* 1560 */ 695, 87, 312, 211, 1292, 1291, 309,
+ /* 0 */ 546, 1222, 546, 451, 1260, 546, 1239, 546, 114, 111,
+ /* 10 */ 211, 546, 1537, 546, 1260, 523, 114, 111, 211, 392,
+ /* 20 */ 1232, 344, 42, 42, 42, 42, 1225, 42, 42, 71,
+ /* 30 */ 71, 937, 1224, 71, 71, 71, 71, 1462, 1493, 938,
+ /* 40 */ 820, 453, 6, 121, 122, 112, 1165, 1165, 1006, 1009,
+ /* 50 */ 999, 999, 119, 119, 120, 120, 120, 120, 1543, 392,
+ /* 60 */ 1358, 1517, 552, 2, 1193, 194, 528, 436, 143, 291,
+ /* 70 */ 528, 136, 528, 371, 261, 504, 272, 385, 1273, 527,
+ /* 80 */ 503, 493, 164, 121, 122, 112, 1165, 1165, 1006, 1009,
+ /* 90 */ 999, 999, 119, 119, 120, 120, 120, 120, 1358, 442,
+ /* 100 */ 1514, 118, 118, 118, 118, 117, 117, 116, 116, 116,
+ /* 110 */ 115, 424, 266, 266, 266, 266, 1498, 358, 1500, 435,
+ /* 120 */ 357, 1498, 517, 524, 1485, 543, 1114, 543, 1114, 392,
+ /* 130 */ 405, 241, 208, 114, 111, 211, 98, 290, 537, 221,
+ /* 140 */ 1029, 118, 118, 118, 118, 117, 117, 116, 116, 116,
+ /* 150 */ 115, 424, 1142, 121, 122, 112, 1165, 1165, 1006, 1009,
+ /* 160 */ 999, 999, 119, 119, 120, 120, 120, 120, 406, 428,
+ /* 170 */ 117, 117, 116, 116, 116, 115, 424, 1418, 468, 123,
+ /* 180 */ 118, 118, 118, 118, 117, 117, 116, 116, 116, 115,
+ /* 190 */ 424, 116, 116, 116, 115, 424, 540, 540, 540, 392,
+ /* 200 */ 505, 120, 120, 120, 120, 113, 1051, 1142, 1143, 1144,
+ /* 210 */ 1051, 118, 118, 118, 118, 117, 117, 116, 116, 116,
+ /* 220 */ 115, 424, 1461, 121, 122, 112, 1165, 1165, 1006, 1009,
+ /* 230 */ 999, 999, 119, 119, 120, 120, 120, 120, 392, 444,
+ /* 240 */ 316, 83, 463, 81, 359, 382, 1142, 80, 118, 118,
+ /* 250 */ 118, 118, 117, 117, 116, 116, 116, 115, 424, 179,
+ /* 260 */ 434, 424, 121, 122, 112, 1165, 1165, 1006, 1009, 999,
+ /* 270 */ 999, 119, 119, 120, 120, 120, 120, 434, 433, 266,
+ /* 280 */ 266, 118, 118, 118, 118, 117, 117, 116, 116, 116,
+ /* 290 */ 115, 424, 543, 1109, 903, 506, 1142, 114, 111, 211,
+ /* 300 */ 1431, 1142, 1143, 1144, 206, 491, 1109, 392, 449, 1109,
+ /* 310 */ 545, 330, 120, 120, 120, 120, 298, 1431, 1433, 17,
+ /* 320 */ 118, 118, 118, 118, 117, 117, 116, 116, 116, 115,
+ /* 330 */ 424, 121, 122, 112, 1165, 1165, 1006, 1009, 999, 999,
+ /* 340 */ 119, 119, 120, 120, 120, 120, 392, 1358, 434, 1142,
+ /* 350 */ 482, 1142, 1143, 1144, 996, 996, 1007, 1010, 445, 118,
+ /* 360 */ 118, 118, 118, 117, 117, 116, 116, 116, 115, 424,
+ /* 370 */ 121, 122, 112, 1165, 1165, 1006, 1009, 999, 999, 119,
+ /* 380 */ 119, 120, 120, 120, 120, 1054, 1054, 465, 1431, 118,
+ /* 390 */ 118, 118, 118, 117, 117, 116, 116, 116, 115, 424,
+ /* 400 */ 1142, 451, 546, 1426, 1142, 1143, 1144, 233, 966, 1142,
+ /* 410 */ 481, 478, 477, 171, 360, 392, 164, 407, 414, 842,
+ /* 420 */ 476, 164, 185, 334, 71, 71, 1243, 1000, 118, 118,
+ /* 430 */ 118, 118, 117, 117, 116, 116, 116, 115, 424, 121,
+ /* 440 */ 122, 112, 1165, 1165, 1006, 1009, 999, 999, 119, 119,
+ /* 450 */ 120, 120, 120, 120, 392, 1142, 1143, 1144, 835, 12,
+ /* 460 */ 314, 509, 163, 356, 1142, 1143, 1144, 114, 111, 211,
+ /* 470 */ 508, 290, 537, 546, 276, 180, 290, 537, 121, 122,
+ /* 480 */ 112, 1165, 1165, 1006, 1009, 999, 999, 119, 119, 120,
+ /* 490 */ 120, 120, 120, 345, 484, 71, 71, 118, 118, 118,
+ /* 500 */ 118, 117, 117, 116, 116, 116, 115, 424, 1142, 209,
+ /* 510 */ 411, 523, 1142, 1109, 1571, 378, 252, 269, 342, 487,
+ /* 520 */ 337, 486, 238, 392, 513, 364, 1109, 1127, 333, 1109,
+ /* 530 */ 191, 409, 286, 32, 457, 443, 118, 118, 118, 118,
+ /* 540 */ 117, 117, 116, 116, 116, 115, 424, 121, 122, 112,
+ /* 550 */ 1165, 1165, 1006, 1009, 999, 999, 119, 119, 120, 120,
+ /* 560 */ 120, 120, 392, 1142, 1143, 1144, 987, 1142, 1143, 1144,
+ /* 570 */ 1142, 233, 492, 1492, 481, 478, 477, 6, 163, 546,
+ /* 580 */ 512, 546, 115, 424, 476, 5, 121, 122, 112, 1165,
+ /* 590 */ 1165, 1006, 1009, 999, 999, 119, 119, 120, 120, 120,
+ /* 600 */ 120, 13, 13, 13, 13, 118, 118, 118, 118, 117,
+ /* 610 */ 117, 116, 116, 116, 115, 424, 403, 502, 408, 546,
+ /* 620 */ 1486, 544, 1142, 892, 892, 1142, 1143, 1144, 1473, 1142,
+ /* 630 */ 275, 392, 808, 809, 810, 971, 422, 422, 422, 16,
+ /* 640 */ 16, 55, 55, 1242, 118, 118, 118, 118, 117, 117,
+ /* 650 */ 116, 116, 116, 115, 424, 121, 122, 112, 1165, 1165,
+ /* 660 */ 1006, 1009, 999, 999, 119, 119, 120, 120, 120, 120,
+ /* 670 */ 392, 1189, 1, 1, 552, 2, 1193, 1142, 1143, 1144,
+ /* 680 */ 194, 291, 898, 136, 1142, 1143, 1144, 897, 521, 1492,
+ /* 690 */ 1273, 3, 380, 6, 121, 122, 112, 1165, 1165, 1006,
+ /* 700 */ 1009, 999, 999, 119, 119, 120, 120, 120, 120, 858,
+ /* 710 */ 546, 924, 546, 118, 118, 118, 118, 117, 117, 116,
+ /* 720 */ 116, 116, 115, 424, 266, 266, 1092, 1569, 1142, 551,
+ /* 730 */ 1569, 1193, 13, 13, 13, 13, 291, 543, 136, 392,
+ /* 740 */ 485, 421, 420, 966, 344, 1273, 468, 410, 859, 279,
+ /* 750 */ 140, 221, 118, 118, 118, 118, 117, 117, 116, 116,
+ /* 760 */ 116, 115, 424, 121, 122, 112, 1165, 1165, 1006, 1009,
+ /* 770 */ 999, 999, 119, 119, 120, 120, 120, 120, 546, 266,
+ /* 780 */ 266, 428, 392, 1142, 1143, 1144, 1172, 830, 1172, 468,
+ /* 790 */ 431, 145, 543, 1146, 401, 314, 439, 302, 838, 1490,
+ /* 800 */ 71, 71, 412, 6, 1090, 473, 221, 100, 112, 1165,
+ /* 810 */ 1165, 1006, 1009, 999, 999, 119, 119, 120, 120, 120,
+ /* 820 */ 120, 118, 118, 118, 118, 117, 117, 116, 116, 116,
+ /* 830 */ 115, 424, 237, 1425, 546, 451, 428, 287, 986, 546,
+ /* 840 */ 236, 235, 234, 830, 97, 529, 429, 1265, 1265, 1146,
+ /* 850 */ 494, 307, 430, 838, 977, 546, 71, 71, 976, 1241,
+ /* 860 */ 546, 51, 51, 300, 118, 118, 118, 118, 117, 117,
+ /* 870 */ 116, 116, 116, 115, 424, 194, 103, 70, 70, 266,
+ /* 880 */ 266, 546, 71, 71, 266, 266, 30, 391, 344, 976,
+ /* 890 */ 976, 978, 543, 528, 1109, 328, 392, 543, 495, 397,
+ /* 900 */ 1470, 195, 530, 13, 13, 1358, 240, 1109, 277, 280,
+ /* 910 */ 1109, 280, 304, 457, 306, 333, 392, 31, 188, 419,
+ /* 920 */ 121, 122, 112, 1165, 1165, 1006, 1009, 999, 999, 119,
+ /* 930 */ 119, 120, 120, 120, 120, 142, 392, 365, 457, 986,
+ /* 940 */ 121, 122, 112, 1165, 1165, 1006, 1009, 999, 999, 119,
+ /* 950 */ 119, 120, 120, 120, 120, 977, 323, 1142, 326, 976,
+ /* 960 */ 121, 110, 112, 1165, 1165, 1006, 1009, 999, 999, 119,
+ /* 970 */ 119, 120, 120, 120, 120, 464, 377, 1185, 118, 118,
+ /* 980 */ 118, 118, 117, 117, 116, 116, 116, 115, 424, 1142,
+ /* 990 */ 976, 976, 978, 305, 9, 366, 244, 362, 118, 118,
+ /* 1000 */ 118, 118, 117, 117, 116, 116, 116, 115, 424, 313,
+ /* 1010 */ 546, 344, 1142, 1143, 1144, 299, 290, 537, 118, 118,
+ /* 1020 */ 118, 118, 117, 117, 116, 116, 116, 115, 424, 1263,
+ /* 1030 */ 1263, 1163, 13, 13, 278, 421, 420, 468, 392, 923,
+ /* 1040 */ 260, 260, 289, 1169, 1142, 1143, 1144, 189, 1171, 266,
+ /* 1050 */ 266, 468, 390, 543, 1186, 546, 1170, 263, 144, 489,
+ /* 1060 */ 922, 546, 543, 122, 112, 1165, 1165, 1006, 1009, 999,
+ /* 1070 */ 999, 119, 119, 120, 120, 120, 120, 71, 71, 1142,
+ /* 1080 */ 1172, 1272, 1172, 13, 13, 898, 1070, 1163, 546, 468,
+ /* 1090 */ 897, 107, 538, 1491, 4, 1268, 1109, 6, 525, 1049,
+ /* 1100 */ 12, 1071, 1092, 1570, 312, 455, 1570, 520, 541, 1109,
+ /* 1110 */ 56, 56, 1109, 1489, 423, 1358, 1072, 6, 345, 285,
+ /* 1120 */ 118, 118, 118, 118, 117, 117, 116, 116, 116, 115,
+ /* 1130 */ 424, 425, 1271, 321, 1142, 1143, 1144, 878, 266, 266,
+ /* 1140 */ 1277, 107, 538, 535, 4, 1488, 293, 879, 1211, 6,
+ /* 1150 */ 210, 543, 543, 164, 294, 496, 416, 204, 541, 267,
+ /* 1160 */ 267, 1214, 398, 511, 499, 204, 266, 266, 396, 531,
+ /* 1170 */ 8, 986, 543, 519, 546, 922, 458, 105, 105, 543,
+ /* 1180 */ 1090, 425, 266, 266, 106, 417, 425, 548, 547, 266,
+ /* 1190 */ 266, 976, 518, 535, 1373, 543, 15, 15, 266, 266,
+ /* 1200 */ 456, 1120, 543, 266, 266, 1070, 1372, 515, 290, 537,
+ /* 1210 */ 546, 543, 514, 97, 444, 316, 543, 546, 922, 125,
+ /* 1220 */ 1071, 986, 976, 976, 978, 979, 27, 105, 105, 401,
+ /* 1230 */ 343, 1511, 44, 44, 106, 1072, 425, 548, 547, 57,
+ /* 1240 */ 57, 976, 343, 1511, 107, 538, 546, 4, 462, 401,
+ /* 1250 */ 214, 1120, 459, 297, 377, 1091, 534, 1309, 546, 539,
+ /* 1260 */ 398, 541, 290, 537, 104, 244, 102, 526, 58, 58,
+ /* 1270 */ 546, 199, 976, 976, 978, 979, 27, 1516, 1131, 427,
+ /* 1280 */ 59, 59, 270, 237, 425, 138, 95, 375, 375, 374,
+ /* 1290 */ 255, 372, 60, 60, 817, 1180, 535, 546, 273, 546,
+ /* 1300 */ 1163, 1308, 389, 388, 546, 438, 546, 215, 210, 296,
+ /* 1310 */ 515, 849, 546, 265, 208, 516, 1476, 295, 274, 61,
+ /* 1320 */ 61, 62, 62, 308, 986, 109, 45, 45, 46, 46,
+ /* 1330 */ 105, 105, 1186, 922, 47, 47, 341, 106, 546, 425,
+ /* 1340 */ 548, 547, 1542, 546, 976, 867, 340, 217, 546, 937,
+ /* 1350 */ 397, 107, 538, 218, 4, 156, 1163, 938, 158, 546,
+ /* 1360 */ 49, 49, 1162, 546, 268, 50, 50, 546, 541, 1450,
+ /* 1370 */ 63, 63, 546, 1449, 216, 976, 976, 978, 979, 27,
+ /* 1380 */ 446, 64, 64, 546, 460, 65, 65, 546, 318, 14,
+ /* 1390 */ 14, 425, 1305, 546, 66, 66, 1087, 546, 141, 379,
+ /* 1400 */ 38, 546, 963, 535, 322, 127, 127, 546, 393, 67,
+ /* 1410 */ 67, 546, 325, 290, 537, 52, 52, 515, 546, 68,
+ /* 1420 */ 68, 845, 514, 69, 69, 399, 165, 857, 856, 53,
+ /* 1430 */ 53, 986, 311, 151, 151, 97, 432, 105, 105, 327,
+ /* 1440 */ 152, 152, 526, 1048, 106, 1048, 425, 548, 547, 1131,
+ /* 1450 */ 427, 976, 1032, 270, 968, 239, 329, 243, 375, 375,
+ /* 1460 */ 374, 255, 372, 940, 941, 817, 1296, 546, 220, 546,
+ /* 1470 */ 107, 538, 546, 4, 546, 1256, 199, 845, 215, 1036,
+ /* 1480 */ 296, 1530, 976, 976, 978, 979, 27, 541, 295, 76,
+ /* 1490 */ 76, 54, 54, 980, 72, 72, 128, 128, 864, 865,
+ /* 1500 */ 107, 538, 546, 4, 1047, 546, 1047, 533, 469, 546,
+ /* 1510 */ 425, 546, 450, 1240, 546, 243, 546, 541, 217, 546,
+ /* 1520 */ 452, 197, 535, 243, 73, 73, 156, 129, 129, 158,
+ /* 1530 */ 336, 130, 130, 126, 126, 1036, 150, 150, 149, 149,
+ /* 1540 */ 425, 134, 134, 317, 474, 216, 97, 239, 331, 980,
+ /* 1550 */ 986, 97, 535, 346, 347, 546, 105, 105, 902, 931,
+ /* 1560 */ 546, 895, 243, 106, 109, 425, 548, 547, 546, 1505,
+ /* 1570 */ 976, 828, 99, 538, 139, 4, 546, 133, 133, 393,
+ /* 1580 */ 986, 1317, 131, 131, 290, 537, 105, 105, 1357, 541,
+ /* 1590 */ 132, 132, 1292, 106, 1303, 425, 548, 547, 75, 75,
+ /* 1600 */ 976, 976, 976, 978, 979, 27, 546, 432, 896, 1289,
+ /* 1610 */ 532, 109, 425, 1363, 546, 1221, 1213, 1202, 258, 546,
+ /* 1620 */ 349, 546, 1201, 11, 535, 1203, 1524, 351, 77, 77,
+ /* 1630 */ 376, 976, 976, 978, 979, 27, 74, 74, 353, 213,
+ /* 1640 */ 301, 43, 43, 48, 48, 437, 310, 201, 303, 1350,
+ /* 1650 */ 315, 355, 986, 454, 479, 1239, 339, 192, 105, 105,
+ /* 1660 */ 1422, 1421, 193, 536, 205, 106, 1527, 425, 548, 547,
+ /* 1670 */ 1180, 167, 976, 270, 247, 1469, 1467, 1177, 375, 375,
+ /* 1680 */ 374, 255, 372, 200, 369, 817, 400, 83, 79, 82,
+ /* 1690 */ 1427, 448, 177, 95, 1342, 161, 169, 1339, 215, 440,
+ /* 1700 */ 296, 172, 173, 976, 976, 978, 979, 27, 295, 174,
+ /* 1710 */ 175, 441, 472, 223, 1347, 383, 35, 381, 36, 461,
+ /* 1720 */ 88, 1353, 181, 447, 384, 1416, 227, 467, 259, 229,
+ /* 1730 */ 186, 488, 470, 324, 1250, 230, 231, 320, 217, 1204,
+ /* 1740 */ 1438, 1259, 386, 1258, 413, 90, 156, 849, 1541, 158,
+ /* 1750 */ 206, 415, 1540, 507, 1300, 1257, 94, 348, 1229, 1301,
+ /* 1760 */ 387, 1510, 1228, 338, 1227, 216, 350, 1539, 498, 283,
+ /* 1770 */ 284, 1249, 501, 1299, 352, 245, 246, 418, 1298, 354,
+ /* 1780 */ 1496, 1495, 124, 10, 526, 363, 101, 1324, 253, 96,
+ /* 1790 */ 510, 1210, 34, 549, 1137, 254, 256, 257, 166, 393,
+ /* 1800 */ 550, 1199, 1282, 361, 290, 537, 1281, 196, 367, 368,
+ /* 1810 */ 1194, 153, 1454, 137, 281, 1323, 1455, 804, 154, 426,
+ /* 1820 */ 198, 155, 1453, 1452, 292, 212, 202, 432, 1402, 203,
+ /* 1830 */ 271, 135, 288, 78, 1046, 1044, 960, 168, 157, 881,
+ /* 1840 */ 170, 219, 309, 222, 1060, 176, 964, 159, 402, 84,
+ /* 1850 */ 178, 404, 85, 86, 87, 160, 1063, 224, 394, 395,
+ /* 1860 */ 225, 1059, 146, 18, 226, 319, 243, 1174, 466, 228,
+ /* 1870 */ 1052, 182, 183, 37, 819, 471, 340, 232, 332, 483,
+ /* 1880 */ 184, 89, 162, 19, 20, 475, 91, 480, 847, 335,
+ /* 1890 */ 147, 860, 282, 92, 490, 93, 1125, 148, 1012, 1095,
+ /* 1900 */ 39, 497, 1096, 40, 500, 262, 207, 264, 930, 187,
+ /* 1910 */ 925, 109, 1111, 1115, 1113, 7, 1099, 242, 33, 1119,
+ /* 1920 */ 21, 522, 22, 23, 24, 1118, 25, 190, 97, 26,
+ /* 1930 */ 1027, 1013, 1011, 1015, 1069, 1016, 1068, 249, 248, 28,
+ /* 1940 */ 41, 891, 981, 829, 108, 29, 250, 542, 251, 370,
+ /* 1950 */ 373, 1133, 1132, 1190, 1190, 1190, 1190, 1190, 1190, 1190,
+ /* 1960 */ 1532, 1531,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28,
- /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
- /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133,
- /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33,
- /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 187, 43,
- /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97,
- /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28,
- /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
- /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19,
- /* 120 */ 16, 22, 92, 172, 173, 52, 53, 27, 28, 29,
- /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49,
- /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208,
- /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32,
- /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79,
- /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 190 */ 53, 19, 88, 157, 90, 23, 97, 98, 193, 27,
- /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172,
- /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32,
- /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187,
- /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 260 */ 53, 19, 22, 23, 228, 23, 26, 231, 152, 27,
- /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 280 */ 38, 39, 40, 41, 172, 43, 44, 45, 46, 47,
- /* 290 */ 48, 49, 50, 51, 52, 53, 19, 221, 222, 223,
- /* 300 */ 23, 96, 152, 172, 27, 28, 29, 30, 31, 32,
- /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152,
- /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 330 */ 53, 19, 0, 1, 2, 23, 96, 190, 191, 27,
- /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 350 */ 38, 39, 40, 41, 238, 43, 44, 45, 46, 47,
- /* 360 */ 48, 49, 50, 51, 52, 53, 19, 185, 218, 221,
- /* 370 */ 222, 223, 152, 152, 27, 28, 29, 30, 31, 32,
- /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 241,
- /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 400 */ 53, 19, 152, 168, 169, 170, 22, 190, 191, 27,
- /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
- /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
- /* 430 */ 48, 49, 50, 51, 52, 53, 19, 19, 218, 55,
- /* 440 */ 56, 24, 22, 152, 27, 28, 29, 30, 31, 32,
- /* 450 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152,
- /* 460 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 470 */ 53, 250, 194, 195, 56, 55, 56, 55, 19, 172,
- /* 480 */ 173, 97, 98, 152, 206, 138, 27, 28, 29, 30,
- /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 500 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 510 */ 51, 52, 53, 19, 207, 208, 152, 97, 98, 97,
- /* 520 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- /* 530 */ 36, 37, 38, 39, 40, 41, 181, 43, 44, 45,
- /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 30,
- /* 550 */ 31, 32, 33, 247, 248, 19, 152, 28, 29, 30,
- /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
- /* 580 */ 51, 52, 53, 19, 168, 169, 170, 238, 19, 53,
- /* 590 */ 152, 172, 173, 29, 30, 31, 32, 33, 34, 35,
- /* 600 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45,
- /* 610 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 20,
- /* 620 */ 101, 22, 23, 169, 170, 56, 207, 85, 55, 56,
- /* 630 */ 23, 19, 20, 26, 22, 99, 100, 101, 102, 103,
- /* 640 */ 104, 105, 238, 152, 152, 210, 47, 48, 112, 152,
- /* 650 */ 108, 109, 110, 54, 55, 56, 221, 222, 223, 47,
- /* 660 */ 48, 119, 120, 172, 173, 66, 54, 55, 56, 152,
- /* 670 */ 97, 98, 99, 148, 149, 102, 103, 104, 66, 154,
- /* 680 */ 23, 156, 83, 26, 230, 152, 113, 152, 163, 194,
- /* 690 */ 195, 92, 92, 30, 95, 83, 97, 98, 207, 208,
- /* 700 */ 101, 206, 179, 180, 92, 172, 173, 95, 152, 97,
- /* 710 */ 98, 188, 99, 101, 219, 102, 103, 104, 152, 119,
- /* 720 */ 120, 196, 55, 56, 19, 20, 113, 22, 193, 163,
- /* 730 */ 11, 132, 133, 134, 135, 136, 24, 65, 172, 173,
- /* 740 */ 207, 208, 250, 152, 132, 133, 134, 135, 136, 193,
- /* 750 */ 78, 84, 47, 48, 49, 98, 199, 152, 86, 54,
- /* 760 */ 55, 56, 196, 152, 97, 98, 209, 55, 163, 244,
- /* 770 */ 107, 66, 152, 207, 208, 164, 175, 172, 173, 19,
- /* 780 */ 20, 124, 22, 111, 38, 39, 40, 41, 83, 43,
- /* 790 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 800 */ 95, 196, 97, 98, 85, 152, 101, 47, 48, 97,
- /* 810 */ 85, 92, 207, 193, 54, 55, 56, 92, 49, 175,
- /* 820 */ 55, 56, 221, 222, 223, 12, 66, 108, 109, 110,
- /* 830 */ 137, 163, 139, 108, 109, 110, 26, 132, 133, 134,
- /* 840 */ 135, 136, 152, 83, 43, 44, 45, 46, 47, 48,
- /* 850 */ 49, 50, 51, 52, 53, 95, 26, 97, 98, 55,
- /* 860 */ 56, 101, 97, 98, 196, 221, 222, 223, 146, 147,
- /* 870 */ 57, 171, 152, 22, 26, 19, 20, 49, 22, 179,
- /* 880 */ 108, 109, 110, 55, 56, 116, 73, 219, 75, 124,
- /* 890 */ 121, 152, 132, 133, 134, 135, 136, 163, 85, 152,
- /* 900 */ 232, 97, 98, 47, 48, 237, 55, 56, 98, 5,
- /* 910 */ 54, 55, 56, 193, 10, 11, 12, 13, 14, 172,
- /* 920 */ 173, 17, 66, 47, 48, 97, 98, 152, 124, 152,
- /* 930 */ 196, 55, 56, 186, 124, 152, 106, 160, 152, 83,
- /* 940 */ 152, 164, 152, 61, 22, 211, 212, 152, 97, 98,
- /* 950 */ 152, 95, 70, 97, 98, 172, 173, 101, 172, 173,
- /* 960 */ 172, 173, 172, 173, 60, 181, 62, 172, 173, 47,
- /* 970 */ 48, 123, 186, 97, 98, 71, 100, 55, 56, 152,
- /* 980 */ 181, 186, 21, 107, 152, 109, 82, 163, 132, 133,
- /* 990 */ 134, 135, 136, 89, 16, 207, 92, 93, 19, 172,
- /* 1000 */ 173, 169, 170, 195, 55, 56, 12, 152, 132, 30,
- /* 1010 */ 134, 47, 48, 186, 206, 225, 152, 95, 114, 97,
- /* 1020 */ 196, 245, 246, 101, 152, 38, 39, 40, 41, 42,
- /* 1030 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- /* 1040 */ 53, 152, 163, 219, 152, 141, 97, 98, 193, 152,
- /* 1050 */ 152, 57, 91, 164, 132, 133, 134, 152, 55, 152,
- /* 1060 */ 152, 237, 230, 152, 103, 193, 88, 73, 90, 75,
- /* 1070 */ 172, 173, 183, 152, 185, 196, 152, 172, 173, 172,
- /* 1080 */ 173, 217, 152, 172, 173, 152, 107, 22, 152, 24,
- /* 1090 */ 193, 112, 152, 172, 173, 152, 132, 242, 134, 152,
- /* 1100 */ 97, 140, 152, 92, 152, 172, 173, 152, 172, 173,
- /* 1110 */ 152, 100, 172, 173, 152, 172, 173, 152, 140, 172,
- /* 1120 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152,
- /* 1130 */ 172, 173, 152, 152, 172, 173, 152, 172, 173, 213,
- /* 1140 */ 152, 172, 173, 152, 152, 152, 172, 173, 152, 172,
- /* 1150 */ 173, 152, 172, 173, 152, 210, 172, 173, 152, 26,
- /* 1160 */ 172, 173, 152, 172, 173, 172, 173, 152, 172, 173,
- /* 1170 */ 152, 172, 173, 152, 172, 173, 152, 59, 172, 173,
- /* 1180 */ 152, 63, 172, 173, 152, 193, 152, 152, 152, 152,
- /* 1190 */ 172, 173, 152, 172, 173, 77, 172, 173, 152, 152,
- /* 1200 */ 172, 173, 152, 152, 172, 173, 172, 173, 172, 173,
- /* 1210 */ 152, 22, 172, 173, 152, 152, 152, 22, 172, 173,
- /* 1220 */ 152, 152, 152, 172, 173, 152, 7, 8, 9, 163,
- /* 1230 */ 172, 173, 22, 23, 172, 173, 172, 173, 166, 167,
- /* 1240 */ 172, 173, 172, 173, 55, 172, 173, 22, 23, 108,
- /* 1250 */ 109, 110, 217, 152, 217, 166, 167, 163, 163, 163,
- /* 1260 */ 163, 163, 196, 130, 217, 211, 212, 217, 116, 23,
- /* 1270 */ 22, 101, 26, 121, 23, 23, 23, 26, 26, 26,
- /* 1280 */ 23, 23, 112, 26, 26, 37, 97, 100, 101, 55,
- /* 1290 */ 196, 196, 196, 196, 196, 23, 23, 55, 26, 26,
- /* 1300 */ 7, 8, 23, 152, 23, 26, 96, 26, 132, 132,
- /* 1310 */ 134, 134, 23, 152, 152, 26, 152, 122, 152, 191,
- /* 1320 */ 152, 96, 234, 152, 152, 152, 152, 152, 197, 210,
- /* 1330 */ 152, 97, 152, 152, 210, 233, 210, 198, 150, 97,
- /* 1340 */ 184, 201, 239, 214, 214, 201, 239, 180, 214, 227,
- /* 1350 */ 200, 198, 155, 67, 243, 176, 69, 175, 175, 175,
- /* 1360 */ 122, 159, 159, 240, 159, 240, 22, 220, 27, 130,
- /* 1370 */ 201, 18, 159, 18, 189, 158, 158, 220, 192, 159,
- /* 1380 */ 137, 236, 192, 192, 192, 189, 74, 189, 159, 235,
- /* 1390 */ 159, 158, 22, 177, 201, 201, 159, 107, 158, 177,
- /* 1400 */ 159, 174, 158, 76, 174, 182, 174, 106, 182, 125,
- /* 1410 */ 174, 107, 177, 22, 159, 216, 215, 137, 159, 53,
- /* 1420 */ 216, 176, 215, 174, 174, 216, 215, 215, 174, 229,
- /* 1430 */ 216, 129, 224, 177, 126, 229, 127, 177, 128, 25,
- /* 1440 */ 162, 226, 26, 161, 13, 153, 6, 153, 151, 151,
- /* 1450 */ 151, 151, 205, 165, 178, 178, 165, 4, 3, 22,
- /* 1460 */ 165, 142, 15, 94, 202, 204, 203, 201, 16, 23,
- /* 1470 */ 249, 23, 120, 249, 246, 111, 131, 123, 20, 16,
- /* 1480 */ 1, 125, 123, 111, 56, 64, 37, 37, 131, 122,
- /* 1490 */ 1, 37, 5, 37, 22, 107, 26, 80, 140, 80,
- /* 1500 */ 87, 72, 107, 20, 24, 19, 112, 105, 23, 79,
- /* 1510 */ 22, 79, 22, 22, 22, 58, 22, 79, 23, 68,
- /* 1520 */ 23, 23, 26, 116, 22, 26, 23, 22, 122, 23,
- /* 1530 */ 23, 56, 64, 22, 124, 26, 26, 64, 64, 23,
- /* 1540 */ 23, 23, 23, 11, 23, 22, 26, 23, 22, 24,
- /* 1550 */ 1, 23, 22, 26, 251, 24, 23, 22, 122, 23,
- /* 1560 */ 23, 22, 15, 122, 122, 122, 23,
+ /* 0 */ 189, 211, 189, 189, 218, 189, 220, 189, 267, 268,
+ /* 10 */ 269, 189, 210, 189, 228, 189, 267, 268, 269, 19,
+ /* 20 */ 218, 189, 211, 212, 211, 212, 211, 211, 212, 211,
+ /* 30 */ 212, 31, 211, 211, 212, 211, 212, 288, 300, 39,
+ /* 40 */ 21, 189, 304, 43, 44, 45, 46, 47, 48, 49,
+ /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 225, 19,
+ /* 60 */ 189, 183, 184, 185, 186, 189, 248, 263, 236, 191,
+ /* 70 */ 248, 193, 248, 197, 208, 257, 262, 201, 200, 257,
+ /* 80 */ 200, 257, 81, 43, 44, 45, 46, 47, 48, 49,
+ /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 189, 80,
+ /* 100 */ 189, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 110 */ 110, 111, 234, 235, 234, 235, 305, 306, 305, 118,
+ /* 120 */ 307, 305, 306, 297, 298, 247, 86, 247, 88, 19,
+ /* 130 */ 259, 251, 252, 267, 268, 269, 26, 136, 137, 261,
+ /* 140 */ 121, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 150 */ 110, 111, 59, 43, 44, 45, 46, 47, 48, 49,
+ /* 160 */ 50, 51, 52, 53, 54, 55, 56, 57, 259, 291,
+ /* 170 */ 105, 106, 107, 108, 109, 110, 111, 158, 189, 69,
+ /* 180 */ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 190 */ 111, 107, 108, 109, 110, 111, 205, 206, 207, 19,
+ /* 200 */ 19, 54, 55, 56, 57, 58, 29, 114, 115, 116,
+ /* 210 */ 33, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 220 */ 110, 111, 233, 43, 44, 45, 46, 47, 48, 49,
+ /* 230 */ 50, 51, 52, 53, 54, 55, 56, 57, 19, 126,
+ /* 240 */ 127, 148, 65, 24, 214, 200, 59, 67, 101, 102,
+ /* 250 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 22,
+ /* 260 */ 189, 111, 43, 44, 45, 46, 47, 48, 49, 50,
+ /* 270 */ 51, 52, 53, 54, 55, 56, 57, 206, 207, 234,
+ /* 280 */ 235, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 290 */ 110, 111, 247, 76, 107, 114, 59, 267, 268, 269,
+ /* 300 */ 189, 114, 115, 116, 162, 163, 89, 19, 263, 92,
+ /* 310 */ 189, 23, 54, 55, 56, 57, 189, 206, 207, 22,
+ /* 320 */ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 330 */ 111, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+ /* 340 */ 52, 53, 54, 55, 56, 57, 19, 189, 277, 59,
+ /* 350 */ 23, 114, 115, 116, 46, 47, 48, 49, 61, 101,
+ /* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ /* 370 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 380 */ 53, 54, 55, 56, 57, 125, 126, 127, 277, 101,
+ /* 390 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ /* 400 */ 59, 189, 189, 276, 114, 115, 116, 117, 73, 59,
+ /* 410 */ 120, 121, 122, 72, 214, 19, 81, 259, 19, 23,
+ /* 420 */ 130, 81, 72, 24, 211, 212, 221, 119, 101, 102,
+ /* 430 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 43,
+ /* 440 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 450 */ 54, 55, 56, 57, 19, 114, 115, 116, 23, 208,
+ /* 460 */ 125, 248, 189, 189, 114, 115, 116, 267, 268, 269,
+ /* 470 */ 189, 136, 137, 189, 262, 22, 136, 137, 43, 44,
+ /* 480 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ /* 490 */ 55, 56, 57, 189, 95, 211, 212, 101, 102, 103,
+ /* 500 */ 104, 105, 106, 107, 108, 109, 110, 111, 59, 189,
+ /* 510 */ 111, 189, 59, 76, 294, 295, 117, 118, 119, 120,
+ /* 520 */ 121, 122, 123, 19, 87, 189, 89, 23, 129, 92,
+ /* 530 */ 279, 227, 248, 22, 189, 284, 101, 102, 103, 104,
+ /* 540 */ 105, 106, 107, 108, 109, 110, 111, 43, 44, 45,
+ /* 550 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ /* 560 */ 56, 57, 19, 114, 115, 116, 23, 114, 115, 116,
+ /* 570 */ 59, 117, 299, 300, 120, 121, 122, 304, 189, 189,
+ /* 580 */ 143, 189, 110, 111, 130, 22, 43, 44, 45, 46,
+ /* 590 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 600 */ 57, 211, 212, 211, 212, 101, 102, 103, 104, 105,
+ /* 610 */ 106, 107, 108, 109, 110, 111, 226, 189, 226, 189,
+ /* 620 */ 298, 132, 59, 134, 135, 114, 115, 116, 189, 59,
+ /* 630 */ 285, 19, 7, 8, 9, 23, 205, 206, 207, 211,
+ /* 640 */ 212, 211, 212, 221, 101, 102, 103, 104, 105, 106,
+ /* 650 */ 107, 108, 109, 110, 111, 43, 44, 45, 46, 47,
+ /* 660 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ /* 670 */ 19, 181, 182, 183, 184, 185, 186, 114, 115, 116,
+ /* 680 */ 189, 191, 133, 193, 114, 115, 116, 138, 299, 300,
+ /* 690 */ 200, 22, 201, 304, 43, 44, 45, 46, 47, 48,
+ /* 700 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 35,
+ /* 710 */ 189, 141, 189, 101, 102, 103, 104, 105, 106, 107,
+ /* 720 */ 108, 109, 110, 111, 234, 235, 22, 23, 59, 184,
+ /* 730 */ 26, 186, 211, 212, 211, 212, 191, 247, 193, 19,
+ /* 740 */ 66, 105, 106, 73, 189, 200, 189, 226, 74, 226,
+ /* 750 */ 22, 261, 101, 102, 103, 104, 105, 106, 107, 108,
+ /* 760 */ 109, 110, 111, 43, 44, 45, 46, 47, 48, 49,
+ /* 770 */ 50, 51, 52, 53, 54, 55, 56, 57, 189, 234,
+ /* 780 */ 235, 291, 19, 114, 115, 116, 150, 59, 152, 189,
+ /* 790 */ 233, 236, 247, 59, 189, 125, 126, 127, 59, 300,
+ /* 800 */ 211, 212, 128, 304, 100, 19, 261, 156, 45, 46,
+ /* 810 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ /* 820 */ 57, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ /* 830 */ 110, 111, 46, 233, 189, 189, 291, 248, 99, 189,
+ /* 840 */ 125, 126, 127, 115, 26, 200, 289, 230, 231, 115,
+ /* 850 */ 200, 16, 189, 114, 115, 189, 211, 212, 119, 221,
+ /* 860 */ 189, 211, 212, 258, 101, 102, 103, 104, 105, 106,
+ /* 870 */ 107, 108, 109, 110, 111, 189, 156, 211, 212, 234,
+ /* 880 */ 235, 189, 211, 212, 234, 235, 22, 201, 189, 150,
+ /* 890 */ 151, 152, 247, 248, 76, 16, 19, 247, 248, 113,
+ /* 900 */ 189, 24, 257, 211, 212, 189, 26, 89, 262, 223,
+ /* 910 */ 92, 225, 77, 189, 79, 129, 19, 53, 226, 248,
+ /* 920 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 930 */ 53, 54, 55, 56, 57, 236, 19, 271, 189, 99,
+ /* 940 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 950 */ 53, 54, 55, 56, 57, 115, 77, 59, 79, 119,
+ /* 960 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 970 */ 53, 54, 55, 56, 57, 259, 22, 23, 101, 102,
+ /* 980 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 59,
+ /* 990 */ 150, 151, 152, 158, 22, 244, 24, 246, 101, 102,
+ /* 1000 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 285,
+ /* 1010 */ 189, 189, 114, 115, 116, 200, 136, 137, 101, 102,
+ /* 1020 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 230,
+ /* 1030 */ 231, 59, 211, 212, 285, 105, 106, 189, 19, 141,
+ /* 1040 */ 234, 235, 239, 113, 114, 115, 116, 226, 118, 234,
+ /* 1050 */ 235, 189, 249, 247, 100, 189, 126, 23, 236, 107,
+ /* 1060 */ 26, 189, 247, 44, 45, 46, 47, 48, 49, 50,
+ /* 1070 */ 51, 52, 53, 54, 55, 56, 57, 211, 212, 59,
+ /* 1080 */ 150, 233, 152, 211, 212, 133, 12, 115, 189, 189,
+ /* 1090 */ 138, 19, 20, 300, 22, 233, 76, 304, 226, 11,
+ /* 1100 */ 208, 27, 22, 23, 200, 19, 26, 87, 36, 89,
+ /* 1110 */ 211, 212, 92, 300, 248, 189, 42, 304, 189, 250,
+ /* 1120 */ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+ /* 1130 */ 111, 59, 200, 233, 114, 115, 116, 63, 234, 235,
+ /* 1140 */ 235, 19, 20, 71, 22, 300, 189, 73, 200, 304,
+ /* 1150 */ 116, 247, 247, 81, 189, 200, 227, 26, 36, 234,
+ /* 1160 */ 235, 203, 204, 143, 200, 26, 234, 235, 194, 200,
+ /* 1170 */ 48, 99, 247, 66, 189, 141, 284, 105, 106, 247,
+ /* 1180 */ 100, 59, 234, 235, 112, 259, 114, 115, 116, 234,
+ /* 1190 */ 235, 119, 85, 71, 266, 247, 211, 212, 234, 235,
+ /* 1200 */ 114, 94, 247, 234, 235, 12, 266, 85, 136, 137,
+ /* 1210 */ 189, 247, 90, 26, 126, 127, 247, 189, 26, 22,
+ /* 1220 */ 27, 99, 150, 151, 152, 153, 154, 105, 106, 189,
+ /* 1230 */ 302, 303, 211, 212, 112, 42, 114, 115, 116, 211,
+ /* 1240 */ 212, 119, 302, 303, 19, 20, 189, 22, 274, 189,
+ /* 1250 */ 15, 144, 278, 189, 22, 23, 63, 189, 189, 203,
+ /* 1260 */ 204, 36, 136, 137, 155, 24, 157, 143, 211, 212,
+ /* 1270 */ 189, 140, 150, 151, 152, 153, 154, 0, 1, 2,
+ /* 1280 */ 211, 212, 5, 46, 59, 161, 147, 10, 11, 12,
+ /* 1290 */ 13, 14, 211, 212, 17, 60, 71, 189, 258, 189,
+ /* 1300 */ 59, 189, 105, 106, 189, 189, 189, 30, 116, 32,
+ /* 1310 */ 85, 124, 189, 251, 252, 90, 189, 40, 258, 211,
+ /* 1320 */ 212, 211, 212, 189, 99, 26, 211, 212, 211, 212,
+ /* 1330 */ 105, 106, 100, 141, 211, 212, 119, 112, 189, 114,
+ /* 1340 */ 115, 116, 23, 189, 119, 26, 129, 70, 189, 31,
+ /* 1350 */ 113, 19, 20, 24, 22, 78, 115, 39, 81, 189,
+ /* 1360 */ 211, 212, 26, 189, 22, 211, 212, 189, 36, 189,
+ /* 1370 */ 211, 212, 189, 189, 97, 150, 151, 152, 153, 154,
+ /* 1380 */ 127, 211, 212, 189, 189, 211, 212, 189, 189, 211,
+ /* 1390 */ 212, 59, 189, 189, 211, 212, 23, 189, 22, 26,
+ /* 1400 */ 24, 189, 149, 71, 189, 211, 212, 189, 131, 211,
+ /* 1410 */ 212, 189, 189, 136, 137, 211, 212, 85, 189, 211,
+ /* 1420 */ 212, 59, 90, 211, 212, 292, 293, 118, 119, 211,
+ /* 1430 */ 212, 99, 23, 211, 212, 26, 159, 105, 106, 189,
+ /* 1440 */ 211, 212, 143, 150, 112, 152, 114, 115, 116, 1,
+ /* 1450 */ 2, 119, 23, 5, 23, 26, 189, 26, 10, 11,
+ /* 1460 */ 12, 13, 14, 83, 84, 17, 253, 189, 139, 189,
+ /* 1470 */ 19, 20, 189, 22, 189, 189, 140, 115, 30, 59,
+ /* 1480 */ 32, 139, 150, 151, 152, 153, 154, 36, 40, 211,
+ /* 1490 */ 212, 211, 212, 59, 211, 212, 211, 212, 7, 8,
+ /* 1500 */ 19, 20, 189, 22, 150, 189, 152, 231, 281, 189,
+ /* 1510 */ 59, 189, 23, 189, 189, 26, 189, 36, 70, 189,
+ /* 1520 */ 23, 237, 71, 26, 211, 212, 78, 211, 212, 81,
+ /* 1530 */ 189, 211, 212, 211, 212, 115, 211, 212, 211, 212,
+ /* 1540 */ 59, 211, 212, 23, 23, 97, 26, 26, 23, 115,
+ /* 1550 */ 99, 26, 71, 189, 189, 189, 105, 106, 107, 23,
+ /* 1560 */ 189, 23, 26, 112, 26, 114, 115, 116, 189, 309,
+ /* 1570 */ 119, 23, 19, 20, 26, 22, 189, 211, 212, 131,
+ /* 1580 */ 99, 189, 211, 212, 136, 137, 105, 106, 189, 36,
+ /* 1590 */ 211, 212, 189, 112, 189, 114, 115, 116, 211, 212,
+ /* 1600 */ 119, 150, 151, 152, 153, 154, 189, 159, 23, 250,
+ /* 1610 */ 189, 26, 59, 189, 189, 189, 189, 189, 280, 189,
+ /* 1620 */ 250, 189, 189, 238, 71, 189, 189, 250, 211, 212,
+ /* 1630 */ 187, 150, 151, 152, 153, 154, 211, 212, 250, 290,
+ /* 1640 */ 240, 211, 212, 211, 212, 254, 286, 209, 254, 241,
+ /* 1650 */ 240, 254, 99, 286, 215, 220, 214, 244, 105, 106,
+ /* 1660 */ 214, 214, 244, 273, 224, 112, 192, 114, 115, 116,
+ /* 1670 */ 60, 290, 119, 5, 139, 196, 196, 38, 10, 11,
+ /* 1680 */ 12, 13, 14, 238, 240, 17, 196, 148, 287, 287,
+ /* 1690 */ 276, 113, 22, 147, 241, 43, 229, 241, 30, 18,
+ /* 1700 */ 32, 232, 232, 150, 151, 152, 153, 154, 40, 232,
+ /* 1710 */ 232, 196, 18, 195, 265, 265, 264, 241, 264, 196,
+ /* 1720 */ 155, 229, 229, 241, 241, 241, 195, 62, 196, 195,
+ /* 1730 */ 22, 113, 216, 196, 222, 195, 195, 282, 70, 196,
+ /* 1740 */ 283, 213, 216, 213, 64, 22, 78, 124, 219, 81,
+ /* 1750 */ 162, 111, 219, 142, 256, 213, 113, 255, 213, 256,
+ /* 1760 */ 216, 303, 215, 213, 213, 97, 255, 213, 216, 275,
+ /* 1770 */ 275, 222, 216, 256, 255, 196, 91, 82, 256, 255,
+ /* 1780 */ 308, 308, 146, 22, 143, 196, 155, 260, 25, 145,
+ /* 1790 */ 144, 199, 26, 198, 13, 190, 190, 6, 293, 131,
+ /* 1800 */ 188, 188, 245, 244, 136, 137, 245, 243, 242, 241,
+ /* 1810 */ 188, 202, 208, 217, 217, 260, 208, 4, 202, 3,
+ /* 1820 */ 22, 202, 208, 208, 160, 15, 209, 159, 270, 209,
+ /* 1830 */ 98, 16, 272, 208, 23, 23, 137, 148, 128, 20,
+ /* 1840 */ 140, 24, 16, 142, 1, 140, 149, 128, 61, 53,
+ /* 1850 */ 148, 37, 53, 53, 53, 128, 114, 34, 296, 296,
+ /* 1860 */ 139, 1, 5, 22, 113, 158, 26, 75, 41, 139,
+ /* 1870 */ 68, 68, 113, 24, 20, 19, 129, 123, 23, 96,
+ /* 1880 */ 22, 22, 37, 22, 22, 67, 22, 67, 59, 24,
+ /* 1890 */ 23, 28, 67, 147, 22, 26, 23, 23, 23, 23,
+ /* 1900 */ 22, 24, 23, 22, 24, 23, 139, 23, 114, 22,
+ /* 1910 */ 141, 26, 88, 75, 86, 44, 23, 34, 22, 75,
+ /* 1920 */ 34, 24, 34, 34, 34, 93, 34, 26, 26, 34,
+ /* 1930 */ 23, 23, 23, 23, 23, 11, 23, 22, 26, 22,
+ /* 1940 */ 22, 133, 23, 23, 22, 22, 139, 26, 139, 23,
+ /* 1950 */ 15, 1, 1, 310, 310, 310, 310, 310, 310, 310,
+ /* 1960 */ 139, 139, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 1970 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 1980 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 1990 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2000 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2010 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2020 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2030 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2040 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2050 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2060 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2070 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2080 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2090 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2100 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2110 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2120 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2130 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
+ /* 2140 */ 310, 310, 310,
};
-#define YY_SHIFT_USE_DFLT (1567)
-#define YY_SHIFT_COUNT (455)
-#define YY_SHIFT_MIN (-94)
-#define YY_SHIFT_MAX (1549)
-static const short yy_shift_ofst[] = {
- /* 0 */ 40, 599, 904, 612, 760, 760, 760, 760, 725, -19,
- /* 10 */ 16, 16, 100, 760, 760, 760, 760, 760, 760, 760,
- /* 20 */ 876, 876, 573, 542, 719, 600, 61, 137, 172, 207,
- /* 30 */ 242, 277, 312, 347, 382, 417, 459, 459, 459, 459,
- /* 40 */ 459, 459, 459, 459, 459, 459, 459, 459, 459, 459,
- /* 50 */ 459, 459, 459, 494, 459, 529, 564, 564, 705, 760,
- /* 60 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 70 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 80 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 90 */ 856, 760, 760, 760, 760, 760, 760, 760, 760, 760,
- /* 100 */ 760, 760, 760, 760, 987, 746, 746, 746, 746, 746,
- /* 110 */ 801, 23, 32, 949, 961, 979, 964, 964, 949, 73,
- /* 120 */ 113, -51, 1567, 1567, 1567, 536, 536, 536, 99, 99,
- /* 130 */ 813, 813, 667, 205, 240, 949, 949, 949, 949, 949,
- /* 140 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949,
- /* 150 */ 949, 949, 949, 949, 949, 332, 1011, 422, 422, 113,
- /* 160 */ 30, 30, 30, 30, 30, 30, 1567, 1567, 1567, 922,
- /* 170 */ -94, -94, 384, 613, 828, 420, 765, 804, 851, 949,
- /* 180 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949,
- /* 190 */ 949, 949, 949, 949, 949, 672, 672, 672, 949, 949,
- /* 200 */ 657, 949, 949, 949, -18, 949, 949, 994, 949, 949,
- /* 210 */ 949, 949, 949, 949, 949, 949, 949, 949, 772, 1118,
- /* 220 */ 712, 712, 712, 810, 45, 769, 1219, 1133, 418, 418,
- /* 230 */ 569, 1133, 569, 830, 607, 663, 882, 418, 693, 882,
- /* 240 */ 882, 848, 1152, 1065, 1286, 1238, 1238, 1287, 1287, 1238,
- /* 250 */ 1344, 1341, 1239, 1353, 1353, 1353, 1353, 1238, 1355, 1239,
- /* 260 */ 1344, 1341, 1341, 1239, 1238, 1355, 1243, 1312, 1238, 1238,
- /* 270 */ 1355, 1370, 1238, 1355, 1238, 1355, 1370, 1290, 1290, 1290,
- /* 280 */ 1327, 1370, 1290, 1301, 1290, 1327, 1290, 1290, 1284, 1304,
- /* 290 */ 1284, 1304, 1284, 1304, 1284, 1304, 1238, 1391, 1238, 1280,
- /* 300 */ 1370, 1366, 1366, 1370, 1302, 1308, 1310, 1309, 1239, 1414,
- /* 310 */ 1416, 1431, 1431, 1440, 1440, 1440, 1440, 1567, 1567, 1567,
- /* 320 */ 1567, 1567, 1567, 1567, 1567, 519, 978, 1210, 1225, 104,
- /* 330 */ 1141, 1189, 1246, 1248, 1251, 1252, 1253, 1257, 1258, 1273,
- /* 340 */ 1003, 1187, 1293, 1170, 1272, 1279, 1234, 1281, 1176, 1177,
- /* 350 */ 1289, 1242, 1195, 1453, 1455, 1437, 1319, 1447, 1369, 1452,
- /* 360 */ 1446, 1448, 1352, 1345, 1364, 1354, 1458, 1356, 1463, 1479,
- /* 370 */ 1359, 1357, 1449, 1450, 1454, 1456, 1372, 1428, 1421, 1367,
- /* 380 */ 1489, 1487, 1472, 1388, 1358, 1417, 1470, 1419, 1413, 1429,
- /* 390 */ 1395, 1480, 1483, 1486, 1394, 1402, 1488, 1430, 1490, 1491,
- /* 400 */ 1485, 1492, 1432, 1457, 1494, 1438, 1451, 1495, 1497, 1498,
- /* 410 */ 1496, 1407, 1502, 1503, 1505, 1499, 1406, 1506, 1507, 1475,
- /* 420 */ 1468, 1511, 1410, 1509, 1473, 1510, 1474, 1516, 1509, 1517,
- /* 430 */ 1518, 1519, 1520, 1521, 1523, 1532, 1524, 1526, 1525, 1527,
- /* 440 */ 1528, 1530, 1531, 1527, 1533, 1535, 1536, 1537, 1539, 1436,
- /* 450 */ 1441, 1442, 1443, 1543, 1547, 1549,
+#define YY_SHIFT_COUNT (552)
+#define YY_SHIFT_MIN (0)
+#define YY_SHIFT_MAX (1951)
+static const unsigned short int yy_shift_ofst[] = {
+ /* 0 */ 1448, 1277, 1668, 1072, 1072, 340, 1122, 1225, 1332, 1481,
+ /* 10 */ 1481, 1481, 335, 0, 0, 180, 897, 1481, 1481, 1481,
+ /* 20 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
+ /* 30 */ 930, 930, 1020, 1020, 290, 1, 340, 340, 340, 340,
+ /* 40 */ 340, 340, 40, 110, 219, 288, 327, 396, 435, 504,
+ /* 50 */ 543, 612, 651, 720, 877, 897, 897, 897, 897, 897,
+ /* 60 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 70 */ 897, 897, 897, 917, 897, 1019, 763, 763, 1451, 1481,
+ /* 80 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
+ /* 90 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
+ /* 100 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
+ /* 110 */ 1481, 1481, 1553, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
+ /* 120 */ 1481, 1481, 1481, 1481, 1481, 1481, 147, 258, 258, 258,
+ /* 130 */ 258, 258, 79, 65, 84, 449, 19, 786, 449, 636,
+ /* 140 */ 636, 449, 880, 880, 880, 880, 113, 142, 142, 472,
+ /* 150 */ 150, 1962, 1962, 399, 399, 399, 93, 237, 341, 237,
+ /* 160 */ 237, 1074, 1074, 437, 350, 704, 1080, 449, 449, 449,
+ /* 170 */ 449, 449, 449, 449, 449, 449, 449, 449, 449, 449,
+ /* 180 */ 449, 449, 449, 449, 449, 449, 449, 449, 818, 818,
+ /* 190 */ 449, 1088, 217, 217, 734, 734, 1124, 1126, 1962, 1962,
+ /* 200 */ 1962, 739, 840, 840, 453, 454, 511, 187, 563, 570,
+ /* 210 */ 898, 669, 449, 449, 449, 449, 449, 449, 449, 449,
+ /* 220 */ 449, 670, 449, 449, 449, 449, 449, 449, 449, 449,
+ /* 230 */ 449, 449, 449, 449, 674, 674, 674, 449, 449, 449,
+ /* 240 */ 449, 1034, 449, 449, 449, 972, 1107, 449, 449, 1193,
+ /* 250 */ 449, 449, 449, 449, 449, 449, 449, 449, 260, 177,
+ /* 260 */ 489, 1241, 1241, 1241, 1241, 1192, 489, 489, 952, 1197,
+ /* 270 */ 625, 1235, 1131, 181, 181, 1086, 1139, 1131, 1086, 1187,
+ /* 280 */ 1319, 1237, 1318, 1318, 1318, 181, 1299, 1299, 1109, 1336,
+ /* 290 */ 549, 1376, 1610, 1535, 1535, 1639, 1639, 1535, 1539, 1578,
+ /* 300 */ 1670, 1546, 1652, 1546, 1681, 1681, 1681, 1681, 1535, 1694,
+ /* 310 */ 1546, 1546, 1578, 1670, 1652, 1546, 1652, 1546, 1535, 1694,
+ /* 320 */ 1565, 1665, 1535, 1694, 1708, 1535, 1694, 1535, 1694, 1708,
+ /* 330 */ 1618, 1618, 1618, 1680, 1723, 1723, 1708, 1618, 1623, 1618,
+ /* 340 */ 1680, 1618, 1618, 1588, 1708, 1640, 1640, 1708, 1611, 1643,
+ /* 350 */ 1611, 1643, 1611, 1643, 1611, 1643, 1535, 1685, 1685, 1695,
+ /* 360 */ 1695, 1636, 1641, 1761, 1535, 1631, 1636, 1644, 1646, 1546,
+ /* 370 */ 1763, 1766, 1781, 1781, 1791, 1791, 1791, 1962, 1962, 1962,
+ /* 380 */ 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962,
+ /* 390 */ 1962, 1962, 308, 835, 954, 1232, 879, 715, 728, 1373,
+ /* 400 */ 864, 1329, 1253, 1409, 297, 1431, 1489, 1497, 1520, 1521,
+ /* 410 */ 1525, 1362, 1309, 1491, 1217, 1420, 1429, 1536, 1380, 1538,
+ /* 420 */ 1293, 1354, 1548, 1585, 1434, 1342, 1813, 1816, 1798, 1664,
+ /* 430 */ 1810, 1732, 1815, 1811, 1812, 1699, 1689, 1710, 1817, 1700,
+ /* 440 */ 1819, 1701, 1826, 1843, 1705, 1697, 1719, 1787, 1814, 1702,
+ /* 450 */ 1796, 1799, 1800, 1801, 1727, 1742, 1823, 1721, 1860, 1857,
+ /* 460 */ 1841, 1751, 1707, 1802, 1840, 1803, 1792, 1827, 1730, 1759,
+ /* 470 */ 1849, 1854, 1856, 1747, 1754, 1858, 1818, 1859, 1861, 1855,
+ /* 480 */ 1862, 1820, 1829, 1865, 1783, 1863, 1864, 1825, 1845, 1867,
+ /* 490 */ 1746, 1872, 1873, 1874, 1875, 1869, 1876, 1878, 1877, 1879,
+ /* 500 */ 1881, 1880, 1767, 1882, 1884, 1794, 1883, 1887, 1769, 1885,
+ /* 510 */ 1886, 1888, 1889, 1890, 1824, 1838, 1828, 1871, 1844, 1832,
+ /* 520 */ 1892, 1893, 1896, 1897, 1901, 1902, 1895, 1907, 1885, 1908,
+ /* 530 */ 1909, 1910, 1911, 1912, 1913, 1915, 1924, 1917, 1918, 1919,
+ /* 540 */ 1920, 1922, 1923, 1921, 1808, 1807, 1809, 1821, 1822, 1926,
+ /* 550 */ 1935, 1950, 1951,
};
-#define YY_REDUCE_USE_DFLT (-130)
-#define YY_REDUCE_COUNT (324)
-#define YY_REDUCE_MIN (-129)
-#define YY_REDUCE_MAX (1300)
+#define YY_REDUCE_COUNT (391)
+#define YY_REDUCE_MIN (-262)
+#define YY_REDUCE_MAX (1625)
static const short yy_reduce_ofst[] = {
- /* 0 */ -29, 566, 525, 605, -49, 307, 491, 533, 668, 435,
- /* 10 */ 601, 644, 148, 747, 786, 795, 419, 788, 827, 790,
- /* 20 */ 454, 832, 889, 495, 824, 734, 76, 76, 76, 76,
- /* 30 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
- /* 40 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
- /* 50 */ 76, 76, 76, 76, 76, 76, 76, 76, 783, 898,
- /* 60 */ 905, 907, 911, 921, 933, 936, 940, 943, 947, 950,
- /* 70 */ 952, 955, 958, 962, 965, 969, 974, 977, 980, 984,
- /* 80 */ 988, 991, 993, 996, 999, 1002, 1006, 1010, 1018, 1021,
- /* 90 */ 1024, 1028, 1032, 1034, 1036, 1040, 1046, 1051, 1058, 1062,
- /* 100 */ 1064, 1068, 1070, 1073, 76, 76, 76, 76, 76, 76,
- /* 110 */ 76, 76, 76, 855, 36, 523, 235, 416, 777, 76,
- /* 120 */ 278, 76, 76, 76, 76, 700, 700, 700, 150, 220,
- /* 130 */ 147, 217, 221, 306, 306, 611, 5, 535, 556, 620,
- /* 140 */ 720, 872, 897, 116, 864, 349, 1035, 1037, 404, 1047,
- /* 150 */ 992, -129, 1050, 492, 62, 722, 879, 1072, 1089, 808,
- /* 160 */ 1066, 1094, 1095, 1096, 1097, 1098, 776, 1054, 557, 57,
- /* 170 */ 112, 131, 167, 182, 250, 272, 291, 331, 364, 438,
- /* 180 */ 497, 517, 591, 653, 690, 739, 775, 798, 892, 908,
- /* 190 */ 924, 930, 1015, 1063, 1069, 355, 784, 799, 981, 1101,
- /* 200 */ 926, 1151, 1161, 1162, 945, 1164, 1166, 1128, 1168, 1171,
- /* 210 */ 1172, 250, 1173, 1174, 1175, 1178, 1180, 1181, 1088, 1102,
- /* 220 */ 1119, 1124, 1126, 926, 1131, 1139, 1188, 1140, 1129, 1130,
- /* 230 */ 1103, 1144, 1107, 1179, 1156, 1167, 1182, 1134, 1122, 1183,
- /* 240 */ 1184, 1150, 1153, 1197, 1111, 1202, 1203, 1123, 1125, 1205,
- /* 250 */ 1147, 1185, 1169, 1186, 1190, 1191, 1192, 1213, 1217, 1193,
- /* 260 */ 1157, 1196, 1198, 1194, 1220, 1218, 1145, 1154, 1229, 1231,
- /* 270 */ 1233, 1216, 1237, 1240, 1241, 1244, 1222, 1227, 1230, 1232,
- /* 280 */ 1223, 1235, 1236, 1245, 1249, 1226, 1250, 1254, 1199, 1201,
- /* 290 */ 1204, 1207, 1209, 1211, 1214, 1212, 1255, 1208, 1259, 1215,
- /* 300 */ 1256, 1200, 1206, 1260, 1247, 1261, 1263, 1262, 1266, 1278,
- /* 310 */ 1282, 1292, 1294, 1297, 1298, 1299, 1300, 1221, 1224, 1228,
- /* 320 */ 1288, 1291, 1276, 1277, 1295,
+ /* 0 */ 490, -122, 545, 645, 650, -120, -189, -187, -184, -182,
+ /* 10 */ -178, -176, 45, 30, 200, -251, -134, 390, 392, 521,
+ /* 20 */ 523, 213, 692, 821, 284, 589, 872, 666, 671, 866,
+ /* 30 */ 71, 111, 273, 389, 686, 815, 904, 932, 948, 955,
+ /* 40 */ 964, 969, -259, -259, -259, -259, -259, -259, -259, -259,
+ /* 50 */ -259, -259, -259, -259, -259, -259, -259, -259, -259, -259,
+ /* 60 */ -259, -259, -259, -259, -259, -259, -259, -259, -259, -259,
+ /* 70 */ -259, -259, -259, -259, -259, -259, -259, -259, 428, 430,
+ /* 80 */ 899, 985, 1021, 1028, 1057, 1069, 1081, 1108, 1110, 1115,
+ /* 90 */ 1117, 1123, 1149, 1154, 1159, 1170, 1174, 1178, 1183, 1194,
+ /* 100 */ 1198, 1204, 1208, 1212, 1218, 1222, 1229, 1278, 1280, 1283,
+ /* 110 */ 1285, 1313, 1316, 1320, 1322, 1325, 1327, 1330, 1366, 1371,
+ /* 120 */ 1379, 1387, 1417, 1425, 1430, 1432, -259, -259, -259, -259,
+ /* 130 */ -259, -259, -259, -259, -259, 557, 974, -214, -174, -9,
+ /* 140 */ 431, -124, 806, 925, 806, 925, 251, 928, 940, -259,
+ /* 150 */ -259, -259, -259, -198, -198, -198, 127, -186, -168, 212,
+ /* 160 */ 646, 617, 799, -262, 555, 220, 220, 491, 605, 1040,
+ /* 170 */ 1060, 699, -11, 600, 848, 862, 345, -129, 724, -91,
+ /* 180 */ 158, 749, 716, 900, 304, 822, 929, 926, 499, 793,
+ /* 190 */ 322, 892, 813, 845, 958, 1056, 751, 905, 1133, 1062,
+ /* 200 */ 803, -210, -185, -179, -148, -167, -89, 121, 274, 281,
+ /* 210 */ 320, 336, 439, 663, 711, 957, 965, 1064, 1068, 1112,
+ /* 220 */ 1116, -196, 1127, 1134, 1180, 1184, 1195, 1199, 1203, 1215,
+ /* 230 */ 1223, 1250, 1267, 1286, 205, 422, 638, 1324, 1341, 1364,
+ /* 240 */ 1365, 1213, 1392, 1399, 1403, 869, 1260, 1405, 1421, 1276,
+ /* 250 */ 1424, 121, 1426, 1427, 1428, 1433, 1436, 1437, 1227, 1338,
+ /* 260 */ 1284, 1359, 1370, 1377, 1388, 1213, 1284, 1284, 1385, 1438,
+ /* 270 */ 1443, 1349, 1400, 1391, 1394, 1360, 1408, 1410, 1367, 1439,
+ /* 280 */ 1440, 1435, 1442, 1446, 1447, 1397, 1413, 1418, 1390, 1444,
+ /* 290 */ 1445, 1474, 1381, 1479, 1480, 1401, 1402, 1490, 1414, 1449,
+ /* 300 */ 1452, 1453, 1467, 1456, 1469, 1470, 1477, 1478, 1515, 1518,
+ /* 310 */ 1476, 1482, 1450, 1454, 1492, 1483, 1493, 1484, 1523, 1531,
+ /* 320 */ 1457, 1455, 1532, 1534, 1516, 1537, 1540, 1543, 1541, 1526,
+ /* 330 */ 1528, 1530, 1542, 1512, 1529, 1533, 1544, 1545, 1547, 1550,
+ /* 340 */ 1549, 1551, 1554, 1458, 1552, 1494, 1495, 1556, 1498, 1502,
+ /* 350 */ 1503, 1511, 1517, 1519, 1522, 1524, 1579, 1472, 1473, 1527,
+ /* 360 */ 1555, 1557, 1559, 1558, 1589, 1560, 1561, 1564, 1566, 1568,
+ /* 370 */ 1592, 1595, 1605, 1606, 1612, 1613, 1622, 1562, 1563, 1505,
+ /* 380 */ 1609, 1604, 1608, 1614, 1615, 1616, 1596, 1597, 1617, 1620,
+ /* 390 */ 1625, 1619,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1281, 1271, 1271, 1271, 1203, 1203, 1203, 1203, 1271, 1096,
- /* 10 */ 1125, 1125, 1255, 1332, 1332, 1332, 1332, 1332, 1332, 1202,
- /* 20 */ 1332, 1332, 1332, 1332, 1271, 1100, 1131, 1332, 1332, 1332,
- /* 30 */ 1332, 1204, 1205, 1332, 1332, 1332, 1254, 1256, 1141, 1140,
- /* 40 */ 1139, 1138, 1237, 1112, 1136, 1129, 1133, 1204, 1198, 1199,
- /* 50 */ 1197, 1201, 1205, 1332, 1132, 1167, 1182, 1166, 1332, 1332,
- /* 60 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 70 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 80 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 90 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 100 */ 1332, 1332, 1332, 1332, 1176, 1181, 1188, 1180, 1177, 1169,
- /* 110 */ 1168, 1170, 1171, 1332, 1019, 1067, 1332, 1332, 1332, 1172,
- /* 120 */ 1332, 1173, 1185, 1184, 1183, 1262, 1289, 1288, 1332, 1332,
- /* 130 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 140 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 150 */ 1332, 1332, 1332, 1332, 1332, 1281, 1271, 1025, 1025, 1332,
- /* 160 */ 1271, 1271, 1271, 1271, 1271, 1271, 1267, 1100, 1091, 1332,
- /* 170 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 180 */ 1259, 1257, 1332, 1218, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 190 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 200 */ 1332, 1332, 1332, 1332, 1096, 1332, 1332, 1332, 1332, 1332,
- /* 210 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1283, 1332, 1232,
- /* 220 */ 1096, 1096, 1096, 1098, 1080, 1090, 1004, 1135, 1114, 1114,
- /* 230 */ 1321, 1135, 1321, 1042, 1303, 1039, 1125, 1114, 1200, 1125,
- /* 240 */ 1125, 1097, 1090, 1332, 1324, 1105, 1105, 1323, 1323, 1105,
- /* 250 */ 1146, 1070, 1135, 1076, 1076, 1076, 1076, 1105, 1016, 1135,
- /* 260 */ 1146, 1070, 1070, 1135, 1105, 1016, 1236, 1318, 1105, 1105,
- /* 270 */ 1016, 1211, 1105, 1016, 1105, 1016, 1211, 1068, 1068, 1068,
- /* 280 */ 1057, 1211, 1068, 1042, 1068, 1057, 1068, 1068, 1118, 1113,
- /* 290 */ 1118, 1113, 1118, 1113, 1118, 1113, 1105, 1206, 1105, 1332,
- /* 300 */ 1211, 1215, 1215, 1211, 1130, 1119, 1128, 1126, 1135, 1022,
- /* 310 */ 1060, 1286, 1286, 1282, 1282, 1282, 1282, 1329, 1329, 1267,
- /* 320 */ 1298, 1298, 1044, 1044, 1298, 1332, 1332, 1332, 1332, 1332,
- /* 330 */ 1332, 1293, 1332, 1220, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 340 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 350 */ 1332, 1332, 1152, 1332, 1000, 1264, 1332, 1332, 1263, 1332,
- /* 360 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 370 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1320,
- /* 380 */ 1332, 1332, 1332, 1332, 1332, 1332, 1235, 1234, 1332, 1332,
- /* 390 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 400 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
- /* 410 */ 1332, 1082, 1332, 1332, 1332, 1307, 1332, 1332, 1332, 1332,
- /* 420 */ 1332, 1332, 1332, 1127, 1332, 1120, 1332, 1332, 1311, 1332,
- /* 430 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1273,
- /* 440 */ 1332, 1332, 1332, 1272, 1332, 1332, 1332, 1332, 1332, 1154,
- /* 450 */ 1332, 1153, 1157, 1332, 1010, 1332,
+ /* 0 */ 1575, 1575, 1575, 1411, 1188, 1297, 1188, 1188, 1188, 1411,
+ /* 10 */ 1411, 1411, 1188, 1327, 1327, 1464, 1219, 1188, 1188, 1188,
+ /* 20 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1410, 1188, 1188,
+ /* 30 */ 1188, 1188, 1494, 1494, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 40 */ 1188, 1188, 1188, 1336, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 50 */ 1412, 1413, 1188, 1188, 1188, 1463, 1465, 1428, 1346, 1345,
+ /* 60 */ 1344, 1343, 1446, 1314, 1341, 1334, 1338, 1406, 1407, 1405,
+ /* 70 */ 1409, 1413, 1412, 1188, 1337, 1377, 1391, 1376, 1188, 1188,
+ /* 80 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 90 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 100 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 110 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 120 */ 1188, 1188, 1188, 1188, 1188, 1188, 1385, 1390, 1396, 1389,
+ /* 130 */ 1386, 1379, 1378, 1380, 1381, 1188, 1209, 1261, 1188, 1188,
+ /* 140 */ 1188, 1188, 1482, 1481, 1188, 1188, 1219, 1371, 1370, 1382,
+ /* 150 */ 1383, 1393, 1392, 1471, 1529, 1528, 1429, 1188, 1188, 1188,
+ /* 160 */ 1188, 1188, 1188, 1494, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 170 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 180 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1494, 1494,
+ /* 190 */ 1188, 1219, 1494, 1494, 1215, 1215, 1321, 1188, 1477, 1297,
+ /* 200 */ 1288, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 210 */ 1188, 1188, 1188, 1188, 1188, 1468, 1466, 1188, 1188, 1188,
+ /* 220 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 230 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 240 */ 1188, 1188, 1188, 1188, 1188, 1293, 1188, 1188, 1188, 1188,
+ /* 250 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1523, 1188, 1441,
+ /* 260 */ 1275, 1293, 1293, 1293, 1293, 1295, 1276, 1274, 1287, 1220,
+ /* 270 */ 1195, 1567, 1294, 1316, 1316, 1564, 1340, 1294, 1564, 1236,
+ /* 280 */ 1545, 1231, 1327, 1327, 1327, 1316, 1321, 1321, 1408, 1294,
+ /* 290 */ 1287, 1188, 1567, 1302, 1302, 1566, 1566, 1302, 1429, 1349,
+ /* 300 */ 1355, 1340, 1264, 1340, 1270, 1270, 1270, 1270, 1302, 1206,
+ /* 310 */ 1340, 1340, 1349, 1355, 1264, 1340, 1264, 1340, 1302, 1206,
+ /* 320 */ 1445, 1561, 1302, 1206, 1419, 1302, 1206, 1302, 1206, 1419,
+ /* 330 */ 1262, 1262, 1262, 1251, 1188, 1188, 1419, 1262, 1236, 1262,
+ /* 340 */ 1251, 1262, 1262, 1512, 1419, 1423, 1423, 1419, 1320, 1315,
+ /* 350 */ 1320, 1315, 1320, 1315, 1320, 1315, 1302, 1504, 1504, 1330,
+ /* 360 */ 1330, 1335, 1321, 1414, 1302, 1188, 1335, 1333, 1331, 1340,
+ /* 370 */ 1212, 1254, 1526, 1526, 1522, 1522, 1522, 1572, 1572, 1477,
+ /* 380 */ 1538, 1219, 1219, 1219, 1219, 1538, 1238, 1238, 1220, 1220,
+ /* 390 */ 1219, 1538, 1188, 1188, 1188, 1188, 1188, 1188, 1533, 1188,
+ /* 400 */ 1430, 1306, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 410 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 420 */ 1188, 1188, 1188, 1188, 1188, 1360, 1188, 1191, 1474, 1188,
+ /* 430 */ 1188, 1472, 1188, 1188, 1188, 1188, 1188, 1188, 1307, 1188,
+ /* 440 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 450 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1563, 1188, 1188,
+ /* 460 */ 1188, 1188, 1188, 1188, 1444, 1443, 1188, 1188, 1304, 1188,
+ /* 470 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 480 */ 1188, 1188, 1234, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 490 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 500 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1332,
+ /* 510 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 520 */ 1188, 1188, 1188, 1188, 1509, 1322, 1188, 1188, 1554, 1188,
+ /* 530 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ /* 540 */ 1188, 1188, 1188, 1549, 1278, 1362, 1188, 1361, 1365, 1188,
+ /* 550 */ 1200, 1188, 1188,
};
/********** End of lemon-generated parsing tables *****************************/
-/* The next table maps tokens (terminal symbols) into fallback tokens.
+/* The next table maps tokens (terminal symbols) into fallback tokens.
** If a construct like the following:
-**
+**
** %fallback ID X Y Z.
**
** appears in the grammar, then ID becomes a fallback token for X, Y,
@@ -133656,36 +155196,52 @@ static const YYACTIONTYPE yy_default[] = {
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 55, /* EXPLAIN => ID */
- 55, /* QUERY => ID */
- 55, /* PLAN => ID */
- 55, /* BEGIN => ID */
+ 59, /* EXPLAIN => ID */
+ 59, /* QUERY => ID */
+ 59, /* PLAN => ID */
+ 59, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 55, /* DEFERRED => ID */
- 55, /* IMMEDIATE => ID */
- 55, /* EXCLUSIVE => ID */
+ 59, /* DEFERRED => ID */
+ 59, /* IMMEDIATE => ID */
+ 59, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 55, /* END => ID */
- 55, /* ROLLBACK => ID */
- 55, /* SAVEPOINT => ID */
- 55, /* RELEASE => ID */
+ 59, /* END => ID */
+ 59, /* ROLLBACK => ID */
+ 59, /* SAVEPOINT => ID */
+ 59, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 55, /* IF => ID */
+ 59, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 55, /* TEMP => ID */
+ 59, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
- 55, /* WITHOUT => ID */
+ 59, /* WITHOUT => ID */
0, /* COMMA => nothing */
+ 59, /* ABORT => ID */
+ 59, /* ACTION => ID */
+ 59, /* AFTER => ID */
+ 59, /* ANALYZE => ID */
+ 59, /* ASC => ID */
+ 59, /* ATTACH => ID */
+ 59, /* BEFORE => ID */
+ 59, /* BY => ID */
+ 59, /* CASCADE => ID */
+ 59, /* CAST => ID */
+ 59, /* CONFLICT => ID */
+ 59, /* DATABASE => ID */
+ 59, /* DESC => ID */
+ 59, /* DETACH => ID */
+ 59, /* EACH => ID */
+ 59, /* FAIL => ID */
0, /* OR => nothing */
0, /* AND => nothing */
0, /* IS => nothing */
- 55, /* MATCH => ID */
- 55, /* LIKE_KW => ID */
+ 59, /* MATCH => ID */
+ 59, /* LIKE_KW => ID */
0, /* BETWEEN => nothing */
0, /* IN => nothing */
0, /* ISNULL => nothing */
@@ -133697,6 +155253,48 @@ static const YYCODETYPE yyFallback[] = {
0, /* LT => nothing */
0, /* GE => nothing */
0, /* ESCAPE => nothing */
+ 0, /* ID => nothing */
+ 59, /* COLUMNKW => ID */
+ 59, /* DO => ID */
+ 59, /* FOR => ID */
+ 59, /* IGNORE => ID */
+ 59, /* INITIALLY => ID */
+ 59, /* INSTEAD => ID */
+ 59, /* NO => ID */
+ 59, /* KEY => ID */
+ 59, /* OF => ID */
+ 59, /* OFFSET => ID */
+ 59, /* PRAGMA => ID */
+ 59, /* RAISE => ID */
+ 59, /* RECURSIVE => ID */
+ 59, /* REPLACE => ID */
+ 59, /* RESTRICT => ID */
+ 59, /* ROW => ID */
+ 59, /* ROWS => ID */
+ 59, /* TRIGGER => ID */
+ 59, /* VACUUM => ID */
+ 59, /* VIEW => ID */
+ 59, /* VIRTUAL => ID */
+ 59, /* WITH => ID */
+ 59, /* NULLS => ID */
+ 59, /* FIRST => ID */
+ 59, /* LAST => ID */
+ 59, /* CURRENT => ID */
+ 59, /* FOLLOWING => ID */
+ 59, /* PARTITION => ID */
+ 59, /* PRECEDING => ID */
+ 59, /* RANGE => ID */
+ 59, /* UNBOUNDED => ID */
+ 59, /* EXCLUDE => ID */
+ 59, /* GROUPS => ID */
+ 59, /* OTHERS => ID */
+ 59, /* TIES => ID */
+ 59, /* GENERATED => ID */
+ 59, /* ALWAYS => ID */
+ 59, /* REINDEX => ID */
+ 59, /* RENAME => ID */
+ 59, /* CTIME_KW => ID */
+ 0, /* ANY => nothing */
0, /* BITAND => nothing */
0, /* BITOR => nothing */
0, /* LSHIFT => nothing */
@@ -133709,47 +155307,74 @@ static const YYCODETYPE yyFallback[] = {
0, /* CONCAT => nothing */
0, /* COLLATE => nothing */
0, /* BITNOT => nothing */
- 0, /* ID => nothing */
+ 0, /* ON => nothing */
0, /* INDEXED => nothing */
- 55, /* ABORT => ID */
- 55, /* ACTION => ID */
- 55, /* AFTER => ID */
- 55, /* ANALYZE => ID */
- 55, /* ASC => ID */
- 55, /* ATTACH => ID */
- 55, /* BEFORE => ID */
- 55, /* BY => ID */
- 55, /* CASCADE => ID */
- 55, /* CAST => ID */
- 55, /* COLUMNKW => ID */
- 55, /* CONFLICT => ID */
- 55, /* DATABASE => ID */
- 55, /* DESC => ID */
- 55, /* DETACH => ID */
- 55, /* EACH => ID */
- 55, /* FAIL => ID */
- 55, /* FOR => ID */
- 55, /* IGNORE => ID */
- 55, /* INITIALLY => ID */
- 55, /* INSTEAD => ID */
- 55, /* NO => ID */
- 55, /* KEY => ID */
- 55, /* OF => ID */
- 55, /* OFFSET => ID */
- 55, /* PRAGMA => ID */
- 55, /* RAISE => ID */
- 55, /* RECURSIVE => ID */
- 55, /* REPLACE => ID */
- 55, /* RESTRICT => ID */
- 55, /* ROW => ID */
- 55, /* TRIGGER => ID */
- 55, /* VACUUM => ID */
- 55, /* VIEW => ID */
- 55, /* VIRTUAL => ID */
- 55, /* WITH => ID */
- 55, /* REINDEX => ID */
- 55, /* RENAME => ID */
- 55, /* CTIME_KW => ID */
+ 0, /* STRING => nothing */
+ 0, /* JOIN_KW => nothing */
+ 0, /* CONSTRAINT => nothing */
+ 0, /* DEFAULT => nothing */
+ 0, /* NULL => nothing */
+ 0, /* PRIMARY => nothing */
+ 0, /* UNIQUE => nothing */
+ 0, /* CHECK => nothing */
+ 0, /* REFERENCES => nothing */
+ 0, /* AUTOINCR => nothing */
+ 0, /* INSERT => nothing */
+ 0, /* DELETE => nothing */
+ 0, /* UPDATE => nothing */
+ 0, /* SET => nothing */
+ 0, /* DEFERRABLE => nothing */
+ 0, /* FOREIGN => nothing */
+ 0, /* DROP => nothing */
+ 0, /* UNION => nothing */
+ 0, /* ALL => nothing */
+ 0, /* EXCEPT => nothing */
+ 0, /* INTERSECT => nothing */
+ 0, /* SELECT => nothing */
+ 0, /* VALUES => nothing */
+ 0, /* DISTINCT => nothing */
+ 0, /* DOT => nothing */
+ 0, /* FROM => nothing */
+ 0, /* JOIN => nothing */
+ 0, /* USING => nothing */
+ 0, /* ORDER => nothing */
+ 0, /* GROUP => nothing */
+ 0, /* HAVING => nothing */
+ 0, /* LIMIT => nothing */
+ 0, /* WHERE => nothing */
+ 0, /* INTO => nothing */
+ 0, /* NOTHING => nothing */
+ 0, /* FLOAT => nothing */
+ 0, /* BLOB => nothing */
+ 0, /* INTEGER => nothing */
+ 0, /* VARIABLE => nothing */
+ 0, /* CASE => nothing */
+ 0, /* WHEN => nothing */
+ 0, /* THEN => nothing */
+ 0, /* ELSE => nothing */
+ 0, /* INDEX => nothing */
+ 0, /* ALTER => nothing */
+ 0, /* ADD => nothing */
+ 0, /* WINDOW => nothing */
+ 0, /* OVER => nothing */
+ 0, /* FILTER => nothing */
+ 0, /* COLUMN => nothing */
+ 0, /* AGG_FUNCTION => nothing */
+ 0, /* AGG_COLUMN => nothing */
+ 0, /* TRUEFALSE => nothing */
+ 0, /* ISNOT => nothing */
+ 0, /* FUNCTION => nothing */
+ 0, /* UMINUS => nothing */
+ 0, /* UPLUS => nothing */
+ 0, /* TRUTH => nothing */
+ 0, /* REGISTER => nothing */
+ 0, /* VECTOR => nothing */
+ 0, /* SELECT_COLUMN => nothing */
+ 0, /* IF_NULL_ROW => nothing */
+ 0, /* ASTERISK => nothing */
+ 0, /* SPAN => nothing */
+ 0, /* SPACE => nothing */
+ 0, /* ILLEGAL => nothing */
};
#endif /* YYFALLBACK */
@@ -133789,12 +155414,14 @@ struct yyParser {
int yyerrcnt; /* Shifts left before out of the error */
#endif
sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
+ sqlite3ParserCTX_SDECL /* A place to hold %extra_context */
#if YYSTACKDEPTH<=0
int yystksz; /* Current side of the stack */
yyStackEntry *yystack; /* The parser's stack */
yyStackEntry yystk0; /* First stack entry */
#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+ yyStackEntry *yystackEnd; /* Last entry in the stack */
#endif
};
typedef struct yyParser yyParser;
@@ -133806,10 +155433,10 @@ static char *yyTracePrompt = 0;
#endif /* NDEBUG */
#ifndef NDEBUG
-/*
+/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
+** by making either argument NULL
**
** Inputs:
** <ul>
@@ -133831,75 +155458,322 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){
}
#endif /* NDEBUG */
-#ifndef NDEBUG
+#if defined(YYCOVERAGE) || !defined(NDEBUG)
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
-static const char *const yyTokenName[] = {
- "$", "SEMI", "EXPLAIN", "QUERY",
- "PLAN", "BEGIN", "TRANSACTION", "DEFERRED",
- "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END",
- "ROLLBACK", "SAVEPOINT", "RELEASE", "TO",
- "TABLE", "CREATE", "IF", "NOT",
- "EXISTS", "TEMP", "LP", "RP",
- "AS", "WITHOUT", "COMMA", "OR",
- "AND", "IS", "MATCH", "LIKE_KW",
- "BETWEEN", "IN", "ISNULL", "NOTNULL",
- "NE", "EQ", "GT", "LE",
- "LT", "GE", "ESCAPE", "BITAND",
- "BITOR", "LSHIFT", "RSHIFT", "PLUS",
- "MINUS", "STAR", "SLASH", "REM",
- "CONCAT", "COLLATE", "BITNOT", "ID",
- "INDEXED", "ABORT", "ACTION", "AFTER",
- "ANALYZE", "ASC", "ATTACH", "BEFORE",
- "BY", "CASCADE", "CAST", "COLUMNKW",
- "CONFLICT", "DATABASE", "DESC", "DETACH",
- "EACH", "FAIL", "FOR", "IGNORE",
- "INITIALLY", "INSTEAD", "NO", "KEY",
- "OF", "OFFSET", "PRAGMA", "RAISE",
- "RECURSIVE", "REPLACE", "RESTRICT", "ROW",
- "TRIGGER", "VACUUM", "VIEW", "VIRTUAL",
- "WITH", "REINDEX", "RENAME", "CTIME_KW",
- "ANY", "STRING", "JOIN_KW", "CONSTRAINT",
- "DEFAULT", "NULL", "PRIMARY", "UNIQUE",
- "CHECK", "REFERENCES", "AUTOINCR", "ON",
- "INSERT", "DELETE", "UPDATE", "SET",
- "DEFERRABLE", "FOREIGN", "DROP", "UNION",
- "ALL", "EXCEPT", "INTERSECT", "SELECT",
- "VALUES", "DISTINCT", "DOT", "FROM",
- "JOIN", "USING", "ORDER", "GROUP",
- "HAVING", "LIMIT", "WHERE", "INTO",
- "FLOAT", "BLOB", "INTEGER", "VARIABLE",
- "CASE", "WHEN", "THEN", "ELSE",
- "INDEX", "ALTER", "ADD", "error",
- "input", "cmdlist", "ecmd", "explain",
- "cmdx", "cmd", "transtype", "trans_opt",
- "nm", "savepoint_opt", "create_table", "create_table_args",
- "createkw", "temp", "ifnotexists", "dbnm",
- "columnlist", "conslist_opt", "table_options", "select",
- "columnname", "carglist", "typetoken", "typename",
- "signed", "plus_num", "minus_num", "ccons",
- "term", "expr", "onconf", "sortorder",
- "autoinc", "eidlist_opt", "refargs", "defer_subclause",
- "refarg", "refact", "init_deferred_pred_opt", "conslist",
- "tconscomma", "tcons", "sortlist", "eidlist",
- "defer_subclause_opt", "orconf", "resolvetype", "raisetype",
- "ifexists", "fullname", "selectnowith", "oneselect",
- "with", "multiselect_op", "distinct", "selcollist",
- "from", "where_opt", "groupby_opt", "having_opt",
- "orderby_opt", "limit_opt", "values", "nexprlist",
- "exprlist", "sclp", "as", "seltablist",
- "stl_prefix", "joinop", "indexed_opt", "on_opt",
- "using_opt", "idlist", "setlist", "insert_cmd",
- "idlist_opt", "likeop", "between_op", "in_op",
- "paren_exprlist", "case_operand", "case_exprlist", "case_else",
- "uniqueflag", "collate", "nmnum", "trigger_decl",
- "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause",
- "when_clause", "trigger_cmd", "trnm", "tridxby",
- "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt",
- "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken",
- "lp", "anylist", "wqlist",
+static const char *const yyTokenName[] = {
+ /* 0 */ "$",
+ /* 1 */ "SEMI",
+ /* 2 */ "EXPLAIN",
+ /* 3 */ "QUERY",
+ /* 4 */ "PLAN",
+ /* 5 */ "BEGIN",
+ /* 6 */ "TRANSACTION",
+ /* 7 */ "DEFERRED",
+ /* 8 */ "IMMEDIATE",
+ /* 9 */ "EXCLUSIVE",
+ /* 10 */ "COMMIT",
+ /* 11 */ "END",
+ /* 12 */ "ROLLBACK",
+ /* 13 */ "SAVEPOINT",
+ /* 14 */ "RELEASE",
+ /* 15 */ "TO",
+ /* 16 */ "TABLE",
+ /* 17 */ "CREATE",
+ /* 18 */ "IF",
+ /* 19 */ "NOT",
+ /* 20 */ "EXISTS",
+ /* 21 */ "TEMP",
+ /* 22 */ "LP",
+ /* 23 */ "RP",
+ /* 24 */ "AS",
+ /* 25 */ "WITHOUT",
+ /* 26 */ "COMMA",
+ /* 27 */ "ABORT",
+ /* 28 */ "ACTION",
+ /* 29 */ "AFTER",
+ /* 30 */ "ANALYZE",
+ /* 31 */ "ASC",
+ /* 32 */ "ATTACH",
+ /* 33 */ "BEFORE",
+ /* 34 */ "BY",
+ /* 35 */ "CASCADE",
+ /* 36 */ "CAST",
+ /* 37 */ "CONFLICT",
+ /* 38 */ "DATABASE",
+ /* 39 */ "DESC",
+ /* 40 */ "DETACH",
+ /* 41 */ "EACH",
+ /* 42 */ "FAIL",
+ /* 43 */ "OR",
+ /* 44 */ "AND",
+ /* 45 */ "IS",
+ /* 46 */ "MATCH",
+ /* 47 */ "LIKE_KW",
+ /* 48 */ "BETWEEN",
+ /* 49 */ "IN",
+ /* 50 */ "ISNULL",
+ /* 51 */ "NOTNULL",
+ /* 52 */ "NE",
+ /* 53 */ "EQ",
+ /* 54 */ "GT",
+ /* 55 */ "LE",
+ /* 56 */ "LT",
+ /* 57 */ "GE",
+ /* 58 */ "ESCAPE",
+ /* 59 */ "ID",
+ /* 60 */ "COLUMNKW",
+ /* 61 */ "DO",
+ /* 62 */ "FOR",
+ /* 63 */ "IGNORE",
+ /* 64 */ "INITIALLY",
+ /* 65 */ "INSTEAD",
+ /* 66 */ "NO",
+ /* 67 */ "KEY",
+ /* 68 */ "OF",
+ /* 69 */ "OFFSET",
+ /* 70 */ "PRAGMA",
+ /* 71 */ "RAISE",
+ /* 72 */ "RECURSIVE",
+ /* 73 */ "REPLACE",
+ /* 74 */ "RESTRICT",
+ /* 75 */ "ROW",
+ /* 76 */ "ROWS",
+ /* 77 */ "TRIGGER",
+ /* 78 */ "VACUUM",
+ /* 79 */ "VIEW",
+ /* 80 */ "VIRTUAL",
+ /* 81 */ "WITH",
+ /* 82 */ "NULLS",
+ /* 83 */ "FIRST",
+ /* 84 */ "LAST",
+ /* 85 */ "CURRENT",
+ /* 86 */ "FOLLOWING",
+ /* 87 */ "PARTITION",
+ /* 88 */ "PRECEDING",
+ /* 89 */ "RANGE",
+ /* 90 */ "UNBOUNDED",
+ /* 91 */ "EXCLUDE",
+ /* 92 */ "GROUPS",
+ /* 93 */ "OTHERS",
+ /* 94 */ "TIES",
+ /* 95 */ "GENERATED",
+ /* 96 */ "ALWAYS",
+ /* 97 */ "REINDEX",
+ /* 98 */ "RENAME",
+ /* 99 */ "CTIME_KW",
+ /* 100 */ "ANY",
+ /* 101 */ "BITAND",
+ /* 102 */ "BITOR",
+ /* 103 */ "LSHIFT",
+ /* 104 */ "RSHIFT",
+ /* 105 */ "PLUS",
+ /* 106 */ "MINUS",
+ /* 107 */ "STAR",
+ /* 108 */ "SLASH",
+ /* 109 */ "REM",
+ /* 110 */ "CONCAT",
+ /* 111 */ "COLLATE",
+ /* 112 */ "BITNOT",
+ /* 113 */ "ON",
+ /* 114 */ "INDEXED",
+ /* 115 */ "STRING",
+ /* 116 */ "JOIN_KW",
+ /* 117 */ "CONSTRAINT",
+ /* 118 */ "DEFAULT",
+ /* 119 */ "NULL",
+ /* 120 */ "PRIMARY",
+ /* 121 */ "UNIQUE",
+ /* 122 */ "CHECK",
+ /* 123 */ "REFERENCES",
+ /* 124 */ "AUTOINCR",
+ /* 125 */ "INSERT",
+ /* 126 */ "DELETE",
+ /* 127 */ "UPDATE",
+ /* 128 */ "SET",
+ /* 129 */ "DEFERRABLE",
+ /* 130 */ "FOREIGN",
+ /* 131 */ "DROP",
+ /* 132 */ "UNION",
+ /* 133 */ "ALL",
+ /* 134 */ "EXCEPT",
+ /* 135 */ "INTERSECT",
+ /* 136 */ "SELECT",
+ /* 137 */ "VALUES",
+ /* 138 */ "DISTINCT",
+ /* 139 */ "DOT",
+ /* 140 */ "FROM",
+ /* 141 */ "JOIN",
+ /* 142 */ "USING",
+ /* 143 */ "ORDER",
+ /* 144 */ "GROUP",
+ /* 145 */ "HAVING",
+ /* 146 */ "LIMIT",
+ /* 147 */ "WHERE",
+ /* 148 */ "INTO",
+ /* 149 */ "NOTHING",
+ /* 150 */ "FLOAT",
+ /* 151 */ "BLOB",
+ /* 152 */ "INTEGER",
+ /* 153 */ "VARIABLE",
+ /* 154 */ "CASE",
+ /* 155 */ "WHEN",
+ /* 156 */ "THEN",
+ /* 157 */ "ELSE",
+ /* 158 */ "INDEX",
+ /* 159 */ "ALTER",
+ /* 160 */ "ADD",
+ /* 161 */ "WINDOW",
+ /* 162 */ "OVER",
+ /* 163 */ "FILTER",
+ /* 164 */ "COLUMN",
+ /* 165 */ "AGG_FUNCTION",
+ /* 166 */ "AGG_COLUMN",
+ /* 167 */ "TRUEFALSE",
+ /* 168 */ "ISNOT",
+ /* 169 */ "FUNCTION",
+ /* 170 */ "UMINUS",
+ /* 171 */ "UPLUS",
+ /* 172 */ "TRUTH",
+ /* 173 */ "REGISTER",
+ /* 174 */ "VECTOR",
+ /* 175 */ "SELECT_COLUMN",
+ /* 176 */ "IF_NULL_ROW",
+ /* 177 */ "ASTERISK",
+ /* 178 */ "SPAN",
+ /* 179 */ "SPACE",
+ /* 180 */ "ILLEGAL",
+ /* 181 */ "input",
+ /* 182 */ "cmdlist",
+ /* 183 */ "ecmd",
+ /* 184 */ "cmdx",
+ /* 185 */ "explain",
+ /* 186 */ "cmd",
+ /* 187 */ "transtype",
+ /* 188 */ "trans_opt",
+ /* 189 */ "nm",
+ /* 190 */ "savepoint_opt",
+ /* 191 */ "create_table",
+ /* 192 */ "create_table_args",
+ /* 193 */ "createkw",
+ /* 194 */ "temp",
+ /* 195 */ "ifnotexists",
+ /* 196 */ "dbnm",
+ /* 197 */ "columnlist",
+ /* 198 */ "conslist_opt",
+ /* 199 */ "table_options",
+ /* 200 */ "select",
+ /* 201 */ "columnname",
+ /* 202 */ "carglist",
+ /* 203 */ "typetoken",
+ /* 204 */ "typename",
+ /* 205 */ "signed",
+ /* 206 */ "plus_num",
+ /* 207 */ "minus_num",
+ /* 208 */ "scanpt",
+ /* 209 */ "scantok",
+ /* 210 */ "ccons",
+ /* 211 */ "term",
+ /* 212 */ "expr",
+ /* 213 */ "onconf",
+ /* 214 */ "sortorder",
+ /* 215 */ "autoinc",
+ /* 216 */ "eidlist_opt",
+ /* 217 */ "refargs",
+ /* 218 */ "defer_subclause",
+ /* 219 */ "generated",
+ /* 220 */ "refarg",
+ /* 221 */ "refact",
+ /* 222 */ "init_deferred_pred_opt",
+ /* 223 */ "conslist",
+ /* 224 */ "tconscomma",
+ /* 225 */ "tcons",
+ /* 226 */ "sortlist",
+ /* 227 */ "eidlist",
+ /* 228 */ "defer_subclause_opt",
+ /* 229 */ "orconf",
+ /* 230 */ "resolvetype",
+ /* 231 */ "raisetype",
+ /* 232 */ "ifexists",
+ /* 233 */ "fullname",
+ /* 234 */ "selectnowith",
+ /* 235 */ "oneselect",
+ /* 236 */ "wqlist",
+ /* 237 */ "multiselect_op",
+ /* 238 */ "distinct",
+ /* 239 */ "selcollist",
+ /* 240 */ "from",
+ /* 241 */ "where_opt",
+ /* 242 */ "groupby_opt",
+ /* 243 */ "having_opt",
+ /* 244 */ "orderby_opt",
+ /* 245 */ "limit_opt",
+ /* 246 */ "window_clause",
+ /* 247 */ "values",
+ /* 248 */ "nexprlist",
+ /* 249 */ "sclp",
+ /* 250 */ "as",
+ /* 251 */ "seltablist",
+ /* 252 */ "stl_prefix",
+ /* 253 */ "joinop",
+ /* 254 */ "indexed_opt",
+ /* 255 */ "on_opt",
+ /* 256 */ "using_opt",
+ /* 257 */ "exprlist",
+ /* 258 */ "xfullname",
+ /* 259 */ "idlist",
+ /* 260 */ "nulls",
+ /* 261 */ "with",
+ /* 262 */ "setlist",
+ /* 263 */ "insert_cmd",
+ /* 264 */ "idlist_opt",
+ /* 265 */ "upsert",
+ /* 266 */ "filter_over",
+ /* 267 */ "likeop",
+ /* 268 */ "between_op",
+ /* 269 */ "in_op",
+ /* 270 */ "paren_exprlist",
+ /* 271 */ "case_operand",
+ /* 272 */ "case_exprlist",
+ /* 273 */ "case_else",
+ /* 274 */ "uniqueflag",
+ /* 275 */ "collate",
+ /* 276 */ "vinto",
+ /* 277 */ "nmnum",
+ /* 278 */ "trigger_decl",
+ /* 279 */ "trigger_cmd_list",
+ /* 280 */ "trigger_time",
+ /* 281 */ "trigger_event",
+ /* 282 */ "foreach_clause",
+ /* 283 */ "when_clause",
+ /* 284 */ "trigger_cmd",
+ /* 285 */ "trnm",
+ /* 286 */ "tridxby",
+ /* 287 */ "database_kw_opt",
+ /* 288 */ "key_opt",
+ /* 289 */ "add_column_fullname",
+ /* 290 */ "kwcolumn_opt",
+ /* 291 */ "create_vtab",
+ /* 292 */ "vtabarglist",
+ /* 293 */ "vtabarg",
+ /* 294 */ "vtabargtoken",
+ /* 295 */ "lp",
+ /* 296 */ "anylist",
+ /* 297 */ "windowdefn_list",
+ /* 298 */ "windowdefn",
+ /* 299 */ "window",
+ /* 300 */ "frame_opt",
+ /* 301 */ "part_opt",
+ /* 302 */ "filter_clause",
+ /* 303 */ "over_clause",
+ /* 304 */ "range_or_rows",
+ /* 305 */ "frame_bound",
+ /* 306 */ "frame_bound_s",
+ /* 307 */ "frame_bound_e",
+ /* 308 */ "frame_exclude_opt",
+ /* 309 */ "frame_exclude",
};
-#endif /* NDEBUG */
+#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
@@ -133913,330 +155787,383 @@ static const char *const yyRuleName[] = {
/* 5 */ "transtype ::= DEFERRED",
/* 6 */ "transtype ::= IMMEDIATE",
/* 7 */ "transtype ::= EXCLUSIVE",
- /* 8 */ "cmd ::= COMMIT trans_opt",
- /* 9 */ "cmd ::= END trans_opt",
- /* 10 */ "cmd ::= ROLLBACK trans_opt",
- /* 11 */ "cmd ::= SAVEPOINT nm",
- /* 12 */ "cmd ::= RELEASE savepoint_opt nm",
- /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
- /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
- /* 15 */ "createkw ::= CREATE",
- /* 16 */ "ifnotexists ::=",
- /* 17 */ "ifnotexists ::= IF NOT EXISTS",
- /* 18 */ "temp ::= TEMP",
- /* 19 */ "temp ::=",
- /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
- /* 21 */ "create_table_args ::= AS select",
- /* 22 */ "table_options ::=",
- /* 23 */ "table_options ::= WITHOUT nm",
- /* 24 */ "columnname ::= nm typetoken",
- /* 25 */ "typetoken ::=",
- /* 26 */ "typetoken ::= typename LP signed RP",
- /* 27 */ "typetoken ::= typename LP signed COMMA signed RP",
- /* 28 */ "typename ::= typename ID|STRING",
- /* 29 */ "ccons ::= CONSTRAINT nm",
- /* 30 */ "ccons ::= DEFAULT term",
- /* 31 */ "ccons ::= DEFAULT LP expr RP",
- /* 32 */ "ccons ::= DEFAULT PLUS term",
- /* 33 */ "ccons ::= DEFAULT MINUS term",
- /* 34 */ "ccons ::= DEFAULT ID|INDEXED",
- /* 35 */ "ccons ::= NOT NULL onconf",
- /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
- /* 37 */ "ccons ::= UNIQUE onconf",
- /* 38 */ "ccons ::= CHECK LP expr RP",
- /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
- /* 40 */ "ccons ::= defer_subclause",
- /* 41 */ "ccons ::= COLLATE ID|STRING",
- /* 42 */ "autoinc ::=",
- /* 43 */ "autoinc ::= AUTOINCR",
- /* 44 */ "refargs ::=",
- /* 45 */ "refargs ::= refargs refarg",
- /* 46 */ "refarg ::= MATCH nm",
- /* 47 */ "refarg ::= ON INSERT refact",
- /* 48 */ "refarg ::= ON DELETE refact",
- /* 49 */ "refarg ::= ON UPDATE refact",
- /* 50 */ "refact ::= SET NULL",
- /* 51 */ "refact ::= SET DEFAULT",
- /* 52 */ "refact ::= CASCADE",
- /* 53 */ "refact ::= RESTRICT",
- /* 54 */ "refact ::= NO ACTION",
- /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 57 */ "init_deferred_pred_opt ::=",
- /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 60 */ "conslist_opt ::=",
- /* 61 */ "tconscomma ::= COMMA",
- /* 62 */ "tcons ::= CONSTRAINT nm",
- /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
- /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf",
- /* 65 */ "tcons ::= CHECK LP expr RP onconf",
- /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
- /* 67 */ "defer_subclause_opt ::=",
- /* 68 */ "onconf ::=",
- /* 69 */ "onconf ::= ON CONFLICT resolvetype",
- /* 70 */ "orconf ::=",
- /* 71 */ "orconf ::= OR resolvetype",
- /* 72 */ "resolvetype ::= IGNORE",
- /* 73 */ "resolvetype ::= REPLACE",
- /* 74 */ "cmd ::= DROP TABLE ifexists fullname",
- /* 75 */ "ifexists ::= IF EXISTS",
- /* 76 */ "ifexists ::=",
- /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
- /* 78 */ "cmd ::= DROP VIEW ifexists fullname",
- /* 79 */ "cmd ::= select",
- /* 80 */ "select ::= with selectnowith",
- /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect",
- /* 82 */ "multiselect_op ::= UNION",
- /* 83 */ "multiselect_op ::= UNION ALL",
- /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT",
- /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /* 86 */ "values ::= VALUES LP nexprlist RP",
- /* 87 */ "values ::= values COMMA LP exprlist RP",
- /* 88 */ "distinct ::= DISTINCT",
- /* 89 */ "distinct ::= ALL",
- /* 90 */ "distinct ::=",
- /* 91 */ "sclp ::=",
- /* 92 */ "selcollist ::= sclp expr as",
- /* 93 */ "selcollist ::= sclp STAR",
- /* 94 */ "selcollist ::= sclp nm DOT STAR",
- /* 95 */ "as ::= AS nm",
- /* 96 */ "as ::=",
- /* 97 */ "from ::=",
- /* 98 */ "from ::= FROM seltablist",
- /* 99 */ "stl_prefix ::= seltablist joinop",
- /* 100 */ "stl_prefix ::=",
- /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
- /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
- /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
- /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
- /* 105 */ "dbnm ::=",
- /* 106 */ "dbnm ::= DOT nm",
- /* 107 */ "fullname ::= nm dbnm",
- /* 108 */ "joinop ::= COMMA|JOIN",
- /* 109 */ "joinop ::= JOIN_KW JOIN",
- /* 110 */ "joinop ::= JOIN_KW nm JOIN",
- /* 111 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 112 */ "on_opt ::= ON expr",
- /* 113 */ "on_opt ::=",
- /* 114 */ "indexed_opt ::=",
- /* 115 */ "indexed_opt ::= INDEXED BY nm",
- /* 116 */ "indexed_opt ::= NOT INDEXED",
- /* 117 */ "using_opt ::= USING LP idlist RP",
- /* 118 */ "using_opt ::=",
- /* 119 */ "orderby_opt ::=",
- /* 120 */ "orderby_opt ::= ORDER BY sortlist",
- /* 121 */ "sortlist ::= sortlist COMMA expr sortorder",
- /* 122 */ "sortlist ::= expr sortorder",
- /* 123 */ "sortorder ::= ASC",
- /* 124 */ "sortorder ::= DESC",
- /* 125 */ "sortorder ::=",
- /* 126 */ "groupby_opt ::=",
- /* 127 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 128 */ "having_opt ::=",
- /* 129 */ "having_opt ::= HAVING expr",
- /* 130 */ "limit_opt ::=",
- /* 131 */ "limit_opt ::= LIMIT expr",
- /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 133 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
- /* 135 */ "where_opt ::=",
- /* 136 */ "where_opt ::= WHERE expr",
- /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
- /* 138 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
- /* 140 */ "setlist ::= nm EQ expr",
- /* 141 */ "setlist ::= LP idlist RP EQ expr",
- /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
- /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
- /* 144 */ "insert_cmd ::= INSERT orconf",
- /* 145 */ "insert_cmd ::= REPLACE",
- /* 146 */ "idlist_opt ::=",
- /* 147 */ "idlist_opt ::= LP idlist RP",
- /* 148 */ "idlist ::= idlist COMMA nm",
- /* 149 */ "idlist ::= nm",
- /* 150 */ "expr ::= LP expr RP",
- /* 151 */ "term ::= NULL",
- /* 152 */ "expr ::= ID|INDEXED",
- /* 153 */ "expr ::= JOIN_KW",
- /* 154 */ "expr ::= nm DOT nm",
- /* 155 */ "expr ::= nm DOT nm DOT nm",
- /* 156 */ "term ::= FLOAT|BLOB",
- /* 157 */ "term ::= STRING",
- /* 158 */ "term ::= INTEGER",
- /* 159 */ "expr ::= VARIABLE",
- /* 160 */ "expr ::= expr COLLATE ID|STRING",
- /* 161 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 162 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 163 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 164 */ "term ::= CTIME_KW",
- /* 165 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 166 */ "expr ::= expr AND expr",
- /* 167 */ "expr ::= expr OR expr",
- /* 168 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 169 */ "expr ::= expr EQ|NE expr",
- /* 170 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 171 */ "expr ::= expr PLUS|MINUS expr",
- /* 172 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 173 */ "expr ::= expr CONCAT expr",
- /* 174 */ "likeop ::= LIKE_KW|MATCH",
- /* 175 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 176 */ "expr ::= expr likeop expr",
- /* 177 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 178 */ "expr ::= expr ISNULL|NOTNULL",
- /* 179 */ "expr ::= expr NOT NULL",
- /* 180 */ "expr ::= expr IS expr",
- /* 181 */ "expr ::= expr IS NOT expr",
- /* 182 */ "expr ::= NOT expr",
- /* 183 */ "expr ::= BITNOT expr",
- /* 184 */ "expr ::= MINUS expr",
- /* 185 */ "expr ::= PLUS expr",
- /* 186 */ "between_op ::= BETWEEN",
- /* 187 */ "between_op ::= NOT BETWEEN",
- /* 188 */ "expr ::= expr between_op expr AND expr",
- /* 189 */ "in_op ::= IN",
- /* 190 */ "in_op ::= NOT IN",
- /* 191 */ "expr ::= expr in_op LP exprlist RP",
- /* 192 */ "expr ::= LP select RP",
- /* 193 */ "expr ::= expr in_op LP select RP",
- /* 194 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 195 */ "expr ::= EXISTS LP select RP",
- /* 196 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 197 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 198 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 199 */ "case_else ::= ELSE expr",
- /* 200 */ "case_else ::=",
- /* 201 */ "case_operand ::= expr",
- /* 202 */ "case_operand ::=",
- /* 203 */ "exprlist ::=",
- /* 204 */ "nexprlist ::= nexprlist COMMA expr",
- /* 205 */ "nexprlist ::= expr",
- /* 206 */ "paren_exprlist ::=",
- /* 207 */ "paren_exprlist ::= LP exprlist RP",
- /* 208 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 209 */ "uniqueflag ::= UNIQUE",
- /* 210 */ "uniqueflag ::=",
- /* 211 */ "eidlist_opt ::=",
- /* 212 */ "eidlist_opt ::= LP eidlist RP",
- /* 213 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 214 */ "eidlist ::= nm collate sortorder",
- /* 215 */ "collate ::=",
- /* 216 */ "collate ::= COLLATE ID|STRING",
- /* 217 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 218 */ "cmd ::= VACUUM",
- /* 219 */ "cmd ::= VACUUM nm",
- /* 220 */ "cmd ::= PRAGMA nm dbnm",
- /* 221 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 222 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 223 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 224 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 225 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 226 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 227 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 228 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 229 */ "trigger_time ::= BEFORE",
- /* 230 */ "trigger_time ::= AFTER",
- /* 231 */ "trigger_time ::= INSTEAD OF",
- /* 232 */ "trigger_time ::=",
- /* 233 */ "trigger_event ::= DELETE|INSERT",
- /* 234 */ "trigger_event ::= UPDATE",
- /* 235 */ "trigger_event ::= UPDATE OF idlist",
- /* 236 */ "when_clause ::=",
- /* 237 */ "when_clause ::= WHEN expr",
- /* 238 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 239 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 240 */ "trnm ::= nm DOT nm",
- /* 241 */ "tridxby ::= INDEXED BY nm",
- /* 242 */ "tridxby ::= NOT INDEXED",
- /* 243 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
- /* 244 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
- /* 245 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
- /* 246 */ "trigger_cmd ::= select",
- /* 247 */ "expr ::= RAISE LP IGNORE RP",
- /* 248 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 249 */ "raisetype ::= ROLLBACK",
- /* 250 */ "raisetype ::= ABORT",
- /* 251 */ "raisetype ::= FAIL",
- /* 252 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 253 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 254 */ "cmd ::= DETACH database_kw_opt expr",
- /* 255 */ "key_opt ::=",
- /* 256 */ "key_opt ::= KEY expr",
- /* 257 */ "cmd ::= REINDEX",
- /* 258 */ "cmd ::= REINDEX nm dbnm",
- /* 259 */ "cmd ::= ANALYZE",
- /* 260 */ "cmd ::= ANALYZE nm dbnm",
- /* 261 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 262 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 263 */ "add_column_fullname ::= fullname",
- /* 264 */ "cmd ::= create_vtab",
- /* 265 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 266 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 267 */ "vtabarg ::=",
- /* 268 */ "vtabargtoken ::= ANY",
- /* 269 */ "vtabargtoken ::= lp anylist RP",
- /* 270 */ "lp ::= LP",
- /* 271 */ "with ::=",
- /* 272 */ "with ::= WITH wqlist",
- /* 273 */ "with ::= WITH RECURSIVE wqlist",
- /* 274 */ "wqlist ::= nm eidlist_opt AS LP select RP",
- /* 275 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
- /* 276 */ "input ::= cmdlist",
- /* 277 */ "cmdlist ::= cmdlist ecmd",
- /* 278 */ "cmdlist ::= ecmd",
- /* 279 */ "ecmd ::= SEMI",
- /* 280 */ "ecmd ::= explain cmdx SEMI",
- /* 281 */ "explain ::=",
- /* 282 */ "trans_opt ::=",
- /* 283 */ "trans_opt ::= TRANSACTION",
- /* 284 */ "trans_opt ::= TRANSACTION nm",
- /* 285 */ "savepoint_opt ::= SAVEPOINT",
- /* 286 */ "savepoint_opt ::=",
- /* 287 */ "cmd ::= create_table create_table_args",
- /* 288 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 289 */ "columnlist ::= columnname carglist",
- /* 290 */ "nm ::= ID|INDEXED",
- /* 291 */ "nm ::= STRING",
- /* 292 */ "nm ::= JOIN_KW",
- /* 293 */ "typetoken ::= typename",
- /* 294 */ "typename ::= ID|STRING",
- /* 295 */ "signed ::= plus_num",
- /* 296 */ "signed ::= minus_num",
- /* 297 */ "carglist ::= carglist ccons",
- /* 298 */ "carglist ::=",
- /* 299 */ "ccons ::= NULL onconf",
- /* 300 */ "conslist_opt ::= COMMA conslist",
- /* 301 */ "conslist ::= conslist tconscomma tcons",
- /* 302 */ "conslist ::= tcons",
- /* 303 */ "tconscomma ::=",
- /* 304 */ "defer_subclause_opt ::= defer_subclause",
- /* 305 */ "resolvetype ::= raisetype",
- /* 306 */ "selectnowith ::= oneselect",
- /* 307 */ "oneselect ::= values",
- /* 308 */ "sclp ::= selcollist COMMA",
- /* 309 */ "as ::= ID|STRING",
- /* 310 */ "expr ::= term",
- /* 311 */ "exprlist ::= nexprlist",
- /* 312 */ "nmnum ::= plus_num",
- /* 313 */ "nmnum ::= nm",
- /* 314 */ "nmnum ::= ON",
- /* 315 */ "nmnum ::= DELETE",
- /* 316 */ "nmnum ::= DEFAULT",
- /* 317 */ "plus_num ::= INTEGER|FLOAT",
- /* 318 */ "foreach_clause ::=",
- /* 319 */ "foreach_clause ::= FOR EACH ROW",
- /* 320 */ "trnm ::= nm",
- /* 321 */ "tridxby ::=",
- /* 322 */ "database_kw_opt ::= DATABASE",
- /* 323 */ "database_kw_opt ::=",
- /* 324 */ "kwcolumn_opt ::=",
- /* 325 */ "kwcolumn_opt ::= COLUMNKW",
- /* 326 */ "vtabarglist ::= vtabarg",
- /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 328 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 329 */ "anylist ::=",
- /* 330 */ "anylist ::= anylist LP anylist RP",
- /* 331 */ "anylist ::= anylist ANY",
+ /* 8 */ "cmd ::= COMMIT|END trans_opt",
+ /* 9 */ "cmd ::= ROLLBACK trans_opt",
+ /* 10 */ "cmd ::= SAVEPOINT nm",
+ /* 11 */ "cmd ::= RELEASE savepoint_opt nm",
+ /* 12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
+ /* 13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
+ /* 14 */ "createkw ::= CREATE",
+ /* 15 */ "ifnotexists ::=",
+ /* 16 */ "ifnotexists ::= IF NOT EXISTS",
+ /* 17 */ "temp ::= TEMP",
+ /* 18 */ "temp ::=",
+ /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
+ /* 20 */ "create_table_args ::= AS select",
+ /* 21 */ "table_options ::=",
+ /* 22 */ "table_options ::= WITHOUT nm",
+ /* 23 */ "columnname ::= nm typetoken",
+ /* 24 */ "typetoken ::=",
+ /* 25 */ "typetoken ::= typename LP signed RP",
+ /* 26 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 27 */ "typename ::= typename ID|STRING",
+ /* 28 */ "scanpt ::=",
+ /* 29 */ "scantok ::=",
+ /* 30 */ "ccons ::= CONSTRAINT nm",
+ /* 31 */ "ccons ::= DEFAULT scantok term",
+ /* 32 */ "ccons ::= DEFAULT LP expr RP",
+ /* 33 */ "ccons ::= DEFAULT PLUS scantok term",
+ /* 34 */ "ccons ::= DEFAULT MINUS scantok term",
+ /* 35 */ "ccons ::= DEFAULT scantok ID|INDEXED",
+ /* 36 */ "ccons ::= NOT NULL onconf",
+ /* 37 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 38 */ "ccons ::= UNIQUE onconf",
+ /* 39 */ "ccons ::= CHECK LP expr RP",
+ /* 40 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
+ /* 41 */ "ccons ::= defer_subclause",
+ /* 42 */ "ccons ::= COLLATE ID|STRING",
+ /* 43 */ "generated ::= LP expr RP",
+ /* 44 */ "generated ::= LP expr RP ID",
+ /* 45 */ "autoinc ::=",
+ /* 46 */ "autoinc ::= AUTOINCR",
+ /* 47 */ "refargs ::=",
+ /* 48 */ "refargs ::= refargs refarg",
+ /* 49 */ "refarg ::= MATCH nm",
+ /* 50 */ "refarg ::= ON INSERT refact",
+ /* 51 */ "refarg ::= ON DELETE refact",
+ /* 52 */ "refarg ::= ON UPDATE refact",
+ /* 53 */ "refact ::= SET NULL",
+ /* 54 */ "refact ::= SET DEFAULT",
+ /* 55 */ "refact ::= CASCADE",
+ /* 56 */ "refact ::= RESTRICT",
+ /* 57 */ "refact ::= NO ACTION",
+ /* 58 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 59 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 60 */ "init_deferred_pred_opt ::=",
+ /* 61 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 62 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 63 */ "conslist_opt ::=",
+ /* 64 */ "tconscomma ::= COMMA",
+ /* 65 */ "tcons ::= CONSTRAINT nm",
+ /* 66 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
+ /* 67 */ "tcons ::= UNIQUE LP sortlist RP onconf",
+ /* 68 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 69 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
+ /* 70 */ "defer_subclause_opt ::=",
+ /* 71 */ "onconf ::=",
+ /* 72 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 73 */ "orconf ::=",
+ /* 74 */ "orconf ::= OR resolvetype",
+ /* 75 */ "resolvetype ::= IGNORE",
+ /* 76 */ "resolvetype ::= REPLACE",
+ /* 77 */ "cmd ::= DROP TABLE ifexists fullname",
+ /* 78 */ "ifexists ::= IF EXISTS",
+ /* 79 */ "ifexists ::=",
+ /* 80 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
+ /* 81 */ "cmd ::= DROP VIEW ifexists fullname",
+ /* 82 */ "cmd ::= select",
+ /* 83 */ "select ::= WITH wqlist selectnowith",
+ /* 84 */ "select ::= WITH RECURSIVE wqlist selectnowith",
+ /* 85 */ "select ::= selectnowith",
+ /* 86 */ "selectnowith ::= selectnowith multiselect_op oneselect",
+ /* 87 */ "multiselect_op ::= UNION",
+ /* 88 */ "multiselect_op ::= UNION ALL",
+ /* 89 */ "multiselect_op ::= EXCEPT|INTERSECT",
+ /* 90 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 91 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
+ /* 92 */ "values ::= VALUES LP nexprlist RP",
+ /* 93 */ "values ::= values COMMA LP nexprlist RP",
+ /* 94 */ "distinct ::= DISTINCT",
+ /* 95 */ "distinct ::= ALL",
+ /* 96 */ "distinct ::=",
+ /* 97 */ "sclp ::=",
+ /* 98 */ "selcollist ::= sclp scanpt expr scanpt as",
+ /* 99 */ "selcollist ::= sclp scanpt STAR",
+ /* 100 */ "selcollist ::= sclp scanpt nm DOT STAR",
+ /* 101 */ "as ::= AS nm",
+ /* 102 */ "as ::=",
+ /* 103 */ "from ::=",
+ /* 104 */ "from ::= FROM seltablist",
+ /* 105 */ "stl_prefix ::= seltablist joinop",
+ /* 106 */ "stl_prefix ::=",
+ /* 107 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
+ /* 108 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
+ /* 109 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
+ /* 110 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
+ /* 111 */ "dbnm ::=",
+ /* 112 */ "dbnm ::= DOT nm",
+ /* 113 */ "fullname ::= nm",
+ /* 114 */ "fullname ::= nm DOT nm",
+ /* 115 */ "xfullname ::= nm",
+ /* 116 */ "xfullname ::= nm DOT nm",
+ /* 117 */ "xfullname ::= nm DOT nm AS nm",
+ /* 118 */ "xfullname ::= nm AS nm",
+ /* 119 */ "joinop ::= COMMA|JOIN",
+ /* 120 */ "joinop ::= JOIN_KW JOIN",
+ /* 121 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 122 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 123 */ "on_opt ::= ON expr",
+ /* 124 */ "on_opt ::=",
+ /* 125 */ "indexed_opt ::=",
+ /* 126 */ "indexed_opt ::= INDEXED BY nm",
+ /* 127 */ "indexed_opt ::= NOT INDEXED",
+ /* 128 */ "using_opt ::= USING LP idlist RP",
+ /* 129 */ "using_opt ::=",
+ /* 130 */ "orderby_opt ::=",
+ /* 131 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 132 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
+ /* 133 */ "sortlist ::= expr sortorder nulls",
+ /* 134 */ "sortorder ::= ASC",
+ /* 135 */ "sortorder ::= DESC",
+ /* 136 */ "sortorder ::=",
+ /* 137 */ "nulls ::= NULLS FIRST",
+ /* 138 */ "nulls ::= NULLS LAST",
+ /* 139 */ "nulls ::=",
+ /* 140 */ "groupby_opt ::=",
+ /* 141 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 142 */ "having_opt ::=",
+ /* 143 */ "having_opt ::= HAVING expr",
+ /* 144 */ "limit_opt ::=",
+ /* 145 */ "limit_opt ::= LIMIT expr",
+ /* 146 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 147 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 148 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt",
+ /* 149 */ "where_opt ::=",
+ /* 150 */ "where_opt ::= WHERE expr",
+ /* 151 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt",
+ /* 152 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 153 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
+ /* 154 */ "setlist ::= nm EQ expr",
+ /* 155 */ "setlist ::= LP idlist RP EQ expr",
+ /* 156 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
+ /* 157 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES",
+ /* 158 */ "upsert ::=",
+ /* 159 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt",
+ /* 160 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING",
+ /* 161 */ "upsert ::= ON CONFLICT DO NOTHING",
+ /* 162 */ "insert_cmd ::= INSERT orconf",
+ /* 163 */ "insert_cmd ::= REPLACE",
+ /* 164 */ "idlist_opt ::=",
+ /* 165 */ "idlist_opt ::= LP idlist RP",
+ /* 166 */ "idlist ::= idlist COMMA nm",
+ /* 167 */ "idlist ::= nm",
+ /* 168 */ "expr ::= LP expr RP",
+ /* 169 */ "expr ::= ID|INDEXED",
+ /* 170 */ "expr ::= JOIN_KW",
+ /* 171 */ "expr ::= nm DOT nm",
+ /* 172 */ "expr ::= nm DOT nm DOT nm",
+ /* 173 */ "term ::= NULL|FLOAT|BLOB",
+ /* 174 */ "term ::= STRING",
+ /* 175 */ "term ::= INTEGER",
+ /* 176 */ "expr ::= VARIABLE",
+ /* 177 */ "expr ::= expr COLLATE ID|STRING",
+ /* 178 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 179 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
+ /* 180 */ "expr ::= ID|INDEXED LP STAR RP",
+ /* 181 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
+ /* 182 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
+ /* 183 */ "term ::= CTIME_KW",
+ /* 184 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 185 */ "expr ::= expr AND expr",
+ /* 186 */ "expr ::= expr OR expr",
+ /* 187 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 188 */ "expr ::= expr EQ|NE expr",
+ /* 189 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 190 */ "expr ::= expr PLUS|MINUS expr",
+ /* 191 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 192 */ "expr ::= expr CONCAT expr",
+ /* 193 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 194 */ "expr ::= expr likeop expr",
+ /* 195 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 196 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 197 */ "expr ::= expr NOT NULL",
+ /* 198 */ "expr ::= expr IS expr",
+ /* 199 */ "expr ::= expr IS NOT expr",
+ /* 200 */ "expr ::= NOT expr",
+ /* 201 */ "expr ::= BITNOT expr",
+ /* 202 */ "expr ::= PLUS|MINUS expr",
+ /* 203 */ "between_op ::= BETWEEN",
+ /* 204 */ "between_op ::= NOT BETWEEN",
+ /* 205 */ "expr ::= expr between_op expr AND expr",
+ /* 206 */ "in_op ::= IN",
+ /* 207 */ "in_op ::= NOT IN",
+ /* 208 */ "expr ::= expr in_op LP exprlist RP",
+ /* 209 */ "expr ::= LP select RP",
+ /* 210 */ "expr ::= expr in_op LP select RP",
+ /* 211 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 212 */ "expr ::= EXISTS LP select RP",
+ /* 213 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 214 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 215 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 216 */ "case_else ::= ELSE expr",
+ /* 217 */ "case_else ::=",
+ /* 218 */ "case_operand ::= expr",
+ /* 219 */ "case_operand ::=",
+ /* 220 */ "exprlist ::=",
+ /* 221 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 222 */ "nexprlist ::= expr",
+ /* 223 */ "paren_exprlist ::=",
+ /* 224 */ "paren_exprlist ::= LP exprlist RP",
+ /* 225 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 226 */ "uniqueflag ::= UNIQUE",
+ /* 227 */ "uniqueflag ::=",
+ /* 228 */ "eidlist_opt ::=",
+ /* 229 */ "eidlist_opt ::= LP eidlist RP",
+ /* 230 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 231 */ "eidlist ::= nm collate sortorder",
+ /* 232 */ "collate ::=",
+ /* 233 */ "collate ::= COLLATE ID|STRING",
+ /* 234 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 235 */ "cmd ::= VACUUM vinto",
+ /* 236 */ "cmd ::= VACUUM nm vinto",
+ /* 237 */ "vinto ::= INTO expr",
+ /* 238 */ "vinto ::=",
+ /* 239 */ "cmd ::= PRAGMA nm dbnm",
+ /* 240 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 241 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 242 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 243 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 244 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 245 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 246 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 247 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 248 */ "trigger_time ::= BEFORE|AFTER",
+ /* 249 */ "trigger_time ::= INSTEAD OF",
+ /* 250 */ "trigger_time ::=",
+ /* 251 */ "trigger_event ::= DELETE|INSERT",
+ /* 252 */ "trigger_event ::= UPDATE",
+ /* 253 */ "trigger_event ::= UPDATE OF idlist",
+ /* 254 */ "when_clause ::=",
+ /* 255 */ "when_clause ::= WHEN expr",
+ /* 256 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 257 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 258 */ "trnm ::= nm DOT nm",
+ /* 259 */ "tridxby ::= INDEXED BY nm",
+ /* 260 */ "tridxby ::= NOT INDEXED",
+ /* 261 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
+ /* 262 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
+ /* 263 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
+ /* 264 */ "trigger_cmd ::= scanpt select scanpt",
+ /* 265 */ "expr ::= RAISE LP IGNORE RP",
+ /* 266 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 267 */ "raisetype ::= ROLLBACK",
+ /* 268 */ "raisetype ::= ABORT",
+ /* 269 */ "raisetype ::= FAIL",
+ /* 270 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 271 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 272 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 273 */ "key_opt ::=",
+ /* 274 */ "key_opt ::= KEY expr",
+ /* 275 */ "cmd ::= REINDEX",
+ /* 276 */ "cmd ::= REINDEX nm dbnm",
+ /* 277 */ "cmd ::= ANALYZE",
+ /* 278 */ "cmd ::= ANALYZE nm dbnm",
+ /* 279 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 280 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 281 */ "add_column_fullname ::= fullname",
+ /* 282 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
+ /* 283 */ "cmd ::= create_vtab",
+ /* 284 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 285 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 286 */ "vtabarg ::=",
+ /* 287 */ "vtabargtoken ::= ANY",
+ /* 288 */ "vtabargtoken ::= lp anylist RP",
+ /* 289 */ "lp ::= LP",
+ /* 290 */ "with ::= WITH wqlist",
+ /* 291 */ "with ::= WITH RECURSIVE wqlist",
+ /* 292 */ "wqlist ::= nm eidlist_opt AS LP select RP",
+ /* 293 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
+ /* 294 */ "windowdefn_list ::= windowdefn",
+ /* 295 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 296 */ "windowdefn ::= nm AS LP window RP",
+ /* 297 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 298 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 299 */ "window ::= ORDER BY sortlist frame_opt",
+ /* 300 */ "window ::= nm ORDER BY sortlist frame_opt",
+ /* 301 */ "window ::= frame_opt",
+ /* 302 */ "window ::= nm frame_opt",
+ /* 303 */ "frame_opt ::=",
+ /* 304 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
+ /* 305 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
+ /* 306 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
+ /* 307 */ "frame_bound_s ::= frame_bound",
+ /* 308 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
+ /* 309 */ "frame_bound_e ::= frame_bound",
+ /* 310 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
+ /* 311 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
+ /* 312 */ "frame_bound ::= CURRENT ROW",
+ /* 313 */ "frame_exclude_opt ::=",
+ /* 314 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
+ /* 315 */ "frame_exclude ::= NO OTHERS",
+ /* 316 */ "frame_exclude ::= CURRENT ROW",
+ /* 317 */ "frame_exclude ::= GROUP|TIES",
+ /* 318 */ "window_clause ::= WINDOW windowdefn_list",
+ /* 319 */ "filter_over ::= filter_clause over_clause",
+ /* 320 */ "filter_over ::= over_clause",
+ /* 321 */ "filter_over ::= filter_clause",
+ /* 322 */ "over_clause ::= OVER LP window RP",
+ /* 323 */ "over_clause ::= OVER nm",
+ /* 324 */ "filter_clause ::= FILTER LP WHERE expr RP",
+ /* 325 */ "input ::= cmdlist",
+ /* 326 */ "cmdlist ::= cmdlist ecmd",
+ /* 327 */ "cmdlist ::= ecmd",
+ /* 328 */ "ecmd ::= SEMI",
+ /* 329 */ "ecmd ::= cmdx SEMI",
+ /* 330 */ "ecmd ::= explain cmdx SEMI",
+ /* 331 */ "trans_opt ::=",
+ /* 332 */ "trans_opt ::= TRANSACTION",
+ /* 333 */ "trans_opt ::= TRANSACTION nm",
+ /* 334 */ "savepoint_opt ::= SAVEPOINT",
+ /* 335 */ "savepoint_opt ::=",
+ /* 336 */ "cmd ::= create_table create_table_args",
+ /* 337 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 338 */ "columnlist ::= columnname carglist",
+ /* 339 */ "nm ::= ID|INDEXED",
+ /* 340 */ "nm ::= STRING",
+ /* 341 */ "nm ::= JOIN_KW",
+ /* 342 */ "typetoken ::= typename",
+ /* 343 */ "typename ::= ID|STRING",
+ /* 344 */ "signed ::= plus_num",
+ /* 345 */ "signed ::= minus_num",
+ /* 346 */ "carglist ::= carglist ccons",
+ /* 347 */ "carglist ::=",
+ /* 348 */ "ccons ::= NULL onconf",
+ /* 349 */ "ccons ::= GENERATED ALWAYS AS generated",
+ /* 350 */ "ccons ::= AS generated",
+ /* 351 */ "conslist_opt ::= COMMA conslist",
+ /* 352 */ "conslist ::= conslist tconscomma tcons",
+ /* 353 */ "conslist ::= tcons",
+ /* 354 */ "tconscomma ::=",
+ /* 355 */ "defer_subclause_opt ::= defer_subclause",
+ /* 356 */ "resolvetype ::= raisetype",
+ /* 357 */ "selectnowith ::= oneselect",
+ /* 358 */ "oneselect ::= values",
+ /* 359 */ "sclp ::= selcollist COMMA",
+ /* 360 */ "as ::= ID|STRING",
+ /* 361 */ "expr ::= term",
+ /* 362 */ "likeop ::= LIKE_KW|MATCH",
+ /* 363 */ "exprlist ::= nexprlist",
+ /* 364 */ "nmnum ::= plus_num",
+ /* 365 */ "nmnum ::= nm",
+ /* 366 */ "nmnum ::= ON",
+ /* 367 */ "nmnum ::= DELETE",
+ /* 368 */ "nmnum ::= DEFAULT",
+ /* 369 */ "plus_num ::= INTEGER|FLOAT",
+ /* 370 */ "foreach_clause ::=",
+ /* 371 */ "foreach_clause ::= FOR EACH ROW",
+ /* 372 */ "trnm ::= nm",
+ /* 373 */ "tridxby ::=",
+ /* 374 */ "database_kw_opt ::= DATABASE",
+ /* 375 */ "database_kw_opt ::=",
+ /* 376 */ "kwcolumn_opt ::=",
+ /* 377 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 378 */ "vtabarglist ::= vtabarg",
+ /* 379 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 380 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 381 */ "anylist ::=",
+ /* 382 */ "anylist ::= anylist LP anylist RP",
+ /* 383 */ "anylist ::= anylist ANY",
+ /* 384 */ "with ::=",
};
#endif /* NDEBUG */
@@ -134270,7 +156197,7 @@ static int yyGrowStack(yyParser *p){
#endif
p->yystksz = newSize;
}
- return pNew==0;
+ return pNew==0;
}
#endif
@@ -134283,7 +156210,36 @@ static int yyGrowStack(yyParser *p){
# define YYMALLOCARGTYPE size_t
#endif
-/*
+/* Initialize a new parser that has already been allocated.
+*/
+SQLITE_PRIVATE void sqlite3ParserInit(void *yypRawParser sqlite3ParserCTX_PDECL){
+ yyParser *yypParser = (yyParser*)yypRawParser;
+ sqlite3ParserCTX_STORE
+#ifdef YYTRACKMAXSTACKDEPTH
+ yypParser->yyhwm = 0;
+#endif
+#if YYSTACKDEPTH<=0
+ yypParser->yytos = NULL;
+ yypParser->yystack = NULL;
+ yypParser->yystksz = 0;
+ if( yyGrowStack(yypParser) ){
+ yypParser->yystack = &yypParser->yystk0;
+ yypParser->yystksz = 1;
+ }
+#endif
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ yypParser->yytos = yypParser->yystack;
+ yypParser->yystack[0].stateno = 0;
+ yypParser->yystack[0].major = 0;
+#if YYSTACKDEPTH>0
+ yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
+#endif
+}
+
+#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
+/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
@@ -134295,36 +156251,22 @@ static int yyGrowStack(yyParser *p){
** A pointer to a parser. This pointer is used in subsequent calls
** to sqlite3Parser and sqlite3ParserFree.
*/
-SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
- yyParser *pParser;
- pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
- if( pParser ){
-#ifdef YYTRACKMAXSTACKDEPTH
- pParser->yyhwm = 0;
-#endif
-#if YYSTACKDEPTH<=0
- pParser->yytos = NULL;
- pParser->yystack = NULL;
- pParser->yystksz = 0;
- if( yyGrowStack(pParser) ){
- pParser->yystack = &pParser->yystk0;
- pParser->yystksz = 1;
- }
-#endif
-#ifndef YYNOERRORRECOVERY
- pParser->yyerrcnt = -1;
-#endif
- pParser->yytos = pParser->yystack;
- pParser->yystack[0].stateno = 0;
- pParser->yystack[0].major = 0;
+SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) sqlite3ParserCTX_PDECL){
+ yyParser *yypParser;
+ yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+ if( yypParser ){
+ sqlite3ParserCTX_STORE
+ sqlite3ParserInit(yypParser sqlite3ParserCTX_PARAM);
}
- return pParser;
+ return (void*)yypParser;
}
+#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */
+
/* The following function deletes the "minor type" or semantic value
** associated with a symbol. The symbol can be either a terminal
** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
-** a pointer to the value to be deleted. The code used to do the
+** a pointer to the value to be deleted. The code used to do the
** deletions is derived from the %destructor and/or %token_destructor
** directives of the input grammar.
*/
@@ -134333,12 +156275,13 @@ static void yy_destructor(
YYCODETYPE yymajor, /* Type code for object to destroy */
YYMINORTYPE *yypminor /* The object to be destroyed */
){
- sqlite3ParserARG_FETCH;
+ sqlite3ParserARG_FETCH
+ sqlite3ParserCTX_FETCH
switch( yymajor ){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
+ ** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
@@ -134346,77 +156289,98 @@ static void yy_destructor(
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
- case 163: /* select */
- case 194: /* selectnowith */
- case 195: /* oneselect */
- case 206: /* values */
+ case 200: /* select */
+ case 234: /* selectnowith */
+ case 235: /* oneselect */
+ case 247: /* values */
+{
+sqlite3SelectDelete(pParse->db, (yypminor->yy539));
+}
+ break;
+ case 211: /* term */
+ case 212: /* expr */
+ case 241: /* where_opt */
+ case 243: /* having_opt */
+ case 255: /* on_opt */
+ case 271: /* case_operand */
+ case 273: /* case_else */
+ case 276: /* vinto */
+ case 283: /* when_clause */
+ case 288: /* key_opt */
+ case 302: /* filter_clause */
+{
+sqlite3ExprDelete(pParse->db, (yypminor->yy202));
+}
+ break;
+ case 216: /* eidlist_opt */
+ case 226: /* sortlist */
+ case 227: /* eidlist */
+ case 239: /* selcollist */
+ case 242: /* groupby_opt */
+ case 244: /* orderby_opt */
+ case 248: /* nexprlist */
+ case 249: /* sclp */
+ case 257: /* exprlist */
+ case 262: /* setlist */
+ case 270: /* paren_exprlist */
+ case 272: /* case_exprlist */
+ case 301: /* part_opt */
{
-sqlite3SelectDelete(pParse->db, (yypminor->yy243));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy242));
}
break;
- case 172: /* term */
- case 173: /* expr */
+ case 233: /* fullname */
+ case 240: /* from */
+ case 251: /* seltablist */
+ case 252: /* stl_prefix */
+ case 258: /* xfullname */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr);
+sqlite3SrcListDelete(pParse->db, (yypminor->yy47));
}
break;
- case 177: /* eidlist_opt */
- case 186: /* sortlist */
- case 187: /* eidlist */
- case 199: /* selcollist */
- case 202: /* groupby_opt */
- case 204: /* orderby_opt */
- case 207: /* nexprlist */
- case 208: /* exprlist */
- case 209: /* sclp */
- case 218: /* setlist */
- case 224: /* paren_exprlist */
- case 226: /* case_exprlist */
+ case 236: /* wqlist */
{
-sqlite3ExprListDelete(pParse->db, (yypminor->yy148));
+sqlite3WithDelete(pParse->db, (yypminor->yy131));
}
break;
- case 193: /* fullname */
- case 200: /* from */
- case 211: /* seltablist */
- case 212: /* stl_prefix */
+ case 246: /* window_clause */
+ case 297: /* windowdefn_list */
{
-sqlite3SrcListDelete(pParse->db, (yypminor->yy185));
+sqlite3WindowListDelete(pParse->db, (yypminor->yy303));
}
break;
- case 196: /* with */
- case 250: /* wqlist */
+ case 256: /* using_opt */
+ case 259: /* idlist */
+ case 264: /* idlist_opt */
{
-sqlite3WithDelete(pParse->db, (yypminor->yy285));
+sqlite3IdListDelete(pParse->db, (yypminor->yy600));
}
break;
- case 201: /* where_opt */
- case 203: /* having_opt */
- case 215: /* on_opt */
- case 225: /* case_operand */
- case 227: /* case_else */
- case 236: /* when_clause */
- case 241: /* key_opt */
+ case 266: /* filter_over */
+ case 298: /* windowdefn */
+ case 299: /* window */
+ case 300: /* frame_opt */
+ case 303: /* over_clause */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy72));
+sqlite3WindowDelete(pParse->db, (yypminor->yy303));
}
break;
- case 216: /* using_opt */
- case 217: /* idlist */
- case 220: /* idlist_opt */
+ case 279: /* trigger_cmd_list */
+ case 284: /* trigger_cmd */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy254));
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy447));
}
break;
- case 232: /* trigger_cmd_list */
- case 237: /* trigger_cmd */
+ case 281: /* trigger_event */
{
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145));
+sqlite3IdListDelete(pParse->db, (yypminor->yy230).b);
}
break;
- case 234: /* trigger_event */
+ case 305: /* frame_bound */
+ case 306: /* frame_bound_s */
+ case 307: /* frame_bound_e */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy332).b);
+sqlite3ExprDelete(pParse->db, (yypminor->yy77).pExpr);
}
break;
/********* End destructor definitions *****************************************/
@@ -134445,7 +156409,19 @@ static void yy_pop_parser_stack(yyParser *pParser){
yy_destructor(pParser, yytos->major, &yytos->minor);
}
-/*
+/*
+** Clear all secondary memory allocations from the parser
+*/
+SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){
+ yyParser *pParser = (yyParser*)p;
+ while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+#endif
+}
+
+#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
+/*
** Deallocate and destroy a parser. Destructors are called for
** all stack elements before shutting the parser down.
**
@@ -134457,16 +156433,13 @@ SQLITE_PRIVATE void sqlite3ParserFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
){
- yyParser *pParser = (yyParser*)p;
#ifndef YYPARSEFREENEVERNULL
- if( pParser==0 ) return;
-#endif
- while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
-#if YYSTACKDEPTH<=0
- if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+ if( p==0 ) return;
#endif
- (*freeProc)((void*)pParser);
+ sqlite3ParserFinalize(p);
+ (*freeProc)(p);
}
+#endif /* sqlite3Parser_ENGINEALWAYSONSTACK */
/*
** Return the peak depth of the stack for a parser.
@@ -134478,28 +156451,73 @@ SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){
}
#endif
+/* This array of booleans keeps track of the parser statement
+** coverage. The element yycoverage[X][Y] is set when the parser
+** is in state X and has a lookahead token Y. In a well-tested
+** systems, every element of this matrix should end up being set.
+*/
+#if defined(YYCOVERAGE)
+static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
+#endif
+
+/*
+** Write into out a description of every state/lookahead combination that
+**
+** (1) has not been used by the parser, and
+** (2) is not a syntax error.
+**
+** Return the number of missed state/lookahead combinations.
+*/
+#if defined(YYCOVERAGE)
+SQLITE_PRIVATE int sqlite3ParserCoverage(FILE *out){
+ int stateno, iLookAhead, i;
+ int nMissed = 0;
+ for(stateno=0; stateno<YYNSTATE; stateno++){
+ i = yy_shift_ofst[stateno];
+ for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){
+ if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
+ if( yycoverage[stateno][iLookAhead]==0 ) nMissed++;
+ if( out ){
+ fprintf(out,"State %d lookahead %s %s\n", stateno,
+ yyTokenName[iLookAhead],
+ yycoverage[stateno][iLookAhead] ? "ok" : "missed");
+ }
+ }
+ }
+ return nMissed;
+}
+#endif
+
/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
*/
-static unsigned int yy_find_shift_action(
- yyParser *pParser, /* The parser */
- YYCODETYPE iLookAhead /* The look-ahead token */
+static YYACTIONTYPE yy_find_shift_action(
+ YYCODETYPE iLookAhead, /* The look-ahead token */
+ YYACTIONTYPE stateno /* Current state number */
){
int i;
- int stateno = pParser->yytos->stateno;
-
- if( stateno>=YY_MIN_REDUCE ) return stateno;
+
+ if( stateno>YY_MAX_SHIFT ) return stateno;
assert( stateno <= YY_SHIFT_COUNT );
+#if defined(YYCOVERAGE)
+ yycoverage[stateno][iLookAhead] = 1;
+#endif
do{
i = yy_shift_ofst[stateno];
+ assert( i>=0 );
+ assert( i<=YY_ACTTAB_COUNT );
+ assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD );
assert( iLookAhead!=YYNOCODE );
+ assert( iLookAhead < YYNTOKEN );
i += iLookAhead;
- if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ assert( i<(int)YY_NLOOKAHEAD );
+ if( yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
YYCODETYPE iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
+ assert( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) );
+ iFallback = yyFallback[iLookAhead];
+ if( iFallback!=0 ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
@@ -134514,15 +156532,8 @@ static unsigned int yy_find_shift_action(
#ifdef YYWILDCARD
{
int j = i - iLookAhead + YYWILDCARD;
- if(
-#if YY_SHIFT_MIN+YYWILDCARD<0
- j>=0 &&
-#endif
-#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
- j<YY_ACTTAB_COUNT &&
-#endif
- yy_lookahead[j]==YYWILDCARD && iLookAhead>0
- ){
+ assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) );
+ if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
@@ -134536,6 +156547,7 @@ static unsigned int yy_find_shift_action(
#endif /* YYWILDCARD */
return yy_default[stateno];
}else{
+ assert( i>=0 && i<sizeof(yy_action)/sizeof(yy_action[0]) );
return yy_action[i];
}
}while(1);
@@ -134545,8 +156557,8 @@ static unsigned int yy_find_shift_action(
** Find the appropriate action for a parser given the non-terminal
** look-ahead token iLookAhead.
*/
-static int yy_find_reduce_action(
- int stateno, /* Current state number */
+static YYACTIONTYPE yy_find_reduce_action(
+ YYACTIONTYPE stateno, /* Current state number */
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
@@ -134558,7 +156570,6 @@ static int yy_find_reduce_action(
assert( stateno<=YY_REDUCE_COUNT );
#endif
i = yy_reduce_ofst[stateno];
- assert( i!=YY_REDUCE_USE_DFLT );
assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
#ifdef YYERRORSYMBOL
@@ -134576,8 +156587,8 @@ static int yy_find_reduce_action(
** The following routine is called if the stack overflows.
*/
static void yyStackOverflow(yyParser *yypParser){
- sqlite3ParserARG_FETCH;
- yypParser->yytos--;
+ sqlite3ParserARG_FETCH
+ sqlite3ParserCTX_FETCH
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
@@ -134590,27 +156601,29 @@ static void yyStackOverflow(yyParser *yypParser){
sqlite3ErrorMsg(pParse, "parser stack overflow");
/******** End %stack_overflow code ********************************************/
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
+ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */
+ sqlite3ParserCTX_STORE
}
/*
** Print tracing information for a SHIFT action
*/
#ifndef NDEBUG
-static void yyTraceShift(yyParser *yypParser, int yyNewState){
+static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){
if( yyTraceFILE ){
if( yyNewState<YYNSTATE ){
- fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
- yyTracePrompt,yyTokenName[yypParser->yytos->major],
+ fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n",
+ yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
yyNewState);
}else{
- fprintf(yyTraceFILE,"%sShift '%s'\n",
- yyTracePrompt,yyTokenName[yypParser->yytos->major]);
+ fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n",
+ yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
+ yyNewState - YY_MIN_REDUCE);
}
}
}
#else
-# define yyTraceShift(X,Y)
+# define yyTraceShift(X,Y,Z)
#endif
/*
@@ -134618,8 +156631,8 @@ static void yyTraceShift(yyParser *yypParser, int yyNewState){
*/
static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */
- int yyNewState, /* The new state to shift in */
- int yyMajor, /* The major token to shift in */
+ YYACTIONTYPE yyNewState, /* The new state to shift in */
+ YYCODETYPE yyMajor, /* The major token to shift in */
sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */
){
yyStackEntry *yytos;
@@ -134630,14 +156643,16 @@ static void yy_shift(
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
}
#endif
-#if YYSTACKDEPTH>0
- if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>yypParser->yystackEnd ){
+ yypParser->yytos--;
yyStackOverflow(yypParser);
return;
}
#else
if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
if( yyGrowStack(yypParser) ){
+ yypParser->yytos--;
yyStackOverflow(yypParser);
return;
}
@@ -134647,351 +156662,790 @@ static void yy_shift(
yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
}
yytos = yypParser->yytos;
- yytos->stateno = (YYACTIONTYPE)yyNewState;
- yytos->major = (YYCODETYPE)yyMajor;
+ yytos->stateno = yyNewState;
+ yytos->major = yyMajor;
yytos->minor.yy0 = yyMinor;
- yyTraceShift(yypParser, yyNewState);
-}
+ yyTraceShift(yypParser, yyNewState, "Shift");
+}
+
+/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
+** of that rule */
+static const YYCODETYPE yyRuleInfoLhs[] = {
+ 185, /* (0) explain ::= EXPLAIN */
+ 185, /* (1) explain ::= EXPLAIN QUERY PLAN */
+ 184, /* (2) cmdx ::= cmd */
+ 186, /* (3) cmd ::= BEGIN transtype trans_opt */
+ 187, /* (4) transtype ::= */
+ 187, /* (5) transtype ::= DEFERRED */
+ 187, /* (6) transtype ::= IMMEDIATE */
+ 187, /* (7) transtype ::= EXCLUSIVE */
+ 186, /* (8) cmd ::= COMMIT|END trans_opt */
+ 186, /* (9) cmd ::= ROLLBACK trans_opt */
+ 186, /* (10) cmd ::= SAVEPOINT nm */
+ 186, /* (11) cmd ::= RELEASE savepoint_opt nm */
+ 186, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ 191, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ 193, /* (14) createkw ::= CREATE */
+ 195, /* (15) ifnotexists ::= */
+ 195, /* (16) ifnotexists ::= IF NOT EXISTS */
+ 194, /* (17) temp ::= TEMP */
+ 194, /* (18) temp ::= */
+ 192, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
+ 192, /* (20) create_table_args ::= AS select */
+ 199, /* (21) table_options ::= */
+ 199, /* (22) table_options ::= WITHOUT nm */
+ 201, /* (23) columnname ::= nm typetoken */
+ 203, /* (24) typetoken ::= */
+ 203, /* (25) typetoken ::= typename LP signed RP */
+ 203, /* (26) typetoken ::= typename LP signed COMMA signed RP */
+ 204, /* (27) typename ::= typename ID|STRING */
+ 208, /* (28) scanpt ::= */
+ 209, /* (29) scantok ::= */
+ 210, /* (30) ccons ::= CONSTRAINT nm */
+ 210, /* (31) ccons ::= DEFAULT scantok term */
+ 210, /* (32) ccons ::= DEFAULT LP expr RP */
+ 210, /* (33) ccons ::= DEFAULT PLUS scantok term */
+ 210, /* (34) ccons ::= DEFAULT MINUS scantok term */
+ 210, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */
+ 210, /* (36) ccons ::= NOT NULL onconf */
+ 210, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ 210, /* (38) ccons ::= UNIQUE onconf */
+ 210, /* (39) ccons ::= CHECK LP expr RP */
+ 210, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */
+ 210, /* (41) ccons ::= defer_subclause */
+ 210, /* (42) ccons ::= COLLATE ID|STRING */
+ 219, /* (43) generated ::= LP expr RP */
+ 219, /* (44) generated ::= LP expr RP ID */
+ 215, /* (45) autoinc ::= */
+ 215, /* (46) autoinc ::= AUTOINCR */
+ 217, /* (47) refargs ::= */
+ 217, /* (48) refargs ::= refargs refarg */
+ 220, /* (49) refarg ::= MATCH nm */
+ 220, /* (50) refarg ::= ON INSERT refact */
+ 220, /* (51) refarg ::= ON DELETE refact */
+ 220, /* (52) refarg ::= ON UPDATE refact */
+ 221, /* (53) refact ::= SET NULL */
+ 221, /* (54) refact ::= SET DEFAULT */
+ 221, /* (55) refact ::= CASCADE */
+ 221, /* (56) refact ::= RESTRICT */
+ 221, /* (57) refact ::= NO ACTION */
+ 218, /* (58) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ 218, /* (59) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 222, /* (60) init_deferred_pred_opt ::= */
+ 222, /* (61) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ 222, /* (62) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 198, /* (63) conslist_opt ::= */
+ 224, /* (64) tconscomma ::= COMMA */
+ 225, /* (65) tcons ::= CONSTRAINT nm */
+ 225, /* (66) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ 225, /* (67) tcons ::= UNIQUE LP sortlist RP onconf */
+ 225, /* (68) tcons ::= CHECK LP expr RP onconf */
+ 225, /* (69) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 228, /* (70) defer_subclause_opt ::= */
+ 213, /* (71) onconf ::= */
+ 213, /* (72) onconf ::= ON CONFLICT resolvetype */
+ 229, /* (73) orconf ::= */
+ 229, /* (74) orconf ::= OR resolvetype */
+ 230, /* (75) resolvetype ::= IGNORE */
+ 230, /* (76) resolvetype ::= REPLACE */
+ 186, /* (77) cmd ::= DROP TABLE ifexists fullname */
+ 232, /* (78) ifexists ::= IF EXISTS */
+ 232, /* (79) ifexists ::= */
+ 186, /* (80) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ 186, /* (81) cmd ::= DROP VIEW ifexists fullname */
+ 186, /* (82) cmd ::= select */
+ 200, /* (83) select ::= WITH wqlist selectnowith */
+ 200, /* (84) select ::= WITH RECURSIVE wqlist selectnowith */
+ 200, /* (85) select ::= selectnowith */
+ 234, /* (86) selectnowith ::= selectnowith multiselect_op oneselect */
+ 237, /* (87) multiselect_op ::= UNION */
+ 237, /* (88) multiselect_op ::= UNION ALL */
+ 237, /* (89) multiselect_op ::= EXCEPT|INTERSECT */
+ 235, /* (90) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ 235, /* (91) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ 247, /* (92) values ::= VALUES LP nexprlist RP */
+ 247, /* (93) values ::= values COMMA LP nexprlist RP */
+ 238, /* (94) distinct ::= DISTINCT */
+ 238, /* (95) distinct ::= ALL */
+ 238, /* (96) distinct ::= */
+ 249, /* (97) sclp ::= */
+ 239, /* (98) selcollist ::= sclp scanpt expr scanpt as */
+ 239, /* (99) selcollist ::= sclp scanpt STAR */
+ 239, /* (100) selcollist ::= sclp scanpt nm DOT STAR */
+ 250, /* (101) as ::= AS nm */
+ 250, /* (102) as ::= */
+ 240, /* (103) from ::= */
+ 240, /* (104) from ::= FROM seltablist */
+ 252, /* (105) stl_prefix ::= seltablist joinop */
+ 252, /* (106) stl_prefix ::= */
+ 251, /* (107) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+ 251, /* (108) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+ 251, /* (109) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+ 251, /* (110) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+ 196, /* (111) dbnm ::= */
+ 196, /* (112) dbnm ::= DOT nm */
+ 233, /* (113) fullname ::= nm */
+ 233, /* (114) fullname ::= nm DOT nm */
+ 258, /* (115) xfullname ::= nm */
+ 258, /* (116) xfullname ::= nm DOT nm */
+ 258, /* (117) xfullname ::= nm DOT nm AS nm */
+ 258, /* (118) xfullname ::= nm AS nm */
+ 253, /* (119) joinop ::= COMMA|JOIN */
+ 253, /* (120) joinop ::= JOIN_KW JOIN */
+ 253, /* (121) joinop ::= JOIN_KW nm JOIN */
+ 253, /* (122) joinop ::= JOIN_KW nm nm JOIN */
+ 255, /* (123) on_opt ::= ON expr */
+ 255, /* (124) on_opt ::= */
+ 254, /* (125) indexed_opt ::= */
+ 254, /* (126) indexed_opt ::= INDEXED BY nm */
+ 254, /* (127) indexed_opt ::= NOT INDEXED */
+ 256, /* (128) using_opt ::= USING LP idlist RP */
+ 256, /* (129) using_opt ::= */
+ 244, /* (130) orderby_opt ::= */
+ 244, /* (131) orderby_opt ::= ORDER BY sortlist */
+ 226, /* (132) sortlist ::= sortlist COMMA expr sortorder nulls */
+ 226, /* (133) sortlist ::= expr sortorder nulls */
+ 214, /* (134) sortorder ::= ASC */
+ 214, /* (135) sortorder ::= DESC */
+ 214, /* (136) sortorder ::= */
+ 260, /* (137) nulls ::= NULLS FIRST */
+ 260, /* (138) nulls ::= NULLS LAST */
+ 260, /* (139) nulls ::= */
+ 242, /* (140) groupby_opt ::= */
+ 242, /* (141) groupby_opt ::= GROUP BY nexprlist */
+ 243, /* (142) having_opt ::= */
+ 243, /* (143) having_opt ::= HAVING expr */
+ 245, /* (144) limit_opt ::= */
+ 245, /* (145) limit_opt ::= LIMIT expr */
+ 245, /* (146) limit_opt ::= LIMIT expr OFFSET expr */
+ 245, /* (147) limit_opt ::= LIMIT expr COMMA expr */
+ 186, /* (148) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+ 241, /* (149) where_opt ::= */
+ 241, /* (150) where_opt ::= WHERE expr */
+ 186, /* (151) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt */
+ 262, /* (152) setlist ::= setlist COMMA nm EQ expr */
+ 262, /* (153) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ 262, /* (154) setlist ::= nm EQ expr */
+ 262, /* (155) setlist ::= LP idlist RP EQ expr */
+ 186, /* (156) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ 186, /* (157) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
+ 265, /* (158) upsert ::= */
+ 265, /* (159) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
+ 265, /* (160) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
+ 265, /* (161) upsert ::= ON CONFLICT DO NOTHING */
+ 263, /* (162) insert_cmd ::= INSERT orconf */
+ 263, /* (163) insert_cmd ::= REPLACE */
+ 264, /* (164) idlist_opt ::= */
+ 264, /* (165) idlist_opt ::= LP idlist RP */
+ 259, /* (166) idlist ::= idlist COMMA nm */
+ 259, /* (167) idlist ::= nm */
+ 212, /* (168) expr ::= LP expr RP */
+ 212, /* (169) expr ::= ID|INDEXED */
+ 212, /* (170) expr ::= JOIN_KW */
+ 212, /* (171) expr ::= nm DOT nm */
+ 212, /* (172) expr ::= nm DOT nm DOT nm */
+ 211, /* (173) term ::= NULL|FLOAT|BLOB */
+ 211, /* (174) term ::= STRING */
+ 211, /* (175) term ::= INTEGER */
+ 212, /* (176) expr ::= VARIABLE */
+ 212, /* (177) expr ::= expr COLLATE ID|STRING */
+ 212, /* (178) expr ::= CAST LP expr AS typetoken RP */
+ 212, /* (179) expr ::= ID|INDEXED LP distinct exprlist RP */
+ 212, /* (180) expr ::= ID|INDEXED LP STAR RP */
+ 212, /* (181) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ 212, /* (182) expr ::= ID|INDEXED LP STAR RP filter_over */
+ 211, /* (183) term ::= CTIME_KW */
+ 212, /* (184) expr ::= LP nexprlist COMMA expr RP */
+ 212, /* (185) expr ::= expr AND expr */
+ 212, /* (186) expr ::= expr OR expr */
+ 212, /* (187) expr ::= expr LT|GT|GE|LE expr */
+ 212, /* (188) expr ::= expr EQ|NE expr */
+ 212, /* (189) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 212, /* (190) expr ::= expr PLUS|MINUS expr */
+ 212, /* (191) expr ::= expr STAR|SLASH|REM expr */
+ 212, /* (192) expr ::= expr CONCAT expr */
+ 267, /* (193) likeop ::= NOT LIKE_KW|MATCH */
+ 212, /* (194) expr ::= expr likeop expr */
+ 212, /* (195) expr ::= expr likeop expr ESCAPE expr */
+ 212, /* (196) expr ::= expr ISNULL|NOTNULL */
+ 212, /* (197) expr ::= expr NOT NULL */
+ 212, /* (198) expr ::= expr IS expr */
+ 212, /* (199) expr ::= expr IS NOT expr */
+ 212, /* (200) expr ::= NOT expr */
+ 212, /* (201) expr ::= BITNOT expr */
+ 212, /* (202) expr ::= PLUS|MINUS expr */
+ 268, /* (203) between_op ::= BETWEEN */
+ 268, /* (204) between_op ::= NOT BETWEEN */
+ 212, /* (205) expr ::= expr between_op expr AND expr */
+ 269, /* (206) in_op ::= IN */
+ 269, /* (207) in_op ::= NOT IN */
+ 212, /* (208) expr ::= expr in_op LP exprlist RP */
+ 212, /* (209) expr ::= LP select RP */
+ 212, /* (210) expr ::= expr in_op LP select RP */
+ 212, /* (211) expr ::= expr in_op nm dbnm paren_exprlist */
+ 212, /* (212) expr ::= EXISTS LP select RP */
+ 212, /* (213) expr ::= CASE case_operand case_exprlist case_else END */
+ 272, /* (214) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 272, /* (215) case_exprlist ::= WHEN expr THEN expr */
+ 273, /* (216) case_else ::= ELSE expr */
+ 273, /* (217) case_else ::= */
+ 271, /* (218) case_operand ::= expr */
+ 271, /* (219) case_operand ::= */
+ 257, /* (220) exprlist ::= */
+ 248, /* (221) nexprlist ::= nexprlist COMMA expr */
+ 248, /* (222) nexprlist ::= expr */
+ 270, /* (223) paren_exprlist ::= */
+ 270, /* (224) paren_exprlist ::= LP exprlist RP */
+ 186, /* (225) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ 274, /* (226) uniqueflag ::= UNIQUE */
+ 274, /* (227) uniqueflag ::= */
+ 216, /* (228) eidlist_opt ::= */
+ 216, /* (229) eidlist_opt ::= LP eidlist RP */
+ 227, /* (230) eidlist ::= eidlist COMMA nm collate sortorder */
+ 227, /* (231) eidlist ::= nm collate sortorder */
+ 275, /* (232) collate ::= */
+ 275, /* (233) collate ::= COLLATE ID|STRING */
+ 186, /* (234) cmd ::= DROP INDEX ifexists fullname */
+ 186, /* (235) cmd ::= VACUUM vinto */
+ 186, /* (236) cmd ::= VACUUM nm vinto */
+ 276, /* (237) vinto ::= INTO expr */
+ 276, /* (238) vinto ::= */
+ 186, /* (239) cmd ::= PRAGMA nm dbnm */
+ 186, /* (240) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ 186, /* (241) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ 186, /* (242) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ 186, /* (243) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ 206, /* (244) plus_num ::= PLUS INTEGER|FLOAT */
+ 207, /* (245) minus_num ::= MINUS INTEGER|FLOAT */
+ 186, /* (246) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ 278, /* (247) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ 280, /* (248) trigger_time ::= BEFORE|AFTER */
+ 280, /* (249) trigger_time ::= INSTEAD OF */
+ 280, /* (250) trigger_time ::= */
+ 281, /* (251) trigger_event ::= DELETE|INSERT */
+ 281, /* (252) trigger_event ::= UPDATE */
+ 281, /* (253) trigger_event ::= UPDATE OF idlist */
+ 283, /* (254) when_clause ::= */
+ 283, /* (255) when_clause ::= WHEN expr */
+ 279, /* (256) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ 279, /* (257) trigger_cmd_list ::= trigger_cmd SEMI */
+ 285, /* (258) trnm ::= nm DOT nm */
+ 286, /* (259) tridxby ::= INDEXED BY nm */
+ 286, /* (260) tridxby ::= NOT INDEXED */
+ 284, /* (261) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ 284, /* (262) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ 284, /* (263) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ 284, /* (264) trigger_cmd ::= scanpt select scanpt */
+ 212, /* (265) expr ::= RAISE LP IGNORE RP */
+ 212, /* (266) expr ::= RAISE LP raisetype COMMA nm RP */
+ 231, /* (267) raisetype ::= ROLLBACK */
+ 231, /* (268) raisetype ::= ABORT */
+ 231, /* (269) raisetype ::= FAIL */
+ 186, /* (270) cmd ::= DROP TRIGGER ifexists fullname */
+ 186, /* (271) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ 186, /* (272) cmd ::= DETACH database_kw_opt expr */
+ 288, /* (273) key_opt ::= */
+ 288, /* (274) key_opt ::= KEY expr */
+ 186, /* (275) cmd ::= REINDEX */
+ 186, /* (276) cmd ::= REINDEX nm dbnm */
+ 186, /* (277) cmd ::= ANALYZE */
+ 186, /* (278) cmd ::= ANALYZE nm dbnm */
+ 186, /* (279) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ 186, /* (280) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ 289, /* (281) add_column_fullname ::= fullname */
+ 186, /* (282) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ 186, /* (283) cmd ::= create_vtab */
+ 186, /* (284) cmd ::= create_vtab LP vtabarglist RP */
+ 291, /* (285) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 293, /* (286) vtabarg ::= */
+ 294, /* (287) vtabargtoken ::= ANY */
+ 294, /* (288) vtabargtoken ::= lp anylist RP */
+ 295, /* (289) lp ::= LP */
+ 261, /* (290) with ::= WITH wqlist */
+ 261, /* (291) with ::= WITH RECURSIVE wqlist */
+ 236, /* (292) wqlist ::= nm eidlist_opt AS LP select RP */
+ 236, /* (293) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+ 297, /* (294) windowdefn_list ::= windowdefn */
+ 297, /* (295) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 298, /* (296) windowdefn ::= nm AS LP window RP */
+ 299, /* (297) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 299, /* (298) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 299, /* (299) window ::= ORDER BY sortlist frame_opt */
+ 299, /* (300) window ::= nm ORDER BY sortlist frame_opt */
+ 299, /* (301) window ::= frame_opt */
+ 299, /* (302) window ::= nm frame_opt */
+ 300, /* (303) frame_opt ::= */
+ 300, /* (304) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 300, /* (305) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 304, /* (306) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 306, /* (307) frame_bound_s ::= frame_bound */
+ 306, /* (308) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 307, /* (309) frame_bound_e ::= frame_bound */
+ 307, /* (310) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 305, /* (311) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 305, /* (312) frame_bound ::= CURRENT ROW */
+ 308, /* (313) frame_exclude_opt ::= */
+ 308, /* (314) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 309, /* (315) frame_exclude ::= NO OTHERS */
+ 309, /* (316) frame_exclude ::= CURRENT ROW */
+ 309, /* (317) frame_exclude ::= GROUP|TIES */
+ 246, /* (318) window_clause ::= WINDOW windowdefn_list */
+ 266, /* (319) filter_over ::= filter_clause over_clause */
+ 266, /* (320) filter_over ::= over_clause */
+ 266, /* (321) filter_over ::= filter_clause */
+ 303, /* (322) over_clause ::= OVER LP window RP */
+ 303, /* (323) over_clause ::= OVER nm */
+ 302, /* (324) filter_clause ::= FILTER LP WHERE expr RP */
+ 181, /* (325) input ::= cmdlist */
+ 182, /* (326) cmdlist ::= cmdlist ecmd */
+ 182, /* (327) cmdlist ::= ecmd */
+ 183, /* (328) ecmd ::= SEMI */
+ 183, /* (329) ecmd ::= cmdx SEMI */
+ 183, /* (330) ecmd ::= explain cmdx SEMI */
+ 188, /* (331) trans_opt ::= */
+ 188, /* (332) trans_opt ::= TRANSACTION */
+ 188, /* (333) trans_opt ::= TRANSACTION nm */
+ 190, /* (334) savepoint_opt ::= SAVEPOINT */
+ 190, /* (335) savepoint_opt ::= */
+ 186, /* (336) cmd ::= create_table create_table_args */
+ 197, /* (337) columnlist ::= columnlist COMMA columnname carglist */
+ 197, /* (338) columnlist ::= columnname carglist */
+ 189, /* (339) nm ::= ID|INDEXED */
+ 189, /* (340) nm ::= STRING */
+ 189, /* (341) nm ::= JOIN_KW */
+ 203, /* (342) typetoken ::= typename */
+ 204, /* (343) typename ::= ID|STRING */
+ 205, /* (344) signed ::= plus_num */
+ 205, /* (345) signed ::= minus_num */
+ 202, /* (346) carglist ::= carglist ccons */
+ 202, /* (347) carglist ::= */
+ 210, /* (348) ccons ::= NULL onconf */
+ 210, /* (349) ccons ::= GENERATED ALWAYS AS generated */
+ 210, /* (350) ccons ::= AS generated */
+ 198, /* (351) conslist_opt ::= COMMA conslist */
+ 223, /* (352) conslist ::= conslist tconscomma tcons */
+ 223, /* (353) conslist ::= tcons */
+ 224, /* (354) tconscomma ::= */
+ 228, /* (355) defer_subclause_opt ::= defer_subclause */
+ 230, /* (356) resolvetype ::= raisetype */
+ 234, /* (357) selectnowith ::= oneselect */
+ 235, /* (358) oneselect ::= values */
+ 249, /* (359) sclp ::= selcollist COMMA */
+ 250, /* (360) as ::= ID|STRING */
+ 212, /* (361) expr ::= term */
+ 267, /* (362) likeop ::= LIKE_KW|MATCH */
+ 257, /* (363) exprlist ::= nexprlist */
+ 277, /* (364) nmnum ::= plus_num */
+ 277, /* (365) nmnum ::= nm */
+ 277, /* (366) nmnum ::= ON */
+ 277, /* (367) nmnum ::= DELETE */
+ 277, /* (368) nmnum ::= DEFAULT */
+ 206, /* (369) plus_num ::= INTEGER|FLOAT */
+ 282, /* (370) foreach_clause ::= */
+ 282, /* (371) foreach_clause ::= FOR EACH ROW */
+ 285, /* (372) trnm ::= nm */
+ 286, /* (373) tridxby ::= */
+ 287, /* (374) database_kw_opt ::= DATABASE */
+ 287, /* (375) database_kw_opt ::= */
+ 290, /* (376) kwcolumn_opt ::= */
+ 290, /* (377) kwcolumn_opt ::= COLUMNKW */
+ 292, /* (378) vtabarglist ::= vtabarg */
+ 292, /* (379) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 293, /* (380) vtabarg ::= vtabarg vtabargtoken */
+ 296, /* (381) anylist ::= */
+ 296, /* (382) anylist ::= anylist LP anylist RP */
+ 296, /* (383) anylist ::= anylist ANY */
+ 261, /* (384) with ::= */
+};
-/* The following table contains information about every rule that
-** is used during the reduce.
-*/
-static const struct {
- YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
- unsigned char nrhs; /* Number of right-hand side symbols in the rule */
-} yyRuleInfo[] = {
- { 147, 1 },
- { 147, 3 },
- { 148, 1 },
- { 149, 3 },
- { 150, 0 },
- { 150, 1 },
- { 150, 1 },
- { 150, 1 },
- { 149, 2 },
- { 149, 2 },
- { 149, 2 },
- { 149, 2 },
- { 149, 3 },
- { 149, 5 },
- { 154, 6 },
- { 156, 1 },
- { 158, 0 },
- { 158, 3 },
- { 157, 1 },
- { 157, 0 },
- { 155, 5 },
- { 155, 2 },
- { 162, 0 },
- { 162, 2 },
- { 164, 2 },
- { 166, 0 },
- { 166, 4 },
- { 166, 6 },
- { 167, 2 },
- { 171, 2 },
- { 171, 2 },
- { 171, 4 },
- { 171, 3 },
- { 171, 3 },
- { 171, 2 },
- { 171, 3 },
- { 171, 5 },
- { 171, 2 },
- { 171, 4 },
- { 171, 4 },
- { 171, 1 },
- { 171, 2 },
- { 176, 0 },
- { 176, 1 },
- { 178, 0 },
- { 178, 2 },
- { 180, 2 },
- { 180, 3 },
- { 180, 3 },
- { 180, 3 },
- { 181, 2 },
- { 181, 2 },
- { 181, 1 },
- { 181, 1 },
- { 181, 2 },
- { 179, 3 },
- { 179, 2 },
- { 182, 0 },
- { 182, 2 },
- { 182, 2 },
- { 161, 0 },
- { 184, 1 },
- { 185, 2 },
- { 185, 7 },
- { 185, 5 },
- { 185, 5 },
- { 185, 10 },
- { 188, 0 },
- { 174, 0 },
- { 174, 3 },
- { 189, 0 },
- { 189, 2 },
- { 190, 1 },
- { 190, 1 },
- { 149, 4 },
- { 192, 2 },
- { 192, 0 },
- { 149, 9 },
- { 149, 4 },
- { 149, 1 },
- { 163, 2 },
- { 194, 3 },
- { 197, 1 },
- { 197, 2 },
- { 197, 1 },
- { 195, 9 },
- { 206, 4 },
- { 206, 5 },
- { 198, 1 },
- { 198, 1 },
- { 198, 0 },
- { 209, 0 },
- { 199, 3 },
- { 199, 2 },
- { 199, 4 },
- { 210, 2 },
- { 210, 0 },
- { 200, 0 },
- { 200, 2 },
- { 212, 2 },
- { 212, 0 },
- { 211, 7 },
- { 211, 9 },
- { 211, 7 },
- { 211, 7 },
- { 159, 0 },
- { 159, 2 },
- { 193, 2 },
- { 213, 1 },
- { 213, 2 },
- { 213, 3 },
- { 213, 4 },
- { 215, 2 },
- { 215, 0 },
- { 214, 0 },
- { 214, 3 },
- { 214, 2 },
- { 216, 4 },
- { 216, 0 },
- { 204, 0 },
- { 204, 3 },
- { 186, 4 },
- { 186, 2 },
- { 175, 1 },
- { 175, 1 },
- { 175, 0 },
- { 202, 0 },
- { 202, 3 },
- { 203, 0 },
- { 203, 2 },
- { 205, 0 },
- { 205, 2 },
- { 205, 4 },
- { 205, 4 },
- { 149, 6 },
- { 201, 0 },
- { 201, 2 },
- { 149, 8 },
- { 218, 5 },
- { 218, 7 },
- { 218, 3 },
- { 218, 5 },
- { 149, 6 },
- { 149, 7 },
- { 219, 2 },
- { 219, 1 },
- { 220, 0 },
- { 220, 3 },
- { 217, 3 },
- { 217, 1 },
- { 173, 3 },
- { 172, 1 },
- { 173, 1 },
- { 173, 1 },
- { 173, 3 },
- { 173, 5 },
- { 172, 1 },
- { 172, 1 },
- { 172, 1 },
- { 173, 1 },
- { 173, 3 },
- { 173, 6 },
- { 173, 5 },
- { 173, 4 },
- { 172, 1 },
- { 173, 5 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 173, 3 },
- { 221, 1 },
- { 221, 2 },
- { 173, 3 },
- { 173, 5 },
- { 173, 2 },
- { 173, 3 },
- { 173, 3 },
- { 173, 4 },
- { 173, 2 },
- { 173, 2 },
- { 173, 2 },
- { 173, 2 },
- { 222, 1 },
- { 222, 2 },
- { 173, 5 },
- { 223, 1 },
- { 223, 2 },
- { 173, 5 },
- { 173, 3 },
- { 173, 5 },
- { 173, 5 },
- { 173, 4 },
- { 173, 5 },
- { 226, 5 },
- { 226, 4 },
- { 227, 2 },
- { 227, 0 },
- { 225, 1 },
- { 225, 0 },
- { 208, 0 },
- { 207, 3 },
- { 207, 1 },
- { 224, 0 },
- { 224, 3 },
- { 149, 12 },
- { 228, 1 },
- { 228, 0 },
- { 177, 0 },
- { 177, 3 },
- { 187, 5 },
- { 187, 3 },
- { 229, 0 },
- { 229, 2 },
- { 149, 4 },
- { 149, 1 },
- { 149, 2 },
- { 149, 3 },
- { 149, 5 },
- { 149, 6 },
- { 149, 5 },
- { 149, 6 },
- { 169, 2 },
- { 170, 2 },
- { 149, 5 },
- { 231, 11 },
- { 233, 1 },
- { 233, 1 },
- { 233, 2 },
- { 233, 0 },
- { 234, 1 },
- { 234, 1 },
- { 234, 3 },
- { 236, 0 },
- { 236, 2 },
- { 232, 3 },
- { 232, 2 },
- { 238, 3 },
- { 239, 3 },
- { 239, 2 },
- { 237, 7 },
- { 237, 5 },
- { 237, 5 },
- { 237, 1 },
- { 173, 4 },
- { 173, 6 },
- { 191, 1 },
- { 191, 1 },
- { 191, 1 },
- { 149, 4 },
- { 149, 6 },
- { 149, 3 },
- { 241, 0 },
- { 241, 2 },
- { 149, 1 },
- { 149, 3 },
- { 149, 1 },
- { 149, 3 },
- { 149, 6 },
- { 149, 7 },
- { 242, 1 },
- { 149, 1 },
- { 149, 4 },
- { 244, 8 },
- { 246, 0 },
- { 247, 1 },
- { 247, 3 },
- { 248, 1 },
- { 196, 0 },
- { 196, 2 },
- { 196, 3 },
- { 250, 6 },
- { 250, 8 },
- { 144, 1 },
- { 145, 2 },
- { 145, 1 },
- { 146, 1 },
- { 146, 3 },
- { 147, 0 },
- { 151, 0 },
- { 151, 1 },
- { 151, 2 },
- { 153, 1 },
- { 153, 0 },
- { 149, 2 },
- { 160, 4 },
- { 160, 2 },
- { 152, 1 },
- { 152, 1 },
- { 152, 1 },
- { 166, 1 },
- { 167, 1 },
- { 168, 1 },
- { 168, 1 },
- { 165, 2 },
- { 165, 0 },
- { 171, 2 },
- { 161, 2 },
- { 183, 3 },
- { 183, 1 },
- { 184, 0 },
- { 188, 1 },
- { 190, 1 },
- { 194, 1 },
- { 195, 1 },
- { 209, 2 },
- { 210, 1 },
- { 173, 1 },
- { 208, 1 },
- { 230, 1 },
- { 230, 1 },
- { 230, 1 },
- { 230, 1 },
- { 230, 1 },
- { 169, 1 },
- { 235, 0 },
- { 235, 3 },
- { 238, 1 },
- { 239, 0 },
- { 240, 1 },
- { 240, 0 },
- { 243, 0 },
- { 243, 1 },
- { 245, 1 },
- { 245, 3 },
- { 246, 2 },
- { 249, 0 },
- { 249, 4 },
- { 249, 2 },
+/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
+** of symbols on the right-hand side of that rule. */
+static const signed char yyRuleInfoNRhs[] = {
+ -1, /* (0) explain ::= EXPLAIN */
+ -3, /* (1) explain ::= EXPLAIN QUERY PLAN */
+ -1, /* (2) cmdx ::= cmd */
+ -3, /* (3) cmd ::= BEGIN transtype trans_opt */
+ 0, /* (4) transtype ::= */
+ -1, /* (5) transtype ::= DEFERRED */
+ -1, /* (6) transtype ::= IMMEDIATE */
+ -1, /* (7) transtype ::= EXCLUSIVE */
+ -2, /* (8) cmd ::= COMMIT|END trans_opt */
+ -2, /* (9) cmd ::= ROLLBACK trans_opt */
+ -2, /* (10) cmd ::= SAVEPOINT nm */
+ -3, /* (11) cmd ::= RELEASE savepoint_opt nm */
+ -5, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ -6, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ -1, /* (14) createkw ::= CREATE */
+ 0, /* (15) ifnotexists ::= */
+ -3, /* (16) ifnotexists ::= IF NOT EXISTS */
+ -1, /* (17) temp ::= TEMP */
+ 0, /* (18) temp ::= */
+ -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
+ -2, /* (20) create_table_args ::= AS select */
+ 0, /* (21) table_options ::= */
+ -2, /* (22) table_options ::= WITHOUT nm */
+ -2, /* (23) columnname ::= nm typetoken */
+ 0, /* (24) typetoken ::= */
+ -4, /* (25) typetoken ::= typename LP signed RP */
+ -6, /* (26) typetoken ::= typename LP signed COMMA signed RP */
+ -2, /* (27) typename ::= typename ID|STRING */
+ 0, /* (28) scanpt ::= */
+ 0, /* (29) scantok ::= */
+ -2, /* (30) ccons ::= CONSTRAINT nm */
+ -3, /* (31) ccons ::= DEFAULT scantok term */
+ -4, /* (32) ccons ::= DEFAULT LP expr RP */
+ -4, /* (33) ccons ::= DEFAULT PLUS scantok term */
+ -4, /* (34) ccons ::= DEFAULT MINUS scantok term */
+ -3, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */
+ -3, /* (36) ccons ::= NOT NULL onconf */
+ -5, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+ -2, /* (38) ccons ::= UNIQUE onconf */
+ -4, /* (39) ccons ::= CHECK LP expr RP */
+ -4, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */
+ -1, /* (41) ccons ::= defer_subclause */
+ -2, /* (42) ccons ::= COLLATE ID|STRING */
+ -3, /* (43) generated ::= LP expr RP */
+ -4, /* (44) generated ::= LP expr RP ID */
+ 0, /* (45) autoinc ::= */
+ -1, /* (46) autoinc ::= AUTOINCR */
+ 0, /* (47) refargs ::= */
+ -2, /* (48) refargs ::= refargs refarg */
+ -2, /* (49) refarg ::= MATCH nm */
+ -3, /* (50) refarg ::= ON INSERT refact */
+ -3, /* (51) refarg ::= ON DELETE refact */
+ -3, /* (52) refarg ::= ON UPDATE refact */
+ -2, /* (53) refact ::= SET NULL */
+ -2, /* (54) refact ::= SET DEFAULT */
+ -1, /* (55) refact ::= CASCADE */
+ -1, /* (56) refact ::= RESTRICT */
+ -2, /* (57) refact ::= NO ACTION */
+ -3, /* (58) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+ -2, /* (59) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ 0, /* (60) init_deferred_pred_opt ::= */
+ -2, /* (61) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ -2, /* (62) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+ 0, /* (63) conslist_opt ::= */
+ -1, /* (64) tconscomma ::= COMMA */
+ -2, /* (65) tcons ::= CONSTRAINT nm */
+ -7, /* (66) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+ -5, /* (67) tcons ::= UNIQUE LP sortlist RP onconf */
+ -5, /* (68) tcons ::= CHECK LP expr RP onconf */
+ -10, /* (69) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ 0, /* (70) defer_subclause_opt ::= */
+ 0, /* (71) onconf ::= */
+ -3, /* (72) onconf ::= ON CONFLICT resolvetype */
+ 0, /* (73) orconf ::= */
+ -2, /* (74) orconf ::= OR resolvetype */
+ -1, /* (75) resolvetype ::= IGNORE */
+ -1, /* (76) resolvetype ::= REPLACE */
+ -4, /* (77) cmd ::= DROP TABLE ifexists fullname */
+ -2, /* (78) ifexists ::= IF EXISTS */
+ 0, /* (79) ifexists ::= */
+ -9, /* (80) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ -4, /* (81) cmd ::= DROP VIEW ifexists fullname */
+ -1, /* (82) cmd ::= select */
+ -3, /* (83) select ::= WITH wqlist selectnowith */
+ -4, /* (84) select ::= WITH RECURSIVE wqlist selectnowith */
+ -1, /* (85) select ::= selectnowith */
+ -3, /* (86) selectnowith ::= selectnowith multiselect_op oneselect */
+ -1, /* (87) multiselect_op ::= UNION */
+ -2, /* (88) multiselect_op ::= UNION ALL */
+ -1, /* (89) multiselect_op ::= EXCEPT|INTERSECT */
+ -9, /* (90) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ -10, /* (91) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+ -4, /* (92) values ::= VALUES LP nexprlist RP */
+ -5, /* (93) values ::= values COMMA LP nexprlist RP */
+ -1, /* (94) distinct ::= DISTINCT */
+ -1, /* (95) distinct ::= ALL */
+ 0, /* (96) distinct ::= */
+ 0, /* (97) sclp ::= */
+ -5, /* (98) selcollist ::= sclp scanpt expr scanpt as */
+ -3, /* (99) selcollist ::= sclp scanpt STAR */
+ -5, /* (100) selcollist ::= sclp scanpt nm DOT STAR */
+ -2, /* (101) as ::= AS nm */
+ 0, /* (102) as ::= */
+ 0, /* (103) from ::= */
+ -2, /* (104) from ::= FROM seltablist */
+ -2, /* (105) stl_prefix ::= seltablist joinop */
+ 0, /* (106) stl_prefix ::= */
+ -7, /* (107) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+ -9, /* (108) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+ -7, /* (109) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+ -7, /* (110) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+ 0, /* (111) dbnm ::= */
+ -2, /* (112) dbnm ::= DOT nm */
+ -1, /* (113) fullname ::= nm */
+ -3, /* (114) fullname ::= nm DOT nm */
+ -1, /* (115) xfullname ::= nm */
+ -3, /* (116) xfullname ::= nm DOT nm */
+ -5, /* (117) xfullname ::= nm DOT nm AS nm */
+ -3, /* (118) xfullname ::= nm AS nm */
+ -1, /* (119) joinop ::= COMMA|JOIN */
+ -2, /* (120) joinop ::= JOIN_KW JOIN */
+ -3, /* (121) joinop ::= JOIN_KW nm JOIN */
+ -4, /* (122) joinop ::= JOIN_KW nm nm JOIN */
+ -2, /* (123) on_opt ::= ON expr */
+ 0, /* (124) on_opt ::= */
+ 0, /* (125) indexed_opt ::= */
+ -3, /* (126) indexed_opt ::= INDEXED BY nm */
+ -2, /* (127) indexed_opt ::= NOT INDEXED */
+ -4, /* (128) using_opt ::= USING LP idlist RP */
+ 0, /* (129) using_opt ::= */
+ 0, /* (130) orderby_opt ::= */
+ -3, /* (131) orderby_opt ::= ORDER BY sortlist */
+ -5, /* (132) sortlist ::= sortlist COMMA expr sortorder nulls */
+ -3, /* (133) sortlist ::= expr sortorder nulls */
+ -1, /* (134) sortorder ::= ASC */
+ -1, /* (135) sortorder ::= DESC */
+ 0, /* (136) sortorder ::= */
+ -2, /* (137) nulls ::= NULLS FIRST */
+ -2, /* (138) nulls ::= NULLS LAST */
+ 0, /* (139) nulls ::= */
+ 0, /* (140) groupby_opt ::= */
+ -3, /* (141) groupby_opt ::= GROUP BY nexprlist */
+ 0, /* (142) having_opt ::= */
+ -2, /* (143) having_opt ::= HAVING expr */
+ 0, /* (144) limit_opt ::= */
+ -2, /* (145) limit_opt ::= LIMIT expr */
+ -4, /* (146) limit_opt ::= LIMIT expr OFFSET expr */
+ -4, /* (147) limit_opt ::= LIMIT expr COMMA expr */
+ -6, /* (148) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+ 0, /* (149) where_opt ::= */
+ -2, /* (150) where_opt ::= WHERE expr */
+ -9, /* (151) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt */
+ -5, /* (152) setlist ::= setlist COMMA nm EQ expr */
+ -7, /* (153) setlist ::= setlist COMMA LP idlist RP EQ expr */
+ -3, /* (154) setlist ::= nm EQ expr */
+ -5, /* (155) setlist ::= LP idlist RP EQ expr */
+ -7, /* (156) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+ -7, /* (157) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
+ 0, /* (158) upsert ::= */
+ -11, /* (159) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
+ -8, /* (160) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
+ -4, /* (161) upsert ::= ON CONFLICT DO NOTHING */
+ -2, /* (162) insert_cmd ::= INSERT orconf */
+ -1, /* (163) insert_cmd ::= REPLACE */
+ 0, /* (164) idlist_opt ::= */
+ -3, /* (165) idlist_opt ::= LP idlist RP */
+ -3, /* (166) idlist ::= idlist COMMA nm */
+ -1, /* (167) idlist ::= nm */
+ -3, /* (168) expr ::= LP expr RP */
+ -1, /* (169) expr ::= ID|INDEXED */
+ -1, /* (170) expr ::= JOIN_KW */
+ -3, /* (171) expr ::= nm DOT nm */
+ -5, /* (172) expr ::= nm DOT nm DOT nm */
+ -1, /* (173) term ::= NULL|FLOAT|BLOB */
+ -1, /* (174) term ::= STRING */
+ -1, /* (175) term ::= INTEGER */
+ -1, /* (176) expr ::= VARIABLE */
+ -3, /* (177) expr ::= expr COLLATE ID|STRING */
+ -6, /* (178) expr ::= CAST LP expr AS typetoken RP */
+ -5, /* (179) expr ::= ID|INDEXED LP distinct exprlist RP */
+ -4, /* (180) expr ::= ID|INDEXED LP STAR RP */
+ -6, /* (181) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ -5, /* (182) expr ::= ID|INDEXED LP STAR RP filter_over */
+ -1, /* (183) term ::= CTIME_KW */
+ -5, /* (184) expr ::= LP nexprlist COMMA expr RP */
+ -3, /* (185) expr ::= expr AND expr */
+ -3, /* (186) expr ::= expr OR expr */
+ -3, /* (187) expr ::= expr LT|GT|GE|LE expr */
+ -3, /* (188) expr ::= expr EQ|NE expr */
+ -3, /* (189) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ -3, /* (190) expr ::= expr PLUS|MINUS expr */
+ -3, /* (191) expr ::= expr STAR|SLASH|REM expr */
+ -3, /* (192) expr ::= expr CONCAT expr */
+ -2, /* (193) likeop ::= NOT LIKE_KW|MATCH */
+ -3, /* (194) expr ::= expr likeop expr */
+ -5, /* (195) expr ::= expr likeop expr ESCAPE expr */
+ -2, /* (196) expr ::= expr ISNULL|NOTNULL */
+ -3, /* (197) expr ::= expr NOT NULL */
+ -3, /* (198) expr ::= expr IS expr */
+ -4, /* (199) expr ::= expr IS NOT expr */
+ -2, /* (200) expr ::= NOT expr */
+ -2, /* (201) expr ::= BITNOT expr */
+ -2, /* (202) expr ::= PLUS|MINUS expr */
+ -1, /* (203) between_op ::= BETWEEN */
+ -2, /* (204) between_op ::= NOT BETWEEN */
+ -5, /* (205) expr ::= expr between_op expr AND expr */
+ -1, /* (206) in_op ::= IN */
+ -2, /* (207) in_op ::= NOT IN */
+ -5, /* (208) expr ::= expr in_op LP exprlist RP */
+ -3, /* (209) expr ::= LP select RP */
+ -5, /* (210) expr ::= expr in_op LP select RP */
+ -5, /* (211) expr ::= expr in_op nm dbnm paren_exprlist */
+ -4, /* (212) expr ::= EXISTS LP select RP */
+ -5, /* (213) expr ::= CASE case_operand case_exprlist case_else END */
+ -5, /* (214) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ -4, /* (215) case_exprlist ::= WHEN expr THEN expr */
+ -2, /* (216) case_else ::= ELSE expr */
+ 0, /* (217) case_else ::= */
+ -1, /* (218) case_operand ::= expr */
+ 0, /* (219) case_operand ::= */
+ 0, /* (220) exprlist ::= */
+ -3, /* (221) nexprlist ::= nexprlist COMMA expr */
+ -1, /* (222) nexprlist ::= expr */
+ 0, /* (223) paren_exprlist ::= */
+ -3, /* (224) paren_exprlist ::= LP exprlist RP */
+ -12, /* (225) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ -1, /* (226) uniqueflag ::= UNIQUE */
+ 0, /* (227) uniqueflag ::= */
+ 0, /* (228) eidlist_opt ::= */
+ -3, /* (229) eidlist_opt ::= LP eidlist RP */
+ -5, /* (230) eidlist ::= eidlist COMMA nm collate sortorder */
+ -3, /* (231) eidlist ::= nm collate sortorder */
+ 0, /* (232) collate ::= */
+ -2, /* (233) collate ::= COLLATE ID|STRING */
+ -4, /* (234) cmd ::= DROP INDEX ifexists fullname */
+ -2, /* (235) cmd ::= VACUUM vinto */
+ -3, /* (236) cmd ::= VACUUM nm vinto */
+ -2, /* (237) vinto ::= INTO expr */
+ 0, /* (238) vinto ::= */
+ -3, /* (239) cmd ::= PRAGMA nm dbnm */
+ -5, /* (240) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ -6, /* (241) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ -5, /* (242) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ -6, /* (243) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ -2, /* (244) plus_num ::= PLUS INTEGER|FLOAT */
+ -2, /* (245) minus_num ::= MINUS INTEGER|FLOAT */
+ -5, /* (246) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ -11, /* (247) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ -1, /* (248) trigger_time ::= BEFORE|AFTER */
+ -2, /* (249) trigger_time ::= INSTEAD OF */
+ 0, /* (250) trigger_time ::= */
+ -1, /* (251) trigger_event ::= DELETE|INSERT */
+ -1, /* (252) trigger_event ::= UPDATE */
+ -3, /* (253) trigger_event ::= UPDATE OF idlist */
+ 0, /* (254) when_clause ::= */
+ -2, /* (255) when_clause ::= WHEN expr */
+ -3, /* (256) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ -2, /* (257) trigger_cmd_list ::= trigger_cmd SEMI */
+ -3, /* (258) trnm ::= nm DOT nm */
+ -3, /* (259) tridxby ::= INDEXED BY nm */
+ -2, /* (260) tridxby ::= NOT INDEXED */
+ -9, /* (261) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ -8, /* (262) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ -6, /* (263) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ -3, /* (264) trigger_cmd ::= scanpt select scanpt */
+ -4, /* (265) expr ::= RAISE LP IGNORE RP */
+ -6, /* (266) expr ::= RAISE LP raisetype COMMA nm RP */
+ -1, /* (267) raisetype ::= ROLLBACK */
+ -1, /* (268) raisetype ::= ABORT */
+ -1, /* (269) raisetype ::= FAIL */
+ -4, /* (270) cmd ::= DROP TRIGGER ifexists fullname */
+ -6, /* (271) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ -3, /* (272) cmd ::= DETACH database_kw_opt expr */
+ 0, /* (273) key_opt ::= */
+ -2, /* (274) key_opt ::= KEY expr */
+ -1, /* (275) cmd ::= REINDEX */
+ -3, /* (276) cmd ::= REINDEX nm dbnm */
+ -1, /* (277) cmd ::= ANALYZE */
+ -3, /* (278) cmd ::= ANALYZE nm dbnm */
+ -6, /* (279) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ -7, /* (280) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ -1, /* (281) add_column_fullname ::= fullname */
+ -8, /* (282) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ -1, /* (283) cmd ::= create_vtab */
+ -4, /* (284) cmd ::= create_vtab LP vtabarglist RP */
+ -8, /* (285) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 0, /* (286) vtabarg ::= */
+ -1, /* (287) vtabargtoken ::= ANY */
+ -3, /* (288) vtabargtoken ::= lp anylist RP */
+ -1, /* (289) lp ::= LP */
+ -2, /* (290) with ::= WITH wqlist */
+ -3, /* (291) with ::= WITH RECURSIVE wqlist */
+ -6, /* (292) wqlist ::= nm eidlist_opt AS LP select RP */
+ -8, /* (293) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+ -1, /* (294) windowdefn_list ::= windowdefn */
+ -3, /* (295) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ -5, /* (296) windowdefn ::= nm AS LP window RP */
+ -5, /* (297) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ -6, /* (298) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ -4, /* (299) window ::= ORDER BY sortlist frame_opt */
+ -5, /* (300) window ::= nm ORDER BY sortlist frame_opt */
+ -1, /* (301) window ::= frame_opt */
+ -2, /* (302) window ::= nm frame_opt */
+ 0, /* (303) frame_opt ::= */
+ -3, /* (304) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ -6, /* (305) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ -1, /* (306) range_or_rows ::= RANGE|ROWS|GROUPS */
+ -1, /* (307) frame_bound_s ::= frame_bound */
+ -2, /* (308) frame_bound_s ::= UNBOUNDED PRECEDING */
+ -1, /* (309) frame_bound_e ::= frame_bound */
+ -2, /* (310) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ -2, /* (311) frame_bound ::= expr PRECEDING|FOLLOWING */
+ -2, /* (312) frame_bound ::= CURRENT ROW */
+ 0, /* (313) frame_exclude_opt ::= */
+ -2, /* (314) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ -2, /* (315) frame_exclude ::= NO OTHERS */
+ -2, /* (316) frame_exclude ::= CURRENT ROW */
+ -1, /* (317) frame_exclude ::= GROUP|TIES */
+ -2, /* (318) window_clause ::= WINDOW windowdefn_list */
+ -2, /* (319) filter_over ::= filter_clause over_clause */
+ -1, /* (320) filter_over ::= over_clause */
+ -1, /* (321) filter_over ::= filter_clause */
+ -4, /* (322) over_clause ::= OVER LP window RP */
+ -2, /* (323) over_clause ::= OVER nm */
+ -5, /* (324) filter_clause ::= FILTER LP WHERE expr RP */
+ -1, /* (325) input ::= cmdlist */
+ -2, /* (326) cmdlist ::= cmdlist ecmd */
+ -1, /* (327) cmdlist ::= ecmd */
+ -1, /* (328) ecmd ::= SEMI */
+ -2, /* (329) ecmd ::= cmdx SEMI */
+ -3, /* (330) ecmd ::= explain cmdx SEMI */
+ 0, /* (331) trans_opt ::= */
+ -1, /* (332) trans_opt ::= TRANSACTION */
+ -2, /* (333) trans_opt ::= TRANSACTION nm */
+ -1, /* (334) savepoint_opt ::= SAVEPOINT */
+ 0, /* (335) savepoint_opt ::= */
+ -2, /* (336) cmd ::= create_table create_table_args */
+ -4, /* (337) columnlist ::= columnlist COMMA columnname carglist */
+ -2, /* (338) columnlist ::= columnname carglist */
+ -1, /* (339) nm ::= ID|INDEXED */
+ -1, /* (340) nm ::= STRING */
+ -1, /* (341) nm ::= JOIN_KW */
+ -1, /* (342) typetoken ::= typename */
+ -1, /* (343) typename ::= ID|STRING */
+ -1, /* (344) signed ::= plus_num */
+ -1, /* (345) signed ::= minus_num */
+ -2, /* (346) carglist ::= carglist ccons */
+ 0, /* (347) carglist ::= */
+ -2, /* (348) ccons ::= NULL onconf */
+ -4, /* (349) ccons ::= GENERATED ALWAYS AS generated */
+ -2, /* (350) ccons ::= AS generated */
+ -2, /* (351) conslist_opt ::= COMMA conslist */
+ -3, /* (352) conslist ::= conslist tconscomma tcons */
+ -1, /* (353) conslist ::= tcons */
+ 0, /* (354) tconscomma ::= */
+ -1, /* (355) defer_subclause_opt ::= defer_subclause */
+ -1, /* (356) resolvetype ::= raisetype */
+ -1, /* (357) selectnowith ::= oneselect */
+ -1, /* (358) oneselect ::= values */
+ -2, /* (359) sclp ::= selcollist COMMA */
+ -1, /* (360) as ::= ID|STRING */
+ -1, /* (361) expr ::= term */
+ -1, /* (362) likeop ::= LIKE_KW|MATCH */
+ -1, /* (363) exprlist ::= nexprlist */
+ -1, /* (364) nmnum ::= plus_num */
+ -1, /* (365) nmnum ::= nm */
+ -1, /* (366) nmnum ::= ON */
+ -1, /* (367) nmnum ::= DELETE */
+ -1, /* (368) nmnum ::= DEFAULT */
+ -1, /* (369) plus_num ::= INTEGER|FLOAT */
+ 0, /* (370) foreach_clause ::= */
+ -3, /* (371) foreach_clause ::= FOR EACH ROW */
+ -1, /* (372) trnm ::= nm */
+ 0, /* (373) tridxby ::= */
+ -1, /* (374) database_kw_opt ::= DATABASE */
+ 0, /* (375) database_kw_opt ::= */
+ 0, /* (376) kwcolumn_opt ::= */
+ -1, /* (377) kwcolumn_opt ::= COLUMNKW */
+ -1, /* (378) vtabarglist ::= vtabarg */
+ -3, /* (379) vtabarglist ::= vtabarglist COMMA vtabarg */
+ -2, /* (380) vtabarg ::= vtabarg vtabargtoken */
+ 0, /* (381) anylist ::= */
+ -4, /* (382) anylist ::= anylist LP anylist RP */
+ -2, /* (383) anylist ::= anylist ANY */
+ 0, /* (384) with ::= */
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -134999,45 +157453,71 @@ static void yy_accept(yyParser*); /* Forward Declaration */
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
+**
+** The yyLookahead and yyLookaheadToken parameters provide reduce actions
+** access to the lookahead token (if any). The yyLookahead will be YYNOCODE
+** if the lookahead token has already been consumed. As this procedure is
+** only called from one place, optimizing compilers will in-line it, which
+** means that the extra parameters have no performance impact.
*/
-static void yy_reduce(
+static YYACTIONTYPE yy_reduce(
yyParser *yypParser, /* The parser */
- unsigned int yyruleno /* Number of the rule by which to reduce */
+ unsigned int yyruleno, /* Number of the rule by which to reduce */
+ int yyLookahead, /* Lookahead token, or YYNOCODE if none */
+ sqlite3ParserTOKENTYPE yyLookaheadToken /* Value of the lookahead token */
+ sqlite3ParserCTX_PDECL /* %extra_context */
){
int yygoto; /* The next state */
- int yyact; /* The next action */
+ YYACTIONTYPE yyact; /* The next action */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
- sqlite3ParserARG_FETCH;
+ sqlite3ParserARG_FETCH
+ (void)yyLookahead;
+ (void)yyLookaheadToken;
yymsp = yypParser->yytos;
#ifndef NDEBUG
if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
- yysize = yyRuleInfo[yyruleno].nrhs;
- fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
- yyRuleName[yyruleno], yymsp[-yysize].stateno);
+ yysize = yyRuleInfoNRhs[yyruleno];
+ if( yysize ){
+ fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
+ yyTracePrompt,
+ yyruleno, yyRuleName[yyruleno],
+ yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
+ yymsp[yysize].stateno);
+ }else{
+ fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
+ yyTracePrompt, yyruleno, yyRuleName[yyruleno],
+ yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
+ }
}
#endif /* NDEBUG */
/* Check that the stack is large enough to grow by a single entry
** if the RHS of the rule is empty. This ensures that there is room
** enough on the stack to push the LHS value */
- if( yyRuleInfo[yyruleno].nrhs==0 ){
+ if( yyRuleInfoNRhs[yyruleno]==0 ){
#ifdef YYTRACKMAXSTACKDEPTH
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
yypParser->yyhwm++;
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
}
#endif
-#if YYSTACKDEPTH>0
- if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>=yypParser->yystackEnd ){
yyStackOverflow(yypParser);
- return;
+ /* The call to yyStackOverflow() above pops the stack until it is
+ ** empty, causing the main parser loop to exit. So the return value
+ ** is never used and does not matter. */
+ return 0;
}
#else
if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
if( yyGrowStack(yypParser) ){
yyStackOverflow(yypParser);
- return;
+ /* The call to yyStackOverflow() above pops the stack until it is
+ ** empty, causing the main parser loop to exit. So the return value
+ ** is never used and does not matter. */
+ return 0;
}
yymsp = yypParser->yytos;
}
@@ -135065,801 +157545,876 @@ static void yy_reduce(
{ sqlite3FinishCoding(pParse); }
break;
case 3: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);}
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy192);}
break;
case 4: /* transtype ::= */
-{yymsp[1].minor.yy194 = TK_DEFERRED;}
+{yymsp[1].minor.yy192 = TK_DEFERRED;}
break;
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
-{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/}
- break;
- case 8: /* cmd ::= COMMIT trans_opt */
- case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9);
-{sqlite3CommitTransaction(pParse);}
+ case 306: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==306);
+{yymsp[0].minor.yy192 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 10: /* cmd ::= ROLLBACK trans_opt */
-{sqlite3RollbackTransaction(pParse);}
+ case 8: /* cmd ::= COMMIT|END trans_opt */
+ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
+{sqlite3EndTransaction(pParse,yymsp[-1].major);}
break;
- case 11: /* cmd ::= SAVEPOINT nm */
+ case 10: /* cmd ::= SAVEPOINT nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0);
}
break;
- case 12: /* cmd ::= RELEASE savepoint_opt nm */
+ case 11: /* cmd ::= RELEASE savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0);
}
break;
- case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
break;
- case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy192,0,0,yymsp[-2].minor.yy192);
}
break;
- case 15: /* createkw ::= CREATE */
+ case 14: /* createkw ::= CREATE */
{disableLookaside(pParse);}
break;
- case 16: /* ifnotexists ::= */
- case 19: /* temp ::= */ yytestcase(yyruleno==19);
- case 22: /* table_options ::= */ yytestcase(yyruleno==22);
- case 42: /* autoinc ::= */ yytestcase(yyruleno==42);
- case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57);
- case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67);
- case 76: /* ifexists ::= */ yytestcase(yyruleno==76);
- case 90: /* distinct ::= */ yytestcase(yyruleno==90);
- case 215: /* collate ::= */ yytestcase(yyruleno==215);
-{yymsp[1].minor.yy194 = 0;}
- break;
- case 17: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy194 = 1;}
- break;
- case 18: /* temp ::= TEMP */
- case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43);
-{yymsp[0].minor.yy194 = 1;}
- break;
- case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
+ case 15: /* ifnotexists ::= */
+ case 18: /* temp ::= */ yytestcase(yyruleno==18);
+ case 21: /* table_options ::= */ yytestcase(yyruleno==21);
+ case 45: /* autoinc ::= */ yytestcase(yyruleno==45);
+ case 60: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==60);
+ case 70: /* defer_subclause_opt ::= */ yytestcase(yyruleno==70);
+ case 79: /* ifexists ::= */ yytestcase(yyruleno==79);
+ case 96: /* distinct ::= */ yytestcase(yyruleno==96);
+ case 232: /* collate ::= */ yytestcase(yyruleno==232);
+{yymsp[1].minor.yy192 = 0;}
+ break;
+ case 16: /* ifnotexists ::= IF NOT EXISTS */
+{yymsp[-2].minor.yy192 = 1;}
+ break;
+ case 17: /* temp ::= TEMP */
+ case 46: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==46);
+{yymsp[0].minor.yy192 = 1;}
+ break;
+ case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
{
- sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0);
+ sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy192,0);
}
break;
- case 21: /* create_table_args ::= AS select */
+ case 20: /* create_table_args ::= AS select */
{
- sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243);
+ sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy539);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy539);
}
break;
- case 23: /* table_options ::= WITHOUT nm */
+ case 22: /* table_options ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yymsp[-1].minor.yy192 = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
- yymsp[-1].minor.yy194 = 0;
+ yymsp[-1].minor.yy192 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
break;
- case 24: /* columnname ::= nm typetoken */
+ case 23: /* columnname ::= nm typetoken */
{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
break;
- case 25: /* typetoken ::= */
- case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60);
- case 96: /* as ::= */ yytestcase(yyruleno==96);
+ case 24: /* typetoken ::= */
+ case 63: /* conslist_opt ::= */ yytestcase(yyruleno==63);
+ case 102: /* as ::= */ yytestcase(yyruleno==102);
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
break;
- case 26: /* typetoken ::= typename LP signed RP */
+ case 25: /* typetoken ::= typename LP signed RP */
{
yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
break;
- case 27: /* typetoken ::= typename LP signed COMMA signed RP */
+ case 26: /* typetoken ::= typename LP signed COMMA signed RP */
{
yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
break;
- case 28: /* typename ::= typename ID|STRING */
+ case 27: /* typename ::= typename ID|STRING */
{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
break;
- case 29: /* ccons ::= CONSTRAINT nm */
- case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62);
+ case 28: /* scanpt ::= */
+{
+ assert( yyLookahead!=YYNOCODE );
+ yymsp[1].minor.yy436 = yyLookaheadToken.z;
+}
+ break;
+ case 29: /* scantok ::= */
+{
+ assert( yyLookahead!=YYNOCODE );
+ yymsp[1].minor.yy0 = yyLookaheadToken;
+}
+ break;
+ case 30: /* ccons ::= CONSTRAINT nm */
+ case 65: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==65);
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
- case 30: /* ccons ::= DEFAULT term */
- case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32);
-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);}
+ case 31: /* ccons ::= DEFAULT scantok term */
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy202,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
+ break;
+ case 32: /* ccons ::= DEFAULT LP expr RP */
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy202,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
break;
- case 31: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);}
+ case 33: /* ccons ::= DEFAULT PLUS scantok term */
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy202,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
break;
- case 33: /* ccons ::= DEFAULT MINUS term */
+ case 34: /* ccons ::= DEFAULT MINUS scantok term */
{
- ExprSpan v;
- v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0, 0);
- v.zStart = yymsp[-1].minor.yy0.z;
- v.zEnd = yymsp[0].minor.yy190.zEnd;
- sqlite3AddDefaultValue(pParse,&v);
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy202, 0);
+ sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
break;
- case 34: /* ccons ::= DEFAULT ID|INDEXED */
+ case 35: /* ccons ::= DEFAULT scantok ID|INDEXED */
{
- ExprSpan v;
- spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0);
- sqlite3AddDefaultValue(pParse,&v);
+ Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
+ if( p ){
+ sqlite3ExprIdToTrueFalse(p);
+ testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) );
+ }
+ sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
}
break;
- case 35: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);}
+ case 36: /* ccons ::= NOT NULL onconf */
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy192);}
break;
- case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);}
+ case 37: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy192,yymsp[0].minor.yy192,yymsp[-2].minor.yy192);}
break;
- case 37: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0,
+ case 38: /* ccons ::= UNIQUE onconf */
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy192,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
- case 38: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);}
+ case 39: /* ccons ::= CHECK LP expr RP */
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy202);}
break;
- case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);}
+ case 40: /* ccons ::= REFERENCES nm eidlist_opt refargs */
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy242,yymsp[0].minor.yy192);}
break;
- case 40: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);}
+ case 41: /* ccons ::= defer_subclause */
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy192);}
break;
- case 41: /* ccons ::= COLLATE ID|STRING */
+ case 42: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
- case 44: /* refargs ::= */
-{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */}
+ case 43: /* generated ::= LP expr RP */
+{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy202,0);}
+ break;
+ case 44: /* generated ::= LP expr RP ID */
+{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy202,&yymsp[0].minor.yy0);}
break;
- case 45: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; }
+ case 47: /* refargs ::= */
+{ yymsp[1].minor.yy192 = OE_None*0x0101; /* EV: R-19803-45884 */}
break;
- case 46: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; }
+ case 48: /* refargs ::= refargs refarg */
+{ yymsp[-1].minor.yy192 = (yymsp[-1].minor.yy192 & ~yymsp[0].minor.yy207.mask) | yymsp[0].minor.yy207.value; }
break;
- case 47: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; }
+ case 49: /* refarg ::= MATCH nm */
+{ yymsp[-1].minor.yy207.value = 0; yymsp[-1].minor.yy207.mask = 0x000000; }
break;
- case 48: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; }
+ case 50: /* refarg ::= ON INSERT refact */
+{ yymsp[-2].minor.yy207.value = 0; yymsp[-2].minor.yy207.mask = 0x000000; }
break;
- case 49: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; }
+ case 51: /* refarg ::= ON DELETE refact */
+{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy192; yymsp[-2].minor.yy207.mask = 0x0000ff; }
break;
- case 50: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */}
+ case 52: /* refarg ::= ON UPDATE refact */
+{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy192<<8; yymsp[-2].minor.yy207.mask = 0x00ff00; }
break;
- case 51: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */}
+ case 53: /* refact ::= SET NULL */
+{ yymsp[-1].minor.yy192 = OE_SetNull; /* EV: R-33326-45252 */}
break;
- case 52: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */}
+ case 54: /* refact ::= SET DEFAULT */
+{ yymsp[-1].minor.yy192 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
- case 53: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */}
+ case 55: /* refact ::= CASCADE */
+{ yymsp[0].minor.yy192 = OE_Cascade; /* EV: R-33326-45252 */}
break;
- case 54: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */}
+ case 56: /* refact ::= RESTRICT */
+{ yymsp[0].minor.yy192 = OE_Restrict; /* EV: R-33326-45252 */}
break;
- case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy194 = 0;}
+ case 57: /* refact ::= NO ACTION */
+{ yymsp[-1].minor.yy192 = OE_None; /* EV: R-33326-45252 */}
break;
- case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71);
- case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144);
-{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;}
+ case 58: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+{yymsp[-2].minor.yy192 = 0;}
break;
- case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
- case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75);
- case 187: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==187);
- case 190: /* in_op ::= NOT IN */ yytestcase(yyruleno==190);
- case 216: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==216);
-{yymsp[-1].minor.yy194 = 1;}
+ case 59: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ case 74: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==74);
+ case 162: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==162);
+{yymsp[-1].minor.yy192 = yymsp[0].minor.yy192;}
break;
- case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy194 = 0;}
+ case 61: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ case 78: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==78);
+ case 204: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==204);
+ case 207: /* in_op ::= NOT IN */ yytestcase(yyruleno==207);
+ case 233: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==233);
+{yymsp[-1].minor.yy192 = 1;}
break;
- case 61: /* tconscomma ::= COMMA */
+ case 62: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+{yymsp[-1].minor.yy192 = 0;}
+ break;
+ case 64: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
break;
- case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);}
+ case 66: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy242,yymsp[0].minor.yy192,yymsp[-2].minor.yy192,0);}
break;
- case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0,
+ case 67: /* tcons ::= UNIQUE LP sortlist RP onconf */
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy242,yymsp[0].minor.yy192,0,0,0,0,
SQLITE_IDXTYPE_UNIQUE);}
break;
- case 65: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);}
+ case 68: /* tcons ::= CHECK LP expr RP onconf */
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy202);}
break;
- case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ case 69: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy242, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy242, yymsp[-1].minor.yy192);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy192);
}
break;
- case 68: /* onconf ::= */
- case 70: /* orconf ::= */ yytestcase(yyruleno==70);
-{yymsp[1].minor.yy194 = OE_Default;}
+ case 71: /* onconf ::= */
+ case 73: /* orconf ::= */ yytestcase(yyruleno==73);
+{yymsp[1].minor.yy192 = OE_Default;}
+ break;
+ case 72: /* onconf ::= ON CONFLICT resolvetype */
+{yymsp[-2].minor.yy192 = yymsp[0].minor.yy192;}
break;
- case 69: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;}
+ case 75: /* resolvetype ::= IGNORE */
+{yymsp[0].minor.yy192 = OE_Ignore;}
break;
- case 72: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy194 = OE_Ignore;}
+ case 76: /* resolvetype ::= REPLACE */
+ case 163: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==163);
+{yymsp[0].minor.yy192 = OE_Replace;}
break;
- case 73: /* resolvetype ::= REPLACE */
- case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145);
-{yymsp[0].minor.yy194 = OE_Replace;}
+ case 77: /* cmd ::= DROP TABLE ifexists fullname */
+{
+ sqlite3DropTable(pParse, yymsp[0].minor.yy47, 0, yymsp[-1].minor.yy192);
+}
break;
- case 74: /* cmd ::= DROP TABLE ifexists fullname */
+ case 80: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194);
+ sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy242, yymsp[0].minor.yy539, yymsp[-7].minor.yy192, yymsp[-5].minor.yy192);
}
break;
- case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ case 81: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy47, 1, yymsp[-1].minor.yy192);
}
break;
- case 78: /* cmd ::= DROP VIEW ifexists fullname */
+ case 82: /* cmd ::= select */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194);
+ SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
+ sqlite3Select(pParse, yymsp[0].minor.yy539, &dest);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy539);
}
break;
- case 79: /* cmd ::= select */
+ case 83: /* select ::= WITH wqlist selectnowith */
{
- SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
- sqlite3Select(pParse, yymsp[0].minor.yy243, &dest);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243);
+ Select *p = yymsp[0].minor.yy539;
+ if( p ){
+ p->pWith = yymsp[-1].minor.yy131;
+ parserDoubleLinkSelect(pParse, p);
+ }else{
+ sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy131);
+ }
+ yymsp[-2].minor.yy539 = p;
}
break;
- case 80: /* select ::= with selectnowith */
+ case 84: /* select ::= WITH RECURSIVE wqlist selectnowith */
{
- Select *p = yymsp[0].minor.yy243;
+ Select *p = yymsp[0].minor.yy539;
if( p ){
- p->pWith = yymsp[-1].minor.yy285;
+ p->pWith = yymsp[-1].minor.yy131;
parserDoubleLinkSelect(pParse, p);
}else{
- sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285);
+ sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy131);
+ }
+ yymsp[-3].minor.yy539 = p;
+}
+ break;
+ case 85: /* select ::= selectnowith */
+{
+ Select *p = yymsp[0].minor.yy539;
+ if( p ){
+ parserDoubleLinkSelect(pParse, p);
}
- yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/
+ yymsp[0].minor.yy539 = p; /*A-overwrites-X*/
}
break;
- case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */
+ case 86: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy243;
- Select *pLhs = yymsp[-2].minor.yy243;
+ Select *pRhs = yymsp[0].minor.yy539;
+ Select *pLhs = yymsp[-2].minor.yy539;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
x.n = 0;
parserDoubleLinkSelect(pParse, pRhs);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
- pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
+ pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy194;
+ pRhs->op = (u8)yymsp[-1].minor.yy192;
pRhs->pPrior = pLhs;
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1;
+ if( yymsp[-1].minor.yy192!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, pLhs);
}
- yymsp[-2].minor.yy243 = pRhs;
+ yymsp[-2].minor.yy539 = pRhs;
}
break;
- case 82: /* multiselect_op ::= UNION */
- case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84);
-{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/}
+ case 87: /* multiselect_op ::= UNION */
+ case 89: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==89);
+{yymsp[0].minor.yy192 = yymsp[0].major; /*A-overwrites-OP*/}
break;
- case 83: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy194 = TK_ALL;}
+ case 88: /* multiselect_op ::= UNION ALL */
+{yymsp[-1].minor.yy192 = TK_ALL;}
break;
- case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ case 90: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
-#if SELECTTRACE_ENABLED
- Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
-#endif
- yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset);
-#if SELECTTRACE_ENABLED
- /* Populate the Select.zSelName[] string that is used to help with
- ** query planner debugging, to differentiate between multiple Select
- ** objects in a complex query.
- **
- ** If the SELECT keyword is immediately followed by a C-style comment
- ** then extract the first few alphanumeric characters from within that
- ** comment to be the zSelName value. Otherwise, the label is #N where
- ** is an integer that is incremented with each SELECT statement seen.
- */
- if( yymsp[-8].minor.yy243!=0 ){
- const char *z = s.z+6;
- int i;
- sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d",
- ++pParse->nSelect);
- while( z[0]==' ' ) z++;
- if( z[0]=='/' && z[1]=='*' ){
- z += 2;
- while( z[0]==' ' ) z++;
- for(i=0; sqlite3Isalnum(z[i]); i++){}
- sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z);
- }
+ yymsp[-8].minor.yy539 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy242,yymsp[-5].minor.yy47,yymsp[-4].minor.yy202,yymsp[-3].minor.yy242,yymsp[-2].minor.yy202,yymsp[-1].minor.yy242,yymsp[-7].minor.yy192,yymsp[0].minor.yy202);
+}
+ break;
+ case 91: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+{
+ yymsp[-9].minor.yy539 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy242,yymsp[-6].minor.yy47,yymsp[-5].minor.yy202,yymsp[-4].minor.yy242,yymsp[-3].minor.yy202,yymsp[-1].minor.yy242,yymsp[-8].minor.yy192,yymsp[0].minor.yy202);
+ if( yymsp[-9].minor.yy539 ){
+ yymsp[-9].minor.yy539->pWinDefn = yymsp[-2].minor.yy303;
+ }else{
+ sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy303);
}
-#endif /* SELECTRACE_ENABLED */
}
break;
- case 86: /* values ::= VALUES LP nexprlist RP */
+ case 92: /* values ::= VALUES LP nexprlist RP */
{
- yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0);
+ yymsp[-3].minor.yy539 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy242,0,0,0,0,0,SF_Values,0);
}
break;
- case 87: /* values ::= values COMMA LP exprlist RP */
+ case 93: /* values ::= values COMMA LP nexprlist RP */
{
- Select *pRight, *pLeft = yymsp[-4].minor.yy243;
- pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
+ Select *pRight, *pLeft = yymsp[-4].minor.yy539;
+ pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy242,0,0,0,0,0,SF_Values|SF_MultiValue,0);
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){
pRight->op = TK_ALL;
pRight->pPrior = pLeft;
- yymsp[-4].minor.yy243 = pRight;
+ yymsp[-4].minor.yy539 = pRight;
}else{
- yymsp[-4].minor.yy243 = pLeft;
+ yymsp[-4].minor.yy539 = pLeft;
}
}
break;
- case 88: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy194 = SF_Distinct;}
+ case 94: /* distinct ::= DISTINCT */
+{yymsp[0].minor.yy192 = SF_Distinct;}
break;
- case 89: /* distinct ::= ALL */
-{yymsp[0].minor.yy194 = SF_All;}
+ case 95: /* distinct ::= ALL */
+{yymsp[0].minor.yy192 = SF_All;}
break;
- case 91: /* sclp ::= */
- case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119);
- case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126);
- case 203: /* exprlist ::= */ yytestcase(yyruleno==203);
- case 206: /* paren_exprlist ::= */ yytestcase(yyruleno==206);
- case 211: /* eidlist_opt ::= */ yytestcase(yyruleno==211);
-{yymsp[1].minor.yy148 = 0;}
+ case 97: /* sclp ::= */
+ case 130: /* orderby_opt ::= */ yytestcase(yyruleno==130);
+ case 140: /* groupby_opt ::= */ yytestcase(yyruleno==140);
+ case 220: /* exprlist ::= */ yytestcase(yyruleno==220);
+ case 223: /* paren_exprlist ::= */ yytestcase(yyruleno==223);
+ case 228: /* eidlist_opt ::= */ yytestcase(yyruleno==228);
+{yymsp[1].minor.yy242 = 0;}
break;
- case 92: /* selcollist ::= sclp expr as */
+ case 98: /* selcollist ::= sclp scanpt expr scanpt as */
{
- yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr);
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1);
- sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy242, yymsp[-2].minor.yy202);
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy242, &yymsp[0].minor.yy0, 1);
+ sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy242,yymsp[-3].minor.yy436,yymsp[-1].minor.yy436);
}
break;
- case 93: /* selcollist ::= sclp STAR */
+ case 99: /* selcollist ::= sclp scanpt STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
- yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p);
+ yymsp[-2].minor.yy242 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy242, p);
}
break;
- case 94: /* selcollist ::= sclp nm DOT STAR */
+ case 100: /* selcollist ::= sclp scanpt nm DOT STAR */
{
- Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, 0);
- Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
- Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
- yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot);
+ Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
+ Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242, pDot);
}
break;
- case 95: /* as ::= AS nm */
- case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106);
- case 225: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==225);
- case 226: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==226);
+ case 101: /* as ::= AS nm */
+ case 112: /* dbnm ::= DOT nm */ yytestcase(yyruleno==112);
+ case 244: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==244);
+ case 245: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==245);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 97: /* from ::= */
-{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));}
+ case 103: /* from ::= */
+ case 106: /* stl_prefix ::= */ yytestcase(yyruleno==106);
+{yymsp[1].minor.yy47 = 0;}
break;
- case 98: /* from ::= FROM seltablist */
+ case 104: /* from ::= FROM seltablist */
{
- yymsp[-1].minor.yy185 = yymsp[0].minor.yy185;
- sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185);
+ yymsp[-1].minor.yy47 = yymsp[0].minor.yy47;
+ sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy47);
}
break;
- case 99: /* stl_prefix ::= seltablist joinop */
+ case 105: /* stl_prefix ::= seltablist joinop */
{
- if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194;
+ if( ALWAYS(yymsp[-1].minor.yy47 && yymsp[-1].minor.yy47->nSrc>0) ) yymsp[-1].minor.yy47->a[yymsp[-1].minor.yy47->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy192;
}
break;
- case 100: /* stl_prefix ::= */
-{yymsp[1].minor.yy185 = 0;}
- break;
- case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+ case 107: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
- yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
- sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0);
+ yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy47, &yymsp[-2].minor.yy0);
}
break;
- case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+ case 108: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
{
- yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
- sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148);
+ yymsp[-8].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy47,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
+ sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy47, yymsp[-4].minor.yy242);
}
break;
- case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+ case 109: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
- yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
+ yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy539,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
}
break;
- case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+ case 110: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
- if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){
- yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185;
- }else if( yymsp[-4].minor.yy185->nSrc==1 ){
- yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
- if( yymsp[-6].minor.yy185 ){
- struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1];
- struct SrcList_item *pOld = yymsp[-4].minor.yy185->a;
+ if( yymsp[-6].minor.yy47==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy202==0 && yymsp[0].minor.yy600==0 ){
+ yymsp[-6].minor.yy47 = yymsp[-4].minor.yy47;
+ }else if( yymsp[-4].minor.yy47->nSrc==1 ){
+ yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
+ if( yymsp[-6].minor.yy47 ){
+ struct SrcList_item *pNew = &yymsp[-6].minor.yy47->a[yymsp[-6].minor.yy47->nSrc-1];
+ struct SrcList_item *pOld = yymsp[-4].minor.yy47->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
+ if( pOld->fg.isTabFunc ){
+ pNew->u1.pFuncArg = pOld->u1.pFuncArg;
+ pOld->u1.pFuncArg = 0;
+ pOld->fg.isTabFunc = 0;
+ pNew->fg.isTabFunc = 1;
+ }
pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
}
- sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185);
+ sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy47);
}else{
Select *pSubquery;
- sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0);
- yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
+ sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy47);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy47,0,0,0,0,SF_NestedFrom,0);
+ yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
}
}
break;
- case 105: /* dbnm ::= */
- case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114);
+ case 111: /* dbnm ::= */
+ case 125: /* indexed_opt ::= */ yytestcase(yyruleno==125);
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
break;
- case 107: /* fullname ::= nm dbnm */
-{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 113: /* fullname ::= nm */
+{
+ yylhsminor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy47 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy47->a[0].zName, &yymsp[0].minor.yy0);
+}
+ yymsp[0].minor.yy47 = yylhsminor.yy47;
+ break;
+ case 114: /* fullname ::= nm DOT nm */
+{
+ yylhsminor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ if( IN_RENAME_OBJECT && yylhsminor.yy47 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy47->a[0].zName, &yymsp[0].minor.yy0);
+}
+ yymsp[-2].minor.yy47 = yylhsminor.yy47;
+ break;
+ case 115: /* xfullname ::= nm */
+{yymsp[0].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
+ break;
+ case 116: /* xfullname ::= nm DOT nm */
+{yymsp[-2].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ break;
+ case 117: /* xfullname ::= nm DOT nm AS nm */
+{
+ yymsp[-4].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
+ if( yymsp[-4].minor.yy47 ) yymsp[-4].minor.yy47->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+}
+ break;
+ case 118: /* xfullname ::= nm AS nm */
+{
+ yymsp[-2].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
+ if( yymsp[-2].minor.yy47 ) yymsp[-2].minor.yy47->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+}
break;
- case 108: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy194 = JT_INNER; }
+ case 119: /* joinop ::= COMMA|JOIN */
+{ yymsp[0].minor.yy192 = JT_INNER; }
break;
- case 109: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
+ case 120: /* joinop ::= JOIN_KW JOIN */
+{yymsp[-1].minor.yy192 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
break;
- case 110: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+ case 121: /* joinop ::= JOIN_KW nm JOIN */
+{yymsp[-2].minor.yy192 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
break;
- case 111: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+ case 122: /* joinop ::= JOIN_KW nm nm JOIN */
+{yymsp[-3].minor.yy192 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
break;
- case 112: /* on_opt ::= ON expr */
- case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129);
- case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136);
- case 199: /* case_else ::= ELSE expr */ yytestcase(yyruleno==199);
-{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;}
+ case 123: /* on_opt ::= ON expr */
+ case 143: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==143);
+ case 150: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==150);
+ case 216: /* case_else ::= ELSE expr */ yytestcase(yyruleno==216);
+ case 237: /* vinto ::= INTO expr */ yytestcase(yyruleno==237);
+{yymsp[-1].minor.yy202 = yymsp[0].minor.yy202;}
break;
- case 113: /* on_opt ::= */
- case 128: /* having_opt ::= */ yytestcase(yyruleno==128);
- case 135: /* where_opt ::= */ yytestcase(yyruleno==135);
- case 200: /* case_else ::= */ yytestcase(yyruleno==200);
- case 202: /* case_operand ::= */ yytestcase(yyruleno==202);
-{yymsp[1].minor.yy72 = 0;}
+ case 124: /* on_opt ::= */
+ case 142: /* having_opt ::= */ yytestcase(yyruleno==142);
+ case 144: /* limit_opt ::= */ yytestcase(yyruleno==144);
+ case 149: /* where_opt ::= */ yytestcase(yyruleno==149);
+ case 217: /* case_else ::= */ yytestcase(yyruleno==217);
+ case 219: /* case_operand ::= */ yytestcase(yyruleno==219);
+ case 238: /* vinto ::= */ yytestcase(yyruleno==238);
+{yymsp[1].minor.yy202 = 0;}
break;
- case 115: /* indexed_opt ::= INDEXED BY nm */
+ case 126: /* indexed_opt ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 116: /* indexed_opt ::= NOT INDEXED */
+ case 127: /* indexed_opt ::= NOT INDEXED */
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
break;
- case 117: /* using_opt ::= USING LP idlist RP */
-{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;}
+ case 128: /* using_opt ::= USING LP idlist RP */
+{yymsp[-3].minor.yy600 = yymsp[-1].minor.yy600;}
break;
- case 118: /* using_opt ::= */
- case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146);
-{yymsp[1].minor.yy254 = 0;}
+ case 129: /* using_opt ::= */
+ case 164: /* idlist_opt ::= */ yytestcase(yyruleno==164);
+{yymsp[1].minor.yy600 = 0;}
break;
- case 120: /* orderby_opt ::= ORDER BY sortlist */
- case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127);
-{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;}
+ case 131: /* orderby_opt ::= ORDER BY sortlist */
+ case 141: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==141);
+{yymsp[-2].minor.yy242 = yymsp[0].minor.yy242;}
break;
- case 121: /* sortlist ::= sortlist COMMA expr sortorder */
+ case 132: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
- yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr);
- sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242,yymsp[-2].minor.yy202);
+ sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy242,yymsp[-1].minor.yy192,yymsp[0].minor.yy192);
}
break;
- case 122: /* sortlist ::= expr sortorder */
+ case 133: /* sortlist ::= expr sortorder nulls */
{
- yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/
- sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194);
+ yymsp[-2].minor.yy242 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy202); /*A-overwrites-Y*/
+ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy242,yymsp[-1].minor.yy192,yymsp[0].minor.yy192);
}
break;
- case 123: /* sortorder ::= ASC */
-{yymsp[0].minor.yy194 = SQLITE_SO_ASC;}
+ case 134: /* sortorder ::= ASC */
+{yymsp[0].minor.yy192 = SQLITE_SO_ASC;}
+ break;
+ case 135: /* sortorder ::= DESC */
+{yymsp[0].minor.yy192 = SQLITE_SO_DESC;}
break;
- case 124: /* sortorder ::= DESC */
-{yymsp[0].minor.yy194 = SQLITE_SO_DESC;}
+ case 136: /* sortorder ::= */
+ case 139: /* nulls ::= */ yytestcase(yyruleno==139);
+{yymsp[1].minor.yy192 = SQLITE_SO_UNDEFINED;}
break;
- case 125: /* sortorder ::= */
-{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;}
+ case 137: /* nulls ::= NULLS FIRST */
+{yymsp[-1].minor.yy192 = SQLITE_SO_ASC;}
break;
- case 130: /* limit_opt ::= */
-{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;}
+ case 138: /* nulls ::= NULLS LAST */
+{yymsp[-1].minor.yy192 = SQLITE_SO_DESC;}
break;
- case 131: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;}
+ case 145: /* limit_opt ::= LIMIT expr */
+{yymsp[-1].minor.yy202 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy202,0);}
break;
- case 132: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;}
+ case 146: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yymsp[-3].minor.yy202 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);}
break;
- case 133: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;}
+ case 147: /* limit_opt ::= LIMIT expr COMMA expr */
+{yymsp[-3].minor.yy202 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy202,yymsp[-2].minor.yy202);}
break;
- case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
+ case 148: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
{
- sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1);
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy47, &yymsp[-1].minor.yy0);
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy47,yymsp[0].minor.yy202,0,0);
}
break;
- case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
+ case 151: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt */
{
- sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1);
- sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy148,"set list");
- sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy47, &yymsp[-4].minor.yy0);
+ sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy242,"set list");
+ yymsp[-5].minor.yy47 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy47, yymsp[-1].minor.yy47);
+ sqlite3Update(pParse,yymsp[-5].minor.yy47,yymsp[-2].minor.yy242,yymsp[0].minor.yy202,yymsp[-6].minor.yy192,0,0,0);
}
break;
- case 138: /* setlist ::= setlist COMMA nm EQ expr */
+ case 152: /* setlist ::= setlist COMMA nm EQ expr */
{
- yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr);
- sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy242, yymsp[0].minor.yy202);
+ sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy242, &yymsp[-2].minor.yy0, 1);
}
break;
- case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
+ case 153: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
- yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr);
+ yymsp[-6].minor.yy242 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy242, yymsp[-3].minor.yy600, yymsp[0].minor.yy202);
}
break;
- case 140: /* setlist ::= nm EQ expr */
+ case 154: /* setlist ::= nm EQ expr */
{
- yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr);
- sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1);
+ yylhsminor.yy242 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy202);
+ sqlite3ExprListSetName(pParse, yylhsminor.yy242, &yymsp[-2].minor.yy0, 1);
}
- yymsp[-2].minor.yy148 = yylhsminor.yy148;
+ yymsp[-2].minor.yy242 = yylhsminor.yy242;
break;
- case 141: /* setlist ::= LP idlist RP EQ expr */
+ case 155: /* setlist ::= LP idlist RP EQ expr */
{
- yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy600, yymsp[0].minor.yy202);
}
break;
- case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
+ case 156: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
- sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1);
- sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194);
+ sqlite3Insert(pParse, yymsp[-3].minor.yy47, yymsp[-1].minor.yy539, yymsp[-2].minor.yy600, yymsp[-5].minor.yy192, yymsp[0].minor.yy318);
}
break;
- case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
+ case 157: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
{
- sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1);
- sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194);
+ sqlite3Insert(pParse, yymsp[-3].minor.yy47, 0, yymsp[-2].minor.yy600, yymsp[-5].minor.yy192, 0);
}
break;
- case 147: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;}
+ case 158: /* upsert ::= */
+{ yymsp[1].minor.yy318 = 0; }
break;
- case 148: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);}
+ case 159: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
+{ yymsp[-10].minor.yy318 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy242,yymsp[-5].minor.yy202,yymsp[-1].minor.yy242,yymsp[0].minor.yy202);}
break;
- case 149: /* idlist ::= nm */
-{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+ case 160: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
+{ yymsp[-7].minor.yy318 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy242,yymsp[-2].minor.yy202,0,0); }
break;
- case 150: /* expr ::= LP expr RP */
-{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;}
+ case 161: /* upsert ::= ON CONFLICT DO NOTHING */
+{ yymsp[-3].minor.yy318 = sqlite3UpsertNew(pParse->db,0,0,0,0); }
break;
- case 151: /* term ::= NULL */
- case 156: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==156);
- case 157: /* term ::= STRING */ yytestcase(yyruleno==157);
-{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/}
+ case 165: /* idlist_opt ::= LP idlist RP */
+{yymsp[-2].minor.yy600 = yymsp[-1].minor.yy600;}
break;
- case 152: /* expr ::= ID|INDEXED */
- case 153: /* expr ::= JOIN_KW */ yytestcase(yyruleno==153);
-{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ case 166: /* idlist ::= idlist COMMA nm */
+{yymsp[-2].minor.yy600 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy600,&yymsp[0].minor.yy0);}
break;
- case 154: /* expr ::= nm DOT nm */
+ case 167: /* idlist ::= nm */
+{yymsp[0].minor.yy600 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+ break;
+ case 168: /* expr ::= LP expr RP */
+{yymsp[-2].minor.yy202 = yymsp[-1].minor.yy202;}
+ break;
+ case 169: /* expr ::= ID|INDEXED */
+ case 170: /* expr ::= JOIN_KW */ yytestcase(yyruleno==170);
+{yymsp[0].minor.yy202=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ break;
+ case 171: /* expr ::= nm DOT nm */
{
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
- spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0);
+ sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0);
+ }
+ yylhsminor.yy202 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
+ yymsp[-2].minor.yy202 = yylhsminor.yy202;
break;
- case 155: /* expr ::= nm DOT nm DOT nm */
+ case 172: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
- Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
- spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
+ Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
+ if( IN_RENAME_OBJECT ){
+ sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0);
+ sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0);
+ }
+ yylhsminor.yy202 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
+ yymsp[-4].minor.yy202 = yylhsminor.yy202;
+ break;
+ case 173: /* term ::= NULL|FLOAT|BLOB */
+ case 174: /* term ::= STRING */ yytestcase(yyruleno==174);
+{yymsp[0].minor.yy202=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 158: /* term ::= INTEGER */
+ case 175: /* term ::= INTEGER */
{
- yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
- yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z;
- yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n;
- if( yylhsminor.yy190.pExpr ) yylhsminor.yy190.pExpr->flags |= EP_Leaf;
+ yylhsminor.yy202 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
}
- yymsp[0].minor.yy190 = yylhsminor.yy190;
+ yymsp[0].minor.yy202 = yylhsminor.yy202;
break;
- case 159: /* expr ::= VARIABLE */
+ case 176: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
- spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0);
- sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr, n);
+ yymsp[0].minor.yy202 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+ sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy202, n);
}else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
assert( t.n>=2 );
- spanSet(&yymsp[0].minor.yy190, &t, &t);
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
- yymsp[0].minor.yy190.pExpr = 0;
+ yymsp[0].minor.yy202 = 0;
}else{
- yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, 0);
- if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable);
+ yymsp[0].minor.yy202 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( yymsp[0].minor.yy202 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy202->iTable);
}
}
}
break;
- case 160: /* expr ::= expr COLLATE ID|STRING */
+ case 177: /* expr ::= expr COLLATE ID|STRING */
{
- yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1);
- yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yymsp[-2].minor.yy202 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy202, &yymsp[0].minor.yy0, 1);
}
break;
- case 161: /* expr ::= CAST LP expr AS typetoken RP */
+ case 178: /* expr ::= CAST LP expr AS typetoken RP */
{
- spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-5].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy190.pExpr, 0, &yymsp[-1].minor.yy0);
+ yymsp[-5].minor.yy202 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy202, yymsp[-3].minor.yy202, 0);
}
break;
- case 162: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 179: /* expr ::= ID|INDEXED LP distinct exprlist RP */
{
- if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
- sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
- }
- yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0);
- spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
- if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){
- yylhsminor.yy190.pExpr->flags |= EP_Distinct;
- }
+ yylhsminor.yy202 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy242, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy192);
+}
+ yymsp[-4].minor.yy202 = yylhsminor.yy202;
+ break;
+ case 180: /* expr ::= ID|INDEXED LP STAR RP */
+{
+ yylhsminor.yy202 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
+}
+ yymsp[-3].minor.yy202 = yylhsminor.yy202;
+ break;
+ case 181: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+{
+ yylhsminor.yy202 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy242, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy192);
+ sqlite3WindowAttach(pParse, yylhsminor.yy202, yymsp[0].minor.yy303);
}
- yymsp[-4].minor.yy190 = yylhsminor.yy190;
+ yymsp[-5].minor.yy202 = yylhsminor.yy202;
break;
- case 163: /* expr ::= ID|INDEXED LP STAR RP */
+ case 182: /* expr ::= ID|INDEXED LP STAR RP filter_over */
{
- yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
- spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ yylhsminor.yy202 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
+ sqlite3WindowAttach(pParse, yylhsminor.yy202, yymsp[0].minor.yy303);
}
- yymsp[-3].minor.yy190 = yylhsminor.yy190;
+ yymsp[-4].minor.yy202 = yylhsminor.yy202;
break;
- case 164: /* term ::= CTIME_KW */
+ case 183: /* term ::= CTIME_KW */
{
- yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
- spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
+ yylhsminor.yy202 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
}
- yymsp[0].minor.yy190 = yylhsminor.yy190;
+ yymsp[0].minor.yy202 = yylhsminor.yy202;
break;
- case 165: /* expr ::= LP nexprlist COMMA expr RP */
+ case 184: /* expr ::= LP nexprlist COMMA expr RP */
{
- ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr);
- yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0, 0);
- if( yylhsminor.yy190.pExpr ){
- yylhsminor.yy190.pExpr->x.pList = pList;
- spanSet(&yylhsminor.yy190, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
+ ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy242, yymsp[-1].minor.yy202);
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( yymsp[-4].minor.yy202 ){
+ yymsp[-4].minor.yy202->x.pList = pList;
+ if( ALWAYS(pList->nExpr) ){
+ yymsp[-4].minor.yy202->flags |= pList->a[0].pExpr->flags & EP_Propagate;
+ }
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
}
- yymsp[-4].minor.yy190 = yylhsminor.yy190;
break;
- case 166: /* expr ::= expr AND expr */
- case 167: /* expr ::= expr OR expr */ yytestcase(yyruleno==167);
- case 168: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==168);
- case 169: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==169);
- case 170: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==170);
- case 171: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==171);
- case 172: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==172);
- case 173: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==173);
-{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);}
+ case 185: /* expr ::= expr AND expr */
+{yymsp[-2].minor.yy202=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);}
break;
- case 174: /* likeop ::= LIKE_KW|MATCH */
-{yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/}
+ case 186: /* expr ::= expr OR expr */
+ case 187: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==187);
+ case 188: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==188);
+ case 189: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==189);
+ case 190: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==190);
+ case 191: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==191);
+ case 192: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==192);
+{yymsp[-2].minor.yy202=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);}
break;
- case 175: /* likeop ::= NOT LIKE_KW|MATCH */
+ case 193: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
break;
- case 176: /* expr ::= expr likeop expr */
+ case 194: /* expr ::= expr likeop expr */
{
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
yymsp[-1].minor.yy0.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr);
- yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0);
- exprNot(pParse, bNot, &yymsp[-2].minor.yy190);
- yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd;
- if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy202);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy202);
+ yymsp[-2].minor.yy202 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+ if( bNot ) yymsp[-2].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy202, 0);
+ if( yymsp[-2].minor.yy202 ) yymsp[-2].minor.yy202->flags |= EP_InfixFunc;
}
break;
- case 177: /* expr ::= expr likeop expr ESCAPE expr */
+ case 195: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
yymsp[-3].minor.yy0.n &= 0x7fffffff;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr);
- yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0);
- exprNot(pParse, bNot, &yymsp[-4].minor.yy190);
- yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd;
- if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy202);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy202);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy202);
+ yymsp[-4].minor.yy202 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
+ if( bNot ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
+ if( yymsp[-4].minor.yy202 ) yymsp[-4].minor.yy202->flags |= EP_InfixFunc;
}
break;
- case 178: /* expr ::= expr ISNULL|NOTNULL */
-{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);}
+ case 196: /* expr ::= expr ISNULL|NOTNULL */
+{yymsp[-1].minor.yy202 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy202,0);}
break;
- case 179: /* expr ::= expr NOT NULL */
-{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);}
+ case 197: /* expr ::= expr NOT NULL */
+{yymsp[-2].minor.yy202 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy202,0);}
break;
- case 180: /* expr ::= expr IS expr */
+ case 198: /* expr ::= expr IS expr */
{
- spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL);
+ yymsp[-2].minor.yy202 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy202, yymsp[-2].minor.yy202, TK_ISNULL);
}
break;
- case 181: /* expr ::= expr IS NOT expr */
+ case 199: /* expr ::= expr IS NOT expr */
{
- spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL);
+ yymsp[-3].minor.yy202 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy202,yymsp[0].minor.yy202);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy202, yymsp[-3].minor.yy202, TK_NOTNULL);
}
break;
- case 182: /* expr ::= NOT expr */
- case 183: /* expr ::= BITNOT expr */ yytestcase(yyruleno==183);
-{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
+ case 200: /* expr ::= NOT expr */
+ case 201: /* expr ::= BITNOT expr */ yytestcase(yyruleno==201);
+{yymsp[-1].minor.yy202 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy202, 0);/*A-overwrites-B*/}
break;
- case 184: /* expr ::= MINUS expr */
-{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
- break;
- case 185: /* expr ::= PLUS expr */
-{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
+ case 202: /* expr ::= PLUS|MINUS expr */
+{
+ yymsp[-1].minor.yy202 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy202, 0);
+ /*A-overwrites-B*/
+}
break;
- case 186: /* between_op ::= BETWEEN */
- case 189: /* in_op ::= IN */ yytestcase(yyruleno==189);
-{yymsp[0].minor.yy194 = 0;}
+ case 203: /* between_op ::= BETWEEN */
+ case 206: /* in_op ::= IN */ yytestcase(yyruleno==206);
+{yymsp[0].minor.yy192 = 0;}
break;
- case 188: /* expr ::= expr between_op expr AND expr */
+ case 205: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr);
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0, 0);
- if( yymsp[-4].minor.yy190.pExpr ){
- yymsp[-4].minor.yy190.pExpr->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy202);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy202);
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy202, 0);
+ if( yymsp[-4].minor.yy202 ){
+ yymsp[-4].minor.yy202->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
- }
- exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
- yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd;
+ }
+ if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
}
break;
- case 191: /* expr ::= expr in_op LP exprlist RP */
+ case 208: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy148==0 ){
+ if( yymsp[-1].minor.yy242==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -135868,440 +158423,563 @@ static void yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr);
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy194]);
- }else if( yymsp[-1].minor.yy148->nExpr==1 ){
- /* Expressions of the form:
- **
- ** expr1 IN (?1)
- ** expr1 NOT IN (?2)
- **
- ** with exactly one value on the RHS can be simplified to something
- ** like this:
- **
- ** expr1 == ?1
- ** expr1 <> ?2
- **
- ** But, the RHS of the == or <> is marked with the EP_Generic flag
- ** so that it may not contribute to the computation of comparison
- ** affinity or the collating sequence to use for comparison. Otherwise,
- ** the semantics would be subtly different from IN or NOT IN.
- */
- Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr;
- yymsp[-1].minor.yy148->a[0].pExpr = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148);
- /* pRHS cannot be NULL because a malloc error would have been detected
- ** before now and control would have never reached this point */
- if( ALWAYS(pRHS) ){
- pRHS->flags &= ~EP_Collate;
- pRHS->flags |= EP_Generic;
- }
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS, 0);
- }else{
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0);
- if( yymsp[-4].minor.yy190.pExpr ){
- yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr);
+ sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy202);
+ yymsp[-4].minor.yy202 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy192 ? "1" : "0");
+ }else if( yymsp[-1].minor.yy242->nExpr==1 && sqlite3ExprIsConstant(yymsp[-1].minor.yy242->a[0].pExpr) ){
+ Expr *pRHS = yymsp[-1].minor.yy242->a[0].pExpr;
+ yymsp[-1].minor.yy242->a[0].pExpr = 0;
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy242);
+ pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy202, pRHS);
+ if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
+ }else{
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
+ if( yymsp[-4].minor.yy202 ){
+ yymsp[-4].minor.yy202->x.pList = yymsp[-1].minor.yy242;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy202);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148);
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy242);
}
- exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
+ if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
}
- yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 192: /* expr ::= LP select RP */
+ case 209: /* expr ::= LP select RP */
{
- spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
- yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243);
+ yymsp[-2].minor.yy202 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy202, yymsp[-1].minor.yy539);
}
break;
- case 193: /* expr ::= expr in_op LP select RP */
+ case 210: /* expr ::= expr in_op LP select RP */
{
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243);
- exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
- yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy202, yymsp[-1].minor.yy539);
+ if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
}
break;
- case 194: /* expr ::= expr in_op nm dbnm paren_exprlist */
+ case 211: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
- SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
- Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148);
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0, 0);
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect);
- exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
- yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n];
+ SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
+ Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
+ if( yymsp[0].minor.yy242 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy242);
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy202, pSelect);
+ if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
}
break;
- case 195: /* expr ::= EXISTS LP select RP */
+ case 212: /* expr ::= EXISTS LP select RP */
{
Expr *p;
- spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
- p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
- sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243);
+ p = yymsp[-3].minor.yy202 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy539);
}
break;
- case 196: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 213: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/
- yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0, 0);
- if( yymsp[-4].minor.yy190.pExpr ){
- yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148;
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr);
+ yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy202, 0);
+ if( yymsp[-4].minor.yy202 ){
+ yymsp[-4].minor.yy202->x.pList = yymsp[-1].minor.yy202 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy242,yymsp[-1].minor.yy202) : yymsp[-2].minor.yy242;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy202);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148);
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72);
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy242);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy202);
}
}
break;
- case 197: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 214: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr);
- yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242, yymsp[-2].minor.yy202);
+ yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242, yymsp[0].minor.yy202);
}
break;
- case 198: /* case_exprlist ::= WHEN expr THEN expr */
+ case 215: /* case_exprlist ::= WHEN expr THEN expr */
{
- yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr);
- yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr);
+ yymsp[-3].minor.yy242 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy202);
+ yymsp[-3].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy242, yymsp[0].minor.yy202);
}
break;
- case 201: /* case_operand ::= expr */
-{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/}
+ case 218: /* case_operand ::= expr */
+{yymsp[0].minor.yy202 = yymsp[0].minor.yy202; /*A-overwrites-X*/}
break;
- case 204: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);}
+ case 221: /* nexprlist ::= nexprlist COMMA expr */
+{yymsp[-2].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy242,yymsp[0].minor.yy202);}
break;
- case 205: /* nexprlist ::= expr */
-{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/}
+ case 222: /* nexprlist ::= expr */
+{yymsp[0].minor.yy242 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy202); /*A-overwrites-Y*/}
break;
- case 207: /* paren_exprlist ::= LP exprlist RP */
- case 212: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==212);
-{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;}
+ case 224: /* paren_exprlist ::= LP exprlist RP */
+ case 229: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==229);
+{yymsp[-2].minor.yy242 = yymsp[-1].minor.yy242;}
break;
- case 208: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 225: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
- sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
- sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF);
+ sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
+ sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy242, yymsp[-10].minor.yy192,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy202, SQLITE_SO_ASC, yymsp[-8].minor.yy192, SQLITE_IDXTYPE_APPDEF);
+ if( IN_RENAME_OBJECT && pParse->pNewIndex ){
+ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
+ }
}
break;
- case 209: /* uniqueflag ::= UNIQUE */
- case 250: /* raisetype ::= ABORT */ yytestcase(yyruleno==250);
-{yymsp[0].minor.yy194 = OE_Abort;}
+ case 226: /* uniqueflag ::= UNIQUE */
+ case 268: /* raisetype ::= ABORT */ yytestcase(yyruleno==268);
+{yymsp[0].minor.yy192 = OE_Abort;}
break;
- case 210: /* uniqueflag ::= */
-{yymsp[1].minor.yy194 = OE_None;}
+ case 227: /* uniqueflag ::= */
+{yymsp[1].minor.yy192 = OE_None;}
break;
- case 213: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 230: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
- yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194);
+ yymsp[-4].minor.yy242 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy242, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy192, yymsp[0].minor.yy192);
}
break;
- case 214: /* eidlist ::= nm collate sortorder */
+ case 231: /* eidlist ::= nm collate sortorder */
{
- yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/
+ yymsp[-2].minor.yy242 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy192, yymsp[0].minor.yy192); /*A-overwrites-Y*/
}
break;
- case 217: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);}
+ case 234: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy47, yymsp[-1].minor.yy192);}
break;
- case 218: /* cmd ::= VACUUM */
-{sqlite3Vacuum(pParse,0);}
+ case 235: /* cmd ::= VACUUM vinto */
+{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy202);}
break;
- case 219: /* cmd ::= VACUUM nm */
-{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);}
+ case 236: /* cmd ::= VACUUM nm vinto */
+{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy202);}
break;
- case 220: /* cmd ::= PRAGMA nm dbnm */
+ case 239: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 221: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 240: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 222: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 241: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 223: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 242: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 224: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 243: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 227: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 246: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
Token all;
all.z = yymsp[-3].minor.yy0.z;
all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all);
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy447, &all);
}
break;
- case 228: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 247: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194);
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy192, yymsp[-4].minor.yy230.a, yymsp[-4].minor.yy230.b, yymsp[-2].minor.yy47, yymsp[0].minor.yy202, yymsp[-10].minor.yy192, yymsp[-8].minor.yy192);
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
break;
- case 229: /* trigger_time ::= BEFORE */
-{ yymsp[0].minor.yy194 = TK_BEFORE; }
- break;
- case 230: /* trigger_time ::= AFTER */
-{ yymsp[0].minor.yy194 = TK_AFTER; }
+ case 248: /* trigger_time ::= BEFORE|AFTER */
+{ yymsp[0].minor.yy192 = yymsp[0].major; /*A-overwrites-X*/ }
break;
- case 231: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy194 = TK_INSTEAD;}
+ case 249: /* trigger_time ::= INSTEAD OF */
+{ yymsp[-1].minor.yy192 = TK_INSTEAD;}
break;
- case 232: /* trigger_time ::= */
-{ yymsp[1].minor.yy194 = TK_BEFORE; }
+ case 250: /* trigger_time ::= */
+{ yymsp[1].minor.yy192 = TK_BEFORE; }
break;
- case 233: /* trigger_event ::= DELETE|INSERT */
- case 234: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==234);
-{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;}
+ case 251: /* trigger_event ::= DELETE|INSERT */
+ case 252: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==252);
+{yymsp[0].minor.yy230.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy230.b = 0;}
break;
- case 235: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;}
+ case 253: /* trigger_event ::= UPDATE OF idlist */
+{yymsp[-2].minor.yy230.a = TK_UPDATE; yymsp[-2].minor.yy230.b = yymsp[0].minor.yy600;}
break;
- case 236: /* when_clause ::= */
- case 255: /* key_opt ::= */ yytestcase(yyruleno==255);
-{ yymsp[1].minor.yy72 = 0; }
+ case 254: /* when_clause ::= */
+ case 273: /* key_opt ::= */ yytestcase(yyruleno==273);
+{ yymsp[1].minor.yy202 = 0; }
break;
- case 237: /* when_clause ::= WHEN expr */
- case 256: /* key_opt ::= KEY expr */ yytestcase(yyruleno==256);
-{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; }
+ case 255: /* when_clause ::= WHEN expr */
+ case 274: /* key_opt ::= KEY expr */ yytestcase(yyruleno==274);
+{ yymsp[-1].minor.yy202 = yymsp[0].minor.yy202; }
break;
- case 238: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 256: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy145!=0 );
- yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145;
- yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145;
+ assert( yymsp[-2].minor.yy447!=0 );
+ yymsp[-2].minor.yy447->pLast->pNext = yymsp[-1].minor.yy447;
+ yymsp[-2].minor.yy447->pLast = yymsp[-1].minor.yy447;
}
break;
- case 239: /* trigger_cmd_list ::= trigger_cmd SEMI */
-{
- assert( yymsp[-1].minor.yy145!=0 );
- yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145;
+ case 257: /* trigger_cmd_list ::= trigger_cmd SEMI */
+{
+ assert( yymsp[-1].minor.yy447!=0 );
+ yymsp[-1].minor.yy447->pLast = yymsp[-1].minor.yy447;
}
break;
- case 240: /* trnm ::= nm DOT nm */
+ case 258: /* trnm ::= nm DOT nm */
{
yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
- sqlite3ErrorMsg(pParse,
+ sqlite3ErrorMsg(pParse,
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
"statements within triggers");
}
break;
- case 241: /* tridxby ::= INDEXED BY nm */
+ case 259: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 242: /* tridxby ::= NOT INDEXED */
+ case 260: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 243: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
-{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);}
+ case 261: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+{yylhsminor.yy447 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy47, yymsp[-3].minor.yy242, yymsp[-1].minor.yy202, yymsp[-7].minor.yy192, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy436);}
+ yymsp[-8].minor.yy447 = yylhsminor.yy447;
break;
- case 244: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
-{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/}
+ case 262: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+{
+ yylhsminor.yy447 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy600,yymsp[-2].minor.yy539,yymsp[-6].minor.yy192,yymsp[-1].minor.yy318,yymsp[-7].minor.yy436,yymsp[0].minor.yy436);/*yylhsminor.yy447-overwrites-yymsp[-6].minor.yy192*/
+}
+ yymsp[-7].minor.yy447 = yylhsminor.yy447;
break;
- case 245: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
-{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);}
+ case 263: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+{yylhsminor.yy447 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy202, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy436);}
+ yymsp[-5].minor.yy447 = yylhsminor.yy447;
break;
- case 246: /* trigger_cmd ::= select */
-{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/}
+ case 264: /* trigger_cmd ::= scanpt select scanpt */
+{yylhsminor.yy447 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy539, yymsp[-2].minor.yy436, yymsp[0].minor.yy436); /*yylhsminor.yy447-overwrites-yymsp[-1].minor.yy539*/}
+ yymsp[-2].minor.yy447 = yylhsminor.yy447;
break;
- case 247: /* expr ::= RAISE LP IGNORE RP */
+ case 265: /* expr ::= RAISE LP IGNORE RP */
{
- spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
- if( yymsp[-3].minor.yy190.pExpr ){
- yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore;
+ yymsp[-3].minor.yy202 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( yymsp[-3].minor.yy202 ){
+ yymsp[-3].minor.yy202->affExpr = OE_Ignore;
}
}
break;
- case 248: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 266: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
- spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
- yymsp[-5].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
- if( yymsp[-5].minor.yy190.pExpr ) {
- yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194;
+ yymsp[-5].minor.yy202 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
+ if( yymsp[-5].minor.yy202 ) {
+ yymsp[-5].minor.yy202->affExpr = (char)yymsp[-3].minor.yy192;
}
}
break;
- case 249: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy194 = OE_Rollback;}
+ case 267: /* raisetype ::= ROLLBACK */
+{yymsp[0].minor.yy192 = OE_Rollback;}
break;
- case 251: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy194 = OE_Fail;}
+ case 269: /* raisetype ::= FAIL */
+{yymsp[0].minor.yy192 = OE_Fail;}
break;
- case 252: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 270: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy192);
}
break;
- case 253: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 271: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy202, yymsp[-1].minor.yy202, yymsp[0].minor.yy202);
}
break;
- case 254: /* cmd ::= DETACH database_kw_opt expr */
+ case 272: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr);
+ sqlite3Detach(pParse, yymsp[0].minor.yy202);
}
break;
- case 257: /* cmd ::= REINDEX */
+ case 275: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
- case 258: /* cmd ::= REINDEX nm dbnm */
+ case 276: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 259: /* cmd ::= ANALYZE */
+ case 277: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
- case 260: /* cmd ::= ANALYZE nm dbnm */
+ case 278: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 261: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 279: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy47,&yymsp[0].minor.yy0);
}
break;
- case 262: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ case 280: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
break;
- case 263: /* add_column_fullname ::= fullname */
+ case 281: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185);
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy47);
}
break;
- case 264: /* cmd ::= create_vtab */
+ case 282: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+{
+ sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy47, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
+}
+ break;
+ case 283: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
- case 265: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 284: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 266: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 285: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy192);
}
break;
- case 267: /* vtabarg ::= */
+ case 286: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
- case 268: /* vtabargtoken ::= ANY */
- case 269: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==269);
- case 270: /* lp ::= LP */ yytestcase(yyruleno==270);
+ case 287: /* vtabargtoken ::= ANY */
+ case 288: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==288);
+ case 289: /* lp ::= LP */ yytestcase(yyruleno==289);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 271: /* with ::= */
-{yymsp[1].minor.yy285 = 0;}
+ case 290: /* with ::= WITH wqlist */
+ case 291: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==291);
+{ sqlite3WithPush(pParse, yymsp[0].minor.yy131, 1); }
+ break;
+ case 292: /* wqlist ::= nm eidlist_opt AS LP select RP */
+{
+ yymsp[-5].minor.yy131 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy242, yymsp[-1].minor.yy539); /*A-overwrites-X*/
+}
+ break;
+ case 293: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+{
+ yymsp[-7].minor.yy131 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy131, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy242, yymsp[-1].minor.yy539);
+}
+ break;
+ case 294: /* windowdefn_list ::= windowdefn */
+{ yylhsminor.yy303 = yymsp[0].minor.yy303; }
+ yymsp[0].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 295: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+{
+ assert( yymsp[0].minor.yy303!=0 );
+ sqlite3WindowChain(pParse, yymsp[0].minor.yy303, yymsp[-2].minor.yy303);
+ yymsp[0].minor.yy303->pNextWin = yymsp[-2].minor.yy303;
+ yylhsminor.yy303 = yymsp[0].minor.yy303;
+}
+ yymsp[-2].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 296: /* windowdefn ::= nm AS LP window RP */
+{
+ if( ALWAYS(yymsp[-1].minor.yy303) ){
+ yymsp[-1].minor.yy303->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
+ }
+ yylhsminor.yy303 = yymsp[-1].minor.yy303;
+}
+ yymsp[-4].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 297: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+{
+ yymsp[-4].minor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, yymsp[-2].minor.yy242, yymsp[-1].minor.yy242, 0);
+}
break;
- case 272: /* with ::= WITH wqlist */
-{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; }
+ case 298: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+{
+ yylhsminor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, yymsp[-2].minor.yy242, yymsp[-1].minor.yy242, &yymsp[-5].minor.yy0);
+}
+ yymsp[-5].minor.yy303 = yylhsminor.yy303;
break;
- case 273: /* with ::= WITH RECURSIVE wqlist */
-{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; }
+ case 299: /* window ::= ORDER BY sortlist frame_opt */
+{
+ yymsp[-3].minor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, 0, yymsp[-1].minor.yy242, 0);
+}
break;
- case 274: /* wqlist ::= nm eidlist_opt AS LP select RP */
+ case 300: /* window ::= nm ORDER BY sortlist frame_opt */
{
- yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/
+ yylhsminor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, 0, yymsp[-1].minor.yy242, &yymsp[-4].minor.yy0);
}
+ yymsp[-4].minor.yy303 = yylhsminor.yy303;
break;
- case 275: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+ case 301: /* window ::= frame_opt */
+ case 320: /* filter_over ::= over_clause */ yytestcase(yyruleno==320);
{
- yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243);
+ yylhsminor.yy303 = yymsp[0].minor.yy303;
}
+ yymsp[0].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 302: /* window ::= nm frame_opt */
+{
+ yylhsminor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, 0, 0, &yymsp[-1].minor.yy0);
+}
+ yymsp[-1].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 303: /* frame_opt ::= */
+{
+ yymsp[1].minor.yy303 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
+}
+ break;
+ case 304: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+{
+ yylhsminor.yy303 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy192, yymsp[-1].minor.yy77.eType, yymsp[-1].minor.yy77.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy58);
+}
+ yymsp[-2].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 305: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+{
+ yylhsminor.yy303 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy192, yymsp[-3].minor.yy77.eType, yymsp[-3].minor.yy77.pExpr, yymsp[-1].minor.yy77.eType, yymsp[-1].minor.yy77.pExpr, yymsp[0].minor.yy58);
+}
+ yymsp[-5].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 307: /* frame_bound_s ::= frame_bound */
+ case 309: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==309);
+{yylhsminor.yy77 = yymsp[0].minor.yy77;}
+ yymsp[0].minor.yy77 = yylhsminor.yy77;
+ break;
+ case 308: /* frame_bound_s ::= UNBOUNDED PRECEDING */
+ case 310: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==310);
+ case 312: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==312);
+{yylhsminor.yy77.eType = yymsp[-1].major; yylhsminor.yy77.pExpr = 0;}
+ yymsp[-1].minor.yy77 = yylhsminor.yy77;
+ break;
+ case 311: /* frame_bound ::= expr PRECEDING|FOLLOWING */
+{yylhsminor.yy77.eType = yymsp[0].major; yylhsminor.yy77.pExpr = yymsp[-1].minor.yy202;}
+ yymsp[-1].minor.yy77 = yylhsminor.yy77;
+ break;
+ case 313: /* frame_exclude_opt ::= */
+{yymsp[1].minor.yy58 = 0;}
+ break;
+ case 314: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
+{yymsp[-1].minor.yy58 = yymsp[0].minor.yy58;}
+ break;
+ case 315: /* frame_exclude ::= NO OTHERS */
+ case 316: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==316);
+{yymsp[-1].minor.yy58 = yymsp[-1].major; /*A-overwrites-X*/}
+ break;
+ case 317: /* frame_exclude ::= GROUP|TIES */
+{yymsp[0].minor.yy58 = yymsp[0].major; /*A-overwrites-X*/}
+ break;
+ case 318: /* window_clause ::= WINDOW windowdefn_list */
+{ yymsp[-1].minor.yy303 = yymsp[0].minor.yy303; }
+ break;
+ case 319: /* filter_over ::= filter_clause over_clause */
+{
+ yymsp[0].minor.yy303->pFilter = yymsp[-1].minor.yy202;
+ yylhsminor.yy303 = yymsp[0].minor.yy303;
+}
+ yymsp[-1].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 321: /* filter_over ::= filter_clause */
+{
+ yylhsminor.yy303 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yylhsminor.yy303 ){
+ yylhsminor.yy303->eFrmType = TK_FILTER;
+ yylhsminor.yy303->pFilter = yymsp[0].minor.yy202;
+ }else{
+ sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy202);
+ }
+}
+ yymsp[0].minor.yy303 = yylhsminor.yy303;
+ break;
+ case 322: /* over_clause ::= OVER LP window RP */
+{
+ yymsp[-3].minor.yy303 = yymsp[-1].minor.yy303;
+ assert( yymsp[-3].minor.yy303!=0 );
+}
+ break;
+ case 323: /* over_clause ::= OVER nm */
+{
+ yymsp[-1].minor.yy303 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+ if( yymsp[-1].minor.yy303 ){
+ yymsp[-1].minor.yy303->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
+ }
+}
+ break;
+ case 324: /* filter_clause ::= FILTER LP WHERE expr RP */
+{ yymsp[-4].minor.yy202 = yymsp[-1].minor.yy202; }
break;
default:
- /* (276) input ::= cmdlist */ yytestcase(yyruleno==276);
- /* (277) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==277);
- /* (278) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=278);
- /* (279) ecmd ::= SEMI */ yytestcase(yyruleno==279);
- /* (280) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==280);
- /* (281) explain ::= */ yytestcase(yyruleno==281);
- /* (282) trans_opt ::= */ yytestcase(yyruleno==282);
- /* (283) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==283);
- /* (284) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==284);
- /* (285) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==285);
- /* (286) savepoint_opt ::= */ yytestcase(yyruleno==286);
- /* (287) cmd ::= create_table create_table_args */ yytestcase(yyruleno==287);
- /* (288) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==288);
- /* (289) columnlist ::= columnname carglist */ yytestcase(yyruleno==289);
- /* (290) nm ::= ID|INDEXED */ yytestcase(yyruleno==290);
- /* (291) nm ::= STRING */ yytestcase(yyruleno==291);
- /* (292) nm ::= JOIN_KW */ yytestcase(yyruleno==292);
- /* (293) typetoken ::= typename */ yytestcase(yyruleno==293);
- /* (294) typename ::= ID|STRING */ yytestcase(yyruleno==294);
- /* (295) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=295);
- /* (296) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=296);
- /* (297) carglist ::= carglist ccons */ yytestcase(yyruleno==297);
- /* (298) carglist ::= */ yytestcase(yyruleno==298);
- /* (299) ccons ::= NULL onconf */ yytestcase(yyruleno==299);
- /* (300) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==300);
- /* (301) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==301);
- /* (302) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=302);
- /* (303) tconscomma ::= */ yytestcase(yyruleno==303);
- /* (304) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=304);
- /* (305) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=305);
- /* (306) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=306);
- /* (307) oneselect ::= values */ yytestcase(yyruleno==307);
- /* (308) sclp ::= selcollist COMMA */ yytestcase(yyruleno==308);
- /* (309) as ::= ID|STRING */ yytestcase(yyruleno==309);
- /* (310) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=310);
- /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311);
- /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312);
- /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313);
- /* (314) nmnum ::= ON */ yytestcase(yyruleno==314);
- /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315);
- /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316);
- /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317);
- /* (318) foreach_clause ::= */ yytestcase(yyruleno==318);
- /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319);
- /* (320) trnm ::= nm */ yytestcase(yyruleno==320);
- /* (321) tridxby ::= */ yytestcase(yyruleno==321);
- /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322);
- /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323);
- /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324);
- /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325);
- /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326);
- /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327);
- /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328);
- /* (329) anylist ::= */ yytestcase(yyruleno==329);
- /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330);
- /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331);
+ /* (325) input ::= cmdlist */ yytestcase(yyruleno==325);
+ /* (326) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==326);
+ /* (327) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=327);
+ /* (328) ecmd ::= SEMI */ yytestcase(yyruleno==328);
+ /* (329) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==329);
+ /* (330) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=330);
+ /* (331) trans_opt ::= */ yytestcase(yyruleno==331);
+ /* (332) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==332);
+ /* (333) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==333);
+ /* (334) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==334);
+ /* (335) savepoint_opt ::= */ yytestcase(yyruleno==335);
+ /* (336) cmd ::= create_table create_table_args */ yytestcase(yyruleno==336);
+ /* (337) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==337);
+ /* (338) columnlist ::= columnname carglist */ yytestcase(yyruleno==338);
+ /* (339) nm ::= ID|INDEXED */ yytestcase(yyruleno==339);
+ /* (340) nm ::= STRING */ yytestcase(yyruleno==340);
+ /* (341) nm ::= JOIN_KW */ yytestcase(yyruleno==341);
+ /* (342) typetoken ::= typename */ yytestcase(yyruleno==342);
+ /* (343) typename ::= ID|STRING */ yytestcase(yyruleno==343);
+ /* (344) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=344);
+ /* (345) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=345);
+ /* (346) carglist ::= carglist ccons */ yytestcase(yyruleno==346);
+ /* (347) carglist ::= */ yytestcase(yyruleno==347);
+ /* (348) ccons ::= NULL onconf */ yytestcase(yyruleno==348);
+ /* (349) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==349);
+ /* (350) ccons ::= AS generated */ yytestcase(yyruleno==350);
+ /* (351) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==351);
+ /* (352) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==352);
+ /* (353) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=353);
+ /* (354) tconscomma ::= */ yytestcase(yyruleno==354);
+ /* (355) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=355);
+ /* (356) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=356);
+ /* (357) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=357);
+ /* (358) oneselect ::= values */ yytestcase(yyruleno==358);
+ /* (359) sclp ::= selcollist COMMA */ yytestcase(yyruleno==359);
+ /* (360) as ::= ID|STRING */ yytestcase(yyruleno==360);
+ /* (361) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=361);
+ /* (362) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==362);
+ /* (363) exprlist ::= nexprlist */ yytestcase(yyruleno==363);
+ /* (364) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=364);
+ /* (365) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=365);
+ /* (366) nmnum ::= ON */ yytestcase(yyruleno==366);
+ /* (367) nmnum ::= DELETE */ yytestcase(yyruleno==367);
+ /* (368) nmnum ::= DEFAULT */ yytestcase(yyruleno==368);
+ /* (369) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==369);
+ /* (370) foreach_clause ::= */ yytestcase(yyruleno==370);
+ /* (371) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==371);
+ /* (372) trnm ::= nm */ yytestcase(yyruleno==372);
+ /* (373) tridxby ::= */ yytestcase(yyruleno==373);
+ /* (374) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==374);
+ /* (375) database_kw_opt ::= */ yytestcase(yyruleno==375);
+ /* (376) kwcolumn_opt ::= */ yytestcase(yyruleno==376);
+ /* (377) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==377);
+ /* (378) vtabarglist ::= vtabarg */ yytestcase(yyruleno==378);
+ /* (379) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==379);
+ /* (380) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==380);
+ /* (381) anylist ::= */ yytestcase(yyruleno==381);
+ /* (382) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==382);
+ /* (383) anylist ::= anylist ANY */ yytestcase(yyruleno==383);
+ /* (384) with ::= */ yytestcase(yyruleno==384);
break;
/********** End reduce actions ************************************************/
};
- assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
- yygoto = yyRuleInfo[yyruleno].lhs;
- yysize = yyRuleInfo[yyruleno].nrhs;
- yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
- if( yyact <= YY_MAX_SHIFTREDUCE ){
- if( yyact>YY_MAX_SHIFT ){
- yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
- }
- yymsp -= yysize-1;
- yypParser->yytos = yymsp;
- yymsp->stateno = (YYACTIONTYPE)yyact;
- yymsp->major = (YYCODETYPE)yygoto;
- yyTraceShift(yypParser, yyact);
- }else{
- assert( yyact == YY_ACCEPT_ACTION );
- yypParser->yytos -= yysize;
- yy_accept(yypParser);
- }
+ assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
+ yygoto = yyRuleInfoLhs[yyruleno];
+ yysize = yyRuleInfoNRhs[yyruleno];
+ yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);
+
+ /* There are no SHIFTREDUCE actions on nonterminals because the table
+ ** generator has simplified them to pure REDUCE actions. */
+ assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) );
+
+ /* It is not possible for a REDUCE to be followed by an error */
+ assert( yyact!=YY_ERROR_ACTION );
+
+ yymsp += yysize+1;
+ yypParser->yytos = yymsp;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yyTraceShift(yypParser, yyact, "... then shift");
+ return yyact;
}
/*
@@ -136311,7 +158989,8 @@ static void yy_reduce(
static void yy_parse_failed(
yyParser *yypParser /* The parser */
){
- sqlite3ParserARG_FETCH;
+ sqlite3ParserARG_FETCH
+ sqlite3ParserCTX_FETCH
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
@@ -136322,7 +159001,8 @@ static void yy_parse_failed(
** parser fails */
/************ Begin %parse_failure code ***************************************/
/************ End %parse_failure code *****************************************/
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
+ sqlite3ParserCTX_STORE
}
#endif /* YYNOERRORRECOVERY */
@@ -136334,15 +159014,20 @@ static void yy_syntax_error(
int yymajor, /* The major type of the error token */
sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */
){
- sqlite3ParserARG_FETCH;
+ sqlite3ParserARG_FETCH
+ sqlite3ParserCTX_FETCH
#define TOKEN yyminor
/************ Begin %syntax_error code ****************************************/
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
- assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+ if( TOKEN.z[0] ){
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
+ }else{
+ sqlite3ErrorMsg(pParse, "incomplete input");
+ }
/************ End %syntax_error code ******************************************/
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
+ sqlite3ParserCTX_STORE
}
/*
@@ -136351,7 +159036,8 @@ static void yy_syntax_error(
static void yy_accept(
yyParser *yypParser /* The parser */
){
- sqlite3ParserARG_FETCH;
+ sqlite3ParserARG_FETCH
+ sqlite3ParserCTX_FETCH
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
@@ -136365,7 +159051,8 @@ static void yy_accept(
** parser accepts */
/*********** Begin %parse_accept code *****************************************/
/*********** End %parse_accept code *******************************************/
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
+ sqlite3ParserCTX_STORE
}
/* The main parser program.
@@ -136394,38 +159081,51 @@ SQLITE_PRIVATE void sqlite3Parser(
sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */
){
YYMINORTYPE yyminorunion;
- unsigned int yyact; /* The parser action. */
+ YYACTIONTYPE yyact; /* The parser action. */
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
int yyendofinput; /* True if we are at the end of input */
#endif
#ifdef YYERRORSYMBOL
int yyerrorhit = 0; /* True if yymajor has invoked an error */
#endif
- yyParser *yypParser; /* The parser */
+ yyParser *yypParser = (yyParser*)yyp; /* The parser */
+ sqlite3ParserCTX_FETCH
+ sqlite3ParserARG_STORE
- yypParser = (yyParser*)yyp;
assert( yypParser->yytos!=0 );
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
yyendofinput = (yymajor==0);
#endif
- sqlite3ParserARG_STORE;
+ yyact = yypParser->yytos->stateno;
#ifndef NDEBUG
if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+ if( yyact < YY_MIN_REDUCE ){
+ fprintf(yyTraceFILE,"%sInput '%s' in state %d\n",
+ yyTracePrompt,yyTokenName[yymajor],yyact);
+ }else{
+ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
+ yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
+ }
}
#endif
do{
- yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
- if( yyact <= YY_MAX_SHIFTREDUCE ){
- yy_shift(yypParser,yyact,yymajor,yyminor);
+ assert( yyact==yypParser->yytos->stateno );
+ yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
+ if( yyact >= YY_MIN_REDUCE ){
+ yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,
+ yyminor sqlite3ParserCTX_PARAM);
+ }else if( yyact <= YY_MAX_SHIFTREDUCE ){
+ yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt--;
#endif
- yymajor = YYNOCODE;
- }else if( yyact <= YY_MAX_REDUCE ){
- yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+ break;
+ }else if( yyact==YY_ACCEPT_ACTION ){
+ yypParser->yytos--;
+ yy_accept(yypParser);
+ return;
}else{
assert( yyact == YY_ERROR_ACTION );
yyminorunion.yy0 = yyminor;
@@ -136440,7 +159140,7 @@ SQLITE_PRIVATE void sqlite3Parser(
#ifdef YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
+ ** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
@@ -136472,10 +159172,9 @@ SQLITE_PRIVATE void sqlite3Parser(
yymajor = YYNOCODE;
}else{
while( yypParser->yytos >= yypParser->yystack
- && yymx != YYERRORSYMBOL
&& (yyact = yy_find_reduce_action(
yypParser->yytos->stateno,
- YYERRORSYMBOL)) >= YY_MIN_REDUCE
+ YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE
){
yy_pop_parser_stack(yypParser);
}
@@ -136492,6 +159191,8 @@ SQLITE_PRIVATE void sqlite3Parser(
}
yypParser->yyerrcnt = 3;
yyerrorhit = 1;
+ if( yymajor==YYNOCODE ) break;
+ yyact = yypParser->yytos->stateno;
#elif defined(YYNOERRORRECOVERY)
/* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
** do any kind of error recovery. Instead, simply invoke the syntax
@@ -136502,8 +159203,7 @@ SQLITE_PRIVATE void sqlite3Parser(
*/
yy_syntax_error(yypParser,yymajor, yyminor);
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
- yymajor = YYNOCODE;
-
+ break;
#else /* YYERRORSYMBOL is not defined */
/* This is what we do if the grammar does not define ERROR:
**
@@ -136525,10 +159225,10 @@ SQLITE_PRIVATE void sqlite3Parser(
yypParser->yyerrcnt = -1;
#endif
}
- yymajor = YYNOCODE;
+ break;
#endif
}
- }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
+ }while( yypParser->yytos>yypParser->yystack );
#ifndef NDEBUG
if( yyTraceFILE ){
yyStackEntry *i;
@@ -136544,6 +159244,20 @@ SQLITE_PRIVATE void sqlite3Parser(
return;
}
+/*
+** Return the fallback token corresponding to canonical token iToken, or
+** 0 if iToken has no fallback.
+*/
+SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){
+#ifdef YYFALLBACK
+ assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
+ return yyFallback[iToken];
+#else
+ (void)iToken;
+ return 0;
+#endif
+}
+
/************** End of parse.c ***********************************************/
/************** Begin file tokenize.c ****************************************/
/*
@@ -136602,11 +159316,12 @@ SQLITE_PRIVATE void sqlite3Parser(
#define CC_TILDA 25 /* '~' */
#define CC_DOT 26 /* '.' */
#define CC_ILLEGAL 27 /* Illegal character */
+#define CC_NUL 28 /* 0x00 */
static const unsigned char aiClass[] = {
#ifdef SQLITE_ASCII
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
-/* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
+/* 0x */ 28, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
@@ -136629,13 +159344,13 @@ static const unsigned char aiClass[] = {
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 12, 17, 20, 10,
+/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10,
/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27,
-/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 7,
+/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6,
/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8,
/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
-/* 9x */ 25, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
+/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27,
/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
@@ -136649,7 +159364,7 @@ static const unsigned char aiClass[] = {
** lower-case ASCII equivalent. On ASCII machines, this is just
** an upper-to-lower case map. On EBCDIC machines we also need
** to adjust the encoding. The mapping is only valid for alphabetics
-** which are the only characters for which this feature is used.
+** which are the only characters for which this feature is used.
**
** Used by keywordhash.h
*/
@@ -136681,7 +159396,7 @@ const unsigned char ebcdicToAscii[] = {
/*
** The sqlite3KeywordCode function looks up an identifier to determine if
-** it is a keyword. If it is a keyword, the token code of that keyword is
+** it is a keyword. If it is a keyword, the token code of that keyword is
** returned. If the input is not a keyword, TK_ID is returned.
**
** The implementation of this routine was generated by a program,
@@ -136705,139 +159420,300 @@ const unsigned char ebcdicToAscii[] = {
** is substantially reduced. This is important for embedded applications
** on platforms with limited memory.
*/
-/* Hash score: 182 */
+/* Hash score: 227 */
+/* zKWText[] encodes 984 bytes of keyword text in 648 bytes */
+/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
+/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */
+/* IESNOTNULLIKEXCEPTRANSACTIONATURALTERAISEXCLUSIVEXISTS */
+/* CONSTRAINTOFFSETRIGGERANGENERATEDETACHAVINGLOBEGINNEREFERENCES */
+/* UNIQUERYWITHOUTERELEASEATTACHBETWEENOTHINGROUPSCASCADEFAULT */
+/* CASECOLLATECREATECURRENT_DATEIMMEDIATEJOINSERTMATCHPLANALYZE */
+/* PRAGMABORTUPDATEVALUESVIRTUALWAYSWHENWHERECURSIVEAFTERENAMEAND */
+/* EFERREDISTINCTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSS */
+/* CURRENT_TIMESTAMPARTITIONDROPRECEDINGFAILASTFILTEREPLACEFIRST */
+/* FOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVERIGHTROLLBACKROWS */
+/* UNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBYINITIALLYPRIMARY */
+static const char zKWText[647] = {
+ 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
+ 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
+ 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
+ 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
+ 'E','R','R','A','B','L','E','L','S','E','X','C','L','U','D','E','L','E',
+ 'T','E','M','P','O','R','A','R','Y','I','S','N','U','L','L','S','A','V',
+ 'E','P','O','I','N','T','E','R','S','E','C','T','I','E','S','N','O','T',
+ 'N','U','L','L','I','K','E','X','C','E','P','T','R','A','N','S','A','C',
+ 'T','I','O','N','A','T','U','R','A','L','T','E','R','A','I','S','E','X',
+ 'C','L','U','S','I','V','E','X','I','S','T','S','C','O','N','S','T','R',
+ 'A','I','N','T','O','F','F','S','E','T','R','I','G','G','E','R','A','N',
+ 'G','E','N','E','R','A','T','E','D','E','T','A','C','H','A','V','I','N',
+ 'G','L','O','B','E','G','I','N','N','E','R','E','F','E','R','E','N','C',
+ 'E','S','U','N','I','Q','U','E','R','Y','W','I','T','H','O','U','T','E',
+ 'R','E','L','E','A','S','E','A','T','T','A','C','H','B','E','T','W','E',
+ 'E','N','O','T','H','I','N','G','R','O','U','P','S','C','A','S','C','A',
+ 'D','E','F','A','U','L','T','C','A','S','E','C','O','L','L','A','T','E',
+ 'C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E',
+ 'I','M','M','E','D','I','A','T','E','J','O','I','N','S','E','R','T','M',
+ 'A','T','C','H','P','L','A','N','A','L','Y','Z','E','P','R','A','G','M',
+ 'A','B','O','R','T','U','P','D','A','T','E','V','A','L','U','E','S','V',
+ 'I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H','E','R',
+ 'E','C','U','R','S','I','V','E','A','F','T','E','R','E','N','A','M','E',
+ 'A','N','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','A',
+ 'U','T','O','I','N','C','R','E','M','E','N','T','C','A','S','T','C','O',
+ 'L','U','M','N','C','O','M','M','I','T','C','O','N','F','L','I','C','T',
+ 'C','R','O','S','S','C','U','R','R','E','N','T','_','T','I','M','E','S',
+ 'T','A','M','P','A','R','T','I','T','I','O','N','D','R','O','P','R','E',
+ 'C','E','D','I','N','G','F','A','I','L','A','S','T','F','I','L','T','E',
+ 'R','E','P','L','A','C','E','F','I','R','S','T','F','O','L','L','O','W',
+ 'I','N','G','F','R','O','M','F','U','L','L','I','M','I','T','I','F','O',
+ 'R','D','E','R','E','S','T','R','I','C','T','O','T','H','E','R','S','O',
+ 'V','E','R','I','G','H','T','R','O','L','L','B','A','C','K','R','O','W',
+ 'S','U','N','B','O','U','N','D','E','D','U','N','I','O','N','U','S','I',
+ 'N','G','V','A','C','U','U','M','V','I','E','W','I','N','D','O','W','B',
+ 'Y','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R','Y',
+};
+/* aKWHash[i] is the hash value for the i-th keyword */
+static const unsigned char aKWHash[127] = {
+ 84, 102, 132, 82, 114, 29, 0, 0, 91, 0, 85, 72, 0,
+ 53, 35, 86, 15, 0, 42, 94, 54, 126, 133, 19, 0, 0,
+ 138, 0, 40, 128, 0, 22, 104, 0, 9, 0, 0, 122, 80,
+ 0, 78, 6, 0, 65, 99, 145, 0, 134, 112, 0, 0, 48,
+ 0, 100, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 140,
+ 107, 121, 0, 73, 101, 71, 143, 61, 119, 74, 0, 49, 0,
+ 11, 41, 0, 110, 0, 0, 0, 106, 10, 108, 113, 124, 14,
+ 50, 123, 0, 89, 0, 18, 120, 142, 56, 129, 137, 88, 83,
+ 37, 30, 125, 0, 0, 105, 51, 130, 127, 0, 34, 0, 0,
+ 44, 0, 95, 38, 39, 0, 20, 45, 116, 90,
+};
+/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0
+** then the i-th keyword has no more hash collisions. Otherwise,
+** the next keyword with the same hash is aKWHash[i]-1. */
+static const unsigned char aKWNext[145] = {
+ 0, 0, 0, 0, 4, 0, 43, 0, 0, 103, 111, 0, 0,
+ 0, 2, 0, 0, 141, 0, 0, 0, 13, 0, 0, 0, 0,
+ 139, 0, 0, 118, 52, 0, 0, 135, 12, 0, 0, 62, 0,
+ 136, 0, 131, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0,
+ 0, 59, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 69, 0, 0, 0, 0, 0, 144, 3, 0, 58, 0, 1,
+ 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 64, 66,
+ 63, 0, 0, 0, 0, 46, 0, 16, 0, 115, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 81, 97, 0, 8, 0, 109,
+ 21, 7, 67, 0, 79, 93, 117, 0, 0, 68, 0, 0, 96,
+ 0, 55, 0, 76, 0, 92, 32, 33, 57, 25, 0, 98, 0,
+ 0, 87,
+};
+/* aKWLen[i] is the length (in bytes) of the i-th keyword */
+static const unsigned char aKWLen[145] = {
+ 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
+ 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
+ 6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
+ 4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 10, 4, 6,
+ 2, 3, 7, 5, 9, 6, 6, 4, 5, 5, 10, 6, 5,
+ 7, 4, 5, 7, 6, 7, 7, 6, 5, 7, 3, 7, 4,
+ 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 5, 6, 6,
+ 7, 6, 4, 5, 9, 5, 6, 3, 8, 8, 2, 13, 2,
+ 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, 4, 9, 4,
+ 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6, 4,
+ 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2, 2, 9,
+ 3, 7,
+};
+/* aKWOffset[i] is the index into zKWText[] of the start of
+** the text for the i-th keyword. */
+static const unsigned short int aKWOffset[145] = {
+ 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
+ 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
+ 86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
+ 129, 132, 137, 142, 146, 147, 152, 156, 160, 168, 174, 181, 184,
+ 184, 187, 189, 195, 198, 206, 211, 216, 219, 222, 226, 236, 239,
+ 244, 244, 248, 252, 259, 265, 271, 277, 277, 283, 284, 288, 295,
+ 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 360, 365, 371,
+ 377, 382, 388, 392, 395, 404, 408, 414, 416, 423, 424, 431, 433,
+ 435, 444, 448, 454, 460, 468, 473, 473, 473, 489, 498, 501, 510,
+ 513, 517, 522, 529, 534, 543, 547, 550, 555, 557, 561, 569, 575,
+ 578, 583, 591, 591, 595, 604, 609, 614, 620, 623, 626, 629, 631,
+ 636, 640,
+};
+/* aKWCode[i] is the parser symbol code for the i-th keyword */
+static const unsigned char aKWCode[145] = {
+ TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
+ TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
+ TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
+ TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE,
+ TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE,
+ TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR,
+ TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES,
+ TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW,
+ TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW,
+ TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT,
+ TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER,
+ TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW,
+ TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY,
+ TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH,
+ TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE,
+ TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE,
+ TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH,
+ TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_ABORT, TK_UPDATE,
+ TK_VALUES, TK_VIRTUAL, TK_ALWAYS, TK_WHEN, TK_WHERE,
+ TK_RECURSIVE, TK_AFTER, TK_RENAME, TK_AND, TK_DEFERRED,
+ TK_DISTINCT, TK_IS, TK_AUTOINCR, TK_TO, TK_IN,
+ TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW,
+ TK_CTIME_KW, TK_CTIME_KW, TK_CURRENT, TK_PARTITION, TK_DROP,
+ TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER, TK_REPLACE,
+ TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, TK_LIMIT,
+ TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS, TK_OVER,
+ TK_JOIN_KW, TK_ROLLBACK, TK_ROWS, TK_ROW, TK_UNBOUNDED,
+ TK_UNION, TK_USING, TK_VACUUM, TK_VIEW, TK_WINDOW,
+ TK_DO, TK_BY, TK_INITIALLY, TK_ALL, TK_PRIMARY,
+};
+/* Hash table decoded:
+** 0: INSERT
+** 1: IS
+** 2: ROLLBACK TRIGGER
+** 3: IMMEDIATE
+** 4: PARTITION
+** 5: TEMP
+** 6:
+** 7:
+** 8: VALUES WITHOUT
+** 9:
+** 10: MATCH
+** 11: NOTHING
+** 12:
+** 13: OF
+** 14: TIES IGNORE
+** 15: PLAN
+** 16: INSTEAD INDEXED
+** 17:
+** 18: TRANSACTION RIGHT
+** 19: WHEN
+** 20: SET HAVING
+** 21: IF
+** 22: ROWS
+** 23: SELECT
+** 24:
+** 25:
+** 26: VACUUM SAVEPOINT
+** 27:
+** 28: LIKE UNION VIRTUAL REFERENCES
+** 29: RESTRICT
+** 30:
+** 31: THEN REGEXP
+** 32: TO
+** 33:
+** 34: BEFORE
+** 35:
+** 36:
+** 37: FOLLOWING COLLATE CASCADE
+** 38: CREATE
+** 39:
+** 40: CASE REINDEX
+** 41: EACH
+** 42:
+** 43: QUERY
+** 44: AND ADD
+** 45: PRIMARY ANALYZE
+** 46:
+** 47: ROW ASC DETACH
+** 48: CURRENT_TIME CURRENT_DATE
+** 49:
+** 50:
+** 51: EXCLUSIVE TEMPORARY
+** 52:
+** 53: DEFERRED
+** 54: DEFERRABLE
+** 55:
+** 56: DATABASE
+** 57:
+** 58: DELETE VIEW GENERATED
+** 59: ATTACH
+** 60: END
+** 61: EXCLUDE
+** 62: ESCAPE DESC
+** 63: GLOB
+** 64: WINDOW ELSE
+** 65: COLUMN
+** 66: FIRST
+** 67:
+** 68: GROUPS ALL
+** 69: DISTINCT DROP KEY
+** 70: BETWEEN
+** 71: INITIALLY
+** 72: BEGIN
+** 73: FILTER CHECK ACTION
+** 74: GROUP INDEX
+** 75:
+** 76: EXISTS DEFAULT
+** 77:
+** 78: FOR CURRENT_TIMESTAMP
+** 79: EXCEPT
+** 80:
+** 81: CROSS
+** 82:
+** 83:
+** 84:
+** 85: CAST
+** 86: FOREIGN AUTOINCREMENT
+** 87: COMMIT
+** 88: CURRENT AFTER ALTER
+** 89: FULL FAIL CONFLICT
+** 90: EXPLAIN
+** 91: CONSTRAINT
+** 92: FROM ALWAYS
+** 93:
+** 94: ABORT
+** 95:
+** 96: AS DO
+** 97: REPLACE WITH RELEASE
+** 98: BY RENAME
+** 99: RANGE RAISE
+** 100: OTHERS
+** 101: USING NULLS
+** 102: PRAGMA
+** 103: JOIN ISNULL OFFSET
+** 104: NOT
+** 105: OR LAST LEFT
+** 106: LIMIT
+** 107:
+** 108:
+** 109: IN
+** 110: INTO
+** 111: OVER RECURSIVE
+** 112: ORDER OUTER
+** 113:
+** 114: INTERSECT UNBOUNDED
+** 115:
+** 116:
+** 117: ON
+** 118:
+** 119: WHERE
+** 120: NO INNER
+** 121: NULL
+** 122:
+** 123: TABLE
+** 124: NATURAL NOTNULL
+** 125: PRECEDING
+** 126: UPDATE UNIQUE
+*/
+/* Check to see if z[0..n-1] is a keyword. If it is, write the
+** parser symbol code for that keyword into *pType. Always
+** return the integer n (the length of the token). */
static int keywordCode(const char *z, int n, int *pType){
- /* zText[] encodes 834 bytes of keywords in 554 bytes */
- /* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
- /* ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE */
- /* XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY */
- /* UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE */
- /* BETWEENOTNULLIKECASCADELETECASECOLLATECREATECURRENT_DATEDETACH */
- /* IMMEDIATEJOINSERTMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMITWHEN */
- /* WHERENAMEAFTEREPLACEANDEFAULTAUTOINCREMENTCASTCOLUMNCOMMIT */
- /* CONFLICTCROSSCURRENT_TIMESTAMPRIMARYDEFERREDISTINCTDROPFAIL */
- /* FROMFULLGLOBYIFISNULLORDERESTRICTRIGHTROLLBACKROWUNIONUSING */
- /* VACUUMVIEWINITIALLY */
- static const char zText[553] = {
- 'R','E','I','N','D','E','X','E','D','E','S','C','A','P','E','A','C','H',
- 'E','C','K','E','Y','B','E','F','O','R','E','I','G','N','O','R','E','G',
- 'E','X','P','L','A','I','N','S','T','E','A','D','D','A','T','A','B','A',
- 'S','E','L','E','C','T','A','B','L','E','F','T','H','E','N','D','E','F',
- 'E','R','R','A','B','L','E','L','S','E','X','C','E','P','T','R','A','N',
- 'S','A','C','T','I','O','N','A','T','U','R','A','L','T','E','R','A','I',
- 'S','E','X','C','L','U','S','I','V','E','X','I','S','T','S','A','V','E',
- 'P','O','I','N','T','E','R','S','E','C','T','R','I','G','G','E','R','E',
- 'F','E','R','E','N','C','E','S','C','O','N','S','T','R','A','I','N','T',
- 'O','F','F','S','E','T','E','M','P','O','R','A','R','Y','U','N','I','Q',
- 'U','E','R','Y','W','I','T','H','O','U','T','E','R','E','L','E','A','S',
- 'E','A','T','T','A','C','H','A','V','I','N','G','R','O','U','P','D','A',
- 'T','E','B','E','G','I','N','N','E','R','E','C','U','R','S','I','V','E',
- 'B','E','T','W','E','E','N','O','T','N','U','L','L','I','K','E','C','A',
- 'S','C','A','D','E','L','E','T','E','C','A','S','E','C','O','L','L','A',
- 'T','E','C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A',
- 'T','E','D','E','T','A','C','H','I','M','M','E','D','I','A','T','E','J',
- 'O','I','N','S','E','R','T','M','A','T','C','H','P','L','A','N','A','L',
- 'Y','Z','E','P','R','A','G','M','A','B','O','R','T','V','A','L','U','E',
- 'S','V','I','R','T','U','A','L','I','M','I','T','W','H','E','N','W','H',
- 'E','R','E','N','A','M','E','A','F','T','E','R','E','P','L','A','C','E',
- 'A','N','D','E','F','A','U','L','T','A','U','T','O','I','N','C','R','E',
- 'M','E','N','T','C','A','S','T','C','O','L','U','M','N','C','O','M','M',
- 'I','T','C','O','N','F','L','I','C','T','C','R','O','S','S','C','U','R',
- 'R','E','N','T','_','T','I','M','E','S','T','A','M','P','R','I','M','A',
- 'R','Y','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','D',
- 'R','O','P','F','A','I','L','F','R','O','M','F','U','L','L','G','L','O',
- 'B','Y','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T',
- 'R','I','C','T','R','I','G','H','T','R','O','L','L','B','A','C','K','R',
- 'O','W','U','N','I','O','N','U','S','I','N','G','V','A','C','U','U','M',
- 'V','I','E','W','I','N','I','T','I','A','L','L','Y',
- };
- static const unsigned char aHash[127] = {
- 76, 105, 117, 74, 0, 45, 0, 0, 82, 0, 77, 0, 0,
- 42, 12, 78, 15, 0, 116, 85, 54, 112, 0, 19, 0, 0,
- 121, 0, 119, 115, 0, 22, 93, 0, 9, 0, 0, 70, 71,
- 0, 69, 6, 0, 48, 90, 102, 0, 118, 101, 0, 0, 44,
- 0, 103, 24, 0, 17, 0, 122, 53, 23, 0, 5, 110, 25,
- 96, 0, 0, 124, 106, 60, 123, 57, 28, 55, 0, 91, 0,
- 100, 26, 0, 99, 0, 0, 0, 95, 92, 97, 88, 109, 14,
- 39, 108, 0, 81, 0, 18, 89, 111, 32, 0, 120, 80, 113,
- 62, 46, 84, 0, 0, 94, 40, 59, 114, 0, 36, 0, 0,
- 29, 0, 86, 63, 64, 0, 20, 61, 0, 56,
- };
- static const unsigned char aNext[124] = {
- 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 2, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0,
- 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 33, 0, 21, 0, 0, 0, 0, 0, 50,
- 0, 43, 3, 47, 0, 0, 0, 0, 30, 0, 58, 0, 38,
- 0, 0, 0, 1, 66, 0, 0, 67, 0, 41, 0, 0, 0,
- 0, 0, 0, 49, 65, 0, 0, 0, 0, 31, 52, 16, 34,
- 10, 0, 0, 0, 0, 0, 0, 0, 11, 72, 79, 0, 8,
- 0, 104, 98, 0, 107, 0, 87, 0, 75, 51, 0, 27, 37,
- 73, 83, 0, 35, 68, 0, 0,
- };
- static const unsigned char aLen[124] = {
- 7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
- 7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 6,
- 11, 6, 2, 7, 5, 5, 9, 6, 9, 9, 7, 10, 10,
- 4, 6, 2, 3, 9, 4, 2, 6, 5, 7, 4, 5, 7,
- 6, 6, 5, 6, 5, 5, 9, 7, 7, 3, 2, 4, 4,
- 7, 3, 6, 4, 7, 6, 12, 6, 9, 4, 6, 5, 4,
- 7, 6, 5, 6, 7, 5, 4, 5, 6, 5, 7, 3, 7,
- 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 8, 8,
- 2, 4, 4, 4, 4, 4, 2, 2, 6, 5, 8, 5, 8,
- 3, 5, 5, 6, 4, 9, 3,
- };
- static const unsigned short int aOffset[124] = {
- 0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
- 36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
- 86, 91, 95, 96, 101, 105, 109, 117, 122, 128, 136, 142, 152,
- 159, 162, 162, 165, 167, 167, 171, 176, 179, 184, 184, 188, 192,
- 199, 204, 209, 212, 218, 221, 225, 234, 240, 240, 240, 243, 246,
- 250, 251, 255, 261, 265, 272, 278, 290, 296, 305, 307, 313, 318,
- 320, 327, 332, 337, 343, 349, 354, 358, 361, 367, 371, 378, 380,
- 387, 389, 391, 400, 404, 410, 416, 424, 429, 429, 445, 452, 459,
- 460, 467, 471, 475, 479, 483, 486, 488, 490, 496, 500, 508, 513,
- 521, 524, 529, 534, 540, 544, 549,
- };
- static const unsigned char aCode[124] = {
- TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
- TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
- TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
- TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE,
- TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE,
- TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW,
- TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_SAVEPOINT,
- TK_INTERSECT, TK_TRIGGER, TK_REFERENCES, TK_CONSTRAINT, TK_INTO,
- TK_OFFSET, TK_OF, TK_SET, TK_TEMP, TK_TEMP,
- TK_OR, TK_UNIQUE, TK_QUERY, TK_WITHOUT, TK_WITH,
- TK_JOIN_KW, TK_RELEASE, TK_ATTACH, TK_HAVING, TK_GROUP,
- TK_UPDATE, TK_BEGIN, TK_JOIN_KW, TK_RECURSIVE, TK_BETWEEN,
- TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW,
- TK_CASCADE, TK_ASC, TK_DELETE, TK_CASE, TK_COLLATE,
- TK_CREATE, TK_CTIME_KW, TK_DETACH, TK_IMMEDIATE, TK_JOIN,
- TK_INSERT, TK_MATCH, TK_PLAN, TK_ANALYZE, TK_PRAGMA,
- TK_ABORT, TK_VALUES, TK_VIRTUAL, TK_LIMIT, TK_WHEN,
- TK_WHERE, TK_RENAME, TK_AFTER, TK_REPLACE, TK_AND,
- TK_DEFAULT, TK_AUTOINCR, TK_TO, TK_IN, TK_CAST,
- TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW,
- TK_CTIME_KW, TK_PRIMARY, TK_DEFERRED, TK_DISTINCT, TK_IS,
- TK_DROP, TK_FAIL, TK_FROM, TK_JOIN_KW, TK_LIKE_KW,
- TK_BY, TK_IF, TK_ISNULL, TK_ORDER, TK_RESTRICT,
- TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_UNION, TK_USING,
- TK_VACUUM, TK_VIEW, TK_INITIALLY, TK_ALL,
- };
int i, j;
const char *zKW;
if( n>=2 ){
i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;
- for(i=((int)aHash[i])-1; i>=0; i=((int)aNext[i])-1){
- if( aLen[i]!=n ) continue;
- j = 0;
- zKW = &zText[aOffset[i]];
+ for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
+ if( aKWLen[i]!=n ) continue;
+ zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
+ if( (z[0]&~0x20)!=zKW[0] ) continue;
+ if( (z[1]&~0x20)!=zKW[1] ) continue;
+ j = 2;
while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
#endif
#ifdef SQLITE_EBCDIC
+ if( toupper(z[0])!=zKW[0] ) continue;
+ if( toupper(z[1])!=zKW[1] ) continue;
+ j = 2;
while( j<n && toupper(z[j])==zKW[j] ){ j++; }
#endif
if( j<n ) continue;
@@ -136866,106 +159742,127 @@ static int keywordCode(const char *z, int n, int *pType){
testcase( i==22 ); /* END */
testcase( i==23 ); /* DEFERRABLE */
testcase( i==24 ); /* ELSE */
- testcase( i==25 ); /* EXCEPT */
- testcase( i==26 ); /* TRANSACTION */
- testcase( i==27 ); /* ACTION */
- testcase( i==28 ); /* ON */
- testcase( i==29 ); /* NATURAL */
- testcase( i==30 ); /* ALTER */
- testcase( i==31 ); /* RAISE */
- testcase( i==32 ); /* EXCLUSIVE */
- testcase( i==33 ); /* EXISTS */
- testcase( i==34 ); /* SAVEPOINT */
- testcase( i==35 ); /* INTERSECT */
- testcase( i==36 ); /* TRIGGER */
- testcase( i==37 ); /* REFERENCES */
- testcase( i==38 ); /* CONSTRAINT */
- testcase( i==39 ); /* INTO */
- testcase( i==40 ); /* OFFSET */
- testcase( i==41 ); /* OF */
- testcase( i==42 ); /* SET */
- testcase( i==43 ); /* TEMPORARY */
- testcase( i==44 ); /* TEMP */
- testcase( i==45 ); /* OR */
- testcase( i==46 ); /* UNIQUE */
- testcase( i==47 ); /* QUERY */
- testcase( i==48 ); /* WITHOUT */
- testcase( i==49 ); /* WITH */
- testcase( i==50 ); /* OUTER */
- testcase( i==51 ); /* RELEASE */
- testcase( i==52 ); /* ATTACH */
- testcase( i==53 ); /* HAVING */
- testcase( i==54 ); /* GROUP */
- testcase( i==55 ); /* UPDATE */
- testcase( i==56 ); /* BEGIN */
- testcase( i==57 ); /* INNER */
- testcase( i==58 ); /* RECURSIVE */
- testcase( i==59 ); /* BETWEEN */
- testcase( i==60 ); /* NOTNULL */
- testcase( i==61 ); /* NOT */
- testcase( i==62 ); /* NO */
- testcase( i==63 ); /* NULL */
- testcase( i==64 ); /* LIKE */
- testcase( i==65 ); /* CASCADE */
- testcase( i==66 ); /* ASC */
- testcase( i==67 ); /* DELETE */
- testcase( i==68 ); /* CASE */
- testcase( i==69 ); /* COLLATE */
- testcase( i==70 ); /* CREATE */
- testcase( i==71 ); /* CURRENT_DATE */
- testcase( i==72 ); /* DETACH */
- testcase( i==73 ); /* IMMEDIATE */
- testcase( i==74 ); /* JOIN */
- testcase( i==75 ); /* INSERT */
- testcase( i==76 ); /* MATCH */
- testcase( i==77 ); /* PLAN */
- testcase( i==78 ); /* ANALYZE */
- testcase( i==79 ); /* PRAGMA */
- testcase( i==80 ); /* ABORT */
- testcase( i==81 ); /* VALUES */
- testcase( i==82 ); /* VIRTUAL */
- testcase( i==83 ); /* LIMIT */
- testcase( i==84 ); /* WHEN */
- testcase( i==85 ); /* WHERE */
- testcase( i==86 ); /* RENAME */
- testcase( i==87 ); /* AFTER */
- testcase( i==88 ); /* REPLACE */
- testcase( i==89 ); /* AND */
- testcase( i==90 ); /* DEFAULT */
- testcase( i==91 ); /* AUTOINCREMENT */
- testcase( i==92 ); /* TO */
- testcase( i==93 ); /* IN */
- testcase( i==94 ); /* CAST */
- testcase( i==95 ); /* COLUMN */
- testcase( i==96 ); /* COMMIT */
- testcase( i==97 ); /* CONFLICT */
- testcase( i==98 ); /* CROSS */
- testcase( i==99 ); /* CURRENT_TIMESTAMP */
- testcase( i==100 ); /* CURRENT_TIME */
- testcase( i==101 ); /* PRIMARY */
- testcase( i==102 ); /* DEFERRED */
- testcase( i==103 ); /* DISTINCT */
- testcase( i==104 ); /* IS */
- testcase( i==105 ); /* DROP */
- testcase( i==106 ); /* FAIL */
- testcase( i==107 ); /* FROM */
- testcase( i==108 ); /* FULL */
- testcase( i==109 ); /* GLOB */
- testcase( i==110 ); /* BY */
- testcase( i==111 ); /* IF */
- testcase( i==112 ); /* ISNULL */
- testcase( i==113 ); /* ORDER */
- testcase( i==114 ); /* RESTRICT */
- testcase( i==115 ); /* RIGHT */
- testcase( i==116 ); /* ROLLBACK */
- testcase( i==117 ); /* ROW */
- testcase( i==118 ); /* UNION */
- testcase( i==119 ); /* USING */
- testcase( i==120 ); /* VACUUM */
- testcase( i==121 ); /* VIEW */
- testcase( i==122 ); /* INITIALLY */
- testcase( i==123 ); /* ALL */
- *pType = aCode[i];
+ testcase( i==25 ); /* EXCLUDE */
+ testcase( i==26 ); /* DELETE */
+ testcase( i==27 ); /* TEMPORARY */
+ testcase( i==28 ); /* TEMP */
+ testcase( i==29 ); /* OR */
+ testcase( i==30 ); /* ISNULL */
+ testcase( i==31 ); /* NULLS */
+ testcase( i==32 ); /* SAVEPOINT */
+ testcase( i==33 ); /* INTERSECT */
+ testcase( i==34 ); /* TIES */
+ testcase( i==35 ); /* NOTNULL */
+ testcase( i==36 ); /* NOT */
+ testcase( i==37 ); /* NO */
+ testcase( i==38 ); /* NULL */
+ testcase( i==39 ); /* LIKE */
+ testcase( i==40 ); /* EXCEPT */
+ testcase( i==41 ); /* TRANSACTION */
+ testcase( i==42 ); /* ACTION */
+ testcase( i==43 ); /* ON */
+ testcase( i==44 ); /* NATURAL */
+ testcase( i==45 ); /* ALTER */
+ testcase( i==46 ); /* RAISE */
+ testcase( i==47 ); /* EXCLUSIVE */
+ testcase( i==48 ); /* EXISTS */
+ testcase( i==49 ); /* CONSTRAINT */
+ testcase( i==50 ); /* INTO */
+ testcase( i==51 ); /* OFFSET */
+ testcase( i==52 ); /* OF */
+ testcase( i==53 ); /* SET */
+ testcase( i==54 ); /* TRIGGER */
+ testcase( i==55 ); /* RANGE */
+ testcase( i==56 ); /* GENERATED */
+ testcase( i==57 ); /* DETACH */
+ testcase( i==58 ); /* HAVING */
+ testcase( i==59 ); /* GLOB */
+ testcase( i==60 ); /* BEGIN */
+ testcase( i==61 ); /* INNER */
+ testcase( i==62 ); /* REFERENCES */
+ testcase( i==63 ); /* UNIQUE */
+ testcase( i==64 ); /* QUERY */
+ testcase( i==65 ); /* WITHOUT */
+ testcase( i==66 ); /* WITH */
+ testcase( i==67 ); /* OUTER */
+ testcase( i==68 ); /* RELEASE */
+ testcase( i==69 ); /* ATTACH */
+ testcase( i==70 ); /* BETWEEN */
+ testcase( i==71 ); /* NOTHING */
+ testcase( i==72 ); /* GROUPS */
+ testcase( i==73 ); /* GROUP */
+ testcase( i==74 ); /* CASCADE */
+ testcase( i==75 ); /* ASC */
+ testcase( i==76 ); /* DEFAULT */
+ testcase( i==77 ); /* CASE */
+ testcase( i==78 ); /* COLLATE */
+ testcase( i==79 ); /* CREATE */
+ testcase( i==80 ); /* CURRENT_DATE */
+ testcase( i==81 ); /* IMMEDIATE */
+ testcase( i==82 ); /* JOIN */
+ testcase( i==83 ); /* INSERT */
+ testcase( i==84 ); /* MATCH */
+ testcase( i==85 ); /* PLAN */
+ testcase( i==86 ); /* ANALYZE */
+ testcase( i==87 ); /* PRAGMA */
+ testcase( i==88 ); /* ABORT */
+ testcase( i==89 ); /* UPDATE */
+ testcase( i==90 ); /* VALUES */
+ testcase( i==91 ); /* VIRTUAL */
+ testcase( i==92 ); /* ALWAYS */
+ testcase( i==93 ); /* WHEN */
+ testcase( i==94 ); /* WHERE */
+ testcase( i==95 ); /* RECURSIVE */
+ testcase( i==96 ); /* AFTER */
+ testcase( i==97 ); /* RENAME */
+ testcase( i==98 ); /* AND */
+ testcase( i==99 ); /* DEFERRED */
+ testcase( i==100 ); /* DISTINCT */
+ testcase( i==101 ); /* IS */
+ testcase( i==102 ); /* AUTOINCREMENT */
+ testcase( i==103 ); /* TO */
+ testcase( i==104 ); /* IN */
+ testcase( i==105 ); /* CAST */
+ testcase( i==106 ); /* COLUMN */
+ testcase( i==107 ); /* COMMIT */
+ testcase( i==108 ); /* CONFLICT */
+ testcase( i==109 ); /* CROSS */
+ testcase( i==110 ); /* CURRENT_TIMESTAMP */
+ testcase( i==111 ); /* CURRENT_TIME */
+ testcase( i==112 ); /* CURRENT */
+ testcase( i==113 ); /* PARTITION */
+ testcase( i==114 ); /* DROP */
+ testcase( i==115 ); /* PRECEDING */
+ testcase( i==116 ); /* FAIL */
+ testcase( i==117 ); /* LAST */
+ testcase( i==118 ); /* FILTER */
+ testcase( i==119 ); /* REPLACE */
+ testcase( i==120 ); /* FIRST */
+ testcase( i==121 ); /* FOLLOWING */
+ testcase( i==122 ); /* FROM */
+ testcase( i==123 ); /* FULL */
+ testcase( i==124 ); /* LIMIT */
+ testcase( i==125 ); /* IF */
+ testcase( i==126 ); /* ORDER */
+ testcase( i==127 ); /* RESTRICT */
+ testcase( i==128 ); /* OTHERS */
+ testcase( i==129 ); /* OVER */
+ testcase( i==130 ); /* RIGHT */
+ testcase( i==131 ); /* ROLLBACK */
+ testcase( i==132 ); /* ROWS */
+ testcase( i==133 ); /* ROW */
+ testcase( i==134 ); /* UNBOUNDED */
+ testcase( i==135 ); /* UNION */
+ testcase( i==136 ); /* USING */
+ testcase( i==137 ); /* VACUUM */
+ testcase( i==138 ); /* VIEW */
+ testcase( i==139 ); /* WINDOW */
+ testcase( i==140 ); /* DO */
+ testcase( i==141 ); /* BY */
+ testcase( i==142 ); /* INITIALLY */
+ testcase( i==143 ); /* ALL */
+ testcase( i==144 ); /* PRIMARY */
+ *pType = aKWCode[i];
break;
}
}
@@ -136976,7 +159873,17 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
keywordCode((char*)z, n, &id);
return id;
}
-#define SQLITE_N_KEYWORD 124
+#define SQLITE_N_KEYWORD 145
+SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){
+ if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
+ *pzName = zKWText + aKWOffset[i];
+ *pnName = aKWLen[i];
+ return SQLITE_OK;
+}
+SQLITE_API int sqlite3_keyword_count(void){ return SQLITE_N_KEYWORD; }
+SQLITE_API int sqlite3_keyword_check(const char *zName, int nName){
+ return TK_ID!=sqlite3KeywordCode((const u8*)zName, nName);
+}
/************** End of keywordhash.h *****************************************/
/************** Continuing where we left off in tokenize.c *******************/
@@ -136987,14 +159894,14 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
** IdChar(X) will be true. Otherwise it is false.
**
** For ASCII, any character with the high-order bit set is
-** allowed in an identifier. For 7-bit characters,
+** allowed in an identifier. For 7-bit characters,
** sqlite3IsIdChar[X] must be 1.
**
** For EBCDIC, the rules are more complex but have the same
** end result.
**
** Ticket #1066. the SQL standard does not allow '$' in the
-** middle of identifiers. But many SQL implementations do.
+** middle of identifiers. But many SQL implementations do.
** SQLite will allow '$' in identifiers for compatibility.
** But the feature is undocumented.
*/
@@ -137020,14 +159927,88 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = {
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
#endif
-/* Make the IdChar function accessible from ctime.c */
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+/* Make the IdChar function accessible from ctime.c and alter.c */
SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }
-#endif
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Return the id of the next token in string (*pz). Before returning, set
+** (*pz) to point to the byte following the parsed token.
+*/
+static int getToken(const unsigned char **pz){
+ const unsigned char *z = *pz;
+ int t; /* Token type to return */
+ do {
+ z += sqlite3GetToken(z, &t);
+ }while( t==TK_SPACE );
+ if( t==TK_ID
+ || t==TK_STRING
+ || t==TK_JOIN_KW
+ || t==TK_WINDOW
+ || t==TK_OVER
+ || sqlite3ParserFallback(t)==TK_ID
+ ){
+ t = TK_ID;
+ }
+ *pz = z;
+ return t;
+}
+
+/*
+** The following three functions are called immediately after the tokenizer
+** reads the keywords WINDOW, OVER and FILTER, respectively, to determine
+** whether the token should be treated as a keyword or an SQL identifier.
+** This cannot be handled by the usual lemon %fallback method, due to
+** the ambiguity in some constructions. e.g.
+**
+** SELECT sum(x) OVER ...
+**
+** In the above, "OVER" might be a keyword, or it might be an alias for the
+** sum(x) expression. If a "%fallback ID OVER" directive were added to
+** grammar, then SQLite would always treat "OVER" as an alias, making it
+** impossible to call a window-function without a FILTER clause.
+**
+** WINDOW is treated as a keyword if:
+**
+** * the following token is an identifier, or a keyword that can fallback
+** to being an identifier, and
+** * the token after than one is TK_AS.
+**
+** OVER is a keyword if:
+**
+** * the previous token was TK_RP, and
+** * the next token is either TK_LP or an identifier.
+**
+** FILTER is a keyword if:
+**
+** * the previous token was TK_RP, and
+** * the next token is TK_LP.
+*/
+static int analyzeWindowKeyword(const unsigned char *z){
+ int t;
+ t = getToken(&z);
+ if( t!=TK_ID ) return TK_ID;
+ t = getToken(&z);
+ if( t!=TK_AS ) return TK_ID;
+ return TK_WINDOW;
+}
+static int analyzeOverKeyword(const unsigned char *z, int lastToken){
+ if( lastToken==TK_RP ){
+ int t = getToken(&z);
+ if( t==TK_LP || t==TK_ID ) return TK_OVER;
+ }
+ return TK_ID;
+}
+static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
+ if( lastToken==TK_RP && getToken(&z)==TK_LP ){
+ return TK_FILTER;
+ }
+ return TK_ID;
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
-** Return the length (in bytes) of the token that begins at z[0].
+** Return the length (in bytes) of the token that begins at z[0].
** Store the token type in *tokenType before returning.
*/
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
@@ -137184,6 +160165,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
}
/* If the next character is a digit, this is a floating point
** number that begins with ".". Fall thru into the next case */
+ /* no break */ deliberate_fall_through
}
case CC_DIGIT: {
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
@@ -137205,7 +160187,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_FLOAT;
}
if( (z[i]=='e' || z[i]=='E') &&
- ( sqlite3Isdigit(z[i+1])
+ ( sqlite3Isdigit(z[i+1])
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
)
){
@@ -137288,11 +160270,16 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
#endif
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
+ /* no break */ deliberate_fall_through
}
case CC_ID: {
i = 1;
break;
}
+ case CC_NUL: {
+ *tokenType = TK_ILLEGAL;
+ return 0;
+ }
default: {
*tokenType = TK_ILLEGAL;
return 1;
@@ -137306,79 +160293,115 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
/*
** Run the parser on the given SQL string. The parser structure is
** passed in. An SQLITE_ status code is returned. If an error occurs
-** then an and attempt is made to write an error message into
+** then an and attempt is made to write an error message into
** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that
** error message.
*/
SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int nErr = 0; /* Number of errors encountered */
- int i; /* Loop counter */
void *pEngine; /* The LEMON-generated LALR(1) parser */
+ int n = 0; /* Length of the next token token */
int tokenType; /* type of the next token */
int lastTokenParsed = -1; /* type of the previous token */
sqlite3 *db = pParse->db; /* The database connection */
int mxSqlLen; /* Max length of an SQL string */
+#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
+ yyParser sEngine; /* Space to hold the Lemon-generated Parser object */
+#endif
+ VVA_ONLY( u8 startedWithOom = db->mallocFailed );
assert( zSql!=0 );
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
if( db->nVdbeActive==0 ){
- db->u1.isInterrupted = 0;
+ AtomicStore(&db->u1.isInterrupted, 0);
}
pParse->rc = SQLITE_OK;
pParse->zTail = zSql;
- i = 0;
assert( pzErrMsg!=0 );
- /* sqlite3ParserTrace(stdout, "parser: "); */
- pEngine = sqlite3ParserAlloc(sqlite3Malloc);
+#ifdef SQLITE_DEBUG
+ if( db->flags & SQLITE_ParserTrace ){
+ printf("parser: [[[%s]]]\n", zSql);
+ sqlite3ParserTrace(stdout, "parser: ");
+ }else{
+ sqlite3ParserTrace(0, 0);
+ }
+#endif
+#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
+ pEngine = &sEngine;
+ sqlite3ParserInit(pEngine, pParse);
+#else
+ pEngine = sqlite3ParserAlloc(sqlite3Malloc, pParse);
if( pEngine==0 ){
sqlite3OomFault(db);
return SQLITE_NOMEM_BKPT;
}
+#endif
assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 );
- assert( pParse->nzVar==0 );
- assert( pParse->azVar==0 );
+ assert( pParse->pVList==0 );
+ pParse->pParentParse = db->pParse;
+ db->pParse = pParse;
while( 1 ){
- assert( i>=0 );
- if( zSql[i]!=0 ){
- pParse->sLastToken.z = &zSql[i];
- pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType);
- i += pParse->sLastToken.n;
- if( i>mxSqlLen ){
- pParse->rc = SQLITE_TOOBIG;
- break;
- }
- }else{
- /* Upon reaching the end of input, call the parser two more times
- ** with tokens TK_SEMI and 0, in that order. */
- if( lastTokenParsed==TK_SEMI ){
- tokenType = 0;
- }else if( lastTokenParsed==0 ){
- break;
- }else{
- tokenType = TK_SEMI;
- }
+ n = sqlite3GetToken((u8*)zSql, &tokenType);
+ mxSqlLen -= n;
+ if( mxSqlLen<0 ){
+ pParse->rc = SQLITE_TOOBIG;
+ break;
}
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( tokenType>=TK_WINDOW ){
+ assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
+ || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
+ );
+#else
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
- if( db->u1.isInterrupted ){
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+ if( AtomicLoad(&db->u1.isInterrupted) ){
pParse->rc = SQLITE_INTERRUPT;
break;
}
- if( tokenType==TK_ILLEGAL ){
- sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"",
- &pParse->sLastToken);
+ if( tokenType==TK_SPACE ){
+ zSql += n;
+ continue;
+ }
+ if( zSql[0]==0 ){
+ /* Upon reaching the end of input, call the parser two more times
+ ** with tokens TK_SEMI and 0, in that order. */
+ if( lastTokenParsed==TK_SEMI ){
+ tokenType = 0;
+ }else if( lastTokenParsed==0 ){
+ break;
+ }else{
+ tokenType = TK_SEMI;
+ }
+ n = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ }else if( tokenType==TK_WINDOW ){
+ assert( n==6 );
+ tokenType = analyzeWindowKeyword((const u8*)&zSql[6]);
+ }else if( tokenType==TK_OVER ){
+ assert( n==4 );
+ tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed);
+ }else if( tokenType==TK_FILTER ){
+ assert( n==6 );
+ tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+ }else{
+ sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
break;
}
- }else{
- sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
- lastTokenParsed = tokenType;
- if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
}
+ pParse->sLastToken.z = zSql;
+ pParse->sLastToken.n = n;
+ sqlite3Parser(pEngine, tokenType, pParse->sLastToken);
+ lastTokenParsed = tokenType;
+ zSql += n;
+ assert( db->mallocFailed==0 || pParse->rc!=SQLITE_OK || startedWithOom );
+ if( pParse->rc!=SQLITE_OK ) break;
}
assert( nErr==0 );
- pParse->zTail = &zSql[i];
#ifdef YYTRACKMAXSTACKDEPTH
sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
@@ -137386,7 +160409,11 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
);
sqlite3_mutex_leave(sqlite3MallocMutex());
#endif /* YYDEBUG */
+#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
+ sqlite3ParserFinalize(pEngine);
+#else
sqlite3ParserFree(pEngine, sqlite3_free);
+#endif
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM_BKPT;
}
@@ -137396,10 +160423,12 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
assert( pzErrMsg!=0 );
if( pParse->zErrMsg ){
*pzErrMsg = pParse->zErrMsg;
- sqlite3_log(pParse->rc, "%s", *pzErrMsg);
+ sqlite3_log(pParse->rc, "%s in \"%s\"",
+ *pzErrMsg, pParse->zTail);
pParse->zErrMsg = 0;
nErr++;
}
+ pParse->zTail = zSql;
if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
sqlite3VdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
@@ -137415,32 +160444,170 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
sqlite3_free(pParse->apVtabLock);
#endif
- if( !IN_DECLARE_VTAB ){
- /* If the pParse->declareVtab flag is set, do not delete any table
+ if( !IN_SPECIAL_PARSE ){
+ /* If the pParse->declareVtab flag is set, do not delete any table
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
** will take responsibility for freeing the Table structure.
*/
sqlite3DeleteTable(db, pParse->pNewTable);
}
+ if( !IN_RENAME_OBJECT ){
+ sqlite3DeleteTrigger(db, pParse->pNewTrigger);
+ }
if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
- sqlite3DeleteTrigger(db, pParse->pNewTrigger);
- for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
- sqlite3DbFree(db, pParse->azVar);
+ sqlite3DbFree(db, pParse->pVList);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
pParse->pAinc = p->pNext;
- sqlite3DbFree(db, p);
+ sqlite3DbFreeNN(db, p);
}
while( pParse->pZombieTab ){
Table *p = pParse->pZombieTab;
pParse->pZombieTab = p->pNextZombie;
sqlite3DeleteTable(db, p);
}
+ db->pParse = pParse->pParentParse;
+ pParse->pParentParse = 0;
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
}
+
+#ifdef SQLITE_ENABLE_NORMALIZE
+/*
+** Insert a single space character into pStr if the current string
+** ends with an identifier
+*/
+static void addSpaceSeparator(sqlite3_str *pStr){
+ if( pStr->nChar && sqlite3IsIdChar(pStr->zText[pStr->nChar-1]) ){
+ sqlite3_str_append(pStr, " ", 1);
+ }
+}
+
+/*
+** Compute a normalization of the SQL given by zSql[0..nSql-1]. Return
+** the normalization in space obtained from sqlite3DbMalloc(). Or return
+** NULL if anything goes wrong or if zSql is NULL.
+*/
+SQLITE_PRIVATE char *sqlite3Normalize(
+ Vdbe *pVdbe, /* VM being reprepared */
+ const char *zSql /* The original SQL string */
+){
+ sqlite3 *db; /* The database connection */
+ int i; /* Next unread byte of zSql[] */
+ int n; /* length of current token */
+ int tokenType; /* type of current token */
+ int prevType = 0; /* Previous non-whitespace token */
+ int nParen; /* Number of nested levels of parentheses */
+ int iStartIN; /* Start of RHS of IN operator in z[] */
+ int nParenAtIN; /* Value of nParent at start of RHS of IN operator */
+ u32 j; /* Bytes of normalized SQL generated so far */
+ sqlite3_str *pStr; /* The normalized SQL string under construction */
+
+ db = sqlite3VdbeDb(pVdbe);
+ tokenType = -1;
+ nParen = iStartIN = nParenAtIN = 0;
+ pStr = sqlite3_str_new(db);
+ assert( pStr!=0 ); /* sqlite3_str_new() never returns NULL */
+ for(i=0; zSql[i] && pStr->accError==0; i+=n){
+ if( tokenType!=TK_SPACE ){
+ prevType = tokenType;
+ }
+ n = sqlite3GetToken((unsigned char*)zSql+i, &tokenType);
+ if( NEVER(n<=0) ) break;
+ switch( tokenType ){
+ case TK_SPACE: {
+ break;
+ }
+ case TK_NULL: {
+ if( prevType==TK_IS || prevType==TK_NOT ){
+ sqlite3_str_append(pStr, " NULL", 5);
+ break;
+ }
+ /* Fall through */
+ }
+ case TK_STRING:
+ case TK_INTEGER:
+ case TK_FLOAT:
+ case TK_VARIABLE:
+ case TK_BLOB: {
+ sqlite3_str_append(pStr, "?", 1);
+ break;
+ }
+ case TK_LP: {
+ nParen++;
+ if( prevType==TK_IN ){
+ iStartIN = pStr->nChar;
+ nParenAtIN = nParen;
+ }
+ sqlite3_str_append(pStr, "(", 1);
+ break;
+ }
+ case TK_RP: {
+ if( iStartIN>0 && nParen==nParenAtIN ){
+ assert( pStr->nChar>=(u32)iStartIN );
+ pStr->nChar = iStartIN+1;
+ sqlite3_str_append(pStr, "?,?,?", 5);
+ iStartIN = 0;
+ }
+ nParen--;
+ sqlite3_str_append(pStr, ")", 1);
+ break;
+ }
+ case TK_ID: {
+ iStartIN = 0;
+ j = pStr->nChar;
+ if( sqlite3Isquote(zSql[i]) ){
+ char *zId = sqlite3DbStrNDup(db, zSql+i, n);
+ int nId;
+ int eType = 0;
+ if( zId==0 ) break;
+ sqlite3Dequote(zId);
+ if( zSql[i]=='"' && sqlite3VdbeUsesDoubleQuotedString(pVdbe, zId) ){
+ sqlite3_str_append(pStr, "?", 1);
+ sqlite3DbFree(db, zId);
+ break;
+ }
+ nId = sqlite3Strlen30(zId);
+ if( sqlite3GetToken((u8*)zId, &eType)==nId && eType==TK_ID ){
+ addSpaceSeparator(pStr);
+ sqlite3_str_append(pStr, zId, nId);
+ }else{
+ sqlite3_str_appendf(pStr, "\"%w\"", zId);
+ }
+ sqlite3DbFree(db, zId);
+ }else{
+ addSpaceSeparator(pStr);
+ sqlite3_str_append(pStr, zSql+i, n);
+ }
+ while( j<pStr->nChar ){
+ pStr->zText[j] = sqlite3Tolower(pStr->zText[j]);
+ j++;
+ }
+ break;
+ }
+ case TK_SELECT: {
+ iStartIN = 0;
+ /* fall through */
+ }
+ default: {
+ if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr);
+ j = pStr->nChar;
+ sqlite3_str_append(pStr, zSql+i, n);
+ while( j<pStr->nChar ){
+ pStr->zText[j] = sqlite3Toupper(pStr->zText[j]);
+ j++;
+ }
+ break;
+ }
+ }
+ }
+ if( tokenType!=TK_SEMI ) sqlite3_str_append(pStr, ";", 1);
+ return sqlite3_str_finish(pStr);
+}
+#endif /* SQLITE_ENABLE_NORMALIZE */
+
/************** End of tokenize.c ********************************************/
/************** Begin file complete.c ****************************************/
/*
@@ -137511,7 +160678,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
** (2) NORMAL We are in the middle of statement which ends with a single
** semicolon.
**
-** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
+** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
** a statement.
**
** (4) CREATE The keyword CREATE has been seen at the beginning of a
@@ -137807,6 +160974,10 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db);
*/
/* #include "sqlite3.h" */
+#ifdef SQLITE_OMIT_VIRTUALTABLE
+# undef SQLITE_ENABLE_RTREE
+#endif
+
#if 0
extern "C" {
#endif /* __cplusplus */
@@ -137820,7 +160991,7 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db);
/************** End of rtree.h ***********************************************/
/************** Continuing where we left off in main.c ***********************/
#endif
-#ifdef SQLITE_ENABLE_ICU
+#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
/************** Include sqliteicu.h in the middle of main.c ******************/
/************** Begin file sqliteicu.h ***************************************/
/*
@@ -137850,34 +161021,101 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
} /* extern "C" */
#endif /* __cplusplus */
-
/************** End of sqliteicu.h *******************************************/
/************** Continuing where we left off in main.c ***********************/
#endif
+
+/*
+** This is an extension initializer that is a no-op and always
+** succeeds, except that it fails if the fault-simulation is set
+** to 500.
+*/
+static int sqlite3TestExtInit(sqlite3 *db){
+ (void)db;
+ return sqlite3FaultSim(500);
+}
+
+
+/*
+** Forward declarations of external module initializer functions
+** for modules that need them.
+*/
+#ifdef SQLITE_ENABLE_FTS1
+SQLITE_PRIVATE int sqlite3Fts1Init(sqlite3*);
+#endif
+#ifdef SQLITE_ENABLE_FTS2
+SQLITE_PRIVATE int sqlite3Fts2Init(sqlite3*);
+#endif
+#ifdef SQLITE_ENABLE_FTS5
+SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
+#endif
#ifdef SQLITE_ENABLE_JSON1
SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*);
#endif
+#ifdef SQLITE_ENABLE_STMTVTAB
+SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*);
+#endif
+
+/*
+** An array of pointers to extension initializer functions for
+** built-in extensions.
+*/
+static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
+#ifdef SQLITE_ENABLE_FTS1
+ sqlite3Fts1Init,
+#endif
+#ifdef SQLITE_ENABLE_FTS2
+ sqlite3Fts2Init,
+#endif
+#ifdef SQLITE_ENABLE_FTS3
+ sqlite3Fts3Init,
+#endif
#ifdef SQLITE_ENABLE_FTS5
-SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
+ sqlite3Fts5Init,
+#endif
+#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
+ sqlite3IcuInit,
+#endif
+#ifdef SQLITE_ENABLE_RTREE
+ sqlite3RtreeInit,
+#endif
+#ifdef SQLITE_ENABLE_DBPAGE_VTAB
+ sqlite3DbpageRegister,
#endif
+#ifdef SQLITE_ENABLE_DBSTAT_VTAB
+ sqlite3DbstatRegister,
+#endif
+ sqlite3TestExtInit,
+#ifdef SQLITE_ENABLE_JSON1
+ sqlite3Json1Init,
+#endif
+#ifdef SQLITE_ENABLE_STMTVTAB
+ sqlite3StmtVtabInit,
+#endif
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
+ sqlite3VdbeBytecodeVtabInit,
+#endif
+};
#ifndef SQLITE_AMALGAMATION
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
-** contains the text of SQLITE_VERSION macro.
+** contains the text of SQLITE_VERSION macro.
*/
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
#endif
/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
-** a pointer to the to the sqlite3_version[] string constant.
+** a pointer to the to the sqlite3_version[] string constant.
*/
SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
-/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
+/* IMPLEMENTATION-OF: R-25063-23286 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
-** SQLITE_SOURCE_ID C preprocessor macro.
+** SQLITE_SOURCE_ID C preprocessor macro. Except if SQLite is built using
+** an edited copy of the amalgamation, then the last four characters of
+** the hash might be different from SQLITE_SOURCE_ID.
*/
-SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+/* SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } */
/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
** returns an integer equal to SQLITE_VERSION_NUMBER.
@@ -137931,13 +161169,13 @@ SQLITE_API char *sqlite3_temp_directory = 0;
SQLITE_API char *sqlite3_data_directory = 0;
/*
-** Initialize SQLite.
+** Initialize SQLite.
**
** This routine must be called to initialize the memory allocation,
** VFS, and mutex subsystems prior to doing any serious work with
** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT
** this routine will be called automatically by key routines such as
-** sqlite3_open().
+** sqlite3_open().
**
** This routine is a no-op except on its very first call for the process,
** or for the first call after a call to sqlite3_shutdown.
@@ -137962,7 +161200,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
** without blocking.
*/
SQLITE_API int sqlite3_initialize(void){
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
int bRunExtraInit = 0; /* Extra initialization needed */
@@ -137985,9 +161223,12 @@ SQLITE_API int sqlite3_initialize(void){
** must be complete. So isInit must not be set until the very end
** of this routine.
*/
- if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;
+ if( sqlite3GlobalConfig.isInit ){
+ sqlite3MemoryBarrier();
+ return SQLITE_OK;
+ }
- /* Make sure the mutex subsystem is initialized. If unable to
+ /* Make sure the mutex subsystem is initialized. If unable to
** initialize the mutex subsystem, return early with the error.
** If the system is so sick that we are unable to allocate a mutex,
** there is not much SQLite is going to be able to do.
@@ -137999,13 +161240,13 @@ SQLITE_API int sqlite3_initialize(void){
if( rc ) return rc;
/* Initialize the malloc() system and the recursive pInitMutex mutex.
- ** This operation is protected by the STATIC_MASTER mutex. Note that
+ ** This operation is protected by the STATIC_MAIN mutex. Note that
** MutexAlloc() is called for a static mutex prior to initializing the
** malloc subsystem - this implies that the allocation of a static
** mutex must not require support from the malloc subsystem.
*/
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
- sqlite3_mutex_enter(pMaster);
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
+ sqlite3_mutex_enter(pMainMtx);
sqlite3GlobalConfig.isMutexInit = 1;
if( !sqlite3GlobalConfig.isMallocInit ){
rc = sqlite3MallocInit();
@@ -138023,7 +161264,7 @@ SQLITE_API int sqlite3_initialize(void){
if( rc==SQLITE_OK ){
sqlite3GlobalConfig.nRefInitMutex++;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
/* If rc is not SQLITE_OK at this point, then either the malloc
** subsystem could not be initialized or the system failed to allocate
@@ -138063,9 +161304,15 @@ SQLITE_API int sqlite3_initialize(void){
sqlite3GlobalConfig.isPCacheInit = 1;
rc = sqlite3OsInit();
}
+#ifdef SQLITE_ENABLE_DESERIALIZE
if( rc==SQLITE_OK ){
- sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
+ rc = sqlite3MemdbInit();
+ }
+#endif
+ if( rc==SQLITE_OK ){
+ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
+ sqlite3MemoryBarrier();
sqlite3GlobalConfig.isInit = 1;
#ifdef SQLITE_EXTRA_INIT
bRunExtraInit = 1;
@@ -138078,14 +161325,14 @@ SQLITE_API int sqlite3_initialize(void){
/* Go back under the static mutex and clean up the recursive
** mutex to prevent a resource leak.
*/
- sqlite3_mutex_enter(pMaster);
+ sqlite3_mutex_enter(pMainMtx);
sqlite3GlobalConfig.nRefInitMutex--;
if( sqlite3GlobalConfig.nRefInitMutex<=0 ){
assert( sqlite3GlobalConfig.nRefInitMutex==0 );
sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex);
sqlite3GlobalConfig.pInitMutex = 0;
}
- sqlite3_mutex_leave(pMaster);
+ sqlite3_mutex_leave(pMainMtx);
/* The following is just a sanity check to make sure SQLite has
** been compiled correctly. It is important to run this code, but
@@ -138095,7 +161342,7 @@ SQLITE_API int sqlite3_initialize(void){
#ifndef NDEBUG
#ifndef SQLITE_OMIT_FLOATING_POINT
/* This section of code's only "output" is via assert() statements. */
- if ( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
u64 x = (((u64)1)<<63)-1;
double y;
assert(sizeof(x)==8);
@@ -138262,14 +161509,8 @@ SQLITE_API int sqlite3_config(int op, ...){
sqlite3GlobalConfig.bMemstat = va_arg(ap, int);
break;
}
- case SQLITE_CONFIG_SCRATCH: {
- /* EVIDENCE-OF: R-08404-60887 There are three arguments to
- ** SQLITE_CONFIG_SCRATCH: A pointer an 8-byte aligned memory buffer from
- ** which the scratch allocations will be drawn, the size of each scratch
- ** allocation (sz), and the maximum number of scratch allocations (N). */
- sqlite3GlobalConfig.pScratch = va_arg(ap, void*);
- sqlite3GlobalConfig.szScratch = va_arg(ap, int);
- sqlite3GlobalConfig.nScratch = va_arg(ap, int);
+ case SQLITE_CONFIG_SMALL_MALLOC: {
+ sqlite3GlobalConfig.bSmallMalloc = va_arg(ap, int);
break;
}
case SQLITE_CONFIG_PAGECACHE: {
@@ -138287,7 +161528,7 @@ SQLITE_API int sqlite3_config(int op, ...){
** a single parameter which is a pointer to an integer and writes into
** that integer the number of extra bytes per page required for each page
** in SQLITE_CONFIG_PAGECACHE. */
- *va_arg(ap, int*) =
+ *va_arg(ap, int*) =
sqlite3HeaderSizeBtree() +
sqlite3HeaderSizePcache() +
sqlite3HeaderSizePcache1();
@@ -138374,7 +161615,7 @@ SQLITE_API int sqlite3_config(int op, ...){
sqlite3GlobalConfig.nLookaside = va_arg(ap, int);
break;
}
-
+
/* Record a pointer to the logger function and its first argument.
** The default is NULL. Logging is disabled if the function pointer is
** NULL.
@@ -138467,6 +161708,24 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
+ case SQLITE_CONFIG_SORTERREF_SIZE: {
+ int iVal = va_arg(ap, int);
+ if( iVal<0 ){
+ iVal = SQLITE_DEFAULT_SORTERREF_SIZE;
+ }
+ sqlite3GlobalConfig.szSorterRef = (u32)iVal;
+ break;
+ }
+#endif /* SQLITE_ENABLE_SORTER_REFERENCES */
+
+#ifdef SQLITE_ENABLE_DESERIALIZE
+ case SQLITE_CONFIG_MEMDB_MAXSIZE: {
+ sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64);
+ break;
+ }
+#endif /* SQLITE_ENABLE_DESERIALIZE */
+
default: {
rc = SQLITE_ERROR;
break;
@@ -138478,7 +161737,7 @@ SQLITE_API int sqlite3_config(int op, ...){
/*
** Set up the lookaside buffers for a database connection.
-** Return SQLITE_OK on success.
+** Return SQLITE_OK on success.
** If lookaside is already active, return SQLITE_BUSY.
**
** The sz parameter is the number of bytes in each lookaside slot.
@@ -138490,11 +161749,15 @@ SQLITE_API int sqlite3_config(int op, ...){
static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
#ifndef SQLITE_OMIT_LOOKASIDE
void *pStart;
- if( db->lookaside.nOut ){
+ sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
+ int nBig; /* Number of full-size slots */
+ int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
+
+ if( sqlite3LookasideUsed(db,0)>0 ){
return SQLITE_BUSY;
}
/* Free any existing lookaside buffer for this handle before
- ** allocating a new one so we don't have to have space for
+ ** allocating a new one so we don't have to have space for
** both at the same time.
*/
if( db->lookaside.bMalloced ){
@@ -138511,34 +161774,71 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
pStart = 0;
}else if( pBuf==0 ){
sqlite3BeginBenignMalloc();
- pStart = sqlite3Malloc( sz*cnt ); /* IMP: R-61949-35727 */
+ pStart = sqlite3Malloc( szAlloc ); /* IMP: R-61949-35727 */
sqlite3EndBenignMalloc();
- if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
+ if( pStart ) szAlloc = sqlite3MallocSize(pStart);
}else{
pStart = pBuf;
}
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( sz>=LOOKASIDE_SMALL*3 ){
+ nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
+ nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+ }else if( sz>=LOOKASIDE_SMALL*2 ){
+ nBig = szAlloc/(LOOKASIDE_SMALL+sz);
+ nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
+ }else
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( sz>0 ){
+ nBig = szAlloc/sz;
+ nSm = 0;
+ }else{
+ nBig = nSm = 0;
+ }
db->lookaside.pStart = pStart;
+ db->lookaside.pInit = 0;
db->lookaside.pFree = 0;
db->lookaside.sz = (u16)sz;
+ db->lookaside.szTrue = (u16)sz;
if( pStart ){
int i;
LookasideSlot *p;
assert( sz > (int)sizeof(LookasideSlot*) );
p = (LookasideSlot*)pStart;
- for(i=cnt-1; i>=0; i--){
- p->pNext = db->lookaside.pFree;
- db->lookaside.pFree = p;
+ for(i=0; i<nBig; i++){
+ p->pNext = db->lookaside.pInit;
+ db->lookaside.pInit = p;
p = (LookasideSlot*)&((u8*)p)[sz];
}
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ db->lookaside.pSmallInit = 0;
+ db->lookaside.pSmallFree = 0;
+ db->lookaside.pMiddle = p;
+ for(i=0; i<nSm; i++){
+ p->pNext = db->lookaside.pSmallInit;
+ db->lookaside.pSmallInit = p;
+ p = (LookasideSlot*)&((u8*)p)[LOOKASIDE_SMALL];
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ assert( ((uptr)p)<=szAlloc + (uptr)pStart );
db->lookaside.pEnd = p;
db->lookaside.bDisable = 0;
db->lookaside.bMalloced = pBuf==0 ?1:0;
+ db->lookaside.nSlot = nBig+nSm;
}else{
db->lookaside.pStart = db;
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ db->lookaside.pSmallInit = 0;
+ db->lookaside.pSmallFree = 0;
+ db->lookaside.pMiddle = db;
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
db->lookaside.pEnd = db;
db->lookaside.bDisable = 1;
+ db->lookaside.sz = 0;
db->lookaside.bMalloced = 0;
+ db->lookaside.nSlot = 0;
}
+ assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
}
@@ -138619,6 +161919,8 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
+ /* IMP: R-06824-28531 */
+ /* IMP: R-36257-52125 */
db->aDb[0].zDbSName = va_arg(ap,char*);
rc = SQLITE_OK;
break;
@@ -138637,8 +161939,21 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
} aFlagOp[] = {
{ SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
{ SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
+ { SQLITE_DBCONFIG_ENABLE_VIEW, SQLITE_EnableView },
{ SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
{ SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
+ { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
+ { SQLITE_DBCONFIG_ENABLE_QPSG, SQLITE_EnableQPSG },
+ { SQLITE_DBCONFIG_TRIGGER_EQP, SQLITE_TriggerEQP },
+ { SQLITE_DBCONFIG_RESET_DATABASE, SQLITE_ResetDatabase },
+ { SQLITE_DBCONFIG_DEFENSIVE, SQLITE_Defensive },
+ { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema|
+ SQLITE_NoSchemaError },
+ { SQLITE_DBCONFIG_LEGACY_ALTER_TABLE, SQLITE_LegacyAlter },
+ { SQLITE_DBCONFIG_DQS_DDL, SQLITE_DqsDDL },
+ { SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
+ { SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
+ { SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -138646,14 +161961,14 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
if( aFlagOp[i].op==op ){
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
- int oldFlags = db->flags;
+ u64 oldFlags = db->flags;
if( onoff>0 ){
db->flags |= aFlagOp[i].mask;
}else if( onoff==0 ){
- db->flags &= ~aFlagOp[i].mask;
+ db->flags &= ~(u64)aFlagOp[i].mask;
}
if( oldFlags!=db->flags ){
- sqlite3ExpirePreparedStatements(db);
+ sqlite3ExpirePreparedStatements(db, 0);
}
if( pRes ){
*pRes = (db->flags & aFlagOp[i].mask)!=0;
@@ -138669,52 +161984,55 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
return rc;
}
-
-/*
-** Return true if the buffer z[0..n-1] contains all spaces.
-*/
-static int allSpaces(const char *z, int n){
- while( n>0 && z[n-1]==' ' ){ n--; }
- return n==0;
-}
-
/*
** This is the default collating function named "BINARY" which is always
** available.
-**
-** If the padFlag argument is not NULL then space padding at the end
-** of strings is ignored. This implements the RTRIM collation.
*/
static int binCollFunc(
- void *padFlag,
+ void *NotUsed,
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
){
int rc, n;
+ UNUSED_PARAMETER(NotUsed);
n = nKey1<nKey2 ? nKey1 : nKey2;
/* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
** strings byte by byte using the memcmp() function from the standard C
** library. */
+ assert( pKey1 && pKey2 );
rc = memcmp(pKey1, pKey2, n);
if( rc==0 ){
- if( padFlag
- && allSpaces(((char*)pKey1)+n, nKey1-n)
- && allSpaces(((char*)pKey2)+n, nKey2-n)
- ){
- /* EVIDENCE-OF: R-31624-24737 RTRIM is like BINARY except that extra
- ** spaces at the end of either string do not change the result. In other
- ** words, strings will compare equal to one another as long as they
- ** differ only in the number of spaces at the end.
- */
- }else{
- rc = nKey1 - nKey2;
- }
+ rc = nKey1 - nKey2;
}
return rc;
}
/*
-** Another built-in collating sequence: NOCASE.
+** This is the collating function named "RTRIM" which is always
+** available. Ignore trailing spaces.
+*/
+static int rtrimCollFunc(
+ void *pUser,
+ int nKey1, const void *pKey1,
+ int nKey2, const void *pKey2
+){
+ const u8 *pK1 = (const u8*)pKey1;
+ const u8 *pK2 = (const u8*)pKey2;
+ while( nKey1 && pK1[nKey1-1]==' ' ) nKey1--;
+ while( nKey2 && pK2[nKey2-1]==' ' ) nKey2--;
+ return binCollFunc(pUser, nKey1, pKey1, nKey2, pKey2);
+}
+
+/*
+** Return true if CollSeq is the default built-in BINARY.
+*/
+SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq *p){
+ assert( p==0 || p->xCmp!=binCollFunc || strcmp(p->zName,"BINARY")==0 );
+ return p==0 || p->xCmp==binCollFunc;
+}
+
+/*
+** Another built-in collating sequence: NOCASE.
**
** This collating sequence is intended to be used for "case independent
** comparison". SQLite's knowledge of upper and lower case equivalents
@@ -138750,6 +162068,21 @@ SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
}
/*
+** Set the value returned by the sqlite3_last_insert_rowid() API function.
+*/
+SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ (void)SQLITE_MISUSE_BKPT;
+ return;
+ }
+#endif
+ sqlite3_mutex_enter(db->mutex);
+ db->lastRowid = iRowid;
+ sqlite3_mutex_leave(db->mutex);
+}
+
+/*
** Return the number of changes in the most recent call to sqlite3_exec().
*/
SQLITE_API int sqlite3_changes(sqlite3 *db){
@@ -138819,7 +162152,7 @@ static void disconnectAllVtab(sqlite3 *db){
sqlite3BtreeEnterAll(db);
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
- if( db->aDb[i].pSchema ){
+ if( pSchema ){
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
Table *pTab = (Table *)sqliteHashData(p);
if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
@@ -138841,7 +162174,7 @@ static void disconnectAllVtab(sqlite3 *db){
/*
** Return TRUE if database connection db has unfinalized prepared
-** statements or unfinished sqlite3_backup objects.
+** statements or unfinished sqlite3_backup objects.
*/
static int connectionIsBusy(sqlite3 *db){
int j;
@@ -138868,7 +162201,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
}
sqlite3_mutex_enter(db->mutex);
if( db->mTrace & SQLITE_TRACE_CLOSE ){
- db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
+ db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
}
/* Force xDisconnect calls on all virtual tables */
@@ -139008,11 +162341,8 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){
Module *pMod = (Module *)sqliteHashData(i);
- if( pMod->xDestroy ){
- pMod->xDestroy(pMod->pAux);
- }
sqlite3VtabEponymousTableClear(db, pMod);
- sqlite3DbFree(db, pMod);
+ sqlite3VtabModuleUnref(db, pMod);
}
sqlite3HashClear(&db->aModule);
#endif
@@ -139030,14 +162360,14 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
/* The temp-database schema is allocated differently from the other schema
** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
** So it needs to be freed here. Todo: Why not roll the temp schema into
- ** the same sqliteMalloc() as the one that allocates the database
+ ** the same sqliteMalloc() as the one that allocates the database
** structure?
*/
sqlite3DbFree(db, db->aDb[1].pSchema);
sqlite3_mutex_leave(db->mutex);
db->magic = SQLITE_MAGIC_CLOSED;
sqlite3_mutex_free(db->mutex);
- assert( db->lookaside.nOut==0 ); /* Fails on a lookaside memory leak */
+ assert( sqlite3LookasideUsed(db,0)==0 );
if( db->lookaside.bMalloced ){
sqlite3_free(db->lookaside.pStart);
}
@@ -139058,14 +162388,14 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
assert( sqlite3_mutex_held(db->mutex) );
sqlite3BeginBenignMalloc();
- /* Obtain all b-tree mutexes before making any calls to BtreeRollback().
+ /* Obtain all b-tree mutexes before making any calls to BtreeRollback().
** This is important in case the transaction being rolled back has
** modified the database schema. If the b-tree mutexes are not taken
** here, then another shared-cache connection might sneak in between
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
- schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
+ schemaChange = (db->mDbFlags & DBFLAG_SchemaChange)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@@ -139079,8 +162409,8 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
- if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
- sqlite3ExpirePreparedStatements(db);
+ if( schemaChange ){
+ sqlite3ExpirePreparedStatements(db, 0);
sqlite3ResetAllSchemasOfConnection(db);
}
sqlite3BtreeLeaveAll(db);
@@ -139088,7 +162418,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
/* Any deferred constraint violations have now been resolved. */
db->nDeferredCons = 0;
db->nDeferredImmCons = 0;
- db->flags &= ~SQLITE_DeferFKs;
+ db->flags &= ~(u64)SQLITE_DeferFKs;
/* If one has been configured, invoke the rollback-hook callback */
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
@@ -139108,6 +162438,7 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
switch( rc ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
+ case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break;
case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
@@ -139120,9 +162451,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break;
- case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break;
+ case SQLITE_READONLY_CANTINIT: zName = "SQLITE_READONLY_CANTINIT"; break;
case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break;
case SQLITE_READONLY_DBMOVED: zName = "SQLITE_READONLY_DBMOVED"; break;
+ case SQLITE_READONLY_DIRECTORY: zName = "SQLITE_READONLY_DIRECTORY";break;
case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break;
@@ -139160,6 +162492,7 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break;
case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break;
case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break;
+ case SQLITE_CANTOPEN_SYMLINK: zName = "SQLITE_CANTOPEN_SYMLINK"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
@@ -139212,10 +162545,10 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
static const char* const aMsg[] = {
/* SQLITE_OK */ "not an error",
- /* SQLITE_ERROR */ "SQL logic error or missing database",
+ /* SQLITE_ERROR */ "SQL logic error",
/* SQLITE_INTERNAL */ 0,
/* SQLITE_PERM */ "access permission denied",
- /* SQLITE_ABORT */ "callback requested query abort",
+ /* SQLITE_ABORT */ "query aborted",
/* SQLITE_BUSY */ "database is locked",
/* SQLITE_LOCKED */ "database table is locked",
/* SQLITE_NOMEM */ "out of memory",
@@ -139227,17 +162560,23 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
/* SQLITE_FULL */ "database or disk is full",
/* SQLITE_CANTOPEN */ "unable to open database file",
/* SQLITE_PROTOCOL */ "locking protocol",
- /* SQLITE_EMPTY */ "table contains no data",
+ /* SQLITE_EMPTY */ 0,
/* SQLITE_SCHEMA */ "database schema has changed",
/* SQLITE_TOOBIG */ "string or blob too big",
/* SQLITE_CONSTRAINT */ "constraint failed",
/* SQLITE_MISMATCH */ "datatype mismatch",
- /* SQLITE_MISUSE */ "library routine called out of sequence",
+ /* SQLITE_MISUSE */ "bad parameter or other API misuse",
+#ifdef SQLITE_DISABLE_LFS
/* SQLITE_NOLFS */ "large file support is disabled",
+#else
+ /* SQLITE_NOLFS */ 0,
+#endif
/* SQLITE_AUTH */ "authorization denied",
- /* SQLITE_FORMAT */ "auxiliary database format error",
- /* SQLITE_RANGE */ "bind or column index out of range",
- /* SQLITE_NOTADB */ "file is encrypted or is not a database",
+ /* SQLITE_FORMAT */ 0,
+ /* SQLITE_RANGE */ "column index out of range",
+ /* SQLITE_NOTADB */ "file is not a database",
+ /* SQLITE_NOTICE */ "notification message",
+ /* SQLITE_WARNING */ "warning message",
};
const char *zErr = "unknown error";
switch( rc ){
@@ -139245,6 +162584,14 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
zErr = "abort due to ROLLBACK";
break;
}
+ case SQLITE_ROW: {
+ zErr = "another row available";
+ break;
+ }
+ case SQLITE_DONE: {
+ zErr = "no more rows available";
+ break;
+ }
default: {
rc &= 0xff;
if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){
@@ -139261,19 +162608,24 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
** again until a timeout value is reached. The timeout value is
** an integer number of milliseconds passed in as the first
** argument.
+**
+** Return non-zero to retry the lock. Return zero to stop trying
+** and cause SQLite to return SQLITE_BUSY.
*/
static int sqliteDefaultBusyCallback(
- void *ptr, /* Database connection */
- int count /* Number of times table has been busy */
+ void *ptr, /* Database connection */
+ int count /* Number of times table has been busy */
){
#if SQLITE_OS_WIN || HAVE_USLEEP
+ /* This case is for systems that have support for sleeping for fractions of
+ ** a second. Examples: All windows systems, unix systems with usleep() */
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228 };
# define NDELAY ArraySize(delays)
sqlite3 *db = (sqlite3 *)ptr;
- int timeout = db->busyTimeout;
+ int tmout = db->busyTimeout;
int delay, prior;
assert( count>=0 );
@@ -139284,16 +162636,18 @@ static int sqliteDefaultBusyCallback(
delay = delays[NDELAY-1];
prior = totals[NDELAY-1] + delay*(count-(NDELAY-1));
}
- if( prior + delay > timeout ){
- delay = timeout - prior;
+ if( prior + delay > tmout ){
+ delay = tmout - prior;
if( delay<=0 ) return 0;
}
sqlite3OsSleep(db->pVfs, delay*1000);
return 1;
#else
+ /* This case for unix systems that lack usleep() support. Sleeping
+ ** must be done in increments of whole seconds */
sqlite3 *db = (sqlite3 *)ptr;
- int timeout = ((sqlite3 *)ptr)->busyTimeout;
- if( (count+1)*1000 > timeout ){
+ int tmout = ((sqlite3 *)ptr)->busyTimeout;
+ if( (count+1)*1000 > tmout ){
return 0;
}
sqlite3OsSleep(db->pVfs, 1000000);
@@ -139304,20 +162658,22 @@ static int sqliteDefaultBusyCallback(
/*
** Invoke the given busy handler.
**
-** This routine is called when an operation failed with a lock.
+** This routine is called when an operation failed to acquire a
+** lock on VFS file pFile.
+**
** If this routine returns non-zero, the lock is retried. If it
** returns 0, the operation aborts with an SQLITE_BUSY error.
*/
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
int rc;
- if( NEVER(p==0) || p->xFunc==0 || p->nBusy<0 ) return 0;
- rc = p->xFunc(p->pArg, p->nBusy);
+ if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
+ rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
if( rc==0 ){
p->nBusy = -1;
}else{
p->nBusy++;
}
- return rc;
+ return rc;
}
/*
@@ -139333,8 +162689,8 @@ SQLITE_API int sqlite3_busy_handler(
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
sqlite3_mutex_enter(db->mutex);
- db->busyHandler.xFunc = xBusy;
- db->busyHandler.pArg = pArg;
+ db->busyHandler.xBusyHandler = xBusy;
+ db->busyHandler.pBusyArg = pArg;
db->busyHandler.nBusy = 0;
db->busyTimeout = 0;
sqlite3_mutex_leave(db->mutex);
@@ -139348,9 +162704,9 @@ SQLITE_API int sqlite3_busy_handler(
** be invoked every nOps opcodes.
*/
SQLITE_API void sqlite3_progress_handler(
- sqlite3 *db,
+ sqlite3 *db,
int nOps,
- int (*xProgress)(void*),
+ int (*xProgress)(void*),
void *pArg
){
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -139383,7 +162739,8 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
- sqlite3_busy_handler(db, sqliteDefaultBusyCallback, (void*)db);
+ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
+ (void*)db);
db->busyTimeout = ms;
}else{
sqlite3_busy_handler(db, 0, 0);
@@ -139396,12 +162753,12 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ){
+ if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
(void)SQLITE_MISUSE_BKPT;
return;
}
#endif
- db->u1.isInterrupted = 1;
+ AtomicStore(&db->u1.isInterrupted, 1);
}
@@ -139409,7 +162766,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3 *db){
** This function is exactly the same as sqlite3_create_function(), except
** that it is designed to be called by internal code. The difference is
** that if a malloc() fails in sqlite3_create_function(), an error code
-** is returned and the mallocFailed flag cleared.
+** is returned and the mallocFailed flag cleared.
*/
SQLITE_PRIVATE int sqlite3CreateFunc(
sqlite3 *db,
@@ -139420,6 +162777,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
void (*xStep)(sqlite3_context*,int,sqlite3_value **),
void (*xFinal)(sqlite3_context*),
+ void (*xValue)(sqlite3_context*),
+ void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
FuncDestructor *pDestructor
){
FuncDef *p;
@@ -139427,19 +162786,29 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
int extraFlags;
assert( sqlite3_mutex_held(db->mutex) );
- if( zFunctionName==0 ||
- (xSFunc && (xFinal || xStep)) ||
- (!xSFunc && (xFinal && !xStep)) ||
- (!xSFunc && (!xFinal && xStep)) ||
- (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
- (255<(nName = sqlite3Strlen30( zFunctionName))) ){
+ assert( xValue==0 || xSFunc==0 );
+ if( zFunctionName==0 /* Must have a valid name */
+ || (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */
+ || ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */
+ || ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */
+ || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
+ || (255<(nName = sqlite3Strlen30( zFunctionName)))
+ ){
return SQLITE_MISUSE_BKPT;
}
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
- extraFlags = enc & SQLITE_DETERMINISTIC;
+ assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
+ extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
-
+
+ /* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
+ ** the meaning is inverted. So flip the bit. */
+ assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
+ extraFlags ^= SQLITE_FUNC_UNSAFE;
+
+
#ifndef SQLITE_OMIT_UTF16
/* If SQLITE_UTF16 is specified as the encoding type, transform this
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
@@ -139452,11 +162821,13 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
enc = SQLITE_UTF16NATIVE;
}else if( enc==SQLITE_ANY ){
int rc;
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
- pUserData, xSFunc, xStep, xFinal, pDestructor);
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg,
+ (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
+ pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
- rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
- pUserData, xSFunc, xStep, xFinal, pDestructor);
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg,
+ (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
+ pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
}
if( rc!=SQLITE_OK ){
return rc;
@@ -139466,21 +162837,21 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
#else
enc = SQLITE_UTF8;
#endif
-
+
/* Check if an existing function is being overridden or deleted. If so,
** and there are active VMs, then return SQLITE_BUSY. If a function
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
- if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
+ if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){
if( db->nVdbeActive ){
- sqlite3ErrorWithMsg(db, SQLITE_BUSY,
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify user-function due to active statements");
assert( !db->mallocFailed );
return SQLITE_BUSY;
}else{
- sqlite3ExpirePreparedStatements(db);
+ sqlite3ExpirePreparedStatements(db, 0);
}
}
@@ -139500,40 +162871,35 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
p->u.pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
+ testcase( p->funcFlags & SQLITE_DIRECTONLY );
p->xSFunc = xSFunc ? xSFunc : xStep;
p->xFinalize = xFinal;
+ p->xValue = xValue;
+ p->xInverse = xInverse;
p->pUserData = pUserData;
p->nArg = (u16)nArg;
return SQLITE_OK;
}
/*
-** Create new user functions.
+** Worker function used by utf-8 APIs that create new functions:
+**
+** sqlite3_create_function()
+** sqlite3_create_function_v2()
+** sqlite3_create_window_function()
*/
-SQLITE_API int sqlite3_create_function(
- sqlite3 *db,
- const char *zFunc,
- int nArg,
- int enc,
- void *p,
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
- void (*xStep)(sqlite3_context*,int,sqlite3_value **),
- void (*xFinal)(sqlite3_context*)
-){
- return sqlite3_create_function_v2(db, zFunc, nArg, enc, p, xSFunc, xStep,
- xFinal, 0);
-}
-
-SQLITE_API int sqlite3_create_function_v2(
+static int createFunctionApi(
sqlite3 *db,
const char *zFunc,
int nArg,
int enc,
void *p,
- void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
- void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
- void (*xDestroy)(void *)
+ void (*xValue)(sqlite3_context*),
+ void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
+ void(*xDestroy)(void*)
){
int rc = SQLITE_ERROR;
FuncDestructor *pArg = 0;
@@ -139545,19 +162911,23 @@ SQLITE_API int sqlite3_create_function_v2(
#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
- pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
+ pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor));
if( !pArg ){
+ sqlite3OomFault(db);
xDestroy(p);
goto out;
}
+ pArg->nRef = 0;
pArg->xDestroy = xDestroy;
pArg->pUserData = p;
}
- rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
+ rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p,
+ xSFunc, xStep, xFinal, xValue, xInverse, pArg
+ );
if( pArg && pArg->nRef==0 ){
assert( rc!=SQLITE_OK );
xDestroy(p);
- sqlite3DbFree(db, pArg);
+ sqlite3_free(pArg);
}
out:
@@ -139566,6 +162936,52 @@ SQLITE_API int sqlite3_create_function_v2(
return rc;
}
+/*
+** Create new user functions.
+*/
+SQLITE_API int sqlite3_create_function(
+ sqlite3 *db,
+ const char *zFunc,
+ int nArg,
+ int enc,
+ void *p,
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFinal)(sqlite3_context*)
+){
+ return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
+ xFinal, 0, 0, 0);
+}
+SQLITE_API int sqlite3_create_function_v2(
+ sqlite3 *db,
+ const char *zFunc,
+ int nArg,
+ int enc,
+ void *p,
+ void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
+ void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFinal)(sqlite3_context*),
+ void (*xDestroy)(void *)
+){
+ return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
+ xFinal, 0, 0, xDestroy);
+}
+SQLITE_API int sqlite3_create_window_function(
+ sqlite3 *db,
+ const char *zFunc,
+ int nArg,
+ int enc,
+ void *p,
+ void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+ void (*xFinal)(sqlite3_context*),
+ void (*xValue)(sqlite3_context*),
+ void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
+ void (*xDestroy)(void *)
+){
+ return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep,
+ xFinal, xValue, xInverse, xDestroy);
+}
+
#ifndef SQLITE_OMIT_UTF16
SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
@@ -139586,7 +163002,7 @@ SQLITE_API int sqlite3_create_function16(
sqlite3_mutex_enter(db->mutex);
assert( !db->mallocFailed );
zFunc8 = sqlite3Utf16to8(db, zFunctionName, -1, SQLITE_UTF16NATIVE);
- rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0);
+ rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0);
sqlite3DbFree(db, zFunc8);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
@@ -139596,11 +163012,33 @@ SQLITE_API int sqlite3_create_function16(
/*
+** The following is the implementation of an SQL function that always
+** fails with an error message stating that the function is used in the
+** wrong context. The sqlite3_overload_function() API might construct
+** SQL function that use this routine so that the functions will exist
+** for name resolution but are actually overloaded by the xFindFunction
+** method of virtual tables.
+*/
+static void sqlite3InvalidFunction(
+ sqlite3_context *context, /* The function calling context */
+ int NotUsed, /* Number of arguments to the function */
+ sqlite3_value **NotUsed2 /* Value of each argument */
+){
+ const char *zName = (const char*)sqlite3_user_data(context);
+ char *zErr;
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
+ zErr = sqlite3_mprintf(
+ "unable to use function %s in the requested context", zName);
+ sqlite3_result_error(context, zErr, -1);
+ sqlite3_free(zErr);
+}
+
+/*
** Declare that a function has been overloaded by a virtual table.
**
** If the function already exists as a regular global function, then
** this routine is a no-op. If the function does not exist, then create
-** a new one that always throws a run-time error.
+** a new one that always throws a run-time error.
**
** When virtual tables intend to provide an overloaded function, they
** should call this routine to make sure the global function exists.
@@ -139612,7 +163050,8 @@ SQLITE_API int sqlite3_overload_function(
const char *zName,
int nArg
){
- int rc = SQLITE_OK;
+ int rc;
+ char *zCopy;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
@@ -139620,19 +163059,19 @@ SQLITE_API int sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
- if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
- rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
- 0, sqlite3InvalidFunction, 0, 0, 0);
- }
- rc = sqlite3ApiExit(db, rc);
+ rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
sqlite3_mutex_leave(db->mutex);
- return rc;
+ if( rc ) return SQLITE_OK;
+ zCopy = sqlite3_mprintf(zName);
+ if( zCopy==0 ) return SQLITE_NOMEM;
+ return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
+ zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
}
#ifndef SQLITE_OMIT_TRACE
/*
** Register a trace function. The pArg from the previously registered trace
-** is returned.
+** is returned.
**
** A NULL trace function means that no tracing is executes. A non-NULL
** trace is a pointer to a function that is invoked at the start of each
@@ -139651,7 +163090,7 @@ SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), vo
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
- db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
+ db->trace.xLegacy = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pOld;
@@ -139675,7 +163114,7 @@ SQLITE_API int sqlite3_trace_v2(
if( mTrace==0 ) xTrace = 0;
if( xTrace==0 ) mTrace = 0;
db->mTrace = mTrace;
- db->xTrace = xTrace;
+ db->trace.xV2 = xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
@@ -139683,8 +163122,8 @@ SQLITE_API int sqlite3_trace_v2(
#ifndef SQLITE_OMIT_DEPRECATED
/*
-** Register a profile function. The pArg from the previously registered
-** profile function is returned.
+** Register a profile function. The pArg from the previously registered
+** profile function is returned.
**
** A NULL profile function means that no profiling is executes. A non-NULL
** profile is a pointer to a function that is invoked at the conclusion of
@@ -139707,6 +163146,8 @@ SQLITE_API void *sqlite3_profile(
pOld = db->pProfileArg;
db->xProfile = xProfile;
db->pProfileArg = pArg;
+ db->mTrace &= SQLITE_TRACE_NONLEGACY_MASK;
+ if( db->xProfile ) db->mTrace |= SQLITE_TRACE_XPROFILE;
sqlite3_mutex_leave(db->mutex);
return pOld;
}
@@ -139816,7 +163257,7 @@ SQLITE_API void *sqlite3_preupdate_hook(
** Invoke sqlite3_wal_checkpoint if the number of frames in the log file
** is greater than sqlite3.pWalArg cast to an integer (the value configured by
** wal_autocheckpoint()).
-*/
+*/
SQLITE_PRIVATE int sqlite3WalDefaultHook(
void *pClientData, /* Argument */
sqlite3 *db, /* Connection */
@@ -139935,6 +163376,13 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
sqlite3Error(db, rc);
}
rc = sqlite3ApiExit(db, rc);
+
+ /* If there are no active statements, clear the interrupt flag at this
+ ** point. */
+ if( db->nVdbeActive==0 ){
+ AtomicStore(&db->u1.isInterrupted, 0);
+ }
+
sqlite3_mutex_leave(db->mutex);
return rc;
#endif
@@ -139943,7 +163391,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
/*
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
-** to contains a zero-length string, all attached databases are
+** to contains a zero-length string, all attached databases are
** checkpointed.
*/
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
@@ -139957,9 +163405,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
** Run a checkpoint on database iDb. This is a no-op if database iDb is
** not currently open in WAL mode.
**
-** If a transaction is open on the database being checkpointed, this
-** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
-** an error occurs while running the checkpoint, an SQLite error code is
+** If a transaction is open on the database being checkpointed, this
+** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
+** an error occurs while running the checkpoint, an SQLite error code is
** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
**
** The mutex on database handle db should be held by the caller. The mutex
@@ -139970,7 +163418,8 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
** checkpointed. If an error is encountered it is returned immediately -
** no attempt is made to checkpoint any remaining databases.
**
-** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
+** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL, RESTART
+** or TRUNCATE.
*/
SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK; /* Return code */
@@ -140050,7 +163499,7 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
}else{
testcase( db->pErr==0 );
- z = (char*)sqlite3_value_text(db->pErr);
+ z = db->errCode ? (char*)sqlite3_value_text(db->pErr) : 0;
assert( !db->mallocFailed );
if( z==0 ){
z = sqlite3ErrStr(db->errCode);
@@ -140070,12 +163519,9 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
};
static const u16 misuse[] = {
- 'l', 'i', 'b', 'r', 'a', 'r', 'y', ' ',
- 'r', 'o', 'u', 't', 'i', 'n', 'e', ' ',
- 'c', 'a', 'l', 'l', 'e', 'd', ' ',
- 'o', 'u', 't', ' ',
- 'o', 'f', ' ',
- 's', 'e', 'q', 'u', 'e', 'n', 'c', 'e', 0
+ 'b', 'a', 'd', ' ', 'p', 'a', 'r', 'a', 'm', 'e', 't', 'e', 'r', ' ',
+ 'o', 'r', ' ', 'o', 't', 'h', 'e', 'r', ' ', 'A', 'P', 'I', ' ',
+ 'm', 'i', 's', 'u', 's', 'e', 0
};
const void *z;
@@ -140130,7 +163576,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
}
SQLITE_API int sqlite3_system_errno(sqlite3 *db){
return db ? db->iSysErrno : 0;
-}
+}
/*
** Return a string that describes the kind of error specified in the
@@ -140147,7 +163593,7 @@ SQLITE_API const char *sqlite3_errstr(int rc){
*/
static int createCollation(
sqlite3* db,
- const char *zName,
+ const char *zName,
u8 enc,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*),
@@ -140155,7 +163601,7 @@ static int createCollation(
){
CollSeq *pColl;
int enc2;
-
+
assert( sqlite3_mutex_held(db->mutex) );
/* If SQLITE_UTF16 is specified as the encoding type, transform this
@@ -140172,25 +163618,25 @@ static int createCollation(
return SQLITE_MISUSE_BKPT;
}
- /* Check if this call is removing or replacing an existing collation
+ /* Check if this call is removing or replacing an existing collation
** sequence. If so, and there are active VMs, return busy. If there
** are no active VMs, invalidate any pre-compiled statements.
*/
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0);
if( pColl && pColl->xCmp ){
if( db->nVdbeActive ){
- sqlite3ErrorWithMsg(db, SQLITE_BUSY,
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify collation sequence due to active statements");
return SQLITE_BUSY;
}
- sqlite3ExpirePreparedStatements(db);
+ sqlite3ExpirePreparedStatements(db, 0);
/* If collation sequence pColl was created directly by a call to
** sqlite3_create_collation, and not generated by synthCollSeq(),
** then any copies made by synthCollSeq() need to be invalidated.
** Also, collation destructor - CollSeq.xDel() - function may need
** to be called.
- */
+ */
if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName);
int j;
@@ -140339,17 +163785,19 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
** 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
+** *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.
+** point to a buffer containing the name of the file to open. The value
+** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter()
+** and is in the same format as names created using sqlite3_create_filename().
+** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on
+** the value returned in *pzFile to avoid a memory leak.
**
** 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
+** 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().
*/
@@ -140357,7 +163805,7 @@ 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 */
+ sqlite3_vfs **ppVfs, /* OUT: VFS to use */
char **pzFile, /* OUT: Filename component of URI */
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
){
@@ -140378,9 +163826,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
int eState; /* Parser state when parsing URI */
int iIn; /* Input character index */
int iOut = 0; /* Output character index */
- u64 nByte = nUri+2; /* Bytes of space to allocate */
+ u64 nByte = nUri+8; /* Bytes of space to allocate */
- /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
+ /* 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;
@@ -140388,6 +163836,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
zFile = sqlite3_malloc64(nByte);
if( !zFile ) return SQLITE_NOMEM_BKPT;
+ memset(zFile, 0, 4); /* 4-byte of 0x00 is the start of DB name marker */
+ zFile += 4;
+
iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
if( strncmp(zUri+5, "///", 3)==0 ){
@@ -140395,7 +163846,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
/* The following condition causes URIs with five leading / characters
** like file://///host/path to be converted into UNCs like //host/path.
** The correct URI for that UNC has only two or four leading / characters
- ** file://host/path or file:////host/path. But 5 leading slashes is a
+ ** file://host/path or file:////host/path. But 5 leading slashes is a
** common error, we are told, so we handle it as a special case. */
if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; }
}else if( strncmp(zUri+5, "//localhost/", 12)==0 ){
@@ -140407,7 +163858,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
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",
+ *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
iIn-7, &zUri[7]);
rc = SQLITE_ERROR;
goto parse_uri_out;
@@ -140415,8 +163866,8 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}
#endif
- /* Copy the filename and any query parameters into the zFile buffer.
- ** Decode %HH escape codes along the way.
+ /* 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:
@@ -140428,20 +163879,21 @@ SQLITE_PRIVATE int sqlite3ParseUri(
eState = 0;
while( (c = zUri[iIn])!=0 && c!='#' ){
iIn++;
- if( c=='%'
- && sqlite3Isxdigit(zUri[iIn])
- && sqlite3Isxdigit(zUri[iIn+1])
+ 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 ){
+#ifndef SQLITE_ENABLE_URI_00_ERROR
/* 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!='#'
+ while( (c = zUri[iIn])!=0 && c!='#'
&& (eState!=0 || c!='?')
&& (eState!=1 || (c!='=' && c!='&'))
&& (eState!=2 || c!='&')
@@ -140449,6 +163901,12 @@ SQLITE_PRIVATE int sqlite3ParseUri(
iIn++;
}
continue;
+#else
+ /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */
+ *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri");
+ rc = SQLITE_ERROR;
+ goto parse_uri_out;
+#endif
}
c = octet;
}else if( eState==1 && (c=='&' || c=='=') ){
@@ -140470,10 +163928,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
zFile[iOut++] = c;
}
if( eState==1 ) zFile[iOut++] = '\0';
- zFile[iOut++] = '\0';
- zFile[iOut++] = '\0';
+ memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */
- /* Check if there were any options specified that should be interpreted
+ /* 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. */
@@ -140509,7 +163966,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){
static struct OpenMode aOpenMode[] = {
{ "ro", SQLITE_OPEN_READONLY },
- { "rw", SQLITE_OPEN_READWRITE },
+ { "rw", SQLITE_OPEN_READWRITE },
{ "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE },
{ "memory", SQLITE_OPEN_MEMORY },
{ 0, 0 }
@@ -140551,11 +164008,14 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}
}else{
- zFile = sqlite3_malloc64(nUri+2);
+ zFile = sqlite3_malloc64(nUri+8);
if( !zFile ) return SQLITE_NOMEM_BKPT;
- memcpy(zFile, zUri, nUri);
- zFile[nUri] = '\0';
- zFile[nUri+1] = '\0';
+ memset(zFile, 0, 4);
+ zFile += 4;
+ if( nUri ){
+ memcpy(zFile, zUri, nUri);
+ }
+ memset(zFile+nUri, 0, 4);
flags &= ~SQLITE_OPEN_URI;
}
@@ -140566,7 +164026,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}
parse_uri_out:
if( rc!=SQLITE_OK ){
- sqlite3_free(zFile);
+ sqlite3_free_filename(zFile);
zFile = 0;
}
*pFlags = flags;
@@ -140574,10 +164034,26 @@ SQLITE_PRIVATE int sqlite3ParseUri(
return rc;
}
+/*
+** This routine does the core work of extracting URI parameters from a
+** database filename for the sqlite3_uri_parameter() interface.
+*/
+static const char *uriParameter(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;
+}
+
+
/*
** This routine does the work of opening a database on behalf of
-** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
+** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
** is UTF-8 encoded.
*/
static int openDatabase(
@@ -140591,6 +164067,7 @@ static int openDatabase(
int isThreadsafe; /* True for threadsafe connections */
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
+ int i; /* Loop counter */
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
@@ -140601,26 +164078,6 @@ static int openDatabase(
if( rc ) return rc;
#endif
- /* Only allow sensible combinations of bits in the flags argument.
- ** Throw an error if any non-sense combination is used. If we
- ** do not block illegal combinations here, it could trigger
- ** assert() statements in deeper layers. Sensible combinations
- ** are:
- **
- ** 1: SQLITE_OPEN_READONLY
- ** 2: SQLITE_OPEN_READWRITE
- ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
- */
- assert( SQLITE_OPEN_READONLY == 0x01 );
- assert( SQLITE_OPEN_READWRITE == 0x02 );
- assert( SQLITE_OPEN_CREATE == 0x04 );
- 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_BKPT; /* IMP: R-65497-44594 */
- }
-
if( sqlite3GlobalConfig.bCoreMutex==0 ){
isThreadsafe = 0;
}else if( flags & SQLITE_OPEN_NOMUTEX ){
@@ -140630,6 +164087,7 @@ static int openDatabase(
}else{
isThreadsafe = sqlite3GlobalConfig.bFullMutex;
}
+
if( flags & SQLITE_OPEN_PRIVATECACHE ){
flags &= ~SQLITE_OPEN_SHAREDCACHE;
}else if( sqlite3GlobalConfig.sharedCacheEnabled ){
@@ -140648,12 +164106,12 @@ static int openDatabase(
flags &= ~( SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_EXCLUSIVE |
SQLITE_OPEN_MAIN_DB |
- SQLITE_OPEN_TEMP_DB |
- SQLITE_OPEN_TRANSIENT_DB |
- SQLITE_OPEN_MAIN_JOURNAL |
- SQLITE_OPEN_TEMP_JOURNAL |
- SQLITE_OPEN_SUBJOURNAL |
- SQLITE_OPEN_MASTER_JOURNAL |
+ SQLITE_OPEN_TEMP_DB |
+ SQLITE_OPEN_TRANSIENT_DB |
+ SQLITE_OPEN_MAIN_JOURNAL |
+ SQLITE_OPEN_TEMP_JOURNAL |
+ SQLITE_OPEN_SUBJOURNAL |
+ SQLITE_OPEN_SUPER_JOURNAL |
SQLITE_OPEN_NOMUTEX |
SQLITE_OPEN_FULLMUTEX |
SQLITE_OPEN_WAL
@@ -140662,19 +164120,28 @@ static int openDatabase(
/* Allocate the sqlite data structure */
db = sqlite3MallocZero( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
- if( isThreadsafe ){
+ if( isThreadsafe
+#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
+ || sqlite3GlobalConfig.bCoreMutex
+#endif
+ ){
db->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( db->mutex==0 ){
sqlite3_free(db);
db = 0;
goto opendb_out;
}
+ if( isThreadsafe==0 ){
+ sqlite3MutexWarnOnContention(db->mutex);
+ }
}
sqlite3_mutex_enter(db->mutex);
db->errMask = 0xff;
db->nDb = 2;
db->magic = SQLITE_MAGIC_BUSY;
db->aDb = db->aDbStatic;
+ db->lookaside.bDisable = 1;
+ db->lookaside.sz = 0;
assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
@@ -140684,7 +164151,38 @@ static int openDatabase(
db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0;
db->nMaxSorterMmap = 0x7FFFFFFF;
- db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
+ db->flags |= SQLITE_ShortColNames
+ | SQLITE_EnableTrigger
+ | SQLITE_EnableView
+ | SQLITE_CacheSpill
+#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
+ | SQLITE_TrustedSchema
+#endif
+/* The SQLITE_DQS compile-time option determines the default settings
+** for SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML.
+**
+** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML
+** ---------- ----------------------- -----------------------
+** undefined on on
+** 3 on on
+** 2 on off
+** 1 off on
+** 0 off off
+**
+** Legacy behavior is 3 (double-quoted string literals are allowed anywhere)
+** and so that is the default. But developers are encouranged to use
+** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible.
+*/
+#if !defined(SQLITE_DQS)
+# define SQLITE_DQS 3
+#endif
+#if (SQLITE_DQS&1)==1
+ | SQLITE_DqsDML
+#endif
+#if (SQLITE_DQS&2)==2
+ | SQLITE_DqsDDL
+#endif
+
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
#endif
@@ -140712,6 +164210,15 @@ static int openDatabase(
#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
| SQLITE_Fts3Tokenizer
#endif
+#if defined(SQLITE_ENABLE_QPSG)
+ | SQLITE_EnableQPSG
+#endif
+#if defined(SQLITE_DEFAULT_DEFENSIVE)
+ | SQLITE_Defensive
+#endif
+#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
+ | SQLITE_LegacyAlter
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -140729,19 +164236,35 @@ static int openDatabase(
createCollation(db, sqlite3StrBINARY, SQLITE_UTF16BE, 0, binCollFunc, 0);
createCollation(db, sqlite3StrBINARY, SQLITE_UTF16LE, 0, binCollFunc, 0);
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
- createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
+ createCollation(db, "RTRIM", SQLITE_UTF8, 0, rtrimCollFunc, 0);
if( db->mallocFailed ){
goto opendb_out;
}
- /* EVIDENCE-OF: R-08308-17224 The default collating function for all
- ** strings is BINARY.
- */
- db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
- assert( db->pDfltColl!=0 );
- /* Parse the filename/URI argument. */
+ /* Parse the filename/URI argument
+ **
+ ** Only allow sensible combinations of bits in the flags argument.
+ ** Throw an error if any non-sense combination is used. If we
+ ** do not block illegal combinations here, it could trigger
+ ** assert() statements in deeper layers. Sensible combinations
+ ** are:
+ **
+ ** 1: SQLITE_OPEN_READONLY
+ ** 2: SQLITE_OPEN_READWRITE
+ ** 6: SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
+ */
db->openFlags = flags;
- rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
+ assert( SQLITE_OPEN_READONLY == 0x01 );
+ assert( SQLITE_OPEN_READWRITE == 0x02 );
+ assert( SQLITE_OPEN_CREATE == 0x04 );
+ 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 ){
+ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
+ }else{
+ rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
+ }
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
sqlite3ErrorWithMsg(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
@@ -140761,12 +164284,14 @@ static int openDatabase(
}
sqlite3BtreeEnter(db->aDb[0].pBt);
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
- if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
+ if( !db->mallocFailed ){
+ sqlite3SetTextEncoding(db, SCHEMA_ENC(db));
+ }
sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
/* The default safety_level for the main database is FULL; for the temp
- ** database it is OFF. This matches the pager layer defaults.
+ ** database it is OFF. This matches the pager layer defaults.
*/
db->aDb[0].zDbSName = "main";
db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
@@ -140786,14 +164311,11 @@ static int openDatabase(
sqlite3RegisterPerConnectionBuiltinFunctions(db);
rc = sqlite3_errcode(db);
-#ifdef SQLITE_ENABLE_FTS5
- /* Register any built-in FTS5 module before loading the automatic
- ** extensions. This allows automatic extensions to register FTS5
- ** tokenizers and auxiliary functions. */
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3Fts5Init(db);
+
+ /* Load compiled-in extensions */
+ for(i=0; rc==SQLITE_OK && i<ArraySize(sqlite3BuiltinExtensions); i++){
+ rc = sqlite3BuiltinExtensions[i](db);
}
-#endif
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
@@ -140806,48 +164328,11 @@ static int openDatabase(
}
}
-#ifdef SQLITE_ENABLE_FTS1
- if( !db->mallocFailed ){
- extern int sqlite3Fts1Init(sqlite3*);
- rc = sqlite3Fts1Init(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_FTS2
- if( !db->mallocFailed && rc==SQLITE_OK ){
- extern int sqlite3Fts2Init(sqlite3*);
- rc = sqlite3Fts2Init(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3Fts3Init(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_ICU
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3IcuInit(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_RTREE
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3RtreeInit(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_DBSTAT_VTAB
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3DbstatRegister(db);
- }
-#endif
-
-#ifdef SQLITE_ENABLE_JSON1
- if( !db->mallocFailed && rc==SQLITE_OK){
- rc = sqlite3Json1Init(db);
- }
+#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
+ /* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
+ ** option gives access to internal functions by default.
+ ** Testing use only!!! */
+ db->mDbFlags |= DBFLAG_InternalFunc;
#endif
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
@@ -140890,31 +164375,17 @@ opendb_out:
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
}
#endif
-#if defined(SQLITE_HAS_CODEC)
- if( rc==SQLITE_OK ){
- const char *zHexKey = sqlite3_uri_parameter(zOpen, "hexkey");
- if( zHexKey && zHexKey[0] ){
- u8 iByte;
- int i;
- char zKey[40];
- for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zHexKey[i]); i++){
- iByte = (iByte<<4) + sqlite3HexToInt(zHexKey[i]);
- if( (i&1)!=0 ) zKey[i/2] = iByte;
- }
- sqlite3_key_v2(db, 0, zKey, i/2);
- }
- }
-#endif
- sqlite3_free(zOpen);
+ sqlite3_free_filename(zOpen);
return rc & 0xff;
}
+
/*
** Open a new database handle.
*/
SQLITE_API int sqlite3_open(
- const char *zFilename,
- sqlite3 **ppDb
+ const char *zFilename,
+ sqlite3 **ppDb
){
return openDatabase(zFilename, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
@@ -140933,7 +164404,7 @@ SQLITE_API int sqlite3_open_v2(
** Open a new database handle.
*/
SQLITE_API int sqlite3_open16(
- const void *zFilename,
+ const void *zFilename,
sqlite3 **ppDb
){
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
@@ -140972,9 +164443,9 @@ SQLITE_API int sqlite3_open16(
** Register a new collation sequence with the database handle db.
*/
SQLITE_API int sqlite3_create_collation(
- sqlite3* db,
- const char *zName,
- int enc,
+ sqlite3* db,
+ const char *zName,
+ int enc,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
@@ -140985,9 +164456,9 @@ SQLITE_API int sqlite3_create_collation(
** Register a new collation sequence with the database handle db.
*/
SQLITE_API int sqlite3_create_collation_v2(
- sqlite3* db,
- const char *zName,
- int enc,
+ sqlite3* db,
+ const char *zName,
+ int enc,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDel)(void*)
@@ -141010,9 +164481,9 @@ SQLITE_API int sqlite3_create_collation_v2(
** Register a new collation sequence with the database handle db.
*/
SQLITE_API int sqlite3_create_collation16(
- sqlite3* db,
+ sqlite3* db,
const void *zName,
- int enc,
+ int enc,
void* pCtx,
int(*xCompare)(void*,int,const void*,int,const void*)
){
@@ -141040,8 +164511,8 @@ SQLITE_API int sqlite3_create_collation16(
** db. Replace any previously installed collation sequence factory.
*/
SQLITE_API int sqlite3_collation_needed(
- sqlite3 *db,
- void *pCollNeededArg,
+ sqlite3 *db,
+ void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
){
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -141061,8 +164532,8 @@ SQLITE_API int sqlite3_collation_needed(
** db. Replace any previously installed collation sequence factory.
*/
SQLITE_API int sqlite3_collation_needed16(
- sqlite3 *db,
- void *pCollNeededArg,
+ sqlite3 *db,
+ void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
){
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -141114,31 +164585,39 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
** 2. Invoke sqlite3_log() to provide the source code location where
** a low-level error is first detected.
*/
-static int reportError(int iErr, int lineno, const char *zType){
+SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){
sqlite3_log(iErr, "%s at line %d of [%.10s]",
zType, lineno, 20+sqlite3_sourceid());
return iErr;
}
SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_CORRUPT, lineno, "database corruption");
+ return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption");
}
SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_MISUSE, lineno, "misuse");
+ return sqlite3ReportError(SQLITE_MISUSE, lineno, "misuse");
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
+ return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
+}
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
+SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
+ char zMsg[100];
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
}
+#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3NomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_NOMEM, lineno, "OOM");
+ return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
}
SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
+ return sqlite3ReportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
}
#endif
@@ -141226,13 +164705,13 @@ SQLITE_API int sqlite3_table_column_metadata(
/* The following block stores the meta information that will be returned
** to the caller in local variables zDataType, zCollSeq, notnull, primarykey
** and autoinc. At this point there are two possibilities:
- **
- ** 1. The specified column name was rowid", "oid" or "_rowid_"
- ** and there is no explicitly declared IPK column.
**
- ** 2. The table is not a view and the column name identified an
+ ** 1. The specified column name was rowid", "oid" or "_rowid_"
+ ** and there is no explicitly declared IPK column.
+ **
+ ** 2. The table is not a view and the column name identified an
** explicitly declared column. Copy meta information from *pCol.
- */
+ */
if( pCol ){
zDataType = sqlite3ColumnType(pCol,0);
zCollSeq = pCol->zColl;
@@ -141282,7 +164761,7 @@ SQLITE_API int sqlite3_sleep(int ms){
pVfs = sqlite3_vfs_find(0);
if( pVfs==0 ) return 0;
- /* This function works in milliseconds, but the underlying OsSleep()
+ /* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
@@ -141331,10 +164810,18 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
}else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
*(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
rc = SQLITE_OK;
- }else if( fd->pMethods ){
- rc = sqlite3OsFileControl(fd, op, pArg);
+ }else if( op==SQLITE_FCNTL_DATA_VERSION ){
+ *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
+ rc = SQLITE_OK;
+ }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
+ int iNew = *(int*)pArg;
+ *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
+ if( iNew>=0 && iNew<=255 ){
+ sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
+ }
+ rc = SQLITE_OK;
}else{
- rc = SQLITE_NOTFOUND;
+ rc = sqlite3OsFileControl(fd, op, pArg);
}
sqlite3BtreeLeave(pBtree);
}
@@ -141347,7 +164834,7 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
*/
SQLITE_API int sqlite3_test_control(int op, ...){
int rc = 0;
-#ifdef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_UNTESTABLE
UNUSED_PARAMETER(op);
#else
va_list ap;
@@ -141372,15 +164859,38 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
- /*
- ** Reset the PRNG back to its uninitialized state. The next call
- ** to sqlite3_randomness() will reseed the PRNG using a single call
- ** to the xRandomness method of the default VFS.
+ /* sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, int x, sqlite3 *db);
+ **
+ ** Control the seed for the pseudo-random number generator (PRNG) that
+ ** is built into SQLite. Cases:
+ **
+ ** x!=0 && db!=0 Seed the PRNG to the current value of the
+ ** schema cookie in the main database for db, or
+ ** x if the schema cookie is zero. This case
+ ** is convenient to use with database fuzzers
+ ** as it allows the fuzzer some control over the
+ ** the PRNG seed.
+ **
+ ** x!=0 && db==0 Seed the PRNG to the value of x.
+ **
+ ** x==0 && db==0 Revert to default behavior of using the
+ ** xRandomness method on the primary VFS.
+ **
+ ** This test-control also resets the PRNG so that the new seed will
+ ** be used for the next call to sqlite3_randomness().
*/
- case SQLITE_TESTCTRL_PRNG_RESET: {
+#ifndef SQLITE_OMIT_WSD
+ case SQLITE_TESTCTRL_PRNG_SEED: {
+ int x = va_arg(ap, int);
+ int y;
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ assert( db==0 || db->aDb[0].pSchema!=0 );
+ if( db && (y = db->aDb[0].pSchema->schema_cookie)!=0 ){ x = y; }
+ sqlite3Config.iPrngSeed = x;
sqlite3_randomness(0,0);
break;
}
+#endif
/*
** sqlite3_test_control(BITVEC_TEST, size, program)
@@ -141422,7 +164932,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
/*
** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd)
**
- ** Register hooks to call to indicate which malloc() failures
+ ** Register hooks to call to indicate which malloc() failures
** are benign.
*/
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: {
@@ -141483,7 +164993,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** This action provides a run-time test to see how the ALWAYS and
** NEVER macros were defined at compile-time.
**
- ** The return value is ALWAYS(X).
+ ** The return value is ALWAYS(X) if X is true, or 0 if X is false.
**
** The recommended test is X==2. If the return value is 2, that means
** ALWAYS() and NEVER() are both no-op pass-through macros, which is the
@@ -141506,7 +165016,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_ALWAYS: {
int x = va_arg(ap,int);
- rc = ALWAYS(x);
+ rc = x ? ALWAYS(x) : 0;
break;
}
@@ -141520,29 +165030,15 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** 10 little-endian, determined at run-time
** 432101 big-endian, determined at compile-time
** 123410 little-endian, determined at compile-time
- */
+ */
case SQLITE_TESTCTRL_BYTEORDER: {
rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
break;
}
- /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
- **
- ** Set the nReserve size to N for the main database on the database
- ** connection db.
- */
- case SQLITE_TESTCTRL_RESERVE: {
- sqlite3 *db = va_arg(ap, sqlite3*);
- int x = va_arg(ap,int);
- sqlite3_mutex_enter(db->mutex);
- sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0);
- sqlite3_mutex_leave(db->mutex);
- break;
- }
-
/* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
**
- ** Enable or disable various optimizations for testing purposes. The
+ ** Enable or disable various optimizations for testing purposes. The
** argument N is a bitmask of optimizations to be disabled. For normal
** operation N should be 0. The idea is that a test program (like the
** SQL Logic Test or SLT test module) can run the same SQL multiple times
@@ -141555,48 +165051,24 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
-#ifdef SQLITE_N_KEYWORD
- /* sqlite3_test_control(SQLITE_TESTCTRL_ISKEYWORD, const char *zWord)
- **
- ** If zWord is a keyword recognized by the parser, then return the
- ** number of keywords. Or if zWord is not a keyword, return 0.
- **
- ** This test feature is only available in the amalgamation since
- ** the SQLITE_N_KEYWORD macro is not defined in this file if SQLite
- ** is built using separate source files.
- */
- case SQLITE_TESTCTRL_ISKEYWORD: {
- const char *zWord = va_arg(ap, const char*);
- int n = sqlite3Strlen30(zWord);
- rc = (sqlite3KeywordCode((u8*)zWord, n)!=TK_ID) ? SQLITE_N_KEYWORD : 0;
- break;
- }
-#endif
-
- /* sqlite3_test_control(SQLITE_TESTCTRL_SCRATCHMALLOC, sz, &pNew, pFree);
+ /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
**
- ** Pass pFree into sqlite3ScratchFree().
- ** If sz>0 then allocate a scratch buffer into pNew.
+ ** If parameter onoff is non-zero, subsequent calls to localtime()
+ ** and its variants fail. If onoff is zero, undo this setting.
*/
- case SQLITE_TESTCTRL_SCRATCHMALLOC: {
- void *pFree, **ppNew;
- int sz;
- sz = va_arg(ap, int);
- ppNew = va_arg(ap, void**);
- pFree = va_arg(ap, void*);
- if( sz ) *ppNew = sqlite3ScratchMalloc(sz);
- sqlite3ScratchFree(pFree);
+ case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
+ sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
break;
}
- /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
+ /* sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, sqlite3*);
**
- ** 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.
+ ** Toggle the ability to use internal functions on or off for
+ ** the database connection given in the argument.
*/
- case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
- sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
+ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ db->mDbFlags ^= DBFLAG_InternalFunc;
break;
}
@@ -141613,6 +165085,23 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+ /* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
+ **
+ ** Set or clear a flag that causes SQLite to verify that type, name,
+ ** and tbl_name fields of the sqlite_schema table. This is normally
+ ** on, but it is sometimes useful to turn it off for testing.
+ **
+ ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
+ ** verification of rootpage numbers when parsing the schema. This
+ ** is useful to make it easier to reach strange internal error states
+ ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
+ ** in production.
+ */
+ case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
+ sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
+ break;
+ }
+
/* Set the threshold at which OP_Once counters reset back to zero.
** By default this is 0x7ffffffe (over 2 billion), but that value is
** too big to test in a reasonable amount of time, so this control is
@@ -141625,12 +165114,13 @@ SQLITE_API int sqlite3_test_control(int op, ...){
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
**
- ** Set the VDBE coverage callback function to xCallback with context
+ ** Set the VDBE coverage callback function to xCallback with context
** pointer ptr.
*/
case SQLITE_TESTCTRL_VDBE_COVERAGE: {
#ifdef SQLITE_VDBE_COVERAGE
- typedef void (*branch_callback)(void*,int,u8,u8);
+ typedef void (*branch_callback)(void*,unsigned int,
+ unsigned char,unsigned char);
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
#endif
@@ -141682,15 +165172,124 @@ SQLITE_API int sqlite3_test_control(int op, ...){
sqlite3_mutex_leave(db->mutex);
break;
}
+
+#if defined(YYCOVERAGE)
+ /* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out)
+ **
+ ** This test control (only available when SQLite is compiled with
+ ** -DYYCOVERAGE) writes a report onto "out" that shows all
+ ** state/lookahead combinations in the parser state machine
+ ** which are never exercised. If any state is missed, make the
+ ** return code SQLITE_ERROR.
+ */
+ case SQLITE_TESTCTRL_PARSER_COVERAGE: {
+ FILE *out = va_arg(ap, FILE*);
+ if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR;
+ break;
+ }
+#endif /* defined(YYCOVERAGE) */
+
+ /* sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, sqlite3_context*);
+ **
+ ** This test-control causes the most recent sqlite3_result_int64() value
+ ** to be interpreted as a MEM_IntReal instead of as an MEM_Int. Normally,
+ ** MEM_IntReal values only arise during an INSERT operation of integer
+ ** values into a REAL column, so they can be challenging to test. This
+ ** test-control enables us to write an intreal() SQL function that can
+ ** inject an intreal() value at arbitrary places in an SQL statement,
+ ** for testing purposes.
+ */
+ case SQLITE_TESTCTRL_RESULT_INTREAL: {
+ sqlite3_context *pCtx = va_arg(ap, sqlite3_context*);
+ sqlite3ResultIntReal(pCtx);
+ break;
+ }
}
va_end(ap);
-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+#endif /* SQLITE_UNTESTABLE */
return rc;
}
/*
+** The Pager stores the Database filename, Journal filename, and WAL filename
+** consecutively in memory, in that order. The database filename is prefixed
+** by four zero bytes. Locate the start of the database filename by searching
+** backwards for the first byte following four consecutive zero bytes.
+**
+** This only works if the filename passed in was obtained from the Pager.
+*/
+static const char *databaseName(const char *zName){
+ while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
+ zName--;
+ }
+ return zName;
+}
+
+/*
+** Append text z[] to the end of p[]. Return a pointer to the first
+** character after then zero terminator on the new text in p[].
+*/
+static char *appendText(char *p, const char *z){
+ size_t n = strlen(z);
+ memcpy(p, z, n+1);
+ return p+n+1;
+}
+
+/*
+** Allocate memory to hold names for a database, journal file, WAL file,
+** and query parameters. The pointer returned is valid for use by
+** sqlite3_filename_database() and sqlite3_uri_parameter() and related
+** functions.
+**
+** Memory layout must be compatible with that generated by the pager
+** and expected by sqlite3_uri_parameter() and databaseName().
+*/
+SQLITE_API char *sqlite3_create_filename(
+ const char *zDatabase,
+ const char *zJournal,
+ const char *zWal,
+ int nParam,
+ const char **azParam
+){
+ sqlite3_int64 nByte;
+ int i;
+ char *pResult, *p;
+ nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10;
+ for(i=0; i<nParam*2; i++){
+ nByte += strlen(azParam[i])+1;
+ }
+ pResult = p = sqlite3_malloc64( nByte );
+ if( p==0 ) return 0;
+ memset(p, 0, 4);
+ p += 4;
+ p = appendText(p, zDatabase);
+ for(i=0; i<nParam*2; i++){
+ p = appendText(p, azParam[i]);
+ }
+ *(p++) = 0;
+ p = appendText(p, zJournal);
+ p = appendText(p, zWal);
+ *(p++) = 0;
+ *(p++) = 0;
+ assert( (sqlite3_int64)(p - pResult)==nByte );
+ return pResult + 4;
+}
+
+/*
+** Free memory obtained from sqlite3_create_filename(). It is a severe
+** error to call this routine with any parameter other than a pointer
+** previously obtained from sqlite3_create_filename() or a NULL pointer.
+*/
+SQLITE_API void sqlite3_free_filename(char *p){
+ if( p==0 ) return;
+ p = (char*)databaseName(p);
+ sqlite3_free(p - 4);
+}
+
+
+/*
** 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
+** 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()
@@ -141701,14 +165300,22 @@ SQLITE_API int sqlite3_test_control(int op, ...){
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
if( zFilename==0 || zParam==0 ) return 0;
+ zFilename = databaseName(zFilename);
+ return uriParameter(zFilename, zParam);
+}
+
+/*
+** Return a pointer to the name of Nth query parameter of the filename.
+*/
+SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N){
+ if( zFilename==0 || N<0 ) return 0;
+ zFilename = databaseName(zFilename);
zFilename += sqlite3Strlen30(zFilename) + 1;
- while( zFilename[0] ){
- int x = strcmp(zFilename, zParam);
+ while( zFilename[0] && (N--)>0 ){
zFilename += sqlite3Strlen30(zFilename) + 1;
- if( x==0 ) return zFilename;
zFilename += sqlite3Strlen30(zFilename) + 1;
}
- return 0;
+ return zFilename[0] ? zFilename : 0;
}
/*
@@ -141730,25 +165337,50 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(
){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
sqlite3_int64 v;
- if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){
+ if( z && sqlite3DecOrHexToI64(z, &v)==0 ){
bDflt = v;
}
return bDflt;
}
/*
-** Return the Btree pointer identified by zDbName. Return NULL if not found.
+** Translate a filename that was handed to a VFS routine into the corresponding
+** database, journal, or WAL file.
+**
+** It is an error to pass this routine a filename string that was not
+** passed into the VFS from the SQLite core. Doing so is similar to
+** passing free() a pointer that was not obtained from malloc() - it is
+** an error that we cannot easily detect but that will likely cause memory
+** corruption.
*/
-SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
- int i;
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt
- && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zDbSName)==0)
- ){
- return db->aDb[i].pBt;
- }
+SQLITE_API const char *sqlite3_filename_database(const char *zFilename){
+ return databaseName(zFilename);
+}
+SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){
+ zFilename = databaseName(zFilename);
+ zFilename += sqlite3Strlen30(zFilename) + 1;
+ while( zFilename[0] ){
+ zFilename += sqlite3Strlen30(zFilename) + 1;
+ zFilename += sqlite3Strlen30(zFilename) + 1;
}
+ return zFilename + 1;
+}
+SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){
+#ifdef SQLITE_OMIT_WAL
return 0;
+#else
+ zFilename = sqlite3_filename_journal(zFilename);
+ zFilename += sqlite3Strlen30(zFilename) + 1;
+ return zFilename;
+#endif
+}
+
+/*
+** Return the Btree pointer identified by zDbName. Return NULL if not found.
+*/
+SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
+ int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
+ return iDb<0 ? 0 : db->aDb[iDb].pBt;
}
/*
@@ -141785,17 +165417,16 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
-** Obtain a snapshot handle for the snapshot of database zDb currently
+** Obtain a snapshot handle for the snapshot of database zDb currently
** being read by handle db.
*/
SQLITE_API int sqlite3_snapshot_get(
- sqlite3 *db,
+ sqlite3 *db,
const char *zDb,
sqlite3_snapshot **ppSnapshot
){
int rc = SQLITE_ERROR;
#ifndef SQLITE_OMIT_WAL
- int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
@@ -141804,13 +165435,15 @@ SQLITE_API int sqlite3_snapshot_get(
#endif
sqlite3_mutex_enter(db->mutex);
- iDb = sqlite3FindDbName(db, zDb);
- if( iDb==0 || iDb>1 ){
- Btree *pBt = db->aDb[iDb].pBt;
- if( 0==sqlite3BtreeIsInTrans(pBt) ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
+ if( db->autoCommit==0 ){
+ int iDb = sqlite3FindDbName(db, zDb);
+ if( iDb==0 || iDb>1 ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ if( 0==sqlite3BtreeIsInTrans(pBt) ){
+ rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
+ }
}
}
}
@@ -141824,8 +165457,8 @@ SQLITE_API int sqlite3_snapshot_get(
** Open a read-transaction on the snapshot idendified by pSnapshot.
*/
SQLITE_API int sqlite3_snapshot_open(
- sqlite3 *db,
- const char *zDb,
+ sqlite3 *db,
+ const char *zDb,
sqlite3_snapshot *pSnapshot
){
int rc = SQLITE_ERROR;
@@ -141842,11 +165475,29 @@ SQLITE_API int sqlite3_snapshot_open(
iDb = sqlite3FindDbName(db, zDb);
if( iDb==0 || iDb>1 ){
Btree *pBt = db->aDb[iDb].pBt;
- if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
- rc = sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), pSnapshot);
+ if( sqlite3BtreeIsInTrans(pBt)==0 ){
+ Pager *pPager = sqlite3BtreePager(pBt);
+ int bUnlock = 0;
+ if( sqlite3BtreeIsInReadTrans(pBt) ){
+ if( db->nVdbeActive==0 ){
+ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
+ if( rc==SQLITE_OK ){
+ bUnlock = 1;
+ rc = sqlite3BtreeCommit(pBt);
+ }
+ }
+ }else{
+ rc = SQLITE_OK;
+ }
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
- sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
+ rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
+ sqlite3PagerSnapshotOpen(pPager, 0);
+ }
+ if( bUnlock ){
+ sqlite3PagerSnapshotUnlock(pPager);
}
}
}
@@ -141858,6 +165509,38 @@ SQLITE_API int sqlite3_snapshot_open(
}
/*
+** Recover as many snapshots as possible from the wal file associated with
+** schema zDb of database db.
+*/
+SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
+ int rc = SQLITE_ERROR;
+ int iDb;
+#ifndef SQLITE_OMIT_WAL
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+
+ sqlite3_mutex_enter(db->mutex);
+ iDb = sqlite3FindDbName(db, zDb);
+ if( iDb==0 || iDb>1 ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
+ rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
+ sqlite3BtreeCommit(pBt);
+ }
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+#endif /* SQLITE_OMIT_WAL */
+ return rc;
+}
+
+/*
** Free a snapshot handle obtained from sqlite3_snapshot_get().
*/
SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
@@ -141865,6 +165548,58 @@ SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+/*
+** Given the name of a compile-time option, return true if that option
+** was used and false if not.
+**
+** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
+** is not required for a match.
+*/
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
+ int i, n;
+ int nOpt;
+ const char **azCompileOpt;
+
+#if SQLITE_ENABLE_API_ARMOR
+ if( zOptName==0 ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+
+ azCompileOpt = sqlite3CompileOptions(&nOpt);
+
+ if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
+ n = sqlite3Strlen30(zOptName);
+
+ /* Since nOpt is normally in single digits, a linear search is
+ ** adequate. No need for a binary search. */
+ for(i=0; i<nOpt; i++){
+ if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
+ && sqlite3IsIdChar((unsigned char)azCompileOpt[i][n])==0
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** Return the N-th compile-time option string. If N is out of range,
+** return a NULL pointer.
+*/
+SQLITE_API const char *sqlite3_compileoption_get(int N){
+ int nOpt;
+ const char **azCompileOpt;
+ azCompileOpt = sqlite3CompileOptions(&nOpt);
+ if( N>=0 && N<nOpt ){
+ return azCompileOpt[N];
+ }
+ return 0;
+}
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+
/************** End of main.c ************************************************/
/************** Begin file notify.c ******************************************/
/*
@@ -141898,25 +165633,25 @@ SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
*/
#define assertMutexHeld() \
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) )
/*
** Head of a linked list of all sqlite3 objects created by this process
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
-** is not NULL. This variable may only accessed while the STATIC_MASTER
+** is not NULL. This variable may only accessed while the STATIC_MAIN
** mutex is held.
*/
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
#ifndef NDEBUG
/*
-** This function is a complex assert() that verifies the following
+** This function is a complex assert() that verifies the following
** properties of the blocked connections list:
**
-** 1) Each entry in the list has a non-NULL value for either
+** 1) Each entry in the list has a non-NULL value for either
** pUnlockConnection or pBlockingConnection, or both.
**
-** 2) All entries in the list that share a common value for
+** 2) All entries in the list that share a common value for
** xUnlockNotify are grouped together.
**
** 3) If the argument db is not NULL, then none of the entries in the
@@ -141968,8 +165703,8 @@ static void addToBlockedList(sqlite3 *db){
sqlite3 **pp;
assertMutexHeld();
for(
- pp=&sqlite3BlockedList;
- *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
+ pp=&sqlite3BlockedList;
+ *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
pp=&(*pp)->pNextBlocked
);
db->pNextBlocked = *pp;
@@ -141977,20 +165712,20 @@ static void addToBlockedList(sqlite3 *db){
}
/*
-** Obtain the STATIC_MASTER mutex.
+** Obtain the STATIC_MAIN mutex.
*/
static void enterMutex(void){
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
checkListProperties(0);
}
/*
-** Release the STATIC_MASTER mutex.
+** Release the STATIC_MAIN mutex.
*/
static void leaveMutex(void){
assertMutexHeld();
checkListProperties(0);
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
}
/*
@@ -142031,9 +165766,9 @@ SQLITE_API int sqlite3_unlock_notify(
db->xUnlockNotify = 0;
db->pUnlockArg = 0;
}else if( 0==db->pBlockingConnection ){
- /* The blocking transaction has been concluded. Or there never was a
+ /* The blocking transaction has been concluded. Or there never was a
** blocking transaction. In either case, invoke the notify callback
- ** immediately.
+ ** immediately.
*/
xNotify(&pArg, 1);
}else{
@@ -142059,7 +165794,7 @@ SQLITE_API int sqlite3_unlock_notify(
}
/*
-** This function is called while stepping or preparing a statement
+** This function is called while stepping or preparing a statement
** associated with connection db. The operation will return SQLITE_LOCKED
** to the user because it requires a lock that will not be available
** until connection pBlocker concludes its current transaction.
@@ -142075,7 +165810,7 @@ SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
/*
** This function is called when
-** the transaction opened by database db has just finished. Locks held
+** the transaction opened by database db has just finished. Locks held
** by database connection db have been released.
**
** This function loops through each entry in the blocked connections
@@ -142101,7 +165836,7 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
void *aStatic[16]; /* Starter space for aArg[]. No malloc required */
aArg = aStatic;
- enterMutex(); /* Enter STATIC_MASTER mutex */
+ enterMutex(); /* Enter STATIC_MAIN mutex */
/* This loop runs once for each entry in the blocked-connections list. */
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
@@ -142135,7 +165870,7 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
}else{
/* This occurs when the array of context pointers that need to
** be passed to the unlock-notify callback is larger than the
- ** aStatic[] array allocated on the stack and the attempt to
+ ** aStatic[] array allocated on the stack and the attempt to
** allocate a larger array from the heap has failed.
**
** This is a difficult situation to handle. Returning an error
@@ -142143,17 +165878,17 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
** is returned the transaction on connection db will still be
** closed and the unlock-notify callbacks on blocked connections
** will go unissued. This might cause the application to wait
- ** indefinitely for an unlock-notify callback that will never
+ ** indefinitely for an unlock-notify callback that will never
** arrive.
**
** Instead, invoke the unlock-notify callback with the context
** array already accumulated. We can then clear the array and
- ** begin accumulating any further context pointers without
+ ** begin accumulating any further context pointers without
** requiring any dynamic allocation. This is sub-optimal because
** it means that instead of one callback with a large array of
** context pointers the application will receive two or more
** callbacks with smaller arrays of context pointers, which will
- ** reduce the applications ability to prioritize multiple
+ ** reduce the applications ability to prioritize multiple
** connections. But it is the best that can be done under the
** circumstances.
*/
@@ -142184,11 +165919,11 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
xUnlockNotify(aArg, nArg);
}
sqlite3_free(aDyn);
- leaveMutex(); /* Leave STATIC_MASTER mutex */
+ leaveMutex(); /* Leave STATIC_MAIN mutex */
}
/*
-** This is called when the database connection passed as an argument is
+** This is called when the database connection passed as an argument is
** being closed. The connection is removed from the blocked list.
*/
SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
@@ -142265,7 +166000,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
** A doclist (document list) holds a docid-sorted list of hits for a
** given term. Doclists hold docids and associated token positions.
** A docid is the unique integer identifier for a single document.
-** A position is the index of a word within the document. The first
+** A position is the index of a word within the document. The first
** word of the document has a position of 0.
**
** FTS3 used to optionally store character offsets using a compile-time
@@ -142290,7 +166025,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
**
** Here, array { X } means zero or more occurrences of X, adjacent in
** memory. A "position" is an index of a token in the token stream
-** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
+** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
** in the same logical place as the position element, and act as sentinals
** ending a position list array. POS_END is 0. POS_COLUMN is 1.
** The positions numbers are not stored literally but rather as two more
@@ -142314,7 +166049,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
** a document record consists of a docid followed by a position-list and
** a doclist consists of one or more document records.
**
-** A bare doclist omits the position information, becoming an
+** A bare doclist omits the position information, becoming an
** array of varint-encoded docids.
**
**** Segment leaf nodes ****
@@ -142510,7 +166245,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
#ifndef _FTSINT_H
#define _FTSINT_H
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
@@ -142533,7 +166268,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
/* If not building as part of the core, include sqlite3ext.h. */
#ifndef SQLITE_CORE
-/* # include "sqlite3ext.h" */
+/* # include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT3
#endif
@@ -142577,7 +166312,7 @@ SQLITE_EXTENSION_INIT3
** When an fts3 table is created, it passes any arguments passed to
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
-** implementation. The xCreate() function in turn returns an
+** implementation. The xCreate() function in turn returns an
** sqlite3_tokenizer structure representing the specific tokenizer to
** be used for the fts3 table (customized by the tokenizer clause arguments).
**
@@ -142609,7 +166344,7 @@ struct sqlite3_tokenizer_module {
** then argc is set to 2, and the argv[] array contains pointers
** to the strings "arg1" and "arg2".
**
- ** This method should return either SQLITE_OK (0), or an SQLite error
+ ** This method should return either SQLITE_OK (0), or an SQLite error
** code. If SQLITE_OK is returned, then *ppTokenizer should be set
** to point at the newly created tokenizer structure. The generic
** sqlite3_tokenizer.pModule variable should not be initialized by
@@ -142630,7 +166365,7 @@ struct sqlite3_tokenizer_module {
/*
** Create a tokenizer cursor to tokenize an input buffer. The caller
** is responsible for ensuring that the input buffer remains valid
- ** until the cursor is closed (using the xClose() method).
+ ** until the cursor is closed (using the xClose() method).
*/
int (*xOpen)(
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
@@ -142639,7 +166374,7 @@ struct sqlite3_tokenizer_module {
);
/*
- ** Destroy an existing tokenizer cursor. The fts3 module calls this
+ ** Destroy an existing tokenizer cursor. The fts3 module calls this
** method exactly once for each successful call to xOpen().
*/
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
@@ -142650,7 +166385,7 @@ struct sqlite3_tokenizer_module {
** "OUT" variables identified below, or SQLITE_DONE to indicate that
** the end of the buffer has been reached, or an SQLite error code.
**
- ** *ppToken should be set to point at a buffer containing the
+ ** *ppToken should be set to point at a buffer containing the
** normalized version of the token (i.e. after any case-folding and/or
** stemming has been performed). *pnBytes should be set to the length
** of this buffer in bytes. The input text that generated the token is
@@ -142662,7 +166397,7 @@ struct sqlite3_tokenizer_module {
**
** The buffer *ppToken is set to point at is managed by the tokenizer
** implementation. It is only required to be valid until the next call
- ** to xNext() or xClose().
+ ** to xNext() or xClose().
*/
/* TODO(shess) current implementation requires pInput to be
** nul-terminated. This should either be fixed, or pInput/nBytes
@@ -142680,7 +166415,7 @@ struct sqlite3_tokenizer_module {
** Methods below this point are only available if iVersion>=1.
*/
- /*
+ /*
** Configure the language id of a tokenizer cursor.
*/
int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
@@ -142749,7 +166484,7 @@ struct Fts3Hash {
} *ht;
};
-/* Each element in the hash table is an instance of the following
+/* Each element in the hash table is an instance of the following
** structure. All elements are stored on a single doubly-linked list.
**
** Again, this structure is intended to be opaque, but it can't really
@@ -142768,10 +166503,10 @@ struct Fts3HashElem {
** (including the null-terminator, if any). Case
** is respected in comparisons.
**
-** FTS3_HASH_BINARY pKey points to binary data nKey bytes long.
+** FTS3_HASH_BINARY pKey points to binary data nKey bytes long.
** memcmp() is used to compare keys.
**
-** A copy of the key is made if the copyKey parameter to fts3HashInit is 1.
+** A copy of the key is made if the copyKey parameter to fts3HashInit is 1.
*/
#define FTS3_HASH_STRING 1
#define FTS3_HASH_BINARY 2
@@ -142824,7 +166559,7 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
/*
** This constant determines the maximum depth of an FTS expression tree
-** that the library will create and use. FTS uses recursion to perform
+** that the library will create and use. FTS uses recursion to perform
** various operations on the query tree, so the disadvantage of a large
** limit is that it may allow very large queries to use large amounts
** of stack space (perhaps causing a stack overflow).
@@ -142842,11 +166577,11 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
#define FTS3_MERGE_COUNT 16
/*
-** This is the maximum amount of data (in bytes) to store in the
+** This is the maximum amount of data (in bytes) to store in the
** Fts3Table.pendingTerms hash table. Normally, the hash table is
** populated as documents are inserted/updated/deleted in a transaction
** and used to create a new segment when the transaction is committed.
-** However if this limit is reached midway through a transaction, a new
+** However if this limit is reached midway through a transaction, a new
** segment is created and the hash table cleared immediately.
*/
#define FTS3_MAX_PENDING_DATA (1*1024*1024)
@@ -142872,10 +166607,12 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
*/
#define FTS3_VARINT_MAX 10
+#define FTS3_BUFFER_PADDING 8
+
/*
** 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.
+** 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
@@ -142883,8 +166620,8 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
** 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
+** 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
@@ -142902,11 +166639,23 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
** Terminator values for position-lists and column-lists.
*/
#define POS_COLUMN (1) /* Column-list terminator */
-#define POS_END (0) /* Position-list terminator */
+#define POS_END (0) /* Position-list terminator */
+
+/*
+** The assert_fts3_nc() macro is similar to the assert() macro, except that it
+** is used for assert() conditions that are true only if it can be
+** guranteed that the database is not corrupt.
+*/
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
+SQLITE_API extern int sqlite3_fts3_may_be_corrupt;
+# define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x))
+#else
+# define assert_fts3_nc(x) assert(x)
+#endif
/*
** This section provides definitions to allow the
-** FTS3 extension to be compiled outside of the
+** FTS3 extension to be compiled outside of the
** amalgamation.
*/
#ifndef SQLITE_AMALGAMATION
@@ -142944,7 +166693,7 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
/*
** Activate assert() only if SQLITE_TEST is enabled.
*/
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
@@ -142959,6 +166708,11 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
# define TESTONLY(X)
#endif
+#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
+#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+
+#define deliberate_fall_through
+
#endif /* SQLITE_AMALGAMATION */
#ifdef SQLITE_DEBUG
@@ -143002,11 +166756,13 @@ struct Fts3Table {
char *zLanguageid; /* languageid=xxx option, or NULL */
int nAutoincrmerge; /* Value configured by 'automerge' */
u32 nLeafAdd; /* Number of leaf blocks added this trans */
+ int bLock; /* Used to prevent recursive content= tbls */
- /* Precompiled statements used by the implementation. Each of these
- ** statements is run and reset within a single virtual table API call.
+ /* Precompiled statements used by the implementation. Each of these
+ ** statements is run and reset within a single virtual table API call.
*/
sqlite3_stmt *aStmt[40];
+ sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */
char *zReadExprlist;
char *zWriteExprlist;
@@ -143021,8 +166777,8 @@ struct Fts3Table {
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
- /*
- ** The following array of hash tables is used to buffer pending index
+ /*
+ ** The following array of hash tables is used to buffer pending index
** updates during transactions. All pending updates buffered at any one
** time must share a common language-id (see the FTS4 langid= feature).
** The current language id is stored in variable iPrevLangid.
@@ -143032,10 +166788,10 @@ struct Fts3Table {
** terms that appear in the document set. Each subsequent index in aIndex[]
** is an index of prefixes of a specific length.
**
- ** Variable nPendingData contains an estimate the memory consumed by the
+ ** Variable nPendingData contains an estimate the memory consumed by the
** pending data structures, including hash table overhead, but not including
** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash
- ** tables are flushed to disk. Variable iPrevDocid is the docid of the most
+ ** tables are flushed to disk. Variable iPrevDocid is the docid of the most
** recently inserted record.
*/
int nIndex; /* Size of aIndex[] */
@@ -143059,13 +166815,23 @@ struct Fts3Table {
int mxSavepoint; /* Largest valid xSavepoint integer */
#endif
-#ifdef SQLITE_TEST
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/* True to disable the incremental doclist optimization. This is controled
** by special insert command 'test-no-incr-doclist'. */
int bNoIncrDoclist;
+
+ /* Number of segments in a level */
+ int nMergeCount;
#endif
};
+/* Macro to find the number of segments to merge */
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
+# define MergeCount(P) ((P)->nMergeCount)
+#else
+# define MergeCount(P) FTS3_MERGE_COUNT
+#endif
+
/*
** When the core wants to read from the virtual table, it creates a
** virtual table cursor (an instance of the following structure) using
@@ -143076,6 +166842,7 @@ struct Fts3Cursor {
i16 eSearch; /* Search strategy (see below) */
u8 isEof; /* True if at End Of Results */
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
+ u8 bSeekStmt; /* True if pStmt is a seek */
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
Fts3Expr *pExpr; /* Parsed MATCH query string */
int iLangid; /* Language being queried for */
@@ -143107,10 +166874,10 @@ struct Fts3Cursor {
**
** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d);
** SELECT docid FROM ex1 WHERE b MATCH 'one two three';
-**
+**
** Because the LHS of the MATCH operator is 2nd column "b",
** Fts3Cursor.eSearch will be set to FTS3_FULLTEXT_SEARCH+1. (+0 for a,
-** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1"
+** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1"
** indicating that all columns should be searched,
** then eSearch would be set to FTS3_FULLTEXT_SEARCH+4.
*/
@@ -143169,8 +166936,8 @@ struct Fts3Phrase {
char *pOrPoslist;
i64 iOrDocid;
- /* Variables below this point are populated by fts3_expr.c when parsing
- ** a MATCH expression. Everything above is part of the evaluation phase.
+ /* 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 */
@@ -143180,10 +166947,10 @@ struct Fts3Phrase {
/*
** A tree of these objects forms the RHS of a MATCH operator.
**
-** 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
+** 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
@@ -143195,7 +166962,7 @@ struct Fts3Phrase {
** aMI[iCol*3 + 1] = Number of occurrences
** aMI[iCol*3 + 2] = Number of rows containing at least one instance
**
-** The aMI array is allocated using sqlite3_malloc(). It should be freed
+** The aMI array is allocated using sqlite3_malloc(). It should be freed
** when the expression node is.
*/
struct Fts3Expr {
@@ -143219,7 +166986,7 @@ struct Fts3Expr {
/*
** Candidate values for Fts3Query.eType. Note that the order of the first
-** four values is in order of precedence when parsing expressions. For
+** four values is in order of precedence when parsing expressions. For
** example, the following:
**
** "a OR b AND c NOT d NEAR e"
@@ -143276,7 +167043,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Ft
SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *);
SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *);
-SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *,
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *,
int, int, int, const char *, int, int, int, Fts3MultiSegReader *);
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
@@ -143328,6 +167095,8 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...);
SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64);
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
+SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
+SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
@@ -143336,11 +167105,12 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut);
/* fts3_tokenizer.c */
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
-SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
+SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
sqlite3_tokenizer **, char **
);
SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char);
@@ -143359,7 +167129,7 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
);
SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
#ifdef SQLITE_TEST
-SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
+SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*);
SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
#endif
@@ -143376,7 +167146,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *);
-SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
+SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
@@ -143409,7 +167179,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
/* #include <stdarg.h> */
/* #include "fts3.h" */
-#ifndef SQLITE_CORE
+#ifndef SQLITE_CORE
/* # include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#endif
@@ -143426,7 +167196,15 @@ SQLITE_PRIVATE int sqlite3Fts3Never(int b) { assert( !b ); return b; }
# endif
#endif
-/*
+/*
+** This variable is set to false when running tests for which the on disk
+** structures should not be corrupt. Otherwise, true. If it is false, extra
+** assert() conditions in the fts3 code are activated - conditions that are
+** only true if it is guaranteed that the fts3 database is not corrupt.
+*/
+SQLITE_API int sqlite3_fts3_may_be_corrupt = 1;
+
+/*
** Write a 64-bit variable-length integer to memory starting at p[0].
** The length of data written will be between 1 and FTS3_VARINT_MAX bytes.
** The number of bytes written is returned.
@@ -143444,19 +167222,15 @@ SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
}
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
- v = (v & mask1) | ( (*ptr++) << shift ); \
+ v = (v & mask1) | ( (*(const unsigned char*)(ptr++)) << shift ); \
if( (v & mask2)==0 ){ var = v; return ret; }
#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \
v = (*ptr++); \
if( (v & mask2)==0 ){ var = v; return ret; }
-/*
-** Read a 64-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read, or 0 on error.
-** The value is stored in *v.
-*/
-SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
- const char *pStart = p;
+SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
+ const unsigned char *p = (const unsigned char*)pBuf;
+ const unsigned char *pStart = p;
u32 a;
u64 b;
int shift;
@@ -143477,24 +167251,62 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
}
/*
-** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to a
-** 32-bit integer before it is returned.
+** Read a 64-bit variable-length integer from memory starting at p[0].
+** Return the number of bytes read, or 0 on error.
+** The value is stored in *v.
+*/
+SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+ return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
+}
+
+/*
+** Read a 64-bit variable-length integer from memory starting at p[0] and
+** not extending past pEnd[-1].
+** Return the number of bytes read, or 0 on error.
+** The value is stored in *v.
+*/
+SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(
+ const char *pBuf,
+ const char *pEnd,
+ sqlite_int64 *v
+){
+ const unsigned char *p = (const unsigned char*)pBuf;
+ const unsigned char *pStart = p;
+ const unsigned char *pX = (const unsigned char*)pEnd;
+ u64 b = 0;
+ int shift;
+ for(shift=0; shift<=63; shift+=7){
+ u64 c = p<pX ? *p : 0;
+ p++;
+ b += (c&0x7F) << shift;
+ if( (c & 0x80)==0 ) break;
+ }
+ *v = b;
+ return (int)(p - pStart);
+}
+
+/*
+** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
+** a non-negative 32-bit integer before it is returned.
*/
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){
+ const unsigned char *ptr = (const unsigned char*)p;
u32 a;
#ifndef fts3GetVarint32
- GETVARINT_INIT(a, p, 0, 0x00, 0x80, *pi, 1);
+ GETVARINT_INIT(a, ptr, 0, 0x00, 0x80, *pi, 1);
#else
- a = (*p++);
+ a = (*ptr++);
assert( a & 0x80 );
#endif
- GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *pi, 2);
- GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *pi, 3);
- GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *pi, 4);
+ GETVARINT_STEP(a, ptr, 7, 0x7F, 0x4000, *pi, 2);
+ GETVARINT_STEP(a, ptr, 14, 0x3FFF, 0x200000, *pi, 3);
+ GETVARINT_STEP(a, ptr, 21, 0x1FFFFF, 0x10000000, *pi, 4);
a = (a & 0x0FFFFFFF );
- *pi = (int)(a | ((u32)(*p & 0x0F) << 28));
+ *pi = (int)(a | ((u32)(*ptr & 0x07) << 28));
+ assert( 0==(a & 0x80000000) );
+ assert( *pi>=0 );
return 5;
}
@@ -143533,7 +167345,7 @@ SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){
int iOut = 0; /* Index of next byte to write to output */
/* If the first byte was a '[', then the close-quote character is a ']' */
- if( quote=='[' ) quote = ']';
+ if( quote=='[' ) quote = ']';
while( z[iIn] ){
if( z[iIn]==quote ){
@@ -143569,14 +167381,14 @@ static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
** varint is part of.
*/
static void fts3GetReverseVarint(
- char **pp,
- char *pStart,
+ char **pp,
+ char *pStart,
sqlite3_int64 *pVal
){
sqlite3_int64 iVal;
char *p;
- /* Pointer p now points at the first byte past the varint we are
+ /* 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--);
@@ -143598,6 +167410,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
assert( p->pSegments==0 );
/* Free any prepared statements held */
+ sqlite3_finalize(p->pSeekStmt);
for(i=0; i<SizeofArray(p->aStmt); i++){
sqlite3_finalize(p->aStmt[i]);
}
@@ -143662,13 +167475,18 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
sqlite3 *db = p->db; /* Database handle */
/* Drop the shadow tables */
- if( p->zContentTbl==0 ){
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName);
- }
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName);
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName);
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName);
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName);
+ fts3DbExec(&rc, db,
+ "DROP TABLE IF EXISTS %Q.'%q_segments';"
+ "DROP TABLE IF EXISTS %Q.'%q_segdir';"
+ "DROP TABLE IF EXISTS %Q.'%q_docsize';"
+ "DROP TABLE IF EXISTS %Q.'%q_stat';"
+ "%s DROP TABLE IF EXISTS %Q.'%q_content';",
+ zDb, p->zName,
+ zDb, p->zName,
+ zDb, p->zName,
+ zDb, p->zName,
+ (p->zContentTbl ? "--" : ""), zDb,p->zName
+ );
/* If everything has worked, invoke fts3DisconnectMethod() to free the
** memory associated with the Fts3Table structure and return SQLITE_OK.
@@ -143683,7 +167501,7 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
** passed as the first argument. This is done as part of the xConnect()
** and xCreate() methods.
**
-** If *pRc is non-zero when this function is called, it is a no-op.
+** If *pRc is non-zero when this function is called, it is a no-op.
** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
** before returning.
*/
@@ -143706,7 +167524,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
/* Create the whole "CREATE TABLE" statement to pass to SQLite */
zSql = sqlite3_mprintf(
- "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)",
+ "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)",
zCols, p->zName, zLanguageid
);
if( !zCols || !zSql ){
@@ -143725,7 +167543,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
** Create the %_stat table if it does not already exist.
*/
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){
- fts3DbExec(pRc, p->db,
+ fts3DbExec(pRc, p->db,
"CREATE TABLE IF NOT EXISTS %Q.'%q_stat'"
"(id INTEGER PRIMARY KEY, value BLOB);",
p->zDb, p->zName
@@ -143761,9 +167579,9 @@ static int fts3CreateTables(Fts3Table *p){
zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid);
}
if( zContentCols==0 ) rc = SQLITE_NOMEM;
-
+
/* Create the content table */
- fts3DbExec(&rc, db,
+ fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_content'(%s)",
p->zDb, p->zName, zContentCols
);
@@ -143771,11 +167589,11 @@ static int fts3CreateTables(Fts3Table *p){
}
/* Create other tables */
- fts3DbExec(&rc, db,
+ fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
p->zDb, p->zName
);
- fts3DbExec(&rc, db,
+ fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_segdir'("
"level INTEGER,"
"idx INTEGER,"
@@ -143788,7 +167606,7 @@ static int fts3CreateTables(Fts3Table *p){
p->zDb, p->zName
);
if( p->bHasDocsize ){
- fts3DbExec(&rc, db,
+ fts3DbExec(&rc, db,
"CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
p->zDb, p->zName
);
@@ -143803,7 +167621,7 @@ static int fts3CreateTables(Fts3Table *p){
/*
** Store the current database page-size in bytes in p->nPgsz.
**
-** If *pRc is non-zero when this function is called, it is a no-op.
+** If *pRc is non-zero when this function is called, it is a no-op.
** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
** before returning.
*/
@@ -143812,7 +167630,7 @@ static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
int rc; /* Return code */
char *zSql; /* SQL text "PRAGMA %Q.page_size" */
sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */
-
+
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb);
if( !zSql ){
rc = SQLITE_NOMEM;
@@ -143838,11 +167656,11 @@ static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
**
** <key> = <value>
**
-** There may not be whitespace surrounding the "=" character. The <value>
+** There may not be whitespace surrounding the "=" character. The <value>
** term may be quoted, but the <key> may not.
*/
static int fts3IsSpecialColumn(
- const char *z,
+ const char *z,
int *pnKey,
char **pzValue
){
@@ -143900,10 +167718,10 @@ static void fts3Appendf(
** memory.
*/
static char *fts3QuoteId(char const *zInput){
- int nRet;
+ sqlite3_int64 nRet;
char *zRet;
nRet = 2 + (int)strlen(zInput)*2 + 1;
- zRet = sqlite3_malloc(nRet);
+ zRet = sqlite3_malloc64(nRet);
if( zRet ){
int i;
char *z = zRet;
@@ -143919,7 +167737,7 @@ static char *fts3QuoteId(char const *zInput){
}
/*
-** Return a list of comma separated SQL expressions and a FROM clause that
+** Return a list of comma separated SQL expressions and a FROM clause that
** could be used in a SELECT statement such as the following:
**
** SELECT <list of expressions> FROM %_content AS x ...
@@ -143970,7 +167788,7 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid);
}
}
- fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
+ fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
p->zDb,
(p->zContentTbl ? p->zContentTbl : p->zName),
(p->zContentTbl ? "" : "_content")
@@ -143985,7 +167803,7 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
**
** If argument zFunc is not NULL, then all but the first question mark
** is preceded by zFunc and an open bracket, and followed by a closed
-** bracket. For example, if zFunc is "zip" and the FTS3 table has three
+** bracket. For example, if zFunc is "zip" and the FTS3 table has three
** user-defined text columns, the following string is returned:
**
** "?, zip(?), zip(?), zip(?)"
@@ -144021,12 +167839,28 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
}
/*
+** Buffer z contains a positive integer value encoded as utf-8 text.
+** Decode this value and store it in *pnOut, returning the number of bytes
+** consumed. If an overflow error occurs return a negative value.
+*/
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut){
+ u64 iVal = 0;
+ int i;
+ for(i=0; z[i]>='0' && z[i]<='9'; i++){
+ iVal = iVal*10 + (z[i] - '0');
+ if( iVal>0x7FFFFFFF ) return -1;
+ }
+ *pnOut = (int)iVal;
+ return i;
+}
+
+/*
** This function interprets the string at (*pp) as a non-negative integer
-** value. It reads the integer and sets *pnOut to the value read, then
+** value. It reads the integer and sets *pnOut to the value read, then
** sets *pp to point to the byte immediately following the last byte of
** the integer value.
**
-** Only decimal digits ('0'..'9') may be part of an integer value.
+** Only decimal digits ('0'..'9') may be part of an integer value.
**
** If *pp does not being with a decimal digit SQLITE_ERROR is returned and
** the output value undefined. Otherwise SQLITE_OK is returned.
@@ -144035,19 +167869,17 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
*/
static int fts3GobbleInt(const char **pp, int *pnOut){
const int MAX_NPREFIX = 10000000;
- const char *p; /* Iterator pointer */
int nInt = 0; /* Output value */
-
- for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
- nInt = nInt * 10 + (p[0] - '0');
- if( nInt>MAX_NPREFIX ){
- nInt = 0;
- break;
- }
+ int nByte;
+ nByte = sqlite3Fts3ReadInt(*pp, &nInt);
+ if( nInt>MAX_NPREFIX ){
+ nInt = 0;
+ }
+ if( nByte==0 ){
+ return SQLITE_ERROR;
}
- if( p==*pp ) return SQLITE_ERROR;
*pnOut = nInt;
- *pp = p;
+ *pp += nByte;
return SQLITE_OK;
}
@@ -144084,7 +167916,7 @@ static int fts3PrefixParameter(
}
}
- aIndex = sqlite3_malloc(sizeof(struct Fts3Index) * nIndex);
+ aIndex = sqlite3_malloc64(sizeof(struct Fts3Index) * nIndex);
*apIndex = aIndex;
if( !aIndex ){
return SQLITE_NOMEM;
@@ -144147,7 +167979,7 @@ static int fts3ContentColumns(
char **pzErr /* OUT: error message */
){
int rc = SQLITE_OK; /* Return code */
- char *zSql; /* "SELECT *" statement on zTbl */
+ char *zSql; /* "SELECT *" statement on zTbl */
sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */
zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl);
@@ -144163,7 +167995,7 @@ static int fts3ContentColumns(
if( rc==SQLITE_OK ){
const char **azCol; /* Output array */
- int nStr = 0; /* Size of all column names (incl. 0x00) */
+ sqlite3_int64 nStr = 0; /* Size of all column names (incl. 0x00) */
int nCol; /* Number of table columns */
int i; /* Used to iterate through columns */
@@ -144173,11 +168005,11 @@ static int fts3ContentColumns(
nCol = sqlite3_column_count(pStmt);
for(i=0; i<nCol; i++){
const char *zCol = sqlite3_column_name(pStmt, i);
- nStr += (int)strlen(zCol) + 1;
+ nStr += strlen(zCol) + 1;
}
/* Allocate and populate the array to return. */
- azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
+ azCol = (const char **)sqlite3_malloc64(sizeof(char *) * nCol + nStr);
if( azCol==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -144225,7 +168057,7 @@ static int fts3InitVtab(
Fts3Table *p = 0; /* Pointer to allocated vtab */
int rc = SQLITE_OK; /* Return code */
int i; /* Iterator variable */
- int nByte; /* Size of allocation used for *p */
+ sqlite3_int64 nByte; /* Size of allocation used for *p */
int iCol; /* Column index */
int nString = 0; /* Bytes required to hold all column names */
int nCol = 0; /* Number of columns in the FTS table */
@@ -144259,10 +168091,10 @@ static int fts3InitVtab(
nName = (int)strlen(argv[2]) + 1;
nByte = sizeof(const char *) * (argc-2);
- aCol = (const char **)sqlite3_malloc(nByte);
+ aCol = (const char **)sqlite3_malloc64(nByte);
if( aCol ){
memset((void*)aCol, 0, nByte);
- azNotindexed = (char **)sqlite3_malloc(nByte);
+ azNotindexed = (char **)sqlite3_malloc64(nByte);
}
if( azNotindexed ){
memset(azNotindexed, 0, nByte);
@@ -144289,9 +168121,9 @@ static int fts3InitVtab(
char *zVal;
/* Check if this is a tokenizer specification */
- if( !pTokenizer
+ if( !pTokenizer
&& strlen(z)>8
- && 0==sqlite3_strnicmp(z, "tokenize", 8)
+ && 0==sqlite3_strnicmp(z, "tokenize", 8)
&& 0==sqlite3Fts3IsIdChar(z[8])
){
rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr);
@@ -144323,65 +168155,66 @@ static int fts3InitVtab(
break;
}
}
- if( iOpt==SizeofArray(aFts4Opt) ){
- sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
- rc = SQLITE_ERROR;
- }else{
- switch( iOpt ){
- case 0: /* MATCHINFO */
- if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
- sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
- rc = SQLITE_ERROR;
- }
- bNoDocsize = 1;
- break;
+ switch( iOpt ){
+ case 0: /* MATCHINFO */
+ if( strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "fts3", 4) ){
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized matchinfo: %s", zVal);
+ rc = SQLITE_ERROR;
+ }
+ bNoDocsize = 1;
+ break;
- case 1: /* PREFIX */
- sqlite3_free(zPrefix);
- zPrefix = zVal;
- zVal = 0;
- break;
+ case 1: /* PREFIX */
+ sqlite3_free(zPrefix);
+ zPrefix = zVal;
+ zVal = 0;
+ break;
- case 2: /* COMPRESS */
- sqlite3_free(zCompress);
- zCompress = 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 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", 4))
- ){
- sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
- rc = SQLITE_ERROR;
- }
- bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
- break;
+ case 4: /* ORDER */
+ if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
+ && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
+ ){
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
+ rc = SQLITE_ERROR;
+ }
+ bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
+ break;
- case 5: /* CONTENT */
- sqlite3_free(zContent);
- zContent = zVal;
- zVal = 0;
- break;
+ case 5: /* CONTENT */
+ sqlite3_free(zContent);
+ zContent = zVal;
+ zVal = 0;
+ break;
- case 6: /* LANGUAGEID */
- assert( iOpt==6 );
- sqlite3_free(zLanguageid);
- zLanguageid = zVal;
- zVal = 0;
- break;
+ case 6: /* LANGUAGEID */
+ assert( iOpt==6 );
+ sqlite3_free(zLanguageid);
+ zLanguageid = zVal;
+ zVal = 0;
+ break;
- case 7: /* NOTINDEXED */
- azNotindexed[nNotindexed++] = zVal;
- zVal = 0;
- break;
- }
+ case 7: /* NOTINDEXED */
+ azNotindexed[nNotindexed++] = zVal;
+ zVal = 0;
+ break;
+
+ default:
+ assert( iOpt==SizeofArray(aFts4Opt) );
+ sqlite3Fts3ErrMsg(pzErr, "unrecognized parameter: %s", z);
+ rc = SQLITE_ERROR;
+ break;
}
sqlite3_free(zVal);
}
@@ -144402,17 +168235,17 @@ static int fts3InitVtab(
** TABLE statement, use all columns from the content table.
*/
if( rc==SQLITE_OK && zContent ){
- sqlite3_free(zCompress);
- sqlite3_free(zUncompress);
+ sqlite3_free(zCompress);
+ sqlite3_free(zUncompress);
zCompress = 0;
zUncompress = 0;
if( nCol==0 ){
- sqlite3_free((void*)aCol);
+ sqlite3_free((void*)aCol);
aCol = 0;
rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr);
/* If a languageid= option was specified, remove the language id
- ** column from the aCol[] array. */
+ ** column from the aCol[] array. */
if( rc==SQLITE_OK && zLanguageid ){
int j;
for(j=0; j<nCol; j++){
@@ -144456,7 +168289,7 @@ static int fts3InitVtab(
nName + /* zName */
nDb + /* zDb */
nString; /* Space for azColumn strings */
- p = (Fts3Table*)sqlite3_malloc(nByte);
+ p = (Fts3Table*)sqlite3_malloc64(nByte);
if( p==0 ){
rc = SQLITE_NOMEM;
goto fts3_init_out;
@@ -144469,9 +168302,9 @@ static int fts3InitVtab(
p->pTokenizer = pTokenizer;
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
p->bHasDocsize = (isFts4 && bNoDocsize==0);
- p->bHasStat = isFts4;
- p->bFts4 = isFts4;
- p->bDescIdx = bDescIdx;
+ p->bHasStat = (u8)isFts4;
+ p->bFts4 = (u8)isFts4;
+ p->bDescIdx = (u8)bDescIdx;
p->nAutoincrmerge = 0xff; /* 0xff means setting unknown */
p->zContentTbl = zContent;
p->zLanguageid = zLanguageid;
@@ -144499,10 +168332,12 @@ static int fts3InitVtab(
/* Fill in the azColumn array */
for(iCol=0; iCol<nCol; iCol++){
- char *z;
+ char *z;
int n = 0;
z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
- memcpy(zCsr, z, n);
+ if( n>0 ){
+ memcpy(zCsr, z, n);
+ }
zCsr[n] = '\0';
sqlite3Fts3Dequote(zCsr);
p->azColumn[iCol] = zCsr;
@@ -144516,7 +168351,7 @@ static int fts3InitVtab(
for(i=0; i<nNotindexed; i++){
char *zNot = azNotindexed[i];
if( zNot && n==(int)strlen(zNot)
- && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n)
+ && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n)
){
p->abNotindexed[iCol] = 1;
sqlite3_free(zNot);
@@ -144540,7 +168375,7 @@ static int fts3InitVtab(
p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc);
if( rc!=SQLITE_OK ) goto fts3_init_out;
- /* If this is an xCreate call, create the underlying tables in the
+ /* If this is an xCreate call, create the underlying tables in the
** database. TODO: For xConnect(), it could verify that said tables exist.
*/
if( isCreate ){
@@ -144559,6 +168394,10 @@ static int fts3InitVtab(
fts3DatabasePageSize(&rc, p);
p->nNodeSize = p->nPgsz-35;
+#if defined(SQLITE_DEBUG)||defined(SQLITE_TEST)
+ p->nMergeCount = FTS3_MERGE_COUNT;
+#endif
+
/* Declare the table schema to SQLite. */
fts3DeclareVtab(&rc, p);
@@ -144636,11 +168475,11 @@ static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){
#endif
}
-/*
+/*
** Implementation of the xBestIndex method for FTS3 tables. There
** are three possible strategies, in order of preference:
**
-** 1. Direct lookup by rowid or docid.
+** 1. Direct lookup by rowid or docid.
** 2. Full-text search using a MATCH operator on a non-docid column.
** 3. Linear scan of %_content table.
*/
@@ -144654,8 +168493,12 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int iDocidLe = -1; /* Index of docid<=x constraint, if present */
int iIdx;
+ if( p->bLock ){
+ return SQLITE_ERROR;
+ }
+
/* By default use a full table scan. This is an expensive option,
- ** so search through the constraints to see if a more efficient
+ ** so search through the constraints to see if a more efficient
** strategy is possible.
*/
pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
@@ -144691,12 +168534,12 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
**
** If there is more than one MATCH constraint available, use the first
** one encountered. If there is both a MATCH constraint and a direct
- ** rowid/docid lookup, prefer the MATCH strategy. This is done even
+ ** rowid/docid lookup, prefer the MATCH strategy. This is done even
** though the rowid/docid lookup is faster than a MATCH query, selecting
- ** it would lead to an "unable to use function MATCH in the requested
+ ** it would lead to an "unable to use function MATCH in the requested
** context" error.
*/
- if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH
+ if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH
&& pCons->iColumn>=0 && pCons->iColumn<=p->nColumn
){
pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn;
@@ -144705,7 +168548,7 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
/* Equality constraint on the langid column */
- if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
+ if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
&& pCons->iColumn==p->nColumn + 2
){
iLangidCons = i;
@@ -144733,22 +168576,22 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
if( iCons>=0 ){
pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
pInfo->aConstraintUsage[iCons].omit = 1;
- }
+ }
if( iLangidCons>=0 ){
pInfo->idxNum |= FTS3_HAVE_LANGID;
pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++;
- }
+ }
if( iDocidGe>=0 ){
pInfo->idxNum |= FTS3_HAVE_DOCID_GE;
pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++;
- }
+ }
if( iDocidLe>=0 ){
pInfo->idxNum |= FTS3_HAVE_DOCID_LE;
pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++;
- }
+ }
/* Regardless of the strategy selected, FTS can deliver rows in rowid (or
- ** docid) order. Both ascending and descending are possible.
+ ** docid) order. Both ascending and descending are possible.
*/
if( pInfo->nOrderBy==1 ){
struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0];
@@ -144775,7 +168618,7 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
UNUSED_PARAMETER(pVTab);
/* Allocate a buffer large enough for an Fts3Cursor structure. If the
- ** allocation succeeds, zero it and return SQLITE_OK. Otherwise,
+ ** allocation succeeds, zero it and return SQLITE_OK. Otherwise,
** if the allocation fails, return SQLITE_NOMEM.
*/
*ppCsr = pCsr = (sqlite3_vtab_cursor *)sqlite3_malloc(sizeof(Fts3Cursor));
@@ -144787,17 +168630,46 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
}
/*
+** Finalize the statement handle at pCsr->pStmt.
+**
+** Or, if that statement handle is one created by fts3CursorSeekStmt(),
+** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement
+** pointer there instead of finalizing it.
+*/
+static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){
+ if( pCsr->bSeekStmt ){
+ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
+ if( p->pSeekStmt==0 ){
+ p->pSeekStmt = pCsr->pStmt;
+ sqlite3_reset(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ }
+ pCsr->bSeekStmt = 0;
+ }
+ sqlite3_finalize(pCsr->pStmt);
+}
+
+/*
+** Free all resources currently held by the cursor passed as the only
+** argument.
+*/
+static void fts3ClearCursor(Fts3Cursor *pCsr){
+ fts3CursorFinalizeStmt(pCsr);
+ sqlite3Fts3FreeDeferredTokens(pCsr);
+ sqlite3_free(pCsr->aDoclist);
+ sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
+ sqlite3Fts3ExprFree(pCsr->pExpr);
+ memset(&(&pCsr->base)[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
+}
+
+/*
** Close the cursor. For additional information see the documentation
** on the xClose method of the virtual table interface.
*/
static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
- sqlite3_finalize(pCsr->pStmt);
- sqlite3Fts3ExprFree(pCsr->pExpr);
- sqlite3Fts3FreeDeferredTokens(pCsr);
- sqlite3_free(pCsr->aDoclist);
- sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
+ fts3ClearCursor(pCsr);
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
sqlite3_free(pCsr);
return SQLITE_OK;
@@ -144811,40 +168683,49 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
**
** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
** it. If an error occurs, return an SQLite error code.
-**
-** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
*/
-static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
+static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
int rc = SQLITE_OK;
if( pCsr->pStmt==0 ){
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
char *zSql;
- zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
- if( !zSql ) return SQLITE_NOMEM;
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
- sqlite3_free(zSql);
+ if( p->pSeekStmt ){
+ pCsr->pStmt = p->pSeekStmt;
+ p->pSeekStmt = 0;
+ }else{
+ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
+ if( !zSql ) return SQLITE_NOMEM;
+ p->bLock++;
+ rc = sqlite3_prepare_v3(
+ p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
+ );
+ p->bLock--;
+ sqlite3_free(zSql);
+ }
+ if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
}
- *ppStmt = pCsr->pStmt;
return rc;
}
/*
** Position the pCsr->pStmt statement so that it is on the row
** of the %_content table that contains the last match. Return
-** SQLITE_OK on success.
+** SQLITE_OK on success.
*/
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
int rc = SQLITE_OK;
if( pCsr->isRequireSeek ){
- sqlite3_stmt *pStmt = 0;
-
- rc = fts3CursorSeekStmt(pCsr, &pStmt);
+ rc = fts3CursorSeekStmt(pCsr);
if( rc==SQLITE_OK ){
+ Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
+ pTab->bLock++;
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
pCsr->isRequireSeek = 0;
if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
+ pTab->bLock--;
return SQLITE_OK;
}else{
+ pTab->bLock--;
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
/* If no row was found and no error has occurred, then the %_content
@@ -144865,7 +168746,7 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
/*
** This function is used to process a single interior node when searching
-** a b-tree for a term or term prefix. The node data is passed to this
+** a b-tree for a term or term prefix. The node data is passed to this
** function via the zNode/nNode parameters. The term to search for is
** passed in zTerm/nTerm.
**
@@ -144890,13 +168771,14 @@ static int fts3ScanInteriorNode(
const char *zCsr = zNode; /* Cursor to iterate through node */
const char *zEnd = &zCsr[nNode];/* End of interior node buffer */
char *zBuffer = 0; /* Buffer to load terms into */
- int nAlloc = 0; /* Size of allocated buffer */
+ i64 nAlloc = 0; /* Size of allocated buffer */
int isFirstTerm = 1; /* True when processing first term on page */
sqlite3_int64 iChild; /* Block id of child node to descend to */
+ int nBuffer = 0; /* Total term size */
- /* Skip over the 'height' varint that occurs at the start of every
+ /* Skip over the 'height' varint that occurs at the start of every
** interior node. Then load the blockid of the left-child of the b-tree
- ** node into variable iChild.
+ ** node into variable iChild.
**
** Even if the data structure on disk is corrupted, this (reading two
** varints from the buffer) does not risk an overread. If zNode is a
@@ -144912,29 +168794,33 @@ static int fts3ScanInteriorNode(
if( zCsr>zEnd ){
return FTS_CORRUPT_VTAB;
}
-
+
while( zCsr<zEnd && (piFirst || piLast) ){
int cmp; /* memcmp() result */
int nSuffix; /* Size of term suffix */
int nPrefix = 0; /* Size of term prefix */
- int nBuffer; /* Total term size */
-
+
/* Load the next term on the node into zBuffer. Use realloc() to expand
** the size of zBuffer if required. */
if( !isFirstTerm ){
zCsr += fts3GetVarint32(zCsr, &nPrefix);
+ if( nPrefix>nBuffer ){
+ rc = FTS_CORRUPT_VTAB;
+ goto finish_scan;
+ }
}
isFirstTerm = 0;
zCsr += fts3GetVarint32(zCsr, &nSuffix);
-
- if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
+
+ assert( nPrefix>=0 && nSuffix>=0 );
+ if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){
rc = FTS_CORRUPT_VTAB;
goto finish_scan;
}
- if( nPrefix+nSuffix>nAlloc ){
+ if( (i64)nPrefix+nSuffix>nAlloc ){
char *zNew;
- nAlloc = (nPrefix+nSuffix) * 2;
- zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
+ nAlloc = ((i64)nPrefix+nSuffix) * 2;
+ zNew = (char *)sqlite3_realloc64(zBuffer, nAlloc);
if( !zNew ){
rc = SQLITE_NOMEM;
goto finish_scan;
@@ -144948,8 +168834,8 @@ static int fts3ScanInteriorNode(
/* Compare the term we are searching for with the term just loaded from
** the interior node. If the specified term is greater than or equal
- ** to the term from the interior node, then all terms on the sub-tree
- ** headed by node iChild are smaller than zTerm. No need to search
+ ** to the term from the interior node, then all terms on the sub-tree
+ ** headed by node iChild are smaller than zTerm. No need to search
** iChild.
**
** If the interior node term is larger than the specified term, then
@@ -144985,20 +168871,20 @@ static int fts3ScanInteriorNode(
** node for the range of leaf nodes that may contain the specified term
** or terms for which the specified term is a prefix.
**
-** If piLeaf is not NULL, then *piLeaf is set to the blockid of the
+** If piLeaf is not NULL, then *piLeaf is set to the blockid of the
** left-most leaf node in the tree that may contain the specified term.
** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the
** right-most leaf node that may contain a term for which the specified
** term is a prefix.
**
-** It is possible that the range of returned leaf nodes does not contain
-** the specified term or any terms for which it is a prefix. However, if the
+** It is possible that the range of returned leaf nodes does not contain
+** the specified term or any terms for which it is a prefix. However, if the
** segment does contain any such terms, they are stored within the identified
** range. Because this function only inspects interior segment nodes (and
** never loads leaf nodes into memory), it is not possible to be sure.
**
** If an error occurs, an error code other than SQLITE_OK is returned.
-*/
+*/
static int fts3SelectLeaf(
Fts3Table *p, /* Virtual table handle */
const char *zTerm, /* Term to select leaves for */
@@ -145015,7 +168901,7 @@ static int fts3SelectLeaf(
fts3GetVarint32(zNode, &iHeight);
rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
- assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
+ assert_fts3_nc( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
if( rc==SQLITE_OK && iHeight>1 ){
char *zBlob = 0; /* Blob read from %_segments table */
@@ -145035,7 +168921,13 @@ static int fts3SelectLeaf(
rc = sqlite3Fts3ReadBlock(p, piLeaf?*piLeaf:*piLeaf2, &zBlob, &nBlob, 0);
}
if( rc==SQLITE_OK ){
- rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
+ int iNewHeight = 0;
+ fts3GetVarint32(zBlob, &iNewHeight);
+ if( iNewHeight>=iHeight ){
+ rc = FTS_CORRUPT_VTAB;
+ }else{
+ rc = fts3SelectLeaf(p, zTerm, nTerm, zBlob, nBlob, piLeaf, piLeaf2);
+ }
}
sqlite3_free(zBlob);
}
@@ -145044,7 +168936,7 @@ static int fts3SelectLeaf(
}
/*
-** This function is used to create delta-encoded serialized lists of FTS3
+** This function is used to create delta-encoded serialized lists of FTS3
** varints. Each call to this function appends a single varint to a list.
*/
static void fts3PutDeltaVarint(
@@ -145052,17 +168944,17 @@ static void fts3PutDeltaVarint(
sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */
sqlite3_int64 iVal /* Write this value to the list */
){
- assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
+ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
*piPrev = iVal;
}
/*
-** When this function is called, *ppPoslist is assumed to point to the
+** When this function is called, *ppPoslist is assumed to point to the
** start of a position-list. After it returns, *ppPoslist points to the
** first byte after the position-list.
**
-** A position list is list of positions (delta encoded) and columns for
+** A position list is list of positions (delta encoded) and columns for
** a single document record of a doclist. So, in other words, this
** routine advances *ppPoslist so that it points to the next docid in
** the doclist, or to the first byte past the end of the doclist.
@@ -145075,12 +168967,12 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
char *pEnd = *ppPoslist;
char c = 0;
- /* The end of a position list is marked by a zero encoded as an FTS3
+ /* The end of a position list is marked by a zero encoded as an FTS3
** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by
** a byte with the 0x80 bit set, then it is not a varint 0, but the tail
** of some other, multi-byte, value.
**
- ** The following while-loop moves pEnd to point to the first byte that is not
+ ** The following while-loop moves pEnd to point to the first byte that is not
** immediately preceded by a byte with the 0x80 bit set. Then increments
** pEnd once more so that it points to the byte immediately following the
** last byte in the position-list.
@@ -145102,7 +168994,7 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
}
/*
-** When this function is called, *ppPoslist is assumed to point to the
+** When this function is called, *ppPoslist is assumed to point to the
** start of a column-list. After it returns, *ppPoslist points to the
** to the terminator (POS_COLUMN or POS_END) byte of the column-list.
**
@@ -145140,10 +169032,11 @@ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
}
/*
-** Value used to signify the end of an position-list. This is safe because
-** it is not possible to have a document with 2^31 terms.
+** Value used to signify the end of an position-list. This must be
+** as large or larger than any value that might appear on the
+** position-list, even a position list that has been corrupted.
*/
-#define POSITION_LIST_END 0x7fffffff
+#define POSITION_LIST_END LARGEST_INT64
/*
** This function is used to help parse position-lists. When this function is
@@ -145152,7 +169045,7 @@ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
** (in which case **pp will be a terminator bytes POS_END (0) or
** (1)).
**
-** If *pp points past the end of the current position-list, set *pi to
+** If *pp points past the end of the current position-list, set *pi to
** POSITION_LIST_END and return. Otherwise, read the next varint from *pp,
** increment the current value of *pi by the value read, and set *pp to
** point to the next value before returning.
@@ -145168,7 +169061,9 @@ static void fts3ReadNextPos(
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
){
if( (**pp)&0xFE ){
- fts3GetDeltaVarint(pp, pi);
+ int iVal;
+ *pp += fts3GetVarint32((*pp), &iVal);
+ *pi += iVal;
*pi -= 2;
}else{
*pi = POSITION_LIST_END;
@@ -145180,7 +169075,7 @@ static void fts3ReadNextPos(
** the value of iCol encoded as a varint to *pp. This will start a new
** column list.
**
-** Set *pp to point to the byte just after the last byte written before
+** Set *pp to point to the byte just after the last byte written before
** returning (do not modify it if iCol==0). Return the total number of bytes
** written (0 if iCol==0).
*/
@@ -145202,7 +169097,7 @@ static int fts3PutColNumber(char **pp, int iCol){
** updated appropriately. The caller is responsible for insuring
** that there is enough space in *pp to hold the complete output.
*/
-static void fts3PoslistMerge(
+static int fts3PoslistMerge(
char **pp, /* Output buffer */
char **pp1, /* Left input list */
char **pp2 /* Right input list */
@@ -145215,12 +169110,18 @@ static void fts3PoslistMerge(
int iCol1; /* The current column index in pp1 */
int iCol2; /* The current column index in pp2 */
- if( *p1==POS_COLUMN ) fts3GetVarint32(&p1[1], &iCol1);
- else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
+ if( *p1==POS_COLUMN ){
+ fts3GetVarint32(&p1[1], &iCol1);
+ if( iCol1==0 ) return FTS_CORRUPT_VTAB;
+ }
+ else if( *p1==POS_END ) iCol1 = 0x7fffffff;
else iCol1 = 0;
- if( *p2==POS_COLUMN ) fts3GetVarint32(&p2[1], &iCol2);
- else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
+ if( *p2==POS_COLUMN ){
+ fts3GetVarint32(&p2[1], &iCol2);
+ if( iCol2==0 ) return FTS_CORRUPT_VTAB;
+ }
+ else if( *p2==POS_END ) iCol2 = 0x7fffffff;
else iCol2 = 0;
if( iCol1==iCol2 ){
@@ -145233,7 +169134,7 @@ static void fts3PoslistMerge(
/* At this point, both p1 and p2 point to the start of column-lists
** for the same column (the column with index iCol1 and iCol2).
- ** A column-list is a list of non-negative delta-encoded varints, each
+ ** A column-list is a list of non-negative delta-encoded varints, each
** incremented by 2 before being stored. Each list is terminated by a
** POS_END (0) or POS_COLUMN (1). The following block merges the two lists
** and writes the results to buffer p. p is left pointing to the byte
@@ -145242,8 +169143,11 @@ static void fts3PoslistMerge(
*/
fts3GetDeltaVarint(&p1, &i1);
fts3GetDeltaVarint(&p2, &i2);
+ if( i1<2 || i2<2 ){
+ break;
+ }
do {
- fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2);
+ fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2);
iPrev -= 2;
if( i1==i2 ){
fts3ReadNextPos(&p1, &i1);
@@ -145267,6 +169171,7 @@ static void fts3PoslistMerge(
*pp = p;
*pp1 = p1 + 1;
*pp2 = p2 + 1;
+ return SQLITE_OK;
}
/*
@@ -145284,7 +169189,7 @@ static void fts3PoslistMerge(
** When this function returns, both *pp1 and *pp2 are left pointing to the
** byte following the 0x00 terminator of their respective position lists.
**
-** If isSaveLeft is 0, an entry is added to the output position list for
+** If isSaveLeft is 0, an entry is added to the output position list for
** each position in *pp2 for which there exists one or more positions in
** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e.
** when the *pp1 token appears before the *pp2 token, but not more than nToken
@@ -145309,12 +169214,12 @@ static int fts3PoslistPhraseMerge(
/* Never set both isSaveLeft and isExact for the same invocation. */
assert( isSaveLeft==0 || isExact==0 );
- assert( p!=0 && *p1!=0 && *p2!=0 );
- if( *p1==POS_COLUMN ){
+ assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
+ if( *p1==POS_COLUMN ){
p1++;
p1 += fts3GetVarint32(p1, &iCol1);
}
- if( *p2==POS_COLUMN ){
+ if( *p2==POS_COLUMN ){
p2++;
p2 += fts3GetVarint32(p2, &iCol2);
}
@@ -145331,14 +169236,13 @@ static int fts3PoslistPhraseMerge(
p += sqlite3Fts3PutVarint(p, iCol1);
}
- assert( *p1!=POS_END && *p1!=POS_COLUMN );
- assert( *p2!=POS_END && *p2!=POS_COLUMN );
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
+ if( iPos1<0 || iPos2<0 ) break;
while( 1 ){
- if( iPos2==iPos1+nToken
- || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
+ if( iPos2==iPos1+nToken
+ || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
){
sqlite3_int64 iSave;
iSave = isSaveLeft ? iPos1 : iPos2;
@@ -145373,8 +169277,8 @@ static int fts3PoslistPhraseMerge(
/* Advance pointer p1 or p2 (whichever corresponds to the smaller of
** iCol1 and iCol2) so that it points to either the 0x00 that marks the
- ** end of the position list, or the 0x01 that precedes the next
- ** column-number in the position list.
+ ** end of the position list, or the 0x01 that precedes the next
+ ** column-number in the position list.
*/
else if( iCol1<iCol2 ){
fts3ColumnlistCopy(0, &p1);
@@ -145403,14 +169307,14 @@ static int fts3PoslistPhraseMerge(
/*
** Merge two position-lists as required by the NEAR operator. The argument
-** position lists correspond to the left and right phrases of an expression
+** 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"
+** 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
@@ -145450,7 +169354,7 @@ static int fts3PoslistNearMerge(
return res;
}
-/*
+/*
** An instance of this function is used to merge together the (potentially
** large number of) doclists for each term that matches a prefix query.
** See function fts3TermSelectMerge() for details.
@@ -145471,7 +169375,7 @@ struct TermSelect {
** from *pp. *pp is then set to point 1 byte past the end of the read varint.
**
** If bDescIdx is false, the value read is added to *pVal before returning.
-** If it is true, the value read is subtracted from *pVal before this
+** If it is true, the value read is subtracted from *pVal before this
** function returns.
*/
static void fts3GetDeltaVarint3(
@@ -145483,12 +169387,12 @@ static void fts3GetDeltaVarint3(
if( *pp>=pEnd ){
*pp = 0;
}else{
- sqlite3_int64 iVal;
- *pp += sqlite3Fts3GetVarint(*pp, &iVal);
+ u64 iVal;
+ *pp += sqlite3Fts3GetVarintU(*pp, &iVal);
if( bDescIdx ){
- *pVal -= iVal;
+ *pVal = (i64)((u64)*pVal - iVal);
}else{
- *pVal += iVal;
+ *pVal = (i64)((u64)*pVal + iVal);
}
}
}
@@ -145499,9 +169403,9 @@ static void fts3GetDeltaVarint3(
** end of the value written.
**
** If *pbFirst is zero when this function is called, the value written to
-** the buffer is that of parameter iVal.
+** the buffer is that of parameter iVal.
**
-** If *pbFirst is non-zero when this function is called, then the value
+** If *pbFirst is non-zero when this function is called, then the value
** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal)
** (if bDescIdx is non-zero).
**
@@ -145515,14 +169419,16 @@ static void fts3PutDeltaVarint3(
int *pbFirst, /* IN/OUT: True after first int written */
sqlite3_int64 iVal /* Write this value to the list */
){
- sqlite3_int64 iWrite;
+ sqlite3_uint64 iWrite;
if( bDescIdx==0 || *pbFirst==0 ){
- iWrite = iVal - *piPrev;
+ assert_fts3_nc( *pbFirst==0 || iVal>=*piPrev );
+ iWrite = (u64)iVal - (u64)*piPrev;
}else{
- iWrite = *piPrev - iVal;
+ assert_fts3_nc( *piPrev>=iVal );
+ iWrite = (u64)*piPrev - (u64)iVal;
}
assert( *pbFirst || *piPrev==0 );
- assert( *pbFirst==0 || iWrite>0 );
+ assert_fts3_nc( *pbFirst==0 || iWrite>0 );
*pp += sqlite3Fts3PutVarint(*pp, iWrite);
*piPrev = iVal;
*pbFirst = 1;
@@ -145532,17 +169438,18 @@ static void fts3PutDeltaVarint3(
/*
** This macro is used by various functions that merge doclists. The two
** arguments are 64-bit docid values. If the value of the stack variable
-** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2).
+** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2).
** Otherwise, (i2-i1).
**
** Using this makes it easier to write code that can merge doclists that are
** sorted in either ascending or descending order.
*/
-#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))
+/* #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2)) */
+#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))
/*
** This function does an "OR" merge of two doclists (output contains all
-** positions contained in either argument doclist). If the docids in the
+** positions contained in either argument doclist). If the docids in the
** input doclists are sorted in ascending order, parameter bDescDoclist
** should be false. If they are sorted in ascending order, it should be
** passed a non-zero value.
@@ -145560,6 +169467,7 @@ static int fts3DoclistOrMerge(
char *a2, int n2, /* Second doclist */
char **paOut, int *pnOut /* OUT: Malloc'd doclist */
){
+ int rc = SQLITE_OK;
sqlite3_int64 i1 = 0;
sqlite3_int64 i2 = 0;
sqlite3_int64 iPrev = 0;
@@ -145581,12 +169489,12 @@ static int fts3DoclistOrMerge(
** current and previous docid (a positive number - since the list is in
** ascending order).
**
- ** The first docid written to the output is therefore encoded using the
+ ** The first docid written to the output is therefore encoded using the
** same number of bytes as it is in whichever of the input lists it is
- ** read from. And each subsequent docid read from the same input list
+ ** read from. And each subsequent docid read from the same input list
** consumes either the same or less bytes as it did in the input (since
** the difference between it and the previous value in the output must
- ** be a positive value less than or equal to the delta value read from
+ ** be a positive value less than or equal to the delta value read from
** the input list). The same argument applies to all but the first docid
** read from the 'other' list. And to the contents of all position lists
** that will be copied and merged from the input to the output.
@@ -145598,12 +169506,12 @@ static int fts3DoclistOrMerge(
**
** The space required to store the output is therefore the sum of the
** sizes of the two inputs, plus enough space for exactly one of the input
- ** docids to grow.
+ ** docids to grow.
**
- ** A symetric argument may be made if the doclists are in descending
+ ** A symetric argument may be made if the doclists are in descending
** order.
*/
- aOut = sqlite3_malloc(n1+n2+FTS3_VARINT_MAX-1);
+ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
if( !aOut ) return SQLITE_NOMEM;
p = aOut;
@@ -145614,7 +169522,8 @@ static int fts3DoclistOrMerge(
if( p2 && p1 && iDiff==0 ){
fts3PutDeltaVarint3(&p, bDescDoclist, &iPrev, &bFirstOut, i1);
- fts3PoslistMerge(&p, &p1, &p2);
+ rc = fts3PoslistMerge(&p, &p1, &p2);
+ if( rc ) break;
fts3GetDeltaVarint3(&p1, pEnd1, bDescDoclist, &i1);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}else if( !p2 || (p1 && iDiff<0) ){
@@ -145626,12 +169535,20 @@ static int fts3DoclistOrMerge(
fts3PoslistCopy(&p, &p2);
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
}
+
+ assert( (p-aOut)<=((p1?(p1-a1):n1)+(p2?(p2-a2):n2)+FTS3_VARINT_MAX-1) );
}
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(aOut);
+ p = aOut = 0;
+ }else{
+ assert( (p-aOut)<=n1+n2+FTS3_VARINT_MAX-1 );
+ memset(&aOut[(p-aOut)], 0, FTS3_BUFFER_PADDING);
+ }
*paOut = aOut;
*pnOut = (int)(p-aOut);
- assert( *pnOut<=n1+n2+FTS3_VARINT_MAX-1 );
- return SQLITE_OK;
+ return rc;
}
/*
@@ -145641,7 +169558,7 @@ static int fts3DoclistOrMerge(
** exactly nDist tokens before it.
**
** If the docids in the input doclists are sorted in ascending order,
-** parameter bDescDoclist should be false. If they are sorted in ascending
+** parameter bDescDoclist should be false. If they are sorted in ascending
** order, it should be passed a non-zero value.
**
** The right-hand input doclist is overwritten by this function.
@@ -145666,7 +169583,7 @@ static int fts3DoclistPhraseMerge(
assert( nDist>0 );
if( bDescDoclist ){
- aOut = sqlite3_malloc(*pnRight + FTS3_VARINT_MAX);
+ aOut = sqlite3_malloc64((sqlite3_int64)*pnRight + FTS3_VARINT_MAX);
if( aOut==0 ) return SQLITE_NOMEM;
}else{
aOut = aRight;
@@ -145737,7 +169654,7 @@ SQLITE_PRIVATE int sqlite3Fts3FirstFilter(
fts3ColumnlistCopy(0, &p);
}
- while( p<pEnd && *p==0x01 ){
+ while( p<pEnd ){
sqlite3_int64 iCol;
p++;
p += sqlite3Fts3GetVarint(p, &iCol);
@@ -145787,7 +169704,7 @@ static int fts3TermSelectFinishMerge(Fts3Table *p, TermSelect *pTS){
int nNew;
char *aNew;
- int rc = fts3DoclistOrMerge(p->bDescIdx,
+ int rc = fts3DoclistOrMerge(p->bDescIdx,
pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew
);
if( rc!=SQLITE_OK ){
@@ -145831,15 +169748,15 @@ static int fts3TermSelectMerge(
){
if( pTS->aaOutput[0]==0 ){
/* If this is the first term selected, copy the doclist to the output
- ** buffer using memcpy().
+ ** buffer using memcpy().
**
- ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
+ ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
** allocation. This is so as to ensure that the buffer is big enough
** to hold the current doclist AND'd with any other doclist. If the
** doclists are stored in order=ASC order, this padding would not be
** required (since the size of [doclistA AND doclistB] is always less
** than or equal to the size of [doclistA] in that case). But this is
- ** not true for order=DESC. For example, a doclist containing (1, -1)
+ ** not true for order=DESC. For example, a doclist containing (1, -1)
** may be smaller than (-1), as in the first example the -1 may be stored
** as a single-byte delta, whereas in the second it must be stored as a
** FTS3_VARINT_MAX byte varint.
@@ -145850,6 +169767,7 @@ static int fts3TermSelectMerge(
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
+ memset(&pTS->aaOutput[0][nDoclist], 0, FTS3_VARINT_MAX);
}else{
return SQLITE_NOMEM;
}
@@ -145868,7 +169786,7 @@ static int fts3TermSelectMerge(
char *aNew;
int nNew;
- int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge,
+ int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge,
pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew
);
if( rc!=SQLITE_OK ){
@@ -145879,7 +169797,7 @@ static int fts3TermSelectMerge(
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) ){
@@ -145896,13 +169814,13 @@ static int fts3TermSelectMerge(
** Append SegReader object pNew to the end of the pCsr->apSegment[] array.
*/
static int fts3SegReaderCursorAppend(
- Fts3MultiSegReader *pCsr,
+ 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);
+ sqlite3_int64 nByte = (pCsr->nSegment + 16)*sizeof(Fts3SegReader*);
+ apNew = (Fts3SegReader **)sqlite3_realloc64(pCsr->apSegment, nByte);
if( !apNew ){
sqlite3Fts3SegReaderFree(pNew);
return SQLITE_NOMEM;
@@ -145935,13 +169853,13 @@ static int fts3SegReaderCursor(
sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */
int rc2; /* Result of sqlite3_reset() */
- /* If iLevel is less than 0 and this is not a scan, include a seg-reader
+ /* 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
+ ** 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 ){
+ if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
Fts3SegReader *pSeg = 0;
rc = sqlite3Fts3SegReaderPending(p, iIndex, zTerm, nTerm, isPrefix||isScan, &pSeg);
if( rc==SQLITE_OK && pSeg ){
@@ -145966,16 +169884,16 @@ static int fts3SegReaderCursor(
/* 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( iStartBlock && zTerm && zRoot ){
sqlite3_int64 *pi = (isPrefix ? &iLeavesEndBlock : 0);
rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &iStartBlock, pi);
if( rc!=SQLITE_OK ) goto finished;
if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock;
}
-
- rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
+
+ rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
(isPrefix==0 && isScan==0),
- iStartBlock, iLeavesEndBlock,
+ iStartBlock, iLeavesEndBlock,
iEndBlock, zRoot, nRoot, &pSeg
);
if( rc!=SQLITE_OK ) goto finished;
@@ -145991,7 +169909,7 @@ static int fts3SegReaderCursor(
}
/*
-** Set up a cursor object for iterating through a full-text index or a
+** Set up a cursor object for iterating through a full-text index or a
** single level therein.
*/
SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
@@ -146007,7 +169925,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
){
assert( iIndex>=0 && iIndex<p->nIndex );
assert( iLevel==FTS3_SEGCURSOR_ALL
- || iLevel==FTS3_SEGCURSOR_PENDING
+ || iLevel==FTS3_SEGCURSOR_PENDING
|| iLevel>=0
);
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
@@ -146033,20 +169951,20 @@ static int fts3SegReaderCursorAddZero(
int nTerm, /* Number of bytes in zTerm */
Fts3MultiSegReader *pCsr /* Fts3MultiSegReader to modify */
){
- return fts3SegReaderCursor(p,
+ return fts3SegReaderCursor(p,
iLangid, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr
);
}
/*
** Open an Fts3MultiSegReader to scan the doclist for term zTerm/nTerm. Or,
-** if isPrefix is true, to scan the doclist for all terms for which
+** if isPrefix is true, to scan the doclist for all terms for which
** zTerm/nTerm is a prefix. If successful, return SQLITE_OK and write
** a pointer to the new Fts3MultiSegReader to *ppSegcsr. Otherwise, return
** an SQLite error code.
**
** It is the responsibility of the caller to free this object by eventually
-** passing it to fts3SegReaderCursorFree()
+** passing it to fts3SegReaderCursorFree()
**
** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
** Output parameter *ppSegcsr is set to 0 if an error occurs.
@@ -146071,7 +169989,7 @@ static int fts3TermSegReaderCursor(
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm ){
bFound = 1;
- rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr
);
pSegcsr->bLookup = 1;
@@ -146081,7 +169999,7 @@ static int fts3TermSegReaderCursor(
for(i=1; bFound==0 && i<p->nIndex; i++){
if( p->aIndex[i].nPrefix==nTerm+1 ){
bFound = 1;
- rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr
);
if( rc==SQLITE_OK ){
@@ -146094,7 +170012,7 @@ static int fts3TermSegReaderCursor(
}
if( bFound==0 ){
- rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr
);
pSegcsr->bLookup = !isPrefix;
@@ -146142,7 +170060,7 @@ static int fts3TermSelect(
rc = sqlite3Fts3SegReaderStart(p, pSegcsr, &filter);
while( SQLITE_OK==rc
- && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr))
+ && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr))
){
rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist);
}
@@ -146171,7 +170089,7 @@ static int fts3TermSelect(
**
** If the isPoslist argument is true, then it is assumed that the doclist
** contains a position-list following each docid. Otherwise, it is assumed
-** that the doclist is simply a list of docids stored as delta encoded
+** that the doclist is simply a list of docids stored as delta encoded
** varints.
*/
static int fts3DoclistCountDocids(char *aList, int nList){
@@ -146204,6 +170122,8 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
int rc;
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
if( pCsr->eSearch==FTS3_DOCID_SEARCH || pCsr->eSearch==FTS3_FULLSCAN_SEARCH ){
+ Fts3Table *pTab = (Fts3Table*)pCursor->pVtab;
+ pTab->bLock++;
if( SQLITE_ROW!=sqlite3_step(pCsr->pStmt) ){
pCsr->isEof = 1;
rc = sqlite3_reset(pCsr->pStmt);
@@ -146211,6 +170131,7 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0);
rc = SQLITE_OK;
}
+ pTab->bLock--;
}else{
rc = fts3EvalNext((Fts3Cursor *)pCursor);
}
@@ -146219,18 +170140,6 @@ static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
}
/*
-** The following are copied from sqliteInt.h.
-**
-** Constants for the largest and smallest possible 64-bit signed integers.
-** These macros are designed to work correctly on both 32-bit and 64-bit
-** compilers.
-*/
-#ifndef SQLITE_AMALGAMATION
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
-/*
** If the numeric type of argument pVal is "integer", then return it
** converted to a 64-bit signed integer. Otherwise, return a copy of
** the second parameter, iDefault.
@@ -146283,6 +170192,10 @@ static int fts3FilterMethod(
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(nVal);
+ if( p->bLock ){
+ return SQLITE_ERROR;
+ }
+
eSearch = (idxNum & 0x0000FFFF);
assert( eSearch>=0 && eSearch<=(FTS3_FULLTEXT_SEARCH+p->nColumn) );
assert( p->pSegments==0 );
@@ -146296,11 +170209,7 @@ static int fts3FilterMethod(
assert( iIdx==nVal );
/* In case the cursor has been used before, clear it now. */
- sqlite3_finalize(pCsr->pStmt);
- sqlite3_free(pCsr->aDoclist);
- sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
- sqlite3Fts3ExprFree(pCsr->pExpr);
- memset(&pCursor[1], 0, sizeof(Fts3Cursor)-sizeof(sqlite3_vtab_cursor));
+ fts3ClearCursor(pCsr);
/* Set the lower and upper bounds on docids to return */
pCsr->iMinDocid = fts3DocidRange(pDocidGe, SMALLEST_INT64);
@@ -146326,7 +170235,7 @@ static int fts3FilterMethod(
assert( p->base.zErrMsg==0 );
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
- p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
+ p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
&p->base.zErrMsg
);
if( rc!=SQLITE_OK ){
@@ -146353,18 +170262,22 @@ static int fts3FilterMethod(
(pCsr->bDesc ? "DESC" : "ASC")
);
}else{
- zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
+ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
);
}
if( zSql ){
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
+ p->bLock++;
+ rc = sqlite3_prepare_v3(
+ p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0
+ );
+ p->bLock--;
sqlite3_free(zSql);
}else{
rc = SQLITE_NOMEM;
}
}else if( eSearch==FTS3_DOCID_SEARCH ){
- rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
+ rc = fts3CursorSeekStmt(pCsr);
if( rc==SQLITE_OK ){
rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
}
@@ -146374,15 +170287,20 @@ static int fts3FilterMethod(
return fts3NextMethod(pCursor);
}
-/*
-** This is the xEof method of the virtual table. SQLite calls this
+/*
+** This is the xEof method of the virtual table. SQLite calls this
** routine to find out if it has reached the end of a result set.
*/
static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
- return ((Fts3Cursor *)pCursor)->isEof;
+ Fts3Cursor *pCsr = (Fts3Cursor*)pCursor;
+ if( pCsr->isEof ){
+ fts3ClearCursor(pCsr);
+ pCsr->isEof = 1;
+ }
+ return pCsr->isEof;
}
-/*
+/*
** This is the xRowid method. The SQLite core calls this routine to
** retrieve the rowid for the current row of the result set. fts3
** exposes %_content.docid as the rowid for the virtual table. The
@@ -146394,7 +170312,7 @@ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
return SQLITE_OK;
}
-/*
+/*
** This is the xColumn method, called by SQLite to request a value from
** the row that the supplied cursor currently points to.
**
@@ -146417,41 +170335,45 @@ static int fts3ColumnMethod(
/* The column value supplied by SQLite must be in range. */
assert( iCol>=0 && iCol<=p->nColumn+2 );
- if( iCol==p->nColumn+1 ){
- /* 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_result_int64(pCtx, 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(pCtx, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
- }else if( iCol==p->nColumn+2 && pCsr->pExpr ){
- sqlite3_result_int64(pCtx, pCsr->iLangid);
- }else{
- /* The requested column is either a user column (one that contains
- ** indexed data), or the language-id column. */
- rc = fts3CursorSeek(0, pCsr);
+ switch( iCol-p->nColumn ){
+ case 0:
+ /* The special 'table-name' column */
+ sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0);
+ break;
- if( rc==SQLITE_OK ){
- if( iCol==p->nColumn+2 ){
- int iLangid = 0;
- if( p->zLanguageid ){
- iLangid = sqlite3_column_int(pCsr->pStmt, p->nColumn+1);
- }
- sqlite3_result_int(pCtx, iLangid);
- }else if( sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
+ case 1:
+ /* The docid column */
+ sqlite3_result_int64(pCtx, pCsr->iPrevId);
+ break;
+
+ case 2:
+ if( pCsr->pExpr ){
+ sqlite3_result_int64(pCtx, pCsr->iLangid);
+ break;
+ }else if( p->zLanguageid==0 ){
+ sqlite3_result_int(pCtx, 0);
+ break;
+ }else{
+ iCol = p->nColumn;
+ /* no break */ deliberate_fall_through
+ }
+
+ default:
+ /* A user column. Or, if this is a full-table scan, possibly the
+ ** language-id column. Seek the cursor. */
+ rc = fts3CursorSeek(0, pCsr);
+ if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)-1>iCol ){
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
}
- }
+ break;
}
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
return rc;
}
-/*
-** This function is the implementation of the xUpdate callback used by
+/*
+** This function is the implementation of the xUpdate callback used by
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
** inserted, updated or deleted.
*/
@@ -146486,16 +170408,18 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
**
** Of course, updating the input segments also involves deleting a bunch
** of blocks from the segments table. But this is not considered overhead
- ** as it would also be required by a crisis-merge that used the same input
+ ** as it would also be required by a crisis-merge that used the same input
** segments.
*/
const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */
Fts3Table *p = (Fts3Table*)pVtab;
- int rc = sqlite3Fts3PendingTermsFlush(p);
+ int rc;
+ i64 iLastRowid = sqlite3_last_insert_rowid(p->db);
- if( rc==SQLITE_OK
- && p->nLeafAdd>(nMinMerge/16)
+ rc = sqlite3Fts3PendingTermsFlush(p);
+ if( rc==SQLITE_OK
+ && p->nLeafAdd>(nMinMerge/16)
&& p->nAutoincrmerge && p->nAutoincrmerge!=0xff
){
int mxLevel = 0; /* Maximum relative level value in db */
@@ -146508,6 +170432,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
if( A>(int)nMinMerge ) rc = sqlite3Fts3Incrmerge(p, A, p->nAutoincrmerge);
}
sqlite3Fts3SegmentsClose(p);
+ sqlite3_set_last_insert_rowid(p->db, iLastRowid);
return rc;
}
@@ -146520,17 +170445,11 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
static int fts3SetHasStat(Fts3Table *p){
int rc = SQLITE_OK;
if( p->bHasStat==2 ){
- const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
- char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
- if( zSql ){
- sqlite3_stmt *pStmt = 0;
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
- if( rc==SQLITE_OK ){
- int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
- rc = sqlite3_finalize(pStmt);
- if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
- }
- sqlite3_free(zSql);
+ char *zTbl = sqlite3_mprintf("%s_stat", p->zName);
+ if( zTbl ){
+ int res = sqlite3_table_column_metadata(p->db, p->zDb, zTbl, 0,0,0,0,0,0);
+ sqlite3_free(zTbl);
+ p->bHasStat = (res==SQLITE_OK);
}else{
rc = SQLITE_NOMEM;
}
@@ -146539,7 +170458,7 @@ static int fts3SetHasStat(Fts3Table *p){
}
/*
-** Implementation of xBegin() method.
+** Implementation of xBegin() method.
*/
static int fts3BeginMethod(sqlite3_vtab *pVtab){
Fts3Table *p = (Fts3Table*)pVtab;
@@ -146595,17 +170514,17 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){
/* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */
while( p>pStart && (c=*p--)==0 );
- /* Search backwards for a varint with value zero (the end of the previous
+ /* Search backwards for a varint with value zero (the end of the previous
** poslist). This is an 0x00 byte preceded by some byte that does not
** have the 0x80 bit set. */
- while( p>pStart && (*p & 0x80) | c ){
- c = *p--;
+ while( p>pStart && (*p & 0x80) | c ){
+ c = *p--;
}
assert( p==pStart || c==0 );
/* At this point p points to that preceding byte without the 0x80 bit
** set. So to find the start of the poslist, skip forward 2 bytes then
- ** over a varint.
+ ** over a varint.
**
** Normally. The other case is that p==pStart and the poslist to return
** is the first in the doclist. In this case do not skip forward 2 bytes.
@@ -146626,7 +170545,7 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){
** offsets() and optimize() SQL functions.
**
** If the value passed as the third argument is a blob of size
-** sizeof(Fts3Cursor*), then the blob contents are copied to the
+** sizeof(Fts3Cursor*), then the blob contents are copied to the
** output variable *ppCsr and SQLITE_OK is returned. Otherwise, an error
** message is written to context pContext and SQLITE_ERROR returned. The
** string passed via zFunc is used as part of the error message.
@@ -146637,18 +170556,17 @@ static int fts3FunctionArg(
sqlite3_value *pVal, /* argv[0] passed to function */
Fts3Cursor **ppCsr /* OUT: Store cursor handle here */
){
- Fts3Cursor *pRet;
- if( sqlite3_value_type(pVal)!=SQLITE_BLOB
- || sqlite3_value_bytes(pVal)!=sizeof(Fts3Cursor *)
- ){
+ int rc;
+ *ppCsr = (Fts3Cursor*)sqlite3_value_pointer(pVal, "fts3cursor");
+ if( (*ppCsr)!=0 ){
+ rc = SQLITE_OK;
+ }else{
char *zErr = sqlite3_mprintf("illegal first argument to %s", zFunc);
sqlite3_result_error(pContext, zErr, -1);
sqlite3_free(zErr);
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
}
- memcpy(&pRet, sqlite3_value_blob(pVal), sizeof(Fts3Cursor *));
- *ppCsr = pRet;
- return SQLITE_OK;
+ return rc;
}
/*
@@ -146672,7 +170590,7 @@ static void fts3SnippetFunc(
assert( nVal>=1 );
if( nVal>6 ){
- sqlite3_result_error(pContext,
+ sqlite3_result_error(pContext,
"wrong number of arguments to function snippet()", -1);
return;
}
@@ -146680,9 +170598,13 @@ static void fts3SnippetFunc(
switch( nVal ){
case 6: nToken = sqlite3_value_int(apVal[5]);
+ /* no break */ deliberate_fall_through
case 5: iCol = sqlite3_value_int(apVal[4]);
+ /* no break */ deliberate_fall_through
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
+ /* no break */ deliberate_fall_through
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
+ /* no break */ deliberate_fall_through
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
}
if( !zEllipsis || !zEnd || !zStart ){
@@ -146714,8 +170636,8 @@ static void fts3OffsetsFunc(
}
}
-/*
-** Implementation of the special optimize() function for FTS3. This
+/*
+** Implementation of the special optimize() function for FTS3. This
** function merges all segments in the database to a single segment.
** Example usage is:
**
@@ -146824,10 +170746,10 @@ static int fts3RenameMethod(
/* At this point it must be known if the %_stat table exists or not.
** So bHasStat may not be 2. */
rc = fts3SetHasStat(p);
-
+
/* As it happens, the pending terms table is always empty here. This is
- ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
- ** always opens a savepoint transaction. And the xSavepoint() method
+ ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
+ ** always opens a savepoint transaction. And the xSavepoint() method
** flushes the pending terms table. But leave the (no-op) call to
** PendingTermsFlush() in in case that changes.
*/
@@ -146875,7 +170797,7 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
int rc = SQLITE_OK;
UNUSED_PARAMETER(iSavepoint);
assert( ((Fts3Table *)pVtab)->inTransaction );
- assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint );
+ assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint );
TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
rc = fts3SyncMethod(pVtab);
@@ -146907,14 +170829,28 @@ 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;
}
+/*
+** Return true if zName is the extension on one of the shadow tables used
+** by this module.
+*/
+static int fts3ShadowName(const char *zName){
+ static const char *azName[] = {
+ "content", "docsize", "segdir", "segments", "stat",
+ };
+ unsigned int i;
+ for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
+ if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
+ }
+ return 0;
+}
+
static const sqlite3_module fts3Module = {
- /* iVersion */ 2,
+ /* iVersion */ 3,
/* xCreate */ fts3CreateMethod,
/* xConnect */ fts3ConnectMethod,
/* xBestIndex */ fts3BestIndexMethod,
@@ -146937,6 +170873,7 @@ static const sqlite3_module fts3Module = {
/* xSavepoint */ fts3SavepointMethod,
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
+ /* xShadowName */ fts3ShadowName,
};
/*
@@ -146951,7 +170888,7 @@ static void hashDestroy(void *p){
}
/*
-** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are
+** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are
** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c
** respectively. The following three forward declarations are for functions
** declared in these files used to retrieve the respective implementations.
@@ -147015,10 +170952,10 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
/* Load the built-in tokenizers into the hash table */
if( rc==SQLITE_OK ){
if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
- || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
+ || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
#ifndef SQLITE_DISABLE_FTS3_UNICODE
- || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
+ || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
#endif
#ifdef SQLITE_ENABLE_ICU
|| (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu))
@@ -147030,15 +170967,15 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
#ifdef SQLITE_TEST
if( rc==SQLITE_OK ){
- rc = sqlite3Fts3ExprInitTestInterface(db);
+ rc = sqlite3Fts3ExprInitTestInterface(db, pHash);
}
#endif
- /* Create the virtual table wrapper around the hash-table and overload
- ** the two scalar functions. If this is successful, register the
+ /* Create the virtual table wrapper around the hash-table and overload
+ ** the four scalar functions. If this is successful, register the
** module with sqlite.
*/
- if( SQLITE_OK==rc
+ if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
@@ -147072,7 +171009,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
/*
** Allocate an Fts3MultiSegReader for each token in the expression headed
-** by pExpr.
+** 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
@@ -147082,7 +171019,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
** 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
+** and merged incrementally. Otherwise, it has to be merged into an in-memory
** doclist and then traversed.
*/
static void fts3EvalAllocateReaders(
@@ -147099,7 +171036,7 @@ static void fts3EvalAllocateReaders(
*pnToken += nToken;
for(i=0; i<nToken; i++){
Fts3PhraseToken *pToken = &pExpr->pPhrase->aToken[i];
- int rc = fts3TermSegReaderCursor(pCsr,
+ int rc = fts3TermSegReaderCursor(pCsr,
pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr
);
if( rc!=SQLITE_OK ){
@@ -147217,6 +171154,7 @@ static int fts3EvalPhraseLoad(
return rc;
}
+#ifndef SQLITE_DISABLE_FTS4_DEFERRED
/*
** This function is called on each phrase after the position lists for
** any deferred tokens have been loaded into memory. It updates the phrases
@@ -147304,7 +171242,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
}
-
+
pPhrase->doclist.pList = aOut;
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
pPhrase->doclist.bFreeList = 1;
@@ -147320,6 +171258,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
return SQLITE_OK;
}
+#endif /* SQLITE_DISABLE_FTS4_DEFERRED */
/*
** Maximum number of tokens a phrase may have to be considered for the
@@ -147328,7 +171267,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
#define MAX_INCR_PHRASE_TOKENS 4
/*
-** This function is called for each Fts3Phrase in a full-text query
+** 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.
@@ -147346,14 +171285,14 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
/* Determine if doclists may be loaded from disk incrementally. This is
** possible if the bOptOk argument is true, the FTS doclists will be
- ** scanned in forward order, and the phrase consists of
+ ** scanned in forward order, and the phrase consists of
** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first"
** tokens or prefix tokens that cannot use a prefix-index. */
int bHaveIncr = 0;
- int bIncrOk = (bOptOk
- && pCsr->bDesc==pTab->bDescIdx
+ int bIncrOk = (bOptOk
+ && pCsr->bDesc==pTab->bDescIdx
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
-#ifdef SQLITE_TEST
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
&& pTab->bNoIncrDoclist==0
#endif
);
@@ -147387,12 +171326,12 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
}
/*
-** This function is used to iterate backwards (from the end to start)
+** This function is used to iterate backwards (from the end to start)
** through doclists. It is used by this module to iterate through phrase
** doclists in reverse and by the fts3_write.c module to iterate through
** pending-terms lists when writing to databases with "order=desc".
**
-** The doclist may be sorted in ascending (parameter bDescIdx==0) or
+** The doclist may be sorted in ascending (parameter bDescIdx==0) or
** descending (parameter bDescIdx==1) order of docid. Regardless, this
** function iterates from the end of the doclist to the beginning.
*/
@@ -147464,7 +171403,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistNext(
assert( nDoclist>0 );
assert( *pbEof==0 );
- assert( p || *piDocid==0 );
+ assert_fts3_nc( p || *piDocid==0 );
assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
if( p==0 ){
@@ -147472,7 +171411,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistNext(
p += sqlite3Fts3GetVarint(p, piDocid);
}else{
fts3PoslistCopy(0, &p);
- while( p<&aDoclist[nDoclist] && *p==0 ) p++;
+ while( p<&aDoclist[nDoclist] && *p==0 ) p++;
if( p>=&aDoclist[nDoclist] ){
*pbEof = 1;
}else{
@@ -147495,15 +171434,16 @@ static void fts3EvalDlPhraseNext(
u8 *pbEof
){
char *pIter; /* Used to iterate through aAll */
- char *pEnd = &pDL->aAll[pDL->nAll]; /* 1 byte past end of aAll */
-
+ char *pEnd; /* 1 byte past end of aAll */
+
if( pDL->pNextDocid ){
pIter = pDL->pNextDocid;
+ assert( pDL->aAll!=0 || pIter==0 );
}else{
pIter = pDL->aAll;
}
- if( pIter>=pEnd ){
+ if( pIter==0 || pIter>=(pEnd = pDL->aAll + pDL->nAll) ){
/* We have already reached the end of this doclist. EOF. */
*pbEof = 1;
}else{
@@ -147544,12 +171484,12 @@ struct TokenDoclist {
};
/*
-** Token pToken is an incrementally loaded token that is part of a
+** Token pToken is an incrementally loaded token that is part of a
** multi-token phrase. Advance it to the next matching document in the
** database and populate output variable *p with the details of the new
** entry. Or, if the iterator has reached EOF, set *pbEof to true.
**
-** If an error occurs, return an SQLite error code. Otherwise, return
+** If an error occurs, return an SQLite error code. Otherwise, return
** SQLITE_OK.
*/
static int incrPhraseTokenNext(
@@ -147590,18 +171530,18 @@ static int incrPhraseTokenNext(
/*
** The phrase iterator passed as the second argument:
**
-** * features at least one token that uses an incremental doclist, and
+** * features at least one token that uses an incremental doclist, and
**
** * does not contain any deferred tokens.
**
** Advance it to the next matching documnent in the database and populate
-** the Fts3Doclist.pList and nList fields.
+** the Fts3Doclist.pList and nList fields.
**
** 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.
**
-** If an error occurs, return an SQLite error code. Otherwise, return
+** If an error occurs, return an SQLite error code. Otherwise, return
** SQLITE_OK.
*/
static int fts3EvalIncrPhraseNext(
@@ -147618,8 +171558,8 @@ static int fts3EvalIncrPhraseNext(
** one incremental token. In which case the bIncr flag is set. */
assert( p->bIncr==1 );
- if( p->nToken==1 && p->bIncr ){
- rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
+ if( p->nToken==1 ){
+ rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
&pDL->iDocid, &pDL->pList, &pDL->nList
);
if( pDL->pList==0 ) bEof = 1;
@@ -147649,8 +171589,8 @@ static int fts3EvalIncrPhraseNext(
/* Keep advancing iterators until they all point to the same document */
for(i=0; i<p->nToken; i++){
- while( rc==SQLITE_OK && bEof==0
- && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
+ while( rc==SQLITE_OK && bEof==0
+ && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
){
rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
if( DOCID_CMP(a[i].iDocid, iMax)>0 ){
@@ -147664,9 +171604,10 @@ static int fts3EvalIncrPhraseNext(
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
- char *aDoclist = sqlite3_malloc(nByte+1);
+ char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
+ memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
for(i=0; i<(p->nToken-1); i++){
if( a[i].bIgnore==0 ){
@@ -147696,8 +171637,8 @@ static int fts3EvalIncrPhraseNext(
}
/*
-** Attempt to move the phrase iterator to point to the next matching docid.
-** If an error occurs, return an SQLite error code. Otherwise, return
+** 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
@@ -147716,7 +171657,7 @@ static int fts3EvalPhraseNext(
if( p->bIncr ){
rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof);
}else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
- sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
+ sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
&pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
);
pDL->pList = pDL->pNextDocid;
@@ -147776,7 +171717,7 @@ static void fts3EvalStartReaders(
** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong
** to phrases that are connected only by AND and NEAR operators (not OR or
** NOT). When determining tokens to defer, each AND/NEAR cluster is considered
-** separately. The root of a tokens AND/NEAR cluster is stored in
+** separately. The root of a tokens AND/NEAR cluster is stored in
** Fts3TokenAndCost.pRoot.
*/
typedef struct Fts3TokenAndCost Fts3TokenAndCost;
@@ -147844,26 +171785,26 @@ static void fts3EvalTokenCosts(
** write this value to *pnPage and return SQLITE_OK. Otherwise, return
** an SQLite error code.
**
-** The average document size in pages is calculated by first calculating
+** The average document size in pages is calculated by first calculating
** determining the average size in bytes, B. If B is less than the amount
** of data that will fit on a single leaf page of an intkey table in
** this database, then the average docsize is 1. Otherwise, it is 1 plus
** the number of overflow pages consumed by a record B bytes in size.
*/
static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
+ int rc = SQLITE_OK;
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
+ ** 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
+ ** 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;
@@ -147874,12 +171815,13 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
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);
+ testcase( a==0 ); /* If %_stat.value set to X'' */
+ if( a ){
+ pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
+ a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc);
+ while( a<pEnd ){
+ a += sqlite3Fts3GetVarintBounded(a, pEnd, &nByte);
+ }
}
if( nDoc==0 || nByte==0 ){
sqlite3_reset(pStmt);
@@ -147888,21 +171830,20 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
pCsr->nDoc = nDoc;
pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
- assert( pCsr->nRowAvg>0 );
+ assert( pCsr->nRowAvg>0 );
rc = sqlite3_reset(pStmt);
- if( rc!=SQLITE_OK ) return rc;
}
*pnPage = pCsr->nRowAvg;
- return SQLITE_OK;
+ return rc;
}
/*
-** This function is called to select the tokens (if any) that will be
+** This function is called to select the tokens (if any) that will be
** deferred. The array aTC[] has already been populated when this is
** called.
**
-** This function is called once for each AND/NEAR cluster in the
+** This function is called once for each AND/NEAR cluster in the
** expression. Each invocation determines which tokens to defer within
** the cluster with root node pRoot. See comments above the definition
** of struct Fts3TokenAndCost for more details.
@@ -147952,8 +171893,8 @@ static int fts3EvalSelectDeferred(
assert( rc!=SQLITE_OK || nDocSize>0 );
- /* Iterate through all tokens in this AND/NEAR cluster, in ascending order
- ** of the number of overflow pages that will be loaded by the pager layer
+ /* Iterate through all tokens in this AND/NEAR cluster, in ascending order
+ ** of the number of overflow pages that will be loaded by the pager layer
** to retrieve the entire doclist for the token from the full-text index.
** Load the doclists for tokens that are either:
**
@@ -147964,7 +171905,7 @@ static int fts3EvalSelectDeferred(
**
** After each token doclist is loaded, merge it with the others from the
** same phrase and count the number of documents that the merged doclist
- ** contains. Set variable "nMinEst" to the smallest number of documents in
+ ** contains. Set variable "nMinEst" to the smallest number of documents in
** any phrase doclist for which 1 or more token doclists have been loaded.
** Let nOther be the number of other phrases for which it is certain that
** one or more tokens will not be deferred.
@@ -147980,8 +171921,8 @@ static int fts3EvalSelectDeferred(
/* Set pTC to point to the cheapest remaining token. */
for(iTC=0; iTC<nTC; iTC++){
- if( aTC[iTC].pToken && aTC[iTC].pRoot==pRoot
- && (!pTC || aTC[iTC].nOvfl<pTC->nOvfl)
+ if( aTC[iTC].pToken && aTC[iTC].pRoot==pRoot
+ && (!pTC || aTC[iTC].nOvfl<pTC->nOvfl)
){
pTC = &aTC[iTC];
}
@@ -147990,7 +171931,7 @@ static int fts3EvalSelectDeferred(
if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){
/* The number of overflow pages to load for this (and therefore all
- ** subsequent) tokens is greater than the estimated number of pages
+ ** subsequent) tokens is greater than the estimated number of pages
** that will be loaded if all subsequent tokens are deferred.
*/
Fts3PhraseToken *pToken = pTC->pToken;
@@ -147999,7 +171940,7 @@ static int fts3EvalSelectDeferred(
pToken->pSegcsr = 0;
}else{
/* Set nLoad4 to the value of (4^nOther) for the next iteration of the
- ** for-loop. Except, limit the value to 2^24 to prevent it from
+ ** for-loop. Except, limit the value to 2^24 to prevent it from
** overflowing the 32-bit integer it is stored in. */
if( ii<12 ) nLoad4 = nLoad4*4;
@@ -148058,7 +171999,7 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
Fts3TokenAndCost *aTC;
Fts3Expr **apOr;
- aTC = (Fts3TokenAndCost *)sqlite3_malloc(
+ aTC = (Fts3TokenAndCost *)sqlite3_malloc64(
sizeof(Fts3TokenAndCost) * nToken
+ sizeof(Fts3Expr *) * nOr * 2
);
@@ -148112,7 +172053,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
**
** Parameter nNear is passed the NEAR distance of the expression (5 in
** the example above). When this function is called, *paPoslist points to
-** the position list, and *pnToken is the number of phrase tokens in, the
+** the position list, and *pnToken is the number of phrase tokens in the
** phrase on the other side of the NEAR operator to pPhrase. For example,
** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to
** the position list associated with phrase "abc".
@@ -148121,7 +172062,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
** close to a position in the *paPoslist position list are removed. If this
** leaves 0 positions, zero is returned. Otherwise, non-zero.
**
-** Before returning, *paPoslist is set to point to the position lsit
+** Before returning, *paPoslist is set to point to the position lsit
** associated with pPhrase. And *pnToken is set to the number of tokens in
** pPhrase.
*/
@@ -148135,8 +172076,8 @@ static int fts3EvalNearTrim(
int nParam1 = nNear + pPhrase->nToken;
int nParam2 = nNear + *pnToken;
int nNew;
- char *p2;
- char *pOut;
+ char *p2;
+ char *pOut;
int res;
assert( pPhrase->doclist.pList );
@@ -148147,10 +172088,12 @@ static int fts3EvalNearTrim(
);
if( res ){
nNew = (int)(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;
+ if( nNew>=0 ){
+ 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;
}
@@ -148183,19 +172126,19 @@ static int fts3EvalNearTrim(
**
** 1. Deferred tokens are not taken into account. If a phrase consists
** entirely of deferred tokens, it is assumed to match every row in
-** the db. In this case the position-list is not populated at all.
+** the db. In this case the position-list is not populated at all.
**
** Or, if a phrase contains one or more deferred tokens and one or
-** more non-deferred tokens, then the expression is advanced to the
+** more non-deferred tokens, then the expression is advanced to the
** next possible match, considering only non-deferred tokens. In other
** words, if the phrase is "A B C", and "B" is deferred, the expression
-** is advanced to the next row that contains an instance of "A * C",
+** is advanced to the next row that contains an instance of "A * C",
** where "*" may match any single token. The position list in this case
** is populated as for "A * C" before returning.
**
-** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is
+** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is
** advanced to point to the next row that matches "x AND y".
-**
+**
** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is
** really a match, taking into account deferred tokens and NEAR operators.
*/
@@ -148244,7 +172187,8 @@ static void fts3EvalNextRow(
pExpr->iDocid = pLeft->iDocid;
pExpr->bEof = (pLeft->bEof || pRight->bEof);
if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
- if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
+ assert( pRight->eType==FTSQUERY_PHRASE );
+ if( pRight->pPhrase->doclist.aAll ){
Fts3Doclist *pDl = &pRight->pPhrase->doclist;
while( *pRc==SQLITE_OK && pRight->bEof==0 ){
memset(pDl->pList, 0, pDl->nList);
@@ -148258,11 +172202,12 @@ static void fts3EvalNextRow(
fts3EvalNextRow(pCsr, pLeft, pRc);
}
}
+ pRight->bEof = pLeft->bEof = 1;
}
}
break;
}
-
+
case FTSQUERY_OR: {
Fts3Expr *pLeft = pExpr->pLeft;
Fts3Expr *pRight = pExpr->pRight;
@@ -148273,7 +172218,7 @@ static void fts3EvalNextRow(
if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
fts3EvalNextRow(pCsr, pLeft, pRc);
- }else if( pLeft->bEof || (pRight->bEof==0 && iCmp>0) ){
+ }else if( pLeft->bEof || iCmp>0 ){
fts3EvalNextRow(pCsr, pRight, pRc);
}else{
fts3EvalNextRow(pCsr, pLeft, pRc);
@@ -148302,9 +172247,9 @@ static void fts3EvalNextRow(
fts3EvalNextRow(pCsr, pLeft, pRc);
if( pLeft->bEof==0 ){
- while( !*pRc
- && !pRight->bEof
- && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0
+ while( !*pRc
+ && !pRight->bEof
+ && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0
){
fts3EvalNextRow(pCsr, pRight, pRc);
}
@@ -148329,14 +172274,14 @@ static void fts3EvalNextRow(
** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR
** cluster, then this function returns 1 immediately.
**
-** Otherwise, it checks if the current row really does match the NEAR
-** expression, using the data currently stored in the position lists
-** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression.
+** Otherwise, it checks if the current row really does match the NEAR
+** expression, using the data currently stored in the position lists
+** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression.
**
** If the current row is a match, the position list associated with each
** phrase in the NEAR expression is edited in place to contain only those
** phrase instances sufficiently close to their peers to satisfy all NEAR
-** constraints. In this case it returns 1. If the NEAR expression does not
+** constraints. In this case it returns 1. If the NEAR expression does not
** match the current row, 0 is returned. The position lists may or may not
** be edited if 0 is returned.
*/
@@ -148359,57 +172304,53 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
** | |
** "w" "x"
**
- ** The right-hand child of a NEAR node is always a phrase. The
+ ** 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 - it's the way the parser in fts3_expr.c works.
*/
- if( *pRc==SQLITE_OK
- && pExpr->eType==FTSQUERY_NEAR
- && pExpr->bEof==0
+ if( *pRc==SQLITE_OK
+ && pExpr->eType==FTSQUERY_NEAR
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
){
- Fts3Expr *p;
- int nTmp = 0; /* Bytes of temp space */
+ Fts3Expr *p;
+ sqlite3_int64 nTmp = 0; /* Bytes of temp space */
char *aTmp; /* Temp space for PoslistNearMerge() */
/* Allocate temporary working space. */
for(p=pExpr; p->pLeft; p=p->pLeft){
+ assert( p->pRight->pPhrase->doclist.nList>0 );
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- if( nTmp==0 ){
+ aTmp = sqlite3_malloc64(nTmp*2);
+ if( !aTmp ){
+ *pRc = SQLITE_NOMEM;
res = 0;
}else{
- 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 = fts3EvalNearTrim(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;
- Fts3Phrase *pPhrase;
- assert( p->pParent && p->pParent->pLeft==p );
- nNear = p->pParent->nNear;
- pPhrase = (
- p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
- );
- res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
- }
+ 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 = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
}
- sqlite3_free(aTmp);
+ aPoslist = pExpr->pRight->pPhrase->doclist.pList;
+ nToken = pExpr->pRight->pPhrase->nToken;
+ for(p=pExpr->pLeft; p && res; p=p->pLeft){
+ int nNear;
+ Fts3Phrase *pPhrase;
+ assert( p->pParent && p->pParent->pLeft==p );
+ nNear = p->pParent->nNear;
+ pPhrase = (
+ p->eType==FTSQUERY_NEAR ? p->pRight->pPhrase : p->pPhrase
+ );
+ res = fts3EvalNearTrim(nNear, aTmp, &aPoslist, &nToken, pPhrase);
+ }
}
+
+ sqlite3_free(aTmp);
}
return res;
@@ -148418,12 +172359,12 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
/*
** This function is a helper function for sqlite3Fts3EvalTestDeferred().
** Assuming no error occurs or has occurred, It returns non-zero if the
-** expression passed as the second argument matches the row that pCsr
+** expression passed as the second argument matches the row that pCsr
** currently points to, or zero if it does not.
**
** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
-** If an error occurs during execution of this function, *pRc is set to
-** the appropriate SQLite error code. In this case the returned value is
+** If an error occurs during execution of this function, *pRc is set to
+** the appropriate SQLite error code. In this case the returned value is
** undefined.
*/
static int fts3EvalTestExpr(
@@ -148442,10 +172383,10 @@ static int fts3EvalTestExpr(
&& fts3EvalNearTest(pExpr, pRc)
);
- /* If the NEAR expression does not match any rows, zero the doclist for
+ /* 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.
+ ** 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)'
@@ -148457,8 +172398,8 @@ static int fts3EvalTestExpr(
** 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
+ if( bHit==0
+ && pExpr->eType==FTSQUERY_NEAR
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
){
Fts3Expr *p;
@@ -148490,7 +172431,7 @@ static int fts3EvalTestExpr(
default: {
#ifndef SQLITE_DISABLE_FTS4_DEFERRED
- if( pCsr->pDeferred
+ if( pCsr->pDeferred
&& (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred)
){
Fts3Phrase *pPhrase = pExpr->pPhrase;
@@ -148504,7 +172445,10 @@ static int fts3EvalTestExpr(
}else
#endif
{
- bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
+ bHit = (
+ pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId
+ && pExpr->pPhrase->doclist.nList>0
+ );
}
break;
}
@@ -148546,7 +172490,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){
** memory and scan it to determine the position list for each deferred
** token. Then, see if this row is really a match, considering deferred
** tokens and NEAR operators (neither of which were taken into account
- ** earlier, by fts3EvalNextRow()).
+ ** earlier, by fts3EvalNextRow()).
*/
if( pCsr->pDeferred ){
rc = fts3CursorSeek(0, pCsr);
@@ -148601,7 +172545,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){
/*
** Restart interation for expression pExpr so that the next call to
-** fts3EvalNext() visits the first row. Do not allow incremental
+** fts3EvalNext() 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
@@ -148644,22 +172588,21 @@ static void fts3EvalRestart(
}
/*
-** After allocating the Fts3Expr.aMI[] array for each phrase in the
+** 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
+** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase
** expression nodes.
*/
-static void fts3EvalUpdateCounts(Fts3Expr *pExpr){
+static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
if( pExpr ){
Fts3Phrase *pPhrase = pExpr->pPhrase;
if( pPhrase && pPhrase->doclist.pList ){
int iCol = 0;
char *p = pPhrase->doclist.pList;
- assert( *p );
- while( 1 ){
+ do{
u8 c = 0;
int iCnt = 0;
while( 0xFE & (*p | c) ){
@@ -148675,11 +172618,11 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr){
if( *p==0x00 ) break;
p++;
p += fts3GetVarint32(p, &iCol);
- }
+ }while( iCol<nCol );
}
- fts3EvalUpdateCounts(pExpr->pLeft);
- fts3EvalUpdateCounts(pExpr->pRight);
+ fts3EvalUpdateCounts(pExpr->pLeft, nCol);
+ fts3EvalUpdateCounts(pExpr->pRight, nCol);
}
}
@@ -148723,7 +172666,7 @@ static int fts3EvalGatherStats(
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));
+ pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
if( !pE->aMI ) return SQLITE_NOMEM;
memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
}
@@ -148743,13 +172686,13 @@ static int fts3EvalGatherStats(
pCsr->isRequireSeek = 1;
pCsr->isMatchinfoNeeded = 1;
pCsr->iPrevId = pRoot->iDocid;
- }while( pCsr->isEof==0
- && pRoot->eType==FTSQUERY_NEAR
- && sqlite3Fts3EvalTestDeferred(pCsr, &rc)
+ }while( pCsr->isEof==0
+ && pRoot->eType==FTSQUERY_NEAR
+ && sqlite3Fts3EvalTestDeferred(pCsr, &rc)
);
if( rc==SQLITE_OK && pCsr->isEof==0 ){
- fts3EvalUpdateCounts(pRoot);
+ fts3EvalUpdateCounts(pRoot, pTab->nColumn);
}
}
@@ -148760,7 +172703,7 @@ static int fts3EvalGatherStats(
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
+ ** 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 );
@@ -148768,7 +172711,8 @@ static int fts3EvalGatherStats(
fts3EvalRestart(pCsr, pRoot, &rc);
do {
fts3EvalNextRow(pCsr, pRoot, &rc);
- assert( pRoot->bEof==0 );
+ assert_fts3_nc( pRoot->bEof==0 );
+ if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
}
}
@@ -148776,10 +172720,10 @@ static int fts3EvalGatherStats(
}
/*
-** This function is used by the matchinfo() module to query a phrase
+** 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
+** 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
@@ -148793,12 +172737,12 @@ static int fts3EvalGatherStats(
**
** Caveats:
**
-** * If a phrase consists entirely of deferred tokens, then all output
+** * 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
+** 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
+** * 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.
**
@@ -148836,14 +172780,14 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(
/*
** The expression pExpr passed as the second argument to this function
-** must be of type FTSQUERY_PHRASE.
+** 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.
+** of the current row.
**
-** More specifically, the returned buffer contains 1 varint for each
-** occurrence of the phrase in the column, stored using the normal (delta+2)
+** More specifically, the returned buffer contains 1 varint for each
+** occurrence 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:
@@ -148865,7 +172809,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
int iThis;
sqlite3_int64 iDocid;
- /* If this phrase is applies specifically to some column other than
+ /* If this phrase is applies specifically to some column other than
** column iCol, return a NULL pointer. */
*ppOut = 0;
assert( iCol>=0 && iCol<pTab->nColumn );
@@ -148884,8 +172828,8 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
int bMatch;
- /* Check if this phrase descends from an OR expression node. If not,
- ** return NULL. Otherwise, the entry that corresponds to docid
+ /* Check if this phrase descends from an OR expression node. If not,
+ ** return NULL. Otherwise, the entry that corresponds to docid
** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the
** tree that the node is part of has been marked as EOF, but the node
** itself is not EOF, then it may point to an earlier entry. */
@@ -148933,7 +172877,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
(pIter >= (pPh->doclist.aAll + pPh->doclist.nAll));
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
sqlite3Fts3DoclistNext(
- bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
+ bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
&pIter, &iDocid, &bEof
);
}
@@ -148942,7 +172886,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
int dummy;
sqlite3Fts3DoclistPrev(
- bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
+ bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
&pIter, &iDocid, &dummy, &bEof
);
}
@@ -149018,7 +172962,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
__declspec(dllexport)
#endif
SQLITE_API int sqlite3_fts3_init(
- sqlite3 *db,
+ sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
@@ -149099,7 +173043,7 @@ static int fts3auxConnectMethod(
char const *zFts3; /* Name of fts3 table */
int nDb; /* Result of strlen(zDb) */
int nFts3; /* Result of strlen(zFts3) */
- int nByte; /* Bytes of space to allocate here */
+ sqlite3_int64 nByte; /* Bytes of space to allocate here */
int rc; /* value returned by declare_vtab() */
Fts3auxTable *p; /* Virtual table object to return */
@@ -149112,11 +173056,11 @@ static int fts3auxConnectMethod(
*/
if( argc!=4 && argc!=5 ) goto bad_args;
- zDb = argv[1];
+ zDb = argv[1];
nDb = (int)strlen(zDb);
if( argc==5 ){
if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){
- zDb = argv[3];
+ zDb = argv[3];
nDb = (int)strlen(zDb);
zFts3 = argv[4];
}else{
@@ -149131,7 +173075,7 @@ static int fts3auxConnectMethod(
if( rc!=SQLITE_OK ) return rc;
nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
- p = (Fts3auxTable *)sqlite3_malloc(nByte);
+ p = (Fts3auxTable *)sqlite3_malloc64(nByte);
if( !p ) return SQLITE_NOMEM;
memset(p, 0, nByte);
@@ -149180,7 +173124,7 @@ static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){
** xBestIndex - Analyze a WHERE and ORDER BY clause.
*/
static int fts3auxBestIndexMethod(
- sqlite3_vtab *pVTab,
+ sqlite3_vtab *pVTab,
sqlite3_index_info *pInfo
){
int i;
@@ -149193,14 +173137,14 @@ static int fts3auxBestIndexMethod(
UNUSED_PARAMETER(pVTab);
/* This vtab delivers always results in "ORDER BY term ASC" order. */
- if( pInfo->nOrderBy==1
- && pInfo->aOrderBy[0].iColumn==0
+ if( pInfo->nOrderBy==1
+ && pInfo->aOrderBy[0].iColumn==0
&& pInfo->aOrderBy[0].desc==0
){
pInfo->orderByConsumed = 1;
}
- /* Search for equality and range constraints on the "term" column.
+ /* Search for equality and range constraints on the "term" column.
** And equality constraints on the hidden "languageid" column. */
for(i=0; i<pInfo->nConstraint; i++){
if( pInfo->aConstraint[i].usable ){
@@ -149281,11 +173225,11 @@ static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){
static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){
if( nSize>pCsr->nStat ){
struct Fts3auxColstats *aNew;
- aNew = (struct Fts3auxColstats *)sqlite3_realloc(pCsr->aStat,
+ aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat,
sizeof(struct Fts3auxColstats) * nSize
);
if( aNew==0 ) return SQLITE_NOMEM;
- memset(&aNew[pCsr->nStat], 0,
+ memset(&aNew[pCsr->nStat], 0,
sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat)
);
pCsr->aStat = aNew;
@@ -149345,8 +173289,8 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
/* State 1. In this state we are expecting either a 1, indicating
** that the following integer will be a column number, or the
- ** start of a position list for column 0.
- **
+ ** start of a position list for column 0.
+ **
** The only difference between state 1 and state 2 is that if the
** integer encountered in state 1 is not 0 or 1, then we need to
** increment the column 0 "nDoc" count for this term.
@@ -149449,17 +173393,17 @@ static int fts3auxFilterMethod(
assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) );
if( zStr ){
pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr);
- pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]);
if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM;
+ pCsr->filter.nTerm = (int)strlen(pCsr->filter.zTerm);
}
}
if( iLe>=0 ){
pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe]));
- pCsr->nStop = sqlite3_value_bytes(apVal[iLe]);
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
+ pCsr->nStop = (int)strlen(pCsr->zStop);
}
-
+
if( iLangid>=0 ){
iLangVal = sqlite3_value_int(apVal[iLangid]);
@@ -149572,7 +173516,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
int rc; /* Return code */
@@ -149597,15 +173542,15 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
******************************************************************************
**
** This module contains code that implements a parser for fts3 query strings
-** (the right-hand argument to the MATCH operator). Because the supported
+** (the right-hand argument to the MATCH operator). Because the supported
** syntax is relatively simple, the whole tokenizer/parser system is
-** hand-coded.
+** hand-coded.
*/
/* #include "fts3Int.h" */
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
/*
-** By default, this module parses the legacy syntax that has been
+** By default, this module parses the legacy syntax that has been
** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS
** is defined, then it uses the new syntax. The differences between
** the new and the old syntaxes are:
@@ -149614,7 +173559,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
**
** b) The new syntax supports the AND and NOT operators. The old does not.
**
-** c) The old syntax supports the "-" token qualifier. This is not
+** c) The old syntax supports the "-" token qualifier. This is not
** supported by the new syntax (it is replaced by the NOT operator).
**
** d) When using the old syntax, the OR operator has a greater precedence
@@ -149623,7 +173568,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
**
** If compiled with SQLITE_TEST defined, then this module exports the
** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable
-** to zero causes the module to use the old syntax. If it is set to
+** to zero causes the module to use the old syntax. If it is set to
** non-zero the new syntax is activated. This is so both syntaxes can
** be tested using a single build of testfixture.
**
@@ -149652,7 +173597,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_fts3_enable_parentheses = 0;
#else
-# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
+# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
# define sqlite3_fts3_enable_parentheses 1
# else
# define sqlite3_fts3_enable_parentheses 0
@@ -149670,7 +173615,7 @@ SQLITE_API int sqlite3_fts3_enable_parentheses = 0;
/*
** isNot:
** This variable is used by function getNextNode(). When getNextNode() is
-** called, it sets ParseContext.isNot to true if the 'next node' is a
+** 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.
@@ -149689,7 +173634,7 @@ struct ParseContext {
};
/*
-** This function is equivalent to the standard isspace() function.
+** This function is equivalent to the standard isspace() function.
**
** The standard isspace() can be awkward to use safely, because although it
** is defined to accept an argument of type int, its behavior when passed
@@ -149705,11 +173650,11 @@ static int fts3isspace(char c){
/*
** Allocate nByte bytes of memory using sqlite3_malloc(). If successful,
-** zero the memory before returning a pointer to it. If unsuccessful,
+** zero the memory before returning a pointer to it. If unsuccessful,
** return NULL.
*/
-static void *fts3MallocZero(int nByte){
- void *pRet = sqlite3_malloc(nByte);
+static void *fts3MallocZero(sqlite3_int64 nByte){
+ void *pRet = sqlite3_malloc64(nByte);
if( pRet ) memset(pRet, 0, nByte);
return pRet;
}
@@ -149753,7 +173698,7 @@ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
** single token and set *ppExpr to point to it. If the end of the buffer is
** reached before a token is found, set *ppExpr to zero. It is the
-** responsibility of the caller to eventually deallocate the allocated
+** responsibility of the caller to eventually deallocate the allocated
** Fts3Expr structure (if any) by passing it to sqlite3_free().
**
** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation
@@ -149784,7 +173729,7 @@ static int getNextToken(
if( rc==SQLITE_OK ){
const char *zToken;
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
- int nByte; /* total space to allocate */
+ sqlite3_int64 nByte; /* total space to allocate */
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){
@@ -149807,8 +173752,8 @@ static int getNextToken(
}
while( 1 ){
- if( !sqlite3_fts3_enable_parentheses
- && iStart>0 && z[iStart-1]=='-'
+ if( !sqlite3_fts3_enable_parentheses
+ && iStart>0 && z[iStart-1]=='-'
){
pParse->isNot = 1;
iStart--;
@@ -149828,7 +173773,7 @@ static int getNextToken(
pModule->xClose(pCursor);
}
-
+
*ppExpr = pRet;
return rc;
}
@@ -149838,8 +173783,8 @@ static int getNextToken(
** Enlarge a memory allocation. If an out-of-memory allocation occurs,
** then free the old allocation.
*/
-static void *fts3ReallocOrFree(void *pOrig, int nNew){
- void *pRet = sqlite3_realloc(pOrig, nNew);
+static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){
+ void *pRet = sqlite3_realloc64(pOrig, nNew);
if( !pRet ){
sqlite3_free(pOrig);
}
@@ -149850,7 +173795,7 @@ static void *fts3ReallocOrFree(void *pOrig, int nNew){
** Buffer zInput, length nInput, contains the contents of a quoted string
** that appeared as part of an fts3 query expression. Neither quote character
** is included in the buffer. This function attempts to tokenize the entire
-** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE
+** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE
** containing the results.
**
** If successful, SQLITE_OK is returned and *ppExpr set to point at the
@@ -149875,7 +173820,7 @@ static int getNextString(
int nToken = 0;
/* The final Fts3Expr data structure, including the Fts3Phrase,
- ** Fts3PhraseToken structures token buffers are all stored as a single
+ ** 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.
**
@@ -149884,7 +173829,7 @@ static int getNextString(
** 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
+ ** structure, followed by the array of Fts3PhraseToken
** structures. This pass only populates the Fts3PhraseToken array.
**
** Buffer zTemp: Contains copies of all tokens.
@@ -149969,7 +173914,7 @@ no_mem:
}
/*
-** The output variable *ppExpr is populated with an allocated Fts3Expr
+** The output variable *ppExpr is populated with an allocated Fts3Expr
** structure, or set to 0 if the end of the input buffer is reached.
**
** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM
@@ -150005,7 +173950,7 @@ static int getNextNode(
pParse->isNot = 0;
/* Skip over any whitespace before checking for a keyword, an open or
- ** close bracket, or a quoted string.
+ ** close bracket, or a quoted string.
*/
while( nInput>0 && fts3isspace(*zInput) ){
nInput--;
@@ -150032,19 +173977,16 @@ static int getNextNode(
if( pKey->eType==FTSQUERY_NEAR ){
assert( nKey==4 );
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
- nNear = 0;
- for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
- nNear = nNear * 10 + (zInput[nKey] - '0');
- }
+ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
}
}
/* At this point this is probably a keyword. But for that to be true,
** the next byte must contain either whitespace, an open or close
- ** parenthesis, a quote character, or EOF.
+ ** parenthesis, a quote character, or EOF.
*/
cNext = zInput[nKey];
- if( fts3isspace(cNext)
+ if( fts3isspace(cNext)
|| cNext=='"' || cNext=='(' || cNext==')' || cNext==0
){
pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr));
@@ -150083,7 +174025,6 @@ static int getNextNode(
int nConsumed = 0;
pParse->nNest++;
rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
- if( rc==SQLITE_OK && !*ppExpr ){ rc = SQLITE_DONE; }
*pnConsumed = (int)(zInput - z) + 1 + nConsumed;
return rc;
}else if( *zInput==')' ){
@@ -150094,15 +174035,15 @@ static int getNextNode(
}
}
- /* If control flows to this point, this must be a regular token, or
+ /* If control flows to this point, this must be a regular token, or
** the end of the input. Read a regular token using the sqlite3_tokenizer
** interface. Before doing so, figure out if there is an explicit
- ** column specifier for the token.
+ ** column specifier for the token.
**
** TODO: Strangely, it is not possible to associate a column specifier
** with a quoted phrase, only with a single token. Not sure if this was
** an implementation artifact or an intentional decision when fts3 was
- ** first implemented. Whichever it was, this module duplicates the
+ ** first implemented. Whichever it was, this module duplicates the
** limitation.
*/
iCol = pParse->iDefaultCol;
@@ -150110,8 +174051,8 @@ static int getNextNode(
for(ii=0; ii<pParse->nCol; ii++){
const char *zStr = pParse->azCol[ii];
int nStr = (int)strlen(zStr);
- if( nInput>nStr && zInput[nStr]==':'
- && sqlite3_strnicmp(zStr, zInput, nStr)==0
+ if( nInput>nStr && zInput[nStr]==':'
+ && sqlite3_strnicmp(zStr, zInput, nStr)==0
){
iCol = ii;
iColLen = (int)((zInput - z) + nStr + 1);
@@ -150156,7 +174097,7 @@ static int opPrecedence(Fts3Expr *p){
}
/*
-** Argument ppHead contains a pointer to the current head of a query
+** Argument ppHead contains a pointer to the current head of a query
** expression tree being parsed. pPrev is the expression node most recently
** inserted into the tree. This function adds pNew, which is always a binary
** operator node, into the expression tree based on the relative precedence
@@ -150186,7 +174127,7 @@ static void insertBinaryOperator(
/*
** Parse the fts3 query expression found in buffer z, length n. This function
-** returns either when the end of the buffer is reached or an unmatched
+** returns either when the end of the buffer is reached or an unmatched
** closing bracket - ')' - is encountered.
**
** If successful, SQLITE_OK is returned, *ppExpr is set to point to the
@@ -150218,8 +174159,8 @@ static int fts3ExprParse(
if( p ){
int isPhrase;
- if( !sqlite3_fts3_enable_parentheses
- && p->eType==FTSQUERY_PHRASE && pParse->isNot
+ if( !sqlite3_fts3_enable_parentheses
+ && p->eType==FTSQUERY_PHRASE && pParse->isNot
){
/* Create an implicit NOT operator. */
Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
@@ -150340,13 +174281,13 @@ exprparse_out:
}
/*
-** Return SQLITE_ERROR if the maximum depth of the expression tree passed
+** Return SQLITE_ERROR if the maximum depth of the expression tree passed
** as the only argument is more than nMaxDepth.
*/
static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
int rc = SQLITE_OK;
if( p ){
- if( nMaxDepth<0 ){
+ if( nMaxDepth<0 ){
rc = SQLITE_TOOBIG;
}else{
rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1);
@@ -150361,12 +174302,12 @@ static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
/*
** This function attempts to transform the expression tree at (*pp) to
** an equivalent but more balanced form. The tree is modified in place.
-** If successful, SQLITE_OK is returned and (*pp) set to point to the
-** new root expression node.
+** If successful, SQLITE_OK is returned and (*pp) set to point to the
+** new root expression node.
**
** nMaxDepth is the maximum allowable depth of the balanced sub-tree.
**
-** Otherwise, if an error occurs, an SQLite error code is returned and
+** Otherwise, if an error occurs, an SQLite error code is returned and
** expression (*pp) freed.
*/
static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
@@ -150382,7 +174323,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
if( rc==SQLITE_OK ){
if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
Fts3Expr **apLeaf;
- apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
+ apLeaf = (Fts3Expr **)sqlite3_malloc64(sizeof(Fts3Expr *) * nMaxDepth);
if( 0==apLeaf ){
rc = SQLITE_NOMEM;
}else{
@@ -150481,7 +174422,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
}
pRoot = p;
}else{
- /* An error occurred. Delete the contents of the apLeaf[] array
+ /* An error occurred. Delete the contents of the apLeaf[] array
** and pFree list. Everything else is cleaned up by the call to
** sqlite3Fts3ExprFree(pRoot) below. */
Fts3Expr *pDel;
@@ -150523,7 +174464,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
}
}
}
-
+
if( rc!=SQLITE_OK ){
sqlite3Fts3ExprFree(pRoot);
pRoot = 0;
@@ -150537,9 +174478,9 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
** differences:
**
** 1. It does not do expression rebalancing.
-** 2. It does not check that the expression does not exceed the
+** 2. It does not check that the expression does not exceed the
** maximum allowable depth.
-** 3. Even if it fails, *ppExpr may still be set to point to an
+** 3. Even if it fails, *ppExpr may still be set to point to an
** expression tree. It should be deleted using sqlite3Fts3ExprFree()
** in this case.
*/
@@ -150578,7 +174519,7 @@ static int fts3ExprParseUnbalanced(
if( rc==SQLITE_OK && sParse.nNest ){
rc = SQLITE_ERROR;
}
-
+
return rc;
}
@@ -150597,7 +174538,7 @@ static int fts3ExprParseUnbalanced(
** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
** use to normalize query tokens while parsing the expression. The azCol[]
** array, which is assumed to contain nCol entries, should contain the names
-** of each column in the target fts3 table, in order from left to right.
+** of each column in the target fts3 table, in order from left to right.
** Column names must be nul-terminated strings.
**
** The iDefaultCol parameter should be passed the index of the table column
@@ -150620,7 +174561,7 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
int rc = fts3ExprParseUnbalanced(
pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr
);
-
+
/* Rebalance the expression. And check that its depth does not exceed
** SQLITE_FTS3_MAX_EXPR_DEPTH. */
if( rc==SQLITE_OK && *ppExpr ){
@@ -150635,7 +174576,7 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
*ppExpr = 0;
if( rc==SQLITE_TOOBIG ){
sqlite3Fts3ErrMsg(pzErr,
- "FTS expression tree is too large (maximum depth %d)",
+ "FTS expression tree is too large (maximum depth %d)",
SQLITE_FTS3_MAX_EXPR_DEPTH
);
rc = SQLITE_ERROR;
@@ -150695,41 +174636,13 @@ SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){
/* #include <stdio.h> */
/*
-** Function to query the hash-table of tokenizers (see README.tokenizers).
-*/
-static int queryTestTokenizer(
- sqlite3 *db,
- const char *zName,
- const sqlite3_tokenizer_module **pp
-){
- int rc;
- sqlite3_stmt *pStmt;
- const char zSql[] = "SELECT fts3_tokenizer(?)";
-
- *pp = 0;
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
- if( rc!=SQLITE_OK ){
- return rc;
- }
-
- sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
- if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
- memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
- }
- }
-
- return sqlite3_finalize(pStmt);
-}
-
-/*
** Return a pointer to a buffer containing a text representation of the
** expression passed as the first argument. The buffer is obtained from
-** sqlite3_malloc(). It is the responsibility of the caller to use
+** sqlite3_malloc(). It is the responsibility of the caller to use
** sqlite3_free() to release the memory. If an OOM condition is encountered,
** NULL is returned.
**
-** If the second argument is not NULL, then its contents are prepended to
+** If the second argument is not NULL, then its contents are prepended to
** the returned expression text and then freed using sqlite3_free().
*/
static char *exprToString(Fts3Expr *pExpr, char *zBuf){
@@ -150743,7 +174656,7 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
zBuf = sqlite3_mprintf(
"%zPHRASE %d 0", zBuf, pPhrase->iColumn);
for(i=0; zBuf && i<pPhrase->nToken; i++){
- zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
+ zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
pPhrase->aToken[i].n, pPhrase->aToken[i].z,
(pPhrase->aToken[i].isPrefix?"+":"")
);
@@ -150776,7 +174689,7 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
}
/*
-** This is the implementation of a scalar SQL function used to test the
+** This is the implementation of a scalar SQL function used to test the
** expression parser. It should be called as follows:
**
** fts3_exprtest(<tokenizer>, <expr>, <column 1>, ...);
@@ -150789,12 +174702,12 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
**
** SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2');
*/
-static void fts3ExprTest(
+static void fts3ExprTestCommon(
+ int bRebalance,
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
- sqlite3_tokenizer_module const *pModule = 0;
sqlite3_tokenizer *pTokenizer = 0;
int rc;
char **azCol = 0;
@@ -150804,37 +174717,33 @@ static void fts3ExprTest(
int ii;
Fts3Expr *pExpr;
char *zBuf = 0;
- sqlite3 *db = sqlite3_context_db_handle(context);
+ Fts3Hash *pHash = (Fts3Hash*)sqlite3_user_data(context);
+ const char *zTokenizer = 0;
+ char *zErr = 0;
if( argc<3 ){
- sqlite3_result_error(context,
+ sqlite3_result_error(context,
"Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1
);
return;
}
- rc = queryTestTokenizer(db,
- (const char *)sqlite3_value_text(argv[0]), &pModule);
- if( rc==SQLITE_NOMEM ){
- sqlite3_result_error_nomem(context);
- goto exprtest_out;
- }else if( !pModule ){
- sqlite3_result_error(context, "No such tokenizer module", -1);
- goto exprtest_out;
- }
-
- rc = pModule->xCreate(0, 0, &pTokenizer);
- assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
- if( rc==SQLITE_NOMEM ){
- sqlite3_result_error_nomem(context);
- goto exprtest_out;
+ zTokenizer = (const char*)sqlite3_value_text(argv[0]);
+ rc = sqlite3Fts3InitTokenizer(pHash, zTokenizer, &pTokenizer, &zErr);
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_NOMEM ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_error(context, zErr, -1);
+ }
+ sqlite3_free(zErr);
+ return;
}
- pTokenizer->pModule = pModule;
zExpr = (const char *)sqlite3_value_text(argv[1]);
nExpr = sqlite3_value_bytes(argv[1]);
nCol = argc-2;
- azCol = (char **)sqlite3_malloc(nCol*sizeof(char *));
+ azCol = (char **)sqlite3_malloc64(nCol*sizeof(char *));
if( !azCol ){
sqlite3_result_error_nomem(context);
goto exprtest_out;
@@ -150843,7 +174752,7 @@ static void fts3ExprTest(
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
}
- if( sqlite3_user_data(context) ){
+ if( bRebalance ){
char *zDummy = 0;
rc = sqlite3Fts3ExprParse(
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy
@@ -150869,23 +174778,38 @@ static void fts3ExprTest(
sqlite3Fts3ExprFree(pExpr);
exprtest_out:
- if( pModule && pTokenizer ){
- rc = pModule->xDestroy(pTokenizer);
+ if( pTokenizer ){
+ rc = pTokenizer->pModule->xDestroy(pTokenizer);
}
sqlite3_free(azCol);
}
+static void fts3ExprTest(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ fts3ExprTestCommon(0, context, argc, argv);
+}
+static void fts3ExprTestRebalance(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ fts3ExprTestCommon(1, context, argc, argv);
+}
+
/*
-** Register the query expression parser test function fts3_exprtest()
-** with database connection db.
+** Register the query expression parser test function fts3_exprtest()
+** with database connection db.
*/
-SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
+SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash *pHash){
int rc = sqlite3_create_function(
- db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0
+ db, "fts3_exprtest", -1, SQLITE_UTF8, (void*)pHash, fts3ExprTest, 0, 0
);
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(db, "fts3_exprtest_rebalance",
- -1, SQLITE_UTF8, (void *)1, fts3ExprTest, 0, 0
+ rc = sqlite3_create_function(db, "fts3_exprtest_rebalance",
+ -1, SQLITE_UTF8, (void*)pHash, fts3ExprTestRebalance, 0, 0
);
}
return rc;
@@ -150933,8 +174857,8 @@ SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3* db){
/*
** Malloc and Free functions
*/
-static void *fts3HashMalloc(int n){
- void *p = sqlite3_malloc(n);
+static void *fts3HashMalloc(sqlite3_int64 n){
+ void *p = sqlite3_malloc64(n);
if( p ){
memset(p, 0, n);
}
@@ -150948,8 +174872,8 @@ static void fts3HashFree(void *p){
** fields of the Hash structure.
**
** "pNew" is a pointer to the hash table that is to be initialized.
-** keyClass is one of the constants
-** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass
+** keyClass is one of the constants
+** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass
** determines what kind of key the hash table will use. "copyKey" is
** true if the hash table should make its own private copy of keys and
** false if it should just use the supplied pointer.
@@ -151026,7 +174950,7 @@ static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){
/*
** Return a pointer to the appropriate hash function given the key class.
**
-** The C syntax in this function definition may be unfamilar to some
+** The C syntax in this function definition may be unfamilar to some
** programmers, so we provide the following additional explanation:
**
** The name of the function is "ftsHashFunction". The function takes a
@@ -151086,7 +175010,7 @@ static void fts3HashInsertElement(
/* Resize the hash table so that it cantains "new_size" buckets.
-** "new_size" must be a power of 2. The hash table might fail
+** "new_size" must be a power of 2. The hash table might fail
** to resize if sqliteMalloc() fails.
**
** Return non-zero if a memory allocation error occurs.
@@ -151131,7 +175055,7 @@ static Fts3HashElem *fts3FindElementByHash(
count = pEntry->count;
xCompare = ftsCompareFunction(pH->keyClass);
while( count-- && elem ){
- if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
+ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
return elem;
}
elem = elem->next;
@@ -151150,7 +175074,7 @@ static void fts3RemoveElementByHash(
){
struct _fts3ht *pEntry;
if( elem->prev ){
- elem->prev->next = elem->next;
+ elem->prev->next = elem->next;
}else{
pH->first = elem->next;
}
@@ -151178,8 +175102,8 @@ static void fts3RemoveElementByHash(
}
SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(
- const Fts3Hash *pH,
- const void *pKey,
+ const Fts3Hash *pH,
+ const void *pKey,
int nKey
){
int h; /* A hash on key */
@@ -151193,7 +175117,7 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(
return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
}
-/*
+/*
** Attempt to locate an element of the hash table pH with a key
** that matches pKey,nKey. Return the data for this element if it is
** found, or NULL if there is no match.
@@ -151367,7 +175291,7 @@ static int porterDestroy(sqlite3_tokenizer *pTokenizer){
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is zInput[0..nInput-1]. A cursor
-** used to incrementally tokenize this string is returned in
+** used to incrementally tokenize this string is returned in
** *ppCursor.
*/
static int porterOpen(
@@ -151420,7 +175344,7 @@ static const char cType[] = {
/*
** isConsonant() and isVowel() determine if their first character in
** the string they point to is a consonant or a vowel, according
-** to Porter ruls.
+** to Porter ruls.
**
** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'.
** 'Y' is a consonant unless it follows another consonant,
@@ -151540,11 +175464,11 @@ static int star_oh(const char *z){
/*
** If the word ends with zFrom and xCond() is true for the stem
-** of the word that preceeds the zFrom ending, then change the
+** of the word that preceeds the zFrom ending, then change the
** ending to zTo.
**
** The input word *pz and zFrom are both in reverse order. zTo
-** is in normal order.
+** is in normal order.
**
** Return TRUE if zFrom matches. Return FALSE if zFrom does not
** match. Not that TRUE is returned even if xCond() fails and
@@ -151613,9 +175537,9 @@ static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
** word contains digits, 3 bytes are taken from the beginning and
** 3 bytes from the end. For long words without digits, 10 bytes
** are taken from each end. US-ASCII case folding still applies.
-**
-** If the input word contains not digits but does characters not
-** in [a-zA-Z] then no stemming is attempted and this routine just
+**
+** If the input word contains not digits but does characters not
+** in [a-zA-Z] then no stemming is attempted and this routine just
** copies the input into the input into the output with US-ASCII
** case folding.
**
@@ -151660,11 +175584,11 @@ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
}
}
- /* Step 1b */
+ /* Step 1b */
z2 = z;
if( stem(&z, "dee", "ee", m_gt_0) ){
/* Do nothing. The work was all in the test */
- }else if(
+ }else if(
(stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel))
&& z!=z2
){
@@ -151703,7 +175627,7 @@ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
stem(&z, "igol", "log", m_gt_0);
break;
case 'l':
- if( !stem(&z, "ilb", "ble", m_gt_0)
+ if( !stem(&z, "ilb", "ble", m_gt_0)
&& !stem(&z, "illa", "al", m_gt_0)
&& !stem(&z, "iltne", "ent", m_gt_0)
&& !stem(&z, "ile", "e", m_gt_0)
@@ -151991,7 +175915,7 @@ static int fts3TokenizerEnabled(sqlite3_context *context){
}
/*
-** Implementation of the SQL scalar function for accessing the underlying
+** Implementation of the SQL scalar function for accessing the underlying
** hash table. This function may be called as follows:
**
** SELECT <function-name>(<key-name>);
@@ -152028,7 +175952,7 @@ static void fts3TokenizerFunc(
nName = sqlite3_value_bytes(argv[0])+1;
if( argc==2 ){
- if( fts3TokenizerEnabled(context) ){
+ if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[1]) ){
void *pOld;
int n = sqlite3_value_bytes(argv[1]);
if( zName==0 || n!=sizeof(pPtr) ){
@@ -152055,7 +175979,9 @@ static void fts3TokenizerFunc(
return;
}
}
- sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
+ if( fts3TokenizerEnabled(context) || sqlite3_value_frombind(argv[0]) ){
+ sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
+ }
}
SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char c){
@@ -152143,8 +176069,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
int iArg = 0;
z = &z[n+1];
while( z<zEnd && (NULL!=(z = (char *)sqlite3Fts3NextToken(z, &n))) ){
- int nNew = sizeof(char *)*(iArg+1);
- char const **aNew = (const char **)sqlite3_realloc((void *)aArg, nNew);
+ sqlite3_int64 nNew = sizeof(char *)*(iArg+1);
+ char const **aNew = (const char **)sqlite3_realloc64((void *)aArg, nNew);
if( !aNew ){
sqlite3_free(zCopy);
sqlite3_free((void *)aArg);
@@ -152161,7 +176087,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
if( rc!=SQLITE_OK ){
sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer");
}else{
- (*ppTok)->pModule = m;
+ (*ppTok)->pModule = m;
}
sqlite3_free((void *)aArg);
}
@@ -152181,7 +176107,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
/* #include <string.h> */
/*
-** Implementation of a special SQL scalar function for testing tokenizers
+** Implementation of a special SQL scalar function for testing tokenizers
** designed to be used in concert with the Tcl testing framework. This
** function must be called with two or more arguments:
**
@@ -152193,9 +176119,9 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
**
** The return value is a string that may be interpreted as a Tcl
** list. For each token in the <input-string>, three elements are
-** added to the returned list. The first is the token position, the
+** added to the returned list. The first is the token position, the
** second is the token text (folded, stemmed, etc.) and the third is the
-** substring of <input-string> associated with the token. For example,
+** substring of <input-string> associated with the token. For example,
** using the built-in "simple" tokenizer:
**
** SELECT fts_tokenizer_test('simple', 'I don't see how');
@@ -152203,7 +176129,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
** will return the string:
**
** "{0 i I 1 dont don't 2 see see 3 how how}"
-**
+**
*/
static void testFunc(
sqlite3_context *context,
@@ -152298,8 +176224,8 @@ finish:
static
int registerTokenizer(
- sqlite3 *db,
- char *zName,
+ sqlite3 *db,
+ char *zName,
const sqlite3_tokenizer_module *p
){
int rc;
@@ -152321,8 +176247,8 @@ int registerTokenizer(
static
int queryTokenizer(
- sqlite3 *db,
- char *zName,
+ sqlite3 *db,
+ char *zName,
const sqlite3_tokenizer_module **pp
){
int rc;
@@ -152337,7 +176263,9 @@ int queryTokenizer(
sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
- if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
+ if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB
+ && sqlite3_column_bytes(pStmt, 0)==sizeof(*pp)
+ ){
memcpy((void *)pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
}
}
@@ -152405,28 +176333,28 @@ static void intTestFunc(
/*
** Set up SQL objects in database db used to access the contents of
** the hash table pointed to by argument pHash. The hash table must
-** been initialized to use string keys, and to take a private copy
+** been initialized to use string keys, and to take a private copy
** of the key when a value is inserted. i.e. by a call similar to:
**
** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
**
** This function adds a scalar function (see header comment above
** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
-** defined at compilation time, a temporary virtual table (see header
-** comment above struct HashTableVtab) to the database schema. Both
+** defined at compilation time, a temporary virtual table (see header
+** comment above struct HashTableVtab) to the database schema. Both
** provide read/write access to the contents of *pHash.
**
** The third argument to this function, zName, is used as the name
** of both the scalar and, if created, the virtual table.
*/
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
- sqlite3 *db,
- Fts3Hash *pHash,
+ sqlite3 *db,
+ Fts3Hash *pHash,
const char *zName
){
int rc = SQLITE_OK;
void *p = (void *)pHash;
- const int any = SQLITE_ANY;
+ const int any = SQLITE_UTF8|SQLITE_DIRECTONLY;
#ifdef SQLITE_TEST
char *zTest = 0;
@@ -152575,7 +176503,7 @@ static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is pInput[0..nBytes-1]. A cursor
-** used to incrementally tokenize this string is returned in
+** used to incrementally tokenize this string is returned in
** *ppCursor.
*/
static int simpleOpen(
@@ -152730,8 +176658,8 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
**
** input = <string>
**
-** The virtual table module tokenizes this <string>, using the FTS3
-** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
+** The virtual table module tokenizes this <string>, using the FTS3
+** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
** statement and returns one row for each token in the result. With
** fields set as follows:
**
@@ -152800,7 +176728,7 @@ static int fts3tokQueryTokenizer(
/*
** The second argument, argv[], is an array of pointers to nul-terminated
-** strings. This function makes a copy of the array and strings into a
+** strings. This function makes a copy of the array and strings into a
** single block of memory. It then dequotes any of the strings that appear
** to be quoted.
**
@@ -152827,7 +176755,7 @@ static int fts3tokDequoteArray(
nByte += (int)(strlen(argv[i]) + 1);
}
- *pazDequote = azDequote = sqlite3_malloc(sizeof(char *)*argc + nByte);
+ *pazDequote = azDequote = sqlite3_malloc64(sizeof(char *)*argc + nByte);
if( azDequote==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -152856,7 +176784,7 @@ static int fts3tokDequoteArray(
** and xCreate are identical operations.
**
** argv[0]: module name
-** argv[1]: database name
+** argv[1]: database name
** argv[2]: table name
** argv[3]: first argument (tokenizer name)
*/
@@ -152893,7 +176821,8 @@ static int fts3tokConnectMethod(
assert( (rc==SQLITE_OK)==(pMod!=0) );
if( rc==SQLITE_OK ){
- const char * const *azArg = (const char * const *)&azDequote[1];
+ const char * const *azArg = 0;
+ if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
}
@@ -152936,16 +176865,16 @@ static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){
** xBestIndex - Analyze a WHERE and ORDER BY clause.
*/
static int fts3tokBestIndexMethod(
- sqlite3_vtab *pVTab,
+ sqlite3_vtab *pVTab,
sqlite3_index_info *pInfo
){
int i;
UNUSED_PARAMETER(pVTab);
for(i=0; i<pInfo->nConstraint; i++){
- if( pInfo->aConstraint[i].usable
- && pInfo->aConstraint[i].iColumn==0
- && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
+ if( pInfo->aConstraint[i].usable
+ && pInfo->aConstraint[i].iColumn==0
+ && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
){
pInfo->idxNum = 1;
pInfo->aConstraintUsage[i].argvIndex = 1;
@@ -153051,11 +176980,11 @@ static int fts3tokFilterMethod(
if( idxNum==1 ){
const char *zByte = (const char *)sqlite3_value_text(apVal[0]);
int nByte = sqlite3_value_bytes(apVal[0]);
- pCsr->zInput = sqlite3_malloc(nByte+1);
+ pCsr->zInput = sqlite3_malloc64(nByte+1);
if( pCsr->zInput==0 ){
rc = SQLITE_NOMEM;
}else{
- memcpy(pCsr->zInput, zByte, nByte);
+ if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
pCsr->zInput[nByte] = 0;
rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
if( rc==SQLITE_OK ){
@@ -153148,7 +177077,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
0, /* xRename */
0, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
int rc; /* Return code */
@@ -153175,7 +177105,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
** This file is part of the SQLite FTS3 extension module. Specifically,
** this file contains code to insert, update and delete rows from FTS3
** tables. It also contains code to merge FTS3 b-tree segments. Some
-** of the sub-routines used to merge segments are also used by the query
+** of the sub-routines used to merge segments are also used by the query
** code in fts3.c.
*/
@@ -153185,13 +177115,13 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
/* #include <string.h> */
/* #include <assert.h> */
/* #include <stdlib.h> */
-
+/* #include <stdio.h> */
#define FTS_MAX_APPENDABLE_HEIGHT 16
/*
** When full-text index nodes are loaded from disk, the buffer that they
-** are loaded into has the following number of bytes of padding at the end
+** are loaded into has the following number of bytes of padding at the end
** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer
** of 920 bytes is allocated for it.
**
@@ -153208,10 +177138,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
** 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
+** 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
+** 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
@@ -153224,12 +177154,12 @@ 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_CHUNKSIZE (4*1024)
# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4)
#endif
/*
-** The two values that may be meaningfully bound to the :1 parameter in
+** The values that may be meaningfully bound to the :1 parameter in
** statements SQL_REPLACE_STAT and SQL_SELECT_STAT.
*/
#define FTS_STAT_DOCTOTAL 0
@@ -153238,7 +177168,7 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
/*
** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic
-** and incremental merge operation that takes place. This is used for
+** and incremental merge operation that takes place. This is used for
** debugging FTS only, it should not usually be turned on in production
** systems.
*/
@@ -153324,7 +177254,7 @@ struct Fts3SegReader {
char *aDoclist; /* Pointer to doclist of current entry */
int nDoclist; /* Size of doclist in current entry */
- /* The following variables are used by fts3SegReaderNextDocid() to iterate
+ /* The following variables are used by fts3SegReaderNextDocid() to iterate
** through the current doclist (aDoclist/nDoclist).
*/
char *pOffsetList;
@@ -153369,11 +177299,11 @@ struct SegmentWriter {
** 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
+** 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
+** very large, meaning that the interior of the tree consumes relatively
** little memory.
*/
struct SegmentNode {
@@ -153394,7 +177324,7 @@ struct SegmentNode {
*/
#define SQL_DELETE_CONTENT 0
#define SQL_IS_EMPTY 1
-#define SQL_DELETE_ALL_CONTENT 2
+#define SQL_DELETE_ALL_CONTENT 2
#define SQL_DELETE_ALL_SEGMENTS 3
#define SQL_DELETE_ALL_SEGDIR 4
#define SQL_DELETE_ALL_DOCSIZE 5
@@ -153442,7 +177372,7 @@ struct SegmentNode {
** Otherwise, an SQLite error code is returned and *pp is set to 0.
**
** If argument apVal is not NULL, then it must point to an array with
-** at least as many entries as the requested statement has bound
+** at least as many entries as the requested statement has bound
** parameters. The values are bound to the statements parameters before
** returning.
*/
@@ -153466,7 +177396,7 @@ static int fts3SqlStmt(
/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
- /* Return segments in order from oldest to newest.*/
+ /* Return segments in order from oldest to newest.*/
/* 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 "
@@ -153497,13 +177427,15 @@ static int fts3SqlStmt(
** returns zero rows. */
/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
" GROUP BY level HAVING cnt>=?"
- " ORDER BY (level %% 1024) ASC LIMIT 1",
+ " ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1",
/* Estimate the upper limit on the number of leaf nodes in a new segment
-** created by merging the oldest :2 segments from absolute level :1. See
+** created by merging the oldest :2 segments from absolute level :1. See
** function sqlite3Fts3Incrmerge() for details. */
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
- " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
+ " FROM (SELECT * FROM %Q.'%q_segdir' "
+ " WHERE level = ? ORDER BY idx ASC LIMIT ?"
+ " )",
/* SQL_DELETE_SEGDIR_ENTRY
** Delete the %_segdir entry on absolute level :1 with index :2. */
@@ -153515,7 +177447,7 @@ static int fts3SqlStmt(
/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?",
/* SQL_SELECT_SEGDIR
-** Read a single entry from the %_segdir table. The entry from absolute
+** Read a single entry from the %_segdir table. The entry from absolute
** level :1 with index value :2. */
/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
"FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
@@ -153539,7 +177471,7 @@ static int fts3SqlStmt(
** Return the largest relative level in the FTS index or indexes. */
/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'",
- /* Return segments in order from oldest to newest.*/
+ /* Return segments in order from oldest to newest.*/
/* 37 */ "SELECT level, idx, end_block "
"FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? "
"ORDER BY level DESC, idx ASC",
@@ -153555,13 +177487,15 @@ static int fts3SqlStmt(
assert( SizeofArray(azSql)==SizeofArray(p->aStmt) );
assert( eStmt<SizeofArray(azSql) && eStmt>=0 );
-
+
pStmt = p->aStmt[eStmt];
if( !pStmt ){
+ int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
char *zSql;
if( eStmt==SQL_CONTENT_INSERT ){
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
+ f &= ~SQLITE_PREPARE_NO_VTAB;
zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
}else{
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
@@ -153569,7 +177503,7 @@ static int fts3SqlStmt(
if( !zSql ){
rc = SQLITE_NOMEM;
}else{
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL);
+ rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL);
sqlite3_free(zSql);
assert( rc==SQLITE_OK || pStmt==0 );
p->aStmt[eStmt] = pStmt;
@@ -153658,7 +177592,7 @@ static void fts3SqlExec(
sqlite3_stmt *pStmt;
int rc;
if( *pRC ) return;
- rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
+ rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
if( rc==SQLITE_OK ){
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
@@ -153668,22 +177602,22 @@ static void fts3SqlExec(
/*
-** This function ensures that the caller has obtained an exclusive
-** shared-cache table-lock on the %_segdir table. This is required before
+** This function ensures that the caller has obtained an exclusive
+** shared-cache table-lock on the %_segdir table. This is required before
** writing data to the fts3 table. If this lock is not acquired first, then
** the caller may end up attempting to take this lock as part of committing
-** a transaction, causing SQLite to return SQLITE_LOCKED or
+** a transaction, causing SQLite to return SQLITE_LOCKED or
** LOCKED_SHAREDCACHEto a COMMIT command.
**
-** It is best to avoid this because if FTS3 returns any error when
-** committing a transaction, the whole transaction will be rolled back.
-** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE.
-** It can still happen if the user locks the underlying tables directly
+** It is best to avoid this because if FTS3 returns any error when
+** committing a transaction, the whole transaction will be rolled back.
+** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE.
+** It can still happen if the user locks the underlying tables directly
** instead of accessing them via FTS.
*/
static int fts3Writelock(Fts3Table *p){
int rc = SQLITE_OK;
-
+
if( p->nPendingData==0 ){
sqlite3_stmt *pStmt;
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0);
@@ -153700,7 +177634,7 @@ static int fts3Writelock(Fts3Table *p){
/*
** FTS maintains a separate indexes for each language-id (a 32-bit integer).
** Within each language id, a separate index is maintained to store the
-** document terms, and each configured prefix size (configured the FTS
+** document terms, and each configured prefix size (configured the FTS
** "prefix=" option). And each index consists of multiple levels ("relative
** levels").
**
@@ -153710,14 +177644,14 @@ static int fts3Writelock(Fts3Table *p){
** separate component values into the single 64-bit integer value that
** can be used to query the %_segdir table.
**
-** Specifically, each language-id/index combination is allocated 1024
+** Specifically, each language-id/index combination is allocated 1024
** 64-bit integer level values ("absolute levels"). The main terms index
** for language-id 0 is allocate values 0-1023. The first prefix index
** (if any) for language-id 0 is allocated values 1024-2047. And so on.
** Language 1 indexes are allocated immediately following language 0.
**
** So, for a system with nPrefix prefix indexes configured, the block of
-** absolute levels that corresponds to language-id iLangid and index
+** absolute levels that corresponds to language-id iLangid and index
** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024).
*/
static sqlite3_int64 getAbsoluteLevel(
@@ -153727,7 +177661,7 @@ static sqlite3_int64 getAbsoluteLevel(
int iLevel /* Level of segments */
){
sqlite3_int64 iBase; /* First absolute level for iLangid/iIndex */
- assert( iLangid>=0 );
+ assert_fts3_nc( iLangid>=0 );
assert( p->nIndex>0 );
assert( iIndex>=0 && iIndex<p->nIndex );
@@ -153738,7 +177672,7 @@ static sqlite3_int64 getAbsoluteLevel(
/*
** Set *ppStmt to a statement handle that may be used to iterate through
** all rows in the %_segdir table, from oldest to newest. If successful,
-** return SQLITE_OK. If an error occurs while preparing the statement,
+** return SQLITE_OK. If an error occurs while preparing the statement,
** return an SQLite error code.
**
** There is only ever one instance of this SQL statement compiled for
@@ -153769,16 +177703,16 @@ SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
if( iLevel<0 ){
/* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0);
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
- sqlite3_bind_int64(pStmt, 2,
+ sqlite3_bind_int64(pStmt, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
}
}else{
/* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel));
}
}
@@ -153856,7 +177790,7 @@ static int fts3PendingListAppend(
assert( !p || p->iLastDocid<=iDocid );
if( !p || p->iLastDocid!=iDocid ){
- sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
+ u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
if( p ){
assert( p->nData<p->nSpace );
assert( p->aData[p->nData]==0 );
@@ -153922,7 +177856,7 @@ static int fts3PendingTermsAddOne(
}
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
+ /* 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) );
@@ -153968,7 +177902,7 @@ static int fts3PendingTermsAdd(
assert( pTokenizer && pModule );
/* If the user has inserted a NULL value, this function may be called with
- ** zText==0. In this case, add zero token entries to the hash table and
+ ** zText==0. In this case, add zero token entries to the hash table and
** return early. */
if( zText==0 ){
*pnWord = 0;
@@ -153999,8 +177933,8 @@ static int fts3PendingTermsAdd(
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
+
+ /* 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];
@@ -154016,8 +177950,8 @@ static int fts3PendingTermsAdd(
return (rc==SQLITE_DONE ? SQLITE_OK : rc);
}
-/*
-** Calling this function indicates that subsequent calls to
+/*
+** Calling this function indicates that subsequent calls to
** fts3PendingTermsAdd() are to add term/position-list pairs for the
** contents of the document with docid iDocid.
*/
@@ -154036,10 +177970,10 @@ static int fts3PendingTermsDocid(
** buffer was half empty, that would let the less frequent terms
** generate longer doclists.
*/
- if( iDocid<p->iPrevDocid
+ if( iDocid<p->iPrevDocid
|| (iDocid==p->iPrevDocid && p->bPrevDelete==0)
|| p->iPrevLangid!=iLangid
- || p->nPendingData>p->nMaxPendingData
+ || p->nPendingData>p->nMaxPendingData
){
int rc = sqlite3Fts3PendingTermsFlush(p);
if( rc!=SQLITE_OK ) return rc;
@@ -154051,7 +177985,7 @@ static int fts3PendingTermsDocid(
}
/*
-** Discard the contents of the pending-terms hash tables.
+** Discard the contents of the pending-terms hash tables.
*/
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
int i;
@@ -154076,9 +178010,9 @@ SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
** fts3InsertData(). Parameter iDocid is the docid of the new row.
*/
static int fts3InsertTerms(
- Fts3Table *p,
- int iLangid,
- sqlite3_value **apVal,
+ Fts3Table *p,
+ int iLangid,
+ sqlite3_value **apVal,
u32 *aSz
){
int i; /* Iterator variable */
@@ -154141,7 +178075,7 @@ static int fts3InsertData(
rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]);
if( rc==SQLITE_OK && p->zLanguageid ){
rc = sqlite3_bind_int(
- pContentInsert, p->nColumn+2,
+ pContentInsert, p->nColumn+2,
sqlite3_value_int(apVal[p->nColumn+4])
);
}
@@ -154168,8 +178102,8 @@ static int fts3InsertData(
if( rc!=SQLITE_OK ) return rc;
}
- /* Execute the statement to insert the record. Set *piDocid to the
- ** new docid value.
+ /* Execute the statement to insert the record. Set *piDocid to the
+ ** new docid value.
*/
sqlite3_step(pContentInsert);
rc = sqlite3_reset(pContentInsert);
@@ -154219,7 +178153,7 @@ static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){
** (an integer) of a row about to be deleted. Remove all terms from the
** full-text index.
*/
-static void fts3DeleteTerms(
+static void fts3DeleteTerms(
int *pRC, /* Result code */
Fts3Table *p, /* The FTS table to delete from */
sqlite3_value *pRowid, /* The docid to be deleted */
@@ -154266,7 +178200,7 @@ static void fts3DeleteTerms(
*/
static int fts3SegmentMerge(Fts3Table *, int, int, int);
-/*
+/*
** This function allocates a new level iLevel index in the segdir table.
** Usually, indexes are allocated within a level sequentially starting
** with 0, so the allocated index is one greater than the value returned
@@ -154275,17 +178209,17 @@ static int fts3SegmentMerge(Fts3Table *, int, int, int);
** SELECT max(idx) FROM %_segdir WHERE level = :iLevel
**
** However, if there are already FTS3_MERGE_COUNT indexes at the requested
-** level, they are merged into a single level (iLevel+1) segment and the
+** level, they are merged into a single level (iLevel+1) segment and the
** allocated index is 0.
**
** 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,
+ Fts3Table *p,
int iLangid, /* Language id */
int iIndex, /* Index for p->aIndex */
- int iLevel,
+ int iLevel,
int *piIdx
){
int rc; /* Return Code */
@@ -154313,7 +178247,7 @@ static int fts3AllocateSegdirIdx(
** segment and allocate (newly freed) index 0 at level iLevel. Otherwise,
** if iNext is less than FTS3_MERGE_COUNT, allocate index iNext.
*/
- if( iNext>=FTS3_MERGE_COUNT ){
+ if( iNext>=MergeCount(p) ){
fts3LogMerge(16, getAbsoluteLevel(p, iLangid, iIndex, iLevel));
rc = fts3SegmentMerge(p, iLangid, iIndex, iLevel);
*piIdx = 0;
@@ -154333,7 +178267,7 @@ static int fts3AllocateSegdirIdx(
** This function reads data from a single row of the %_segments table. The
** specific row is identified by the iBlockid parameter. If paBlob is not
** NULL, then a buffer is allocated using sqlite3_malloc() and populated
-** with the contents of the blob stored in the "block" column of the
+** with the contents of the blob stored in the "block" column of the
** identified table row is. Whether or not paBlob is NULL, *pnBlob is set
** to the size of the blob in bytes before returning.
**
@@ -154397,6 +178331,8 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
}
*paBlob = aByte;
}
+ }else if( rc==SQLITE_ERROR ){
+ rc = FTS_CORRUPT_VTAB;
}
return rc;
@@ -154410,14 +178346,14 @@ SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){
sqlite3_blob_close(p->pSegments);
p->pSegments = 0;
}
-
+
static int fts3SegReaderIncrRead(Fts3SegReader *pReader){
int nRead; /* Number of bytes to read */
int rc; /* Return code */
nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE);
rc = sqlite3_blob_read(
- pReader->pBlob,
+ pReader->pBlob,
&pReader->aNode[pReader->nPopulate],
nRead,
pReader->nPopulate
@@ -154437,10 +178373,10 @@ static int fts3SegReaderIncrRead(Fts3SegReader *pReader){
static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){
int rc = SQLITE_OK;
- assert( !pReader->pBlob
+ assert( !pReader->pBlob
|| (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode])
);
- while( pReader->pBlob && rc==SQLITE_OK
+ while( pReader->pBlob && rc==SQLITE_OK
&& (pFrom - pReader->aNode + nByte)>pReader->nPopulate
){
rc = fts3SegReaderIncrRead(pReader);
@@ -154466,7 +178402,7 @@ static void fts3SegReaderSetEof(Fts3SegReader *pSeg){
** SQLITE_DONE. Otherwise, an SQLite error code.
*/
static int fts3SegReaderNext(
- Fts3Table *p,
+ Fts3Table *p,
Fts3SegReader *pReader,
int bIncr
){
@@ -154506,15 +178442,17 @@ static int fts3SegReaderNext(
fts3SegReaderSetEof(pReader);
- /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
+ /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
** blocks have already been traversed. */
- assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock );
+#ifdef CORRUPT_DB
+ assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB );
+#endif
if( pReader->iCurrentBlock>=pReader->iLeafEndBlock ){
return SQLITE_OK;
}
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;
@@ -154530,20 +178468,24 @@ static int fts3SegReaderNext(
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
+
+ /* Because of the FTS3_NODE_PADDING bytes of padding, the following is
** safe (no risk of overread) even if the node data is corrupted. */
pNext += fts3GetVarint32(pNext, &nPrefix);
pNext += fts3GetVarint32(pNext, &nSuffix);
- if( nPrefix<0 || nSuffix<=0
- || &pNext[nSuffix]>&pReader->aNode[pReader->nNode]
+ if( nSuffix<=0
+ || (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
+ || nPrefix>pReader->nTerm
){
return FTS_CORRUPT_VTAB;
}
- if( nPrefix+nSuffix>pReader->nTermAlloc ){
- int nNew = (nPrefix+nSuffix)*2;
- char *zNew = sqlite3_realloc(pReader->zTerm, nNew);
+ /* Both nPrefix and nSuffix were read by fts3GetVarint32() and so are
+ ** between 0 and 0x7FFFFFFF. But the sum of the two may cause integer
+ ** overflow - hence the (i64) casts. */
+ if( (i64)nPrefix+nSuffix>(i64)pReader->nTermAlloc ){
+ i64 nNew = ((i64)nPrefix+nSuffix)*2;
+ char *zNew = sqlite3_realloc64(pReader->zTerm, nNew);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -154562,11 +178504,12 @@ static int fts3SegReaderNext(
pReader->pOffsetList = 0;
/* Check that the doclist does not appear to extend past the end of the
- ** b-tree node. And that the final byte of the doclist is 0x00. If either
+ ** b-tree node. And that the final byte of the doclist is 0x00. If either
** of these statements is untrue, then the data structure is corrupt.
*/
- if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode]
+ if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
+ || pReader->nDoclist==0
){
return FTS_CORRUPT_VTAB;
}
@@ -154586,7 +178529,7 @@ static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){
pReader->iDocid = 0;
pReader->nOffsetList = 0;
sqlite3Fts3DoclistPrev(0,
- pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList,
+ pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList,
&pReader->iDocid, &pReader->nOffsetList, &bEof
);
}else{
@@ -154602,8 +178545,8 @@ static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){
/*
** Advance the SegReader to point to the next docid in the doclist
** associated with the current term.
-**
-** If arguments ppOffsetList and pnOffsetList are not NULL, then
+**
+** If arguments ppOffsetList and pnOffsetList are not NULL, then
** *ppOffsetList is set to point to the first column-offset list
** in the doclist entry (i.e. immediately past the docid varint).
** *pnOffsetList is set to the length of the set of column-offset
@@ -154646,22 +178589,22 @@ static int fts3SegReaderNextDocid(
** 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
+ ** 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 past
** the populated part of pReader->aNode[].
*/
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.
*/
@@ -154672,7 +178615,7 @@ static int fts3SegReaderNextDocid(
/* List may have been edited in place by fts3EvalNearTrim() */
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
@@ -154683,23 +178626,23 @@ static int fts3SegReaderNextDocid(
}else{
rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
if( rc==SQLITE_OK ){
- sqlite3_int64 iDelta;
- pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
+ u64 iDelta;
+ pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
if( pTab->bDescIdx ){
- pReader->iDocid -= iDelta;
+ pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
}else{
- pReader->iDocid += iDelta;
+ pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
}
}
}
}
- return SQLITE_OK;
+ return rc;
}
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
- Fts3Cursor *pCsr,
+ Fts3Cursor *pCsr,
Fts3MultiSegReader *pMsr,
int *pnOvfl
){
@@ -154714,8 +178657,8 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
for(ii=0; rc==SQLITE_OK && ii<pMsr->nSegment; ii++){
Fts3SegReader *pReader = pMsr->apSegment[ii];
- if( !fts3SegReaderIsPending(pReader)
- && !fts3SegReaderIsRootOnly(pReader)
+ if( !fts3SegReaderIsPending(pReader)
+ && !fts3SegReaderIsRootOnly(pReader)
){
sqlite3_int64 jj;
for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){
@@ -154733,7 +178676,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
}
/*
-** Free all allocations associated with the iterator passed as the
+** Free all allocations associated with the iterator passed as the
** second argument.
*/
SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
@@ -154765,8 +178708,13 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
Fts3SegReader *pReader; /* Newly allocated SegReader object */
int nExtra = 0; /* Bytes to allocate segment root node */
- assert( iStartLeaf<=iEndLeaf );
+ assert( zRoot!=0 || nRoot==0 );
+#ifdef CORRUPT_DB
+ assert( zRoot!=0 || CORRUPT_DB );
+#endif
+
if( iStartLeaf==0 ){
+ if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB;
nExtra = nRoot + FTS3_NODE_PADDING;
}
@@ -154786,7 +178734,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
pReader->aNode = (char *)&pReader[1];
pReader->rootOnly = 1;
pReader->nNode = nRoot;
- memcpy(pReader->aNode, zRoot, nRoot);
+ if( nRoot ) memcpy(pReader->aNode, zRoot, nRoot);
memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
}else{
pReader->iCurrentBlock = iStartLeaf-1;
@@ -154887,7 +178835,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
}else{
/* 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.
+ ** the index. All that is required is a straight hash-lookup.
**
** Because the stack address of pE may be accessed via the aElem pointer
** below, the "Fts3HashElem *pE" must be declared so that it is valid
@@ -154901,8 +178849,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
}
if( nElem>0 ){
- int nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *);
- pReader = (Fts3SegReader *)sqlite3_malloc(nByte);
+ sqlite3_int64 nByte;
+ nByte = sizeof(Fts3SegReader) + (nElem+1)*sizeof(Fts3HashElem *);
+ pReader = (Fts3SegReader *)sqlite3_malloc64(nByte);
if( !pReader ){
rc = SQLITE_NOMEM;
}else{
@@ -154921,7 +178870,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
}
/*
-** Compare the entries pointed to by two Fts3SegReader structures.
+** Compare the entries pointed to by two Fts3SegReader structures.
** Comparison is as follows:
**
** 1) EOF is greater than not EOF.
@@ -154992,7 +178941,7 @@ static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
/*
** Compare the term that the Fts3SegReader object passed as the first argument
-** points to with the term specified by arguments zTerm and nTerm.
+** points to with the term specified by arguments zTerm and nTerm.
**
** If the pSeg iterator is already at EOF, return 0. Otherwise, return
** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are
@@ -155053,7 +179002,7 @@ static void fts3SegReaderSort(
#endif
}
-/*
+/*
** Insert a record into the %_segments table.
*/
static int fts3WriteSegment(
@@ -155069,6 +179018,7 @@ static int fts3WriteSegment(
sqlite3_bind_blob(pStmt, 2, z, n, SQLITE_STATIC);
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
+ sqlite3_bind_null(pStmt, 2);
}
return rc;
}
@@ -155094,7 +179044,7 @@ SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){
return rc;
}
-/*
+/*
** Insert a record into the %_segdir table.
*/
static int fts3WriteSegdir(
@@ -155125,13 +179075,14 @@ static int fts3WriteSegdir(
sqlite3_bind_blob(pStmt, 6, zRoot, nRoot, SQLITE_STATIC);
sqlite3_step(pStmt);
rc = sqlite3_reset(pStmt);
+ sqlite3_bind_null(pStmt, 6);
}
return rc;
}
/*
** Return the size of the common prefix (if any) shared by zPrev and
-** zNext, in bytes. For example,
+** zNext, in bytes. For example,
**
** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3
** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2
@@ -155155,7 +179106,7 @@ static int fts3PrefixCompress(
*/
static int fts3NodeAddTerm(
Fts3Table *p, /* Virtual table handle */
- SegmentNode **ppTree, /* IN/OUT: SegmentNode handle */
+ SegmentNode **ppTree, /* IN/OUT: SegmentNode handle */
int isCopyTerm, /* True if zTerm/nTerm is transient */
const char *zTerm, /* Pointer to buffer containing term */
int nTerm /* Size of term in bytes */
@@ -155164,7 +179115,7 @@ static int fts3NodeAddTerm(
int rc;
SegmentNode *pNew;
- /* First try to append the term to the current node. Return early if
+ /* First try to append the term to the current node. Return early if
** this is possible.
*/
if( pTree ){
@@ -155176,6 +179127,11 @@ static int fts3NodeAddTerm(
nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm);
nSuffix = nTerm-nPrefix;
+ /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
+ ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
+ ** compared with BINARY collation. This indicates corruption. */
+ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
+
nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix;
if( nReq<=p->nNodeSize || !pTree->zTerm ){
@@ -155184,8 +179140,8 @@ static int fts3NodeAddTerm(
** and the static node buffer (p->nNodeSize bytes) is not large
** enough. Use a separately malloced buffer instead This wastes
** p->nNodeSize bytes, but since this scenario only comes about when
- ** the database contain two terms that share a prefix of almost 2KB,
- ** this is not expected to be a serious problem.
+ ** the database contain two terms that share a prefix of almost 2KB,
+ ** this is not expected to be a serious problem.
*/
assert( pTree->aData==(char *)&pTree[1] );
pTree->aData = (char *)sqlite3_malloc(nReq);
@@ -155229,7 +179185,7 @@ static int fts3NodeAddTerm(
** If this is the first node in the tree, the term is added to it.
**
** Otherwise, the term is not added to the new node, it is left empty for
- ** now. Instead, the term is inserted into the parent of pTree. If pTree
+ ** now. Instead, the term is inserted into the parent of pTree. If pTree
** has no parent, one is created here.
*/
pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
@@ -155254,7 +179210,7 @@ static int fts3NodeAddTerm(
pTree->zMalloc = 0;
}else{
pNew->pLeftmost = pNew;
- rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm);
+ rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm);
}
*ppTree = pNew;
@@ -155265,8 +179221,8 @@ static int fts3NodeAddTerm(
** Helper function for fts3NodeWrite().
*/
static int fts3TreeFinishNode(
- SegmentNode *pTree,
- int iHeight,
+ SegmentNode *pTree,
+ int iHeight,
sqlite3_int64 iLeftChild
){
int nStart;
@@ -155279,15 +179235,15 @@ static int fts3TreeFinishNode(
/*
** Write the buffer for the segment node pTree and all of its peers to the
-** database. Then call this function recursively to write the parent of
-** pTree and its peers to the database.
+** database. Then call this function recursively to write the parent of
+** pTree and its peers to the database.
**
** Except, if pTree is a root node, do not write it to the database. Instead,
** set output variables *paRoot and *pnRoot to contain the root node.
**
** If successful, SQLITE_OK is returned and output variable *piLast is
** set to the largest blockid written to the database (or zero if no
-** blocks were written to the db). Otherwise, an SQLite error code is
+** blocks were written to the db). Otherwise, an SQLite error code is
** returned.
*/
static int fts3NodeWrite(
@@ -155315,7 +179271,7 @@ static int fts3NodeWrite(
for(pIter=pTree->pLeftmost; pIter && rc==SQLITE_OK; pIter=pIter->pRight){
int nStart = fts3TreeFinishNode(pIter, iHeight, iNextLeaf);
int nWrite = pIter->nData - nStart;
-
+
rc = fts3WriteSegment(p, iNextFree, &pIter->aData[nStart], nWrite);
iNextFree++;
iNextLeaf += (pIter->nEntry+1);
@@ -155361,7 +179317,7 @@ static void fts3NodeFree(SegmentNode *pTree){
*/
static int fts3SegWriterAdd(
Fts3Table *p, /* Virtual table handle */
- SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */
+ SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */
int isCopyTerm, /* True if buffer zTerm must be copied */
const char *zTerm, /* Pointer to buffer containing term */
int nTerm, /* Size of term in bytes */
@@ -155404,6 +179360,11 @@ static int fts3SegWriterAdd(
nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm);
nSuffix = nTerm-nPrefix;
+ /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
+ ** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
+ ** compared with BINARY collation. This indicates corruption. */
+ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
+
/* Figure out how many bytes are required by this new entry */
nReq = sqlite3Fts3VarintLen(nPrefix) + /* varint containing prefix size */
sqlite3Fts3VarintLen(nSuffix) + /* varint containing suffix size */
@@ -155415,6 +179376,7 @@ static int fts3SegWriterAdd(
int rc;
/* The current leaf node is full. Write it out to the database. */
+ if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
if( rc!=SQLITE_OK ) return rc;
p->nLeafAdd++;
@@ -155464,9 +179426,11 @@ static int fts3SegWriterAdd(
/* Append the prefix-compressed term and doclist to the buffer. */
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nPrefix);
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nSuffix);
+ assert( nSuffix>0 );
memcpy(&pWriter->aData[nData], &zTerm[nPrefix], nSuffix);
nData += nSuffix;
nData += sqlite3Fts3PutVarint(&pWriter->aData[nData], nDoclist);
+ assert( nDoclist>0 );
memcpy(&pWriter->aData[nData], aDoclist, nDoclist);
pWriter->nData = nData + nDoclist;
@@ -155486,6 +179450,7 @@ static int fts3SegWriterAdd(
pWriter->zTerm = zNew;
}
assert( pWriter->zTerm==pWriter->zMalloc );
+ assert( nTerm>0 );
memcpy(pWriter->zTerm, zTerm, nTerm);
}else{
pWriter->zTerm = (char *)zTerm;
@@ -155521,12 +179486,12 @@ static int fts3SegWriterFlush(
pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot);
}
if( rc==SQLITE_OK ){
- rc = fts3WriteSegdir(p, iLevel, iIdx,
+ rc = fts3WriteSegdir(p, iLevel, iIdx,
pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot);
}
}else{
/* The entire tree fits on the root node. Write it to the segdir table. */
- rc = fts3WriteSegdir(p, iLevel, iIdx,
+ rc = fts3WriteSegdir(p, iLevel, iIdx,
0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData);
}
p->nLeafAdd++;
@@ -155534,7 +179499,7 @@ static int fts3SegWriterFlush(
}
/*
-** Release all memory held by the SegmentWriter object passed as the
+** Release all memory held by the SegmentWriter object passed as the
** first argument.
*/
static void fts3SegWriterFree(SegmentWriter *pWriter){
@@ -155584,9 +179549,9 @@ static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
** Return SQLITE_OK if successful, or an SQLite error code if not.
*/
static int fts3SegmentMaxLevel(
- Fts3Table *p,
+ Fts3Table *p,
int iLangid,
- int iIndex,
+ int iIndex,
sqlite3_int64 *pnMax
){
sqlite3_stmt *pStmt;
@@ -155602,7 +179567,7 @@ static int fts3SegmentMaxLevel(
rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
- sqlite3_bind_int64(pStmt, 2,
+ sqlite3_bind_int64(pStmt, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
if( SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -155631,8 +179596,8 @@ static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){
int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
- sqlite3_bind_int64(pStmt, 2,
- ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
+ sqlite3_bind_int64(pStmt, 2,
+ (((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
);
*pbMax = 0;
@@ -155669,9 +179634,9 @@ static int fts3DeleteSegment(
** This function is used after merging multiple segments into a single large
** segment to delete the old, now redundant, segment b-trees. Specifically,
** it:
-**
-** 1) Deletes all %_segments entries for the segments associated with
-** each of the SegReader objects in the array passed as the third
+**
+** 1) Deletes all %_segments entries for the segments associated with
+** each of the SegReader objects in the array passed as the third
** argument, and
**
** 2) deletes all %_segdir entries with level iLevel, or all %_segdir
@@ -155703,7 +179668,7 @@ static int fts3DeleteSegdir(
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
- sqlite3_bind_int64(pDelete, 2,
+ sqlite3_bind_int64(pDelete, 2,
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
);
}
@@ -155725,7 +179690,7 @@ static int fts3DeleteSegdir(
}
/*
-** When this function is called, buffer *ppList (size *pnList bytes) contains
+** When this function is called, buffer *ppList (size *pnList bytes) contains
** a position list that may (or may not) feature multiple columns. This
** function adjusts the pointer *ppList and the length *pnList so that they
** identify the subset of the position list that corresponds to column iCol.
@@ -155752,7 +179717,7 @@ static void fts3ColumnFilter(
while( 1 ){
char c = 0;
while( p<pEnd && (c | *p)&0xFE ) c = *p++ & 0x80;
-
+
if( iCol==iCurrent ){
nList = (int)(p - pList);
break;
@@ -155760,14 +179725,14 @@ static void fts3ColumnFilter(
nList -= (int)(p - pList);
pList = p;
- if( nList==0 ){
+ if( nList<=0 ){
break;
}
p = &pList[1];
p += fts3GetVarint32(p, &iCurrent);
}
- if( bZero && &pList[nList]!=pEnd ){
+ if( bZero && (pEnd - &pList[nList])>0){
memset(&pList[nList], 0, pEnd - &pList[nList]);
}
*ppList = pList;
@@ -155794,6 +179759,7 @@ static int fts3MsrBufferData(
pMsr->aBuffer = pNew;
}
+ assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
return SQLITE_OK;
}
@@ -155832,7 +179798,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList);
j = 1;
- while( rc==SQLITE_OK
+ while( rc==SQLITE_OK
&& j<nMerge
&& apSegment[j]->pOffsetList
&& apSegment[j]->iDocid==iDocid
@@ -155875,7 +179841,7 @@ static int fts3SegReaderStart(
int i;
int nSeg = pCsr->nSegment;
- /* If the Fts3SegFilter defines a specific term (or term prefix) to search
+ /* 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
** equal or greater value than the specified term. This prevents many
** unnecessary merge/sort operations for the case where single segment
@@ -155959,7 +179925,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
** sqlite3Fts3SegReaderStart()
** sqlite3Fts3SegReaderStep()
**
-** then the entire doclist for the term is available in
+** then the entire doclist for the term is available in
** MultiSegReader.aDoclist/nDoclist.
*/
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
@@ -155981,6 +179947,19 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
+static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
+ if( nReq>pCsr->nBuffer ){
+ char *aNew;
+ pCsr->nBuffer = nReq*2;
+ aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
+ if( !aNew ){
+ return SQLITE_NOMEM;
+ }
+ pCsr->aBuffer = aNew;
+ }
+ return SQLITE_OK;
+}
+
SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
Fts3Table *p, /* Virtual table handle */
@@ -156007,9 +179986,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
do {
int nMerge;
int i;
-
+
/* Advance the first pCsr->nAdvance entries in the apSegment[] array
- ** forward. Then sort the list in order of current term again.
+ ** forward. Then sort the list in order of current term again.
*/
for(i=0; i<pCsr->nAdvance; i++){
Fts3SegReader *pSeg = apSegment[i];
@@ -156031,34 +180010,34 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
pCsr->zTerm = apSegment[0]->zTerm;
/* If this is a prefix-search, and if the term that apSegment[0] points
- ** to does not share a suffix with pFilter->zTerm/nTerm, then all
+ ** to does not share a suffix with pFilter->zTerm/nTerm, then all
** required callbacks have been made. In this case exit early.
**
** Similarly, if this is a search for an exact match, and the first term
** of segment apSegment[0] is not a match, exit early.
*/
if( pFilter->zTerm && !isScan ){
- if( pCsr->nTerm<pFilter->nTerm
+ if( pCsr->nTerm<pFilter->nTerm
|| (!isPrefix && pCsr->nTerm>pFilter->nTerm)
- || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm)
+ || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm)
){
break;
}
}
nMerge = 1;
- while( nMerge<nSegment
+ while( nMerge<nSegment
&& apSegment[nMerge]->aNode
- && apSegment[nMerge]->nTerm==pCsr->nTerm
+ && apSegment[nMerge]->nTerm==pCsr->nTerm
&& 0==memcmp(pCsr->zTerm, apSegment[nMerge]->zTerm, pCsr->nTerm)
){
nMerge++;
}
assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
- if( nMerge==1
- && !isIgnoreEmpty
- && !isFirst
+ if( nMerge==1
+ && !isIgnoreEmpty
+ && !isFirst
&& (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
){
pCsr->nDoclist = apSegment[0]->nDoclist;
@@ -156103,32 +180082,26 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
if( !isIgnoreEmpty || nList>0 ){
- /* Calculate the 'docid' delta value to write into the merged
+ /* Calculate the 'docid' delta value to write into the merged
** doclist. */
sqlite3_int64 iDelta;
if( p->bDescIdx && nDoclist>0 ){
- iDelta = iPrev - iDocid;
+ if( iPrev<=iDocid ) return FTS_CORRUPT_VTAB;
+ iDelta = (i64)((u64)iPrev - (u64)iDocid);
}else{
- iDelta = iDocid - iPrev;
+ if( nDoclist>0 && iPrev>=iDocid ) return FTS_CORRUPT_VTAB;
+ iDelta = (i64)((u64)iDocid - (u64)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;
- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
- if( !aNew ){
- return SQLITE_NOMEM;
- }
- pCsr->aBuffer = aNew;
- }
+
+ rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist);
+ if( rc ) return rc;
if( isFirst ){
char *a = &pCsr->aBuffer[nDoclist];
int nWrite;
-
+
nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a);
if( nWrite ){
iPrev = iDocid;
@@ -156148,6 +180121,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
+ rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
+ if( rc ) return rc;
+ memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
pCsr->nDoclist = nDoclist;
rc = SQLITE_ROW;
@@ -156178,18 +180154,18 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(
}
/*
-** Decode the "end_block" field, selected by column iCol of the SELECT
-** statement passed as the first argument.
+** Decode the "end_block" field, selected by column iCol of the SELECT
+** statement passed as the first argument.
**
** The "end_block" field may contain either an integer, or a text field
-** containing the text representation of two non-negative integers separated
-** by one or more space (0x20) characters. In the first case, set *piEndBlock
-** to the integer value and *pnByte to zero before returning. In the second,
+** containing the text representation of two non-negative integers separated
+** by one or more space (0x20) characters. In the first case, set *piEndBlock
+** to the integer value and *pnByte to zero before returning. In the second,
** set *piEndBlock to the first value and *pnByte to the second.
*/
static void fts3ReadEndBlockField(
- sqlite3_stmt *pStmt,
- int iCol,
+ sqlite3_stmt *pStmt,
+ int iCol,
i64 *piEndBlock,
i64 *pnByte
){
@@ -156197,11 +180173,11 @@ static void fts3ReadEndBlockField(
if( zText ){
int i;
int iMul = 1;
- i64 iVal = 0;
+ u64 iVal = 0;
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *piEndBlock = iVal;
+ *piEndBlock = (i64)iVal;
while( zText[i]==' ' ) i++;
iVal = 0;
if( zText[i]=='-' ){
@@ -156211,7 +180187,7 @@ static void fts3ReadEndBlockField(
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
iVal = iVal*10 + (zText[i] - '0');
}
- *pnByte = (iVal * (i64)iMul);
+ *pnByte = ((i64)iVal * (i64)iMul);
}
}
@@ -156235,10 +180211,10 @@ static int fts3PromoteSegments(
i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1;
i64 nLimit = (nByte*3)/2;
- /* Loop through all entries in the %_segdir table corresponding to
+ /* Loop through all entries in the %_segdir table corresponding to
** segments in this index on levels greater than iAbsLevel. If there is
- ** at least one such segment, and it is possible to determine that all
- ** such segments are smaller than nLimit bytes in size, they will be
+ ** at least one such segment, and it is possible to determine that all
+ ** such segments are smaller than nLimit bytes in size, they will be
** promoted to level iAbsLevel. */
sqlite3_bind_int64(pRange, 1, iAbsLevel+1);
sqlite3_bind_int64(pRange, 2, iLast);
@@ -156246,7 +180222,7 @@ static int fts3PromoteSegments(
i64 nSize = 0, dummy;
fts3ReadEndBlockField(pRange, 2, &dummy, &nSize);
if( nSize<=0 || nSize>nLimit ){
- /* If nSize==0, then the %_segdir.end_block field does not not
+ /* If nSize==0, then the %_segdir.end_block field does not not
** contain a size value. This happens if it was written by an
** old version of FTS. In this case it is not possible to determine
** the size of the segment, and so segment promotion does not
@@ -156312,18 +180288,18 @@ static int fts3PromoteSegments(
}
/*
-** Merge all level iLevel segments in the database into a single
+** Merge all level iLevel segments in the database into a single
** iLevel+1 segment. Or, if iLevel<0, merge all segments into a
-** single segment with a level equal to the numerically largest level
+** single segment with a level equal to the numerically largest level
** currently present in the database.
**
** If this function is called with iLevel<0, but there is only one
-** segment in the database, SQLITE_DONE is returned immediately.
-** Otherwise, if successful, SQLITE_OK is returned. If an error occurs,
+** segment in the database, SQLITE_DONE is returned immediately.
+** Otherwise, if successful, SQLITE_OK is returned. If an error occurs,
** an SQLite error code is returned.
*/
static int fts3SegmentMerge(
- Fts3Table *p,
+ Fts3Table *p,
int iLangid, /* Language id to merge */
int iIndex, /* Index in p->aIndex[] to merge */
int iLevel /* Level to merge */
@@ -156367,7 +180343,7 @@ static int fts3SegmentMerge(
}else{
/* 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
+ ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to
** a single iLevel+2 segment if necessary. */
assert( FTS3_SEGCURSOR_PENDING==-1 );
iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1);
@@ -156377,8 +180353,10 @@ static int fts3SegmentMerge(
if( rc!=SQLITE_OK ) goto finished;
assert( csr.nSegment>0 );
- assert( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
- assert( iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL) );
+ assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
+ assert_fts3_nc(
+ iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL)
+ );
memset(&filter, 0, sizeof(Fts3SegFilter));
filter.flags = FTS3_SEGMENT_REQUIRE_POS;
@@ -156388,11 +180366,11 @@ static int fts3SegmentMerge(
while( SQLITE_OK==rc ){
rc = sqlite3Fts3SegReaderStep(p, &csr);
if( rc!=SQLITE_ROW ) break;
- rc = fts3SegWriterAdd(p, &pWriter, 1,
+ rc = fts3SegWriterAdd(p, &pWriter, 1,
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
}
if( rc!=SQLITE_OK ) goto finished;
- assert( pWriter || bIgnoreEmpty );
+ assert_fts3_nc( pWriter || bIgnoreEmpty );
if( iLevel!=FTS3_SEGCURSOR_PENDING ){
rc = fts3DeleteSegdir(
@@ -156416,13 +180394,13 @@ static int fts3SegmentMerge(
}
-/*
-** Flush the contents of pendingTerms to level 0 segments.
+/*
+** Flush the contents of pendingTerms to level 0 segments.
*/
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
int rc = SQLITE_OK;
int i;
-
+
for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
@@ -156477,14 +180455,16 @@ static void fts3DecodeIntArray(
const char *zBuf, /* The BLOB containing the varints */
int nBuf /* size of the BLOB */
){
- int i, j;
- UNUSED_PARAMETER(nBuf);
- for(i=j=0; i<N; i++){
- sqlite3_int64 x;
- j += sqlite3Fts3GetVarint(&zBuf[j], &x);
- assert(j<=nBuf);
- a[i] = (u32)(x & 0xffffffff);
+ int i = 0;
+ if( nBuf && (zBuf[nBuf-1]&0x80)==0 ){
+ int j;
+ for(i=j=0; i<N && j<nBuf; i++){
+ sqlite3_int64 x;
+ j += sqlite3Fts3GetVarint(&zBuf[j], &x);
+ a[i] = (u32)(x & 0xffffffff);
+ }
}
+ while( i<N ) a[i++] = 0;
}
/*
@@ -156503,7 +180483,7 @@ static void fts3InsertDocsize(
int rc; /* Result code from subfunctions */
if( *pRC ) return;
- pBlob = sqlite3_malloc( 10*p->nColumn );
+ pBlob = sqlite3_malloc64( 10*(sqlite3_int64)p->nColumn );
if( pBlob==0 ){
*pRC = SQLITE_NOMEM;
return;
@@ -156524,7 +180504,7 @@ static void fts3InsertDocsize(
/*
** Record 0 of the %_stat table contains a blob consisting of N varints,
** where N is the number of user defined columns in the fts3 table plus
-** two. If nCol is the number of user defined columns, then values of the
+** two. If nCol is the number of user defined columns, then values of the
** varints are set as follows:
**
** Varint 0: Total number of rows in the table.
@@ -156553,7 +180533,7 @@ static void fts3UpdateDocTotals(
const int nStat = p->nColumn+2;
if( *pRC ) return;
- a = sqlite3_malloc( (sizeof(u32)+10)*nStat );
+ a = sqlite3_malloc64( (sizeof(u32)+10)*(sqlite3_int64)nStat );
if( a==0 ){
*pRC = SQLITE_NOMEM;
return;
@@ -156604,11 +180584,12 @@ static void fts3UpdateDocTotals(
sqlite3_bind_blob(pStmt, 2, pBlob, nBlob, SQLITE_STATIC);
sqlite3_step(pStmt);
*pRC = sqlite3_reset(pStmt);
+ sqlite3_bind_null(pStmt, 2);
sqlite3_free(a);
}
/*
-** Merge the entire database so that there is one segment for each
+** Merge the entire database so that there is one segment for each
** iIndex/iLangid combination.
*/
static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
@@ -156616,7 +180597,10 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
int rc;
sqlite3_stmt *pAllLangid = 0;
- rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ rc = sqlite3Fts3PendingTermsFlush(p);
+ if( rc==SQLITE_OK ){
+ rc = fts3SqlStmt(p, SQL_SELECT_ALL_LANGID, &pAllLangid, 0);
+ }
if( rc==SQLITE_OK ){
int rc2;
sqlite3_bind_int(pAllLangid, 1, p->iPrevLangid);
@@ -156637,7 +180621,6 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
}
sqlite3Fts3SegmentsClose(p);
- sqlite3Fts3PendingTermsClear(p);
return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
}
@@ -156647,7 +180630,7 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
**
** INSERT INTO <tbl>(<tbl>) VALUES('rebuild');
**
-** The entire FTS index is discarded and rebuilt. If the table is one
+** The entire FTS index is discarded and rebuilt. If the table is one
** created using the content=xxx option, then the new index is based on
** the current contents of the xxx table. Otherwise, it is rebuilt based
** on the contents of the %_content table.
@@ -156673,8 +180656,8 @@ static int fts3DoRebuild(Fts3Table *p){
}
if( rc==SQLITE_OK ){
- int nByte = sizeof(u32) * (p->nColumn+1)*3;
- aSz = (u32 *)sqlite3_malloc(nByte);
+ sqlite3_int64 nByte = sizeof(u32) * ((sqlite3_int64)p->nColumn+1)*3;
+ aSz = (u32 *)sqlite3_malloc64(nByte);
if( aSz==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -156727,9 +180710,9 @@ static int fts3DoRebuild(Fts3Table *p){
/*
-** This function opens a cursor used to read the input data for an
+** This function opens a cursor used to read the input data for an
** incremental merge operation. Specifically, it opens a cursor to scan
-** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute
+** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute
** level iAbsLevel.
*/
static int fts3IncrmergeCsr(
@@ -156739,13 +180722,13 @@ static int fts3IncrmergeCsr(
Fts3MultiSegReader *pCsr /* Cursor object to populate */
){
int rc; /* Return Code */
- sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
- int nByte; /* Bytes allocated at pCsr->apSegment[] */
+ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
+ sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */
/* Allocate space for the Fts3MultiSegReader.aCsr[] array */
memset(pCsr, 0, sizeof(*pCsr));
nByte = sizeof(Fts3SegReader *) * nSeg;
- pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc(nByte);
+ pCsr->apSegment = (Fts3SegReader **)sqlite3_malloc64(nByte);
if( pCsr->apSegment==0 ){
rc = SQLITE_NOMEM;
@@ -156794,7 +180777,7 @@ struct Blob {
};
/*
-** This structure is used to build up buffers containing segment b-tree
+** This structure is used to build up buffers containing segment b-tree
** nodes (blocks).
*/
struct NodeWriter {
@@ -156863,12 +180846,12 @@ static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
/*
** Attempt to advance the node-reader object passed as the first argument to
-** the next entry on the node.
+** the next entry on the node.
**
-** Return an error code if an error occurs (SQLITE_NOMEM is possible).
+** Return an error code if an error occurs (SQLITE_NOMEM is possible).
** Otherwise return SQLITE_OK. If there is no next entry on the node
** (e.g. because the current entry is the last) set NodeReader->aNode to
-** NULL to indicate EOF. Otherwise, populate the NodeReader structure output
+** NULL to indicate EOF. Otherwise, populate the NodeReader structure output
** variables for the new entry.
*/
static int nodeReaderNext(NodeReader *p){
@@ -156888,6 +180871,9 @@ static int nodeReaderNext(NodeReader *p){
}
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);
+ if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){
+ return FTS_CORRUPT_VTAB;
+ }
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
if( rc==SQLITE_OK ){
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
@@ -156895,14 +180881,16 @@ static int nodeReaderNext(NodeReader *p){
p->iOff += nSuffix;
if( p->iChild==0 ){
p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
+ if( (p->nNode-p->iOff)<p->nDoclist ){
+ return FTS_CORRUPT_VTAB;
+ }
p->aDoclist = &p->aNode[p->iOff];
p->iOff += p->nDoclist;
}
}
}
- assert( p->iOff<=p->nNode );
-
+ assert_fts3_nc( p->iOff<=p->nNode );
return rc;
}
@@ -156916,7 +180904,7 @@ static void nodeReaderRelease(NodeReader *p){
/*
** Initialize a node-reader object to read the node in buffer aNode/nNode.
**
-** If successful, SQLITE_OK is returned and the NodeReader object set to
+** If successful, SQLITE_OK is returned and the NodeReader object set to
** point to the first entry on the node (if any). Otherwise, an SQLite
** error code is returned.
*/
@@ -156926,14 +180914,14 @@ static int nodeReaderInit(NodeReader *p, const char *aNode, int nNode){
p->nNode = nNode;
/* Figure out if this is a leaf or an internal node. */
- if( p->aNode[0] ){
+ if( aNode && aNode[0] ){
/* An internal node. */
p->iOff = 1 + sqlite3Fts3GetVarint(&p->aNode[1], &p->iChild);
}else{
p->iOff = 1;
}
- return nodeReaderNext(p);
+ return aNode ? nodeReaderNext(p) : SQLITE_OK;
}
/*
@@ -156965,17 +180953,18 @@ static int fts3IncrmergePush(
int nSpace;
/* Figure out how much space the key will consume if it is written to
- ** the current node of layer iLayer. Due to the prefix compression,
+ ** the current node of layer iLayer. Due to the prefix compression,
** the space required changes depending on which node the key is to
** be added to. */
nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
+ if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
nSpace = sqlite3Fts3VarintLen(nPrefix);
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
- if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){
+ if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){
/* If the current node of layer iLayer contains zero keys, or if adding
- ** the key to it will not cause it to grow to larger than nNodeSize
+ ** the key to it will not cause it to grow to larger than nNodeSize
** bytes in size, write the key here. */
Blob *pBlk = &pNode->block;
@@ -157031,12 +181020,12 @@ static int fts3IncrmergePush(
** A node header is a single 0x00 byte for a leaf node, or a height varint
** followed by the left-hand-child varint for an internal node.
**
-** The term to be appended is passed via arguments zTerm/nTerm. For a
+** The term to be appended is passed via arguments zTerm/nTerm. For a
** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal
** node, both aDoclist and nDoclist must be passed 0.
**
** If the size of the value in blob pPrev is zero, then this is the first
-** term written to the node. Otherwise, pPrev contains a copy of the
+** term written to the node. Otherwise, pPrev contains a copy of the
** previous term. Before this function returns, it is updated to contain a
** copy of zTerm/nTerm.
**
@@ -157053,7 +181042,7 @@ static int fts3AppendToNode(
const char *zTerm, /* New term to write */
int nTerm, /* Size of zTerm in bytes */
const char *aDoclist, /* Doclist (or NULL) to write */
- int nDoclist /* Size of aDoclist in bytes */
+ int nDoclist /* Size of aDoclist in bytes */
){
int rc = SQLITE_OK; /* Return code */
int bFirst = (pPrev->n==0); /* True if this is the first term written */
@@ -157063,13 +181052,14 @@ static int fts3AppendToNode(
/* Node must have already been started. There must be a doclist for a
** leaf node, and there must not be a doclist for an internal node. */
assert( pNode->n>0 );
- assert( (pNode->a[0]=='\0')==(aDoclist!=0) );
+ assert_fts3_nc( (pNode->a[0]=='\0')==(aDoclist!=0) );
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
+ if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
memcpy(pPrev->a, zTerm, nTerm);
pPrev->n = nTerm;
@@ -157127,7 +181117,7 @@ static int fts3IncrmergeAppend(
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
- /* Add the current term to the parent node. The term added to the
+ /* Add the current term to the parent node. The term added to the
** parent must:
**
** a) be greater than the largest term on the leaf node just written
@@ -157192,7 +181182,7 @@ static void fts3IncrmergeRelease(
NodeWriter *pRoot; /* NodeWriter for root node */
int rc = *pRc; /* Error code */
- /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment
+ /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment
** root node. If the segment fits entirely on a single leaf node, iRoot
** will be set to 0. If the root node is the parent of the leaves, iRoot
** will be 1. And so on. */
@@ -157210,17 +181200,17 @@ static void fts3IncrmergeRelease(
/* The entire output segment fits on a single node. Normally, this means
** the node would be stored as a blob in the "root" column of the %_segdir
- ** table. However, this is not permitted in this case. The problem is that
- ** space has already been reserved in the %_segments table, and so the
- ** start_block and end_block fields of the %_segdir table must be populated.
- ** And, by design or by accident, released versions of FTS cannot handle
+ ** table. However, this is not permitted in this case. The problem is that
+ ** space has already been reserved in the %_segments table, and so the
+ ** start_block and end_block fields of the %_segdir table must be populated.
+ ** And, by design or by accident, released versions of FTS cannot handle
** segments that fit entirely on the root node with start_block!=0.
**
- ** Instead, create a synthetic root node that contains nothing but a
+ ** Instead, create a synthetic root node that contains nothing but a
** pointer to the single content node. So that the segment consists of a
** single leaf and a single interior (root) node.
**
- ** Todo: Better might be to defer allocating space in the %_segments
+ ** Todo: Better might be to defer allocating space in the %_segments
** table until we are sure it is needed.
*/
if( iRoot==0 ){
@@ -157248,7 +181238,7 @@ static void fts3IncrmergeRelease(
/* Write the %_segdir record. */
if( rc==SQLITE_OK ){
- rc = fts3WriteSegdir(p,
+ rc = fts3WriteSegdir(p,
pWriter->iAbsLevel+1, /* level */
pWriter->iIdx, /* idx */
pWriter->iStart, /* start_block */
@@ -157279,7 +181269,7 @@ static int fts3TermCmp(
int nCmp = MIN(nLhs, nRhs);
int res;
- res = memcmp(zLhs, zRhs, nCmp);
+ res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0);
if( res==0 ) res = nLhs - nRhs;
return res;
@@ -157287,11 +181277,11 @@ static int fts3TermCmp(
/*
-** Query to see if the entry in the %_segments table with blockid iEnd is
+** Query to see if the entry in the %_segments table with blockid iEnd is
** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before
-** returning. Otherwise, set *pbRes to 0.
+** returning. Otherwise, set *pbRes to 0.
**
-** Or, if an error occurs while querying the database, return an SQLite
+** Or, if an error occurs while querying the database, return an SQLite
** error code. The final value of *pbRes is undefined in this case.
**
** This is used to test if a segment is an "appendable" segment. If it
@@ -157309,14 +181299,14 @@ static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1;
rc = sqlite3_reset(pCheck);
}
-
+
*pbRes = bRes;
return rc;
}
/*
** This function is called when initializing an incremental-merge operation.
-** It checks if the existing segment with index value iIdx at absolute level
+** It checks if the existing segment with index value iIdx at absolute level
** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the
** merge-writer object *pWriter is initialized to write to it.
**
@@ -157325,7 +181315,7 @@ static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
** * It was initially created as an appendable segment (with all required
** space pre-allocated), and
**
-** * The first key read from the input (arguments zKey and nKey) is
+** * The first key read from the input (arguments zKey and nKey) is
** greater than the largest key currently stored in the potential
** output segment.
*/
@@ -157363,6 +181353,10 @@ static int fts3IncrmergeLoad(
pWriter->bNoLeafData = (pWriter->nLeafData==0);
nRoot = sqlite3_column_bytes(pSelect, 4);
aRoot = sqlite3_column_blob(pSelect, 4);
+ if( aRoot==0 ){
+ sqlite3_reset(pSelect);
+ return nRoot ? SQLITE_NOMEM : FTS_CORRUPT_VTAB;
+ }
}else{
return sqlite3_reset(pSelect);
}
@@ -157398,6 +181392,10 @@ static int fts3IncrmergeLoad(
int i;
int nHeight = (int)aRoot[0];
NodeWriter *pNode;
+ if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){
+ sqlite3_reset(pSelect);
+ return FTS_CORRUPT_VTAB;
+ }
pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT;
pWriter->iStart = iStart;
@@ -157411,34 +181409,42 @@ static int fts3IncrmergeLoad(
pNode = &pWriter->aNodeWriter[nHeight];
pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight;
- blobGrowBuffer(&pNode->block, MAX(nRoot, p->nNodeSize), &rc);
+ blobGrowBuffer(&pNode->block,
+ MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc
+ );
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aRoot, nRoot);
pNode->block.n = nRoot;
+ memset(&pNode->block.a[nRoot], 0, FTS3_NODE_PADDING);
}
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
NodeReader reader;
pNode = &pWriter->aNodeWriter[i];
- rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
- while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
- blobGrowBuffer(&pNode->key, reader.term.n, &rc);
- if( rc==SQLITE_OK ){
- memcpy(pNode->key.a, reader.term.a, reader.term.n);
- pNode->key.n = reader.term.n;
- if( i>0 ){
- char *aBlock = 0;
- int nBlock = 0;
- pNode = &pWriter->aNodeWriter[i-1];
- pNode->iBlock = reader.iChild;
- rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
- blobGrowBuffer(&pNode->block, MAX(nBlock, p->nNodeSize), &rc);
- if( rc==SQLITE_OK ){
- memcpy(pNode->block.a, aBlock, nBlock);
- pNode->block.n = nBlock;
+ if( pNode->block.a){
+ rc = nodeReaderInit(&reader, pNode->block.a, pNode->block.n);
+ while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
+ blobGrowBuffer(&pNode->key, reader.term.n, &rc);
+ if( rc==SQLITE_OK ){
+ memcpy(pNode->key.a, reader.term.a, reader.term.n);
+ pNode->key.n = reader.term.n;
+ if( i>0 ){
+ char *aBlock = 0;
+ int nBlock = 0;
+ pNode = &pWriter->aNodeWriter[i-1];
+ pNode->iBlock = reader.iChild;
+ rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
+ blobGrowBuffer(&pNode->block,
+ MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
+ );
+ if( rc==SQLITE_OK ){
+ memcpy(pNode->block.a, aBlock, nBlock);
+ pNode->block.n = nBlock;
+ memset(&pNode->block.a[nBlock], 0, FTS3_NODE_PADDING);
+ }
+ sqlite3_free(aBlock);
}
- sqlite3_free(aBlock);
}
}
nodeReaderRelease(&reader);
@@ -157455,13 +181461,13 @@ static int fts3IncrmergeLoad(
/*
** Determine the largest segment index value that exists within absolute
** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus
-** one before returning SQLITE_OK. Or, if there are no segments at all
+** one before returning SQLITE_OK. Or, if there are no segments at all
** within level iAbsLevel, set *piIdx to zero.
**
** If an error occurs, return an SQLite error code. The final value of
** *piIdx is undefined in this case.
*/
-static int fts3IncrmergeOutputIdx(
+static int fts3IncrmergeOutputIdx(
Fts3Table *p, /* FTS Table handle */
sqlite3_int64 iAbsLevel, /* Absolute index of input segments */
int *piIdx /* OUT: Next free index at iAbsLevel+1 */
@@ -157480,7 +181486,7 @@ static int fts3IncrmergeOutputIdx(
return rc;
}
-/*
+/*
** Allocate an appendable output segment on absolute level iAbsLevel+1
** with idx value iIdx.
**
@@ -157494,7 +181500,7 @@ static int fts3IncrmergeOutputIdx(
** When an appendable segment is allocated, it is estimated that the
** maximum number of leaf blocks that may be required is the sum of the
** number of leaf blocks consumed by the input segments, plus the number
-** of input segments, multiplied by two. This value is stored in stack
+** of input segments, multiplied by two. This value is stored in stack
** variable nLeafEst.
**
** A total of 16*nLeafEst blocks are allocated when an appendable segment
@@ -157503,10 +181509,10 @@ static int fts3IncrmergeOutputIdx(
** of interior nodes that are parents of the leaf nodes start at block
** (start_block + (1 + end_block - start_block) / 16). And so on.
**
-** In the actual code below, the value "16" is replaced with the
+** In the actual code below, the value "16" is replaced with the
** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT.
*/
-static int fts3IncrmergeWriter(
+static int fts3IncrmergeWriter(
Fts3Table *p, /* Fts3 table handle */
sqlite3_int64 iAbsLevel, /* Absolute level of input segments */
int iIdx, /* Index of new output segment */
@@ -157544,7 +181550,7 @@ static int fts3IncrmergeWriter(
if( rc!=SQLITE_OK ) return rc;
/* Insert the marker in the %_segments table to make sure nobody tries
- ** to steal the space just allocated. This is also used to identify
+ ** to steal the space just allocated. This is also used to identify
** appendable segments. */
rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0);
if( rc!=SQLITE_OK ) return rc;
@@ -157561,13 +181567,13 @@ static int fts3IncrmergeWriter(
}
/*
-** Remove an entry from the %_segdir table. This involves running the
+** Remove an entry from the %_segdir table. This involves running the
** following two statements:
**
** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx
** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx
**
-** The DELETE statement removes the specific %_segdir level. The UPDATE
+** The DELETE statement removes the specific %_segdir level. The UPDATE
** statement ensures that the remaining segments have contiguously allocated
** idx values.
*/
@@ -157681,7 +181687,10 @@ static int fts3TruncateNode(
NodeReader reader; /* Reader object */
Blob prev = {0, 0, 0}; /* Previous term written to new node */
int rc = SQLITE_OK; /* Return code */
- int bLeaf = aNode[0]=='\0'; /* True for a leaf node */
+ int bLeaf; /* True for a leaf node */
+
+ if( nNode<1 ) return FTS_CORRUPT_VTAB;
+ bLeaf = aNode[0]=='\0';
/* Allocate required output space */
blobGrowBuffer(pNew, nNode, &rc);
@@ -157689,8 +181698,8 @@ static int fts3TruncateNode(
pNew->n = 0;
/* Populate new node buffer */
- for(rc = nodeReaderInit(&reader, aNode, nNode);
- rc==SQLITE_OK && reader.aNode;
+ for(rc = nodeReaderInit(&reader, aNode, nNode);
+ rc==SQLITE_OK && reader.aNode;
rc = nodeReaderNext(&reader)
){
if( pNew->n==0 ){
@@ -157717,7 +181726,7 @@ static int fts3TruncateNode(
}
/*
-** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute
+** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute
** level iAbsLevel. This may involve deleting entries from the %_segments
** table, and modifying existing entries in both the %_segments and %_segdir
** tables.
@@ -157792,6 +181801,7 @@ static int fts3TruncateSegment(
sqlite3_bind_int(pChomp, 4, iIdx);
sqlite3_step(pChomp);
rc = sqlite3_reset(pChomp);
+ sqlite3_bind_null(pChomp, 2);
}
}
@@ -157840,9 +181850,9 @@ static int fts3IncrmergeChomp(
}
*pnRem = 0;
}else{
- /* The incremental merge did not copy all the data from this
+ /* The incremental merge did not copy all the data from this
** segment to the upper level. The segment is modified in place
- ** so that it contains no keys smaller than zTerm/nTerm. */
+ ** so that it contains no keys smaller than zTerm/nTerm. */
const char *zTerm = pSeg->zTerm;
int nTerm = pSeg->nTerm;
rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm);
@@ -157871,13 +181881,14 @@ static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){
sqlite3_bind_blob(pReplace, 2, pHint->a, pHint->n, SQLITE_STATIC);
sqlite3_step(pReplace);
rc = sqlite3_reset(pReplace);
+ sqlite3_bind_null(pReplace, 2);
}
return rc;
}
/*
-** Load an incr-merge hint from the database. The incr-merge hint, if one
+** Load an incr-merge hint from the database. The incr-merge hint, if one
** exists, is stored in the rowid==1 row of the %_stat table.
**
** If successful, populate blob *pHint with the value read from the %_stat
@@ -157914,7 +181925,7 @@ static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){
/*
** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
** Otherwise, append an entry to the hint stored in blob *pHint. Each entry
-** consists of two varints, the absolute level number of the input segments
+** consists of two varints, the absolute level number of the input segments
** and the number of input segments.
**
** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs,
@@ -157935,7 +181946,7 @@ static void fts3IncrmergeHintPush(
/*
** Read the last entry (most recently pushed) from the hint blob *pHint
-** and then remove the entry. Write the two values read to *piAbsLevel and
+** and then remove the entry. Write the two values read to *piAbsLevel and
** *pnInput before returning.
**
** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does
@@ -157945,13 +181956,17 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
const int nHint = pHint->n;
int i;
- i = pHint->n-2;
+ i = pHint->n-1;
+ if( (pHint->a[i] & 0x80) ) return FTS_CORRUPT_VTAB;
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
+ if( i==0 ) return FTS_CORRUPT_VTAB;
+ i--;
while( i>0 && (pHint->a[i-1] & 0x80) ) i--;
pHint->n = i;
i += sqlite3Fts3GetVarint(&pHint->a[i], piAbsLevel);
i += fts3GetVarint32(&pHint->a[i], pnInput);
+ assert( i<=nHint );
if( i!=nHint ) return FTS_CORRUPT_VTAB;
return SQLITE_OK;
@@ -157961,10 +181976,10 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
/*
** Attempt an incremental merge that writes nMerge leaf blocks.
**
-** Incremental merges happen nMin segments at a time. The segments
-** to be merged are the nMin oldest segments (the ones with the smallest
-** values for the _segdir.idx field) in the highest level that contains
-** at least nMin segments. Multiple merges might occur in an attempt to
+** Incremental merges happen nMin segments at a time. The segments
+** to be merged are the nMin oldest segments (the ones with the smallest
+** values for the _segdir.idx field) in the highest level that contains
+** at least nMin segments. Multiple merges might occur in an attempt to
** write the quota of nMerge leaf blocks.
*/
SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
@@ -157995,7 +182010,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* Search the %_segdir table for the absolute level with the smallest
** relative level number that contains at least nMin segments, if any.
** If one is found, set iAbsLevel to the absolute level number and
- ** nSeg to nMin. If no level with at least nMin segments can be found,
+ ** nSeg to nMin. If no level with at least nMin segments can be found,
** set nSeg to -1.
*/
rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
@@ -158011,7 +182026,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* If the hint read from the %_stat table is not empty, check if the
** last entry in it specifies a relative level smaller than or equal
- ** to the level identified by the block above (if any). If so, this
+ ** to the level identified by the block above (if any). If so, this
** iteration of the loop will work on merging at the hinted level.
*/
if( rc==SQLITE_OK && hint.n ){
@@ -158021,8 +182036,14 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
rc = fts3IncrmergeHintPop(&hint, &iHintAbsLevel, &nHintSeg);
if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
+ /* Based on the scan in the block above, it is known that there
+ ** are no levels with a relative level smaller than that of
+ ** iAbsLevel with more than nSeg segments, or if nSeg is -1,
+ ** no levels with more than nMin segments. Use this to limit the
+ ** value of nHintSeg to avoid a large memory allocation in case the
+ ** merge-hint is corrupt*/
iAbsLevel = iHintAbsLevel;
- nSeg = nHintSeg;
+ nSeg = MIN(MAX(nMin,nSeg), nHintSeg);
bUseHint = 1;
bDirtyHint = 1;
}else{
@@ -158035,13 +182056,19 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* If nSeg is less that zero, then there is no level with at least
** nMin segments and no hint in the %_stat table. No work to do.
** Exit early in this case. */
- if( nSeg<0 ) break;
+ if( nSeg<=0 ) break;
+
+ assert( nMod<=0x7FFFFFFF );
+ if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){
+ rc = FTS_CORRUPT_VTAB;
+ break;
+ }
- /* Open a cursor to iterate through the contents of the oldest nSeg
- ** indexes of absolute level iAbsLevel. If this cursor is opened using
+ /* Open a cursor to iterate through the contents of the oldest nSeg
+ ** indexes of absolute level iAbsLevel. If this cursor is opened using
** the 'hint' parameters, it is possible that there are less than nSeg
** segments available in level iAbsLevel. In this case, no work is
- ** done on iAbsLevel - fall through to the next iteration of the loop
+ ** done on iAbsLevel - fall through to the next iteration of the loop
** to start work on some other level. */
memset(pWriter, 0, nAlloc);
pFilter->flags = FTS3_SEGMENT_REQUIRE_POS;
@@ -158063,8 +182090,15 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
}
if( SQLITE_OK==rc && pCsr->nSegment==nSeg
&& SQLITE_OK==(rc = sqlite3Fts3SegReaderStart(p, pCsr, pFilter))
- && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pCsr))
){
+ int bEmpty = 0;
+ rc = sqlite3Fts3SegReaderStep(p, pCsr);
+ if( rc==SQLITE_OK ){
+ bEmpty = 1;
+ }else if( rc!=SQLITE_ROW ){
+ sqlite3Fts3SegReaderFinish(pCsr);
+ break;
+ }
if( bUseHint && iIdx>0 ){
const char *zKey = pCsr->zTerm;
int nKey = pCsr->nTerm;
@@ -158075,11 +182109,13 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
if( rc==SQLITE_OK && pWriter->nLeafEst ){
fts3LogMerge(nSeg, iAbsLevel);
- do {
- rc = fts3IncrmergeAppend(p, pWriter, pCsr);
- if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
- if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
- }while( rc==SQLITE_ROW );
+ if( bEmpty==0 ){
+ do {
+ rc = fts3IncrmergeAppend(p, pWriter, pCsr);
+ if( rc==SQLITE_OK ) rc = sqlite3Fts3SegReaderStep(p, pCsr);
+ if( pWriter->nWork>=nRem && rc==SQLITE_ROW ) rc = SQLITE_OK;
+ }while( rc==SQLITE_ROW );
+ }
/* Update or delete the input segments */
if( rc==SQLITE_OK ){
@@ -158118,11 +182154,14 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
** Convert the text beginning at *pz into an integer and return
** its value. Advance *pz to point to the first character past
** the integer.
+**
+** This function used for parameters to merge= and incrmerge=
+** commands.
*/
static int fts3Getint(const char **pz){
const char *z = *pz;
int i = 0;
- while( (*z)>='0' && (*z)<='9' ) i = 10*i + *(z++) - '0';
+ while( (*z)>='0' && (*z)<='9' && i<214748363 ) i = 10*i + *(z++) - '0';
*pz = z;
return i;
}
@@ -158141,7 +182180,7 @@ static int fts3DoIncrmerge(
const char *zParam /* Nul-terminated string containing "A,B" */
){
int rc;
- int nMin = (FTS3_MERGE_COUNT / 2);
+ int nMin = (MergeCount(p) / 2);
int nMerge = 0;
const char *z = zParam;
@@ -158186,7 +182225,7 @@ static int fts3DoAutoincrmerge(
int rc = SQLITE_OK;
sqlite3_stmt *pStmt = 0;
p->nAutoincrmerge = fts3Getint(&zParam);
- if( p->nAutoincrmerge==1 || p->nAutoincrmerge>FTS3_MERGE_COUNT ){
+ if( p->nAutoincrmerge==1 || p->nAutoincrmerge>MergeCount(p) ){
p->nAutoincrmerge = 8;
}
if( !p->bHasStat ){
@@ -158269,12 +182308,12 @@ static u64 fts3ChecksumIndex(
i64 iDocid = 0;
i64 iCol = 0;
- i64 iPos = 0;
+ u64 iPos = 0;
pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
while( pCsr<pEnd ){
- i64 iVal = 0;
- pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
+ u64 iVal = 0;
+ pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
if( pCsr<pEnd ){
if( iVal==0 || iVal==1 ){
iCol = 0;
@@ -158282,8 +182321,12 @@ static u64 fts3ChecksumIndex(
if( iVal ){
pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
}else{
- pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
- iDocid += iVal;
+ pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
+ if( p->bDescIdx ){
+ iDocid = (i64)((u64)iDocid - iVal);
+ }else{
+ iDocid = (i64)((u64)iDocid + iVal);
+ }
}
}else{
iPos += (iVal - 2);
@@ -158308,7 +182351,7 @@ static u64 fts3ChecksumIndex(
** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk
** to false before returning.
**
-** If an error occurs (e.g. an OOM or IO error), return an SQLite error
+** If an error occurs (e.g. an OOM or IO error), return an SQLite error
** code. The final value of *pbOk is undefined in this case.
*/
static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
@@ -158339,7 +182382,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule;
sqlite3_stmt *pStmt = 0;
char *zSql;
-
+
zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
if( !zSql ){
rc = SQLITE_NOMEM;
@@ -158356,10 +182399,9 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
if( p->abNotindexed[iCol]==0 ){
const char *zText = (const char *)sqlite3_column_text(pStmt, iCol+1);
- int nText = sqlite3_column_bytes(pStmt, iCol+1);
sqlite3_tokenizer_cursor *pT = 0;
- rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, nText,&pT);
+ rc = sqlite3Fts3OpenTokenizer(p->pTokenizer, iLang, zText, -1, &pT);
while( rc==SQLITE_OK ){
char const *zToken; /* Buffer containing token */
int nToken = 0; /* Number of bytes in token */
@@ -158399,7 +182441,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
** the FTS index are correct, return SQLITE_OK. Or, if the contents of the
** FTS index are incorrect, return SQLITE_CORRUPT_VTAB.
**
-** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite
+** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite
** error code.
**
** The integrity-check works as follows. For each token and indexed token
@@ -158408,7 +182450,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
**
** + The index number (0 for the main index, 1 for the first prefix
** index etc.),
-** + The token (or token prefix) text itself,
+** + The token (or token prefix) text itself,
** + The language-id of the row it appears in,
** + The docid of the row it appears in,
** + The column it appears in, and
@@ -158419,7 +182461,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
**
** The integrity-check code calculates the same checksum in two ways:
**
-** 1. By scanning the contents of the FTS index, and
+** 1. By scanning the contents of the FTS index, and
** 2. By scanning and tokenizing the content table.
**
** If the two checksums are identical, the integrity-check is deemed to have
@@ -158440,11 +182482,11 @@ static int fts3DoIntegrityCheck(
**
** "INSERT INTO tbl(tbl) VALUES(<expr>)"
**
-** Argument pVal contains the result of <expr>. Currently the only
+** Argument pVal contains the result of <expr>. Currently the only
** meaningful value to insert is the text 'optimize'.
*/
static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
- int rc; /* Return Code */
+ int rc = SQLITE_ERROR; /* Return Code */
const char *zVal = (const char *)sqlite3_value_text(pVal);
int nVal = sqlite3_value_bytes(pVal);
@@ -158460,21 +182502,27 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
-#ifdef SQLITE_TEST
- }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
- p->nNodeSize = atoi(&zVal[9]);
- rc = SQLITE_OK;
- }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
- p->nMaxPendingData = atoi(&zVal[11]);
- rc = SQLITE_OK;
- }else if( nVal>21 && 0==sqlite3_strnicmp(zVal, "test-no-incr-doclist=", 21) ){
- p->bNoIncrDoclist = atoi(&zVal[21]);
- rc = SQLITE_OK;
-#endif
+#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
}else{
- rc = SQLITE_ERROR;
+ int v;
+ if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
+ v = atoi(&zVal[9]);
+ if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v;
+ rc = SQLITE_OK;
+ }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
+ v = atoi(&zVal[11]);
+ if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v;
+ rc = SQLITE_OK;
+ }else if( nVal>21 && 0==sqlite3_strnicmp(zVal,"test-no-incr-doclist=",21) ){
+ p->bNoIncrDoclist = atoi(&zVal[21]);
+ rc = SQLITE_OK;
+ }else if( nVal>11 && 0==sqlite3_strnicmp(zVal,"mergecount=",11) ){
+ v = atoi(&zVal[11]);
+ if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
+ rc = SQLITE_OK;
+ }
+#endif
}
-
return rc;
}
@@ -158492,7 +182540,7 @@ SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){
}
/*
-** Free all entries in the pCsr->pDeffered list. Entries are added to
+** Free all entries in the pCsr->pDeffered list. Entries are added to
** this list using sqlite3Fts3DeferToken().
*/
SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){
@@ -158520,14 +182568,14 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
int i; /* Used to iterate through table columns */
sqlite3_int64 iDocid; /* Docid of the row pCsr points to */
Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */
-
+
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
sqlite3_tokenizer *pT = p->pTokenizer;
sqlite3_tokenizer_module const *pModule = pT->pModule;
-
+
assert( pCsr->isRequireSeek==0 );
iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
-
+
for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
if( p->abNotindexed[i]==0 ){
const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
@@ -158568,8 +182616,8 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
}
SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
- Fts3DeferredToken *p,
- char **ppData,
+ Fts3DeferredToken *p,
+ char **ppData,
int *pnData
){
char *pRet;
@@ -158589,7 +182637,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
*pnData = p->pList->nData - nSkip;
*ppData = pRet;
-
+
memcpy(pRet, &p->pList->aData[nSkip], *pnData);
return SQLITE_OK;
}
@@ -158609,7 +182657,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
}
memset(pDeferred, 0, sizeof(*pDeferred));
pDeferred->pToken = pToken;
- pDeferred->pNext = pCsr->pDeferred;
+ pDeferred->pNext = pCsr->pDeferred;
pDeferred->iCol = iCol;
pCsr->pDeferred = pDeferred;
@@ -158626,8 +182674,8 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
** of subsiduary data structures accordingly.
*/
static int fts3DeleteByRowid(
- Fts3Table *p,
- sqlite3_value *pRowid,
+ Fts3Table *p,
+ sqlite3_value *pRowid,
int *pnChng, /* IN/OUT: Decrement if row is deleted */
u32 *aSzDel
){
@@ -158665,14 +182713,14 @@ static int fts3DeleteByRowid(
** This function does the work for the xUpdate method of FTS3 virtual
** tables. The schema of the virtual table being:
**
-** CREATE TABLE <table name>(
+** CREATE TABLE <table name>(
** <user columns>,
-** <table name> HIDDEN,
-** docid HIDDEN,
+** <table name> HIDDEN,
+** docid HIDDEN,
** <langid> HIDDEN
** );
**
-**
+**
*/
SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
sqlite3_vtab *pVtab, /* FTS3 vtab object */
@@ -158682,7 +182730,6 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
){
Fts3Table *p = (Fts3Table *)pVtab;
int rc = SQLITE_OK; /* Return Code */
- int isRemove = 0; /* True for an UPDATE or DELETE */
u32 *aSzIns = 0; /* Sizes of inserted documents */
u32 *aSzDel = 0; /* Sizes of deleted documents */
int nChng = 0; /* Net change in number of documents */
@@ -158693,7 +182740,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
assert( p->bHasStat==0 || p->bHasStat==1 );
assert( p->pSegments==0 );
- assert(
+ assert(
nArg==1 /* DELETE operations */
|| nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
);
@@ -158702,9 +182749,9 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
**
** 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
+ 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;
@@ -158716,7 +182763,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
}
/* Allocate space to hold the change in document sizes */
- aSzDel = sqlite3_malloc( sizeof(aSzDel[0])*(p->nColumn+1)*2 );
+ aSzDel = sqlite3_malloc64(sizeof(aSzDel[0])*((sqlite3_int64)p->nColumn+1)*2);
if( aSzDel==0 ){
rc = SQLITE_NOMEM;
goto update_out;
@@ -158743,24 +182790,24 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
pNewRowid = apVal[1];
}
- if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && (
+ 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
+ ** 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.
+ ** existing row with rowid=pNewRowid.
**
- ** Or, if the conflict mode is not REPLACE, insert the new record into
+ ** 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
+ ** 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
+ ** 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).
*/
@@ -158780,9 +182827,8 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
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;
}
-
+
/* If this is an INSERT or UPDATE operation, insert the new record. */
if( nArg>1 && rc==SQLITE_OK ){
int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]);
@@ -158792,7 +182838,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
rc = FTS_CORRUPT_VTAB;
}
}
- if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
+ if( rc==SQLITE_OK ){
rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid);
}
if( rc==SQLITE_OK ){
@@ -158815,10 +182861,10 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
return rc;
}
-/*
+/*
** Flush any data in the pending-terms hash table to disk. If successful,
-** merge all segments in the database (including the new segment, if
-** there was any data to flush) into a single segment.
+** merge all segments in the database (including the new segment, if
+** there was any data to flush) into a single segment.
*/
SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
int rc;
@@ -158874,7 +182920,7 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */
/*
-** The default value for the second argument to matchinfo().
+** The default value for the second argument to matchinfo().
*/
#define FTS3_MATCHINFO_DEFAULT "pcx"
@@ -158891,7 +182937,7 @@ struct LoadDoclistCtx {
};
/*
-** The following types are used as part of the implementation of the
+** The following types are used as part of the implementation of the
** fts3BestSnippet() routine.
*/
typedef struct SnippetIter SnippetIter;
@@ -158924,7 +182970,7 @@ struct SnippetFragment {
};
/*
-** This type is used as an fts3ExprIterate() context object while
+** This type is used as an fts3ExprIterate() context object while
** accumulating the data returned by the matchinfo() function.
*/
typedef struct MatchInfo MatchInfo;
@@ -158971,17 +183017,19 @@ struct StrBuffer {
/*
** Allocate a two-slot MatchinfoBuffer object.
*/
-static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){
+static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
MatchinfoBuffer *pRet;
- int nByte = sizeof(u32) * (2*nElem + 1) + sizeof(MatchinfoBuffer);
- int nStr = (int)strlen(zMatchinfo);
+ sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
+ + sizeof(MatchinfoBuffer);
+ sqlite3_int64 nStr = strlen(zMatchinfo);
- pRet = sqlite3_malloc(nByte + nStr+1);
+ pRet = sqlite3_malloc64(nByte + nStr+1);
if( pRet ){
memset(pRet, 0, nByte);
pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
- pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0] + sizeof(u32)*(nElem+1);
- pRet->nElem = nElem;
+ pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
+ + sizeof(u32)*((int)nElem+1);
+ pRet->nElem = (int)nElem;
pRet->zMatchinfo = ((char*)pRet) + nByte;
memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1);
pRet->aRef[0] = 1;
@@ -158993,8 +183041,8 @@ static MatchinfoBuffer *fts3MIBufferNew(int nElem, const char *zMatchinfo){
static void fts3MIBufferFree(void *p){
MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
- assert( (u32*)p==&pBuf->aMatchinfo[1]
- || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
+ assert( (u32*)p==&pBuf->aMatchinfo[1]
+ || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
);
if( (u32*)p==&pBuf->aMatchinfo[1] ){
pBuf->aRef[1] = 0;
@@ -159021,7 +183069,7 @@ static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
aOut = &p->aMatchinfo[p->nElem+2];
xRet = fts3MIBufferFree;
}else{
- aOut = (u32*)sqlite3_malloc(p->nElem * sizeof(u32));
+ aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
if( aOut ){
xRet = sqlite3_free;
if( p->bGlobal ) memcpy(aOut, &p->aMatchinfo[1], p->nElem*sizeof(u32));
@@ -159050,7 +183098,7 @@ SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
}
}
-/*
+/*
** End of MatchinfoBuffer code.
*************************************************************************/
@@ -159111,7 +183159,7 @@ static int fts3ExprIterate2(
** are part of a sub-tree that is the right-hand-side of a NOT operator.
** For each phrase node found, the supplied callback function is invoked.
**
-** If the callback function returns anything other than SQLITE_OK,
+** If the callback function returns anything other than SQLITE_OK,
** the iteration is abandoned and the error code returned immediately.
** Otherwise, SQLITE_OK is returned after a callback has been made for
** all eligible phrase nodes.
@@ -159146,11 +183194,11 @@ static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
/*
** Load the doclists for each phrase in the query associated with FTS3 cursor
-** pCsr.
+** pCsr.
**
-** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable
-** phrases in the expression (all phrases except those directly or
-** indirectly descended from the right-hand-side of a NOT operator). If
+** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable
+** phrases in the expression (all phrases except those directly or
+** indirectly descended from the right-hand-side of a NOT operator). If
** pnToken is not NULL, then it is set to the number of tokens in all
** matchable phrases of the expression.
*/
@@ -159180,7 +183228,7 @@ static int fts3ExprPhraseCount(Fts3Expr *pExpr){
}
/*
-** Advance the position list iterator specified by the first two
+** Advance the position list iterator specified by the first two
** arguments so that it points to the first element with a value greater
** than or equal to parameter iNext.
*/
@@ -159249,7 +183297,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){
}
/*
-** Retrieve information about the current candidate snippet of snippet
+** Retrieve information about the current candidate snippet of snippet
** iterator pIter.
*/
static void fts3SnippetDetails(
@@ -159272,11 +183320,12 @@ static void fts3SnippetDetails(
char *pCsr = pPhrase->pTail;
int iCsr = pPhrase->iTail;
- while( iCsr<(iStart+pIter->nSnippet) ){
+ while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){
int j;
- u64 mPhrase = (u64)1 << i;
+ u64 mPhrase = (u64)1 << (i%64);
u64 mPos = (u64)1 << (iCsr - iStart);
- assert( iCsr>=iStart );
+ assert( iCsr>=iStart && (iCsr - iStart)<=64 );
+ assert( i>=0 );
if( (mCover|mCovered)&mPhrase ){
iScore++;
}else{
@@ -159318,14 +183367,17 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
int iFirst = 0;
pPhrase->pList = pCsr;
fts3GetDeltaPosition(&pCsr, &iFirst);
- assert( iFirst>=0 );
- pPhrase->pHead = pCsr;
- pPhrase->pTail = pCsr;
- pPhrase->iHead = iFirst;
- pPhrase->iTail = iFirst;
+ if( iFirst<0 ){
+ rc = FTS_CORRUPT_VTAB;
+ }else{
+ pPhrase->pHead = pCsr;
+ pPhrase->pTail = pCsr;
+ pPhrase->iHead = iFirst;
+ pPhrase->iTail = iFirst;
+ }
}else{
assert( rc!=SQLITE_OK || (
- pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
+ pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
));
}
@@ -159333,14 +183385,14 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
}
/*
-** Select the fragment of text consisting of nFragment contiguous tokens
+** Select the fragment of text consisting of nFragment contiguous tokens
** from column iCol that represent the "best" snippet. The best snippet
** is the snippet with the highest score, where scores are calculated
** by adding:
**
** (a) +1 point for each occurrence of a matchable phrase in the snippet.
**
-** (b) +1000 points for the first occurrence of each matchable phrase in
+** (b) +1000 points for the first occurrence of each matchable phrase in
** the snippet for which the corresponding mCovered bit is not set.
**
** The selected snippet parameters are stored in structure *pFragment before
@@ -159359,7 +183411,7 @@ static int fts3BestSnippet(
int rc; /* Return Code */
int nList; /* Number of phrases in expression */
SnippetIter sIter; /* Iterates through snippet candidates */
- int nByte; /* Number of bytes of space to allocate */
+ sqlite3_int64 nByte; /* Number of bytes of space to allocate */
int iBestScore = -1; /* Best snippet score found so far */
int i; /* Loop counter */
@@ -159377,7 +183429,7 @@ static int fts3BestSnippet(
** the required space using malloc().
*/
nByte = sizeof(SnippetPhrase) * nList;
- sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc(nByte);
+ sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte);
if( !sIter.aPhrase ){
return SQLITE_NOMEM;
}
@@ -159397,11 +183449,11 @@ static int fts3BestSnippet(
/* Set the *pmSeen output variable. */
for(i=0; i<nList; i++){
if( sIter.aPhrase[i].pHead ){
- *pmSeen |= (u64)1 << i;
+ *pmSeen |= (u64)1 << (i%64);
}
}
- /* Loop through all candidate snippets. Store the best snippet in
+ /* Loop through all candidate snippets. Store the best snippet in
** *pFragment. Store its associated 'score' in iBestScore.
*/
pFragment->iCol = iCol;
@@ -159447,8 +183499,8 @@ static int fts3StringAppend(
** appended data.
*/
if( pStr->n+nAppend+1>=pStr->nAlloc ){
- int nAlloc = pStr->nAlloc+nAppend+100;
- char *zNew = sqlite3_realloc(pStr->z, nAlloc);
+ sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100;
+ char *zNew = sqlite3_realloc64(pStr->z, nAlloc);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -159473,8 +183525,8 @@ static int fts3StringAppend(
**
** ........X.....X
**
-** This function "shifts" the beginning of the snippet forward in the
-** document so that there are approximately the same number of
+** This function "shifts" the beginning of the snippet forward in the
+** document so that there are approximately the same number of
** non-highlighted terms to the right of the final highlighted term as there
** are to the left of the first highlighted term. For example, to this:
**
@@ -159482,8 +183534,8 @@ static int fts3StringAppend(
**
** This is done as part of extracting the snippet text, not when selecting
** the snippet. Snippet selection is done based on doclists only, so there
-** is no way for fts3BestSnippet() to know whether or not the document
-** actually contains terms that follow the final highlighted term.
+** is no way for fts3BestSnippet() to know whether or not the document
+** actually contains terms that follow the final highlighted term.
*/
static int fts3SnippetShift(
Fts3Table *pTab, /* FTS3 table snippet comes from */
@@ -159503,6 +183555,7 @@ static int fts3SnippetShift(
for(nLeft=0; !(hlmask & ((u64)1 << nLeft)); nLeft++);
for(nRight=0; !(hlmask & ((u64)1 << (nSnippet-1-nRight))); nRight++);
+ assert( (nSnippet-1-nRight)<=63 && (nSnippet-1-nRight)>=0 );
nDesired = (nLeft-nRight)/2;
/* Ideally, the start of the snippet should be pushed forward in the
@@ -159572,7 +183625,7 @@ static int fts3SnippetText(
int iCol = pFragment->iCol+1; /* Query column to extract text from */
sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */
sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */
-
+
zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol);
if( zDoc==0 ){
if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){
@@ -159612,7 +183665,7 @@ static int fts3SnippetText(
if( rc==SQLITE_DONE ){
/* Special case - the last token of the snippet is also the last token
** of the column. Append any punctuation that occurred between the end
- ** of the previous token and the end of the document to the output.
+ ** of the previous token and the end of the document to the output.
** Then break out of the loop. */
rc = fts3StringAppend(pOut, &zDoc[iEnd], -1);
}
@@ -159629,7 +183682,7 @@ static int fts3SnippetText(
/* Now that the shift has been done, check if the initial "..." are
** required. They are required if (a) this is not the first fragment,
- ** or (b) this fragment does not begin at position 0 of its column.
+ ** or (b) this fragment does not begin at position 0 of its column.
*/
if( rc==SQLITE_OK ){
if( iPos>0 || iFragment>0 ){
@@ -159665,8 +183718,8 @@ static int fts3SnippetText(
/*
-** This function is used to count the entries in a column-list (a
-** delta-encoded list of term offsets within a single column of a single
+** This function is used to count the entries in a column-list (a
+** delta-encoded list of term offsets within a single column of a single
** row). When this function is called, *ppCollist should point to the
** beginning of the first varint in the column-list (the varint that
** contains the position of the first matching term in the column data).
@@ -159695,7 +183748,7 @@ static int fts3ColumnlistCount(char **ppCollist){
/*
** This function gathers 'y' or 'b' data for a single phrase.
*/
-static void fts3ExprLHits(
+static int fts3ExprLHits(
Fts3Expr *pExpr, /* Phrase expression node */
MatchInfo *p /* Matchinfo context */
){
@@ -159712,7 +183765,7 @@ static void fts3ExprLHits(
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
}
- while( 1 ){
+ if( pIter ) while( 1 ){
int nHit = fts3ColumnlistCount(&pIter);
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
if( p->flag==FTS3_MATCHINFO_LHITS ){
@@ -159725,34 +183778,38 @@ static void fts3ExprLHits(
if( *pIter!=0x01 ) break;
pIter++;
pIter += fts3GetVarint32(pIter, &iCol);
+ if( iCol>=p->nCol ) return FTS_CORRUPT_VTAB;
}
+ return SQLITE_OK;
}
/*
** Gather the results for matchinfo directives 'y' and 'b'.
*/
-static void fts3ExprLHitGather(
+static int fts3ExprLHitGather(
Fts3Expr *pExpr,
MatchInfo *p
){
+ int rc = SQLITE_OK;
assert( (pExpr->pLeft==0)==(pExpr->pRight==0) );
if( pExpr->bEof==0 && pExpr->iDocid==p->pCursor->iPrevId ){
if( pExpr->pLeft ){
- fts3ExprLHitGather(pExpr->pLeft, p);
- fts3ExprLHitGather(pExpr->pRight, p);
+ rc = fts3ExprLHitGather(pExpr->pLeft, p);
+ if( rc==SQLITE_OK ) rc = fts3ExprLHitGather(pExpr->pRight, p);
}else{
- fts3ExprLHits(pExpr, p);
+ rc = fts3ExprLHits(pExpr, p);
}
}
+ return rc;
}
/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query.
+** for a single query.
**
** fts3ExprIterate() callback to load the 'global' elements of a
-** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
-** of the matchinfo array that are constant for all rows returned by the
+** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
+** of the matchinfo array that are constant for all rows returned by the
** current query.
**
** Argument pCtx is actually a pointer to a struct of type MatchInfo. This
@@ -159768,7 +183825,7 @@ static void fts3ExprLHitGather(
** at least one instance of phrase iPhrase.
**
** If the phrase pExpr consists entirely of deferred tokens, then all X and
-** Y values are set to nDoc, where nDoc is the number of documents in the
+** Y values are set to nDoc, where nDoc is the number of documents in the
** file system. This is done because the full-text index doclist is required
** to calculate these values properly, and the full-text index doclist is
** not available for deferred tokens.
@@ -159786,7 +183843,7 @@ static int fts3ExprGlobalHitsCb(
/*
** fts3ExprIterate() callback used to collect the "local" part of the
-** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
+** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
** array that are different for each row returned by the query.
*/
static int fts3ExprLocalHitsCb(
@@ -159813,7 +183870,7 @@ static int fts3ExprLocalHitsCb(
}
static int fts3MatchinfoCheck(
- Fts3Table *pTab,
+ Fts3Table *pTab,
char cArg,
char **pzErr
){
@@ -159833,13 +183890,13 @@ static int fts3MatchinfoCheck(
return SQLITE_ERROR;
}
-static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
- int nVal; /* Number of integers output by cArg */
+static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
+ size_t nVal; /* Number of integers output by cArg */
switch( cArg ){
case FTS3_MATCHINFO_NDOC:
- case FTS3_MATCHINFO_NPHRASE:
- case FTS3_MATCHINFO_NCOL:
+ case FTS3_MATCHINFO_NPHRASE:
+ case FTS3_MATCHINFO_NCOL:
nVal = 1;
break;
@@ -159870,11 +183927,15 @@ static int fts3MatchinfoSelectDoctotal(
Fts3Table *pTab,
sqlite3_stmt **ppStmt,
sqlite3_int64 *pnDoc,
- const char **paLen
+ const char **paLen,
+ const char **ppEnd
){
sqlite3_stmt *pStmt;
const char *a;
+ const char *pEnd;
sqlite3_int64 nDoc;
+ int n;
+
if( !*ppStmt ){
int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
@@ -159883,17 +183944,25 @@ static int fts3MatchinfoSelectDoctotal(
pStmt = *ppStmt;
assert( sqlite3_data_count(pStmt)==1 );
+ n = sqlite3_column_bytes(pStmt, 0);
a = sqlite3_column_blob(pStmt, 0);
- a += sqlite3Fts3GetVarint(a, &nDoc);
- if( nDoc==0 ) return FTS_CORRUPT_VTAB;
- *pnDoc = (u32)nDoc;
+ if( a==0 ){
+ return FTS_CORRUPT_VTAB;
+ }
+ pEnd = a + n;
+ a += sqlite3Fts3GetVarintBounded(a, pEnd, &nDoc);
+ if( nDoc<=0 || a>pEnd ){
+ return FTS_CORRUPT_VTAB;
+ }
+ *pnDoc = nDoc;
if( paLen ) *paLen = a;
+ if( ppEnd ) *ppEnd = pEnd;
return SQLITE_OK;
}
/*
-** An instance of the following structure is used to store state while
+** An instance of the following structure is used to store state while
** iterating through a multi-column position-list corresponding to the
** hits for a single phrase on a single row in order to calculate the
** values for a matchinfo() FTS3_MATCHINFO_LCS request.
@@ -159906,7 +183975,7 @@ struct LcsIterator {
int iPos; /* Current position */
};
-/*
+/*
** If LcsIterator.iCol is set to the following value, the iterator has
** finished iterating through all offsets for all columns.
*/
@@ -159943,16 +184012,16 @@ static int fts3LcsIteratorAdvance(LcsIterator *pIter){
pIter->pRead = pRead;
return rc;
}
-
+
/*
-** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag.
+** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag.
**
** If the call is successful, the longest-common-substring lengths for each
-** column are written into the first nCol elements of the pInfo->aMatchinfo[]
+** column are written into the first nCol elements of the pInfo->aMatchinfo[]
** array before returning. SQLITE_OK is returned in this case.
**
** Otherwise, if an error occurs, an SQLite error code is returned and the
-** data written to the first nCol elements of pInfo->aMatchinfo[] is
+** data written to the first nCol elements of pInfo->aMatchinfo[] is
** undefined.
*/
static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
@@ -159960,11 +184029,12 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
int i;
int iCol;
int nToken = 0;
+ int rc = SQLITE_OK;
/* Allocate and populate the array of LcsIterator objects. The array
** contains one element for each matchable phrase in the query.
**/
- aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
+ aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase);
if( !aIter ) return SQLITE_NOMEM;
memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
(void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
@@ -159980,13 +184050,16 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
int nLive = 0; /* Number of iterators in aIter not at EOF */
for(i=0; i<pInfo->nPhrase; i++){
- int rc;
LcsIterator *pIt = &aIter[i];
rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc!=SQLITE_OK ) goto matchinfo_lcs_out;
if( pIt->pRead ){
pIt->iPos = pIt->iPosOffset;
- fts3LcsIteratorAdvance(&aIter[i]);
+ fts3LcsIteratorAdvance(pIt);
+ if( pIt->pRead==0 ){
+ rc = FTS_CORRUPT_VTAB;
+ goto matchinfo_lcs_out;
+ }
nLive++;
}
}
@@ -160018,13 +184091,14 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
pInfo->aMatchinfo[iCol] = nLcs;
}
+ matchinfo_lcs_out:
sqlite3_free(aIter);
- return SQLITE_OK;
+ return rc;
}
/*
** Populate the buffer pInfo->aMatchinfo[] with an array of integers to
-** be returned by the matchinfo() function. Argument zArg contains the
+** be returned by the matchinfo() function. Argument zArg contains the
** format string passed as the second argument to matchinfo (or the
** default value "pcx" if no second argument was specified). The format
** string has already been validated and the pInfo->aMatchinfo[] array
@@ -160035,7 +184109,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS)
** have already been populated.
**
-** Return SQLITE_OK if successful, or an SQLite error code if an error
+** Return SQLITE_OK if successful, or an SQLite error code if an error
** occurs. If a value other than SQLITE_OK is returned, the state the
** pInfo->aMatchinfo[] buffer is left in is undefined.
*/
@@ -160060,27 +184134,32 @@ static int fts3MatchinfoValues(
case FTS3_MATCHINFO_NCOL:
if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol;
break;
-
+
case FTS3_MATCHINFO_NDOC:
if( bGlobal ){
sqlite3_int64 nDoc = 0;
- rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0, 0);
pInfo->aMatchinfo[0] = (u32)nDoc;
}
break;
- case FTS3_MATCHINFO_AVGLENGTH:
+ case FTS3_MATCHINFO_AVGLENGTH:
if( bGlobal ){
sqlite3_int64 nDoc; /* Number of rows in table */
const char *a; /* Aggregate column length array */
+ const char *pEnd; /* First byte past end of length array */
- rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a, &pEnd);
if( rc==SQLITE_OK ){
int iCol;
for(iCol=0; iCol<pInfo->nCol; iCol++){
u32 iVal;
sqlite3_int64 nToken;
a += sqlite3Fts3GetVarint(a, &nToken);
+ if( a>pEnd ){
+ rc = SQLITE_CORRUPT_VTAB;
+ break;
+ }
iVal = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
pInfo->aMatchinfo[iCol] = iVal;
}
@@ -160094,9 +184173,14 @@ static int fts3MatchinfoValues(
if( rc==SQLITE_OK ){
int iCol;
const char *a = sqlite3_column_blob(pSelectDocsize, 0);
+ const char *pEnd = a + sqlite3_column_bytes(pSelectDocsize, 0);
for(iCol=0; iCol<pInfo->nCol; iCol++){
sqlite3_int64 nToken;
- a += sqlite3Fts3GetVarint(a, &nToken);
+ a += sqlite3Fts3GetVarintBounded(a, pEnd, &nToken);
+ if( a>pEnd ){
+ rc = SQLITE_CORRUPT_VTAB;
+ break;
+ }
pInfo->aMatchinfo[iCol] = (u32)nToken;
}
}
@@ -160113,9 +184197,9 @@ static int fts3MatchinfoValues(
case FTS3_MATCHINFO_LHITS_BM:
case FTS3_MATCHINFO_LHITS: {
- int nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
+ size_t nZero = fts3MatchinfoSize(pInfo, zArg[i]) * sizeof(u32);
memset(pInfo->aMatchinfo, 0, nZero);
- fts3ExprLHitGather(pCsr->pExpr, pInfo);
+ rc = fts3ExprLHitGather(pCsr->pExpr, pInfo);
break;
}
@@ -160127,7 +184211,7 @@ static int fts3MatchinfoValues(
if( rc!=SQLITE_OK ) break;
if( bGlobal ){
if( pCsr->pDeferred ){
- rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
+ rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
if( rc!=SQLITE_OK ) break;
}
rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
@@ -160148,7 +184232,7 @@ static int fts3MatchinfoValues(
/*
-** Populate pCsr->aMatchinfo[] with data for the current row. The
+** Populate pCsr->aMatchinfo[] with data for the current row. The
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
*/
static void fts3GetMatchinfo(
@@ -160168,8 +184252,8 @@ static void fts3GetMatchinfo(
sInfo.pCursor = pCsr;
sInfo.nCol = pTab->nColumn;
- /* If there is cached matchinfo() data, but the format string for the
- ** cache does not match the format string for this request, discard
+ /* If there is cached matchinfo() data, but the format string for the
+ ** cache does not match the format string for this request, discard
** the cached data. */
if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
@@ -160177,12 +184261,12 @@ static void fts3GetMatchinfo(
}
/* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the
- ** matchinfo function has been called for this query. In this case
+ ** matchinfo function has been called for this query. In this case
** allocate the array used to accumulate the matchinfo data and
** initialize those elements that are constant for every row.
*/
if( pCsr->pMIBuffer==0 ){
- int nMatchinfo = 0; /* Number of u32 elements in match-info */
+ size_t nMatchinfo = 0; /* Number of u32 elements in match-info */
int i; /* Used to iterate through zArg */
/* Determine the number of phrases in the query */
@@ -160252,7 +184336,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
/* The returned text includes up to four fragments of text extracted from
** the data in the current row. The first iteration of the for(...) loop
- ** below attempts to locate a single fragment of text nToken tokens in
+ ** below attempts to locate a single fragment of text nToken tokens in
** size that contains at least one instance of all phrases in the query
** expression that appear in the current row. If such a fragment of text
** cannot be found, the second iteration of the loop attempts to locate
@@ -160267,6 +184351,10 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
return;
}
+ /* Limit the snippet length to 64 tokens. */
+ if( nToken<-64 ) nToken = -64;
+ if( nToken>+64 ) nToken = +64;
+
for(nSnippet=1; 1; nSnippet++){
int iSnip; /* Loop counter 0..nSnippet-1 */
@@ -160319,7 +184407,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
assert( nFToken>0 );
for(i=0; i<nSnippet && rc==SQLITE_OK; i++){
- rc = fts3SnippetText(pCsr, &aSnippet[i],
+ rc = fts3SnippetText(pCsr, &aSnippet[i],
i, (i==nSnippet-1), nFToken, zStart, zEnd, zEllipsis, &res
);
}
@@ -160368,7 +184456,7 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
nTerm = pExpr->pPhrase->nToken;
if( pList ){
fts3GetDeltaPosition(&pList, &iPos);
- assert( iPos>=0 );
+ assert_fts3_nc( iPos>=0 );
}
for(iTerm=0; iTerm<nTerm; iTerm++){
@@ -160409,7 +184497,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
if( rc!=SQLITE_OK ) goto offsets_out;
/* Allocate the array of TermOffset iterators. */
- sCtx.aTerm = (TermOffset *)sqlite3_malloc(sizeof(TermOffset)*nToken);
+ sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken);
if( 0==sCtx.aTerm ){
rc = SQLITE_NOMEM;
goto offsets_out;
@@ -160417,7 +184505,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
sCtx.iDocid = pCsr->iPrevId;
sCtx.pCsr = pCsr;
- /* Loop through the table columns, appending offset information to
+ /* Loop through the table columns, appending offset information to
** string-buffer res for each column.
*/
for(iCol=0; iCol<pTab->nColumn; iCol++){
@@ -160430,7 +184518,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
const char *zDoc;
int nDoc;
- /* Initialize the contents of sCtx.aTerm[] for column iCol. There is
+ /* Initialize the contents of sCtx.aTerm[] for column iCol. There is
** no way that this operation can fail, so the return code from
** fts3ExprIterate() can be discarded.
*/
@@ -160438,11 +184526,11 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
sCtx.iTerm = 0;
(void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
- /* Retreive the text stored in column iCol. If an SQL NULL is stored
+ /* Retreive the text stored in column iCol. If an SQL NULL is stored
** in column iCol, jump immediately to the next iteration of the loop.
** If an OOM occurs while retrieving the data (this can happen if SQLite
- ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM
- ** to the caller.
+ ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM
+ ** to the caller.
*/
zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1);
nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
@@ -160478,7 +184566,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
/* All offsets for this column have been gathered. */
rc = SQLITE_DONE;
}else{
- assert( iCurrent<=iMinPos );
+ assert_fts3_nc( iCurrent<=iMinPos );
if( 0==(0xFE&*pTerm->pList) ){
pTerm->pList = 0;
}else{
@@ -160489,7 +184577,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
}
if( rc==SQLITE_OK ){
char aBuffer[64];
- sqlite3_snprintf(sizeof(aBuffer), aBuffer,
+ sqlite3_snprintf(sizeof(aBuffer), aBuffer,
"%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
);
rc = fts3StringAppend(&res, aBuffer, -1);
@@ -160634,7 +184722,7 @@ typedef struct unicode_cursor unicode_cursor;
struct unicode_tokenizer {
sqlite3_tokenizer base;
- int bRemoveDiacritic;
+ int eRemoveDiacritic;
int nException;
int *aiException;
};
@@ -160670,7 +184758,7 @@ static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){
**
** For each codepoint in the zIn/nIn string, this function checks if the
** sqlite3FtsUnicodeIsalnum() function already returns the desired result.
-** If so, no action is taken. Otherwise, the codepoint is added to the
+** If so, no action is taken. Otherwise, the codepoint is added to the
** unicode_tokenizer.aiException[] array. For the purposes of tokenization,
** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all
** codepoints in the aiException[] array.
@@ -160688,16 +184776,16 @@ static int unicodeAddExceptions(
){
const unsigned char *z = (const unsigned char *)zIn;
const unsigned char *zTerm = &z[nIn];
- int iCode;
+ unsigned int iCode;
int nEntry = 0;
assert( bAlnum==0 || bAlnum==1 );
while( z<zTerm ){
READ_UTF8(z, zTerm, iCode);
- assert( (sqlite3FtsUnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
- if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum
- && sqlite3FtsUnicodeIsdiacritic(iCode)==0
+ assert( (sqlite3FtsUnicodeIsalnum((int)iCode) & 0xFFFFFFFE)==0 );
+ if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
+ && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
){
nEntry++;
}
@@ -160707,20 +184795,20 @@ static int unicodeAddExceptions(
int *aNew; /* New aiException[] array */
int nNew; /* Number of valid entries in array aNew[] */
- aNew = sqlite3_realloc(p->aiException, (p->nException+nEntry)*sizeof(int));
+ aNew = sqlite3_realloc64(p->aiException,(p->nException+nEntry)*sizeof(int));
if( aNew==0 ) return SQLITE_NOMEM;
nNew = p->nException;
z = (const unsigned char *)zIn;
while( z<zTerm ){
READ_UTF8(z, zTerm, iCode);
- if( sqlite3FtsUnicodeIsalnum(iCode)!=bAlnum
- && sqlite3FtsUnicodeIsdiacritic(iCode)==0
+ if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
+ && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
){
int i, j;
- for(i=0; i<nNew && aNew[i]<iCode; i++);
+ for(i=0; i<nNew && aNew[i]<(int)iCode; i++);
for(j=nNew; j>i; j--) aNew[j] = aNew[j-1];
- aNew[i] = iCode;
+ aNew[i] = (int)iCode;
nNew++;
}
}
@@ -160779,17 +184867,20 @@ static int unicodeCreate(
pNew = (unicode_tokenizer *) sqlite3_malloc(sizeof(unicode_tokenizer));
if( pNew==NULL ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(unicode_tokenizer));
- pNew->bRemoveDiacritic = 1;
+ pNew->eRemoveDiacritic = 1;
for(i=0; rc==SQLITE_OK && i<nArg; i++){
const char *z = azArg[i];
int n = (int)strlen(z);
if( n==19 && memcmp("remove_diacritics=1", z, 19)==0 ){
- pNew->bRemoveDiacritic = 1;
+ pNew->eRemoveDiacritic = 1;
}
else if( n==19 && memcmp("remove_diacritics=0", z, 19)==0 ){
- pNew->bRemoveDiacritic = 0;
+ pNew->eRemoveDiacritic = 0;
+ }
+ else if( n==19 && memcmp("remove_diacritics=2", z, 19)==0 ){
+ pNew->eRemoveDiacritic = 2;
}
else if( n>=11 && memcmp("tokenchars=", z, 11)==0 ){
rc = unicodeAddExceptions(pNew, 1, &z[11], n-11);
@@ -160814,7 +184905,7 @@ static int unicodeCreate(
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is pInput[0..nBytes-1]. A cursor
-** used to incrementally tokenize this string is returned in
+** used to incrementally tokenize this string is returned in
** *ppCursor.
*/
static int unicodeOpen(
@@ -160870,7 +184961,7 @@ static int unicodeNext(
){
unicode_cursor *pCsr = (unicode_cursor *)pC;
unicode_tokenizer *p = ((unicode_tokenizer *)pCsr->base.pTokenizer);
- int iCode = 0;
+ unsigned int iCode = 0;
char *zOut;
const unsigned char *z = &pCsr->aInput[pCsr->iOff];
const unsigned char *zStart = z;
@@ -160878,11 +184969,11 @@ static int unicodeNext(
const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput];
/* Scan past any delimiter characters before the start of the next token.
- ** Return SQLITE_DONE early if this takes us all the way to the end of
+ ** Return SQLITE_DONE early if this takes us all the way to the end of
** the input. */
while( z<zTerm ){
READ_UTF8(z, zTerm, iCode);
- if( unicodeIsAlnum(p, iCode) ) break;
+ if( unicodeIsAlnum(p, (int)iCode) ) break;
zStart = z;
}
if( zStart>=zTerm ) return SQLITE_DONE;
@@ -160893,7 +184984,7 @@ static int unicodeNext(
/* Grow the output buffer if required. */
if( (zOut-pCsr->zToken)>=(pCsr->nAlloc-4) ){
- char *zNew = sqlite3_realloc(pCsr->zToken, pCsr->nAlloc+64);
+ char *zNew = sqlite3_realloc64(pCsr->zToken, pCsr->nAlloc+64);
if( !zNew ) return SQLITE_NOMEM;
zOut = &zNew[zOut - pCsr->zToken];
pCsr->zToken = zNew;
@@ -160902,7 +184993,7 @@ static int unicodeNext(
/* Write the folded case of the last character read to the output */
zEnd = z;
- iOut = sqlite3FtsUnicodeFold(iCode, p->bRemoveDiacritic);
+ iOut = sqlite3FtsUnicodeFold((int)iCode, p->eRemoveDiacritic);
if( iOut ){
WRITE_UTF8(zOut, iOut);
}
@@ -160910,8 +185001,8 @@ static int unicodeNext(
/* If the cursor is not at EOF, read the next character */
if( z>=zTerm ) break;
READ_UTF8(z, zTerm, iCode);
- }while( unicodeIsAlnum(p, iCode)
- || sqlite3FtsUnicodeIsdiacritic(iCode)
+ }while( unicodeIsAlnum(p, (int)iCode)
+ || sqlite3FtsUnicodeIsdiacritic((int)iCode)
);
/* Set the output variables and return. */
@@ -160925,7 +185016,7 @@ static int unicodeNext(
}
/*
-** Set *ppModule to a pointer to the sqlite3_tokenizer_module
+** Set *ppModule to a pointer to the sqlite3_tokenizer_module
** structure for the unicode tokenizer.
*/
SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){
@@ -160947,7 +185038,7 @@ SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const *
/************** End of fts3_unicode.c ****************************************/
/************** Begin file fts3_unicode2.c ***********************************/
/*
-** 2012 May 25
+** 2012-05-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -160980,11 +185071,11 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
** range of unicode codepoints that are not either letters or numbers (i.e.
** codepoints for which this function should return 0).
**
- ** The most significant 22 bits in each 32-bit value contain the first
+ ** The most significant 22 bits in each 32-bit value contain the first
** codepoint in the range. The least significant 10 bits are used to store
- ** the size of the range (always at least 1). In other words, the value
- ** ((C<<22) + N) represents a range of N codepoints starting with codepoint
- ** C. It is not possible to represent a range larger than 1023 codepoints
+ ** the size of the range (always at least 1). In other words, the value
+ ** ((C<<22) + N) represents a range of N codepoints starting with codepoint
+ ** C. It is not possible to represent a range larger than 1023 codepoints
** using this format.
*/
static const unsigned int aEntry[] = {
@@ -161075,9 +185166,9 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
- if( c<128 ){
- return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
- }else if( c<(1<<22) ){
+ if( (unsigned int)c<128 ){
+ return ( (aAscii[c >> 5] & ((unsigned int)1 << (c & 0x001F)))==0 );
+ }else if( (unsigned int)c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
@@ -161107,32 +185198,48 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
** E"). The resuls of passing a codepoint that corresponds to an
** uppercase letter are undefined.
*/
-static int remove_diacritic(int c){
+static int remove_diacritic(int c, int bComplex){
unsigned short aDia[] = {
- 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
- 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
- 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
- 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
- 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
- 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
- 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
- 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
- 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
- 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
- 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
- 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
- 62924, 63050, 63082, 63274, 63390,
+ 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
+ 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
+ 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
+ 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
+ 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
+ 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
+ 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
+ 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
+ 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
+ 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
+ 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
+ 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
+ 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
+ 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
+ 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
+ 63182, 63242, 63274, 63310, 63368, 63390,
};
- char aChar[] = {
- '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
- 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
- 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
- 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
- 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
- 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
- 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
- 'e', 'i', 'o', 'u', 'y',
+#define HIBIT ((unsigned char)0x80)
+ unsigned char aChar[] = {
+ '\0', 'a', 'c', 'e', 'i', 'n',
+ 'o', 'u', 'y', 'y', 'a', 'c',
+ 'd', 'e', 'e', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'n', 'o', 'r',
+ 's', 't', 'u', 'u', 'w', 'y',
+ 'z', 'o', 'u', 'a', 'i', 'o',
+ 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
+ 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
+ 'e', 'i', 'o', 'r', 'u', 's',
+ 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
+ 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', 'a', 'b',
+ 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
+ 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
+ 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
+ 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
+ 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
+ 'w', 'x', 'y', 'z', 'h', 't',
+ 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
+ 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
+ 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
};
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
@@ -161149,7 +185256,8 @@ static int remove_diacritic(int c){
}
}
assert( key>=aDia[iRes] );
- return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
+ if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
+ return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);
}
@@ -161162,8 +185270,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){
unsigned int mask1 = 0x000361F8;
if( c<768 || c>817 ) return 0;
return (c < 768+32) ?
- (mask0 & (1 << (c-768))) :
- (mask1 & (1 << (c-768-32)));
+ (mask0 & ((unsigned int)1 << (c-768))) :
+ (mask1 & ((unsigned int)1 << (c-768-32)));
}
@@ -161176,7 +185284,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int c){
** The results are undefined if the value passed to this function
** is less than zero.
*/
-SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
+SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
/* Each entry in the following array defines a rule for folding a range
** of codepoints to lower case. The rule applies to a range of nRange
** codepoints starting at codepoint iCode.
@@ -161253,33 +185361,34 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
{42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
{42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
{42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
- {65313, 14, 26},
+ {65313, 14, 26},
};
static const unsigned short aiOff[] = {
- 1, 2, 8, 15, 16, 26, 28, 32,
- 37, 38, 40, 48, 63, 64, 69, 71,
- 79, 80, 116, 202, 203, 205, 206, 207,
- 209, 210, 211, 213, 214, 217, 218, 219,
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
- 65514, 65521, 65527, 65528, 65529,
+ 1, 2, 8, 15, 16, 26, 28, 32,
+ 37, 38, 40, 48, 63, 64, 69, 71,
+ 79, 80, 116, 202, 203, 205, 206, 207,
+ 209, 210, 211, 213, 214, 217, 218, 219,
+ 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
+ 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
+ 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
+ 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
+ 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
+ 65514, 65521, 65527, 65528, 65529,
};
int ret = c;
- assert( c>=0 );
assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
if( c<128 ){
if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
}else if( c<65536 ){
+ const struct TableEntry *p;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
int iRes = -1;
+ assert( c>aEntry[0].iCode );
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
int cmp = (c - aEntry[iTest].iCode);
@@ -161290,19 +185399,19 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
iHi = iTest-1;
}
}
- assert( iRes<0 || c>=aEntry[iRes].iCode );
- if( iRes>=0 ){
- const struct TableEntry *p = &aEntry[iRes];
- if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
- ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
- assert( ret>0 );
- }
+ assert( iRes>=0 && c>=aEntry[iRes].iCode );
+ p = &aEntry[iRes];
+ if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
+ ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
+ assert( ret>0 );
}
- if( bRemoveDiacritic ) ret = remove_diacritic(ret);
+ if( eRemoveDiacritic ){
+ ret = remove_diacritic(ret, eRemoveDiacritic==2);
+ }
}
-
+
else if( c>=66560 && c<66600 ){
ret = c + 40;
}
@@ -161313,6 +185422,2640 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */
/************** End of fts3_unicode2.c ***************************************/
+/************** Begin file json1.c *******************************************/
+/*
+** 2015-08-12
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This SQLite extension implements JSON functions. The interface is
+** modeled after MySQL JSON functions:
+**
+** https://dev.mysql.com/doc/refman/5.7/en/json.html
+**
+** For the time being, all JSON is stored as pure text. (We might add
+** a JSONB type in the future which stores a binary encoding of JSON in
+** a BLOB, but there is no support for JSONB in the current implementation.
+** This implementation parses JSON text at 250 MB/s, so it is hard to see
+** how JSONB might improve on that.)
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
+#if !defined(SQLITEINT_H)
+/* #include "sqlite3ext.h" */
+#endif
+SQLITE_EXTENSION_INIT1
+/* #include <assert.h> */
+/* #include <string.h> */
+/* #include <stdlib.h> */
+/* #include <stdarg.h> */
+
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAM
+# define UNUSED_PARAM(X) (void)(X)
+#endif
+
+#ifndef LARGEST_INT64
+# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
+# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
+#endif
+
+#ifndef deliberate_fall_through
+# define deliberate_fall_through
+#endif
+
+/*
+** Versions of isspace(), isalnum() and isdigit() to which it is safe
+** to pass signed char values.
+*/
+#ifdef sqlite3Isdigit
+ /* Use the SQLite core versions if this routine is part of the
+ ** SQLite amalgamation */
+# define safe_isdigit(x) sqlite3Isdigit(x)
+# define safe_isalnum(x) sqlite3Isalnum(x)
+# define safe_isxdigit(x) sqlite3Isxdigit(x)
+#else
+ /* Use the standard library for separate compilation */
+#include <ctype.h> /* amalgamator: keep */
+# define safe_isdigit(x) isdigit((unsigned char)(x))
+# define safe_isalnum(x) isalnum((unsigned char)(x))
+# define safe_isxdigit(x) isxdigit((unsigned char)(x))
+#endif
+
+/*
+** Growing our own isspace() routine this way is twice as fast as
+** the library isspace() function, resulting in a 7% overall performance
+** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
+*/
+static const char jsonIsSpace[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
+
+#ifndef SQLITE_AMALGAMATION
+ /* Unsigned integer types. These are already defined in the sqliteInt.h,
+ ** but the definitions need to be repeated for separate compilation. */
+ typedef sqlite3_uint64 u64;
+ typedef unsigned int u32;
+ typedef unsigned short int u16;
+ typedef unsigned char u8;
+#endif
+
+/* Objects */
+typedef struct JsonString JsonString;
+typedef struct JsonNode JsonNode;
+typedef struct JsonParse JsonParse;
+
+/* An instance of this object represents a JSON string
+** under construction. Really, this is a generic string accumulator
+** that can be and is used to create strings other than JSON.
+*/
+struct JsonString {
+ sqlite3_context *pCtx; /* Function context - put error messages here */
+ char *zBuf; /* Append JSON content here */
+ u64 nAlloc; /* Bytes of storage available in zBuf[] */
+ u64 nUsed; /* Bytes of zBuf[] currently used */
+ u8 bStatic; /* True if zBuf is static space */
+ u8 bErr; /* True if an error has been encountered */
+ char zSpace[100]; /* Initial static space */
+};
+
+/* JSON type values
+*/
+#define JSON_NULL 0
+#define JSON_TRUE 1
+#define JSON_FALSE 2
+#define JSON_INT 3
+#define JSON_REAL 4
+#define JSON_STRING 5
+#define JSON_ARRAY 6
+#define JSON_OBJECT 7
+
+/* The "subtype" set for JSON values */
+#define JSON_SUBTYPE 74 /* Ascii for "J" */
+
+/*
+** Names of the various JSON types:
+*/
+static const char * const jsonType[] = {
+ "null", "true", "false", "integer", "real", "text", "array", "object"
+};
+
+/* Bit values for the JsonNode.jnFlag field
+*/
+#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
+#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
+#define JNODE_REMOVE 0x04 /* Do not output */
+#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
+#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
+#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
+#define JNODE_LABEL 0x40 /* Is a label of an object */
+
+
+/* A single node of parsed JSON
+*/
+struct JsonNode {
+ u8 eType; /* One of the JSON_ type values */
+ u8 jnFlags; /* JNODE flags */
+ u32 n; /* Bytes of content, or number of sub-nodes */
+ union {
+ const char *zJContent; /* Content for INT, REAL, and STRING */
+ u32 iAppend; /* More terms for ARRAY and OBJECT */
+ u32 iKey; /* Key for ARRAY objects in json_tree() */
+ u32 iReplace; /* Replacement content for JNODE_REPLACE */
+ JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */
+ } u;
+};
+
+/* A completely parsed JSON string
+*/
+struct JsonParse {
+ u32 nNode; /* Number of slots of aNode[] used */
+ u32 nAlloc; /* Number of slots of aNode[] allocated */
+ JsonNode *aNode; /* Array of nodes containing the parse */
+ const char *zJson; /* Original JSON string */
+ u32 *aUp; /* Index of parent of each node */
+ u8 oom; /* Set to true if out of memory */
+ u8 nErr; /* Number of errors seen */
+ u16 iDepth; /* Nesting depth */
+ int nJson; /* Length of the zJson string in bytes */
+ u32 iHold; /* Replace cache line with the lowest iHold value */
+};
+
+/*
+** Maximum nesting depth of JSON for this implementation.
+**
+** This limit is needed to avoid a stack overflow in the recursive
+** descent parser. A depth of 2000 is far deeper than any sane JSON
+** should go.
+*/
+#define JSON_MAX_DEPTH 2000
+
+/**************************************************************************
+** Utility routines for dealing with JsonString objects
+**************************************************************************/
+
+/* Set the JsonString object to an empty string
+*/
+static void jsonZero(JsonString *p){
+ p->zBuf = p->zSpace;
+ p->nAlloc = sizeof(p->zSpace);
+ p->nUsed = 0;
+ p->bStatic = 1;
+}
+
+/* Initialize the JsonString object
+*/
+static void jsonInit(JsonString *p, sqlite3_context *pCtx){
+ p->pCtx = pCtx;
+ p->bErr = 0;
+ jsonZero(p);
+}
+
+
+/* Free all allocated memory and reset the JsonString object back to its
+** initial state.
+*/
+static void jsonReset(JsonString *p){
+ if( !p->bStatic ) sqlite3_free(p->zBuf);
+ jsonZero(p);
+}
+
+
+/* Report an out-of-memory (OOM) condition
+*/
+static void jsonOom(JsonString *p){
+ p->bErr = 1;
+ sqlite3_result_error_nomem(p->pCtx);
+ jsonReset(p);
+}
+
+/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
+** Return zero on success. Return non-zero on an OOM error
+*/
+static int jsonGrow(JsonString *p, u32 N){
+ u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
+ char *zNew;
+ if( p->bStatic ){
+ if( p->bErr ) return 1;
+ zNew = sqlite3_malloc64(nTotal);
+ if( zNew==0 ){
+ jsonOom(p);
+ return SQLITE_NOMEM;
+ }
+ memcpy(zNew, p->zBuf, (size_t)p->nUsed);
+ p->zBuf = zNew;
+ p->bStatic = 0;
+ }else{
+ zNew = sqlite3_realloc64(p->zBuf, nTotal);
+ if( zNew==0 ){
+ jsonOom(p);
+ return SQLITE_NOMEM;
+ }
+ p->zBuf = zNew;
+ }
+ p->nAlloc = nTotal;
+ return SQLITE_OK;
+}
+
+/* Append N bytes from zIn onto the end of the JsonString string.
+*/
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( N==0 ) return;
+ if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+}
+
+/* Append formatted text (not to exceed N bytes) to the JsonString.
+*/
+static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
+ va_list ap;
+ if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
+ va_start(ap, zFormat);
+ sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
+ va_end(ap);
+ p->nUsed += (int)strlen(p->zBuf+p->nUsed);
+}
+
+/* Append a single character
+*/
+static void jsonAppendChar(JsonString *p, char c){
+ if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+ p->zBuf[p->nUsed++] = c;
+}
+
+/* Append a comma separator to the output buffer, if the previous
+** character is not '[' or '{'.
+*/
+static void jsonAppendSeparator(JsonString *p){
+ char c;
+ if( p->nUsed==0 ) return;
+ c = p->zBuf[p->nUsed-1];
+ if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+}
+
+/* Append the N-byte string in zIn to the end of the JsonString string
+** under construction. Enclose the string in "..." and escape
+** any double-quotes or backslash characters contained within the
+** string.
+*/
+static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
+ u32 i;
+ if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
+ p->zBuf[p->nUsed++] = '"';
+ for(i=0; i<N; i++){
+ unsigned char c = ((unsigned const char*)zIn)[i];
+ if( c=='"' || c=='\\' ){
+ json_simple_escape:
+ if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
+ p->zBuf[p->nUsed++] = '\\';
+ }else if( c<=0x1f ){
+ static const char aSpecial[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ assert( sizeof(aSpecial)==32 );
+ assert( aSpecial['\b']=='b' );
+ assert( aSpecial['\f']=='f' );
+ assert( aSpecial['\n']=='n' );
+ assert( aSpecial['\r']=='r' );
+ assert( aSpecial['\t']=='t' );
+ if( aSpecial[c] ){
+ c = aSpecial[c];
+ goto json_simple_escape;
+ }
+ if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
+ p->zBuf[p->nUsed++] = '\\';
+ p->zBuf[p->nUsed++] = 'u';
+ p->zBuf[p->nUsed++] = '0';
+ p->zBuf[p->nUsed++] = '0';
+ p->zBuf[p->nUsed++] = '0' + (c>>4);
+ c = "0123456789abcdef"[c&0xf];
+ }
+ p->zBuf[p->nUsed++] = c;
+ }
+ p->zBuf[p->nUsed++] = '"';
+ assert( p->nUsed<p->nAlloc );
+}
+
+/*
+** Append a function parameter value to the JSON string under
+** construction.
+*/
+static void jsonAppendValue(
+ JsonString *p, /* Append to this JSON string */
+ sqlite3_value *pValue /* Value to append */
+){
+ switch( sqlite3_value_type(pValue) ){
+ case SQLITE_NULL: {
+ jsonAppendRaw(p, "null", 4);
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ const char *z = (const char*)sqlite3_value_text(pValue);
+ u32 n = (u32)sqlite3_value_bytes(pValue);
+ jsonAppendRaw(p, z, n);
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *z = (const char*)sqlite3_value_text(pValue);
+ u32 n = (u32)sqlite3_value_bytes(pValue);
+ if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
+ jsonAppendRaw(p, z, n);
+ }else{
+ jsonAppendString(p, z, n);
+ }
+ break;
+ }
+ default: {
+ if( p->bErr==0 ){
+ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
+ p->bErr = 2;
+ jsonReset(p);
+ }
+ break;
+ }
+ }
+}
+
+
+/* Make the JSON in p the result of the SQL function.
+*/
+static void jsonResult(JsonString *p){
+ if( p->bErr==0 ){
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
+ SQLITE_UTF8);
+ jsonZero(p);
+ }
+ assert( p->bStatic );
+}
+
+/**************************************************************************
+** Utility routines for dealing with JsonNode and JsonParse objects
+**************************************************************************/
+
+/*
+** Return the number of consecutive JsonNode slots need to represent
+** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
+** OBJECT types, the number might be larger.
+**
+** Appended elements are not counted. The value returned is the number
+** by which the JsonNode counter should increment in order to go to the
+** next peer value.
+*/
+static u32 jsonNodeSize(JsonNode *pNode){
+ return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
+}
+
+/*
+** Reclaim all memory allocated by a JsonParse object. But do not
+** delete the JsonParse object itself.
+*/
+static void jsonParseReset(JsonParse *pParse){
+ sqlite3_free(pParse->aNode);
+ pParse->aNode = 0;
+ pParse->nNode = 0;
+ pParse->nAlloc = 0;
+ sqlite3_free(pParse->aUp);
+ pParse->aUp = 0;
+}
+
+/*
+** Free a JsonParse object that was obtained from sqlite3_malloc().
+*/
+static void jsonParseFree(JsonParse *pParse){
+ jsonParseReset(pParse);
+ sqlite3_free(pParse);
+}
+
+/*
+** Convert the JsonNode pNode into a pure JSON string and
+** append to pOut. Subsubstructure is also included. Return
+** the number of JsonNode objects that are encoded.
+*/
+static void jsonRenderNode(
+ JsonNode *pNode, /* The node to render */
+ JsonString *pOut, /* Write JSON here */
+ sqlite3_value **aReplace /* Replacement values */
+){
+ if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
+ if( pNode->jnFlags & JNODE_REPLACE ){
+ jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
+ return;
+ }
+ pNode = pNode->u.pPatch;
+ }
+ switch( pNode->eType ){
+ default: {
+ assert( pNode->eType==JSON_NULL );
+ jsonAppendRaw(pOut, "null", 4);
+ break;
+ }
+ case JSON_TRUE: {
+ jsonAppendRaw(pOut, "true", 4);
+ break;
+ }
+ case JSON_FALSE: {
+ jsonAppendRaw(pOut, "false", 5);
+ break;
+ }
+ case JSON_STRING: {
+ if( pNode->jnFlags & JNODE_RAW ){
+ jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
+ break;
+ }
+ /* no break */ deliberate_fall_through
+ }
+ case JSON_REAL:
+ case JSON_INT: {
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ break;
+ }
+ case JSON_ARRAY: {
+ u32 j = 1;
+ jsonAppendChar(pOut, '[');
+ for(;;){
+ while( j<=pNode->n ){
+ if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
+ jsonAppendSeparator(pOut);
+ jsonRenderNode(&pNode[j], pOut, aReplace);
+ }
+ j += jsonNodeSize(&pNode[j]);
+ }
+ if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ pNode = &pNode[pNode->u.iAppend];
+ j = 1;
+ }
+ jsonAppendChar(pOut, ']');
+ break;
+ }
+ case JSON_OBJECT: {
+ u32 j = 1;
+ jsonAppendChar(pOut, '{');
+ for(;;){
+ while( j<=pNode->n ){
+ if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
+ jsonAppendSeparator(pOut);
+ jsonRenderNode(&pNode[j], pOut, aReplace);
+ jsonAppendChar(pOut, ':');
+ jsonRenderNode(&pNode[j+1], pOut, aReplace);
+ }
+ j += 1 + jsonNodeSize(&pNode[j+1]);
+ }
+ if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+ pNode = &pNode[pNode->u.iAppend];
+ j = 1;
+ }
+ jsonAppendChar(pOut, '}');
+ break;
+ }
+ }
+}
+
+/*
+** Return a JsonNode and all its descendents as a JSON string.
+*/
+static void jsonReturnJson(
+ JsonNode *pNode, /* Node to return */
+ sqlite3_context *pCtx, /* Return value for this function */
+ sqlite3_value **aReplace /* Array of replacement values */
+){
+ JsonString s;
+ jsonInit(&s, pCtx);
+ jsonRenderNode(pNode, &s, aReplace);
+ jsonResult(&s);
+ sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
+}
+
+/*
+** 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 jsonHexToInt(int h){
+ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+#ifdef SQLITE_EBCDIC
+ h += 9*(1&~(h>>4));
+#else
+ h += 9*(1&(h>>6));
+#endif
+ return (u8)(h & 0xf);
+}
+
+/*
+** Convert a 4-byte hex string into an integer
+*/
+static u32 jsonHexToInt4(const char *z){
+ u32 v;
+ assert( safe_isxdigit(z[0]) );
+ assert( safe_isxdigit(z[1]) );
+ assert( safe_isxdigit(z[2]) );
+ assert( safe_isxdigit(z[3]) );
+ v = (jsonHexToInt(z[0])<<12)
+ + (jsonHexToInt(z[1])<<8)
+ + (jsonHexToInt(z[2])<<4)
+ + jsonHexToInt(z[3]);
+ return v;
+}
+
+/*
+** Make the JsonNode the return value of the function.
+*/
+static void jsonReturn(
+ JsonNode *pNode, /* Node to return */
+ sqlite3_context *pCtx, /* Return value for this function */
+ sqlite3_value **aReplace /* Array of replacement values */
+){
+ switch( pNode->eType ){
+ default: {
+ assert( pNode->eType==JSON_NULL );
+ sqlite3_result_null(pCtx);
+ break;
+ }
+ case JSON_TRUE: {
+ sqlite3_result_int(pCtx, 1);
+ break;
+ }
+ case JSON_FALSE: {
+ sqlite3_result_int(pCtx, 0);
+ break;
+ }
+ case JSON_INT: {
+ sqlite3_int64 i = 0;
+ const char *z = pNode->u.zJContent;
+ if( z[0]=='-' ){ z++; }
+ while( z[0]>='0' && z[0]<='9' ){
+ unsigned v = *(z++) - '0';
+ if( i>=LARGEST_INT64/10 ){
+ if( i>LARGEST_INT64/10 ) goto int_as_real;
+ if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
+ if( v==9 ) goto int_as_real;
+ if( v==8 ){
+ if( pNode->u.zJContent[0]=='-' ){
+ sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ goto int_done;
+ }else{
+ goto int_as_real;
+ }
+ }
+ }
+ i = i*10 + v;
+ }
+ if( pNode->u.zJContent[0]=='-' ){ i = -i; }
+ sqlite3_result_int64(pCtx, i);
+ int_done:
+ break;
+ int_as_real: i=0; /* no break */ deliberate_fall_through
+ }
+ case JSON_REAL: {
+ double r;
+#ifdef SQLITE_AMALGAMATION
+ const char *z = pNode->u.zJContent;
+ sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
+#else
+ r = strtod(pNode->u.zJContent, 0);
+#endif
+ sqlite3_result_double(pCtx, r);
+ break;
+ }
+ case JSON_STRING: {
+#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
+ ** json_insert() and json_replace() and those routines do not
+ ** call jsonReturn() */
+ if( pNode->jnFlags & JNODE_RAW ){
+ sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
+ SQLITE_TRANSIENT);
+ }else
+#endif
+ assert( (pNode->jnFlags & JNODE_RAW)==0 );
+ if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
+ /* JSON formatted without any backslash-escapes */
+ sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
+ SQLITE_TRANSIENT);
+ }else{
+ /* Translate JSON formatted string into raw text */
+ u32 i;
+ u32 n = pNode->n;
+ const char *z = pNode->u.zJContent;
+ char *zOut;
+ u32 j;
+ zOut = sqlite3_malloc( n+1 );
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ break;
+ }
+ for(i=1, j=0; i<n-1; i++){
+ char c = z[i];
+ if( c!='\\' ){
+ zOut[j++] = c;
+ }else{
+ c = z[++i];
+ if( c=='u' ){
+ u32 v = jsonHexToInt4(z+i+1);
+ i += 4;
+ if( v==0 ) break;
+ if( v<=0x7f ){
+ zOut[j++] = (char)v;
+ }else if( v<=0x7ff ){
+ zOut[j++] = (char)(0xc0 | (v>>6));
+ zOut[j++] = 0x80 | (v&0x3f);
+ }else{
+ u32 vlo;
+ if( (v&0xfc00)==0xd800
+ && i<n-6
+ && z[i+1]=='\\'
+ && z[i+2]=='u'
+ && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
+ ){
+ /* We have a surrogate pair */
+ v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
+ i += 6;
+ zOut[j++] = 0xf0 | (v>>18);
+ zOut[j++] = 0x80 | ((v>>12)&0x3f);
+ zOut[j++] = 0x80 | ((v>>6)&0x3f);
+ zOut[j++] = 0x80 | (v&0x3f);
+ }else{
+ zOut[j++] = 0xe0 | (v>>12);
+ zOut[j++] = 0x80 | ((v>>6)&0x3f);
+ zOut[j++] = 0x80 | (v&0x3f);
+ }
+ }
+ }else{
+ if( c=='b' ){
+ c = '\b';
+ }else if( c=='f' ){
+ c = '\f';
+ }else if( c=='n' ){
+ c = '\n';
+ }else if( c=='r' ){
+ c = '\r';
+ }else if( c=='t' ){
+ c = '\t';
+ }
+ zOut[j++] = c;
+ }
+ }
+ }
+ zOut[j] = 0;
+ sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
+ }
+ break;
+ }
+ case JSON_ARRAY:
+ case JSON_OBJECT: {
+ jsonReturnJson(pNode, pCtx, aReplace);
+ break;
+ }
+ }
+}
+
+/* Forward reference */
+static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
+
+/*
+** A macro to hint to the compiler that a function should not be
+** inlined.
+*/
+#if defined(__GNUC__)
+# define JSON_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER) && _MSC_VER>=1310
+# define JSON_NOINLINE __declspec(noinline)
+#else
+# define JSON_NOINLINE
+#endif
+
+
+static JSON_NOINLINE int jsonParseAddNodeExpand(
+ JsonParse *pParse, /* Append the node to this object */
+ u32 eType, /* Node type */
+ u32 n, /* Content size or sub-node count */
+ const char *zContent /* Content */
+){
+ u32 nNew;
+ JsonNode *pNew;
+ assert( pParse->nNode>=pParse->nAlloc );
+ if( pParse->oom ) return -1;
+ nNew = pParse->nAlloc*2 + 10;
+ pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
+ if( pNew==0 ){
+ pParse->oom = 1;
+ return -1;
+ }
+ pParse->nAlloc = nNew;
+ pParse->aNode = pNew;
+ assert( pParse->nNode<pParse->nAlloc );
+ return jsonParseAddNode(pParse, eType, n, zContent);
+}
+
+/*
+** Create a new JsonNode instance based on the arguments and append that
+** instance to the JsonParse. Return the index in pParse->aNode[] of the
+** new node, or -1 if a memory allocation fails.
+*/
+static int jsonParseAddNode(
+ JsonParse *pParse, /* Append the node to this object */
+ u32 eType, /* Node type */
+ u32 n, /* Content size or sub-node count */
+ const char *zContent /* Content */
+){
+ JsonNode *p;
+ if( pParse->nNode>=pParse->nAlloc ){
+ return jsonParseAddNodeExpand(pParse, eType, n, zContent);
+ }
+ p = &pParse->aNode[pParse->nNode];
+ p->eType = (u8)eType;
+ p->jnFlags = 0;
+ p->n = n;
+ p->u.zJContent = zContent;
+ return pParse->nNode++;
+}
+
+/*
+** Return true if z[] begins with 4 (or more) hexadecimal digits
+*/
+static int jsonIs4Hex(const char *z){
+ int i;
+ for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
+ return 1;
+}
+
+/*
+** Parse a single JSON value which begins at pParse->zJson[i]. Return the
+** index of the first character past the end of the value parsed.
+**
+** Return negative for a syntax error. Special cases: return -2 if the
+** first non-whitespace character is '}' and return -3 if the first
+** non-whitespace character is ']'.
+*/
+static int jsonParseValue(JsonParse *pParse, u32 i){
+ char c;
+ u32 j;
+ int iThis;
+ int x;
+ JsonNode *pNode;
+ const char *z = pParse->zJson;
+ while( safe_isspace(z[i]) ){ i++; }
+ if( (c = z[i])=='{' ){
+ /* Parse object */
+ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+ if( iThis<0 ) return -1;
+ for(j=i+1;;j++){
+ while( safe_isspace(z[j]) ){ j++; }
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+ x = jsonParseValue(pParse, j);
+ if( x<0 ){
+ pParse->iDepth--;
+ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ return -1;
+ }
+ if( pParse->oom ) return -1;
+ pNode = &pParse->aNode[pParse->nNode-1];
+ if( pNode->eType!=JSON_STRING ) return -1;
+ pNode->jnFlags |= JNODE_LABEL;
+ j = x;
+ while( safe_isspace(z[j]) ){ j++; }
+ if( z[j]!=':' ) return -1;
+ j++;
+ x = jsonParseValue(pParse, j);
+ pParse->iDepth--;
+ if( x<0 ) return -1;
+ j = x;
+ while( safe_isspace(z[j]) ){ j++; }
+ c = z[j];
+ if( c==',' ) continue;
+ if( c!='}' ) return -1;
+ break;
+ }
+ pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ return j+1;
+ }else if( c=='[' ){
+ /* Parse array */
+ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+ if( iThis<0 ) return -1;
+ for(j=i+1;;j++){
+ while( safe_isspace(z[j]) ){ j++; }
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+ x = jsonParseValue(pParse, j);
+ pParse->iDepth--;
+ if( x<0 ){
+ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ return -1;
+ }
+ j = x;
+ while( safe_isspace(z[j]) ){ j++; }
+ c = z[j];
+ if( c==',' ) continue;
+ if( c!=']' ) return -1;
+ break;
+ }
+ pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ return j+1;
+ }else if( c=='"' ){
+ /* Parse string */
+ u8 jnFlags = 0;
+ j = i+1;
+ for(;;){
+ c = z[j];
+ if( (c & ~0x1f)==0 ){
+ /* Control characters are not allowed in strings */
+ return -1;
+ }
+ if( c=='\\' ){
+ c = z[++j];
+ if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
+ || c=='n' || c=='r' || c=='t'
+ || (c=='u' && jsonIs4Hex(z+j+1)) ){
+ jnFlags = JNODE_ESCAPE;
+ }else{
+ return -1;
+ }
+ }else if( c=='"' ){
+ break;
+ }
+ j++;
+ }
+ jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
+ if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ return j+1;
+ }else if( c=='n'
+ && strncmp(z+i,"null",4)==0
+ && !safe_isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+ return i+4;
+ }else if( c=='t'
+ && strncmp(z+i,"true",4)==0
+ && !safe_isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ return i+4;
+ }else if( c=='f'
+ && strncmp(z+i,"false",5)==0
+ && !safe_isalnum(z[i+5]) ){
+ jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
+ return i+5;
+ }else if( c=='-' || (c>='0' && c<='9') ){
+ /* Parse number */
+ u8 seenDP = 0;
+ u8 seenE = 0;
+ assert( '-' < '0' );
+ if( c<='0' ){
+ j = c=='-' ? i+1 : i;
+ if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ }
+ j = i+1;
+ for(;; j++){
+ c = z[j];
+ if( c>='0' && c<='9' ) continue;
+ if( c=='.' ){
+ if( z[j-1]=='-' ) return -1;
+ if( seenDP ) return -1;
+ seenDP = 1;
+ continue;
+ }
+ if( c=='e' || c=='E' ){
+ if( z[j-1]<'0' ) return -1;
+ if( seenE ) return -1;
+ seenDP = seenE = 1;
+ c = z[j+1];
+ if( c=='+' || c=='-' ){
+ j++;
+ c = z[j+1];
+ }
+ if( c<'0' || c>'9' ) return -1;
+ continue;
+ }
+ break;
+ }
+ if( z[j-1]<'0' ) return -1;
+ jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
+ j - i, &z[i]);
+ return j;
+ }else if( c=='}' ){
+ return -2; /* End of {...} */
+ }else if( c==']' ){
+ return -3; /* End of [...] */
+ }else if( c==0 ){
+ return 0; /* End of file */
+ }else{
+ return -1; /* Syntax error */
+ }
+}
+
+/*
+** Parse a complete JSON string. Return 0 on success or non-zero if there
+** are any errors. If an error occurs, free all memory associated with
+** pParse.
+**
+** pParse is uninitialized when this routine is called.
+*/
+static int jsonParse(
+ JsonParse *pParse, /* Initialize and fill this JsonParse object */
+ sqlite3_context *pCtx, /* Report errors here */
+ const char *zJson /* Input JSON text to be parsed */
+){
+ int i;
+ memset(pParse, 0, sizeof(*pParse));
+ if( zJson==0 ) return 1;
+ pParse->zJson = zJson;
+ i = jsonParseValue(pParse, 0);
+ if( pParse->oom ) i = -1;
+ if( i>0 ){
+ assert( pParse->iDepth==0 );
+ while( safe_isspace(zJson[i]) ) i++;
+ if( zJson[i] ) i = -1;
+ }
+ if( i<=0 ){
+ if( pCtx!=0 ){
+ if( pParse->oom ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ sqlite3_result_error(pCtx, "malformed JSON", -1);
+ }
+ }
+ jsonParseReset(pParse);
+ return 1;
+ }
+ return 0;
+}
+
+/* Mark node i of pParse as being a child of iParent. Call recursively
+** to fill in all the descendants of node i.
+*/
+static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
+ JsonNode *pNode = &pParse->aNode[i];
+ u32 j;
+ pParse->aUp[i] = iParent;
+ switch( pNode->eType ){
+ case JSON_ARRAY: {
+ for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
+ jsonParseFillInParentage(pParse, i+j, i);
+ }
+ break;
+ }
+ case JSON_OBJECT: {
+ for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
+ pParse->aUp[i+j] = i;
+ jsonParseFillInParentage(pParse, i+j+1, i);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+/*
+** Compute the parentage of all nodes in a completed parse.
+*/
+static int jsonParseFindParents(JsonParse *pParse){
+ u32 *aUp;
+ assert( pParse->aUp==0 );
+ aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
+ if( aUp==0 ){
+ pParse->oom = 1;
+ return SQLITE_NOMEM;
+ }
+ jsonParseFillInParentage(pParse, 0, 0);
+ return SQLITE_OK;
+}
+
+/*
+** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID (-429938) /* First cache entry */
+#define JSON_CACHE_SZ 4 /* Max number of cache entries */
+
+/*
+** Obtain a complete parse of the JSON found in the first argument
+** of the argv array. Use the sqlite3_get_auxdata() cache for this
+** parse if it is available. If the cache is not available or if it
+** is no longer valid, parse the JSON again and return the new parse,
+** and also register the new parse so that it will be available for
+** future sqlite3_get_auxdata() calls.
+*/
+static JsonParse *jsonParseCached(
+ sqlite3_context *pCtx,
+ sqlite3_value **argv,
+ sqlite3_context *pErrCtx
+){
+ const char *zJson = (const char*)sqlite3_value_text(argv[0]);
+ int nJson = sqlite3_value_bytes(argv[0]);
+ JsonParse *p;
+ JsonParse *pMatch = 0;
+ int iKey;
+ int iMinKey = 0;
+ u32 iMinHold = 0xffffffff;
+ u32 iMaxHold = 0;
+ if( zJson==0 ) return 0;
+ for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
+ p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
+ if( p==0 ){
+ iMinKey = iKey;
+ break;
+ }
+ if( pMatch==0
+ && p->nJson==nJson
+ && memcmp(p->zJson,zJson,nJson)==0
+ ){
+ p->nErr = 0;
+ pMatch = p;
+ }else if( p->iHold<iMinHold ){
+ iMinHold = p->iHold;
+ iMinKey = iKey;
+ }
+ if( p->iHold>iMaxHold ){
+ iMaxHold = p->iHold;
+ }
+ }
+ if( pMatch ){
+ pMatch->nErr = 0;
+ pMatch->iHold = iMaxHold+1;
+ return pMatch;
+ }
+ p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
+ if( p==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return 0;
+ }
+ memset(p, 0, sizeof(*p));
+ p->zJson = (char*)&p[1];
+ memcpy((char*)p->zJson, zJson, nJson+1);
+ if( jsonParse(p, pErrCtx, p->zJson) ){
+ sqlite3_free(p);
+ return 0;
+ }
+ p->nJson = nJson;
+ p->iHold = iMaxHold+1;
+ sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
+ (void(*)(void*))jsonParseFree);
+ return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
+}
+
+/*
+** Compare the OBJECT label at pNode against zKey,nKey. Return true on
+** a match.
+*/
+static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
+ if( pNode->jnFlags & JNODE_RAW ){
+ if( pNode->n!=nKey ) return 0;
+ return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+ }else{
+ if( pNode->n!=nKey+2 ) return 0;
+ return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+ }
+}
+
+/* forward declaration */
+static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+
+/*
+** Search along zPath to find the node specified. Return a pointer
+** to that node, or NULL if zPath is malformed or if there is no such
+** node.
+**
+** If pApnd!=0, then try to append new nodes to complete zPath if it is
+** possible to do so and if no existing node corresponds to zPath. If
+** new nodes are appended *pApnd is set to 1.
+*/
+static JsonNode *jsonLookupStep(
+ JsonParse *pParse, /* The JSON to search */
+ u32 iRoot, /* Begin the search at this node */
+ const char *zPath, /* The path to search */
+ int *pApnd, /* Append nodes to complete path if not NULL */
+ const char **pzErr /* Make *pzErr point to any syntax error in zPath */
+){
+ u32 i, j, nKey;
+ const char *zKey;
+ JsonNode *pRoot = &pParse->aNode[iRoot];
+ if( zPath[0]==0 ) return pRoot;
+ if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
+ if( zPath[0]=='.' ){
+ if( pRoot->eType!=JSON_OBJECT ) return 0;
+ zPath++;
+ if( zPath[0]=='"' ){
+ zKey = zPath + 1;
+ for(i=1; zPath[i] && zPath[i]!='"'; i++){}
+ nKey = i-1;
+ if( zPath[i] ){
+ i++;
+ }else{
+ *pzErr = zPath;
+ return 0;
+ }
+ }else{
+ zKey = zPath;
+ for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
+ nKey = i;
+ }
+ if( nKey==0 ){
+ *pzErr = zPath;
+ return 0;
+ }
+ j = 1;
+ for(;;){
+ while( j<=pRoot->n ){
+ if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
+ return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
+ }
+ j++;
+ j += jsonNodeSize(&pRoot[j]);
+ }
+ if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+ iRoot += pRoot->u.iAppend;
+ pRoot = &pParse->aNode[iRoot];
+ j = 1;
+ }
+ if( pApnd ){
+ u32 iStart, iLabel;
+ JsonNode *pNode;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+ zPath += i;
+ pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+ if( pParse->oom ) return 0;
+ if( pNode ){
+ pRoot = &pParse->aNode[iRoot];
+ pRoot->u.iAppend = iStart - iRoot;
+ pRoot->jnFlags |= JNODE_APPEND;
+ pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
+ }
+ return pNode;
+ }
+ }else if( zPath[0]=='[' ){
+ i = 0;
+ j = 1;
+ while( safe_isdigit(zPath[j]) ){
+ i = i*10 + zPath[j] - '0';
+ j++;
+ }
+ if( j<2 || zPath[j]!=']' ){
+ if( zPath[1]=='#' ){
+ JsonNode *pBase = pRoot;
+ int iBase = iRoot;
+ if( pRoot->eType!=JSON_ARRAY ) return 0;
+ for(;;){
+ while( j<=pBase->n ){
+ if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
+ j += jsonNodeSize(&pBase[j]);
+ }
+ if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
+ iBase += pBase->u.iAppend;
+ pBase = &pParse->aNode[iBase];
+ j = 1;
+ }
+ j = 2;
+ if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
+ unsigned int x = 0;
+ j = 3;
+ do{
+ x = x*10 + zPath[j] - '0';
+ j++;
+ }while( safe_isdigit(zPath[j]) );
+ if( x>i ) return 0;
+ i -= x;
+ }
+ if( zPath[j]!=']' ){
+ *pzErr = zPath;
+ return 0;
+ }
+ }else{
+ *pzErr = zPath;
+ return 0;
+ }
+ }
+ if( pRoot->eType!=JSON_ARRAY ) return 0;
+ zPath += j + 1;
+ j = 1;
+ for(;;){
+ while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
+ if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
+ j += jsonNodeSize(&pRoot[j]);
+ }
+ if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+ iRoot += pRoot->u.iAppend;
+ pRoot = &pParse->aNode[iRoot];
+ j = 1;
+ }
+ if( j<=pRoot->n ){
+ return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
+ }
+ if( i==0 && pApnd ){
+ u32 iStart;
+ JsonNode *pNode;
+ iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
+ pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+ if( pParse->oom ) return 0;
+ if( pNode ){
+ pRoot = &pParse->aNode[iRoot];
+ pRoot->u.iAppend = iStart - iRoot;
+ pRoot->jnFlags |= JNODE_APPEND;
+ }
+ return pNode;
+ }
+ }else{
+ *pzErr = zPath;
+ }
+ return 0;
+}
+
+/*
+** Append content to pParse that will complete zPath. Return a pointer
+** to the inserted node, or return NULL if the append fails.
+*/
+static JsonNode *jsonLookupAppend(
+ JsonParse *pParse, /* Append content to the JSON parse */
+ const char *zPath, /* Description of content to append */
+ int *pApnd, /* Set this flag to 1 */
+ const char **pzErr /* Make this point to any syntax error */
+){
+ *pApnd = 1;
+ if( zPath[0]==0 ){
+ jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+ return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
+ }
+ if( zPath[0]=='.' ){
+ jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+ }else if( strncmp(zPath,"[0]",3)==0 ){
+ jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+ }else{
+ return 0;
+ }
+ if( pParse->oom ) return 0;
+ return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+}
+
+/*
+** Return the text of a syntax error message on a JSON path. Space is
+** obtained from sqlite3_malloc().
+*/
+static char *jsonPathSyntaxError(const char *zErr){
+ return sqlite3_mprintf("JSON path error near '%q'", zErr);
+}
+
+/*
+** Do a node lookup using zPath. Return a pointer to the node on success.
+** Return NULL if not found or if there is an error.
+**
+** On an error, write an error message into pCtx and increment the
+** pParse->nErr counter.
+**
+** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
+** nodes are appended.
+*/
+static JsonNode *jsonLookup(
+ JsonParse *pParse, /* The JSON to search */
+ const char *zPath, /* The path to search */
+ int *pApnd, /* Append nodes to complete path if not NULL */
+ sqlite3_context *pCtx /* Report errors here, if not NULL */
+){
+ const char *zErr = 0;
+ JsonNode *pNode = 0;
+ char *zMsg;
+
+ if( zPath==0 ) return 0;
+ if( zPath[0]!='$' ){
+ zErr = zPath;
+ goto lookup_err;
+ }
+ zPath++;
+ pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
+ if( zErr==0 ) return pNode;
+
+lookup_err:
+ pParse->nErr++;
+ assert( zErr!=0 && pCtx!=0 );
+ zMsg = jsonPathSyntaxError(zErr);
+ if( zMsg ){
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+ }else{
+ sqlite3_result_error_nomem(pCtx);
+ }
+ return 0;
+}
+
+
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+ sqlite3_context *pCtx,
+ const char *zFuncName
+){
+ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+ zFuncName);
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+}
+
+/*
+** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+*/
+static void jsonRemoveAllNulls(JsonNode *pNode){
+ int i, n;
+ assert( pNode->eType==JSON_OBJECT );
+ n = pNode->n;
+ for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
+ switch( pNode[i].eType ){
+ case JSON_NULL:
+ pNode[i].jnFlags |= JNODE_REMOVE;
+ break;
+ case JSON_OBJECT:
+ jsonRemoveAllNulls(&pNode[i]);
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#ifdef SQLITE_DEBUG
+/*
+** The json_parse(JSON) function returns a string which describes
+** a parse of the JSON provided. Or it returns NULL if JSON is not
+** well-formed.
+*/
+static void jsonParseFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString s; /* Output string - not real JSON */
+ JsonParse x; /* The parse */
+ u32 i;
+
+ assert( argc==1 );
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ jsonParseFindParents(&x);
+ jsonInit(&s, ctx);
+ for(i=0; i<x.nNode; i++){
+ const char *zType;
+ if( x.aNode[i].jnFlags & JNODE_LABEL ){
+ assert( x.aNode[i].eType==JSON_STRING );
+ zType = "label";
+ }else{
+ zType = jsonType[x.aNode[i].eType];
+ }
+ jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
+ i, zType, x.aNode[i].n, x.aUp[i]);
+ if( x.aNode[i].u.zJContent!=0 ){
+ jsonAppendRaw(&s, " ", 1);
+ jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
+ }
+ jsonAppendRaw(&s, "\n", 1);
+ }
+ jsonParseReset(&x);
+ jsonResult(&s);
+}
+
+/*
+** The json_test1(JSON) function return true (1) if the input is JSON
+** text generated by another json function. It returns (0) if the input
+** is not known to be JSON.
+*/
+static void jsonTest1Func(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ UNUSED_PARAM(argc);
+ sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
+}
+#endif /* SQLITE_DEBUG */
+
+/****************************************************************************
+** Scalar SQL function implementations
+****************************************************************************/
+
+/*
+** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
+** corresponding to the SQL value input. Mostly this means putting
+** double-quotes around strings and returning the unquoted string "null"
+** when given a NULL input.
+*/
+static void jsonQuoteFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString jx;
+ UNUSED_PARAM(argc);
+
+ jsonInit(&jx, ctx);
+ jsonAppendValue(&jx, argv[0]);
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+/*
+** Implementation of the json_array(VALUE,...) function. Return a JSON
+** array that contains all values given in arguments. Or if any argument
+** is a BLOB, throw an error.
+*/
+static void jsonArrayFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ JsonString jx;
+
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '[');
+ for(i=0; i<argc; i++){
+ jsonAppendSeparator(&jx);
+ jsonAppendValue(&jx, argv[i]);
+ }
+ jsonAppendChar(&jx, ']');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+
+/*
+** json_array_length(JSON)
+** json_array_length(JSON, PATH)
+**
+** Return the number of elements in the top-level JSON array.
+** Return 0 if the input is not a well-formed JSON array.
+*/
+static void jsonArrayLengthFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ sqlite3_int64 n = 0;
+ u32 i;
+ JsonNode *pNode;
+
+ p = jsonParseCached(ctx, argv, ctx);
+ if( p==0 ) return;
+ assert( p->nNode );
+ if( argc==2 ){
+ const char *zPath = (const char*)sqlite3_value_text(argv[1]);
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ }else{
+ pNode = p->aNode;
+ }
+ if( pNode==0 ){
+ return;
+ }
+ if( pNode->eType==JSON_ARRAY ){
+ assert( (pNode->jnFlags & JNODE_APPEND)==0 );
+ for(i=1; i<=pNode->n; n++){
+ i += jsonNodeSize(&pNode[i]);
+ }
+ }
+ sqlite3_result_int64(ctx, n);
+}
+
+/*
+** json_extract(JSON, PATH, ...)
+**
+** Return the element described by PATH. Return NULL if there is no
+** PATH element. If there are multiple PATHs, then return a JSON array
+** with the result from each path. Throw an error if the JSON or any PATH
+** is malformed.
+*/
+static void jsonExtractFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ JsonString jx;
+ int i;
+
+ if( argc<2 ) return;
+ p = jsonParseCached(ctx, argv, ctx);
+ if( p==0 ) return;
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '[');
+ for(i=1; i<argc; i++){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ if( p->nErr ) break;
+ if( argc>2 ){
+ jsonAppendSeparator(&jx);
+ if( pNode ){
+ jsonRenderNode(pNode, &jx, 0);
+ }else{
+ jsonAppendRaw(&jx, "null", 4);
+ }
+ }else if( pNode ){
+ jsonReturn(pNode, ctx, 0);
+ }
+ }
+ if( argc>2 && i==argc ){
+ jsonAppendChar(&jx, ']');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+ jsonReset(&jx);
+}
+
+/* This is the RFC 7396 MergePatch algorithm.
+*/
+static JsonNode *jsonMergePatch(
+ JsonParse *pParse, /* The JSON parser that contains the TARGET */
+ u32 iTarget, /* Node of the TARGET in pParse */
+ JsonNode *pPatch /* The PATCH */
+){
+ u32 i, j;
+ u32 iRoot;
+ JsonNode *pTarget;
+ if( pPatch->eType!=JSON_OBJECT ){
+ return pPatch;
+ }
+ assert( iTarget>=0 && iTarget<pParse->nNode );
+ pTarget = &pParse->aNode[iTarget];
+ assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
+ if( pTarget->eType!=JSON_OBJECT ){
+ jsonRemoveAllNulls(pPatch);
+ return pPatch;
+ }
+ iRoot = iTarget;
+ for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
+ u32 nKey;
+ const char *zKey;
+ assert( pPatch[i].eType==JSON_STRING );
+ assert( pPatch[i].jnFlags & JNODE_LABEL );
+ nKey = pPatch[i].n;
+ zKey = pPatch[i].u.zJContent;
+ assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+ for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
+ assert( pTarget[j].eType==JSON_STRING );
+ assert( pTarget[j].jnFlags & JNODE_LABEL );
+ assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+ if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
+ if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
+ if( pPatch[i+1].eType==JSON_NULL ){
+ pTarget[j+1].jnFlags |= JNODE_REMOVE;
+ }else{
+ JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
+ if( pNew==0 ) return 0;
+ pTarget = &pParse->aNode[iTarget];
+ if( pNew!=&pTarget[j+1] ){
+ pTarget[j+1].u.pPatch = pNew;
+ pTarget[j+1].jnFlags |= JNODE_PATCH;
+ }
+ }
+ break;
+ }
+ }
+ if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
+ int iStart, iPatch;
+ iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+ jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+ iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ if( pParse->oom ) return 0;
+ jsonRemoveAllNulls(pPatch);
+ pTarget = &pParse->aNode[iTarget];
+ pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
+ pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
+ iRoot = iStart;
+ pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
+ pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
+ }
+ }
+ return pTarget;
+}
+
+/*
+** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
+** object that is the result of running the RFC 7396 MergePatch() algorithm
+** on the two arguments.
+*/
+static void jsonPatchFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The JSON that is being patched */
+ JsonParse y; /* The patch */
+ JsonNode *pResult; /* The result of the merge */
+
+ UNUSED_PARAM(argc);
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
+ jsonParseReset(&x);
+ return;
+ }
+ pResult = jsonMergePatch(&x, 0, y.aNode);
+ assert( pResult!=0 || x.oom );
+ if( pResult ){
+ jsonReturnJson(pResult, ctx, 0);
+ }else{
+ sqlite3_result_error_nomem(ctx);
+ }
+ jsonParseReset(&x);
+ jsonParseReset(&y);
+}
+
+
+/*
+** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON
+** object that contains all name/value given in arguments. Or if any name
+** is not a string or if any value is a BLOB, throw an error.
+*/
+static void jsonObjectFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ int i;
+ JsonString jx;
+ const char *z;
+ u32 n;
+
+ if( argc&1 ){
+ sqlite3_result_error(ctx, "json_object() requires an even number "
+ "of arguments", -1);
+ return;
+ }
+ jsonInit(&jx, ctx);
+ jsonAppendChar(&jx, '{');
+ for(i=0; i<argc; i+=2){
+ if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
+ sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
+ jsonReset(&jx);
+ return;
+ }
+ jsonAppendSeparator(&jx);
+ z = (const char*)sqlite3_value_text(argv[i]);
+ n = (u32)sqlite3_value_bytes(argv[i]);
+ jsonAppendString(&jx, z, n);
+ jsonAppendChar(&jx, ':');
+ jsonAppendValue(&jx, argv[i+1]);
+ }
+ jsonAppendChar(&jx, '}');
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+
+/*
+** json_remove(JSON, PATH, ...)
+**
+** Remove the named elements from JSON and return the result. malformed
+** JSON or PATH arguments result in an error.
+*/
+static void jsonRemoveFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ u32 i;
+
+ if( argc<1 ) return;
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ assert( x.nNode );
+ for(i=1; i<(u32)argc; i++){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ if( zPath==0 ) goto remove_done;
+ pNode = jsonLookup(&x, zPath, 0, ctx);
+ if( x.nErr ) goto remove_done;
+ if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
+ }
+ if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
+ jsonReturnJson(x.aNode, ctx, 0);
+ }
+remove_done:
+ jsonParseReset(&x);
+}
+
+/*
+** json_replace(JSON, PATH, VALUE, ...)
+**
+** Replace the value at PATH with VALUE. If PATH does not already exist,
+** this routine is a no-op. If JSON or PATH is malformed, throw an error.
+*/
+static void jsonReplaceFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ u32 i;
+
+ if( argc<1 ) return;
+ if( (argc&1)==0 ) {
+ jsonWrongNumArgs(ctx, "replace");
+ return;
+ }
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ assert( x.nNode );
+ for(i=1; i<(u32)argc; i+=2){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ pNode = jsonLookup(&x, zPath, 0, ctx);
+ if( x.nErr ) goto replace_err;
+ if( pNode ){
+ pNode->jnFlags |= (u8)JNODE_REPLACE;
+ pNode->u.iReplace = i + 1;
+ }
+ }
+ if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
+ }else{
+ jsonReturnJson(x.aNode, ctx, argv);
+ }
+replace_err:
+ jsonParseReset(&x);
+}
+
+/*
+** json_set(JSON, PATH, VALUE, ...)
+**
+** Set the value at PATH to VALUE. Create the PATH if it does not already
+** exist. Overwrite existing values that do exist.
+** If JSON or PATH is malformed, throw an error.
+**
+** json_insert(JSON, PATH, VALUE, ...)
+**
+** Create PATH and initialize it to VALUE. If PATH already exists, this
+** routine is a no-op. If JSON or PATH is malformed, throw an error.
+*/
+static void jsonSetFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse x; /* The parse */
+ JsonNode *pNode;
+ const char *zPath;
+ u32 i;
+ int bApnd;
+ int bIsSet = *(int*)sqlite3_user_data(ctx);
+
+ if( argc<1 ) return;
+ if( (argc&1)==0 ) {
+ jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
+ return;
+ }
+ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+ assert( x.nNode );
+ for(i=1; i<(u32)argc; i+=2){
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ bApnd = 0;
+ pNode = jsonLookup(&x, zPath, &bApnd, ctx);
+ if( x.oom ){
+ sqlite3_result_error_nomem(ctx);
+ goto jsonSetDone;
+ }else if( x.nErr ){
+ goto jsonSetDone;
+ }else if( pNode && (bApnd || bIsSet) ){
+ pNode->jnFlags |= (u8)JNODE_REPLACE;
+ pNode->u.iReplace = i + 1;
+ }
+ }
+ if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+ sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
+ }else{
+ jsonReturnJson(x.aNode, ctx, argv);
+ }
+jsonSetDone:
+ jsonParseReset(&x);
+}
+
+/*
+** json_type(JSON)
+** json_type(JSON, PATH)
+**
+** Return the top-level "type" of a JSON string. Throw an error if
+** either the JSON or PATH inputs are not well-formed.
+*/
+static void jsonTypeFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ const char *zPath;
+ JsonNode *pNode;
+
+ p = jsonParseCached(ctx, argv, ctx);
+ if( p==0 ) return;
+ if( argc==2 ){
+ zPath = (const char*)sqlite3_value_text(argv[1]);
+ pNode = jsonLookup(p, zPath, 0, ctx);
+ }else{
+ pNode = p->aNode;
+ }
+ if( pNode ){
+ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ }
+}
+
+/*
+** json_valid(JSON)
+**
+** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
+** Return 0 otherwise.
+*/
+static void jsonValidFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ UNUSED_PARAM(argc);
+ p = jsonParseCached(ctx, argv, 0);
+ sqlite3_result_int(ctx, p!=0);
+}
+
+
+/****************************************************************************
+** Aggregate SQL function implementations
+****************************************************************************/
+/*
+** json_group_array(VALUE)
+**
+** Return a JSON array composed of all values in the aggregate.
+*/
+static void jsonArrayStep(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString *pStr;
+ UNUSED_PARAM(argc);
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
+ if( pStr ){
+ if( pStr->zBuf==0 ){
+ jsonInit(pStr, ctx);
+ jsonAppendChar(pStr, '[');
+ }else if( pStr->nUsed>1 ){
+ jsonAppendChar(pStr, ',');
+ pStr->pCtx = ctx;
+ }
+ jsonAppendValue(pStr, argv[0]);
+ }
+}
+static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
+ JsonString *pStr;
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+ if( pStr ){
+ pStr->pCtx = ctx;
+ jsonAppendChar(pStr, ']');
+ if( pStr->bErr ){
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
+ assert( pStr->bStatic );
+ }else if( isFinal ){
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
+ pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic = 1;
+ }else{
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
+ pStr->nUsed--;
+ }
+ }else{
+ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
+ }
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+static void jsonArrayValue(sqlite3_context *ctx){
+ jsonArrayCompute(ctx, 0);
+}
+static void jsonArrayFinal(sqlite3_context *ctx){
+ jsonArrayCompute(ctx, 1);
+}
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** This method works for both json_group_array() and json_group_object().
+** It works by removing the first element of the group by searching forward
+** to the first comma (",") that is not within a string and deleting all
+** text through that comma.
+*/
+static void jsonGroupInverse(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ unsigned int i;
+ int inStr = 0;
+ int nNest = 0;
+ char *z;
+ char c;
+ JsonString *pStr;
+ UNUSED_PARAM(argc);
+ UNUSED_PARAM(argv);
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+#ifdef NEVER
+ /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
+ ** always have been called to initalize it */
+ if( NEVER(!pStr) ) return;
+#endif
+ z = pStr->zBuf;
+ for(i=1; (c = z[i])!=',' || inStr || nNest; i++){
+ if( i>=pStr->nUsed ){
+ pStr->nUsed = 1;
+ return;
+ }
+ if( c=='"' ){
+ inStr = !inStr;
+ }else if( c=='\\' ){
+ i++;
+ }else if( !inStr ){
+ if( c=='{' || c=='[' ) nNest++;
+ if( c=='}' || c==']' ) nNest--;
+ }
+ }
+ pStr->nUsed -= i;
+ memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1);
+}
+#else
+# define jsonGroupInverse 0
+#endif
+
+
+/*
+** json_group_obj(NAME,VALUE)
+**
+** Return a JSON object composed of all names and values in the aggregate.
+*/
+static void jsonObjectStep(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString *pStr;
+ const char *z;
+ u32 n;
+ UNUSED_PARAM(argc);
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
+ if( pStr ){
+ if( pStr->zBuf==0 ){
+ jsonInit(pStr, ctx);
+ jsonAppendChar(pStr, '{');
+ }else if( pStr->nUsed>1 ){
+ jsonAppendChar(pStr, ',');
+ pStr->pCtx = ctx;
+ }
+ z = (const char*)sqlite3_value_text(argv[0]);
+ n = (u32)sqlite3_value_bytes(argv[0]);
+ jsonAppendString(pStr, z, n);
+ jsonAppendChar(pStr, ':');
+ jsonAppendValue(pStr, argv[1]);
+ }
+}
+static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
+ JsonString *pStr;
+ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+ if( pStr ){
+ jsonAppendChar(pStr, '}');
+ if( pStr->bErr ){
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
+ assert( pStr->bStatic );
+ }else if( isFinal ){
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
+ pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic = 1;
+ }else{
+ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
+ pStr->nUsed--;
+ }
+ }else{
+ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
+ }
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+static void jsonObjectValue(sqlite3_context *ctx){
+ jsonObjectCompute(ctx, 0);
+}
+static void jsonObjectFinal(sqlite3_context *ctx){
+ jsonObjectCompute(ctx, 1);
+}
+
+
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/****************************************************************************
+** The json_each virtual table
+****************************************************************************/
+typedef struct JsonEachCursor JsonEachCursor;
+struct JsonEachCursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ u32 iRowid; /* The rowid */
+ u32 iBegin; /* The first node of the scan */
+ u32 i; /* Index in sParse.aNode[] of current row */
+ u32 iEnd; /* EOF when i equals or exceeds this value */
+ u8 eType; /* Type of top-level element */
+ u8 bRecursive; /* True for json_tree(). False for json_each() */
+ char *zJson; /* Input JSON */
+ char *zRoot; /* Path by which to filter zJson */
+ JsonParse sParse; /* Parse of the input JSON */
+};
+
+/* Constructor for the json_each virtual table */
+static int jsonEachConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ sqlite3_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define JEACH_KEY 0
+#define JEACH_VALUE 1
+#define JEACH_TYPE 2
+#define JEACH_ATOM 3
+#define JEACH_ID 4
+#define JEACH_PARENT 5
+#define JEACH_FULLKEY 6
+#define JEACH_PATH 7
+/* The xBestIndex method assumes that the JSON and ROOT columns are
+** the last two columns in the table. Should this ever changes, be
+** sure to update the xBestIndex method. */
+#define JEACH_JSON 8
+#define JEACH_ROOT 9
+
+ UNUSED_PARAM(pzErr);
+ UNUSED_PARAM(argv);
+ UNUSED_PARAM(argc);
+ UNUSED_PARAM(pAux);
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
+ "json HIDDEN,root HIDDEN)");
+ if( rc==SQLITE_OK ){
+ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ }
+ return rc;
+}
+
+/* destructor for json_each virtual table */
+static int jsonEachDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/* constructor for a JsonEachCursor object for json_each(). */
+static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ JsonEachCursor *pCur;
+
+ UNUSED_PARAM(p);
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/* constructor for a JsonEachCursor object for json_tree(). */
+static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ int rc = jsonEachOpenEach(p, ppCursor);
+ if( rc==SQLITE_OK ){
+ JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
+ pCur->bRecursive = 1;
+ }
+ return rc;
+}
+
+/* Reset a JsonEachCursor back to its original state. Free any memory
+** held. */
+static void jsonEachCursorReset(JsonEachCursor *p){
+ sqlite3_free(p->zJson);
+ sqlite3_free(p->zRoot);
+ jsonParseReset(&p->sParse);
+ p->iRowid = 0;
+ p->i = 0;
+ p->iEnd = 0;
+ p->eType = 0;
+ p->zJson = 0;
+ p->zRoot = 0;
+}
+
+/* Destructor for a jsonEachCursor object */
+static int jsonEachClose(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ jsonEachCursorReset(p);
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+/* Return TRUE if the jsonEachCursor object has been advanced off the end
+** of the JSON object */
+static int jsonEachEof(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ return p->i >= p->iEnd;
+}
+
+/* Advance the cursor to the next element for json_tree() */
+static int jsonEachNext(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ if( p->bRecursive ){
+ if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
+ p->i++;
+ p->iRowid++;
+ if( p->i<p->iEnd ){
+ u32 iUp = p->sParse.aUp[p->i];
+ JsonNode *pUp = &p->sParse.aNode[iUp];
+ p->eType = pUp->eType;
+ if( pUp->eType==JSON_ARRAY ){
+ if( iUp==p->i-1 ){
+ pUp->u.iKey = 0;
+ }else{
+ pUp->u.iKey++;
+ }
+ }
+ }
+ }else{
+ switch( p->eType ){
+ case JSON_ARRAY: {
+ p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
+ p->iRowid++;
+ break;
+ }
+ case JSON_OBJECT: {
+ p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
+ p->iRowid++;
+ break;
+ }
+ default: {
+ p->i = p->iEnd;
+ break;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Append the name of the path for element i to pStr
+*/
+static void jsonEachComputePath(
+ JsonEachCursor *p, /* The cursor */
+ JsonString *pStr, /* Write the path here */
+ u32 i /* Path to this element */
+){
+ JsonNode *pNode, *pUp;
+ u32 iUp;
+ if( i==0 ){
+ jsonAppendChar(pStr, '$');
+ return;
+ }
+ iUp = p->sParse.aUp[i];
+ jsonEachComputePath(p, pStr, iUp);
+ pNode = &p->sParse.aNode[i];
+ pUp = &p->sParse.aNode[iUp];
+ if( pUp->eType==JSON_ARRAY ){
+ jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
+ }else{
+ assert( pUp->eType==JSON_OBJECT );
+ if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
+ assert( pNode->eType==JSON_STRING );
+ assert( pNode->jnFlags & JNODE_LABEL );
+ jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
+ }
+}
+
+/* Return the value of a column */
+static int jsonEachColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ JsonNode *pThis = &p->sParse.aNode[p->i];
+ switch( i ){
+ case JEACH_KEY: {
+ if( p->i==0 ) break;
+ if( p->eType==JSON_OBJECT ){
+ jsonReturn(pThis, ctx, 0);
+ }else if( p->eType==JSON_ARRAY ){
+ u32 iKey;
+ if( p->bRecursive ){
+ if( p->iRowid==0 ) break;
+ iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
+ }else{
+ iKey = p->iRowid;
+ }
+ sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
+ }
+ break;
+ }
+ case JEACH_VALUE: {
+ if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+ jsonReturn(pThis, ctx, 0);
+ break;
+ }
+ case JEACH_TYPE: {
+ if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+ sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
+ break;
+ }
+ case JEACH_ATOM: {
+ if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+ if( pThis->eType>=JSON_ARRAY ) break;
+ jsonReturn(pThis, ctx, 0);
+ break;
+ }
+ case JEACH_ID: {
+ sqlite3_result_int64(ctx,
+ (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
+ break;
+ }
+ case JEACH_PARENT: {
+ if( p->i>p->iBegin && p->bRecursive ){
+ sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
+ }
+ break;
+ }
+ case JEACH_FULLKEY: {
+ JsonString x;
+ jsonInit(&x, ctx);
+ if( p->bRecursive ){
+ jsonEachComputePath(p, &x, p->i);
+ }else{
+ if( p->zRoot ){
+ jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
+ }else{
+ jsonAppendChar(&x, '$');
+ }
+ if( p->eType==JSON_ARRAY ){
+ jsonPrintf(30, &x, "[%d]", p->iRowid);
+ }else if( p->eType==JSON_OBJECT ){
+ jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
+ }
+ }
+ jsonResult(&x);
+ break;
+ }
+ case JEACH_PATH: {
+ if( p->bRecursive ){
+ JsonString x;
+ jsonInit(&x, ctx);
+ jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
+ jsonResult(&x);
+ break;
+ }
+ /* For json_each() path and root are the same so fall through
+ ** into the root case */
+ /* no break */ deliberate_fall_through
+ }
+ default: {
+ const char *zRoot = p->zRoot;
+ if( zRoot==0 ) zRoot = "$";
+ sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+ break;
+ }
+ case JEACH_JSON: {
+ assert( i==JEACH_JSON );
+ sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Return the current rowid value */
+static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ *pRowid = p->iRowid;
+ return SQLITE_OK;
+}
+
+/* The query strategy is to look for an equality constraint on the json
+** column. Without such a constraint, the table cannot operate. idxNum is
+** 1 if the constraint is found, 3 if the constraint and zRoot are found,
+** and 0 otherwise.
+*/
+static int jsonEachBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i; /* Loop counter or computed array index */
+ int aIdx[2]; /* Index of constraints for JSON and ROOT */
+ int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */
+ int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */
+ const struct sqlite3_index_constraint *pConstraint;
+
+ /* This implementation assumes that JSON and ROOT are the last two
+ ** columns in the table */
+ assert( JEACH_ROOT == JEACH_JSON+1 );
+ UNUSED_PARAM(tab);
+ aIdx[0] = aIdx[1] = -1;
+ pConstraint = pIdxInfo->aConstraint;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ int iCol;
+ int iMask;
+ if( pConstraint->iColumn < JEACH_JSON ) continue;
+ iCol = pConstraint->iColumn - JEACH_JSON;
+ assert( iCol==0 || iCol==1 );
+ iMask = 1 << iCol;
+ if( pConstraint->usable==0 ){
+ unusableMask |= iMask;
+ }else if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ aIdx[iCol] = i;
+ idxMask |= iMask;
+ }
+ }
+ if( (unusableMask & ~idxMask)!=0 ){
+ /* If there are any unusable constraints on JSON or ROOT, then reject
+ ** this entire plan */
+ return SQLITE_CONSTRAINT;
+ }
+ if( aIdx[0]<0 ){
+ /* No JSON input. Leave estimatedCost at the huge value that it was
+ ** initialized to to discourage the query planner from selecting this
+ ** plan. */
+ pIdxInfo->idxNum = 0;
+ }else{
+ pIdxInfo->estimatedCost = 1.0;
+ i = aIdx[0];
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ if( aIdx[1]<0 ){
+ pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */
+ }else{
+ i = aIdx[1];
+ pIdxInfo->aConstraintUsage[i].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* Start a search on a new JSON string */
+static int jsonEachFilter(
+ sqlite3_vtab_cursor *cur,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ const char *z;
+ const char *zRoot = 0;
+ sqlite3_int64 n;
+
+ UNUSED_PARAM(idxStr);
+ UNUSED_PARAM(argc);
+ jsonEachCursorReset(p);
+ if( idxNum==0 ) return SQLITE_OK;
+ z = (const char*)sqlite3_value_text(argv[0]);
+ if( z==0 ) return SQLITE_OK;
+ n = sqlite3_value_bytes(argv[0]);
+ p->zJson = sqlite3_malloc64( n+1 );
+ if( p->zJson==0 ) return SQLITE_NOMEM;
+ memcpy(p->zJson, z, (size_t)n+1);
+ if( jsonParse(&p->sParse, 0, p->zJson) ){
+ int rc = SQLITE_NOMEM;
+ if( p->sParse.oom==0 ){
+ sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
+ if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
+ }
+ jsonEachCursorReset(p);
+ return rc;
+ }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
+ jsonEachCursorReset(p);
+ return SQLITE_NOMEM;
+ }else{
+ JsonNode *pNode = 0;
+ if( idxNum==3 ){
+ const char *zErr = 0;
+ zRoot = (const char*)sqlite3_value_text(argv[1]);
+ if( zRoot==0 ) return SQLITE_OK;
+ n = sqlite3_value_bytes(argv[1]);
+ p->zRoot = sqlite3_malloc64( n+1 );
+ if( p->zRoot==0 ) return SQLITE_NOMEM;
+ memcpy(p->zRoot, zRoot, (size_t)n+1);
+ if( zRoot[0]!='$' ){
+ zErr = zRoot;
+ }else{
+ pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
+ }
+ if( zErr ){
+ sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+ }else if( pNode==0 ){
+ return SQLITE_OK;
+ }
+ }else{
+ pNode = p->sParse.aNode;
+ }
+ p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
+ p->eType = pNode->eType;
+ if( p->eType>=JSON_ARRAY ){
+ pNode->u.iKey = 0;
+ p->iEnd = p->i + pNode->n + 1;
+ if( p->bRecursive ){
+ p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
+ if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
+ p->i--;
+ }
+ }else{
+ p->i++;
+ }
+ }else{
+ p->iEnd = p->i+1;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/* The methods of the json_each virtual table */
+static sqlite3_module jsonEachModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ jsonEachConnect, /* xConnect */
+ jsonEachBestIndex, /* xBestIndex */
+ jsonEachDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ jsonEachOpenEach, /* xOpen - open a cursor */
+ jsonEachClose, /* xClose - close a cursor */
+ jsonEachFilter, /* xFilter - configure scan constraints */
+ jsonEachNext, /* xNext - advance a cursor */
+ jsonEachEof, /* xEof - check for end of scan */
+ jsonEachColumn, /* xColumn - read data */
+ jsonEachRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+
+/* The methods of the json_tree virtual table. */
+static sqlite3_module jsonTreeModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ jsonEachConnect, /* xConnect */
+ jsonEachBestIndex, /* xBestIndex */
+ jsonEachDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ jsonEachOpenTree, /* xOpen - open a cursor */
+ jsonEachClose, /* xClose - close a cursor */
+ jsonEachFilter, /* xFilter - configure scan constraints */
+ jsonEachNext, /* xNext - advance a cursor */
+ jsonEachEof, /* xEof - check for end of scan */
+ jsonEachColumn, /* xColumn - read data */
+ jsonEachRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+};
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+/****************************************************************************
+** The following routines are the only publically visible identifiers in this
+** file. Call the following routines in order to register the various SQL
+** functions and the virtual table implemented by this file.
+****************************************************************************/
+
+SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
+ int rc = SQLITE_OK;
+ unsigned int i;
+ static const struct {
+ const char *zName;
+ int nArg;
+ int flag;
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ } aFunc[] = {
+ { "json", 1, 0, jsonRemoveFunc },
+ { "json_array", -1, 0, jsonArrayFunc },
+ { "json_array_length", 1, 0, jsonArrayLengthFunc },
+ { "json_array_length", 2, 0, jsonArrayLengthFunc },
+ { "json_extract", -1, 0, jsonExtractFunc },
+ { "json_insert", -1, 0, jsonSetFunc },
+ { "json_object", -1, 0, jsonObjectFunc },
+ { "json_patch", 2, 0, jsonPatchFunc },
+ { "json_quote", 1, 0, jsonQuoteFunc },
+ { "json_remove", -1, 0, jsonRemoveFunc },
+ { "json_replace", -1, 0, jsonReplaceFunc },
+ { "json_set", -1, 1, jsonSetFunc },
+ { "json_type", 1, 0, jsonTypeFunc },
+ { "json_type", 2, 0, jsonTypeFunc },
+ { "json_valid", 1, 0, jsonValidFunc },
+
+#if SQLITE_DEBUG
+ /* DEBUG and TESTING functions */
+ { "json_parse", 1, 0, jsonParseFunc },
+ { "json_test1", 1, 0, jsonTest1Func },
+#endif
+ };
+ static const struct {
+ const char *zName;
+ int nArg;
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**);
+ void (*xFinal)(sqlite3_context*);
+ void (*xValue)(sqlite3_context*);
+ } aAgg[] = {
+ { "json_group_array", 1,
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue },
+ { "json_group_object", 2,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue },
+ };
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ static const struct {
+ const char *zName;
+ sqlite3_module *pModule;
+ } aMod[] = {
+ { "json_each", &jsonEachModule },
+ { "json_tree", &jsonTreeModule },
+ };
+#endif
+ static const int enc =
+ SQLITE_UTF8 |
+ SQLITE_DETERMINISTIC |
+ SQLITE_INNOCUOUS;
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc,
+ (void*)&aFunc[i].flag,
+ aFunc[i].xFunc, 0, 0);
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
+ SQLITE_SUBTYPE | enc, 0,
+ aAgg[i].xStep, aAgg[i].xFinal,
+ aAgg[i].xValue, jsonGroupInverse, 0);
+ }
+#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
+ }
+#endif
+ return rc;
+}
+
+
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+SQLITE_API int sqlite3_json_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ SQLITE_EXTENSION_INIT2(pApi);
+ (void)pzErrMsg; /* Unused parameter */
+ return sqlite3Json1Init(db);
+}
+#endif
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
+
+/************** End of json1.c ***********************************************/
/************** Begin file rtree.c *******************************************/
/*
** 2001 September 15
@@ -161333,21 +188076,22 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
** Database Format of R-Tree Tables
** --------------------------------
**
-** The data structure for a single virtual r-tree table is stored in three
+** The data structure for a single virtual r-tree table is stored in three
** native SQLite tables declared as follows. In each case, the '%' character
** in the table name is replaced with the user-supplied name of the r-tree
** table.
**
** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB)
** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
-** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
+** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...)
**
** The data for each node of the r-tree structure is stored in the %_node
** table. For each node that is not the root node of the r-tree, there is
** an entry in the %_parent table associating the node with its parent.
** And for each row of data in the table, there is an entry in the %_rowid
** table that maps from the entries rowid to the id of the node that it
-** is stored on.
+** is stored on. If the r-tree contains auxiliary columns, those are stored
+** on the end of the %_rowid table.
**
** The root node of an r-tree always exists, even if the r-tree table is
** empty. The nodeno of the root node is always 1. All other nodes in the
@@ -161358,7 +188102,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
** of the node contain the tree depth as a big-endian integer.
** For non-root nodes, the first 2 bytes are left unused.
**
-** 2. The next 2 bytes contain the number of entries currently
+** 2. The next 2 bytes contain the number of entries currently
** stored in the node.
**
** 3. The remainder of the node contains the node entries. Each entry
@@ -161368,7 +188112,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
** child page.
*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)
+#if !defined(SQLITE_CORE) \
+ || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))
#ifndef SQLITE_CORE
/* #include "sqlite3ext.h" */
@@ -161376,18 +188121,27 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
#else
/* #include "sqlite3.h" */
#endif
-
-/* #include <string.h> */
-/* #include <assert.h> */
-/* #include <stdio.h> */
+SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
#ifndef SQLITE_AMALGAMATION
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
+typedef sqlite3_uint64 u64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+# define NDEBUG 1
#endif
+#if defined(NDEBUG) && defined(SQLITE_DEBUG)
+# undef NDEBUG
+#endif
+#endif
+
+/* #include <string.h> */
+/* #include <stdio.h> */
+/* #include <assert.h> */
+/* #include <stdlib.h> */
/* The following macro is used to suppress compiler warnings.
*/
@@ -161408,8 +188162,11 @@ typedef struct RtreeSearchPoint RtreeSearchPoint;
/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */
#define RTREE_MAX_DIMENSIONS 5
+/* Maximum number of auxiliary columns */
+#define RTREE_MAX_AUX_COLUMN 100
+
/* Size of hash table Rtree.aHash. This hash table is not expected to
-** ever contain very many entries, so a fixed number of buckets is
+** ever contain very many entries, so a fixed number of buckets is
** used.
*/
#define HASHSIZE 97
@@ -161418,13 +188175,13 @@ typedef struct RtreeSearchPoint RtreeSearchPoint;
** the number of rows in the virtual table to calculate the costs of
** various strategies. If possible, this estimate is loaded from the
** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum).
-** Otherwise, if no sqlite_stat1 entry is available, use
+** Otherwise, if no sqlite_stat1 entry is available, use
** RTREE_DEFAULT_ROWEST.
*/
#define RTREE_DEFAULT_ROWEST 1048576
#define RTREE_MIN_ROWEST 100
-/*
+/*
** An rtree virtual-table object.
*/
struct Rtree {
@@ -161432,24 +188189,36 @@ struct Rtree {
sqlite3 *db; /* Host database connection */
int iNodeSize; /* Size in bytes of each node in the node table */
u8 nDim; /* Number of dimensions */
+ u8 nDim2; /* Twice the number of dimensions */
u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
u8 nBytesPerCell; /* Bytes consumed per cell */
+ u8 inWrTrans; /* True if inside write transaction */
+ u8 nAux; /* # of auxiliary columns in %_rowid */
+ u8 nAuxNotNull; /* Number of initial not-null aux columns */
+#ifdef SQLITE_DEBUG
+ u8 bCorrupt; /* Shadow table corruption detected */
+#endif
int iDepth; /* Current depth of the r-tree structure */
char *zDb; /* Name of database containing r-tree table */
- char *zName; /* Name of r-tree table */
- int nBusy; /* Current number of users of this structure */
+ char *zName; /* Name of r-tree table */
+ u32 nBusy; /* Current number of users of this structure */
i64 nRowEst; /* Estimated number of rows in this table */
+ u32 nCursor; /* Number of open cursors */
+ u32 nNodeRef; /* Number RtreeNodes with positive nRef */
+ char *zReadAuxSql; /* SQL for statement to read aux data */
/* List of nodes removed during a CondenseTree operation. List is
** linked together via the pointer normally used for hash chains -
- ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree
+ ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree
** headed by the node (leaf nodes have RtreeNode.iNode==0).
*/
RtreeNode *pDeleted;
int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */
+ /* Blob I/O on xxx_node */
+ sqlite3_blob *pNodeBlob;
+
/* Statements to read/write/delete a record from xxx_node */
- sqlite3_stmt *pReadNode;
sqlite3_stmt *pWriteNode;
sqlite3_stmt *pDeleteNode;
@@ -161463,7 +188232,10 @@ struct Rtree {
sqlite3_stmt *pWriteParent;
sqlite3_stmt *pDeleteParent;
- RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */
+ /* Statement for writing to the "aux:" fields, if there are any */
+ sqlite3_stmt *pWriteAux;
+
+ RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */
};
/* Possible values for Rtree.eCoordType: */
@@ -161486,6 +188258,15 @@ struct Rtree {
#endif
/*
+** Set the Rtree.bCorrupt flag
+*/
+#ifdef SQLITE_DEBUG
+# define RTREE_IS_CORRUPT(X) ((X)->bCorrupt = 1)
+#else
+# define RTREE_IS_CORRUPT(X)
+#endif
+
+/*
** When doing a search of an r-tree, instances of the following structure
** record intermediate results from the tree walk.
**
@@ -161503,7 +188284,7 @@ struct RtreeSearchPoint {
};
/*
-** The minimum number of cells allowed for a node is a third of the
+** The minimum number of cells allowed for a node is a third of the
** maximum. In Gutman's notation:
**
** m = M/3
@@ -161518,8 +188299,8 @@ struct RtreeSearchPoint {
/*
** The smallest possible node-size is (512-64)==448 bytes. And the largest
** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
-** Therefore all non-root nodes must contain at least 3 entries. Since
-** 2^40 is greater than 2^64, an r-tree structure always has a depth of
+** Therefore all non-root nodes must contain at least 3 entries. Since
+** 3^40 is greater than 2^64, an r-tree structure always has a depth of
** 40 or less.
*/
#define RTREE_MAX_DEPTH 40
@@ -161532,13 +188313,14 @@ struct RtreeSearchPoint {
*/
#define RTREE_CACHE_SZ 5
-/*
+/*
** An rtree cursor object.
*/
struct RtreeCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
u8 atEOF; /* True if at end of search */
u8 bPoint; /* True if sPoint is valid */
+ u8 bAuxValid; /* True if pReadAux is valid */
int iStrategy; /* Copy of idxNum search parameter */
int nConstraint; /* Number of entries in aConstraint */
RtreeConstraint *aConstraint; /* Search constraints. */
@@ -161546,6 +188328,7 @@ struct RtreeCursor {
int nPoint; /* Number of slots used in aPoint[] */
int mxLevel; /* iLevel value for root of the tree */
RtreeSearchPoint *aPoint; /* Priority queue for search points */
+ sqlite3_stmt *pReadAux; /* Statement to read aux-data */
RtreeSearchPoint sPoint; /* Cached next search point */
RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */
u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */
@@ -161603,8 +188386,14 @@ struct RtreeConstraint {
#define RTREE_MATCH 0x46 /* F: Old-style sqlite3_rtree_geometry_callback() */
#define RTREE_QUERY 0x47 /* G: New-style sqlite3_rtree_query_callback() */
+/* Special operators available only on cursors. Needs to be consecutive
+** with the normal values above, but must be less than RTREE_MATCH. These
+** are used in the cursor for contraints such as x=NULL (RTREE_FALSE) or
+** x<'xyz' (RTREE_TRUE) */
+#define RTREE_TRUE 0x3f /* ? */
+#define RTREE_FALSE 0x40 /* @ */
-/*
+/*
** An rtree structure node.
*/
struct RtreeNode {
@@ -161619,7 +188408,7 @@ struct RtreeNode {
/* Return the number of cells in a node */
#define NCELL(pNode) readInt16(&(pNode)->zData[2])
-/*
+/*
** A single cell from a node, deserialized
*/
struct RtreeCell {
@@ -161634,11 +188423,11 @@ struct RtreeCell {
** sqlite3_rtree_query_callback() and which appear on the right of MATCH
** operators in order to constrain a search.
**
-** xGeom and xQueryFunc are the callback functions. Exactly one of
+** xGeom and xQueryFunc are the callback functions. Exactly one of
** xGeom and xQueryFunc fields is non-NULL, depending on whether the
** SQL function was created using sqlite3_rtree_geometry_callback() or
** sqlite3_rtree_query_callback().
-**
+**
** This object is deleted automatically by the destructor mechanism in
** sqlite3_create_function_v2().
*/
@@ -161649,14 +188438,6 @@ struct RtreeGeomCallback {
void *pContext;
};
-
-/*
-** Value for the first field of every RtreeMatchArg object. The MATCH
-** operator tests that the first field of a blob operand matches this
-** value to avoid operating on invalid blobs (which could cause a segfault).
-*/
-#define RTREE_GEOMETRY_MAGIC 0x891245AB
-
/*
** An instance of this structure (in the form of a BLOB) is returned by
** the SQL functions that sqlite3_rtree_geometry_callback() and
@@ -161664,7 +188445,7 @@ struct RtreeGeomCallback {
** operand to the MATCH operator of an R-Tree.
*/
struct RtreeMatchArg {
- u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
+ u32 iSize; /* Size of this object */
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
sqlite3_value **apSqlParam; /* Original SQL parameter values */
@@ -161678,6 +188459,75 @@ struct RtreeMatchArg {
# define MIN(x,y) ((x) > (y) ? (y) : (x))
#endif
+/* What version of GCC is being used. 0 means GCC is not being used .
+** Note that the GCC_VERSION macro will also be set correctly when using
+** clang, since clang works hard to be gcc compatible. So the gcc
+** optimizations will also work when compiling with clang.
+*/
+#ifndef GCC_VERSION
+#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
+# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
+#else
+# define GCC_VERSION 0
+#endif
+#endif
+
+/* The testcase() macro should already be defined in the amalgamation. If
+** it is not, make it a no-op.
+*/
+#ifndef SQLITE_AMALGAMATION
+# define testcase(X)
+#endif
+
+/*
+** Make sure that the compiler intrinsics we desire are enabled when
+** compiling with an appropriate version of MSVC unless prevented by
+** the SQLITE_DISABLE_INTRINSIC define.
+*/
+#if !defined(SQLITE_DISABLE_INTRINSIC)
+# if defined(_MSC_VER) && _MSC_VER>=1400
+# if !defined(_WIN32_WCE)
+/* # include <intrin.h> */
+# pragma intrinsic(_byteswap_ulong)
+# pragma intrinsic(_byteswap_uint64)
+# else
+/* # include <cmnintrin.h> */
+# endif
+# endif
+#endif
+
+/*
+** Macros to determine whether the machine is big or little endian,
+** and whether or not that determination is run-time or compile-time.
+**
+** For best performance, an attempt is made to guess at the byte-order
+** using C-preprocessor macros. If that is unsuccessful, or if
+** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
+** at run-time.
+*/
+#ifndef SQLITE_BYTEORDER
+#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__arm__)
+# define SQLITE_BYTEORDER 1234
+#elif defined(sparc) || defined(__ppc__)
+# define SQLITE_BYTEORDER 4321
+#else
+# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
+#endif
+#endif
+
+
+/* What version of MSVC is being used. 0 means MSVC is not being used */
+#ifndef MSVC_VERSION
+#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
+# define MSVC_VERSION _MSC_VER
+#else
+# define MSVC_VERSION 0
+#endif
+#endif
+
/*
** Functions to deserialize a 16 bit integer, 32 bit real number and
** 64 bit integer. The deserialized value is returned.
@@ -161686,24 +188536,47 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
+ assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
+#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
+ pCoord->u = _byteswap_ulong(*(u32*)p);
+#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
+ pCoord->u = __builtin_bswap32(*(u32*)p);
+#elif SQLITE_BYTEORDER==4321
+ pCoord->u = *(u32*)p;
+#else
pCoord->u = (
- (((u32)p[0]) << 24) +
- (((u32)p[1]) << 16) +
- (((u32)p[2]) << 8) +
+ (((u32)p[0]) << 24) +
+ (((u32)p[1]) << 16) +
+ (((u32)p[2]) << 8) +
(((u32)p[3]) << 0)
);
+#endif
}
static i64 readInt64(u8 *p){
- return (
- (((i64)p[0]) << 56) +
- (((i64)p[1]) << 48) +
- (((i64)p[2]) << 40) +
- (((i64)p[3]) << 32) +
- (((i64)p[4]) << 24) +
- (((i64)p[5]) << 16) +
- (((i64)p[6]) << 8) +
- (((i64)p[7]) << 0)
+#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
+ u64 x;
+ memcpy(&x, p, 8);
+ return (i64)_byteswap_uint64(x);
+#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
+ u64 x;
+ memcpy(&x, p, 8);
+ return (i64)__builtin_bswap64(x);
+#elif SQLITE_BYTEORDER==4321
+ i64 x;
+ memcpy(&x, p, 8);
+ return x;
+#else
+ return (i64)(
+ (((u64)p[0]) << 56) +
+ (((u64)p[1]) << 48) +
+ (((u64)p[2]) << 40) +
+ (((u64)p[3]) << 32) +
+ (((u64)p[4]) << 24) +
+ (((u64)p[5]) << 16) +
+ (((u64)p[6]) << 8) +
+ (((u64)p[7]) << 0)
);
+#endif
}
/*
@@ -161711,23 +188584,43 @@ static i64 readInt64(u8 *p){
** 64 bit integer. The value returned is the number of bytes written
** to the argument buffer (always 2, 4 and 8 respectively).
*/
-static int writeInt16(u8 *p, int i){
+static void writeInt16(u8 *p, int i){
p[0] = (i>> 8)&0xFF;
p[1] = (i>> 0)&0xFF;
- return 2;
}
static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
+ assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
+#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
+ i = __builtin_bswap32(pCoord->u);
+ memcpy(p, &i, 4);
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
+ i = _byteswap_ulong(pCoord->u);
+ memcpy(p, &i, 4);
+#elif SQLITE_BYTEORDER==4321
+ i = pCoord->u;
+ memcpy(p, &i, 4);
+#else
i = pCoord->u;
p[0] = (i>>24)&0xFF;
p[1] = (i>>16)&0xFF;
p[2] = (i>> 8)&0xFF;
p[3] = (i>> 0)&0xFF;
+#endif
return 4;
}
static int writeInt64(u8 *p, i64 i){
+#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
+ i = (i64)__builtin_bswap64((u64)i);
+ memcpy(p, &i, 8);
+#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
+ i = (i64)_byteswap_uint64((u64)i);
+ memcpy(p, &i, 8);
+#elif SQLITE_BYTEORDER==4321
+ memcpy(p, &i, 8);
+#else
p[0] = (i>>56)&0xFF;
p[1] = (i>>48)&0xFF;
p[2] = (i>>40)&0xFF;
@@ -161736,6 +188629,7 @@ static int writeInt64(u8 *p, i64 i){
p[5] = (i>>16)&0xFF;
p[6] = (i>> 8)&0xFF;
p[7] = (i>> 0)&0xFF;
+#endif
return 8;
}
@@ -161744,6 +188638,7 @@ static int writeInt64(u8 *p, i64 i){
*/
static void nodeReference(RtreeNode *p){
if( p ){
+ assert( p->nRef>0 );
p->nRef++;
}
}
@@ -161760,8 +188655,8 @@ static void nodeZero(Rtree *pRtree, RtreeNode *p){
** Given a node number iNode, return the corresponding key to use
** in the Rtree.aHash table.
*/
-static int nodeHash(i64 iNode){
- return iNode % HASHSIZE;
+static unsigned int nodeHash(i64 iNode){
+ return ((unsigned)iNode) % HASHSIZE;
}
/*
@@ -161806,11 +188701,12 @@ static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){
*/
static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
RtreeNode *pNode;
- pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
+ pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode) + pRtree->iNodeSize);
if( pNode ){
memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
pNode->zData = (u8 *)&pNode[1];
pNode->nRef = 1;
+ pRtree->nNodeRef++;
pNode->pParent = pParent;
pNode->isDirty = 1;
nodeReference(pParent);
@@ -161819,6 +188715,29 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
}
/*
+** Clear the Rtree.pNodeBlob object
+*/
+static void nodeBlobReset(Rtree *pRtree){
+ if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
+ sqlite3_blob *pBlob = pRtree->pNodeBlob;
+ pRtree->pNodeBlob = 0;
+ sqlite3_blob_close(pBlob);
+ }
+}
+
+/*
+** Check to see if pNode is the same as pParent or any of the parents
+** of pParent.
+*/
+static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){
+ do{
+ if( pNode==pParent ) return 1;
+ pParent = pParent->pParent;
+ }while( pParent );
+ return 0;
+}
+
+/*
** Obtain a reference to an r-tree node.
*/
static int nodeAcquire(
@@ -161827,46 +188746,71 @@ static int nodeAcquire(
RtreeNode *pParent, /* Either the parent node or NULL */
RtreeNode **ppNode /* OUT: Acquired node */
){
- int rc;
- int rc2 = SQLITE_OK;
- RtreeNode *pNode;
+ int rc = SQLITE_OK;
+ RtreeNode *pNode = 0;
/* Check if the requested node is already in the hash table. If so,
** increase its reference count and return it.
*/
- if( (pNode = nodeHashLookup(pRtree, iNode)) ){
- assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
+ if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
if( pParent && !pNode->pParent ){
- nodeReference(pParent);
+ if( nodeInParentChain(pNode, pParent) ){
+ RTREE_IS_CORRUPT(pRtree);
+ return SQLITE_CORRUPT_VTAB;
+ }
+ pParent->nRef++;
pNode->pParent = pParent;
+ }else if( pParent && pNode->pParent && pParent!=pNode->pParent ){
+ RTREE_IS_CORRUPT(pRtree);
+ return SQLITE_CORRUPT_VTAB;
}
pNode->nRef++;
*ppNode = pNode;
return SQLITE_OK;
}
- sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);
- rc = sqlite3_step(pRtree->pReadNode);
- if( rc==SQLITE_ROW ){
- const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
- if( pRtree->iNodeSize==sqlite3_column_bytes(pRtree->pReadNode, 0) ){
- pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
- if( !pNode ){
- rc2 = SQLITE_NOMEM;
- }else{
- pNode->pParent = pParent;
- pNode->zData = (u8 *)&pNode[1];
- pNode->nRef = 1;
- pNode->iNode = iNode;
- pNode->isDirty = 0;
- pNode->pNext = 0;
- memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
- nodeReference(pParent);
- }
+ if( pRtree->pNodeBlob ){
+ sqlite3_blob *pBlob = pRtree->pNodeBlob;
+ pRtree->pNodeBlob = 0;
+ rc = sqlite3_blob_reopen(pBlob, iNode);
+ pRtree->pNodeBlob = pBlob;
+ if( rc ){
+ nodeBlobReset(pRtree);
+ if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
+ }
+ }
+ if( pRtree->pNodeBlob==0 ){
+ char *zTab = sqlite3_mprintf("%s_node", pRtree->zName);
+ if( zTab==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
+ &pRtree->pNodeBlob);
+ sqlite3_free(zTab);
+ }
+ if( rc ){
+ nodeBlobReset(pRtree);
+ *ppNode = 0;
+ /* If unable to open an sqlite3_blob on the desired row, that can only
+ ** be because the shadow tables hold erroneous data. */
+ if( rc==SQLITE_ERROR ){
+ rc = SQLITE_CORRUPT_VTAB;
+ RTREE_IS_CORRUPT(pRtree);
+ }
+ }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){
+ pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize);
+ if( !pNode ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pNode->pParent = pParent;
+ pNode->zData = (u8 *)&pNode[1];
+ pNode->nRef = 1;
+ pRtree->nNodeRef++;
+ pNode->iNode = iNode;
+ pNode->isDirty = 0;
+ pNode->pNext = 0;
+ rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
+ pRtree->iNodeSize, 0);
}
}
- rc = sqlite3_reset(pRtree->pReadNode);
- if( rc==SQLITE_OK ) rc = rc2;
/* If the root node was just loaded, set pRtree->iDepth to the height
** of the r-tree structure. A height of zero means all data is stored on
@@ -161878,28 +188822,35 @@ static int nodeAcquire(
pRtree->iDepth = readInt16(pNode->zData);
if( pRtree->iDepth>RTREE_MAX_DEPTH ){
rc = SQLITE_CORRUPT_VTAB;
+ RTREE_IS_CORRUPT(pRtree);
}
}
/* 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
+ ** field on the node is too large. If so, set the return code to
** SQLITE_CORRUPT_VTAB.
*/
if( pNode && rc==SQLITE_OK ){
if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){
rc = SQLITE_CORRUPT_VTAB;
+ RTREE_IS_CORRUPT(pRtree);
}
}
if( rc==SQLITE_OK ){
if( pNode!=0 ){
+ nodeReference(pParent);
nodeHashInsert(pRtree, pNode);
}else{
rc = SQLITE_CORRUPT_VTAB;
+ RTREE_IS_CORRUPT(pRtree);
}
*ppNode = pNode;
}else{
- sqlite3_free(pNode);
+ if( pNode ){
+ pRtree->nNodeRef--;
+ sqlite3_free(pNode);
+ }
*ppNode = 0;
}
@@ -161918,7 +188869,7 @@ static void nodeOverwriteCell(
int ii;
u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
p += writeInt64(p, pCell->iRowid);
- for(ii=0; ii<(pRtree->nDim*2); ii++){
+ for(ii=0; ii<pRtree->nDim2; ii++){
p += writeCoord(p, &pCell->aCoord[ii]);
}
pNode->isDirty = 1;
@@ -161979,6 +188930,7 @@ static int nodeWrite(Rtree *pRtree, RtreeNode *pNode){
sqlite3_step(p);
pNode->isDirty = 0;
rc = sqlite3_reset(p);
+ sqlite3_bind_null(p, 2);
if( pNode->iNode==0 && rc==SQLITE_OK ){
pNode->iNode = sqlite3_last_insert_rowid(pRtree->db);
nodeHashInsert(pRtree, pNode);
@@ -161995,8 +188947,10 @@ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){
int rc = SQLITE_OK;
if( pNode ){
assert( pNode->nRef>0 );
+ assert( pRtree->nNodeRef>0 );
pNode->nRef--;
if( pNode->nRef==0 ){
+ pRtree->nNodeRef--;
if( pNode->iNode==1 ){
pRtree->iDepth = -1;
}
@@ -162052,13 +189006,16 @@ static void nodeGetCell(
){
u8 *pData;
RtreeCoord *pCoord;
- int ii;
+ int ii = 0;
pCell->iRowid = nodeGetRowid(pRtree, pNode, iCell);
pData = pNode->zData + (12 + pRtree->nBytesPerCell*iCell);
pCoord = pCell->aCoord;
- for(ii=0; ii<pRtree->nDim*2; ii++){
- readCoord(&pData[ii*4], &pCoord[ii]);
- }
+ do{
+ readCoord(pData, &pCoord[ii]);
+ readCoord(pData+4, &pCoord[ii+1]);
+ pData += 8;
+ ii += 2;
+ }while( ii<pRtree->nDim2 );
}
@@ -162069,7 +189026,7 @@ static int rtreeInit(
sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int
);
-/*
+/*
** Rtree virtual table module xCreate method.
*/
static int rtreeCreate(
@@ -162082,7 +189039,7 @@ static int rtreeCreate(
return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
}
-/*
+/*
** Rtree virtual table module xConnect method.
*/
static int rtreeConnect(
@@ -162109,7 +189066,10 @@ static void rtreeReference(Rtree *pRtree){
static void rtreeRelease(Rtree *pRtree){
pRtree->nBusy--;
if( pRtree->nBusy==0 ){
- sqlite3_finalize(pRtree->pReadNode);
+ pRtree->inWrTrans = 0;
+ assert( pRtree->nCursor==0 );
+ nodeBlobReset(pRtree);
+ assert( pRtree->nNodeRef==0 || pRtree->bCorrupt );
sqlite3_finalize(pRtree->pWriteNode);
sqlite3_finalize(pRtree->pDeleteNode);
sqlite3_finalize(pRtree->pReadRowid);
@@ -162118,11 +189078,13 @@ static void rtreeRelease(Rtree *pRtree){
sqlite3_finalize(pRtree->pReadParent);
sqlite3_finalize(pRtree->pWriteParent);
sqlite3_finalize(pRtree->pDeleteParent);
+ sqlite3_finalize(pRtree->pWriteAux);
+ sqlite3_free(pRtree->zReadAuxSql);
sqlite3_free(pRtree);
}
}
-/*
+/*
** Rtree virtual table module xDisconnect method.
*/
static int rtreeDisconnect(sqlite3_vtab *pVtab){
@@ -162130,7 +189092,7 @@ static int rtreeDisconnect(sqlite3_vtab *pVtab){
return SQLITE_OK;
}
-/*
+/*
** Rtree virtual table module xDestroy method.
*/
static int rtreeDestroy(sqlite3_vtab *pVtab){
@@ -162140,13 +189102,14 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
"DROP TABLE '%q'.'%q_node';"
"DROP TABLE '%q'.'%q_rowid';"
"DROP TABLE '%q'.'%q_parent';",
- pRtree->zDb, pRtree->zName,
+ pRtree->zDb, pRtree->zName,
pRtree->zDb, pRtree->zName,
pRtree->zDb, pRtree->zName
);
if( !zCreate ){
rc = SQLITE_NOMEM;
}else{
+ nodeBlobReset(pRtree);
rc = sqlite3_exec(pRtree->db, zCreate, 0, 0, 0);
sqlite3_free(zCreate);
}
@@ -162157,18 +189120,20 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
return rc;
}
-/*
+/*
** Rtree virtual table module xOpen method.
*/
static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
int rc = SQLITE_NOMEM;
+ Rtree *pRtree = (Rtree *)pVTab;
RtreeCursor *pCsr;
- pCsr = (RtreeCursor *)sqlite3_malloc(sizeof(RtreeCursor));
+ pCsr = (RtreeCursor *)sqlite3_malloc64(sizeof(RtreeCursor));
if( pCsr ){
memset(pCsr, 0, sizeof(RtreeCursor));
pCsr->base.pVtab = pVTab;
rc = SQLITE_OK;
+ pRtree->nCursor++;
}
*ppCursor = (sqlite3_vtab_cursor *)pCsr;
@@ -162177,9 +189142,12 @@ static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
/*
-** Free the RtreeCursor.aConstraint[] array and its contents.
+** Reset a cursor back to its initial state.
*/
-static void freeCursorConstraints(RtreeCursor *pCsr){
+static void resetCursor(RtreeCursor *pCsr){
+ Rtree *pRtree = (Rtree *)(pCsr->base.pVtab);
+ int ii;
+ sqlite3_stmt *pStmt;
if( pCsr->aConstraint ){
int i; /* Used to iterate through constraint array */
for(i=0; i<pCsr->nConstraint; i++){
@@ -162192,26 +189160,34 @@ static void freeCursorConstraints(RtreeCursor *pCsr){
sqlite3_free(pCsr->aConstraint);
pCsr->aConstraint = 0;
}
+ for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
+ sqlite3_free(pCsr->aPoint);
+ pStmt = pCsr->pReadAux;
+ memset(pCsr, 0, sizeof(RtreeCursor));
+ pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+ pCsr->pReadAux = pStmt;
+
}
-/*
+/*
** Rtree virtual table module xClose method.
*/
static int rtreeClose(sqlite3_vtab_cursor *cur){
Rtree *pRtree = (Rtree *)(cur->pVtab);
- int ii;
RtreeCursor *pCsr = (RtreeCursor *)cur;
- freeCursorConstraints(pCsr);
- sqlite3_free(pCsr->aPoint);
- for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
+ assert( pRtree->nCursor>0 );
+ resetCursor(pCsr);
+ sqlite3_finalize(pCsr->pReadAux);
sqlite3_free(pCsr);
+ pRtree->nCursor--;
+ nodeBlobReset(pRtree);
return SQLITE_OK;
}
/*
** Rtree virtual table module xEof method.
**
-** Return non-zero if the cursor does not currently point to a valid
+** Return non-zero if the cursor does not currently point to a valid
** record (i.e if the scan has finished), or zero otherwise.
*/
static int rtreeEof(sqlite3_vtab_cursor *cur){
@@ -162227,15 +189203,22 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
** false. a[] is the four bytes of the on-disk record to be decoded.
** Store the results in "r".
**
-** There are three versions of this macro, one each for little-endian and
-** big-endian processors and a third generic implementation. The endian-
-** specific implementations are much faster and are preferred if the
-** processor endianness is known at compile-time. The SQLITE_BYTEORDER
-** macro is part of sqliteInt.h and hence the endian-specific
-** implementation will only be used if this module is compiled as part
-** of the amalgamation.
+** There are five versions of this macro. The last one is generic. The
+** other four are various architectures-specific optimizations.
*/
-#if defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==1234
+#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
+#define RTREE_DECODE_COORD(eInt, a, r) { \
+ RtreeCoord c; /* Coordinate decoded */ \
+ c.u = _byteswap_ulong(*(u32*)a); \
+ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
+}
+#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
+#define RTREE_DECODE_COORD(eInt, a, r) { \
+ RtreeCoord c; /* Coordinate decoded */ \
+ c.u = __builtin_bswap32(*(u32*)a); \
+ r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
+}
+#elif SQLITE_BYTEORDER==1234
#define RTREE_DECODE_COORD(eInt, a, r) { \
RtreeCoord c; /* Coordinate decoded */ \
memcpy(&c.u,a,4); \
@@ -162243,7 +189226,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
((c.u&0xff)<<24)|((c.u&0xff00)<<8); \
r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
}
-#elif defined(SQLITE_BYTEORDER) && SQLITE_BYTEORDER==4321
+#elif SQLITE_BYTEORDER==4321
#define RTREE_DECODE_COORD(eInt, a, r) { \
RtreeCoord c; /* Coordinate decoded */ \
memcpy(&c.u,a,4); \
@@ -162260,7 +189243,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
/*
** Check the RTree node or entry given by pCellData and p against the MATCH
-** constraint pConstraint.
+** constraint pConstraint.
*/
static int rtreeCallbackConstraint(
RtreeConstraint *pConstraint, /* The constraint to test */
@@ -162270,10 +189253,10 @@ static int rtreeCallbackConstraint(
sqlite3_rtree_dbl *prScore, /* OUT: score for the cell */
int *peWithin /* OUT: visibility of the cell */
){
- int i; /* Loop counter */
sqlite3_rtree_query_info *pInfo = pConstraint->pInfo; /* Callback info */
int nCoord = pInfo->nCoord; /* No. of coordinates */
int rc; /* Callback return code */
+ RtreeCoord c; /* Translator union */
sqlite3_rtree_dbl aCoord[RTREE_MAX_DIMENSIONS*2]; /* Decoded coordinates */
assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY );
@@ -162283,13 +189266,41 @@ static int rtreeCallbackConstraint(
pInfo->iRowid = readInt64(pCellData);
}
pCellData += 8;
- for(i=0; i<nCoord; i++, pCellData += 4){
- RTREE_DECODE_COORD(eInt, pCellData, aCoord[i]);
+#ifndef SQLITE_RTREE_INT_ONLY
+ if( eInt==0 ){
+ switch( nCoord ){
+ case 10: readCoord(pCellData+36, &c); aCoord[9] = c.f;
+ readCoord(pCellData+32, &c); aCoord[8] = c.f;
+ case 8: readCoord(pCellData+28, &c); aCoord[7] = c.f;
+ readCoord(pCellData+24, &c); aCoord[6] = c.f;
+ case 6: readCoord(pCellData+20, &c); aCoord[5] = c.f;
+ readCoord(pCellData+16, &c); aCoord[4] = c.f;
+ case 4: readCoord(pCellData+12, &c); aCoord[3] = c.f;
+ readCoord(pCellData+8, &c); aCoord[2] = c.f;
+ default: readCoord(pCellData+4, &c); aCoord[1] = c.f;
+ readCoord(pCellData, &c); aCoord[0] = c.f;
+ }
+ }else
+#endif
+ {
+ switch( nCoord ){
+ case 10: readCoord(pCellData+36, &c); aCoord[9] = c.i;
+ readCoord(pCellData+32, &c); aCoord[8] = c.i;
+ case 8: readCoord(pCellData+28, &c); aCoord[7] = c.i;
+ readCoord(pCellData+24, &c); aCoord[6] = c.i;
+ case 6: readCoord(pCellData+20, &c); aCoord[5] = c.i;
+ readCoord(pCellData+16, &c); aCoord[4] = c.i;
+ case 4: readCoord(pCellData+12, &c); aCoord[3] = c.i;
+ readCoord(pCellData+8, &c); aCoord[2] = c.i;
+ default: readCoord(pCellData+4, &c); aCoord[1] = c.i;
+ readCoord(pCellData, &c); aCoord[0] = c.i;
+ }
}
if( pConstraint->op==RTREE_MATCH ){
+ int eWithin = 0;
rc = pConstraint->u.xGeom((sqlite3_rtree_geometry*)pInfo,
- nCoord, aCoord, &i);
- if( i==0 ) *peWithin = NOT_WITHIN;
+ nCoord, aCoord, &eWithin);
+ if( eWithin==0 ) *peWithin = NOT_WITHIN;
*prScore = RTREE_ZERO;
}else{
pInfo->aCoord = aCoord;
@@ -162305,7 +189316,7 @@ static int rtreeCallbackConstraint(
return rc;
}
-/*
+/*
** Check the internal RTree node given by pCellData against constraint p.
** If this constraint cannot be satisfied by any child within the node,
** set *peWithin to NOT_WITHIN.
@@ -162323,9 +189334,13 @@ static void rtreeNonleafConstraint(
*/
pCellData += 8 + 4*(p->iCoord&0xfe);
- assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
- || p->op==RTREE_GT || p->op==RTREE_EQ );
+ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
+ || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
+ || p->op==RTREE_FALSE );
+ assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
switch( p->op ){
+ case RTREE_TRUE: return; /* Always satisfied */
+ case RTREE_FALSE: break; /* Never satisfied */
case RTREE_LE:
case RTREE_LT:
case RTREE_EQ:
@@ -162362,27 +189377,31 @@ static void rtreeLeafConstraint(
){
RtreeDValue xN; /* Coordinate value converted to a double */
- assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
- || p->op==RTREE_GT || p->op==RTREE_EQ );
+ assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
+ || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
+ || p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
+ assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
- case RTREE_LE: if( xN <= p->u.rValue ) return; break;
- case RTREE_LT: if( xN < p->u.rValue ) return; break;
- case RTREE_GE: if( xN >= p->u.rValue ) return; break;
- case RTREE_GT: if( xN > p->u.rValue ) return; break;
- default: if( xN == p->u.rValue ) return; break;
+ case RTREE_TRUE: return; /* Always satisfied */
+ case RTREE_FALSE: break; /* Never satisfied */
+ case RTREE_LE: if( xN <= p->u.rValue ) return; break;
+ case RTREE_LT: if( xN < p->u.rValue ) return; break;
+ case RTREE_GE: if( xN >= p->u.rValue ) return; break;
+ case RTREE_GT: if( xN > p->u.rValue ) return; break;
+ default: if( xN == p->u.rValue ) return; break;
}
*peWithin = NOT_WITHIN;
}
/*
-** One of the cells in node pNode is guaranteed to have a 64-bit
+** One of the cells in node pNode is guaranteed to have a 64-bit
** integer value equal to iRowid. Return the index of this cell.
*/
static int nodeRowidIndex(
- Rtree *pRtree,
- RtreeNode *pNode,
+ Rtree *pRtree,
+ RtreeNode *pNode,
i64 iRowid,
int *piIndex
){
@@ -162395,6 +189414,7 @@ static int nodeRowidIndex(
return SQLITE_OK;
}
}
+ RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@@ -162433,7 +189453,7 @@ static int rtreeSearchPointCompare(
}
/*
-** Interchange to search points in a cursor.
+** Interchange two search points in a cursor.
*/
static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){
RtreeSearchPoint t = p->aPoint[i];
@@ -162488,7 +189508,7 @@ static RtreeSearchPoint *rtreeEnqueue(
RtreeSearchPoint *pNew;
if( pCur->nPoint>=pCur->nPointAlloc ){
int nNew = pCur->nPointAlloc*2 + 8;
- pNew = sqlite3_realloc(pCur->aPoint, nNew*sizeof(pCur->aPoint[0]));
+ pNew = sqlite3_realloc64(pCur->aPoint, nNew*sizeof(pCur->aPoint[0]));
if( pNew==0 ) return 0;
pCur->aPoint = pNew;
pCur->nPointAlloc = nNew;
@@ -162523,7 +189543,7 @@ static RtreeSearchPoint *rtreeSearchPointNew(
pFirst = rtreeSearchPointFirst(pCur);
pCur->anQueue[iLevel]++;
if( pFirst==0
- || pFirst->rScore>rScore
+ || pFirst->rScore>rScore
|| (pFirst->rScore==rScore && pFirst->iLevel>iLevel)
){
if( pCur->bPoint ){
@@ -162534,7 +189554,7 @@ static RtreeSearchPoint *rtreeSearchPointNew(
if( ii<RTREE_CACHE_SZ ){
assert( pCur->aNode[ii]==0 );
pCur->aNode[ii] = pCur->aNode[0];
- }else{
+ }else{
nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]);
}
pCur->aNode[0] = 0;
@@ -162643,13 +189663,14 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
eInt = pRtree->eCoordType==RTREE_COORD_INT32;
while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){
+ u8 *pCellData;
pNode = rtreeNodeOfFirstSearchPoint(pCur, &rc);
if( rc ) return rc;
nCell = NCELL(pNode);
assert( nCell<200 );
+ pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell);
while( p->iCell<nCell ){
sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1;
- u8 *pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell);
eWithin = FULLY_WITHIN;
for(ii=0; ii<nConstraint; ii++){
RtreeConstraint *pConstraint = pCur->aConstraint + ii;
@@ -162662,13 +189683,23 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
}else{
rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin);
}
- if( eWithin==NOT_WITHIN ) break;
+ if( eWithin==NOT_WITHIN ){
+ p->iCell++;
+ pCellData += pRtree->nBytesPerCell;
+ break;
+ }
}
- p->iCell++;
if( eWithin==NOT_WITHIN ) continue;
+ p->iCell++;
x.iLevel = p->iLevel - 1;
if( x.iLevel ){
x.id = readInt64(pCellData);
+ for(ii=0; ii<pCur->nPoint; ii++){
+ if( pCur->aPoint[ii].id==x.id ){
+ RTREE_IS_CORRUPT(pRtree);
+ return SQLITE_CORRUPT_VTAB;
+ }
+ }
x.iCell = 0;
}else{
x.id = p->id;
@@ -162681,7 +189712,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
if( rScore<RTREE_ZERO ) rScore = RTREE_ZERO;
p = rtreeSearchPointNew(pCur, rScore, x.iLevel);
if( p==0 ) return SQLITE_NOMEM;
- p->eWithin = eWithin;
+ p->eWithin = (u8)eWithin;
p->id = x.id;
p->iCell = x.iCell;
RTREE_QUEUE_TRACE(pCur, "PUSH-S:");
@@ -162696,7 +189727,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
return SQLITE_OK;
}
-/*
+/*
** Rtree virtual table module xNext method.
*/
static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
@@ -162705,12 +189736,16 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
/* Move to the next entry that matches the configured constraints. */
RTREE_QUEUE_TRACE(pCsr, "POP-Nx:");
+ if( pCsr->bAuxValid ){
+ pCsr->bAuxValid = 0;
+ sqlite3_reset(pCsr->pReadAux);
+ }
rtreeSearchPointPop(pCsr);
rc = rtreeStepToLeaf(pCsr);
return rc;
}
-/*
+/*
** Rtree virtual table module xRowid method.
*/
static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
@@ -162724,7 +189759,7 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
return rc;
}
-/*
+/*
** Rtree virtual table module xColumn method.
*/
static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
@@ -162739,8 +189774,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
if( p==0 ) return SQLITE_OK;
if( i==0 ){
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
- }else{
- if( rc ) return rc;
+ }else if( i<=pRtree->nDim2 ){
nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
@@ -162751,12 +189785,32 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
assert( pRtree->eCoordType==RTREE_COORD_INT32 );
sqlite3_result_int(ctx, c.i);
}
+ }else{
+ if( !pCsr->bAuxValid ){
+ if( pCsr->pReadAux==0 ){
+ rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
+ &pCsr->pReadAux, 0);
+ if( rc ) return rc;
+ }
+ sqlite3_bind_int64(pCsr->pReadAux, 1,
+ nodeGetRowid(pRtree, pNode, p->iCell));
+ rc = sqlite3_step(pCsr->pReadAux);
+ if( rc==SQLITE_ROW ){
+ pCsr->bAuxValid = 1;
+ }else{
+ sqlite3_reset(pCsr->pReadAux);
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ return rc;
+ }
+ }
+ sqlite3_result_value(ctx,
+ sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1));
}
return SQLITE_OK;
}
-/*
-** Use nodeAcquire() to obtain the leaf node containing the record with
+/*
+** Use nodeAcquire() to obtain the leaf node containing the record with
** rowid iRowid. If successful, set *ppLeaf to point to the node and
** return SQLITE_OK. If there is no such record in the table, set
** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf
@@ -162789,33 +189843,17 @@ static int findLeafNode(
** operator.
*/
static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
- RtreeMatchArg *pBlob; /* BLOB returned by geometry function */
+ RtreeMatchArg *pBlob, *pSrc; /* BLOB returned by geometry function */
sqlite3_rtree_query_info *pInfo; /* Callback information */
- int nBlob; /* Size of the geometry function blob */
- int nExpected; /* Expected size of the BLOB */
- /* Check that value is actually a blob. */
- if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR;
-
- /* Check that the blob is roughly the right size. */
- nBlob = sqlite3_value_bytes(pValue);
- if( nBlob<(int)sizeof(RtreeMatchArg) ){
- return SQLITE_ERROR;
- }
-
- pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob );
+ pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
+ if( pSrc==0 ) return SQLITE_ERROR;
+ pInfo = (sqlite3_rtree_query_info*)
+ sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
if( !pInfo ) return SQLITE_NOMEM;
memset(pInfo, 0, sizeof(*pInfo));
pBlob = (RtreeMatchArg*)&pInfo[1];
-
- memcpy(pBlob, sqlite3_value_blob(pValue), nBlob);
- nExpected = (int)(sizeof(RtreeMatchArg) +
- pBlob->nParam*sizeof(sqlite3_value*) +
- (pBlob->nParam-1)*sizeof(RtreeDValue));
- if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){
- sqlite3_free(pInfo);
- return SQLITE_ERROR;
- }
+ memcpy(pBlob, pSrc, pSrc->iSize);
pInfo->pContext = pBlob->cb.pContext;
pInfo->nParam = pBlob->nParam;
pInfo->aParam = pBlob->aParam;
@@ -162831,11 +189869,11 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
return SQLITE_OK;
}
-/*
+/*
** Rtree virtual table module xFilter method.
*/
static int rtreeFilter(
- sqlite3_vtab_cursor *pVtabCursor,
+ sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
@@ -162849,10 +189887,7 @@ static int rtreeFilter(
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
- freeCursorConstraints(pCsr);
- sqlite3_free(pCsr->aPoint);
- memset(pCsr, 0, sizeof(RtreeCursor));
- pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+ resetCursor(pCsr);
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
@@ -162861,7 +189896,15 @@ static int rtreeFilter(
RtreeSearchPoint *p; /* Search point for the leaf */
i64 iRowid = sqlite3_value_int64(argv[0]);
i64 iNode = 0;
- rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
+ int eType = sqlite3_value_numeric_type(argv[0]);
+ if( eType==SQLITE_INTEGER
+ || (eType==SQLITE_FLOAT && sqlite3_value_double(argv[0])==iRowid)
+ ){
+ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
+ }else{
+ rc = SQLITE_OK;
+ pLeaf = 0;
+ }
if( rc==SQLITE_OK && pLeaf!=0 ){
p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
assert( p!=0 ); /* Always returns pCsr->sPoint */
@@ -162869,18 +189912,18 @@ static int rtreeFilter(
p->id = iNode;
p->eWithin = PARTLY_WITHIN;
rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
- p->iCell = iCell;
+ p->iCell = (u8)iCell;
RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:");
}else{
pCsr->atEOF = 1;
}
}else{
- /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
- ** with the configured constraints.
+ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
+ ** with the configured constraints.
*/
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
if( rc==SQLITE_OK && argc>0 ){
- pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc);
+ pCsr->aConstraint = sqlite3_malloc64(sizeof(RtreeConstraint)*argc);
pCsr->nConstraint = argc;
if( !pCsr->aConstraint ){
rc = SQLITE_NOMEM;
@@ -162891,6 +189934,7 @@ static int rtreeFilter(
|| (idxStr && (int)strlen(idxStr)==argc*2) );
for(ii=0; ii<argc; ii++){
RtreeConstraint *p = &pCsr->aConstraint[ii];
+ int eType = sqlite3_value_numeric_type(argv[ii]);
p->op = idxStr[ii*2];
p->iCoord = idxStr[ii*2+1]-'0';
if( p->op>=RTREE_MATCH ){
@@ -162902,22 +189946,31 @@ static int rtreeFilter(
if( rc!=SQLITE_OK ){
break;
}
- p->pInfo->nCoord = pRtree->nDim*2;
+ p->pInfo->nCoord = pRtree->nDim2;
p->pInfo->anQueue = pCsr->anQueue;
p->pInfo->mxLevel = pRtree->iDepth + 1;
- }else{
+ }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
p->u.rValue = sqlite3_value_int64(argv[ii]);
#else
p->u.rValue = sqlite3_value_double(argv[ii]);
#endif
+ }else{
+ p->u.rValue = RTREE_ZERO;
+ if( eType==SQLITE_NULL ){
+ p->op = RTREE_FALSE;
+ }else if( p->op==RTREE_LT || p->op==RTREE_LE ){
+ p->op = RTREE_TRUE;
+ }else{
+ p->op = RTREE_FALSE;
+ }
}
}
}
}
if( rc==SQLITE_OK ){
RtreeSearchPoint *pNew;
- pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, pRtree->iDepth+1);
+ pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
if( pNew==0 ) return SQLITE_NOMEM;
pNew->id = 1;
pNew->iCell = 0;
@@ -162936,21 +189989,8 @@ static int rtreeFilter(
}
/*
-** Set the pIdxInfo->estimatedRows variable to nRow. Unless this
-** extension is currently being used by a version of SQLite too old to
-** support estimatedRows. In that case this function is a no-op.
-*/
-static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
-#if SQLITE_VERSION_NUMBER>=3008002
- if( sqlite3_libversion_number()>=3008002 ){
- pIdxInfo->estimatedRows = nRow;
- }
-#endif
-}
-
-/*
** Rtree virtual table module xBestIndex method. There are three
-** table scan strategies to choose from (in order from most to
+** table scan strategies to choose from (in order from most to
** least desirable):
**
** idxNum idxStr Strategy
@@ -162960,8 +190000,8 @@ static void setEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
** ------------------------------------------------
**
** If strategy 1 is used, then idxStr is not meaningful. If strategy
-** 2 is used, idxStr is formatted to contain 2 bytes for each
-** constraint used. The first two bytes of idxStr correspond to
+** 2 is used, idxStr is formatted to contain 2 bytes for each
+** constraint used. The first two bytes of idxStr correspond to
** the constraint in sqlite3_index_info.aConstraintUsage[] with
** (argvIndex==1) etc.
**
@@ -163007,8 +190047,8 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
- if( bMatch==0 && p->usable
- && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
+ if( bMatch==0 && p->usable
+ && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
){
/* We have an equality constraint on the rowid. Use strategy 1. */
int jj;
@@ -163021,33 +190061,37 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
pIdxInfo->aConstraintUsage[jj].omit = 1;
/* This strategy involves a two rowid lookups on an B-Tree structures
- ** and then a linear search of an R-Tree node. This should be
- ** considered almost as quick as a direct rowid lookup (for which
+ ** and then a linear search of an R-Tree node. This should be
+ ** considered almost as quick as a direct rowid lookup (for which
** sqlite uses an internal cost of 0.0). It is expected to return
** a single row.
- */
+ */
pIdxInfo->estimatedCost = 30.0;
- setEstimatedRows(pIdxInfo, 1);
+ pIdxInfo->estimatedRows = 1;
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
return SQLITE_OK;
}
- if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
+ if( p->usable
+ && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2)
+ || p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
+ ){
u8 op;
switch( p->op ){
- case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
- case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
- case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
- case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
- case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
- default:
- assert( p->op==SQLITE_INDEX_CONSTRAINT_MATCH );
- op = RTREE_MATCH;
- break;
+ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
+ case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
+ case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
+ case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break;
+ default: op = 0; break;
+ }
+ if( op ){
+ zIdxStr[iIdx++] = op;
+ zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
+ pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
+ pIdxInfo->aConstraintUsage[ii].omit = 1;
}
- zIdxStr[iIdx++] = op;
- zIdxStr[iIdx++] = p->iColumn - 1 + '0';
- pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
- pIdxInfo->aConstraintUsage[ii].omit = 1;
}
}
@@ -163059,7 +190103,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
nRow = pRtree->nRowEst >> (iIdx/2);
pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
- setEstimatedRows(pIdxInfo, nRow);
+ pIdxInfo->estimatedRows = nRow;
return rc;
}
@@ -163069,9 +190113,26 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
*/
static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
RtreeDValue area = (RtreeDValue)1;
- int ii;
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
- area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
+ assert( pRtree->nDim>=1 && pRtree->nDim<=5 );
+#ifndef SQLITE_RTREE_INT_ONLY
+ if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
+ switch( pRtree->nDim ){
+ case 5: area = p->aCoord[9].f - p->aCoord[8].f;
+ case 4: area *= p->aCoord[7].f - p->aCoord[6].f;
+ case 3: area *= p->aCoord[5].f - p->aCoord[4].f;
+ case 2: area *= p->aCoord[3].f - p->aCoord[2].f;
+ default: area *= p->aCoord[1].f - p->aCoord[0].f;
+ }
+ }else
+#endif
+ {
+ switch( pRtree->nDim ){
+ case 5: area = (i64)p->aCoord[9].i - (i64)p->aCoord[8].i;
+ case 4: area *= (i64)p->aCoord[7].i - (i64)p->aCoord[6].i;
+ case 3: area *= (i64)p->aCoord[5].i - (i64)p->aCoord[4].i;
+ case 2: area *= (i64)p->aCoord[3].i - (i64)p->aCoord[2].i;
+ default: area *= (i64)p->aCoord[1].i - (i64)p->aCoord[0].i;
+ }
}
return area;
}
@@ -163081,11 +190142,12 @@ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
** of the objects size in each dimension.
*/
static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
- RtreeDValue margin = (RtreeDValue)0;
- int ii;
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
+ RtreeDValue margin = 0;
+ int ii = pRtree->nDim2 - 2;
+ do{
margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
- }
+ ii -= 2;
+ }while( ii>=0 );
return margin;
}
@@ -163093,17 +190155,19 @@ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
** Store the union of cells p1 and p2 in p1.
*/
static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
- int ii;
+ int ii = 0;
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
+ do{
p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f);
p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f);
- }
+ ii += 2;
+ }while( ii<pRtree->nDim2 );
}else{
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
+ do{
p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i);
p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i);
- }
+ ii += 2;
+ }while( ii<pRtree->nDim2 );
}
}
@@ -163114,11 +190178,11 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
int ii;
int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
- for(ii=0; ii<(pRtree->nDim*2); ii+=2){
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
RtreeCoord *a1 = &p1->aCoord[ii];
RtreeCoord *a2 = &p2->aCoord[ii];
- if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
- || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
+ if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
+ || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
){
return 0;
}
@@ -163139,9 +190203,9 @@ static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
}
static RtreeDValue cellOverlap(
- Rtree *pRtree,
- RtreeCell *p,
- RtreeCell *aCell,
+ Rtree *pRtree,
+ RtreeCell *p,
+ RtreeCell *aCell,
int nCell
){
int ii;
@@ -163149,7 +190213,7 @@ static RtreeDValue cellOverlap(
for(ii=0; ii<nCell; ii++){
int jj;
RtreeDValue o = (RtreeDValue)1;
- for(jj=0; jj<(pRtree->nDim*2); jj+=2){
+ for(jj=0; jj<pRtree->nDim2; jj+=2){
RtreeDValue x1, x2;
x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
@@ -163178,7 +190242,7 @@ static int ChooseLeaf(
){
int rc;
int ii;
- RtreeNode *pNode;
+ RtreeNode *pNode = 0;
rc = nodeAcquire(pRtree, 1, 0, &pNode);
for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
@@ -163236,12 +190300,14 @@ static int AdjustTree(
RtreeCell *pCell /* This cell was just inserted */
){
RtreeNode *p = pNode;
+ int cnt = 0;
while( p->pParent ){
RtreeNode *pParent = p->pParent;
RtreeCell cell;
int iCell;
- if( nodeParentIndex(pRtree, p, &iCell) ){
+ if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){
+ RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@@ -163250,7 +190316,7 @@ static int AdjustTree(
cellUnion(pRtree, &cell, pCell);
nodeOverwriteCell(pRtree, pParent, &cell, iCell);
}
-
+
p = pParent;
}
return SQLITE_OK;
@@ -163281,7 +190347,7 @@ static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
/*
** Arguments aIdx, aDistance and aSpare all point to arrays of size
-** nIdx. The aIdx array contains the set of integers from 0 to
+** nIdx. The aIdx array contains the set of integers from 0 to
** (nIdx-1) in no particular order. This function sorts the values
** in aIdx according to the indexed values in aDistance. For
** example, assuming the inputs:
@@ -163297,9 +190363,9 @@ static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
** sorting algorithm.
*/
static void SortByDistance(
- int *aIdx,
- int nIdx,
- RtreeDValue *aDistance,
+ int *aIdx,
+ int nIdx,
+ RtreeDValue *aDistance,
int *aSpare
){
if( nIdx>1 ){
@@ -163353,7 +190419,7 @@ static void SortByDistance(
/*
** Arguments aIdx, aCell and aSpare all point to arrays of size
-** nIdx. The aIdx array contains the set of integers from 0 to
+** nIdx. The aIdx array contains the set of integers from 0 to
** (nIdx-1) in no particular order. This function sorts the values
** in aIdx according to dimension iDim of the cells in aCell. The
** minimum value of dimension iDim is considered first, the
@@ -163364,10 +190430,10 @@ static void SortByDistance(
*/
static void SortByDimension(
Rtree *pRtree,
- int *aIdx,
- int nIdx,
- int iDim,
- RtreeCell *aCell,
+ int *aIdx,
+ int nIdx,
+ int iDim,
+ RtreeCell *aCell,
int *aSpare
){
if( nIdx>1 ){
@@ -163438,9 +190504,9 @@ static int splitNodeStartree(
int iBestSplit = 0;
RtreeDValue fBestMargin = RTREE_ZERO;
- int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
+ sqlite3_int64 nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
- aaSorted = (int **)sqlite3_malloc(nByte);
+ aaSorted = (int **)sqlite3_malloc64(nByte);
if( !aaSorted ){
return SQLITE_NOMEM;
}
@@ -163464,8 +190530,8 @@ static int splitNodeStartree(
int nLeft;
for(
- nLeft=RTREE_MINCELLS(pRtree);
- nLeft<=(nCell-RTREE_MINCELLS(pRtree));
+ nLeft=RTREE_MINCELLS(pRtree);
+ nLeft<=(nCell-RTREE_MINCELLS(pRtree));
nLeft++
){
RtreeCell left;
@@ -163520,9 +190586,9 @@ static int splitNodeStartree(
static int updateMapping(
- Rtree *pRtree,
- i64 iRowid,
- RtreeNode *pNode,
+ Rtree *pRtree,
+ i64 iRowid,
+ RtreeNode *pNode,
int iHeight
){
int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64);
@@ -163558,10 +190624,10 @@ static int SplitNode(
RtreeCell leftbbox;
RtreeCell rightbbox;
- /* Allocate an array and populate it with a copy of pCell and
+ /* Allocate an array and populate it with a copy of pCell and
** all cells from node pLeft. Then zero the original node.
*/
- aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
+ aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
if( !aCell ){
rc = SQLITE_NOMEM;
goto splitnode_out;
@@ -163584,7 +190650,7 @@ static int SplitNode(
}else{
pLeft = pNode;
pRight = nodeNew(pRtree, pLeft->pParent);
- nodeReference(pLeft);
+ pLeft->nRef++;
}
if( !pLeft || !pRight ){
@@ -163675,14 +190741,14 @@ splitnode_out:
}
/*
-** If node pLeaf is not the root of the r-tree and its pParent pointer is
+** If node pLeaf is not the root of the r-tree and its pParent pointer is
** still NULL, load all ancestor nodes of pLeaf into memory and populate
** the pLeaf->pParent chain all the way up to the root node.
**
** This operation is required when a row is deleted (or updated - an update
** is implemented as a delete followed by an insert). SQLite provides the
** rowid of the row to delete, which can be used to find the leaf on which
-** the entry resides (argument pLeaf). Once the leaf is located, this
+** the entry resides (argument pLeaf). Once the leaf is located, this
** function is called to determine its ancestry.
*/
static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
@@ -163709,7 +190775,10 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
}
rc = sqlite3_reset(pRtree->pReadParent);
if( rc==SQLITE_OK ) rc = rc2;
- if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB;
+ if( rc==SQLITE_OK && !pChild->pParent ){
+ RTREE_IS_CORRUPT(pRtree);
+ rc = SQLITE_CORRUPT_VTAB;
+ }
pChild = pChild->pParent;
}
return rc;
@@ -163753,7 +190822,7 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteParent)) ){
return rc;
}
-
+
/* Remove the node from the in-memory hash table and link it into
** the Rtree.pDeleted list. Its contents will be re-inserted later on.
*/
@@ -163768,9 +190837,9 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
RtreeNode *pParent = pNode->pParent;
- int rc = SQLITE_OK;
+ int rc = SQLITE_OK;
if( pParent ){
- int ii;
+ int ii;
int nCell = NCELL(pNode);
RtreeCell box; /* Bounding box for pNode */
nodeGetCell(pRtree, pNode, 0, &box);
@@ -163825,9 +190894,9 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
}
static int Reinsert(
- Rtree *pRtree,
- RtreeNode *pNode,
- RtreeCell *pCell,
+ Rtree *pRtree,
+ RtreeNode *pNode,
+ RtreeCell *pCell,
int iHeight
){
int *aOrder;
@@ -163849,7 +190918,7 @@ static int Reinsert(
/* Allocate the buffers used by this operation. The allocation is
** relinquished before this function returns.
*/
- aCell = (RtreeCell *)sqlite3_malloc(n * (
+ aCell = (RtreeCell *)sqlite3_malloc64(n * (
sizeof(RtreeCell) + /* aCell array */
sizeof(int) + /* aOrder array */
sizeof(int) + /* aSpare array */
@@ -163881,7 +190950,7 @@ static int Reinsert(
for(ii=0; ii<nCell; ii++){
aDistance[ii] = RTREE_ZERO;
for(iDim=0; iDim<pRtree->nDim; iDim++){
- RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
+ RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
DCOORD(aCell[ii].aCoord[iDim*2]));
aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
}
@@ -163926,7 +190995,7 @@ static int Reinsert(
}
/*
-** Insert cell pCell into node pNode. Node pNode is the head of a
+** Insert cell pCell into node pNode. Node pNode is the head of a
** subtree iHeight high (leaf nodes have iHeight==0).
*/
static int rtreeInsertCell(
@@ -163993,7 +191062,7 @@ static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){
/*
** Select a currently unused rowid for a new r-tree record.
*/
-static int newRowid(Rtree *pRtree, i64 *piRowid){
+static int rtreeNewRowid(Rtree *pRtree, i64 *piRowid){
int rc;
sqlite3_bind_null(pRtree->pWriteRowid, 1);
sqlite3_bind_null(pRtree->pWriteRowid, 2);
@@ -164010,21 +191079,25 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
int rc; /* Return code */
RtreeNode *pLeaf = 0; /* Leaf node containing record iDelete */
int iCell; /* Index of iDelete cell in pLeaf */
- RtreeNode *pRoot; /* Root node of rtree structure */
+ RtreeNode *pRoot = 0; /* Root node of rtree structure */
/* Obtain a reference to the root node to initialize Rtree.iDepth */
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
- /* Obtain a reference to the leaf node that contains the entry
- ** about to be deleted.
+ /* Obtain a reference to the leaf node that contains the entry
+ ** about to be deleted.
*/
if( rc==SQLITE_OK ){
rc = findLeafNode(pRtree, iDelete, &pLeaf, 0);
}
+#ifdef CORRUPT_DB
+ assert( pLeaf!=0 || rc!=SQLITE_OK || CORRUPT_DB );
+#endif
+
/* Delete the cell in question from the leaf node. */
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && pLeaf ){
int rc2;
rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell);
if( rc==SQLITE_OK ){
@@ -164044,16 +191117,16 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
}
/* Check if the root node now has exactly one child. If so, remove
- ** it, schedule the contents of the child for reinsertion and
+ ** 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
+ ** 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;
+ RtreeNode *pChild = 0;
i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
if( rc==SQLITE_OK ){
@@ -164074,6 +191147,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
rc = reinsertNodeContent(pRtree, pLeaf);
}
pRtree->pDeleted = pLeaf->pNext;
+ pRtree->nNodeRef--;
sqlite3_free(pLeaf);
}
@@ -164117,8 +191191,8 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
#endif /* !defined(SQLITE_RTREE_INT_ONLY) */
/*
-** A constraint has failed while inserting a row into an rtree table.
-** Assuming no OOM error occurs, this function sets the error message
+** A constraint has failed while inserting a row into an rtree table.
+** Assuming no OOM error occurs, this function sets the error message
** (at pRtree->base.zErrMsg) to an appropriate value and returns
** SQLITE_CONSTRAINT.
**
@@ -164131,7 +191205,7 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
*/
static int rtreeConstraintError(Rtree *pRtree, int iCol){
sqlite3_stmt *pStmt = 0;
- char *zSql;
+ char *zSql;
int rc;
assert( iCol==0 || iCol%2 );
@@ -164168,9 +191242,9 @@ static int rtreeConstraintError(Rtree *pRtree, int iCol){
** The xUpdate method for rtree module virtual tables.
*/
static int rtreeUpdate(
- sqlite3_vtab *pVtab,
- int nData,
- sqlite3_value **azData,
+ sqlite3_vtab *pVtab,
+ int nData,
+ sqlite3_value **aData,
sqlite_int64 *pRowid
){
Rtree *pRtree = (Rtree *)pVtab;
@@ -164178,6 +191252,12 @@ static int rtreeUpdate(
RtreeCell cell; /* New cell to insert if nData>1 */
int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
+ if( pRtree->nNodeRef ){
+ /* Unable to write to the btree while another cursor is reading from it,
+ ** since the write might do a rebalance which would disrupt the read
+ ** cursor. */
+ return SQLITE_LOCKED_VTAB;
+ }
rtreeReference(pRtree);
assert(nData>=1);
@@ -164196,8 +191276,10 @@ static int rtreeUpdate(
*/
if( nData>1 ){
int ii;
+ int nn = nData - 4;
- /* Populate the cell.aCoord[] array. The first coordinate is azData[3].
+ if( nn > pRtree->nDim2 ) nn = pRtree->nDim2;
+ /* Populate the cell.aCoord[] array. The first coordinate is aData[3].
**
** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared
** with "column" that are interpreted as table constraints.
@@ -164205,13 +191287,12 @@ static int rtreeUpdate(
** This problem was discovered after years of use, so we silently ignore
** these kinds of misdeclared tables to avoid breaking any legacy.
*/
- assert( nData<=(pRtree->nDim*2 + 3) );
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
- for(ii=0; ii<nData-4; ii+=2){
- cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
- cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
+ for(ii=0; ii<nn; ii+=2){
+ cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
+ cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
@@ -164220,9 +191301,9 @@ static int rtreeUpdate(
}else
#endif
{
- for(ii=0; ii<nData-4; ii+=2){
- cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
- cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
+ for(ii=0; ii<nn; ii+=2){
+ cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
+ cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
@@ -164230,12 +191311,12 @@ static int rtreeUpdate(
}
}
- /* If a rowid value was supplied, check if it is already present in
+ /* 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]);
- if( sqlite3_value_type(azData[0])==SQLITE_NULL
- || sqlite3_value_int64(azData[0])!=cell.iRowid
+ if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){
+ cell.iRowid = sqlite3_value_int64(aData[2]);
+ if( sqlite3_value_type(aData[0])==SQLITE_NULL
+ || sqlite3_value_int64(aData[0])!=cell.iRowid
){
int steprc;
sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
@@ -164254,16 +191335,16 @@ static int rtreeUpdate(
}
}
- /* If azData[0] is not an SQL NULL value, it is the rowid of a
+ /* If aData[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( sqlite3_value_type(aData[0])!=SQLITE_NULL ){
+ rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
}
- /* If the azData[] array contains more than one element, elements
- ** (azData[2]..azData[argc-1]) contain a new record to insert into
+ /* If the aData[] array contains more than one element, elements
+ ** (aData[2]..aData[argc-1]) contain a new record to insert into
** the r-tree structure.
*/
if( rc==SQLITE_OK && nData>1 ){
@@ -164272,7 +191353,7 @@ static int rtreeUpdate(
/* Figure out the rowid of the new row. */
if( bHaveRowid==0 ){
- rc = newRowid(pRtree, &cell.iRowid);
+ rc = rtreeNewRowid(pRtree, &cell.iRowid);
}
*pRowid = cell.iRowid;
@@ -164288,6 +191369,16 @@ static int rtreeUpdate(
rc = rc2;
}
}
+ if( rc==SQLITE_OK && pRtree->nAux ){
+ sqlite3_stmt *pUp = pRtree->pWriteAux;
+ int jj;
+ sqlite3_bind_int64(pUp, 1, *pRowid);
+ for(jj=0; jj<pRtree->nAux; jj++){
+ sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
+ }
+ sqlite3_step(pUp);
+ rc = sqlite3_reset(pUp);
+ }
}
constraint:
@@ -164296,6 +191387,27 @@ constraint:
}
/*
+** Called when a transaction starts.
+*/
+static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
+ Rtree *pRtree = (Rtree *)pVtab;
+ assert( pRtree->inWrTrans==0 );
+ pRtree->inWrTrans++;
+ return SQLITE_OK;
+}
+
+/*
+** Called when a transaction completes (either by COMMIT or ROLLBACK).
+** The sqlite3_blob object should be released at this point.
+*/
+static int rtreeEndTransaction(sqlite3_vtab *pVtab){
+ Rtree *pRtree = (Rtree *)pVtab;
+ pRtree->inWrTrans = 0;
+ nodeBlobReset(pRtree);
+ return SQLITE_OK;
+}
+
+/*
** The xRename method for rtree module virtual tables.
*/
static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
@@ -164305,11 +191417,12 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
"ALTER TABLE %Q.'%q_node' RENAME TO \"%w_node\";"
"ALTER TABLE %Q.'%q_parent' RENAME TO \"%w_parent\";"
"ALTER TABLE %Q.'%q_rowid' RENAME TO \"%w_rowid\";"
- , pRtree->zDb, pRtree->zName, zNewName
- , pRtree->zDb, pRtree->zName, zNewName
+ , pRtree->zDb, pRtree->zName, zNewName
+ , pRtree->zDb, pRtree->zName, zNewName
, pRtree->zDb, pRtree->zName, zNewName
);
if( zSql ){
+ nodeBlobReset(pRtree);
rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
@@ -164317,6 +191430,30 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
}
/*
+** The xSavepoint method.
+**
+** This module does not need to do anything to support savepoints. However,
+** it uses this hook to close any open blob handle. This is done because a
+** DROP TABLE command - which fortunately always opens a savepoint - cannot
+** succeed if there are any open blob handles. i.e. if the blob handle were
+** not closed here, the following would fail:
+**
+** BEGIN;
+** INSERT INTO rtree...
+** DROP TABLE <tablename>; -- Would fail with SQLITE_LOCKED
+** COMMIT;
+*/
+static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
+ Rtree *pRtree = (Rtree *)pVtab;
+ u8 iwt = pRtree->inWrTrans;
+ UNUSED_PARAMETER(iSavepoint);
+ pRtree->inWrTrans = 0;
+ nodeBlobReset(pRtree);
+ pRtree->inWrTrans = iwt;
+ return SQLITE_OK;
+}
+
+/*
** This function populates the pRtree->nRowEst variable with an estimate
** of the number of rows in the virtual table. If possible, this is based
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
@@ -164360,8 +191497,24 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
return rc;
}
+
+/*
+** Return true if zName is the extension on one of the shadow tables used
+** by this module.
+*/
+static int rtreeShadowName(const char *zName){
+ static const char *azName[] = {
+ "node", "parent", "rowid"
+ };
+ unsigned int i;
+ for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
+ if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
+ }
+ return 0;
+}
+
static sqlite3_module rtreeModule = {
- 0, /* iVersion */
+ 3, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
@@ -164375,57 +191528,69 @@ static sqlite3_module rtreeModule = {
rtreeColumn, /* xColumn - read data */
rtreeRowid, /* xRowid - read data */
rtreeUpdate, /* xUpdate - write data */
- 0, /* xBegin - begin transaction */
- 0, /* xSync - sync transaction */
- 0, /* xCommit - commit transaction */
- 0, /* xRollback - rollback transaction */
+ rtreeBeginTransaction, /* xBegin - begin transaction */
+ rtreeEndTransaction, /* xSync - sync transaction */
+ rtreeEndTransaction, /* xCommit - commit transaction */
+ rtreeEndTransaction, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
rtreeRename, /* xRename - rename the table */
- 0, /* xSavepoint */
+ rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
- 0 /* xRollbackTo */
+ 0, /* xRollbackTo */
+ rtreeShadowName /* xShadowName */
};
static int rtreeSqlInit(
- Rtree *pRtree,
- sqlite3 *db,
- const char *zDb,
- const char *zPrefix,
+ Rtree *pRtree,
+ sqlite3 *db,
+ const char *zDb,
+ const char *zPrefix,
int isCreate
){
int rc = SQLITE_OK;
- #define N_STATEMENT 9
+ #define N_STATEMENT 8
static const char *azSql[N_STATEMENT] = {
- /* Read and write the xxx_node table */
- "SELECT data FROM '%q'.'%q_node' WHERE nodeno = :1",
- "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)",
- "DELETE FROM '%q'.'%q_node' WHERE nodeno = :1",
+ /* Write the xxx_node table */
+ "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(?1, ?2)",
+ "DELETE FROM '%q'.'%q_node' WHERE nodeno = ?1",
/* Read and write the xxx_rowid table */
- "SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = :1",
- "INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(:1, :2)",
- "DELETE FROM '%q'.'%q_rowid' WHERE rowid = :1",
+ "SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = ?1",
+ "INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(?1, ?2)",
+ "DELETE FROM '%q'.'%q_rowid' WHERE rowid = ?1",
/* Read and write the xxx_parent table */
- "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = :1",
- "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(:1, :2)",
- "DELETE FROM '%q'.'%q_parent' WHERE nodeno = :1"
+ "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = ?1",
+ "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(?1, ?2)",
+ "DELETE FROM '%q'.'%q_parent' WHERE nodeno = ?1"
};
sqlite3_stmt **appStmt[N_STATEMENT];
int i;
+ const int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
pRtree->db = db;
if( isCreate ){
- char *zCreate = sqlite3_mprintf(
-"CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);"
-"CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);"
-"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,"
- " parentnode INTEGER);"
-"INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))",
- zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize
- );
+ char *zCreate;
+ sqlite3_str *p = sqlite3_str_new(db);
+ int ii;
+ sqlite3_str_appendf(p,
+ "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno",
+ zDb, zPrefix);
+ for(ii=0; ii<pRtree->nAux; ii++){
+ sqlite3_str_appendf(p,",a%d",ii);
+ }
+ sqlite3_str_appendf(p,
+ ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);",
+ zDb, zPrefix);
+ sqlite3_str_appendf(p,
+ "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);",
+ zDb, zPrefix);
+ sqlite3_str_appendf(p,
+ "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))",
+ zDb, zPrefix, pRtree->iNodeSize);
+ zCreate = sqlite3_str_finish(p);
if( !zCreate ){
return SQLITE_NOMEM;
}
@@ -164436,26 +191601,64 @@ static int rtreeSqlInit(
}
}
- appStmt[0] = &pRtree->pReadNode;
- appStmt[1] = &pRtree->pWriteNode;
- appStmt[2] = &pRtree->pDeleteNode;
- appStmt[3] = &pRtree->pReadRowid;
- appStmt[4] = &pRtree->pWriteRowid;
- appStmt[5] = &pRtree->pDeleteRowid;
- appStmt[6] = &pRtree->pReadParent;
- appStmt[7] = &pRtree->pWriteParent;
- appStmt[8] = &pRtree->pDeleteParent;
+ appStmt[0] = &pRtree->pWriteNode;
+ appStmt[1] = &pRtree->pDeleteNode;
+ appStmt[2] = &pRtree->pReadRowid;
+ appStmt[3] = &pRtree->pWriteRowid;
+ appStmt[4] = &pRtree->pDeleteRowid;
+ appStmt[5] = &pRtree->pReadParent;
+ appStmt[6] = &pRtree->pWriteParent;
+ appStmt[7] = &pRtree->pDeleteParent;
rc = rtreeQueryStat1(db, pRtree);
for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){
- char *zSql = sqlite3_mprintf(azSql[i], zDb, zPrefix);
+ char *zSql;
+ const char *zFormat;
+ if( i!=3 || pRtree->nAux==0 ){
+ zFormat = azSql[i];
+ }else {
+ /* An UPSERT is very slightly slower than REPLACE, but it is needed
+ ** if there are auxiliary columns */
+ zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)"
+ "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno";
+ }
+ zSql = sqlite3_mprintf(zFormat, zDb, zPrefix);
if( zSql ){
- rc = sqlite3_prepare_v2(db, zSql, -1, appStmt[i], 0);
+ rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0);
}else{
rc = SQLITE_NOMEM;
}
sqlite3_free(zSql);
}
+ if( pRtree->nAux ){
+ pRtree->zReadAuxSql = sqlite3_mprintf(
+ "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
+ zDb, zPrefix);
+ if( pRtree->zReadAuxSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_str *p = sqlite3_str_new(db);
+ int ii;
+ char *zSql;
+ sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
+ for(ii=0; ii<pRtree->nAux; ii++){
+ if( ii ) sqlite3_str_append(p, ",", 1);
+ if( ii<pRtree->nAuxNotNull ){
+ sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
+ }else{
+ sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
+ }
+ }
+ sqlite3_str_appendf(p, " WHERE rowid=?1");
+ zSql = sqlite3_str_finish(p);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0);
+ sqlite3_free(zSql);
+ }
+ }
+ }
return rc;
}
@@ -164492,9 +191695,9 @@ static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
** table already exists. In this case the node-size is determined by inspecting
** the root node of the tree.
**
-** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
-** This ensures that each node is stored on a single database page. If the
-** database page-size is so large that more than RTREE_MAXCELLS entries
+** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
+** This ensures that each node is stored on a single database page. If the
+** database page-size is so large that more than RTREE_MAXCELLS entries
** would fit in a single node, use a smaller node-size.
*/
static int getNodeSize(
@@ -164525,6 +191728,11 @@ static int getNodeSize(
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }else if( pRtree->iNodeSize<(512-64) ){
+ rc = SQLITE_CORRUPT_VTAB;
+ RTREE_IS_CORRUPT(pRtree);
+ *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
+ pRtree->zName);
}
}
@@ -164532,7 +191740,15 @@ static int getNodeSize(
return rc;
}
-/*
+/*
+** Return the length of a token
+*/
+static int rtreeTokenLength(const char *z){
+ int dummy = 0;
+ return sqlite3GetToken((const unsigned char*)z,&dummy);
+}
+
+/*
** This function is the implementation of both the xConnect and xCreate
** methods of the r-tree virtual table.
**
@@ -164554,17 +191770,22 @@ static int rtreeInit(
int nDb; /* Length of string argv[1] */
int nName; /* Length of string argv[2] */
int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32);
+ sqlite3_str *pSql;
+ char *zSql;
+ int ii = 4;
+ int iErr;
const char *aErrMsg[] = {
0, /* 0 */
"Wrong number of columns for an rtree table", /* 1 */
"Too few columns for an rtree table", /* 2 */
- "Too many columns for an rtree table" /* 3 */
+ "Too many columns for an rtree table", /* 3 */
+ "Auxiliary rtree columns must be last" /* 4 */
};
- int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2;
- if( aErrMsg[iErr] ){
- *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
+ assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
+ if( argc<6 || argc>RTREE_MAX_AUX_COLUMN+3 ){
+ *pzErr = sqlite3_mprintf("%s", aErrMsg[2 + (argc>=6)]);
return SQLITE_ERROR;
}
@@ -164573,7 +191794,7 @@ static int rtreeInit(
/* Allocate the sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
- pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
if( !pRtree ){
return SQLITE_NOMEM;
}
@@ -164582,52 +191803,77 @@ static int rtreeInit(
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
- pRtree->nDim = (argc-4)/2;
- pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2;
- pRtree->eCoordType = eCoordType;
+ pRtree->eCoordType = (u8)eCoordType;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
- /* Figure out the node size to use. */
- rc = getNodeSize(db, pRtree, isCreate, pzErr);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the r-tree table schema.
*/
- if( rc==SQLITE_OK ){
- if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
- *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ pSql = sqlite3_str_new(db);
+ sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT",
+ rtreeTokenLength(argv[3]), argv[3]);
+ for(ii=4; ii<argc; ii++){
+ const char *zArg = argv[ii];
+ if( zArg[0]=='+' ){
+ pRtree->nAux++;
+ sqlite3_str_appendf(pSql, ",%.*s", rtreeTokenLength(zArg+1), zArg+1);
+ }else if( pRtree->nAux>0 ){
+ break;
}else{
- char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
- char *zTmp;
- int ii;
- for(ii=4; zSql && ii<argc; ii++){
- zTmp = zSql;
- zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
- sqlite3_free(zTmp);
- }
- if( zSql ){
- zTmp = zSql;
- zSql = sqlite3_mprintf("%s);", zTmp);
- sqlite3_free(zTmp);
- }
- if( !zSql ){
- rc = SQLITE_NOMEM;
- }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
- *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
- }
- sqlite3_free(zSql);
+ static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"};
+ pRtree->nDim2++;
+ sqlite3_str_appendf(pSql, azFormat[eCoordType],
+ rtreeTokenLength(zArg), zArg);
}
}
+ sqlite3_str_appendf(pSql, ");");
+ zSql = sqlite3_str_finish(pSql);
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else if( ii<argc ){
+ *pzErr = sqlite3_mprintf("%s", aErrMsg[4]);
+ rc = SQLITE_ERROR;
+ }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+ sqlite3_free(zSql);
+ if( rc ) goto rtreeInit_fail;
+ pRtree->nDim = pRtree->nDim2/2;
+ if( pRtree->nDim<1 ){
+ iErr = 2;
+ }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){
+ iErr = 3;
+ }else if( pRtree->nDim2 % 2 ){
+ iErr = 1;
+ }else{
+ iErr = 0;
+ }
+ if( iErr ){
+ *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
+ goto rtreeInit_fail;
+ }
+ pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
- if( rc==SQLITE_OK ){
- *ppVtab = (sqlite3_vtab *)pRtree;
- }else{
- assert( *ppVtab==0 );
- assert( pRtree->nBusy==1 );
- rtreeRelease(pRtree);
+ /* Figure out the node size to use. */
+ rc = getNodeSize(db, pRtree, isCreate, pzErr);
+ if( rc ) goto rtreeInit_fail;
+ rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
+ if( rc ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ goto rtreeInit_fail;
}
+
+ *ppVtab = (sqlite3_vtab *)pRtree;
+ return SQLITE_OK;
+
+rtreeInit_fail:
+ if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
+ assert( *ppVtab==0 );
+ assert( pRtree->nBusy==1 );
+ rtreeRelease(pRtree);
return rc;
}
@@ -164645,52 +191891,49 @@ static int rtreeInit(
**
** The human readable string takes the form of a Tcl list with one
** entry for each cell in the r-tree node. Each entry is itself a
-** list, containing the 8-byte rowid/pageno followed by the
+** list, containing the 8-byte rowid/pageno followed by the
** <num-dimension>*2 coordinates.
*/
static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
- char *zText = 0;
RtreeNode node;
Rtree tree;
int ii;
+ int nData;
+ int errCode;
+ sqlite3_str *pOut;
UNUSED_PARAMETER(nArg);
memset(&node, 0, sizeof(RtreeNode));
memset(&tree, 0, sizeof(Rtree));
- tree.nDim = sqlite3_value_int(apArg[0]);
+ tree.nDim = (u8)sqlite3_value_int(apArg[0]);
+ if( tree.nDim<1 || tree.nDim>5 ) return;
+ tree.nDim2 = tree.nDim*2;
tree.nBytesPerCell = 8 + 8 * tree.nDim;
node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
+ nData = sqlite3_value_bytes(apArg[1]);
+ if( nData<4 ) return;
+ if( nData<NCELL(&node)*tree.nBytesPerCell ) return;
+ pOut = sqlite3_str_new(0);
for(ii=0; ii<NCELL(&node); ii++){
- char zCell[512];
- int nCell = 0;
RtreeCell cell;
int jj;
nodeGetCell(&tree, &node, ii, &cell);
- sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
- nCell = (int)strlen(zCell);
- for(jj=0; jj<tree.nDim*2; jj++){
+ if( ii>0 ) sqlite3_str_append(pOut, " ", 1);
+ sqlite3_str_appendf(pOut, "{%lld", cell.iRowid);
+ for(jj=0; jj<tree.nDim2; jj++){
#ifndef SQLITE_RTREE_INT_ONLY
- sqlite3_snprintf(512-nCell,&zCell[nCell], " %g",
- (double)cell.aCoord[jj].f);
+ sqlite3_str_appendf(pOut, " %g", (double)cell.aCoord[jj].f);
#else
- sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
- cell.aCoord[jj].i);
+ sqlite3_str_appendf(pOut, " %d", cell.aCoord[jj].i);
#endif
- nCell = (int)strlen(zCell);
- }
-
- if( zText ){
- char *zTextNew = sqlite3_mprintf("%s {%s}", zText, zCell);
- sqlite3_free(zText);
- zText = zTextNew;
- }else{
- zText = sqlite3_mprintf("{%s}", zCell);
}
+ sqlite3_str_append(pOut, "}", 1);
}
-
- sqlite3_result_text(ctx, zText, -1, sqlite3_free);
+ errCode = sqlite3_str_errcode(pOut);
+ sqlite3_result_text(ctx, sqlite3_str_finish(pOut), -1, sqlite3_free);
+ sqlite3_result_error_code(ctx, errCode);
}
/* This routine implements an SQL function that returns the "depth" parameter
@@ -164704,10 +191947,10 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
*/
static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
UNUSED_PARAMETER(nArg);
- if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB
+ if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB
|| sqlite3_value_bytes(apArg[0])<2
){
- sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1);
+ sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1);
}else{
u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
sqlite3_result_int(ctx, readInt16(zBlob));
@@ -164715,8 +191958,2293 @@ static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
}
/*
+** Context object passed between the various routines that make up the
+** implementation of integrity-check function rtreecheck().
+*/
+typedef struct RtreeCheck RtreeCheck;
+struct RtreeCheck {
+ sqlite3 *db; /* Database handle */
+ const char *zDb; /* Database containing rtree table */
+ const char *zTab; /* Name of rtree table */
+ int bInt; /* True for rtree_i32 table */
+ int nDim; /* Number of dimensions for this rtree tbl */
+ sqlite3_stmt *pGetNode; /* Statement used to retrieve nodes */
+ sqlite3_stmt *aCheckMapping[2]; /* Statements to query %_parent/%_rowid */
+ int nLeaf; /* Number of leaf cells in table */
+ int nNonLeaf; /* Number of non-leaf cells in table */
+ int rc; /* Return code */
+ char *zReport; /* Message to report */
+ int nErr; /* Number of lines in zReport */
+};
+
+#define RTREE_CHECK_MAX_ERROR 100
+
+/*
+** Reset SQL statement pStmt. If the sqlite3_reset() call returns an error,
+** and RtreeCheck.rc==SQLITE_OK, set RtreeCheck.rc to the error code.
+*/
+static void rtreeCheckReset(RtreeCheck *pCheck, sqlite3_stmt *pStmt){
+ int rc = sqlite3_reset(pStmt);
+ if( pCheck->rc==SQLITE_OK ) pCheck->rc = rc;
+}
+
+/*
+** The second and subsequent arguments to this function are a format string
+** and printf style arguments. This function formats the string and attempts
+** to compile it as an SQL statement.
+**
+** If successful, a pointer to the new SQL statement is returned. Otherwise,
+** NULL is returned and an error code left in RtreeCheck.rc.
+*/
+static sqlite3_stmt *rtreeCheckPrepare(
+ RtreeCheck *pCheck, /* RtreeCheck object */
+ const char *zFmt, ... /* Format string and trailing args */
+){
+ va_list ap;
+ char *z;
+ sqlite3_stmt *pRet = 0;
+
+ va_start(ap, zFmt);
+ z = sqlite3_vmprintf(zFmt, ap);
+
+ if( pCheck->rc==SQLITE_OK ){
+ if( z==0 ){
+ pCheck->rc = SQLITE_NOMEM;
+ }else{
+ pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
+ }
+ }
+
+ sqlite3_free(z);
+ va_end(ap);
+ return pRet;
+}
+
+/*
+** The second and subsequent arguments to this function are a printf()
+** style format string and arguments. This function formats the string and
+** appends it to the report being accumuated in pCheck.
+*/
+static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
+ va_list ap;
+ va_start(ap, zFmt);
+ if( pCheck->rc==SQLITE_OK && pCheck->nErr<RTREE_CHECK_MAX_ERROR ){
+ char *z = sqlite3_vmprintf(zFmt, ap);
+ if( z==0 ){
+ pCheck->rc = SQLITE_NOMEM;
+ }else{
+ pCheck->zReport = sqlite3_mprintf("%z%s%z",
+ pCheck->zReport, (pCheck->zReport ? "\n" : ""), z
+ );
+ if( pCheck->zReport==0 ){
+ pCheck->rc = SQLITE_NOMEM;
+ }
+ }
+ pCheck->nErr++;
+ }
+ va_end(ap);
+}
+
+/*
+** This function is a no-op if there is already an error code stored
+** in the RtreeCheck object indicated by the first argument. NULL is
+** returned in this case.
+**
+** Otherwise, the contents of rtree table node iNode are loaded from
+** the database and copied into a buffer obtained from sqlite3_malloc().
+** If no error occurs, a pointer to the buffer is returned and (*pnNode)
+** is set to the size of the buffer in bytes.
+**
+** Or, if an error does occur, NULL is returned and an error code left
+** in the RtreeCheck object. The final value of *pnNode is undefined in
+** this case.
+*/
+static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
+ u8 *pRet = 0; /* Return value */
+
+ if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){
+ pCheck->pGetNode = rtreeCheckPrepare(pCheck,
+ "SELECT data FROM %Q.'%q_node' WHERE nodeno=?",
+ pCheck->zDb, pCheck->zTab
+ );
+ }
+
+ if( pCheck->rc==SQLITE_OK ){
+ sqlite3_bind_int64(pCheck->pGetNode, 1, iNode);
+ if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
+ int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
+ const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
+ pRet = sqlite3_malloc64(nNode);
+ if( pRet==0 ){
+ pCheck->rc = SQLITE_NOMEM;
+ }else{
+ memcpy(pRet, pNode, nNode);
+ *pnNode = nNode;
+ }
+ }
+ rtreeCheckReset(pCheck, pCheck->pGetNode);
+ if( pCheck->rc==SQLITE_OK && pRet==0 ){
+ rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode);
+ }
+ }
+
+ return pRet;
+}
+
+/*
+** This function is used to check that the %_parent (if bLeaf==0) or %_rowid
+** (if bLeaf==1) table contains a specified entry. The schemas of the
+** two tables are:
+**
+** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
+** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...)
+**
+** In both cases, this function checks that there exists an entry with
+** IPK value iKey and the second column set to iVal.
+**
+*/
+static void rtreeCheckMapping(
+ RtreeCheck *pCheck, /* RtreeCheck object */
+ int bLeaf, /* True for a leaf cell, false for interior */
+ i64 iKey, /* Key for mapping */
+ i64 iVal /* Expected value for mapping */
+){
+ int rc;
+ sqlite3_stmt *pStmt;
+ const char *azSql[2] = {
+ "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1",
+ "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1"
+ };
+
+ assert( bLeaf==0 || bLeaf==1 );
+ if( pCheck->aCheckMapping[bLeaf]==0 ){
+ pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck,
+ azSql[bLeaf], pCheck->zDb, pCheck->zTab
+ );
+ }
+ if( pCheck->rc!=SQLITE_OK ) return;
+
+ pStmt = pCheck->aCheckMapping[bLeaf];
+ sqlite3_bind_int64(pStmt, 1, iKey);
+ rc = sqlite3_step(pStmt);
+ if( rc==SQLITE_DONE ){
+ rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table",
+ iKey, iVal, (bLeaf ? "%_rowid" : "%_parent")
+ );
+ }else if( rc==SQLITE_ROW ){
+ i64 ii = sqlite3_column_int64(pStmt, 0);
+ if( ii!=iVal ){
+ rtreeCheckAppendMsg(pCheck,
+ "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
+ iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
+ );
+ }
+ }
+ rtreeCheckReset(pCheck, pStmt);
+}
+
+/*
+** Argument pCell points to an array of coordinates stored on an rtree page.
+** This function checks that the coordinates are internally consistent (no
+** x1>x2 conditions) and adds an error message to the RtreeCheck object
+** if they are not.
+**
+** Additionally, if pParent is not NULL, then it is assumed to point to
+** the array of coordinates on the parent page that bound the page
+** containing pCell. In this case it is also verified that the two
+** sets of coordinates are mutually consistent and an error message added
+** to the RtreeCheck object if they are not.
+*/
+static void rtreeCheckCellCoord(
+ RtreeCheck *pCheck,
+ i64 iNode, /* Node id to use in error messages */
+ int iCell, /* Cell number to use in error messages */
+ u8 *pCell, /* Pointer to cell coordinates */
+ u8 *pParent /* Pointer to parent coordinates */
+){
+ RtreeCoord c1, c2;
+ RtreeCoord p1, p2;
+ int i;
+
+ for(i=0; i<pCheck->nDim; i++){
+ readCoord(&pCell[4*2*i], &c1);
+ readCoord(&pCell[4*(2*i + 1)], &c2);
+
+ /* printf("%e, %e\n", c1.u.f, c2.u.f); */
+ if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){
+ rtreeCheckAppendMsg(pCheck,
+ "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode
+ );
+ }
+
+ if( pParent ){
+ readCoord(&pParent[4*2*i], &p1);
+ readCoord(&pParent[4*(2*i + 1)], &p2);
+
+ if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f)
+ || (pCheck->bInt ? c2.i>p2.i : c2.f>p2.f)
+ ){
+ rtreeCheckAppendMsg(pCheck,
+ "Dimension %d of cell %d on node %lld is corrupt relative to parent"
+ , i, iCell, iNode
+ );
+ }
+ }
+ }
+}
+
+/*
+** Run rtreecheck() checks on node iNode, which is at depth iDepth within
+** the r-tree structure. Argument aParent points to the array of coordinates
+** that bound node iNode on the parent node.
+**
+** If any problems are discovered, an error message is appended to the
+** report accumulated in the RtreeCheck object.
+*/
+static void rtreeCheckNode(
+ RtreeCheck *pCheck,
+ int iDepth, /* Depth of iNode (0==leaf) */
+ u8 *aParent, /* Buffer containing parent coords */
+ i64 iNode /* Node to check */
+){
+ u8 *aNode = 0;
+ int nNode = 0;
+
+ assert( iNode==1 || aParent!=0 );
+ assert( pCheck->nDim>0 );
+
+ aNode = rtreeCheckGetNode(pCheck, iNode, &nNode);
+ if( aNode ){
+ if( nNode<4 ){
+ rtreeCheckAppendMsg(pCheck,
+ "Node %lld is too small (%d bytes)", iNode, nNode
+ );
+ }else{
+ int nCell; /* Number of cells on page */
+ int i; /* Used to iterate through cells */
+ if( aParent==0 ){
+ iDepth = readInt16(aNode);
+ if( iDepth>RTREE_MAX_DEPTH ){
+ rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth);
+ sqlite3_free(aNode);
+ return;
+ }
+ }
+ nCell = readInt16(&aNode[2]);
+ if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){
+ rtreeCheckAppendMsg(pCheck,
+ "Node %lld is too small for cell count of %d (%d bytes)",
+ iNode, nCell, nNode
+ );
+ }else{
+ for(i=0; i<nCell; i++){
+ u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
+ i64 iVal = readInt64(pCell);
+ rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
+
+ if( iDepth>0 ){
+ rtreeCheckMapping(pCheck, 0, iVal, iNode);
+ rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
+ pCheck->nNonLeaf++;
+ }else{
+ rtreeCheckMapping(pCheck, 1, iVal, iNode);
+ pCheck->nLeaf++;
+ }
+ }
+ }
+ }
+ sqlite3_free(aNode);
+ }
+}
+
+/*
+** The second argument to this function must be either "_rowid" or
+** "_parent". This function checks that the number of entries in the
+** %_rowid or %_parent table is exactly nExpect. If not, it adds
+** an error message to the report in the RtreeCheck object indicated
+** by the first argument.
+*/
+static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
+ if( pCheck->rc==SQLITE_OK ){
+ sqlite3_stmt *pCount;
+ pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
+ pCheck->zDb, pCheck->zTab, zTbl
+ );
+ if( pCount ){
+ if( sqlite3_step(pCount)==SQLITE_ROW ){
+ i64 nActual = sqlite3_column_int64(pCount, 0);
+ if( nActual!=nExpect ){
+ rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
+ " - expected %lld, actual %lld" , zTbl, nExpect, nActual
+ );
+ }
+ }
+ pCheck->rc = sqlite3_finalize(pCount);
+ }
+ }
+}
+
+/*
+** This function does the bulk of the work for the rtree integrity-check.
+** It is called by rtreecheck(), which is the SQL function implementation.
+*/
+static int rtreeCheckTable(
+ sqlite3 *db, /* Database handle to access db through */
+ const char *zDb, /* Name of db ("main", "temp" etc.) */
+ const char *zTab, /* Name of rtree table to check */
+ char **pzReport /* OUT: sqlite3_malloc'd report text */
+){
+ RtreeCheck check; /* Common context for various routines */
+ sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */
+ int bEnd = 0; /* True if transaction should be closed */
+ int nAux = 0; /* Number of extra columns. */
+
+ /* Initialize the context object */
+ memset(&check, 0, sizeof(check));
+ check.db = db;
+ check.zDb = zDb;
+ check.zTab = zTab;
+
+ /* If there is not already an open transaction, open one now. This is
+ ** to ensure that the queries run as part of this integrity-check operate
+ ** on a consistent snapshot. */
+ if( sqlite3_get_autocommit(db) ){
+ check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
+ bEnd = 1;
+ }
+
+ /* Find the number of auxiliary columns */
+ if( check.rc==SQLITE_OK ){
+ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
+ if( pStmt ){
+ nAux = sqlite3_column_count(pStmt) - 2;
+ sqlite3_finalize(pStmt);
+ }
+ check.rc = SQLITE_OK;
+ }
+
+ /* Find number of dimensions in the rtree table. */
+ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
+ if( pStmt ){
+ int rc;
+ check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;
+ if( check.nDim<1 ){
+ rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree");
+ }else if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER);
+ }
+ rc = sqlite3_finalize(pStmt);
+ if( rc!=SQLITE_CORRUPT ) check.rc = rc;
+ }
+
+ /* Do the actual integrity-check */
+ if( check.nDim>=1 ){
+ if( check.rc==SQLITE_OK ){
+ rtreeCheckNode(&check, 0, 0, 1);
+ }
+ rtreeCheckCount(&check, "_rowid", check.nLeaf);
+ rtreeCheckCount(&check, "_parent", check.nNonLeaf);
+ }
+
+ /* Finalize SQL statements used by the integrity-check */
+ sqlite3_finalize(check.pGetNode);
+ sqlite3_finalize(check.aCheckMapping[0]);
+ sqlite3_finalize(check.aCheckMapping[1]);
+
+ /* If one was opened, close the transaction */
+ if( bEnd ){
+ int rc = sqlite3_exec(db, "END", 0, 0, 0);
+ if( check.rc==SQLITE_OK ) check.rc = rc;
+ }
+ *pzReport = check.zReport;
+ return check.rc;
+}
+
+/*
+** Usage:
+**
+** rtreecheck(<rtree-table>);
+** rtreecheck(<database>, <rtree-table>);
+**
+** Invoking this SQL function runs an integrity-check on the named rtree
+** table. The integrity-check verifies the following:
+**
+** 1. For each cell in the r-tree structure (%_node table), that:
+**
+** a) for each dimension, (coord1 <= coord2).
+**
+** b) unless the cell is on the root node, that the cell is bounded
+** by the parent cell on the parent node.
+**
+** c) for leaf nodes, that there is an entry in the %_rowid
+** table corresponding to the cell's rowid value that
+** points to the correct node.
+**
+** d) for cells on non-leaf nodes, that there is an entry in the
+** %_parent table mapping from the cell's child node to the
+** node that it resides on.
+**
+** 2. That there are the same number of entries in the %_rowid table
+** as there are leaf cells in the r-tree structure, and that there
+** is a leaf cell that corresponds to each entry in the %_rowid table.
+**
+** 3. That there are the same number of entries in the %_parent table
+** as there are non-leaf cells in the r-tree structure, and that
+** there is a non-leaf cell that corresponds to each entry in the
+** %_parent table.
+*/
+static void rtreecheck(
+ sqlite3_context *ctx,
+ int nArg,
+ sqlite3_value **apArg
+){
+ if( nArg!=1 && nArg!=2 ){
+ sqlite3_result_error(ctx,
+ "wrong number of arguments to function rtreecheck()", -1
+ );
+ }else{
+ int rc;
+ char *zReport = 0;
+ const char *zDb = (const char*)sqlite3_value_text(apArg[0]);
+ const char *zTab;
+ if( nArg==1 ){
+ zTab = zDb;
+ zDb = "main";
+ }else{
+ zTab = (const char*)sqlite3_value_text(apArg[1]);
+ }
+ rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_error_code(ctx, rc);
+ }
+ sqlite3_free(zReport);
+ }
+}
+
+/* Conditionally include the geopoly code */
+#ifdef SQLITE_ENABLE_GEOPOLY
+/************** Include geopoly.c in the middle of rtree.c *******************/
+/************** Begin file geopoly.c *****************************************/
+/*
+** 2018-05-25
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file implements an alternative R-Tree virtual table that
+** uses polygons to express the boundaries of 2-dimensional objects.
+**
+** This file is #include-ed onto the end of "rtree.c" so that it has
+** access to all of the R-Tree internals.
+*/
+/* #include <stdlib.h> */
+
+/* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */
+#ifdef GEOPOLY_ENABLE_DEBUG
+ static int geo_debug = 0;
+# define GEODEBUG(X) if(geo_debug)printf X
+#else
+# define GEODEBUG(X)
+#endif
+
+#ifndef JSON_NULL /* The following stuff repeats things found in json1 */
+/*
+** Versions of isspace(), isalnum() and isdigit() to which it is safe
+** to pass signed char values.
+*/
+#ifdef sqlite3Isdigit
+ /* Use the SQLite core versions if this routine is part of the
+ ** SQLite amalgamation */
+# define safe_isdigit(x) sqlite3Isdigit(x)
+# define safe_isalnum(x) sqlite3Isalnum(x)
+# define safe_isxdigit(x) sqlite3Isxdigit(x)
+#else
+ /* Use the standard library for separate compilation */
+#include <ctype.h> /* amalgamator: keep */
+# define safe_isdigit(x) isdigit((unsigned char)(x))
+# define safe_isalnum(x) isalnum((unsigned char)(x))
+# define safe_isxdigit(x) isxdigit((unsigned char)(x))
+#endif
+
+/*
+** Growing our own isspace() routine this way is twice as fast as
+** the library isspace() function.
+*/
+static const char geopolyIsSpace[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define safe_isspace(x) (geopolyIsSpace[(unsigned char)x])
+#endif /* JSON NULL - back to original code */
+
+/* Compiler and version */
+#ifndef GCC_VERSION
+#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
+# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
+#else
+# define GCC_VERSION 0
+#endif
+#endif
+#ifndef MSVC_VERSION
+#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
+# define MSVC_VERSION _MSC_VER
+#else
+# define MSVC_VERSION 0
+#endif
+#endif
+
+/* Datatype for coordinates
+*/
+typedef float GeoCoord;
+
+/*
+** Internal representation of a polygon.
+**
+** The polygon consists of a sequence of vertexes. There is a line
+** segment between each pair of vertexes, and one final segment from
+** the last vertex back to the first. (This differs from the GeoJSON
+** standard in which the final vertex is a repeat of the first.)
+**
+** The polygon follows the right-hand rule. The area to the right of
+** each segment is "outside" and the area to the left is "inside".
+**
+** The on-disk representation consists of a 4-byte header followed by
+** the values. The 4-byte header is:
+**
+** encoding (1 byte) 0=big-endian, 1=little-endian
+** nvertex (3 bytes) Number of vertexes as a big-endian integer
+**
+** Enough space is allocated for 4 coordinates, to work around over-zealous
+** warnings coming from some compiler (notably, clang). In reality, the size
+** of each GeoPoly memory allocate is adjusted as necessary so that the
+** GeoPoly.a[] array at the end is the appropriate size.
+*/
+typedef struct GeoPoly GeoPoly;
+struct GeoPoly {
+ int nVertex; /* Number of vertexes */
+ unsigned char hdr[4]; /* Header for on-disk representation */
+ GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */
+};
+
+/* The size of a memory allocation needed for a GeoPoly object sufficient
+** to hold N coordinate pairs.
+*/
+#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4))
+
+/* Macros to access coordinates of a GeoPoly.
+** We have to use these macros, rather than just say p->a[i] in order
+** to silence (incorrect) UBSAN warnings if the array index is too large.
+*/
+#define GeoX(P,I) (((GeoCoord*)(P)->a)[(I)*2])
+#define GeoY(P,I) (((GeoCoord*)(P)->a)[(I)*2+1])
+
+
+/*
+** State of a parse of a GeoJSON input.
+*/
+typedef struct GeoParse GeoParse;
+struct GeoParse {
+ const unsigned char *z; /* Unparsed input */
+ int nVertex; /* Number of vertexes in a[] */
+ int nAlloc; /* Space allocated to a[] */
+ int nErr; /* Number of errors encountered */
+ GeoCoord *a; /* Array of vertexes. From sqlite3_malloc64() */
+};
+
+/* Do a 4-byte byte swap */
+static void geopolySwab32(unsigned char *a){
+ unsigned char t = a[0];
+ a[0] = a[3];
+ a[3] = t;
+ t = a[1];
+ a[1] = a[2];
+ a[2] = t;
+}
+
+/* Skip whitespace. Return the next non-whitespace character. */
+static char geopolySkipSpace(GeoParse *p){
+ while( safe_isspace(p->z[0]) ) p->z++;
+ return p->z[0];
+}
+
+/* Parse out a number. Write the value into *pVal if pVal!=0.
+** return non-zero on success and zero if the next token is not a number.
+*/
+static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
+ char c = geopolySkipSpace(p);
+ const unsigned char *z = p->z;
+ int j = 0;
+ int seenDP = 0;
+ int seenE = 0;
+ if( c=='-' ){
+ j = 1;
+ c = z[j];
+ }
+ if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
+ for(;; j++){
+ c = z[j];
+ if( safe_isdigit(c) ) continue;
+ if( c=='.' ){
+ if( z[j-1]=='-' ) return 0;
+ if( seenDP ) return 0;
+ seenDP = 1;
+ continue;
+ }
+ if( c=='e' || c=='E' ){
+ if( z[j-1]<'0' ) return 0;
+ if( seenE ) return -1;
+ seenDP = seenE = 1;
+ c = z[j+1];
+ if( c=='+' || c=='-' ){
+ j++;
+ c = z[j+1];
+ }
+ if( c<'0' || c>'9' ) return 0;
+ continue;
+ }
+ break;
+ }
+ if( z[j-1]<'0' ) return 0;
+ if( pVal ){
+#ifdef SQLITE_AMALGAMATION
+ /* The sqlite3AtoF() routine is much much faster than atof(), if it
+ ** is available */
+ double r;
+ (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8);
+ *pVal = r;
+#else
+ *pVal = (GeoCoord)atof((const char*)p->z);
+#endif
+ }
+ p->z += j;
+ return 1;
+}
+
+/*
+** If the input is a well-formed JSON array of coordinates with at least
+** four coordinates and where each coordinate is itself a two-value array,
+** then convert the JSON into a GeoPoly object and return a pointer to
+** that object.
+**
+** If any error occurs, return NULL.
+*/
+static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
+ GeoParse s;
+ int rc = SQLITE_OK;
+ memset(&s, 0, sizeof(s));
+ s.z = z;
+ if( geopolySkipSpace(&s)=='[' ){
+ s.z++;
+ while( geopolySkipSpace(&s)=='[' ){
+ int ii = 0;
+ char c;
+ s.z++;
+ if( s.nVertex>=s.nAlloc ){
+ GeoCoord *aNew;
+ s.nAlloc = s.nAlloc*2 + 16;
+ aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 );
+ if( aNew==0 ){
+ rc = SQLITE_NOMEM;
+ s.nErr++;
+ break;
+ }
+ s.a = aNew;
+ }
+ while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){
+ ii++;
+ if( ii==2 ) s.nVertex++;
+ c = geopolySkipSpace(&s);
+ s.z++;
+ if( c==',' ) continue;
+ if( c==']' && ii>=2 ) break;
+ s.nErr++;
+ rc = SQLITE_ERROR;
+ goto parse_json_err;
+ }
+ if( geopolySkipSpace(&s)==',' ){
+ s.z++;
+ continue;
+ }
+ break;
+ }
+ if( geopolySkipSpace(&s)==']'
+ && s.nVertex>=4
+ && s.a[0]==s.a[s.nVertex*2-2]
+ && s.a[1]==s.a[s.nVertex*2-1]
+ && (s.z++, geopolySkipSpace(&s)==0)
+ ){
+ GeoPoly *pOut;
+ int x = 1;
+ s.nVertex--; /* Remove the redundant vertex at the end */
+ pOut = sqlite3_malloc64( GEOPOLY_SZ((sqlite3_int64)s.nVertex) );
+ x = 1;
+ if( pOut==0 ) goto parse_json_err;
+ pOut->nVertex = s.nVertex;
+ memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord));
+ pOut->hdr[0] = *(unsigned char*)&x;
+ pOut->hdr[1] = (s.nVertex>>16)&0xff;
+ pOut->hdr[2] = (s.nVertex>>8)&0xff;
+ pOut->hdr[3] = s.nVertex&0xff;
+ sqlite3_free(s.a);
+ if( pRc ) *pRc = SQLITE_OK;
+ return pOut;
+ }else{
+ s.nErr++;
+ rc = SQLITE_ERROR;
+ }
+ }
+parse_json_err:
+ if( pRc ) *pRc = rc;
+ sqlite3_free(s.a);
+ return 0;
+}
+
+/*
+** Given a function parameter, try to interpret it as a polygon, either
+** in the binary format or JSON text. Compute a GeoPoly object and
+** return a pointer to that object. Or if the input is not a well-formed
+** polygon, put an error message in sqlite3_context and return NULL.
+*/
+static GeoPoly *geopolyFuncParam(
+ sqlite3_context *pCtx, /* Context for error messages */
+ sqlite3_value *pVal, /* The value to decode */
+ int *pRc /* Write error here */
+){
+ GeoPoly *p = 0;
+ int nByte;
+ if( sqlite3_value_type(pVal)==SQLITE_BLOB
+ && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
+ ){
+ const unsigned char *a = sqlite3_value_blob(pVal);
+ int nVertex;
+ nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
+ if( (a[0]==0 || a[0]==1)
+ && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
+ ){
+ p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
+ if( p==0 ){
+ if( pRc ) *pRc = SQLITE_NOMEM;
+ if( pCtx ) sqlite3_result_error_nomem(pCtx);
+ }else{
+ int x = 1;
+ p->nVertex = nVertex;
+ memcpy(p->hdr, a, nByte);
+ if( a[0] != *(unsigned char*)&x ){
+ int ii;
+ for(ii=0; ii<nVertex; ii++){
+ geopolySwab32((unsigned char*)&GeoX(p,ii));
+ geopolySwab32((unsigned char*)&GeoY(p,ii));
+ }
+ p->hdr[0] ^= 1;
+ }
+ }
+ }
+ if( pRc ) *pRc = SQLITE_OK;
+ return p;
+ }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
+ const unsigned char *zJson = sqlite3_value_text(pVal);
+ if( zJson==0 ){
+ if( pRc ) *pRc = SQLITE_NOMEM;
+ return 0;
+ }
+ return geopolyParseJson(zJson, pRc);
+ }else{
+ if( pRc ) *pRc = SQLITE_ERROR;
+ return 0;
+ }
+}
+
+/*
+** Implementation of the geopoly_blob(X) function.
+**
+** If the input is a well-formed Geopoly BLOB or JSON string
+** then return the BLOB representation of the polygon. Otherwise
+** return NULL.
+*/
+static void geopolyBlobFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ if( p ){
+ sqlite3_result_blob(context, p->hdr,
+ 4+8*p->nVertex, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** SQL function: geopoly_json(X)
+**
+** Interpret X as a polygon and render it as a JSON array
+** of coordinates. Or, if X is not a valid polygon, return NULL.
+*/
+static void geopolyJsonFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ if( p ){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ sqlite3_str *x = sqlite3_str_new(db);
+ int i;
+ sqlite3_str_append(x, "[", 1);
+ for(i=0; i<p->nVertex; i++){
+ sqlite3_str_appendf(x, "[%!g,%!g],", GeoX(p,i), GeoY(p,i));
+ }
+ sqlite3_str_appendf(x, "[%!g,%!g]]", GeoX(p,0), GeoY(p,0));
+ sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** SQL function: geopoly_svg(X, ....)
+**
+** Interpret X as a polygon and render it as a SVG <polyline>.
+** Additional arguments are added as attributes to the <polyline>.
+*/
+static void geopolySvgFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p;
+ if( argc<1 ) return;
+ p = geopolyFuncParam(context, argv[0], 0);
+ if( p ){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ sqlite3_str *x = sqlite3_str_new(db);
+ int i;
+ char cSep = '\'';
+ sqlite3_str_appendf(x, "<polyline points=");
+ for(i=0; i<p->nVertex; i++){
+ sqlite3_str_appendf(x, "%c%g,%g", cSep, GeoX(p,i), GeoY(p,i));
+ cSep = ' ';
+ }
+ sqlite3_str_appendf(x, " %g,%g'", GeoX(p,0), GeoY(p,0));
+ for(i=1; i<argc; i++){
+ const char *z = (const char*)sqlite3_value_text(argv[i]);
+ if( z && z[0] ){
+ sqlite3_str_appendf(x, " %s", z);
+ }
+ }
+ sqlite3_str_appendf(x, "></polyline>");
+ sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** SQL Function: geopoly_xform(poly, A, B, C, D, E, F)
+**
+** Transform and/or translate a polygon as follows:
+**
+** x1 = A*x0 + B*y0 + E
+** y1 = C*x0 + D*y0 + F
+**
+** For a translation:
+**
+** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset)
+**
+** Rotate by R around the point (0,0):
+**
+** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0)
+*/
+static void geopolyXformFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ double A = sqlite3_value_double(argv[1]);
+ double B = sqlite3_value_double(argv[2]);
+ double C = sqlite3_value_double(argv[3]);
+ double D = sqlite3_value_double(argv[4]);
+ double E = sqlite3_value_double(argv[5]);
+ double F = sqlite3_value_double(argv[6]);
+ GeoCoord x1, y1, x0, y0;
+ int ii;
+ if( p ){
+ for(ii=0; ii<p->nVertex; ii++){
+ x0 = GeoX(p,ii);
+ y0 = GeoY(p,ii);
+ x1 = (GeoCoord)(A*x0 + B*y0 + E);
+ y1 = (GeoCoord)(C*x0 + D*y0 + F);
+ GeoX(p,ii) = x1;
+ GeoY(p,ii) = y1;
+ }
+ sqlite3_result_blob(context, p->hdr,
+ 4+8*p->nVertex, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Compute the area enclosed by the polygon.
+**
+** This routine can also be used to detect polygons that rotate in
+** the wrong direction. Polygons are suppose to be counter-clockwise (CCW).
+** This routine returns a negative value for clockwise (CW) polygons.
+*/
+static double geopolyArea(GeoPoly *p){
+ double rArea = 0.0;
+ int ii;
+ for(ii=0; ii<p->nVertex-1; ii++){
+ rArea += (GeoX(p,ii) - GeoX(p,ii+1)) /* (x0 - x1) */
+ * (GeoY(p,ii) + GeoY(p,ii+1)) /* (y0 + y1) */
+ * 0.5;
+ }
+ rArea += (GeoX(p,ii) - GeoX(p,0)) /* (xN - x0) */
+ * (GeoY(p,ii) + GeoY(p,0)) /* (yN + y0) */
+ * 0.5;
+ return rArea;
+}
+
+/*
+** Implementation of the geopoly_area(X) function.
+**
+** If the input is a well-formed Geopoly BLOB then return the area
+** enclosed by the polygon. If the polygon circulates clockwise instead
+** of counterclockwise (as it should) then return the negative of the
+** enclosed area. Otherwise return NULL.
+*/
+static void geopolyAreaFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ if( p ){
+ sqlite3_result_double(context, geopolyArea(p));
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Implementation of the geopoly_ccw(X) function.
+**
+** If the rotation of polygon X is clockwise (incorrect) instead of
+** counter-clockwise (the correct winding order according to RFC7946)
+** then reverse the order of the vertexes in polygon X.
+**
+** In other words, this routine returns a CCW polygon regardless of the
+** winding order of its input.
+**
+** Use this routine to sanitize historical inputs that that sometimes
+** contain polygons that wind in the wrong direction.
+*/
+static void geopolyCcwFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ if( p ){
+ if( geopolyArea(p)<0.0 ){
+ int ii, jj;
+ for(ii=1, jj=p->nVertex-1; ii<jj; ii++, jj--){
+ GeoCoord t = GeoX(p,ii);
+ GeoX(p,ii) = GeoX(p,jj);
+ GeoX(p,jj) = t;
+ t = GeoY(p,ii);
+ GeoY(p,ii) = GeoY(p,jj);
+ GeoY(p,jj) = t;
+ }
+ }
+ sqlite3_result_blob(context, p->hdr,
+ 4+8*p->nVertex, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+ }
+}
+
+#define GEOPOLY_PI 3.1415926535897932385
+
+/* Fast approximation for sine(X) for X between -0.5*pi and 2*pi
+*/
+static double geopolySine(double r){
+ assert( r>=-0.5*GEOPOLY_PI && r<=2.0*GEOPOLY_PI );
+ if( r>=1.5*GEOPOLY_PI ){
+ r -= 2.0*GEOPOLY_PI;
+ }
+ if( r>=0.5*GEOPOLY_PI ){
+ return -geopolySine(r-GEOPOLY_PI);
+ }else{
+ double r2 = r*r;
+ double r3 = r2*r;
+ double r5 = r3*r2;
+ return 0.9996949*r - 0.1656700*r3 + 0.0075134*r5;
+ }
+}
+
+/*
+** Function: geopoly_regular(X,Y,R,N)
+**
+** Construct a simple, convex, regular polygon centered at X, Y
+** with circumradius R and with N sides.
+*/
+static void geopolyRegularFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ double x = sqlite3_value_double(argv[0]);
+ double y = sqlite3_value_double(argv[1]);
+ double r = sqlite3_value_double(argv[2]);
+ int n = sqlite3_value_int(argv[3]);
+ int i;
+ GeoPoly *p;
+
+ if( n<3 || r<=0.0 ) return;
+ if( n>1000 ) n = 1000;
+ p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) );
+ if( p==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ i = 1;
+ p->hdr[0] = *(unsigned char*)&i;
+ p->hdr[1] = 0;
+ p->hdr[2] = (n>>8)&0xff;
+ p->hdr[3] = n&0xff;
+ for(i=0; i<n; i++){
+ double rAngle = 2.0*GEOPOLY_PI*i/n;
+ GeoX(p,i) = x - r*geopolySine(rAngle-0.5*GEOPOLY_PI);
+ GeoY(p,i) = y + r*geopolySine(rAngle);
+ }
+ sqlite3_result_blob(context, p->hdr, 4+8*n, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+}
+
+/*
+** If pPoly is a polygon, compute its bounding box. Then:
+**
+** (1) if aCoord!=0 store the bounding box in aCoord, returning NULL
+** (2) otherwise, compute a GeoPoly for the bounding box and return the
+** new GeoPoly
+**
+** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from
+** the bounding box in aCoord and return a pointer to that GeoPoly.
+*/
+static GeoPoly *geopolyBBox(
+ sqlite3_context *context, /* For recording the error */
+ sqlite3_value *pPoly, /* The polygon */
+ RtreeCoord *aCoord, /* Results here */
+ int *pRc /* Error code here */
+){
+ GeoPoly *pOut = 0;
+ GeoPoly *p;
+ float mnX, mxX, mnY, mxY;
+ if( pPoly==0 && aCoord!=0 ){
+ p = 0;
+ mnX = aCoord[0].f;
+ mxX = aCoord[1].f;
+ mnY = aCoord[2].f;
+ mxY = aCoord[3].f;
+ goto geopolyBboxFill;
+ }else{
+ p = geopolyFuncParam(context, pPoly, pRc);
+ }
+ if( p ){
+ int ii;
+ mnX = mxX = GeoX(p,0);
+ mnY = mxY = GeoY(p,0);
+ for(ii=1; ii<p->nVertex; ii++){
+ double r = GeoX(p,ii);
+ if( r<mnX ) mnX = (float)r;
+ else if( r>mxX ) mxX = (float)r;
+ r = GeoY(p,ii);
+ if( r<mnY ) mnY = (float)r;
+ else if( r>mxY ) mxY = (float)r;
+ }
+ if( pRc ) *pRc = SQLITE_OK;
+ if( aCoord==0 ){
+ geopolyBboxFill:
+ pOut = sqlite3_realloc64(p, GEOPOLY_SZ(4));
+ if( pOut==0 ){
+ sqlite3_free(p);
+ if( context ) sqlite3_result_error_nomem(context);
+ if( pRc ) *pRc = SQLITE_NOMEM;
+ return 0;
+ }
+ pOut->nVertex = 4;
+ ii = 1;
+ pOut->hdr[0] = *(unsigned char*)&ii;
+ pOut->hdr[1] = 0;
+ pOut->hdr[2] = 0;
+ pOut->hdr[3] = 4;
+ GeoX(pOut,0) = mnX;
+ GeoY(pOut,0) = mnY;
+ GeoX(pOut,1) = mxX;
+ GeoY(pOut,1) = mnY;
+ GeoX(pOut,2) = mxX;
+ GeoY(pOut,2) = mxY;
+ GeoX(pOut,3) = mnX;
+ GeoY(pOut,3) = mxY;
+ }else{
+ sqlite3_free(p);
+ aCoord[0].f = mnX;
+ aCoord[1].f = mxX;
+ aCoord[2].f = mnY;
+ aCoord[3].f = mxY;
+ }
+ }else{
+ memset(aCoord, 0, sizeof(RtreeCoord)*4);
+ }
+ return pOut;
+}
+
+/*
+** Implementation of the geopoly_bbox(X) SQL function.
+*/
+static void geopolyBBoxFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
+ if( p ){
+ sqlite3_result_blob(context, p->hdr,
+ 4+8*p->nVertex, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** State vector for the geopoly_group_bbox() aggregate function.
+*/
+typedef struct GeoBBox GeoBBox;
+struct GeoBBox {
+ int isInit;
+ RtreeCoord a[4];
+};
+
+
+/*
+** Implementation of the geopoly_group_bbox(X) aggregate SQL function.
+*/
+static void geopolyBBoxStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ RtreeCoord a[4];
+ int rc = SQLITE_OK;
+ (void)geopolyBBox(context, argv[0], a, &rc);
+ if( rc==SQLITE_OK ){
+ GeoBBox *pBBox;
+ pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox));
+ if( pBBox==0 ) return;
+ if( pBBox->isInit==0 ){
+ pBBox->isInit = 1;
+ memcpy(pBBox->a, a, sizeof(RtreeCoord)*4);
+ }else{
+ if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0];
+ if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1];
+ if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2];
+ if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3];
+ }
+ }
+}
+static void geopolyBBoxFinal(
+ sqlite3_context *context
+){
+ GeoPoly *p;
+ GeoBBox *pBBox;
+ pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0);
+ if( pBBox==0 ) return;
+ p = geopolyBBox(context, 0, pBBox->a, 0);
+ if( p ){
+ sqlite3_result_blob(context, p->hdr,
+ 4+8*p->nVertex, SQLITE_TRANSIENT);
+ sqlite3_free(p);
+ }
+}
+
+
+/*
+** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
+** Returns:
+**
+** +2 x0,y0 is on the line segement
+**
+** +1 x0,y0 is beneath line segment
+**
+** 0 x0,y0 is not on or beneath the line segment or the line segment
+** is vertical and x0,y0 is not on the line segment
+**
+** The left-most coordinate min(x1,x2) is not considered to be part of
+** the line segment for the purposes of this analysis.
+*/
+static int pointBeneathLine(
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2
+){
+ double y;
+ if( x0==x1 && y0==y1 ) return 2;
+ if( x1<x2 ){
+ if( x0<=x1 || x0>x2 ) return 0;
+ }else if( x1>x2 ){
+ if( x0<=x2 || x0>x1 ) return 0;
+ }else{
+ /* Vertical line segment */
+ if( x0!=x1 ) return 0;
+ if( y0<y1 && y0<y2 ) return 0;
+ if( y0>y1 && y0>y2 ) return 0;
+ return 2;
+ }
+ y = y1 + (y2-y1)*(x0-x1)/(x2-x1);
+ if( y0==y ) return 2;
+ if( y0<y ) return 1;
+ return 0;
+}
+
+/*
+** SQL function: geopoly_contains_point(P,X,Y)
+**
+** Return +2 if point X,Y is within polygon P.
+** Return +1 if point X,Y is on the polygon boundary.
+** Return 0 if point X,Y is outside the polygon
+*/
+static void geopolyContainsPointFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+ double x0 = sqlite3_value_double(argv[1]);
+ double y0 = sqlite3_value_double(argv[2]);
+ int v = 0;
+ int cnt = 0;
+ int ii;
+ if( p1==0 ) return;
+ for(ii=0; ii<p1->nVertex-1; ii++){
+ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
+ GeoX(p1,ii+1),GeoY(p1,ii+1));
+ if( v==2 ) break;
+ cnt += v;
+ }
+ if( v!=2 ){
+ v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
+ GeoX(p1,0), GeoY(p1,0));
+ }
+ if( v==2 ){
+ sqlite3_result_int(context, 1);
+ }else if( ((v+cnt)&1)==0 ){
+ sqlite3_result_int(context, 0);
+ }else{
+ sqlite3_result_int(context, 2);
+ }
+ sqlite3_free(p1);
+}
+
+/* Forward declaration */
+static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
+
+/*
+** SQL function: geopoly_within(P1,P2)
+**
+** Return +2 if P1 and P2 are the same polygon
+** Return +1 if P2 is contained within P1
+** Return 0 if any part of P2 is on the outside of P1
+**
+*/
+static void geopolyWithinFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+ GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+ if( p1 && p2 ){
+ int x = geopolyOverlap(p1, p2);
+ if( x<0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
+ }
+ }
+ sqlite3_free(p1);
+ sqlite3_free(p2);
+}
+
+/* Objects used by the overlap algorihm. */
+typedef struct GeoEvent GeoEvent;
+typedef struct GeoSegment GeoSegment;
+typedef struct GeoOverlap GeoOverlap;
+struct GeoEvent {
+ double x; /* X coordinate at which event occurs */
+ int eType; /* 0 for ADD, 1 for REMOVE */
+ GeoSegment *pSeg; /* The segment to be added or removed */
+ GeoEvent *pNext; /* Next event in the sorted list */
+};
+struct GeoSegment {
+ double C, B; /* y = C*x + B */
+ double y; /* Current y value */
+ float y0; /* Initial y value */
+ unsigned char side; /* 1 for p1, 2 for p2 */
+ unsigned int idx; /* Which segment within the side */
+ GeoSegment *pNext; /* Next segment in a list sorted by y */
+};
+struct GeoOverlap {
+ GeoEvent *aEvent; /* Array of all events */
+ GeoSegment *aSegment; /* Array of all segments */
+ int nEvent; /* Number of events */
+ int nSegment; /* Number of segments */
+};
+
+/*
+** Add a single segment and its associated events.
+*/
+static void geopolyAddOneSegment(
+ GeoOverlap *p,
+ GeoCoord x0,
+ GeoCoord y0,
+ GeoCoord x1,
+ GeoCoord y1,
+ unsigned char side,
+ unsigned int idx
+){
+ GeoSegment *pSeg;
+ GeoEvent *pEvent;
+ if( x0==x1 ) return; /* Ignore vertical segments */
+ if( x0>x1 ){
+ GeoCoord t = x0;
+ x0 = x1;
+ x1 = t;
+ t = y0;
+ y0 = y1;
+ y1 = t;
+ }
+ pSeg = p->aSegment + p->nSegment;
+ p->nSegment++;
+ pSeg->C = (y1-y0)/(x1-x0);
+ pSeg->B = y1 - x1*pSeg->C;
+ pSeg->y0 = y0;
+ pSeg->side = side;
+ pSeg->idx = idx;
+ pEvent = p->aEvent + p->nEvent;
+ p->nEvent++;
+ pEvent->x = x0;
+ pEvent->eType = 0;
+ pEvent->pSeg = pSeg;
+ pEvent = p->aEvent + p->nEvent;
+ p->nEvent++;
+ pEvent->x = x1;
+ pEvent->eType = 1;
+ pEvent->pSeg = pSeg;
+}
+
+
+
+/*
+** Insert all segments and events for polygon pPoly.
+*/
+static void geopolyAddSegments(
+ GeoOverlap *p, /* Add segments to this Overlap object */
+ GeoPoly *pPoly, /* Take all segments from this polygon */
+ unsigned char side /* The side of pPoly */
+){
+ unsigned int i;
+ GeoCoord *x;
+ for(i=0; i<(unsigned)pPoly->nVertex-1; i++){
+ x = &GeoX(pPoly,i);
+ geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i);
+ }
+ x = &GeoX(pPoly,i);
+ geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i);
+}
+
+/*
+** Merge two lists of sorted events by X coordinate
+*/
+static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){
+ GeoEvent head, *pLast;
+ head.pNext = 0;
+ pLast = &head;
+ while( pRight && pLeft ){
+ if( pRight->x <= pLeft->x ){
+ pLast->pNext = pRight;
+ pLast = pRight;
+ pRight = pRight->pNext;
+ }else{
+ pLast->pNext = pLeft;
+ pLast = pLeft;
+ pLeft = pLeft->pNext;
+ }
+ }
+ pLast->pNext = pRight ? pRight : pLeft;
+ return head.pNext;
+}
+
+/*
+** Sort an array of nEvent event objects into a list.
+*/
+static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){
+ int mx = 0;
+ int i, j;
+ GeoEvent *p;
+ GeoEvent *a[50];
+ for(i=0; i<nEvent; i++){
+ p = &aEvent[i];
+ p->pNext = 0;
+ for(j=0; j<mx && a[j]; j++){
+ p = geopolyEventMerge(a[j], p);
+ a[j] = 0;
+ }
+ a[j] = p;
+ if( j>=mx ) mx = j+1;
+ }
+ p = 0;
+ for(i=0; i<mx; i++){
+ p = geopolyEventMerge(a[i], p);
+ }
+ return p;
+}
+
+/*
+** Merge two lists of sorted segments by Y, and then by C.
+*/
+static GeoSegment *geopolySegmentMerge(GeoSegment *pLeft, GeoSegment *pRight){
+ GeoSegment head, *pLast;
+ head.pNext = 0;
+ pLast = &head;
+ while( pRight && pLeft ){
+ double r = pRight->y - pLeft->y;
+ if( r==0.0 ) r = pRight->C - pLeft->C;
+ if( r<0.0 ){
+ pLast->pNext = pRight;
+ pLast = pRight;
+ pRight = pRight->pNext;
+ }else{
+ pLast->pNext = pLeft;
+ pLast = pLeft;
+ pLeft = pLeft->pNext;
+ }
+ }
+ pLast->pNext = pRight ? pRight : pLeft;
+ return head.pNext;
+}
+
+/*
+** Sort a list of GeoSegments in order of increasing Y and in the event of
+** a tie, increasing C (slope).
+*/
+static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){
+ int mx = 0;
+ int i;
+ GeoSegment *p;
+ GeoSegment *a[50];
+ while( pList ){
+ p = pList;
+ pList = pList->pNext;
+ p->pNext = 0;
+ for(i=0; i<mx && a[i]; i++){
+ p = geopolySegmentMerge(a[i], p);
+ a[i] = 0;
+ }
+ a[i] = p;
+ if( i>=mx ) mx = i+1;
+ }
+ p = 0;
+ for(i=0; i<mx; i++){
+ p = geopolySegmentMerge(a[i], p);
+ }
+ return p;
+}
+
+/*
+** Determine the overlap between two polygons
+*/
+static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
+ sqlite3_int64 nVertex = p1->nVertex + p2->nVertex + 2;
+ GeoOverlap *p;
+ sqlite3_int64 nByte;
+ GeoEvent *pThisEvent;
+ double rX;
+ int rc = 0;
+ int needSort = 0;
+ GeoSegment *pActive = 0;
+ GeoSegment *pSeg;
+ unsigned char aOverlap[4];
+
+ nByte = sizeof(GeoEvent)*nVertex*2
+ + sizeof(GeoSegment)*nVertex
+ + sizeof(GeoOverlap);
+ p = sqlite3_malloc64( nByte );
+ if( p==0 ) return -1;
+ p->aEvent = (GeoEvent*)&p[1];
+ p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2];
+ p->nEvent = p->nSegment = 0;
+ geopolyAddSegments(p, p1, 1);
+ geopolyAddSegments(p, p2, 2);
+ pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
+ rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
+ memset(aOverlap, 0, sizeof(aOverlap));
+ while( pThisEvent ){
+ if( pThisEvent->x!=rX ){
+ GeoSegment *pPrev = 0;
+ int iMask = 0;
+ GEODEBUG(("Distinct X: %g\n", pThisEvent->x));
+ rX = pThisEvent->x;
+ if( needSort ){
+ GEODEBUG(("SORT\n"));
+ pActive = geopolySortSegmentsByYAndC(pActive);
+ needSort = 0;
+ }
+ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
+ if( pPrev ){
+ if( pPrev->y!=pSeg->y ){
+ GEODEBUG(("MASK: %d\n", iMask));
+ aOverlap[iMask] = 1;
+ }
+ }
+ iMask ^= pSeg->side;
+ pPrev = pSeg;
+ }
+ pPrev = 0;
+ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
+ double y = pSeg->C*rX + pSeg->B;
+ GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y));
+ pSeg->y = y;
+ if( pPrev ){
+ if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){
+ rc = 1;
+ GEODEBUG(("Crossing: %d.%d and %d.%d\n",
+ pPrev->side, pPrev->idx,
+ pSeg->side, pSeg->idx));
+ goto geopolyOverlapDone;
+ }else if( pPrev->y!=pSeg->y ){
+ GEODEBUG(("MASK: %d\n", iMask));
+ aOverlap[iMask] = 1;
+ }
+ }
+ iMask ^= pSeg->side;
+ pPrev = pSeg;
+ }
+ }
+ GEODEBUG(("%s %d.%d C=%g B=%g\n",
+ pThisEvent->eType ? "RM " : "ADD",
+ pThisEvent->pSeg->side, pThisEvent->pSeg->idx,
+ pThisEvent->pSeg->C,
+ pThisEvent->pSeg->B));
+ if( pThisEvent->eType==0 ){
+ /* Add a segment */
+ pSeg = pThisEvent->pSeg;
+ pSeg->y = pSeg->y0;
+ pSeg->pNext = pActive;
+ pActive = pSeg;
+ needSort = 1;
+ }else{
+ /* Remove a segment */
+ if( pActive==pThisEvent->pSeg ){
+ pActive = pActive->pNext;
+ }else{
+ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
+ if( pSeg->pNext==pThisEvent->pSeg ){
+ pSeg->pNext = pSeg->pNext->pNext;
+ break;
+ }
+ }
+ }
+ }
+ pThisEvent = pThisEvent->pNext;
+ }
+ if( aOverlap[3]==0 ){
+ rc = 0;
+ }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){
+ rc = 3;
+ }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){
+ rc = 2;
+ }else if( aOverlap[1]==0 && aOverlap[2]==0 ){
+ rc = 4;
+ }else{
+ rc = 1;
+ }
+
+geopolyOverlapDone:
+ sqlite3_free(p);
+ return rc;
+}
+
+/*
+** SQL function: geopoly_overlap(P1,P2)
+**
+** Determine whether or not P1 and P2 overlap. Return value:
+**
+** 0 The two polygons are disjoint
+** 1 They overlap
+** 2 P1 is completely contained within P2
+** 3 P2 is completely contained within P1
+** 4 P1 and P2 are the same polygon
+** NULL Either P1 or P2 or both are not valid polygons
+*/
+static void geopolyOverlapFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+ GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+ if( p1 && p2 ){
+ int x = geopolyOverlap(p1, p2);
+ if( x<0 ){
+ sqlite3_result_error_nomem(context);
+ }else{
+ sqlite3_result_int(context, x);
+ }
+ }
+ sqlite3_free(p1);
+ sqlite3_free(p2);
+}
+
+/*
+** Enable or disable debugging output
+*/
+static void geopolyDebugFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+#ifdef GEOPOLY_ENABLE_DEBUG
+ geo_debug = sqlite3_value_int(argv[0]);
+#endif
+}
+
+/*
+** This function is the implementation of both the xConnect and xCreate
+** methods of the geopoly virtual table.
+**
+** argv[0] -> module name
+** argv[1] -> database name
+** argv[2] -> table name
+** argv[...] -> column names...
+*/
+static int geopolyInit(
+ sqlite3 *db, /* Database connection */
+ void *pAux, /* One of the RTREE_COORD_* constants */
+ int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */
+ sqlite3_vtab **ppVtab, /* OUT: New virtual table */
+ char **pzErr, /* OUT: Error message, if any */
+ int isCreate /* True for xCreate, false for xConnect */
+){
+ int rc = SQLITE_OK;
+ Rtree *pRtree;
+ sqlite3_int64 nDb; /* Length of string argv[1] */
+ sqlite3_int64 nName; /* Length of string argv[2] */
+ sqlite3_str *pSql;
+ char *zSql;
+ int ii;
+
+ sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+
+ /* Allocate the sqlite3_vtab structure */
+ nDb = strlen(argv[1]);
+ nName = strlen(argv[2]);
+ pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ if( !pRtree ){
+ return SQLITE_NOMEM;
+ }
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ pRtree->nBusy = 1;
+ pRtree->base.pModule = &rtreeModule;
+ pRtree->zDb = (char *)&pRtree[1];
+ pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->eCoordType = RTREE_COORD_REAL32;
+ pRtree->nDim = 2;
+ pRtree->nDim2 = 4;
+ memcpy(pRtree->zDb, argv[1], nDb);
+ memcpy(pRtree->zName, argv[2], nName);
+
+
+ /* Create/Connect to the underlying relational database schema. If
+ ** that is successful, call sqlite3_declare_vtab() to configure
+ ** the r-tree table schema.
+ */
+ pSql = sqlite3_str_new(db);
+ sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape");
+ pRtree->nAux = 1; /* Add one for _shape */
+ pRtree->nAuxNotNull = 1; /* The _shape column is always not-null */
+ for(ii=3; ii<argc; ii++){
+ pRtree->nAux++;
+ sqlite3_str_appendf(pSql, ",%s", argv[ii]);
+ }
+ sqlite3_str_appendf(pSql, ");");
+ zSql = sqlite3_str_finish(pSql);
+ if( !zSql ){
+ rc = SQLITE_NOMEM;
+ }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+ sqlite3_free(zSql);
+ if( rc ) goto geopolyInit_fail;
+ pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
+
+ /* Figure out the node size to use. */
+ rc = getNodeSize(db, pRtree, isCreate, pzErr);
+ if( rc ) goto geopolyInit_fail;
+ rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
+ if( rc ){
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ goto geopolyInit_fail;
+ }
+
+ *ppVtab = (sqlite3_vtab *)pRtree;
+ return SQLITE_OK;
+
+geopolyInit_fail:
+ if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
+ assert( *ppVtab==0 );
+ assert( pRtree->nBusy==1 );
+ rtreeRelease(pRtree);
+ return rc;
+}
+
+
+/*
+** GEOPOLY virtual table module xCreate method.
+*/
+static int geopolyCreate(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
+}
+
+/*
+** GEOPOLY virtual table module xConnect method.
+*/
+static int geopolyConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0);
+}
+
+
+/*
+** GEOPOLY virtual table module xFilter method.
+**
+** Query plans:
+**
+** 1 rowid lookup
+** 2 search for objects overlapping the same bounding box
+** that contains polygon argv[0]
+** 3 search for objects overlapping the same bounding box
+** that contains polygon argv[0]
+** 4 full table scan
+*/
+static int geopolyFilter(
+ sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */
+ int idxNum, /* Query plan */
+ const char *idxStr, /* Not Used */
+ int argc, sqlite3_value **argv /* Parameters to the query plan */
+){
+ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
+ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
+ RtreeNode *pRoot = 0;
+ int rc = SQLITE_OK;
+ int iCell = 0;
+
+ rtreeReference(pRtree);
+
+ /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
+ resetCursor(pCsr);
+
+ pCsr->iStrategy = idxNum;
+ if( idxNum==1 ){
+ /* Special case - lookup by rowid. */
+ RtreeNode *pLeaf; /* Leaf on which the required cell resides */
+ RtreeSearchPoint *p; /* Search point for the leaf */
+ i64 iRowid = sqlite3_value_int64(argv[0]);
+ i64 iNode = 0;
+ rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
+ if( rc==SQLITE_OK && pLeaf!=0 ){
+ p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0);
+ assert( p!=0 ); /* Always returns pCsr->sPoint */
+ pCsr->aNode[0] = pLeaf;
+ p->id = iNode;
+ p->eWithin = PARTLY_WITHIN;
+ rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell);
+ p->iCell = (u8)iCell;
+ RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:");
+ }else{
+ pCsr->atEOF = 1;
+ }
+ }else{
+ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
+ ** with the configured constraints.
+ */
+ rc = nodeAcquire(pRtree, 1, 0, &pRoot);
+ if( rc==SQLITE_OK && idxNum<=3 ){
+ RtreeCoord bbox[4];
+ RtreeConstraint *p;
+ assert( argc==1 );
+ geopolyBBox(0, argv[0], bbox, &rc);
+ if( rc ){
+ goto geopoly_filter_end;
+ }
+ pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4);
+ pCsr->nConstraint = 4;
+ if( p==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4);
+ memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
+ if( idxNum==2 ){
+ /* Overlap query */
+ p->op = 'B';
+ p->iCoord = 0;
+ p->u.rValue = bbox[1].f;
+ p++;
+ p->op = 'D';
+ p->iCoord = 1;
+ p->u.rValue = bbox[0].f;
+ p++;
+ p->op = 'B';
+ p->iCoord = 2;
+ p->u.rValue = bbox[3].f;
+ p++;
+ p->op = 'D';
+ p->iCoord = 3;
+ p->u.rValue = bbox[2].f;
+ }else{
+ /* Within query */
+ p->op = 'D';
+ p->iCoord = 0;
+ p->u.rValue = bbox[0].f;
+ p++;
+ p->op = 'B';
+ p->iCoord = 1;
+ p->u.rValue = bbox[1].f;
+ p++;
+ p->op = 'D';
+ p->iCoord = 2;
+ p->u.rValue = bbox[2].f;
+ p++;
+ p->op = 'B';
+ p->iCoord = 3;
+ p->u.rValue = bbox[3].f;
+ }
+ }
+ }
+ if( rc==SQLITE_OK ){
+ RtreeSearchPoint *pNew;
+ pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ goto geopoly_filter_end;
+ }
+ pNew->id = 1;
+ pNew->iCell = 0;
+ pNew->eWithin = PARTLY_WITHIN;
+ assert( pCsr->bPoint==1 );
+ pCsr->aNode[0] = pRoot;
+ pRoot = 0;
+ RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:");
+ rc = rtreeStepToLeaf(pCsr);
+ }
+ }
+
+geopoly_filter_end:
+ nodeRelease(pRtree, pRoot);
+ rtreeRelease(pRtree);
+ return rc;
+}
+
+/*
+** Rtree virtual table module xBestIndex method. There are three
+** table scan strategies to choose from (in order from most to
+** least desirable):
+**
+** idxNum idxStr Strategy
+** ------------------------------------------------
+** 1 "rowid" Direct lookup by rowid.
+** 2 "rtree" R-tree overlap query using geopoly_overlap()
+** 3 "rtree" R-tree within query using geopoly_within()
+** 4 "fullscan" full-table scan.
+** ------------------------------------------------
+*/
+static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int ii;
+ int iRowidTerm = -1;
+ int iFuncTerm = -1;
+ int idxNum = 0;
+
+ for(ii=0; ii<pIdxInfo->nConstraint; ii++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
+ if( !p->usable ) continue;
+ if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ iRowidTerm = ii;
+ break;
+ }
+ if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
+ /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap()
+ ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within().
+ ** See geopolyFindFunction() */
+ iFuncTerm = ii;
+ idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2;
+ }
+ }
+
+ if( iRowidTerm>=0 ){
+ pIdxInfo->idxNum = 1;
+ pIdxInfo->idxStr = "rowid";
+ pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
+ pIdxInfo->estimatedCost = 30.0;
+ pIdxInfo->estimatedRows = 1;
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+ return SQLITE_OK;
+ }
+ if( iFuncTerm>=0 ){
+ pIdxInfo->idxNum = idxNum;
+ pIdxInfo->idxStr = "rtree";
+ pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0;
+ pIdxInfo->estimatedCost = 300.0;
+ pIdxInfo->estimatedRows = 10;
+ return SQLITE_OK;
+ }
+ pIdxInfo->idxNum = 4;
+ pIdxInfo->idxStr = "fullscan";
+ pIdxInfo->estimatedCost = 3000000.0;
+ pIdxInfo->estimatedRows = 100000;
+ return SQLITE_OK;
+}
+
+
+/*
+** GEOPOLY virtual table module xColumn method.
+*/
+static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+ Rtree *pRtree = (Rtree *)cur->pVtab;
+ RtreeCursor *pCsr = (RtreeCursor *)cur;
+ RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
+ int rc = SQLITE_OK;
+ RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
+
+ if( rc ) return rc;
+ if( p==0 ) return SQLITE_OK;
+ if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK;
+ if( i<=pRtree->nAux ){
+ if( !pCsr->bAuxValid ){
+ if( pCsr->pReadAux==0 ){
+ rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
+ &pCsr->pReadAux, 0);
+ if( rc ) return rc;
+ }
+ sqlite3_bind_int64(pCsr->pReadAux, 1,
+ nodeGetRowid(pRtree, pNode, p->iCell));
+ rc = sqlite3_step(pCsr->pReadAux);
+ if( rc==SQLITE_ROW ){
+ pCsr->bAuxValid = 1;
+ }else{
+ sqlite3_reset(pCsr->pReadAux);
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ return rc;
+ }
+ }
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2));
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** The xUpdate method for GEOPOLY module virtual tables.
+**
+** For DELETE:
+**
+** argv[0] = the rowid to be deleted
+**
+** For INSERT:
+**
+** argv[0] = SQL NULL
+** argv[1] = rowid to insert, or an SQL NULL to select automatically
+** argv[2] = _shape column
+** argv[3] = first application-defined column....
+**
+** For UPDATE:
+**
+** argv[0] = rowid to modify. Never NULL
+** argv[1] = rowid after the change. Never NULL
+** argv[2] = new value for _shape
+** argv[3] = new value for first application-defined column....
+*/
+static int geopolyUpdate(
+ sqlite3_vtab *pVtab,
+ int nData,
+ sqlite3_value **aData,
+ sqlite_int64 *pRowid
+){
+ Rtree *pRtree = (Rtree *)pVtab;
+ int rc = SQLITE_OK;
+ RtreeCell cell; /* New cell to insert if nData>1 */
+ i64 oldRowid; /* The old rowid */
+ int oldRowidValid; /* True if oldRowid is valid */
+ i64 newRowid; /* The new rowid */
+ int newRowidValid; /* True if newRowid is valid */
+ int coordChange = 0; /* Change in coordinates */
+
+ if( pRtree->nNodeRef ){
+ /* Unable to write to the btree while another cursor is reading from it,
+ ** since the write might do a rebalance which would disrupt the read
+ ** cursor. */
+ return SQLITE_LOCKED_VTAB;
+ }
+ rtreeReference(pRtree);
+ assert(nData>=1);
+
+ oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;;
+ oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0;
+ newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL;
+ newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0;
+ cell.iRowid = newRowid;
+
+ if( nData>1 /* not a DELETE */
+ && (!oldRowidValid /* INSERT */
+ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */
+ || oldRowid!=newRowid) /* Rowid change */
+ ){
+ geopolyBBox(0, aData[2], cell.aCoord, &rc);
+ if( rc ){
+ if( rc==SQLITE_ERROR ){
+ pVtab->zErrMsg =
+ sqlite3_mprintf("_shape does not contain a valid polygon");
+ }
+ goto geopoly_update_end;
+ }
+ coordChange = 1;
+
+ /* If a rowid value was supplied, check if it is already present in
+ ** the table. If so, the constraint has failed. */
+ if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){
+ 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 = rtreeConstraintError(pRtree, 0);
+ }
+ }
+ }
+ }
+
+ /* If aData[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( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){
+ rc = rtreeDeleteRowid(pRtree, oldRowid);
+ }
+
+ /* If the aData[] array contains more than one element, elements
+ ** (aData[2]..aData[argc-1]) contain a new record to insert into
+ ** the r-tree structure.
+ */
+ if( rc==SQLITE_OK && nData>1 && coordChange ){
+ /* Insert the new record into the r-tree */
+ RtreeNode *pLeaf = 0;
+ if( !newRowidValid ){
+ rc = rtreeNewRowid(pRtree, &cell.iRowid);
+ }
+ *pRowid = cell.iRowid;
+ if( rc==SQLITE_OK ){
+ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
+ }
+ if( rc==SQLITE_OK ){
+ int rc2;
+ pRtree->iReinsertHeight = -1;
+ rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
+ rc2 = nodeRelease(pRtree, pLeaf);
+ if( rc==SQLITE_OK ){
+ rc = rc2;
+ }
+ }
+ }
+
+ /* Change the data */
+ if( rc==SQLITE_OK && nData>1 ){
+ sqlite3_stmt *pUp = pRtree->pWriteAux;
+ int jj;
+ int nChange = 0;
+ sqlite3_bind_int64(pUp, 1, cell.iRowid);
+ assert( pRtree->nAux>=1 );
+ if( sqlite3_value_nochange(aData[2]) ){
+ sqlite3_bind_null(pUp, 2);
+ }else{
+ GeoPoly *p = 0;
+ if( sqlite3_value_type(aData[2])==SQLITE_TEXT
+ && (p = geopolyFuncParam(0, aData[2], &rc))!=0
+ && rc==SQLITE_OK
+ ){
+ sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_bind_value(pUp, 2, aData[2]);
+ }
+ sqlite3_free(p);
+ nChange = 1;
+ }
+ for(jj=1; jj<pRtree->nAux; jj++){
+ nChange++;
+ sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
+ }
+ if( nChange ){
+ sqlite3_step(pUp);
+ rc = sqlite3_reset(pUp);
+ }
+ }
+
+geopoly_update_end:
+ rtreeRelease(pRtree);
+ return rc;
+}
+
+/*
+** Report that geopoly_overlap() is an overloaded function suitable
+** for use in xBestIndex.
+*/
+static int geopolyFindFunction(
+ sqlite3_vtab *pVtab,
+ int nArg,
+ const char *zName,
+ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
+ void **ppArg
+){
+ if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
+ *pxFunc = geopolyOverlapFunc;
+ *ppArg = 0;
+ return SQLITE_INDEX_CONSTRAINT_FUNCTION;
+ }
+ if( sqlite3_stricmp(zName, "geopoly_within")==0 ){
+ *pxFunc = geopolyWithinFunc;
+ *ppArg = 0;
+ return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
+ }
+ return 0;
+}
+
+
+static sqlite3_module geopolyModule = {
+ 3, /* iVersion */
+ geopolyCreate, /* xCreate - create a table */
+ geopolyConnect, /* xConnect - connect to an existing table */
+ geopolyBestIndex, /* xBestIndex - Determine search strategy */
+ rtreeDisconnect, /* xDisconnect - Disconnect from a table */
+ rtreeDestroy, /* xDestroy - Drop a table */
+ rtreeOpen, /* xOpen - open a cursor */
+ rtreeClose, /* xClose - close a cursor */
+ geopolyFilter, /* xFilter - configure scan constraints */
+ rtreeNext, /* xNext - advance a cursor */
+ rtreeEof, /* xEof */
+ geopolyColumn, /* xColumn - read data */
+ rtreeRowid, /* xRowid - read data */
+ geopolyUpdate, /* xUpdate - write data */
+ rtreeBeginTransaction, /* xBegin - begin transaction */
+ rtreeEndTransaction, /* xSync - sync transaction */
+ rtreeEndTransaction, /* xCommit - commit transaction */
+ rtreeEndTransaction, /* xRollback - rollback transaction */
+ geopolyFindFunction, /* xFindFunction - function overloading */
+ rtreeRename, /* xRename - rename the table */
+ rtreeSavepoint, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ rtreeShadowName /* xShadowName */
+};
+
+static int sqlite3_geopoly_init(sqlite3 *db){
+ int rc = SQLITE_OK;
+ static const struct {
+ void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+ signed char nArg;
+ unsigned char bPure;
+ const char *zName;
+ } aFunc[] = {
+ { geopolyAreaFunc, 1, 1, "geopoly_area" },
+ { geopolyBlobFunc, 1, 1, "geopoly_blob" },
+ { geopolyJsonFunc, 1, 1, "geopoly_json" },
+ { geopolySvgFunc, -1, 1, "geopoly_svg" },
+ { geopolyWithinFunc, 2, 1, "geopoly_within" },
+ { geopolyContainsPointFunc, 3, 1, "geopoly_contains_point" },
+ { geopolyOverlapFunc, 2, 1, "geopoly_overlap" },
+ { geopolyDebugFunc, 1, 0, "geopoly_debug" },
+ { geopolyBBoxFunc, 1, 1, "geopoly_bbox" },
+ { geopolyXformFunc, 7, 1, "geopoly_xform" },
+ { geopolyRegularFunc, 4, 1, "geopoly_regular" },
+ { geopolyCcwFunc, 1, 1, "geopoly_ccw" },
+ };
+ static const struct {
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**);
+ void (*xFinal)(sqlite3_context*);
+ const char *zName;
+ } aAgg[] = {
+ { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" },
+ };
+ int i;
+ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+ int enc;
+ if( aFunc[i].bPure ){
+ enc = SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS;
+ }else{
+ enc = SQLITE_UTF8|SQLITE_DIRECTONLY;
+ }
+ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
+ enc, 0,
+ aFunc[i].xFunc, 0, 0);
+ }
+ for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
+ rc = sqlite3_create_function(db, aAgg[i].zName, 1,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, 0,
+ 0, aAgg[i].xStep, aAgg[i].xFinal);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
+ }
+ return rc;
+}
+
+/************** End of geopoly.c *********************************************/
+/************** Continuing where we left off in rtree.c **********************/
+#endif
+
+/*
** Register the r-tree module with database handle db. This creates the
-** virtual table module "rtree" and the debugging/analysis scalar
+** virtual table module "rtree" and the debugging/analysis scalar
** function "rtreenode".
*/
SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
@@ -164728,6 +194256,9 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
}
if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "rtreecheck", -1, utf8, 0,rtreecheck, 0,0);
+ }
+ if( rc==SQLITE_OK ){
#ifdef SQLITE_RTREE_INT_ONLY
void *c = (void *)RTREE_COORD_INT32;
#else
@@ -164739,6 +194270,11 @@ SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
void *c = (void *)RTREE_COORD_INT32;
rc = sqlite3_create_module_v2(db, "rtree_i32", &rtreeModule, c, 0);
}
+#ifdef SQLITE_ENABLE_GEOPOLY
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_geopoly_init(db);
+ }
+#endif
return rc;
}
@@ -164785,17 +194321,17 @@ static void rtreeMatchArgFree(void *pArg){
static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
RtreeMatchArg *pBlob;
- int nBlob;
+ sqlite3_int64 nBlob;
int memErr = 0;
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue)
+ nArg*sizeof(sqlite3_value*);
- pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
+ pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
}else{
int i;
- pBlob->magic = RTREE_GEOMETRY_MAGIC;
+ pBlob->iSize = nBlob;
pBlob->cb = pGeomCtx[0];
pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
pBlob->nParam = nArg;
@@ -164812,7 +194348,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
sqlite3_result_error_nomem(ctx);
rtreeMatchArgFree(pBlob);
}else{
- sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree);
+ sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree);
}
}
}
@@ -164835,7 +194371,7 @@ SQLITE_API int sqlite3_rtree_geometry_callback(
pGeomCtx->xQueryFunc = 0;
pGeomCtx->xDestructor = 0;
pGeomCtx->pContext = pContext;
- return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY,
+ return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY,
(void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
);
}
@@ -164860,7 +194396,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
pGeomCtx->xQueryFunc = xQueryFunc;
pGeomCtx->xDestructor = xDestructor;
pGeomCtx->pContext = pContext;
- return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
+ return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
(void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
);
}
@@ -164896,9 +194432,9 @@ SQLITE_API int sqlite3_rtree_init(
*************************************************************************
** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $
**
-** This file implements an integration between the ICU library
-** ("International Components for Unicode", an open-source library
-** for handling unicode data) and SQLite. The integration uses
+** This file implements an integration between the ICU library
+** ("International Components for Unicode", an open-source library
+** for handling unicode data) and SQLite. The integration uses
** ICU to provide the following to SQLite:
**
** * An implementation of the SQL regexp() function (and hence REGEXP
@@ -164909,11 +194445,13 @@ SQLITE_API int sqlite3_rtree_init(
**
** * Integration of ICU and SQLite collation sequences.
**
-** * An implementation of the LIKE operator that uses ICU to
+** * An implementation of the LIKE operator that uses ICU to
** provide case-independent matching.
*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
+#if !defined(SQLITE_CORE) \
+ || defined(SQLITE_ENABLE_ICU) \
+ || defined(SQLITE_ENABLE_ICU_COLLATIONS)
/* Include ICU headers */
#include <unicode/utypes.h>
@@ -164931,6 +194469,26 @@ SQLITE_API int sqlite3_rtree_init(
#endif
/*
+** This function is called when an ICU function called from within
+** the implementation of an SQL scalar function returns an error.
+**
+** The scalar function context passed as the first argument is
+** loaded with an error message based on the following two args.
+*/
+static void icuFunctionError(
+ sqlite3_context *pCtx, /* SQLite scalar function context */
+ const char *zName, /* Name of ICU function that failed */
+ UErrorCode e /* Error code returned by ICU function */
+){
+ char zBuf[128];
+ sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
+ zBuf[127] = '\0';
+ sqlite3_result_error(pCtx, zBuf, -1);
+}
+
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
+
+/*
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
** operator.
*/
@@ -164979,7 +194537,7 @@ static const unsigned char icuUtf8Trans1[] = {
/*
** Compare two UTF-8 strings for equality where the first string is
-** a "LIKE" expression. Return true (1) if they are the same and
+** a "LIKE" expression. Return true (1) if they are the same and
** false (0) if they are different.
*/
static int icuLikeCompare(
@@ -164987,15 +194545,15 @@ static int icuLikeCompare(
const uint8_t *zString, /* The UTF-8 string to compare against */
const UChar32 uEsc /* The escape character */
){
- static const int MATCH_ONE = (UChar32)'_';
- static const int MATCH_ALL = (UChar32)'%';
+ static const uint32_t MATCH_ONE = (uint32_t)'_';
+ static const uint32_t MATCH_ALL = (uint32_t)'%';
int prevEscape = 0; /* True if the previous character was uEsc */
while( 1 ){
/* Read (and consume) the next character from the input pattern. */
- UChar32 uPattern;
+ uint32_t uPattern;
SQLITE_ICU_READ_UTF8(zPattern, uPattern);
if( uPattern==0 ) break;
@@ -165006,12 +194564,12 @@ static int icuLikeCompare(
** 3. uPattern is an unescaped escape character, or
** 4. uPattern is to be handled as an ordinary character
*/
- if( !prevEscape && uPattern==MATCH_ALL ){
+ if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
/* Case 1. */
uint8_t c;
/* Skip any MATCH_ALL or MATCH_ONE characters that follow a
- ** MATCH_ALL. For each MATCH_ONE, skip one character in the
+ ** MATCH_ALL. For each MATCH_ONE, skip one character in the
** test string.
*/
while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
@@ -165032,21 +194590,21 @@ static int icuLikeCompare(
}
return 0;
- }else if( !prevEscape && uPattern==MATCH_ONE ){
+ }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
/* Case 2. */
if( *zString==0 ) return 0;
SQLITE_ICU_SKIP_UTF8(zString);
- }else if( !prevEscape && uPattern==uEsc){
+ }else if( uPattern==(uint32_t)uEsc && !prevEscape ){
/* Case 3. */
prevEscape = 1;
}else{
/* Case 4. */
- UChar32 uString;
+ uint32_t uString;
SQLITE_ICU_READ_UTF8(zString, uString);
- uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
- uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
+ uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
+ uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
if( uString!=uPattern ){
return 0;
}
@@ -165064,15 +194622,15 @@ static int icuLikeCompare(
**
** A LIKE B
**
-** is implemented as like(B, A). If there is an escape character E,
+** is implemented as like(B, A). If there is an escape character E,
**
** A LIKE B ESCAPE E
**
** is mapped to like(B, A, E).
*/
static void icuLikeFunc(
- sqlite3_context *context,
- int argc,
+ sqlite3_context *context,
+ int argc,
sqlite3_value **argv
){
const unsigned char *zA = sqlite3_value_text(argv[0]);
@@ -165098,7 +194656,7 @@ static void icuLikeFunc(
if( zE==0 ) return;
U8_NEXT(zE, i, nE, uEsc);
if( i!=nE){
- sqlite3_result_error(context,
+ sqlite3_result_error(context,
"ESCAPE expression must be a single character", -1);
return;
}
@@ -165110,24 +194668,6 @@ static void icuLikeFunc(
}
/*
-** This function is called when an ICU function called from within
-** the implementation of an SQL scalar function returns an error.
-**
-** The scalar function context passed as the first argument is
-** loaded with an error message based on the following two args.
-*/
-static void icuFunctionError(
- sqlite3_context *pCtx, /* SQLite scalar function context */
- const char *zName, /* Name of ICU function that failed */
- UErrorCode e /* Error code returned by ICU function */
-){
- char zBuf[128];
- sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
- zBuf[127] = '\0';
- sqlite3_result_error(pCtx, zBuf, -1);
-}
-
-/*
** Function to delete compiled regexp objects. Registered as
** a destructor function with sqlite3_set_auxdata().
*/
@@ -165139,7 +194679,7 @@ static void icuRegexpDelete(void *p){
/*
** Implementation of SQLite REGEXP operator. This scalar function takes
** two arguments. The first is a regular expression pattern to compile
-** the second is a string to match against that pattern. If either
+** the second is a string to match against that pattern. If either
** argument is an SQL NULL, then NULL Is returned. Otherwise, the result
** is 1 if the string matches the pattern, or 0 otherwise.
**
@@ -165163,8 +194703,8 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
(void)nArg; /* Unused parameter */
- /* If the left hand side of the regexp operator is NULL,
- ** then the result is also NULL.
+ /* If the left hand side of the regexp operator is NULL,
+ ** then the result is also NULL.
*/
if( !zString ){
return;
@@ -165202,7 +194742,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
}
/* Set the text that the regular expression operates on to a NULL
- ** pointer. This is not really necessary, but it is tidier than
+ ** pointer. This is not really necessary, but it is tidier than
** leaving the regular expression object configured with an invalid
** pointer after this function returns.
*/
@@ -165213,7 +194753,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
}
/*
-** Implementations of scalar functions for case mapping - upper() and
+** Implementations of scalar functions for case mapping - upper() and
** lower(). Function upper() converts its input to upper-case (ABC).
** Function lower() converts to lower-case (abc).
**
@@ -165221,7 +194761,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
** "language specific". Refer to ICU documentation for the differences
** between the two.
**
-** To utilise "general" case mapping, the upper() or lower() scalar
+** To utilise "general" case mapping, the upper() or lower() scalar
** functions are invoked with one argument:
**
** upper('ABC') -> 'abc'
@@ -165292,6 +194832,8 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
assert( 0 ); /* Unreachable */
}
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
+
/*
** Collation sequence destructor function. The pCtx argument points to
** a UCollator structure previously allocated using ucol_open().
@@ -165327,7 +194869,7 @@ static int icuCollationColl(
/*
** Implementation of the scalar function icu_load_collation().
**
-** This scalar function is used to add ICU collation based collation
+** This scalar function is used to add ICU collation based collation
** types to an SQLite database connection. It is intended to be called
** as follows:
**
@@ -165338,8 +194880,8 @@ static int icuCollationColl(
** collation sequence to create.
*/
static void icuLoadCollation(
- sqlite3_context *p,
- int nArg,
+ sqlite3_context *p,
+ int nArg,
sqlite3_value **apArg
){
sqlite3 *db = (sqlite3 *)sqlite3_user_data(p);
@@ -165365,7 +194907,7 @@ static void icuLoadCollation(
}
assert(p);
- rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
+ rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
icuCollationColl, icuCollationDel
);
if( rc!=SQLITE_OK ){
@@ -165378,38 +194920,38 @@ static void icuLoadCollation(
** Register the ICU extension functions with database db.
*/
SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
- struct IcuScalar {
+# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
+ static const struct IcuScalar {
const char *zName; /* Function name */
- int nArg; /* Number of arguments */
- int enc; /* Optimal text encoding */
- void *pContext; /* sqlite3_user_data() context */
+ unsigned char nArg; /* Number of arguments */
+ unsigned int enc; /* Optimal text encoding */
+ unsigned char iContext; /* sqlite3_user_data() context */
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} scalars[] = {
- {"regexp", 2, SQLITE_ANY, 0, icuRegexpFunc},
-
- {"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16},
- {"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16},
- {"upper", 1, SQLITE_UTF16, (void*)1, icuCaseFunc16},
- {"upper", 2, SQLITE_UTF16, (void*)1, icuCaseFunc16},
-
- {"lower", 1, SQLITE_UTF8, 0, icuCaseFunc16},
- {"lower", 2, SQLITE_UTF8, 0, icuCaseFunc16},
- {"upper", 1, SQLITE_UTF8, (void*)1, icuCaseFunc16},
- {"upper", 2, SQLITE_UTF8, (void*)1, icuCaseFunc16},
-
- {"like", 2, SQLITE_UTF8, 0, icuLikeFunc},
- {"like", 3, SQLITE_UTF8, 0, icuLikeFunc},
-
- {"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation},
+ {"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
+ {"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
+ {"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
+ {"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
+ {"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
+ {"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
+ {"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
+ {"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
+ {"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
+ {"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
+ {"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
+ {"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
};
-
int rc = SQLITE_OK;
int i;
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
- struct IcuScalar *p = &scalars[i];
+ const struct IcuScalar *p = &scalars[i];
rc = sqlite3_create_function(
- db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0
+ db, p->zName, p->nArg, p->enc,
+ p->iContext ? (void*)db : (void*)0,
+ p->xFunc, 0, 0
);
}
@@ -165421,7 +194963,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
__declspec(dllexport)
#endif
SQLITE_API int sqlite3_icu_init(
- sqlite3 *db,
+ sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
@@ -165496,7 +195038,7 @@ static int icuCreate(
if( argc>0 ){
n = strlen(argv[0])+1;
}
- p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
+ p = (IcuTokenizer *)sqlite3_malloc64(sizeof(IcuTokenizer)+n);
if( !p ){
return SQLITE_NOMEM;
}
@@ -165524,7 +195066,7 @@ static int icuDestroy(sqlite3_tokenizer *pTokenizer){
/*
** Prepare to begin tokenizing a particular string. The input
** string to be tokenized is pInput[0..nBytes-1]. A cursor
-** used to incrementally tokenize this string is returned in
+** used to incrementally tokenize this string is returned in
** *ppCursor.
*/
static int icuOpen(
@@ -165553,7 +195095,7 @@ static int icuOpen(
nInput = strlen(zInput);
}
nChar = nInput+1;
- pCsr = (IcuCursor *)sqlite3_malloc(
+ pCsr = (IcuCursor *)sqlite3_malloc64(
sizeof(IcuCursor) + /* IcuCursor */
((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */
(nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */
@@ -165566,7 +195108,7 @@ static int icuOpen(
pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3];
pCsr->aOffset[iOut] = iInput;
- U8_NEXT(zInput, iInput, nInput, c);
+ U8_NEXT(zInput, iInput, nInput, c);
while( c>0 ){
int isError = 0;
c = u_foldCase(c, opt);
@@ -165712,7 +195254,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
*************************************************************************
**
**
-** OVERVIEW
+** OVERVIEW
**
** The RBU extension requires that the RBU update be packaged as an
** SQLite database. The tables it expects to find are described in
@@ -165720,34 +195262,34 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** that the user wishes to write to, a corresponding data_xyz table is
** created in the RBU database and populated with one row for each row to
** update, insert or delete from the target table.
-**
+**
** The update proceeds in three stages:
-**
+**
** 1) The database is updated. The modified database pages are written
** to a *-oal file. A *-oal file is just like a *-wal file, except
** that it is named "<database>-oal" instead of "<database>-wal".
** Because regular SQLite clients do not look for file named
** "<database>-oal", they go on using the original database in
** rollback mode while the *-oal file is being generated.
-**
+**
** During this stage RBU does not update the database by writing
** directly to the target tables. Instead it creates "imposter"
** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses
** to update each b-tree individually. All updates required by each
** b-tree are completed before moving on to the next, and all
** updates are done in sorted key order.
-**
+**
** 2) The "<database>-oal" file is moved to the equivalent "<database>-wal"
** location using a call to rename(2). Before doing this the RBU
** module takes an EXCLUSIVE lock on the database file, ensuring
** that there are no other active readers.
-**
+**
** Once the EXCLUSIVE lock is released, any other database readers
** detect the new *-wal file and read the database in wal mode. At
** this point they see the new version of the database - including
** the updates made as part of the RBU update.
-**
-** 3) The new *-wal file is checkpointed. This proceeds in the same way
+**
+** 3) The new *-wal file is checkpointed. This proceeds in the same way
** as a regular database checkpoint, except that a single frame is
** checkpointed each time sqlite3rbu_step() is called. If the RBU
** handle is closed before the entire *-wal file is checkpointed,
@@ -165756,7 +195298,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** the future.
**
** POTENTIAL PROBLEMS
-**
+**
** The rename() call might not be portable. And RBU is not currently
** syncing the directory after renaming the file.
**
@@ -165778,7 +195320,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** fields are collected. This means we're probably writing a lot more
** data to disk when saving the state of an ongoing update to the RBU
** update database than is strictly necessary.
-**
+**
*/
/* #include <assert.h> */
@@ -165802,42 +195344,42 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
**
*************************************************************************
**
-** This file contains the public interface for the RBU extension.
+** This file contains the public interface for the RBU extension.
*/
/*
** SUMMARY
**
-** Writing a transaction containing a large number of operations on
+** Writing a transaction containing a large number of operations on
** b-tree indexes that are collectively larger than the available cache
-** memory can be very inefficient.
+** memory can be very inefficient.
**
** The problem is that in order to update a b-tree, the leaf page (at least)
** containing the entry being inserted or deleted must be modified. If the
-** working set of leaves is larger than the available cache memory, then a
-** single leaf that is modified more than once as part of the transaction
+** working set of leaves is larger than the available cache memory, then a
+** single leaf that is modified more than once as part of the transaction
** may be loaded from or written to the persistent media multiple times.
** Additionally, because the index updates are likely to be applied in
-** random order, access to pages within the database is also likely to be in
+** random order, access to pages within the database is also likely to be in
** random order, which is itself quite inefficient.
**
** One way to improve the situation is to sort the operations on each index
** by index key before applying them to the b-tree. This leads to an IO
** pattern that resembles a single linear scan through the index b-tree,
-** and all but guarantees each modified leaf page is loaded and stored
+** and all but guarantees each modified leaf page is loaded and stored
** exactly once. SQLite uses this trick to improve the performance of
** CREATE INDEX commands. This extension allows it to be used to improve
** the performance of large transactions on existing databases.
**
-** Additionally, this extension allows the work involved in writing the
-** large transaction to be broken down into sub-transactions performed
-** sequentially by separate processes. This is useful if the system cannot
-** guarantee that a single update process will run for long enough to apply
-** the entire update, for example because the update is being applied on a
-** mobile device that is frequently rebooted. Even after the writer process
+** Additionally, this extension allows the work involved in writing the
+** large transaction to be broken down into sub-transactions performed
+** sequentially by separate processes. This is useful if the system cannot
+** guarantee that a single update process will run for long enough to apply
+** the entire update, for example because the update is being applied on a
+** mobile device that is frequently rebooted. Even after the writer process
** has committed one or more sub-transactions, other database clients continue
-** to read from the original database snapshot. In other words, partially
-** applied transactions are not visible to other clients.
+** to read from the original database snapshot. In other words, partially
+** applied transactions are not visible to other clients.
**
** "RBU" stands for "Resumable Bulk Update". As in a large database update
** transmitted via a wireless network to a mobile device. A transaction
@@ -165853,9 +195395,9 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
**
** * INSERT statements may not use any default values.
**
-** * UPDATE and DELETE statements must identify their target rows by
+** * UPDATE and DELETE statements must identify their target rows by
** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY
-** KEY fields may not be updated or deleted. If the table being written
+** KEY fields may not be updated or deleted. If the table being written
** has no PRIMARY KEY, affected rows must be identified by rowid.
**
** * UPDATE statements may not modify PRIMARY KEY columns.
@@ -165872,10 +195414,10 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** PREPARATION
**
** An "RBU update" is stored as a separate SQLite database. A database
-** containing an RBU update is an "RBU database". For each table in the
+** containing an RBU update is an "RBU database". For each table in the
** target database to be updated, the RBU database should contain a table
** named "data_<target name>" containing the same set of columns as the
-** target table, and one more - "rbu_control". The data_% table should
+** target table, and one more - "rbu_control". The data_% table should
** have no PRIMARY KEY or UNIQUE constraints, but each column should have
** the same type as the corresponding column in the target database.
** The "rbu_control" column should have no type at all. For example, if
@@ -165890,22 +195432,22 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** The order of the columns in the data_% table does not matter.
**
** Instead of a regular table, the RBU database may also contain virtual
-** tables or view named using the data_<target> naming scheme.
+** tables or view named using the data_<target> naming scheme.
**
-** Instead of the plain data_<target> naming scheme, RBU database tables
+** Instead of the plain data_<target> naming scheme, RBU database tables
** may also be named data<integer>_<target>, where <integer> is any sequence
** of zero or more numeric characters (0-9). This can be significant because
-** tables within the RBU database are always processed in order sorted by
+** tables within the RBU database are always processed in order sorted by
** name. By judicious selection of the <integer> portion of the names
** of the RBU tables the user can therefore control the order in which they
** are processed. This can be useful, for example, to ensure that "external
** content" FTS4 tables are updated before their underlying content tables.
**
** If the target database table is a virtual table or a table that has no
-** PRIMARY KEY declaration, the data_% table must also contain a column
-** named "rbu_rowid". This column is mapped to the tables implicit primary
-** key column - "rowid". Virtual tables for which the "rowid" column does
-** not function like a primary key value cannot be updated using RBU. For
+** PRIMARY KEY declaration, the data_% table must also contain a column
+** named "rbu_rowid". This column is mapped to the tables implicit primary
+** key column - "rowid". Virtual tables for which the "rowid" column does
+** not function like a primary key value cannot be updated using RBU. For
** example, if the target db contains either of the following:
**
** CREATE VIRTUAL TABLE x1 USING fts3(a, b);
@@ -165928,35 +195470,35 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control);
** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control);
**
-** For each row to INSERT into the target database as part of the RBU
+** For each row to INSERT into the target database as part of the RBU
** update, the corresponding data_% table should contain a single record
** with the "rbu_control" column set to contain integer value 0. The
-** other columns should be set to the values that make up the new record
-** to insert.
+** other columns should be set to the values that make up the new record
+** to insert.
**
-** If the target database table has an INTEGER PRIMARY KEY, it is not
-** possible to insert a NULL value into the IPK column. Attempting to
+** If the target database table has an INTEGER PRIMARY KEY, it is not
+** possible to insert a NULL value into the IPK column. Attempting to
** do so results in an SQLITE_MISMATCH error.
**
-** For each row to DELETE from the target database as part of the RBU
+** For each row to DELETE from the target database as part of the RBU
** update, the corresponding data_% table should contain a single record
** with the "rbu_control" column set to contain integer value 1. The
** real primary key values of the row to delete should be stored in the
** corresponding columns of the data_% table. The values stored in the
** other columns are not used.
**
-** For each row to UPDATE from the target database as part of the RBU
+** For each row to UPDATE from the target database as part of the RBU
** update, the corresponding data_% table should contain a single record
** with the "rbu_control" column set to contain a value of type text.
-** The real primary key values identifying the row to update should be
+** The real primary key values identifying the row to update should be
** stored in the corresponding columns of the data_% table row, as should
-** the new values of all columns being update. The text value in the
+** the new values of all columns being update. The text value in the
** "rbu_control" column must contain the same number of characters as
** there are columns in the target database table, and must consist entirely
-** of 'x' and '.' characters (or in some special cases 'd' - see below). For
+** of 'x' and '.' characters (or in some special cases 'd' - see below). For
** each column that is being updated, the corresponding character is set to
** 'x'. For those that remain as they are, the corresponding character of the
-** rbu_control value should be set to '.'. For example, given the tables
+** rbu_control value should be set to '.'. For example, given the tables
** above, the update statement:
**
** UPDATE t1 SET c = 'usa' WHERE a = 4;
@@ -165970,30 +195512,30 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** target table with the value stored in the corresponding data_% column, the
** user-defined SQL function "rbu_delta()" is invoked and the result stored in
** the target table column. rbu_delta() is invoked with two arguments - the
-** original value currently stored in the target table column and the
+** original value currently stored in the target table column and the
** value specified in the data_xxx table.
**
** For example, this row:
**
** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d');
**
-** is similar to an UPDATE statement such as:
+** is similar to an UPDATE statement such as:
**
** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4;
**
-** Finally, if an 'f' character appears in place of a 'd' or 's' in an
+** Finally, if an 'f' character appears in place of a 'd' or 's' in an
** ota_control string, the contents of the data_xxx table column is assumed
** to be a "fossil delta" - a patch to be applied to a blob value in the
** format used by the fossil source-code management system. In this case
-** the existing value within the target database table must be of type BLOB.
+** the existing value within the target database table must be of type BLOB.
** It is replaced by the result of applying the specified fossil delta to
** itself.
**
** If the target database table is a virtual table or a table with no PRIMARY
-** KEY, the rbu_control value should not include a character corresponding
+** KEY, the rbu_control value should not include a character corresponding
** to the rbu_rowid value. For example, this:
**
-** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control)
+** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control)
** VALUES(NULL, 'usa', 12, '.x');
**
** causes a result similar to:
@@ -166003,14 +195545,14 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** The data_xxx tables themselves should have no PRIMARY KEY declarations.
** However, RBU is more efficient if reading the rows in from each data_xxx
** table in "rowid" order is roughly the same as reading them sorted by
-** the PRIMARY KEY of the corresponding target database table. In other
-** words, rows should be sorted using the destination table PRIMARY KEY
+** the PRIMARY KEY of the corresponding target database table. In other
+** words, rows should be sorted using the destination table PRIMARY KEY
** fields before they are inserted into the data_xxx tables.
**
** USAGE
**
-** The API declared below allows an application to apply an RBU update
-** stored on disk to an existing target database. Essentially, the
+** The API declared below allows an application to apply an RBU update
+** stored on disk to an existing target database. Essentially, the
** application:
**
** 1) Opens an RBU handle using the sqlite3rbu_open() function.
@@ -166021,24 +195563,24 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
**
** 3) Calls the sqlite3rbu_step() function one or more times on
** the new handle. Each call to sqlite3rbu_step() performs a single
-** b-tree operation, so thousands of calls may be required to apply
+** b-tree operation, so thousands of calls may be required to apply
** a complete update.
**
** 4) Calls sqlite3rbu_close() to close the RBU update handle. If
** sqlite3rbu_step() has been called enough times to completely
** apply the update to the target database, then the RBU database
-** is marked as fully applied. Otherwise, the state of the RBU
-** update application is saved in the RBU database for later
+** is marked as fully applied. Otherwise, the state of the RBU
+** update application is saved in the RBU database for later
** resumption.
**
** See comments below for more detail on APIs.
**
** If an update is only partially applied to the target database by the
-** time sqlite3rbu_close() is called, various state information is saved
+** time sqlite3rbu_close() is called, various state information is saved
** within the RBU database. This allows subsequent processes to automatically
** resume the RBU update from where it left off.
**
-** To remove all RBU extension state information, returning an RBU database
+** To remove all RBU extension state information, returning an RBU database
** to its original contents, it is sufficient to drop all tables that begin
** with the prefix "rbu_"
**
@@ -166074,21 +195616,21 @@ typedef struct sqlite3rbu sqlite3rbu;
** the path to the RBU database. Each call to this function must be matched
** by a call to sqlite3rbu_close(). When opening the databases, RBU passes
** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget
-** or zRbu begin with "file:", it will be interpreted as an SQLite
+** or zRbu begin with "file:", it will be interpreted as an SQLite
** database URI, not a regular file name.
**
-** If the zState argument is passed a NULL value, the RBU extension stores
-** the current state of the update (how many rows have been updated, which
+** If the zState argument is passed a NULL value, the RBU extension stores
+** the current state of the update (how many rows have been updated, which
** indexes are yet to be updated etc.) within the RBU database itself. This
** can be convenient, as it means that the RBU application does not need to
-** organize removing a separate state file after the update is concluded.
-** Or, if zState is non-NULL, it must be a path to a database file in which
+** organize removing a separate state file after the update is concluded.
+** Or, if zState is non-NULL, it must be a path to a database file in which
** the RBU extension can store the state of the update.
**
** When resuming an RBU update, the zState argument must be passed the same
** value as when the RBU update was started.
**
-** Once the RBU update is finished, the RBU extension does not
+** Once the RBU update is finished, the RBU extension does not
** automatically remove any zState database file, even if it created it.
**
** By default, RBU uses the default VFS to access the files on disk. To
@@ -166101,7 +195643,7 @@ typedef struct sqlite3rbu sqlite3rbu;
** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
*/
SQLITE_API sqlite3rbu *sqlite3rbu_open(
- const char *zTarget,
+ const char *zTarget,
const char *zRbu,
const char *zState
);
@@ -166111,13 +195653,13 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
** that it can be suspended and resumed like an RBU update.
**
-** The second argument to this function identifies a database in which
-** to store the state of the RBU vacuum operation if it is suspended. The
+** The second argument to this function identifies a database in which
+** to store the state of the RBU vacuum operation if it is suspended. The
** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
** operation, the state database should either not exist or be empty
-** (contain no tables). If an RBU vacuum is suspended by calling
+** (contain no tables). If an RBU vacuum is suspended by calling
** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
-** returned SQLITE_DONE, the vacuum state is stored in the state database.
+** returned SQLITE_DONE, the vacuum state is stored in the state database.
** The vacuum can be resumed by calling this function to open a new RBU
** handle specifying the same target and state databases.
**
@@ -166127,25 +195669,51 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
** state database is not already present in the file-system, it is created
** with the same permissions as the target db is made.
**
+** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
+** state database ends with "-vactmp". This name is reserved for internal
+** use.
+**
** This function does not delete the state database after an RBU vacuum
** is completed, even if it created it. However, if the call to
** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
** of the state tables within the state database are zeroed. This way,
-** the next call to sqlite3rbu_vacuum() opens a handle that starts a
+** the next call to sqlite3rbu_vacuum() opens a handle that starts a
** new RBU vacuum operation.
**
** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
-** describing the sqlite3rbu_create_vfs() API function below for
-** a description of the complications associated with using RBU with
+** describing the sqlite3rbu_create_vfs() API function below for
+** a description of the complications associated with using RBU with
** zipvfs databases.
*/
SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
- const char *zTarget,
+ const char *zTarget,
const char *zState
);
/*
-** Internally, each RBU connection uses a separate SQLite database
+** Configure a limit for the amount of temp space that may be used by
+** the RBU handle passed as the first argument. The new limit is specified
+** in bytes by the second parameter. If it is positive, the limit is updated.
+** If the second parameter to this function is passed zero, then the limit
+** is removed entirely. If the second parameter is negative, the limit is
+** not modified (this is useful for querying the current limit).
+**
+** In all cases the returned value is the current limit in bytes (zero
+** indicates unlimited).
+**
+** If the temp space limit is exceeded during operation, an SQLITE_FULL
+** error is returned.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
+
+/*
+** Return the current amount of temp file space, in bytes, currently used by
+** the RBU handle passed as the only argument.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
+
+/*
+** Internally, each RBU connection uses a separate SQLite database
** connection to access the target and rbu update databases. This
** API allows the application direct access to these database handles.
**
@@ -166156,10 +195724,10 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
** following scenarios:
**
** * If any target tables are virtual tables, it may be necessary to
-** call sqlite3_create_module() on the target database handle to
+** call sqlite3_create_module() on the target database handle to
** register the required virtual table implementations.
**
-** * If the data_xxx tables in the RBU source database are virtual
+** * If the data_xxx tables in the RBU source database are virtual
** tables, the application may need to call sqlite3_create_module() on
** the rbu update db handle to any required virtual table
** implementations.
@@ -166178,12 +195746,12 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
/*
-** Do some work towards applying the RBU update to the target db.
+** Do some work towards applying the RBU update to the target db.
**
-** Return SQLITE_DONE if the update has been completely applied, or
+** Return SQLITE_DONE if the update has been completely applied, or
** SQLITE_OK if no error occurs but there remains work to do to apply
-** the RBU update. If an error does occur, some other error code is
-** returned.
+** the RBU update. If an error does occur, some other error code is
+** returned.
**
** Once a call to sqlite3rbu_step() has returned a value other than
** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
@@ -166196,7 +195764,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
**
** If a power failure or application crash occurs during an update, following
** system recovery RBU may resume the update from the point at which the state
-** was last saved. In other words, from the most recent successful call to
+** was last saved. In other words, from the most recent successful call to
** sqlite3rbu_close() or this function.
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
@@ -166204,7 +195772,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
/*
-** Close an RBU handle.
+** Close an RBU handle.
**
** If the RBU update has been completely applied, mark the RBU database
** as fully applied. Otherwise, assuming no error has occurred, save the
@@ -166212,26 +195780,26 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
**
** If an error has already occurred as part of an sqlite3rbu_step()
** or sqlite3rbu_open() call, or if one occurs within this function, an
-** SQLite error code is returned. Additionally, *pzErrmsg may be set to
-** point to a buffer containing a utf-8 formatted English language error
-** message. It is the responsibility of the caller to eventually free any
-** such buffer using sqlite3_free().
+** SQLite error code is returned. Additionally, if pzErrmsg is not NULL,
+** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted
+** English language error message. It is the responsibility of the caller to
+** eventually free any such buffer using sqlite3_free().
**
** Otherwise, if no error occurs, this function returns SQLITE_OK if the
-** update has been partially applied, or SQLITE_DONE if it has been
+** update has been partially applied, or SQLITE_DONE if it has been
** completely applied.
*/
SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
/*
-** Return the total number of key-value operations (inserts, deletes or
+** Return the total number of key-value operations (inserts, deletes or
** updates) that have been performed on the target database since the
** current RBU update was started.
*/
SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
/*
-** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
+** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
** progress indications for the two stages of an RBU update. This API may
** be useful for driving GUI progress indicators and similar.
**
@@ -166244,16 +195812,16 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
** The update is visible to non-RBU clients during stage 2. During stage 1
** non-RBU reader clients may see the original database.
**
-** If this API is called during stage 2 of the update, output variable
+** If this API is called during stage 2 of the update, output variable
** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
** to a value between 0 and 10000 to indicate the permyriadage progress of
-** stage 2. A value of 5000 indicates that stage 2 is half finished,
+** stage 2. A value of 5000 indicates that stage 2 is half finished,
** 9000 indicates that it is 90% finished, and so on.
**
-** If this API is called during stage 1 of the update, output variable
+** If this API is called during stage 1 of the update, output variable
** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
-** value to which (*pnOne) is set depends on whether or not the RBU
-** database contains an "rbu_count" table. The rbu_count table, if it
+** value to which (*pnOne) is set depends on whether or not the RBU
+** database contains an "rbu_count" table. The rbu_count table, if it
** exists, must contain the same columns as the following:
**
** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
@@ -166270,7 +195838,7 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
** table exists but is not correctly populated, the value of the *pnOne
** output variable during stage 1 is undefined.
*/
-SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
/*
** Obtain an indication as to the current stage of an RBU update or vacuum.
@@ -166312,20 +195880,20 @@ SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
/*
** Create an RBU VFS named zName that accesses the underlying file-system
-** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
+** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
** then the new RBU VFS uses the default system VFS to access the file-system.
-** The new object is registered as a non-default VFS with SQLite before
+** The new object is registered as a non-default VFS with SQLite before
** returning.
**
** Part of the RBU implementation uses a custom VFS object. Usually, this
-** object is created and deleted automatically by RBU.
+** object is created and deleted automatically by RBU.
**
** The exception is for applications that also use zipvfs. In this case,
** the custom VFS must be explicitly created by the user before the RBU
** handle is opened. The RBU VFS should be installed so that the zipvfs
-** VFS uses the RBU VFS, which in turn uses any other VFS layers in use
+** VFS uses the RBU VFS, which in turn uses any other VFS layers in use
** (for example multiplexor) to access the file-system. For example,
-** to assemble an RBU enabled VFS stack that uses both zipvfs and
+** to assemble an RBU enabled VFS stack that uses both zipvfs and
** multiplexor (error checking omitted):
**
** // Create a VFS named "multiplex" (not the default).
@@ -166347,9 +195915,9 @@ SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack
** that does not include the RBU layer results in an error.
**
-** The overhead of adding the "rbu" VFS to the system is negligible for
-** non-RBU users. There is no harm in an application accessing the
-** file-system via "rbu" all the time, even if it only uses RBU functionality
+** The overhead of adding the "rbu" VFS to the system is negligible for
+** non-RBU users. There is no harm in an application accessing the
+** file-system via "rbu" all the time, even if it only uses RBU functionality
** occasionally.
*/
SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
@@ -166380,6 +195948,13 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
/* Maximum number of prepared UPDATE statements held by this module */
#define SQLITE_RBU_UPDATE_CACHESIZE 16
+/* Delta checksums disabled by default. Compile with -DRBU_ENABLE_DELTA_CKSUM
+** to enable checksum verification.
+*/
+#ifndef RBU_ENABLE_DELTA_CKSUM
+# define RBU_ENABLE_DELTA_CKSUM 0
+#endif
+
/*
** Swap two objects of type TYPE.
*/
@@ -166395,17 +195970,17 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
** RBU_STATE_STAGE:
** May be set to integer values 1, 2, 4 or 5. As follows:
** 1: the *-rbu file is currently under construction.
-** 2: the *-rbu file has been constructed, but not yet moved
+** 2: the *-rbu file has been constructed, but not yet moved
** to the *-wal path.
** 4: the checkpoint is underway.
** 5: the rbu update has been checkpointed.
**
** RBU_STATE_TBL:
-** Only valid if STAGE==1. The target database name of the table
+** Only valid if STAGE==1. The target database name of the table
** currently being written.
**
** RBU_STATE_IDX:
-** Only valid if STAGE==1. The target database name of the index
+** Only valid if STAGE==1. The target database name of the index
** currently being written, or NULL if the main table is currently being
** updated.
**
@@ -166425,11 +196000,15 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
** be continued if this happens).
**
** RBU_STATE_COOKIE:
-** Valid if STAGE==1. The current change-counter cookie value in the
+** Valid if STAGE==1. The current change-counter cookie value in the
** target db file.
**
** RBU_STATE_OALSZ:
** Valid if STAGE==1. The size in bytes of the *-oal file.
+**
+** RBU_STATE_DATATBL:
+** Only valid if STAGE==1. The RBU database name of the table
+** currently being read.
*/
#define RBU_STATE_STAGE 1
#define RBU_STATE_TBL 2
@@ -166440,6 +196019,7 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
#define RBU_STATE_COOKIE 7
#define RBU_STATE_OALSZ 8
#define RBU_STATE_PHASEONESTEP 9
+#define RBU_STATE_DATATBL 10
#define RBU_STAGE_OAL 1
#define RBU_STAGE_MOVE 2
@@ -166454,6 +196034,7 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
typedef struct RbuFrame RbuFrame;
typedef struct RbuObjIter RbuObjIter;
typedef struct RbuState RbuState;
+typedef struct RbuSpan RbuSpan;
typedef struct rbu_vfs rbu_vfs;
typedef struct rbu_file rbu_file;
typedef struct RbuUpdateStmt RbuUpdateStmt;
@@ -166482,6 +196063,7 @@ typedef sqlite3_int64 i64;
struct RbuState {
int eStage;
char *zTbl;
+ char *zDataTbl;
char *zIdx;
i64 iWalCksum;
int nRow;
@@ -166497,12 +196079,17 @@ struct RbuUpdateStmt {
RbuUpdateStmt *pNext;
};
+struct RbuSpan {
+ const char *zSpan;
+ int nSpan;
+};
+
/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**
-** * the table itself,
+** * the table itself,
** * each index of the table (zero or more points to visit), and
** * a special "cleanup table" state.
**
@@ -166511,7 +196098,12 @@ struct RbuUpdateStmt {
** it points to an array of flags nTblCol elements in size. The flag is
** set for each column that is either a part of the PK or a part of an
** index. Or clear otherwise.
-**
+**
+** If there are one or more partial indexes on the table, all fields of
+** this array set set to 1. This is because in that case, the module has
+** no way to tell which fields will be required to add and remove entries
+** from the partial indexes.
+**
*/
struct RbuObjIter {
sqlite3_stmt *pTblIter; /* Iterate through tables */
@@ -166541,6 +196133,9 @@ struct RbuObjIter {
sqlite3_stmt *pInsert; /* Statement for INSERT operations */
sqlite3_stmt *pDelete; /* Statement for DELETE ops */
sqlite3_stmt *pTmpInsert; /* Insert into rbu_tmp_$zDataTbl */
+ int nIdxCol;
+ RbuSpan *aIdxCol;
+ char *zIdxSql;
/* Last UPDATE used (for PK b-tree updates only), or NULL. */
RbuUpdateStmt *pRbuUpdate;
@@ -166590,7 +196185,7 @@ struct RbuFrame {
**
** nPhaseOneStep:
** If the RBU database contains an rbu_count table, this value is set to
-** a running estimate of the number of b-tree operations required to
+** a running estimate of the number of b-tree operations required to
** finish populating the *-oal file. This allows the sqlite3_bp_progress()
** API to calculate the permyriadage progress of populating the *-oal file
** using the formula:
@@ -166610,7 +196205,7 @@ struct RbuFrame {
**
** * the RBU update contains any UPDATE operations. If the PK specified
** for an UPDATE operation does not exist in the target table, then
-** no b-tree operations are required on index b-trees. Or if the
+** no b-tree operations are required on index b-trees. Or if the
** specified PK does exist, then (nIndex*2) such operations are
** required (one delete and one insert on each index b-tree).
**
@@ -166640,6 +196235,7 @@ struct sqlite3rbu {
RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
const char *zVfsName; /* Name of automatically created rbu vfs */
rbu_file *pTargetFd; /* File handle open on target db */
+ int nPagePerSector; /* Pages per sector for pTargetFd */
i64 iOalSz;
i64 nPhaseOneStep;
@@ -166654,6 +196250,8 @@ struct sqlite3rbu {
int pgsz;
u8 *aBuf;
i64 iWalCksum;
+ i64 szTemp; /* Current size of all temp files in use */
+ i64 szTempLimit; /* Total size limit for temp files */
/* Used in RBU vacuum mode only */
int nRbu; /* Number of RBU VFS in the stack */
@@ -166662,23 +196260,34 @@ struct sqlite3rbu {
/*
** An rbu VFS is implemented using an instance of this structure.
+**
+** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
+** It is NULL for RBU VFS objects created explicitly using
+** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
+** space used by the RBU handle.
*/
struct rbu_vfs {
sqlite3_vfs base; /* rbu VFS shim methods */
sqlite3_vfs *pRealVfs; /* Underlying VFS */
sqlite3_mutex *mutex; /* Mutex to protect pMain */
- rbu_file *pMain; /* Linked list of main db files */
+ sqlite3rbu *pRbu; /* Owner RBU object */
+ rbu_file *pMain; /* List of main db files */
+ rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */
};
/*
** Each file opened by an rbu VFS is represented by an instance of
** the following structure.
+**
+** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
+** "sz" is set to the current size of the database file.
*/
struct rbu_file {
sqlite3_file base; /* sqlite3_file methods */
sqlite3_file *pReal; /* Underlying file handle */
rbu_vfs *pRbuVfs; /* Pointer to the rbu_vfs object */
sqlite3rbu *pRbu; /* Pointer to rbu object (rbu target only) */
+ i64 sz; /* Size of file in bytes (temp only) */
int openFlags; /* Flags this file was opened with */
u32 iCookie; /* Cookie value for main db files */
@@ -166692,6 +196301,7 @@ struct rbu_file {
const char *zWal; /* Wal filename for this main db file */
rbu_file *pWalFd; /* Wal file descriptor for this main db */
rbu_file *pMainNext; /* Next MAIN_DB file */
+ rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */
};
/*
@@ -166741,6 +196351,7 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
return v;
}
+#if RBU_ENABLE_DELTA_CKSUM
/*
** Compute a 32-bit checksum on the N-byte buffer. Return the result.
*/
@@ -166775,6 +196386,7 @@ static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
}
return sum3;
}
+#endif
/*
** Apply a delta.
@@ -166805,7 +196417,7 @@ static int rbuDeltaApply(
){
unsigned int limit;
unsigned int total = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+#if RBU_ENABLE_DELTA_CKSUM
char *zOrigOut = zOut;
#endif
@@ -166860,7 +196472,7 @@ static int rbuDeltaApply(
case ';': {
zDelta++; lenDelta--;
zOut[0] = 0;
-#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+#if RBU_ENABLE_DELTA_CKSUM
if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
/* ERROR: bad checksum */
return -1;
@@ -166938,6 +196550,7 @@ static void rbuFossilDeltaFunc(
}else{
nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut);
if( nOut2!=nOut ){
+ sqlite3_free(aOut);
sqlite3_result_error(context, "corrupt fossil delta", -1);
}else{
sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
@@ -166949,7 +196562,7 @@ static void rbuFossilDeltaFunc(
/*
** Prepare the SQL statement in buffer zSql against database handle db.
** If successful, set *ppStmt to point to the new statement and return
-** SQLITE_OK.
+** SQLITE_OK.
**
** Otherwise, if an error does occur, set *ppStmt to NULL and return
** an SQLite error code. Additionally, set output variable *pzErrmsg to
@@ -166957,7 +196570,7 @@ static void rbuFossilDeltaFunc(
** of the caller to (eventually) free this buffer using sqlite3_free().
*/
static int prepareAndCollectError(
- sqlite3 *db,
+ sqlite3 *db,
sqlite3_stmt **ppStmt,
char **pzErrmsg,
const char *zSql
@@ -166989,9 +196602,9 @@ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){
/*
** Unless it is NULL, argument zSql points to a buffer allocated using
** sqlite3_malloc containing an SQL statement. This function prepares the SQL
-** statement against database db and frees the buffer. If statement
-** compilation is successful, *ppStmt is set to point to the new statement
-** handle and SQLITE_OK is returned.
+** statement against database db and frees the buffer. If statement
+** compilation is successful, *ppStmt is set to point to the new statement
+** handle and SQLITE_OK is returned.
**
** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code
** returned. In this case, *pzErrmsg may also be set to point to an error
@@ -167002,7 +196615,7 @@ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){
** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL.
*/
static int prepareFreeAndCollectError(
- sqlite3 *db,
+ sqlite3 *db,
sqlite3_stmt **ppStmt,
char **pzErrmsg,
char *zSql
@@ -167057,13 +196670,18 @@ static void rbuObjIterClearStatements(RbuObjIter *pIter){
sqlite3_free(pUp);
pUp = pTmp;
}
-
+ sqlite3_free(pIter->aIdxCol);
+ sqlite3_free(pIter->zIdxSql);
+
pIter->pSelect = 0;
pIter->pInsert = 0;
pIter->pDelete = 0;
pIter->pRbuUpdate = 0;
pIter->pTmpInsert = 0;
pIter->nCol = 0;
+ pIter->nIdxCol = 0;
+ pIter->aIdxCol = 0;
+ pIter->zIdxSql = 0;
}
/*
@@ -167081,16 +196699,16 @@ static void rbuObjIterFinalize(RbuObjIter *pIter){
/*
** Advance the iterator to the next position.
**
-** If no error occurs, SQLITE_OK is returned and the iterator is left
-** pointing to the next entry. Otherwise, an error code and message is
-** left in the RBU handle passed as the first argument. A copy of the
+** If no error occurs, SQLITE_OK is returned and the iterator is left
+** pointing to the next entry. Otherwise, an error code and message is
+** left in the RBU handle passed as the first argument. A copy of the
** error code is returned.
*/
static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
int rc = p->rc;
if( rc==SQLITE_OK ){
- /* Free any SQLite statements used while processing the previous object */
+ /* Free any SQLite statements used while processing the previous object */
rbuObjIterClearStatements(pIter);
if( pIter->zIdx==0 ){
rc = sqlite3_exec(p->dbMain,
@@ -167149,7 +196767,7 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
** The implementation of the rbu_target_name() SQL function. This function
** accepts one or two arguments. The first argument is the name of a table -
** the name of a table in the RBU database. The second, if it is present, is 1
-** for a view or 0 for a table.
+** for a view or 0 for a table.
**
** For a non-vacuum RBU handle, if the table name matches the pattern:
**
@@ -167178,6 +196796,7 @@ static void rbuTargetNameFunc(
zIn = (const char*)sqlite3_value_text(argv[0]);
if( zIn ){
if( rbuIsVacuum(p) ){
+ assert( argc==2 || argc==1 );
if( argc==1 || 0==sqlite3_value_int(argv[1]) ){
sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC);
}
@@ -167196,19 +196815,19 @@ static void rbuTargetNameFunc(
/*
** Initialize the iterator structure passed as the second argument.
**
-** If no error occurs, SQLITE_OK is returned and the iterator is left
-** pointing to the first entry. Otherwise, an error code and message is
-** left in the RBU handle passed as the first argument. A copy of the
+** If no error occurs, SQLITE_OK is returned and the iterator is left
+** pointing to the first entry. Otherwise, an error code and message is
+** left in the RBU handle passed as the first argument. A copy of the
** error code is returned.
*/
static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
int rc;
memset(pIter, 0, sizeof(RbuObjIter));
- rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
+ rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
sqlite3_mprintf(
"SELECT rbu_target_name(name, type='view') AS target, name "
- "FROM sqlite_master "
+ "FROM sqlite_schema "
"WHERE type IN ('table', 'view') AND target IS NOT NULL "
" %s "
"ORDER BY name"
@@ -167217,7 +196836,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
"SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
- " FROM main.sqlite_master "
+ " FROM main.sqlite_schema "
" WHERE type='index' AND tbl_name = ?"
);
}
@@ -167233,7 +196852,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
**
** If an error has already occurred (p->rc is already set to something other
** than SQLITE_OK), then this function returns NULL without modifying the
-** stored error code. In this case it still calls sqlite3_free() on any
+** stored error code. In this case it still calls sqlite3_free() on any
** printf() parameters associated with %z conversions.
*/
static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){
@@ -167279,16 +196898,16 @@ static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){
}
/*
-** Attempt to allocate and return a pointer to a zeroed block of nByte
-** bytes.
+** Attempt to allocate and return a pointer to a zeroed block of nByte
+** bytes.
**
-** If an error (i.e. an OOM condition) occurs, return NULL and leave an
-** error code in the rbu handle passed as the first argument. Or, if an
-** error has already occurred when this function is called, return NULL
+** If an error (i.e. an OOM condition) occurs, return NULL and leave an
+** error code in the rbu handle passed as the first argument. Or, if an
+** error has already occurred when this function is called, return NULL
** immediately without attempting the allocation or modifying the stored
** error code.
*/
-static void *rbuMalloc(sqlite3rbu *p, int nByte){
+static void *rbuMalloc(sqlite3rbu *p, sqlite3_int64 nByte){
void *pRet = 0;
if( p->rc==SQLITE_OK ){
assert( nByte>0 );
@@ -167309,7 +196928,7 @@ static void *rbuMalloc(sqlite3rbu *p, int nByte){
** error code in the RBU handle passed as the first argument.
*/
static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){
- int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol;
+ sqlite3_int64 nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol;
char **azNew;
azNew = (char**)rbuMalloc(p, nByte);
@@ -167336,14 +196955,15 @@ static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){
static char *rbuStrndup(const char *zStr, int *pRc){
char *zRet = 0;
- assert( *pRc==SQLITE_OK );
- if( zStr ){
- size_t nCopy = strlen(zStr) + 1;
- zRet = (char*)sqlite3_malloc64(nCopy);
- if( zRet ){
- memcpy(zRet, zStr, nCopy);
- }else{
- *pRc = SQLITE_NOMEM;
+ if( *pRc==SQLITE_OK ){
+ if( zStr ){
+ size_t nCopy = strlen(zStr) + 1;
+ zRet = (char*)sqlite3_malloc64(nCopy);
+ if( zRet ){
+ memcpy(zRet, zStr, nCopy);
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
}
}
@@ -167380,7 +197000,7 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
** RBU_PK_VTAB: Table is a virtual table.
**
** Argument *piPk is also of type (int*), and also points to an output
-** parameter. Unless the table has an external primary key index
+** parameter. Unless the table has an external primary key index
** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or,
** if the table does have an external primary key index, then *piPk
** is set to the root page number of the primary key index before
@@ -167388,12 +197008,12 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
**
** ALGORITHM:
**
-** if( no entry exists in sqlite_master ){
+** if( no entry exists in sqlite_schema ){
** return RBU_PK_NOTABLE
** }else if( sql for the entry starts with "CREATE VIRTUAL" ){
** return RBU_PK_VTAB
** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){
-** if( the index that is the pk exists in sqlite_master ){
+** if( the index that is the pk exists in sqlite_schema ){
** *piPK = rootpage of that index.
** return RBU_PK_EXTERNAL
** }else{
@@ -167413,9 +197033,9 @@ static void rbuTableType(
int *piPk
){
/*
- ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
+ ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q)
** 1) PRAGMA index_list = ?
- ** 2) SELECT count(*) FROM sqlite_master where name=%Q
+ ** 2) SELECT count(*) FROM sqlite_schema where name=%Q
** 3) PRAGMA table_info = ?
*/
sqlite3_stmt *aStmt[4] = {0, 0, 0, 0};
@@ -167424,10 +197044,10 @@ static void rbuTableType(
*piPk = 0;
assert( p->rc==SQLITE_OK );
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
sqlite3_mprintf(
"SELECT (sql LIKE 'create virtual%%'), rootpage"
- " FROM sqlite_master"
+ " FROM sqlite_schema"
" WHERE name=%Q", zTab
));
if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
@@ -167440,7 +197060,7 @@ static void rbuTableType(
}
*piTnum = sqlite3_column_int(aStmt[0], 1);
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg,
sqlite3_mprintf("PRAGMA index_list=%Q",zTab)
);
if( p->rc ) goto rbuTableType_end;
@@ -167448,9 +197068,9 @@ static void rbuTableType(
const u8 *zOrig = sqlite3_column_text(aStmt[1], 3);
const u8 *zIdx = sqlite3_column_text(aStmt[1], 1);
if( zOrig && zIdx && zOrig[0]=='p' ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
sqlite3_mprintf(
- "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
+ "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx
));
if( p->rc==SQLITE_OK ){
if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
@@ -167464,7 +197084,7 @@ static void rbuTableType(
}
}
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg,
sqlite3_mprintf("PRAGMA table_info=%Q",zTab)
);
if( p->rc==SQLITE_OK ){
@@ -167503,14 +197123,21 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
pIter->nIndex = 0;
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
+ int bPartial = sqlite3_column_int(pList, 4);
sqlite3_stmt *pXInfo = 0;
if( zIdx==0 ) break;
+ if( bPartial ){
+ memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol);
+ }
p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
);
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
int iCid = sqlite3_column_int(pXInfo, 1);
if( iCid>=0 ) pIter->abIndexed[iCid] = 1;
+ if( iCid==-2 ){
+ memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol);
+ }
}
rbuFinalize(p, pXInfo);
bIndex = 1;
@@ -167533,7 +197160,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
** the table (not index) that the iterator currently points to.
**
** Return SQLITE_OK if successful, or an SQLite error code otherwise. If
-** an error does occur, an error code and error message are also left in
+** an error does occur, an error code and error message are also left in
** the RBU handle.
*/
static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
@@ -167555,7 +197182,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
if( p->rc ) return p->rc;
if( pIter->zIdx==0 ) pIter->iTnum = iTnum;
- assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK
+ assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK
|| pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID
|| pIter->eType==RBU_PK_VTAB
);
@@ -167563,7 +197190,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
/* Populate the azTblCol[] and nTblCol variables based on the columns
** of the input table. Ignore any input table columns that begin with
** "rbu_". */
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl)
);
if( p->rc==SQLITE_OK ){
@@ -167599,7 +197226,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
** present in the input table. Populate the abTblPk[], azTblType[] and
** aiTblOrder[] arrays at the same time. */
if( p->rc==SQLITE_OK ){
- p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl)
);
}
@@ -167625,7 +197252,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
}
pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc);
- pIter->abTblPk[iOrder] = (iPk!=0);
+ assert( iPk>=0 );
+ pIter->abTblPk[iOrder] = (u8)iPk;
pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
iOrder++;
}
@@ -167641,8 +197269,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
}
/*
-** This function constructs and returns a pointer to a nul-terminated
-** string containing some SQL clause or list based on one or more of the
+** This function constructs and returns a pointer to a nul-terminated
+** string containing some SQL clause or list based on one or more of the
** column names currently stored in the pIter->azTblCol[] array.
*/
static char *rbuObjIterGetCollist(
@@ -167661,23 +197289,230 @@ static char *rbuObjIterGetCollist(
}
/*
-** This function is used to create a SELECT list (the list of SQL
-** expressions that follows a SELECT keyword) for a SELECT statement
-** used to read from an data_xxx or rbu_tmp_xxx table while updating the
-** index object currently indicated by the iterator object passed as the
-** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used
+** Return a comma separated list of the quoted PRIMARY KEY column names,
+** in order, for the current table. Before each column name, add the text
+** zPre. After each column name, add the zPost text. Use zSeparator as
+** the separator text (usually ", ").
+*/
+static char *rbuObjIterGetPkList(
+ sqlite3rbu *p, /* RBU object */
+ RbuObjIter *pIter, /* Object iterator for column names */
+ const char *zPre, /* Before each quoted column name */
+ const char *zSeparator, /* Separator to use between columns */
+ const char *zPost /* After each quoted column name */
+){
+ int iPk = 1;
+ char *zRet = 0;
+ const char *zSep = "";
+ while( 1 ){
+ int i;
+ for(i=0; i<pIter->nTblCol; i++){
+ if( (int)pIter->abTblPk[i]==iPk ){
+ const char *zCol = pIter->azTblCol[i];
+ zRet = rbuMPrintf(p, "%z%s%s\"%w\"%s", zRet, zSep, zPre, zCol, zPost);
+ zSep = zSeparator;
+ break;
+ }
+ }
+ if( i==pIter->nTblCol ) break;
+ iPk++;
+ }
+ return zRet;
+}
+
+/*
+** This function is called as part of restarting an RBU vacuum within
+** stage 1 of the process (while the *-oal file is being built) while
+** updating a table (not an index). The table may be a rowid table or
+** a WITHOUT ROWID table. It queries the target database to find the
+** largest key that has already been written to the target table and
+** constructs a WHERE clause that can be used to extract the remaining
+** rows from the source table. For a rowid table, the WHERE clause
+** is of the form:
+**
+** "WHERE _rowid_ > ?"
+**
+** and for WITHOUT ROWID tables:
+**
+** "WHERE (key1, key2) > (?, ?)"
+**
+** Instead of "?" placeholders, the actual WHERE clauses created by
+** this function contain literal SQL values.
+*/
+static char *rbuVacuumTableStart(
+ sqlite3rbu *p, /* RBU handle */
+ RbuObjIter *pIter, /* RBU iterator object */
+ int bRowid, /* True for a rowid table */
+ const char *zWrite /* Target table name prefix */
+){
+ sqlite3_stmt *pMax = 0;
+ char *zRet = 0;
+ if( bRowid ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg,
+ sqlite3_mprintf(
+ "SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl
+ )
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){
+ sqlite3_int64 iMax = sqlite3_column_int64(pMax, 0);
+ zRet = rbuMPrintf(p, " WHERE _rowid_ > %lld ", iMax);
+ }
+ rbuFinalize(p, pMax);
+ }else{
+ char *zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", " DESC");
+ char *zSelect = rbuObjIterGetPkList(p, pIter, "quote(", "||','||", ")");
+ char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", "");
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg,
+ sqlite3_mprintf(
+ "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1",
+ zSelect, zWrite, pIter->zTbl, zOrder
+ )
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pMax) ){
+ const char *zVal = (const char*)sqlite3_column_text(pMax, 0);
+ zRet = rbuMPrintf(p, " WHERE (%s) > (%s) ", zList, zVal);
+ }
+ rbuFinalize(p, pMax);
+ }
+
+ sqlite3_free(zOrder);
+ sqlite3_free(zSelect);
+ sqlite3_free(zList);
+ }
+ return zRet;
+}
+
+/*
+** This function is called as part of restating an RBU vacuum when the
+** current operation is writing content to an index. If possible, it
+** queries the target index b-tree for the largest key already written to
+** it, then composes and returns an expression that can be used in a WHERE
+** clause to select the remaining required rows from the source table.
+** It is only possible to return such an expression if:
+**
+** * The index contains no DESC columns, and
+** * The last key written to the index before the operation was
+** suspended does not contain any NULL values.
+**
+** The expression is of the form:
+**
+** (index-field1, index-field2, ...) > (?, ?, ...)
+**
+** except that the "?" placeholders are replaced with literal values.
+**
+** If the expression cannot be created, NULL is returned. In this case,
+** the caller has to use an OFFSET clause to extract only the required
+** rows from the sourct table, just as it does for an RBU update operation.
+*/
+char *rbuVacuumIndexStart(
+ sqlite3rbu *p, /* RBU handle */
+ RbuObjIter *pIter /* RBU iterator object */
+){
+ char *zOrder = 0;
+ char *zLhs = 0;
+ char *zSelect = 0;
+ char *zVector = 0;
+ char *zRet = 0;
+ int bFailed = 0;
+ const char *zSep = "";
+ int iCol = 0;
+ sqlite3_stmt *pXInfo = 0;
+
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx)
+ );
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
+ int iCid = sqlite3_column_int(pXInfo, 1);
+ const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
+ const char *zCol;
+ if( sqlite3_column_int(pXInfo, 3) ){
+ bFailed = 1;
+ break;
+ }
+
+ if( iCid<0 ){
+ if( pIter->eType==RBU_PK_IPK ){
+ int i;
+ for(i=0; pIter->abTblPk[i]==0; i++);
+ assert( i<pIter->nTblCol );
+ zCol = pIter->azTblCol[i];
+ }else{
+ zCol = "_rowid_";
+ }
+ }else{
+ zCol = pIter->azTblCol[iCid];
+ }
+
+ zLhs = rbuMPrintf(p, "%z%s \"%w\" COLLATE %Q",
+ zLhs, zSep, zCol, zCollate
+ );
+ zOrder = rbuMPrintf(p, "%z%s \"rbu_imp_%d%w\" COLLATE %Q DESC",
+ zOrder, zSep, iCol, zCol, zCollate
+ );
+ zSelect = rbuMPrintf(p, "%z%s quote(\"rbu_imp_%d%w\")",
+ zSelect, zSep, iCol, zCol
+ );
+ zSep = ", ";
+ iCol++;
+ }
+ rbuFinalize(p, pXInfo);
+ if( bFailed ) goto index_start_out;
+
+ if( p->rc==SQLITE_OK ){
+ sqlite3_stmt *pSel = 0;
+
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pSel, &p->zErrmsg,
+ sqlite3_mprintf("SELECT %s FROM \"rbu_imp_%w\" ORDER BY %s LIMIT 1",
+ zSelect, pIter->zTbl, zOrder
+ )
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSel) ){
+ zSep = "";
+ for(iCol=0; iCol<pIter->nCol; iCol++){
+ const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol);
+ if( zQuoted[0]=='N' ){
+ bFailed = 1;
+ break;
+ }
+ zVector = rbuMPrintf(p, "%z%s%s", zVector, zSep, zQuoted);
+ zSep = ", ";
+ }
+
+ if( !bFailed ){
+ zRet = rbuMPrintf(p, "(%s) > (%s)", zLhs, zVector);
+ }
+ }
+ rbuFinalize(p, pSel);
+ }
+
+ index_start_out:
+ sqlite3_free(zOrder);
+ sqlite3_free(zSelect);
+ sqlite3_free(zVector);
+ sqlite3_free(zLhs);
+ return zRet;
+}
+
+/*
+** This function is used to create a SELECT list (the list of SQL
+** expressions that follows a SELECT keyword) for a SELECT statement
+** used to read from an data_xxx or rbu_tmp_xxx table while updating the
+** index object currently indicated by the iterator object passed as the
+** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used
** to obtain the required information.
**
** If the index is of the following form:
**
** CREATE INDEX i1 ON t1(c, b COLLATE nocase);
**
-** and "t1" is a table with an explicit INTEGER PRIMARY KEY column
+** and "t1" is a table with an explicit INTEGER PRIMARY KEY column
** "ipk", the returned string is:
**
** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'"
**
-** As well as the returned string, three other malloc'd strings are
+** As well as the returned string, three other malloc'd strings are
** returned via output parameters. As follows:
**
** pzImposterCols: ...
@@ -167714,36 +197549,44 @@ static char *rbuObjIterGetIndexCols(
int iCid = sqlite3_column_int(pXInfo, 1);
int bDesc = sqlite3_column_int(pXInfo, 3);
const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
- const char *zCol;
+ const char *zCol = 0;
const char *zType;
- if( iCid<0 ){
- /* An integer primary key. If the table has an explicit IPK, use
- ** its name. Otherwise, use "rbu_rowid". */
- if( pIter->eType==RBU_PK_IPK ){
- int i;
- for(i=0; pIter->abTblPk[i]==0; i++);
- assert( i<pIter->nTblCol );
- zCol = pIter->azTblCol[i];
- }else if( rbuIsVacuum(p) ){
- zCol = "_rowid_";
+ if( iCid==-2 ){
+ int iSeq = sqlite3_column_int(pXInfo, 0);
+ zRet = sqlite3_mprintf("%z%s(%.*s) COLLATE %Q", zRet, zCom,
+ pIter->aIdxCol[iSeq].nSpan, pIter->aIdxCol[iSeq].zSpan, zCollate
+ );
+ zType = "";
+ }else {
+ if( iCid<0 ){
+ /* An integer primary key. If the table has an explicit IPK, use
+ ** its name. Otherwise, use "rbu_rowid". */
+ if( pIter->eType==RBU_PK_IPK ){
+ int i;
+ for(i=0; pIter->abTblPk[i]==0; i++);
+ assert( i<pIter->nTblCol );
+ zCol = pIter->azTblCol[i];
+ }else if( rbuIsVacuum(p) ){
+ zCol = "_rowid_";
+ }else{
+ zCol = "rbu_rowid";
+ }
+ zType = "INTEGER";
}else{
- zCol = "rbu_rowid";
+ zCol = pIter->azTblCol[iCid];
+ zType = pIter->azTblType[iCid];
}
- zType = "INTEGER";
- }else{
- zCol = pIter->azTblCol[iCid];
- zType = pIter->azTblType[iCid];
+ zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom,zCol,zCollate);
}
- zRet = sqlite3_mprintf("%z%s\"%w\" COLLATE %Q", zRet, zCom, zCol, zCollate);
if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){
const char *zOrder = (bDesc ? " DESC" : "");
- zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s",
+ zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s",
zImpPK, zCom, nBind, zCol, zOrder
);
}
- zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q",
+ zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q",
zImpCols, zCom, nBind, zCol, zType, zCollate
);
zWhere = sqlite3_mprintf(
@@ -167789,7 +197632,7 @@ static char *rbuObjIterGetIndexCols(
** the text ", old._rowid_" to the returned value.
*/
static char *rbuObjIterGetOldlist(
- sqlite3rbu *p,
+ sqlite3rbu *p,
RbuObjIter *pIter,
const char *zObj
){
@@ -167830,7 +197673,7 @@ static char *rbuObjIterGetOldlist(
** "b = ?1 AND c = ?2"
*/
static char *rbuObjIterGetWhere(
- sqlite3rbu *p,
+ sqlite3rbu *p,
RbuObjIter *pIter
){
char *zList = 0;
@@ -167845,7 +197688,7 @@ static char *rbuObjIterGetWhere(
zSep = " AND ";
}
}
- zList = rbuMPrintf(p,
+ zList = rbuMPrintf(p,
"_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList
);
@@ -167885,7 +197728,7 @@ static void rbuBadControlError(sqlite3rbu *p){
**
** The memory for the returned string is obtained from sqlite3_malloc().
** It is the responsibility of the caller to eventually free it using
-** sqlite3_free().
+** sqlite3_free().
**
** If an OOM error is encountered when allocating space for the new
** string, an error code is left in the rbu handle passed as the first
@@ -167909,19 +197752,19 @@ static char *rbuObjIterGetSetlist(
for(i=0; i<pIter->nTblCol; i++){
char c = zMask[pIter->aiSrcOrder[i]];
if( c=='x' ){
- zList = rbuMPrintf(p, "%z%s\"%w\"=?%d",
+ zList = rbuMPrintf(p, "%z%s\"%w\"=?%d",
zList, zSep, pIter->azTblCol[i], i+1
);
zSep = ", ";
}
else if( c=='d' ){
- zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)",
+ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)",
zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
);
zSep = ", ";
}
else if( c=='f' ){
- zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)",
+ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)",
zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
);
zSep = ", ";
@@ -167939,7 +197782,7 @@ static char *rbuObjIterGetSetlist(
**
** The memory for the returned string is obtained from sqlite3_malloc().
** It is the responsibility of the caller to eventually free it using
-** sqlite3_free().
+** sqlite3_free().
**
** If an OOM error is encountered when allocating space for the new
** string, an error code is left in the rbu handle passed as the first
@@ -167949,7 +197792,7 @@ static char *rbuObjIterGetSetlist(
*/
static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){
char *zRet = 0;
- int nByte = nBind*2 + 1;
+ sqlite3_int64 nByte = 2*(sqlite3_int64)nBind + 1;
zRet = (char*)rbuMalloc(p, nByte);
if( zRet ){
@@ -167963,8 +197806,8 @@ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){
}
/*
-** The iterator currently points to a table (not index) of type
-** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY
+** The iterator currently points to a table (not index) of type
+** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY
** declaration for the corresponding imposter table. For example,
** if the iterator points to a table created as:
**
@@ -167981,7 +197824,7 @@ static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
const char *zSep = "PRIMARY KEY(";
sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */
sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */
-
+
p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg,
sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
);
@@ -168019,7 +197862,7 @@ static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
** a table b-tree where the table has an external primary key. If the
** iterator passed as the second argument does not currently point to
** a table (not index) with an external primary key, this function is a
-** no-op.
+** no-op.
**
** Assuming the iterator does point to a table with an external PK, this
** function creates a WITHOUT ROWID imposter table named "rbu_imposter2"
@@ -168046,8 +197889,8 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
/* Figure out the name of the primary key index for the current table.
** This is needed for the argument to "PRAGMA index_xinfo". Set
** zIdx to point to a nul-terminated string containing this name. */
- p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
- "SELECT name FROM sqlite_master WHERE rootpage = ?"
+ p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
+ "SELECT name FROM sqlite_schema WHERE rootpage = ?"
);
if( p->rc==SQLITE_OK ){
sqlite3_bind_int(pQuery, 1, tnum);
@@ -168068,7 +197911,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
int iCid = sqlite3_column_int(pXInfo, 1);
int bDesc = sqlite3_column_int(pXInfo, 3);
const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
- zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma,
+ zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma,
iCid, pIter->azTblType[iCid], zCollate
);
zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":"");
@@ -168080,7 +197923,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
rbuMPrintfExec(p, p->dbMain,
- "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
+ "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
zCols, zPk
);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
@@ -168088,7 +197931,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
}
/*
-** If an error has already occurred when this function is called, it
+** If an error has already occurred when this function is called, it
** immediately returns zero (without doing any work). Or, if an error
** occurs during the execution of this function, it sets the error code
** in the sqlite3rbu object indicated by the first argument and returns
@@ -168101,9 +197944,9 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
** an imposter table are created, or zero otherwise.
**
** An imposter table is required in all cases except RBU_PK_VTAB. Only
-** virtual tables are written to directly. The imposter table has the
-** same schema as the actual target table (less any UNIQUE constraints).
-** More precisely, the "same schema" means the same columns, types,
+** virtual tables are written to directly. The imposter table has the
+** same schema as the actual target table (less any UNIQUE constraints).
+** More precisely, the "same schema" means the same columns, types,
** collation sequences. For tables that do not have an external PRIMARY
** KEY, it also means the same PRIMARY KEY declaration.
*/
@@ -168129,7 +197972,7 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
** "PRIMARY KEY" to the imposter table column declaration. */
zPk = "PRIMARY KEY ";
}
- zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s",
+ zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s",
zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
(pIter->abNotNull[iCol] ? " NOT NULL" : "")
);
@@ -168144,8 +197987,8 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
}
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
- rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s",
- pIter->zTbl, zSql,
+ rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s",
+ pIter->zTbl, zSql,
(pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "")
);
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
@@ -168159,12 +198002,12 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...);
**
** The number of bound variables is equal to the number of columns in
-** the target table, plus one (for the rbu_control column), plus one more
-** (for the rbu_rowid column) if the target table is an implicit IPK or
+** the target table, plus one (for the rbu_control column), plus one more
+** (for the rbu_rowid column) if the target table is an implicit IPK or
** virtual table.
*/
static void rbuObjIterPrepareTmpInsert(
- sqlite3rbu *p,
+ sqlite3rbu *p,
RbuObjIter *pIter,
const char *zCollist,
const char *zRbuRowid
@@ -168175,14 +198018,14 @@ static void rbuObjIterPrepareTmpInsert(
assert( pIter->pTmpInsert==0 );
p->rc = prepareFreeAndCollectError(
p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf(
- "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)",
+ "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)",
p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind
));
}
}
static void rbuTmpInsertFunc(
- sqlite3_context *pCtx,
+ sqlite3_context *pCtx,
int nVal,
sqlite3_value **apVal
){
@@ -168191,8 +198034,8 @@ static void rbuTmpInsertFunc(
int i;
assert( sqlite3_value_int(apVal[0])!=0
- || p->objiter.eType==RBU_PK_EXTERNAL
- || p->objiter.eType==RBU_PK_NONE
+ || p->objiter.eType==RBU_PK_EXTERNAL
+ || p->objiter.eType==RBU_PK_NONE
);
if( sqlite3_value_int(apVal[0])!=0 ){
p->nPhaseOneStep += p->objiter.nIndex;
@@ -168211,13 +198054,108 @@ static void rbuTmpInsertFunc(
}
}
+static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
+ sqlite3_stmt *pStmt = 0;
+ int rc = p->rc;
+ char *zRet = 0;
+
+ assert( pIter->zIdxSql==0 && pIter->nIdxCol==0 && pIter->aIdxCol==0 );
+
+ if( rc==SQLITE_OK ){
+ rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
+ "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?"
+ );
+ }
+ if( rc==SQLITE_OK ){
+ int rc2;
+ rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC);
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ char *zSql = (char*)sqlite3_column_text(pStmt, 0);
+ if( zSql ){
+ pIter->zIdxSql = zSql = rbuStrndup(zSql, &rc);
+ }
+ if( zSql ){
+ int nParen = 0; /* Number of open parenthesis */
+ int i;
+ int iIdxCol = 0;
+ int nIdxAlloc = 0;
+ for(i=0; zSql[i]; i++){
+ char c = zSql[i];
+
+ /* If necessary, grow the pIter->aIdxCol[] array */
+ if( iIdxCol==nIdxAlloc ){
+ RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc(
+ pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan)
+ );
+ if( aIdxCol==0 ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ pIter->aIdxCol = aIdxCol;
+ nIdxAlloc += 16;
+ }
+
+ if( c=='(' ){
+ if( nParen==0 ){
+ assert( iIdxCol==0 );
+ pIter->aIdxCol[0].zSpan = &zSql[i+1];
+ }
+ nParen++;
+ }
+ else if( c==')' ){
+ nParen--;
+ if( nParen==0 ){
+ int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
+ pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
+ i++;
+ break;
+ }
+ }else if( c==',' && nParen==1 ){
+ int nSpan = &zSql[i] - pIter->aIdxCol[iIdxCol].zSpan;
+ pIter->aIdxCol[iIdxCol++].nSpan = nSpan;
+ pIter->aIdxCol[iIdxCol].zSpan = &zSql[i+1];
+ }else if( c=='"' || c=='\'' || c=='`' ){
+ for(i++; 1; i++){
+ if( zSql[i]==c ){
+ if( zSql[i+1]!=c ) break;
+ i++;
+ }
+ }
+ }else if( c=='[' ){
+ for(i++; 1; i++){
+ if( zSql[i]==']' ) break;
+ }
+ }else if( c=='-' && zSql[i+1]=='-' ){
+ for(i=i+2; zSql[i] && zSql[i]!='\n'; i++);
+ if( zSql[i]=='\0' ) break;
+ }else if( c=='/' && zSql[i+1]=='*' ){
+ for(i=i+2; zSql[i] && (zSql[i]!='*' || zSql[i+1]!='/'); i++);
+ if( zSql[i]=='\0' ) break;
+ i++;
+ }
+ }
+ if( zSql[i] ){
+ zRet = rbuStrndup(&zSql[i], &rc);
+ }
+ pIter->nIdxCol = iIdxCol;
+ }
+ }
+
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+
+ p->rc = rc;
+ return zRet;
+}
+
/*
-** Ensure that the SQLite statement handles required to update the
-** target database object currently indicated by the iterator passed
+** Ensure that the SQLite statement handles required to update the
+** target database object currently indicated by the iterator passed
** as the second argument are available.
*/
static int rbuObjIterPrepareAll(
- sqlite3rbu *p,
+ sqlite3rbu *p,
RbuObjIter *pIter,
int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */
){
@@ -168240,9 +198178,11 @@ static int rbuObjIterPrepareAll(
char *zImposterPK = 0; /* Primary key declaration for imposter */
char *zWhere = 0; /* WHERE clause on PK columns */
char *zBind = 0;
+ char *zPart = 0;
int nBind = 0;
assert( pIter->eType!=RBU_PK_VTAB );
+ zPart = rbuObjIterGetIndexWhere(p, pIter);
zCollist = rbuObjIterGetIndexCols(
p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
);
@@ -168278,39 +198218,58 @@ static int rbuObjIterPrepareAll(
if( p->rc==SQLITE_OK ){
char *zSql;
if( rbuIsVacuum(p) ){
+ char *zStart = 0;
+ if( nOffset ){
+ zStart = rbuVacuumIndexStart(p, pIter);
+ if( zStart ){
+ sqlite3_free(zLimit);
+ zLimit = 0;
+ }
+ }
+
zSql = sqlite3_mprintf(
- "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
- zCollist,
+ "SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s",
+ zCollist,
pIter->zDataTbl,
+ zPart,
+ (zStart ? (zPart ? "AND" : "WHERE") : ""), zStart,
zCollist, zLimit
);
+ sqlite3_free(zStart);
}else
if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
zSql = sqlite3_mprintf(
- "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
+ "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s",
zCollist, p->zStateDb, pIter->zDataTbl,
- zCollist, zLimit
+ zPart, zCollist, zLimit
);
}else{
zSql = sqlite3_mprintf(
- "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
+ "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s "
"UNION ALL "
"SELECT %s, rbu_control FROM '%q' "
- "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
+ "%s %s typeof(rbu_control)='integer' AND rbu_control!=1 "
"ORDER BY %s%s",
- zCollist, p->zStateDb, pIter->zDataTbl,
- zCollist, pIter->zDataTbl,
+ zCollist, p->zStateDb, pIter->zDataTbl, zPart,
+ zCollist, pIter->zDataTbl,
+ zPart,
+ (zPart ? "AND" : "WHERE"),
zCollist, zLimit
);
}
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql);
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(p->dbRbu,&pIter->pSelect,pz,zSql);
+ }else{
+ sqlite3_free(zSql);
+ }
}
sqlite3_free(zImposterCols);
sqlite3_free(zImposterPK);
sqlite3_free(zWhere);
sqlite3_free(zBind);
+ sqlite3_free(zPart);
}else{
int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
||(pIter->eType==RBU_PK_NONE)
@@ -168335,7 +198294,7 @@ static int rbuObjIterPrepareAll(
if( p->rc==SQLITE_OK ){
p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz,
sqlite3_mprintf(
- "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)",
+ "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)",
zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings
)
);
@@ -168403,18 +198362,42 @@ static int rbuObjIterPrepareAll(
/* Create the SELECT statement to read keys from data_xxx */
if( p->rc==SQLITE_OK ){
const char *zRbuRowid = "";
+ char *zStart = 0;
+ char *zOrder = 0;
if( bRbuRowid ){
zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid";
}
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
- sqlite3_mprintf(
- "SELECT %s,%s rbu_control%s FROM '%q'%s",
- zCollist,
- (rbuIsVacuum(p) ? "0 AS " : ""),
- zRbuRowid,
- pIter->zDataTbl, zLimit
- )
- );
+
+ if( rbuIsVacuum(p) ){
+ if( nOffset ){
+ zStart = rbuVacuumTableStart(p, pIter, bRbuRowid, zWrite);
+ if( zStart ){
+ sqlite3_free(zLimit);
+ zLimit = 0;
+ }
+ }
+ if( bRbuRowid ){
+ zOrder = rbuMPrintf(p, "_rowid_");
+ }else{
+ zOrder = rbuObjIterGetPkList(p, pIter, "", ", ", "");
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
+ sqlite3_mprintf(
+ "SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s",
+ zCollist,
+ (rbuIsVacuum(p) ? "0 AS " : ""),
+ zRbuRowid,
+ pIter->zDataTbl, (zStart ? zStart : ""),
+ (zOrder ? "ORDER BY" : ""), zOrder,
+ zLimit
+ )
+ );
+ }
+ sqlite3_free(zStart);
+ sqlite3_free(zOrder);
}
sqlite3_free(zWhere);
@@ -168425,16 +198408,16 @@ static int rbuObjIterPrepareAll(
sqlite3_free(zCollist);
sqlite3_free(zLimit);
}
-
+
return p->rc;
}
/*
** Set output variable *ppStmt to point to an UPDATE statement that may
** be used to update the imposter table for the main table b-tree of the
-** table object that pIter currently points to, assuming that the
+** table object that pIter currently points to, assuming that the
** rbu_control column of the data_xyz table contains zMask.
-**
+**
** If the zMask string does not specify any columns to update, then this
** is not an error. Output variable *ppStmt is set to NULL in this case.
*/
@@ -168461,7 +198444,7 @@ static int rbuGetUpdateStmt(
*pp = pUp->pNext;
pUp->pNext = pIter->pRbuUpdate;
pIter->pRbuUpdate = pUp;
- *ppStmt = pUp->pUpdate;
+ *ppStmt = pUp->pUpdate;
return SQLITE_OK;
}
nUp++;
@@ -168491,7 +198474,7 @@ static int rbuGetUpdateStmt(
const char *zPrefix = "";
if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_";
- zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s",
+ zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s",
zPrefix, pIter->zTbl, zSet, zWhere
);
p->rc = prepareFreeAndCollectError(
@@ -168507,8 +198490,8 @@ static int rbuGetUpdateStmt(
}
static sqlite3 *rbuOpenDbhandle(
- sqlite3rbu *p,
- const char *zName,
+ sqlite3rbu *p,
+ const char *zName,
int bUseVfs
){
sqlite3 *db = 0;
@@ -168530,14 +198513,15 @@ static sqlite3 *rbuOpenDbhandle(
static void rbuFreeState(RbuState *p){
if( p ){
sqlite3_free(p->zTbl);
+ sqlite3_free(p->zDataTbl);
sqlite3_free(p->zIdx);
sqlite3_free(p);
}
}
/*
-** Allocate an RbuState object and load the contents of the rbu_state
-** table into it. Return a pointer to the new object. It is the
+** Allocate an RbuState object and load the contents of the rbu_state
+** table into it. Return a pointer to the new object. It is the
** responsibility of the caller to eventually free the object using
** sqlite3_free().
**
@@ -168553,7 +198537,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
if( pRet==0 ) return 0;
- rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
@@ -168600,6 +198584,10 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
break;
+ case RBU_STATE_DATATBL:
+ pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+ break;
+
default:
rc = SQLITE_CORRUPT;
break;
@@ -168617,7 +198605,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
** Open the database handle and attach the RBU database as "rbu". If an
** error occurs, leave an error code and message in the RBU handle.
*/
-static void rbuOpenDatabase(sqlite3rbu *p){
+static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
@@ -168657,9 +198645,9 @@ static void rbuOpenDatabase(sqlite3rbu *p){
int bOk = 0;
sqlite3_stmt *pCnt = 0;
p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
- "SELECT count(*) FROM stat.sqlite_master"
+ "SELECT count(*) FROM stat.sqlite_schema"
);
- if( p->rc==SQLITE_OK
+ if( p->rc==SQLITE_OK
&& sqlite3_step(pCnt)==SQLITE_ROW
&& 1==sqlite3_column_int(pCnt, 0)
){
@@ -168672,7 +198660,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){
p->rc = SQLITE_ERROR;
p->zErrmsg = sqlite3_mprintf("invalid state database");
}
-
+
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
}
@@ -168692,7 +198680,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){
}else{
RbuState *pState = rbuLoadState(p);
if( pState ){
- bOpen = (pState->eStage>RBU_STAGE_MOVE);
+ bOpen = (pState->eStage>=RBU_STAGE_MOVE);
rbuFreeState(pState);
}
}
@@ -168704,6 +198692,15 @@ static void rbuOpenDatabase(sqlite3rbu *p){
if( !rbuIsVacuum(p) ){
p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
}else if( p->pRbuFd->pWalFd ){
+ if( pbRetry ){
+ p->pRbuFd->bNolock = 0;
+ sqlite3_close(p->dbRbu);
+ sqlite3_close(p->dbMain);
+ p->dbMain = 0;
+ p->dbRbu = 0;
+ *pbRetry = 1;
+ return;
+ }
p->rc = SQLITE_ERROR;
p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
}else{
@@ -168717,7 +198714,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){
if( *zExtra=='\0' ) zExtra = 0;
}
- zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s",
+ zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
sqlite3_db_filename(p->dbRbu, "main"),
(zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
);
@@ -168732,19 +198729,19 @@ static void rbuOpenDatabase(sqlite3rbu *p){
}
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_create_function(p->dbMain,
+ p->rc = sqlite3_create_function(p->dbMain,
"rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
);
}
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_create_function(p->dbMain,
+ p->rc = sqlite3_create_function(p->dbMain,
"rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0
);
}
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_create_function(p->dbRbu,
+ p->rc = sqlite3_create_function(p->dbRbu,
"rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
);
}
@@ -168752,9 +198749,9 @@ static void rbuOpenDatabase(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
}
- rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
+ rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema");
- /* Mark the database file just opened as an RBU target database. If
+ /* Mark the database file just opened as an RBU target database. If
** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
** This is an error. */
if( p->rc==SQLITE_OK ){
@@ -168802,10 +198799,10 @@ static void rbuFileSuffix3(const char *zBase, char *z){
}
/*
-** Return the current wal-index header checksum for the target database
+** Return the current wal-index header checksum for the target database
** as a 64-bit integer.
**
-** The checksum is store in the first page of xShmMap memory as an 8-byte
+** The checksum is store in the first page of xShmMap memory as an 8-byte
** blob starting at byte offset 40.
*/
static i64 rbuShmChecksum(sqlite3rbu *p){
@@ -168823,11 +198820,11 @@ static i64 rbuShmChecksum(sqlite3rbu *p){
/*
** This function is called as part of initializing or reinitializing an
-** incremental checkpoint.
+** incremental checkpoint.
**
-** It populates the sqlite3rbu.aFrame[] array with the set of
-** (wal frame -> db page) copy operations required to checkpoint the
-** current wal file, and obtains the set of shm locks required to safely
+** It populates the sqlite3rbu.aFrame[] array with the set of
+** (wal frame -> db page) copy operations required to checkpoint the
+** current wal file, and obtains the set of shm locks required to safely
** perform the copy operations directly on the file-system.
**
** If argument pState is not NULL, then the incremental checkpoint is
@@ -168845,7 +198842,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
if( pState==0 ){
p->eStage = 0;
if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
+ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0);
}
}
@@ -168862,19 +198859,19 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
** would be read/written are recorded in the sqlite3rbu.aFrame[]
** array.
**
- ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER,
+ ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER,
** READ0 and CHECKPOINT locks taken as part of the checkpoint are
** no-ops. These locks will not be released until the connection
** is closed.
**
- ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
+ ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
** error.
**
** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the
** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[]
- ** array populated with a set of (frame -> page) mappings. Because the
- ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
- ** data from the wal file into the database file according to the
+ ** array populated with a set of (frame -> page) mappings. Because the
+ ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
+ ** data from the wal file into the database file according to the
** contents of aFrame[].
*/
if( p->rc==SQLITE_OK ){
@@ -168884,16 +198881,35 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
}
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK && p->nFrame>0 ){
p->eStage = RBU_STAGE_CKPT;
p->nStep = (pState ? pState->nRow : 0);
p->aBuf = rbuMalloc(p, p->pgsz);
p->iWalCksum = rbuShmChecksum(p);
}
- if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
- p->rc = SQLITE_DONE;
- p->eStage = RBU_STAGE_DONE;
+ if( p->rc==SQLITE_OK ){
+ if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
+ p->rc = SQLITE_DONE;
+ p->eStage = RBU_STAGE_DONE;
+ }else{
+ int nSectorSize;
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
+ assert( p->nPagePerSector==0 );
+ nSectorSize = pDb->pMethods->xSectorSize(pDb);
+ if( nSectorSize>p->pgsz ){
+ p->nPagePerSector = nSectorSize / p->pgsz;
+ }else{
+ p->nPagePerSector = 1;
+ }
+
+ /* Call xSync() on the wal file. This causes SQLite to sync the
+ ** directory in which the target database and the wal file reside, in
+ ** case it has not been synced since the rename() call in
+ ** rbuMoveOalFile(). */
+ p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
+ }
}
}
@@ -168931,7 +198947,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
/*
** Called when a page of data is written to offset iOff of the database
-** file while the rbu handle is in capture mode. Record the page number
+** file while the rbu handle is in capture mode. Record the page number
** of the page being written in the aFrame[] array.
*/
static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){
@@ -168999,7 +199015,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
** on the database file. This proc moves the *-oal file to the *-wal path,
** then reopens the database file (this time in vanilla, non-oal, WAL mode).
-** If an error occurs, leave an error code and error message in the rbu
+** If an error occurs, leave an error code and error message in the rbu
** handle.
*/
static void rbuMoveOalFile(sqlite3rbu *p){
@@ -169021,7 +199037,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
}else{
/* Move the *-oal file to *-wal. At this point connection p->db is
** holding a SHARED lock on the target database file (because it is
- ** in WAL mode). So no other connection may be writing the db.
+ ** in WAL mode). So no other connection may be writing the db.
**
** In order to ensure that there are no database readers, an EXCLUSIVE
** lock is obtained here before the *-oal is moved to *-wal.
@@ -169066,7 +199082,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
#endif
if( p->rc==SQLITE_OK ){
- rbuOpenDatabase(p);
+ rbuOpenDatabase(p, 0);
rbuSetupCheckpoint(p, 0);
}
}
@@ -169179,8 +199195,8 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){
/* If this is an INSERT into a table b-tree and the table has an
** explicit INTEGER PRIMARY KEY, check that this is not an attempt
** to write a NULL into the IPK column. That is not permitted. */
- if( eType==RBU_INSERT
- && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
+ if( eType==RBU_INSERT
+ && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
&& sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
){
p->rc = SQLITE_MISMATCH;
@@ -169197,18 +199213,18 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){
if( p->rc ) return;
}
if( pIter->zIdx==0 ){
- if( pIter->eType==RBU_PK_VTAB
- || pIter->eType==RBU_PK_NONE
- || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
+ if( pIter->eType==RBU_PK_VTAB
+ || pIter->eType==RBU_PK_NONE
+ || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
){
- /* For a virtual table, or a table with no primary key, the
+ /* For a virtual table, or a table with no primary key, the
** SELECT statement is:
**
** SELECT <cols>, rbu_control, rbu_rowid FROM ....
**
** Hence column_value(pIter->nCol+1).
*/
- assertColumnName(pIter->pSelect, pIter->nCol+1,
+ assertColumnName(pIter->pSelect, pIter->nCol+1,
rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
);
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
@@ -169272,8 +199288,8 @@ static int rbuStep(sqlite3rbu *p){
p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
}
}
- if( p->rc==SQLITE_OK
- && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
+ if( p->rc==SQLITE_OK
+ && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
){
/* Bind the rbu_rowid value to column _rowid_ */
assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
@@ -169303,7 +199319,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){
int iCookie = 1000000;
sqlite3_stmt *pStmt;
- p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
+ p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
"PRAGMA schema_version"
);
if( p->rc==SQLITE_OK ){
@@ -169335,7 +199351,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
int rc;
assert( p->zErrmsg==0 );
- rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg,
+ rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg,
sqlite3_mprintf(
"INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
"(%d, %d), "
@@ -169346,17 +199362,19 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
"(%d, %lld), "
"(%d, %lld), "
"(%d, %lld), "
- "(%d, %lld) ",
+ "(%d, %lld), "
+ "(%d, %Q) ",
p->zStateDb,
RBU_STATE_STAGE, eStage,
- RBU_STATE_TBL, p->objiter.zTbl,
- RBU_STATE_IDX, p->objiter.zIdx,
- RBU_STATE_ROW, p->nStep,
+ RBU_STATE_TBL, p->objiter.zTbl,
+ RBU_STATE_IDX, p->objiter.zIdx,
+ RBU_STATE_ROW, p->nStep,
RBU_STATE_PROGRESS, p->nProgress,
RBU_STATE_CKPT, p->iWalCksum,
RBU_STATE_COOKIE, (i64)pFd->iCookie,
RBU_STATE_OALSZ, p->iOalSz,
- RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
+ RBU_STATE_PHASEONESTEP, p->nPhaseOneStep,
+ RBU_STATE_DATATBL, p->objiter.zDataTbl
)
);
assert( pInsert==0 || rc==SQLITE_OK );
@@ -169371,7 +199389,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
/*
-** The second argument passed to this function is the name of a PRAGMA
+** The second argument passed to this function is the name of a PRAGMA
** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
** This function executes the following on sqlite3rbu.dbRbu:
**
@@ -169390,7 +199408,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
if( p->rc==SQLITE_OK ){
sqlite3_stmt *pPragma = 0;
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
sqlite3_mprintf("PRAGMA main.%s", zPragma)
);
if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
@@ -169403,7 +199421,7 @@ static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
}
/*
-** The RBU handle passed as the only argument has just been opened and
+** The RBU handle passed as the only argument has just been opened and
** the state database is empty. If this RBU handle was opened for an
** RBU vacuum operation, create the schema in the target db.
*/
@@ -169414,8 +199432,8 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
assert( rbuIsVacuum(p) );
p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
+ "SELECT sql FROM sqlite_schema WHERE sql!='' AND rootpage!=0"
" AND name!='sqlite_sequence' "
" ORDER BY type DESC"
);
@@ -169429,14 +199447,14 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
if( p->rc!=SQLITE_OK ) return;
if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
- "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
+ "SELECT * FROM sqlite_schema WHERE rootpage=0 OR rootpage IS NULL"
);
}
if( p->rc==SQLITE_OK ){
- p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
- "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+ p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
+ "INSERT INTO sqlite_schema VALUES(?,?,?,?,?)"
);
}
@@ -169476,11 +199494,11 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
while( p->rc==SQLITE_OK && pIter->zTbl ){
if( pIter->bCleanup ){
- /* Clean up the rbu_tmp_xxx table for the previous table. It
+ /* Clean up the rbu_tmp_xxx table for the previous table. It
** cannot be dropped as there are currently active SQL statements.
** But the contents can be deleted. */
if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
- rbuMPrintfExec(p, p->dbRbu,
+ rbuMPrintfExec(p, p->dbRbu,
"DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
);
}
@@ -169530,10 +199548,10 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
if( p->nStep>=p->nFrame ){
sqlite3_file *pDb = p->pTargetFd->pReal;
-
+
/* Sync the db file */
p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
-
+
/* Update nBackfill */
if( p->rc==SQLITE_OK ){
void volatile *ptr;
@@ -169542,15 +199560,32 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
((u32 volatile*)ptr)[24] = p->iMaxFrame;
}
}
-
+
if( p->rc==SQLITE_OK ){
p->eStage = RBU_STAGE_DONE;
p->rc = SQLITE_DONE;
}
}else{
- RbuFrame *pFrame = &p->aFrame[p->nStep];
- rbuCheckpointFrame(p, pFrame);
- p->nStep++;
+ /* At one point the following block copied a single frame from the
+ ** wal file to the database file. So that one call to sqlite3rbu_step()
+ ** checkpointed a single frame.
+ **
+ ** However, if the sector-size is larger than the page-size, and the
+ ** application calls sqlite3rbu_savestate() or close() immediately
+ ** after this step, then rbu_step() again, then a power failure occurs,
+ ** then the database page written here may be damaged. Work around
+ ** this by checkpointing frames until the next page in the aFrame[]
+ ** lies on a different disk sector to the current one. */
+ u32 iSector;
+ do{
+ RbuFrame *pFrame = &p->aFrame[p->nStep];
+ iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
+ rbuCheckpointFrame(p, pFrame);
+ p->nStep++;
+ }while( p->nStep<p->nFrame
+ && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
+ && p->rc==SQLITE_OK
+ );
}
p->nProgress++;
}
@@ -169593,9 +199628,10 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
RbuObjIter *pIter = &p->objiter;
int rc = SQLITE_OK;
- while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup
+ while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup
|| rbuStrCompare(pIter->zIdx, pState->zIdx)
- || rbuStrCompare(pIter->zTbl, pState->zTbl)
+ || (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl))
+ || (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl))
)){
rc = rbuObjIterNext(p, pIter);
}
@@ -169647,6 +199683,7 @@ static void rbuCreateVfs(sqlite3rbu *p){
sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
assert( pVfs );
p->zVfsName = pVfs->zName;
+ ((rbu_vfs*)pVfs)->pRbu = p;
}
}
@@ -169667,7 +199704,7 @@ static void rbuDeleteVfs(sqlite3rbu *p){
** the number of auxilliary indexes on the table.
*/
static void rbuIndexCntFunc(
- sqlite3_context *pCtx,
+ sqlite3_context *pCtx,
int nVal,
sqlite3_value **apVal
){
@@ -169675,11 +199712,12 @@ static void rbuIndexCntFunc(
sqlite3_stmt *pStmt = 0;
char *zErrmsg = 0;
int rc;
+ sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
assert( nVal==1 );
-
- rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg,
- sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+
+ rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
+ sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
);
if( rc!=SQLITE_OK ){
@@ -169693,7 +199731,7 @@ static void rbuIndexCntFunc(
if( rc==SQLITE_OK ){
sqlite3_result_int(pCtx, nIndex);
}else{
- sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
+ sqlite3_result_error(pCtx, sqlite3_errmsg(db), -1);
}
}
@@ -169712,7 +199750,7 @@ static void rbuIndexCntFunc(
** and the cnt column the number of rows it contains.
**
** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
-** for all rows in the rbu_count table, where nIndex is the number of
+** for all rows in the rbu_count table, where nIndex is the number of
** indexes on the corresponding target database table.
*/
static void rbuInitPhaseOneSteps(sqlite3rbu *p){
@@ -169722,15 +199760,15 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
p->nPhaseOneStep = -1;
- p->rc = sqlite3_create_function(p->dbRbu,
+ p->rc = sqlite3_create_function(p->dbRbu,
"rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
);
-
+
/* Check for the rbu_count table. If it does not exist, or if an error
** occurs, nPhaseOneStep will be left set to -1. */
if( p->rc==SQLITE_OK ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+ "SELECT 1 FROM sqlite_schema WHERE tbl_name = 'rbu_count'"
);
}
if( p->rc==SQLITE_OK ){
@@ -169739,7 +199777,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
}
p->rc = sqlite3_finalize(pStmt);
}
-
+
if( p->rc==SQLITE_OK && bExists ){
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
"SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
@@ -169757,7 +199795,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
static sqlite3rbu *openRbuHandle(
- const char *zTarget,
+ const char *zTarget,
const char *zRbu,
const char *zState
){
@@ -169777,6 +199815,7 @@ static sqlite3rbu *openRbuHandle(
/* Open the target, RBU and state databases */
if( p->rc==SQLITE_OK ){
char *pCsr = (char*)&p[1];
+ int bRetry = 0;
if( zTarget ){
p->zTarget = pCsr;
memcpy(p->zTarget, zTarget, nTarget+1);
@@ -169788,7 +199827,18 @@ static sqlite3rbu *openRbuHandle(
if( zState ){
p->zState = rbuMPrintf(p, "%s", zState);
}
- rbuOpenDatabase(p);
+
+ /* If the first attempt to open the database file fails and the bRetry
+ ** flag it set, this means that the db was not opened because it seemed
+ ** to be a wal-mode db. But, this may have happened due to an earlier
+ ** RBU vacuum operation leaving an old wal file in the directory.
+ ** If this is the case, it will have been checkpointed and deleted
+ ** when the handle was closed and a second attempt to open the
+ ** database may succeed. */
+ rbuOpenDatabase(p, &bRetry);
+ if( bRetry ){
+ rbuOpenDatabase(p, 0);
+ }
}
if( p->rc==SQLITE_OK ){
@@ -169796,7 +199846,7 @@ static sqlite3rbu *openRbuHandle(
assert( pState || p->rc!=SQLITE_OK );
if( p->rc==SQLITE_OK ){
- if( pState->eStage==0 ){
+ if( pState->eStage==0 ){
rbuDeleteOalFile(p);
rbuInitPhaseOneSteps(p);
p->eStage = RBU_STAGE_OAL;
@@ -169820,15 +199870,15 @@ static sqlite3rbu *openRbuHandle(
}
}
- if( p->rc==SQLITE_OK
+ if( p->rc==SQLITE_OK
&& (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
&& pState->eStage!=0
){
rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
- if( pFd->iCookie!=pState->iCookie ){
+ if( pFd->iCookie!=pState->iCookie ){
/* At this point (pTargetFd->iCookie) contains the value of the
- ** change-counter cookie (the thing that gets incremented when a
- ** transaction is committed in rollback mode) currently stored on
+ ** change-counter cookie (the thing that gets incremented when a
+ ** transaction is committed in rollback mode) currently stored on
** page 1 of the database file. */
p->rc = SQLITE_BUSY;
p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
@@ -169865,7 +199915,7 @@ static sqlite3rbu *openRbuHandle(
}
/* Check if the main database is a zipvfs db. If it is, set the upper
- ** level pager to use "journal_mode=off". This prevents it from
+ ** level pager to use "journal_mode=off". This prevents it from
** generating a large journal using a temp file. */
if( p->rc==SQLITE_OK ){
int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
@@ -169911,10 +199961,10 @@ static sqlite3rbu *rbuMisuseError(void){
}
/*
-** Open and return a new RBU handle.
+** Open and return a new RBU handle.
*/
SQLITE_API sqlite3rbu *sqlite3rbu_open(
- const char *zTarget,
+ const char *zTarget,
const char *zRbu,
const char *zState
){
@@ -169927,10 +199977,16 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
** Open a handle to begin or resume an RBU VACUUM operation.
*/
SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
- const char *zTarget,
+ const char *zTarget,
const char *zState
){
if( zTarget==0 ){ return rbuMisuseError(); }
+ if( zState ){
+ int n = strlen(zState);
+ if( n>=7 && 0==memcmp("-vactmp", &zState[n-7], 7) ){
+ return rbuMisuseError();
+ }
+ }
/* TODO: Check that both arguments are non-NULL */
return openRbuHandle(0, zTarget, zState);
}
@@ -169979,6 +200035,12 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
}
+ /* Sync the db file if currently doing an incremental checkpoint */
+ if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+ }
+
rbuSaveState(p, p->eStage);
if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
@@ -169989,8 +200051,8 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
rbuObjIterFinalize(&p->objiter);
/* If this is an RBU vacuum handle and the vacuum has either finished
- ** successfully or encountered an error, delete the contents of the
- ** state table. This causes the next call to sqlite3rbu_vacuum()
+ ** successfully or encountered an error, delete the contents of the
+ ** state table. This causes the next call to sqlite3rbu_vacuum()
** specifying the current target and state databases to start a new
** vacuum from scratch. */
if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
@@ -170001,13 +200063,18 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
/* Close the open database handle and VFS object. */
sqlite3_close(p->dbRbu);
sqlite3_close(p->dbMain);
+ assert( p->szTemp==0 );
rbuDeleteVfs(p);
sqlite3_free(p->aBuf);
sqlite3_free(p->aFrame);
rbuEditErrmsg(p);
rc = p->rc;
- *pzErrmsg = p->zErrmsg;
+ if( pzErrmsg ){
+ *pzErrmsg = p->zErrmsg;
+ }else{
+ sqlite3_free(p->zErrmsg);
+ }
sqlite3_free(p->zState);
sqlite3_free(p);
}else{
@@ -170018,7 +200085,7 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
}
/*
-** Return the total number of key-value operations (inserts, deletes or
+** Return the total number of key-value operations (inserts, deletes or
** updates) that have been performed on the target database since the
** current RBU update was started.
*/
@@ -170103,6 +200170,12 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
}
+ /* Sync the db file */
+ if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+ sqlite3_file *pDb = p->pTargetFd->pReal;
+ rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+ }
+
p->rc = rc;
rbuSaveState(p, p->eStage);
rc = p->rc;
@@ -170110,7 +200183,10 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
if( p->eStage==RBU_STAGE_OAL ){
assert( rc!=SQLITE_DONE );
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
- if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE";
+ rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0);
+ }
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
}
@@ -170122,7 +200198,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
** of a standard VFS in the following ways:
**
-** 1. Whenever the first page of a main database file is read or
+** 1. Whenever the first page of a main database file is read or
** written, the value of the change-counter cookie is stored in
** rbu_file.iCookie. Similarly, the value of the "write-version"
** database header field is stored in rbu_file.iWriteVer. This ensures
@@ -170130,15 +200206,15 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
**
** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd)
** member variable of the associated database file descriptor is set
-** to point to the new file. A mutex protected linked list of all main
-** db fds opened using a particular RBU VFS is maintained at
+** to point to the new file. A mutex protected linked list of all main
+** db fds opened using a particular RBU VFS is maintained at
** rbu_vfs.pMain to facilitate this.
**
-** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file
+** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file
** object can be marked as the target database of an RBU update. This
** turns on the following extra special behaviour:
**
-** 3a. If xAccess() is called to check if there exists a *-wal file
+** 3a. If xAccess() is called to check if there exists a *-wal file
** associated with an RBU target database currently in RBU_STAGE_OAL
** stage (preparing the *-oal file), the following special handling
** applies:
@@ -170151,26 +200227,26 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
**
** Then, when xOpen() is called to open the *-wal file associated with
** the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal
-** file, the rbu vfs opens the corresponding *-oal file instead.
+** file, the rbu vfs opens the corresponding *-oal file instead.
**
** 3b. The *-shm pages returned by xShmMap() for a target db file in
** RBU_STAGE_OAL mode are actually stored in heap memory. This is to
** avoid creating a *-shm file on disk. Additionally, xShmLock() calls
** are no-ops on target database files in RBU_STAGE_OAL mode. This is
-** because assert() statements in some VFS implementations fail if
+** because assert() statements in some VFS implementations fail if
** xShmLock() is called before xShmMap().
**
** 3c. If an EXCLUSIVE lock is attempted on a target database file in any
-** mode except RBU_STAGE_DONE (all work completed and checkpointed), it
+** mode except RBU_STAGE_DONE (all work completed and checkpointed), it
** fails with an SQLITE_BUSY error. This is to stop RBU connections
** from automatically checkpointing a *-wal (or *-oal) file from within
** sqlite3_close().
**
** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and
-** all xWrite() calls on the target database file perform no IO.
+** all xWrite() calls on the target database file perform no IO.
** Instead the frame and page numbers that would be read and written
** are recorded. Additionally, successful attempts to obtain exclusive
-** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target
+** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target
** database file are recorded. xShmLock() calls to unlock the same
** locks are no-ops (so that once obtained, these locks are never
** relinquished). Finally, calls to xSync() on the target database
@@ -170178,6 +200254,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
*/
static void rbuUnlockShm(rbu_file *p){
+ assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
if( p->pRbu ){
int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
int i;
@@ -170191,6 +200268,81 @@ static void rbuUnlockShm(rbu_file *p){
}
/*
+*/
+static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
+ sqlite3rbu *pRbu = pFd->pRbu;
+ i64 nDiff = nNew - pFd->sz;
+ pRbu->szTemp += nDiff;
+ pFd->sz = nNew;
+ assert( pRbu->szTemp>=0 );
+ if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
+ return SQLITE_OK;
+}
+
+/*
+** Add an item to the main-db lists, if it is not already present.
+**
+** There are two main-db lists. One for all file descriptors, and one
+** for all file descriptors with rbu_file.pDb!=0. If the argument has
+** rbu_file.pDb!=0, then it is assumed to already be present on the
+** main list and is only added to the pDb!=0 list.
+*/
+static void rbuMainlistAdd(rbu_file *p){
+ rbu_vfs *pRbuVfs = p->pRbuVfs;
+ rbu_file *pIter;
+ assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) );
+ sqlite3_mutex_enter(pRbuVfs->mutex);
+ if( p->pRbu==0 ){
+ for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext);
+ p->pMainNext = pRbuVfs->pMain;
+ pRbuVfs->pMain = p;
+ }else{
+ for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){}
+ if( pIter==0 ){
+ p->pMainRbuNext = pRbuVfs->pMainRbu;
+ pRbuVfs->pMainRbu = p;
+ }
+ }
+ sqlite3_mutex_leave(pRbuVfs->mutex);
+}
+
+/*
+** Remove an item from the main-db lists.
+*/
+static void rbuMainlistRemove(rbu_file *p){
+ rbu_file **pp;
+ sqlite3_mutex_enter(p->pRbuVfs->mutex);
+ for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){}
+ if( *pp ) *pp = p->pMainNext;
+ p->pMainNext = 0;
+ for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){}
+ if( *pp ) *pp = p->pMainRbuNext;
+ p->pMainRbuNext = 0;
+ sqlite3_mutex_leave(p->pRbuVfs->mutex);
+}
+
+/*
+** Given that zWal points to a buffer containing a wal file name passed to
+** either the xOpen() or xAccess() VFS method, search the main-db list for
+** a file-handle opened by the same database connection on the corresponding
+** database file.
+**
+** If parameter bRbu is true, only search for file-descriptors with
+** rbu_file.pDb!=0.
+*/
+static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){
+ rbu_file *pDb;
+ sqlite3_mutex_enter(pRbuVfs->mutex);
+ if( bRbu ){
+ for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){}
+ }else{
+ for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
+ }
+ sqlite3_mutex_leave(pRbuVfs->mutex);
+ return pDb;
+}
+
+/*
** Close an rbu file.
*/
static int rbuVfsClose(sqlite3_file *pFile){
@@ -170207,14 +200359,14 @@ static int rbuVfsClose(sqlite3_file *pFile){
sqlite3_free(p->zDel);
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
- rbu_file **pp;
- sqlite3_mutex_enter(p->pRbuVfs->mutex);
- for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
- *pp = p->pMainNext;
- sqlite3_mutex_leave(p->pRbuVfs->mutex);
+ rbuMainlistRemove(p);
rbuUnlockShm(p);
p->pReal->pMethods->xShmUnmap(p->pReal, 0);
}
+ else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ rbuUpdateTempSize(p, 0);
+ }
+ assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p );
/* Close the underlying file handle */
rc = p->pReal->pMethods->xClose(p->pReal);
@@ -170223,7 +200375,7 @@ static int rbuVfsClose(sqlite3_file *pFile){
/*
-** Read and return an unsigned 32-bit big-endian integer from the buffer
+** Read and return an unsigned 32-bit big-endian integer from the buffer
** passed as the only argument.
*/
static u32 rbuGetU32(u8 *aBuf){
@@ -170253,9 +200405,9 @@ static void rbuPutU16(u8 *aBuf, u16 iVal){
** Read data from an rbuVfs-file.
*/
static int rbuVfsRead(
- sqlite3_file *pFile,
- void *zBuf,
- int iAmt,
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
sqlite_int64 iOfst
){
rbu_file *p = (rbu_file*)pFile;
@@ -170266,20 +200418,20 @@ static int rbuVfsRead(
assert( p->openFlags & SQLITE_OPEN_WAL );
rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt);
}else{
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
- && (p->openFlags & SQLITE_OPEN_WAL)
- && iOfst>=pRbu->iOalSz
+ if( pRbu && pRbu->eStage==RBU_STAGE_OAL
+ && (p->openFlags & SQLITE_OPEN_WAL)
+ && iOfst>=pRbu->iOalSz
){
rc = SQLITE_OK;
memset(zBuf, 0, iAmt);
}else{
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
#if 1
- /* If this is being called to read the first page of the target
- ** database as part of an rbu vacuum operation, synthesize the
+ /* If this is being called to read the first page of the target
+ ** database as part of an rbu vacuum operation, synthesize the
** contents of the first page if it does not yet exist. Otherwise,
** SQLite will not check for a *-wal file. */
- if( pRbu && rbuIsVacuum(pRbu)
+ if( pRbu && rbuIsVacuum(pRbu)
&& rc==SQLITE_IOERR_SHORT_READ && iOfst==0
&& (p->openFlags & SQLITE_OPEN_MAIN_DB)
&& pRbu->rc==SQLITE_OK
@@ -170319,9 +200471,9 @@ static int rbuVfsRead(
** Write data to an rbuVfs-file.
*/
static int rbuVfsWrite(
- sqlite3_file *pFile,
- const void *zBuf,
- int iAmt,
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
sqlite_int64 iOfst
){
rbu_file *p = (rbu_file*)pFile;
@@ -170332,11 +200484,19 @@ static int rbuVfsWrite(
assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
rc = rbuCaptureDbWrite(p->pRbu, iOfst);
}else{
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
- && (p->openFlags & SQLITE_OPEN_WAL)
- && iOfst>=pRbu->iOalSz
- ){
- pRbu->iOalSz = iAmt + iOfst;
+ if( pRbu ){
+ if( pRbu->eStage==RBU_STAGE_OAL
+ && (p->openFlags & SQLITE_OPEN_WAL)
+ && iOfst>=pRbu->iOalSz
+ ){
+ pRbu->iOalSz = iAmt + iOfst;
+ }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
+ i64 szNew = iAmt+iOfst;
+ if( szNew>p->sz ){
+ rc = rbuUpdateTempSize(p, szNew);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+ }
}
rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
@@ -170355,6 +200515,10 @@ static int rbuVfsWrite(
*/
static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
rbu_file *p = (rbu_file*)pFile;
+ if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+ int rc = rbuUpdateTempSize(p, size);
+ if( rc!=SQLITE_OK ) return rc;
+ }
return p->pReal->pMethods->xTruncate(p->pReal, size);
}
@@ -170382,10 +200546,10 @@ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
/* If this is an RBU vacuum operation and this is the target database,
** pretend that it has at least one page. Otherwise, SQLite will not
- ** check for the existance of a *-wal file. rbuVfsRead() contains
+ ** check for the existance of a *-wal file. rbuVfsRead() contains
** similar logic. */
- if( rc==SQLITE_OK && *pSize==0
- && p->pRbu && rbuIsVacuum(p->pRbu)
+ if( rc==SQLITE_OK && *pSize==0
+ && p->pRbu && rbuIsVacuum(p->pRbu)
&& (p->openFlags & SQLITE_OPEN_MAIN_DB)
){
*pSize = 1024;
@@ -170402,10 +200566,10 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){
int rc = SQLITE_OK;
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( eLock==SQLITE_LOCK_EXCLUSIVE
+ if( eLock==SQLITE_LOCK_EXCLUSIVE
&& (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
){
- /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
+ /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
** prevents it from checkpointing the database from sqlite3_close(). */
rc = SQLITE_BUSY;
}else{
@@ -170461,6 +200625,7 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
}else if( rc==SQLITE_NOTFOUND ){
pRbu->pTargetFd = p;
p->pRbu = pRbu;
+ rbuMainlistAdd(p);
if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
rc = SQLITE_OK;
}
@@ -170517,16 +200682,13 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
/* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
- ** taking this lock also prevents any checkpoints from occurring.
- ** todo: really, it's not clear why this might occur, as
+ ** taking this lock also prevents any checkpoints from occurring.
+ ** todo: really, it's not clear why this might occur, as
** wal_autocheckpoint ought to be turned off. */
if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
}else{
int bCapture = 0;
- if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
- && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE
- && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
- ){
+ if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
bCapture = 1;
}
@@ -170545,10 +200707,10 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file.
*/
static int rbuVfsShmMap(
- sqlite3_file *pFile,
- int iRegion,
- int szRegion,
- int isWrite,
+ sqlite3_file *pFile,
+ int iRegion,
+ int szRegion,
+ int isWrite,
void volatile **pp
){
rbu_file *p = (rbu_file*)pFile;
@@ -170556,23 +200718,27 @@ static int rbuVfsShmMap(
int eStage = (p->pRbu ? p->pRbu->eStage : 0);
/* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this
- ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space
+ ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space
** instead of a file on disk. */
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
- if( iRegion<=p->nShm ){
- int nByte = (iRegion+1) * sizeof(char*);
- char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
- if( apNew==0 ){
- rc = SQLITE_NOMEM;
- }else{
- memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
- p->apShm = apNew;
- p->nShm = iRegion+1;
- }
+ if( eStage==RBU_STAGE_OAL ){
+ sqlite3_int64 nByte = (iRegion+1) * sizeof(char*);
+ char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
+
+ /* This is an RBU connection that uses its own heap memory for the
+ ** pages of the *-shm file. Since no other process can have run
+ ** recovery, the connection must request *-shm pages in order
+ ** from start to finish. */
+ assert( iRegion==p->nShm );
+ if( apNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
+ p->apShm = apNew;
+ p->nShm = iRegion+1;
}
- if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
+ if( rc==SQLITE_OK ){
char *pNew = (char*)sqlite3_malloc64(szRegion);
if( pNew==0 ){
rc = SQLITE_NOMEM;
@@ -170623,47 +200789,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
}
/*
-** Given that zWal points to a buffer containing a wal file name passed to
-** either the xOpen() or xAccess() VFS method, return a pointer to the
-** file-handle opened by the same database connection on the corresponding
-** database file.
-*/
-static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
- rbu_file *pDb;
- sqlite3_mutex_enter(pRbuVfs->mutex);
- for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
- sqlite3_mutex_leave(pRbuVfs->mutex);
- return pDb;
-}
-
-/*
-** A main database named zName has just been opened. The following
-** function returns a pointer to a buffer owned by SQLite that contains
-** the name of the *-wal file this db connection will use. SQLite
-** happens to pass a pointer to this buffer when using xAccess()
-** or xOpen() to operate on the *-wal file.
-*/
-static const char *rbuMainToWal(const char *zName, int flags){
- int n = (int)strlen(zName);
- const char *z = &zName[n];
- if( flags & SQLITE_OPEN_URI ){
- int odd = 0;
- while( 1 ){
- if( z[0]==0 ){
- odd = 1 - odd;
- if( odd && z[1]==0 ) break;
- }
- z++;
- }
- z += 2;
- }else{
- while( *z==0 ) z++;
- }
- z += (n + 8 + 1);
- return z;
-}
-
-/*
** Open an rbu file handle.
*/
static int rbuVfsOpen(
@@ -170711,22 +200836,22 @@ static int rbuVfsOpen(
** the name of the *-wal file this db connection will use. SQLite
** happens to pass a pointer to this buffer when using xAccess()
** or xOpen() to operate on the *-wal file. */
- pFd->zWal = rbuMainToWal(zName, flags);
+ pFd->zWal = sqlite3_filename_wal(zName);
}
else if( flags & SQLITE_OPEN_WAL ){
- rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
+ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
if( pDb ){
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
/* This call is to open a *-wal file. Intead, open the *-oal. This
** code ensures that the string passed to xOpen() is terminated by a
- ** pair of '\0' bytes in case the VFS attempts to extract a URI
+ ** pair of '\0' bytes in case the VFS attempts to extract a URI
** parameter from it. */
const char *zBase = zName;
size_t nCopy;
char *zCopy;
if( rbuIsVacuum(pDb->pRbu) ){
zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
- zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
+ zBase = sqlite3_filename_wal(zBase);
}
nCopy = strlen(zBase);
zCopy = sqlite3_malloc64(nCopy+2);
@@ -170744,10 +200869,12 @@ static int rbuVfsOpen(
pDb->pWalFd = pFd;
}
}
+ }else{
+ pFd->pRbu = pRbuVfs->pRbu;
}
- if( oflags & SQLITE_OPEN_MAIN_DB
- && sqlite3_uri_boolean(zName, "rbu_memory", 0)
+ if( oflags & SQLITE_OPEN_MAIN_DB
+ && sqlite3_uri_boolean(zName, "rbu_memory", 0)
){
assert( oflags & SQLITE_OPEN_MAIN_DB );
oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
@@ -170764,10 +200891,7 @@ static int rbuVfsOpen(
** mutex protected linked list of all such files. */
pFile->pMethods = &rbuvfs_io_methods;
if( flags & SQLITE_OPEN_MAIN_DB ){
- sqlite3_mutex_enter(pRbuVfs->mutex);
- pFd->pMainNext = pRbuVfs->pMain;
- pRbuVfs->pMain = pFd;
- sqlite3_mutex_leave(pRbuVfs->mutex);
+ rbuMainlistAdd(pFd);
}
}else{
sqlite3_free(pFd->zDel);
@@ -170789,9 +200913,9 @@ static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
** is available, or false otherwise.
*/
static int rbuVfsAccess(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int flags,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
int *pResOut
){
rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
@@ -170807,7 +200931,7 @@ static int rbuVfsAccess(
** a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
** ensures that the RBU extension never tries to update a database
** in wal mode, even if the first page of the database file has
- ** been damaged.
+ ** been damaged.
**
** b) if the *-wal file does not exist, claim that it does anyway,
** causing SQLite to call xOpen() to open it. This call will also
@@ -170815,12 +200939,15 @@ static int rbuVfsAccess(
** file opened instead.
*/
if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
- rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
- if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
+ rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1);
+ if( pDb && pDb->pRbu->eStage==RBU_STAGE_OAL ){
+ assert( pDb->pRbu );
if( *pResOut ){
rc = SQLITE_CANTOPEN;
}else{
- *pResOut = 1;
+ sqlite3_int64 sz = 0;
+ rc = rbuVfsFileSize(&pDb->base, &sz);
+ *pResOut = (sz>0);
}
}
}
@@ -170834,9 +200961,9 @@ static int rbuVfsAccess(
** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
*/
static int rbuVfsFullPathname(
- sqlite3_vfs *pVfs,
- const char *zPath,
- int nOut,
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
char *zOut
){
sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
@@ -170854,7 +200981,7 @@ static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
/*
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
-** utf-8 string describing the most recent error encountered associated
+** utf-8 string describing the most recent error encountered associated
** with dynamic libraries.
*/
static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
@@ -170866,8 +200993,8 @@ static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void (*rbuVfsDlSym(
- sqlite3_vfs *pVfs,
- void *pArg,
+ sqlite3_vfs *pVfs,
+ void *pArg,
const char *zSym
))(void){
sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
@@ -170884,7 +201011,7 @@ static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
/*
-** Populate the buffer pointed to by zBufOut with nByte bytes of
+** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
@@ -170893,7 +201020,7 @@ static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
}
/*
-** Sleep for nMicro microseconds. Return the number of microseconds
+** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){
@@ -171009,6 +201136,20 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
return rc;
}
+/*
+** Configure the aggregate temp file size limit for this RBU handle.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
+ if( n>=0 ){
+ pRbu->szTempLimit = n;
+ }
+ return pRbu->szTempLimit;
+}
+
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
+ return pRbu->szTemp;
+}
+
/**************************************************************************/
@@ -171030,7 +201171,7 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
**
** This file contains an implementation of the "dbstat" virtual table.
**
-** The dbstat virtual table is used to extract low-level formatting
+** The dbstat virtual table is used to extract low-level storage
** information from an SQLite database in order to implement the
** "sqlite3_analyzer" utility. See the ../tool/spaceanal.tcl script
** for an example implementation.
@@ -171045,22 +201186,22 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
/*
** Page paths:
-**
-** The value of the 'path' column describes the path taken from the
-** root-node of the b-tree structure to each page. The value of the
+**
+** The value of the 'path' column describes the path taken from the
+** root-node of the b-tree structure to each page. The value of the
** root-node path is '/'.
**
** The value of the path for the left-most child page of the root of
** a b-tree is '/000/'. (Btrees store content ordered from left to right
** so the pages to the left have smaller keys than the pages to the right.)
** The next to left-most child of the root page is
-** '/001', and so on, each sibling page identified by a 3-digit hex
+** '/001', and so on, each sibling page identified by a 3-digit hex
** value. The children of the 451st left-most sibling have paths such
** as '/1c2/000/, '/1c2/001/' etc.
**
-** Overflow pages are specified by appending a '+' character and a
+** Overflow pages are specified by appending a '+' character and a
** six-digit hexadecimal value to the path to the cell they are linked
-** from. For example, the three overflow pages in a chain linked from
+** from. For example, the three overflow pages in a chain linked from
** the left-most cell of the 450th child of the root page are identified
** by the paths:
**
@@ -171074,27 +201215,30 @@ SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
**
** '/1c2/000/' // Left-most child of 451st child of root
*/
-#define VTAB_SCHEMA \
- "CREATE TABLE xx( " \
- " name TEXT, /* Name of table or index */" \
- " path TEXT, /* Path to page from root */" \
- " pageno INTEGER, /* Page number */" \
- " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
- " ncell INTEGER, /* Cells on page (0 for overflow) */" \
- " payload INTEGER, /* Bytes of payload on this page */" \
- " unused INTEGER, /* Bytes of unused space on this page */" \
- " mx_payload INTEGER, /* Largest payload size of all cells */" \
- " pgoffset INTEGER, /* Offset of page in file */" \
- " pgsize INTEGER, /* Size of the page */" \
- " schema TEXT HIDDEN /* Database schema being analyzed */" \
- ");"
-
-
+static const char zDbstatSchema[] =
+ "CREATE TABLE x("
+ " name TEXT," /* 0 Name of table or index */
+ " path TEXT," /* 1 Path to page from root (NULL for agg) */
+ " pageno INTEGER," /* 2 Page number (page count for aggregates) */
+ " pagetype TEXT," /* 3 'internal', 'leaf', 'overflow', or NULL */
+ " ncell INTEGER," /* 4 Cells on page (0 for overflow) */
+ " payload INTEGER," /* 5 Bytes of payload on this page */
+ " unused INTEGER," /* 6 Bytes of unused space on this page */
+ " mx_payload INTEGER," /* 7 Largest payload size of all cells */
+ " pgoffset INTEGER," /* 8 Offset of page in file (NULL for agg) */
+ " pgsize INTEGER," /* 9 Size of the page (sum for aggregate) */
+ " schema TEXT HIDDEN," /* 10 Database schema being analyzed */
+ " aggregate BOOLEAN HIDDEN" /* 11 aggregate info for each table */
+ ")"
+;
+
+/* Forward reference to data structured used in this module */
typedef struct StatTable StatTable;
typedef struct StatCursor StatCursor;
typedef struct StatPage StatPage;
typedef struct StatCell StatCell;
+/* Size information for a single cell within a btree page */
struct StatCell {
int nLocal; /* Bytes of local payload */
u32 iChildPg; /* Child node (or 0 if this is a leaf) */
@@ -171104,10 +201248,11 @@ struct StatCell {
int iOvfl; /* Iterates through aOvfl[] */
};
+/* Size information for a single btree page */
struct StatPage {
- u32 iPgno;
- DbPage *pPg;
- int iCell;
+ u32 iPgno; /* Page number */
+ DbPage *pPg; /* Page content */
+ int iCell; /* Current cell */
char *zPath; /* Path to this page */
@@ -171117,34 +201262,38 @@ struct StatPage {
int nUnused; /* Number of unused bytes on page */
StatCell *aCell; /* Array of parsed cells */
u32 iRightChildPg; /* Right-child page number (or 0) */
- int nMxPayload; /* Largest payload of any cell on this page */
+ int nMxPayload; /* Largest payload of any cell on the page */
};
+/* The cursor for scanning the dbstat virtual table */
struct StatCursor {
- sqlite3_vtab_cursor base;
+ sqlite3_vtab_cursor base; /* base class. MUST BE FIRST! */
sqlite3_stmt *pStmt; /* Iterates through set of root pages */
- int isEof; /* After pStmt has returned SQLITE_DONE */
+ u8 isEof; /* After pStmt has returned SQLITE_DONE */
+ u8 isAgg; /* Aggregate results for each table */
int iDb; /* Schema used for this query */
- StatPage aPage[32];
+ StatPage aPage[32]; /* Pages in path to current page */
int iPage; /* Current entry in aPage[] */
/* Values to return. */
+ u32 iPageno; /* Value of 'pageno' column */
char *zName; /* Value of 'name' column */
char *zPath; /* Value of 'path' column */
- u32 iPageno; /* Value of 'pageno' column */
char *zPagetype; /* Value of 'pagetype' column */
+ int nPage; /* Number of pages in current btree */
int nCell; /* Value of 'ncell' column */
- int nPayload; /* Value of 'payload' column */
- int nUnused; /* Value of 'unused' column */
int nMxPayload; /* Value of 'mx_payload' column */
+ i64 nUnused; /* Value of 'unused' column */
+ i64 nPayload; /* Value of 'payload' column */
i64 iOffset; /* Value of 'pgOffset' column */
- int szPage; /* Value of 'pgSize' column */
+ i64 szPage; /* Value of 'pgSize' column */
};
+/* An instance of the DBSTAT virtual table */
struct StatTable {
- sqlite3_vtab base;
- sqlite3 *db;
+ sqlite3_vtab base; /* base class. MUST BE FIRST! */
+ sqlite3 *db; /* Database connection that owns this vtab */
int iDb; /* Index of database to analyze */
};
@@ -171153,7 +201302,7 @@ struct StatTable {
#endif
/*
-** Connect to or create a statvfs virtual table.
+** Connect to or create a new DBSTAT virtual table.
*/
static int statConnect(
sqlite3 *db,
@@ -171177,7 +201326,8 @@ static int statConnect(
}else{
iDb = 0;
}
- rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ rc = sqlite3_declare_vtab(db, zDbstatSchema);
if( rc==SQLITE_OK ){
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
@@ -171195,7 +201345,7 @@ static int statConnect(
}
/*
-** Disconnect from or destroy a statvfs virtual table.
+** Disconnect from or destroy the DBSTAT virtual table.
*/
static int statDisconnect(sqlite3_vtab *pVtab){
sqlite3_free(pVtab);
@@ -171203,16 +201353,20 @@ static int statDisconnect(sqlite3_vtab *pVtab){
}
/*
-** There is no "best-index". This virtual table always does a linear
-** scan. However, a schema=? constraint should cause this table to
-** operate on a different database schema, so check for it.
+** Compute the best query strategy and return the result in idxNum.
**
-** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
+** idxNum-Bit Meaning
+** ---------- ----------------------------------------------
+** 0x01 There is a schema=? term in the WHERE clause
+** 0x02 There is a name=? term in the WHERE clause
+** 0x04 There is an aggregate=? term in the WHERE clause
+** 0x08 Output should be ordered by name and path
*/
static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int i;
-
- pIdxInfo->estimatedCost = 1.0e6; /* Initial cost estimate */
+ int iSchema = -1;
+ int iName = -1;
+ int iAgg = -1;
/* Look for a valid schema=? constraint. If found, change the idxNum to
** 1 and request the value of that constraint be sent to xFilter. And
@@ -171220,19 +201374,44 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
** used.
*/
for(i=0; i<pIdxInfo->nConstraint; i++){
- if( pIdxInfo->aConstraint[i].usable==0 ) continue;
if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
- pIdxInfo->idxNum = 1;
- pIdxInfo->estimatedCost = 1.0;
- pIdxInfo->aConstraintUsage[i].argvIndex = 1;
- pIdxInfo->aConstraintUsage[i].omit = 1;
- break;
+ if( pIdxInfo->aConstraint[i].usable==0 ){
+ /* Force DBSTAT table should always be the right-most table in a join */
+ return SQLITE_CONSTRAINT;
+ }
+ switch( pIdxInfo->aConstraint[i].iColumn ){
+ case 0: { /* name */
+ iName = i;
+ break;
+ }
+ case 10: { /* schema */
+ iSchema = i;
+ break;
+ }
+ case 11: { /* aggregate */
+ iAgg = i;
+ break;
+ }
+ }
}
+ i = 0;
+ if( iSchema>=0 ){
+ pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
+ pIdxInfo->aConstraintUsage[iSchema].omit = 1;
+ pIdxInfo->idxNum |= 0x01;
+ }
+ if( iName>=0 ){
+ pIdxInfo->aConstraintUsage[iName].argvIndex = ++i;
+ pIdxInfo->idxNum |= 0x02;
+ }
+ if( iAgg>=0 ){
+ pIdxInfo->aConstraintUsage[iAgg].argvIndex = ++i;
+ pIdxInfo->idxNum |= 0x04;
+ }
+ pIdxInfo->estimatedCost = 1.0;
-
- /* Records are always returned in ascending order of (name, path).
- ** If this will satisfy the client, set the orderByConsumed flag so that
+ /* Records are always returned in ascending order of (name, path).
+ ** If this will satisfy the client, set the orderByConsumed flag so that
** SQLite does not do an external sort.
*/
if( ( pIdxInfo->nOrderBy==1
@@ -171247,13 +201426,14 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
)
){
pIdxInfo->orderByConsumed = 1;
+ pIdxInfo->idxNum |= 0x08;
}
return SQLITE_OK;
}
/*
-** Open a new statvfs cursor.
+** Open a new DBSTAT cursor.
*/
static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
StatTable *pTab = (StatTable *)pVTab;
@@ -171272,7 +201452,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
return SQLITE_OK;
}
-static void statClearPage(StatPage *p){
+static void statClearCells(StatPage *p){
int i;
if( p->aCell ){
for(i=0; i<p->nCell; i++){
@@ -171280,6 +201460,12 @@ static void statClearPage(StatPage *p){
}
sqlite3_free(p->aCell);
}
+ p->nCell = 0;
+ p->aCell = 0;
+}
+
+static void statClearPage(StatPage *p){
+ statClearCells(p);
sqlite3PagerUnref(p->pPg);
sqlite3_free(p->zPath);
memset(p, 0, sizeof(StatPage));
@@ -171297,8 +201483,18 @@ static void statResetCsr(StatCursor *pCsr){
pCsr->isEof = 0;
}
+/* Resize the space-used counters inside of the cursor */
+static void statResetCounts(StatCursor *pCsr){
+ pCsr->nCell = 0;
+ pCsr->nMxPayload = 0;
+ pCsr->nUnused = 0;
+ pCsr->nPayload = 0;
+ pCsr->szPage = 0;
+ pCsr->nPage = 0;
+}
+
/*
-** Close a statvfs cursor.
+** Close a DBSTAT cursor.
*/
static int statClose(sqlite3_vtab_cursor *pCursor){
StatCursor *pCsr = (StatCursor *)pCursor;
@@ -171308,16 +201504,20 @@ static int statClose(sqlite3_vtab_cursor *pCursor){
return SQLITE_OK;
}
-static void getLocalPayload(
+/*
+** For a single cell on a btree page, compute the number of bytes of
+** content (payload) stored on that page. That is to say, compute the
+** number of bytes of content not found on overflow pages.
+*/
+static int getLocalPayload(
int nUsable, /* Usable bytes per page */
u8 flags, /* Page flags */
- int nTotal, /* Total record (payload) size */
- int *pnLocal /* OUT: Bytes stored locally */
+ int nTotal /* Total record (payload) size */
){
int nLocal;
int nMinLocal;
int nMaxLocal;
-
+
if( flags==0x0D ){ /* Table leaf node */
nMinLocal = (nUsable - 12) * 32 / 255 - 23;
nMaxLocal = nUsable - 35;
@@ -171328,9 +201528,12 @@ static void getLocalPayload(
nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
if( nLocal>nMaxLocal ) nLocal = nMinLocal;
- *pnLocal = nLocal;
+ return nLocal;
}
+/* Populate the StatPage object with information about the all
+** cells found on the page currently under analysis.
+*/
static int statDecodePage(Btree *pBt, StatPage *p){
int nUnused;
int iOff;
@@ -171342,22 +201545,33 @@ static int statDecodePage(Btree *pBt, StatPage *p){
u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
p->flags = aHdr[0];
+ if( p->flags==0x0A || p->flags==0x0D ){
+ isLeaf = 1;
+ nHdr = 8;
+ }else if( p->flags==0x05 || p->flags==0x02 ){
+ isLeaf = 0;
+ nHdr = 12;
+ }else{
+ goto statPageIsCorrupt;
+ }
+ if( p->iPgno==1 ) nHdr += 100;
p->nCell = get2byte(&aHdr[3]);
p->nMxPayload = 0;
-
- isLeaf = (p->flags==0x0A || p->flags==0x0D);
- nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
+ szPage = sqlite3BtreeGetPageSize(pBt);
nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
nUnused += (int)aHdr[7];
iOff = get2byte(&aHdr[1]);
while( iOff ){
+ int iNext;
+ if( iOff>=szPage ) goto statPageIsCorrupt;
nUnused += get2byte(&aData[iOff+2]);
- iOff = get2byte(&aData[iOff]);
+ iNext = get2byte(&aData[iOff]);
+ if( iNext<iOff+4 && iNext>0 ) goto statPageIsCorrupt;
+ iOff = iNext;
}
p->nUnused = nUnused;
p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
- szPage = sqlite3BtreeGetPageSize(pBt);
if( p->nCell ){
int i; /* Used to iterate through cells */
@@ -171374,6 +201588,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
StatCell *pCell = &p->aCell[i];
iOff = get2byte(&aData[nHdr+i*2]);
+ if( iOff<nHdr || iOff>=szPage ) goto statPageIsCorrupt;
if( !isLeaf ){
pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
iOff += 4;
@@ -171389,14 +201604,17 @@ static int statDecodePage(Btree *pBt, StatPage *p){
iOff += sqlite3GetVarint(&aData[iOff], &dummy);
}
if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
- getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
+ nLocal = getLocalPayload(nUsable, p->flags, nPayload);
+ if( nLocal<0 ) goto statPageIsCorrupt;
pCell->nLocal = nLocal;
- assert( nLocal>=0 );
assert( nPayload>=(u32)nLocal );
assert( nLocal<=(nUsable-35) );
if( nPayload>(u32)nLocal ){
int j;
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
+ if( iOff+nLocal>nUsable || nPayload>0x7fffffff ){
+ goto statPageIsCorrupt;
+ }
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
pCell->nOvfl = nOvfl;
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
@@ -171410,7 +201628,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
if( rc!=SQLITE_OK ){
assert( pPg==0 );
return rc;
- }
+ }
pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
sqlite3PagerUnref(pPg);
}
@@ -171420,6 +201638,11 @@ static int statDecodePage(Btree *pBt, StatPage *p){
}
return SQLITE_OK;
+
+statPageIsCorrupt:
+ p->flags = 0;
+ statClearCells(p);
+ return SQLITE_OK;
}
/*
@@ -171433,23 +201656,25 @@ static void statSizeAndOffset(StatCursor *pCsr){
sqlite3_file *fd;
sqlite3_int64 x[2];
- /* The default page size and offset */
- pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
- pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
-
- /* If connected to a ZIPVFS backend, override the page size and
- ** offset with actual values obtained from ZIPVFS.
+ /* If connected to a ZIPVFS backend, find the page size and
+ ** offset from ZIPVFS.
*/
fd = sqlite3PagerFile(pPager);
x[0] = pCsr->iPageno;
- if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
+ if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
pCsr->iOffset = x[0];
- pCsr->szPage = (int)x[1];
+ pCsr->szPage += x[1];
+ }else{
+ /* Not ZIPVFS: The default page size and offset */
+ pCsr->szPage += sqlite3BtreeGetPageSize(pBt);
+ pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
}
}
/*
-** Move a statvfs cursor to the next entry in the file.
+** Move a DBSTAT cursor to the next entry. Normally, the next
+** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
+** the next entry is the next btree.
*/
static int statNext(sqlite3_vtab_cursor *pCursor){
int rc;
@@ -171465,6 +201690,8 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
statNextRestart:
if( pCsr->aPage[0].pPg==0 ){
+ /* Start measuring space on the next btree */
+ statResetCounts(pCsr);
rc = sqlite3_step(pCsr->pStmt);
if( rc==SQLITE_ROW ){
int nPage;
@@ -171477,44 +201704,47 @@ statNextRestart:
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
pCsr->aPage[0].iPgno = iRoot;
pCsr->aPage[0].iCell = 0;
- pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
+ if( !pCsr->isAgg ){
+ pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
pCsr->iPage = 0;
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ pCsr->nPage = 1;
}else{
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
}
}else{
-
- /* Page p itself has already been visited. */
+ /* Continue analyzing the btree previously started */
StatPage *p = &pCsr->aPage[pCsr->iPage];
-
+ if( !pCsr->isAgg ) statResetCounts(pCsr);
while( p->iCell<p->nCell ){
StatCell *pCell = &p->aCell[p->iCell];
- if( pCell->iOvfl<pCell->nOvfl ){
- int nUsable;
+ while( pCell->iOvfl<pCell->nOvfl ){
+ int nUsable, iOvfl;
sqlite3BtreeEnter(pBt);
- nUsable = sqlite3BtreeGetPageSize(pBt) -
+ nUsable = sqlite3BtreeGetPageSize(pBt) -
sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
- pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
- pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
- pCsr->zPagetype = "overflow";
- pCsr->nCell = 0;
- pCsr->nMxPayload = 0;
- pCsr->zPath = z = sqlite3_mprintf(
- "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
- );
+ pCsr->nPage++;
+ statSizeAndOffset(pCsr);
if( pCell->iOvfl<pCell->nOvfl-1 ){
- pCsr->nUnused = 0;
- pCsr->nPayload = nUsable - 4;
+ pCsr->nPayload += nUsable - 4;
}else{
- pCsr->nPayload = pCell->nLastOvfl;
- pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
+ pCsr->nPayload += pCell->nLastOvfl;
+ pCsr->nUnused += nUsable - 4 - pCell->nLastOvfl;
}
+ iOvfl = pCell->iOvfl;
pCell->iOvfl++;
- statSizeAndOffset(pCsr);
- return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+ if( !pCsr->isAgg ){
+ pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
+ pCsr->iPageno = pCell->aOvfl[iOvfl];
+ pCsr->zPagetype = "overflow";
+ pCsr->zPath = z = sqlite3_mprintf(
+ "%s%.3x+%.6x", p->zPath, p->iCell, iOvfl
+ );
+ return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+ }
}
if( p->iRightChildPg ) break;
p->iCell++;
@@ -171522,11 +201752,20 @@ statNextRestart:
if( !p->iRightChildPg || p->iCell>p->nCell ){
statClearPage(p);
- if( pCsr->iPage==0 ) return statNext(pCursor);
- pCsr->iPage--;
+ if( pCsr->iPage>0 ){
+ pCsr->iPage--;
+ }else if( pCsr->isAgg ){
+ /* label-statNext-done: When computing aggregate space usage over
+ ** an entire btree, this is the exit point from this function */
+ return SQLITE_OK;
+ }
goto statNextRestart; /* Tail recursion */
}
pCsr->iPage++;
+ if( pCsr->iPage>=ArraySize(pCsr->aPage) ){
+ statResetCsr(pCsr);
+ return SQLITE_CORRUPT_BKPT;
+ }
assert( p==&pCsr->aPage[pCsr->iPage-1] );
if( p->iCell==p->nCell ){
@@ -171535,10 +201774,13 @@ statNextRestart:
p[1].iPgno = p->aCell[p->iCell].iChildPg;
}
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
+ pCsr->nPage++;
p[1].iCell = 0;
- p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
+ if( !pCsr->isAgg ){
+ p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
p->iCell++;
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
}
@@ -171568,16 +201810,23 @@ statNextRestart:
pCsr->zPagetype = "corrupted";
break;
}
- pCsr->nCell = p->nCell;
- pCsr->nUnused = p->nUnused;
- pCsr->nMxPayload = p->nMxPayload;
- pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
- if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ pCsr->nCell += p->nCell;
+ pCsr->nUnused += p->nUnused;
+ if( p->nMxPayload>pCsr->nMxPayload ) pCsr->nMxPayload = p->nMxPayload;
+ if( !pCsr->isAgg ){
+ pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
nPayload = 0;
for(i=0; i<p->nCell; i++){
nPayload += p->aCell[i].nLocal;
}
- pCsr->nPayload = nPayload;
+ pCsr->nPayload += nPayload;
+
+ /* If computing aggregate space usage by btree, continue with the
+ ** next page. The loop will exit via the return at label-statNext-done
+ */
+ if( pCsr->isAgg ) goto statNextRestart;
}
}
@@ -171589,38 +201838,63 @@ static int statEof(sqlite3_vtab_cursor *pCursor){
return pCsr->isEof;
}
+/* Initialize a cursor according to the query plan idxNum using the
+** arguments in argv[0]. See statBestIndex() for a description of the
+** meaning of the bits in idxNum.
+*/
static int statFilter(
- sqlite3_vtab_cursor *pCursor,
+ sqlite3_vtab_cursor *pCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
StatCursor *pCsr = (StatCursor *)pCursor;
StatTable *pTab = (StatTable*)(pCursor->pVtab);
- char *zSql;
- int rc = SQLITE_OK;
- char *zMaster;
+ sqlite3_str *pSql; /* Query of btrees to analyze */
+ char *zSql; /* String value of pSql */
+ int iArg = 0; /* Count of argv[] parameters used so far */
+ int rc = SQLITE_OK; /* Result of this operation */
+ const char *zName = 0; /* Only provide analysis of this table */
- if( idxNum==1 ){
- const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
+ statResetCsr(pCsr);
+ sqlite3_finalize(pCsr->pStmt);
+ pCsr->pStmt = 0;
+ if( idxNum & 0x01 ){
+ /* schema=? constraint is present. Get its value */
+ const char *zDbase = (const char*)sqlite3_value_text(argv[iArg++]);
pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
if( pCsr->iDb<0 ){
- sqlite3_free(pCursor->pVtab->zErrMsg);
- pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
- return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
+ pCsr->iDb = 0;
+ pCsr->isEof = 1;
+ return SQLITE_OK;
}
}else{
pCsr->iDb = pTab->iDb;
}
- statResetCsr(pCsr);
- sqlite3_finalize(pCsr->pStmt);
- pCsr->pStmt = 0;
- zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
- zSql = sqlite3_mprintf(
- "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
- " UNION ALL "
- "SELECT name, rootpage, type"
- " FROM \"%w\".%s WHERE rootpage!=0"
- " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
+ if( idxNum & 0x02 ){
+ /* name=? constraint is present */
+ zName = (const char*)sqlite3_value_text(argv[iArg++]);
+ }
+ if( idxNum & 0x04 ){
+ /* aggregate=? constraint is present */
+ pCsr->isAgg = sqlite3_value_double(argv[iArg++])!=0.0;
+ }else{
+ pCsr->isAgg = 0;
+ }
+ pSql = sqlite3_str_new(pTab->db);
+ sqlite3_str_appendf(pSql,
+ "SELECT * FROM ("
+ "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type"
+ " UNION ALL "
+ "SELECT name,rootpage,type"
+ " FROM \"%w\".sqlite_schema WHERE rootpage!=0)",
+ pTab->db->aDb[pCsr->iDb].zDbSName);
+ if( zName ){
+ sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
+ }
+ if( idxNum & 0x08 ){
+ sqlite3_str_appendf(pSql, " ORDER BY name");
+ }
+ zSql = sqlite3_str_finish(pSql);
if( zSql==0 ){
return SQLITE_NOMEM_BKPT;
}else{
@@ -171635,8 +201909,8 @@ static int statFilter(
}
static int statColumn(
- sqlite3_vtab_cursor *pCursor,
- sqlite3_context *ctx,
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
int i
){
StatCursor *pCsr = (StatCursor *)pCursor;
@@ -171645,13 +201919,21 @@ static int statColumn(
sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
break;
case 1: /* path */
- sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
+ if( !pCsr->isAgg ){
+ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
+ }
break;
case 2: /* pageno */
- sqlite3_result_int64(ctx, pCsr->iPageno);
+ if( pCsr->isAgg ){
+ sqlite3_result_int64(ctx, pCsr->nPage);
+ }else{
+ sqlite3_result_int64(ctx, pCsr->iPageno);
+ }
break;
case 3: /* pagetype */
- sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
+ if( !pCsr->isAgg ){
+ sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
+ }
break;
case 4: /* ncell */
sqlite3_result_int(ctx, pCsr->nCell);
@@ -171666,17 +201948,23 @@ static int statColumn(
sqlite3_result_int(ctx, pCsr->nMxPayload);
break;
case 8: /* pgoffset */
- sqlite3_result_int64(ctx, pCsr->iOffset);
+ if( !pCsr->isAgg ){
+ sqlite3_result_int64(ctx, pCsr->iOffset);
+ }
break;
case 9: /* pgsize */
sqlite3_result_int(ctx, pCsr->szPage);
break;
- default: { /* schema */
+ case 10: { /* schema */
sqlite3 *db = sqlite3_context_db_handle(ctx);
int iDb = pCsr->iDb;
sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
break;
}
+ default: { /* aggregate */
+ sqlite3_result_int(ctx, pCsr->isAgg);
+ break;
+ }
}
return SQLITE_OK;
}
@@ -171712,6 +202000,10 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
0, /* xRollback */
0, /* xFindMethod */
0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
};
return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
@@ -171720,6 +202012,425 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
/************** End of dbstat.c **********************************************/
+/************** Begin file dbpage.c ******************************************/
+/*
+** 2017-10-11
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an implementation of the "sqlite_dbpage" virtual table.
+**
+** The sqlite_dbpage virtual table is used to read or write whole raw
+** pages of the database file. The pager interface is used so that
+** uncommitted changes and changes recorded in the WAL file are correctly
+** retrieved.
+**
+** Usage example:
+**
+** SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
+**
+** This is an eponymous virtual table so it does not need to be created before
+** use. The optional argument to the sqlite_dbpage() table name is the
+** schema for the database file that is to be read. The default schema is
+** "main".
+**
+** The data field of sqlite_dbpage table can be updated. The new
+** value must be a BLOB which is the correct page size, otherwise the
+** update fails. Rows may not be deleted or inserted.
+*/
+
+/* #include "sqliteInt.h" ** Requires access to internal data structures ** */
+#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
+ && !defined(SQLITE_OMIT_VIRTUALTABLE)
+
+typedef struct DbpageTable DbpageTable;
+typedef struct DbpageCursor DbpageCursor;
+
+struct DbpageCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ int pgno; /* Current page number */
+ int mxPgno; /* Last page to visit on this scan */
+ Pager *pPager; /* Pager being read/written */
+ DbPage *pPage1; /* Page 1 of the database */
+ int iDb; /* Index of database to analyze */
+ int szPage; /* Size of each page in bytes */
+};
+
+struct DbpageTable {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database */
+};
+
+/* Columns */
+#define DBPAGE_COLUMN_PGNO 0
+#define DBPAGE_COLUMN_DATA 1
+#define DBPAGE_COLUMN_SCHEMA 2
+
+
+
+/*
+** Connect to or create a dbpagevfs virtual table.
+*/
+static int dbpageConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ DbpageTable *pTab = 0;
+ int rc = SQLITE_OK;
+
+ sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
+ if( rc==SQLITE_OK ){
+ pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
+ if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
+ }
+
+ assert( rc==SQLITE_OK || pTab==0 );
+ if( rc==SQLITE_OK ){
+ memset(pTab, 0, sizeof(DbpageTable));
+ pTab->db = db;
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Disconnect from or destroy a dbpagevfs virtual table.
+*/
+static int dbpageDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** idxNum:
+**
+** 0 schema=main, full table scan
+** 1 schema=main, pgno=?1
+** 2 schema=?1, full table scan
+** 3 schema=?1, pgno=?2
+*/
+static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ int i;
+ int iPlan = 0;
+
+ /* If there is a schema= constraint, it must be honored. Report a
+ ** ridiculously large estimated cost if the schema= constraint is
+ ** unavailable
+ */
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
+ if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( !p->usable ){
+ /* No solution. */
+ return SQLITE_CONSTRAINT;
+ }
+ iPlan = 2;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ break;
+ }
+
+ /* If we reach this point, it means that either there is no schema=
+ ** constraint (in which case we use the "main" schema) or else the
+ ** schema constraint was accepted. Lower the estimated cost accordingly
+ */
+ pIdxInfo->estimatedCost = 1.0e6;
+
+ /* Check for constraints against pgno */
+ for(i=0; i<pIdxInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+ if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+ pIdxInfo->estimatedRows = 1;
+ pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+ pIdxInfo->estimatedCost = 1.0;
+ pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ iPlan |= 1;
+ break;
+ }
+ }
+ pIdxInfo->idxNum = iPlan;
+
+ if( pIdxInfo->nOrderBy>=1
+ && pIdxInfo->aOrderBy[0].iColumn<=0
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Open a new dbpagevfs cursor.
+*/
+static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+ DbpageCursor *pCsr;
+
+ pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
+ if( pCsr==0 ){
+ return SQLITE_NOMEM_BKPT;
+ }else{
+ memset(pCsr, 0, sizeof(DbpageCursor));
+ pCsr->base.pVtab = pVTab;
+ pCsr->pgno = -1;
+ }
+
+ *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+ return SQLITE_OK;
+}
+
+/*
+** Close a dbpagevfs cursor.
+*/
+static int dbpageClose(sqlite3_vtab_cursor *pCursor){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/*
+** Move a dbpagevfs cursor to the next entry in the file.
+*/
+static int dbpageNext(sqlite3_vtab_cursor *pCursor){
+ int rc = SQLITE_OK;
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ pCsr->pgno++;
+ return rc;
+}
+
+static int dbpageEof(sqlite3_vtab_cursor *pCursor){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ return pCsr->pgno > pCsr->mxPgno;
+}
+
+/*
+** idxNum:
+**
+** 0 schema=main, full table scan
+** 1 schema=main, pgno=?1
+** 2 schema=?1, full table scan
+** 3 schema=?1, pgno=?2
+**
+** idxStr is not used
+*/
+static int dbpageFilter(
+ sqlite3_vtab_cursor *pCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
+ int rc;
+ sqlite3 *db = pTab->db;
+ Btree *pBt;
+
+ /* Default setting is no rows of result */
+ pCsr->pgno = 1;
+ pCsr->mxPgno = 0;
+
+ if( idxNum & 2 ){
+ const char *zSchema;
+ assert( argc>=1 );
+ zSchema = (const char*)sqlite3_value_text(argv[0]);
+ pCsr->iDb = sqlite3FindDbName(db, zSchema);
+ if( pCsr->iDb<0 ) return SQLITE_OK;
+ }else{
+ pCsr->iDb = 0;
+ }
+ pBt = db->aDb[pCsr->iDb].pBt;
+ if( pBt==0 ) return SQLITE_OK;
+ pCsr->pPager = sqlite3BtreePager(pBt);
+ pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
+ pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
+ if( idxNum & 1 ){
+ assert( argc>(idxNum>>1) );
+ pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
+ if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
+ pCsr->pgno = 1;
+ pCsr->mxPgno = 0;
+ }else{
+ pCsr->mxPgno = pCsr->pgno;
+ }
+ }else{
+ assert( pCsr->pgno==1 );
+ }
+ if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
+ rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
+ return rc;
+}
+
+static int dbpageColumn(
+ sqlite3_vtab_cursor *pCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ int rc = SQLITE_OK;
+ switch( i ){
+ case 0: { /* pgno */
+ sqlite3_result_int(ctx, pCsr->pgno);
+ break;
+ }
+ case 1: { /* data */
+ DbPage *pDbPage = 0;
+ rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
+ SQLITE_TRANSIENT);
+ }
+ sqlite3PagerUnref(pDbPage);
+ break;
+ }
+ default: { /* schema */
+ sqlite3 *db = sqlite3_context_db_handle(ctx);
+ sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+ DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+ *pRowid = pCsr->pgno;
+ return SQLITE_OK;
+}
+
+static int dbpageUpdate(
+ sqlite3_vtab *pVtab,
+ int argc,
+ sqlite3_value **argv,
+ sqlite_int64 *pRowid
+){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ Pgno pgno;
+ DbPage *pDbPage = 0;
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+ const char *zSchema;
+ int iDb;
+ Btree *pBt;
+ Pager *pPager;
+ int szPage;
+
+ if( pTab->db->flags & SQLITE_Defensive ){
+ zErr = "read-only";
+ goto update_fail;
+ }
+ if( argc==1 ){
+ zErr = "cannot delete";
+ goto update_fail;
+ }
+ pgno = sqlite3_value_int(argv[0]);
+ if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
+ zErr = "cannot insert";
+ goto update_fail;
+ }
+ zSchema = (const char*)sqlite3_value_text(argv[4]);
+ iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
+ if( iDb<0 ){
+ zErr = "no such schema";
+ goto update_fail;
+ }
+ pBt = pTab->db->aDb[iDb].pBt;
+ if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
+ zErr = "bad page number";
+ goto update_fail;
+ }
+ szPage = sqlite3BtreeGetPageSize(pBt);
+ if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
+ || sqlite3_value_bytes(argv[3])!=szPage
+ ){
+ zErr = "bad page value";
+ goto update_fail;
+ }
+ pPager = sqlite3BtreePager(pBt);
+ rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerWrite(pDbPage);
+ if( rc==SQLITE_OK ){
+ memcpy(sqlite3PagerGetData(pDbPage),
+ sqlite3_value_blob(argv[3]),
+ szPage);
+ }
+ }
+ sqlite3PagerUnref(pDbPage);
+ return rc;
+
+update_fail:
+ sqlite3_free(pVtab->zErrMsg);
+ pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
+ return SQLITE_ERROR;
+}
+
+/* Since we do not know in advance which database files will be
+** written by the sqlite_dbpage virtual table, start a write transaction
+** on them all.
+*/
+static int dbpageBegin(sqlite3_vtab *pVtab){
+ DbpageTable *pTab = (DbpageTable *)pVtab;
+ sqlite3 *db = pTab->db;
+ int i;
+ for(i=0; i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0);
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Invoke this routine to register the "dbpage" virtual table module
+*/
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
+ static sqlite3_module dbpage_module = {
+ 0, /* iVersion */
+ dbpageConnect, /* xCreate */
+ dbpageConnect, /* xConnect */
+ dbpageBestIndex, /* xBestIndex */
+ dbpageDisconnect, /* xDisconnect */
+ dbpageDisconnect, /* xDestroy */
+ dbpageOpen, /* xOpen - open a cursor */
+ dbpageClose, /* xClose - close a cursor */
+ dbpageFilter, /* xFilter - configure scan constraints */
+ dbpageNext, /* xNext - advance a cursor */
+ dbpageEof, /* xEof - check for end of scan */
+ dbpageColumn, /* xColumn - read data */
+ dbpageRowid, /* xRowid - read data */
+ dbpageUpdate, /* xUpdate */
+ dbpageBegin, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0 /* xShadowName */
+ };
+ return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
+}
+#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
+
+/************** End of dbpage.c **********************************************/
/************** Begin file sqlite3session.c **********************************/
#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
@@ -171748,6 +202459,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
+static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
+
typedef struct SessionHook SessionHook;
struct SessionHook {
void *pCtx;
@@ -171769,6 +202482,7 @@ struct sqlite3_session {
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
+ sqlite3_value *pZeroBlob; /* Value containing X'' */
sqlite3_session *pNext; /* Next session object on same db. */
SessionTable *pTable; /* List of attached tables */
SessionHook hook; /* APIs to grab new and old data with */
@@ -171784,13 +202498,13 @@ struct SessionBuffer {
};
/*
-** An object of this type is used internally as an abstraction for
+** An object of this type is used internally as an abstraction for
** input data. Input data may be supplied either as a single large buffer
** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
** sqlite3changeset_start_strm()).
*/
struct SessionInput {
- int bNoDiscard; /* If true, discard no data */
+ int bNoDiscard; /* If true, do not discard in InputBuffer() */
int iCurrent; /* Offset in aData[] of current change */
int iNext; /* Offset in aData[] of next change */
u8 *aData; /* Pointer to buffer containing changeset */
@@ -171809,6 +202523,7 @@ struct sqlite3_changeset_iter {
SessionInput in; /* Input buffer or stream */
SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
int bPatchset; /* True if this is a patchset */
+ int bInvert; /* True to invert changeset */
int rc; /* Iterator error code */
sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
char *zTab; /* Current table */
@@ -171836,6 +202551,7 @@ struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
+ int bStat1; /* True if this is sqlite_stat1 */
const char **azCol; /* Column names */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
@@ -171843,11 +202559,11 @@ struct SessionTable {
SessionChange **apChange; /* Hash table buckets */
};
-/*
+/*
** RECORD FORMAT:
**
-** The following record format is similar to (but not compatible with) that
-** used in SQLite database files. This format is used as part of the
+** The following record format is similar to (but not compatible with) that
+** used in SQLite database files. This format is used as part of the
** change-set binary format, and so must be architecture independent.
**
** Unlike the SQLite database record format, each field is self-contained -
@@ -171881,7 +202597,7 @@ struct SessionTable {
** Real values:
** An 8-byte big-endian IEEE 754-2008 real value.
**
-** Varint values are encoded in the same way as varints in the SQLite
+** Varint values are encoded in the same way as varints in the SQLite
** record format.
**
** CHANGESET FORMAT:
@@ -171913,7 +202629,7 @@ struct SessionTable {
**
** The new.* record that is part of each INSERT change contains the values
** that make up the new row. Similarly, the old.* record that is part of each
-** DELETE change contains the values that made up the row that was deleted
+** DELETE change contains the values that made up the row that was deleted
** from the database. In the changeset format, the records that are part
** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
** fields.
@@ -171922,8 +202638,8 @@ struct SessionTable {
** associated with table columns that are not PRIMARY KEY columns and are
** not modified by the UPDATE change are set to "undefined". Other fields
** are set to the values that made up the row before the UPDATE that the
-** change records took place. Within the new.* record, fields associated
-** with table columns modified by the UPDATE change contain the new
+** change records took place. Within the new.* record, fields associated
+** with table columns modified by the UPDATE change contain the new
** values. Fields associated with table columns that are not modified
** are set to "undefined".
**
@@ -171949,12 +202665,12 @@ struct SessionTable {
**
** As in the changeset format, each field of the single record that is part
** of a patchset change is associated with the correspondingly positioned
-** table column, counting from left to right within the CREATE TABLE
+** table column, counting from left to right within the CREATE TABLE
** statement.
**
** For a DELETE change, all fields within the record except those associated
-** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields
-** contain the values identifying the row to delete.
+** with PRIMARY KEY columns are omitted. The PRIMARY KEY fields contain the
+** values identifying the row to delete.
**
** For an UPDATE change, all fields except those associated with PRIMARY KEY
** columns and columns that are modified by the UPDATE are set to "undefined".
@@ -171964,6 +202680,42 @@ struct SessionTable {
** The records associated with INSERT changes are in the same format as for
** changesets. It is not possible for a record associated with an INSERT
** change to contain a field set to "undefined".
+**
+** REBASE BLOB FORMAT:
+**
+** A rebase blob may be output by sqlite3changeset_apply_v2() and its
+** streaming equivalent for use with the sqlite3_rebaser APIs to rebase
+** existing changesets. A rebase blob contains one entry for each conflict
+** resolved using either the OMIT or REPLACE strategies within the apply_v2()
+** call.
+**
+** The format used for a rebase blob is very similar to that used for
+** changesets. All entries related to a single table are grouped together.
+**
+** Each group of entries begins with a table header in changeset format:
+**
+** 1 byte: Constant 0x54 (capital 'T')
+** Varint: Number of columns in the table.
+** nCol bytes: 0x01 for PK columns, 0x00 otherwise.
+** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
+**
+** Followed by one or more entries associated with the table.
+**
+** 1 byte: Either SQLITE_INSERT (0x12), DELETE (0x09).
+** 1 byte: Flag. 0x01 for REPLACE, 0x00 for OMIT.
+** record: (in the record format defined above).
+**
+** In a rebase blob, the first field is set to SQLITE_INSERT if the change
+** that caused the conflict was an INSERT or UPDATE, or to SQLITE_DELETE if
+** it was a DELETE. The second field is set to 0x01 if the conflict
+** resolution strategy was REPLACE, or 0x00 if it was OMIT.
+**
+** If the change that caused the conflict was a DELETE, then the single
+** record is a copy of the old.* record from the original changeset. If it
+** was an INSERT, then the single record is a copy of the new.* record. If
+** the conflicting change was an UPDATE, then the single record is a copy
+** of the new.* record with the PK fields filled in based on the original
+** old.* record.
*/
/*
@@ -171979,7 +202731,7 @@ struct SessionChange {
};
/*
-** Write a varint with value iVal into the buffer at aBuf. Return the
+** Write a varint with value iVal into the buffer at aBuf. Return the
** number of bytes written.
*/
static int sessionVarintPut(u8 *aBuf, int iVal){
@@ -171994,7 +202746,7 @@ static int sessionVarintLen(int iVal){
}
/*
-** Read a varint value from aBuf[] into *piVal. Return the number of
+** Read a varint value from aBuf[] into *piVal. Return the number of
** bytes read.
*/
static int sessionVarintGet(u8 *aBuf, int *piVal){
@@ -172033,34 +202785,34 @@ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
** This function is used to serialize the contents of value pValue (see
** comment titled "RECORD FORMAT" above).
**
-** If it is non-NULL, the serialized form of the value is written to
+** If it is non-NULL, the serialized form of the value is written to
** buffer aBuf. *pnWrite is set to the number of bytes written before
** returning. Or, if aBuf is NULL, the only thing this function does is
** set *pnWrite.
**
** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
-** within a call to sqlite3_value_text() (may fail if the db is utf-16))
+** within a call to sqlite3_value_text() (may fail if the db is utf-16))
** SQLITE_NOMEM is returned.
*/
static int sessionSerializeValue(
u8 *aBuf, /* If non-NULL, write serialized value here */
sqlite3_value *pValue, /* Value to serialize */
- int *pnWrite /* IN/OUT: Increment by bytes written */
+ sqlite3_int64 *pnWrite /* IN/OUT: Increment by bytes written */
){
int nByte; /* Size of serialized value in bytes */
if( pValue ){
int eType; /* Value type (SQLITE_NULL, TEXT etc.) */
-
+
eType = sqlite3_value_type(pValue);
if( aBuf ) aBuf[0] = eType;
-
+
switch( eType ){
- case SQLITE_NULL:
+ case SQLITE_NULL:
nByte = 1;
break;
-
- case SQLITE_INTEGER:
+
+ case SQLITE_INTEGER:
case SQLITE_FLOAT:
if( aBuf ){
/* TODO: SQLite does something special to deal with mixed-endian
@@ -172077,14 +202829,14 @@ static int sessionSerializeValue(
}
sessionPutI64(&aBuf[1], i);
}
- nByte = 9;
+ nByte = 9;
break;
-
+
default: {
u8 *z;
int n;
int nVarint;
-
+
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
if( eType==SQLITE_TEXT ){
z = (u8 *)sqlite3_value_text(pValue);
@@ -172094,14 +202846,12 @@ static int sessionSerializeValue(
n = sqlite3_value_bytes(pValue);
if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
nVarint = sessionVarintLen(n);
-
+
if( aBuf ){
sessionVarintPut(&aBuf[1], n);
- memcpy(&aBuf[nVarint + 1], eType==SQLITE_TEXT ?
- sqlite3_value_text(pValue) : sqlite3_value_blob(pValue), n
- );
+ if( n ) memcpy(&aBuf[nVarint + 1], z, n);
}
-
+
nByte = 1 + nVarint + n;
break;
}
@@ -172143,7 +202893,7 @@ static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
}
/*
-** Append the hash of the blob passed via the second and third arguments to
+** Append the hash of the blob passed via the second and third arguments to
** the hash-key value passed as the first. Return the new hash-key value.
*/
static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
@@ -172162,7 +202912,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
/*
** This function may only be called from within a pre-update callback.
-** It calculates a hash based on the primary key values of the old.* or
+** It calculates a hash based on the primary key values of the old.* or
** new.* row currently available and, assuming no error occurs, writes it to
** *piHash before returning. If the primary key contains one or more NULL
** values, *pbNullPK is set to true before returning.
@@ -172221,6 +202971,7 @@ static int sessionPreupdateHash(
h = sessionHashAppendBlob(h, n, z);
}else{
assert( eType==SQLITE_NULL );
+ assert( pTab->bStat1==0 || i!=1 );
*pbNullPK = 1;
}
}
@@ -172238,7 +202989,7 @@ static int sessionPreupdateHash(
static int sessionSerialLen(u8 *a){
int e = *a;
int n;
- if( e==0 ) return 1;
+ if( e==0 || e==0xFF ) return 1;
if( e==SQLITE_NULL ) return 1;
if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
return sessionVarintGet(&a[1], &n) + 1 + n;
@@ -172268,12 +203019,12 @@ static unsigned int sessionChangeHash(
int isPK = pTab->abPK[i];
if( bPkOnly && isPK==0 ) continue;
- /* It is not possible for eType to be SQLITE_NULL here. The session
+ /* It is not possible for eType to be SQLITE_NULL here. The session
** module does not record changes for rows with NULL values stored in
** primary key columns. */
- assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
- || eType==SQLITE_TEXT || eType==SQLITE_BLOB
- || eType==SQLITE_NULL || eType==0
+ assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
+ || eType==SQLITE_TEXT || eType==SQLITE_BLOB
+ || eType==SQLITE_NULL || eType==0
);
assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
@@ -172284,7 +203035,7 @@ static unsigned int sessionChangeHash(
h = sessionHashAppendI64(h, sessionGetI64(a));
a += 8;
}else{
- int n;
+ int n;
a += sessionVarintGet(a, &n);
h = sessionHashAppendBlob(h, n, a);
a += n;
@@ -172299,7 +203050,7 @@ static unsigned int sessionChangeHash(
/*
** Arguments aLeft and aRight are pointers to change records for table pTab.
** This function returns true if the two records apply to the same row (i.e.
-** have the same values stored in the primary key columns), or false
+** have the same values stored in the primary key columns), or false
** otherwise.
*/
static int sessionChangeEqual(
@@ -172318,7 +203069,7 @@ static int sessionChangeEqual(
int n1 = sessionSerialLen(a1);
int n2 = sessionSerialLen(a2);
- if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){
+ if( n1!=n2 || memcmp(a1, a2, n1) ){
return 0;
}
a1 += n1;
@@ -172336,17 +203087,17 @@ static int sessionChangeEqual(
** Arguments aLeft and aRight both point to buffers containing change
** records with nCol columns. This function "merges" the two records into
** a single records which is written to the buffer at *paOut. *paOut is
-** then set to point to one byte after the last byte written before
+** then set to point to one byte after the last byte written before
** returning.
**
-** The merging of records is done as follows: For each column, if the
+** The merging of records is done as follows: For each column, if the
** aRight record contains a value for the column, copy the value from
** their. Otherwise, if aLeft contains a value, copy it. If neither
** record contains a value for a given column, then neither does the
** output record.
*/
static void sessionMergeRecord(
- u8 **paOut,
+ u8 **paOut,
int nCol,
u8 *aLeft,
u8 *aRight
@@ -172376,13 +203127,13 @@ static void sessionMergeRecord(
/*
** This is a helper function used by sessionMergeUpdate().
**
-** When this function is called, both *paOne and *paTwo point to a value
-** within a change record. Before it returns, both have been advanced so
+** When this function is called, both *paOne and *paTwo point to a value
+** within a change record. Before it returns, both have been advanced so
** as to point to the next value in the record.
**
** If, when this function is called, *paTwo points to a valid value (i.e.
** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
-** pointer is returned and *pnVal is set to the number of bytes in the
+** pointer is returned and *pnVal is set to the number of bytes in the
** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
** set to the number of bytes in the value at *paOne. If *paOne points
** to the "no value" placeholder, *pnVal is set to 1. In other words:
@@ -172481,8 +203232,8 @@ static int sessionMergeUpdate(
aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
- if( bPatchset==0
- && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)))
+ if( bPatchset==0
+ && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)))
){
*(aOut++) = '\0';
}else{
@@ -172561,9 +203312,8 @@ static int sessionPreupdateEqual(
}else{
z = sqlite3_value_blob(pVal);
}
- if( memcmp(a, z, n) ) return 0;
+ if( n>0 && memcmp(a, z, n) ) return 0;
a += n;
- break;
}
}
}
@@ -172572,7 +203322,7 @@ static int sessionPreupdateEqual(
}
/*
-** If required, grow the hash table used to store changes on table pTab
+** If required, grow the hash table used to store changes on table pTab
** (part of the session pSession). If a fatal OOM error occurs, set the
** session object to failed and return SQLITE_ERROR. Otherwise, return
** SQLITE_OK.
@@ -172586,9 +203336,9 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
int i;
SessionChange **apNew;
- int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
+ sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128);
- apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
+ apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew);
if( apNew==0 ){
if( pTab->nChange==0 ){
return SQLITE_ERROR;
@@ -172619,9 +203369,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
/*
** This function queries the database for the names of the columns of table
-** zThis, in schema zDb. It is expected that the table has nCol columns. If
-** not, SQLITE_SCHEMA is returned and none of the output variables are
-** populated.
+** zThis, in schema zDb.
**
** Otherwise, if they are not NULL, variable *pnCol is set to the number
** of columns in the database table and variable *pzTab is set to point to a
@@ -172642,9 +203390,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
** *pabPK = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
-** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
-** pointer *pazCol should be freed to release all memory. Otherwise, pointer
-** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
+** be freed using sqlite3_free() by the caller
*/
static int sessionTableInfo(
sqlite3 *db, /* Database connection */
@@ -172658,7 +203404,7 @@ static int sessionTableInfo(
char *zPragma;
sqlite3_stmt *pStmt;
int rc;
- int nByte;
+ sqlite3_int64 nByte;
int nDbCol = 0;
int nThis;
int i;
@@ -172669,7 +203415,23 @@ static int sessionTableInfo(
assert( pazCol && pabPK );
nThis = sqlite3Strlen30(zThis);
- zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+ if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
+ rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
+ zPragma = sqlite3_mprintf(
+ "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL "
+ "SELECT 1, 'idx', '', 0, '', 2 UNION ALL "
+ "SELECT 2, 'stat', '', 0, '', 0"
+ );
+ }else if( rc==SQLITE_ERROR ){
+ zPragma = sqlite3_mprintf("");
+ }else{
+ return rc;
+ }
+ }else{
+ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+ }
if( !zPragma ) return SQLITE_NOMEM;
rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
@@ -172685,7 +203447,7 @@ static int sessionTableInfo(
if( rc==SQLITE_OK ){
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
- pAlloc = sqlite3_malloc(nByte);
+ pAlloc = sqlite3_malloc64(nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
}
@@ -172700,7 +203462,7 @@ static int sessionTableInfo(
*pzTab = (char *)pAlloc;
pAlloc += nThis+1;
}
-
+
i = 0;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
int nName = sqlite3_column_bytes(pStmt, 1);
@@ -172713,7 +203475,7 @@ static int sessionTableInfo(
i++;
}
rc = sqlite3_reset(pStmt);
-
+
}
/* If successful, populate the output variables. Otherwise, zero them and
@@ -172743,14 +203505,14 @@ static int sessionTableInfo(
** If an error occurs, an error code is stored in sqlite3_session.rc and
** non-zero returned. Or, if no error occurs but the table has no primary
** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
-** indicate that updates on this table should be ignored. SessionTable.abPK
+** indicate that updates on this table should be ignored. SessionTable.abPK
** is set to NULL in this case.
*/
static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
- pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
+ pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
);
if( pSession->rc==SQLITE_OK ){
@@ -172761,13 +203523,57 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
break;
}
}
+ if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
+ pTab->bStat1 = 1;
+ }
}
}
return (pSession->rc || pTab->abPK==0);
}
/*
-** This function is only called from with a pre-update-hook reporting a
+** Versions of the four methods in object SessionHook for use with the
+** sqlite_stat1 table. The purpose of this is to substitute a zero-length
+** blob each time a NULL value is read from the "idx" column of the
+** sqlite_stat1 table.
+*/
+typedef struct SessionStat1Ctx SessionStat1Ctx;
+struct SessionStat1Ctx {
+ SessionHook hook;
+ sqlite3_session *pSession;
+};
+static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
+ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+ sqlite3_value *pVal = 0;
+ int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
+ if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
+ pVal = p->pSession->pZeroBlob;
+ }
+ *ppVal = pVal;
+ return rc;
+}
+static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
+ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+ sqlite3_value *pVal = 0;
+ int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
+ if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
+ pVal = p->pSession->pZeroBlob;
+ }
+ *ppVal = pVal;
+ return rc;
+}
+static int sessionStat1Count(void *pCtx){
+ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+ return p->hook.xCount(p->hook.pCtx);
+}
+static int sessionStat1Depth(void *pCtx){
+ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+ return p->hook.xDepth(p->hook.pCtx);
+}
+
+
+/*
+** This function is only called from with a pre-update-hook reporting a
** change on table pTab (attached to session pSession). The type of change
** (UPDATE, INSERT, DELETE) is specified by the first argument.
**
@@ -172779,16 +203585,17 @@ static void sessionPreupdateOneChange(
sqlite3_session *pSession, /* Session object pTab is attached to */
SessionTable *pTab /* Table that change applies to */
){
- int iHash;
- int bNull = 0;
+ int iHash;
+ int bNull = 0;
int rc = SQLITE_OK;
+ SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
if( pSession->rc ) return;
/* Load table details if required */
if( sessionInitTable(pSession, pTab) ) return;
- /* Check the number of columns in this xPreUpdate call matches the
+ /* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
pSession->rc = SQLITE_SCHEMA;
@@ -172801,6 +203608,25 @@ static void sessionPreupdateOneChange(
return;
}
+ if( pTab->bStat1 ){
+ stat1.hook = pSession->hook;
+ stat1.pSession = pSession;
+ pSession->hook.pCtx = (void*)&stat1;
+ pSession->hook.xNew = sessionStat1New;
+ pSession->hook.xOld = sessionStat1Old;
+ pSession->hook.xCount = sessionStat1Count;
+ pSession->hook.xDepth = sessionStat1Depth;
+ if( pSession->pZeroBlob==0 ){
+ sqlite3_value *p = sqlite3ValueNew(0);
+ if( p==0 ){
+ rc = SQLITE_NOMEM;
+ goto error_out;
+ }
+ sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
+ pSession->pZeroBlob = p;
+ }
+ }
+
/* Calculate the hash-key for this change. If the primary key of the row
** includes a NULL value, exit early. Such changes are ignored by the
** session module. */
@@ -172819,12 +203645,12 @@ static void sessionPreupdateOneChange(
** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
** values (if this is an INSERT). */
SessionChange *pChange; /* New change object */
- int nByte; /* Number of bytes to allocate */
+ sqlite3_int64 nByte; /* Number of bytes to allocate */
int i; /* Used to iterate through columns */
-
+
assert( rc==SQLITE_OK );
pTab->nEntry++;
-
+
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
for(i=0; i<pTab->nCol; i++){
@@ -172842,9 +203668,9 @@ static void sessionPreupdateOneChange(
rc = sessionSerializeValue(0, p, &nByte);
if( rc!=SQLITE_OK ) goto error_out;
}
-
+
/* Allocate the change object */
- pChange = (SessionChange *)sqlite3_malloc(nByte);
+ pChange = (SessionChange *)sqlite3_malloc64(nByte);
if( !pChange ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -172852,7 +203678,7 @@ static void sessionPreupdateOneChange(
memset(pChange, 0, sizeof(SessionChange));
pChange->aRecord = (u8 *)&pChange[1];
}
-
+
/* Populate the change object. None of the preupdate_old(),
** preupdate_new() or SerializeValue() calls below may fail as all
** required values and encodings have already been cached in memory.
@@ -172880,8 +203706,8 @@ static void sessionPreupdateOneChange(
}else if( pC->bIndirect ){
/* If the existing change is considered "indirect", but this current
** change is "direct", mark the change object as direct. */
- if( pSession->hook.xDepth(pSession->hook.pCtx)==0
- && pSession->bIndirect==0
+ if( pSession->hook.xDepth(pSession->hook.pCtx)==0
+ && pSession->bIndirect==0
){
pC->bIndirect = 0;
}
@@ -172890,13 +203716,16 @@ static void sessionPreupdateOneChange(
/* If an error has occurred, mark the session object as failed. */
error_out:
+ if( pTab->bStat1 ){
+ pSession->hook = stat1.hook;
+ }
if( rc!=SQLITE_OK ){
pSession->rc = rc;
}
}
static int sessionFindTable(
- sqlite3_session *pSession,
+ sqlite3_session *pSession,
const char *zName,
SessionTable **ppTab
){
@@ -172913,7 +203742,7 @@ static int sessionFindTable(
/* If there is a table-filter configured, invoke it. If it returns 0,
** do not automatically add the new table. */
if( pSession->xTableFilter==0
- || pSession->xTableFilter(pSession->pFilterCtx, zName)
+ || pSession->xTableFilter(pSession->pFilterCtx, zName)
){
rc = sqlite3session_attach(pSession, zName);
if( rc==SQLITE_OK ){
@@ -172948,8 +203777,8 @@ static void xPreUpdate(
for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
SessionTable *pTab;
- /* If this session is attached to a different database ("main", "temp"
- ** etc.), or if it is not currently enabled, there is nothing to do. Skip
+ /* If this session is attached to a different database ("main", "temp"
+ ** etc.), or if it is not currently enabled, there is nothing to do. Skip
** to the next session object attached to this database. */
if( pSession->bEnable==0 ) continue;
if( pSession->rc ) continue;
@@ -173040,7 +203869,7 @@ static void sessionDiffHooks(
static char *sessionExprComparePK(
int nCol,
- const char *zDb1, const char *zDb2,
+ const char *zDb1, const char *zDb2,
const char *zTab,
const char **azCol, u8 *abPK
){
@@ -173063,7 +203892,7 @@ static char *sessionExprComparePK(
static char *sessionExprCompareOther(
int nCol,
- const char *zDb1, const char *zDb2,
+ const char *zDb1, const char *zDb2,
const char *zTab,
const char **azCol, u8 *abPK
){
@@ -173140,9 +203969,9 @@ static int sessionDiffFindNew(
}
static int sessionDiffFindModified(
- sqlite3_session *pSession,
- SessionTable *pTab,
- const char *zFrom,
+ sqlite3_session *pSession,
+ SessionTable *pTab,
+ const char *zFrom,
const char *zExpr
){
int rc = SQLITE_OK;
@@ -173226,11 +204055,12 @@ SQLITE_API int sqlite3session_diff(
if( abPK[i] ) bHasPk = 1;
}
}
-
}
sqlite3_free((char*)azCol);
if( bMismatch ){
- *pzErrMsg = sqlite3_mprintf("table schemas do not match");
+ if( pzErrMsg ){
+ *pzErrMsg = sqlite3_mprintf("table schemas do not match");
+ }
rc = SQLITE_SCHEMA;
}
if( bHasPk==0 ){
@@ -173240,7 +204070,7 @@ SQLITE_API int sqlite3session_diff(
}
if( rc==SQLITE_OK ){
- zExpr = sessionExprComparePK(pTo->nCol,
+ zExpr = sessionExprComparePK(pTo->nCol,
zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
);
}
@@ -173286,7 +204116,7 @@ SQLITE_API int sqlite3session_create(
*ppSession = 0;
/* Allocate and populate the new session object. */
- pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
+ pNew = (sqlite3_session *)sqlite3_malloc64(sizeof(sqlite3_session) + nDb + 1);
if( !pNew ) return SQLITE_NOMEM;
memset(pNew, 0, sizeof(sqlite3_session));
pNew->db = db;
@@ -173295,7 +204125,7 @@ SQLITE_API int sqlite3session_create(
memcpy(pNew->zDb, zDb, nDb+1);
sessionPreupdateHooks(pNew);
- /* Add the new session object to the linked list of session objects
+ /* Add the new session object to the linked list of session objects
** attached to database handle $db. Do this under the cover of the db
** handle mutex. */
sqlite3_mutex_enter(sqlite3_db_mutex(db));
@@ -173352,8 +204182,9 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
}
}
sqlite3_mutex_leave(sqlite3_db_mutex(db));
+ sqlite3ValueFree(pSession->pZeroBlob);
- /* Delete all attached table objects. And the contents of their
+ /* Delete all attached table objects. And the contents of their
** associated hash-tables. */
sessionDeleteTable(pSession->pTable);
@@ -173365,7 +204196,7 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
** Set a table filter on a Session Object.
*/
SQLITE_API void sqlite3session_table_filter(
- sqlite3_session *pSession,
+ sqlite3_session *pSession,
int(*xFilter)(void*, const char*),
void *pCtx /* First argument passed to xFilter */
){
@@ -173404,12 +204235,12 @@ SQLITE_API int sqlite3session_attach(
if( !pTab ){
/* Allocate new SessionTable object. */
- pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
+ pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1);
if( !pTab ){
rc = SQLITE_NOMEM;
}else{
/* Populate the new SessionTable object and link it into the list.
- ** The new object must be linked onto the end of the list, not
+ ** The new object must be linked onto the end of the list, not
** simply added to the start of it in order to ensure that tables
** appear in the correct order when a changeset or patchset is
** eventually generated. */
@@ -173434,15 +204265,15 @@ SQLITE_API int sqlite3session_attach(
** If successful, return zero. Otherwise, if an OOM condition is encountered,
** set *pRc to SQLITE_NOMEM and return non-zero.
*/
-static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
- if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
+static int sessionBufferGrow(SessionBuffer *p, size_t nByte, int *pRc){
+ if( *pRc==SQLITE_OK && (size_t)(p->nAlloc-p->nBuf)<nByte ){
u8 *aNew;
- int nNew = p->nAlloc ? p->nAlloc : 128;
+ i64 nNew = p->nAlloc ? p->nAlloc : 128;
do {
nNew = nNew*2;
- }while( nNew<(p->nBuf+nByte) );
+ }while( (size_t)(nNew-p->nBuf)<nByte );
- aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
+ aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew);
if( 0==aNew ){
*pRc = SQLITE_NOMEM;
}else{
@@ -173464,7 +204295,7 @@ static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
int rc = *pRc;
if( rc==SQLITE_OK ){
- int nByte = 0;
+ sqlite3_int64 nByte = 0;
rc = sessionSerializeValue(0, pVal, &nByte);
sessionBufferGrow(p, nByte, &rc);
if( rc==SQLITE_OK ){
@@ -173477,8 +204308,8 @@ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
}
/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a single byte to the buffer.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a single byte to the buffer.
**
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
** returning.
@@ -173490,8 +204321,8 @@ static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
}
/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a single varint to the buffer.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a single varint to the buffer.
**
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
** returning.
@@ -173503,26 +204334,26 @@ static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
}
/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwise, append a blob of data to the buffer.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a blob of data to the buffer.
**
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
** returning.
*/
static void sessionAppendBlob(
- SessionBuffer *p,
- const u8 *aBlob,
- int nBlob,
+ SessionBuffer *p,
+ const u8 *aBlob,
+ int nBlob,
int *pRc
){
- if( 0==sessionBufferGrow(p, nBlob, pRc) ){
+ if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
p->nBuf += nBlob;
}
}
/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append a string to the buffer. All bytes in the string
** up to (but not including) the nul-terminator are written to the buffer.
**
@@ -173530,8 +204361,8 @@ static void sessionAppendBlob(
** returning.
*/
static void sessionAppendStr(
- SessionBuffer *p,
- const char *zStr,
+ SessionBuffer *p,
+ const char *zStr,
int *pRc
){
int nStr = sqlite3Strlen30(zStr);
@@ -173542,7 +204373,7 @@ static void sessionAppendStr(
}
/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string representation of integer iVal
** to the buffer. No nul-terminator is written.
**
@@ -173560,9 +204391,9 @@ static void sessionAppendInteger(
}
/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string zStr enclosed in quotes (") and
-** with any embedded quote characters escaped to the buffer. No
+** with any embedded quote characters escaped to the buffer. No
** nul-terminator byte is written.
**
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
@@ -173635,8 +204466,8 @@ static void sessionAppendCol(
/*
**
-** This function appends an update change to the buffer (see the comments
-** under "CHANGESET FORMAT" at the top of the file). An update change
+** This function appends an update change to the buffer (see the comments
+** under "CHANGESET FORMAT" at the top of the file). An update change
** consists of:
**
** 1 byte: SQLITE_UPDATE (0x17)
@@ -173651,10 +204482,10 @@ static void sessionAppendCol(
** If all of the old.* values are equal to their corresponding new.* value
** (i.e. nothing has changed), then no data at all is appended to the buffer.
**
-** Otherwise, the old.* record contains all primary key values and the
-** original values of any fields that have been modified. The new.* record
+** Otherwise, the old.* record contains all primary key values and the
+** original values of any fields that have been modified. The new.* record
** contains the new values of only those fields that have been modified.
-*/
+*/
static int sessionAppendUpdate(
SessionBuffer *pBuf, /* Buffer to append to */
int bPatchset, /* True for "patchset", 0 for "changeset" */
@@ -173701,13 +204532,13 @@ static int sessionAppendUpdate(
}
default: {
- int nByte;
- int nHdr = 1 + sessionVarintGet(&pCsr[1], &nByte);
+ int n;
+ int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
- nAdvance = nHdr + nByte;
- if( eType==sqlite3_column_type(pStmt, i)
- && nByte==sqlite3_column_bytes(pStmt, i)
- && 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), nByte)
+ nAdvance = nHdr + n;
+ if( eType==sqlite3_column_type(pStmt, i)
+ && n==sqlite3_column_bytes(pStmt, i)
+ && (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
){
break;
}
@@ -173819,28 +204650,42 @@ static int sessionSelectStmt(
sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */
){
int rc = SQLITE_OK;
- int i;
- const char *zSep = "";
- SessionBuffer buf = {0, 0, 0};
+ char *zSql = 0;
+ int nSql = -1;
- sessionAppendStr(&buf, "SELECT * FROM ", &rc);
- sessionAppendIdent(&buf, zDb, &rc);
- sessionAppendStr(&buf, ".", &rc);
- sessionAppendIdent(&buf, zTab, &rc);
- sessionAppendStr(&buf, " WHERE ", &rc);
- for(i=0; i<nCol; i++){
- if( abPK[i] ){
- sessionAppendStr(&buf, zSep, &rc);
- sessionAppendIdent(&buf, azCol[i], &rc);
- sessionAppendStr(&buf, " = ?", &rc);
- sessionAppendInteger(&buf, i+1, &rc);
- zSep = " AND ";
+ if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
+ zSql = sqlite3_mprintf(
+ "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
+ "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
+ );
+ if( zSql==0 ) rc = SQLITE_NOMEM;
+ }else{
+ int i;
+ const char *zSep = "";
+ SessionBuffer buf = {0, 0, 0};
+
+ sessionAppendStr(&buf, "SELECT * FROM ", &rc);
+ sessionAppendIdent(&buf, zDb, &rc);
+ sessionAppendStr(&buf, ".", &rc);
+ sessionAppendIdent(&buf, zTab, &rc);
+ sessionAppendStr(&buf, " WHERE ", &rc);
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ sessionAppendStr(&buf, zSep, &rc);
+ sessionAppendIdent(&buf, azCol[i], &rc);
+ sessionAppendStr(&buf, " IS ?", &rc);
+ sessionAppendInteger(&buf, i+1, &rc);
+ zSep = " AND ";
+ }
}
+ zSql = (char*)buf.aBuf;
+ nSql = buf.nBuf;
}
+
if( rc==SQLITE_OK ){
- rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
+ rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
}
- sqlite3_free(buf.aBuf);
+ sqlite3_free(zSql);
return rc;
}
@@ -173919,7 +204764,7 @@ static int sessionSelectBind(
/*
** This function is a no-op if *pRc is set to other than SQLITE_OK when it
-** is called. Otherwise, append a serialized table header (part of the binary
+** is called. Otherwise, append a serialized table header (part of the binary
** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
** SQLite error code before returning.
*/
@@ -173943,7 +204788,7 @@ static void sessionAppendTableHdr(
**
** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
-** occurs, an SQLite error code is returned and both output variables set
+** occurs, an SQLite error code is returned and both output variables set
** to 0.
*/
static int sessionGenerateChangeset(
@@ -174026,12 +204871,12 @@ static int sessionGenerateChangeset(
rc = sqlite3_reset(pSel);
}
- /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
+ /* If the buffer is now larger than sessions_strm_chunk_size, pass
** its contents to the xOutput() callback. */
- if( xOutput
- && rc==SQLITE_OK
- && buf.nBuf>nNoop
- && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE
+ if( xOutput
+ && rc==SQLITE_OK
+ && buf.nBuf>nNoop
+ && buf.nBuf>sessions_strm_chunk_size
){
rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
nNoop = -1;
@@ -174066,10 +204911,10 @@ static int sessionGenerateChangeset(
}
/*
-** Obtain a changeset object containing all changes recorded by the
+** Obtain a changeset object containing all changes recorded by the
** session object passed as the first argument.
**
-** It is the responsibility of the caller to eventually free the buffer
+** It is the responsibility of the caller to eventually free the buffer
** using sqlite3_free().
*/
SQLITE_API int sqlite3session_changeset(
@@ -174103,10 +204948,10 @@ SQLITE_API int sqlite3session_patchset_strm(
}
/*
-** Obtain a patchset object containing all changes recorded by the
+** Obtain a patchset object containing all changes recorded by the
** session object passed as the first argument.
**
-** It is the responsibility of the caller to eventually free the buffer
+** It is the responsibility of the caller to eventually free the buffer
** using sqlite3_free().
*/
SQLITE_API int sqlite3session_patchset(
@@ -174170,7 +205015,8 @@ static int sessionChangesetStart(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int nChangeset, /* Size of buffer pChangeset in bytes */
- void *pChangeset /* Pointer to buffer containing changeset */
+ void *pChangeset, /* Pointer to buffer containing changeset */
+ int bInvert /* True to invert changeset */
){
sqlite3_changeset_iter *pRet; /* Iterator to return */
int nByte; /* Number of bytes to allocate for iterator */
@@ -174190,6 +205036,7 @@ static int sessionChangesetStart(
pRet->in.xInput = xInput;
pRet->in.pIn = pIn;
pRet->in.bEof = (xInput ? 0 : 1);
+ pRet->bInvert = bInvert;
/* Populate the output variable and return success. */
*pp = pRet;
@@ -174204,7 +205051,16 @@ SQLITE_API int sqlite3changeset_start(
int nChangeset, /* Size of buffer pChangeset in bytes */
void *pChangeset /* Pointer to buffer containing changeset */
){
- return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
+ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0);
+}
+SQLITE_API int sqlite3changeset_start_v2(
+ sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
+ int nChangeset, /* Size of buffer pChangeset in bytes */
+ void *pChangeset, /* Pointer to buffer containing changeset */
+ int flags
+){
+ int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
+ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert);
}
/*
@@ -174215,7 +205071,16 @@ SQLITE_API int sqlite3changeset_start_strm(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
){
- return sessionChangesetStart(pp, xInput, pIn, 0, 0);
+ return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0);
+}
+SQLITE_API int sqlite3changeset_start_v2_strm(
+ sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int flags
+){
+ int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
+ return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert);
}
/*
@@ -174223,7 +205088,7 @@ SQLITE_API int sqlite3changeset_start_strm(
** object and the buffer is full, discard some data to free up space.
*/
static void sessionDiscardData(SessionInput *pIn){
- if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
+ if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){
int nMove = pIn->buf.nBuf - pIn->iNext;
assert( nMove>=0 );
if( nMove>0 ){
@@ -174246,7 +205111,7 @@ static int sessionInputBuffer(SessionInput *pIn, int nByte){
int rc = SQLITE_OK;
if( pIn->xInput ){
while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
- int nNew = SESSIONS_STRM_CHUNK_SIZE;
+ int nNew = sessions_strm_chunk_size;
if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
@@ -174292,7 +205157,7 @@ static void sessionSkipRecord(
/*
** This function sets the value of the sqlite3_value object passed as the
-** first argument to a copy of the string or blob held in the aData[]
+** first argument to a copy of the string or blob held in the aData[]
** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
** error occurs.
*/
@@ -174303,10 +205168,10 @@ static int sessionValueSetStr(
u8 enc /* String encoding (0 for blobs) */
){
/* In theory this code could just pass SQLITE_TRANSIENT as the final
- ** argument to sqlite3ValueSetStr() and have the copy created
+ ** argument to sqlite3ValueSetStr() and have the copy created
** automatically. But doing so makes it difficult to detect any OOM
** error. Hence the code to create the copy externally. */
- u8 *aCopy = sqlite3_malloc(nData+1);
+ u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1);
if( aCopy==0 ) return SQLITE_NOMEM;
memcpy(aCopy, aData, nData);
sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
@@ -174351,13 +205216,16 @@ static int sessionReadRecord(
if( abPK && abPK[i]==0 ) continue;
rc = sessionInputBuffer(pIn, 9);
if( rc==SQLITE_OK ){
- eType = pIn->aData[pIn->iNext++];
- }
-
- assert( apOut[i]==0 );
- if( eType ){
- apOut[i] = sqlite3ValueNew(0);
- if( !apOut[i] ) rc = SQLITE_NOMEM;
+ if( pIn->iNext>=pIn->nData ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ eType = pIn->aData[pIn->iNext++];
+ assert( apOut[i]==0 );
+ if( eType ){
+ apOut[i] = sqlite3ValueNew(0);
+ if( !apOut[i] ) rc = SQLITE_NOMEM;
+ }
+ }
}
if( rc==SQLITE_OK ){
@@ -174367,10 +205235,14 @@ static int sessionReadRecord(
pIn->iNext += sessionVarintGet(aVal, &nByte);
rc = sessionInputBuffer(pIn, nByte);
if( rc==SQLITE_OK ){
- u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
- rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
+ if( nByte<0 || nByte>pIn->nData-pIn->iNext ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
+ rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
+ pIn->iNext += nByte;
+ }
}
- pIn->iNext += nByte;
}
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
sqlite3_int64 v = sessionGetI64(aVal);
@@ -174397,7 +205269,7 @@ static int sessionReadRecord(
** + array of PK flags (1 byte per column),
** + table name (nul terminated).
**
-** This function ensures that all of the above is present in the input
+** This function ensures that all of the above is present in the input
** buffer (i.e. that it can be accessed without any calls to xInput()).
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
** The input pointer is not moved.
@@ -174410,8 +205282,19 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
rc = sessionInputBuffer(pIn, 9);
if( rc==SQLITE_OK ){
nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
- rc = sessionInputBuffer(pIn, nRead+nCol+100);
- nRead += nCol;
+ /* The hard upper limit for the number of columns in an SQLite
+ ** database table is, according to sqliteLimit.h, 32676. So
+ ** consider any table-header that purports to have more than 65536
+ ** columns to be corrupt. This is convenient because otherwise,
+ ** if the (nCol>65536) condition below were omitted, a sufficiently
+ ** large value for nCol may cause nRead to wrap around and become
+ ** negative. Leading to a crash. */
+ if( nCol<0 || nCol>65536 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = sessionInputBuffer(pIn, nRead+nCol+100);
+ nRead += nCol;
+ }
}
while( rc==SQLITE_OK ){
@@ -174469,8 +205352,8 @@ static int sessionChangesetBufferRecord(
** + array of PK flags (1 byte per column),
** + table name (nul terminated).
**
-** This function decodes the table-header and populates the p->nCol,
-** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is
+** This function decodes the table-header and populates the p->nCol,
+** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is
** also allocated or resized according to the new value of p->nCol. The
** input pointer is left pointing to the byte following the table header.
**
@@ -174488,23 +205371,32 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
int nByte;
int nVarint;
nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
- nCopy -= nVarint;
- p->in.iNext += nVarint;
- nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
- p->tblhdr.nBuf = 0;
- sessionBufferGrow(&p->tblhdr, nByte, &rc);
+ if( p->nCol>0 ){
+ nCopy -= nVarint;
+ p->in.iNext += nVarint;
+ nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
+ p->tblhdr.nBuf = 0;
+ sessionBufferGrow(&p->tblhdr, nByte, &rc);
+ }else{
+ rc = SQLITE_CORRUPT_BKPT;
+ }
}
if( rc==SQLITE_OK ){
- int iPK = sizeof(sqlite3_value*)*p->nCol*2;
+ size_t iPK = sizeof(sqlite3_value*)*p->nCol*2;
memset(p->tblhdr.aBuf, 0, iPK);
memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
p->in.iNext += nCopy;
}
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
- p->abPK = (u8*)&p->apValue[p->nCol*2];
- p->zTab = (char*)&p->abPK[p->nCol];
+ if( p->apValue==0 ){
+ p->abPK = 0;
+ p->zTab = 0;
+ }else{
+ p->abPK = (u8*)&p->apValue[p->nCol*2];
+ p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
+ }
return (p->rc = rc);
}
@@ -174519,15 +205411,16 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
** record is written to *paRec before returning and the number of bytes in
** the record to *pnRec.
**
-** Either way, this function returns SQLITE_ROW if the iterator is
-** successfully advanced to the next change in the changeset, an SQLite
-** error code if an error occurs, or SQLITE_DONE if there are no further
+** Either way, this function returns SQLITE_ROW if the iterator is
+** successfully advanced to the next change in the changeset, an SQLite
+** error code if an error occurs, or SQLITE_DONE if there are no further
** changes in the changeset.
*/
static int sessionChangesetNext(
sqlite3_changeset_iter *p, /* Changeset iterator */
u8 **paRec, /* If non-NULL, store record pointer here */
- int *pnRec /* If non-NULL, store size of record here */
+ int *pnRec, /* If non-NULL, store size of record here */
+ int *pbNew /* If non-NULL, true if new table */
){
int i;
u8 op;
@@ -174561,21 +205454,30 @@ static int sessionChangesetNext(
p->in.iCurrent = p->in.iNext;
op = p->in.aData[p->in.iNext++];
- if( op=='T' || op=='P' ){
+ while( op=='T' || op=='P' ){
+ if( pbNew ) *pbNew = 1;
p->bPatchset = (op=='P');
if( sessionChangesetReadTblhdr(p) ) return p->rc;
if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
p->in.iCurrent = p->in.iNext;
+ if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
op = p->in.aData[p->in.iNext++];
}
+ if( p->zTab==0 || (p->bPatchset && p->bInvert) ){
+ /* The first record in the changeset is not a table header. Must be a
+ ** corrupt changeset. */
+ assert( p->in.iNext==1 || p->zTab );
+ return (p->rc = SQLITE_CORRUPT_BKPT);
+ }
+
p->op = op;
p->bIndirect = p->in.aData[p->in.iNext++];
if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
return (p->rc = SQLITE_CORRUPT_BKPT);
}
- if( paRec ){
+ if( paRec ){
int nVal; /* Number of values to buffer */
if( p->bPatchset==0 && op==SQLITE_UPDATE ){
nVal = p->nCol * 2;
@@ -174590,33 +205492,39 @@ static int sessionChangesetNext(
*paRec = &p->in.aData[p->in.iNext];
p->in.iNext += *pnRec;
}else{
+ sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue);
+ sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]);
/* If this is an UPDATE or DELETE, read the old.* record. */
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
u8 *abPK = p->bPatchset ? p->abPK : 0;
- p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
+ p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld);
if( p->rc!=SQLITE_OK ) return p->rc;
}
/* If this is an INSERT or UPDATE, read the new.* record. */
if( p->op!=SQLITE_DELETE ){
- p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
+ p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew);
if( p->rc!=SQLITE_OK ) return p->rc;
}
- if( p->bPatchset && p->op==SQLITE_UPDATE ){
+ if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){
/* If this is an UPDATE that is part of a patchset, then all PK and
** modified fields are present in the new.* record. The old.* record
** is currently completely empty. This block shifts the PK fields from
** new.* to old.*, to accommodate the code that reads these arrays. */
for(i=0; i<p->nCol; i++){
- assert( p->apValue[i]==0 );
- assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
+ assert( p->bPatchset==0 || p->apValue[i]==0 );
if( p->abPK[i] ){
+ assert( p->apValue[i]==0 );
p->apValue[i] = p->apValue[i+p->nCol];
+ if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT);
p->apValue[i+p->nCol] = 0;
}
}
+ }else if( p->bInvert ){
+ if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
+ else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
}
}
@@ -174632,7 +205540,7 @@ static int sessionChangesetNext(
** callback by changeset_apply().
*/
SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){
- return sessionChangesetNext(p, 0, 0);
+ return sessionChangesetNext(p, 0, 0, 0);
}
/*
@@ -174736,7 +205644,7 @@ SQLITE_API int sqlite3changeset_new(
/*
** This function may only be called with a changeset iterator that has been
-** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
+** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
**
** If successful, *ppValue is set to point to an sqlite3_value structure
@@ -174753,7 +205661,7 @@ SQLITE_API int sqlite3changeset_conflict(
if( !pIter->pConflict ){
return SQLITE_MISUSE;
}
- if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){
+ if( iVal<0 || iVal>=pIter->nCol ){
return SQLITE_RANGE;
}
*ppValue = sqlite3_column_value(pIter->pConflict, iVal);
@@ -174881,7 +205789,7 @@ static int sessionChangesetInvert(
int iCol;
if( 0==apVal ){
- apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
+ apVal = (sqlite3_value **)sqlite3_malloc64(sizeof(apVal[0])*nCol*2);
if( 0==apVal ){
rc = SQLITE_NOMEM;
goto finished_invert;
@@ -174933,7 +205841,7 @@ static int sessionChangesetInvert(
}
assert( rc==SQLITE_OK );
- if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
+ if( xOutput && sOut.nBuf>=sessions_strm_chunk_size ){
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
sOut.nBuf = 0;
if( rc!=SQLITE_OK ) goto finished_invert;
@@ -175008,9 +205916,13 @@ struct SessionApplyCtx {
int nCol; /* Size of azCol[] and abPK[] arrays */
const char **azCol; /* Array of column names */
u8 *abPK; /* Boolean array - true if column is in PK */
-
+ int bStat1; /* True if table is sqlite_stat1 */
int bDeferConstraints; /* True to defer constraints */
+ int bInvertConstraints; /* Invert when iterating constraints buffer */
SessionBuffer constraints; /* Deferred constraints are stored here */
+ SessionBuffer rebase; /* Rebase information (if any) here */
+ u8 bRebaseStarted; /* If table header is already in rebase */
+ u8 bRebase; /* True to collect rebase information */
};
/*
@@ -175041,7 +205953,7 @@ static int sessionDeleteRow(
SessionBuffer buf = {0, 0, 0};
int nPk = 0;
- sessionAppendStr(&buf, "DELETE FROM ", &rc);
+ sessionAppendStr(&buf, "DELETE FROM main.", &rc);
sessionAppendIdent(&buf, zTab, &rc);
sessionAppendStr(&buf, " WHERE ", &rc);
@@ -175083,7 +205995,7 @@ static int sessionDeleteRow(
}
/*
-** Formulate and prepare a statement to UPDATE a row from database db.
+** Formulate and prepare a statement to UPDATE a row from database db.
** Assuming a table structure like this:
**
** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
@@ -175095,7 +206007,7 @@ static int sessionDeleteRow(
** b = CASE WHEN ?5 THEN ?6 ELSE b END,
** c = CASE WHEN ?8 THEN ?9 ELSE c END,
** d = CASE WHEN ?11 THEN ?12 ELSE d END
-** WHERE a = ?1 AND c = ?7 AND (?13 OR
+** WHERE a = ?1 AND c = ?7 AND (?13 OR
** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
** )
**
@@ -175124,7 +206036,7 @@ static int sessionUpdateRow(
SessionBuffer buf = {0, 0, 0};
/* Append "UPDATE tbl SET " */
- sessionAppendStr(&buf, "UPDATE ", &rc);
+ sessionAppendStr(&buf, "UPDATE main.", &rc);
sessionAppendIdent(&buf, zTab, &rc);
sessionAppendStr(&buf, " SET ", &rc);
@@ -175178,6 +206090,7 @@ static int sessionUpdateRow(
return rc;
}
+
/*
** Formulate and prepare an SQL statement to query table zTab by primary
** key. Assuming the following table structure:
@@ -175220,7 +206133,13 @@ static int sessionInsertRow(
sessionAppendStr(&buf, "INSERT INTO main.", &rc);
sessionAppendIdent(&buf, zTab, &rc);
- sessionAppendStr(&buf, " VALUES(?", &rc);
+ sessionAppendStr(&buf, "(", &rc);
+ for(i=0; i<p->nCol; i++){
+ if( i!=0 ) sessionAppendStr(&buf, ", ", &rc);
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ }
+
+ sessionAppendStr(&buf, ") VALUES(?", &rc);
for(i=1; i<p->nCol; i++){
sessionAppendStr(&buf, ", ?", &rc);
}
@@ -175233,8 +206152,48 @@ static int sessionInsertRow(
return rc;
}
+static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
+ return sqlite3_prepare_v2(db, zSql, -1, pp, 0);
+}
+
+/*
+** Prepare statements for applying changes to the sqlite_stat1 table.
+** These are similar to those created by sessionSelectRow(),
+** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for
+** other tables.
+*/
+static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
+ int rc = sessionSelectRow(db, "sqlite_stat1", p);
+ if( rc==SQLITE_OK ){
+ rc = sessionPrepare(db, &p->pInsert,
+ "INSERT INTO main.sqlite_stat1 VALUES(?1, "
+ "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
+ "?3)"
+ );
+ }
+ if( rc==SQLITE_OK ){
+ rc = sessionPrepare(db, &p->pUpdate,
+ "UPDATE main.sqlite_stat1 SET "
+ "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
+ "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
+ "stat = CASE WHEN ?8 THEN ?9 ELSE stat END "
+ "WHERE tbl=?1 AND idx IS "
+ "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
+ "AND (?10 OR ?8=0 OR stat IS ?7)"
+ );
+ }
+ if( rc==SQLITE_OK ){
+ rc = sessionPrepare(db, &p->pDelete,
+ "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
+ "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
+ "AND (?4 OR stat IS ?3)"
+ );
+ }
+ return rc;
+}
+
/*
-** A wrapper around sqlite3_bind_value() that detects an extra problem.
+** A wrapper around sqlite3_bind_value() that detects an extra problem.
** See comments in the body of this function for details.
*/
static int sessionBindValue(
@@ -175257,15 +206216,15 @@ static int sessionBindValue(
}
/*
-** Iterator pIter must point to an SQLITE_INSERT entry. This function
+** Iterator pIter must point to an SQLITE_INSERT entry. This function
** transfers new.* values from the current iterator entry to statement
** pStmt. The table being inserted into has nCol columns.
**
-** New.* value $i from the iterator is bound to variable ($i+1) of
+** New.* value $i from the iterator is bound to variable ($i+1) of
** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
** are transfered to the statement. Otherwise, if abPK is not NULL, it points
-** to an array nCol elements in size. In this case only those values for
-** which abPK[$i] is true are read from the iterator and bound to the
+** to an array nCol elements in size. In this case only those values for
+** which abPK[$i] is true are read from the iterator and bound to the
** statement.
**
** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
@@ -175281,8 +206240,8 @@ static int sessionBindRow(
int rc = SQLITE_OK;
/* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
- ** argument iterator points to a suitable entry. Make sure that xValue
- ** is one of these to guarantee that it is safe to ignore the return
+ ** argument iterator points to a suitable entry. Make sure that xValue
+ ** is one of these to guarantee that it is safe to ignore the return
** in the code below. */
assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
@@ -175290,7 +206249,13 @@ static int sessionBindRow(
if( !abPK || abPK[i] ){
sqlite3_value *pVal;
(void)xValue(pIter, i, &pVal);
- rc = sessionBindValue(pStmt, i+1, pVal);
+ if( pVal==0 ){
+ /* The value in the changeset was "undefined". This indicates a
+ ** corrupt changeset blob. */
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = sessionBindValue(pStmt, i+1, pVal);
+ }
}
}
return rc;
@@ -175300,18 +206265,18 @@ static int sessionBindRow(
** SQL statement pSelect is as generated by the sessionSelectRow() function.
** This function binds the primary key values from the change that changeset
** iterator pIter points to to the SELECT and attempts to seek to the table
-** entry. If a row is found, the SELECT statement left pointing at the row
+** entry. If a row is found, the SELECT statement left pointing at the row
** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
** has occured, the statement is reset and SQLITE_OK is returned. If an
** error occurs, the statement is reset and an SQLite error code is returned.
**
-** If this function returns SQLITE_ROW, the caller must eventually reset()
+** If this function returns SQLITE_ROW, the caller must eventually reset()
** statement pSelect. If any other value is returned, the statement does
** not require a reset().
**
** If the iterator currently points to an INSERT record, bind values from the
** new.* record to the SELECT statement. Or, if it points to a DELETE or
-** UPDATE, bind values from the old.* record.
+** UPDATE, bind values from the old.* record.
*/
static int sessionSeekToRow(
sqlite3 *db, /* Database handle */
@@ -175325,7 +206290,7 @@ static int sessionSeekToRow(
const char *zDummy; /* Unused */
sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
- rc = sessionBindRow(pIter,
+ rc = sessionBindRow(pIter,
op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
nCol, abPK, pSelect
);
@@ -175339,6 +206304,55 @@ static int sessionSeekToRow(
}
/*
+** This function is called from within sqlite3changeset_apply_v2() when
+** a conflict is encountered and resolved using conflict resolution
+** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE)..
+** It adds a conflict resolution record to the buffer in
+** SessionApplyCtx.rebase, which will eventually be returned to the caller
+** of apply_v2() as the "rebase" buffer.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
+*/
+static int sessionRebaseAdd(
+ SessionApplyCtx *p, /* Apply context */
+ int eType, /* Conflict resolution (OMIT or REPLACE) */
+ sqlite3_changeset_iter *pIter /* Iterator pointing at current change */
+){
+ int rc = SQLITE_OK;
+ if( p->bRebase ){
+ int i;
+ int eOp = pIter->op;
+ if( p->bRebaseStarted==0 ){
+ /* Append a table-header to the rebase buffer */
+ const char *zTab = pIter->zTab;
+ sessionAppendByte(&p->rebase, 'T', &rc);
+ sessionAppendVarint(&p->rebase, p->nCol, &rc);
+ sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc);
+ sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc);
+ p->bRebaseStarted = 1;
+ }
+
+ assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
+ assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
+
+ sessionAppendByte(&p->rebase,
+ (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
+ );
+ sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
+ for(i=0; i<p->nCol; i++){
+ sqlite3_value *pVal = 0;
+ if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){
+ sqlite3changeset_old(pIter, i, &pVal);
+ }else{
+ sqlite3changeset_new(pIter, i, &pVal);
+ }
+ sessionAppendValue(&p->rebase, pVal, &rc);
+ }
+ }
+ return rc;
+}
+
+/*
** Invoke the conflict handler for the change that the changeset iterator
** currently points to.
**
@@ -175369,7 +206383,7 @@ static int sessionSeekToRow(
** is set to non-zero before returning SQLITE_OK.
**
** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
-** returned. Or, if the conflict handler returns an invalid value,
+** returned. Or, if the conflict handler returns an invalid value,
** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
** this function returns SQLITE_OK.
*/
@@ -175413,7 +206427,7 @@ static int sessionConflictHandler(
u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
int nBlob = pIter->in.iNext - pIter->in.iCurrent;
sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
- res = SQLITE_CHANGESET_OMIT;
+ return SQLITE_OK;
}else{
/* No other row with the new.* primary key. */
res = xConflict(pCtx, eType+1, pIter);
@@ -175439,6 +206453,9 @@ static int sessionConflictHandler(
rc = SQLITE_MISUSE;
break;
}
+ if( rc==SQLITE_OK ){
+ rc = sessionRebaseAdd(p, res, pIter);
+ }
}
return rc;
@@ -175456,16 +206473,16 @@ static int sessionConflictHandler(
** to true before returning. In this case the caller will invoke this function
** again, this time with pbRetry set to NULL.
**
-** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
+** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
** before retrying. In this case the caller attempts to remove the conflicting
-** row before invoking this function again, this time with pbReplace set
+** row before invoking this function again, this time with pbReplace set
** to NULL.
**
** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
-** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
+** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
** returned.
*/
static int sessionApplyOneOp(
@@ -175563,11 +206580,25 @@ static int sessionApplyOneOp(
}else{
assert( op==SQLITE_INSERT );
- rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
- if( rc!=SQLITE_OK ) return rc;
+ if( p->bStat1 ){
+ /* Check if there is a conflicting row. For sqlite_stat1, this needs
+ ** to be done using a SELECT, as there is no PRIMARY KEY in the
+ ** database schema to throw an exception if a duplicate is inserted. */
+ rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+ if( rc==SQLITE_ROW ){
+ rc = SQLITE_CONSTRAINT;
+ sqlite3_reset(p->pSelect);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
+ if( rc!=SQLITE_OK ) return rc;
+
+ sqlite3_step(p->pInsert);
+ rc = sqlite3_reset(p->pInsert);
+ }
- sqlite3_step(p->pInsert);
- rc = sqlite3_reset(p->pInsert);
if( (rc&0xff)==SQLITE_CONSTRAINT ){
rc = sessionConflictHandler(
SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
@@ -175584,7 +206615,7 @@ static int sessionApplyOneOp(
** the conflict handler callback.
**
** The difference between this function and sessionApplyOne() is that this
-** function handles the case where the conflict-handler is invoked and
+** function handles the case where the conflict-handler is invoked and
** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
** retried in some manner.
*/
@@ -175600,42 +206631,42 @@ static int sessionApplyOneWithRetry(
int rc;
rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
- assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) );
-
- /* If the bRetry flag is set, the change has not been applied due to an
- ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
- ** a row with the correct PK is present in the db, but one or more other
- ** fields do not contain the expected values) and the conflict handler
- ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
- ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
- ** the SQLITE_CHANGESET_DATA problem. */
- if( bRetry ){
- assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
- rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
- }
-
- /* If the bReplace flag is set, the change is an INSERT that has not
- ** been performed because the database already contains a row with the
- ** specified primary key and the conflict handler returned
- ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
- ** before reattempting the INSERT. */
- else if( bReplace ){
- assert( pIter->op==SQLITE_INSERT );
- rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sessionBindRow(pIter,
- sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
- sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
- }
- if( rc==SQLITE_OK ){
- sqlite3_step(pApply->pDelete);
- rc = sqlite3_reset(pApply->pDelete);
- }
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
+ /* If the bRetry flag is set, the change has not been applied due to an
+ ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
+ ** a row with the correct PK is present in the db, but one or more other
+ ** fields do not contain the expected values) and the conflict handler
+ ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
+ ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
+ ** the SQLITE_CHANGESET_DATA problem. */
+ if( bRetry ){
+ assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
}
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
+
+ /* If the bReplace flag is set, the change is an INSERT that has not
+ ** been performed because the database already contains a row with the
+ ** specified primary key and the conflict handler returned
+ ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
+ ** before reattempting the INSERT. */
+ else if( bReplace ){
+ assert( pIter->op==SQLITE_INSERT );
+ rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sessionBindRow(pIter,
+ sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
+ sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pApply->pDelete);
+ rc = sqlite3_reset(pApply->pDelete);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
+ }
}
}
@@ -175646,7 +206677,7 @@ static int sessionApplyOneWithRetry(
** Retry the changes accumulated in the pApply->constraints buffer.
*/
static int sessionRetryConstraints(
- sqlite3 *db,
+ sqlite3 *db,
int bPatchset,
const char *zTab,
SessionApplyCtx *pApply,
@@ -175660,9 +206691,11 @@ static int sessionRetryConstraints(
SessionBuffer cons = pApply->constraints;
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
- rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
+ rc = sessionChangesetStart(
+ &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints
+ );
if( rc==SQLITE_OK ){
- int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
+ size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
int rc2;
pIter2->bPatchset = bPatchset;
pIter2->zTab = (char*)zTab;
@@ -175694,7 +206727,7 @@ static int sessionRetryConstraints(
/*
** Argument pIter is a changeset iterator that has been initialized, but
-** not yet passed to sqlite3changeset_next(). This function applies the
+** not yet passed to sqlite3changeset_next(). This function applies the
** changeset to the main database attached to handle "db". The supplied
** conflict handler callback is invoked to resolve any conflicts encountered
** while applying the change.
@@ -175711,10 +206744,12 @@ static int sessionChangesetApply(
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
- void *pCtx /* First argument passed to xConflict */
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase, /* OUT: Rebase information */
+ int flags /* SESSION_APPLY_XXX flags */
){
int schemaMismatch = 0;
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
const char *zTab = 0; /* Name of current table */
int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
SessionApplyCtx sApply; /* changeset_apply() context object */
@@ -175724,8 +206759,12 @@ static int sessionChangesetApply(
pIter->in.bNoDiscard = 1;
memset(&sApply, 0, sizeof(sApply));
+ sApply.bRebase = (ppRebase && pnRebase);
+ sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
sqlite3_mutex_enter(sqlite3_db_mutex(db));
- rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
+ if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
+ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
+ }
if( rc==SQLITE_OK ){
rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
}
@@ -175733,7 +206772,7 @@ static int sessionChangesetApply(
int nCol;
int op;
const char *zNew;
-
+
sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
@@ -175746,14 +206785,23 @@ static int sessionChangesetApply(
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
sqlite3_finalize(sApply.pDelete);
- sqlite3_finalize(sApply.pUpdate);
+ sqlite3_finalize(sApply.pUpdate);
sqlite3_finalize(sApply.pInsert);
sqlite3_finalize(sApply.pSelect);
- memset(&sApply, 0, sizeof(sApply));
sApply.db = db;
+ sApply.pDelete = 0;
+ sApply.pUpdate = 0;
+ sApply.pInsert = 0;
+ sApply.pSelect = 0;
+ sApply.nCol = 0;
+ sApply.azCol = 0;
+ sApply.abPK = 0;
+ sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
+ sApply.bRebaseStarted = 0;
+ memset(&sApply.constraints, 0, sizeof(SessionBuffer));
- /* If an xFilter() callback was specified, invoke it now. If the
+ /* If an xFilter() callback was specified, invoke it now. If the
** xFilter callback returns zero, skip this table. If it returns
** non-zero, proceed. */
schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
@@ -175766,38 +206814,55 @@ static int sessionChangesetApply(
nTab = (int)strlen(zTab);
sApply.azCol = (const char **)zTab;
}else{
+ int nMinCol = 0;
+ int i;
+
sqlite3changeset_pk(pIter, &abPK, 0);
rc = sessionTableInfo(
db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
);
if( rc!=SQLITE_OK ) break;
-
+ for(i=0; i<sApply.nCol; i++){
+ if( sApply.abPK[i] ) nMinCol = i+1;
+ }
+
if( sApply.nCol==0 ){
schemaMismatch = 1;
- sqlite3_log(SQLITE_SCHEMA,
+ sqlite3_log(SQLITE_SCHEMA,
"sqlite3changeset_apply(): no such table: %s", zTab
);
}
- else if( sApply.nCol!=nCol ){
+ else if( sApply.nCol<nCol ){
schemaMismatch = 1;
- sqlite3_log(SQLITE_SCHEMA,
- "sqlite3changeset_apply(): table %s has %d columns, expected %d",
+ sqlite3_log(SQLITE_SCHEMA,
+ "sqlite3changeset_apply(): table %s has %d columns, "
+ "expected %d or more",
zTab, sApply.nCol, nCol
);
}
- else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){
+ else if( nCol<nMinCol || memcmp(sApply.abPK, abPK, nCol)!=0 ){
schemaMismatch = 1;
sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
"primary key mismatch for table %s", zTab
);
}
- else if(
- (rc = sessionSelectRow(db, zTab, &sApply))
- || (rc = sessionUpdateRow(db, zTab, &sApply))
- || (rc = sessionDeleteRow(db, zTab, &sApply))
- || (rc = sessionInsertRow(db, zTab, &sApply))
- ){
- break;
+ else{
+ sApply.nCol = nCol;
+ if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
+ if( (rc = sessionStat1Sql(db, &sApply) ) ){
+ break;
+ }
+ sApply.bStat1 = 1;
+ }else{
+ if((rc = sessionSelectRow(db, zTab, &sApply))
+ || (rc = sessionUpdateRow(db, zTab, &sApply))
+ || (rc = sessionDeleteRow(db, zTab, &sApply))
+ || (rc = sessionInsertRow(db, zTab, &sApply))
+ ){
+ break;
+ }
+ sApply.bStat1 = 0;
+ }
}
nTab = sqlite3Strlen30(zTab);
}
@@ -175837,24 +206902,65 @@ static int sessionChangesetApply(
}
sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
- }else{
- sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
- sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+ if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+ }else{
+ sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
+ sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+ }
}
+ assert( sApply.bRebase || sApply.rebase.nBuf==0 );
+ if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){
+ *ppRebase = (void*)sApply.rebase.aBuf;
+ *pnRebase = sApply.rebase.nBuf;
+ sApply.rebase.aBuf = 0;
+ }
sqlite3_finalize(sApply.pInsert);
sqlite3_finalize(sApply.pDelete);
sqlite3_finalize(sApply.pUpdate);
sqlite3_finalize(sApply.pSelect);
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
sqlite3_free((char*)sApply.constraints.aBuf);
+ sqlite3_free((char*)sApply.rebase.aBuf);
sqlite3_mutex_leave(sqlite3_db_mutex(db));
return rc;
}
/*
+** Apply the changeset passed via pChangeset/nChangeset to the main
+** database attached to handle "db".
+*/
+SQLITE_API int sqlite3changeset_apply_v2(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int nChangeset, /* Size of changeset in bytes */
+ void *pChangeset, /* Changeset blob */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase,
+ int flags
+){
+ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
+ int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
+ int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse);
+ if( rc==SQLITE_OK ){
+ rc = sessionChangesetApply(
+ db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
+ );
+ }
+ return rc;
+}
+
+/*
** Apply the changeset passed via pChangeset/nChangeset to the main database
** attached to handle "db". Invoke the supplied conflict handler callback
** to resolve any conflicts encountered while applying the change.
@@ -175874,12 +206980,9 @@ SQLITE_API int sqlite3changeset_apply(
),
void *pCtx /* First argument passed to xConflict */
){
- sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
- int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
- if( rc==SQLITE_OK ){
- rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
- }
- return rc;
+ return sqlite3changeset_apply_v2(
+ db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0, 0
+ );
}
/*
@@ -175887,7 +206990,7 @@ SQLITE_API int sqlite3changeset_apply(
** attached to handle "db". Invoke the supplied conflict handler callback
** to resolve any conflicts encountered while applying the change.
*/
-SQLITE_API int sqlite3changeset_apply_strm(
+SQLITE_API int sqlite3changeset_apply_v2_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
void *pIn, /* First arg for xInput */
@@ -175900,15 +207003,39 @@ SQLITE_API int sqlite3changeset_apply_strm(
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
sqlite3_changeset_iter *p /* Handle describing change and conflict */
),
- void *pCtx /* First argument passed to xConflict */
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase,
+ int flags
){
- sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
- int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
+ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
+ int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
+ int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse);
if( rc==SQLITE_OK ){
- rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
+ rc = sessionChangesetApply(
+ db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
+ );
}
return rc;
}
+SQLITE_API int sqlite3changeset_apply_strm(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+ void *pIn, /* First arg for xInput */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+){
+ return sqlite3changeset_apply_v2_strm(
+ db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0, 0
+ );
+}
/*
** sqlite3_changegroup handle.
@@ -175926,6 +207053,7 @@ struct sqlite3_changegroup {
*/
static int sessionChangeMerge(
SessionTable *pTab, /* Table structure */
+ int bRebase, /* True for a rebase hash-table */
int bPatchset, /* True for patchsets */
SessionChange *pExist, /* Existing change */
int op2, /* Second change operation */
@@ -175935,22 +207063,80 @@ static int sessionChangeMerge(
SessionChange **ppNew /* OUT: Merged change */
){
SessionChange *pNew = 0;
+ int rc = SQLITE_OK;
if( !pExist ){
- pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
+ pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec);
if( !pNew ){
return SQLITE_NOMEM;
}
memset(pNew, 0, sizeof(SessionChange));
pNew->op = op2;
pNew->bIndirect = bIndirect;
- pNew->nRecord = nRec;
pNew->aRecord = (u8*)&pNew[1];
- memcpy(pNew->aRecord, aRec, nRec);
+ if( bIndirect==0 || bRebase==0 ){
+ pNew->nRecord = nRec;
+ memcpy(pNew->aRecord, aRec, nRec);
+ }else{
+ int i;
+ u8 *pIn = aRec;
+ u8 *pOut = pNew->aRecord;
+ for(i=0; i<pTab->nCol; i++){
+ int nIn = sessionSerialLen(pIn);
+ if( *pIn==0 ){
+ *pOut++ = 0;
+ }else if( pTab->abPK[i]==0 ){
+ *pOut++ = 0xFF;
+ }else{
+ memcpy(pOut, pIn, nIn);
+ pOut += nIn;
+ }
+ pIn += nIn;
+ }
+ pNew->nRecord = pOut - pNew->aRecord;
+ }
+ }else if( bRebase ){
+ if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){
+ *ppNew = pExist;
+ }else{
+ sqlite3_int64 nByte = nRec + pExist->nRecord + sizeof(SessionChange);
+ pNew = (SessionChange*)sqlite3_malloc64(nByte);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ int i;
+ u8 *a1 = pExist->aRecord;
+ u8 *a2 = aRec;
+ u8 *pOut;
+
+ memset(pNew, 0, nByte);
+ pNew->bIndirect = bIndirect || pExist->bIndirect;
+ pNew->op = op2;
+ pOut = pNew->aRecord = (u8*)&pNew[1];
+
+ for(i=0; i<pTab->nCol; i++){
+ int n1 = sessionSerialLen(a1);
+ int n2 = sessionSerialLen(a2);
+ if( *a1==0xFF || (pTab->abPK[i]==0 && bIndirect) ){
+ *pOut++ = 0xFF;
+ }else if( *a2==0 ){
+ memcpy(pOut, a1, n1);
+ pOut += n1;
+ }else{
+ memcpy(pOut, a2, n2);
+ pOut += n2;
+ }
+ a1 += n1;
+ a2 += n2;
+ }
+ pNew->nRecord = pOut - pNew->aRecord;
+ }
+ sqlite3_free(pExist);
+ }
}else{
int op1 = pExist->op;
- /*
+ /*
** op1=INSERT, op2=INSERT -> Unsupported. Discard op2.
** op1=INSERT, op2=UPDATE -> INSERT.
** op1=INSERT, op2=DELETE -> (none)
@@ -175962,7 +207148,7 @@ static int sessionChangeMerge(
** op1=DELETE, op2=INSERT -> UPDATE.
** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2.
** op1=DELETE, op2=DELETE -> Unsupported. Discard op2.
- */
+ */
if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
|| (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
|| (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
@@ -175974,14 +207160,14 @@ static int sessionChangeMerge(
assert( pNew==0 );
}else{
u8 *aExist = pExist->aRecord;
- int nByte;
+ sqlite3_int64 nByte;
u8 *aCsr;
/* Allocate a new SessionChange object. Ensure that the aRecord[]
** buffer of the new object is large enough to hold any record that
** may be generated by combining the input records. */
nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
- pNew = (SessionChange *)sqlite3_malloc(nByte);
+ pNew = (SessionChange *)sqlite3_malloc64(nByte);
if( !pNew ){
sqlite3_free(pExist);
return SQLITE_NOMEM;
@@ -176040,7 +207226,7 @@ static int sessionChangeMerge(
}
*ppNew = pNew;
- return SQLITE_OK;
+ return rc;
}
/*
@@ -176049,15 +207235,15 @@ static int sessionChangeMerge(
*/
static int sessionChangesetToHash(
sqlite3_changeset_iter *pIter, /* Iterator to read from */
- sqlite3_changegroup *pGrp /* Changegroup object to add changeset to */
+ sqlite3_changegroup *pGrp, /* Changegroup object to add changeset to */
+ int bRebase /* True if hash table is for rebasing */
){
u8 *aRec;
int nRec;
int rc = SQLITE_OK;
SessionTable *pTab = 0;
-
- while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
+ while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
const char *zNew;
int nCol;
int op;
@@ -176087,7 +207273,7 @@ static int sessionChangesetToHash(
if( !pTab ){
SessionTable **ppTab;
- pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
+ pTab = sqlite3_malloc64(sizeof(SessionTable) + nCol + nNew+1);
if( !pTab ){
rc = SQLITE_NOMEM;
break;
@@ -176101,7 +207287,7 @@ static int sessionChangesetToHash(
/* The new object must be linked on to the end of the list, not
** simply added to the start of it. This is to ensure that the
- ** tables within the output of sqlite3changegroup_output() are in
+ ** tables within the output of sqlite3changegroup_output() are in
** the right order. */
for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
*ppTab = pTab;
@@ -176119,7 +207305,7 @@ static int sessionChangesetToHash(
pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
);
- /* Search for existing entry. If found, remove it from the hash table.
+ /* Search for existing entry. If found, remove it from the hash table.
** Code below may link it back in.
*/
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
@@ -176137,7 +207323,7 @@ static int sessionChangesetToHash(
}
}
- rc = sessionChangeMerge(pTab,
+ rc = sessionChangeMerge(pTab, bRebase,
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
);
if( rc ) break;
@@ -176158,7 +207344,7 @@ static int sessionChangesetToHash(
**
** If xOutput is not NULL, then the changeset/patchset is returned to the
** user via one or more calls to xOutput, as with the other streaming
-** interfaces.
+** interfaces.
**
** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
** buffer containing the output changeset before this function returns. In
@@ -176183,7 +207369,7 @@ static int sessionChangegroupOutput(
assert( xOutput==0 || (ppOut==0 && pnOut==0) );
/* Create the serialized output changeset based on the contents of the
- ** hash tables attached to the SessionTable objects in list p->pList.
+ ** hash tables attached to the SessionTable objects in list p->pList.
*/
for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
int i;
@@ -176196,13 +207382,12 @@ static int sessionChangegroupOutput(
sessionAppendByte(&buf, p->op, &rc);
sessionAppendByte(&buf, p->bIndirect, &rc);
sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
+ if( rc==SQLITE_OK && xOutput && buf.nBuf>=sessions_strm_chunk_size ){
+ rc = xOutput(pOut, buf.aBuf, buf.nBuf);
+ buf.nBuf = 0;
+ }
}
}
-
- if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
- rc = xOutput(pOut, buf.aBuf, buf.nBuf);
- buf.nBuf = 0;
- }
}
if( rc==SQLITE_OK ){
@@ -176245,7 +207430,7 @@ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void
rc = sqlite3changeset_start(&pIter, nData, pData);
if( rc==SQLITE_OK ){
- rc = sessionChangesetToHash(pIter, pGrp);
+ rc = sessionChangesetToHash(pIter, pGrp, 0);
}
sqlite3changeset_finalize(pIter);
return rc;
@@ -176276,7 +207461,7 @@ SQLITE_API int sqlite3changegroup_add_strm(
rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
if( rc==SQLITE_OK ){
- rc = sessionChangesetToHash(pIter, pGrp);
+ rc = sessionChangesetToHash(pIter, pGrp, 0);
}
sqlite3changeset_finalize(pIter);
return rc;
@@ -176287,7 +207472,7 @@ SQLITE_API int sqlite3changegroup_add_strm(
*/
SQLITE_API int sqlite3changegroup_output_strm(
sqlite3_changegroup *pGrp,
- int (*xOutput)(void *pOut, const void *pData, int nData),
+ int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
){
return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
@@ -176303,7 +207488,7 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
}
}
-/*
+/*
** Combine two changesets together.
*/
SQLITE_API int sqlite3changeset_concat(
@@ -176361,2231 +207546,379 @@ SQLITE_API int sqlite3changeset_concat_strm(
return rc;
}
-#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
-
-/************** End of sqlite3session.c **************************************/
-/************** Begin file json1.c *******************************************/
-/*
-** 2015-08-12
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This SQLite extension implements JSON functions. The interface is
-** modeled after MySQL JSON functions:
-**
-** https://dev.mysql.com/doc/refman/5.7/en/json.html
-**
-** For the time being, all JSON is stored as pure text. (We might add
-** a JSONB type in the future which stores a binary encoding of JSON in
-** a BLOB, but there is no support for JSONB in the current implementation.
-** This implementation parses JSON text at 250 MB/s, so it is hard to see
-** how JSONB might improve on that.)
-*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
-#if !defined(_SQLITEINT_H_)
-/* #include "sqlite3ext.h" */
-#endif
-SQLITE_EXTENSION_INIT1
-/* #include <assert.h> */
-/* #include <string.h> */
-/* #include <stdlib.h> */
-/* #include <stdarg.h> */
-
-/* Mark a function parameter as unused, to suppress nuisance compiler
-** warnings. */
-#ifndef UNUSED_PARAM
-# define UNUSED_PARAM(X) (void)(X)
-#endif
-
-#ifndef LARGEST_INT64
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
-/*
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
-** to pass signed char values.
-*/
-#ifdef sqlite3Isdigit
- /* Use the SQLite core versions if this routine is part of the
- ** SQLite amalgamation */
-# define safe_isdigit(x) sqlite3Isdigit(x)
-# define safe_isalnum(x) sqlite3Isalnum(x)
-#else
- /* Use the standard library for separate compilation */
-#include <ctype.h> /* amalgamator: keep */
-# define safe_isdigit(x) isdigit((unsigned char)(x))
-# define safe_isalnum(x) isalnum((unsigned char)(x))
-#endif
-
/*
-** Growing our own isspace() routine this way is twice as fast as
-** the library isspace() function, resulting in a 7% overall performance
-** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
-*/
-static const char jsonIsSpace[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
-
-#ifndef SQLITE_AMALGAMATION
- /* Unsigned integer types. These are already defined in the sqliteInt.h,
- ** but the definitions need to be repeated for separate compilation. */
- typedef sqlite3_uint64 u64;
- typedef unsigned int u32;
- typedef unsigned char u8;
-#endif
-
-/* Objects */
-typedef struct JsonString JsonString;
-typedef struct JsonNode JsonNode;
-typedef struct JsonParse JsonParse;
-
-/* An instance of this object represents a JSON string
-** under construction. Really, this is a generic string accumulator
-** that can be and is used to create strings other than JSON.
+** Changeset rebaser handle.
*/
-struct JsonString {
- sqlite3_context *pCtx; /* Function context - put error messages here */
- char *zBuf; /* Append JSON content here */
- u64 nAlloc; /* Bytes of storage available in zBuf[] */
- u64 nUsed; /* Bytes of zBuf[] currently used */
- u8 bStatic; /* True if zBuf is static space */
- u8 bErr; /* True if an error has been encountered */
- char zSpace[100]; /* Initial static space */
+struct sqlite3_rebaser {
+ sqlite3_changegroup grp; /* Hash table */
};
-/* JSON type values
-*/
-#define JSON_NULL 0
-#define JSON_TRUE 1
-#define JSON_FALSE 2
-#define JSON_INT 3
-#define JSON_REAL 4
-#define JSON_STRING 5
-#define JSON_ARRAY 6
-#define JSON_OBJECT 7
-
-/* The "subtype" set for JSON values */
-#define JSON_SUBTYPE 74 /* Ascii for "J" */
-
/*
-** Names of the various JSON types:
+** Buffers a1 and a2 must both contain a sessions module record nCol
+** fields in size. This function appends an nCol sessions module
+** record to buffer pBuf that is a copy of a1, except that for
+** each field that is undefined in a1[], swap in the field from a2[].
*/
-static const char * const jsonType[] = {
- "null", "true", "false", "integer", "real", "text", "array", "object"
-};
-
-/* Bit values for the JsonNode.jnFlag field
-*/
-#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
-#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */
-#define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x20 /* Is a label of an object */
-
-
-/* A single node of parsed JSON
-*/
-struct JsonNode {
- u8 eType; /* One of the JSON_ type values */
- u8 jnFlags; /* JNODE flags */
- u8 iVal; /* Replacement value when JNODE_REPLACE */
- u32 n; /* Bytes of content, or number of sub-nodes */
- union {
- const char *zJContent; /* Content for INT, REAL, and STRING */
- u32 iAppend; /* More terms for ARRAY and OBJECT */
- u32 iKey; /* Key for ARRAY objects in json_tree() */
- } u;
-};
-
-/* A completely parsed JSON string
-*/
-struct JsonParse {
- u32 nNode; /* Number of slots of aNode[] used */
- u32 nAlloc; /* Number of slots of aNode[] allocated */
- JsonNode *aNode; /* Array of nodes containing the parse */
- const char *zJson; /* Original JSON string */
- u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
-};
-
-/**************************************************************************
-** Utility routines for dealing with JsonString objects
-**************************************************************************/
-
-/* Set the JsonString object to an empty string
-*/
-static void jsonZero(JsonString *p){
- p->zBuf = p->zSpace;
- p->nAlloc = sizeof(p->zSpace);
- p->nUsed = 0;
- p->bStatic = 1;
-}
-
-/* Initialize the JsonString object
-*/
-static void jsonInit(JsonString *p, sqlite3_context *pCtx){
- p->pCtx = pCtx;
- p->bErr = 0;
- jsonZero(p);
-}
-
-
-/* Free all allocated memory and reset the JsonString object back to its
-** initial state.
-*/
-static void jsonReset(JsonString *p){
- if( !p->bStatic ) sqlite3_free(p->zBuf);
- jsonZero(p);
-}
-
-
-/* Report an out-of-memory (OOM) condition
-*/
-static void jsonOom(JsonString *p){
- p->bErr = 1;
- sqlite3_result_error_nomem(p->pCtx);
- jsonReset(p);
-}
-
-/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
-** Return zero on success. Return non-zero on an OOM error
-*/
-static int jsonGrow(JsonString *p, u32 N){
- u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
- char *zNew;
- if( p->bStatic ){
- if( p->bErr ) return 1;
- zNew = sqlite3_malloc64(nTotal);
- if( zNew==0 ){
- jsonOom(p);
- return SQLITE_NOMEM;
- }
- memcpy(zNew, p->zBuf, (size_t)p->nUsed);
- p->zBuf = zNew;
- p->bStatic = 0;
- }else{
- zNew = sqlite3_realloc64(p->zBuf, nTotal);
- if( zNew==0 ){
- jsonOom(p);
- return SQLITE_NOMEM;
- }
- p->zBuf = zNew;
- }
- p->nAlloc = nTotal;
- return SQLITE_OK;
-}
-
-/* Append N bytes from zIn onto the end of the JsonString string.
-*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
- if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
- memcpy(p->zBuf+p->nUsed, zIn, N);
- p->nUsed += N;
-}
-
-/* Append formatted text (not to exceed N bytes) to the JsonString.
-*/
-static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
- va_list ap;
- if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
- va_start(ap, zFormat);
- sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
- va_end(ap);
- p->nUsed += (int)strlen(p->zBuf+p->nUsed);
-}
-
-/* Append a single character
-*/
-static void jsonAppendChar(JsonString *p, char c){
- if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
- p->zBuf[p->nUsed++] = c;
-}
-
-/* Append a comma separator to the output buffer, if the previous
-** character is not '[' or '{'.
-*/
-static void jsonAppendSeparator(JsonString *p){
- char c;
- if( p->nUsed==0 ) return;
- c = p->zBuf[p->nUsed-1];
- if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
-}
-
-/* Append the N-byte string in zIn to the end of the JsonString string
-** under construction. Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
-** string.
-*/
-static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
- u32 i;
- if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
- p->zBuf[p->nUsed++] = '"';
- for(i=0; i<N; i++){
- unsigned char c = ((unsigned const char*)zIn)[i];
- if( c=='"' || c=='\\' ){
- json_simple_escape:
- if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
- p->zBuf[p->nUsed++] = '\\';
- }else if( c<=0x1f ){
- static const char aSpecial[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
- assert( sizeof(aSpecial)==32 );
- assert( aSpecial['\b']=='b' );
- assert( aSpecial['\f']=='f' );
- assert( aSpecial['\n']=='n' );
- assert( aSpecial['\r']=='r' );
- assert( aSpecial['\t']=='t' );
- if( aSpecial[c] ){
- c = aSpecial[c];
- goto json_simple_escape;
- }
- if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
- p->zBuf[p->nUsed++] = '\\';
- p->zBuf[p->nUsed++] = 'u';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0' + (c>>4);
- c = "0123456789abcdef"[c&0xf];
- }
- p->zBuf[p->nUsed++] = c;
- }
- p->zBuf[p->nUsed++] = '"';
- assert( p->nUsed<p->nAlloc );
-}
-
-/*
-** Append a function parameter value to the JSON string under
-** construction.
-*/
-static void jsonAppendValue(
- JsonString *p, /* Append to this JSON string */
- sqlite3_value *pValue /* Value to append */
+static void sessionAppendRecordMerge(
+ SessionBuffer *pBuf, /* Buffer to append to */
+ int nCol, /* Number of columns in each record */
+ u8 *a1, int n1, /* Record 1 */
+ u8 *a2, int n2, /* Record 2 */
+ int *pRc /* IN/OUT: error code */
){
- switch( sqlite3_value_type(pValue) ){
- case SQLITE_NULL: {
- jsonAppendRaw(p, "null", 4);
- break;
- }
- case SQLITE_INTEGER:
- case SQLITE_FLOAT: {
- const char *z = (const char*)sqlite3_value_text(pValue);
- u32 n = (u32)sqlite3_value_bytes(pValue);
- jsonAppendRaw(p, z, n);
- break;
- }
- case SQLITE_TEXT: {
- const char *z = (const char*)sqlite3_value_text(pValue);
- u32 n = (u32)sqlite3_value_bytes(pValue);
- if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
- jsonAppendRaw(p, z, n);
+ sessionBufferGrow(pBuf, n1+n2, pRc);
+ if( *pRc==SQLITE_OK ){
+ int i;
+ u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
+ for(i=0; i<nCol; i++){
+ int nn1 = sessionSerialLen(a1);
+ int nn2 = sessionSerialLen(a2);
+ if( *a1==0 || *a1==0xFF ){
+ memcpy(pOut, a2, nn2);
+ pOut += nn2;
}else{
- jsonAppendString(p, z, n);
- }
- break;
- }
- default: {
- if( p->bErr==0 ){
- sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
- p->bErr = 2;
- jsonReset(p);
+ memcpy(pOut, a1, nn1);
+ pOut += nn1;
}
- break;
+ a1 += nn1;
+ a2 += nn2;
}
- }
-}
-
-/* Make the JSON in p the result of the SQL function.
-*/
-static void jsonResult(JsonString *p){
- if( p->bErr==0 ){
- sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
- p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
- SQLITE_UTF8);
- jsonZero(p);
+ pBuf->nBuf = pOut-pBuf->aBuf;
+ assert( pBuf->nBuf<=pBuf->nAlloc );
}
- assert( p->bStatic );
}
-/**************************************************************************
-** Utility routines for dealing with JsonNode and JsonParse objects
-**************************************************************************/
-
/*
-** Return the number of consecutive JsonNode slots need to represent
-** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
-** OBJECT types, the number might be larger.
+** This function is called when rebasing a local UPDATE change against one
+** or more remote UPDATE changes. The aRec/nRec buffer contains the current
+** old.* and new.* records for the change. The rebase buffer (a single
+** record) is in aChange/nChange. The rebased change is appended to buffer
+** pBuf.
**
-** Appended elements are not counted. The value returned is the number
-** by which the JsonNode counter should increment in order to go to the
-** next peer value.
-*/
-static u32 jsonNodeSize(JsonNode *pNode){
- return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
-}
-
-/*
-** Reclaim all memory allocated by a JsonParse object. But do not
-** delete the JsonParse object itself.
-*/
-static void jsonParseReset(JsonParse *pParse){
- sqlite3_free(pParse->aNode);
- pParse->aNode = 0;
- pParse->nNode = 0;
- pParse->nAlloc = 0;
- sqlite3_free(pParse->aUp);
- pParse->aUp = 0;
-}
-
-/*
-** Convert the JsonNode pNode into a pure JSON string and
-** append to pOut. Subsubstructure is also included. Return
-** the number of JsonNode objects that are encoded.
-*/
-static void jsonRenderNode(
- JsonNode *pNode, /* The node to render */
- JsonString *pOut, /* Write JSON here */
- sqlite3_value **aReplace /* Replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- jsonAppendRaw(pOut, "null", 4);
- break;
- }
- case JSON_TRUE: {
- jsonAppendRaw(pOut, "true", 4);
- break;
- }
- case JSON_FALSE: {
- jsonAppendRaw(pOut, "false", 5);
- break;
- }
- case JSON_STRING: {
- if( pNode->jnFlags & JNODE_RAW ){
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- /* Fall through into the next case */
- }
- case JSON_REAL:
- case JSON_INT: {
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- case JSON_ARRAY: {
- u32 j = 1;
- jsonAppendChar(pOut, '[');
- for(;;){
- while( j<=pNode->n ){
- if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){
- if( pNode[j].jnFlags & JNODE_REPLACE ){
- jsonAppendSeparator(pOut);
- jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
- }
- }else{
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- }
- j += jsonNodeSize(&pNode[j]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, ']');
- break;
- }
- case JSON_OBJECT: {
- u32 j = 1;
- jsonAppendChar(pOut, '{');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- jsonAppendChar(pOut, ':');
- if( pNode[j+1].jnFlags & JNODE_REPLACE ){
- jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
- }else{
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
- }
- }
- j += 1 + jsonNodeSize(&pNode[j+1]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, '}');
- break;
- }
- }
-}
-
-/*
-** Return a JsonNode and all its descendents as a JSON string.
+** Rebasing the UPDATE involves:
+**
+** * Removing any changes to fields for which the corresponding field
+** in the rebase buffer is set to "replaced" (type 0xFF). If this
+** means the UPDATE change updates no fields, nothing is appended
+** to the output buffer.
+**
+** * For each field modified by the local change for which the
+** corresponding field in the rebase buffer is not "undefined" (0x00)
+** or "replaced" (0xFF), the old.* value is replaced by the value
+** in the rebase buffer.
*/
-static void jsonReturnJson(
- JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
+static void sessionAppendPartialUpdate(
+ SessionBuffer *pBuf, /* Append record here */
+ sqlite3_changeset_iter *pIter, /* Iterator pointed at local change */
+ u8 *aRec, int nRec, /* Local change */
+ u8 *aChange, int nChange, /* Record to rebase against */
+ int *pRc /* IN/OUT: Return Code */
){
- JsonString s;
- jsonInit(&s, pCtx);
- jsonRenderNode(pNode, &s, aReplace);
- jsonResult(&s);
- sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
-}
+ sessionBufferGrow(pBuf, 2+nRec+nChange, pRc);
+ if( *pRc==SQLITE_OK ){
+ int bData = 0;
+ u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
+ int i;
+ u8 *a1 = aRec;
+ u8 *a2 = aChange;
-/*
-** Make the JsonNode the return value of the function.
-*/
-static void jsonReturn(
- JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- sqlite3_result_null(pCtx);
- break;
- }
- case JSON_TRUE: {
- sqlite3_result_int(pCtx, 1);
- break;
- }
- case JSON_FALSE: {
- sqlite3_result_int(pCtx, 0);
- break;
- }
- case JSON_INT: {
- sqlite3_int64 i = 0;
- const char *z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
- }
- }
- }
- i = i*10 + v;
+ *pOut++ = SQLITE_UPDATE;
+ *pOut++ = pIter->bIndirect;
+ for(i=0; i<pIter->nCol; i++){
+ int n1 = sessionSerialLen(a1);
+ int n2 = sessionSerialLen(a2);
+ if( pIter->abPK[i] || a2[0]==0 ){
+ if( !pIter->abPK[i] ) bData = 1;
+ memcpy(pOut, a1, n1);
+ pOut += n1;
+ }else if( a2[0]!=0xFF ){
+ bData = 1;
+ memcpy(pOut, a2, n2);
+ pOut += n2;
+ }else{
+ *pOut++ = '\0';
}
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- sqlite3_result_int64(pCtx, i);
- int_done:
- break;
- int_as_real: /* fall through to real */;
- }
- case JSON_REAL: {
- double r;
-#ifdef SQLITE_AMALGAMATION
- const char *z = pNode->u.zJContent;
- sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- r = strtod(pNode->u.zJContent, 0);
-#endif
- sqlite3_result_double(pCtx, r);
- break;
+ a1 += n1;
+ a2 += n2;
}
- case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
- if( pNode->jnFlags & JNODE_RAW ){
- sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
- SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
- /* JSON formatted without any backslash-escapes */
- sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
- SQLITE_TRANSIENT);
- }else{
- /* Translate JSON formatted string into raw text */
- u32 i;
- u32 n = pNode->n;
- const char *z = pNode->u.zJContent;
- char *zOut;
- u32 j;
- zOut = sqlite3_malloc( n+1 );
- if( zOut==0 ){
- sqlite3_result_error_nomem(pCtx);
- break;
- }
- for(i=1, j=0; i<n-1; i++){
- char c = z[i];
- if( c!='\\' ){
- zOut[j++] = c;
- }else{
- c = z[++i];
- if( c=='u' ){
- u32 v = 0, k;
- for(k=0; k<4 && i<n-2; i++, k++){
- c = z[i+1];
- if( c>='0' && c<='9' ) v = v*16 + c - '0';
- else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10;
- else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10;
- else break;
- }
- if( v==0 ) break;
- if( v<=0x7f ){
- zOut[j++] = (char)v;
- }else if( v<=0x7ff ){
- zOut[j++] = (char)(0xc0 | (v>>6));
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- zOut[j++] = (char)(0xe0 | (v>>12));
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }
- }else{
- if( c=='b' ){
- c = '\b';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='t' ){
- c = '\t';
- }
- zOut[j++] = c;
- }
- }
+ if( bData ){
+ a2 = aChange;
+ for(i=0; i<pIter->nCol; i++){
+ int n1 = sessionSerialLen(a1);
+ int n2 = sessionSerialLen(a2);
+ if( pIter->abPK[i] || a2[0]!=0xFF ){
+ memcpy(pOut, a1, n1);
+ pOut += n1;
+ }else{
+ *pOut++ = '\0';
}
- zOut[j] = 0;
- sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
+ a1 += n1;
+ a2 += n2;
}
- break;
- }
- case JSON_ARRAY:
- case JSON_OBJECT: {
- jsonReturnJson(pNode, pCtx, aReplace);
- break;
+ pBuf->nBuf = (pOut - pBuf->aBuf);
}
}
}
-/* Forward reference */
-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
-
/*
-** A macro to hint to the compiler that a function should not be
-** inlined.
+** pIter is configured to iterate through a changeset. This function rebases
+** that changeset according to the current configuration of the rebaser
+** object passed as the first argument. If no error occurs and argument xOutput
+** is not NULL, then the changeset is returned to the caller by invoking
+** xOutput zero or more times and SQLITE_OK returned. Or, if xOutput is NULL,
+** then (*ppOut) is set to point to a buffer containing the rebased changeset
+** before this function returns. In this case (*pnOut) is set to the size of
+** the buffer in bytes. It is the responsibility of the caller to eventually
+** free the (*ppOut) buffer using sqlite3_free().
+**
+** If an error occurs, an SQLite error code is returned. If ppOut and
+** pnOut are not NULL, then the two output parameters are set to 0 before
+** returning.
*/
-#if defined(__GNUC__)
-# define JSON_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER) && _MSC_VER>=1310
-# define JSON_NOINLINE __declspec(noinline)
-#else
-# define JSON_NOINLINE
-#endif
-
-
-static JSON_NOINLINE int jsonParseAddNodeExpand(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+static int sessionRebase(
+ sqlite3_rebaser *p, /* Rebaser hash table */
+ sqlite3_changeset_iter *pIter, /* Input data */
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut, /* Context for xOutput callback */
+ int *pnOut, /* OUT: Number of bytes in output changeset */
+ void **ppOut /* OUT: Inverse of pChangeset */
){
- u32 nNew;
- JsonNode *pNew;
- assert( pParse->nNode>=pParse->nAlloc );
- if( pParse->oom ) return -1;
- nNew = pParse->nAlloc*2 + 10;
- pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
- if( pNew==0 ){
- pParse->oom = 1;
- return -1;
- }
- pParse->nAlloc = nNew;
- pParse->aNode = pNew;
- assert( pParse->nNode<pParse->nAlloc );
- return jsonParseAddNode(pParse, eType, n, zContent);
-}
+ int rc = SQLITE_OK;
+ u8 *aRec = 0;
+ int nRec = 0;
+ int bNew = 0;
+ SessionTable *pTab = 0;
+ SessionBuffer sOut = {0,0,0};
-/*
-** Create a new JsonNode instance based on the arguments and append that
-** instance to the JsonParse. Return the index in pParse->aNode[] of the
-** new node, or -1 if a memory allocation fails.
-*/
-static int jsonParseAddNode(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
-){
- JsonNode *p;
- if( pParse->nNode>=pParse->nAlloc ){
- return jsonParseAddNodeExpand(pParse, eType, n, zContent);
- }
- p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
- p->iVal = 0;
- p->n = n;
- p->u.zJContent = zContent;
- return pParse->nNode++;
-}
+ while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, &bNew) ){
+ SessionChange *pChange = 0;
+ int bDone = 0;
-/*
-** Parse a single JSON value which begins at pParse->zJson[i]. Return the
-** index of the first character past the end of the value parsed.
-**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
-*/
-static int jsonParseValue(JsonParse *pParse, u32 i){
- char c;
- u32 j;
- int iThis;
- int x;
- JsonNode *pNode;
- while( safe_isspace(pParse->zJson[i]) ){ i++; }
- if( (c = pParse->zJson[i])=='{' ){
- /* Parse object */
- iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- if( iThis<0 ) return -1;
- for(j=i+1;;j++){
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
- }
- if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
- pNode->jnFlags |= JNODE_LABEL;
- j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- if( pParse->zJson[j]!=':' ) return -1;
- j++;
- x = jsonParseValue(pParse, j);
- if( x<0 ) return -1;
- j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- c = pParse->zJson[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
- }
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
- return j+1;
- }else if( c=='[' ){
- /* Parse array */
- iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- if( iThis<0 ) return -1;
- for(j=i+1;;j++){
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
- }
- j = x;
- while( safe_isspace(pParse->zJson[j]) ){ j++; }
- c = pParse->zJson[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
- }
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
- return j+1;
- }else if( c=='"' ){
- /* Parse string */
- u8 jnFlags = 0;
- j = i+1;
- for(;;){
- c = pParse->zJson[j];
- if( c==0 ) return -1;
- if( c=='\\' ){
- c = pParse->zJson[++j];
- if( c==0 ) return -1;
- jnFlags = JNODE_ESCAPE;
- }else if( c=='"' ){
- break;
- }
- j++;
- }
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
- return j+1;
- }else if( c=='n'
- && strncmp(pParse->zJson+i,"null",4)==0
- && !safe_isalnum(pParse->zJson[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(pParse->zJson+i,"true",4)==0
- && !safe_isalnum(pParse->zJson[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(pParse->zJson+i,"false",5)==0
- && !safe_isalnum(pParse->zJson[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
- /* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
- j = i+1;
- for(;; j++){
- c = pParse->zJson[j];
- if( c>='0' && c<='9' ) continue;
- if( c=='.' ){
- if( pParse->zJson[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
- continue;
- }
- if( c=='e' || c=='E' ){
- if( pParse->zJson[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
- c = pParse->zJson[j+1];
- if( c=='+' || c=='-' ){
- j++;
- c = pParse->zJson[j+1];
- }
- if( c<'0' || c>'9' ) return -1;
- continue;
+ if( bNew ){
+ const char *zTab = pIter->zTab;
+ for(pTab=p->grp.pList; pTab; pTab=pTab->pNext){
+ if( 0==sqlite3_stricmp(pTab->zName, zTab) ) break;
}
- break;
- }
- if( pParse->zJson[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &pParse->zJson[i]);
- return j;
- }else if( c=='}' ){
- return -2; /* End of {...} */
- }else if( c==']' ){
- return -3; /* End of [...] */
- }else if( c==0 ){
- return 0; /* End of file */
- }else{
- return -1; /* Syntax error */
- }
-}
+ bNew = 0;
-/*
-** Parse a complete JSON string. Return 0 on success or non-zero if there
-** are any errors. If an error occurs, free all memory associated with
-** pParse.
-**
-** pParse is uninitialized when this routine is called.
-*/
-static int jsonParse(
- JsonParse *pParse, /* Initialize and fill this JsonParse object */
- sqlite3_context *pCtx, /* Report errors here */
- const char *zJson /* Input JSON text to be parsed */
-){
- int i;
- memset(pParse, 0, sizeof(*pParse));
- if( zJson==0 ) return 1;
- pParse->zJson = zJson;
- i = jsonParseValue(pParse, 0);
- if( pParse->oom ) i = -1;
- if( i>0 ){
- while( safe_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
- }
- if( i<=0 ){
- if( pCtx!=0 ){
- if( pParse->oom ){
- sqlite3_result_error_nomem(pCtx);
- }else{
- sqlite3_result_error(pCtx, "malformed JSON", -1);
+ /* A patchset may not be rebased */
+ if( pIter->bPatchset ){
+ rc = SQLITE_ERROR;
}
- }
- jsonParseReset(pParse);
- return 1;
- }
- return 0;
-}
-/* Mark node i of pParse as being a child of iParent. Call recursively
-** to fill in all the descendants of node i.
-*/
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
- JsonNode *pNode = &pParse->aNode[i];
- u32 j;
- pParse->aUp[i] = iParent;
- switch( pNode->eType ){
- case JSON_ARRAY: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
- jsonParseFillInParentage(pParse, i+j, i);
- }
- break;
- }
- case JSON_OBJECT: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
- pParse->aUp[i+j] = i;
- jsonParseFillInParentage(pParse, i+j+1, i);
- }
- break;
- }
- default: {
- break;
+ /* Append a table header to the output for this new table */
+ sessionAppendByte(&sOut, pIter->bPatchset ? 'P' : 'T', &rc);
+ sessionAppendVarint(&sOut, pIter->nCol, &rc);
+ sessionAppendBlob(&sOut, pIter->abPK, pIter->nCol, &rc);
+ sessionAppendBlob(&sOut,(u8*)pIter->zTab,(int)strlen(pIter->zTab)+1,&rc);
}
- }
-}
-
-/*
-** Compute the parentage of all nodes in a completed parse.
-*/
-static int jsonParseFindParents(JsonParse *pParse){
- u32 *aUp;
- assert( pParse->aUp==0 );
- aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
- if( aUp==0 ){
- pParse->oom = 1;
- return SQLITE_NOMEM;
- }
- jsonParseFillInParentage(pParse, 0, 0);
- return SQLITE_OK;
-}
-
-/*
-** Compare the OBJECT label at pNode against zKey,nKey. Return true on
-** a match.
-*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
- if( pNode->jnFlags & JNODE_RAW ){
- if( pNode->n!=nKey ) return 0;
- return strncmp(pNode->u.zJContent, zKey, nKey)==0;
- }else{
- if( pNode->n!=nKey+2 ) return 0;
- return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
- }
-}
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+ if( pTab && rc==SQLITE_OK ){
+ int iHash = sessionChangeHash(pTab, 0, aRec, pTab->nChange);
-/*
-** Search along zPath to find the node specified. Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
-**
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath. If
-** new nodes are appended *pApnd is set to 1.
-*/
-static JsonNode *jsonLookupStep(
- JsonParse *pParse, /* The JSON to search */
- u32 iRoot, /* Begin the search at this node */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- const char **pzErr /* Make *pzErr point to any syntax error in zPath */
-){
- u32 i, j, nKey;
- const char *zKey;
- JsonNode *pRoot = &pParse->aNode[iRoot];
- if( zPath[0]==0 ) return pRoot;
- if( zPath[0]=='.' ){
- if( pRoot->eType!=JSON_OBJECT ) return 0;
- zPath++;
- if( zPath[0]=='"' ){
- zKey = zPath + 1;
- for(i=1; zPath[i] && zPath[i]!='"'; i++){}
- nKey = i-1;
- if( zPath[i] ){
- i++;
- }else{
- *pzErr = zPath;
- return 0;
- }
- }else{
- zKey = zPath;
- for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
- nKey = i;
- }
- if( nKey==0 ){
- *pzErr = zPath;
- return 0;
- }
- j = 1;
- for(;;){
- while( j<=pRoot->n ){
- if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
- return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
+ for(pChange=pTab->apChange[iHash]; pChange; pChange=pChange->pNext){
+ if( sessionChangeEqual(pTab, 0, aRec, 0, pChange->aRecord) ){
+ break;
}
- j++;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( pApnd ){
- u32 iStart, iLabel;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
- zPath += i;
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
- }
- return pNode;
- }
- }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- i = 0;
- j = 1;
- while( safe_isdigit(zPath[j]) ){
- i = i*10 + zPath[j] - '0';
- j++;
- }
- if( zPath[j]!=']' ){
- *pzErr = zPath;
- return 0;
- }
- zPath += j + 1;
- j = 1;
- for(;;){
- while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
- if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( j<=pRoot->n ){
- return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
- }
- if( i==0 && pApnd ){
- u32 iStart;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
}
- return pNode;
}
- }else{
- *pzErr = zPath;
- }
- return 0;
-}
-
-/*
-** Append content to pParse that will complete zPath. Return a pointer
-** to the inserted node, or return NULL if the append fails.
-*/
-static JsonNode *jsonLookupAppend(
- JsonParse *pParse, /* Append content to the JSON parse */
- const char *zPath, /* Description of content to append */
- int *pApnd, /* Set this flag to 1 */
- const char **pzErr /* Make this point to any syntax error */
-){
- *pApnd = 1;
- if( zPath[0]==0 ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
- }
- if( zPath[0]=='.' ){
- jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- }else if( strncmp(zPath,"[0]",3)==0 ){
- jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- }else{
- return 0;
- }
- if( pParse->oom ) return 0;
- return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
-}
-
-/*
-** Return the text of a syntax error message on a JSON path. Space is
-** obtained from sqlite3_malloc().
-*/
-static char *jsonPathSyntaxError(const char *zErr){
- return sqlite3_mprintf("JSON path error near '%q'", zErr);
-}
-
-/*
-** Do a node lookup using zPath. Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
-**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
-**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
-*/
-static JsonNode *jsonLookup(
- JsonParse *pParse, /* The JSON to search */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- sqlite3_context *pCtx /* Report errors here, if not NULL */
-){
- const char *zErr = 0;
- JsonNode *pNode = 0;
- char *zMsg;
-
- if( zPath==0 ) return 0;
- if( zPath[0]!='$' ){
- zErr = zPath;
- goto lookup_err;
- }
- zPath++;
- pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
- if( zErr==0 ) return pNode;
-
-lookup_err:
- pParse->nErr++;
- assert( zErr!=0 && pCtx!=0 );
- zMsg = jsonPathSyntaxError(zErr);
- if( zMsg ){
- sqlite3_result_error(pCtx, zMsg, -1);
- sqlite3_free(zMsg);
- }else{
- sqlite3_result_error_nomem(pCtx);
- }
- return 0;
-}
-
-
-/*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
-*/
-static void jsonWrongNumArgs(
- sqlite3_context *pCtx,
- const char *zFuncName
-){
- char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
- zFuncName);
- sqlite3_result_error(pCtx, zMsg, -1);
- sqlite3_free(zMsg);
-}
+ if( pChange ){
+ assert( pChange->op==SQLITE_DELETE || pChange->op==SQLITE_INSERT );
+ switch( pIter->op ){
+ case SQLITE_INSERT:
+ if( pChange->op==SQLITE_INSERT ){
+ bDone = 1;
+ if( pChange->bIndirect==0 ){
+ sessionAppendByte(&sOut, SQLITE_UPDATE, &rc);
+ sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+ sessionAppendBlob(&sOut, pChange->aRecord, pChange->nRecord, &rc);
+ sessionAppendBlob(&sOut, aRec, nRec, &rc);
+ }
+ }
+ break;
-/****************************************************************************
-** SQL functions used for testing and debugging
-****************************************************************************/
-
-#ifdef SQLITE_DEBUG
-/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided. Or it returns NULL if JSON is not
-** well-formed.
-*/
-static void jsonParseFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString s; /* Output string - not real JSON */
- JsonParse x; /* The parse */
- u32 i;
-
- assert( argc==1 );
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonParseFindParents(&x);
- jsonInit(&s, ctx);
- for(i=0; i<x.nNode; i++){
- const char *zType;
- if( x.aNode[i].jnFlags & JNODE_LABEL ){
- assert( x.aNode[i].eType==JSON_STRING );
- zType = "label";
- }else{
- zType = jsonType[x.aNode[i].eType];
- }
- jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
- i, zType, x.aNode[i].n, x.aUp[i]);
- if( x.aNode[i].u.zJContent!=0 ){
- jsonAppendRaw(&s, " ", 1);
- jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
- }
- jsonAppendRaw(&s, "\n", 1);
- }
- jsonParseReset(&x);
- jsonResult(&s);
-}
-
-/*
-** The json_test1(JSON) function return true (1) if the input is JSON
-** text generated by another json function. It returns (0) if the input
-** is not known to be JSON.
-*/
-static void jsonTest1Func(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- UNUSED_PARAM(argc);
- sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
-}
-#endif /* SQLITE_DEBUG */
-
-/****************************************************************************
-** Scalar SQL function implementations
-****************************************************************************/
-
-/*
-** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
-** corresponding to the SQL value input. Mostly this means putting
-** double-quotes around strings and returning the unquoted string "null"
-** when given a NULL input.
-*/
-static void jsonQuoteFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString jx;
- UNUSED_PARAM(argc);
-
- jsonInit(&jx, ctx);
- jsonAppendValue(&jx, argv[0]);
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-/*
-** Implementation of the json_array(VALUE,...) function. Return a JSON
-** array that contains all values given in arguments. Or if any argument
-** is a BLOB, throw an error.
-*/
-static void jsonArrayFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- int i;
- JsonString jx;
-
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=0; i<argc; i++){
- jsonAppendSeparator(&jx);
- jsonAppendValue(&jx, argv[i]);
- }
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-/*
-** json_array_length(JSON)
-** json_array_length(JSON, PATH)
-**
-** Return the number of elements in the top-level JSON array.
-** Return 0 if the input is not a well-formed JSON array.
-*/
-static void jsonArrayLengthFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- sqlite3_int64 n = 0;
- u32 i;
- JsonNode *pNode;
-
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- if( argc==2 ){
- const char *zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- }else{
- pNode = x.aNode;
- }
- if( pNode==0 ){
- x.nErr = 1;
- }else if( pNode->eType==JSON_ARRAY ){
- assert( (pNode->jnFlags & JNODE_APPEND)==0 );
- for(i=1; i<=pNode->n; n++){
- i += jsonNodeSize(&pNode[i]);
- }
- }
- if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
- jsonParseReset(&x);
-}
-
-/*
-** json_extract(JSON, PATH, ...)
-**
-** Return the element described by PATH. Return NULL if there is no
-** PATH element. If there are multiple PATHs, then return a JSON array
-** with the result from each path. Throw an error if the JSON or any PATH
-** is malformed.
-*/
-static void jsonExtractFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- JsonString jx;
- int i;
+ case SQLITE_UPDATE:
+ bDone = 1;
+ if( pChange->op==SQLITE_DELETE ){
+ if( pChange->bIndirect==0 ){
+ u8 *pCsr = aRec;
+ sessionSkipRecord(&pCsr, pIter->nCol);
+ sessionAppendByte(&sOut, SQLITE_INSERT, &rc);
+ sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+ sessionAppendRecordMerge(&sOut, pIter->nCol,
+ pCsr, nRec-(pCsr-aRec),
+ pChange->aRecord, pChange->nRecord, &rc
+ );
+ }
+ }else{
+ sessionAppendPartialUpdate(&sOut, pIter,
+ aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
+ );
+ }
+ break;
- if( argc<2 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; i<argc; i++){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) break;
- if( argc>2 ){
- jsonAppendSeparator(&jx);
- if( pNode ){
- jsonRenderNode(pNode, &jx, 0);
- }else{
- jsonAppendRaw(&jx, "null", 4);
+ default:
+ assert( pIter->op==SQLITE_DELETE );
+ bDone = 1;
+ if( pChange->op==SQLITE_INSERT ){
+ sessionAppendByte(&sOut, SQLITE_DELETE, &rc);
+ sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+ sessionAppendRecordMerge(&sOut, pIter->nCol,
+ pChange->aRecord, pChange->nRecord, aRec, nRec, &rc
+ );
+ }
+ break;
}
- }else if( pNode ){
- jsonReturn(pNode, ctx, 0);
}
- }
- if( argc>2 && i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
- }
- jsonReset(&jx);
- jsonParseReset(&x);
-}
-
-/*
-** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON
-** object that contains all name/value given in arguments. Or if any name
-** is not a string or if any value is a BLOB, throw an error.
-*/
-static void jsonObjectFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- int i;
- JsonString jx;
- const char *z;
- u32 n;
- if( argc&1 ){
- sqlite3_result_error(ctx, "json_object() requires an even number "
- "of arguments", -1);
- return;
- }
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '{');
- for(i=0; i<argc; i+=2){
- if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
- sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
- jsonReset(&jx);
- return;
+ if( bDone==0 ){
+ sessionAppendByte(&sOut, pIter->op, &rc);
+ sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+ sessionAppendBlob(&sOut, aRec, nRec, &rc);
}
- jsonAppendSeparator(&jx);
- z = (const char*)sqlite3_value_text(argv[i]);
- n = (u32)sqlite3_value_bytes(argv[i]);
- jsonAppendString(&jx, z, n);
- jsonAppendChar(&jx, ':');
- jsonAppendValue(&jx, argv[i+1]);
+ if( rc==SQLITE_OK && xOutput && sOut.nBuf>sessions_strm_chunk_size ){
+ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+ sOut.nBuf = 0;
+ }
+ if( rc ) break;
}
- jsonAppendChar(&jx, '}');
- jsonResult(&jx);
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-/*
-** json_remove(JSON, PATH, ...)
-**
-** Remove the named elements from JSON and return the result. malformed
-** JSON or PATH arguments result in an error.
-*/
-static void jsonRemoveFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- if( argc<1 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i++){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- if( zPath==0 ) goto remove_done;
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto remove_done;
- if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
- }
- if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturnJson(x.aNode, ctx, 0);
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(sOut.aBuf);
+ memset(&sOut, 0, sizeof(sOut));
}
-remove_done:
- jsonParseReset(&x);
-}
-
-/*
-** json_replace(JSON, PATH, VALUE, ...)
-**
-** Replace the value at PATH with VALUE. If PATH does not already exist,
-** this routine is a no-op. If JSON or PATH is malformed, throw an error.
-*/
-static void jsonReplaceFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- if( argc<1 ) return;
- if( (argc&1)==0 ) {
- jsonWrongNumArgs(ctx, "replace");
- return;
- }
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto replace_err;
- if( pNode ){
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->iVal = (u8)(i+1);
+ if( rc==SQLITE_OK ){
+ if( xOutput ){
+ if( sOut.nBuf>0 ){
+ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+ }
+ }else{
+ *ppOut = (void*)sOut.aBuf;
+ *pnOut = sOut.nBuf;
+ sOut.aBuf = 0;
}
}
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-replace_err:
- jsonParseReset(&x);
+ sqlite3_free(sOut.aBuf);
+ return rc;
}
/*
-** json_set(JSON, PATH, VALUE, ...)
-**
-** Set the value at PATH to VALUE. Create the PATH if it does not already
-** exist. Overwrite existing values that do exist.
-** If JSON or PATH is malformed, throw an error.
-**
-** json_insert(JSON, PATH, VALUE, ...)
-**
-** Create PATH and initialize it to VALUE. If PATH already exists, this
-** routine is a no-op. If JSON or PATH is malformed, throw an error.
+** Create a new rebaser object.
*/
-static void jsonSetFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- int bApnd;
- int bIsSet = *(int*)sqlite3_user_data(ctx);
+SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew){
+ int rc = SQLITE_OK;
+ sqlite3_rebaser *pNew;
- if( argc<1 ) return;
- if( (argc&1)==0 ) {
- jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
- return;
- }
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx);
- if( x.oom ){
- sqlite3_result_error_nomem(ctx);
- goto jsonSetDone;
- }else if( x.nErr ){
- goto jsonSetDone;
- }else if( pNode && (bApnd || bIsSet) ){
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->iVal = (u8)(i+1);
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
+ pNew = sqlite3_malloc(sizeof(sqlite3_rebaser));
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
}else{
- jsonReturnJson(x.aNode, ctx, argv);
+ memset(pNew, 0, sizeof(sqlite3_rebaser));
}
-jsonSetDone:
- jsonParseReset(&x);
+ *ppNew = pNew;
+ return rc;
}
/*
-** json_type(JSON)
-** json_type(JSON, PATH)
-**
-** Return the top-level "type" of a JSON string. Throw an error if
-** either the JSON or PATH inputs are not well-formed.
+** Call this one or more times to configure a rebaser.
*/
-static void jsonTypeFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
+SQLITE_API int sqlite3rebaser_configure(
+ sqlite3_rebaser *p,
+ int nRebase, const void *pRebase
){
- JsonParse x; /* The parse */
- const char *zPath;
- JsonNode *pNode;
-
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- if( argc==2 ){
- zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- }else{
- pNode = x.aNode;
- }
- if( pNode ){
- sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */
+ int rc; /* Return code */
+ rc = sqlite3changeset_start(&pIter, nRebase, (void*)pRebase);
+ if( rc==SQLITE_OK ){
+ rc = sessionChangesetToHash(pIter, &p->grp, 1);
}
- jsonParseReset(&x);
+ sqlite3changeset_finalize(pIter);
+ return rc;
}
/*
-** json_valid(JSON)
-**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** Rebase a changeset according to current rebaser configuration
*/
-static void jsonValidFunc(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
+SQLITE_API int sqlite3rebaser_rebase(
+ sqlite3_rebaser *p,
+ int nIn, const void *pIn,
+ int *pnOut, void **ppOut
){
- JsonParse x; /* The parse */
- int rc = 0;
+ sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */
+ int rc = sqlite3changeset_start(&pIter, nIn, (void*)pIn);
- UNUSED_PARAM(argc);
- if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){
- rc = 1;
+ if( rc==SQLITE_OK ){
+ rc = sessionRebase(p, pIter, 0, 0, pnOut, ppOut);
+ sqlite3changeset_finalize(pIter);
}
- jsonParseReset(&x);
- sqlite3_result_int(ctx, rc);
-}
-
-/****************************************************************************
-** Aggregate SQL function implementations
-****************************************************************************/
-/*
-** json_group_array(VALUE)
-**
-** Return a JSON array composed of all values in the aggregate.
-*/
-static void jsonArrayStep(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString *pStr;
- UNUSED_PARAM(argc);
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
- if( pStr ){
- if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
- jsonAppendChar(pStr, '[');
- }else{
- jsonAppendChar(pStr, ',');
- pStr->pCtx = ctx;
- }
- jsonAppendValue(pStr, argv[0]);
- }
-}
-static void jsonArrayFinal(sqlite3_context *ctx){
- JsonString *pStr;
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
- if( pStr ){
- pStr->pCtx = ctx;
- jsonAppendChar(pStr, ']');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
- }else{
- sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
- pStr->bStatic = 1;
- }
- }else{
- sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
- }
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ return rc;
}
/*
-** json_group_obj(NAME,VALUE)
-**
-** Return a JSON object composed of all names and values in the aggregate.
+** Rebase a changeset according to current rebaser configuration
*/
-static void jsonObjectStep(
- sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
-){
- JsonString *pStr;
- const char *z;
- u32 n;
- UNUSED_PARAM(argc);
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
- if( pStr ){
- if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
- jsonAppendChar(pStr, '{');
- }else{
- jsonAppendChar(pStr, ',');
- pStr->pCtx = ctx;
- }
- z = (const char*)sqlite3_value_text(argv[0]);
- n = (u32)sqlite3_value_bytes(argv[0]);
- jsonAppendString(pStr, z, n);
- jsonAppendChar(pStr, ':');
- jsonAppendValue(pStr, argv[1]);
- }
-}
-static void jsonObjectFinal(sqlite3_context *ctx){
- JsonString *pStr;
- pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
- if( pStr ){
- jsonAppendChar(pStr, '}');
- if( pStr->bErr ){
- if( pStr->bErr==0 ) sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
- }else{
- sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
- pStr->bStatic = 1;
- }
- }else{
- sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
- }
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-/****************************************************************************
-** The json_each virtual table
-****************************************************************************/
-typedef struct JsonEachCursor JsonEachCursor;
-struct JsonEachCursor {
- sqlite3_vtab_cursor base; /* Base class - must be first */
- u32 iRowid; /* The rowid */
- u32 iBegin; /* The first node of the scan */
- u32 i; /* Index in sParse.aNode[] of current row */
- u32 iEnd; /* EOF when i equals or exceeds this value */
- u8 eType; /* Type of top-level element */
- u8 bRecursive; /* True for json_tree(). False for json_each() */
- char *zJson; /* Input JSON */
- char *zRoot; /* Path by which to filter zJson */
- JsonParse sParse; /* Parse of the input JSON */
-};
-
-/* Constructor for the json_each virtual table */
-static int jsonEachConnect(
- sqlite3 *db,
- void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVtab,
- char **pzErr
+SQLITE_API int sqlite3rebaser_rebase_strm(
+ sqlite3_rebaser *p,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
){
- sqlite3_vtab *pNew;
- int rc;
-
-/* Column numbers */
-#define JEACH_KEY 0
-#define JEACH_VALUE 1
-#define JEACH_TYPE 2
-#define JEACH_ATOM 3
-#define JEACH_ID 4
-#define JEACH_PARENT 5
-#define JEACH_FULLKEY 6
-#define JEACH_PATH 7
-#define JEACH_JSON 8
-#define JEACH_ROOT 9
+ sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */
+ int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
- UNUSED_PARAM(pzErr);
- UNUSED_PARAM(argv);
- UNUSED_PARAM(argc);
- UNUSED_PARAM(pAux);
- rc = sqlite3_declare_vtab(db,
- "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
- "json HIDDEN,root HIDDEN)");
if( rc==SQLITE_OK ){
- pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
- if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
+ rc = sessionRebase(p, pIter, xOutput, pOut, 0, 0);
+ sqlite3changeset_finalize(pIter);
}
- return rc;
-}
-
-/* destructor for json_each virtual table */
-static int jsonEachDisconnect(sqlite3_vtab *pVtab){
- sqlite3_free(pVtab);
- return SQLITE_OK;
-}
-
-/* constructor for a JsonEachCursor object for json_each(). */
-static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
- JsonEachCursor *pCur;
-
- UNUSED_PARAM(p);
- pCur = sqlite3_malloc( sizeof(*pCur) );
- if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
- *ppCursor = &pCur->base;
- return SQLITE_OK;
-}
-/* constructor for a JsonEachCursor object for json_tree(). */
-static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
- int rc = jsonEachOpenEach(p, ppCursor);
- if( rc==SQLITE_OK ){
- JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
- pCur->bRecursive = 1;
- }
return rc;
}
-/* Reset a JsonEachCursor back to its original state. Free any memory
-** held. */
-static void jsonEachCursorReset(JsonEachCursor *p){
- sqlite3_free(p->zJson);
- sqlite3_free(p->zRoot);
- jsonParseReset(&p->sParse);
- p->iRowid = 0;
- p->i = 0;
- p->iEnd = 0;
- p->eType = 0;
- p->zJson = 0;
- p->zRoot = 0;
-}
-
-/* Destructor for a jsonEachCursor object */
-static int jsonEachClose(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- jsonEachCursorReset(p);
- sqlite3_free(cur);
- return SQLITE_OK;
-}
-
-/* Return TRUE if the jsonEachCursor object has been advanced off the end
-** of the JSON object */
-static int jsonEachEof(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- return p->i >= p->iEnd;
-}
-
-/* Advance the cursor to the next element for json_tree() */
-static int jsonEachNext(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- if( p->bRecursive ){
- if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
- p->i++;
- p->iRowid++;
- if( p->i<p->iEnd ){
- u32 iUp = p->sParse.aUp[p->i];
- JsonNode *pUp = &p->sParse.aNode[iUp];
- p->eType = pUp->eType;
- if( pUp->eType==JSON_ARRAY ){
- if( iUp==p->i-1 ){
- pUp->u.iKey = 0;
- }else{
- pUp->u.iKey++;
- }
- }
- }
- }else{
- switch( p->eType ){
- case JSON_ARRAY: {
- p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
- p->iRowid++;
- break;
- }
- case JSON_OBJECT: {
- p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
- p->iRowid++;
- break;
- }
- default: {
- p->i = p->iEnd;
- break;
- }
- }
- }
- return SQLITE_OK;
-}
-
-/* Append the name of the path for element i to pStr
+/*
+** Destroy a rebaser object
*/
-static void jsonEachComputePath(
- JsonEachCursor *p, /* The cursor */
- JsonString *pStr, /* Write the path here */
- u32 i /* Path to this element */
-){
- JsonNode *pNode, *pUp;
- u32 iUp;
- if( i==0 ){
- jsonAppendChar(pStr, '$');
- return;
- }
- iUp = p->sParse.aUp[i];
- jsonEachComputePath(p, pStr, iUp);
- pNode = &p->sParse.aNode[i];
- pUp = &p->sParse.aNode[iUp];
- if( pUp->eType==JSON_ARRAY ){
- jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
- }else{
- assert( pUp->eType==JSON_OBJECT );
- if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
- assert( pNode->eType==JSON_STRING );
- assert( pNode->jnFlags & JNODE_LABEL );
- jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){
+ if( p ){
+ sessionDeleteTable(p->grp.pList);
+ sqlite3_free(p);
}
}
-/* Return the value of a column */
-static int jsonEachColumn(
- sqlite3_vtab_cursor *cur, /* The cursor */
- sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
- int i /* Which column to return */
-){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- JsonNode *pThis = &p->sParse.aNode[p->i];
- switch( i ){
- case JEACH_KEY: {
- if( p->i==0 ) break;
- if( p->eType==JSON_OBJECT ){
- jsonReturn(pThis, ctx, 0);
- }else if( p->eType==JSON_ARRAY ){
- u32 iKey;
- if( p->bRecursive ){
- if( p->iRowid==0 ) break;
- iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
- }else{
- iKey = p->iRowid;
- }
- sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
- }
- break;
- }
- case JEACH_VALUE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- jsonReturn(pThis, ctx, 0);
- break;
- }
- case JEACH_TYPE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
- break;
- }
- case JEACH_ATOM: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- if( pThis->eType>=JSON_ARRAY ) break;
- jsonReturn(pThis, ctx, 0);
- break;
- }
- case JEACH_ID: {
- sqlite3_result_int64(ctx,
- (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
- break;
- }
- case JEACH_PARENT: {
- if( p->i>p->iBegin && p->bRecursive ){
- sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
- }
- break;
- }
- case JEACH_FULLKEY: {
- JsonString x;
- jsonInit(&x, ctx);
- if( p->bRecursive ){
- jsonEachComputePath(p, &x, p->i);
- }else{
- if( p->zRoot ){
- jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
- }else{
- jsonAppendChar(&x, '$');
- }
- if( p->eType==JSON_ARRAY ){
- jsonPrintf(30, &x, "[%d]", p->iRowid);
- }else{
- jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
- }
- }
- jsonResult(&x);
- break;
- }
- case JEACH_PATH: {
- if( p->bRecursive ){
- JsonString x;
- jsonInit(&x, ctx);
- jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
- jsonResult(&x);
- break;
+/*
+** Global configuration
+*/
+SQLITE_API int sqlite3session_config(int op, void *pArg){
+ int rc = SQLITE_OK;
+ switch( op ){
+ case SQLITE_SESSION_CONFIG_STRMSIZE: {
+ int *pInt = (int*)pArg;
+ if( *pInt>0 ){
+ sessions_strm_chunk_size = *pInt;
}
- /* For json_each() path and root are the same so fall through
- ** into the root case */
- }
- case JEACH_ROOT: {
- const char *zRoot = p->zRoot;
- if( zRoot==0 ) zRoot = "$";
- sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+ *pInt = sessions_strm_chunk_size;
break;
}
- case JEACH_JSON: {
- assert( i==JEACH_JSON );
- sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+ default:
+ rc = SQLITE_MISUSE;
break;
- }
- }
- return SQLITE_OK;
-}
-
-/* Return the current rowid value */
-static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- *pRowid = p->iRowid;
- return SQLITE_OK;
-}
-
-/* The query strategy is to look for an equality constraint on the json
-** column. Without such a constraint, the table cannot operate. idxNum is
-** 1 if the constraint is found, 3 if the constraint and zRoot are found,
-** and 0 otherwise.
-*/
-static int jsonEachBestIndex(
- sqlite3_vtab *tab,
- sqlite3_index_info *pIdxInfo
-){
- int i;
- int jsonIdx = -1;
- int rootIdx = -1;
- const struct sqlite3_index_constraint *pConstraint;
-
- UNUSED_PARAM(tab);
- pConstraint = pIdxInfo->aConstraint;
- for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
- if( pConstraint->usable==0 ) continue;
- if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
- switch( pConstraint->iColumn ){
- case JEACH_JSON: jsonIdx = i; break;
- case JEACH_ROOT: rootIdx = i; break;
- default: /* no-op */ break;
- }
- }
- if( jsonIdx<0 ){
- pIdxInfo->idxNum = 0;
- pIdxInfo->estimatedCost = 1e99;
- }else{
- pIdxInfo->estimatedCost = 1.0;
- pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1;
- pIdxInfo->aConstraintUsage[jsonIdx].omit = 1;
- if( rootIdx<0 ){
- pIdxInfo->idxNum = 1;
- }else{
- pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2;
- pIdxInfo->aConstraintUsage[rootIdx].omit = 1;
- pIdxInfo->idxNum = 3;
- }
- }
- return SQLITE_OK;
-}
-
-/* Start a search on a new JSON string */
-static int jsonEachFilter(
- sqlite3_vtab_cursor *cur,
- int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv
-){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- const char *z;
- const char *zRoot = 0;
- sqlite3_int64 n;
-
- UNUSED_PARAM(idxStr);
- UNUSED_PARAM(argc);
- jsonEachCursorReset(p);
- if( idxNum==0 ) return SQLITE_OK;
- z = (const char*)sqlite3_value_text(argv[0]);
- if( z==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[0]);
- p->zJson = sqlite3_malloc64( n+1 );
- if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, 0, p->zJson) ){
- int rc = SQLITE_NOMEM;
- if( p->sParse.oom==0 ){
- sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
- if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
- }
- jsonEachCursorReset(p);
- return rc;
- }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
- jsonEachCursorReset(p);
- return SQLITE_NOMEM;
- }else{
- JsonNode *pNode = 0;
- if( idxNum==3 ){
- const char *zErr = 0;
- zRoot = (const char*)sqlite3_value_text(argv[1]);
- if( zRoot==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[1]);
- p->zRoot = sqlite3_malloc64( n+1 );
- if( p->zRoot==0 ) return SQLITE_NOMEM;
- memcpy(p->zRoot, zRoot, (size_t)n+1);
- if( zRoot[0]!='$' ){
- zErr = zRoot;
- }else{
- pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
- }
- if( zErr ){
- sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
- jsonEachCursorReset(p);
- return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
- }else if( pNode==0 ){
- return SQLITE_OK;
- }
- }else{
- pNode = p->sParse.aNode;
- }
- p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
- p->eType = pNode->eType;
- if( p->eType>=JSON_ARRAY ){
- pNode->u.iKey = 0;
- p->iEnd = p->i + pNode->n + 1;
- if( p->bRecursive ){
- p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
- if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
- p->i--;
- }
- }else{
- p->i++;
- }
- }else{
- p->iEnd = p->i+1;
- }
- }
- return SQLITE_OK;
-}
-
-/* The methods of the json_each virtual table */
-static sqlite3_module jsonEachModule = {
- 0, /* iVersion */
- 0, /* xCreate */
- jsonEachConnect, /* xConnect */
- jsonEachBestIndex, /* xBestIndex */
- jsonEachDisconnect, /* xDisconnect */
- 0, /* xDestroy */
- jsonEachOpenEach, /* xOpen - open a cursor */
- jsonEachClose, /* xClose - close a cursor */
- jsonEachFilter, /* xFilter - configure scan constraints */
- jsonEachNext, /* xNext - advance a cursor */
- jsonEachEof, /* xEof - check for end of scan */
- jsonEachColumn, /* xColumn - read data */
- jsonEachRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- 0, /* xSavepoint */
- 0, /* xRelease */
- 0 /* xRollbackTo */
-};
-
-/* The methods of the json_tree virtual table. */
-static sqlite3_module jsonTreeModule = {
- 0, /* iVersion */
- 0, /* xCreate */
- jsonEachConnect, /* xConnect */
- jsonEachBestIndex, /* xBestIndex */
- jsonEachDisconnect, /* xDisconnect */
- 0, /* xDestroy */
- jsonEachOpenTree, /* xOpen - open a cursor */
- jsonEachClose, /* xClose - close a cursor */
- jsonEachFilter, /* xFilter - configure scan constraints */
- jsonEachNext, /* xNext - advance a cursor */
- jsonEachEof, /* xEof - check for end of scan */
- jsonEachColumn, /* xColumn - read data */
- jsonEachRowid, /* xRowid - read data */
- 0, /* xUpdate */
- 0, /* xBegin */
- 0, /* xSync */
- 0, /* xCommit */
- 0, /* xRollback */
- 0, /* xFindMethod */
- 0, /* xRename */
- 0, /* xSavepoint */
- 0, /* xRelease */
- 0 /* xRollbackTo */
-};
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
-
-/****************************************************************************
-** The following routines are the only publically visible identifiers in this
-** file. Call the following routines in order to register the various SQL
-** functions and the virtual table implemented by this file.
-****************************************************************************/
-
-SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
- int rc = SQLITE_OK;
- unsigned int i;
- static const struct {
- const char *zName;
- int nArg;
- int flag;
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
- } aFunc[] = {
- { "json", 1, 0, jsonRemoveFunc },
- { "json_array", -1, 0, jsonArrayFunc },
- { "json_array_length", 1, 0, jsonArrayLengthFunc },
- { "json_array_length", 2, 0, jsonArrayLengthFunc },
- { "json_extract", -1, 0, jsonExtractFunc },
- { "json_insert", -1, 0, jsonSetFunc },
- { "json_object", -1, 0, jsonObjectFunc },
- { "json_quote", 1, 0, jsonQuoteFunc },
- { "json_remove", -1, 0, jsonRemoveFunc },
- { "json_replace", -1, 0, jsonReplaceFunc },
- { "json_set", -1, 1, jsonSetFunc },
- { "json_type", 1, 0, jsonTypeFunc },
- { "json_type", 2, 0, jsonTypeFunc },
- { "json_valid", 1, 0, jsonValidFunc },
-
-#if SQLITE_DEBUG
- /* DEBUG and TESTING functions */
- { "json_parse", 1, 0, jsonParseFunc },
- { "json_test1", 1, 0, jsonTest1Func },
-#endif
- };
- static const struct {
- const char *zName;
- int nArg;
- void (*xStep)(sqlite3_context*,int,sqlite3_value**);
- void (*xFinal)(sqlite3_context*);
- } aAgg[] = {
- { "json_group_array", 1, jsonArrayStep, jsonArrayFinal },
- { "json_group_object", 2, jsonObjectStep, jsonObjectFinal },
- };
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- static const struct {
- const char *zName;
- sqlite3_module *pModule;
- } aMod[] = {
- { "json_each", &jsonEachModule },
- { "json_tree", &jsonTreeModule },
- };
-#endif
- for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
- rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC,
- (void*)&aFunc[i].flag,
- aFunc[i].xFunc, 0, 0);
- }
- for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
- rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
- SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
- 0, aAgg[i].xStep, aAgg[i].xFinal);
- }
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
- rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
}
-#endif
return rc;
}
+#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
-#ifndef SQLITE_CORE
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-SQLITE_API int sqlite3_json_init(
- sqlite3 *db,
- char **pzErrMsg,
- const sqlite3_api_routines *pApi
-){
- SQLITE_EXTENSION_INIT2(pApi);
- (void)pzErrMsg; /* Unused parameter */
- return sqlite3Json1Init(db);
-}
-#endif
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
-
-/************** End of json1.c ***********************************************/
+/************** End of sqlite3session.c **************************************/
/************** Begin file fts5.c ********************************************/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
@@ -178604,7 +207937,7 @@ SQLITE_API int sqlite3_json_init(
**
******************************************************************************
**
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
+** Interfaces to extend FTS5. Using the interfaces defined in this file,
** FTS5 may be extended with:
**
** * custom tokenizers, and
@@ -178649,19 +207982,19 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
+** Return a copy of the context pointer the extension function was
** registered with.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
** to the total number of tokens in the FTS5 table. Or, if iCol is
** non-negative but less than the number of columns in the table, return
-** the total number of tokens in column iCol, considering all rows in
+** the total number of tokens in column iCol, considering all rows in
** the FTS5 table.
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
+** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** xColumnCount(pFts):
@@ -178675,7 +208008,7 @@ struct Fts5PhraseIter {
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
+** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** This function may be quite inefficient if used with an FTS5 table
@@ -178702,8 +208035,8 @@ struct Fts5PhraseIter {
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
+** "detail=none" or "detail=column" option. If the FTS5 table is created
+** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always returns 0.
**
** xInst:
@@ -178714,15 +208047,11 @@ struct Fts5PhraseIter {
**
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. The exception is if the table was created
-** with the offsets=0 option specified. In this case *piOff is always
-** set to -1.
-**
-** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
-** if an error occurs.
+** first token of the phrase. Returns SQLITE_OK if successful, or an error
+** code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option.
+** "detail=none" or "detail=column" option.
**
** xRowid:
** Returns the rowid of the current row.
@@ -178738,11 +208067,11 @@ struct Fts5PhraseIter {
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
** current query is executed. Any column filter that applies to
-** phrase iPhrase of the current query is included in $p. For each
-** row visited, the callback function passed as the fourth argument
-** is invoked. The context and API objects passed to the callback
+** phrase iPhrase of the current query is included in $p. For each
+** row visited, the callback function passed as the fourth argument
+** is invoked. The context and API objects passed to the callback
** function may be used to access the properties of each matched row.
-** Invoking Api.xUserData() returns a copy of the pointer passed as
+** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
@@ -178757,14 +208086,14 @@ struct Fts5PhraseIter {
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
-** Save the pointer passed as the second argument as the extension functions
+** Save the pointer passed as the second argument as the extension function's
** "auxiliary data". The pointer may then be retrieved by the current or any
** future invocation of the same fts5 extension function made as part of
-** of the same MATCH query using the xGetAuxdata() API.
+** the same MATCH query using the xGetAuxdata() API.
**
** Each extension function is allocated a single auxiliary data slot for
-** each FTS query (MATCH expression). If the extension function is invoked
-** more than once for a single FTS query, then all invocations share a
+** each FTS query (MATCH expression). If the extension function is invoked
+** more than once for a single FTS query, then all invocations share a
** single auxiliary data context.
**
** If there is already an auxiliary data pointer when this function is
@@ -178775,7 +208104,7 @@ struct Fts5PhraseIter {
** The xDelete callback, if one is specified, is also invoked on the
** auxiliary data pointer after the FTS5 query has finished.
**
-** If an error (e.g. an OOM condition) occurs within this function, an
+** If an error (e.g. an OOM condition) occurs within this function,
** the auxiliary data is set to NULL and an error code returned. If the
** xDelete parameter was not NULL, it is invoked on the auxiliary data
** pointer before returning.
@@ -178783,7 +208112,7 @@ struct Fts5PhraseIter {
**
** xGetAuxdata(pFts5, bClear)
**
-** Returns the current auxiliary data pointer for the fts5 extension
+** Returns the current auxiliary data pointer for the fts5 extension
** function. See the xSetAuxdata() method for details.
**
** If the bClear argument is non-zero, then the auxiliary data is cleared
@@ -178803,7 +208132,7 @@ struct Fts5PhraseIter {
** method, to iterate through all instances of a single query phrase within
** the current row. This is the same information as is accessible via the
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
-** to use, this API may be faster under some circumstances. To iterate
+** to use, this API may be faster under some circumstances. To iterate
** through instances of phrase iPhrase, use the following code:
**
** Fts5PhraseIter iter;
@@ -178821,8 +208150,8 @@ struct Fts5PhraseIter {
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
+** "detail=none" or "detail=column" option. If the FTS5 table is created
+** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
@@ -178846,16 +208175,16 @@ struct Fts5PhraseIter {
** }
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" option. If the FTS5 table is created with either
-** "detail=none" "content=" option (i.e. if it is a contentless table),
-** then this API always iterates through an empty set (all calls to
+** "detail=none" option. If the FTS5 table is created with either
+** "detail=none" "content=" option (i.e. if it is a contentless table),
+** then this API always iterates through an empty set (all calls to
** xPhraseFirstColumn() set iCol to -1).
**
** The information accessed using this API and its companion
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
** (or xInst/xInstCount). The chief advantage of this API is that it is
** significantly more efficient than those alternatives when used with
-** "detail=column" tables.
+** "detail=column" tables.
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
@@ -178869,7 +208198,7 @@ struct Fts5ExtensionApi {
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
- int (*xTokenize)(Fts5Context*,
+ int (*xTokenize)(Fts5Context*,
const char *pText, int nText, /* Text to tokenize */
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
@@ -178898,15 +208227,15 @@ struct Fts5ExtensionApi {
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
};
-/*
+/*
** CUSTOM AUXILIARY FUNCTIONS
*************************************************************************/
/*************************************************************************
** CUSTOM TOKENIZERS
**
-** Applications may also register custom tokenizer types. A tokenizer
-** is registered by providing fts5 with a populated instance of the
+** Applications may also register custom tokenizer types. A tokenizer
+** is registered by providing fts5 with a populated instance of the
** following structure. All structure methods must be defined, setting
** any member of the fts5_tokenizer struct to NULL leads to undefined
** behaviour. The structure methods are expected to function as follows:
@@ -178917,16 +208246,16 @@ struct Fts5ExtensionApi {
**
** The first argument passed to this function is a copy of the (void*)
** pointer provided by the application when the fts5_tokenizer object
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
+** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
** to create the FTS5 table.
**
-** The final argument is an output variable. If successful, (*ppOut)
+** The final argument is an output variable. If successful, (*ppOut)
** should be set to point to the new tokenizer handle and SQLITE_OK
** returned. If an error occurs, some value other than SQLITE_OK should
-** be returned. In this case, fts5 assumes that the final value of *ppOut
+** be returned. In this case, fts5 assumes that the final value of *ppOut
** is undefined.
**
** xDelete:
@@ -178935,7 +208264,7 @@ struct Fts5ExtensionApi {
** be invoked exactly once for each successful call to xCreate().
**
** xTokenize:
-** This function is expected to tokenize the nText byte string indicated
+** This function is expected to tokenize the nText byte string indicated
** by argument pText. pText may or may not be nul-terminated. The first
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
@@ -178949,8 +208278,8 @@ struct Fts5ExtensionApi {
** determine the set of tokens to add to (or delete from) the
** FTS index.
**
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
-** against the FTS index. The tokenizer is being called to tokenize
+** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
+** against the FTS index. The tokenizer is being called to tokenize
** a bareword or quoted string specified as part of the query.
**
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
@@ -178958,10 +208287,10 @@ struct Fts5ExtensionApi {
** followed by a "*" character, indicating that the last token
** returned by the tokenizer will be treated as a token prefix.
**
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
+** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
** satisfy an fts5_api.xTokenize() request made by an auxiliary
** function. Or an fts5_api.xColumnSize() request made by the same
-** on a columnsize=0 database.
+** on a columnsize=0 database.
** </ul>
**
** For each token in the input string, the supplied callback xToken() must
@@ -178973,10 +208302,10 @@ struct Fts5ExtensionApi {
** which the token is derived within the input.
**
** The second argument passed to the xToken() callback ("tflags") should
-** normally be set to 0. The exception is if the tokenizer supports
+** normally be set to 0. The exception is if the tokenizer supports
** synonyms. In this case see the discussion below for details.
**
-** FTS5 assumes the xToken() callback is invoked for each token in the
+** FTS5 assumes the xToken() callback is invoked for each token in the
** order that they occur within the input text.
**
** If an xToken() callback returns any value other than SQLITE_OK, then
@@ -178990,7 +208319,7 @@ struct Fts5ExtensionApi {
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
-** user wishes to query for a phrase such as "first place". Using the
+** user wishes to query for a phrase such as "first place". Using the
** built-in tokenizers, the FTS5 query 'first + place' will match instances
** of "first place" within the document set, but not alternative forms
** such as "1st place". In some applications, it would be better to match
@@ -178999,8 +208328,8 @@ struct Fts5ExtensionApi {
**
** There are several ways to approach this in FTS5:
**
-** <ol><li> By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
+** <ol><li> By mapping all synonyms to a single token. In this case, using
+** the above example, this means that the tokenizer returns the
** same token for inputs "first" and "1st". Say that token is in
** fact "first", so that when the user inserts the document "I won
** 1st place" entries are added to the index for tokens "i", "won",
@@ -179008,37 +208337,37 @@ struct Fts5ExtensionApi {
** the tokenizer substitutes "first" for "1st" and the query works
** as expected.
**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
+** <li> By querying the index for all synonyms of each query term
+** separately. In this case, when tokenizing query text, the
+** tokenizer may provide multiple synonyms for a single term
+** within the document. FTS5 then queries the index for each
+** synonym individually. For example, faced with the query:
**
** <codeblock>
** ... MATCH 'first place'</codeblock>
**
** the tokenizer offers both "1st" and "first" as synonyms for the
-** first token in the MATCH query and FTS5 effectively runs a query
+** first token in the MATCH query and FTS5 effectively runs a query
** similar to:
**
** <codeblock>
** ... MATCH '(first OR 1st) place'</codeblock>
**
** except that, for the purposes of auxiliary functions, the query
-** still appears to contain just two phrases - "(first OR 1st)"
+** still appears to contain just two phrases - "(first OR 1st)"
** being treated as a single phrase.
**
** <li> By adding multiple synonyms for a single term to the FTS index.
** Using this method, when tokenizing document text, the tokenizer
-** provides multiple synonyms for each token. So that when a
+** provides multiple synonyms for each token. So that when a
** document such as "I won first place" is tokenized, entries are
** added to the FTS index for "i", "won", "first", "1st" and
** "place".
**
** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
-** inefficient), it doesn't matter if the user queries for
-** 'first + place' or '1st + place', as there are entires in the
+** when tokenizing query text (it should not - to do so would be
+** inefficient), it doesn't matter if the user queries for
+** 'first + place' or '1st + place', as there are entries in the
** FTS index corresponding to both forms of the first token.
** </ol>
**
@@ -179058,15 +208387,15 @@ struct Fts5ExtensionApi {
**
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
** xToken() is called. Multiple synonyms may be specified for a single token
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
+** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
** There is no limit to the number of synonyms that may be provided for a
** single token.
**
-** In many cases, method (1) above is the best approach. It does not add
+** In many cases, method (1) above is the best approach. It does not add
** extra data to the FTS index or require FTS5 to query for multiple terms,
** so it is efficient in terms of disk space and query speed. However, it
** does not support prefix queries very well. If, as suggested above, the
-** token "first" is subsituted for "1st" by the tokenizer, then the query:
+** token "first" is substituted for "1st" by the tokenizer, then the query:
**
** <codeblock>
** ... MATCH '1s*'</codeblock>
@@ -179074,18 +208403,18 @@ struct Fts5ExtensionApi {
** will not match documents that contain the token "1st" (as the tokenizer
** will probably not map "1s" to any prefix of "first").
**
-** For full prefix support, method (3) may be preferred. In this case,
+** For full prefix support, method (3) may be preferred. In this case,
** because the index contains entries for both "first" and "1st", prefix
** queries such as 'fi*' or '1s*' will match correctly. However, because
** extra entries are added to the FTS index, this method uses more space
** within the database.
**
** Method (2) offers a midpoint between (1) and (3). Using this method,
-** a query such as '1s*' will match documents that contain the literal
+** a query such as '1s*' will match documents that contain the literal
** token "1st", but not "first" (assuming the tokenizer is not able to
** provide synonyms for prefixes). However, a non-prefix query like '1st'
** will match against "1st" and "first". This method does not require
-** extra disk space, as no extra entries are added to the FTS index.
+** extra disk space, as no extra entries are added to the FTS index.
** On the other hand, it may require more CPU cycles to run MATCH queries,
** as separate queries of the FTS index are required for each synonym.
**
@@ -179099,10 +208428,10 @@ typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
- int (*xTokenize)(Fts5Tokenizer*,
+ int (*xTokenize)(Fts5Tokenizer*,
void *pCtx,
int flags, /* Mask of FTS5_TOKENIZE_* flags */
- const char *pText, int nText,
+ const char *pText, int nText,
int (*xToken)(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
@@ -179204,7 +208533,9 @@ typedef short i16;
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
-#define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
+#ifndef ArraySize
+# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
+#endif
#define testcase(x)
#define ALWAYS(x) 1
@@ -179221,7 +208552,7 @@ typedef sqlite3_uint64 u64;
#endif
-/* Truncate very long tokens to this many bytes. Hard limit is
+/* Truncate very long tokens to this many bytes. Hard limit is
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
** field that occurs at the start of each leaf page (see fts5_index.c). */
#define FTS5_MAX_TOKEN_SIZE 32768
@@ -179233,6 +208564,11 @@ typedef sqlite3_uint64 u64;
*/
#define FTS5_MAX_PREFIX_INDEXES 31
+/*
+** Maximum segments permitted in a single index
+*/
+#define FTS5_MAX_SEGMENT 2000
+
#define FTS5_DEFAULT_NEARDIST 10
#define FTS5_DEFAULT_RANK "bm25"
@@ -179249,7 +208585,7 @@ static int sqlite3Fts5Corrupt(void);
/*
** The assert_nc() macro is similar to the assert() macro, except that it
-** is used for assert() conditions that are true only if it can be
+** is used for assert() conditions that are true only if it can be
** guranteed that the database is not corrupt.
*/
#ifdef SQLITE_DEBUG
@@ -179259,6 +208595,12 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
# define assert_nc(x) assert(x)
#endif
+/*
+** A version of memcmp() that does not cause asan errors if one of the pointer
+** parameters is NULL and the number of bytes to compare is zero.
+*/
+#define fts5Memcmp(s1, s2, n) ((n)==0 ? 0 : memcmp((s1), (s2), (n)))
+
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAM
@@ -179272,7 +208614,7 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
typedef struct Fts5Global Fts5Global;
typedef struct Fts5Colset Fts5Colset;
-/* If a NEAR() clump or phrase may only match a specific set of columns,
+/* If a NEAR() clump or phrase may only match a specific set of columns,
** then an object of the following type is used to record the set of columns.
** Each entry in the aiCol[] array is a column that may be matched.
**
@@ -179300,20 +208642,20 @@ typedef struct Fts5Config Fts5Config;
**
** nAutomerge:
** The minimum number of segments that an auto-merge operation should
-** attempt to merge together. A value of 1 sets the object to use the
+** attempt to merge together. A value of 1 sets the object to use the
** compile time default. Zero disables auto-merge altogether.
**
** zContent:
**
** zContentRowid:
-** The value of the content_rowid= option, if one was specified. Or
+** The value of the content_rowid= option, if one was specified. Or
** the string "rowid" otherwise. This text is not quoted - if it is
** used as part of an SQL statement it needs to be quoted appropriately.
**
** zContentExprlist:
**
** pzErrmsg:
-** This exists in order to allow the fts5_index.c module to return a
+** This exists in order to allow the fts5_index.c module to return a
** decent error message if it encounters a file-format version it does
** not understand.
**
@@ -179337,13 +208679,14 @@ struct Fts5Config {
int nPrefix; /* Number of prefix indexes */
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
- char *zContent; /* content table */
- char *zContentRowid; /* "content_rowid=" option value */
+ char *zContent; /* content table */
+ char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
Fts5Tokenizer *pTok;
fts5_tokenizer *pTokApi;
+ int bLock; /* True when table is preparing statement */
/* Values loaded from the %_config table */
int iCookie; /* Incremented when %_config is modified */
@@ -179446,7 +208789,7 @@ static void sqlite3Fts5Put32(u8*, int);
static int sqlite3Fts5Get32(const u8*);
#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
-#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF)
+#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
typedef struct Fts5PoslistReader Fts5PoslistReader;
struct Fts5PoslistReader {
@@ -179481,7 +208824,7 @@ static int sqlite3Fts5PoslistNext64(
);
/* Malloc utility */
-static void *sqlite3Fts5MallocZero(int *pRc, int nByte);
+static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte);
static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
/* Character set tests (like isspace(), isalpha() etc.) */
@@ -179539,27 +208882,27 @@ static int sqlite3Fts5IndexClose(Fts5Index *p);
** Return a simple checksum value based on the arguments.
*/
static u64 sqlite3Fts5IndexEntryCksum(
- i64 iRowid,
- int iCol,
- int iPos,
+ i64 iRowid,
+ int iCol,
+ int iPos,
int iIdx,
const char *pTerm,
int nTerm
);
/*
-** Argument p points to a buffer containing utf-8 text that is n bytes in
+** Argument p points to a buffer containing utf-8 text that is n bytes in
** size. Return the number of bytes in the nChar character prefix of the
** buffer, or 0 if there are less than nChar characters in total.
*/
static int sqlite3Fts5IndexCharlenToBytelen(
- const char *p,
- int nByte,
+ const char *p,
+ int nByte,
int nChar
);
/*
-** Open a new iterator to iterate though all rowids that match the
+** Open a new iterator to iterate though all rowids that match the
** specified token or token prefix.
*/
static int sqlite3Fts5IndexQuery(
@@ -179583,6 +208926,11 @@ static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
static void sqlite3Fts5IterClose(Fts5IndexIter*);
/*
+** Close the reader blob handle, if it is open.
+*/
+static void sqlite3Fts5IndexCloseReader(Fts5Index*);
+
+/*
** This interface is used by the fts5vocab module.
*/
static const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*);
@@ -179590,7 +208938,7 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter*);
/*
-** Insert or remove data to or from the index. Each time a document is
+** Insert or remove data to or from the index. Each time a document is
** added to or removed from the index, this function is called one or more
** times.
**
@@ -179618,14 +208966,14 @@ static int sqlite3Fts5IndexBeginWrite(
/*
** Flush any data stored in the in-memory hash tables to the database.
-** If the bCommit flag is true, also close any open blob handles.
+** Also close any open blob handles.
*/
-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
+static int sqlite3Fts5IndexSync(Fts5Index *p);
/*
** Discard any data stored in the in-memory hash tables. Do not write it
** to the database. Additionally, assume that the contents of the %_data
-** table may have changed on disk. So any in-memory caches of %_data
+** table may have changed on disk. So any in-memory caches of %_data
** records must be invalidated.
*/
static int sqlite3Fts5IndexRollback(Fts5Index *p);
@@ -179641,16 +208989,16 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
*/
static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
-/*
-** Called during virtual module initialization to register UDF
-** fts5_decode() with SQLite
+/*
+** Called during virtual module initialization to register UDF
+** fts5_decode() with SQLite
*/
static int sqlite3Fts5IndexInit(sqlite3*);
static int sqlite3Fts5IndexSetCookie(Fts5Index*, int);
/*
-** Return the total number of entries read from the %_data table by
+** Return the total number of entries read from the %_data table by
** this connection since it was created.
*/
static int sqlite3Fts5IndexReads(Fts5Index *p);
@@ -179667,7 +209015,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
**************************************************************************/
/**************************************************************************
-** Interface to code in fts5_varint.c.
+** Interface to code in fts5_varint.c.
*/
static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v);
static int sqlite3Fts5GetVarintLen(u32 iVal);
@@ -179692,11 +209040,21 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
/**************************************************************************
-** Interface to code in fts5.c.
+** Interface to code in fts5_main.c.
+*/
+
+/*
+** Virtual-table object.
*/
+typedef struct Fts5Table Fts5Table;
+struct Fts5Table {
+ sqlite3_vtab base; /* Base class used by SQLite core */
+ Fts5Config *pConfig; /* Virtual table configuration */
+ Fts5Index *pIndex; /* Full-text index */
+};
static int sqlite3Fts5GetTokenizer(
- Fts5Global*,
+ Fts5Global*,
const char **azArg,
int nArg,
Fts5Tokenizer**,
@@ -179704,14 +209062,16 @@ static int sqlite3Fts5GetTokenizer(
char **pzErr
);
-static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, Fts5Config **);
+static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
+
+static int sqlite3Fts5FlushToDisk(Fts5Table*);
/*
** End of interface to code in fts5.c.
**************************************************************************/
/**************************************************************************
-** Interface to code in fts5_hash.c.
+** Interface to code in fts5_hash.c.
*/
typedef struct Fts5Hash Fts5Hash;
@@ -179737,8 +209097,9 @@ static void sqlite3Fts5HashClear(Fts5Hash*);
static int sqlite3Fts5HashQuery(
Fts5Hash*, /* Hash table to query */
+ int nPre,
const char *pTerm, int nTerm, /* Query term */
- const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
+ void **ppObj, /* OUT: Pointer to doclist for pTerm */
int *pnDoclist /* OUT: Size of doclist in bytes */
);
@@ -179760,7 +209121,7 @@ static void sqlite3Fts5HashScanEntry(Fts5Hash *,
**************************************************************************/
/**************************************************************************
-** Interface to code in fts5_storage.c. fts5_storage.c contains contains
+** Interface to code in fts5_storage.c. fts5_storage.c contains contains
** code to access the data stored in the %_content and %_docsize tables.
*/
@@ -179790,7 +209151,7 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
+static int sqlite3Fts5StorageSync(Fts5Storage *p);
static int sqlite3Fts5StorageRollback(Fts5Storage *p);
static int sqlite3Fts5StorageConfigValue(
@@ -179809,7 +209170,7 @@ static int sqlite3Fts5StorageReset(Fts5Storage *p);
/**************************************************************************
-** Interface to code in fts5_expr.c.
+** Interface to code in fts5_expr.c.
*/
typedef struct Fts5Expr Fts5Expr;
typedef struct Fts5ExprNode Fts5ExprNode;
@@ -179825,9 +209186,10 @@ struct Fts5Token {
/* Parse a MATCH expression. */
static int sqlite3Fts5ExprNew(
- Fts5Config *pConfig,
+ Fts5Config *pConfig,
+ int iCol, /* Column on LHS of MATCH operator */
const char *zExpr,
- Fts5Expr **ppNew,
+ Fts5Expr **ppNew,
char **pzErr
);
@@ -179846,6 +209208,7 @@ static int sqlite3Fts5ExprEof(Fts5Expr*);
static i64 sqlite3Fts5ExprRowid(Fts5Expr*);
static void sqlite3Fts5ExprFree(Fts5Expr*);
+static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2);
/* Called during startup to register a UDF with SQLite */
static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
@@ -179887,21 +209250,23 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
);
static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
- Fts5Parse *pParse,
- Fts5ExprPhrase *pPhrase,
+ Fts5Parse *pParse,
+ Fts5ExprPhrase *pPhrase,
Fts5Token *pToken,
int bPrefix
);
+static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*);
+
static Fts5ExprNearset *sqlite3Fts5ParseNearset(
- Fts5Parse*,
+ Fts5Parse*,
Fts5ExprNearset*,
- Fts5ExprPhrase*
+ Fts5ExprPhrase*
);
static Fts5Colset *sqlite3Fts5ParseColset(
- Fts5Parse*,
- Fts5Colset*,
+ Fts5Parse*,
+ Fts5Colset*,
Fts5Token *
);
@@ -179910,7 +209275,7 @@ static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
-static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
+static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNode*, Fts5Colset*);
static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
@@ -179922,7 +209287,7 @@ static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
/**************************************************************************
-** Interface to code in fts5_aux.c.
+** Interface to code in fts5_aux.c.
*/
static int sqlite3Fts5AuxInit(fts5_api*);
@@ -179931,7 +209296,7 @@ static int sqlite3Fts5AuxInit(fts5_api*);
**************************************************************************/
/**************************************************************************
-** Interface to code in fts5_tokenizer.c.
+** Interface to code in fts5_tokenizer.c.
*/
static int sqlite3Fts5TokenizerInit(fts5_api*);
@@ -179940,7 +209305,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api*);
**************************************************************************/
/**************************************************************************
-** Interface to code in fts5_vocab.c.
+** Interface to code in fts5_vocab.c.
*/
static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
@@ -179951,11 +209316,14 @@ static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
/**************************************************************************
-** Interface to automatically generated code in fts5_unicode2.c.
+** Interface to automatically generated code in fts5_unicode2.c.
*/
-static int sqlite3Fts5UnicodeIsalnum(int c);
static int sqlite3Fts5UnicodeIsdiacritic(int c);
static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
+
+static int sqlite3Fts5UnicodeCatParse(const char*, u8*);
+static int sqlite3Fts5UnicodeCategory(u32 iCode);
+static void sqlite3Fts5UnicodeAscii(u8*, u8*);
/*
** End of interface to code in fts5_unicode2.c.
**************************************************************************/
@@ -179967,15 +209335,16 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
#define FTS5_NOT 3
#define FTS5_TERM 4
#define FTS5_COLON 5
-#define FTS5_LP 6
-#define FTS5_RP 7
-#define FTS5_MINUS 8
-#define FTS5_LCP 9
-#define FTS5_RCP 10
-#define FTS5_STRING 11
-#define FTS5_COMMA 12
-#define FTS5_PLUS 13
-#define FTS5_STAR 14
+#define FTS5_MINUS 6
+#define FTS5_LCP 7
+#define FTS5_RCP 8
+#define FTS5_STRING 9
+#define FTS5_LP 10
+#define FTS5_RP 11
+#define FTS5_CARET 12
+#define FTS5_COMMA 13
+#define FTS5_PLUS 14
+#define FTS5_STAR 15
/*
** 2000-05-29
@@ -180002,6 +209371,7 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
** input grammar file:
*/
/* #include <stdio.h> */
+/* #include <assert.h> */
/************ Begin %include sections from the grammar ************************/
/* #include "fts5Int.h" */
@@ -180060,7 +209430,7 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
** the minor type might be the name of the identifier.
** Each non-terminal can have a different minor type.
** Terminal symbols all have the same minor type, though.
-** This macros defines the minor type for terminal
+** This macros defines the minor type for terminal
** symbols.
** fts5YYMINORTYPE is the data type used for all minor types.
** This is typically a union of many types, one of
@@ -180070,26 +209440,30 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
** zero the stack is dynamically sized using realloc()
** sqlite3Fts5ParserARG_SDECL A static variable declaration for the %extra_argument
** sqlite3Fts5ParserARG_PDECL A parameter declaration for the %extra_argument
+** sqlite3Fts5ParserARG_PARAM Code to pass %extra_argument as a subroutine parameter
** sqlite3Fts5ParserARG_STORE Code to store %extra_argument into fts5yypParser
** sqlite3Fts5ParserARG_FETCH Code to extract %extra_argument from fts5yypParser
+** sqlite3Fts5ParserCTX_* As sqlite3Fts5ParserARG_ except for %extra_context
** fts5YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing.
** fts5YYNSTATE the combined number of states.
** fts5YYNRULE the number of rules in the grammar
+** fts5YYNFTS5TOKEN Number of terminal symbols
** fts5YY_MAX_SHIFT Maximum value for shift actions
** fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
** fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-** fts5YY_MIN_REDUCE Maximum value for reduce actions
** fts5YY_ERROR_ACTION The fts5yy_action[] code for syntax error
** fts5YY_ACCEPT_ACTION The fts5yy_action[] code for accept
** fts5YY_NO_ACTION The fts5yy_action[] code for no-op
+** fts5YY_MIN_REDUCE Minimum value for reduce actions
+** fts5YY_MAX_REDUCE Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define fts5YYCODETYPE unsigned char
-#define fts5YYNOCODE 28
+#define fts5YYNOCODE 27
#define fts5YYACTIONTYPE unsigned char
#define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token
typedef union {
@@ -180106,19 +209480,28 @@ typedef union {
#endif
#define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse;
#define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
-#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
-#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
-#define fts5YYNSTATE 29
-#define fts5YYNRULE 26
-#define fts5YY_MAX_SHIFT 28
-#define fts5YY_MIN_SHIFTREDUCE 45
-#define fts5YY_MAX_SHIFTREDUCE 70
-#define fts5YY_MIN_REDUCE 71
-#define fts5YY_MAX_REDUCE 96
-#define fts5YY_ERROR_ACTION 97
-#define fts5YY_ACCEPT_ACTION 98
-#define fts5YY_NO_ACTION 99
+#define sqlite3Fts5ParserARG_PARAM ,pParse
+#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse;
+#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse;
+#define sqlite3Fts5ParserCTX_SDECL
+#define sqlite3Fts5ParserCTX_PDECL
+#define sqlite3Fts5ParserCTX_PARAM
+#define sqlite3Fts5ParserCTX_FETCH
+#define sqlite3Fts5ParserCTX_STORE
+#define fts5YYNSTATE 35
+#define fts5YYNRULE 28
+#define fts5YYNRULE_WITH_ACTION 28
+#define fts5YYNFTS5TOKEN 16
+#define fts5YY_MAX_SHIFT 34
+#define fts5YY_MIN_SHIFTREDUCE 52
+#define fts5YY_MAX_SHIFTREDUCE 79
+#define fts5YY_ERROR_ACTION 80
+#define fts5YY_ACCEPT_ACTION 81
+#define fts5YY_NO_ACTION 82
+#define fts5YY_MIN_REDUCE 83
+#define fts5YY_MAX_REDUCE 110
/************* End control #defines *******************************************/
+#define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])))
/* Define the fts5yytestcase() macro to be a no-op if is not already defined
** otherwise.
@@ -180136,7 +209519,7 @@ typedef union {
/* Next are the tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
-** action integer.
+** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
@@ -180147,9 +209530,6 @@ typedef union {
** N between fts5YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
** and fts5YY_MAX_SHIFTREDUCE reduce by rule N-fts5YY_MIN_SHIFTREDUCE.
**
-** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE
-** and fts5YY_MAX_REDUCE
-**
** N == fts5YY_ERROR_ACTION A syntax error has occurred.
**
** N == fts5YY_ACCEPT_ACTION The parser accepts its input.
@@ -180157,25 +209537,22 @@ typedef union {
** N == fts5YY_NO_ACTION No such action. Denotes unused
** slots in the fts5yy_action[] table.
**
+** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE
+** and fts5YY_MAX_REDUCE
+**
** The action table is constructed as a single large table named fts5yy_action[].
** Given state S and lookahead X, the action is computed as either:
**
** (A) N = fts5yy_action[ fts5yy_shift_ofst[S] + X ]
** (B) N = fts5yy_default[S]
**
-** The (A) formula is preferred. The B formula is used instead if:
-** (1) The fts5yy_shift_ofst[S]+X value is out of range, or
-** (2) fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X, or
-** (3) fts5yy_shift_ofst[S] equal fts5YY_SHIFT_USE_DFLT.
-** (Implementation note: fts5YY_SHIFT_USE_DFLT is chosen so that
-** fts5YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
-** Hence only tests (1) and (2) need to be evaluated.)
+** The (A) formula is preferred. The B formula is used instead if
+** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X.
**
** The formulas above are for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of
-** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of
-** fts5YY_SHIFT_USE_DFLT.
+** the fts5yy_shift_ofst[] array.
**
** The following are the tables generated in this section:
**
@@ -180189,56 +209566,62 @@ typedef union {
** fts5yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define fts5YY_ACTTAB_COUNT (85)
+#define fts5YY_ACTTAB_COUNT (105)
static const fts5YYACTIONTYPE fts5yy_action[] = {
- /* 0 */ 98, 16, 51, 5, 53, 27, 83, 7, 26, 15,
- /* 10 */ 51, 5, 53, 27, 13, 69, 26, 48, 51, 5,
- /* 20 */ 53, 27, 19, 11, 26, 9, 20, 51, 5, 53,
- /* 30 */ 27, 13, 22, 26, 28, 51, 5, 53, 27, 68,
- /* 40 */ 1, 26, 19, 11, 17, 9, 52, 10, 53, 27,
- /* 50 */ 23, 24, 26, 54, 3, 4, 2, 26, 6, 21,
- /* 60 */ 49, 71, 3, 4, 2, 7, 56, 59, 55, 59,
- /* 70 */ 4, 2, 12, 69, 58, 60, 18, 67, 62, 69,
- /* 80 */ 25, 66, 8, 14, 2,
+ /* 0 */ 81, 20, 96, 6, 28, 99, 98, 26, 26, 18,
+ /* 10 */ 96, 6, 28, 17, 98, 56, 26, 19, 96, 6,
+ /* 20 */ 28, 14, 98, 14, 26, 31, 92, 96, 6, 28,
+ /* 30 */ 108, 98, 25, 26, 21, 96, 6, 28, 78, 98,
+ /* 40 */ 58, 26, 29, 96, 6, 28, 107, 98, 22, 26,
+ /* 50 */ 24, 16, 12, 11, 1, 13, 13, 24, 16, 23,
+ /* 60 */ 11, 33, 34, 13, 97, 8, 27, 32, 98, 7,
+ /* 70 */ 26, 3, 4, 5, 3, 4, 5, 3, 83, 4,
+ /* 80 */ 5, 3, 63, 5, 3, 62, 12, 2, 86, 13,
+ /* 90 */ 9, 30, 10, 10, 54, 57, 75, 78, 78, 53,
+ /* 100 */ 57, 15, 82, 82, 71,
};
static const fts5YYCODETYPE fts5yy_lookahead[] = {
- /* 0 */ 16, 17, 18, 19, 20, 21, 5, 6, 24, 17,
- /* 10 */ 18, 19, 20, 21, 11, 14, 24, 17, 18, 19,
- /* 20 */ 20, 21, 8, 9, 24, 11, 17, 18, 19, 20,
- /* 30 */ 21, 11, 12, 24, 17, 18, 19, 20, 21, 26,
- /* 40 */ 6, 24, 8, 9, 22, 11, 18, 11, 20, 21,
- /* 50 */ 24, 25, 24, 20, 1, 2, 3, 24, 23, 24,
- /* 60 */ 7, 0, 1, 2, 3, 6, 10, 11, 10, 11,
- /* 70 */ 2, 3, 9, 14, 11, 11, 22, 26, 7, 14,
- /* 80 */ 13, 11, 5, 11, 3,
+ /* 0 */ 16, 17, 18, 19, 20, 22, 22, 24, 24, 17,
+ /* 10 */ 18, 19, 20, 7, 22, 9, 24, 17, 18, 19,
+ /* 20 */ 20, 9, 22, 9, 24, 13, 17, 18, 19, 20,
+ /* 30 */ 26, 22, 24, 24, 17, 18, 19, 20, 15, 22,
+ /* 40 */ 9, 24, 17, 18, 19, 20, 26, 22, 21, 24,
+ /* 50 */ 6, 7, 9, 9, 10, 12, 12, 6, 7, 21,
+ /* 60 */ 9, 24, 25, 12, 18, 5, 20, 14, 22, 5,
+ /* 70 */ 24, 3, 1, 2, 3, 1, 2, 3, 0, 1,
+ /* 80 */ 2, 3, 11, 2, 3, 11, 9, 10, 5, 12,
+ /* 90 */ 23, 24, 10, 10, 8, 9, 9, 15, 15, 8,
+ /* 100 */ 9, 9, 27, 27, 11, 27, 27, 27, 27, 27,
+ /* 110 */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ /* 120 */ 27,
};
-#define fts5YY_SHIFT_USE_DFLT (85)
-#define fts5YY_SHIFT_COUNT (28)
+#define fts5YY_SHIFT_COUNT (34)
#define fts5YY_SHIFT_MIN (0)
-#define fts5YY_SHIFT_MAX (81)
+#define fts5YY_SHIFT_MAX (93)
static const unsigned char fts5yy_shift_ofst[] = {
- /* 0 */ 34, 34, 34, 34, 34, 14, 20, 3, 36, 1,
- /* 10 */ 59, 64, 64, 65, 65, 53, 61, 56, 58, 63,
- /* 20 */ 68, 67, 70, 67, 71, 72, 67, 77, 81,
+ /* 0 */ 44, 44, 44, 44, 44, 44, 51, 77, 43, 12,
+ /* 10 */ 14, 83, 82, 14, 23, 23, 31, 31, 71, 74,
+ /* 20 */ 78, 81, 86, 91, 6, 53, 53, 60, 64, 68,
+ /* 30 */ 53, 87, 92, 53, 93,
};
-#define fts5YY_REDUCE_USE_DFLT (-17)
-#define fts5YY_REDUCE_COUNT (14)
-#define fts5YY_REDUCE_MIN (-16)
-#define fts5YY_REDUCE_MAX (54)
+#define fts5YY_REDUCE_COUNT (17)
+#define fts5YY_REDUCE_MIN (-17)
+#define fts5YY_REDUCE_MAX (67)
static const signed char fts5yy_reduce_ofst[] = {
- /* 0 */ -16, -8, 0, 9, 17, 28, 26, 35, 33, 13,
- /* 10 */ 13, 22, 54, 13, 51,
+ /* 0 */ -16, -8, 0, 9, 17, 25, 46, -17, -17, 37,
+ /* 10 */ 67, 4, 4, 8, 4, 20, 27, 38,
};
static const fts5YYACTIONTYPE fts5yy_default[] = {
- /* 0 */ 97, 97, 97, 97, 97, 76, 91, 97, 97, 96,
- /* 10 */ 96, 97, 97, 96, 96, 97, 97, 97, 97, 97,
- /* 20 */ 73, 89, 97, 90, 97, 97, 87, 97, 72,
+ /* 0 */ 80, 80, 80, 80, 80, 80, 95, 80, 80, 105,
+ /* 10 */ 80, 110, 110, 80, 110, 110, 80, 80, 80, 80,
+ /* 20 */ 80, 91, 80, 80, 80, 101, 100, 80, 80, 90,
+ /* 30 */ 103, 80, 80, 104, 80,
};
/********** End of lemon-generated parsing tables *****************************/
-/* The next table maps tokens (terminal symbols) into fallback tokens.
+/* The next table maps tokens (terminal symbols) into fallback tokens.
** If a construct like the following:
-**
+**
** %fallback ID X Y Z.
**
** appears in the grammar, then ID becomes a fallback token for X, Y,
@@ -180291,12 +209674,14 @@ struct fts5yyParser {
int fts5yyerrcnt; /* Shifts left before out of the error */
#endif
sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */
+ sqlite3Fts5ParserCTX_SDECL /* A place to hold %extra_context */
#if fts5YYSTACKDEPTH<=0
int fts5yystksz; /* Current side of the stack */
fts5yyStackEntry *fts5yystack; /* The parser's stack */
fts5yyStackEntry fts5yystk0; /* First stack entry */
#else
fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */
+ fts5yyStackEntry *fts5yystackEnd; /* Last entry in the stack */
#endif
};
typedef struct fts5yyParser fts5yyParser;
@@ -180308,10 +209693,10 @@ static char *fts5yyTracePrompt = 0;
#endif /* NDEBUG */
#ifndef NDEBUG
-/*
+/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
+** by making either argument NULL
**
** Inputs:
** <ul>
@@ -180333,50 +209718,72 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
}
#endif /* NDEBUG */
-#ifndef NDEBUG
+#if defined(fts5YYCOVERAGE) || !defined(NDEBUG)
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
-static const char *const fts5yyTokenName[] = {
- "$", "OR", "AND", "NOT",
- "TERM", "COLON", "LP", "RP",
- "MINUS", "LCP", "RCP", "STRING",
- "COMMA", "PLUS", "STAR", "error",
- "input", "expr", "cnearset", "exprlist",
- "nearset", "colset", "colsetlist", "nearphrases",
- "phrase", "neardist_opt", "star_opt",
+static const char *const fts5yyTokenName[] = {
+ /* 0 */ "$",
+ /* 1 */ "OR",
+ /* 2 */ "AND",
+ /* 3 */ "NOT",
+ /* 4 */ "TERM",
+ /* 5 */ "COLON",
+ /* 6 */ "MINUS",
+ /* 7 */ "LCP",
+ /* 8 */ "RCP",
+ /* 9 */ "STRING",
+ /* 10 */ "LP",
+ /* 11 */ "RP",
+ /* 12 */ "CARET",
+ /* 13 */ "COMMA",
+ /* 14 */ "PLUS",
+ /* 15 */ "STAR",
+ /* 16 */ "input",
+ /* 17 */ "expr",
+ /* 18 */ "cnearset",
+ /* 19 */ "exprlist",
+ /* 20 */ "colset",
+ /* 21 */ "colsetlist",
+ /* 22 */ "nearset",
+ /* 23 */ "nearphrases",
+ /* 24 */ "phrase",
+ /* 25 */ "neardist_opt",
+ /* 26 */ "star_opt",
};
-#endif /* NDEBUG */
+#endif /* defined(fts5YYCOVERAGE) || !defined(NDEBUG) */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const fts5yyRuleName[] = {
/* 0 */ "input ::= expr",
- /* 1 */ "expr ::= expr AND expr",
- /* 2 */ "expr ::= expr OR expr",
- /* 3 */ "expr ::= expr NOT expr",
- /* 4 */ "expr ::= LP expr RP",
- /* 5 */ "expr ::= exprlist",
- /* 6 */ "exprlist ::= cnearset",
- /* 7 */ "exprlist ::= exprlist cnearset",
- /* 8 */ "cnearset ::= nearset",
- /* 9 */ "cnearset ::= colset COLON nearset",
- /* 10 */ "colset ::= MINUS LCP colsetlist RCP",
- /* 11 */ "colset ::= LCP colsetlist RCP",
- /* 12 */ "colset ::= STRING",
- /* 13 */ "colset ::= MINUS STRING",
- /* 14 */ "colsetlist ::= colsetlist STRING",
- /* 15 */ "colsetlist ::= STRING",
- /* 16 */ "nearset ::= phrase",
- /* 17 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
- /* 18 */ "nearphrases ::= phrase",
- /* 19 */ "nearphrases ::= nearphrases phrase",
- /* 20 */ "neardist_opt ::=",
- /* 21 */ "neardist_opt ::= COMMA STRING",
- /* 22 */ "phrase ::= phrase PLUS STRING star_opt",
- /* 23 */ "phrase ::= STRING star_opt",
- /* 24 */ "star_opt ::= STAR",
- /* 25 */ "star_opt ::=",
+ /* 1 */ "colset ::= MINUS LCP colsetlist RCP",
+ /* 2 */ "colset ::= LCP colsetlist RCP",
+ /* 3 */ "colset ::= STRING",
+ /* 4 */ "colset ::= MINUS STRING",
+ /* 5 */ "colsetlist ::= colsetlist STRING",
+ /* 6 */ "colsetlist ::= STRING",
+ /* 7 */ "expr ::= expr AND expr",
+ /* 8 */ "expr ::= expr OR expr",
+ /* 9 */ "expr ::= expr NOT expr",
+ /* 10 */ "expr ::= colset COLON LP expr RP",
+ /* 11 */ "expr ::= LP expr RP",
+ /* 12 */ "expr ::= exprlist",
+ /* 13 */ "exprlist ::= cnearset",
+ /* 14 */ "exprlist ::= exprlist cnearset",
+ /* 15 */ "cnearset ::= nearset",
+ /* 16 */ "cnearset ::= colset COLON nearset",
+ /* 17 */ "nearset ::= phrase",
+ /* 18 */ "nearset ::= CARET phrase",
+ /* 19 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
+ /* 20 */ "nearphrases ::= phrase",
+ /* 21 */ "nearphrases ::= nearphrases phrase",
+ /* 22 */ "neardist_opt ::=",
+ /* 23 */ "neardist_opt ::= COMMA STRING",
+ /* 24 */ "phrase ::= phrase PLUS STRING star_opt",
+ /* 25 */ "phrase ::= STRING star_opt",
+ /* 26 */ "star_opt ::= STAR",
+ /* 27 */ "star_opt ::=",
};
#endif /* NDEBUG */
@@ -180410,7 +209817,7 @@ static int fts5yyGrowStack(fts5yyParser *p){
#endif
p->fts5yystksz = newSize;
}
- return pNew==0;
+ return pNew==0;
}
#endif
@@ -180423,7 +209830,36 @@ static int fts5yyGrowStack(fts5yyParser *p){
# define fts5YYMALLOCARGTYPE size_t
#endif
-/*
+/* Initialize a new parser that has already been allocated.
+*/
+static void sqlite3Fts5ParserInit(void *fts5yypRawParser sqlite3Fts5ParserCTX_PDECL){
+ fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yypRawParser;
+ sqlite3Fts5ParserCTX_STORE
+#ifdef fts5YYTRACKMAXSTACKDEPTH
+ fts5yypParser->fts5yyhwm = 0;
+#endif
+#if fts5YYSTACKDEPTH<=0
+ fts5yypParser->fts5yytos = NULL;
+ fts5yypParser->fts5yystack = NULL;
+ fts5yypParser->fts5yystksz = 0;
+ if( fts5yyGrowStack(fts5yypParser) ){
+ fts5yypParser->fts5yystack = &fts5yypParser->fts5yystk0;
+ fts5yypParser->fts5yystksz = 1;
+ }
+#endif
+#ifndef fts5YYNOERRORRECOVERY
+ fts5yypParser->fts5yyerrcnt = -1;
+#endif
+ fts5yypParser->fts5yytos = fts5yypParser->fts5yystack;
+ fts5yypParser->fts5yystack[0].stateno = 0;
+ fts5yypParser->fts5yystack[0].major = 0;
+#if fts5YYSTACKDEPTH>0
+ fts5yypParser->fts5yystackEnd = &fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1];
+#endif
+}
+
+#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
+/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
@@ -180435,36 +209871,22 @@ static int fts5yyGrowStack(fts5yyParser *p){
** A pointer to a parser. This pointer is used in subsequent calls
** to sqlite3Fts5Parser and sqlite3Fts5ParserFree.
*/
-static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){
- fts5yyParser *pParser;
- pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) );
- if( pParser ){
-#ifdef fts5YYTRACKMAXSTACKDEPTH
- pParser->fts5yyhwm = 0;
-#endif
-#if fts5YYSTACKDEPTH<=0
- pParser->fts5yytos = NULL;
- pParser->fts5yystack = NULL;
- pParser->fts5yystksz = 0;
- if( fts5yyGrowStack(pParser) ){
- pParser->fts5yystack = &pParser->fts5yystk0;
- pParser->fts5yystksz = 1;
- }
-#endif
-#ifndef fts5YYNOERRORRECOVERY
- pParser->fts5yyerrcnt = -1;
-#endif
- pParser->fts5yytos = pParser->fts5yystack;
- pParser->fts5yystack[0].stateno = 0;
- pParser->fts5yystack[0].major = 0;
+static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE) sqlite3Fts5ParserCTX_PDECL){
+ fts5yyParser *fts5yypParser;
+ fts5yypParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) );
+ if( fts5yypParser ){
+ sqlite3Fts5ParserCTX_STORE
+ sqlite3Fts5ParserInit(fts5yypParser sqlite3Fts5ParserCTX_PARAM);
}
- return pParser;
+ return (void*)fts5yypParser;
}
+#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */
+
/* The following function deletes the "minor type" or semantic value
** associated with a symbol. The symbol can be either a terminal
** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is
-** a pointer to the value to be deleted. The code used to do the
+** a pointer to the value to be deleted. The code used to do the
** deletions is derived from the %destructor and/or %token_destructor
** directives of the input grammar.
*/
@@ -180473,12 +209895,13 @@ static void fts5yy_destructor(
fts5YYCODETYPE fts5yymajor, /* Type code for object to destroy */
fts5YYMINORTYPE *fts5yypminor /* The object to be destroyed */
){
- sqlite3Fts5ParserARG_FETCH;
+ sqlite3Fts5ParserARG_FETCH
+ sqlite3Fts5ParserCTX_FETCH
switch( fts5yymajor ){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
+ ** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
@@ -180488,31 +209911,31 @@ static void fts5yy_destructor(
/********* Begin destructor definitions ***************************************/
case 16: /* input */
{
- (void)pParse;
+ (void)pParse;
}
break;
case 17: /* expr */
case 18: /* cnearset */
case 19: /* exprlist */
{
- sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24));
+ sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24));
}
break;
- case 20: /* nearset */
- case 23: /* nearphrases */
+ case 20: /* colset */
+ case 21: /* colsetlist */
{
- sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46));
+ sqlite3_free((fts5yypminor->fts5yy11));
}
break;
- case 21: /* colset */
- case 22: /* colsetlist */
+ case 22: /* nearset */
+ case 23: /* nearphrases */
{
- sqlite3_free((fts5yypminor->fts5yy11));
+ sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46));
}
break;
case 24: /* phrase */
{
- sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53));
+ sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53));
}
break;
/********* End destructor definitions *****************************************/
@@ -180541,7 +209964,19 @@ static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
fts5yy_destructor(pParser, fts5yytos->major, &fts5yytos->minor);
}
-/*
+/*
+** Clear all secondary memory allocations from the parser
+*/
+static void sqlite3Fts5ParserFinalize(void *p){
+ fts5yyParser *pParser = (fts5yyParser*)p;
+ while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
+#if fts5YYSTACKDEPTH<=0
+ if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
+#endif
+}
+
+#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
+/*
** Deallocate and destroy a parser. Destructors are called for
** all stack elements before shutting the parser down.
**
@@ -180553,16 +209988,13 @@ static void sqlite3Fts5ParserFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
){
- fts5yyParser *pParser = (fts5yyParser*)p;
#ifndef fts5YYPARSEFREENEVERNULL
- if( pParser==0 ) return;
-#endif
- while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
-#if fts5YYSTACKDEPTH<=0
- if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
+ if( p==0 ) return;
#endif
- (*freeProc)((void*)pParser);
+ sqlite3Fts5ParserFinalize(p);
+ (*freeProc)(p);
}
+#endif /* sqlite3Fts5Parser_ENGINEALWAYSONSTACK */
/*
** Return the peak depth of the stack for a parser.
@@ -180574,28 +210006,73 @@ static int sqlite3Fts5ParserStackPeak(void *p){
}
#endif
+/* This array of booleans keeps track of the parser statement
+** coverage. The element fts5yycoverage[X][Y] is set when the parser
+** is in state X and has a lookahead token Y. In a well-tested
+** systems, every element of this matrix should end up being set.
+*/
+#if defined(fts5YYCOVERAGE)
+static unsigned char fts5yycoverage[fts5YYNSTATE][fts5YYNFTS5TOKEN];
+#endif
+
+/*
+** Write into out a description of every state/lookahead combination that
+**
+** (1) has not been used by the parser, and
+** (2) is not a syntax error.
+**
+** Return the number of missed state/lookahead combinations.
+*/
+#if defined(fts5YYCOVERAGE)
+static int sqlite3Fts5ParserCoverage(FILE *out){
+ int stateno, iLookAhead, i;
+ int nMissed = 0;
+ for(stateno=0; stateno<fts5YYNSTATE; stateno++){
+ i = fts5yy_shift_ofst[stateno];
+ for(iLookAhead=0; iLookAhead<fts5YYNFTS5TOKEN; iLookAhead++){
+ if( fts5yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
+ if( fts5yycoverage[stateno][iLookAhead]==0 ) nMissed++;
+ if( out ){
+ fprintf(out,"State %d lookahead %s %s\n", stateno,
+ fts5yyTokenName[iLookAhead],
+ fts5yycoverage[stateno][iLookAhead] ? "ok" : "missed");
+ }
+ }
+ }
+ return nMissed;
+}
+#endif
+
/*
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
*/
-static unsigned int fts5yy_find_shift_action(
- fts5yyParser *pParser, /* The parser */
- fts5YYCODETYPE iLookAhead /* The look-ahead token */
+static fts5YYACTIONTYPE fts5yy_find_shift_action(
+ fts5YYCODETYPE iLookAhead, /* The look-ahead token */
+ fts5YYACTIONTYPE stateno /* Current state number */
){
int i;
- int stateno = pParser->fts5yytos->stateno;
-
- if( stateno>=fts5YY_MIN_REDUCE ) return stateno;
+
+ if( stateno>fts5YY_MAX_SHIFT ) return stateno;
assert( stateno <= fts5YY_SHIFT_COUNT );
+#if defined(fts5YYCOVERAGE)
+ fts5yycoverage[stateno][iLookAhead] = 1;
+#endif
do{
i = fts5yy_shift_ofst[stateno];
+ assert( i>=0 );
+ assert( i<=fts5YY_ACTTAB_COUNT );
+ assert( i+fts5YYNFTS5TOKEN<=(int)fts5YY_NLOOKAHEAD );
assert( iLookAhead!=fts5YYNOCODE );
+ assert( iLookAhead < fts5YYNFTS5TOKEN );
i += iLookAhead;
- if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
+ assert( i<(int)fts5YY_NLOOKAHEAD );
+ if( fts5yy_lookahead[i]!=iLookAhead ){
#ifdef fts5YYFALLBACK
fts5YYCODETYPE iFallback; /* Fallback token */
- if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
- && (iFallback = fts5yyFallback[iLookAhead])!=0 ){
+ assert( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0]) );
+ iFallback = fts5yyFallback[iLookAhead];
+ if( iFallback!=0 ){
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n",
@@ -180610,15 +210087,8 @@ static unsigned int fts5yy_find_shift_action(
#ifdef fts5YYWILDCARD
{
int j = i - iLookAhead + fts5YYWILDCARD;
- if(
-#if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0
- j>=0 &&
-#endif
-#if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
- j<fts5YY_ACTTAB_COUNT &&
-#endif
- fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0
- ){
+ assert( j<(int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])) );
+ if( fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0 ){
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
@@ -180632,6 +210102,7 @@ static unsigned int fts5yy_find_shift_action(
#endif /* fts5YYWILDCARD */
return fts5yy_default[stateno];
}else{
+ assert( i>=0 && i<sizeof(fts5yy_action)/sizeof(fts5yy_action[0]) );
return fts5yy_action[i];
}
}while(1);
@@ -180641,8 +210112,8 @@ static unsigned int fts5yy_find_shift_action(
** Find the appropriate action for a parser given the non-terminal
** look-ahead token iLookAhead.
*/
-static int fts5yy_find_reduce_action(
- int stateno, /* Current state number */
+static fts5YYACTIONTYPE fts5yy_find_reduce_action(
+ fts5YYACTIONTYPE stateno, /* Current state number */
fts5YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
@@ -180654,7 +210125,6 @@ static int fts5yy_find_reduce_action(
assert( stateno<=fts5YY_REDUCE_COUNT );
#endif
i = fts5yy_reduce_ofst[stateno];
- assert( i!=fts5YY_REDUCE_USE_DFLT );
assert( iLookAhead!=fts5YYNOCODE );
i += iLookAhead;
#ifdef fts5YYERRORSYMBOL
@@ -180672,8 +210142,8 @@ static int fts5yy_find_reduce_action(
** The following routine is called if the stack overflows.
*/
static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){
- sqlite3Fts5ParserARG_FETCH;
- fts5yypParser->fts5yytos--;
+ sqlite3Fts5ParserARG_FETCH
+ sqlite3Fts5ParserCTX_FETCH
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt);
@@ -180686,27 +210156,29 @@ static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){
sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
/******** End %stack_overflow code ********************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
+ sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument var */
+ sqlite3Fts5ParserCTX_STORE
}
/*
** Print tracing information for a SHIFT action
*/
#ifndef NDEBUG
-static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
+static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState, const char *zTag){
if( fts5yyTraceFILE ){
if( fts5yyNewState<fts5YYNSTATE ){
- fprintf(fts5yyTraceFILE,"%sShift '%s', go to state %d\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major],
+ fprintf(fts5yyTraceFILE,"%s%s '%s', go to state %d\n",
+ fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major],
fts5yyNewState);
}else{
- fprintf(fts5yyTraceFILE,"%sShift '%s'\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major]);
+ fprintf(fts5yyTraceFILE,"%s%s '%s', pending reduce %d\n",
+ fts5yyTracePrompt, zTag, fts5yyTokenName[fts5yypParser->fts5yytos->major],
+ fts5yyNewState - fts5YY_MIN_REDUCE);
}
}
}
#else
-# define fts5yyTraceShift(X,Y)
+# define fts5yyTraceShift(X,Y,Z)
#endif
/*
@@ -180714,8 +210186,8 @@ static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
*/
static void fts5yy_shift(
fts5yyParser *fts5yypParser, /* The parser to be shifted */
- int fts5yyNewState, /* The new state to shift in */
- int fts5yyMajor, /* The major token to shift in */
+ fts5YYACTIONTYPE fts5yyNewState, /* The new state to shift in */
+ fts5YYCODETYPE fts5yyMajor, /* The major token to shift in */
sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */
){
fts5yyStackEntry *fts5yytos;
@@ -180726,14 +210198,16 @@ static void fts5yy_shift(
assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
}
#endif
-#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH] ){
+#if fts5YYSTACKDEPTH>0
+ if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){
+ fts5yypParser->fts5yytos--;
fts5yyStackOverflow(fts5yypParser);
return;
}
#else
if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){
if( fts5yyGrowStack(fts5yypParser) ){
+ fts5yypParser->fts5yytos--;
fts5yyStackOverflow(fts5yypParser);
return;
}
@@ -180743,45 +210217,76 @@ static void fts5yy_shift(
fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
}
fts5yytos = fts5yypParser->fts5yytos;
- fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState;
- fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor;
+ fts5yytos->stateno = fts5yyNewState;
+ fts5yytos->major = fts5yyMajor;
fts5yytos->minor.fts5yy0 = fts5yyMinor;
- fts5yyTraceShift(fts5yypParser, fts5yyNewState);
-}
+ fts5yyTraceShift(fts5yypParser, fts5yyNewState, "Shift");
+}
+
+/* For rule J, fts5yyRuleInfoLhs[J] contains the symbol on the left-hand side
+** of that rule */
+static const fts5YYCODETYPE fts5yyRuleInfoLhs[] = {
+ 16, /* (0) input ::= expr */
+ 20, /* (1) colset ::= MINUS LCP colsetlist RCP */
+ 20, /* (2) colset ::= LCP colsetlist RCP */
+ 20, /* (3) colset ::= STRING */
+ 20, /* (4) colset ::= MINUS STRING */
+ 21, /* (5) colsetlist ::= colsetlist STRING */
+ 21, /* (6) colsetlist ::= STRING */
+ 17, /* (7) expr ::= expr AND expr */
+ 17, /* (8) expr ::= expr OR expr */
+ 17, /* (9) expr ::= expr NOT expr */
+ 17, /* (10) expr ::= colset COLON LP expr RP */
+ 17, /* (11) expr ::= LP expr RP */
+ 17, /* (12) expr ::= exprlist */
+ 19, /* (13) exprlist ::= cnearset */
+ 19, /* (14) exprlist ::= exprlist cnearset */
+ 18, /* (15) cnearset ::= nearset */
+ 18, /* (16) cnearset ::= colset COLON nearset */
+ 22, /* (17) nearset ::= phrase */
+ 22, /* (18) nearset ::= CARET phrase */
+ 22, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */
+ 23, /* (20) nearphrases ::= phrase */
+ 23, /* (21) nearphrases ::= nearphrases phrase */
+ 25, /* (22) neardist_opt ::= */
+ 25, /* (23) neardist_opt ::= COMMA STRING */
+ 24, /* (24) phrase ::= phrase PLUS STRING star_opt */
+ 24, /* (25) phrase ::= STRING star_opt */
+ 26, /* (26) star_opt ::= STAR */
+ 26, /* (27) star_opt ::= */
+};
-/* The following table contains information about every rule that
-** is used during the reduce.
-*/
-static const struct {
- fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
- unsigned char nrhs; /* Number of right-hand side symbols in the rule */
-} fts5yyRuleInfo[] = {
- { 16, 1 },
- { 17, 3 },
- { 17, 3 },
- { 17, 3 },
- { 17, 3 },
- { 17, 1 },
- { 19, 1 },
- { 19, 2 },
- { 18, 1 },
- { 18, 3 },
- { 21, 4 },
- { 21, 3 },
- { 21, 1 },
- { 21, 2 },
- { 22, 2 },
- { 22, 1 },
- { 20, 1 },
- { 20, 5 },
- { 23, 1 },
- { 23, 2 },
- { 25, 0 },
- { 25, 2 },
- { 24, 4 },
- { 24, 2 },
- { 26, 1 },
- { 26, 0 },
+/* For rule J, fts5yyRuleInfoNRhs[J] contains the negative of the number
+** of symbols on the right-hand side of that rule. */
+static const signed char fts5yyRuleInfoNRhs[] = {
+ -1, /* (0) input ::= expr */
+ -4, /* (1) colset ::= MINUS LCP colsetlist RCP */
+ -3, /* (2) colset ::= LCP colsetlist RCP */
+ -1, /* (3) colset ::= STRING */
+ -2, /* (4) colset ::= MINUS STRING */
+ -2, /* (5) colsetlist ::= colsetlist STRING */
+ -1, /* (6) colsetlist ::= STRING */
+ -3, /* (7) expr ::= expr AND expr */
+ -3, /* (8) expr ::= expr OR expr */
+ -3, /* (9) expr ::= expr NOT expr */
+ -5, /* (10) expr ::= colset COLON LP expr RP */
+ -3, /* (11) expr ::= LP expr RP */
+ -1, /* (12) expr ::= exprlist */
+ -1, /* (13) exprlist ::= cnearset */
+ -2, /* (14) exprlist ::= exprlist cnearset */
+ -1, /* (15) cnearset ::= nearset */
+ -3, /* (16) cnearset ::= colset COLON nearset */
+ -1, /* (17) nearset ::= phrase */
+ -2, /* (18) nearset ::= CARET phrase */
+ -5, /* (19) nearset ::= STRING LP nearphrases neardist_opt RP */
+ -1, /* (20) nearphrases ::= phrase */
+ -2, /* (21) nearphrases ::= nearphrases phrase */
+ 0, /* (22) neardist_opt ::= */
+ -2, /* (23) neardist_opt ::= COMMA STRING */
+ -4, /* (24) phrase ::= phrase PLUS STRING star_opt */
+ -2, /* (25) phrase ::= STRING star_opt */
+ -1, /* (26) star_opt ::= STAR */
+ 0, /* (27) star_opt ::= */
};
static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */
@@ -180789,45 +210294,71 @@ static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
+**
+** The fts5yyLookahead and fts5yyLookaheadToken parameters provide reduce actions
+** access to the lookahead token (if any). The fts5yyLookahead will be fts5YYNOCODE
+** if the lookahead token has already been consumed. As this procedure is
+** only called from one place, optimizing compilers will in-line it, which
+** means that the extra parameters have no performance impact.
*/
-static void fts5yy_reduce(
+static fts5YYACTIONTYPE fts5yy_reduce(
fts5yyParser *fts5yypParser, /* The parser */
- unsigned int fts5yyruleno /* Number of the rule by which to reduce */
+ unsigned int fts5yyruleno, /* Number of the rule by which to reduce */
+ int fts5yyLookahead, /* Lookahead token, or fts5YYNOCODE if none */
+ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyLookaheadToken /* Value of the lookahead token */
+ sqlite3Fts5ParserCTX_PDECL /* %extra_context */
){
int fts5yygoto; /* The next state */
- int fts5yyact; /* The next action */
+ fts5YYACTIONTYPE fts5yyact; /* The next action */
fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */
int fts5yysize; /* Amount to pop the stack */
- sqlite3Fts5ParserARG_FETCH;
+ sqlite3Fts5ParserARG_FETCH
+ (void)fts5yyLookahead;
+ (void)fts5yyLookaheadToken;
fts5yymsp = fts5yypParser->fts5yytos;
#ifndef NDEBUG
if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
- fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
- fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt,
- fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno);
+ fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
+ if( fts5yysize ){
+ fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
+ fts5yyTracePrompt,
+ fts5yyruleno, fts5yyRuleName[fts5yyruleno],
+ fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action",
+ fts5yymsp[fts5yysize].stateno);
+ }else{
+ fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s.\n",
+ fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno],
+ fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action");
+ }
}
#endif /* NDEBUG */
/* Check that the stack is large enough to grow by a single entry
** if the RHS of the rule is empty. This ensures that there is room
** enough on the stack to push the LHS value */
- if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){
+ if( fts5yyRuleInfoNRhs[fts5yyruleno]==0 ){
#ifdef fts5YYTRACKMAXSTACKDEPTH
if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
fts5yypParser->fts5yyhwm++;
assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
}
#endif
-#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1] ){
+#if fts5YYSTACKDEPTH>0
+ if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
fts5yyStackOverflow(fts5yypParser);
- return;
+ /* The call to fts5yyStackOverflow() above pops the stack until it is
+ ** empty, causing the main parser loop to exit. So the return value
+ ** is never used and does not matter. */
+ return 0;
}
#else
if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
if( fts5yyGrowStack(fts5yypParser) ){
fts5yyStackOverflow(fts5yypParser);
- return;
+ /* The call to fts5yyStackOverflow() above pops the stack until it is
+ ** empty, causing the main parser loop to exit. So the return value
+ ** is never used and does not matter. */
+ return 0;
}
fts5yymsp = fts5yypParser->fts5yytos;
}
@@ -180848,87 +210379,100 @@ static void fts5yy_reduce(
case 0: /* input ::= expr */
{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); }
break;
- case 1: /* expr ::= expr AND expr */
+ case 1: /* colset ::= MINUS LCP colsetlist RCP */
+{
+ fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
+}
+ break;
+ case 2: /* colset ::= LCP colsetlist RCP */
+{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; }
+ break;
+ case 3: /* colset ::= STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+}
+ fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ break;
+ case 4: /* colset ::= MINUS STRING */
+{
+ fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+ fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
+}
+ break;
+ case 5: /* colsetlist ::= colsetlist STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); }
+ fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ break;
+ case 6: /* colsetlist ::= STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+}
+ fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ break;
+ case 7: /* expr ::= expr AND expr */
{
fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
}
fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 2: /* expr ::= expr OR expr */
+ case 8: /* expr ::= expr OR expr */
{
fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
}
fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 3: /* expr ::= expr NOT expr */
+ case 9: /* expr ::= expr NOT expr */
{
fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
}
fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 4: /* expr ::= LP expr RP */
+ case 10: /* expr ::= colset COLON LP expr RP */
+{
+ sqlite3Fts5ParseSetColset(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[-4].minor.fts5yy11);
+ fts5yylhsminor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;
+}
+ fts5yymsp[-4].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 11: /* expr ::= LP expr RP */
{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;}
break;
- case 5: /* expr ::= exprlist */
- case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
+ case 12: /* expr ::= exprlist */
+ case 13: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==13);
{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;}
fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 7: /* exprlist ::= exprlist cnearset */
+ case 14: /* exprlist ::= exprlist cnearset */
{
fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24);
}
fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 8: /* cnearset ::= nearset */
-{
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
+ case 15: /* cnearset ::= nearset */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
}
fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 9: /* cnearset ::= colset COLON nearset */
-{
- sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy46, fts5yymsp[-2].minor.fts5yy11);
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
+ case 16: /* cnearset ::= colset COLON nearset */
+{
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
+ sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy24, fts5yymsp[-2].minor.fts5yy11);
}
fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
- case 10: /* colset ::= MINUS LCP colsetlist RCP */
-{
- fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
-}
- break;
- case 11: /* colset ::= LCP colsetlist RCP */
-{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; }
- break;
- case 12: /* colset ::= STRING */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
-}
- fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
+ case 17: /* nearset ::= phrase */
+{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); }
+ fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 13: /* colset ::= MINUS STRING */
+ case 18: /* nearset ::= CARET phrase */
{
- fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
- fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
-}
- break;
- case 14: /* colsetlist ::= colsetlist STRING */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); }
- fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 15: /* colsetlist ::= STRING */
-{
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+ sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy53);
+ fts5yymsp[-1].minor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
}
- fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
- break;
- case 16: /* nearset ::= phrase */
-{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); }
- fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 17: /* nearset ::= STRING LP nearphrases neardist_opt RP */
+ case 19: /* nearset ::= STRING LP nearphrases neardist_opt RP */
{
sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0);
@@ -180936,64 +210480,64 @@ static void fts5yy_reduce(
}
fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 18: /* nearphrases ::= phrase */
-{
- fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
+ case 20: /* nearphrases ::= phrase */
+{
+ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
}
fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 19: /* nearphrases ::= nearphrases phrase */
+ case 21: /* nearphrases ::= nearphrases phrase */
{
fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53);
}
fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 20: /* neardist_opt ::= */
+ case 22: /* neardist_opt ::= */
{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; }
break;
- case 21: /* neardist_opt ::= COMMA STRING */
+ case 23: /* neardist_opt ::= COMMA STRING */
{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
break;
- case 22: /* phrase ::= phrase PLUS STRING star_opt */
-{
+ case 24: /* phrase ::= phrase PLUS STRING star_opt */
+{
fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
}
fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
break;
- case 23: /* phrase ::= STRING star_opt */
-{
+ case 25: /* phrase ::= STRING star_opt */
+{
fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
}
fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
break;
- case 24: /* star_opt ::= STAR */
+ case 26: /* star_opt ::= STAR */
{ fts5yymsp[0].minor.fts5yy4 = 1; }
break;
- case 25: /* star_opt ::= */
+ case 27: /* star_opt ::= */
{ fts5yymsp[1].minor.fts5yy4 = 0; }
break;
default:
break;
/********** End reduce actions ************************************************/
};
- assert( fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
- fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs;
- fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
- fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
- if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
- if( fts5yyact>fts5YY_MAX_SHIFT ){
- fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
- }
- fts5yymsp -= fts5yysize-1;
- fts5yypParser->fts5yytos = fts5yymsp;
- fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
- fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
- fts5yyTraceShift(fts5yypParser, fts5yyact);
- }else{
- assert( fts5yyact == fts5YY_ACCEPT_ACTION );
- fts5yypParser->fts5yytos -= fts5yysize;
- fts5yy_accept(fts5yypParser);
- }
+ assert( fts5yyruleno<sizeof(fts5yyRuleInfoLhs)/sizeof(fts5yyRuleInfoLhs[0]) );
+ fts5yygoto = fts5yyRuleInfoLhs[fts5yyruleno];
+ fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
+ fts5yyact = fts5yy_find_reduce_action(fts5yymsp[fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
+
+ /* There are no SHIFTREDUCE actions on nonterminals because the table
+ ** generator has simplified them to pure REDUCE actions. */
+ assert( !(fts5yyact>fts5YY_MAX_SHIFT && fts5yyact<=fts5YY_MAX_SHIFTREDUCE) );
+
+ /* It is not possible for a REDUCE to be followed by an error */
+ assert( fts5yyact!=fts5YY_ERROR_ACTION );
+
+ fts5yymsp += fts5yysize+1;
+ fts5yypParser->fts5yytos = fts5yymsp;
+ fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
+ fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
+ fts5yyTraceShift(fts5yypParser, fts5yyact, "... then shift");
+ return fts5yyact;
}
/*
@@ -181003,7 +210547,8 @@ static void fts5yy_reduce(
static void fts5yy_parse_failed(
fts5yyParser *fts5yypParser /* The parser */
){
- sqlite3Fts5ParserARG_FETCH;
+ sqlite3Fts5ParserARG_FETCH
+ sqlite3Fts5ParserCTX_FETCH
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt);
@@ -181014,7 +210559,8 @@ static void fts5yy_parse_failed(
** parser fails */
/************ Begin %parse_failure code ***************************************/
/************ End %parse_failure code *****************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
+ sqlite3Fts5ParserCTX_STORE
}
#endif /* fts5YYNOERRORRECOVERY */
@@ -181026,7 +210572,8 @@ static void fts5yy_syntax_error(
int fts5yymajor, /* The major type of the error token */
sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */
){
- sqlite3Fts5ParserARG_FETCH;
+ sqlite3Fts5ParserARG_FETCH
+ sqlite3Fts5ParserCTX_FETCH
#define FTS5TOKEN fts5yyminor
/************ Begin %syntax_error code ****************************************/
@@ -181035,7 +210582,8 @@ static void fts5yy_syntax_error(
pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p
);
/************ End %syntax_error code ******************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
+ sqlite3Fts5ParserCTX_STORE
}
/*
@@ -181044,7 +210592,8 @@ static void fts5yy_syntax_error(
static void fts5yy_accept(
fts5yyParser *fts5yypParser /* The parser */
){
- sqlite3Fts5ParserARG_FETCH;
+ sqlite3Fts5ParserARG_FETCH
+ sqlite3Fts5ParserCTX_FETCH
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt);
@@ -181058,7 +210607,8 @@ static void fts5yy_accept(
** parser accepts */
/*********** Begin %parse_accept code *****************************************/
/*********** End %parse_accept code *******************************************/
- sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+ sqlite3Fts5ParserARG_STORE /* Suppress warning about unused %extra_argument variable */
+ sqlite3Fts5ParserCTX_STORE
}
/* The main parser program.
@@ -181087,38 +210637,51 @@ static void sqlite3Fts5Parser(
sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */
){
fts5YYMINORTYPE fts5yyminorunion;
- unsigned int fts5yyact; /* The parser action. */
+ fts5YYACTIONTYPE fts5yyact; /* The parser action. */
#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
int fts5yyendofinput; /* True if we are at the end of input */
#endif
#ifdef fts5YYERRORSYMBOL
int fts5yyerrorhit = 0; /* True if fts5yymajor has invoked an error */
#endif
- fts5yyParser *fts5yypParser; /* The parser */
+ fts5yyParser *fts5yypParser = (fts5yyParser*)fts5yyp; /* The parser */
+ sqlite3Fts5ParserCTX_FETCH
+ sqlite3Fts5ParserARG_STORE
- fts5yypParser = (fts5yyParser*)fts5yyp;
assert( fts5yypParser->fts5yytos!=0 );
#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
fts5yyendofinput = (fts5yymajor==0);
#endif
- sqlite3Fts5ParserARG_STORE;
+ fts5yyact = fts5yypParser->fts5yytos->stateno;
#ifndef NDEBUG
if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sInput '%s'\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
+ if( fts5yyact < fts5YY_MIN_REDUCE ){
+ fprintf(fts5yyTraceFILE,"%sInput '%s' in state %d\n",
+ fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],fts5yyact);
+ }else{
+ fprintf(fts5yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
+ fts5yyTracePrompt,fts5yyTokenName[fts5yymajor],fts5yyact-fts5YY_MIN_REDUCE);
+ }
}
#endif
do{
- fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor);
- if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
- fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor);
+ assert( fts5yyact==fts5yypParser->fts5yytos->stateno );
+ fts5yyact = fts5yy_find_shift_action((fts5YYCODETYPE)fts5yymajor,fts5yyact);
+ if( fts5yyact >= fts5YY_MIN_REDUCE ){
+ fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor,
+ fts5yyminor sqlite3Fts5ParserCTX_PARAM);
+ }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
+ fts5yy_shift(fts5yypParser,fts5yyact,(fts5YYCODETYPE)fts5yymajor,fts5yyminor);
#ifndef fts5YYNOERRORRECOVERY
fts5yypParser->fts5yyerrcnt--;
#endif
- fts5yymajor = fts5YYNOCODE;
- }else if( fts5yyact <= fts5YY_MAX_REDUCE ){
- fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE);
+ break;
+ }else if( fts5yyact==fts5YY_ACCEPT_ACTION ){
+ fts5yypParser->fts5yytos--;
+ fts5yy_accept(fts5yypParser);
+ return;
}else{
assert( fts5yyact == fts5YY_ERROR_ACTION );
fts5yyminorunion.fts5yy0 = fts5yyminor;
@@ -181133,7 +210696,7 @@ static void sqlite3Fts5Parser(
#ifdef fts5YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
+ ** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
@@ -181165,10 +210728,9 @@ static void sqlite3Fts5Parser(
fts5yymajor = fts5YYNOCODE;
}else{
while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack
- && fts5yymx != fts5YYERRORSYMBOL
&& (fts5yyact = fts5yy_find_reduce_action(
fts5yypParser->fts5yytos->stateno,
- fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE
+ fts5YYERRORSYMBOL)) > fts5YY_MAX_SHIFTREDUCE
){
fts5yy_pop_parser_stack(fts5yypParser);
}
@@ -181185,6 +210747,8 @@ static void sqlite3Fts5Parser(
}
fts5yypParser->fts5yyerrcnt = 3;
fts5yyerrorhit = 1;
+ if( fts5yymajor==fts5YYNOCODE ) break;
+ fts5yyact = fts5yypParser->fts5yytos->stateno;
#elif defined(fts5YYNOERRORRECOVERY)
/* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to
** do any kind of error recovery. Instead, simply invoke the syntax
@@ -181195,8 +210759,7 @@ static void sqlite3Fts5Parser(
*/
fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
- fts5yymajor = fts5YYNOCODE;
-
+ break;
#else /* fts5YYERRORSYMBOL is not defined */
/* This is what we do if the grammar does not define ERROR:
**
@@ -181218,10 +210781,10 @@ static void sqlite3Fts5Parser(
fts5yypParser->fts5yyerrcnt = -1;
#endif
}
- fts5yymajor = fts5YYNOCODE;
+ break;
#endif
}
- }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack );
+ }while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack );
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fts5yyStackEntry *i;
@@ -181238,6 +210801,20 @@ static void sqlite3Fts5Parser(
}
/*
+** Return the fallback token corresponding to canonical token iToken, or
+** 0 if iToken has no fallback.
+*/
+static int sqlite3Fts5ParserFallback(int iToken){
+#ifdef fts5YYFALLBACK
+ assert( iToken<(int)(sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])) );
+ return fts5yyFallback[iToken];
+#else
+ (void)iToken;
+ return 0;
+#endif
+}
+
+/*
** 2014 May 31
**
** The author disclaims copyright to this source code. In place of
@@ -181255,7 +210832,7 @@ static void sqlite3Fts5Parser(
#include <math.h> /* amalgamator: keep */
/*
-** Object used to iterate through all "coalesced phrase instances" in
+** Object used to iterate through all "coalesced phrase instances" in
** a single column of the current row. If the phrase instances in the
** column being considered do not overlap, this object simply iterates
** through them. Or, if they do overlap (share one or more tokens in
@@ -181318,7 +210895,7 @@ static int fts5CInstIterNext(CInstIter *pIter){
}
/*
-** Initialize the iterator object indicated by the final parameter to
+** Initialize the iterator object indicated by the final parameter to
** iterate through coalesced phrase instances in column iCol.
*/
static int fts5CInstIterInit(
@@ -181363,19 +210940,19 @@ struct HighlightContext {
/*
** Append text to the HighlightContext output string - p->zOut. Argument
-** z points to a buffer containing n bytes of text to append. If n is
+** z points to a buffer containing n bytes of text to append. If n is
** negative, everything up until the first '\0' is appended to the output.
**
-** If *pRc is set to any value other than SQLITE_OK when this function is
-** called, it is a no-op. If an error (i.e. an OOM condition) is encountered,
-** *pRc is set to an error code before returning.
+** If *pRc is set to any value other than SQLITE_OK when this function is
+** called, it is a no-op. If an error (i.e. an OOM condition) is encountered,
+** *pRc is set to an error code before returning.
*/
static void fts5HighlightAppend(
- int *pRc,
- HighlightContext *p,
+ int *pRc,
+ HighlightContext *p,
const char *z, int n
){
- if( *pRc==SQLITE_OK ){
+ if( *pRc==SQLITE_OK && z ){
if( n<0 ) n = (int)strlen(z);
p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
@@ -181507,7 +211084,7 @@ static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){
int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64;
int *aNew;
- aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int));
+ aNew = (int*)sqlite3_realloc64(p->aFirst, nNew*sizeof(int));
if( aNew==0 ) return SQLITE_NOMEM;
p->aFirst = aNew;
p->nFirstAlloc = nNew;
@@ -181574,11 +211151,12 @@ static int fts5SnippetScore(
int nInst;
int nScore = 0;
int iLast = 0;
+ sqlite3_int64 iEnd = (sqlite3_int64)iPos + nToken;
rc = pApi->xInstCount(pFts, &nInst);
for(i=0; i<nInst && rc==SQLITE_OK; i++){
rc = pApi->xInst(pFts, i, &ip, &ic, &iOff);
- if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){
+ if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<iEnd ){
nScore += (aSeen[ip] ? 1 : 1000);
aSeen[ip] = 1;
if( iFirst<0 ) iFirst = iOff;
@@ -181588,16 +211166,26 @@ static int fts5SnippetScore(
*pnScore = nScore;
if( piPos ){
- int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
+ sqlite3_int64 iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken;
if( iAdj<0 ) iAdj = 0;
- *piPos = iAdj;
+ *piPos = (int)iAdj;
}
return rc;
}
/*
+** Return the value in pVal interpreted as utf-8 text. Except, if pVal
+** contains a NULL value, return a pointer to a static string zero
+** bytes in length instead of a NULL pointer.
+*/
+static const char *fts5ValueToText(sqlite3_value *pVal){
+ const char *zRet = (const char*)sqlite3_value_text(pVal);
+ return zRet ? zRet : "";
+}
+
+/*
** Implementation of snippet() function.
*/
static void fts5SnippetFunction(
@@ -181632,9 +211220,9 @@ static void fts5SnippetFunction(
nCol = pApi->xColumnCount(pFts);
memset(&ctx, 0, sizeof(HighlightContext));
iCol = sqlite3_value_int(apVal[0]);
- ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
- ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
- zEllips = (const char*)sqlite3_value_text(apVal[3]);
+ ctx.zOpen = fts5ValueToText(apVal[1]);
+ ctx.zClose = fts5ValueToText(apVal[2]);
+ zEllips = fts5ValueToText(apVal[3]);
nToken = sqlite3_value_int(apVal[4]);
iBestCol = (iCol>=0 ? iCol : 0);
@@ -181657,7 +211245,7 @@ static void fts5SnippetFunction(
sFinder.nFirst = 0;
rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
if( rc!=SQLITE_OK ) break;
- rc = pApi->xTokenize(pFts,
+ rc = pApi->xTokenize(pFts,
sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
);
if( rc!=SQLITE_OK ) break;
@@ -181671,7 +211259,9 @@ static void fts5SnippetFunction(
int jj;
rc = pApi->xInst(pFts, ii, &ip, &ic, &io);
- if( ic!=i || rc!=SQLITE_OK ) continue;
+ if( ic!=i ) continue;
+ if( io>nDocsize ) rc = FTS5_CORRUPT;
+ if( rc!=SQLITE_OK ) continue;
memset(aSeen, 0, nPhrase);
rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
io, nToken, &nScore, &iAdj
@@ -181690,7 +211280,7 @@ static void fts5SnippetFunction(
if( sFinder.aFirst[jj]<io ){
memset(aSeen, 0, nPhrase);
- rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
+ rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
sFinder.aFirst[jj], nToken, &nScore, 0
);
@@ -181769,7 +211359,7 @@ struct Fts5Bm25Data {
** table matched by each individual phrase within the query.
*/
static int fts5CountCb(
- const Fts5ExtensionApi *pApi,
+ const Fts5ExtensionApi *pApi,
Fts5Context *pFts,
void *pUserData /* Pointer to sqlite3_int64 variable */
){
@@ -181780,12 +211370,12 @@ static int fts5CountCb(
}
/*
-** Set *ppData to point to the Fts5Bm25Data object for the current query.
+** Set *ppData to point to the Fts5Bm25Data object for the current query.
** If the object has not already been allocated, allocate and populate it
** now.
*/
static int fts5Bm25GetData(
- const Fts5ExtensionApi *pApi,
+ const Fts5ExtensionApi *pApi,
Fts5Context *pFts,
Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */
){
@@ -181797,17 +211387,17 @@ static int fts5Bm25GetData(
int nPhrase; /* Number of phrases in query */
sqlite3_int64 nRow = 0; /* Number of rows in table */
sqlite3_int64 nToken = 0; /* Number of tokens in table */
- int nByte; /* Bytes of space to allocate */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
int i;
/* Allocate the Fts5Bm25Data object */
nPhrase = pApi->xPhraseCount(pFts);
nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double);
- p = (Fts5Bm25Data*)sqlite3_malloc(nByte);
+ p = (Fts5Bm25Data*)sqlite3_malloc64(nByte);
if( p==0 ){
rc = SQLITE_NOMEM;
}else{
- memset(p, 0, nByte);
+ memset(p, 0, (size_t)nByte);
p->nPhrase = nPhrase;
p->aIDF = (double*)&p[1];
p->aFreq = &p->aIDF[nPhrase];
@@ -181815,6 +211405,7 @@ static int fts5Bm25GetData(
/* Calculate the average document length for this FTS5 table */
if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow);
+ assert( rc!=SQLITE_OK || nRow>0 );
if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken);
if( rc==SQLITE_OK ) p->avgdl = (double)nToken / (double)nRow;
@@ -181832,7 +211423,7 @@ static int fts5Bm25GetData(
** is the number that contain at least one instance of the phrase
** under consideration.
**
- ** The problem with this is that if (N < 2*nHit), the IDF is
+ ** The problem with this is that if (N < 2*nHit), the IDF is
** negative. Which is undesirable. So the mimimum allowable IDF is
** (1e-6) - roughly the same as a term that appears in just over
** half of set of 5,000,000 documents. */
@@ -181900,11 +211491,11 @@ static void fts5Bm25Function(
/* Determine the BM25 score for the current row. */
for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
score += pData->aIDF[i] * (
- ( aFreq[i] * (k1 + 1.0) ) /
+ ( aFreq[i] * (k1 + 1.0) ) /
( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
);
}
-
+
/* If no error has occurred, return the calculated score. Otherwise,
** throw an SQL exception. */
if( rc==SQLITE_OK ){
@@ -181940,8 +211531,6 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
return rc;
}
-
-
/*
** 2014 May 31
**
@@ -181961,17 +211550,17 @@ static int sqlite3Fts5AuxInit(fts5_api *pApi){
static int sqlite3Fts5BufferSize(int *pRc, Fts5Buffer *pBuf, u32 nByte){
if( (u32)pBuf->nSpace<nByte ){
- u32 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
+ u64 nNew = pBuf->nSpace ? pBuf->nSpace : 64;
u8 *pNew;
while( nNew<nByte ){
nNew = nNew * 2;
}
- pNew = sqlite3_realloc(pBuf->p, nNew);
+ pNew = sqlite3_realloc64(pBuf->p, nNew);
if( pNew==0 ){
*pRc = SQLITE_NOMEM;
return 1;
}else{
- pBuf->nSpace = nNew;
+ pBuf->nSpace = (int)nNew;
pBuf->p = pNew;
}
}
@@ -181996,34 +211585,36 @@ static void sqlite3Fts5Put32(u8 *aBuf, int iVal){
}
static int sqlite3Fts5Get32(const u8 *aBuf){
- return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
+ return (int)((((u32)aBuf[0])<<24) + (aBuf[1]<<16) + (aBuf[2]<<8) + aBuf[3]);
}
/*
-** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set
+** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set
** the error code in p. If an error has already occurred when this function
** is called, it is a no-op.
*/
static void sqlite3Fts5BufferAppendBlob(
int *pRc,
- Fts5Buffer *pBuf,
- u32 nData,
+ Fts5Buffer *pBuf,
+ u32 nData,
const u8 *pData
){
assert_nc( *pRc || nData>=0 );
- if( fts5BufferGrow(pRc, pBuf, nData) ) return;
- memcpy(&pBuf->p[pBuf->n], pData, nData);
- pBuf->n += nData;
+ if( nData ){
+ if( fts5BufferGrow(pRc, pBuf, nData) ) return;
+ memcpy(&pBuf->p[pBuf->n], pData, nData);
+ pBuf->n += nData;
+ }
}
/*
** Append the nul-terminated string zStr to the buffer pBuf. This function
-** ensures that the byte following the buffer data is set to 0x00, even
+** ensures that the byte following the buffer data is set to 0x00, even
** though this byte is not included in the pBuf->n count.
*/
static void sqlite3Fts5BufferAppendString(
int *pRc,
- Fts5Buffer *pBuf,
+ Fts5Buffer *pBuf,
const char *zStr
){
int nStr = (int)strlen(zStr);
@@ -182035,13 +211626,13 @@ static void sqlite3Fts5BufferAppendString(
** Argument zFmt is a printf() style format string. This function performs
** the printf() style processing, then appends the results to buffer pBuf.
**
-** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte
+** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte
** following the buffer data is set to 0x00, even though this byte is not
** included in the pBuf->n count.
-*/
+*/
static void sqlite3Fts5BufferAppendPrintf(
int *pRc,
- Fts5Buffer *pBuf,
+ Fts5Buffer *pBuf,
char *zFmt, ...
){
if( *pRc==SQLITE_OK ){
@@ -182068,12 +211659,12 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){
zRet = sqlite3_vmprintf(zFmt, ap);
va_end(ap);
if( zRet==0 ){
- *pRc = SQLITE_NOMEM;
+ *pRc = SQLITE_NOMEM;
}
}
return zRet;
}
-
+
/*
** Free any buffer allocated by pBuf. Zero the structure before returning.
@@ -182084,7 +211675,7 @@ static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){
}
/*
-** Zero the contents of the buffer object. But do not free the associated
+** Zero the contents of the buffer object. But do not free the associated
** memory allocation.
*/
static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){
@@ -182098,8 +211689,8 @@ static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){
*/
static void sqlite3Fts5BufferSet(
int *pRc,
- Fts5Buffer *pBuf,
- int nData,
+ Fts5Buffer *pBuf,
+ int nData,
const u8 *pData
){
pBuf->n = 0;
@@ -182115,17 +211706,26 @@ static int sqlite3Fts5PoslistNext64(
if( i>=n ){
/* EOF */
*piOff = -1;
- return 1;
+ return 1;
}else{
i64 iOff = *piOff;
int iVal;
fts5FastGetVarint32(a, i, iVal);
- if( iVal==1 ){
+ if( iVal<=1 ){
+ if( iVal==0 ){
+ *pi = i;
+ return 0;
+ }
fts5FastGetVarint32(a, i, iVal);
iOff = ((i64)iVal) << 32;
fts5FastGetVarint32(a, i, iVal);
+ if( iVal<2 ){
+ /* This is a corrupt record. So stop parsing it here. */
+ *piOff = -1;
+ return 1;
+ }
}
- *piOff = iOff + (iVal-2);
+ *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
*pi = i;
return 0;
}
@@ -182161,8 +211761,8 @@ static int sqlite3Fts5PoslistReaderInit(
** to iPos before returning.
*/
static void sqlite3Fts5PoslistSafeAppend(
- Fts5Buffer *pBuf,
- i64 *piPrev,
+ Fts5Buffer *pBuf,
+ i64 *piPrev,
i64 iPos
){
static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
@@ -182176,7 +211776,7 @@ static void sqlite3Fts5PoslistSafeAppend(
}
static int sqlite3Fts5PoslistWriterAppend(
- Fts5Buffer *pBuf,
+ Fts5Buffer *pBuf,
Fts5PoslistWriter *pWriter,
i64 iPos
){
@@ -182186,14 +211786,14 @@ static int sqlite3Fts5PoslistWriterAppend(
return SQLITE_OK;
}
-static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
+static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){
void *pRet = 0;
if( *pRc==SQLITE_OK ){
- pRet = sqlite3_malloc(nByte);
- if( pRet==0 && nByte>0 ){
- *pRc = SQLITE_NOMEM;
+ pRet = sqlite3_malloc64(nByte);
+ if( pRet==0 ){
+ if( nByte>0 ) *pRc = SQLITE_NOMEM;
}else{
- memset(pRet, 0, nByte);
+ memset(pRet, 0, (size_t)nByte);
}
}
return pRet;
@@ -182205,7 +211805,7 @@ static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
** the length of the string is determined using strlen().
**
** It is the responsibility of the caller to eventually free the returned
-** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
+** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
*/
static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
char *zRet = 0;
@@ -182272,9 +211872,9 @@ static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
}
static int sqlite3Fts5TermsetAdd(
- Fts5Termset *p,
+ Fts5Termset *p,
int iIdx,
- const char *pTerm, int nTerm,
+ const char *pTerm, int nTerm,
int *pbPresent
){
int rc = SQLITE_OK;
@@ -182295,9 +211895,9 @@ static int sqlite3Fts5TermsetAdd(
hash = hash % ArraySize(p->apHash);
for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
- if( pEntry->iIdx==iIdx
- && pEntry->nTerm==nTerm
- && memcmp(pEntry->pTerm, pTerm, nTerm)==0
+ if( pEntry->iIdx==iIdx
+ && pEntry->nTerm==nTerm
+ && memcmp(pEntry->pTerm, pTerm, nTerm)==0
){
*pbPresent = 1;
break;
@@ -182360,7 +211960,7 @@ static void sqlite3Fts5TermsetFree(Fts5Termset *p){
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
/* Maximum allowed page size */
-#define FTS5_MAX_PAGE_SIZE (128*1024)
+#define FTS5_MAX_PAGE_SIZE (64*1024)
static int fts5_iswhitespace(char x){
return (x==' ');
@@ -182371,8 +211971,8 @@ static int fts5_isopenquote(char x){
}
/*
-** Argument pIn points to a character that is part of a nul-terminated
-** string. Return a pointer to the first character following *pIn in
+** Argument pIn points to a character that is part of a nul-terminated
+** string. Return a pointer to the first character following *pIn in
** the string that is not a white-space character.
*/
static const char *fts5ConfigSkipWhitespace(const char *pIn){
@@ -182384,8 +211984,8 @@ static const char *fts5ConfigSkipWhitespace(const char *pIn){
}
/*
-** Argument pIn points to a character that is part of a nul-terminated
-** string. Return a pointer to the first character following *pIn in
+** Argument pIn points to a character that is part of a nul-terminated
+** string. Return a pointer to the first character following *pIn in
** the string that is not a "bareword" character.
*/
static const char *fts5ConfigSkipBareword(const char *pIn){
@@ -182416,9 +212016,9 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){
p++;
if( *p=='\'' ){
p++;
- while( (*p>='a' && *p<='f')
- || (*p>='A' && *p<='F')
- || (*p>='0' && *p<='9')
+ while( (*p>='a' && *p<='f')
+ || (*p>='A' && *p<='F')
+ || (*p>='0' && *p<='9')
){
p++;
}
@@ -182449,7 +212049,7 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){
if( *p=='+' || *p=='-' ) p++;
while( fts5_isdigit(*p) ) p++;
- /* At this point, if the literal was an integer, the parse is
+ /* At this point, if the literal was an integer, the parse is
** finished. Or, if it is a floating point value, it may continue
** with either a decimal point or an 'E' character. */
if( *p=='.' && fts5_isdigit(p[1]) ){
@@ -182473,8 +212073,8 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){
** nul-terminator byte.
**
** If the close-quote is found, the value returned is the byte offset of
-** the character immediately following it. Or, if the close-quote is not
-** found, -1 is returned. If -1 is returned, the buffer is left in an
+** the character immediately following it. Or, if the close-quote is not
+** found, -1 is returned. If -1 is returned, the buffer is left in an
** undefined state.
*/
static int fts5Dequote(char *z){
@@ -182485,9 +212085,9 @@ static int fts5Dequote(char *z){
/* Set stack variable q to the close-quote character */
assert( q=='[' || q=='\'' || q=='"' || q=='`' );
- if( q=='[' ) q = ']';
+ if( q=='[' ) q = ']';
- while( ALWAYS(z[iIn]) ){
+ while( z[iIn] ){
if( z[iIn]==q ){
if( z[iIn+1]!=q ){
/* Character iIn was the close quote. */
@@ -182495,7 +212095,7 @@ static int fts5Dequote(char *z){
break;
}else{
/* Character iIn and iIn+1 form an escaped quote character. Skip
- ** the input cursor past both and copy a single quote character
+ ** the input cursor past both and copy a single quote character
** to the output buffer. */
iIn += 2;
z[iOut++] = q;
@@ -182540,8 +212140,8 @@ struct Fts5Enum {
typedef struct Fts5Enum Fts5Enum;
static int fts5ConfigSetEnum(
- const Fts5Enum *aEnum,
- const char *zEnum,
+ const Fts5Enum *aEnum,
+ const char *zEnum,
int *peVal
){
int nEnum = (int)strlen(zEnum);
@@ -182632,7 +212232,7 @@ static int fts5ConfigParseSpecial(
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
const char *p = (const char*)zArg;
- int nArg = (int)strlen(zArg) + 1;
+ sqlite3_int64 nArg = strlen(zArg) + 1;
char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
char *pSpace = pDel;
@@ -182661,8 +212261,8 @@ static int fts5ConfigParseSpecial(
*pzErr = sqlite3_mprintf("parse error in tokenize directive");
rc = SQLITE_ERROR;
}else{
- rc = sqlite3Fts5GetTokenizer(pGlobal,
- (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi,
+ rc = sqlite3Fts5GetTokenizer(pGlobal,
+ (const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi,
pzErr
);
}
@@ -182728,7 +212328,7 @@ static int fts5ConfigParseSpecial(
}
/*
-** Allocate an instance of the default tokenizer ("simple") at
+** Allocate an instance of the default tokenizer ("simple") at
** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
** code if an error occurs.
*/
@@ -182762,8 +212362,8 @@ static const char *fts5ConfigGobbleWord(
){
const char *zRet = 0;
- int nIn = (int)strlen(zIn);
- char *zOut = sqlite3_malloc(nIn+1);
+ sqlite3_int64 nIn = strlen(zIn);
+ char *zOut = sqlite3_malloc64(nIn+1);
assert( *pRc==SQLITE_OK );
*pbQuoted = 0;
@@ -182772,7 +212372,7 @@ static const char *fts5ConfigGobbleWord(
if( zOut==0 ){
*pRc = SQLITE_NOMEM;
}else{
- memcpy(zOut, zIn, nIn+1);
+ memcpy(zOut, zIn, (size_t)(nIn+1));
if( fts5_isopenquote(zOut[0]) ){
int ii = fts5Dequote(zOut);
zRet = &zIn[ii];
@@ -182795,14 +212395,14 @@ static const char *fts5ConfigGobbleWord(
}
static int fts5ConfigParseColumn(
- Fts5Config *p,
- char *zCol,
- char *zArg,
+ Fts5Config *p,
+ char *zCol,
+ char *zArg,
char **pzErr
){
int rc = SQLITE_OK;
- if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
- || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
+ if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
+ || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
){
*pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
rc = SQLITE_ERROR;
@@ -182845,14 +212445,14 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){
/*
** Arguments nArg/azArg contain the string arguments passed to the xCreate
-** or xConnect method of the virtual table. This function attempts to
+** or xConnect method of the virtual table. This function attempts to
** allocate an instance of Fts5Config containing the results of parsing
** those arguments.
**
** If successful, SQLITE_OK is returned and *ppOut is set to point to the
-** new Fts5Config object. If an error occurs, an SQLite error code is
+** new Fts5Config object. If an error occurs, an SQLite error code is
** returned, *ppOut is set to NULL and an error message may be left in
-** *pzErr. It is the responsibility of the caller to eventually free any
+** *pzErr. It is the responsibility of the caller to eventually free any
** such error message using sqlite3_free().
*/
static int sqlite3Fts5ConfigParse(
@@ -182866,7 +212466,7 @@ static int sqlite3Fts5ConfigParse(
int rc = SQLITE_OK; /* Return code */
Fts5Config *pRet; /* New object to return */
int i;
- int nByte;
+ sqlite3_int64 nByte;
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
@@ -182939,8 +212539,8 @@ static int sqlite3Fts5ConfigParse(
/* If no zContent option was specified, fill in the default values. */
if( rc==SQLITE_OK && pRet->zContent==0 ){
const char *zTail = 0;
- assert( pRet->eContent==FTS5_CONTENT_NORMAL
- || pRet->eContent==FTS5_CONTENT_NONE
+ assert( pRet->eContent==FTS5_CONTENT_NORMAL
+ || pRet->eContent==FTS5_CONTENT_NONE
);
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
zTail = "content";
@@ -183011,7 +212611,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
const char *zSep = (i==0?"":", ");
zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]);
}
- zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)",
+ zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)",
zSql, pConfig->zName, FTS5_RANK_NAME
);
@@ -183020,7 +212620,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
rc = sqlite3_declare_vtab(pConfig->db, zSql);
sqlite3_free(zSql);
}
-
+
return rc;
}
@@ -183038,7 +212638,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
** int iPos // Position of token in input (first token is 0)
**
** If the callback returns a non-zero value the tokenization is abandoned
-** and no further callbacks are issued.
+** and no further callbacks are issued.
**
** This function returns SQLITE_OK if successful or an SQLite error code
** if an error occurs. If the tokenization was abandoned early because
@@ -183068,7 +212668,7 @@ static int sqlite3Fts5Tokenize(
*/
static const char *fts5ConfigSkipArgs(const char *pIn){
const char *p = pIn;
-
+
while( 1 ){
p = fts5ConfigSkipWhitespace(p);
p = fts5ConfigSkipLiteral(p);
@@ -183085,7 +212685,7 @@ static const char *fts5ConfigSkipArgs(const char *pIn){
}
/*
-** Parameter zIn contains a rank() function specification. The format of
+** Parameter zIn contains a rank() function specification. The format of
** this is:
**
** + Bareword (function name)
@@ -183127,7 +212727,7 @@ static int sqlite3Fts5ConfigParseRank(
p++;
}
if( rc==SQLITE_OK ){
- const char *pArgs;
+ const char *pArgs;
p = fts5ConfigSkipWhitespace(p);
pArgs = p;
if( *p!=')' ){
@@ -183153,8 +212753,8 @@ static int sqlite3Fts5ConfigParseRank(
}
static int sqlite3Fts5ConfigSetValue(
- Fts5Config *pConfig,
- const char *zKey,
+ Fts5Config *pConfig,
+ const char *zKey,
sqlite3_value *pVal,
int *pbBadkey
){
@@ -183165,7 +212765,7 @@ static int sqlite3Fts5ConfigSetValue(
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
pgsz = sqlite3_value_int(pVal);
}
- if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){
+ if( pgsz<32 || pgsz>FTS5_MAX_PAGE_SIZE ){
*pbBadkey = 1;
}else{
pConfig->pgsz = pgsz;
@@ -183218,6 +212818,7 @@ static int sqlite3Fts5ConfigSetValue(
*pbBadkey = 1;
}else{
if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
+ if( nCrisisMerge>=FTS5_MAX_SEGMENT ) nCrisisMerge = FTS5_MAX_SEGMENT-1;
pConfig->nCrisisMerge = nCrisisMerge;
}
}
@@ -183279,7 +212880,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
}
rc = sqlite3_finalize(p);
}
-
+
if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
rc = SQLITE_ERROR;
if( pConfig->pzErrmsg ){
@@ -183335,6 +212936,7 @@ static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
/* #include <stdio.h> */
static void sqlite3Fts5ParserTrace(FILE*, char*);
#endif
+static int sqlite3Fts5ParserFallback(int);
struct Fts5Expr {
@@ -183367,7 +212969,7 @@ struct Fts5ExprNode {
i64 iRowid; /* Current rowid */
Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */
- /* Child nodes. For a NOT node, this array always contains 2 entries. For
+ /* Child nodes. For a NOT node, this array always contains 2 entries. For
** AND or OR nodes, it contains 2 or more entries. */
int nChild; /* Number of child nodes */
Fts5ExprNode *apChild[1]; /* Array of child nodes */
@@ -183386,7 +212988,8 @@ struct Fts5ExprNode {
** or term prefix.
*/
struct Fts5ExprTerm {
- int bPrefix; /* True for a prefix term */
+ u8 bPrefix; /* True for a prefix term */
+ u8 bFirst; /* True if token must be first in column */
char *zTerm; /* nul-terminated term */
Fts5IndexIter *pIter; /* Iterator for this term */
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
@@ -183445,7 +213048,7 @@ static int fts5ExprIsspace(char t){
** Read the first token from the nul-terminated string at *pz.
*/
static int fts5ExprGetToken(
- Fts5Parse *pParse,
+ Fts5Parse *pParse,
const char **pz, /* IN/OUT: Pointer into buffer */
Fts5Token *pToken
){
@@ -183467,6 +213070,7 @@ static int fts5ExprGetToken(
case '+': tok = FTS5_PLUS; break;
case '*': tok = FTS5_STAR; break;
case '-': tok = FTS5_MINUS; break;
+ case '^': tok = FTS5_CARET; break;
case '\0': tok = FTS5_EOF; break;
case '"': {
@@ -183507,13 +213111,14 @@ static int fts5ExprGetToken(
return tok;
}
-static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
+static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc64((sqlite3_int64)t);}
static void fts5ParseFree(void *p){ sqlite3_free(p); }
static int sqlite3Fts5ExprNew(
Fts5Config *pConfig, /* FTS5 Configuration */
+ int iCol,
const char *zExpr, /* Expression text */
- Fts5Expr **ppNew,
+ Fts5Expr **ppNew,
char **pzErr
){
Fts5Parse sParse;
@@ -183536,6 +213141,18 @@ static int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ /* If the LHS of the MATCH expression was a user column, apply the
+ ** implicit column-filter. */
+ if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
+ int n = sizeof(Fts5Colset);
+ Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
+ if( pColset ){
+ pColset->nCol = 1;
+ pColset->aiCol[0] = iCol;
+ sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
+ }
+ }
+
assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
if( sParse.rc==SQLITE_OK ){
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
@@ -183592,6 +213209,42 @@ static void sqlite3Fts5ExprFree(Fts5Expr *p){
}
}
+static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
+ Fts5Parse sParse;
+ memset(&sParse, 0, sizeof(sParse));
+
+ if( *pp1 ){
+ Fts5Expr *p1 = *pp1;
+ int nPhrase = p1->nPhrase + p2->nPhrase;
+
+ p1->pRoot = sqlite3Fts5ParseNode(&sParse, FTS5_AND, p1->pRoot, p2->pRoot,0);
+ p2->pRoot = 0;
+
+ if( sParse.rc==SQLITE_OK ){
+ Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc(
+ p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*)
+ );
+ if( ap==0 ){
+ sParse.rc = SQLITE_NOMEM;
+ }else{
+ int i;
+ memmove(&ap[p2->nPhrase], ap, p1->nPhrase*sizeof(Fts5ExprPhrase*));
+ for(i=0; i<p2->nPhrase; i++){
+ ap[i] = p2->apExprPhrase[i];
+ }
+ p1->nPhrase = nPhrase;
+ p1->apExprPhrase = ap;
+ }
+ }
+ sqlite3_free(p2->apExprPhrase);
+ sqlite3_free(p2);
+ }else{
+ *pp1 = p2;
+ }
+
+ return sParse.rc;
+}
+
/*
** Argument pTerm must be a synonym iterator. Return the current rowid
** that it points to.
@@ -183621,7 +213274,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
** Argument pTerm must be a synonym iterator.
*/
static int fts5ExprSynonymList(
- Fts5ExprTerm *pTerm,
+ Fts5ExprTerm *pTerm,
i64 iRowid,
Fts5Buffer *pBuf, /* Use this buffer for space if required */
u8 **pa, int *pn
@@ -183639,8 +213292,8 @@ static int fts5ExprSynonymList(
if( sqlite3Fts5IterEof(pIter)==0 && pIter->iRowid==iRowid ){
if( pIter->nData==0 ) continue;
if( nIter==nAlloc ){
- int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
- Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
+ sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
+ Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
if( aNew==0 ){
rc = SQLITE_NOMEM;
goto synonym_poslist_out;
@@ -183694,13 +213347,13 @@ static int fts5ExprSynonymList(
/*
** All individual term iterators in pPhrase are guaranteed to be valid and
-** pointing to the same rowid when this function is called. This function
+** pointing to the same rowid when this function is called. This function
** checks if the current rowid really is a match, and if so populates
** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch
** is set to true if this is really a match, or false otherwise.
**
-** SQLITE_OK is returned if an error occurs, or an SQLite error code
-** otherwise. It is not considered an error code if the current rowid is
+** SQLITE_OK is returned if an error occurs, or an SQLite error code
+** otherwise. It is not considered an error code if the current rowid is
** not a match.
*/
static int fts5ExprPhraseIsMatch(
@@ -183713,14 +213366,15 @@ static int fts5ExprPhraseIsMatch(
Fts5PoslistReader *aIter = aStatic;
int i;
int rc = SQLITE_OK;
-
+ int bFirst = pPhrase->aTerm[0].bFirst;
+
fts5BufferZero(&pPhrase->poslist);
/* If the aStatic[] array is not large enough, allocate a large array
** using sqlite3_malloc(). This approach could be improved upon. */
if( pPhrase->nTerm>ArraySize(aStatic) ){
- int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
- aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
+ sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
+ aIter = (Fts5PoslistReader*)sqlite3_malloc64(nByte);
if( !aIter ) return SQLITE_NOMEM;
}
memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm);
@@ -183767,8 +213421,10 @@ static int fts5ExprPhraseIsMatch(
}while( bMatch==0 );
/* Append position iPos to the output */
- rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
- if( rc!=SQLITE_OK ) goto ismatch_out;
+ if( bFirst==0 || FTS5_POS2OFFSET(iPos)==0 ){
+ rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
+ if( rc!=SQLITE_OK ) goto ismatch_out;
+ }
for(i=0; i<pPhrase->nTerm; i++){
if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
@@ -183833,7 +213489,7 @@ struct Fts5NearTrimmer {
** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM)
** occurs within this function (*pRc) is set accordingly before returning.
** The return value is undefined in both these cases.
-**
+**
** If no error occurs and non-zero (a match) is returned, the position-list
** of each phrase object is edited to contain only those entries that
** meet the constraint before returning.
@@ -183852,7 +213508,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
/* If the aStatic[] array is not large enough, allocate a large array
** using sqlite3_malloc(). This approach could be improved upon. */
if( pNear->nPhrase>ArraySize(aStatic) ){
- int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
+ sqlite3_int64 nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
}else{
memset(aStatic, 0, sizeof(aStatic));
@@ -183865,7 +213521,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
/* Initialize a lookahead iterator for each phrase. After passing the
** buffer and buffer size to the lookaside-reader init function, zero
** the phrase poslist buffer. The new poslist for the phrase (containing
- ** the same entries as the original with some entries removed on account
+ ** the same entries as the original with some entries removed on account
** of the NEAR constraint) is written over the original even as it is
** being read. This is safe as the entries for the new poslist are a
** subset of the old, so it is not possible for data yet to be read to
@@ -184022,7 +213678,9 @@ static int fts5ExprNearTest(
** phrase is not a match, break out of the loop early. */
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
+ if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym
+ || pNear->pColset || pPhrase->aTerm[0].bFirst
+ ){
int bMatch = 0;
rc = fts5ExprPhraseIsMatch(pNode, pPhrase, &bMatch);
if( bMatch==0 ) break;
@@ -184045,48 +213703,61 @@ static int fts5ExprNearTest(
** Initialize all term iterators in the pNear object. If any term is found
** to match no documents at all, return immediately without initializing any
** further iterators.
+**
+** If an error occurs, return an SQLite error code. Otherwise, return
+** SQLITE_OK. It is not considered an error if some term matches zero
+** documents.
*/
static int fts5ExprNearInitAll(
Fts5Expr *pExpr,
Fts5ExprNode *pNode
){
Fts5ExprNearset *pNear = pNode->pNear;
- int i, j;
- int rc = SQLITE_OK;
- int bEof = 1;
+ int i;
assert( pNode->bNomatch==0 );
- for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
+ for(i=0; i<pNear->nPhrase; i++){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- for(j=0; j<pPhrase->nTerm; j++){
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
- Fts5ExprTerm *p;
+ if( pPhrase->nTerm==0 ){
+ pNode->bEof = 1;
+ return SQLITE_OK;
+ }else{
+ int j;
+ for(j=0; j<pPhrase->nTerm; j++){
+ Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
+ Fts5ExprTerm *p;
+ int bHit = 0;
+
+ for(p=pTerm; p; p=p->pSynonym){
+ int rc;
+ if( p->pIter ){
+ sqlite3Fts5IterClose(p->pIter);
+ p->pIter = 0;
+ }
+ rc = sqlite3Fts5IndexQuery(
+ pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
+ (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
+ (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
+ pNear->pColset,
+ &p->pIter
+ );
+ assert( (rc==SQLITE_OK)==(p->pIter!=0) );
+ if( rc!=SQLITE_OK ) return rc;
+ if( 0==sqlite3Fts5IterEof(p->pIter) ){
+ bHit = 1;
+ }
+ }
- for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
- if( p->pIter ){
- sqlite3Fts5IterClose(p->pIter);
- p->pIter = 0;
- }
- rc = sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
- (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
- (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
- pNear->pColset,
- &p->pIter
- );
- assert( rc==SQLITE_OK || p->pIter==0 );
- if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
- bEof = 0;
+ if( bHit==0 ){
+ pNode->bEof = 1;
+ return SQLITE_OK;
}
}
-
- if( bEof ) break;
}
- if( bEof ) break;
}
- pNode->bEof = bEof;
- return rc;
+ pNode->bEof = 0;
+ return SQLITE_OK;
}
/*
@@ -184155,7 +213826,7 @@ static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
*/
static int fts5NodeCompare(
Fts5Expr *pExpr,
- Fts5ExprNode *p1,
+ Fts5ExprNode *p1,
Fts5ExprNode *p2
){
if( p2->bEof ) return -1;
@@ -184170,7 +213841,7 @@ static int fts5NodeCompare(
** If an EOF is reached before this happens, *pbEof is set to true before
** returning.
**
-** SQLITE_OK is returned if an error occurs, or an SQLite error code
+** SQLITE_OK is returned if an error occurs, or an SQLite error code
** otherwise. It is not considered an error code if an iterator reaches
** EOF.
*/
@@ -184187,9 +213858,10 @@ static int fts5ExprNodeTest_STRING(
const int bDesc = pExpr->bDesc;
/* Check that this node should not be FTS5_TERM */
- assert( pNear->nPhrase>1
- || pNear->apPhrase[0]->nTerm>1
+ assert( pNear->nPhrase>1
+ || pNear->apPhrase[0]->nTerm>1
|| pNear->apPhrase[0]->aTerm[0].pSynonym
+ || pNear->apPhrase[0]->aTerm[0].bFirst
);
/* Initialize iLast, the "lastest" rowid any iterator points to. If the
@@ -184219,7 +213891,7 @@ static int fts5ExprNodeTest_STRING(
}
}else{
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- if( pIter->iRowid==iLast ) continue;
+ if( pIter->iRowid==iLast || pIter->bEof ) continue;
bMatch = 0;
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
return rc;
@@ -184247,7 +213919,7 @@ static int fts5ExprNodeNext_STRING(
Fts5Expr *pExpr, /* Expression pPhrase belongs to */
Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */
int bFromValid,
- i64 iFrom
+ i64 iFrom
){
Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
int rc = SQLITE_OK;
@@ -184265,8 +213937,8 @@ static int fts5ExprNodeNext_STRING(
for(p=pTerm; p; p=p->pSynonym){
if( sqlite3Fts5IterEof(p->pIter)==0 ){
i64 ii = p->pIter->iRowid;
- if( ii==iRowid
- || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc)
+ if( ii==iRowid
+ || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc)
){
if( bFromValid ){
rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
@@ -184312,9 +213984,9 @@ static int fts5ExprNodeTest_TERM(
Fts5Expr *pExpr, /* Expression that pNear is a part of */
Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */
){
- /* As this "NEAR" object is actually a single phrase that consists
+ /* As this "NEAR" object is actually a single phrase that consists
** of a single term only, grab pointers into the poslist managed by the
- ** fts5_index.c iterator object. This is much faster than synthesizing
+ ** fts5_index.c iterator object. This is much faster than synthesizing
** a new poslist the way we have to for more complicated phrase or NEAR
** expressions. */
Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0];
@@ -184337,7 +214009,7 @@ static int fts5ExprNodeTest_TERM(
** xNext() method for a node of type FTS5_TERM.
*/
static int fts5ExprNodeNext_TERM(
- Fts5Expr *pExpr,
+ Fts5Expr *pExpr,
Fts5ExprNode *pNode,
int bFromValid,
i64 iFrom
@@ -184380,7 +214052,7 @@ static void fts5ExprNodeTest_OR(
}
static int fts5ExprNodeNext_OR(
- Fts5Expr *pExpr,
+ Fts5Expr *pExpr,
Fts5ExprNode *pNode,
int bFromValid,
i64 iFrom
@@ -184392,11 +214064,14 @@ static int fts5ExprNodeNext_OR(
Fts5ExprNode *p1 = pNode->apChild[i];
assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
if( p1->bEof==0 ){
- if( (p1->iRowid==iLast)
+ if( (p1->iRowid==iLast)
|| (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
){
int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc!=SQLITE_OK ){
+ pNode->bNomatch = 0;
+ return rc;
+ }
}
}
}
@@ -184427,7 +214102,10 @@ static int fts5ExprNodeTest_AND(
if( cmp>0 ){
/* Advance pChild until it points to iLast or laster */
rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
- if( rc!=SQLITE_OK ) return rc;
+ if( rc!=SQLITE_OK ){
+ pAnd->bNomatch = 0;
+ return rc;
+ }
}
/* If the child node is now at EOF, so is the parent AND node. Otherwise,
@@ -184458,7 +214136,7 @@ static int fts5ExprNodeTest_AND(
}
static int fts5ExprNodeNext_AND(
- Fts5Expr *pExpr,
+ Fts5Expr *pExpr,
Fts5ExprNode *pNode,
int bFromValid,
i64 iFrom
@@ -184466,6 +214144,8 @@ static int fts5ExprNodeNext_AND(
int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
if( rc==SQLITE_OK ){
rc = fts5ExprNodeTest_AND(pExpr, pNode);
+ }else{
+ pNode->bNomatch = 0;
}
return rc;
}
@@ -184499,7 +214179,7 @@ static int fts5ExprNodeTest_NOT(
}
static int fts5ExprNodeNext_NOT(
- Fts5Expr *pExpr,
+ Fts5Expr *pExpr,
Fts5ExprNode *pNode,
int bFromValid,
i64 iFrom
@@ -184508,6 +214188,9 @@ static int fts5ExprNodeNext_NOT(
if( rc==SQLITE_OK ){
rc = fts5ExprNodeTest_NOT(pExpr, pNode);
}
+ if( rc!=SQLITE_OK ){
+ pNode->bNomatch = 0;
+ }
return rc;
}
@@ -184553,7 +214236,7 @@ static int fts5ExprNodeTest(
return rc;
}
-
+
/*
** Set node pNode, which is part of expression pExpr, to point to the first
** match. If there are no matches, set the Node.bEof flag to indicate EOF.
@@ -184607,8 +214290,8 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
/*
** Begin iterating through the set of documents in index pIdx matched by
-** the MATCH expression passed as the first argument. If the "bDesc"
-** parameter is passed a non-zero value, iteration is in descending rowid
+** the MATCH expression passed as the first argument. If the "bDesc"
+** parameter is passed a non-zero value, iteration is in descending rowid
** order. Or, if it is zero, in ascending order.
**
** If iterating in ascending rowid order (bDesc==0), the first document
@@ -184630,7 +214313,10 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD
/* If not at EOF but the current rowid occurs earlier than iFirst in
** the iteration order, move to document iFirst or later. */
- if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
+ if( rc==SQLITE_OK
+ && 0==pRoot->bEof
+ && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0
+ ){
rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
}
@@ -184643,7 +214329,7 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD
}
/*
-** Move to the next document
+** Move to the next document
**
** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
** is not considered an error if the query does not match any documents.
@@ -184701,6 +214387,16 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
}
/*
+** Set the "bFirst" flag on the first token of the phrase passed as the
+** only argument.
+*/
+static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase *pPhrase){
+ if( pPhrase && pPhrase->nTerm ){
+ pPhrase->aTerm[0].bFirst = 1;
+ }
+}
+
+/*
** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
** appended to it and the results returned.
@@ -184721,18 +214417,20 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
return pNear;
}
if( pNear==0 ){
- int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
- pRet = sqlite3_malloc(nByte);
+ sqlite3_int64 nByte;
+ nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
+ pRet = sqlite3_malloc64(nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
- memset(pRet, 0, nByte);
+ memset(pRet, 0, (size_t)nByte);
}
}else if( (pNear->nPhrase % SZALLOC)==0 ){
int nNew = pNear->nPhrase + SZALLOC;
- int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
+ sqlite3_int64 nByte;
- pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
+ nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
+ pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
}
@@ -184796,12 +214494,12 @@ static int fts5ParseTokenize(
if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
Fts5ExprTerm *pSyn;
- int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
- pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
+ sqlite3_int64 nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
+ pSyn = (Fts5ExprTerm*)sqlite3_malloc64(nByte);
if( pSyn==0 ){
rc = SQLITE_NOMEM;
}else{
- memset(pSyn, 0, nByte);
+ memset(pSyn, 0, (size_t)nByte);
pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
memcpy(pSyn->zTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
@@ -184813,7 +214511,7 @@ static int fts5ParseTokenize(
Fts5ExprPhrase *pNew;
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
- pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase,
+ pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
);
if( pNew==0 ){
@@ -184884,7 +214582,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
rc = fts5ParseStringFromToken(pToken, &z);
if( rc==SQLITE_OK ){
- int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0);
+ int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_PREFIX : 0);
int n;
sqlite3Fts5Dequote(z);
n = (int)strlen(z);
@@ -184899,9 +214597,9 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
if( pAppend==0 ){
if( (pParse->nPhrase % 8)==0 ){
- int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
+ sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
Fts5ExprPhrase **apNew;
- apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte);
+ apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
if( apNew==0 ){
pParse->rc = SQLITE_NOMEM;
fts5ExprPhraseFree(sCtx.pPhrase);
@@ -184917,7 +214615,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
** no token characters at all. (e.g ... MATCH '""'). */
sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
}else if( sCtx.pPhrase->nTerm ){
- sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
+ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
}
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
}
@@ -184930,8 +214628,8 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
** expression passed as the second argument.
*/
static int sqlite3Fts5ExprClonePhrase(
- Fts5Expr *pExpr,
- int iPhrase,
+ Fts5Expr *pExpr,
+ int iPhrase,
Fts5Expr **ppNew
){
int rc = SQLITE_OK; /* Return code */
@@ -184942,24 +214640,26 @@ static int sqlite3Fts5ExprClonePhrase(
pOrig = pExpr->apExprPhrase[iPhrase];
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
if( rc==SQLITE_OK ){
- pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
+ pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
}
if( rc==SQLITE_OK ){
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
+ pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNode));
}
if( rc==SQLITE_OK ){
- pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
+ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
}
if( rc==SQLITE_OK ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
- int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
- Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
- if( pColset ){
- memcpy(pColset, pColsetOrig, nByte);
+ sqlite3_int64 nByte;
+ Fts5Colset *pColset;
+ nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
+ pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
+ if( pColset ){
+ memcpy(pColset, pColsetOrig, (size_t)nByte);
}
pNew->pRoot->pNear->pColset = pColset;
}
@@ -184978,6 +214678,7 @@ static int sqlite3Fts5ExprClonePhrase(
}
if( rc==SQLITE_OK ){
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
}
}
}else{
@@ -184996,7 +214697,10 @@ static int sqlite3Fts5ExprClonePhrase(
pNew->pRoot->pNear->nPhrase = 1;
sCtx.pPhrase->pNode = pNew->pRoot;
- if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
+ if( pOrig->nTerm==1
+ && pOrig->aTerm[0].pSynonym==0
+ && pOrig->aTerm[0].bFirst==0
+ ){
pNew->pRoot->eType = FTS5_TERM;
pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
}else{
@@ -185028,7 +214732,7 @@ static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){
}
static void sqlite3Fts5ParseSetDistance(
- Fts5Parse *pParse,
+ Fts5Parse *pParse,
Fts5ExprNearset *pNear,
Fts5Token *p
){
@@ -185057,7 +214761,7 @@ static void sqlite3Fts5ParseSetDistance(
** The second argument passed to this function may be NULL, or it may be
** an existing Fts5Colset object. This function returns a pointer to
** a new colset object containing the contents of (p) with new value column
-** number iCol appended.
+** number iCol appended.
**
** If an OOM error occurs, store an error code in pParse and return NULL.
** The old colset object (if any) is not freed in this case.
@@ -185073,7 +214777,7 @@ static Fts5Colset *fts5ParseColset(
assert( pParse->rc==SQLITE_OK );
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
- pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
+ pNew = sqlite3_realloc64(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
if( pNew==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
@@ -185107,7 +214811,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p
Fts5Colset *pRet;
int nCol = pParse->pConfig->nCol;
- pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
+ pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
sizeof(Fts5Colset) + sizeof(int)*nCol
);
if( pRet ){
@@ -185158,33 +214862,119 @@ static Fts5Colset *sqlite3Fts5ParseColset(
return pRet;
}
+/*
+** If argument pOrig is NULL, or if (*pRc) is set to anything other than
+** SQLITE_OK when this function is called, NULL is returned.
+**
+** Otherwise, a copy of (*pOrig) is made into memory obtained from
+** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
+** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
+*/
+static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
+ Fts5Colset *pRet;
+ if( pOrig ){
+ sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
+ pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
+ if( pRet ){
+ memcpy(pRet, pOrig, (size_t)nByte);
+ }
+ }else{
+ pRet = 0;
+ }
+ return pRet;
+}
+
+/*
+** Remove from colset pColset any columns that are not also in colset pMerge.
+*/
+static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
+ int iIn = 0; /* Next input in pColset */
+ int iMerge = 0; /* Next input in pMerge */
+ int iOut = 0; /* Next output slot in pColset */
+
+ while( iIn<pColset->nCol && iMerge<pMerge->nCol ){
+ int iDiff = pColset->aiCol[iIn] - pMerge->aiCol[iMerge];
+ if( iDiff==0 ){
+ pColset->aiCol[iOut++] = pMerge->aiCol[iMerge];
+ iMerge++;
+ iIn++;
+ }else if( iDiff>0 ){
+ iMerge++;
+ }else{
+ iIn++;
+ }
+ }
+ pColset->nCol = iOut;
+}
+
+/*
+** Recursively apply colset pColset to expression node pNode and all of
+** its decendents. If (*ppFree) is not NULL, it contains a spare copy
+** of pColset. This function may use the spare copy and set (*ppFree) to
+** zero, or it may create copies of pColset using fts5CloneColset().
+*/
+static void fts5ParseSetColset(
+ Fts5Parse *pParse,
+ Fts5ExprNode *pNode,
+ Fts5Colset *pColset,
+ Fts5Colset **ppFree
+){
+ if( pParse->rc==SQLITE_OK ){
+ assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING
+ || pNode->eType==FTS5_AND || pNode->eType==FTS5_OR
+ || pNode->eType==FTS5_NOT || pNode->eType==FTS5_EOF
+ );
+ if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
+ Fts5ExprNearset *pNear = pNode->pNear;
+ if( pNear->pColset ){
+ fts5MergeColset(pNear->pColset, pColset);
+ if( pNear->pColset->nCol==0 ){
+ pNode->eType = FTS5_EOF;
+ pNode->xNext = 0;
+ }
+ }else if( *ppFree ){
+ pNear->pColset = pColset;
+ *ppFree = 0;
+ }else{
+ pNear->pColset = fts5CloneColset(&pParse->rc, pColset);
+ }
+ }else{
+ int i;
+ assert( pNode->eType!=FTS5_EOF || pNode->nChild==0 );
+ for(i=0; i<pNode->nChild; i++){
+ fts5ParseSetColset(pParse, pNode->apChild[i], pColset, ppFree);
+ }
+ }
+ }
+}
+
+/*
+** Apply colset pColset to expression node pExpr and all of its descendents.
+*/
static void sqlite3Fts5ParseSetColset(
- Fts5Parse *pParse,
- Fts5ExprNearset *pNear,
- Fts5Colset *pColset
+ Fts5Parse *pParse,
+ Fts5ExprNode *pExpr,
+ Fts5Colset *pColset
){
+ Fts5Colset *pFree = pColset;
if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
pParse->rc = SQLITE_ERROR;
pParse->zErr = sqlite3_mprintf(
"fts5: column queries are not supported (detail=none)"
);
- sqlite3_free(pColset);
- return;
- }
-
- if( pNear ){
- pNear->pColset = pColset;
}else{
- sqlite3_free(pColset);
+ fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
}
+ sqlite3_free(pFree);
}
static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
switch( pNode->eType ){
case FTS5_STRING: {
Fts5ExprNearset *pNear = pNode->pNear;
- if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
+ if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
&& pNear->apPhrase[0]->aTerm[0].pSynonym==0
+ && pNear->apPhrase[0]->aTerm[0].bFirst==0
){
pNode->eType = FTS5_TERM;
pNode->xNext = fts5ExprNodeNext_TERM;
@@ -185237,8 +215027,8 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
if( pParse->rc==SQLITE_OK ){
int nChild = 0; /* Number of children of returned node */
- int nByte; /* Bytes of space to allocate for this node */
-
+ sqlite3_int64 nByte; /* Bytes of space to allocate for this node */
+
assert( (eType!=FTS5_STRING && !pNear)
|| (eType==FTS5_STRING && !pLeft && !pRight)
);
@@ -185271,20 +215061,23 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
}
}
- if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL
- && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1)
- ){
- assert( pParse->rc==SQLITE_OK );
- pParse->rc = SQLITE_ERROR;
- assert( pParse->zErr==0 );
- pParse->zErr = sqlite3_mprintf(
- "fts5: %s queries are not supported (detail!=full)",
- pNear->nPhrase==1 ? "phrase": "NEAR"
- );
- sqlite3_free(pRet);
- pRet = 0;
+ if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
+ Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
+ if( pNear->nPhrase!=1
+ || pPhrase->nTerm>1
+ || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
+ ){
+ assert( pParse->rc==SQLITE_OK );
+ pParse->rc = SQLITE_ERROR;
+ assert( pParse->zErr==0 );
+ pParse->zErr = sqlite3_mprintf(
+ "fts5: %s queries are not supported (detail!=full)",
+ pNear->nPhrase==1 ? "phrase": "NEAR"
+ );
+ sqlite3_free(pRet);
+ pRet = 0;
+ }
}
-
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
@@ -185314,14 +215107,14 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
sqlite3Fts5ParseNodeFree(pRight);
}else{
- assert( pLeft->eType==FTS5_STRING
+ assert( pLeft->eType==FTS5_STRING
|| pLeft->eType==FTS5_TERM
|| pLeft->eType==FTS5_EOF
|| pLeft->eType==FTS5_AND
);
- assert( pRight->eType==FTS5_STRING
- || pRight->eType==FTS5_TERM
- || pRight->eType==FTS5_EOF
+ assert( pRight->eType==FTS5_STRING
+ || pRight->eType==FTS5_TERM
+ || pRight->eType==FTS5_EOF
);
if( pLeft->eType==FTS5_AND ){
@@ -185329,9 +215122,9 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
}else{
pPrev = pLeft;
}
- assert( pPrev->eType==FTS5_STRING
- || pPrev->eType==FTS5_TERM
- || pPrev->eType==FTS5_EOF
+ assert( pPrev->eType==FTS5_STRING
+ || pPrev->eType==FTS5_TERM
+ || pPrev->eType==FTS5_EOF
);
if( pRight->eType==FTS5_EOF ){
@@ -185366,7 +215159,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
}
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
- int nByte = 0;
+ sqlite3_int64 nByte = 0;
Fts5ExprTerm *p;
char *zQuoted;
@@ -185374,7 +215167,7 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
for(p=pTerm; p; p=p->pSynonym){
nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
}
- zQuoted = sqlite3_malloc(nByte);
+ zQuoted = sqlite3_malloc64(nByte);
if( zQuoted ){
int i = 0;
@@ -185413,20 +215206,20 @@ static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){
}
/*
-** Compose a tcl-readable representation of expression pExpr. Return a
-** pointer to a buffer containing that representation. It is the
-** responsibility of the caller to at some point free the buffer using
+** Compose a tcl-readable representation of expression pExpr. Return a
+** pointer to a buffer containing that representation. It is the
+** responsibility of the caller to at some point free the buffer using
** sqlite3_free().
*/
static char *fts5ExprPrintTcl(
- Fts5Config *pConfig,
+ Fts5Config *pConfig,
const char *zNearsetCmd,
Fts5ExprNode *pExpr
){
char *zRet = 0;
if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
Fts5ExprNearset *pNear = pExpr->pNear;
- int i;
+ int i;
int iTerm;
zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd);
@@ -185476,9 +215269,9 @@ static char *fts5ExprPrintTcl(
switch( pExpr->eType ){
case FTS5_AND: zOp = "AND"; break;
case FTS5_NOT: zOp = "NOT"; break;
- default:
+ default:
assert( pExpr->eType==FTS5_OR );
- zOp = "OR";
+ zOp = "OR";
break;
}
@@ -185504,7 +215297,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
}else
if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
Fts5ExprNearset *pNear = pExpr->pNear;
- int i;
+ int i;
int iTerm;
if( pNear->pColset ){
@@ -185549,9 +215342,9 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
switch( pExpr->eType ){
case FTS5_AND: zOp = " AND "; break;
case FTS5_NOT: zOp = " NOT "; break;
- default:
+ default:
assert( pExpr->eType==FTS5_OR );
- zOp = " OR ";
+ zOp = " OR ";
break;
}
@@ -185563,7 +215356,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
}else{
int e = pExpr->apChild[i]->eType;
int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
- zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
+ zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
(i==0 ? "" : zOp),
(b?"(":""), z, (b?")":"")
);
@@ -185614,7 +215407,7 @@ static void fts5ExprFunction(
}
nConfig = 3 + (nArg-iArg);
- azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig);
+ azConfig = (const char**)sqlite3_malloc64(sizeof(char*) * nConfig);
if( azConfig==0 ){
sqlite3_result_error_nomem(pCtx);
return;
@@ -185623,14 +215416,16 @@ static void fts5ExprFunction(
azConfig[1] = "main";
azConfig[2] = "tbl";
for(i=3; iArg<nArg; iArg++){
- azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);
+ const char *z = (const char*)sqlite3_value_text(apVal[iArg]);
+ azConfig[i++] = (z ? z : "");
}
zExpr = (const char*)sqlite3_value_text(apVal[0]);
+ if( zExpr==0 ) zExpr = "";
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
+ rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
}
if( rc==SQLITE_OK ){
char *zText;
@@ -185679,7 +215474,7 @@ static void fts5ExprFunctionTcl(
/*
** The implementation of an SQLite user-defined-function that accepts a
-** single integer as an argument. If the integer is an alpha-numeric
+** single integer as an argument. If the integer is an alpha-numeric
** unicode code point, 1 is returned. Otherwise 0.
*/
static void fts5ExprIsAlnum(
@@ -185688,14 +215483,19 @@ static void fts5ExprIsAlnum(
sqlite3_value **apVal /* Function arguments */
){
int iCode;
+ u8 aArr[32];
if( nArg!=1 ){
- sqlite3_result_error(pCtx,
+ sqlite3_result_error(pCtx,
"wrong number of arguments to function fts5_isalnum", -1
);
return;
}
+ memset(aArr, 0, sizeof(aArr));
+ sqlite3Fts5UnicodeCatParse("L*", aArr);
+ sqlite3Fts5UnicodeCatParse("N*", aArr);
+ sqlite3Fts5UnicodeCatParse("Co", aArr);
iCode = sqlite3_value_int(apVal[0]);
- sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode));
+ sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory((u32)iCode)]);
}
static void fts5ExprFold(
@@ -185704,7 +215504,7 @@ static void fts5ExprFold(
sqlite3_value **apVal /* Function arguments */
){
if( nArg!=1 && nArg!=2 ){
- sqlite3_result_error(pCtx,
+ sqlite3_result_error(pCtx,
"wrong number of arguments to function fts5_fold", -1
);
}else{
@@ -185739,10 +215539,12 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
}
- /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
+ /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and
+ ** sqlite3Fts5ParserFallback() are unused */
#ifndef NDEBUG
(void)sqlite3Fts5ParserTrace;
#endif
+ (void)sqlite3Fts5ParserFallback;
return rc;
}
@@ -185788,7 +215590,7 @@ struct Fts5PoslistPopulator {
static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
Fts5PoslistPopulator *pRet;
- pRet = sqlite3_malloc(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
+ pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
if( pRet ){
int i;
memset(pRet, 0, sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
@@ -185796,7 +215598,7 @@ static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int b
Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
assert( pExpr->apExprPhrase[i]->nTerm==1 );
- if( bLive &&
+ if( bLive &&
(pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
){
pRet[i].bMiss = 1;
@@ -185863,9 +215665,9 @@ static int fts5ExprPopulatePoslistsCb(
static int sqlite3Fts5ExprPopulatePoslists(
Fts5Config *pConfig,
- Fts5Expr *pExpr,
+ Fts5Expr *pExpr,
Fts5PoslistPopulator *aPopulator,
- int iCol,
+ int iCol,
const char *z, int n
){
int i;
@@ -185877,7 +215679,7 @@ static int sqlite3Fts5ExprPopulatePoslists(
for(i=0; i<pExpr->nPhrase; i++){
Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
Fts5Colset *pColset = pNode->pNear->pColset;
- if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
+ if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
|| aPopulator[i].bMiss
){
aPopulator[i].bOk = 0;
@@ -185886,7 +215688,7 @@ static int sqlite3Fts5ExprPopulatePoslists(
}
}
- return sqlite3Fts5Tokenize(pConfig,
+ return sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
);
}
@@ -185951,12 +215753,12 @@ static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
}
/*
-** This function is only called for detail=columns tables.
+** This function is only called for detail=columns tables.
*/
static int sqlite3Fts5ExprPhraseCollist(
- Fts5Expr *pExpr,
- int iPhrase,
- const u8 **ppCollist,
+ Fts5Expr *pExpr,
+ int iPhrase,
+ const u8 **ppCollist,
int *pnCollist
){
Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
@@ -185966,8 +215768,8 @@ static int sqlite3Fts5ExprPhraseCollist(
assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
- if( pNode->bEof==0
- && pNode->iRowid==pExpr->pRoot->iRowid
+ if( pNode->bEof==0
+ && pNode->iRowid==pExpr->pRoot->iRowid
&& pPhrase->poslist.n>0
){
Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
@@ -185988,7 +215790,6 @@ static int sqlite3Fts5ExprPhraseCollist(
return rc;
}
-
/*
** 2014 August 11
**
@@ -186026,10 +215827,11 @@ struct Fts5Hash {
};
/*
-** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (zKey[]) and its current data
-** are stored in a single memory allocation. The position list data
-** immediately follows the key data in memory.
+** Each entry in the hash table is represented by an object of the
+** following type. Each object, its key (a nul-terminated string) and
+** its current data are stored in a single memory allocation. The
+** key immediately follows the object in memory. The position list
+** data immediately follows the key data in memory.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
@@ -186049,24 +215851,24 @@ struct Fts5Hash {
struct Fts5HashEntry {
Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */
Fts5HashEntry *pScanNext; /* Next entry in sorted order */
-
+
int nAlloc; /* Total size of allocation */
int iSzPoslist; /* Offset of space for 4-byte poslist size */
int nData; /* Total bytes of data (incl. structure) */
- int nKey; /* Length of zKey[] in bytes */
+ int nKey; /* Length of key in bytes */
u8 bDel; /* Set delete-flag @ iSzPoslist */
u8 bContent; /* Set content-flag (detail=none mode) */
i16 iCol; /* Column of last value written */
int iPos; /* Position of last value written */
i64 iRowid; /* Rowid of last value written */
- char zKey[8]; /* Nul-terminated entry key */
};
/*
-** Size of Fts5HashEntry without the zKey[] array.
+** Eqivalent to:
+**
+** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
*/
-#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8)
-
+#define fts5EntryKey(p) ( ((char *)(&(p)[1])) )
/*
@@ -186080,20 +215882,20 @@ static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
- int nByte;
+ sqlite3_int64 nByte;
memset(pNew, 0, sizeof(Fts5Hash));
pNew->pnByte = pnByte;
pNew->eDetail = pConfig->eDetail;
pNew->nSlot = 1024;
nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
- pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
+ pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc64(nByte);
if( pNew->aSlot==0 ){
sqlite3_free(pNew);
*ppNew = 0;
rc = SQLITE_NOMEM;
}else{
- memset(pNew->aSlot, 0, nByte);
+ memset(pNew->aSlot, 0, (size_t)nByte);
}
}
return rc;
@@ -186155,16 +215957,17 @@ static int fts5HashResize(Fts5Hash *pHash){
Fts5HashEntry **apNew;
Fts5HashEntry **apOld = pHash->aSlot;
- apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*));
+ apNew = (Fts5HashEntry**)sqlite3_malloc64(nNew*sizeof(Fts5HashEntry*));
if( !apNew ) return SQLITE_NOMEM;
memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
for(i=0; i<pHash->nSlot; i++){
while( apOld[i] ){
- int iHash;
+ unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)p->zKey, (int)strlen(p->zKey));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
+ (int)strlen(fts5EntryKey(p)));
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
@@ -186176,19 +215979,25 @@ static int fts5HashResize(Fts5Hash *pHash){
return SQLITE_OK;
}
-static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
+static int fts5HashAddPoslistSize(
+ Fts5Hash *pHash,
+ Fts5HashEntry *p,
+ Fts5HashEntry *p2
+){
+ int nRet = 0;
if( p->iSzPoslist ){
- u8 *pPtr = (u8*)p;
+ u8 *pPtr = p2 ? (u8*)p2 : (u8*)p;
+ int nData = p->nData;
if( pHash->eDetail==FTS5_DETAIL_NONE ){
- assert( p->nData==p->iSzPoslist );
+ assert( nData==p->iSzPoslist );
if( p->bDel ){
- pPtr[p->nData++] = 0x00;
+ pPtr[nData++] = 0x00;
if( p->bContent ){
- pPtr[p->nData++] = 0x00;
+ pPtr[nData++] = 0x00;
}
}
}else{
- int nSz = (p->nData - p->iSzPoslist - 1); /* Size in bytes */
+ int nSz = (nData - p->iSzPoslist - 1); /* Size in bytes */
int nPos = nSz*2 + p->bDel; /* Value of nPos field */
assert( p->bDel==0 || p->bDel==1 );
@@ -186198,14 +216007,19 @@ static void fts5HashAddPoslistSize(Fts5Hash *pHash, Fts5HashEntry *p){
int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
- p->nData += (nByte-1);
+ nData += (nByte-1);
}
}
- p->iSzPoslist = 0;
- p->bDel = 0;
- p->bContent = 0;
+ nRet = nData - p->nData;
+ if( p2==0 ){
+ p->iSzPoslist = 0;
+ p->bDel = 0;
+ p->bContent = 0;
+ p->nData = nData;
+ }
}
+ return nRet;
}
/*
@@ -186229,15 +216043,16 @@ static int sqlite3Fts5HashWrite(
u8 *pPtr;
int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */
int bNew; /* If non-delete entry should be written */
-
+
bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
/* Attempt to locate an existing hash entry */
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
- if( p->zKey[0]==bByte
+ char *zKey = fts5EntryKey(p);
+ if( zKey[0]==bByte
&& p->nKey==nToken
- && memcmp(&p->zKey[1], pToken, nToken)==0
+ && memcmp(&zKey[1], pToken, nToken)==0
){
break;
}
@@ -186246,7 +216061,8 @@ static int sqlite3Fts5HashWrite(
/* If an existing hash entry cannot be found, create a new one. */
if( p==0 ){
/* Figure out how much space to allocate */
- int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
+ char *zKey;
+ sqlite3_int64 nByte = sizeof(Fts5HashEntry) + (nToken+1) + 1 + 64;
if( nByte<128 ) nByte = 128;
/* Grow the Fts5Hash.aSlot[] array if necessary. */
@@ -186257,16 +216073,17 @@ static int sqlite3Fts5HashWrite(
}
/* Allocate new Fts5HashEntry and add it to the hash table. */
- p = (Fts5HashEntry*)sqlite3_malloc(nByte);
+ p = (Fts5HashEntry*)sqlite3_malloc64(nByte);
if( !p ) return SQLITE_NOMEM;
- memset(p, 0, FTS5_HASHENTRYSIZE);
- p->nAlloc = nByte;
- p->zKey[0] = bByte;
- memcpy(&p->zKey[1], pToken, nToken);
- assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
+ memset(p, 0, sizeof(Fts5HashEntry));
+ p->nAlloc = (int)nByte;
+ zKey = fts5EntryKey(p);
+ zKey[0] = bByte;
+ memcpy(&zKey[1], pToken, nToken);
+ assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
p->nKey = nToken;
- p->zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
+ zKey[nToken+1] = '\0';
+ p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
p->pHashNext = pHash->aSlot[iHash];
pHash->aSlot[iHash] = p;
pHash->nEntry++;
@@ -186284,8 +216101,8 @@ static int sqlite3Fts5HashWrite(
nIncr += p->nData;
}else{
- /* Appending to an existing hash-entry. Check that there is enough
- ** space to append the largest possible new entry. Worst case scenario
+ /* Appending to an existing hash-entry. Check that there is enough
+ ** space to append the largest possible new entry. Worst case scenario
** is:
**
** + 9 bytes for a new rowid,
@@ -186295,12 +216112,12 @@ static int sqlite3Fts5HashWrite(
** + 5 bytes for the new position offset (32-bit max).
*/
if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
- int nNew = p->nAlloc * 2;
+ sqlite3_int64 nNew = p->nAlloc * 2;
Fts5HashEntry *pNew;
Fts5HashEntry **pp;
- pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
+ pNew = (Fts5HashEntry*)sqlite3_realloc64(p, nNew);
if( pNew==0 ) return SQLITE_NOMEM;
- pNew->nAlloc = nNew;
+ pNew->nAlloc = (int)nNew;
for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
*pp = pNew;
p = pNew;
@@ -186314,7 +216131,7 @@ static int sqlite3Fts5HashWrite(
/* If this is a new rowid, append the 4-byte size field for the previous
** entry, and the new rowid for this entry. */
if( iRowid!=p->iRowid ){
- fts5HashAddPoslistSize(pHash, p);
+ fts5HashAddPoslistSize(pHash, p, 0);
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
p->iRowid = iRowid;
bNew = 1;
@@ -186384,9 +216201,11 @@ static Fts5HashEntry *fts5HashEntryMerge(
p1 = 0;
}else{
int i = 0;
- while( p1->zKey[i]==p2->zKey[i] ) i++;
+ char *zKey1 = fts5EntryKey(p1);
+ char *zKey2 = fts5EntryKey(p2);
+ while( zKey1[i]==zKey2[i] ) i++;
- if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){
+ if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
/* p2 is smaller */
*ppOut = p2;
ppOut = &p2->pScanNext;
@@ -186411,7 +216230,7 @@ static Fts5HashEntry *fts5HashEntryMerge(
** list.
*/
static int fts5HashEntrySort(
- Fts5Hash *pHash,
+ Fts5Hash *pHash,
const char *pTerm, int nTerm, /* Query prefix, if any */
Fts5HashEntry **ppSorted
){
@@ -186422,14 +216241,16 @@ static int fts5HashEntrySort(
int i;
*ppSorted = 0;
- ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot);
+ ap = sqlite3_malloc64(sizeof(Fts5HashEntry*) * nMergeSlot);
if( !ap ) return SQLITE_NOMEM;
memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
Fts5HashEntry *pIter;
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
- if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){
+ if( pTerm==0
+ || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
+ ){
Fts5HashEntry *pEntry = pIter;
pEntry->pScanNext = 0;
for(i=0; ap[i]; i++){
@@ -186457,23 +216278,36 @@ static int fts5HashEntrySort(
*/
static int sqlite3Fts5HashQuery(
Fts5Hash *pHash, /* Hash table to query */
+ int nPre,
const char *pTerm, int nTerm, /* Query term */
- const u8 **ppDoclist, /* OUT: Pointer to doclist for pTerm */
+ void **ppOut, /* OUT: Pointer to new object */
int *pnDoclist /* OUT: Size of doclist in bytes */
){
unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
+ char *zKey = 0;
Fts5HashEntry *p;
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
- if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
+ zKey = fts5EntryKey(p);
+ assert( p->nKey+1==(int)strlen(zKey) );
+ if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
}
if( p ){
- fts5HashAddPoslistSize(pHash, p);
- *ppDoclist = (const u8*)&p->zKey[nTerm+1];
- *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
+ int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
+ int nList = p->nData - nHashPre;
+ u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10));
+ if( pRet ){
+ Fts5HashEntry *pFaux = (Fts5HashEntry*)&pRet[nPre-nHashPre];
+ memcpy(&pRet[nPre], &((u8*)p)[nHashPre], nList);
+ nList += fts5HashAddPoslistSize(pHash, p, pFaux);
+ *pnDoclist = nList;
+ }else{
+ *pnDoclist = 0;
+ return SQLITE_NOMEM;
+ }
}else{
- *ppDoclist = 0;
+ *ppOut = 0;
*pnDoclist = 0;
}
@@ -186504,11 +216338,12 @@ static void sqlite3Fts5HashScanEntry(
){
Fts5HashEntry *p;
if( (p = pHash->pScan) ){
- int nTerm = (int)strlen(p->zKey);
- fts5HashAddPoslistSize(pHash, p);
- *pzTerm = p->zKey;
- *ppDoclist = (const u8*)&p->zKey[nTerm+1];
- *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
+ char *zKey = fts5EntryKey(p);
+ int nTerm = (int)strlen(zKey);
+ fts5HashAddPoslistSize(pHash, p, 0);
+ *pzTerm = zKey;
+ *ppDoclist = (const u8*)&zKey[nTerm+1];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
}else{
*pzTerm = 0;
*ppDoclist = 0;
@@ -186516,7 +216351,6 @@ static void sqlite3Fts5HashScanEntry(
}
}
-
/*
** 2014 May 31
**
@@ -186529,7 +216363,7 @@ static void sqlite3Fts5HashScanEntry(
**
******************************************************************************
**
-** Low level access to the FTS index stored in the database file. The
+** Low level access to the FTS index stored in the database file. The
** routines in this file file implement all read and write access to the
** %_data table. Other parts of the system access this functionality via
** the interface defined in fts5Int.h.
@@ -186545,10 +216379,10 @@ static void sqlite3Fts5HashScanEntry(
** As well as the main term index, there may be up to 31 prefix indexes.
** The format is similar to FTS3/4, except that:
**
-** * all segment b-tree leaf data is stored in fixed size page records
-** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is
-** taken to ensure it is possible to iterate in either direction through
-** the entries in a doclist, or to seek to a specific entry within a
+** * all segment b-tree leaf data is stored in fixed size page records
+** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is
+** taken to ensure it is possible to iterate in either direction through
+** the entries in a doclist, or to seek to a specific entry within a
** doclist, without loading it into memory.
**
** * large doclists that span many pages have associated "doclist index"
@@ -186581,14 +216415,14 @@ static void sqlite3Fts5HashScanEntry(
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
**
** , contains the following 5 types of records. See the comments surrounding
-** the FTS5_*_ROWID macros below for a description of how %_data rowids are
+** the FTS5_*_ROWID macros below for a description of how %_data rowids are
** assigned to each fo them.
**
** 1. Structure Records:
**
** The set of segments that make up an index - the index structure - are
** recorded in a single record within the %_data table. The record consists
-** of a single 32-bit configuration cookie value followed by a list of
+** of a single 32-bit configuration cookie value followed by a list of
** SQLite varints. If the FTS table features more than one index (because
** there are one or more prefix indexes), it is guaranteed that all share
** the same cookie value.
@@ -186620,7 +216454,7 @@ static void sqlite3Fts5HashScanEntry(
**
** TERM/DOCLIST FORMAT:
**
-** Most of each segment leaf is taken up by term/doclist data. The
+** Most of each segment leaf is taken up by term/doclist data. The
** general format of term/doclist, starting with the first term
** on the leaf page, is:
**
@@ -186663,7 +216497,7 @@ static void sqlite3Fts5HashScanEntry(
**
** PAGE FORMAT
**
-** Each leaf page begins with a 4-byte header containing 2 16-bit
+** Each leaf page begins with a 4-byte header containing 2 16-bit
** unsigned integer fields in big-endian format. They are:
**
** * The byte offset of the first rowid on the page, if it exists
@@ -186698,7 +216532,7 @@ static void sqlite3Fts5HashScanEntry(
** 5. Segment doclist indexes:
**
** Doclist indexes are themselves b-trees, however they usually consist of
-** a single leaf record only. The format of each doclist index leaf page
+** a single leaf record only. The format of each doclist index leaf page
** is:
**
** * Flags byte. Bits are:
@@ -186708,8 +216542,8 @@ static void sqlite3Fts5HashScanEntry(
**
** * First rowid on page indicated by previous field. As a varint.
**
-** * A list of varints, one for each subsequent termless page. A
-** positive delta if the termless page contains at least one rowid,
+** * A list of varints, one for each subsequent termless page. A
+** positive delta if the termless page contains at least one rowid,
** or an 0x00 byte otherwise.
**
** Internal doclist index nodes are:
@@ -186722,7 +216556,7 @@ static void sqlite3Fts5HashScanEntry(
** * Copy of first rowid on page indicated by previous field. As a varint.
**
** * A list of delta-encoded varints - the first rowid on each subsequent
-** child page.
+** child page.
**
*/
@@ -186739,7 +216573,7 @@ static void sqlite3Fts5HashScanEntry(
**
** Each segment has a unique non-zero 16-bit id.
**
-** The rowid for each segment leaf is found by passing the segment id and
+** The rowid for each segment leaf is found by passing the segment id and
** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered
** sequentially starting from 1.
*/
@@ -186758,11 +216592,6 @@ static void sqlite3Fts5HashScanEntry(
#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
-/*
-** Maximum segments permitted in a single index
-*/
-#define FTS5_MAX_SEGMENT 2000
-
#ifdef SQLITE_DEBUG
static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
#endif
@@ -186841,7 +216670,7 @@ struct Fts5DoclistIter {
/*
** The contents of the "structure" record for each index are represented
-** using an Fts5Structure record in memory. Which uses instances of the
+** using an Fts5Structure record in memory. Which uses instances of the
** other Fts5StructureXXX types as components.
*/
struct Fts5StructureSegment {
@@ -186914,10 +216743,10 @@ struct Fts5CResult {
** Current leaf page number within segment.
**
** iLeafOffset:
-** Byte offset within the current leaf that is the first byte of the
+** Byte offset within the current leaf that is the first byte of the
** position list data (one byte passed the position-list size field).
** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
+** position list data. The exception is if the rowid for the current entry
** is the last thing on the leaf page.
**
** pLeaf:
@@ -186931,7 +216760,7 @@ struct Fts5CResult {
** Mask of FTS5_SEGITER_XXX values. Interpreted as follows:
**
** FTS5_SEGITER_ONETERM:
-** If set, set the iterator to point to EOF after the current doclist
+** If set, set the iterator to point to EOF after the current doclist
** has been exhausted. Do not proceed to the next term in the segment.
**
** FTS5_SEGITER_REVERSE:
@@ -186960,7 +216789,7 @@ struct Fts5SegIter {
/* Next method */
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
- /* The page and offset from which the current term was read. The offset
+ /* The page and offset from which the current term was read. The offset
** is the offset of the first rowid in the current doclist. */
int iTermLeafPgno;
int iTermLeafOffset;
@@ -186983,7 +216812,7 @@ struct Fts5SegIter {
};
/*
-** Argument is a pointer to an Fts5Data structure that contains a
+** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
*/
#define ASSERT_SZLEAF_OK(x) assert( \
@@ -186993,7 +216822,7 @@ struct Fts5SegIter {
#define FTS5_SEGITER_ONETERM 0x01
#define FTS5_SEGITER_REVERSE 0x02
-/*
+/*
** Argument is a pointer to an Fts5Data structure that contains a leaf
** page. This macro evaluates to true if the leaf contains no terms, or
** false if it contains at least one term.
@@ -187015,13 +216844,13 @@ struct Fts5SegIter {
** on empty segments.
**
** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
-** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the
+** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the
** comparison in this context is the index of the iterator that currently
** points to the smaller term/rowid combination. Iterators at EOF are
** considered to be greater than all other iterators.
**
** aFirst[1] contains the index in aSeg[] of the iterator that points to
-** the smallest key overall. aFirst[0] is unused.
+** the smallest key overall. aFirst[0] is unused.
**
** poslist:
** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
@@ -187031,7 +216860,6 @@ struct Fts5Iter {
Fts5IndexIter base; /* Base class containing output vars */
Fts5Index *pIndex; /* Index that owns this iterator */
- Fts5Structure *pStruct; /* Database structure for this iterator */
Fts5Buffer poslist; /* Buffer containing current poslist */
Fts5Colset *pColset; /* Restrict matches to these columns */
@@ -187084,7 +216912,7 @@ static void fts5PutU16(u8 *aOut, u16 iVal){
static u16 fts5GetU16(const u8 *aIn){
return ((u16)aIn[0] << 8) + aIn[1];
-}
+}
/*
** Allocate and return a buffer at least nByte bytes in size.
@@ -187092,7 +216920,7 @@ static u16 fts5GetU16(const u8 *aIn){
** If an OOM error is encountered, return NULL and set the error code in
** the Fts5Index handle passed as the first argument.
*/
-static void *fts5IdxMalloc(Fts5Index *p, int nByte){
+static void *fts5IdxMalloc(Fts5Index *p, sqlite3_int64 nByte){
return sqlite3Fts5MallocZero(&p->rc, nByte);
}
@@ -187126,7 +216954,7 @@ static int fts5BufferCompareBlob(
*/
static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
int nCmp = MIN(pLeft->n, pRight->n);
- int res = memcmp(pLeft->p, pRight->p, nCmp);
+ int res = fts5Memcmp(pLeft->p, pRight->p, nCmp);
return (res==0 ? (pLeft->n - pRight->n) : res);
}
@@ -187139,7 +216967,7 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
/*
** Close the read-only blob handle, if it is open.
*/
-static void fts5CloseReader(Fts5Index *p){
+static void sqlite3Fts5IndexCloseReader(Fts5Index *p){
if( p->pReader ){
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
@@ -187147,11 +216975,10 @@ static void fts5CloseReader(Fts5Index *p){
}
}
-
/*
** Retrieve a record from the %_data table.
**
-** If an error occurs, NULL is returned and an error left in the
+** If an error occurs, NULL is returned and an error left in the
** Fts5Index object.
*/
static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
@@ -187169,16 +216996,16 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
assert( p->pReader==0 );
p->pReader = pBlob;
if( rc!=SQLITE_OK ){
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
}
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
}
- /* If the blob handle is not open at this point, open it and seek
+ /* If the blob handle is not open at this point, open it and seek
** to the requested entry. */
if( p->pReader==0 && rc==SQLITE_OK ){
Fts5Config *pConfig = p->pConfig;
- rc = sqlite3_blob_open(pConfig->db,
+ rc = sqlite3_blob_open(pConfig->db,
pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader
);
}
@@ -187186,15 +217013,15 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
/* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls
** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead.
** All the reasons those functions might return SQLITE_ERROR - missing
- ** table, missing row, non-blob/text in block column - indicate
+ ** table, missing row, non-blob/text in block column - indicate
** backing store corruption. */
if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT;
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader);
- int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
- pRet = (Fts5Data*)sqlite3_malloc(nAlloc);
+ sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
+ pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
if( pRet ){
pRet->nn = nByte;
aOut = pRet->p = (u8*)&pRet[1];
@@ -187210,6 +217037,8 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
pRet = 0;
}else{
/* TODO1: Fix this */
+ pRet->p[nByte] = 0x00;
+ pRet->p[nByte+1] = 0x00;
pRet->szLeaf = fts5GetU16(&pRet->p[2]);
}
}
@@ -187232,7 +217061,7 @@ static void fts5DataRelease(Fts5Data *pData){
static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
Fts5Data *pRet = fts5DataRead(p, iRowid);
if( pRet ){
- if( pRet->szLeaf>pRet->nn ){
+ if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){
p->rc = FTS5_CORRUPT;
fts5DataRelease(pRet);
pRet = 0;
@@ -187248,7 +217077,9 @@ static int fts5IndexPrepareStmt(
){
if( p->rc==SQLITE_OK ){
if( zSql ){
- p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0);
+ p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
+ SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
+ ppStmt, 0);
}else{
p->rc = SQLITE_NOMEM;
}
@@ -187267,7 +217098,7 @@ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){
if( p->pWriter==0 ){
Fts5Config *pConfig = p->pConfig;
fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf(
- "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)",
+ "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)",
pConfig->zDb, pConfig->zName
));
if( p->rc ) return;
@@ -187277,6 +217108,7 @@ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){
sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC);
sqlite3_step(p->pWriter);
p->rc = sqlite3_reset(p->pWriter);
+ sqlite3_bind_null(p->pWriter, 2);
}
/*
@@ -187288,22 +217120,12 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
if( p->rc!=SQLITE_OK ) return;
if( p->pDeleter==0 ){
- int rc;
Fts5Config *pConfig = p->pConfig;
char *zSql = sqlite3_mprintf(
- "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
+ "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
pConfig->zDb, pConfig->zName
);
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0);
- sqlite3_free(zSql);
- }
- if( rc!=SQLITE_OK ){
- p->rc = rc;
- return;
- }
+ if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return;
}
sqlite3_bind_int64(p->pDeleter, 1, iFirst);
@@ -187334,7 +217156,7 @@ static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
}
/*
-** Release a reference to an Fts5Structure object returned by an earlier
+** Release a reference to an Fts5Structure object returned by an earlier
** call to fts5StructureRead() or fts5StructureDecode().
*/
static void fts5StructureRelease(Fts5Structure *pStruct){
@@ -187375,7 +217197,7 @@ static int fts5StructureDecode(
int iLvl;
int nLevel = 0;
int nSegment = 0;
- int nByte; /* Bytes of space to allocate at pRet */
+ sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
Fts5Structure *pRet = 0; /* Structure object to return */
/* Grab the cookie value */
@@ -187386,6 +217208,11 @@ static int fts5StructureDecode(
** structure record. */
i += fts5GetVarint32(&pData[i], nLevel);
i += fts5GetVarint32(&pData[i], nSegment);
+ if( nLevel>FTS5_MAX_SEGMENT || nLevel<0
+ || nSegment>FTS5_MAX_SEGMENT || nSegment<0
+ ){
+ return FTS5_CORRUPT;
+ }
nByte = (
sizeof(Fts5Structure) + /* Main structure */
sizeof(Fts5StructureLevel) * (nLevel-1) /* aLevel[] array */
@@ -187408,25 +217235,35 @@ static int fts5StructureDecode(
}else{
i += fts5GetVarint32(&pData[i], pLvl->nMerge);
i += fts5GetVarint32(&pData[i], nTotal);
- assert( nTotal>=pLvl->nMerge );
- pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
+ if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
+ pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
nTotal * sizeof(Fts5StructureSegment)
);
+ nSegment -= nTotal;
}
if( rc==SQLITE_OK ){
pLvl->nSeg = nTotal;
for(iSeg=0; iSeg<nTotal; iSeg++){
+ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
if( i>=nData ){
rc = FTS5_CORRUPT;
break;
}
- i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
- i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
- i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
+ i += fts5GetVarint32(&pData[i], pSeg->iSegid);
+ i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
+ i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
+ if( pSeg->pgnoLast<pSeg->pgnoFirst ){
+ rc = FTS5_CORRUPT;
+ break;
+ }
}
+ if( iLvl>0 && pLvl[-1].nMerge && nTotal==0 ) rc = FTS5_CORRUPT;
+ if( iLvl==nLevel-1 && pLvl->nMerge ) rc = FTS5_CORRUPT;
}
}
+ if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
+
if( rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
pRet = 0;
@@ -187444,12 +217281,12 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
- int nByte = (
+ sqlite3_int64 nByte = (
sizeof(Fts5Structure) + /* Main structure */
sizeof(Fts5StructureLevel) * (nLevel+1) /* aLevel[] array */
);
- pStruct = sqlite3_realloc(pStruct, nByte);
+ pStruct = sqlite3_realloc64(pStruct, nByte);
if( pStruct ){
memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel));
pStruct->nLevel++;
@@ -187465,19 +217302,19 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
** segments.
*/
static void fts5StructureExtendLevel(
- int *pRc,
- Fts5Structure *pStruct,
- int iLvl,
- int nExtra,
+ int *pRc,
+ Fts5Structure *pStruct,
+ int iLvl,
+ int nExtra,
int bInsert
){
if( *pRc==SQLITE_OK ){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
Fts5StructureSegment *aNew;
- int nByte;
+ sqlite3_int64 nByte;
nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment);
- aNew = sqlite3_realloc(pLvl->aSeg, nByte);
+ aNew = sqlite3_realloc64(pLvl->aSeg, nByte);
if( aNew ){
if( bInsert==0 ){
memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra);
@@ -187504,7 +217341,7 @@ static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
/* TODO: Do we need this if the leaf-index is appended? Probably... */
memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
- if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
+ if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){
p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
}
fts5DataRelease(pData);
@@ -187522,7 +217359,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){
if( p->rc==SQLITE_OK ){
if( p->pDataVersion==0 ){
- p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
+ p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
);
if( p->rc ) return 0;
@@ -187541,7 +217378,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){
** Read, deserialize and return the structure record.
**
** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
-** are over-allocated as described for function fts5StructureDecode()
+** are over-allocated as described for function fts5StructureDecode()
** above.
**
** If an error occurs, NULL is returned and an error code left in the
@@ -187690,8 +217527,8 @@ static int fts5SegmentSize(Fts5StructureSegment *pSeg){
}
/*
-** Return a copy of index structure pStruct. Except, promote as many
-** segments as possible to level iPromote. If an OOM occurs, NULL is
+** Return a copy of index structure pStruct. Except, promote as many
+** segments as possible to level iPromote. If an OOM occurs, NULL is
** returned.
*/
static void fts5StructurePromoteTo(
@@ -187731,8 +217568,8 @@ static void fts5StructurePromoteTo(
**
** b) If the segment just written is larger than the newest segment on
** the next populated level, then that segment, and any other adjacent
-** segments that are also smaller than the one just written, are
-** promoted.
+** segments that are also smaller than the one just written, are
+** promoted.
**
** If one or more segments are promoted, the structure object is updated
** to reflect this.
@@ -187766,7 +217603,7 @@ static void fts5StructurePromote(
if( sz>szMax ) szMax = sz;
}
if( szMax>=szSeg ){
- /* Condition (a) is true. Promote the newest segment on level
+ /* Condition (a) is true. Promote the newest segment on level
** iLvl to level iTst. */
iPromote = iTst;
szPromote = szMax;
@@ -187785,7 +217622,7 @@ static void fts5StructurePromote(
/*
-** Advance the iterator passed as the only argument. If the end of the
+** Advance the iterator passed as the only argument. If the end of the
** doclist-index page is reached, return non-zero.
*/
static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
@@ -187800,7 +217637,7 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
}else{
int iOff;
for(iOff=pLvl->iOff; iOff<pData->nn; iOff++){
- if( pData->p[iOff] ) break;
+ if( pData->p[iOff] ) break;
}
if( iOff<pData->nn ){
@@ -187830,7 +217667,7 @@ static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
if( pLvl[1].bEof==0 ){
fts5DataRelease(pLvl->pData);
memset(pLvl, 0, sizeof(Fts5DlidxLvl));
- pLvl->pData = fts5DataRead(p,
+ pLvl->pData = fts5DataRead(p,
FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
);
if( pLvl->pData ) fts5DlidxLvlNext(pLvl);
@@ -187850,7 +217687,7 @@ static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){
** points to the first rowid in the doclist-index.
**
** pData:
-** pointer to doclist-index record,
+** pointer to doclist-index record,
**
** When this function is called pIter->iLeafPgno is the page number the
** doclist is associated with (the one featuring the term).
@@ -187881,7 +217718,7 @@ static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){
Fts5DlidxLvl *pChild = &pLvl[-1];
fts5DataRelease(pChild->pData);
memset(pChild, 0, sizeof(Fts5DlidxLvl));
- pChild->pData = fts5DataRead(p,
+ pChild->pData = fts5DataRead(p,
FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno)
);
}
@@ -187904,8 +217741,8 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
int ii;
int nZero = 0;
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
+ /* Currently iOff points to the first byte of a varint. This block
+ ** decrements iOff until it points to the first byte of the previous
** varint. Taking care not to read any memory locations that occur
** before the buffer in memory. */
iLimit = (iOff>9 ? iOff-9 : 0);
@@ -187950,7 +217787,7 @@ static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
if( pLvl[1].bEof==0 ){
fts5DataRelease(pLvl->pData);
memset(pLvl, 0, sizeof(Fts5DlidxLvl));
- pLvl->pData = fts5DataRead(p,
+ pLvl->pData = fts5DataRead(p,
FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
);
if( pLvl->pData ){
@@ -187991,10 +217828,10 @@ static Fts5DlidxIter *fts5DlidxIterInit(
int bDone = 0;
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
- int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
+ sqlite3_int64 nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
Fts5DlidxIter *pNew;
- pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte);
+ pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
if( pNew==0 ){
p->rc = SQLITE_NOMEM;
}else{
@@ -188049,7 +217886,7 @@ static void fts5SegIterNextPage(
pIter->pLeaf = pIter->pNextLeaf;
pIter->pNextLeaf = 0;
}else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
- pIter->pLeaf = fts5LeafRead(p,
+ pIter->pLeaf = fts5LeafRead(p,
FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
);
}else{
@@ -188093,7 +217930,7 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
** Fts5SegIter.nPos
** Fts5SegIter.bDel
**
-** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
+** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
** position list content (if any).
*/
static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
@@ -188144,7 +217981,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
}
/*
-** Fts5SegIter.iLeafOffset currently points to the first byte of the
+** Fts5SegIter.iLeafOffset currently points to the first byte of the
** "nSuffix" field of a term. Function parameter nKeep contains the value
** of the "nPrefix" field (if there was one - it is passed 0 if this is
** the first term in the segment).
@@ -188155,7 +217992,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
** Fts5SegIter.rowid
**
** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of
-** the first position list. The position list belonging to document
+** the first position list. The position list belonging to document
** (Fts5SegIter.iRowid).
*/
static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
@@ -188164,12 +218001,13 @@ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
int nNew; /* Bytes of new data */
iOff += fts5GetVarint32(&a[iOff], nNew);
- if( iOff+nNew>pIter->pLeaf->nn ){
+ if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){
p->rc = FTS5_CORRUPT;
return;
}
pIter->term.n = nKeep;
fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
+ assert( pIter->term.n<=pIter->term.nSpace );
iOff += nNew;
pIter->iTermLeafOffset = iOff;
pIter->iTermLeafPgno = pIter->iLeafPgno;
@@ -188202,10 +218040,10 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
/*
** Initialize the iterator object pIter to iterate through the entries in
-** segment pSeg. The iterator is left pointing to the first entry when
+** segment pSeg. The iterator is left pointing to the first entry when
** this function returns.
**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
** an error has already occurred when this function is called, it is a no-op.
*/
static void fts5SegIterInit(
@@ -188234,7 +218072,7 @@ static void fts5SegIterInit(
if( p->rc==SQLITE_OK ){
pIter->iLeafOffset = 4;
assert_nc( pIter->pLeaf->nn>4 );
- assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
+ assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
fts5SegIterLoadTerm(p, pIter, 0);
fts5SegIterLoadNPos(p, pIter);
@@ -188250,8 +218088,8 @@ static void fts5SegIterInit(
** the position-list size field for the first relevant rowid on the page.
** Fts5SegIter.rowid is set, but nPos and bDel are not.
**
-** This function advances the iterator so that it points to the last
-** relevant rowid on the page and, if necessary, initializes the
+** This function advances the iterator so that it points to the last
+** relevant rowid on the page and, if necessary, initializes the
** aRowidOffset[] and iRowidOffset variables. At this point the iterator
** is in its regular state - Fts5SegIter.iLeafOffset points to the first
** byte of the position list content associated with said rowid.
@@ -188290,7 +218128,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
/* If necessary, grow the pIter->aRowidOffset[] array. */
if( iRowidOffset>=pIter->nRowidOffset ){
int nNew = pIter->nRowidOffset + 8;
- int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
+ int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int));
if( aNew==0 ){
p->rc = SQLITE_NOMEM;
break;
@@ -188471,10 +218309,10 @@ static void fts5SegIterNext_None(
/*
-** Advance iterator pIter to the next entry.
+** Advance iterator pIter to the next entry.
**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
-** is not considered an error if the iterator reaches EOF. If an error has
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
+** is not considered an error if the iterator reaches EOF. If an error has
** already occurred when this function is called, it is a no-op.
*/
static void fts5SegIterNext(
@@ -188558,7 +218396,7 @@ static void fts5SegIterNext(
else if( pLeaf->nn>pLeaf->szLeaf ){
pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
&pLeaf->p[pLeaf->szLeaf], iOff
- );
+ );
pIter->iLeafOffset = iOff;
pIter->iEndofDoclist = iOff;
bNewTerm = 1;
@@ -188585,13 +218423,14 @@ static void fts5SegIterNext(
}else{
/* The following could be done by calling fts5SegIterLoadNPos(). But
** this block is particularly performance critical, so equivalent
- ** code is inlined.
+ ** code is inlined.
**
** Later: Switched back to fts5SegIterLoadNPos() because it supports
** detail=none mode. Not ideal.
*/
int nSz;
assert( p->rc==SQLITE_OK );
+ assert( pIter->iLeafOffset<=pIter->pLeaf->nn );
fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
pIter->bDel = (nSz & 0x0001);
pIter->nPos = nSz>>1;
@@ -188664,7 +218503,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
}
/* If pLast is NULL at this point, then the last rowid for this doclist
- ** lies on the page currently indicated by the iterator. In this case
+ ** lies on the page currently indicated by the iterator. In this case
** pIter->iLeafOffset is already set to point to the position-list size
** field associated with the first relevant rowid on the page.
**
@@ -188694,8 +218533,8 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
/*
** Iterator pIter currently points to the first rowid of a doclist.
-** There is a doclist-index associated with the final term on the current
-** page. If the current term is the last term on the page, load the
+** There is a doclist-index associated with the final term on the current
+** page. If the current term is the last term on the page, load the
** doclist-index from disk and initialize an iterator at (pIter->pDlidx).
*/
static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
@@ -188709,8 +218548,8 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
/* Check if the current doclist ends on this page. If it does, return
** early without loading the doclist-index (as it belongs to a different
** term. */
- if( pIter->iTermLeafPgno==pIter->iLeafPgno
- && pIter->iEndofDoclist<pLeaf->szLeaf
+ if( pIter->iTermLeafPgno==pIter->iLeafPgno
+ && pIter->iEndofDoclist<pLeaf->szLeaf
){
return;
}
@@ -188743,10 +218582,10 @@ static void fts5LeafSeek(
int szLeaf = pIter->pLeaf->szLeaf;
int n = pIter->pLeaf->nn;
- int nMatch = 0;
- int nKeep = 0;
- int nNew = 0;
- int iTermOff;
+ u32 nMatch = 0;
+ u32 nKeep = 0;
+ u32 nNew = 0;
+ u32 iTermOff;
int iPgidx; /* Current offset in pgidx */
int bEndOfPage = 0;
@@ -188770,15 +218609,15 @@ static void fts5LeafSeek(
assert( nKeep>=nMatch );
if( nKeep==nMatch ){
- int nCmp;
- int i;
- nCmp = MIN(nNew, nTerm-nMatch);
+ u32 nCmp;
+ u32 i;
+ nCmp = (u32)MIN(nNew, nTerm-nMatch);
for(i=0; i<nCmp; i++){
if( a[iOff+i]!=pTerm[nMatch+i] ) break;
}
nMatch += i;
- if( nTerm==nMatch ){
+ if( (u32)nTerm==nMatch ){
if( i==nNew ){
goto search_success;
}else{
@@ -188822,6 +218661,7 @@ static void fts5LeafSeek(
iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
+ return;
}else{
nKeep = 0;
iTermOff = iOff;
@@ -188834,7 +218674,10 @@ static void fts5LeafSeek(
}
search_success:
-
+ if( (i64)iOff+nNew>n || nNew<1 ){
+ p->rc = FTS5_CORRUPT;
+ return;
+ }
pIter->iLeafOffset = iOff + nNew;
pIter->iTermLeafOffset = pIter->iLeafOffset;
pIter->iTermLeafPgno = pIter->iLeafPgno;
@@ -188871,7 +218714,7 @@ static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
** Initialize the object pIter to point to term pTerm/nTerm within segment
** pSeg. If there is no such term in the index, the iterator is set to EOF.
**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
** an error has already occurred when this function is called, it is a no-op.
*/
static void fts5SegIterSeekInit(
@@ -188903,6 +218746,7 @@ static void fts5SegIterSeekInit(
bDlidx = (val & 0x0001);
}
p->rc = sqlite3_reset(pIdxSelect);
+ sqlite3_bind_null(pIdxSelect, 2);
if( iPg<pSeg->pgnoFirst ){
iPg = pSeg->pgnoFirst;
@@ -188941,7 +218785,7 @@ static void fts5SegIterSeekInit(
** 4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
** to an entry with a term greater than or equal to (pTerm/nTerm).
*/
- assert( p->rc!=SQLITE_OK /* 1 */
+ assert_nc( p->rc!=SQLITE_OK /* 1 */
|| pIter->pLeaf==0 /* 2 */
|| fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0 /* 3 */
|| (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0) /* 4 */
@@ -188950,10 +218794,10 @@ static void fts5SegIterSeekInit(
/*
** Initialize the object pIter to point to term pTerm/nTerm within the
-** in-memory hash table. If there is no such term in the hash-table, the
+** in-memory hash table. If there is no such term in the hash-table, the
** iterator is set to EOF.
**
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
** an error has already occurred when this function is called, it is a no-op.
*/
static void fts5SegIterHashInit(
@@ -188962,31 +218806,40 @@ static void fts5SegIterHashInit(
int flags, /* Mask of FTS5INDEX_XXX flags */
Fts5SegIter *pIter /* Object to populate */
){
- const u8 *pList = 0;
int nList = 0;
const u8 *z = 0;
int n = 0;
+ Fts5Data *pLeaf = 0;
assert( p->pHash );
assert( p->rc==SQLITE_OK );
if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
+ const u8 *pList = 0;
+
p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
n = (z ? (int)strlen((const char*)z) : 0);
+ if( pList ){
+ pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
+ if( pLeaf ){
+ pLeaf->p = (u8*)pList;
+ }
+ }
}else{
- pIter->flags |= FTS5_SEGITER_ONETERM;
- sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList);
+ p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
+ (const char*)pTerm, nTerm, (void**)&pLeaf, &nList
+ );
+ if( pLeaf ){
+ pLeaf->p = (u8*)&pLeaf[1];
+ }
z = pTerm;
n = nTerm;
+ pIter->flags |= FTS5_SEGITER_ONETERM;
}
- if( pList ){
- Fts5Data *pLeaf;
+ if( pLeaf ){
sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z);
- pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
- if( pLeaf==0 ) return;
- pLeaf->p = (u8*)pList;
pLeaf->nn = pLeaf->szLeaf = nList;
pIter->pLeaf = pLeaf;
pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
@@ -189024,7 +218877,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){
** two iterators.
*/
static void fts5AssertComparisonResult(
- Fts5Iter *pIter,
+ Fts5Iter *pIter,
Fts5SegIter *p1,
Fts5SegIter *p2,
Fts5CResult *pRes
@@ -189039,7 +218892,7 @@ static void fts5AssertComparisonResult(
assert( pRes->iFirst==i1 );
}else{
int nMin = MIN(p1->term.n, p2->term.n);
- int res = memcmp(p1->term.p, p2->term.p, nMin);
+ int res = fts5Memcmp(p1->term.p, p2->term.p, nMin);
if( res==0 ) res = p1->term.n - p2->term.n;
if( res==0 ){
@@ -189061,7 +218914,7 @@ static void fts5AssertComparisonResult(
/*
** This function is a no-op unless SQLITE_DEBUG is defined when this module
-** is compiled. In that case, this function is essentially an assert()
+** is compiled. In that case, this function is essentially an assert()
** statement used to verify that the contents of the pIter->aFirst[] array
** are correct.
*/
@@ -189075,9 +218928,9 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
/* Check that pIter->iSwitchRowid is set correctly. */
for(i=0; i<pIter->nSeg; i++){
Fts5SegIter *p1 = &pIter->aSeg[i];
- assert( p1==pFirst
- || p1->pLeaf==0
- || fts5BufferCompare(&pFirst->term, &p1->term)
+ assert( p1==pFirst
+ || p1->pLeaf==0
+ || fts5BufferCompare(&pFirst->term, &p1->term)
|| p1->iRowid==pIter->iSwitchRowid
|| (p1->iRowid<pIter->iSwitchRowid)==pIter->bRev
);
@@ -189107,7 +218960,7 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
**
** If the returned value is non-zero, then it is the index of an entry
** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing
-** to a key that is a duplicate of another, higher priority,
+** to a key that is a duplicate of another, higher priority,
** segment-iterator in the pSeg->aSeg[] array.
*/
static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
@@ -189139,8 +218992,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
}else{
int res = fts5BufferCompare(&p1->term, &p2->term);
if( res==0 ){
- assert( i2>i1 );
- assert( i2!=0 );
+ assert_nc( i2>i1 );
+ assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
p1->bDel = p2->bDel;
@@ -189198,7 +219051,7 @@ static void fts5SegIterGotoPage(
}
/*
-** Advance the iterator passed as the second argument until it is at or
+** Advance the iterator passed as the second argument until it is at or
** past rowid iFrom. Regardless of the value of iFrom, the iterator is
** always advanced at least once.
*/
@@ -189262,7 +219115,6 @@ static void fts5MultiIterFree(Fts5Iter *pIter){
for(i=0; i<pIter->nSeg; i++){
fts5SegIterClear(&pIter->aSeg[i]);
}
- fts5StructureRelease(pIter->pStruct);
fts5BufferFree(&pIter->poslist);
sqlite3_free(pIter);
}
@@ -189295,7 +219147,7 @@ static void fts5MultiIterAdvanced(
** If non-zero is returned, the caller should call fts5MultiIterAdvanced()
** on the iterator instead. That function does the same as this one, except
** that it deals with more complicated cases as well.
-*/
+*/
static int fts5MultiIterAdvanceRowid(
Fts5Iter *pIter, /* Iterator to update aFirst[] array for */
int iChanged, /* Index of sub-iterator just advanced */
@@ -189346,19 +219198,20 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){
}
/*
-** Move the iterator to the next entry.
+** Move the iterator to the next entry.
**
-** If an error occurs, an error code is left in Fts5Index.rc. It is not
-** considered an error if the iterator reaches EOF, or if it is already at
+** If an error occurs, an error code is left in Fts5Index.rc. It is not
+** considered an error if the iterator reaches EOF, or if it is already at
** EOF when this function is called.
*/
static void fts5MultiIterNext(
- Fts5Index *p,
+ Fts5Index *p,
Fts5Iter *pIter,
int bFrom, /* True if argument iFrom is valid */
i64 iFrom /* Advance at least as far as this */
){
int bUseFrom = bFrom;
+ assert( pIter->base.bEof==0 );
while( p->rc==SQLITE_OK ){
int iFirst = pIter->aFirst[1].iFirst;
int bNewTerm = 0;
@@ -189370,7 +219223,7 @@ static void fts5MultiIterNext(
pSeg->xNext(p, pSeg, &bNewTerm);
}
- if( pSeg->pLeaf==0 || bNewTerm
+ if( pSeg->pLeaf==0 || bNewTerm
|| fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
){
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
@@ -189390,27 +219243,26 @@ static void fts5MultiIterNext(
}
static void fts5MultiIterNext2(
- Fts5Index *p,
+ Fts5Index *p,
Fts5Iter *pIter,
int *pbNewTerm /* OUT: True if *might* be new term */
){
assert( pIter->bSkipEmpty );
if( p->rc==SQLITE_OK ){
- do {
+ *pbNewTerm = 0;
+ do{
int iFirst = pIter->aFirst[1].iFirst;
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
int bNewTerm = 0;
assert( p->rc==SQLITE_OK );
pSeg->xNext(p, pSeg, &bNewTerm);
- if( pSeg->pLeaf==0 || bNewTerm
+ if( pSeg->pLeaf==0 || bNewTerm
|| fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
){
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
fts5MultiIterSetEof(pIter);
*pbNewTerm = 1;
- }else{
- *pbNewTerm = 0;
}
fts5AssertMultiIterSetup(p, pIter);
@@ -189430,7 +219282,7 @@ static Fts5Iter *fts5MultiIterAlloc(
int nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
- pNew = fts5IdxMalloc(p,
+ pNew = fts5IdxMalloc(p,
sizeof(Fts5Iter) + /* pNew */
sizeof(Fts5SegIter) * (nSlot-1) + /* pNew->aSeg[] */
sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
@@ -189445,8 +219297,8 @@ static Fts5Iter *fts5MultiIterAlloc(
}
static void fts5PoslistCallback(
- Fts5Index *pUnused,
- void *pContext,
+ Fts5Index *pUnused,
+ void *pContext,
const u8 *pChunk, int nChunk
){
UNUSED_PARAM(pUnused);
@@ -189483,8 +219335,8 @@ static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
}
static void fts5PoslistOffsetsCallback(
- Fts5Index *pUnused,
- void *pContext,
+ Fts5Index *pUnused,
+ void *pContext,
const u8 *pChunk, int nChunk
){
PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
@@ -189507,7 +219359,7 @@ static void fts5PoslistOffsetsCallback(
static void fts5PoslistFilterCallback(
Fts5Index *pUnused,
- void *pContext,
+ void *pContext,
const u8 *pChunk, int nChunk
){
PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
@@ -189585,7 +219437,7 @@ static void fts5ChunkIterate(
break;
}else{
pgno++;
- pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
+ pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
if( pData==0 ) break;
pChunk = &pData->p[4];
nChunk = MIN(nRem, pData->szLeaf - 4);
@@ -189610,7 +219462,8 @@ static void fts5SegiterPoslist(
Fts5Colset *pColset,
Fts5Buffer *pBuf
){
- if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
+ if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){
+ memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING);
if( pColset==0 ){
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
}else{
@@ -189651,7 +219504,7 @@ static int fts5IndexExtractCol(
while( iCol>iCurrent ){
/* Advance pointer p until it points to pEnd or an 0x01 byte that is
** not part of a varint. Note that it is not possible for a negative
- ** or extremely large varint to occur within an uncorrupted position
+ ** or extremely large varint to occur within an uncorrupted position
** list. So the last byte of each varint may be assumed to have a clear
** 0x80 bit. */
while( *p!=0x01 ){
@@ -189676,23 +219529,23 @@ static int fts5IndexExtractCol(
return p - (*pa);
}
-static int fts5IndexExtractColset (
+static void fts5IndexExtractColset(
+ int *pRc,
Fts5Colset *pColset, /* Colset to filter on */
const u8 *pPos, int nPos, /* Position list */
Fts5Buffer *pBuf /* Output buffer */
){
- int rc = SQLITE_OK;
- int i;
-
- fts5BufferZero(pBuf);
- for(i=0; i<pColset->nCol; i++){
- const u8 *pSub = pPos;
- int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
- if( nSub ){
- fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
+ if( *pRc==SQLITE_OK ){
+ int i;
+ fts5BufferZero(pBuf);
+ for(i=0; i<pColset->nCol; i++){
+ const u8 *pSub = pPos;
+ int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
+ if( nSub ){
+ fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
+ }
}
}
- return rc;
}
/*
@@ -189716,7 +219569,7 @@ static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
assert( pIter->pColset==0 );
if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
- /* All data is stored on the current page. Populate the output
+ /* All data is stored on the current page. Populate the output
** variables to point into the body of the page object. */
pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
}else{
@@ -189752,13 +219605,13 @@ static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){
}
/*
-** xSetOutputs callback used when:
+** xSetOutputs callback used when:
**
** * detail=col,
** * there is a column filter, and
-** * the table contains 100 or fewer columns.
+** * the table contains 100 or fewer columns.
**
-** The last point is to ensure all column numbers are stored as
+** The last point is to ensure all column numbers are stored as
** single-byte varints.
*/
static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
@@ -189770,7 +219623,7 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
fts5IterSetOutputs_Col(pIter, pSeg);
}else{
u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
- u8 *pEnd = (u8*)&a[pSeg->nPos];
+ u8 *pEnd = (u8*)&a[pSeg->nPos];
int iPrev = 0;
int *aiCol = pIter->pColset->aiCol;
int *aiColEnd = &aiCol[pIter->pColset->nCol];
@@ -189809,15 +219662,16 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
assert( pColset );
if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
- /* All data is stored on the current page. Populate the output
+ /* All data is stored on the current page. Populate the output
** variables to point into the body of the page object. */
const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
if( pColset->nCol==1 ){
pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
pIter->base.pData = a;
}else{
+ int *pRc = &pIter->pIndex->rc;
fts5BufferZero(&pIter->poslist);
- fts5IndexExtractColset(pColset, a, pSeg->nPos, &pIter->poslist);
+ fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
pIter->base.pData = pIter->poslist.p;
pIter->base.nData = pIter->poslist.n;
}
@@ -189872,7 +219726,7 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
** is zero or greater, data from the first nSegment segments on level iLevel
** is merged.
**
-** The iterator initially points to the first term/rowid entry in the
+** The iterator initially points to the first term/rowid entry in the
** iterated data.
*/
static void fts5MultiIterNew(
@@ -189907,9 +219761,7 @@ static void fts5MultiIterNew(
if( pNew==0 ) return;
pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
- pNew->pStruct = pStruct;
pNew->pColset = pColset;
- fts5StructureRef(pStruct);
if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
fts5IterSetOutputCb(&p->rc, pNew);
}
@@ -189943,8 +219795,8 @@ static void fts5MultiIterNew(
assert( iIter==nSeg );
}
- /* If the above was successful, each component iterators now points
- ** to the first entry in its segment. In this case initialize the
+ /* If the above was successful, each component iterators now points
+ ** to the first entry in its segment. In this case initialize the
** aFirst[] array. Or, if an error has occurred, free the iterator
** object and set the output variable to NULL. */
if( p->rc==SQLITE_OK ){
@@ -190013,12 +219865,12 @@ static void fts5MultiIterNew2(
}
/*
-** Return true if the iterator is at EOF or if an error has occurred.
+** Return true if the iterator is at EOF or if an error has occurred.
** False otherwise.
*/
static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){
- assert( p->rc
- || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
+ assert( p->rc
+ || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
);
return (p->rc || pIter->base.bEof);
}
@@ -190037,8 +219889,8 @@ static i64 fts5MultiIterRowid(Fts5Iter *pIter){
** Move the iterator to the next entry at or following iMatch.
*/
static void fts5MultiIterNextFrom(
- Fts5Index *p,
- Fts5Iter *pIter,
+ Fts5Index *p,
+ Fts5Iter *pIter,
i64 iMatch
){
while( 1 ){
@@ -190052,7 +219904,7 @@ static void fts5MultiIterNextFrom(
}
/*
-** Return a pointer to a buffer containing the term associated with the
+** Return a pointer to a buffer containing the term associated with the
** entry that the iterator currently points to.
*/
static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
@@ -190063,11 +219915,11 @@ static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
/*
** Allocate a new segment-id for the structure pStruct. The new segment
-** id must be between 1 and 65335 inclusive, and must not be used by
+** id must be between 1 and 65335 inclusive, and must not be used by
** any currently existing segment. If a free segment id cannot be found,
** SQLITE_FULL is returned.
**
-** If an error has already occurred, this function is a no-op. 0 is
+** If an error has already occurred, this function is a no-op. 0 is
** returned in this case.
*/
static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
@@ -190087,24 +219939,24 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
- if( iId<=FTS5_MAX_SEGMENT ){
- aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
+ if( iId<=FTS5_MAX_SEGMENT && iId>0 ){
+ aUsed[(iId-1) / 32] |= (u32)1 << ((iId-1) % 32);
}
}
}
for(i=0; aUsed[i]==0xFFFFFFFF; i++);
mask = aUsed[i];
- for(iSegid=0; mask & (1 << iSegid); iSegid++);
+ for(iSegid=0; mask & ((u32)1 << iSegid); iSegid++);
iSegid += 1 + i*32;
#ifdef SQLITE_DEBUG
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
- assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
+ assert_nc( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
}
}
- assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
+ assert_nc( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
{
sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
@@ -190112,8 +219964,9 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
u8 aBlob[2] = {0xff, 0xff};
sqlite3_bind_int(pIdxSelect, 1, iSegid);
sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
- assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
+ assert_nc( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
p->rc = sqlite3_reset(pIdxSelect);
+ sqlite3_bind_null(pIdxSelect, 2);
}
}
#endif
@@ -190135,10 +219988,10 @@ static void fts5IndexDiscardData(Fts5Index *p){
}
/*
-** Return the size of the prefix, in bytes, that buffer
+** Return the size of the prefix, in bytes, that buffer
** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
**
-** Buffer (pNew/<length-unknown>) is guaranteed to be greater
+** Buffer (pNew/<length-unknown>) is guaranteed to be greater
** than buffer (pOld/nOld).
*/
static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
@@ -190150,7 +220003,7 @@ static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
}
static void fts5WriteDlidxClear(
- Fts5Index *p,
+ Fts5Index *p,
Fts5SegWriter *pWriter,
int bFlush /* If true, write dlidx to disk */
){
@@ -190161,7 +220014,7 @@ static void fts5WriteDlidxClear(
if( pDlidx->buf.n==0 ) break;
if( bFlush ){
assert( pDlidx->pgno!=0 );
- fts5DataWrite(p,
+ fts5DataWrite(p,
FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
pDlidx->buf.p, pDlidx->buf.n
);
@@ -190181,13 +220034,13 @@ static int fts5WriteDlidxGrow(
int nLvl
){
if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){
- Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc(
+ Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc64(
pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl
);
if( aDlidx==0 ){
p->rc = SQLITE_NOMEM;
}else{
- int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx);
+ size_t nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx);
memset(&aDlidx[pWriter->nDlidx], 0, nByte);
pWriter->aDlidx = aDlidx;
pWriter->nDlidx = nLvl;
@@ -190215,8 +220068,8 @@ static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){
}
/*
-** This function is called whenever processing of the doclist for the
-** last term on leaf page (pWriter->iBtPage) is completed.
+** This function is called whenever processing of the doclist for the
+** last term on leaf page (pWriter->iBtPage) is completed.
**
** The doclist-index for that term is currently stored in-memory within the
** Fts5SegWriter.aDlidx[] array. If it is large enough, this function
@@ -190240,6 +220093,7 @@ static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){
sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1));
sqlite3_step(p->pIdxWriter);
p->rc = sqlite3_reset(p->pIdxWriter);
+ sqlite3_bind_null(p->pIdxWriter, 2);
}
pWriter->iBtPage = 0;
}
@@ -190259,8 +220113,10 @@ static void fts5WriteBtreeTerm(
int nTerm, const u8 *pTerm /* First term on new page */
){
fts5WriteFlushBtree(p, pWriter);
- fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
- pWriter->iBtPage = pWriter->writer.pgno;
+ if( p->rc==SQLITE_OK ){
+ fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
+ pWriter->iBtPage = pWriter->writer.pgno;
+ }
}
/*
@@ -190298,8 +220154,8 @@ static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){
** doclist-index.
*/
static void fts5WriteDlidxAppend(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
+ Fts5Index *p,
+ Fts5SegWriter *pWriter,
i64 iRowid
){
int i;
@@ -190312,11 +220168,11 @@ static void fts5WriteDlidxAppend(
if( pDlidx->buf.n>=p->pConfig->pgsz ){
/* The current doclist-index page is full. Write it to disk and push
** a copy of iRowid (which will become the first rowid on the next
- ** doclist-index leaf page) up into the next level of the b-tree
+ ** doclist-index leaf page) up into the next level of the b-tree
** hierarchy. If the node being flushed is currently the root node,
** also push its first rowid upwards. */
pDlidx->buf.p[0] = 0x01; /* Not the root node */
- fts5DataWrite(p,
+ fts5DataWrite(p,
FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
pDlidx->buf.p, pDlidx->buf.n
);
@@ -190362,9 +220218,6 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
Fts5PageWriter *pPage = &pWriter->writer;
i64 iRowid;
-static int nCall = 0;
-nCall++;
-
assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
/* Set the szLeaf header field. */
@@ -190403,17 +220256,18 @@ nCall++;
** Append term pTerm/nTerm to the segment being written by the writer passed
** as the second argument.
**
-** If an error occurs, set the Fts5Index.rc error code. If an error has
+** If an error occurs, set the Fts5Index.rc error code. If an error has
** already occurred, this function is a no-op.
*/
static void fts5WriteAppendTerm(
- Fts5Index *p,
+ Fts5Index *p,
Fts5SegWriter *pWriter,
- int nTerm, const u8 *pTerm
+ int nTerm, const u8 *pTerm
){
int nPrefix; /* Bytes of prefix compression for term */
Fts5PageWriter *pPage = &pWriter->writer;
Fts5Buffer *pPgidx = &pWriter->writer.pgidx;
+ int nMin = MIN(pPage->term.n, nTerm);
assert( p->rc==SQLITE_OK );
assert( pPage->buf.n>=4 );
@@ -190423,10 +220277,11 @@ static void fts5WriteAppendTerm(
if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){
if( pPage->buf.n>4 ){
fts5WriteFlushLeaf(p, pWriter);
+ if( p->rc!=SQLITE_OK ) return;
}
fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING);
}
-
+
/* TODO1: Updating pgidx here. */
pPgidx->n += sqlite3Fts5PutVarint(
&pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx
@@ -190442,11 +220297,11 @@ static void fts5WriteAppendTerm(
if( pPage->pgno!=1 ){
/* This is the first term on a leaf that is not the leftmost leaf in
** the segment b-tree. In this case it is necessary to add a term to
- ** the b-tree hierarchy that is (a) larger than the largest term
+ ** the b-tree hierarchy that is (a) larger than the largest term
** already written to the segment and (b) smaller than or equal to
** this term. In other words, a prefix of (pTerm/nTerm) that is one
** byte longer than the longest prefix (pTerm/nTerm) shares with the
- ** previous term.
+ ** previous term.
**
** Usually, the previous term is available in pPage->term. The exception
** is if this is the first term written in an incremental-merge step.
@@ -190455,13 +220310,14 @@ static void fts5WriteAppendTerm(
** inefficient, but still correct. */
int n = nTerm;
if( pPage->term.n ){
- n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
+ n = 1 + fts5PrefixCompress(nMin, pPage->term.p, pTerm);
}
fts5WriteBtreeTerm(p, pWriter, n, pTerm);
+ if( p->rc!=SQLITE_OK ) return;
pPage = &pWriter->writer;
}
}else{
- nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, pTerm);
+ nPrefix = fts5PrefixCompress(nMin, pPage->term.p, pTerm);
fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
}
@@ -190482,10 +220338,10 @@ static void fts5WriteAppendTerm(
}
/*
-** Append a rowid and position-list size field to the writers output.
+** Append a rowid and position-list size field to the writers output.
*/
static void fts5WriteAppendRowid(
- Fts5Index *p,
+ Fts5Index *p,
Fts5SegWriter *pWriter,
i64 iRowid
){
@@ -190496,7 +220352,7 @@ static void fts5WriteAppendRowid(
fts5WriteFlushLeaf(p, pWriter);
}
- /* If this is to be the first rowid written to the page, set the
+ /* If this is to be the first rowid written to the page, set the
** rowid-pointer in the page-header. Also append a value to the dlidx
** buffer, in case a doclist-index is required. */
if( pWriter->bFirstRowidInPage ){
@@ -190508,7 +220364,7 @@ static void fts5WriteAppendRowid(
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
- assert( p->rc || iRowid>pWriter->iPrevRowid );
+ assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
}
pWriter->iPrevRowid = iRowid;
@@ -190518,18 +220374,18 @@ static void fts5WriteAppendRowid(
}
static void fts5WriteAppendPoslistData(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
- const u8 *aData,
+ Fts5Index *p,
+ Fts5SegWriter *pWriter,
+ const u8 *aData,
int nData
){
Fts5PageWriter *pPage = &pWriter->writer;
const u8 *a = aData;
int n = nData;
-
+
assert( p->pConfig->pgsz>0 );
- while( p->rc==SQLITE_OK
- && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
+ while( p->rc==SQLITE_OK
+ && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
){
int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n;
int nCopy = 0;
@@ -190552,7 +220408,7 @@ static void fts5WriteAppendPoslistData(
** allocations associated with the writer.
*/
static void fts5WriteFinish(
- Fts5Index *p,
+ Fts5Index *p,
Fts5SegWriter *pWriter, /* Writer object */
int *pnLeaf /* OUT: Number of leaf pages in b-tree */
){
@@ -190580,8 +220436,8 @@ static void fts5WriteFinish(
}
static void fts5WriteInit(
- Fts5Index *p,
- Fts5SegWriter *pWriter,
+ Fts5Index *p,
+ Fts5SegWriter *pWriter,
int iSegid
){
const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING;
@@ -190604,7 +220460,7 @@ static void fts5WriteInit(
if( p->pIdxWriter==0 ){
Fts5Config *pConfig = p->pConfig;
fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf(
- "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)",
+ "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)",
pConfig->zDb, pConfig->zName
));
}
@@ -190630,7 +220486,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
int i;
Fts5Buffer buf;
memset(&buf, 0, sizeof(Fts5Buffer));
- for(i=0; i<pIter->nSeg; i++){
+ for(i=0; i<pIter->nSeg && p->rc==SQLITE_OK; i++){
Fts5SegIter *pSeg = &pIter->aSeg[i];
if( pSeg->pSeg==0 ){
/* no-op */
@@ -190648,35 +220504,44 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00};
iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno);
- pData = fts5DataRead(p, iLeafRowid);
+ pData = fts5LeafRead(p, iLeafRowid);
if( pData ){
- fts5BufferZero(&buf);
- fts5BufferGrow(&p->rc, &buf, pData->nn);
- fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
- fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
- fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
- if( p->rc==SQLITE_OK ){
- /* Set the szLeaf field */
- fts5PutU16(&buf.p[2], (u16)buf.n);
- }
+ if( iOff>pData->szLeaf ){
+ /* This can occur if the pages that the segments occupy overlap - if
+ ** a single page has been assigned to more than one segment. In
+ ** this case a prior iteration of this loop may have corrupted the
+ ** segment currently being trimmed. */
+ p->rc = FTS5_CORRUPT;
+ }else{
+ fts5BufferZero(&buf);
+ fts5BufferGrow(&p->rc, &buf, pData->nn);
+ fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
+ fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
+ fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
+ if( p->rc==SQLITE_OK ){
+ /* Set the szLeaf field */
+ fts5PutU16(&buf.p[2], (u16)buf.n);
+ }
- /* Set up the new page-index array */
- fts5BufferAppendVarint(&p->rc, &buf, 4);
- if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
- && pSeg->iEndofDoclist<pData->szLeaf
- ){
- int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
- fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
- fts5BufferAppendBlob(&p->rc, &buf,
- pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
- );
- }
+ /* Set up the new page-index array */
+ fts5BufferAppendVarint(&p->rc, &buf, 4);
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
+ && pSeg->iEndofDoclist<pData->szLeaf
+ && pSeg->iPgidxOff<=pData->nn
+ ){
+ int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
+ fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
+ fts5BufferAppendBlob(&p->rc, &buf,
+ pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
+ );
+ }
+ pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
+ fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
+ fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
+ }
fts5DataRelease(pData);
- pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
- fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
- fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
}
}
}
@@ -190684,8 +220549,8 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
}
static void fts5MergeChunkCallback(
- Fts5Index *p,
- void *pCtx,
+ Fts5Index *p,
+ void *pCtx,
const u8 *pChunk, int nChunk
){
Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx;
@@ -190713,6 +220578,7 @@ static void fts5IndexMergeLevel(
int bOldest; /* True if the output segment is the oldest */
int eDetail = p->pConfig->eDetail;
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
+ int bTermWritten = 0; /* True if current term already output */
assert( iLvl<pStruct->nLevel );
assert( pLvl->nMerge<=pLvl->nSeg );
@@ -190766,18 +220632,22 @@ static void fts5IndexMergeLevel(
int nTerm;
const u8 *pTerm;
- /* Check for key annihilation. */
- if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
-
pTerm = fts5MultiIterTerm(pIter, &nTerm);
- if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
+ if( nTerm!=term.n || fts5Memcmp(pTerm, term.p, nTerm) ){
if( pnRem && writer.nLeafWritten>nRem ){
break;
}
+ fts5BufferSet(&p->rc, &term, nTerm, pTerm);
+ bTermWritten =0;
+ }
+
+ /* Check for key annihilation. */
+ if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
/* This is a new term. Append a term to the output segment. */
fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
- fts5BufferSet(&p->rc, &term, nTerm, pTerm);
+ bTermWritten = 1;
}
/* Append the rowid to the output */
@@ -190895,7 +220765,7 @@ static int fts5IndexMerge(
** segment. This function updates the write-counter accordingly and, if
** necessary, performs incremental merge work.
**
-** If an error occurs, set the Fts5Index.rc error code. If an error has
+** If an error occurs, set the Fts5Index.rc error code. If an error has
** already occurred, this function is a no-op.
*/
static void fts5IndexAutomerge(
@@ -190946,12 +220816,12 @@ static int fts5IndexReturn(Fts5Index *p){
typedef struct Fts5FlushCtx Fts5FlushCtx;
struct Fts5FlushCtx {
Fts5Index *pIdx;
- Fts5SegWriter writer;
+ Fts5SegWriter writer;
};
/*
** Buffer aBuf[] contains a list of varints, all small enough to fit
-** in a 32-bit integer. Return the size of the largest prefix of this
+** in a 32-bit integer. Return the size of the largest prefix of this
** list nMax bytes or less in size.
*/
static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
@@ -190969,10 +220839,10 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
}
/*
-** Flush the contents of in-memory hash table iHash to a new level-0
+** Flush the contents of in-memory hash table iHash to a new level-0
** segment on disk. Also update the corresponding structure record.
**
-** If an error occurs, set the Fts5Index.rc error code. If an error has
+** If an error occurs, set the Fts5Index.rc error code. If an error has
** already occurred, this function is a no-op.
*/
static void fts5FlushOneHash(Fts5Index *p){
@@ -191018,6 +220888,7 @@ static void fts5FlushOneHash(Fts5Index *p){
/* Write the term for this entry to disk. */
sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
+ if( p->rc!=SQLITE_OK ) break;
assert( writer.bFirstRowidInPage==0 );
if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
@@ -191028,18 +220899,19 @@ static void fts5FlushOneHash(Fts5Index *p){
i64 iDelta = 0;
int iOff = 0;
- /* The entire doclist will not fit on this leaf. The following
- ** loop iterates through the poslists that make up the current
+ /* The entire doclist will not fit on this leaf. The following
+ ** loop iterates through the poslists that make up the current
** doclist. */
while( p->rc==SQLITE_OK && iOff<nDoclist ){
iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
iRowid += iDelta;
-
+
if( writer.bFirstRowidInPage ){
fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
writer.bFirstRowidInPage = 0;
fts5WriteDlidxAppend(p, &writer, iRowid);
+ if( p->rc!=SQLITE_OK ) break;
}else{
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
}
@@ -191097,7 +220969,7 @@ static void fts5FlushOneHash(Fts5Index *p){
/* TODO2: Doclist terminator written here. */
/* pBuf->p[pBuf->n++] = '\0'; */
assert( pBuf->n<=pBuf->nSpace );
- sqlite3Fts5HashScanNext(pHash);
+ if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
}
sqlite3Fts5HashClear(pHash);
fts5WriteFinish(p, &writer, &pgnoLast);
@@ -191137,18 +221009,18 @@ static void fts5IndexFlush(Fts5Index *p){
}
static Fts5Structure *fts5IndexOptimizeStruct(
- Fts5Index *p,
+ Fts5Index *p,
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
- int nByte = sizeof(Fts5Structure);
+ sqlite3_int64 nByte = sizeof(Fts5Structure);
int nSeg = pStruct->nSegment;
int i;
/* Figure out if this structure requires optimization. A structure does
** not require optimization if either:
**
- ** + it consists of fewer than two segments, or
+ ** + it consists of fewer than two segments, or
** + all segments are on the same level, or
** + all segments except one are currently inputs to a merge operation.
**
@@ -191225,7 +221097,7 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
fts5StructureRelease(pNew);
}
- return fts5IndexReturn(p);
+ return fts5IndexReturn(p);
}
/*
@@ -191271,11 +221143,13 @@ static void fts5AppendPoslist(
Fts5Buffer *pBuf
){
int nData = pMulti->base.nData;
+ int nByte = nData + 9 + 9 + FTS5_DATA_ZERO_PADDING;
assert( nData>0 );
- if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nData+9+9) ){
+ if( p->rc==SQLITE_OK && 0==fts5BufferGrow(&p->rc, pBuf, nByte) ){
fts5BufferSafeAppendVarint(pBuf, iDelta);
fts5BufferSafeAppendVarint(pBuf, nData*2);
fts5BufferSafeAppendBlob(pBuf, pMulti->base.pData, nData);
+ memset(&pBuf->p[pBuf->n], 0, FTS5_DATA_ZERO_PADDING);
}
}
@@ -191307,7 +221181,7 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
}
static void fts5DoclistIterInit(
- Fts5Buffer *pBuf,
+ Fts5Buffer *pBuf,
Fts5DoclistIter *pIter
){
memset(pIter, 0, sizeof(*pIter));
@@ -191423,7 +221297,19 @@ static void fts5MergePrefixLists(
Fts5Buffer out = {0, 0, 0};
Fts5Buffer tmp = {0, 0, 0};
- if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return;
+ /* The maximum size of the output is equal to the sum of the two
+ ** input sizes + 1 varint (9 bytes). The extra varint is because if the
+ ** first rowid in one input is a large negative number, and the first in
+ ** the other a non-negative number, the delta for the non-negative
+ ** number will be larger on disk than the literal integer value
+ ** was.
+ **
+ ** Or, if the input position-lists are corrupt, then the output might
+ ** include up to 2 extra 10-byte positions created by interpreting -1
+ ** (the value PoslistNext64() uses for EOF) as a position and appending
+ ** it to the output. This can happen at most once for each input
+ ** position-list, hence two 10 byte paddings. */
+ if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9+10+10) ) return;
fts5DoclistIterInit(p1, &i1);
fts5DoclistIterInit(p2, &i2);
@@ -191434,6 +221320,7 @@ static void fts5MergePrefixLists(
fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
fts5DoclistIterNext(&i1);
if( i1.aPoslist==0 ) break;
+ assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
}
else if( i2.iRowid!=i1.iRowid ){
/* Copy entry from i2 */
@@ -191441,28 +221328,34 @@ static void fts5MergePrefixLists(
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
fts5DoclistIterNext(&i2);
if( i2.aPoslist==0 ) break;
+ assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
}
else{
- /* Merge the two position lists. */
+ /* Merge the two position lists. */
i64 iPos1 = 0;
i64 iPos2 = 0;
int iOff1 = 0;
int iOff2 = 0;
u8 *a1 = &i1.aPoslist[i1.nSize];
u8 *a2 = &i2.aPoslist[i2.nSize];
+ int nCopy;
+ u8 *aCopy;
i64 iPrev = 0;
Fts5PoslistWriter writer;
memset(&writer, 0, sizeof(writer));
+ /* See the earlier comment in this function for an explanation of why
+ ** corrupt input position lists might cause the output to consume
+ ** at most 20 bytes of unexpected space. */
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferZero(&tmp);
- sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist);
+ sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist + 10 + 10);
if( p->rc ) break;
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
- assert( iPos1>=0 && iPos2>=0 );
+ assert_nc( iPos1>=0 && iPos2>=0 );
if( iPos1<iPos2 ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
@@ -191471,7 +221364,6 @@ static void fts5MergePrefixLists(
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
}
-
if( iPos1>=0 && iPos2>=0 ){
while( 1 ){
if( iPos1<iPos2 ){
@@ -191481,7 +221373,7 @@ static void fts5MergePrefixLists(
sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
if( iPos1<0 ) break;
}else{
- assert( iPos2!=iPrev );
+ assert_nc( iPos2!=iPrev );
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
if( iPos2<0 ) break;
@@ -191493,19 +221385,32 @@ static void fts5MergePrefixLists(
if( iPos1!=iPrev ){
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
}
- fts5BufferSafeAppendBlob(&tmp, &a1[iOff1], i1.nPoslist-iOff1);
+ aCopy = &a1[iOff1];
+ nCopy = i1.nPoslist - iOff1;
}else{
- assert( iPos2>=0 && iPos2!=iPrev );
+ assert_nc( iPos2>=0 && iPos2!=iPrev );
sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
- fts5BufferSafeAppendBlob(&tmp, &a2[iOff2], i2.nPoslist-iOff2);
+ aCopy = &a2[iOff2];
+ nCopy = i2.nPoslist - iOff2;
+ }
+ if( nCopy>0 ){
+ fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy);
}
/* WRITEPOSLISTSIZE */
+ assert_nc( tmp.n<=i1.nPoslist+i2.nPoslist );
+ assert( tmp.n<=i1.nPoslist+i2.nPoslist+10+10 );
+ if( tmp.n>i1.nPoslist+i2.nPoslist ){
+ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
+ break;
+ }
fts5BufferSafeAppendVarint(&out, tmp.n * 2);
fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
fts5DoclistIterNext(&i1);
fts5DoclistIterNext(&i2);
+ assert_nc( out.n<=(p1->n+p2->n+9) );
if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
+ assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
}
}
@@ -191517,6 +221422,7 @@ static void fts5MergePrefixLists(
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
}
+ assert_nc( out.n<=(p1->n+p2->n+9) );
fts5BufferSet(&p->rc, p1, out.n, out.p);
fts5BufferFree(&tmp);
@@ -191550,8 +221456,8 @@ static void fts5SetupPrefixIter(
pStruct = fts5StructureRead(p);
if( aBuf && pStruct ){
- const int flags = FTS5INDEX_QUERY_SCAN
- | FTS5INDEX_QUERY_SKIPEMPTY
+ const int flags = FTS5INDEX_QUERY_SCAN
+ | FTS5INDEX_QUERY_SKIPEMPTY
| FTS5INDEX_QUERY_NOOUTPUT;
int i;
i64 iLastRowid = 0;
@@ -191605,11 +221511,11 @@ static void fts5SetupPrefixIter(
}
fts5MultiIterFree(p1);
- pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
+ pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
if( pData ){
pData->p = (u8*)&pData[1];
pData->nn = pData->szLeaf = doclist.n;
- memcpy(pData->p, doclist.p, doclist.n);
+ if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
fts5MultiIterNew2(p, pData, bDesc, ppIter);
}
fts5BufferFree(&doclist);
@@ -191633,9 +221539,9 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
}
/* Flush the hash table to disk if required */
- if( iRowid<p->iWriteRowid
+ if( iRowid<p->iWriteRowid
|| (iRowid==p->iWriteRowid && p->bDelete==0)
- || (p->nPendingData > p->pConfig->nHashSize)
+ || (p->nPendingData > p->pConfig->nHashSize)
){
fts5IndexFlush(p);
}
@@ -191648,21 +221554,21 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
/*
** Commit data to disk.
*/
-static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
+static int sqlite3Fts5IndexSync(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
- if( bCommit ) fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
return fts5IndexReturn(p);
}
/*
** Discard any data stored in the in-memory hash tables. Do not write it
** to the database. Additionally, assume that the contents of the %_data
-** table may have changed on disk. So any in-memory caches of %_data
+** table may have changed on disk. So any in-memory caches of %_data
** records must be invalidated.
*/
static int sqlite3Fts5IndexRollback(Fts5Index *p){
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
fts5IndexDiscardData(p);
fts5StructureInvalidate(p);
/* assert( p->rc==SQLITE_OK ); */
@@ -191677,6 +221583,7 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){
static int sqlite3Fts5IndexReinit(Fts5Index *p){
Fts5Structure s;
fts5StructureInvalidate(p);
+ fts5IndexDiscardData(p);
memset(&s, 0, sizeof(Fts5Structure));
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
@@ -191691,8 +221598,8 @@ static int sqlite3Fts5IndexReinit(Fts5Index *p){
** Otherwise, set *pp to NULL and return an SQLite error code.
*/
static int sqlite3Fts5IndexOpen(
- Fts5Config *pConfig,
- int bCreate,
+ Fts5Config *pConfig,
+ int bCreate,
Fts5Index **pp,
char **pzErr
){
@@ -191709,8 +221616,8 @@ static int sqlite3Fts5IndexOpen(
pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr
);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5CreateTable(pConfig, "idx",
- "segid, term, pgno, PRIMARY KEY(segid, term)",
+ rc = sqlite3Fts5CreateTable(pConfig, "idx",
+ "segid, term, pgno, PRIMARY KEY(segid, term)",
1, pzErr
);
}
@@ -191750,13 +221657,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
}
/*
-** Argument p points to a buffer containing utf-8 text that is n bytes in
+** Argument p points to a buffer containing utf-8 text that is n bytes in
** size. Return the number of bytes in the nChar character prefix of the
** buffer, or 0 if there are less than nChar characters in total.
*/
static int sqlite3Fts5IndexCharlenToBytelen(
- const char *p,
- int nByte,
+ const char *p,
+ int nByte,
int nChar
){
int n = 0;
@@ -191764,7 +221671,14 @@ static int sqlite3Fts5IndexCharlenToBytelen(
for(i=0; i<nChar; i++){
if( n>=nByte ) return 0; /* Input contains fewer than nChar chars */
if( (unsigned char)p[n++]>=0xc0 ){
- while( (p[n] & 0xc0)==0x80 ) n++;
+ if( n>=nByte ) return 0;
+ while( (p[n] & 0xc0)==0x80 ){
+ n++;
+ if( n>=nByte ){
+ if( i+1==nChar ) break;
+ return 0;
+ }
+ }
}
}
return n;
@@ -191775,7 +221689,7 @@ static int sqlite3Fts5IndexCharlenToBytelen(
** unicode characters in the string.
*/
static int fts5IndexCharlen(const char *pIn, int nIn){
- int nChar = 0;
+ int nChar = 0;
int i = 0;
while( i<nIn ){
if( (unsigned char)pIn[i++]>=0xc0 ){
@@ -191787,7 +221701,7 @@ static int fts5IndexCharlen(const char *pIn, int nIn){
}
/*
-** Insert or remove data to or from the index. Each time a document is
+** Insert or remove data to or from the index. Each time a document is
** added to or removed from the index, this function is called one or more
** times.
**
@@ -191818,7 +221732,7 @@ static int sqlite3Fts5IndexWrite(
const int nChar = pConfig->aPrefix[i];
int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
if( nByte ){
- rc = sqlite3Fts5HashWrite(p->pHash,
+ rc = sqlite3Fts5HashWrite(p->pHash,
p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
nByte
);
@@ -191829,7 +221743,7 @@ static int sqlite3Fts5IndexWrite(
}
/*
-** Open a new iterator to iterate though all rowid that match the
+** Open a new iterator to iterate though all rowid that match the
** specified token or token prefix.
*/
static int sqlite3Fts5IndexQuery(
@@ -191848,7 +221762,7 @@ static int sqlite3Fts5IndexQuery(
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
- memcpy(&buf.p[1], pToken, nToken);
+ if( nToken ) memcpy(&buf.p[1], pToken, nToken);
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
@@ -191856,9 +221770,9 @@ static int sqlite3Fts5IndexQuery(
** satisfied by scanning multiple terms in the main index.
**
** If the QUERY_TEST_NOIDX flag was specified, then this must be a
- ** prefix-query. Instead of using a prefix-index (if one exists),
+ ** prefix-query. Instead of using a prefix-index (if one exists),
** evaluate the prefix query using the main FTS index. This is used
- ** for internal sanity checking by the integrity-check in debug
+ ** for internal sanity checking by the integrity-check in debug
** mode only. */
#ifdef SQLITE_DEBUG
if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
@@ -191878,7 +221792,7 @@ static int sqlite3Fts5IndexQuery(
Fts5Structure *pStruct = fts5StructureRead(p);
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
if( pStruct ){
- fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY,
+ fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY,
pColset, buf.p, nToken+1, -1, 0, &pRet
);
fts5StructureRelease(pStruct);
@@ -191897,12 +221811,12 @@ static int sqlite3Fts5IndexQuery(
}
if( p->rc ){
- sqlite3Fts5IterClose(&pRet->base);
+ sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
pRet = 0;
- fts5CloseReader(p);
+ sqlite3Fts5IndexCloseReader(p);
}
- *ppIter = &pRet->base;
+ *ppIter = (Fts5IndexIter*)pRet;
sqlite3Fts5BufferFree(&buf);
}
return fts5IndexReturn(p);
@@ -191912,7 +221826,7 @@ static int sqlite3Fts5IndexQuery(
** Return true if the iterator passed as the only argument is at EOF.
*/
/*
-** Move to the next matching rowid.
+** Move to the next matching rowid.
*/
static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
@@ -191972,12 +221886,12 @@ static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5Index *pIndex = pIter->pIndex;
fts5MultiIterFree(pIter);
- fts5CloseReader(pIndex);
+ sqlite3Fts5IndexCloseReader(pIndex);
}
}
/*
-** Read and decode the "averages" record from the database.
+** Read and decode the "averages" record from the database.
**
** Parameter anSize must point to an array of size nCol, where nCol is
** the number of user defined columns in the FTS table.
@@ -192003,7 +221917,7 @@ static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){
}
/*
-** Replace the current "averages" record with the contents of the buffer
+** Replace the current "averages" record with the contents of the buffer
** supplied as the second argument.
*/
static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){
@@ -192021,7 +221935,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p){
}
/*
-** Set the 32-bit cookie value stored at the start of all structure
+** Set the 32-bit cookie value stored at the start of all structure
** records to the value passed as the second argument.
**
** Return SQLITE_OK if successful, or an SQLite error code if an error
@@ -192036,7 +221950,7 @@ static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){
assert( p->rc==SQLITE_OK );
sqlite3Fts5Put32(aCookie, iNew);
- rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl,
+ rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl,
"block", FTS5_STRUCTURE_ROWID, 1, &pBlob
);
if( rc==SQLITE_OK ){
@@ -192057,7 +221971,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
/*************************************************************************
**************************************************************************
-** Below this point is the implementation of the integrity-check
+** Below this point is the implementation of the integrity-check
** functionality.
*/
@@ -192065,9 +221979,9 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
** Return a simple checksum value based on the arguments.
*/
static u64 sqlite3Fts5IndexEntryCksum(
- i64 iRowid,
- int iCol,
- int iPos,
+ i64 iRowid,
+ int iCol,
+ int iPos,
int iIdx,
const char *pTerm,
int nTerm
@@ -192083,15 +221997,15 @@ static u64 sqlite3Fts5IndexEntryCksum(
#ifdef SQLITE_DEBUG
/*
-** This function is purely an internal test. It does not contribute to
+** This function is purely an internal test. It does not contribute to
** FTS functionality, or even the integrity-check, in any way.
**
-** Instead, it tests that the same set of pgno/rowid combinations are
+** Instead, it tests that the same set of pgno/rowid combinations are
** visited regardless of whether the doclist-index identified by parameters
** iSegid/iLeaf is iterated in forwards or reverse order.
*/
static void fts5TestDlidxReverse(
- Fts5Index *p,
+ Fts5Index *p,
int iSegid, /* Segment id to load from */
int iLeaf /* Load doclist-index for this leaf */
){
@@ -192165,13 +222079,44 @@ static int fts5QueryCksum(
return rc;
}
+/*
+** Check if buffer z[], size n bytes, contains as series of valid utf-8
+** encoded codepoints. If so, return 0. Otherwise, if the buffer does not
+** contain valid utf-8, return non-zero.
+*/
+static int fts5TestUtf8(const char *z, int n){
+ int i = 0;
+ assert_nc( n>0 );
+ while( i<n ){
+ if( (z[i] & 0x80)==0x00 ){
+ i++;
+ }else
+ if( (z[i] & 0xE0)==0xC0 ){
+ if( i+1>=n || (z[i+1] & 0xC0)!=0x80 ) return 1;
+ i += 2;
+ }else
+ if( (z[i] & 0xF0)==0xE0 ){
+ if( i+2>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
+ i += 3;
+ }else
+ if( (z[i] & 0xF8)==0xF0 ){
+ if( i+3>=n || (z[i+1] & 0xC0)!=0x80 || (z[i+2] & 0xC0)!=0x80 ) return 1;
+ if( (z[i+2] & 0xC0)!=0x80 ) return 1;
+ i += 3;
+ }else{
+ return 1;
+ }
+ }
+
+ return 0;
+}
/*
-** This function is also purely an internal test. It does not contribute to
+** This function is also purely an internal test. It does not contribute to
** FTS functionality, or even the integrity-check, in any way.
*/
static void fts5TestTerm(
- Fts5Index *p,
+ Fts5Index *p,
Fts5Buffer *pPrev, /* Previous term */
const char *z, int n, /* Possibly new term to test */
u64 expected,
@@ -192200,13 +222145,19 @@ static void fts5TestTerm(
if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
/* If this is a prefix query, check that the results returned if the
- ** the index is disabled are the same. In both ASC and DESC order.
+ ** the index is disabled are the same. In both ASC and DESC order.
**
** This check may only be performed if the hash table is empty. This
** is because the hash table only supports a single scan query at
** a time, and the multi-iter loop from which this function is called
- ** is already performing such a scan. */
- if( p->nPendingData==0 ){
+ ** is already performing such a scan.
+ **
+ ** Also only do this if buffer zTerm contains nTerm bytes of valid
+ ** utf-8. Otherwise, the last part of the buffer contents might contain
+ ** a non-utf-8 sequence that happens to be a prefix of a valid utf-8
+ ** character stored in the main fts index, which will cause the
+ ** test to fail. */
+ if( p->nPendingData==0 && 0==fts5TestUtf8(zTerm, nTerm) ){
if( iIdx>0 && rc==SQLITE_OK ){
int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
ck2 = 0;
@@ -192231,7 +222182,7 @@ static void fts5TestTerm(
}
p->rc = rc;
}
-
+
#else
# define fts5TestDlidxReverse(x,y,z)
# define fts5TestTerm(u,v,w,x,y,z)
@@ -192329,7 +222280,8 @@ static void fts5IndexIntegrityCheckSegment(
if( pSeg->pgnoFirst==0 ) return;
fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
- "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d",
+ "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d "
+ "ORDER BY 1, 2",
pConfig->zDb, pConfig->zName, pSeg->iSegid
));
@@ -192338,16 +222290,16 @@ static void fts5IndexIntegrityCheckSegment(
i64 iRow; /* Rowid for this leaf */
Fts5Data *pLeaf; /* Data for this leaf */
+ const char *zIdxTerm = (const char*)sqlite3_column_blob(pStmt, 1);
int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
- const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
int iIdxLeaf = sqlite3_column_int(pStmt, 2);
int bIdxDlidx = sqlite3_column_int(pStmt, 3);
- /* If the leaf in question has already been trimmed from the segment,
+ /* If the leaf in question has already been trimmed from the segment,
** ignore this b-tree entry. Otherwise, load it into memory. */
if( iIdxLeaf<pSeg->pgnoFirst ) continue;
iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
- pLeaf = fts5DataRead(p, iRow);
+ pLeaf = fts5LeafRead(p, iRow);
if( pLeaf==0 ) break;
/* Check that the leaf contains at least one term, and that it is equal
@@ -192364,11 +222316,11 @@ static void fts5IndexIntegrityCheckSegment(
iOff = fts5LeafFirstTermOff(pLeaf);
iRowidOff = fts5LeafFirstRowidOff(pLeaf);
- if( iRowidOff>=iOff ){
+ if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
}else{
iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
- res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
+ res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
if( res==0 ) res = nTerm - nIdxTerm;
if( res<0 ) p->rc = FTS5_CORRUPT;
}
@@ -192451,7 +222403,7 @@ static void fts5IndexIntegrityCheckSegment(
/*
-** Run internal checks to ensure that the FTS index (a) is internally
+** Run internal checks to ensure that the FTS index (a) is internally
** consistent and (b) contains entries for which the XOR of the checksums
** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
**
@@ -192473,7 +222425,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */
#endif
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
-
+
/* Load the FTS index structure */
pStruct = fts5StructureRead(p);
@@ -192495,7 +222447,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
**
** Two versions of the same checksum are calculated. The first (stack
** variable cksum2) based on entries extracted from the full-text index
- ** while doing a linear scan of each individual index in turn.
+ ** while doing a linear scan of each individual index in turn.
**
** As each term visited by the linear scans, a separate query for the
** same term is performed. cksum3 is calculated based on the entries
@@ -192597,12 +222549,12 @@ static void fts5DebugStructure(
for(iLvl=0; iLvl<p->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &p->aLevel[iLvl];
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf,
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf,
" {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg
);
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
);
}
@@ -192615,7 +222567,7 @@ static void fts5DebugStructure(
**
** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This
** function appends a human-readable representation of the same object
-** to the buffer passed as the second argument.
+** to the buffer passed as the second argument.
*/
static void fts5DecodeStructure(
int *pRc, /* IN/OUT: error code */
@@ -192638,9 +222590,9 @@ static void fts5DecodeStructure(
/*
** This is part of the fts5_decode() debugging aid.
**
-** Arguments pBlob/nBlob contain an "averages" record. This function
-** appends a human-readable representation of record to the buffer passed
-** as the second argument.
+** Arguments pBlob/nBlob contain an "averages" record. This function
+** appends a human-readable representation of record to the buffer passed
+** as the second argument.
*/
static void fts5DecodeAverages(
int *pRc, /* IN/OUT: error code */
@@ -192679,7 +222631,7 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
** The start of buffer (a/n) contains the start of a doclist. The doclist
** may or may not finish within the buffer. This function appends a text
** representation of the part of the doclist that is present to buffer
-** pBuf.
+** pBuf.
**
** The return value is the number of bytes read from the input buffer.
*/
@@ -192709,7 +222661,7 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
}
/*
-** This function is part of the fts5_decode() debugging function. It is
+** This function is part of the fts5_decode() debugging function. It is
** only ever used with detail=none tables.
**
** Buffer (pData/nData) contains a doclist in the format used by detail=none
@@ -192763,7 +222715,7 @@ static void fts5DecodeFunction(
u8 *a = 0;
Fts5Buffer s; /* Build up text to return here */
int rc = SQLITE_OK; /* Return code */
- int nSpace = 0;
+ sqlite3_int64 nSpace = 0;
int eDetailNone = (sqlite3_user_data(pCtx)!=0);
assert( nArg==2 );
@@ -192779,8 +222731,7 @@ static void fts5DecodeFunction(
nSpace = n + FTS5_DATA_ZERO_PADDING;
a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
if( a==0 ) goto decode_out;
- memcpy(a, aBlob, n);
-
+ if( n>0 ) memcpy(a, aBlob, n);
fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
@@ -192797,7 +222748,7 @@ static void fts5DecodeFunction(
lvl.iLeafPgno = iPgno;
for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){
- sqlite3Fts5BufferAppendPrintf(&rc, &s,
+ sqlite3Fts5BufferAppendPrintf(&rc, &s,
" %d(%lld)", lvl.iLeafPgno, lvl.iRowid
);
}
@@ -192875,6 +222826,9 @@ static void fts5DecodeFunction(
iPgidxOff = szLeaf = fts5GetU16(&a[2]);
if( iPgidxOff<n ){
fts5GetVarint32(&a[iPgidxOff], iTermOff);
+ }else if( iPgidxOff>n ){
+ rc = FTS5_CORRUPT;
+ goto decode_out;
}
}
@@ -192886,18 +222840,26 @@ static void fts5DecodeFunction(
}else{
iOff = szLeaf;
}
+ if( iOff>n ){
+ rc = FTS5_CORRUPT;
+ goto decode_out;
+ }
fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
/* Decode any more doclist data that appears on the page before the
** first term. */
nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff;
+ if( nDoclist+iOff>n ){
+ rc = FTS5_CORRUPT;
+ goto decode_out;
+ }
fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist);
- while( iPgidxOff<n ){
+ while( iPgidxOff<n && rc==SQLITE_OK ){
int bFirst = (iPgidxOff==szLeaf); /* True for first term on page */
int nByte; /* Bytes of data */
int iEnd;
-
+
iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nByte);
iPgidxPrev += nByte;
iOff = iPgidxPrev;
@@ -192908,12 +222870,24 @@ static void fts5DecodeFunction(
}else{
iEnd = szLeaf;
}
+ if( iEnd>szLeaf ){
+ rc = FTS5_CORRUPT;
+ break;
+ }
if( bFirst==0 ){
iOff += fts5GetVarint32(&a[iOff], nByte);
+ if( nByte>term.n ){
+ rc = FTS5_CORRUPT;
+ break;
+ }
term.n = nByte;
}
iOff += fts5GetVarint32(&a[iOff], nByte);
+ if( iOff+nByte>n ){
+ rc = FTS5_CORRUPT;
+ break;
+ }
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
iOff += nByte;
@@ -192925,7 +222899,7 @@ static void fts5DecodeFunction(
fts5BufferFree(&term);
}
-
+
decode_out:
sqlite3_free(a);
if( rc==SQLITE_OK ){
@@ -192953,7 +222927,7 @@ static void fts5RowidFunction(
i64 iRowid;
int segid, pgno;
if( nArg!=3 ){
- sqlite3_result_error(pCtx,
+ sqlite3_result_error(pCtx,
"should be: fts5_rowid('segment', segid, pgno))", -1
);
}else{
@@ -192963,7 +222937,7 @@ static void fts5RowidFunction(
sqlite3_result_int64(pCtx, iRowid);
}
}else{
- sqlite3_result_error(pCtx,
+ sqlite3_result_error(pCtx,
"first arg to fts5_rowid() must be 'segment'" , -1
);
}
@@ -192985,7 +222959,7 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(
- db, "fts5_decode_none", 2,
+ db, "fts5_decode_none", 2,
SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
);
}
@@ -193037,14 +223011,14 @@ SQLITE_API int sqlite3_fts5_may_be_corrupt = 1;
typedef struct Fts5Auxdata Fts5Auxdata;
typedef struct Fts5Auxiliary Fts5Auxiliary;
typedef struct Fts5Cursor Fts5Cursor;
+typedef struct Fts5FullTable Fts5FullTable;
typedef struct Fts5Sorter Fts5Sorter;
-typedef struct Fts5Table Fts5Table;
typedef struct Fts5TokenizerModule Fts5TokenizerModule;
/*
-** NOTES ON TRANSACTIONS:
+** NOTES ON TRANSACTIONS:
**
-** SQLite invokes the following virtual table methods as transactions are
+** SQLite invokes the following virtual table methods as transactions are
** opened and closed by the user:
**
** xBegin(): Start of a new transaction.
@@ -193053,7 +223027,7 @@ typedef struct Fts5TokenizerModule Fts5TokenizerModule;
** xRollback(): Rollback the transaction.
**
** Anything that is required as part of a commit that may fail is performed
-** in the xSync() callback. Current versions of SQLite ignore any errors
+** in the xSync() callback. Current versions of SQLite ignore any errors
** returned by xCommit().
**
** And as sub-transactions are opened/closed:
@@ -193062,9 +223036,9 @@ typedef struct Fts5TokenizerModule Fts5TokenizerModule;
** xRelease(int S): Commit and close savepoint S.
** xRollbackTo(int S): Rollback to start of savepoint S.
**
-** During a write-transaction the fts5_index.c module may cache some data
+** During a write-transaction the fts5_index.c module may cache some data
** in-memory. It is flushed to disk whenever xSync(), xRelease() or
-** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
+** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
** is called.
**
** Additionally, if SQLITE_DEBUG is defined, an instance of the following
@@ -193078,13 +223052,13 @@ struct Fts5TransactionState {
};
/*
-** A single object of this type is allocated when the FTS5 module is
+** A single object of this type is allocated when the FTS5 module is
** registered with a database handle. It is used to store pointers to
** all registered FTS5 extensions - tokenizers and auxiliary functions.
*/
struct Fts5Global {
fts5_api api; /* User visible part of object (see fts5.h) */
- sqlite3 *db; /* Associated database connection */
+ sqlite3 *db; /* Associated database connection */
i64 iNextId; /* Used to allocate unique cursor ids */
Fts5Auxiliary *pAux; /* First in list of all aux. functions */
Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
@@ -193119,13 +223093,8 @@ struct Fts5TokenizerModule {
Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
};
-/*
-** Virtual-table object.
-*/
-struct Fts5Table {
- sqlite3_vtab base; /* Base class used by SQLite core */
- Fts5Config *pConfig; /* Virtual table configuration */
- Fts5Index *pIndex; /* Full-text index */
+struct Fts5FullTable {
+ Fts5Table p; /* Public class members from fts5Int.h */
Fts5Storage *pStorage; /* Document store */
Fts5Global *pGlobal; /* Global (connection wide) data */
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
@@ -193145,7 +223114,7 @@ struct Fts5MatchPhrase {
**
** aIdx[]:
** There is one entry in the aIdx[] array for each phrase in the query,
-** the value of which is the offset within aPoslist[] following the last
+** the value of which is the offset within aPoslist[] following the last
** byte of the position list for the corresponding phrase.
*/
struct Fts5Sorter {
@@ -193161,8 +223130,8 @@ struct Fts5Sorter {
** Virtual-table cursor object.
**
** iSpecial:
-** If this is a 'special' query (refer to function fts5SpecialMatch()),
-** then this variable contains the result of the query.
+** If this is a 'special' query (refer to function fts5SpecialMatch()),
+** then this variable contains the result of the query.
**
** iFirstRowid, iLastRowid:
** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
@@ -193213,7 +223182,7 @@ struct Fts5Cursor {
};
/*
-** Bits that make up the "idxNum" parameter passed indirectly by
+** Bits that make up the "idxNum" parameter passed indirectly by
** xBestIndex() to xFilter().
*/
#define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
@@ -193263,7 +223232,7 @@ struct Fts5Auxdata {
#define FTS5_SAVEPOINT 5
#define FTS5_RELEASE 6
#define FTS5_ROLLBACKTO 7
-static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
+static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
switch( op ){
case FTS5_BEGIN:
assert( p->ts.eState==0 );
@@ -193289,10 +223258,10 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
case FTS5_SAVEPOINT:
assert( p->ts.eState==1 );
assert( iSavepoint>=0 );
- assert( iSavepoint>p->ts.iSavepoint );
+ assert( iSavepoint>=p->ts.iSavepoint );
p->ts.iSavepoint = iSavepoint;
break;
-
+
case FTS5_RELEASE:
assert( p->ts.eState==1 );
assert( iSavepoint>=0 );
@@ -193302,8 +223271,11 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
case FTS5_ROLLBACKTO:
assert( p->ts.eState==1 );
- assert( iSavepoint>=0 );
- assert( iSavepoint<=p->ts.iSavepoint );
+ assert( iSavepoint>=-1 );
+ /* The following assert() can fail if another vtab strikes an error
+ ** within an xSavepoint() call then SQLite calls xRollbackTo() - without
+ ** having called xSavepoint() on this vtab. */
+ /* assert( iSavepoint<=p->ts.iSavepoint ); */
p->ts.iSavepoint = iSavepoint;
break;
}
@@ -193315,18 +223287,18 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
/*
** Return true if pTab is a contentless table.
*/
-static int fts5IsContentless(Fts5Table *pTab){
- return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
+static int fts5IsContentless(Fts5FullTable *pTab){
+ return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
}
/*
-** Delete a virtual table handle allocated by fts5InitVtab().
+** Delete a virtual table handle allocated by fts5InitVtab().
*/
-static void fts5FreeVtab(Fts5Table *pTab){
+static void fts5FreeVtab(Fts5FullTable *pTab){
if( pTab ){
- sqlite3Fts5IndexClose(pTab->pIndex);
+ sqlite3Fts5IndexClose(pTab->p.pIndex);
sqlite3Fts5StorageClose(pTab->pStorage);
- sqlite3Fts5ConfigFree(pTab->pConfig);
+ sqlite3Fts5ConfigFree(pTab->p.pConfig);
sqlite3_free(pTab);
}
}
@@ -193335,7 +223307,7 @@ static void fts5FreeVtab(Fts5Table *pTab){
** The xDisconnect() virtual table method.
*/
static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
- fts5FreeVtab((Fts5Table*)pVtab);
+ fts5FreeVtab((Fts5FullTable*)pVtab);
return SQLITE_OK;
}
@@ -193346,7 +223318,7 @@ static int fts5DestroyMethod(sqlite3_vtab *pVtab){
Fts5Table *pTab = (Fts5Table*)pVtab;
int rc = sqlite3Fts5DropAll(pTab->pConfig);
if( rc==SQLITE_OK ){
- fts5FreeVtab((Fts5Table*)pVtab);
+ fts5FreeVtab((Fts5FullTable*)pVtab);
}
return rc;
}
@@ -193375,28 +223347,28 @@ static int fts5InitVtab(
const char **azConfig = (const char**)argv;
int rc = SQLITE_OK; /* Return code */
Fts5Config *pConfig = 0; /* Results of parsing argc/argv */
- Fts5Table *pTab = 0; /* New virtual table object */
+ Fts5FullTable *pTab = 0; /* New virtual table object */
/* Allocate the new vtab object and parse the configuration */
- pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
+ pTab = (Fts5FullTable*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5FullTable));
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
}
if( rc==SQLITE_OK ){
- pTab->pConfig = pConfig;
+ pTab->p.pConfig = pConfig;
pTab->pGlobal = pGlobal;
}
/* Open the index sub-system */
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr);
+ rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->p.pIndex, pzErr);
}
/* Open the storage sub-system */
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageOpen(
- pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr
+ pConfig, pTab->p.pIndex, bCreate, &pTab->pStorage, pzErr
);
}
@@ -193409,8 +223381,8 @@ static int fts5InitVtab(
if( rc==SQLITE_OK ){
assert( pConfig->pzErrmsg==0 );
pConfig->pzErrmsg = pzErr;
- rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
- sqlite3Fts5IndexRollback(pTab->pIndex);
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ sqlite3Fts5IndexRollback(pTab->p.pIndex);
pConfig->pzErrmsg = 0;
}
@@ -193476,20 +223448,42 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
}
/*
-** Implementation of the xBestIndex method for FTS5 tables. Within the
+** Implementation of the xBestIndex method for FTS5 tables. Within the
** WHERE constraint, it searches for the following:
**
-** 1. A MATCH constraint against the special column.
+** 1. A MATCH constraint against the table column.
** 2. A MATCH constraint against the "rank" column.
-** 3. An == constraint against the rowid column.
-** 4. A < or <= constraint against the rowid column.
-** 5. A > or >= constraint against the rowid column.
+** 3. A MATCH constraint against some other column.
+** 4. An == constraint against the rowid column.
+** 5. A < or <= constraint against the rowid column.
+** 6. A > or >= constraint against the rowid column.
**
-** Within the ORDER BY, either:
+** Within the ORDER BY, the following are supported:
**
** 5. ORDER BY rank [ASC|DESC]
** 6. ORDER BY rowid [ASC|DESC]
**
+** Information for the xFilter call is passed via both the idxNum and
+** idxStr variables. Specifically, idxNum is a bitmask of the following
+** flags used to encode the ORDER BY clause:
+**
+** FTS5_BI_ORDER_RANK
+** FTS5_BI_ORDER_ROWID
+** FTS5_BI_ORDER_DESC
+**
+** idxStr is used to encode data from the WHERE clause. For each argument
+** passed to the xFilter method, the following is appended to idxStr:
+**
+** Match against table column: "m"
+** Match against rank column: "r"
+** Match against other column: "<column-number>"
+** Equality constraint against the rowid: "="
+** A < or <= against the rowid: "<"
+** A > or >= against the rowid: ">"
+**
+** This function ensures that there is at most one "r" or "=". And that if
+** there exists an "=" then there is no "<" or ">".
+**
** Costs are assigned as follows:
**
** a) If an unusable MATCH operator is present in the WHERE clause, the
@@ -193515,58 +223509,106 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
Fts5Table *pTab = (Fts5Table*)pVTab;
Fts5Config *pConfig = pTab->pConfig;
+ const int nCol = pConfig->nCol;
int idxFlags = 0; /* Parameter passed through to xFilter() */
- int bHasMatch;
- int iNext;
int i;
- struct Constraint {
- int op; /* Mask against sqlite3_index_constraint.op */
- int fts5op; /* FTS5 mask for idxFlags */
- int iCol; /* 0==rowid, 1==tbl, 2==rank */
- int omit; /* True to omit this if found */
- int iConsIndex; /* Index in pInfo->aConstraint[] */
- } aConstraint[] = {
- {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
- FTS5_BI_MATCH, 1, 1, -1},
- {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ,
- FTS5_BI_RANK, 2, 1, -1},
- {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1},
- {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE,
- FTS5_BI_ROWID_LE, 0, 0, -1},
- {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE,
- FTS5_BI_ROWID_GE, 0, 0, -1},
- };
+ char *idxStr;
+ int iIdxStr = 0;
+ int iCons = 0;
+
+ int bSeenEq = 0;
+ int bSeenGt = 0;
+ int bSeenLt = 0;
+ int bSeenMatch = 0;
+ int bSeenRank = 0;
+
+
+ assert( SQLITE_INDEX_CONSTRAINT_EQ<SQLITE_INDEX_CONSTRAINT_MATCH );
+ assert( SQLITE_INDEX_CONSTRAINT_GT<SQLITE_INDEX_CONSTRAINT_MATCH );
+ assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH );
+ assert( SQLITE_INDEX_CONSTRAINT_GE<SQLITE_INDEX_CONSTRAINT_MATCH );
+ assert( SQLITE_INDEX_CONSTRAINT_LE<SQLITE_INDEX_CONSTRAINT_MATCH );
+
+ if( pConfig->bLock ){
+ pTab->base.zErrMsg = sqlite3_mprintf(
+ "recursively defined fts5 content table"
+ );
+ return SQLITE_ERROR;
+ }
- int aColMap[3];
- aColMap[0] = -1;
- aColMap[1] = pConfig->nCol;
- aColMap[2] = pConfig->nCol+1;
+ idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 6 + 1);
+ if( idxStr==0 ) return SQLITE_NOMEM;
+ pInfo->idxStr = idxStr;
+ pInfo->needToFreeIdxStr = 1;
- /* Set idxFlags flags for all WHERE clause terms that will be used. */
for(i=0; i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
- int j;
- for(j=0; j<ArraySize(aConstraint); j++){
- struct Constraint *pC = &aConstraint[j];
- if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
- if( p->usable ){
- pC->iConsIndex = i;
- idxFlags |= pC->fts5op;
- }else if( j==0 ){
- /* As there exists an unusable MATCH constraint this is an
- ** unusable plan. Set a prohibitively high cost. */
- pInfo->estimatedCost = 1e50;
- return SQLITE_OK;
+ int iCol = p->iColumn;
+ if( p->op==SQLITE_INDEX_CONSTRAINT_MATCH
+ || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol>=nCol)
+ ){
+ /* A MATCH operator or equivalent */
+ if( p->usable==0 || iCol<0 ){
+ /* As there exists an unusable MATCH constraint this is an
+ ** unusable plan. Set a prohibitively high cost. */
+ pInfo->estimatedCost = 1e50;
+ assert( iIdxStr < pInfo->nConstraint*6 + 1 );
+ idxStr[iIdxStr] = 0;
+ return SQLITE_OK;
+ }else{
+ if( iCol==nCol+1 ){
+ if( bSeenRank ) continue;
+ idxStr[iIdxStr++] = 'r';
+ bSeenRank = 1;
+ }else{
+ bSeenMatch = 1;
+ idxStr[iIdxStr++] = 'm';
+ if( iCol<nCol ){
+ sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
+ idxStr += strlen(&idxStr[iIdxStr]);
+ assert( idxStr[iIdxStr]=='\0' );
+ }
+ }
+ pInfo->aConstraintUsage[i].argvIndex = ++iCons;
+ pInfo->aConstraintUsage[i].omit = 1;
+ }
+ }
+ else if( p->usable && bSeenEq==0
+ && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0
+ ){
+ idxStr[iIdxStr++] = '=';
+ bSeenEq = 1;
+ pInfo->aConstraintUsage[i].argvIndex = ++iCons;
+ }
+ }
+
+ if( bSeenEq==0 ){
+ for(i=0; i<pInfo->nConstraint; i++){
+ struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
+ if( p->iColumn<0 && p->usable ){
+ int op = p->op;
+ if( op==SQLITE_INDEX_CONSTRAINT_LT || op==SQLITE_INDEX_CONSTRAINT_LE ){
+ if( bSeenLt ) continue;
+ idxStr[iIdxStr++] = '<';
+ pInfo->aConstraintUsage[i].argvIndex = ++iCons;
+ bSeenLt = 1;
+ }else
+ if( op==SQLITE_INDEX_CONSTRAINT_GT || op==SQLITE_INDEX_CONSTRAINT_GE ){
+ if( bSeenGt ) continue;
+ idxStr[iIdxStr++] = '>';
+ pInfo->aConstraintUsage[i].argvIndex = ++iCons;
+ bSeenGt = 1;
}
}
}
}
+ idxStr[iIdxStr] = '\0';
/* Set idxFlags flags for the ORDER BY clause */
if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn;
- if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){
+ if( iSort==(pConfig->nCol+1) && bSeenMatch ){
idxFlags |= FTS5_BI_ORDER_RANK;
}else if( iSort==-1 ){
idxFlags |= FTS5_BI_ORDER_ROWID;
@@ -193580,33 +223622,22 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
/* Calculate the estimated cost based on the flags set in idxFlags. */
- bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH);
- if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){
- pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0;
- if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo);
- }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
- pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0;
- }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
- pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0;
+ if( bSeenEq ){
+ pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0;
+ if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
+ }else if( bSeenLt && bSeenGt ){
+ pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0;
+ }else if( bSeenLt || bSeenGt ){
+ pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0;
}else{
- pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0;
- }
-
- /* Assign argvIndex values to each constraint in use. */
- iNext = 1;
- for(i=0; i<ArraySize(aConstraint); i++){
- struct Constraint *pC = &aConstraint[i];
- if( pC->iConsIndex>=0 ){
- pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
- pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit;
- }
+ pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0;
}
pInfo->idxNum = idxFlags;
return SQLITE_OK;
}
-static int fts5NewTransaction(Fts5Table *pTab){
+static int fts5NewTransaction(Fts5FullTable *pTab){
Fts5Cursor *pCsr;
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
@@ -193618,19 +223649,19 @@ static int fts5NewTransaction(Fts5Table *pTab){
** Implementation of xOpen method.
*/
static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
- Fts5Table *pTab = (Fts5Table*)pVTab;
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVTab;
+ Fts5Config *pConfig = pTab->p.pConfig;
Fts5Cursor *pCsr = 0; /* New cursor object */
- int nByte; /* Bytes of space to allocate */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
int rc; /* Return code */
rc = fts5NewTransaction(pTab);
if( rc==SQLITE_OK ){
nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
- pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
+ pCsr = (Fts5Cursor*)sqlite3_malloc64(nByte);
if( pCsr ){
Fts5Global *pGlobal = pTab->pGlobal;
- memset(pCsr, 0, nByte);
+ memset(pCsr, 0, (size_t)nByte);
pCsr->aColumnSize = (int*)&pCsr[1];
pCsr->pNext = pGlobal->pCsr;
pGlobal->pCsr = pCsr;
@@ -193652,20 +223683,20 @@ static int fts5StmtType(Fts5Cursor *pCsr){
/*
** This function is called after the cursor passed as the only argument
-** is moved to point at a different row. It clears all cached data
+** is moved to point at a different row. It clears all cached data
** specific to the previous row stored by the cursor object.
*/
static void fts5CsrNewrow(Fts5Cursor *pCsr){
- CsrFlagSet(pCsr,
- FTS5CSR_REQUIRE_CONTENT
- | FTS5CSR_REQUIRE_DOCSIZE
- | FTS5CSR_REQUIRE_INST
- | FTS5CSR_REQUIRE_POSLIST
+ CsrFlagSet(pCsr,
+ FTS5CSR_REQUIRE_CONTENT
+ | FTS5CSR_REQUIRE_DOCSIZE
+ | FTS5CSR_REQUIRE_INST
+ | FTS5CSR_REQUIRE_POSLIST
);
}
static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
Fts5Auxdata *pData;
Fts5Auxdata *pNext;
@@ -193699,6 +223730,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
sqlite3_free(pCsr->zRankArgs);
}
+ sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
}
@@ -193709,7 +223741,7 @@ static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
*/
static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
if( pCursor ){
- Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
Fts5Cursor **pp;
@@ -193763,14 +223795,14 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
/*
-** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
+** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
** open on table pTab.
*/
-static void fts5TripCursors(Fts5Table *pTab){
+static void fts5TripCursors(Fts5FullTable *pTab){
Fts5Cursor *pCsr;
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
if( pCsr->ePlan==FTS5_PLAN_MATCH
- && pCsr->base.pVtab==(sqlite3_vtab*)pTab
+ && pCsr->base.pVtab==(sqlite3_vtab*)pTab
){
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
}
@@ -193779,25 +223811,25 @@ static void fts5TripCursors(Fts5Table *pTab){
/*
** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
-** argument, close and reopen all Fts5IndexIter iterators that the cursor
+** argument, close and reopen all Fts5IndexIter iterators that the cursor
** is using. Then attempt to move the cursor to a rowid equal to or laster
-** (in the cursors sort order - ASC or DESC) than the current rowid.
+** (in the cursors sort order - ASC or DESC) than the current rowid.
**
** If the new rowid is not equal to the old, set output parameter *pbSkip
** to 1 before returning. Otherwise, leave it unchanged.
**
-** Return SQLITE_OK if successful or if no reseek was required, or an
+** Return SQLITE_OK if successful or if no reseek was required, or an
** error code if an error occurred.
*/
static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
int rc = SQLITE_OK;
assert( *pbSkip==0 );
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
int bDesc = pCsr->bDesc;
i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
- rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
+ rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->p.pIndex, iRowid, bDesc);
if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
*pbSkip = 1;
}
@@ -193814,7 +223846,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
/*
-** Advance the cursor to the next row in the table that matches the
+** Advance the cursor to the next row in the table that matches the
** search criteria.
**
** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
@@ -193826,7 +223858,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
int rc;
assert( (pCsr->ePlan<3)==
- (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
+ (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
);
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
@@ -193843,31 +223875,40 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
rc = SQLITE_OK;
break;
}
-
+
case FTS5_PLAN_SORTED_MATCH: {
rc = fts5SorterNext(pCsr);
break;
}
-
- default:
+
+ default: {
+ Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
+ pConfig->bLock++;
rc = sqlite3_step(pCsr->pStmt);
+ pConfig->bLock--;
if( rc!=SQLITE_ROW ){
CsrFlagSet(pCsr, FTS5CSR_EOF);
rc = sqlite3_reset(pCsr->pStmt);
+ if( rc!=SQLITE_OK ){
+ pCursor->pVtab->zErrMsg = sqlite3_mprintf(
+ "%s", sqlite3_errmsg(pConfig->db)
+ );
+ }
}else{
rc = SQLITE_OK;
}
break;
+ }
}
}
-
+
return rc;
}
static int fts5PrepareStatement(
sqlite3_stmt **ppStmt,
- Fts5Config *pConfig,
+ Fts5Config *pConfig,
const char *zFmt,
...
){
@@ -193879,9 +223920,10 @@ static int fts5PrepareStatement(
va_start(ap, zFmt);
zSql = sqlite3_vmprintf(zFmt, ap);
if( zSql==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM;
}else{
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pRet, 0);
+ rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
+ SQLITE_PREPARE_PERSISTENT, &pRet, 0);
if( rc!=SQLITE_OK ){
*pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
}
@@ -193891,33 +223933,37 @@ static int fts5PrepareStatement(
va_end(ap);
*ppStmt = pRet;
return rc;
-}
+}
-static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
- Fts5Config *pConfig = pTab->pConfig;
+static int fts5CursorFirstSorted(
+ Fts5FullTable *pTab,
+ Fts5Cursor *pCsr,
+ int bDesc
+){
+ Fts5Config *pConfig = pTab->p.pConfig;
Fts5Sorter *pSorter;
int nPhrase;
- int nByte;
+ sqlite3_int64 nByte;
int rc;
const char *zRank = pCsr->zRank;
const char *zRankArgs = pCsr->zRankArgs;
-
+
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
- pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
+ pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
if( pSorter==0 ) return SQLITE_NOMEM;
- memset(pSorter, 0, nByte);
+ memset(pSorter, 0, (size_t)nByte);
pSorter->nIdx = nPhrase;
/* TODO: It would be better to have some system for reusing statement
** handles here, rather than preparing a new one for each query. But that
** is not possible as SQLite reference counts the virtual table objects.
- ** And since the statement required here reads from this very virtual
+ ** And since the statement required here reads from this very virtual
** table, saving it creates a circular reference.
**
** If SQLite a built-in statement cache, this wouldn't be a problem. */
rc = fts5PrepareStatement(&pSorter->pStmt, pConfig,
- "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
+ "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(\"%w\"%s%s) %s",
pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
(zRankArgs ? ", " : ""),
(zRankArgs ? zRankArgs : ""),
@@ -193941,10 +223987,10 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
return rc;
}
-static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
+static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
int rc;
Fts5Expr *pExpr = pCsr->pExpr;
- rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc);
+ rc = sqlite3Fts5ExprFirst(pExpr, pTab->p.pIndex, pCsr->iFirstRowid, bDesc);
if( sqlite3Fts5ExprEof(pExpr) ){
CsrFlagSet(pCsr, FTS5CSR_EOF);
}
@@ -193959,8 +224005,8 @@ static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
** parameters.
*/
static int fts5SpecialMatch(
- Fts5Table *pTab,
- Fts5Cursor *pCsr,
+ Fts5FullTable *pTab,
+ Fts5Cursor *pCsr,
const char *zQuery
){
int rc = SQLITE_OK; /* Return code */
@@ -193970,18 +224016,18 @@ static int fts5SpecialMatch(
while( z[0]==' ' ) z++;
for(n=0; z[n] && z[n]!=' '; n++);
- assert( pTab->base.zErrMsg==0 );
+ assert( pTab->p.base.zErrMsg==0 );
pCsr->ePlan = FTS5_PLAN_SPECIAL;
- if( 0==sqlite3_strnicmp("reads", z, n) ){
- pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex);
+ if( n==5 && 0==sqlite3_strnicmp("reads", z, n) ){
+ pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex);
}
- else if( 0==sqlite3_strnicmp("id", z, n) ){
+ else if( n==2 && 0==sqlite3_strnicmp("id", z, n) ){
pCsr->iSpecial = pCsr->iCsrId;
}
else{
/* An unrecognized directive. Return an error message. */
- pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
+ pTab->p.base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
rc = SQLITE_ERROR;
}
@@ -193993,7 +224039,7 @@ static int fts5SpecialMatch(
** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
** structure. Otherwise, if no such function exists, return NULL.
*/
-static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
+static Fts5Auxiliary *fts5FindAuxiliary(Fts5FullTable *pTab, const char *zName){
Fts5Auxiliary *pAux;
for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
@@ -194006,8 +224052,8 @@ static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
static int fts5FindRankFunction(Fts5Cursor *pCsr){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
+ Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
Fts5Auxiliary *pAux = 0;
const char *zRank = pCsr->zRank;
@@ -194017,12 +224063,13 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
if( zSql ){
sqlite3_stmt *pStmt = 0;
- rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0);
+ rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
+ SQLITE_PREPARE_PERSISTENT, &pStmt, 0);
sqlite3_free(zSql);
assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
- int nByte;
+ sqlite3_int64 nByte;
pCsr->nRankArg = sqlite3_column_count(pStmt);
nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
@@ -194044,8 +224091,8 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
if( rc==SQLITE_OK ){
pAux = fts5FindAuxiliary(pTab, zRank);
if( pAux==0 ){
- assert( pTab->base.zErrMsg==0 );
- pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
+ assert( pTab->p.base.zErrMsg==0 );
+ pTab->p.base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
rc = SQLITE_ERROR;
}
}
@@ -194057,7 +224104,7 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
static int fts5CursorParseRank(
Fts5Config *pConfig,
- Fts5Cursor *pCsr,
+ Fts5Cursor *pCsr,
sqlite3_value *pRank
){
int rc = SQLITE_OK;
@@ -194106,7 +224153,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
** This is the xFilter interface for the virtual table. See
** the virtual table xFilter method documentation for additional
** information.
-**
+**
** There are three possible query strategies:
**
** 1. Full-text search using a MATCH operator.
@@ -194116,26 +224163,32 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
static int fts5FilterMethod(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, /* Strategy index */
- const char *zUnused, /* Unused */
+ const char *idxStr, /* Unused */
int nVal, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
- Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
+ Fts5Config *pConfig = pTab->p.pConfig;
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
int rc = SQLITE_OK; /* Error code */
- int iVal = 0; /* Counter for apVal[] */
int bDesc; /* True if ORDER BY [rank|rowid] DESC */
int bOrderByRank; /* True if ORDER BY rank */
- sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */
sqlite3_value *pRank = 0; /* rank MATCH ? expression (or NULL) */
sqlite3_value *pRowidEq = 0; /* rowid = ? expression (or NULL) */
sqlite3_value *pRowidLe = 0; /* rowid <= ? expression (or NULL) */
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
+ int iCol; /* Column on LHS of MATCH operator */
char **pzErrmsg = pConfig->pzErrmsg;
+ int i;
+ int iIdxStr = 0;
+ Fts5Expr *pExpr = 0;
- UNUSED_PARAM(zUnused);
- UNUSED_PARAM(nVal);
+ if( pConfig->bLock ){
+ pTab->p.base.zErrMsg = sqlite3_mprintf(
+ "recursively defined fts5 content table"
+ );
+ return SQLITE_ERROR;
+ }
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
@@ -194148,25 +224201,64 @@ static int fts5FilterMethod(
assert( pCsr->pRank==0 );
assert( pCsr->zRank==0 );
assert( pCsr->zRankArgs==0 );
+ assert( pTab->pSortCsr==0 || nVal==0 );
- assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
- pConfig->pzErrmsg = &pTab->base.zErrMsg;
+ assert( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg );
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
- /* Decode the arguments passed through to this function.
- **
- ** Note: The following set of if(...) statements must be in the same
- ** order as the corresponding entries in the struct at the top of
- ** fts5BestIndexMethod(). */
- if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
- if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
- assert( iVal==nVal );
+ /* Decode the arguments passed through to this function. */
+ for(i=0; i<nVal; i++){
+ switch( idxStr[iIdxStr++] ){
+ case 'r':
+ pRank = apVal[i];
+ break;
+ case 'm': {
+ const char *zText = (const char*)sqlite3_value_text(apVal[i]);
+ if( zText==0 ) zText = "";
+
+ if( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ){
+ iCol = 0;
+ do{
+ iCol = iCol*10 + (idxStr[iIdxStr]-'0');
+ iIdxStr++;
+ }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
+ }else{
+ iCol = pConfig->nCol;
+ }
+
+ if( zText[0]=='*' ){
+ /* The user has issued a query of the form "MATCH '*...'". This
+ ** indicates that the MATCH expression is not a full text query,
+ ** but a request for an internal parameter. */
+ rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
+ goto filter_out;
+ }else{
+ char **pzErr = &pTab->p.base.zErrMsg;
+ rc = sqlite3Fts5ExprNew(pConfig, iCol, zText, &pExpr, pzErr);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
+ pExpr = 0;
+ }
+ if( rc!=SQLITE_OK ) goto filter_out;
+ }
+
+ break;
+ }
+ case '=':
+ pRowidEq = apVal[i];
+ break;
+ case '<':
+ pRowidLe = apVal[i];
+ break;
+ default: assert( idxStr[iIdxStr-1]=='>' );
+ pRowidGe = apVal[i];
+ break;
+ }
+ }
bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
- /* Set the cursor upper and lower rowid limits. Only some strategies
+ /* Set the cursor upper and lower rowid limits. Only some strategies
** actually use them. This is ok, as the xBestIndex() method leaves the
** sqlite3_index_constraint.omit flag clear for range constraints
** on the rowid field. */
@@ -194182,42 +224274,35 @@ static int fts5FilterMethod(
}
if( pTab->pSortCsr ){
- /* If pSortCsr is non-NULL, then this call is being made as part of
+ /* If pSortCsr is non-NULL, then this call is being made as part of
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
- ** return results to the user for this query. The current cursor
- ** (pCursor) is used to execute the query issued by function
+ ** return results to the user for this query. The current cursor
+ ** (pCursor) is used to execute the query issued by function
** fts5CursorFirstSorted() above. */
assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
- assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 );
+ assert( nVal==0 && bOrderByRank==0 && bDesc==0 );
assert( pCsr->iLastRowid==LARGEST_INT64 );
assert( pCsr->iFirstRowid==SMALLEST_INT64 );
+ if( pTab->pSortCsr->bDesc ){
+ pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid;
+ pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid;
+ }else{
+ pCsr->iLastRowid = pTab->pSortCsr->iLastRowid;
+ pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid;
+ }
pCsr->ePlan = FTS5_PLAN_SOURCE;
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
- }else if( pMatch ){
- const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
- if( zExpr==0 ) zExpr = "";
-
+ }else if( pCsr->pExpr ){
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
if( rc==SQLITE_OK ){
- if( zExpr[0]=='*' ){
- /* The user has issued a query of the form "MATCH '*...'". This
- ** indicates that the MATCH expression is not a full text query,
- ** but a request for an internal parameter. */
- rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
+ if( bOrderByRank ){
+ pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
+ rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
}else{
- char **pzErr = &pTab->base.zErrMsg;
- rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
- if( rc==SQLITE_OK ){
- if( bOrderByRank ){
- pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
- rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
- }else{
- pCsr->ePlan = FTS5_PLAN_MATCH;
- rc = fts5CursorFirst(pTab, pCsr, bDesc);
- }
- }
+ pCsr->ePlan = FTS5_PLAN_MATCH;
+ rc = fts5CursorFirst(pTab, pCsr, bDesc);
}
}
}else if( pConfig->zContent==0 ){
@@ -194230,11 +224315,11 @@ static int fts5FilterMethod(
** by rowid (ePlan==FTS5_PLAN_ROWID). */
pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
rc = sqlite3Fts5StorageStmt(
- pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg
+ pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
);
if( rc==SQLITE_OK ){
if( pCsr->ePlan==FTS5_PLAN_ROWID ){
- sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
+ sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq);
}else{
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
@@ -194243,12 +224328,14 @@ static int fts5FilterMethod(
}
}
+ filter_out:
+ sqlite3Fts5ExprFree(pExpr);
pConfig->pzErrmsg = pzErrmsg;
return rc;
}
-/*
-** This is the xEof method of the virtual table. SQLite calls this
+/*
+** This is the xEof method of the virtual table. SQLite calls this
** routine to find out if it has reached the end of a result set.
*/
static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
@@ -194260,9 +224347,9 @@ static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
** Return the rowid that the cursor currently points to.
*/
static i64 fts5CursorRowid(Fts5Cursor *pCsr){
- assert( pCsr->ePlan==FTS5_PLAN_MATCH
- || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
- || pCsr->ePlan==FTS5_PLAN_SOURCE
+ assert( pCsr->ePlan==FTS5_PLAN_MATCH
+ || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
+ || pCsr->ePlan==FTS5_PLAN_SOURCE
);
if( pCsr->pSorter ){
return pCsr->pSorter->iRowid;
@@ -194271,7 +224358,7 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
}
}
-/*
+/*
** This is the xRowid method. The SQLite core calls this routine to
** retrieve the rowid for the current row of the result set. fts5
** exposes %_content.rowid as the rowid for the virtual table. The
@@ -194280,7 +224367,7 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
int ePlan = pCsr->ePlan;
-
+
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
switch( ePlan ){
case FTS5_PLAN_SPECIAL:
@@ -194311,22 +224398,25 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
int rc = SQLITE_OK;
- /* If the cursor does not yet have a statement handle, obtain one now. */
+ /* If the cursor does not yet have a statement handle, obtain one now. */
if( pCsr->pStmt==0 ){
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
int eStmt = fts5StmtType(pCsr);
rc = sqlite3Fts5StorageStmt(
- pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0)
+ pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->p.base.zErrMsg:0)
);
- assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 );
+ assert( rc!=SQLITE_OK || pTab->p.base.zErrMsg==0 );
assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
}
if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
assert( pCsr->pExpr );
sqlite3_reset(pCsr->pStmt);
sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
+ pTab->pConfig->bLock++;
rc = sqlite3_step(pCsr->pStmt);
+ pTab->pConfig->bLock--;
if( rc==SQLITE_ROW ){
rc = SQLITE_OK;
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
@@ -194334,17 +224424,21 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK ){
rc = FTS5_CORRUPT;
+ }else if( pTab->pConfig->pzErrmsg ){
+ *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
+ "%s", sqlite3_errmsg(pTab->pConfig->db)
+ );
}
}
}
return rc;
}
-static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
+static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
va_list ap; /* ... printf arguments */
va_start(ap, zFormat);
- assert( p->base.zErrMsg==0 );
- p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
+ assert( p->p.base.zErrMsg==0 );
+ p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
}
@@ -194355,7 +224449,7 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
** INSERT INTO fts(fts) VALUES($pCmd)
** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
**
-** Argument pVal is the value assigned to column "fts" by the INSERT
+** Argument pVal is the value assigned to column "fts" by the INSERT
** statement. This function returns SQLITE_OK if successful, or an SQLite
** error code if an error occurs.
**
@@ -194364,17 +224458,17 @@ static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
** more commands are added to this function.
*/
static int fts5SpecialInsert(
- Fts5Table *pTab, /* Fts5 table object */
+ Fts5FullTable *pTab, /* Fts5 table object */
const char *zCmd, /* Text inserted into table-name column */
sqlite3_value *pVal /* Value inserted into rank column */
){
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
int bError = 0;
if( 0==sqlite3_stricmp("delete-all", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
- fts5SetVtabError(pTab,
+ fts5SetVtabError(pTab,
"'delete-all' may only be used with a "
"contentless or external content fts5 table"
);
@@ -194384,7 +224478,7 @@ static int fts5SpecialInsert(
}
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NONE ){
- fts5SetVtabError(pTab,
+ fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
);
rc = SQLITE_ERROR;
@@ -194403,9 +224497,9 @@ static int fts5SpecialInsert(
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
#endif
}else{
- rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
+ rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
}
if( rc==SQLITE_OK ){
if( bError ){
@@ -194419,7 +224513,7 @@ static int fts5SpecialInsert(
}
static int fts5SpecialDelete(
- Fts5Table *pTab,
+ Fts5FullTable *pTab,
sqlite3_value **apVal
){
int rc = SQLITE_OK;
@@ -194432,9 +224526,9 @@ static int fts5SpecialDelete(
}
static void fts5StorageInsert(
- int *pRc,
- Fts5Table *pTab,
- sqlite3_value **apVal,
+ int *pRc,
+ Fts5FullTable *pTab,
+ sqlite3_value **apVal,
i64 *piRowid
){
int rc = *pRc;
@@ -194447,13 +224541,13 @@ static void fts5StorageInsert(
*pRc = rc;
}
-/*
-** This function is the implementation of the xUpdate callback used by
+/*
+** This function is the implementation of the xUpdate callback used by
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
** inserted, updated or deleted.
**
** A delete specifies a single argument - the rowid of the row to remove.
-**
+**
** Update and insert operations pass:
**
** 1. The "old" rowid, or NULL.
@@ -194467,8 +224561,8 @@ static int fts5UpdateMethod(
sqlite3_value **apVal, /* Array of arguments */
sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */
){
- Fts5Table *pTab = (Fts5Table*)pVtab;
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
@@ -194477,24 +224571,23 @@ static int fts5UpdateMethod(
assert( pVtab->zErrMsg==0 );
assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
- assert( nArg==1
- || sqlite3_value_type(apVal[1])==SQLITE_INTEGER
- || sqlite3_value_type(apVal[1])==SQLITE_NULL
+ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER
+ || sqlite3_value_type(apVal[0])==SQLITE_NULL
);
- assert( pTab->pConfig->pzErrmsg==0 );
- pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
+ assert( pTab->p.pConfig->pzErrmsg==0 );
+ pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
/* Put any active cursors into REQUIRE_SEEK state. */
fts5TripCursors(pTab);
eType0 = sqlite3_value_type(apVal[0]);
- if( eType0==SQLITE_NULL
- && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
+ if( eType0==SQLITE_NULL
+ && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
){
/* A "special" INSERT op. These are handled separately. */
const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL
- && 0==sqlite3_stricmp("delete", z)
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
+ && 0==sqlite3_stricmp("delete", z)
){
rc = fts5SpecialDelete(pTab, apVal);
}else{
@@ -194502,7 +224595,7 @@ static int fts5UpdateMethod(
}
}else{
/* A regular INSERT, UPDATE or DELETE statement. The trick here is that
- ** any conflict on the rowid value must be detected before any
+ ** any conflict on the rowid value must be detected before any
** modifications are made to the database file. There are 4 cases:
**
** 1) DELETE
@@ -194523,8 +224616,8 @@ static int fts5UpdateMethod(
/* Filter out attempts to run UPDATE or DELETE on contentless tables.
** This is not suported. */
if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
- pTab->base.zErrMsg = sqlite3_mprintf(
- "cannot %s contentless fts5 table: %s",
+ pTab->p.base.zErrMsg = sqlite3_mprintf(
+ "cannot %s contentless fts5 table: %s",
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
);
rc = SQLITE_ERROR;
@@ -194536,69 +224629,75 @@ static int fts5UpdateMethod(
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
}
- /* INSERT */
- else if( eType0!=SQLITE_INTEGER ){
- /* If this is a REPLACE, first remove the current entry (if any) */
- if( eConflict==SQLITE_REPLACE
- && sqlite3_value_type(apVal[1])==SQLITE_INTEGER
- ){
- i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ /* INSERT or UPDATE */
+ else{
+ int eType1 = sqlite3_value_numeric_type(apVal[1]);
+
+ if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
+ rc = SQLITE_MISMATCH;
}
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
- }
- /* UPDATE */
- else{
- i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
- i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
- if( iOld!=iNew ){
- if( eConflict==SQLITE_REPLACE ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
- }
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
- }else{
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
- if( rc==SQLITE_OK ){
+ else if( eType0!=SQLITE_INTEGER ){
+ /* If this is a REPLACE, first remove the current entry (if any) */
+ if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
+ i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ }
+ fts5StorageInsert(&rc, pTab, apVal, pRowid);
+ }
+
+ /* UPDATE */
+ else{
+ i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
+ i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
+ if( eType1==SQLITE_INTEGER && iOld!=iNew ){
+ if( eConflict==SQLITE_REPLACE ){
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ }
+ fts5StorageInsert(&rc, pTab, apVal, pRowid);
+ }else{
+ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
+ }
}
- if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
- }
+ }else{
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
- }else{
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
- fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
}
}
- pTab->pConfig->pzErrmsg = 0;
+ pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
/*
-** Implementation of xSync() method.
+** Implementation of xSync() method.
*/
static int fts5SyncMethod(sqlite3_vtab *pVtab){
int rc;
- Fts5Table *pTab = (Fts5Table*)pVtab;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
- pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
+ pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
fts5TripCursors(pTab);
- rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
- pTab->pConfig->pzErrmsg = 0;
+ rc = sqlite3Fts5StorageSync(pTab->pStorage);
+ pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
/*
-** Implementation of xBegin() method.
+** Implementation of xBegin() method.
*/
static int fts5BeginMethod(sqlite3_vtab *pVtab){
- fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
- fts5NewTransaction((Fts5Table*)pVtab);
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
+ fts5NewTransaction((Fts5FullTable*)pVtab);
return SQLITE_OK;
}
@@ -194609,7 +224708,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){
*/
static int fts5CommitMethod(sqlite3_vtab *pVtab){
UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_COMMIT, 0);
return SQLITE_OK;
}
@@ -194619,7 +224718,7 @@ static int fts5CommitMethod(sqlite3_vtab *pVtab){
*/
static int fts5RollbackMethod(sqlite3_vtab *pVtab){
int rc;
- Fts5Table *pTab = (Fts5Table*)pVtab;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
return rc;
@@ -194638,24 +224737,24 @@ static int fts5ApiColumnCount(Fts5Context *pCtx){
}
static int fts5ApiColumnTotalSize(
- Fts5Context *pCtx,
- int iCol,
+ Fts5Context *pCtx,
+ int iCol,
sqlite3_int64 *pnToken
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
}
static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
}
static int fts5ApiTokenize(
- Fts5Context *pCtx,
- const char *pText, int nText,
+ Fts5Context *pCtx,
+ const char *pText, int nText,
void *pUserData,
int (*xToken)(void*, int, const char*, int, int, int)
){
@@ -194677,14 +224776,16 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
}
static int fts5ApiColumnText(
- Fts5Context *pCtx,
- int iCol,
- const char **pz,
+ Fts5Context *pCtx,
+ int iCol,
+ const char **pz,
int *pn
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
+ if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
+ || pCsr->ePlan==FTS5_PLAN_SPECIAL
+ ){
*pz = 0;
*pn = 0;
}else{
@@ -194698,8 +224799,8 @@ static int fts5ApiColumnText(
}
static int fts5CsrPoslist(
- Fts5Cursor *pCsr,
- int iPhrase,
+ Fts5Cursor *pCsr,
+ int iPhrase,
const u8 **pa,
int *pn
){
@@ -194753,10 +224854,11 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
int rc = SQLITE_OK;
Fts5PoslistReader *aIter; /* One iterator for each phrase */
int nIter; /* Number of iterators/phrases */
-
+ int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol;
+
nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
if( pCsr->aInstIter==0 ){
- int nByte = sizeof(Fts5PoslistReader) * nIter;
+ sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter;
pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
}
aIter = pCsr->aInstIter;
@@ -194768,7 +224870,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
/* Initialize all iterators */
for(i=0; i<nIter && rc==SQLITE_OK; i++){
const u8 *a;
- int n;
+ int n;
rc = fts5CsrPoslist(pCsr, i, &a, &n);
if( rc==SQLITE_OK ){
sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
@@ -194780,8 +224882,8 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
int *aInst;
int iBest = -1;
for(i=0; i<nIter; i++){
- if( (aIter[i].bEof==0)
- && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
+ if( (aIter[i].bEof==0)
+ && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
){
iBest = i;
}
@@ -194791,7 +224893,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
nInst++;
if( nInst>=pCsr->nInstAlloc ){
pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
- aInst = (int*)sqlite3_realloc(
+ aInst = (int*)sqlite3_realloc64(
pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
);
if( aInst ){
@@ -194806,6 +224908,10 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
aInst[0] = iBest;
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
+ if( aInst[1]<0 || aInst[1]>=nCol ){
+ rc = FTS5_CORRUPT;
+ break;
+ }
sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
}
}
@@ -194819,7 +224925,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
int rc = SQLITE_OK;
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
|| SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
*pnInst = pCsr->nInstCount;
}
@@ -194827,16 +224933,16 @@ static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
}
static int fts5ApiInst(
- Fts5Context *pCtx,
- int iIdx,
- int *piPhrase,
- int *piCol,
+ Fts5Context *pCtx,
+ int iIdx,
+ int *piPhrase,
+ int *piCol,
int *piOff
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
int rc = SQLITE_OK;
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
- || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
+ || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
){
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
rc = SQLITE_RANGE;
@@ -194878,8 +224984,8 @@ static int fts5ColumnSizeCb(
static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
+ Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
@@ -194985,8 +225091,8 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
}
static void fts5ApiPhraseNext(
- Fts5Context *pUnused,
- Fts5PhraseIter *pIter,
+ Fts5Context *pUnused,
+ Fts5PhraseIter *pIter,
int *piCol, int *piOff
){
UNUSED_PARAM(pUnused);
@@ -195007,9 +225113,9 @@ static void fts5ApiPhraseNext(
}
static int fts5ApiPhraseFirst(
- Fts5Context *pCtx,
- int iPhrase,
- Fts5PhraseIter *pIter,
+ Fts5Context *pCtx,
+ int iPhrase,
+ Fts5PhraseIter *pIter,
int *piCol, int *piOff
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
@@ -195025,8 +225131,8 @@ static int fts5ApiPhraseFirst(
}
static void fts5ApiPhraseNextColumn(
- Fts5Context *pCtx,
- Fts5PhraseIter *pIter,
+ Fts5Context *pCtx,
+ Fts5PhraseIter *pIter,
int *piCol
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
@@ -195055,9 +225161,9 @@ static void fts5ApiPhraseNextColumn(
}
static int fts5ApiPhraseFirstColumn(
- Fts5Context *pCtx,
- int iPhrase,
- Fts5PhraseIter *pIter,
+ Fts5Context *pCtx,
+ int iPhrase,
+ Fts5PhraseIter *pIter,
int *piCol
){
int rc = SQLITE_OK;
@@ -195098,7 +225204,7 @@ static int fts5ApiPhraseFirstColumn(
}
-static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
+static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
@@ -195129,13 +225235,13 @@ static const Fts5ExtensionApi sFts5Api = {
** Implementation of API function xQueryPhrase().
*/
static int fts5ApiQueryPhrase(
- Fts5Context *pCtx,
- int iPhrase,
+ Fts5Context *pCtx,
+ int iPhrase,
void *pUserData,
int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
int rc;
Fts5Cursor *pNew = 0;
@@ -195201,7 +225307,7 @@ static void fts5ApiCallback(
iCsrId = sqlite3_value_int64(argv[0]);
pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
- if( pCsr==0 ){
+ if( pCsr==0 || pCsr->ePlan==0 ){
char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
@@ -195212,25 +225318,19 @@ static void fts5ApiCallback(
/*
-** Given cursor id iId, return a pointer to the corresponding Fts5Index
+** Given cursor id iId, return a pointer to the corresponding Fts5Table
** object. Or NULL If the cursor id does not exist.
-**
-** If successful, set *ppConfig to point to the associated config object
-** before returning.
*/
-static Fts5Index *sqlite3Fts5IndexFromCsrid(
+static Fts5Table *sqlite3Fts5TableFromCsrid(
Fts5Global *pGlobal, /* FTS5 global context for db handle */
- i64 iCsrId, /* Id of cursor to find */
- Fts5Config **ppConfig /* OUT: Configuration object */
+ i64 iCsrId /* Id of cursor to find */
){
Fts5Cursor *pCsr;
- Fts5Table *pTab;
-
pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
- pTab = (Fts5Table*)pCsr->base.pVtab;
- *ppConfig = pTab->pConfig;
-
- return pTab->pIndex;
+ if( pCsr ){
+ return (Fts5Table*)pCsr->base.pVtab;
+ }
+ return 0;
}
/*
@@ -195301,7 +225401,7 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
return rc;
}
-/*
+/*
** This is the xColumn method, called by SQLite to request a value from
** the row that the supplied cursor currently points to.
*/
@@ -195310,11 +225410,11 @@ static int fts5ColumnMethod(
sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */
int iCol /* Index of column to read value from */
){
- Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
- Fts5Config *pConfig = pTab->pConfig;
+ Fts5FullTable *pTab = (Fts5FullTable*)(pCursor->pVtab);
+ Fts5Config *pConfig = pTab->p.pConfig;
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
int rc = SQLITE_OK;
-
+
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
@@ -195334,7 +225434,7 @@ static int fts5ColumnMethod(
/* The value of the "rank" column. */
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
fts5PoslistBlob(pCtx, pCsr);
- }else if(
+ }else if(
pCsr->ePlan==FTS5_PLAN_MATCH
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
){
@@ -195343,10 +225443,12 @@ static int fts5ColumnMethod(
}
}
}else if( !fts5IsContentless(pTab) ){
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
rc = fts5SeekCursor(pCsr, 1);
if( rc==SQLITE_OK ){
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
}
+ pConfig->pzErrmsg = 0;
}
return rc;
}
@@ -195363,7 +225465,7 @@ static int fts5FindFunctionMethod(
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
void **ppArg /* OUT: User data for *pxFunc */
){
- Fts5Table *pTab = (Fts5Table*)pVtab;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
Fts5Auxiliary *pAux;
UNUSED_PARAM(nUnused);
@@ -195385,21 +225487,24 @@ static int fts5RenameMethod(
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
- Fts5Table *pTab = (Fts5Table*)pVtab;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
return sqlite3Fts5StorageRename(pTab->pStorage, zName);
}
+static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
+ fts5TripCursors((Fts5FullTable*)pTab);
+ return sqlite3Fts5StorageSync(((Fts5FullTable*)pTab)->pStorage);
+}
+
/*
** The xSavepoint() method.
**
** Flush the contents of the pending-terms table to disk.
*/
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
- fts5TripCursors(pTab);
- return sqlite3Fts5StorageSync(pTab->pStorage, 0);
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
+ return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
}
/*
@@ -195408,11 +225513,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts5Table *pTab = (Fts5Table*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
- fts5TripCursors(pTab);
- return sqlite3Fts5StorageSync(pTab->pStorage, 0);
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
+ return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
}
/*
@@ -195421,7 +225524,7 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
** Discard the contents of the pending terms table.
*/
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts5Table *pTab = (Fts5Table*)pVtab;
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
@@ -195442,14 +225545,14 @@ static int fts5CreateAux(
int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
if( rc==SQLITE_OK ){
Fts5Auxiliary *pAux;
- int nName; /* Size of zName in bytes, including \0 */
- int nByte; /* Bytes of space to allocate */
+ sqlite3_int64 nName; /* Size of zName in bytes, including \0 */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
- nName = (int)strlen(zName) + 1;
+ nName = strlen(zName) + 1;
nByte = sizeof(Fts5Auxiliary) + nName;
- pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte);
+ pAux = (Fts5Auxiliary*)sqlite3_malloc64(nByte);
if( pAux ){
- memset(pAux, 0, nByte);
+ memset(pAux, 0, (size_t)nByte);
pAux->zFunc = (char*)&pAux[1];
memcpy(pAux->zFunc, zName, nName);
pAux->pGlobal = pGlobal;
@@ -195467,7 +225570,7 @@ static int fts5CreateAux(
}
/*
-** Register a new tokenizer. This is the implementation of the
+** Register a new tokenizer. This is the implementation of the
** fts5_api.xCreateTokenizer() method.
*/
static int fts5CreateTokenizer(
@@ -195479,15 +225582,15 @@ static int fts5CreateTokenizer(
){
Fts5Global *pGlobal = (Fts5Global*)pApi;
Fts5TokenizerModule *pNew;
- int nName; /* Size of zName and its \0 terminator */
- int nByte; /* Bytes of space to allocate */
+ sqlite3_int64 nName; /* Size of zName and its \0 terminator */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
int rc = SQLITE_OK;
- nName = (int)strlen(zName) + 1;
+ nName = strlen(zName) + 1;
nByte = sizeof(Fts5TokenizerModule) + nName;
- pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte);
+ pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
if( pNew ){
- memset(pNew, 0, nByte);
+ memset(pNew, 0, (size_t)nByte);
pNew->zName = (char*)&pNew[1];
memcpy(pNew->zName, zName, nName);
pNew->pUserData = pUserData;
@@ -195506,7 +225609,7 @@ static int fts5CreateTokenizer(
}
static Fts5TokenizerModule *fts5LocateTokenizer(
- Fts5Global *pGlobal,
+ Fts5Global *pGlobal,
const char *zName
){
Fts5TokenizerModule *pMod = 0;
@@ -195523,7 +225626,7 @@ static Fts5TokenizerModule *fts5LocateTokenizer(
}
/*
-** Find a tokenizer. This is the implementation of the
+** Find a tokenizer. This is the implementation of the
** fts5_api.xFindTokenizer() method.
*/
static int fts5FindTokenizer(
@@ -195548,7 +225651,7 @@ static int fts5FindTokenizer(
}
static int sqlite3Fts5GetTokenizer(
- Fts5Global *pGlobal,
+ Fts5Global *pGlobal,
const char **azArg,
int nArg,
Fts5Tokenizer **ppTok,
@@ -195602,15 +225705,14 @@ static void fts5ModuleDestroy(void *pCtx){
static void fts5Fts5Func(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
- sqlite3_value **apUnused /* Function arguments */
+ sqlite3_value **apArg /* Function arguments */
){
Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
- char buf[8];
- UNUSED_PARAM2(nArg, apUnused);
- assert( nArg==0 );
- assert( sizeof(buf)>=sizeof(pGlobal) );
- memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
- sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
+ fts5_api **ppApi;
+ UNUSED_PARAM(nArg);
+ assert( nArg==1 );
+ ppApi = (fts5_api**)sqlite3_value_pointer(apArg[0], "fts5_api_ptr");
+ if( ppApi ) *ppApi = &pGlobal->api;
}
/*
@@ -195623,12 +225725,27 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2016-11-04 12:08:49 1136863c76576110e710dd5d69ab6bf347c65e36", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f", -1, SQLITE_TRANSIENT);
+}
+
+/*
+** Return true if zName is the extension on one of the shadow tables used
+** by this module.
+*/
+static int fts5ShadowName(const char *zName){
+ static const char *azName[] = {
+ "config", "content", "data", "docsize", "idx"
+ };
+ unsigned int i;
+ for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
+ if( sqlite3_stricmp(zName, azName[i])==0 ) return 1;
+ }
+ return 0;
}
static int fts5Init(sqlite3 *db){
static const sqlite3_module fts5Mod = {
- /* iVersion */ 2,
+ /* iVersion */ 3,
/* xCreate */ fts5CreateMethod,
/* xConnect */ fts5ConnectMethod,
/* xBestIndex */ fts5BestIndexMethod,
@@ -195651,6 +225768,7 @@ static int fts5Init(sqlite3 *db){
/* xSavepoint */ fts5SavepointMethod,
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
+ /* xShadowName */ fts5ShadowName
};
int rc;
@@ -195675,7 +225793,7 @@ static int fts5Init(sqlite3 *db){
if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(
- db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
+ db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
);
}
if( rc==SQLITE_OK ){
@@ -195703,7 +225821,7 @@ static int fts5Init(sqlite3 *db){
** this module is being built as part of the SQLite core (SQLITE_CORE is
** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
**
-** Or, if this module is being built as a loadable extension,
+** Or, if this module is being built as a loadable extension,
** sqlite3Fts5Init() is omitted and the two standard entry points
** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
*/
@@ -195762,19 +225880,19 @@ struct Fts5Storage {
Fts5Index *pIndex;
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
i64 nTotalRow; /* Total number of rows in FTS table */
- i64 *aTotalSize; /* Total sizes of each column */
+ i64 *aTotalSize; /* Total sizes of each column */
sqlite3_stmt *aStmt[11];
};
-#if FTS5_STMT_SCAN_ASC!=0
-# error "FTS5_STMT_SCAN_ASC mismatch"
+#if FTS5_STMT_SCAN_ASC!=0
+# error "FTS5_STMT_SCAN_ASC mismatch"
#endif
-#if FTS5_STMT_SCAN_DESC!=1
-# error "FTS5_STMT_SCAN_DESC mismatch"
+#if FTS5_STMT_SCAN_DESC!=1
+# error "FTS5_STMT_SCAN_DESC mismatch"
#endif
#if FTS5_STMT_LOOKUP!=2
-# error "FTS5_STMT_LOOKUP mismatch"
+# error "FTS5_STMT_LOOKUP mismatch"
#endif
#define FTS5_STMT_INSERT_CONTENT 3
@@ -195800,12 +225918,12 @@ static int fts5StorageGetStmt(
){
int rc = SQLITE_OK;
- /* If there is no %_docsize table, there should be no requests for
+ /* If there is no %_docsize table, there should be no requests for
** statements to operate on it. */
assert( p->pConfig->bColumnsize || (
- eStmt!=FTS5_STMT_REPLACE_DOCSIZE
- && eStmt!=FTS5_STMT_DELETE_DOCSIZE
- && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
+ eStmt!=FTS5_STMT_REPLACE_DOCSIZE
+ && eStmt!=FTS5_STMT_DELETE_DOCSIZE
+ && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
));
assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
@@ -195831,32 +225949,32 @@ static int fts5StorageGetStmt(
switch( eStmt ){
case FTS5_STMT_SCAN:
- zSql = sqlite3_mprintf(azStmt[eStmt],
+ zSql = sqlite3_mprintf(azStmt[eStmt],
pC->zContentExprlist, pC->zContent
);
break;
case FTS5_STMT_SCAN_ASC:
case FTS5_STMT_SCAN_DESC:
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist,
+ zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist,
pC->zContent, pC->zContentRowid, pC->zContentRowid,
pC->zContentRowid
);
break;
case FTS5_STMT_LOOKUP:
- zSql = sqlite3_mprintf(azStmt[eStmt],
+ zSql = sqlite3_mprintf(azStmt[eStmt],
pC->zContentExprlist, pC->zContent, pC->zContentRowid
);
break;
- case FTS5_STMT_INSERT_CONTENT:
+ case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
int nCol = pC->nCol + 1;
char *zBind;
int i;
- zBind = sqlite3_malloc(1 + nCol*2);
+ zBind = sqlite3_malloc64(1 + nCol*2);
if( zBind ){
for(i=0; i<nCol; i++){
zBind[i*2] = '?';
@@ -195877,7 +225995,11 @@ static int fts5StorageGetStmt(
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
- rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
+ int f = SQLITE_PREPARE_PERSISTENT;
+ if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
+ p->pConfig->bLock++;
+ rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
+ p->pConfig->bLock--;
sqlite3_free(zSql);
if( rc!=SQLITE_OK && pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
@@ -195920,7 +226042,7 @@ static int fts5ExecPrintf(
** code otherwise.
*/
static int sqlite3Fts5DropAll(Fts5Config *pConfig){
- int rc = fts5ExecPrintf(pConfig->db, 0,
+ int rc = fts5ExecPrintf(pConfig->db, 0,
"DROP TABLE IF EXISTS %Q.'%q_data';"
"DROP TABLE IF EXISTS %Q.'%q_idx';"
"DROP TABLE IF EXISTS %Q.'%q_config';",
@@ -195929,13 +226051,13 @@ static int sqlite3Fts5DropAll(Fts5Config *pConfig){
pConfig->zDb, pConfig->zName
);
if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = fts5ExecPrintf(pConfig->db, 0,
+ rc = fts5ExecPrintf(pConfig->db, 0,
"DROP TABLE IF EXISTS %Q.'%q_docsize';",
pConfig->zDb, pConfig->zName
);
}
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
- rc = fts5ExecPrintf(pConfig->db, 0,
+ rc = fts5ExecPrintf(pConfig->db, 0,
"DROP TABLE IF EXISTS %Q.'%q_content';",
pConfig->zDb, pConfig->zName
);
@@ -195950,7 +226072,7 @@ static void fts5StorageRenameOne(
const char *zName /* New name of FTS5 table */
){
if( *pRc==SQLITE_OK ){
- *pRc = fts5ExecPrintf(pConfig->db, 0,
+ *pRc = fts5ExecPrintf(pConfig->db, 0,
"ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';",
pConfig->zDb, pConfig->zName, zTail, zName, zTail
);
@@ -195959,7 +226081,7 @@ static void fts5StorageRenameOne(
static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
Fts5Config *pConfig = pStorage->pConfig;
- int rc = sqlite3Fts5StorageSync(pStorage, 1);
+ int rc = sqlite3Fts5StorageSync(pStorage);
fts5StorageRenameOne(pConfig, &rc, "data", zName);
fts5StorageRenameOne(pConfig, &rc, "idx", zName);
@@ -195988,7 +226110,7 @@ static int sqlite3Fts5CreateTable(
char *zErr = 0;
rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
- pConfig->zDb, pConfig->zName, zPost, zDefn,
+ pConfig->zDb, pConfig->zName, zPost, zDefn,
#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID
bWithout?" WITHOUT ROWID":
#endif
@@ -195996,7 +226118,7 @@ static int sqlite3Fts5CreateTable(
);
if( zErr ){
*pzErr = sqlite3_mprintf(
- "fts5: error creating shadow table %q_%s: %s",
+ "fts5: error creating shadow table %q_%s: %s",
pConfig->zName, zPost, zErr
);
sqlite3_free(zErr);
@@ -196007,28 +226129,28 @@ static int sqlite3Fts5CreateTable(
/*
** Open a new Fts5Index handle. If the bCreate argument is true, create
-** and initialize the underlying tables
+** and initialize the underlying tables
**
** If successful, set *pp to point to the new object and return SQLITE_OK.
** Otherwise, set *pp to NULL and return an SQLite error code.
*/
static int sqlite3Fts5StorageOpen(
- Fts5Config *pConfig,
- Fts5Index *pIndex,
- int bCreate,
+ Fts5Config *pConfig,
+ Fts5Index *pIndex,
+ int bCreate,
Fts5Storage **pp,
char **pzErr /* OUT: Error message */
){
int rc = SQLITE_OK;
Fts5Storage *p; /* New object */
- int nByte; /* Bytes of space to allocate */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
nByte = sizeof(Fts5Storage) /* Fts5Storage object */
+ pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */
- *pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
+ *pp = p = (Fts5Storage*)sqlite3_malloc64(nByte);
if( !p ) return SQLITE_NOMEM;
- memset(p, 0, nByte);
+ memset(p, 0, (size_t)nByte);
p->aTotalSize = (i64*)&p[1];
p->pConfig = pConfig;
p->pIndex = pIndex;
@@ -196036,7 +226158,7 @@ static int sqlite3Fts5StorageOpen(
if( bCreate ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
+ char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -196127,8 +226249,8 @@ static int fts5StorageInsertCallback(
** remove the %_content row at this time though.
*/
static int fts5StorageDeleteFromIndex(
- Fts5Storage *p,
- i64 iDel,
+ Fts5Storage *p,
+ i64 iDel,
sqlite3_value **apVal
){
Fts5Config *pConfig = p->pConfig;
@@ -196162,7 +226284,7 @@ static int fts5StorageDeleteFromIndex(
nText = sqlite3_value_bytes(apVal[iCol-1]);
}
ctx.szCol = 0;
- rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
zText, nText, (void*)&ctx, fts5StorageInsertCallback
);
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
@@ -196198,13 +226320,14 @@ static int fts5StorageInsertDocsize(
sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
sqlite3_step(pReplace);
rc = sqlite3_reset(pReplace);
+ sqlite3_bind_null(pReplace, 2);
}
}
return rc;
}
/*
-** Load the contents of the "averages" record from disk into the
+** Load the contents of the "averages" record from disk into the
** p->nTotalRow and p->aTotalSize[] variables. If successful, and if
** argument bCache is true, set the p->bTotalsValid flag to indicate
** that the contents of aTotalSize[] and nTotalRow are valid until
@@ -196223,7 +226346,7 @@ static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){
}
/*
-** Store the current contents of the p->nTotalRow and p->aTotalSize[]
+** Store the current contents of the p->nTotalRow and p->aTotalSize[]
** variables in the "averages" record on disk.
**
** Return SQLITE_OK if successful, or an SQLite error code if an error
@@ -196286,11 +226409,6 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap
}
}
- /* Write the averages record */
- if( rc==SQLITE_OK ){
- rc = fts5StorageSaveTotals(p);
- }
-
return rc;
}
@@ -196301,9 +226419,11 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
Fts5Config *pConfig = p->pConfig;
int rc;
+ p->bTotalsValid = 0;
+
/* Delete the contents of the %_data and %_docsize tables. */
rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_data';"
+ "DELETE FROM %Q.'%q_data';"
"DELETE FROM %Q.'%q_idx';",
pConfig->zDb, pConfig->zName,
pConfig->zDb, pConfig->zName
@@ -196331,7 +226451,7 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
Fts5Config *pConfig = p->pConfig;
sqlite3_stmt *pScan = 0;
Fts5InsertCtx ctx;
- int rc;
+ int rc, rc2;
memset(&ctx, 0, sizeof(Fts5InsertCtx));
ctx.pStorage = p;
@@ -196352,10 +226472,11 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
- rc = sqlite3Fts5Tokenize(pConfig,
+ const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
+ int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
+ rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
- sqlite3_column_bytes(pScan, ctx.iCol+1),
+ zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
@@ -196370,6 +226491,8 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
}
}
sqlite3_free(buf.p);
+ rc2 = sqlite3_reset(pScan);
+ if( rc==SQLITE_OK ) rc = rc2;
/* Write the averages record */
if( rc==SQLITE_OK ){
@@ -196421,8 +226544,8 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
** Insert a new row into the FTS content table.
*/
static int sqlite3Fts5StorageContentInsert(
- Fts5Storage *p,
- sqlite3_value **apVal,
+ Fts5Storage *p,
+ sqlite3_value **apVal,
i64 *piRowid
){
Fts5Config *pConfig = p->pConfig;
@@ -196456,8 +226579,8 @@ static int sqlite3Fts5StorageContentInsert(
** Insert new entries into the FTS index and %_docsize table.
*/
static int sqlite3Fts5StorageIndexInsert(
- Fts5Storage *p,
- sqlite3_value **apVal,
+ Fts5Storage *p,
+ sqlite3_value **apVal,
i64 iRowid
){
Fts5Config *pConfig = p->pConfig;
@@ -196475,10 +226598,11 @@ static int sqlite3Fts5StorageIndexInsert(
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
- rc = sqlite3Fts5Tokenize(pConfig,
+ const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
+ int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
+ rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
- sqlite3_value_bytes(apVal[ctx.iCol+2]),
+ zText, nText,
(void*)&ctx,
fts5StorageInsertCallback
);
@@ -196494,11 +226618,6 @@ static int sqlite3Fts5StorageIndexInsert(
}
sqlite3_free(buf.p);
- /* Write the averages record */
- if( rc==SQLITE_OK ){
- rc = fts5StorageSaveTotals(p);
- }
-
return rc;
}
@@ -196507,7 +226626,7 @@ static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){
char *zSql;
int rc;
- zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'",
+ zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'",
pConfig->zDb, pConfig->zName, zSuffix
);
if( zSql==0 ){
@@ -196624,7 +226743,7 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
ctx.pConfig = p->pConfig;
- aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64)));
+ aTotalSize = (i64*)sqlite3_malloc64(pConfig->nCol*(sizeof(int)+sizeof(i64)));
if( !aTotalSize ) return SQLITE_NOMEM;
aColSize = (int*)&aTotalSize[pConfig->nCol];
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
@@ -196652,10 +226771,11 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5Tokenize(pConfig,
+ const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
+ int nText = sqlite3_column_bytes(pScan, i+1);
+ rc = sqlite3Fts5Tokenize(pConfig,
FTS5_TOKENIZE_DOCUMENT,
- (const char*)sqlite3_column_text(pScan, i+1),
- sqlite3_column_bytes(pScan, i+1),
+ zText, nText,
(void*)&ctx,
fts5StorageIntegrityCallback
);
@@ -196716,13 +226836,13 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
** %_content table.
*/
static int sqlite3Fts5StorageStmt(
- Fts5Storage *p,
- int eStmt,
- sqlite3_stmt **pp,
+ Fts5Storage *p,
+ int eStmt,
+ sqlite3_stmt **pp,
char **pzErrMsg
){
int rc;
- assert( eStmt==FTS5_STMT_SCAN_ASC
+ assert( eStmt==FTS5_STMT_SCAN_ASC
|| eStmt==FTS5_STMT_SCAN_DESC
|| eStmt==FTS5_STMT_LOOKUP
);
@@ -196740,8 +226860,8 @@ static int sqlite3Fts5StorageStmt(
** must match that passed to the sqlite3Fts5StorageStmt() call.
*/
static void sqlite3Fts5StorageStmtRelease(
- Fts5Storage *p,
- int eStmt,
+ Fts5Storage *p,
+ int eStmt,
sqlite3_stmt *pStmt
){
assert( eStmt==FTS5_STMT_SCAN_ASC
@@ -196824,7 +226944,13 @@ static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
int rc = fts5StorageLoadTotals(p, 0);
if( rc==SQLITE_OK ){
+ /* nTotalRow being zero does not necessarily indicate a corrupt
+ ** database - it might be that the FTS5 table really does contain zero
+ ** rows. However this function is only called from the xRowCount() API,
+ ** and there is no way for that API to be invoked if the table contains
+ ** no rows. Hence the FTS5_CORRUPT return. */
*pnRow = p->nTotalRow;
+ if( p->nTotalRow<=0 ) rc = FTS5_CORRUPT;
}
return rc;
}
@@ -196832,13 +226958,18 @@ static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
/*
** Flush any data currently held in-memory to disk.
*/
-static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
- if( bCommit && p->bTotalsValid ){
- int rc = fts5StorageSaveTotals(p);
+static int sqlite3Fts5StorageSync(Fts5Storage *p){
+ int rc = SQLITE_OK;
+ i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
+ if( p->bTotalsValid ){
+ rc = fts5StorageSaveTotals(p);
p->bTotalsValid = 0;
- if( rc!=SQLITE_OK ) return rc;
}
- return sqlite3Fts5IndexSync(p->pIndex, bCommit);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5IndexSync(p->pIndex);
+ }
+ sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
+ return rc;
}
static int sqlite3Fts5StorageRollback(Fts5Storage *p){
@@ -196847,7 +226978,7 @@ static int sqlite3Fts5StorageRollback(Fts5Storage *p){
}
static int sqlite3Fts5StorageConfigValue(
- Fts5Storage *p,
+ Fts5Storage *p,
const char *z,
sqlite3_value *pVal,
int iVal
@@ -196863,6 +226994,7 @@ static int sqlite3Fts5StorageConfigValue(
}
sqlite3_step(pReplace);
rc = sqlite3_reset(pReplace);
+ sqlite3_bind_null(pReplace, 1);
}
if( rc==SQLITE_OK && pVal ){
int iNew = p->pConfig->iCookie + 1;
@@ -196896,7 +227028,7 @@ static int sqlite3Fts5StorageConfigValue(
/*
** For tokenizers with no "unicode" modifier, the set of token characters
-** is the same as the set of ASCII range alphanumeric characters.
+** is the same as the set of ASCII range alphanumeric characters.
*/
static unsigned char aAsciiTokenChar[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */
@@ -196915,8 +227047,8 @@ struct AsciiTokenizer {
};
static void fts5AsciiAddExceptions(
- AsciiTokenizer *p,
- const char *zArg,
+ AsciiTokenizer *p,
+ const char *zArg,
int bTokenChars
){
int i;
@@ -196938,7 +227070,7 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){
** Create an "ascii" tokenizer.
*/
static int fts5AsciiCreate(
- void *pUnused,
+ void *pUnused,
const char **azArg, int nArg,
Fts5Tokenizer **ppOut
){
@@ -197028,7 +227160,7 @@ static int fts5AsciiTokenize(
nByte = ie-is;
if( nByte>nFold ){
if( pFold!=aFold ) sqlite3_free(pFold);
- pFold = sqlite3_malloc(nByte*2);
+ pFold = sqlite3_malloc64((sqlite3_int64)nByte*2);
if( pFold==0 ){
rc = SQLITE_NOMEM;
break;
@@ -197041,7 +227173,7 @@ static int fts5AsciiTokenize(
rc = xToken(pCtx, 0, pFold, nByte, is, ie);
is = ie+1;
}
-
+
if( pFold!=aFold ) sqlite3_free(pFold);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
return rc;
@@ -197110,11 +227242,18 @@ struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
char *aFold; /* Buffer to fold text into */
int nFold; /* Size of aFold[] in bytes */
- int bRemoveDiacritic; /* True if remove_diacritics=1 is set */
+ int eRemoveDiacritic; /* True if remove_diacritics=1 is set */
int nException;
int *aiException;
+
+ unsigned char aCategory[32]; /* True for token char categories */
};
+/* Values for eRemoveDiacritic (must match internals of fts5_unicode2.c) */
+#define FTS5_REMOVE_DIACRITICS_NONE 0
+#define FTS5_REMOVE_DIACRITICS_SIMPLE 1
+#define FTS5_REMOVE_DIACRITICS_COMPLEX 2
+
static int fts5UnicodeAddExceptions(
Unicode61Tokenizer *p, /* Tokenizer object */
const char *z, /* Characters to treat as exceptions */
@@ -197125,25 +227264,26 @@ static int fts5UnicodeAddExceptions(
int *aNew;
if( n>0 ){
- aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int));
+ aNew = (int*)sqlite3_realloc64(p->aiException,
+ (n+p->nException)*sizeof(int));
if( aNew ){
int nNew = p->nException;
const unsigned char *zCsr = (const unsigned char*)z;
const unsigned char *zTerm = (const unsigned char*)&z[n];
while( zCsr<zTerm ){
- int iCode;
+ u32 iCode;
int bToken;
READ_UTF8(zCsr, zTerm, iCode);
if( iCode<128 ){
p->aTokenChar[iCode] = (unsigned char)bTokenChars;
}else{
- bToken = sqlite3Fts5UnicodeIsalnum(iCode);
- assert( (bToken==0 || bToken==1) );
+ bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)];
+ assert( (bToken==0 || bToken==1) );
assert( (bTokenChars==0 || bTokenChars==1) );
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
int i;
for(i=0; i<nNew; i++){
- if( aNew[i]>iCode ) break;
+ if( (u32)aNew[i]>iCode ) break;
}
memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int));
aNew[i] = iCode;
@@ -197198,16 +227338,31 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
return;
}
+static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){
+ const char *z = zCat;
+
+ while( *z ){
+ while( *z==' ' || *z=='\t' ) z++;
+ if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){
+ return SQLITE_ERROR;
+ }
+ while( *z!=' ' && *z!='\t' && *z!='\0' ) z++;
+ }
+
+ sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar);
+ return SQLITE_OK;
+}
+
/*
** Create a "unicode61" tokenizer.
*/
static int fts5UnicodeCreate(
- void *pUnused,
+ void *pUnused,
const char **azArg, int nArg,
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK; /* Return code */
- Unicode61Tokenizer *p = 0; /* New tokenizer object */
+ Unicode61Tokenizer *p = 0; /* New tokenizer object */
UNUSED_PARAM(pUnused);
@@ -197216,32 +227371,54 @@ static int fts5UnicodeCreate(
}else{
p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
if( p ){
+ const char *zCat = "L* N* Co";
int i;
memset(p, 0, sizeof(Unicode61Tokenizer));
- memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
- p->bRemoveDiacritic = 1;
+
+ p->eRemoveDiacritic = FTS5_REMOVE_DIACRITICS_SIMPLE;
p->nFold = 64;
- p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
+ p->aFold = sqlite3_malloc64(p->nFold * sizeof(char));
if( p->aFold==0 ){
rc = SQLITE_NOMEM;
}
+
+ /* Search for a "categories" argument */
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+ if( 0==sqlite3_stricmp(azArg[i], "categories") ){
+ zCat = azArg[i+1];
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = unicodeSetCategories(p, zCat);
+ }
+
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
- if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
rc = SQLITE_ERROR;
+ }else{
+ p->eRemoveDiacritic = (zArg[0] - '0');
+ assert( p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_NONE
+ || p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_SIMPLE
+ || p->eRemoveDiacritic==FTS5_REMOVE_DIACRITICS_COMPLEX
+ );
}
- p->bRemoveDiacritic = (zArg[0]=='1');
}else
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
rc = fts5UnicodeAddExceptions(p, zArg, 1);
}else
if( 0==sqlite3_stricmp(azArg[i], "separators") ){
rc = fts5UnicodeAddExceptions(p, zArg, 0);
+ }else
+ if( 0==sqlite3_stricmp(azArg[i], "categories") ){
+ /* no-op */
}else{
rc = SQLITE_ERROR;
}
}
+
}else{
rc = SQLITE_NOMEM;
}
@@ -197256,12 +227433,14 @@ static int fts5UnicodeCreate(
/*
** Return true if, for the purposes of tokenizing with the tokenizer
-** passed as the first argument, codepoint iCode is considered a token
+** passed as the first argument, codepoint iCode is considered a token
** character (not a separator).
*/
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
- assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
- return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode);
+ return (
+ p->aCategory[sqlite3Fts5UnicodeCategory((u32)iCode)]
+ ^ fts5UnicodeIsException(p, iCode)
+ );
}
static int fts5UnicodeTokenize(
@@ -197288,7 +227467,7 @@ static int fts5UnicodeTokenize(
/* Each iteration of this loop gobbles up a contiguous run of separators,
** then the next token. */
while( rc==SQLITE_OK ){
- int iCode; /* non-ASCII codepoint read from input */
+ u32 iCode; /* non-ASCII codepoint read from input */
char *zOut = aFold;
int is;
int ie;
@@ -197320,7 +227499,7 @@ static int fts5UnicodeTokenize(
/* Grow the output buffer so that there is sufficient space to fit the
** largest possible utf-8 character. */
if( zOut>pEnd ){
- aFold = sqlite3_malloc(nFold*2);
+ aFold = sqlite3_malloc64((sqlite3_int64)nFold*2);
if( aFold==0 ){
rc = SQLITE_NOMEM;
goto tokenize_done;
@@ -197339,14 +227518,14 @@ static int fts5UnicodeTokenize(
READ_UTF8(zCsr, zTerm, iCode);
if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){
non_ascii_tokenchar:
- iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic);
+ iCode = sqlite3Fts5UnicodeFold(iCode, p->eRemoveDiacritic);
if( iCode ) WRITE_UTF8(zOut, iCode);
}else{
break;
}
}else if( a[*zCsr]==0 ){
/* An ascii-range separator character. End of token. */
- break;
+ break;
}else{
ascii_tokenchar:
if( *zCsr>='A' && *zCsr<='Z' ){
@@ -197360,9 +227539,9 @@ static int fts5UnicodeTokenize(
}
/* Invoke the token callback */
- rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie);
+ rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie);
}
-
+
tokenize_done:
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
return rc;
@@ -197400,7 +227579,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){
** Create a "porter" tokenizer.
*/
static int fts5PorterCreate(
- void *pCtx,
+ void *pCtx,
const char **azArg, int nArg,
Fts5Tokenizer **ppOut
){
@@ -197544,7 +227723,7 @@ static int fts5Porter_Ostar(char *zStem, int nStem){
/* porter rule condition: (m > 1 and (*S or *T)) */
static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){
assert( nStem>0 );
- return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t')
+ return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t')
&& fts5Porter_MGt1(zStem, nStem);
}
@@ -197569,16 +227748,16 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
int ret = 0;
int nBuf = *pnBuf;
switch( aBuf[nBuf-2] ){
-
- case 'a':
+
+ case 'a':
if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){
if( fts5Porter_MGt1(aBuf, nBuf-2) ){
*pnBuf = nBuf - 2;
}
}
break;
-
- case 'c':
+
+ case 'c':
if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt1(aBuf, nBuf-4) ){
*pnBuf = nBuf - 4;
@@ -197589,24 +227768,24 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'e':
+
+ case 'e':
if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){
if( fts5Porter_MGt1(aBuf, nBuf-2) ){
*pnBuf = nBuf - 2;
}
}
break;
-
- case 'i':
+
+ case 'i':
if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){
if( fts5Porter_MGt1(aBuf, nBuf-2) ){
*pnBuf = nBuf - 2;
}
}
break;
-
- case 'l':
+
+ case 'l':
if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt1(aBuf, nBuf-4) ){
*pnBuf = nBuf - 4;
@@ -197617,8 +227796,8 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'n':
+
+ case 'n':
if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
@@ -197637,8 +227816,8 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'o':
+
+ case 'o':
if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
@@ -197649,16 +227828,16 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
}
}
break;
-
- case 's':
+
+ case 's':
if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
}
}
break;
-
- case 't':
+
+ case 't':
if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
@@ -197669,76 +227848,76 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'u':
+
+ case 'u':
if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
}
}
break;
-
- case 'v':
+
+ case 'v':
if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
}
}
break;
-
- case 'z':
+
+ case 'z':
if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
}
}
break;
-
+
}
return ret;
}
-
+
static int fts5PorterStep1B2(char *aBuf, int *pnBuf){
int ret = 0;
int nBuf = *pnBuf;
switch( aBuf[nBuf-2] ){
-
- case 'a':
+
+ case 'a':
if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){
memcpy(&aBuf[nBuf-2], "ate", 3);
*pnBuf = nBuf - 2 + 3;
ret = 1;
}
break;
-
- case 'b':
+
+ case 'b':
if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){
memcpy(&aBuf[nBuf-2], "ble", 3);
*pnBuf = nBuf - 2 + 3;
ret = 1;
}
break;
-
- case 'i':
+
+ case 'i':
if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){
memcpy(&aBuf[nBuf-2], "ize", 3);
*pnBuf = nBuf - 2 + 3;
ret = 1;
}
break;
-
+
}
return ret;
}
-
+
static int fts5PorterStep2(char *aBuf, int *pnBuf){
int ret = 0;
int nBuf = *pnBuf;
switch( aBuf[nBuf-2] ){
-
- case 'a':
+
+ case 'a':
if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){
if( fts5Porter_MGt0(aBuf, nBuf-7) ){
memcpy(&aBuf[nBuf-7], "ate", 3);
@@ -197751,8 +227930,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'c':
+
+ case 'c':
if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
memcpy(&aBuf[nBuf-4], "ence", 4);
@@ -197765,8 +227944,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'e':
+
+ case 'e':
if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
memcpy(&aBuf[nBuf-4], "ize", 3);
@@ -197774,8 +227953,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'g':
+
+ case 'g':
if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
memcpy(&aBuf[nBuf-4], "log", 3);
@@ -197783,8 +227962,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'l':
+
+ case 'l':
if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt0(aBuf, nBuf-3) ){
memcpy(&aBuf[nBuf-3], "ble", 3);
@@ -197812,8 +227991,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'o':
+
+ case 'o':
if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){
if( fts5Porter_MGt0(aBuf, nBuf-7) ){
memcpy(&aBuf[nBuf-7], "ize", 3);
@@ -197831,8 +228010,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 's':
+
+ case 's':
if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
memcpy(&aBuf[nBuf-5], "al", 2);
@@ -197855,8 +228034,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
- case 't':
+
+ case 't':
if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
memcpy(&aBuf[nBuf-5], "al", 2);
@@ -197874,18 +228053,18 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
}
}
break;
-
+
}
return ret;
}
-
+
static int fts5PorterStep3(char *aBuf, int *pnBuf){
int ret = 0;
int nBuf = *pnBuf;
switch( aBuf[nBuf-2] ){
-
- case 'a':
+
+ case 'a':
if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
memcpy(&aBuf[nBuf-4], "ic", 2);
@@ -197893,16 +228072,16 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){
}
}
break;
-
- case 's':
+
+ case 's':
if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
*pnBuf = nBuf - 4;
}
}
break;
-
- case 't':
+
+ case 't':
if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
memcpy(&aBuf[nBuf-5], "ic", 2);
@@ -197915,24 +228094,24 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'u':
+
+ case 'u':
if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt0(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
}
}
break;
-
- case 'v':
+
+ case 'v':
if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
*pnBuf = nBuf - 5;
}
}
break;
-
- case 'z':
+
+ case 'z':
if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
memcpy(&aBuf[nBuf-5], "al", 2);
@@ -197940,18 +228119,18 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){
}
}
break;
-
+
}
return ret;
}
-
+
static int fts5PorterStep1B(char *aBuf, int *pnBuf){
int ret = 0;
int nBuf = *pnBuf;
switch( aBuf[nBuf-2] ){
-
- case 'e':
+
+ case 'e':
if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){
if( fts5Porter_MGt0(aBuf, nBuf-3) ){
memcpy(&aBuf[nBuf-3], "ee", 2);
@@ -197964,8 +228143,8 @@ static int fts5PorterStep1B(char *aBuf, int *pnBuf){
}
}
break;
-
- case 'n':
+
+ case 'n':
if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){
if( fts5Porter_Vowel(aBuf, nBuf-3) ){
*pnBuf = nBuf - 3;
@@ -197973,12 +228152,12 @@ static int fts5PorterStep1B(char *aBuf, int *pnBuf){
}
}
break;
-
+
}
return ret;
}
-
-/*
+
+/*
** GENERATED CODE ENDS HERE (mkportersteps.tcl)
***************************************************************************
**************************************************************************/
@@ -197987,7 +228166,7 @@ static void fts5PorterStep1A(char *aBuf, int *pnBuf){
int nBuf = *pnBuf;
if( aBuf[nBuf-1]=='s' ){
if( aBuf[nBuf-2]=='e' ){
- if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s')
+ if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s')
|| (nBuf>3 && aBuf[nBuf-3]=='i' )
){
*pnBuf = nBuf-2;
@@ -198002,11 +228181,11 @@ static void fts5PorterStep1A(char *aBuf, int *pnBuf){
}
static int fts5PorterCb(
- void *pCtx,
+ void *pCtx,
int tflags,
- const char *pToken,
- int nToken,
- int iStart,
+ const char *pToken,
+ int nToken,
+ int iStart,
int iEnd
){
PorterContext *p = (PorterContext*)pCtx;
@@ -198024,8 +228203,8 @@ static int fts5PorterCb(
if( fts5PorterStep1B(aBuf, &nBuf) ){
if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){
char c = aBuf[nBuf-1];
- if( fts5PorterIsVowel(c, 0)==0
- && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2]
+ if( fts5PorterIsVowel(c, 0)==0
+ && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2]
){
nBuf--;
}else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){
@@ -198047,7 +228226,7 @@ static int fts5PorterCb(
/* Step 5a. */
assert( nBuf>0 );
if( aBuf[nBuf-1]=='e' ){
- if( fts5Porter_MGt1(aBuf, nBuf-1)
+ if( fts5Porter_MGt1(aBuf, nBuf-1)
|| (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1))
){
nBuf--;
@@ -198055,8 +228234,8 @@ static int fts5PorterCb(
}
/* Step 5b. */
- if( nBuf>1 && aBuf[nBuf-1]=='l'
- && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1)
+ if( nBuf>1 && aBuf[nBuf-1]=='l'
+ && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1)
){
nBuf--;
}
@@ -198099,7 +228278,7 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
{ "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
};
-
+
int rc = SQLITE_OK; /* Return code */
int i; /* To iterate through builtin functions */
@@ -198115,10 +228294,8 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
return rc;
}
-
-
/*
-** 2012 May 25
+** 2012-05-25
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -198137,135 +228314,6 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
/* #include <assert.h> */
-/*
-** Return true if the argument corresponds to a unicode codepoint
-** classified as either a letter or a number. Otherwise false.
-**
-** The results are undefined if the value passed to this function
-** is less than zero.
-*/
-static int sqlite3Fts5UnicodeIsalnum(int c){
- /* Each unsigned integer in the following array corresponds to a contiguous
- ** range of unicode codepoints that are not either letters or numbers (i.e.
- ** codepoints for which this function should return 0).
- **
- ** The most significant 22 bits in each 32-bit value contain the first
- ** codepoint in the range. The least significant 10 bits are used to store
- ** the size of the range (always at least 1). In other words, the value
- ** ((C<<22) + N) represents a range of N codepoints starting with codepoint
- ** C. It is not possible to represent a range larger than 1023 codepoints
- ** using this format.
- */
- static const unsigned int aEntry[] = {
- 0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
- 0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
- 0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
- 0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
- 0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
- 0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802,
- 0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F,
- 0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401,
- 0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804,
- 0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403,
- 0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812,
- 0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001,
- 0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802,
- 0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805,
- 0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401,
- 0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
- 0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807,
- 0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001,
- 0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01,
- 0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804,
- 0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001,
- 0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802,
- 0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01,
- 0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06,
- 0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007,
- 0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006,
- 0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417,
- 0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14,
- 0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07,
- 0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01,
- 0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001,
- 0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802,
- 0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F,
- 0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002,
- 0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802,
- 0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006,
- 0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D,
- 0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802,
- 0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027,
- 0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403,
- 0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805,
- 0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04,
- 0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401,
- 0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005,
- 0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B,
- 0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A,
- 0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001,
- 0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59,
- 0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807,
- 0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01,
- 0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E,
- 0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100,
- 0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10,
- 0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402,
- 0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804,
- 0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012,
- 0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
- 0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002,
- 0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803,
- 0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07,
- 0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02,
- 0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802,
- 0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013,
- 0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06,
- 0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003,
- 0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01,
- 0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403,
- 0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009,
- 0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003,
- 0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003,
- 0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E,
- 0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046,
- 0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
- 0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
- 0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F,
- 0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C,
- 0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002,
- 0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025,
- 0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6,
- 0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46,
- 0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060,
- 0x380400F0,
- };
- static const unsigned int aAscii[4] = {
- 0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
- };
-
- if( (unsigned int)c<128 ){
- return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
- }else if( (unsigned int)c<(1<<22) ){
- unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
- int iRes = 0;
- int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
- int iLo = 0;
- while( iHi>=iLo ){
- int iTest = (iHi + iLo) / 2;
- if( key >= aEntry[iTest] ){
- iRes = iTest;
- iLo = iTest+1;
- }else{
- iHi = iTest-1;
- }
- }
- assert( aEntry[0]<key );
- assert( key>=aEntry[iRes] );
- return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF)));
- }
- return 1;
-}
/*
@@ -198276,32 +228324,48 @@ static int sqlite3Fts5UnicodeIsalnum(int c){
** E"). The resuls of passing a codepoint that corresponds to an
** uppercase letter are undefined.
*/
-static int fts5_remove_diacritic(int c){
+static int fts5_remove_diacritic(int c, int bComplex){
unsigned short aDia[] = {
- 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
- 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
- 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
- 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
- 3456, 3696, 3712, 3728, 3744, 3896, 3912, 3928,
- 3968, 4008, 4040, 4106, 4138, 4170, 4202, 4234,
- 4266, 4296, 4312, 4344, 4408, 4424, 4472, 4504,
- 6148, 6198, 6264, 6280, 6360, 6429, 6505, 6529,
- 61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726,
- 61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122,
- 62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536,
- 62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730,
- 62924, 63050, 63082, 63274, 63390,
+ 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
+ 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
+ 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
+ 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
+ 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
+ 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
+ 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
+ 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
+ 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
+ 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
+ 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
+ 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
+ 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
+ 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
+ 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
+ 63182, 63242, 63274, 63310, 63368, 63390,
};
- char aChar[] = {
- '\0', 'a', 'c', 'e', 'i', 'n', 'o', 'u', 'y', 'y', 'a', 'c',
- 'd', 'e', 'e', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'o', 'r',
- 's', 't', 'u', 'u', 'w', 'y', 'z', 'o', 'u', 'a', 'i', 'o',
- 'u', 'g', 'k', 'o', 'j', 'g', 'n', 'a', 'e', 'i', 'o', 'r',
- 'u', 's', 't', 'h', 'a', 'e', 'o', 'y', '\0', '\0', '\0', '\0',
- '\0', '\0', '\0', '\0', 'a', 'b', 'd', 'd', 'e', 'f', 'g', 'h',
- 'h', 'i', 'k', 'l', 'l', 'm', 'n', 'p', 'r', 'r', 's', 't',
- 'u', 'v', 'w', 'w', 'x', 'y', 'z', 'h', 't', 'w', 'y', 'a',
- 'e', 'i', 'o', 'u', 'y',
+#define HIBIT ((unsigned char)0x80)
+ unsigned char aChar[] = {
+ '\0', 'a', 'c', 'e', 'i', 'n',
+ 'o', 'u', 'y', 'y', 'a', 'c',
+ 'd', 'e', 'e', 'g', 'h', 'i',
+ 'j', 'k', 'l', 'n', 'o', 'r',
+ 's', 't', 'u', 'u', 'w', 'y',
+ 'z', 'o', 'u', 'a', 'i', 'o',
+ 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
+ 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
+ 'e', 'i', 'o', 'r', 'u', 's',
+ 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
+ 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', 'a', 'b',
+ 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
+ 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
+ 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
+ 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
+ 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
+ 'w', 'x', 'y', 'z', 'h', 't',
+ 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
+ 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
+ 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
};
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
@@ -198318,7 +228382,8 @@ static int fts5_remove_diacritic(int c){
}
}
assert( key>=aDia[iRes] );
- return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
+ if( bComplex==0 && (aChar[iRes] & 0x80) ) return c;
+ return (c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : ((int)aChar[iRes] & 0x7F);
}
@@ -198331,8 +228396,8 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c){
unsigned int mask1 = 0x000361F8;
if( c<768 || c>817 ) return 0;
return (c < 768+32) ?
- (mask0 & (1 << (c-768))) :
- (mask1 & (1 << (c-768-32)));
+ (mask0 & ((unsigned int)1 << (c-768))) :
+ (mask1 & ((unsigned int)1 << (c-768-32)));
}
@@ -198345,7 +228410,7 @@ static int sqlite3Fts5UnicodeIsdiacritic(int c){
** The results are undefined if the value passed to this function
** is less than zero.
*/
-static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
+static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
/* Each entry in the following array defines a rule for folding a range
** of codepoints to lower case. The rule applies to a range of nRange
** codepoints starting at codepoint iCode.
@@ -198422,19 +228487,19 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
{42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
{42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
{42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
- {65313, 14, 26},
+ {65313, 14, 26},
};
static const unsigned short aiOff[] = {
- 1, 2, 8, 15, 16, 26, 28, 32,
- 37, 38, 40, 48, 63, 64, 69, 71,
- 79, 80, 116, 202, 203, 205, 206, 207,
- 209, 210, 211, 213, 214, 217, 218, 219,
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
- 65514, 65521, 65527, 65528, 65529,
+ 1, 2, 8, 15, 16, 26, 28, 32,
+ 37, 38, 40, 48, 63, 64, 69, 71,
+ 79, 80, 116, 202, 203, 205, 206, 207,
+ 209, 210, 211, 213, 214, 217, 218, 219,
+ 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
+ 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
+ 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
+ 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
+ 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
+ 65514, 65521, 65527, 65528, 65529,
};
int ret = c;
@@ -198468,9 +228533,11 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
assert( ret>0 );
}
- if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret);
+ if( eRemoveDiacritic ){
+ ret = fts5_remove_diacritic(ret, eRemoveDiacritic==2);
+ }
}
-
+
else if( c>=66560 && c<66600 ){
ret = c + 40;
}
@@ -198478,6 +228545,532 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
return ret;
}
+
+static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
+ aArray[0] = 1;
+ switch( zCat[0] ){
+ case 'C':
+ switch( zCat[1] ){
+ case 'c': aArray[1] = 1; break;
+ case 'f': aArray[2] = 1; break;
+ case 'n': aArray[3] = 1; break;
+ case 's': aArray[4] = 1; break;
+ case 'o': aArray[31] = 1; break;
+ case '*':
+ aArray[1] = 1;
+ aArray[2] = 1;
+ aArray[3] = 1;
+ aArray[4] = 1;
+ aArray[31] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ case 'L':
+ switch( zCat[1] ){
+ case 'l': aArray[5] = 1; break;
+ case 'm': aArray[6] = 1; break;
+ case 'o': aArray[7] = 1; break;
+ case 't': aArray[8] = 1; break;
+ case 'u': aArray[9] = 1; break;
+ case 'C': aArray[30] = 1; break;
+ case '*':
+ aArray[5] = 1;
+ aArray[6] = 1;
+ aArray[7] = 1;
+ aArray[8] = 1;
+ aArray[9] = 1;
+ aArray[30] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ case 'M':
+ switch( zCat[1] ){
+ case 'c': aArray[10] = 1; break;
+ case 'e': aArray[11] = 1; break;
+ case 'n': aArray[12] = 1; break;
+ case '*':
+ aArray[10] = 1;
+ aArray[11] = 1;
+ aArray[12] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ case 'N':
+ switch( zCat[1] ){
+ case 'd': aArray[13] = 1; break;
+ case 'l': aArray[14] = 1; break;
+ case 'o': aArray[15] = 1; break;
+ case '*':
+ aArray[13] = 1;
+ aArray[14] = 1;
+ aArray[15] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ case 'P':
+ switch( zCat[1] ){
+ case 'c': aArray[16] = 1; break;
+ case 'd': aArray[17] = 1; break;
+ case 'e': aArray[18] = 1; break;
+ case 'f': aArray[19] = 1; break;
+ case 'i': aArray[20] = 1; break;
+ case 'o': aArray[21] = 1; break;
+ case 's': aArray[22] = 1; break;
+ case '*':
+ aArray[16] = 1;
+ aArray[17] = 1;
+ aArray[18] = 1;
+ aArray[19] = 1;
+ aArray[20] = 1;
+ aArray[21] = 1;
+ aArray[22] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ case 'S':
+ switch( zCat[1] ){
+ case 'c': aArray[23] = 1; break;
+ case 'k': aArray[24] = 1; break;
+ case 'm': aArray[25] = 1; break;
+ case 'o': aArray[26] = 1; break;
+ case '*':
+ aArray[23] = 1;
+ aArray[24] = 1;
+ aArray[25] = 1;
+ aArray[26] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ case 'Z':
+ switch( zCat[1] ){
+ case 'l': aArray[27] = 1; break;
+ case 'p': aArray[28] = 1; break;
+ case 's': aArray[29] = 1; break;
+ case '*':
+ aArray[27] = 1;
+ aArray[28] = 1;
+ aArray[29] = 1;
+ break;
+ default: return 1; }
+ break;
+
+ }
+ return 0;
+}
+
+static u16 aFts5UnicodeBlock[] = {
+ 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760,
+ 1760, 1760, 1760, 1760, 1760, 1763, 1765,
+ };
+static u16 aFts5UnicodeMap[] = {
+ 0, 32, 33, 36, 37, 40, 41, 42, 43, 44,
+ 45, 46, 48, 58, 60, 63, 65, 91, 92, 93,
+ 94, 95, 96, 97, 123, 124, 125, 126, 127, 160,
+ 161, 162, 166, 167, 168, 169, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 180, 181, 182, 184, 185,
+ 186, 187, 188, 191, 192, 215, 216, 223, 247, 248,
+ 256, 312, 313, 329, 330, 377, 383, 385, 387, 388,
+ 391, 394, 396, 398, 402, 403, 405, 406, 409, 412,
+ 414, 415, 417, 418, 423, 427, 428, 431, 434, 436,
+ 437, 440, 442, 443, 444, 446, 448, 452, 453, 454,
+ 455, 456, 457, 458, 459, 460, 461, 477, 478, 496,
+ 497, 498, 499, 500, 503, 505, 506, 564, 570, 572,
+ 573, 575, 577, 580, 583, 584, 592, 660, 661, 688,
+ 706, 710, 722, 736, 741, 748, 749, 750, 751, 768,
+ 880, 884, 885, 886, 890, 891, 894, 900, 902, 903,
+ 904, 908, 910, 912, 913, 931, 940, 975, 977, 978,
+ 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072,
+ 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369,
+ 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473,
+ 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545,
+ 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611,
+ 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758,
+ 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791,
+ 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984,
+ 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075,
+ 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210,
+ 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369,
+ 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416,
+ 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482,
+ 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519,
+ 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561,
+ 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622,
+ 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677,
+ 2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749,
+ 2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790,
+ 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869,
+ 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902,
+ 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947,
+ 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006,
+ 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059,
+ 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134,
+ 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199,
+ 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263,
+ 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302,
+ 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402,
+ 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458,
+ 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544,
+ 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655,
+ 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737,
+ 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773,
+ 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860,
+ 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896,
+ 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967,
+ 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046,
+ 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153,
+ 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190,
+ 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229,
+ 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295,
+ 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704,
+ 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888,
+ 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743,
+ 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906,
+ 5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068,
+ 6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107,
+ 6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160,
+ 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435,
+ 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480,
+ 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679,
+ 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754,
+ 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824,
+ 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978,
+ 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043,
+ 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098,
+ 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168,
+ 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288,
+ 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406,
+ 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616,
+ 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976,
+ 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033,
+ 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118,
+ 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141,
+ 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184,
+ 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219,
+ 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249,
+ 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275,
+ 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317,
+ 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413,
+ 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459,
+ 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484,
+ 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500,
+ 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523,
+ 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597,
+ 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623,
+ 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972,
+ 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180,
+ 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
+ 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091,
+ 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101,
+ 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217,
+ 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627,
+ 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637,
+ 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647,
+ 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750,
+ 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365,
+ 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393,
+ 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520,
+ 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696,
+ 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780,
+ 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800,
+ 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812,
+ 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904,
+ 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296,
+ 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306,
+ 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317,
+ 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347,
+ 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449,
+ 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736,
+ 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938,
+ 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981,
+ 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528,
+ 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624,
+ 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800,
+ 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912,
+ 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043,
+ 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136,
+ 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264,
+ 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395,
+ 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472,
+ 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588,
+ 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643,
+ 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713,
+ 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762,
+ 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003,
+ 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203,
+ 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112,
+ 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320,
+ 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020,
+ 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075,
+ 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086,
+ 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097,
+ 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118,
+ 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279,
+ 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294,
+ 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343,
+ 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378,
+ 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490,
+ 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529,
+ 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263,
+ 311, 320, 373, 377, 394, 400, 464, 509, 640, 672,
+ 768, 800, 816, 833, 834, 842, 896, 927, 928, 968,
+ 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103,
+ 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432,
+ 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623,
+ 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912,
+ 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178,
+ 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285,
+ 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416,
+ 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760,
+ 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216,
+ 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248,
+ 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637,
+ 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298,
+ 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441,
+ 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541,
+ 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662,
+ 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922,
+ 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062,
+ 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178,
+ 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961,
+ 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003,
+ 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028,
+ 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099,
+ 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744,
+ 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368,
+ 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971,
+ 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488,
+ 1, 32, 256, 0, 65533,
+ };
+static u16 aFts5UnicodeData[] = {
+ 1025, 61, 117, 55, 117, 54, 50, 53, 57, 53,
+ 49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
+ 56, 48, 56, 837, 54, 57, 50, 57, 1057, 61,
+ 53, 151, 58, 53, 56, 58, 39, 52, 57, 34,
+ 58, 56, 58, 57, 79, 56, 37, 85, 56, 47,
+ 39, 51, 111, 53, 745, 57, 233, 773, 57, 261,
+ 1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126,
+ 126, 73, 69, 137, 37, 73, 37, 105, 101, 73,
+ 37, 73, 37, 190, 158, 37, 126, 126, 73, 37,
+ 126, 94, 37, 39, 94, 69, 135, 41, 40, 37,
+ 41, 40, 37, 41, 40, 37, 542, 37, 606, 37,
+ 41, 40, 37, 126, 73, 37, 1886, 197, 73, 37,
+ 73, 69, 126, 105, 37, 286, 2181, 39, 869, 582,
+ 152, 390, 472, 166, 248, 38, 56, 38, 568, 3596,
+ 158, 38, 56, 94, 38, 101, 53, 88, 41, 53,
+ 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105,
+ 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541,
+ 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38,
+ 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76,
+ 53, 76, 53, 44, 871, 103, 85, 162, 121, 85,
+ 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684,
+ 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58,
+ 204, 70, 76, 58, 140, 71, 333, 103, 90, 39,
+ 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333,
+ 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300,
+ 38, 108, 38, 172, 501, 807, 108, 53, 39, 359,
+ 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268,
+ 138, 44, 74, 39, 236, 327, 76, 85, 333, 53,
+ 38, 199, 231, 44, 74, 263, 71, 711, 231, 39,
+ 135, 44, 39, 106, 140, 74, 74, 44, 39, 42,
+ 71, 103, 76, 333, 71, 87, 207, 58, 55, 76,
+ 42, 199, 71, 711, 231, 71, 71, 71, 44, 106,
+ 76, 76, 108, 44, 135, 39, 333, 76, 103, 44,
+ 76, 42, 295, 103, 711, 231, 71, 167, 44, 39,
+ 106, 172, 76, 42, 74, 44, 39, 71, 76, 333,
+ 53, 55, 44, 74, 263, 71, 711, 231, 71, 167,
+ 44, 39, 42, 44, 42, 140, 74, 74, 44, 44,
+ 42, 71, 103, 76, 333, 58, 39, 207, 44, 39,
+ 199, 103, 135, 71, 39, 71, 71, 103, 391, 74,
+ 44, 74, 106, 106, 44, 39, 42, 333, 111, 218,
+ 55, 58, 106, 263, 103, 743, 327, 167, 39, 108,
+ 138, 108, 140, 76, 71, 71, 76, 333, 239, 58,
+ 74, 263, 103, 743, 327, 167, 44, 39, 42, 44,
+ 170, 44, 74, 74, 76, 74, 39, 71, 76, 333,
+ 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106,
+ 44, 39, 42, 71, 76, 333, 207, 58, 199, 74,
+ 583, 775, 295, 39, 231, 44, 106, 108, 44, 266,
+ 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268,
+ 53, 333, 85, 71, 39, 71, 39, 39, 135, 231,
+ 103, 39, 39, 71, 135, 44, 71, 204, 76, 39,
+ 167, 38, 204, 333, 135, 39, 122, 501, 58, 53,
+ 122, 76, 218, 333, 335, 58, 44, 58, 44, 58,
+ 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42,
+ 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90,
+ 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76,
+ 74, 76, 39, 333, 213, 199, 74, 76, 135, 108,
+ 39, 106, 71, 234, 103, 140, 423, 44, 74, 76,
+ 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41,
+ 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319,
+ 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151,
+ 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551,
+ 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108,
+ 583, 108, 85, 583, 76, 423, 103, 76, 1671, 76,
+ 42, 236, 266, 44, 74, 364, 117, 38, 117, 55,
+ 39, 44, 333, 335, 213, 49, 149, 108, 61, 333,
+ 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138,
+ 76, 106, 74, 44, 202, 108, 58, 85, 333, 967,
+ 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76,
+ 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44,
+ 74, 268, 202, 332, 44, 333, 333, 245, 38, 213,
+ 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44,
+ 74, 231, 333, 245, 346, 300, 314, 76, 42, 967,
+ 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415,
+ 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159,
+ 266, 268, 74, 76, 181, 333, 103, 333, 967, 198,
+ 85, 277, 108, 53, 428, 42, 236, 135, 44, 135,
+ 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260,
+ 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265,
+ 261, 265, 197, 201, 261, 41, 41, 41, 94, 229,
+ 265, 453, 261, 264, 261, 264, 261, 264, 165, 69,
+ 137, 40, 56, 37, 120, 101, 69, 137, 40, 120,
+ 133, 69, 137, 120, 261, 169, 120, 101, 69, 137,
+ 40, 88, 381, 162, 209, 85, 52, 51, 54, 84,
+ 51, 54, 52, 277, 59, 60, 162, 61, 309, 52,
+ 51, 149, 80, 117, 57, 54, 50, 373, 57, 53,
+ 48, 341, 61, 162, 194, 47, 38, 207, 121, 54,
+ 50, 38, 335, 121, 54, 50, 422, 855, 428, 139,
+ 44, 107, 396, 90, 41, 154, 41, 90, 37, 105,
+ 69, 105, 37, 58, 41, 90, 57, 169, 218, 41,
+ 58, 41, 58, 41, 58, 137, 58, 37, 137, 37,
+ 135, 37, 90, 69, 73, 185, 94, 101, 58, 57,
+ 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186,
+ 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018,
+ 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666,
+ 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217,
+ 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57,
+ 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50,
+ 54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
+ 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50,
+ 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54,
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
+ 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281,
+ 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69,
+ 254, 105, 37, 94, 37, 94, 165, 70, 105, 37,
+ 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221,
+ 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231,
+ 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52,
+ 51, 117, 52, 51, 53, 52, 51, 309, 49, 85,
+ 49, 53, 52, 51, 85, 52, 51, 54, 50, 54,
+ 50, 54, 50, 54, 50, 181, 38, 341, 81, 858,
+ 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54,
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 90,
+ 54, 50, 54, 50, 54, 50, 54, 50, 49, 54,
+ 82, 58, 302, 140, 74, 49, 166, 90, 110, 38,
+ 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887,
+ 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178,
+ 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274,
+ 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38,
+ 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333,
+ 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798,
+ 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69,
+ 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382,
+ 70, 37, 231, 44, 103, 44, 135, 44, 743, 74,
+ 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74,
+ 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333,
+ 903, 268, 85, 743, 364, 74, 53, 935, 108, 42,
+ 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333,
+ 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263,
+ 44, 42, 333, 149, 519, 38, 199, 122, 39, 42,
+ 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44,
+ 39, 71, 38, 85, 359, 42, 76, 74, 85, 39,
+ 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74,
+ 44, 74, 44, 74, 53, 42, 44, 333, 39, 39,
+ 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399,
+ 229, 165, 39, 44, 327, 57, 423, 167, 39, 71,
+ 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55,
+ 58, 524, 245, 54, 50, 53, 236, 53, 81, 80,
+ 54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
+ 54, 50, 54, 50, 54, 50, 85, 54, 50, 149,
+ 112, 117, 149, 49, 54, 50, 54, 50, 54, 50,
+ 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34,
+ 117, 55, 117, 54, 50, 53, 57, 53, 49, 85,
+ 333, 85, 121, 85, 841, 54, 53, 50, 56, 48,
+ 56, 837, 54, 57, 50, 57, 54, 50, 53, 54,
+ 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199,
+ 103, 87, 57, 56, 58, 87, 58, 153, 90, 98,
+ 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455,
+ 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575,
+ 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263,
+ 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71,
+ 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799,
+ 71, 39, 108, 76, 140, 135, 103, 871, 108, 44,
+ 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615,
+ 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655,
+ 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34,
+ 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149,
+ 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383,
+ 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182,
+ 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898,
+ 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236,
+ 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837,
+ 841, 229, 581, 841, 837, 41, 73, 41, 73, 137,
+ 265, 133, 37, 229, 357, 841, 837, 73, 137, 265,
+ 233, 837, 73, 137, 169, 41, 233, 837, 841, 837,
+ 841, 837, 841, 837, 841, 837, 841, 837, 841, 901,
+ 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
+ 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
+ 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71,
+ 39, 39, 327, 135, 39, 39, 39, 39, 39, 39,
+ 103, 71, 39, 39, 39, 39, 39, 39, 71, 39,
+ 135, 231, 135, 135, 39, 327, 551, 103, 167, 551,
+ 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946,
+ 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210,
+ 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266,
+ 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351,
+ 34, 3074, 7692, 63, 63,
+ };
+
+static int sqlite3Fts5UnicodeCategory(u32 iCode) {
+ int iRes = -1;
+ int iHi;
+ int iLo;
+ int ret;
+ u16 iKey;
+
+ if( iCode>=(1<<20) ){
+ return 0;
+ }
+ iLo = aFts5UnicodeBlock[(iCode>>16)];
+ iHi = aFts5UnicodeBlock[1+(iCode>>16)];
+ iKey = (iCode & 0xFFFF);
+ while( iHi>iLo ){
+ int iTest = (iHi + iLo) / 2;
+ assert( iTest>=iLo && iTest<iHi );
+ if( iKey>=aFts5UnicodeMap[iTest] ){
+ iRes = iTest;
+ iLo = iTest+1;
+ }else{
+ iHi = iTest;
+ }
+ }
+
+ if( iRes<0 ) return 0;
+ if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0;
+ ret = aFts5UnicodeData[iRes] & 0x1F;
+ if( ret!=30 ) return ret;
+ return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9;
+}
+
+static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
+ int i = 0;
+ int iTbl = 0;
+ while( i<128 ){
+ int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
+ int n = (aFts5UnicodeData[iTbl] >> 5) + i;
+ for(; i<128 && i<n; i++){
+ aAscii[i] = (u8)bToken;
+ }
+ iTbl++;
+ }
+}
+
/*
** 2015 May 30
**
@@ -198556,7 +229149,7 @@ static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){
u8 n;
p -= 2;
n = sqlite3Fts5GetVarint(p, &v64);
- *v = (u32)v64;
+ *v = ((u32)v64) & 0x7FFFFFFF;
assert( n>3 && n<=9 );
return n;
}
@@ -198784,7 +229377,7 @@ static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){
v >>= 7;
}
return 9;
- }
+ }
n = 0;
do{
buf[n++] = (u8)((v & 0x7f) | 0x80);
@@ -198823,7 +229416,6 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
return 5;
}
-
/*
** 2015 May 08
**
@@ -198837,7 +229429,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
******************************************************************************
**
** This is an SQLite virtual table module implementing direct access to an
-** existing FTS5 index. The module may create several different types of
+** existing FTS5 index. The module may create several different types of
** tables:
**
** col:
@@ -198845,16 +229437,21 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
**
** One row for each term/column combination. The value of $doc is set to
** the number of fts5 rows that contain at least one instance of term
-** $term within column $col. Field $cnt is set to the total number of
-** instances of term $term in column $col (in any row of the fts5 table).
+** $term within column $col. Field $cnt is set to the total number of
+** instances of term $term in column $col (in any row of the fts5 table).
**
** row:
** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
**
** One row for each term in the database. The value of $doc is set to
** the number of fts5 rows that contain at least one instance of term
-** $term. Field $cnt is set to the total number of instances of term
+** $term. Field $cnt is set to the total number of instances of term
** $term in the database.
+**
+** instance:
+** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
+**
+** One row for each term instance in the database.
*/
@@ -198870,13 +229467,14 @@ struct Fts5VocabTable {
char *zFts5Db; /* Db containing fts5 table */
sqlite3 *db; /* Database handle */
Fts5Global *pGlobal; /* FTS5 global object for this database */
- int eType; /* FTS5_VOCAB_COL or ROW */
+ int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */
+ unsigned bBusy; /* True if busy */
};
struct Fts5VocabCursor {
sqlite3_vtab_cursor base;
sqlite3_stmt *pStmt; /* Statement holding lock on pIndex */
- Fts5Index *pIndex; /* Associated FTS5 index */
+ Fts5Table *pFts5; /* Associated FTS5 table */
int bEof; /* True if this cursor is at EOF */
Fts5IndexIter *pIter; /* Term/rowid iterator object */
@@ -198885,21 +229483,26 @@ struct Fts5VocabCursor {
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
/* These are used by 'col' tables only */
- Fts5Config *pConfig; /* Fts5 table configuration */
int iCol;
i64 *aCnt;
i64 *aDoc;
- /* Output values used by 'row' and 'col' tables */
+ /* Output values used by all tables. */
i64 rowid; /* This table's current rowid value */
Fts5Buffer term; /* Current value of 'term' column */
+
+ /* Output values Used by 'instance' tables only */
+ i64 iInstPos;
+ int iInstOff;
};
-#define FTS5_VOCAB_COL 0
-#define FTS5_VOCAB_ROW 1
+#define FTS5_VOCAB_COL 0
+#define FTS5_VOCAB_ROW 1
+#define FTS5_VOCAB_INSTANCE 2
#define FTS5_VOCAB_COL_SCHEMA "term, col, doc, cnt"
#define FTS5_VOCAB_ROW_SCHEMA "term, doc, cnt"
+#define FTS5_VOCAB_INST_SCHEMA "term, doc, col, offset"
/*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
@@ -198910,7 +229513,7 @@ struct Fts5VocabCursor {
/*
-** Translate a string containing an fts5vocab table type to an
+** Translate a string containing an fts5vocab table type to an
** FTS5_VOCAB_XXX constant. If successful, set *peType to the output
** value and return SQLITE_OK. Otherwise, set *pzErr to an error message
** and return SQLITE_ERROR.
@@ -198927,6 +229530,9 @@ static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
if( sqlite3_stricmp(zCopy, "row")==0 ){
*peType = FTS5_VOCAB_ROW;
}else
+ if( sqlite3_stricmp(zCopy, "instance")==0 ){
+ *peType = FTS5_VOCAB_INSTANCE;
+ }else
{
*pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
rc = SQLITE_ERROR;
@@ -198985,9 +229591,10 @@ static int fts5VocabInitVtab(
sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
char **pzErr /* Write any error message here */
){
- const char *azSchema[] = {
- "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
- "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")"
+ const char *azSchema[] = {
+ "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
+ "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")",
+ "CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
};
Fts5VocabTable *pRet = 0;
@@ -199004,10 +229611,10 @@ static int fts5VocabInitVtab(
const char *zDb = bDb ? argv[3] : argv[1];
const char *zTab = bDb ? argv[4] : argv[3];
const char *zType = bDb ? argv[5] : argv[4];
- int nDb = (int)strlen(zDb)+1;
+ int nDb = (int)strlen(zDb)+1;
int nTab = (int)strlen(zTab)+1;
int eType = 0;
-
+
rc = fts5VocabTableType(zType, pzErr, &eType);
if( rc==SQLITE_OK ){
assert( eType>=0 && eType<ArraySize(azSchema) );
@@ -199059,8 +229666,17 @@ static int fts5VocabCreateMethod(
return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
}
-/*
+/*
** Implementation of the xBestIndex method.
+**
+** Only constraints of the form:
+**
+** term <= ?
+** term == ?
+** term >= ?
+**
+** are interpreted. Less-than and less-than-or-equal are treated
+** identically, as are greater-than and greater-than-or-equal.
*/
static int fts5VocabBestIndexMethod(
sqlite3_vtab *pUnused,
@@ -199110,8 +229726,8 @@ static int fts5VocabBestIndexMethod(
** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the
** sqlite3_index_info.orderByConsumed flag to tell the core the results
** are already in sorted order. */
- if( pInfo->nOrderBy==1
- && pInfo->aOrderBy[0].iColumn==0
+ if( pInfo->nOrderBy==1
+ && pInfo->aOrderBy[0].iColumn==0
&& pInfo->aOrderBy[0].desc==0
){
pInfo->orderByConsumed = 1;
@@ -199125,17 +229741,22 @@ static int fts5VocabBestIndexMethod(
** Implementation of xOpen method.
*/
static int fts5VocabOpenMethod(
- sqlite3_vtab *pVTab,
+ sqlite3_vtab *pVTab,
sqlite3_vtab_cursor **ppCsr
){
Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
- Fts5Index *pIndex = 0;
- Fts5Config *pConfig = 0;
+ Fts5Table *pFts5 = 0;
Fts5VocabCursor *pCsr = 0;
int rc = SQLITE_OK;
sqlite3_stmt *pStmt = 0;
char *zSql = 0;
+ if( pTab->bBusy ){
+ pVTab->zErrMsg = sqlite3_mprintf(
+ "recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
+ );
+ return SQLITE_ERROR;
+ }
zSql = sqlite3Fts5Mprintf(&rc,
"SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
@@ -199147,33 +229768,38 @@ static int fts5VocabOpenMethod(
assert( rc==SQLITE_OK || pStmt==0 );
if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
+ pTab->bBusy = 1;
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
i64 iId = sqlite3_column_int64(pStmt, 0);
- pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &pConfig);
+ pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
}
+ pTab->bBusy = 0;
- if( rc==SQLITE_OK && pIndex==0 ){
- rc = sqlite3_finalize(pStmt);
- pStmt = 0;
- if( rc==SQLITE_OK ){
- pVTab->zErrMsg = sqlite3_mprintf(
- "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
- );
- rc = SQLITE_ERROR;
+ if( rc==SQLITE_OK ){
+ if( pFts5==0 ){
+ rc = sqlite3_finalize(pStmt);
+ pStmt = 0;
+ if( rc==SQLITE_OK ){
+ pVTab->zErrMsg = sqlite3_mprintf(
+ "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
+ );
+ rc = SQLITE_ERROR;
+ }
+ }else{
+ rc = sqlite3Fts5FlushToDisk(pFts5);
}
}
if( rc==SQLITE_OK ){
- int nByte = pConfig->nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
+ int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
}
if( pCsr ){
- pCsr->pIndex = pIndex;
+ pCsr->pFts5 = pFts5;
pCsr->pStmt = pStmt;
- pCsr->pConfig = pConfig;
pCsr->aCnt = (i64*)&pCsr[1];
- pCsr->aDoc = &pCsr->aCnt[pConfig->nCol];
+ pCsr->aDoc = &pCsr->aCnt[pFts5->pConfig->nCol];
}else{
sqlite3_finalize(pStmt);
}
@@ -199189,6 +229815,7 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
sqlite3_free(pCsr->zLeTerm);
pCsr->nLeTerm = -1;
pCsr->zLeTerm = 0;
+ pCsr->bEof = 0;
}
/*
@@ -199204,6 +229831,56 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
return SQLITE_OK;
}
+static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
+ int rc = SQLITE_OK;
+
+ if( sqlite3Fts5IterEof(pCsr->pIter) ){
+ pCsr->bEof = 1;
+ }else{
+ const char *zTerm;
+ int nTerm;
+ zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
+ if( pCsr->nLeTerm>=0 ){
+ int nCmp = MIN(nTerm, pCsr->nLeTerm);
+ int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
+ if( bCmp<0 || (bCmp==0 && pCsr->nLeTerm<nTerm) ){
+ pCsr->bEof = 1;
+ }
+ }
+
+ sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
+ }
+ return rc;
+}
+
+static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
+ int eDetail = pCsr->pFts5->pConfig->eDetail;
+ int rc = SQLITE_OK;
+ Fts5IndexIter *pIter = pCsr->pIter;
+ i64 *pp = &pCsr->iInstPos;
+ int *po = &pCsr->iInstOff;
+
+ assert( sqlite3Fts5IterEof(pIter)==0 );
+ assert( pCsr->bEof==0 );
+ while( eDetail==FTS5_DETAIL_NONE
+ || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
+ ){
+ pCsr->iInstPos = 0;
+ pCsr->iInstOff = 0;
+
+ rc = sqlite3Fts5IterNextScan(pCsr->pIter);
+ if( rc==SQLITE_OK ){
+ rc = fts5VocabInstanceNewTerm(pCsr);
+ if( pCsr->bEof || eDetail==FTS5_DETAIL_NONE ) break;
+ }
+ if( rc ){
+ pCsr->bEof = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
/*
** Advance the cursor to the next row in the table.
@@ -199212,17 +229889,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
int rc = SQLITE_OK;
- int nCol = pCsr->pConfig->nCol;
+ int nCol = pCsr->pFts5->pConfig->nCol;
pCsr->rowid++;
+ if( pTab->eType==FTS5_VOCAB_INSTANCE ){
+ return fts5VocabInstanceNext(pCsr);
+ }
+
if( pTab->eType==FTS5_VOCAB_COL ){
for(pCsr->iCol++; pCsr->iCol<nCol; pCsr->iCol++){
if( pCsr->aDoc[pCsr->iCol] ) break;
}
}
- if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=nCol ){
+ if( pTab->eType!=FTS5_VOCAB_COL || pCsr->iCol>=nCol ){
if( sqlite3Fts5IterEof(pCsr->pIter) ){
pCsr->bEof = 1;
}else{
@@ -199230,6 +229911,7 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
int nTerm;
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
+ assert( nTerm>=0 );
if( pCsr->nLeTerm>=0 ){
int nCmp = MIN(nTerm, pCsr->nLeTerm);
int bCmp = memcmp(pCsr->zLeTerm, zTerm, nCmp);
@@ -199246,26 +229928,29 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
while( rc==SQLITE_OK ){
+ int eDetail = pCsr->pFts5->pConfig->eDetail;
const u8 *pPos; int nPos; /* Position list */
i64 iPos = 0; /* 64-bit position read from poslist */
int iOff = 0; /* Current offset within position list */
pPos = pCsr->pIter->pData;
nPos = pCsr->pIter->nData;
- switch( pCsr->pConfig->eDetail ){
- case FTS5_DETAIL_FULL:
- pPos = pCsr->pIter->pData;
- nPos = pCsr->pIter->nData;
- if( pTab->eType==FTS5_VOCAB_ROW ){
+
+ switch( pTab->eType ){
+ case FTS5_VOCAB_ROW:
+ if( eDetail==FTS5_DETAIL_FULL ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
pCsr->aCnt[0]++;
}
- pCsr->aDoc[0]++;
- }else{
+ }
+ pCsr->aDoc[0]++;
+ break;
+
+ case FTS5_VOCAB_COL:
+ if( eDetail==FTS5_DETAIL_FULL ){
int iCol = -1;
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
int ii = FTS5_POS2COLUMN(iPos);
- pCsr->aCnt[ii]++;
if( iCol!=ii ){
if( ii>=nCol ){
rc = FTS5_CORRUPT;
@@ -199274,14 +229959,9 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
pCsr->aDoc[ii]++;
iCol = ii;
}
+ pCsr->aCnt[ii]++;
}
- }
- break;
-
- case FTS5_DETAIL_COLUMNS:
- if( pTab->eType==FTS5_VOCAB_ROW ){
- pCsr->aDoc[0]++;
- }else{
+ }else if( eDetail==FTS5_DETAIL_COLUMNS ){
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff,&iPos) ){
assert_nc( iPos>=0 && iPos<nCol );
if( iPos>=nCol ){
@@ -199290,22 +229970,27 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
}
pCsr->aDoc[iPos]++;
}
+ }else{
+ assert( eDetail==FTS5_DETAIL_NONE );
+ pCsr->aDoc[0]++;
}
break;
- default:
- assert( pCsr->pConfig->eDetail==FTS5_DETAIL_NONE );
- pCsr->aDoc[0]++;
+ default:
+ assert( pTab->eType==FTS5_VOCAB_INSTANCE );
break;
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IterNextScan(pCsr->pIter);
}
+ if( pTab->eType==FTS5_VOCAB_INSTANCE ) break;
if( rc==SQLITE_OK ){
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
- if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ){
+ if( nTerm!=pCsr->term.n
+ || (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm))
+ ){
break;
}
if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
@@ -199315,8 +230000,10 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
}
if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
- while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++;
- assert( pCsr->iCol<pCsr->pConfig->nCol );
+ for(/* noop */; pCsr->iCol<nCol && pCsr->aDoc[pCsr->iCol]==0; pCsr->iCol++);
+ if( pCsr->iCol==nCol ){
+ rc = FTS5_CORRUPT;
+ }
}
return rc;
}
@@ -199331,7 +230018,9 @@ static int fts5VocabFilterMethod(
int nUnused, /* Number of elements in apVal */
sqlite3_value **apVal /* Arguments for the indexing scheme */
){
+ Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+ int eType = pTab->eType;
int rc = SQLITE_OK;
int iVal = 0;
@@ -199361,6 +230050,7 @@ static int fts5VocabFilterMethod(
}
if( pLe ){
const char *zCopy = (const char *)sqlite3_value_text(pLe);
+ if( zCopy==0 ) zCopy = "";
pCsr->nLeTerm = sqlite3_value_bytes(pLe);
pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1);
if( pCsr->zLeTerm==0 ){
@@ -199371,19 +230061,25 @@ static int fts5VocabFilterMethod(
}
}
-
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5IndexQuery(pCsr->pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
+ Fts5Index *pIndex = pCsr->pFts5->pIndex;
+ rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
+ rc = fts5VocabInstanceNewTerm(pCsr);
+ }
+ if( rc==SQLITE_OK && !pCsr->bEof
+ && (eType!=FTS5_VOCAB_INSTANCE
+ || pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE)
+ ){
rc = fts5VocabNextMethod(pCursor);
}
return rc;
}
-/*
-** This is the xEof method of the virtual table. SQLite calls this
+/*
+** This is the xEof method of the virtual table. SQLite calls this
** routine to find out if it has reached the end of a result set.
*/
static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){
@@ -199397,7 +230093,7 @@ static int fts5VocabColumnMethod(
int iCol /* Index of column to read value from */
){
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
- int eDetail = pCsr->pConfig->eDetail;
+ int eDetail = pCsr->pFts5->pConfig->eDetail;
int eType = ((Fts5VocabTable*)(pCursor->pVtab))->eType;
i64 iVal = 0;
@@ -199409,7 +230105,7 @@ static int fts5VocabColumnMethod(
assert( iCol==1 || iCol==2 || iCol==3 );
if( iCol==1 ){
if( eDetail!=FTS5_DETAIL_NONE ){
- const char *z = pCsr->pConfig->azCol[pCsr->iCol];
+ const char *z = pCsr->pFts5->pConfig->azCol[pCsr->iCol];
sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
}
}else if( iCol==2 ){
@@ -199417,26 +230113,54 @@ static int fts5VocabColumnMethod(
}else{
iVal = pCsr->aCnt[pCsr->iCol];
}
- }else{
+ }else if( eType==FTS5_VOCAB_ROW ){
assert( iCol==1 || iCol==2 );
if( iCol==1 ){
iVal = pCsr->aDoc[0];
}else{
iVal = pCsr->aCnt[0];
}
+ }else{
+ assert( eType==FTS5_VOCAB_INSTANCE );
+ switch( iCol ){
+ case 1:
+ sqlite3_result_int64(pCtx, pCsr->pIter->iRowid);
+ break;
+ case 2: {
+ int ii = -1;
+ if( eDetail==FTS5_DETAIL_FULL ){
+ ii = FTS5_POS2COLUMN(pCsr->iInstPos);
+ }else if( eDetail==FTS5_DETAIL_COLUMNS ){
+ ii = (int)pCsr->iInstPos;
+ }
+ if( ii>=0 && ii<pCsr->pFts5->pConfig->nCol ){
+ const char *z = pCsr->pFts5->pConfig->azCol[ii];
+ sqlite3_result_text(pCtx, z, -1, SQLITE_STATIC);
+ }
+ break;
+ }
+ default: {
+ assert( iCol==3 );
+ if( eDetail==FTS5_DETAIL_FULL ){
+ int ii = FTS5_POS2OFFSET(pCsr->iInstPos);
+ sqlite3_result_int(pCtx, ii);
+ }
+ break;
+ }
+ }
}
if( iVal>0 ) sqlite3_result_int64(pCtx, iVal);
return SQLITE_OK;
}
-/*
+/*
** This is the xRowid method. The SQLite core calls this routine to
** retrieve the rowid for the current row of the result set. The
** rowid should be written to *pRowid.
*/
static int fts5VocabRowidMethod(
- sqlite3_vtab_cursor *pCursor,
+ sqlite3_vtab_cursor *pCursor,
sqlite_int64 *pRowid
){
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
@@ -199469,6 +230193,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
+ /* xShadowName */ 0
};
void *p = (void*)pGlobal;
@@ -199477,8 +230202,316 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
-
-
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
/************** End of fts5.c ************************************************/
+/************** Begin file stmt.c ********************************************/
+/*
+** 2017-05-31
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file demonstrates an eponymous virtual table that returns information
+** about all prepared statements for the database connection.
+**
+** Usage example:
+**
+** .load ./stmt
+** .mode line
+** .header on
+** SELECT * FROM stmt;
+*/
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB)
+#if !defined(SQLITEINT_H)
+/* #include "sqlite3ext.h" */
+#endif
+SQLITE_EXTENSION_INIT1
+/* #include <assert.h> */
+/* #include <string.h> */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/* stmt_vtab is a subclass of sqlite3_vtab which will
+** serve as the underlying representation of a stmt virtual table
+*/
+typedef struct stmt_vtab stmt_vtab;
+struct stmt_vtab {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this stmt vtab */
+};
+
+/* stmt_cursor is a subclass of sqlite3_vtab_cursor which will
+** serve as the underlying representation of a cursor that scans
+** over rows of the result
+*/
+typedef struct stmt_cursor stmt_cursor;
+struct stmt_cursor {
+ sqlite3_vtab_cursor base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection for this cursor */
+ sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */
+ sqlite3_int64 iRowid; /* The rowid */
+};
+
+/*
+** The stmtConnect() method is invoked to create a new
+** stmt_vtab that describes the stmt virtual table.
+**
+** Think of this routine as the constructor for stmt_vtab objects.
+**
+** All this routine needs to do is:
+**
+** (1) Allocate the stmt_vtab object and initialize all fields.
+**
+** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
+** result set of queries against stmt will look like.
+*/
+static int stmtConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ stmt_vtab *pNew;
+ int rc;
+
+/* Column numbers */
+#define STMT_COLUMN_SQL 0 /* SQL for the statement */
+#define STMT_COLUMN_NCOL 1 /* Number of result columns */
+#define STMT_COLUMN_RO 2 /* True if read-only */
+#define STMT_COLUMN_BUSY 3 /* True if currently busy */
+#define STMT_COLUMN_NSCAN 4 /* SQLITE_STMTSTATUS_FULLSCAN_STEP */
+#define STMT_COLUMN_NSORT 5 /* SQLITE_STMTSTATUS_SORT */
+#define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */
+#define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */
+#define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */
+#define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */
+#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */
+
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
+ "reprep,run,mem)");
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3_malloc( sizeof(*pNew) );
+ *ppVtab = (sqlite3_vtab*)pNew;
+ if( pNew==0 ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for stmt_cursor objects.
+*/
+static int stmtDisconnect(sqlite3_vtab *pVtab){
+ sqlite3_free(pVtab);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new stmt_cursor object.
+*/
+static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ stmt_cursor *pCur;
+ pCur = sqlite3_malloc( sizeof(*pCur) );
+ if( pCur==0 ) return SQLITE_NOMEM;
+ memset(pCur, 0, sizeof(*pCur));
+ pCur->db = ((stmt_vtab*)p)->db;
+ *ppCursor = &pCur->base;
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a stmt_cursor.
+*/
+static int stmtClose(sqlite3_vtab_cursor *cur){
+ sqlite3_free(cur);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a stmt_cursor to its next row of output.
+*/
+static int stmtNext(sqlite3_vtab_cursor *cur){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ pCur->iRowid++;
+ pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the stmt_cursor
+** is currently pointing.
+*/
+static int stmtColumn(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ switch( i ){
+ case STMT_COLUMN_SQL: {
+ sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
+ break;
+ }
+ case STMT_COLUMN_NCOL: {
+ sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
+ break;
+ }
+ case STMT_COLUMN_RO: {
+ sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
+ break;
+ }
+ case STMT_COLUMN_BUSY: {
+ sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
+ break;
+ }
+ default: {
+ assert( i==STMT_COLUMN_MEM );
+ i = SQLITE_STMTSTATUS_MEMUSED +
+ STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
+ /* Fall thru */
+ }
+ case STMT_COLUMN_NSCAN:
+ case STMT_COLUMN_NSORT:
+ case STMT_COLUMN_NAIDX:
+ case STMT_COLUMN_NSTEP:
+ case STMT_COLUMN_REPREP:
+ case STMT_COLUMN_RUN: {
+ sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
+ i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return the rowid for the current row. In this implementation, the
+** rowid is the same as the output value.
+*/
+static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ *pRowid = pCur->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int stmtEof(sqlite3_vtab_cursor *cur){
+ stmt_cursor *pCur = (stmt_cursor*)cur;
+ return pCur->pStmt==0;
+}
+
+/*
+** This method is called to "rewind" the stmt_cursor object back
+** to the first row of output. This method is always called at least
+** once prior to any call to stmtColumn() or stmtRowid() or
+** stmtEof().
+*/
+static int stmtFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
+ pCur->pStmt = 0;
+ pCur->iRowid = 0;
+ return stmtNext(pVtabCursor);
+}
+
+/*
+** SQLite will invoke this method one or more times while planning a query
+** that uses the stmt virtual table. This routine needs to create
+** a query plan for each invocation and compute an estimated cost for that
+** plan.
+*/
+static int stmtBestIndex(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ pIdxInfo->estimatedCost = (double)500;
+ pIdxInfo->estimatedRows = 500;
+ return SQLITE_OK;
+}
+
+/*
+** This following structure defines all the methods for the
+** stmt virtual table.
+*/
+static sqlite3_module stmtModule = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ stmtConnect, /* xConnect */
+ stmtBestIndex, /* xBestIndex */
+ stmtDisconnect, /* xDisconnect */
+ 0, /* xDestroy */
+ stmtOpen, /* xOpen - open a cursor */
+ stmtClose, /* xClose - close a cursor */
+ stmtFilter, /* xFilter - configure scan constraints */
+ stmtNext, /* xNext - advance a cursor */
+ stmtEof, /* xEof - check for end of scan */
+ stmtColumn, /* xColumn - read data */
+ stmtRowid, /* xRowid - read data */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindMethod */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){
+ int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3_create_module(db, "sqlite_stmt", &stmtModule, 0);
+#endif
+ return rc;
+}
+
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+SQLITE_API int sqlite3_stmt_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi
+){
+ int rc = SQLITE_OK;
+ SQLITE_EXTENSION_INIT2(pApi);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ rc = sqlite3StmtVtabInit(db);
+#endif
+ return rc;
+}
+#endif /* SQLITE_CORE */
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
+
+/************** End of stmt.c ************************************************/
+#if __LINE__!=230511
+#undef SQLITE_SOURCE_ID
+#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0alt2"
+#endif
+/* Return the source-id for this library */
+SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+/************************** End of sqlite3.c ******************************/
diff --git a/3rdparty/sqlite3/sqlite3.h b/3rdparty/sqlite3/sqlite3.h
index d02aeb187ed..910b687aa7d 100644
--- a/3rdparty/sqlite3/sqlite3.h
+++ b/3rdparty/sqlite3/sqlite3.h
@@ -1,5 +1,5 @@
/*
-** 2001 September 15
+** 2001-09-15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
@@ -108,26 +108,28 @@ extern "C" {
** be held constant and Z will be incremented or else Y will be incremented
** and Z will be reset to zero.
**
-** Since [version 3.6.18] ([dateof:3.6.18]),
+** Since [version 3.6.18] ([dateof:3.6.18]),
** SQLite source code has been stored in the
** <a href="http://www.fossil-scm.org/">Fossil configuration management
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
** within its configuration management system. ^The SQLITE_SOURCE_ID
-** string contains the date and time of the check-in (UTC) and an SHA1
-** hash of the entire source tree.
+** string contains the date and time of the check-in (UTC) and a SHA1
+** or SHA3-256 hash of the entire source tree. If the source code has
+** been edited in any way since it was last checked in, then the last
+** four hexadecimal digits of the hash may be modified.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.15.1"
-#define SQLITE_VERSION_NUMBER 3015001
-#define SQLITE_SOURCE_ID "2016-11-04 12:08:49 1136863c76576110e710dd5d69ab6bf347c65e36"
+#define SQLITE_VERSION "3.33.0"
+#define SQLITE_VERSION_NUMBER 3033000
+#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 fca8dc8b578f215a969cd899336378966156154710873e68b3d9ac5881b0ff3f"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version, sqlite3_sourceid
+** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -139,7 +141,7 @@ extern "C" {
**
** <blockquote><pre>
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
-** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
+** assert( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,80)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** </pre></blockquote>)^
**
@@ -149,9 +151,11 @@ extern "C" {
** function is provided for use in DLLs since DLL users usually do not have
** direct access to string constants within the DLL. ^The
** sqlite3_libversion_number() function returns an integer equal to
-** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns
-** a pointer to a string constant whose value is the same as the
-** [SQLITE_SOURCE_ID] C preprocessor macro.
+** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns
+** a pointer to a string constant whose value is the same as the
+** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built
+** using an edited copy of [the amalgamation], then the last four characters
+** of the hash might be different from [SQLITE_SOURCE_ID].)^
**
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
@@ -163,20 +167,20 @@ SQLITE_API int sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
**
-** ^The sqlite3_compileoption_used() function returns 0 or 1
-** indicating whether the specified option was defined at
-** compile time. ^The SQLITE_ prefix may be omitted from the
-** option name passed to sqlite3_compileoption_used().
+** ^The sqlite3_compileoption_used() function returns 0 or 1
+** indicating whether the specified option was defined at
+** compile time. ^The SQLITE_ prefix may be omitted from the
+** option name passed to sqlite3_compileoption_used().
**
** ^The sqlite3_compileoption_get() function allows iterating
** over the list of options that were defined at compile time by
** returning the N-th compile time option string. ^If N is out of range,
-** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
-** prefix is omitted from any strings returned by
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
+** prefix is omitted from any strings returned by
** sqlite3_compileoption_get().
**
** ^Support for the diagnostic functions sqlite3_compileoption_used()
-** and sqlite3_compileoption_get() may be omitted by specifying the
+** and sqlite3_compileoption_get() may be omitted by specifying the
** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
**
** See also: SQL functions [sqlite_compileoption_used()] and
@@ -185,6 +189,9 @@ SQLITE_API int sqlite3_libversion_number(void);
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
SQLITE_API const char *sqlite3_compileoption_get(int N);
+#else
+# define sqlite3_compileoption_used(X) 0
+# define sqlite3_compileoption_get(X) ((void*)0)
#endif
/*
@@ -197,7 +204,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
** SQLite can be compiled with or without mutexes. When
** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
** are enabled and SQLite is threadsafe. When the
-** [SQLITE_THREADSAFE] macro is 0,
+** [SQLITE_THREADSAFE] macro is 0,
** the mutexes are omitted. Without the mutexes, it is not safe
** to use SQLite concurrently from more than one thread.
**
@@ -254,12 +261,16 @@ typedef struct sqlite3 sqlite3;
**
** ^The sqlite3_int64 and sqlite_int64 types can store integer values
** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
-** sqlite3_uint64 and sqlite_uint64 types can store integer values
+** sqlite3_uint64 and sqlite_uint64 types can store integer values
** between 0 and +18446744073709551615 inclusive.
*/
#ifdef SQLITE_INT64_TYPE
typedef SQLITE_INT64_TYPE sqlite_int64;
- typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
+# ifdef SQLITE_UINT64_TYPE
+ typedef SQLITE_UINT64_TYPE sqlite_uint64;
+# else
+ typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
+# endif
#elif defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 sqlite_int64;
typedef unsigned __int64 sqlite_uint64;
@@ -288,26 +299,22 @@ typedef sqlite_uint64 sqlite3_uint64;
** the [sqlite3] object is successfully destroyed and all associated
** resources are deallocated.
**
-** ^If the database connection is associated with unfinalized prepared
-** statements or unfinished sqlite3_backup objects then sqlite3_close()
-** will leave the database connection open and return [SQLITE_BUSY].
-** ^If sqlite3_close_v2() is called with unfinalized prepared statements
-** and/or unfinished sqlite3_backups, then the database connection becomes
-** an unusable "zombie" which will automatically be deallocated when the
-** last prepared statement is finalized or the last sqlite3_backup is
-** finished. The sqlite3_close_v2() interface is intended for use with
-** host languages that are garbage collected, and where the order in which
-** destructors are called is arbitrary.
-**
-** Applications should [sqlite3_finalize | finalize] all [prepared statements],
-** [sqlite3_blob_close | close] all [BLOB handles], and
+** Ideally, applications should [sqlite3_finalize | finalize] all
+** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
-** with the [sqlite3] object prior to attempting to close the object. ^If
-** sqlite3_close_v2() is called on a [database connection] that still has
-** outstanding [prepared statements], [BLOB handles], and/or
-** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
-** of resources is deferred until all [prepared statements], [BLOB handles],
-** and [sqlite3_backup] objects are also destroyed.
+** with the [sqlite3] object prior to attempting to close the object.
+** ^If the database connection is associated with unfinalized prepared
+** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
+** sqlite3_close() will leave the database connection open and return
+** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
+** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
+** it returns [SQLITE_OK] regardless, but instead of deallocating the database
+** connection immediately, it marks the database connection as an unusable
+** "zombie" and makes arrangements to automatically deallocate the database
+** connection after all prepared statements are finalized, all BLOB handles
+** are closed, and all backups have finished. The sqlite3_close_v2() interface
+** is intended for use with host languages that are garbage collected, and
+** where the order in which destructors are called is arbitrary.
**
** ^If an [sqlite3] object is destroyed while a transaction is open,
** the transaction is automatically rolled back.
@@ -337,7 +344,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** The sqlite3_exec() interface is a convenience wrapper around
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
** that allows an application to run multiple statements of SQL
-** without having to use a lot of C code.
+** without having to use a lot of C code.
**
** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
** semicolon-separate SQL statements passed into its 2nd argument,
@@ -377,7 +384,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** from [sqlite3_column_name()].
**
** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
-** to an empty string, or a pointer that contains only whitespace and/or
+** to an empty string, or a pointer that contains only whitespace and/or
** SQL comments, then no SQL statements are evaluated and the database
** is not changed.
**
@@ -413,7 +420,7 @@ SQLITE_API int sqlite3_exec(
*/
#define SQLITE_OK 0 /* Successful result */
/* beginning-of-error-codes */
-#define SQLITE_ERROR 1 /* SQL error or missing database */
+#define SQLITE_ERROR 1 /* Generic error */
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
#define SQLITE_PERM 3 /* Access permission denied */
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
@@ -428,7 +435,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Database is empty */
+#define SQLITE_EMPTY 16 /* Internal use only */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
@@ -436,7 +443,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
-#define SQLITE_FORMAT 24 /* Auxiliary database format error */
+#define SQLITE_FORMAT 24 /* Not used */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
@@ -462,6 +469,9 @@ SQLITE_API int sqlite3_exec(
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
+#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8))
+#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8))
+#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8))
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
@@ -490,18 +500,30 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8))
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8))
+#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
+#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
+#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
+#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
+#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
+#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
+#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
+#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
+#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
+#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
@@ -513,11 +535,13 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
+#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
+#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -540,14 +564,18 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
+#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
+#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
/* Reserved: 0x00F00000 */
+/* Legacy compatibility: */
+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
+
/*
** CAPI3REF: Device Characteristics
@@ -572,10 +600,15 @@ SQLITE_API int sqlite3_exec(
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
-** flag indicate that a file cannot be deleted when open. The
+** flag indicates that a file cannot be deleted when open. The
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
+**
+** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
+** filesystem supports doing multiple write operations atomically when those
+** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
+** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -591,6 +624,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
+#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
/*
** CAPI3REF: File Locking Levels
@@ -638,7 +672,7 @@ SQLITE_API int sqlite3_exec(
/*
** CAPI3REF: OS Interface Open File Handle
**
-** An [sqlite3_file] object represents an open file in the
+** An [sqlite3_file] object represents an open file in the
** [sqlite3_vfs | OS interface layer]. Individual OS interface
** implementations will
** want to subclass this object by appending additional fields
@@ -660,7 +694,7 @@ struct sqlite3_file {
** This object defines the methods used to perform various operations
** against the open file represented by the [sqlite3_file] object.
**
-** If the [sqlite3_vfs.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 [sqlite3_vfs.xOpen] reported that it failed. The
** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
@@ -722,6 +756,10 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_ATOMIC64K]
** <li> [SQLITE_IOCAP_SAFE_APPEND]
** <li> [SQLITE_IOCAP_SEQUENTIAL]
+** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
+** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
+** <li> [SQLITE_IOCAP_IMMUTABLE]
+** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -794,10 +832,19 @@ struct sqlite3_io_methods {
** file space based on this hint in order to help writes to the database
** file run faster.
**
+** <li>[[SQLITE_FCNTL_SIZE_LIMIT]]
+** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that
+** implements [sqlite3_deserialize()] to set an upper bound on the size
+** of the in-memory database. The argument is a pointer to a [sqlite3_int64].
+** If the integer pointed to is negative, then it is filled in with the
+** current limit. Otherwise the limit is set to the larger of the value
+** of the integer pointed to and the current database size. The integer
+** pointed to is set to the new limit.
+**
** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
** extends and truncates the database file in chunks of a size specified
-** by the user. The fourth argument to [sqlite3_file_control()] should
+** by the user. The fourth argument to [sqlite3_file_control()] should
** point to an integer (type int) containing the new chunk-size to use
** for the nominated database. Allocating database file space in large
** chunks (say 1MB at a time), may reduce file-system fragmentation and
@@ -820,24 +867,24 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_SYNC]]
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
** sent to the VFS immediately before the xSync method is invoked on a
-** database file descriptor. Or, if the xSync method is not invoked
-** because the user has configured SQLite with
-** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
+** database file descriptor. Or, if the xSync method is not invoked
+** because the user has configured SQLite with
+** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
** of the xSync method. In most cases, the pointer argument passed with
** this file-control is NULL. However, if the database file is being synced
** as part of a multi-database commit, the argument points to a nul-terminated
-** string containing the transactions master-journal file name. VFSes that
-** do not need this signal should silently ignore this opcode. Applications
-** should not call [sqlite3_file_control()] with this opcode as doing so may
-** disrupt the operation of the specialized VFSes that do require it.
+** string containing the transactions super-journal file name. VFSes that
+** do not need this signal should silently ignore this opcode. Applications
+** should not call [sqlite3_file_control()] with this opcode as doing so may
+** disrupt the operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]]
** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite
** and sent to the VFS after a transaction has been committed immediately
** but before the database is unlocked. VFSes that do not need this signal
** should silently ignore this opcode. Applications should not call
-** [sqlite3_file_control()] with this opcode as doing so may disrupt the
-** operation of the specialized VFSes that do require it.
+** [sqlite3_file_control()] with this opcode as doing so may disrupt the
+** operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
@@ -850,7 +897,7 @@ struct sqlite3_io_methods {
** opcode allows these two values (10 retries and 25 milliseconds of delay)
** to be adjusted. The values are changed for all database connections
** within the same process. The argument is a pointer to an array of two
-** integers where the first integer i the new retry count and the second
+** integers where the first integer is the new retry count and the second
** integer is the delay. If either integer is negative, then the setting
** is not changed but instead the prior value of that setting is written
** into the array entry, allowing the current retry settings to be
@@ -859,7 +906,8 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_PERSIST_WAL]]
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary
-** write ahead log and shared memory files used for transaction control
+** write ahead log ([WAL file]) and shared memory
+** files used for transaction control
** are automatically deleted when the latest connection to the database
** closes. Setting persistent WAL mode causes those files to persist after
** close. Persisting the files is useful when other processes that do not
@@ -884,13 +932,13 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_OVERWRITE]]
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
** a write transaction to indicate that, unless it is rolled back for some
-** reason, the entire database file will be overwritten by the current
+** reason, the entire database file will be overwritten by the current
** transaction. This is used by VACUUM operations.
**
** <li>[[SQLITE_FCNTL_VFSNAME]]
** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
** all [VFSes] in the VFS stack. The names are of all VFS shims and the
-** final bottom-level VFS are written into memory obtained from
+** final bottom-level VFS are written into memory obtained from
** [sqlite3_malloc()] and the result is stored in the char* variable
** that the fourth parameter of [sqlite3_file_control()] points to.
** The caller is responsible for freeing the memory when done. As with
@@ -909,7 +957,7 @@ struct sqlite3_io_methods {
** upper-most shim only.
**
** <li>[[SQLITE_FCNTL_PRAGMA]]
-** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
+** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
** file control is sent to the open [sqlite3_file] object corresponding
** to the database file to which the pragma statement refers. ^The argument
** to the [SQLITE_FCNTL_PRAGMA] file control is an array of
@@ -920,7 +968,7 @@ struct sqlite3_io_methods {
** of the char** argument point to a string obtained from [sqlite3_mprintf()]
** or the equivalent and that string will become the result of the pragma or
** the error message if the pragma fails. ^If the
-** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
+** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
** file control returns [SQLITE_OK], then the parser assumes that the
** VFS has handled the PRAGMA itself and the parser generates a no-op
@@ -937,16 +985,16 @@ struct sqlite3_io_methods {
** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access
-** to the connections busy-handler callback. The argument is of type (void **)
+** to the connection's busy-handler callback. The argument is of type (void**)
** - an array of two (void *) values. The first (void *) actually points
-** to a function of type (int (*)(void *)). In order to invoke the connections
+** to a function of type (int (*)(void *)). In order to invoke the connection's
** busy-handler, this function should be invoked with the second (void *) in
** the array as the only argument. If it returns non-zero, then the operation
** should be retried. If it returns zero, the custom VFS should abandon the
** current operation.
**
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
-** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
+** ^Applications can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses. The
@@ -960,7 +1008,7 @@ struct sqlite3_io_methods {
** The argument is a pointer to a value of type sqlite3_int64 that
** is an advisory maximum number of bytes in the file to memory map. The
** pointer is overwritten with the old value. The limit is not changed if
-** the value originally pointed to is negative, and so the current limit
+** the value originally pointed to is negative, and so the current limit
** can be queried by passing in a pointer to a negative number. This
** file-control is used internally to implement [PRAGMA mmap_size].
**
@@ -1004,7 +1052,80 @@ struct sqlite3_io_methods {
** <li>[[SQLITE_FCNTL_RBU]]
** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
-** this opcode.
+** this opcode.
+**
+** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
+** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
+** the file descriptor is placed in "batch write mode", which
+** means all subsequent write operations will be deferred and done
+** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
+** that do not support batch atomic writes will return SQLITE_NOTFOUND.
+** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
+** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
+** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
+** no VFS interface calls on the same [sqlite3_file] file descriptor
+** except for calls to the xWrite method and the xFileControl method
+** with [SQLITE_FCNTL_SIZE_HINT].
+**
+** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
+** operations since the previous successful call to
+** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
+** This file control returns [SQLITE_OK] if and only if the writes were
+** all performed successfully and have been committed to persistent storage.
+** ^Regardless of whether or not it is successful, this file control takes
+** the file descriptor out of batch write mode so that all subsequent
+** write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
+** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
+** operations since the previous successful call to
+** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
+** ^This file control takes the file descriptor out of batch write mode
+** so that all subsequent write operations are independent.
+** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
+** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
+**
+** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
+** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
+** to block for up to M milliseconds before failing when attempting to
+** obtain a file lock using the xLock or xShmLock methods of the VFS.
+** The parameter is a pointer to a 32-bit signed integer that contains
+** the value that M is to be set to. Before returning, the 32-bit signed
+** integer is overwritten with the previous value of M.
+**
+** <li>[[SQLITE_FCNTL_DATA_VERSION]]
+** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
+** a database file. The argument is a pointer to a 32-bit unsigned integer.
+** The "data version" for the pager is written into the pointer. The
+** "data version" changes whenever any change occurs to the corresponding
+** database file, either through SQL statements on the same database
+** connection or through transactions committed by separate database
+** connections possibly in other processes. The [sqlite3_total_changes()]
+** interface can be used to find if any database on the connection has changed,
+** but that interface responds to changes on TEMP as well as MAIN and does
+** not provide a mechanism to detect changes to MAIN only. Also, the
+** [sqlite3_total_changes()] interface responds to internal changes only and
+** omits changes made by other database connections. The
+** [PRAGMA data_version] command provides a mechanism to detect changes to
+** a single attached database that occur due to other database connections,
+** but omits changes implemented by the database connection on which it is
+** called. This file control is the only mechanism to detect changes that
+** happen either internally or externally and that are associated with
+** a particular attached database.
+**
+** <li>[[SQLITE_FCNTL_CKPT_START]]
+** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
+** in wal mode before the client starts to copy pages from the wal
+** file to the database file.
+**
+** <li>[[SQLITE_FCNTL_CKPT_DONE]]
+** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
+** in wal mode after the client has finished copying pages from the wal
+** file to the database file, but before the *-shm file is updated to
+** record the fact that the pages have been checkpointed.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1035,6 +1156,16 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
+#define SQLITE_FCNTL_PDB 30
+#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
+#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
+#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
+#define SQLITE_FCNTL_LOCK_TIMEOUT 34
+#define SQLITE_FCNTL_DATA_VERSION 35
+#define SQLITE_FCNTL_SIZE_LIMIT 36
+#define SQLITE_FCNTL_CKPT_DONE 37
+#define SQLITE_FCNTL_RESERVE_BYTES 38
+#define SQLITE_FCNTL_CKPT_START 39
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1072,12 +1203,18 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** 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
-** object when the iVersion value is increased. Note that the structure
-** of the sqlite3_vfs object changes in the transaction between
-** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not
-** modified.
+** The VFS interface is sometimes extended by adding new methods onto
+** the end. Each time such an extension occurs, the iVersion field
+** is incremented. The iVersion value started out as 1 in
+** SQLite [version 3.5.0] on [dateof:3.5.0], then increased to 2
+** with SQLite [version 3.7.0] on [dateof:3.7.0], and then increased
+** to 3 with SQLite [version 3.7.6] on [dateof:3.7.6]. Additional fields
+** may be appended to the sqlite3_vfs object and the iVersion value
+** may increase again in future versions of SQLite.
+** Note that due to an oversight, the structure
+** of the sqlite3_vfs object changed in the transition from
+** SQLite [version 3.5.9] to [version 3.6.0] on [dateof:3.6.0]
+** and yet the iVersion field was not increased.
**
** The szOsFile field is the size of the subclassed [sqlite3_file]
** structure used by this VFS. mxPathname is the maximum length of
@@ -1112,14 +1249,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** the [sqlite3_file] can safely store a pointer to the
** filename if it needs to remember the filename for some reason.
** If the zFilename parameter to xOpen is a NULL pointer then xOpen
-** must invent its own temporary name for the file. ^Whenever the
+** must invent its own temporary name for the file. ^Whenever the
** xFilename parameter is NULL it will also be the case that the
** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
**
** The flags argument to xOpen() includes all bits set in
** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
** or [sqlite3_open16()] is used, then flags includes at least
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
** If xOpen() opens a file read-only then it sets *pOutFlags to
** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
**
@@ -1133,7 +1270,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
** <li> [SQLITE_OPEN_TRANSIENT_DB]
** <li> [SQLITE_OPEN_SUBJOURNAL]
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
+** <li> [SQLITE_OPEN_SUPER_JOURNAL]
** <li> [SQLITE_OPEN_WAL]
** </ul>)^
**
@@ -1161,14 +1298,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
** with the [SQLITE_OPEN_CREATE] flag, which are both directly
** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
-** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
+** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
** SQLITE_OPEN_CREATE, is used to indicate that file should always
** be created, and that it is an error if it already exists.
-** It is <i>not</i> used to indicate the file should be opened
+** It is <i>not</i> used to indicate the file should be opened
** for exclusive access.
**
** ^At least szOsFile bytes of memory are allocated by SQLite
-** to hold the [sqlite3_file] structure passed as the third
+** to hold the [sqlite3_file] structure passed as the third
** argument to xOpen. The xOpen method does not have to
** allocate the structure; it should just fill it in. Note that
** the xOpen method must set the sqlite3_file.pMethods to either
@@ -1181,8 +1318,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** ^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]
-** to test whether a file is at least readable. The file can be a
-** directory.
+** to test whether a file is at least readable. The SQLITE_ACCESS_READ
+** flag is never actually used and is not implemented in the built-in
+** VFSes of SQLite. The file is named by the second argument and can be a
+** directory. The xAccess method returns [SQLITE_OK] on success or some
+** non-zero error code if there is an I/O error or if the name of
+** the file given in the second argument is illegal. If SQLITE_OK
+** is returned, then non-zero or zero is written into *pResOut to indicate
+** whether or not the file is accessible.
**
** ^SQLite will always allocate at least mxPathname+1 bytes for the
** output buffer xFullPathname. The exact size of the output buffer
@@ -1202,16 +1345,16 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** 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 multiplied by 86400000 (the number of milliseconds in
-** a 24-hour day).
+** 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
+** date and time if that method is available (if iVersion is 2 or
** greater and the function pointer is not NULL) and will fall back
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
**
** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
** are not used by the SQLite core. These optional interfaces are provided
-** by some VFSes to facilitate testing of the VFS code. By overriding
+** by some VFSes to facilitate testing of the VFS code. By overriding
** system calls with functions under its control, a test program can
** simulate faults and error conditions that would otherwise be difficult
** or impossible to induce. The set of system calls that can be overridden
@@ -1258,7 +1401,7 @@ struct sqlite3_vfs {
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
** New fields may be appended in future versions. The iVersion
- ** value will increment whenever this happens.
+ ** value will increment whenever this happens.
*/
};
@@ -1302,7 +1445,7 @@ struct sqlite3_vfs {
** </ul>
**
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
-** was given on the corresponding lock.
+** was given on the corresponding lock.
**
** The xShmLock method can transition between unlocked and SHARED or
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
@@ -1447,7 +1590,7 @@ SQLITE_API int sqlite3_config(int, ...);
** [database connection] (specified in the first argument).
**
** The second argument to sqlite3_db_config(D,V,...) is the
-** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
+** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
** that indicates what aspect of the [database connection] is being configured.
** Subsequent arguments vary depending on the configuration verb.
**
@@ -1465,7 +1608,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
** This object is used in only one place in the SQLite interface.
** A pointer to an instance of this object is the argument to
** [sqlite3_config()] when the configuration option is
-** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
+** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
** By creating an instance of this object
** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
** during configuration, an application can specify an alternative
@@ -1495,17 +1638,17 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
** allocators round up memory allocations at least to the next multiple
** of 8. Some allocators round up to a larger multiple or to a power of 2.
** Every memory allocation request coming in through [sqlite3_malloc()]
-** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
+** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator. For example,
-** it might allocate any require mutexes or initialize internal data
+** it might allocate any required mutexes or initialize internal data
** structures. The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
** by xInit. The pAppData pointer is used as the only parameter to
** xInit and xShutdown.
**
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
+** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
** the xInit method, so the xInit method need not be threadsafe. The
** xShutdown method is only called from [sqlite3_shutdown()] so it does
** not need to be threadsafe either. For all other methods, SQLite
@@ -1553,7 +1696,7 @@ struct sqlite3_mem_methods {
** by a single thread. ^If SQLite is compiled with
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
** it is not possible to change the [threading mode] from its default
-** value of Single-thread and so [sqlite3_config()] will return
+** value of Single-thread and so [sqlite3_config()] will return
** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
** configuration option.</dd>
**
@@ -1588,7 +1731,7 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
**
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
-** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
+** <dd> ^(The SQLITE_CONFIG_MALLOC 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
@@ -1605,12 +1748,23 @@ struct sqlite3_mem_methods {
** routines with a wrapper that simulations memory allocation failure or
** tracks memory usage, for example. </dd>
**
+** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
+** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
+** type int, interpreted as a boolean, which if true provides a hint to
+** SQLite that it should avoid large memory allocations if possible.
+** SQLite will run faster if it is free to make large memory allocations,
+** but some application might prefer to run slower in exchange for
+** guarantees about memory fragmentation that are possible if large
+** allocations are avoided. This hint is normally off.
+** </dd>
+**
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
** <dd> ^The SQLITE_CONFIG_MEMSTATUS 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 following SQLite interfaces become non-operational:
** <ul>
+** <li> [sqlite3_hard_heap_limit64()]
** <li> [sqlite3_memory_used()]
** <li> [sqlite3_memory_highwater()]
** <li> [sqlite3_soft_heap_limit64()]
@@ -1622,32 +1776,14 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt>
-** <dd> ^The SQLITE_CONFIG_SCRATCH option specifies a static memory buffer
-** that SQLite can use for scratch memory. ^(There are three arguments
-** to SQLITE_CONFIG_SCRATCH: A pointer an 8-byte
-** aligned memory buffer from which the scratch allocations will be
-** drawn, the size of each scratch allocation (sz),
-** and the maximum number of scratch allocations (N).)^
-** The first argument must be a pointer to an 8-byte aligned buffer
-** of at least sz*N bytes of memory.
-** ^SQLite will not use more than one scratch buffers per thread.
-** ^SQLite will never request a scratch buffer that is more than 6
-** times the database page size.
-** ^If SQLite needs needs additional
-** scratch memory beyond what is provided by this configuration option, then
-** [sqlite3_malloc()] will be used to obtain the memory needed.<p>
-** ^When the application provides any amount of scratch memory using
-** SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary large
-** [sqlite3_malloc|heap allocations].
-** This can help [Robson proof|prevent memory allocation failures] due to heap
-** fragmentation in low-memory embedded systems.
+** <dd> The SQLITE_CONFIG_SCRATCH option is no longer used.
** </dd>
**
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
** that SQLite can use for the database page cache with the default page
-** cache implementation.
-** This configuration option is a no-op if an application-define page
+** cache implementation.
+** This configuration option is a no-op if an application-defined page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned memory (pMem), the size of each page cache line (sz),
@@ -1674,10 +1810,9 @@ struct sqlite3_mem_methods {
** additional cache line. </dd>
**
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
-** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
+** <dd> ^The SQLITE_CONFIG_HEAP 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].
+** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
** [SQLITE_ERROR] if invoked otherwise.
@@ -1730,7 +1865,7 @@ struct sqlite3_mem_methods {
** configuration on individual connections.)^ </dd>
**
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
-** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
** the interface to a custom page cache implementation.)^
** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
@@ -1744,7 +1879,7 @@ struct sqlite3_mem_methods {
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
** global [error log].
** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
-** function with a call signature of void(*)(void*,int,const char*),
+** 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
** invoked by [sqlite3_log()] to process each logging event. ^If the
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
@@ -1853,7 +1988,7 @@ struct sqlite3_mem_methods {
** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
-** becomes the [statement journal] spill-to-disk threshold.
+** becomes the [statement journal] spill-to-disk threshold.
** [Statement journals] are held in memory until their size (in bytes)
** exceeds this threshold, at which point they are written to disk.
** Or if the threshold is -1, statement journals are always held
@@ -1863,6 +1998,33 @@ struct sqlite3_mem_methods {
** I/O required to support statement rollback.
** The default value for this setting is controlled by the
** [SQLITE_STMTJRNL_SPILL] compile-time option.
+**
+** [[SQLITE_CONFIG_SORTERREF_SIZE]]
+** <dt>SQLITE_CONFIG_SORTERREF_SIZE
+** <dd>The SQLITE_CONFIG_SORTERREF_SIZE option accepts a single parameter
+** of type (int) - the new value of the sorter-reference size threshold.
+** Usually, when SQLite uses an external sort to order records according
+** to an ORDER BY clause, all fields required by the caller are present in the
+** sorted records. However, if SQLite determines based on the declared type
+** of a table column that its values are likely to be very large - larger
+** than the configured sorter-reference size threshold - then a reference
+** is stored in each sorted record and the required column values loaded
+** from the database as records are returned in sorted order. The default
+** value for this option is to never use this optimization. Specifying a
+** negative value for this option restores the default behaviour.
+** This option is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
+**
+** [[SQLITE_CONFIG_MEMDB_MAXSIZE]]
+** <dt>SQLITE_CONFIG_MEMDB_MAXSIZE
+** <dd>The SQLITE_CONFIG_MEMDB_MAXSIZE option accepts a single parameter
+** [sqlite3_int64] parameter which is the default maximum size for an in-memory
+** database created using [sqlite3_deserialize()]. This default maximum
+** size can be adjusted up or down for individual databases using the
+** [SQLITE_FCNTL_SIZE_LIMIT] [sqlite3_file_control|file-control]. If this
+** configuration setting is never used, then the default maximum is determined
+** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
+** compile-time option is not set, then the default maximum is 1073741824.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1870,13 +2032,13 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
#define SQLITE_CONFIG_PCACHE 14 /* no-op */
#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
@@ -1891,6 +2053,9 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
+#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
+#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
+#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1906,8 +2071,9 @@ struct sqlite3_mem_methods {
** is invoked.
**
** <dl>
+** [[SQLITE_DBCONFIG_LOOKASIDE]]
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
-** <dd> ^This option takes three additional arguments that determine the
+** <dd> ^This option takes three additional arguments that determine the
** [lookaside memory allocator] configuration for the [database connection].
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
** pointer to a memory buffer to use for lookaside memory.
@@ -1925,9 +2091,10 @@ struct sqlite3_mem_methods {
** when the "current value" returned by
** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
** Any attempt to change the lookaside memory configuration when lookaside
-** memory is in use leaves the configuration unchanged and returns
+** memory is in use leaves the configuration unchanged and returns
** [SQLITE_BUSY].)^</dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
** <dd> ^This option is used to enable or disable the enforcement of
** [foreign key constraints]. There should be two additional arguments.
@@ -1938,6 +2105,7 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the FK enforcement setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_TRIGGER]]
** <dt>SQLITE_DBCONFIG_ENABLE_TRIGGER</dt>
** <dd> ^This option is used to enable or disable [CREATE TRIGGER | triggers].
** There should be two additional arguments.
@@ -1948,9 +2116,21 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
+** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
+** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable views,
+** positive to enable views or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether views are disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the view setting is not reported back. </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
-** <dd> ^This option is used to enable or disable the two-argument
-** version of the [fts3_tokenizer()] function which is part of the
+** <dd> ^This option is used to enable or disable the
+** [fts3_tokenizer()] function which is part of the
** [FTS3] full-text search engine extension.
** There should be two additional arguments.
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
@@ -1961,6 +2141,7 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the new setting is not reported back. </dd>
**
+** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]]
** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
** interface independently of the [load_extension()] SQL function.
@@ -1978,7 +2159,7 @@ struct sqlite3_mem_methods {
** be a NULL pointer, in which case the new setting is not reported back.
** </dd>
**
-** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
+** [[SQLITE_DBCONFIG_MAINDBNAME]] <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
** <dd> ^This option is used to change the name of the "main" database
** schema. ^The sole argument is a pointer to a constant UTF8 string
** which will become the new schema name in place of "main". ^SQLite
@@ -1987,6 +2168,162 @@ struct sqlite3_mem_methods {
** until after the database connection closes.
** </dd>
**
+** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
+** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
+** <dd> Usually, when a database in wal mode is closed or detached from a
+** database handle, SQLite checks if this will mean that there are now no
+** connections at all to the database. If so, it performs a checkpoint
+** operation before closing the connection. This option may be used to
+** override this behaviour. The first parameter passed to this operation
+** is an integer - positive to disable checkpoints-on-close, or zero (the
+** default) to enable them, and negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer
+** into which is written 0 or 1 to indicate whether checkpoints-on-close
+** have been disabled - 0 if they are not disabled, 1 if they are.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_ENABLE_QPSG]] <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
+** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
+** the [query planner stability guarantee] (QPSG). When the QPSG is active,
+** a single SQL query statement will always use the same algorithm regardless
+** of values of [bound parameters].)^ The QPSG disables some query optimizations
+** that look at the values of bound parameters, which can make some queries
+** slower. But the QPSG has the advantage of more predictable behavior. With
+** the QPSG active, SQLite will always use the same query plan in the field as
+** was used during testing in the lab.
+** The first argument to this setting is an integer which is 0 to disable
+** the QPSG, positive to enable QPSG, or negative to leave the setting
+** unchanged. The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether the QPSG is disabled or enabled
+** following this call.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_TRIGGER_EQP]] <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
+** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
+** include output for any operations performed by trigger programs. This
+** option is used to set or clear (the default) a flag that governs this
+** behavior. The first parameter passed to this operation is an integer -
+** positive to enable output for trigger programs, or zero to disable it,
+** or negative to leave the setting unchanged.
+** The second parameter is a pointer to an integer into which is written
+** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
+** it is not disabled, 1 if it is.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_RESET_DATABASE]] <dt>SQLITE_DBCONFIG_RESET_DATABASE</dt>
+** <dd> Set the SQLITE_DBCONFIG_RESET_DATABASE flag and then run
+** [VACUUM] in order to reset a database back to an empty database
+** with no schema and no content. The following process works even for
+** a badly corrupted database file:
+** <ol>
+** <li> If the database connection is newly opened, make sure it has read the
+** database schema by preparing then discarding some query against the
+** database, or calling sqlite3_table_column_metadata(), ignoring any
+** errors. This step is only necessary if the application desires to keep
+** the database in WAL mode after the reset if it was in WAL mode before
+** the reset.
+** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
+** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
+** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
+** </ol>
+** Because resetting a database is destructive and irreversible, the
+** process requires the use of this obscure API and multiple steps to help
+** ensure that it does not happen by accident.
+**
+** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
+** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
+** "defensive" flag for a database connection. When the defensive
+** flag is enabled, language features that allow ordinary SQL to
+** deliberately corrupt the database file are disabled. The disabled
+** features include but are not limited to the following:
+** <ul>
+** <li> The [PRAGMA writable_schema=ON] statement.
+** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> Writes to the [sqlite_dbpage] virtual table.
+** <li> Direct writes to [shadow tables].
+** </ul>
+** </dd>
+**
+** [[SQLITE_DBCONFIG_WRITABLE_SCHEMA]] <dt>SQLITE_DBCONFIG_WRITABLE_SCHEMA</dt>
+** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the
+** "writable_schema" flag. This has the same effect and is logically equivalent
+** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF].
+** The first argument to this setting is an integer which is 0 to disable
+** the writable_schema, positive to enable writable_schema, or negative to
+** leave the setting unchanged. The second parameter is a pointer to an
+** integer into which is written 0 or 1 to indicate whether the writable_schema
+** is enabled or disabled following this call.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]]
+** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt>
+** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates
+** the legacy behavior of the [ALTER TABLE RENAME] command such it
+** behaves as it did prior to [version 3.24.0] (2018-06-04). See the
+** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for
+** additional information. This feature can also be turned on and off
+** using the [PRAGMA legacy_alter_table] statement.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_DQS_DML]]
+** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
+** the legacy [double-quoted string literal] misfeature for DML statements
+** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
+** default value of this setting is determined by the [-DSQLITE_DQS]
+** compile-time option.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_DQS_DDL]]
+** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
+** the legacy [double-quoted string literal] misfeature for DDL statements,
+** such as CREATE TABLE and CREATE INDEX. The
+** default value of this setting is determined by the [-DSQLITE_DQS]
+** compile-time option.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
+** assume that database schemas are untainted by malicious content.
+** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
+** takes additional defensive steps to protect the application from harm
+** including:
+** <ul>
+** <li> Prohibit the use of SQL functions inside triggers, views,
+** CHECK constraints, DEFAULT clauses, expression indexes,
+** partial indexes, or generated columns
+** unless those functions are tagged with [SQLITE_INNOCUOUS].
+** <li> Prohibit the use of virtual tables inside of triggers or views
+** unless those virtual tables are tagged with [SQLITE_VTAB_INNOCUOUS].
+** </ul>
+** This setting defaults to "on" for legacy compatibility, however
+** all applications are advised to turn it off if possible. This setting
+** can also be controlled using the [PRAGMA trusted_schema] statement.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
+** the legacy file format flag. When activated, this flag causes all newly
+** created database file to have a schema format version number (the 4-byte
+** integer found at offset 44 into the database header) of 1. This in turn
+** means that the resulting database file will be readable and writable by
+** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
+** newly created databases are generally not understandable by SQLite versions
+** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
+** is now scarcely any need to generated database files that are compatible
+** all the way back to version 3.0.0, and so this setting is of little
+** practical use, but is provided so that SQLite can continue to claim the
+** ability to generate new database files that are compatible with version
+** 3.0.0.
+** <p>Note that when the SQLITE_DBCONFIG_LEGACY_FILE_FORMAT setting is on,
+** the [VACUUM] command will fail with an obscure error when attempting to
+** process a table with generated columns and a descending index. This is
+** not considered a bug since SQLite versions 3.3.0 and earlier do not support
+** either generated columns or decending indexes.
+** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -1995,7 +2332,19 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
-
+#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */
+#define SQLITE_DBCONFIG_TRIGGER_EQP 1008 /* int int* */
+#define SQLITE_DBCONFIG_RESET_DATABASE 1009 /* int int* */
+#define SQLITE_DBCONFIG_DEFENSIVE 1010 /* int int* */
+#define SQLITE_DBCONFIG_WRITABLE_SCHEMA 1011 /* int int* */
+#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
+#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
+#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
+#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
+#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2019,20 +2368,30 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
** the table has a column of type [INTEGER PRIMARY KEY] then that column
** is another alias for the rowid.
**
-** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the
-** most recent successful [INSERT] into a rowid table or [virtual table]
-** on database connection D.
-** ^Inserts into [WITHOUT ROWID] tables are not recorded.
-** ^If no successful [INSERT]s into rowid tables
-** have ever occurred on the database connection D,
-** then sqlite3_last_insert_rowid(D) returns zero.
-**
-** ^(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.)^
+** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
+** the most recent successful [INSERT] into a rowid table or [virtual table]
+** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
+** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
+** on the database connection D, then sqlite3_last_insert_rowid(D) returns
+** zero.
+**
+** As well as being set automatically as rows are inserted into database
+** tables, the value returned by this function may be set explicitly by
+** [sqlite3_set_last_insert_rowid()]
+**
+** Some virtual table implementations may INSERT rows into rowid tables as
+** part of committing a transaction (e.g. to flush data accumulated in memory
+** to disk). In this case subsequent calls to this function return the rowid
+** associated with these internal INSERT operations, which leads to
+** unintuitive results. Virtual table implementations that do write to rowid
+** tables in this way can avoid this problem by restoring the original
+** rowid value using [sqlite3_set_last_insert_rowid()] before returning
+** control to the user.
+**
+** ^(If an [INSERT] occurs within a trigger then this routine will
+** return the [rowid] of the inserted row as long as the trigger is
+** running. Once the trigger program ends, the value returned
+** by this routine reverts to what it was before the trigger was fired.)^
**
** ^An [INSERT] that fails due to a constraint violation is not a
** successful [INSERT] and does not change the value returned by this
@@ -2060,6 +2419,16 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
/*
+** CAPI3REF: Set the Last Insert Rowid value.
+** METHOD: sqlite3
+**
+** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
+** set the value returned by calling sqlite3_last_insert_rowid(D) to R
+** without inserting a row into the database.
+*/
+SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
+
+/*
** CAPI3REF: Count The Number Of Rows Modified
** METHOD: sqlite3
**
@@ -2070,45 +2439,50 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
** returned by this function.
**
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
-** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
-**
-** Changes to a view that are intercepted by
-** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
-** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
-** DELETE statement run on a view is always zero. Only changes made to real
+**
+** Changes to a view that are intercepted by
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
+** DELETE statement run on a view is always zero. Only changes made to real
** tables are counted.
**
** Things are more complicated if the sqlite3_changes() function is
** executed while a trigger program is running. This may happen if the
** program uses the [changes() SQL function], or if some other callback
** function invokes sqlite3_changes() directly. Essentially:
-**
+**
** <ul>
** <li> ^(Before entering a trigger program the value returned by
-** sqlite3_changes() function is saved. After the trigger program
+** sqlite3_changes() function is saved. After the trigger program
** has finished, the original value is restored.)^
-**
-** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
-** statement sets the value returned by sqlite3_changes()
-** upon completion as normal. Of course, this value will not include
-** any changes performed by sub-triggers, as the sqlite3_changes()
+**
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
+** statement sets the value returned by sqlite3_changes()
+** upon completion as normal. Of course, this value will not include
+** any changes performed by sub-triggers, as the sqlite3_changes()
** value will be saved and restored after each sub-trigger has run.)^
** </ul>
-**
+**
** ^This means that if the changes() SQL function (or similar) is used
-** by the first INSERT, UPDATE or DELETE statement within a trigger, it
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
** returns the value as set when the calling statement began executing.
-** ^If it is used by the second or subsequent such statement within a trigger
-** program, the value returned reflects the number of rows modified by the
+** ^If it is used by the second or subsequent such statement within a trigger
+** program, the value returned reflects the number of rows modified by the
** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
-** See also the [sqlite3_total_changes()] interface, the
-** [count_changes pragma], and the [changes() SQL function].
-**
** If a separate thread makes changes on the same database connection
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_total_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** </ul>
*/
SQLITE_API int sqlite3_changes(sqlite3*);
@@ -2121,18 +2495,31 @@ SQLITE_API int sqlite3_changes(sqlite3*);
** since the database connection was opened, including those executed as
** part of trigger programs. ^Executing any other type of SQL statement
** does not affect the value returned by sqlite3_total_changes().
-**
+**
** ^Changes made as part of [foreign key actions] are included in the
** count, but those made as part of REPLACE constraint resolution are
-** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
** are not counted.
-**
-** See also the [sqlite3_changes()] interface, the
-** [count_changes pragma], and the [total_changes() SQL function].
+**
+** The [sqlite3_total_changes(D)] interface only reports the number
+** of rows that changed due to SQL statement run against database
+** connection D. Any changes by other database connections are ignored.
+** To detect changes against a database file from other database
+** connections use the [PRAGMA data_version] command or the
+** [SQLITE_FCNTL_DATA_VERSION] [file control].
**
** If a separate thread makes changes on the same database connection
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
+** </ul>
*/
SQLITE_API int sqlite3_total_changes(sqlite3*);
@@ -2162,17 +2549,14 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
**
** ^The sqlite3_interrupt(D) call is in effect until all currently running
** SQL statements on [database connection] D complete. ^Any new SQL statements
-** that are started after the sqlite3_interrupt() call and before the
-** running statements reaches zero are interrupted as if they had been
+** that are started after the sqlite3_interrupt() call and before the
+** running statement count reaches zero are interrupted as if they had been
** running prior to the sqlite3_interrupt() call. ^New SQL statements
** that are started after the running statement count reaches zero are
** not effected by the sqlite3_interrupt().
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
-**
-** If the database connection closes while [sqlite3_interrupt()]
-** is running then bad things will likely happen.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
@@ -2197,7 +2581,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
** ^These routines do not parse the SQL statements thus
** will not detect syntactically incorrect SQL.
**
-** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
+** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
** automatically by sqlite3_complete16(). If that initialization fails,
** then the return value from sqlite3_complete16() will be non-zero
@@ -2242,7 +2626,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** The presence of a busy handler does not guarantee that it will be invoked
** when there is lock contention. ^If SQLite determines that invoking the busy
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
-** to the application instead of invoking the
+** to the application instead of invoking the
** busy handler.
** Consider a scenario where one process is holding a read lock that
** it is trying to promote to a reserved lock and
@@ -2267,7 +2651,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
** database connection that invoked the busy handler. In other words,
** the busy handler is not reentrant. Any such actions
** result in undefined behavior.
-**
+**
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
@@ -2334,9 +2718,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
** Cindy | 21
** </pre></blockquote>
**
-** There are two column (M==2) and three rows (N==3). Thus the
+** There are two columns (M==2) and three rows (N==3). Thus the
** result table has 8 entries. Suppose the result table is stored
-** in an array names azResult. Then azResult holds this content:
+** in an array named azResult. Then azResult holds this content:
**
** <blockquote><pre>
** azResult&#91;0] = "Name";
@@ -2384,16 +2768,16 @@ SQLITE_API void sqlite3_free_table(char **result);
**
** These routines are work-alikes of the "printf()" family of functions
** from the standard C library.
-** These routines understand most of the common K&R formatting options,
-** plus some additional non-standard formats, detailed below.
-** Note that some of the more obscure formatting options from recent
-** C-library standards are omitted from this implementation.
+** These routines understand most of the common formatting options from
+** the standard library printf()
+** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
+** See the [built-in printf()] documentation for details.
**
** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
-** results into memory obtained from [sqlite3_malloc()].
+** results into memory obtained from [sqlite3_malloc64()].
** The strings returned by these two routines should be
** released by [sqlite3_free()]. ^Both routines return a
-** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
+** NULL pointer if [sqlite3_malloc64()] is unable to allocate enough
** memory to hold the resulting string.
**
** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from
@@ -2417,71 +2801,7 @@ SQLITE_API void sqlite3_free_table(char **result);
**
** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf().
**
-** These routines all implement some additional formatting
-** options that are useful for constructing SQL statements.
-** All of the usual printf() formatting options apply. In addition, there
-** is are "%q", "%Q", "%w" and "%z" options.
-**
-** ^(The %q option works like %s in that it substitutes a nul-terminated
-** string from the argument list. But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal.)^ By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, assume the string variable zText contains text as follows:
-**
-** <blockquote><pre>
-** char *zText = "It's a happy day!";
-** </pre></blockquote>
-**
-** One can use this text in an SQL statement as follows:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It''s a happy day!')
-** </pre></blockquote>
-**
-** This is correct. Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It's a happy day!');
-** </pre></blockquote>
-**
-** This second example is an SQL syntax error. As a general rule you should
-** always use %q instead of %s when inserting text into a string literal.
-**
-** ^(The %Q option works like %q except it also adds single quotes around
-** the outside of the total string. Additionally, if the parameter in the
-** argument list is a NULL pointer, %Q substitutes the text "NULL" (without
-** single quotes).)^ So, for example, one could say:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** The code above will render a correct SQL statement in the zSQL
-** variable even if the zText variable is a NULL pointer.
-**
-** ^(The "%w" formatting option is like "%q" except that it expects to
-** be contained within double-quotes instead of single quotes, and it
-** escapes the double-quote character instead of the single-quote
-** character.)^ The "%w" formatting option is intended for safely inserting
-** table and column names into a constructed SQL statement.
-**
-** ^(The "%z" formatting option works like "%s" but with the
-** addition that after the string has been read and copied into
-** the result, [sqlite3_free()] is called on the input string.)^
+** See also: [built-in printf()], [printf() SQL function]
*/
SQLITE_API char *sqlite3_mprintf(const char*,...);
SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
@@ -2493,7 +2813,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
**
** The SQLite core uses these three routines for all of its own
** internal memory allocation needs. "Core" in the previous sentence
-** does not include operating-system specific VFS implementation. The
+** does not include operating-system specific [VFS] implementation. The
** Windows VFS uses native malloc() and free() for some operations.
**
** ^The sqlite3_malloc() routine returns a pointer to a block
@@ -2554,19 +2874,6 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used.
**
-** In SQLite version 3.5.0 and 3.5.1, it was possible to define
-** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
-** implementation of these routines to be omitted. That capability
-** is no longer provided. Only built-in memory allocators can be used.
-**
-** Prior to SQLite version 3.7.10, the Windows OS interface layer called
-** the system malloc() and free() directly when converting
-** filenames between the UTF-8 encoding used by SQLite
-** and whatever filename encoding is used by the particular Windows
-** installation. Memory allocation errors were detected, but
-** they were reported back as [SQLITE_CANTOPEN] or
-** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
-**
** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
** must be either NULL or else pointers obtained from a prior
** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have
@@ -2615,7 +2922,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** SQLite contains a high-quality pseudo-random number generator (PRNG) used to
** select random [ROWID | ROWIDs] when inserting new records into a table that
** already uses the largest possible [ROWID]. The PRNG is also used for
-** the build-in random() and randomblob() SQL functions. This interface allows
+** the built-in random() and randomblob() SQL functions. This interface allows
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
@@ -2635,12 +2942,14 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
** METHOD: sqlite3
+** KEYWORDS: {authorizer callback}
**
** ^This routine registers an authorizer callback with a particular
** [database connection], supplied in the first argument.
** ^The authorizer callback is invoked as SQL statements are being compiled
** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various
+** [sqlite3_prepare_v3()], [sqlite3_prepare16()], [sqlite3_prepare16_v2()],
+** and [sqlite3_prepare16_v3()]. ^At various
** points during the compilation process, as logic is being created
** to perform various actions, the authorizer callback is invoked to
** see if those actions are allowed. ^The authorizer callback should
@@ -2656,14 +2965,16 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** requested is ok. ^When the callback returns [SQLITE_DENY], the
** [sqlite3_prepare_v2()] or equivalent call that triggered the
** authorizer will fail with an error message explaining that
-** access is denied.
+** access is denied.
**
** ^The first parameter to the authorizer callback is a copy of the third
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
** to the callback is an integer [SQLITE_COPY | action code] that specifies
** the particular action to be authorized. ^The third through sixth parameters
-** to the callback are zero-terminated strings that contain additional
-** details about the action to be authorized.
+** to the callback are either NULL pointers or zero-terminated strings
+** that contain additional details about the action to be authorized.
+** Applications must always be prepared to encounter a NULL pointer in any
+** of the third through the sixth parameters of the authorization callback.
**
** ^If the action code is [SQLITE_READ]
** and the callback returns [SQLITE_IGNORE] then the
@@ -2672,6 +2983,10 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
** return can be used to deny an untrusted user access to individual
** columns of a table.
+** ^When a table is referenced by a [SELECT] but no column values are
+** extracted from that table (for example in a query like
+** "SELECT count(*) FROM tab") then the [SQLITE_READ] authorizer callback
+** is invoked once for that table with a column name that is an empty string.
** ^If the action code is [SQLITE_DELETE] and the callback returns
** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the
** [truncate optimization] is disabled and all rows are deleted individually.
@@ -2703,7 +3018,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
** database connections for the meaning of "modify" in this paragraph.
**
** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
-** statement might be re-prepared during [sqlite3_step()] due to a
+** statement might be re-prepared during [sqlite3_step()] due to a
** schema change. Hence, the application should ensure that the
** correct authorizer callback remains in place during the [sqlite3_step()].
**
@@ -2817,9 +3132,9 @@ SQLITE_API int sqlite3_set_authorizer(
** time is in units of nanoseconds, however the current implementation
** is only capable of millisecond resolution so the six least significant
** digits in the time are meaningless. Future versions of SQLite
-** might provide greater resolution on the profiler callback. The
-** sqlite3_profile() function is considered experimental and is
-** subject to change in future versions of SQLite.
+** might provide greater resolution on the profiler callback. Invoking
+** either [sqlite3_trace()] or [sqlite3_trace_v2()] will cancel the
+** profile callback.
*/
SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
void(*xTrace)(void*,const char*), void*);
@@ -2831,8 +3146,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** KEYWORDS: SQLITE_TRACE
**
** These constants identify classes of events that can be monitored
-** using the [sqlite3_trace_v2()] tracing logic. The third argument
-** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
+** using the [sqlite3_trace_v2()] tracing logic. The M argument
+** to [sqlite3_trace_v2(D,M,X,P)] is an OR-ed combination of one or more of
** the following constants. ^The first argument to the trace callback
** is one of the following constants.
**
@@ -2851,7 +3166,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** execution of the prepared statement, such as at the start of each
** trigger subprogram. ^The P argument is a pointer to the
** [prepared statement]. ^The X argument is a pointer to a string which
-** is the unexpanded SQL text of the prepared statement or an SQL comment
+** is the unexpanded SQL text of the prepared statement or an SQL comment
** that indicates the invocation of a trigger. ^The callback can compute
** the same text that would have been returned by the legacy [sqlite3_trace()]
** interface by using the X argument when X begins with "--" and invoking
@@ -2867,7 +3182,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
-** statement generates a single row of result.
+** statement generates a single row of result.
** ^The P argument is a pointer to the [prepared statement] and the
** X argument is unused.
**
@@ -2894,10 +3209,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** M argument should be the bitwise OR-ed combination of
** zero or more [SQLITE_TRACE] constants.
**
-** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
**
-** ^The X callback is invoked whenever any of the events identified by
+** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
** ignored, though this may change in future releases. Callback
** implementations should return zero to ensure future compatibility.
@@ -2929,8 +3244,8 @@ SQLITE_API int sqlite3_trace_v2(
** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
-** ^The parameter P is passed through as the only parameter to the
-** callback function X. ^The parameter N is the approximate number of
+** ^The parameter P is passed through as the only parameter to the
+** callback function X. ^The parameter N is the approximate number of
** [virtual machine instructions] that are evaluated between successive
** invocations of the callback X. ^If N is less than one then the progress
** handler is disabled.
@@ -2957,7 +3272,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** CAPI3REF: Opening A New Database Connection
** CONSTRUCTOR: sqlite3
**
-** ^These routines open an SQLite database file as specified 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
@@ -2981,10 +3296,8 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** The sqlite3_open_v2() interface works like sqlite3_open()
** except that it accepts two additional parameters for additional control
** over the new database connection. ^(The flags parameter to
-** sqlite3_open_v2() can take one of
-** the following three values, optionally combined with the
-** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE],
-** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^
+** sqlite3_open_v2() must include, at a minimum, one of the following
+** three flag combinations:)^
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
@@ -3002,23 +3315,51 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** sqlite3_open() and sqlite3_open16().</dd>)^
** </dl>
**
+** In addition to the required flags, the following optional flags are
+** also supported:
+**
+** <dl>
+** ^(<dt>[SQLITE_OPEN_URI]</dt>
+** <dd>The filename can be interpreted as a URI if this flag is set.</dd>)^
+**
+** ^(<dt>[SQLITE_OPEN_MEMORY]</dt>
+** <dd>The database will be opened as an in-memory database. The database
+** is named by the "filename" argument for the purposes of cache-sharing,
+** if shared cache mode is enabled, but the "filename" is otherwise ignored.
+** </dd>)^
+**
+** ^(<dt>[SQLITE_OPEN_NOMUTEX]</dt>
+** <dd>The new database connection will use the "multi-thread"
+** [threading mode].)^ This means that separate threads are allowed
+** to use SQLite at the same time, as long as each thread is using
+** a different [database connection].
+**
+** ^(<dt>[SQLITE_OPEN_FULLMUTEX]</dt>
+** <dd>The new database connection will use the "serialized"
+** [threading mode].)^ This means the multiple threads can safely
+** attempt to use the same database connection at the same time.
+** (Mutexes will block any actual concurrency, but in this mode
+** there is no harm in trying.)
+**
+** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt>
+** <dd>The database is opened [shared cache] enabled, overriding
+** the default shared cache setting provided by
+** [sqlite3_enable_shared_cache()].)^
+**
+** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
+** <dd>The database is opened [shared cache] disabled, overriding
+** the default shared cache setting provided by
+** [sqlite3_enable_shared_cache()].)^
+**
+** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
+** <dd>The database filename is not allowed to be a symbolic link</dd>
+** </dl>)^
+**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
-** combinations shown above optionally combined with other
+** required 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
-** opens in the multi-thread [threading mode] as long as the single-thread
-** mode has not been set at compile-time or start-time. ^If the
-** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens
-** in the serialized [threading mode] unless single-thread was
-** previously selected at compile-time or start-time.
-** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be
-** eligible to use [shared cache mode], regardless of whether or not shared
-** cache is enabled using [sqlite3_enable_shared_cache()]. ^The
-** [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
@@ -3041,26 +3382,26 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** ^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
+** set in the third 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
+** 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
+** 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
+** 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
+** 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]]
@@ -3080,13 +3421,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw",
** "rwc", or "memory". 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_open_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
+** 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_open_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 the mode option is
** set to "memory" then a pure [in-memory database] that never reads
** or writes from disk is used. ^It is an error to specify a value for
@@ -3096,7 +3437,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** <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
+** 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 behavior requested by setting
@@ -3122,7 +3463,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** property on a database file that does in fact change can result
** in incorrect query results and/or [SQLITE_CORRUPT] errors.
** See also: [SQLITE_IOCAP_IMMUTABLE].
-**
+**
** </ul>
**
** ^Specifying an unknown parameter in the query component of a URI is not an
@@ -3134,36 +3475,36 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** <table border="1" align=center cellpadding=5>
** <tr><th> URI filenames <th> Results
-** <tr><td> file:data.db <td>
+** <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>
+** 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>
+** <tr><td> file://darkstar/home/fred/data.db <td>
** An error. "darkstar" is not a recognized authority.
-** <tr><td style="white-space:nowrap">
+** <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
+** 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>
+** <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-dotfile <td>
** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile"
** that uses dot-files in place of posix advisory locking.
-** <tr><td> file:data.db?mode=readonly <td>
+** <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
+** 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
+** 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.
@@ -3198,17 +3539,27 @@ SQLITE_API int sqlite3_open_v2(
/*
** CAPI3REF: Obtain Values For URI Parameters
**
-** These are utility routines, useful to VFS implementations, that check
-** to see if a database file was a URI that contained a specific query
+** These are utility routines, useful to [VFS|custom VFS implementations],
+** that check if a database file was a URI that contained a specific query
** parameter, and if so obtains the value of that query parameter.
**
-** If F is the database filename pointer passed into the xOpen() method of
-** a VFS implementation when the flags parameter to xOpen() has one or
-** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and
-** P is the name of the query parameter, then
+** The first parameter to these interfaces (hereafter referred to
+** as F) must be one of:
+** <ul>
+** <li> A database filename pointer created by the SQLite core and
+** passed into the xOpen() method of a VFS implemention, or
+** <li> A filename obtained from [sqlite3_db_filename()], or
+** <li> A new filename constructed using [sqlite3_create_filename()].
+** </ul>
+** If the F parameter is not one of the above, then the behavior is
+** undefined and probably undesirable. Older versions of SQLite were
+** more tolerant of invalid F parameters than newer versions.
+**
+** If F is a suitable filename (as described in the previous paragraph)
+** and if P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
-** parameter if it exists or a NULL pointer if P does not appear as a
-** query parameter on F. If P is a query parameter of F
+** parameter if it exists or a NULL pointer if P does not appear as a
+** query parameter on F. If P is a query parameter of F and it
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
@@ -3216,44 +3567,176 @@ SQLITE_API int sqlite3_open_v2(
** parameter and returns true (1) or false (0) according to the value
** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
** value of query parameter P is one of "yes", "true", or "on" in any
-** case or if the value begins with a non-zero number. The
+** case or if the value begins with a non-zero number. The
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
** query parameter P is one of "no", "false", or "off" in any case or
** if the value begins with a numeric zero. If P is not a query
-** parameter on F or if the value of P is does not match any of the
+** parameter on F or if the value of P does not match any of the
** above, then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist. If the value of P is something other than an integer, then
** zero is returned.
-**
+**
+** The sqlite3_uri_key(F,N) returns a pointer to the name (not
+** the value) of the N-th query parameter for filename F, or a NULL
+** pointer if N is less than zero or greater than the number of query
+** parameters minus 1. The N value is zero-based so N should be 0 to obtain
+** the name of the first query parameter, 1 for the second parameter, and
+** so forth.
+**
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
-** is not a database file pathname pointer that SQLite passed into the xOpen
-** VFS method, then the behavior of this routine is undefined and probably
-** undesirable.
+** is not a database file pathname pointer that the SQLite core passed
+** into the xOpen VFS method, then the behavior of this routine is undefined
+** and probably undesirable.
+**
+** Beginning with SQLite [version 3.31.0] ([dateof:3.31.0]) the input F
+** parameter can also be the name of a rollback journal file or WAL file
+** in addition to the main database file. Prior to version 3.31.0, these
+** routines would only work if F was the name of the main database file.
+** When the F parameter is the name of the rollback journal or WAL file,
+** it has access to all the same query parameters as were found on the
+** main database file.
+**
+** See the [URI filename] documentation for additional information.
*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
+
+/*
+** CAPI3REF: Translate filenames
+**
+** These routines are available to [VFS|custom VFS implementations] for
+** translating filenames between the main database file, the journal file,
+** and the WAL file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** passed by the SQLite core into the VFS, then sqlite3_filename_database(F)
+** returns the name of the corresponding database file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** passed by the SQLite core into the VFS, or if F is a database filename
+** obtained from [sqlite3_db_filename()], then sqlite3_filename_journal(F)
+** returns the name of the corresponding rollback journal file.
+**
+** If F is the name of an sqlite database file, journal file, or WAL file
+** that was passed by the SQLite core into the VFS, or if F is a database
+** filename obtained from [sqlite3_db_filename()], then
+** sqlite3_filename_wal(F) returns the name of the corresponding
+** WAL file.
+**
+** In all of the above, if F is not the name of a database, journal or WAL
+** filename passed into the VFS from the SQLite core and F is not the
+** return value from [sqlite3_db_filename()], then the result is
+** undefined and is likely a memory access violation.
+*/
+SQLITE_API const char *sqlite3_filename_database(const char*);
+SQLITE_API const char *sqlite3_filename_journal(const char*);
+SQLITE_API const char *sqlite3_filename_wal(const char*);
+/*
+** CAPI3REF: Database File Corresponding To A Journal
+**
+** ^If X is the name of a rollback or WAL-mode journal file that is
+** passed into the xOpen method of [sqlite3_vfs], then
+** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file]
+** object that represents the main database file.
+**
+** This routine is intended for use in custom [VFS] implementations
+** only. It is not a general-purpose interface.
+** The argument sqlite3_file_object(X) must be a filename pointer that
+** has been passed into [sqlite3_vfs].xOpen method where the
+** flags parameter to xOpen contains one of the bits
+** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use
+** of this routine results in undefined and probably undesirable
+** behavior.
+*/
+SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
+
+/*
+** CAPI3REF: Create and Destroy VFS Filenames
+**
+** These interfces are provided for use by [VFS shim] implementations and
+** are not useful outside of that context.
+**
+** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
+** database filename D with corresponding journal file J and WAL file W and
+** with N URI parameters key/values pairs in the array P. The result from
+** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
+** is safe to pass to routines like:
+** <ul>
+** <li> [sqlite3_uri_parameter()],
+** <li> [sqlite3_uri_boolean()],
+** <li> [sqlite3_uri_int64()],
+** <li> [sqlite3_uri_key()],
+** <li> [sqlite3_filename_database()],
+** <li> [sqlite3_filename_journal()], or
+** <li> [sqlite3_filename_wal()].
+** </ul>
+** If a memory allocation error occurs, sqlite3_create_filename() might
+** return a NULL pointer. The memory obtained from sqlite3_create_filename(X)
+** must be released by a corresponding call to sqlite3_free_filename(Y).
+**
+** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
+** of 2*N pointers to strings. Each pair of pointers in this array corresponds
+** to a key and value for a query parameter. The P parameter may be a NULL
+** pointer if N is zero. None of the 2*N pointers in the P array may be
+** NULL pointers and key pointers should not be empty strings.
+** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
+** be NULL pointers, though they can be empty strings.
+**
+** The sqlite3_free_filename(Y) routine releases a memory allocation
+** previously obtained from sqlite3_create_filename(). Invoking
+** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
+**
+** If the Y parameter to sqlite3_free_filename(Y) is anything other
+** than a NULL pointer or a pointer previously acquired from
+** sqlite3_create_filename(), then bad things such as heap
+** corruption or segfaults may occur. The value Y should be
+** used again after sqlite3_free_filename(Y) has been called. This means
+** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
+** then the corresponding [sqlite3_module.xClose() method should also be
+** invoked prior to calling sqlite3_free_filename(Y).
+*/
+SQLITE_API char *sqlite3_create_filename(
+ const char *zDatabase,
+ const char *zJournal,
+ const char *zWal,
+ int nParam,
+ const char **azParam
+);
+SQLITE_API void sqlite3_free_filename(char*);
/*
** CAPI3REF: Error Codes And Messages
** METHOD: sqlite3
**
-** ^If the most recent sqlite3_* API call associated with
+** ^If the most recent sqlite3_* API call associated with
** [database connection] D failed, then the sqlite3_errcode(D) interface
** returns the numeric [result code] or [extended result code] for that
** API call.
-** If the most recent API call was successful,
-** then the return value from sqlite3_errcode() is undefined.
** ^The sqlite3_extended_errcode()
-** interface is the same except that it always returns the
+** interface is the same except that it always returns the
** [extended result code] even when extended result codes are
** disabled.
**
+** The values returned by sqlite3_errcode() and/or
+** sqlite3_extended_errcode() might change with each API call.
+** Except, there are some interfaces that are guaranteed to never
+** change the value of the error code. The error-code preserving
+** interfaces are:
+**
+** <ul>
+** <li> sqlite3_errcode()
+** <li> sqlite3_extended_errcode()
+** <li> sqlite3_errmsg()
+** <li> sqlite3_errmsg16()
+** </ul>
+**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
** text that describes the error, as either UTF-8 or UTF-16 respectively.
** ^(Memory to hold the error message string is managed internally.
@@ -3294,7 +3777,7 @@ SQLITE_API const char *sqlite3_errstr(int);
** has been compiled into binary form and is ready to be evaluated.
**
** Think of each SQL statement as a separate computer program. The
-** original SQL text is source code. A prepared statement object
+** original SQL text is source code. A prepared statement object
** is the compiled object code. All SQL must be converted into a
** prepared statement before it can be run.
**
@@ -3324,7 +3807,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
** new limit for that construct.)^
**
** ^If the new limit is a negative number, the limit is unchanged.
-** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
** [limits | hard upper bound]
** set at compile-time by a C preprocessor macro called
** [limits | SQLITE_MAX_<i>NAME</i>].
@@ -3332,7 +3815,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
** ^Attempts to increase a limit above its hard upper bound are
** silently truncated to the hard upper bound.
**
-** ^Regardless of whether or not the limit was changed, the
+** ^Regardless of whether or not the limit was changed, the
** [sqlite3_limit()] interface returns the prior value of the limit.
** ^Hence, to find the current value of a limit without changing it,
** simply invoke this interface with the third parameter set to -1.
@@ -3383,9 +3866,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
**
** [[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>)^
+** used to implement an SQL statement. If [sqlite3_prepare_v2()] or
+** the equivalent tries to allocate space for more than this many opcodes
+** in a single prepared statement, an SQLITE_NOMEM error is returned.</dd>)^
**
** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt>
** <dd>The maximum number of arguments on a function.</dd>)^
@@ -3424,22 +3907,73 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
#define SQLITE_LIMIT_WORKER_THREADS 11
/*
+** CAPI3REF: Prepare Flags
+**
+** These constants define various flags that can be passed into
+** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
+** [sqlite3_prepare16_v3()] interfaces.
+**
+** New flags may be added in future releases of SQLite.
+**
+** <dl>
+** [[SQLITE_PREPARE_PERSISTENT]] ^(<dt>SQLITE_PREPARE_PERSISTENT</dt>
+** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
+** that the prepared statement will be retained for a long time and
+** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
+** and [sqlite3_prepare16_v3()] assume that the prepared statement will
+** be used just once or at most a few times and then destroyed using
+** [sqlite3_finalize()] relatively soon. The current implementation acts
+** on this hint by avoiding the use of [lookaside memory] so as not to
+** deplete the limited store of lookaside memory. Future versions of
+** SQLite may act on this hint differently.
+**
+** [[SQLITE_PREPARE_NORMALIZE]] <dt>SQLITE_PREPARE_NORMALIZE</dt>
+** <dd>The SQLITE_PREPARE_NORMALIZE flag is a no-op. This flag used
+** to be required for any prepared statement that wanted to use the
+** [sqlite3_normalized_sql()] interface. However, the
+** [sqlite3_normalized_sql()] interface is now available to all
+** prepared statements, regardless of whether or not they use this
+** flag.
+**
+** [[SQLITE_PREPARE_NO_VTAB]] <dt>SQLITE_PREPARE_NO_VTAB</dt>
+** <dd>The SQLITE_PREPARE_NO_VTAB flag causes the SQL compiler
+** to return an error (error code SQLITE_ERROR) if the statement uses
+** any virtual tables.
+** </dl>
+*/
+#define SQLITE_PREPARE_PERSISTENT 0x01
+#define SQLITE_PREPARE_NORMALIZE 0x02
+#define SQLITE_PREPARE_NO_VTAB 0x04
+
+/*
** CAPI3REF: Compiling An SQL Statement
** KEYWORDS: {SQL statement compiler}
** METHOD: sqlite3
** CONSTRUCTOR: sqlite3_stmt
**
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of these routines.
+** To execute an SQL statement, it must first be compiled into a byte-code
+** program using one of these routines. Or, in other words, these routines
+** are constructors for the [prepared statement] object.
+**
+** The preferred routine to use is [sqlite3_prepare_v2()]. The
+** [sqlite3_prepare()] interface is legacy and should be avoided.
+** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used
+** for special purposes.
+**
+** The use of the UTF-8 interfaces is preferred, as SQLite currently
+** does all parsing using UTF-8. The UTF-16 interfaces are provided
+** as a convenience. The UTF-16 interfaces work by converting the
+** input text into UTF-8, then invoking the corresponding UTF-8 interface.
**
** The first argument, "db", is a [database connection] obtained from a
** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or
** [sqlite3_open16()]. The database connection must not have been closed.
**
** The second argument, "zSql", is the statement to be compiled, encoded
-** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2()
-** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2()
-** use UTF-16.
+** as either UTF-8 or UTF-16. The sqlite3_prepare(), sqlite3_prepare_v2(),
+** and sqlite3_prepare_v3()
+** interfaces use UTF-8, and sqlite3_prepare16(), sqlite3_prepare16_v2(),
+** and sqlite3_prepare16_v3() use UTF-16.
**
** ^If the nByte argument is negative, then zSql is read up to the
** first zero terminator. ^If nByte is positive, then it is the
@@ -3466,10 +4000,11 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK];
** otherwise an [error code] is returned.
**
-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
-** recommended for all new programs. The two older interfaces are retained
-** for backwards compatibility, but their use is discouraged.
-** ^In the "v2" interfaces, the prepared statement
+** The sqlite3_prepare_v2(), sqlite3_prepare_v3(), sqlite3_prepare16_v2(),
+** and sqlite3_prepare16_v3() interfaces are recommended for all new programs.
+** The older interfaces (sqlite3_prepare() and sqlite3_prepare16())
+** are retained for backwards compatibility, but their use is discouraged.
+** ^In the "vX" interfaces, the prepared statement
** that is returned (the [sqlite3_stmt] object) contains a copy of the
** original SQL text. This causes the [sqlite3_step()] interface to
** behave differently in three ways:
@@ -3492,17 +4027,23 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
**
** <li>
-** ^If the specific value bound to [parameter | host parameter] in the
+** ^If the specific value bound to a [parameter | host parameter] in the
** WHERE clause might influence the choice of query plan for a statement,
-** then the statement will be automatically recompiled, as if there had been
-** a schema change, on the first [sqlite3_step()] call following any change
-** to the [sqlite3_bind_text | bindings] of that [parameter].
-** ^The specific value of WHERE-clause [parameter] might influence the
+** then the statement will be automatically recompiled, as if there had been
+** a schema change, on the first [sqlite3_step()] call following any change
+** to the [sqlite3_bind_text | bindings] of that [parameter].
+** ^The specific value of a WHERE-clause [parameter] might influence the
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
-** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
+** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
+**
+** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having
+** the extra prepFlags parameter, which is a bit array consisting of zero or
+** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The
+** sqlite3_prepare_v2() interface works exactly the same as
+** sqlite3_prepare_v3() with a zero prepFlags parameter.
*/
SQLITE_API int sqlite3_prepare(
sqlite3 *db, /* Database handle */
@@ -3518,6 +4059,14 @@ SQLITE_API int sqlite3_prepare_v2(
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
+SQLITE_API int sqlite3_prepare_v3(
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL statement, UTF-8 encoded */
+ int nByte, /* Maximum length of zSql in bytes. */
+ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
+);
SQLITE_API int sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
@@ -3532,6 +4081,14 @@ SQLITE_API int sqlite3_prepare16_v2(
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
+SQLITE_API int sqlite3_prepare16_v3(
+ sqlite3 *db, /* Database handle */
+ const void *zSql, /* SQL statement, UTF-16 encoded */
+ int nByte, /* Maximum length of zSql in bytes. */
+ unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_ flags */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
+);
/*
** CAPI3REF: Retrieving Statement SQL
@@ -3539,10 +4096,16 @@ SQLITE_API int sqlite3_prepare16_v2(
**
** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
** SQL text used to create [prepared statement] P if P was
-** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** created by [sqlite3_prepare_v2()], [sqlite3_prepare_v3()],
+** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
** string containing the SQL text of prepared statement P with
** [bound parameters] expanded.
+** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8
+** string containing the normalized SQL text of prepared statement P. The
+** semantics used to normalize a SQL statement are unspecified and subject
+** to change. At a minimum, literal values will be replaced with suitable
+** placeholders.
**
** ^(For example, if a prepared statement is created using the SQL
** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
@@ -3558,14 +4121,16 @@ SQLITE_API int sqlite3_prepare16_v2(
** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
** option causes sqlite3_expanded_sql() to always return NULL.
**
-** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
-** automatically freed when the prepared statement is finalized.
+** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P)
+** are managed by SQLite and are automatically freed when the prepared
+** statement is finalized.
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
** is obtained from [sqlite3_malloc()] and must be free by the application
** by passing it to [sqlite3_free()].
*/
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3576,8 +4141,8 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
** the content of the database file.
**
** Note that [application-defined SQL functions] or
-** [virtual tables] might change the database indirectly as a side effect.
-** ^(For example, if an application defines a function "eval()" that
+** [virtual tables] might change the database indirectly as a side effect.
+** ^(For example, if an application defines a function "eval()" that
** calls [sqlite3_exec()], then the following SQL statement would
** change the database file through side-effects:
**
@@ -3591,31 +4156,47 @@ SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
** since the statements themselves do not actually modify the database but
-** rather they control the timing of when other statements modify the
+** rather they control the timing of when other statements modify the
** database. ^The [ATTACH] and [DETACH] statements also cause
** sqlite3_stmt_readonly() to return true since, while those statements
-** change the configuration of a database connection, they do not make
+** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
+** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
+** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
+** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
+** sqlite3_stmt_readonly() returns false for those commands.
*/
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Query The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlite3_stmt
+**
+** ^The sqlite3_stmt_isexplain(S) interface returns 1 if the
+** prepared statement S is an EXPLAIN statement, or 2 if the
+** statement S is an EXPLAIN QUERY PLAN.
+** ^The sqlite3_stmt_isexplain(S) interface returns 0 if S is
+** an ordinary statement or a NULL pointer.
+*/
+SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
**
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
-** [prepared statement] S has been stepped at least once using
+** [prepared statement] S has been stepped at least once using
** [sqlite3_step(S)] but has neither run to completion (returned
** [SQLITE_DONE] from [sqlite3_step(S)]) nor
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
-** interface returns false if S is a NULL pointer. If S is not a
+** interface returns false if S is a NULL pointer. If S is not a
** NULL pointer and is not a pointer to a valid [prepared statement]
** object, then the behavior is undefined and probably undesirable.
**
** This interface can be used in combination [sqlite3_next_stmt()]
-** to locate all prepared statements associated with a database
+** to locate all prepared statements associated with a database
** connection that are in need of being reset. This can be used,
-** for example, in diagnostic routines to search for prepared
+** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
@@ -3634,7 +4215,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** will accept either a protected or an unprotected sqlite3_value.
** Every interface that accepts sqlite3_value arguments specifies
** whether or not it requires a protected sqlite3_value. The
-** [sqlite3_value_dup()] interface can be used to construct a new
+** [sqlite3_value_dup()] interface can be used to construct a new
** protected sqlite3_value from an unprotected sqlite3_value.
**
** The terms "protected" and "unprotected" refer to whether or not
@@ -3642,7 +4223,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** sqlite3_value object but no mutex is held for an unprotected
** sqlite3_value object. If SQLite is compiled to be single-threaded
** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
-** or if SQLite is run in one of reduced mutex modes
+** or if SQLite is run in one of reduced mutex modes
** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
** then there is no distinction between protected and unprotected
** sqlite3_value objects and they can be used interchangeably. However,
@@ -3654,12 +4235,13 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
** implementation of [application-defined SQL functions] are protected.
** ^The sqlite3_value object returned by
** [sqlite3_column_value()] is unprotected.
-** Unprotected sqlite3_value objects may only be used with
-** [sqlite3_result_value()] and [sqlite3_bind_value()].
+** Unprotected sqlite3_value objects may only be used as arguments
+** to [sqlite3_result_value()], [sqlite3_bind_value()], and
+** [sqlite3_value_dup()].
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
-typedef struct Mem sqlite3_value;
+typedef struct sqlite3_value sqlite3_value;
/*
** CAPI3REF: SQL Function Context Object
@@ -3710,12 +4292,30 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_bind_parameter_index()] API if desired. ^The index
** for "?NNN" parameters is the value of NNN.
** ^The NNN value must be between 1 and the [sqlite3_limit()]
-** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
+** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
**
** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
+** ^If the third parameter to sqlite3_bind_text() is not NULL, then
+** it should be a pointer to well-formed UTF8 text.
+** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
+** it should be a pointer to well-formed UTF16 text.
+** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
+** it should be a pointer to a well-formed unicode string that is
+** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
+** otherwise.
+**
+** [[byte-order determination rules]] ^The byte-order of
+** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
+** found in first character, which is removed, or in the absence of a BOM
+** the byte order is the native byte order of the host
+** machine for sqlite3_bind_text16() or the byte order specified in
+** the 6th parameter for sqlite3_bind_text64().)^
+** ^If UTF16 input text contains invalid unicode
+** characters, then SQLite might change those invalid characters
+** into the unicode replacement character: U+FFFD.
**
** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the
@@ -3729,7 +4329,7 @@ typedef struct sqlite3_context sqlite3_context;
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL
-** terminated. If any NUL characters occur at byte offsets less than
+** terminated. If any NUL characters occurs at byte offsets less than
** the value of the fourth parameter then the resulting string value will
** contain embedded NULs. The result of expressions involving strings
** with embedded NULs is undefined.
@@ -3737,7 +4337,9 @@ typedef struct sqlite3_context sqlite3_context;
** ^The fifth argument to the BLOB and string binding interfaces
** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it. ^The destructor is called
-** to dispose of the BLOB or string even if the call to bind API fails.
+** to dispose of the BLOB or string even if the call to the bind API fails,
+** except the destructor is not called if the third parameter is a NULL
+** pointer or the fourth parameter is negative.
** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed.
@@ -3761,6 +4363,15 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_blob_open | incremental BLOB I/O] routines.
** ^A negative value for the zeroblob results in a zero-length BLOB.
**
+** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
+** [prepared statement] S to have an SQL value of NULL, but to also be
+** associated with the pointer P of type T. ^D is either a NULL pointer or
+** a pointer to a destructor function for P. ^SQLite will invoke the
+** destructor D with a single argument of P when it is finished using
+** P. The T parameter should be a static string, preferably a string
+** literal. The sqlite3_bind_pointer() routine is part of the
+** [pointer passing interface] added for SQLite 3.20.0.
+**
** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
** for the [prepared statement] or with a prepared statement for which
** [sqlite3_step()] has been called more recently than [sqlite3_reset()],
@@ -3794,6 +4405,7 @@ SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*));
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
@@ -3837,8 +4449,8 @@ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
** ^If the value N is out of range or if the N-th parameter is
** nameless, then NULL is returned. ^The returned string is
** always in UTF-8 encoding even if the named parameter was
-** originally specified as UTF-16 in [sqlite3_prepare16()] or
-** [sqlite3_prepare16_v2()].
+** originally specified as UTF-16 in [sqlite3_prepare16()],
+** [sqlite3_prepare16_v2()], or [sqlite3_prepare16_v3()].
**
** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and
@@ -3855,7 +4467,8 @@ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero
** is returned if no matching parameter is found. ^The parameter
** name must be given in UTF-8 even if the original statement
-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
+** was prepared from UTF-16 text using [sqlite3_prepare16_v2()] or
+** [sqlite3_prepare16_v3()].
**
** See also: [sqlite3_bind_blob|sqlite3_bind()],
** [sqlite3_bind_parameter_count()], and
@@ -3878,8 +4491,12 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
** METHOD: sqlite3_stmt
**
** ^Return the number of columns in the result set returned by the
-** [prepared statement]. ^This routine returns 0 if pStmt is an SQL
-** statement that does not return data (for example an [UPDATE]).
+** [prepared statement]. ^If this routine returns 0, that means the
+** [prepared statement] returns no data (for example an [UPDATE]).
+** ^However, just because this routine returns a positive number does not
+** mean that one or more rows of data will be returned. ^A SELECT statement
+** will always have a positive sqlite3_column_count() but depending on the
+** WHERE clause constraints and the table content, it might return no rows.
**
** See also: [sqlite3_data_count()]
*/
@@ -3942,7 +4559,7 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
**
** ^If the Nth column returned by the statement is an expression or
** subquery and is not a column value, then all of these functions return
-** NULL. ^These routine might also return NULL if a memory allocation error
+** NULL. ^These routines might also return NULL if a memory allocation error
** occurs. ^Otherwise, they return the name of the attached database, table,
** or column that query result column was extracted from.
**
@@ -3952,10 +4569,6 @@ SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
** ^These APIs are only available if the library was compiled with the
** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol.
**
-** If two or more threads call one or more of these routines against the same
-** prepared statement and column at the same time then the results are
-** undefined.
-**
** If two or more threads call one or more
** [sqlite3_column_database_name | column metadata interfaces]
** for the same [prepared statement] and result column
@@ -4005,16 +4618,18 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** CAPI3REF: Evaluate An SQL Statement
** METHOD: sqlite3_stmt
**
-** After a [prepared statement] has been prepared using either
-** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy
+** After a [prepared statement] has been prepared using any of
+** [sqlite3_prepare_v2()], [sqlite3_prepare_v3()], [sqlite3_prepare16_v2()],
+** or [sqlite3_prepare16_v3()] or one of the legacy
** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function
** must be called one or more times to evaluate the statement.
**
** The details of the behavior of the sqlite3_step() interface depend
-** on whether the statement was prepared using the newer "v2" interface
-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
-** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
-** new "v2" interface is recommended for new applications but the legacy
+** on whether the statement was prepared using the newer "vX" interfaces
+** [sqlite3_prepare_v3()], [sqlite3_prepare_v2()], [sqlite3_prepare16_v3()],
+** [sqlite3_prepare16_v2()] or the older legacy
+** interfaces [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
+** new "vX" interface is recommended for new applications but the legacy
** interface will continue to be supported.
**
** ^In the legacy interface, the return value will be either [SQLITE_BUSY],
@@ -4058,7 +4673,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** For all versions of SQLite up to and including 3.6.23.1, a call to
** [sqlite3_reset()] was required after sqlite3_step() returned anything
** other than [SQLITE_ROW] before any subsequent invocation of
-** sqlite3_step(). Failure to reset the prepared statement using
+** sqlite3_step(). Failure to reset the prepared statement using
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
** sqlite3_step() began
@@ -4075,10 +4690,11 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** specific [error codes] that better describes the error.
** We admit that this is a goofy design. The problem has been fixed
** with the "v2" interface. If you prepare all of your SQL statements
-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
+** using [sqlite3_prepare_v3()] or [sqlite3_prepare_v2()]
+** or [sqlite3_prepare16_v2()] or [sqlite3_prepare16_v3()] instead
** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces,
** then the more specific [error codes] are returned directly
-** by sqlite3_step(). The use of the "v2" interface is recommended.
+** by sqlite3_step(). The use of the "vX" interfaces is recommended.
*/
SQLITE_API int sqlite3_step(sqlite3_stmt*);
@@ -4089,7 +4705,7 @@ SQLITE_API int sqlite3_step(sqlite3_stmt*);
** ^The sqlite3_data_count(P) interface returns the number of columns in the
** current row of the result set of [prepared statement] P.
** ^If prepared statement P does not have results ready to return
-** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of
+** (via calls to the [sqlite3_column_int | sqlite3_column()] family of
** interfaces) then sqlite3_data_count(P) returns 0.
** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer.
** ^The sqlite3_data_count(P) routine returns 0 if the previous call to
@@ -4140,6 +4756,28 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** KEYWORDS: {column access functions}
** METHOD: sqlite3_stmt
**
+** <b>Summary:</b>
+** <blockquote><table border=0 cellpadding=0 cellspacing=0>
+** <tr><td><b>sqlite3_column_blob</b><td>&rarr;<td>BLOB result
+** <tr><td><b>sqlite3_column_double</b><td>&rarr;<td>REAL result
+** <tr><td><b>sqlite3_column_int</b><td>&rarr;<td>32-bit INTEGER result
+** <tr><td><b>sqlite3_column_int64</b><td>&rarr;<td>64-bit INTEGER result
+** <tr><td><b>sqlite3_column_text</b><td>&rarr;<td>UTF-8 TEXT result
+** <tr><td><b>sqlite3_column_text16</b><td>&rarr;<td>UTF-16 TEXT result
+** <tr><td><b>sqlite3_column_value</b><td>&rarr;<td>The result as an
+** [sqlite3_value|unprotected sqlite3_value] object.
+** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
+** <tr><td><b>sqlite3_column_bytes</b><td>&rarr;<td>Size of a BLOB
+** or a UTF-8 TEXT result in bytes
+** <tr><td><b>sqlite3_column_bytes16&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
+** TEXT in bytes
+** <tr><td><b>sqlite3_column_type</b><td>&rarr;<td>Default
+** datatype of the result
+** </table></blockquote>
+**
+** <b>Details:</b>
+**
** ^These routines return information about a single column of the current
** result row of a query. ^In every case the first argument is a pointer
** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*]
@@ -4161,16 +4799,29 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** are called from a different thread while any of these routines
** are pending, then the results are undefined.
**
+** The first six interfaces (_blob, _double, _int, _int64, _text, and _text16)
+** each return the value of a result column in a specific data format. If
+** the result column is not initially in the requested format (for example,
+** if the query returns an integer but the sqlite3_column_text() interface
+** is used to extract the value) then an automatic type conversion is performed.
+**
** ^The sqlite3_column_type() routine returns the
** [SQLITE_INTEGER | datatype code] for the initial data type
** of the result column. ^The returned value is one of [SQLITE_INTEGER],
-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
-** returned by sqlite3_column_type() is only meaningful if no type
-** conversions have occurred as described below. After a type conversion,
-** the value returned by sqlite3_column_type() is undefined. Future
+** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].
+** The return value of sqlite3_column_type() can be used to decide which
+** of the first six interface should be used to extract the column value.
+** The value returned by sqlite3_column_type() is only meaningful if no
+** automatic type conversions have occurred for the value in question.
+** After a type conversion, the result of calling sqlite3_column_type()
+** is undefined, though harmless. Future
** versions of SQLite may change the behavior of sqlite3_column_type()
** following a type conversion.
**
+** If the result is a BLOB or a TEXT string, then the sqlite3_column_bytes()
+** or sqlite3_column_bytes16() interfaces can be used to determine the size
+** of that BLOB or string.
+**
** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
** routine returns the number of bytes in that BLOB or string.
** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts
@@ -4189,7 +4840,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** the number of bytes in that string.
** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
**
-** ^The values returned by [sqlite3_column_bytes()] and
+** ^The values returned by [sqlite3_column_bytes()] and
** [sqlite3_column_bytes16()] do not include the zero terminators at the end
** of the string. ^For clarity: the values returned by
** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
@@ -4207,9 +4858,13 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** [sqlite3_column_value()] is used in any other way, including calls
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
** or [sqlite3_value_bytes()], the behavior is not threadsafe.
+** Hence, the sqlite3_column_value() interface
+** is normally only useful within the implementation of
+** [application-defined SQL functions] or [virtual tables], not within
+** top-level application code.
**
-** These routines attempt to convert the value where appropriate. ^For
-** example, if the internal representation is FLOAT and a text result
+** The these routines may attempt to convert the datatype of the result.
+** ^For example, if the internal representation is FLOAT and a text result
** is requested, [sqlite3_snprintf()] is used internally to perform the
** conversion automatically. ^(The following table details the conversions
** that are applied:
@@ -4281,26 +4936,40 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** ^The pointers returned are valid until a type conversion occurs as
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
-** and BLOBs is freed automatically. Do <em>not</em> pass the pointers returned
+** and BLOBs is freed automatically. Do not pass the pointers returned
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
-** ^(If a memory allocation error occurs during the evaluation of any
-** of these routines, a default value is returned. The default value
-** is either the integer 0, the floating point number 0.0, or a NULL
-** pointer. Subsequent calls to [sqlite3_errcode()] will return
-** [SQLITE_NOMEM].)^
+** As long as the input parameters are correct, these routines will only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_column_blob()
+** <li> sqlite3_column_text()
+** <li> sqlite3_column_text16()
+** <li> sqlite3_column_bytes()
+** <li> sqlite3_column_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
*/
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@@ -4360,17 +5029,17 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
-** KEYWORDS: {application-defined SQL function}
-** KEYWORDS: {application-defined SQL functions}
** METHOD: sqlite3
**
** ^These functions (collectively known as "function creation routines")
** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates. The only differences between
-** these routines are the text encoding expected for
-** the second parameter (the name of the function being created)
-** and the presence or absence of a destructor callback for
-** the application data pointer.
+** of existing SQL functions or aggregates. The only differences between
+** the three "sqlite3_create_function*" routines are the text encoding
+** expected for the second parameter (the name of the function being
+** created) and the presence or absence of a destructor callback for
+** the application data pointer. Function sqlite3_create_window_function()
+** is similar, but allows the user to supply the extra callback functions
+** needed by [aggregate window functions].
**
** ^The first parameter is the [database connection] to which the SQL
** function is to be added. ^If an application uses more than one database
@@ -4380,7 +5049,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** ^The second parameter is the name of the SQL function to be created or
** redefined. ^The length of the name is limited to 255 bytes in a UTF-8
** representation, exclusive of the zero-terminator. ^Note that the name
-** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
** ^Any attempt to create a function with a longer name
** will result in [SQLITE_MISUSE] being returned.
**
@@ -4395,7 +5064,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** ^The fourth parameter, eTextRep, specifies what
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
** its parameters. The application should set this parameter to
-** [SQLITE_UTF16LE] if the function implementation invokes
+** [SQLITE_UTF16LE] if the function implementation invokes
** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
** implementation invokes [sqlite3_value_text16be()] on an input, or
** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
@@ -4413,10 +5082,28 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
+** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
+** flag, which if present prevents the function from being invoked from
+** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
+** index expressions, or the WHERE clause of partial indexes.
+**
+** <span style="background-color:#ffff90;">
+** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
+** all application-defined SQL functions that do not need to be
+** used inside of triggers, view, CHECK constraints, or other elements of
+** the database schema. This flags is especially recommended for SQL
+** functions that have side effects or reveal internal application state.
+** Without this flag, an attacker might be able to modify the schema of
+** a database file to include invocations of the function with parameters
+** chosen by the attacker, which the application will then execute when
+** the database file is opened and read.
+** </span>
+**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
-** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
+** ^The sixth, seventh and eighth parameters passed to the three
+** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
** pointers to C-language functions that implement the SQL function or
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
** callback only; NULL pointers must be passed as the xStep and xFinal
@@ -4425,15 +5112,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** SQL function or aggregate, pass NULL pointers for all three function
** callbacks.
**
-** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
-** then it is destructor for the application data pointer.
-** The destructor is invoked when the function is deleted, either by being
-** overloaded or when the database connection closes.)^
-** ^The destructor is also invoked if the call to
-** sqlite3_create_function_v2() fails.
-** ^When the destructor callback of the tenth parameter is invoked, it
-** is passed a single argument which is a copy of the application data
-** pointer which was the fifth parameter to sqlite3_create_function_v2().
+** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
+** and xInverse) passed to sqlite3_create_window_function are pointers to
+** C-language callbacks that implement the new function. xStep and xFinal
+** must both be non-NULL. xValue and xInverse may either both be NULL, in
+** which case a regular aggregate function is created, or must both be
+** non-NULL, in which case the new function may be used as either an aggregate
+** or aggregate window function. More details regarding the implementation
+** of aggregate window functions are
+** [user-defined window functions|available here].
+**
+** ^(If the final parameter to sqlite3_create_function_v2() or
+** sqlite3_create_window_function() is not NULL, then it is destructor for
+** the application data pointer. The destructor is invoked when the function
+** is deleted, either by being overloaded or when the database connection
+** closes.)^ ^The destructor is also invoked if the call to
+** sqlite3_create_function_v2() fails. ^When the destructor callback is
+** invoked, it is passed a single argument which is a copy of the application
+** data pointer which was the fifth parameter to sqlite3_create_function_v2().
**
** ^It is permitted to register multiple implementations of the same
** functions with the same name but with either differing numbers of
@@ -4443,7 +5139,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** nArg parameter is a better match than a function implementation with
** a negative nArg. ^A function where the preferred text encoding
** matches the database encoding is a better
-** match than a function where the encoding is different.
+** match than a function where the encoding is different.
** ^A function where the encoding difference is between UTF16le and UTF16be
** is a closer match than a function where the encoding difference is
** between UTF8 and UTF16.
@@ -4486,6 +5182,18 @@ SQLITE_API int sqlite3_create_function_v2(
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*)
);
+SQLITE_API int sqlite3_create_window_function(
+ sqlite3 *db,
+ const char *zFunctionName,
+ int nArg,
+ int eTextRep,
+ void *pApp,
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+ void (*xFinal)(sqlite3_context*),
+ void (*xValue)(sqlite3_context*),
+ void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
+ void(*xDestroy)(void*)
+);
/*
** CAPI3REF: Text Encodings
@@ -4503,19 +5211,79 @@ SQLITE_API int sqlite3_create_function_v2(
/*
** CAPI3REF: Function Flags
**
-** These constants may be ORed together with the
+** These constants may be ORed together with the
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
+**
+** <dl>
+** [[SQLITE_DETERMINISTIC]] <dt>SQLITE_DETERMINISTIC</dt><dd>
+** The SQLITE_DETERMINISTIC flag means that the new function always gives
+** the same output when the input parameters are the same.
+** The [abs|abs() function] is deterministic, for example, but
+** [randomblob|randomblob()] is not. Functions must
+** be deterministic in order to be used in certain contexts such as
+** with the WHERE clause of [partial indexes] or in [generated columns].
+** SQLite might also optimize deterministic functions by factoring them
+** out of inner loops.
+** </dd>
+**
+** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd>
+** The SQLITE_DIRECTONLY flag means that the function may only be invoked
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
+** schema structures such as [CHECK constraints], [DEFAULT clauses],
+** [expression indexes], [partial indexes], or [generated columns].
+** The SQLITE_DIRECTONLY flags is a security feature which is recommended
+** for all [application-defined SQL functions], and especially for functions
+** that have side-effects or that could potentially leak sensitive
+** information.
+** </dd>
+**
+** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
+** The SQLITE_INNOCUOUS flag means that the function is unlikely
+** to cause problems even if misused. An innocuous function should have
+** no side effects and should not depend on any values other than its
+** input parameters. The [abs|abs() function] is an example of an
+** innocuous function.
+** The [load_extension() SQL function] is not innocuous because of its
+** side effects.
+** <p> SQLITE_INNOCUOUS is similar to SQLITE_DETERMINISTIC, but is not
+** exactly the same. The [random|random() function] is an example of a
+** function that is innocuous but not deterministic.
+** <p>Some heightened security settings
+** ([SQLITE_DBCONFIG_TRUSTED_SCHEMA] and [PRAGMA trusted_schema=OFF])
+** disable the use of SQL functions inside views and triggers and in
+** schema structures such as [CHECK constraints], [DEFAULT clauses],
+** [expression indexes], [partial indexes], and [generated columns] unless
+** the function is tagged with SQLITE_INNOCUOUS. Most built-in functions
+** are innocuous. Developers are advised to avoid using the
+** SQLITE_INNOCUOUS flag for application-defined functions unless the
+** function has been carefully audited and found to be free of potentially
+** security-adverse side-effects and information-leaks.
+** </dd>
+**
+** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
+** Specifying this flag makes no difference for scalar or aggregate user
+** functions. However, if it is not specified for a user-defined window
+** function, then any sub-types belonging to arguments passed to the window
+** function may be discarded before the window function is called (i.e.
+** sqlite3_value_subtype() will always return 0).
+** </dd>
+** </dl>
*/
-#define SQLITE_DETERMINISTIC 0x800
+#define SQLITE_DETERMINISTIC 0x000000800
+#define SQLITE_DIRECTONLY 0x000080000
+#define SQLITE_SUBTYPE 0x000100000
+#define SQLITE_INNOCUOUS 0x000200000
/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
**
** These functions are [deprecated]. In order to maintain
-** backwards compatibility with older code, these functions continue
+** backwards compatibility with older code, these functions continue
** to be supported. However, new applications should avoid
** the use of these functions. To encourage programmers to avoid
** these functions, we will not explain what they do.
@@ -4534,21 +5302,45 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** CAPI3REF: Obtaining SQL Values
** METHOD: sqlite3_value
**
-** The C-language implementation of SQL functions and aggregates uses
-** this set of interface routines to access the parameter values on
-** the function or aggregate.
-**
-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
-** define callbacks that implement the SQL functions and aggregates.
-** The 3rd parameter to these callbacks is an array of pointers to
-** [protected sqlite3_value] objects. There is one [sqlite3_value] object for
-** each parameter to the SQL function. These routines are used to
-** extract values from the [sqlite3_value] objects.
+** <b>Summary:</b>
+** <blockquote><table border=0 cellpadding=0 cellspacing=0>
+** <tr><td><b>sqlite3_value_blob</b><td>&rarr;<td>BLOB value
+** <tr><td><b>sqlite3_value_double</b><td>&rarr;<td>REAL value
+** <tr><td><b>sqlite3_value_int</b><td>&rarr;<td>32-bit INTEGER value
+** <tr><td><b>sqlite3_value_int64</b><td>&rarr;<td>64-bit INTEGER value
+** <tr><td><b>sqlite3_value_pointer</b><td>&rarr;<td>Pointer value
+** <tr><td><b>sqlite3_value_text</b><td>&rarr;<td>UTF-8 TEXT value
+** <tr><td><b>sqlite3_value_text16</b><td>&rarr;<td>UTF-16 TEXT value in
+** the native byteorder
+** <tr><td><b>sqlite3_value_text16be</b><td>&rarr;<td>UTF-16be TEXT value
+** <tr><td><b>sqlite3_value_text16le</b><td>&rarr;<td>UTF-16le TEXT value
+** <tr><td>&nbsp;<td>&nbsp;<td>&nbsp;
+** <tr><td><b>sqlite3_value_bytes</b><td>&rarr;<td>Size of a BLOB
+** or a UTF-8 TEXT in bytes
+** <tr><td><b>sqlite3_value_bytes16&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>Size of UTF-16
+** TEXT in bytes
+** <tr><td><b>sqlite3_value_type</b><td>&rarr;<td>Default
+** datatype of the value
+** <tr><td><b>sqlite3_value_numeric_type&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>Best numeric datatype of the value
+** <tr><td><b>sqlite3_value_nochange&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
+** against a virtual table.
+** <tr><td><b>sqlite3_value_frombind&nbsp;&nbsp;</b>
+** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
+** </table></blockquote>
+**
+** <b>Details:</b>
+**
+** These routines extract type, size, and content information from
+** [protected sqlite3_value] objects. Protected sqlite3_value objects
+** are used to pass parameter information into the functions that
+** implement [application-defined SQL functions] and [virtual tables].
**
** These routines work only with [protected sqlite3_value] objects.
** Any attempt to use these routines on an [unprotected sqlite3_value]
-** object results in undefined behavior.
+** is not threadsafe.
**
** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object
@@ -4559,6 +5351,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
** extract UTF-16 strings as big-endian and little-endian respectively.
**
+** ^If [sqlite3_value] object V was initialized
+** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
+** and if X and Y are strings that compare equal according to strcmp(X,Y),
+** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise,
+** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
+**
+** ^(The sqlite3_value_type(V) interface returns the
+** [SQLITE_INTEGER | datatype code] for the initial datatype of the
+** [sqlite3_value] object V. The returned value is one of [SQLITE_INTEGER],
+** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^
+** Other interfaces might change the datatype for an sqlite3_value object.
+** For example, if the datatype is initially SQLITE_INTEGER and
+** sqlite3_value_text(V) is called to extract a text value for that
+** integer, then subsequent calls to sqlite3_value_type(V) might return
+** SQLITE_TEXT. Whether or not a persistent internal datatype conversion
+** occurs is undefined and may change from one release of SQLite to the next.
+**
** ^(The sqlite3_value_numeric_type() interface attempts to apply
** numeric affinity to the value. This means that an attempt is
** made to convert the value to an integer or floating point. If
@@ -4567,6 +5377,24 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** then the conversion is performed. Otherwise no conversion occurs.
** The [SQLITE_INTEGER | datatype] after conversion is returned.)^
**
+** ^Within the [xUpdate] method of a [virtual table], the
+** sqlite3_value_nochange(X) interface returns true if and only if
+** the column corresponding to X is unchanged by the UPDATE operation
+** that the xUpdate method call was invoked to implement and if
+** and the prior [xColumn] method call that was invoked to extracted
+** the value for that column returned without setting a result (probably
+** because it queried [sqlite3_vtab_nochange()] and found that the column
+** was unchanging). ^Within an [xUpdate] method, any value for which
+** sqlite3_value_nochange(X) is true will in all other respects appear
+** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other
+** than within an [xUpdate] method call for an UPDATE statement, then
+** the return value is arbitrary and meaningless.
+**
+** ^The sqlite3_value_frombind(X) interface returns non-zero if the
+** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()]
+** interfaces. ^If X comes from an SQL literal value, or a table column,
+** or an expression, then sqlite3_value_frombind(X) returns zero.
+**
** Please pay particular attention to the fact that the pointer returned
** from [sqlite3_value_blob()], [sqlite3_value_text()], or
** [sqlite3_value_text16()] can be invalidated by a subsequent call to
@@ -4575,19 +5403,44 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
**
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
+**
+** As long as the input parameter is correct, these routines can only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_value_blob()
+** <li> sqlite3_value_text()
+** <li> sqlite3_value_text16()
+** <li> sqlite3_value_text16le()
+** <li> sqlite3_value_text16be()
+** <li> sqlite3_value_bytes()
+** <li> sqlite3_value_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
*/
SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
SQLITE_API double sqlite3_value_double(sqlite3_value*);
SQLITE_API int sqlite3_value_int(sqlite3_value*);
SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
+SQLITE_API void *sqlite3_value_pointer(sqlite3_value*, const char*);
SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
SQLITE_API int sqlite3_value_type(sqlite3_value*);
SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
+SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
@@ -4598,10 +5451,6 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
-**
-** SQLite makes no use of subtype itself. It merely passes the subtype
-** from the result of one [application-defined SQL function] into the
-** input of another.
*/
SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
@@ -4629,9 +5478,9 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
** Implementations of aggregate SQL functions use this
** routine to allocate memory for storing their state.
**
-** ^The first time the sqlite3_aggregate_context(C,N) routine is called
-** for a particular aggregate function, SQLite
-** allocates N of memory, zeroes out that memory, and returns a pointer
+** ^The first time the sqlite3_aggregate_context(C,N) routine is called
+** for a particular aggregate function, SQLite allocates
+** N bytes of memory, zeroes out that memory, and returns a pointer
** to the new memory. ^On second and subsequent calls to
** sqlite3_aggregate_context() for the same aggregate function instance,
** the same buffer is returned. Sqlite3_aggregate_context() is normally
@@ -4642,19 +5491,19 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^
**
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
-** value of N in subsequent call to sqlite3_aggregate_context() within
+** value of N in any subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory
** allocation.)^ Within the xFinal callback, it is customary to set
-** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
** pointless memory allocations occur.
**
-** ^SQLite automatically frees the memory allocated by
+** ^SQLite automatically frees the memory allocated by
** sqlite3_aggregate_context() when the aggregate query concludes.
**
** The first parameter must be a copy of the
@@ -4704,15 +5553,16 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** some circumstances the associated metadata may be preserved. An example
** of where this might be useful is in a regular-expression matching
** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** metadata associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function. ^If there is no metadata
-** associated with the function argument, this sqlite3_get_auxdata() interface
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
+** value to the application-defined function. ^N is zero for the left-most
+** function argument. ^If there is no metadata
+** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
@@ -4729,10 +5579,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** SQL statement)^, or
** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
** parameter)^, or
-** <li> ^(during the original sqlite3_set_auxdata() call when a memory
+** <li> ^(during the original sqlite3_set_auxdata() call when a memory
** allocation error occurs.)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last bullet in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
@@ -4743,6 +5593,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
+** The value of the N parameter to these interfaces should be non-negative.
+** Future enhancements may make use of negative N values to define new
+** kinds of function caching behavior.
+**
** These routines must be called from the same thread in which
** the SQL function is running.
*/
@@ -4800,8 +5654,9 @@ typedef void (*sqlite3_destructor_type)(void*);
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
** as the text of an error message. ^SQLite interprets the error
** message string from sqlite3_result_error() as UTF-8. ^SQLite
-** interprets the string from sqlite3_result_error16() as UTF-16 in native
-** byte order. ^If the third parameter to sqlite3_result_error()
+** interprets the string from sqlite3_result_error16() as UTF-16 using
+** the same [byte-order determination rules] as [sqlite3_bind_text16()].
+** ^If the third parameter to sqlite3_result_error()
** or sqlite3_result_error16() is negative then SQLite takes as the error
** message all text up through the first zero character.
** ^If the third parameter to sqlite3_result_error() or
@@ -4866,9 +5721,28 @@ typedef void (*sqlite3_destructor_type)(void*);
** when it has finished using that result.
** ^If the 4th parameter to the sqlite3_result_text* interfaces
** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
-** then SQLite makes a copy of the result into space obtained from
+** then SQLite makes a copy of the result into space obtained
** from [sqlite3_malloc()] before it returns.
**
+** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
+** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
+** when the encoding is not UTF8, if the input UTF16 begins with a
+** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
+** string and the rest of the string is interpreted according to the
+** byte-order specified by the BOM. ^The byte-order specified by
+** the BOM at the beginning of the text overrides the byte-order
+** specified by the interface procedure. ^So, for example, if
+** sqlite3_result_text16le() is invoked with text that begins
+** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
+** first two bytes of input are skipped and the remaining input
+** is interpreted as UTF16BE text.
+**
+** ^For UTF16 input text to the sqlite3_result_text16(),
+** sqlite3_result_text16be(), sqlite3_result_text16le(), and
+** sqlite3_result_text64() routines, if the text contains invalid
+** UTF16 characters, the invalid characters might be converted
+** into the unicode replacement character, U+FFFD.
+**
** ^The sqlite3_result_value() interface sets the result of
** the application-defined function to be a copy of the
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
@@ -4879,6 +5753,17 @@ typedef void (*sqlite3_destructor_type)(void*);
** [unprotected sqlite3_value] object is required, so either
** kind of [sqlite3_value] object can be used with this interface.
**
+** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
+** SQL NULL value, just like [sqlite3_result_null(C)], except that it
+** also associates the host-language pointer P or type T with that
+** NULL value such that the pointer can be retrieved within an
+** [application-defined SQL function] using [sqlite3_value_pointer()].
+** ^If the D parameter is not NULL, then it is a pointer to a destructor
+** for the P parameter. ^SQLite invokes D with P as its only argument
+** when SQLite is finished with P. The T parameter should be a static
+** string and preferably a string literal. The sqlite3_result_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
+**
** If these routines are called from within the different thread
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
@@ -4902,6 +5787,7 @@ SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*
SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
@@ -4911,8 +5797,8 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
** METHOD: sqlite3_context
**
** The sqlite3_result_subtype(C,T) function causes the subtype of
-** the result from the [application-defined SQL function] with
-** [sqlite3_context] C to be the value T. Only the lower 8 bits
+** the result from the [application-defined SQL function] with
+** [sqlite3_context] C to be the value T. Only the lower 8 bits
** of the subtype T are preserved in current versions of SQLite;
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
@@ -4942,7 +5828,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** <li> [SQLITE_UTF16_ALIGNED].
** </ul>)^
** ^The eTextRep argument determines the encoding of strings passed
-** to the collating function callback, xCallback.
+** to the collating function callback, xCompare.
** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep
** force strings to be UTF16 with native byte order.
** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin
@@ -4951,18 +5837,19 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** ^The fourth argument, pArg, is an application data pointer that is passed
** through as the first argument to the collating function callback.
**
-** ^The fifth argument, xCallback, is a pointer to the collating function.
+** ^The fifth argument, xCompare, is a pointer to the collating function.
** ^Multiple collating functions can be registered using the same name but
** with different eTextRep parameters and SQLite will use whichever
** function requires the least amount of data transformation.
-** ^If the xCallback argument is NULL then the collating function is
+** ^If the xCompare argument is NULL then the collating function is
** deleted. ^When all collating functions having the same name are deleted,
** that collation is no longer usable.
**
-** ^The collating function callback is invoked with a copy of the pArg
+** ^The collating function callback is invoked with a copy of the pArg
** application data pointer and with two strings in the encoding specified
-** by the eTextRep argument. The collating function must return an
-** integer that is negative, zero, or positive
+** by the eTextRep argument. The two integer parameters to the collating
+** function callback are the length of the two strings, in bytes. The collating
+** function must return an integer that is negative, zero, or positive
** if the first string is less than, equal to, or greater than the second,
** respectively. A collating function must always return the same answer
** given the same inputs. If two or more collating functions are registered
@@ -4979,7 +5866,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** </ol>
**
** If a collating function fails any of the above constraints and that
-** collating function is registered and used, then the behavior of SQLite
+** collating function is registered and used, then the behavior of SQLite
** is undefined.
**
** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation()
@@ -4989,36 +5876,36 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
** calls to the collation creation functions or when the
** [database connection] is closed using [sqlite3_close()].
**
-** ^The xDestroy callback is <u>not</u> called if the
+** ^The xDestroy callback is <u>not</u> called if the
** sqlite3_create_collation_v2() function fails. Applications that invoke
-** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
** check the return code and dispose of the application data pointer
** themselves rather than expecting SQLite to deal with it for them.
-** This is different from every other SQLite interface. The inconsistency
-** is unfortunate but cannot be changed without breaking backwards
+** This is different from every other SQLite interface. The inconsistency
+** is unfortunate but cannot be changed without breaking backwards
** compatibility.
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
SQLITE_API int sqlite3_create_collation(
- sqlite3*,
- const char *zName,
- int eTextRep,
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
SQLITE_API int sqlite3_create_collation_v2(
- sqlite3*,
- const char *zName,
- int eTextRep,
+ sqlite3*,
+ const char *zName,
+ int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
SQLITE_API int sqlite3_create_collation16(
- sqlite3*,
+ sqlite3*,
const void *zName,
- int eTextRep,
+ int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
@@ -5051,64 +5938,19 @@ SQLITE_API int sqlite3_create_collation16(
** [sqlite3_create_collation_v2()].
*/
SQLITE_API int sqlite3_collation_needed(
- sqlite3*,
- void*,
+ sqlite3*,
+ void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
SQLITE_API int sqlite3_collation_needed16(
- sqlite3*,
+ sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
-#ifdef SQLITE_HAS_CODEC
-/*
-** Specify the key for an encrypted database. This routine should be
-** called right after sqlite3_open().
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-SQLITE_API int sqlite3_key(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The key */
-);
-SQLITE_API int sqlite3_key_v2(
- sqlite3 *db, /* Database to be rekeyed */
- const char *zDbName, /* Name of the database */
- const void *pKey, int nKey /* The key */
-);
-
-/*
-** Change the key on an open database. If the current database is not
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
-** database is decrypted.
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-SQLITE_API int sqlite3_rekey(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The new key */
-);
-SQLITE_API int sqlite3_rekey_v2(
- sqlite3 *db, /* Database to be rekeyed */
- const char *zDbName, /* Name of the database */
- const void *pKey, int nKey /* The new key */
-);
-
-/*
-** Specify the activation key for a SEE database. Unless
-** activated, none of the SEE routines will work.
-*/
-SQLITE_API void sqlite3_activate_see(
- const char *zPassPhrase /* Activation phrase */
-);
-#endif
-
#ifdef SQLITE_ENABLE_CEROD
/*
-** Specify the activation key for a CEROD database. Unless
+** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
SQLITE_API void sqlite3_activate_cerod(
@@ -5164,7 +6006,7 @@ SQLITE_API int sqlite3_sleep(int);
** ^The [temp_store_directory pragma] may modify this variable and cause
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
** the [temp_store_directory pragma] always assumes that any string
-** that this variable points to is held in memory obtained from
+** that this variable points to is held in memory obtained from
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
@@ -5221,7 +6063,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory;
** ^The [data_store_directory pragma] may modify this variable and cause
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
** the [data_store_directory pragma] always assumes that any string
-** that this variable points to is held in memory obtained from
+** that this variable points to is held in memory obtained from
** [sqlite3_malloc] and the pragma may attempt to free that memory
** using [sqlite3_free].
** Hence, if this variable is modified directly, either it should be
@@ -5231,6 +6073,41 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory;
SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
/*
+** CAPI3REF: Win32 Specific Interface
+**
+** These interfaces are available only on Windows. The
+** [sqlite3_win32_set_directory] interface is used to set the value associated
+** with the [sqlite3_temp_directory] or [sqlite3_data_directory] variable, to
+** zValue, depending on the value of the type parameter. The zValue parameter
+** should be NULL to cause the previous value to be freed via [sqlite3_free];
+** a non-NULL value will be copied into memory obtained from [sqlite3_malloc]
+** prior to being used. The [sqlite3_win32_set_directory] interface returns
+** [SQLITE_OK] to indicate success, [SQLITE_ERROR] if the type is unsupported,
+** or [SQLITE_NOMEM] if memory could not be allocated. The value of the
+** [sqlite3_data_directory] variable is intended to act as a replacement for
+** the current directory on the sub-platforms of Win32 where that concept is
+** not present, e.g. WinRT and UWP. The [sqlite3_win32_set_directory8] and
+** [sqlite3_win32_set_directory16] interfaces behave exactly the same as the
+** sqlite3_win32_set_directory interface except the string parameter must be
+** UTF-8 or UTF-16, respectively.
+*/
+SQLITE_API int sqlite3_win32_set_directory(
+ unsigned long type, /* Identifier for directory being set or reset */
+ void *zValue /* New value for directory being set or reset */
+);
+SQLITE_API int sqlite3_win32_set_directory8(unsigned long type, const char *zValue);
+SQLITE_API int sqlite3_win32_set_directory16(unsigned long type, const void *zValue);
+
+/*
+** CAPI3REF: Win32 Directory Types
+**
+** These macros are only available on Windows. They define the allowed values
+** for the type argument to the [sqlite3_win32_set_directory] interface.
+*/
+#define SQLITE_WIN32_DATA_DIRECTORY_TYPE 1
+#define SQLITE_WIN32_TEMP_DIRECTORY_TYPE 2
+
+/*
** CAPI3REF: Test For Auto-Commit Mode
** KEYWORDS: {autocommit mode}
** METHOD: sqlite3
@@ -5271,16 +6148,31 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
** CAPI3REF: Return The Filename For A Database Connection
** METHOD: sqlite3
**
-** ^The sqlite3_db_filename(D,N) interface returns a pointer to a filename
-** associated with database N of connection D. ^The main database file
-** has the name "main". If there is no attached database N on the database
+** ^The sqlite3_db_filename(D,N) interface returns a pointer to the filename
+** associated with database N of connection D.
+** ^If there is no attached database N on the database
** connection D, or if database N is a temporary or in-memory database, then
-** a NULL pointer is returned.
+** this function will return either a NULL pointer or an empty string.
+**
+** ^The string value returned by this routine is owned and managed by
+** the database connection. ^The value will be valid until the database N
+** is [DETACH]-ed or until the database connection closes.
**
** ^The filename returned by this function is the output of the
** xFullPathname method of the [VFS]. ^In other words, the filename
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
+**
+** If the filename pointer returned by this routine is not NULL, then it
+** can be used as the filename input parameter to these routines:
+** <ul>
+** <li> [sqlite3_uri_parameter()]
+** <li> [sqlite3_uri_boolean()]
+** <li> [sqlite3_uri_int64()]
+** <li> [sqlite3_filename_database()]
+** <li> [sqlite3_filename_journal()]
+** <li> [sqlite3_filename_wal()]
+** </ul>
*/
SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
@@ -5384,11 +6276,11 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^In the case of an update, this is the [rowid] after the update takes place.
**
** ^(The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).)^
+** modified (i.e. sqlite_sequence).)^
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
**
** ^In the current implementation, the update hook
-** is not invoked when duplication rows are deleted because of an
+** is not invoked when conflicting rows are deleted because of an
** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook
** invoked when rows are deleted using the [truncate optimization].
** The exceptions defined in this paragraph might change in a future
@@ -5410,7 +6302,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** and [sqlite3_preupdate_hook()] interfaces.
*/
SQLITE_API void *sqlite3_update_hook(
- sqlite3*,
+ sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
);
@@ -5424,25 +6316,29 @@ SQLITE_API void *sqlite3_update_hook(
** and disabled if the argument is false.)^
**
** ^Cache sharing is enabled and disabled for an entire process.
-** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
+** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
-** Existing database connections continue use the sharing mode
+** Existing database connections continue to use the sharing mode
** that was in effect at the time they were opened.)^
**
** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled
** successfully. An [error code] is returned otherwise.)^
**
-** ^Shared cache is disabled by default. But this might change in
-** future releases of SQLite. Applications that care about shared
-** cache setting should set it explicitly.
+** ^Shared cache is disabled by default. It is recommended that it stay
+** that way. In other words, do not use this routine. This interface
+** continues to be provided for historical compatibility, but its use is
+** discouraged. Any use of shared cache is discouraged. If shared cache
+** must be used, it is recommended that shared cache only be enabled for
+** individual database connections using the [sqlite3_open_v2()] interface
+** with the [SQLITE_OPEN_SHAREDCACHE] flag.
**
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
-** and will always return SQLITE_MISUSE. On those systems,
-** shared cache mode should be enabled per-database connection via
+** and will always return SQLITE_MISUSE. On those systems,
+** shared cache mode should be enabled per-database connection via
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
**
** This interface is threadsafe on processors where writing a
@@ -5485,6 +6381,9 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
**
+** These interfaces impose limits on the amount of heap memory that will be
+** by all database connections within a single process.
+**
** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the
** soft limit on the amount of heap memory that may be allocated by SQLite.
** ^SQLite strives to keep heap memory utilization below the soft heap
@@ -5492,23 +6391,44 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** as heap memory usages approaches the limit.
** ^The soft heap limit is "soft" because even though SQLite strives to stay
** below the limit, it will exceed the limit rather than generate
-** an [SQLITE_NOMEM] error. In other words, the soft heap limit
+** an [SQLITE_NOMEM] error. In other words, the soft heap limit
** is advisory only.
**
-** ^The return value from sqlite3_soft_heap_limit64() is the size of
-** the soft heap limit prior to the call, or negative in the case of an
-** error. ^If the argument N is negative
-** then no change is made to the soft heap limit. Hence, the current
-** size of the soft heap limit can be determined by invoking
-** sqlite3_soft_heap_limit64() with a negative argument.
-**
-** ^If the argument N is zero then the soft heap limit is disabled.
+** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of
+** N bytes on the amount of memory that will be allocated. ^The
+** sqlite3_hard_heap_limit64(N) interface is similar to
+** sqlite3_soft_heap_limit64(N) except that memory allocations will fail
+** when the hard heap limit is reached.
**
-** ^(The soft heap limit is not enforced in the current implementation
+** ^The return value from both sqlite3_soft_heap_limit64() and
+** sqlite3_hard_heap_limit64() is the size of
+** the heap limit prior to the call, or negative in the case of an
+** error. ^If the argument N is negative
+** then no change is made to the heap limit. Hence, the current
+** size of heap limits can be determined by invoking
+** sqlite3_soft_heap_limit64(-1) or sqlite3_hard_heap_limit(-1).
+**
+** ^Setting the heap limits to zero disables the heap limiter mechanism.
+**
+** ^The soft heap limit may not be greater than the hard heap limit.
+** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
+** is invoked with a value of N that is greater than the hard heap limit,
+** the the soft heap limit is set to the value of the hard heap limit.
+** ^The soft heap limit is automatically enabled whenever the hard heap
+** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
+** the soft heap limit is outside the range of 1..N, then the soft heap
+** limit is set to N. ^Invoking sqlite3_soft_heap_limit64(0) when the
+** hard heap limit is enabled makes the soft heap limit equal to the
+** hard heap limit.
+**
+** The memory allocation limits can also be adjusted using
+** [PRAGMA soft_heap_limit] and [PRAGMA hard_heap_limit].
+**
+** ^(The heap limits are not enforced in the current implementation
** if one or more of following conditions are true:
**
** <ul>
-** <li> The soft heap limit is set to zero.
+** <li> The limit value is set to zero.
** <li> Memory accounting is disabled using a combination of the
** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and
** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option.
@@ -5519,21 +6439,11 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** from the heap.
** </ul>)^
**
-** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
-** the soft heap limit is enforced
-** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
-** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
-** the soft heap limit is enforced on every memory allocation. Without
-** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced
-** when memory is allocated by the page cache. Testing suggests that because
-** the page cache is the predominate memory user in SQLite, most
-** applications will achieve adequate soft heap limit enforcement without
-** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT].
-**
-** The circumstances under which SQLite will enforce the soft heap limit may
+** The circumstances under which SQLite will enforce the heap limits may
** changes in future releases of SQLite.
*/
SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 sqlite3_hard_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5557,11 +6467,13 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
** interface returns SQLITE_OK and fills in the non-NULL pointers in
** the final five arguments with appropriate values if the specified
** column exists. ^The sqlite3_table_column_metadata() interface returns
-** SQLITE_ERROR and if the specified column does not exist.
+** SQLITE_ERROR if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
-** does not.
+** does not. If the table name parameter T in a call to
+** sqlite3_table_column_metadata(X,D,T,C,...) is NULL then the result is
+** undefined behavior.
**
** ^The column is identified by the second, third and fourth parameters to
** this function. ^(The second parameter is either the name of the database
@@ -5595,7 +6507,7 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
**
** ^If the specified table is actually a view, an [error code] is returned.
**
-** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
** is not a [WITHOUT ROWID] table and an
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
** parameters are set for the explicitly declared column. ^(If there is no
@@ -5661,7 +6573,7 @@ SQLITE_API int sqlite3_table_column_metadata(
** prior to calling this API,
** otherwise an error will be returned.
**
-** <b>Security warning:</b> It is recommended that the
+** <b>Security warning:</b> It is recommended that the
** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
** interface. The use of the [sqlite3_enable_load_extension()] interface
** should be avoided. This will keep the SQL function [load_extension()]
@@ -5697,7 +6609,7 @@ SQLITE_API int sqlite3_load_extension(
** to enable or disable only the C-API.)^
**
** <b>Security warning:</b> It is recommended that extension loading
-** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
+** be enabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
** rather than this interface, so the [load_extension()] SQL function
** remains disabled. This will prevent SQL injections from giving attackers
** access to extension loading capabilities.
@@ -5748,7 +6660,7 @@ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
** initialization routine X that was registered using a prior call to
** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
-** routine returns 1 if initialization routine X was successfully
+** routine returns 1 if initialization routine X was successfully
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
@@ -5783,8 +6695,8 @@ typedef struct sqlite3_module sqlite3_module;
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
**
-** This structure, sometimes called a "virtual table module",
-** defines the implementation of a [virtual tables].
+** This structure, sometimes called a "virtual table module",
+** defines the implementation of a [virtual table].
** This structure consists mostly of methods for the module.
**
** ^A virtual table module is created by filling in a persistent
@@ -5823,11 +6735,14 @@ struct sqlite3_module {
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg);
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
- /* The methods above are in version 1 of the sqlite_module object. Those
+ /* 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);
+ /* The methods above are in versions 1 and 2 of the sqlite_module object.
+ ** Those below are for version 3 and greater. */
+ int (*xShadowName)(const char*);
};
/*
@@ -5870,7 +6785,7 @@ struct sqlite3_module {
** required by SQLite. If the table has at least 64 columns and any column
** to the right of the first 63 is required, then bit 63 of colUsed is also
** set. In other words, column iCol may be required if the expression
-** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
+** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
** non-zero.
**
** The [xBestIndex] method must fill aConstraintUsage[] with information
@@ -5878,7 +6793,13 @@ struct sqlite3_module {
** the right-hand side of the corresponding aConstraint[] is evaluated
** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit
** is true, then the constraint is assumed to be fully handled by the
-** virtual table and is not checked again by SQLite.)^
+** virtual table and might not be checked again by the byte code.)^ ^(The
+** aConstraintUsage[].omit flag is an optimization hint. When the omit flag
+** is left in its default setting of false, the constraint will always be
+** checked separately in byte code. If the omit flag is change to true, then
+** the constraint may or may not be checked in byte code. In other words,
+** when the omit flag is true there is no guarantee that the constraint will
+** not be checked again using byte code.)^
**
** ^The idxNum and idxPtr values are recorded and passed into the
** [xFilter] method.
@@ -5891,17 +6812,17 @@ struct sqlite3_module {
**
** ^The estimatedCost value is an estimate of the cost of a particular
** strategy. A cost of N indicates that the cost of the strategy is similar
-** to a linear scan of an SQLite table with N rows. A cost of log(N)
+** to a linear scan of an SQLite table with N rows. A cost of log(N)
** indicates that the expense of the operation is similar to that of a
** binary search on a unique indexed field of an SQLite table with N rows.
**
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
-** The xBestIndex method may optionally populate the idxFlags field with a
+** The xBestIndex method may optionally populate the idxFlags field with a
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
-** assumes that the strategy may visit at most one row.
+** assumes that the strategy may visit at most one row.
**
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
** SQLite also assumes that if a call to the xUpdate() method is made as
@@ -5914,14 +6835,14 @@ struct sqlite3_module {
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
-** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
+** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
** If a virtual table extension is
-** used with an SQLite version earlier than 3.8.2, the results of attempting
-** to read or write the estimatedRows field are undefined (but are likely
-** to included crashing the application). The estimatedRows field should
+** used with an SQLite version earlier than 3.8.2, the results of attempting
+** to read or write the estimatedRows field are undefined (but are likely
+** to include crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
-** was added for [version 3.9.0] ([dateof:3.9.0]).
+** was added for [version 3.9.0] ([dateof:3.9.0]).
** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
@@ -5960,26 +6881,36 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Virtual Table Scan Flags
+**
+** Virtual table implementations are allowed to set the
+** [sqlite3_index_info].idxFlags field to some combination of
+** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
/*
** CAPI3REF: Virtual Table Constraint Operator Codes
**
-** These macros defined the allowed values for the
+** These macros define the allowed values for the
** [sqlite3_index_info].aConstraint[].op field. Each value represents
** an operator that is part of a constraint term in the wHERE clause of
** a query that uses a [virtual table].
*/
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-#define SQLITE_INDEX_CONSTRAINT_LIKE 65
-#define SQLITE_INDEX_CONSTRAINT_GLOB 66
-#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
+#define SQLITE_INDEX_CONSTRAINT_GT 4
+#define SQLITE_INDEX_CONSTRAINT_LE 8
+#define SQLITE_INDEX_CONSTRAINT_LT 16
+#define SQLITE_INDEX_CONSTRAINT_GE 32
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
+#define SQLITE_INDEX_CONSTRAINT_LIKE 65
+#define SQLITE_INDEX_CONSTRAINT_GLOB 66
+#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
+#define SQLITE_INDEX_CONSTRAINT_NE 68
+#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
+#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
+#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
+#define SQLITE_INDEX_CONSTRAINT_IS 72
+#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
/*
** CAPI3REF: Register A Virtual Table Implementation
@@ -5991,7 +6922,7 @@ struct sqlite3_index_info {
** preexisting [virtual table] for the module.
**
** ^The module name is registered on the [database connection] specified
-** by the first parameter. ^The name of the module is given by the
+** by the first parameter. ^The name of the module is given by the
** second parameter. ^The third parameter is a pointer to
** the implementation of the [virtual table module]. ^The fourth
** parameter is an arbitrary client data pointer that is passed through
@@ -6006,6 +6937,12 @@ struct sqlite3_index_info {
** ^The sqlite3_create_module()
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
+**
+** ^If the third parameter (the pointer to the sqlite3_module object) is
+** NULL then no new module is create and any existing modules with the
+** same name are dropped.
+**
+** See also: [sqlite3_drop_modules()]
*/
SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
@@ -6022,6 +6959,23 @@ SQLITE_API int sqlite3_create_module_v2(
);
/*
+** CAPI3REF: Remove Unnecessary Virtual Table Implementations
+** METHOD: sqlite3
+**
+** ^The sqlite3_drop_modules(D,L) interface removes all virtual
+** table modules from database connection D except those named on list L.
+** The L parameter must be either NULL or a pointer to an array of pointers
+** to strings where the array is terminated by a single NULL pointer.
+** ^If the L parameter is NULL, then all virtual table modules are removed.
+**
+** See also: [sqlite3_create_module()]
+*/
+SQLITE_API int sqlite3_drop_modules(
+ sqlite3 *db, /* Remove modules from this connection */
+ const char **azKeep /* Except, do not remove the ones named here */
+);
+
+/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
**
@@ -6083,7 +7037,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** METHOD: sqlite3
**
** ^(Virtual tables can provide alternative implementations of functions
-** using the [xFindFunction] method of the [virtual table module].
+** using the [xFindFunction] method of the [virtual table module].
** But global versions of those functions
** must exist in order to be overloaded.)^
**
@@ -6134,7 +7088,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
-** ^(Parameter zDb is not the filename that contains the database, but
+** ^(Parameter zDb is not the filename that contains the database, but
** rather the symbolic name of the database. For attached databases, this is
** the name that appears after the AS keyword in the [ATTACH] statement.
** For the main database file, the database name is "main". For TEMP
@@ -6147,29 +7101,35 @@ typedef struct sqlite3_blob sqlite3_blob;
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
-** the API is not misused, it is always safe to call [sqlite3_blob_close()]
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
** on *ppBlob after this function it returns.
**
** This function fails with SQLITE_ERROR if any of the following are true:
** <ul>
-** <li> ^(Database zDb does not exist)^,
-** <li> ^(Table zTable does not exist within database zDb)^,
-** <li> ^(Table zTable is a WITHOUT ROWID table)^,
+** <li> ^(Database zDb does not exist)^,
+** <li> ^(Table zTable does not exist within database zDb)^,
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
** <li> ^(Column zColumn does not exist)^,
** <li> ^(Row iRow is not present in the table)^,
** <li> ^(The specified column of row iRow contains a value that is not
** a TEXT or BLOB value)^,
-** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
** constraint and the blob is being opened for read/write access)^,
-** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
** column zColumn is part of a [child key] definition and the blob is
** being opened for read/write access)^.
** </ul>
**
-** ^Unless it returns SQLITE_MISUSE, this function sets the
-** [database connection] error code and message accessible via
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+** ^Unless it returns SQLITE_MISUSE, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
+** A BLOB referenced by sqlite3_blob_open() may be read using the
+** [sqlite3_blob_read()] interface and modified by using
+** [sqlite3_blob_write()]. The [BLOB handle] can be moved to a
+** different row of the same table using the [sqlite3_blob_reopen()]
+** interface. However, the column, table, or database of a [BLOB handle]
+** cannot be changed after the [BLOB handle] is opened.
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
@@ -6188,11 +7148,15 @@ typedef struct sqlite3_blob sqlite3_blob;
** blob.
**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
-** and the built-in [zeroblob] SQL function may be used to create a
+** and the built-in [zeroblob] SQL function may be used to create a
** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
+**
+** See also: [sqlite3_blob_close()],
+** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
+** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
*/
SQLITE_API int sqlite3_blob_open(
sqlite3*,
@@ -6208,11 +7172,11 @@ SQLITE_API int sqlite3_blob_open(
** CAPI3REF: Move a BLOB Handle to a New Row
** METHOD: sqlite3_blob
**
-** ^This function is used to move an existing blob handle so that it points
+** ^This function is used to move an existing [BLOB handle] so that it points
** to a different row of the same database table. ^The new row is identified
** by the rowid value passed as the second argument. Only the row can be
** changed. ^The database, table and column on which the blob handle is open
-** remain the same. Moving an existing blob handle to a new row can be
+** remain the same. Moving an existing [BLOB handle] to a new row is
** faster than closing the existing handle and opening a new one.
**
** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
@@ -6234,7 +7198,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** DESTRUCTOR: sqlite3_blob
**
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
-** unconditionally. Even if this routine returns an error code, the
+** unconditionally. Even if this routine returns an error code, the
** handle is still closed.)^
**
** ^If the blob handle being closed was opened for read-write access, and if
@@ -6244,10 +7208,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
-** with a null pointer (such as would be returned by a failed call to
+** open blob handle results in undefined behaviour. ^Calling this routine
+** with a null pointer (such as would be returned by a failed call to
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
-** is passed a valid open blob handle, the values returned by the
+** is passed a valid open blob handle, the values returned by the
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
@@ -6256,7 +7220,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
** CAPI3REF: Return The Size Of An Open BLOB
** METHOD: sqlite3_blob
**
-** ^Returns the size in bytes of the BLOB accessible via the
+** ^Returns the size in bytes of the BLOB accessible via the
** successfully opened [BLOB handle] in its only argument. ^The
** incremental blob I/O routines can only read or overwriting existing
** blob content; they cannot change the size of a blob.
@@ -6307,9 +7271,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
**
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
** Otherwise, an [error code] or an [extended error code] is returned.)^
-** ^Unless SQLITE_MISUSE is returned, this function sets the
-** [database connection] error code and message accessible via
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
+** ^Unless SQLITE_MISUSE is returned, this function sets the
+** [database connection] error code and message accessible via
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
@@ -6318,9 +7282,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
-** [SQLITE_ERROR] is returned and no data is written. The size of the
-** BLOB (and hence the maximum value of N+iOffset) can be determined
-** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
+** [SQLITE_ERROR] is returned and no data is written. The size of the
+** BLOB (and hence the maximum value of N+iOffset) can be determined
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
@@ -6414,7 +7378,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** <ul>
** <li> SQLITE_MUTEX_FAST
** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
+** <li> SQLITE_MUTEX_STATIC_MAIN
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
@@ -6472,7 +7436,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable
+** sqlite3_mutex_try() as an optimization so this is acceptable
** behavior.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
@@ -6537,7 +7501,7 @@ SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
** The only difference is that the public sqlite3_XXX functions enumerated
** above silently ignore any invocations that pass a NULL pointer instead
** of a valid mutex handle. The implementations of the methods defined
-** by this structure are not required to handle this case, the results
+** by this structure are not required to handle this case. The results
** of passing a NULL pointer instead of a valid mutex handle are undefined
** (i.e. it is acceptable to provide an implementation that segfaults if
** it is passed a NULL pointer).
@@ -6616,7 +7580,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
*/
#define SQLITE_MUTEX_FAST 0
#define SQLITE_MUTEX_RECURSIVE 1
-#define SQLITE_MUTEX_STATIC_MASTER 2
+#define SQLITE_MUTEX_STATIC_MAIN 2
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
@@ -6631,11 +7595,15 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
+/* Legacy compatibility: */
+#define SQLITE_MUTEX_STATIC_MASTER 2
+
+
/*
** CAPI3REF: Retrieve the mutex for a database connection
** METHOD: sqlite3
**
-** ^This interface returns a pointer the [sqlite3_mutex] object that
+** ^This interface returns a pointer the [sqlite3_mutex] object that
** serializes access to the [database connection] given in the argument
** when the [threading mode] is Serialized.
** ^If the [threading mode] is Single-thread or Multi-thread then this
@@ -6646,6 +7614,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
** METHOD: sqlite3
+** KEYWORDS: {file control}
**
** ^The [sqlite3_file_control()] interface makes a direct call to the
** xFileControl method for the [sqlite3_io_methods] object associated
@@ -6660,11 +7629,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** the xFileControl method. ^The return value of the xFileControl
** method becomes the return value of this routine.
**
-** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes
+** A few opcodes for [sqlite3_file_control()] are handled directly
+** by the SQLite core and never invoke the
+** sqlite3_io_methods.xFileControl method.
+** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
** a pointer to the underlying [sqlite3_file] object to be written into
-** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER
-** case is a short-circuit path which does not actually invoke the
-** underlying sqlite3_io_methods.xFileControl method.
+** the space pointed to by the 4th parameter. The
+** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
+** the [sqlite3_file] object associated with the journal file instead of
+** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns
+** a pointer to the underlying [sqlite3_vfs] object for the file.
+** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
+** from the pager.
**
** ^If the second parameter (zDbName) does not match the name of any
** open database file, then SQLITE_ERROR is returned. ^This error
@@ -6674,7 +7650,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** an incorrect zDbName and an SQLITE_ERROR return from the underlying
** xFileControl method.
**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
+** See also: [file control opcodes]
*/
SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
@@ -6711,17 +7687,18 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_FIRST 5
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
-#define SQLITE_TESTCTRL_PRNG_RESET 7
+#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
#define SQLITE_TESTCTRL_PENDING_BYTE 11
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
-#define SQLITE_TESTCTRL_RESERVE 14
+#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
-#define SQLITE_TESTCTRL_ISKEYWORD 16
-#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
+#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
+#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
+#define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
@@ -6731,7 +7708,194 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_IMPOSTER 25
-#define SQLITE_TESTCTRL_LAST 25
+#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
+#define SQLITE_TESTCTRL_RESULT_INTREAL 27
+#define SQLITE_TESTCTRL_PRNG_SEED 28
+#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
+#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
+
+/*
+** CAPI3REF: SQL Keyword Checking
+**
+** These routines provide access to the set of SQL language keywords
+** recognized by SQLite. Applications can uses these routines to determine
+** whether or not a specific identifier needs to be escaped (for example,
+** by enclosing in double-quotes) so as not to confuse the parser.
+**
+** The sqlite3_keyword_count() interface returns the number of distinct
+** keywords understood by SQLite.
+**
+** The sqlite3_keyword_name(N,Z,L) interface finds the N-th keyword and
+** makes *Z point to that keyword expressed as UTF8 and writes the number
+** of bytes in the keyword into *L. The string that *Z points to is not
+** zero-terminated. The sqlite3_keyword_name(N,Z,L) routine returns
+** SQLITE_OK if N is within bounds and SQLITE_ERROR if not. If either Z
+** or L are NULL or invalid pointers then calls to
+** sqlite3_keyword_name(N,Z,L) result in undefined behavior.
+**
+** The sqlite3_keyword_check(Z,L) interface checks to see whether or not
+** the L-byte UTF8 identifier that Z points to is a keyword, returning non-zero
+** if it is and zero if not.
+**
+** The parser used by SQLite is forgiving. It is often possible to use
+** a keyword as an identifier as long as such use does not result in a
+** parsing ambiguity. For example, the statement
+** "CREATE TABLE BEGIN(REPLACE,PRAGMA,END);" is accepted by SQLite, and
+** creates a new table named "BEGIN" with three columns named
+** "REPLACE", "PRAGMA", and "END". Nevertheless, best practice is to avoid
+** using keywords as identifiers. Common techniques used to avoid keyword
+** name collisions include:
+** <ul>
+** <li> Put all identifier names inside double-quotes. This is the official
+** SQL way to escape identifier names.
+** <li> Put identifier names inside &#91;...&#93;. This is not standard SQL,
+** but it is what SQL Server does and so lots of programmers use this
+** technique.
+** <li> Begin every identifier with the letter "Z" as no SQL keywords start
+** with "Z".
+** <li> Include a digit somewhere in every identifier name.
+** </ul>
+**
+** Note that the number of keywords understood by SQLite can depend on
+** compile-time options. For example, "VACUUM" is not a keyword if
+** SQLite is compiled with the [-DSQLITE_OMIT_VACUUM] option. Also,
+** new keywords may be added to future releases of SQLite.
+*/
+SQLITE_API int sqlite3_keyword_count(void);
+SQLITE_API int sqlite3_keyword_name(int,const char**,int*);
+SQLITE_API int sqlite3_keyword_check(const char*,int);
+
+/*
+** CAPI3REF: Dynamic String Object
+** KEYWORDS: {dynamic string}
+**
+** An instance of the sqlite3_str object contains a dynamically-sized
+** string under construction.
+**
+** The lifecycle of an sqlite3_str object is as follows:
+** <ol>
+** <li> ^The sqlite3_str object is created using [sqlite3_str_new()].
+** <li> ^Text is appended to the sqlite3_str object using various
+** methods, such as [sqlite3_str_appendf()].
+** <li> ^The sqlite3_str object is destroyed and the string it created
+** is returned using the [sqlite3_str_finish()] interface.
+** </ol>
+*/
+typedef struct sqlite3_str sqlite3_str;
+
+/*
+** CAPI3REF: Create A New Dynamic String Object
+** CONSTRUCTOR: sqlite3_str
+**
+** ^The [sqlite3_str_new(D)] interface allocates and initializes
+** a new [sqlite3_str] object. To avoid memory leaks, the object returned by
+** [sqlite3_str_new()] must be freed by a subsequent call to
+** [sqlite3_str_finish(X)].
+**
+** ^The [sqlite3_str_new(D)] interface always returns a pointer to a
+** valid [sqlite3_str] object, though in the event of an out-of-memory
+** error the returned object might be a special singleton that will
+** silently reject new text, always return SQLITE_NOMEM from
+** [sqlite3_str_errcode()], always return 0 for
+** [sqlite3_str_length()], and always return NULL from
+** [sqlite3_str_finish(X)]. It is always safe to use the value
+** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter
+** to any of the other [sqlite3_str] methods.
+**
+** The D parameter to [sqlite3_str_new(D)] may be NULL. If the
+** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum
+** length of the string contained in the [sqlite3_str] object will be
+** the value set for [sqlite3_limit](D,[SQLITE_LIMIT_LENGTH]) instead
+** of [SQLITE_MAX_LENGTH].
+*/
+SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*);
+
+/*
+** CAPI3REF: Finalize A Dynamic String
+** DESTRUCTOR: sqlite3_str
+**
+** ^The [sqlite3_str_finish(X)] interface destroys the sqlite3_str object X
+** and returns a pointer to a memory buffer obtained from [sqlite3_malloc64()]
+** that contains the constructed string. The calling application should
+** pass the returned value to [sqlite3_free()] to avoid a memory leak.
+** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any
+** errors were encountered during construction of the string. ^The
+** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the
+** string in [sqlite3_str] object X is zero bytes long.
+*/
+SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
+
+/*
+** CAPI3REF: Add Content To A Dynamic String
+** METHOD: sqlite3_str
+**
+** These interfaces add content to an sqlite3_str object previously obtained
+** from [sqlite3_str_new()].
+**
+** ^The [sqlite3_str_appendf(X,F,...)] and
+** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf]
+** functionality of SQLite to append formatted text onto the end of
+** [sqlite3_str] object X.
+**
+** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S
+** onto the end of the [sqlite3_str] object X. N must be non-negative.
+** S must contain at least N non-zero bytes of content. To append a
+** zero-terminated string in its entirety, use the [sqlite3_str_appendall()]
+** method instead.
+**
+** ^The [sqlite3_str_appendall(X,S)] method appends the complete content of
+** zero-terminated string S onto the end of [sqlite3_str] object X.
+**
+** ^The [sqlite3_str_appendchar(X,N,C)] method appends N copies of the
+** single-byte character C onto the end of [sqlite3_str] object X.
+** ^This method can be used, for example, to add whitespace indentation.
+**
+** ^The [sqlite3_str_reset(X)] method resets the string under construction
+** inside [sqlite3_str] object X back to zero bytes in length.
+**
+** These methods do not return a result code. ^If an error occurs, that fact
+** is recorded in the [sqlite3_str] object and can be recovered by a
+** subsequent call to [sqlite3_str_errcode(X)].
+*/
+SQLITE_API void sqlite3_str_appendf(sqlite3_str*, const char *zFormat, ...);
+SQLITE_API void sqlite3_str_vappendf(sqlite3_str*, const char *zFormat, va_list);
+SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N);
+SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn);
+SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C);
+SQLITE_API void sqlite3_str_reset(sqlite3_str*);
+
+/*
+** CAPI3REF: Status Of A Dynamic String
+** METHOD: sqlite3_str
+**
+** These interfaces return the current status of an [sqlite3_str] object.
+**
+** ^If any prior errors have occurred while constructing the dynamic string
+** in sqlite3_str X, then the [sqlite3_str_errcode(X)] method will return
+** an appropriate error code. ^The [sqlite3_str_errcode(X)] method returns
+** [SQLITE_NOMEM] following any out-of-memory error, or
+** [SQLITE_TOOBIG] if the size of the dynamic string exceeds
+** [SQLITE_MAX_LENGTH], or [SQLITE_OK] if there have been no errors.
+**
+** ^The [sqlite3_str_length(X)] method returns the current length, in bytes,
+** of the dynamic string under construction in [sqlite3_str] object X.
+** ^The length returned by [sqlite3_str_length(X)] does not include the
+** zero-termination byte.
+**
+** ^The [sqlite3_str_value(X)] method returns a pointer to the current
+** content of the dynamic string under construction in X. The value
+** returned by [sqlite3_str_value(X)] is managed by the sqlite3_str object X
+** and might be freed or altered by any subsequent method on the same
+** [sqlite3_str] object. Applications must not used the pointer returned
+** [sqlite3_str_value(X)] after any subsequent method call on the same
+** object. ^Applications may change the content of the string returned
+** by [sqlite3_str_value(X)] as long as they do not write into any bytes
+** outside the range of 0 to [sqlite3_str_length(X)] and do not read or
+** write any byte after any subsequent sqlite3_str method call.
+*/
+SQLITE_API int sqlite3_str_errcode(sqlite3_str*);
+SQLITE_API int sqlite3_str_length(sqlite3_str*);
+SQLITE_API char *sqlite3_str_value(sqlite3_str*);
/*
** CAPI3REF: SQLite Runtime Status
@@ -6780,8 +7944,7 @@ SQLITE_API int sqlite3_status64(
** <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
-** and internal memory usage by the SQLite library. Scratch memory
-** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache
+** and internal memory usage by the SQLite library. Auxiliary page-cache
** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in
** this parameter. The amount returned is the sum of the allocation
** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^
@@ -6790,7 +7953,7 @@ SQLITE_API int sqlite3_status64(
** <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.
+** *pHighwater parameter to [sqlite3_status()] is of interest.
** The value written into the *pCurrent parameter is undefined.</dd>)^
**
** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
@@ -6799,11 +7962,11 @@ SQLITE_API int sqlite3_status64(
**
** [[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
+** [pagecache memory allocator] that was configured using
** [SQLITE_CONFIG_PAGECACHE]. The
** value returned is in pages, not in bytes.</dd>)^
**
-** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
+** [[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]
@@ -6815,36 +7978,21 @@ SQLITE_API int sqlite3_status64(
**
** [[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.
+** handed to the [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>)^
**
-** [[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
-** in bytes. Since a single thread may only have one scratch allocation
-** outstanding at time, this parameter also reports the number of threads
-** using scratch memory at the same time.</dd>)^
+** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
+** <dd>No longer used.</dd>
**
** [[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
-** returned include overflows because the requested allocation was too
-** larger (that is, because the requested allocation was larger than the
-** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer
-** slots were available.
-** </dd>)^
+** <dd>No longer used.</dd>
**
-** [[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>)^
+** [[SQLITE_STATUS_SCRATCH_SIZE]] <dt>SQLITE_STATUS_SCRATCH_SIZE</dt>
+** <dd>No longer used.</dd>
**
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
-** <dd>The *pHighwater parameter records the deepest parser stack.
+** <dd>The *pHighwater parameter records the deepest parser stack.
** The *pCurrent value is undefined. The *pHighwater value is only
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
** </dl>
@@ -6854,24 +8002,24 @@ SQLITE_API int sqlite3_status64(
#define SQLITE_STATUS_MEMORY_USED 0
#define SQLITE_STATUS_PAGECACHE_USED 1
#define SQLITE_STATUS_PAGECACHE_OVERFLOW 2
-#define SQLITE_STATUS_SCRATCH_USED 3
-#define SQLITE_STATUS_SCRATCH_OVERFLOW 4
+#define SQLITE_STATUS_SCRATCH_USED 3 /* NOT USED */
+#define SQLITE_STATUS_SCRATCH_OVERFLOW 4 /* NOT USED */
#define SQLITE_STATUS_MALLOC_SIZE 5
#define SQLITE_STATUS_PARSER_STACK 6
#define SQLITE_STATUS_PAGECACHE_SIZE 7
-#define SQLITE_STATUS_SCRATCH_SIZE 8
+#define SQLITE_STATUS_SCRATCH_SIZE 8 /* NOT USED */
#define SQLITE_STATUS_MALLOC_COUNT 9
/*
** CAPI3REF: Database Connection Status
** METHOD: sqlite3
**
-** ^This interface is used to retrieve runtime status information
+** ^This interface is used to retrieve runtime status information
** 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 options], that
-** determines the parameter to interrogate. The set of
+** determines the parameter to interrogate. The set of
** [SQLITE_DBSTATUS options] is likely
** to grow in future releases of SQLite.
**
@@ -6906,7 +8054,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** checked out.</dd>)^
**
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
-** <dd>This parameter returns the number malloc attempts that were
+** <dd>This parameter returns the number of malloc attempts that were
** satisfied using lookaside memory. Only the high-water value is meaningful;
** the current value is always zero.)^
**
@@ -6931,7 +8079,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
-** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
+** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
** pager cache is shared between two or more connections the bytes of heap
@@ -6946,7 +8094,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
-** with the connection - main, temp, and any [ATTACH]-ed databases.)^
+** with the connection - main, temp, and any [ATTACH]-ed databases.)^
** ^The full amount of memory used by the schemas is reported, even if the
** schema memory is shared with other database connections due to
** [shared cache mode] being enabled.
@@ -6961,13 +8109,13 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
**
** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(<dt>SQLITE_DBSTATUS_CACHE_HIT</dt>
** <dd>This parameter returns the number of pager cache hits that have
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
** is always 0.
** </dd>
**
** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt>
** <dd>This parameter returns the number of pager cache misses that have
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
** is always 0.
** </dd>
**
@@ -6982,6 +8130,15 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
** </dd>
**
+** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
+** <dd>This parameter returns the number of dirty cache entries that have
+** been written to disk in the middle of a transaction due to the page
+** cache overflowing. Transactions are more efficient if they are written
+** to disk all at once. When pages spill mid-transaction, that introduces
+** additional overhead. This parameter can be used help identify
+** inefficiencies that can be resolved by increasing the cache size.
+** </dd>
+**
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
** <dd>This parameter returns zero for the current value if and only if
** all foreign key constraints (deferred or immediate) have been
@@ -7001,7 +8158,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
#define SQLITE_DBSTATUS_CACHE_WRITE 9
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
-#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_SPILL 12
+#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */
/*
@@ -7015,7 +8173,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** statements. For example, if the number of table steps greatly exceeds
** the number of table searches or result rows, that would tend to indicate
** that the prepared statement is using a full table scan rather than
-** an index.
+** an index.
**
** ^(This interface is used to retrieve and reset counter values from
** a [prepared statement]. The first argument is the prepared statement
@@ -7042,7 +8200,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** [[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
+** may indicate opportunities for performance improvement through
** careful use of indices.</dd>
**
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
@@ -7060,10 +8218,28 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
** <dd>^This is the number of virtual machine operations executed
** by the prepared statement if that number is less than or equal
-** to 2147483647. The number of virtual machine operations can be
+** to 2147483647. The number of virtual machine operations can be
** used as a proxy for the total work done by the prepared statement.
** If the number of virtual machine operations exceeds 2147483647
** then the value returned by this statement status code is undefined.
+**
+** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
+** <dd>^This is the number of times that the prepare statement has been
+** automatically regenerated due to schema changes or changes to
+** [bound parameters] that might affect the query plan.
+**
+** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
+** <dd>^This is the number of times that the prepared statement has
+** been run. A single "run" for the purposes of this counter is one
+** or more calls to [sqlite3_step()] followed by a call to [sqlite3_reset()].
+** The counter is incremented on the first [sqlite3_step()] call of each
+** cycle.
+**
+** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
+** <dd>^This is the approximate number of bytes of heap memory
+** used to store the prepared statement. ^This value is not actually
+** a counter, and so the resetFlg parameter to sqlite3_stmt_status()
+** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED.
** </dd>
** </dl>
*/
@@ -7071,6 +8247,9 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
#define SQLITE_STMTSTATUS_VM_STEP 4
+#define SQLITE_STMTSTATUS_REPREPARE 5
+#define SQLITE_STMTSTATUS_RUN 6
+#define SQLITE_STMTSTATUS_MEMUSED 99
/*
** CAPI3REF: Custom Page Cache Object
@@ -7106,15 +8285,15 @@ struct sqlite3_pcache_page {
** KEYWORDS: {page cache}
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
-** register an alternative page cache implementation by passing in an
+** register an alternative page cache implementation by passing in an
** instance of the sqlite3_pcache_methods2 structure.)^
-** In many applications, most of the heap memory allocated by
+** In many applications, most of the heap memory allocated by
** SQLite is used for the page cache.
-** By implementing a
+** By implementing a
** custom page cache using this API, an application can better control
-** the amount of memory consumed by SQLite, the way in which
-** that memory is allocated and released, and the policies used to
-** determine exactly which parts of a database file are cached and for
+** the amount of memory consumed by SQLite, the way in which
+** that memory is allocated and released, and the policies used to
+** determine exactly which parts of a database file are cached and for
** how long.
**
** The alternative page cache mechanism is an
@@ -7127,19 +8306,19 @@ struct sqlite3_pcache_page {
** [sqlite3_config()] returns.)^
**
** [[the xInit() page cache method]]
-** ^(The xInit() method is called once for each effective
+** ^(The xInit() method is called once for each effective
** call to [sqlite3_initialize()])^
** (usually only once during the lifetime of the process). ^(The xInit()
** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^
-** The intent of the xInit() method is to set up global data structures
-** required by the custom page cache implementation.
-** ^(If the xInit() method is NULL, then the
+** The intent of the xInit() method is to set up global data structures
+** required by the custom page cache implementation.
+** ^(If the xInit() method is NULL, then the
** 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
+** It can be used to clean up
** any outstanding resources before process shutdown, if required.
** ^The xShutdown() method may be NULL.
**
@@ -7158,7 +8337,7 @@ struct sqlite3_pcache_page {
** though this is not guaranteed. ^The
** first parameter, szPage, is the size in bytes of the pages that must
** be allocated by the cache. ^szPage will always a power of two. ^The
-** second parameter szExtra is a number of bytes of extra storage
+** second parameter szExtra is a number of bytes of extra storage
** associated with each page cache entry. ^The szExtra parameter will
** a number less than 250. SQLite will use the
** extra szExtra bytes on each page to store metadata about the underlying
@@ -7171,7 +8350,7 @@ struct sqlite3_pcache_page {
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
** never invoke xUnpin() except to deliberately delete a page.
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
-** false will always have the "discard" flag set to true.
+** false will always have the "discard" flag set to true.
** ^Hence, a cache created with bPurgeable false will
** never contain any unpinned pages.
**
@@ -7186,12 +8365,12 @@ struct sqlite3_pcache_page {
** [[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 xFetch() method locates a page in the cache and returns a pointer to
** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
** The pBuf element of the returned sqlite3_pcache_page object will be a
-** pointer to a buffer of szPage bytes used to store the content of a
+** pointer to a buffer of szPage bytes used to store the content of a
** single database page. The pExtra element of sqlite3_pcache_page will be
** a pointer to the szExtra bytes of extra storage that SQLite has requested
** for each entry in the page cache.
@@ -7217,7 +8396,7 @@ struct sqlite3_pcache_page {
**
** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite
** will only use a createFlag of 2 after a prior call with a createFlag of 1
-** failed.)^ In between the to xFetch() calls, SQLite may
+** failed.)^ In between the xFetch() calls, SQLite may
** attempt to unpin one or more cache pages by spilling the content of
** pinned pages to disk and synching the operating system disk cache.
**
@@ -7230,8 +8409,8 @@ struct sqlite3_pcache_page {
** page cache implementation. ^The page cache implementation
** may choose to evict unpinned pages at any time.
**
-** The cache must not perform any reference counting. A single
-** call to xUnpin() unpins the page regardless of the number of prior calls
+** The cache must not perform any reference counting. A single
+** call to xUnpin() unpins the page regardless of the number of prior calls
** to xFetch().
**
** [[the xRekey() page cache methods]]
@@ -7271,7 +8450,7 @@ struct sqlite3_pcache_methods2 {
int (*xPagecount)(sqlite3_pcache*);
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
- void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
+ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
unsigned oldKey, unsigned newKey);
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
void (*xDestroy)(sqlite3_pcache*);
@@ -7316,7 +8495,7 @@ typedef struct sqlite3_backup sqlite3_backup;
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
-** for copying in-memory databases to or from persistent files.
+** for copying in-memory databases to or from persistent files.
**
** See Also: [Using the SQLite Online Backup API]
**
@@ -7327,36 +8506,36 @@ typedef struct sqlite3_backup sqlite3_backup;
** ^Thus, the backup may be performed on a live source database without
** preventing other database connections from
** reading or writing to the source database while the backup is underway.
-**
-** ^(To perform a backup operation:
+**
+** ^(To perform a backup operation:
** <ol>
** <li><b>sqlite3_backup_init()</b> is called once to initialize the
-** backup,
-** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
+** backup,
+** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
** the data between the two databases, and finally
-** <li><b>sqlite3_backup_finish()</b> is called to release all resources
-** associated with the backup operation.
+** <li><b>sqlite3_backup_finish()</b> is called to release all resources
+** associated with the backup operation.
** </ol>)^
** There should be exactly one call to sqlite3_backup_finish() for each
** successful call to sqlite3_backup_init().
**
** [[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
+** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
+** [database connection] associated with the destination database
** and the database name, respectively.
** ^The database name is "main" for the main database, "temp" for the
** temporary database, or the name specified after the AS keyword in
** an [ATTACH] statement for an attached database.
-** ^The S and M arguments passed to
+** ^The S and M arguments passed to
** sqlite3_backup_init(D,N,S,M) identify the [database connection]
** and database name of the source database, respectively.
** ^The source and destination [database connections] (parameters S and D)
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
-** ^A call to sqlite3_backup_init() will fail, returning NULL, if
-** there is already a read or read-write transaction open on the
+** ^A call to sqlite3_backup_init() will fail, returning NULL, if
+** there is already a read or read-write transaction open on the
** destination database.
**
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
@@ -7368,14 +8547,14 @@ typedef struct sqlite3_backup sqlite3_backup;
** ^A successful call to sqlite3_backup_init() returns a pointer to an
** [sqlite3_backup] object.
** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and
-** sqlite3_backup_finish() functions to perform the specified backup
+** sqlite3_backup_finish() functions to perform the specified backup
** operation.
**
** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
**
-** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
+** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
** the source and destination databases specified by [sqlite3_backup] object B.
-** ^If N is negative, all remaining source pages are copied.
+** ^If N is negative, all remaining source pages are copied.
** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
** are still more pages to be copied, then the function returns [SQLITE_OK].
** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
@@ -7397,8 +8576,8 @@ typedef struct sqlite3_backup sqlite3_backup;
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
-** is invoked (if one is specified). ^If the
-** busy-handler returns non-zero before the lock is available, then
+** is invoked (if one is specified). ^If the
+** busy-handler returns non-zero before the lock is available, then
** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
** sqlite3_backup_step() can be retried later. ^If the source
** [database connection]
@@ -7406,15 +8585,15 @@ typedef struct sqlite3_backup sqlite3_backup;
** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this
** case the call to sqlite3_backup_step() can be retried later on. ^(If
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or
-** [SQLITE_READONLY] is returned, then
-** there is no point in retrying the call to sqlite3_backup_step(). These
-** errors are considered fatal.)^ The application must accept
-** that the backup operation has failed and pass the backup operation handle
+** [SQLITE_READONLY] is returned, then
+** there is no point in retrying the call to sqlite3_backup_step(). These
+** errors are considered fatal.)^ The application must accept
+** that the backup operation has failed and pass the backup operation handle
** to the sqlite3_backup_finish() to release associated resources.
**
** ^The first call to sqlite3_backup_step() obtains an exclusive lock
-** on the destination file. ^The exclusive lock is not released until either
-** sqlite3_backup_finish() is called or the backup operation is complete
+** on the destination file. ^The exclusive lock is not released until either
+** sqlite3_backup_finish() is called or the backup operation is complete
** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to
** sqlite3_backup_step() obtains a [shared lock] on the source database that
** lasts for the duration of the sqlite3_backup_step() call.
@@ -7423,18 +8602,18 @@ typedef struct sqlite3_backup sqlite3_backup;
** through the backup process. ^If the source database is modified by an
** external process or via a database connection other than the one being
** used by the backup operation, then the backup will be automatically
-** restarted by the next call to sqlite3_backup_step(). ^If the source
+** restarted by the next call to sqlite3_backup_step(). ^If the source
** database is modified by the using the same database connection as is used
** by the backup operation, then the backup database is automatically
** updated at the same time.
**
** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
**
-** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
+** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
** application wishes to abandon the backup operation, the application
** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish().
** ^The sqlite3_backup_finish() interfaces releases all
-** resources associated with the [sqlite3_backup] object.
+** resources associated with the [sqlite3_backup] object.
** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any
** active write-transaction on the destination database is rolled back.
** The [sqlite3_backup] object is invalid
@@ -7474,8 +8653,8 @@ typedef struct sqlite3_backup sqlite3_backup;
** connections, then the source database connection may be used concurrently
** from within other threads.
**
-** However, the application must guarantee that the destination
-** [database connection] is not passed to any other API (by any thread) after
+** However, the application must guarantee that the destination
+** [database connection] is not passed to any other API (by any thread) after
** sqlite3_backup_init() is called and before the corresponding call to
** sqlite3_backup_finish(). SQLite does not currently check to see
** if the application incorrectly accesses the destination [database connection]
@@ -7486,11 +8665,11 @@ typedef struct sqlite3_backup sqlite3_backup;
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
** is not accessed while the backup is running. In practice this means
-** that the application must guarantee that the disk file being
+** that the application must guarantee that the disk file being
** backed up to is not accessed by any connection within the process,
** not just the specific connection that was passed to sqlite3_backup_init().
**
-** The [sqlite3_backup] object itself is partially threadsafe. Multiple
+** The [sqlite3_backup] object itself is partially threadsafe. Multiple
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
** APIs are not strictly speaking threadsafe. If they are invoked at the
@@ -7515,8 +8694,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
** individual tables within the shared-cache cannot be obtained. See
-** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
-** ^This API may be used to register a callback that SQLite will invoke
+** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
+** ^This API may be used to register a callback that SQLite will invoke
** when the connection currently holding the required lock relinquishes it.
** ^This API is only available if the library was compiled with the
** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined.
@@ -7524,18 +8703,18 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** See Also: [Using the SQLite Unlock Notification Feature].
**
** ^Shared-cache locks are released when a database connection concludes
-** its current transaction, either by committing it or rolling it back.
+** its current transaction, either by committing it or rolling it back.
**
** ^When a connection (known as the blocked connection) fails to obtain a
** shared-cache lock and SQLITE_LOCKED is returned to the caller, the
** identity of the database connection (the blocking connection) that
-** has locked the required resource is stored internally. ^After an
+** has locked the required resource is stored internally. ^After an
** application receives an SQLITE_LOCKED error, it may call the
-** sqlite3_unlock_notify() method with the blocked connection handle as
+** sqlite3_unlock_notify() method with the blocked connection handle as
** the first argument to register for a callback that will be invoked
** when the blocking connections current transaction is concluded. ^The
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
-** call that concludes the blocking connections transaction.
+** call that concludes the blocking connection's transaction.
**
** ^(If sqlite3_unlock_notify() is called in a multi-threaded application,
** there is a chance that the blocking connection will have already
@@ -7545,15 +8724,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** ^If the blocked connection is attempting to obtain a write-lock on a
** shared-cache table, and more than one other connection currently holds
-** a read-lock on the same table, then SQLite arbitrarily selects one of
+** a read-lock on the same table, then SQLite arbitrarily selects one of
** the other connections to use as the blocking connection.
**
-** ^(There may be at most one unlock-notify callback registered by a
+** ^(There may be at most one unlock-notify callback registered by a
** blocked connection. If sqlite3_unlock_notify() is called when the
** blocked connection already has a registered unlock-notify callback,
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
** called with a NULL pointer as its second argument, then any existing
-** unlock-notify callback is canceled. ^The blocked connections
+** unlock-notify callback is canceled. ^The blocked connections
** unlock-notify callback may also be canceled by closing the blocked
** connection using [sqlite3_close()].
**
@@ -7566,25 +8745,25 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** <b>Callback Invocation Details</b>
**
-** When an unlock-notify callback is registered, the application provides a
+** When an unlock-notify callback is registered, the application provides a
** single void* pointer that is passed to the callback when it is invoked.
** However, the signature of the callback function allows SQLite to pass
** it an array of void* context pointers. The first argument passed to
** an unlock-notify callback is a pointer to an array of void* pointers,
** and the second is the number of entries in the array.
**
-** When a blocking connections transaction is concluded, there may be
+** When a blocking connection's transaction is concluded, there may be
** more than one blocked connection that has registered for an unlock-notify
** callback. ^If two or more such blocked connections have specified the
** same callback function, then instead of invoking the callback function
** multiple times, it is invoked once with the set of void* context pointers
** specified by the blocked connections bundled together into an array.
-** This gives the application an opportunity to prioritize any actions
+** This gives the application an opportunity to prioritize any actions
** related to the set of unblocked database connections.
**
** <b>Deadlock Detection</b>
**
-** Assuming that after registering for an unlock-notify callback a
+** Assuming that after registering for an unlock-notify callback a
** database waits for the callback to be issued before taking any further
** action (a reasonable assumption), then using this API may cause the
** application to deadlock. For example, if connection X is waiting for
@@ -7607,7 +8786,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
**
** <b>The "DROP TABLE" Exception</b>
**
-** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
+** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
** always appropriate to call sqlite3_unlock_notify(). There is however,
** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
** SQLite checks if there are any currently executing SELECT statements
@@ -7620,7 +8799,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
** One way around this problem is to check the extended error code returned
** by an sqlite3_step() call. ^(If there is a blocking connection, then the
** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
-** the special "DROP TABLE/INDEX" case, the extended error code is just
+** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
SQLITE_API int sqlite3_unlock_notify(
@@ -7711,8 +8890,8 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** ^The [sqlite3_wal_hook()] function is used to register a callback that
** is invoked each time data is committed to a database in wal mode.
**
-** ^(The callback is invoked by SQLite after the commit has taken place and
-** the associated write-lock on the database released)^, so the implementation
+** ^(The callback is invoked by SQLite after the commit has taken place and
+** the associated write-lock on the database released)^, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
@@ -7731,7 +8910,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** that does not correspond to any valid SQLite error code, the results
** are undefined.
**
-** A single database handle may have at most a single write-ahead log callback
+** A single database handle may have at most a single write-ahead log callback
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
@@ -7739,7 +8918,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
** overwrite any prior [sqlite3_wal_hook()] settings.
*/
SQLITE_API void *sqlite3_wal_hook(
- sqlite3*,
+ sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
);
@@ -7752,7 +8931,7 @@ SQLITE_API void *sqlite3_wal_hook(
** [sqlite3_wal_hook()] that causes any database on [database connection] D
** to automatically [checkpoint]
** after committing a transaction if there are N or
-** more frames in the [write-ahead log] file. ^Passing zero or
+** more frames in the [write-ahead log] file. ^Passing zero or
** a negative value as the nFrame parameter disables automatic
** checkpoints entirely.
**
@@ -7782,7 +8961,7 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
**
-** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
** [write-ahead log] for database X on [database connection] D to be
** transferred into the database file and for the write-ahead log to
** be reset. See the [checkpointing] documentation for addition
@@ -7808,10 +8987,10 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
**
** <dl>
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
-** ^Checkpoint as many frames as possible without waiting for any database
-** readers or writers to finish, then sync the database file if all frames
+** ^Checkpoint as many frames as possible without waiting for any database
+** readers or writers to finish, then sync the database file if all frames
** in the log were checkpointed. ^The [busy-handler callback]
-** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
** ^On the other hand, passive mode might leave the checkpoint unfinished
** if there are concurrent readers or writers.
**
@@ -7825,9 +9004,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
**
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
-** that after checkpointing the log file it blocks (calls the
+** that after checkpointing the log file it blocks (calls the
** [busy-handler callback])
-** until all readers are reading from the database file only. ^This ensures
+** until all readers are reading from the database file only. ^This ensures
** that the next writer will restart the log file from the beginning.
** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
** database writer attempts while it is pending, but does not impede readers.
@@ -7849,31 +9028,31 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
**
** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
-** any other process is running a checkpoint operation at the same time, the
-** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
+** any other process is running a checkpoint operation at the same time, the
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
** busy-handler configured, it will not be invoked in this case.
**
-** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
** exclusive "writer" lock on the database file. ^If the writer lock cannot be
** obtained immediately, and a busy-handler is configured, it is invoked and
** the writer lock retried until either the busy-handler returns 0 or the lock
** is successfully obtained. ^The busy-handler is also invoked while waiting for
** database readers as described above. ^If the busy-handler returns 0 before
** the writer lock is obtained or while waiting for database readers, the
-** checkpoint operation proceeds from that point in the same way as
-** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
+** checkpoint operation proceeds from that point in the same way as
+** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
** without blocking any further. ^SQLITE_BUSY is returned in this case.
**
** ^If parameter zDb is NULL or points to a zero length string, then the
-** specified operation is attempted on all WAL databases [attached] to
+** specified operation is attempted on all WAL databases [attached] to
** [database connection] db. In this case the
-** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
-** an SQLITE_BUSY error is encountered when processing one or more of the
-** attached WAL databases, the operation is still attempted on any remaining
-** attached databases and SQLITE_BUSY is returned at the end. ^If any other
-** error occurs while processing an attached database, processing is abandoned
-** and the error code is returned to the caller immediately. ^If no error
-** (SQLITE_BUSY or otherwise) is encountered while processing the attached
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
+** an SQLITE_BUSY error is encountered when processing one or more of the
+** attached WAL databases, the operation is still attempted on any remaining
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
+** error occurs while processing an attached database, processing is abandoned
+** and the error code is returned to the caller immediately. ^If no error
+** (SQLITE_BUSY or otherwise) is encountered while processing the attached
** databases, SQLITE_OK is returned.
**
** ^If database zDb is the name of an attached database that is not in WAL
@@ -7921,21 +9100,28 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
** 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.
+** In the call sqlite3_vtab_config(D,C,...) the D parameter is the
+** [database connection] in which the virtual table is being created and
+** which is passed in as the first argument to the [xConnect] or [xCreate]
+** method that is invoking sqlite3_vtab_config(). The C parameter is one
+** of the [virtual table configuration options]. The presence and meaning
+** of parameters after C depend on which [virtual table configuration option]
+** is used.
*/
SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
+** KEYWORDS: {virtual table configuration options}
+** KEYWORDS: {virtual table configuration option}
**
** 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
+** [[SQLITE_VTAB_CONSTRAINT_SUPPORT]]
+** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT</dt>
** <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
@@ -7949,24 +9135,46 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** 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
+** 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.
+** 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
+** 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
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
** constraint handling.
+** </dd>
+**
+** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** prohibits that virtual table from being used from within triggers and
+** views.
+** </dd>
+**
+** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** identify that virtual table as being safe to use from within triggers
+** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
+** virtual table can do no serious harm even if it is controlled by a
+** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
+** flag unless absolutely necessary.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
+#define SQLITE_VTAB_INNOCUOUS 2
+#define SQLITE_VTAB_DIRECTONLY 3
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -7981,6 +9189,40 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
+** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
+**
+** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
+** method of a [virtual table], then it returns true if and only if the
+** column is being fetched as part of an UPDATE operation during which the
+** column value will not change. Applications might use this to substitute
+** a return value that is less expensive to compute and that the corresponding
+** [xUpdate] method understands as a "no-change" value.
+**
+** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
+** the column is not changed by the UPDATE statement, then the xColumn
+** method can optionally return without setting a result, without calling
+** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
+** In that case, [sqlite3_value_nochange(X)] will return true for the
+** same column in the [xUpdate] method.
+*/
+SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
+
+/*
+** CAPI3REF: Determine The Collation For a Virtual Table Constraint
+**
+** This function may only be called from within a call to the [xBestIndex]
+** method of a [virtual table].
+**
+** The first argument must be the sqlite3_index_info object that is the
+** first parameter to the xBestIndex() method. The second argument must be
+** an index into the aConstraint[] array belonging to the sqlite3_index_info
+** structure passed to xBestIndex. This function returns a pointer to a buffer
+** containing the name of the collation sequence for the corresponding
+** constraint.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
+
+/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
**
@@ -8012,15 +9254,15 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
-** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
+** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
-** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
+** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be set
** to the total number of rows examined by all iterations of the X-th loop.</dd>
**
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
-** <dd>^The "double" variable pointed to by the T parameter will be set to the
+** <dd>^The "double" variable pointed to by the V parameter will be set to the
** query planner's estimate for the average number of rows output from each
** iteration of the X-th loop. If the query planner's estimates was accurate,
** then this value will approximate the quotient NVISIT/NLOOP and the
@@ -8028,17 +9270,17 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
** be the NLOOP value for the current loop.
**
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
-** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the name of the index or table
** used for the X-th loop.
**
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
-** <dd>^The "const char *" variable pointed to by the T parameter will be set
+** <dd>^The "const char *" variable pointed to by the V parameter will be set
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
-** <dd>^The "int" variable pointed to by the T parameter will be set to the
+** <dd>^The "int" variable pointed to by the V parameter will be set to the
** "select-id" for the X-th loop. The select-id identifies which query or
** subquery the loop is part of. The main query has a select-id of zero.
** The select-id is the same value as is output in the first column
@@ -8088,7 +9330,7 @@ SQLITE_API int sqlite3_stmt_scanstatus(
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
-);
+);
/*
** CAPI3REF: Zero Scan-Status Counters
@@ -8106,15 +9348,15 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
**
** ^If a write-transaction is open on [database connection] D when the
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
-** pages in the pager-cache that are not currently in use are written out
+** pages in the pager-cache that are not currently in use are written out
** to disk. A dirty page may be in use if a database cursor created by an
** active SQL statement is reading from it, or if it is page 1 of a database
** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
** interface flushes caches for all schemas - "main", "temp", and
** any [attached] databases.
**
-** ^If this function needs to obtain extra database locks before dirty pages
-** can be flushed to disk, it does so. ^If those locks cannot be obtained
+** ^If this function needs to obtain extra database locks before dirty pages
+** can be flushed to disk, it does so. ^If those locks cannot be obtained
** immediately and there is a busy-handler callback configured, it is invoked
** in the usual manner. ^If the required lock still cannot be obtained, then
** the database is skipped and an attempt made to flush any dirty pages
@@ -8141,7 +9383,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
**
** ^The [sqlite3_preupdate_hook()] interface registers a callback function
** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
-** on a [rowid table].
+** on a database table.
** ^At most one preupdate hook may be registered at a time on a single
** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
** the previous setting.
@@ -8150,9 +9392,9 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
** the first parameter to callbacks.
**
-** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
-** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
-** tables.
+** ^The preupdate hook only fires for changes to real database tables; the
+** preupdate hook is not invoked for changes to [virtual tables] or to
+** system tables like sqlite_sequence or sqlite_stat1.
**
** ^The second parameter to the preupdate callback is a pointer to
** the [database connection] that registered the preupdate hook.
@@ -8161,17 +9403,21 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** kind of update operation that is about to occur.
** ^(The fourth parameter to the preupdate callback is the name of the
** database within the database connection that is being modified. This
-** will be "main" for the main database or "temp" for TEMP tables or
+** will be "main" for the main database or "temp" for TEMP tables or
** the name given after the AS keyword in the [ATTACH] statement for attached
** databases.)^
** ^The fifth parameter to the preupdate callback is the name of the
** table that is being modified.
-** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
-** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
-** undefined for SQLITE_INSERT changes.
-** ^The seventh parameter to the preupdate callback is the final [rowid] of
-** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
-** undefined for SQLITE_DELETE changes.
+**
+** For an UPDATE or DELETE operation on a [rowid table], the sixth
+** parameter passed to the preupdate callback is the initial [rowid] of the
+** row being modified or deleted. For an INSERT operation on a rowid table,
+** or any operation on a WITHOUT ROWID table, the value of the sixth
+** parameter is undefined. For an INSERT or UPDATE on a rowid table the
+** seventh parameter is the final rowid value of the row being inserted
+** or updated. The value of the seventh parameter passed to the callback
+** function is not defined for operations on WITHOUT ROWID tables, or for
+** INSERT operations on rowid tables.
**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
@@ -8205,13 +9451,14 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
**
** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
** callback was invoked as a result of a direct insert, update, or delete
-** operation; or 1 for inserts, updates, or deletes invoked by top-level
+** operation; or 1 for inserts, updates, or deletes invoked by top-level
** triggers; or 2 for changes resulting from triggers called by top-level
** triggers; and so forth.
**
** See also: [sqlite3_update_hook()]
*/
-SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
+#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+SQLITE_API void *sqlite3_preupdate_hook(
sqlite3 *db,
void(*xPreUpdate)(
void *pCtx, /* Copy of third arg to preupdate_hook() */
@@ -8224,10 +9471,11 @@ SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_preupdate_hook(
),
void*
);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_count(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_depth(sqlite3 *);
-SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
+SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
+SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
+#endif
/*
** CAPI3REF: Low-level system error code
@@ -8237,14 +9485,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_preupdate_new(sqlite3 *, int, sqlite3
** The return value is OS-dependent. For example, on unix systems, after
** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
** called to get back the underlying "errno" that caused the problem, such
-** as ENOSPC, EAUTH, EISDIR, and so forth.
+** as ENOSPC, EAUTH, EISDIR, and so forth.
*/
SQLITE_API int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Database Snapshot
-** KEYWORDS: {snapshot}
-** EXPERIMENTAL
+** KEYWORDS: {snapshot} {sqlite3_snapshot}
**
** An instance of the snapshot object records the state of a [WAL mode]
** database for some specific point in history.
@@ -8261,33 +9508,53 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
** version of the database file so that it is possible to later open a new read
** transaction that sees that historical version of the database rather than
** the most recent version.
-**
-** The constructor for this object is [sqlite3_snapshot_get()]. The
-** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
-** to an historical snapshot (if possible). The destructor for
-** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
*/
-typedef struct sqlite3_snapshot sqlite3_snapshot;
+typedef struct sqlite3_snapshot {
+ unsigned char hidden[48];
+} sqlite3_snapshot;
/*
** CAPI3REF: Record A Database Snapshot
-** EXPERIMENTAL
+** CONSTRUCTOR: sqlite3_snapshot
**
** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
** new [sqlite3_snapshot] object that records the current state of
** schema S in database connection D. ^On success, the
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
-** ^If schema S of [database connection] D is not a [WAL mode] database
-** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
-** leaves the *P value unchanged and returns an appropriate [error code].
+** If there is not already a read-transaction open on schema S when
+** this function is called, one is opened automatically.
+**
+** The following must be true for this function to succeed. If any of
+** the following statements are false when sqlite3_snapshot_get() is
+** called, SQLITE_ERROR is returned. The final value of *P is undefined
+** in this case.
+**
+** <ul>
+** <li> The database handle must not be in [autocommit mode].
+**
+** <li> Schema S of [database connection] D must be a [WAL mode] database.
+**
+** <li> There must not be a write transaction open on schema S of database
+** connection D.
+**
+** <li> One or more transactions must have been written to the current wal
+** file since it was created on disk (by any connection). This means
+** that a snapshot cannot be taken on a wal mode database with no wal
+** file immediately after it is first opened. At least one transaction
+** must be written to it first.
+** </ul>
+**
+** This function may also return SQLITE_NOMEM. If it is called with the
+** database handle in autocommit mode but fails for some other reason,
+** whether or not a read transaction is opened on schema S is undefined.
**
** The [sqlite3_snapshot] object returned from a successful call to
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
** to avoid a memory leak.
**
** The [sqlite3_snapshot_get()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
sqlite3 *db,
@@ -8297,35 +9564,46 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
/*
** CAPI3REF: Start a read transaction on an historical snapshot
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
+**
+** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
+** transaction or upgrades an existing one for schema S of
+** [database connection] D such that the read transaction refers to
+** historical [snapshot] P, rather than the most recent change to the
+** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
+** on success or an appropriate [error code] if it fails.
+**
+** ^In order to succeed, the database connection must not be in
+** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
+** is already a read transaction open on schema S, then the database handle
+** must have no active statements (SELECT statements that have been passed
+** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
+** SQLITE_ERROR is returned if either of these conditions is violated, or
+** if schema S does not exist, or if the snapshot object is invalid.
+**
+** ^A call to sqlite3_snapshot_open() will fail to open if the specified
+** snapshot has been overwritten by a [checkpoint]. In this case
+** SQLITE_ERROR_SNAPSHOT is returned.
+**
+** If there is already a read transaction open when this function is
+** invoked, then the same read transaction remains open (on the same
+** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
+** is returned. If another error code - for example SQLITE_PROTOCOL or an
+** SQLITE_IOERR error code - is returned, then the final state of the
+** read transaction is undefined. If SQLITE_OK is returned, then the
+** read transaction is now open on database snapshot P.
**
-** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
-** read transaction for schema S of
-** [database connection] D such that the read transaction
-** refers to historical [snapshot] P, rather than the most
-** recent change to the database.
-** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
-** or an appropriate [error code] if it fails.
-**
-** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
-** the first operation following the [BEGIN] that takes the schema S
-** out of [autocommit mode].
-** ^In other words, schema S must not currently be in
-** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
-** database connection D must be out of [autocommit mode].
-** ^A [snapshot] will fail to open if it has been overwritten by a
-** [checkpoint].
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
** database connection D does not know that the database file for
** schema S is in [WAL mode]. A database connection might not know
** that the database file is in [WAL mode] if there has been no prior
-** I/O on that database connection, or if the database entered [WAL mode]
+** I/O on that database connection, or if the database entered [WAL mode]
** after the most recent I/O on the database connection.)^
** (Hint: Run "[PRAGMA application_id]" against a newly opened
** database connection in order to make it ready to use snapshots.)
**
** The [sqlite3_snapshot_open()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
sqlite3 *db,
@@ -8335,38 +9613,41 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
/*
** CAPI3REF: Destroy a snapshot
-** EXPERIMENTAL
+** DESTRUCTOR: sqlite3_snapshot
**
** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
** The application must eventually free every [sqlite3_snapshot] object
** using this routine to avoid a memory leak.
**
** The [sqlite3_snapshot_free()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
*/
SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
/*
** CAPI3REF: Compare the ages of two snapshot handles.
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
**
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
-** of two valid snapshot handles.
+** of two valid snapshot handles.
**
-** If the two snapshot handles are not associated with the same database
-** file, the result of the comparison is undefined.
+** If the two snapshot handles are not associated with the same database
+** file, the result of the comparison is undefined.
**
** Additionally, the result of the comparison is only valid if both of the
** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
** last time the wal file was deleted. The wal file is deleted when the
** database is changed back to rollback mode or when the number of database
-** clients drops to zero. If either snapshot handle was obtained before the
-** wal file was last deleted, the value returned by this function
+** clients drops to zero. If either snapshot handle was obtained before the
+** wal file was last deleted, the value returned by this function
** is undefined.
**
** Otherwise, this API returns a negative value if P1 refers to an older
** snapshot than P2, zero if the two handles refer to the same database
** snapshot, and a positive value if P1 is a newer snapshot than P2.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
sqlite3_snapshot *p1,
@@ -8374,6 +9655,153 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
);
/*
+** CAPI3REF: Recover snapshots from a wal file
+** METHOD: sqlite3_snapshot
+**
+** If a [WAL file] remains on disk after all database connections close
+** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control]
+** or because the last process to have the database opened exited without
+** calling [sqlite3_close()]) and a new connection is subsequently opened
+** on that database and [WAL file], the [sqlite3_snapshot_open()] interface
+** will only be able to open the last transaction added to the WAL file
+** even though the WAL file contains other valid transactions.
+**
+** This function attempts to scan the WAL file associated with database zDb
+** of database handle db and make all valid snapshots available to
+** sqlite3_snapshot_open(). It is an error if there is already a read
+** transaction open on the database, or if the database is not a WAL mode
+** database.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
+
+/*
+** CAPI3REF: Serialize a database
+**
+** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
+** that is a serialization of the S database on [database connection] D.
+** If P is not a NULL pointer, then the size of the database in bytes
+** is written into *P.
+**
+** For an ordinary on-disk database file, the serialization is just a
+** copy of the disk file. For an in-memory database or a "TEMP" database,
+** the serialization is the same sequence of bytes which would be written
+** to disk if that database where backed up to disk.
+**
+** The usual case is that sqlite3_serialize() copies the serialization of
+** the database into memory obtained from [sqlite3_malloc64()] and returns
+** a pointer to that memory. The caller is responsible for freeing the
+** returned value to avoid a memory leak. However, if the F argument
+** contains the SQLITE_SERIALIZE_NOCOPY bit, then no memory allocations
+** are made, and the sqlite3_serialize() function will return a pointer
+** to the contiguous memory representation of the database that SQLite
+** is currently using for that database, or NULL if the no such contiguous
+** memory representation of the database exists. A contiguous memory
+** representation of the database will usually only exist if there has
+** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
+** values of D and S.
+** The size of the database is written into *P even if the
+** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
+** of the database exists.
+**
+** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
+** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
+** allocation error occurs.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_DESERIALIZE] option.
+*/
+SQLITE_API unsigned char *sqlite3_serialize(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */
+ sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */
+ unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_serialize
+**
+** Zero or more of the following constants can be OR-ed together for
+** the F argument to [sqlite3_serialize(D,S,P,F)].
+**
+** SQLITE_SERIALIZE_NOCOPY means that [sqlite3_serialize()] will return
+** a pointer to contiguous in-memory database that it is currently using,
+** without making a copy of the database. If SQLite is not currently using
+** a contiguous in-memory database, then this option causes
+** [sqlite3_serialize()] to return a NULL pointer. SQLite will only be
+** using a contiguous in-memory database if it has been initialized by a
+** prior call to [sqlite3_deserialize()].
+*/
+#define SQLITE_SERIALIZE_NOCOPY 0x001 /* Do no memory allocations */
+
+/*
+** CAPI3REF: Deserialize a database
+**
+** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
+** [database connection] D to disconnect from database S and then
+** reopen S as an in-memory database based on the serialization contained
+** in P. The serialized database P is N bytes in size. M is the size of
+** the buffer P, which might be larger than N. If M is larger than N, and
+** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is
+** permitted to add content to the in-memory database as long as the total
+** size does not exceed M bytes.
+**
+** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will
+** invoke sqlite3_free() on the serialization buffer when the database
+** connection closes. If the SQLITE_DESERIALIZE_RESIZEABLE bit is set, then
+** SQLite will try to increase the buffer size using sqlite3_realloc64()
+** if writes on the database cause it to grow larger than M bytes.
+**
+** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
+** database is currently in a read transaction or is involved in a backup
+** operation.
+**
+** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
+** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
+** [sqlite3_free()] is invoked on argument P prior to returning.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_DESERIALIZE] option.
+*/
+SQLITE_API int sqlite3_deserialize(
+ sqlite3 *db, /* The database connection */
+ const char *zSchema, /* Which DB to reopen with the deserialization */
+ unsigned char *pData, /* The serialized database content */
+ sqlite3_int64 szDb, /* Number bytes in the deserialization */
+ sqlite3_int64 szBuf, /* Total size of buffer pData[] */
+ unsigned mFlags /* Zero or more SQLITE_DESERIALIZE_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3_deserialize()
+**
+** The following are allowed values for 6th argument (the F argument) to
+** the [sqlite3_deserialize(D,S,P,N,M,F)] interface.
+**
+** The SQLITE_DESERIALIZE_FREEONCLOSE means that the database serialization
+** in the P argument is held in memory obtained from [sqlite3_malloc64()]
+** and that SQLite should take ownership of this memory and automatically
+** free it when it has finished using it. Without this flag, the caller
+** is responsible for freeing any dynamically allocated memory.
+**
+** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
+** grow the size of the database using calls to [sqlite3_realloc64()]. This
+** flag should only be used if SQLITE_DESERIALIZE_FREEONCLOSE is also used.
+** Without this flag, the deserialized database cannot increase in size beyond
+** the number of bytes specified by the M parameter.
+**
+** The SQLITE_DESERIALIZE_READONLY flag means that the deserialized database
+** should be treated as read-only.
+*/
+#define SQLITE_DESERIALIZE_FREEONCLOSE 1 /* Call sqlite3_free() on close */
+#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */
+#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */
+
+/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
@@ -8447,7 +9875,7 @@ struct sqlite3_rtree_geometry {
};
/*
-** Register a 2nd-generation geometry callback named zScore that can be
+** Register a 2nd-generation geometry callback named zScore that can be
** used as part of an R-Tree geometry query as follows:
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
@@ -8462,7 +9890,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
/*
-** A pointer to a structure of the following type is passed as the
+** A pointer to a structure of the following type is passed as the
** argument to scored geometry callback registered using
** sqlite3_rtree_query_callback().
**
@@ -8484,7 +9912,7 @@ struct sqlite3_rtree_query_info {
sqlite3_int64 iRowid; /* Rowid for current entry */
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
int eParentWithin; /* Visibility of parent node */
- int eWithin; /* OUT: Visiblity */
+ int eWithin; /* OUT: Visibility */
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
/* The following fields are only available in 3.8.11 and later */
sqlite3_value **apSqlParam; /* Original SQL values of parameters */
@@ -8520,16 +9948,23 @@ extern "C" {
/*
** CAPI3REF: Session Object Handle
+**
+** An instance of this object is a [session] that can be used to
+** record changes to a database.
*/
typedef struct sqlite3_session sqlite3_session;
/*
** CAPI3REF: Changeset Iterator Handle
+**
+** An instance of this object acts as a cursor for iterating
+** over the elements of a [changeset] or [patchset].
*/
typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
/*
** CAPI3REF: Create A New Session Object
+** CONSTRUCTOR: sqlite3_session
**
** Create a new session object attached to database handle db. If successful,
** a pointer to the new object is written to *ppSession and SQLITE_OK is
@@ -8550,7 +9985,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
** is not possible for an application to register a pre-update hook on a
** database handle that has one or more session objects attached. Nor is
** it possible to create a session object attached to a database handle for
-** which a pre-update hook is already defined. The results of attempting
+** which a pre-update hook is already defined. The results of attempting
** either of these things are undefined.
**
** The session object will be used to create changesets for tables in
@@ -8558,7 +9993,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
** attached database. It is not an error if database zDb is not attached
** to the database when the session object is created.
*/
-int sqlite3session_create(
+SQLITE_API int sqlite3session_create(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of db (e.g. "main") */
sqlite3_session **ppSession /* OUT: New session object */
@@ -8566,21 +10001,23 @@ int sqlite3session_create(
/*
** CAPI3REF: Delete A Session Object
+** DESTRUCTOR: sqlite3_session
**
-** Delete a session object previously allocated using
+** Delete a session object previously allocated using
** [sqlite3session_create()]. Once a session object has been deleted, the
** results of attempting to use pSession with any other session module
** function are undefined.
**
** Session objects must be deleted before the database handle to which they
-** are attached is closed. Refer to the documentation for
+** are attached is closed. Refer to the documentation for
** [sqlite3session_create()] for details.
*/
-void sqlite3session_delete(sqlite3_session *pSession);
+SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
** CAPI3REF: Enable Or Disable A Session Object
+** METHOD: sqlite3_session
**
** Enable or disable the recording of changes by a session object. When
** enabled, a session object records changes made to the database. When
@@ -8590,16 +10027,17 @@ void sqlite3session_delete(sqlite3_session *pSession);
** the eventual changesets.
**
** Passing zero to this function disables the session. Passing a value
-** greater than zero enables it. Passing a value less than zero is a
+** greater than zero enables it. Passing a value less than zero is a
** no-op, and may be used to query the current state of the session.
**
-** The return value indicates the final state of the session object: 0 if
+** The return value indicates the final state of the session object: 0 if
** the session is disabled, or 1 if it is enabled.
*/
-int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
+SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
/*
** CAPI3REF: Set Or Clear the Indirect Change Flag
+** METHOD: sqlite3_session
**
** Each change recorded by a session object is marked as either direct or
** indirect. A change is marked as indirect if either:
@@ -8607,7 +10045,7 @@ int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
** <ul>
** <li> The session object "indirect" flag is set when the change is
** made, or
-** <li> The change is made by an SQL trigger or foreign key action
+** <li> The change is made by an SQL trigger or foreign key action
** instead of directly as a result of a users SQL statement.
** </ul>
**
@@ -8619,32 +10057,33 @@ int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
** flag. If the second argument passed to this function is zero, then the
** indirect flag is cleared. If it is greater than zero, the indirect flag
** is set. Passing a value less than zero does not modify the current value
-** of the indirect flag, and may be used to query the current state of the
+** of the indirect flag, and may be used to query the current state of the
** indirect flag for the specified session object.
**
-** The return value indicates the final state of the indirect flag: 0 if
+** The return value indicates the final state of the indirect flag: 0 if
** it is clear, or 1 if it is set.
*/
-int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
+SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
/*
** CAPI3REF: Attach A Table To A Session Object
+** METHOD: sqlite3_session
**
** If argument zTab is not NULL, then it is the name of a table to attach
-** to the session object passed as the first argument. All subsequent changes
-** made to the table while the session object is enabled will be recorded. See
+** to the session object passed as the first argument. All subsequent changes
+** made to the table while the session object is enabled will be recorded. See
** documentation for [sqlite3session_changeset()] for further details.
**
** Or, if argument zTab is NULL, then changes are recorded for all tables
-** in the database. If additional tables are added to the database (by
-** executing "CREATE TABLE" statements) after this call is made, changes for
+** in the database. If additional tables are added to the database (by
+** executing "CREATE TABLE" statements) after this call is made, changes for
** the new tables are also recorded.
**
** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
-** defined as part of their CREATE TABLE statement. It does not matter if the
+** defined as part of their CREATE TABLE statement. It does not matter if the
** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
** KEY may consist of a single column, or may be a composite key.
-**
+**
** It is not an error if the named table does not exist in the database. Nor
** is it an error if the named table does not have a PRIMARY KEY. However,
** no changes will be recorded in either of these scenarios.
@@ -8652,24 +10091,54 @@ int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
** Changes are not recorded for individual rows that have NULL values stored
** in one or more of their PRIMARY KEY columns.
**
-** SQLITE_OK is returned if the call completes without error. Or, if an error
+** SQLITE_OK is returned if the call completes without error. Or, if an error
** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
-*/
-int sqlite3session_attach(
+**
+** <h3>Special sqlite_stat1 Handling</h3>
+**
+** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to
+** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
+** <pre>
+** &nbsp; CREATE TABLE sqlite_stat1(tbl,idx,stat)
+** </pre>
+**
+** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are
+** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes
+** are recorded for rows for which (idx IS NULL) is true. However, for such
+** rows a zero-length blob (SQL value X'') is stored in the changeset or
+** patchset instead of a NULL value. This allows such changesets to be
+** manipulated by legacy implementations of sqlite3changeset_invert(),
+** concat() and similar.
+**
+** The sqlite3changeset_apply() function automatically converts the
+** zero-length blob back to a NULL value when updating the sqlite_stat1
+** table. However, if the application calls sqlite3changeset_new(),
+** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset
+** iterator directly (including on a changeset iterator passed to a
+** conflict-handler callback) then the X'' value is returned. The application
+** must translate X'' to NULL itself if required.
+**
+** Legacy (older than 3.22.0) versions of the sessions module cannot capture
+** changes made to the sqlite_stat1 table. Legacy versions of the
+** sqlite3changeset_apply() function silently ignore any modifications to the
+** sqlite_stat1 table that are part of a changeset or patchset.
+*/
+SQLITE_API int sqlite3session_attach(
sqlite3_session *pSession, /* Session object */
const char *zTab /* Table name */
);
/*
** CAPI3REF: Set a table filter on a Session Object.
+** METHOD: sqlite3_session
**
-** The second argument (xFilter) is the "filter callback". For changes to rows
+** The second argument (xFilter) is the "filter callback". For changes to rows
** in tables that are not attached to the Session object, the filter is called
-** to determine whether changes to the table's rows should be tracked or not.
-** If xFilter returns 0, changes is not tracked. Note that once a table is
+** to determine whether changes to the table's rows should be tracked or not.
+** If xFilter returns 0, changes are not tracked. Note that once a table is
** attached, xFilter will not be called again.
*/
-void sqlite3session_table_filter(
+SQLITE_API void sqlite3session_table_filter(
sqlite3_session *pSession, /* Session object */
int(*xFilter)(
void *pCtx, /* Copy of third arg to _filter_table() */
@@ -8680,10 +10149,11 @@ void sqlite3session_table_filter(
/*
** CAPI3REF: Generate A Changeset From A Session Object
+** METHOD: sqlite3_session
**
-** Obtain a changeset containing changes to the tables attached to the
-** session object passed as the first argument. If successful,
-** set *ppChangeset to point to a buffer containing the changeset
+** Obtain a changeset containing changes to the tables attached to the
+** session object passed as the first argument. If successful,
+** set *ppChangeset to point to a buffer containing the changeset
** and *pnChangeset to the size of the changeset in bytes before returning
** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
** zero and return an SQLite error code.
@@ -8698,7 +10168,7 @@ void sqlite3session_table_filter(
** modifies the values of primary key columns. If such a change is made, it
** is represented in a changeset as a DELETE followed by an INSERT.
**
-** Changes are not recorded for rows that have NULL values stored in one or
+** Changes are not recorded for rows that have NULL values stored in one or
** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
** no corresponding change is present in the changesets returned by this
** function. If an existing row with one or more NULL values stored in
@@ -8751,14 +10221,14 @@ void sqlite3session_table_filter(
** <ul>
** <li> For each record generated by an insert, the database is queried
** for a row with a matching primary key. If one is found, an INSERT
-** change is added to the changeset. If no such row is found, no change
+** change is added to the changeset. If no such row is found, no change
** is added to the changeset.
**
-** <li> For each record generated by an update or delete, the database is
+** <li> For each record generated by an update or delete, the database is
** queried for a row with a matching primary key. If such a row is
** found and one or more of the non-primary key fields have been
-** modified from their original values, an UPDATE change is added to
-** the changeset. Or, if no such row is found in the table, a DELETE
+** modified from their original values, an UPDATE change is added to
+** the changeset. Or, if no such row is found in the table, a DELETE
** change is added to the changeset. If there is a row with a matching
** primary key in the database, but all fields contain their original
** values, no change is added to the changeset.
@@ -8766,7 +10236,7 @@ void sqlite3session_table_filter(
**
** This means, amongst other things, that if a row is inserted and then later
** deleted while a session object is active, neither the insert nor the delete
-** will be present in the changeset. Or if a row is deleted and then later a
+** will be present in the changeset. Or if a row is deleted and then later a
** row with the same primary key values inserted while a session object is
** active, the resulting changeset will contain an UPDATE change instead of
** a DELETE and an INSERT.
@@ -8775,21 +10245,22 @@ void sqlite3session_table_filter(
** it does not accumulate records when rows are inserted, updated or deleted.
** This may appear to have some counter-intuitive effects if a single row
** is written to more than once during a session. For example, if a row
-** is inserted while a session object is enabled, then later deleted while
+** is inserted while a session object is enabled, then later deleted while
** the same session object is disabled, no INSERT record will appear in the
** changeset, even though the delete took place while the session was disabled.
-** Or, if one field of a row is updated while a session is disabled, and
+** Or, if one field of a row is updated while a session is disabled, and
** another field of the same row is updated while the session is enabled, the
** resulting changeset will contain an UPDATE change that updates both fields.
*/
-int sqlite3session_changeset(
+SQLITE_API int sqlite3session_changeset(
sqlite3_session *pSession, /* Session object */
int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
void **ppChangeset /* OUT: Buffer containing changeset */
);
/*
-** CAPI3REF: Load The Difference Between Tables Into A Session
+** CAPI3REF: Load The Difference Between Tables Into A Session
+** METHOD: sqlite3_session
**
** If it is not already attached to the session object passed as the first
** argument, this function attaches table zTbl in the same manner as the
@@ -8798,7 +10269,7 @@ int sqlite3session_changeset(
** an error).
**
** Argument zFromDb must be the name of a database ("main", "temp" etc.)
-** attached to the same database handle as the session object that contains
+** attached to the same database handle as the session object that contains
** a table compatible with the table attached to the session by this function.
** A table is considered compatible if it:
**
@@ -8814,36 +10285,37 @@ int sqlite3session_changeset(
** APIs, tables without PRIMARY KEYs are simply ignored.
**
** This function adds a set of changes to the session object that could be
-** used to update the table in database zFrom (call this the "from-table")
-** so that its content is the same as the table attached to the session
+** used to update the table in database zFrom (call this the "from-table")
+** so that its content is the same as the table attached to the session
** object (call this the "to-table"). Specifically:
**
** <ul>
-** <li> For each row (primary key) that exists in the to-table but not in
+** <li> For each row (primary key) that exists in the to-table but not in
** the from-table, an INSERT record is added to the session object.
**
-** <li> For each row (primary key) that exists in the to-table but not in
+** <li> For each row (primary key) that exists in the to-table but not in
** the from-table, a DELETE record is added to the session object.
**
-** <li> For each row (primary key) that exists in both tables, but features
-** different in each, an UPDATE record is added to the session.
+** <li> For each row (primary key) that exists in both tables, but features
+** different non-PK values in each, an UPDATE record is added to the
+** session.
** </ul>
**
** To clarify, if this function is called and then a changeset constructed
-** using [sqlite3session_changeset()], then after applying that changeset to
-** database zFrom the contents of the two compatible tables would be
+** using [sqlite3session_changeset()], then after applying that changeset to
+** database zFrom the contents of the two compatible tables would be
** identical.
**
** It an error if database zFrom does not exist or does not contain the
** required compatible table.
**
-** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
+** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
-** may be set to point to a buffer containing an English language error
+** may be set to point to a buffer containing an English language error
** message. It is the responsibility of the caller to free this buffer using
** sqlite3_free().
*/
-int sqlite3session_diff(
+SQLITE_API int sqlite3session_diff(
sqlite3_session *pSession,
const char *zFromDb,
const char *zTbl,
@@ -8853,23 +10325,24 @@ int sqlite3session_diff(
/*
** CAPI3REF: Generate A Patchset From A Session Object
+** METHOD: sqlite3_session
**
** The differences between a patchset and a changeset are that:
**
** <ul>
-** <li> DELETE records consist of the primary key fields only. The
+** <li> DELETE records consist of the primary key fields only. The
** original values of other fields are omitted.
-** <li> The original values of any modified fields are omitted from
+** <li> The original values of any modified fields are omitted from
** UPDATE records.
** </ul>
**
-** A patchset blob may be used with up to date versions of all
-** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
+** A patchset blob may be used with up to date versions of all
+** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
** attempting to use a patchset blob with old versions of the
-** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
+** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
**
-** Because the non-primary key "old.*" fields are omitted, no
+** Because the non-primary key "old.*" fields are omitted, no
** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
** is passed to the sqlite3changeset_apply() API. Other conflict types work
** in the same way as for changesets.
@@ -8879,38 +10352,39 @@ int sqlite3session_diff(
** a single table are grouped together, tables appear in the order in which
** they were attached to the session object).
*/
-int sqlite3session_patchset(
+SQLITE_API int sqlite3session_patchset(
sqlite3_session *pSession, /* Session object */
- int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
- void **ppPatchset /* OUT: Buffer containing changeset */
+ int *pnPatchset, /* OUT: Size of buffer at *ppPatchset */
+ void **ppPatchset /* OUT: Buffer containing patchset */
);
/*
** CAPI3REF: Test if a changeset has recorded any changes.
**
-** Return non-zero if no changes to attached tables have been recorded by
-** the session object passed as the first argument. Otherwise, if one or
+** Return non-zero if no changes to attached tables have been recorded by
+** the session object passed as the first argument. Otherwise, if one or
** more changes have been recorded, return zero.
**
** Even if this function returns zero, it is possible that calling
** [sqlite3session_changeset()] on the session handle may still return a
-** changeset that contains no changes. This can happen when a row in
-** an attached table is modified and then later on the original values
+** changeset that contains no changes. This can happen when a row in
+** an attached table is modified and then later on the original values
** are restored. However, if this function returns non-zero, then it is
-** guaranteed that a call to sqlite3session_changeset() will return a
+** guaranteed that a call to sqlite3session_changeset() will return a
** changeset containing zero changes.
*/
-int sqlite3session_isempty(sqlite3_session *pSession);
+SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
/*
-** CAPI3REF: Create An Iterator To Traverse A Changeset
+** CAPI3REF: Create An Iterator To Traverse A Changeset
+** CONSTRUCTOR: sqlite3_changeset_iter
**
** Create an iterator used to iterate through the contents of a changeset.
** If successful, *pp is set to point to the iterator handle and SQLITE_OK
** is returned. Otherwise, if an error occurs, *pp is set to zero and an
** SQLite error code is returned.
**
-** The following functions can be used to advance and query a changeset
+** The following functions can be used to advance and query a changeset
** iterator created by this function:
**
** <ul>
@@ -8927,25 +10401,52 @@ int sqlite3session_isempty(sqlite3_session *pSession);
**
** Assuming the changeset blob was created by one of the
** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
-** [sqlite3changeset_invert()] functions, all changes within the changeset
-** that apply to a single table are grouped together. This means that when
-** an application iterates through a changeset using an iterator created by
-** this function, all changes that relate to a single table are visited
-** consecutively. There is no chance that the iterator will visit a change
-** the applies to table X, then one for table Y, and then later on visit
+** [sqlite3changeset_invert()] functions, all changes within the changeset
+** that apply to a single table are grouped together. This means that when
+** an application iterates through a changeset using an iterator created by
+** this function, all changes that relate to a single table are visited
+** consecutively. There is no chance that the iterator will visit a change
+** the applies to table X, then one for table Y, and then later on visit
** another change for table X.
+**
+** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
+** may be modified by passing a combination of
+** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter.
+**
+** Note that the sqlite3changeset_start_v2() API is still <b>experimental</b>
+** and therefore subject to change.
*/
-int sqlite3changeset_start(
+SQLITE_API int sqlite3changeset_start(
sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
int nChangeset, /* Size of changeset blob in bytes */
void *pChangeset /* Pointer to blob containing changeset */
);
+SQLITE_API int sqlite3changeset_start_v2(
+ sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
+ int nChangeset, /* Size of changeset blob in bytes */
+ void *pChangeset, /* Pointer to blob containing changeset */
+ int flags /* SESSION_CHANGESETSTART_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3changeset_start_v2
+**
+** The following flags may passed via the 4th parameter to
+** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
+**
+** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
+** Invert the changeset while iterating through it. This is equivalent to
+** inverting a changeset using sqlite3changeset_invert() before applying it.
+** It is an error to specify this flag with a patchset.
+*/
+#define SQLITE_CHANGESETSTART_INVERT 0x0002
/*
** CAPI3REF: Advance A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
-** This function may only be used with iterators created by function
+** This function may only be used with iterators created by the function
** [sqlite3changeset_start()]. If it is called on an iterator passed to
** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
** is returned and the call has no effect.
@@ -8956,18 +10457,19 @@ int sqlite3changeset_start(
** point to the first change in the changeset. Each subsequent call advances
** the iterator to point to the next change in the changeset (if any). If
** no error occurs and the iterator points to a valid change after a call
-** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
+** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
** Otherwise, if all changes in the changeset have already been visited,
** SQLITE_DONE is returned.
**
-** If an error occurs, an SQLite error code is returned. Possible error
-** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
+** If an error occurs, an SQLite error code is returned. Possible error
+** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
** SQLITE_NOMEM.
*/
-int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
+SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
/*
** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** The pIter argument passed to this function may either be an iterator
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
@@ -8978,21 +10480,21 @@ int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
** If argument pzTab is not NULL, then *pzTab is set to point to a
** nul-terminated utf-8 encoded string containing the name of the table
** affected by the current change. The buffer remains valid until either
-** sqlite3changeset_next() is called on the iterator or until the
-** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
+** sqlite3changeset_next() is called on the iterator or until the
+** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
** set to the number of columns in the table affected by the change. If
-** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
+** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
** is an indirect change, or false (0) otherwise. See the documentation for
** [sqlite3session_indirect()] for a description of direct and indirect
-** changes. Finally, if pOp is not NULL, then *pOp is set to one of
-** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
+** changes. Finally, if pOp is not NULL, then *pOp is set to one of
+** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
** type of change that the iterator currently points to.
**
** If no error occurs, SQLITE_OK is returned. If an error does occur, an
** SQLite error code is returned. The values of the output variables may not
** be trusted in this case.
*/
-int sqlite3changeset_op(
+SQLITE_API int sqlite3changeset_op(
sqlite3_changeset_iter *pIter, /* Iterator object */
const char **pzTab, /* OUT: Pointer to table name */
int *pnCol, /* OUT: Number of columns in table */
@@ -9002,6 +10504,7 @@ int sqlite3changeset_op(
/*
** CAPI3REF: Obtain The Primary Key Definition Of A Table
+** METHOD: sqlite3_changeset_iter
**
** For each modified table, a changeset includes the following:
**
@@ -9025,7 +10528,7 @@ int sqlite3changeset_op(
** SQLITE_OK is returned and the output variables populated as described
** above.
*/
-int sqlite3changeset_pk(
+SQLITE_API int sqlite3changeset_pk(
sqlite3_changeset_iter *pIter, /* Iterator object */
unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
int *pnCol /* OUT: Number of entries in output array */
@@ -9033,11 +10536,12 @@ int sqlite3changeset_pk(
/*
** CAPI3REF: Obtain old.* Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** The pIter argument passed to this function may either be an iterator
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
** Furthermore, it may only be called if the type of change that the iterator
** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
@@ -9047,15 +10551,15 @@ int sqlite3changeset_pk(
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
**
** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
+** sqlite3_value object containing the iVal'th value from the vector of
** original row values stored as part of the UPDATE or DELETE change and
-** returns SQLITE_OK. The name of the function comes from the fact that this
+** returns SQLITE_OK. The name of the function comes from the fact that this
** is similar to the "old.*" columns available to update or delete triggers.
**
** If some other error occurs (e.g. an OOM condition), an SQLite error code
** is returned and *ppValue is set to NULL.
*/
-int sqlite3changeset_old(
+SQLITE_API int sqlite3changeset_old(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int iVal, /* Column number */
sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
@@ -9063,11 +10567,12 @@ int sqlite3changeset_old(
/*
** CAPI3REF: Obtain new.* Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** The pIter argument passed to this function may either be an iterator
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
** created by [sqlite3changeset_start()]. In the latter case, the most recent
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
** Furthermore, it may only be called if the type of change that the iterator
** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
@@ -9077,18 +10582,18 @@ int sqlite3changeset_old(
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
**
** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the vector of
+** sqlite3_value object containing the iVal'th value from the vector of
** new row values stored as part of the UPDATE or INSERT change and
** returns SQLITE_OK. If the change is an UPDATE and does not include
-** a new value for the requested column, *ppValue is set to NULL and
-** SQLITE_OK returned. The name of the function comes from the fact that
-** this is similar to the "new.*" columns available to update or delete
+** a new value for the requested column, *ppValue is set to NULL and
+** SQLITE_OK returned. The name of the function comes from the fact that
+** this is similar to the "new.*" columns available to update or delete
** triggers.
**
** If some other error occurs (e.g. an OOM condition), an SQLite error code
** is returned and *ppValue is set to NULL.
*/
-int sqlite3changeset_new(
+SQLITE_API int sqlite3changeset_new(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int iVal, /* Column number */
sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
@@ -9096,6 +10601,7 @@ int sqlite3changeset_new(
/*
** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** This function should only be used with iterator objects passed to a
** conflict-handler callback by [sqlite3changeset_apply()] with either
@@ -9108,14 +10614,14 @@ int sqlite3changeset_new(
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
**
** If successful, this function sets *ppValue to point to a protected
-** sqlite3_value object containing the iVal'th value from the
+** sqlite3_value object containing the iVal'th value from the
** "conflicting row" associated with the current conflict-handler callback
** and returns SQLITE_OK.
**
** If some other error occurs (e.g. an OOM condition), an SQLite error code
** is returned and *ppValue is set to NULL.
*/
-int sqlite3changeset_conflict(
+SQLITE_API int sqlite3changeset_conflict(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int iVal, /* Column number */
sqlite3_value **ppValue /* OUT: Value from conflicting row */
@@ -9123,6 +10629,7 @@ int sqlite3changeset_conflict(
/*
** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
+** METHOD: sqlite3_changeset_iter
**
** This function may only be called with an iterator passed to an
** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
@@ -9131,7 +10638,7 @@ int sqlite3changeset_conflict(
**
** In all other cases this function returns SQLITE_MISUSE.
*/
-int sqlite3changeset_fk_conflicts(
+SQLITE_API int sqlite3changeset_fk_conflicts(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
int *pnOut /* OUT: Number of FK violations */
);
@@ -9139,6 +10646,7 @@ int sqlite3changeset_fk_conflicts(
/*
** CAPI3REF: Finalize A Changeset Iterator
+** METHOD: sqlite3_changeset_iter
**
** This function is used to finalize an iterator allocated with
** [sqlite3changeset_start()].
@@ -9150,21 +10658,23 @@ int sqlite3changeset_fk_conflicts(
** call has no effect.
**
** If an error was encountered within a call to an sqlite3changeset_xxx()
-** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
+** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
** to that error is returned by this function. Otherwise, SQLITE_OK is
** returned. This is to allow the following pattern (pseudo-code):
**
+** <pre>
** sqlite3changeset_start();
** while( SQLITE_ROW==sqlite3changeset_next() ){
** // Do something with change.
** }
** rc = sqlite3changeset_finalize();
** if( rc!=SQLITE_OK ){
-** // An error has occurred
+** // An error has occurred
** }
+** </pre>
*/
-int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
+SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
/*
** CAPI3REF: Invert A Changeset
@@ -9188,13 +10698,13 @@ int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
** zeroed and an SQLite error code returned.
**
** It is the responsibility of the caller to eventually call sqlite3_free()
-** on the *ppOut pointer to free the buffer allocation following a successful
+** on the *ppOut pointer to free the buffer allocation following a successful
** call to this function.
**
** WARNING/TODO: This function currently assumes that the input is a valid
** changeset. If it is not, the results are undefined.
*/
-int sqlite3changeset_invert(
+SQLITE_API int sqlite3changeset_invert(
int nIn, const void *pIn, /* Input changeset */
int *pnOut, void **ppOut /* OUT: Inverse of input */
);
@@ -9202,14 +10712,15 @@ int sqlite3changeset_invert(
/*
** CAPI3REF: Concatenate Two Changeset Objects
**
-** This function is used to concatenate two changesets, A and B, into a
+** This function is used to concatenate two changesets, A and B, into a
** single changeset. The result is a changeset equivalent to applying
-** changeset A followed by changeset B.
+** changeset A followed by changeset B.
**
-** This function combines the two input changesets using an
+** This function combines the two input changesets using an
** sqlite3_changegroup object. Calling it produces similar results as the
** following code fragment:
**
+** <pre>
** sqlite3_changegroup *pGrp;
** rc = sqlite3_changegroup_new(&pGrp);
** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
@@ -9220,10 +10731,11 @@ int sqlite3changeset_invert(
** *ppOut = 0;
** *pnOut = 0;
** }
+** </pre>
**
** Refer to the sqlite3_changegroup documentation below for details.
*/
-int sqlite3changeset_concat(
+SQLITE_API int sqlite3changeset_concat(
int nA, /* Number of bytes in buffer pA */
void *pA, /* Pointer to buffer containing changeset A */
int nB, /* Number of bytes in buffer pB */
@@ -9235,11 +10747,15 @@ int sqlite3changeset_concat(
/*
** CAPI3REF: Changegroup Handle
+**
+** A changegroup is an object used to combine two or more
+** [changesets] or [patchsets]
*/
typedef struct sqlite3_changegroup sqlite3_changegroup;
/*
** CAPI3REF: Create A New Changegroup Object
+** CONSTRUCTOR: sqlite3_changegroup
**
** An sqlite3_changegroup object is used to combine two or more changesets
** (or patchsets) into a single changeset (or patchset). A single changegroup
@@ -9248,7 +10764,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
**
** If successful, this function returns SQLITE_OK and populates (*pp) with
** a pointer to a new sqlite3_changegroup object before returning. The caller
-** should eventually free the returned object using a call to
+** should eventually free the returned object using a call to
** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
**
@@ -9260,7 +10776,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
** <li> Zero or more changesets (or patchsets) are added to the object
** by calling sqlite3changegroup_add().
**
-** <li> The result of combining all input changesets together is obtained
+** <li> The result of combining all input changesets together is obtained
** by the application via a call to sqlite3changegroup_output().
**
** <li> The object is deleted using a call to sqlite3changegroup_delete().
@@ -9269,17 +10785,18 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
** Any number of calls to add() and output() may be made between the calls to
** new() and delete(), and in any order.
**
-** As well as the regular sqlite3changegroup_add() and
+** As well as the regular sqlite3changegroup_add() and
** sqlite3changegroup_output() functions, also available are the streaming
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
*/
-int sqlite3changegroup_new(sqlite3_changegroup **pp);
+SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
** CAPI3REF: Add A Changeset To A Changegroup
+** METHOD: sqlite3_changegroup
**
** Add all changes within the changeset (or patchset) in buffer pData (size
-** nData bytes) to the changegroup.
+** nData bytes) to the changegroup.
**
** If the buffer contains a patchset, then all prior calls to this function
** on the same changegroup object must also have specified patchsets. Or, if
@@ -9306,7 +10823,7 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** changeset was recorded immediately after the changesets already
** added to the changegroup.
** <tr><td>INSERT <td>UPDATE <td>
-** The INSERT change remains in the changegroup. The values in the
+** The INSERT change remains in the changegroup. The values in the
** INSERT change are modified as if the row was inserted by the
** existing change and then updated according to the new change.
** <tr><td>INSERT <td>DELETE <td>
@@ -9317,17 +10834,17 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** changeset was recorded immediately after the changesets already
** added to the changegroup.
** <tr><td>UPDATE <td>UPDATE <td>
-** The existing UPDATE remains within the changegroup. It is amended
-** so that the accompanying values are as if the row was updated once
+** The existing UPDATE remains within the changegroup. It is amended
+** so that the accompanying values are as if the row was updated once
** by the existing change and then again by the new change.
** <tr><td>UPDATE <td>DELETE <td>
** The existing UPDATE is replaced by the new DELETE within the
** changegroup.
** <tr><td>DELETE <td>INSERT <td>
** If one or more of the column values in the row inserted by the
-** new change differ from those in the row deleted by the existing
+** new change differ from those in the row deleted by the existing
** change, the existing DELETE is replaced by an UPDATE within the
-** changegroup. Otherwise, if the inserted row is exactly the same
+** changegroup. Otherwise, if the inserted row is exactly the same
** as the deleted row, the existing DELETE is simply discarded.
** <tr><td>DELETE <td>UPDATE <td>
** The new change is ignored. This case does not occur if the new
@@ -9345,15 +10862,16 @@ int sqlite3changegroup_new(sqlite3_changegroup **pp);
** case, this function fails with SQLITE_SCHEMA. If the input changeset
** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
** returned. Or, if an out-of-memory condition occurs during processing, this
-** function returns SQLITE_NOMEM. In all cases, if an error occurs the
-** final contents of the changegroup is undefined.
+** function returns SQLITE_NOMEM. In all cases, if an error occurs the state
+** of the final contents of the changegroup is undefined.
**
** If no error occurs, SQLITE_OK is returned.
*/
-int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
+SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
/*
** CAPI3REF: Obtain A Composite Changeset From A Changegroup
+** METHOD: sqlite3_changegroup
**
** Obtain a buffer containing a changeset (or patchset) representing the
** current contents of the changegroup. If the inputs to the changegroup
@@ -9371,12 +10889,12 @@ int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
**
** If an error occurs, an SQLite error code is returned and the output
** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
-** is returned and the output variables are set to the size of and a
+** is returned and the output variables are set to the size of and a
** pointer to the output buffer, respectively. In this case it is the
** responsibility of the caller to eventually free the buffer using a
** call to sqlite3_free().
*/
-int sqlite3changegroup_output(
+SQLITE_API int sqlite3changegroup_output(
sqlite3_changegroup*,
int *pnData, /* OUT: Size of output buffer in bytes */
void **ppData /* OUT: Pointer to output buffer */
@@ -9384,36 +10902,36 @@ int sqlite3changegroup_output(
/*
** CAPI3REF: Delete A Changegroup Object
+** DESTRUCTOR: sqlite3_changegroup
*/
-void sqlite3changegroup_delete(sqlite3_changegroup*);
+SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
/*
** CAPI3REF: Apply A Changeset To A Database
**
-** Apply a changeset to a database. This function attempts to update the
-** "main" database attached to handle db with the changes found in the
-** changeset passed via the second and third arguments.
+** Apply a changeset or patchset to a database. These functions attempt to
+** update the "main" database attached to handle db with the changes found in
+** the changeset passed via the second and third arguments.
**
-** The fourth argument (xFilter) passed to this function is the "filter
+** The fourth argument (xFilter) passed to these functions is the "filter
** callback". If it is not NULL, then for each table affected by at least one
** change in the changeset, the filter callback is invoked with
** the table name as the second argument, and a copy of the context pointer
-** passed as the sixth argument to this function as the first. If the "filter
-** callback" returns zero, then no attempt is made to apply any changes to
-** the table. Otherwise, if the return value is non-zero or the xFilter
-** argument to this function is NULL, all changes related to the table are
-** attempted.
-**
-** For each table that is not excluded by the filter callback, this function
-** tests that the target database contains a compatible table. A table is
+** passed as the sixth argument as the first. If the "filter callback"
+** returns zero, then no attempt is made to apply any changes to the table.
+** Otherwise, if the return value is non-zero or the xFilter argument to
+** is NULL, all changes related to the table are attempted.
+**
+** For each table that is not excluded by the filter callback, this function
+** tests that the target database contains a compatible table. A table is
** considered compatible if all of the following are true:
**
** <ul>
-** <li> The table has the same name as the name recorded in the
+** <li> The table has the same name as the name recorded in the
** changeset, and
-** <li> The table has the same number of columns as recorded in the
+** <li> The table has at least as many columns as recorded in the
** changeset, and
-** <li> The table has primary key columns in the same position as
+** <li> The table has primary key columns in the same position as
** recorded in the changeset.
** </ul>
**
@@ -9422,11 +10940,11 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
** one such warning is issued for each table in the changeset.
**
-** For each change for which there is a compatible table, an attempt is made
-** to modify the table contents according to the UPDATE, INSERT or DELETE
-** change. If a change cannot be applied cleanly, the conflict handler
-** function passed as the fifth argument to sqlite3changeset_apply() may be
-** invoked. A description of exactly when the conflict handler is invoked for
+** For each change for which there is a compatible table, an attempt is made
+** to modify the table contents according to the UPDATE, INSERT or DELETE
+** change. If a change cannot be applied cleanly, the conflict handler
+** function passed as the fifth argument to sqlite3changeset_apply() may be
+** invoked. A description of exactly when the conflict handler is invoked for
** each type of change is below.
**
** Unlike the xFilter argument, xConflict may not be passed NULL. The results
@@ -9434,29 +10952,33 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** argument are undefined.
**
** Each time the conflict handler function is invoked, it must return one
-** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
+** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
** if the second argument passed to the conflict handler is either
** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
** returns an illegal value, any changes already made are rolled back and
-** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
+** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
** actions are taken by sqlite3changeset_apply() depending on the value
** returned by each invocation of the conflict-handler function. Refer to
-** the documentation for the three
+** the documentation for the three
** [SQLITE_CHANGESET_OMIT|available return values] for details.
**
** <dl>
** <dt>DELETE Changes<dd>
-** For each DELETE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
+** For each DELETE change, the function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all non-primary key columns also match the values stored in
** the changeset the row is deleted from the target database.
**
** If a row with matching primary key values is found, but one or more of
** the non-primary key fields contains a value different from the original
** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument.
+** invoked with [SQLITE_CHANGESET_DATA] as the second argument. If the
+** database table has more columns than are recorded in the changeset,
+** only the values of those non-primary key fields are compared against
+** the current database contents - any trailing database table columns
+** are ignored.
**
** If no row with matching primary key values is found in the database,
** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
@@ -9471,31 +10993,33 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
**
** <dt>INSERT Changes<dd>
** For each INSERT change, an attempt is made to insert the new row into
-** the database.
+** the database. If the changeset row contains fewer fields than the
+** database table, the trailing fields are populated with their default
+** values.
**
-** If the attempt to insert the row fails because the database already
+** If the attempt to insert the row fails because the database already
** contains a row with the same primary key values, the conflict handler
-** function is invoked with the second argument set to
+** function is invoked with the second argument set to
** [SQLITE_CHANGESET_CONFLICT].
**
** If the attempt to insert the row fails because of some other constraint
-** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
+** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
-** This includes the case where the INSERT operation is re-attempted because
-** an earlier call to the conflict handler function returned
+** This includes the case where the INSERT operation is re-attempted because
+** an earlier call to the conflict handler function returned
** [SQLITE_CHANGESET_REPLACE].
**
** <dt>UPDATE Changes<dd>
-** For each UPDATE change, this function checks if the target database
-** contains a row with the same primary key value (or values) as the
-** original row values stored in the changeset. If it does, and the values
-** stored in all non-primary key columns also match the values stored in
-** the changeset the row is updated within the target database.
+** For each UPDATE change, the function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all modified non-primary key columns also match the values
+** stored in the changeset the row is updated within the target database.
**
** If a row with matching primary key values is found, but one or more of
-** the non-primary key fields contains a value different from an original
-** row value stored in the changeset, the conflict-handler function is
-** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
+** the modified non-primary key fields contains a value different from an
+** original row value stored in the changeset, the conflict-handler function
+** is invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
** UPDATE changes only contain values for non-primary key fields that are
** to be modified, only those fields need to match the original values to
** avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
@@ -9504,26 +11028,43 @@ void sqlite3changegroup_delete(sqlite3_changegroup*);
** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
** passed as the second argument.
**
-** If the UPDATE operation is attempted, but SQLite returns
-** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
+** If the UPDATE operation is attempted, but SQLite returns
+** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
-** This includes the case where the UPDATE operation is attempted after
+** This includes the case where the UPDATE operation is attempted after
** an earlier call to the conflict handler function returned
-** [SQLITE_CHANGESET_REPLACE].
+** [SQLITE_CHANGESET_REPLACE].
** </dl>
**
** It is safe to execute SQL statements, including those that write to the
** table that the callback related to, from within the xConflict callback.
-** This can be used to further customize the applications conflict
+** This can be used to further customize the application's conflict
** resolution strategy.
**
-** All changes made by this function are enclosed in a savepoint transaction.
+** All changes made by these functions are enclosed in a savepoint transaction.
** If any other error (aside from a constraint failure when attempting to
** write to the target database) occurs, then the savepoint transaction is
-** rolled back, restoring the target database to its original state, and an
+** rolled back, restoring the target database to its original state, and an
** SQLite error code returned.
+**
+** If the output parameters (ppRebase) and (pnRebase) are non-NULL and
+** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2()
+** may set (*ppRebase) to point to a "rebase" that may be used with the
+** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase)
+** is set to the size of the buffer in bytes. It is the responsibility of the
+** caller to eventually free any such buffer using sqlite3_free(). The buffer
+** is only allocated and populated if one or more conflicts were encountered
+** while applying the patchset. See comments surrounding the sqlite3_rebaser
+** APIs for further details.
+**
+** The behavior of sqlite3changeset_apply_v2() and its streaming equivalent
+** may be modified by passing a combination of
+** [SQLITE_CHANGESETAPPLY_NOSAVEPOINT | supported flags] as the 9th parameter.
+**
+** Note that the sqlite3changeset_apply_v2() API is still <b>experimental</b>
+** and therefore subject to change.
*/
-int sqlite3changeset_apply(
+SQLITE_API int sqlite3changeset_apply(
sqlite3 *db, /* Apply change to "main" db of this handle */
int nChangeset, /* Size of changeset in bytes */
void *pChangeset, /* Changeset blob */
@@ -9538,8 +11079,49 @@ int sqlite3changeset_apply(
),
void *pCtx /* First argument passed to xConflict */
);
+SQLITE_API int sqlite3changeset_apply_v2(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int nChangeset, /* Size of changeset in bytes */
+ void *pChangeset, /* Changeset blob */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase, /* OUT: Rebase data */
+ int flags /* SESSION_CHANGESETAPPLY_* flags */
+);
+
+/*
+** CAPI3REF: Flags for sqlite3changeset_apply_v2
+**
+** The following flags may passed via the 9th parameter to
+** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]:
+**
+** <dl>
+** <dt>SQLITE_CHANGESETAPPLY_NOSAVEPOINT <dd>
+** Usually, the sessions module encloses all operations performed by
+** a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The
+** SAVEPOINT is committed if the changeset or patchset is successfully
+** applied, or rolled back if an error occurs. Specifying this flag
+** causes the sessions module to omit this savepoint. In this case, if the
+** caller has an open transaction or savepoint when apply_v2() is called,
+** it may revert the partially applied changeset by rolling it back.
+**
+** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
+** Invert the changeset before applying it. This is equivalent to inverting
+** a changeset using sqlite3changeset_invert() before applying it. It is
+** an error to specify this flag with a patchset.
+*/
+#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
+#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
-/*
+/*
** CAPI3REF: Constants Passed To The Conflict Handler
**
** Values that may be passed as the second argument to a conflict-handler.
@@ -9548,32 +11130,32 @@ int sqlite3changeset_apply(
** <dt>SQLITE_CHANGESET_DATA<dd>
** The conflict handler is invoked with CHANGESET_DATA as the second argument
** when processing a DELETE or UPDATE change if a row with the required
-** PRIMARY KEY fields is present in the database, but one or more other
-** (non primary-key) fields modified by the update do not contain the
+** PRIMARY KEY fields is present in the database, but one or more other
+** (non primary-key) fields modified by the update do not contain the
** expected "before" values.
-**
+**
** The conflicting row, in this case, is the database row with the matching
** primary key.
-**
+**
** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
** argument when processing a DELETE or UPDATE change if a row with the
** required PRIMARY KEY fields is not present in the database.
-**
+**
** There is no conflicting row in this case. The results of invoking the
** sqlite3changeset_conflict() API are undefined.
-**
+**
** <dt>SQLITE_CHANGESET_CONFLICT<dd>
** CHANGESET_CONFLICT is passed as the second argument to the conflict
-** handler while processing an INSERT change if the operation would result
+** handler while processing an INSERT change if the operation would result
** in duplicate primary key values.
-**
+**
** The conflicting row in this case is the database row with the matching
** primary key.
**
** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
** If foreign key handling is enabled, and applying a changeset leaves the
-** database in a state containing foreign key violations, the conflict
+** database in a state containing foreign key violations, the conflict
** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
** exactly once before the changeset is committed. If the conflict handler
** returns CHANGESET_OMIT, the changes, including those that caused the
@@ -9583,12 +11165,12 @@ int sqlite3changeset_apply(
** No current or conflicting row information is provided. The only function
** it is possible to call on the supplied sqlite3_changeset_iter handle
** is sqlite3changeset_fk_conflicts().
-**
+**
** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
-** If any other constraint violation occurs while applying a change (i.e.
-** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
+** If any other constraint violation occurs while applying a change (i.e.
+** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
** invoked with CHANGESET_CONSTRAINT as the second argument.
-**
+**
** There is no conflicting row in this case. The results of invoking the
** sqlite3changeset_conflict() API are undefined.
**
@@ -9600,7 +11182,7 @@ int sqlite3changeset_apply(
#define SQLITE_CHANGESET_CONSTRAINT 4
#define SQLITE_CHANGESET_FOREIGN_KEY 5
-/*
+/*
** CAPI3REF: Constants Returned By The Conflict Handler
**
** A conflict handler callback must return one of the following three values.
@@ -9608,13 +11190,13 @@ int sqlite3changeset_apply(
** <dl>
** <dt>SQLITE_CHANGESET_OMIT<dd>
** If a conflict handler returns this value no special action is taken. The
-** change that caused the conflict is not applied. The session module
+** change that caused the conflict is not applied. The session module
** continues to the next change in the changeset.
**
** <dt>SQLITE_CHANGESET_REPLACE<dd>
** This value may only be returned if the second argument to the conflict
** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
-** is not the case, any changes applied so far are rolled back and the
+** is not the case, any changes applied so far are rolled back and the
** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
**
** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
@@ -9627,7 +11209,7 @@ int sqlite3changeset_apply(
** the original row is restored to the database before continuing.
**
** <dt>SQLITE_CHANGESET_ABORT<dd>
-** If this value is returned, any changes applied so far are rolled back
+** If this value is returned, any changes applied so far are rolled back
** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
** </dl>
*/
@@ -9636,26 +11218,182 @@ int sqlite3changeset_apply(
#define SQLITE_CHANGESET_ABORT 2
/*
+** CAPI3REF: Rebasing changesets
+** EXPERIMENTAL
+**
+** Suppose there is a site hosting a database in state S0. And that
+** modifications are made that move that database to state S1 and a
+** changeset recorded (the "local" changeset). Then, a changeset based
+** on S0 is received from another site (the "remote" changeset) and
+** applied to the database. The database is then in state
+** (S1+"remote"), where the exact state depends on any conflict
+** resolution decisions (OMIT or REPLACE) made while applying "remote".
+** Rebasing a changeset is to update it to take those conflict
+** resolution decisions into account, so that the same conflicts
+** do not have to be resolved elsewhere in the network.
+**
+** For example, if both the local and remote changesets contain an
+** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)":
+**
+** local: INSERT INTO t1 VALUES(1, 'v1');
+** remote: INSERT INTO t1 VALUES(1, 'v2');
+**
+** and the conflict resolution is REPLACE, then the INSERT change is
+** removed from the local changeset (it was overridden). Or, if the
+** conflict resolution was "OMIT", then the local changeset is modified
+** to instead contain:
+**
+** UPDATE t1 SET b = 'v2' WHERE a=1;
+**
+** Changes within the local changeset are rebased as follows:
+**
+** <dl>
+** <dt>Local INSERT<dd>
+** This may only conflict with a remote INSERT. If the conflict
+** resolution was OMIT, then add an UPDATE change to the rebased
+** changeset. Or, if the conflict resolution was REPLACE, add
+** nothing to the rebased changeset.
+**
+** <dt>Local DELETE<dd>
+** This may conflict with a remote UPDATE or DELETE. In both cases the
+** only possible resolution is OMIT. If the remote operation was a
+** DELETE, then add no change to the rebased changeset. If the remote
+** operation was an UPDATE, then the old.* fields of change are updated
+** to reflect the new.* values in the UPDATE.
+**
+** <dt>Local UPDATE<dd>
+** This may conflict with a remote UPDATE or DELETE. If it conflicts
+** with a DELETE, and the conflict resolution was OMIT, then the update
+** is changed into an INSERT. Any undefined values in the new.* record
+** from the update change are filled in using the old.* values from
+** the conflicting DELETE. Or, if the conflict resolution was REPLACE,
+** the UPDATE change is simply omitted from the rebased changeset.
+**
+** If conflict is with a remote UPDATE and the resolution is OMIT, then
+** the old.* values are rebased using the new.* values in the remote
+** change. Or, if the resolution is REPLACE, then the change is copied
+** into the rebased changeset with updates to columns also updated by
+** the conflicting remote UPDATE removed. If this means no columns would
+** be updated, the change is omitted.
+** </dl>
+**
+** A local change may be rebased against multiple remote changes
+** simultaneously. If a single key is modified by multiple remote
+** changesets, they are combined as follows before the local changeset
+** is rebased:
+**
+** <ul>
+** <li> If there has been one or more REPLACE resolutions on a
+** key, it is rebased according to a REPLACE.
+**
+** <li> If there have been no REPLACE resolutions on a key, then
+** the local changeset is rebased according to the most recent
+** of the OMIT resolutions.
+** </ul>
+**
+** Note that conflict resolutions from multiple remote changesets are
+** combined on a per-field basis, not per-row. This means that in the
+** case of multiple remote UPDATE operations, some fields of a single
+** local change may be rebased for REPLACE while others are rebased for
+** OMIT.
+**
+** In order to rebase a local changeset, the remote changeset must first
+** be applied to the local database using sqlite3changeset_apply_v2() and
+** the buffer of rebase information captured. Then:
+**
+** <ol>
+** <li> An sqlite3_rebaser object is created by calling
+** sqlite3rebaser_create().
+** <li> The new object is configured with the rebase buffer obtained from
+** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure().
+** If the local changeset is to be rebased against multiple remote
+** changesets, then sqlite3rebaser_configure() should be called
+** multiple times, in the same order that the multiple
+** sqlite3changeset_apply_v2() calls were made.
+** <li> Each local changeset is rebased by calling sqlite3rebaser_rebase().
+** <li> The sqlite3_rebaser object is deleted by calling
+** sqlite3rebaser_delete().
+** </ol>
+*/
+typedef struct sqlite3_rebaser sqlite3_rebaser;
+
+/*
+** CAPI3REF: Create a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Allocate a new changeset rebaser object. If successful, set (*ppNew) to
+** point to the new object and return SQLITE_OK. Otherwise, if an error
+** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew)
+** to NULL.
+*/
+SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
+
+/*
+** CAPI3REF: Configure a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Configure the changeset rebaser object to rebase changesets according
+** to the conflict resolutions described by buffer pRebase (size nRebase
+** bytes), which must have been obtained from a previous call to
+** sqlite3changeset_apply_v2().
+*/
+SQLITE_API int sqlite3rebaser_configure(
+ sqlite3_rebaser*,
+ int nRebase, const void *pRebase
+);
+
+/*
+** CAPI3REF: Rebase a changeset
+** EXPERIMENTAL
+**
+** Argument pIn must point to a buffer containing a changeset nIn bytes
+** in size. This function allocates and populates a buffer with a copy
+** of the changeset rebased according to the configuration of the
+** rebaser object passed as the first argument. If successful, (*ppOut)
+** is set to point to the new buffer containing the rebased changeset and
+** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
+** responsibility of the caller to eventually free the new buffer using
+** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
+** are set to zero and an SQLite error code returned.
+*/
+SQLITE_API int sqlite3rebaser_rebase(
+ sqlite3_rebaser*,
+ int nIn, const void *pIn,
+ int *pnOut, void **ppOut
+);
+
+/*
+** CAPI3REF: Delete a changeset rebaser object.
+** EXPERIMENTAL
+**
+** Delete the changeset rebaser object and all associated resources. There
+** should be one call to this function for each successful invocation
+** of sqlite3rebaser_create().
+*/
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
+
+/*
** CAPI3REF: Streaming Versions of API functions.
**
-** The six streaming API xxx_strm() functions serve similar purposes to the
+** The six streaming API xxx_strm() functions serve similar purposes to the
** corresponding non-streaming API functions:
**
** <table border=1 style="margin-left:8ex;margin-right:8ex">
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
-** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
-** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
-** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
-** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
-** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
-** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
+** <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2]
+** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat]
+** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert]
+** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start]
+** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset]
+** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset]
** </table>
**
** Non-streaming functions that accept changesets (or patchsets) as input
-** require that the entire changeset be stored in a single buffer in memory.
-** Similarly, those that return a changeset or patchset do so by returning
-** a pointer to a single large buffer allocated using sqlite3_malloc().
-** Normally this is convenient. However, if an application running in a
+** require that the entire changeset be stored in a single buffer in memory.
+** Similarly, those that return a changeset or patchset do so by returning
+** a pointer to a single large buffer allocated using sqlite3_malloc().
+** Normally this is convenient. However, if an application running in a
** low-memory environment is required to handle very large changesets, the
** large contiguous memory allocations required can become onerous.
**
@@ -9677,12 +11415,12 @@ int sqlite3changeset_apply(
** </pre>
**
** Each time the xInput callback is invoked by the sessions module, the first
-** argument passed is a copy of the supplied pIn context pointer. The second
-** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
-** error occurs the xInput method should copy up to (*pnData) bytes of data
-** into the buffer and set (*pnData) to the actual number of bytes copied
-** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
-** should be set to zero to indicate this. Or, if an error occurs, an SQLite
+** argument passed is a copy of the supplied pIn context pointer. The second
+** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
+** error occurs the xInput method should copy up to (*pnData) bytes of data
+** into the buffer and set (*pnData) to the actual number of bytes copied
+** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
+** should be set to zero to indicate this. Or, if an error occurs, an SQLite
** error code should be returned. In all cases, if an xInput callback returns
** an error, all processing is abandoned and the streaming API function
** returns a copy of the error code to the caller.
@@ -9690,7 +11428,7 @@ int sqlite3changeset_apply(
** In the case of sqlite3changeset_start_strm(), the xInput callback may be
** invoked by the sessions module at any point during the lifetime of the
** iterator. If such an xInput callback returns an error, the iterator enters
-** an error state, whereby all subsequent calls to iterator functions
+** an error state, whereby all subsequent calls to iterator functions
** immediately fail with the same error code as returned by xInput.
**
** Similarly, streaming API functions that return changesets (or patchsets)
@@ -9720,11 +11458,11 @@ int sqlite3changeset_apply(
** is immediately abandoned and the streaming API function returns a copy
** of the xOutput error code to the application.
**
-** The sessions module never invokes an xOutput callback with the third
+** The sessions module never invokes an xOutput callback with the third
** parameter set to a value less than or equal to zero. Other than this,
** no guarantees are made as to the size of the chunks of data returned.
*/
-int sqlite3changeset_apply_strm(
+SQLITE_API int sqlite3changeset_apply_strm(
sqlite3 *db, /* Apply change to "main" db of this handle */
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
void *pIn, /* First arg for xInput */
@@ -9739,7 +11477,24 @@ int sqlite3changeset_apply_strm(
),
void *pCtx /* First argument passed to xConflict */
);
-int sqlite3changeset_concat_strm(
+SQLITE_API int sqlite3changeset_apply_v2_strm(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+ void *pIn, /* First arg for xInput */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx, /* First argument passed to xConflict */
+ void **ppRebase, int *pnRebase,
+ int flags
+);
+SQLITE_API int sqlite3changeset_concat_strm(
int (*xInputA)(void *pIn, void *pData, int *pnData),
void *pInA,
int (*xInputB)(void *pIn, void *pData, int *pnData),
@@ -9747,36 +11502,88 @@ int sqlite3changeset_concat_strm(
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changeset_invert_strm(
+SQLITE_API int sqlite3changeset_invert_strm(
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changeset_start_strm(
+SQLITE_API int sqlite3changeset_start_strm(
sqlite3_changeset_iter **pp,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
-int sqlite3session_changeset_strm(
+SQLITE_API int sqlite3changeset_start_v2_strm(
+ sqlite3_changeset_iter **pp,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int flags
+);
+SQLITE_API int sqlite3session_changeset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3session_patchset_strm(
+SQLITE_API int sqlite3session_patchset_strm(
sqlite3_session *pSession,
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
-int sqlite3changegroup_add_strm(sqlite3_changegroup*,
+SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
int (*xInput)(void *pIn, void *pData, int *pnData),
void *pIn
);
-int sqlite3changegroup_output_strm(sqlite3_changegroup*,
- int (*xOutput)(void *pOut, const void *pData, int nData),
+SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut
);
+SQLITE_API int sqlite3rebaser_rebase_strm(
+ sqlite3_rebaser *pRebaser,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+
+/*
+** CAPI3REF: Configure global parameters
+**
+** The sqlite3session_config() interface is used to make global configuration
+** changes to the sessions module in order to tune it to the specific needs
+** of the application.
+**
+** The sqlite3session_config() interface is not threadsafe. If it is invoked
+** while any other thread is inside any other sessions method then the
+** results are undefined. Furthermore, if it is invoked after any sessions
+** related objects have been created, the results are also undefined.
+**
+** The first argument to the sqlite3session_config() function must be one
+** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
+** interpretation of the (void*) value passed as the second parameter and
+** the effect of calling this function depends on the value of the first
+** parameter.
+**
+** <dl>
+** <dt>SQLITE_SESSION_CONFIG_STRMSIZE<dd>
+** By default, the sessions module streaming interfaces attempt to input
+** and output data in approximately 1 KiB chunks. This operand may be used
+** to set and query the value of this configuration setting. The pointer
+** passed as the second argument must point to a value of type (int).
+** If this value is greater than 0, it is used as the new streaming data
+** chunk size for both input and output. Before returning, the (int) value
+** pointed to by pArg is set to the final value of the streaming interface
+** chunk size.
+** </dl>
+**
+** This function returns SQLITE_OK if successful, or an SQLite error code
+** otherwise.
+*/
+SQLITE_API int sqlite3session_config(int op, void *pArg);
+/*
+** CAPI3REF: Values for sqlite3session_config().
+*/
+#define SQLITE_SESSION_CONFIG_STRMSIZE 1
/*
** Make sure we can call this stuff from C++.
@@ -9801,7 +11608,7 @@ int sqlite3changegroup_output_strm(sqlite3_changegroup*,
**
******************************************************************************
**
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
+** Interfaces to extend FTS5. Using the interfaces defined in this file,
** FTS5 may be extended with:
**
** * custom tokenizers, and
@@ -9845,19 +11652,19 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
+** Return a copy of the context pointer the extension function was
** registered with.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
** to the total number of tokens in the FTS5 table. Or, if iCol is
** non-negative but less than the number of columns in the table, return
-** the total number of tokens in column iCol, considering all rows in
+** the total number of tokens in column iCol, considering all rows in
** the FTS5 table.
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
+** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** xColumnCount(pFts):
@@ -9871,7 +11678,7 @@ struct Fts5PhraseIter {
**
** If parameter iCol is greater than or equal to the number of columns
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
-** an OOM condition or IO error), an appropriate SQLite error code is
+** an OOM condition or IO error), an appropriate SQLite error code is
** returned.
**
** This function may be quite inefficient if used with an FTS5 table
@@ -9898,8 +11705,8 @@ struct Fts5PhraseIter {
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
+** "detail=none" or "detail=column" option. If the FTS5 table is created
+** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always returns 0.
**
** xInst:
@@ -9910,15 +11717,11 @@ struct Fts5PhraseIter {
**
** Usually, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. The exception is if the table was created
-** with the offsets=0 option specified. In this case *piOff is always
-** set to -1.
-**
-** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
-** if an error occurs.
+** first token of the phrase. Returns SQLITE_OK if successful, or an error
+** code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option.
+** "detail=none" or "detail=column" option.
**
** xRowid:
** Returns the rowid of the current row.
@@ -9934,11 +11737,11 @@ struct Fts5PhraseIter {
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
** current query is executed. Any column filter that applies to
-** phrase iPhrase of the current query is included in $p. For each
-** row visited, the callback function passed as the fourth argument
-** is invoked. The context and API objects passed to the callback
+** phrase iPhrase of the current query is included in $p. For each
+** row visited, the callback function passed as the fourth argument
+** is invoked. The context and API objects passed to the callback
** function may be used to access the properties of each matched row.
-** Invoking Api.xUserData() returns a copy of the pointer passed as
+** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
@@ -9953,14 +11756,14 @@ struct Fts5PhraseIter {
**
** xSetAuxdata(pFts5, pAux, xDelete)
**
-** Save the pointer passed as the second argument as the extension functions
+** Save the pointer passed as the second argument as the extension function's
** "auxiliary data". The pointer may then be retrieved by the current or any
** future invocation of the same fts5 extension function made as part of
-** of the same MATCH query using the xGetAuxdata() API.
+** the same MATCH query using the xGetAuxdata() API.
**
** Each extension function is allocated a single auxiliary data slot for
-** each FTS query (MATCH expression). If the extension function is invoked
-** more than once for a single FTS query, then all invocations share a
+** each FTS query (MATCH expression). If the extension function is invoked
+** more than once for a single FTS query, then all invocations share a
** single auxiliary data context.
**
** If there is already an auxiliary data pointer when this function is
@@ -9971,7 +11774,7 @@ struct Fts5PhraseIter {
** The xDelete callback, if one is specified, is also invoked on the
** auxiliary data pointer after the FTS5 query has finished.
**
-** If an error (e.g. an OOM condition) occurs within this function, an
+** If an error (e.g. an OOM condition) occurs within this function,
** the auxiliary data is set to NULL and an error code returned. If the
** xDelete parameter was not NULL, it is invoked on the auxiliary data
** pointer before returning.
@@ -9979,7 +11782,7 @@ struct Fts5PhraseIter {
**
** xGetAuxdata(pFts5, bClear)
**
-** Returns the current auxiliary data pointer for the fts5 extension
+** Returns the current auxiliary data pointer for the fts5 extension
** function. See the xSetAuxdata() method for details.
**
** If the bClear argument is non-zero, then the auxiliary data is cleared
@@ -9999,7 +11802,7 @@ struct Fts5PhraseIter {
** method, to iterate through all instances of a single query phrase within
** the current row. This is the same information as is accessible via the
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
-** to use, this API may be faster under some circumstances. To iterate
+** to use, this API may be faster under some circumstances. To iterate
** through instances of phrase iPhrase, use the following code:
**
** Fts5PhraseIter iter;
@@ -10017,8 +11820,8 @@ struct Fts5PhraseIter {
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" or "detail=column" option. If the FTS5 table is created
-** with either "detail=none" or "detail=column" and "content=" option
+** "detail=none" or "detail=column" option. If the FTS5 table is created
+** with either "detail=none" or "detail=column" and "content=" option
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
@@ -10042,16 +11845,16 @@ struct Fts5PhraseIter {
** }
**
** This API can be quite slow if used with an FTS5 table created with the
-** "detail=none" option. If the FTS5 table is created with either
-** "detail=none" "content=" option (i.e. if it is a contentless table),
-** then this API always iterates through an empty set (all calls to
+** "detail=none" option. If the FTS5 table is created with either
+** "detail=none" "content=" option (i.e. if it is a contentless table),
+** then this API always iterates through an empty set (all calls to
** xPhraseFirstColumn() set iCol to -1).
**
** The information accessed using this API and its companion
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
** (or xInst/xInstCount). The chief advantage of this API is that it is
** significantly more efficient than those alternatives when used with
-** "detail=column" tables.
+** "detail=column" tables.
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
@@ -10065,7 +11868,7 @@ struct Fts5ExtensionApi {
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
- int (*xTokenize)(Fts5Context*,
+ int (*xTokenize)(Fts5Context*,
const char *pText, int nText, /* Text to tokenize */
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
@@ -10094,15 +11897,15 @@ struct Fts5ExtensionApi {
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
};
-/*
+/*
** CUSTOM AUXILIARY FUNCTIONS
*************************************************************************/
/*************************************************************************
** CUSTOM TOKENIZERS
**
-** Applications may also register custom tokenizer types. A tokenizer
-** is registered by providing fts5 with a populated instance of the
+** Applications may also register custom tokenizer types. A tokenizer
+** is registered by providing fts5 with a populated instance of the
** following structure. All structure methods must be defined, setting
** any member of the fts5_tokenizer struct to NULL leads to undefined
** behaviour. The structure methods are expected to function as follows:
@@ -10113,16 +11916,16 @@ struct Fts5ExtensionApi {
**
** The first argument passed to this function is a copy of the (void*)
** pointer provided by the application when the fts5_tokenizer object
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
+** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
** to create the FTS5 table.
**
-** The final argument is an output variable. If successful, (*ppOut)
+** The final argument is an output variable. If successful, (*ppOut)
** should be set to point to the new tokenizer handle and SQLITE_OK
** returned. If an error occurs, some value other than SQLITE_OK should
-** be returned. In this case, fts5 assumes that the final value of *ppOut
+** be returned. In this case, fts5 assumes that the final value of *ppOut
** is undefined.
**
** xDelete:
@@ -10131,7 +11934,7 @@ struct Fts5ExtensionApi {
** be invoked exactly once for each successful call to xCreate().
**
** xTokenize:
-** This function is expected to tokenize the nText byte string indicated
+** This function is expected to tokenize the nText byte string indicated
** by argument pText. pText may or may not be nul-terminated. The first
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
@@ -10145,8 +11948,8 @@ struct Fts5ExtensionApi {
** determine the set of tokens to add to (or delete from) the
** FTS index.
**
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
-** against the FTS index. The tokenizer is being called to tokenize
+** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
+** against the FTS index. The tokenizer is being called to tokenize
** a bareword or quoted string specified as part of the query.
**
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
@@ -10154,10 +11957,10 @@ struct Fts5ExtensionApi {
** followed by a "*" character, indicating that the last token
** returned by the tokenizer will be treated as a token prefix.
**
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
+** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
** satisfy an fts5_api.xTokenize() request made by an auxiliary
** function. Or an fts5_api.xColumnSize() request made by the same
-** on a columnsize=0 database.
+** on a columnsize=0 database.
** </ul>
**
** For each token in the input string, the supplied callback xToken() must
@@ -10169,10 +11972,10 @@ struct Fts5ExtensionApi {
** which the token is derived within the input.
**
** The second argument passed to the xToken() callback ("tflags") should
-** normally be set to 0. The exception is if the tokenizer supports
+** normally be set to 0. The exception is if the tokenizer supports
** synonyms. In this case see the discussion below for details.
**
-** FTS5 assumes the xToken() callback is invoked for each token in the
+** FTS5 assumes the xToken() callback is invoked for each token in the
** order that they occur within the input text.
**
** If an xToken() callback returns any value other than SQLITE_OK, then
@@ -10186,7 +11989,7 @@ struct Fts5ExtensionApi {
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
-** user wishes to query for a phrase such as "first place". Using the
+** user wishes to query for a phrase such as "first place". Using the
** built-in tokenizers, the FTS5 query 'first + place' will match instances
** of "first place" within the document set, but not alternative forms
** such as "1st place". In some applications, it would be better to match
@@ -10195,8 +11998,8 @@ struct Fts5ExtensionApi {
**
** There are several ways to approach this in FTS5:
**
-** <ol><li> By mapping all synonyms to a single token. In this case, the
-** In the above example, this means that the tokenizer returns the
+** <ol><li> By mapping all synonyms to a single token. In this case, using
+** the above example, this means that the tokenizer returns the
** same token for inputs "first" and "1st". Say that token is in
** fact "first", so that when the user inserts the document "I won
** 1st place" entries are added to the index for tokens "i", "won",
@@ -10204,37 +12007,37 @@ struct Fts5ExtensionApi {
** the tokenizer substitutes "first" for "1st" and the query works
** as expected.
**
-** <li> By adding multiple synonyms for a single term to the FTS index.
-** In this case, when tokenizing query text, the tokenizer may
-** provide multiple synonyms for a single term within the document.
-** FTS5 then queries the index for each synonym individually. For
-** example, faced with the query:
+** <li> By querying the index for all synonyms of each query term
+** separately. In this case, when tokenizing query text, the
+** tokenizer may provide multiple synonyms for a single term
+** within the document. FTS5 then queries the index for each
+** synonym individually. For example, faced with the query:
**
** <codeblock>
** ... MATCH 'first place'</codeblock>
**
** the tokenizer offers both "1st" and "first" as synonyms for the
-** first token in the MATCH query and FTS5 effectively runs a query
+** first token in the MATCH query and FTS5 effectively runs a query
** similar to:
**
** <codeblock>
** ... MATCH '(first OR 1st) place'</codeblock>
**
** except that, for the purposes of auxiliary functions, the query
-** still appears to contain just two phrases - "(first OR 1st)"
+** still appears to contain just two phrases - "(first OR 1st)"
** being treated as a single phrase.
**
** <li> By adding multiple synonyms for a single term to the FTS index.
** Using this method, when tokenizing document text, the tokenizer
-** provides multiple synonyms for each token. So that when a
+** provides multiple synonyms for each token. So that when a
** document such as "I won first place" is tokenized, entries are
** added to the FTS index for "i", "won", "first", "1st" and
** "place".
**
** This way, even if the tokenizer does not provide synonyms
-** when tokenizing query text (it should not - to do would be
-** inefficient), it doesn't matter if the user queries for
-** 'first + place' or '1st + place', as there are entires in the
+** when tokenizing query text (it should not - to do so would be
+** inefficient), it doesn't matter if the user queries for
+** 'first + place' or '1st + place', as there are entries in the
** FTS index corresponding to both forms of the first token.
** </ol>
**
@@ -10254,15 +12057,15 @@ struct Fts5ExtensionApi {
**
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
** xToken() is called. Multiple synonyms may be specified for a single token
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
+** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
** There is no limit to the number of synonyms that may be provided for a
** single token.
**
-** In many cases, method (1) above is the best approach. It does not add
+** In many cases, method (1) above is the best approach. It does not add
** extra data to the FTS index or require FTS5 to query for multiple terms,
** so it is efficient in terms of disk space and query speed. However, it
** does not support prefix queries very well. If, as suggested above, the
-** token "first" is subsituted for "1st" by the tokenizer, then the query:
+** token "first" is substituted for "1st" by the tokenizer, then the query:
**
** <codeblock>
** ... MATCH '1s*'</codeblock>
@@ -10270,18 +12073,18 @@ struct Fts5ExtensionApi {
** will not match documents that contain the token "1st" (as the tokenizer
** will probably not map "1s" to any prefix of "first").
**
-** For full prefix support, method (3) may be preferred. In this case,
+** For full prefix support, method (3) may be preferred. In this case,
** because the index contains entries for both "first" and "1st", prefix
** queries such as 'fi*' or '1s*' will match correctly. However, because
** extra entries are added to the FTS index, this method uses more space
** within the database.
**
** Method (2) offers a midpoint between (1) and (3). Using this method,
-** a query such as '1s*' will match documents that contain the literal
+** a query such as '1s*' will match documents that contain the literal
** token "1st", but not "first" (assuming the tokenizer is not able to
** provide synonyms for prefixes). However, a non-prefix query like '1st'
** will match against "1st" and "first". This method does not require
-** extra disk space, as no extra entries are added to the FTS index.
+** extra disk space, as no extra entries are added to the FTS index.
** On the other hand, it may require more CPU cycles to run MATCH queries,
** as separate queries of the FTS index are required for each synonym.
**
@@ -10295,10 +12098,10 @@ typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
void (*xDelete)(Fts5Tokenizer*);
- int (*xTokenize)(Fts5Tokenizer*,
+ int (*xTokenize)(Fts5Tokenizer*,
void *pCtx,
int flags, /* Mask of FTS5_TOKENIZE_* flags */
- const char *pText, int nText,
+ const char *pText, int nText,
int (*xToken)(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
diff --git a/3rdparty/sqlite3/sqlite3ext.h b/3rdparty/sqlite3/sqlite3ext.h
index ce87e74690b..78c19a0d10c 100644
--- a/3rdparty/sqlite3/sqlite3ext.h
+++ b/3rdparty/sqlite3/sqlite3ext.h
@@ -134,7 +134,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
- char * (*snprintf)(int,char*,const char*,...);
+ char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -246,7 +246,7 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
- char *(*vsnprintf)(int,char*,const char*,va_list);
+ char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
@@ -282,6 +282,59 @@ struct sqlite3_api_routines {
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
+ /* Version 3.18.0 and later */
+ void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
+ /* Version 3.20.0 and later */
+ int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
+ sqlite3_stmt**,const char**);
+ int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
+ sqlite3_stmt**,const void**);
+ int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
+ void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
+ void *(*value_pointer)(sqlite3_value*,const char*);
+ int (*vtab_nochange)(sqlite3_context*);
+ int (*value_nochange)(sqlite3_value*);
+ const char *(*vtab_collation)(sqlite3_index_info*,int);
+ /* Version 3.24.0 and later */
+ int (*keyword_count)(void);
+ int (*keyword_name)(int,const char**,int*);
+ int (*keyword_check)(const char*,int);
+ sqlite3_str *(*str_new)(sqlite3*);
+ char *(*str_finish)(sqlite3_str*);
+ void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
+ void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
+ void (*str_append)(sqlite3_str*, const char *zIn, int N);
+ void (*str_appendall)(sqlite3_str*, const char *zIn);
+ void (*str_appendchar)(sqlite3_str*, int N, char C);
+ void (*str_reset)(sqlite3_str*);
+ int (*str_errcode)(sqlite3_str*);
+ int (*str_length)(sqlite3_str*);
+ char *(*str_value)(sqlite3_str*);
+ /* Version 3.25.0 and later */
+ int (*create_window_function)(sqlite3*,const char*,int,int,void*,
+ void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+ void (*xFinal)(sqlite3_context*),
+ void (*xValue)(sqlite3_context*),
+ void (*xInv)(sqlite3_context*,int,sqlite3_value**),
+ void(*xDestroy)(void*));
+ /* Version 3.26.0 and later */
+ const char *(*normalized_sql)(sqlite3_stmt*);
+ /* Version 3.28.0 and later */
+ int (*stmt_isexplain)(sqlite3_stmt*);
+ int (*value_frombind)(sqlite3_value*);
+ /* Version 3.30.0 and later */
+ int (*drop_modules)(sqlite3*,const char**);
+ /* Version 3.31.0 and later */
+ sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
+ const char *(*uri_key)(const char*,int);
+ const char *(*filename_database)(const char*);
+ const char *(*filename_journal)(const char*);
+ const char *(*filename_wal)(const char*);
+ /* Version 3.32.0 and later */
+ char *(*create_filename)(const char*,const char*,const char*,
+ int,const char**);
+ void (*free_filename)(char*);
+ sqlite3_file *(*database_file_object)(const char*);
};
/*
@@ -408,7 +461,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
-#define sqlite3_snprintf sqlite3_api->snprintf
+#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -432,7 +485,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
-#define sqlite3_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -508,7 +561,7 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
-#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
+#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
@@ -540,6 +593,52 @@ typedef int (*sqlite3_loadext_entry)(
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
+/* Version 3.18.0 and later */
+#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
+/* Version 3.20.0 and later */
+#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
+#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
+#define sqlite3_bind_pointer sqlite3_api->bind_pointer
+#define sqlite3_result_pointer sqlite3_api->result_pointer
+#define sqlite3_value_pointer sqlite3_api->value_pointer
+/* Version 3.22.0 and later */
+#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
+#define sqlite3_value_nochange sqlite3_api->value_nochange
+#define sqlite3_vtab_collation sqlite3_api->vtab_collation
+/* Version 3.24.0 and later */
+#define sqlite3_keyword_count sqlite3_api->keyword_count
+#define sqlite3_keyword_name sqlite3_api->keyword_name
+#define sqlite3_keyword_check sqlite3_api->keyword_check
+#define sqlite3_str_new sqlite3_api->str_new
+#define sqlite3_str_finish sqlite3_api->str_finish
+#define sqlite3_str_appendf sqlite3_api->str_appendf
+#define sqlite3_str_vappendf sqlite3_api->str_vappendf
+#define sqlite3_str_append sqlite3_api->str_append
+#define sqlite3_str_appendall sqlite3_api->str_appendall
+#define sqlite3_str_appendchar sqlite3_api->str_appendchar
+#define sqlite3_str_reset sqlite3_api->str_reset
+#define sqlite3_str_errcode sqlite3_api->str_errcode
+#define sqlite3_str_length sqlite3_api->str_length
+#define sqlite3_str_value sqlite3_api->str_value
+/* Version 3.25.0 and later */
+#define sqlite3_create_window_function sqlite3_api->create_window_function
+/* Version 3.26.0 and later */
+#define sqlite3_normalized_sql sqlite3_api->normalized_sql
+/* Version 3.28.0 and later */
+#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
+#define sqlite3_value_frombind sqlite3_api->value_frombind
+/* Version 3.30.0 and later */
+#define sqlite3_drop_modules sqlite3_api->drop_modules
+/* Version 3.31.0 and later */
+#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
+#define sqlite3_uri_key sqlite3_api->uri_key
+#define sqlite3_filename_database sqlite3_api->filename_database
+#define sqlite3_filename_journal sqlite3_api->filename_journal
+#define sqlite3_filename_wal sqlite3_api->filename_wal
+/* Version 3.32.0 and later */
+#define sqlite3_create_filename sqlite3_api->create_filename
+#define sqlite3_free_filename sqlite3_api->free_filename
+#define sqlite3_database_file_object sqlite3_api->database_file_object
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/COPYING b/COPYING
index 740df3074d1..4e5626b4b7a 100644
--- a/COPYING
+++ b/COPYING
@@ -154,9 +154,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Expat
-Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
-and Clark Cooper
-Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers
+Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and
+Clark Cooper
+Copyright (c) 2001-2019 Expat maintainers
Lua - a powerful, fast, lightweight, embeddable scripting language
Copyright (c) 1994-2017 Lua.org, PUC-Rio
diff --git a/android-project/app/src/main/AndroidManifest.xml b/android-project/app/src/main/AndroidManifest.xml
index 0c98d15c612..be78134bc00 100644
--- a/android-project/app/src/main/AndroidManifest.xml
+++ b/android-project/app/src/main/AndroidManifest.xml
@@ -4,8 +4,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mamedev.mame"
- android:versionCode="224"
- android:versionName="0.224"
+ android:versionCode="225"
+ android:versionName="0.225"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->
diff --git a/docs/source/images/MAMElogo.svg b/docs/source/images/MAMElogo.svg
index b45bc7ebdb3..01d860d18e7 100644
--- a/docs/source/images/MAMElogo.svg
+++ b/docs/source/images/MAMElogo.svg
@@ -1,68 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- id="svg4563"
+ id="svg-mamelogo"
version="1.1"
- viewBox="0 0 321.26581 91.07238"
- height="91.07238mm"
- width="321.26581mm">
- <defs
- id="defs4557">
- <linearGradient
- id="left-dark">
- <stop
- style="stop-color:#00274f;stop-opacity:1"
- offset="0"
- id="stop5213" />
- <stop
- style="stop-color:#68cafb;stop-opacity:1"
- offset="1"
- id="stop5215" />
+ viewBox="0 0 1214 344"
+ height="344px"
+ width="1214px">
+ <defs>
+ <linearGradient id="left-dark" x1="0" x2="1" y1="0" y2="0">
+ <stop id="stop5213" offset="0" stop-color="#00274f" />
+ <stop id="stop5215" offset="1" stop-color="#68cafb" />
</linearGradient>
- <linearGradient
- gradientUnits="userSpaceOnUse"
- y2="299.328"
- x2="11"
- y1="299.328"
- x1="1213.16"
- id="right-dark">
- <stop
- id="stop4"
- stop-color="#68cafb"
- offset="0" />
- <stop
- id="stop6"
- stop-color="#00274f"
- offset="1" />
+ <linearGradient id="right-dark" x1="0" x2="1" y1="0" y2="0">
+ <stop id="stop4" offset="0" stop-color="#68cafb" />
+ <stop id="stop6" offset="1" stop-color="#00274f" />
</linearGradient>
- <linearGradient
- gradientUnits="userSpaceOnUse"
- y2="162.44048"
- x2="237.65611"
- y1="162.44048"
- x1="-80.41803"
- id="linearGradient5175"
- xlink:href="#right-dark" />
- <linearGradient
- gradientUnits="userSpaceOnUse"
- y2="162.44048"
- x2="237.65611"
- y1="162.44048"
- x1="-80.41803"
- id="linearGradient5211"
- xlink:href="#left-dark" />
</defs>
- <g
- transform="translate(82.012688,-116.4355)"
- id="layer1">
+ <g>
<path
- style="fill:url(#linearGradient5175);fill-rule:evenodd;stroke:url(#linearGradient5211);stroke-width:1.32291663px;stroke-linejoin:miter;stroke-opacity:0.75"
- d="m -80.418029,184.88601 66.4546,-66.5869 v 28.92769 l 29.05998,-28.92769 v 46.56667 l 46.74315,-46.83125 v 52.51979 l 52.519789,-52.51979 v 29.19227 l 29.01579,-28.92769 v 44.6704 l 43.56815,-43.65625 h 50.71269 l -16.36184,16.36025 h -25.83921 l -7.40833,7.40833 h 13.44877 l -17.02064,17.24184 h -13.80332 l -7.67291,7.54062 h 44.93418 l -17.15293,17.02171 h -68.74748 l 4.14496,-4.54211 V 161.91118 L 101.6153,186.07663 V 158.0308 L 74.715911,184.88601 H 44.421121 V 162.17576 L -0.24927857,206.84642 H -26.707609 L -2.1013586,182.1518 V 162.17576 L -26.707609,186.6058 v -29.10417 l -27.25209,27.38438 z"
- class="cls-1" />
+ fill="url(#right-dark)" stroke="url(#left-dark)" stroke-width="5" stroke-linejoin="miter" stroke-opacity="0.75"
+ d="M 6,259 257,7 V 116 L 367,7 V 183 L 544,6 V 204 L 742,7 V 116 L 852,7 V 176 L 1017,11 H 1208 L 1146,73 H 1049 L 1021,101 H 1072 L 1007,166 H 955 L 926,195 H 1096 L 1031,259 H 771 L 787,241 V 172 L 694,263 V 157 L 592,259 H 478 V 172 L 309,341 H 209 L 302,248 V 172 L 209,263 V 157 L 106,259 z" />
</g>
</svg>
diff --git a/docs/source/techspecs/layout_files.rst b/docs/source/techspecs/layout_files.rst
index 31864f1c70f..9ebb5863de5 100644
--- a/docs/source/techspecs/layout_files.rst
+++ b/docs/source/techspecs/layout_files.rst
@@ -64,7 +64,7 @@ in the rightward and downward directions. The origin (0,0) has no particular
significance, and you may freely use negative coordinates in layouts.
Coordinates are supplied as floating-point numbers.
-MAME assumes that view coordinates have the same aspect ratio as pixel on the
+MAME assumes that view coordinates have the same aspect ratio as pixels on the
output device (host screen or window). Assuming square pixels and no rotation,
this means equal distances in X and Y axes correspond to equal horizontal and
vertical distances in the rendered output.
@@ -73,20 +73,30 @@ Views, groups and elements all have their own internal coordinate systems. When
an element or group is referenced from a view or another group, its coordinates
are scaled as necessary to fit the specified bounds.
-Objects are positioned and sized using ``bounds`` elements. A bounds element
-may specify the position of the top left corner and the size using ``x``, ``y``,
-``width`` and ``height`` attributes, or it may specify the coordinates of the
-edges with the ``left``, ``top``, ``right`` and ``bottom`` attributes. These
-two ``bounds`` elements are equivalent::
+Objects are positioned and sized using ``bounds`` elements. The horizontal
+position and size may be specified in three ways: left edge and width using
+``x`` and ``width`` attributes, horizontal centre and width using ``xc`` and
+``width`` attributes, or left and right edges using ``left`` and ``right``
+attributes. Similarly, the vertical position and size may be specified in terms
+of the top edge and height using ``y`` and ``height`` attributes, vertical
+centre and height using ``yc`` and ``height`` attributes, or top and bottom
+edges using ``top`` and ``bottom`` attributes.
- <bounds x="455" y="120" width="11" height="7" />
- <bounds left="455" top="120" right="466" bottom="127" />
+These three ``bounds`` elements are equivalent::
-Either the ``x`` or ``left`` attribute must be present to distinguish between
-the two schemes. The ``width`` and ``height`` or ``right`` and ``bottom``
-default to 1.0 if not supplied. It is an error if ``width`` or ``height`` are
-negative, if ``right`` is less than ``left``, or if ``bottom`` is less than
-``top``.
+ <bounds x="455" y="120" width="12" height="8" />
+ <bounds xc="461" yc="124" width="12" height="8" />
+ <bounds left="455" top="120" right="467" bottom="128" />
+
+It’s possible to use different schemes in the horizontal and vertical
+directions. For example, these equivalent ``bounds`` elements are also valid::
+
+ <bounds x="455" top="120" width="12" bottom="128" />
+ <bounds left="455" yc="124" right="467" height="8" />
+
+The ``width``/``height`` or ``right``/``bottom`` default to 1.0 if not supplied.
+It is an error if ``width`` or ``height`` are negative, if ``right`` is less
+than ``left``, or if ``bottom`` is less than ``top``.
.. _layout-concepts-colours:
@@ -376,12 +386,12 @@ and rendering. An element may be used in multiple views, and may be used
multiple times within a view.
An element’s appearance depends on its *state*. The state is an integer which
-usually comes from an I/O port field or an emulated output (see the discussion
-of :ref:`layout-parts-views` for information on connecting an element to an I/O
-port or output). Any component of an element may be restricted to only drawing
-when the element’s state is a particular value. Some components (e.g.
-multi-segment displays and reels) use the state directly to determine their
-appearance.
+usually comes from an I/O port field or an emulated output (see
+:ref:`layout-interact-elemstate` for information on connecting an element to an
+emulated I/O port or output). Any component of an element may be restricted to
+only drawing when the element’s state is a particular value. Some components
+(e.g. multi-segment displays and reels) use the state directly to determine
+their appearance.
Each element has its own internal coordinate system. The bounds of the
element’s coordinate system are computed as the union of the bounds of the
@@ -395,8 +405,9 @@ attribute, to be used if not connected to an emulated output or I/O port. If
present, the ``defstate`` attribute must be a non-negative integer.
Child elements of the ``element`` element instantiate components, which are
-drawn in reading order from first to last (components draw on top of components
-that come before them). All components support a few common features:
+drawn into the element texture in reading order from first to last using alpha
+blending (components draw over and may obscure components that come before
+them). All components support a few common features:
* Components may be conditionally drawn depending on the element’s state by
supplying ``state`` and/or ``statemask`` attributes. If present, these
@@ -459,18 +470,25 @@ rect
disk
Draws a uniform colour ellipse fitted to its bounds.
image
- Draws an image loaded from a PNG or JPEG file. The name of the file to load
- (including the file name extension) is supplied with the required ``file``
- attribute. Additionally, an optional ``alphafile`` attribute may be used to
- specify the name of a PNG file (including the file name extension) to load
- into the alpha channel of the image. The image file(s) should be placed in
- the same directory/archive as the layout file. If the ``alphafile``
- attribute refers refers to a file, it must have the same dimensions as the
- file referred to by the ``file`` attribute, and must have a bit depth no
- greater than eight bits per channel per pixel. The intensity from this
- image (brightness) is copied to the alpha channel, with full intensity (white
- in a greyscale image) corresponding to fully opaque, and black corresponding
- to fully transparent.
+ Draws an image loaded from a PNG, JPEG, Windows DIB (BMP) or SVG file. The
+ name of the file to load (including the file name extension) is supplied
+ using the required ``file`` attribute. Additionally, an optional
+ ``alphafile`` attribute may be used to specify the name of a PNG file
+ (including the file name extension) to load into the alpha channel of the
+ image.
+
+ If the ``alphafile`` attribute refers refers to a file, it must have the
+ same dimensions (in pixels) as the file referred to by the ``file``
+ attribute, and must have a bit depth no greater than eight bits per channel
+ per pixel. The intensity from this image (brightness) is copied to the
+ alpha channel, with full intensity (white in a greyscale image)
+ corresponding to fully opaque, and black corresponding to fully transparent.
+ The ``alphafile`` attribute will be ignored if the ``file`` attribute refers
+ to an SVG image; it is only used in conjunction with bitmap images.
+
+ The image file(s) should be placed in the same directory/archive as the
+ layout file. Image file formats are detected by examining the content of
+ the files, file name extensions are ignored.
text
Draws text in using the UI font in the specified colour. The text to draw
must be supplied using a ``string`` attribute. An ``align`` attribute may
@@ -680,11 +698,15 @@ param
element
Adds an element to the view (see :ref:`layout-parts-elements`). The name of
the element to add is specified using the required ``ref`` attribute. It is
- an error if no element with this name is defined in the layout file. May
- optionally be connected to an emulated I/O port using ``inputtag`` and
+ an error if no element with this name is defined in the layout file. Within
+ a layer, elements are drawn in the order they appear in the layout file,
+ from front to back. See below for more details.
+
+ May optionally be connected to an emulated I/O port using ``inputtag`` and
``inputmask`` attributes, and/or an emulated output using a ``name``
- attribute. Within a layer, elements are drawn in the order they appear in
- the layout file, from front to back. See below for more details.
+ attribute. See :ref:`layout-interact-clickable` for details. See
+ :ref:`layout-interact-elemstate` for details on supplying a state value to
+ the instantiated element.
screen
Adds an emulated screen image to the view. The screen must be identified
using either an ``index`` attribute or a ``tag`` attribute (it is an error
@@ -694,6 +716,10 @@ screen
zero (0). If present, the ``tag`` attribute must be the tag path to the
screen relative to the device that causes the layout to be loaded. Screens
are drawn in the order they appear in the layout file, from front to back.
+
+ May optionally be connected to an emulated I/O port using ``inputtag`` and
+ ``inputmask`` attributes, and/or an emulated output using a ``name``
+ attribute. See :ref:`layout-interact-clickable` for details.
collection
Adds screens and/or items in a collection that can be shown or hidden by the
user (see :ref:`layout-parts-collections`). The name of the collection is
@@ -765,51 +791,10 @@ Screens (``screen`` elements), layout elements (``element`` elements) and groups
:ref:`layout-concepts-colours`) specifying a modifier colour. The component
colours of the screen or layout element(s) are multiplied by this colour.
-If an ``element`` element has ``inputtag`` and ``inputmask`` attributes,
-clicking it is equivalent to pressing a key/button mapped to the corresponding
-input(s). The ``inputtag`` specifies the tag path of an I/O port relative to
-the device that caused the layout file to be loaded. The ``inputmask``
-attribute must be an integer specifying the bits of the I/O port that the
-element should activate. This sample shows instantiation of clickable buttons::
-
- <element ref="btn_3" inputtag="X2" inputmask="0x10">
- <bounds x="2.30" y="4.325" width="1.0" height="1.0" />
- </element>
- <element ref="btn_0" inputtag="X0" inputmask="0x20">
- <bounds x="0.725" y="5.375" width="1.0" height="1.0" />
- </element>
- <element ref="btn_rst" inputtag="RESET" inputmask="0x01">
- <bounds x="1.775" y="5.375" width="1.0" height="1.0" />
- </element>
-
-If an ``element`` element has a ``name`` attribute, it will take its state from
-the value of the correspondingly named emulated output. Note that output names
-are global, which can become an issue when a machine uses multiple instances of
-the same type of device. See :ref:`layout-parts-elements` for details on how an
-element’s state affects its appearance. This example shows how digital displays
-may be connected to emulated outputs::
-
- <element name="digit6" ref="digit"><bounds x="16" y="16" width="48" height="80" /></element>
- <element name="digit5" ref="digit"><bounds x="64" y="16" width="48" height="80" /></element>
- <element name="digit4" ref="digit"><bounds x="112" y="16" width="48" height="80" /></element>
- <element name="digit3" ref="digit"><bounds x="160" y="16" width="48" height="80" /></element>
- <element name="digit2" ref="digit"><bounds x="208" y="16" width="48" height="80" /></element>
- <element name="digit1" ref="digit"><bounds x="256" y="16" width="48" height="80" /></element>
-
-If an element instantiating a layout element has ``inputtag`` and ``inputmask``
-attributes but lacks a ``name`` attribute, it will take its state from the value
-of the corresponding I/O port, masked with the ``inputmask`` value and XORed
-with the I/O port default field value. The latter is useful for inputs that are
-active-low. If the result is non-zero, the state is 1, otherwise it’s 0. This
-is often used to allow clickable buttons and toggle switches to provide visible
-feedback. By using ``inputraw="1"``, it’s possible to obtain the raw data from
-the I/O port, masked with the ``inputmask`` value and shifted to the right to
-remove trailing zeroes (for example a mask of 0x05 will result in no shift, while
-a mask of 0xb0 will result in the value being shifted four bits to the right).
-
-When handling mouse input, MAME treats all layout elements as being rectangular,
-and only activates the frontmost element whose area includes the location of the
-mouse pointer.
+Screens (``screen`` elements) and layout elements (``element`` elements) may
+have their colour and position/size animated by supplying multiple ``color``
+and/or ``bounds`` child elements with ``state`` attributes. See
+:ref:`layout-interact-itemanim` for details.
.. _layout-parts-collections:
@@ -1087,6 +1072,207 @@ tiles on each iteration. Rows are connected to I/O ports ``board:IN.7`` at the
top to ``board.IN.0`` at the bottom.
+.. _layout-interact:
+
+Interactivity
+-------------
+
+Interactive views are supported by allowing items to be bound to emulated
+outputs and I/O ports. Five kinds of interactivity are supported:
+
+Clickable items
+ If an item in a view is bound to an I/O port switch field, clicking the
+ item will activate the emulated switch.
+State-dependent components
+ Some components will be drawn differently depending on the containing
+ element’s state. These include the dot matrix, multi-segment LED display,
+ simple counter and reel elements. See :ref:`layout-parts-elements` for
+ details.
+Conditionally-drawn components
+ Components may be conditionally drawn or hidden depending on the containing
+ element’s state by supplying ``state`` and/or ``statemask`` attributes. See
+ :ref:`layout-parts-elements` for details.
+Component parameter animation
+ Components’ colour and position/size within their containing element may be
+ animated according the element’s state by providing multiple ``color``
+ and/or ``bounds`` elements with ``state`` attributes. See
+ :ref:`layout-parts-elements` for details.
+Item parameter animation
+ Items’ colour and position/size within their containing view may be animated
+ according to their animation state.
+
+
+.. _layout-interact-clickable:
+
+Clickable items
+~~~~~~~~~~~~~~~
+
+If a view item (``element`` or ``screen`` element) has ``inputtag`` and
+``inputmask`` attribute values that correspond to a digital switch field in the
+emulated system, clicking the element will activate the switch. The switch
+will remain active as long as the mouse button is held down and the pointer is
+within the item’s current bounds. (Note that the bounds may change depending on
+the item’s animation state, see :ref:`layout-interact-itemanim`).
+
+The ``inputtag`` attribute specifies the tag path of an I/O port relative to the
+device that caused the layout file to be loaded. The ``inputmask`` attribute
+must be an integer specifying the bits of the I/O port field that the item
+should activate. This sample shows instantiation of clickable buttons::
+
+ <element ref="btn_3" inputtag="X2" inputmask="0x10">
+ <bounds x="2.30" y="4.325" width="1.0" height="1.0" />
+ </element>
+ <element ref="btn_0" inputtag="X0" inputmask="0x20">
+ <bounds x="0.725" y="5.375" width="1.0" height="1.0" />
+ </element>
+ <element ref="btn_rst" inputtag="RESET" inputmask="0x01">
+ <bounds x="1.775" y="5.375" width="1.0" height="1.0" />
+ </element>
+
+When handling mouse input, MAME treats all layout elements as being rectangular,
+and only activates the first clickable item whose area includes the location of
+the mouse pointer.
+
+
+.. _layout-interact-elemstate:
+
+Element state
+~~~~~~~~~~~~~
+
+A view item that instantiates an element (``element`` element) may supply a
+state value to the element from an emulated I/O port or output. See
+:ref:`layout-parts-elements` for details on how an element’s state affects its
+appearance.
+
+If the ``element`` element has a ``name`` attribute, the element state value
+will be taken from the value of the correspondingly named emulated output. Note
+that output names are global, which can become an issue when a machine uses
+multiple instances of the same type of device. This example shows how digital
+displays may be connected to emulated outputs::
+
+ <element name="digit6" ref="digit"><bounds x="16" y="16" width="48" height="80" /></element>
+ <element name="digit5" ref="digit"><bounds x="64" y="16" width="48" height="80" /></element>
+ <element name="digit4" ref="digit"><bounds x="112" y="16" width="48" height="80" /></element>
+ <element name="digit3" ref="digit"><bounds x="160" y="16" width="48" height="80" /></element>
+ <element name="digit2" ref="digit"><bounds x="208" y="16" width="48" height="80" /></element>
+ <element name="digit1" ref="digit"><bounds x="256" y="16" width="48" height="80" /></element>
+
+If the ``element`` element has ``inputtag`` and ``inputmask`` attributes but
+lacks a ``name`` attribute, the element state value will be taken from the value
+of the corresponding I/O port, masked with the ``inputmask`` value. The
+``inputtag`` attribute specifies the tag path of an I/O port relative to the
+device that caused the layout file to be loaded. The ``inputmask`` attribute
+must be an integer specifying the bits of the I/O port field to use.
+
+If the ``element`` element has no ``inputraw`` attribute, or if the value of the
+``inputraw`` attribute is ``no``, the I/O port’s value is masked with the
+``inputmask`` value and XORed with the I/O port default field value. If the
+result is non-zero, the element state is 1, otherwise it’s 0. This is often
+used or provide visual feedback for clickable buttons, as values for active-high
+and active-low switches are normalised.
+
+If the ``element`` element has an ``inputraw`` attribute with the value ``yes``,
+the element state will be taken from the I/O port’s value masked with the
+``inputmask`` value and shifted to the right to remove trailing zeroes (for
+example a mask of 0x05 will result in no shift, while a mask of 0xb0 will result
+in the value being shifted four bits to the right). This is useful for
+obtaining the value of analog or positional inputs.
+
+
+.. _layout-interact-itemanim:
+
+View item animation
+~~~~~~~~~~~~~~~~~~~
+
+Items’ colour and position/size within their containing view may be animated.
+This is achieved by supplying multiple ``color`` and/or ``bounds`` child
+elements with ``state`` attributes. The ``state`` attribute of each ``color``
+or ``bounds`` child element must be a non-negative integer. Withing a view
+item, no two ``color`` elements may have equal state ``state`` attributes, and
+no two ``bounds`` elements may have equal ``state`` attributes.
+
+If the item’s animation state is lower than the ``state`` value of any
+``bounds`` child element, the position/size specified by the ``bounds`` child
+element with the lowest ``state`` value will be used. If the item’s
+animation state is higher than the ``state`` value of any ``bounds`` child
+element, the position/size specified by the ``bounds`` child element with the
+highest ``state`` value will be used. If the item’s animation state is between
+the ``state`` values of two ``bounds`` child elements, the position/size will be
+interpolated linearly.
+
+If the item’s animation state is lower than the ``state`` value of any ``color``
+child element, the colour specified by the ``color`` child element with the
+lowest ``state`` value will be used. If the item’s animation state is higher
+than the ``state`` value of any ``color`` child element, the colour specified by
+the ``color`` child element with the highest ``state`` value will be used. If
+the item’s animation state is between the ``state`` values of two ``color``
+child elements, the RGBA colour components will be interpolated linearly.
+
+An item’s animation state may be bound to an emulated output or input port by
+supplying an ``animate`` child element. If present, the ``animate`` element
+must have either an ``inputtag`` attribute or a ``name`` attribute (but not
+both). If the ``animate`` child element is not present, the item’s animation
+state is the same as its element state (see :ref:`layout-interact-elemstate`).
+
+If the ``animate`` child element is present and has an ``inputtag``
+attribute, the item’s animation state will be taken from the value of the
+corresponding I/O port. The ``inputtag`` attribute specifies the tag path of an
+I/O port relative to the device that caused the layout file to be loaded. The
+raw value from the input port is used, active-low switch values are not
+normalised.
+
+If the ``animate`` child element is present and has a ``name`` attribute, the
+item’s animation state will be taken from the value of the correspondingly named
+emulated output. Note that output names are global, which can become an issue
+when a machine uses multiple instances of the same type of device.
+
+If the ``animate`` child element has a ``mask`` attribute, the item’s animation
+state will be masked with the ``mask`` value and shifted to the right to remove
+trailing zeroes (for example a mask of 0x05 will result in no shift, while a
+mask of 0xb0 will result in the value being shifted four bits to the right).
+Note that the ``mask`` attribute applies to output value (specified with the
+``name`` attribute) as well as input port values (specified with the
+``inputtag`` attribute). If the ``mask`` attribute is present, it must be an
+integer value. If the ``mask`` attribute is not present, it is equivalent to
+all 32 bits being set.
+
+This example shows elements with independent element state and animation state,
+using the animation state taken from emulated outputs to control their
+position::
+
+ <repeat count="5">
+ <param name="x" start="10" increment="9" />
+ <param name="i" start="0" increment="1" />
+ <param name="mask" start="0x01" lshift="1" />
+
+ <element name="cg_sol~i~" ref="cosmo">
+ <animate name="cg_count~i~" />
+ <bounds state="0" x="~x~" y="10" width="6" height="7" />
+ <bounds state="255" x="~x~" y="48.5" width="6" height="7" />
+ </element>
+
+ <element ref="nothing" inputtag="FAKE1" inputmask="~mask~">
+ <animate name="cg_count~i~" />
+ <bounds state="0" x="~x~" y="10" width="6" height="7" />
+ <bounds state="255" x="~x~" y="48.5" width="6" height="7" />
+ </element>
+ </repeat>
+
+This example shows elements with independent element state and animation state,
+using the animation state taken from an emulated positional input to control
+their positions::
+
+ <repeat count="4">
+ <param name="y" start="1" increment="3" />
+ <param name="n" start="0" increment="1" />
+ <element ref="ledr" name="~n~.7">
+ <animate inputtag="IN.1" mask="0x0f" />
+ <bounds state="0" x="0" y="~y~" width="1" height="1" />
+ <bounds state="11" x="16.5" y="~y~" width="1" height="1" />
+ </element>
+ </repeat>
+
+
.. _layout-errors:
Error handling
diff --git a/docs/source/usingmame/defaultkeys.rst b/docs/source/usingmame/defaultkeys.rst
index fad002e3b90..c55dc42b786 100644
--- a/docs/source/usingmame/defaultkeys.rst
+++ b/docs/source/usingmame/defaultkeys.rst
@@ -1,13 +1,19 @@
-.. _default-keys:
+Default Keyboard Controls
+=========================
+
+.. contents:: :local:
+
+
+.. _default-keys-foreword:
Controls Foreword
-=================
+-----------------
MAME supports a vast array of different types of machines, with a
significantly different array of inputs across them. This means that some
keyboard keys, mouse buttons, and joystick buttons will be used for multiple
functions. As a result, the control charts below are separated by machine-types
-to make it easier to find what you're looking for.
+to make it easier to find what you’re looking for.
All of the controls below are fully configurable in the user interface. These
charts show the default configuration.
@@ -15,10 +21,10 @@ charts show the default configuration.
Note that the defaults shown here are arranged by US ANSI key positioning. If
you are using a different layout, the keys will vary.
-MAME Controls
-=============
+MAME User Interface Controls
+----------------------------
-The controls here cover MAME functions such as MAME's menus, machine pause,
+The controls here cover MAME functions such as MAME’s menus, machine pause,
and saving/loading save states.
@@ -26,9 +32,9 @@ and saving/loading save states.
Toggles the configuration menu.
Switches to the next UI panel.
**~** (tilde key)
- Toggles the On Screen Display.
+ Toggles the On-Screen Display.
- If you are running with -debug, this key sends a 'break' in emulation.
+ If you are running with -debug, this key sends a ‘break’ in emulation.
When the on-screen display is visible, you can use the following
keys to control it:
@@ -73,28 +79,22 @@ and saving/loading save states.
UI Next Group
**P**
Pauses the emulated machine.
-**Shift+P**
+**Left Shift+P**
While paused, advances to next frame. If rewind is enabled, a new rewind
save state is also captured.
-**Shift+~**
+**Left Shift+~**
While paused, loads the most recent rewind save state.
-**-** *(not numeric keypad)*
- Volume Down for machines that have a volume control.
-**=** *(not numeric keypad)*
- Volume Up for machines that have a volume control.
**F1**
Power the machine on for machines that have specific power button behavior.
**F2**
Power the machine off for machines that have specific power button behavior.
-
- Service Mode button for machines that support that.
**F3**
Soft resets the machine.
-**Shift+F3**
- Performs a "hard reset", which tears everything down and re-creates it from
+**Left Shift+F3**
+ Performs a “hard resetâ€, which tears everything down and re-creates it from
scratch. This is a more thorough and complete reset than the reset you get
from hitting F3.
-**LCtrl+F3**
+**Left Ctrl+F3**
Toggle uneven stretch. (*SDL ONLY*)
**F4**
Shows the game palette, decoded graphics tiles/characters and any tilemaps.
@@ -136,20 +136,20 @@ and saving/loading save states.
* **Enter** - switch to palette/colortable mode.
Note: Not all games have decoded graphics and/or tilemaps.
-**LCtrl+F4**
+**Left Ctrl+F4**
Toggles keeping aspect ratio.
(*SDL MAME only*)
-**LCtrl+F5**
+**Left Ctrl+F5**
Toggle Filter. (*SDL ONLY*)
(*SDL MAME only*)
-**Alt+Ctrl+F5**
+**Left Alt+Left Ctrl+F5**
Toggle HLSL Post-Processing.
(*Windows non-SDL MAME only*)
**F6**
- Toggle cheat mode. (if started with "-cheat")
-**LCtrl+F6**
+ Toggle cheat mode. (if started with “-cheatâ€)
+**Left Ctrl+F6**
Decrease Prescaling.
-**LCtrl+F7**
+**Left Ctrl+F7**
Increase Prescaling.
**F7**
Load a save state. You will be prompted to press a key or select from the
@@ -159,7 +159,7 @@ and saving/loading save states.
drivers. If a given driver is not known to work perfectly, you will
receive a warning that the save state may not be valid when attempting to
save or load.*
-**Shift+F7**
+**Left Shift+F7**
Create a save state. Requires an additional keypress to identify the state,
similar to the load option above. If an existing save state is present, it
will also appear in the selection menu to allow overwriting of that save
@@ -172,9 +172,9 @@ and saving/loading save states.
Toggle speed throttling.
**F11**
Toggles speed display.
-**Shift+F11**
+**Left Shift+F11**
Toggles internal profiler display (if compiled in).
-**Alt+F11**
+**Left Alt+F11**
Record HLSL Rendered Video.
**F12**
Saves a screen snapshot.
@@ -182,22 +182,22 @@ and saving/loading save states.
Begin recording MNG video.
**Left Control+Left Shift+F12**
Begin recording AVI video.
-**Alt+F12**
+**Left Alt+F12**
Take HLSL Rendered Snapshot.
**Insert**
Fast forward. While held, runs game with throttling disabled and with the
maximum frameskip.
(*Windows non-SDL MAME only*)
-**Page DN**
+**Page Down**
Fast forward. While held, runs game with throttling disabled and with the
maximum frameskip.
(*Windows non-SDL MAME only*)
-**Alt+ENTER**
+**Left Alt+Enter**
Toggles between full-screen and windowed mode.
**Scroll Lock**/**Forward Delete** (Mac Desktop)/**fn-Delete** (Mac Laptop)
Default mapping for the **uimodekey**.
- This key toggles MAME's response to user interface keys such as the
+ This key toggles MAME’s response to user interface keys such as the
(by default) **Tab** key being used for menus. All emulated machines
which require emulated keyboards will start with UI controls disabled by
default and you can only access the internal UI by first hitting this
@@ -212,38 +212,92 @@ and saving/loading save states.
.. _default-arcade-keys:
Default Arcade Machine Controls
-===============================
+-------------------------------
-All the controls below are fully configurable in the user interface. This list
-shows the standard keyboard configuration.
+This section covers controls that are applicable to most kinds of arcade
+machines. Note that not all machines will have all of these controls. All the
+controls below are fully configurable in the user interface. This list shows
+the standard keyboard configuration.
-**5**
+**5** *(not numeric keypad)*
Coin slot 1
-**6**
+**6** *(not numeric keypad)*
Coin slot 2
-**7**
+**7** *(not numeric keypad)*
Coin slot 3
-**8**
+**8** *(not numeric keypad)*
Coin slot 4
-**1**
- Player 1 start or 1 player mode
-**2**
- Player 2 start or 2 players mode
-**3**
- Player 3 start or 3 players mode
-**4**
- Player 4 start or 4 players mode
**Backspace**
Bill 1 (For machines that have a bill receptor/note reader)
-**9**
- Service 1 (Service buttons are typically used to give free credits or to
- navigate the internal operator service menus)
-**0**
+**T**
+ Tilt
+
+ Usually a tilt switch or shock sensor that will end the current game, reset
+ credits and/or reset the machine if the machine is knocked excessively hard
+ or moved. Most commonly found on pinball machines.
+**-** *(not numeric keypad)*
+ Volume Down
+
+ For machines that have an electronic volume control.
+**=** *(not numeric keypad)*
+ Volume Up
+
+ For machines that have an electronic volume control.
+**F1**
+ Memory Reset
+
+ This resets high scores, credits/winnings, statistics, and/or operator
+ settings on machines that support it.
+**F2**
+ Service Mode
+
+ This is a momentary push-button on some machines, while it is a toggle
+ switch or DIP switch on others.
+**9** *(not numeric keypad)*
+ Service 1
+
+ Service buttons are typically used to give free credits or to navigate the
+ operator service menus.
+**0** *(not numeric keypad)*
Service 2
-**-** (not numeric keypad)
+**-** *(not numeric keypad)*
Service 3
-**=** (not numeric keypad)
+**=** *(not numeric keypad)*
Service 4
+
+
+.. _default-game-keys:
+
+Default Arcade Game Controls
+----------------------------
+
+This section covers controls for arcade games using common joystick/button
+control schemes. All the controls below are fully configurable in the user
+interface. This list shows the standard keyboard configuration.
+
+**5** *(not numeric keypad)*
+ Coin slot 1
+**6** *(not numeric keypad)*
+ Coin slot 2
+**7** *(not numeric keypad)*
+ Coin slot 3
+**8** *(not numeric keypad)*
+ Coin slot 4
+**1** *(not numeric keypad)*
+ Player 1 start or 1 player mode
+**2** *(not numeric keypad)*
+ Player 2 start or 2 players mode
+**3** *(not numeric keypad)*
+ Player 3 start or 3 players mode
+**4** *(not numeric keypad)*
+ Player 4 start or 4 players mode
+
+
+.. _default-player1-keys:
+
+Player 1 Controls
+~~~~~~~~~~~~~~~~~
+
**Up Arrow**
Player 1 Up
**Down Arrow**
@@ -253,28 +307,28 @@ shows the standard keyboard configuration.
**Right Arrow**
Player 1 Right
**E**
- Up on Left Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Up on Left Stick for dual-stick machines (e.g. Robotron)
**D**
- Down on Left Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Down on Left Stick for dual-stick machines (e.g. Robotron)
**S**
- Left on Left Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Left on Left Stick for dual-stick machines (e.g. Robotron)
**F**
- Right on Left Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Right on Left Stick for dual-stick machines (e.g. Robotron)
**I**
- Up on Right Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Up on Right Stick for dual-stick machines (e.g. Robotron)
**K**
- Down on Right Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Down on Right Stick for dual-stick machines (e.g. Robotron)
**J**
- Left on Right Stick for dual-stick machines (e.g. Robotron)
+ Player 1 Left on Right Stick for dual-stick machines (e.g. Robotron)
**L**
- Right on Right Stick for dual-stick machines (e.g. Robotron)
-**Ctrl**/**Mouse B0**/**Gun 1 Button 0**
+ Player 1 Right on Right Stick for dual-stick machines (e.g. Robotron)
+**Left Ctrl**/**Mouse B0**/**Gun 1 Button 0**
Player 1 Button 1
-**Alt**/**Mouse B2**/**Gun 1 Button 1**
+**Left Alt**/**Mouse B2**/**Gun 1 Button 1**
Player 1 Button 2
**Spacebar**/**Mouse B1**/**Joystick 1 Button 1 or B**
Player 1 Button 3
-**Shift**
+**Left Shift**
Player 1 Button 4
**Z**
Player 1 Button 5
@@ -298,42 +352,118 @@ shows the standard keyboard configuration.
Player 1 Button 14
**Right Shift**
Player 1 Button 15
-**9**
- Service
-**0**
- Book-Keeping
+
+
+.. _default-player2-keys:
+
+Player 2 Controls
+~~~~~~~~~~~~~~~~~
+
+**R**
+ Player 2 Up
+**F**
+ Player 2 Down
+**D**
+ Player 2 Left
+**G**
+ Player 2 Right
+**A**
+ Player 2 Button 1
+**S**
+ Player 2 Button 2
+**Q**
+ Player 2 Button 3
+**W**
+ Player 2 Button 4
+**E**
+ Player 2 Button 5
+
+
+.. _default-player3-keys:
+
+Player 3 Controls
+~~~~~~~~~~~~~~~~~
+
+**I**
+ Player 3 Up
+**K**
+ Player 3 Down
+**J**
+ Player 3 Left
+**L**
+ Player 3 Right
+**Right Control**
+ Player 3 Button 1
+**Right Shift**
+ Player 3 Button 2
+**Enter** *(not numeric keypad)*
+ Player 3 Button 3
+
+
+.. _default-player4-keys:
+
+Player 4 Controls
+~~~~~~~~~~~~~~~~~
+
+**8** *(on numeric keypad)*
+ Player 4 Up
+**2** *(on numeric keypad)*
+ Player 4 Down
+**4** *(on numeric keypad)*
+ Player 4 Left
+**6** *(on numeric keypad)*
+ Player 4 Right
+**0** *(on numeric keypad)*
+ Player 4 Button 1
+**.** *(on numeric keypad)*
+ Player 4 Button 2
+**Enter** *(on numeric keypad)*
+ Player 4 Button 3
.. _default-mahjong-hanafuda-keys:
Default Mahjong and Hanafuda Keys
-=================================
+---------------------------------
-All the keys below are fully configurable in the user interface. This list shows
-the standard keyboard configuration.
+Most mahjong and hanafuda games use a standard control panel layout. Some keys
+may not be present, depending on the kind of game. For example games without a
+bonus game feature may lack the Take Score, Double Up, Big and Small keys, and
+games without gambling features may also lack the Bet key. Some games may not
+use all keys that are present. For example many games do not use the Flip Flop
+and Last Chance keys.
+.. image:: images/mahjongpanel.svg
+ :width: 100%
+ :align: center
+ :alt: Standard mahjong control panel layout
-**5**
+Due to the large number of keys, MAME only provides default input configuration
+for a single set of player controls. For multi-player mahjong/hanafuda games,
+or mahjong/hanafuda games with multiple player positions, manual configuration
+is required. All the keys below are fully configurable in the user interface.
+This list shows the standard keyboard configuration.
+
+
+**5** *(not numeric keypad)*
Coin slot 1
-**6**
+**6** *(not numeric keypad)*
Coin slot 2
-**7**
+**7** *(not numeric keypad)*
Coin slot 3
-**8**
+**8** *(not numeric keypad)*
Coin slot 4
-**Backspace**
- Bill 1 (For machines that have a bill receptor/note reader)
**Y**
Player 1 Mahjong/Hanafuda Flip Flop
-**1**
+**1** *(not numeric keypad)*
Player 1 start or 1 player mode
-**2**
+**2** *(not numeric keypad)*
Player 2 start or 2 players mode
-**3**
+**3** *(not numeric keypad)*
Player 3 start or 3 players mode
Mahjong Bet
-**4**
+**4** *(not numeric keypad)*
Player 4 start or 4 players mode
**Right Ctrl**
Player 1 Mahjong/Hanafuda Take Score
@@ -393,21 +523,12 @@ the standard keyboard configuration.
Player 1 Taiwanese Mahjong P
**Q**
Player 1 Taiwanese Mahjong Q
-**9**
- Service 1 (Service buttons are typically used to give free credits or to
- navigate the internal operator service menus)
-**0**
- Service 2
-**-** (not numeric keypad)
- Service 3
-**=** (not numeric keypad)
- Service 4
.. _default-gambling-keys:
Default Gambling Keys
-=====================
+---------------------
All the keys below are fully configurable in the user interface. This list shows
the standard keyboard configuration.
@@ -435,44 +556,53 @@ buttons.
Key In
**W**
Key Out
-**9**
+**F1**
+ Memory Reset
+**9** *(not numeric keypad)*
Service 1 (Service buttons are typically used to give free credits or to
navigate the internal operator service menus)
-**0**
+**0** *(not numeric keypad)*
Service 2
Book-Keeping (for machines that have this functionality)
-**-** (not numeric keypad)
+**-** *(not numeric keypad)*
Service 3
-**=** (not numeric keypad)
+**=** *(not numeric keypad)*
Service 4
**M**
Bet
-**1**
+**1** *(not numeric keypad)*
Player 1 start or 1 player mode
-**2**
+**2** *(not numeric keypad)*
Deal
**L**
Stand
-**4**
+**4** *(not numeric keypad)*
Take Score
-**3**
+
+ For games that allow gambling winnings in a double-or-nothing bonus game,
+ this takes the winnings from the main game.
+**3** *(not numeric keypad)*
Double Up
+
+ For games that allow gambling winnings in a double-or-nothing bonus game,
+ this gambles the winnings from the main game in the bonus game.
**D**
Half Gamble
+
+ Used by games that allow gambling half or all of the winnings from the main
+ game in the bonus game.
**A**
High
**S**
Low
**O**
Door
-**0**
- Book-Keeping
.. _default-blackjack-keys:
Default Blackjack Keys
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~
All the keys below are fully configurable in the user interface. This list shows
the standard keyboard configuration.
@@ -480,8 +610,14 @@ the standard keyboard configuration.
**1**
Player 1 start or 1 player mode
+
+ Used to deal a new hand for games that have separate buttons to deal a new
+ hand and draw an additional card.
**2**
- Deal
+ Deal (hit)
+
+ Used to draw an additional card, and to deal a new hand in games that don’t
+ use separate buttons to deal a new hand and draw an additional card.
**L**
Stand
@@ -489,7 +625,7 @@ the standard keyboard configuration.
.. _default-poker-keys:
Default Poker Keys
-------------------
+~~~~~~~~~~~~~~~~~~
All the keys below are fully configurable in the user interface. This list shows
the standard keyboard configuration.
@@ -497,26 +633,34 @@ the standard keyboard configuration.
**1**
Player 1 start or 1 player mode
+
+ Used to deal a new hand for games that have separate buttons to deal a new
+ hand and draw replacement cards.
**2**
Deal
+
+ Used to draw replacement cards, and to deal a new hand in games that don’t
+ use separate buttons to deal a new hand and draw replacement cards.
**Z**
- Hold 1
+ Hold 1/discard 1
**X**
- Hold 2
+ Hold 2/discard 2
**C**
- Hold 3
+ Hold 3/discard 3
**V**
- Hold 4
+ Hold 4/discard 4
**B**
- Hold 5
+ Hold 5/discard 5
**N**
Cancel
+ Used by some games to cancel current selection for cards to hold/discard.
+
.. _default-slots-keys:
Default Slots Keys
-------------------
+~~~~~~~~~~~~~~~~~~
All the keys below are fully configurable in the user interface. This list shows
the standard keyboard configuration.
@@ -539,13 +683,13 @@ the standard keyboard configuration.
.. _default-computer-keys:
Default Computer Keys
-=====================
+---------------------
All the keys below are fully configurable in the user interface. This list shows
the standard keyboard configuration.
Note that controls can vary widely by computer type, so not all keys are shown
-here. See the "Input (this Machine)" section of MAME's configuration menu for
+here. See the “Input (this Machine)†section of MAME’s configuration menu for
details for the machine you are currently using.
@@ -554,7 +698,7 @@ details for the machine you are currently using.
**Scroll Lock**/**Forward Delete** (Mac Desktop)/**fn-Delete** (Mac Laptop)
Default mapping for the **uimodekey**.
- This key toggles MAME's response to user interface keys such as the
+ This key toggles MAME’s response to user interface keys such as the
(by default) **Tab** key being used for menus. All emulated machines
which require emulated keyboards will start with UI controls disabled by
default and you can only access the internal UI by first hitting this
@@ -575,12 +719,11 @@ details for the machine you are currently using.
.. _default-othermachine-keys:
Other Machines
-==============
+--------------
All the keys are fully configurable in the user interface.
Note that controls can vary widely by machine type, so default keys are not
shown here and defaults will vary considerably based on the manufacturer and
-style. See the "Input (this Machine)" section of MAME's configuration menu for
+style. See the “Input (this Machine)†section of MAME’s configuration menu for
details for the machine you are currently using.
-
diff --git a/docs/source/usingmame/images/mahjongpanel.svg b/docs/source/usingmame/images/mahjongpanel.svg
new file mode 100644
index 00000000000..963ca2e0be0
--- /dev/null
+++ b/docs/source/usingmame/images/mahjongpanel.svg
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg-mahjong"
+ version="1.1"
+ viewBox="0 0 1136 176"
+ height="176"
+ width="1136">
+ <g id="buttons" stroke="none">
+ <rect y="0" x="0" height="64" width="64" id="button-a" fill="#cccccc" />
+ <rect y="0" x="80" height="64" width="64" id="button-b" fill="#cccccc" />
+ <rect y="0" x="160" height="64" width="64" id="button-c" fill="#cccccc" />
+ <rect y="0" x="240" height="64" width="64" id="button-d" fill="#cccccc" />
+ <rect y="0" x="320" height="64" width="64" id="button-e" fill="#cccccc" />
+ <rect y="0" x="400" height="64" width="64" id="button-f" fill="#cccccc" />
+ <rect y="0" x="480" height="64" width="64" id="button-g" fill="#cccccc" />
+ <rect y="0" x="560" height="64" width="64" id="button-h" fill="#cccccc" />
+ <rect y="0" x="640" height="64" width="64" id="button-i" fill="#cccccc" />
+ <rect y="0" x="720" height="64" width="64" id="button-j" fill="#cccccc" />
+ <rect y="0" x="800" height="64" width="64" id="button-k" fill="#cccccc" />
+ <rect y="0" x="880" height="64" width="64" id="button-l" fill="#cccccc" />
+ <rect y="0" x="960" height="64" width="64" id="button-m" fill="#cccccc" />
+ <rect y="0" x="1072" height="64" width="64" id="button-n" fill="#ff3333" />
+ <rect y="112" x="0" height="64" width="64" id="button-flipflop" fill="#ffff33" />
+ <rect y="112" x="80" height="64" width="64" id="button-start" fill="#ffff33" />
+ <rect y="112" x="160" height="64" width="64" id="button-bet" fill="#ffff33" />
+ <rect y="112" x="280" height="64" width="64" id="button-take" fill="#ff66cc" />
+ <rect y="112" x="360" height="64" width="64" id="button-dup" fill="#ff66cc" />
+ <rect y="112" x="440" height="64" width="64" id="button-big" fill="#ff66cc" />
+ <rect y="112" x="520" height="64" width="64" id="button-small" fill="#ff66cc" />
+ <rect y="112" x="640" height="64" width="64" id="button-last" fill="#33ff99" />
+ <rect y="112" x="720" height="64" width="64" id="button-kan" fill="#33ff99" />
+ <rect y="112" x="800" height="64" width="64" id="button-pon" fill="#33ff99" />
+ <rect y="112" x="880" height="64" width="64" id="button-chi" fill="#33ff99" />
+ <rect y="112" x="960" height="64" width="64" id="button-reach" fill="#33ff99" />
+ <rect y="112" x="1072" height="64" width="64" id="button-ron" fill="#ff9933" />
+ </g>
+ <g id="labels"
+ font-family="sans-serif" font-style="normal" font-variant="normal" font-weight="bold" font-stretch="normal"
+ text-anchor="middle"
+ fill="#000000" stroke="none"
+ style="text-align:center;line-height:1.25;letter-spacing:0px;word-spacing:0px">
+ <text id="label-a"
+ y="47.5104" x="32"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="32"
+ id="tspan-a0">A</tspan></text>
+ <text id="label-b"
+ y="47.5104" x="112"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="112"
+ id="tspan-b0">B</tspan></text>
+ <text id="label-c"
+ y="47.5104" x="192"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="192"
+ id="tspan-c0">C</tspan></text>
+ <text id="label-d"
+ y="47.5104" x="272"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="272"
+ id="tspan-d0">D</tspan></text>
+ <text id="label-e"
+ y="47.5104" x="352"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="352"
+ id="tspan-e0">E</tspan></text>
+ <text id="label-f"
+ y="47.5104" x="432"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="432"
+ id="tspan-f0">F</tspan></text>
+ <text id="label-g"
+ y="47.5104" x="512"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="512"
+ id="tspan-g0">G</tspan></text>
+ <text id="label-h"
+ y="47.5104" x="592"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="592"
+ id="tspan-h0">H</tspan></text>
+ <text id="label-i"
+ y="47.5104" x="672"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="672"
+ id="tspan-i0">I</tspan></text>
+ <text id="label-j"
+ y="47.5104" x="752"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="752"
+ id="tspan-j0">J</tspan></text>
+ <text id="label-k"
+ y="47.5104" x="832"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="832"
+ id="tspan-k0">K</tspan></text>
+ <text id="label-l"
+ y="47.5104" x="912"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="912"
+ id="tspan-l0">L</tspan></text>
+ <text id="label-m"
+ y="47.5104" x="992"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="992"
+ id="tspan-m0">M</tspan></text>
+ <text id="label-n"
+ y="47.5104" x="1104"
+ style="font-size:42.66666794px"
+ xml:space="preserve"><tspan
+ y="47.5104" x="1104"
+ id="tspan-n0">N</tspan></text>
+ <text id="label-flipflop"
+ y="140.4128" x="32"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="140.4128" x="32"
+ id="tspan-flipflop0">FLIP</tspan><tspan
+ y="157.17379" x="32"
+ id="tspan-flipflop1">FLOP</tspan></text>
+ <text id="label-start"
+ y="148.84703" x="112"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="112"
+ id="tspan-start0">START</tspan></text>
+ <text id="label-bet"
+ y="148.84703" x="192"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="192"
+ id="tspan-bet0">BET</tspan></text>
+ <text id="label-take"
+ y="140.4128" x="312"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="140.4128" x="312"
+ id="tspan-take0">TAKE</tspan><tspan
+ y="157.17379" x="312"
+ id="tspan-take1">SCORE</tspan></text>
+ <text id="label-dup"
+ y="140.4128" x="392"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="140.4128" x="392"
+ id="tspan-dup0">DOUBLE</tspan><tspan
+ y="157.17379" x="392"
+ id="tspan-dup1">UP</tspan></text>
+ <text id="label-big"
+ y="148.84703" x="472"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="472"
+ id="tspan-big0">BIG</tspan></text>
+ <text id="label-small"
+ y="148.84703" x="552"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="552"
+ id="tspan-small0">SMALL</tspan></text>
+ <text id="label-last"
+ y="140.4128" x="672"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="140.4128" x="672"
+ id="tspan-last0">LAST</tspan><tspan
+ y="157.17379" x="672"
+ id="tspan-last1">CHANCE</tspan></text>
+ <text id="label-kan"
+ y="148.84703" x="752"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="752"
+ id="tspan-kan0">KAN</tspan></text>
+ <text id="label-pon"
+ y="148.84703" x="832"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="832"
+ id="tspan-pon0">PON</tspan></text>
+ <text id="label-chi"
+ y="148.84703" x="912"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="912"
+ id="tspan-chi0">CHI</tspan></text>
+ <text id="label-reach"
+ y="148.84703" x="992"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="992"
+ id="tspan-reach0">REACH</tspan></text>
+ <text id="label-ron"
+ y="148.84703" x="1104"
+ style="font-size:13.33333302px"
+ xml:space="preserve"><tspan
+ y="148.84703" x="1104"
+ id="tspan-ron0">RON</tspan></text>
+ </g>
+</svg>
diff --git a/hash/bbc_flop_hybrid.xml b/hash/bbc_flop_hybrid.xml
new file mode 100644
index 00000000000..8af919a58f6
--- /dev/null
+++ b/hash/bbc_flop_hybrid.xml
@@ -0,0 +1,1107 @@
+<?xml version="1.0"?>
+<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
+<!--
+license:CC0
+-->
+
+<softwarelist name="bbc_flop_hybrid" description="Hybrid Music System discs">
+
+ <!-- Music 500 -->
+
+ <software name="m500">
+ <description>Music 500</description>
+ <year>1984</year>
+ <publisher>Acorn Computers</publisher>
+ <sharedfeat name="compatibility" value="M500"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="204800">
+ <rom name="Music 500_Issue Disc.ssd" size="204800" crc="7ebc0c92" sha1="fba88e59c392c99bf18047693e09a0035808ccb8"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <!-- Hybrid Music System -->
+
+ <software name="symphony">
+ <description>ATPL Symphony</description>
+ <year>1985</year>
+ <publisher>ATPL</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="ATPL Symphony.ssd" size="204800" crc="478b6622" sha1="687f02f33dcfc9b8cc83b528dc8054843212fa9e"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="studio2">
+ <description>Studio-2</description>
+ <year>198?</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Studio-2_Issue Disc.ssd" size="102400" crc="2aac288c" sha1="95bb0d572cd12b58d6d69647afb20440e40cfe23"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="studio3">
+ <description>Studio-3</description>
+ <year>1989</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Studio-3_Issue Disc.ssd" size="102400" crc="77441449" sha1="b7eb939318a9d2e0c8f3db819c204ff7eb85f91e"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="studio5">
+ <description>Studio 5000</description>
+ <year>1986</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="System Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Studio 5000_System Disc.ssd" size="102400" crc="0bdd6707" sha1="893800a49313a696feb669287f53f4e37a8b2d58"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Studio 5000_Issue Disc.ssd" size="102400" crc="00f3d6fc" sha1="8ee44104c35e3d16321c407d5e51e010ac2b9d42"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="studio54b">
+ <description>Studio 5000-4B</description>
+ <year>1989</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Studio 5000-4B_Issue Disc.ssd" size="102400" crc="a4dec092" sha1="1f4120a501c1d14b2ca71e14eca1e8598242deaf"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sndspace">
+ <description>Sound Worlds 1: Soundspace</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundspace_Issue Disc.ssd" size="102400" crc="0faf6be1" sha1="5f11edae0772f751faa3806ff8d219b9c5c2a35b"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sndscape">
+ <description>Sound Worlds 2: Soundscape</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundscape_Issue Disc.ssd" size="102400" crc="0d3786bb" sha1="32d249ed0fca84beba7edd2ea3ebda861c24387c"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sndscore">
+ <description>Sound Worlds 4: Soundscore</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="System Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundscore_System Disc.ssd" size="102400" crc="b92d6d86" sha1="2da57d27a2e13c34c842fdc7904390bdfa1044f6"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundscore_Issue Disc.ssd" size="102400" crc="aa1c45c9" sha1="489fe48d7ee0c6873d5917405c30f93c2f227e8c"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sndshow">
+ <description>Soundshow</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundshow_Issue Disc.ssd" size="102400" crc="183b9d50" sha1="3fab8852238c9989eb6577dbe59ea8516accd246"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sndstage" supported="no">
+ <description>Soundstage</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="System Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundstage_System Disc.ssd" size="102400" crc="daca75ba" sha1="907782390724bb857f2c36810eb5d92f59539bc2"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundstage_Issue Disc.ssd" size="102400" crc="e6ac0807" sha1="1e8cb3028d5f4b7ca21b75f3564b9f7819916e32"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sndstory">
+ <description>Soundstory</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="System Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundstory_System Disc.ssd" size="102400" crc="ebb12cc1" sha1="a6743dae72e7784308fbbda198eb24e05e0ba621"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Soundstory_Issue Disc.ssd" size="102400" crc="eb123c50" sha1="48ec24b85b9f980b68e8b79f147de226bb9c77e1"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="toolbox">
+ <description>AMPLE Toolbox</description>
+ <year>1989</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="Issue Disc"/>
+ <dataarea name="flop" size="102400">
+ <rom name="AMPLE Toolbox_Issue Disc.ssd" size="102400" crc="c2f60e00" sha1="2b6cd885ecddd8ca86c6f590ccca738549533d39"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="wavedsgn">
+ <description>Wave Designer</description>
+ <year>1988</year>
+ <publisher>SoundSculptures</publisher>
+ <info name="author" value="Jonty Stockdale" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="75520">
+ <rom name="Wave Designer.1.ssd" size="75520" crc="3db5b981" sha1="c88c9c068685cbfd30bd51ced7770df8e4c61aeb"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="91136">
+ <rom name="Wave Designer.2.ssd" size="91136" crc="55ee886b" sha1="ac40a3a1547a4c7d33aaa7e1d56e8207bd001103"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <!-- Music 87 -->
+
+ <software name="music87">
+ <description>Music 87 Software</description>
+ <year>1987</year>
+ <publisher>Peartree Computers</publisher>
+ <sharedfeat name="compatibility" value="M87"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="348928">
+ <rom name="Music87.dsd" size="348928" crc="f19f40ea" sha1="8f1a7f22ab4d1db57b074581a61134e227c94e44"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <!-- AMPLE Albums -->
+
+ <software name="ampbyte1" cloneof="ampbyte2">
+ <description>AMPLE Bytes Back R1</description>
+ <year>1987</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="David Reed" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="101376">
+ <rom name="Ample Bytes Back_R1.ssd" size="101376" crc="e6b09eb5" sha1="b02e31d12e2e80c93618c81b0f4127af6bc088f6"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampbyte2">
+ <description>AMPLE Bytes Back R2</description>
+ <year>1987</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="David Reed" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="102400">
+ <rom name="Ample Bytes Back_R2.ssd" size="102400" crc="1605f2c6" sha1="c855f61d75744b37fa1c0c3d80b926a8a9fc4c28"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampvibr">
+ <description>AMPLE Vibrations</description>
+ <year>1988</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="David Reed" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="115200">
+ <rom name="Ample Vibrations.ssd" size="115200" crc="013366cc" sha1="fa4e854194a7347ddc2a500fe51a9b94ac22c9cb"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ashes">
+ <description>Ashes R1</description>
+ <year>1990</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Michael Harbour" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="63488">
+ <rom name="Ashes.ssd" size="63488" crc="9bd25fca" sha1="a3ed279dcb5a4c89d8d858b2372e684f03cce198"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="cosmix">
+ <description>Cosmix R2</description>
+ <year>1987</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Pilgrim Beart" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="102400">
+ <rom name="Cosmix.ssd" size="102400" crc="ac0f9030" sha1="2fde9d91680f00617e50dc7468c339827f13a4a0"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="instories">
+ <description>Inside Stories</description>
+ <year>1988</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Peter Chase" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="102400">
+ <rom name="Inside Stories.ssd" size="102400" crc="8bbb897f" sha1="455e603dcfc344d0956d8f41db71d16ea050bc87"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="homeland1" cloneof="homeland2">
+ <description>Return to the Homeland R1</description>
+ <year>1988</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Obernell" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="51712">
+ <rom name="Return to the Homeland_R1.ssd" size="51712" crc="dffa461c" sha1="de2b571ff7038cbd688b48dc7990b31eb8b97a30"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="homeland2">
+ <description>Return to the Homeland R2</description>
+ <year>1988</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Obernell" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Return to the Homeland_R2.ssd" size="204800" crc="26ed6d1d" sha1="f574fe74079fa4bcea1aa71cb373aaff0c64ce79"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="jazz1">
+ <description>Jazz Disc Vol.1</description>
+ <year>1989</year>
+ <publisher>JBSoftware</publisher>
+ <info name="author" value="John Bartlett" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="101888">
+ <rom name="Jazz Vol I.1.ssd" size="101888" crc="79b59202" sha1="019c068d64e1c6b94118c6b266878eca8bf86998"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="legendo">
+ <description>The Legend of Obernell</description>
+ <year>1990</year>
+ <publisher>Phil Comber</publisher>
+ <info name="author" value="Phil Comber" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="69888">
+ <rom name="The Legend of Obernell.ssd" size="69888" crc="2e74665b" sha1="a33fb633240352e5f8d54f2263b27708a6819c19"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcity">
+ <description>Music City R2</description>
+ <year>1987</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Ian Guinan" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="40 track"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Music City_40t.ssd" size="102400" crc="9cd9bcfc" sha1="6e958366d158dd481e68d431ec2e54bc75d6d945"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <feature name="part_id" value="80 track"/>
+ <dataarea name="flop" size="204800">
+ <rom name="Music City_80t.ssd" size="204800" crc="65621356" sha1="d1512754ef1896c64cd220761b3aa9a5bfe8865e"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcity2">
+ <description>Music City 2</description>
+ <year>1988</year>
+ <publisher>Hybrid Technology</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Music City 2.ssd" size="204800" crc="25cea818" sha1="2d078945ef8e9ac4e71fd6871a9ca4cd0248f0d0"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="notes">
+ <description>Notes</description>
+ <year>1987</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Pilgrim Beart" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="102400">
+ <rom name="Notes.ssd" size="102400" crc="a884a5c5" sha1="30efd636da421e3ae22ff093fedb972ba4025f6d"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="plaice">
+ <description>Plaice R1</description>
+ <year>1988</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Fish Shop Boys" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <feature name="part_id" value="40 track"/>
+ <dataarea name="flop" size="102400">
+ <rom name="Plaice_40t.ssd" size="102400" crc="760a6b9c" sha1="c0d12a330cf92414d66f2c42a327c1d928f4776e"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <feature name="part_id" value="80 track"/>
+ <dataarea name="flop" size="204800">
+ <rom name="Plaice_80t.ssd" size="204800" crc="101eba1e" sha1="525288de2f7a87a556faceef014709eaab6f5fb0"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="shiver">
+ <description>Shivering Again</description>
+ <year>1989</year>
+ <publisher>Hybrid Technology</publisher>
+ <info name="author" value="Michael Harbour" />
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="70656">
+ <rom name="Shivering Again.ssd" size="70656" crc="f8cba7f8" sha1="46b9708b874f6aa29168977d411ed620422bad60"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <!-- AMPLE Information Exchange -->
+
+ <software name="ampex001">
+ <description>Amplinex 001</description>
+ <year>1987</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-001.ssd" size="204800" crc="5442c90b" sha1="b52fe8e5a69cbe2a1847c22f44dd49db20489dc4"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex002">
+ <description>Amplinex 002</description>
+ <year>1987</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-002.ssd" size="204800" crc="464140c6" sha1="0e54e76ba7f8c1bf3a168dc96f01a2c3352dcd27"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex003">
+ <description>Amplinex 003</description>
+ <year>1987</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-003.ssd" size="204800" crc="ad024d8c" sha1="ebcdbbb034c2bb0b83213e7e4ab628670f9fc789"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex004">
+ <description>Amplinex 004</description>
+ <year>1988</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-004.ssd" size="204800" crc="2febe1af" sha1="55c996c15569dbbb918446618c8b595b93c626c3"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex005">
+ <description>Amplinex 005</description>
+ <year>1988</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-005.ssd" size="204800" crc="5af23e84" sha1="ea36ce0ed99a018993caf7f5e19500bf7f52a7fd"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex006">
+ <description>Amplinex 006</description>
+ <year>1988</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-006.ssd" size="204800" crc="a8649f39" sha1="20ca26c86cbc5c02541782c107cf1fe03d791b78"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampexm06">
+ <description>Amplinex M06</description>
+ <year>1988</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-M06.ssd" size="204800" crc="aa1c23ae" sha1="b67af3f59107a09e148c9477d1fe557c4793f8a3"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex007">
+ <description>Amplinex 007</description>
+ <year>1988</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-007.ssd" size="204800" crc="8118bec2" sha1="b6d59efc0859b243a4a418f52799021cc690bbbf"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex008">
+ <description>Amplinex 008</description>
+ <year>1988</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-008.ssd" size="204800" crc="afecb2b3" sha1="de0e2ee8eac1e51c96118fff77ff7f8ef68fd3fe"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex009">
+ <description>Amplinex 009</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-009.ssd" size="204800" crc="7ad77e4f" sha1="9d48c582e27af199c1a9e466734e7d1599cd148e"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampexm09">
+ <description>Amplinex M09</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-M09.ssd" size="204800" crc="b25f074f" sha1="0c956d6237340c58b3418291b43161da12fc2080"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex010">
+ <description>Amplinex 010</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-010.ssd" size="204800" crc="b0a71d20" sha1="92f1fa2a466be5fa0613c4dc5a90a1f5b77d4abd"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex011">
+ <description>Amplinex 011</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-011.ssd" size="204800" crc="40640c1a" sha1="e9d692f37f0ffa19126234389bf1716fabd6d7f9"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampexu11">
+ <description>Amplinex U11</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-U11.ssd" size="204800" crc="6d62cc85" sha1="b5886a17c759abeb593dab0df8ca64713353d21d"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex012">
+ <description>Amplinex 012</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-012.ssd" size="204800" crc="d471c2fc" sha1="8e6e093e264746da672aa14322597e2a4e8573c5"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex013">
+ <description>Amplinex 013</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-013.ssd" size="204800" crc="30159b3f" sha1="7a2d9b4b150f4fab6f1166f6c2d4e80ab4ac4134"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampexm13">
+ <description>Amplinex M13</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-M13.ssd" size="204800" crc="23d1baf5" sha1="4e69efa57abf865f30c7d52c031b4aefd6e03f41"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex014">
+ <description>Amplinex 014</description>
+ <year>1989</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-014.ssd" size="204800" crc="d8f779f3" sha1="93cbebaf2c9bde6c3ef79afaca9d13ef2f97a828"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex015">
+ <description>Amplinex 015</description>
+ <year>1990</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-015.ssd" size="204800" crc="a2edb3db" sha1="67bf2467893fa813f1d44c6b99787768d20543b8"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex016">
+ <description>Amplinex 016</description>
+ <year>1990</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-016.ssd" size="204800" crc="24f1f113" sha1="6925fd70bedc9dafb2b2fcc5270fdf732f54619a"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex017">
+ <description>Amplinex 017</description>
+ <year>1990</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-017.ssd" size="204800" crc="12ca0372" sha1="dd25bcb15abc5a8e6715b98f6b41f06dbb764c2c"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex018">
+ <description>Amplinex 018</description>
+ <year>1990</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-018.ssd" size="204800" crc="1593bd63" sha1="cf2471b5a015856e0b4032e1236d8dff7657979b"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex019">
+ <description>Amplinex 019</description>
+ <year>1990</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-019.ssd" size="204800" crc="66d5669b" sha1="3ea727c68c1d5b826b15d35b607da26aef985662"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex020">
+ <description>Amplinex 020</description>
+ <year>1990</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-020.ssd" size="204800" crc="ca57d380" sha1="63437615269eb69d5d5b3e89ac9bfde9179b2942"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex021">
+ <description>Amplinex 021</description>
+ <year>1991</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-021.ssd" size="204800" crc="b2faf87e" sha1="7ff66db52e47bb3dccb7e7a57c3ef25bc1b5f824"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex022">
+ <description>Amplinex 022</description>
+ <year>1991</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-022.ssd" size="204800" crc="f599a0f8" sha1="6c058c9724c39c8edc008083a5aab2724666b864"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex023">
+ <description>Amplinex 023</description>
+ <year>1991</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-023.ssd" size="204800" crc="62f25074" sha1="2d4ca93e3007cc42e53a0af581d3f61c0917d58b"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex024">
+ <description>Amplinex 024</description>
+ <year>1992</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-024.ssd" size="204800" crc="25890a1d" sha1="1363201ac5ecd73f276d265e6bac78e72d3eab10"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex025">
+ <description>Amplinex 025</description>
+ <year>1992</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-025.ssd" size="204800" crc="d68b7255" sha1="1059cc80b7771a48229b0494c3d3028cb1e2f1b6"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex026">
+ <description>Amplinex 026</description>
+ <year>1992</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-026.ssd" size="204800" crc="687c530e" sha1="ccf348fdd48e155f99317e1f4d3dbbbbf38f3ff8"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex027">
+ <description>Amplinex 027</description>
+ <year>1992</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-027.ssd" size="204800" crc="eacf7e84" sha1="e66992b6ecadee616fbd7a397b0a09b96c7cf2cf"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ampex028">
+ <description>Amplinex 028</description>
+ <year>1992</year>
+ <publisher>AMPLE Information Exchange</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="204800">
+ <rom name="Amplinex-028.ssd" size="204800" crc="2af0c718" sha1="2731d63af740e77bf2d08468abbca22f4ce12fa2"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <!-- Panda Discs - double sided discs, imaged as ssd -->
+
+ <software name="panda1">
+ <description>Music 5000 Volume 1: Monster Computations 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="189440">
+ <rom name="Panda1.1.ssd" size="189440" crc="11e11cbf" sha1="8b5a42bed3d65daf80f1e27b28604b816ed02167"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="189440">
+ <rom name="Panda1.2.ssd" size="189440" crc="11e11cbf" sha1="8b5a42bed3d65daf80f1e27b28604b816ed02167"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda2">
+ <description>Music 5000 Volume 2: Phil Comber 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="88320">
+ <rom name="Panda2.1.ssd" size="88320" crc="05a5209f" sha1="104bb730f31b4ce6b6b8de6fdf2a7a0964e310ae"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="87040">
+ <rom name="Panda2.2.ssd" size="87040" crc="9feb62dd" sha1="fde524edf2f586d8b750dd5b60baba7422ce3953"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda3">
+ <description>Music 5000 Volume 3: Bernie Dawson 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="108032">
+ <rom name="Panda3.1.ssd" size="108032" crc="7949b3e9" sha1="4367387712950cac58adc1341ad57c414f0d5c22"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="106752">
+ <rom name="Panda3.2.ssd" size="106752" crc="475d9ec6" sha1="4ebc837bbedc5cba0d86530fcd32c1df950140fb"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda4">
+ <description>Music 5000 Volume 4: Monster Computations 2</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="174592">
+ <rom name="Panda4.1.ssd" size="174592" crc="22487883" sha1="4296c44de669d18aaf647ea035f4b1a5181639a2"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="173312">
+ <rom name="Panda4.2.ssd" size="173312" crc="93114580" sha1="c8c9d3d05ab7387798b223e3d6ab20bb70d74292"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda5">
+ <description>Music 5000 Volume 5: Paul Nuttall 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="146432">
+ <rom name="Panda5.1.ssd" size="146432" crc="e167430d" sha1="ceaf92bc79bf3b4bffe14eb3372b56842168b924"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="145152">
+ <rom name="Panda5.2.ssd" size="145152" crc="2e336256" sha1="95bffc4575804fb66d5598661dd30c30e52aacbd"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda6">
+ <description>Music 5000 Volume 6: Andy Knight 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="103680">
+ <rom name="Panda6.1.ssd" size="103680" crc="f0b84294" sha1="d3bbdaf087150b963510b87e45e9dfb75c797e3c"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="103680">
+ <rom name="Panda6.2.ssd" size="103680" crc="2ec1cb06" sha1="d9dc29516f3457dd3bd60c611fc4dfb3ac34cac5"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda7">
+ <description>Music 5000 Volume 7: David King 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="89600">
+ <rom name="Panda7.1.ssd" size="89600" crc="7ea38d59" sha1="130e78a9cbe1005463c2e867b106b460419c6548"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="89600">
+ <rom name="Panda7.2.ssd" size="89600" crc="7ea38d59" sha1="130e78a9cbe1005463c2e867b106b460419c6548"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda8">
+ <description>Music 5000 Volume 8: Children in Need 1</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="142080">
+ <rom name="Panda8.1.ssd" size="142080" crc="74e68f92" sha1="82b70062a93586c0e38d857c9be0cbf91d77ad16"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="136192">
+ <rom name="Panda8.2.ssd" size="136192" crc="b779f450" sha1="47008246d1e7c35b47b84368cb16da1747d9bfb1"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda9">
+ <description>Music 5000 Volume 9: The Noige &quot;Echoes&quot;</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="35840">
+ <rom name="Panda9.1.ssd" size="35840" crc="e3b24094" sha1="a8ceb6b4744e80b11dabaea9708b7396e091bfe5"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="29952">
+ <rom name="Panda9.2.ssd" size="29952" crc="69d8e542" sha1="14f7f223f9e772a2f010f6291442ef7f66e29d02"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda10">
+ <description>Music 5000 Volume 10: Monster Computations 3</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="128512">
+ <rom name="Panda10.1.ssd" size="128512" crc="9558ae89" sha1="5b24793256da4b6401f6e7e7d466ed046f86af6f"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="121600">
+ <rom name="Panda10.2.ssd" size="121600" crc="42b0ee6b" sha1="75370f6a19175f5dbf3b70b811fc11a826af7158"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda11">
+ <description>Music 5000 Volume 11: Phil Comber &quot;Deux&quot;</description>
+ <year>1989</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="79616">
+ <rom name="Panda11.1.ssd" size="79616" crc="7c5a1753" sha1="70469990b5a866b224abe5a2d9b3e148a8a5974b"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="73216">
+ <rom name="Panda11.2.ssd" size="73216" crc="7fde34c7" sha1="c9a26b95269b6f8d78b8906dcc87312ad6041cd6"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda12">
+ <description>Music 5000 Volume 12: The Noige's &quot;Moments in Time&quot;</description>
+ <year>1990</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="47104">
+ <rom name="Panda12.1.ssd" size="47104" crc="87b5cfab" sha1="3aed7f4d18e20f0e0f58d80a3e45ef051bb06561"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="40192">
+ <rom name="Panda12.2.ssd" size="40192" crc="7293b909" sha1="d624bd46ba3cb51d234ab38d45d8cefda56cd28f"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda13">
+ <description>Music 5000 Volume 13: Jean-Michel Jarre</description>
+ <year>1990</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="133120">
+ <rom name="Panda13.1.ssd" size="133120" crc="0953dd04" sha1="2af0167079fca34e7629d005710493a0914b8d00"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="133120">
+ <rom name="Panda13.2.ssd" size="133120" crc="6f437ae7" sha1="f1129771a17930ec90d58b70f7956419bf2bd42b"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda14">
+ <description>Music 5000 Volume 14: Take a Bite</description>
+ <year>1990</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="78080">
+ <rom name="Panda14.1.ssd" size="78080" crc="d6e2e6c5" sha1="cb02fc219fc53f3c259f53b714aec7e47db0dc92"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="71168">
+ <rom name="Panda14.2.ssd" size="71168" crc="11c1f826" sha1="ead701713dd784222ea5c4e57adb36e16a78951e"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda15">
+ <description>Music 5000 Volume 15: Children in Need 2</description>
+ <year>1990</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="155392">
+ <rom name="Panda15.1.ssd" size="155392" crc="6bd7dfad" sha1="f6ab9e7f7a4f05e289d67b94cef4a962b91d493f"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="148480">
+ <rom name="Panda15.2.ssd" size="148480" crc="a12d4687" sha1="10d5e7f88a8a7041aa666f11cc10e9d1202d8c36"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="panda16">
+ <description>Music 5000 Volume 16: Monster Computations 4</description>
+ <year>1990</year>
+ <publisher>Panda Discs</publisher>
+ <sharedfeat name="compatibility" value="M5000"/>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="163072">
+ <rom name="Panda16.1.ssd" size="163072" crc="0234d991" sha1="cbce6316ffa9aa00dca770bf7593db4bbfd2e771"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size="156160">
+ <rom name="Panda16.2.ssd" size="156160" crc="2d4a51e0" sha1="aab03364cc94acf82faef3779090d0b9ba53e394"/>
+ </dataarea>
+ </part>
+ </software>
+
+</softwarelist>
diff --git a/hash/bbc_rom.xml b/hash/bbc_rom.xml
index e598ca5f858..fc12051e964 100644
--- a/hash/bbc_rom.xml
+++ b/hash/bbc_rom.xml
@@ -6,6 +6,18 @@ license:CC0
<softwarelist name="bbc_rom" description="Acorn BBC Micro ROMs">
+ <software name="128dfs">
+ <description>128 File DFS</description>
+ <year>1987</year>
+ <publisher>Acorn User</publisher>
+ <info name="author" value="David Lawrence"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="8192">
+ <rom name="128DFS-1.00.rom" size="8192" crc="2922e4eb" sha1="8453f0d0e5fc443597e010313363c18c14464847"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="65c02asm">
<description>65C02 Assembler 1.60</description>
<year>1987</year>
@@ -686,7 +698,7 @@ license:CC0
</part>
</software>
- <software name="adfs133">
+ <software name="adfs133" cloneof="adfs130">
<description>Acorn ADFS 1.33 (IDE)</description>
<year>2005</year>
<publisher>Acorn / J.G.Harston</publisher>
@@ -698,6 +710,55 @@ license:CC0
</part>
</software>
+ <software name="adfs32b140">
+ <description>Acorn ADFS-32B 1.40 (32016 Tube)</description>
+ <year>1984</year>
+ <publisher>Acorn</publisher>
+ <info name="usage" value="Requires Acorn 1770 FDC" />
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-ADFS-32B-1.40.rom" size="16384" crc="08051cef" sha1="e72f1d7a0e06791f8f13e34a265826f6531834ea"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="adfs32m140">
+ <description>Acorn ADFS-32M 1.40 (32016 Tube)</description>
+ <year>1986</year>
+ <publisher>Acorn</publisher>
+ <sharedfeat name="compatibility" value="M"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-ADFS-32M-1.40.rom" size="16384" crc="c5cbf548" sha1="461879b9600c52c53f2a6004364f9999fb32e9c8"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="adfs151">
+ <description>Acorn ADFS 1.51 (patched)</description>
+ <year>2002</year>
+ <publisher>Acorn / J.G.Harston</publisher>
+ <sharedfeat name="compatibility" value="M"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-ADFS-1.51.rom" size="16384" crc="fd4b64c6" sha1="d919ddfc6d92ac3303d37cb59c9778b7ddd7259b"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="adfs152">
+ <description>Acorn ADFS 1.52 (patched)</description>
+ <year>2005</year>
+ <publisher>Acorn / J.G.Harston</publisher>
+ <sharedfeat name="compatibility" value="M"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-ADFS-1.52.rom" size="16384" crc="a5445bdb" sha1="e1c237ffca1dcd3592e1305bd34b1c9e72246876"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="adfs153">
<description>Acorn ADFS 1.53 (IDE)</description>
<year>2005</year>
@@ -710,6 +771,18 @@ license:CC0
</part>
</software>
+ <software name="adfs156">
+ <description>Acorn ADFS 1.56 (patched)</description>
+ <year>2016</year>
+ <publisher>Acorn / J.G.Harston</publisher>
+ <sharedfeat name="compatibility" value="M"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-ADFS-1.56.rom" size="16384" crc="c77185a5" sha1="313ef577a2f77bd921bc41d453f35a82d77cafcd"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="adfs157">
<description>Acorn ADFS 1.57 (MMC)</description>
<year>2016</year>
@@ -1256,6 +1329,17 @@ license:CC0
</part>
</software>
+ <software name="archive">
+ <description>Archive</description>
+ <year>1985</year>
+ <publisher>Bodleysoft</publisher>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Archive.rom" size="16384" crc="ca737584" sha1="d22de12a817621ca065a48cb9b9e2ab8c993e16a"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="ariesb2022" cloneof="ariesb20">
<description>Aries-B20 2.2</description>
<year>1984</year>
@@ -2497,6 +2581,18 @@ license:CC0
</part>
</software>
+ <software name="cpn071">
+ <description>CPN 0.71</description>
+ <year>1982</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="8192">
+ <rom name="CPN-0.71.rom" size="8192" crc="fcb1bdc8" sha1="756e22f6d76eb26206765f92c78c7152944102b6"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="cprom101" cloneof="cprom">
<description>CP-ROM 1.01</description>
<year>1985</year>
@@ -2942,6 +3038,32 @@ license:CC0
</part>
</software>
+ <software name="dnfs121" cloneof="dnfs120">
+ <description>Acorn DNFS 1.21 (patched for 3.5")</description>
+ <year>1998</year>
+ <publisher>Acorn / J.G.Harston</publisher>
+ <info name="usage" value="Requires Acorn 8271 FDC" />
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-DNFS-1.21.rom" size="16384" crc="d76d57aa" sha1="40353d0737369521dbc47fe8cda2c8c0339ee7a7"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="dnfs122" cloneof="dnfs120">
+ <description>Acorn DNFS 1.22 (patched for 3.5")</description>
+ <year>2015</year>
+ <publisher>Acorn / J.G.Harston</publisher>
+ <info name="usage" value="Requires Acorn 8271 FDC" />
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Acorn-DNFS-1.22.rom" size="16384" crc="7a90f105" sha1="822c333526d08ad4582ac0360344210ce4e3f0fb"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="dfs210" cloneof="dfs226">
<description>Acorn DFS 2.10</description>
<year>1985</year>
@@ -3411,6 +3533,30 @@ license:CC0
</part>
</software>
+ <software name="dvcats">
+ <description>Digivision Cats</description>
+ <year>1986</year>
+ <publisher>Digivision</publisher>
+ <info name="usage" value="*CATS" />
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="8192">
+ <rom name="Digivision-Cats.rom" size="8192" crc="3263a193" sha1="11eaadd6c17eb8da10c233d785753ffa5d06b47c"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="dvdem1">
+ <description>Digivision Demo1</description>
+ <year>1986</year>
+ <publisher>Digivision</publisher>
+ <info name="usage" value="*DEM1" />
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="8192">
+ <rom name="Digivision-Dem1.rom" size="8192" crc="bd05b63b" sha1="afdd22d3cf7957490b32699e37432d78f984e674"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="easytalk101" cloneof="easytalk">
<description>Easy Talk 1.01</description>
<year>1984</year>
@@ -3477,6 +3623,17 @@ license:CC0
</part>
</software>
+ <software name="edword2c" cloneof="edword2">
+ <description>Edword 2.02C</description>
+ <year>1982</year>
+ <publisher>Clwyd Technics</publisher>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="Edword2-2.02C.rom" size="16384" crc="9af446ba" sha1="43af13fbc9a0aa70e6550c8946997d0d6a012bb3"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="enigma004" cloneof="enigma">
<description>Enigma Disc Imager 0.04</description>
<year>1984</year>
@@ -5345,6 +5502,90 @@ license:CC0
</part>
</software>
+ <software name="mcp041cbl">
+ <description>MCP v0.41 (CBL)</description>
+ <year>1983</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-0.41-CBL.rom" size="16384" crc="b36f07f4" sha1="bd53f09bf73357845a6f97df1ee9e5aea5cdca90"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcp120cbl">
+ <description>MCP v1.20 (CBL)</description>
+ <year>1985</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-1.20-CBL.rom" size="16384" crc="851d0879" sha1="2e54ef15692ba7dd9fcfd1ef0d660464a772b156"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcp121abl">
+ <description>MCP v1.21 (ABL)</description>
+ <year>1985</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="B"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-1.21-ABL.rom" size="16384" crc="216f1074" sha1="ec3d285f757b1b35bd0cc65155048a55cc1146ed"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcp121abw">
+ <description>MCP v1.21 (ABW)</description>
+ <year>1985</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="B+"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-1.21-ABW.rom" size="16384" crc="5e4a4a56" sha1="27172e29f1020147c7ae52111b4234ee4a22e627"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcp122abw">
+ <description>MCP v1.22 (ABW)</description>
+ <year>1986</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="B+"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-1.22-ABW.rom" size="16384" crc="7124e9a6" sha1="39cdd4367bfb2c8d6599b4a4420e6d311f8acaa9"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcp122abm">
+ <description>MCP v1.22 (ABM)</description>
+ <year>1986</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="M"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-1.22-ABM.rom" size="16384" crc="596be795" sha1="35843ace281494ab40463a69a263244d0cb0ecd6"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mcp202cbm">
+ <description>MCP v2.02 (CBM)</description>
+ <year>1987</year>
+ <publisher>Torch Computers</publisher>
+ <sharedfeat name="compatibility" value="M"/>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="MCP-2.02-CBM.rom" size="16384" crc="237bd2d0" sha1="064203ce44c764b189465fa93b71bcc6f0c66e3b"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="medmon">
<description>MedMon-B</description>
<year>1983</year>
@@ -7712,6 +7953,17 @@ license:CC0
</part>
</software>
+ <software name="sprite">
+ <description>Sprite Rom</description>
+ <year>1986</year>
+ <publisher>Acorn</publisher>
+ <part name="rom1" interface="bbc_rom">
+ <dataarea name="rom" size="16384">
+ <rom name="SpriteRom-0.6.rom" size="16384" crc="25fdd08e" sha1="cd28815bf1a0184ab3f057268258ea2312eb4622"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="spy100" cloneof="spy">
<description>SPY 1.00</description>
<year>1984</year>
@@ -8034,7 +8286,7 @@ license:CC0
<sharedfeat name="compatibility" value="B"/>
<part name="rom1" interface="bbc_rom">
<dataarea name="rom" size="16384">
- <rom name="Solidisk-DFS-2.0-Feb85.rom" size="16384" crc="1f609389" sha1="706f3de07b9f128c0e89d69d80e4e49b1ebf6b29"/>
+ <rom name="Solidisk-DFS-2.0-Jan85.rom" size="16384" crc="1f609389" sha1="706f3de07b9f128c0e89d69d80e4e49b1ebf6b29"/>
</dataarea>
</part>
</software>
diff --git a/hash/clipper_flop.xml b/hash/clipper_flop.xml
index 3b0feca7825..d01ae11f508 100644
--- a/hash/clipper_flop.xml
+++ b/hash/clipper_flop.xml
@@ -4,7 +4,7 @@
license:CC0
-->
<softwarelist name="clipper_flop" description="PDC Clipper disks">
- <software name="system">
+ <software name="system" supported="no">
<description>System</description>
<year>1984</year>
<publisher>Professional Data Computer</publisher>
diff --git a/hash/fmtowns_cd.xml b/hash/fmtowns_cd.xml
index 27befb2b6d0..9f91b8ffb6f 100644
--- a/hash/fmtowns_cd.xml
+++ b/hash/fmtowns_cd.xml
@@ -428,7 +428,6 @@ New Horizon CD Learning System 2 3-nen Tokyo Shoseki
New Horizon CD Running System 1-nen Tokyo Shoseki 1990/7 SET(CD+FD)
New Horizon CD Running System 2-nen Tokyo Shoseki 1990/7 SET(CD+FD)
New Horizon CD Running System 2-nen Tokyo Shoseki 1991/1 SET(CD+FD)
-NHK Eigo de Asobo 3 Fujitsu 1994/7 CD
NHK Hitori de Dekiru Mon! Ray 1995/3 CD
NHK Jissen Eikaiwa (Marty compatible) CRC Sougou Kenkyuusho 1993/3 CD
NHK Jissen Eikaiwa Part 2 CRC Sougou Kenkyuusho 1993/12 CD
@@ -465,7 +464,6 @@ Obaachan no Chiebukuro Gyousei
Only You: Seikimatsu Juliet-tachi Alice Soft 1996/1 CD
Orient Express Gyousei 1994/12 CD
Oryx Blue Wave: Eikou e no Kiseki Data West 1995/10 SET(CD+FD)
-Oshiete, Nouveau TDK Core 1994/3 CD
Otto Anime-kun Nihon Micom Hanbai 1990/3 CD
Palamedes Ving 1991/10 CD
Pasocon de Tanoshimu Yama to Chizu Inter Limited Logic 1995/10 CD
@@ -488,7 +486,6 @@ Pyoko-tan no Niji no Shima: Nanairo no Ninjin wo Sagase Nanken Koubou
Q2 ROM Magazine - Soukangou Disinfectant 1993/5 CD
Queen of Duellist Gaiden + Gaiden Alpha Agumix 1994/3 CD
Quiz de Let's Go! Great 1993/3 ?
-* Railroad Tycoon MicroProse Japan 1993/12 SET(CD+FD)
* Rainbow Islands Extra Ving 1992/4 CD
Rakuraku Sozai Vol. 1 Fujitsu 1995/3 CD
Reijou Monogatari Interheart 1995/4 CD
@@ -3230,11 +3227,22 @@ User/save disks that can be created from the game itself are not included.
<software name="burai2">
<!--
- Origin: Neo Kobe Collection
- <rom name="Burai Kanketsu-hen.ccd" size="3239" crc="c76b92a8" sha1="1900364eb3dd1017930c6b1a7091271bb94fbbbd"/>
- <rom name="Burai Kanketsu-hen.cue" size="594" crc="07a0beed" sha1="990f39d94dc2f9b08103d8b1174b035f400bd197"/>
- <rom name="Burai Kanketsu-hen.img" size="363736800" crc="c7df9688" sha1="e41c64943ea23e4a175805e37f458697e71ee460"/>
- <rom name="Burai Kanketsu-hen.sub" size="14846400" crc="db0444e1" sha1="961e2f66b060f5f335fe83f46a9468769915773b"/>
+ Origin: redump.org
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 01).bin" size="20815200" crc="ea057b75" sha1="79dcfd0df5dce948596360d90e298d665a9357b9"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 02).bin" size="31575600" crc="2660447e" sha1="5b6e3b2e34107244a166a3d2e095e1c5b740291c"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 03).bin" size="35828016" crc="7e5e00f3" sha1="5524d39ec94a9f8e325d2a93df302c8f5fd55cbf"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 04).bin" size="5602464" crc="535491bf" sha1="02e5d74897c8f75e21d47e50d85d2d2b706a08a5"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 05).bin" size="20998656" crc="c4208823" sha1="6bddecbfbca1ab5d810d8685133b549b942e290f"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 06).bin" size="7625184" crc="8858251d" sha1="99cc2311b4b06429709b40fe69d55163054970ad"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 07).bin" size="34374480" crc="d8e1094f" sha1="ca34a7532ddf489108fa3e087fdee6ad13dd4fd6"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 08).bin" size="14448336" crc="84d77d0d" sha1="3dd800f2f8e5f89f0314f09b170336c55e956b23"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 09).bin" size="26024880" crc="c60879cd" sha1="73c6844554e732d74e7665a6bb0a10c4bffd692a"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 10).bin" size="5362560" crc="6c67135a" sha1="24cf0549ad8185836cfd6d400a33a2bdbd0502d8"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 11).bin" size="35037744" crc="5a3ce2e7" sha1="1d0fdfe849bc43c2deeafd3a99c025cd9c851918"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 12).bin" size="13547520" crc="cc8e5d41" sha1="09b6b81ba5736f06d5dcaf0a6a7df25a398e08ad"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 13).bin" size="12983040" crc="ba5323af" sha1="5b468cc5a0a3e5ec174bb51909e11b5b3f668ed1"/>
+ <rom name="Burai - Kanketsu-hen (Japan) (Track 14).bin" size="99513120" crc="92253ae8" sha1="c39de65f227806e1af08433fc2d2e8abe7c72c25"/>
+ <rom name="Burai - Kanketsu-hen (Japan).cue" size="1704" crc="e32613d6" sha1="ffd0f4410f9022329035047741fb3a4bf8bcb395"/>
-->
<description>Burai Kanketsu-hen</description>
<year>1991</year>
@@ -3245,7 +3253,7 @@ User/save disks that can be created from the game itself are not included.
<info name="usage" value="Requires 2 MB RAM"/>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
- <disk name="burai kanketsu-hen" sha1="acf9f3c856ef1398805509352b4e6e2f53f61b47" />
+ <disk name="burai - kanketsu-hen (japan)" sha1="d41e001618a596877865e03a401ae53577dfa89b" />
</diskarea>
</part>
</software>
@@ -8284,11 +8292,22 @@ User/save disks that can be created from the game itself are not included.
<software name="jealousy">
<!--
- Origin: Neo Kobe Collection
- <rom name="Jealousy.ccd" size="3239" crc="1394fcc5" sha1="36c10240660297f0a314b003fc6ece54513bf193"/>
- <rom name="Jealousy.cue" size="584" crc="924c2fdb" sha1="29b3e09e4e63ec68ebb36a3dab80d12333b48f61"/>
- <rom name="Jealousy.img" size="624989904" crc="692d5787" sha1="944a314004dad7bd994ea36326566fd67af3ee11"/>
- <rom name="Jealousy.sub" size="25509792" crc="3539ea8c" sha1="ca7d7248f35a62d616f33fa834c839162b1cf00d"/>
+ Origin: redump.org
+ <rom name="Jealousy (Japan) (Track 01).bin" size="5647152" crc="9fd37d6c" sha1="34322ecc55265556bfb0d6448c61060548ec5636"/>
+ <rom name="Jealousy (Japan) (Track 02).bin" size="55034448" crc="95888189" sha1="7a042b195943f0ebfc49268d8597fc1bad47ba27"/>
+ <rom name="Jealousy (Japan) (Track 03).bin" size="56271600" crc="fc8086f2" sha1="27d4da7649b4c3f52ad19fdb36cfa526210b784f"/>
+ <rom name="Jealousy (Japan) (Track 04).bin" size="42161952" crc="331b4903" sha1="e289d3efe0116595103dcd94649c4406a4ebf881"/>
+ <rom name="Jealousy (Japan) (Track 05).bin" size="47980800" crc="0fc8d7f7" sha1="1eec94e57b51e8b56ec69781247784e9c7275373"/>
+ <rom name="Jealousy (Japan) (Track 06).bin" size="42338352" crc="0e8b205c" sha1="2f16ebe683b2976b4a7dfb1550c2057eab30c13a"/>
+ <rom name="Jealousy (Japan) (Track 07).bin" size="41630400" crc="3fdf60ce" sha1="4edc22000a6bd236a7690e31d016a806e4a7a2cd"/>
+ <rom name="Jealousy (Japan) (Track 08).bin" size="46746000" crc="1a57bfec" sha1="12cba803fcc1fa0795ec4285a631d43cd27a8d48"/>
+ <rom name="Jealousy (Japan) (Track 09).bin" size="50803200" crc="44bef5ed" sha1="097f689c619e1956eee0b45893fe717b34d24a44"/>
+ <rom name="Jealousy (Japan) (Track 10).bin" size="43923600" crc="3da971b8" sha1="d1ac590d4f425f26c2d04ba45323c12283238e54"/>
+ <rom name="Jealousy (Japan) (Track 11).bin" size="47098800" crc="7331ffa3" sha1="0eb74a0a3b7f898d31a1fef8bc013e8ddaf9536c"/>
+ <rom name="Jealousy (Japan) (Track 12).bin" size="47628000" crc="20af6b89" sha1="be444f07b49786a7acd198f35e10f5a477d3d5c8"/>
+ <rom name="Jealousy (Japan) (Track 13).bin" size="40924800" crc="e0e09c11" sha1="444214048f4eca6d4090e994efd842b665db6162"/>
+ <rom name="Jealousy (Japan) (Track 14).bin" size="56800800" crc="fa934cb8" sha1="02c05d2c7e3e678241aac181ece57af8a962ca05"/>
+ <rom name="Jealousy (Japan).cue" size="1559" crc="69fea1ec" sha1="694694a8864aabfa635caa0c33512f35d3679261"/>
-->
<description>Jealousy</description>
<year>1995</year>
@@ -8298,7 +8317,7 @@ User/save disks that can be created from the game itself are not included.
<info name="usage" value="Requires 2 MB RAM"/>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
- <disk name="jealousy" sha1="49244a1e50fc4300f4ead328d4b43c8449042d53" />
+ <disk name="jealousy (japan)" sha1="1d14efa85e889f00ce444700e6d8c53327e2496d" />
</diskarea>
</part>
</software>
@@ -8611,22 +8630,30 @@ User/save disks that can be created from the game itself are not included.
<software name="kindanke">
<!--
- Origin: Neo Kobe Collection
- <rom name="Kindan no Ketsuzoku.ccd" size="2823" crc="0eb0eeae" sha1="0c2bdf0b806b1264c57468c1e0461a2f30502b88"/>
- <rom name="Kindan no Ketsuzoku.cue" size="685" crc="7ce5e0fc" sha1="bcdc1e469199b66ac6ac582a181e7b764e0ef064"/>
- <rom name="Kindan no Ketsuzoku.img" size="417186000" crc="d549a494" sha1="90c756e866553d64df3a8369bed3f3fda6b19c48"/>
- <rom name="Kindan no Ketsuzoku.sub" size="17028000" crc="41f52572" sha1="1190e57fd83e073e165caf3bec248107af4acfa0"/>
+ Origin: redump.org
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 01).bin" size="94905552" crc="49f1cb0b" sha1="25945e0786a36e3a75961fcf8d6617d1022973a3"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 02).bin" size="29275344" crc="a5d1ebf9" sha1="895a616e4698ce2587bd7baece78d0684f34e089"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 03).bin" size="32111856" crc="531e4c48" sha1="8c7ad2a7ea2ea60e6f9fec02058b581439dd7e59"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 04).bin" size="38102400" crc="8ac68a3a" sha1="6720062e60ac75c91986044cc0175dda9c833d16"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 05).bin" size="35451696" crc="a01a6374" sha1="3bb6a456b28acfac9e4c0bf6c23818a49bbc845e"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 06).bin" size="25754400" crc="1c5d69d3" sha1="941d8a3cc3cfc9be12ea3e127c10a38d65c17acc"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 07).bin" size="29282400" crc="afd11219" sha1="b5cace7f1edb06319a42cf0038979a67680a2fad"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 08).bin" size="29635200" crc="af6835ac" sha1="9a793cce40dc1c342c91c875c78c00b27cef48c2"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 09).bin" size="31573248" crc="d00a89c5" sha1="fe4ded8cd7127b3ebd902b23884c24cfc91235e5"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 10).bin" size="33516000" crc="5a761f24" sha1="fe18251170e84c2de2a40a68d0e7a2e3293903f5"/>
+ <rom name="Kindan no Ketsuzoku (Japan) (Track 11).bin" size="37577904" crc="a4ab6ec4" sha1="3cc0d6563b417e17878d48785131986cf3e93405"/>
+ <rom name="Kindan no Ketsuzoku (Japan).cue" size="1347" crc="158404c5" sha1="29c2409c2293cb1b80029fe3f189c2b77fa2683c"/>
-->
<description>Kindan no Ketsuzoku</description>
<year>1993</year>
<publisher>シーズウェア (C's Ware)</publisher>
- <info name="serial" value="HMF-155"/>
+ <info name="serial" value="HMF-155 / 2TD-3014"/>
<info name="alt_title" value="ç¦æ–­ã®è¡€æ—" />
<info name="release" value="199407xx" />
<info name="usage" value="Requires 2 MB RAM"/>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
- <disk name="kindan no ketsuzoku" sha1="589dfff7b733335530a19f3a88a7cdda91826187" />
+ <disk name="kindan no ketsuzoku (japan)" sha1="8fdb182fe5904dcad4d0911938372d7d1b022d71" />
</diskarea>
</part>
</software>
@@ -9339,15 +9366,41 @@ User/save disks that can be created from the game itself are not included.
<software name="ldawn2">
<!--
- Origin: Neo Kobe Collection
- <rom name="Lunatic Dawn II.ccd" size="5024" crc="130c27c9" sha1="fd9885d981912596999bca682dd5587c513bcd0f"/>
- <rom name="Lunatic Dawn II.cue" size="1825" crc="8299d5e4" sha1="17a86c05a6b28a2590e4b96161329e0e59df4fd3"/>
- <rom name="Lunatic Dawn II.img" size="511261296" crc="2db8badd" sha1="7a37ffa772f1ade9ab56ef6c808a96afe9e90084"/>
- <rom name="Lunatic Dawn II.sub" size="20867808" crc="d1986582" sha1="d4f119946fb61aa6211ced6c818b112f089595b9"/>
+ Origin: redump.org
+ <rom name="Lunatic Dawn II (Japan) (Track 01).bin" size="34804896" crc="d8a381b6" sha1="8b2e9368841838771522936806d49feb9758d647"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 02).bin" size="18874800" crc="9756b934" sha1="e9899618e7b57aacbc51b988c2adfb66c9863ae2"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 03).bin" size="17816400" crc="3d83a9e5" sha1="645674ed51e5b98dbffb7febea3105e829e5f6e9"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 04).bin" size="18698400" crc="37e94fb7" sha1="56e81b915ba7af734bd29e938e666c27581ae6a1"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 05).bin" size="18522000" crc="9cb6f5dd" sha1="a22858b38b8486dff0c0aa1f3617d76ccd05425d"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 06).bin" size="21344400" crc="92248220" sha1="13472ef8ba66306925fbf94f214a365ba654572b"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 07).bin" size="17287200" crc="328a51da" sha1="6a5400fc7eafa96acd65325f62299735b22606a4"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 08).bin" size="18169200" crc="c43745fb" sha1="92bbffb0625afc40d9cc0583647c6f2cfc1ec9db"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 09).bin" size="19227600" crc="e3a5059e" sha1="45df6ae72c986045b29f6c740435771a292ef873"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 10).bin" size="16228800" crc="1146dbde" sha1="803423f586e2a5ff506206f0a4b04da8d3eb1353"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 11).bin" size="16405200" crc="b942fcae" sha1="5ccfc7fbf24312333ed94434a2e4758521f3ec0d"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 12).bin" size="24519600" crc="ac16fec2" sha1="42017dedbaa61c61472927799aabef59101d0585"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 13).bin" size="17287200" crc="c2ddfb5b" sha1="b6b692a2f2094949c8ada311bca1962f87ed31f9"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 14).bin" size="18169200" crc="f42f48f4" sha1="e421a0dd3c4bbc7506c03fac274aaf0bd1374566"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 15).bin" size="17640000" crc="11e2b513" sha1="52c010ad0a5870d84eae492c20c37b2f1e046104"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 16).bin" size="16052400" crc="3382879c" sha1="702536ce0033abdd70b2076d255046be15349aa8"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 17).bin" size="17992800" crc="8d37fbee" sha1="78c65d8a0ba4131de5608dbbd33762fe9989d231"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 18).bin" size="19580400" crc="c90d9908" sha1="2df0514e2cbecbd18a109a2cffa233f7698ee8dc"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 19).bin" size="16758000" crc="ccb92882" sha1="a1f17e75e31e2878626e6e7add17d550b05f13fd"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 20).bin" size="20462400" crc="07103a41" sha1="82d10db23cf216a1563e816ef8e8b51b5edd6bdc"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 21).bin" size="18874800" crc="2db64611" sha1="6ade4fb802781b9cfbaee91742b92a1d9ea7f0ef"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 22).bin" size="18698400" crc="3512737f" sha1="47cfde4f993db629f84abdbbffc765e32fb7bbc4"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 23).bin" size="7232400" crc="189970bd" sha1="b2ae6767c4daa6a038aad00f5124bfa179ff57d2"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 24).bin" size="1587600" crc="468ff234" sha1="cc3c5ea21d4934f4f3333bf0139a3a417d4ab459"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 25).bin" size="2646000" crc="7cab1b3d" sha1="6a6d69b4de5bd803e0d5691793c93498df026f81"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 26).bin" size="25578000" crc="b14b037f" sha1="e874d032a28b117ece7e659bb6aa091705f86d2a"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 27).bin" size="32986800" crc="9692d42d" sha1="8e8e021d1477503444f8d4dd5352d0b9483e41d1"/>
+ <rom name="Lunatic Dawn II (Japan) (Track 28).bin" size="17816400" crc="77776d02" sha1="cd97d4e9f800e77d23afa71a5a9751f3ab9da257"/>
+ <rom name="Lunatic Dawn II (Japan).cue" size="3286" crc="83fd48b7" sha1="52d19495efbb51ac5ff6fc4cb36c4f444ca21d20"/>
-->
<description>Lunatic Dawn II</description>
<year>1994</year>
<publisher>アートディンク (Artdink)</publisher>
+ <info name="serial" value="MTC-1107"/>
<info name="alt_title" value="ルナティックドーンII" />
<info name="release" value="199411xx" />
<info name="usage" value="Requires 4 MB RAM"/>
@@ -9359,7 +9412,7 @@ User/save disks that can be created from the game itself are not included.
</part>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
- <disk name="lunatic dawn ii" sha1="2e724da365c6d53e2d94f8bfb1e348a2f5b709d4" />
+ <disk name="lunatic dawn ii (japan)" sha1="923edaf8b0d1ea49eb7d8f58030502867b092b0c" />
</diskarea>
</part>
</software>
@@ -9614,8 +9667,7 @@ User/save disks that can be created from the game itself are not included.
</part>
</software>
- <!-- Missing a floppy disk? -->
- <software name="lipsadv3" supported="no">
+ <software name="lipsadv3">
<!--
Origin: redump.org
<rom name="Lip 3 - Lipstick Adventure 3 (Japan) (Track 01).bin" size="52567200" crc="7462e0c3" sha1="48900be15c74d4099e25710dcd5e6f26123c1d7f"/>
@@ -9638,6 +9690,15 @@ User/save disks that can be created from the game itself are not included.
<info name="serial" value="HME-221"/>
<info name="release" value="199305xx" />
<info name="usage" value="Requires 2 MB RAM"/>
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size="1261568">
+ <!--
+ This image has been reconstructed manually by creating empty files with the names that the game expects and re-initializing them with the in-game option.
+ It's enough to make the game work, but it should be replaced with an actual dump of the original disk.
+ -->
+ <rom name="lip3_userdisk.hdm" size="1261568" crc="d1ea991e" sha1="da73198e178d90871b0b8e90f5b0ee8bc2a9c5eb" offset="000000" status="baddump" />
+ </dataarea>
+ </part>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
<disk name="lip 3 - lipstick adventure 3 (japan)" sha1="c0507c340b55c1fa08a8080e0fc3d53d271f6a1e" />
@@ -11274,11 +11335,29 @@ User/save disks that can be created from the game itself are not included.
<software name="necronom">
<!--
- Origin: Neo Kobe Collection
- <rom name="Necronomicon.ccd" size="4583" crc="42a633fc" sha1="4edd1de4cfeb80cef936189ce6f14d2a9badfb6a"/>
- <rom name="Necronomicon.cue" size="868" crc="16626f66" sha1="a947af7d9e13bccc0ad74a9dac694378f847057a"/>
- <rom name="Necronomicon.img" size="661370640" crc="5de570c6" sha1="1d79fbaf3b3bb7f3cbb3d06d9a8928b5c91ecbee"/>
- <rom name="Necronomicon.sub" size="26994720" crc="b023097e" sha1="b474073d0de6a77d8d8ca4fa33886c584b16dc08"/>
+ Origin: redump.org
+ <rom name="Necronomicon (Japan) (Track 01).bin" size="41994960" crc="e69847f6" sha1="9feb6befd06ae8b8ef5db0a7456e3d55b9bdaebe"/>
+ <rom name="Necronomicon (Japan) (Track 02).bin" size="36503040" crc="65271603" sha1="e361ceab5a0d856fd8295568fd259f7a8c3e9596"/>
+ <rom name="Necronomicon (Japan) (Track 03).bin" size="35280000" crc="226713e3" sha1="8f5a855fa2ce7c95ddf94671383d5828bb672068"/>
+ <rom name="Necronomicon (Japan) (Track 04).bin" size="35632800" crc="67760d7d" sha1="5d6f2d886b209c331a7d7b8163d956a1bd048e9f"/>
+ <rom name="Necronomicon (Japan) (Track 05).bin" size="42336000" crc="0bfcd852" sha1="cc22a9f7566976a0d44345e1b83bfb1ba0433af2"/>
+ <rom name="Necronomicon (Japan) (Track 06).bin" size="26812800" crc="a9f5fccd" sha1="57995c6379842c5294c4d818f5a2641208bb0e87"/>
+ <rom name="Necronomicon (Japan) (Track 07).bin" size="35632800" crc="60cc8c91" sha1="ee7f74ec66f33dc462d76679fd58c7b957e20ce5"/>
+ <rom name="Necronomicon (Japan) (Track 08).bin" size="35456400" crc="c5ed736d" sha1="27163b06717f2a12ee4eee1f34dfa4fec23a53f3"/>
+ <rom name="Necronomicon (Japan) (Track 09).bin" size="45334800" crc="621c95dc" sha1="9f5c13183befe019cdd9612c5f5e27f98033313c"/>
+ <rom name="Necronomicon (Japan) (Track 10).bin" size="33868800" crc="273ce058" sha1="aeffbde65deff8256fda85e86464c3d0dacc1483"/>
+ <rom name="Necronomicon (Japan) (Track 11).bin" size="31752000" crc="af732c8c" sha1="6a25979a7e9deadc86b54df57a99a7df3a37ca7f"/>
+ <rom name="Necronomicon (Japan) (Track 12).bin" size="46040400" crc="c67ae671" sha1="6edf281bebb21f00d0f96c0b620498c550bf7bf0"/>
+ <rom name="Necronomicon (Japan) (Track 13).bin" size="29282400" crc="5c789854" sha1="a460a08bec2c0a1fd4b943dfda2d7c0f21316455"/>
+ <rom name="Necronomicon (Japan) (Track 14).bin" size="33516000" crc="6f93a446" sha1="958009d2a08de104462de5a29943bb212dad2db3"/>
+ <rom name="Necronomicon (Japan) (Track 15).bin" size="28929600" crc="41a47a6b" sha1="c4e057bf0eb15ddafc1791c6a848128a29a7719b"/>
+ <rom name="Necronomicon (Japan) (Track 16).bin" size="39337200" crc="4618682f" sha1="30081aa270d2cb0dbf509bde015be176fb9a27ad"/>
+ <rom name="Necronomicon (Japan) (Track 17).bin" size="35632800" crc="1ba19e3e" sha1="4d81ab67876acf2ba93f6016dc60de821233435e"/>
+ <rom name="Necronomicon (Japan) (Track 18).bin" size="34927200" crc="fbcfbc91" sha1="eaf01264849d176aab0cf80865f64c39352b5029"/>
+ <rom name="Necronomicon (Japan) (Track 19).bin" size="1234800" crc="9eae3269" sha1="ce043258165554281e3c20f84c74e89a45d8600b"/>
+ <rom name="Necronomicon (Japan) (Track 20).bin" size="10760400" crc="e3ed67da" sha1="feceacd7226f3afc97f2e51db452c4ca2d9c3a65"/>
+ <rom name="Necronomicon (Japan) (Track 21).bin" size="1105440" crc="a68cfda0" sha1="922607a261724c9694f0d322cbfade5b07f50aca"/>
+ <rom name="Necronomicon (Japan).cue" size="2397" crc="e4753387" sha1="901b5c1fdf691ebe40b28fce59ed60d2e9a90586"/>
-->
<description>Necronomicon</description>
<year>1994</year>
@@ -11289,7 +11368,7 @@ User/save disks that can be created from the game itself are not included.
<info name="usage" value="Requires 2 MB RAM"/>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
- <disk name="necronomicon" sha1="82672ceafa32c0e9975aeda8f3f578c1c204ff52" />
+ <disk name="necronomicon (japan)" sha1="c4b0233639a9021f36ebe5f43f8a4df0ed62a4e2" />
</diskarea>
</part>
</software>
@@ -11498,6 +11577,105 @@ User/save disks that can be created from the game itself are not included.
</part>
</software>
+ <software name="nhkeigo3">
+ <!--
+ Origin: redump.org
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 01).bin" size="211327200" crc="27716987" sha1="9f63a73076e70401c40c3526a9ef5647639a8f68"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 02).bin" size="8643600" crc="e7cffa1c" sha1="de355dfa38f7469b3518df1e24e419fc7b187cbb"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 03).bin" size="13935600" crc="5a45cea6" sha1="cec54cc61521e5a1b3e99d1c4bfbdee654912442"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 04).bin" size="8114400" crc="739e771a" sha1="e43a20f4473c2f1983e198d2107808dd1e685b59"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 05).bin" size="10231200" crc="6d741fc4" sha1="035adce2f48e3605cbc552e72d1932e09ebb74dc"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 06).bin" size="1411200" crc="04c5cd14" sha1="2c38a7941495aef97c997d293b995ac03d5794f2"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 07).bin" size="29988000" crc="b6cda3fd" sha1="899f3270a0a31c4e9e5d59362a4dbd22ae63a82d"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 08).bin" size="1058400" crc="99256836" sha1="3155cf298405be3bfb6c02a5c374b4e7596f04d7"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 09).bin" size="2293200" crc="b1a3c993" sha1="fecdc438cf2363f1d4fd1cfe7d1576e83d40e1d2"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 10).bin" size="4233600" crc="8a84d6d0" sha1="559622df465f88c8a200d86a0cb03ad4e68a73dc"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 11).bin" size="1058400" crc="4c0d3a4c" sha1="42eacd36ec7d4e684fa9d4cd65b05949e825e3c5"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 12).bin" size="2646000" crc="c7f27eb8" sha1="819a8fc7849bf7e660ca23d3ea6dfb9179b5d31e"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 13).bin" size="5997600" crc="fe102b64" sha1="783202f408642f06d422972f2c8793321e094c1e"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 14).bin" size="1058400" crc="b7784d58" sha1="39650659e21df8ed255fe5085659a3951a9926df"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 15).bin" size="7056000" crc="e3c60c3a" sha1="a5704f3789adfa5108f1d8d14f0c1d66c6b78a71"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 16).bin" size="2998800" crc="306ba95c" sha1="148590f9f597720f7c330e5424e692af4806f74f"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 17).bin" size="3351600" crc="eb359746" sha1="d88cbb861087c3ad3cfa3593f617c79b316dd659"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 18).bin" size="2822400" crc="4f9b3c81" sha1="5f64cfc4fbfe628b59ef7bc15478ef39c8e746af"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 19).bin" size="3528000" crc="9dba0649" sha1="ef261641af88db1113608ae9a16b1de38bcd353b"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 20).bin" size="6526800" crc="9f7a587e" sha1="07be4ec898c384f2662cd5ab490448605f88f89e"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 21).bin" size="5997600" crc="019ce5cf" sha1="c4833071e750e85560a90207855fc42a9625a7fd"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 22).bin" size="35103600" crc="f4c3e17f" sha1="56e1c01a5ab2eb60323f449726beaa7cf4720039"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 23).bin" size="6174000" crc="239c0c9f" sha1="3e56ec7fe545991ebf9fc4254d441a91d37fa280"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 24).bin" size="4762800" crc="6737405c" sha1="7e4e6978790a121a6d7f76f7cd0b858823040804"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 25).bin" size="34045200" crc="1879409c" sha1="ef35a76f40510c4bd9faa30d3f857821e69fbf46"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 26).bin" size="6174000" crc="03d4c862" sha1="bb41bd066e87a7d60fd5f991f1766f8134058fdf"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 27).bin" size="5468400" crc="9129eab1" sha1="f6d1e301f44877d0984ef7dfaa0c1bfed1b2f944"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 28).bin" size="34574400" crc="c2a2f2cc" sha1="4b892149df625abf82f0e7e916c9b14191c9142c"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 29).bin" size="4939200" crc="2c84e2af" sha1="5fc8eb0fe9f88849f27fbf97181a70cc8cdf4358"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 30).bin" size="8643600" crc="e40b012c" sha1="bf99e45ecd356a06490aa5447127547cb24aba2c"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 31).bin" size="2469600" crc="440f2354" sha1="adc4f9a3f793c17beafec1707db62e71970684d5"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 32).bin" size="3880800" crc="09852ac8" sha1="35cc855b2b5e7914d095295cfcf7e668f653320f"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 33).bin" size="2293200" crc="f3e5165b" sha1="821d9f35450cae1b2f2411f14c9eb5bab8eea1a4"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 34).bin" size="2998800" crc="88943db0" sha1="e5f0cd32c0e9cf039225d1476f5d020881e7fb9a"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 35).bin" size="2646000" crc="d0a2d0a4" sha1="ba54716bb69a0cc43fb990232d58e3a39df60514"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 36).bin" size="2998800" crc="9633a1ac" sha1="d3bc5b24a3b57d935d9a859071f7292d8d2a4a91"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 37).bin" size="1058400" crc="85a2f70e" sha1="86dea2f4118a77205465049872ce17b412597bfc"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 38).bin" size="8643600" crc="9f8e717b" sha1="0471fdb1cc6935d6fc06c33fc1e5ebf88c211ab1"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 39).bin" size="1940400" crc="c901f7d8" sha1="a6c8259e06f521ebe6ea5350ad30deb545a3dff6"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 40).bin" size="7585200" crc="a2ea6969" sha1="809694c75e5a85455d7948d6a030d15c4b8723fa"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 41).bin" size="8290800" crc="2da4f737" sha1="7ec205a13119a3c67708ac4155ec42393c4b76a2"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 42).bin" size="1764000" crc="7286ea07" sha1="aa785e6690f0884a769b59cfba25ec61e19f47c8"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 43).bin" size="2116800" crc="a23d49e5" sha1="2076e73e964f803165166101925c7369562d062a"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 44).bin" size="4762800" crc="cf23bc98" sha1="2d7957a4a005b9820dddec164f6f3e2e08533953"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 45).bin" size="1764000" crc="f73c231e" sha1="2110e44c8133c234cacdaa44a45948982110e273"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 46).bin" size="1764000" crc="0998ffc5" sha1="fb1e1cf103d07cc5abd8fa4ad73e2951b6cf98aa"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 47).bin" size="1587600" crc="d47baef6" sha1="ce125c6e5adb22ec63b2608c6a66e89b13739317"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 48).bin" size="1411200" crc="c14660e0" sha1="dcb49a777fb8d7a53b83415c5c630fe76da36eee"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 49).bin" size="1587600" crc="0ab54ee3" sha1="7b1a0562442e8a36b91004dad70c6e48c4ec77bc"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 50).bin" size="1411200" crc="672719b8" sha1="d3cdf78dbd68b8acce6219ec19fd6a13ad0dea13"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 51).bin" size="1764000" crc="f4bcd85a" sha1="db464319fb86f0658f2bac76492f4c9b3311632a"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 52).bin" size="1587600" crc="e654610c" sha1="5ac04d6097f32a142a2d3973ae1ed0bc4c8c39a5"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 53).bin" size="1411200" crc="cb253ac5" sha1="0c347c6281eae4e32506b7d0a89db9fad1bb1887"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 54).bin" size="1058400" crc="f74db355" sha1="958b6cb3ee221503c8f5aa8c273a3a7ac8822f3f"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 55).bin" size="1587600" crc="9b709665" sha1="85f95ce72527ac00b28b46dc7d8dc3d75ae5816d"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 56).bin" size="1587600" crc="f447162e" sha1="8deda8797392b8cdcb194dd5bbed3d2694e9df57"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 57).bin" size="1587600" crc="0f8dc6ca" sha1="b4441d919e97bc0718f7152825afcca6255b3407"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 58).bin" size="1234800" crc="5e8edfc6" sha1="d394b813ee6c49e6952dcaee2b36d1efb70b6e84"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 59).bin" size="1234800" crc="110f08d1" sha1="75ab76f3e3ce4ee7d38a5a33d57b627c0bed061c"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 60).bin" size="1411200" crc="4c25c381" sha1="4983835ee04356d9e2a9aea02817856c63cd7360"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 61).bin" size="1411200" crc="57d40b4d" sha1="eb1567bd6e38d26fae0819d25a4945fe704f7bd8"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 62).bin" size="8643600" crc="c0fc10af" sha1="a4027ee04dd7d90703534823e69545c34e6cbdf7"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 63).bin" size="1940400" crc="66d8f884" sha1="9526ab9f19a4afc8d66d323514e68b455a1726d7"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 64).bin" size="12171600" crc="da4b8700" sha1="d9071b3fa2a83d273fab51b9c0068570b1afea7b"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 65).bin" size="8467200" crc="7ff0c340" sha1="47459b06ebcf57910d68f123ea22677b091ef176"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 66).bin" size="3351600" crc="81a75d31" sha1="f1caa5d381e5947338f05054ae0b92cd0285371d"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 67).bin" size="1764000" crc="52c49fbc" sha1="40096acbcf48ff5186a4e2e86b88585f3feaa7e8"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 68).bin" size="7585200" crc="00e6b2f0" sha1="17e6d741774b6e0c4571ccd192ffc398721cabb8"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 69).bin" size="16758000" crc="eb82db8e" sha1="007333288c325b57a1aa24d0898714e6247a8788"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 70).bin" size="20638800" crc="69aa8628" sha1="ca52977249dd370aa7d3be16218c568b1a11e1b4"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 71).bin" size="1058400" crc="7ba298ab" sha1="5c72fc1f1ed91171bb3523c59b6361807f53ac96"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 72).bin" size="1058400" crc="6cd9582b" sha1="738afb2421360398701d768e4c7b6956f8cc3df2"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 73).bin" size="1058400" crc="27d4dabf" sha1="705e48507ca4659e781ee75a2fe76d30c4c812b1"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 74).bin" size="1411200" crc="3575badf" sha1="3305af3449b046d4ef1e5b442862ec5e525ec240"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 75).bin" size="1058400" crc="86af2499" sha1="eed83fcd059bc62e01792d581d010e57aaf1cd9c"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 76).bin" size="1058400" crc="1ad19b9b" sha1="5b4ae571d1f044ae472cdbc21134509aeabfc025"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 77).bin" size="1234800" crc="e4df5c07" sha1="968a69e5fe6777ebc61dcc3f34de09233ed0adc6"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 78).bin" size="1940400" crc="53f6c3c1" sha1="c8134d2b3a646eb99af384ce0843188a70321a9d"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 79).bin" size="1587600" crc="67d807ca" sha1="8a3d25f20b5829336665b30d6f2464da683ac21b"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan) (Track 80).bin" size="1411200" crc="240ba978" sha1="3c7595e0829aa6f6104f0e9f9a5be456e1a0bf7f"/>
+ <rom name="NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park (Japan).cue" size="12382" crc="428da735" sha1="dc0b316d01b78fd572985abf28f035e7f877de91"/>
+ -->
+ <description>NHK Eigo de Asobo Vol. 3 - Bernard no Amusement Park</description>
+ <year>1994</year>
+ <publisher>富士通 (Fujitsu)</publisher>
+ <info name="serial" value="HME-206 / A2760461"/>
+ <info name="alt_title" value="NHK英語ã§ã‚ãã¼ 3 ~ベルナールã®ã‚¢ãƒŸãƒ¥ãƒ¼ã‚ºãƒ¡ãƒ³ãƒˆãƒ‘ーク~" />
+ <info name="release" value="199407xx" />
+ <info name="usage" value="Requires 2 MB RAM"/>
+ <part name="cdrom" interface="fmt_cdrom">
+ <diskarea name="cdrom">
+ <disk name="nhk eigo de asobo vol. 3 - bernard no amusement park (japan)" sha1="9c87df4600a1e62df272fe1b61c3d923f5a551aa" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="nhkeikai">
<!--
Origin: P2P
@@ -12027,6 +12205,26 @@ User/save disks that can be created from the game itself are not included.
</part>
</software>
+ <software name="noobow">
+ <!--
+ Origin: private dump (sampson)
+ <rom name="PNB01.BIN" size="466015872" crc="e321a989" sha1="6cdb89465315cae85276e4c02d600edfe242e3dc"/>
+ <rom name="PNB01.CUE" size="6277" crc="1a5394ce" sha1="6f80d819a7f9e66fa5ff658161f466087f116477"/>
+ -->
+ <description>Oshiete Noobow</description>
+ <year>1994</year>
+ <publisher>TDKコア (TDK Core)</publisher>
+ <info name="serial" value="HMF-110 / PNB01-FR"/>
+ <info name="alt_title" value="ãŠã—ãˆã¦ ã¬ãƒ¼ã¼ãƒ¼" />
+ <info name="release" value="199403xx" />
+ <info name="usage" value="Requires 2 MB RAM"/>
+ <part name="cdrom" interface="fmt_cdrom">
+ <diskarea name="cdrom">
+ <disk name="pnb01" sha1="922f25586b84d0aea1c1630fcb439f8cbbacc275" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="nova">
<!--
Origin: redump.org
@@ -13432,8 +13630,7 @@ User/save disks that can be created from the game itself are not included.
</part>
</software>
- <!-- Missing a floppy disk -->
- <software name="railtycn" supported="no">
+ <software name="railtycn">
<!--
Origin: Neo Kobe Collection
<rom name="Railroad Tycoon.ccd" size="2223" crc="0d66b2f2" sha1="07a4e276d83d808f21f86b32a5b0dfafa26efdb9"/>
@@ -13447,6 +13644,11 @@ User/save disks that can be created from the game itself are not included.
<info name="serial" value="HME-245"/>
<info name="alt_title" value="レイルロードタイクーン" />
<info name="release" value="199312xx" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size="1261568">
+ <rom name="railroad_boot.bin" size="1261568" crc="12182b7a" sha1="00094bab0b9969524ec3694a38b1fa3cd1993d8b" offset="000000" />
+ </dataarea>
+ </part>
<part name="cdrom" interface="fmt_cdrom">
<diskarea name="cdrom">
<disk name="railroad tycoon" sha1="175a06c227bb9c61a86e808d45a976e9892155d1" />
@@ -17940,7 +18142,7 @@ User/save disks that can be created from the game itself are not included.
<rom name="Z's Triphony DigitalCraft Towns (Japan) (Rev A).bin" size="20815200" crc="0b236cbb" sha1="c11d402af69cb6faac8b9d2e5562ccf14e13b35f"/>
<rom name="Z's Triphony DigitalCraft Towns (Japan) (Rev A).cue" size="113" crc="c6698b0f" sha1="a74c7c4911991ea4adff4748eeb225f1bf20cd36"/>
-->
- <description>Z's Triphony DigitalCraft Towns</description>
+ <description>Z's Triphony DigitalCraft Towns (HMB-212A)</description>
<year>1990</year>
<publisher>ツァイト (Zeit)</publisher>
<info name="serial" value="HMB-212A"/>
@@ -17953,6 +18155,25 @@ User/save disks that can be created from the game itself are not included.
</part>
</software>
+ <software name="ztdco" cloneof="ztdc">
+ <!--
+ Origin: redump.org
+ <rom name="Z's Triphony DigitalCraft Towns (Japan).bin" size="14460096" crc="fcb85250" sha1="3fe11ba7d1488b31883044eb72fe43eabddfe104"/>
+ <rom name="Z's Triphony DigitalCraft Towns (Japan).cue" size="105" crc="e9d3d283" sha1="dbea85f233b8e2e396a95f1f0e15f8acd858b19c"/>
+ -->
+ <description>Z's Triphony DigitalCraft Towns (HMB-212)</description>
+ <year>1990</year>
+ <publisher>ツァイト (Zeit)</publisher>
+ <info name="serial" value="HMB-212"/>
+ <info name="release" value="199012xx" />
+ <info name="usage" value="Requires 2 MB RAM"/>
+ <part name="cdrom" interface="fmt_cdrom">
+ <diskarea name="cdrom">
+ <disk name="z's triphony digitalcraft towns (japan)" sha1="653d32f88bd032fb23a2f790f187e98f3d3c52e1" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="zak">
<!--
Origin: Neo Kobe Collection
diff --git a/hash/fmtowns_flop.xml b/hash/fmtowns_flop.xml
index 267d74caedf..01a3d774023 100644
--- a/hash/fmtowns_flop.xml
+++ b/hash/fmtowns_flop.xml
@@ -57,7 +57,6 @@ D-Return Nikkonren Kikaku
Euphony V1.1 Fujitsu 1989/7 FD
F-ISAM386 V1.1 Fujitsu 1991/3 FD
F-ISAM386 V3.1 Fujitsu 1992/11 FD
-FM Towns 386-ASM Tool Kit V1.1 Fujitsu 1989/12 FD
FM TOWNS 386-ASM Tool Kit V2.2 Fujitsu 1992/12 FD
FM Towns BSC Tejun Library V1.1 Fujitsu ? FD
FM Towns F6650 WS Library V1.1 Fujitsu 1992/5 FD
@@ -85,7 +84,6 @@ Geitassha Towns (Data Shuu) Shoubi Gakuen
Gokanshi Tensui Software 1995/7 FD
Gorby no Pipeline Daisakusen Compile 1991/4 FD
Grapharmony V1.0 Fujitsu 1992/3 FD
-Gyakutama Ou Grocer 1995/1 FD×05
Hametaoshi Tool Nikkonren Kikaku 1995/12 FD×02
Hana yori Dango Active 1992/4 FD×03
Healthy Life 2 Ryouri Data Top Business System 1993/7 FD
@@ -197,7 +195,6 @@ Sougen Towns: Nihongo Expert Shell AI Soft
Soukou Towns: Idea Processor AI Soft 1990/9 FD×29
Spell Master Junior Kakitaoshi Nikkonren Kikaku 1991/8 FD×02
Spell Master Kakitaoshi Nikkonren Kikaku 1991/8 FD×02
-Super Daisenryaku System Soft 1990/3 FD×02
Super Itekomashi Perfect Nikkonren Kikaku 1994/12 FD
Super Paso-rika Keisuke Fujitsu Ooita Software Laboratory 1993/7 FD×02
Symmetry 17 Jouhou Suuri Kenkyuusho 1992/2 FD
@@ -245,7 +242,6 @@ Towns Jouhou Kiso Select-F Tokyo Shoseki
TownsGEAR de Obenkyou Dai-1-kan: Seigo Mondai Kyouiku Soft Kenkyuusho 1992/3 FD×02
TownsGEAR de Obenkyou Dai-2-kan: Sentaku Mondai Kyouiku Soft Kenkyuusho 1992/3 FD×02
TownsGEAR de Obenkyou Dai-3-kan: Suuchi Mondai Kyouiku Soft Kenkyuusho 1992/3 FD×02
-Traffic Confusion Masterpiece 1992/6 FD×02
Type Master Oshitaoshi Nikkonren Kikaku 1992/7 FD
Video Library V1.1 Fujitsu 1991/10 FD
Video Library V2.1 Fujitsu 1992/12 FD
@@ -421,7 +417,19 @@ Zurukamashi Ver 2.0 Nikkonren Kikaku
-<!-- GAME DISCS -->
+<!-- GAME / APPLICATION DISCS -->
+
+ <software name="386asm">
+ <description>386|ASM Tool Kit V1.1</description>
+ <year>1989</year>
+ <publisher>富士通 (Fujitsu)</publisher>
+ <info name="release" value="198912xx" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size="1261568">
+ <rom name="386asm.bin" size="1261568" crc="b7a1dedd" sha1="307cf2b575c057c49d23db6b6dcbfcb15ac2c427"/>
+ </dataarea>
+ </part>
+ </software>
<!-- Controller input issues -->
<software name="abunaten" supported="no">
@@ -534,6 +542,36 @@ Zurukamashi Ver 2.0 Nikkonren Kikaku
</part>
</software>
+ <!--
+ Compatible with FM Towns, FM-R50 and FM-16 Beta.
+ All the text is misplaced in MAME, confirmed to not happen on real hardware.
+ -->
+ <software name="bunkun" supported="no">
+ <description>Bun-kun Series - Youji Kiso Nouryoku Training Soft Set</description>
+ <year>1989?</year>
+ <publisher>日本教育情報センター (JEIC)</publisher>
+ <info name="alt_title" value="æ–‡å›ã‚·ãƒªãƒ¼ã‚ºã€€å¹¼å… 基礎能力トレーニングソフト・セット" />
+ <info name="usage" value="Prepare a bootable MS-DOS 3.1 disk and insert it on drive B. Insert one of the 3 original disks on drive A and run SETTW.BAT to install the program to the bootable disk." />
+ <part name="flop1" interface="floppy_3_5">
+ <feature name="part_id" value="æ–¹å‘ã¨è¿·è·¯ / Houkou to Meiro" />
+ <dataarea name="flop" size="1261568">
+ <rom name="bun-kun - houkou to meiro.hdm" size="1261568" crc="c65dbb07" sha1="20837c3f5d6c1f92d668eadb3106ae5ba048c415"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <feature name="part_id" value="相似ã¨é †åˆ— / Souji to Junretsu" />
+ <dataarea name="flop" size="1261568">
+ <rom name="bun-kun - souji to junretsu.hdm" size="1261568" crc="9866bb7b" sha1="a2eb5b5bf1d4575457ee8f62a1c8fa49d1bb12b8"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_3_5">
+ <feature name="part_id" value="é¸æŠžã¨è¨˜æ†¶ / Sentaku to Kioku" />
+ <dataarea name="flop" size="1261568">
+ <rom name="bun-kun - sentaku to kioku.hdm" size="1261568" crc="fa4ca205" sha1="3d52402adc2a37be62293488746821bf43687ad1"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="cameltry">
<description>Cameltry</description>
<year>1994</year>
@@ -1703,6 +1741,27 @@ Zurukamashi Ver 2.0 Nikkonren Kikaku
</part>
</software>
+ <!-- Possibly cracked. A redump from the original disks would be welcome. -->
+ <software name="supdaisn">
+ <description>Super Daisenryaku</description>
+ <year>1990</year>
+ <publisher>システムソフト (SystemSoft)</publisher>
+ <info name="alt_title" value="スーパー大戦略" />
+ <info name="release" value="199003xx" />
+ <part name="flop1" interface="floppy_3_5">
+ <feature name="part_id" value="Disk 1" />
+ <dataarea name="flop" size="1261568">
+ <rom name="superdaisen_1.xdf" size="1261568" crc="49aa5147" sha1="39be212fbef4ef4a93642f6e47dd6d1bae3cb937"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <feature name="part_id" value="Disk 2" />
+ <dataarea name="flop" size="1261568">
+ <rom name="superdaisen_2.xdf" size="1261568" crc="c7f7f2d3" sha1="394ac85565728e69c30c3cf974d4a3031267f86d"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="shangrl2sp">
<description>Shangrlia 2 Special Disk</description>
<year>1993</year>
@@ -1938,6 +1997,26 @@ Zurukamashi Ver 2.0 Nikkonren Kikaku
</part>
</software>
+ <software name="trafconf">
+ <description>Traffic Confusion</description>
+ <year>1992</year>
+ <publisher>マスターピース (Masterpiece)</publisher>
+ <info name="alt_title" value="トラフィックコンフュージョン" />
+ <info name="release" value="199206xx" />
+ <part name="flop1" interface="floppy_3_5">
+ <feature name="part_id" value="System Disk" />
+ <dataarea name="flop" size="1261568">
+ <rom name="traffic confusion (system disk).hdm" size="1261568" crc="5b02ec79" sha1="e9223c67b18e53ce906ca65f29cf2807604fc124"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <feature name="part_id" value="User Disk" />
+ <dataarea name="flop" size="1261568">
+ <rom name="traffic confusion (user disk).hdm" size="1261568" crc="a639e9b5" sha1="df1566fbbbd512e89aac75ca26664cceda3b0272"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="ushinawa">
<description>Ushinawareta Rakuen</description>
<year>1995</year>
@@ -2112,6 +2191,50 @@ Zurukamashi Ver 2.0 Nikkonren Kikaku
</part>
</software>
+ <software name="wedderra">
+ <description>Wedding Errantry - Gyakutama Ou</description>
+ <year>1995</year>
+ <publisher>グローサー (Grocer)</publisher>
+ <info name="alt_title" value="ウエディング・エラントリー 逆玉王" />
+ <info name="release" value="199501xx" />
+ <part name="flop1" interface="floppy_3_5">
+ <feature name="part_id" value="Disk A" />
+ <dataarea name="flop" size="1261568">
+ <rom name="wedding errantry - gyakutama ou (disk a).hdm" size="1261568" crc="aaaafda4" sha1="0f11a09a075384d9a796cdfc67a9170a17b0b3c6"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <feature name="part_id" value="Disk B" />
+ <dataarea name="flop" size="1261568">
+ <rom name="wedding errantry - gyakutama ou (disk b).hdm" size="1261568" crc="edaad3bd" sha1="87cec9967eaef39ac639825e9e9677fdba4ac02b"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_3_5">
+ <feature name="part_id" value="Disk C" />
+ <dataarea name="flop" size="1261568">
+ <rom name="wedding errantry - gyakutama ou (disk c).hdm" size="1261568" crc="c4c805f0" sha1="72c5a1f0ceb0aa977f007de32204149a800913ac"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_3_5">
+ <feature name="part_id" value="Disk D" />
+ <dataarea name="flop" size="1261568">
+ <rom name="wedding errantry - gyakutama ou (disk d).hdm" size="1261568" crc="ebeae4bf" sha1="34d7a971381b12f3340a6991e376faeccfeadd13"/>
+ </dataarea>
+ </part>
+ <part name="flop5" interface="floppy_3_5">
+ <feature name="part_id" value="Disk E" />
+ <dataarea name="flop" size="1261568">
+ <rom name="wedding errantry - gyakutama ou (disk e).hdm" size="1261568" crc="62317ff3" sha1="3505721f2f256f80bd8463e1dd90662cc60e95e6"/>
+ </dataarea>
+ </part>
+ <part name="flop6" interface="floppy_3_5">
+ <feature name="part_id" value="Disk F" />
+ <dataarea name="flop" size="1261568">
+ <rom name="wedding errantry - gyakutama ou (disk f).hdm" size="1261568" crc="ec99238a" sha1="70eb057a67ffab0072473e37ed3fa39f81492917"/>
+ </dataarea>
+ </part>
+ </software>
+
<!-- DOUJIN / HOMEBREW DISCS -->
@@ -2442,6 +2565,31 @@ Zurukamashi Ver 2.0 Nikkonren Kikaku
</part>
</software>
+ <!--
+ Runs too fast and has some slight graphical glitches in the score display.
+ Most of the visual artifacts (missing sprites in the water and explosions, for example) aren't emulation bugs, they also happen on real hardware.
+ -->
+ <software name="metalbld" supported="partial">
+ <description>Metal Blade</description>
+ <year>1991</year>
+ <publisher>&lt;doujin&gt;</publisher>
+ <info name="developer" value="Laizaps" />
+ <info name="alt_title" value="メタルブレード" />
+ <info name="usage" value="Boot TownsOS V1.1, then run the icon on drive A: with both floppy disks mounted" />
+ <part name="flop1" interface="floppy_3_5">
+ <feature name="part_id" value="System Disk" />
+ <dataarea name="flop" size = "1261568">
+ <rom name="metal blade a.hdm" size="1261568" crc="f1eee349" sha1="8125d8d11477887a958ef8d10b63872ccb26917f"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <feature name="part_id" value="Data Disk" />
+ <dataarea name="flop" size = "1261568">
+ <rom name="metal blade b.hdm" size="1261568" crc="aa170a51" sha1="4f29e03d230db84c62347cdb9024e1853ba654dd"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="mister">
<description>Mister - Meitantei Toujou</description>
<year>2014</year>
diff --git a/hash/ibm5150.xml b/hash/ibm5150.xml
index 2d9a188a7fd..fcf7d9b401c 100644
--- a/hash/ibm5150.xml
+++ b/hash/ibm5150.xml
@@ -97,7 +97,7 @@ Known PC Booter Games Not Dumped, Or Dumped and Lost when Demonlord's Site went
<description>Adventure in Serenia</description>
<year>1982</year>
<publisher>IBM</publisher>
- <info name="developer" value="Sierra" />
+ <info name="developer" value="Sierra On-Line" />
<info name="usage" value="PC Booter" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="163840">
@@ -1251,7 +1251,7 @@ Known PC Booter Games Not Dumped, Or Dumped and Lost when Demonlord's Site went
<description>King's Quest</description>
<year>1984</year>
<publisher>IBM</publisher>
- <info name="developer" value="Sierra" />
+ <info name="developer" value="Sierra On-Line" />
<info name="usage" value="PC Booter" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="368640">
@@ -1546,7 +1546,7 @@ Known PC Booter Games Not Dumped, Or Dumped and Lost when Demonlord's Site went
<!-- This is not an original and has been converted from a PCjr cartridge. -->
<year>1983</year>
<publisher>IBM</publisher>
- <info name="developer" value="Sierra" />
+ <info name="developer" value="Sierra On-Line" />
<info name="usage" value="PC Booter" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="163840">
@@ -1973,6 +1973,23 @@ Known PC Booter Games Not Dumped, Or Dumped and Lost when Demonlord's Site went
</part>
</software>
+ <software name="sexvixen">
+ <description>Sex Vixens from Space</description>
+ <year>1989</year>
+ <publisher>Free Spirit Software</publisher>
+ <info name="developer" value="Free Spirit Software" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Sex Vixens from Space [Free Spirit Software] [1989] [5.25DD] [Disk 1 of 2].img" size="368640" crc="8d479cd2" sha1="386b9004dfa5181a283f1dac6d40093fbad2cefc"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Sex Vixens from Space [Free Spirit Software] [1989] [5.25DD] [Disk 2 of 2].img" size="368640" crc="a3877e3a" sha1="080c3c8c4f40a0e1528c812c67bb92d763f31b6d"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="cboxing">
<description>Sierra Championship Boxing</description>
<year>1985</year>
@@ -2033,6 +2050,80 @@ Known PC Booter Games Not Dumped, Or Dumped and Lost when Demonlord's Site went
</part>
</software>
+ <software name="silents2">
+ <description>Silent Service II (v457.03, 5.25")</description>
+ <year>1991</year>
+ <publisher>MicroProse</publisher>
+ <info name="developer" value="MPS Labs" />
+ <info name="version" value="IBM Version 457.03, 02/10/91" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.03) [Microprose] [1991] [5.25DD] [Disk A].img" size="368640" crc="0f3eecee" sha1="56b51becfccfc95b237a7bb13a4fd4ad35c25b62"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.03) [Microprose] [1991] [5.25DD] [Disk B].img" size="368640" crc="4bb4fc32" sha1="5baeb9314c76c57fd81c593aa410898ded860b65"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.03) [Microprose] [1991] [5.25DD] [Disk C].img" size="368640" crc="3ad81a11" sha1="2b2ff8a2324aed6d04d555acb796e4e8da57fae6"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.03) [Microprose] [1991] [5.25DD] [Disk D].img" size="368640" crc="181c65b0" sha1="7a98274b45bfd11d8393a7f76d9e5be1c89574bd"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="silents2a" cloneof="silents2">
+ <description>Silent Service II (v457.01, 5.25")</description>
+ <year>1990</year>
+ <publisher>MicroProse</publisher>
+ <info name="developer" value="MPS Labs" />
+ <info name="version" value="IBM Version 457.01, 07/10/90" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.01) [Microprose] [1990] [5.25DD] [Disk A].img" size="368640" crc="e76309c6" sha1="526deaf5dc94f586a3733aa8a54f785cc55f9cdb"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.01) [Microprose] [1990] [5.25DD] [Disk B].img" size="368640" crc="c2e71598" sha1="53f3ca86c50c8d2378f04ce637e3e9640d923fb1"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.01) [Microprose] [1990] [5.25DD] [Disk C].img" size="368640" crc="555ee174" sha1="34cfb62d13996879f39769dfb12c010806f0b5db"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Silent Service 2 (v457.01) [Microprose] [1990] [5.25DD] [Disk D].img" size="368640" crc="6b74b0dd" sha1="c7ba8e9812fffaeb8b68491552b50c490dda43ce"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="silents2_35" cloneof="silents2">
+ <description>Silent Service II (v457.01, 3.5")</description>
+ <year>1990</year>
+ <publisher>MicroProse</publisher>
+ <info name="developer" value="MPS Labs" />
+ <info name="version" value="IBM Version 457.01, 07/10/90" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="Silent Service 2 (v457.01) [Microprose] [1990] [3.5DD] [Disk A].img" size="737280" crc="d21eeeb5" sha1="196d053414c08bff51936a669025cb933b4b9096"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="Silent Service 2 (v457.01) [Microprose] [1990] [3.5DD] [Disk B].img" size="737280" crc="e3d92c3d" sha1="787b795422552c413bfe14465bc06b152943ce91"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="sidwindr">
<description>SideWinder</description>
<year>1988</year>
@@ -7941,18 +8032,77 @@ has been replaced with an all-zero block. -->
</part>
</software>
- <software name="batlches">
- <description>Battle Chess</description>
+ <software name="btlchess">
+ <description>Battle Chess (5.25", VGA version)</description>
+ <year>1990</year>
+ <publisher>Interplay</publisher>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Battle Chess [Interplay] [1990] [5.25DD] [Disk 1 of 3].img" size="368640" crc="22fe945a" sha1="de0951b1921246251e02722e3273373df578d2b9"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Battle Chess [Interplay] [1990] [5.25DD] [Disk 2 of 3].img" size="368640" crc="53a53054" sha1="397c7603e24b38a028bdb6bee399ac1d74effd68"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Battle Chess [Interplay] [1990] [5.25DD] [Disk 3 of 3].img" size="368640" crc="501307ad" sha1="1705209f3ea9c98b34bf3ca97bce57092698d5f2"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="btlchessa" cloneof="btlchess">
+ <description>Battle Chess (5.25", EGA version)</description>
<year>1988</year>
<publisher>Interplay</publisher>
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Battle Chess (EGA) [Interplay] [1988] [5.25DD] [Startup Disk].img" size="368640" crc="2d245433" sha1="1dfe4065fe66147994cdf331e3b34ae214ef721e"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Battle Chess (EGA) [Interplay] [1988] [5.25DD] [Animation Disk].img" size="368640" crc="73c9096f" sha1="4cf27086a92a742e0a53b478a771bbc539d65374"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="btlchess35" cloneof="btlchess">
+ <description>Battle Chess (3.5", VGA version)</description>
+ <year>1990</year>
+ <publisher>Interplay</publisher>
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
- <rom name="Battle Chess (1988)(Interplay)(Disk 1 of 2)[cp codebook].dsk" size="737280" crc="21763440" sha1="680ebdcd55b52910df9bd92792f12df5e80d9412"/>
+ <rom name="Battle Chess [Interplay] [1990] [3.5DD] [Disk 1 of 2].img" size="737280" crc="21763440" sha1="680ebdcd55b52910df9bd92792f12df5e80d9412"/>
</dataarea>
</part>
<part name="flop2" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
- <rom name="Battle Chess (1988)(Interplay)(Disk 2 of 2)[cp codebook].dsk" size="737280" crc="8c0a720f" sha1="9a0b9b8adda97a65da4b2a1490c31f605dfef4a8"/>
+ <rom name="Battle Chess [Interplay] [1990] [3.5DD] [Disk 2 of 2].img" size="737280" crc="8c0a720f" sha1="9a0b9b8adda97a65da4b2a1490c31f605dfef4a8"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="btlchess35a" cloneof="btlchess">
+ <description>Battle Chess (3.5", EGA version - first release)</description>
+ <year>1988</year>
+ <publisher>Interplay</publisher>
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="Battle Chess (EGA version - 1st release) [Interplay] [1988] [3.5DD] [Disk 1 of 1].img" size="737280" crc="7933e954" sha1="4746834847333c5785a0094c71dec03f7a53d8c4"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="btlchess35b" cloneof="btlchess">
+ <description>Battle Chess (3.5", EGA version - second release)</description>
+ <year>1988</year>
+ <publisher>Interplay</publisher>
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="Battle Chess (EGA version - 2nd release) [Interplay] [1988] [3.5DD] [Disk 1 of 1].img" size="737280" crc="040ff059" sha1="b21954c1c0ae2e44e78f8d4d5cb955ba6f4967a6"/>
</dataarea>
</part>
</software>
@@ -8172,7 +8322,7 @@ has been replaced with an all-zero block. -->
<description>Cadaver (5.25")</description>
<year>1991</year>
<publisher>Image Works</publisher>
- <info name="developer" value="Bitmap Brothers" />
+ <info name="developer" value="The Bitmap Brothers" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
<rom name="cad1-4.img" size="368640" crc="a6e04e3d" sha1="0b381a62151674d75485ed67e1766b4799d65b36"/>
@@ -8199,7 +8349,7 @@ has been replaced with an all-zero block. -->
<description>Cadaver (3.5", Quest &amp; Glory Compilation)</description>
<year>1991</year>
<publisher>Image Works</publisher>
- <info name="developer" value="Bitmap Brothers" />
+ <info name="developer" value="The Bitmap Brothers" />
<part name="flop1" interface="floppy_3_5">
<!-- modified .ini file -->
<dataarea name="flop" size = "737280">
@@ -8217,7 +8367,7 @@ has been replaced with an all-zero block. -->
<description>Cadaver (3.5")</description>
<year>1991</year>
<publisher>Image Works</publisher>
- <info name="developer" value="Bitmap Brothers" />
+ <info name="developer" value="The Bitmap Brothers" />
<part name="flop1" interface="floppy_3_5">
<!-- disk has gone bad -->
<dataarea name="flop" size = "737280">
@@ -8288,7 +8438,7 @@ has been replaced with an all-zero block. -->
<description>Caveman Ugh-Lympics</description>
<year>1988</year>
<publisher>Electronic Arts</publisher>
- <info name="developer" value="Dynamix, Inc." />
+ <info name="developer" value="Dynamix" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
<rom name="Caveman Ugh-Lympics [1988] [5.25] [1 of 4].img" size="368640" crc="e2b6a566" sha1="92be8b5883718a2df46eee48f30b8db1088ab39c"/>
@@ -9338,6 +9488,19 @@ has been replaced with an all-zero block. -->
</part>
</software>
+ <software name="fireforget2">
+ <!-- dumped via KryoFlux, some tracks show up as modified -->
+ <description>Fire &amp; Forget 2</description>
+ <year>1990</year>
+ <publisher>Titus</publisher>
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size="737280">
+ <rom name="fireforget2.img" size="737280" crc="24ac2704" sha1="737ca587fa78d5f1160557c99a68b0022f1f216c" status="baddump" />
+ </dataarea>
+ </part>
+ </software>
+
+
<software name="futurwar">
<description>Future Wars - Adventures in Time</description>
<year>1990</year>
@@ -9693,7 +9856,7 @@ has been replaced with an all-zero block. -->
<description>Indiana Jones and the Last Crusade - The Action Game (Kixx release)</description>
<year>1989</year>
<publisher>Lucasfilm - U.S. Gold</publisher>
- <info name="developer" value="LucasFilm Games" />
+ <info name="developer" value="Lucasfilm Games" />
<part name="flop1" interface="floppy_3_5">
<!-- Copy-protected key disk -->
<dataarea name="flop" size = "2157701">
@@ -11058,7 +11221,7 @@ has been replaced with an all-zero block. -->
<description>Menace (5.25")</description>
<year>1989</year>
<publisher>Psygnosis</publisher>
- <info name="developer" value="DMA Design Limited" />
+ <info name="developer" value="DMA Design" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
<rom name="Menace [Psygnosis] [1989] [5.25DD] [Disk 1 of 2].img" size="368640" crc="7746a156" sha1="cd0d944da7486d141922357b09cc22a2809cfd64"/>
@@ -11075,7 +11238,7 @@ has been replaced with an all-zero block. -->
<description>Menace (3.5")</description>
<year>1989</year>
<publisher>Psygnosis</publisher>
- <info name="developer" value="DMA Design Limited" />
+ <info name="developer" value="DMA Design" />
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
<rom name="Menace.img" size="737280" crc="94e7307c" sha1="430573d0d4867a724e6241dbfb0120439aa1d5cc"/>
@@ -12847,48 +13010,94 @@ has been replaced with an all-zero block. -->
</part>
</software>
- <software name="stunts">
- <description>Stunts (5.25") (USA)</description>
- <year>1990</year>
+ <software name="4dsdrv">
+ <description>4D Sports Driving (5.25", Euro)</description>
+ <year>1991</year>
+ <publisher>Mindscape</publisher>
+ <info name="developer" value="Distinctive Software" />
+ <info name="version" value="1.1 (Feb 25 1991)" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="4D Sports Driving [Mindscape] [1991] [5.25DD] [Disk A].img" size="368640" crc="eb9b5986" sha1="d7b5f9a82344df5d176566cbfbb52d2181a7ea61"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="4D Sports Driving [Mindscape] [1991] [5.25DD] [Disk B].img" size="368640" crc="bdafb9d5" sha1="06e94ed5e9e8aac425e0e9e3e02cc4e009a8a688"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="4D Sports Driving [Mindscape] [1991] [5.25DD] [Disk C].img" size="368640" crc="69a9849f" sha1="5a7517ce2d16c6106606fb25b0ab2587244b5f34"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="4D Sports Driving [Mindscape] [1991] [5.25DD] [Disk D].img" size="368640" crc="77f15cca" sha1="142a99848dca1c8b41c2a5d5f78362effa8263e0"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="4dsdrv35" cloneof="4dsdrv">
+ <description>4D Sports Driving (3.5", Euro)</description>
+ <year>1991</year>
+ <publisher>Mindscape</publisher>
+ <info name="developer" value="Distinctive Software" />
+ <info name="version" value="1.1 (Feb 25 1991)" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="4D Sports Driving [Mindscape] [1991] [3.5DD] [Disk A].img" size="737280" crc="cde096c0" sha1="9e1cf5c5615136023d6eb3503049b638a879accc"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="4D Sports Driving [Mindscape] [1991] [3.5DD] [Disk B].img" size="737280" crc="c87c7d0d" sha1="a7dfed99afa3bfd195b06aadb24d2572d2581c60"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="stunts" cloneof="4dsdrv">
+ <description>Stunts (5.25", USA)</description>
+ <year>1991</year>
<publisher>Brøderbund Software</publisher>
<info name="developer" value="Distinctive Software" />
<info name="version" value="1.1 (Feb 12 1991)" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
- <rom name="Stunts [Broderbund Software] [1990] [5.25] [Disk A].img" size="368640" crc="ba32d817" sha1="206aec96920e6603c762eda9acb01e24c4c849a0"/>
+ <rom name="Stunts [Broderbund Software] [1991] [5.25DD] [Disk A].img" size="368640" crc="1d308255" sha1="35d5563ac4e15813aef2ad0f0b0dbde3e86d8221"/>
</dataarea>
</part>
<part name="flop2" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
- <rom name="Stunts [Broderbund Software] [1990] [5.25] [Disk B].img" size="368640" crc="adeb46a6" sha1="996808c253cd2ec413db8e6a5eda22ddf28bd49b"/>
+ <rom name="Stunts [Broderbund Software] [1991] [5.25DD] [Disk B].img" size="368640" crc="a4a37649" sha1="b8f69ed16613fd8672622e9ceffe7624e3efe396"/>
</dataarea>
</part>
<part name="flop3" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
- <rom name="Stunts [Broderbund Software] [1990] [5.25] [Disk C].img" size="368640" crc="ad24245e" sha1="f8feb9c99b997a06b9dd822febd77706088f4371"/>
+ <rom name="Stunts [Broderbund Software] [1991] [5.25DD] [Disk C].img" size="368640" crc="4ab40d3d" sha1="196092f386c5975a3d6f0b62aaedbc083f142ee9"/>
</dataarea>
</part>
<part name="flop4" interface="floppy_5_25">
<dataarea name="flop" size = "368640">
- <rom name="Stunts [Broderbund Software] [1990] [5.25] [Disk D].img" size="368640" crc="6fa65143" sha1="24cd4dec00ba7c4e447ffc255df795af5580cd79"/>
+ <rom name="Stunts [Broderbund Software] [1991] [5.25DD] [Disk D].img" size="368640" crc="bc161bcb" sha1="d5dd3ebaa93eb8493afb07ab1039b49d0d3af895"/>
</dataarea>
</part>
</software>
- <software name="stunts35" cloneof="stunts">
- <description>Stunts (3.5") (USA)</description>
- <year>1990</year>
+ <software name="stunts35" cloneof="4dsdrv">
+ <description>Stunts (3.5", USA)</description>
+ <year>1991</year>
<publisher>Brøderbund Software</publisher>
<info name="developer" value="Distinctive Software" />
<info name="version" value="1.1 (Feb 12 1991)" />
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
- <rom name="Stunts [Broderbund Software] [1990] [3.5DD] [Disk A].img" size="737280" crc="364a0069" sha1="fe3b35fa91619815e1565066c9404d02812dd17a"/>
+ <rom name="Stunts [Broderbund Software] [1991] [3.5DD] [Disk A].img" size="737280" crc="94630086" sha1="b77d10c20c5daa5318ba74836b079dc8c0e60253"/>
</dataarea>
</part>
<part name="flop2" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
- <rom name="Stunts [Broderbund Software] [1990] [3.5DD] [Disk B].img" size="737280" crc="273c9396" sha1="57f637e6cbfd6f2ae8efd54857d9ee0b4528d182"/>
+ <rom name="Stunts [Broderbund Software] [1991] [3.5DD] [Disk B].img" size="737280" crc="1b67a396" sha1="06095fffee95369d00f0eecce77337ce4b510642"/>
</dataarea>
</part>
</software>
@@ -12933,15 +13142,77 @@ has been replaced with an all-zero block. -->
</part>
</software>
- <software name="supertet">
- <description>Super Tetris</description>
+ <software name="ssinv">
+ <description>Super Space Invaders (5.25")</description>
+ <year>1992</year>
+ <publisher>Domark</publisher>
+ <info name="developer" value="Taito Corporation" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Super Space Invaders [Domark] [1992] [5.25DD] [Disk 1 of 4].img" size="368640" crc="472b3787" sha1="5ce141127b0d8bf333f773d976182a177bfabdcb"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Super Space Invaders [Domark] [1992] [5.25DD] [Disk 2 of 4].img" size="368640" crc="542b0d86" sha1="e32d94ba58a5c200adb54f3586e1cde0702c33c4"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Super Space Invaders [Domark] [1992] [5.25DD] [Disk 3 of 4].img" size="368640" crc="d6e79a21" sha1="b2e547aeaca1cf6df7e9a4ffaf7e6f9e27b0e4d4"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Super Space Invaders [Domark] [1992] [5.25DD] [Disk 4 of 4].img" size="368640" crc="57320ba0" sha1="24bda4eae51d903166c731a56537c9207c2db034"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ssinv35" cloneof="ssinv">
+ <description>Super Space Invaders (3.5")</description>
+ <year>1992</year>
+ <publisher>Domark</publisher>
+ <info name="developer" value="Taito Corporation" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="Super Space Invaders [Domark] [1992] [3.5DD] [Disk 1 of 2].img" size="737280" crc="ef812c7e" sha1="b3ff35c180622a8088c47406b6b891ad64007951"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size = "737280">
+ <rom name="Super Space Invaders [Domark] [1992] [3.5DD] [Disk 2 of 2].img" size="737280" crc="59d22848" sha1="689f8cc1a5a98b3639ff035f41e00f4f8fd36785"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="stetris">
+ <description>Super Tetris (5.25")</description>
+ <year>1991</year>
+ <publisher>Spectrum Holobyte</publisher>
+ <info name="developer" value="Sphere" />
+ <info name="version" value="version 1.0" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Super Tetris [Spectrum Holobyte] [1991] [5.25DD] [Disk 1 of 2].img" size="368640" crc="8284b783" sha1="66089260c95269ad690d8496ce03910ad6b7fe1b"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_5_25">
+ <dataarea name="flop" size = "368640">
+ <rom name="Super Tetris [Spectrum Holobyte] [1991] [5.25DD] [Disk 2 of 2].img" size="368640" crc="37f71c81" sha1="9c0dd04a52adffad41ad9c64c750e6acbbbffadf"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="stetris35" cloneof="stetris">
+ <description>Super Tetris (3.5")</description>
<year>1991</year>
<publisher>Spectrum Holobyte</publisher>
<info name="developer" value="Sphere" />
<info name="version" value="1.0" />
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
- <rom name="Super Tetris [Spectrum Holobyte] [1991] [3,5DD] [Disk 1 of 1].img" size="737280" crc="7e506514" sha1="a961229ec82ec8f5eafd57b239b61ece448e437b"/>
+ <rom name="Super Tetris [Spectrum Holobyte] [1991] [3.5DD] [Disk 1 of 1].img" size="737280" crc="7e506514" sha1="a961229ec82ec8f5eafd57b239b61ece448e437b"/>
</dataarea>
</part>
</software>
diff --git a/hash/ibm5170.xml b/hash/ibm5170.xml
index e4f376e086a..eb0104c8120 100644
--- a/hash/ibm5170.xml
+++ b/hash/ibm5170.xml
@@ -8572,30 +8572,29 @@ license:CC0
</software>
<!-- Game Disks -->
-
- <software name="1830rail" supported="no">
+ <software name="1830rail">
<description>1830 - Railroads &amp; Robber Barons</description>
<year>1995</year>
<publisher>Avalon Hill</publisher>
<info name="developer" value="Simtex" />
<part name="flop1" interface="floppy_3_5">
- <dataarea name="flop" size = "1474560">
- <rom name="1830 Railroads &amp; Robber Barons (USA, Europe) (Disk 1).img" size="1474560" crc="c91a1322" sha1="91120df39f996d8713840dccf0ee322aa07a07e2"/>
+ <dataarea name="flop" size="1474560">
+ <rom name="1830 Railroads &amp; Robber Barons [Avalon Hill] [1995] [3.5HD] [Disk 1 of 4].img" size="1474560" crc="38edb2bc" sha1="cda6c8de61645496cea395e2344a987783e3bd46"/>
</dataarea>
</part>
<part name="flop2" interface="floppy_3_5">
- <dataarea name="flop" size = "1474560">
- <rom name="1830 Railroads &amp; Robber Barons (USA, Europe) (Disk 2).img" size="1474560" crc="f00758ba" sha1="0588634cee114f697d9e97254e188f4223627993"/>
+ <dataarea name="flop" size="1474560">
+ <rom name="1830 Railroads &amp; Robber Barons [Avalon Hill] [1995] [3.5HD] [Disk 2 of 4].img" size="1474560" crc="d8bad151" sha1="c6a2a27bf5d3c929b90da1cba59ef6755c0b5054"/>
</dataarea>
</part>
<part name="flop3" interface="floppy_3_5">
- <dataarea name="flop" size = "1474560">
- <rom name="1830 Railroads &amp; Robber Barons (USA, Europe) (Disk 3).img" size="1474560" crc="d6d9a334" sha1="4d644adc76af7e04213237a3047fe6de761cbd5b"/>
+ <dataarea name="flop" size="1474560">
+ <rom name="1830 Railroads &amp; Robber Barons [Avalon Hill] [1995] [3.5HD] [Disk 3 of 4].img" size="1474560" crc="8b9cfa8d" sha1="0842b9d404bfb3edc8aa0cffb8a46bf9bf32144a"/>
</dataarea>
</part>
<part name="flop4" interface="floppy_3_5">
- <dataarea name="flop" size = "1474560">
- <rom name="1830 Railroads &amp; Robber Barons (USA, Europe) (Disk 4).img" size="1474560" crc="2d61f1b1" sha1="728b2d863c985a250fbd41024ed289704836cc9f"/>
+ <dataarea name="flop" size="1474560">
+ <rom name="1830 Railroads &amp; Robber Barons [Avalon Hill] [1995] [3.5HD] [Disk 4 of 4].img" size="1474560" crc="01d9a5b5" sha1="7d03243a41e098e9c682637599024c4818186a8f"/>
</dataarea>
</part>
</software>
@@ -10355,6 +10354,29 @@ license:CC0
</part>
</software>
+ <software name="doombbs" cloneof="doom">
+ <description>DOOM (1.2, Shareware for BBS SysOps)</description>
+ <year>1994</year>
+ <publisher>Sybex</publisher>
+ <info name="developer" value="id Software" />
+ <info name="version" value="1.2" />
+ <!-- Origin: archive.org -->
+ <part name="flop1" interface="floppy_3_5">
+ <feature name="part_number" value="0863-1"/>
+ <feature name="part_id" value="Disk 1 of 2"/>
+ <dataarea name="flop" size="1474560">
+ <rom name="Doom_BBS_1.img" size="1474560" crc="e9b64e07" sha1="2f2a7ddc19b1c68696deaa06296684a6b0f4c538" status="baddump" />
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <feature name="part_number" value="0863-2"/>
+ <feature name="part_id" value="Disk 2 of 2"/>
+ <dataarea name="flop" size="1474560">
+ <rom name="Doom_BBS_2.img" size="1474560" crc="154abef0" sha1="d34df477cd0e8f403a250a4c98ec1c7d06fb4042" status="baddump" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="doomsw" cloneof="doom">
<!-- Companion Disk for The Official DOOMâ„¢ Survivor's Strategies & Secrets -->
<description>DOOM (1.25, Shareware)</description>
@@ -10848,7 +10870,7 @@ license:CC0
</software>
<software name="kyrandia">
- <description>Fables &amp; Fiends - Book One: The Legend of Kyrandia(v1.3, 3.5")</description>
+ <description>Fables &amp; Fiends - Book One: The Legend of Kyrandia (v1.3, 3.5")</description>
<year>1992</year>
<publisher>Virgin Games</publisher>
<info name="version" value="1.3" />
@@ -10936,50 +10958,98 @@ license:CC0
</part>
</software>
- <software name="hofde">
- <description>Fables &amp; Fiends - Book Two: The Hand of Fate (Germany)</description>
+ <software name="hof">
+ <description>Fables &amp; Fiends - Book Two: The Hand of Fate</description>
<year>1993</year>
<publisher>Virgin Interactive Entertainment</publisher>
+ <info name="version" value="v1.00c" />
+ <info name="developer" value="Westwood Studios" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 1 of 8].img" size="1474560" crc="c747690b" sha1="659353b54a015a8916a84091bcddfde30265dbf3"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 2 of 8].img" size="1474560" crc="4cd3a049" sha1="93b12ba7d7d026267f4b0cd63e88016648d38b0d"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 3 of 8].img" size="1474560" crc="a7c0c898" sha1="67256b49079329e255decccda8f40597be432c72"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 4 of 8].img" size="1474560" crc="f3a249be" sha1="8dd62c8c0d923faa0374d786b2a1f91c5a69275e"/>
+ </dataarea>
+ </part>
+ <part name="flop5" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 5 of 8].img" size="1474560" crc="1b6b8aa9" sha1="bb483aee0dba9a12b6b4101a144f9f30d9591cbb"/>
+ </dataarea>
+ </part>
+ <part name="flop6" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 6 of 8].img" size="1474560" crc="702a1193" sha1="30ee3e66c79d01aff6574074fe2a8f55a2f21f1a"/>
+ </dataarea>
+ </part>
+ <part name="flop7" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 7 of 8].img" size="1474560" crc="c11eec74" sha1="c0fd65c72359fed7f6b453926de494084fab7d22"/>
+ </dataarea>
+ </part>
+ <part name="flop8" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="The Hand of Fate [1993] [Virgin] [3.5HD] [Disk 8 of 8].img" size="1474560" crc="0fd00a3d" sha1="5197ef4c02ca39ad259425a3d755b498c593c7bc"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="hofde" cloneof="hof">
+ <description>Fables &amp; Fiends - Book Two: The Hand of Fate (Germany)</description>
+ <year>1994</year>
+ <publisher>Virgin Interactive Entertainment</publisher>
<info name="version" value="1.41" />
<info name="developer" value="Westwood Studios" />
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 1 of 8].img" size="1474560" crc="f109ad49" sha1="c11eebac377d87990374f802a47f3574e92310fa"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 1 of 8].img" size="1474560" crc="f109ad49" sha1="c11eebac377d87990374f802a47f3574e92310fa" status="baddump" />
</dataarea>
</part>
<part name="flop2" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 2 of 8].img" size="1474560" crc="9bcefa29" sha1="c71360c47f26cc50f024259747499a024355c86b"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 2 of 8].img" size="1474560" crc="9bcefa29" sha1="c71360c47f26cc50f024259747499a024355c86b" />
</dataarea>
</part>
<part name="flop3" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 3 of 8].img" size="1474560" crc="4bd2ef7b" sha1="e39f0df11f5e042d5c2e08d80c2a8a76a2f61aa8"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 3 of 8].img" size="1474560" crc="4bd2ef7b" sha1="e39f0df11f5e042d5c2e08d80c2a8a76a2f61aa8" status="baddump" />
</dataarea>
</part>
<part name="flop4" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 4 of 8].img" size="1474560" crc="ca427f9b" sha1="6edf8d1696645b37ef58f1444c8d68a637d7c6d7"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 4 of 8].img" size="1474560" crc="ca427f9b" sha1="6edf8d1696645b37ef58f1444c8d68a637d7c6d7" status="baddump" />
</dataarea>
</part>
<part name="flop5" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 5 of 8].img" size="1474560" crc="f12b7d73" sha1="f8cc1cfeb466f464f8c4dd3df5e33f1055ca25a9"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 5 of 8].img" size="1474560" crc="f12b7d73" sha1="f8cc1cfeb466f464f8c4dd3df5e33f1055ca25a9" />
</dataarea>
</part>
<part name="flop6" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 6 of 8].img" size="1474560" crc="2c3743dd" sha1="5bb7ffcaf7159658adf11c701fd875e89f93c466"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 6 of 8].img" size="1474560" crc="2c3743dd" sha1="5bb7ffcaf7159658adf11c701fd875e89f93c466" />
</dataarea>
</part>
<part name="flop7" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 7 of 8].img" size="1474560" crc="34f16970" sha1="71f3fc2e66ec11105fd33d1bc55fa6e8c5e7aa71"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 7 of 8].img" size="1474560" crc="34f16970" sha1="71f3fc2e66ec11105fd33d1bc55fa6e8c5e7aa71" />
</dataarea>
</part>
<part name="flop8" interface="floppy_3_5">
<dataarea name="flop" size = "1474560">
- <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 8 of 8].img" size="1474560" crc="ee9bfc16" sha1="52fed013a128433583c40bb8fcc3ada9b28597d3"/>
+ <rom name="The Hand of Fate [1994] [Virgin] [DE] [3.5HD] [Disk 8 of 8].img" size="1474560" crc="ee9bfc16" sha1="52fed013a128433583c40bb8fcc3ada9b28597d3" />
</dataarea>
</part>
</software>
@@ -11056,17 +11126,17 @@ license:CC0
<info name="version" value="1.03" />
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size="1474560">
- <rom name="Formula One Grand Prix [MicroProse] [1992] [3.5HD] [Disk A].img" size="1474560" crc="b6b492b4" sha1="72f8342d0f5c8088be1d26026834d2d08d3c430d"/>
+ <rom name="Formula One Grand Prix [MicroProse] [1992] [3.5HD] [Disk A].img" size="1474560" crc="b6b492b4" sha1="72f8342d0f5c8088be1d26026834d2d08d3c430d" status="baddump" />
</dataarea>
</part>
<part name="flop2" interface="floppy_3_5">
<dataarea name="flop" size="1474560">
- <rom name="Formula One Grand Prix [MicroProse] [1992] [3.5HD] [Disk B].img" size="1474560" crc="730ac7ca" sha1="3f2e0bc149ec259fd7f8d5481005743975891b99"/>
+ <rom name="Formula One Grand Prix [MicroProse] [1992] [3.5HD] [Disk B].img" size="1474560" crc="730ac7ca" sha1="3f2e0bc149ec259fd7f8d5481005743975891b99" status="baddump" />
</dataarea>
</part>
<part name="flop3" interface="floppy_3_5">
<dataarea name="flop" size="1474560">
- <rom name="Formula One Grand Prix [MicroProse] [1992] [3.5HD] [Disk C].img" size="1474560" crc="746eb33e" sha1="74cad4aed7f95cf4fb987844495f85b646801cde"/>
+ <rom name="Formula One Grand Prix [MicroProse] [1992] [3.5HD] [Disk C].img" size="1474560" crc="746eb33e" sha1="74cad4aed7f95cf4fb987844495f85b646801cde" status="baddump" />
</dataarea>
</part>
</software>
@@ -11575,13 +11645,14 @@ license:CC0
</part>
</software>
- <software name="humans" supported="no">
+ <software name="humans">
<description>The Humans (3.5" DD)</description>
- <year>1993</year>
+ <year>1992</year>
<publisher>GameTek</publisher>
+ <info name="version" value="VER 0.3, 22/10/92" />
<part name="flop1" interface="floppy_3_5">
<dataarea name="flop" size = "737280">
- <rom name="The Humans [GameTek] [1992] [3.5DD] [Disk 1 of 4].img" size="737280" crc="c495a6cc" sha1="a052eecea85a433e32af3b95502ac5d4ff9e8dd6"/>
+ <rom name="The Humans [GameTek] [1992] [3.5DD] [Disk 1 of 4].img" size="737280" crc="2f75a54e" sha1="0d6420ae8abe43648bfcc8d63df7b7ee2558c992"/>
</dataarea>
</part>
<part name="flop2" interface="floppy_3_5">
@@ -11603,8 +11674,9 @@ license:CC0
<software name="humans_525" cloneof="humans">
<description>The Humans (5.25" HD)</description>
- <year>1993</year>
+ <year>1992</year>
<publisher>GameTek</publisher>
+ <info name="version" value="VER 0.3, 22/10/92" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size = "1228800">
<rom name="The Humans [GameTek] [1992] [5.25HD] [Disk 1 of 3].img" size="1228800" crc="2dc56954" sha1="25877a02d07686f71e9bfc74a6e507a02a859c56"/>
@@ -11622,6 +11694,43 @@ license:CC0
</part>
</software>
+ <software name="extremis">
+ <description>In Extremis</description>
+ <year>1994</year>
+ <publisher>U.S. Gold</publisher>
+ <info name="developer" value="Blue Sphere" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="In Extremis [US Gold] [1994] [3.5HD] [Disk 1 of 6].img" size="1474560" crc="6ae06031" sha1="dcd4b2c9e76274e8e1c32a5279be2cc89d84500c"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="In Extremis [US Gold] [1994] [3.5HD] [Disk 2 of 6].img" size="1474560" crc="e24acd05" sha1="268ad0acf9ab7aacb1d1bc07d13a107c3906a499"/>
+ </dataarea>
+ </part>
+ <part name="flop3" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="In Extremis [US Gold] [1994] [3.5HD] [Disk 3 of 6].img" size="1474560" crc="eb13c088" sha1="08cb07ea19a595bc39e5f64f88aef5e5577c0e03"/>
+ </dataarea>
+ </part>
+ <part name="flop4" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="In Extremis [US Gold] [1994] [3.5HD] [Disk 4 of 6].img" size="1474560" crc="db6cfdc6" sha1="0674dc81da2ffc5dfb68136e9fdb04c6dbf2ae95"/>
+ </dataarea>
+ </part>
+ <part name="flop5" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="In Extremis [US Gold] [1994] [3.5HD] [Disk 5 of 6].img" size="1474560" crc="d2aa88e5" sha1="c92a192f1c93132e952e7468136952ba41471a54"/>
+ </dataarea>
+ </part>
+ <part name="flop6" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="In Extremis [US Gold] [1994] [3.5HD] [Disk 6 of 6].img" size="1474560" crc="3e6fd6d0" sha1="6b4984e8ea3213c3ef5ad5dc4cb4e7c7fb94c188"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="incait">
<description>Inca (Italy)</description>
<year>1992</year>
@@ -12783,6 +12892,40 @@ license:CC0
</part>
</software>
+ <software name="megaloge">
+ <description>Mega lo Mania (Germany)</description>
+ <year>1992</year>
+ <publisher>Ubi Soft</publisher>
+ <info name="developer" value="Sensible Software" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="Mega Lo Mania (Germany) [Ubi Soft] [1992] [3.5HD] [Disk 1 of 2].img" size="1474560" crc="1c61b8e7" sha1="3c932dbf8e30f31c7a23b46647bb3f6f27aaace4"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size="1474560">
+ <rom name="Mega Lo Mania (Germany) [Ubi Soft] [1992] [3.5HD] [Disk 2 of 2].img" size="1474560" crc="e8eeb3ca" sha1="f6a9e1312ad9f1f794d753012084bad0ce174a54"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mjflight">
+ <description>Michael Jordan in Flight</description>
+ <year>1993</year>
+ <publisher>Electronic Arts</publisher>
+ <info name="developer" value="Pacific Gameworks, ZCT Systems Group" />
+ <part name="flop1" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="Michael Jordan in Flight [Electronic Arts] [1993] [3.5HD] [Disk 1 of 2].img" size="1474560" crc="a9de8087" sha1="dbba3b92d0a56f5a5afa3c86f539cbb1cafe3f6c"/>
+ </dataarea>
+ </part>
+ <part name="flop2" interface="floppy_3_5">
+ <dataarea name="flop" size = "1474560">
+ <rom name="Michael Jordan in Flight [Electronic Arts] [1993] [3.5HD] [Disk 2 of 2].img" size="1474560" crc="c8002fd1" sha1="7bc70f93d506a5e3408945fc9a32de285a9877ce"/>
+ </dataarea>
+ </part>
+ </software>
+
<software name="micromac">
<description>Micro Machines</description>
<year>1994</year>
@@ -12823,23 +12966,6 @@ license:CC0
</part>
</software>
- <software name="mjflight">
- <description>Michael Jordan in Flight</description>
- <year>1993</year>
- <publisher>Electronic Arts</publisher>
- <info name="developer" value="Pacific Gameworks, ZCT Systems Group" />
- <part name="flop1" interface="floppy_3_5">
- <dataarea name="flop" size = "1474560">
- <rom name="Michael Jordan in Flight [Electronic Arts] [1993] [3.5HD] [Disk 1 of 2].img" size="1474560" crc="a9de8087" sha1="dbba3b92d0a56f5a5afa3c86f539cbb1cafe3f6c"/>
- </dataarea>
- </part>
- <part name="flop2" interface="floppy_3_5">
- <dataarea name="flop" size = "1474560">
- <rom name="Michael Jordan in Flight [Electronic Arts] [1993] [3.5HD] [Disk 2 of 2].img" size="1474560" crc="c8002fd1" sha1="7bc70f93d506a5e3408945fc9a32de285a9877ce"/>
- </dataarea>
- </part>
- </software>
-
<software name="msroa">
<description>Microsoft Return of Arcade</description>
<year>1996</year>
diff --git a/hash/kayproii.xml b/hash/kaypro.xml
index d19c601bb12..8e5ee9f6a03 100644
--- a/hash/kayproii.xml
+++ b/hash/kaypro.xml
@@ -3,7 +3,9 @@
<!--
license:CC0
-->
-<softwarelist name="kayproii" description="Kaypro II disk images">
+<softwarelist name="kaypro" description="Kaypro CP/M disk images">
+
+<!-- A:ii -->
<!-- Operating systems -->
@@ -11,6 +13,7 @@ license:CC0
<description>CP/M 2.2 Boot Disk (Ger)</description>
<year>19??</year>
<publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="139911">
<rom name="cp-m 2.2 boot disk (19xx)(digital research)(de).td0" size="139911" crc="ab5d7ae0" sha1="b73622c17306e32b42cef31d58616378329605ef"/>
@@ -22,6 +25,7 @@ license:CC0
<description>CP/M 2.2</description>
<year>19??</year>
<publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="188479">
<rom name="cp-m 2.2 (19xx)(digital research).imd" size="188479" crc="602c4f18" sha1="c4158b4f84066514af2b74cb6d0915f661402819"/>
@@ -35,6 +39,7 @@ license:CC0
<description>Perfect Calc v1.00</description>
<year>1982</year>
<publisher>Perfect Software</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="163451">
<rom name="perfect calc v1.00 (1982)(perfect software).imd" size="163451" crc="d7c79f18" sha1="3666da3855bfc9c82a328fee67906ac04b6bd75b"/>
@@ -46,6 +51,7 @@ license:CC0
<description>Perfect Speller</description>
<year>1982</year>
<publisher>Perfect Software</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="150160">
<rom name="perfect speller (1982)(perfect software).imd" size="150160" crc="c03fc828" sha1="4a405c65a55b5ba9be17b638cfe9c0b539698fbc"/>
@@ -57,6 +63,7 @@ license:CC0
<description>Perfect Writer</description>
<year>1982</year>
<publisher>Perfect Software</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="197701">
<rom name="perfect writer (1982)(perfect software).imd" size="197701" crc="43cb00ac" sha1="67145d125f3f50e660ae8b2e299aad8200d59a7f"/>
@@ -68,6 +75,7 @@ license:CC0
<description>Perfect Writer - Docs and Utilities</description>
<year>198?</year>
<publisher>&lt;unknown&gt;</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="151202">
<rom name="perfect writer - docs and utilities (198x)(-).imd" size="151202" crc="94cda75d" sha1="46348510ff682ef3a8a1e5a27f1625beae21980e"/>
@@ -79,6 +87,7 @@ license:CC0
<description>Perfect Writer - Lessons</description>
<year>198?</year>
<publisher>Perfect Software</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="180829">
<rom name="perfect writer - lessons (198x)(perfect software).imd" size="180829" crc="b8bba8ca" sha1="6e18f014337efcb70248b8cff2483bc1d5c8ec4f"/>
@@ -90,6 +99,7 @@ license:CC0
<description>Profit Plan</description>
<year>1982</year>
<publisher>Chang Laboratories</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="113909">
<rom name="profit plan (1982)(chang laboratories).imd" size="113909" crc="1d967882" sha1="03d00c14e57e0e84e0e1fa127ab36b47d1731ea4"/>
@@ -101,6 +111,7 @@ license:CC0
<description>Select - Teach</description>
<year>1981</year>
<publisher>Select Information Systems</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="148661">
<rom name="select - teach (1981)(select information systems).imd" size="148661" crc="459b51f0" sha1="7bb16452689cbb39a9c8a2088306a98b2f3ca31a"/>
@@ -112,6 +123,7 @@ license:CC0
<description>Select - Work Processor</description>
<year>1981</year>
<publisher>Select Information Systems</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="106254">
<rom name="select - work processor (1981)(select information systems).imd" size="106254" crc="ebcb98c5" sha1="1c8d1a3228e6ac5fdffe7409d921499db22fea72"/>
@@ -123,6 +135,7 @@ license:CC0
<description>WordStar v3.3</description>
<year>1983</year>
<publisher>MicroPro</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="202296">
<rom name="wordstar v3.3 (1983)(micropro).imd" size="202296" crc="64e0f3d6" sha1="6abf468d538e65e82bc0b85cc5d656282048ce3c"/>
@@ -134,6 +147,7 @@ license:CC0
<description>Synergy Host Control System 10/11/85</description>
<year>1985</year>
<publisher>Digital Keyboards</publisher>
+ <sharedfeat name="compatibility" value="A" />
<part name="flop1" interface="floppy_5_25">
<dataarea name="flop" size="191031">
<rom name="synhcs.imd" size="191031" crc="c87f1400" sha1="550c6c35e7605956498345df3c151b6abd89b62d"/>
@@ -141,4 +155,87 @@ license:CC0
</part>
</software>
+<!-- B: 284 -->
+
+ <software name="k28422g">
+ <description>CP/M 2.2G</description>
+ <year>19??</year>
+ <publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="B" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="0x01b508">
+ <rom name="k284-22g.td0" size="0x01b508" crc="d80ce9a0" sha1="0d3da88129ad7ff04079b2a7fe73f19f5da21681"/>
+ </dataarea>
+ </part>
+ </software>
+
+<!-- C: 2X,484 -->
+
+ <software name="cpm22f">
+ <description>CP/M 2.2F (81-292)</description>
+ <year>19??</year>
+ <publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="C" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="270208">
+ <rom name="k4f-292.td0" size="270208" crc="8309cabe" sha1="7eb6829aaadae67b71bf4bfa19ce72f1e780747e"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="cpm22g">
+ <description>CP/M 2.2G (81-292-A)</description>
+ <year>19??</year>
+ <publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="C" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="202620">
+ <rom name="kp22gdsd.td0" size="202620" crc="6ab35630" sha1="106fb294b719d620abd82ee74f0f16130264e3d1"/>
+ </dataarea>
+ </part>
+ </software>
+
+<!-- D: iv -->
+
+ <software name="kiv22">
+ <description>CP/M 2.2 for Kaypro IV</description>
+ <year>19??</year>
+ <publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="D" />
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="0x056639">
+ <rom name="kiv-22.imd" size="0x056639" crc="99182539" sha1="d4b5a6a0a0038fc12aa39a7dd17006f1c71198df"/>
+ </dataarea>
+ </part>
+ </software>
+
+<!-- E: 10 - kaypro10 disks are loadable by 2X,484 -->
+
+ <software name="kay10a0s">
+ <description>CP/M 2.2F</description>
+ <year>19??</year>
+ <publisher>Digital Research</publisher>
+ <sharedfeat name="compatibility" value="E,C" />
+ <part name="flop" interface="floppy_5_25">
+ <dataarea name="flop" size="0x05741e">
+ <rom name="kay10a0s.imd" size="0x05741e" crc="adfb4421" sha1="684758a5ddf467aba3be46c62f59bebcb97bbc1b"/>
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="kay10games">
+ <description>Kaypro 10 Games</description>
+ <year>19??</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <sharedfeat name="compatibility" value="E,C" />
+ <part name="flop" interface="floppy_5_25">
+ <dataarea name="flop" size="0x05d7eb">
+ <rom name="kay10b0a.imd" size="0x05d7eb" crc="f52ac968" sha1="1acc4d20bc1bfd3db8adbc28226bffdf3940c350"/>
+ </dataarea>
+ </part>
+ </software>
+
+<!-- F: 4X,robie (rom 1.7R) -->
+<!-- G: new2,1,omni4 (rom 2.01) -->
+
</softwarelist>
diff --git a/hash/kaypro484.xml b/hash/kaypro484.xml
deleted file mode 100644
index 2450ec1cc55..00000000000
--- a/hash/kaypro484.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
-<!--
-license:CC0
--->
-<softwarelist name="kaypro484" description="Kaypro 4/84 disk images">
-
-<!-- Operating systems -->
-
- <software name="cpm22f">
- <description>CP/M 2.2F (81-292)</description>
- <year>19??</year>
- <publisher>Digital Research</publisher>
- <part name="flop1" interface="floppy_5_25">
- <dataarea name="flop" size="270208">
- <rom name="k4f-292.td0" size="270208" crc="8309cabe" sha1="7eb6829aaadae67b71bf4bfa19ce72f1e780747e"/>
- </dataarea>
- </part>
- </software>
-
- <software name="cpm22g">
- <description>CP/M 2.2G (81-292-A)</description>
- <year>19??</year>
- <publisher>Digital Research</publisher>
- <part name="flop1" interface="floppy_5_25">
- <dataarea name="flop" size="202620">
- <rom name="kp22gdsd.td0" size="202620" crc="6ab35630" sha1="106fb294b719d620abd82ee74f0f16130264e3d1"/>
- </dataarea>
- </part>
- </software>
-
-</softwarelist>
diff --git a/hash/laser2001_flop.xml b/hash/laser2001_flop.xml
new file mode 100644
index 00000000000..7e8cbd4426e
--- /dev/null
+++ b/hash/laser2001_flop.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!DOCTYPE softwarelist SYSTEM "softwarelist.dtd">
+<!--
+license:CC0
+-->
+<softwarelist name="laser2001_flop" description="V-Tech Laser 2001 / Salora Manager disks">
+
+ <software name="kaarme">
+ <description>Käärmepeli (Finland)</description>
+ <year>198?</year>
+ <publisher>Salora</publisher>
+
+ <part name="flop1" interface="floppy_5_25">
+ <dataarea name="flop" size="143360">
+ <rom name="kaarmepeli.img" size="143360" crc="5c32d1ee" sha1="0ab36be0f2bb9c690b5210b20b95a1159246abb6"/>
+ </dataarea>
+ </part>
+ </software>
+
+</softwarelist>
diff --git a/hash/megadriv.xml b/hash/megadriv.xml
index 84cd4317942..7b699c253e6 100644
--- a/hash/megadriv.xml
+++ b/hash/megadriv.xml
@@ -21423,6 +21423,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
</part>
</software>
+ <!-- this 'prototype' set has also been found on a PAL/UK Radica Out Run 2019 Plug & Play unit (see rad_orun in megadriv_rad.cpp) -->
<software name="outr2019up" cloneof="outr2019">
<description>Out Run 2019 (USA, Prototype)</description>
<year>1993</year>
@@ -32994,4 +32995,19 @@ This dump is either a bad dump or a wrongly patched one.
</dataarea>
</part>
</software>
+
+ <!-- Doesn't boot correctly. Needs emulation improvements -->
+ <!-- titan-overdrive2.zip -->
+ <!-- http://www.pouet.net/prod.php?which=69648 -->
+ <software name="d_titov2" supported="no">
+ <description>Overdrive 2 (Demo) (Euro)</description>
+ <year>2017</year>
+ <publisher>Titan</publisher>
+ <part name="cart" interface="megadriv_cart">
+ <feature name="slot" value="rom_ssf2"/>
+ <dataarea name="rom" width="16" endianness="big" size="16777216">
+ <rom name="titan-overdrive2.bin" size="8386056" crc="f0429fd6" sha1="603db0a214ee50c6c11e15c0d1d3bba919116d07" offset="00000"/>
+ </dataarea>
+ </part>
+ </software>
</softwarelist>
diff --git a/hash/pc98_cd.xml b/hash/pc98_cd.xml
index 4013f1e42f8..cd1572eff61 100644
--- a/hash/pc98_cd.xml
+++ b/hash/pc98_cd.xml
@@ -4741,7 +4741,7 @@ license:CC0
<info name="release" value="19951208" />
<part name="cdrom" interface="cdrom">
<diskarea name="cdrom">
- <disk name="toushin toshi ii - soshite, sorekara..." sha1="10ae6ad7d25f19f4af5dc51953c733496b14b5b2" />
+ <disk name="toushin toshi ii - soshite, sorekara" sha1="10ae6ad7d25f19f4af5dc51953c733496b14b5b2" />
</diskarea>
</part>
</software>
diff --git a/hash/sgi_mips.xml b/hash/sgi_mips.xml
index 038de0b5ab9..b735576fbd8 100644
--- a/hash/sgi_mips.xml
+++ b/hash/sgi_mips.xml
@@ -1400,6 +1400,45 @@ license:CC0
</part>
</software>
+ <software name="dev_toolbox_42">
+ <description>Developer Toolbox 4.2</description>
+ <year>1994</year> <!-- 08/94 -->
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="devtoolbox42" sha1="9b85e8d9d35635794408a8ce7d168af96e14bc47" />
+ </diskarea>
+ </part>
+ </software>
+
+ <software name="dev_toolbox_61">
+ <description>Developer Toolbox 6.1</description>
+ <year>1996</year> <!-- 09/96 -->
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom1" interface="cdrom">
+ <feature name="part_id" value="Developer Toolbox 6.1 (CD 0)" />
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="devtoolbox61-0" sha1="191db2ed342be4f514e9be29e8793fbc5718bf77" />
+ </diskarea>
+ </part>
+ <part name="cdrom2" interface="cdrom">
+ <feature name="part_id" value="Developer Toolbox 6.1 (CD 1)" />
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="devtoolbox61-1" sha1="c978ecf1333446424d952646d95ce52b2c20496e" />
+ </diskarea>
+ </part>
+ <part name="cdrom3" interface="cdrom">
+ <feature name="part_id" value="Developer Toolbox 6.1 (CD 2)" />
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="devtoolbox61-2" sha1="928cfe53e856de90a554fe1b82594b119b7b255c" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="dmdo_1_1">
<description>Digital Media Dev Option 1.1</description>
<year>1993</year> <!-- 03/93 -->
@@ -1688,6 +1727,19 @@ license:CC0
<!-- Hot Mix -->
+ <software name="hotmix_1">
+ <description>Hot Mix Volume 1</description>
+ <year>1992</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="812-8101-001"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_1" sha1="3d55993a7ebf9b9d607edda155ac90e78f8c8e09" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="hotmix_4">
<description>Hot Mix 4</description>
<year>1993</year>
@@ -1740,9 +1792,35 @@ license:CC0
</part>
</software>
+ <software name="hotmix_9">
+ <description>Hot Mix Volume 9</description>
+ <year>1994</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="812-8101-009"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_9" sha1="0cac323851e8502eee63283e737d541bf806fa09" />
+ </diskarea>
+ </part>
+ </software>
+
+ <software name="hotmix_10">
+ <description>Hot Mix Volume 10</description>
+ <year>1995</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="812-8101-010"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_10" sha1="97b2604f21474fa376c94ca66f6e465e730e7123" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="hotmix_11">
<description>Hot Mix Volume 11</description>
- <year>1994</year>
+ <year>1995</year>
<publisher>Silicon Graphics</publisher>
<part name="cdrom" interface="cdrom">
<feature name="part_number" value="812-8101-011"/>
@@ -1755,7 +1833,7 @@ license:CC0
<software name="hotmix_12">
<description>Hot Mix Volume 12</description>
- <year>1994</year>
+ <year>1995</year>
<publisher>Silicon Graphics</publisher>
<part name="cdrom" interface="cdrom">
<feature name="part_number" value="812-8101-012"/>
@@ -1766,6 +1844,58 @@ license:CC0
</part>
</software>
+ <software name="hotmix_13">
+ <description>Hot Mix Volume 13</description>
+ <year>1996</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="814-8101-013"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_13" sha1="36360aac69a12728b6716d5f584768db5fad1400" />
+ </diskarea>
+ </part>
+ </software>
+
+ <software name="hotmix_14">
+ <description>Hot Mix Volume 14</description>
+ <year>1996</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="812-0544-003"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_14" sha1="3e3a962260923f58edafd3052b9133789057998c" />
+ </diskarea>
+ </part>
+ </software>
+
+ <software name="hotmix_15">
+ <description>Hot Mix Volume 15</description>
+ <year>1996</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="812-0544-004"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_15" sha1="173163f1366fd729d80857f097fd0b9c1f8778f4" />
+ </diskarea>
+ </part>
+ </software>
+
+ <software name="hotmix_16">
+ <description>Hot Mix Volume 16</description>
+ <year>1997</year>
+ <publisher>Silicon Graphics</publisher>
+ <part name="cdrom" interface="cdrom">
+ <feature name="part_number" value="812-0544-005"/>
+ <!-- Origin: nixzone.nl -->
+ <diskarea name="cdrom">
+ <disk name="hot_mix_16" sha1="47b4d2ad094d204d726c3d9fb2a181e11af7422f" />
+ </diskarea>
+ </part>
+ </software>
+
<software name="hotmix_17">
<description>Hot Mix Volume 17</description>
<year>1997</year>
diff --git a/hash/sorcerer_cass.xml b/hash/sorcerer_cass.xml
index 028a7b60037..d467ca80bab 100644
--- a/hash/sorcerer_cass.xml
+++ b/hash/sorcerer_cass.xml
@@ -133,7 +133,7 @@ Compiled by Robbbert
<info name="usage" value="In Basic, BYE then LOG" />
<part name="cass" interface="sorcerer_cass">
<dataarea name="cass" size="12103836">
- <rom name="salvo.wav" size="12103836" crc="07925abd" sha1="cde6fa8c9da41eee8db6c7c936f9bb61c5591ae6" />
+ <rom name="milen.wav" size="12103836" crc="07925abd" sha1="cde6fa8c9da41eee8db6c7c936f9bb61c5591ae6" />
</dataarea>
</part>
</software>
@@ -1223,4 +1223,215 @@ Compiled by Robbbert
</dataarea>
</part>
</software>
+ <!-- Added 2020-10-08 -->
+ <software name="atc1">
+ <description>Air Traffic Controller (Mt Purscent)</description>
+ <year>19??</year>
+ <publisher>Creative Computing</publisher>
+ <info name="developer" value="David Mannering"/>
+ <info name="usage" value="Boot to Monitor, LOG" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x230d90">
+ <rom name="atc1.wav" size="0x230d90" crc="a519090b" sha1="655f751500c08977b26a50199e06ab212342619d" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="arith">
+ <description>Arithmetic CAI</description>
+ <year>1981</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="Peter Aird"/>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0xda8814">
+ <rom name="arith.wav" size="0xda8814" crc="711c3429" sha1="f6f740d5ddd2d25c7a32bf2b821674ace16990fd" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="aster">
+ <description>Asteroids</description>
+ <year>1980</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="J.T.Staley"/>
+ <info name="usage" value="Boot to Monitor, LOG" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x76f3f2">
+ <rom name="aster.wav" size="0x76f3f2" crc="3b2732fd" sha1="feac5acbb5298ba67d6cdd300c199e0beb841f65" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="biochart">
+ <description>Biochart</description>
+ <year>19??</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x6123de">
+ <rom name="biochart.wav" size="0x6123de" crc="bc4e0723" sha1="bb9302bdda3365ff3269caecd0ea233ff763c826" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="biorhythm">
+ <description>Bio-Rhythm</description>
+ <year>19??</year>
+ <publisher>Micro Software</publisher>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x5ac182">
+ <rom name="biorhythm.wav" size="0x5ac182" crc="bbe0f0ce" sha1="1709c4fa65b5f9c7b887cf1d63c3f3b6d6383bd1" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="blackj">
+ <description>Black Jack</description>
+ <year>1979</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="J.T.Staley"/>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x7c0ecc">
+ <rom name="blackj.wav" size="0x7c0ecc" crc="1591a2c8" sha1="36ae79e27299cc694d6562c7c3d97d7189d645b5" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="cadas">
+ <description>Cassette Disk database system</description>
+ <year>1981</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="Jim Stafford"/>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x602f6a">
+ <rom name="cadas.wav" size="0x602f6a" crc="8ee689bd" sha1="5c6bc70ec8a79aea00ca6e3ec9efe2bc82f05c69" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="com48">
+ <description>Basic Compiler v1.21</description>
+ <year>1982</year>
+ <publisher>System Software</publisher>
+ <info name="usage" value="Boot to Monitor, LOG" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x11fff26">
+ <rom name="com48.wav" size="0x11fff26" crc="db015584" sha1="593ee5afa5ac1721955e35af38e7f1152831c963" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="dybug">
+ <description>DYBUG2</description>
+ <year>1981</year>
+ <publisher>Global Software Network</publisher>
+ <info name="developer" value="M. E. Sevior"/>
+ <info name="usage" value="Boot to Monitor, LOG" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x3ad9d4">
+ <rom name="dybug2.wav" size="0x3ad9d4" crc="35471c94" sha1="b951c8ccbd3ac509fcb89916820dcce414e14cfb" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="flip">
+ <description>Flip</description>
+ <year>1979</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="J.T.Staley"/>
+ <info name="usage" value="In Basic, CLOAD then RUN. To pass, press Enter." />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x82aa64">
+ <rom name="flip.wav" size="0x82aa64" crc="e750993a" sha1="4cf9b56e226727935e8eb887c10434decc48a9d7" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="homerun">
+ <description>Home Run</description>
+ <year>1979</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="J.T.Staley"/>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x80084c">
+ <rom name="homerun.wav" size="0x80084c" crc="e64c9407" sha1="b9f7f1f31e9bfdaf23ff54437459db815dd496ac" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="wumpus">
+ <description>Hunt the Wumpus</description>
+ <year>19??</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="Duncan Craven"/>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x277880">
+ <rom name="wumpus.wav" size="0x277880" crc="122511b8" sha1="03a1478b5e845550b0b3daf24a5ab6d05cf9c786" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="kalid">
+ <description>Kaleidoscope</description>
+ <year>19??</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x191144">
+ <rom name="kalid.wav" size="0x191144" crc="d075ae97" sha1="08ace76909a0d4c26642c1533cfcdb4a33ed5de7" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="ldg">
+ <description>Lost Dutchman's Gold</description>
+ <year>1981</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0xbeb07c">
+ <rom name="ldg.wav" size="0xbeb07c" crc="4e57455f" sha1="badcea2a991543dda5bbac0be0f69a5650657fda" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="robot">
+ <description>Robot Attack (ported from TRS-80)</description>
+ <year>1981</year>
+ <publisher>Big Five Software</publisher>
+ <info name="developer" value="Bill Hogue and Jeff Konyu"/>
+ <info name="usage" value="Boot to Monitor, LOG. Esc+F5 to escape from demo. Esc to skip the intro. 1 or 2 to start. Arrows to move, F and arrow to fire." />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0xd7442c">
+ <rom name="robot.wav" size="0xd7442c" crc="2edd199f" sha1="3916a5a96c57766bcee9aa56a08abe5c2ba8ee57" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="apatrol">
+ <description>Armored Patrol</description>
+ <year>1981</year>
+ <publisher>Adventure International</publisher>
+ <info name="developer" value="Wayne Westmoreland and Terry Gilman"/>
+ <info name="usage" value="Boot to Monitor, LOG. Z=left .=right, space=fire" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0xd0742c">
+ <rom name="tank.wav" size="0xd0742c" crc="db36467d" sha1="3b590f470de8f0cc7d604f0b07ddf2bd8290aed8" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="mmind">
+ <description>Mastermind</description>
+ <year>1979</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="developer" value="M. S. Warden"/>
+ <info name="usage" value="In Basic, CLOAD then RUN" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0xa11572">
+ <rom name="mastermind.wav" size="0xa11572" crc="53bc223b" sha1="0b248697fd362de954cb282307e7293c2f5a3d0a" />
+ </dataarea>
+ </part>
+ </software>
+ <software name="dterm">
+ <description>The Sorcerer Dumb Terminal</description>
+ <year>19??</year>
+ <publisher>&lt;unknown&gt;</publisher>
+ <info name="usage" value="Boot to Monitor, LOG" />
+ <part name="cass" interface="sorcerer_cass">
+ <dataarea name="cass" size="0x215dd6">
+ <rom name="dterm.wav" size="0x215dd6" crc="9d2cc9eb" sha1="e04df986039b804ae1589376fb89ca62d1684e90" />
+ </dataarea>
+ </part>
+ </software>
</softwarelist>
diff --git a/hash/vgmplay.xml b/hash/vgmplay.xml
index 9ef3c6e9396..626200da21f 100644
--- a/hash/vgmplay.xml
+++ b/hash/vgmplay.xml
@@ -1080,194 +1080,194 @@ license:CC0
</software>
<software name="lemmings_pc">
- <description>Lemmings DOS (PC)</description>
+ <description>Lemmings Series (IBM PC AT)</description>
<year>1991</year>
<publisher>Psygnosis</publisher>
<info name="cores" value="AdLib/OPL2 (YM3812)"/>
<part name="001" interface="vgm_quik">
- <feature name="part_id" value="00_lets_go.vgm" />
- <dataarea name="quik" size="388">
- <rom name="00_lets_go.vgm" size="388" crc="fd4517e7" sha1="a27625356dfb2a5f23b2b6d7b75864ba41ea0881" offset="0" />
+ <feature name="part_id" value="01 let's go.vgz" />
+ <dataarea name="quik" size="381">
+ <rom name="01 let's go.vgz" size="381" crc="1cd45b3f" sha1="9722d0a0f75c96a2d93d781309486007d7373597" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
- <feature name="part_id" value="01_lemming1.vgm" />
- <dataarea name="quik" size="1998">
- <rom name="01_lemming1.vgm" size="1998" crc="7309bb2f" sha1="129526a6dd891914edcc3269de301f1d67f79a37" offset="0" />
+ <feature name="part_id" value="02 lemming 1.vgz" />
+ <dataarea name="quik" size="1986">
+ <rom name="02 lemming 1.vgz" size="1986" crc="3c14583e" sha1="e1dfa7c444ecbe7cd547ece0a874eb9c02e2459b" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
- <feature name="part_id" value="02_lemming2.vgm" />
- <dataarea name="quik" size="3138">
- <rom name="02_lemming2.vgm" size="3138" crc="83bc1e4b" sha1="1d93016f7fcaf4bda140a7242182a45d89e656f2" offset="0" />
+ <feature name="part_id" value="03 lemming 2.vgz" />
+ <dataarea name="quik" size="3129">
+ <rom name="03 lemming 2.vgz" size="3129" crc="e9768a1f" sha1="33045a56ed0d90becf12a67420c643404abef787" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
- <feature name="part_id" value="03_lemming3.vgm" />
- <dataarea name="quik" size="2470">
- <rom name="03_lemming3.vgm" size="2470" crc="5d10c10a" sha1="5a9ebf9e122c2e1de9407d18740e0b4632c978f4" offset="0" />
+ <feature name="part_id" value="04 lemming 3.vgz" />
+ <dataarea name="quik" size="2461">
+ <rom name="04 lemming 3.vgz" size="2461" crc="f3391209" sha1="b3af817f519aa1d63cb258f71faa382c6bbbdffa" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
- <feature name="part_id" value="04_mountain.vgm" />
- <dataarea name="quik" size="2531">
- <rom name="04_mountain.vgm" size="2531" crc="7f322aed" sha1="5ff166270df35c40d458697db4dfa2177bffd1e5" offset="0" />
+ <feature name="part_id" value="05 she'll be coming 'round the mountain when she comes.vgz" />
+ <dataarea name="quik" size="2519">
+ <rom name="05 she'll be coming 'round the mountain when she comes.vgz" size="2519" crc="8ab26792" sha1="af52855032547fef73a2058a7b89294449161519" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
- <feature name="part_id" value="05_tenlemmings.vgm" />
- <dataarea name="quik" size="2093">
- <rom name="05_tenlemmings.vgm" size="2093" crc="e9f55ab9" sha1="51ebd14ff4dcd5bed421f0a3ed59c81a52d99271" offset="0" />
+ <feature name="part_id" value="06 ten lemmings.vgz" />
+ <dataarea name="quik" size="2083">
+ <rom name="06 ten lemmings.vgz" size="2083" crc="83fcd3ac" sha1="c5b9b8efdde45688f3dcd0d3e1d3332fd24d6f67" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
- <feature name="part_id" value="06_cancan.vgm" />
- <dataarea name="quik" size="1462">
- <rom name="06_cancan.vgm" size="1462" crc="281f6a99" sha1="1d5a4e104ab7b494194b1fe095748859aff2205d" offset="0" />
+ <feature name="part_id" value="07 can-can.vgz" />
+ <dataarea name="quik" size="1450">
+ <rom name="07 can-can.vgz" size="1450" crc="47851c5c" sha1="fb6b8feaa6edf6af1bc55f361f053b7e97f41a92" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
- <feature name="part_id" value="07_tim1.vgm" />
- <dataarea name="quik" size="1302">
- <rom name="07_tim1.vgm" size="1302" crc="1a354aa9" sha1="e1cd181e350489dfa6207485279563407edaaed6" offset="0" />
+ <feature name="part_id" value="08 tim 1.vgz" />
+ <dataarea name="quik" size="2289">
+ <rom name="08 tim 1.vgz" size="2289" crc="e611cf45" sha1="cb833616bb372f288a0a03dc044fbe5f20195895" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
- <feature name="part_id" value="08_tim2.vgm" />
- <dataarea name="quik" size="1411">
- <rom name="08_tim2.vgm" size="1411" crc="bb76f32f" sha1="38b9f090722ce655ea55014dae6a008fb67109ff" offset="0" />
+ <feature name="part_id" value="09 tim 2.vgz" />
+ <dataarea name="quik" size="1400">
+ <rom name="09 tim 2.vgz" size="1400" crc="b9112a88" sha1="d1e34fcd678552c63d0b0d38e0f8dcd77a4f9f63" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
- <feature name="part_id" value="09_tim3.vgm" />
- <dataarea name="quik" size="1396">
- <rom name="09_tim3.vgm" size="1396" crc="a9ac3636" sha1="b3fc28337cb2c02835b9e00e7b32b9911737c5b5" offset="0" />
+ <feature name="part_id" value="10 tim 3.vgz" />
+ <dataarea name="quik" size="1386">
+ <rom name="10 tim 3.vgz" size="1386" crc="c78b6270" sha1="7ed1010f6ff3fbbfb37beb18c897ff4ae7df5e28" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
- <feature name="part_id" value="10_tim4.vgm" />
- <dataarea name="quik" size="1972">
- <rom name="10_tim4.vgm" size="1972" crc="37a2f25e" sha1="ea4ba5c06eace34e2a3a1a1f1087292d27abec88" offset="0" />
+ <feature name="part_id" value="11 tim 4.vgz" />
+ <dataarea name="quik" size="1963">
+ <rom name="11 tim 4.vgz" size="1963" crc="530ffd29" sha1="a394fbfa6db07fa630d010839cbf1fc0028c10ac" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
- <feature name="part_id" value="11_doggie.vgm" />
- <dataarea name="quik" size="1919">
- <rom name="11_doggie.vgm" size="1919" crc="42c0df19" sha1="1da933af320b27709486cd789308482e52801150" offset="0" />
+ <feature name="part_id" value="12 that doggy in the window.vgz" />
+ <dataarea name="quik" size="1872">
+ <rom name="12 that doggy in the window.vgz" size="1872" crc="15e318f0" sha1="4e905549c7f85203739caec0eaa82140360bba56" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
- <feature name="part_id" value="12_tim5.vgm" />
- <dataarea name="quik" size="2166">
- <rom name="12_tim5.vgm" size="2166" crc="91603037" sha1="08ae5308259336c09dccc46fdd2e772fea8f8e3c" offset="0" />
+ <feature name="part_id" value="13 tim 5.vgz" />
+ <dataarea name="quik" size="2158">
+ <rom name="13 tim 5.vgz" size="2158" crc="8b44d97d" sha1="94c76ed8ce93cf498864119f45c4c0981c04a0cc" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
- <feature name="part_id" value="13_tim6.vgm" />
- <dataarea name="quik" size="1958">
- <rom name="13_tim6.vgm" size="1958" crc="c77cee66" sha1="94412edefdc94f9e087aa299cc8a8bc6d65ede5c" offset="0" />
+ <feature name="part_id" value="14 tim 6 - dance of the reed-flutes.vgz" />
+ <dataarea name="quik" size="1949">
+ <rom name="14 tim 6 - dance of the reed-flutes.vgz" size="1949" crc="31a41e13" sha1="15501b7a85ff1c43cb05a85721f379f82e7d44c9" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
- <feature name="part_id" value="14_tim7.vgm" />
- <dataarea name="quik" size="1587">
- <rom name="14_tim7.vgm" size="1587" crc="352c7bb0" sha1="01f553ba9cb1581fcd7a192e9ab87a12c3ab66ba" offset="0" />
+ <feature name="part_id" value="15 tim 7 - ronda alla turca.vgz" />
+ <dataarea name="quik" size="1578">
+ <rom name="15 tim 7 - ronda alla turca.vgz" size="1578" crc="9961091f" sha1="e55ca8f60971dde6e40591771ab70bb25be63865" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
- <feature name="part_id" value="15_tim8.vgm" />
- <dataarea name="quik" size="1428">
- <rom name="15_tim8.vgm" size="1428" crc="258d1ad4" sha1="a9ffa5b05a73f5b033179b4b59ef78dfbbbdebab" offset="0" />
+ <feature name="part_id" value="16 tim 8 - dance of the four little swans.vgz" />
+ <dataarea name="quik" size="1420">
+ <rom name="16 tim 8 - dance of the four little swans.vgz" size="1420" crc="7a89a413" sha1="47cf7817edbf937486c76aa739da3954313149ec" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
- <feature name="part_id" value="16_tim9.vgm" />
- <dataarea name="quik" size="1614">
- <rom name="16_tim9.vgm" size="1614" crc="07cb69d4" sha1="d1a1a91e609d08964c122616711abcacd56bc56b" offset="0" />
+ <feature name="part_id" value="17 tim 9 - london bridge is falling down.vgz" />
+ <dataarea name="quik" size="1604">
+ <rom name="17 tim 9 - london bridge is falling down.vgz" size="1604" crc="806fb6d2" sha1="41db2a2777b6025e7828c2122cdd7df57b444514" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
- <feature name="part_id" value="17_tim10.vgm" />
+ <feature name="part_id" value="18 tim 10 - forest green.vgz" />
<dataarea name="quik" size="1391">
- <rom name="17_tim10.vgm" size="1391" crc="cb1a8cea" sha1="52c4500db3cc7afe521a383f2778ab00f5265703" offset="0" />
+ <rom name="18 tim 10 - forest green.vgz" size="1391" crc="fade4df8" sha1="ebba864efa9e8dd8853ef3b6964523c6b67975c0" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
- <feature name="part_id" value="18_beast.vgm" />
- <dataarea name="quik" size="1567">
- <rom name="18_beast.vgm" size="1567" crc="025e2c18" sha1="a1749edc08e26658c345eae8646c2a2790fcefd6" offset="0" />
+ <feature name="part_id" value="19 beast.vgz" />
+ <dataarea name="quik" size="1561">
+ <rom name="19 beast.vgz" size="1561" crc="593abb78" sha1="611e8cd727b5452e252cd9962428139975a44e2d" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
- <feature name="part_id" value="19_menace.vgm" />
- <dataarea name="quik" size="2304">
- <rom name="19_menace.vgm" size="2304" crc="1d35d84e" sha1="9c8c4ad08bb961d4e0c50a5f20d803f561e33727" offset="0" />
+ <feature name="part_id" value="20 menace.vgz" />
+ <dataarea name="quik" size="2296">
+ <rom name="20 menace.vgz" size="2296" crc="b708644f" sha1="4e3f528c50b8140c7e28e094e75282a21bf05c7a" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
- <feature name="part_id" value="20_awesome.vgm" />
- <dataarea name="quik" size="1542">
- <rom name="20_awesome.vgm" size="1542" crc="fcf9a852" sha1="7628c797633ffa38a39b79616825aaf27270bea1" offset="0" />
+ <feature name="part_id" value="21 awesome.vgz" />
+ <dataarea name="quik" size="1533">
+ <rom name="21 awesome.vgz" size="1533" crc="c25aa6ac" sha1="a29b094be1b42610354ffb27aeba67ee24c9b2ff" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
- <feature name="part_id" value="21_beastii.vgm" />
- <dataarea name="quik" size="1944">
- <rom name="21_beastii.vgm" size="1944" crc="030aef52" sha1="9ecec87fdf51e58de40f61d08f9d82abb19e126f" offset="0" />
+ <feature name="part_id" value="22 beastii.vgz" />
+ <dataarea name="quik" size="1935">
+ <rom name="22 beastii.vgz" size="1935" crc="84512822" sha1="2d7d2a997f552e5775ea0d6108a88e9fece1c83a" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
- <feature name="part_id" value="d1_cancan.vgm" />
- <dataarea name="quik" size="2421">
- <rom name="d1_cancan.vgm" size="2421" crc="a71b2b19" sha1="9dbf41a0d6d5c987c8a0488f892982f8ffb97f95" offset="0" />
+ <feature name="part_id" value="23 very cute.vgz" />
+ <dataarea name="quik" size="2155">
+ <rom name="23 very cute.vgz" size="2155" crc="c5aeca30" sha1="deb1aa92d65818171a3bc68988128604906427a1" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
- <feature name="part_id" value="o1_tune1.vgm" />
- <dataarea name="quik" size="2156">
- <rom name="o1_tune1.vgm" size="2156" crc="4d3a5cd5" sha1="41327bb979188dabef98dc0ced5d3510639e5ef4" offset="0" />
+ <feature name="part_id" value="24 wacky.vgz" />
+ <dataarea name="quik" size="2673">
+ <rom name="24 wacky.vgz" size="2673" crc="732381cf" sha1="be306cad0824a635728a2a9d5ad5421040451cd7" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
- <feature name="part_id" value="o2_tune2.vgm" />
- <dataarea name="quik" size="2676">
- <rom name="o2_tune2.vgm" size="2676" crc="b1f9c4aa" sha1="5a46bcb5b8d2ec8ca67932e10c1b64ae9f923a90" offset="0" />
+ <feature name="part_id" value="25 patronizingly happy.vgz" />
+ <dataarea name="quik" size="2675">
+ <rom name="25 patronizingly happy.vgz" size="2675" crc="c6c2e12a" sha1="0cda095c593049531ce8a30adb7b57665e86355c" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
- <feature name="part_id" value="o3_tune3.vgm" />
- <dataarea name="quik" size="2658">
- <rom name="o3_tune3.vgm" size="2658" crc="9601f166" sha1="d537ce7760f09a8f410dbaa160592d3d9446c3b7" offset="0" />
+ <feature name="part_id" value="26 the smiling blues.vgz" />
+ <dataarea name="quik" size="2261">
+ <rom name="26 the smiling blues.vgz" size="2261" crc="fc43eede" sha1="0e1a1c684547476112cd006cb4322e19284c18b0" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
- <feature name="part_id" value="o4_tune4.vgm" />
- <dataarea name="quik" size="2257">
- <rom name="o4_tune4.vgm" size="2257" crc="51d8fc99" sha1="64a35a6bb67eccf1246d250a766ce9c7e907c4ce" offset="0" />
+ <feature name="part_id" value="27 much joviality.vgz" />
+ <dataarea name="quik" size="2818">
+ <rom name="27 much joviality.vgz" size="2818" crc="c2791eec" sha1="103bf60325309f245c17353baba25fe4a7b7dfde" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
- <feature name="part_id" value="o5_tune5.vgm" />
- <dataarea name="quik" size="2810">
- <rom name="o5_tune5.vgm" size="2810" crc="206d0080" sha1="55f3dd16ad8577fbdf570bcf202d9c18bd92a982" offset="0" />
+ <feature name="part_id" value="28 not at all serious.vgz" />
+ <dataarea name="quik" size="1760">
+ <rom name="28 not at all serious.vgz" size="1760" crc="c3621198" sha1="22ccaadbf3b38e1fa83b3ab923c418954abd95c2" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
- <feature name="part_id" value="o6_tune6.vgm" />
- <dataarea name="quik" size="1746">
- <rom name="o6_tune6.vgm" size="1746" crc="bd7f37d3" sha1="cb77103a89cd4632d3a5bc2edaab29a4440cbe19" offset="0" />
+ <feature name="part_id" value="29 jingle bells.vgz" />
+ <dataarea name="quik" size="2469">
+ <rom name="29 jingle bells.vgz" size="2469" crc="43521e14" sha1="9e7b7dfe58257292373d87135013bd20cc7c647c" offset="0" />
</dataarea>
</part>
<part name="030" interface="vgm_quik">
- <feature name="part_id" value="x01_jb.vgm" />
- <dataarea name="quik" size="2480">
- <rom name="x01_jb.vgm" size="2480" crc="2011c208" sha1="6356185f4d6360efc372c39929b556cebf2855f7" offset="0" />
+ <feature name="part_id" value="30 good king wenceslas.vgz" />
+ <dataarea name="quik" size="1676">
+ <rom name="30 good king wenceslas.vgz" size="1676" crc="a155deb2" sha1="7ec20477c5aedf196770c910d2c2bbe83ef000c9" offset="0" />
</dataarea>
</part>
<part name="031" interface="vgm_quik">
- <feature name="part_id" value="x02_gkw.vgm" />
- <dataarea name="quik" size="1694">
- <rom name="x02_gkw.vgm" size="1694" crc="d3050d21" sha1="940780da432ab36637d8da2ba38d6896d49bf47f" offset="0" />
+ <feature name="part_id" value="31 can-can.vgz" />
+ <dataarea name="quik" size="2413">
+ <rom name="31 can-can.vgz" size="2413" crc="14b82d5e" sha1="e73b5ac0289ba1fc8e62735aa2820a0914faec4d" offset="0" />
</dataarea>
</part>
</software>
@@ -33559,116 +33559,116 @@ license:CC0
<info name="cores" value="QSound"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 element in the story (opening).vgz" />
- <dataarea name="quik" size="610766">
- <rom name="01 element in the story (opening).vgz" size="610766" crc="d1fba354" sha1="81de8475197010711605547616ff241488980be1" offset="0" />
+ <dataarea name="quik" size="610775">
+ <rom name="01 element in the story (opening).vgz" size="610775" crc="5f6790a8" sha1="875a361baead2d840fac8888300c635166ddb249" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 credit.vgz" />
- <dataarea name="quik" size="28168">
- <rom name="02 credit.vgz" size="28168" crc="29d40ab9" sha1="da6b103e37a028298701cffaaae9d60c05f5976b" offset="0" />
+ <dataarea name="quik" size="28170">
+ <rom name="02 credit.vgz" size="28170" crc="a231763b" sha1="a8598d207f53bd8c2a50c60bc7b45d3ba696bcc1" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 purple advance (character select).vgz" />
- <dataarea name="quik" size="292869">
- <rom name="03 purple advance (character select).vgz" size="292869" crc="bdf64ee4" sha1="d0e36b067331bb40d5eae3161ab121574cbd3efc" offset="0" />
+ <dataarea name="quik" size="292856">
+ <rom name="03 purple advance (character select).vgz" size="292856" crc="4854c69a" sha1="7c9c8fa0b3176284f95ccc66300ddb2f930e58b3" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 scramble! (stage 1).vgz" />
- <dataarea name="quik" size="577188">
- <rom name="04 scramble (stage 1).vgz" size="577188" crc="a958966c" sha1="b62494f2e2712eff191f58380b42b1d180087883" offset="0" />
+ <dataarea name="quik" size="577186">
+ <rom name="04 scramble (stage 1).vgz" size="577186" crc="490fed87" sha1="bbb2de7eecf8d29e3b0b912b2cba33fb2769fb62" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 black fight (boss 1).vgz" />
- <dataarea name="quik" size="637867">
- <rom name="05 black fight (boss 1).vgz" size="637867" crc="079453c7" sha1="19a8aad58bca699029a1b3ec68965819d53f36ae" offset="0" />
+ <dataarea name="quik" size="637866">
+ <rom name="05 black fight (boss 1).vgz" size="637866" crc="1a428b3f" sha1="b5a7b4f0546b163eb17fcdee01ead6dd800d5512" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 critical attack (stage clear).vgz" />
- <dataarea name="quik" size="502347">
- <rom name="06 critical attack (stage clear).vgz" size="502347" crc="74f5734d" sha1="cbd6d4a5d8097cb34415eaaa879225404e7629ee" offset="0" />
+ <dataarea name="quik" size="502356">
+ <rom name="06 critical attack (stage clear).vgz" size="502356" crc="835a0777" sha1="14ea11ad834527cb7c6a315fdd12f909c967dbb9" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 iron knuckle (stage 2).vgz" />
- <dataarea name="quik" size="845106">
- <rom name="07 iron knuckle (stage 2).vgz" size="845106" crc="6e498b17" sha1="c71fdc0a2495d967e6ffa493aca9d1a60a2819b7" offset="0" />
+ <dataarea name="quik" size="845109">
+ <rom name="07 iron knuckle (stage 2).vgz" size="845109" crc="6ece8f62" sha1="763c78838b0c72a357a0fe3dbd4c6f60db75f139" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 bold trap (boss 2).vgz" />
- <dataarea name="quik" size="429989">
- <rom name="08 bold trap (boss 2).vgz" size="429989" crc="48c17346" sha1="1024324877cac8c884b87c965230b11fd2ad6f15" offset="0" />
+ <dataarea name="quik" size="430026">
+ <rom name="08 bold trap (boss 2).vgz" size="430026" crc="85a41c9b" sha1="f468fc77fa8e9f246b7ce5dfc5aacc13bcdd46df" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 overwhelming existence (stage 3).vgz" />
- <dataarea name="quik" size="444982">
- <rom name="09 overwhelming existence (stage 3).vgz" size="444982" crc="6848d23a" sha1="1fa1bc1a77641cf547009b37d028acac554b344b" offset="0" />
+ <dataarea name="quik" size="444985">
+ <rom name="09 overwhelming existence (stage 3).vgz" size="444985" crc="904ed603" sha1="9a721262820a17d85e38e515ab928a6cefe6eb38" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 velvet fire (stage 4).vgz" />
- <dataarea name="quik" size="415940">
- <rom name="10 velvet fire (stage 4).vgz" size="415940" crc="49828b6e" sha1="d05d06efef0834b5aa2bf6a6028b44854efb0126" offset="0" />
+ <dataarea name="quik" size="415942">
+ <rom name="10 velvet fire (stage 4).vgz" size="415942" crc="5ebf2b8a" sha1="1e84f1957ae557ea21ebe02201ea296659f4ae7f" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 thunder storm (stage 5).vgz" />
- <dataarea name="quik" size="877504">
- <rom name="11 thunder storm (stage 5).vgz" size="877504" crc="db556f2e" sha1="2500d8d451b2a199e408c45ad4d122c625da9215" offset="0" />
+ <dataarea name="quik" size="877506">
+ <rom name="11 thunder storm (stage 5).vgz" size="877506" crc="12ba3206" sha1="bab161f1dddfeec275c6b13b86649b87065ef7cb" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 the genius of battle (rival).vgz" />
- <dataarea name="quik" size="525526">
- <rom name="12 the genius of battle (rival).vgz" size="525526" crc="6c95eca0" sha1="2068732da54df07a2747ae4c20d541fc712ce1b0" offset="0" />
+ <dataarea name="quik" size="525551">
+ <rom name="12 the genius of battle (rival).vgz" size="525551" crc="a4d68eca" sha1="67c0b1573ebab28ccef4f73ca4a14a04a581e168" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 dark plot (stage 6).vgz" />
- <dataarea name="quik" size="457248">
- <rom name="13 dark plot (stage 6).vgz" size="457248" crc="35ac1ad1" sha1="94b5447661b975fa3c6a8e22626f4884e169ed7f" offset="0" />
+ <dataarea name="quik" size="457257">
+ <rom name="13 dark plot (stage 6).vgz" size="457257" crc="846524ce" sha1="1703648a0f1b72701d4fa9f3d9967ba654d4fbee" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 dark sky (boss 3(last)).vgz" />
- <dataarea name="quik" size="863455">
- <rom name="14 dark sky (boss 3(last)).vgz" size="863455" crc="5e6c455c" sha1="59c6ba98af5913058be05b6be9a5e8b381894c0b" offset="0" />
+ <dataarea name="quik" size="863478">
+ <rom name="14 dark sky (boss 3(last)).vgz" size="863478" crc="ec52cf23" sha1="5a2caf14b6566ddb1ba7f2aeac126f718d96359a" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 perfect medicine (last stage clear).vgz" />
- <dataarea name="quik" size="360551">
- <rom name="15 perfect medicine (last stage clear).vgz" size="360551" crc="18e4d9e8" sha1="4a01fac50ce4d1f5626b65c22c9529ba88f1355d" offset="0" />
+ <dataarea name="quik" size="360568">
+ <rom name="15 perfect medicine (last stage clear).vgz" size="360568" crc="40ab18ed" sha1="817da296975737dea64e51ae7b9909965b635bd4" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 soft machine (ending).vgz" />
- <dataarea name="quik" size="792535">
- <rom name="16 soft machine (ending).vgz" size="792535" crc="3f2f7ef5" sha1="6971b2fcf2bb8a8a345eb9b826a12b54c4b90e8e" offset="0" />
+ <dataarea name="quik" size="792545">
+ <rom name="16 soft machine (ending).vgz" size="792545" crc="ddecf603" sha1="7ea1823de38ae21cfbebebd4b33b54bb797bf759" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 broken body (game over).vgz" />
- <dataarea name="quik" size="374569">
- <rom name="17 broken body (game over).vgz" size="374569" crc="2b7b8fec" sha1="d6f7c88b1424491a543734cb7f162738a7e6fbbe" offset="0" />
+ <dataarea name="quik" size="374572">
+ <rom name="17 broken body (game over).vgz" size="374572" crc="a9d1f24f" sha1="966d46dbfb8215cf6d3973ebe365a623d0ac7583" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 mechanical petrifaction (ranking).vgz" />
- <dataarea name="quik" size="245986">
- <rom name="18 mechanical petrifaction (ranking).vgz" size="245986" crc="0361718a" sha1="22d42bff103d4240a33fa1d49671f82eb2531fab" offset="0" />
+ <dataarea name="quik" size="245975">
+ <rom name="18 mechanical petrifaction (ranking).vgz" size="245975" crc="30cdcce0" sha1="633ba024286cfd6177664716f2673eba2d12ac35" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 speaker check.vgz" />
- <dataarea name="quik" size="104747">
- <rom name="19 speaker check.vgz" size="104747" crc="dad4b7bf" sha1="b66505fe1f37156590cbe2656753a0e5d65e7cd9" offset="0" />
+ <dataarea name="quik" size="104763">
+ <rom name="19 speaker check.vgz" size="104763" crc="68d728b1" sha1="bcac570981b6b9261a4dad75d436c4744668b808" offset="0" />
</dataarea>
</part>
</software>
@@ -37137,194 +37137,194 @@ license:CC0
<info name="cores" value="QSound"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 qsound logo.vgz" />
- <dataarea name="quik" size="79892">
- <rom name="01 qsound logo.vgz" size="79892" crc="a684b89c" sha1="cf43e39590af8d616acda19327ebd759d7b2c5fd" offset="0" />
+ <dataarea name="quik" size="79899">
+ <rom name="01 qsound logo.vgz" size="79899" crc="d0ed0126" sha1="f53812885e2a5233d0f731704d0e96f0d2b064e9" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 title.vgz" />
- <dataarea name="quik" size="212029">
- <rom name="02 title.vgz" size="212029" crc="5f389978" sha1="7c182a61ada8097c07b41d6c4f049914373ae676" offset="0" />
+ <dataarea name="quik" size="212031">
+ <rom name="02 title.vgz" size="212031" crc="fea03a2a" sha1="acba3f8debb02f2b7a36423ddb201a4c0ad3c675" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 player select.vgz" />
- <dataarea name="quik" size="85294">
- <rom name="03 player select.vgz" size="85294" crc="03603315" sha1="666bef89c7cd228b148953d3c5b3be589bab53fc" offset="0" />
+ <dataarea name="quik" size="85283">
+ <rom name="03 player select.vgz" size="85283" crc="ef9dd40b" sha1="03909e7bc1aba230fca4f7dd401806c6b883587f" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 stage select (mega man 1-2).vgz" />
- <dataarea name="quik" size="132004">
- <rom name="04 stage select (mega man 1-2).vgz" size="132004" crc="06056c45" sha1="13e9ec787aaf510e45b3524401a9ed6494934c40" offset="0" />
+ <dataarea name="quik" size="132006">
+ <rom name="04 stage select (mega man 1-2).vgz" size="132006" crc="620548d6" sha1="52deec016e0aaefffdd655bf3359495f62fec3c3" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 stage starting.vgz" />
- <dataarea name="quik" size="141888">
- <rom name="05 stage starting.vgz" size="141888" crc="ac994a50" sha1="edfedde8cf1385737577464cce992b0d18e71711" offset="0" />
+ <dataarea name="quik" size="141887">
+ <rom name="05 stage starting.vgz" size="141887" crc="5faf8307" sha1="08ce14968b766768cd31627426dc8ee916d068e2" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 stage 1 (napalm man).vgz" />
<dataarea name="quik" size="164668">
- <rom name="06 stage 1 (napalm man).vgz" size="164668" crc="aa8846ea" sha1="20cffa8cbf1a0e6765cd7f2ec8e8ea8354666dc9" offset="0" />
+ <rom name="06 stage 1 (napalm man).vgz" size="164668" crc="0b056c70" sha1="a357c46a01b1b099b94b833a3efad8d73357ee33" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 stage 2 (crash man).vgz" />
- <dataarea name="quik" size="307188">
- <rom name="07 stage 2 (crash man).vgz" size="307188" crc="8dbbcd5c" sha1="38726f8003fc2c21cc02453ebe201af68344116b" offset="0" />
+ <dataarea name="quik" size="307186">
+ <rom name="07 stage 2 (crash man).vgz" size="307186" crc="7304e4a4" sha1="c34349929b1814e7b506c76a4f503cbd9db3694e" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 stage 3 (guts man).vgz" />
- <dataarea name="quik" size="227545">
- <rom name="08 stage 3 (guts man).vgz" size="227545" crc="aaf0cddd" sha1="ff7c5ff13db5aba5cd215683a5674cdfc14759a9" offset="0" />
+ <dataarea name="quik" size="227530">
+ <rom name="08 stage 3 (guts man).vgz" size="227530" crc="7d282426" sha1="a75f7a42abc4ff0c8b2c9a8e8c5a2d4308b036d6" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 stage select (mega man 3-6).vgz" />
- <dataarea name="quik" size="128202">
- <rom name="09 stage select (mega man 3-6).vgz" size="128202" crc="6033d0e7" sha1="4a59d7304aa0af100b81a2668e77818024b6dff7" offset="0" />
+ <dataarea name="quik" size="128194">
+ <rom name="09 stage select (mega man 3-6).vgz" size="128194" crc="1916889a" sha1="47e35861cb2ed4bfe3c631ec00728a04f4be82b1" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 stage 4 (gyro man).vgz" />
- <dataarea name="quik" size="319264">
- <rom name="10 stage 4 (gyro man).vgz" size="319264" crc="0723ac28" sha1="c0e890c9f2ad1f522d7f0c9a20cc01337a54fa31" offset="0" />
+ <dataarea name="quik" size="319262">
+ <rom name="10 stage 4 (gyro man).vgz" size="319262" crc="a11da893" sha1="762d710da3ee63c4268e780ba26c7defee691c48" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 stage 5 (gemini man).vgz" />
- <dataarea name="quik" size="232681">
- <rom name="11 stage 5 (gemini man).vgz" size="232681" crc="f9c046a9" sha1="ae33b9c4d8c18bbae7ed05810af462c8a26cdeaf" offset="0" />
+ <dataarea name="quik" size="232671">
+ <rom name="11 stage 5 (gemini man).vgz" size="232671" crc="c251fa6e" sha1="913c03c48ebfea29e3f3d3dd1664e3551fd09931" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 stage 6 (shadow man).vgz" />
- <dataarea name="quik" size="224502">
- <rom name="12 stage 6 (shadow man).vgz" size="224502" crc="82539b45" sha1="cb5db97562a628ded5d6f412b80fa1d21c51ff79" offset="0" />
+ <dataarea name="quik" size="224490">
+ <rom name="12 stage 6 (shadow man).vgz" size="224490" crc="8c2a05c2" sha1="027b97eeb70ab9b1363dafd355a0041a4f7cbf2b" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 stage clear.vgz" />
- <dataarea name="quik" size="85651">
- <rom name="13 stage clear.vgz" size="85651" crc="aa371579" sha1="a185668e40f6c98f2c59e17fd78ff317b04bbe5b" offset="0" />
+ <dataarea name="quik" size="85657">
+ <rom name="13 stage clear.vgz" size="85657" crc="95c046bc" sha1="2298084ddba35133e0a350fe36b0c6d006617fd1" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 you got new weapon.vgz" />
- <dataarea name="quik" size="75714">
- <rom name="14 you got new weapon.vgz" size="75714" crc="c27fcd69" sha1="ad5940b2be28aa0efbccdc7806a0a4b10ef10367" offset="0" />
+ <dataarea name="quik" size="75704">
+ <rom name="14 you got new weapon.vgz" size="75704" crc="e442345b" sha1="3bcdbaf2b0e4bda8862693b98fcaba7622fa0c1c" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 stage select (mega man 7).vgz" />
- <dataarea name="quik" size="94112">
- <rom name="15 stage select (mega man 7).vgz" size="94112" crc="f2adba26" sha1="11976f2e74b905f9673dd2babbf07898de09ca75" offset="0" />
+ <dataarea name="quik" size="94097">
+ <rom name="15 stage select (mega man 7).vgz" size="94097" crc="d5a169bb" sha1="5a5bc410dee5d37992d3b6bdaadae4d6e6395d4e" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 stage 7 (mega man 7 opening stage).vgz" />
- <dataarea name="quik" size="208550">
- <rom name="16 stage 7 (mega man 7 opening stage).vgz" size="208550" crc="66869691" sha1="d6f6ae7b59ded3469d4510f09719da410ebd9206" offset="0" />
+ <dataarea name="quik" size="208533">
+ <rom name="16 stage 7 (mega man 7 opening stage).vgz" size="208533" crc="e4684938" sha1="ffccb195487560a31185e535a2a257391dbf9f7d" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 stage 8 (cloud man).vgz" />
- <dataarea name="quik" size="257464">
- <rom name="17 stage 8 (cloud man).vgz" size="257464" crc="fc1d9c5c" sha1="35951fb3b1e26ab93d2fee8d1f671b747831790f" offset="0" />
+ <dataarea name="quik" size="257465">
+ <rom name="17 stage 8 (cloud man).vgz" size="257465" crc="1bb585be" sha1="52bab98605e5e79e3f7b2ec0c5cf9da7330370f8" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 stage 9 (slash man).vgz" />
- <dataarea name="quik" size="302102">
- <rom name="18 stage 9 (slash man).vgz" size="302102" crc="edbe0d14" sha1="498593a866e36146921f35a870bcd0cde9435eb9" offset="0" />
+ <dataarea name="quik" size="302105">
+ <rom name="18 stage 9 (slash man).vgz" size="302105" crc="201208a6" sha1="d79c10fc52ff41e3a24d947ebba9b02cba801100" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 stage 10 (freeze man).vgz" />
<dataarea name="quik" size="235029">
- <rom name="19 stage 10 (freeze man).vgz" size="235029" crc="9a96cc13" sha1="a0717a6c53924a1b31e4885b967d994f84013ffe" offset="0" />
+ <rom name="19 stage 10 (freeze man).vgz" size="235029" crc="ebac53bc" sha1="5d8d9e41aab942b6ef69b3770efe696a6ed610c2" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 stage 11 (junk man).vgz" />
- <dataarea name="quik" size="301451">
- <rom name="20 stage 11 (junk man).vgz" size="301451" crc="8625ee81" sha1="f1d80fb13d2047c64475a6537ca6cf53f5955218" offset="0" />
+ <dataarea name="quik" size="301458">
+ <rom name="20 stage 11 (junk man).vgz" size="301458" crc="bc99196d" sha1="60e349d899494062fbb1baf656d1844eca09a534" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 stage 12 (shade man).vgz" />
- <dataarea name="quik" size="229825">
- <rom name="21 stage 12 (shade man).vgz" size="229825" crc="1e7c7788" sha1="0301a671bb13e20c8c7621e6e04fe7f704cae28e" offset="0" />
+ <dataarea name="quik" size="229819">
+ <rom name="21 stage 12 (shade man).vgz" size="229819" crc="d63b112f" sha1="74439b1442c786af18412d33133266f6024e7029" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 stage 13 (from makai).vgz" />
- <dataarea name="quik" size="191859">
- <rom name="22 stage 13 (from makai).vgz" size="191859" crc="70394658" sha1="fae1d9bf8511329f296fd18ac467939aa5af6e2a" offset="0" />
+ <dataarea name="quik" size="191862">
+ <rom name="22 stage 13 (from makai).vgz" size="191862" crc="ea690b54" sha1="045cd62f3655964537f66762b86891c1003e6640" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
<feature name="part_id" value="23 vs wily.vgz" />
- <dataarea name="quik" size="56600">
- <rom name="23 vs wily.vgz" size="56600" crc="366140c0" sha1="1b2cc2946daf52732c36279d9ae32c73e1f55024" offset="0" />
+ <dataarea name="quik" size="56606">
+ <rom name="23 vs wily.vgz" size="56606" crc="3616b9e0" sha1="e1b8e6815166a93ca1de3bf80caea5240f08c17b" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 stage wily boss.vgz" />
- <dataarea name="quik" size="276174">
- <rom name="24 stage wily boss.vgz" size="276174" crc="ef84c040" sha1="c09e135d4b9e615c51f1f61e2e26125264f81263" offset="0" />
+ <dataarea name="quik" size="276169">
+ <rom name="24 stage wily boss.vgz" size="276169" crc="9e7391f8" sha1="ad7d6ab258e904a0cb778a7da86f36a5d944338d" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
<feature name="part_id" value="25 stage wily machine.vgz" />
- <dataarea name="quik" size="216244">
- <rom name="25 stage wily machine.vgz" size="216244" crc="a52e8529" sha1="a76dba272674ffb3a46d01951fdb2181f28140ce" offset="0" />
+ <dataarea name="quik" size="216239">
+ <rom name="25 stage wily machine.vgz" size="216239" crc="d16d137f" sha1="cd8c072da0e0095265f74d9ba172b81ca98dc16b" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
<feature name="part_id" value="26 stage wily capsule.vgz" />
- <dataarea name="quik" size="321657">
- <rom name="26 stage wily capsule.vgz" size="321657" crc="39860337" sha1="2a2d5f492d5b624bbfd6eb53e2e0eba2e477a2d8" offset="0" />
+ <dataarea name="quik" size="321663">
+ <rom name="26 stage wily capsule.vgz" size="321663" crc="a4614ffd" sha1="da774a100916be6a40c925870602c25d147ad67a" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 continue.vgz" />
- <dataarea name="quik" size="175552">
- <rom name="27 continue.vgz" size="175552" crc="3af04273" sha1="8cc08b2f81039e84f43d20d09db3f9d797c8fc93" offset="0" />
+ <dataarea name="quik" size="175537">
+ <rom name="27 continue.vgz" size="175537" crc="78c7bb23" sha1="0b5e94cb0f6d97588dbab9ce04ec5e8bb90248c2" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
<feature name="part_id" value="28 game over.vgz" />
- <dataarea name="quik" size="159675">
- <rom name="28 game over.vgz" size="159675" crc="ad6eb95d" sha1="c4888abb35c913f8e9f6c55135f943a647cdb062" offset="0" />
+ <dataarea name="quik" size="159672">
+ <rom name="28 game over.vgz" size="159672" crc="cad854dc" sha1="4a8f752702a499ac4cb8885bcf22176a08937c9d" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
<feature name="part_id" value="29 ending (mega man 1).vgz" />
<dataarea name="quik" size="152589">
- <rom name="29 ending (mega man 1).vgz" size="152589" crc="978c6a33" sha1="6bf86e69e5d36923a09d557adf8b890794603102" offset="0" />
+ <rom name="29 ending (mega man 1).vgz" size="152589" crc="5dc5ab83" sha1="08f55d234c876f7151edb6f800b80a36ab52b031" offset="0" />
</dataarea>
</part>
<part name="030" interface="vgm_quik">
<feature name="part_id" value="30 ending (proto man).vgz" />
- <dataarea name="quik" size="282650">
- <rom name="30 ending (proto man).vgz" size="282650" crc="1471a3bc" sha1="37b91887c9789dd9008c834c8f1a2d8a935caf05" offset="0" />
+ <dataarea name="quik" size="282657">
+ <rom name="30 ending (proto man).vgz" size="282657" crc="55478185" sha1="61fe65eb2dcb0b78be1dd4d5f82ee80bd4fe359b" offset="0" />
</dataarea>
</part>
<part name="031" interface="vgm_quik">
<feature name="part_id" value="31 ending (bass).vgz" />
- <dataarea name="quik" size="145579">
- <rom name="31 ending (bass).vgz" size="145579" crc="02dfdd5d" sha1="8a051e49f729581e0d02d92408e547324a34370c" offset="0" />
+ <dataarea name="quik" size="145569">
+ <rom name="31 ending (bass).vgz" size="145569" crc="21d6efab" sha1="944c4cc1878c2ce8b734571314a066fefcf04a6b" offset="0" />
</dataarea>
</part>
<part name="032" interface="vgm_quik">
<feature name="part_id" value="32 ending (mega man 2).vgz" />
- <dataarea name="quik" size="271288">
- <rom name="32 ending (mega man 2).vgz" size="271288" crc="cdc3ff93" sha1="bbac533cf6674a772d7a40e13aa685169981c84b" offset="0" />
+ <dataarea name="quik" size="271286">
+ <rom name="32 ending (mega man 2).vgz" size="271286" crc="776b2ff1" sha1="06b326e6f7051448b34c1e6c683c2dbc42dbd800" offset="0" />
</dataarea>
</part>
</software>
@@ -37336,278 +37336,278 @@ license:CC0
<info name="cores" value="QSound"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 qsound logo.vgz" />
- <dataarea name="quik" size="78042">
- <rom name="01 qsound logo.vgz" size="78042" crc="4d3b5d55" sha1="72958520b8c8c0296de4b1774080c990f373f8ab" offset="0" />
+ <dataarea name="quik" size="78053">
+ <rom name="01 qsound logo.vgz" size="78053" crc="2af912cc" sha1="9bea48d4754b4c28cf0c85b312a723a19c090588" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 opening.vgz" />
- <dataarea name="quik" size="309720">
- <rom name="02 opening.vgz" size="309720" crc="45057b00" sha1="c67a6034453d61c4f6da47c5dcb311b0705db1c2" offset="0" />
+ <dataarea name="quik" size="309733">
+ <rom name="02 opening.vgz" size="309733" crc="ce8a5387" sha1="1af96dda73eddf5aa34b2dea8074056248442bb3" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 player select.vgz" />
- <dataarea name="quik" size="74004">
- <rom name="03 player select.vgz" size="74004" crc="a2acd603" sha1="bae69901174905f1b49c7f3954d74512d97486f7" offset="0" />
+ <dataarea name="quik" size="74006">
+ <rom name="03 player select.vgz" size="74006" crc="3d3a6881" sha1="a12166c6ce8cc7498d7126c28f5b9cdef669fc45" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 course select.vgz" />
- <dataarea name="quik" size="120911">
- <rom name="04 course select.vgz" size="120911" crc="69a767bd" sha1="8dca71629c0ecb16552a1afa6da90922d71c5805" offset="0" />
+ <dataarea name="quik" size="120904">
+ <rom name="04 course select.vgz" size="120904" crc="8a766304" sha1="42c6fb266517723dc164db3a3b03ef1becb219fb" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 vs ~stage start~.vgz" />
- <dataarea name="quik" size="98143">
- <rom name="05 vs ~stage start~.vgz" size="98143" crc="214462ab" sha1="13edb6a6adbff7df65da7f3639ffc35a4c1c1bd0" offset="0" />
+ <dataarea name="quik" size="98154">
+ <rom name="05 vs ~stage start~.vgz" size="98154" crc="d0b10af4" sha1="395a0de260010e059028a2d5835898a54ccc2d06" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 plant man.vgz" />
- <dataarea name="quik" size="263129">
- <rom name="06 plant man.vgz" size="263129" crc="bbe8725f" sha1="f960bf24121927f83c404c408b4eef667e4141dd" offset="0" />
+ <dataarea name="quik" size="263139">
+ <rom name="06 plant man.vgz" size="263139" crc="8e12a2a0" sha1="2224f92504aa5c5b0d792c5472a9a050651efe11" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 bubble man.vgz" />
- <dataarea name="quik" size="193101">
- <rom name="07 bubble man.vgz" size="193101" crc="378a0c36" sha1="22abc0e69c1c0c9e823d03d4536c5e3e675ef870" offset="0" />
+ <dataarea name="quik" size="193103">
+ <rom name="07 bubble man.vgz" size="193103" crc="47d75d15" sha1="3b1254362c4c5771c1491da65ba1a54cd8eb3b2a" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 heat man.vgz" />
- <dataarea name="quik" size="205613">
- <rom name="08 heat man.vgz" size="205613" crc="4e7a2dfb" sha1="2cd7a90d3f8a6394f7f7d453274f93bdee1eadc8" offset="0" />
+ <dataarea name="quik" size="205615">
+ <rom name="08 heat man.vgz" size="205615" crc="aeef8142" sha1="f3e7da1a3a28b92ed5478e4a792b0ac13e40f45c" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 gyro man.vgz" />
- <dataarea name="quik" size="308572">
- <rom name="09 gyro man.vgz" size="308572" crc="110e30d0" sha1="be78ad2fb979844d29b7771dfa7f7144f2bdc96a" offset="0" />
+ <dataarea name="quik" size="308580">
+ <rom name="09 gyro man.vgz" size="308580" crc="fff9beaf" sha1="2cef735a5102f9665f5944ce791c89e0be147dac" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 centaur man.vgz" />
- <dataarea name="quik" size="250207">
- <rom name="10 centaur man.vgz" size="250207" crc="a999a525" sha1="6266aa82a86e91bc1030fbb74fb83764127c88b7" offset="0" />
+ <dataarea name="quik" size="250215">
+ <rom name="10 centaur man.vgz" size="250215" crc="348dfb5a" sha1="fa895aa632f182d82ce5c7e57870b7f98a373c0e" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 shadow man.vgz" />
- <dataarea name="quik" size="196027">
- <rom name="11 shadow man.vgz" size="196027" crc="e8f393a6" sha1="2ece27c78330e78a1ddc292bb1245592252cddc3" offset="0" />
+ <dataarea name="quik" size="196014">
+ <rom name="11 shadow man.vgz" size="196014" crc="b05f9530" sha1="f78d12fbecf81fbf64b614b27741b7a0d2f6a380" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 stage clear.vgz" />
- <dataarea name="quik" size="67133">
- <rom name="12 stage clear.vgz" size="67133" crc="2ea4e4d0" sha1="b612e2aff83bc60ea9b1ab84d9c32d469386af43" offset="0" />
+ <dataarea name="quik" size="67151">
+ <rom name="12 stage clear.vgz" size="67151" crc="cd133478" sha1="b1ba2188e89781ad68b8c8ac3b88bac0688b2de6" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 weapon get.vgz" />
- <dataarea name="quik" size="124417">
- <rom name="13 weapon get.vgz" size="124417" crc="35d5f977" sha1="66f279196fc1d4cdfffa691752a1388adad1875b" offset="0" />
+ <dataarea name="quik" size="124411">
+ <rom name="13 weapon get.vgz" size="124411" crc="29405348" sha1="08d25a43fc73d6506186a2d829d2912e45dde7e8" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 cut man.vgz" />
- <dataarea name="quik" size="220863">
- <rom name="14 cut man.vgz" size="220863" crc="eecf35c6" sha1="2826a5ed0ea96ebbabd8c915799a755a10518a2f" offset="0" />
+ <dataarea name="quik" size="220860">
+ <rom name="14 cut man.vgz" size="220860" crc="7b36cf21" sha1="e6fc7f8c6fb438a1ddb3ed8e5950121c3d7e0dc1" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 dive man.vgz" />
- <dataarea name="quik" size="303394">
- <rom name="15 dive man.vgz" size="303394" crc="7c64d945" sha1="2c4ecd06508ef1188c5af1d94a8dacb72cd70a6a" offset="0" />
+ <dataarea name="quik" size="303404">
+ <rom name="15 dive man.vgz" size="303404" crc="d01ea6ac" sha1="223db3985abdf2defae2ac4a1d98d03a936cc9c8" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 stone man.vgz" />
- <dataarea name="quik" size="307185">
- <rom name="16 stone man.vgz" size="307185" crc="a95f90fd" sha1="390d7b87c6157d1a61661cd993b26f1e22d76ec2" offset="0" />
+ <dataarea name="quik" size="307191">
+ <rom name="16 stone man.vgz" size="307191" crc="ea77f778" sha1="166928a3cc75a553c349dffbb863d5919b807c88" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 roll rescued.vgz" />
- <dataarea name="quik" size="131035">
- <rom name="17 roll rescued.vgz" size="131035" crc="df00f170" sha1="980ad7b7e7f9d3343dfc155b148c1745cbf36302" offset="0" />
+ <dataarea name="quik" size="131043">
+ <rom name="17 roll rescued.vgz" size="131043" crc="7852d312" sha1="9d778c4426b106eced7dc2a023aca27482402d98" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 elec man.vgz" />
<dataarea name="quik" size="193702">
- <rom name="18 elec man.vgz" size="193702" crc="1a8b0c8d" sha1="bc6ffb4a94486e9874d0c760438487844cee6189" offset="0" />
+ <rom name="18 elec man.vgz" size="193702" crc="458065b6" sha1="3e0176b3d6342da4bbf558070ce7a1e345c33f0f" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 shade man.vgz" />
- <dataarea name="quik" size="195764">
- <rom name="19 shade man.vgz" size="195764" crc="d4089f84" sha1="26c517108bfdd320a085dc07b0c29a10b88635a6" offset="0" />
+ <dataarea name="quik" size="195784">
+ <rom name="19 shade man.vgz" size="195784" crc="eeb843f5" sha1="39f638fe2120f629e0b3d81b0ae50375b319493e" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 slash man.vgz" />
- <dataarea name="quik" size="267262">
- <rom name="20 slash man.vgz" size="267262" crc="0b0628de" sha1="2edc5261b27d660af5ba346144046c532e1d23a1" offset="0" />
+ <dataarea name="quik" size="267261">
+ <rom name="20 slash man.vgz" size="267261" crc="ffbf3c9e" sha1="40a8c9ca068fbb707f76890ed2bfb801192b133f" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 ranking.vgz" />
- <dataarea name="quik" size="108924">
- <rom name="21 ranking.vgz" size="108924" crc="f753120c" sha1="8e9fae3194d2eded09d05fefa791c7f1822e6f31" offset="0" />
+ <dataarea name="quik" size="108912">
+ <rom name="21 ranking.vgz" size="108912" crc="be5d3400" sha1="77241dfdec086eb0c6f84859a508eda6a90bcd89" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 napalm man.vgz" />
- <dataarea name="quik" size="139180">
- <rom name="22 napalm man.vgz" size="139180" crc="c40b9818" sha1="3910c380082bc40f81a7c98e5d1ca0a9b5209e6e" offset="0" />
+ <dataarea name="quik" size="139193">
+ <rom name="22 napalm man.vgz" size="139193" crc="d92d6e6f" sha1="c88a134de2a3c2c2c0982ae8e1bb607f6f294c6c" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
<feature name="part_id" value="23 gemini man.vgz" />
<dataarea name="quik" size="212291">
- <rom name="23 gemini man.vgz" size="212291" crc="5b6074d6" sha1="10d61ff42d336a0a22a09a2741d6618c66646b6e" offset="0" />
+ <rom name="23 gemini man.vgz" size="212291" crc="234ed9e9" sha1="592ad5a7e4d910e453538b3ebff4874c27bffb93" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 guts man.vgz" />
- <dataarea name="quik" size="207076">
- <rom name="24 guts man.vgz" size="207076" crc="c4e34d5c" sha1="107c076f08db4c29781e8251787d88c6443a1e86" offset="0" />
+ <dataarea name="quik" size="207083">
+ <rom name="24 guts man.vgz" size="207083" crc="da31d8aa" sha1="7ec886b18d7446370eaa7853370dab34096eba69" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
<feature name="part_id" value="25 neo parts reclaimed.vgz" />
- <dataarea name="quik" size="120537">
- <rom name="25 neo parts reclaimed.vgz" size="120537" crc="ef1537bf" sha1="9f7f094f575b8463313a8a4b602dbaaeb1334d24" offset="0" />
+ <dataarea name="quik" size="120536">
+ <rom name="25 neo parts reclaimed.vgz" size="120536" crc="5731f9ae" sha1="8615b2a617538feb7daf909f6511705bde0f092f" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
<feature name="part_id" value="26 air man.vgz" />
- <dataarea name="quik" size="206873">
- <rom name="26 air man.vgz" size="206873" crc="268ba747" sha1="d678ba7d22d119033764273e05950a2f292a273f" offset="0" />
+ <dataarea name="quik" size="206903">
+ <rom name="26 air man.vgz" size="206903" crc="45302583" sha1="14695e5f23df9d15fee047cfc0b6406a6545354c" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 quick man.vgz" />
- <dataarea name="quik" size="235162">
- <rom name="27 quick man.vgz" size="235162" crc="05b621c2" sha1="4707fa8318e7a6a0468477a08ee26125817a9c2c" offset="0" />
+ <dataarea name="quik" size="235175">
+ <rom name="27 quick man.vgz" size="235175" crc="f006a6da" sha1="18c1efe7d33504dae424a5b75236810cc91ba078" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
<feature name="part_id" value="28 pharaoh man.vgz" />
- <dataarea name="quik" size="318785">
- <rom name="28 pharaoh man.vgz" size="318785" crc="310a411c" sha1="22433a40ee90c39f1f80534de5680f63e6a59a97" offset="0" />
+ <dataarea name="quik" size="318784">
+ <rom name="28 pharaoh man.vgz" size="318784" crc="3b3197fe" sha1="7a63a097c06caf894bdd209b121889a8cdf9ec36" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
<feature name="part_id" value="29 vs ~wily~.vgz" />
- <dataarea name="quik" size="53059">
- <rom name="29 vs ~wily~.vgz" size="53059" crc="853a4265" sha1="9446cc50c7e80910940f0801667c22fa8d95ecc3" offset="0" />
+ <dataarea name="quik" size="53065">
+ <rom name="29 vs ~wily~.vgz" size="53065" crc="a2232966" sha1="91a0330b91027310a8090a2a7285a9269375d7eb" offset="0" />
</dataarea>
</part>
<part name="030" interface="vgm_quik">
<feature name="part_id" value="30 mad grinder.vgz" />
- <dataarea name="quik" size="183185">
- <rom name="30 mad grinder.vgz" size="183185" crc="ba0a1124" sha1="f543598d678b53f75a8baa9f14d8a28d0c21172d" offset="0" />
+ <dataarea name="quik" size="183172">
+ <rom name="30 mad grinder.vgz" size="183172" crc="e8738639" sha1="5d40b5248893aa96d4753144e9f291476ef7a01b" offset="0" />
</dataarea>
</part>
<part name="031" interface="vgm_quik">
<feature name="part_id" value="31 yellow devil.vgz" />
- <dataarea name="quik" size="250155">
- <rom name="31 yellow devil.vgz" size="250155" crc="4dfe57cb" sha1="3daf0c3a69fadfb73d9de00c13f88dbef2e184ab" offset="0" />
+ <dataarea name="quik" size="250158">
+ <rom name="31 yellow devil.vgz" size="250158" crc="f74e5277" sha1="92cd33ff51f9268aa6a72eb973fa812a5565c24f" offset="0" />
</dataarea>
</part>
<part name="032" interface="vgm_quik">
<feature name="part_id" value="32 mecha dragon.vgz" />
- <dataarea name="quik" size="243261">
- <rom name="32 mecha dragon.vgz" size="243261" crc="75f84223" sha1="d18fe99efbf863e1479b2755c291f8dd3400533f" offset="0" />
+ <dataarea name="quik" size="243252">
+ <rom name="32 mecha dragon.vgz" size="243252" crc="0fa9debd" sha1="df076433ca31b4500bca3e086a1a9e5606368e9d" offset="0" />
</dataarea>
</part>
<part name="033" interface="vgm_quik">
<feature name="part_id" value="33 wily machine.vgz" />
- <dataarea name="quik" size="283415">
- <rom name="33 wily machine.vgz" size="283415" crc="59d3014f" sha1="a562f124ba48dfeed47d7dd23366d062dae1a7c3" offset="0" />
+ <dataarea name="quik" size="283441">
+ <rom name="33 wily machine.vgz" size="283441" crc="116f9b34" sha1="999184beefcc0a012c87c4917bad70ce3595a9a3" offset="0" />
</dataarea>
</part>
<part name="034" interface="vgm_quik">
<feature name="part_id" value="34 wily capsule.vgz" />
- <dataarea name="quik" size="121023">
- <rom name="34 wily capsule.vgz" size="121023" crc="757be792" sha1="203f65e2f1a3354a7ceaf3d7873191ed0f2904a8" offset="0" />
+ <dataarea name="quik" size="121028">
+ <rom name="34 wily capsule.vgz" size="121028" crc="0ab4997e" sha1="10b2a6948ff24b1555b6acfe71f51707deaf0a1e" offset="0" />
</dataarea>
</part>
<part name="035" interface="vgm_quik">
<feature name="part_id" value="35 continue.vgz" />
- <dataarea name="quik" size="157907">
- <rom name="35 continue.vgz" size="157907" crc="3180498b" sha1="99508550c5350eadfde2c9b4df2c74fdbf43616b" offset="0" />
+ <dataarea name="quik" size="157931">
+ <rom name="35 continue.vgz" size="157931" crc="1030ff18" sha1="eca763eff456032d5b78344bd790070673dc2054" offset="0" />
</dataarea>
</part>
<part name="036" interface="vgm_quik">
<feature name="part_id" value="36 game over.vgz" />
- <dataarea name="quik" size="127561">
- <rom name="36 game over.vgz" size="127561" crc="4906bc6f" sha1="089bb810587afeb4bd836f0d13ba28b1c6dbe7f2" offset="0" />
+ <dataarea name="quik" size="127575">
+ <rom name="36 game over.vgz" size="127575" crc="f78eb07c" sha1="98573398895d3b8550667aa73526d80bbba1c9c4" offset="0" />
</dataarea>
</part>
<part name="037" interface="vgm_quik">
<feature name="part_id" value="37 escape.vgz" />
- <dataarea name="quik" size="134228">
- <rom name="37 escape.vgz" size="134228" crc="0adf0ece" sha1="257b47b2bb13f8b56b576c0200e5d9628021f485" offset="0" />
+ <dataarea name="quik" size="134214">
+ <rom name="37 escape.vgz" size="134214" crc="a697febf" sha1="a28cc7206f78895e6bec6dca6935da5b831325ea" offset="0" />
</dataarea>
</part>
<part name="038" interface="vgm_quik">
<feature name="part_id" value="38 megaman ending 1.vgz" />
- <dataarea name="quik" size="123761">
- <rom name="38 megaman ending 1.vgz" size="123761" crc="c2b99c09" sha1="c8bf23b49b4110b81e7e450177c354a0172efb12" offset="0" />
+ <dataarea name="quik" size="123779">
+ <rom name="38 megaman ending 1.vgz" size="123779" crc="8e0a42b2" sha1="332f9ea8b422f330f77af461cda5fe9b005baa52" offset="0" />
</dataarea>
</part>
<part name="039" interface="vgm_quik">
<feature name="part_id" value="39 megaman ending 2.vgz" />
- <dataarea name="quik" size="251050">
- <rom name="39 megaman ending 2.vgz" size="251050" crc="cb36a179" sha1="a27511cc6dc2b690afd739fa3efce9106419dd92" offset="0" />
+ <dataarea name="quik" size="251054">
+ <rom name="39 megaman ending 2.vgz" size="251054" crc="4682ed20" sha1="63d3caf437cc71d91bbefca31f70966225516b16" offset="0" />
</dataarea>
</part>
<part name="040" interface="vgm_quik">
<feature name="part_id" value="40 protoman ending.vgz" />
- <dataarea name="quik" size="253693">
- <rom name="40 protoman ending.vgz" size="253693" crc="b82ede21" sha1="15222933066e501125ecdeaccfcdf15ef6e0207d" offset="0" />
+ <dataarea name="quik" size="253705">
+ <rom name="40 protoman ending.vgz" size="253705" crc="b0614f06" sha1="114be17451a6a11db7a45aea386337fd14261a8d" offset="0" />
</dataarea>
</part>
<part name="041" interface="vgm_quik">
<feature name="part_id" value="41 bass ending 1.vgz" />
- <dataarea name="quik" size="238293">
- <rom name="41 bass ending 1.vgz" size="238293" crc="c60a4985" sha1="333e5bb6c90f782999e44e3f3336b7acbbbc8b8f" offset="0" />
+ <dataarea name="quik" size="238309">
+ <rom name="41 bass ending 1.vgz" size="238309" crc="cd38c2a0" sha1="28b2cbbf630efbdf289e6d04fd05bfb9246923dd" offset="0" />
</dataarea>
</part>
<part name="042" interface="vgm_quik">
<feature name="part_id" value="42 bass ending 2.vgz" />
- <dataarea name="quik" size="129949">
- <rom name="42 bass ending 2.vgz" size="129949" crc="8b478e37" sha1="087972c61cbc325ded2715d304f735929a862b69" offset="0" />
+ <dataarea name="quik" size="129953">
+ <rom name="42 bass ending 2.vgz" size="129953" crc="a4e5f61a" sha1="d70febf889f296a2e2d7423f0c00414f7dffc3ac" offset="0" />
</dataarea>
</part>
<part name="043" interface="vgm_quik">
<feature name="part_id" value="43 duo ending 1.vgz" />
- <dataarea name="quik" size="177381">
- <rom name="43 duo ending 1.vgz" size="177381" crc="b590a81d" sha1="28598d59244aea0e4f298eb5c19dc4589c06dbc2" offset="0" />
+ <dataarea name="quik" size="177368">
+ <rom name="43 duo ending 1.vgz" size="177368" crc="3099ef44" sha1="973ed52eb93a56e0b0e49be1ac1589fe189cf68a" offset="0" />
</dataarea>
</part>
<part name="044" interface="vgm_quik">
<feature name="part_id" value="44 duo ending 2.vgz" />
- <dataarea name="quik" size="388519">
- <rom name="44 duo ending 2.vgz" size="388519" crc="2a10f9fb" sha1="eaecf91fe096e08e0d6942df97678f5c8ce391c8" offset="0" />
+ <dataarea name="quik" size="388540">
+ <rom name="44 duo ending 2.vgz" size="388540" crc="baf8093f" sha1="9d3ecd7c2cc8ea3e88fca8a759d05d98057e81f1" offset="0" />
</dataarea>
</part>
<part name="045" interface="vgm_quik">
<feature name="part_id" value="45 unused.vgz" />
<dataarea name="quik" size="11978">
- <rom name="45 unused.vgz" size="11978" crc="ff8bc8ef" sha1="d12903974dabb1217b52f3683b878a8359ad4e8d" offset="0" />
+ <rom name="45 unused.vgz" size="11978" crc="2aec23ae" sha1="3da11e9894d02da9dafa7e8da6364469fd675d11" offset="0" />
</dataarea>
</part>
<part name="046" interface="vgm_quik">
<feature name="part_id" value="46 elec man (nes version).vgz" />
- <dataarea name="quik" size="147189">
- <rom name="46 elec man (nes version).vgz" size="147189" crc="288fb512" sha1="ca8bdd7d458c0152d5482eae2e7bbc25392c64d8" offset="0" />
+ <dataarea name="quik" size="147208">
+ <rom name="46 elec man (nes version).vgz" size="147208" crc="9bc961e8" sha1="ee255bb67647106f64ea32f573b3562347fadfd0" offset="0" />
</dataarea>
</part>
</software>
@@ -40694,176 +40694,200 @@ license:CC0
<info name="cores" value="QSound"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 qsound logo.vgz" />
- <dataarea name="quik" size="122641">
- <rom name="01 qsound logo.vgz" size="122641" crc="92236d8d" sha1="ae15b0493dab40c824bc0efe8c54fc48d6df0bbd" offset="0" />
+ <dataarea name="quik" size="122704">
+ <rom name="01 qsound logo.vgz" size="122704" crc="c0726121" sha1="c02a5ff46005312b1e51ba6879d99fa49754880a" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 opening demo.vgz" />
- <dataarea name="quik" size="335401">
- <rom name="02 opening demo.vgz" size="335401" crc="3ed7aabf" sha1="55fa25907b01b8794ecf0c3666752447aca9e802" offset="0" />
+ <dataarea name="quik" size="336106">
+ <rom name="02 opening demo.vgz" size="336106" crc="9ee7e781" sha1="ffee818b1efd992e689fc612c96ef3ffcfd129c6" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 character select.vgz" />
- <dataarea name="quik" size="290637">
- <rom name="03 character select.vgz" size="290637" crc="b88a39ec" sha1="efeb40a11000ae7290dbaad22a78084260063c83" offset="0" />
+ <dataarea name="quik" size="291048">
+ <rom name="03 character select.vgz" size="291048" crc="982eaf7d" sha1="131d4154384db8d814e193569dc8fd8d4a2f05e1" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 stage 1.vgz" />
- <dataarea name="quik" size="626367">
- <rom name="04 stage 1.vgz" size="626367" crc="f7f82a73" sha1="91b14493b751cf26a546a905995e8df7326d2bda" offset="0" />
+ <dataarea name="quik" size="629432">
+ <rom name="04 stage 1.vgz" size="629432" crc="54c764bd" sha1="00c292a02d3275ed12365ba8c9bf62e2fa446198" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 stage 2.vgz" />
- <dataarea name="quik" size="402174">
- <rom name="05 stage 2.vgz" size="402174" crc="8922587c" sha1="c152adef33237826fa1558a0f9410c464b69072e" offset="0" />
+ <dataarea name="quik" size="403414">
+ <rom name="05 stage 2.vgz" size="403414" crc="e6776b99" sha1="562ff793177df805783e613039487cd464d8f974" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 stage 3.vgz" />
- <dataarea name="quik" size="596530">
- <rom name="06 stage 3.vgz" size="596530" crc="f63b6c90" sha1="fd5467551fbb2e58899b83ff77a14f79461072a8" offset="0" />
+ <dataarea name="quik" size="599546">
+ <rom name="06 stage 3.vgz" size="599546" crc="69c3c1cd" sha1="3bda7d0fdacc0d5b5bf46f0d196f2edd779dfd08" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 stage 4.vgz" />
- <dataarea name="quik" size="297118">
- <rom name="07 stage 4.vgz" size="297118" crc="934164ed" sha1="36a807f8f1b74d0a7cfd12f555f68e715b09ca11" offset="0" />
+ <dataarea name="quik" size="299803">
+ <rom name="07 stage 4.vgz" size="299803" crc="beec74d4" sha1="decd3b0e0a09e40079f2bba23b8363deaa0733c4" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 stage 5.vgz" />
- <dataarea name="quik" size="254903">
- <rom name="08 stage 5.vgz" size="254903" crc="585c4fb1" sha1="22715bf38da244428a338259d8aed34c49c43aec" offset="0" />
+ <dataarea name="quik" size="255299">
+ <rom name="08 stage 5.vgz" size="255299" crc="62b0ae43" sha1="59e38399d29ab639a6be46b15711d7b9f4265055" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 stage 6.vgz" />
- <dataarea name="quik" size="369917">
- <rom name="09 stage 6.vgz" size="369917" crc="21cef255" sha1="acb0e2c6764e9c5ef87a8cd827730fa1a01ddccf" offset="0" />
+ <dataarea name="quik" size="371507">
+ <rom name="09 stage 6.vgz" size="371507" crc="58fa3397" sha1="4e4e06433abf15f9301bd9b29a9177d585f4eb5a" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 stage 7.vgz" />
- <dataarea name="quik" size="427464">
- <rom name="10 stage 7.vgz" size="427464" crc="52514f7b" sha1="5cb3290bd09ff85103396b693779a2aea8e4c446" offset="0" />
+ <dataarea name="quik" size="429278">
+ <rom name="10 stage 7.vgz" size="429278" crc="5e6b0298" sha1="a549384a8ccc896fb4464216585999982c663a54" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 stage 8.vgz" />
- <dataarea name="quik" size="582062">
- <rom name="11 stage 8.vgz" size="582062" crc="9e75c2ac" sha1="a662307a939b450c2067ece0a713ba2553bc9f65" offset="0" />
+ <dataarea name="quik" size="583241">
+ <rom name="11 stage 8.vgz" size="583241" crc="ba8c5172" sha1="c2f95d70dac968f64eb106ee759f60a8cd8f4a27" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 stage 9.vgz" />
- <dataarea name="quik" size="372002">
- <rom name="12 stage 9.vgz" size="372002" crc="48e8c8cc" sha1="570e4ac1e92da666e70819b8de349a819d07aada" offset="0" />
+ <dataarea name="quik" size="373149">
+ <rom name="12 stage 9.vgz" size="373149" crc="e38f81d4" sha1="137c59d7526dc07f0599075755b3f05b6c4bffe8" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 stage 10.vgz" />
- <dataarea name="quik" size="485542">
- <rom name="13 stage 10.vgz" size="485542" crc="bf948239" sha1="fbafcebba6f17eb66b7d437f92a32d69ea64bf90" offset="0" />
+ <dataarea name="quik" size="486909">
+ <rom name="13 stage 10.vgz" size="486909" crc="d396476c" sha1="5789509e88a13af855db4cf75fdad41f0dcebc6a" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 special stage.vgz" />
- <dataarea name="quik" size="392958">
- <rom name="14 special stage.vgz" size="392958" crc="ec83f82e" sha1="acbda6427e94d0487ecdd4160a5a06994de74dc5" offset="0" />
+ <dataarea name="quik" size="394362">
+ <rom name="14 special stage.vgz" size="394362" crc="9488db00" sha1="d9b839ed8a672665d90a39912bca4c82a7afc093" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 here comes a new challenger.vgz" />
- <dataarea name="quik" size="208166">
- <rom name="15 here comes a new challenger.vgz" size="208166" crc="f6706a0c" sha1="fb53a8280f1f55734ef5ad621fd5c6c784df318d" offset="0" />
+ <dataarea name="quik" size="208212">
+ <rom name="15 here comes a new challenger.vgz" size="208212" crc="5be96e0f" sha1="66007b79837fe2b04cb97d663e81b882a9780dfa" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 continue.vgz" />
- <dataarea name="quik" size="106071">
- <rom name="16 continue.vgz" size="106071" crc="c4daf6f7" sha1="61b078bd937989a93430770d8f0a379a9b33e9f4" offset="0" />
+ <dataarea name="quik" size="106151">
+ <rom name="16 continue.vgz" size="106151" crc="1d56af53" sha1="898c1d1b6b552d1f0149f3551b09b28f34c165d3" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 name entry.vgz" />
- <dataarea name="quik" size="153235">
- <rom name="17 name entry.vgz" size="153235" crc="21682fec" sha1="d54f16233bb124babefff03d4249f8a430c1a611" offset="0" />
+ <dataarea name="quik" size="153364">
+ <rom name="17 name entry.vgz" size="153364" crc="e846fede" sha1="d2cee4d7eff4853c5703b44abd025f09a11b6163" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 bad ending.vgz" />
- <dataarea name="quik" size="297436">
- <rom name="18 bad ending.vgz" size="297436" crc="5a6240e9" sha1="546769ad18febc04d909d85ca9a85d31260aa592" offset="0" />
+ <dataarea name="quik" size="297627">
+ <rom name="18 bad ending.vgz" size="297627" crc="fbffeb10" sha1="f44289100909afdb445ea992d34c1f407b41e220" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 good ending hayato.vgz" />
- <dataarea name="quik" size="159071">
- <rom name="19 good ending hayato.vgz" size="159071" crc="6930cae5" sha1="2b0178201c2f632355a3e98b2d796c7014d354f7" offset="0" />
+ <dataarea name="quik" size="159340">
+ <rom name="19 good ending hayato.vgz" size="159340" crc="28a1d61b" sha1="64edd301ee89ab57193118821ae290cd8105631e" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 good ending june.vgz" />
- <dataarea name="quik" size="98620">
- <rom name="20 good ending june.vgz" size="98620" crc="0d5fdddd" sha1="e0182ae84c599f01a3689c2452ded50916efb951" offset="0" />
+ <dataarea name="quik" size="98744">
+ <rom name="20 good ending june.vgz" size="98744" crc="1d4693f9" sha1="36a6079210316f55f101be91ce11dfcaedbdd474" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 good ending saturn.vgz" />
- <dataarea name="quik" size="170088">
- <rom name="21 good ending saturn.vgz" size="170088" crc="c5cf5d35" sha1="b5049b6914c8afac32d04147ec3ae482b51f3b4b" offset="0" />
+ <dataarea name="quik" size="170321">
+ <rom name="21 good ending saturn.vgz" size="170321" crc="cdeebac0" sha1="e9324007500eba71e06ac30ae54a8a0c0e84913c" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 good ending gamof.vgz" />
- <dataarea name="quik" size="144360">
- <rom name="22 good ending gamof.vgz" size="144360" crc="8602c0db" sha1="71205ab18715cb564b0e589cac9180e3e146b18e" offset="0" />
+ <dataarea name="quik" size="144470">
+ <rom name="22 good ending gamof.vgz" size="144470" crc="152f0e56" sha1="972c10e28c754b31ef12e889d2385846c22c50ca" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
<feature name="part_id" value="23 good ending gerelt.vgz" />
- <dataarea name="quik" size="57381">
- <rom name="23 good ending gerelt.vgz" size="57381" crc="c5db6561" sha1="8e7012008351be742a7582856a86dd41cbfb5507" offset="0" />
+ <dataarea name="quik" size="57614">
+ <rom name="23 good ending gerelt.vgz" size="57614" crc="ed28add4" sha1="579328531abfeb3f48ca3c4942d530b4a0bc5da8" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 good ending rimgal.vgz" />
- <dataarea name="quik" size="124956">
- <rom name="24 good ending rimgal.vgz" size="124956" crc="f84d6add" sha1="02e24f55f9d269577ce494640c3a83adc4adcc23" offset="0" />
+ <dataarea name="quik" size="125235">
+ <rom name="24 good ending rimgal.vgz" size="125235" crc="59dd732b" sha1="8c6ef704409ba03da9181abfc9124aacd138e531" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
<feature name="part_id" value="25 good ending zelkin.vgz" />
- <dataarea name="quik" size="205113">
- <rom name="25 good ending zelkin.vgz" size="205113" crc="daa7430d" sha1="7f13a3322eb9248e42d67491009fa48ce65fae8d" offset="0" />
+ <dataarea name="quik" size="205664">
+ <rom name="25 good ending zelkin.vgz" size="205664" crc="f5eace0c" sha1="e5f8525be3a1e1abcac612e3d32c48492a17a014" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
<feature name="part_id" value="26 good ending vector.vgz" />
- <dataarea name="quik" size="99210">
- <rom name="26 good ending vector.vgz" size="99210" crc="48ddc309" sha1="a750cf84766e4d2932a4440ec55ace65646133d9" offset="0" />
+ <dataarea name="quik" size="99460">
+ <rom name="26 good ending vector.vgz" size="99460" crc="12daf467" sha1="6b38ac01617b2374e8b19e810af8a3f8dde5268d" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 good ending gore.vgz" />
- <dataarea name="quik" size="178113">
- <rom name="27 good ending gore.vgz" size="178113" crc="bc59b67e" sha1="aaa1b948965483091e710a3a85b8daadbe5abb19" offset="0" />
+ <dataarea name="quik" size="178558">
+ <rom name="27 good ending gore.vgz" size="178558" crc="6b79e212" sha1="75fe5293df13069b553563035595052f9b5263a8" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
<feature name="part_id" value="28 good ending bilstein.vgz" />
- <dataarea name="quik" size="160609">
- <rom name="28 good ending bilstein.vgz" size="160609" crc="67f6251d" sha1="093a0a0ed9295be1d5af593914afc39c207e3d38" offset="0" />
+ <dataarea name="quik" size="160968">
+ <rom name="28 good ending bilstein.vgz" size="160968" crc="9caaf78d" sha1="dd41b30fa1aff2852bd517cf582d5c01af44a30a" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
<feature name="part_id" value="29 staff roll.vgz" />
- <dataarea name="quik" size="452847">
- <rom name="29 staff roll.vgz" size="452847" crc="892946a1" sha1="21b5e03f601391e5487727dafc3c5430b04d453b" offset="0" />
+ <dataarea name="quik" size="454442">
+ <rom name="29 staff roll.vgz" size="454442" crc="7f04d200" sha1="2f63f250c6b8583c96dbd6f64213d20c651eda3a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 stage 1 (no loop).vgz" />
+ <dataarea name="quik" size="629263">
+ <rom name="30 stage 1 (no loop).vgz" size="629263" crc="6414a78e" sha1="1ec11339d165c63aeea4fb810df3aec21b735bd2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 stage 3 (no loop).vgz" />
+ <dataarea name="quik" size="599303">
+ <rom name="31 stage 3 (no loop).vgz" size="599303" crc="993ec423" sha1="17b7c4d31d7cb32429f11936d04dee118f81486d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="032" interface="vgm_quik">
+ <feature name="part_id" value="32 stage 7 (no loop).vgz" />
+ <dataarea name="quik" size="429233">
+ <rom name="32 stage 7 (no loop).vgz" size="429233" crc="2561fa26" sha1="f7a5ed41105b69b67739376b127a29e3a33e80fc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="033" interface="vgm_quik">
+ <feature name="part_id" value="33 stage 10 (no loop).vgz" />
+ <dataarea name="quik" size="486659">
+ <rom name="33 stage 10 (no loop).vgz" size="486659" crc="d1105b25" sha1="06ab7c3c499af0093c2a51944e16b31a8f8ebfe0" offset="0" />
</dataarea>
</part>
</software>
@@ -44473,188 +44497,188 @@ license:CC0
<info name="cores" value="QSound"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 player select.vgz" />
- <dataarea name="quik" size="67955">
- <rom name="01 player select.vgz" size="67955" crc="f0d260fa" sha1="8e92bef67c466a4949de11f9fdefcab3b6098920" offset="0" />
+ <dataarea name="quik" size="68114">
+ <rom name="01 player select.vgz" size="68114" crc="94eecbf8" sha1="53aecea2466b43e4fae11e9b981c2e7f2863cfe2" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 crime hunter (stage 1).vgz" />
- <dataarea name="quik" size="158007">
- <rom name="02 crime hunter (stage 1).vgz" size="158007" crc="8522bf46" sha1="8191e479268a52f87c1bf5f1761636c2d694724b" offset="0" />
+ <dataarea name="quik" size="158943">
+ <rom name="02 crime hunter (stage 1).vgz" size="158943" crc="bf8dedc5" sha1="8ad9df14c932b7e1971eeb8a8a3c8b3d20c18d05" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
- <feature name="part_id" value="03 iron golem -the guardroid appears- (boss entrance).vgz" />
- <dataarea name="quik" size="78321">
- <rom name="03 iron golem -the guardroid appears- (boss entrance).vgz" size="78321" crc="034ac8ad" sha1="1afff8e40de90e1d5896abb818974ed877a4b37f" offset="0" />
+ <feature name="part_id" value="03 iron golem -enter the guardroid- (boss entrance).vgz" />
+ <dataarea name="quik" size="78506">
+ <rom name="03 iron golem -enter the guardroid- (boss entrance).vgz" size="78506" crc="499553d3" sha1="63b468ee3521d9a646c4ba2c02769f626683163f" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 boss 1.vgz" />
- <dataarea name="quik" size="138780">
- <rom name="04 boss 1.vgz" size="138780" crc="02313c34" sha1="2aacfc4f6c925d2a0164d9a298d152c3bf66065c" offset="0" />
+ <dataarea name="quik" size="139440">
+ <rom name="04 boss 1.vgz" size="139440" crc="2b5d508a" sha1="0eef2eb2c7ee44d71c8a89e5506927b0324c427c" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 stage clear.vgz" />
- <dataarea name="quik" size="110467">
- <rom name="05 stage clear.vgz" size="110467" crc="21f90a64" sha1="938bd771f0c24a447e79a91f9a52c15387f52003" offset="0" />
+ <dataarea name="quik" size="110605">
+ <rom name="05 stage clear.vgz" size="110605" crc="f02db65d" sha1="6da3d4b322ccbec5303e2d49d29a5a2f82d46bbb" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 stage 2 start demo (pool).vgz" />
- <dataarea name="quik" size="96497">
- <rom name="06 stage 2 start demo (pool).vgz" size="96497" crc="a9f0ca72" sha1="9d89025a052b0f2f37306915eae05b5fbffa9835" offset="0" />
+ <dataarea name="quik" size="96566">
+ <rom name="06 stage 2 start demo (pool).vgz" size="96566" crc="73c33e27" sha1="9910400364ef3bb82723e7e6ba090cb6219ee794" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 castle pantaberde (stage 2).vgz" />
- <dataarea name="quik" size="174331">
- <rom name="07 castle pantaberde (stage 2).vgz" size="174331" crc="a93a144a" sha1="04c3bec0caaa998a2a7882bba724223c752a73b0" offset="0" />
+ <dataarea name="quik" size="172034">
+ <rom name="07 castle pantaberde (stage 2).vgz" size="172034" crc="a1099dc6" sha1="39ddcdf860f6d2bcdff2183a33a55dc28c67d0ad" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 shock! (unused bgm).vgz" />
- <dataarea name="quik" size="139149">
- <rom name="08 shock (unused bgm).vgz" size="139149" crc="828c6dcb" sha1="2c1408c8ec0c42ed438942aed2b1d12402ee51e0" offset="0" />
+ <dataarea name="quik" size="139388">
+ <rom name="08 shock (unused bgm).vgz" size="139388" crc="e39629eb" sha1="769557e6d43ec803cbd3cde9fc1fa5e97b7a6531" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 stage 3 start demo (harbor).vgz" />
- <dataarea name="quik" size="49209">
- <rom name="09 stage 3 start demo (harbor).vgz" size="49209" crc="e4abe93a" sha1="bb2ffe527cedadcd92cc95b3d29b969ea10489d2" offset="0" />
+ <dataarea name="quik" size="49249">
+ <rom name="09 stage 3 start demo (harbor).vgz" size="49249" crc="19dc239e" sha1="0ba89bff03ffdd7aea5f4f9ca5afa2509d6e2ccc" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 seaside trap (stage 3).vgz" />
- <dataarea name="quik" size="155215">
- <rom name="10 seaside trap (stage 3).vgz" size="155215" crc="4ac6d558" sha1="b11834bc46661a628a9bb3a1a889056d3c57513b" offset="0" />
+ <dataarea name="quik" size="155909">
+ <rom name="10 seaside trap (stage 3).vgz" size="155909" crc="0f235883" sha1="735f94651b9b6b866574ce2bf2c5d89f3f8c0677" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
- <feature name="part_id" value="11 stage 4 start demo (huge cave).vgz" />
- <dataarea name="quik" size="59762">
- <rom name="11 stage 4 start demo (huge cave).vgz" size="59762" crc="399c5659" sha1="09f765e699fb1baca377c54fafb423f565f0bfd5" offset="0" />
+ <feature name="part_id" value="11 stage 4 start demo (gigantic cave).vgz" />
+ <dataarea name="quik" size="59827">
+ <rom name="11 stage 4 start demo (gigantic cave).vgz" size="59827" crc="eb3ae0ee" sha1="ba80fdfd2a0b82d34cdf196a6277bc05a95f7c54" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
- <feature name="part_id" value="12 runaway train -huge cave- (stage 4).vgz" />
- <dataarea name="quik" size="130575">
- <rom name="12 runaway train -huge cave- (stage 4).vgz" size="130575" crc="c8d55b57" sha1="81fc97ce8897177fa65ed7662deb95e415f39e0f" offset="0" />
+ <feature name="part_id" value="12 runaway train -gigantic cave- (stage 4).vgz" />
+ <dataarea name="quik" size="130823">
+ <rom name="12 runaway train -gigantic cave- (stage 4).vgz" size="130823" crc="98a47911" sha1="fef57689100837cd4018404e40edb1e5be11da82" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 bonus stage.vgz" />
- <dataarea name="quik" size="145402">
- <rom name="13 bonus stage.vgz" size="145402" crc="e99dbeb6" sha1="1ef2bf2d316a5a63c825afaeefb777da595fbfe1" offset="0" />
+ <dataarea name="quik" size="146374">
+ <rom name="13 bonus stage.vgz" size="146374" crc="6258ee1a" sha1="714c3bcd7eb071dc163545779485c7b76854a940" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 boss 2 (archenemy).vgz" />
- <dataarea name="quik" size="124084">
- <rom name="14 boss 2 (archenemy).vgz" size="124084" crc="76174289" sha1="a6e8067afd0c658e13fba9befe75b2c48b7654e9" offset="0" />
+ <dataarea name="quik" size="124274">
+ <rom name="14 boss 2 (archenemy).vgz" size="124274" crc="0a78c546" sha1="0250abbfe3935ec6ad749ea4581def44b0b7beee" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 stage 5 start demo (hideout).vgz" />
- <dataarea name="quik" size="84094">
- <rom name="15 stage 5 start demo (hideout).vgz" size="84094" crc="0e48e8f0" sha1="42d0a0025e676879f20fd37953bdcaaf44b5fc6c" offset="0" />
+ <dataarea name="quik" size="84259">
+ <rom name="15 stage 5 start demo (hideout).vgz" size="84259" crc="a4d35681" sha1="c900a6ff21295ff40b23911a48172a28a9316d8a" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 revenger -theme of vengeance- (stage 5).vgz" />
- <dataarea name="quik" size="194905">
- <rom name="16 revenger -theme of vengeance- (stage 5).vgz" size="194905" crc="2c4a720f" sha1="af700d6c73c6d969de162b85383504032a1f463c" offset="0" />
+ <dataarea name="quik" size="195514">
+ <rom name="16 revenger -theme of vengeance- (stage 5).vgz" size="195514" crc="0d358953" sha1="29d7a45113bd63ce355e4cb1c5a92c3681c86201" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 stage 6 start demo (king building).vgz" />
- <dataarea name="quik" size="27077">
- <rom name="17 stage 6 start demo (king building).vgz" size="27077" crc="3588f6cd" sha1="c2a496b76813a8c45da4d40ac56c62362b20f7cc" offset="0" />
+ <dataarea name="quik" size="27086">
+ <rom name="17 stage 6 start demo (king building).vgz" size="27086" crc="c0e67878" sha1="78c997772bfffb7d3fa3bbbcf1ea29f793e903d2" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 king building infiltration (stage 6-1).vgz" />
- <dataarea name="quik" size="230498">
- <rom name="18 king building infiltration (stage 6-1).vgz" size="230498" crc="caa811c8" sha1="08ee23fa8e2aa69bf167bbb4be57f13f05a70b51" offset="0" />
+ <dataarea name="quik" size="231403">
+ <rom name="18 king building infiltration (stage 6-1).vgz" size="231403" crc="6600e835" sha1="f1dee3b9052ffc763dea561832404114047ba232" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 elevator (stage 6-2).vgz" />
- <dataarea name="quik" size="123170">
- <rom name="19 elevator (stage 6-2).vgz" size="123170" crc="e2d39e51" sha1="f83afe6c6148ed0e50ca4f57b81a09519fcfa2dc" offset="0" />
+ <dataarea name="quik" size="125458">
+ <rom name="19 elevator (stage 6-2).vgz" size="125458" crc="4da62124" sha1="04b0bd57cd3e14e9258a7e88efdb11240f194241" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 endless corridor (stage 6-3).vgz" />
- <dataarea name="quik" size="157381">
- <rom name="20 endless corridor (stage 6-3).vgz" size="157381" crc="708a3a41" sha1="0e1ad4bf7120592ca4fffd476101c70a79bd6424" offset="0" />
+ <dataarea name="quik" size="157785">
+ <rom name="20 endless corridor (stage 6-3).vgz" size="157785" crc="0b003760" sha1="eacc97ab55fa17b9f547848f53f74d14456ab4fc" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 bruno costa (last boss entrance).vgz" />
- <dataarea name="quik" size="133737">
- <rom name="21 bruno costa (last boss entrance).vgz" size="133737" crc="66684357" sha1="ce5f9f00ecdd72436bc540dce53bc9fb5b3d88ad" offset="0" />
+ <dataarea name="quik" size="134339">
+ <rom name="21 bruno costa (last boss entrance).vgz" size="134339" crc="39637472" sha1="199a6aae24bb27e65e92dfc2e194ffe6fc4af550" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 last boss (kingpin).vgz" />
- <dataarea name="quik" size="128335">
- <rom name="22 last boss (kingpin).vgz" size="128335" crc="427036e1" sha1="ca23f7ecce84f4b06239ed5c0a364246d89d6be7" offset="0" />
+ <dataarea name="quik" size="128639">
+ <rom name="22 last boss (kingpin).vgz" size="128639" crc="3ab0084a" sha1="fc20a6a44440db1c5618022c8575cd993aed8871" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
<feature name="part_id" value="23 last stage clear.vgz" />
- <dataarea name="quik" size="47182">
- <rom name="23 last stage clear.vgz" size="47182" crc="b0e2a601" sha1="eb182fdaff256b25002e8ff219bf73e02dc7ef42" offset="0" />
+ <dataarea name="quik" size="47236">
+ <rom name="23 last stage clear.vgz" size="47236" crc="d00cd2be" sha1="0b1beb2eb75f978b0ff73d59694ba03fec50905f" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 ending theme.vgz" />
- <dataarea name="quik" size="127381">
- <rom name="24 ending theme.vgz" size="127381" crc="2ce4d867" sha1="0a2cf85697fe63f650ff3c80d54cd075adc92a5f" offset="0" />
+ <dataarea name="quik" size="128650">
+ <rom name="24 ending theme.vgz" size="128650" crc="a77e62b6" sha1="1d507bbf72e94cb4119e6ae7a111b7b89707d450" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
- <feature name="part_id" value="25 continue.vgz" />
- <dataarea name="quik" size="119221">
- <rom name="25 continue.vgz" size="119221" crc="d415b4fa" sha1="127ab23a1d64ba968fbf9371cc250aed5b430c6f" offset="0" />
+ <feature name="part_id" value="25 continue (the punisher).vgz" />
+ <dataarea name="quik" size="119567">
+ <rom name="25 continue (the punisher).vgz" size="119567" crc="0d205aa9" sha1="e076f65e48c274d25442fc21e29e32cc1d47274d" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
- <feature name="part_id" value="26 game over.vgz" />
- <dataarea name="quik" size="136255">
- <rom name="26 game over.vgz" size="136255" crc="6e606feb" sha1="97fab6a7d54d5628aecd1c4345a7157b5b654fdb" offset="0" />
+ <feature name="part_id" value="26 continue (nick fury).vgz" />
+ <dataarea name="quik" size="60617">
+ <rom name="26 continue (nick fury).vgz" size="60617" crc="8f07ced1" sha1="568fe7a029fe11818e1f9fdc1d6640f18f3e733b" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
- <feature name="part_id" value="27 unused bgm 2.vgz" />
- <dataarea name="quik" size="106890">
- <rom name="27 unused bgm 2.vgz" size="106890" crc="2b95df3d" sha1="48d9f08f6614f5d0c2a040e22a96c653a089e892" offset="0" />
+ <feature name="part_id" value="27 game over.vgz" />
+ <dataarea name="quik" size="136325">
+ <rom name="27 game over.vgz" size="136325" crc="5d655066" sha1="a384564d1d8482b446963324067268eaf9c04e9c" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
- <feature name="part_id" value="28 unused bgm 3.vgz" />
- <dataarea name="quik" size="60229">
- <rom name="28 unused bgm 3.vgz" size="60229" crc="a8970873" sha1="1a247d6c985304c04a0513383576b08315933e30" offset="0" />
+ <feature name="part_id" value="28 unused bgm 2.vgz" />
+ <dataarea name="quik" size="73806">
+ <rom name="28 unused bgm 2.vgz" size="73806" crc="b0949a45" sha1="763b9c32a45e334c94c00e4121c45ed42c0b069f" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
- <feature name="part_id" value="29 unused bgm 4.vgz" />
- <dataarea name="quik" size="73791">
- <rom name="29 unused bgm 4.vgz" size="73791" crc="d5268bde" sha1="dd9110b82750371917d7072f38e1e11c4cf48027" offset="0" />
+ <feature name="part_id" value="29 unused bgm 3.vgz" />
+ <dataarea name="quik" size="107323">
+ <rom name="29 unused bgm 3.vgz" size="107323" crc="75b5d5c8" sha1="279929a856e699f6cdfc42d40a23412b331ec374" offset="0" />
</dataarea>
</part>
<part name="030" interface="vgm_quik">
- <feature name="part_id" value="30 unused bgm 5.vgz" />
- <dataarea name="quik" size="119267">
- <rom name="30 unused bgm 5.vgz" size="119267" crc="4156c559" sha1="8cc24cdd3a69da0ca1009a01c62a5ecd6b0c189d" offset="0" />
+ <feature name="part_id" value="30 unused bgm 4.vgz" />
+ <dataarea name="quik" size="119533">
+ <rom name="30 unused bgm 4.vgz" size="119533" crc="cc46f787" sha1="73fcb96f3a7eaf9dd86a109438062d4e364f76a1" offset="0" />
</dataarea>
</part>
<part name="031" interface="vgm_quik">
- <feature name="part_id" value="31 unused bgm 6.vgz" />
- <dataarea name="quik" size="81930">
- <rom name="31 unused bgm 6.vgz" size="81930" crc="ad0421f3" sha1="5a4cf1bc00f37b2347870d60cb2f630dc7a024a2" offset="0" />
+ <feature name="part_id" value="31 unused bgm 5.vgz" />
+ <dataarea name="quik" size="82008">
+ <rom name="31 unused bgm 5.vgz" size="82008" crc="b6b569bd" sha1="8f4919f5155150db2158a83ec85880e7b9e5941e" offset="0" />
</dataarea>
</part>
</software>
@@ -49942,9 +49966,9 @@ license:CC0
</dataarea>
</part>
<part name="002" interface="vgm_quik">
- <feature name="part_id" value="02 credit.vgz" />
- <dataarea name="quik" size="13550">
- <rom name="02 credit.vgz" size="13550" crc="d1b77c16" sha1="1f005d75c4dae5b7ae672b01dea05378f70f5bca" offset="0" />
+ <feature name="part_id" value="02 yo joe! (credit).vgz" />
+ <dataarea name="quik" size="13596">
+ <rom name="02 yo joe (credit).vgz" size="13596" crc="9be443af" sha1="51bddac630f145f21beb1452ddfaee5ebf0f49ea" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
@@ -49960,9 +49984,9 @@ license:CC0
</dataarea>
</part>
<part name="005" interface="vgm_quik">
- <feature name="part_id" value="05 mission 1-1 - chemical plant.vgz" />
- <dataarea name="quik" size="297601">
- <rom name="05 mission 1-1 - chemical plant.vgz" size="297601" crc="f9d3100b" sha1="e0b6657f87510b3ea5c6f6e2cf34c3ee14dbdfd9" offset="0" />
+ <feature name="part_id" value="05 got to get tough, yo joe! (mission 1-1 - chemical plant).vgz" />
+ <dataarea name="quik" size="297655">
+ <rom name="05 got to get tough, yo joe (mission 1-1 - chemical plant).vgz" size="297655" crc="c7a92fbb" sha1="7d2f83ca3efb96994ed0cba60cdbdbf569e4638b" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
@@ -81903,410 +81927,410 @@ license:CC0
<info name="cores" value="Game Boy DMG"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 prologue ~the final decisive battle~.vgz" />
- <dataarea name="quik" size="11489">
- <rom name="01 prologue ~the final decisive battle~.vgz" size="11489" crc="125c42e6" sha1="747ab2e93dc46d4e8bbd52c671b2e52f8996ef2e" offset="0" />
+ <dataarea name="quik" size="11540">
+ <rom name="01 prologue ~the final decisive battle~.vgz" size="11540" crc="a558e1de" sha1="dd8370d8228200aaed3492c9e034b02154aad1f6" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 the legend returns.vgz" />
- <dataarea name="quik" size="2786">
- <rom name="02 the legend returns.vgz" size="2786" crc="edd5a80f" sha1="f4ae0db4ac9d6c0b3e6136168566b45bb8686cec" offset="0" />
+ <dataarea name="quik" size="2829">
+ <rom name="02 the legend returns.vgz" size="2829" crc="d30bb4e7" sha1="1ba5ff0148b31479bc178c8de622a991e89c37eb" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 epsis continent.vgz" />
- <dataarea name="quik" size="7202">
- <rom name="03 epsis continent.vgz" size="7202" crc="65306180" sha1="8df0fcb214aef34fca765b65d0953061742bfeac" offset="0" />
+ <dataarea name="quik" size="7252">
+ <rom name="03 epsis continent.vgz" size="7252" crc="a5652d49" sha1="3365d4c76e9c842fef07bbfb1f2ce26570855d30" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 patos village.vgz" />
- <dataarea name="quik" size="4594">
- <rom name="04 patos village.vgz" size="4594" crc="5525ee4c" sha1="9a093f9ce9393db3a19b706634b8cd4fd162ee7a" offset="0" />
+ <dataarea name="quik" size="4645">
+ <rom name="04 patos village.vgz" size="4645" crc="8fecb324" sha1="c8e8fd6910946c59128338706e32780d9057274d" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 tutorial.vgz" />
- <dataarea name="quik" size="2109">
- <rom name="05 tutorial.vgz" size="2109" crc="7a73c99e" sha1="986dc085a2b1feb895e1d94124726fefeb9eef33" offset="0" />
+ <dataarea name="quik" size="2156">
+ <rom name="05 tutorial.vgz" size="2156" crc="12b22613" sha1="c25c491de4d25a465c448d0fd49877349cc9d55f" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 tower of death.vgz" />
- <dataarea name="quik" size="5214">
- <rom name="06 tower of death.vgz" size="5214" crc="250e38a7" sha1="abfa53290375c612bb939ddc5033e97dd8506878" offset="0" />
+ <dataarea name="quik" size="5264">
+ <rom name="06 tower of death.vgz" size="5264" crc="c6422b07" sha1="f4c91fec5334f45ec343d2738f5e1ac97bdebb42" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 town of albano.vgz" />
- <dataarea name="quik" size="7632">
- <rom name="07 town of albano.vgz" size="7632" crc="4528152e" sha1="5252ee39e23f15b944596e9837e342bb6c8125dd" offset="0" />
+ <dataarea name="quik" size="7686">
+ <rom name="07 town of albano.vgz" size="7686" crc="f22dc53c" sha1="1e917a57a0b22409ce0a3389edb32ec70422d2f2" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 cave #1.vgz" />
- <dataarea name="quik" size="8040">
- <rom name="08 cave #1.vgz" size="8040" crc="cf0fd7ae" sha1="490f30cb264a96ed06156eb7c9c8d83c2eb6ff66" offset="0" />
+ <dataarea name="quik" size="8093">
+ <rom name="08 cave #1.vgz" size="8093" crc="45d045eb" sha1="1c0f61ae2ec6695f0fb85b6c0912ee33b5460b7b" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 battle #1.vgz" />
- <dataarea name="quik" size="18900">
- <rom name="09 battle #1.vgz" size="18900" crc="18b8f6d9" sha1="b876fbb6197561f53fb3e03d47ab3e1fe4a78567" offset="0" />
+ <dataarea name="quik" size="18953">
+ <rom name="09 battle #1.vgz" size="18953" crc="cf46c30d" sha1="e0430b7fae7551f574df9fab4e45fbcd9f4111dd" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 victory.vgz" />
- <dataarea name="quik" size="1910">
- <rom name="10 victory.vgz" size="1910" crc="4ae6bd1b" sha1="cf09f0c6ba102778eddb50b8042cd4ed18537be9" offset="0" />
+ <dataarea name="quik" size="1955">
+ <rom name="10 victory.vgz" size="1955" crc="4dea72bb" sha1="7b91db58299d3ab14e4ff8728098777ca1bdf45c" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 majari village.vgz" />
- <dataarea name="quik" size="4466">
- <rom name="11 majari village.vgz" size="4466" crc="7cd43f8b" sha1="04bcdc04a53617c938a7b9f508e3245b94821623" offset="0" />
+ <dataarea name="quik" size="4514">
+ <rom name="11 majari village.vgz" size="4514" crc="a1132ef0" sha1="07a48628246bde846b01fd4d093f3b132848c5bc" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 port city #1.vgz" />
- <dataarea name="quik" size="6290">
- <rom name="12 port city #1.vgz" size="6290" crc="9d3ec1b2" sha1="802d3011f6e071ab3e53248611b28ca453a980f5" offset="0" />
+ <dataarea name="quik" size="6340">
+ <rom name="12 port city #1.vgz" size="6340" crc="86e2b9b4" sha1="2698dba16f35ee5e2c039e8d1d431b27b4f03fca" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 leong temple.vgz" />
- <dataarea name="quik" size="7590">
- <rom name="13 leong temple.vgz" size="7590" crc="ec126105" sha1="8add776687b687dd860b65f018860a6ad86a0240" offset="0" />
+ <dataarea name="quik" size="7639">
+ <rom name="13 leong temple.vgz" size="7639" crc="86bdf1d3" sha1="ba964f61c630912d6867c5aad094d09e85995448" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 infiltration.vgz" />
- <dataarea name="quik" size="6635">
- <rom name="14 infiltration.vgz" size="6635" crc="b76888b8" sha1="e12125764965c23ab258c0963222a0d45a3be811" offset="0" />
+ <dataarea name="quik" size="6688">
+ <rom name="14 infiltration.vgz" size="6688" crc="d89dc6a0" sha1="07369a65ff4b2baeb39a6a3e213c80a3d1823405" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 lost peace.vgz" />
- <dataarea name="quik" size="6326">
- <rom name="15 lost peace.vgz" size="6326" crc="8d059ff8" sha1="39f659ef9a9ce7ab2f558ffee17646862e805d12" offset="0" />
+ <dataarea name="quik" size="6375">
+ <rom name="15 lost peace.vgz" size="6375" crc="d8dcf291" sha1="2f18c8cd458c393e35b28347e9436665ccf1d005" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 sorrow and parting.vgz" />
- <dataarea name="quik" size="5190">
- <rom name="16 sorrow and parting.vgz" size="5190" crc="28de6896" sha1="dded2db87adb118d4875d84c6549e0c50073b8b9" offset="0" />
+ <dataarea name="quik" size="5238">
+ <rom name="16 sorrow and parting.vgz" size="5238" crc="3ede4be2" sha1="661bc807a0b41477500d6d2198cc8ff4c3201fd6" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 cave #2.vgz" />
- <dataarea name="quik" size="10046">
- <rom name="17 cave #2.vgz" size="10046" crc="fa65f3bb" sha1="36ed09310cfe11c8a7cd72af271fef8e2ae82696" offset="0" />
+ <dataarea name="quik" size="10102">
+ <rom name="17 cave #2.vgz" size="10102" crc="aa0c81ee" sha1="8d02b335b0eeeb915b0f822da064c9f77075fcc3" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 lidal continent.vgz" />
- <dataarea name="quik" size="9486">
- <rom name="18 lidal continent.vgz" size="9486" crc="67cd5302" sha1="3556833506780c6aa5fe4825cd8bd61a4ccbe024" offset="0" />
+ <dataarea name="quik" size="9539">
+ <rom name="18 lidal continent.vgz" size="9539" crc="6679f2e5" sha1="bb5286ff62c361ad9e15ff820908161a4af2f3bf" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 tower of ruins.vgz" />
- <dataarea name="quik" size="7521">
- <rom name="19 tower of ruins.vgz" size="7521" crc="cb616b28" sha1="9c9267dc29e6601a9d2cd737c40502da0ee23170" offset="0" />
+ <dataarea name="quik" size="7571">
+ <rom name="19 tower of ruins.vgz" size="7571" crc="42710fae" sha1="0d1ea4cfdcfbab60ba70ace45effd88942fa8935" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 enhancement.vgz" />
- <dataarea name="quik" size="9805">
- <rom name="20 enhancement.vgz" size="9805" crc="8d0ab675" sha1="ff44c7870a9ff8df23f4a5510f7664d48a451b5b" offset="0" />
+ <dataarea name="quik" size="9857">
+ <rom name="20 enhancement.vgz" size="9857" crc="3803f2bc" sha1="61cf8a07f8f809a12314ed73eabbbd5ff53be0b9" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 battle #2.vgz" />
- <dataarea name="quik" size="10124">
- <rom name="21 battle #2.vgz" size="10124" crc="9f4009fe" sha1="4e4209d75074721ce9f0416cee4e767e1ecc4cd1" offset="0" />
+ <dataarea name="quik" size="10174">
+ <rom name="21 battle #2.vgz" size="10174" crc="e73f261d" sha1="43453a5639c9722c5443b59bceca04d1fe316cec" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 labyrinth in the forest.vgz" />
- <dataarea name="quik" size="6984">
- <rom name="22 labyrinth in the forest.vgz" size="6984" crc="add4b7c5" sha1="70b4e6cbb4a35f65369cb05d47ff1aa4855cfbba" offset="0" />
+ <dataarea name="quik" size="7035">
+ <rom name="22 labyrinth in the forest.vgz" size="7035" crc="6b78c7c9" sha1="e9d3676192b96136c1a7b41f88c87c29eb0c6336" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
<feature name="part_id" value="23 port city #2.vgz" />
- <dataarea name="quik" size="5978">
- <rom name="23 port city #2.vgz" size="5978" crc="bbc42b6f" sha1="e85914ef3cdf92db9c120c4098b06ccfd283872b" offset="0" />
+ <dataarea name="quik" size="6030">
+ <rom name="23 port city #2.vgz" size="6030" crc="a877d9ad" sha1="5bb05be4ad3eed7ceda7bbd198fd75577bc406ea" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 quiet sleep.vgz" />
- <dataarea name="quik" size="1260">
- <rom name="24 quiet sleep.vgz" size="1260" crc="ec471f59" sha1="1c3825a21037649b61201911ad18652a84a32b96" offset="0" />
+ <dataarea name="quik" size="1304">
+ <rom name="24 quiet sleep.vgz" size="1304" crc="962a83fc" sha1="ae636ae05c9ffb12fae8203b5998f16cf935ca2e" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
<feature name="part_id" value="25 pirate ship.vgz" />
- <dataarea name="quik" size="7656">
- <rom name="25 pirate ship.vgz" size="7656" crc="590740a5" sha1="7ff201fa1ae19beea16948778587cdca8c6af9f4" offset="0" />
+ <dataarea name="quik" size="7704">
+ <rom name="25 pirate ship.vgz" size="7704" crc="125f7f85" sha1="d7e95ded63515a445a7a1c74f2aadc52c3d9b55f" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
<feature name="part_id" value="26 nightmare.vgz" />
- <dataarea name="quik" size="3772">
- <rom name="26 nightmare.vgz" size="3772" crc="0c14a017" sha1="58255559905eb24627e615bcd1ac147df43f2429" offset="0" />
+ <dataarea name="quik" size="3821">
+ <rom name="26 nightmare.vgz" size="3821" crc="aedffc72" sha1="47bdeb5066340ce2956971d99543fdb929dfd308" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 chivalrous thief deckard.vgz" />
- <dataarea name="quik" size="5288">
- <rom name="27 chivalrous thief deckard.vgz" size="5288" crc="911923e5" sha1="1dd1fbadec61a81502dc492769b24ddccd26fc5e" offset="0" />
+ <dataarea name="quik" size="5338">
+ <rom name="27 chivalrous thief deckard.vgz" size="5338" crc="9df1cef1" sha1="f2d1e6b9178541519e72a427a63e7551908f86b6" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
<feature name="part_id" value="28 rescue.vgz" />
- <dataarea name="quik" size="9304">
- <rom name="28 rescue.vgz" size="9304" crc="2309bf9d" sha1="4402e8e87114c5e367bb27755ff1c7049ef9a1b7" offset="0" />
+ <dataarea name="quik" size="9356">
+ <rom name="28 rescue.vgz" size="9356" crc="5cf4dbac" sha1="4c786b22d0299b8ef0b6d17e5a3dcb5877cb51a5" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
<feature name="part_id" value="29 tower of illusion.vgz" />
- <dataarea name="quik" size="6776">
- <rom name="29 tower of illusion.vgz" size="6776" crc="5d9d8199" sha1="868ca30ab1f3e8bbe5ba5de1fb2e870639a3bcef" offset="0" />
+ <dataarea name="quik" size="6828">
+ <rom name="29 tower of illusion.vgz" size="6828" crc="f851dbec" sha1="f5ba1870db1b146bc49d98ab611b450e2790d0e4" offset="0" />
</dataarea>
</part>
<part name="030" interface="vgm_quik">
<feature name="part_id" value="30 alstadt castle.vgz" />
- <dataarea name="quik" size="4041">
- <rom name="30 alstadt castle.vgz" size="4041" crc="7123ec3d" sha1="4f1bb4216a8bc5c805f2537b55dad74651821c51" offset="0" />
+ <dataarea name="quik" size="4093">
+ <rom name="30 alstadt castle.vgz" size="4093" crc="51711290" sha1="9d743eac801baf5df9ef5e23ff4d34b35fa36650" offset="0" />
</dataarea>
</part>
<part name="031" interface="vgm_quik">
<feature name="part_id" value="31 cobe village.vgz" />
- <dataarea name="quik" size="5045">
- <rom name="31 cobe village.vgz" size="5045" crc="3dd6792c" sha1="95335a21e1915a505ba85bb28c10562717185601" offset="0" />
+ <dataarea name="quik" size="5095">
+ <rom name="31 cobe village.vgz" size="5095" crc="d5aff004" sha1="11e427ba596db34a4f2ec4dcb538a993eb1d79f6" offset="0" />
</dataarea>
</part>
<part name="032" interface="vgm_quik">
<feature name="part_id" value="32 ensnaring maze.vgz" />
- <dataarea name="quik" size="7793">
- <rom name="32 ensnaring maze.vgz" size="7793" crc="d2810521" sha1="26bdf539fc9f895de5a7bc03515b0bd61b09307c" offset="0" />
+ <dataarea name="quik" size="7845">
+ <rom name="32 ensnaring maze.vgz" size="7845" crc="7ad69ded" sha1="fb477e311aaf432f89beba55e9fc4220810f6919" offset="0" />
</dataarea>
</part>
<part name="033" interface="vgm_quik">
<feature name="part_id" value="33 to the ocean.vgz" />
- <dataarea name="quik" size="7640">
- <rom name="33 to the ocean.vgz" size="7640" crc="996d727b" sha1="8dad91a67d26157c2bb7e91e860d46e4bf9e7f8d" offset="0" />
+ <dataarea name="quik" size="7688">
+ <rom name="33 to the ocean.vgz" size="7688" crc="592a5c64" sha1="39ffc2d73fae515c0ce3009a4f2b7cb29175804f" offset="0" />
</dataarea>
</part>
<part name="034" interface="vgm_quik">
<feature name="part_id" value="34 fante continent.vgz" />
- <dataarea name="quik" size="7047">
- <rom name="34 fante continent.vgz" size="7047" crc="5f35db6d" sha1="f0e16ac7780d0886adee5cfa0bd80ceee590259e" offset="0" />
+ <dataarea name="quik" size="7099">
+ <rom name="34 fante continent.vgz" size="7099" crc="6b461466" sha1="0b7aa753c5f98ac75b090997ad7d89b4eeb7b495" offset="0" />
</dataarea>
</part>
<part name="035" interface="vgm_quik">
<feature name="part_id" value="35 town of redwood.vgz" />
- <dataarea name="quik" size="8009">
- <rom name="35 town of redwood.vgz" size="8009" crc="38c4040d" sha1="5aa98a77a25a3a52520344242cac383410d14839" offset="0" />
+ <dataarea name="quik" size="8060">
+ <rom name="35 town of redwood.vgz" size="8060" crc="85774775" sha1="b7ec32b0998a6439353c9451ad3cbdc33690c632" offset="0" />
</dataarea>
</part>
<part name="036" interface="vgm_quik">
<feature name="part_id" value="36 tanba village.vgz" />
- <dataarea name="quik" size="5813">
- <rom name="36 tanba village.vgz" size="5813" crc="854606cc" sha1="e6be6c72c3868018dc4784f61b2ca5d8248d9931" offset="0" />
+ <dataarea name="quik" size="5869">
+ <rom name="36 tanba village.vgz" size="5869" crc="4d3e2799" sha1="91366fde77ef998d4fbc2a0d02a69c5ede0761de" offset="0" />
</dataarea>
</part>
<part name="037" interface="vgm_quik">
<feature name="part_id" value="37 tower of sorrow.vgz" />
- <dataarea name="quik" size="10404">
- <rom name="37 tower of sorrow.vgz" size="10404" crc="5b5201f1" sha1="6929a9ebff37fa3e6dc4b35968f427db938001b8" offset="0" />
+ <dataarea name="quik" size="10456">
+ <rom name="37 tower of sorrow.vgz" size="10456" crc="c1094605" sha1="20900d1adc6e419259d703e87f5106b38847eec2" offset="0" />
</dataarea>
</part>
<part name="038" interface="vgm_quik">
<feature name="part_id" value="38 wedding bell.vgz" />
- <dataarea name="quik" size="1778">
- <rom name="38 wedding bell.vgz" size="1778" crc="1334d66c" sha1="7ea97f3399de16e20b142f67c07ec29a91a24a38" offset="0" />
+ <dataarea name="quik" size="6080">
+ <rom name="38 wedding bell.vgz" size="6080" crc="28b08f0b" sha1="a15c2f7ed9fc8b4c109bf5b4711ceb5ee69e9173" offset="0" />
</dataarea>
</part>
<part name="039" interface="vgm_quik">
<feature name="part_id" value="39 beloved person.vgz" />
- <dataarea name="quik" size="4039">
- <rom name="39 beloved person.vgz" size="4039" crc="16790145" sha1="d627b47daadbb764addbbc6dc2f2b212fa54b17f" offset="0" />
+ <dataarea name="quik" size="4088">
+ <rom name="39 beloved person.vgz" size="4088" crc="7d6b64f9" sha1="40e1aa6f1ada695ddff3481e197877706e29a858" offset="0" />
</dataarea>
</part>
<part name="040" interface="vgm_quik">
<feature name="part_id" value="40 cave #3.vgz" />
- <dataarea name="quik" size="5570">
- <rom name="40 cave #3.vgz" size="5570" crc="159680e5" sha1="705baf0602afbec9efb36ea7d0250ddc5bac6952" offset="0" />
+ <dataarea name="quik" size="5620">
+ <rom name="40 cave #3.vgz" size="5620" crc="b1e43956" sha1="bee8aa064107a6f8e2fa30e58e5005c401816e4e" offset="0" />
</dataarea>
</part>
<part name="041" interface="vgm_quik">
<feature name="part_id" value="41 dr. isaac.vgz" />
- <dataarea name="quik" size="14637">
- <rom name="41 dr. isaac.vgz" size="14637" crc="3fea3a38" sha1="a7bbab4dcbeae465fc1180ba0e3864d94a2fe431" offset="0" />
+ <dataarea name="quik" size="14690">
+ <rom name="41 dr. isaac.vgz" size="14690" crc="426c2c1c" sha1="d532e2262aac891b470422f59cb21257c7acd75f" offset="0" />
</dataarea>
</part>
<part name="042" interface="vgm_quik">
<feature name="part_id" value="42 temple.vgz" />
- <dataarea name="quik" size="6636">
- <rom name="42 temple.vgz" size="6636" crc="7e984a59" sha1="471ac0f61873f0b637175d3828ac4c6f3d25f7cd" offset="0" />
+ <dataarea name="quik" size="6687">
+ <rom name="42 temple.vgz" size="6687" crc="e4ecb0d8" sha1="3792521e49806aa8d03081c6472cff3916bb8934" offset="0" />
</dataarea>
</part>
<part name="043" interface="vgm_quik">
<feature name="part_id" value="43 four mad gods gades &amp; daos.vgz" />
- <dataarea name="quik" size="7384">
- <rom name="43 four mad gods gades &amp; daos.vgz" size="7384" crc="8056ff45" sha1="a7d3017ba29e30b1cfacac86a50bf648c5286ebe" offset="0" />
+ <dataarea name="quik" size="7435">
+ <rom name="43 four mad gods gades &amp; daos.vgz" size="7435" crc="6aa80561" sha1="7d50a64909bb8c33006fcb61bdae4718eba7cd99" offset="0" />
</dataarea>
</part>
<part name="044" interface="vgm_quik">
<feature name="part_id" value="44 four mad gods amon &amp; erim.vgz" />
- <dataarea name="quik" size="6259">
- <rom name="44 four mad gods amon &amp; erim.vgz" size="6259" crc="e3593496" sha1="9cf2260d9791cf6f86170fd826cc93f9d84d2b41" offset="0" />
+ <dataarea name="quik" size="6307">
+ <rom name="44 four mad gods amon &amp; erim.vgz" size="6307" crc="589d6c8a" sha1="4b6e72735692d56cf24970ecfe51abec9eaebdff" offset="0" />
</dataarea>
</part>
<part name="045" interface="vgm_quik">
<feature name="part_id" value="45 battle #3.vgz" />
- <dataarea name="quik" size="8369">
- <rom name="45 battle #3.vgz" size="8369" crc="2323763d" sha1="0a577a92da725dbf924ac607cd66cb5a548b3981" offset="0" />
+ <dataarea name="quik" size="8420">
+ <rom name="45 battle #3.vgz" size="8420" crc="c6125ea1" sha1="d19923b71e3b2dad69fc2ef9903886657f41af76" offset="0" />
</dataarea>
</part>
<part name="046" interface="vgm_quik">
<feature name="part_id" value="46 the wounded warrior.vgz" />
- <dataarea name="quik" size="6294">
- <rom name="46 the wounded warrior.vgz" size="6294" crc="c89a9afc" sha1="d08549256212c3a77aee6534df1113fb03d97ba7" offset="0" />
+ <dataarea name="quik" size="6346">
+ <rom name="46 the wounded warrior.vgz" size="6346" crc="b77b03d0" sha1="aa7e21dfe6e0675433f99681041ea0b0a142d160" offset="0" />
</dataarea>
</part>
<part name="047" interface="vgm_quik">
<feature name="part_id" value="47 decision.vgz" />
- <dataarea name="quik" size="8682">
- <rom name="47 decision.vgz" size="8682" crc="a919a615" sha1="05f697dd068886ad7645e9f6ae637ca7df17cf18" offset="0" />
+ <dataarea name="quik" size="8732">
+ <rom name="47 decision.vgz" size="8732" crc="1e95f0c2" sha1="99502f198d8839fbc0ed0795e624a93d947aaa7e" offset="0" />
</dataarea>
</part>
<part name="048" interface="vgm_quik">
<feature name="part_id" value="48 the new world.vgz" />
- <dataarea name="quik" size="4621">
- <rom name="48 the new world.vgz" size="4621" crc="b2a1224e" sha1="4228f151ea76de65236fdd23d543f1e9a182b956" offset="0" />
+ <dataarea name="quik" size="4670">
+ <rom name="48 the new world.vgz" size="4670" crc="2569a944" sha1="72cba85e3fc125f46708e69dd55d9d63c8c42548" offset="0" />
</dataarea>
</part>
<part name="049" interface="vgm_quik">
<feature name="part_id" value="49 rosplett continent.vgz" />
- <dataarea name="quik" size="7196">
- <rom name="49 rosplett continent.vgz" size="7196" crc="5fb2fb1d" sha1="0c11bf91a9d933b47879996d69729fa6b3e527fe" offset="0" />
+ <dataarea name="quik" size="7248">
+ <rom name="49 rosplett continent.vgz" size="7248" crc="56e0bfb6" sha1="5c6c419a681cebbd954c333a26b48bd9513d380b" offset="0" />
</dataarea>
</part>
<part name="050" interface="vgm_quik">
<feature name="part_id" value="50 midy village.vgz" />
- <dataarea name="quik" size="5510">
- <rom name="50 midy village.vgz" size="5510" crc="d9736f7f" sha1="3ac305a8c63a67139ffc9355ef8ecec5b212ae2e" offset="0" />
+ <dataarea name="quik" size="5570">
+ <rom name="50 midy village.vgz" size="5570" crc="d71d5031" sha1="5db8cefdfb56d9ee0b85dde09a2cb8cdd3cf1a19" offset="0" />
</dataarea>
</part>
<part name="051" interface="vgm_quik">
<feature name="part_id" value="51 gulduck village.vgz" />
- <dataarea name="quik" size="5586">
- <rom name="51 gulduck village.vgz" size="5586" crc="d71433bd" sha1="aea5d5b9d44026a8f6653a342124bc841e2981bd" offset="0" />
+ <dataarea name="quik" size="5637">
+ <rom name="51 gulduck village.vgz" size="5637" crc="2aa32180" sha1="94521042fb0b764c3997e4164553bb7a05727640" offset="0" />
</dataarea>
</part>
<part name="052" interface="vgm_quik">
<feature name="part_id" value="52 the bottom of the ocean.vgz" />
- <dataarea name="quik" size="7640">
- <rom name="52 the bottom of the ocean.vgz" size="7640" crc="11f9fdc9" sha1="02add0a4d87f21870fd189954f44d415a71777d0" offset="0" />
+ <dataarea name="quik" size="7693">
+ <rom name="52 the bottom of the ocean.vgz" size="7693" crc="ecf10fca" sha1="17963a1526770441324b93d17f40c0b42700532a" offset="0" />
</dataarea>
</part>
<part name="053" interface="vgm_quik">
<feature name="part_id" value="53 tower of twilight.vgz" />
- <dataarea name="quik" size="9521">
- <rom name="53 tower of twilight.vgz" size="9521" crc="b16894e2" sha1="478e24247dea7ee93d99bad442c503a5c5c85874" offset="0" />
+ <dataarea name="quik" size="9576">
+ <rom name="53 tower of twilight.vgz" size="9576" crc="2d4994c4" sha1="b0c64f660b127e1d46108976afa5ea706bd7ac1a" offset="0" />
</dataarea>
</part>
<part name="054" interface="vgm_quik">
<feature name="part_id" value="54 god of destruction guard daos.vgz" />
- <dataarea name="quik" size="6778">
- <rom name="54 god of destruction guard daos.vgz" size="6778" crc="41e2ebde" sha1="73e7103f5cec98abe275bbba66a0b76d64b64b8e" offset="0" />
+ <dataarea name="quik" size="6827">
+ <rom name="54 god of destruction guard daos.vgz" size="6827" crc="04a376ed" sha1="e40549fc40f5bd70cd40a57d499a91b5b53ec84c" offset="0" />
</dataarea>
</part>
<part name="055" interface="vgm_quik">
<feature name="part_id" value="55 confession.vgz" />
- <dataarea name="quik" size="2856">
- <rom name="55 confession.vgz" size="2856" crc="18d60678" sha1="be5d0c6b0238f1d8acf8104655e0457a5616e9ff" offset="0" />
+ <dataarea name="quik" size="2903">
+ <rom name="55 confession.vgz" size="2903" crc="f4cfc8fb" sha1="912ba14c211bf9301a2e0de4d5bf8cff6cfb4e86" offset="0" />
</dataarea>
</part>
<part name="056" interface="vgm_quik">
<feature name="part_id" value="56 battle #4.vgz" />
- <dataarea name="quik" size="10616">
- <rom name="56 battle #4.vgz" size="10616" crc="767ddd43" sha1="1d546c3d9ffdae40124b9df333b723ed4932ceee" offset="0" />
+ <dataarea name="quik" size="10667">
+ <rom name="56 battle #4.vgz" size="10667" crc="c77cc4f0" sha1="2e9a2e87a10f02338fdfe1b77a41bf53e79cf092" offset="0" />
</dataarea>
</part>
<part name="057" interface="vgm_quik">
<feature name="part_id" value="57 to doom island!!.vgz" />
- <dataarea name="quik" size="12902">
- <rom name="57 to doom island.vgz" size="12902" crc="649672ee" sha1="093c594d30580e4f3844a7e643fb588148f3003d" offset="0" />
+ <dataarea name="quik" size="12955">
+ <rom name="57 to doom island.vgz" size="12955" crc="ac35e589" sha1="01d854653588fc98eba493f5aeca063403e8c0bc" offset="0" />
</dataarea>
</part>
<part name="058" interface="vgm_quik">
<feature name="part_id" value="58 god of eternal flame zalbak.vgz" />
- <dataarea name="quik" size="8063">
- <rom name="58 god of eternal flame zalbak.vgz" size="8063" crc="65f96d3e" sha1="f691222884f6d64406d25f7a4917ed2b33254204" offset="0" />
+ <dataarea name="quik" size="8115">
+ <rom name="58 god of eternal flame zalbak.vgz" size="8115" crc="6e477193" sha1="3a87bbca6911401da12f0a02d9feb2cabe938b55" offset="0" />
</dataarea>
</part>
<part name="059" interface="vgm_quik">
<feature name="part_id" value="59 reunion, and then....vgz" />
- <dataarea name="quik" size="9493">
- <rom name="59 reunion, and then....vgz" size="9493" crc="1a3bde92" sha1="c624367ff6e1cc5a0b8035f770870dce66d07f0d" offset="0" />
+ <dataarea name="quik" size="9547">
+ <rom name="59 reunion, and then....vgz" size="9547" crc="7ea1937a" sha1="9fe556a81f8480d14f04ebcfe51b5f85436b77c0" offset="0" />
</dataarea>
</part>
<part name="060" interface="vgm_quik">
<feature name="part_id" value="60 ending.vgz" />
- <dataarea name="quik" size="12511">
- <rom name="60 ending.vgz" size="12511" crc="052009e3" sha1="58698810340bcebf83524537033949c1bd2c2fa0" offset="0" />
+ <dataarea name="quik" size="12563">
+ <rom name="60 ending.vgz" size="12563" crc="2f08c966" sha1="9242f558bdf83a89edf002913dd5a08cf973ea42" offset="0" />
</dataarea>
</part>
<part name="061" interface="vgm_quik">
<feature name="part_id" value="61 the journey continues!.vgz" />
- <dataarea name="quik" size="32864">
- <rom name="61 the journey continues.vgz" size="32864" crc="c6183833" sha1="e1fee678f4d3e78706bee702942e790a1c3dc038" offset="0" />
+ <dataarea name="quik" size="32907">
+ <rom name="61 the journey continues.vgz" size="32907" crc="bb69071a" sha1="b563daf5c0f3b9bb7389e528fcd4128ff94f177e" offset="0" />
</dataarea>
</part>
<part name="062" interface="vgm_quik">
<feature name="part_id" value="62 diary of memories.vgz" />
- <dataarea name="quik" size="8867">
- <rom name="62 diary of memories.vgz" size="8867" crc="d7858e5e" sha1="66049ea6f094328a1dd1453a97906e1bdbe922ad" offset="0" />
+ <dataarea name="quik" size="8923">
+ <rom name="62 diary of memories.vgz" size="8923" crc="37ef665d" sha1="8c19ef2a5d90a776d54fcc0f3801b797e0e5483f" offset="0" />
</dataarea>
</part>
<part name="063" interface="vgm_quik">
<feature name="part_id" value="63 unused music 1.vgz" />
- <dataarea name="quik" size="11561">
- <rom name="63 unused music 1.vgz" size="11561" crc="36b0739c" sha1="732c44274db691db0a5f5cac928ec6582df44247" offset="0" />
+ <dataarea name="quik" size="11616">
+ <rom name="63 unused music 1.vgz" size="11616" crc="e6869a96" sha1="6bef3449a686fed8a106879da59c104e1b1ce514" offset="0" />
</dataarea>
</part>
<part name="064" interface="vgm_quik">
<feature name="part_id" value="64 unused music 2.vgz" />
- <dataarea name="quik" size="6619">
- <rom name="64 unused music 2.vgz" size="6619" crc="7874ea0d" sha1="1a4613c9ed9bad8b75f8c8eb88c4674c857b35a9" offset="0" />
+ <dataarea name="quik" size="6671">
+ <rom name="64 unused music 2.vgz" size="6671" crc="b505abee" sha1="b7b55c0c0cab2b8ca1e331a9fc60ca569de0c44d" offset="0" />
</dataarea>
</part>
<part name="065" interface="vgm_quik">
<feature name="part_id" value="65 unused music 3.vgz" />
- <dataarea name="quik" size="8378">
- <rom name="65 unused music 3.vgz" size="8378" crc="5f231ec6" sha1="07fe96cf33509c8672ab77eed9dd8633e9dcf80d" offset="0" />
+ <dataarea name="quik" size="8428">
+ <rom name="65 unused music 3.vgz" size="8428" crc="e019d5e8" sha1="bbe34d0b56fda07c220cf3f9272c97afea714da4" offset="0" />
</dataarea>
</part>
<part name="066" interface="vgm_quik">
<feature name="part_id" value="66 unused music 4.vgz" />
- <dataarea name="quik" size="9274">
- <rom name="66 unused music 4.vgz" size="9274" crc="4548fa62" sha1="fc3138251cedc97d3a1606d3e6be3fbc86f49f37" offset="0" />
+ <dataarea name="quik" size="9327">
+ <rom name="66 unused music 4.vgz" size="9327" crc="fac884c6" sha1="365668ac16273f1360552e2e9c4e9176017b2791" offset="0" />
</dataarea>
</part>
<part name="067" interface="vgm_quik">
<feature name="part_id" value="67 unused music 5.vgz" />
- <dataarea name="quik" size="3990">
- <rom name="67 unused music 5.vgz" size="3990" crc="7d338524" sha1="851f491d615d87daaaa1162c4221e4615eb4315c" offset="0" />
+ <dataarea name="quik" size="4040">
+ <rom name="67 unused music 5.vgz" size="4040" crc="842e646f" sha1="49b864d1d7646669272cd6b1be11abe90c95b95c" offset="0" />
</dataarea>
</part>
<part name="068" interface="vgm_quik">
<feature name="part_id" value="68 unused music 6.vgz" />
- <dataarea name="quik" size="4979">
- <rom name="68 unused music 6.vgz" size="4979" crc="7c0036cc" sha1="f5831e65f15b4d342f34919f625bc5ded59b32d6" offset="0" />
+ <dataarea name="quik" size="5031">
+ <rom name="68 unused music 6.vgz" size="5031" crc="36ec02c4" sha1="495de3cdf75f1e1b129d09c6287d85d677624793" offset="0" />
</dataarea>
</part>
</software>
@@ -89655,56 +89679,68 @@ license:CC0
<info name="cores" value="AY-3-8910A"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 title.vgz" />
- <dataarea name="quik" size="649">
- <rom name="01 title.vgz" size="649" crc="7d2c4041" sha1="46dc2155da1d84a2e1f11a1e9a289752fe8e945a" offset="0" />
+ <dataarea name="quik" size="626">
+ <rom name="01 title.vgz" size="626" crc="f0f3d492" sha1="7df4abcae38256f1076bd2e9f5942956d8772094" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
- <feature name="part_id" value="02 operation intrude n313 ~ theme of tara.vgz" />
- <dataarea name="quik" size="12650">
- <rom name="02 operation intrude n313 ~ theme of tara.vgz" size="12650" crc="9e54e8dc" sha1="6a2b5a670a254b3f0a1735ede482d4e8be3bbfa0" offset="0" />
+ <feature name="part_id" value="02 operation intrude n313.vgz" />
+ <dataarea name="quik" size="1775">
+ <rom name="02 operation intrude n313.vgz" size="1775" crc="731cbd37" sha1="93273393474a6ba80dda0acff8ae5a29dae6ca5d" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
- <feature name="part_id" value="03 -!- red alert.vgz" />
- <dataarea name="quik" size="6393">
- <rom name="03 -- red alert.vgz" size="6393" crc="4653ecf3" sha1="3452d1f3266f753a983cf9f02c87d06ab6c946f8" offset="0" />
+ <feature name="part_id" value="03 theme of tara.vgz" />
+ <dataarea name="quik" size="7836">
+ <rom name="03 theme of tara.vgz" size="7836" crc="f3e2fd97" sha1="d1be302ec16e12a823b706b1675d3e9e7198dfb5" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
- <feature name="part_id" value="04 sneaking mission.vgz" />
- <dataarea name="quik" size="4429">
- <rom name="04 sneaking mission.vgz" size="4429" crc="cb1e3a01" sha1="4a26916d541f518d89a3dd46a7a16405dccc977a" offset="0" />
+ <feature name="part_id" value="04 -!- red alert.vgz" />
+ <dataarea name="quik" size="3987">
+ <rom name="04 red alert.vgz" size="3987" crc="4e418b63" sha1="fc364c60d790ff62762b4d2261e370c991c918d9" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
- <feature name="part_id" value="05 mercenary.vgz" />
- <dataarea name="quik" size="4306">
- <rom name="05 mercenary.vgz" size="4306" crc="07052da5" sha1="662ad9e3e185bdc121348895c0bdec230ef250ba" offset="0" />
+ <feature name="part_id" value="05 sneaking mission.vgz" />
+ <dataarea name="quik" size="3214">
+ <rom name="05 sneaking mission.vgz" size="3214" crc="598b4c1a" sha1="450aad2dbe25209699bb8b3c3dc863e65a8f1c30" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
- <feature name="part_id" value="06 tx-55 metal gear.vgz" />
- <dataarea name="quik" size="3899">
- <rom name="06 tx-55 metal gear.vgz" size="3899" crc="8b266caf" sha1="f607ae3dc5c1149c57cd808ad8b67ca6e2e3c5bd" offset="0" />
+ <feature name="part_id" value="06 mercenary.vgz" />
+ <dataarea name="quik" size="2641">
+ <rom name="06 mercenary.vgz" size="2641" crc="676e003d" sha1="9f7d9cb190316c005c576a06839604f6b689c473" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
- <feature name="part_id" value="07 escape -beyond big boss-.vgz" />
- <dataarea name="quik" size="5493">
- <rom name="07 escape -beyond big boss-.vgz" size="5493" crc="7834aee7" sha1="d7c76930e1534c410e523c9f27615e9c669baff8" offset="0" />
+ <feature name="part_id" value="07 tx-55 metal gear.vgz" />
+ <dataarea name="quik" size="2267">
+ <rom name="07 tx-55 metal gear.vgz" size="2267" crc="9560778d" sha1="9ade637e5b37c4a3194ee72a50221f6924d3e15b" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
- <feature name="part_id" value="08 return of fox hounder.vgz" />
- <dataarea name="quik" size="7699">
- <rom name="08 return of fox hounder.vgz" size="7699" crc="ffa5b449" sha1="303c1a7e2ad55df245f6ffe3909bb2215a494396" offset="0" />
+ <feature name="part_id" value="08 escape -beyond big boss-.vgz" />
+ <dataarea name="quik" size="3931">
+ <rom name="08 escape -beyond big boss-.vgz" size="3931" crc="8cbc81fe" sha1="cc539a1e4e67a49ef8ca247fe11c3c7bffe1797a" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
- <feature name="part_id" value="09 just another dead soldier.vgz" />
- <dataarea name="quik" size="1650">
- <rom name="09 just another dead soldier.vgz" size="1650" crc="9c446a1c" sha1="f902e377a2ee853980bafba47acd977cc1ee909e" offset="0" />
+ <feature name="part_id" value="09 return of fox hounder.vgz" />
+ <dataarea name="quik" size="5463">
+ <rom name="09 return of fox hounder.vgz" size="5463" crc="a6e1ccb7" sha1="7eebd3a1cf08c5b759f8b22f15701447436f0fa8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 just another dead soldier.vgz" />
+ <dataarea name="quik" size="1430">
+ <rom name="10 just another dead soldier.vgz" size="1430" crc="2d0348eb" sha1="c6e3a7a8127ee8d4323959cd9929a2be116e8b0f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 -!- red alert (alternate, unused).vgz" />
+ <dataarea name="quik" size="4233">
+ <rom name="11 red alert (alternate, unused).vgz" size="4233" crc="a74d1104" sha1="0eb1e554b4fb73f5524daacdf398b862004ea9b5" offset="0" />
</dataarea>
</part>
</software>
@@ -94267,169 +94303,169 @@ license:CC0
<software name="crsword">
<description>Crossed Swords (Neo Geo)</description>
- <year>1990</year>
+ <year>1991</year>
<publisher>SNK</publisher>
<info name="cores" value="YM2610"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 crossed swords opening.vgz" />
- <dataarea name="quik" size="115951">
- <rom name="01 crossed swords opening.vgz" size="115951" crc="7c5b11b7" sha1="98174ee84648666dccafc41b37fe55a84f0fa143" offset="0" />
+ <dataarea name="quik" size="107090">
+ <rom name="01 crossed swords opening.vgz" size="107090" crc="31a573d2" sha1="77094723f82bea843492430b42981b41ffed2baf" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 map.vgz" />
- <dataarea name="quik" size="43229">
- <rom name="02 map.vgz" size="43229" crc="1ae9d9f6" sha1="e3c3fa572f6edab714db000b2f2a7e32a41cefe8" offset="0" />
+ <dataarea name="quik" size="37862">
+ <rom name="02 map.vgz" size="37862" crc="3b2f301a" sha1="1d9da2fd6583d2e5767cb03cbe786fbf106275f3" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 stage select.vgz" />
- <dataarea name="quik" size="135442">
- <rom name="03 stage select.vgz" size="135442" crc="2e3cae82" sha1="43e182f6690f6cf4a439a7b04818db0f19548dbd" offset="0" />
+ <dataarea name="quik" size="127409">
+ <rom name="03 stage select.vgz" size="127409" crc="a5befce0" sha1="5d5fa87a550c2fe4ec30c6aa538cc0f004d2f796" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
- <feature name="part_id" value="04 event at gate village.vgz" />
- <dataarea name="quik" size="133372">
- <rom name="04 event at gate village.vgz" size="133372" crc="8ded6452" sha1="b760cf8c1a6ca4fbebbcf2df8c3f47b625ee0569" offset="0" />
+ <feature name="part_id" value="04 disaster in the poor village of dio.vgz" />
+ <dataarea name="quik" size="134558">
+ <rom name="04 disaster in the poor village of dio.vgz" size="134558" crc="35ed3624" sha1="3347a5b43fc04c698ea247413e324562f5525140" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 strong enemy.vgz" />
- <dataarea name="quik" size="81755">
- <rom name="05 strong enemy.vgz" size="81755" crc="69833632" sha1="c8baf6ff81be6b239815b46db327129cdaa39f5e" offset="0" />
+ <dataarea name="quik" size="75652">
+ <rom name="05 strong enemy.vgz" size="75652" crc="dfcc8e35" sha1="c35dc82c45d1d74937c52c66f3550f1c9f3c7279" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 clear.vgz" />
- <dataarea name="quik" size="62400">
- <rom name="06 clear.vgz" size="62400" crc="00d51da7" sha1="47dab5ad184b939150a311a80c7f05b488044e72" offset="0" />
+ <dataarea name="quik" size="59841">
+ <rom name="06 clear.vgz" size="59841" crc="ce5304dd" sha1="1035b16736cd1df55a7cc32b04fee0bb76cf0658" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
- <feature name="part_id" value="07 the merchant raosta.vgz" />
- <dataarea name="quik" size="9751">
- <rom name="07 the merchant raosta.vgz" size="9751" crc="72e35ffa" sha1="74cbdad5525c5ca4f8f5175791b21eaf9c182861" offset="0" />
+ <feature name="part_id" value="07 raoster the merchant.vgz" />
+ <dataarea name="quik" size="10058">
+ <rom name="07 raoster the merchant.vgz" size="10058" crc="1156b72f" sha1="45391b8faab9641cb9fef10d66ef14717c85d771" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 guidepost.vgz" />
- <dataarea name="quik" size="39957">
- <rom name="08 guidepost.vgz" size="39957" crc="210882e6" sha1="ca1e5c4ecbc4166d1962c85dd0007348bae3b5f4" offset="0" />
+ <dataarea name="quik" size="40085">
+ <rom name="08 guidepost.vgz" size="40085" crc="e1fe8d39" sha1="269ca78af8ac8562c86fb5e1d4540c1ebfd2352f" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
- <feature name="part_id" value="09 paulista castle shake.vgz" />
- <dataarea name="quik" size="40174">
- <rom name="09 paulista castle shake.vgz" size="40174" crc="744fff33" sha1="a96b8858ddd4268ed3f150516d77aceb03b1f0b6" offset="0" />
+ <feature name="part_id" value="09 pulista castle shake.vgz" />
+ <dataarea name="quik" size="40133">
+ <rom name="09 pulista castle shake.vgz" size="40133" crc="219ba155" sha1="ce0b94744240a9a4ead675af5ae4583dec0a2be8" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 old man.vgz" />
- <dataarea name="quik" size="32177">
- <rom name="10 old man.vgz" size="32177" crc="7ec36603" sha1="bc926f0972b59d3e1208a44d0b6c3034b83c6005" offset="0" />
+ <dataarea name="quik" size="29092">
+ <rom name="10 old man.vgz" size="29092" crc="df4276ee" sha1="02aaab29f192c8b96777acaf8b5fc4ed33bad80a" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 hard fight at matius tower.vgz" />
- <dataarea name="quik" size="113449">
- <rom name="11 hard fight at matius tower.vgz" size="113449" crc="64ab87ce" sha1="fe35a7acdd028ea0a7b5bcc20513e2c4a8416ddc" offset="0" />
+ <dataarea name="quik" size="107019">
+ <rom name="11 hard fight at matius tower.vgz" size="107019" crc="d9cd718c" sha1="679b57924196c6ba6ee22d4de464128a43ed7f78" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 fear.vgz" />
- <dataarea name="quik" size="30191">
- <rom name="12 fear.vgz" size="30191" crc="f358b5de" sha1="e12137d01b8449d1713d6c20381db8ce01626c8c" offset="0" />
+ <dataarea name="quik" size="30131">
+ <rom name="12 fear.vgz" size="30131" crc="3093a621" sha1="3d3ca4107732ea0266e87cd138e51ca67b73ed66" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
- <feature name="part_id" value="13 tinne.vgz" />
- <dataarea name="quik" size="90230">
- <rom name="13 tinne.vgz" size="90230" crc="891d6168" sha1="194638df8d9264cdabd9dcb63f5b53cd0e5da894" offset="0" />
+ <feature name="part_id" value="13 teanu.vgz" />
+ <dataarea name="quik" size="81954">
+ <rom name="13 teanu.vgz" size="81954" crc="34640f75" sha1="9ff98759190870ec0f9d606fee2fcadf5c1813b7" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 death masquerade.vgz" />
- <dataarea name="quik" size="58978">
- <rom name="14 death masquerade.vgz" size="58978" crc="7cf5fd03" sha1="8bc9ded9b1acbd1fefcaa229fc3bf8af3e75a69e" offset="0" />
+ <dataarea name="quik" size="59713">
+ <rom name="14 death masquerade.vgz" size="59713" crc="ee56b0a4" sha1="15b9b5612a7605693a832a9f4cf118ffe1aa64b7" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
- <feature name="part_id" value="15 strange fish at gohda fortress.vgz" />
- <dataarea name="quik" size="267345">
- <rom name="15 strange fish at gohda fortress.vgz" size="267345" crc="6a5dc834" sha1="1d53ffb77dbf437eb1947f32cd96df2199034e36" offset="0" />
+ <feature name="part_id" value="15 strange fish at gauda fortress.vgz" />
+ <dataarea name="quik" size="267751">
+ <rom name="15 strange fish at gauda fortress.vgz" size="267751" crc="96c0f00e" sha1="5cd9d194dbb3b828f4462cf12c153b9e1c6a6e66" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
- <feature name="part_id" value="16 earth crawler.vgz" />
- <dataarea name="quik" size="175229">
- <rom name="16 earth crawler.vgz" size="175229" crc="14d6d806" sha1="dfa47c0262ba4d7c098f281415c2a4e8732cf173" offset="0" />
+ <feature name="part_id" value="16 crawler.vgz" />
+ <dataarea name="quik" size="175537">
+ <rom name="16 crawler.vgz" size="175537" crc="2de9f70f" sha1="9819fae4cb61c91685bb37e95715cc249a5add97" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 assault on the battleship.vgz" />
- <dataarea name="quik" size="72978">
- <rom name="17 assault on the battleship.vgz" size="72978" crc="4402bc29" sha1="f0b7393c812071f284be615c591824e2d9a54795" offset="0" />
+ <dataarea name="quik" size="73063">
+ <rom name="17 assault on the battleship.vgz" size="73063" crc="cdd1af8f" sha1="8db1531884d66d4c5bcef9cc8112bfa8f08c1a3a" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 baxley.vgz" />
- <dataarea name="quik" size="70423">
- <rom name="18 baxley.vgz" size="70423" crc="07023fb2" sha1="8e03ad601c7fc42bd0267d758fefff03abe27509" offset="0" />
+ <dataarea name="quik" size="62427">
+ <rom name="18 baxley.vgz" size="62427" crc="724db52f" sha1="1008f0515db0c523ffb66edb0af46b92cd6719cd" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 reali cave.vgz" />
- <dataarea name="quik" size="49916">
- <rom name="19 reali cave.vgz" size="49916" crc="145300d2" sha1="9def0331d9c708555ffa9448744b3b8695c1c0b2" offset="0" />
+ <dataarea name="quik" size="50008">
+ <rom name="19 reali cave.vgz" size="50008" crc="1f30b43a" sha1="612f2b84746e216c44b5ee68f28c391da6638508" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 old warrior.vgz" />
- <dataarea name="quik" size="100835">
- <rom name="20 old warrior.vgz" size="100835" crc="d03d0ad1" sha1="9efd2b9096c6de38f52520fdff305f9a3779fe13" offset="0" />
+ <dataarea name="quik" size="97612">
+ <rom name="20 old warrior.vgz" size="97612" crc="e8c1d3db" sha1="ae3aefbc03f4ca440ca9683e3566b5b9423d0869" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 impatience.vgz" />
- <dataarea name="quik" size="59788">
- <rom name="21 impatience.vgz" size="59788" crc="050243b2" sha1="62cc538ad78fb765f43d95db60840ec3dd4cb981" offset="0" />
+ <dataarea name="quik" size="56740">
+ <rom name="21 impatience.vgz" size="56740" crc="20e4d1d7" sha1="d8110e49e144aaf00e6b3324f8b99ecf33ef3c17" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 opening fight at glacier.vgz" />
- <dataarea name="quik" size="72805">
- <rom name="22 opening fight at glacier.vgz" size="72805" crc="37b93b28" sha1="9f392d5f4196bcbcaee202dda6882b2c251e7f72" offset="0" />
+ <dataarea name="quik" size="62317">
+ <rom name="22 opening fight at glacier.vgz" size="62317" crc="62eea1d7" sha1="221a091647993780b821a9f4e523e0f8c87bc63d" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
- <feature name="part_id" value="23 nauthiz.vgz" />
- <dataarea name="quik" size="119220">
- <rom name="23 nauthiz.vgz" size="119220" crc="f6e628ff" sha1="4eb4f9c0c9d6e3875d7c9709b3c1d500b9fa9528" offset="0" />
+ <feature name="part_id" value="23 nausizz.vgz" />
+ <dataarea name="quik" size="119590">
+ <rom name="23 nausizz.vgz" size="119590" crc="834e8707" sha1="7c58ac3d97887606829d837686d314735ec9d7df" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 distant thunder.vgz" />
- <dataarea name="quik" size="30763">
- <rom name="24 distant thunder.vgz" size="30763" crc="a49165f0" sha1="bed56f36b657929f12b3493d0b54a96749725bc5" offset="0" />
+ <dataarea name="quik" size="23904">
+ <rom name="24 distant thunder.vgz" size="23904" crc="a045e499" sha1="c9dd6bc8ff17b282a42063c6fbafc040f59edbd4" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
<feature name="part_id" value="25 clore.vgz" />
- <dataarea name="quik" size="36110">
- <rom name="25 clore.vgz" size="36110" crc="707f653b" sha1="d86b370d02a6a16db9ecfaf644b6a0b604782a5f" offset="0" />
+ <dataarea name="quik" size="36332">
+ <rom name="25 clore.vgz" size="36332" crc="9557b5b8" sha1="2e2f163055dfaf08f849ad28308f53366a47c296" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
- <feature name="part_id" value="26 recollection.vgz" />
- <dataarea name="quik" size="223015">
- <rom name="26 recollection.vgz" size="223015" crc="7a69cc19" sha1="7ea779e7c6cf7a98a38a5de2fa9cc6627078842c" offset="0" />
+ <feature name="part_id" value="26 reminiscence.vgz" />
+ <dataarea name="quik" size="187212">
+ <rom name="26 reminiscence.vgz" size="187212" crc="310c7503" sha1="c5745e9fbf007f6cc55c1313db736188e9560eec" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 game over.vgz" />
- <dataarea name="quik" size="79009">
- <rom name="27 game over.vgz" size="79009" crc="f712abb6" sha1="d68d27c48765522d9487a77be7014226e11f3bf7" offset="0" />
+ <dataarea name="quik" size="76200">
+ <rom name="27 game over.vgz" size="76200" crc="94c26b2d" sha1="3378ffb18b4fc9381f263cdd3fe500898d6e2423" offset="0" />
</dataarea>
</part>
</software>
@@ -95798,200 +95834,200 @@ license:CC0
<info name="cores" value="YM2610"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 neo geo logo.vgz" />
- <dataarea name="quik" size="1807">
- <rom name="01 neo geo logo.vgz" size="1807" crc="5c2db8f0" sha1="3c7e405dc8e837fb9575c97f716016f7d32268e1" offset="0" />
+ <dataarea name="quik" size="1748">
+ <rom name="01 neo geo logo.vgz" size="1748" crc="7c994903" sha1="00dbfba7aac3169c3b0a2e0dd598b5fab200c170" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
- <feature name="part_id" value="02 galaxy fight (title).vgz" />
- <dataarea name="quik" size="287664">
- <rom name="02 galaxy fight (title).vgz" size="287664" crc="8442746a" sha1="980b83f61cdbcb04788a7bc496aba68a5adc4643" offset="0" />
+ <feature name="part_id" value="02 galaxy fight (opening).vgz" />
+ <dataarea name="quik" size="287626">
+ <rom name="02 galaxy fight (opening).vgz" size="287626" crc="f0f605bd" sha1="874ff2fce4d21a34789b8b01b932c8598e28e74f" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 here we go! (character select).vgz" />
- <dataarea name="quik" size="103181">
- <rom name="03 here we go (character select).vgz" size="103181" crc="8a75e681" sha1="37e99f296925bcaba01c8c34dd3c371fc8bec52f" offset="0" />
+ <dataarea name="quik" size="103144">
+ <rom name="03 here we go (character select).vgz" size="103144" crc="08a847bd" sha1="fcb73249cbed72a025522dbd1150854f5bb82c04" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
- <feature name="part_id" value="04 rolf's intro.vgz" />
- <dataarea name="quik" size="83726">
- <rom name="04 rolf's intro.vgz" size="83726" crc="c4f2bffc" sha1="6fd1d1f55ebc479449bd6e479c577ac662fbdff0" offset="0" />
+ <feature name="part_id" value="04 rolf opening.vgz" />
+ <dataarea name="quik" size="83689">
+ <rom name="04 rolf opening.vgz" size="83689" crc="b8617582" sha1="d0cfb609cad969d90b37bb2e0fb0db4586d35a1f" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
- <feature name="part_id" value="05 power of fire (rolf - planet airrass).vgz" />
- <dataarea name="quik" size="390516">
- <rom name="05 power of fire (rolf - planet airrass).vgz" size="390516" crc="4b1205e7" sha1="bf1f149d74f1f996ddcb0330db93852cd72cd96e" offset="0" />
+ <feature name="part_id" value="05 power of fire (rolf stage).vgz" />
+ <dataarea name="quik" size="390455">
+ <rom name="05 power of fire (rolf stage).vgz" size="390455" crc="0851fafe" sha1="02e919c465d2a068ea75367d6865c531bdb6052c" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
- <feature name="part_id" value="06 kazuma's intro.vgz" />
- <dataarea name="quik" size="19245">
- <rom name="06 kazuma's intro.vgz" size="19245" crc="504fa7c5" sha1="6f17ebd4e1a61ace5588e40ef12403b80758e1de" offset="0" />
+ <feature name="part_id" value="06 kazuma opening.vgz" />
+ <dataarea name="quik" size="19209">
+ <rom name="06 kazuma opening.vgz" size="19209" crc="4d61ac7e" sha1="d6b4ae7777fae53e9a70f7e7e2c084db3a1417f7" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
- <feature name="part_id" value="07 yami-kagura (kazuma - planet airrass).vgz" />
- <dataarea name="quik" size="101916">
- <rom name="07 yami-kagura (kazuma - planet airrass).vgz" size="101916" crc="74ee9de8" sha1="2354793c54bbd8ba56e42353973285d914747841" offset="0" />
+ <feature name="part_id" value="07 yami-kagura (kazuma stage).vgz" />
+ <dataarea name="quik" size="101857">
+ <rom name="07 yami-kagura (kazuma stage).vgz" size="101857" crc="eb6b740f" sha1="2ccce4d6fcc295830925ac88a4ab413125c18ddb" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
- <feature name="part_id" value="08 juri's intro.vgz" />
- <dataarea name="quik" size="98851">
- <rom name="08 juri's intro.vgz" size="98851" crc="e46da20a" sha1="4eec2c242aef1c166a7c37a67cd2b1be6a97290a" offset="0" />
+ <feature name="part_id" value="08 juri opening.vgz" />
+ <dataarea name="quik" size="98812">
+ <rom name="08 juri opening.vgz" size="98812" crc="e3a8e7cc" sha1="fa67ccf00ca77777378d2a8da6b3b32a9b98ed13" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
- <feature name="part_id" value="09 eternal beauty forever (juri - planet lezaar).vgz" />
- <dataarea name="quik" size="477713">
- <rom name="09 eternal beauty forever (juri - planet lezaar).vgz" size="477713" crc="65161969" sha1="d621e61b3e3ee3e6aa48a532fd9fd17b5124b3d7" offset="0" />
+ <feature name="part_id" value="09 eternal beauty forever (juri stage).vgz" />
+ <dataarea name="quik" size="477651">
+ <rom name="09 eternal beauty forever (juri stage).vgz" size="477651" crc="afbce336" sha1="035733993c53decb34c28d8100f60d2fdcbfeda5" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
- <feature name="part_id" value="10 roomi's intro.vgz" />
- <dataarea name="quik" size="13601">
- <rom name="10 roomi's intro.vgz" size="13601" crc="05b73c00" sha1="86aff8db97d712581d0085c3042d526e4281b487" offset="0" />
+ <feature name="part_id" value="10 roomi opening.vgz" />
+ <dataarea name="quik" size="13562">
+ <rom name="10 roomi opening.vgz" size="13562" crc="902e4dfd" sha1="291b96d5f41b1faf32c60b00274883ce3093a5f2" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
- <feature name="part_id" value="11 are you listening (roomi - planet lutecia).vgz" />
- <dataarea name="quik" size="132517">
- <rom name="11 are you listening (roomi - planet lutecia).vgz" size="132517" crc="b2d426f4" sha1="1e5126b18cbebfa840832bd51c607de4a6f4428f" offset="0" />
+ <feature name="part_id" value="11 everybody is listening! (roomi stage).vgz" />
+ <dataarea name="quik" size="195439">
+ <rom name="11 everybody is listening (roomi stage).vgz" size="195439" crc="c7b4ceb4" sha1="f53c39b9fc2550bbc1ba04ef3ab714f83b0f17ea" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
- <feature name="part_id" value="12 gunter's intro.vgz" />
- <dataarea name="quik" size="44022">
- <rom name="12 gunter's intro.vgz" size="44022" crc="e2866420" sha1="726c05e73080ed9aacaf94bcc2c16cc3b9bc998c" offset="0" />
+ <feature name="part_id" value="12 gunter opening.vgz" />
+ <dataarea name="quik" size="43987">
+ <rom name="12 gunter opening.vgz" size="43987" crc="9b3d0e16" sha1="bbfb0c171331fdaf2e1a02470129185ae4fbd5ff" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
- <feature name="part_id" value="13 ancient wrath (gunter - planet guljeff).vgz" />
- <dataarea name="quik" size="105787">
- <rom name="13 ancient wrath (gunter - planet guljeff).vgz" size="105787" crc="9f1f37c7" sha1="1ba4c348d336e50daac4a082d9b8d3261b199ab3" offset="0" />
+ <feature name="part_id" value="13 ancient wrath (gunter stage).vgz" />
+ <dataarea name="quik" size="105775">
+ <rom name="13 ancient wrath (gunter stage).vgz" size="105775" crc="29de7743" sha1="699a7c962bfd891212f6af3f5a21ffcc5db6f2b3" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
- <feature name="part_id" value="14 alvan's intro.vgz" />
- <dataarea name="quik" size="17839">
- <rom name="14 alvan's intro.vgz" size="17839" crc="3cfffa22" sha1="b456c49827bacfbc2142968d5d409b11b7c64f2f" offset="0" />
+ <feature name="part_id" value="14 alvan opening.vgz" />
+ <dataarea name="quik" size="17805">
+ <rom name="14 alvan opening.vgz" size="17805" crc="2a0949cf" sha1="2218e5dcaaefc86c8ddf9275aba7ff2699c1d249" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
- <feature name="part_id" value="15 ba-rock (alvan - planet rozalis).vgz" />
- <dataarea name="quik" size="171241">
- <rom name="15 ba-rock (alvan - planet rozalis).vgz" size="171241" crc="9bb1f3d5" sha1="1efe2d2bb6f9deee7f2522b690184f003007a79c" offset="0" />
+ <feature name="part_id" value="15 ba-rock (alvan stage).vgz" />
+ <dataarea name="quik" size="171178">
+ <rom name="15 ba-rock (alvan stage).vgz" size="171178" crc="ae9d3153" sha1="3496cb1c3579fe2c742348c02397aa8575ec1a44" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
- <feature name="part_id" value="16 golden done's intro.vgz" />
- <dataarea name="quik" size="14580">
- <rom name="16 golden done's intro.vgz" size="14580" crc="5fd8fb02" sha1="51102c96dfa3cf1c0d177773740e18860dc2dc95" offset="0" />
+ <feature name="part_id" value="16 golden done opening.vgz" />
+ <dataarea name="quik" size="14535">
+ <rom name="16 golden done opening.vgz" size="14535" crc="786dc789" sha1="9580706aa20bc89465968a8b4a5b3d2b6b8ac9e6" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
- <feature name="part_id" value="17 ethereal dance (golden done - planet mani).vgz" />
- <dataarea name="quik" size="122008">
- <rom name="17 ethereal dance (golden done - planet mani).vgz" size="122008" crc="1fcca268" sha1="60819351bc14baa959da400b496123913a900f26" offset="0" />
+ <feature name="part_id" value="17 ethereal dance (golden done stage).vgz" />
+ <dataarea name="quik" size="121949">
+ <rom name="17 ethereal dance (golden done stage).vgz" size="121949" crc="499d4074" sha1="30ad9d1c821314e91c4d8388895f52634abe9d56" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
- <feature name="part_id" value="18 musafar's intro.vgz" />
- <dataarea name="quik" size="16313">
- <rom name="18 musafar's intro.vgz" size="16313" crc="4898c5f8" sha1="b7511edc7d943cc654669dd5a5d6f9df49d01c67" offset="0" />
+ <feature name="part_id" value="18 musafar opening.vgz" />
+ <dataarea name="quik" size="16275">
+ <rom name="18 musafar opening.vgz" size="16275" crc="097eefe1" sha1="ef7324ce179f407906a9b8066cdd2b3fff57be9e" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
- <feature name="part_id" value="19 strong of bring the noise (musafar - planet fakir).vgz" />
- <dataarea name="quik" size="95979">
- <rom name="19 strong of bring the noise (musafar - planet fakir).vgz" size="95979" crc="d0a9555f" sha1="45558607d3a23e569ca986dcbf2957beb0b781a8" offset="0" />
+ <feature name="part_id" value="19 strong of bring the noise (musafar stage).vgz" />
+ <dataarea name="quik" size="95915">
+ <rom name="19 strong of bring the noise (musafar stage).vgz" size="95915" crc="a91b0ed8" sha1="f9e03241fb58134ac3051736c5c66675415981fe" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
- <feature name="part_id" value="20 bloody street (matchup - planet verazques).vgz" />
- <dataarea name="quik" size="511434">
- <rom name="20 bloody street (matchup - planet verazques).vgz" size="511434" crc="c102d8a3" sha1="2c713ff78969257b8cf96a55af509895972ce954" offset="0" />
+ <feature name="part_id" value="20 bloody street (matchup stage).vgz" />
+ <dataarea name="quik" size="511598">
+ <rom name="20 bloody street (matchup stage).vgz" size="511598" crc="804cde3d" sha1="815e50ee350700d170501391386aafc53e97a893" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
- <feature name="part_id" value="21 yacopu's intro.vgz" />
- <dataarea name="quik" size="101381">
- <rom name="21 yacopu's intro.vgz" size="101381" crc="06636b96" sha1="da59f3852da762c65fea09d78069e223e45880d8" offset="0" />
+ <feature name="part_id" value="21 yacopu opening.vgz" />
+ <dataarea name="quik" size="101337">
+ <rom name="21 yacopu opening.vgz" size="101337" crc="224db731" sha1="e47bef2d1800800988a42295a779a4c49873e42f" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
- <feature name="part_id" value="22 trip! trip! trip! (yacopu - planet lutecia).vgz" />
- <dataarea name="quik" size="189245">
- <rom name="22 trip trip trip (yacopu - planet lutecia).vgz" size="189245" crc="9fcdfbd7" sha1="e5f47080709737d0cb7fb25fb5b89a0660935837" offset="0" />
+ <feature name="part_id" value="22 trip! trip! trip! (yacopu stage).vgz" />
+ <dataarea name="quik" size="189377">
+ <rom name="22 trip trip trip (yacopu stage).vgz" size="189377" crc="bf1701ab" sha1="003d6e13d15da3c867772c565a5ce123c0079a9e" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
- <feature name="part_id" value="23 felden crais' intro.vgz" />
- <dataarea name="quik" size="37032">
- <rom name="23 felden crais' intro.vgz" size="37032" crc="f9bc7bf0" sha1="8fdd7e65eb0dd25f05b76c8c66b24ee0e796e13e" offset="0" />
+ <feature name="part_id" value="23 felden crais opening.vgz" />
+ <dataarea name="quik" size="36996">
+ <rom name="23 felden crais opening.vgz" size="36996" crc="450e98e5" sha1="3a2291bba4133b73cd3890b363d1c0b1956eb374" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
- <feature name="part_id" value="24 pressure drop (felden crais' stage).vgz" />
- <dataarea name="quik" size="192674">
- <rom name="24 pressure drop (felden crais' stage).vgz" size="192674" crc="93c8f384" sha1="ba1e6d841d61bbbffaf7fb5063ee8227c4cbe6ff" offset="0" />
+ <feature name="part_id" value="24 pressure drop (felden crais stage).vgz" />
+ <dataarea name="quik" size="192664">
+ <rom name="24 pressure drop (felden crais stage).vgz" size="192664" crc="07a83744" sha1="7347c0014683cb018861088750a64748cca94863" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
- <feature name="part_id" value="25 rouwe's intro.vgz" />
- <dataarea name="quik" size="95933">
- <rom name="25 rouwe's intro.vgz" size="95933" crc="c8501500" sha1="913f4118de0dae511bda6b99b792082181bf7b77" offset="0" />
+ <feature name="part_id" value="25 rouwe opening.vgz" />
+ <dataarea name="quik" size="95896">
+ <rom name="25 rouwe opening.vgz" size="95896" crc="5a7b0edc" sha1="64f129685cdeb2a5f1a3758d800f7e5cd79012bc" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
- <feature name="part_id" value="26 you will not a mysterious hermit (rouwe's stage).vgz" />
- <dataarea name="quik" size="197339">
- <rom name="26 you will not a mysterious hermit (rouwe's stage).vgz" size="197339" crc="88810434" sha1="10ad4c74f2c793031fe87516d6463d0f803eacda" offset="0" />
+ <feature name="part_id" value="26 you will not a mysterious hermit (rouwe stage).vgz" />
+ <dataarea name="quik" size="197306">
+ <rom name="26 you will not a mysterious hermit (rouwe stage).vgz" size="197306" crc="fa1adfc8" sha1="b2e330dfe6072bf731c2cd7401b7ded1cc779d52" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 what the hell are you doing (continue).vgz" />
- <dataarea name="quik" size="94440">
- <rom name="27 what the hell are you doing (continue).vgz" size="94440" crc="0547e07f" sha1="192fd375bee9540f5583243907dcaf6ccb446560" offset="0" />
+ <dataarea name="quik" size="94414">
+ <rom name="27 what the hell are you doing (continue).vgz" size="94414" crc="a77df531" sha1="7c7211015f65142e50c86924123fba9f0021e09e" offset="0" />
</dataarea>
</part>
<part name="028" interface="vgm_quik">
- <feature name="part_id" value="28 full of fight (rolf, musafar - ending).vgz" />
- <dataarea name="quik" size="225213">
- <rom name="28 full of fight (rolf, musafar - ending).vgz" size="225213" crc="24357533" sha1="d29bc004a3d204db14f1acb722957eabafacb3b0" offset="0" />
+ <feature name="part_id" value="28 full of fight (rolf, musafar ending).vgz" />
+ <dataarea name="quik" size="225176">
+ <rom name="28 full of fight (rolf, musafar ending).vgz" size="225176" crc="7a89156f" sha1="3d7755d9d489d841b29b8d98a37c8cdda21a3498" offset="0" />
</dataarea>
</part>
<part name="029" interface="vgm_quik">
- <feature name="part_id" value="29 bloody sabbath day (kazuma, juri, golden done - ending).vgz" />
- <dataarea name="quik" size="139867">
- <rom name="29 bloody sabbath day (kazuma, juri, golden done - ending).vgz" size="139867" crc="1737718d" sha1="d40b13115dcd544f099b99de1f393e0847c6be0f" offset="0" />
+ <feature name="part_id" value="29 bloody sabbath day (kazuma, juri, golden done ending).vgz" />
+ <dataarea name="quik" size="139789">
+ <rom name="29 bloody sabbath day (kazuma, juri, golden done ending).vgz" size="139789" crc="434c3607" sha1="4024fe8d82903676d0fd60b103d90264f205915f" offset="0" />
</dataarea>
</part>
<part name="030" interface="vgm_quik">
- <feature name="part_id" value="30 good fortune! (gunter, alvan - ending).vgz" />
- <dataarea name="quik" size="17979">
- <rom name="30 good fortune (gunter, alvan - ending).vgz" size="17979" crc="26f1540b" sha1="c253dfbbb42bf652bd3e95608e2abaf79c6fdfc3" offset="0" />
+ <feature name="part_id" value="30 good fortune! (gunter, alvan ending).vgz" />
+ <dataarea name="quik" size="17945">
+ <rom name="30 good fortune (gunter, alvan ending).vgz" size="17945" crc="e3f0f0ea" sha1="4735812fc03474e360457dd4fb3f53c8b8da504d" offset="0" />
</dataarea>
</part>
<part name="031" interface="vgm_quik">
- <feature name="part_id" value="31 star puncher (roomi - ending).vgz" />
- <dataarea name="quik" size="228275">
- <rom name="31 star puncher (roomi - ending).vgz" size="228275" crc="612bc495" sha1="f5b1e362b072307fb4067e8084f273b915f97465" offset="0" />
+ <feature name="part_id" value="31 star puncher (roomi ending).vgz" />
+ <dataarea name="quik" size="228238">
+ <rom name="31 star puncher (roomi ending).vgz" size="228238" crc="b8ecc3e7" sha1="f6c65b119f6d20b5c778a39f9368ff23c79d7f40" offset="0" />
</dataarea>
</part>
<part name="032" interface="vgm_quik">
- <feature name="part_id" value="32 the end of fights (credits).vgz" />
- <dataarea name="quik" size="281031">
- <rom name="32 the end of fights (credits).vgz" size="281031" crc="02793a5f" sha1="798750b0fbc26f26239d069a672f2644abbf95d6" offset="0" />
+ <feature name="part_id" value="32 the end of fights (staff roll).vgz" />
+ <dataarea name="quik" size="281005">
+ <rom name="32 the end of fights (staff roll).vgz" size="281005" crc="2a9858e8" sha1="97b0f1557b85d95cadef3b7a6e34a366c7635107" offset="0" />
</dataarea>
</part>
<part name="033" interface="vgm_quik">
<feature name="part_id" value="33 game over.vgz" />
- <dataarea name="quik" size="16037">
- <rom name="33 game over.vgz" size="16037" crc="e0eb56c6" sha1="4b7fdc3dc9741ef4fb2fba73ce933f2de52c18c0" offset="0" />
+ <dataarea name="quik" size="15997">
+ <rom name="33 game over.vgz" size="15997" crc="d6d142f7" sha1="c43de99d50606db8deb7ca6ec00be58a497daf96" offset="0" />
</dataarea>
</part>
</software>
@@ -119169,18 +119205,18 @@ license:CC0
<software name="ghostbst_nes">
<description>Ghostbusters (NES)</description>
<year>1986</year>
- <publisher>Activision (US); Tokuma Shoten (JP)</publisher>
+ <publisher>Activision (U) / Tokuma Shoten (J)</publisher>
<info name="cores" value="NES APU (N2A03)"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 ghostbusters!.vgz" />
- <dataarea name="quik" size="3295">
- <rom name="01 ghostbusters.vgz" size="3295" crc="5e229f54" sha1="7d1492d25d3d93041535ecb55f1f643ea01596c0" offset="0" />
+ <dataarea name="quik" size="3366">
+ <rom name="01 ghostbusters.vgz" size="3366" crc="54e936f9" sha1="14afad094da5fe6ea3a246c111698ae8273442a1" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 main bgm.vgz" />
- <dataarea name="quik" size="7781">
- <rom name="02 main bgm.vgz" size="7781" crc="80fe5a3f" sha1="be63f855fdb67a5bde280d040642c27f9d998332" offset="0" />
+ <dataarea name="quik" size="7852">
+ <rom name="02 main bgm.vgz" size="7852" crc="cc0fe941" sha1="fbbdb308f7a3c5b797b41f60849e268bd39ce11e" offset="0" />
</dataarea>
</part>
</software>
@@ -132620,80 +132656,80 @@ license:CC0
<info name="cores" value="NES APU (N2A03)"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 title screen.vgz" />
- <dataarea name="quik" size="4365">
- <rom name="01 title screen.vgz" size="4365" crc="878b1db2" sha1="9c4d42d42b2ae4cd3a59250f34d8a5d29448c086" offset="0" />
+ <dataarea name="quik" size="4431">
+ <rom name="01 title screen.vgz" size="4431" crc="7f767ecc" sha1="1c3c138e101309ee74fbff1581f862888c976498" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 green hill zone.vgz" />
- <dataarea name="quik" size="5659">
- <rom name="02 green hill zone.vgz" size="5659" crc="42e5711a" sha1="927fe7c8c80ae18084ebac245b34dec1fd97a9f1" offset="0" />
+ <dataarea name="quik" size="5743">
+ <rom name="02 green hill zone.vgz" size="5743" crc="eaf65848" sha1="be851a2bea4b7e6946fa479a5cda985d9e16409d" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 marble zone.vgz" />
- <dataarea name="quik" size="6558">
- <rom name="03 marble zone.vgz" size="6558" crc="ddd2b21c" sha1="a0707f7021c731697faacf24ce3b95e58e84bea2" offset="0" />
+ <dataarea name="quik" size="6639">
+ <rom name="03 marble zone.vgz" size="6639" crc="0e0ada31" sha1="5676c289fd0e724a77d75d127f557d869d4496a6" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 spring yard zone.vgz" />
- <dataarea name="quik" size="8892">
- <rom name="04 spring yard zone.vgz" size="8892" crc="8305aa9d" sha1="052283a6ca1174cbd92044e94e9b96c7317c5da6" offset="0" />
+ <dataarea name="quik" size="8969">
+ <rom name="04 spring yard zone.vgz" size="8969" crc="5800565e" sha1="0943899266a8091a1e436101567a1086f36e940b" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 labyrinth zone.vgz" />
- <dataarea name="quik" size="6501">
- <rom name="05 labyrinth zone.vgz" size="6501" crc="abe15021" sha1="44a52b41a7f5715c5017b343e897bdb54242ec35" offset="0" />
+ <dataarea name="quik" size="6589">
+ <rom name="05 labyrinth zone.vgz" size="6589" crc="b0f7d204" sha1="b19cd158b4381f42daf7db8398f7d8d8a0ad672c" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 star light zone.vgz" />
- <dataarea name="quik" size="8194">
- <rom name="06 star light zone.vgz" size="8194" crc="bce8bce3" sha1="f8aecdbdf706227161810ea1c94405663f897cde" offset="0" />
+ <dataarea name="quik" size="8280">
+ <rom name="06 star light zone.vgz" size="8280" crc="08b8ffe3" sha1="27ea13b74e32ca79532f23c5a55443a21b160381" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 invincible.vgz" />
- <dataarea name="quik" size="2716">
- <rom name="07 invincible.vgz" size="2716" crc="979fc7d7" sha1="0c4587958d97a4c7bfde09ee8fc24715f746b520" offset="0" />
+ <dataarea name="quik" size="2790">
+ <rom name="07 invincible.vgz" size="2790" crc="4ea13e41" sha1="6bdb95d96ebf9bc5f2f221e855fecfbde072210e" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 act clear.vgz" />
- <dataarea name="quik" size="1715">
- <rom name="08 act clear.vgz" size="1715" crc="b78b2aa1" sha1="74c05a922a5b2b5b0ee51624065ae55f9495f35c" offset="0" />
+ <dataarea name="quik" size="1754">
+ <rom name="08 act clear.vgz" size="1754" crc="df46ba9d" sha1="c46eb94c70ebd749733dcc10e75aed7bef672b87" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 special zone.vgz" />
- <dataarea name="quik" size="6045">
- <rom name="09 special zone.vgz" size="6045" crc="b3f738b4" sha1="7a3d356faac816f2c0f4d7cde44d6e3831edc9cd" offset="0" />
+ <dataarea name="quik" size="6126">
+ <rom name="09 special zone.vgz" size="6126" crc="b879fd53" sha1="fad48e2b26ac40e625d02cef1af07785c59f1591" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 boss.vgz" />
- <dataarea name="quik" size="5365">
- <rom name="10 boss.vgz" size="5365" crc="282f0fec" sha1="5ae215ccb19cecce97a9091e60df11b2ef5be92f" offset="0" />
+ <dataarea name="quik" size="5445">
+ <rom name="10 boss.vgz" size="5445" crc="ddde9461" sha1="7664c68b33cf365cc1790720e672ce4cb2b682b8" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 drown.vgz" />
- <dataarea name="quik" size="1610">
- <rom name="11 drown.vgz" size="1610" crc="74a8a256" sha1="45f85736fffccbb8eba7a1a56ed49893a469758c" offset="0" />
+ <dataarea name="quik" size="1685">
+ <rom name="11 drown.vgz" size="1685" crc="38f344e4" sha1="5fd8d46cc56df2e4987343a3f32584b3ed33d610" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 game over.vgz" />
- <dataarea name="quik" size="2057">
- <rom name="12 game over.vgz" size="2057" crc="2ceb2240" sha1="36c04ef5033b64cb5f0143b8b911eceaca2a87be" offset="0" />
+ <dataarea name="quik" size="2131">
+ <rom name="12 game over.vgz" size="2131" crc="575102ee" sha1="46d5d4ae59cbeccdc30b137b1aafa98265d0d711" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 sonic &amp; knuckles 5 title screen.vgz" />
- <dataarea name="quik" size="2971">
- <rom name="13 sonic &amp; knuckles 5 title screen.vgz" size="2971" crc="ca2dcaf0" sha1="b05f6e6bf0701e5627372bae8853aaff30ec11b3" offset="0" />
+ <dataarea name="quik" size="3031">
+ <rom name="13 sonic &amp; knuckles 5 title screen.vgz" size="3031" crc="76af24eb" sha1="f3504dc946f61c65726fa2a614f3a580dd664479" offset="0" />
</dataarea>
</part>
</software>
@@ -134049,9 +134085,15 @@ license:CC0
</dataarea>
</part>
<part name="020" interface="vgm_quik">
- <feature name="part_id" value="20 unused.vgz" />
+ <feature name="part_id" value="20 saved the princess.vgz" />
+ <dataarea name="quik" size="3243">
+ <rom name="20 saved the princess.vgz" size="3243" crc="7bf06553" sha1="279e726aa8454f7826869377a760bbde4682db90" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 unused.vgz" />
<dataarea name="quik" size="679">
- <rom name="20 unused.vgz" size="679" crc="64ced7ac" sha1="9f03b70d6c1218772efdfeafab5114305c2d2475" offset="0" />
+ <rom name="21 unused.vgz" size="679" crc="64ced7ac" sha1="9f03b70d6c1218772efdfeafab5114305c2d2475" offset="0" />
</dataarea>
</part>
</software>
@@ -139791,164 +139833,164 @@ license:CC0
<info name="cores" value="NES APU (N2A03)"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 title screen.vgz" />
- <dataarea name="quik" size="1002">
- <rom name="01 title screen.vgz" size="1002" crc="a8ce24f7" sha1="f8debc1e846e3d2e13f9e2a10b6f6f8d83e96974" offset="0" />
+ <dataarea name="quik" size="1033">
+ <rom name="01 title screen.vgz" size="1033" crc="16d0dbed" sha1="de775114f51c059d3900fd61aa440b4245c23f05" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 title screen.vgz" />
- <dataarea name="quik" size="1088">
- <rom name="02 title screen.vgz" size="1088" crc="78b7c559" sha1="6e46e6bbbaac60403100bfe35ebad495f3c94d32" offset="0" />
+ <dataarea name="quik" size="1118">
+ <rom name="02 title screen.vgz" size="1118" crc="e985da10" sha1="e30cd83d460ee5ef20c09a8fabdcd4fc4df1069d" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 map.vgz" />
- <dataarea name="quik" size="814">
- <rom name="03 map.vgz" size="814" crc="bd7a845b" sha1="0fd67c1f10d581c888046b42a71ee087018f0266" offset="0" />
+ <dataarea name="quik" size="847">
+ <rom name="03 map.vgz" size="847" crc="ad0953cf" sha1="e3f892b527163b8c8064027854762174972b22fd" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 map.vgz" />
- <dataarea name="quik" size="801">
- <rom name="04 map.vgz" size="801" crc="f14d085d" sha1="aa68532d51cf05ef4cc4ad71b59387653e690784" offset="0" />
+ <dataarea name="quik" size="830">
+ <rom name="04 map.vgz" size="830" crc="4a18d340" sha1="f9c9f9317cfe447b04a7dd4649c3577714efd600" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 pier ~ ice supermarket.vgz" />
- <dataarea name="quik" size="2955">
- <rom name="05 pier ~ ice supermarket.vgz" size="2955" crc="89f8b89c" sha1="0f98a244edaa25a7d2585e71d678bea753f023c5" offset="0" />
+ <dataarea name="quik" size="2988">
+ <rom name="05 pier ~ ice supermarket.vgz" size="2988" crc="d10f4ab0" sha1="303a74f2183299018b26dd293270cbf8703e496d" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 island ~ ice island.vgz" />
- <dataarea name="quik" size="3413">
- <rom name="06 island ~ ice island.vgz" size="3413" crc="cfd578e4" sha1="49976183f5c783391dedb4d91028d73f28d0144c" offset="0" />
+ <dataarea name="quik" size="3450">
+ <rom name="06 island ~ ice island.vgz" size="3450" crc="106c6b41" sha1="9785dd46b8776d48f08dd62859120414c6d6365c" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 pizza duel.vgz" />
- <dataarea name="quik" size="2379">
- <rom name="07 pizza duel.vgz" size="2379" crc="9a007d8d" sha1="c6e1ce9d84c5b75a3fbae749fe0c5f3a3f19cbe0" offset="0" />
+ <dataarea name="quik" size="2414">
+ <rom name="07 pizza duel.vgz" size="2414" crc="1bb1cd4d" sha1="371bd124a175fbc24c084e29c5ce6e1a5898d006" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 card duel.vgz" />
- <dataarea name="quik" size="1260">
- <rom name="08 card duel.vgz" size="1260" crc="cdfa1e30" sha1="df059570b098b3afa84eaa22ff0cc230bf6fb1af" offset="0" />
+ <dataarea name="quik" size="1292">
+ <rom name="08 card duel.vgz" size="1292" crc="96d72d16" sha1="188081bafa7ed7553877d43cd00162626098ef3b" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 stage clear.vgz" />
- <dataarea name="quik" size="792">
- <rom name="09 stage clear.vgz" size="792" crc="6fd36085" sha1="1f4333e775cf37a56dfa14a805e5de3e11e84317" offset="0" />
+ <dataarea name="quik" size="822">
+ <rom name="09 stage clear.vgz" size="822" crc="de298bec" sha1="e14adb1afb52800e168deefe15de88051d4f34dd" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 stage clear.vgz" />
- <dataarea name="quik" size="762">
- <rom name="10 stage clear.vgz" size="762" crc="70407c9a" sha1="fea053726f0cd814cfd1c7b61ab85fd46ff2b9c1" offset="0" />
+ <dataarea name="quik" size="791">
+ <rom name="10 stage clear.vgz" size="791" crc="eb63150e" sha1="7d83a204e0232db8e9752e590ac13446d61bfb9e" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 skating ~ rooftop.vgz" />
- <dataarea name="quik" size="2275">
- <rom name="11 skating ~ rooftop.vgz" size="2275" crc="ff0124ff" sha1="864e56156c70804e4c0cd0aa84dcb4cf29541f59" offset="0" />
+ <dataarea name="quik" size="2309">
+ <rom name="11 skating ~ rooftop.vgz" size="2309" crc="6af2617d" sha1="3f54165389a481a61f11fc62e8b4380693ff04a8" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 sewer~cave ~ ship yard~jungle.vgz" />
- <dataarea name="quik" size="2550">
- <rom name="12 sewer~cave ~ ship yard~jungle.vgz" size="2550" crc="1e3f8b8e" sha1="f9b694797f6f8e80ca54785db4bfd557b9e6b723" offset="0" />
+ <dataarea name="quik" size="2584">
+ <rom name="12 sewer~cave ~ ship yard~jungle.vgz" size="2584" crc="92b067c4" sha1="5ec2835260f21a3fe273ccc0eca5eb8c9ff7bfbc" offset="0" />
</dataarea>
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 circus ~ flying.vgz" />
- <dataarea name="quik" size="3553">
- <rom name="13 circus ~ flying.vgz" size="3553" crc="d0c26f36" sha1="27a24c05a52bb01d3bcdd0f13b7a111eca3e5d0b" offset="0" />
+ <dataarea name="quik" size="3587">
+ <rom name="13 circus ~ flying.vgz" size="3587" crc="800f6368" sha1="0bcbd5ffea41443a8468ffd3c9aa761ffd3e4de2" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
<feature name="part_id" value="14 haunted house ~ haunted castle.vgz" />
- <dataarea name="quik" size="1262">
- <rom name="14 haunted house ~ haunted castle.vgz" size="1262" crc="de505834" sha1="81412ccf8711981a3127a61e75a809f7ecf25a69" offset="0" />
+ <dataarea name="quik" size="1296">
+ <rom name="14 haunted house ~ haunted castle.vgz" size="1296" crc="1a89057f" sha1="cbf3e97e0f8a7fb43d893aa5907ca2f0bc5e84c2" offset="0" />
</dataarea>
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 alley ~ wild west.vgz" />
- <dataarea name="quik" size="2429">
- <rom name="15 alley ~ wild west.vgz" size="2429" crc="649d4822" sha1="17c02cdbd98c9815b531d89ff1cdf0ad0741147b" offset="0" />
+ <dataarea name="quik" size="2462">
+ <rom name="15 alley ~ wild west.vgz" size="2462" crc="8cbcc7a8" sha1="787c302a1abb61bde558005a67c6e1a6070c47d8" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
<feature name="part_id" value="16 factory entrance ~ factory.vgz" />
- <dataarea name="quik" size="2196">
- <rom name="16 factory entrance ~ factory.vgz" size="2196" crc="2b0cd0c2" sha1="6651d9afd3d05e291dbc90bb79ee95f8114e7147" offset="0" />
+ <dataarea name="quik" size="2228">
+ <rom name="16 factory entrance ~ factory.vgz" size="2228" crc="ac6a9354" sha1="80bd41b4d02d4ffdd08ca7dc5003e0f597f4afa7" offset="0" />
</dataarea>
</part>
<part name="017" interface="vgm_quik">
<feature name="part_id" value="17 cosmic ambience ~ inside air plane.vgz" />
- <dataarea name="quik" size="2786">
- <rom name="17 cosmic ambience ~ inside air plane.vgz" size="2786" crc="ef51b605" sha1="1acec5aeb59e8cb6c1442c1120facce76d47b22d" offset="0" />
+ <dataarea name="quik" size="2816">
+ <rom name="17 cosmic ambience ~ inside air plane.vgz" size="2816" crc="f5d42dee" sha1="78a665ef9599500c4ce63803065b483c235df1b3" offset="0" />
</dataarea>
</part>
<part name="018" interface="vgm_quik">
<feature name="part_id" value="18 building~mountain ~ last flying.vgz" />
- <dataarea name="quik" size="3877">
- <rom name="18 building~mountain ~ last flying.vgz" size="3877" crc="d63e4817" sha1="0bc03c7969823a5553a406acbfb5c21d1d6fc138" offset="0" />
+ <dataarea name="quik" size="3910">
+ <rom name="18 building~mountain ~ last flying.vgz" size="3910" crc="c3a282f9" sha1="2561200a6a9a7c2cdc69791e8fe324272851edfc" offset="0" />
</dataarea>
</part>
<part name="019" interface="vgm_quik">
<feature name="part_id" value="19 final card duel.vgz" />
- <dataarea name="quik" size="1658">
- <rom name="19 final card duel.vgz" size="1658" crc="d318f813" sha1="686df3ff86fc28b5fd3354972b8e83978fa1b2f5" offset="0" />
+ <dataarea name="quik" size="1690">
+ <rom name="19 final card duel.vgz" size="1690" crc="69ad8bd5" sha1="0bed1b3cbcb45163d9171f91356267abadb97486" offset="0" />
</dataarea>
</part>
<part name="020" interface="vgm_quik">
<feature name="part_id" value="20 ending.vgz" />
- <dataarea name="quik" size="3578">
- <rom name="20 ending.vgz" size="3578" crc="3feca3dc" sha1="887b2aa21a0c709240a109e914ac4a4a6df46636" offset="0" />
+ <dataarea name="quik" size="3615">
+ <rom name="20 ending.vgz" size="3615" crc="d6f0230d" sha1="68a91d604d66bbc7a9f582c670c1ffd6715ee40d" offset="0" />
</dataarea>
</part>
<part name="021" interface="vgm_quik">
<feature name="part_id" value="21 ending.vgz" />
- <dataarea name="quik" size="953">
- <rom name="21 ending.vgz" size="953" crc="9b4eaa2c" sha1="7d4f6f956fed4becd025a646c80a969b17e64148" offset="0" />
+ <dataarea name="quik" size="984">
+ <rom name="21 ending.vgz" size="984" crc="3990b9b8" sha1="906ad197b553168ff001044e9be01691b5c36735" offset="0" />
</dataarea>
</part>
<part name="022" interface="vgm_quik">
<feature name="part_id" value="22 game over.vgz" />
- <dataarea name="quik" size="750">
- <rom name="22 game over.vgz" size="750" crc="2d257ba3" sha1="23e6d6a78910642b50a1baa0448636326cd6711b" offset="0" />
+ <dataarea name="quik" size="782">
+ <rom name="22 game over.vgz" size="782" crc="f06873f0" sha1="a5307b9c053d92efcea41a67b3f50ebd23faec82" offset="0" />
</dataarea>
</part>
<part name="023" interface="vgm_quik">
<feature name="part_id" value="23 game over.vgz" />
- <dataarea name="quik" size="804">
- <rom name="23 game over.vgz" size="804" crc="3ed3c599" sha1="e76f106054235ddec41fa7bc4400801c2577c02c" offset="0" />
+ <dataarea name="quik" size="834">
+ <rom name="23 game over.vgz" size="834" crc="1ad68636" sha1="3d15cf742753d219b6502b01a096399b3081138a" offset="0" />
</dataarea>
</part>
<part name="024" interface="vgm_quik">
<feature name="part_id" value="24 warp proporsal.vgz" />
- <dataarea name="quik" size="1155">
- <rom name="24 warp proporsal.vgz" size="1155" crc="820ba463" sha1="cb85a8ff72cff92ddbd1ad94d2f99076dc51fb65" offset="0" />
+ <dataarea name="quik" size="1186">
+ <rom name="24 warp proporsal.vgz" size="1186" crc="1600de9d" sha1="0284dda520e01e433201a6eedf248060764e9af8" offset="0" />
</dataarea>
</part>
<part name="025" interface="vgm_quik">
<feature name="part_id" value="25 whack-a-mole.vgz" />
- <dataarea name="quik" size="1129">
- <rom name="25 whack-a-mole.vgz" size="1129" crc="03c09fba" sha1="13a705043afce65b99fd24e44636093dfe5d86ec" offset="0" />
+ <dataarea name="quik" size="1158">
+ <rom name="25 whack-a-mole.vgz" size="1158" crc="f0ae6001" sha1="9426ea48107c9a49df97f7b7cc5682b324b3a3c7" offset="0" />
</dataarea>
</part>
<part name="026" interface="vgm_quik">
<feature name="part_id" value="26 invincible.vgz" />
- <dataarea name="quik" size="900">
- <rom name="26 invincible.vgz" size="900" crc="51bc29ac" sha1="c7b7b1b08a954d15212a533b1cc7251a0a79b3ca" offset="0" />
+ <dataarea name="quik" size="933">
+ <rom name="26 invincible.vgz" size="933" crc="85f399a0" sha1="79b6a70bc3a7fb0c156c58579dc7151a6042d321" offset="0" />
</dataarea>
</part>
<part name="027" interface="vgm_quik">
<feature name="part_id" value="27 invincible.vgz" />
- <dataarea name="quik" size="962">
- <rom name="27 invincible.vgz" size="962" crc="f5c009ff" sha1="dd089c793e082160b6fde2a0b8af3a02380dc3d7" offset="0" />
+ <dataarea name="quik" size="994">
+ <rom name="27 invincible.vgz" size="994" crc="0650fb26" sha1="4b34f2b2ec5d39d074f9a33fb1e5529f6970eb27" offset="0" />
</dataarea>
</part>
</software>
@@ -157689,74 +157731,80 @@ license:CC0
<info name="cores" value="Soundblaster 16 (YMF262)"/>
<part name="001" interface="vgm_quik">
<feature name="part_id" value="01 painful sigh.vgz" />
- <dataarea name="quik" size="17515">
- <rom name="01 painful sigh.vgz" size="17515" crc="29097e10" sha1="8a91063e6501c557f566e93efa1f0bfbacd8d146" offset="0" />
+ <dataarea name="quik" size="17530">
+ <rom name="01 painful sigh.vgz" size="17530" crc="5fa972ec" sha1="68ab8eab2adec80990e52152e773bdf802a2ccac" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
<feature name="part_id" value="02 beyond several nights.vgz" />
- <dataarea name="quik" size="15864">
- <rom name="02 beyond several nights.vgz" size="15864" crc="ed4ada29" sha1="20a2cd8a34171e9866a795cafd0fac50da9bc5b7" offset="0" />
+ <dataarea name="quik" size="15878">
+ <rom name="02 beyond several nights.vgz" size="15878" crc="519162bc" sha1="76e950b5e6afa043971fb456b4b6f2c9452a7eb3" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
<feature name="part_id" value="03 timeless area.vgz" />
- <dataarea name="quik" size="7120">
- <rom name="03 timeless area.vgz" size="7120" crc="2ddd54bc" sha1="644d10a5d4fe002fdf9c4d311b3dc52c54e81707" offset="0" />
+ <dataarea name="quik" size="7137">
+ <rom name="03 timeless area.vgz" size="7137" crc="cec1d049" sha1="e4c3b6dd3c7c5debe63550fa3f945f327a37d6bd" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
<feature name="part_id" value="04 tension night.vgz" />
- <dataarea name="quik" size="10109">
- <rom name="04 tension night.vgz" size="10109" crc="4aa76f02" sha1="282b8d59ccbfabed89a590b318c3ecf9cdd1a6cb" offset="0" />
+ <dataarea name="quik" size="10127">
+ <rom name="04 tension night.vgz" size="10127" crc="cbae8e45" sha1="98199bd5437d13d5fb6e74fda19d9d6fb4738a05" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
<feature name="part_id" value="05 suspicious pain.vgz" />
- <dataarea name="quik" size="12949">
- <rom name="05 suspicious pain.vgz" size="12949" crc="8c956ed3" sha1="ae78f55cc68cd631da9ecef7f11d26d0fa2670ce" offset="0" />
+ <dataarea name="quik" size="12967">
+ <rom name="05 suspicious pain.vgz" size="12967" crc="96c2ab05" sha1="27ce70ec59069690334e5e2fea11aa0c91f2cf78" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
<feature name="part_id" value="06 love the party.vgz" />
- <dataarea name="quik" size="10324">
- <rom name="06 love the party.vgz" size="10324" crc="9cd379d4" sha1="590f8bfcfddf927a8d220ca3c42e3e89627b8410" offset="0" />
+ <dataarea name="quik" size="10340">
+ <rom name="06 love the party.vgz" size="10340" crc="c6c63043" sha1="af4f322595c3542e66ff18f3dfe64c529c0e5450" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
<feature name="part_id" value="07 encounter like a wind.vgz" />
- <dataarea name="quik" size="26209">
- <rom name="07 encounter like a wind.vgz" size="26209" crc="ff15cd2f" sha1="86fdb9cffeae91106af07bd09e791a21c3bd7f99" offset="0" />
+ <dataarea name="quik" size="26226">
+ <rom name="07 encounter like a wind.vgz" size="26226" crc="03c5ab96" sha1="42fc70e810a2d34919efe890ccf2082f12f7c41c" offset="0" />
</dataarea>
</part>
<part name="008" interface="vgm_quik">
<feature name="part_id" value="08 don't look for.vgz" />
- <dataarea name="quik" size="11451">
- <rom name="08 don't look for.vgz" size="11451" crc="f70cc5ec" sha1="3e6390770c676993afa2cd13ac267e565fa5afdc" offset="0" />
+ <dataarea name="quik" size="11469">
+ <rom name="08 don't look for.vgz" size="11469" crc="7ccda88d" sha1="5a3233e78860fe3aaabeacc0c917fc32355dec89" offset="0" />
</dataarea>
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 deep blue.vgz" />
- <dataarea name="quik" size="11314">
- <rom name="09 deep blue.vgz" size="11314" crc="800139bb" sha1="d9e1b1bfa017a9189d51e4a3a4dd75172398e8e3" offset="0" />
+ <dataarea name="quik" size="11331">
+ <rom name="09 deep blue.vgz" size="11331" crc="f49febba" sha1="331770aad826ac38f7b3c50ac8f9ede1dba8d8c2" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
<feature name="part_id" value="10 obvious lovers.vgz" />
- <dataarea name="quik" size="29358">
- <rom name="10 obvious lovers.vgz" size="29358" crc="4de313b2" sha1="b75399cacd633c3981e5aa3b0ec89fadc281ad4d" offset="0" />
+ <dataarea name="quik" size="29375">
+ <rom name="10 obvious lovers.vgz" size="29375" crc="d8952dc6" sha1="772a601bbb31b4c5826d67dd28af236db0336780" offset="0" />
</dataarea>
</part>
<part name="011" interface="vgm_quik">
<feature name="part_id" value="11 our statue of liberty.vgz" />
- <dataarea name="quik" size="5103">
- <rom name="11 our statue of liberty.vgz" size="5103" crc="fdee2b0d" sha1="8ff63befce5793232de52d03a3da8c51cfe9e701" offset="0" />
+ <dataarea name="quik" size="5116">
+ <rom name="11 our statue of liberty.vgz" size="5116" crc="689f0fdf" sha1="501a254897ff0ac86b6308770736d3e6a556ea8b" offset="0" />
</dataarea>
</part>
<part name="012" interface="vgm_quik">
<feature name="part_id" value="12 morning glow of despair.vgz" />
- <dataarea name="quik" size="6324">
- <rom name="12 morning glow of despair.vgz" size="6324" crc="7468784f" sha1="13492ecd0519d152863fef621ea3f15b01516053" offset="0" />
+ <dataarea name="quik" size="6338">
+ <rom name="12 morning glow of despair.vgz" size="6338" crc="25661230" sha1="7fc07f40b5780f4a09374893af1b8eed6f1eaf67" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="miwaku no chousho.txt" />
+ <dataarea name="quik" size="1537">
+ <rom name="miwaku no chousho.txt" size="1537" crc="b1491839" sha1="4dd1597096c50c896ff605c09eb0a426955e3b3b" offset="0" />
</dataarea>
</part>
</software>
@@ -158564,45 +158612,129 @@ license:CC0
<publisher>Konami</publisher>
<info name="cores" value="YM2151, OKIM6258"/>
<part name="001" interface="vgm_quik">
- <feature name="part_id" value="01 loader.vgz" />
- <dataarea name="quik" size="32957">
- <rom name="01 loader.vgz" size="32957" crc="09c5f7ae" sha1="5cb1c51c780c4799f5e861357e81693a3451a3e6" offset="0" />
+ <feature name="part_id" value="01 load.vgz" />
+ <dataarea name="quik" size="32698">
+ <rom name="01 load.vgz" size="32698" crc="9e82bec6" sha1="239113f4f5e9f90c98f0ef5fdf2a97098cd00540" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
- <feature name="part_id" value="02 intro.vgz" />
- <dataarea name="quik" size="32834">
- <rom name="02 intro.vgz" size="32834" crc="7fea8b22" sha1="b245ce589486b871651914d717bcf6f2aa1e7d47" offset="0" />
+ <feature name="part_id" value="02 konami logo.vgz" />
+ <dataarea name="quik" size="1863">
+ <rom name="02 konami logo.vgz" size="1863" crc="4e032502" sha1="fed0e69f027d6d90d0b2101533ff5cc94dbeeb06" offset="0" />
</dataarea>
</part>
<part name="003" interface="vgm_quik">
- <feature name="part_id" value="03 menu.vgz" />
- <dataarea name="quik" size="21607">
- <rom name="03 menu.vgz" size="21607" crc="46631ebf" sha1="e9342f42c0864e5b8fea3bf07f2cf5c6e4c0b9cf" offset="0" />
+ <feature name="part_id" value="03 opening.vgz" />
+ <dataarea name="quik" size="31752">
+ <rom name="03 opening.vgz" size="31752" crc="13f41434" sha1="c9b5442d83d27a23794944db6ace014d6525f04f" offset="0" />
</dataarea>
</part>
<part name="004" interface="vgm_quik">
- <feature name="part_id" value="04 end of round.vgz" />
- <dataarea name="quik" size="14056">
- <rom name="04 end of round.vgz" size="14056" crc="89b43712" sha1="d090879404577dc5de4d979e59890d20e24c3e4c" offset="0" />
+ <feature name="part_id" value="04 menu.vgz" />
+ <dataarea name="quik" size="21036">
+ <rom name="04 menu.vgz" size="21036" crc="0391e629" sha1="aeecb15a8cc9578d8a21227a00629c841d554187" offset="0" />
</dataarea>
</part>
<part name="005" interface="vgm_quik">
- <feature name="part_id" value="05 end of game 1.vgz" />
- <dataarea name="quik" size="14481">
- <rom name="05 end of game 1.vgz" size="14481" crc="8cb6aeb5" sha1="8b68f70b36cc454b1c93626f8ff68c27f86ea4ab" offset="0" />
+ <feature name="part_id" value="05 pennant race start.vgz" />
+ <dataarea name="quik" size="1828">
+ <rom name="05 pennant race start.vgz" size="1828" crc="f1f23551" sha1="c27a6629f16141f41ea516c392b698e2764fb92b" offset="0" />
</dataarea>
</part>
<part name="006" interface="vgm_quik">
- <feature name="part_id" value="06 end of game 2.vgz" />
- <dataarea name="quik" size="23017">
- <rom name="06 end of game 2.vgz" size="23017" crc="b8fca931" sha1="2d0c5a2fdd292b0a7ac7c35758effcad517029e5" offset="0" />
+ <feature name="part_id" value="06 pennant race.vgz" />
+ <dataarea name="quik" size="27930">
+ <rom name="06 pennant race.vgz" size="27930" crc="43d45721" sha1="86edeffea387df2952a23b776569d5f010821a8f" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
- <feature name="part_id" value="07 match commentary.vgz" />
- <dataarea name="quik" size="36911">
- <rom name="07 match commentary.vgz" size="36911" crc="8f40a954" sha1="15c6b687c826aa398098375424b7ebd99194a562" offset="0" />
+ <feature name="part_id" value="07 hitting march #1.vgz" />
+ <dataarea name="quik" size="10597">
+ <rom name="07 hitting march #1.vgz" size="10597" crc="ae22f426" sha1="292a1f3e1ab0f5b4975fd50e383df9ccbf87d1c0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 hitting march #2.vgz" />
+ <dataarea name="quik" size="10306">
+ <rom name="08 hitting march #2.vgz" size="10306" crc="bfba813c" sha1="5e81ca95e02482c4d6939f4a67d126deb62fe561" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 hitting march #3.vgz" />
+ <dataarea name="quik" size="8015">
+ <rom name="09 hitting march #3.vgz" size="8015" crc="67492bba" sha1="3fe7d12b2db8638c32647f0c49aa6277eeb7b4ac" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 hitting march #4.vgz" />
+ <dataarea name="quik" size="6486">
+ <rom name="10 hitting march #4.vgz" size="6486" crc="595b1ba3" sha1="ee3f276ee5636e88ef0098439a81d0fb220bdcb8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 hit #1.vgz" />
+ <dataarea name="quik" size="4310">
+ <rom name="11 hit #1.vgz" size="4310" crc="12645d0e" sha1="123f975ff556f1832987325936f68388ad29bd66" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 hit #2.vgz" />
+ <dataarea name="quik" size="2912">
+ <rom name="12 hit #2.vgz" size="2912" crc="d162b759" sha1="9ee20be0ae5a77ce19f0346fabca7b6b268a8aca" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 lucky 7.vgz" />
+ <dataarea name="quik" size="1522">
+ <rom name="13 lucky 7.vgz" size="1522" crc="f39faa2f" sha1="ea33b8152a8e1f98b1704654bf77f54c5bde1ab8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 homerun.vgz" />
+ <dataarea name="quik" size="2271">
+ <rom name="14 homerun.vgz" size="2271" crc="e442402f" sha1="86418c47906ec6f2a5dce37e9d1f0876403f4695" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 change.vgz" />
+ <dataarea name="quik" size="13597">
+ <rom name="15 change.vgz" size="13597" crc="16f07ae3" sha1="f00cc4ff7e4be4f30fa7bdf94f9b52a9ceb76f8a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 match end.vgz" />
+ <dataarea name="quik" size="14216">
+ <rom name="16 match end.vgz" size="14216" crc="adc4d7e9" sha1="0644aa01749a0de801b009da0bf4de81e0d2d582" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 pro baseball news jingle.vgz" />
+ <dataarea name="quik" size="22802">
+ <rom name="17 pro baseball news jingle.vgz" size="22802" crc="1d5a603c" sha1="362eb6cfb59887b0d744f13c46f46a4cc0528195" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 pro baseball news.vgz" />
+ <dataarea name="quik" size="26047">
+ <rom name="18 pro baseball news.vgz" size="26047" crc="7fb95f0a" sha1="19bbedd9dec4118d04c489ef542962d576cc99f1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 league championship.vgz" />
+ <dataarea name="quik" size="25276">
+ <rom name="19 league championship.vgz" size="25276" crc="fc5f8e44" sha1="6fa5bc7b672330a4ffd483de5650a81e6ca32a65" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 ending.vgz" />
+ <dataarea name="quik" size="50379">
+ <rom name="20 ending.vgz" size="50379" crc="2d05c232" sha1="0db18295c460fdb0c5b1bf79636bf5add8e315d8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 unknown track.vgz" />
+ <dataarea name="quik" size="26441">
+ <rom name="21 unknown track.vgz" size="26441" crc="cf56d312" sha1="eb0ed3e4663d9dd9f3e40970409d4b1e9bee9015" offset="0" />
</dataarea>
</part>
</software>
@@ -177386,9 +177518,9 @@ license:CC0
</dataarea>
</part>
<part name="006" interface="vgm_quik">
- <feature name="part_id" value="06 may i help youi.vgz" />
+ <feature name="part_id" value="06 may i help you.vgz" />
<dataarea name="quik" size="4274">
- <rom name="06 may i help youi.vgz" size="4274" crc="7750d770" sha1="28b3c411f2b9293bdac4c92df7ab8bfe9ae9d716" offset="0" />
+ <rom name="06 may i help you.vgz" size="4274" crc="7750d770" sha1="28b3c411f2b9293bdac4c92df7ab8bfe9ae9d716" offset="0" />
</dataarea>
</part>
<part name="007" interface="vgm_quik">
@@ -210282,8 +210414,8 @@ license:CC0
</part>
<part name="015" interface="vgm_quik">
<feature name="part_id" value="15 bonus score.vgz" />
- <dataarea name="quik" size="29075">
- <rom name="15 bonus score.vgz" size="29075" crc="6d4c3af8" sha1="5d14e4789299717bf519468e011aa547cc4dcbc2" offset="0" />
+ <dataarea name="quik" size="29803">
+ <rom name="15 bonus score.vgz" size="29803" crc="f999a606" sha1="d5cc6422c5c7dd63c6047e86c3f8bad0ffa0d0e0" offset="0" />
</dataarea>
</part>
<part name="016" interface="vgm_quik">
@@ -237693,9 +237825,9 @@ license:CC0
<publisher>Atari</publisher>
<info name="cores" value="YM2151"/>
<part name="001" interface="vgm_quik">
- <feature name="part_id" value="01 saber dance (attract mode - stage 4).vgz" />
- <dataarea name="quik" size="5977">
- <rom name="01 saber dance (attract mode - stage 4).vgz" size="5977" crc="930844fd" sha1="bd09a48d9d55a684809384fc3cede2f48542562a" offset="0" />
+ <feature name="part_id" value="01 sabre dance (attract mode - stage 4).vgz" />
+ <dataarea name="quik" size="5976">
+ <rom name="01 sabre dance (attract mode - stage 4).vgz" size="5976" crc="fde03429" sha1="2ef343b767d4807440f7208c8ded53b87f640950" offset="0" />
</dataarea>
</part>
<part name="002" interface="vgm_quik">
@@ -237879,7 +238011,7 @@ license:CC0
<!-- vgmrips.net update - July 24, 2020 - 25 Entries -->
- <software name="konagcbh_msx2">
+ <software name="konagcbhab_msx2">
<description>Ago Board (MSX2, PSG)</description>
<year>1989</year>
<publisher>Konami</publisher>
@@ -237904,7 +238036,7 @@ license:CC0
</part>
</software>
- <software name="konagcbh_scc">
+ <software name="konagcbhab_scc">
<description>Ago Board (MSX2, SCC)</description>
<year>1989</year>
<publisher>Konami</publisher>
@@ -239287,8 +239419,8 @@ license:CC0
</part>
<part name="009" interface="vgm_quik">
<feature name="part_id" value="09 shadow (hanzo hattori).vgz" />
- <dataarea name="quik" size="244664">
- <rom name="09 shadow (hanzo hattori).vgz" size="244664" crc="96ed5118" sha1="8f466978493e43b23ef8a198de6e0d22260b21ee" offset="0" />
+ <dataarea name="quik" size="244668">
+ <rom name="09 shadow (hanzo hattori).vgz" size="244668" crc="e7bbeb65" sha1="47b41cdb4adec9fa52094372f1294b85ab899efe" offset="0" />
</dataarea>
</part>
<part name="010" interface="vgm_quik">
@@ -239311,8 +239443,8 @@ license:CC0
</part>
<part name="013" interface="vgm_quik">
<feature name="part_id" value="13 indigenous (tam tam).vgz" />
- <dataarea name="quik" size="102641">
- <rom name="13 indigenous (tam tam).vgz" size="102641" crc="e6de628c" sha1="50990d0893282b66eae010a7e03169f52128d5ec" offset="0" />
+ <dataarea name="quik" size="104671">
+ <rom name="13 indigenous (tam tam).vgz" size="104671" crc="6c244578" sha1="34d75715d2c9632716a7a518eb283df142b56118" offset="0" />
</dataarea>
</part>
<part name="014" interface="vgm_quik">
@@ -241725,6 +241857,4262 @@ license:CC0
</part>
</software>
+<!-- vgmrips.net update - October 10, 2020 - 23 Entries -->
+<!-- All are updates to existing sets (no new games) and have been merged with previous -->
+
+<!-- vgmrips.net update - October 11, 2020 - 5 Entries -->
+<!-- 1 updated set and 4 new sets -->
+
+ <software name="brival">
+ <description>Burning Rival (Sega System 32)</description>
+ <year>1993</year>
+ <publisher>Sega</publisher>
+ <info name="cores" value="2xYM3438, RF5C68"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 opening.vgz" />
+ <dataarea name="quik" size="87330">
+ <rom name="01 opening.vgz" size="87330" crc="e6cafdeb" sha1="0f5f64124f0bdd1dfe903cbb2c242296139ae622" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 credit.vgz" />
+ <dataarea name="quik" size="1159">
+ <rom name="02 credit.vgz" size="1159" crc="17c60c69" sha1="71bc2858b45d77d4ea811b6d5880dd46a1b9b2bd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 player select.vgz" />
+ <dataarea name="quik" size="35213">
+ <rom name="03 player select.vgz" size="35213" crc="a275ab36" sha1="951313fb8ece86ad684d363000a8a4c7d5c87a4d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 vs.vgz" />
+ <dataarea name="quik" size="36538">
+ <rom name="04 vs.vgz" size="36538" crc="add1d1be" sha1="e21a5589e6e2d598fc4b8d41603f9895abb2976c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 arnold's stage.vgz" />
+ <dataarea name="quik" size="89185">
+ <rom name="05 arnold's stage.vgz" size="89185" crc="f9f09327" sha1="c8a21a7b9df4867f5eb0d4123d9a5d4391e56299" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 craze's stage.vgz" />
+ <dataarea name="quik" size="137617">
+ <rom name="06 craze's stage.vgz" size="137617" crc="c8caadc5" sha1="3c78e455250581b787d881ab71894f216de55b59" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 jackson's stage.vgz" />
+ <dataarea name="quik" size="65716">
+ <rom name="07 jackson's stage.vgz" size="65716" crc="5903c560" sha1="01ce02e8a9c8691d2f4d2a3f1f5d38ff987599d5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 santana's stage.vgz" />
+ <dataarea name="quik" size="71636">
+ <rom name="08 santana's stage.vgz" size="71636" crc="175844c7" sha1="95c20dc6addc98948a36075fd2f1ae3f8d4c84da" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 shingen's stage.vgz" />
+ <dataarea name="quik" size="135910">
+ <rom name="09 shingen's stage.vgz" size="135910" crc="6219b72f" sha1="f5fcddc5a2be0afc0d69acd1b2c056fdd78e84e1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 mr.chin's stage.vgz" />
+ <dataarea name="quik" size="69958">
+ <rom name="10 mr.chin's stage.vgz" size="69958" crc="b3171398" sha1="4e5cb39981ae1b60d621253c7907fceff120a30f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 asuka's stage.vgz" />
+ <dataarea name="quik" size="57943">
+ <rom name="11 asuka's stage.vgz" size="57943" crc="c2bf3eca" sha1="bd52479c7e037d36fe22fc1db2a63bef99eb59cc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 bill's stage.vgz" />
+ <dataarea name="quik" size="61233">
+ <rom name="12 bill's stage.vgz" size="61233" crc="4f5f6213" sha1="92f32a231150cd4cc5c73fdca38613bf1f61660d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 danger.vgz" />
+ <dataarea name="quik" size="65164">
+ <rom name="13 danger.vgz" size="65164" crc="926daf79" sha1="2da794090144f1f1f95282b06104089e49da570f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 stage end.vgz" />
+ <dataarea name="quik" size="34477">
+ <rom name="14 stage end.vgz" size="34477" crc="d078f77b" sha1="33d2fecfb1128b1a767b43d72c7526675cd52c0c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 new challenger.vgz" />
+ <dataarea name="quik" size="43313">
+ <rom name="15 new challenger.vgz" size="43313" crc="607e4039" sha1="0f9fc6b8caa1d060e757c8e1e5ba6eaddf086ef5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 congratulations, continue.vgz" />
+ <dataarea name="quik" size="37575">
+ <rom name="16 congratulations, continue.vgz" size="37575" crc="f766a794" sha1="8c764093876e467d904a33e717cd1d31d84122ac" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 arnold's ending.vgz" />
+ <dataarea name="quik" size="91941">
+ <rom name="17 arnold's ending.vgz" size="91941" crc="4e6116e5" sha1="31da1894f580282c2d70d8ad95d28f24fe838942" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 craze's ending.vgz" />
+ <dataarea name="quik" size="56916">
+ <rom name="18 craze's ending.vgz" size="56916" crc="f3bdca0d" sha1="cba3a955b304a94499ef8439a42b01bfa9c5e97c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 jackson's ending.vgz" />
+ <dataarea name="quik" size="59269">
+ <rom name="19 jackson's ending.vgz" size="59269" crc="f724122d" sha1="fbc9bfc56d37c785f767dba5127c5e3a3400fc8f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 santana's ending.vgz" />
+ <dataarea name="quik" size="50501">
+ <rom name="20 santana's ending.vgz" size="50501" crc="1d2dbcc2" sha1="6b4d933eae8b9153a34f2c7589554670de8f6b75" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 shingen's ending.vgz" />
+ <dataarea name="quik" size="56299">
+ <rom name="21 shingen's ending.vgz" size="56299" crc="1856b36d" sha1="dddc626884cadf3dd5fe4fbf79f41f641a3ec8bc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 mr.chin's ending.vgz" />
+ <dataarea name="quik" size="63953">
+ <rom name="22 mr.chin's ending.vgz" size="63953" crc="0d4b3580" sha1="717336850471996069ab4288b6bed45a1346bb7d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 asuka's ending.vgz" />
+ <dataarea name="quik" size="61738">
+ <rom name="23 asuka's ending.vgz" size="61738" crc="dc53c289" sha1="fbd69870fd2f7a314f1ea28838987a4d9070d7d6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 bill's ending.vgz" />
+ <dataarea name="quik" size="59971">
+ <rom name="24 bill's ending.vgz" size="59971" crc="0aac7440" sha1="280dd447295ef3baf500ece805d734d4cca9b49d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 staff roll.vgz" />
+ <dataarea name="quik" size="64466">
+ <rom name="25 staff roll.vgz" size="64466" crc="a10b38cf" sha1="24cb0000121b3e59c9989917f653d2bf2521a406" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 game over.vgz" />
+ <dataarea name="quik" size="38100">
+ <rom name="26 game over.vgz" size="38100" crc="db9be4e1" sha1="1750dd04e274909a6cbe74a717593b3258d319f7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 vs (alt.).vgz" />
+ <dataarea name="quik" size="36595">
+ <rom name="27 vs (alt.).vgz" size="36595" crc="b3069f5d" sha1="894ab973eae40d3b2cbee7a2c95cd92c1a83997e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 unknown.vgz" />
+ <dataarea name="quik" size="39890">
+ <rom name="28 unknown.vgz" size="39890" crc="374f3d69" sha1="1bbdf59dc1f6267686bc6aab86c4551ae5a57d3b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 unknown (alt.).vgz" />
+ <dataarea name="quik" size="39733">
+ <rom name="29 unknown (alt.).vgz" size="39733" crc="f1a207dd" sha1="73fbde9938275e6e36a53898d6d90c1705802dcb" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="motos_68k">
+ <description>Motos (Sharp X68000)</description>
+ <year>1989</year>
+ <publisher>Dempa</publisher>
+ <info name="cores" value="YM2151, OKIM6258"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 loading bgm.vgz" />
+ <dataarea name="quik" size="7466">
+ <rom name="01 loading bgm.vgz" size="7466" crc="30968ae3" sha1="500d2e0fb005c3ad2a73947f040465abba2a7fc4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 attract music.vgz" />
+ <dataarea name="quik" size="3362">
+ <rom name="02 attract music.vgz" size="3362" crc="10305f94" sha1="e98b91d55299522a343241841cc1b1b75e0f34f8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 credit sound.vgz" />
+ <dataarea name="quik" size="1417">
+ <rom name="03 credit sound.vgz" size="1417" crc="a853092c" sha1="82c9c7259f80d64261900c8eea4ff1e5d8f12e52" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 round start music.vgz" />
+ <dataarea name="quik" size="2435">
+ <rom name="04 round start music.vgz" size="2435" crc="0dbbbf87" sha1="8fb16fb01ede7745bc0deb8a906ea2d8d24b0f8e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 in-game music.vgz" />
+ <dataarea name="quik" size="2764">
+ <rom name="05 in-game music.vgz" size="2764" crc="c276fa03" sha1="ac80b1a65a8670440796c0341a50448abf69542e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 round clear music.vgz" />
+ <dataarea name="quik" size="1364">
+ <rom name="06 round clear music.vgz" size="1364" crc="dbd4aa65" sha1="4f7cd2e131507fa1cfbda59c96e50f4dfe000958" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 extend fanfare.vgz" />
+ <dataarea name="quik" size="1696">
+ <rom name="07 extend fanfare.vgz" size="1696" crc="825be333" sha1="7cbc8706c2e493045d1a1449269b07487bfaa22c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 high score fanfare.vgz" />
+ <dataarea name="quik" size="1683">
+ <rom name="08 high score fanfare.vgz" size="1683" crc="60f9ff44" sha1="0df3d8b0f11d271b43d6372a3b3d38626c236d09" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 game over music.vgz" />
+ <dataarea name="quik" size="1257">
+ <rom name="09 game over music.vgz" size="1257" crc="50b6c77b" sha1="0df4c27d84a5701d2581e1fcfd6220aadde5e71b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 name entry music.vgz" />
+ <dataarea name="quik" size="4169">
+ <rom name="10 name entry music.vgz" size="4169" crc="d193edbe" sha1="ef1159f16b8244b4a29ae1fd96e01e4182bfe998" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 attract sound (arrange version).vgz" />
+ <dataarea name="quik" size="191158">
+ <rom name="11 attract sound (arrange version).vgz" size="191158" crc="47dfbc8e" sha1="c597d59d714a870eafabcaa167637181a20ff966" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 theme of motos (arrange version).vgz" />
+ <dataarea name="quik" size="72754">
+ <rom name="12 theme of motos (arrange version).vgz" size="72754" crc="7eb3e428" sha1="840f0bf097772c3cc779e11b59ee0ed49900f13c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 round clear (arrange version).vgz" />
+ <dataarea name="quik" size="26808">
+ <rom name="13 round clear (arrange version).vgz" size="26808" crc="82c0ce82" sha1="6c47b605b52a6a20c0c5761e15ff44e29cf42ce0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 hi score (arrange version).vgz" />
+ <dataarea name="quik" size="22240">
+ <rom name="14 hi score (arrange version).vgz" size="22240" crc="57b54643" sha1="1a72a201476e5f96e0aca24d67ec67754a0ead80" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 game over (arrange version).vgz" />
+ <dataarea name="quik" size="28679">
+ <rom name="15 game over (arrange version).vgz" size="28679" crc="364fe508" sha1="85d31b0c6ac44fec2a5612c15439d96f54d04054" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 ranking bgm (arrange version).vgz" />
+ <dataarea name="quik" size="99660">
+ <rom name="16 ranking bgm (arrange version).vgz" size="99660" crc="63e84d95" sha1="f9321422c37417259a20a843cccaf9229bee7e14" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 black vinegar.vgz" />
+ <dataarea name="quik" size="238176">
+ <rom name="17 black vinegar.vgz" size="238176" crc="9d91743b" sha1="8cd0413cd78d121c93a0762ebfef599d910bad98" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 girl force.vgz" />
+ <dataarea name="quik" size="134484">
+ <rom name="18 girl force.vgz" size="134484" crc="c2e5c347" sha1="a7def4c05d254dab626e815d3222b93cf0edcd8d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 lione -lu-.vgz" />
+ <dataarea name="quik" size="94806">
+ <rom name="19 lione -lu-.vgz" size="94806" crc="c6ca0a8d" sha1="8925e4959e5a7db72ce028fc4027d3dc07f94e9b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 motos giant.vgz" />
+ <dataarea name="quik" size="154826">
+ <rom name="20 motos giant.vgz" size="154826" crc="cc620eb9" sha1="1c150def0fcb758d4964b12bbd2922150ebd8b62" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 bow of truth.vgz" />
+ <dataarea name="quik" size="136221">
+ <rom name="21 bow of truth.vgz" size="136221" crc="e679a731" sha1="5bc73bdec54db56369b8dc25a42b9d9d7df78c92" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 religion -axe-.vgz" />
+ <dataarea name="quik" size="122241">
+ <rom name="22 religion -axe-.vgz" size="122241" crc="755fc581" sha1="b51ff8b6310f9a9691157792500df52c5f81ec33" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 wall of valkyrie.vgz" />
+ <dataarea name="quik" size="201623">
+ <rom name="23 wall of valkyrie.vgz" size="201623" crc="e4a99e47" sha1="777f414b3cbb5116b7e1d3f03fecbf715e4f4d86" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 rolling saru.vgz" />
+ <dataarea name="quik" size="882485">
+ <rom name="24 rolling saru.vgz" size="882485" crc="3bd36951" sha1="888cee5d04bb9b357bb29f2ec3ff13e6c776ba13" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 loading bgm (a happy new year!!).vgz" />
+ <dataarea name="quik" size="10096">
+ <rom name="25 loading bgm (a happy new year).vgz" size="10096" crc="4c7b3c2f" sha1="b00da20cac0e3d43409a8f44b6ffd04183fb8437" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 loading bgm (spring in the head).vgz" />
+ <dataarea name="quik" size="3701">
+ <rom name="26 loading bgm (spring in the head).vgz" size="3701" crc="60689558" sha1="0deb1847562384af22ac627d70a5dc8e3c3b244b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 loading bgm (for you).vgz" />
+ <dataarea name="quik" size="13858">
+ <rom name="27 loading bgm (for you).vgz" size="13858" crc="5d5849fc" sha1="8fa55d48e5dbb181cf0735ae6026a76ef990464a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 loading bgm (merry x-mas).vgz" />
+ <dataarea name="quik" size="5548">
+ <rom name="28 loading bgm (merry x-mas).vgz" size="5548" crc="ead4af2b" sha1="6d480e6714763433c867435d52482cfcecdbb28d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 loading bgm (big net).vgz" />
+ <dataarea name="quik" size="6093">
+ <rom name="29 loading bgm (big net).vgz" size="6093" crc="c103f48f" sha1="87f123682e3d738b1fa873d55f875b5a000201c1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 loading bgm (x68k initial program loader).vgz" />
+ <dataarea name="quik" size="17388">
+ <rom name="30 loading bgm (x68k initial program loader).vgz" size="17388" crc="1d7c90d9" sha1="596df82c0dede03241fa72d117ce54325de75686" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 balance test.vgz" />
+ <dataarea name="quik" size="955">
+ <rom name="31 balance test.vgz" size="955" crc="3c5a20fc" sha1="6e664b642972bae2b4b2bd05b28d460547b7c220" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ssf2_68k">
+ <description>Super Street Fighter II - The New Challengers (Sharp X68000)</description>
+ <year>1994</year>
+ <publisher>Capcom</publisher>
+ <info name="cores" value="YM2151, OKIM6258"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 opening demo.vgz" />
+ <dataarea name="quik" size="148896">
+ <rom name="01 opening demo.vgz" size="148896" crc="e09426ca" sha1="1fa6b7d9bafbcf187914211f84a2885d943bf1b7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 player select.vgz" />
+ <dataarea name="quik" size="133040">
+ <rom name="02 player select.vgz" size="133040" crc="2c5816cb" sha1="d20e545d41c137f9857664baa9f841b87d85ce83" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 tournament.vgz" />
+ <dataarea name="quik" size="26037">
+ <rom name="03 tournament.vgz" size="26037" crc="785c293f" sha1="278608aae2454b201f873dcfa0c47b27409ca482" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 vs.vgz" />
+ <dataarea name="quik" size="37960">
+ <rom name="04 vs.vgz" size="37960" crc="3eb82835" sha1="b2be68a9ac9693fa9f7bec2d7bf33f646807c019" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 ken stage 1.vgz" />
+ <dataarea name="quik" size="634648">
+ <rom name="05 ken stage 1.vgz" size="634648" crc="ad5f6b4b" sha1="2c237e3a8e932ab85d0ff401b783fdf44288b393" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 ken stage 2.vgz" />
+ <dataarea name="quik" size="407387">
+ <rom name="06 ken stage 2.vgz" size="407387" crc="4b896ced" sha1="5a5d3ce2177b61786999abc27b7436777f65f4f7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 ryu stage 1.vgz" />
+ <dataarea name="quik" size="447288">
+ <rom name="07 ryu stage 1.vgz" size="447288" crc="9b1b0019" sha1="b2d43c00afd78e5887d5d3e94ad51f5481c58625" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 ryu stage 2.vgz" />
+ <dataarea name="quik" size="242271">
+ <rom name="08 ryu stage 2.vgz" size="242271" crc="b4fb5761" sha1="2a2a6bbc238c8258fb7540083d0a9c25eb041522" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 e. honda stage 1.vgz" />
+ <dataarea name="quik" size="420974">
+ <rom name="09 e. honda stage 1.vgz" size="420974" crc="f666674f" sha1="145e62e7d3fc98eaa8f3726f7d4155b8ae1b39a3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 e. honda stage 2.vgz" />
+ <dataarea name="quik" size="199891">
+ <rom name="10 e. honda stage 2.vgz" size="199891" crc="eeae42aa" sha1="bcd70464245f44f2731bfaa0cb5bd725c4a57ee2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 chun-li stage 1.vgz" />
+ <dataarea name="quik" size="298166">
+ <rom name="11 chun-li stage 1.vgz" size="298166" crc="4bed3db8" sha1="55f714fb2839b1d105dcce7abe574345eeb3237d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 chun-li stage 2.vgz" />
+ <dataarea name="quik" size="170231">
+ <rom name="12 chun-li stage 2.vgz" size="170231" crc="9b26eeff" sha1="76b5b9532ed3ee8eaef7323a25c67bb2df92dff2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 blanka stage 1.vgz" />
+ <dataarea name="quik" size="494122">
+ <rom name="13 blanka stage 1.vgz" size="494122" crc="06b98c27" sha1="99d57603c4c84ae808edca5d00a05574beb547d3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 blanka stage 2.vgz" />
+ <dataarea name="quik" size="214100">
+ <rom name="14 blanka stage 2.vgz" size="214100" crc="494bc2b3" sha1="3dca5027ab7f9fd98297ee012f4d8f8298d6b646" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 zangief stage 1.vgz" />
+ <dataarea name="quik" size="355133">
+ <rom name="15 zangief stage 1.vgz" size="355133" crc="40d493f2" sha1="47b61862d511f4ff39288761936bacbc562463af" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 zangief stage 2.vgz" />
+ <dataarea name="quik" size="159135">
+ <rom name="16 zangief stage 2.vgz" size="159135" crc="10f96583" sha1="c4b982e56323271f3ca311970c7a8d23a78dec90" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 guile stage 1.vgz" />
+ <dataarea name="quik" size="518958">
+ <rom name="17 guile stage 1.vgz" size="518958" crc="a1518b5f" sha1="0e317e47dd37cdcc5ee6f491e24e27e6c00de80d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 guile stage 2.vgz" />
+ <dataarea name="quik" size="334243">
+ <rom name="18 guile stage 2.vgz" size="334243" crc="332ccaa4" sha1="faff3d7dfad834c6bde0e3dadf2c567997e54297" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 dhalsim stage 1.vgz" />
+ <dataarea name="quik" size="677079">
+ <rom name="19 dhalsim stage 1.vgz" size="677079" crc="9d65f2a4" sha1="3707ed10a5f1331dd1ced6beba5e2b8807715e99" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 dhalsim stage 2.vgz" />
+ <dataarea name="quik" size="433718">
+ <rom name="20 dhalsim stage 2.vgz" size="433718" crc="9d4c59c9" sha1="e6c9e4b7f1a1e2be92df4db463fda5462663ec46" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 fei long stage 1.vgz" />
+ <dataarea name="quik" size="302246">
+ <rom name="21 fei long stage 1.vgz" size="302246" crc="9c0afc3c" sha1="f6f4fb7ede8c9e1bd87a187cac91b65889db53d3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 fei long stage 2.vgz" />
+ <dataarea name="quik" size="163930">
+ <rom name="22 fei long stage 2.vgz" size="163930" crc="a5f82ea1" sha1="24184b454485636bc5bd8c19507791363be965e2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 cammy stage 1.vgz" />
+ <dataarea name="quik" size="461658">
+ <rom name="23 cammy stage 1.vgz" size="461658" crc="cc8f0a17" sha1="bc5bc36ee3e6c7e49b378e1643bbe73ab425d5a3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 cammy stage 2.vgz" />
+ <dataarea name="quik" size="200920">
+ <rom name="24 cammy stage 2.vgz" size="200920" crc="e7682845" sha1="f48da0d560e65dfe727a498f42bac1eebdb1ced1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 t. hawk stage 1.vgz" />
+ <dataarea name="quik" size="391288">
+ <rom name="25 t. hawk stage 1.vgz" size="391288" crc="4a43f7c9" sha1="fd5b181ea28277f670c7f5eb33ed3fe0a3a6d19f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 t.hawk stage 2.vgz" />
+ <dataarea name="quik" size="411313">
+ <rom name="26 t.hawk stage 2.vgz" size="411313" crc="531be088" sha1="e4bce770e5fe9c57ff493bb9cd371c0d4511fb6d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 dee jay stage 1.vgz" />
+ <dataarea name="quik" size="326106">
+ <rom name="27 dee jay stage 1.vgz" size="326106" crc="4958c5ae" sha1="af915fe8d89eb8269f5409188a74eb0d76538305" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 dee jay stage 2.vgz" />
+ <dataarea name="quik" size="112342">
+ <rom name="28 dee jay stage 2.vgz" size="112342" crc="0d078025" sha1="ce45fd9aab6716b669fc30a0663e4a46ba5ac5da" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 stage-end.vgz" />
+ <dataarea name="quik" size="53573">
+ <rom name="29 stage-end.vgz" size="53573" crc="2ea9ba01" sha1="ca21067c23ce2dcc0a427a47faacc6b51a2634b2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 bonus stage.vgz" />
+ <dataarea name="quik" size="163249">
+ <rom name="30 bonus stage.vgz" size="163249" crc="7fcafc3d" sha1="edcf8b11575f505040b414397fb30d51f8cb1932" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 balrog stage 1.vgz" />
+ <dataarea name="quik" size="476844">
+ <rom name="31 balrog stage 1.vgz" size="476844" crc="f612f21a" sha1="3740f362038cc36c06a5f86b250f8a83d8891494" offset="0" />
+ </dataarea>
+ </part>
+ <part name="032" interface="vgm_quik">
+ <feature name="part_id" value="32 balrog stage 2.vgz" />
+ <dataarea name="quik" size="197181">
+ <rom name="32 balrog stage 2.vgz" size="197181" crc="674e9e64" sha1="4bc278fc4a2368b56cd11566aec194b0c6906202" offset="0" />
+ </dataarea>
+ </part>
+ <part name="033" interface="vgm_quik">
+ <feature name="part_id" value="33 vega stage 1.vgz" />
+ <dataarea name="quik" size="352325">
+ <rom name="33 vega stage 1.vgz" size="352325" crc="dbf8ee38" sha1="f0656471fbc86fefd6a54ce8f255e1ebe5f0c320" offset="0" />
+ </dataarea>
+ </part>
+ <part name="034" interface="vgm_quik">
+ <feature name="part_id" value="34 vega stage 2.vgz" />
+ <dataarea name="quik" size="256424">
+ <rom name="34 vega stage 2.vgz" size="256424" crc="d74aedbd" sha1="d115010941f44525bb6b11faccd50238a0bad3b1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="035" interface="vgm_quik">
+ <feature name="part_id" value="35 sagat stage 1.vgz" />
+ <dataarea name="quik" size="608800">
+ <rom name="35 sagat stage 1.vgz" size="608800" crc="8511de3a" sha1="18f6328b2e14096d6dce62163e6c9cbe9703e5cb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="036" interface="vgm_quik">
+ <feature name="part_id" value="36 sagat stage 2.vgz" />
+ <dataarea name="quik" size="97868">
+ <rom name="36 sagat stage 2.vgz" size="97868" crc="6ecb8c85" sha1="ca8720c83e88605c7722d1e4aacfb38e36b5f734" offset="0" />
+ </dataarea>
+ </part>
+ <part name="037" interface="vgm_quik">
+ <feature name="part_id" value="37 m. bison stage 1.vgz" />
+ <dataarea name="quik" size="479838">
+ <rom name="37 m. bison stage 1.vgz" size="479838" crc="28d875eb" sha1="8c3a50ef37ad49892ebbe104582b6a1ce7cc191e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="038" interface="vgm_quik">
+ <feature name="part_id" value="38 m. bison stage 2.vgz" />
+ <dataarea name="quik" size="543709">
+ <rom name="38 m. bison stage 2.vgz" size="543709" crc="b603d686" sha1="7972c2620ab36d074234e71e6552a680946135f7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="039" interface="vgm_quik">
+ <feature name="part_id" value="39 here comes the new challenger.vgz" />
+ <dataarea name="quik" size="23449">
+ <rom name="39 here comes the new challenger.vgz" size="23449" crc="2529a490" sha1="583f7f9a2928c2da6c62e7820fe25675396a1c88" offset="0" />
+ </dataarea>
+ </part>
+ <part name="040" interface="vgm_quik">
+ <feature name="part_id" value="40 ken ending.vgz" />
+ <dataarea name="quik" size="104458">
+ <rom name="40 ken ending.vgz" size="104458" crc="f7d5c0cf" sha1="8f02ea1b10195af3602675ebe4b0efea14c0b3ac" offset="0" />
+ </dataarea>
+ </part>
+ <part name="041" interface="vgm_quik">
+ <feature name="part_id" value="41 ken ending 2.vgz" />
+ <dataarea name="quik" size="54306">
+ <rom name="41 ken ending 2.vgz" size="54306" crc="7086e92a" sha1="2b420238ecdfbc928900c6fc4c2486186411447a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="042" interface="vgm_quik">
+ <feature name="part_id" value="42 ryu ending.vgz" />
+ <dataarea name="quik" size="203417">
+ <rom name="42 ryu ending.vgz" size="203417" crc="9520939b" sha1="5b6ef4eae18dd5bf3e5b83d3d4012208199b018e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="043" interface="vgm_quik">
+ <feature name="part_id" value="43 e. honda ending.vgz" />
+ <dataarea name="quik" size="36449">
+ <rom name="43 e. honda ending.vgz" size="36449" crc="9d516ed2" sha1="8ae17543742d26c1e4b355c27d5268f5dad33319" offset="0" />
+ </dataarea>
+ </part>
+ <part name="044" interface="vgm_quik">
+ <feature name="part_id" value="44 chun-li ending.vgz" />
+ <dataarea name="quik" size="40376">
+ <rom name="44 chun-li ending.vgz" size="40376" crc="6a76a9e1" sha1="221ef9b967bf1594459fd0cc32f069647dd2aad1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="045" interface="vgm_quik">
+ <feature name="part_id" value="45 chun-li ending 2.vgz" />
+ <dataarea name="quik" size="142126">
+ <rom name="45 chun-li ending 2.vgz" size="142126" crc="47b80cae" sha1="d584520b3daee4308c8b68feed7c9de9336c72a2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="046" interface="vgm_quik">
+ <feature name="part_id" value="46 chun-li ending 3.vgz" />
+ <dataarea name="quik" size="334305">
+ <rom name="46 chun-li ending 3.vgz" size="334305" crc="f4f2b44e" sha1="856e99f5c16f2661109bf4a212f4c13f44f4c0d7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="047" interface="vgm_quik">
+ <feature name="part_id" value="47 blanka ending.vgz" />
+ <dataarea name="quik" size="127583">
+ <rom name="47 blanka ending.vgz" size="127583" crc="5660a6ce" sha1="0c559fb9d0571c86dd14564cebe72580d6808d19" offset="0" />
+ </dataarea>
+ </part>
+ <part name="048" interface="vgm_quik">
+ <feature name="part_id" value="48 zangief ending.vgz" />
+ <dataarea name="quik" size="68957">
+ <rom name="48 zangief ending.vgz" size="68957" crc="74279de1" sha1="935c8f64678dfc4108af7a0a5f233dc25f7f5918" offset="0" />
+ </dataarea>
+ </part>
+ <part name="049" interface="vgm_quik">
+ <feature name="part_id" value="49 guile ending.vgz" />
+ <dataarea name="quik" size="21066">
+ <rom name="49 guile ending.vgz" size="21066" crc="0d940407" sha1="64d7d0fd6e55366b6b521e04e428cda932ea38d1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="050" interface="vgm_quik">
+ <feature name="part_id" value="50 dhalsim ending.vgz" />
+ <dataarea name="quik" size="158999">
+ <rom name="50 dhalsim ending.vgz" size="158999" crc="5a77a8ef" sha1="fb93923efe20e43c5e936489ad07bb02d6d04261" offset="0" />
+ </dataarea>
+ </part>
+ <part name="051" interface="vgm_quik">
+ <feature name="part_id" value="51 fei long ending.vgz" />
+ <dataarea name="quik" size="220266">
+ <rom name="51 fei long ending.vgz" size="220266" crc="fda21086" sha1="334797d85393dc3f7901804f87b774a44dcac4e7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="052" interface="vgm_quik">
+ <feature name="part_id" value="52 cammy ending.vgz" />
+ <dataarea name="quik" size="509731">
+ <rom name="52 cammy ending.vgz" size="509731" crc="1df5147f" sha1="4306f46085bbe0fcfb40e65579c2ef11589a2e9c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="053" interface="vgm_quik">
+ <feature name="part_id" value="53 t. hawk ending.vgz" />
+ <dataarea name="quik" size="160922">
+ <rom name="53 t. hawk ending.vgz" size="160922" crc="1cb8169a" sha1="a25846e2adaebdc6feb802a66ae11927f2db7003" offset="0" />
+ </dataarea>
+ </part>
+ <part name="054" interface="vgm_quik">
+ <feature name="part_id" value="54 dee jay ending.vgz" />
+ <dataarea name="quik" size="300347">
+ <rom name="54 dee jay ending.vgz" size="300347" crc="105f2f80" sha1="b5210db04eee1f947a4d840365b1a8e59d53ff69" offset="0" />
+ </dataarea>
+ </part>
+ <part name="055" interface="vgm_quik">
+ <feature name="part_id" value="55 balrog ending.vgz" />
+ <dataarea name="quik" size="362411">
+ <rom name="55 balrog ending.vgz" size="362411" crc="b2084a8f" sha1="f28a69356709423f71f69012b25dab70593f99fd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="056" interface="vgm_quik">
+ <feature name="part_id" value="56 vega ending.vgz" />
+ <dataarea name="quik" size="73704">
+ <rom name="56 vega ending.vgz" size="73704" crc="d5172beb" sha1="de52c3c79c57d48ee2429782258612f101aa3e91" offset="0" />
+ </dataarea>
+ </part>
+ <part name="057" interface="vgm_quik">
+ <feature name="part_id" value="57 sagat ending.vgz" />
+ <dataarea name="quik" size="118791">
+ <rom name="57 sagat ending.vgz" size="118791" crc="1e2c188b" sha1="010fa3d059f216d7783d0033d5b0c752f53a4763" offset="0" />
+ </dataarea>
+ </part>
+ <part name="058" interface="vgm_quik">
+ <feature name="part_id" value="58 m. bison ending.vgz" />
+ <dataarea name="quik" size="46573">
+ <rom name="58 m. bison ending.vgz" size="46573" crc="46d3ab7e" sha1="cbf05163dae9cf6f30e91ef9c49c1bade83dced2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="059" interface="vgm_quik">
+ <feature name="part_id" value="59 congratulations!.vgz" />
+ <dataarea name="quik" size="305403">
+ <rom name="59 congratulations.vgz" size="305403" crc="219446ae" sha1="03f4dd0d021c08789d2ce830300803297255123c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="060" interface="vgm_quik">
+ <feature name="part_id" value="60 staff roll.vgz" />
+ <dataarea name="quik" size="642910">
+ <rom name="60 staff roll.vgz" size="642910" crc="3d2253dc" sha1="d2fbfb9d5d19be6bb6446c986b7086652c2ca15d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="061" interface="vgm_quik">
+ <feature name="part_id" value="61 continue.vgz" />
+ <dataarea name="quik" size="100352">
+ <rom name="61 continue.vgz" size="100352" crc="fc35e2b6" sha1="1224904fb062a322876ee56afd119a5ab8e82515" offset="0" />
+ </dataarea>
+ </part>
+ <part name="062" interface="vgm_quik">
+ <feature name="part_id" value="62 game over.vgz" />
+ <dataarea name="quik" size="24112">
+ <rom name="62 game over.vgz" size="24112" crc="db58dfbb" sha1="66b7fb4da0470921e5d2a0ffd95b07e86c8dd064" offset="0" />
+ </dataarea>
+ </part>
+ <part name="063" interface="vgm_quik">
+ <feature name="part_id" value="63 ranking display.vgz" />
+ <dataarea name="quik" size="16029">
+ <rom name="63 ranking display.vgz" size="16029" crc="91a53cd7" sha1="72d597950bcaa97c103995fde21149b2d6eb45a8" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="tblade_68k">
+ <description>Thunder Blade (Sharp X68000)</description>
+ <year>1990</year>
+ <publisher>Sharp</publisher>
+ <info name="cores" value="YM2151, OKIM6258"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 coin.vgz" />
+ <dataarea name="quik" size="1538">
+ <rom name="01 coin.vgz" size="1538" crc="2e7ed633" sha1="ab9093d7fd6acc119be6f4c82ff1ddec6263c9b2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 thunder blade (bgm 1).vgz" />
+ <dataarea name="quik" size="1128669">
+ <rom name="02 thunder blade (bgm 1).vgz" size="1128669" crc="2bb08060" sha1="eaa3d9231e97557dc213a43174413acb83684440" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 burning point (boss).vgz" />
+ <dataarea name="quik" size="317737">
+ <rom name="03 burning point (boss).vgz" size="317737" crc="0a3d21d7" sha1="7354375cab8a287a16602692eb3ea48635e89cfe" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 round clear.vgz" />
+ <dataarea name="quik" size="27156">
+ <rom name="04 round clear.vgz" size="27156" crc="f3a20d97" sha1="4888ac651afb1c5a7c40bc68844a27960cef003f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 type ii (bgm 2).vgz" />
+ <dataarea name="quik" size="667924">
+ <rom name="05 type ii (bgm 2).vgz" size="667924" crc="3dea73fc" sha1="a93087295caae8916f21def7d243d948b227f0c3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 name entry.vgz" />
+ <dataarea name="quik" size="189120">
+ <rom name="06 name entry.vgz" size="189120" crc="5a7c4bce" sha1="c3ab2d52b23a096f79338662a76d196be553358f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 extra bgm 1 ~take off~.vgz" />
+ <dataarea name="quik" size="210447">
+ <rom name="07 extra bgm 1 ~take off~.vgz" size="210447" crc="017a1477" sha1="e2b9656878cf9ff41f3184dcc67a0e9d342d352e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 extra bgm 2 ~primary attack~.vgz" />
+ <dataarea name="quik" size="52019">
+ <rom name="08 extra bgm 2 ~primary attack~.vgz" size="52019" crc="6b81d796" sha1="70c02cd55344e9741f8a65040b24caacfa658e29" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 extra bgm 3 ~in conclusion~.vgz" />
+ <dataarea name="quik" size="257852">
+ <rom name="09 extra bgm 3 ~in conclusion~.vgz" size="257852" crc="9b0f4a93" sha1="1aa93d29a35bd2342e51adc141082c0bc72a75ef" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+<!-- vgmrips.net update - October 12, 2020 - 32 Entries -->
+<!-- 1 updated set and 31 new sets -->
+
+ <software name="46okunen_pc98">
+ <description>46 Okunen Monogatari ~The Shinka Ron~ (NEC PC-9801)</description>
+ <year>1990</year>
+ <publisher>Enix</publisher>
+ <info name="cores" value="NEC PC-9801-26K (YM2203)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 genesis.vgz" />
+ <dataarea name="quik" size="10930">
+ <rom name="01 genesis.vgz" size="10930" crc="36d9ad93" sha1="b6ab48182bd1ed9334781b03ad19e7add37b49bd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 opening theme.vgz" />
+ <dataarea name="quik" size="22990">
+ <rom name="02 opening theme.vgz" size="22990" crc="e1382925" sha1="f5d41d4e9709bc2231d832b63037f1babaf79337" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 spring is coming.vgz" />
+ <dataarea name="quik" size="8428">
+ <rom name="03 spring is coming.vgz" size="8428" crc="5ae42bc3" sha1="172f5fee2e6c6247ec04e0c8ea5d70e47d5c756c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 theme of shrine.vgz" />
+ <dataarea name="quik" size="5572">
+ <rom name="04 theme of shrine.vgz" size="5572" crc="fddf0068" sha1="5621868533667714632768c75991502eef2b6863" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 field theme a.vgz" />
+ <dataarea name="quik" size="8144">
+ <rom name="05 field theme a.vgz" size="8144" crc="3ae48679" sha1="ec170478544b35e36f9c273a5da01e463ad8b286" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 battle theme.vgz" />
+ <dataarea name="quik" size="6444">
+ <rom name="06 battle theme.vgz" size="6444" crc="ff2beedf" sha1="e4c23886b8bddbe8d2b804dbaa37e1c3f12fc284" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 evolution theme.vgz" />
+ <dataarea name="quik" size="3735">
+ <rom name="07 evolution theme.vgz" size="3735" crc="191bfb2f" sha1="56a29659c26d4da242aa4bb04f1f36b7819ec049" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 creepy dungeon.vgz" />
+ <dataarea name="quik" size="25458">
+ <rom name="08 creepy dungeon.vgz" size="25458" crc="74c99861" sha1="6d261b485e367c259cdc1c523d6ce7598475241a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 theme of goddess gaia.vgz" />
+ <dataarea name="quik" size="6438">
+ <rom name="09 theme of goddess gaia.vgz" size="6438" crc="60ea8e6c" sha1="9ae1c42042252c711f3df14d43960543595243a6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 sorrow.vgz" />
+ <dataarea name="quik" size="19244">
+ <rom name="10 sorrow.vgz" size="19244" crc="ee56646d" sha1="c0a5f24c60d9837905d1901456dcba5b8da0f2f8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 theme of curse.vgz" />
+ <dataarea name="quik" size="6645">
+ <rom name="11 theme of curse.vgz" size="6645" crc="a8d70286" sha1="fba9ba63076f0785e97133fe40a02c2f8ef38036" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 destruction and birth.vgz" />
+ <dataarea name="quik" size="2614">
+ <rom name="12 destruction and birth.vgz" size="2614" crc="4b51338f" sha1="4100e9eb85d044a6ec1ae3d9df65635aa4335de9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 field theme b.vgz" />
+ <dataarea name="quik" size="10209">
+ <rom name="13 field theme b.vgz" size="10209" crc="fc8855f9" sha1="288768a8e7334b60e53ab69d06aa7c9b3014ca8a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 army of atlantis.vgz" />
+ <dataarea name="quik" size="6289">
+ <rom name="14 army of atlantis.vgz" size="6289" crc="c9edd008" sha1="bb1af177e57582a2575ab58188233d7beac898bf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 tension!.vgz" />
+ <dataarea name="quik" size="9266">
+ <rom name="15 tension.vgz" size="9266" crc="0386678e" sha1="a26a8cffee921f1a797a2e5c2761dd2c0f96ffac" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 final battle.vgz" />
+ <dataarea name="quik" size="11234">
+ <rom name="16 final battle.vgz" size="11234" crc="3cc0a83d" sha1="a6346ae042dda8e5fd6233345274395daf8592a0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 end of battle.vgz" />
+ <dataarea name="quik" size="12563">
+ <rom name="17 end of battle.vgz" size="12563" crc="cd496e5f" sha1="1ea6430e65f5d0107485623d385f723a3cdd4f65" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 ending.vgz" />
+ <dataarea name="quik" size="45425">
+ <rom name="18 ending.vgz" size="45425" crc="02ae3faa" sha1="3816ea0aee036ac37262a33a0eb90cace3615e1a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 evoltion fanfare.vgz" />
+ <dataarea name="quik" size="941">
+ <rom name="19 evoltion fanfare.vgz" size="941" crc="627b2dfc" sha1="1cc8d67c54d66b7a3c3d41b1784fc609eb325262" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 good item.vgz" />
+ <dataarea name="quik" size="1122">
+ <rom name="20 good item.vgz" size="1122" crc="6fb4f0c5" sha1="1d7e7872a699f896efaa18f7906cb998a7f20592" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 bad item.vgz" />
+ <dataarea name="quik" size="1046">
+ <rom name="21 bad item.vgz" size="1046" crc="7a4f5817" sha1="7791fac9915e5a9e648d694f0c33126e787eb006" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 sugiyaman.vgz" />
+ <dataarea name="quik" size="7145">
+ <rom name="22 sugiyaman.vgz" size="7145" crc="21e5631f" sha1="54b4acc52f0e69a2e96c174b54af9068970dd2fe" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 end of evolution.vgz" />
+ <dataarea name="quik" size="9647">
+ <rom name="23 end of evolution.vgz" size="9647" crc="1d3454ca" sha1="0d8661448e27c34cab2891f45eb125a03d9c6fcd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 game over.vgz" />
+ <dataarea name="quik" size="1341">
+ <rom name="24 game over.vgz" size="1341" crc="30848e5f" sha1="5f561ae226608dfe0650e4759bfd653b7e0f81c2" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="vgm0002">
+ <description>Door Door (Family Computer)</description>
+ <year>1985</year>
+ <publisher>Enix</publisher>
+ <info name="cores" value="NES APU (N2A03)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 game start.vgz" />
+ <dataarea name="quik" size="553">
+ <rom name="01 game start.vgz" size="553" crc="52699af1" sha1="7e38c87b690c114e9241db4dd0a044f4ccd882bc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 main (bgm 1).vgz" />
+ <dataarea name="quik" size="2889">
+ <rom name="02 main (bgm 1).vgz" size="2889" crc="894b1fc4" sha1="250d9a01ad90edaafa40ee97487b9b39f6726385" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 linda (bgm 2).vgz" />
+ <dataarea name="quik" size="487">
+ <rom name="03 linda (bgm 2).vgz" size="487" crc="42b57fa3" sha1="186dc0f24766015be98956d35ca1c14e1466ed6e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 techno (bgm 3).vgz" />
+ <dataarea name="quik" size="823">
+ <rom name="04 techno (bgm 3).vgz" size="823" crc="0461f3cd" sha1="482ed2b4e7ccb678f69037bcd092385e0226c6d3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 curious (bgm 4).vgz" />
+ <dataarea name="quik" size="531">
+ <rom name="05 curious (bgm 4).vgz" size="531" crc="9fb85d5b" sha1="dca3a760995102ff15303d31c34f911b604e060f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 okinawa (bgm 5).vgz" />
+ <dataarea name="quik" size="825">
+ <rom name="06 okinawa (bgm 5).vgz" size="825" crc="e06fbb19" sha1="1ffd3a5c52454304d89802259c0e5adba7c9ae88" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 omocha (bgm 6).vgz" />
+ <dataarea name="quik" size="538">
+ <rom name="07 omocha (bgm 6).vgz" size="538" crc="7d1d51a3" sha1="572945fca309cf4a7ee15036d74eb00b84e7dddb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 poppo (bgm 7).vgz" />
+ <dataarea name="quik" size="499">
+ <rom name="08 poppo (bgm 7).vgz" size="499" crc="cbd9fa89" sha1="bb03ec6936ab77366b4a5010c4cafa2ae41b5876" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 western (bgm 8).vgz" />
+ <dataarea name="quik" size="621">
+ <rom name="09 western (bgm 8).vgz" size="621" crc="0665ebb4" sha1="40e9e9481770affa826a25d0535bbfc7aa213b63" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 komori (bgm 9).vgz" />
+ <dataarea name="quik" size="494">
+ <rom name="10 komori (bgm 9).vgz" size="494" crc="dda1041b" sha1="8a3e91a6fcf39e06772f3e536e483e9c7feaf7c9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 china (bgm 10).vgz" />
+ <dataarea name="quik" size="840">
+ <rom name="11 china (bgm 10).vgz" size="840" crc="d28e6011" sha1="b9c617d6a2090bcc8ebb54aac09f5d5ed780ccc9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 enka (bgm 11).vgz" />
+ <dataarea name="quik" size="1519">
+ <rom name="12 enka (bgm 11).vgz" size="1519" crc="91cb13de" sha1="d0918cfd7b4a26e5a2d45e93ff48cdf5162025ce" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 round clear.vgz" />
+ <dataarea name="quik" size="337">
+ <rom name="13 round clear.vgz" size="337" crc="9527ad51" sha1="e5715afa3ddf4323058c4c3cd5c828fbc6a90f9a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 lost a life.vgz" />
+ <dataarea name="quik" size="460">
+ <rom name="14 lost a life.vgz" size="460" crc="f47eff1e" sha1="45faf826343199017bbda1295b7f103b1b1a8b32" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 game over.vgz" />
+ <dataarea name="quik" size="449">
+ <rom name="15 game over.vgz" size="449" crc="42f0a78b" sha1="f3678aae6c1eb643f687805bc71f1da452ef85e5" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="dbz2">
+ <description>Dragon Ball Z 2 - Super Battle (Arcade)</description>
+ <year>1994</year>
+ <publisher>Banpresto</publisher>
+ <info name="cores" value="YM2151, OKIM6295"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 coin insertion.vgz" />
+ <dataarea name="quik" size="6428">
+ <rom name="01 coin insertion.vgz" size="6428" crc="2248352d" sha1="bfe48fc096589de15126f5404e909b7822c2c8b6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 character select.vgz" />
+ <dataarea name="quik" size="13724">
+ <rom name="02 character select.vgz" size="13724" crc="ed74e9d1" sha1="8f192b40cc083c9a3e421f5d3cf5def6738c6635" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 vs. goku (world martial arts championship).vgz" />
+ <dataarea name="quik" size="16933">
+ <rom name="03 vs. goku (world martial arts championship).vgz" size="16933" crc="ab31be53" sha1="45de8cea1e6d68e9e23e7bc8b9e6f52f856ef9d9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 win.vgz" />
+ <dataarea name="quik" size="12874">
+ <rom name="04 win.vgz" size="12874" crc="657f5344" sha1="9922c09597ce0df330b583c4114161606f2cee0e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 between the battles.vgz" />
+ <dataarea name="quik" size="14384">
+ <rom name="05 between the battles.vgz" size="14384" crc="3c6fede5" sha1="51cb73ad138b073651b86f4625e53e6a55bc5518" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 vs. gohan (forest).vgz" />
+ <dataarea name="quik" size="16960">
+ <rom name="06 vs. gohan (forest).vgz" size="16960" crc="1a475f7d" sha1="f13ce01facea38c5676cf1b28a36ed3e16436a87" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 vs. vegeta (mountains).vgz" />
+ <dataarea name="quik" size="15430">
+ <rom name="07 vs. vegeta (mountains).vgz" size="15430" crc="a72047ca" sha1="5ba91af8e28de7f041b7dffa66871766a420b4d6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 vs. trunks (city of the future).vgz" />
+ <dataarea name="quik" size="16901">
+ <rom name="08 vs. trunks (city of the future).vgz" size="16901" crc="8f40f296" sha1="54ebfd9cea798e0826830790fd732fdb1420170d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 vs. satan (satan city stadium arena).vgz" />
+ <dataarea name="quik" size="16881">
+ <rom name="09 vs. satan (satan city stadium arena).vgz" size="16881" crc="16c879a7" sha1="4577a64e670ea8fe56cc9496cc6cfef276f39040" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 vs. piccolo (porunga temple).vgz" />
+ <dataarea name="quik" size="12781">
+ <rom name="10 vs. piccolo (porunga temple).vgz" size="12781" crc="d81b6846" sha1="f562597421aaa77c8196b59addcaf084f790272e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 vs. android 20 (dr.gero's laboratory).vgz" />
+ <dataarea name="quik" size="20316">
+ <rom name="11 vs. android 20 (dr.gero's laboratory).vgz" size="20316" crc="8ec5815b" sha1="6a8c576b269c253414b1676863032af2458bbb17" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 vs. android 18 (north capitale).vgz" />
+ <dataarea name="quik" size="12553">
+ <rom name="12 vs. android 18 (north capitale).vgz" size="12553" crc="6032f7c7" sha1="e45f62f84dd6cffa9bd0362f2e59f388c3157d39" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 vs. android 16 (red ribbon army hq).vgz" />
+ <dataarea name="quik" size="12547">
+ <rom name="13 vs. android 16 (red ribbon army hq).vgz" size="12547" crc="4baa79b9" sha1="cabd191fc4b4ad0a78f682bdc83906f35cc98d0c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 vs. cell (cell games arena).vgz" />
+ <dataarea name="quik" size="17573">
+ <rom name="14 vs. cell (cell games arena).vgz" size="17573" crc="0ca7e4c1" sha1="db05f63cea98fd32b1822867ea7956e0d7430d3d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 ending &amp; credits.vgz" />
+ <dataarea name="quik" size="17333">
+ <rom name="15 ending &amp; credits.vgz" size="17333" crc="ee2156d2" sha1="9ae28686e62d094fb8c5a366b12b4bdae5dde400" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 ending (perfect cell).vgz" />
+ <dataarea name="quik" size="15934">
+ <rom name="16 ending (perfect cell).vgz" size="15934" crc="1984b0a9" sha1="f395b899eea8b8bbedd6435b52263735f08daf14" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 game over.vgz" />
+ <dataarea name="quik" size="14813">
+ <rom name="17 game over.vgz" size="14813" crc="cffcd26a" sha1="f367d346b3006166862d7aca44d652c0b9bab2ed" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 unused bgm.vgz" />
+ <dataarea name="quik" size="14780">
+ <rom name="18 unused bgm.vgz" size="14780" crc="bdd09c53" sha1="7f33c2a0cecb987cceccfe4b3878ea7ce20b4903" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 unused jingle 1.vgz" />
+ <dataarea name="quik" size="16047">
+ <rom name="19 unused jingle 1.vgz" size="16047" crc="e2c402aa" sha1="7ad9874259df02ca7e954a91ed2aeef595fb3dd9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 unused jingle 2.vgz" />
+ <dataarea name="quik" size="15512">
+ <rom name="20 unused jingle 2.vgz" size="15512" crc="48d57c6c" sha1="281871b574db4714e5fff414074fdf49168b180f" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="famista3_gb">
+ <description>Famista 3 (Nintendo Game Boy)</description>
+ <year>1993</year>
+ <publisher>Namco</publisher>
+ <info name="cores" value="Game Boy DMG (LR35902)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 title screen.vgz" />
+ <dataarea name="quik" size="1883">
+ <rom name="01 title screen.vgz" size="1883" crc="c728dae1" sha1="cebab717fcfcaf198f6b3731366bbe906e4ddfe1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 mode select.vgz" />
+ <dataarea name="quik" size="5464">
+ <rom name="02 mode select.vgz" size="5464" crc="9551637d" sha1="500a88b2542ff6857ab652e2ca90fb6188c56cc8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 play ball.vgz" />
+ <dataarea name="quik" size="3334">
+ <rom name="03 play ball.vgz" size="3334" crc="ca7e31e9" sha1="c630cba816c203f196441c028c26ddbd1aa09e14" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 main bgm.vgz" />
+ <dataarea name="quik" size="12637">
+ <rom name="04 main bgm.vgz" size="12637" crc="0f7c51b5" sha1="6e48f1b70d3b2ae00194e0e9d832616683fbe8bf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 change side.vgz" />
+ <dataarea name="quik" size="852">
+ <rom name="05 change side.vgz" size="852" crc="3ef33697" sha1="137948e3255c22077ad1760a722aaf5c23c32f32" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 namco stars theme.vgz" />
+ <dataarea name="quik" size="5736">
+ <rom name="06 namco stars theme.vgz" size="5736" crc="bb11857c" sha1="c104336d18420bedd499c9bb7503393da9ec781f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 chance bgm.vgz" />
+ <dataarea name="quik" size="1716">
+ <rom name="07 chance bgm.vgz" size="1716" crc="c8946ebc" sha1="6c466ca8151152b65ce354b8e474e50d771f2a5c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 home run.vgz" />
+ <dataarea name="quik" size="1582">
+ <rom name="08 home run.vgz" size="1582" crc="2e175a1e" sha1="e7918bd4ea63cbcf6e377b675d8f942b2f6629e9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 time bgm.vgz" />
+ <dataarea name="quik" size="2217">
+ <rom name="09 time bgm.vgz" size="2217" crc="1911d24b" sha1="245a796d26a2fe729163bb946de90bc26b5e49ce" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 cutscene.vgz" />
+ <dataarea name="quik" size="3227">
+ <rom name="10 cutscene.vgz" size="3227" crc="13cfbde5" sha1="b5488832e06539d3507221242325734d8432d043" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 game set.vgz" />
+ <dataarea name="quik" size="1879">
+ <rom name="11 game set.vgz" size="1879" crc="adf9a54a" sha1="e933fbb20d0878d5c0b16d7ee0918f19b4ef8423" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 sports news (win).vgz" />
+ <dataarea name="quik" size="4237">
+ <rom name="12 sports news (win).vgz" size="4237" crc="cfaa5fda" sha1="5ae330a763ed66dc773d7391944ef7f98faa780f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 sports news (lose).vgz" />
+ <dataarea name="quik" size="4314">
+ <rom name="13 sports news (lose).vgz" size="4314" crc="51c7d8b9" sha1="3ad0c215ce57a96ec187367d1767b569bc4ee051" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 link error.vgz" />
+ <dataarea name="quik" size="880">
+ <rom name="14 link error.vgz" size="880" crc="589c1035" sha1="ca18c6bbbf322166e1fc32ca60925136da5a8965" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 unknown 1.vgz" />
+ <dataarea name="quik" size="2855">
+ <rom name="15 unknown 1.vgz" size="2855" crc="703d3039" sha1="26336349b2294d4d2b442318e11daf5ffb71e0a7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 unknown 2.vgz" />
+ <dataarea name="quik" size="3853">
+ <rom name="16 unknown 2.vgz" size="3853" crc="cb58273d" sha1="0fbf52317d24e991f93efa9e8caa36e409d304b5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 unknown 3.vgz" />
+ <dataarea name="quik" size="1840">
+ <rom name="17 unknown 3.vgz" size="1840" crc="c3ed3a41" sha1="07771e1c5962f4250ac6b48891e73359f8e2022a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 unknown 4.vgz" />
+ <dataarea name="quik" size="757">
+ <rom name="18 unknown 4.vgz" size="757" crc="14c2bf6f" sha1="c3db998afda975028c17402a7a2951c4d75fd8f8" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="hydefos_msx2o">
+ <description>Hydefos - Hyper Defending Force System (MSX2, OPLL)</description>
+ <year>1989</year>
+ <publisher>Hertz</publisher>
+ <info name="cores" value="YM2413, AY-3-8910"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 hyper defending force (title).vgz" />
+ <dataarea name="quik" size="9144">
+ <rom name="01 hyper defending force (title).vgz" size="9144" crc="87167427" sha1="72c26d545d080a6ada8e88207cc498999499d960" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 area-1 (graveyard - the deep sea).vgz" />
+ <dataarea name="quik" size="4602">
+ <rom name="02 area-1 (graveyard - the deep sea).vgz" size="4602" crc="3900cfb9" sha1="0a255d7b52eba6cc12b6e54644b0e83d098a6581" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 pit approach.vgz" />
+ <dataarea name="quik" size="1650">
+ <rom name="03 pit approach.vgz" size="1650" crc="3ba30c62" sha1="a4199d825c2a8fd8888d6bed0e38b208a3a4db6e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 metal creature a.vgz" />
+ <dataarea name="quik" size="1592">
+ <rom name="04 metal creature a.vgz" size="1592" crc="15d7f754" sha1="c76fb2c304776e77675b782618061e3df617bb71" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 area clear.vgz" />
+ <dataarea name="quik" size="1907">
+ <rom name="05 area clear.vgz" size="1907" crc="240e555d" sha1="c13005af2f3714738e4bd632784076c5fa604db3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 area-2 (lost world - the island).vgz" />
+ <dataarea name="quik" size="3618">
+ <rom name="06 area-2 (lost world - the island).vgz" size="3618" crc="9021737a" sha1="e7e733556eadc1039968a574a943d87ec0290e05" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 metal creature b.vgz" />
+ <dataarea name="quik" size="1667">
+ <rom name="07 metal creature b.vgz" size="1667" crc="2cb794ca" sha1="57f30590ae18d9f9e5df09673c203f46a3090e72" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 visual alien (visual scene 1).vgz" />
+ <dataarea name="quik" size="5917">
+ <rom name="08 visual alien (visual scene 1).vgz" size="5917" crc="96e8fe27" sha1="8724530c66c31676cfbfbbc700dc8b2fcb93e762" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 area-3 (electric woods - the fortress city).vgz" />
+ <dataarea name="quik" size="3347">
+ <rom name="09 area-3 (electric woods - the fortress city).vgz" size="3347" crc="078ab4c0" sha1="58398b7dccfaadc74363b39957dc8cec685df7a3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 area-4 (clouds - the air castle).vgz" />
+ <dataarea name="quik" size="3849">
+ <rom name="10 area-4 (clouds - the air castle).vgz" size="3849" crc="ee8faff6" sha1="9e4487bfe48ee0e894041f89e491482a16f0c374" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 visual theme of stacy (visual scene 2).vgz" />
+ <dataarea name="quik" size="5824">
+ <rom name="11 visual theme of stacy (visual scene 2).vgz" size="5824" crc="f7225a54" sha1="55220d756a470c57c16552ac3eededb725b1d813" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 area-5 (van allen - the alien attack).vgz" />
+ <dataarea name="quik" size="5528">
+ <rom name="12 area-5 (van allen - the alien attack).vgz" size="5528" crc="2ee526dd" sha1="ac6e42d98bbd205b52050357aca68d4d24c09d52" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 area-6 (what's goin'on in the chase).vgz" />
+ <dataarea name="quik" size="8532">
+ <rom name="13 area-6 (what's goin'on in the chase).vgz" size="8532" crc="83ebd829" sha1="52bf873ac4aedfbfafda9d11658ee2bbfae62b1a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 visual great race (visual scene 3).vgz" />
+ <dataarea name="quik" size="6699">
+ <rom name="14 visual great race (visual scene 3).vgz" size="6699" crc="c210dadb" sha1="0a0d1c97760e91c5a8fbf61942d2ebe3faa69eea" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 staff roll (ending credits).vgz" />
+ <dataarea name="quik" size="5489">
+ <rom name="15 staff roll (ending credits).vgz" size="5489" crc="8ea91d27" sha1="144cdbd57d63676eb393996f569b10d3aa0629ae" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 visual wedding (hidden ending).vgz" />
+ <dataarea name="quik" size="8020">
+ <rom name="16 visual wedding (hidden ending).vgz" size="8020" crc="3c318239" sha1="2f47c8190dad5e763fea772c8d2ce090d7a93d67" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 game over.vgz" />
+ <dataarea name="quik" size="4134">
+ <rom name="17 game over.vgz" size="4134" crc="74cad79e" sha1="b63af4d93bd81d2bd17818aaa9b3963c0f0f7c27" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="hydefos_msx2">
+ <description>Hydefos - Hyper Defending Force System (MSX2, PSG)</description>
+ <year>1989</year>
+ <publisher>Hertz</publisher>
+ <info name="cores" value="AY-3-8910"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 hyper defending force (title).vgz" />
+ <dataarea name="quik" size="5400">
+ <rom name="01 hyper defending force (title).vgz" size="5400" crc="4a9bf7fd" sha1="bd6498a3c8d33aa5df6b66a95493384636cba561" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 area-1 (graveyard - the deep sea).vgz" />
+ <dataarea name="quik" size="5499">
+ <rom name="02 area-1 (graveyard - the deep sea).vgz" size="5499" crc="5bce6c1d" sha1="f89e49498b646d5c7e282302eb45140bf0e279d0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 pit approach.vgz" />
+ <dataarea name="quik" size="1952">
+ <rom name="03 pit approach.vgz" size="1952" crc="8136d0bd" sha1="05d7b0723b7271c65382c28835e7ee573e47c3b8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 metal creature a.vgz" />
+ <dataarea name="quik" size="1815">
+ <rom name="04 metal creature a.vgz" size="1815" crc="77ab2cd1" sha1="344a80d436d4d392d56022ba1f30a9040b7e29cf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 area clear.vgz" />
+ <dataarea name="quik" size="1663">
+ <rom name="05 area clear.vgz" size="1663" crc="4837388c" sha1="98acc41dde233686f5969fe894c219559ccb3936" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 area-2 (lost world - the island).vgz" />
+ <dataarea name="quik" size="5452">
+ <rom name="06 area-2 (lost world - the island).vgz" size="5452" crc="9b2843c6" sha1="b361623dbbc7a4b971310274d6db732e4f0fb67a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 metal creature b.vgz" />
+ <dataarea name="quik" size="2343">
+ <rom name="07 metal creature b.vgz" size="2343" crc="98f599c5" sha1="b1b9df5adbd768419ba7fadb07d87e03f12d88ce" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 visual alien (visual scene 1).vgz" />
+ <dataarea name="quik" size="5371">
+ <rom name="08 visual alien (visual scene 1).vgz" size="5371" crc="394d258f" sha1="f1c9d0905c95ef430d76ec9fa097098113027495" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 area-3 (electric woods - the fortress city).vgz" />
+ <dataarea name="quik" size="4316">
+ <rom name="09 area-3 (electric woods - the fortress city).vgz" size="4316" crc="af615a20" sha1="b6abfa44d42254ab3ad737940ea3d53330625cec" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 area-4 (clouds - the air castle).vgz" />
+ <dataarea name="quik" size="4471">
+ <rom name="10 area-4 (clouds - the air castle).vgz" size="4471" crc="d83b3394" sha1="e6b8d6b097bf307c0e78b099f406412ecc3378ff" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 visual theme of stacy (visual scene 2).vgz" />
+ <dataarea name="quik" size="4967">
+ <rom name="11 visual theme of stacy (visual scene 2).vgz" size="4967" crc="a9258658" sha1="cd0dc8cdc39dd134c266f11bf6f3f6cf6c3b1378" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 area-5 (van allen - the alien attack).vgz" />
+ <dataarea name="quik" size="6496">
+ <rom name="12 area-5 (van allen - the alien attack).vgz" size="6496" crc="dcc43cd8" sha1="e07e7ee68f24cac10ea912cdafd620487d32787b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 area-6 (what's goin'on in the chase).vgz" />
+ <dataarea name="quik" size="11979">
+ <rom name="13 area-6 (what's goin'on in the chase).vgz" size="11979" crc="e6fe7b35" sha1="c7116e2681eb44f36abc680fdc21b8beceb447a5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 visual great race (visual scene 3).vgz" />
+ <dataarea name="quik" size="7478">
+ <rom name="14 visual great race (visual scene 3).vgz" size="7478" crc="d3c1451b" sha1="6565e58a5a5329a9f695ceb7c0abae8239047e2e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 staff roll (ending credits).vgz" />
+ <dataarea name="quik" size="5808">
+ <rom name="15 staff roll (ending credits).vgz" size="5808" crc="e4e3ae8a" sha1="31edbfc4fe1eb654d02a10a90424c8b9f46c1dc5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 visual wedding (hidden ending).vgz" />
+ <dataarea name="quik" size="6808">
+ <rom name="16 visual wedding (hidden ending).vgz" size="6808" crc="35993370" sha1="50ed017ae35e782d4c6121e451a0bf56f9c39f55" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 game over.vgz" />
+ <dataarea name="quik" size="4777">
+ <rom name="17 game over.vgz" size="4777" crc="da660048" sha1="91c544a9f99c1acffcd6be50ec169a4a5e95d495" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="konagcbhhs_msx2">
+ <description>Hyper Somen (MSX2, PSG)</description>
+ <year>1989</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 helicopter.vgz" />
+ <dataarea name="quik" size="383">
+ <rom name="01 helicopter.vgz" size="383" crc="77f4c177" sha1="dc00bf6949ebaa0b97cd3418d170ae32cd030fe3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 main bgm.vgz" />
+ <dataarea name="quik" size="9003">
+ <rom name="02 main bgm.vgz" size="9003" crc="7eac759d" sha1="7c50be1579f72a13dd1e11acafae27574bbf6882" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 game over.vgz" />
+ <dataarea name="quik" size="1590">
+ <rom name="03 game over.vgz" size="1590" crc="d5bcee48" sha1="c6df96e4419aa19fb4fd9a0975614746d3c01ef5" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="konagcbhhs_ssc">
+ <description>Hyper Somen (MSX2, SCC)</description>
+ <year>1989</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="SCC-I (K052539), PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 helicopter.vgz" />
+ <dataarea name="quik" size="727">
+ <rom name="01 helicopter.vgz" size="727" crc="50ddc8a5" sha1="d7f70798cfbdbe531ef9a47f9e40235ff3a5f8af" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 main bgm.vgz" />
+ <dataarea name="quik" size="18323">
+ <rom name="02 main bgm.vgz" size="18323" crc="0b477a74" sha1="8062bb7ca1130f24b4cfc214fc62936879c12521" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 game over.vgz" />
+ <dataarea name="quik" size="4610">
+ <rom name="03 game over.vgz" size="4610" crc="71f67af4" sha1="2732f4fca91286c0bc9a8501f26964c6c17442b4" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="konbball_msx">
+ <description>Konami's Baseball (MSX)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 play start.vgz" />
+ <dataarea name="quik" size="754">
+ <rom name="01 play start.vgz" size="754" crc="5bc6d775" sha1="5281c72700b5ef916dfc257012a956265d1d8bab" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 switch.vgz" />
+ <dataarea name="quik" size="462">
+ <rom name="02 switch.vgz" size="462" crc="6c70193c" sha1="77b1cf095e9aeda3062b2379cb72aa99fecd3dcf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 home run.vgz" />
+ <dataarea name="quik" size="510">
+ <rom name="03 home run.vgz" size="510" crc="fe305ac7" sha1="e256bc10bceecf1241f4c0fd77f3ab6d6accf96c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 all home.vgz" />
+ <dataarea name="quik" size="752">
+ <rom name="04 all home.vgz" size="752" crc="85c30525" sha1="8c2fcf880d953b497c31cf69e5b42cb3c4424653" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 game set.vgz" />
+ <dataarea name="quik" size="643">
+ <rom name="05 game set.vgz" size="643" crc="9af4dfbe" sha1="fc2e3cd2f4b6f82fdddeac11d6d0880c1ba762c9" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="kongolf_msx">
+ <description>Konami's Golf (MSX)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 play start.vgz" />
+ <dataarea name="quik" size="682">
+ <rom name="01 play start.vgz" size="682" crc="ca6a142b" sha1="6f64042ffd4f67a11c40a3948bad44eb627b22cb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 next hole.vgz" />
+ <dataarea name="quik" size="335">
+ <rom name="02 next hole.vgz" size="335" crc="1ef3db79" sha1="2c3515137ea5cc05be117799aee17250f25b5baf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 hole out.vgz" />
+ <dataarea name="quik" size="859">
+ <rom name="03 hole out.vgz" size="859" crc="9821f63c" sha1="b0a33c12734f0f0f3165188c7f7f279412a9380a" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="pingpong_msx">
+ <description>Konami's Ping Pong (MSX, PSG)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 play start.vgz" />
+ <dataarea name="quik" size="889">
+ <rom name="01 play start.vgz" size="889" crc="25eb9c7d" sha1="9d6a022e1ebb6ba804175723cf9c1f0531379f99" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 game.vgz" />
+ <dataarea name="quik" size="651">
+ <rom name="02 game.vgz" size="651" crc="692e7132" sha1="40bc433fae697a10d280c25f66222c3cb466d75d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 game set.vgz" />
+ <dataarea name="quik" size="758">
+ <rom name="03 game set.vgz" size="758" crc="1db8a59e" sha1="b77e5bc452b377fb458ed4c0b10639a593cd5ef9" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="pingpong_scc">
+ <description>Konami's Ping Pong (MSX, SCC)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="SCC-I (K052539), PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 play start.vgz" />
+ <dataarea name="quik" size="2641">
+ <rom name="01 play start.vgz" size="2641" crc="a145eb18" sha1="87d2ae65046154d8fae467a2b89ed5210f28cf92" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 game.vgz" />
+ <dataarea name="quik" size="1821">
+ <rom name="02 game.vgz" size="1821" crc="50892d2a" sha1="a021602a106dd32c0404cdd91dab25573038eaf2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 game set.vgz" />
+ <dataarea name="quik" size="2397">
+ <rom name="03 game set.vgz" size="2397" crc="9d979c6e" sha1="6dece457e538859f58780b00efe93ad41984f4a9" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="win31_pc">
+ <description>Microsoft Windows 3.x (IBM PC AT)</description>
+ <year>1990</year>
+ <publisher>Microsoft</publisher>
+ <info name="cores" value="OPL3 (YMF262)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 trip through the grand canyon (basic).vgz" />
+ <dataarea name="quik" size="30673">
+ <rom name="01 trip through the grand canyon (basic).vgz" size="30673" crc="6e6d5604" sha1="0052094907845c3c115b6fa8bddd063f6a885832" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 trip through the grand canyon (extended).vgz" />
+ <dataarea name="quik" size="55445">
+ <rom name="02 trip through the grand canyon (extended).vgz" size="55445" crc="deeaa885" sha1="0d9ca37d69418dd2b2e06ecbcf3f95c7e4722546" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 passport (basic).vgz" />
+ <dataarea name="quik" size="54206">
+ <rom name="03 passport (basic).vgz" size="54206" crc="c8563d23" sha1="db9bba83ea5810d535de8f2ad78bc60bc0a6adfa" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 passport (extended).vgz" />
+ <dataarea name="quik" size="64847">
+ <rom name="04 passport (extended).vgz" size="64847" crc="aa568544" sha1="9ef1d79ed82c77e05b8417d4fff710b3379a4b20" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 almonds (basic).vgz" />
+ <dataarea name="quik" size="44510">
+ <rom name="05 almonds (basic).vgz" size="44510" crc="847a5d29" sha1="0809cf2741063b68d86a2f6b40ad86ed0f97590d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 almonds (extended).vgz" />
+ <dataarea name="quik" size="80002">
+ <rom name="06 almonds (extended).vgz" size="80002" crc="7a90ee5a" sha1="9864efce60e45a42db541e433288706a8b57bede" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 brandenburg (basic).vgz" />
+ <dataarea name="quik" size="13158">
+ <rom name="07 brandenburg (basic).vgz" size="13158" crc="a338d8f0" sha1="846b0a2dd43344734e2044c1ee9fcf0355fcdab9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 brandenburg (extended).vgz" />
+ <dataarea name="quik" size="19448">
+ <rom name="08 brandenburg (extended).vgz" size="19448" crc="91c84b94" sha1="e6d7544db8e90609a8fd963947a6f7f7fa7ab81f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 dreamy (basic).vgz" />
+ <dataarea name="quik" size="27209">
+ <rom name="09 dreamy (basic).vgz" size="27209" crc="84416b5e" sha1="470478980aaa62aa2ffa8fcc940ce0fe79d3cdf1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 dreamy (extended).vgz" />
+ <dataarea name="quik" size="49408">
+ <rom name="10 dreamy (extended).vgz" size="49408" crc="63ca74af" sha1="d241bd17810e92657078c0eabe2049e4d632ef03" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 rockin' (basic).vgz" />
+ <dataarea name="quik" size="48791">
+ <rom name="11 rockin' (basic).vgz" size="48791" crc="237946df" sha1="97ecb1e9109dca3e146a57ec058ca3f5479a6580" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 rockin' (extended).vgz" />
+ <dataarea name="quik" size="72090">
+ <rom name="12 rockin' (extended).vgz" size="72090" crc="4cd397e4" sha1="0fc5087e8f53e571da3069fe8d6a17c2ec6f47d3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 four seasons (basic).vgz" />
+ <dataarea name="quik" size="23796">
+ <rom name="13 four seasons (basic).vgz" size="23796" crc="3fe19b20" sha1="bde20baa24ba0db7092cc803c79a521cdc4c8d93" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 four seasons (extended).vgz" />
+ <dataarea name="quik" size="39294">
+ <rom name="14 four seasons (extended).vgz" size="39294" crc="ac671394" sha1="2f2a061cac0646a7bee0405da3338e6a53ea957d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 someone's band (basic).vgz" />
+ <dataarea name="quik" size="35070">
+ <rom name="15 someone's band (basic).vgz" size="35070" crc="a82eba44" sha1="1de1d3aed0f005260f059ae58c19bf50f7234219" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 someone's band (extended).vgz" />
+ <dataarea name="quik" size="55763">
+ <rom name="16 someone's band (extended).vgz" size="55763" crc="efb2432e" sha1="ddcee1166be7c6ecc4f996b4db615fc3749e77cb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 king george's stomp (basic).vgz" />
+ <dataarea name="quik" size="47345">
+ <rom name="17 king george's stomp (basic).vgz" size="47345" crc="2d352053" sha1="38b81e1d1d9cf140b14d91457f075e47c83445ee" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 king george's stomp (extended).vgz" />
+ <dataarea name="quik" size="66514">
+ <rom name="18 king george's stomp (extended).vgz" size="66514" crc="92e707af" sha1="9f100ffbedcf3b15c91a693f208aa600452a4d34" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 the cake (basic).vgz" />
+ <dataarea name="quik" size="47142">
+ <rom name="19 the cake (basic).vgz" size="47142" crc="501d1b4f" sha1="73d003038b820bf5757477b1618b5540b85cc661" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 the cake (extended).vgz" />
+ <dataarea name="quik" size="72058">
+ <rom name="20 the cake (extended).vgz" size="72058" crc="2f3b62dd" sha1="3c27b185e81be30cfd4e7dbc5e6bd4aed9184076" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="monkeyac_msx">
+ <description>Monkey Academy (MSX)</description>
+ <year>1984</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 level select.vgz" />
+ <dataarea name="quik" size="576">
+ <rom name="01 level select.vgz" size="576" crc="a7f53062" sha1="c55a5efb18bb2313095cd3b77b5513b45d483fd4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 let's do math.vgz" />
+ <dataarea name="quik" size="653">
+ <rom name="02 let's do math.vgz" size="653" crc="b2ff7d7a" sha1="2bb4e641075801e7db509138a2276364920601d3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 correct number selected.vgz" />
+ <dataarea name="quik" size="393">
+ <rom name="03 correct number selected.vgz" size="393" crc="fd272e85" sha1="24504525df427512dc1ed0d94145ba01911207b9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 correct number revealed.vgz" />
+ <dataarea name="quik" size="465">
+ <rom name="04 correct number revealed.vgz" size="465" crc="a39621c8" sha1="664c6c239c0bed10f2c3785974731efdd517f719" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 equation completed.vgz" />
+ <dataarea name="quik" size="534">
+ <rom name="05 equation completed.vgz" size="534" crc="50530144" sha1="73165caff43ba4312100bc53bd07eb76badc0f1a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 stage clear.vgz" />
+ <dataarea name="quik" size="583">
+ <rom name="06 stage clear.vgz" size="583" crc="b498a104" sha1="4fd287dd9e182a0604443b739b3635a603eee657" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 game over.vgz" />
+ <dataarea name="quik" size="505">
+ <rom name="07 game over.vgz" size="505" crc="263122db" sha1="8cb4734d404254905cc83e78e8c1127b675b01bc" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mopirang_msx">
+ <description>Mopi Ranger (MSX)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 title screen.vgz" />
+ <dataarea name="quik" size="603">
+ <rom name="01 title screen.vgz" size="603" crc="d38a1b9d" sha1="8e5c09b8ec6f09977019e8ece9400b5803170324" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 stage start.vgz" />
+ <dataarea name="quik" size="627">
+ <rom name="02 stage start.vgz" size="627" crc="d393dcfd" sha1="0f2c3b9395b0caef653714b611939ff65c47aee2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 main bgm.vgz" />
+ <dataarea name="quik" size="304">
+ <rom name="03 main bgm.vgz" size="304" crc="e24f051e" sha1="ac777d3e7245a303f52fddbaeeee94056b4faaf1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 stage clear.vgz" />
+ <dataarea name="quik" size="424">
+ <rom name="04 stage clear.vgz" size="424" crc="d12ed3bf" sha1="4983f5f0f796b637cbd69717fd1798f1cd4c61cd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 game over.vgz" />
+ <dataarea name="quik" size="694">
+ <rom name="05 game over.vgz" size="694" crc="1a2b5083" sha1="9d14d36938db69e607e2f6a242c5f11646ce72c3" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="mspacman_gb">
+ <description>Ms. Pac-Man (Nintendo Game Boy)</description>
+ <year>1993</year>
+ <publisher>Namco (U) / Nintendo (E)</publisher>
+ <info name="cores" value="Game Boy DMG (LR35902)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 game start.vgz" />
+ <dataarea name="quik" size="1868">
+ <rom name="01 game start.vgz" size="1868" crc="88d9632f" sha1="38fd3d8dd064a2ddc6e478d3925bcb56bc3567c7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 intermission.vgz" />
+ <dataarea name="quik" size="3324">
+ <rom name="02 intermission.vgz" size="3324" crc="2e7707e2" sha1="eac8e0860b1406d8b33e65b8b65dd8bef4ae4ec6" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="nbajam">
+ <description>NBA Jam (Midway T Unit)</description>
+ <year>1993</year>
+ <publisher>Midway</publisher>
+ <info name="cores" value="YM2151, DAC"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 attract &amp; player setup.vgz" />
+ <dataarea name="quik" size="28088">
+ <rom name="01 attract &amp; player setup.vgz" size="28088" crc="3fd11921" sha1="ab2b92964f0b7f31227fe4d194aa115cec8609fb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 1st &amp; 3rd quarter.vgz" />
+ <dataarea name="quik" size="32668">
+ <rom name="02 1st &amp; 3rd quarter.vgz" size="32668" crc="5b2d318f" sha1="19f45c5e24b01ea7fa3f4f4f8c7911b110df3ca4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 end of 1st &amp; 3rd quarter.vgz" />
+ <dataarea name="quik" size="25472">
+ <rom name="03 end of 1st &amp; 3rd quarter.vgz" size="25472" crc="f86f6c67" sha1="39308409fdd9624e8dfb688cd7db7d070709e4dc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 2nd quarter.vgz" />
+ <dataarea name="quik" size="34119">
+ <rom name="04 2nd quarter.vgz" size="34119" crc="4b26b549" sha1="0e5841bc2557b8b8a3dc51b3f3e91c1cab25547c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 halftime.vgz" />
+ <dataarea name="quik" size="25392">
+ <rom name="05 halftime.vgz" size="25392" crc="e5ef1830" sha1="1da40c370d61584b241baee01ae6a64714ac2f15" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 4th quarter.vgz" />
+ <dataarea name="quik" size="41664">
+ <rom name="06 4th quarter.vgz" size="41664" crc="0e20f886" sha1="11f4f34c90c162ac9857ace04835c239567da97a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 end of game.vgz" />
+ <dataarea name="quik" size="44267">
+ <rom name="07 end of game.vgz" size="44267" crc="f6ded3b0" sha1="25cb1e5c990104bd515b46e335cad1eeaf0e537c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 game over.vgz" />
+ <dataarea name="quik" size="21821">
+ <rom name="08 game over.vgz" size="21821" crc="4ba15541" sha1="9fe47a879f009b0864006c878f4b0f0da01db4d0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 unused tune.vgz" />
+ <dataarea name="quik" size="17808">
+ <rom name="09 unused tune.vgz" size="17808" crc="d3025d1d" sha1="a6a21aafcc79a89ae3f22e1143c54e18d689a6bb" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="roadfght_msx">
+ <description>Road Fighter (MSX, PSG)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 play start.vgz" />
+ <dataarea name="quik" size="589">
+ <rom name="01 play start.vgz" size="589" crc="43481471" sha1="ab6d4d306e1e710ec26168af504c64acdc461c1c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 checkpoint.vgz" />
+ <dataarea name="quik" size="759">
+ <rom name="02 checkpoint.vgz" size="759" crc="6f3cc5ac" sha1="28fe3a17c0764bfb5d05fd2f661f36be54f00789" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 game over.vgz" />
+ <dataarea name="quik" size="580">
+ <rom name="03 game over.vgz" size="580" crc="077df49e" sha1="be4b008d56454ffd41b17ab7138546a15d0d8d56" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="roadfght_scc">
+ <description>Road Fighter (MSX, SCC)</description>
+ <year>1985</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="SCC-I (K052539), PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 play start.vgz" />
+ <dataarea name="quik" size="1916">
+ <rom name="01 play start.vgz" size="1916" crc="7299cc33" sha1="80a76d5c48be3fee58a581f4cf4036ce68a9b3de" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 checkpoint.vgz" />
+ <dataarea name="quik" size="2759">
+ <rom name="02 checkpoint.vgz" size="2759" crc="e5098732" sha1="df226e99b5dc80b8f5646bc1d6e465b9d23d9e94" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 game over.vgz" />
+ <dataarea name="quik" size="1915">
+ <rom name="03 game over.vgz" size="1915" crc="40a5b66c" sha1="f16981c6d49ee198db30cc6322c3172a343c0b95" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="samsho3">
+ <description>Samurai Shodown III - Blades of Blood (Neo Geo)</description>
+ <year>1995</year>
+ <publisher>SNK</publisher>
+ <info name="cores" value="YM2610"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 sword's soul (title).vgz" />
+ <dataarea name="quik" size="187030">
+ <rom name="01 sword's soul (title).vgz" size="187030" crc="f7576e7c" sha1="fb1df9dba373103ffaa3774a5c582f5fe1628eaf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 the twelve challengers (player select).vgz" />
+ <dataarea name="quik" size="75589">
+ <rom name="02 the twelve challengers (player select).vgz" size="75589" crc="fd4d791e" sha1="777bb2ec9853b5297c8a28cda0c2bf38e02d5b86" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 iza jinjyouni.vgz" />
+ <dataarea name="quik" size="108172">
+ <rom name="03 iza jinjyouni.vgz" size="108172" crc="68a78177" sha1="4b77ebf5127a882f39c697078ef26042e44ce29b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 the scent of wind (shizumaru hisame).vgz" />
+ <dataarea name="quik" size="88886">
+ <rom name="04 the scent of wind (shizumaru hisame).vgz" size="88886" crc="d8c1bdb2" sha1="2d6ae9b4784721fce217676d6a1190cd7bbcbb76" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 shoubuari.vgz" />
+ <dataarea name="quik" size="64401">
+ <rom name="05 shoubuari.vgz" size="64401" crc="1da9b6ad" sha1="d8f107288fc23b7ffe2086246f3c8157ce7df438" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 waterfall of devotion (galford).vgz" />
+ <dataarea name="quik" size="306513">
+ <rom name="06 waterfall of devotion (galford).vgz" size="306513" crc="f5ec536a" sha1="33d02b1985dc945858994284b3d8e60fb797bf38" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 breath of nature (nakoruru).vgz" />
+ <dataarea name="quik" size="98344">
+ <rom name="07 breath of nature (nakoruru).vgz" size="98344" crc="d7ff7d78" sha1="4d2471895985c2eb5ff0ab32a830b421529288db" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 the mirror of heart (rimururu).vgz" />
+ <dataarea name="quik" size="271989">
+ <rom name="08 the mirror of heart (rimururu).vgz" size="271989" crc="63ac019e" sha1="50b797ef8305887a544279d1b6c91440c24a9034" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 kachi ikusa (winner demo).vgz" />
+ <dataarea name="quik" size="87155">
+ <rom name="09 kachi ikusa (winner demo).vgz" size="87155" crc="e7c679d8" sha1="bfb9167c875b59fd2ce2e01259eb40a1638d63d6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 the peerless sword (interim demo).vgz" />
+ <dataarea name="quik" size="113340">
+ <rom name="10 the peerless sword (interim demo).vgz" size="113340" crc="f81463bb" sha1="f0f40be71831000e8ac4ab7fdcc425e5413634cb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 the river (ukyo tachibana).vgz" />
+ <dataarea name="quik" size="154430">
+ <rom name="11 the river (ukyo tachibana).vgz" size="154430" crc="0a9976af" sha1="7b9e365e4665622fa092f6bf9febb247583d14af" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 the man in the shadows (kuroko demo).vgz" />
+ <dataarea name="quik" size="85167">
+ <rom name="12 the man in the shadows (kuroko demo).vgz" size="85167" crc="5c3943ee" sha1="3c663094daf3c595434c18bcf3778d8a10fedac6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 the play of dancing battle (kuroko).vgz" />
+ <dataarea name="quik" size="241376">
+ <rom name="13 the play of dancing battle (kuroko).vgz" size="241376" crc="2e003f85" sha1="0405f4aef0851618f07822d01de0f4f3713d1d56" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 the tune of biwa (image screen me).vgz" />
+ <dataarea name="quik" size="10637">
+ <rom name="14 the tune of biwa (image screen me).vgz" size="10637" crc="aaaf0131" sha1="dbab89bc7f7ddef79f5a7c3663b0d7456cad5f6e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 honor's sake (haohmaru).vgz" />
+ <dataarea name="quik" size="240232">
+ <rom name="15 honor's sake (haohmaru).vgz" size="240232" crc="32c90705" sha1="da7925fd1f3d0b281b0d23d0acc0e7a54bb9dcf1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 the song of oni (genjuro kibagami).vgz" />
+ <dataarea name="quik" size="182481">
+ <rom name="16 the song of oni (genjuro kibagami).vgz" size="182481" crc="c304f905" sha1="f3bd95f10738a1454580249d43b3554118b128b9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 the sorrow of styx (basara).vgz" />
+ <dataarea name="quik" size="341074">
+ <rom name="17 the sorrow of styx (basara).vgz" size="341074" crc="245cb5e2" sha1="a968523bc2a79106e905011f5387fb45474ee44b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 temple (gaira caffeine).vgz" />
+ <dataarea name="quik" size="175543">
+ <rom name="18 temple (gaira caffeine).vgz" size="175543" crc="6136df77" sha1="8b1aa0596fc149e52ba0397d6449aca3ce53fa0b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 dance of banquet (kyoshiro senryo).vgz" />
+ <dataarea name="quik" size="127677">
+ <rom name="19 dance of banquet (kyoshiro senryo).vgz" size="127677" crc="dfef8963" sha1="3de8dc8b250ac48d4fc62626ebe987eb6d8475eb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 penitentiary (hanzo hattori).vgz" />
+ <dataarea name="quik" size="143993">
+ <rom name="20 penitentiary (hanzo hattori).vgz" size="143993" crc="d08a439a" sha1="2ed15e27f8616988f1483048632383ad1fec6a5a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 disgraceful behaviour (shiro tokisada amakusa).vgz" />
+ <dataarea name="quik" size="235297">
+ <rom name="21 disgraceful behaviour (shiro tokisada amakusa).vgz" size="235297" crc="441f951c" sha1="0661110a9221d0241ad847a1793a6646347c4f30" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 a strong warrior appears! (before boss battle).vgz" />
+ <dataarea name="quik" size="129621">
+ <rom name="22 a strong warrior appears (before boss battle).vgz" size="129621" crc="ed942f96" sha1="f753fa45abfd7db7977e1e47ba6b48ec42f1676c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 iza jinjyouni 2 (zankuro stage ''iza jinjyouni'').vgz" />
+ <dataarea name="quik" size="59841">
+ <rom name="23 iza jinjyouni 2 (zankuro stage ''iza jinjyouni'').vgz" size="59841" crc="7dd60ae4" sha1="aa4d79cbd76f4d04db93b4d105edb5a6b2fc1457" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 the last blade (zankuro minazuki 1).vgz" />
+ <dataarea name="quik" size="171270">
+ <rom name="24 the last blade (zankuro minazuki 1).vgz" size="171270" crc="a0a3229f" sha1="b2807183971741071df3615ef508ad2641d796a2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 the collapse of the great buddha.vgz" />
+ <dataarea name="quik" size="18538">
+ <rom name="25 the collapse of the great buddha.vgz" size="18538" crc="1c09cfa3" sha1="6c732139a58015939df279ee59422a381f4ab694" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 eternity (zankuro minazuki 2).vgz" />
+ <dataarea name="quik" size="223907">
+ <rom name="26 eternity (zankuro minazuki 2).vgz" size="223907" crc="418d7356" sha1="cc8feaef262352253f85f68db32d3836c5ceba42" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 rain calling taiko (ending).vgz" />
+ <dataarea name="quik" size="125037">
+ <rom name="27 rain calling taiko (ending).vgz" size="125037" crc="e9b49b15" sha1="3d88616579aa71da68de5f8688c0c1a258ed8f04" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 celebration (staff roll).vgz" />
+ <dataarea name="quik" size="275661">
+ <rom name="28 celebration (staff roll).vgz" size="275661" crc="27a8b833" sha1="4016349f8e56129825f5b942bcf9dbbf10906677" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 request for an encore (continue).vgz" />
+ <dataarea name="quik" size="77755">
+ <rom name="29 request for an encore (continue).vgz" size="77755" crc="0da52e77" sha1="9614520d6c78bcae3d69e106dcea6fab4d7f6c0a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 the curtain falls (game over).vgz" />
+ <dataarea name="quik" size="20835">
+ <rom name="30 the curtain falls (game over).vgz" size="20835" crc="7a9b4f50" sha1="41e26c8c91f09ce20a16ded6906b4cde67ae1fce" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="samsho4">
+ <description>Samurai Shodown IV - Amakusa's Revenge (Neo Geo)</description>
+ <year>1996</year>
+ <publisher>SNK</publisher>
+ <info name="cores" value="YM2610"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 amakusa's revenge (title).vgz" />
+ <dataarea name="quik" size="464635">
+ <rom name="01 amakusa's revenge (title).vgz" size="464635" crc="cb5298c1" sha1="df92d13ae5ad558a31de45acad369cb5d7b18a85" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 the seventeen challengers (select).vgz" />
+ <dataarea name="quik" size="95776">
+ <rom name="02 the seventeen challengers (select).vgz" size="95776" crc="ce718500" sha1="58b1f2071782185360f00ff010407c7871ad1429" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 shimabara (map screen).vgz" />
+ <dataarea name="quik" size="77672">
+ <rom name="03 shimabara (map screen).vgz" size="77672" crc="b8cba77b" sha1="5df1233ae8b1d77aae8eb5bd79981b80ba411aaf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 iza jinjyouni.vgz" />
+ <dataarea name="quik" size="74222">
+ <rom name="04 iza jinjyouni.vgz" size="74222" crc="84a88812" sha1="b766151352c2d2102ef81f63005b3a3e4294746c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 asura realm (haohmaru).vgz" />
+ <dataarea name="quik" size="149338">
+ <rom name="05 asura realm (haohmaru).vgz" size="149338" crc="eed54b63" sha1="c14bd435556eb73e4db7f04d0d8f01d08ae40010" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 shoubuari.vgz" />
+ <dataarea name="quik" size="81833">
+ <rom name="06 shoubuari.vgz" size="81833" crc="cd653ca9" sha1="fb29145c2b8d5834491e278398f25205007b91fd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 river -revision- (ukyo tachibana).vgz" />
+ <dataarea name="quik" size="167929">
+ <rom name="07 river -revision- (ukyo tachibana).vgz" size="167929" crc="9ee4c430" sha1="e9961772cd0a25ebeff68eeab206e122abf717cc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 tuna incarnation (galford).vgz" />
+ <dataarea name="quik" size="252214">
+ <rom name="08 tuna incarnation (galford).vgz" size="252214" crc="1200a9da" sha1="6ed232b749427da50dc3f7cc8eb87270259836de" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 banquet of nature -part ii- (nakoruru).vgz" />
+ <dataarea name="quik" size="191256">
+ <rom name="09 banquet of nature -part ii- (nakoruru).vgz" size="191256" crc="149962bf" sha1="19b3be081f8ee18fdc2981748555aada212c9611" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 the mirror of heart -part ii- (rimururu).vgz" />
+ <dataarea name="quik" size="142414">
+ <rom name="10 the mirror of heart -part ii- (rimururu).vgz" size="142414" crc="4667861a" sha1="c0042bd6ab3c2f341be547f6161b841504220ede" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 meditation -i- (image screen 1).vgz" />
+ <dataarea name="quik" size="13427">
+ <rom name="11 meditation -i- (image screen 1).vgz" size="13427" crc="44abef78" sha1="1f2b241b9cddcf06eed83bba3fe333485fa063aa" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 meditation -ii- (image screen 2).vgz" />
+ <dataarea name="quik" size="20931">
+ <rom name="12 meditation -ii- (image screen 2).vgz" size="20931" crc="8d487206" sha1="925be4f60ea4bd3f0b7c51dccc812e76a69a5048" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 meditation -iii- (image screen 3).vgz" />
+ <dataarea name="quik" size="46482">
+ <rom name="13 meditation -iii- (image screen 3).vgz" size="46482" crc="dac6f7de" sha1="9b522db085bacaa2057af5612f3a8dedaa368474" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 the song of oni -revision- (genjuro kibagami).vgz" />
+ <dataarea name="quik" size="462365">
+ <rom name="14 the song of oni -revision- (genjuro kibagami).vgz" size="462365" crc="44a82f0a" sha1="ce82081bc86ff9d3035649c89ad407ac70ef7c7b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 exotic lady (successive) (charlotte).vgz" />
+ <dataarea name="quik" size="146733">
+ <rom name="15 exotic lady (successive) (charlotte).vgz" size="146733" crc="5183a4a0" sha1="3c81ac27c2faaac0e46eec67d93ab92416272940" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 blaze (kazuki kazama).vgz" />
+ <dataarea name="quik" size="393583">
+ <rom name="16 blaze (kazuki kazama).vgz" size="393583" crc="c5f546ca" sha1="dc1e0e239aa8299a2e2ab36e1f009ba3c6646212" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 water incarnation (sogetsu kazama).vgz" />
+ <dataarea name="quik" size="184852">
+ <rom name="17 water incarnation (sogetsu kazama).vgz" size="184852" crc="8135a867" sha1="b9ea92bcd963f584d239f970208b22265ef1df55" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 duet (before amakusa battle demo).vgz" />
+ <dataarea name="quik" size="94619">
+ <rom name="18 duet (before amakusa battle demo).vgz" size="94619" crc="5205eb90" sha1="c6df814ad169f94d66669ee7057cda401ca5a615" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 agitated calm (shiro tokisada amakusa).vgz" />
+ <dataarea name="quik" size="324224">
+ <rom name="19 agitated calm (shiro tokisada amakusa).vgz" size="324224" crc="1f9e445b" sha1="760927c5cdd6f27b44edb598810f9b9cd7379db5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 calm agitation (unknown).vgz" />
+ <dataarea name="quik" size="235283">
+ <rom name="20 calm agitation (unknown).vgz" size="235283" crc="40a0f509" sha1="becfe6153724ddf69c3e2e47e9489146cbbbb100" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 sakura (cherry trees stage).vgz" />
+ <dataarea name="quik" size="81747">
+ <rom name="21 sakura (cherry trees stage).vgz" size="81747" crc="c4dc39c2" sha1="55bcb7a2dd383fbddc6974043e356e7bfc85aaaf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 seaside (seaside stage).vgz" />
+ <dataarea name="quik" size="100440">
+ <rom name="22 seaside (seaside stage).vgz" size="100440" crc="83c5a3ff" sha1="691576246e1cb98c77b5755e37dc3d0de7499971" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 bambuseae (bamboo stage).vgz" />
+ <dataarea name="quik" size="66468">
+ <rom name="23 bambuseae (bamboo stage).vgz" size="66468" crc="5773d38d" sha1="f1dcabdd93a1867ff3f71945741155a6c312af9a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 dog (abandoned village stage).vgz" />
+ <dataarea name="quik" size="157190">
+ <rom name="24 dog (abandoned village stage).vgz" size="157190" crc="0778ffbd" sha1="f7cc0a203dcbdd82c8798a667a58cb19b82df6a5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 inferno (fire stage).vgz" />
+ <dataarea name="quik" size="35940">
+ <rom name="25 inferno (fire stage).vgz" size="35940" crc="5ef35ef1" sha1="a50b62e0a6aa9602b55b4278e960c2156c6f601a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 old temple (old temple stage 1).vgz" />
+ <dataarea name="quik" size="48660">
+ <rom name="26 old temple (old temple stage 1).vgz" size="48660" crc="318a702a" sha1="e5f89e34313972731d582cf3b4a9683463411977" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 the 2 deva kings (old temple stage 2).vgz" />
+ <dataarea name="quik" size="91230">
+ <rom name="27 the 2 deva kings (old temple stage 2).vgz" size="91230" crc="5d11dace" sha1="8a6c6ad5899e08c626ec7fb4ecc2714a8e2c6e7d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 steam (rocky mountain stage).vgz" />
+ <dataarea name="quik" size="160938">
+ <rom name="28 steam (rocky mountain stage).vgz" size="160938" crc="9e3eaa69" sha1="c3c1780b059adcc5853c43249fd4373bd0d60ecb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 unescapeable (execution place stage).vgz" />
+ <dataarea name="quik" size="135690">
+ <rom name="29 unescapeable (execution place stage).vgz" size="135690" crc="0e25f439" sha1="fef996b5f25e2a69c0f4d43cda5fd6f5540af8db" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 trio (before rival battle demo).vgz" />
+ <dataarea name="quik" size="21772">
+ <rom name="30 trio (before rival battle demo).vgz" size="21772" crc="1ea3dffa" sha1="79a20bbf9600bd9182c7f612533d88cb07054b09" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 worthy rival (rival last battle).vgz" />
+ <dataarea name="quik" size="281660">
+ <rom name="31 worthy rival (rival last battle).vgz" size="281660" crc="aa3dae12" sha1="49cb5448b3dfce2391ad9e8d28e50e3a815e5521" offset="0" />
+ </dataarea>
+ </part>
+ <part name="032" interface="vgm_quik">
+ <feature name="part_id" value="32 request for an encore (continue).vgz" />
+ <dataarea name="quik" size="118161">
+ <rom name="32 request for an encore (continue).vgz" size="118161" crc="cc06e1a5" sha1="8e04cad8a22ccc844e1b8506b742673baa0c3530" offset="0" />
+ </dataarea>
+ </part>
+ <part name="033" interface="vgm_quik">
+ <feature name="part_id" value="33 horizon -i- (normal ending).vgz" />
+ <dataarea name="quik" size="140466">
+ <rom name="33 horizon -i- (normal ending).vgz" size="140466" crc="d8064653" sha1="a7218608d961da76b913108faff3a44cab63a84c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="034" interface="vgm_quik">
+ <feature name="part_id" value="34 horizon -ii- (bad ending).vgz" />
+ <dataarea name="quik" size="254743">
+ <rom name="34 horizon -ii- (bad ending).vgz" size="254743" crc="cd23fe89" sha1="8182f0878dc6227fd53af871e70bb56919496ffe" offset="0" />
+ </dataarea>
+ </part>
+ <part name="035" interface="vgm_quik">
+ <feature name="part_id" value="35 promoter (staff roll).vgz" />
+ <dataarea name="quik" size="308109">
+ <rom name="35 promoter (staff roll).vgz" size="308109" crc="8be53964" sha1="3effc17267c4d2f16de32efb03e2b809c52ad63e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="036" interface="vgm_quik">
+ <feature name="part_id" value="36 the curtain falls (game over).vgz" />
+ <dataarea name="quik" size="14337">
+ <rom name="36 the curtain falls (game over).vgz" size="14337" crc="173ce652" sha1="f32ea374938242feaa67dcc1ef03b9ad6d026a85" offset="0" />
+ </dataarea>
+ </part>
+ <part name="037" interface="vgm_quik">
+ <feature name="part_id" value="37 unused.vgz" />
+ <dataarea name="quik" size="13545">
+ <rom name="37 unused.vgz" size="13545" crc="6bfaf0eb" sha1="8a9411ac15b5203221818f0b519cd2201589acb7" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="samsho5">
+ <description>Samurai Shodown V (Neo Geo)</description>
+ <year>2003</year>
+ <publisher>SNK Playmore</publisher>
+ <info name="cores" value="YM2610"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 bushido (title).vgz" />
+ <dataarea name="quik" size="571816">
+ <rom name="01 bushido (title).vgz" size="571816" crc="33aaa895" sha1="83dc7f290ad65cca580c3b1b150aff3baca9b924" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 the twenty four challengers (player selection).vgz" />
+ <dataarea name="quik" size="418213">
+ <rom name="02 the twenty four challengers (player selection).vgz" size="418213" crc="77c4f801" sha1="b31ba2de0c42265af14aa23668e7f907d852e1f3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 journey (map screen).vgz" />
+ <dataarea name="quik" size="93020">
+ <rom name="03 journey (map screen).vgz" size="93020" crc="788374d9" sha1="a0c5cdc747e0432df92364a640afe6d628e4569d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 iza jinjyouni.vgz" />
+ <dataarea name="quik" size="157764">
+ <rom name="04 iza jinjyouni.vgz" size="157764" crc="9460c1aa" sha1="eaa062ad896f5420a0a61c0642d7e9df5e682182" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 shogun (yoshitora tokugawa).vgz" />
+ <dataarea name="quik" size="564439">
+ <rom name="05 shogun (yoshitora tokugawa).vgz" size="564439" crc="3fe77bd9" sha1="d35144e6c7bb3ed3b0c887bb9ca35506e66d03d1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 shoubuari.vgz" />
+ <dataarea name="quik" size="147396">
+ <rom name="06 shoubuari.vgz" size="147396" crc="f432cc49" sha1="c1a91f27a3a78123085401530bd3028a30b279ab" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 kachi ikusa (winner demo).vgz" />
+ <dataarea name="quik" size="70925">
+ <rom name="07 kachi ikusa (winner demo).vgz" size="70925" crc="4afdc90c" sha1="eb44fd03747f185b3b09989533f0edec9cc6a86c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 papillon (mina majikina).vgz" />
+ <dataarea name="quik" size="408221">
+ <rom name="08 papillon (mina majikina).vgz" size="408221" crc="c9af04b3" sha1="90a39878835cc4601f88cdef5b1300ffa064f1b0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 ceremony (liu yunfei).vgz" />
+ <dataarea name="quik" size="277550">
+ <rom name="09 ceremony (liu yunfei).vgz" size="277550" crc="276ccd84" sha1="203ff4c41eaa7fa2df29fbee278929f81a413a29" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 moonlight dinner (youkai kusaregedo).vgz" />
+ <dataarea name="quik" size="214247">
+ <rom name="10 moonlight dinner (youkai kusaregedo).vgz" size="214247" crc="ce83cb16" sha1="8927e4e0be46d99b52330dc6bc88472284ab255f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 water incarnation (sogetsu kazama).vgz" />
+ <dataarea name="quik" size="178473">
+ <rom name="11 water incarnation (sogetsu kazama).vgz" size="178473" crc="3403013e" sha1="6b469724f9e8d77fc039ca57d195b84a1112509f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 sankuro appears (sankuro yorozu challenges).vgz" />
+ <dataarea name="quik" size="66231">
+ <rom name="12 sankuro appears (sankuro yorozu challenges).vgz" size="66231" crc="4bb74423" sha1="ba1b7b0c6017323a56b8250d3f9db6457cb4faf8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 the mirror of heart -part ii- (rimururu).vgz" />
+ <dataarea name="quik" size="139745">
+ <rom name="13 the mirror of heart -part ii- (rimururu).vgz" size="139745" crc="90e59399" sha1="5bedcb6e11281c502d0b4a642625cf5832e48015" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 banquet of nature -part ii- (nakoruru).vgz" />
+ <dataarea name="quik" size="214960">
+ <rom name="14 banquet of nature -part ii- (nakoruru).vgz" size="214960" crc="c79c8f9e" sha1="481dd1d639695dc7fd165e44b51466408e03c697" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 tuna incarnation (galford).vgz" />
+ <dataarea name="quik" size="285512">
+ <rom name="15 tuna incarnation (galford).vgz" size="285512" crc="007daf88" sha1="3c7f069aeff8a5d9c223b587bf44b392bb3a1b03" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 yumeji appears (yumeji kurokouchi demo).vgz" />
+ <dataarea name="quik" size="240665">
+ <rom name="16 yumeji appears (yumeji kurokouchi demo).vgz" size="240665" crc="380549a8" sha1="28ce6cfe91c137d104dcb554ef7322267d96c4ce" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 yomigahara (yumeji kurokouchi).vgz" />
+ <dataarea name="quik" size="460589">
+ <rom name="17 yomigahara (yumeji kurokouchi).vgz" size="460589" crc="24192ae7" sha1="c3e44942a1160527e2cacfac3d8fead3cf66cd27" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 sakura (haohmaru).vgz" />
+ <dataarea name="quik" size="81741">
+ <rom name="18 sakura (haohmaru).vgz" size="81741" crc="7156f011" sha1="759bb35f0c26d56564b49784ec1de185ec82fbb1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 southern barbarians visiting (dejima stage).vgz" />
+ <dataarea name="quik" size="340113">
+ <rom name="19 southern barbarians visiting (dejima stage).vgz" size="340113" crc="1c70e55e" sha1="404fec0b3fc487b79ead394334ef0fea7e915fa0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 sannomiya (seaside stage).vgz" />
+ <dataarea name="quik" size="100466">
+ <rom name="20 sannomiya (seaside stage).vgz" size="100466" crc="cb6f0421" sha1="faee50a99eb53942be5e3f87b85cb1eca685e162" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 bambuseae (bamboo stage).vgz" />
+ <dataarea name="quik" size="67471">
+ <rom name="21 bambuseae (bamboo stage).vgz" size="67471" crc="cdd7c274" sha1="8de192d050d251e6a477a8aeeed3dd73215710d1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 dog (abandoned village stage).vgz" />
+ <dataarea name="quik" size="137944">
+ <rom name="22 dog (abandoned village stage).vgz" size="137944" crc="f1f457da" sha1="72589bfee60e135c28592f1b527a9e2ecdb7a4a4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 inferno (fire stage).vgz" />
+ <dataarea name="quik" size="35811">
+ <rom name="23 inferno (fire stage).vgz" size="35811" crc="45455597" sha1="ad3a65fcc790a3553da8cb3712272c9a65174e81" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 old temple (old temple stage).vgz" />
+ <dataarea name="quik" size="48425">
+ <rom name="24 old temple (old temple stage).vgz" size="48425" crc="149027b9" sha1="cb26726bc191dbd0d614ddc2c7487d94f96a7e5d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 gaoh appears (gaoh kyogoku hinowanokami demo).vgz" />
+ <dataarea name="quik" size="248966">
+ <rom name="25 gaoh appears (gaoh kyogoku hinowanokami demo).vgz" size="248966" crc="39c7a6f2" sha1="e8f7be33f2316f0f3078751d6f998ed946e79d0a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 hero (gaoh kyogoku hinowanokami).vgz" />
+ <dataarea name="quik" size="381243">
+ <rom name="26 hero (gaoh kyogoku hinowanokami).vgz" size="381243" crc="9d0b11b6" sha1="d3117d10752d2345c95d3563d9cca214e0680a0e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 lamentations (kuraki-sumeragi).vgz" />
+ <dataarea name="quik" size="268859">
+ <rom name="27 lamentations (kuraki-sumeragi).vgz" size="268859" crc="246259a6" sha1="f6aca082627b12bbecaf0cb77ee98c4a6a4f635a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 gaoh's farewell (ending).vgz" />
+ <dataarea name="quik" size="585438">
+ <rom name="28 gaoh's farewell (ending).vgz" size="585438" crc="f3e6bfee" sha1="ee3d740a4f5fe6109d8ea31ce16ff1278c236f94" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 to a new journey (staff roll).vgz" />
+ <dataarea name="quik" size="165932">
+ <rom name="29 to a new journey (staff roll).vgz" size="165932" crc="c310094c" sha1="b7569b7ec49374e91f915777037a405cddf28ff5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 request for an encore (continue).vgz" />
+ <dataarea name="quik" size="356423">
+ <rom name="30 request for an encore (continue).vgz" size="356423" crc="4ade9104" sha1="94c20be5fdbc4334f84424280cef081f5b4d1fe9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 the curtain falls (game over).vgz" />
+ <dataarea name="quik" size="119050">
+ <rom name="31 the curtain falls (game over).vgz" size="119050" crc="9f9c0043" sha1="c33caf2191741dbe53377121eeecfdd48036186d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="032" interface="vgm_quik">
+ <feature name="part_id" value="32 unused (meditation -ii-).vgz" />
+ <dataarea name="quik" size="20559">
+ <rom name="32 unused (meditation -ii-).vgz" size="20559" crc="eadf4ebe" sha1="dd2bb89cb211d7909bf3ce20b137b1bad9c7f9e7" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="samsh5sp">
+ <description>Samurai Shodown V Special (Neo Geo)</description>
+ <year>2004</year>
+ <publisher>SNK Playmore</publisher>
+ <info name="cores" value="YM2610"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 bushido (title).vgz" />
+ <dataarea name="quik" size="908170">
+ <rom name="01 bushido (title).vgz" size="908170" crc="645865c5" sha1="a8cbbb82b0d5d7864b3416121709b301892fa618" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 player select.vgz" />
+ <dataarea name="quik" size="459570">
+ <rom name="02 player select.vgz" size="459570" crc="a80b24ec" sha1="a06115393045ed78633187c71e7970837d7f45ef" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 pre-war demo.vgz" />
+ <dataarea name="quik" size="183109">
+ <rom name="03 pre-war demo.vgz" size="183109" crc="f5de7569" sha1="77048fc862484e00acd32b612cf9b580637c6cc7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 iza jinjyouni.vgz" />
+ <dataarea name="quik" size="157787">
+ <rom name="04 iza jinjyouni.vgz" size="157787" crc="96a95618" sha1="619efe74659ef8380cf133a5cb16d6dccd009d88" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 sunpu, fujiminoma stage (shogun).vgz" />
+ <dataarea name="quik" size="564484">
+ <rom name="05 sunpu, fujiminoma stage (shogun).vgz" size="564484" crc="bc4e8f1d" sha1="6ea32dfdcd3f3c14f1a88c848c46d94aeeaee19e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 overkill.vgz" />
+ <dataarea name="quik" size="81919">
+ <rom name="06 overkill.vgz" size="81919" crc="6a10c9b7" sha1="88e3ce5f923e464e07a198fb34b1bedd228bdc87" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 shoubuari.vgz" />
+ <dataarea name="quik" size="147531">
+ <rom name="07 shoubuari.vgz" size="147531" crc="972ef64d" sha1="d640ebed4f417d7be562e63bada8eef7dd1568fb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 ryukyu kingdom, shuri castle stage (papillon).vgz" />
+ <dataarea name="quik" size="353150">
+ <rom name="08 ryukyu kingdom, shuri castle stage (papillon).vgz" size="353150" crc="0ef80b72" sha1="5235564a294a9e5924f5e7a70f3544d684b16a52" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 qing, millenary daibutsu stage (ceremony).vgz" />
+ <dataarea name="quik" size="277611">
+ <rom name="09 qing, millenary daibutsu stage (ceremony).vgz" size="277611" crc="dabfbe92" sha1="96d6e5d3491ef9e9954298da2a6f5919ac44f9c7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 sado, gedoh's lair stage.vgz" />
+ <dataarea name="quik" size="328519">
+ <rom name="10 sado, gedoh's lair stage.vgz" size="328519" crc="878e1e71" sha1="d7967ef6c842ebb5a3d1497dcba546411e7f1c23" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 yomigahara kassemba stage (hero).vgz" />
+ <dataarea name="quik" size="381280">
+ <rom name="11 yomigahara kassemba stage (hero).vgz" size="381280" crc="8d118045" sha1="81f69f6220d0484cba5c1dc8b8861aeb4bc353c3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 old temple stage.vgz" />
+ <dataarea name="quik" size="229353">
+ <rom name="12 old temple stage.vgz" size="229353" crc="f05c58d9" sha1="7205c898a1cae4148fb83914b892b2e3c68f23bf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 rocky mountain stage.vgz" />
+ <dataarea name="quik" size="88402">
+ <rom name="13 rocky mountain stage.vgz" size="88402" crc="85917050" sha1="c9f40043c71ef01672b03d76f67ae0551cc37b90" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 gallows stage.vgz" />
+ <dataarea name="quik" size="101082">
+ <rom name="14 gallows stage.vgz" size="101082" crc="54bf843c" sha1="11192c576a202a889aa450a1d7e51ad08c016fec" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 gairyu isle stage.vgz" />
+ <dataarea name="quik" size="377405">
+ <rom name="15 gairyu isle stage.vgz" size="377405" crc="ab349684" sha1="88c3783208986634338b0a89e3adb77e19599b71" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 japan bridge stage.vgz" />
+ <dataarea name="quik" size="192703">
+ <rom name="16 japan bridge stage.vgz" size="192703" crc="dd4624c5" sha1="9860327068627c3940a49dd1e246c83609dce2b6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 kuroko dojo stage.vgz" />
+ <dataarea name="quik" size="175314">
+ <rom name="17 kuroko dojo stage.vgz" size="175314" crc="d8829daf" sha1="201becd7f2079199a609f70350558e669d791a7c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 osorezan stage.vgz" />
+ <dataarea name="quik" size="470090">
+ <rom name="18 osorezan stage.vgz" size="470090" crc="639a8aa8" sha1="8f7d8d51ead5e0c340382b8defa9501205830974" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 ending.vgz" />
+ <dataarea name="quik" size="573369">
+ <rom name="19 ending.vgz" size="573369" crc="25e81535" sha1="16d6e5bbfd89a4b04747bbb7a2d398be9da8b49c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 request for an encore (continue).vgz" />
+ <dataarea name="quik" size="356446">
+ <rom name="20 request for an encore (continue).vgz" size="356446" crc="b9ea7fd9" sha1="583d8893e3c1374b6f8dc8ae4cf92affe3dabac2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 the curtain falls (game over).vgz" />
+ <dataarea name="quik" size="119071">
+ <rom name="21 the curtain falls (game over).vgz" size="119071" crc="c6acdea9" sha1="0e9ca722f28e16a6df893cecd70d8f8b34ac7bda" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 unused song 1.vgz" />
+ <dataarea name="quik" size="193449">
+ <rom name="22 unused song 1.vgz" size="193449" crc="f5c19b95" sha1="bd2ab0d7bf2341cf044943ea39923f5c4c79c541" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 unused song 2.vgz" />
+ <dataarea name="quik" size="271043">
+ <rom name="23 unused song 2.vgz" size="271043" crc="cb035be9" sha1="34b9ae74c5fcb385a671e308860027c26848a60d" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="knightm3_msx">
+ <description>Shalom (MSX)</description>
+ <year>1987</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 title.vgz" />
+ <dataarea name="quik" size="438">
+ <rom name="01 title.vgz" size="438" crc="c0756501" sha1="a213c93434b6f9d87649b95b81650693ed01eb49" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 opening.vgz" />
+ <dataarea name="quik" size="7492">
+ <rom name="02 opening.vgz" size="7492" crc="97f16523" sha1="6d8e42ab7948f9438bf89bab591957ef584b0d5f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 administration - story bgm1.vgz" />
+ <dataarea name="quik" size="4151">
+ <rom name="03 administration - story bgm1.vgz" size="4151" crc="9cd43154" sha1="61fe2a377fe36b87a7028662e81ec866172b2e2a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 enter - exit game world.vgz" />
+ <dataarea name="quik" size="2509">
+ <rom name="04 enter - exit game world.vgz" size="2509" crc="dbb39927" sha1="1afe4c2c706f6f9276474dd6d0cfe46de44fe713" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 story bgm2.vgz" />
+ <dataarea name="quik" size="2392">
+ <rom name="05 story bgm2.vgz" size="2392" crc="e5ee3f9a" sha1="4e44d0555ed279cdeba79281299b9096ec828949" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 world bgm.vgz" />
+ <dataarea name="quik" size="6116">
+ <rom name="06 world bgm.vgz" size="6116" crc="ffc9d522" sha1="0646ae2d4ab6dd7814dfe9578a61d363a86f03de" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 outside the castle bgm.vgz" />
+ <dataarea name="quik" size="5492">
+ <rom name="07 outside the castle bgm.vgz" size="5492" crc="a26b9ae6" sha1="01fe696bab49af2e17b3a4f23843dc39fcd01523" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 castle bgm.vgz" />
+ <dataarea name="quik" size="4524">
+ <rom name="08 castle bgm.vgz" size="4524" crc="3f9fb3b6" sha1="bf4eae669e81794606818af7ca71d309a06a8e73" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 story bgm3.vgz" />
+ <dataarea name="quik" size="1288">
+ <rom name="09 story bgm3.vgz" size="1288" crc="c98899fb" sha1="7a3c180cd3a8c302c85aaae2c3b8138e2cb823c2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 grand cross bgm.vgz" />
+ <dataarea name="quik" size="2067">
+ <rom name="10 grand cross bgm.vgz" size="2067" crc="17d12fbf" sha1="f5b0ca4a3527ee221ecb6083e71a2a1adecf06fe" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 mountain bgm.vgz" />
+ <dataarea name="quik" size="3883">
+ <rom name="11 mountain bgm.vgz" size="3883" crc="b8394147" sha1="21f596461cfdf540bc126cde8f16dc9d4e810623" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 boss bgm1.vgz" />
+ <dataarea name="quik" size="2962">
+ <rom name="12 boss bgm1.vgz" size="2962" crc="f39a878f" sha1="c9b5dbfd490cc173b04702b65b909513d8457129" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 cave bgm.vgz" />
+ <dataarea name="quik" size="3228">
+ <rom name="13 cave bgm.vgz" size="3228" crc="0b865df1" sha1="baddf440df15244a49edf6283ded4048dc51bce3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 boss bgm2.vgz" />
+ <dataarea name="quik" size="5991">
+ <rom name="14 boss bgm2.vgz" size="5991" crc="8a8aa7d7" sha1="a1bc89c9597fa1117f70832e17ce16fdc077def5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 enter heaven.vgz" />
+ <dataarea name="quik" size="858">
+ <rom name="15 enter heaven.vgz" size="858" crc="b007c379" sha1="ee0dfb782944b37c9109466a8c61cb03540c9e43" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 popolon and aphrodite bgm.vgz" />
+ <dataarea name="quik" size="2417">
+ <rom name="16 popolon and aphrodite bgm.vgz" size="2417" crc="0ea22e28" sha1="c7c78a648d2e6b951d3245b5813f500fdcc84492" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 stomach bgm.vgz" />
+ <dataarea name="quik" size="2947">
+ <rom name="17 stomach bgm.vgz" size="2947" crc="4af75d2b" sha1="50585c8f6faaf7ad6d95d237feb036942489fbc3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 mermaid's house bgm.vgz" />
+ <dataarea name="quik" size="5239">
+ <rom name="18 mermaid's house bgm.vgz" size="5239" crc="0c1a71b5" sha1="34cc91ec43afe1fd66de58cde841ab9eb9b33da7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 the end.vgz" />
+ <dataarea name="quik" size="3669">
+ <rom name="19 the end.vgz" size="3669" crc="f15d0985" sha1="408f0143aa28d951fd8672e66ee4ed99bf7b2b49" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 story bgm4.vgz" />
+ <dataarea name="quik" size="3213">
+ <rom name="20 story bgm4.vgz" size="3213" crc="0df08af7" sha1="74d968127208b038dee7302fe76465303608fe8e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 ruins bgm.vgz" />
+ <dataarea name="quik" size="1941">
+ <rom name="21 ruins bgm.vgz" size="1941" crc="1c24086e" sha1="e399c3034a616b0a1e2f663a42b230b9b58306fb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 sea bgm.vgz" />
+ <dataarea name="quik" size="4700">
+ <rom name="22 sea bgm.vgz" size="4700" crc="476f167c" sha1="7e4a0af6f139dbb7ee1c890ee99f570457839d55" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 to the final battle bgm.vgz" />
+ <dataarea name="quik" size="2645">
+ <rom name="23 to the final battle bgm.vgz" size="2645" crc="d5f9105c" sha1="cc86411a44ab4c461725776c3bf6ac80ddd84152" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 farewell bgm.vgz" />
+ <dataarea name="quik" size="5184">
+ <rom name="24 farewell bgm.vgz" size="5184" crc="c64e8ff5" sha1="d01f9a756765d279ed7844d69ff2dcd64905f091" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 story bgm5 - final battle.vgz" />
+ <dataarea name="quik" size="1831">
+ <rom name="25 story bgm5 - final battle.vgz" size="1831" crc="95cc81f0" sha1="0c75c292463d7cf290f46aaf2ff2be2dbcfa2df0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 story bgm6.vgz" />
+ <dataarea name="quik" size="2405">
+ <rom name="26 story bgm6.vgz" size="2405" crc="50cedede" sha1="69c5d47b93c96044e8e8bc2b90ea887ff337342a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 story bgm7.vgz" />
+ <dataarea name="quik" size="1202">
+ <rom name="27 story bgm7.vgz" size="1202" crc="0e014621" sha1="54839078983f0a35976488c202ff2e1727f2cf6a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 flash of light.vgz" />
+ <dataarea name="quik" size="1072">
+ <rom name="28 flash of light.vgz" size="1072" crc="f2f28c95" sha1="ffb38d8f51e7ce95807439f846d64d8377a3dce7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 ending.vgz" />
+ <dataarea name="quik" size="8030">
+ <rom name="29 ending.vgz" size="8030" crc="bc4f4f16" sha1="9762375397b26ca465f8937865e2ff32efa98c43" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sonic3d5_gb">
+ <description>Sonic 3D Blast 5 (Nintendo Game Boy)</description>
+ <year>1997</year>
+ <publisher>unknown</publisher>
+ <info name="cores" value="Game Boy DMG (LR35902)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 title screen.vgz" />
+ <dataarea name="quik" size="573">
+ <rom name="01 title screen.vgz" size="573" crc="9bc8b6fa" sha1="675f2e175ea743105fdb60c0c1a72df80790a76d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 map ~ ending.vgz" />
+ <dataarea name="quik" size="857">
+ <rom name="02 map ~ ending.vgz" size="857" crc="6fd0d7a2" sha1="6287f90830f04d7be667ca26b32c9251a6d45442" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 act 1 ~ act 5.vgz" />
+ <dataarea name="quik" size="1750">
+ <rom name="03 act 1 ~ act 5.vgz" size="1750" crc="3b65f095" sha1="048ce29bcc4f7dc7d1bfc4eaefb98c557d0a9d09" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 act 2.vgz" />
+ <dataarea name="quik" size="789">
+ <rom name="04 act 2.vgz" size="789" crc="d4c34788" sha1="dfec41f16d3030b79b044df78b904e37e10662e5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 act 3.vgz" />
+ <dataarea name="quik" size="1322">
+ <rom name="05 act 3.vgz" size="1322" crc="1eb98e11" sha1="8facf8973f6e941270bbc9c747f8fd722fe797a4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 act 4.vgz" />
+ <dataarea name="quik" size="1336">
+ <rom name="06 act 4.vgz" size="1336" crc="3d2ab460" sha1="1558f8da9e55f4eb9ba71ed0d9a1dbbdc612177e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 act clear.vgz" />
+ <dataarea name="quik" size="501">
+ <rom name="07 act clear.vgz" size="501" crc="036880a3" sha1="b9108e72e2857921fbf60b6534690f04171f6781" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 miss.vgz" />
+ <dataarea name="quik" size="438">
+ <rom name="08 miss.vgz" size="438" crc="6cbc16e1" sha1="33bc086e956719e7e55dbc8d85cdf7e03f4d1f30" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 game over.vgz" />
+ <dataarea name="quik" size="459">
+ <rom name="09 game over.vgz" size="459" crc="27e21d41" sha1="d5ef83e85bf39e87c3b286dbf21f5d482a7c5b6b" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sorcer_msx2o">
+ <description>Sorcerian (MSX2, OPLL)</description>
+ <year>1991</year>
+ <publisher>Falcom</publisher>
+ <info name="cores" value="MSX-MUSIC (YM2413), PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 opening.vgz" />
+ <dataarea name="quik" size="4017">
+ <rom name="01 opening.vgz" size="4017" crc="92846899" sha1="4177351679c0d02ad3123939ba536897bcc63bf0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 castle [let's meet here].vgz" />
+ <dataarea name="quik" size="17521">
+ <rom name="02 castle [let's meet here].vgz" size="17521" crc="b064bd5b" sha1="587c9cfbca4c3197015c709aa08edd64bb7a458f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 town [pentawa i].vgz" />
+ <dataarea name="quik" size="5866">
+ <rom name="03 town [pentawa i].vgz" size="5866" crc="2ac2ceef" sha1="8f1c29a35e2b9f9b64c41b138188e2bc4a815984" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 town [pentawa ii].vgz" />
+ <dataarea name="quik" size="24170">
+ <rom name="04 town [pentawa ii].vgz" size="24170" crc="337e8180" sha1="36027be00445bb14414d81f26cf6ab2479bf0258" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 dungeon (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="9034">
+ <rom name="05 dungeon (disappearance of the king's scepter).vgz" size="9034" crc="e2bae21e" sha1="0e95a0df2b6ff9fc98b3a54a69112f93cd264379" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 hydra (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="7314">
+ <rom name="06 hydra (disappearance of the king's scepter).vgz" size="7314" crc="e6bdf1ab" sha1="ee2e959f52bb4a8770c1a5fb89f8160701dc9e78" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 survivor (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="11434">
+ <rom name="07 survivor (disappearance of the king's scepter).vgz" size="11434" crc="eb0ce10c" sha1="8faf414ca3c06324df8afdb23fecb6b4b1d08ae0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 travelers inn (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="4295">
+ <rom name="08 travelers inn (disappearance of the king's scepter).vgz" size="4295" crc="d6ed447c" sha1="7e88ad99553b823fa43817cbcabe41a7ed0823d2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 forest (the lost talisman).vgz" />
+ <dataarea name="quik" size="7934">
+ <rom name="09 forest (the lost talisman).vgz" size="7934" crc="82a74944" sha1="cdcfee419f0656fb525f02b2e42ec99ef681f9d1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 underground dungeon (the lost talisman).vgz" />
+ <dataarea name="quik" size="6334">
+ <rom name="10 underground dungeon (the lost talisman).vgz" size="6334" crc="612f33c2" sha1="3d7a3fc4e2c4021baf91c5f7cef03526d7d7f0a2" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 priest dehytel (the lost talisman).vgz" />
+ <dataarea name="quik" size="7563">
+ <rom name="11 priest dehytel (the lost talisman).vgz" size="7563" crc="77fdca3e" sha1="bbc5321a9e30da8950a5464872c25a45972c4488" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 sand marivoux (the lost talisman).vgz" />
+ <dataarea name="quik" size="6903">
+ <rom name="12 sand marivoux (the lost talisman).vgz" size="6903" crc="003390b3" sha1="ae380a26f22c2fc22be9794dfc8df332465581c9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 underground dungeon (lucifer's water gate).vgz" />
+ <dataarea name="quik" size="11885">
+ <rom name="13 underground dungeon (lucifer's water gate).vgz" size="11885" crc="6f206bfc" sha1="1faf886bf7f33a51ffafac823156ce4bbf778e4e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 kraken (lucifer's water gate).vgz" />
+ <dataarea name="quik" size="8067">
+ <rom name="14 kraken (lucifer's water gate).vgz" size="8067" crc="220f8fc9" sha1="4fafff4d4ec54d80730fc4e1f59cbbb1e23b73e9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 bloody river (lucifer's water gate).vgz" />
+ <dataarea name="quik" size="13332">
+ <rom name="15 bloody river (lucifer's water gate).vgz" size="13332" crc="a4d7b316" sha1="67be8f08a01e32cb6614bc88aa1d4001c0128773" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 desert (cursed oasis).vgz" />
+ <dataarea name="quik" size="7438">
+ <rom name="16 desert (cursed oasis).vgz" size="7438" crc="86e701f3" sha1="a25bd57047cac754e3a213f35b6ee7b5921044e3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 sand castle (cursed oasis).vgz" />
+ <dataarea name="quik" size="13261">
+ <rom name="17 sand castle (cursed oasis).vgz" size="13261" crc="5a87e030" sha1="9bc6270aa480900dd23f542fcc2cd6116208258a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 ruwan and the gold dragon (cursed oasis).vgz" />
+ <dataarea name="quik" size="10100">
+ <rom name="18 ruwan and the gold dragon (cursed oasis).vgz" size="10100" crc="abcd0374" sha1="9766a6fcd37f8fe320875eb9cc1091151dad0f58" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 tower (thieves tower).vgz" />
+ <dataarea name="quik" size="8687">
+ <rom name="19 tower (thieves tower).vgz" size="8687" crc="f7e2d22e" sha1="60d278187dc66d422f2892c778beb54a1d03e22f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 depths of the earth (thieves tower).vgz" />
+ <dataarea name="quik" size="9153">
+ <rom name="20 depths of the earth (thieves tower).vgz" size="9153" crc="507fc328" sha1="e6e268eac29899e6895bd429b899e50c32fd545c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 rooftop (thieves tower).vgz" />
+ <dataarea name="quik" size="2625">
+ <rom name="21 rooftop (thieves tower).vgz" size="2625" crc="1eaf3df1" sha1="1d304f132f06e750c695bcaa91a23dd088348c35" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 major demon (thieves tower).vgz" />
+ <dataarea name="quik" size="9037">
+ <rom name="22 major demon (thieves tower).vgz" size="9037" crc="688448c7" sha1="41958440440aec2c2fae8ad23ed826325d4200b8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 shadow dragon (thieves tower).vgz" />
+ <dataarea name="quik" size="5299">
+ <rom name="23 shadow dragon (thieves tower).vgz" size="5299" crc="c34346ab" sha1="3d36e5f65b1f3300a47f6dbe2a75acc3197d3560" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 seal (thieves tower).vgz" />
+ <dataarea name="quik" size="9843">
+ <rom name="24 seal (thieves tower).vgz" size="9843" crc="36876c84" sha1="0722d18efcc921af895313d852b6c3c8c12fc794" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 dark swamp (the wizard in the dark swamp).vgz" />
+ <dataarea name="quik" size="7668">
+ <rom name="25 dark swamp (the wizard in the dark swamp).vgz" size="7668" crc="a6d99613" sha1="62bccb5cd49258fce836a13332ca3b6934899d83" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 red dragon (the wizard in the dark swamp).vgz" />
+ <dataarea name="quik" size="7507">
+ <rom name="26 red dragon (the wizard in the dark swamp).vgz" size="7507" crc="17568114" sha1="38b8bdc0f0d18661a80267d6ad39b87a0877369e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 romancia kingdom (romancia).vgz" />
+ <dataarea name="quik" size="5884">
+ <rom name="27 romancia kingdom (romancia).vgz" size="5884" crc="5f4d5b0f" sha1="f6ba54c31a575c40ab83d298adc385d29fcc5536" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 romancia castle (romancia).vgz" />
+ <dataarea name="quik" size="4843">
+ <rom name="28 romancia castle (romancia).vgz" size="4843" crc="7a0cb7aa" sha1="3eeb7a98411e15f14a25279bd3d72ac388bdb10d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 azorba kingdom (romancia).vgz" />
+ <dataarea name="quik" size="5511">
+ <rom name="29 azorba kingdom (romancia).vgz" size="5511" crc="64329b37" sha1="ccdf5d2012d6b666bf88c72fce6bde4a6cec55d1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 vaides (romancia).vgz" />
+ <dataarea name="quik" size="5445">
+ <rom name="30 vaides (romancia).vgz" size="5445" crc="23b0f89a" sha1="d20c9f154eeb12ec5e684d0f96dccf138c818930" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 forest (riddle of the red coin).vgz" />
+ <dataarea name="quik" size="8906">
+ <rom name="31 forest (riddle of the red coin).vgz" size="8906" crc="1f4d27c8" sha1="14fc958ad3045df2507a7751f6be49f208632e09" offset="0" />
+ </dataarea>
+ </part>
+ <part name="032" interface="vgm_quik">
+ <feature name="part_id" value="32 moss giant (riddle of the red coin).vgz" />
+ <dataarea name="quik" size="10827">
+ <rom name="32 moss giant (riddle of the red coin).vgz" size="10827" crc="a9527bf8" sha1="53cdc29599daf4e158c11a4b799c87ef2d564b79" offset="0" />
+ </dataarea>
+ </part>
+ <part name="033" interface="vgm_quik">
+ <feature name="part_id" value="33 peaceful forest (riddle of the red coin).vgz" />
+ <dataarea name="quik" size="8316">
+ <rom name="33 peaceful forest (riddle of the red coin).vgz" size="8316" crc="3bf752ca" sha1="12423cc5d76053e4530493c210d5bd9c2a11e788" offset="0" />
+ </dataarea>
+ </part>
+ <part name="034" interface="vgm_quik">
+ <feature name="part_id" value="34 dungeon i (the black wizard).vgz" />
+ <dataarea name="quik" size="10090">
+ <rom name="34 dungeon i (the black wizard).vgz" size="10090" crc="7e119f84" sha1="7d254f3ff034179fc9ae408128459e40c9145922" offset="0" />
+ </dataarea>
+ </part>
+ <part name="035" interface="vgm_quik">
+ <feature name="part_id" value="35 dungeon ii (the black wizard).vgz" />
+ <dataarea name="quik" size="3238">
+ <rom name="35 dungeon ii (the black wizard).vgz" size="3238" crc="36febe3f" sha1="589912a15825214bb4dbf9d33dae1d093e63aeab" offset="0" />
+ </dataarea>
+ </part>
+ <part name="036" interface="vgm_quik">
+ <feature name="part_id" value="36 ghedis (the black wizard).vgz" />
+ <dataarea name="quik" size="5335">
+ <rom name="36 ghedis (the black wizard).vgz" size="5335" crc="8fd2a2ba" sha1="31eea22a2bd280e708566fa4c024fd8fbefaa205" offset="0" />
+ </dataarea>
+ </part>
+ <part name="037" interface="vgm_quik">
+ <feature name="part_id" value="37 blue dragon (the black wizard).vgz" />
+ <dataarea name="quik" size="8432">
+ <rom name="37 blue dragon (the black wizard).vgz" size="8432" crc="6cf39edd" sha1="beeec36cf482cc8fb4a178f8870a37ee71dc9a6b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="038" interface="vgm_quik">
+ <feature name="part_id" value="38 aboard ship (cursed queen mary).vgz" />
+ <dataarea name="quik" size="12920">
+ <rom name="38 aboard ship (cursed queen mary).vgz" size="12920" crc="ab7b59a7" sha1="1448932358b8c27fdc047db08924dc4170d890ad" offset="0" />
+ </dataarea>
+ </part>
+ <part name="039" interface="vgm_quik">
+ <feature name="part_id" value="39 after disembarking (cursed queen mary).vgz" />
+ <dataarea name="quik" size="11873">
+ <rom name="39 after disembarking (cursed queen mary).vgz" size="11873" crc="61a9ab79" sha1="8049285e272fdaa6f1e84425872c76a2c5f75f07" offset="0" />
+ </dataarea>
+ </part>
+ <part name="040" interface="vgm_quik">
+ <feature name="part_id" value="40 arch demon (cursed queen mary).vgz" />
+ <dataarea name="quik" size="7408">
+ <rom name="40 arch demon (cursed queen mary).vgz" size="7408" crc="307fe8cf" sha1="9e0947253f030c6f3d48e733004a49568089d698" offset="0" />
+ </dataarea>
+ </part>
+ <part name="041" interface="vgm_quik">
+ <feature name="part_id" value="41 village (the olympians).vgz" />
+ <dataarea name="quik" size="4812">
+ <rom name="41 village (the olympians).vgz" size="4812" crc="fb821276" sha1="38de7c673ef73126528dbf76e00070e819940f11" offset="0" />
+ </dataarea>
+ </part>
+ <part name="042" interface="vgm_quik">
+ <feature name="part_id" value="42 combat scene (the olympians).vgz" />
+ <dataarea name="quik" size="11437">
+ <rom name="42 combat scene (the olympians).vgz" size="11437" crc="b43b52c7" sha1="873df81d3e7b0ccf62551f7248bca223c80a7f9b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="043" interface="vgm_quik">
+ <feature name="part_id" value="43 the heavens (the olympians).vgz" />
+ <dataarea name="quik" size="10080">
+ <rom name="43 the heavens (the olympians).vgz" size="10080" crc="c33d95b5" sha1="fc228dfeb21817e0ebbdbef67113d38852d5bb4c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="044" interface="vgm_quik">
+ <feature name="part_id" value="44 harp (the olympians).vgz" />
+ <dataarea name="quik" size="5446">
+ <rom name="44 harp (the olympians).vgz" size="5446" crc="fc9f949a" sha1="bad188b8d17a42134c78c297f44e9d1c53a3004b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="045" interface="vgm_quik">
+ <feature name="part_id" value="45 evil shaman (the olympians).vgz" />
+ <dataarea name="quik" size="6419">
+ <rom name="45 evil shaman (the olympians).vgz" size="6419" crc="6fba005d" sha1="5718ec6c6f7e66c67a38332ba1e2ea30a3329f81" offset="0" />
+ </dataarea>
+ </part>
+ <part name="046" interface="vgm_quik">
+ <feature name="part_id" value="46 cave i (the frozen cave).vgz" />
+ <dataarea name="quik" size="11771">
+ <rom name="46 cave i (the frozen cave).vgz" size="11771" crc="c4d67f1f" sha1="3b6ed950fcb0b7b952e050e3f46d5a00654f3711" offset="0" />
+ </dataarea>
+ </part>
+ <part name="047" interface="vgm_quik">
+ <feature name="part_id" value="47 cave ii (the frozen cave).vgz" />
+ <dataarea name="quik" size="10946">
+ <rom name="47 cave ii (the frozen cave).vgz" size="10946" crc="beb4c4b4" sha1="0603511965b6b0e32c53ca45a6c59e8e9a144f39" offset="0" />
+ </dataarea>
+ </part>
+ <part name="048" interface="vgm_quik">
+ <feature name="part_id" value="48 ekim (the frozen cave).vgz" />
+ <dataarea name="quik" size="3626">
+ <rom name="48 ekim (the frozen cave).vgz" size="3626" crc="b7565372" sha1="0763d00863b93f0877f783f9d704f3f478d99f55" offset="0" />
+ </dataarea>
+ </part>
+ <part name="049" interface="vgm_quik">
+ <feature name="part_id" value="49 forest (medusa's neck).vgz" />
+ <dataarea name="quik" size="20135">
+ <rom name="49 forest (medusa's neck).vgz" size="20135" crc="d9e925ab" sha1="2ff14628044842fd80dbd150e699792bb9090bfc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="050" interface="vgm_quik">
+ <feature name="part_id" value="50 village (medusa's neck).vgz" />
+ <dataarea name="quik" size="4526">
+ <rom name="50 village (medusa's neck).vgz" size="4526" crc="a808c69c" sha1="14627200743e2d8f354e3a59621e7b29897cf166" offset="0" />
+ </dataarea>
+ </part>
+ <part name="051" interface="vgm_quik">
+ <feature name="part_id" value="51 medusa (medusa's neck).vgz" />
+ <dataarea name="quik" size="5443">
+ <rom name="51 medusa (medusa's neck).vgz" size="5443" crc="68c7bd1f" sha1="f2b46cda5f29ac4e199287c583768496b12bf646" offset="0" />
+ </dataarea>
+ </part>
+ <part name="052" interface="vgm_quik">
+ <feature name="part_id" value="52 underground fortress (the imprisoned wizard).vgz" />
+ <dataarea name="quik" size="8564">
+ <rom name="52 underground fortress (the imprisoned wizard).vgz" size="8564" crc="cf993326" sha1="0a16dceba550f4d498a297b77b933d455d6ed457" offset="0" />
+ </dataarea>
+ </part>
+ <part name="053" interface="vgm_quik">
+ <feature name="part_id" value="53 fire element (the imprisoned wizard).vgz" />
+ <dataarea name="quik" size="3264">
+ <rom name="53 fire element (the imprisoned wizard).vgz" size="3264" crc="e27952f1" sha1="47351080e3356848b7c648114ba592e1a41f987c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="054" interface="vgm_quik">
+ <feature name="part_id" value="54 the cave of life (the fountain of youth).vgz" />
+ <dataarea name="quik" size="6168">
+ <rom name="54 the cave of life (the fountain of youth).vgz" size="6168" crc="56a58cb5" sha1="80bea34fd46ac7a878e9b1690c87b6b5a53d463d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="055" interface="vgm_quik">
+ <feature name="part_id" value="55 pounding heart (the fountain of youth).vgz" />
+ <dataarea name="quik" size="9647">
+ <rom name="55 pounding heart (the fountain of youth).vgz" size="9647" crc="168a2445" sha1="e0230805bd7315ba273e3184e2ed016a48c2bb1a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="056" interface="vgm_quik">
+ <feature name="part_id" value="56 double demons (the fountain of youth).vgz" />
+ <dataarea name="quik" size="8888">
+ <rom name="56 double demons (the fountain of youth).vgz" size="8888" crc="9837e162" sha1="47e91683c3ae814b743806c9c7de4de6b33da52d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="057" interface="vgm_quik">
+ <feature name="part_id" value="57 the king dragon (the fountain of youth).vgz" />
+ <dataarea name="quik" size="21114">
+ <rom name="57 the king dragon (the fountain of youth).vgz" size="21114" crc="27ff93ea" sha1="4ccdb2d51dc3bbc45f30800cfde333362a27b985" offset="0" />
+ </dataarea>
+ </part>
+ <part name="058" interface="vgm_quik">
+ <feature name="part_id" value="58 ending i (the fountain of youth).vgz" />
+ <dataarea name="quik" size="3180">
+ <rom name="58 ending i (the fountain of youth).vgz" size="3180" crc="bb829583" sha1="624f73af0c6e91ccd8e9fa6badc4317c72b83f81" offset="0" />
+ </dataarea>
+ </part>
+ <part name="059" interface="vgm_quik">
+ <feature name="part_id" value="59 ending ii (the fountain of youth).vgz" />
+ <dataarea name="quik" size="16770">
+ <rom name="59 ending ii (the fountain of youth).vgz" size="16770" crc="d00fa1bc" sha1="12761926a949ea1dbafcea835cac1881fe7751ec" offset="0" />
+ </dataarea>
+ </part>
+ <part name="060" interface="vgm_quik">
+ <feature name="part_id" value="60 scenario clear.vgz" />
+ <dataarea name="quik" size="852">
+ <rom name="60 scenario clear.vgz" size="852" crc="e0120c3b" sha1="14833c24db19cb7bd624f214abfaafbd158a07c0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="061" interface="vgm_quik">
+ <feature name="part_id" value="61 destroy.vgz" />
+ <dataarea name="quik" size="3345">
+ <rom name="61 destroy.vgz" size="3345" crc="36f545d9" sha1="f47aa8743ae09858dea909a26d84f9d5c8c90c03" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="sorcer_msx2">
+ <description>Sorcerian (MSX2, PSG)</description>
+ <year>1991</year>
+ <publisher>Falcom</publisher>
+ <info name="cores" value="PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 opening.vgz" />
+ <dataarea name="quik" size="8641">
+ <rom name="01 opening.vgz" size="8641" crc="ab51b25d" sha1="b499f339d21d4eaa320e732a159425ff916e4b7d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 castle [let's meet here].vgz" />
+ <dataarea name="quik" size="7583">
+ <rom name="02 castle [let's meet here].vgz" size="7583" crc="884da6d2" sha1="60e3524efaa43dbf57d8ff0154bed76d116fb34e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 town [pentawa i].vgz" />
+ <dataarea name="quik" size="7960">
+ <rom name="03 town [pentawa i].vgz" size="7960" crc="e5faa0f1" sha1="8635903e465c3f5a1de84a89b7aa304f9f5157ed" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 town [pentawa ii].vgz" />
+ <dataarea name="quik" size="14510">
+ <rom name="04 town [pentawa ii].vgz" size="14510" crc="ccc9b9fe" sha1="69a0ea6e2851fa79399c4b0917db3973ace73b85" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 dungeon (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="19767">
+ <rom name="05 dungeon (disappearance of the king's scepter).vgz" size="19767" crc="89389fc9" sha1="68fdbd34198969b38edf6707c40e4a63acfc5048" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 hydra (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="5926">
+ <rom name="06 hydra (disappearance of the king's scepter).vgz" size="5926" crc="5a689f93" sha1="47e3afab50ff6cfdf1f9891fb87bf4b0d97b4478" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 survivor (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="4902">
+ <rom name="07 survivor (disappearance of the king's scepter).vgz" size="4902" crc="2cc7b452" sha1="46b7c01defc4e9ccd55624f75112f1bd047eda5e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 travelers inn (disappearance of the king's scepter).vgz" />
+ <dataarea name="quik" size="4486">
+ <rom name="08 travelers inn (disappearance of the king's scepter).vgz" size="4486" crc="bc9a683d" sha1="d63ee2b7964ece1a7bd53f21037575504948689e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 forest (the lost talisman).vgz" />
+ <dataarea name="quik" size="7048">
+ <rom name="09 forest (the lost talisman).vgz" size="7048" crc="304f2946" sha1="234dd6a737bb160bc1286797742abf7b7f7831bd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 underground dungeon (the lost talisman).vgz" />
+ <dataarea name="quik" size="4318">
+ <rom name="10 underground dungeon (the lost talisman).vgz" size="4318" crc="35a48597" sha1="ac6f06a7da05885affefa2ecd8bdd9f78a728aca" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 priest dehytel (the lost talisman).vgz" />
+ <dataarea name="quik" size="3162">
+ <rom name="11 priest dehytel (the lost talisman).vgz" size="3162" crc="9b40ca9b" sha1="1ec9ab40a4d028da80bebf87d2f3320cbe397c9c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 sand marivoux (the lost talisman).vgz" />
+ <dataarea name="quik" size="2847">
+ <rom name="12 sand marivoux (the lost talisman).vgz" size="2847" crc="d2cb4b98" sha1="951cfa8597dfb2189b9227f3992585142a5004ac" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 underground dungeon (lucifer's water gate).vgz" />
+ <dataarea name="quik" size="13075">
+ <rom name="13 underground dungeon (lucifer's water gate).vgz" size="13075" crc="f1ff1866" sha1="e750294fd8c8545ee79b4dec602fbd252d6fd7bb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 kraken (lucifer's water gate).vgz" />
+ <dataarea name="quik" size="7285">
+ <rom name="14 kraken (lucifer's water gate).vgz" size="7285" crc="19575f19" sha1="b0a8feb844478f2888e08c11e516de66382531ae" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 bloody river (lucifer's water gate).vgz" />
+ <dataarea name="quik" size="6220">
+ <rom name="15 bloody river (lucifer's water gate).vgz" size="6220" crc="dc75026a" sha1="56af8e3865138298bdbe398171e56be6f013bbbe" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 desert (cursed oasis).vgz" />
+ <dataarea name="quik" size="7379">
+ <rom name="16 desert (cursed oasis).vgz" size="7379" crc="c052c1ed" sha1="9b01c186496ccdfc3165b29e29a6080b8df25e2a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 sand castle (cursed oasis).vgz" />
+ <dataarea name="quik" size="8207">
+ <rom name="17 sand castle (cursed oasis).vgz" size="8207" crc="fc55f6df" sha1="93a330717ecc98ae76e86ee5894f1ac4a416a8f0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 ruwan and the gold dragon (cursed oasis).vgz" />
+ <dataarea name="quik" size="8809">
+ <rom name="18 ruwan and the gold dragon (cursed oasis).vgz" size="8809" crc="ff9d9e34" sha1="c5f1e16d4e0f67b357e177b82b20ad63084bd36b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 tower (thieves tower).vgz" />
+ <dataarea name="quik" size="9029">
+ <rom name="19 tower (thieves tower).vgz" size="9029" crc="4fa8aabc" sha1="c690eac6ca29b53de07c4583e38572e5f9cacf55" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 depths of the earth (thieves tower).vgz" />
+ <dataarea name="quik" size="6875">
+ <rom name="20 depths of the earth (thieves tower).vgz" size="6875" crc="d9ee4331" sha1="925f738e758a4352d45088d3a075f0084df71eeb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 rooftop (thieves tower).vgz" />
+ <dataarea name="quik" size="3866">
+ <rom name="21 rooftop (thieves tower).vgz" size="3866" crc="c5c4ae86" sha1="822c1d24d9a67f03fc8b97c5233d1b426a08aaea" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 major demon (thieves tower).vgz" />
+ <dataarea name="quik" size="3386">
+ <rom name="22 major demon (thieves tower).vgz" size="3386" crc="61955f53" sha1="7f1b4832e7a7d2442a5ef031dc7572ad8e9a22bf" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 shadow dragon (thieves tower).vgz" />
+ <dataarea name="quik" size="2135">
+ <rom name="23 shadow dragon (thieves tower).vgz" size="2135" crc="79393343" sha1="9e87f6d4fa84310e8fee2391b5269409c87893d4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 seal (thieves tower).vgz" />
+ <dataarea name="quik" size="9562">
+ <rom name="24 seal (thieves tower).vgz" size="9562" crc="d0c8bea1" sha1="44b32d26adc98c4df1fdf6044d8c63a3f67fec87" offset="0" />
+ </dataarea>
+ </part>
+ <part name="025" interface="vgm_quik">
+ <feature name="part_id" value="25 dark swamp (the wizard in the dark swamp).vgz" />
+ <dataarea name="quik" size="5970">
+ <rom name="25 dark swamp (the wizard in the dark swamp).vgz" size="5970" crc="066c2091" sha1="9d4ca9267e87f7c405abcfcf394d76c6ef72f956" offset="0" />
+ </dataarea>
+ </part>
+ <part name="026" interface="vgm_quik">
+ <feature name="part_id" value="26 red dragon (the wizard in the dark swamp).vgz" />
+ <dataarea name="quik" size="6038">
+ <rom name="26 red dragon (the wizard in the dark swamp).vgz" size="6038" crc="d995f3ad" sha1="57034056e2804fef5d63d268f3b2c5df9452d04c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="027" interface="vgm_quik">
+ <feature name="part_id" value="27 romancia kingdom (romancia).vgz" />
+ <dataarea name="quik" size="3997">
+ <rom name="27 romancia kingdom (romancia).vgz" size="3997" crc="30e5c1f4" sha1="e731c1a896eb161143ed9f7e6721335ecf775ae0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="028" interface="vgm_quik">
+ <feature name="part_id" value="28 romancia castle (romancia).vgz" />
+ <dataarea name="quik" size="3344">
+ <rom name="28 romancia castle (romancia).vgz" size="3344" crc="fd5e2630" sha1="24b902b9005fed91bb60488258422ce3422f3f82" offset="0" />
+ </dataarea>
+ </part>
+ <part name="029" interface="vgm_quik">
+ <feature name="part_id" value="29 azorba kingdom (romancia).vgz" />
+ <dataarea name="quik" size="4737">
+ <rom name="29 azorba kingdom (romancia).vgz" size="4737" crc="dc4eaa35" sha1="c9877d063bebab59a273cc4dcb3d152944dfcdc8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="030" interface="vgm_quik">
+ <feature name="part_id" value="30 vaides (romancia).vgz" />
+ <dataarea name="quik" size="2379">
+ <rom name="30 vaides (romancia).vgz" size="2379" crc="fabfea31" sha1="4256299a2d9897a9f546e18aea5079f5053600b8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="031" interface="vgm_quik">
+ <feature name="part_id" value="31 forest (riddle of the red coin).vgz" />
+ <dataarea name="quik" size="13042">
+ <rom name="31 forest (riddle of the red coin).vgz" size="13042" crc="7a2f81b6" sha1="ffe2921faca24cfec25803447b555c581ffd6483" offset="0" />
+ </dataarea>
+ </part>
+ <part name="032" interface="vgm_quik">
+ <feature name="part_id" value="32 moss giant (riddle of the red coin).vgz" />
+ <dataarea name="quik" size="10928">
+ <rom name="32 moss giant (riddle of the red coin).vgz" size="10928" crc="2cdf0883" sha1="103483bbc484a31d45d0e46c018a210c64894612" offset="0" />
+ </dataarea>
+ </part>
+ <part name="033" interface="vgm_quik">
+ <feature name="part_id" value="33 peaceful forest (riddle of the red coin).vgz" />
+ <dataarea name="quik" size="4736">
+ <rom name="33 peaceful forest (riddle of the red coin).vgz" size="4736" crc="ca1cd170" sha1="6092000764331f4b1fce8e99d05952ddde478312" offset="0" />
+ </dataarea>
+ </part>
+ <part name="034" interface="vgm_quik">
+ <feature name="part_id" value="34 dungeon i (the black wizard).vgz" />
+ <dataarea name="quik" size="7380">
+ <rom name="34 dungeon i (the black wizard).vgz" size="7380" crc="858d2756" sha1="b99eaab1775193942fbcc395fcc1d3c7e8b8d9bd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="035" interface="vgm_quik">
+ <feature name="part_id" value="35 dungeon ii (the black wizard).vgz" />
+ <dataarea name="quik" size="4100">
+ <rom name="35 dungeon ii (the black wizard).vgz" size="4100" crc="29349713" sha1="df4fb50e3fb5d311abb104bdc1deb09e84708133" offset="0" />
+ </dataarea>
+ </part>
+ <part name="036" interface="vgm_quik">
+ <feature name="part_id" value="36 ghedis (the black wizard).vgz" />
+ <dataarea name="quik" size="4451">
+ <rom name="36 ghedis (the black wizard).vgz" size="4451" crc="4c2f7779" sha1="0ec9abc525a033cb979ad55fdbd4e9eb4896a7fd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="037" interface="vgm_quik">
+ <feature name="part_id" value="37 blue dragon (the black wizard).vgz" />
+ <dataarea name="quik" size="5261">
+ <rom name="37 blue dragon (the black wizard).vgz" size="5261" crc="00474aa2" sha1="e96efe1253afbca26058b37e490ebb225252b99f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="038" interface="vgm_quik">
+ <feature name="part_id" value="38 aboard ship (cursed queen mary).vgz" />
+ <dataarea name="quik" size="9642">
+ <rom name="38 aboard ship (cursed queen mary).vgz" size="9642" crc="ba7865ca" sha1="a5a3acf7fc55f910f5f83d7c71399f7c0dd7dd0c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="039" interface="vgm_quik">
+ <feature name="part_id" value="39 after disembarking (cursed queen mary).vgz" />
+ <dataarea name="quik" size="18080">
+ <rom name="39 after disembarking (cursed queen mary).vgz" size="18080" crc="19c3cb19" sha1="834da51ea44bb956db014fef4931e5ce26b6f2db" offset="0" />
+ </dataarea>
+ </part>
+ <part name="040" interface="vgm_quik">
+ <feature name="part_id" value="40 arch demon (cursed queen mary).vgz" />
+ <dataarea name="quik" size="3927">
+ <rom name="40 arch demon (cursed queen mary).vgz" size="3927" crc="587232cf" sha1="e4f28701fe4e57fd54fd28585a818f877297dc4b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="041" interface="vgm_quik">
+ <feature name="part_id" value="41 village (the olympians).vgz" />
+ <dataarea name="quik" size="5409">
+ <rom name="41 village (the olympians).vgz" size="5409" crc="0de3ea50" sha1="d2397ec643361aedacc21b0d9762d0c38659617b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="042" interface="vgm_quik">
+ <feature name="part_id" value="42 combat scene (the olympians).vgz" />
+ <dataarea name="quik" size="7660">
+ <rom name="42 combat scene (the olympians).vgz" size="7660" crc="6f0b9edb" sha1="45f7fb16a035c35d3ced16bc07739b3d35d47c1a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="043" interface="vgm_quik">
+ <feature name="part_id" value="43 the heavens (the olympians).vgz" />
+ <dataarea name="quik" size="10367">
+ <rom name="43 the heavens (the olympians).vgz" size="10367" crc="ebc92de6" sha1="3198c233bbd3db934063e5dde0162f6ac71ba3c3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="044" interface="vgm_quik">
+ <feature name="part_id" value="44 harp (the olympians).vgz" />
+ <dataarea name="quik" size="3586">
+ <rom name="44 harp (the olympians).vgz" size="3586" crc="03cdb06e" sha1="02bf9bb4b5faff6c375f5628bb19ecf7c6165ddb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="045" interface="vgm_quik">
+ <feature name="part_id" value="45 evil shaman (the olympians).vgz" />
+ <dataarea name="quik" size="4056">
+ <rom name="45 evil shaman (the olympians).vgz" size="4056" crc="5411e411" sha1="f089a5cac46856122bd4b8223758a51eb30c4c15" offset="0" />
+ </dataarea>
+ </part>
+ <part name="046" interface="vgm_quik">
+ <feature name="part_id" value="46 cave i (the frozen cave).vgz" />
+ <dataarea name="quik" size="10528">
+ <rom name="46 cave i (the frozen cave).vgz" size="10528" crc="760958d1" sha1="831ad1a1d70099b61352174f2397b39872bb7d3b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="047" interface="vgm_quik">
+ <feature name="part_id" value="47 cave ii (the frozen cave).vgz" />
+ <dataarea name="quik" size="10076">
+ <rom name="47 cave ii (the frozen cave).vgz" size="10076" crc="0e12d237" sha1="a240efc8c60a416b861db009857612c3b735b908" offset="0" />
+ </dataarea>
+ </part>
+ <part name="048" interface="vgm_quik">
+ <feature name="part_id" value="48 ekim (the frozen cave).vgz" />
+ <dataarea name="quik" size="6200">
+ <rom name="48 ekim (the frozen cave).vgz" size="6200" crc="5de15bcf" sha1="86375610daadcbfdd7fa2ac5ef91ab6980a3ca70" offset="0" />
+ </dataarea>
+ </part>
+ <part name="049" interface="vgm_quik">
+ <feature name="part_id" value="49 forest (medusa's neck).vgz" />
+ <dataarea name="quik" size="17145">
+ <rom name="49 forest (medusa's neck).vgz" size="17145" crc="338d3f7f" sha1="d3ad468c2e69daf634b20e3bb441cb7792a2a29e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="050" interface="vgm_quik">
+ <feature name="part_id" value="50 village (medusa's neck).vgz" />
+ <dataarea name="quik" size="9932">
+ <rom name="50 village (medusa's neck).vgz" size="9932" crc="51d19196" sha1="1c4e4255cbff240efa3250d3b0a6624457b90830" offset="0" />
+ </dataarea>
+ </part>
+ <part name="051" interface="vgm_quik">
+ <feature name="part_id" value="51 medusa (medusa's neck).vgz" />
+ <dataarea name="quik" size="3204">
+ <rom name="51 medusa (medusa's neck).vgz" size="3204" crc="9fdcafc6" sha1="c57f0ec9cf5a64493c3c09f16e0ca1745dff7d61" offset="0" />
+ </dataarea>
+ </part>
+ <part name="052" interface="vgm_quik">
+ <feature name="part_id" value="52 underground fortress (the imprisoned wizard).vgz" />
+ <dataarea name="quik" size="6736">
+ <rom name="52 underground fortress (the imprisoned wizard).vgz" size="6736" crc="f3d12d6c" sha1="44fc3c0eb8cb9eae769c14ff9fda831c64d6a289" offset="0" />
+ </dataarea>
+ </part>
+ <part name="053" interface="vgm_quik">
+ <feature name="part_id" value="53 fire element (the imprisoned wizard).vgz" />
+ <dataarea name="quik" size="2528">
+ <rom name="53 fire element (the imprisoned wizard).vgz" size="2528" crc="839b6eca" sha1="5e643baf48b87b7daaef2a276c5329330944a49d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="054" interface="vgm_quik">
+ <feature name="part_id" value="54 the cave of life (the fountain of youth).vgz" />
+ <dataarea name="quik" size="5372">
+ <rom name="54 the cave of life (the fountain of youth).vgz" size="5372" crc="200aa285" sha1="4ab8015f44caeac1672e61618b7c95ea0d03754b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="055" interface="vgm_quik">
+ <feature name="part_id" value="55 pounding heart (the fountain of youth).vgz" />
+ <dataarea name="quik" size="7617">
+ <rom name="55 pounding heart (the fountain of youth).vgz" size="7617" crc="3369a165" sha1="434fc075391c06b8135205e57585990fd74be216" offset="0" />
+ </dataarea>
+ </part>
+ <part name="056" interface="vgm_quik">
+ <feature name="part_id" value="56 double demons (the fountain of youth).vgz" />
+ <dataarea name="quik" size="5523">
+ <rom name="56 double demons (the fountain of youth).vgz" size="5523" crc="0082190a" sha1="6d832a55560afeaec98589a67465477723f667ed" offset="0" />
+ </dataarea>
+ </part>
+ <part name="057" interface="vgm_quik">
+ <feature name="part_id" value="57 the king dragon (the fountain of youth).vgz" />
+ <dataarea name="quik" size="13678">
+ <rom name="57 the king dragon (the fountain of youth).vgz" size="13678" crc="2baf3aa9" sha1="5d5423b98630beb3c72f88a0282488ece3531993" offset="0" />
+ </dataarea>
+ </part>
+ <part name="058" interface="vgm_quik">
+ <feature name="part_id" value="58 ending i (the fountain of youth).vgz" />
+ <dataarea name="quik" size="9056">
+ <rom name="58 ending i (the fountain of youth).vgz" size="9056" crc="b844186f" sha1="de73556ead1e74182368b5c0ce8760b0da3d4ac1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="059" interface="vgm_quik">
+ <feature name="part_id" value="59 ending ii (the fountain of youth).vgz" />
+ <dataarea name="quik" size="13894">
+ <rom name="59 ending ii (the fountain of youth).vgz" size="13894" crc="82978591" sha1="91d8a9cb4142a89dae60907b3d9ffa66e14a256b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="060" interface="vgm_quik">
+ <feature name="part_id" value="60 scenario clear.vgz" />
+ <dataarea name="quik" size="1231">
+ <rom name="60 scenario clear.vgz" size="1231" crc="7d7517d2" sha1="77c9ac9536feb1fd1f4e10b036380af255b0eed1" offset="0" />
+ </dataarea>
+ </part>
+ <part name="061" interface="vgm_quik">
+ <feature name="part_id" value="61 destroy.vgz" />
+ <dataarea name="quik" size="2707">
+ <rom name="61 destroy.vgz" size="2707" crc="ea91f288" sha1="77a999cd80c74264d019063ce8f98acd950552bd" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="cheeta2_nes">
+ <description>The Cheetahmen II (NES)</description>
+ <year>1992</year>
+ <publisher>Active Enterprises</publisher>
+ <info name="cores" value="NES APU (N2A03)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 title screen.vgz" />
+ <dataarea name="quik" size="1725">
+ <rom name="01 title screen.vgz" size="1725" crc="36f5e52d" sha1="8ebd3d59cc7209eb22ad27cb4edacc9f156aa4bd" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 main theme.vgz" />
+ <dataarea name="quik" size="6555">
+ <rom name="02 main theme.vgz" size="6555" crc="f31408ee" sha1="6b0f7a8a3735fea539a3e9baa9ccda21bfaee720" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 death.vgz" />
+ <dataarea name="quik" size="393">
+ <rom name="03 death.vgz" size="393" crc="2863d682" sha1="e2a1548583a81492569828e16a7137b072744de2" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="gekipenn_scc">
+ <description>The Pro Baseball Clash Pennant Race (MSX2, SCC)</description>
+ <year>1988</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="SCC (K051649), PSG (AY-3-8910)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 opening.vgz" />
+ <dataarea name="quik" size="19427">
+ <rom name="01 opening.vgz" size="19427" crc="c69a6c31" sha1="d77de908ae4e3122c72526807eff781ebe7c40c0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 play start.vgz" />
+ <dataarea name="quik" size="7433">
+ <rom name="02 play start.vgz" size="7433" crc="e3396766" sha1="f9968a9b4af62a99d589e5f08b102be6072c65dc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 selection bgm.vgz" />
+ <dataarea name="quik" size="4093">
+ <rom name="03 selection bgm.vgz" size="4093" crc="20ebd83a" sha1="c760a0fa996b561564fdf9d6aef2466db619785f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 game bgm 1.vgz" />
+ <dataarea name="quik" size="3744">
+ <rom name="04 game bgm 1.vgz" size="3744" crc="a3ea47df" sha1="5f0555b9e7af5d197f7a3b71f663e8a0ea150c0b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 game bgm 2.vgz" />
+ <dataarea name="quik" size="3503">
+ <rom name="05 game bgm 2.vgz" size="3503" crc="f995aa13" sha1="1784aeecde70ae5f723526fb09514b29c53ac29e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 game bgm 3.vgz" />
+ <dataarea name="quik" size="2934">
+ <rom name="06 game bgm 3.vgz" size="2934" crc="201e4763" sha1="af9507c12c2ba8a4f7d94fa98913a3ba91b62306" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 game bgm 4.vgz" />
+ <dataarea name="quik" size="3993">
+ <rom name="07 game bgm 4.vgz" size="3993" crc="aa7fe34d" sha1="e4edd1d4b66204df616ba740f3547da23e98e8f6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 game bgm 5.vgz" />
+ <dataarea name="quik" size="3120">
+ <rom name="08 game bgm 5.vgz" size="3120" crc="211bee56" sha1="c572cafbec3b70e7a38722a1d75530c3aa32fa26" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 game bgm 6.vgz" />
+ <dataarea name="quik" size="3441">
+ <rom name="09 game bgm 6.vgz" size="3441" crc="83dd6a28" sha1="280c4c5c8a59aff14bac84794bd9067e1c6c2417" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 game bgm 7.vgz" />
+ <dataarea name="quik" size="3876">
+ <rom name="10 game bgm 7.vgz" size="3876" crc="c855cfab" sha1="1eae71be97d1cc467dd8ec44975fd6966300a5a5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 game bgm 8.vgz" />
+ <dataarea name="quik" size="3677">
+ <rom name="11 game bgm 8.vgz" size="3677" crc="c6a57e12" sha1="b5275942b1e6c071c15eaac5372f32b110b1fdf9" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 base reached bgm 1.vgz" />
+ <dataarea name="quik" size="2291">
+ <rom name="12 base reached bgm 1.vgz" size="2291" crc="1588963b" sha1="e50f90d19b4aac6ab595dbdfced867c6de613942" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 base reached bgm 2.vgz" />
+ <dataarea name="quik" size="3057">
+ <rom name="13 base reached bgm 2.vgz" size="3057" crc="1a2ac6c6" sha1="1c93b2b2c79b5772677434fecae5dce5da78fa67" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 base stolen bgm 1.vgz" />
+ <dataarea name="quik" size="2118">
+ <rom name="14 base stolen bgm 1.vgz" size="2118" crc="d12b6942" sha1="2b53dc3b50ecfa6b62fe032c726b977d6a558209" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 base stolen bgm 2.vgz" />
+ <dataarea name="quik" size="2129">
+ <rom name="15 base stolen bgm 2.vgz" size="2129" crc="329b1a47" sha1="7b80fa089a547a1d171395677de79dafb39a6e92" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 base stolen bgm 3.vgz" />
+ <dataarea name="quik" size="2007">
+ <rom name="16 base stolen bgm 3.vgz" size="2007" crc="aac7a533" sha1="ac6358089aec8f5d864383223d43d01eb8344a11" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 base stolen bgm 4.vgz" />
+ <dataarea name="quik" size="1912">
+ <rom name="17 base stolen bgm 4.vgz" size="1912" crc="45271da2" sha1="515e0b9ba2d1a2e117ec98d289b54f1923b3fbec" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 base stolen bgm 5.vgz" />
+ <dataarea name="quik" size="1938">
+ <rom name="18 base stolen bgm 5.vgz" size="1938" crc="495ec2eb" sha1="884bc2fcdf0daf279e2c4da506761bbe04e6ef31" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 home run bgm.vgz" />
+ <dataarea name="quik" size="1145">
+ <rom name="19 home run bgm.vgz" size="1145" crc="e250da0c" sha1="afcf0e22607a20642386812ab5526fd8bb467209" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 game set bgm.vgz" />
+ <dataarea name="quik" size="3190">
+ <rom name="20 game set bgm.vgz" size="3190" crc="f4602748" sha1="7420ad1a57f554d8665ebc0bcffbc07fd65be9fe" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 team switch bgm 1.vgz" />
+ <dataarea name="quik" size="1481">
+ <rom name="21 team switch bgm 1.vgz" size="1481" crc="813dcb35" sha1="977368110f521edbab9f6b892a4861dfce8b9f7d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 team switch bgm 2.vgz" />
+ <dataarea name="quik" size="1859">
+ <rom name="22 team switch bgm 2.vgz" size="1859" crc="ee4e3a00" sha1="9b94b9834daaa54ab9a7481fbd2be7220154e1d4" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 ending.vgz" />
+ <dataarea name="quik" size="9723">
+ <rom name="23 ending.vgz" size="9723" crc="d59425c0" sha1="046ab0444b97e8eb39d28c4f1b266c1a90bef557" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="ttoonadv_nes">
+ <description>Tiny Toon Adventures (NES)</description>
+ <year>1991</year>
+ <publisher>Konami</publisher>
+ <info name="cores" value="NES APU (N2A03)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 opening (theme song).vgz" />
+ <dataarea name="quik" size="7110">
+ <rom name="01 opening (theme song).vgz" size="7110" crc="0ff66890" sha1="dfd27f8e70a8ea6b58018c2107f0987b69845f1d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 map screen &amp; partner select.vgz" />
+ <dataarea name="quik" size="3505">
+ <rom name="02 map screen &amp; partner select.vgz" size="3505" crc="cbd58c10" sha1="547bb147c0baa0f20b783484515980240642eb18" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 map screen &amp; partner select (no intro).vgz" />
+ <dataarea name="quik" size="2894">
+ <rom name="03 map screen &amp; partner select (no intro).vgz" size="2894" crc="d097ba30" sha1="5ce367f9b17cd2ea7921ba81450a59399598fe38" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 acme acres.vgz" />
+ <dataarea name="quik" size="5148">
+ <rom name="04 acme acres.vgz" size="5148" crc="9a58d7dd" sha1="477271c99ae6dafc3abf15cc4140d4c68d6d290a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 hamton (extra room).vgz" />
+ <dataarea name="quik" size="3399">
+ <rom name="05 hamton (extra room).vgz" size="3399" crc="eb39f538" sha1="1161e7b4e7622912d3e5a30f4e026a35a88552df" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 gene splicer castle &amp; wolverine cave.vgz" />
+ <dataarea name="quik" size="6103">
+ <rom name="06 gene splicer castle &amp; wolverine cave.vgz" size="6103" crc="d804080b" sha1="1be94d133bcda6dfe7943b894e530ee411b6b835" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 undersea.vgz" />
+ <dataarea name="quik" size="3778">
+ <rom name="07 undersea.vgz" size="3778" crc="3938480a" sha1="7ebdf855e83b803585705a0b6e10b20faba4e2eb" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 elmyra! (room).vgz" />
+ <dataarea name="quik" size="5614">
+ <rom name="08 elmyra (room).vgz" size="5614" crc="361d5cdf" sha1="bc12f422ce46e411049a89afb4ae0a31964598c8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 pirate ship &amp; garbage car tires.vgz" />
+ <dataarea name="quik" size="4683">
+ <rom name="09 pirate ship &amp; garbage car tires.vgz" size="4683" crc="162b13fd" sha1="26a51c831c3eadfdc65e8de3cc4ebdacd4320825" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 haunted forest.vgz" />
+ <dataarea name="quik" size="4293">
+ <rom name="10 haunted forest.vgz" size="4293" crc="00f9d4f2" sha1="c55f1a52372ad201e17c7cca723b6f11138fba7c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 boss battle.vgz" />
+ <dataarea name="quik" size="3559">
+ <rom name="11 boss battle.vgz" size="3559" crc="300b1dd9" sha1="3e3a574ca8eb95d61fef33e34e460e2306e1cc06" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 wackyland.vgz" />
+ <dataarea name="quik" size="5885">
+ <rom name="12 wackyland.vgz" size="5885" crc="e042854a" sha1="d3a9c98f560211c399b247b0c720c3c3a6a34719" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 monty's mansion.vgz" />
+ <dataarea name="quik" size="4943">
+ <rom name="13 monty's mansion.vgz" size="4943" crc="424bfa66" sha1="8723547bbf7cb41ce4672246929474cb78f8acd8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 monty (final boss).vgz" />
+ <dataarea name="quik" size="3498">
+ <rom name="14 monty (final boss).vgz" size="3498" crc="0ee229fa" sha1="a8a45a204eef443749acc9b76e6ef7a6aca247f3" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 caught.vgz" />
+ <dataarea name="quik" size="2772">
+ <rom name="15 caught.vgz" size="2772" crc="48029292" sha1="15a33e6906b89e207c6989683d0210fafeceb8ee" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 death (lost life).vgz" />
+ <dataarea name="quik" size="1302">
+ <rom name="16 death (lost life).vgz" size="1302" crc="19aaeeb1" sha1="b94c354cc023095c5b930336feddc0a1fe127740" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 something happened (game over).vgz" />
+ <dataarea name="quik" size="2362">
+ <rom name="17 something happened (game over).vgz" size="2362" crc="3631f561" sha1="76c7fa323fc8f55a416cac4861a4d189dd525625" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 area clear.vgz" />
+ <dataarea name="quik" size="2918">
+ <rom name="18 area clear.vgz" size="2918" crc="b899b370" sha1="37e419902820b78d54c650498af83c2b530fdb79" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 boss defeated &amp; key collected.vgz" />
+ <dataarea name="quik" size="2266">
+ <rom name="19 boss defeated &amp; key collected.vgz" size="2266" crc="0ee7dbb9" sha1="8335dbdbf2d952dfaf5f1d9ea6bf36f80fa4bcb7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 stage clear.vgz" />
+ <dataarea name="quik" size="2625">
+ <rom name="20 stage clear.vgz" size="2625" crc="28544187" sha1="95ce54e0c3b2fce37ccdb651288aa741cd3e89e7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 you win (babs has rescued).vgz" />
+ <dataarea name="quik" size="5701">
+ <rom name="21 you win (babs has rescued).vgz" size="5701" crc="0989c7ba" sha1="ed76f05c5d45c770f801a4567121084df0f25d1e" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 ending &amp; credit roll (theme song).vgz" />
+ <dataarea name="quik" size="9809">
+ <rom name="22 ending &amp; credit roll (theme song).vgz" size="9809" crc="3f990511" sha1="18cf657e15b1e8c0a9f8df6464abd68489a157bc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 concord condor (nope. nope.).vgz" />
+ <dataarea name="quik" size="1187">
+ <rom name="23 concord condor (nope. nope.).vgz" size="1187" crc="6cef91a8" sha1="38816526eb0ba16441e35c3fe3e68e123c6ebddd" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="touhou5_98">
+ <description>Touhou Kaikidan ~ Mystic Square. (NEC PC-9801)</description>
+ <year>1998</year>
+ <publisher>Amusement Makers</publisher>
+ <info name="cores" value="NEC PC-9801-86 (YM2608)"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="01 team shangai alice.vgz" />
+ <dataarea name="quik" size="2033">
+ <rom name="01 team shangai alice.vgz" size="2033" crc="9e2e75e4" sha1="6b9be8f42ebc4869546f345ef54ee89c260750ea" offset="0" />
+ </dataarea>
+ </part>
+ <part name="002" interface="vgm_quik">
+ <feature name="part_id" value="02 bizarre romantic story ~ mystic square.vgz" />
+ <dataarea name="quik" size="14574">
+ <rom name="02 bizarre romantic story ~ mystic square.vgz" size="14574" crc="7528b1dc" sha1="4d4f1c9868432d0cd3c050f899f02a9f8a84b591" offset="0" />
+ </dataarea>
+ </part>
+ <part name="003" interface="vgm_quik">
+ <feature name="part_id" value="03 dream express.vgz" />
+ <dataarea name="quik" size="23990">
+ <rom name="03 dream express.vgz" size="23990" crc="cbf7c554" sha1="7bd96089982565029cd721db993e4bb53d69242a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="004" interface="vgm_quik">
+ <feature name="part_id" value="04 magic square.vgz" />
+ <dataarea name="quik" size="16393">
+ <rom name="04 magic square.vgz" size="16393" crc="cee2b2cc" sha1="dc828c8f708c7b7a17225b53e1552fee35d58916" offset="0" />
+ </dataarea>
+ </part>
+ <part name="005" interface="vgm_quik">
+ <feature name="part_id" value="05 dimension of reverie.vgz" />
+ <dataarea name="quik" size="14698">
+ <rom name="05 dimension of reverie.vgz" size="14698" crc="8b0d5428" sha1="789ec529151709a8654f909b0fbc61b074a6b764" offset="0" />
+ </dataarea>
+ </part>
+ <part name="006" interface="vgm_quik">
+ <feature name="part_id" value="06 spiritual heaven.vgz" />
+ <dataarea name="quik" size="16149">
+ <rom name="06 spiritual heaven.vgz" size="16149" crc="c430d21e" sha1="366f09665510ed2196b909db90ff7ad29a59b33b" offset="0" />
+ </dataarea>
+ </part>
+ <part name="007" interface="vgm_quik">
+ <feature name="part_id" value="07 romantic children.vgz" />
+ <dataarea name="quik" size="24002">
+ <rom name="07 romantic children.vgz" size="24002" crc="6a647d62" sha1="7174f41970daaf48a9768a5113ace48582465758" offset="0" />
+ </dataarea>
+ </part>
+ <part name="008" interface="vgm_quik">
+ <feature name="part_id" value="08 plastic mind.vgz" />
+ <dataarea name="quik" size="17467">
+ <rom name="08 plastic mind.vgz" size="17467" crc="3538336d" sha1="0ff6cdc8c86e8b809bd87558684a2f895423d418" offset="0" />
+ </dataarea>
+ </part>
+ <part name="009" interface="vgm_quik">
+ <feature name="part_id" value="09 maple wise.vgz" />
+ <dataarea name="quik" size="20249">
+ <rom name="09 maple wise.vgz" size="20249" crc="2b3dd7f6" sha1="097cfcfb9845253f122a74e14fbd3c0e71646f6a" offset="0" />
+ </dataarea>
+ </part>
+ <part name="010" interface="vgm_quik">
+ <feature name="part_id" value="10 forbidden magic.vgz" />
+ <dataarea name="quik" size="22784">
+ <rom name="10 forbidden magic.vgz" size="22784" crc="236fbdc5" sha1="6036b3ac08b5c3506ada1c4a6143fdd9b34aedc0" offset="0" />
+ </dataarea>
+ </part>
+ <part name="011" interface="vgm_quik">
+ <feature name="part_id" value="11 crimson maiden ~ crimson dead!!.vgz" />
+ <dataarea name="quik" size="15152">
+ <rom name="11 crimson maiden ~ crimson dead.vgz" size="15152" crc="e2d69193" sha1="6c6497a3e551f62f34ed8df03b08f40bd02e8a73" offset="0" />
+ </dataarea>
+ </part>
+ <part name="012" interface="vgm_quik">
+ <feature name="part_id" value="12 treacherous maiden ~ judas kiss.vgz" />
+ <dataarea name="quik" size="12899">
+ <rom name="12 treacherous maiden ~ judas kiss.vgz" size="12899" crc="656ca5f2" sha1="7dae6c5c36e437edab7b39beaf9d52d4b1d575e8" offset="0" />
+ </dataarea>
+ </part>
+ <part name="013" interface="vgm_quik">
+ <feature name="part_id" value="13 the last judgement.vgz" />
+ <dataarea name="quik" size="19539">
+ <rom name="13 the last judgement.vgz" size="19539" crc="09535c68" sha1="b4b54a70e6abf8dd0606f60f1c5d15a7ade94416" offset="0" />
+ </dataarea>
+ </part>
+ <part name="014" interface="vgm_quik">
+ <feature name="part_id" value="14 doll of misery.vgz" />
+ <dataarea name="quik" size="15918">
+ <rom name="14 doll of misery.vgz" size="15918" crc="f38d8265" sha1="99cc0e79117010e404ee5126a7e7709c33de0ac5" offset="0" />
+ </dataarea>
+ </part>
+ <part name="015" interface="vgm_quik">
+ <feature name="part_id" value="15 end of the world ~ world's end.vgz" />
+ <dataarea name="quik" size="7684">
+ <rom name="15 end of the world ~ world's end.vgz" size="7684" crc="bbd13fa3" sha1="3861e2a9183ef4304f68c6f12b31804b2f0210d7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="016" interface="vgm_quik">
+ <feature name="part_id" value="16 legendary illusion ~ infinite being.vgz" />
+ <dataarea name="quik" size="26169">
+ <rom name="16 legendary illusion ~ infinite being.vgz" size="26169" crc="018559b3" sha1="f9615eb838a43df7465a35f74c528f5a938aa1d7" offset="0" />
+ </dataarea>
+ </part>
+ <part name="017" interface="vgm_quik">
+ <feature name="part_id" value="17 alice in wonderland.vgz" />
+ <dataarea name="quik" size="31993">
+ <rom name="17 alice in wonderland.vgz" size="31993" crc="10727a92" sha1="0778bb15a3a24cee51d528ea350832380b390aa6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="018" interface="vgm_quik">
+ <feature name="part_id" value="18 the grimoire of alice.vgz" />
+ <dataarea name="quik" size="16222">
+ <rom name="18 the grimoire of alice.vgz" size="16222" crc="e5fb6529" sha1="3bd9102cdfd1f5285ce3796de2d1ef7483941d6d" offset="0" />
+ </dataarea>
+ </part>
+ <part name="019" interface="vgm_quik">
+ <feature name="part_id" value="19 shinto shrine.vgz" />
+ <dataarea name="quik" size="10797">
+ <rom name="19 shinto shrine.vgz" size="10797" crc="700be27b" sha1="9f02b6cefe1973b775ede51c3b1e474201a55473" offset="0" />
+ </dataarea>
+ </part>
+ <part name="020" interface="vgm_quik">
+ <feature name="part_id" value="20 endless.vgz" />
+ <dataarea name="quik" size="13391">
+ <rom name="20 endless.vgz" size="13391" crc="76081133" sha1="7069ed323d9e049f3bad66652de453580a45b04f" offset="0" />
+ </dataarea>
+ </part>
+ <part name="021" interface="vgm_quik">
+ <feature name="part_id" value="21 eternal paradise.vgz" />
+ <dataarea name="quik" size="4349">
+ <rom name="21 eternal paradise.vgz" size="4349" crc="c30924e2" sha1="b76c569af4b5e1af3af1d50ea48c40b323561adc" offset="0" />
+ </dataarea>
+ </part>
+ <part name="022" interface="vgm_quik">
+ <feature name="part_id" value="22 mystic dream.vgz" />
+ <dataarea name="quik" size="15497">
+ <rom name="22 mystic dream.vgz" size="15497" crc="9764b2f5" sha1="61a573c35411575f80cbc7393982398bd335df0c" offset="0" />
+ </dataarea>
+ </part>
+ <part name="023" interface="vgm_quik">
+ <feature name="part_id" value="23 peaceful romancer.vgz" />
+ <dataarea name="quik" size="25496">
+ <rom name="23 peaceful romancer.vgz" size="25496" crc="63b6ac20" sha1="28d68409a7f247e75e5fb54098baf735dec7a9d6" offset="0" />
+ </dataarea>
+ </part>
+ <part name="024" interface="vgm_quik">
+ <feature name="part_id" value="24 soul's resting place.vgz" />
+ <dataarea name="quik" size="10960">
+ <rom name="24 soul's resting place.vgz" size="10960" crc="d3ba869a" sha1="42bc45eb6386485dff6693b46c91ac75a8a8abce" offset="0" />
+ </dataarea>
+ </part>
+ </software>
+
<!-- Project 2612 VGM Archives located at http://project2612.org/list.php
Also https://archive.org/details/Project2612CompleteArchive20180623681Sets.7z -->
@@ -345947,4 +350335,19 @@ license:CC0
</part>
</software>
+
+<!-- Demonstrations and Miscellaneous VGMs -->
+
+ <software name="d_titov2_md">
+ <description>Overdrive 2 (Megadrive Demo)</description>
+ <year>2017</year>
+ <publisher>Titan</publisher>
+ <info name="cores" value="SN76496, YM2612"/>
+ <part name="001" interface="vgm_quik">
+ <feature name="part_id" value="overdrive2.vgm" />
+ <dataarea name="quik" size="3590051">
+ <rom name="overdrive2.vgm" size="3590051" crc="0afbf930" sha1="3d703cfb9513c3edfc61276c1819ab5eb12b43b6" offset="0" />
+ </dataarea>
+ </part>
+ </software>
</softwarelist>
diff --git a/hash/videopac.xml b/hash/videopac.xml
index 5badbd7fc39..16c244e535c 100644
--- a/hash/videopac.xml
+++ b/hash/videopac.xml
@@ -20,22 +20,18 @@ TODO:
Undumped (or dumped but not public):
- Spaans (spanish to dutch translator)
- Crazy Horses
-- Des Chiffres et des Lettres
- misc. homebrew cartridges
Protos:
- Bastion youtube.com/watch?v=cFdmgs4r7_E
- Catburglar youtube.com/watch?v=DDsWDFxy0oE
- Himalaya youtube.com/watch?v=L_lvOs6EnA4
-- SoundTool youtube.com/watch?v=7JYn6B7rxqw
- Terrahawks youtube.com/watch?v=AXk7OSA6NGg
http://www.ozyr.com/rene/PICS/protos.jpg
-- Sherlock Holmes Consulting Detective (programmed by Ed Friedman, most likely dumped and hoarded)
- Back Gammon
- Freedom Fighters
- K.C.'s Crazy Chase
-- Killer Bees (also 10/12/82 (silent version), and 11/12/82 builds exist)
- Handicap I (?)
- Frogger
- Robot City
@@ -53,14 +49,9 @@ Unreleased, possibly no prototypes exist:
Undumped Odyssey³/G7400 prototypes:
-USA:
-- TMS2764
-- Freedom Fighters
-- Pick Axe Pete
-
http://www.ozyr.com/rene/PICS/protos.jpg
+- Pick Axe Pete
- Modem Program
-- Attack of the Time Lord
- Requins [Shark Hunter]
- monsternet dedicated g7400 840209 [Norseman]
- 58+ Air Battle
@@ -189,6 +180,18 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
+ <software name="linguaduc"><!-- not a consumer product, communication aid for the handicapped -->
+ <description>Linguaduc (Europe, prototype)</description>
+ <year>198?</year>
+ <publisher>Carba</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <dataarea name="rom" size="0x800">
+ <rom name="pr_linguaduc.bin" size="0x800" crc="bd623665" sha1="d33dedd4b880f0cb655faa2396ab05c619799269" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="newscast">
<description>Newscaster (Europe)</description>
<year>1980</year>
@@ -228,7 +231,19 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
- <software name="testcart">
+ <software name="soundtool"><!-- not a consumer product, developer sound tool -->
+ <description>Sound Tool (Europe)</description>
+ <year>198?</year>
+ <publisher>Philips</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <dataarea name="rom" size="0x800">
+ <rom name="soundtool.bin" size="0x800" crc="3e454bbe" sha1="976bbac3557e6daa262439645511e280b7c740fe" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="testcart"><!-- not a consumer product, factory test rom -->
<description>Service Test Cartridge (Europe)</description>
<year>198?</year>
<publisher>Philips</publisher>
@@ -737,7 +752,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<part name="cart" interface="odyssey_cart">
<feature name="slot" value="o2_rom" />
<dataarea name="rom" size="0x1000">
- <rom name="jo_chez-maxime.bin" size="0x1000" crc="0f46cf66" sha1="cd58d267fe5bab82f5dab01dbb08d5adf0053108" />
+ <rom name="jo_vxt_a08.bin" size="0x1000" crc="0f46cf66" sha1="cd58d267fe5bab82f5dab01dbb08d5adf0053108" />
</dataarea>
</part>
</software>
@@ -803,7 +818,7 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
- <software name="conquest">
+ <software name="conquest"><!-- board game -->
<description>Conquest of the World (Europe, US)</description>
<year>1981</year>
<publisher>Philips</publisher>
@@ -951,6 +966,18 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
+ <software name="chifflet">
+ <description>Des Chiffres et des Lettres (France)</description>
+ <year>198?</year>
+ <publisher>Brandt</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <dataarea name="rom" size="0x2000">
+ <rom name="jo_jft_d03.bin" size="0x2000" crc="248bf33e" sha1="5c86921225b93d87bfd63bc13dd22dddab4e8826" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="billiard">
<description>Electronic Billiards (Europe, US)</description>
<year>1978</year>
@@ -1235,6 +1262,32 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
+ <software name="beesp" cloneof="bees">
+ <description>Killer Bees! (US, prototype, set 1)</description>
+ <year>1982</year>
+ <publisher>Philips</publisher>
+ <info name="programmer" value="Robert S. Harris" />
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <dataarea name="rom" size="0x1000">
+ <rom name="o2_47_pr.bin" size="0x1000" crc="f308018d" sha1="15880a92e42258776801fdae4239f3e529662913" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="beespa" cloneof="bees">
+ <description>Killer Bees! (US, prototype, set 2)</description>
+ <year>1982</year>
+ <publisher>Philips</publisher>
+ <info name="programmer" value="Robert S. Harris" />
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <dataarea name="rom" size="0x1000">
+ <rom name="o2_47_pr_alt.bin" size="0x1000" crc="9bec21c2" sha1="5f38cdc587091cb149364d20d508e800c860d82d" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="lasvegas">
<description>Las Vegas Gambling (Europe, US)</description>
<year>1980</year>
@@ -1825,7 +1878,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<part name="cart" interface="odyssey_cart">
<feature name="slot" value="o2_rom" />
<dataarea name="rom" size="0x1000">
- <rom name="jo_syracuse.bin" size="0x1000" crc="280d08f4" sha1="37aa11cbf0a32ece89d1d2c500b74660830377df" />
+ <rom name="jo_vxt_a07.bin" size="0x1000" crc="280d08f4" sha1="37aa11cbf0a32ece89d1d2c500b74660830377df" />
</dataarea>
</part>
</software>
@@ -1857,6 +1910,18 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
+ <software name="sherlock"><!-- board game -->
+ <description>The Adventures of Sherlock Holmes (US, prototype)</description>
+ <year>198?</year>
+ <publisher>Magnavox</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <dataarea name="rom" size="0x2000">
+ <rom name="pr_sherlock.bin" size="0x2000" crc="245dd6a5" sha1="3046caec84ea4b4b5c84ff7e3d1fd38231367f94" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="gtwallst">
<description>The Great Wall Street Fortune Hunt (Europe, US)</description>
<year>1983</year>
@@ -1907,7 +1972,7 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
- <software name="quest">
+ <software name="quest"><!-- board game -->
<description>The Quest for the Rings (Europe, US)</description>
<year>1981</year>
<publisher>Philips</publisher>
@@ -1921,7 +1986,7 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
- <software name="laquete" cloneof="quest">
+ <software name="laquete" cloneof="quest"><!-- board game -->
<description>La Quête des Anneux (France)</description>
<year>1982</year>
<publisher>Radiola</publisher>
@@ -2032,7 +2097,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_basket-bowling_pl.bin" size="0x2000" crc="b5fb1416" sha1="c341ed24346546b75de2ab24af1a9223ca2d1aac" />
+ <rom name="jo_jfa_e03.bin" size="0x2000" crc="b5fb1416" sha1="c341ed24346546b75de2ab24af1a9223ca2d1aac" />
</dataarea>
</part>
</software>
@@ -2060,7 +2125,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_billard_pl.bin" size="0x2000" crc="4cec1404" sha1="004ea921b691db6b310f5b51c495df9b86be3aa8" />
+ <rom name="jo_jxa_d03.bin" size="0x2000" crc="4cec1404" sha1="004ea921b691db6b310f5b51c495df9b86be3aa8" />
</dataarea>
</part>
</software>
@@ -2139,7 +2204,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_demon-attack_pl.bin" size="0x2000" crc="50af9d45" sha1="cfd1337c8d5a40f2f4e1ab49158a8963764919da" />
+ <rom name="jo_jxt_c07.bin" size="0x2000" crc="50af9d45" sha1="cfd1337c8d5a40f2f4e1ab49158a8963764919da" />
</dataarea>
</part>
</software>
@@ -2152,7 +2217,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_exojet_pl.bin" size="0x2000" crc="cfca6f39" sha1="8aafcd055a2ef45c3d85804c8a3ea04d9a9732ab" />
+ <rom name="jo_jxt_c05.bin" size="0x2000" crc="cfca6f39" sha1="8aafcd055a2ef45c3d85804c8a3ea04d9a9732ab" />
</dataarea>
</part>
</software>
@@ -2165,7 +2230,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_flipper_pl.bin" size="0x2000" crc="ac5c74e6" sha1="215439c1044b93888b71bd6a210ebfda93d97c22" />
+ <rom name="jo_jfa_d01.bin" size="0x2000" crc="ac5c74e6" sha1="215439c1044b93888b71bd6a210ebfda93d97c22" />
</dataarea>
</part>
</software>
@@ -2230,7 +2295,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_le-tresor-englouti_pl.bin" size="0x2000" crc="b2f0f0b4" sha1="c0fcaef6a18026e0acc04c3d48443d768043cb03" />
+ <rom name="jo_jft_a10.bin" size="0x2000" crc="b2f0f0b4" sha1="c0fcaef6a18026e0acc04c3d48443d768043cb03" />
</dataarea>
</part>
</software>
@@ -2399,7 +2464,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<feature name="slot" value="o2_rom" />
<feature name="b_pin" value="1" />
<dataarea name="rom" size="0x2000">
- <rom name="jo_moto-crash_pl.bin" size="0x2000" crc="68560dc7" sha1="f6de2f95e5cf4849a4d7071b1a470c3ef0634e5f" />
+ <rom name="jo_jxt_e05.bin" size="0x2000" crc="68560dc7" sha1="f6de2f95e5cf4849a4d7071b1a470c3ef0634e5f" />
</dataarea>
</part>
</software>
@@ -2436,8 +2501,21 @@ Official VP+ upgaded versions (simply adds a background picture):
<!-- Odyssey³ prototypes, they won't work properly on European VP+ consoles -->
+ <software name="timelordpl" cloneof="timelord">
+ <description>Attack of the Timelord! (US, plus, prototype)</description>
+ <year>1983</year>
+ <publisher>Philips</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <feature name="b_pin" value="1" />
+ <dataarea name="rom" size="0x2000">
+ <rom name="o3_45.bin" size="0x2000" crc="5bbb30c8" sha1="29d999b9e7c59d16e5e68d833f28dbc86f062d1f" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="baseballpl" cloneof="baseball">
- <description>Baseball (US, plus, prototype)</description>
+ <description>Baseball! (US, plus, prototype)</description>
<year>1983</year>
<publisher>Philips</publisher>
<part name="cart" interface="odyssey_cart">
@@ -2462,6 +2540,45 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
+ <software name="freedomplu" cloneof="freedom">
+ <description>Freedom Fighters! (US, plus, prototype)</description>
+ <year>1983</year>
+ <publisher>Philips</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <feature name="b_pin" value="1" />
+ <dataarea name="rom" size="0x2000">
+ <rom name="o3_36.bin" size="0x2000" crc="3150a9bf" sha1="e1f78160d273a19f4c322423bc28a566fa668e71" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="beesplu" cloneof="bees">
+ <description>Killer Bees! (US, plus, prototype)</description>
+ <year>1983</year>
+ <publisher>Philips</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <feature name="b_pin" value="1" />
+ <dataarea name="rom" size="0x2000">
+ <rom name="o3_47.bin" size="0x2000" crc="3026e732" sha1="a944e7d6c5c8924dcbd9ef08e0f74b4bca1177c3" />
+ </dataarea>
+ </part>
+ </software>
+
+ <software name="terminal">
+ <description>Terminal Program (US, prototype)</description>
+ <year>1983</year>
+ <publisher>Philips</publisher>
+ <part name="cart" interface="odyssey_cart">
+ <feature name="slot" value="o2_rom" />
+ <feature name="b_pin" value="1" />
+ <dataarea name="rom" size="0x800">
+ <rom name="o3_terminal.bin" size="0x800" crc="e5d2cf23" sha1="3e6e4f407a8f37636336029950acf7d46253e50a" />
+ </dataarea>
+ </part>
+ </software>
+
<!-- Homebrew -->
@@ -2492,7 +2609,6 @@ Official VP+ upgaded versions (simply adds a background picture):
</part>
</software>
- <!-- NTSC Cartridge dumped from a 39SF010 flashrom (1MB) and actual data (2KB) data is repeated to fill space and matches publicly posted rom from author -->
<software name="deathrac">
<description>Death Race (US)</description>
<year>2014</year>
@@ -2501,7 +2617,8 @@ Official VP+ upgaded versions (simply adds a background picture):
<part name="cart" interface="odyssey_cart">
<feature name="slot" value="o2_rom" />
<dataarea name="rom" size="0x800">
- <rom name="drace_rc04.ntsc.bin" size="0x800" crc="91a767de" sha1="26a044c68ff08f574f6649b731b82caca8c0e797" />
+ <!-- 39SF010 flashrom (1MB), actual data (2KB) is repeated to fill space and matches publicly posted rom from author -->
+ <rom name="drace_rc04_ntsc.bin" size="0x800" crc="91a767de" sha1="26a044c68ff08f574f6649b731b82caca8c0e797" />
</dataarea>
</part>
</software>
@@ -2514,7 +2631,7 @@ Official VP+ upgaded versions (simply adds a background picture):
<part name="cart" interface="odyssey_cart">
<feature name="slot" value="o2_rom" />
<dataarea name="rom" size="0x800">
- <rom name="drace_rc04.pal.bin" size="0x800" crc="0ca8c961" sha1="3918d6c2c324fba55e8b90acc8d38e540e4ec5c6" />
+ <rom name="drace_rc04_pal.bin" size="0x800" crc="0ca8c961" sha1="3918d6c2c324fba55e8b90acc8d38e540e4ec5c6" />
</dataarea>
</part>
</software>
diff --git a/hash/vsmile_cart.xml b/hash/vsmile_cart.xml
index 1e26e3db281..aa29b4905a7 100644
--- a/hash/vsmile_cart.xml
+++ b/hash/vsmile_cart.xml
@@ -136,6 +136,7 @@ Regular game cartridges
+========+===================+================================================================================================+
| XX | 80-092000(US) | Alphabet Park Adventure (red haired girl version) |
| XX | 80-092000(US) | Alphabet Park Adventure (red haired girl version, alt) |
+| XX | 80-092000(US) | Alphabet Park Adventure (red haired girl version, rev. 2) |
| XX | 80-092000-101(US) | Alphabet Park Adventure (rev. 101, blond haired girl version) |
| XX | (IT) | Avventura nel parco alfabeto |
| XX | 80-092002(NL) | Alfabet Pretpark |
@@ -683,6 +684,25 @@ V.Smile Smartbook Smartidges (need a Smartbook touch tablet connected to a regul
</part>
</software>
+ <software name="alphaprkr2" cloneof="alphaprkr101">
+ <description>Alphabet Park Adventure (USA, rev. 2)</description>
+ <year>200?</year>
+ <publisher>VTech</publisher>
+ <info name="serial" value="80-092000(US)" />
+ <part name="cart" interface="vsmile_cart">
+ <feature name="slot" value="vsmile_rom" />
+ <feature name="pcb" value="706148" />
+ <feature name="pcb_model" value="706148-3" />
+ <feature name="cart_type" value="lilac" />
+ <feature name="u1" value="" /> <!-- EPOXY BLOB ROM --> <!-- 2 globs, uses /CS2 for 2nd glob -->
+ <feature name="u2" value="" /> <!-- EPOXY BLOB ROM -->
+ <dataarea name="rom" size="0x0800000">
+ <rom name="alphaprkr2.u1" size="0x0400000" crc="4e635c94" sha1="96792d607a94f8fb36dbfff8c68f720c68c742a8" offset="0x0000000" />
+ <rom name="alphaprkr2.u2" size="0x0200000" crc="2feee80a" sha1="d1ca700602c3b2bce2a8920f017370cb0ef322de" offset="0x0400000" />
+ </dataarea>
+ </part>
+ </software>
+
<software name="alphaprk" cloneof="alphaprkr101">
<description>Alphabet Park Adventure (USA)</description>
<year>200?</year>
@@ -1982,8 +2002,7 @@ V.Smile Smartbook Smartidges (need a Smartbook touch tablet connected to a regul
</part>
</software>
- <!-- No inputs, uses a dance mat controller -->
- <software name="jamgymg" supported="no"> <!-- Will be clone of "jamgym" once found and dumped. -->
+ <software name="jamgymg" supported="yes"> <!-- Will be clone of "jamgym" once found and dumped. -->
<description>V.Smile Tanz Mit Center (Germany)</description>
<year>200?</year>
<publisher>VTech</publisher>
@@ -2000,8 +2019,7 @@ V.Smile Smartbook Smartidges (need a Smartbook touch tablet connected to a regul
</part>
</software>
- <!-- No inputs, uses a dance mat controller -->
- <software name="jamgymf" cloneof="jamgymg" supported="no"> <!-- Will be clone of "jamgym" once found and dumped. -->
+ <software name="jamgymf" cloneof="jamgymg" supported="yes"> <!-- Will be clone of "jamgym" once found and dumped. -->
<description>V.Smile Défi Gym (France)</description>
<year>200?</year>
<publisher>VTech</publisher>
@@ -2016,8 +2034,7 @@ V.Smile Smartbook Smartidges (need a Smartbook touch tablet connected to a regul
</part>
</software>
- <!-- No inputs, uses a dance mat controller -->
- <software name="jamgyms" cloneof="jamgymg" supported="no">
+ <software name="jamgyms" cloneof="jamgymg" supported="yes">
<description>Gimnasio Interactivo V.Smile (Spain)</description>
<year>200?</year>
<publisher>VTech</publisher>
diff --git a/hash/vtech_storio_cart.xml b/hash/vtech_storio_cart.xml
index 72bf1625f18..30207f54b71 100644
--- a/hash/vtech_storio_cart.xml
+++ b/hash/vtech_storio_cart.xml
@@ -11,50 +11,121 @@ license:CC0
<!--
Language:
- ********0 = US
- ********1 = Italy
- ********2 = Netherlands
+ ********0 = US / Canada / Hong Kong
+ ********1 = Unused
+ *******22 = Spain / Mexico / Latin America
********3 = UK
+ *******23 = Netherlands
********4 = Germany
- ********5 = France
- ********6 = Portugal
- ********7 = Spain
+ ********5 = France / Canada (French)
+ ********6 = Unused
+ ********7 = Italy
+
Dumped | Serial | Name
==============================================================================================
| 80-115600(US) | What's That Noise (it's 52-280800 on VTech catalog)
NA | 80-115622(SP) | ¿Qué ruido es ese? (no ROM cartridge)
+ | 80-115633(UK) | What's That Noise? (Storio Pack-in cart)
| 80-280000(US) | Shrek's Vacation
| 80-280003(UK) | Shrek's Holiday
| 80-280100(US) | Toy Story 3
- | 80-280200(US) | Mr. Men/Little Miss
+ | 80-280103(UK) | Toy Story 3
+ | 80-280107(??) | Toy Story 3 (Italy)
+ | 80-280122(SP) | Toy Story 3
+ | 80-280123(??) | Toy Story 3 (Netherlands)
+ | 80-280200(US) | Mr. Men and Little Miss - Mr. Messy and the Missing Sock
+ | 80-280203(UK) | Mr. Men and Little Miss - Mr. Messy and the Missing Sock
| 80-280300(US) | Disney Fairies - Tinkerbell and The Great Fairy Rescue
+ | 80-280303(UK) | Disney Fairies - Tinkerbell and The Great Fairy Rescue
+ | 80-280304(GER) | Disney Fairies - Tinkerbell Ein Sommer Voller Abenteuer
+ | 80-280323(??) | Disney Fairies - Tinkerbell en de Grote Reddingsoperatie (Netherlands)
| 80-280400(US) | Scooby Doo! - Scooby Doo and a Mummy, Too!
| 80-280403(UK) | Scooby Doo! - Scooby Doo and a Mummy, Too!
+ | 80-280405(FR) | Scooby Doo! - Momie en folie!
+ | 80-280407(??) | Scooby Doo! - Scooby-Doo e una mummia a tu per tu! (Italy)
XX | 80-280422(SP) | Scooby Doo! - Scooby Doo y la momia
- | 80-280600(US) | Olivia
+ | 80-280600(US) | Olivia Takes Ballet
+ | 80-280603(UK) | Olivia Takes Ballet
| 80-280700(US) | The Little Engine That Could
- | 80-280900(US) | Dora and the Three Little Pigs
- XX | 80-280422(GER) | Dora und die drei Schweinchen
+ | 80-280804(GER) | Rufus in der Stadt (Storio Pack-in cart)
+ | 80-280???(??) | Rufus arriva in città (Italy, Storio Pack-in cart, product code unconfirmed)
+ | 80-280900(US) | Dora the Explorer - Dora and the Three Little Pigs
+ | 80-280903(UK) | Dora the Explorer - Dora and the Three Little Pigs
+ XX | 80-280904(GER) | Dora - Dora und die drei Schweinchen
+ | 80-280905(FR) | Dora l'exploratrice - Dora et les trois petit cochons
+ | 80-280922(SP) | Dora la exploradora - Dora y los Tres Cerditos
+ | 80-280923(??) | Dora - Dora en de Drie Kleine Biggetjes (Netherlands)
| 80-281000(US) | Mickey Mouse Clubhouse
+ | 80-281003(UK) | Mickey Mouse Clubhouse
XX | 80-281004(GER) | Micky Maus Wunderhaus
- | 80-281100(US) | Disney Princess
- | 80-281103(UK) | Disney Princess
- | 80-281200(US) | Cars
- | 80-281300(US) | Sesame Street The Happy Scientists
- | 80-281400(US) | SpongeBob SquarePants Model Sponge
+ | 80-281005(FR) | La Maison de Mickey
+ | 80-281022(SP) | La casa de Mickey Mouse
+ | 80-281023(??) | Mickey Mouse Clubhuis - Mickey zoekt en vindt! (Netherlands)
+ | 80-281100(US) | Disney Princess - Belle's Special Treat / A Gift from the Heart
+ | 80-281103(UK) | Disney Princess - Belle's Special Treat / A Gift from the Heart
+ | 80-281104(GER) | Disney Princess - Eine besondere Überraschung für Belle / Das Geburtstagsgeschenk
+ | 80-281105(FR) | Disney Princess - Une surprise pour Belle / Un cadeau qui vient du coeur
+ | 80-281107(??) | Disney Princess - Una sorpresa speciale / Un regalo dal cuore (Italy)
+ | 80-281122(SP) | Disney Princess - Historia de Bella / Historia de Cenicienta
+ | 80-281123(??) | Disney Princess - Ein Speciale Verrassing / Ein ???? (Netherlands)
+ | 80-281200(US) | Disney/Pixar Cars Toon - Tokyo Mater
+ | 80-281203(UK) | Disney/Pixar Cars Toon - Tokyo Mater
+ | 80-281204(GER) | Disney/Pixar Cars Toon - Hook in Tokyo
+ | 80-281300(US) | Sesame Street - The Happy Scientists
+ | 80-281400(US) | SpongeBob SquarePants - Model Sponge
XX | 80-281404(GER) | Spongebob Schwammkopf - Ein Schwamm will nach oben
+ | 80-281405(FR) | Bob L'éponge - Bob, la star des éponges
+ | 80-281422(SP) | Bob Esponja - Modelo Esponja
| 80-281500(US) | Tangled
+ | 80-281503(UK) | Rapunzel
XX | 80-281504(GER) | Rapunzel - Neu verföhnt
| 80-281600(US) | Chuggington - Babysitter Brewster
- | 80-281700(US) | Penguins of Madagascar - The Helmet
+ | 80-281603(UK) | Chuggington - Babysitter Brewster
+ | 80-281604(GER) | Chuggington - Bastian, der Babysitter
+ | 80-281605(FR) | Chuggington - Bruno fait du baby-sitting
+ | 80-281700(US) | The Penguins of Madagascar - The Helmet
+ | 80-281703(UK) | The Penguins of Madagascar - The Helmet
+ | 80-281723(??) | De Pinguïns van Madagascar - De Helm (Netherlands)
| 80-281800(US) | Kung Fu Panda 2
- | 80-281900(US) | Cars 2
+ | 80-281803(UK) | Kung Fu Panda 2
+ | 80-281900(US) | Disney/Pixar Cars 2
+ | 80-281903(UK) | Disney/Pixar Cars 2
+ | 80-281904(GER) | Disney/Pixar Cars 2
+ | 80-281905(FR) | Disney/Pixar Cars 2
+ | 80-281907(??) | Disney/Pixar Cars 2 (Italy)
+ | 80-281922(SP) | Disney/Pixar Cars 2
+ | 80-281923(??) | Disney/Pixar Cars 2 (Netherlands)
| 80-282000(US) | Winnie the Pooh
+ | 80-282003(UK) | Winnie the Pooh
+ | 80-282004(GER) | Winnie Puuh
+ | 80-282005(FR) | Winnie l'ourson
+ | 80-282022(SP) | Winnie the Pooh (Found in Spain product catalog, may not have been released)
+ | 80-282023(??) | Winnie de Poeh (Netherlands)
| 80-282100(US) | Super Why! - Attack of the Eraser
- | 80-282200(US) | Madagascar 3
+ | 80-282200(US) | Madagascar 3 - Europe's Most Wanted
+ | 80-282204(GER) | Madagascar 3 - Flucht durch Europa
+ | 80-282205(FR) | Madagascar 3 - Bons baisers d'Europe
+ | 80-282222(SP) | Madagascar 3 - De marcha por Europa
+ | 80-282223(??) | Madagascar 3 - Op Avontuur in Europa (Netherlands)
| 80-282300(US) | Dinosaur Train - T.Rex Teeth
- | 80-282400(US) | Hello Kitty's Surprise
+ | 80-282400(US) | Hello Kitty - Hello Kitty's Surprise
+ | 80-282403(UK) | Hello Kitty - Hello Kitty's Surprise
+ | 80-282404(GER) | Hello Kitty - Hello Kittys Überraschung!
+ | 80-282422(SP) | Hello Kitty - La sorpresa de Hello Kitty
+ | 80-282423(??) | Hello Kitty - Hello Kitty's Verrassing! (Netherlands)
+ | 80-282700(US) | Thomas and Friends - Up, Up and Away! Diesel's Special Delivery
+ | 80-282703(UK) | Thomas and Friends - Up, Up and Away! Diesel's Special Delivery
+ | 80-282704(GER) | Thomas und seine Freunde - Auf und davon Diesel ist neidisch
+
+ Notes: Storio 1 carts follow an 80-28XXXX(XX) product code sequence. Spain and Netherlands releases use an 80-28XX2X(XX) sequence.
+ EAN is calculated by using a 341776 prefix, appending the six digit product code, and adding an EAN check number at the end.
+ EG: 341776 + 280003 + 3 (calculated check digit) = 3417762800033 - Shrek's Holiday (UK.)
+
+ Two letter Netherlands and Italy suffixes have not yet been confirmed. All items have been confirmed via physical photographs, product code searches,
+ and online shopping sites, with the exception of Winnie Puuh (Spain) which was listed in a Spanish product catalog and may have not been released.
+
+ Storio 1 carts come in boxes with an orange stripe in front. Storio carts with a blue stripe in front are only compatible with Storio 2 and later systems.
-->
diff --git a/makefile b/makefile
index 4ec2186cac3..880057968c9 100644
--- a/makefile
+++ b/makefile
@@ -196,7 +196,7 @@ GENIEOS := solaris
endif
ifeq ($(firstword $(filter FreeBSD,$(UNAME))),FreeBSD)
OS := freebsd
-GENIEOS := freebsd
+GENIEOS := bsd
endif
ifeq ($(firstword $(filter GNU/kFreeBSD,$(UNAME))),GNU/kFreeBSD)
OS := freebsd
@@ -1719,14 +1719,14 @@ endif
ifeq (posix,$(SHELLTYPE))
$(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS)
- @echo '#define BARE_BUILD_VERSION "0.224"' > $@
+ @echo '#define BARE_BUILD_VERSION "0.225"' > $@
@echo 'extern const char bare_build_version[];' >> $@
@echo 'extern const char build_version[];' >> $@
@echo 'const char bare_build_version[] = BARE_BUILD_VERSION;' >> $@
@echo 'const char build_version[] = BARE_BUILD_VERSION " ($(NEW_GIT_VERSION))";' >> $@
else
$(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS)
- @echo #define BARE_BUILD_VERSION "0.224" > $@
+ @echo #define BARE_BUILD_VERSION "0.225" > $@
@echo extern const char bare_build_version[]; >> $@
@echo extern const char build_version[]; >> $@
@echo const char bare_build_version[] = BARE_BUILD_VERSION; >> $@
@@ -1738,7 +1738,7 @@ $(GENDIR)/%.lh: $(SRC)/%.lay scripts/build/complay.py | $(GEN_FOLDERS)
@echo Compressing $<...
$(SILENT)$(PYTHON) scripts/build/complay.py $< $@ layout_$(basename $(notdir $<))
-$(GENDIR)/mame/machine/mulcd.hxx: $(SRC)/mame/machine/mulcd.ppm scripts/build/file2str.py
+$(GENDIR)/mame/machine/mulcd.hxx: $(SRC)/mame/machine/mulcd.ppm scripts/build/file2str.py | $(GEN_FOLDERS)
@echo Converting $<...
$(SILENT)$(PYTHON) scripts/build/file2str.py $< $@ mulcd_bkg uint8_t
diff --git a/plugins/cheat/init.lua b/plugins/cheat/init.lua
index b0e045477b1..3fa625fb4d3 100644
--- a/plugins/cheat/init.lua
+++ b/plugins/cheat/init.lua
@@ -938,12 +938,13 @@ function cheat.startplugin()
if cheat.parameter.item then
intf.parameter.item = {}
for idx, item in pairs(cheat.parameter.item) do
+ intf.parameter.item[idx] = {}
intf.parameter.item[idx].text = cheat.parameter.item[idx].text
intf.parameter.item[idx].value = cheat.parameter.item[idx].value
end
end
end
- return intf
+ return intf
end
function ce.list()
diff --git a/plugins/hiscore/hiscore.dat b/plugins/hiscore/hiscore.dat
index 12d6a38c38e..05c2ee79b54 100644
--- a/plugins/hiscore/hiscore.dat
+++ b/plugins/hiscore/hiscore.dat
@@ -5434,9 +5434,9 @@ sidetrac:
venture:
-venture2:
-venture2b:
venture4:
+venture5a:
+venture5b:
@:maincpu,program,0380,23,00,53
@@ -5449,10 +5449,10 @@ fax2:
;@s:expro02.cpp
galsnew:
-galsnewu:
galsnewj:
galsnewk:
galsnewt:
+galsnewu:
@:maincpu,program,c825b6,64,30,31
@@ -7218,7 +7218,7 @@ hvyunitu:
roadf:
roadf2:
-roadfh
+roadfh:
roadfu:
@:maincpu,program,3bd0,10a,01,01
@:maincpu,program,3066,3,01,00
@@ -8202,8 +8202,8 @@ dbreed:
;dbreedm72:******dragon breed (m72 pcb version)
+dbreedjm72:
dbreedm72:
-dbreedm72j:
@:maincpu,program,9096a,03,58,00
@:maincpu,program,90990,82,58,2e
@:maincpu,program,90950,01,06,06
@@ -11246,7 +11246,7 @@ ketb:
@:maincpu,program,801093,1,30,30
-photoy2k102:
+photoy2k102j:
photoy2k104:
@:maincpu,program,80a306,1,12,12
@:maincpu,program,813452,78,49,40
@@ -11284,16 +11284,16 @@ orlegend105k:
@:maincpu,program,811918,d4,49,b0
-drgw2hk:
-@:maincpu,program,80f13a,46,49,40
-
-
;********Dragon World II (ver. 110X, Export)
drgw2:
-dw2v100x:
+drgw2100x:
@:maincpu,program,80caf8,46,49,40
+drgw2100hk:
+@:maincpu,program,80f13a,46,49,40
+
+
;@s:phoenix.cpp
; fenix is not working yet ;[Special thanks to Cananas for enhancing this entry]
@@ -18091,7 +18091,7 @@ maydayb:
;joustr:******joust (solid red label)
joust:
joustr:
-joustwr:
+jousty:
@:maincpu,program,cfa4,54,f1,f5
diff --git a/scripts/build/complay.py b/scripts/build/complay.py
index 34a43992b7c..6903418e242 100755
--- a/scripts/build/complay.py
+++ b/scripts/build/complay.py
@@ -96,7 +96,7 @@ class LayoutChecker(Minifyer):
BADTAGPATTERN = re.compile('[^abcdefghijklmnopqrstuvwxyz0123456789_.:^$]')
VARPATTERN = re.compile('^.*~[0-9A-Za-z_]+~.*$')
FLOATCHARS = re.compile('^.*[.eE].*$')
- SHAPES = frozenset(('disk', 'dotmatrix', 'dotmatrix5dot', 'dotmatrixdot', 'led14seg', 'led14segsc', 'led16seg', 'led16segsc', 'led7seg', 'led8seg_gts1', 'rect'))
+ SHAPES = frozenset(('disk', 'led14seg', 'led14segsc', 'led16seg', 'led16segsc', 'led7seg', 'led8seg_gts1', 'rect'))
ORIENTATIONS = frozenset((0, 90, 180, 270))
YESNO = frozenset(('yes', 'no'))
BLENDMODES = frozenset(('none', 'alpha', 'multiply', 'add'))
@@ -225,6 +225,8 @@ class LayoutChecker(Minifyer):
bottom = self.checkFloatAttribute('bounds', attrs, 'bottom', 1.0)
x = self.checkFloatAttribute('bounds', attrs, 'x', 0.0)
y = self.checkFloatAttribute('bounds', attrs, 'y', 0.0)
+ xc = self.checkFloatAttribute('bounds', attrs, 'xc', 0.0)
+ yc = self.checkFloatAttribute('bounds', attrs, 'yc', 0.0)
width = self.checkFloatAttribute('bounds', attrs, 'width', 1.0)
height = self.checkFloatAttribute('bounds', attrs, 'height', 1.0)
if (left is not None) and (right is not None) and (left > right):
@@ -239,12 +241,14 @@ class LayoutChecker(Minifyer):
self.handleError('Element bounds attribute width "%s" is negative' % (attrs['width'], ))
if (height is not None) and (0.0 > height):
self.handleError('Element bounds attribute height "%s" is negative' % (attrs['height'], ))
- if ('left' not in attrs) and ('x' not in attrs):
- self.handleError('Element bounds has neither attribute left nor attribute x')
- has_ltrb = ('left' in attrs) or ('top' in attrs) or ('right' in attrs) or ('bottom' in attrs)
- has_origin_size = ('x' in attrs) or ('y' in attrs) or ('width' in attrs) or ('height' in attrs)
- if has_ltrb and has_origin_size:
- self.handleError('Element bounds has both left/top/right/bottom and origin/size attributes')
+ if (('left' in attrs) and (('x' in attrs) or ('xc' in attrs))) or (('x' in attrs) and ('xc' in attrs)):
+ self.handleError('Element bounds has multiple horizontal origin attributes (left/x/xc)')
+ if (('left' in attrs) and ('width' in attrs)) or ((('x' in attrs) or ('xc' in attrs)) and ('right' in attrs)):
+ self.handleError('Element bounds has both left/right and x/xc/width attributes')
+ if (('top' in attrs) and (('y' in attrs) or ('yc' in attrs))) or (('y' in attrs) and ('yc' in attrs)):
+ self.handleError('Element bounds has multiple vertical origin attributes (top/y/yc)')
+ if (('top' in attrs) and ('height' in attrs)) or ((('y' in attrs) or ('yc' in attrs)) and ('bottom' in attrs)):
+ self.handleError('Element bounds has both top/bottom and y/yc/height attributes')
def checkOrientation(self, attrs):
if self.have_orientation[-1]:
@@ -287,15 +291,42 @@ class LayoutChecker(Minifyer):
self.handleError('Element %s attribute state "%s" is negative' % (name, attrs['state']))
if (statemask is not None) and (stateval & ~statemask):
self.handleError('Element %s attribute state "%s" has bits set that are clear in attribute statemask "%s"' % (name, attrs['state'], attrs['statemask']))
- self.handlers.append((self.componentStartHandler, self.componentEndHandler))
+ if 'image' == name:
+ self.handlers.append((self.imageComponentStartHandler, self.imageComponentEndHandler))
+ else:
+ self.handlers.append((self.componentStartHandler, self.componentEndHandler))
self.have_bounds.append({ })
self.have_color.append({ })
- def startObject(self):
- self.handlers.append((self.objectStartHandler, self.objectEndHandler))
- self.have_bounds.append(None)
+ def checkViewItem(self, name, attrs):
+ if ('blend' in attrs) and (attrs['blend'] not in self.BLENDMODES) and not self.VARPATTERN.match(attrs['blend']):
+ self.handleError('Element %s attribute blend "%s" is unsupported' % (name, attrs['blend']))
+ if 'inputtag' in attrs:
+ if 'inputmask' not in attrs:
+ self.handleError('Element %s has inputtag attribute without inputmask attribute' % (name, ))
+ self.checkTag(attrs['inputtag'], name, 'inputtag')
+ elif 'inputmask' in attrs:
+ self.handleError('Element %s has inputmask attribute without inputtag attribute' % (name, ))
+ inputraw = None
+ if 'inputraw' in attrs:
+ if (attrs['inputraw'] not in self.YESNO) and (not self.VARPATTERN.match(attrs['inputraw'])):
+ self.handleError('Element %s attribute inputraw "%s" is not "yes" or "no"' % (name, attrs['inputraw']))
+ else:
+ inputraw = 'yes' == attrs['inputraw']
+ if 'inputmask' not in attrs:
+ self.handleError('Element %s has inputraw attribute without inputmask attribute' % (name, ))
+ if 'inputtag' not in attrs:
+ self.handleError('Element %s has inputraw attribute without inputtag attribute' % (name, ))
+ inputmask = self.checkIntAttribute(name, attrs, 'inputmask', None)
+ if (inputmask is not None) and (not inputmask):
+ if (inputraw is None) or (not inputraw):
+ self.handleError('Element %s attribute inputmask "%s" is zero' % (name, attrs['inputmask']))
+
+ def startViewItem(self, name):
+ self.handlers.append((self.viewItemStartHandler, self.viewItemEndHandler))
+ self.have_bounds.append(None if 'group' == name else { })
self.have_orientation.append(False)
- self.have_color.append(None)
+ self.have_color.append(None if 'group' == name else { })
def rootStartHandler(self, name, attrs):
if 'mamelayout' != name:
@@ -420,8 +451,8 @@ class LayoutChecker(Minifyer):
self.handleError('Element simplecounter attribute align "%s" not in valid range 0-2' % (attrs['align'], ))
self.checkComponent(name, attrs)
elif 'image' == name:
- if 'file' not in attrs:
- self.handleError('Element image missing attribute file')
+ self.have_file = 'file' in attrs
+ self.have_data = None
self.checkComponent(name, attrs)
elif 'reel' == name:
# TODO: validate symbollist and improve validation of other attributes
@@ -471,35 +502,33 @@ class LayoutChecker(Minifyer):
self.have_color.pop()
self.handlers.pop()
+ def imageComponentStartHandler(self, name, attrs):
+ if 'data' == name:
+ if self.have_data is not None:
+ self.handleError('Element image has multiple data child elements (previous %s)' % (self.have_data))
+ else:
+ self.have_data = self.formatLocation()
+ if self.have_file:
+ self.handleError('Element image has attribute file and child element data')
+ self.ignored_depth = 1
+ else:
+ self.componentStartHandler(name, attrs)
+
+ def imageComponentEndHandler(self, name):
+ if (not self.have_file) and (self.have_data is None):
+ self.handleError('Element image missing attribute file or child element data')
+ del self.have_file
+ del self.have_data
+ self.componentEndHandler(name)
+
def groupViewStartHandler(self, name, attrs):
if 'element' == name:
if 'ref' not in attrs:
self.handleError('Element %s missing attribute ref' % (name, ))
elif attrs['ref'] not in self.referenced_elements:
self.referenced_elements[attrs['ref']] = self.formatLocation()
- if ('blend' in attrs) and (attrs['blend'] not in self.BLENDMODES) and not self.VARPATTERN.match(attrs['blend']):
- self.handleError('Element %s attribute blend "%s" is unsupported' % (name, attrs['blend']))
- if 'inputtag' in attrs:
- if 'inputmask' not in attrs:
- self.handleError('Element %s has inputtag attribute without inputmask attribute' % (name, ))
- self.checkTag(attrs['inputtag'], name, 'inputtag')
- elif 'inputmask' in attrs:
- self.handleError('Element %s has inputmask attribute without inputtag attribute' % (name, ))
- inputraw = None
- if 'inputraw' in attrs:
- if (attrs['inputraw'] not in self.YESNO) and (not self.VARPATTERN.match(attrs['inputraw'])):
- self.handleError('Element %s attribute inputraw "%s" is not "yes" or "no"' % (name, attrs['inputraw']))
- else:
- inputraw = 'yes' == attrs['inputraw']
- if 'inputmask' not in attrs:
- self.handleError('Element %s has inputraw attribute without inputmask attribute' % (name, ))
- if 'inputtag' not in attrs:
- self.handleError('Element %s has inputraw attribute without inputtag attribute' % (name, ))
- inputmask = self.checkIntAttribute(name, attrs, 'inputmask', None)
- if (inputmask is not None) and (0 == inputmask):
- if (inputraw is None) or (0 == inputraw):
- self.handleError('Element %s attribute inputmask "%s" is zero' % (name, attrs['inputmask']))
- self.startObject();
+ self.checkViewItem(name, attrs)
+ self.startViewItem(name)
elif 'screen' == name:
if 'index' in attrs:
index = self.checkIntAttribute(name, attrs, 'index', None)
@@ -512,7 +541,8 @@ class LayoutChecker(Minifyer):
self.checkTag(tag, name, 'tag')
if self.BADTAGPATTERN.search(tag):
self.handleError('Element screen attribute tag "%s" contains invalid characters' % (tag, ))
- self.startObject();
+ self.checkViewItem(name, attrs)
+ self.startViewItem(name)
elif 'group' == name:
if 'ref' not in attrs:
self.handleError('Element group missing attribute ref')
@@ -525,7 +555,7 @@ class LayoutChecker(Minifyer):
self.current_collections[n] = l
else:
self.handleError('Element group instantiates collection with duplicate name "%s" from %s (previous %s)' % (n, l, self.current_collections[n]))
- self.startObject();
+ self.startViewItem(name)
elif 'repeat' == name:
if 'count' not in attrs:
self.handleError('Element repeat missing attribute count')
@@ -577,24 +607,55 @@ class LayoutChecker(Minifyer):
self.have_bounds.pop()
self.handlers.pop()
- def objectStartHandler(self, name, attrs):
- if 'bounds' == name:
- if self.have_bounds[-1] is not None:
- self.handleError('Duplicate element bounds (previous %s)' % (self.have_bounds[-1], ))
+ def viewItemStartHandler(self, name, attrs):
+ if 'animate' == name:
+ if isinstance(self.have_bounds[-1], dict):
+ if 'inputtag' in attrs:
+ if 'name' in attrs:
+ self.handleError('Element animate has both attribute inputtag and attribute name')
+ self.checkTag(attrs['inputtag'], name, 'inputtag')
+ elif 'name' not in attrs:
+ self.handleError('Element animate has neither attribute inputtag nor attribute name')
+ self.checkIntAttribute(name, attrs, 'mask', None)
else:
+ self.handleError('Encountered unexpected element %s' % (name, ))
+ elif 'bounds' == name:
+ if self.have_bounds[-1] is None:
self.have_bounds[-1] = self.formatLocation()
+ elif isinstance(self.have_bounds[-1], dict):
+ state = self.checkIntAttribute(name, attrs, 'state', 0)
+ if state is not None:
+ if 0 > state:
+ self.handleError('Element bounds attribute state "%s" is negative' % (attrs['state'], ))
+ if state in self.have_bounds[-1]:
+ self.handleError('Duplicate bounds for state %d (previous %s)' % (state, self.have_bounds[-1][state]))
+ else:
+ self.have_bounds[-1][state] = self.formatLocation()
+ else:
+ self.handleError('Duplicate element bounds (previous %s)' % (self.have_bounds[-1], ))
self.checkBounds(attrs)
elif 'orientation' == name:
self.checkOrientation(attrs)
- if 'color' == name:
- if self.have_color[-1] is not None:
- self.handleError('Duplicate element color (previous %s)' % (self.have_color[-1], ))
- else:
+ elif 'color' == name:
+ if self.have_color[-1] is None:
self.have_color[-1] = self.formatLocation()
+ elif isinstance(self.have_color[-1], dict):
+ state = self.checkIntAttribute(name, attrs, 'state', 0)
+ if state is not None:
+ if 0 > state:
+ self.handleError('Element color attribute state "%s" is negative' % (attrs['state'], ))
+ if state in self.have_color[-1]:
+ self.handleError('Duplicate color for state %d (previous %s)' % (state, self.have_color[-1][state]))
+ else:
+ self.have_color[-1][state] = self.formatLocation()
+ else:
+ self.handleError('Duplicate element color (previous %s)' % (self.have_color[-1], ))
self.checkColor(attrs)
+ else:
+ self.handleError('Encountered unexpected element %s' % (name, ))
self.ignored_depth = 1
- def objectEndHandler(self, name):
+ def viewItemEndHandler(self, name):
self.have_bounds.pop()
self.have_orientation.pop()
self.have_color.pop()
diff --git a/scripts/genie.lua b/scripts/genie.lua
index b8655c0c24b..5310e003ed8 100644
--- a/scripts/genie.lua
+++ b/scripts/genie.lua
@@ -1173,7 +1173,7 @@ configuration { "asmjs" }
buildoptions_cpp {
"-std=c++14",
"-s DISABLE_EXCEPTION_CATCHING=2",
- "-s EXCEPTION_CATCHING_WHITELIST=\"['_ZN15running_machine17start_all_devicesEv','_ZN12cli_frontend7executeEiPPc','_ZN8chd_file11open_commonEb','_ZN8chd_file13read_metadataEjjRNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE','_ZN8chd_file13read_metadataEjjRNSt3__26vectorIhNS0_9allocatorIhEEEE']\"",
+ "-s EXCEPTION_CATCHING_WHITELIST=\"['_ZN15running_machine17start_all_devicesEv','_ZN12cli_frontend7executeEiPPc','_ZN8chd_file11open_commonEb','_ZN8chd_file13read_metadataEjjRNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE','_ZN8chd_file13read_metadataEjjRNSt3__26vectorIhNS0_9allocatorIhEEEE','_ZNK19netlist_mame_device19base_validity_checkER16validity_checker']\"",
}
linkoptions {
"-Wl,--start-group",
diff --git a/scripts/src/3rdparty.lua b/scripts/src/3rdparty.lua
index b3fc924eab4..27383c3a8ed 100644
--- a/scripts/src/3rdparty.lua
+++ b/scripts/src/3rdparty.lua
@@ -19,18 +19,21 @@ project "expat"
kind "StaticLib"
-- fake out the enough of expat_config.h to get by
+ -- could possibly add more defines here for specific targets
defines {
"HAVE_MEMMOVE",
"HAVE_STDINT_H",
"HAVE_STDLIB_H",
"HAVE_STRING_H",
+ "PACKAGE=\"expat\"",
"PACKAGE_BUGREPORT=\"expat-bugs@libexpat.org\"",
"PACKAGE_NAME=\"expat\"",
- "PACKAGE_STRING=\"expat 2.1.1\"",
+ "PACKAGE_STRING=\"expat 2.2.10\"",
"PACKAGE_TARNAME=\"expat\"",
"PACKAGE_URL=\"\"",
- "PACKAGE_VERSION=\"2.1.1\"",
+ "PACKAGE_VERSION=\"2.2.10\"",
"STDC_HEADERS",
+ "VERSION=\"2.2.10\"",
"XML_CONTEXT_BYTES=1024",
"XML_DTD",
"XML_NS",
@@ -45,6 +48,22 @@ else
"BYTEORDER=1234",
}
end
+if _OPTIONS["targetos"]=="macosx" or _OPTIONS["targetos"]=="freebsd" then
+ defines {
+ "HAVE_ARC4RANDOM",
+ }
+end
+if BASE_TARGETOS=="unix" then
+ defines {
+ "HAVE_DLFCN_H",
+ "HAVE_FCNTL_H",
+ "HAVE_MMAP",
+ "HAVE_SYS_STAT_H",
+ "HAVE_SYS_TYPES_H",
+ "HAVE_UNISTD_H",
+ "XML_DEV_URANDOM",
+ }
+end
configuration { "vs*" }
buildoptions {
@@ -1390,6 +1409,12 @@ end
end
end
+ if _OPTIONS["targetos"]=="freebsd" then
+ buildoptions {
+ backtick(pkgconfigcmd() .. " --cflags gl")
+ }
+ end
+
defines {
"__STDC_LIMIT_MACROS",
"__STDC_FORMAT_MACROS",
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index e2404cf1abf..eb1784a9c67 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -504,6 +504,8 @@ if (BUSES["BBC_1MHZBUS"]~=null) then
MAME_DIR .. "src/devices/bus/bbc/1mhzbus/ieee488.h",
MAME_DIR .. "src/devices/bus/bbc/1mhzbus/m2000.cpp",
MAME_DIR .. "src/devices/bus/bbc/1mhzbus/m2000.h",
+ MAME_DIR .. "src/devices/bus/bbc/1mhzbus/m5000.cpp",
+ MAME_DIR .. "src/devices/bus/bbc/1mhzbus/m5000.h",
MAME_DIR .. "src/devices/bus/bbc/1mhzbus/multiform.cpp",
MAME_DIR .. "src/devices/bus/bbc/1mhzbus/multiform.h",
MAME_DIR .. "src/devices/bus/bbc/1mhzbus/opus3.cpp",
@@ -597,6 +599,8 @@ if (BUSES["BBC_USERPORT"]~=null) then
MAME_DIR .. "src/devices/bus/bbc/userport/beebspch.h",
MAME_DIR .. "src/devices/bus/bbc/userport/lcd.cpp",
MAME_DIR .. "src/devices/bus/bbc/userport/lcd.h",
+ MAME_DIR .. "src/devices/bus/bbc/userport/m4000.cpp",
+ MAME_DIR .. "src/devices/bus/bbc/userport/m4000.h",
MAME_DIR .. "src/devices/bus/bbc/userport/palext.cpp",
MAME_DIR .. "src/devices/bus/bbc/userport/palext.h",
MAME_DIR .. "src/devices/bus/bbc/userport/pointer.cpp",
@@ -1113,6 +1117,20 @@ end
---------------------------------------------------
--
+--@src/devices/bus/fmt_scsi/fmt_scsi.h,BUSES["FMT_SCSI"] = true
+---------------------------------------------------
+
+if (BUSES["FMT_SCSI"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/bus/fmt_scsi/fmt_scsi.cpp",
+ MAME_DIR .. "src/devices/bus/fmt_scsi/fmt_scsi.h",
+ MAME_DIR .. "src/devices/bus/fmt_scsi/fmt121.cpp",
+ MAME_DIR .. "src/devices/bus/fmt_scsi/fmt121.h",
+ }
+end
+
+---------------------------------------------------
+--
--@src/devices/bus/gamate/slot.h,BUSES["GAMATE"] = true
---------------------------------------------------
@@ -2378,6 +2396,8 @@ if (BUSES["A2BUS"]~=null) then
MAME_DIR .. "src/devices/bus/a2bus/cmsscsi.h",
MAME_DIR .. "src/devices/bus/a2bus/uthernet.cpp",
MAME_DIR .. "src/devices/bus/a2bus/uthernet.h",
+ MAME_DIR .. "src/devices/bus/a2bus/sider.cpp",
+ MAME_DIR .. "src/devices/bus/a2bus/sider.h",
}
end
@@ -3867,6 +3887,8 @@ if (BUSES["VSMILE"]~=null) then
MAME_DIR .. "src/devices/bus/vsmile/vsmile_ctrl.h",
MAME_DIR .. "src/devices/bus/vsmile/pad.cpp",
MAME_DIR .. "src/devices/bus/vsmile/pad.h",
+ MAME_DIR .. "src/devices/bus/vsmile/mat.cpp",
+ MAME_DIR .. "src/devices/bus/vsmile/mat.h",
MAME_DIR .. "src/devices/bus/vsmile/vsmile_slot.cpp",
MAME_DIR .. "src/devices/bus/vsmile/vsmile_slot.h",
MAME_DIR .. "src/devices/bus/vsmile/rom.cpp",
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index a55cf443fdb..b1b068030fe 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -1580,7 +1580,7 @@ if (CPUS["M6502"]~=null) then
{ MAME_DIR .. "src/devices/cpu/m6502/om65ce02.lst", GEN_DIR .. "emu/cpu/m6502/m65ce02.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dm65ce02.lst" }, {"@echo Generating m65ce02 disassembler source file...", PYTHON .. " $(1) s m65ce02 $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/om6509.lst", GEN_DIR .. "emu/cpu/m6502/m6509.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dm6509.lst" }, {"@echo Generating m6509 disassembler source file...", PYTHON .. " $(1) s m6509 $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/om6510.lst", GEN_DIR .. "emu/cpu/m6502/m6510.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dm6510.lst" }, {"@echo Generating m6510 disassembler source file...", PYTHON .. " $(1) s m6510 $(<) $(2) $(@)" }},
- { MAME_DIR .. "src/devices/cpu/m6502/on2a03.lst", GEN_DIR .. "emu/cpu/m6502/n2a03.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dn2a03.lst" }, {"@echo Generating n2a03 disassembler source file...", PYTHON .. " $(1) s n2a03 $(<) $(2) $(@)" }},
+ { MAME_DIR .. "src/devices/cpu/m6502/on2a03.lst", GEN_DIR .. "emu/cpu/m6502/n2a03.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dn2a03.lst" }, {"@echo Generating n2a03 disassembler source file...", PYTHON .. " $(1) s n2a03_core $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/om740.lst" , GEN_DIR .. "emu/cpu/m6502/m740.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dm740.lst" }, {"@echo Generating m740 disassembler source file...", PYTHON .. " $(1) s m740 $(<) $(2) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/dr65c02.lst", GEN_DIR .. "emu/cpu/m6502/r65c02.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", }, {"@echo Generating r65c02 disassembler source file...", PYTHON .. " $(1) s r65c02 - $(<) $(@)" }},
{ MAME_DIR .. "src/devices/cpu/m6502/or65c19.lst", GEN_DIR .. "emu/cpu/m6502/r65c19.hxx", { MAME_DIR .. "src/devices/cpu/m6502/m6502make.py", MAME_DIR .. "src/devices/cpu/m6502/dr65c19.lst" }, {"@echo Generating r65c19 disassembler source file...", PYTHON .. " $(1) s r65c19 $(<) $(2) $(@)" }},
@@ -3014,6 +3014,7 @@ if (CPUS["NS32000"]~=null) then
files {
MAME_DIR .. "src/devices/cpu/ns32000/ns32000.cpp",
MAME_DIR .. "src/devices/cpu/ns32000/ns32000.h",
+ MAME_DIR .. "src/devices/cpu/ns32000/slave.h",
}
end
@@ -3319,3 +3320,13 @@ if (CPUS["UPD177X"]~=null or _OPTIONS["with-tools"]) then
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/upd177x/upd177xd.cpp")
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/upd177x/upd177xd.h")
end
+
+--------------------------------------------------
+-- Sanyo LC58 - Disassembler only
+--@src/devices/cpu/lc58/lc58.h,CPUS["LC58"] = true
+--------------------------------------------------
+
+if (CPUS["LC58"]~=null or _OPTIONS["with-tools"]) then
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/lc58/lc58d.cpp")
+ table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/lc58/lc58d.h")
+end
diff --git a/scripts/src/emu.lua b/scripts/src/emu.lua
index 89c7d3ccd20..d65ea40c21d 100644
--- a/scripts/src/emu.lua
+++ b/scripts/src/emu.lua
@@ -181,6 +181,7 @@ files {
MAME_DIR .. "src/emu/recording.h",
MAME_DIR .. "src/emu/render.cpp",
MAME_DIR .. "src/emu/render.h",
+ MAME_DIR .. "src/emu/rendertypes.h",
MAME_DIR .. "src/emu/rendfont.cpp",
MAME_DIR .. "src/emu/rendfont.h",
MAME_DIR .. "src/emu/rendlay.cpp",
diff --git a/scripts/src/lib.lua b/scripts/src/lib.lua
index a5ce6180857..edc68ee3c13 100644
--- a/scripts/src/lib.lua
+++ b/scripts/src/lib.lua
@@ -74,7 +74,10 @@ project "utils"
MAME_DIR .. "src/lib/util/jedparse.h",
MAME_DIR .. "src/lib/util/md5.cpp",
MAME_DIR .. "src/lib/util/md5.h",
+ MAME_DIR .. "src/lib/util/msdib.cpp",
+ MAME_DIR .. "src/lib/util/msdib.h",
MAME_DIR .. "src/lib/util/nanosvg.cpp",
+ MAME_DIR .. "src/lib/util/nanosvg.h",
MAME_DIR .. "src/lib/util/opresolv.cpp",
MAME_DIR .. "src/lib/util/opresolv.h",
MAME_DIR .. "src/lib/util/options.cpp",
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua
index 600c22f2746..ac96f03e4cc 100644
--- a/scripts/src/machine.lua
+++ b/scripts/src/machine.lua
@@ -4546,3 +4546,36 @@ if (MACHINES["ALPHA_8921"]~=null) then
MAME_DIR .. "src/devices/machine/alpha_8921.h",
}
end
+
+---------------------------------------------------
+--
+--@src/devices/machine/bl_handhelds_menucontrol.h,MACHINES["BL_HANDHELDS_MENUCONTROL"] = true
+---------------------------------------------------
+if (MACHINES["BL_HANDHELDS_MENUCONTROL"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/bl_handhelds_menucontrol.cpp",
+ MAME_DIR .. "src/devices/machine/bl_handhelds_menucontrol.h",
+ }
+end
+
+---------------------------------------------------
+--
+--@src/devices/machine/ns32081.h,MACHINES["NS32081"] = true
+---------------------------------------------------
+if (MACHINES["NS32081"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/ns32081.cpp",
+ MAME_DIR .. "src/devices/machine/ns32081.h",
+ }
+end
+
+---------------------------------------------------
+--
+--@src/devices/machine/ns32202.h,MACHINES["NS32202"] = true
+---------------------------------------------------
+if (MACHINES["NS32202"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/ns32202.cpp",
+ MAME_DIR .. "src/devices/machine/ns32202.h",
+ }
+end
diff --git a/scripts/src/main.lua b/scripts/src/main.lua
index 4d787bfbdaf..6ae28487563 100644
--- a/scripts/src/main.lua
+++ b/scripts/src/main.lua
@@ -151,10 +151,13 @@ end
.. " -s ALLOW_MEMORY_GROWTH=0"
.. " -s TOTAL_MEMORY=268435456"
.. " -s DISABLE_EXCEPTION_CATCHING=2"
- .. " -s EXCEPTION_CATCHING_WHITELIST=\"['__ZN15running_machine17start_all_devicesEv','__ZN12cli_frontend7executeEiPPc','__ZN8chd_file11open_commonEb','__ZN8chd_file13read_metadataEjjRNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE','__ZN8chd_file13read_metadataEjjRNSt3__26vectorIhNS0_9allocatorIhEEEE']\""
+ .. " -s EXCEPTION_CATCHING_WHITELIST=\"['__ZN15running_machine17start_all_devicesEv','__ZN12cli_frontend7executeEiPPc','__ZN8chd_file11open_commonEb','__ZN8chd_file13read_metadataEjjRNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE','__ZN8chd_file13read_metadataEjjRNSt3__26vectorIhNS0_9allocatorIhEEEE','__ZNK19netlist_mame_device19base_validity_checkER16validity_checker']\""
.. " -s EXPORTED_FUNCTIONS=\"['_main', '_malloc', '__ZN15running_machine30emscripten_get_running_machineEv', '__ZN15running_machine17emscripten_get_uiEv', '__ZN15running_machine20emscripten_get_soundEv', '__ZN15mame_ui_manager12set_show_fpsEb', '__ZNK15mame_ui_manager8show_fpsEv', '__ZN13sound_manager4muteEbh', '_SDL_PauseAudio', '_SDL_SendKeyboardKey', '__ZN15running_machine15emscripten_saveEPKc', '__ZN15running_machine15emscripten_loadEPKc', '__ZN15running_machine21emscripten_hard_resetEv', '__ZN15running_machine21emscripten_soft_resetEv', '__ZN15running_machine15emscripten_exitEv']\""
.. " -s EXTRA_EXPORTED_RUNTIME_METHODS=\"['cwrap']\""
.. " -s ERROR_ON_UNDEFINED_SYMBOLS=0"
+ .. " -s USE_WEBGL2=1"
+ .. " -s LEGACY_GL_EMULATION=1"
+ .. " -s GL_UNSAFE_OPTS=0"
.. " --pre-js " .. _MAKE.esc(MAME_DIR) .. "src/osd/modules/sound/js_sound.js"
.. " --post-js " .. _MAKE.esc(MAME_DIR) .. "scripts/resources/emscripten/emscripten_post.js"
.. " --embed-file " .. _MAKE.esc(MAME_DIR) .. "bgfx/chains@bgfx/chains"
@@ -179,7 +182,8 @@ end
end
postbuildcommands {
- os.getenv("EMSCRIPTEN") .. "/emcc " .. emccopts .. " $(TARGET) -o " .. _MAKE.esc(MAME_DIR) .. _OPTIONS["target"] .. _OPTIONS["subtarget"] .. ".js",
+ --os.getenv("EMSCRIPTEN") .. "/emcc " .. emccopts .. " $(TARGET) -o " .. _MAKE.esc(MAME_DIR) .. _OPTIONS["target"] .. _OPTIONS["subtarget"] .. ".js",
+ os.getenv("EMSCRIPTEN") .. "/emcc " .. emccopts .. " $(TARGET) -o " .. _MAKE.esc(MAME_DIR) .. _OPTIONS["target"] .. _OPTIONS["subtarget"] .. ".html",
}
end
diff --git a/scripts/src/mame/frontend.lua b/scripts/src/mame/frontend.lua
index 8253bf439b5..04e06bd2b6e 100644
--- a/scripts/src/mame/frontend.lua
+++ b/scripts/src/mame/frontend.lua
@@ -121,6 +121,8 @@ files {
MAME_DIR .. "src/frontend/mame/ui/inifile.h",
MAME_DIR .. "src/frontend/mame/ui/inputmap.cpp",
MAME_DIR .. "src/frontend/mame/ui/inputmap.h",
+ MAME_DIR .. "src/frontend/mame/ui/keyboard.cpp",
+ MAME_DIR .. "src/frontend/mame/ui/keyboard.h",
MAME_DIR .. "src/frontend/mame/ui/mainmenu.cpp",
MAME_DIR .. "src/frontend/mame/ui/mainmenu.h",
MAME_DIR .. "src/frontend/mame/ui/menu.cpp",
diff --git a/scripts/src/netlist.lua b/scripts/src/netlist.lua
index 442074f0215..ff21a35cde3 100644
--- a/scripts/src/netlist.lua
+++ b/scripts/src/netlist.lua
@@ -32,7 +32,7 @@ project "netlist"
}
includedirs {
- -- MAME_DIR .. "src/lib",
+ -- MAME_DIR .. "src/lib",
MAME_DIR .. "src/lib/netlist",
}
@@ -81,6 +81,7 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/plib/pmain.cpp",
MAME_DIR .. "src/lib/netlist/plib/pmain.h",
MAME_DIR .. "src/lib/netlist/plib/pmath.h",
+ MAME_DIR .. "src/lib/netlist/plib/pmatrix_cr.h",
MAME_DIR .. "src/lib/netlist/plib/pmempool.h",
MAME_DIR .. "src/lib/netlist/plib/pmulti_threading.h",
MAME_DIR .. "src/lib/netlist/plib/pomp.h",
@@ -123,7 +124,6 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/solver/nld_ms_sor.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_sor_mat.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_gmres.h",
- MAME_DIR .. "src/lib/netlist/solver/mat_cr.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_sm.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_w.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_direct_lu.h",
@@ -131,14 +131,17 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/devices/net_lib.cpp",
MAME_DIR .. "src/lib/netlist/devices/net_lib.h",
MAME_DIR .. "src/lib/netlist/devices/nld_9316_base.hxx",
- MAME_DIR .. "src/lib/netlist/devices/nld_2102A.cpp",
+ MAME_DIR .. "src/lib/netlist/devices/nld_2102a.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_tms4800.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4006.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4013.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4017.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4020.cpp",
+ MAME_DIR .. "src/lib/netlist/devices/nld_4029.cpp",
+ MAME_DIR .. "src/lib/netlist/devices/nld_4042.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4053.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4066.cpp",
+ MAME_DIR .. "src/lib/netlist/devices/nld_4076.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_4316.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_7448.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_7450.cpp",
@@ -170,8 +173,8 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/devices/nld_74393.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_74365.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_74ls629.cpp",
- MAME_DIR .. "src/lib/netlist/devices/nld_82S16.cpp",
- MAME_DIR .. "src/lib/netlist/devices/nld_82S115.cpp",
+ MAME_DIR .. "src/lib/netlist/devices/nld_82s16.cpp",
+ MAME_DIR .. "src/lib/netlist/devices/nld_82s115.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_8277.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_9310.cpp",
MAME_DIR .. "src/lib/netlist/devices/nld_9316.cpp",
@@ -202,9 +205,9 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/macro/nlm_otheric_lib.cpp",
MAME_DIR .. "src/lib/netlist/macro/nlm_roms_lib.cpp",
- MAME_DIR .. "src/lib/netlist/macro/modules/nlmod_RTEST.cpp",
- MAME_DIR .. "src/lib/netlist/macro/modules/nlmod_NE556_DIP.cpp",
- MAME_DIR .. "src/lib/netlist/macro/modules/nlmod_ICL8038_DIP.cpp",
+ MAME_DIR .. "src/lib/netlist/macro/modules/nlmod_rtest.cpp",
+ MAME_DIR .. "src/lib/netlist/macro/modules/nlmod_ne556_dip.cpp",
+ MAME_DIR .. "src/lib/netlist/macro/modules/nlmod_icl8038_dip.cpp",
MAME_DIR .. "src/lib/netlist/generated/static_solvers.cpp",
MAME_DIR .. "src/lib/netlist/generated/nld_devinc.h",
diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua
index a49d74dbc9e..bcbc9749c4b 100644
--- a/scripts/src/sound.lua
+++ b/scripts/src/sound.lua
@@ -10,6 +10,8 @@
----------------------------------------------------------------------------
files {
+ MAME_DIR .. "src/devices/sound/flt_biquad.cpp",
+ MAME_DIR .. "src/devices/sound/flt_biquad.h",
MAME_DIR .. "src/devices/sound/flt_vol.cpp",
MAME_DIR .. "src/devices/sound/flt_vol.h",
MAME_DIR .. "src/devices/sound/flt_rc.cpp",
@@ -657,6 +659,8 @@ if (SOUNDS["NES_APU"]~=null) then
MAME_DIR .. "src/devices/sound/nes_apu.cpp",
MAME_DIR .. "src/devices/sound/nes_apu.h",
MAME_DIR .. "src/devices/sound/nes_defs.h",
+ MAME_DIR .. "src/devices/sound/nes_apu_vt.cpp",
+ MAME_DIR .. "src/devices/sound/nes_apu_vt.h",
}
end
diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua
index 98d86d70a89..e1cc34196c4 100644
--- a/scripts/target/mame/arcade.lua
+++ b/scripts/target/mame/arcade.lua
@@ -542,7 +542,7 @@ MACHINES["MC6843"] = true
MACHINES["MC6846"] = true
MACHINES["MC6852"] = true
MACHINES["MC6854"] = true
---MACHINES["MC68328"] = true
+MACHINES["MC68328"] = true
MACHINES["MC68901"] = true
MACHINES["MCCS1850"] = true
MACHINES["M68307"] = true
@@ -823,6 +823,7 @@ BUSES["ZORRO"] = true
-- specify used file formats
--------------------------------------------------
+FORMATS["APOLLO_DSK"] = true
FORMATS["GUAB_DSK"] = true
FORMATS["AMI_DSK"] = true
FORMATS["SC3000_BIT"] = true
@@ -3607,6 +3608,10 @@ files {
MAME_DIR .. "src/mame/includes/vicdual.h",
MAME_DIR .. "src/mame/audio/vicdual.cpp",
MAME_DIR .. "src/mame/audio/vicdual.h",
+ MAME_DIR .. "src/mame/audio/nl_brdrline.cpp",
+ MAME_DIR .. "src/mame/audio/nl_brdrline.h",
+ MAME_DIR .. "src/mame/audio/nl_frogs.cpp",
+ MAME_DIR .. "src/mame/audio/nl_frogs.h",
MAME_DIR .. "src/mame/audio/vicdual-97271p.cpp",
MAME_DIR .. "src/mame/audio/vicdual-97271p.h",
MAME_DIR .. "src/mame/video/vicdual.cpp",
@@ -3620,8 +3625,6 @@ files {
MAME_DIR .. "src/mame/audio/invinco.h",
MAME_DIR .. "src/mame/audio/pulsar.cpp",
MAME_DIR .. "src/mame/audio/pulsar.h",
- MAME_DIR .. "src/mame/audio/tranqgun.cpp",
- MAME_DIR .. "src/mame/audio/tranqgun.h",
MAME_DIR .. "src/mame/drivers/zaxxon.cpp",
MAME_DIR .. "src/mame/includes/zaxxon.h",
MAME_DIR .. "src/mame/audio/zaxxon.cpp",
@@ -4799,6 +4802,7 @@ files {
MAME_DIR .. "src/mame/drivers/coinmstr.cpp",
MAME_DIR .. "src/mame/drivers/coinmvga.cpp",
MAME_DIR .. "src/mame/drivers/comebaby.cpp",
+ MAME_DIR .. "src/mame/drivers/cowtipping.cpp",
MAME_DIR .. "src/mame/drivers/crazybal.cpp",
MAME_DIR .. "src/mame/drivers/cromptons.cpp",
MAME_DIR .. "src/mame/drivers/cupidon.cpp",
diff --git a/scripts/target/mame/ci.lua b/scripts/target/mame/ci.lua
index d710f3a4ea9..d4f1014864d 100644
--- a/scripts/target/mame/ci.lua
+++ b/scripts/target/mame/ci.lua
@@ -120,8 +120,8 @@ function createProjects_mame_ci(_target, _subtarget)
}
files{
- MAME_DIR .. "src/mame/audio/nl_carpolo.h",
MAME_DIR .. "src/mame/audio/nl_carpolo.cpp",
+ MAME_DIR .. "src/mame/audio/nl_carpolo.h",
MAME_DIR .. "src/mame/drivers/carpolo.cpp",
MAME_DIR .. "src/mame/includes/carpolo.h",
MAME_DIR .. "src/mame/machine/carpolo.cpp",
@@ -138,10 +138,10 @@ files{
MAME_DIR .. "src/mame/audio/exidy440.cpp",
MAME_DIR .. "src/mame/audio/exidy440.h",
MAME_DIR .. "src/mame/drivers/starfire.cpp",
- MAME_DIR .. "src/mame/audio/nl_fireone.h",
MAME_DIR .. "src/mame/audio/nl_fireone.cpp",
- MAME_DIR .. "src/mame/audio/nl_starfire.h",
+ MAME_DIR .. "src/mame/audio/nl_fireone.h",
MAME_DIR .. "src/mame/audio/nl_starfire.cpp",
+ MAME_DIR .. "src/mame/audio/nl_starfire.h",
MAME_DIR .. "src/mame/includes/starfire.h",
MAME_DIR .. "src/mame/video/starfire.cpp",
MAME_DIR .. "src/mame/drivers/vertigo.cpp",
@@ -165,6 +165,8 @@ files{
MAME_DIR .. "src/mame/audio/williams.cpp",
MAME_DIR .. "src/mame/audio/williams.h",
MAME_DIR .. "src/mame/video/williams.cpp",
+ MAME_DIR .. "src/mame/audio/s11c_bg.cpp",
+ MAME_DIR .. "src/mame/audio/s11c_bg.h",
MAME_DIR .. "src/mame/drivers/gaelco.cpp",
MAME_DIR .. "src/mame/includes/gaelco.h",
MAME_DIR .. "src/mame/video/gaelco.cpp",
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index cc704293f0f..1401795fd94 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -779,6 +779,9 @@ MACHINES["XC1700E"] = true
MACHINES["EDLC"] = true
MACHINES["WTL3132"] = true
MACHINES["CXD1185"] = true
+MACHINES["BL_HANDHELDS_MENUCONTROL"] = true
+MACHINES["NS32081"] = true
+MACHINES["NS32202"] = true
--------------------------------------------------
-- specify available bus cores
@@ -839,6 +842,7 @@ BUSES["ELECTRON"] = true
BUSES["ELECTRON_CART"] = true
BUSES["EP64"] = true
BUSES["EPSON_SIO"] = true
+BUSES["FMT_SCSI"] = true
BUSES["GAMATE"] = true
BUSES["GAMEBOY"] = true
BUSES["GAMEGEAR"] = true
@@ -1167,6 +1171,7 @@ function linkProjects_mame_mess(_target, _subtarget)
"cccp",
"cce",
"ccs",
+ "ceres",
"chessking",
"chromatics",
"chrysler",
@@ -1747,6 +1752,7 @@ files {
MAME_DIR .. "src/mame/machine/lisa.cpp",
MAME_DIR .. "src/mame/drivers/lwriter.cpp",
MAME_DIR .. "src/mame/drivers/mac128.cpp",
+ MAME_DIR .. "src/mame/drivers/macquadra700.cpp",
MAME_DIR .. "src/mame/drivers/mac.cpp",
MAME_DIR .. "src/mame/includes/mac.h",
MAME_DIR .. "src/mame/machine/egret.cpp",
@@ -1862,10 +1868,8 @@ files {
MAME_DIR .. "src/mame/drivers/rx78.cpp",
MAME_DIR .. "src/mame/drivers/tamag1.cpp",
MAME_DIR .. "src/mame/drivers/wswan.cpp",
- MAME_DIR .. "src/mame/includes/wswan.h",
MAME_DIR .. "src/mame/audio/wswan.cpp",
MAME_DIR .. "src/mame/audio/wswan.h",
- MAME_DIR .. "src/mame/machine/wswan.cpp",
MAME_DIR .. "src/mame/video/wswan.cpp",
MAME_DIR .. "src/mame/video/wswan.h",
MAME_DIR .. "src/mame/drivers/bandai_design_master.cpp",
@@ -2018,6 +2022,11 @@ files {
MAME_DIR .. "src/mame/drivers/ccs2810.cpp",
}
+createMESSProjects(_target, _subtarget, "ceres")
+files {
+ MAME_DIR .. "src/mame/drivers/ceres.cpp",
+}
+
createMESSProjects(_target, _subtarget, "chessking")
files {
MAME_DIR .. "src/mame/drivers/cking_master.cpp",
@@ -2609,6 +2618,8 @@ files {
MAME_DIR .. "src/mame/drivers/informer_213.cpp",
MAME_DIR .. "src/mame/machine/informer_207_376_kbd.cpp",
MAME_DIR .. "src/mame/machine/informer_207_376_kbd.h",
+ MAME_DIR .. "src/mame/machine/informer_213_kbd.cpp",
+ MAME_DIR .. "src/mame/machine/informer_213_kbd.h",
}
createMESSProjects(_target, _subtarget, "intel")
@@ -4024,6 +4035,7 @@ files {
MAME_DIR .. "src/mame/machine/generalplus_gpl16250.cpp",
MAME_DIR .. "src/mame/machine/generalplus_gpl16250.h",
MAME_DIR .. "src/mame/drivers/generalplus_gpl32612.cpp",
+ MAME_DIR .. "src/mame/drivers/generalplus_gpl162xx_lcdtype.cpp",
MAME_DIR .. "src/mame/drivers/generalplus_gpl_unknown.cpp",
MAME_DIR .. "src/mame/drivers/xavix.cpp",
MAME_DIR .. "src/mame/includes/xavix.h",
@@ -4281,6 +4293,7 @@ files {
MAME_DIR .. "src/mame/drivers/aaa.cpp",
MAME_DIR .. "src/mame/drivers/acd.cpp",
MAME_DIR .. "src/mame/drivers/aceex.cpp",
+ MAME_DIR .. "src/mame/drivers/adacp150.cpp",
MAME_DIR .. "src/mame/drivers/aid80f.cpp",
MAME_DIR .. "src/mame/drivers/akaiax80.cpp",
MAME_DIR .. "src/mame/drivers/alcat7100.cpp",
diff --git a/scripts/target/mame/nl.lua b/scripts/target/mame/nl.lua
index 1124c49b641..15306b6d881 100644
--- a/scripts/target/mame/nl.lua
+++ b/scripts/target/mame/nl.lua
@@ -288,6 +288,28 @@ files{
MAME_DIR .. "src/mame/machine/nl_palestra.cpp",
MAME_DIR .. "src/mame/machine/nl_palestra.h",
+ MAME_DIR .. "src/mame/drivers/vicdual.cpp",
+ MAME_DIR .. "src/mame/includes/vicdual.h",
+ MAME_DIR .. "src/mame/audio/vicdual.cpp",
+ MAME_DIR .. "src/mame/audio/vicdual.h",
+ MAME_DIR .. "src/mame/audio/nl_brdrline.cpp",
+ MAME_DIR .. "src/mame/audio/nl_brdrline.h",
+ MAME_DIR .. "src/mame/audio/nl_frogs.cpp",
+ MAME_DIR .. "src/mame/audio/nl_frogs.h",
+ MAME_DIR .. "src/mame/audio/vicdual-97271p.cpp",
+ MAME_DIR .. "src/mame/audio/vicdual-97271p.h",
+ MAME_DIR .. "src/mame/video/vicdual.cpp",
+ MAME_DIR .. "src/mame/video/vicdual-97269pb.cpp",
+ MAME_DIR .. "src/mame/video/vicdual-97269pb.h",
+ MAME_DIR .. "src/mame/audio/carnival.cpp",
+ MAME_DIR .. "src/mame/audio/carnival.h",
+ MAME_DIR .. "src/mame/audio/depthch.cpp",
+ MAME_DIR .. "src/mame/audio/depthch.h",
+ MAME_DIR .. "src/mame/audio/invinco.cpp",
+ MAME_DIR .. "src/mame/audio/invinco.h",
+ MAME_DIR .. "src/mame/audio/pulsar.cpp",
+ MAME_DIR .. "src/mame/audio/pulsar.h",
+
MAME_DIR .. "src/mame/machine/segacrpt_device.cpp",
MAME_DIR .. "src/mame/machine/segacrpt_device.h",
MAME_DIR .. "src/mame/drivers/segag80r.cpp",
diff --git a/scripts/target/mame/tiny.lua b/scripts/target/mame/tiny.lua
index e02b47c4198..89d3e36284f 100644
--- a/scripts/target/mame/tiny.lua
+++ b/scripts/target/mame/tiny.lua
@@ -108,15 +108,15 @@ function createProjects_mame_tiny(_target, _subtarget)
}
files{
- MAME_DIR .. "src/mame/audio/nl_carpolo.h",
MAME_DIR .. "src/mame/audio/nl_carpolo.cpp",
+ MAME_DIR .. "src/mame/audio/nl_carpolo.h",
MAME_DIR .. "src/mame/drivers/carpolo.cpp",
MAME_DIR .. "src/mame/includes/carpolo.h",
MAME_DIR .. "src/mame/machine/carpolo.cpp",
MAME_DIR .. "src/mame/video/carpolo.cpp",
+ MAME_DIR .. "src/mame/audio/circus.cpp",
MAME_DIR .. "src/mame/drivers/circus.cpp",
MAME_DIR .. "src/mame/includes/circus.h",
- MAME_DIR .. "src/mame/audio/circus.cpp",
MAME_DIR .. "src/mame/video/circus.cpp",
MAME_DIR .. "src/mame/drivers/exidy.cpp",
MAME_DIR .. "src/mame/includes/exidy.h",
@@ -147,11 +147,13 @@ files{
MAME_DIR .. "src/mame/includes/gridlee.h",
MAME_DIR .. "src/mame/audio/gridlee.cpp",
MAME_DIR .. "src/mame/video/gridlee.cpp",
+ MAME_DIR .. "src/mame/audio/s11c_bg.cpp",
+ MAME_DIR .. "src/mame/audio/s11c_bg.h",
+ MAME_DIR .. "src/mame/audio/williams.cpp",
+ MAME_DIR .. "src/mame/audio/williams.h",
MAME_DIR .. "src/mame/drivers/williams.cpp",
MAME_DIR .. "src/mame/includes/williams.h",
MAME_DIR .. "src/mame/machine/williams.cpp",
- MAME_DIR .. "src/mame/audio/williams.cpp",
- MAME_DIR .. "src/mame/audio/williams.h",
MAME_DIR .. "src/mame/video/williams.cpp",
MAME_DIR .. "src/mame/drivers/gaelco.cpp",
MAME_DIR .. "src/mame/includes/gaelco.h",
diff --git a/scripts/target/zexall/zexall.lua b/scripts/target/zexall/zexall.lua
index 008ea252d0c..4b07b2ca061 100644
--- a/scripts/target/zexall/zexall.lua
+++ b/scripts/target/zexall/zexall.lua
@@ -2,6 +2,8 @@ STANDALONE = true
CPUS["Z80"] = true
+MACHINES["Z80DAISY"] = true
+
function standalone()
files{
MAME_DIR .. "src/zexall/main.cpp",
diff --git a/src/devices/bus/a2bus/a2bus.cpp b/src/devices/bus/a2bus/a2bus.cpp
index ae5dbf82643..e09671f8f16 100644
--- a/src/devices/bus/a2bus/a2bus.cpp
+++ b/src/devices/bus/a2bus/a2bus.cpp
@@ -205,8 +205,6 @@ uint8_t a2bus_device::get_a2bus_nmi_mask()
void a2bus_device::set_irq_line(int state, int slot)
{
- m_out_irq_cb(state);
-
if (state == CLEAR_LINE)
{
m_slot_irq_mask &= ~(1<<slot);
@@ -215,6 +213,8 @@ void a2bus_device::set_irq_line(int state, int slot)
{
m_slot_irq_mask |= (1<<slot);
}
+
+ m_out_irq_cb(state);
}
void a2bus_device::set_nmi_line(int state, int slot)
diff --git a/src/devices/bus/a2bus/a2hsscsi.cpp b/src/devices/bus/a2bus/a2hsscsi.cpp
index 98c612dae78..20342e6fd14 100644
--- a/src/devices/bus/a2bus/a2hsscsi.cpp
+++ b/src/devices/bus/a2bus/a2hsscsi.cpp
@@ -2,7 +2,7 @@
// copyright-holders:R. Belmont
/*********************************************************************
- a2hsscsi.c
+ a2hsscsi.cpp
Implementation of the Apple II High Speed SCSI Card
@@ -101,7 +101,8 @@ a2bus_hsscsi_device::a2bus_hsscsi_device(const machine_config &mconfig, device_t
device_t(mconfig, type, tag, owner, clock),
device_a2bus_card_interface(mconfig, *this),
m_ncr5380(*this, SCSI_5380_TAG),
- m_scsibus(*this, SCSI_BUS_TAG), m_rom(nullptr), m_rambank(0), m_rombank(0), m_drq(0), m_bank(0), m_816block(false), m_c0ne(0), m_c0nf(0)
+ m_scsibus(*this, SCSI_BUS_TAG), m_rom(*this, SCSI_ROM_REGION), m_rambank(0), m_rombank(0), m_drq(0), m_bank(0), m_c0ne(0), m_c0nf(0),
+ m_dma_addr(0), m_dma_size(0)
{
}
@@ -116,8 +117,6 @@ a2bus_hsscsi_device::a2bus_hsscsi_device(const machine_config &mconfig, const ch
void a2bus_hsscsi_device::device_start()
{
- m_rom = machine().root_device().memregion(this->subtag(SCSI_ROM_REGION).c_str())->base();
-
memset(m_ram, 0, 8192);
save_item(NAME(m_ram));
@@ -125,15 +124,16 @@ void a2bus_hsscsi_device::device_start()
save_item(NAME(m_rombank));
save_item(NAME(m_bank));
save_item(NAME(m_drq));
- save_item(NAME(m_816block));
+ save_item(NAME(m_dma_addr));
+ save_item(NAME(m_dma_size));
}
void a2bus_hsscsi_device::device_reset()
{
m_rambank = 0;
m_rombank = 0;
+ m_dma_addr = m_dma_size = 0;
m_c0ne = m_c0nf = 0;
- m_816block = false;
}
@@ -151,13 +151,35 @@ uint8_t a2bus_hsscsi_device::read_c0nx(uint8_t offset)
case 3:
case 4:
case 5:
- case 6:
case 7:
// logerror("Read 5380 @ %x\n", offset);
return m_ncr5380->read(offset);
- case 0xc:
- return 0x00; // indicate watchdog?
+ case 6:
+ if (m_dma_control & 1) // pseudo-DMA?
+ {
+ return m_ncr5380->dma_r();
+ }
+ else
+ {
+ //printf("Read 5380 PIO data (%s)\n", machine().describe_context().c_str());
+ return m_ncr5380->read(offset);
+ }
+
+ case 8: // DMA address low
+ return m_dma_addr & 0xff;
+
+ case 9: // DMA address high
+ return (m_dma_addr >> 8) & 0xff;
+
+ case 0xa: // DMA size low
+ return m_dma_size & 0xff;
+
+ case 0xb: // DMA size high
+ return (m_dma_size >> 8) & 0xff;
+
+ case 0xc: // DMA control
+ return m_dma_control;
case 0xe: // code at cf32 wants to RMW this without killing the ROM bank
return m_c0ne;
@@ -166,7 +188,7 @@ uint8_t a2bus_hsscsi_device::read_c0nx(uint8_t offset)
return m_c0nf;
default:
- logerror("Read c0n%x (%s)\n", offset, machine().describe_context());
+ logerror("Read c0n%x (%s)\n", offset, machine().describe_context().c_str());
break;
}
@@ -182,7 +204,17 @@ void a2bus_hsscsi_device::write_c0nx(uint8_t offset, uint8_t data)
{
switch (offset)
{
- case 0:
+ case 0: // data out register; in PDMA mode, it's assumed this goes to DMA as reads do
+ if (m_dma_control & 1)
+ {
+ m_ncr5380->dma_w(data);
+ }
+ else
+ {
+ m_ncr5380->write(offset, data);
+ }
+ break;
+
case 1:
case 2:
case 3:
@@ -193,25 +225,39 @@ void a2bus_hsscsi_device::write_c0nx(uint8_t offset, uint8_t data)
// logerror("%02x to 5380 reg %x\n", data, offset);
m_ncr5380->write(offset, data);
break;
-#if 0
+
case 8: // DMA address low
+ //printf("%02x to DMA adr low\n", data);
+ m_dma_addr &= 0xff00;
+ m_dma_addr |= data;
break;
case 9: // DMA address high
+ //printf("%02x to DMA adr high\n", data);
+ m_dma_addr &= 0x00ff;
+ m_dma_addr |= (data << 8);
break;
case 0xa: // DMA count low
+ //printf("%02x to DMA count low\n", data);
+ m_dma_size &= 0xff00;
+ m_dma_size |= data;
break;
case 0xb: // DMA count high
+ //printf("%02x to DMA count high\n", data);
+ m_dma_size &= 0x00ff;
+ m_dma_size |= (data << 8);
break;
case 0xc: // DMA control
+ //printf("%02x to DMA control\n", data);
+ m_dma_control &= ~0x2b; // clear the read/write bits
+ m_dma_control |= (data & 0x2b);
break;
-#endif
case 0xd: // DMA enable / reset
- logerror("%02x to DMA enable/reset\n", data);
+ //printf("%02x to DMA enable/reset\n", data);
if (data & 0x2)
{
// logerror("Resetting SCSI: %02x at %s\n", data, machine().describe_context());
@@ -222,17 +268,17 @@ void a2bus_hsscsi_device::write_c0nx(uint8_t offset, uint8_t data)
case 0xe:
m_c0ne = data;
m_rombank = (data & 0x1f) * 0x400;
- logerror("c0ne to %x (ROM bank %x)\n", data & 0x1f, m_rombank);
+ //logerror("c0ne to %x (ROM bank %x)\n", data & 0x1f, m_rombank);
break;
case 0xf:
m_c0nf = data;
m_rambank = (data & 0x7) * 0x400;
- logerror("c0nf to %x (RAM bank %x)\n", data & 0x7, m_rambank);
+ //logerror("c0nf to %x (RAM bank %x)\n", data & 0x7, m_rambank);
break;
default:
- logerror("Write %02x to c0n%x (%s)\n", data, offset, machine().describe_context());
+ logerror("Write %02x to c0n%x (%s)\n", data, offset, machine().describe_context().c_str());
break;
}
}
@@ -263,11 +309,6 @@ uint8_t a2bus_hsscsi_device::read_c800(uint16_t offset)
if (offset < 0x400)
{
// logerror("Read RAM at %x = %02x\n", offset+m_rambank, m_ram[offset + m_rambank]);
- if (m_816block)
- {
- return m_ncr5380->dma_r();
- }
-
return m_ram[offset + m_rambank];
}
else
@@ -284,18 +325,12 @@ void a2bus_hsscsi_device::write_c800(uint16_t offset, uint8_t data)
if (offset < 0x400)
{
// logerror("%02x to RAM at %x\n", data, offset+m_rambank);
- if (m_816block)
- {
- m_ncr5380->dma_w(data);
- }
- else
- {
- m_ram[offset + m_rambank] = data;
- }
+ m_ram[offset + m_rambank] = data;
}
}
WRITE_LINE_MEMBER( a2bus_hsscsi_device::drq_w )
{
m_drq = (state ? 0x80 : 0x00);
+// printf("DRQ to %d\n", state);
}
diff --git a/src/devices/bus/a2bus/a2hsscsi.h b/src/devices/bus/a2bus/a2hsscsi.h
index 905de8b620d..36a5a9df15b 100644
--- a/src/devices/bus/a2bus/a2hsscsi.h
+++ b/src/devices/bus/a2bus/a2hsscsi.h
@@ -50,15 +50,16 @@ protected:
required_device<ncr53c80_device> m_ncr5380;
required_device<nscsi_bus_device> m_scsibus;
+ required_region_ptr<u8> m_rom;
private:
- uint8_t *m_rom;
uint8_t m_ram[8192]; // 8 banks of 1024 bytes
int m_rambank, m_rombank;
uint8_t m_drq;
uint8_t m_bank;
- bool m_816block;
+ uint8_t m_dma_control;
uint8_t m_c0ne, m_c0nf;
+ uint16_t m_dma_addr, m_dma_size;
};
// device type definition
diff --git a/src/devices/bus/a2bus/a2mcms.cpp b/src/devices/bus/a2bus/a2mcms.cpp
index f9de57897f8..1ef164aff41 100644
--- a/src/devices/bus/a2bus/a2mcms.cpp
+++ b/src/devices/bus/a2bus/a2mcms.cpp
@@ -206,7 +206,7 @@ mcms_device::mcms_device(const machine_config &mconfig, const char *tag, device_
void mcms_device::device_start()
{
m_write_irq.resolve();
- m_stream = stream_alloc_legacy(0, 2, 31250);
+ m_stream = stream_alloc(0, 2, 31250);
m_timer = timer_alloc(0, nullptr);
m_clrtimer = timer_alloc(1, nullptr);
m_enabled = false;
@@ -252,20 +252,19 @@ void mcms_device::device_timer(emu_timer &timer, device_timer_id tid, int param,
}
}
-void mcms_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mcms_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outL, *outR;
int i, v;
uint16_t wptr;
int8_t sample;
int32_t mixL, mixR;
- outL = outputs[1];
- outR = outputs[0];
+ auto &outL = outputs[1];
+ auto &outR = outputs[0];
if (m_enabled)
{
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outL.samples(); i++)
{
mixL = mixR = 0;
@@ -286,16 +285,14 @@ void mcms_device::sound_stream_update_legacy(sound_stream &stream, stream_sample
}
}
- outL[i] = (mixL * m_mastervol)>>9;
- outR[i] = (mixR * m_mastervol)>>9;
+ outL.put_int(i, mixL * m_mastervol, 32768 << 9);
+ outR.put_int(i, mixR * m_mastervol, 32768 << 9);
}
}
else
{
- for (i = 0; i < samples; i++)
- {
- outL[i] = outR[i] = 0;
- }
+ outL.fill(0);
+ outR.fill(0);
}
}
diff --git a/src/devices/bus/a2bus/a2mcms.h b/src/devices/bus/a2bus/a2mcms.h
index 11e8b332ee0..487c6ddb7a7 100644
--- a/src/devices/bus/a2bus/a2mcms.h
+++ b/src/devices/bus/a2bus/a2mcms.h
@@ -42,7 +42,7 @@ protected:
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_stream;
diff --git a/src/devices/bus/a2bus/a2mockingboard.cpp b/src/devices/bus/a2bus/a2mockingboard.cpp
index 167c7dc2f6f..c7f5fda534d 100644
--- a/src/devices/bus/a2bus/a2mockingboard.cpp
+++ b/src/devices/bus/a2bus/a2mockingboard.cpp
@@ -53,7 +53,7 @@ void a2bus_ayboard_device::add_common_devices(machine_config &config)
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
AY8913(config, m_ay1, 1022727);
- m_ay1->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
+ m_ay1->add_route(ALL_OUTPUTS, "lspeaker", 0.5);
}
void a2bus_ayboard_device::device_add_mconfig(machine_config &config)
@@ -61,7 +61,7 @@ void a2bus_ayboard_device::device_add_mconfig(machine_config &config)
add_common_devices(config);
AY8913(config, m_ay2, 1022727);
- m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
+ m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
}
void a2bus_mockingboard_device::device_add_mconfig(machine_config &config)
@@ -72,7 +72,7 @@ void a2bus_mockingboard_device::device_add_mconfig(machine_config &config)
m_via1->cb2_handler().set(FUNC(a2bus_mockingboard_device::write_via1_cb2));
AY8913(config, m_ay2, 1022727);
- m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
+ m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
VOTRAX_SC01(config, m_sc01, 1022727);
m_sc01->ar_callback().set(m_via1, FUNC(via6522_device::write_cb1));
@@ -92,9 +92,9 @@ void a2bus_phasor_device::device_add_mconfig(machine_config &config)
AY8913(config, m_ay2, 1022727);
AY8913(config, m_ay3, 1022727);
AY8913(config, m_ay4, 1022727);
- m_ay2->add_route(ALL_OUTPUTS, "lspeaker2", 1.0);
- m_ay3->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
- m_ay4->add_route(ALL_OUTPUTS, "rspeaker2", 1.0);
+ m_ay2->add_route(ALL_OUTPUTS, "lspeaker2", 0.5);
+ m_ay3->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
+ m_ay4->add_route(ALL_OUTPUTS, "rspeaker2", 0.5);
}
void a2bus_echoplus_device::device_add_mconfig(machine_config &config)
@@ -102,7 +102,7 @@ void a2bus_echoplus_device::device_add_mconfig(machine_config &config)
add_common_devices(config);
AY8913(config, m_ay2, 1022727);
- m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
+ m_ay2->add_route(ALL_OUTPUTS, "rspeaker", 0.5);
SPEAKER(config, "echosp").front_center();
TMS5220(config, m_tms, 640000);
@@ -414,16 +414,35 @@ void a2bus_phasor_device::via2_out_b(uint8_t data)
}
}
+void a2bus_phasor_device::set_clocks()
+{
+ if (m_native)
+ {
+ m_ay1->set_clock(1022727*2);
+ m_ay2->set_clock(1022727*2);
+ m_ay3->set_clock(1022727*2);
+ m_ay4->set_clock(1022727*2);
+ }
+ else
+ {
+ m_ay1->set_clock(1022727);
+ m_ay2->set_clock(1022727);
+ m_ay3->set_clock(1022727);
+ m_ay4->set_clock(1022727);
+ }
+}
uint8_t a2bus_phasor_device::read_c0nx(uint8_t offset)
{
m_native = BIT(offset, 0);
+ set_clocks();
return 0xff;
}
void a2bus_phasor_device::write_c0nx(uint8_t offset, uint8_t data)
{
m_native = BIT(offset, 0);
+ set_clocks();
}
uint8_t a2bus_echoplus_device::read_c0nx(uint8_t offset)
diff --git a/src/devices/bus/a2bus/a2mockingboard.h b/src/devices/bus/a2bus/a2mockingboard.h
index 6d4aa8e73af..44acff10006 100644
--- a/src/devices/bus/a2bus/a2mockingboard.h
+++ b/src/devices/bus/a2bus/a2mockingboard.h
@@ -97,6 +97,8 @@ protected:
required_device<ay8913_device> m_ay4;
private:
+ void set_clocks();
+
bool m_native;
};
diff --git a/src/devices/bus/a2bus/a2ultraterm.cpp b/src/devices/bus/a2bus/a2ultraterm.cpp
index 7b6caa40624..e8d5972e4ec 100644
--- a/src/devices/bus/a2bus/a2ultraterm.cpp
+++ b/src/devices/bus/a2bus/a2ultraterm.cpp
@@ -304,11 +304,10 @@ void a2bus_videx160_device::write_c800(uint16_t offset, uint8_t data)
MC6845_UPDATE_ROW( a2bus_videx160_device::crtc_update_row )
{
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
uint16_t chr_base = ra;
- int i;
- for ( i = 0; i < x_count; i++ )
+ for ( int i = 0; i < x_count; i++ )
{
uint16_t offset = ( ma + i );
uint8_t chr = m_ram[ offset ];
diff --git a/src/devices/bus/a2bus/a2videoterm.cpp b/src/devices/bus/a2bus/a2videoterm.cpp
index b0fda659783..839fa19e74a 100644
--- a/src/devices/bus/a2bus/a2videoterm.cpp
+++ b/src/devices/bus/a2bus/a2videoterm.cpp
@@ -347,7 +347,7 @@ void a2bus_videx80_device::write_c800(uint16_t offset, uint8_t data)
MC6845_UPDATE_ROW( a2bus_videx80_device::crtc_update_row )
{
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
uint16_t chr_base = ra; //( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
for (int i = 0; i < x_count; i++)
diff --git a/src/devices/bus/a2bus/computereyes2.cpp b/src/devices/bus/a2bus/computereyes2.cpp
index b8a80819023..b8dcab00373 100644
--- a/src/devices/bus/a2bus/computereyes2.cpp
+++ b/src/devices/bus/a2bus/computereyes2.cpp
@@ -196,22 +196,22 @@ void a2bus_computereyes2_device::write_c0nx(uint8_t offset, uint8_t data)
m_x = m_y = 0;
std::fill_n(m_a2_bitmap, 280*193, 0);
- m_bitmap = &m_picture->get_bitmap();
- if (m_bitmap)
+ const bitmap_argb32 &bitmap = m_picture->get_bitmap();
+ if (bitmap.valid())
{
// convert arbitrary sized ARGB32 image to a 188x193 image with 256 levels of grayscale
- double stepx = (double)m_bitmap->width() / 188.0;
- double stepy = (double)m_bitmap->height() / 193.0;
+ double stepx = (double)bitmap.width() / 188.0;
+ double stepy = (double)bitmap.height() / 193.0;
for (int y = 0; y < 193; y++)
{
for (int x = 0; x < 280; x++)
{
- u32 pixel = m_bitmap->pix((int)((double)y * stepy), (int)((double)x * stepx));
- double mono = ((0.2126 * (double)(((pixel>>16) & 0xff) / 255.0)) +
- (0.7152 * (double)(((pixel>>8) & 0xff) / 255.0)) +
- (0.0722 * (double)((pixel& 0xff) / 255.0)));
- m_a2_bitmap[(y*280)+x] = (u8)(mono * 255.0);
+ u32 pixel = bitmap.pix(int((double)y * stepy), int((double)x * stepx));
+ double mono = ((0.2126 * double(((pixel>>16) & 0xff) / 255.0)) +
+ (0.7152 * double(((pixel>>8) & 0xff) / 255.0)) +
+ (0.0722 * double((pixel& 0xff) / 255.0)));
+ m_a2_bitmap[(y*280)+x] = u8(mono * 255.0);
}
}
}
diff --git a/src/devices/bus/a2bus/computereyes2.h b/src/devices/bus/a2bus/computereyes2.h
index 31856f08813..a69600b6de2 100644
--- a/src/devices/bus/a2bus/computereyes2.h
+++ b/src/devices/bus/a2bus/computereyes2.h
@@ -46,7 +46,6 @@ private:
u8 m_a2_bitmap[280*193];
u8 m_threshold;
bool m_bActive;
- bitmap_argb32 *m_bitmap;
};
// device type definition
diff --git a/src/devices/bus/a2bus/mouse.cpp b/src/devices/bus/a2bus/mouse.cpp
index 03b219cf72e..e5c2e7fcf84 100644
--- a/src/devices/bus/a2bus/mouse.cpp
+++ b/src/devices/bus/a2bus/mouse.cpp
@@ -299,17 +299,15 @@ void a2bus_mouse_device::mcu_port_c_w(uint8_t data)
template <unsigned AXIS, u8 DIR, u8 CLK> void a2bus_mouse_device::update_axis()
{
- // read the axis
+ // read the axis and check for changes
const int new_m = m_mousexy[AXIS]->read();
-
- // did it change?
int diff = new_m - m_last[AXIS];
// check for wrap
if (diff > 0x80)
- diff = 0x100 - diff;
- if (diff < -0x80)
- diff = -0x100 - diff;
+ diff -= 0x100;
+ else if (diff < -0x80)
+ diff += 0x100;
m_count[AXIS] += diff;
m_last[AXIS] = new_m;
diff --git a/src/devices/bus/a2bus/sider.cpp b/src/devices/bus/a2bus/sider.cpp
new file mode 100644
index 00000000000..d2722c8bb77
--- /dev/null
+++ b/src/devices/bus/a2bus/sider.cpp
@@ -0,0 +1,296 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ sider.cpp
+
+ Implementation of the First Class Peripherals / Advanced Tech Services / Xebec Sider cards
+
+ Sider 1: based on Xebec SASI hardware, with Xebec firmware. Requires HDD with 256 byte sectors
+ and special formatting - not compatible with standard .po/.hdv type images.
+
+ Sider 2: Same hardware, new firmware that's fully ProDOS compliant including 512 byte sectors.
+ Sectors are interleaved: the first byte is the byte that would be at 0, the second byte is the byte that would be at $100,
+ the third is the byte at $1, the fourth at $101, and so on. So this is also not compatible with standard images.
+
+ This command-line program will convert a standard image to work with Sider 2. First parameter is the input filename,
+ second parameter is the output filename. No error checking is done, if the input file doesn't exist it'll probably crash.
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+
+ static char block[512];
+ static char blockout[512];
+
+ int main(int argc, char *argv[])
+ {
+ FILE *in, *out;
+
+ in = fopen(argv[1], "rb");
+ out = fopen(argv[2], "wb");
+
+ int len = 0;
+ fseek(in, 0, SEEK_END);
+ len = ftell(in);
+ fseek(in, 0, SEEK_SET);
+
+ for (int bnum = 0; bnum < (len / 512); bnum++)
+ {
+ fread(block, 512, 1, in);
+ for (int byte = 0; byte < 256; byte++)
+ {
+ blockout[byte*2] = block[byte];
+ blockout[(byte*2)+1] = block[byte+256];
+ }
+ fwrite(blockout, 512, 1, out);
+ printf("block %d\n", bnum);
+ }
+
+ fclose(out);
+ fclose(in);
+ return 0;
+ }
+
+ --------------------------------------
+
+ $C0(n+8)X space:
+ $0: read state / write latch
+ $1: read data / write control
+
+ State:
+ b3: /Busy
+ b4: /Message
+ b5: I/O
+ b6: C/D
+ b7: REQ
+
+ Control:
+ b4: drive contents of output latch onto the SASI bus (reverse logic; latch is driven when this bit is clear)
+ b5: reset bus
+ b6: /BSY
+ b7: /SEL
+
+*********************************************************************/
+
+#include "emu.h"
+#include "sider.h"
+#include "bus/scsi/scsihd.h"
+#include "bus/scsi/s1410.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(A2BUS_SIDER2, a2bus_sider2card_device, "a2sider2", "First Class Peripherals Sider 2 SASI Card")
+DEFINE_DEVICE_TYPE(A2BUS_SIDER1, a2bus_sider1card_device, "a2sider1", "First Class Peripherals Sider 1 SASI Card")
+
+#define SASI_ROM_REGION "sasi_rom"
+
+ROM_START( sider2 )
+ ROM_REGION(0x800, SASI_ROM_REGION, 0)
+ ROM_LOAD( "atsv22_a02a9baad2262a8a49ecea843f602124.bin", 0x000000, 0x000800, CRC(97773a0b) SHA1(8d0a5d6ce3b9a236771126033c4aba6c0cc5e704) )
+ROM_END
+
+ROM_START( sider1 )
+ ROM_REGION(0x800, SASI_ROM_REGION, 0)
+ ROM_LOAD( "xebec-103684c-1986.bin", 0x000000, 0x000800, CRC(9e62e15f) SHA1(7f50b5e00cac4960204f50448a6e2d623b1a41e2) )
+ROM_END
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void a2bus_sider_device::device_add_mconfig(machine_config &config)
+{
+ NSCSI_BUS(config, m_sasibus);
+ NSCSI_CONNECTOR(config, "sasibus:0", default_scsi_devices, "s1410", false);
+ NSCSI_CONNECTOR(config, "sasibus:1", default_scsi_devices, nullptr, false);
+ NSCSI_CONNECTOR(config, "sasibus:2", default_scsi_devices, nullptr, false);
+ NSCSI_CONNECTOR(config, "sasibus:3", default_scsi_devices, nullptr, false);
+ NSCSI_CONNECTOR(config, "sasibus:4", default_scsi_devices, nullptr, false);
+ NSCSI_CONNECTOR(config, "sasibus:5", default_scsi_devices, nullptr, false);
+ NSCSI_CONNECTOR(config, "sasibus:6", default_scsi_devices, nullptr, false);
+ NSCSI_CONNECTOR(config, "sasibus:7", default_scsi_devices, "scsicb", true).option_add_internal("scsicb", NSCSI_CB);
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const tiny_rom_entry *a2bus_sider2card_device::device_rom_region() const
+{
+ return ROM_NAME( sider2 );
+}
+
+const tiny_rom_entry *a2bus_sider1card_device::device_rom_region() const
+{
+ return ROM_NAME( sider1 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+a2bus_sider_device::a2bus_sider_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_a2bus_card_interface(mconfig, *this),
+ m_sasibus(*this, "sasibus"),
+ m_sasi(*this, "sasibus:7:scsicb"),
+ m_rom(*this, SASI_ROM_REGION),
+ m_latch(0xff),
+ m_control(0)
+{
+}
+
+a2bus_sider2card_device::a2bus_sider2card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ a2bus_sider_device(mconfig, A2BUS_SIDER2, tag, owner, clock)
+{
+}
+
+a2bus_sider1card_device::a2bus_sider1card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ a2bus_sider_device(mconfig, A2BUS_SIDER1, tag, owner, clock)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void a2bus_sider_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_control));
+}
+
+void a2bus_sider_device::device_reset()
+{
+ m_latch = 0xff;
+ m_control = 0;
+}
+
+/*-------------------------------------------------
+ read_c0nx - called for reads from this card's c0nx space
+-------------------------------------------------*/
+
+uint8_t a2bus_sider_device::read_c0nx(uint8_t offset)
+{
+ u8 rv = 0;
+
+ switch (offset)
+ {
+ case 0:
+ // b3: /Busy
+ // b4: /Message
+ // b5: I/O
+ // b6: C/D
+ // b7: REQ
+ rv |= m_sasi->req_r() ? 0x80 : 0;
+ rv |= m_sasi->cd_r() ? 0x40 : 0;
+ rv |= m_sasi->io_r() ? 0x20 : 0;
+ rv |= m_sasi->msg_r() ? 0x10 : 0;
+ rv |= m_sasi->bsy_r() ? 0x08 : 0;
+ return rv;
+
+ case 1:
+ rv = m_sasi->read();
+ if ((m_sasi->req_r()) && (m_sasi->io_r()))
+ {
+ m_sasi->ack_w(1);
+ m_sasi->ack_w(0);
+ }
+ return rv;
+
+ default:
+ logerror("Read c0n%x (%s)\n", offset, machine().describe_context().c_str());
+ break;
+ }
+
+ return 0xff;
+}
+
+
+/*-------------------------------------------------
+ write_c0nx - called for writes to this card's c0nx space
+-------------------------------------------------*/
+
+void a2bus_sider_device::write_c0nx(uint8_t offset, uint8_t data)
+{
+ switch (offset)
+ {
+ case 0:
+ m_latch = data;
+ if (!(m_control & 0x10))
+ {
+ m_sasi->write(m_latch);
+
+ if (m_sasi->req_r())
+ {
+ m_sasi->ack_w(1);
+ m_sasi->write(0); // stop driving the data lines
+ m_sasi->ack_w(0);
+ }
+ }
+ break;
+
+ case 1:
+// b4: drive contents of output latch onto the SASI bus
+// b5: reset bus
+// b6: /BSY
+// b7: /SEL (error in note on A2DP's schematic; BSY and SEL are the same polarity from the 6502's POV)
+ m_control = data;
+ m_sasi->sel_w((data & 0x80) ? 1 : 0);
+ m_sasi->bsy_w((data & 0x40) ? 1 : 0);
+ if (data & 0x20)
+ {
+ m_sasibus->reset();
+ }
+ else if (!(data & 0x10))
+ {
+ m_sasi->write(m_latch);
+ }
+ break;
+
+ default:
+ logerror("Write %02x to c0n%x (%s)\n", data, offset, machine().describe_context().c_str());
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ read_cnxx - called for reads from this card's cnxx space
+-------------------------------------------------*/
+
+uint8_t a2bus_sider_device::read_cnxx(uint8_t offset)
+{
+ // slot images at $700
+ return m_rom[offset + 0x700];
+}
+
+void a2bus_sider_device::write_cnxx(uint8_t offset, uint8_t data)
+{
+}
+
+/*-------------------------------------------------
+ read_c800 - called for reads from this card's c800 space
+-------------------------------------------------*/
+
+uint8_t a2bus_sider_device::read_c800(uint16_t offset)
+{
+ return m_rom[offset];
+}
+
+/*-------------------------------------------------
+ write_c800 - called for writes to this card's c800 space
+-------------------------------------------------*/
+void a2bus_sider_device::write_c800(uint16_t offset, uint8_t data)
+{
+}
diff --git a/src/devices/bus/a2bus/sider.h b/src/devices/bus/a2bus/sider.h
new file mode 100644
index 00000000000..6bb5ed3c036
--- /dev/null
+++ b/src/devices/bus/a2bus/sider.h
@@ -0,0 +1,71 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*********************************************************************
+
+ sider.h
+
+ Implementation of the First Class Peripherals / Advanced Tech Services / Xebec Sider SASI Card
+
+*********************************************************************/
+
+#ifndef MAME_BUS_A2BUS_SIDER_H
+#define MAME_BUS_A2BUS_SIDER_H
+
+#pragma once
+
+#include "a2bus.h"
+#include "bus/nscsi/devices.h"
+#include "machine/nscsi_bus.h"
+#include "machine/nscsi_cb.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class a2bus_sider_device:
+ public device_t,
+ public device_a2bus_card_interface
+{
+protected:
+ a2bus_sider_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ // overrides of standard a2bus slot functions
+ virtual uint8_t read_c0nx(uint8_t offset) override;
+ virtual void write_c0nx(uint8_t offset, uint8_t data) override;
+ virtual uint8_t read_cnxx(uint8_t offset) override;
+ virtual void write_cnxx(uint8_t offset, uint8_t data) override;
+ virtual uint8_t read_c800(uint16_t offset) override;
+ virtual void write_c800(uint16_t offset, uint8_t data) override;
+
+ required_device<nscsi_bus_device> m_sasibus;
+ required_device<nscsi_callback_device> m_sasi;
+ required_region_ptr<u8> m_rom;
+
+private:
+ u8 m_latch;
+ u8 m_control;
+};
+
+class a2bus_sider2card_device: public a2bus_sider_device
+{
+public:
+ a2bus_sider2card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual const tiny_rom_entry *device_rom_region() const override;
+};
+
+class a2bus_sider1card_device: public a2bus_sider_device
+{
+public:
+ a2bus_sider1card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ virtual const tiny_rom_entry *device_rom_region() const override;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(A2BUS_SIDER2, a2bus_sider2card_device)
+DECLARE_DEVICE_TYPE(A2BUS_SIDER1, a2bus_sider1card_device)
+
+#endif // MAME_BUS_A2BUS_SIDER_H
diff --git a/src/devices/bus/a2gameio/computereyes.cpp b/src/devices/bus/a2gameio/computereyes.cpp
index 1c587f54254..af597361c8e 100644
--- a/src/devices/bus/a2gameio/computereyes.cpp
+++ b/src/devices/bus/a2gameio/computereyes.cpp
@@ -82,23 +82,22 @@ WRITE_LINE_MEMBER(apple2_compeyes_device::an0_w)
std::fill_n(m_a2_bitmap, 280*192, 0);
- m_bitmap = &m_picture->get_bitmap();
- if (m_bitmap)
+ const bitmap_argb32 &bitmap = m_picture->get_bitmap();
+ if (bitmap.valid())
{
// convert arbitrary sized ARGB32 image to a 280x192 image with 256 levels of grayscale
- double stepx = (double)m_bitmap->width() / 280.0;
- double stepy = (double)m_bitmap->height() / 192.0;
-
+ double stepx = (double)bitmap.width() / 280.0;
+ double stepy = (double)bitmap.height() / 192.0;
for (int y = 0; y < 192; y++)
{
for (int x = 0; x < 280; x++)
{
- u32 pixel = m_bitmap->pix((int)((double)y * stepy), (int)((double)x * stepx));
- double mono = ((0.2126 * (double)(((pixel>>16) & 0xff) / 255.0)) +
- (0.7152 * (double)(((pixel>>8) & 0xff) / 255.0)) +
- (0.0722 * (double)((pixel& 0xff) / 255.0)));
- m_a2_bitmap[(y*280)+x] = (u8)(mono * 255.0);
+ u32 pixel = bitmap.pix(int((double)y * stepy), int((double)x * stepx));
+ double mono = ((0.2126 * double(((pixel>>16) & 0xff) / 255.0)) +
+ (0.7152 * double(((pixel>>8) & 0xff) / 255.0)) +
+ (0.0722 * double((pixel& 0xff) / 255.0)));
+ m_a2_bitmap[(y*280)+x] = u8(mono * 255.0);
}
}
}
diff --git a/src/devices/bus/a2gameio/computereyes.h b/src/devices/bus/a2gameio/computereyes.h
index 6aef78796a6..9445ce4df25 100644
--- a/src/devices/bus/a2gameio/computereyes.h
+++ b/src/devices/bus/a2gameio/computereyes.h
@@ -41,7 +41,6 @@ private:
required_device<picture_image_device> m_picture;
int m_x, m_y, m_an1, m_an2, m_an3, m_level;
u8 m_a2_bitmap[280*192];
- bitmap_argb32 *m_bitmap;
};
// device type declaration
diff --git a/src/devices/bus/acorn/system/vdu40.cpp b/src/devices/bus/acorn/system/vdu40.cpp
index dcee8cd9b53..7bc8629ac35 100644
--- a/src/devices/bus/acorn/system/vdu40.cpp
+++ b/src/devices/bus/acorn/system/vdu40.cpp
@@ -93,7 +93,7 @@ void acorn_vdu40_device::device_reset()
MC6845_UPDATE_ROW(acorn_vdu40_device::crtc_update_row)
{
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
m_trom->lose_w(1);
m_trom->lose_w(0);
diff --git a/src/devices/bus/acorn/system/vdu80.cpp b/src/devices/bus/acorn/system/vdu80.cpp
index 5cf995d8d3c..77bad0bf32c 100644
--- a/src/devices/bus/acorn/system/vdu80.cpp
+++ b/src/devices/bus/acorn/system/vdu80.cpp
@@ -172,7 +172,7 @@ void acorn_vdu80_device::device_reset()
MC6845_UPDATE_ROW(acorn_vdu80_device::crtc_update_row)
{
uint8_t invert = BIT(m_links->read(), 1);
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
for (int column = 0; column < x_count; column++)
{
diff --git a/src/devices/bus/adamnet/adamnet.cpp b/src/devices/bus/adamnet/adamnet.cpp
index 69b25ce30e7..18b91c4fb8c 100644
--- a/src/devices/bus/adamnet/adamnet.cpp
+++ b/src/devices/bus/adamnet/adamnet.cpp
@@ -113,7 +113,7 @@ void adamnet_device::device_stop()
void adamnet_device::add_device(device_t *target)
{
- auto entry = global_alloc(daisy_entry(target));
+ auto entry = new daisy_entry(target);
entry->m_interface->m_bus = this;
diff --git a/src/devices/bus/adamnet/ddp.cpp b/src/devices/bus/adamnet/ddp.cpp
index 6e05689cb29..b4a17e909cd 100644
--- a/src/devices/bus/adamnet/ddp.cpp
+++ b/src/devices/bus/adamnet/ddp.cpp
@@ -58,7 +58,7 @@ void adam_digital_data_pack_device::adam_ddp_mem(address_map &map)
map(0xf800, 0xffff).rom().region(M6801_TAG, 0);
}
-static const struct CassetteOptions adam_cassette_options =
+static const cassette_image::Options adam_cassette_options =
{
2, /* channels */
16, /* bits per sample */
diff --git a/src/devices/bus/adamnet/kb.cpp b/src/devices/bus/adamnet/kb.cpp
index a401dbfb335..046ceba61f4 100644
--- a/src/devices/bus/adamnet/kb.cpp
+++ b/src/devices/bus/adamnet/kb.cpp
@@ -134,7 +134,7 @@ static INPUT_PORTS_START( adam_kb )
PORT_START("Y5")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('\'')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('`')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('=')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('~')
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
diff --git a/src/devices/bus/bbc/1mhzbus/1mhzbus.cpp b/src/devices/bus/bbc/1mhzbus/1mhzbus.cpp
index 1246cb1902c..6fa98419abc 100644
--- a/src/devices/bus/bbc/1mhzbus/1mhzbus.cpp
+++ b/src/devices/bus/bbc/1mhzbus/1mhzbus.cpp
@@ -117,7 +117,7 @@ void bbc_1mhzbus_slot_device::jim_w(offs_t offset, uint8_t data)
#include "ide.h"
#include "ieee488.h"
#include "m2000.h"
-//#include "m5000.h"
+#include "m5000.h"
#include "sasi.h"
#include "scsi.h"
#include "multiform.h"
@@ -137,7 +137,7 @@ void bbc_1mhzbus_devices(device_slot_interface &device)
{
//device.option_add("teletext", BBC_TELETEXT); /* Acorn ANE01 Teletext Adapter */
device.option_add("ieee488", BBC_IEEE488); /* Acorn ANK01 IEEE488 Interface */
- //device.option_add("m500", BBC_M500); /* Acorn ANV02 Music 500 */
+ device.option_add("m500", BBC_M500); /* Acorn ANV02 Music 500 */
device.option_add("awhd", BBC_AWHD); /* Acorn Winchester Disc */
device.option_add("autoprom", BBC_AUTOPROM); /* ATPL AutoPrommer */
device.option_add("beebide", BBC_BEEBIDE); /* Sprow BeebIDE 16-bit */
@@ -147,6 +147,10 @@ void bbc_1mhzbus_devices(device_slot_interface &device)
//device.option_add("videodig", BBC_VIDEODIG); /* Video Digitiser (RH Electronics) */
device.option_add("emrmidi", BBC_EMRMIDI); /* EMR Midi Interface */
//device.option_add("procyon", BBC_PROCYON); /* CST Procyon IEEE Interface */
+ device.option_add("m2000", BBC_M2000); /* Hybrid Music 2000 Interface */
+ device.option_add("m3000", BBC_M3000); /* Hybrid Music 3000 Expander */
+ device.option_add("m5000", BBC_M5000); /* Hybrid Music 5000 Synthesiser */
+ device.option_add("m87", BBC_M87); /* Peartree Music 87 Synthesiser */
device.option_add("multiform", BBC_MULTIFORM); /* PEDL Multiform Z80 */
device.option_add("opus3", BBC_OPUS3); /* Opus Challenger 3 */
device.option_add("pdram", BBC_PDRAM); /* Micro User Pull Down RAM */
@@ -160,13 +164,13 @@ void bbc_1mhzbus_devices(device_slot_interface &device)
device.option_add("cc500", BBC_CC500); /* CTS Colour Card 500 */
//device.option_add("prisma3", BBC_PRISMA3); /* PRISMA-3 - Millipede 1989 */
device.option_add("sprite", BBC_SPRITE); /* Logotron Sprite Board */
+ device.option_add_internal("cfa3000opt", CFA3000_OPT);/* Henson CFA 3000 Option Board */
}
void bbcm_1mhzbus_devices(device_slot_interface &device)
{
//device.option_add("teletext", BBC_TELETEXT); /* Acorn ANE01 Teletext Adapter */
device.option_add("ieee488", BBC_IEEE488); /* Acorn ANK01 IEEE488 Interface */
- //device.option_add("m500", BBC_M500); /* Acorn ANV02 Music 500 */
device.option_add("awhd", BBC_AWHD); /* Acorn Winchester Disc */
device.option_add("beebide", BBC_BEEBIDE); /* Sprow BeebIDE 16-bit */
device.option_add("ide8", BBC_IDE8); /* RetroClinic BBC 8-bit IDE */
@@ -175,9 +179,9 @@ void bbcm_1mhzbus_devices(device_slot_interface &device)
device.option_add("emrmidi", BBC_EMRMIDI); /* EMR Midi Interface */
//device.option_add("procyon", BBC_PROCYON); /* CST Procyon IEEE Interface */
device.option_add("m2000", BBC_M2000); /* Hybrid Music 2000 Interface */
- //device.option_add("m3000", BBC_M3000); /* Hybrid Music 3000 Expander */
- //device.option_add("m5000", BBC_M5000); /* Hybrid Music 5000 Synthesiser */
- //device.option_add("m87", BBC_M87); /* Peartree Music 87 Synthesiser */
+ device.option_add("m3000", BBC_M3000); /* Hybrid Music 3000 Expander */
+ device.option_add("m5000", BBC_M5000); /* Hybrid Music 5000 Synthesiser */
+ device.option_add("m87", BBC_M87); /* Peartree Music 87 Synthesiser */
device.option_add("multiform", BBC_MULTIFORM); /* PEDL Multiform Z80 */
device.option_add("opusa", BBC_OPUSA); /* Opus Challenger ADFS */
device.option_add("pdram", BBC_PDRAM); /* Micro User Pull Down RAM */
diff --git a/src/devices/bus/bbc/1mhzbus/m5000.cpp b/src/devices/bus/bbc/1mhzbus/m5000.cpp
new file mode 100644
index 00000000000..1844de74a0d
--- /dev/null
+++ b/src/devices/bus/bbc/1mhzbus/m5000.cpp
@@ -0,0 +1,435 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+// thanks-to:Darren Izzard
+/**********************************************************************
+
+ Acorn ANV02 Music 500
+
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_ANV02_Music500.html
+
+ Hybrid Music 5000 Synthesiser
+
+ https://www.retro-kit.co.uk/page.cfm/content/Hybrid-Music-5000-Synthesiser/
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Hybrid_Music5000.html
+
+ Hybrid Music 3000 Expander
+
+ https://www.retro-kit.co.uk/page.cfm/content/Hybrid-Music-3000-Expander/
+
+ Peartree Music 87 Synthesiser
+
+ http://www.computinghistory.org.uk/det/4535/Peartree-Computers-Music-87-Synthesizer-(M500)/
+
+ TODO:
+ - convert to use DAC76 device
+ - add suitably patched version of Ample ROM
+ - add ROMs for Music 87
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "m5000.h"
+#include "speaker.h"
+#include "softlist_dev.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(HTMUSIC, htmusic_device, "htmusic", "Hybrid Technology Music System")
+
+DEFINE_DEVICE_TYPE(BBC_M500, bbc_m500_device, "bbc_m500", "Acorn Music 500");
+DEFINE_DEVICE_TYPE(BBC_M5000, bbc_m5000_device, "bbc_m5000", "Hybrid Music 5000 Synthesiser");
+DEFINE_DEVICE_TYPE(BBC_M3000, bbc_m3000_device, "bbc_m3000", "Hybrid Music 3000 Expander");
+DEFINE_DEVICE_TYPE(BBC_M87, bbc_m87_device, "bbc_m87", "Peartree Music 87 Synthesiser");
+
+
+//-------------------------------------------------
+// ROM( m5000 )
+//-------------------------------------------------
+
+//ROM_START( m5000 )
+ //ROM_REGION(0x4000, "exp_rom", 0)
+ // Each AMPLE Nucleus ROM has a unique identification code (ID)
+ //ROM_LOAD("ample_patch.rom", 0x0000, 0x4000, CRC(15bbd499) SHA1(ac90f403b3bde0cdaae68546799b94962bc00fcb))
+//ROM_END
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void bbc_m500_device::add_common_devices(machine_config &config)
+{
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+
+ HTMUSIC(config, m_hybrid, 12_MHz_XTAL / 2);
+ m_hybrid->add_route(0, "lspeaker", 1.0);
+ m_hybrid->add_route(1, "rspeaker", 1.0);
+
+ BBC_1MHZBUS_SLOT(config, m_1mhzbus, DERIVED_CLOCK(1, 1), bbc_1mhzbus_devices, nullptr);
+ m_1mhzbus->irq_handler().set(DEVICE_SELF_OWNER, FUNC(bbc_1mhzbus_slot_device::irq_w));
+ m_1mhzbus->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(bbc_1mhzbus_slot_device::nmi_w));
+}
+
+void bbc_m500_device::device_add_mconfig(machine_config &config)
+{
+ add_common_devices(config);
+
+ SOFTWARE_LIST(config, "flop_ls_hybrid").set_original("bbc_flop_hybrid").set_filter("M500");
+}
+
+void bbc_m5000_device::device_add_mconfig(machine_config &config)
+{
+ add_common_devices(config);
+
+ SOFTWARE_LIST(config, "flop_ls_hybrid").set_original("bbc_flop_hybrid").set_filter("M5000");
+}
+
+void bbc_m3000_device::device_add_mconfig(machine_config &config)
+{
+ add_common_devices(config);
+}
+
+void bbc_m87_device::device_add_mconfig(machine_config &config)
+{
+ add_common_devices(config);
+
+ SOFTWARE_LIST(config, "flop_ls_hybrid").set_original("bbc_flop_hybrid").set_filter("M87");
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+//const tiny_rom_entry *bbc_m5000_device::device_rom_region() const
+//{
+ //return ROM_NAME( m5000 );
+//}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// bbc_hybrid_device - constructor
+//-------------------------------------------------
+
+bbc_m500_device::bbc_m500_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_bbc_1mhzbus_interface(mconfig, *this)
+ , m_1mhzbus(*this, "1mhzbus")
+ , m_hybrid(*this, "hybrid")
+ , m_page(0)
+{
+}
+
+bbc_m500_device::bbc_m500_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_m500_device(mconfig, BBC_M500, tag, owner, clock)
+{
+}
+
+bbc_m5000_device::bbc_m5000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_m500_device(mconfig, BBC_M5000, tag, owner, clock)
+{
+}
+
+bbc_m3000_device::bbc_m3000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_m500_device(mconfig, BBC_M3000, tag, owner, clock)
+{
+}
+
+bbc_m87_device::bbc_m87_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : bbc_m500_device(mconfig, BBC_M87, tag, owner, clock)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void bbc_m500_device::device_start()
+{
+ // register for save states
+ save_item(NAME(m_page));
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+uint8_t bbc_m500_device::fred_r(offs_t offset)
+{
+ return m_1mhzbus->fred_r(offset);
+}
+
+void bbc_m500_device::fred_w(offs_t offset, uint8_t data)
+{
+ if (offset == 0xff)
+ {
+ m_page = data;
+ }
+
+ m_1mhzbus->fred_w(offset, data);
+}
+
+uint8_t bbc_m500_device::jim_r(offs_t offset)
+{
+ return m_1mhzbus->jim_r(offset);
+}
+
+void bbc_m500_device::jim_w(offs_t offset, uint8_t data)
+{
+ if ((m_page & 0xf0) == 0x30)
+ {
+ uint8_t page = (m_page >> 1) & 7;
+
+ m_hybrid->ram_w((page << 8) | offset, data);
+ }
+
+ m_1mhzbus->jim_w(offset, data);
+}
+
+
+void bbc_m3000_device::jim_w(offs_t offset, uint8_t data)
+{
+ if ((m_page & 0xf0) == 0x50)
+ {
+ uint8_t page = (m_page >> 1) & 7;
+
+ m_hybrid->ram_w((page << 8) | offset, data);
+ }
+
+ m_1mhzbus->jim_w(offset, data);
+}
+
+
+//**************************************************************************
+// HYBRID MUSIC IMPLEMENTATION
+//**************************************************************************
+
+//-------------------------------------------------
+// htmusic_device - constructor
+//-------------------------------------------------
+
+htmusic_device::htmusic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, HTMUSIC, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , m_counter(0)
+ , m_c4d(0)
+ , m_sign(0)
+ , m_sam(0)
+ , m_disable(false)
+ , m_modulate(false)
+ , m_dsp_timer(nullptr)
+ , m_stream(nullptr)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void htmusic_device::device_start()
+{
+ // 12-bit antilog as per Am6070 datasheet
+ for (int i = 0; i < 128; i++)
+ m_antilog[i] = (uint16_t)(2 * (pow(2.0, i >> 4) * ((i & 15) + 16.5) - 16.5));
+
+ // create the stream
+ m_stream = stream_alloc(0, 2, clock() / 128);
+
+ // allocate timer
+ m_dsp_timer = timer_alloc(0);
+
+ // register for save states
+ save_item(NAME(m_wave_ram));
+ save_item(NAME(m_phase_ram));
+ save_item(NAME(m_counter));
+ save_item(NAME(m_c4d));
+ save_item(NAME(m_sign));
+ save_item(NAME(m_disable));
+ save_item(NAME(m_modulate));
+ save_item(NAME(m_sam));
+ save_item(NAME(m_sam_l));
+ save_item(NAME(m_sam_r));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void htmusic_device::device_reset()
+{
+ // clear ram
+ memset(m_wave_ram, 0, sizeof(m_wave_ram));
+ memset(m_phase_ram, 0, sizeof(m_phase_ram));
+
+ memset(m_sam_l, 0, sizeof(m_sam_l));
+ memset(m_sam_r, 0, sizeof(m_sam_r));
+
+ // reset counter
+ m_counter = 0;
+ m_disable = false;
+ m_modulate = false;
+
+ // start timer
+ m_dsp_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
+}
+
+
+//-------------------------------------------------
+// digital signal processor
+//-------------------------------------------------
+
+#define I_CHAN(c) ((((c) & 0x1e) >> 1) + (((c) & 0x01) << 7) + 0x700)
+#define I_FREQ(c) (I_CHAN(c))
+#define I_WAVESEL(c) (I_CHAN(c) + 0x50)
+#define I_AMP(c) (I_CHAN(c) + 0x60)
+#define I_CTL(c) (I_CHAN(c) + 0x70)
+#define FREQ(c) ((m_wave_ram[I_FREQ(c) + 0x20] << 16) | (m_wave_ram[I_FREQ(c) + 0x10] << 8) | (m_wave_ram[I_FREQ(c)] & 0x7e))
+#define DISABLE(c) (BIT(m_wave_ram[I_FREQ(c)], 0))
+#define AMP(c) (m_wave_ram[I_AMP(c)])
+#define WAVESEL(c) (m_wave_ram[I_WAVESEL(c)] >> 4)
+#define CTL(c) (m_wave_ram[I_CTL(c)])
+#define MODULATE(c) (BIT(CTL(c), 5))
+#define INVERT(c) (BIT(CTL(c), 4))
+#define PAN(c) (CTL(c) & 0x0f)
+
+void htmusic_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ // 4-bit channel select
+ uint8_t channel = (m_counter >> 3) & 0x0f;
+ uint8_t c = (channel << 1) + (m_modulate ? 1 : 0);
+
+ // 3-bit program counter
+ switch (m_counter & 0x07)
+ {
+ case 0:
+ m_stream->update();
+
+ m_disable = DISABLE(c);
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ // In the real hardware the disable bit works by forcing the
+ // phase accumulator to zero.
+ if (m_disable)
+ {
+ m_phase_ram[channel] = 0;
+ m_c4d = 0;
+ }
+ else
+ {
+ uint32_t sum = m_phase_ram[channel] + FREQ(c);
+ m_phase_ram[channel] = sum & 0xffffff;
+ // c4d is used for "Synchronization" e.g. the "Wha" instrument
+ m_c4d = sum >> 24;
+ }
+ break;
+
+ case 3:
+ break;
+
+ case 4:
+ break;
+
+ case 5:
+ m_sam = m_wave_ram[(WAVESEL(c) << 7) + (m_phase_ram[channel] >> 17)];
+ break;
+
+ case 6:
+ // The amplitude operates in the log domain
+ // - m_sam holds the wave table output which is 1 bit sign and 7 bit magnitude
+ // - amp holds the amplitude which is 1 bit sign and 8 bit magnitude (0x00 being quite, 0x7f being loud)
+ // The real hardware combines these in a single 8 bit adder, as we do here.
+ //
+ // Consider a positive wav value (sign bit = 1)
+ // wav: (0x80 -> 0xFF) + amp: (0x00 -> 0x7F) => (0x80 -> 0x7E)
+ // values in the range 0x80...0xff are very small and clamped to zero
+ //
+ // Consider a negative wav value (sign bit = 0)
+ // wav: (0x00 -> 0x7F) + amp: (0x00 -> 0x7F) => (0x00 -> 0xFE)
+ // values in the range 0x00...0x7f are very small and clamped to zero
+ //
+ // In both cases:
+ // - zero clamping happens when the sign bit stays the same
+ // - the 7-bit result is in bits 0..6
+ //
+ m_sign = m_sam & 0x80;
+ m_sam += AMP(c);
+ if ((m_sign ^ m_sam) & 0x80)
+ m_sam &= 0x7f; // sign bits being different is the normal case
+ else
+ m_sam = 0x00; // sign bits being the same indicates underflow so clamp to zero
+ break;
+
+ case 7:
+ {
+ m_modulate = MODULATE(c) && (!!(m_sign) || !!(m_c4d));
+
+ // in the real hardware, inversion does not affect modulation
+ if (INVERT(c))
+ m_sign ^= 0x80;
+
+ // m_sam is an 8-bit log value
+ if (m_sign)
+ m_sam = m_antilog[m_sam]; // sign being 1 is positive
+ else
+ m_sam = -m_antilog[m_sam]; // sign being 0 is negative
+
+ // m_sam is a 12-bit linear sample
+ uint8_t pan;
+ switch (PAN(c))
+ {
+ case 8: case 9: case 10: pan = 6; break;
+ case 11: pan = 5; break;
+ case 12: pan = 4; break;
+ case 13: pan = 3; break;
+ case 14: pan = 2; break;
+ case 15: pan = 1; break;
+ default: pan = 0; break;
+ }
+
+ // Apply panning. In the real hardware, a disabled channel is not actually
+ // forced to zero, but this seems harmless so leave in for now.
+ m_sam_l[channel] = m_disable ? 0 : ((m_sam * pan) / 6);
+ m_sam_r[channel] = m_disable ? 0 : ((m_sam * (6 - pan)) / 6);
+ break;
+ }
+ }
+
+ m_counter++;
+}
+
+
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void htmusic_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ // reset the output streams
+ outputs[0].fill(0);
+ outputs[1].fill(0);
+
+ // iterate over channels and accumulate sample data
+ for (int channel = 0; channel < 16; channel++)
+ {
+ for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
+ {
+ outputs[0].add_int(sampindex, m_sam_l[channel], 8031 * 16);
+ outputs[1].add_int(sampindex, m_sam_r[channel], 8031 * 16);
+ }
+ }
+}
diff --git a/src/devices/bus/bbc/1mhzbus/m5000.h b/src/devices/bus/bbc/1mhzbus/m5000.h
new file mode 100644
index 00000000000..d2507ab4abe
--- /dev/null
+++ b/src/devices/bus/bbc/1mhzbus/m5000.h
@@ -0,0 +1,158 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Acorn ANV02 Music 500
+
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Acorn_ANV02_Music500.html
+
+ Hybrid Music 5000 Synthesiser
+
+ https://www.retro-kit.co.uk/page.cfm/content/Hybrid-Music-5000-Synthesiser/
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Hybrid_Music5000.html
+
+ Hybrid Music 3000 Expander
+
+ https://www.retro-kit.co.uk/page.cfm/content/Hybrid-Music-3000-Expander/
+
+ Peartree Music 87 Synthesiser
+
+ http://www.computinghistory.org.uk/det/4535/Peartree-Computers-Music-87-Synthesizer-(M500)/
+
+**********************************************************************/
+
+
+#ifndef MAME_BUS_BBC_1MHZBUS_M5000_H
+#define MAME_BUS_BBC_1MHZBUS_M5000_H
+
+#include "1mhzbus.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> htmusic_device
+
+class htmusic_device : public device_t, public device_sound_interface
+{
+public:
+ htmusic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void ram_w(offs_t offset, uint8_t data) { m_wave_ram[offset & 0x7ff] = data; }
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ uint16_t m_antilog[128];
+ uint8_t m_wave_ram[0x800];
+ uint32_t m_phase_ram[0x200];
+
+ uint8_t m_counter;
+ uint8_t m_c4d;
+ uint8_t m_sign;
+ int16_t m_sam;
+ bool m_disable;
+ bool m_modulate;
+
+ int32_t m_sam_l[16];
+ int32_t m_sam_r[16];
+
+ emu_timer *m_dsp_timer;
+
+ sound_stream *m_stream;
+};
+
+
+// ======================> bbc_m500_device
+
+class bbc_m500_device : public device_t, public device_bbc_1mhzbus_interface
+{
+public:
+ // construction/destruction
+ bbc_m500_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ bbc_m500_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ void add_common_devices(machine_config &config);
+
+ virtual uint8_t fred_r(offs_t offset) override;
+ virtual void fred_w(offs_t offset, uint8_t data) override;
+ virtual uint8_t jim_r(offs_t offset) override;
+ virtual void jim_w(offs_t offset, uint8_t data) override;
+
+ required_device<bbc_1mhzbus_slot_device> m_1mhzbus;
+ required_device<htmusic_device> m_hybrid;
+
+ uint8_t m_page;
+};
+
+
+// ======================> bbc_m5000_device
+
+class bbc_m5000_device : public bbc_m500_device
+{
+public:
+ // construction/destruction
+ bbc_m5000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ //virtual const tiny_rom_entry *device_rom_region() const override;
+};
+
+
+// ======================> bbc_m3000_device
+
+class bbc_m3000_device : public bbc_m500_device
+{
+public:
+ // construction/destruction
+ bbc_m3000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+
+ virtual void jim_w(offs_t offset, uint8_t data) override;
+};
+
+
+// ======================> bbc_m87_device
+
+class bbc_m87_device : public bbc_m500_device
+{
+public:
+ // construction/destruction
+ bbc_m87_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // optional information overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(BBC_M500, bbc_m500_device);
+DECLARE_DEVICE_TYPE(BBC_M5000, bbc_m5000_device);
+DECLARE_DEVICE_TYPE(BBC_M3000, bbc_m3000_device);
+DECLARE_DEVICE_TYPE(BBC_M87, bbc_m87_device);
+
+
+#endif /* MAME_BUS_BBC_1MHZBUS_M5000_H */
diff --git a/src/devices/bus/bbc/joyport/joyport.cpp b/src/devices/bus/bbc/joyport/joyport.cpp
index 79f285b0670..26abb9678ef 100644
--- a/src/devices/bus/bbc/joyport/joyport.cpp
+++ b/src/devices/bus/bbc/joyport/joyport.cpp
@@ -40,12 +40,12 @@ device_bbc_joyport_interface::device_bbc_joyport_interface(const machine_config
// bbcmc_joyport_slot_device - constructor
//-------------------------------------------------
-bbc_joyport_slot_device::bbc_joyport_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, BBC_JOYPORT_SLOT, tag, owner, clock),
- device_single_card_slot_interface(mconfig, *this),
- m_device(nullptr),
- m_cb1_handler(*this),
- m_cb2_handler(*this)
+bbc_joyport_slot_device::bbc_joyport_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, BBC_JOYPORT_SLOT, tag, owner, clock)
+ , device_single_card_slot_interface(mconfig, *this)
+ , m_device(nullptr)
+ , m_cb1_handler(*this)
+ , m_cb2_handler(*this)
{
}
@@ -70,7 +70,6 @@ void bbc_joyport_slot_device::device_start()
uint8_t bbc_joyport_slot_device::pb_r()
{
- // TODO: Joyport connected to PB0-PB4 only. PB5-PB7 are expansion port.
if (m_device)
return 0xe0 | m_device->pb_r();
else
@@ -90,6 +89,28 @@ void bbc_joyport_slot_device::pb_w(uint8_t data)
//-------------------------------------------------
+// write_cb1
+//-------------------------------------------------
+
+void bbc_joyport_slot_device::write_cb1(int state)
+{
+ if (m_device)
+ m_device->write_cb1(state);
+}
+
+
+//-------------------------------------------------
+// write_cb2
+//-------------------------------------------------
+
+void bbc_joyport_slot_device::write_cb2(int state)
+{
+ if (m_device)
+ m_device->write_cb2(state);
+}
+
+
+//-------------------------------------------------
// SLOT_INTERFACE( bbc_joyport_devices )
//-------------------------------------------------
diff --git a/src/devices/bus/bbc/joyport/joyport.h b/src/devices/bus/bbc/joyport/joyport.h
index e2d44111995..15d81243d84 100644
--- a/src/devices/bus/bbc/joyport/joyport.h
+++ b/src/devices/bus/bbc/joyport/joyport.h
@@ -61,11 +61,15 @@ public:
auto cb1_handler() { return m_cb1_handler.bind(); }
auto cb2_handler() { return m_cb2_handler.bind(); }
+ // from slot
DECLARE_WRITE_LINE_MEMBER(cb1_w) { m_cb1_handler(state); }
DECLARE_WRITE_LINE_MEMBER(cb2_w) { m_cb2_handler(state); }
+ // from host
uint8_t pb_r();
void pb_w(uint8_t data);
+ void write_cb1(int state);
+ void write_cb2(int state);
protected:
// device-level overrides
@@ -86,6 +90,8 @@ class device_bbc_joyport_interface : public device_interface
public:
virtual uint8_t pb_r() { return 0xff; }
virtual void pb_w(uint8_t data) { }
+ virtual void write_cb1(int state) { }
+ virtual void write_cb2(int state) { }
protected:
device_bbc_joyport_interface(const machine_config &mconfig, device_t &device);
diff --git a/src/devices/bus/bbc/tube/tube_32016.cpp b/src/devices/bus/bbc/tube/tube_32016.cpp
index 6a54665937d..f621cef4f07 100644
--- a/src/devices/bus/bbc/tube/tube_32016.cpp
+++ b/src/devices/bus/bbc/tube/tube_32016.cpp
@@ -38,10 +38,6 @@ DEFINE_DEVICE_TYPE(BBC_TUBE_32016L, bbc_tube_32016l_device, "bbc_tube_32016l", "
void bbc_tube_32016_device::tube_32016_mem(address_map &map)
{
- map(0x000000, 0xffffff).rw(FUNC(bbc_tube_32016_device::read), FUNC(bbc_tube_32016_device::write));
- map(0xf00000, 0xf07fff).rom().region("rom", 0).mirror(0x0f8000);
- map(0xf90000, 0xf90001).portr("CONFIG");
- map(0xfffff0, 0xffffff).rw("ula", FUNC(tube_device::parasite_r), FUNC(tube_device::parasite_w)).umask16(0x00ff);
}
//-------------------------------------------------
@@ -76,36 +72,36 @@ ROM_END
static INPUT_PORTS_START(tube_32016)
PORT_START("CONFIG")
- PORT_DIPNAME(0x80, 0x80, "H") PORT_DIPLOCATION("LKS:1")
- PORT_DIPSETTING(0x80, "FPU")
+ PORT_DIPNAME(0x01, 0x01, "H") PORT_DIPLOCATION("LKS:1")
+ PORT_DIPSETTING(0x01, "FPU")
PORT_DIPSETTING(0x00, "No FPU")
- PORT_DIPNAME(0x40, 0x00, "G") PORT_DIPLOCATION("LKS:2")
- PORT_DIPSETTING(0x40, "MMU")
+ PORT_DIPNAME(0x02, 0x00, "G") PORT_DIPLOCATION("LKS:2")
+ PORT_DIPSETTING(0x02, "MMU")
PORT_DIPSETTING(0x00, "No MMU")
- PORT_DIPNAME(0x20, 0x00, "F") PORT_DIPLOCATION("LKS:3")
- PORT_DIPSETTING(0x20, "Reserved")
+ PORT_DIPNAME(0x04, 0x00, "F") PORT_DIPLOCATION("LKS:3")
+ PORT_DIPSETTING(0x04, "Reserved")
PORT_DIPSETTING(0x00, "Reserved")
- PORT_DIPNAME(0x10, 0x00, "E") PORT_DIPLOCATION("LKS:4")
- PORT_DIPSETTING(0x10, "Reserved")
+ PORT_DIPNAME(0x08, 0x00, "E") PORT_DIPLOCATION("LKS:4")
+ PORT_DIPSETTING(0x08, "Reserved")
PORT_DIPSETTING(0x00, "Reserved")
- PORT_DIPNAME(0x08, 0x00, "D") PORT_DIPLOCATION("LKS:5")
- PORT_DIPSETTING(0x08, "Reserved")
+ PORT_DIPNAME(0x10, 0x00, "D") PORT_DIPLOCATION("LKS:5")
+ PORT_DIPSETTING(0x10, "Reserved")
PORT_DIPSETTING(0x00, "Reserved")
- PORT_DIPNAME(0x04, 0x00, "C") PORT_DIPLOCATION("LKS:6")
- PORT_DIPSETTING(0x04, "Reserved")
+ PORT_DIPNAME(0x20, 0x00, "C") PORT_DIPLOCATION("LKS:6")
+ PORT_DIPSETTING(0x20, "Reserved")
PORT_DIPSETTING(0x00, "Reserved")
- PORT_DIPNAME(0x02, 0x00, "B") PORT_DIPLOCATION("LKS:7")
- PORT_DIPSETTING(0x02, "Reserved")
+ PORT_DIPNAME(0x40, 0x00, "B") PORT_DIPLOCATION("LKS:7")
+ PORT_DIPSETTING(0x40, "Reserved")
PORT_DIPSETTING(0x00, "Reserved")
- PORT_DIPNAME(0x01, 0x00, "A") PORT_DIPLOCATION("LKS:8")
- PORT_DIPSETTING(0x01, "Reserved")
+ PORT_DIPNAME(0x80, 0x00, "A") PORT_DIPLOCATION("LKS:8")
+ PORT_DIPSETTING(0x80, "Reserved")
PORT_DIPSETTING(0x00, "Reserved")
INPUT_PORTS_END
@@ -117,13 +113,16 @@ void bbc_tube_32016_device::device_add_mconfig(machine_config &config)
{
NS32016(config, m_maincpu, 12_MHz_XTAL / 2);
m_maincpu->set_addrmap(AS_PROGRAM, &bbc_tube_32016_device::tube_32016_mem);
+ m_maincpu->set_fpu(m_ns32081);
+
+ NS32081(config, m_ns32081, 12_MHz_XTAL / 2);
TUBE(config, m_ula);
m_ula->pnmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI);
m_ula->pirq_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
/* internal ram */
- RAM(config, m_ram).set_default_size("1M").set_extra_options("256K");
+ RAM(config, m_ram).set_default_size("1M").set_extra_options("256K").set_default_value(0);
/* software lists */
SOFTWARE_LIST(config, "flop_ls_32016").set_original("bbc_flop_32016");
@@ -137,7 +136,7 @@ void bbc_tube_32016l_device::device_add_mconfig(machine_config &config)
m_maincpu->set_clock(16_MHz_XTAL / 2);
/* internal ram */
- m_ram->set_default_size("4M");
+ m_ram->set_default_size("4M").set_extra_options("1M").set_default_value(0);
}
//-------------------------------------------------
@@ -175,10 +174,10 @@ bbc_tube_32016_device::bbc_tube_32016_device(const machine_config &mconfig, devi
: device_t(mconfig, type, tag, owner, clock)
, device_bbc_tube_interface(mconfig, *this)
, m_maincpu(*this, "maincpu")
+ , m_ns32081(*this, "ns32081")
, m_ula(*this, "ula")
, m_ram(*this, "ram")
, m_rom(*this, "rom")
- , m_rom_enabled(true)
{
}
@@ -198,7 +197,6 @@ bbc_tube_32016l_device::bbc_tube_32016l_device(const machine_config &mconfig, co
void bbc_tube_32016_device::device_start()
{
- save_item(NAME(m_rom_enabled));
}
//-------------------------------------------------
@@ -207,7 +205,23 @@ void bbc_tube_32016_device::device_start()
void bbc_tube_32016_device::device_reset()
{
- m_rom_enabled = true;
+ address_space &program = m_maincpu->space(AS_PROGRAM);
+
+ // address map during booting
+ program.install_rom(0x000000, 0x007fff, 0xff8000, m_rom->base());
+
+ m_rom_shadow_tap = program.install_write_tap(0x000000, 0xffffff, "rom_shadow_w",[this](offs_t offset, u16 &data, u16 mem_mask)
+ {
+ // delete this tap
+ m_rom_shadow_tap->remove();
+
+ // address map after booting
+ m_maincpu->space(AS_PROGRAM).nop_readwrite(0x000000, 0xffffff);
+ m_maincpu->space(AS_PROGRAM).install_ram(0x000000, m_ram->mask(), 0x7fffff ^ m_ram->mask(), m_ram->pointer());
+ m_maincpu->space(AS_PROGRAM).install_rom(0xf00000, 0xf07fff, 0x038000, m_rom->base());
+ m_maincpu->space(AS_PROGRAM).install_read_port(0xf90000, 0xf90001, 0x00fffe, "CONFIG");
+ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xfffff0, 0xffffff, read8sm_delegate(*m_ula, FUNC(tube_device::parasite_r)), write8sm_delegate(*m_ula, FUNC(tube_device::parasite_w)), 0xff);
+ });
}
@@ -224,24 +238,3 @@ void bbc_tube_32016_device::host_w(offs_t offset, uint8_t data)
{
m_ula->host_w(offset, data);
}
-
-
-uint8_t bbc_tube_32016_device::read(offs_t offset)
-{
- uint16_t data;
-
- if (m_rom_enabled)
- data = m_rom->base()[offset & 0x7fff];
- else
- data = m_ram->pointer()[offset & m_ram->mask()];
-
- return data;
-}
-
-void bbc_tube_32016_device::write(offs_t offset, uint8_t data)
-{
- /* clear ROM select on first write */
- m_rom_enabled = false;
-
- m_ram->pointer()[offset & m_ram->mask()] = data;
-}
diff --git a/src/devices/bus/bbc/tube/tube_32016.h b/src/devices/bus/bbc/tube/tube_32016.h
index 7e7753ae5f6..aa772e1369c 100644
--- a/src/devices/bus/bbc/tube/tube_32016.h
+++ b/src/devices/bus/bbc/tube/tube_32016.h
@@ -18,6 +18,7 @@
#include "tube.h"
#include "cpu/ns32000/ns32000.h"
+#include "machine/ns32081.h"
#include "machine/ram.h"
#include "machine/tube.h"
@@ -51,16 +52,14 @@ protected:
virtual void host_w(offs_t offset, uint8_t data) override;
required_device<ns32016_device> m_maincpu;
+ required_device<ns32081_device> m_ns32081;
required_device<tube_device> m_ula;
required_device<ram_device> m_ram;
required_memory_region m_rom;
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
+ memory_passthrough_handler *m_rom_shadow_tap;
void tube_32016_mem(address_map &map);
-
- bool m_rom_enabled;
};
diff --git a/src/devices/bus/bbc/userport/lcd.cpp b/src/devices/bus/bbc/userport/lcd.cpp
index cdc70bc35fe..f5f92270ca9 100644
--- a/src/devices/bus/bbc/userport/lcd.cpp
+++ b/src/devices/bus/bbc/userport/lcd.cpp
@@ -87,7 +87,7 @@ HD44780_PIXEL_UPDATE(bbc_lcd_device::lcd_pixel_update)
}
if (line < 4)
- bitmap.pix16(line * (8 + 1) + y, pos * 6 + x) = state ? 1 : 2;
+ bitmap.pix(line * (8 + 1) + y, pos * 6 + x) = state ? 1 : 2;
}
}
diff --git a/src/devices/bus/bbc/userport/m4000.cpp b/src/devices/bus/bbc/userport/m4000.cpp
new file mode 100644
index 00000000000..910f2f8b3f1
--- /dev/null
+++ b/src/devices/bus/bbc/userport/m4000.cpp
@@ -0,0 +1,170 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Hybrid Music 4000 Keyboard (also known as ATPL Symphony)
+
+ https://www.retro-kit.co.uk/page.cfm/content/Hybrid-Music-4000-Keyboard/
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Hybrid_Music4000.html
+
+**********************************************************************/
+
+
+#include "emu.h"
+#include "m4000.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(BBC_M4000, bbc_m4000_device, "bbc_m4000", "Hybrid Music 4000 Keyboard")
+
+
+//-------------------------------------------------
+// INPUT_PORTS( m4000 )
+//-------------------------------------------------
+
+static INPUT_PORTS_START( m4000 )
+ PORT_START("KBLOCK_1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C2")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C2#")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D2")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D2#")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E2")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F2")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F2#")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G2")
+
+ PORT_START("KBLOCK_2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G2#")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A2")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A2#")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B2")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C3")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C3#")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D3")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D3#")
+
+ PORT_START("KBLOCK_3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E3")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F3")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F3#")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G3")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G3#")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A3")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A3#")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B3")
+
+ PORT_START("KBLOCK_4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C4")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C4#")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D4")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D4#")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E4")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F4")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F4#")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G4")
+
+ PORT_START("KBLOCK_5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G4#")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A4")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A4#")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B4")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C5")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C5#")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D5")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("D5#")
+
+ PORT_START("KBLOCK_6")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("E5")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F5")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("F5#")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G5")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("G5#")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A5")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("A5#")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("B5")
+
+ PORT_START("KBLOCK_7")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("C6")
+ PORT_BIT(0xfe, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("KBLOCK_8")
+ PORT_BIT(0x7f, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Foot Switch")
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor bbc_m4000_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( m4000 );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// bbc_m4000_device - constructor
+//-------------------------------------------------
+
+bbc_m4000_device::bbc_m4000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, BBC_M4000, tag, owner, clock)
+ , device_bbc_userport_interface(mconfig, *this)
+ , m_kbd(*this, "KBLOCK_%u", 1)
+ , m_clk(0)
+ , m_dsb(0)
+ , m_out(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void bbc_m4000_device::device_start()
+{
+ save_item(NAME(m_clk));
+ save_item(NAME(m_dsb));
+ save_item(NAME(m_out));
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+void bbc_m4000_device::write_cb1(int state)
+{
+ // 74hc164
+ if (!m_clk && state)
+ {
+ m_out = (m_out << 1) | m_dsb;
+ }
+ m_clk = state;
+}
+
+void bbc_m4000_device::write_cb2(int state)
+{
+ // 74hc164
+ m_dsb = state;
+}
+
+uint8_t bbc_m4000_device::pb_r()
+{
+ uint8_t data = 0xff;
+
+ for (int block = 0; block < 8; block++)
+ {
+ if (!BIT(m_out, block))
+ data = m_kbd[block]->read();
+ }
+
+ return data;
+}
diff --git a/src/devices/bus/bbc/userport/m4000.h b/src/devices/bus/bbc/userport/m4000.h
new file mode 100644
index 00000000000..df9c5e556cf
--- /dev/null
+++ b/src/devices/bus/bbc/userport/m4000.h
@@ -0,0 +1,58 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/**********************************************************************
+
+ Hybrid Music 4000 Keyboard
+
+ https://www.retro-kit.co.uk/page.cfm/content/Hybrid-Music-4000-Keyboard/
+ http://chrisacorns.computinghistory.org.uk/8bit_Upgrades/Hybrid_Music4000.html
+
+**********************************************************************/
+
+
+#ifndef MAME_BUS_BBC_USERPORT_M4000_H
+#define MAME_BUS_BBC_USERPORT_M4000_H
+
+#pragma once
+
+#include "userport.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> bbc_m4000_device
+
+class bbc_m4000_device :
+ public device_t,
+ public device_bbc_userport_interface
+{
+public:
+ // construction/destruction
+ bbc_m4000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const override;
+
+ virtual uint8_t pb_r() override;
+ virtual void write_cb1(int state) override;
+ virtual void write_cb2(int state) override;
+
+private:
+ required_ioport_array<8> m_kbd;
+
+ int m_clk;
+ int m_dsb;
+ uint8_t m_out;
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(BBC_M4000, bbc_m4000_device)
+
+
+#endif // MAME_BUS_BBC_USERPORT_M4000_H
diff --git a/src/devices/bus/bbc/userport/userport.cpp b/src/devices/bus/bbc/userport/userport.cpp
index d312cc10d50..3091c04f816 100644
--- a/src/devices/bus/bbc/userport/userport.cpp
+++ b/src/devices/bus/bbc/userport/userport.cpp
@@ -51,12 +51,12 @@ device_bbc_userport_interface::~device_bbc_userport_interface()
// bbc_userport_slot_device - constructor
//-------------------------------------------------
-bbc_userport_slot_device::bbc_userport_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, BBC_USERPORT_SLOT, tag, owner, clock),
- device_single_card_slot_interface<device_bbc_userport_interface>(mconfig, *this),
- m_device(nullptr),
- m_cb1_handler(*this),
- m_cb2_handler(*this)
+bbc_userport_slot_device::bbc_userport_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, BBC_USERPORT_SLOT, tag, owner, clock)
+ , device_single_card_slot_interface<device_bbc_userport_interface>(mconfig, *this)
+ , m_device(nullptr)
+ , m_cb1_handler(*this)
+ , m_cb2_handler(*this)
{
}
@@ -101,6 +101,28 @@ void bbc_userport_slot_device::pb_w(uint8_t data)
//-------------------------------------------------
+// write_cb1
+//-------------------------------------------------
+
+void bbc_userport_slot_device::write_cb1(int state)
+{
+ if (m_device)
+ m_device->write_cb1(state);
+}
+
+
+//-------------------------------------------------
+// write_cb2
+//-------------------------------------------------
+
+void bbc_userport_slot_device::write_cb2(int state)
+{
+ if (m_device)
+ m_device->write_cb2(state);
+}
+
+
+//-------------------------------------------------
// SLOT_INTERFACE( bbc_userport_devices )
//-------------------------------------------------
@@ -110,6 +132,7 @@ void bbc_userport_slot_device::pb_w(uint8_t data)
//#include "digitiser.h"
//#include "ev1.h"
#include "lcd.h"
+#include "m4000.h"
#include "palext.h"
#include "pointer.h"
#include "usersplit.h"
@@ -129,11 +152,11 @@ void bbc_userport_devices(device_slot_interface &device)
//device.option_add("ev1", BBC_EV1); /* Micro-Robotics EV1 */
//device.option_add("hobbit", BBC_HOBBIT); /* Hobbit Floppy Tape System (Ikon) */
device.option_add("lcd", BBC_LCD); /* Sprow LCD Display */
+ device.option_add("m4000", BBC_M4000); /* Hybrid Music 4000 Keyboard */
device.option_add("m512mouse", BBC_M512MOUSE); /* Acorn Mouse (provided with Master 512) */
device.option_add("tracker", BBC_TRACKER); /* Marconi RB2 Tracker Ball / Acorn Tracker Ball */
device.option_add("usersplit", BBC_USERSPLIT); /*User Port Splitter (Watford Electronics) */
//device.option_add("vci", BBC_VCI); /* Video Camera Interface (Data Harvest) */
device.option_add("voicebox", BBC_VOICEBOX); /* Robin Voice Box */
- //device.option_add("music4000", BBC_MUSIC4000); /* Hybrid Music 4000 Keyboard */
device.option_add_internal("cfa3000kbd", CFA3000_KBD);/* Henson CFA 3000 Keyboard */
}
diff --git a/src/devices/bus/bbc/userport/userport.h b/src/devices/bus/bbc/userport/userport.h
index c0a0b560eac..29374eb9058 100644
--- a/src/devices/bus/bbc/userport/userport.h
+++ b/src/devices/bus/bbc/userport/userport.h
@@ -61,11 +61,15 @@ public:
auto cb1_handler() { return m_cb1_handler.bind(); }
auto cb2_handler() { return m_cb2_handler.bind(); }
+ // from slot
DECLARE_WRITE_LINE_MEMBER(cb1_w) { m_cb1_handler(state); }
DECLARE_WRITE_LINE_MEMBER(cb2_w) { m_cb2_handler(state); }
+ // from host
uint8_t pb_r();
void pb_w(uint8_t data);
+ void write_cb1(int state);
+ void write_cb2(int state);
protected:
// device-level overrides
@@ -89,6 +93,8 @@ public:
virtual uint8_t pb_r() { return 0xff; }
virtual void pb_w(uint8_t data) { }
+ virtual void write_cb1(int state) { }
+ virtual void write_cb2(int state) { }
protected:
device_bbc_userport_interface(const machine_config &mconfig, device_t &device);
diff --git a/src/devices/bus/bbc/userport/usersplit.cpp b/src/devices/bus/bbc/userport/usersplit.cpp
index abe6ec155bf..520abaebdb9 100644
--- a/src/devices/bus/bbc/userport/usersplit.cpp
+++ b/src/devices/bus/bbc/userport/usersplit.cpp
@@ -98,6 +98,17 @@ void bbc_usersplit_device::pb_w(uint8_t data)
m_userport[m_selected]->pb_w(data);
}
+void bbc_usersplit_device::write_cb1(int state)
+{
+ m_userport[m_selected]->write_cb1(state);
+}
+
+void bbc_usersplit_device::write_cb2(int state)
+{
+ m_userport[m_selected]->write_cb2(state);
+}
+
+
WRITE_LINE_MEMBER(bbc_usersplit_device::cb1a_w)
{
if (m_selected == 0x00)
diff --git a/src/devices/bus/bbc/userport/usersplit.h b/src/devices/bus/bbc/userport/usersplit.h
index d10a31a3eb2..27ce11a9fde 100644
--- a/src/devices/bus/bbc/userport/usersplit.h
+++ b/src/devices/bus/bbc/userport/usersplit.h
@@ -40,6 +40,8 @@ protected:
virtual uint8_t pb_r() override;
virtual void pb_w(uint8_t data) override;
+ virtual void write_cb1(int state) override;
+ virtual void write_cb2(int state) override;
private:
DECLARE_WRITE_LINE_MEMBER(cb1a_w);
diff --git a/src/devices/bus/bw2/ramcard.cpp b/src/devices/bus/bw2/ramcard.cpp
index 48de6cffdec..b1e0bfe5bcf 100644
--- a/src/devices/bus/bw2/ramcard.cpp
+++ b/src/devices/bus/bw2/ramcard.cpp
@@ -90,15 +90,17 @@ void bw2_ramcard_device::device_reset()
uint8_t bw2_ramcard_device::bw2_cd_r(offs_t offset, uint8_t data, int ram2, int ram3, int ram4, int ram5, int ram6)
{
- if (!ram2)
+ if (offset < 0x8000)
{
- data = m_rom->base()[offset & 0x3fff];
+ if (!ram2)
+ {
+ data = m_rom->base()[offset & 0x3fff];
+ }
+ else if (m_en && !ram5)
+ {
+ data = m_ram[(m_bank << 15) | offset];
+ }
}
- else if (m_en && !ram5)
- {
- data = m_ram[(m_bank << 15) | offset];
- }
-
return data;
}
@@ -109,9 +111,12 @@ uint8_t bw2_ramcard_device::bw2_cd_r(offs_t offset, uint8_t data, int ram2, int
void bw2_ramcard_device::bw2_cd_w(offs_t offset, uint8_t data, int ram2, int ram3, int ram4, int ram5, int ram6)
{
- if (m_en && !ram5)
+ if (offset < 0x8000)
{
- m_ram[(m_bank << 15) | offset] = data;
+ if (m_en && !ram5)
+ {
+ m_ram[(m_bank << 15) | offset] = data;
+ }
}
}
diff --git a/src/devices/bus/c64/xl80.cpp b/src/devices/bus/c64/xl80.cpp
index 8f0f35b523f..6bfa6e9d8cd 100644
--- a/src/devices/bus/c64/xl80.cpp
+++ b/src/devices/bus/c64/xl80.cpp
@@ -85,12 +85,12 @@ const tiny_rom_entry *c64_xl80_device::device_rom_region() const
MC6845_UPDATE_ROW( c64_xl80_device::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
for (int column = 0; column < x_count; column++)
{
- uint8_t code = m_ram[((ma + column) & 0x7ff)];
- uint16_t addr = (code << 3) | (ra & 0x07);
+ uint8_t const code = m_ram[((ma + column) & 0x7ff)];
+ uint16_t const addr = (code << 3) | (ra & 0x07);
uint8_t data = m_char_rom->base()[addr & 0x7ff];
if (column == cursor_x)
@@ -100,10 +100,10 @@ MC6845_UPDATE_ROW( c64_xl80_device::crtc_update_row )
for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
- int color = BIT(data, 7) && de;
+ int const x = (column * 8) + bit;
+ int const color = BIT(data, 7) && de;
- bitmap.pix32(vbp + y, hbp + x) = pen[color];
+ bitmap.pix(vbp + y, hbp + x) = pen[color];
data <<= 1;
}
diff --git a/src/devices/bus/cbmiec/cbmiec.cpp b/src/devices/bus/cbmiec/cbmiec.cpp
index 98535963034..4ee8f287200 100644
--- a/src/devices/bus/cbmiec/cbmiec.cpp
+++ b/src/devices/bus/cbmiec/cbmiec.cpp
@@ -338,7 +338,7 @@ void cbm_iec_device::device_stop()
void cbm_iec_device::add_device(cbm_iec_slot_device *slot, device_t *target)
{
- auto entry = global_alloc(daisy_entry(target));
+ auto entry = new daisy_entry(target);
entry->m_interface->m_slot = slot;
entry->m_interface->m_bus = this;
diff --git a/src/devices/bus/centronics/epson_lx810l.cpp b/src/devices/bus/centronics/epson_lx810l.cpp
index 1d9c0ac8577..2744ea3e3ac 100644
--- a/src/devices/bus/centronics/epson_lx810l.cpp
+++ b/src/devices/bus/centronics/epson_lx810l.cpp
@@ -575,9 +575,9 @@ WRITE_LINE_MEMBER( epson_lx810l_device::co0_w )
*/
if (m_real_cr_pos < m_bitmap.width()) {
for (int i = 0; i < 9; i++) {
- unsigned int y = bitmap_line(i);
+ unsigned int const y = bitmap_line(i);
if ((m_printhead & (1<<(8-i))) != 0)
- m_bitmap.pix32(y, m_real_cr_pos + CR_OFFSET) = 0x000000;
+ m_bitmap.pix(y, m_real_cr_pos + CR_OFFSET) = 0x000000;
}
}
}
diff --git a/src/devices/bus/coco/coco_ssc.cpp b/src/devices/bus/coco/coco_ssc.cpp
index 63f6e90fcc5..3677010648f 100644
--- a/src/devices/bus/coco/coco_ssc.cpp
+++ b/src/devices/bus/coco/coco_ssc.cpp
@@ -130,7 +130,7 @@ namespace
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream* m_stream;
@@ -535,25 +535,25 @@ cocossc_sac_device::cocossc_sac_device(const machine_config &mconfig, const char
void cocossc_sac_device::device_start()
{
- m_stream = stream_alloc_legacy(1, 1, machine().sample_rate());
+ m_stream = stream_alloc(1, 1, machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void cocossc_sac_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void cocossc_sac_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t const *src = inputs[0];
- stream_sample_t *dst = outputs[0];
+ auto &src = inputs[0];
+ auto &dst = outputs[0];
- double n = samples;
+ double n = dst.samples();
- while (samples--)
+ for (int sampindex = 0; sampindex < n; sampindex++)
{
- m_rms[m_index] += ( (double)*src * (double)*src );
- *dst++ = (*src++);
+ m_rms[m_index] += src.get(sampindex) * src.get(sampindex);
+ dst.put(sampindex, src.get(sampindex));
}
m_rms[m_index] = m_rms[m_index] / n;
@@ -576,7 +576,7 @@ bool cocossc_sac_device::sound_activity_circuit_output()
average /= 16.0;
- if( average > 10400.0 )
+ if( average > 0.317 )
return true;
return false;
diff --git a/src/devices/bus/compis/hrg.cpp b/src/devices/bus/compis/hrg.cpp
index 7aa8aa72f7e..1612729e706 100644
--- a/src/devices/bus/compis/hrg.cpp
+++ b/src/devices/bus/compis/hrg.cpp
@@ -51,11 +51,11 @@ void compis_uhrg_device::uhrg_map(address_map &map)
UPD7220_DISPLAY_PIXELS_MEMBER( compis_hrg_device::display_pixels )
{
- uint16_t i,gfx = m_video_ram[(address & 0x7fff) >> 1];
- const pen_t *pen = m_palette->pens();
+ uint16_t const gfx = m_video_ram[(address & 0x7fff) >> 1];
+ pen_t const *const pen = m_palette->pens();
- for(i=0; i<16; i++)
- bitmap.pix32(y, x + i) = pen[BIT(gfx, i)];
+ for(uint16_t i=0; i<16; i++)
+ bitmap.pix(y, x + i) = pen[BIT(gfx, i)];
}
@@ -65,11 +65,11 @@ UPD7220_DISPLAY_PIXELS_MEMBER( compis_hrg_device::display_pixels )
UPD7220_DISPLAY_PIXELS_MEMBER( compis_uhrg_device::display_pixels )
{
- uint16_t i,gfx = m_video_ram[(address & 0x1ffff) >> 1];
- const pen_t *pen = m_palette->pens();
+ uint16_t const gfx = m_video_ram[(address & 0x1ffff) >> 1];
+ pen_t const *const pen = m_palette->pens();
- for(i=0; i<16; i++)
- bitmap.pix32(y, x + i) = pen[BIT(gfx, i)];
+ for(uint16_t i=0; i<16; i++)
+ bitmap.pix(y, x + i) = pen[BIT(gfx, i)];
}
diff --git a/src/devices/bus/comx35/clm.cpp b/src/devices/bus/comx35/clm.cpp
index ebf7e1f271e..192e5989a36 100644
--- a/src/devices/bus/comx35/clm.cpp
+++ b/src/devices/bus/comx35/clm.cpp
@@ -104,8 +104,8 @@ MC6845_UPDATE_ROW( comx_clm_device::crtc_update_row )
{
for (int column = 0; column < x_count; column++)
{
- uint8_t code = m_video_ram[((ma + column) & 0x7ff)];
- uint16_t addr = (code << 3) | (ra & 0x07);
+ uint8_t const code = m_video_ram[((ma + column) & 0x7ff)];
+ uint16_t const addr = (code << 3) | (ra & 0x07);
uint8_t data = m_char_rom->base()[addr & 0x7ff];
if (BIT(ra, 3) && column == cursor_x)
@@ -115,9 +115,9 @@ MC6845_UPDATE_ROW( comx_clm_device::crtc_update_row )
for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
+ int const x = (column * 8) + bit;
- bitmap.pix32(vbp + y, hbp + x) = m_palette->pen(BIT(data, 7) && de);
+ bitmap.pix(vbp + y, hbp + x) = m_palette->pen(BIT(data, 7) && de);
data <<= 1;
}
diff --git a/src/devices/bus/ecbbus/grip.cpp b/src/devices/bus/ecbbus/grip.cpp
index 88e3d2fe23b..659bab524ad 100644
--- a/src/devices/bus/ecbbus/grip.cpp
+++ b/src/devices/bus/ecbbus/grip.cpp
@@ -179,35 +179,33 @@ MC6845_UPDATE_ROW( ecb_grip21_device::crtc_update_row )
{
for (int column = 0; column < x_count; column++)
{
- uint16_t address = (m_page << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07);
- uint8_t data = m_video_ram[address];
+ uint16_t const address = (m_page << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07);
+ uint8_t const data = m_video_ram[address];
for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
- int color = (m_flash ? 0 : BIT(data, bit)) && de;
+ int const x = (column * 8) + bit;
+ int const color = (m_flash ? 0 : BIT(data, bit)) && de;
- bitmap.pix32(vbp + y, hbp + x) = m_palette->pen(color);
+ bitmap.pix(vbp + y, hbp + x) = m_palette->pen(color);
}
}
}
/*
MC6845_UPDATE_ROW( ecb_grip21_device::grip5_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int column, bit;
-
- for (column = 0; column < x_count; column++)
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ for (int column = 0; column < x_count; column++)
{
- uint16_t address = (m_dpage << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07);
- uint8_t data = m_video_ram[address];
+ uint16_t const address = (m_dpage << 12) | (((ma + column) & 0xfff) << 3) | (ra & 0x07);
+ uint8_t const data = m_video_ram[address];
- for (bit = 0; bit < 8; bit++)
+ for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
- int color = m_flash ? 0 : BIT(data, bit);
+ int const x = (column * 8) + bit;
+ int const color = m_flash ? 0 : BIT(data, bit);
- bitmap.pix32(y, x) = palette[color];
+ bitmap.pix(y, x) = palette[color];
}
}
}
@@ -217,7 +215,7 @@ MC6845_ON_UPDATE_ADDR_CHANGED( ecb_grip21_device::grip5_addr_changed )
}
*/
-static const int16_t speaker_levels[] = { -32768, 0, 32767, 0 };
+static const double speaker_levels[] = { -1.0, 0.0, 1.0, 0.0 };
//-------------------------------------------------
// I8255A interface
diff --git a/src/devices/bus/econet/econet.cpp b/src/devices/bus/econet/econet.cpp
index f87850fe133..e9afc9c0d49 100644
--- a/src/devices/bus/econet/econet.cpp
+++ b/src/devices/bus/econet/econet.cpp
@@ -223,7 +223,7 @@ void econet_device::device_stop()
void econet_device::add_device(device_t *target, int address)
{
- auto entry = global_alloc(daisy_entry(target));
+ auto entry = new daisy_entry(target);
entry->m_interface->m_econet = this;
entry->m_interface->m_address = address;
diff --git a/src/devices/bus/einstein/pipe/tk02.cpp b/src/devices/bus/einstein/pipe/tk02.cpp
index b0cf5998131..74cd880e151 100644
--- a/src/devices/bus/einstein/pipe/tk02.cpp
+++ b/src/devices/bus/einstein/pipe/tk02.cpp
@@ -185,14 +185,14 @@ MC6845_UPDATE_ROW( tk02_device::crtc_update_row )
if (i == cursor_x)
data ^= 0xff;
- bitmap.pix32(y, i * 8 + 0) = pen[BIT(data, 7)];
- bitmap.pix32(y, i * 8 + 1) = pen[BIT(data, 6)];
- bitmap.pix32(y, i * 8 + 2) = pen[BIT(data, 5)];
- bitmap.pix32(y, i * 8 + 3) = pen[BIT(data, 4)];
- bitmap.pix32(y, i * 8 + 4) = pen[BIT(data, 3)];
- bitmap.pix32(y, i * 8 + 5) = pen[BIT(data, 2)];
- bitmap.pix32(y, i * 8 + 6) = pen[BIT(data, 1)];
- bitmap.pix32(y, i * 8 + 7) = pen[BIT(data, 0)];
+ bitmap.pix(y, i * 8 + 0) = pen[BIT(data, 7)];
+ bitmap.pix(y, i * 8 + 1) = pen[BIT(data, 6)];
+ bitmap.pix(y, i * 8 + 2) = pen[BIT(data, 5)];
+ bitmap.pix(y, i * 8 + 3) = pen[BIT(data, 4)];
+ bitmap.pix(y, i * 8 + 4) = pen[BIT(data, 3)];
+ bitmap.pix(y, i * 8 + 5) = pen[BIT(data, 2)];
+ bitmap.pix(y, i * 8 + 6) = pen[BIT(data, 1)];
+ bitmap.pix(y, i * 8 + 7) = pen[BIT(data, 0)];
}
}
diff --git a/src/devices/bus/electron/cart/ap5.cpp b/src/devices/bus/electron/cart/ap5.cpp
index c65daf911d4..3deacaa655b 100644
--- a/src/devices/bus/electron/cart/ap5.cpp
+++ b/src/devices/bus/electron/cart/ap5.cpp
@@ -36,6 +36,8 @@ void electron_ap5_device::device_add_mconfig(machine_config &config)
VIA6522(config, m_via, DERIVED_CLOCK(1, 16));
m_via->readpb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_r));
m_via->writepb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_w));
+ m_via->cb1_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb1));
+ m_via->cb2_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb2));
m_via->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<0>));
/* user port */
diff --git a/src/devices/bus/electron/mode7.cpp b/src/devices/bus/electron/mode7.cpp
index 103c861c4ae..408b6a92300 100644
--- a/src/devices/bus/electron/mode7.cpp
+++ b/src/devices/bus/electron/mode7.cpp
@@ -195,7 +195,7 @@ void electron_mode7_device::expbus_w(offs_t offset, uint8_t data)
MC6845_UPDATE_ROW(electron_mode7_device::crtc_update_row)
{
- uint32_t* p = &bitmap.pix32(y);
+ uint32_t* p = &bitmap.pix(y);
m_trom->lose_w(1);
m_trom->lose_w(0);
diff --git a/src/devices/bus/electron/plus2.cpp b/src/devices/bus/electron/plus2.cpp
index f0e28d73150..1e9d9d6591b 100644
--- a/src/devices/bus/electron/plus2.cpp
+++ b/src/devices/bus/electron/plus2.cpp
@@ -53,6 +53,8 @@ void electron_plus2_device::device_add_mconfig(machine_config &config)
VIA6522(config, m_via, DERIVED_CLOCK(1, 16));
m_via->readpb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_r));
m_via->writepb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_w));
+ m_via->cb1_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb1));
+ m_via->cb2_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb2));
m_via->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<2>));
/* user port */
diff --git a/src/devices/bus/fmt_scsi/fmt121.cpp b/src/devices/bus/fmt_scsi/fmt121.cpp
new file mode 100644
index 00000000000..34f784115a0
--- /dev/null
+++ b/src/devices/bus/fmt_scsi/fmt121.cpp
@@ -0,0 +1,150 @@
+// license:BSD-3-Clause
+// copyright-holders:r09
+/****************************************************************************
+
+ Fujitsu FMT-121 SCSI Card
+
+ An expansion card for the dedicated SCSI card slot on the FM Towns
+ Model 1 and 2 computers. It contains a Fujitsu MB673522U SCSI controller
+ and an external 50-pin Centronics connector.
+
+ |||||||||||||||||||||
++-------------------------| |-------------------------+
+| CN1 +-------------------+ |
+| |
+| 74LS04N |
+| 74LS14N 74LS240N SN74LS06N |
+| MB413 |
+| MB463 |
+| 74AS00N |
+| +-----------+ |
+| MB463 | | |
+| | MB673522U | MB412 |
+| +-----------+ |
+| MB463 74LS240N |
+| CN3 |
+| .......................................... |
+| . . |
+| .......................................... |
+| CN2 |
+| +----------------------------------------+ |
+| | | |
++--------------| |---------------+
+ ||||||||||||||||||||||||||||||||||||||||||
+
+ CN1: 30-pin MFC-30LFD DIP connector
+ CN2: 50-pin Centronics connector
+ CN3: solder pads for internal 50-pin connector (not present)
+
+****************************************************************************/
+
+#include "emu.h"
+#include "fmt121.h"
+
+#include "bus/scsi/scsi.h"
+#include "bus/scsi/scsihd.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(FMT121, fmt121_device, "fmt121", "FMT-121 SCSI Card")
+
+//**************************************************************************
+// DEVICE DEFINITION
+//**************************************************************************
+
+//-------------------------------------------------
+// fmt121_device - construction
+//-------------------------------------------------
+
+fmt121_device::fmt121_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, FMT121, tag, owner, clock)
+ , fmt_scsi_card_interface(mconfig, *this)
+ , m_scsi_ctlr(*this, "fmscsi")
+{
+}
+
+
+//-------------------------------------------------
+// device_add_mconfig - add device-specific
+// machine configuration
+//-------------------------------------------------
+
+void fmt121_device::device_add_mconfig(machine_config &config)
+{
+ scsi_port_device &scsi(SCSI_PORT(config, "scsi", 0));
+ scsi.set_slot_device(1, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_0));
+ scsi.set_slot_device(2, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_1));
+ scsi.set_slot_device(3, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_2));
+ scsi.set_slot_device(4, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_3));
+ scsi.set_slot_device(5, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_4));
+
+ FMSCSI(config, m_scsi_ctlr, 0);
+ m_scsi_ctlr->set_scsi_port("scsi");
+ m_scsi_ctlr->irq_handler().set(FUNC(fmt121_device::irq_w));
+ m_scsi_ctlr->drq_handler().set(FUNC(fmt121_device::drq_w));
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void fmt121_device::device_start()
+{
+}
+
+//**************************************************************************
+// FMT121 INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// fmt_scsi_read - I/O read access
+//-------------------------------------------------
+
+u8 fmt121_device::fmt_scsi_read(offs_t offset)
+{
+ return m_scsi_ctlr->fmscsi_r(offset);
+}
+
+
+//-------------------------------------------------
+// fmt_scsi_write - I/O write access
+//-------------------------------------------------
+
+void fmt121_device::fmt_scsi_write(offs_t offset, u8 data)
+{
+ m_scsi_ctlr->fmscsi_w(offset, data);
+}
+
+//-------------------------------------------------
+// fmt_scsi_data_read - data read access
+//-------------------------------------------------
+
+u8 fmt121_device::fmt_scsi_data_read()
+{
+ return m_scsi_ctlr->fmscsi_data_r();
+}
+
+//-------------------------------------------------
+// fmt_scsi_data_write - data write access
+//-------------------------------------------------
+
+void fmt121_device::fmt_scsi_data_write(u8 data)
+{
+ m_scsi_ctlr->fmscsi_data_w(data);
+}
+
+
+void fmt121_device::irq_w(int state)
+{
+ m_slot->irq_w(state);
+}
+
+
+void fmt121_device::drq_w(int state)
+{
+ m_slot->drq_w(state);
+}
diff --git a/src/devices/bus/fmt_scsi/fmt121.h b/src/devices/bus/fmt_scsi/fmt121.h
new file mode 100644
index 00000000000..9b80b2c70f1
--- /dev/null
+++ b/src/devices/bus/fmt_scsi/fmt121.h
@@ -0,0 +1,50 @@
+// license:BSD-3-Clause
+// copyright-holders:r09
+
+#ifndef MAME_BUS_FMT_SCSI_FMT121_H
+#define MAME_BUS_FMT_SCSI_FMT121_H
+
+#pragma once
+
+#include "fmt_scsi.h"
+
+#include "machine/fm_scsi.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> fmt121_device
+
+class fmt121_device : public device_t, public fmt_scsi_card_interface
+{
+public:
+ // device type constructor
+ fmt121_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+protected:
+ // device-level overrides
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+
+ // fmt_scsi_card_interface overrides
+ virtual u8 fmt_scsi_read(offs_t offset) override;
+ virtual void fmt_scsi_write(offs_t offset, u8 data) override;
+
+ virtual u8 fmt_scsi_data_read(void) override;
+ virtual void fmt_scsi_data_write(u8 data) override;
+
+private:
+
+ required_device<fmscsi_device> m_scsi_ctlr;
+
+ void irq_w(int state);
+ void drq_w(int state);
+
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(FMT121, fmt121_device)
+
+#endif // MAME_BUS_FMT_SCSI_FMT121_H
diff --git a/src/devices/bus/fmt_scsi/fmt_scsi.cpp b/src/devices/bus/fmt_scsi/fmt_scsi.cpp
new file mode 100644
index 00000000000..b5d62fb3577
--- /dev/null
+++ b/src/devices/bus/fmt_scsi/fmt_scsi.cpp
@@ -0,0 +1,158 @@
+// license:BSD-3-Clause
+// copyright-holders:r09
+/****************************************************************************
+
+ Fujitsu FM Towns SCSI card slot
+
+ This is a dedicated 30-pin slot for the FMT-121 SCSI Card. It is only
+ present on the Model 1 and 2; all later models integrate the SCSI
+ controller directly on the motherboard.
+
+****************************************************************************/
+
+#include "emu.h"
+#include "fmt_scsi.h"
+
+#include "fmt121.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(FMT_SCSI_SLOT, fmt_scsi_slot_device, "fmt_scsi_slot", "FM Towns SCSI card slot")
+
+//**************************************************************************
+// FMT_SCSI SLOT DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// fmt_scsi_slot_device - construction
+//-------------------------------------------------
+
+fmt_scsi_slot_device::fmt_scsi_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, FMT_SCSI_SLOT, tag, owner, clock)
+ , device_single_card_slot_interface<fmt_scsi_card_interface>(mconfig, *this)
+ , m_card(nullptr)
+ , m_irq_handler(*this)
+ , m_drq_handler(*this)
+{
+}
+
+
+//-------------------------------------------------
+// device_resolve_objects - resolve objects that
+// may be needed for other devices to set
+// initial conditions at start time
+//-------------------------------------------------
+
+void fmt_scsi_slot_device::device_resolve_objects()
+{
+ m_card = get_card_device();
+ if (m_card != nullptr)
+ m_card->m_slot = this;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void fmt_scsi_slot_device::device_start()
+{
+ m_irq_handler.resolve_safe();
+ m_drq_handler.resolve_safe();
+}
+
+
+//-------------------------------------------------
+// read - I/O read access
+//-------------------------------------------------
+
+u8 fmt_scsi_slot_device::read(address_space &space, offs_t offset)
+{
+ if (m_card)
+ return m_card->fmt_scsi_read(offset);
+ else
+ return space.unmap();
+}
+
+
+//-------------------------------------------------
+// write - I/O write access
+//-------------------------------------------------
+
+void fmt_scsi_slot_device::write(offs_t offset, u8 data)
+{
+ if (m_card)
+ m_card->fmt_scsi_write(offset, data);
+}
+
+//-------------------------------------------------
+// data_read - data read access
+//-------------------------------------------------
+
+u8 fmt_scsi_slot_device::data_read()
+{
+ if (m_card)
+ return m_card->fmt_scsi_data_read();
+ else
+ return 0;
+}
+
+//-------------------------------------------------
+// data_write - data write access
+//-------------------------------------------------
+
+void fmt_scsi_slot_device::data_write(u8 data)
+{
+ if (m_card)
+ m_card->fmt_scsi_data_write(data);
+}
+
+void fmt_scsi_slot_device::irq_w(int state)
+{
+ m_irq_handler(state);
+}
+
+void fmt_scsi_slot_device::drq_w(int state)
+{
+ m_drq_handler(state);
+}
+
+//**************************************************************************
+// FMT_SCSI CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// fmt_scsi_card_interface - construction
+//-------------------------------------------------
+
+fmt_scsi_card_interface::fmt_scsi_card_interface(const machine_config &mconfig, device_t &device)
+ : device_interface(device, "fmtscsicard")
+ , m_slot(nullptr)
+{
+}
+
+
+//-------------------------------------------------
+// interface_pre_start - called before the
+// device's own start function
+//-------------------------------------------------
+
+void fmt_scsi_card_interface::interface_pre_start()
+{
+ if (!m_slot)
+ throw device_missing_dependencies();
+}
+
+
+//-------------------------------------------------
+// fmt_scsi_default_devices - add standard options
+// for main slots
+//-------------------------------------------------
+
+void fmt_scsi_default_devices(device_slot_interface &device)
+{
+ device.option_add("fmt121", FMT121);
+}
diff --git a/src/devices/bus/fmt_scsi/fmt_scsi.h b/src/devices/bus/fmt_scsi/fmt_scsi.h
new file mode 100644
index 00000000000..549b1047f4c
--- /dev/null
+++ b/src/devices/bus/fmt_scsi/fmt_scsi.h
@@ -0,0 +1,98 @@
+// license:BSD-3-Clause
+// copyright-holders:r09
+/**********************************************************************
+
+ Fujitsu FM Towns SCSI card slot
+
+**********************************************************************/
+
+#ifndef MAME_BUS_FMT_SCSI_FMT_SCSI_H
+#define MAME_BUS_FMT_SCSI_FMT_SCSI_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// forward declarations
+class fmt_scsi_card_interface;
+
+// ======================> fmt_scsi_slot_device
+
+class fmt_scsi_slot_device : public device_t, public device_single_card_slot_interface<fmt_scsi_card_interface>
+{
+ friend class fmt_scsi_card_interface;
+
+public:
+ // construction/destruction
+ template <typename T>
+ fmt_scsi_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt)
+ : fmt_scsi_slot_device(mconfig, tag, owner, 0)
+ {
+ option_reset();
+ opts(*this);
+ set_default_option(dflt);
+ set_fixed(false);
+ }
+
+ fmt_scsi_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ auto irq_handler() { return m_irq_handler.bind(); }
+ auto drq_handler() { return m_drq_handler.bind(); }
+
+ u8 read(address_space &space, offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ uint8_t data_read(void);
+ void data_write(uint8_t data);
+
+ void irq_w(int state);
+ void drq_w(int state);
+
+protected:
+ // device-specific overrides
+ virtual void device_resolve_objects() override;
+ virtual void device_start() override;
+
+private:
+ fmt_scsi_card_interface *m_card;
+
+ devcb_write_line m_irq_handler;
+ devcb_write_line m_drq_handler;
+
+};
+
+
+// ======================> fmt_scsi_card_interface
+
+class fmt_scsi_card_interface : public device_interface
+{
+ friend class fmt_scsi_slot_device;
+
+protected:
+ // construction/destruction
+ fmt_scsi_card_interface(const machine_config &mconfig, device_t &device);
+
+ // required overrides
+ virtual u8 fmt_scsi_read(offs_t offset) = 0;
+ virtual void fmt_scsi_write(offs_t offset, u8 data) = 0;
+
+ virtual u8 fmt_scsi_data_read(void) = 0;
+ virtual void fmt_scsi_data_write(u8 data) = 0;
+
+ fmt_scsi_slot_device *m_slot;
+
+private:
+ virtual void interface_pre_start() override;
+
+};
+
+
+// device type definition
+DECLARE_DEVICE_TYPE(FMT_SCSI_SLOT, fmt_scsi_slot_device)
+
+void fmt_scsi_default_devices(device_slot_interface &device);
+
+#endif // MAME_BUS_FMT_SCSI_FMT_SCSI_H
diff --git a/src/devices/bus/gio64/newport.cpp b/src/devices/bus/gio64/newport.cpp
index 1be643afddd..142947b4ae0 100644
--- a/src/devices/bus/gio64/newport.cpp
+++ b/src/devices/bus/gio64/newport.cpp
@@ -1302,7 +1302,7 @@ uint32_t newport_base_device::screen_update(screen_device &device, bitmap_rgb32
/* loop over rows and copy to the destination */
for (int y = cliprect.min_y, sy = y_start; y <= cliprect.max_y && sy < y_end; y++, sy++)
{
- uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
+ uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
const uint32_t *src_rgbci = m_rb2->rgbci(y);
const uint32_t *src_cidaux = m_rb2->cidaux(y);
diff --git a/src/devices/bus/hexbus/hexbus.cpp b/src/devices/bus/hexbus/hexbus.cpp
index 0b8d7821cb6..53e8a40e7c0 100644
--- a/src/devices/bus/hexbus/hexbus.cpp
+++ b/src/devices/bus/hexbus/hexbus.cpp
@@ -224,18 +224,20 @@ uint8_t hexbus_device::read(int dir)
hexbus_chained_device::hexbus_chained_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock):
device_t(mconfig, type, tag, owner, clock),
device_hexbus_interface(mconfig, *this),
+ m_hexbus_outbound(nullptr),
m_enabled(false),
m_myvalue(0xff)
{
m_hexbus_inbound = dynamic_cast<hexbus_device *>(owner);
}
-void hexbus_chained_device::device_start()
+void hexbus_chained_device::device_resolve_objects()
{
- m_hexbus_outbound = static_cast<hexbus_device*>(subdevice("hexbus"));
+ m_hexbus_outbound = dynamic_cast<hexbus_device *>(subdevice("hexbus"));
// Establish callback for inbound propagations
- m_hexbus_outbound->set_chain_element(this);
+ if (m_hexbus_outbound != nullptr)
+ m_hexbus_outbound->set_chain_element(this);
}
/*
diff --git a/src/devices/bus/hexbus/hexbus.h b/src/devices/bus/hexbus/hexbus.h
index 76092c0f16f..7f39400974b 100644
--- a/src/devices/bus/hexbus/hexbus.h
+++ b/src/devices/bus/hexbus/hexbus.h
@@ -60,7 +60,7 @@ protected:
void set_outbound_hexbus(hexbus_device *outbound) { m_hexbus_outbound = outbound; }
- virtual void device_start() override;
+ virtual void device_resolve_objects() override;
// Link to the inbound Hexbus (if not null, see Oso chip)
hexbus_device *m_hexbus_inbound;
diff --git a/src/devices/bus/hexbus/hx5102.cpp b/src/devices/bus/hexbus/hx5102.cpp
index f9d2341456e..65f59e0a18a 100644
--- a/src/devices/bus/hexbus/hx5102.cpp
+++ b/src/devices/bus/hexbus/hx5102.cpp
@@ -121,7 +121,9 @@ void hx5102_device::memmap(address_map &map)
*/
void hx5102_device::crumap(address_map &map)
{
- map(0x17e0, 0x17ff).rw(FUNC(hx5102_device::cruread), FUNC(hx5102_device::cruwrite));
+ map(0x17e0, 0x17ff).r(FUNC(hx5102_device::cruread));
+ map(0x17e0, 0x17ef).w(m_crulatch[0], FUNC(ls259_device::write_d0));
+ map(0x17f0, 0x17ff).w(m_crulatch[1], FUNC(ls259_device::write_d0));
}
hx5102_device::hx5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock):
@@ -140,6 +142,7 @@ hx5102_device::hx5102_device(const machine_config &mconfig, const char *tag, dev
m_floppy_select_last(UNDEF),
m_hexbus_ctrl(*this, IBC_TAG),
m_floppy_ctrl(*this, FDC_TAG),
+ m_crulatch(*this, "crulatch%u", 0U),
m_motormf(*this, MTRD_TAG),
m_speedmf(*this, MTSPD_TAG),
m_readyff(*this, READYFF_TAG),
@@ -480,92 +483,81 @@ uint8_t hx5102_device::cruread(offs_t offset)
/*
CRU write access.
*/
-void hx5102_device::cruwrite(offs_t offset, uint8_t data)
+WRITE_LINE_MEMBER(hx5102_device::nocomp_w)
{
- // LOG("Writing CRU address %04x: %x\n", 0x17e0 + (offset<<1), data);
- switch (offset)
- {
- case 0:
- // unused right now
- LOGMASKED(LOG_CRU, "Set precompensation = %d\n", data);
- break;
- case 1:
- if (data==1)
- {
- LOGMASKED(LOG_CRU, "Trigger motor monoflop\n");
- }
- m_motormf->b_w(data);
- break;
- case 2:
- LOGMASKED(LOG_CRU, "Set undefined CRU bit 2 to %d\n", data);
- break;
- case 3:
- LOGMASKED(LOG_CRU, "Set step direction = %d\n", data);
- if (m_current_floppy != nullptr) m_current_floppy->dir_w((data==0)? 1 : 0);
- break;
- case 4:
- if (data==1)
- {
- LOGMASKED(LOG_CRU, "Assert DACK*\n");
- m_dacken = (data != 0);
- }
- break;
- case 5:
- if (data==1)
- {
- LOGMASKED(LOG_CRU, "Step pulse\n");
- }
- if (m_current_floppy != nullptr) m_current_floppy->stp_w((data==0)? 1 : 0);
- break;
- case 6:
- if (data==1)
- {
- LOGMASKED(LOG_CRU, "Start watchdog\n");
- }
- m_speedmf->b_w(data);
- break;
- case 7:
- if (data==0)
- {
- LOGMASKED(LOG_CRU, "Reset i8272A controller\n");
- m_floppy_ctrl->soft_reset();
- }
- break;
- case 8:
- LOGMASKED(LOG_CRU, "Set drive select 0 to %d\n", data);
- if (data == 1) m_floppy_select |= 1;
- else m_floppy_select &= ~1;
- break;
- case 9:
- LOGMASKED(LOG_CRU, "Set drive select 1 to %d\n", data);
- if (data == 1) m_floppy_select |= 2;
- else m_floppy_select &= ~2;
- break;
- case 10:
- // External drive; not implemented
- LOGMASKED(LOG_CRU, "Set drive select 2 to %d\n", data);
- break;
- case 11:
- // External drive; not implemented
- LOGMASKED(LOG_CRU, "Set drive select 3 to %d\n", data);
- break;
- case 12:
- // External drive; not implemented
- LOGMASKED(LOG_CRU, "Set auxiliary motor line to %d\n", data);
- break;
- case 13:
- LOGMASKED(LOG_CRU, "Set CRU bit 13 to %d (unused)\n", data);
- break;
- case 14:
- m_wait = (data!=0);
- LOGMASKED(LOG_CRU, "READY circuit %s\n", m_wait? "active" : "inactive" );
- update_readyff_input();
- break;
- case 15:
- LOGMASKED(LOG_CRU, "Set CRU bit 15 to %d (unused)\n", data);
- break;
- }
+ // unused right now
+ LOGMASKED(LOG_CRU, "Set precompensation = %d\n", state);
+}
+WRITE_LINE_MEMBER(hx5102_device::diren_w)
+{
+ LOGMASKED(LOG_CRU, "Set step direction = %d\n", state);
+ if (m_current_floppy != nullptr)
+ m_current_floppy->dir_w((state==0)? 1 : 0);
+}
+
+WRITE_LINE_MEMBER(hx5102_device::dacken_w)
+{
+ if (state==1)
+ LOGMASKED(LOG_CRU, "Assert DACK*\n");
+ m_dacken = (state != 0);
+}
+
+WRITE_LINE_MEMBER(hx5102_device::stepen_w)
+{
+ if (state==1)
+ LOGMASKED(LOG_CRU, "Step pulse\n");
+ if (m_current_floppy != nullptr)
+ m_current_floppy->stp_w((state==0)? 1 : 0);
+}
+
+WRITE_LINE_MEMBER(hx5102_device::ds1_w)
+{
+ LOGMASKED(LOG_CRU, "Set drive select 0 to %d\n", state);
+ if (state == 1)
+ m_floppy_select |= 1;
+ else
+ m_floppy_select &= ~1;
+ update_drive_select();
+}
+
+WRITE_LINE_MEMBER(hx5102_device::ds2_w)
+{
+ LOGMASKED(LOG_CRU, "Set drive select 1 to %d\n", state);
+ if (state == 1)
+ m_floppy_select |= 2;
+ else
+ m_floppy_select &= ~2;
+ update_drive_select();
+}
+
+WRITE_LINE_MEMBER(hx5102_device::ds3_w)
+{
+ // External drive; not implemented
+ LOGMASKED(LOG_CRU, "Set drive select 2 to %d\n", state);
+}
+
+WRITE_LINE_MEMBER(hx5102_device::ds4_w)
+{
+ // External drive; not implemented
+ LOGMASKED(LOG_CRU, "Set drive select 3 to %d\n", state);
+}
+
+WRITE_LINE_MEMBER(hx5102_device::aux_motor_w)
+{
+ // External drive; not implemented
+ LOGMASKED(LOG_CRU, "Set auxiliary motor line to %d\n", state);
+}
+
+WRITE_LINE_MEMBER(hx5102_device::wait_w)
+{
+ m_wait = (state!=0);
+ LOGMASKED(LOG_CRU, "READY circuit %s\n", m_wait? "active" : "inactive" );
+ update_readyff_input();
+}
+
+void hx5102_device::update_drive_select()
+{
if (m_floppy_select != m_floppy_select_last)
{
if (m_floppy_select == 1)
@@ -677,7 +669,7 @@ void hx5102_device::device_add_mconfig(machine_config& config)
HEXBUS(config, "hexbus", 0, hexbus_options, nullptr);
// TMS9995 CPU @ 12.0 MHz
- TMS9995(config, m_flopcpu, XTAL(12'000'000));
+ TMS9995(config, m_flopcpu, 12_MHz_XTAL);
m_flopcpu->set_addrmap(AS_PROGRAM, &hx5102_device::memmap);
m_flopcpu->set_addrmap(AS_IO, &hx5102_device::crumap);
m_flopcpu->extop_cb().set(FUNC(hx5102_device::external_operation));
@@ -687,27 +679,41 @@ void hx5102_device::device_add_mconfig(machine_config& config)
// Not connected: Select lines (DS0, DS1), Head load (HDL), VCO
// Tied to 1: READY
// Tied to 0: TC
- I8272A(config, m_floppy_ctrl, 8'000'000, false);
+ I8272A(config, m_floppy_ctrl, 8_MHz_XTAL / 2, false);
m_floppy_ctrl->intrq_wr_callback().set(FUNC(hx5102_device::fdc_irq_w));
m_floppy_ctrl->drq_wr_callback().set(FUNC(hx5102_device::fdc_drq_w));
FLOPPY_CONNECTOR(config, "d0", hx5102_drive, "525dd", hx5102_device::floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "d1", hx5102_drive, nullptr, hx5102_device::floppy_formats).enable_sound(true);
+ // Addressable latches
+ LS259(config, m_crulatch[0]); // U18
+ m_crulatch[0]->q_out_cb<0>().set(FUNC(hx5102_device::nocomp_w));
+ m_crulatch[0]->q_out_cb<1>().set(m_motormf, FUNC(ttl74123_device::b_w));
+ m_crulatch[0]->q_out_cb<3>().set(FUNC(hx5102_device::diren_w));
+ m_crulatch[0]->q_out_cb<4>().set(FUNC(hx5102_device::dacken_w));
+ m_crulatch[0]->q_out_cb<5>().set(FUNC(hx5102_device::stepen_w));
+ m_crulatch[0]->q_out_cb<6>().set(m_speedmf, FUNC(ttl74123_device::b_w));
+ m_crulatch[0]->q_out_cb<7>().set(m_floppy_ctrl, FUNC(i8272a_device::reset_w)).invert();
+
+ LS259(config, m_crulatch[1]); // U10
+ m_crulatch[1]->q_out_cb<0>().set(FUNC(hx5102_device::ds1_w));
+ m_crulatch[1]->q_out_cb<1>().set(FUNC(hx5102_device::ds2_w));
+ m_crulatch[1]->q_out_cb<2>().set(FUNC(hx5102_device::ds3_w));
+ m_crulatch[1]->q_out_cb<3>().set(FUNC(hx5102_device::ds4_w));
+ m_crulatch[1]->q_out_cb<4>().set(FUNC(hx5102_device::aux_motor_w));
+ m_crulatch[1]->q_out_cb<6>().set(FUNC(hx5102_device::wait_w));
+
// Monoflops
- TTL74123(config, m_motormf, 0);
+ TTL74123(config, m_motormf, RES_K(200), CAP_U(47));
m_motormf->set_connection_type(TTL74123_GROUNDED);
- m_motormf->set_resistor_value(RES_K(200));
- m_motormf->set_capacitor_value(CAP_U(47));
m_motormf->set_a_pin_value(0);
m_motormf->set_b_pin_value(1);
m_motormf->set_clear_pin_value(1);
m_motormf->out_cb().set(FUNC(hx5102_device::motor_w));
- TTL74123(config, m_speedmf, 0);
+ TTL74123(config, m_speedmf, RES_K(200), CAP_U(10));
m_speedmf->set_connection_type(TTL74123_GROUNDED);
- m_speedmf->set_resistor_value(RES_K(200));
- m_speedmf->set_capacitor_value(CAP_U(10));
m_speedmf->set_a_pin_value(0);
m_speedmf->set_b_pin_value(1);
m_speedmf->set_clear_pin_value(1);
diff --git a/src/devices/bus/hexbus/hx5102.h b/src/devices/bus/hexbus/hx5102.h
index 12f48dbe555..573c999ce3b 100644
--- a/src/devices/bus/hexbus/hx5102.h
+++ b/src/devices/bus/hexbus/hx5102.h
@@ -22,6 +22,7 @@
#include "machine/upd765.h"
#include "machine/7474.h"
#include "machine/74123.h"
+#include "machine/74259.h"
#include "machine/rescap.h"
#include "machine/ram.h"
#include "imagedev/floppy.h"
@@ -71,7 +72,17 @@ private:
DECLARE_WRITE_LINE_MEMBER(hsklatch_out);
uint8_t cruread(offs_t offset);
- void cruwrite(offs_t offset, uint8_t data);
+ DECLARE_WRITE_LINE_MEMBER(nocomp_w);
+ DECLARE_WRITE_LINE_MEMBER(diren_w);
+ DECLARE_WRITE_LINE_MEMBER(dacken_w);
+ DECLARE_WRITE_LINE_MEMBER(stepen_w);
+ DECLARE_WRITE_LINE_MEMBER(ds1_w);
+ DECLARE_WRITE_LINE_MEMBER(ds2_w);
+ DECLARE_WRITE_LINE_MEMBER(ds3_w);
+ DECLARE_WRITE_LINE_MEMBER(ds4_w);
+ DECLARE_WRITE_LINE_MEMBER(aux_motor_w);
+ DECLARE_WRITE_LINE_MEMBER(wait_w);
+ void update_drive_select();
// Operate the floppy motors
bool m_motor_on;
@@ -96,6 +107,7 @@ private:
required_device<ibc_device> m_hexbus_ctrl;
required_device<i8272a_device> m_floppy_ctrl;
+ required_device_array<ls259_device, 2> m_crulatch;
required_device<ttl74123_device> m_motormf;
required_device<ttl74123_device> m_speedmf;
required_device<ttl7474_device> m_readyff;
diff --git a/src/devices/bus/hp_dio/hp98543.cpp b/src/devices/bus/hp_dio/hp98543.cpp
index bd96c95852d..eb73c56c6f4 100644
--- a/src/devices/bus/hp_dio/hp98543.cpp
+++ b/src/devices/bus/hp_dio/hp98543.cpp
@@ -235,7 +235,7 @@ uint32_t dio16_98543_device::screen_update(screen_device &screen, bitmap_rgb32 &
}
for (int y = 0; y < m_v_pix; y++) {
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < m_h_pix; x++) {
uint8_t tmp = m_vram[y * m_h_pix + x];
diff --git a/src/devices/bus/hp_dio/hp98544.cpp b/src/devices/bus/hp_dio/hp98544.cpp
index 842a7a78229..e5aced877d8 100644
--- a/src/devices/bus/hp_dio/hp98544.cpp
+++ b/src/devices/bus/hp_dio/hp98544.cpp
@@ -165,26 +165,20 @@ WRITE_LINE_MEMBER(dio16_98544_device::int_w)
uint32_t dio16_98544_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int startx, starty, endx, endy;
-
-
if (!m_topcat->has_changed())
return UPDATE_HAS_NOT_CHANGED;
for (int y = 0; y < m_v_pix; y++) {
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < m_h_pix; x++) {
uint8_t tmp = m_vram[y * m_h_pix + x];
*scanline++ = tmp ? rgb_t(255,255,255) : rgb_t(0, 0, 0);
}
}
+ int startx, starty, endx, endy;
m_topcat->get_cursor_pos(startx, starty, endx, endy);
-
- for (int y = starty; y <= endy; y++) {
- uint32_t *scanline = &bitmap.pix32(y);
- memset(scanline + startx, 0xff, (endx - startx) << 2);
- }
+ bitmap.fill(rgb_t(255, 255, 255), rectangle(startx, endx, starty, endy));
return 0;
}
diff --git a/src/devices/bus/hp_dio/hp98550.cpp b/src/devices/bus/hp_dio/hp98550.cpp
index 738926eae77..38f70d2d670 100644
--- a/src/devices/bus/hp_dio/hp98550.cpp
+++ b/src/devices/bus/hp_dio/hp98550.cpp
@@ -218,7 +218,7 @@ uint32_t dio32_98550_device::screen_update(screen_device &screen, bitmap_rgb32 &
mask |= ce->plane_enabled();
for (int y = 0; y < m_v_pix; y++) {
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < m_h_pix; x++) {
const int offset = y * m_fb_width +x;
diff --git a/src/devices/bus/ieee488/ieee488.cpp b/src/devices/bus/ieee488/ieee488.cpp
index bcbe20e0573..947aad2d1f7 100644
--- a/src/devices/bus/ieee488/ieee488.cpp
+++ b/src/devices/bus/ieee488/ieee488.cpp
@@ -164,7 +164,7 @@ void ieee488_device::device_stop()
void ieee488_device::add_device(ieee488_slot_device *slot, device_t *target)
{
- auto entry = global_alloc(daisy_entry(target));
+ auto entry = new daisy_entry(target);
entry->m_interface->m_bus = this;
entry->m_interface->m_slot = slot;
diff --git a/src/devices/bus/iq151/grafik.cpp b/src/devices/bus/iq151/grafik.cpp
index 304bcf87b43..497012cf2cd 100644
--- a/src/devices/bus/iq151/grafik.cpp
+++ b/src/devices/bus/iq151/grafik.cpp
@@ -178,7 +178,7 @@ void iq151_grafik_device::video_update(bitmap_ind16 &bitmap, const rectangle &cl
{
for (int ra = 0; ra < 8; ra++)
{
- bitmap.pix16(y, x*8 + ra) |= BIT(m_videoram[(32*8 -1 - y)*64 + x], ra);
+ bitmap.pix(y, x*8 + ra) |= BIT(m_videoram[(32*8 -1 - y)*64 + x], ra);
}
}
}
diff --git a/src/devices/bus/iq151/minigraf.cpp b/src/devices/bus/iq151/minigraf.cpp
index d5bf2da1f8b..e0962048411 100644
--- a/src/devices/bus/iq151/minigraf.cpp
+++ b/src/devices/bus/iq151/minigraf.cpp
@@ -162,7 +162,7 @@ void iq151_minigraf_device::plotter_update(uint8_t control)
// if pen is down draws a point
if (m_pen)
- m_paper->pix16(((PAPER_HEIGHT-PAPER_MAX_Y)/2) + m_posy, ((PAPER_WIDTH-PAPER_MAX_X)/2) + m_posx) = 1;
+ m_paper->pix(((PAPER_HEIGHT-PAPER_MAX_Y)/2) + m_posy, ((PAPER_WIDTH-PAPER_MAX_X)/2) + m_posx) = 1;
m_control = control;
}
diff --git a/src/devices/bus/iq151/ms151a.cpp b/src/devices/bus/iq151/ms151a.cpp
index 447c9f0d43a..651e82bfe6f 100644
--- a/src/devices/bus/iq151/ms151a.cpp
+++ b/src/devices/bus/iq151/ms151a.cpp
@@ -164,5 +164,5 @@ void iq151_ms151a_device::plotter_update(uint8_t offset, uint8_t data)
// if pen is down draws a point
if (m_pen)
- m_paper->pix16(((PAPER_HEIGHT-PAPER_MAX_Y)/2) + m_posy, ((PAPER_WIDTH-PAPER_MAX_X)/2) + m_posx) = 1;
+ m_paper->pix(((PAPER_HEIGHT-PAPER_MAX_Y)/2) + m_posy, ((PAPER_WIDTH-PAPER_MAX_X)/2) + m_posx) = 1;
}
diff --git a/src/devices/bus/iq151/video32.cpp b/src/devices/bus/iq151/video32.cpp
index fce21b963e9..2d3f75b66ed 100644
--- a/src/devices/bus/iq151/video32.cpp
+++ b/src/devices/bus/iq151/video32.cpp
@@ -126,7 +126,7 @@ void iq151_video32_device::video_update(bitmap_ind16 &bitmap, const rectangle &c
{
for (int ra = 0; ra < 8; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
for (int x = ma; x < ma + 32; x++)
{
diff --git a/src/devices/bus/iq151/video64.cpp b/src/devices/bus/iq151/video64.cpp
index a965abbd19e..487bf63ca33 100644
--- a/src/devices/bus/iq151/video64.cpp
+++ b/src/devices/bus/iq151/video64.cpp
@@ -140,7 +140,7 @@ void iq151_video64_device::video_update(bitmap_ind16 &bitmap, const rectangle &c
{
for (int ra = 0; ra < 8; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
for (int x = ma; x < ma + 64; x++)
{
diff --git a/src/devices/bus/isa/aga.cpp b/src/devices/bus/isa/aga.cpp
index 244fbc0bb66..81e6ba053fe 100644
--- a/src/devices/bus/isa/aga.cpp
+++ b/src/devices/bus/isa/aga.cpp
@@ -288,7 +288,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::mda_text_inten_update_row )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const videoram = m_videoram.get();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
uint16_t const chr_base = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra;
if (y == 0) logerror("mda_text_inten_update_row\n");
@@ -345,7 +345,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::mda_text_blink_update_row )
{
uint8_t const *const videoram = m_videoram.get();
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
uint16_t const chr_base = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra;
if (y == 0) logerror("mda_text_blink_update_row\n");
@@ -402,7 +402,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_text_inten_update_row )
{
uint8_t const *const videoram = m_videoram.get();
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
if (y == 0) logerror("cga_text_inten_update_row\n");
for (int i = 0; i < x_count; i++) {
@@ -431,7 +431,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_text_inten_alt_update_row )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const videoram = m_videoram.get();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
if (y == 0) logerror("cga_text_inten_alt_update_row\n");
for (int i = 0; i < x_count; i++) {
@@ -459,7 +459,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_text_blink_update_row )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const videoram = m_videoram.get();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
for (int i = 0; i < x_count; i++) {
uint16_t const offset = ((ma + i) << 1) & 0x3fff;
@@ -491,7 +491,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_text_blink_alt_update_row )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const videoram = m_videoram.get();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
if (y == 0) logerror("cga_text_blink_alt_update_row\n");
for (int i = 0; i < x_count; i++) {
@@ -526,7 +526,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_4bppl_update_row )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const videoram = m_videoram.get();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
if (y == 0) logerror("cga_gfx_4bppl_update_row\n");
for (int i = 0; i < x_count; i++) {
@@ -551,7 +551,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_4bpph_update_row )
{
uint8_t const *const videoram = m_videoram.get();
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
if (y == 0) logerror("cga_gfx_4bpph_update_row\n");
for (int i = 0; i < x_count; i++) {
@@ -584,7 +584,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_2bpp_update_row )
{
uint8_t const *const videoram = m_videoram.get();
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
//if (y == 0) logerror("cga_gfx_2bpp_update_row\n");
for (int i = 0; i < x_count; i++) {
@@ -609,7 +609,7 @@ MC6845_UPDATE_ROW( isa8_aga_device::cga_gfx_1bpp_update_row )
{
uint8_t const *const videoram = m_videoram.get();
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
uint8_t const fg = m_cga_color_select & 0x0f;
if (y == 0) logerror("cga_gfx_1bpp_update_row\n");
diff --git a/src/devices/bus/isa/cga.cpp b/src/devices/bus/isa/cga.cpp
index ff30f3690ad..52a0407f065 100644
--- a/src/devices/bus/isa/cga.cpp
+++ b/src/devices/bus/isa/cga.cpp
@@ -469,47 +469,43 @@ isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &m
template<bool blink, bool si, bool comp, bool alt, int width>
MC6845_UPDATE_ROW( isa8_cga_device::cga_text )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int i;
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- if ( y == 0 ) CGA_LOG(1,"cga_text_8",("\n"));
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) CGA_LOG(1,"cga_text_8",("\n"));
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ma + i ) << 1 ) & 0x3fff;
- uint8_t chr = videoram[ offset ];
- uint8_t attr = videoram[ offset +1 ];
- uint8_t data = m_chr_gen[ chr * width + ra ];
+ uint16_t const offset = ((ma + i) << 1) & 0x3fff;
+ uint8_t const chr = videoram[offset];
+ uint8_t const attr = videoram[offset +1];
+ uint8_t data = m_chr_gen[chr * width + ra];
uint16_t fg, bg;
- uint8_t xi;
- if ( comp )
+ if (comp)
{
- fg = 0x10 + ( attr & 0x0F );
- bg = alt ? 0 : ( 0x10 + ( ( attr >> 4 ) & 0x07 ) );
+ fg = 0x10 + (attr & 0x0f);
+ bg = alt ? 0 : (0x10 + ((attr >> 4) & 0x07));
}
else
{
fg = attr & 0x0F;
- bg = alt ? 0 : ( ( attr >> 4 ) & ( blink ? 0x07 : 0x0f ) );
+ bg = alt ? 0 : ((attr >> 4) & (blink ? 0x07 : 0x0f));
}
- if ( ( i == cursor_x ) && ( m_framecnt & 0x08 ) )
- data = 0xFF;
- else if ( blink && ( attr & 0x80 ) && ( m_framecnt & 0x10 ) )
+ if ((i == cursor_x) && (m_framecnt & 0x08))
+ data = 0xff;
+ else if (blink && (attr & 0x80) && (m_framecnt & 0x10))
{
data = 0x00;
- bg = ( attr >> 4 ) & 0x07;
+ bg = (attr >> 4) & 0x07;
}
- for(xi=0;xi<8;xi++)
+ for (int xi = 0; xi < 8; xi++)
{
- uint8_t pen_data, dot;
-
- dot = (data & (1 << (7-xi)));
- pen_data = dot ? fg : bg;
- if(!si || (pen_data || dot))
+ uint8_t const dot = (data & (1 << (7 - xi)));
+ uint8_t const pen_data = dot ? fg : bg;
+ if (!si || (pen_data || dot))
*p = palette[pen_data];
p++;
}
@@ -521,28 +517,29 @@ MC6845_UPDATE_ROW( isa8_cga_device::cga_text )
MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bppl_update_row )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int i;
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bppl_update_row",("\n"));
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) CGA_LOG(1,"cga_gfx_4bppl_update_row",("\n"));
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
- uint8_t data = videoram[ offset ];
+ uint16_t const offset = (((ma + i) << 1) & 0x1fff) | ((y & 1) << 13);
+ uint8_t data;
+
+ data = videoram[offset];
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
- data = videoram[ offset + 1 ];
+ data = videoram[offset + 1];
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
}
}
@@ -580,37 +577,37 @@ static const uint8_t yc_lut[16][8] =
MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bpph_update_row )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int i;
-
- if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bpph_update_row",("\n"));
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) CGA_LOG(1,"cga_gfx_4bpph_update_row",("\n"));
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
- uint8_t data = videoram[ offset ];
-
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
-
- data = videoram[ offset + 1 ];
-
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data >> 4]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
- *p = palette[data & 0x0F]; p++;
+ uint16_t const offset = (((ma + i) << 1) & 0x1fff) | ((y & 1) << 13);
+ uint8_t data;
+
+ data = videoram[offset];
+
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
+
+ data = videoram[offset + 1];
+
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data >> 4];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
+ *p++ = palette[data & 0x0f];
}
}
@@ -623,28 +620,29 @@ MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_4bpph_update_row )
MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_2bpp_update_row )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int i;
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- if ( y == 0 ) CGA_LOG(1,"cga_gfx_2bpp_update_row",("\n"));
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) CGA_LOG(1,"cga_gfx_2bpp_update_row",("\n"));
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 );
- uint8_t data = videoram[ offset ];
+ uint16_t const offset = (((ma + i) << 1) & 0x1fff) | ((ra & 1) << 13);
+ uint8_t data;
+
+ data = videoram[offset];
- *p = palette[m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
- *p = palette[m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
- *p = palette[m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
- *p = palette[m_palette_lut_2bpp[ data & 0x03 ]]; p++;
+ *p++ = palette[m_palette_lut_2bpp[(data >> 6) & 0x03]];
+ *p++ = palette[m_palette_lut_2bpp[(data >> 4) & 0x03]];
+ *p++ = palette[m_palette_lut_2bpp[(data >> 2) & 0x03]];
+ *p++ = palette[m_palette_lut_2bpp[ data & 0x03]];
- data = videoram[ offset+1 ];
+ data = videoram[offset + 1];
- *p = palette[m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
- *p = palette[m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
- *p = palette[m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
- *p = palette[m_palette_lut_2bpp[ data & 0x03 ]]; p++;
+ *p++ = palette[m_palette_lut_2bpp[(data >> 6) & 0x03]];
+ *p++ = palette[m_palette_lut_2bpp[(data >> 4) & 0x03]];
+ *p++ = palette[m_palette_lut_2bpp[(data >> 2) & 0x03]];
+ *p++ = palette[m_palette_lut_2bpp[ data & 0x03]];
}
}
@@ -658,37 +656,38 @@ MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_2bpp_update_row )
MC6845_UPDATE_ROW( isa8_cga_device::cga_gfx_1bpp_update_row )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint8_t fg = m_color_select & 0x0F;
- int i;
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint8_t const fg = m_color_select & 0x0f;
- if ( y == 0 ) CGA_LOG(1,"cga_gfx_1bpp_update_row",("\n"));
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) CGA_LOG(1,"cga_gfx_1bpp_update_row",("\n"));
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 );
- uint8_t data = videoram[ offset ];
-
- *p = palette[( data & 0x80 ) ? fg : 0]; p++;
- *p = palette[( data & 0x40 ) ? fg : 0]; p++;
- *p = palette[( data & 0x20 ) ? fg : 0]; p++;
- *p = palette[( data & 0x10 ) ? fg : 0]; p++;
- *p = palette[( data & 0x08 ) ? fg : 0]; p++;
- *p = palette[( data & 0x04 ) ? fg : 0]; p++;
- *p = palette[( data & 0x02 ) ? fg : 0]; p++;
- *p = palette[( data & 0x01 ) ? fg : 0]; p++;
-
- data = videoram[ offset + 1 ];
-
- *p = palette[( data & 0x80 ) ? fg : 0]; p++;
- *p = palette[( data & 0x40 ) ? fg : 0]; p++;
- *p = palette[( data & 0x20 ) ? fg : 0]; p++;
- *p = palette[( data & 0x10 ) ? fg : 0]; p++;
- *p = palette[( data & 0x08 ) ? fg : 0]; p++;
- *p = palette[( data & 0x04 ) ? fg : 0]; p++;
- *p = palette[( data & 0x02 ) ? fg : 0]; p++;
- *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ uint16_t const offset = (((ma + i) << 1) & 0x1fff) | ((ra & 1) << 13);
+ uint8_t data;
+
+ data = videoram[offset];
+
+ *p++ = palette[(data & 0x80) ? fg : 0];
+ *p++ = palette[(data & 0x40) ? fg : 0];
+ *p++ = palette[(data & 0x20) ? fg : 0];
+ *p++ = palette[(data & 0x10) ? fg : 0];
+ *p++ = palette[(data & 0x08) ? fg : 0];
+ *p++ = palette[(data & 0x04) ? fg : 0];
+ *p++ = palette[(data & 0x02) ? fg : 0];
+ *p++ = palette[(data & 0x01) ? fg : 0];
+
+ data = videoram[offset + 1];
+
+ *p++ = palette[(data & 0x80) ? fg : 0];
+ *p++ = palette[(data & 0x40) ? fg : 0];
+ *p++ = palette[(data & 0x20) ? fg : 0];
+ *p++ = palette[(data & 0x10) ? fg : 0];
+ *p++ = palette[(data & 0x08) ? fg : 0];
+ *p++ = palette[(data & 0x04) ? fg : 0];
+ *p++ = palette[(data & 0x02) ? fg : 0];
+ *p++ = palette[(data & 0x01) ? fg : 0];
}
}
@@ -961,205 +960,200 @@ void isa8_cga_device::io_write(offs_t offset, uint8_t data)
// proc = cga_pgfx_4bpp;
//
-//static inline void pgfx_plot_unit_4bpp(bitmap_ind16 &bitmap,
-// int x, int y, int offs)
-//{
-// int color, values[2];
-// int i;
-//
-// if (cga.plantronics & 0x40)
-// {
-// values[0] = videoram[offs | 0x4000];
-// values[1] = videoram[offs];
-// }
-// else
-// {
-// values[0] = videoram[offs];
-// values[1] = videoram[offs | 0x4000];
-// }
-// for (i=3; i>=0; i--)
-// {
-// color = ((values[0] & 0x3) << 1) |
-// ((values[1] & 2) >> 1) |
-// ((values[1] & 1) << 3);
-// bitmap.pix16(y, x+i) = Machine->pens[color];
-// values[0]>>=2;
-// values[1]>>=2;
-// }
-//}
-//
-//
-//
+#if 0
+static inline void pgfx_plot_unit_4bpp(bitmap_ind16 &bitmap, int x, int y, int offs)
+{
+ int values[2];
+
+ if (cga.plantronics & 0x40)
+ {
+ values[0] = videoram[offs | 0x4000];
+ values[1] = videoram[offs];
+ }
+ else
+ {
+ values[0] = videoram[offs];
+ values[1] = videoram[offs | 0x4000];
+ }
+ for (int i = 3; i >= 0; i--)
+ {
+ int const color =
+ ((values[0] & 0x3) << 1) |
+ ((values[1] & 2) >> 1) |
+ ((values[1] & 1) << 3);
+ bitmap.pix(y, x + i) = Machine->pens[color];
+ values[0] >>= 2;
+ values[1] >>= 2;
+ }
+}
+#endif
+
+
///***************************************************************************
// Draw graphics mode with 640x200 pixels (default) with 2 bits/pixel.
// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
// Second plane at CGA_base + 0x4000 / 0x6000
-//***************************************************************************/
-//
-//static void cga_pgfx_4bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
-//{
-// int i, sx, sy, sh;
-// int offs = mscrtc6845_get_start(crtc)*2;
-// int lines = mscrtc6845_get_char_lines(crtc);
-// int height = mscrtc6845_get_char_height(crtc);
-// int columns = mscrtc6845_get_char_columns(crtc)*2;
-//
-// for (sy=0; sy<lines; sy++,offs=(offs+columns)&0x1fff)
-// {
-// for (sh=0; sh<height; sh++, offs|=0x2000)
-// {
-// // char line 0 used as a12 line in graphic mode
-// if (!(sh & 1))
-// {
-// for (i=offs, sx=0; sx<columns; sx++, i=(i+1)&0x1fff)
-// {
-// pgfx_plot_unit_4bpp(bitmap, sx*4, sy*height+sh, i);
-// }
-// }
-// else
-// {
-// for (i=offs|0x2000, sx=0; sx<columns; sx++, i=((i+1)&0x1fff)|0x2000)
-// {
-// pgfx_plot_unit_4bpp(bitmap, sx*4, sy*height+sh, i);
-// }
-// }
-// }
-// }
-//}
-//
-//
-//
-//static inline void pgfx_plot_unit_2bpp(bitmap_ind16 &bitmap,
-// int x, int y, const uint16_t *palette, int offs)
-//{
-// int i;
-// uint8_t bmap[2], values[2];
-// uint16_t *dest;
-//
-// if (cga.plantronics & 0x40)
-// {
-// values[0] = videoram[offs];
-// values[1] = videoram[offs | 0x4000];
-// }
-// else
-// {
-// values[0] = videoram[offs | 0x4000];
-// values[1] = videoram[offs];
-// }
-// bmap[0] = bmap[1] = 0;
-// for (i=3; i>=0; i--)
-// {
-// bmap[0] = bmap[0] << 1; if (values[0] & 0x80) bmap[0] |= 1;
-// bmap[0] = bmap[0] << 1; if (values[1] & 0x80) bmap[0] |= 1;
-// bmap[1] = bmap[1] << 1; if (values[0] & 0x08) bmap[1] |= 1;
-// bmap[1] = bmap[1] << 1; if (values[1] & 0x08) bmap[1] |= 1;
-// values[0] = values[0] << 1;
-// values[1] = values[1] << 1;
-// }
-//
-// dest = &bitmap.pix16(y, x);
-// *(dest++) = palette[(bmap[0] >> 6) & 0x03];
-// *(dest++) = palette[(bmap[0] >> 4) & 0x03];
-// *(dest++) = palette[(bmap[0] >> 2) & 0x03];
-// *(dest++) = palette[(bmap[0] >> 0) & 0x03];
-// *(dest++) = palette[(bmap[1] >> 6) & 0x03];
-// *(dest++) = palette[(bmap[1] >> 4) & 0x03];
-// *(dest++) = palette[(bmap[1] >> 2) & 0x03];
-// *(dest++) = palette[(bmap[1] >> 0) & 0x03];
-//}
-//
-//
-//
+//****************************************************************************
+
+#if 0
+static void cga_pgfx_4bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
+{
+ int offs = mscrtc6845_get_start(crtc) * 2;
+ int const lines = mscrtc6845_get_char_lines(crtc);
+ int const height = mscrtc6845_get_char_height(crtc);
+ int columns = mscrtc6845_get_char_columns(crtc) * 2;
+
+ for (int sy = 0; sy < lines; sy++, offs = (offs + columns) & 0x1fff)
+ {
+ for (int sh = 0; sh < height; sh++, offs |= 0x2000)
+ {
+ // char line 0 used as a12 line in graphic mode
+ if (!(sh & 1))
+ {
+ for (int i = offs, sx = 0; sx < columns; sx++, i = (i + 1) & 0x1fff)
+ {
+ pgfx_plot_unit_4bpp(bitmap, sx * 4, sy * height + sh, i);
+ }
+ }
+ else
+ {
+ for (int i = offs | 0x2000, sx = 0; sx < columns; sx++, i = ((i + 1) & 0x1fff) | 0x2000)
+ {
+ pgfx_plot_unit_4bpp(bitmap, sx * 4, sy * height + sh, i);
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+#if 0
+static inline void pgfx_plot_unit_2bpp(bitmap_ind16 &bitmap, int x, int y, const uint16_t *palette, int offs)
+{
+ uint8_t values[2];
+ if (cga.plantronics & 0x40)
+ {
+ values[0] = videoram[offs];
+ values[1] = videoram[offs | 0x4000];
+ }
+ else
+ {
+ values[0] = videoram[offs | 0x4000];
+ values[1] = videoram[offs];
+ }
+ uint8_t bmap[2] = { 0, 0 };
+ for (int i = 3; i >= 0; i--)
+ {
+ bmap[0] = (bmap[0] << 1) | BIT(values[0], 7);
+ bmap[0] = (bmap[0] << 1) | BIT(values[1], 7);
+ bmap[1] = (bmap[1] << 1) | BIT(values[0], 3);
+ bmap[1] = (bmap[1] << 1) | BIT(values[1], 3);
+ values[0] <<= 1;
+ values[1] <<= 1;
+ }
+
+ uint16_t *dest = &bitmap.pix(y, x);
+ *dest++ = palette[(bmap[0] >> 6) & 0x03];
+ *dest++ = palette[(bmap[0] >> 4) & 0x03];
+ *dest++ = palette[(bmap[0] >> 2) & 0x03];
+ *dest++ = palette[(bmap[0] >> 0) & 0x03];
+ *dest++ = palette[(bmap[1] >> 6) & 0x03];
+ *dest++ = palette[(bmap[1] >> 4) & 0x03];
+ *dest++ = palette[(bmap[1] >> 2) & 0x03];
+ *dest++ = palette[(bmap[1] >> 0) & 0x03];
+}
+#endif
+
+
///***************************************************************************
// Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel.
// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
// cga fetches 2 byte per mscrtc6845 access (not modeled here)!
-//***************************************************************************/
-//
-//static void cga_pgfx_2bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
-//{
-// int i, sx, sy, sh;
-// int offs = mscrtc6845_get_start(crtc)*2;
-// int lines = mscrtc6845_get_char_lines(crtc);
-// int height = mscrtc6845_get_char_height(crtc);
-// int columns = mscrtc6845_get_char_columns(crtc)*2;
-// int colorset = cga.color_select & 0x3F;
-// const uint16_t *palette;
-//
-// /* Most chipsets use bit 2 of the mode control register to
-// * access a third palette. But not consistently. */
-// pc_cga_check_palette();
-// switch(CGA_CHIPSET)
-// {
-// /* The IBM Professional Graphics Controller behaves like
-// * the PC1512, btw. */
-// case CGA_CHIPSET_PC1512:
-// if ((colorset < 32) && (cga.mode_control & 4)) colorset += 64;
-// break;
-//
-// case CGA_CHIPSET_IBM:
-// case CGA_CHIPSET_PC200:
-// case CGA_CHIPSET_ATI:
-// case CGA_CHIPSET_PARADISE:
-// if (cga.mode_control & 4) colorset = (colorset & 0x1F) + 64;
-// break;
-// }
-//
-//
-// /* The fact that our palette is located in cga_colortable is a vestigial
-// * aspect from when we were doing that ugly trick where drawgfx() would
-// * handle graphics drawing. Truthfully, we should probably be using
-// * palette_set_color_rgb() here and not doing the palette lookup in the loop
-// */
-// palette = &cga_colortable[256*2 + 16*2] + colorset * 4;
-//
-// for (sy=0; sy<lines; sy++,offs=(offs+columns)&0x1fff) {
-//
-// for (sh=0; sh<height; sh++)
-// {
-// if (!(sh&1)) { // char line 0 used as a12 line in graphic mode
-// for (i=offs, sx=0; sx<columns; sx++, i=(i+1)&0x1fff)
-// {
-// pgfx_plot_unit_2bpp(bitmap, sx*8, sy*height+sh, palette, i);
-// }
-// }
-// else
-// {
-// for (i=offs|0x2000, sx=0; sx<columns; sx++, i=((i+1)&0x1fff)|0x2000)
-// {
-// pgfx_plot_unit_2bpp(bitmap, sx*8, sy*height+sh, palette, i);
-// }
-// }
-// }
-// }
-//}
+//****************************************************************************
+
+#if 0
+static void cga_pgfx_2bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
+{
+ int offs = mscrtc6845_get_start(crtc) * 2;
+ int const lines = mscrtc6845_get_char_lines(crtc);
+ int const height = mscrtc6845_get_char_height(crtc);
+ int const columns = mscrtc6845_get_char_columns(crtc) * 2;
+
+ /* Most chipsets use bit 2 of the mode control register to access a third palette. But not consistently. */
+ int colorset = cga.color_select & 0x3f;
+ pc_cga_check_palette();
+ switch (CGA_CHIPSET)
+ {
+ /* The IBM Professional Graphics Controller behaves like the PC1512, btw. */
+ case CGA_CHIPSET_PC1512:
+ if ((colorset < 32) && (cga.mode_control & 4)) colorset += 64;
+ break;
+
+ case CGA_CHIPSET_IBM:
+ case CGA_CHIPSET_PC200:
+ case CGA_CHIPSET_ATI:
+ case CGA_CHIPSET_PARADISE:
+ if (cga.mode_control & 4) colorset = (colorset & 0x1f) + 64;
+ break;
+ }
+
+ /* The fact that our palette is located in cga_colortable is a vestigial
+ * aspect from when we were doing that ugly trick where drawgfx() would
+ * handle graphics drawing. Truthfully, we should probably be using
+ * palette_set_color_rgb() here and not doing the palette lookup in the loop
+ */
+ uint16_t const *const palette = &cga_colortable[256*2 + 16*2] + colorset * 4;
+
+ for (int sy = 0; sy < lines; sy++, offs = (offs + columns) & 0x1fff)
+ {
+
+ for (int sh = 0; sh < height; sh++)
+ {
+ if (!(sh & 1)) // char line 0 used as a12 line in graphic mode
+ {
+ for (int i = offs, sx = 0; sx < columns; sx++, i = (i + 1) & 0x1fff)
+ {
+ pgfx_plot_unit_2bpp(bitmap, sx * 8, sy * height + sh, palette, i);
+ }
+ }
+ else
+ {
+ for (int i = offs | 0x2000, sx = 0; sx < columns; sx++, i= ((i + 1) & 0x1fff) | 0x2000)
+ {
+ pgfx_plot_unit_2bpp(bitmap, sx * 8, sy * height + sh, palette, i);
+ }
+ }
+ }
+ }
+}
+#endif
MC6845_UPDATE_ROW( isa8_cga_pc1512_device::pc1512_gfx_4bpp_update_row )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint16_t offset_base = ra << 13;
- int j;
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint16_t const offset_base = ra << 13;
- if ( y == 0 ) CGA_LOG(1,"pc1512_gfx_4bpp_update_row",("\n"));
- for ( j = 0; j < x_count; j++ )
+ if (y == 0) CGA_LOG(1,"pc1512_gfx_4bpp_update_row",("\n"));
+ for (int j = 0; j < x_count; j++)
{
- uint16_t offset = offset_base | ( ( ma + j ) & 0x1FFF );
- uint16_t i = ( m_color_select & 8 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[3] | offset ] << 3 : 0;
- uint16_t r = ( m_color_select & 4 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[2] | offset ] << 2 : 0;
- uint16_t g = ( m_color_select & 2 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[1] | offset ] << 1 : 0;
- uint16_t b = ( m_color_select & 1 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[0] | offset ] : 0;
-
- *p = palette[( ( i & 0x400 ) | ( r & 0x200 ) | ( g & 0x100 ) | ( b & 0x80 ) ) >> 7]; p++;
- *p = palette[( ( i & 0x200 ) | ( r & 0x100 ) | ( g & 0x080 ) | ( b & 0x40 ) ) >> 6]; p++;
- *p = palette[( ( i & 0x100 ) | ( r & 0x080 ) | ( g & 0x040 ) | ( b & 0x20 ) ) >> 5]; p++;
- *p = palette[( ( i & 0x080 ) | ( r & 0x040 ) | ( g & 0x020 ) | ( b & 0x10 ) ) >> 4]; p++;
- *p = palette[( ( i & 0x040 ) | ( r & 0x020 ) | ( g & 0x010 ) | ( b & 0x08 ) ) >> 3]; p++;
- *p = palette[( ( i & 0x020 ) | ( r & 0x010 ) | ( g & 0x008 ) | ( b & 0x04 ) ) >> 2]; p++;
- *p = palette[( ( i & 0x010 ) | ( r & 0x008 ) | ( g & 0x004 ) | ( b & 0x02 ) ) >> 1]; p++;
- *p = palette[ ( i & 0x008 ) | ( r & 0x004 ) | ( g & 0x002 ) | ( b & 0x01 ) ]; p++;
+ uint16_t const offset = offset_base | ((ma + j) & 0x1fff);
+ uint16_t const i = (m_color_select & 8) ? videoram[isa8_cga_pc1512_device::vram_offset[3] | offset] << 3 : 0;
+ uint16_t const r = (m_color_select & 4) ? videoram[isa8_cga_pc1512_device::vram_offset[2] | offset] << 2 : 0;
+ uint16_t const g = (m_color_select & 2) ? videoram[isa8_cga_pc1512_device::vram_offset[1] | offset] << 1 : 0;
+ uint16_t const b = (m_color_select & 1) ? videoram[isa8_cga_pc1512_device::vram_offset[0] | offset] : 0;
+
+ *p++ = palette[((i & 0x400) | (r & 0x200) | (g & 0x100) | (b & 0x80) ) >> 7];
+ *p++ = palette[((i & 0x200) | (r & 0x100) | (g & 0x080) | (b & 0x40) ) >> 6];
+ *p++ = palette[((i & 0x100) | (r & 0x080) | (g & 0x040) | (b & 0x20) ) >> 5];
+ *p++ = palette[((i & 0x080) | (r & 0x040) | (g & 0x020) | (b & 0x10) ) >> 4];
+ *p++ = palette[((i & 0x040) | (r & 0x020) | (g & 0x010) | (b & 0x08) ) >> 3];
+ *p++ = palette[((i & 0x020) | (r & 0x010) | (g & 0x008) | (b & 0x04) ) >> 2];
+ *p++ = palette[((i & 0x010) | (r & 0x008) | (g & 0x004) | (b & 0x02) ) >> 1];
+ *p++ = palette[ (i & 0x008) | (r & 0x004) | (g & 0x002) | (b & 0x01) ];
}
}
@@ -1500,31 +1494,38 @@ void isa8_wyse700_device::device_reset()
uint32_t isa8_wyse700_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- if (m_control & 0x08) {
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint8_t fg = m_color_select & 0x0F;
+ if (m_control & 0x08)
+ {
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint8_t const fg = m_color_select & 0x0F;
uint32_t addr = 0;
- for (int y = 0; y < 800; y++) {
- uint8_t *src = &m_vram[addr];
+ for (int y = 0; y < 800; y++)
+ {
+ uint8_t const *src = &m_vram[addr];
- if (y & 1) {
+ if (y & 1)
+ {
src += 0x10000;
addr += 160;
}
- for (int x = 0; x < (1280 / 8); x++) {
+ for (int x = 0; x < (1280 / 8); x++)
+ {
uint8_t val = src[x];
- for (int i = 0; i < 8; i++) {
- bitmap.pix32(y,x*8+i) = (val & 0x80) ? palette[fg] : palette[0x00];
+ for (int i = 0; i < 8; i++)
+ {
+ bitmap.pix(y, x * 8 + i) = (val & 0x80) ? palette[fg] : palette[0x00];
val <<= 1;
}
}
}
- } else {
+ return 0;
+ }
+ else
+ {
return isa8_cga_device::screen_update(screen, bitmap, cliprect);
}
- return 0;
}
@@ -1837,7 +1838,7 @@ uint8_t isa8_cga_m24_device::io_read(offs_t offset)
MC6845_UPDATE_ROW(isa8_cga_m24_device::crtc_update_row)
{
- if(m_mode2 & 1)
+ if (m_mode2 & 1)
{
m24_gfx_1bpp_m24_update_row(bitmap, cliprect, ma, ra, y, x_count, cursor_x, de, hbp, vbp);
return;
@@ -1847,7 +1848,7 @@ MC6845_UPDATE_ROW(isa8_cga_m24_device::crtc_update_row)
return;
y = m_y;
- if(m_y >= bitmap.height())
+ if (m_y >= bitmap.height())
return;
switch (m_update_row_type)
@@ -1885,37 +1886,38 @@ MC6845_UPDATE_ROW(isa8_cga_m24_device::crtc_update_row)
MC6845_UPDATE_ROW( isa8_cga_m24_device::m24_gfx_1bpp_m24_update_row )
{
- uint8_t *videoram = &m_vram[m_start_offset];
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint8_t fg = m_color_select & 0x0F;
- int i;
+ uint8_t const *const videoram = &m_vram[m_start_offset];
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint8_t const fg = m_color_select & 0x0f;
- if ( y == 0 ) CGA_LOG(1,"m24_gfx_1bpp_m24_update_row",("\n"));
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) CGA_LOG(1,"m24_gfx_1bpp_m24_update_row",("\n"));
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 3 ) << 13 );
- uint8_t data = videoram[ offset ];
-
- *p = palette[( data & 0x80 ) ? fg : 0]; p++;
- *p = palette[( data & 0x40 ) ? fg : 0]; p++;
- *p = palette[( data & 0x20 ) ? fg : 0]; p++;
- *p = palette[( data & 0x10 ) ? fg : 0]; p++;
- *p = palette[( data & 0x08 ) ? fg : 0]; p++;
- *p = palette[( data & 0x04 ) ? fg : 0]; p++;
- *p = palette[( data & 0x02 ) ? fg : 0]; p++;
- *p = palette[( data & 0x01 ) ? fg : 0]; p++;
-
- data = videoram[ offset + 1 ];
-
- *p = palette[( data & 0x80 ) ? fg : 0]; p++;
- *p = palette[( data & 0x40 ) ? fg : 0]; p++;
- *p = palette[( data & 0x20 ) ? fg : 0]; p++;
- *p = palette[( data & 0x10 ) ? fg : 0]; p++;
- *p = palette[( data & 0x08 ) ? fg : 0]; p++;
- *p = palette[( data & 0x04 ) ? fg : 0]; p++;
- *p = palette[( data & 0x02 ) ? fg : 0]; p++;
- *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ uint16_t const offset = (((ma + i) << 1 ) & 0x1fff) | ((ra & 3) << 13);
+ uint8_t data;
+
+ data = videoram[offset];
+
+ *p++ = palette[(data & 0x80) ? fg : 0];
+ *p++ = palette[(data & 0x40) ? fg : 0];
+ *p++ = palette[(data & 0x20) ? fg : 0];
+ *p++ = palette[(data & 0x10) ? fg : 0];
+ *p++ = palette[(data & 0x08) ? fg : 0];
+ *p++ = palette[(data & 0x04) ? fg : 0];
+ *p++ = palette[(data & 0x02) ? fg : 0];
+ *p++ = palette[(data & 0x01) ? fg : 0];
+
+ data = videoram[offset + 1];
+
+ *p++ = palette[(data & 0x80) ? fg : 0];
+ *p++ = palette[(data & 0x40) ? fg : 0];
+ *p++ = palette[(data & 0x20) ? fg : 0];
+ *p++ = palette[(data & 0x10) ? fg : 0];
+ *p++ = palette[(data & 0x08) ? fg : 0];
+ *p++ = palette[(data & 0x04) ? fg : 0];
+ *p++ = palette[(data & 0x02) ? fg : 0];
+ *p++ = palette[(data & 0x01) ? fg : 0];
}
}
diff --git a/src/devices/bus/isa/ega.cpp b/src/devices/bus/isa/ega.cpp
index e3d75e4070a..45d169f3dff 100644
--- a/src/devices/bus/isa/ega.cpp
+++ b/src/devices/bus/isa/ega.cpp
@@ -783,7 +783,7 @@ WRITE_LINE_MEMBER( isa8_ega_device::vblank_changed )
CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_graphics )
{
- uint16_t *p = &bitmap.pix16(y);
+ uint16_t *p = &bitmap.pix(y);
LOG("%s: y = %d, x_count = %d, ma = %d, ra = %d\n", FUNCNAME, y, x_count, ma, ra );
@@ -844,12 +844,11 @@ CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_graphics )
CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_text )
{
- uint16_t *p = &bitmap.pix16(y);
- int i;
+ uint16_t *p = &bitmap.pix(y);
LOG("%s: y = %d, x_count = %d, ma = %d, ra = %d\n", FUNCNAME, y, x_count, ma, ra );
- for ( i = 0; i < x_count; i++ )
+ for ( int i = 0; i < x_count; i++ )
{
uint16_t offset = ma + i;
uint8_t chr = m_plane[0][ offset ];
@@ -901,8 +900,6 @@ CRTC_EGA_ROW_UPDATE( isa8_ega_device::pc_ega_text )
void isa8_ega_device::change_mode()
{
- int clock, pixels;
-
m_video_mode = 0;
/* Check for graphics mode */
@@ -938,8 +935,8 @@ void isa8_ega_device::change_mode()
}
/* Check for changes to the crtc input clock and number of pixels per clock */
- clock = ( ( m_misc_output & 0x0c ) ? 16257000 : 14318181 );
- pixels = ( ( m_sequencer.data[0x01] & 0x01 ) ? 8 : 9 );
+ int clock = ( ( m_misc_output & 0x0c ) ? 16257000 : 14318181 );
+ int pixels = ( ( m_sequencer.data[0x01] & 0x01 ) ? 8 : 9 );
if ( m_sequencer.data[0x01] & 0x08 )
{
diff --git a/src/devices/bus/isa/eis_hgb107x.cpp b/src/devices/bus/isa/eis_hgb107x.cpp
index 32aeac02c3e..25b16a38fe3 100644
--- a/src/devices/bus/isa/eis_hgb107x.cpp
+++ b/src/devices/bus/isa/eis_hgb107x.cpp
@@ -420,10 +420,6 @@ inline int isa8_epc_mda_device::get_yres()
MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)
{
- uint32_t *p = &bitmap.pix32(y);
- uint16_t chr_base = ra;
- int i;
-
// Get som debug data from a couple of rows now and then
if ( y < (16 * 0 + 0x20) && (m_framecnt & 0xff) == 0 )
{
@@ -436,7 +432,7 @@ MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)
{
for (int i = 0; i < get_xres(); i++)
{
- bitmap.pix32(y, i) = rgb_t::black();
+ bitmap.pix(y, i) = rgb_t::black();
}
}
@@ -449,14 +445,17 @@ MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)
// Text modes using one of two 9x16 fonts in character rom
else
{
+ uint32_t *p = &bitmap.pix(y);
+ uint16_t chr_base = ra;
+
// Adjust row pointer if in monochrome text mode as we insert two scanlines per row of characters (see below)
if (m_vmode & VM_MONO)
{
- p = &bitmap.pix32((y / 14) * 16 + y % 14);
+ p = &bitmap.pix((y / 14) * 16 + y % 14);
}
// Loop over each character in a row
- for ( i = 0; i < x_count; i++ )
+ for ( int i = 0; i < x_count; i++ )
{
uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
uint8_t chr = m_videoram[ offset ];
@@ -555,14 +554,14 @@ MC6845_UPDATE_ROW(isa8_epc_mda_device::crtc_update_row)
{
if (chr >= 0xb3 && chr <= 0xdf) // Handle the meta graphics characters
{
- bitmap.pix32(row + 1, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
- bitmap.pix32(row + 2, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
+ bitmap.pix(row + 1, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
+ bitmap.pix(row + 2, j + i * 9) = (*m_pal)[( data & (0x80 >> j) ) || (j == 8 && (data & 0x01)) ? fg : bg];
}
else
{
// Handle underline
- bitmap.pix32(row + 1, j + i * 9) =(*m_pal)[( attr & ATTR_FOREG ) == ATTR_ULINE ? fg : bg];
- bitmap.pix32(row + 2, j + i * 9) = (*m_pal)[bg];
+ bitmap.pix(row + 1, j + i * 9) =(*m_pal)[( attr & ATTR_FOREG ) == ATTR_ULINE ? fg : bg];
+ bitmap.pix(row + 2, j + i * 9) = (*m_pal)[bg];
}
}
}
diff --git a/src/devices/bus/isa/ex1280.cpp b/src/devices/bus/isa/ex1280.cpp
index 84c8bb8d269..2d9153616e9 100644
--- a/src/devices/bus/isa/ex1280.cpp
+++ b/src/devices/bus/isa/ex1280.cpp
@@ -144,15 +144,15 @@ void isa16_ex1280_device::vram_w(offs_t offset, uint16_t data, uint16_t mem_mask
TMS340X0_SCANLINE_RGB32_CB_MEMBER(isa16_ex1280_device::scanline_update)
{
- uint16_t *src = &m_vram[params->rowaddr << 8];
- uint32_t *dest = &bitmap.pix32(scanline);
- const pen_t *pens = m_ramdac->pens();
+ uint16_t const *const src = &m_vram[params->rowaddr << 8];
+ uint32_t *const dest = &bitmap.pix(scanline);
+ pen_t const *const pens = m_ramdac->pens();
int coladdr = params->coladdr << 1;
/* copy the non-blanked portions of this scanline */
for (int x = params->heblnk; x < params->hsblnk; x += 4)
{
- uint16_t pixels = src[coladdr++];
+ uint16_t const pixels = src[coladdr++];
dest[x + 0] = pens[pixels & 0x0f];
dest[x + 1] = pens[(pixels >> 4) & 0x0f];
dest[x + 2] = pens[(pixels >> 8) & 0x0f];
diff --git a/src/devices/bus/isa/fdc.cpp b/src/devices/bus/isa/fdc.cpp
index 0648a16a6e3..aab99b12ed5 100644
--- a/src/devices/bus/isa/fdc.cpp
+++ b/src/devices/bus/isa/fdc.cpp
@@ -45,10 +45,6 @@ isa8_fdc_device::isa8_fdc_device(const machine_config &mconfig, device_type type
{
}
-void isa8_fdc_device::device_reset()
-{
-}
-
WRITE_LINE_MEMBER( isa8_fdc_device::irq_w )
{
m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE);
@@ -80,7 +76,9 @@ void isa8_fdc_device::eop_w(int state)
}
-isa8_upd765_fdc_device::isa8_upd765_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : isa8_fdc_device(mconfig, type, tag, owner, clock)
+isa8_upd765_fdc_device::isa8_upd765_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : isa8_fdc_device(mconfig, type, tag, owner, clock)
+ , dor(0x00)
{
}
@@ -94,7 +92,11 @@ void isa8_upd765_fdc_device::device_start()
irq = drq = false;
fdc_irq = fdc_drq = false;
- dor = 0x00;
+}
+
+void isa8_upd765_fdc_device::device_reset()
+{
+ dor_w(0x00);
}
// Bits 0-1 select one of the 4 drives, but only if the associated
@@ -109,7 +111,6 @@ void isa8_upd765_fdc_device::device_start()
void isa8_upd765_fdc_device::dor_w(uint8_t data)
{
LOG("dor = %02x\n", data);
- uint8_t pdor = dor;
dor = data;
for(int i=0; i<4; i++)
@@ -124,8 +125,7 @@ void isa8_upd765_fdc_device::dor_w(uint8_t data)
check_irq();
check_drq();
- if((pdor^dor) & 4)
- m_fdc->soft_reset();
+ m_fdc->reset_w(!BIT(dor, 2));
}
uint8_t isa8_upd765_fdc_device::dor_r()
diff --git a/src/devices/bus/isa/fdc.h b/src/devices/bus/isa/fdc.h
index a0c872a28f0..d4321ca4210 100644
--- a/src/devices/bus/isa/fdc.h
+++ b/src/devices/bus/isa/fdc.h
@@ -34,9 +34,6 @@ protected:
// construction/destruction
isa8_fdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
- // device-level overrides
- virtual void device_reset() override;
-
virtual uint8_t dack_r(int line) override;
virtual void dack_w(int line, uint8_t data) override;
virtual void dack_line_w(int line, int state) override;
@@ -53,6 +50,7 @@ protected:
// device-level overrides
virtual void device_start() override;
+ virtual void device_reset() override;
uint8_t dor_r();
void dor_w(uint8_t data);
diff --git a/src/devices/bus/isa/gus.cpp b/src/devices/bus/isa/gus.cpp
index a1c3f39612e..237211047a2 100644
--- a/src/devices/bus/isa/gus.cpp
+++ b/src/devices/bus/isa/gus.cpp
@@ -243,29 +243,26 @@ void gf1_device::device_timer(emu_timer &timer, device_timer_id id, int param, v
}
}
-void gf1_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void gf1_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int x,y;
+ int x;
//uint32_t count;
- stream_sample_t* outputl = outputs[0];
- stream_sample_t* outputr = outputs[1];
- memset( outputl, 0x00, samples * sizeof(*outputl) );
- memset( outputr, 0x00, samples * sizeof(*outputr) );
+ auto &outputl = outputs[0];
+ auto &outputr = outputs[1];
+
+ outputl.fill(0);
+ outputr.fill(0);
for(x=0;x<32;x++) // for each voice
{
- stream_sample_t* left = outputl;
- stream_sample_t* right = outputr;
uint16_t vol = (m_volume_table[(m_voice[x].current_vol & 0xfff0) >> 4]);
- for(y=samples-1; y>=0; y--)
+ for (int sampindex = 0; sampindex < outputl.samples(); sampindex++)
{
uint32_t current = m_voice[x].current_addr >> 9;
// TODO: implement proper panning
- (*left) += ((m_voice[x].sample) * (vol/8192.0));
- (*right) += ((m_voice[x].sample) * (vol/8192.0));
- left++;
- right++;
+ outputl.add_int(sampindex, m_voice[x].sample * vol, 32768 * 8192);
+ outputr.add_int(sampindex, m_voice[x].sample * vol, 32768 * 8192);
if((!(m_voice[x].voice_ctrl & 0x40)) && (m_voice[x].current_addr >= m_voice[x].end_addr) && !m_voice[x].rollover && !(m_voice[x].voice_ctrl & 0x01))
{
if(m_voice[x].vol_ramp_ctrl & 0x04)
@@ -403,7 +400,7 @@ void gf1_device::device_start()
m_wave_ram.resize(1024*1024);
memset(&m_wave_ram[0], 0, 1024*1024);
- m_stream = stream_alloc_legacy(0,2,clock() / (14 * 16));
+ m_stream = stream_alloc(0,2,clock() / (14 * 16));
// init timers
m_timer1 = timer_alloc(ADLIB_TIMER1);
diff --git a/src/devices/bus/isa/gus.h b/src/devices/bus/isa/gus.h
index 3f637bee84d..be8dbbdbe2d 100644
--- a/src/devices/bus/isa/gus.h
+++ b/src/devices/bus/isa/gus.h
@@ -123,7 +123,7 @@ public:
// optional information overrides
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
protected:
// voice-specific registers
diff --git a/src/devices/bus/isa/isa_cards.cpp b/src/devices/bus/isa/isa_cards.cpp
index 72681cc249e..8f1232dcd13 100644
--- a/src/devices/bus/isa/isa_cards.cpp
+++ b/src/devices/bus/isa/isa_cards.cpp
@@ -49,6 +49,7 @@
#include "ultra24f.h"
#include "tekram_dc820.h"
#include "asc88.h"
+#include "omti8621.h"
// sound
#include "adlib.h"
@@ -225,4 +226,5 @@ void pc_isa16_cards(device_slot_interface &device)
device.option_add("dc320e", TEKRAM_DC320E); // actually an EISA card
device.option_add("dc820", TEKRAM_DC820); // actually an EISA card
device.option_add("dc820b", TEKRAM_DC820B); // actually an EISA card
+ device.option_add("omti8621", ISA16_OMTI8621);
}
diff --git a/src/devices/bus/isa/mach32.cpp b/src/devices/bus/isa/mach32.cpp
index 602147aa060..e9f4ad8d197 100644
--- a/src/devices/bus/isa/mach32.cpp
+++ b/src/devices/bus/isa/mach32.cpp
@@ -180,11 +180,8 @@ uint32_t mach32_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
return 0;
uint32_t src = (m_cursor_address & 0x000fffff) << 2;
- uint32_t* dst; // destination pixel
- uint8_t x,y,z;
- uint32_t colour0;
- uint32_t colour1;
+ uint32_t colour0, colour1;
if(depth == 8)
{
colour0 = pen(m_cursor_colour0_b);
@@ -197,18 +194,18 @@ uint32_t mach32_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
}
// draw hardware pointer (64x64 max)
- for(y=0;y<64;y++)
+ for(uint8_t y=0;y<64;y++)
{
- dst = &bitmap.pix32(m_cursor_vertical + y, m_cursor_horizontal);
- for(x=0;x<64;x+=8)
+ uint32_t *dst = &bitmap.pix(m_cursor_vertical + y, m_cursor_horizontal);
+ for(uint8_t x=0;x<64;x+=8)
{
- uint16_t bits = (vga.memory[(src+0) % vga.svga_intf.vram_size] | ((vga.memory[(src+1) % vga.svga_intf.vram_size]) << 8));
+ uint16_t const bits = (vga.memory[(src+0) % vga.svga_intf.vram_size] | ((vga.memory[(src+1) % vga.svga_intf.vram_size]) << 8));
- for(z=0;z<8;z++)
+ for(uint8_t z=0;z<8;z++)
{
if(((z + x) > (m_cursor_offset_horizontal-1)) && (y < (63 - m_cursor_offset_vertical)))
{
- uint8_t val = (bits >> (z*2)) & 0x03;
+ uint8_t const val = (bits >> (z*2)) & 0x03;
switch(val)
{
case 0: // cursor colour 0
diff --git a/src/devices/bus/isa/mda.cpp b/src/devices/bus/isa/mda.cpp
index cf4a6aa3803..ae61e78e116 100644
--- a/src/devices/bus/isa/mda.cpp
+++ b/src/devices/bus/isa/mda.cpp
@@ -225,27 +225,26 @@ void isa8_mda_device::device_reset()
***************************************************************************/
MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
- uint16_t chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
- int i;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
+ uint16_t const chr_base = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra;
- if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
- uint8_t chr = m_videoram[ offset ];
- uint8_t attr = m_videoram[ offset + 1 ];
- uint8_t data = m_chr_gen[ chr_base + chr * 8 ];
- uint8_t fg = ( attr & 0x08 ) ? 3 : 2;
+ uint16_t const offset = ((ma + i) << 1) & 0x0fff;
+ uint8_t const chr = m_videoram[offset];
+ uint8_t const attr = m_videoram[offset + 1];
+ uint8_t data = m_chr_gen[chr_base + chr * 8];
+ uint8_t fg = (attr & 0x08) ? 3 : 2;
uint8_t bg = 0;
- if ( ( attr & ~0x88 ) == 0 )
+ if ((attr & ~0x88) == 0)
{
data = 0x00;
}
- switch( attr )
+ switch (attr)
{
case 0x70:
bg = 2;
@@ -255,36 +254,36 @@ MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row )
bg = 2;
fg = 1;
break;
- case 0xF0:
+ case 0xf0:
bg = 3;
fg = 0;
break;
- case 0xF8:
+ case 0xf8:
bg = 3;
fg = 1;
break;
}
- if ( ( i == cursor_x && ( m_framecnt & 0x08 ) ) || ( attr & 0x07 ) == 0x01 )
+ if ((i == cursor_x && (m_framecnt & 0x08)) || (attr & 0x07) == 0x01)
{
- data = 0xFF;
+ data = 0xff;
}
- *p = palette[( data & 0x80 ) ? fg : bg]; p++;
- *p = palette[( data & 0x40 ) ? fg : bg]; p++;
- *p = palette[( data & 0x20 ) ? fg : bg]; p++;
- *p = palette[( data & 0x10 ) ? fg : bg]; p++;
- *p = palette[( data & 0x08 ) ? fg : bg]; p++;
- *p = palette[( data & 0x04 ) ? fg : bg]; p++;
- *p = palette[( data & 0x02 ) ? fg : bg]; p++;
- *p = palette[( data & 0x01 ) ? fg : bg]; p++;
- if ( ( chr & 0xE0 ) == 0xC0 )
+ *p++ = palette[(data & 0x80) ? fg : bg];
+ *p++ = palette[(data & 0x40) ? fg : bg];
+ *p++ = palette[(data & 0x20) ? fg : bg];
+ *p++ = palette[(data & 0x10) ? fg : bg];
+ *p++ = palette[(data & 0x08) ? fg : bg];
+ *p++ = palette[(data & 0x04) ? fg : bg];
+ *p++ = palette[(data & 0x02) ? fg : bg];
+ *p++ = palette[(data & 0x01) ? fg : bg];
+ if ((chr & 0xe0) == 0xc0)
{
- *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ *p++ = palette[(data & 0x01) ? fg : bg];
}
else
{
- *p = palette[bg]; p++;
+ *p++ = palette[bg];
}
}
}
@@ -298,75 +297,74 @@ MC6845_UPDATE_ROW( isa8_mda_device::mda_text_inten_update_row )
MC6845_UPDATE_ROW( isa8_mda_device::mda_text_blink_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
- uint16_t chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
- int i;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
+ uint16_t const chr_base = (ra & 0x08) ? 0x800 | (ra & 0x07) : ra;
- if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
- uint8_t chr = m_videoram[ offset ];
- uint8_t attr = m_videoram[ offset + 1 ];
- uint8_t data = m_chr_gen[ chr_base + chr * 8 ];
- uint8_t fg = ( attr & 0x08 ) ? 3 : 2;
+ uint16_t const offset = ((ma + i) << 1) & 0x0fff;
+ uint8_t const chr = m_videoram[offset];
+ uint8_t const attr = m_videoram[offset + 1];
+ uint8_t data = m_chr_gen[chr_base + chr * 8];
+ uint8_t fg = (attr & 0x08) ? 3 : 2;
uint8_t bg = 0;
- if ( ( attr & ~0x88 ) == 0 )
+ if ((attr & ~0x88) == 0)
{
data = 0x00;
}
- switch( attr )
+ switch (attr)
{
case 0x70:
- case 0xF0:
+ case 0xf0:
bg = 2;
fg = 0;
break;
case 0x78:
- case 0xF8:
+ case 0xf8:
bg = 2;
fg = 1;
break;
}
- if ( ( attr & 0x07 ) == 0x01 )
+ if ((attr & 0x07) == 0x01)
{
- data = 0xFF;
+ data = 0xff;
}
- if ( i == cursor_x )
+ if (i == cursor_x)
{
- if ( m_framecnt & 0x08 )
+ if (m_framecnt & 0x08)
{
- data = 0xFF;
+ data = 0xff;
}
}
else
{
- if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) )
+ if ((attr & 0x80) && (m_framecnt & 0x10))
{
data = 0x00;
}
}
- *p = palette[( data & 0x80 ) ? fg : bg]; p++;
- *p = palette[( data & 0x40 ) ? fg : bg]; p++;
- *p = palette[( data & 0x20 ) ? fg : bg]; p++;
- *p = palette[( data & 0x10 ) ? fg : bg]; p++;
- *p = palette[( data & 0x08 ) ? fg : bg]; p++;
- *p = palette[( data & 0x04 ) ? fg : bg]; p++;
- *p = palette[( data & 0x02 ) ? fg : bg]; p++;
- *p = palette[( data & 0x01 ) ? fg : bg]; p++;
- if ( ( chr & 0xE0 ) == 0xC0 )
+ *p++ = palette[(data & 0x80) ? fg : bg];
+ *p++ = palette[(data & 0x40) ? fg : bg];
+ *p++ = palette[(data & 0x20) ? fg : bg];
+ *p++ = palette[(data & 0x10) ? fg : bg];
+ *p++ = palette[(data & 0x08) ? fg : bg];
+ *p++ = palette[(data & 0x04) ? fg : bg];
+ *p++ = palette[(data & 0x02) ? fg : bg];
+ *p++ = palette[(data & 0x01) ? fg : bg];
+ if ((chr & 0xe0) == 0xc0)
{
- *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ *p++ = palette[(data & 0x01) ? fg : bg];
}
else
{
- *p = palette[bg]; p++;
+ *p++ = palette[bg];
}
}
}
@@ -631,34 +629,36 @@ void isa8_hercules_device::device_reset()
MC6845_UPDATE_ROW( isa8_hercules_device::hercules_gfx_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
- uint16_t gfx_base = ( ( m_mode_control & 0x80 ) ? 0x8000 : 0x0000 ) | ( ( ra & 0x03 ) << 13 );
- int i;
- if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
- for ( i = 0; i < x_count; i++ )
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
+ uint16_t const gfx_base = ((m_mode_control & 0x80) ? 0x8000 : 0x0000) | ((ra & 0x03) << 13);
+
+ if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
+ for (int i = 0; i < x_count; i++)
{
- uint8_t data = m_videoram[ gfx_base + ( ( ma + i ) << 1 ) ];
-
- *p = palette[( data & 0x80 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x40 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x20 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x10 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x08 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x04 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x02 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x01 ) ? 2 : 0]; p++;
-
- data = m_videoram[ gfx_base + ( ( ma + i ) << 1 ) + 1 ];
-
- *p = palette[( data & 0x80 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x40 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x20 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x10 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x08 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x04 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x02 ) ? 2 : 0]; p++;
- *p = palette[( data & 0x01 ) ? 2 : 0]; p++;
+ uint8_t data;
+
+ data = m_videoram[gfx_base + ((ma + i) << 1)];
+
+ *p++ = palette[(data & 0x80) ? 2 : 0];
+ *p++ = palette[(data & 0x40) ? 2 : 0];
+ *p++ = palette[(data & 0x20) ? 2 : 0];
+ *p++ = palette[(data & 0x10) ? 2 : 0];
+ *p++ = palette[(data & 0x08) ? 2 : 0];
+ *p++ = palette[(data & 0x04) ? 2 : 0];
+ *p++ = palette[(data & 0x02) ? 2 : 0];
+ *p++ = palette[(data & 0x01) ? 2 : 0];
+
+ data = m_videoram[gfx_base + ((ma + i) << 1) + 1];
+
+ *p++ = palette[(data & 0x80) ? 2 : 0];
+ *p++ = palette[(data & 0x40) ? 2 : 0];
+ *p++ = palette[(data & 0x20) ? 2 : 0];
+ *p++ = palette[(data & 0x10) ? 2 : 0];
+ *p++ = palette[(data & 0x08) ? 2 : 0];
+ *p++ = palette[(data & 0x04) ? 2 : 0];
+ *p++ = palette[(data & 0x02) ? 2 : 0];
+ *p++ = palette[(data & 0x01) ? 2 : 0];
}
}
@@ -816,27 +816,26 @@ void isa8_ec1840_0002_device::device_reset()
MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_inten_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
- uint16_t chr_base = ra;
- int i;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
+ uint16_t const chr_base = ra;
- if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
- uint8_t chr = m_videoram[ offset ];
- uint8_t attr = m_videoram[ offset + 1 ];
- uint8_t data = m_chr_gen[ (chr_base + chr * 16) << 1 ];
- uint8_t fg = ( attr & 0x08 ) ? 3 : 2;
+ uint16_t const offset = ((ma + i) << 1) & 0x0fff;
+ uint8_t const chr = m_videoram[offset];
+ uint8_t const attr = m_videoram[offset + 1];
+ uint8_t data = m_chr_gen[(chr_base + chr * 16) << 1];
+ uint8_t fg = (attr & 0x08) ? 3 : 2;
uint8_t bg = 0;
- if ( ( attr & ~0x88 ) == 0 )
+ if ((attr & ~0x88) == 0)
{
data = 0x00;
}
- switch( attr )
+ switch (attr)
{
case 0x70:
bg = 2;
@@ -846,29 +845,29 @@ MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_inten_update_row )
bg = 2;
fg = 1;
break;
- case 0xF0:
+ case 0xf0:
bg = 3;
fg = 0;
break;
- case 0xF8:
+ case 0xf8:
bg = 3;
fg = 1;
break;
}
- if ( ( i == cursor_x && ( m_framecnt & 0x08 ) ) || ( attr & 0x07 ) == 0x01 )
+ if ((i == cursor_x && (m_framecnt & 0x08)) || (attr & 0x07) == 0x01)
{
- data = 0xFF;
+ data = 0xff;
}
- *p = palette[( data & 0x80 ) ? fg : bg]; p++;
- *p = palette[( data & 0x40 ) ? fg : bg]; p++;
- *p = palette[( data & 0x20 ) ? fg : bg]; p++;
- *p = palette[( data & 0x10 ) ? fg : bg]; p++;
- *p = palette[( data & 0x08 ) ? fg : bg]; p++;
- *p = palette[( data & 0x04 ) ? fg : bg]; p++;
- *p = palette[( data & 0x02 ) ? fg : bg]; p++;
- *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ *p++ = palette[(data & 0x80) ? fg : bg];
+ *p++ = palette[(data & 0x40) ? fg : bg];
+ *p++ = palette[(data & 0x20) ? fg : bg];
+ *p++ = palette[(data & 0x10) ? fg : bg];
+ *p++ = palette[(data & 0x08) ? fg : bg];
+ *p++ = palette[(data & 0x04) ? fg : bg];
+ *p++ = palette[(data & 0x02) ? fg : bg];
+ *p++ = palette[(data & 0x01) ? fg : bg];
}
}
@@ -880,68 +879,67 @@ MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_inten_update_row )
MC6845_UPDATE_ROW( isa8_ec1840_0002_device::mda_lowres_text_blink_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
- uint16_t chr_base = ra;
- int i;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
+ uint16_t const chr_base = ra;
- if ( y == 0 ) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
- for ( i = 0; i < x_count; i++ )
+ if (y == 0) LOGROW("%11.6f: %-24s\n", machine().time().as_double(), FUNCNAME);
+ for (int i = 0; i < x_count; i++)
{
- uint16_t offset = ( ( ma + i ) << 1 ) & 0x0FFF;
- uint8_t chr = m_videoram[ offset ];
- uint8_t attr = m_videoram[ offset + 1 ];
- uint8_t data = m_chr_gen[ (chr_base + chr * 16) << 1 ];
- uint8_t fg = ( attr & 0x08 ) ? 3 : 2;
+ uint16_t const offset = ((ma + i) << 1) & 0x0fff;
+ uint8_t const chr = m_videoram[offset];
+ uint8_t const attr = m_videoram[offset + 1];
+ uint8_t data = m_chr_gen[(chr_base + chr * 16) << 1];
+ uint8_t fg = (attr & 0x08) ? 3 : 2;
uint8_t bg = 0;
- if ( ( attr & ~0x88 ) == 0 )
+ if ((attr & ~0x88) == 0)
{
data = 0x00;
}
- switch( attr )
+ switch (attr)
{
case 0x70:
- case 0xF0:
+ case 0xf0:
bg = 2;
fg = 0;
break;
case 0x78:
- case 0xF8:
+ case 0xf8:
bg = 2;
fg = 1;
break;
}
- if ( ( attr & 0x07 ) == 0x01 )
+ if ((attr & 0x07) == 0x01)
{
- data = 0xFF;
+ data = 0xff;
}
- if ( i == cursor_x )
+ if (i == cursor_x)
{
- if ( m_framecnt & 0x08 )
+ if (m_framecnt & 0x08)
{
- data = 0xFF;
+ data = 0xff;
}
}
else
{
- if ( ( attr & 0x80 ) && ( m_framecnt & 0x10 ) )
+ if ((attr & 0x80) && (m_framecnt & 0x10))
{
data = 0x00;
}
}
- *p = palette[( data & 0x80 ) ? fg : bg]; p++;
- *p = palette[( data & 0x40 ) ? fg : bg]; p++;
- *p = palette[( data & 0x20 ) ? fg : bg]; p++;
- *p = palette[( data & 0x10 ) ? fg : bg]; p++;
- *p = palette[( data & 0x08 ) ? fg : bg]; p++;
- *p = palette[( data & 0x04 ) ? fg : bg]; p++;
- *p = palette[( data & 0x02 ) ? fg : bg]; p++;
- *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ *p++ = palette[(data & 0x80) ? fg : bg];
+ *p++ = palette[(data & 0x40) ? fg : bg];
+ *p++ = palette[(data & 0x20) ? fg : bg];
+ *p++ = palette[(data & 0x10) ? fg : bg];
+ *p++ = palette[(data & 0x08) ? fg : bg];
+ *p++ = palette[(data & 0x04) ? fg : bg];
+ *p++ = palette[(data & 0x02) ? fg : bg];
+ *p++ = palette[(data & 0x01) ? fg : bg];
}
}
diff --git a/src/devices/bus/isa/num9rev.cpp b/src/devices/bus/isa/num9rev.cpp
index 07a35ee073c..632eb8b544b 100644
--- a/src/devices/bus/isa/num9rev.cpp
+++ b/src/devices/bus/isa/num9rev.cpp
@@ -36,7 +36,7 @@ UPD7220_DISPLAY_PIXELS_MEMBER( isa8_number_9_rev_device::hgdc_display_pixels )
color.set_r(pal->entry_color(m_ram[addr] | ((overlay & 0xf) << 8)).r());
color.set_g(pal->entry_color(m_ram[addr + 0x40000] | ((overlay & 0xf0) << 4)).g());
color.set_b(pal->entry_color(m_ram[addr + 0x80000] | (overlay & 0xf00)).b());
- bitmap.pix32(y, x + i) = color;
+ bitmap.pix(y, x + i) = color;
}
}
else
@@ -44,7 +44,7 @@ UPD7220_DISPLAY_PIXELS_MEMBER( isa8_number_9_rev_device::hgdc_display_pixels )
if(((address << 3) + 16) > (1024*1024))
return;
for(int i = 0; i < 16; i++)
- bitmap.pix32(y, x + i) = pal->entry_color(m_ram[(address << 4) + i]);
+ bitmap.pix(y, x + i) = pal->entry_color(m_ram[(address << 4) + i]);
}
}
diff --git a/src/devices/bus/isa/omti8621.cpp b/src/devices/bus/isa/omti8621.cpp
index 4c6225baa9f..e9c80e126d3 100644
--- a/src/devices/bus/isa/omti8621.cpp
+++ b/src/devices/bus/isa/omti8621.cpp
@@ -253,8 +253,15 @@ void omti8621_device::device_add_mconfig(machine_config &config)
m_fdc->intrq_wr_callback().set(FUNC(omti8621_device::fdc_irq_w));
m_fdc->drq_wr_callback().set(FUNC(omti8621_device::fdc_drq_w));
FLOPPY_CONNECTOR(config, m_floppy[0], pc_hd_floppies, "525hd", omti8621_device::floppy_formats);
-// Apollo workstations never have more then 1 floppy drive
-// FLOPPY_CONNECTOR(config, m_floppy[1], pc_hd_floppies, nullptr, omti8621_device::floppy_formats);
+ FLOPPY_CONNECTOR(config, m_floppy[1], pc_hd_floppies, nullptr, omti8621_device::floppy_formats);
+}
+
+void omti8621_apollo_device::device_add_mconfig(machine_config &config)
+{
+ omti8621_device::device_add_mconfig(config);
+
+ // Apollo workstations never have more then 1 floppy drive
+ config.device_remove(OMTI_FDC_TAG":1");
}
const tiny_rom_entry *omti8621_device::device_rom_region() const
@@ -1326,8 +1333,7 @@ void omti8621_device::fd_moten_w(uint8_t data)
m_moten = data;
- if (!BIT(data, 2))
- m_fdc->soft_reset();
+ m_fdc->reset_w(!BIT(data, 2));
for (int i = 0; i < 2; i++)
{
@@ -1342,8 +1348,11 @@ void omti8621_device::fd_moten_w(uint8_t data)
void omti8621_device::fd_rate_w(uint8_t data)
{
- // Bit 1 = FD_MINI (TODO)
- // Bit 0 = FD_RATE (TODO)
+ // Bit 1 = FD_MINI (connects to pin 3 of FDC9239)
+ // Bit 0 = FD_RATE (inverted output connects to pin 4 of 74F163)
+ u32 fdc_clk = (48_MHz_XTAL / (BIT(data, 0) ? 5 : 3) / (BIT(data, 1) ? 4 : 2)).value();
+ m_fdc->set_unscaled_clock(fdc_clk);
+ m_fdc->set_rate(fdc_clk / 16);
}
void omti8621_device::fd_extra_w(uint8_t data)
diff --git a/src/devices/bus/isa/omti8621.h b/src/devices/bus/isa/omti8621.h
index d637eb57611..0308b61eee6 100644
--- a/src/devices/bus/isa/omti8621.h
+++ b/src/devices/bus/isa/omti8621.h
@@ -163,7 +163,9 @@ public:
// get sector diskaddr of logical unit lun into data_buffer
uint32_t get_sector(int32_t diskaddr, uint8_t *data_buffer, uint32_t length, uint8_t lun);
+
protected:
+ virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
};
diff --git a/src/devices/bus/isa/pgc.cpp b/src/devices/bus/isa/pgc.cpp
index 1366bc92dbc..f204333f9f2 100644
--- a/src/devices/bus/isa/pgc.cpp
+++ b/src/devices/bus/isa/pgc.cpp
@@ -401,14 +401,11 @@ uint8_t isa8_pgc_device::init_r()
uint32_t isa8_pgc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint16_t *p;
- uint8_t *v;
-
for (int y = 0; y < PGC_DISP_VERT; y++)
{
// XXX address translation happens in hardware
- v = &m_vram[y * 1024];
- p = &bitmap.pix16(y + PGC_VERT_START, PGC_HORZ_START);
+ uint8_t const *v = &m_vram[y * 1024];
+ uint16_t *p = &bitmap.pix(y + PGC_VERT_START, PGC_HORZ_START);
for (int x = 0; x < PGC_DISP_HORZ; x++)
{
diff --git a/src/devices/bus/isa/trident.cpp b/src/devices/bus/isa/trident.cpp
index 0d64df5ba27..5fc2d2d6d19 100644
--- a/src/devices/bus/isa/trident.cpp
+++ b/src/devices/bus/isa/trident.cpp
@@ -212,29 +212,22 @@ void trident_vga_device::device_reset()
uint32_t trident_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t cur_mode;
-
svga_device::screen_update(screen,bitmap,cliprect);
- cur_mode = pc_vga_choosevideomode();
+ uint8_t const cur_mode = pc_vga_choosevideomode();
// draw hardware graphics cursor
if(tri.cursor_ctrl & 0x80) // if cursor is enabled
{
- uint32_t src;
- uint32_t* dst;
- uint8_t val;
- int x,y;
- uint16_t cx = tri.cursor_x & 0x0fff;
- uint16_t cy = tri.cursor_y & 0x0fff;
- uint32_t bg_col;
- uint32_t fg_col;
- uint8_t cursor_size = (tri.cursor_ctrl & 0x01) ? 64 : 32;
+ uint16_t const cx = tri.cursor_x & 0x0fff;
+ uint16_t const cy = tri.cursor_y & 0x0fff;
+ uint8_t const cursor_size = (tri.cursor_ctrl & 0x01) ? 64 : 32;
if(cur_mode == SCREEN_OFF || cur_mode == TEXT_MODE || cur_mode == MONO_MODE || cur_mode == CGA_MODE || cur_mode == EGA_MODE)
return 0; // cursor only works in VGA or SVGA modes
- src = tri.cursor_loc * 1024; // start address is in units of 1024 bytes
+ uint32_t src = tri.cursor_loc * 1024; // start address is in units of 1024 bytes
+ uint32_t bg_col, fg_col;
if(cur_mode == RGB16_MODE)
{
bg_col = tri.cursor_bg;
@@ -246,11 +239,11 @@ uint32_t trident_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &
fg_col = pen(tri.cursor_fg & 0xff);
}
- for(y=0;y<cursor_size;y++)
+ for(int y=0;y<cursor_size;y++)
{
uint8_t bitcount = 31;
- dst = &bitmap.pix32(cy + y, cx);
- for(x=0;x<cursor_size;x++)
+ uint32_t *const dst = &bitmap.pix(cy + y, cx);
+ for(int x=0;x<cursor_size;x++)
{
uint32_t bitb = (vga.memory[(src+3) % vga.svga_intf.vram_size]
| ((vga.memory[(src+2) % vga.svga_intf.vram_size]) << 8)
@@ -260,7 +253,7 @@ uint32_t trident_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &
| ((vga.memory[(src+6) % vga.svga_intf.vram_size]) << 8)
| ((vga.memory[(src+5) % vga.svga_intf.vram_size]) << 16)
| ((vga.memory[(src+4) % vga.svga_intf.vram_size]) << 24));
- val = (BIT(bita << 1,bitcount+1) << 1 | BIT(bitb,bitcount));
+ uint8_t const val = (BIT(bita << 1,bitcount+1) << 1 | BIT(bitb,bitcount));
if(tri.cursor_ctrl & 0x40)
{ // X11 mode
switch(val)
diff --git a/src/devices/bus/macpds/pds_tpdfpd.cpp b/src/devices/bus/macpds/pds_tpdfpd.cpp
index 833d1d3820f..6d9dd93b4ed 100644
--- a/src/devices/bus/macpds/pds_tpdfpd.cpp
+++ b/src/devices/bus/macpds/pds_tpdfpd.cpp
@@ -154,27 +154,23 @@ void macpds_sedisplay_device::device_timer(emu_timer &timer, device_timer_id tid
uint32_t macpds_sedisplay_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
+ uint8_t const *const vram = m_vram.get();
- vram = m_vram.get();
-
- for (y = 0; y < 870; y++)
+ for (int y = 0; y < 870; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * (1024/8)) + (x^1)];
-
- *scanline++ = m_palette[((pixels>>7)&0x1)^1];
- *scanline++ = m_palette[((pixels>>6)&0x1)^1];
- *scanline++ = m_palette[((pixels>>5)&0x1)^1];
- *scanline++ = m_palette[((pixels>>4)&0x1)^1];
- *scanline++ = m_palette[((pixels>>3)&0x1)^1];
- *scanline++ = m_palette[((pixels>>2)&0x1)^1];
- *scanline++ = m_palette[((pixels>>1)&0x1)^1];
- *scanline++ = m_palette[(pixels&1)^1];
+ uint8_t const pixels = vram[(y * (1024/8)) + (x^1)];
+
+ *scanline++ = m_palette[BIT(~pixels, 7)];
+ *scanline++ = m_palette[BIT(~pixels, 6)];
+ *scanline++ = m_palette[BIT(~pixels, 5)];
+ *scanline++ = m_palette[BIT(~pixels, 4)];
+ *scanline++ = m_palette[BIT(~pixels, 3)];
+ *scanline++ = m_palette[BIT(~pixels, 2)];
+ *scanline++ = m_palette[BIT(~pixels, 1)];
+ *scanline++ = m_palette[BIT(~pixels, 0)];
}
}
diff --git a/src/devices/bus/mtx/sdx.cpp b/src/devices/bus/mtx/sdx.cpp
index e413e997f5b..09e7199ac53 100644
--- a/src/devices/bus/mtx/sdx.cpp
+++ b/src/devices/bus/mtx/sdx.cpp
@@ -417,7 +417,7 @@ MC6845_UPDATE_ROW(mtx_sdxcpm_device::crtc_update_row)
int color = BIT(data, 7) ? fg : bg;
- bitmap.pix32(y, x) = pen[de ? color : 0];
+ bitmap.pix(y, x) = pen[de ? color : 0];
data <<= 1;
}
diff --git a/src/devices/bus/nasbus/avc.cpp b/src/devices/bus/nasbus/avc.cpp
index f7bc8e95596..f4590b2ac3f 100644
--- a/src/devices/bus/nasbus/avc.cpp
+++ b/src/devices/bus/nasbus/avc.cpp
@@ -120,7 +120,7 @@ MC6845_UPDATE_ROW( nascom_avc_device::crtc_update_row )
}
// plot the pixel
- bitmap.pix32(y, x) = m_palette->pen_color((b << 2) | (g << 1) | (r << 0));
+ bitmap.pix(y, x) = m_palette->pen_color((b << 2) | (g << 1) | (r << 0));
}
}
diff --git a/src/devices/bus/neogeo/prot_fatfury2.cpp b/src/devices/bus/neogeo/prot_fatfury2.cpp
index c8e7151e6e8..b88d7b43ec1 100644
--- a/src/devices/bus/neogeo/prot_fatfury2.cpp
+++ b/src/devices/bus/neogeo/prot_fatfury2.cpp
@@ -41,7 +41,12 @@ uint16_t fatfury2_prot_device::protection_r(offs_t offset)
m_pro_ct0->h_w(BIT(offset, 2));
u8 gad = m_pro_ct0->gad_r();
u8 gbd = m_pro_ct0->gbd_r();
- return (BIT(gbd, 0, 2) << 6) | (BIT(gbd, 2, 2) << 4) | (BIT(gad, 0, 2) << 6) | (BIT(gad, 2, 2) << 4);
+ /*
+ Data pin from PRO-CT0
+ D0 D1 D2 D3 D4 D5 D6 D7
+ GAD2 GAD3 GAD0 GAD1 GBD2 GBD3 GBD0 GBD1
+ */
+ return (BIT(gbd, 0, 2) << 6) | (BIT(gbd, 2, 2) << 4) | (BIT(gad, 0, 2) << 2) | (BIT(gad, 2, 2) << 0);
}
@@ -55,8 +60,13 @@ void fatfury2_prot_device::protection_w(offs_t offset, uint16_t data)
m_pro_ct0->h_w(BIT(offset, 2)); // A3
// C16-31 = A4-A19, C0-C15 = D0-D15
- m_pro_ct0->c_w((u32(bitswap<16>(BIT(offset, 3, 16), 15, 13, 11, 9, 14, 12, 10, 8, 7, 5, 3, 1, 6, 4, 2, 0)) << 16) |
- bitswap<16>(data, 15, 13, 11, 9, 14, 12, 10, 8, 7, 5, 3, 1, 6, 4, 2, 0));
+ /*
+ Address/Data pin mapping into PRO-CT0
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12 C13 C14 C15 C16 C17 C18 C19 C20 C21 C22 C23 C24 C25 C26 C27 C28 C29 C30 C31 LOAD EVEN H
+ D0 D4 D1 D5 D2 D6 D3 D7 D8 D12 D9 D13 D10 D14 D11 D15 A4 A8 A5 A9 A6 A10 A7 A11 A12 A16 A13 A17 A14 A18 A15 A19 A1 A2 A3
+ */
+ m_pro_ct0->c_w((u32(bitswap<16>(BIT(offset, 3, 16), 15, 11, 14, 10, 13, 9, 12, 8, 7, 3, 6, 2, 5, 1, 4, 0)) << 16) |
+ u32(bitswap<16>(data, 15, 11, 14, 10, 13, 9, 12, 8, 7, 3, 6, 2, 5, 1, 4, 0)));
// release /PORTOEL
m_pro_ct0->clk_w(false);
diff --git a/src/devices/bus/nscsi/hd.cpp b/src/devices/bus/nscsi/hd.cpp
index 6c6543b409c..f4c74962d20 100644
--- a/src/devices/bus/nscsi/hd.cpp
+++ b/src/devices/bus/nscsi/hd.cpp
@@ -119,8 +119,15 @@ void nscsi_harddisk_device::scsi_command()
LOG("command READ start=%08x blocks=%04x\n", lba, blocks);
- scsi_data_in(2, blocks*bytes_per_sector);
- scsi_status_complete(SS_GOOD);
+ if(hard_disk_read(harddisk, lba, block)) {
+ scsi_data_in(2, blocks*bytes_per_sector);
+ scsi_status_complete(SS_GOOD);
+ }
+ else
+ {
+ scsi_status_complete(SS_CHECK_CONDITION);
+ sense(false, SK_ILLEGAL_REQUEST, SK_ASC_INVALID_FIELD_IN_CDB);
+ }
break;
case SC_WRITE_6:
@@ -468,8 +475,15 @@ void nscsi_harddisk_device::scsi_command()
LOG("command READ EXTENDED start=%08x blocks=%04x\n",lba, blocks);
- scsi_data_in(2, blocks*bytes_per_sector);
- scsi_status_complete(SS_GOOD);
+ if(hard_disk_read(harddisk, lba, block)) {
+ scsi_data_in(2, blocks*bytes_per_sector);
+ scsi_status_complete(SS_GOOD);
+ }
+ else
+ {
+ scsi_status_complete(SS_CHECK_CONDITION);
+ sense(false, SK_ILLEGAL_REQUEST, SK_ASC_INVALID_FIELD_IN_CDB);
+ }
break;
case SC_WRITE_10:
diff --git a/src/devices/bus/nubus/laserview.cpp b/src/devices/bus/nubus/laserview.cpp
index 2c58b6e8dc3..7e802b58988 100644
--- a/src/devices/bus/nubus/laserview.cpp
+++ b/src/devices/bus/nubus/laserview.cpp
@@ -117,30 +117,26 @@ void nubus_laserview_device::device_reset()
uint32_t nubus_laserview_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels;
-
if (!m_vbl_disable)
{
raise_slot_irq();
}
- for (y = 0; y < 600; y++)
+ for (int y = 0; y < 600; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 832/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 832/8; x++)
{
- pixels = m_vram[(y * 104) + (BYTE4_XOR_BE(x)) + 0x20];
-
- *scanline++ = m_palette[(pixels>>7)&1];
- *scanline++ = m_palette[(pixels>>6)&1];
- *scanline++ = m_palette[(pixels>>5)&1];
- *scanline++ = m_palette[(pixels>>4)&1];
- *scanline++ = m_palette[(pixels>>3)&1];
- *scanline++ = m_palette[(pixels>>2)&1];
- *scanline++ = m_palette[(pixels>>1)&1];
- *scanline++ = m_palette[(pixels&1)];
+ uint8_t const pixels = m_vram[(y * 104) + (BYTE4_XOR_BE(x)) + 0x20];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
diff --git a/src/devices/bus/nubus/nubus_48gc.cpp b/src/devices/bus/nubus/nubus_48gc.cpp
index 9105414f3e0..b9b831c6de2 100644
--- a/src/devices/bus/nubus/nubus_48gc.cpp
+++ b/src/devices/bus/nubus/nubus_48gc.cpp
@@ -12,6 +12,9 @@
#include "nubus_48gc.h"
#include "screen.h"
+#include <algorithm>
+
+
#define VRAM_SIZE (0x200000) // 2 megs, maxed out
#define GC48_SCREEN_NAME "48gc_screen"
@@ -152,10 +155,7 @@ void jmfb_device::device_timer(emu_timer &timer, device_timer_id tid, int param,
uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline, *base;
- int x, y;
- uint8_t *vram8 = &m_vram[0];
- uint8_t pixels;
+ uint8_t const *const vram8 = &m_vram[0xa00];
// first time? kick off the VBL timer
if (!m_screen)
@@ -164,37 +164,35 @@ uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
m_timer->adjust(m_screen->time_until_pos(479, 0), 0);
}
- vram8 += 0xa00;
-
switch (m_mode)
{
case 0: // 1bpp
- for (y = 0; y < m_yres; y++)
+ for (int y = 0; y < m_yres; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < m_xres/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < m_xres/8; x++)
{
- pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[(pixels>>7)&1];
- *scanline++ = m_palette[(pixels>>6)&1];
- *scanline++ = m_palette[(pixels>>5)&1];
- *scanline++ = m_palette[(pixels>>4)&1];
- *scanline++ = m_palette[(pixels>>3)&1];
- *scanline++ = m_palette[(pixels>>2)&1];
- *scanline++ = m_palette[(pixels>>1)&1];
- *scanline++ = m_palette[pixels&1];
+ uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
break;
case 1: // 2bpp
- for (y = 0; y < m_yres; y++)
+ for (int y = 0; y < m_yres; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < m_xres/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < m_xres/4; x++)
{
- pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels>>6)&0x3];
*scanline++ = m_palette[(pixels>>4)&0x3];
@@ -205,13 +203,12 @@ uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
break;
case 2: // 4 bpp
- for (y = 0; y < m_yres; y++)
+ for (int y = 0; y < m_yres; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < m_xres/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < m_xres/2; x++)
{
- pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels>>4)&0xf];
*scanline++ = m_palette[pixels&0xf];
@@ -220,27 +217,22 @@ uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
break;
case 3: // 8 bpp
- for (y = 0; y < m_yres; y++)
+ for (int y = 0; y < m_yres; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < m_xres; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < m_xres; x++)
{
- pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram8[(y * m_stride) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
break;
case 4: // 24 bpp
- for (y = 0; y < m_yres; y++)
+ for (int y = 0; y < m_yres; y++)
{
- scanline = &bitmap.pix32(y);
- base = (uint32_t *)&m_vram[y * m_stride];
- for (x = 0; x < m_xres; x++)
- {
- *scanline++ = *base++;
- }
+ uint32_t const *base = (uint32_t *)&m_vram[y * m_stride];
+ std::copy_n(base, m_xres, &bitmap.pix(y));
}
break;
}
diff --git a/src/devices/bus/nubus/nubus_cb264.cpp b/src/devices/bus/nubus/nubus_cb264.cpp
index db964ec2055..db1fd821a11 100644
--- a/src/devices/bus/nubus/nubus_cb264.cpp
+++ b/src/devices/bus/nubus/nubus_cb264.cpp
@@ -17,6 +17,9 @@
#include "nubus_cb264.h"
#include "screen.h"
+#include <algorithm>
+
+
#define CB264_SCREEN_NAME "cb264_screen"
#define CB264_ROM_REGION "cb264_rom"
@@ -122,10 +125,6 @@ void nubus_cb264_device::device_reset()
uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline, *base;
- int x, y;
- uint8_t pixels;
-
if (!m_cb264_vbl_disable)
{
raise_slot_irq();
@@ -134,12 +133,12 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
switch (m_cb264_mode)
{
case 0: // 1 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels&0x80];
*scanline++ = m_palette[(pixels<<1)&0x80];
@@ -154,12 +153,12 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
break;
case 1: // 2 bpp (3f/7f/bf/ff)
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels&0xc0];
*scanline++ = m_palette[(pixels<<2)&0xc0];
@@ -170,13 +169,12 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/2; x++)
{
- pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels&0xf0];
*scanline++ = m_palette[(pixels<<4)&0xf0];
@@ -185,13 +183,12 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640; x++)
{
- pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = m_vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
@@ -200,16 +197,11 @@ uint32_t nubus_cb264_device::screen_update(screen_device &screen, bitmap_rgb32 &
case 4: // 24 bpp
case 7: // ???
{
- uint32_t *vram32 = (uint32_t *)&m_vram[0];
+ uint32_t const *const vram32 = (uint32_t *)&m_vram[0];
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- base = &vram32[y * 1024];
- for (x = 0; x < 640; x++)
- {
- *scanline++ = *base++;
- }
+ std::copy_n(&vram32[y * 1024], 640, &bitmap.pix(y));
}
}
break;
diff --git a/src/devices/bus/nubus/nubus_m2hires.cpp b/src/devices/bus/nubus/nubus_m2hires.cpp
index 851537685d2..e913c0cb0cb 100644
--- a/src/devices/bus/nubus/nubus_m2hires.cpp
+++ b/src/devices/bus/nubus/nubus_m2hires.cpp
@@ -137,41 +137,37 @@ void nubus_m2hires_device::device_timer(emu_timer &timer, device_timer_id tid, i
uint32_t nubus_m2hires_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[0x20];
+ uint8_t const *const vram = &m_vram[0x20];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[((pixels>>7)&0x1)];
- *scanline++ = m_palette[((pixels>>6)&0x1)];
- *scanline++ = m_palette[((pixels>>5)&0x1)];
- *scanline++ = m_palette[((pixels>>4)&0x1)];
- *scanline++ = m_palette[((pixels>>3)&0x1)];
- *scanline++ = m_palette[((pixels>>2)&0x1)];
- *scanline++ = m_palette[((pixels>>1)&0x1)];
- *scanline++ = m_palette[(pixels&1)];
+ uint8_t const pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[((pixels>>6)&3)];
*scanline++ = m_palette[((pixels>>4)&3)];
@@ -182,13 +178,13 @@ uint32_t nubus_m2hires_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
- for (x = 0; x < 640/2; x++)
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[((pixels&0xf0)>>4)];
*scanline++ = m_palette[(pixels&0xf)];
@@ -197,13 +193,13 @@ uint32_t nubus_m2hires_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
- for (x = 0; x < 640; x++)
+ for (int x = 0; x < 640; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
diff --git a/src/devices/bus/nubus/nubus_m2video.cpp b/src/devices/bus/nubus/nubus_m2video.cpp
index f557d7631b0..60728d7dd15 100644
--- a/src/devices/bus/nubus/nubus_m2video.cpp
+++ b/src/devices/bus/nubus/nubus_m2video.cpp
@@ -139,21 +139,17 @@ void nubus_m2video_device::device_timer(emu_timer &timer, device_timer_id tid, i
uint32_t nubus_m2video_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[0x20];
+ uint8_t const *const vram = &m_vram[0x20];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0x80)];
*scanline++ = m_palette[((pixels<<1)&0x80)];
@@ -168,12 +164,12 @@ uint32_t nubus_m2video_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0xc0)];
*scanline++ = m_palette[((pixels<<2)&0xc0)];
@@ -184,13 +180,12 @@ uint32_t nubus_m2video_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0xf0)];
*scanline++ = m_palette[((pixels&0x0f)<<4)];
@@ -199,13 +194,12 @@ uint32_t nubus_m2video_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
diff --git a/src/devices/bus/nubus/nubus_radiustpd.cpp b/src/devices/bus/nubus/nubus_radiustpd.cpp
index f6d152be059..89518f0d223 100644
--- a/src/devices/bus/nubus/nubus_radiustpd.cpp
+++ b/src/devices/bus/nubus/nubus_radiustpd.cpp
@@ -139,27 +139,23 @@ void nubus_radiustpd_device::device_timer(emu_timer &timer, device_timer_id tid,
uint32_t nubus_radiustpd_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
+ uint8_t const *const vram = &m_vram[0x200];
- vram = &m_vram[0x200];
-
- for (y = 0; y < 880; y++)
+ for (int y = 0; y < 880; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1152/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152/8; x++)
{
- pixels = vram[(y * (1152/8)) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[((pixels>>7)&0x1)];
- *scanline++ = m_palette[((pixels>>6)&0x1)];
- *scanline++ = m_palette[((pixels>>5)&0x1)];
- *scanline++ = m_palette[((pixels>>4)&0x1)];
- *scanline++ = m_palette[((pixels>>3)&0x1)];
- *scanline++ = m_palette[((pixels>>2)&0x1)];
- *scanline++ = m_palette[((pixels>>1)&0x1)];
- *scanline++ = m_palette[(pixels&1)];
+ uint8_t const pixels = vram[(y * (1152/8)) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
diff --git a/src/devices/bus/nubus/nubus_spec8.cpp b/src/devices/bus/nubus/nubus_spec8.cpp
index b7a29b6f537..6ca1f9f4489 100644
--- a/src/devices/bus/nubus/nubus_spec8.cpp
+++ b/src/devices/bus/nubus/nubus_spec8.cpp
@@ -144,21 +144,17 @@ void nubus_spec8s3_device::device_timer(emu_timer &timer, device_timer_id tid, i
uint32_t nubus_spec8s3_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[0x400];
+ uint8_t const *const vram = &m_vram[0x400];
switch (m_mode)
{
case 0: // 1 bpp
- for (y = 0; y < 768; y++)
+ for (int y = 0; y < 768; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1024/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1024/8; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels&0x80];
*scanline++ = m_palette[(pixels<<1)&0x80];
@@ -173,12 +169,12 @@ uint32_t nubus_spec8s3_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 1: // 2 bpp
- for (y = 0; y < 768; y++)
+ for (int y = 0; y < 768; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1024/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1024/4; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels&0xc0];
*scanline++ = m_palette[(pixels<<2)&0xc0];
@@ -189,13 +185,12 @@ uint32_t nubus_spec8s3_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 2: // 4 bpp
- for (y = 0; y < 768; y++)
+ for (int y = 0; y < 768; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 1024/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1024/2; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels&0xf0];
*scanline++ = m_palette[(pixels<<4)&0xf0];
@@ -204,13 +199,12 @@ uint32_t nubus_spec8s3_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 3: // 8 bpp
- for (y = 0; y < 768; y++)
+ for (int y = 0; y < 768; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 1024; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1024; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
diff --git a/src/devices/bus/nubus/nubus_specpdq.cpp b/src/devices/bus/nubus/nubus_specpdq.cpp
index 891defaa336..c00938c6102 100644
--- a/src/devices/bus/nubus/nubus_specpdq.cpp
+++ b/src/devices/bus/nubus/nubus_specpdq.cpp
@@ -157,22 +157,18 @@ void nubus_specpdq_device::device_timer(emu_timer &timer, device_timer_id tid, i
uint32_t nubus_specpdq_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
// first time? kick off the VBL timer
- vram = &m_vram[0x9000];
+ uint8_t const *const vram = &m_vram[0x9000];
switch (m_mode)
{
case 0: // 1 bpp
- for (y = 0; y < 844; y++)
+ for (int y = 0; y < 844; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1152/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152/8; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette_val[(pixels&0x80)];
*scanline++ = m_palette_val[((pixels<<1)&0x80)];
@@ -187,12 +183,12 @@ uint32_t nubus_specpdq_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 1: // 2 bpp
- for (y = 0; y < 844; y++)
+ for (int y = 0; y < 844; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1152/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152/4; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette_val[(pixels&0xc0)];
*scanline++ = m_palette_val[((pixels<<2)&0xc0)];
@@ -203,13 +199,12 @@ uint32_t nubus_specpdq_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 2: // 4 bpp
- for (y = 0; y < 844; y++)
+ for (int y = 0; y < 844; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 1152/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152/2; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette_val[(pixels&0xf0)];
*scanline++ = m_palette_val[((pixels<<4)&0xf0)];
@@ -218,13 +213,12 @@ uint32_t nubus_specpdq_device::screen_update(screen_device &screen, bitmap_rgb32
break;
case 3: // 8 bpp
- for (y = 0; y < 844; y++)
+ for (int y = 0; y < 844; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 1152; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152; x++)
{
- pixels = vram[(y * 1152) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1152) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette_val[pixels];
}
}
diff --git a/src/devices/bus/nubus/nubus_vikbw.cpp b/src/devices/bus/nubus/nubus_vikbw.cpp
index 1c25795cd45..18c94f9ba5b 100644
--- a/src/devices/bus/nubus/nubus_vikbw.cpp
+++ b/src/devices/bus/nubus/nubus_vikbw.cpp
@@ -117,30 +117,26 @@ void nubus_vikbw_device::device_reset()
uint32_t nubus_vikbw_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels;
-
if (!m_vbl_disable)
{
raise_slot_irq();
}
- for (y = 0; y < 768; y++)
+ for (int y = 0; y < 768; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1024/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1024/8; x++)
{
- pixels = m_vram[(y * 128) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[(pixels>>7)&1];
- *scanline++ = m_palette[(pixels>>6)&1];
- *scanline++ = m_palette[(pixels>>5)&1];
- *scanline++ = m_palette[(pixels>>4)&1];
- *scanline++ = m_palette[(pixels>>3)&1];
- *scanline++ = m_palette[(pixels>>2)&1];
- *scanline++ = m_palette[(pixels>>1)&1];
- *scanline++ = m_palette[(pixels&1)];
+ uint8_t const pixels = m_vram[(y * 128) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
diff --git a/src/devices/bus/nubus/nubus_wsportrait.cpp b/src/devices/bus/nubus/nubus_wsportrait.cpp
index 2f56488bf48..9894e0d7906 100644
--- a/src/devices/bus/nubus/nubus_wsportrait.cpp
+++ b/src/devices/bus/nubus/nubus_wsportrait.cpp
@@ -137,42 +137,38 @@ void nubus_wsportrait_device::device_timer(emu_timer &timer, device_timer_id tid
uint32_t nubus_wsportrait_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
// first time? kick off the VBL timer
- vram = &m_vram[0x80];
+ uint8_t const *const vram = &m_vram[0x80];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 870; y++)
+ for (int y = 0; y < 870; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[((pixels>>7)&0x1)];
- *scanline++ = m_palette[((pixels>>6)&0x1)];
- *scanline++ = m_palette[((pixels>>5)&0x1)];
- *scanline++ = m_palette[((pixels>>4)&0x1)];
- *scanline++ = m_palette[((pixels>>3)&0x1)];
- *scanline++ = m_palette[((pixels>>2)&0x1)];
- *scanline++ = m_palette[((pixels>>1)&0x1)];
- *scanline++ = m_palette[(pixels&1)];
+ uint8_t const pixels = vram[(y * 128) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 256) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[((pixels>>6)&3)];
*scanline++ = m_palette[((pixels>>4)&3)];
@@ -183,13 +179,12 @@ uint32_t nubus_wsportrait_device::screen_update(screen_device &screen, bitmap_rg
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 512) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[((pixels&0xf0)>>4)];
*scanline++ = m_palette[(pixels&0xf)];
diff --git a/src/devices/bus/nubus/pds30_30hr.cpp b/src/devices/bus/nubus/pds30_30hr.cpp
index 2fe4687fc44..dde2348abc6 100644
--- a/src/devices/bus/nubus/pds30_30hr.cpp
+++ b/src/devices/bus/nubus/pds30_30hr.cpp
@@ -139,41 +139,37 @@ void nubus_xceed30hr_device::device_timer(emu_timer &timer, device_timer_id tid,
uint32_t nubus_xceed30hr_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[1024];
+ uint8_t const *const vram = &m_vram[1024];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[(pixels>>7)&1];
- *scanline++ = m_palette[(pixels>>6)&1];
- *scanline++ = m_palette[(pixels>>5)&1];
- *scanline++ = m_palette[(pixels>>4)&1];
- *scanline++ = m_palette[(pixels>>3)&1];
- *scanline++ = m_palette[(pixels>>2)&1];
- *scanline++ = m_palette[(pixels>>1)&1];
- *scanline++ = m_palette[pixels&1];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[((pixels>>6)&3)];
*scanline++ = m_palette[((pixels>>4)&3)];
@@ -184,13 +180,12 @@ uint32_t nubus_xceed30hr_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels>>4)];
*scanline++ = m_palette[(pixels&0xf)];
@@ -199,13 +194,12 @@ uint32_t nubus_xceed30hr_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
diff --git a/src/devices/bus/nubus/pds30_cb264.cpp b/src/devices/bus/nubus/pds30_cb264.cpp
index aa0ca1df648..388aa5f54d5 100644
--- a/src/devices/bus/nubus/pds30_cb264.cpp
+++ b/src/devices/bus/nubus/pds30_cb264.cpp
@@ -10,6 +10,9 @@
#include "pds30_cb264.h"
#include "screen.h"
+#include <algorithm>
+
+
#define CB264SE30_SCREEN_NAME "cb264_screen"
#define CB264SE30_ROM_REGION "cb264_rom"
@@ -133,21 +136,17 @@ void nubus_cb264se30_device::device_timer(emu_timer &timer, device_timer_id tid,
uint32_t nubus_cb264se30_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[8*1024];
+ uint8_t const *const vram = &m_vram[8*1024];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0x80)];
*scanline++ = m_palette[((pixels<<1)&0x80)];
@@ -162,12 +161,12 @@ uint32_t nubus_cb264se30_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0xc0)];
*scanline++ = m_palette[((pixels<<2)&0xc0)];
@@ -178,13 +177,12 @@ uint32_t nubus_cb264se30_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0xf0)];
*scanline++ = m_palette[((pixels&0x0f)<<4)];
@@ -193,13 +191,12 @@ uint32_t nubus_cb264se30_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
@@ -207,17 +204,11 @@ uint32_t nubus_cb264se30_device::screen_update(screen_device &screen, bitmap_rgb
case 4: // 24 bpp
{
- uint32_t *vram32 = (uint32_t *)&m_vram[0];
- uint32_t *base;
+ uint32_t const *const vram32 = (uint32_t *)&m_vram[0];
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- base = &vram32[y * 1024];
- for (x = 0; x < 640; x++)
- {
- *scanline++ = *base++;
- }
+ std::copy_n(&vram32[y * 1024], 640, &bitmap.pix(y));
}
}
break;
diff --git a/src/devices/bus/nubus/pds30_mc30.cpp b/src/devices/bus/nubus/pds30_mc30.cpp
index 20969a5a6b7..87992723319 100644
--- a/src/devices/bus/nubus/pds30_mc30.cpp
+++ b/src/devices/bus/nubus/pds30_mc30.cpp
@@ -13,6 +13,9 @@
#include "pds30_mc30.h"
#include "screen.h"
+#include <algorithm>
+
+
#define XCEEDMC30_SCREEN_NAME "x30hr_screen"
#define XCEEDMC30_ROM_REGION "x30hr_rom"
@@ -135,41 +138,37 @@ void nubus_xceedmc30_device::device_timer(emu_timer &timer, device_timer_id tid,
uint32_t nubus_xceedmc30_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[4*1024];
+ uint8_t const *const vram = &m_vram[4*1024];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
-
- *scanline++ = m_palette[(pixels>>7)&1];
- *scanline++ = m_palette[(pixels>>6)&1];
- *scanline++ = m_palette[(pixels>>5)&1];
- *scanline++ = m_palette[(pixels>>4)&1];
- *scanline++ = m_palette[(pixels>>3)&1];
- *scanline++ = m_palette[(pixels>>2)&1];
- *scanline++ = m_palette[(pixels>>1)&1];
- *scanline++ = m_palette[pixels&1];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_palette[BIT(pixels, 7)];
+ *scanline++ = m_palette[BIT(pixels, 6)];
+ *scanline++ = m_palette[BIT(pixels, 5)];
+ *scanline++ = m_palette[BIT(pixels, 4)];
+ *scanline++ = m_palette[BIT(pixels, 3)];
+ *scanline++ = m_palette[BIT(pixels, 2)];
+ *scanline++ = m_palette[BIT(pixels, 1)];
+ *scanline++ = m_palette[BIT(pixels, 0)];
}
}
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[((pixels>>6)&3)];
*scanline++ = m_palette[((pixels>>4)&3)];
@@ -180,13 +179,13 @@ uint32_t nubus_xceedmc30_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
- for (x = 0; x < 640/2; x++)
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels>>4)];
*scanline++ = m_palette[(pixels&0xf)];
@@ -195,13 +194,13 @@ uint32_t nubus_xceedmc30_device::screen_update(screen_device &screen, bitmap_rgb
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
- for (x = 0; x < 640; x++)
+ for (int x = 0; x < 640; x++)
{
- pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 1024) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
@@ -209,17 +208,11 @@ uint32_t nubus_xceedmc30_device::screen_update(screen_device &screen, bitmap_rgb
case 4: // 24 bpp
{
- uint32_t *vram32 = (uint32_t *)vram;
- uint32_t *base;
+ uint32_t const *const vram32 = (uint32_t *)vram;
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- base = &vram32[y * 1024];
- for (x = 0; x < 640; x++)
- {
- *scanline++ = *base++;
- }
+ std::copy_n(&vram32[y * 1024], 640, &bitmap.pix(y));
}
}
break;
diff --git a/src/devices/bus/nubus/pds30_procolor816.cpp b/src/devices/bus/nubus/pds30_procolor816.cpp
index b251a57c33c..83fd8512704 100644
--- a/src/devices/bus/nubus/pds30_procolor816.cpp
+++ b/src/devices/bus/nubus/pds30_procolor816.cpp
@@ -139,21 +139,17 @@ void nubus_procolor816_device::device_timer(emu_timer &timer, device_timer_id ti
uint32_t nubus_procolor816_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
-
- vram = &m_vram[4];
+ uint8_t const *const vram = &m_vram[4];
switch (m_mode)
{
case 0: // 1 bpp?
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/8; x++)
{
- pixels = vram[(y * 640/8) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 640/8) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0x80)];
*scanline++ = m_palette[((pixels<<1)&0x80)];
@@ -168,12 +164,12 @@ uint32_t nubus_procolor816_device::screen_update(screen_device &screen, bitmap_r
break;
case 1: // 2 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640/4; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/4; x++)
{
- pixels = vram[(y * 640/4) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 640/4) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0xc0)];
*scanline++ = m_palette[((pixels<<2)&0xc0)];
@@ -184,13 +180,12 @@ uint32_t nubus_procolor816_device::screen_update(screen_device &screen, bitmap_r
break;
case 2: // 4 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640/2; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640/2; x++)
{
- pixels = vram[(y * 640/2) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 640/2) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0xf0)];
*scanline++ = m_palette[((pixels&0x0f)<<4)];
@@ -199,13 +194,12 @@ uint32_t nubus_procolor816_device::screen_update(screen_device &screen, bitmap_r
break;
case 3: // 8 bpp
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
-
- for (x = 0; x < 640; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640; x++)
{
- pixels = vram[(y * 640) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * 640) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[pixels];
}
}
@@ -213,16 +207,15 @@ uint32_t nubus_procolor816_device::screen_update(screen_device &screen, bitmap_r
case 4: // 15 bpp
{
- uint16_t *vram16 = (uint16_t *)&m_vram[0];
- uint16_t pixels;
+ uint16_t const *const vram16 = (uint16_t *)&m_vram[0];
- for (y = 0; y < 480; y++)
+ for (int y = 0; y < 480; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 640; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 640; x++)
{
- pixels = vram16[(y * 640) + (x^1)];
- *scanline++ = rgb_t(((pixels>>10) & 0x1f)<<3, ((pixels>>5) & 0x1f)<<3, (pixels & 0x1f)<<3);
+ uint16_t const pixels = vram16[(y * 640) + BYTE_XOR_BE(x)];
+ *scanline++ = rgb_t(pal5bit((pixels>>10) & 0x1f), pal5bit((pixels>>5) & 0x1f), pal5bit(pixels & 0x1f));
}
}
}
diff --git a/src/devices/bus/nubus/pds30_sigmalview.cpp b/src/devices/bus/nubus/pds30_sigmalview.cpp
index c509b908064..e04e4b2e297 100644
--- a/src/devices/bus/nubus/pds30_sigmalview.cpp
+++ b/src/devices/bus/nubus/pds30_sigmalview.cpp
@@ -132,18 +132,14 @@ void nubus_lview_device::device_timer(emu_timer &timer, device_timer_id tid, int
uint32_t nubus_lview_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels, *vram;
+ uint8_t const *const vram = &m_vram[0x20];
- vram = &m_vram[0x20];
-
- for (y = 0; y < 600; y++)
+ for (int y = 0; y < 600; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 832/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 832/8; x++)
{
- pixels = vram[(y * (832/8)) + (BYTE4_XOR_BE(x))];
+ uint8_t const pixels = vram[(y * (832/8)) + (BYTE4_XOR_BE(x))];
*scanline++ = m_palette[(pixels&0x80)];
*scanline++ = m_palette[((pixels<<1)&0x80)];
diff --git a/src/devices/bus/odyssey2/4in1.cpp b/src/devices/bus/odyssey2/4in1.cpp
index f0eefac089b..dfadbf2c1ab 100644
--- a/src/devices/bus/odyssey2/4in1.cpp
+++ b/src/devices/bus/odyssey2/4in1.cpp
@@ -22,7 +22,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_4IN1, o2_4in1_device, "o2_4in1", "Odyssey 2 Videopac 4
// o2_4in1_device - constructor
//-------------------------------------------------
-o2_4in1_device::o2_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_4in1_device::o2_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_4IN1, tag, owner, clock),
device_o2_cart_interface(mconfig, *this)
{ }
diff --git a/src/devices/bus/odyssey2/4in1.h b/src/devices/bus/odyssey2/4in1.h
index 09cfa626b38..2840361bfe0 100644
--- a/src/devices/bus/odyssey2/4in1.h
+++ b/src/devices/bus/odyssey2/4in1.h
@@ -21,7 +21,7 @@ class o2_4in1_device : public device_t,
{
public:
// construction/destruction
- o2_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_4in1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/chess.cpp b/src/devices/bus/odyssey2/chess.cpp
index f954ca93340..6ff1ff76dd2 100644
--- a/src/devices/bus/odyssey2/chess.cpp
+++ b/src/devices/bus/odyssey2/chess.cpp
@@ -21,7 +21,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_CHESS, o2_chess_device, "o2_chess", "Odyssey 2 Videopa
// o2_chess_device - constructor
//-------------------------------------------------
-o2_chess_device::o2_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_chess_device::o2_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_CHESS, tag, owner, clock),
device_o2_cart_interface(mconfig, *this),
m_maincpu(*this, "maincpu"),
diff --git a/src/devices/bus/odyssey2/chess.h b/src/devices/bus/odyssey2/chess.h
index d4e861e2a64..0b37c50684c 100644
--- a/src/devices/bus/odyssey2/chess.h
+++ b/src/devices/bus/odyssey2/chess.h
@@ -24,7 +24,7 @@ class o2_chess_device : public device_t,
{
public:
// construction/destruction
- o2_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_chess_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/homecomp.cpp b/src/devices/bus/odyssey2/homecomp.cpp
index 352d0f2a452..23c6f6c31f7 100644
--- a/src/devices/bus/odyssey2/homecomp.cpp
+++ b/src/devices/bus/odyssey2/homecomp.cpp
@@ -30,7 +30,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_HOMECOMP, o2_homecomp_device, "o2_homecomp", "Odyssey
// o2_homecomp_device - constructor
//-------------------------------------------------
-o2_homecomp_device::o2_homecomp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_homecomp_device::o2_homecomp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_HOMECOMP, tag, owner, clock),
device_o2_cart_interface(mconfig, *this),
m_maincpu(*this, "maincpu"),
diff --git a/src/devices/bus/odyssey2/homecomp.h b/src/devices/bus/odyssey2/homecomp.h
index f530cd36375..6ecc67f1184 100644
--- a/src/devices/bus/odyssey2/homecomp.h
+++ b/src/devices/bus/odyssey2/homecomp.h
@@ -25,7 +25,7 @@ class o2_homecomp_device : public device_t,
{
public:
// construction/destruction
- o2_homecomp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_homecomp_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/ktaa.cpp b/src/devices/bus/odyssey2/ktaa.cpp
index 24d62c81796..4f1fba25153 100644
--- a/src/devices/bus/odyssey2/ktaa.cpp
+++ b/src/devices/bus/odyssey2/ktaa.cpp
@@ -18,7 +18,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_KTAA, o2_ktaa_device, "o2_ktaa", "Odyssey 2 Homebrew K
// o2_ktaa_device - constructor
//-------------------------------------------------
-o2_ktaa_device::o2_ktaa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_ktaa_device::o2_ktaa_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_KTAA, tag, owner, clock),
device_o2_cart_interface(mconfig, *this)
{ }
diff --git a/src/devices/bus/odyssey2/ktaa.h b/src/devices/bus/odyssey2/ktaa.h
index e1ac477e445..53ce2296941 100644
--- a/src/devices/bus/odyssey2/ktaa.h
+++ b/src/devices/bus/odyssey2/ktaa.h
@@ -21,7 +21,7 @@ class o2_ktaa_device : public device_t,
{
public:
// construction/destruction
- o2_ktaa_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_ktaa_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/rally.cpp b/src/devices/bus/odyssey2/rally.cpp
index 7bdec3502b3..42dcdc0b26f 100644
--- a/src/devices/bus/odyssey2/rally.cpp
+++ b/src/devices/bus/odyssey2/rally.cpp
@@ -26,7 +26,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_RALLY, o2_rally_device, "o2_rally", "Odyssey 2 Videopa
// o2_rally_device - constructor
//-------------------------------------------------
-o2_rally_device::o2_rally_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_rally_device::o2_rally_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_RALLY, tag, owner, clock),
device_o2_cart_interface(mconfig, *this)
{ }
diff --git a/src/devices/bus/odyssey2/rally.h b/src/devices/bus/odyssey2/rally.h
index 81de2673ae6..8d359362dce 100644
--- a/src/devices/bus/odyssey2/rally.h
+++ b/src/devices/bus/odyssey2/rally.h
@@ -21,7 +21,7 @@ class o2_rally_device : public device_t,
{
public:
// construction/destruction
- o2_rally_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_rally_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/rom.cpp b/src/devices/bus/odyssey2/rom.cpp
index f54398914e3..12f8fa9b128 100644
--- a/src/devices/bus/odyssey2/rom.cpp
+++ b/src/devices/bus/odyssey2/rom.cpp
@@ -16,7 +16,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_STD, o2_rom_device, "o2_rom", "Odyssey 2 Standard Cart
// o2_rom_device - constructor
//-------------------------------------------------
-o2_rom_device::o2_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_rom_device::o2_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_STD, tag, owner, clock),
device_o2_cart_interface(mconfig, *this)
{ }
diff --git a/src/devices/bus/odyssey2/rom.h b/src/devices/bus/odyssey2/rom.h
index 74e742a38d8..204d96030ce 100644
--- a/src/devices/bus/odyssey2/rom.h
+++ b/src/devices/bus/odyssey2/rom.h
@@ -21,7 +21,7 @@ class o2_rom_device : public device_t,
{
public:
// construction/destruction
- o2_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/slot.cpp b/src/devices/bus/odyssey2/slot.cpp
index 2e020342366..5f0f30e2f35 100644
--- a/src/devices/bus/odyssey2/slot.cpp
+++ b/src/devices/bus/odyssey2/slot.cpp
@@ -50,7 +50,7 @@ device_o2_cart_interface::~device_o2_cart_interface()
//-------------------------------------------------
// o2_cart_slot_device - constructor
//-------------------------------------------------
-o2_cart_slot_device::o2_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+o2_cart_slot_device::o2_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, O2_CART_SLOT, tag, owner, clock)
, device_image_interface(mconfig, *this)
, device_single_card_slot_interface<device_o2_cart_interface>(mconfig, *this)
@@ -148,7 +148,7 @@ image_init_result o2_cart_slot_device::call_load()
}
else
{
- uint32_t size = length();
+ u32 size = length();
fread(m_cart->m_rom, size);
m_type = (size == 0x4000) ? O2_RALLY : O2_STD;
@@ -174,7 +174,7 @@ std::string o2_cart_slot_device::get_default_card_software(get_default_card_soft
if (hook.image_file())
{
const char *slot_string;
- uint32_t size = hook.image_file()->size();
+ u32 size = hook.image_file()->size();
int type = (size == 0x4000) ? O2_RALLY : O2_STD;
slot_string = o2_get_slot(type);
@@ -190,7 +190,7 @@ std::string o2_cart_slot_device::get_default_card_software(get_default_card_soft
read_rom**
-------------------------------------------------*/
-uint8_t o2_cart_slot_device::read_rom04(offs_t offset)
+u8 o2_cart_slot_device::read_rom04(offs_t offset)
{
if (m_cart)
return m_cart->read_rom04(offset);
@@ -198,7 +198,7 @@ uint8_t o2_cart_slot_device::read_rom04(offs_t offset)
return 0xff;
}
-uint8_t o2_cart_slot_device::read_rom0c(offs_t offset)
+u8 o2_cart_slot_device::read_rom0c(offs_t offset)
{
if (m_cart)
return m_cart->read_rom0c(offset);
@@ -210,13 +210,13 @@ uint8_t o2_cart_slot_device::read_rom0c(offs_t offset)
io
-------------------------------------------------*/
-void o2_cart_slot_device::io_write(offs_t offset, uint8_t data)
+void o2_cart_slot_device::io_write(offs_t offset, u8 data)
{
if (m_cart)
m_cart->io_write(offset, data);
}
-uint8_t o2_cart_slot_device::io_read(offs_t offset)
+u8 o2_cart_slot_device::io_read(offs_t offset)
{
if (m_cart)
return m_cart->io_read(offset);
diff --git a/src/devices/bus/odyssey2/slot.h b/src/devices/bus/odyssey2/slot.h
index 0717ce973f2..4c65fafe01e 100644
--- a/src/devices/bus/odyssey2/slot.h
+++ b/src/devices/bus/odyssey2/slot.h
@@ -37,30 +37,30 @@ public:
virtual ~device_o2_cart_interface();
// reading and writing
- virtual uint8_t read_rom04(offs_t offset) { return 0xff; }
- virtual uint8_t read_rom0c(offs_t offset) { return 0xff; }
- virtual void write_p1(uint8_t data) { }
- virtual void write_p2(uint8_t data) { }
+ virtual u8 read_rom04(offs_t offset) { return 0xff; }
+ virtual u8 read_rom0c(offs_t offset) { return 0xff; }
+ virtual void write_p1(u8 data) { }
+ virtual void write_p2(u8 data) { }
- virtual void io_write(offs_t offset, uint8_t data) { }
- virtual uint8_t io_read(offs_t offset) { return 0xff; }
+ virtual void io_write(offs_t offset, u8 data) { }
+ virtual u8 io_read(offs_t offset) { return 0xff; }
virtual DECLARE_READ_LINE_MEMBER(t0_read) { return 0; }
virtual int b_read() { return -1; }
virtual void cart_init() { } // called after loading ROM
- uint8_t* get_rom_base() { return m_rom ? &m_rom[0] : nullptr; }
- uint32_t get_rom_size() { return m_rom ? m_rom.bytes() : 0; }
+ u8* get_rom_base() { return m_rom ? &m_rom[0] : nullptr; }
+ u32 get_rom_size() { return m_rom ? m_rom.bytes() : 0; }
- uint8_t* get_voice_base() { return m_voice ? &m_voice[0] : nullptr; }
- uint32_t get_voice_size() { return m_voice ? m_voice.bytes() : 0; }
+ u8* get_voice_base() { return m_voice ? &m_voice[0] : nullptr; }
+ u32 get_voice_size() { return m_voice ? m_voice.bytes() : 0; }
protected:
device_o2_cart_interface(const machine_config &mconfig, device_t &device);
- optional_shared_ptr<uint8_t> m_rom;
- optional_shared_ptr<uint8_t> m_exrom;
- optional_shared_ptr<uint8_t> m_voice;
+ optional_shared_ptr<u8> m_rom;
+ optional_shared_ptr<u8> m_exrom;
+ optional_shared_ptr<u8> m_voice;
};
@@ -82,7 +82,7 @@ public:
set_fixed(false);
}
- o2_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+ o2_cart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual ~o2_cart_slot_device();
// image-level overrides
@@ -105,15 +105,15 @@ public:
device_o2_cart_interface* cart() { return m_cart; }
// reading and writing
- uint8_t read_rom04(offs_t offset);
- uint8_t read_rom0c(offs_t offset);
- void io_write(offs_t offset, uint8_t data);
- uint8_t io_read(offs_t offset);
+ u8 read_rom04(offs_t offset);
+ u8 read_rom0c(offs_t offset);
+ void io_write(offs_t offset, u8 data);
+ u8 io_read(offs_t offset);
DECLARE_READ_LINE_MEMBER(t0_read) { if (m_cart) return m_cart->t0_read(); else return 0; }
int b_read();
- void write_p1(uint8_t data) { if (m_cart) m_cart->write_p1(data); }
- void write_p2(uint8_t data) { if (m_cart) m_cart->write_p2(data); }
+ void write_p1(u8 data) { if (m_cart) m_cart->write_p1(data); }
+ void write_p2(u8 data) { if (m_cart) m_cart->write_p2(data); }
protected:
// device-level overrides
diff --git a/src/devices/bus/odyssey2/voice.cpp b/src/devices/bus/odyssey2/voice.cpp
index f741946dfa0..927b8fcc05e 100644
--- a/src/devices/bus/odyssey2/voice.cpp
+++ b/src/devices/bus/odyssey2/voice.cpp
@@ -24,7 +24,7 @@ DEFINE_DEVICE_TYPE(O2_ROM_VOICE, o2_voice_device, "o2_voice", "Odyssey 2 The Voi
// o2_voice_device - constructor
//-------------------------------------------------
-o2_voice_device::o2_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+o2_voice_device::o2_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, O2_ROM_VOICE, tag, owner, clock),
device_o2_cart_interface(mconfig, *this),
m_speech(*this, "speech"),
diff --git a/src/devices/bus/odyssey2/voice.h b/src/devices/bus/odyssey2/voice.h
index 829267fd439..b717334149a 100644
--- a/src/devices/bus/odyssey2/voice.h
+++ b/src/devices/bus/odyssey2/voice.h
@@ -22,7 +22,7 @@ class o2_voice_device : public device_t,
{
public:
// construction/destruction
- o2_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ o2_voice_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
virtual void cart_init() override;
diff --git a/src/devices/bus/s100/dg640.cpp b/src/devices/bus/s100/dg640.cpp
index 7f79983f17d..f6adb27cfa8 100644
--- a/src/devices/bus/s100/dg640.cpp
+++ b/src/devices/bus/s100/dg640.cpp
@@ -39,28 +39,26 @@ void dg640_device::device_start()
uint32_t dg640_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// attributes bit 0 = flash, bit 1 = lores. Also bit 7 of the character = reverse-video (text only).
- uint8_t y,ra,chr,gfx,attr,inv,gfxbit;
- uint16_t sy=0,ma=0,x;
- bool flash;
+ uint16_t sy=0,ma=0;
m_framecnt++;
- for (y = 0; y < 16; y++)
+ for (uint8_t y = 0; y < 16; y++)
{
- for (ra = 0; ra < 16; ra++)
+ for (uint8_t ra = 0; ra < 16; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 64; x++)
+ for (uint16_t x = ma; x < ma + 64; x++)
{
- attr = m_p_attribram[x];
- chr = m_p_videoram[x];
- flash = BIT(m_framecnt, 4) & BIT(attr, 0);
+ uint8_t attr = m_p_attribram[x];
+ uint8_t chr = m_p_videoram[x];
+ bool flash = BIT(m_framecnt, 4) & BIT(attr, 0);
if (BIT(attr, 1)) // lores gfx - can flash
{
if (flash) chr = 0; // blank part of flashing
- gfxbit = (ra & 0x0c)>>1;
+ uint8_t gfxbit = (ra & 0x0c) >> 1;
/* Display one line of a lores character (8 pixels) */
*p++ = BIT(chr, gfxbit);
*p++ = BIT(chr, gfxbit);
@@ -74,11 +72,11 @@ uint32_t dg640_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
else
{
- gfx = 0;
+ uint8_t gfx = 0;
if (!flash)
{
- inv = BIT(chr, 7) ? 0xff : 0; // text with bit 7 high is reversed
+ uint8_t inv = BIT(chr, 7) ? 0xff : 0; // text with bit 7 high is reversed
chr &= 0x7f;
gfx = inv;
diff --git a/src/devices/bus/s100/polyvti.cpp b/src/devices/bus/s100/polyvti.cpp
index 973e89c0693..242d13a8fe2 100644
--- a/src/devices/bus/s100/polyvti.cpp
+++ b/src/devices/bus/s100/polyvti.cpp
@@ -119,22 +119,22 @@ u32 poly_vti_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
{
u8 r = b/5;
if (l==0 && r==0)
- bitmap.pix16(y*15+j, xpos+b ) = BIT(code,5) ? 0 : 1;
+ bitmap.pix(y*15+j, xpos+b ) = BIT(code,5) ? 0 : 1;
if (l==0 && r==1)
- bitmap.pix16(y*15+j, xpos+b ) = BIT(code,2) ? 0 : 1;
+ bitmap.pix(y*15+j, xpos+b ) = BIT(code,2) ? 0 : 1;
if (l==1 && r==0)
- bitmap.pix16(y*15+j, xpos+b ) = BIT(code,4) ? 0 : 1;
+ bitmap.pix(y*15+j, xpos+b ) = BIT(code,4) ? 0 : 1;
if (l==1 && r==1)
- bitmap.pix16(y*15+j, xpos+b ) = BIT(code,1) ? 0 : 1;
+ bitmap.pix(y*15+j, xpos+b ) = BIT(code,1) ? 0 : 1;
if (l==2 && r==0)
- bitmap.pix16(y*15+j, xpos+b ) = BIT(code,3) ? 0 : 1;
+ bitmap.pix(y*15+j, xpos+b ) = BIT(code,3) ? 0 : 1;
if (l==2 && r==1)
- bitmap.pix16(y*15+j, xpos+b ) = BIT(code,0) ? 0 : 1;
+ bitmap.pix(y*15+j, xpos+b ) = BIT(code,0) ? 0 : 1;
}
}
}
@@ -156,11 +156,11 @@ u32 poly_vti_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
}
for (int b = 0; b < 7; b++)
- bitmap.pix16(y*15+j, xpos+b ) = (l >> (6-b)) & 1;
+ bitmap.pix(y*15+j, xpos+b ) = (l >> (6-b)) & 1;
- bitmap.pix16(y*15+j, xpos+7 ) = 0;
- bitmap.pix16(y*15+j, xpos+8 ) = 0;
- bitmap.pix16(y*15+j, xpos+9 ) = 0;
+ bitmap.pix(y*15+j, xpos+7 ) = 0;
+ bitmap.pix(y*15+j, xpos+8 ) = 0;
+ bitmap.pix(y*15+j, xpos+9 ) = 0;
}
}
xpos += 10;
diff --git a/src/devices/bus/sbus/bwtwo.cpp b/src/devices/bus/sbus/bwtwo.cpp
index 55d9f92b7b6..c034d43e05f 100644
--- a/src/devices/bus/sbus/bwtwo.cpp
+++ b/src/devices/bus/sbus/bwtwo.cpp
@@ -10,6 +10,9 @@
#include "bwtwo.h"
#include "screen.h"
+#include <algorithm>
+
+
DEFINE_DEVICE_TYPE(SBUS_BWTWO, sbus_bwtwo_device, "bwtwo", "Sun bwtwo SBus Video")
void sbus_bwtwo_device::mem_map(address_map &map)
@@ -72,14 +75,14 @@ void sbus_bwtwo_device::install_device()
uint32_t sbus_bwtwo_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t *line = &m_vram[0];
+ uint8_t const *line = &m_vram[0];
for (int y = 0; y < 900; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 1152/8; x++)
{
- memcpy(scanline, m_mono_lut[*line], sizeof(uint32_t) * 8);
+ std::copy_n(m_mono_lut[*line], 8, scanline);
line++;
scanline += 8;
}
diff --git a/src/devices/bus/sbus/cgsix.cpp b/src/devices/bus/sbus/cgsix.cpp
index 5d7bd715efd..65a24e1b505 100644
--- a/src/devices/bus/sbus/cgsix.cpp
+++ b/src/devices/bus/sbus/cgsix.cpp
@@ -171,12 +171,12 @@ void sbus_cgsix_device::device_reset()
uint32_t sbus_cgsix_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const pen_t *pens = m_ramdac->pens();
- uint8_t *vram = (uint8_t *)&m_vram[0];
+ pen_t const *const pens = m_ramdac->pens();
+ uint8_t const *const vram = (uint8_t *)&m_vram[0];
for (int16_t y = 0; y < 900; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
const bool cursor_row_hit = (y >= m_cursor_y && y < (m_cursor_y + 32));
for (int16_t x = 0; x < 1152; x++)
{
diff --git a/src/devices/bus/sbus/cgthree.cpp b/src/devices/bus/sbus/cgthree.cpp
index 5ffe6a885c5..ad0ba5c1467 100644
--- a/src/devices/bus/sbus/cgthree.cpp
+++ b/src/devices/bus/sbus/cgthree.cpp
@@ -67,12 +67,12 @@ void sbus_cgthree_device::install_device()
uint32_t sbus_cgthree_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const pen_t *pens = m_ramdac->pens();
- uint8_t *vram = (uint8_t *)&m_vram[0];
+ pen_t const *const pens = m_ramdac->pens();
+ uint8_t const *const vram = (uint8_t *)&m_vram[0];
for (int y = 0; y < 900; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 1152; x++)
{
const uint8_t pixel = vram[y * 1152 + BYTE4_XOR_BE(x)];
diff --git a/src/devices/bus/scsi/omti5100.cpp b/src/devices/bus/scsi/omti5100.cpp
index 519aa723a0b..f095dd2b191 100644
--- a/src/devices/bus/scsi/omti5100.cpp
+++ b/src/devices/bus/scsi/omti5100.cpp
@@ -15,7 +15,7 @@ DEFINE_DEVICE_TYPE(OMTI5100, omti5100_device, "omti5100", "OMTI 5100")
#if 0
ROM_START( omti5100 )
ROM_REGION(0x1000, "mcu", 0) // Hitachi Z8
- ROM_LOAD("100240-N.7a", 0x0000, 0x1000, CRC(d227d6cb) SHA1(3d6140764d3d043428c941826370ebf1597c63bd))
+ ROM_LOAD("100240-n.7a", 0x0000, 0x1000, CRC(d227d6cb) SHA1(3d6140764d3d043428c941826370ebf1597c63bd))
ROM_END
const tiny_rom_entry *omti5100_device::device_rom_region() const
diff --git a/src/devices/bus/svi3x8/slot/sv806.cpp b/src/devices/bus/svi3x8/slot/sv806.cpp
index bc4dafbd415..5a7d858d38b 100644
--- a/src/devices/bus/svi3x8/slot/sv806.cpp
+++ b/src/devices/bus/svi3x8/slot/sv806.cpp
@@ -94,7 +94,7 @@ void sv806_device::device_start()
MC6845_UPDATE_ROW( sv806_device::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
for (int i = 0; i < x_count; i++)
{
@@ -103,14 +103,14 @@ MC6845_UPDATE_ROW( sv806_device::crtc_update_row )
if (i == cursor_x)
data = 0xff;
- bitmap.pix32(y, i * 8 + 0) = pen[BIT(data, 7)];
- bitmap.pix32(y, i * 8 + 1) = pen[BIT(data, 6)];
- bitmap.pix32(y, i * 8 + 2) = pen[BIT(data, 5)];
- bitmap.pix32(y, i * 8 + 3) = pen[BIT(data, 4)];
- bitmap.pix32(y, i * 8 + 4) = pen[BIT(data, 3)];
- bitmap.pix32(y, i * 8 + 5) = pen[BIT(data, 2)];
- bitmap.pix32(y, i * 8 + 6) = pen[BIT(data, 1)];
- bitmap.pix32(y, i * 8 + 7) = pen[BIT(data, 0)];
+ bitmap.pix(y, i * 8 + 0) = pen[BIT(data, 7)];
+ bitmap.pix(y, i * 8 + 1) = pen[BIT(data, 6)];
+ bitmap.pix(y, i * 8 + 2) = pen[BIT(data, 5)];
+ bitmap.pix(y, i * 8 + 3) = pen[BIT(data, 4)];
+ bitmap.pix(y, i * 8 + 4) = pen[BIT(data, 3)];
+ bitmap.pix(y, i * 8 + 5) = pen[BIT(data, 2)];
+ bitmap.pix(y, i * 8 + 6) = pen[BIT(data, 1)];
+ bitmap.pix(y, i * 8 + 7) = pen[BIT(data, 0)];
}
}
diff --git a/src/devices/bus/tanbus/mpvdu.cpp b/src/devices/bus/tanbus/mpvdu.cpp
index e9f4fe766eb..28cd0b988f9 100644
--- a/src/devices/bus/tanbus/mpvdu.cpp
+++ b/src/devices/bus/tanbus/mpvdu.cpp
@@ -149,7 +149,7 @@ uint8_t tanbus_mpvdu_device::videoram_r(offs_t offset)
MC6845_UPDATE_ROW(tanbus_mpvdu_device::crtc_update_row)
{
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
m_trom->lose_w(1);
m_trom->lose_w(0);
@@ -165,11 +165,11 @@ MC6845_UPDATE_ROW(tanbus_mpvdu_device::crtc_update_row)
m_trom->tr6_w(1);
m_trom->tr6_w(0);
- int col = m_trom->get_rgb() ^ ((column == cursor_x) ? 7 : 0);
+ int const col = m_trom->get_rgb() ^ ((column == cursor_x) ? 7 : 0);
- int r = BIT(col, 0) * 0xff;
- int g = BIT(col, 1) * 0xff;
- int b = BIT(col, 2) * 0xff;
+ int const r = BIT(col, 0) * 0xff;
+ int const g = BIT(col, 1) * 0xff;
+ int const b = BIT(col, 2) * 0xff;
*p++ = rgb_t(r, g, b);
}
diff --git a/src/devices/bus/tanbus/ravdu.cpp b/src/devices/bus/tanbus/ravdu.cpp
index 80664797081..b93b1a41c35 100644
--- a/src/devices/bus/tanbus/ravdu.cpp
+++ b/src/devices/bus/tanbus/ravdu.cpp
@@ -161,7 +161,7 @@ uint8_t tanbus_ravdu_device::videoram_r(offs_t offset)
MC6845_UPDATE_ROW(tanbus_ravdu_device::crtc_update_row)
{
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
m_trom->lose_w(1);
m_trom->lose_w(0);
@@ -178,11 +178,11 @@ MC6845_UPDATE_ROW(tanbus_ravdu_device::crtc_update_row)
m_trom->tr6_w(1);
m_trom->tr6_w(0);
- int col = m_trom->get_rgb() ^ ((column == cursor_x) ? 7 : 0);
+ int const col = m_trom->get_rgb() ^ ((column == cursor_x) ? 7 : 0);
- int r = BIT(col, 0) * 0xff;
- int g = BIT(col, 1) * 0xff;
- int b = BIT(col, 2) * 0xff;
+ int const r = BIT(col, 0) * 0xff;
+ int const g = BIT(col, 1) * 0xff;
+ int const b = BIT(col, 2) * 0xff;
*p++ = rgb_t(r, g, b);
}
diff --git a/src/devices/bus/tanbus/tanhrg.cpp b/src/devices/bus/tanbus/tanhrg.cpp
index 1c8ffc87ab5..b857e84ac69 100644
--- a/src/devices/bus/tanbus/tanhrg.cpp
+++ b/src/devices/bus/tanbus/tanhrg.cpp
@@ -323,16 +323,13 @@ void tanbus_tanhrgc_device::set_inhibit_lines(offs_t offset, int &inhram, int &i
uint32_t tanbus_tanhrg_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint16_t offset;
- uint32_t *p;
-
for (int y = 0; y < 256; y++)
{
- p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
- offset = (y * 32) + (x / 8);
+ uint16_t const offset = (y * 32) + (x / 8);
*p++ = m_palette->pen_color(BIT(m_videoram[offset], x & 7));
}
@@ -344,21 +341,17 @@ uint32_t tanbus_tanhrg_device::screen_update(screen_device &screen, bitmap_rgb32
uint32_t tanbus_tanhrgc_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t r, g, b;
- uint16_t offset;
- uint32_t *p;
-
for (int y = 0; y < 256; y++)
{
- p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
- offset = (y * 32) + (x / 8);
+ uint16_t const offset = (y * 32) + (x / 8);
- r = m_videoram[0x0000 | offset];
- b = m_videoram[0x2000 | offset];
- g = m_videoram[0x4000 | offset];
+ uint8_t const r = m_videoram[0x0000 | offset];
+ uint8_t const b = m_videoram[0x2000 | offset];
+ uint8_t const g = m_videoram[0x4000 | offset];
*p++ = m_palette->pen_color(BIT(b, x & 7) << 2 | BIT(g, x & 7) << 1 | BIT(r, x & 7));
}
diff --git a/src/devices/bus/tanbus/tug8082.cpp b/src/devices/bus/tanbus/tug8082.cpp
index 1e4ad1a4504..582ab726c8e 100644
--- a/src/devices/bus/tanbus/tug8082.cpp
+++ b/src/devices/bus/tanbus/tug8082.cpp
@@ -241,18 +241,14 @@ WRITE_LINE_MEMBER(tanbus_tug8082_device::vdu_irq_w)
uint32_t tanbus_tug8082_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels;
+ pen_t const *const pen = m_palette->pens();
- const pen_t *pen = m_palette->pens();
-
- for (y = 0; y < 256; y++)
+ for (int y = 0; y < 256; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 64; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 64; x++)
{
- pixels = m_videoram[(y * 64) + x];
+ uint8_t const pixels = m_videoram[(y * 64) + x];
for (int i = 0; i < 8; ++i)
*scanline++ = pen[BIT(pixels, 7 - i)];
diff --git a/src/devices/bus/ti99/gromport/cartridges.cpp b/src/devices/bus/ti99/gromport/cartridges.cpp
index 6b2da977a2a..c703d331bf9 100644
--- a/src/devices/bus/ti99/gromport/cartridges.cpp
+++ b/src/devices/bus/ti99/gromport/cartridges.cpp
@@ -1558,13 +1558,13 @@ void ti99_cartridge_device::rpk::close()
not a network socket)
***************************************************************/
-ti99_cartridge_device::rpk_socket::rpk_socket(const char* id, int length, uint8_t* contents, std::string &&pathname)
- : m_id(id), m_length(length), m_contents(contents), m_pathname(std::move(pathname))
+ti99_cartridge_device::rpk_socket::rpk_socket(const char* id, int length, std::unique_ptr<uint8_t []> &&contents, std::string &&pathname)
+ : m_id(id), m_length(length), m_contents(std::move(contents)), m_pathname(std::move(pathname))
{
}
-ti99_cartridge_device::rpk_socket::rpk_socket(const char* id, int length, uint8_t* contents)
- : rpk_socket(id, length, contents, "")
+ti99_cartridge_device::rpk_socket::rpk_socket(const char* id, int length, std::unique_ptr<uint8_t []> &&contents)
+ : rpk_socket(id, length, std::move(contents), "")
{
}
@@ -1609,7 +1609,7 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
util::archive_file::error ziperr;
uint32_t crc;
int length;
- uint8_t* contents;
+ std::unique_ptr<uint8_t []> contents;
int header;
// find the file attribute (required)
@@ -1635,11 +1635,11 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
length = zip.current_uncompressed_length();
// Allocate storage
- contents = global_alloc_array_clear<uint8_t>(length);
- if (contents==nullptr) throw rpk_exception(RPK_OUT_OF_MEMORY);
+ try { contents = make_unique_clear<uint8_t []>(length); }
+ catch (std::bad_alloc const &) { throw rpk_exception(RPK_OUT_OF_MEMORY); }
// and unzip file from the zip file
- ziperr = zip.decompress(contents, length);
+ ziperr = zip.decompress(contents.get(), length);
if (ziperr != util::archive_file::error::NONE)
{
if (ziperr == util::archive_file::error::UNSUPPORTED) throw rpk_exception(RPK_ZIP_UNSUPPORTED);
@@ -1651,7 +1651,7 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
if (sha1 != nullptr)
{
util::hash_collection actual_hashes;
- actual_hashes.compute((const uint8_t *)contents, length, util::hash_collection::HASH_TYPES_CRC_SHA1);
+ actual_hashes.compute(contents.get(), length, util::hash_collection::HASH_TYPES_CRC_SHA1);
util::hash_collection expected_hashes;
expected_hashes.add_from_string(util::hash_collection::HASH_SHA1, sha1, strlen(sha1));
@@ -1660,7 +1660,7 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
}
// Create a socket instance
- return std::make_unique<rpk_socket>(socketname, length, contents);
+ return std::make_unique<rpk_socket>(socketname, length, std::move(contents));
}
/*
@@ -1673,7 +1673,7 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
const char* ram_filename;
std::string ram_pname;
unsigned int length;
- uint8_t* contents;
+ std::unique_ptr<uint8_t []> contents;
// find the length attribute
length_string = ram_resource_node->get_attribute_string("length", nullptr);
@@ -1701,8 +1701,8 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
}
// Allocate memory for this resource
- contents = global_alloc_array_clear<uint8_t>(length);
- if (contents==nullptr) throw rpk_exception(RPK_OUT_OF_MEMORY);
+ try { contents = make_unique_clear<uint8_t []>(length); }
+ catch (std::bad_alloc const &) { throw rpk_exception(RPK_OUT_OF_MEMORY); }
LOGMASKED(LOG_RPK, "[RPK handler] Allocating RAM buffer (%d bytes) for socket '%s'\n", length, socketname);
@@ -1717,10 +1717,8 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
// Get the file name (required if persistent)
ram_filename = ram_resource_node->get_attribute_string("file", nullptr);
if (ram_filename==nullptr)
- {
- global_free_array(contents);
throw rpk_exception(RPK_INVALID_RAM_SPEC, "<ram type='persistent'> must have a 'file' attribute");
- }
+
ram_pname = std::string(system_name).append(PATH_SEPARATOR).append(ram_filename);
// load, and fill rest with 00
LOGMASKED(LOG_RPK, "[RPK handler] Loading NVRAM contents from '%s'\n", ram_pname.c_str());
@@ -1734,15 +1732,15 @@ std::unique_ptr<ti99_cartridge_device::rpk_socket> ti99_cartridge_device::rpk_re
osd_file::error filerr = file.open(ram_pname);
int bytes_read = 0;
if (filerr == osd_file::error::NONE)
- bytes_read = file.read(contents, length);
+ bytes_read = file.read(contents.get(), length);
// fill remaining bytes (if necessary)
- memset(((char *) contents) + bytes_read, 0x00, length - bytes_read);
+ std::fill_n(&contents[bytes_read], length - bytes_read, 0x00);
}
}
// Create a socket instance
- return std::make_unique<rpk_socket>(socketname, length, contents, std::move(ram_pname));
+ return std::make_unique<rpk_socket>(socketname, length, std::move(contents), std::move(ram_pname));
}
/*-------------------------------------------------
diff --git a/src/devices/bus/ti99/gromport/cartridges.h b/src/devices/bus/ti99/gromport/cartridges.h
index b494ad7e28d..f6e2e991d56 100644
--- a/src/devices/bus/ti99/gromport/cartridges.h
+++ b/src/devices/bus/ti99/gromport/cartridges.h
@@ -170,21 +170,21 @@ private:
class rpk_socket
{
public:
- rpk_socket(const char *id, int length, uint8_t *contents);
- rpk_socket(const char *id, int length, uint8_t *contents, std::string &&pathname);
+ rpk_socket(const char *id, int length, std::unique_ptr<uint8_t []> &&contents);
+ rpk_socket(const char *id, int length, std::unique_ptr<uint8_t []> &&contents, std::string &&pathname);
~rpk_socket() {}
const char* id() { return m_id; }
int get_content_length() { return m_length; }
- uint8_t* get_contents() { return m_contents; }
+ uint8_t* get_contents() { return m_contents.get(); }
bool persistent_ram() { return !m_pathname.empty(); }
const char* get_pathname() { return m_pathname.c_str(); }
- void cleanup() { if (m_contents != nullptr) global_free_array(m_contents); }
+ void cleanup() { m_contents.reset(); }
private:
const char* m_id;
uint32_t m_length;
- uint8_t* m_contents;
+ std::unique_ptr<uint8_t []> m_contents;
const std::string m_pathname;
};
diff --git a/src/devices/bus/ti99/internal/992board.cpp b/src/devices/bus/ti99/internal/992board.cpp
index 031f82d7fe5..2f01c025cb6 100644
--- a/src/devices/bus/ti99/internal/992board.cpp
+++ b/src/devices/bus/ti99/internal/992board.cpp
@@ -202,7 +202,7 @@ void video992_device::device_timer(emu_timer &timer, device_timer_id id, int par
}
int vpos = raw_vpos * m_vertical_size / screen().height();
- uint32_t *p = &m_tmpbmp.pix32(vpos);
+ uint32_t *p = &m_tmpbmp.pix(vpos);
bool endofline = false;
int linelength = 0;
diff --git a/src/devices/bus/ti99/peb/horizon.cpp b/src/devices/bus/ti99/peb/horizon.cpp
index 6da8483a046..8d9aa8dd20a 100644
--- a/src/devices/bus/ti99/peb/horizon.cpp
+++ b/src/devices/bus/ti99/peb/horizon.cpp
@@ -121,24 +121,22 @@ void horizon_ramdisk_device::nvram_read(emu_file &file)
int size = 2097152*(1 << ioport("HORIZONSIZE")->read());
// NVRAM plus ROS
- uint8_t* buffer = global_alloc_array_clear<uint8_t>(MAXSIZE + ROSSIZE);
+ auto buffer = make_unique_clear<uint8_t []>(MAXSIZE + ROSSIZE);
memset(m_nvram->pointer(), 0, size);
memset(m_ros->pointer(), 0, ROSSIZE);
// We assume the last 8K is ROS
- int filesize = file.read(buffer, MAXSIZE+ROSSIZE);
+ int filesize = file.read(&buffer[0], MAXSIZE+ROSSIZE);
int nvramsize = filesize - ROSSIZE;
// If there is a reasonable size
if (nvramsize >= 0)
{
// Copy from buffer to NVRAM and ROS
- memcpy(m_nvram->pointer(), buffer, nvramsize);
- memcpy(m_ros->pointer(), buffer + nvramsize, ROSSIZE);
+ memcpy(m_nvram->pointer(), &buffer[0], nvramsize);
+ memcpy(m_ros->pointer(), &buffer[nvramsize], ROSSIZE);
}
-
- global_free_array(buffer);
}
//-------------------------------------------------
@@ -150,11 +148,11 @@ void horizon_ramdisk_device::nvram_write(emu_file &file)
{
int nvramsize = 2097152*(1 << ioport("HORIZONSIZE")->read());
- uint8_t* buffer = global_alloc_array_clear<uint8_t>(nvramsize + ROSSIZE);
- memcpy(buffer, m_nvram->pointer(), nvramsize);
- memcpy(buffer + nvramsize, m_ros->pointer(), ROSSIZE);
+ auto buffer = make_unique_clear<uint8_t []>(nvramsize + ROSSIZE);
+ memcpy(&buffer[0], m_nvram->pointer(), nvramsize);
+ memcpy(&buffer[nvramsize], m_ros->pointer(), ROSSIZE);
- file.write(buffer, nvramsize + ROSSIZE);
+ file.write(buffer.get(), nvramsize + ROSSIZE);
}
void horizon_ramdisk_device::readz(offs_t offset, uint8_t *value)
diff --git a/src/devices/bus/vic20/videopak.cpp b/src/devices/bus/vic20/videopak.cpp
index 187224721be..1f2b3c35431 100644
--- a/src/devices/bus/vic20/videopak.cpp
+++ b/src/devices/bus/vic20/videopak.cpp
@@ -77,7 +77,7 @@ MC6845_UPDATE_ROW( vic20_video_pak_device::crtc_update_row )
int x = (column * 8) + bit;
int color = BIT(data, 7) && de;
- bitmap.pix32(vbp + y, hbp + x) = pen[color];
+ bitmap.pix(vbp + y, hbp + x) = pen[color];
data <<= 1;
}
diff --git a/src/devices/bus/vsmile/mat.cpp b/src/devices/bus/vsmile/mat.cpp
new file mode 100644
index 00000000000..6dfeac5be98
--- /dev/null
+++ b/src/devices/bus/vsmile/mat.cpp
@@ -0,0 +1,198 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz, Vas Crabb
+
+#include "emu.h"
+#include "mat.h"
+
+#include <algorithm>
+
+//#define VERBOSE 1
+#include "logmacro.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(VSMILE_MAT, vsmile_mat_device, "vsmile_mat", "V.Smile Gym Mat")
+
+
+//**************************************************************************
+// V.Smile gym mat
+//**************************************************************************
+
+vsmile_mat_device::vsmile_mat_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
+ : vsmile_pad_device(mconfig, VSMILE_MAT, tag, owner, clock)
+ , m_io_joy(*this, "JOY")
+ , m_io_colors(*this, "COLORS")
+ , m_io_buttons(*this, "BUTTONS")
+{
+}
+
+vsmile_mat_device::~vsmile_mat_device()
+{
+}
+
+void vsmile_mat_device::tx_complete()
+{
+ // update "joystick"-mapped mat pads
+ if ((m_stale & STALE_JOY) != STALE_NONE)
+ {
+ m_sent_joy = m_io_joy->read();
+ if ((m_stale & STALE_YELLOW_RIGHT) != STALE_NONE)
+ {
+ if (BIT(m_sent_joy, 0))
+ uart_tx_fifo_push(0xcb); // yellow
+ else if (BIT(m_sent_joy, 1))
+ uart_tx_fifo_push(0xcd); // right
+ else
+ uart_tx_fifo_push(0xc0);
+ }
+ if ((m_stale & STALE_RED_LEFT) != STALE_NONE)
+ {
+ if (BIT(m_sent_joy, 2))
+ uart_tx_fifo_push(0x8b); // red
+ else if (BIT(m_sent_joy, 3))
+ uart_tx_fifo_push(0x8d); // left
+ else
+ uart_tx_fifo_push(0x80);
+ }
+ }
+
+ // update "color"-mapped mat pads
+ if ((m_stale & STALE_COLORS) != STALE_NONE)
+ {
+ m_sent_colors = m_io_colors->read();
+ uart_tx_fifo_push(0x90 | m_sent_colors);
+ }
+
+ // update "button"-mapped mat pads
+ if ((m_stale & STALE_BUTTONS) != STALE_NONE)
+ {
+ m_sent_buttons = m_io_buttons->read();
+ if (((m_stale & STALE_OK) != STALE_NONE) && BIT(m_sent_buttons, 0))
+ uart_tx_fifo_push(0xa1);
+ if (((m_stale & STALE_QUIT) != STALE_NONE) && BIT(m_sent_buttons, 1))
+ uart_tx_fifo_push(0xa2);
+ if (((m_stale & STALE_HELP) != STALE_NONE) && BIT(m_sent_buttons, 2))
+ uart_tx_fifo_push(0xa3);
+ if (((m_stale & STALE_BLUE) != STALE_NONE) && BIT(m_sent_buttons, 3))
+ uart_tx_fifo_push(0xa4);
+ if (!m_sent_buttons)
+ uart_tx_fifo_push(0xa0);
+ }
+
+ // if nothing happens in the next second we'll queue a keep-alive
+ if (!m_active)
+ LOG("entered active state\n");
+ m_idle_timer->adjust(attotime::from_seconds(1));
+ m_active = true;
+ m_stale = STALE_NONE;
+}
+
+INPUT_CHANGED_MEMBER(vsmile_mat_device::mat_joy_changed)
+{
+ if (m_active)
+ {
+ if (!is_tx_empty())
+ {
+ LOG("joy changed while transmission in progress, marking stale\n");
+ m_stale |= stale_mat_inputs(param);
+ }
+ else
+ {
+ uint8_t const joy = m_io_joy->read();
+ if ((joy ^ m_sent_joy) & 0x03)
+ {
+ if (BIT(joy, 0))
+ uart_tx_fifo_push(0xcb); // yellow
+ else if (BIT(joy, 1))
+ uart_tx_fifo_push(0xcd); // right
+ else
+ uart_tx_fifo_push(0xc0);
+ }
+ if ((joy ^ m_sent_joy) & 0x0c)
+ {
+ if (BIT(joy, 2))
+ uart_tx_fifo_push(0x8b); // red
+ else if (BIT(joy, 3))
+ uart_tx_fifo_push(0x8d); // left
+ else
+ uart_tx_fifo_push(0x80);
+ }
+ m_sent_joy = joy;
+ }
+ }
+}
+
+INPUT_CHANGED_MEMBER(vsmile_mat_device::mat_color_changed)
+{
+ if (m_active)
+ {
+ if (!is_tx_empty())
+ {
+ LOG("colors changed while transmission in progress, marking stale\n");
+ m_stale |= STALE_COLORS;
+ }
+ else
+ {
+ m_sent_colors = m_io_colors->read();
+ uart_tx_fifo_push(0x90 | m_sent_colors);
+ }
+ }
+}
+
+INPUT_CHANGED_MEMBER(vsmile_mat_device::mat_button_changed)
+{
+ if (m_active)
+ {
+ if (!is_tx_empty())
+ {
+ LOG("buttons changed while transmission in progress, marking stale\n");
+ m_stale |= stale_mat_inputs(param);
+ }
+ else
+ {
+ uint8_t const buttons = m_io_buttons->read();
+ if (BIT((m_sent_buttons ^ buttons) & buttons, 0))
+ uart_tx_fifo_push(0xa1);
+ if (BIT((m_sent_buttons ^ buttons) & buttons, 1))
+ uart_tx_fifo_push(0xa2);
+ if (BIT((m_sent_buttons ^ buttons) & buttons, 2))
+ uart_tx_fifo_push(0xa3);
+ if (BIT((m_sent_buttons ^ buttons) & buttons, 3))
+ uart_tx_fifo_push(0xa4);
+ if (!buttons)
+ uart_tx_fifo_push(0xa0);
+ m_sent_buttons = buttons;
+ }
+ }
+}
+
+static INPUT_PORTS_START( vsmile_mat )
+ PORT_START("JOY")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CODE(KEYCODE_9_PAD) PORT_CODE(JOYCODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_joy_changed, vsmile_mat_device::STALE_YELLOW_RIGHT) PORT_NAME("Yellow")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CODE(KEYCODE_6_PAD) PORT_CODE(JOYCODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_joy_changed, vsmile_mat_device::STALE_YELLOW_RIGHT) PORT_NAME("Right")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CODE(KEYCODE_7_PAD) PORT_CODE(JOYCODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_joy_changed, vsmile_mat_device::STALE_RED_LEFT) PORT_NAME("Red")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_CODE(KEYCODE_4_PAD) PORT_CODE(JOYCODE_BUTTON4) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_joy_changed, vsmile_mat_device::STALE_RED_LEFT) PORT_NAME("Left")
+ PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("COLORS")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_CODE(KEYCODE_5_PAD) PORT_CODE(JOYCODE_BUTTON5) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_color_changed, vsmile_mat_device::STALE_COLORS) PORT_NAME("Center")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_CODE(KEYCODE_8_PAD) PORT_CODE(JOYCODE_BUTTON6) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_color_changed, vsmile_mat_device::STALE_COLORS) PORT_NAME("Up")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON7 ) PORT_CODE(KEYCODE_2_PAD) PORT_CODE(JOYCODE_BUTTON7) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_color_changed, vsmile_mat_device::STALE_COLORS) PORT_NAME("Down")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON8 ) PORT_CODE(KEYCODE_3_PAD) PORT_CODE(JOYCODE_BUTTON8) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_color_changed, vsmile_mat_device::STALE_COLORS) PORT_NAME("Green")
+ PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("BUTTONS")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON9 ) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CODE(JOYCODE_BUTTON9) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_button_changed, vsmile_mat_device::STALE_OK) PORT_NAME("OK")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON10 ) PORT_CODE(KEYCODE_0_PAD) PORT_CODE(JOYCODE_BUTTON10) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_button_changed, vsmile_mat_device::STALE_QUIT) PORT_NAME("Quit")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON11 ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CODE(JOYCODE_BUTTON11) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_button_changed, vsmile_mat_device::STALE_HELP) PORT_NAME("Help")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON12 ) PORT_CODE(KEYCODE_1_PAD) PORT_CODE(JOYCODE_BUTTON12) PORT_CHANGED_MEMBER(DEVICE_SELF, vsmile_mat_device, mat_button_changed, vsmile_mat_device::STALE_BLUE) PORT_NAME("Blue")
+ PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED )
+INPUT_PORTS_END
+
+ioport_constructor vsmile_mat_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( vsmile_mat );
+}
diff --git a/src/devices/bus/vsmile/mat.h b/src/devices/bus/vsmile/mat.h
new file mode 100644
index 00000000000..e184b6b3d25
--- /dev/null
+++ b/src/devices/bus/vsmile/mat.h
@@ -0,0 +1,69 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz, Vas Crabb
+#ifndef MAME_BUS_VSMILE_MAT_H
+#define MAME_BUS_VSMILE_MAT_H
+
+#pragma once
+
+#include "pad.h"
+
+/***************************************************************************
+ TYPE DEFINITIONS
+ ***************************************************************************/
+
+// ======================> vsmile_mat_device
+
+class vsmile_mat_device : public vsmile_pad_device
+{
+public:
+ // construction/destruction
+ vsmile_mat_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U);
+ virtual ~vsmile_mat_device();
+
+ // input handlers
+ DECLARE_INPUT_CHANGED_MEMBER(mat_joy_changed);
+ DECLARE_INPUT_CHANGED_MEMBER(mat_color_changed);
+ DECLARE_INPUT_CHANGED_MEMBER(mat_button_changed);
+
+ enum stale_mat_inputs : uint16_t
+ {
+ STALE_NONE = 0U,
+ STALE_YELLOW_RIGHT = 1U << 0,
+ STALE_RED_LEFT = 1U << 1,
+ STALE_CENTER = 1U << 2,
+ STALE_UP = 1U << 3,
+ STALE_DOWN = 1U << 4,
+ STALE_GREEN = 1U << 5,
+ STALE_OK = 1U << 6,
+ STALE_QUIT = 1U << 7,
+ STALE_HELP = 1U << 8,
+ STALE_BLUE = 1U << 9,
+
+ STALE_JOY = STALE_YELLOW_RIGHT | STALE_RED_LEFT,
+ STALE_COLORS = STALE_CENTER | STALE_UP | STALE_DOWN | STALE_GREEN,
+ STALE_BUTTONS = STALE_OK | STALE_QUIT | STALE_HELP | STALE_BLUE,
+ STALE_ALL = STALE_JOY | STALE_COLORS | STALE_BUTTONS
+ };
+
+protected:
+ // device_t implementation
+ virtual ioport_constructor device_input_ports() const override;
+
+ // vsmile_pad_device implementation
+ virtual void tx_complete() override;
+ virtual uint16_t stale_all() override { return STALE_ALL; }
+
+private:
+ required_ioport m_io_joy;
+ required_ioport m_io_colors;
+ required_ioport m_io_buttons;
+};
+
+
+/***************************************************************************
+ DEVICE TYPES
+ ***************************************************************************/
+
+DECLARE_DEVICE_TYPE(VSMILE_MAT, vsmile_mat_device)
+
+#endif // MAME_BUS_VSMILE_MAT_H
diff --git a/src/devices/bus/vsmile/pad.cpp b/src/devices/bus/vsmile/pad.cpp
index 94c7decdaa9..5cf7940ab39 100644
--- a/src/devices/bus/vsmile/pad.cpp
+++ b/src/devices/bus/vsmile/pad.cpp
@@ -21,22 +21,24 @@ DEFINE_DEVICE_TYPE(VSMILE_PAD, vsmile_pad_device, "vsmile_pad", "V.Smile Joystic
// V.Smile control pad
//**************************************************************************
-DECLARE_ENUM_BITWISE_OPERATORS(vsmile_pad_device::stale_inputs)
-ALLOW_SAVE_TYPE(vsmile_pad_device::stale_inputs);
-
vsmile_pad_device::vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
- : vsmile_ctrl_device_base(mconfig, VSMILE_PAD, tag, owner, clock)
+ : vsmile_pad_device(mconfig, VSMILE_PAD, tag, owner, clock)
+{
+}
+
+vsmile_pad_device::vsmile_pad_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, uint32_t clock)
+ : vsmile_ctrl_device_base(mconfig, type, tag, owner, clock)
, m_io_joy(*this, "JOY")
, m_io_colors(*this, "COLORS")
, m_io_buttons(*this, "BUTTONS")
- , m_idle_timer(nullptr)
- , m_sent_joy(0x00U)
- , m_sent_colors(0x00U)
- , m_sent_buttons(0x00U)
- , m_stale(STALE_ALL)
+ , m_sent_joy(0x0000U)
+ , m_sent_colors(0x0000U)
+ , m_sent_buttons(0x0000U)
, m_active(false)
+ , m_idle_timer(nullptr)
{
std::fill(std::begin(m_ctrl_probe_history), std::end(m_ctrl_probe_history), 0U);
+ m_stale = stale_all();
}
vsmile_pad_device::~vsmile_pad_device()
@@ -51,10 +53,10 @@ void vsmile_pad_device::device_start()
timer_expired_delegate(FUNC(vsmile_pad_device::handle_idle), this));
m_idle_timer->adjust(attotime::from_seconds(1));
- m_sent_joy = 0x00U;
- m_sent_colors = 0x00U;
- m_sent_buttons = 0x00U;
- m_stale = STALE_ALL;
+ m_sent_joy = 0x0000U;
+ m_sent_colors = 0x0000U;
+ m_sent_buttons = 0x0000U;
+ m_stale = stale_all();
m_active = false;
save_item(NAME(m_sent_joy));
@@ -128,7 +130,7 @@ void vsmile_pad_device::tx_timeout()
{
m_idle_timer->reset();
m_active = false;
- m_stale = STALE_ALL;
+ m_stale = stale_all();
std::fill(std::begin(m_ctrl_probe_history), std::end(m_ctrl_probe_history), 0U);
LOG("left active state\n");
}
@@ -174,7 +176,7 @@ INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_joy_changed)
if (!is_tx_empty())
{
LOG("joy changed while transmission in progress, marking stale\n");
- m_stale |= stale_inputs(param);
+ m_stale |= stale_pad_inputs(param);
}
else
{
@@ -226,7 +228,7 @@ INPUT_CHANGED_MEMBER(vsmile_pad_device::pad_button_changed)
if (!is_tx_empty())
{
LOG("buttons changed while transmission in progress, marking stale\n");
- m_stale |= stale_inputs(param);
+ m_stale |= stale_pad_inputs(param);
}
else
{
diff --git a/src/devices/bus/vsmile/pad.h b/src/devices/bus/vsmile/pad.h
index 5e2515c2b58..bdf896b7646 100644
--- a/src/devices/bus/vsmile/pad.h
+++ b/src/devices/bus/vsmile/pad.h
@@ -16,7 +16,16 @@
class vsmile_pad_device : public vsmile_ctrl_device_base
{
public:
- enum stale_inputs : uint8_t
+ // construction/destruction
+ vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U);
+ virtual ~vsmile_pad_device();
+
+ // input handlers
+ DECLARE_INPUT_CHANGED_MEMBER(pad_joy_changed);
+ DECLARE_INPUT_CHANGED_MEMBER(pad_color_changed);
+ DECLARE_INPUT_CHANGED_MEMBER(pad_button_changed);
+
+ enum stale_pad_inputs : uint16_t
{
STALE_NONE = 0U,
STALE_LEFT_RIGHT = 1U << 0,
@@ -32,16 +41,9 @@ public:
STALE_ALL = STALE_JOY | STALE_COLORS | STALE_BUTTONS
};
- // construction/destruction
- vsmile_pad_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0U);
- virtual ~vsmile_pad_device();
-
- // input handlers
- DECLARE_INPUT_CHANGED_MEMBER(pad_joy_changed);
- DECLARE_INPUT_CHANGED_MEMBER(pad_color_changed);
- DECLARE_INPUT_CHANGED_MEMBER(pad_button_changed);
-
protected:
+ vsmile_pad_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, uint32_t clock = 0U);
+
// device_t implementation
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
@@ -50,21 +52,23 @@ protected:
virtual void tx_complete() override;
virtual void tx_timeout() override;
virtual void rx_complete(uint8_t data, bool cts) override;
+ virtual uint16_t stale_all() { return STALE_ALL; }
-private:
void uart_tx_fifo_push(uint8_t data);
- TIMER_CALLBACK_MEMBER(handle_idle);
-
required_ioport m_io_joy;
required_ioport m_io_colors;
required_ioport m_io_buttons;
- emu_timer *m_idle_timer;
+ uint16_t m_sent_joy, m_sent_colors, m_sent_buttons;
- uint8_t m_sent_joy, m_sent_colors, m_sent_buttons;
- stale_inputs m_stale;
+ uint16_t m_stale;
bool m_active;
+ emu_timer *m_idle_timer;
+
+private:
+ TIMER_CALLBACK_MEMBER(handle_idle);
+
uint8_t m_ctrl_probe_history[2];
};
diff --git a/src/devices/bus/vsmile/rom.cpp b/src/devices/bus/vsmile/rom.cpp
index ca2780a2725..bc69099d698 100644
--- a/src/devices/bus/vsmile/rom.cpp
+++ b/src/devices/bus/vsmile/rom.cpp
@@ -52,7 +52,7 @@ void vsmile_rom_device::device_start()
save_item(NAME(m_bank_offset));
}
-void vsmile_rom_device::device_reset()
+void vsmile_rom_device::device_resolve_objects()
{
m_bank_offset = 0;
}
diff --git a/src/devices/bus/vsmile/rom.h b/src/devices/bus/vsmile/rom.h
index 617d1ad6ecd..b9ac8ef0b07 100644
--- a/src/devices/bus/vsmile/rom.h
+++ b/src/devices/bus/vsmile/rom.h
@@ -29,7 +29,7 @@ protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_reset() override;
+ virtual void device_resolve_objects() override;
uint32_t m_bank_offset;
};
diff --git a/src/devices/bus/vsmile/vsmile_ctrl.cpp b/src/devices/bus/vsmile/vsmile_ctrl.cpp
index e3ae106bd3a..4b9d629aaaf 100644
--- a/src/devices/bus/vsmile/vsmile_ctrl.cpp
+++ b/src/devices/bus/vsmile/vsmile_ctrl.cpp
@@ -277,8 +277,10 @@ TIMER_CALLBACK_MEMBER(vsmile_ctrl_device_base::rts_timer_expired)
#include "pad.h"
+#include "mat.h"
void vsmile_controllers(device_slot_interface &device)
{
device.option_add("joy", VSMILE_PAD);
+ device.option_add("mat", VSMILE_MAT);
}
diff --git a/src/devices/bus/wangpc/lvc.cpp b/src/devices/bus/wangpc/lvc.cpp
index 4d31a7b9367..1fd3c0610d4 100644
--- a/src/devices/bus/wangpc/lvc.cpp
+++ b/src/devices/bus/wangpc/lvc.cpp
@@ -62,17 +62,17 @@ MC6845_UPDATE_ROW( wangpc_lvc_device::crtc_update_row )
{
for (int column = 0; column < x_count; column++)
{
- offs_t addr = scroll_y + (m_scroll & 0x3f) + ((ma / 80) * 0x480) + (((ra & 0x0f) << 7) | (column & 0x7f));
+ offs_t const addr = scroll_y + (m_scroll & 0x3f) + ((ma / 80) * 0x480) + (((ra & 0x0f) << 7) | (column & 0x7f));
uint16_t data = m_video_ram[addr & 0x7fff];
for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
+ int const x = (column * 8) + bit;
int color = (BIT(data, 15) << 1) | BIT(data, 7);
if (column == cursor_x) color = 0x03;
- bitmap.pix32(vbp + y, hbp + x) = de ? m_palette[color] : rgb_t::black();
+ bitmap.pix(vbp + y, hbp + x) = de ? m_palette[color] : rgb_t::black();
data <<= 1;
}
@@ -89,12 +89,12 @@ MC6845_UPDATE_ROW( wangpc_lvc_device::crtc_update_row )
for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
+ int const x = (column * 8) + bit;
int color = (BIT(data, 31) << 3) | (BIT(data, 23) << 2) | (BIT(data, 15) << 1) | BIT(data, 7);
if (column == cursor_x) color = 0x03;
- bitmap.pix32(vbp + y, hbp + x) = de ? m_palette[color] : rgb_t::black();
+ bitmap.pix(vbp + y, hbp + x) = de ? m_palette[color] : rgb_t::black();
data <<= 1;
}
diff --git a/src/devices/bus/wangpc/mvc.cpp b/src/devices/bus/wangpc/mvc.cpp
index 562e277f982..cff515a05c1 100644
--- a/src/devices/bus/wangpc/mvc.cpp
+++ b/src/devices/bus/wangpc/mvc.cpp
@@ -73,15 +73,15 @@ MC6845_UPDATE_ROW( wangpc_mvc_device::crtc_update_row )
{
for (int sx = 0; sx < 50; sx++)
{
- offs_t addr = (y * 50) + sx;
+ offs_t const addr = (y * 50) + sx;
uint16_t data = m_bitmap_ram[addr];
for (int bit = 0; bit < 16; bit++)
{
- int x = (sx * 16) + bit;
- int color = BIT(data, 15) && de;
+ int const x = (sx * 16) + bit;
+ int const color = BIT(data, 15) && de;
- bitmap.pix32(vbp + y, hbp + x) = PALETTE_MVC[color];
+ bitmap.pix(vbp + y, hbp + x) = PALETTE_MVC[color];
data <<= 1;
}
@@ -89,8 +89,8 @@ MC6845_UPDATE_ROW( wangpc_mvc_device::crtc_update_row )
for (int column = 0; column < x_count; column++)
{
- uint16_t code = m_video_ram[((ma + column) & 0x7ff)];
- uint8_t attr = code & 0xff;
+ uint16_t const code = m_video_ram[((ma + column) & 0x7ff)];
+ uint8_t const attr = code & 0xff;
uint8_t new_ra = ra + 1;
@@ -103,7 +103,7 @@ MC6845_UPDATE_ROW( wangpc_mvc_device::crtc_update_row )
new_ra = ra;
}
- offs_t addr = ((code >> 8) << 4) | (new_ra & 0x0f);
+ offs_t const addr = ((code >> 8) << 4) | (new_ra & 0x0f);
uint16_t data = m_char_ram[addr & 0xfff];
if ((column == cursor_x) || (!ra && ATTR_OVERSCORE) || ((ra == 9) && ATTR_UNDERSCORE))
@@ -113,11 +113,13 @@ MC6845_UPDATE_ROW( wangpc_mvc_device::crtc_update_row )
for (int bit = 0; bit < 10; bit++)
{
- int x = (column * 10) + bit;
+ int const x = (column * 10) + bit;
int color = ((BIT(data, 9) & ~ATTR_BLANK) ^ ATTR_REVERSE);
- if ((color | bitmap.pix32(vbp + y, hbp + x)) & ATTR_BOLD) color = 2;
- if (color) bitmap.pix32(vbp + y, hbp + x) = de ? PALETTE_MVC[color] : rgb_t::black();
+ if ((color | bitmap.pix(vbp + y, hbp + x)) & ATTR_BOLD)
+ color = 2;
+ if (color)
+ bitmap.pix(vbp + y, hbp + x) = de ? PALETTE_MVC[color] : rgb_t::black();
data <<= 1;
}
diff --git a/src/devices/cpu/bcp/dp8344.cpp b/src/devices/cpu/bcp/dp8344.cpp
index fcc872855eb..b58599e3183 100644
--- a/src/devices/cpu/bcp/dp8344.cpp
+++ b/src/devices/cpu/bcp/dp8344.cpp
@@ -48,8 +48,8 @@
//**************************************************************************
// device type definitions
-DEFINE_DEVICE_TYPE(DP8344A, dp8344a_device, "dp8344a", "DP8344A BCP")
-DEFINE_DEVICE_TYPE(DP8344B, dp8344b_device, "dp8344b", "DP8344B BCP")
+DEFINE_DEVICE_TYPE(DP8344A, dp8344a_device, "dp8344a", "National Semiconductor DP8344A BCP")
+DEFINE_DEVICE_TYPE(DP8344B, dp8344b_device, "dp8344b", "National Semiconductor DP8344B BCP")
//**************************************************************************
@@ -109,6 +109,7 @@ dp8344_device::dp8344_device(const machine_config &mconfig, device_type type, co
, m_tfifo{0, 0, 0}
, m_rfifo_head(0)
, m_tfifo_head(0)
+ , m_receiver_interrupt(false)
{
}
@@ -178,7 +179,7 @@ void dp8344_device::device_start()
set_icountptr(m_icount);
// debug state registration
- state_add<u16>(BCP_PC, "PC", [this]() { return m_pc; }, [this](u16 data) { m_pc = m_ppc = data; prefetch_instruction(); });
+ state_add(BCP_PC, "PC", m_pc, [this](u16 data) { m_pc = m_ppc = data; prefetch_instruction(); });
state_add(STATE_GENPC, "GENPC", m_pc).noshow();
state_add(STATE_GENPCBASE, "GENPCBASE", m_pc).noshow();
state_add(STATE_GENFLAGS, "GENFLAGS", m_ccr).formatstr("%09s").noshow();
@@ -257,6 +258,7 @@ void dp8344_device::device_start()
save_item(NAME(m_tfifo)); // 3-frame Transmit FIFO
save_item(NAME(m_rfifo_head));
save_item(NAME(m_tfifo_head));
+ save_item(NAME(m_receiver_interrupt));
}
@@ -338,7 +340,7 @@ std::unique_ptr<util::disasm_interface> dp8344_device::create_disassembler()
void dp8344_device::set_receiver_interrupt(bool state)
{
- // TODO
+ m_receiver_interrupt = state;
}
@@ -545,8 +547,8 @@ void dp8344_device::set_device_control(u8 data)
bool dp8344_device::interrupt_active() const
{
- // TODO: non-timer interrupts
- return !BIT(m_icr, 4) && BIT(m_ccr, 7);
+ // TODO: non-receiver, non-timer interrupts
+ return (!BIT(m_icr, 0) && m_receiver_interrupt) || (!BIT(m_icr, 4) && BIT(m_ccr, 7));
}
@@ -557,8 +559,11 @@ bool dp8344_device::interrupt_active() const
u8 dp8344_device::get_interrupt_vector() const
{
- // TODO: non-timer interrupts
- return 0x14;
+ // TODO: non-receiver, non-timer interrupts
+ if (!BIT(m_icr, 0) && m_receiver_interrupt)
+ return 0x04;
+ else
+ return 0x14;
}
@@ -592,8 +597,8 @@ bool dp8344_device::get_flag(unsigned f) const
case 5: // Receiver Error
return BIT(m_tsr, 5);
- case 6: // Data Available
- return BIT(m_tsr, 3); // FIXME: differs from numeric value!
+ case 6: // Data Available (differs from DAV bit in TSR)
+ return m_rfifo_head < 3;
case 7: // Transmitter FIFO Full (or else Not Full)
return BIT(m_tsr, 7);
@@ -808,6 +813,19 @@ u8 dp8344_device::data_stack_pop()
// TRANSCEIVER OPERATION
//**************************************************************************
+const char *const dp8344_device::s_protocol_names[8] =
+{
+ "IBM 3270",
+ "IBM 3299 Multiplexer",
+ "IBM 3299 Controller",
+ "IBM 3299 Repeater",
+ "IBM 5250",
+ "IBM 5250 Promiscuous",
+ "8-bit",
+ "8-bit Promiscuous"
+};
+
+
//-------------------------------------------------
// transceiver_reset - reset the receiver and
// transmitter
@@ -846,6 +864,30 @@ void dp8344_device::transceiver_reset()
void dp8344_device::transmit_fifo_push(u8 data)
{
+ // HACK: loopback data
+ if (BIT(m_tmr, 6))
+ {
+ u16 frame = data | u16(m_tcr & 0x07) << 8;
+ if ((m_tmr & 0x07) == 0x00)
+ {
+ // Calculate odd parity on 3270 data frames
+ if (!BIT(m_tcr, 2))
+ {
+ if ((population_count_32(data) & 1) == 0)
+ frame |= 0x100;
+ else
+ frame &= 0x2ff;
+ }
+
+ // Calculate word parity
+ frame &= 0x3ff;
+ if ((population_count_32(frame) & 1) != BIT(m_tcr, 3))
+ frame |= 0x400;
+ }
+ receive_fifo_push(frame);
+ return;
+ }
+
// Push OWP, TF10-8 and RTF7-0 onto transmit FIFO
m_tfifo[0] = data | u16(m_tcr & 0x0f) << 8;
@@ -926,14 +968,43 @@ void dp8344_device::receiver_active()
//-------------------------------------------------
-// receive_fifo_push -
+// receive_fifo_push - push a data frame onto
+// the receive FIFO
//-------------------------------------------------
-void dp8344_device::receive_fifo_push(u8 data)
+void dp8344_device::receive_fifo_push(u16 data)
{
- // Overflow error if the receive FIFO is already full
- if (BIT(m_ncf, 6))
+ // Push word onto receive FIFO
+ m_rfifo[0] = data;
+
+ if (m_rfifo_head != 0)
+ {
+ // Asynchronously propagate data through FIFO (actually takes 40 ns)
+ m_rfifo_head--;
+ for (int i = 0; i < m_rfifo_head; i++)
+ m_rfifo[i + 1] = m_rfifo[i];
+
+ // Set data available flag
+ m_tsr |= 0x08;
+ if ((m_icr & 0xc0) == 0x40)
+ set_receiver_interrupt(true);
+
+ // Copy upper bits to TSR
+ m_tsr = (m_tsr & 0xf8) | (data & 0x700) >> 8;
+
+ // Set flag when FIFO is full
+ if (m_rfifo_head == 0)
+ {
+ m_tsr |= 0x40;
+ if ((m_icr & 0xc0) == 0x00)
+ set_receiver_interrupt(true);
+ }
+ }
+ else
+ {
+ // Overflow error if the receive FIFO is already full
set_receiver_error(0x10);
+ }
}
@@ -943,19 +1014,32 @@ void dp8344_device::receive_fifo_push(u8 data)
u8 dp8344_device::receive_fifo_pop(bool test)
{
+ u8 data = m_rfifo[m_rfifo_head < 3 ? m_rfifo_head : 2] & 0x0ff;
+
if (!test)
{
- // Clear Receive FIFO Full, DEME, Auto-Response and Poll/Acknowledge bits in NCF
- m_ncf &= 0xb0;
+ if (m_rfifo_head < 3)
+ {
+ // Advance the FIFO
+ m_rfifo_head++;
+
+ // Copy upper bits to TSR
+ if (m_rfifo_head < 3)
+ m_tsr = (m_tsr & 0xf8) | (m_rfifo[m_rfifo_head] & 0x700) >> 8;
+ }
// Clear Data Available flag in TSR
m_tsr &= 0xf7;
- if ((m_icr & 0xc0) == 0xc0)
+
+ // Clear Receive FIFO Full, DEME, Auto-Response and Poll/Acknowledge bits in NCF
+ m_ncf &= 0xb0;
+
+ // Clear receiver interrupt unless error interrupt exists
+ if (BIT(m_icr, 7) || !BIT(m_tsr, 5))
set_receiver_interrupt(false);
}
- // TODO
- return 0;
+ return data;
}
@@ -990,12 +1074,19 @@ u8 dp8344_device::get_error_code(bool test)
{
u8 code = m_ecr;
+ // Upper bits come from receive FIFO
+ code |= m_rfifo[m_rfifo_head < 3 ? m_rfifo_head : 2] & 0x0e0;
+
if (!test)
{
// Clear Error Code Register and Receiver Error flag in NCF
m_ecr = 0x00;
m_ncf &= 0xdf;
+ // Reassert DAV if FIFO is not empty
+ if (m_rfifo_head < 3)
+ m_tsr |= 0x08;
+
// Update interrupt status if RE interrupt selected
switch (m_icr & 0xc0)
{
@@ -1049,40 +1140,8 @@ void dp8344_device::set_transceiver_mode(u8 data)
if (!BIT(m_tmr, 6) && BIT(data, 6))
m_tx_act_cb(0);
- switch (data & 0x07)
- {
- case 0:
- logerror("%04X: Protocol Select: IBM 3270\n", m_ppc);
- break;
-
- case 1:
- logerror("%04X: Protocol Select: IBM 3299 Multiplexer\n", m_ppc);
- break;
-
- case 2:
- logerror("%04X: Protocol Select: IBM 3299 Controller\n", m_ppc);
- break;
-
- case 3:
- logerror("%04X: Protocol Select: IBM 3299 Repeater\n", m_ppc);
- break;
-
- case 4:
- logerror("%04X: Protocol Select: IBM 5250\n", m_ppc);
- break;
-
- case 5:
- logerror("%04X: Protocol Select: IBM 5250 Promiscuous\n", m_ppc);
- break;
-
- case 6:
- logerror("%04X: Protocol Select: 8-bit\n", m_ppc);
- break;
-
- case 7:
- logerror("%04X: Protocol Select: 8-bit Promiscuous\n", m_ppc);
- break;
- }
+ if ((m_tmr & 0x07) != (data & 0x07))
+ logerror("%04X: Protocol Select: %s\n", m_ppc, s_protocol_names[data & 0x07]);
m_tmr = data;
}
@@ -2064,6 +2123,10 @@ void dp8344_device::cmd_w(u8 data)
BIT(data, 3) ? "latched" : BIT(data, 5) ? "fast buffered" : "slow buffered",
BIT(data, 6) ? "single step" : BIT(data, 2) ? "start" : "stop");
+ // Make sure not to restart in the middle of an instruction
+ if (!BIT(m_ric, 2) && BIT(data, 2))
+ m_inst_state = T1_START;
+
m_ric = data;
set_input_line(INPUT_LINE_HALT, BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE);
}
@@ -2125,7 +2188,6 @@ u8 dp8344_device::remote_read(offs_t offset)
void dp8344_device::remote_write(offs_t offset, u8 data)
{
// TODO: stop CPU if not accessing DMEM or RIC
-
switch (m_ric & 0x03)
{
case 0x00:
diff --git a/src/devices/cpu/bcp/dp8344.h b/src/devices/cpu/bcp/dp8344.h
index 95e0a671a0b..f4e1e674da9 100644
--- a/src/devices/cpu/bcp/dp8344.h
+++ b/src/devices/cpu/bcp/dp8344.h
@@ -86,6 +86,8 @@ protected:
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
private:
+ static const char *const s_protocol_names[8];
+
enum inst_state : u8 {
T1_DECODE, T1_START, T1_SKIP, T1_LJMP, T1_LCALL,
TX_READ, TX_WRITE,
@@ -123,7 +125,7 @@ private:
u16 transmit_fifo_pop();
void transmitter_idle();
void receiver_active();
- void receive_fifo_push(u8 data);
+ void receive_fifo_push(u16 data);
u8 receive_fifo_pop(bool test);
void set_receiver_error(u8 code);
u8 get_error_code(bool test);
@@ -214,6 +216,9 @@ private:
u16 m_tfifo[3];
u8 m_rfifo_head;
u8 m_tfifo_head;
+
+ // misc. state
+ bool m_receiver_interrupt;
};
// ======================> dp8344a_device
diff --git a/src/devices/cpu/e0c6200/e0c6s46.cpp b/src/devices/cpu/e0c6200/e0c6s46.cpp
index 9f80774a6e5..5094c36a5f7 100644
--- a/src/devices/cpu/e0c6200/e0c6s46.cpp
+++ b/src/devices/cpu/e0c6200/e0c6s46.cpp
@@ -589,7 +589,7 @@ u32 e0c6s46_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, c
if (!m_pixel_update_cb.isnull())
m_pixel_update_cb(bitmap, cliprect, m_lcd_contrast, seg, com, pixel);
else if (cliprect.contains(seg, com))
- bitmap.pix16(com, seg) = pixel;
+ bitmap.pix(com, seg) = pixel;
}
}
}
diff --git a/src/devices/cpu/f8/f8dasm.cpp b/src/devices/cpu/f8/f8dasm.cpp
index 24ec47b5154..e35a7d42f70 100644
--- a/src/devices/cpu/f8/f8dasm.cpp
+++ b/src/devices/cpu/f8/f8dasm.cpp
@@ -17,33 +17,22 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
{
offs_t base_pc = pc;
uint8_t op = opcodes.r8(pc++);
+ offs_t flags = SUPPORTED;
switch( op )
{
/* opcode bitmask */
case 0x00: /* 0000 0000 */
- util::stream_format(stream, "LR A,KU");
- break;
case 0x01: /* 0000 0001 */
- util::stream_format(stream, "LR A,KL");
- break;
case 0x02: /* 0000 0010 */
- util::stream_format(stream, "LR A,QU");
- break;
case 0x03: /* 0000 0011 */
- util::stream_format(stream, "LR A,QL");
+ util::stream_format(stream, "LR A,%s", rname[op + 12]);
break;
case 0x04: /* 0000 0100 */
- util::stream_format(stream, "LR KU,A");
- break;
case 0x05: /* 0000 0101 */
- util::stream_format(stream, "LR KL,A");
- break;
case 0x06: /* 0000 0110 */
- util::stream_format(stream, "LR QU,A");
- break;
case 0x07: /* 0000 0111 */
- util::stream_format(stream, "LR QL,A");
+ util::stream_format(stream, "LR %s,A", rname[(op - 0x04) + 12]);
break;
case 0x08: /* 0000 1000 */
@@ -60,7 +49,8 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
break;
case 0x0c: /* 0000 1100 */
- util::stream_format(stream, "PK") ;
+ util::stream_format(stream, "PK");
+ flags |= STEP_OUT;
break;
case 0x0d: /* 0000 1101 */
util::stream_format(stream, "LR P0,Q");
@@ -109,6 +99,7 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
break;
case 0x1c: /* 0001 1100 */
util::stream_format(stream, "POP");
+ flags |= STEP_OUT;
break;
case 0x1d: /* 0001 1101 */
util::stream_format(stream, "LR W,J");
@@ -120,39 +111,40 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
util::stream_format(stream, "INC");
break;
case 0x20: /* 0010 0000 */
- util::stream_format(stream, "LI $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "LI H'%02X'", opcodes.r8(pc++));
break;
case 0x21: /* 0010 0001 */
- util::stream_format(stream, "NI $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "NI H'%02X'", opcodes.r8(pc++));
break;
case 0x22: /* 0010 0010 */
- util::stream_format(stream, "OI $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "OI H'%02X'", opcodes.r8(pc++));
break;
case 0x23: /* 0010 0011 */
- util::stream_format(stream, "XI $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "XI H'%02X'", opcodes.r8(pc++));
break;
case 0x24: /* 0010 0100 */
- util::stream_format(stream, "AI $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "AI H'%02X'", opcodes.r8(pc++));
break;
case 0x25: /* 0010 0101 */
- util::stream_format(stream, "CI $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "CI H'%02X'", opcodes.r8(pc++));
break;
case 0x26: /* 0010 0110 */
- util::stream_format(stream, "IN $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "IN H'%02X'", opcodes.r8(pc++));
break;
case 0x27: /* 0010 0111 */
- util::stream_format(stream, "OUT $%02X", opcodes.r8(pc++));
+ util::stream_format(stream, "OUT H'%02X'", opcodes.r8(pc++));
break;
case 0x28: /* 0010 1000 */
- util::stream_format(stream, "PI $%04X", opcodes.r16(pc));
+ util::stream_format(stream, "PI H'%04X'", opcodes.r16(pc));
pc += 2;
+ flags |= STEP_OVER;
break;
case 0x29: /* 0010 1001 */
- util::stream_format(stream, "JMP $%04X", opcodes.r16(pc));
+ util::stream_format(stream, "JMP H'%04X'", opcodes.r16(pc));
pc += 2;
break;
case 0x2a: /* 0010 1010 */
- util::stream_format(stream, "DCI $%04X", opcodes.r16(pc));
+ util::stream_format(stream, "DCI H'%04X'", opcodes.r16(pc));
pc += 2;
break;
case 0x2b: /* 0010 1011 */
@@ -161,11 +153,9 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x2c: /* 0010 1100 */
util::stream_format(stream, "XDC");
break;
- case 0x2d: /* 0010 1101 */
- case 0x2e: /* 0010 1110 */
- case 0x2f: /* 0010 1111 */
- util::stream_format(stream, "??? $%02X",op);
- break;
+ /* case 0x2d: 0010 1101 */
+ /* case 0x2e: 0010 1110 */
+ /* case 0x2f: 0010 1111 */
case 0x30: /* 0011 0000 */
case 0x31: /* 0011 0001 */
@@ -179,20 +169,18 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x39: /* 0011 1001 */
case 0x3a: /* 0011 1010 */
case 0x3b: /* 0011 1011 */
- util::stream_format(stream, "DS %s",rname[op & 15]);
+ util::stream_format(stream, "DS %s", rname[op & 15]);
break;
case 0x3c: /* 0011 1100 */
- util::stream_format(stream, "DS (IS)");
+ util::stream_format(stream, "DS S");
break;
case 0x3d: /* 0011 1101 */
- util::stream_format(stream, "DS (IS++)");
+ util::stream_format(stream, "DS I");
break;
case 0x3e: /* 0011 1110 */
- util::stream_format(stream, "DS (IS--)");
- break;
- case 0x3f: /* 0011 1111 */
- util::stream_format(stream, "??? $%02X",op);
+ util::stream_format(stream, "DS D");
break;
+ /* case 0x3f: 0011 1111 */
case 0x40: /* 0100 0000 */
case 0x41: /* 0100 0001 */
@@ -206,20 +194,18 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x49: /* 0100 1001 */
case 0x4a: /* 0100 1010 */
case 0x4b: /* 0100 1011 */
- util::stream_format(stream, "LR A,%s",rname[op & 15]);
+ util::stream_format(stream, "LR A,%s", rname[op & 15]);
break;
case 0x4c: /* 0100 1100 */
- util::stream_format(stream, "LR A,(IS)");
+ util::stream_format(stream, "LR A,S");
break;
case 0x4d: /* 0100 1101 */
- util::stream_format(stream, "LR A,(IS++)");
+ util::stream_format(stream, "LR A,I");
break;
case 0x4e: /* 0100 1110 */
- util::stream_format(stream, "LR A,(IS--)");
- break;
- case 0x4f: /* 0100 1111 */
- util::stream_format(stream, "??? $%02X",op);
+ util::stream_format(stream, "LR A,D");
break;
+ /* case 0x4f: 0100 1111 */
case 0x50: /* 0101 0000 */
case 0x51: /* 0101 0001 */
@@ -233,20 +219,18 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x59: /* 0101 1001 */
case 0x5a: /* 0101 1010 */
case 0x5b: /* 0101 1011 */
- util::stream_format(stream, "LR %s,A",rname[op & 15]);
+ util::stream_format(stream, "LR %s,A", rname[op & 15]);
break;
case 0x5c: /* 0101 1100 */
- util::stream_format(stream, "LR (IS),A");
+ util::stream_format(stream, "LR S,A");
break;
case 0x5d: /* 0101 1101 */
- util::stream_format(stream, "LR (IS++),A");
+ util::stream_format(stream, "LR I,A");
break;
case 0x5e: /* 0101 1110 */
- util::stream_format(stream, "LR (IS--),A");
- break;
- case 0x5f: /* 0101 1111 */
- util::stream_format(stream, "??? $%02X",op);
+ util::stream_format(stream, "LR D,A");
break;
+ /* case 0x5f: 0101 1111 */
case 0x60: /* 0110 0000 */
case 0x61: /* 0110 0001 */
@@ -256,7 +240,7 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x65: /* 0110 0101 */
case 0x66: /* 0110 0110 */
case 0x67: /* 0110 0111 */
- util::stream_format(stream, "LISU $%02X", op & 0x07);
+ util::stream_format(stream, "LISU %d", op & 0x07);
break;
case 0x68: /* 0110 1000 */
case 0x69: /* 0110 1001 */
@@ -266,7 +250,7 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x6d: /* 0110 1101 */
case 0x6e: /* 0110 1110 */
case 0x6f: /* 0110 1111 */
- util::stream_format(stream, "LISL $%02X", op & 0x07);
+ util::stream_format(stream, "LISL %d", op & 0x07);
break;
case 0x70: /* 0111 0000 */
@@ -285,27 +269,27 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x7d: /* 0111 1101 */
case 0x7e: /* 0111 1110 */
case 0x7f: /* 0111 1111 */
- util::stream_format(stream, "LIS $%02X", op & 0x0f);
+ util::stream_format(stream, "LIS H'%02X'", op & 0x0f);
break;
case 0x81: /* 1000 0001 */
case 0x85: /* 1000 0101 */
- util::stream_format(stream, "BP $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BP H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x82: /* 1000 0010 */
- util::stream_format(stream, "BC $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BC H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x84: /* 1000 0100 */
- util::stream_format(stream, "BZ $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BZ H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x80: /* 1000 0000 */
case 0x83: /* 1000 0011 */
case 0x86: /* 1000 0110 */
case 0x87: /* 1000 0111 */
- util::stream_format(stream, "BT $%02X,$%04X", op & 0x07, base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BT H'%02X',H'%04X'", op & 0x07, base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x88: /* 1000 1000 */
@@ -337,28 +321,28 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
break;
case 0x8f: /* 1000 1111 */
- util::stream_format(stream, "BR7 $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BR7 H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x90: /* 1001 0000 */
- util::stream_format(stream, "BR $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BR H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x91: /* 1001 0001 */
case 0x95: /* 1001 0101 */
- util::stream_format(stream, "BM $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BM H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x92: /* 1001 0010 */
- util::stream_format(stream, "BNC $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BNC H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x94: /* 1001 0100 */
- util::stream_format(stream, "BNZ $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BNZ H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x98: /* 1001 1000 */
- util::stream_format(stream, "BNO $%04X", base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BNO H'%04X'", base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0x93: /* 1001 0011 */
@@ -371,18 +355,16 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0x9d: /* 1001 1101 */
case 0x9e: /* 1001 1110 */
case 0x9f: /* 1001 1111 */
- util::stream_format(stream, "BF $%02X,$%04X", op & 0x0f, base_pc + (int8_t)opcodes.r8(pc++) + 1);
+ util::stream_format(stream, "BF H'%02X',H'%04X'", op & 0x0f, base_pc + (int8_t)opcodes.r8(pc++) + 1);
break;
case 0xa0: /* 1010 0000 */
case 0xa1: /* 1010 0001 */
- util::stream_format(stream, "INS $%02X", (unsigned) (int8_t) (op & 0x0F));
+ util::stream_format(stream, "INS %d", op & 0x0f);
break;
- case 0xa2: /* 1010 0010 */
- case 0xa3: /* 1010 0011 */
- util::stream_format(stream, "??? $%02X", op);
- break;
+ /* case 0xa2: 1010 0010 */
+ /* case 0xa3: 1010 0011 */
case 0xa4: /* 1010 0100 */
case 0xa5: /* 1010 0101 */
@@ -396,18 +378,16 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0xad: /* 1010 1101 */
case 0xae: /* 1010 1110 */
case 0xaf: /* 1010 1111 */
- util::stream_format(stream, "INS $%02X", (int8_t) op & 0x0f);
+ util::stream_format(stream, "INS H'%02X'", op & 0x0f);
break;
case 0xb0: /* 1011 0000 */
case 0xb1: /* 1011 0001 */
- util::stream_format(stream, "OUTS $%02X", (int8_t) op & 0x0f);
+ util::stream_format(stream, "OUTS %d", op & 0x0f);
break;
- case 0xb2: /* 1011 0010 */
- case 0xb3: /* 1011 0011 */
- util::stream_format(stream, "??? $%02X", op);
- break;
+ /* case 0xb2: 1011 0010 */
+ /* case 0xb3: 1011 0011 */
case 0xb4: /* 1011 0100 */
case 0xb5: /* 1011 0101 */
@@ -421,7 +401,7 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
case 0xbd: /* 1011 1101 */
case 0xbe: /* 1011 1110 */
case 0xbf: /* 1011 1111 */
- util::stream_format(stream, "OUTS $%02X", (unsigned) (int8_t) op & 0x0f);
+ util::stream_format(stream, "OUTS H'%02X'", op & 0x0f);
break;
case 0xc0: /* 1100 0000 */
@@ -439,17 +419,15 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
util::stream_format(stream, "AS %s", rname[op & 15]);
break;
case 0xcc: /* 1100 1100 */
- util::stream_format(stream, "AS (IS)");
+ util::stream_format(stream, "AS S");
break;
case 0xcd: /* 1100 1101 */
- util::stream_format(stream, "AS (IS++)");
+ util::stream_format(stream, "AS I");
break;
case 0xce: /* 1100 1110 */
- util::stream_format(stream, "AS (IS--)");
- break;
- case 0xcf: /* 1100 1111 */
- util::stream_format(stream, "??? $%02X", op);
+ util::stream_format(stream, "AS D");
break;
+ /* case 0xcf: 1100 1111 */
case 0xd0: /* 1101 0000 */
case 0xd1: /* 1101 0001 */
@@ -466,17 +444,15 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
util::stream_format(stream, "ASD %s", rname[op & 15]);
break;
case 0xdc: /* 1101 1100 */
- util::stream_format(stream, "ASD (IS)");
+ util::stream_format(stream, "ASD S");
break;
case 0xdd: /* 1101 1101 */
- util::stream_format(stream, "ASD (IS++)");
+ util::stream_format(stream, "ASD I");
break;
case 0xde: /* 1101 1110 */
- util::stream_format(stream, "ASD (IS--)");
- break;
- case 0xdf: /* 1101 1111 */
- util::stream_format(stream, "??? $%02X", op);
+ util::stream_format(stream, "ASD D");
break;
+ /* case 0xdf: 1101 1111 */
case 0xe0: /* 1110 0000 */
case 0xe1: /* 1110 0001 */
@@ -493,17 +469,15 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
util::stream_format(stream, "XS %s", rname[op & 15]);
break;
case 0xec: /* 1110 1100 */
- util::stream_format(stream, "XS (IS)");
+ util::stream_format(stream, "XS S");
break;
case 0xed: /* 1110 1101 */
- util::stream_format(stream, "XS (IS++)");
+ util::stream_format(stream, "XS I");
break;
case 0xee: /* 1110 1110 */
- util::stream_format(stream, "XS (IS--)");
- break;
- case 0xef: /* 1110 1111 */
- util::stream_format(stream, "??? $%02X", op);
+ util::stream_format(stream, "XS D");
break;
+ /* case 0xef: 1110 1111 */
case 0xf0: /* 1111 0000 */
@@ -521,18 +495,21 @@ offs_t f8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_
util::stream_format(stream, "NS %s", rname[op & 15]);
break;
case 0xfc: /* 1111 1100 */
- util::stream_format(stream, "NS (IS)");
+ util::stream_format(stream, "NS S");
break;
case 0xfd: /* 1111 1101 */
- util::stream_format(stream, "NS (IS++)");
+ util::stream_format(stream, "NS I");
break;
case 0xfe: /* 1111 1110 */
- util::stream_format(stream, "NS (IS--)");
+ util::stream_format(stream, "NS D");
break;
- case 0xff: /* 1111 1111 */
- util::stream_format(stream, "??? $%02X", op);
+ /* case 0xff: 1111 1111 */
+
+
+ default:
+ util::stream_format(stream, "DC H'%02X' (?)", op);
break;
}
- return pc - base_pc;
+ return (pc - base_pc) | flags;
}
diff --git a/src/devices/cpu/lc58/lc58d.cpp b/src/devices/cpu/lc58/lc58d.cpp
new file mode 100644
index 00000000000..477ee00ffb0
--- /dev/null
+++ b/src/devices/cpu/lc58/lc58d.cpp
@@ -0,0 +1,160 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// LC58 generic disassembler
+
+#include "emu.h"
+#include "lc58d.h"
+
+u32 lc58_disassembler::opcode_alignment() const
+{
+ return 1;
+}
+
+#define P std::ostream &stream, const lc58_disassembler *d, u16 opcode
+const lc58_disassembler::instruction lc58_disassembler::instructions[] {
+ { 0x5a00, 0xffff, [](P) -> u32 { util::stream_format(stream, "cla"); return 1; } },
+ { 0xec01, 0xffff, [](P) -> u32 { util::stream_format(stream, "rcf"); return 1; } },
+ { 0xe801, 0xffff, [](P) -> u32 { util::stream_format(stream, "scf"); return 1; } },
+ { 0x6000, 0xfc00, [](P) -> u32 { util::stream_format(stream, "mrw wr%x, %02x", (opcode >> 7) & 7, opcode & 0x7f); return 1; } },
+ { 0x6400, 0xfc00, [](P) -> u32 { util::stream_format(stream, "mwr %02x, wr%x", opcode & 0x7f, (opcode >> 7) & 7); return 1; } },
+ { 0x6800, 0xff80, [](P) -> u32 { util::stream_format(stream, "sr0 %02x", opcode & 0x7f); return 1; } },
+ { 0x6900, 0xff80, [](P) -> u32 { util::stream_format(stream, "sr1 %02x", opcode & 0x7f); return 1; } },
+ { 0x6a00, 0xff80, [](P) -> u32 { util::stream_format(stream, "sl0 %02x", opcode & 0x7f); return 1; } },
+ { 0x6b00, 0xff80, [](P) -> u32 { util::stream_format(stream, "sl1 %02x", opcode & 0x7f); return 1; } },
+ { 0x6c00, 0xff80, [](P) -> u32 { util::stream_format(stream, "rar %02x", opcode & 0x7f); return 1; } },
+ { 0x6e00, 0xff80, [](P) -> u32 { util::stream_format(stream, "ral %02x", opcode & 0x7f); return 1; } },
+ { 0x7400, 0xff80, [](P) -> u32 { util::stream_format(stream, "maf %02x", opcode & 0x7f); return 1; } },
+ { 0x0f80, 0xff80, [](P) -> u32 { util::stream_format(stream, "mra %02x", opcode & 0x7f); return 1; } },
+
+ { 0x4000, 0xff80, [](P) -> u32 { util::stream_format(stream, "adc %02x", opcode & 0x7f); return 1; } },
+ { 0x4100, 0xff80, [](P) -> u32 { util::stream_format(stream, "adc* %02x", opcode & 0x7f); return 1; } },
+ { 0x4200, 0xff80, [](P) -> u32 { util::stream_format(stream, "sbc %02x", opcode & 0x7f); return 1; } },
+ { 0x4300, 0xff80, [](P) -> u32 { util::stream_format(stream, "sbc* %02x", opcode & 0x7f); return 1; } },
+ { 0x4400, 0xff80, [](P) -> u32 { util::stream_format(stream, "add %02x", opcode & 0x7f); return 1; } },
+ { 0x4500, 0xff80, [](P) -> u32 { util::stream_format(stream, "add* %02x", opcode & 0x7f); return 1; } },
+ { 0x4600, 0xff80, [](P) -> u32 { util::stream_format(stream, "sub %02x", opcode & 0x7f); return 1; } },
+ { 0x4700, 0xff80, [](P) -> u32 { util::stream_format(stream, "sub* %02x", opcode & 0x7f); return 1; } },
+ { 0x4800, 0xff80, [](P) -> u32 { util::stream_format(stream, "adn %02x", opcode & 0x7f); return 1; } },
+ { 0x4900, 0xff80, [](P) -> u32 { util::stream_format(stream, "adn* %02x", opcode & 0x7f); return 1; } },
+ { 0x4a00, 0xff80, [](P) -> u32 { util::stream_format(stream, "and %02x", opcode & 0x7f); return 1; } },
+ { 0x4b00, 0xff80, [](P) -> u32 { util::stream_format(stream, "and* %02x", opcode & 0x7f); return 1; } },
+ { 0x4c00, 0xff80, [](P) -> u32 { util::stream_format(stream, "eor %02x", opcode & 0x7f); return 1; } },
+ { 0x4d00, 0xff80, [](P) -> u32 { util::stream_format(stream, "eor* %02x", opcode & 0x7f); return 1; } },
+ { 0x4e00, 0xff80, [](P) -> u32 { util::stream_format(stream, "or %02x", opcode & 0x7f); return 1; } },
+ { 0x4f00, 0xff80, [](P) -> u32 { util::stream_format(stream, "or* %02x", opcode & 0x7f); return 1; } },
+ { 0x5000, 0xff00, [](P) -> u32 { util::stream_format(stream, "adci #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5100, 0xff00, [](P) -> u32 { util::stream_format(stream, "adci* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5200, 0xff00, [](P) -> u32 { util::stream_format(stream, "sbci #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5300, 0xff00, [](P) -> u32 { util::stream_format(stream, "sbci* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5400, 0xff00, [](P) -> u32 { util::stream_format(stream, "addi #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5500, 0xff00, [](P) -> u32 { util::stream_format(stream, "addi* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5600, 0xff00, [](P) -> u32 { util::stream_format(stream, "subi #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5700, 0xff00, [](P) -> u32 { util::stream_format(stream, "subi* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5800, 0xff00, [](P) -> u32 { util::stream_format(stream, "adni #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5900, 0xff00, [](P) -> u32 { util::stream_format(stream, "adni* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5a00, 0xff00, [](P) -> u32 { util::stream_format(stream, "andi #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5b00, 0xff00, [](P) -> u32 { util::stream_format(stream, "andi* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5c00, 0xff00, [](P) -> u32 { util::stream_format(stream, "eori #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5d00, 0xff00, [](P) -> u32 { util::stream_format(stream, "eori* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5e00, 0xff00, [](P) -> u32 { util::stream_format(stream, "ori #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+ { 0x5f00, 0xff00, [](P) -> u32 { util::stream_format(stream, "ori* #%x, %02x", (opcode >> 4) & 0xf, 0x70 + (opcode & 0xf)); return 1; } },
+
+ { 0x7700, 0xff80, [](P) -> u32 { util::stream_format(stream, "mdpl %02x", opcode & 0x7f); return 1; } },
+ { 0x7680, 0xff80, [](P) -> u32 { util::stream_format(stream, "mdph %02x", opcode & 0x7f); return 1; } },
+ { 0x6b80, 0xff80, [](P) -> u32 { util::stream_format(stream, "mrdl %02x", opcode & 0x7f); return 1; } },
+ { 0x6980, 0xff80, [](P) -> u32 { util::stream_format(stream, "mrdh %02x", opcode & 0x7f); return 1; } },
+ { 0x6a80, 0xff80, [](P) -> u32 { util::stream_format(stream, "mrsp %02x", opcode & 0x7f); return 1; } },
+ { 0xe800, 0xfc00, [](P) -> u32 { util::stream_format(stream, "sf1 %03x", opcode & 0x3ff); return 1; } },
+ { 0xec00, 0xfc00, [](P) -> u32 { util::stream_format(stream, "rf1 %03x", opcode & 0x3ff); return 1; } },
+ { 0xf000, 0xfc00, [](P) -> u32 { util::stream_format(stream, "sf2 %03x", opcode & 0x3ff); return 1; } },
+ { 0xf400, 0xfc00, [](P) -> u32 { util::stream_format(stream, "rf2 %03x", opcode & 0x3ff); return 1; } },
+ { 0xe880, 0xffff, [](P) -> u32 { util::stream_format(stream, "sdpf"); return 1; } },
+ { 0xec80, 0xffff, [](P) -> u32 { util::stream_format(stream, "rdpf"); return 1; } },
+
+ { 0x7780, 0xff80, [](P) -> u32 { util::stream_format(stream, "sta %02x", opcode & 0x7f); return 1; } },
+ { 0x7800, 0xf800, [](P) -> u32 { util::stream_format(stream, "lds %02x, #%x", opcode & 0x7f, (opcode >> 7) & 0xf); return 1; } },
+ { 0x6880, 0xff80, [](P) -> u32 { util::stream_format(stream, "lda %02x", opcode & 0x7f); return 1; } },
+
+ { 0xff00, 0xffff, [](P) -> u32 { util::stream_format(stream, "halt"); return 1; } },
+ { 0xe000, 0xffc0, [](P) -> u32 { util::stream_format(stream, "ssw %02x", opcode & 0x3f); return 1; } },
+ { 0xfa00, 0xfe00, [](P) -> u32 { util::stream_format(stream, "sie %03x", opcode & 0x1ff); return 1 | STEP_OVER; } },
+ { 0xfe00, 0xfff0, [](P) -> u32 { util::stream_format(stream, "sie* %x", opcode & 0xf); return 1 | STEP_OVER; } },
+ { 0x7580, 0xff80, [](P) -> u32 { util::stream_format(stream, "msb %02x", opcode & 0x7f); return 1; } },
+ { 0x7600, 0xff80, [](P) -> u32 { util::stream_format(stream, "msc %02x", opcode & 0x7f); return 1; } },
+ { 0x0000, 0xffff, [](P) -> u32 { util::stream_format(stream, "nop"); return 1; } },
+ { 0xf018, 0xffff, [](P) -> u32 { util::stream_format(stream, "lon"); return 1; } },
+ { 0xf418, 0xffff, [](P) -> u32 { util::stream_format(stream, "loff"); return 1; } },
+ { 0xf004, 0xffff, [](P) -> u32 { util::stream_format(stream, "sbak"); return 1; } },
+ { 0xf404, 0xffff, [](P) -> u32 { util::stream_format(stream, "rbak"); return 1; } },
+
+ { 0x7480, 0xff80, [](P) -> u32 { util::stream_format(stream, "mcd %02x", opcode & 0x7f); return 1; } },
+ { 0x7500, 0xff80, [](P) -> u32 { util::stream_format(stream, "mcf %02x", opcode & 0x7f); return 1; } },
+ { 0xfc22, 0xffff, [](P) -> u32 { util::stream_format(stream, "ccc"); return 1; } },
+ { 0xfc40, 0xffff, [](P) -> u32 { util::stream_format(stream, "rlp"); return 1; } },
+ { 0xfc80, 0xffff, [](P) -> u32 { util::stream_format(stream, "csp"); return 1; } },
+ { 0xfb00, 0xffff, [](P) -> u32 { util::stream_format(stream, "cst"); return 1; } },
+ { 0xe802, 0xffff, [](P) -> u32 { util::stream_format(stream, "scex"); return 1; } },
+ { 0xec02, 0xffff, [](P) -> u32 { util::stream_format(stream, "rcex"); return 1; } },
+ { 0xf000, 0xfffc, [](P) -> u32 { util::stream_format(stream, "schf %x", opcode & 3); return 1; } },
+ { 0xf400, 0xfffc, [](P) -> u32 { util::stream_format(stream, "rchf %x", opcode & 3); return 1; } },
+
+ { 0x7180, 0xff80, [](P) -> u32 { util::stream_format(stream, "ipp %02x", opcode & 0x7f); return 1; } },
+ { 0x7000, 0xff80, [](P) -> u32 { util::stream_format(stream, "ips %02x", opcode & 0x7f); return 1; } },
+ { 0x7080, 0xff80, [](P) -> u32 { util::stream_format(stream, "ipm %02x", opcode & 0x7f); return 1; } },
+ { 0x7100, 0xff80, [](P) -> u32 { util::stream_format(stream, "ipk %02x", opcode & 0x7f); return 1; } },
+ { 0x0080, 0xff80, [](P) -> u32 { util::stream_format(stream, "opp %02x", opcode & 0x7f); return 1; } },
+ { 0x0f00, 0xff80, [](P) -> u32 { util::stream_format(stream, "opm %02x", opcode & 0x7f); return 1; } },
+ { 0xe804, 0xffff, [](P) -> u32 { util::stream_format(stream, "sct1"); return 1; } },
+ { 0xec04, 0xffff, [](P) -> u32 { util::stream_format(stream, "rct1"); return 1; } },
+ { 0xf200, 0xffff, [](P) -> u32 { util::stream_format(stream, "sct2"); return 1; } },
+ { 0xf600, 0xffff, [](P) -> u32 { util::stream_format(stream, "rct2"); return 1; } },
+ { 0xf010, 0xffff, [](P) -> u32 { util::stream_format(stream, "slgt"); return 1; } },
+ { 0xf410, 0xffff, [](P) -> u32 { util::stream_format(stream, "rlgt"); return 1; } },
+ { 0xf800, 0xffff, [](P) -> u32 { util::stream_format(stream, "ras"); return 1; } },
+ { 0xf800, 0xfe00, [](P) -> u32 { util::stream_format(stream, "sas %03x", opcode & 0x1ff); return 1; } },
+ { 0xe800, 0xff9f, [](P) -> u32 { util::stream_format(stream, "comd %x", (opcode >> 5) & 3); return 1; } },
+ { 0xec00, 0xff9f, [](P) -> u32 { util::stream_format(stream, "cimd %x", (opcode >> 5) & 3); return 1; } },
+ { 0xf000, 0xfe1f, [](P) -> u32 { util::stream_format(stream, "spdf %x", (opcode >> 5) & 3); return 1; } },
+ { 0xf400, 0xfe1f, [](P) -> u32 { util::stream_format(stream, "rpdf %x", (opcode >> 5) & 3); return 1; } },
+ { 0xe808, 0xffff, [](P) -> u32 { util::stream_format(stream, "sfsp"); return 1; } },
+ { 0xec08, 0xffff, [](P) -> u32 { util::stream_format(stream, "rfsp"); return 1; } },
+ { 0x0000, 0xf000, [](P) -> u32 { util::stream_format(stream, "wrt %02x, %02x", (opcode >> 7) & 0x1f, opcode & 0x7f); return 1; } },
+ { 0x1000, 0xf000, [](P) -> u32 { util::stream_format(stream, "wrb %02x, %02x", (opcode >> 7) & 0x1f, opcode & 0x7f); return 1; } },
+ { 0x2000, 0xf000, [](P) -> u32 { util::stream_format(stream, "wrc %02x, %02x", (opcode >> 7) & 0x1f, opcode & 0x7f); return 1; } },
+ { 0x3000, 0xf000, [](P) -> u32 { util::stream_format(stream, "wrp %02x, %02x", (opcode >> 7) & 0x1f, opcode & 0x7f); return 1; } },
+
+ { 0xc000, 0xf800, [](P) -> u32 { util::stream_format(stream, "jmp %03x", opcode & 0x7ff); return 1; } },
+ { 0x8000, 0xf800, [](P) -> u32 { util::stream_format(stream, "bab0 %03x", opcode & 0x7ff); return 1; } },
+ { 0x8800, 0xf800, [](P) -> u32 { util::stream_format(stream, "bab1 %03x", opcode & 0x7ff); return 1; } },
+ { 0x9000, 0xf800, [](P) -> u32 { util::stream_format(stream, "bab2 %03x", opcode & 0x7ff); return 1; } },
+ { 0x9800, 0xf800, [](P) -> u32 { util::stream_format(stream, "bab3 %03x", opcode & 0x7ff); return 1; } },
+ { 0xa000, 0xf800, [](P) -> u32 { util::stream_format(stream, "banz %03x", opcode & 0x7ff); return 1; } },
+ { 0xb000, 0xf800, [](P) -> u32 { util::stream_format(stream, "baz %03x", opcode & 0x7ff); return 1; } },
+ { 0xa800, 0xf800, [](P) -> u32 { util::stream_format(stream, "bcnh %03x", opcode & 0x7ff); return 1; } },
+ { 0xb800, 0xf800, [](P) -> u32 { util::stream_format(stream, "bch %03x", opcode & 0x7ff); return 1; } },
+
+ { 0xc800, 0xf800, [](P) -> u32 { util::stream_format(stream, "call %03x", opcode & 0x7ff); return 1 | STEP_OVER; } },
+ { 0xd000, 0xffff, [](P) -> u32 { util::stream_format(stream, "rts"); return 1 | STEP_OUT; } },
+ { 0xd800, 0xffff, [](P) -> u32 { util::stream_format(stream, "pop"); return 1; } },
+
+ { 0xe400, 0xfc00, [](P) -> u32 { util::stream_format(stream, "stm %03x", opcode & 0x7ff); return 1; } },
+ { 0xfc04, 0xffff, [](P) -> u32 { util::stream_format(stream, "rtm"); return 1 | STEP_OUT; } },
+ { 0xf810, 0xffff, [](P) -> u32 { util::stream_format(stream, "sfpd"); return 1 | STEP_OUT; } },
+ { 0xfc10, 0xffff, [](P) -> u32 { util::stream_format(stream, "rfpd"); return 1 | STEP_OUT; } },
+ { 0xfc00, 0xfe00, [](P) -> u32 { util::stream_format(stream, "plc %03x", opcode & 0x1ff); return 1 | STEP_OVER; } },
+
+ { 0x0000, 0x0000, [](P) -> u32 { util::stream_format(stream, "?%04x", opcode); return 1; } },
+};
+
+#undef P
+
+offs_t lc58_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
+{
+ u16 opcode = opcodes.r16(pc);
+
+ for(u32 i=0;; i++)
+ if((opcode & instructions[i].mask) == instructions[i].value)
+ return instructions[i].cb(stream, this, opcode) | SUPPORTED;
+ return 0;
+}
diff --git a/src/devices/cpu/lc58/lc58d.h b/src/devices/cpu/lc58/lc58d.h
new file mode 100644
index 00000000000..6a570c10f02
--- /dev/null
+++ b/src/devices/cpu/lc58/lc58d.h
@@ -0,0 +1,30 @@
+// license:BSD-3-Clause
+// copyright-holders:Olivier Galibert
+
+// Sanyo LC58 generic disassembler
+
+#ifndef MAME_CPU_LC58_LC58D_H
+#define MAME_CPU_LC58_LC58D_H
+
+#pragma once
+
+class lc58_disassembler : public util::disasm_interface
+{
+public:
+ lc58_disassembler() = default;
+ virtual ~lc58_disassembler() = default;
+
+ virtual u32 opcode_alignment() const override;
+ virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
+
+private:
+ struct instruction {
+ u16 value;
+ u16 mask;
+ u32 (*cb)(std::ostream &, const lc58_disassembler *, u16);
+ };
+
+ static const instruction instructions[];
+};
+
+#endif // MAME_CPU_LC58_LC58D_H
diff --git a/src/devices/cpu/m6502/n2a03.cpp b/src/devices/cpu/m6502/n2a03.cpp
index f303f1bf1b6..e1731b62e75 100644
--- a/src/devices/cpu/m6502/n2a03.cpp
+++ b/src/devices/cpu/m6502/n2a03.cpp
@@ -12,6 +12,7 @@
#include "n2a03.h"
#include "n2a03d.h"
+DEFINE_DEVICE_TYPE(N2A03_CORE, n2a03_core_device, "n2a03_core", "Ricoh N2A03 core") // needed for some VT systems with XOP instead of standard APU
DEFINE_DEVICE_TYPE(N2A03, n2a03_device, "n2a03", "Ricoh N2A03")
uint8_t n2a03_device::psg1_4014_r()
@@ -51,15 +52,29 @@ void n2a03_device::n2a03_map(address_map &map)
+n2a03_core_device::n2a03_core_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : m6502_device(mconfig, type, tag, owner, clock)
+{
+}
+
+n2a03_core_device::n2a03_core_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : n2a03_core_device(mconfig, N2A03_CORE, tag, owner, clock)
+{
+}
+
+
+
n2a03_device::n2a03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : m6502_device(mconfig, N2A03, tag, owner, clock)
+ : n2a03_core_device(mconfig, N2A03, tag, owner, clock)
, device_mixer_interface(mconfig, *this, 1)
, m_apu(*this, "nesapu")
{
program_config.m_internal_map = address_map_constructor(FUNC(n2a03_device::n2a03_map), this);
}
-std::unique_ptr<util::disasm_interface> n2a03_device::create_disassembler()
+
+
+std::unique_ptr<util::disasm_interface> n2a03_core_device::create_disassembler()
{
return std::make_unique<n2a03_disassembler>();
}
diff --git a/src/devices/cpu/m6502/n2a03.h b/src/devices/cpu/m6502/n2a03.h
index 5a57bcbed2b..4232093c7a5 100644
--- a/src/devices/cpu/m6502/n2a03.h
+++ b/src/devices/cpu/m6502/n2a03.h
@@ -15,22 +15,18 @@
#include "m6502.h"
#include "sound/nes_apu.h"
-class n2a03_device : public m6502_device, public device_mixer_interface {
+class n2a03_core_device : public m6502_device {
public:
- n2a03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ n2a03_core_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
virtual void do_exec_full() override;
virtual void do_exec_partial() override;
- uint8_t psg1_4014_r();
- uint8_t psg1_4015_r();
- void psg1_4015_w(uint8_t data);
- void psg1_4017_w(uint8_t data);
-
- void n2a03_map(address_map &map);
protected:
+ n2a03_core_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
#define O(o) void o ## _full(); void o ## _partial()
// n2a03 opcodes - same as 6502 with D disabled
@@ -42,6 +38,21 @@ protected:
#undef O
+private:
+};
+
+class n2a03_device : public n2a03_core_device, public device_mixer_interface {
+public:
+ n2a03_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ uint8_t psg1_4014_r();
+ uint8_t psg1_4015_r();
+ void psg1_4015_w(uint8_t data);
+ void psg1_4017_w(uint8_t data);
+
+ void n2a03_map(address_map &map);
+protected:
+
required_device<nesapu_device> m_apu;
virtual void device_add_mconfig(machine_config &config) override;
@@ -52,6 +63,7 @@ private:
};
+
/* These are the official XTAL values and clock rates used by Nintendo for
manufacturing throughout the production of the 2A03. PALC_APU_CLOCK is
the clock rate devised by UMC(?) for PAL Famicom clone hardware. */
@@ -69,6 +81,7 @@ enum {
N2A03_SET_OVERFLOW = m6502_device::V_LINE
};
+DECLARE_DEVICE_TYPE(N2A03_CORE, n2a03_core_device)
DECLARE_DEVICE_TYPE(N2A03, n2a03_device)
#endif // MAME_CPU_M6502_N2A03_H
diff --git a/src/devices/cpu/mcs48/mcs48.cpp b/src/devices/cpu/mcs48/mcs48.cpp
index 58f3d31b150..7aabcc4348a 100644
--- a/src/devices/cpu/mcs48/mcs48.cpp
+++ b/src/devices/cpu/mcs48/mcs48.cpp
@@ -15,6 +15,7 @@
- add special 8022 opcodes (RAD, SEL AN0, SEL AN1, RETI)
- according to the user manual, some opcodes(dis/enable timer/interrupt)
don't increment the timer, does it affect the prescaler too?
+ - IRQ timing is hacked due to WY-100 needing to take JNI branch before servicing interrupt
****************************************************************************
@@ -517,7 +518,7 @@ void mcs48_cpu_device::execute_call(uint16_t address)
conditional jump instruction
-------------------------------------------------*/
-void mcs48_cpu_device::execute_jcc(uint8_t result)
+void mcs48_cpu_device::execute_jcc(bool result)
{
uint16_t pch = m_pc & 0xf00;
uint8_t offset = argument_fetch();
@@ -747,8 +748,8 @@ OPHANDLER( jc ) { burn_cycles(2); execute_jcc((m_psw & C_FLAG) != 0)
OPHANDLER( jf0 ) { burn_cycles(2); execute_jcc((m_psw & F_FLAG) != 0); }
OPHANDLER( jf1 ) { burn_cycles(2); execute_jcc((m_sts & STS_F1) != 0); }
OPHANDLER( jnc ) { burn_cycles(2); execute_jcc((m_psw & C_FLAG) == 0); }
-OPHANDLER( jni ) { burn_cycles(2); execute_jcc(m_irq_state != 0); }
-OPHANDLER( jnibf ) { burn_cycles(2); execute_jcc((m_sts & STS_IBF) == 0); }
+OPHANDLER( jni ) { burn_cycles(2); m_irq_polled = (m_irq_state == 0); execute_jcc(m_irq_state != 0); }
+OPHANDLER( jnibf ) { burn_cycles(2); m_irq_polled = (m_sts & STS_IBF) != 0; execute_jcc((m_sts & STS_IBF) == 0); }
OPHANDLER( jnt_0 ) { burn_cycles(2); execute_jcc(test_r(0) == 0); }
OPHANDLER( jnt_1 ) { burn_cycles(2); execute_jcc(test_r(1) == 0); }
OPHANDLER( jnz ) { burn_cycles(2); execute_jcc(m_a != 0); }
@@ -1175,6 +1176,7 @@ void mcs48_cpu_device::device_start()
save_item(NAME(m_dbbo));
save_item(NAME(m_irq_state));
+ save_item(NAME(m_irq_polled));
save_item(NAME(m_irq_in_progress));
save_item(NAME(m_timer_overflow));
save_item(NAME(m_timer_flag));
@@ -1216,6 +1218,8 @@ void mcs48_cpu_device::device_reset()
/* confirmed from interrupt logic description */
m_irq_in_progress = false;
m_timer_overflow = false;
+
+ m_irq_polled = false;
}
@@ -1239,6 +1243,13 @@ void mcs48_cpu_device::check_irqs()
burn_cycles(2);
m_irq_in_progress = true;
+ // force JNI to be taken (hack)
+ if (m_irq_polled)
+ {
+ m_pc = ((m_prevpc + 1) & 0x7ff) | (m_prevpc & 0x800);
+ execute_jcc(true);
+ }
+
/* transfer to location 0x03 */
push_pc_psw();
m_pc = 0x03;
@@ -1324,6 +1335,10 @@ void mcs48_cpu_device::execute_run()
// iterate over remaining cycles, guaranteeing at least one instruction
do
{
+ // check interrupts
+ check_irqs();
+ m_irq_polled = false;
+
m_prevpc = m_pc;
debugger_instruction_hook(m_pc);
@@ -1331,9 +1346,6 @@ void mcs48_cpu_device::execute_run()
unsigned opcode = opcode_fetch();
(this->*m_opcode_table[opcode])();
- // check interrupts
- check_irqs();
-
} while (m_icount > 0);
}
diff --git a/src/devices/cpu/mcs48/mcs48.h b/src/devices/cpu/mcs48/mcs48.h
index fb78f63cc14..024c084c7f4 100644
--- a/src/devices/cpu/mcs48/mcs48.h
+++ b/src/devices/cpu/mcs48/mcs48.h
@@ -199,6 +199,7 @@ protected:
uint8_t m_dbbo; /* 8-bit output data buffer (UPI-41 only) */
bool m_irq_state; /* true if the IRQ line is active */
+ bool m_irq_polled; /* true if last instruction was JNI (and not taken) */
bool m_irq_in_progress; /* true if an IRQ is in progress */
bool m_timer_overflow; /* true on a timer overflow; cleared by taking interrupt */
bool m_timer_flag; /* true on a timer overflow; cleared on JTF */
@@ -257,7 +258,7 @@ protected:
void execute_addc(uint8_t dat);
void execute_jmp(uint16_t address);
void execute_call(uint16_t address);
- void execute_jcc(uint8_t result);
+ void execute_jcc(bool result);
uint8_t p2_mask();
void expander_operation(expander_op operation, uint8_t port);
void check_irqs();
diff --git a/src/devices/cpu/ns32000/ns32000.cpp b/src/devices/cpu/ns32000/ns32000.cpp
index 4b796f8f345..acfddfcdd29 100644
--- a/src/devices/cpu/ns32000/ns32000.cpp
+++ b/src/devices/cpu/ns32000/ns32000.cpp
@@ -14,14 +14,14 @@ DEFINE_DEVICE_TYPE(NS32032, ns32032_device, "ns32032", "National Semiconductor N
/*
* TODO:
* - prefetch queue
- * - fetch/ea/data/rmw cycles
+ * - fetch/ea/data/rmw bus cycles
* - address translation/abort
- * - floating point and other unimplemented instructions
+ * - unimplemented instructions
* - format 6: subp,addp
- * - format 7: cmpm
* - format 8: movus/movsu
+ * - format 14: rdval,wrval,lmr,smr
* - cascaded interrupts
- * - instruction cycles
+ * - opcode/operand/memory clock cycles
* - 32332, 32532
*/
@@ -71,22 +71,15 @@ enum trap_type : unsigned
UND = 10, // undefined opcode
};
-enum size_code : unsigned
-{
- SIZE_B = 0,
- SIZE_W = 1,
- SIZE_D = 3,
- SIZE_Q = 7,
-};
-
static const u32 size_mask[] = { 0x000000ffU, 0x0000ffffU, 0x00000000U, 0xffffffffU };
#define SP ((m_psr & PSR_S) ? m_sp1 : m_sp0)
-ns32000_device::ns32000_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int databits, int addrbits)
+template <int Width>ns32000_device<Width>::ns32000_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int databits, int addrbits)
: cpu_device(mconfig, type, tag, owner, clock)
, m_program_config("program", ENDIANNESS_LITTLE, databits, addrbits, 0)
, m_interrupt_config("interrupt", ENDIANNESS_LITTLE, databits, addrbits, 0)
+ , m_fpu(*this, finder_base::DUMMY_TAG)
, m_icount(0)
{
}
@@ -106,7 +99,7 @@ ns32032_device::ns32032_device(const machine_config &mconfig, const char *tag, d
{
}
-void ns32000_device::device_start()
+template <int Width> void ns32000_device<Width>::device_start()
{
set_icountptr(m_icount);
@@ -132,27 +125,27 @@ void ns32000_device::device_start()
state_add(STATE_GENFLAGS, "GENFLAGS", m_psr).mask(0xfe7).formatstr("%10s").noshow();
// dedicated registers
- int const reg_base = 16;
- state_add(reg_base + 0, "PC", m_pc);
- state_add(reg_base + 1, "SB", m_sb);
- state_add(reg_base + 2, "FP", m_fp);
- state_add(reg_base + 3, "SP1", m_sp1);
- state_add(reg_base + 4, "SP0", m_sp0);
- state_add(reg_base + 5, "INTBASE", m_intbase);
- state_add(reg_base + 6, "PSR", m_psr);
- state_add(reg_base + 7, "MOD", m_mod);
- state_add(reg_base + 8, "CFG", m_cfg);
+ int index = 0;
+ state_add(index++, "PC", m_pc);
+ state_add(index++, "SB", m_sb);
+ state_add(index++, "FP", m_fp);
+ state_add(index++, "SP1", m_sp1);
+ state_add(index++, "SP0", m_sp0);
+ state_add(index++, "INTBASE", m_intbase);
+ state_add(index++, "PSR", m_psr);
+ state_add(index++, "MOD", m_mod);
+ state_add(index++, "CFG", m_cfg);
// general registers
for (unsigned i = 0; i < 8; i++)
- state_add(i, util::string_format("R%d", i).c_str(), m_r[i]);
+ state_add(index++, util::string_format("R%d", i).c_str(), m_r[i]);
// floating point registers
- //for (unsigned i = 0; i < 8; i++)
- // state_add(8 + i, util::string_format("F%d", i).c_str(), m_f[i]);
+ if (m_fpu)
+ m_fpu->state_add(*this, index);
}
-void ns32000_device::device_reset()
+template <int Width> void ns32000_device<Width>::device_reset()
{
for (std::pair<int, address_space_config const *> s : memory_space_config())
space(has_configured_map(s.first) ? s.first : 0).cache(m_bus[s.first]);
@@ -166,7 +159,7 @@ void ns32000_device::device_reset()
m_wait = false;
}
-void ns32000_device::state_string_export(device_state_entry const &entry, std::string &str) const
+template <int Width> void ns32000_device<Width>::state_string_export(device_state_entry const &entry, std::string &str) const
{
switch (entry.index())
{
@@ -186,7 +179,7 @@ void ns32000_device::state_string_export(device_state_entry const &entry, std::s
}
}
-s32 ns32000_device::displacement(unsigned &bytes)
+template <int Width> s32 ns32000_device<Width>::displacement(unsigned &bytes)
{
s32 disp = space(0).read_byte(m_pc + bytes);
if (BIT(disp, 7))
@@ -214,7 +207,7 @@ s32 ns32000_device::displacement(unsigned &bytes)
return disp;
}
-void ns32000_device::decode(addr_mode *mode, unsigned imm_size, unsigned &bytes)
+template <int Width> void ns32000_device<Width>::decode(addr_mode *mode, unsigned &bytes)
{
bool scaled[] = { false, false };
@@ -277,12 +270,14 @@ void ns32000_device::decode(addr_mode *mode, unsigned imm_size, unsigned &bytes)
break;
case 0x14:
// immediate
- switch (imm_size)
+ switch (mode[i].size)
{
- case SIZE_B: mode[i].base = space(0).read_byte(m_pc + bytes); bytes += 1; break;
- case SIZE_W: mode[i].base = swapendian_int16(space(0).read_word_unaligned(m_pc + bytes)); bytes += 2; break;
- case SIZE_D: mode[i].base = swapendian_int32(space(0).read_dword_unaligned(m_pc + bytes)); bytes += 4; break;
+ case SIZE_B: mode[i].imm = space(0).read_byte(m_pc + bytes); break;
+ case SIZE_W: mode[i].imm = swapendian_int16(space(0).read_word_unaligned(m_pc + bytes)); break;
+ case SIZE_D: mode[i].imm = swapendian_int32(space(0).read_dword_unaligned(m_pc + bytes)); break;
+ case SIZE_Q: mode[i].imm = swapendian_int64(space(0).read_qword_unaligned(m_pc + bytes)); break;
}
+ bytes += mode[i].size + 1;
mode[i].type = IMM;
break;
case 0x15:
@@ -325,7 +320,7 @@ void ns32000_device::decode(addr_mode *mode, unsigned imm_size, unsigned &bytes)
}
}
-u32 ns32000_device::ea(addr_mode const mode)
+template <int Width> u32 ns32000_device<Width>::ea(addr_mode const mode)
{
u32 base;
@@ -352,38 +347,36 @@ u32 ns32000_device::ea(addr_mode const mode)
return base + mode.disp;
}
-u64 ns32000_device::gen_read(addr_mode mode, unsigned size)
+template <int Width> u64 ns32000_device<Width>::gen_read(addr_mode mode)
{
u64 data = 0;
switch (mode.type)
{
case IMM:
- data = mode.base;
+ data = mode.imm;
break;
case REG:
- if (size == SIZE_Q)
- data = (u64(m_r[mode.gen ^ 1]) << 32) | m_r[mode.gen ^ 0];
- else
- data = m_r[mode.gen] & size_mask[size];
+ data = m_r[mode.gen] & size_mask[mode.size];
break;
case TOS:
- if (size)
- if (size == 3)
- data = space(0).read_dword_unaligned(SP);
- else
- data = space(0).read_word_unaligned(SP);
- else
- data = space(0).read_byte(SP);
+ switch (mode.size)
+ {
+ case SIZE_B: data = space(0).read_byte(SP); break;
+ case SIZE_W: data = space(0).read_word_unaligned(SP); break;
+ case SIZE_D: data = space(0).read_dword_unaligned(SP); break;
+ case SIZE_Q: data = space(0).read_qword_unaligned(SP); break;
+ }
// post-increment stack pointer
- SP += size + 1;
+ if (mode.access == READ)
+ SP += mode.size + 1;
break;
default:
- switch (size)
+ switch (mode.size)
{
case SIZE_B: data = space(0).read_byte(ea(mode)); break;
case SIZE_W: data = space(0).read_word_unaligned(ea(mode)); break;
@@ -396,11 +389,11 @@ u64 ns32000_device::gen_read(addr_mode mode, unsigned size)
return data;
}
-s64 ns32000_device::gen_read_sx(addr_mode mode, unsigned size)
+template <int Width> s64 ns32000_device<Width>::gen_read_sx(addr_mode mode)
{
- u64 data = gen_read(mode, size);
+ u64 data = gen_read(mode);
- switch (size)
+ switch (mode.size)
{
case SIZE_B: data = s8(data); break;
case SIZE_W: data = s16(data); break;
@@ -411,35 +404,30 @@ s64 ns32000_device::gen_read_sx(addr_mode mode, unsigned size)
return data;
}
-void ns32000_device::gen_write(addr_mode mode, unsigned size, u64 data)
+template <int Width> void ns32000_device<Width>::gen_write(addr_mode mode, u64 data)
{
switch (mode.type)
{
case REG:
- if (size == SIZE_Q)
- {
- m_r[mode.gen ^ 0] = u32(data);
- m_r[mode.gen ^ 1] = data >> 32;
- }
- else
- m_r[mode.gen] = (m_r[mode.gen] & ~size_mask[size]) | (data & size_mask[size]);
+ m_r[mode.gen] = (m_r[mode.gen] & ~size_mask[mode.size]) | (data & size_mask[mode.size]);
break;
case TOS:
// pre-decrement stack pointer
- SP -= size + 1;
+ if (mode.access == WRITE)
+ SP -= mode.size + 1;
- if (size)
- if (size == 3)
- space(0).write_dword_unaligned(SP, data);
- else
- space(0).write_word_unaligned(SP, data);
- else
- space(0).write_byte(SP, data);
+ switch (mode.size)
+ {
+ case SIZE_B: space(0).write_byte(SP, data); break;
+ case SIZE_W: space(0).write_word_unaligned(SP, data); break;
+ case SIZE_D: space(0).write_dword_unaligned(SP, data); break;
+ case SIZE_Q: space(0).write_qword_unaligned(SP, data); break;
+ }
break;
default:
- switch (size)
+ switch (mode.size)
{
case SIZE_B: space(0).write_byte(ea(mode), data); break;
case SIZE_W: space(0).write_word_unaligned(ea(mode), data); break;
@@ -450,7 +438,7 @@ void ns32000_device::gen_write(addr_mode mode, unsigned size, u64 data)
}
}
-bool ns32000_device::condition(unsigned const cc)
+template <int Width> bool ns32000_device<Width>::condition(unsigned const cc)
{
switch (cc & 15)
{
@@ -492,7 +480,7 @@ bool ns32000_device::condition(unsigned const cc)
return false;
}
-void ns32000_device::flags(u32 const src1, u32 const src2, u32 const dest, unsigned const size, bool const subtraction)
+template <int Width> void ns32000_device<Width>::flags(u32 const src1, u32 const src2, u32 const dest, unsigned const size, bool const subtraction)
{
unsigned const sign_bit = (size + 1) * 8 - 1;
@@ -508,7 +496,7 @@ void ns32000_device::flags(u32 const src1, u32 const src2, u32 const dest, unsig
m_psr |= PSR_F;
}
-void ns32000_device::interrupt(unsigned const vector, u32 const return_address, bool const trap)
+template <int Width> void ns32000_device<Width>::interrupt(unsigned const vector, u32 const return_address, bool const trap)
{
// clear trace pending flag
if (vector == TRC)
@@ -541,9 +529,13 @@ void ns32000_device::interrupt(unsigned const vector, u32 const return_address,
m_pc = space(0).read_dword_unaligned(m_mod + 8) + u16(descriptor >> 16);
// TODO: flush queue
+ m_sequential = false;
+
+ if (trap && (machine().debug_flags & DEBUG_FLAG_ENABLED))
+ debug()->exception_hook(vector);
}
-void ns32000_device::execute_run()
+template <int Width> void ns32000_device<Width>::execute_run()
{
while (m_icount > 0)
{
@@ -597,18 +589,24 @@ void ns32000_device::execute_run()
u8 const opbyte = space(0).read_byte(m_pc);
unsigned bytes = 1;
+ unsigned tcy = 1;
+ m_sequential = true;
if ((opbyte & 15) == 10)
{
// format 0: cccc 1010
- // Bcond dest
+ // Bcond dst
// disp
- s32 const dest = displacement(bytes);
+ s32 const dst = displacement(bytes);
if (condition(opbyte >> 4))
- m_pc += dest;
+ {
+ m_pc += dst;
+ m_sequential = false;
+ tcy = 6;
+ }
else
- m_pc += bytes;
+ tcy = 7;
}
else if ((opbyte & 15) == 2)
{
@@ -616,15 +614,17 @@ void ns32000_device::execute_run()
switch (opbyte >> 4)
{
case 0x0:
- // BSR dest
+ // BSR dst
// disp
{
- s32 const dest = displacement(bytes);
+ s32 const dst = displacement(bytes);
SP -= 4;
space(0).write_dword_unaligned(SP, m_pc + bytes);
- m_pc += dest;
+ m_pc += dst;
+ m_sequential = false;
+ tcy = 6;
}
break;
case 0x1:
@@ -637,6 +637,8 @@ void ns32000_device::execute_run()
SP += 4 + constant;
m_pc = addr;
+ m_sequential = false;
+ tcy = 2;
}
break;
case 0x2:
@@ -656,6 +658,8 @@ void ns32000_device::execute_run()
m_mod = u16(descriptor);
m_sb = space(0).read_dword_unaligned(m_mod + 0);
m_pc = space(0).read_dword_unaligned(m_mod + 8) + u16(descriptor >> 16);
+ m_sequential = false;
+ tcy = 16;
}
break;
case 0x3:
@@ -671,6 +675,8 @@ void ns32000_device::execute_run()
m_sb = space(0).read_dword_unaligned(m_mod + 0);
SP += constant;
+ m_sequential = false;
+ tcy = 2;
}
break;
case 0x4:
@@ -691,6 +697,8 @@ void ns32000_device::execute_run()
m_sb = space(0).read_dword_unaligned(m_mod);
SP += constant;
+ m_sequential = false;
+ tcy = 35;
}
else
interrupt(ILL, m_pc);
@@ -711,6 +719,8 @@ void ns32000_device::execute_run()
sp += 2;
m_sb = space(0).read_dword_unaligned(m_mod);
+ m_sequential = false;
+ tcy = 39;
}
else
interrupt(ILL, m_pc);
@@ -721,16 +731,17 @@ void ns32000_device::execute_run()
{
u8 const reglist = space(0).read_byte(m_pc + bytes++);
+ tcy = 13;
for (unsigned i = 0; i < 8; i++)
{
if (BIT(reglist, i))
{
SP -= 4;
space(0).write_dword_unaligned(SP, m_r[i]);
+ tcy += 4;
}
}
}
- m_pc += bytes;
break;
case 0x7:
// RESTORE reglist
@@ -738,16 +749,17 @@ void ns32000_device::execute_run()
{
u8 const reglist = space(0).read_byte(m_pc + bytes++);
+ tcy = 12;
for (unsigned i = 0; i < 8; i++)
{
if (BIT(reglist, i))
{
m_r[7 - i] = space(0).read_dword_unaligned(SP);
SP += 4;
+ tcy += 5;
}
}
}
- m_pc += bytes;
break;
case 0x8:
// ENTER reglist,constant
@@ -761,16 +773,17 @@ void ns32000_device::execute_run()
m_fp = SP;
SP -= constant;
+ tcy = 18;
for (unsigned i = 0; i < 8; i++)
{
if (BIT(reglist, i))
{
SP -= 4;
space(0).write_dword_unaligned(SP, m_r[i]);
+ tcy += 4;
}
}
}
- m_pc += bytes;
break;
case 0x9:
// EXIT reglist
@@ -778,47 +791,54 @@ void ns32000_device::execute_run()
{
u8 const reglist = space(0).read_byte(m_pc + bytes++);
+ tcy = 17;
for (unsigned i = 0; i < 8; i++)
{
if (BIT(reglist, i))
{
m_r[7 - i] = space(0).read_dword_unaligned(SP);
SP += 4;
+ tcy += 5;
}
}
SP = m_fp;
m_fp = space(0).read_dword_unaligned(SP);
SP += 4;
}
- m_pc += bytes;
break;
case 0xa:
// NOP
- m_pc += bytes;
+ tcy = 3;
break;
case 0xb:
// WAIT
m_wait = true;
- m_pc += bytes;
+ tcy = 6;
break;
case 0xc:
// DIA
m_wait = true;
+ tcy = 3;
break;
case 0xd:
// FLAG
if (m_psr & PSR_F)
+ {
interrupt(FLG, m_pc);
+ tcy = 44;
+ }
else
- m_pc += bytes;
+ tcy = 6;
break;
case 0xe:
// SVC
interrupt(SVC, m_pc);
+ tcy = 40;
break;
case 0xf:
// BPT
interrupt(BPT, m_pc);
+ tcy = 40;
break;
}
}
@@ -832,187 +852,201 @@ void ns32000_device::execute_run()
addr_mode mode[] = { addr_mode((opword >> 11) & 31), addr_mode(0x13) };
unsigned const quick = (opword >> 7) & 15;
- unsigned const size = opbyte & 3;
-
- decode(mode, size, bytes);
+ size_code const size = size_code(opbyte & 3);
switch ((opbyte >> 4) & 7)
{
case 0:
- // ADDQi src,dest
+ // ADDQi src,dst
// quick,gen
// rmw.i
{
- mode[0].rmw();
+ mode[0].rmw_i(size);
+ decode(mode, bytes);
u32 const src1 = s32(quick << 28) >> 28;
- u32 const src2 = gen_read(mode[0], size);
+ u32 const src2 = gen_read(mode[0]);
- u32 const dest = src1 + src2;
- flags(src1, src2, dest, size, false);
+ u32 const dst = src1 + src2;
+ flags(src1, src2, dst, size, false);
- gen_write(mode[0], size, dest);
+ gen_write(mode[0], dst);
+
+ tcy = (mode[0].type == REG) ? 4 : 6;
}
- m_pc += bytes;
break;
case 1:
// CMPQi src1,src2
// quick,gen
// read.i
{
- u32 const src1 = s32(quick << 28) >> 28;
- u32 const src2 = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = (s32(quick << 28) >> 28) & size_mask[size];
+ u32 const src2 = gen_read(mode[0]);
m_psr &= ~(PSR_N | PSR_Z | PSR_L);
if ((size == SIZE_D && s32(src1) > s32(src2))
- || ((size == SIZE_W && s16(src1) > s16(src2))
- || ((size == SIZE_B && s8(src1) > s8(src2)))))
+ || ((size == SIZE_W && s16(src1) > s16(src2))
+ || ((size == SIZE_B && s8(src1) > s8(src2)))))
m_psr |= PSR_N;
if (src1 == src2)
m_psr |= PSR_Z;
if ((size == SIZE_D && u32(src1) > u32(src2))
- || ((size == SIZE_W && u16(src1) > u16(src2))
- || ((size == SIZE_B && u8(src1) > u8(src2)))))
+ || ((size == SIZE_W && u16(src1) > u16(src2))
+ || ((size == SIZE_B && u8(src1) > u8(src2)))))
m_psr |= PSR_L;
+
+ tcy = 3;
}
- m_pc += bytes;
break;
case 2:
- // SPRi procreg,dest
+ // SPRi procreg,dst
// short,gen
// write.i
+ mode[0].write_i(size);
+ decode(mode, bytes);
+
switch (quick)
{
case 0x0: // US
// TODO: user stack pointer?
- gen_write(mode[0], size, m_sp1);
- m_pc += bytes;
+ gen_write(mode[0], m_sp1);
break;
case 0x8: // FP
- gen_write(mode[0], size, m_fp);
- m_pc += bytes;
+ gen_write(mode[0], m_fp);
break;
case 0x9: // SP
- gen_write(mode[0], size, SP);
- m_pc += bytes;
+ gen_write(mode[0], SP);
break;
case 0xa: // SB
- gen_write(mode[0], size, m_sb);
- m_pc += bytes;
+ gen_write(mode[0], m_sb);
break;
case 0xd: // PSR
if (!(m_psr & PSR_U))
- {
- gen_write(mode[0], size, m_psr);
- m_pc += bytes;
- }
+ gen_write(mode[0], m_psr);
else
interrupt(ILL, m_pc);
break;
case 0xe: // INTBASE
if (!(m_psr & PSR_U))
- {
- gen_write(mode[0], size, m_intbase);
- m_pc += bytes;
- }
+ gen_write(mode[0], m_intbase);
else
interrupt(ILL, m_pc);
break;
case 0xf: // MOD
- gen_write(mode[0], size, m_mod);
- m_pc += bytes;
+ gen_write(mode[0], m_mod);
break;
}
+
+ // TODO: tcy 21-27
+ tcy = 21;
break;
case 3:
- // Scondi dest
+ // Scondi dst
// gen
// write.i
- gen_write(mode[0], size, condition(quick));
- m_pc += bytes;
+ {
+ mode[0].write_i(size);
+ decode(mode, bytes);
+
+ bool const dst = condition(quick);
+ gen_write(mode[0], dst);
+
+ tcy = dst ? 10 : 9;
+ }
break;
case 4:
- // ACBi inc,index,dest
+ // ACBi inc,index,dst
// quick,gen,disp
// rmw.i
{
- mode[0].rmw();
+ mode[0].rmw_i(size);
+ decode(mode, bytes);
s32 const inc = s32(quick << 28) >> 28;
- u32 index = gen_read(mode[0], size);
- s32 const dest = displacement(bytes);
+ u32 index = gen_read(mode[0]);
+ s32 const dst = displacement(bytes);
index += inc;
- gen_write(mode[0], size, index);
+ gen_write(mode[0], index);
if (index & size_mask[size])
- m_pc += dest;
+ {
+ m_pc += dst;
+ m_sequential = false;
+
+ tcy = (mode[0].type == REG) ? 17 : 15;
+ }
else
- m_pc += bytes;
+ tcy = (mode[0].type == REG) ? 18 : 16;
}
break;
case 5:
- // MOVQi src,dest
+ // MOVQi src,dst
// quick,gen
// write.i
- gen_write(mode[0], size, s32(quick << 28) >> 28);
- m_pc += bytes;
+ mode[0].write_i(size);
+ decode(mode, bytes);
+
+ gen_write(mode[0], s32(quick << 28) >> 28);
+
+ tcy = (mode[0].type == REG) ? 3 : 2;
break;
case 6:
// LPRi procreg,src
// short,gen
// read.i
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
switch (quick)
{
- case 0x0: // US
- // TODO: user stack pointer?
- m_sp1 = gen_read(mode[0], size);
- m_pc += bytes;
+ case 0x0: // UPSR
+ m_psr = (m_psr & 0xff00) | u8(gen_read(mode[0]));
break;
case 0x8: // FP
- m_fp = gen_read(mode[0], size);
- m_pc += bytes;
+ m_fp = gen_read(mode[0]);
break;
case 0x9: // SP
- SP = gen_read(mode[0], size);
- m_pc += bytes;
+ SP = gen_read(mode[0]);
break;
case 0xa: // SB
- m_sb = gen_read(mode[0], size);
- m_pc += bytes;
+ m_sb = gen_read(mode[0]);
break;
case 0xd: // PSR
if (!(m_psr & PSR_U))
{
- u32 const src = gen_read(mode[0], size);
+ u32 const src = gen_read(mode[0]);
- if (size == 0)
+ if (size == SIZE_B)
m_psr = (m_psr & 0xff00) | u8(src);
else
m_psr = src;
-
- m_pc += bytes;
}
else
interrupt(ILL, m_pc);
break;
case 0xe: // INTBASE
if (!(m_psr & PSR_U))
- {
- m_intbase = gen_read(mode[0], size);
- m_pc += bytes;
- }
+ m_intbase = gen_read(mode[0]);
else
interrupt(ILL, m_pc);
break;
case 0xf: // MOD
- m_mod = gen_read(mode[0], size);
- m_pc += bytes;
+ m_mod = gen_read(mode[0]);
+ break;
+ default:
+ interrupt(UND, m_pc);
break;
}
+
+ // TODO: tcy 19-33
+ tcy = 19;
break;
case 7:
// format 3: gggg gooo o111 11ii
@@ -1022,96 +1056,142 @@ void ns32000_device::execute_run()
// CXPD desc
// gen
// addr
+ if (size == SIZE_D)
{
mode[0].addr();
+ decode(mode, bytes);
- u32 const desc = gen_read(mode[0], SIZE_D);
+ u32 const descriptor = gen_read(mode[0]);
SP -= 4;
space(0).write_dword_unaligned(SP, m_mod);
SP -= 4;
space(0).write_dword_unaligned(SP, m_pc + bytes);
- m_mod = u16(desc);
+ m_mod = u16(descriptor);
m_sb = space(0).read_dword_unaligned(m_mod + 0);
- m_pc = u16(desc >> 16) + space(0).read_dword_unaligned(m_mod + 8);
+ m_pc = space(0).read_dword_unaligned(m_mod + 8) + u16(descriptor >> 16);
+ m_sequential = false;
+
+ tcy = 13;
}
+ else
+ interrupt(UND, m_pc);
break;
case 0x2:
// BICPSRi src
// gen
// read.[BW]
- if (size == 0 || !(m_psr & PSR_U))
+ if (size == SIZE_B || size == SIZE_W)
{
- // FIXME: read.D?
- u16 const src = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ if (size == SIZE_B || !(m_psr & PSR_U))
+ {
+ u16 const src = gen_read(mode[0]);
+
+ m_psr &= ~src;
- m_psr &= ~src;
- m_pc += bytes;
+ tcy = (size == SIZE_B) ? 18 : 30;
+ }
+ else
+ interrupt(ILL, m_pc);
}
else
- interrupt(ILL, m_pc);
+ interrupt(UND, m_pc);
break;
case 0x4:
- // JUMP dest
+ // JUMP dst
// gen
// addr
- mode[0].addr();
+ if (size == SIZE_D)
+ {
+ mode[0].addr();
+ decode(mode, bytes);
- // FIXME: size != 3?
- m_pc = ea(mode[0]);
+ m_pc = ea(mode[0]);
+ m_sequential = false;
+
+ tcy = 2;
+ }
+ else
+ interrupt(UND, m_pc);
break;
case 0x6:
// BISPSRi src
// gen
// read.[BW]
- if (size == 0 || !(m_psr & PSR_U))
+ if (size == SIZE_B || size == SIZE_W)
{
- // FIXME: read.D?
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ if (size == SIZE_B || !(m_psr & PSR_U))
+ {
+ u16 const src = gen_read(mode[0]);
- u16 const src = gen_read(mode[0], size);
+ m_psr |= src;
- m_psr |= src;
- m_pc += bytes;
+ tcy = (size == SIZE_B) ? 18 : 30;
+ }
+ else
+ interrupt(ILL, m_pc);
}
else
- interrupt(ILL, m_pc);
+ interrupt(UND, m_pc);
break;
case 0xa:
// ADJSPi src
// gen
// read.i
{
- s32 const src = gen_read_sx(mode[0], size);
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ s32 const src = gen_read_sx(mode[0]);
SP -= src;
+
+ tcy = 6;
}
- m_pc += bytes;
break;
case 0xc:
- // JSR dest
+ // JSR dst
// gen
// addr
+ if (size == SIZE_D)
{
mode[0].addr();
+ decode(mode, bytes);
SP -= 4;
space(0).write_dword_unaligned(SP, m_pc + bytes);
m_pc = ea(mode[0]);
+ m_sequential = false;
+
+ tcy = 5;
}
+ else
+ interrupt(UND, m_pc);
break;
case 0xe:
// CASEi src
// gen
// read.i
{
- s32 const src = gen_read_sx(mode[0], size);
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ s32 const src = gen_read_sx(mode[0]);
m_pc += src;
+ m_sequential = false;
+
+ tcy = 4;
}
break;
-
default:
interrupt(UND, m_pc);
break;
@@ -1126,175 +1206,214 @@ void ns32000_device::execute_run()
bytes = 2;
addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- unsigned const size = opbyte & 3;
-
- decode(mode, size, bytes);
+ size_code const size = size_code(opbyte & 3);
switch ((opbyte >> 2) & 15)
{
case 0x0:
- // ADDi src,dest
+ // ADDi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ u32 const dst = src1 + src2;
+ flags(src1, src2, dst, size, false);
- u32 const dest = src1 + src2;
- flags(src1, src2, dest, size, false);
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0x1:
// CMPi src1,src2
// gen,gen
// read.i,read.i
{
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ mode[0].read_i(size);
+ mode[1].read_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
m_psr &= ~(PSR_N | PSR_Z | PSR_L);
if ((size == SIZE_D && s32(src1) > s32(src2))
- || ((size == SIZE_W && s16(src1) > s16(src2))
- || ((size == SIZE_B && s8(src1) > s8(src2)))))
+ || ((size == SIZE_W && s16(src1) > s16(src2))
+ || ((size == SIZE_B && s8(src1) > s8(src2)))))
m_psr |= PSR_N;
if (src1 == src2)
m_psr |= PSR_Z;
if ((size == SIZE_D && u32(src1) > u32(src2))
- || ((size == SIZE_W && u16(src1) > u16(src2))
- || ((size == SIZE_B && u8(src1) > u8(src2)))))
+ || ((size == SIZE_W && u16(src1) > u16(src2))
+ || ((size == SIZE_B && u8(src1) > u8(src2)))))
m_psr |= PSR_L;
+
+ tcy = 3;
}
- m_pc += bytes;
break;
case 0x2:
- // BICi src,dest
+ // BICi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- u32 const src = gen_read(mode[0], size);
- u32 const dest = gen_read(mode[1], size);
+ gen_write(mode[1], dst & ~src);
- gen_write(mode[1], size, dest & ~src);
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0x4:
- // ADDCi src,dest
+ // ADDCi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ u32 const dst = src1 + src2 + (m_psr & PSR_C);
+ flags(src1, src2, dst, size, false);
- u32 const dest = src1 + src2 + (m_psr & PSR_C);
- flags(src1, src2, dest, size, false);
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0x5:
- // MOVi src,dest
+ // MOVi src,dst
// gen,gen
// read.i,write.i
{
- u32 const src = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- gen_write(mode[1], size, src);
+ u32 const src = gen_read(mode[0]);
+
+ gen_write(mode[1], src);
+
+ tcy = (mode[1].type == REG) ? 3 : 1;
}
- m_pc += bytes;
break;
case 0x6:
- // ORi src,dest
+ // ORi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- u32 const src = gen_read(mode[0], size);
- u32 const dest = gen_read(mode[1], size);
+ gen_write(mode[1], src | dst);
- gen_write(mode[1], size, src | dest);
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0x8:
- // SUBi src,dest
+ // SUBi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const dest = src2 - src1;
- flags(src1, src2, dest, size, true);
+ u32 const dst = src2 - src1;
+ flags(src1, src2, dst, size, true);
- gen_write(mode[1], size, dest);
+ gen_write(mode[1], dst);
+
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0x9:
- // ADDR src,dest
+ // ADDR src,dst
// gen,gen
// addr,write.D
- mode[0].addr();
+ if (size == SIZE_D)
+ {
+ mode[0].addr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ gen_write(mode[1], ea(mode[0]));
- gen_write(mode[1], SIZE_D, ea(mode[0]));
- m_pc += bytes;
+ tcy = (mode[1].type == REG) ? 3 : 2;
+ }
+ else
+ interrupt(UND, m_pc);
break;
case 0xa:
- // ANDi src,dest
+ // ANDi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- u32 const src = gen_read(mode[0], size);
- u32 const dest = gen_read(mode[1], size);
+ gen_write(mode[1], src & dst);
- gen_write(mode[1], size, src & dest);
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0xc:
- // SUBCi src,dest
+ // SUBCi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const dest = src2 - src1 - (m_psr & PSR_C);
- flags(src1, src2, dest, size, true);
+ u32 const dst = src2 - src1 - (m_psr & PSR_C);
+ flags(src1, src2, dst, size, true);
- gen_write(mode[1], size, dest);
+ gen_write(mode[1], dst);
+
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
case 0xd:
// TBITi offset,base
// gen,gen
// read.i,regaddr
{
+ mode[0].read_i(size);
mode[1].regaddr();
+ decode(mode, bytes);
- s32 const offset = gen_read_sx(mode[0], size);
+ s32 const offset = gen_read_sx(mode[0]);
if (mode[1].type == REG)
{
@@ -1302,6 +1421,8 @@ void ns32000_device::execute_run()
m_psr |= PSR_F;
else
m_psr &= ~PSR_F;
+
+ tcy = 4;
}
else
{
@@ -1311,23 +1432,27 @@ void ns32000_device::execute_run()
m_psr |= PSR_F;
else
m_psr &= ~PSR_F;
+
+ tcy = 14;
}
}
- m_pc += bytes;
break;
case 0xe:
- // XORi src,dest
+ // XORi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u32 const src = gen_read(mode[0], size);
- u32 const dest = gen_read(mode[1], size);
+ u32 const src = gen_read(mode[0]);
+ u32 const dst = gen_read(mode[1]);
- gen_write(mode[1], size, src ^ dest);
+ gen_write(mode[1], src ^ dst);
+
+ tcy = (mode[1].type == REG) ? 4 : 3;
}
- m_pc += bytes;
break;
}
}
@@ -1339,7 +1464,7 @@ void ns32000_device::execute_run()
u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
bytes += 2;
- unsigned const size = opword & 3;
+ size_code const size = size_code(opword & 3);
// string instruction options
bool const translate = BIT(opword, 7);
@@ -1350,6 +1475,8 @@ void ns32000_device::execute_run()
{
case 0:
// MOVSi options
+ tcy = (translate || backward || uw) ? 54 : 18;
+
m_psr &= ~PSR_F;
while (m_r[0])
{
@@ -1361,6 +1488,8 @@ void ns32000_device::execute_run()
if (translate)
data = space(0).read_byte(m_r[3] + u8(data));
+ tcy += translate ? 27 : (backward || uw) ? 24 : 13;
+
bool const match = !((m_r[4] ^ data) & size_mask[size]);
if ((uw == 1 && !match) || (uw == 3 && match))
{
@@ -1388,10 +1517,11 @@ void ns32000_device::execute_run()
m_r[0]--;
}
- m_pc += bytes;
break;
case 1:
// CMPSi options
+ tcy = 53;
+
m_psr |= PSR_Z;
m_psr &= ~(PSR_N | PSR_F | PSR_L);
while (m_r[0])
@@ -1408,6 +1538,8 @@ void ns32000_device::execute_run()
if (translate)
src1 = space(0).read_byte(m_r[3] + u8(src1));
+ tcy += translate ? 38 : 35;
+
bool const match = !((m_r[4] ^ src1) & size_mask[size]);
if ((uw == 1 && !match) || (uw == 3 && match))
{
@@ -1420,13 +1552,13 @@ void ns32000_device::execute_run()
m_psr &= ~PSR_Z;
if ((size == SIZE_D && s32(src1) > s32(src2))
- || ((size == SIZE_W && s16(src1) > s16(src2))
- || ((size == SIZE_B && s8(src1) > s8(src2)))))
+ || ((size == SIZE_W && s16(src1) > s16(src2))
+ || ((size == SIZE_B && s8(src1) > s8(src2)))))
m_psr |= PSR_N;
if ((size == SIZE_D && u32(src1) > u32(src2))
- || ((size == SIZE_W && u16(src1) > u16(src2))
- || ((size == SIZE_B && u8(src1) > u8(src2)))))
+ || ((size == SIZE_W && u16(src1) > u16(src2))
+ || ((size == SIZE_B && u8(src1) > u8(src2)))))
m_psr |= PSR_L;
break;
@@ -1445,7 +1577,6 @@ void ns32000_device::execute_run()
m_r[0]--;
}
- m_pc += bytes;
break;
case 2:
// SETCFG cfglist
@@ -1453,13 +1584,16 @@ void ns32000_device::execute_run()
if (!(m_psr & PSR_U))
{
m_cfg = (opword >> 7) & 15;
- m_pc += bytes;
+
+ tcy = 15;
}
else
interrupt(ILL, m_pc);
break;
case 3:
// SKPSi options
+ tcy = 51;
+
m_psr &= ~PSR_F;
while (m_r[0])
{
@@ -1471,6 +1605,8 @@ void ns32000_device::execute_run()
if (translate)
data = space(0).read_byte(m_r[3] + u8(data));
+ tcy += translate ? 30 : 27;
+
bool const match = !((m_r[4] ^ data) & size_mask[size]);
if ((uw == 1 && !match) || (uw == 3 && match))
{
@@ -1485,7 +1621,6 @@ void ns32000_device::execute_run()
m_r[0]--;
}
- m_pc += bytes;
break;
default:
interrupt(UND, m_pc);
@@ -1500,45 +1635,48 @@ void ns32000_device::execute_run()
bytes += 2;
addr_mode mode[] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- unsigned const size = opword & 3;
-
- // byte-size immediates for ROT, ASH and LSH
- decode(mode, ((opword >> 2) & 10) ? size : SIZE_B, bytes);
+ size_code const size = size_code(opword & 3);
switch ((opword >> 2) & 15)
{
case 0x0:
- // ROTi count,dest
+ // ROTi count,dst
// gen,gen
// read.B,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(SIZE_B);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- s32 const count = gen_read_sx(mode[0], SIZE_B);
- u32 const src = gen_read(mode[1], size);
+ s32 const count = gen_read_sx(mode[0]);
+ u32 const src = gen_read(mode[1]);
unsigned const limit = (size + 1) * 8 - 1;
- u32 const dest = ((src << (count & limit)) & size_mask[size]) | ((src & size_mask[size]) >> (limit - (count & limit)));
+ u32 const dst = ((src << (count & limit)) & size_mask[size]) | ((src & size_mask[size]) >> (limit - (count & limit) + 1));
+
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
+ tcy = 14 + (count & limit);
}
- m_pc += bytes;
break;
case 0x1:
- // ASHi count,dest
+ // ASHi count,dst
// gen,gen
// read.B,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(SIZE_B);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- s32 const count = gen_read_sx(mode[0], SIZE_B);
- s32 const src = gen_read_sx(mode[1], size);
+ s32 const count = gen_read_sx(mode[0]);
+ s32 const src = gen_read_sx(mode[1]);
- u32 const dest = (count < 0) ? (src >> -count) : (src << count);
+ u32 const dst = (count < 0) ? (src >> -count) : (src << count);
- gen_write(mode[1], size, dest);
+ gen_write(mode[1], dst);
+
+ tcy = 14 + std::abs(count);
}
- m_pc += bytes;
break;
case 0x2:
// CBITi offset,base
@@ -1549,9 +1687,11 @@ void ns32000_device::execute_run()
// gen,gen
// read.i,regaddr
{
+ mode[0].read_i(size);
mode[1].regaddr();
+ decode(mode, bytes);
- s32 const offset = gen_read_sx(mode[0], size);
+ s32 const offset = gen_read_sx(mode[0]);
if (mode[1].type == REG)
{
@@ -1561,6 +1701,8 @@ void ns32000_device::execute_run()
m_psr &= ~PSR_F;
m_r[mode[1].gen] &= ~(1U << (offset & 31));
+
+ tcy = 7;
}
else
{
@@ -1573,28 +1715,32 @@ void ns32000_device::execute_run()
m_psr &= ~PSR_F;
space(0).write_byte(byte_ea, byte & ~(1U << (offset & 7)));
+
+ tcy = 15;
}
}
- m_pc += bytes;
break;
case 0x4:
interrupt(UND, m_pc);
break;
case 0x5:
- // LSHi count,dest
+ // LSHi count,dst
// gen,gen
// read.B,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(SIZE_B);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
+
+ s32 const count = gen_read_sx(mode[0]);
+ u32 const src = gen_read(mode[1]);
- s32 const count = gen_read_sx(mode[0], SIZE_B);
- u32 const src = gen_read(mode[1], size);
+ u32 const dst = (count < 0) ? (src >> -count) : (src << count);
- u32 const dest = (count < 0) ? (src >> -count) : (src << count);
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
+ tcy = 14 + std::abs(count);
}
- m_pc += bytes;
break;
case 0x6:
// SBITi offset,base
@@ -1605,9 +1751,11 @@ void ns32000_device::execute_run()
// gen,gen
// read.i,regaddr
{
+ mode[0].read_i(size);
mode[1].regaddr();
+ decode(mode, bytes);
- s32 const offset = gen_read_sx(mode[0], size);
+ s32 const offset = gen_read_sx(mode[0]);
if (mode[1].type == REG)
{
@@ -1616,7 +1764,9 @@ void ns32000_device::execute_run()
else
m_psr &= ~PSR_F;
- m_r[mode[1].gen] |= ~(1U << (offset & 31));
+ m_r[mode[1].gen] |= (1U << (offset & 31));
+
+ tcy = 7;
}
else
{
@@ -1628,17 +1778,22 @@ void ns32000_device::execute_run()
else
m_psr &= ~PSR_F;
- space(0).write_byte(byte_ea, byte | ~(1U << (offset & 7)));
+ space(0).write_byte(byte_ea, byte | (1U << (offset & 7)));
+
+ tcy = 15;
}
}
- m_pc += bytes;
break;
case 0x8:
- // NEGi src,dest
+ // NEGi src,dst
// gen,gen
// read.i,write.i
{
- u32 const src = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
if (src)
m_psr |= PSR_C;
@@ -1648,75 +1803,93 @@ void ns32000_device::execute_run()
if ((src ^ ~(size_mask[size] >> 1)) & size_mask[size])
{
m_psr &= ~PSR_F;
- gen_write(mode[1], size, -src);
+ gen_write(mode[1], -src);
}
else
{
m_psr |= PSR_F;
- gen_write(mode[1], size, src);
+ gen_write(mode[1], src);
}
+
+ tcy = 5;
}
- m_pc += bytes;
break;
case 0x9:
- // NOTi src,dest
+ // NOTi src,dst
// gen,gen
// read.i,write.i
{
- u32 const src = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- gen_write(mode[1], size, src ^ 1U);
+ u32 const src = gen_read(mode[0]);
+
+ gen_write(mode[1], src ^ 1U);
+
+ tcy = 5;
}
- m_pc += bytes;
break;
case 0xa:
interrupt(UND, m_pc);
break;
case 0xb:
- // SUBPi src,dest
+ // SUBPi src,dst
// gen,gen
// read.i,rmw.i
fatalerror("unimplemented: subp (%s)\n", machine().describe_context());
+
+ // TODO: tcy 16/18
break;
case 0xc:
- // ABSi src,dest
+ // ABSi src,dst
// gen,gen
// read.i,write.i
{
- s32 const src = gen_read_sx(mode[0], size);
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
- s32 const dest = std::abs(src);
+ s32 const src = gen_read_sx(mode[0]);
m_psr &= ~PSR_F;
- if (BIT(dest, ((size + 1) * 8 - 1)))
+ if (src == s32(0x80000000) >> (32 - (size + 1) * 8))
{
m_psr |= PSR_F;
- gen_write(mode[1], size, src);
+ gen_write(mode[1], src);
}
else
- gen_write(mode[1], size, dest);
+ gen_write(mode[1], std::abs(src));
+
+ tcy = (src < 0) ? 9 : 8;
}
- m_pc += bytes;
break;
case 0xd:
- // COMi src,dest
+ // COMi src,dst
// gen,gen
// read.i,write.i
{
- u32 const src = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ u32 const src = gen_read(mode[0]);
+
+ gen_write(mode[1], ~src);
- gen_write(mode[1], size, ~src);
+ tcy = 7;
}
- m_pc += bytes;
break;
case 0xe:
// IBITi offset,base
// gen,gen
// read.i,regaddr
{
+ mode[0].read_i(size);
mode[1].regaddr();
+ decode(mode, bytes);
- s32 const offset = gen_read_sx(mode[0], size);
+ s32 const offset = gen_read_sx(mode[0]);
if (mode[1].type == REG)
{
@@ -1726,6 +1899,8 @@ void ns32000_device::execute_run()
m_psr &= ~PSR_F;
m_r[mode[1].gen] ^= (1U << (offset & 31));
+
+ tcy = 9;
}
else
{
@@ -1738,15 +1913,18 @@ void ns32000_device::execute_run()
m_psr &= ~PSR_F;
space(0).write_byte(byte_ea, byte ^ (1U << (offset & 7)));
+
+ tcy = 17;
}
}
- m_pc += bytes;
break;
case 0xf:
- // ADDPi src,dest
+ // ADDPi src,dst
// gen,gen
// read.i,rmw.i
fatalerror("unimplemented: addp (%s)\n", machine().describe_context());
+
+ // TODO: tcy 16/18
break;
}
}
@@ -1758,9 +1936,7 @@ void ns32000_device::execute_run()
bytes += 2;
addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
- unsigned const size = opword & 3;
-
- decode(mode, size, bytes);
+ size_code const size = size_code(opword & 3);
switch ((opword >> 2) & 15)
{
@@ -1771,164 +1947,280 @@ void ns32000_device::execute_run()
{
mode[0].addr();
mode[1].addr();
+ decode(mode, bytes);
u32 block1 = ea(mode[0]);
u32 block2 = ea(mode[1]);
- s32 length = displacement(bytes);
+ unsigned const num = displacement(bytes) / (size + 1) + 1;
// TODO: aligned/unaligned transfers?
- for (unsigned num = 0; num * (size + 1) < length; num++)
+ for (unsigned i = 0; i < num; i++)
{
switch (size)
{
case SIZE_B: space(0).write_byte(block2, space(0).read_byte(block1)); break;
case SIZE_W: space(0).write_word_unaligned(block2, space(0).read_word_unaligned(block1)); break;
case SIZE_D: space(0).write_dword_unaligned(block2, space(0).read_dword_unaligned(block1)); break;
+ default:
+ // can't happen
+ break;
}
block1 += (size + 1);
block2 += (size + 1);
}
+
+ tcy = 20 + 3 * num;
}
- m_pc += bytes;
break;
case 0x1:
// CMPMi block1,block2,length
// gen,gen,disp
// addr,addr
- fatalerror("unimplemented: cmpm (%s)\n", machine().describe_context());
+ {
+ mode[0].addr();
+ mode[1].addr();
+ decode(mode, bytes);
+
+ u32 block1 = ea(mode[0]);
+ u32 block2 = ea(mode[1]);
+ unsigned const num = displacement(bytes) / (size + 1) + 1;
+
+ tcy = 24;
+
+ m_psr |= PSR_Z;
+ m_psr &= ~(PSR_N | PSR_L);
+
+ // TODO: aligned/unaligned transfers?
+ for (unsigned i = 0; i < num; i++)
+ {
+ s32 int1 = 0;
+ s32 int2 = 0;
+
+ switch (size)
+ {
+ case SIZE_B:
+ int1 = s8(space(0).read_byte(block1));
+ int2 = s8(space(0).read_byte(block2));
+ break;
+ case SIZE_W:
+ int1 = s16(space(0).read_word_unaligned(block1));
+ int2 = s16(space(0).read_word_unaligned(block2));
+ break;
+ case SIZE_D:
+ int1 = s32(space(0).read_dword_unaligned(block1));
+ int2 = s32(space(0).read_dword_unaligned(block2));
+ break;
+ default:
+ // can't happen
+ break;
+ }
+
+ tcy += 9;
+
+ if (int1 != int2)
+ {
+ m_psr &= ~PSR_Z;
+ if (int1 > int2)
+ m_psr |= PSR_N;
+ if (u32(int1) > u32(int2))
+ m_psr |= PSR_L;
+
+ break;
+ }
+
+ block1 += (size + 1);
+ block2 += (size + 1);
+ }
+ }
break;
case 0x2:
// INSSi src,base,offset,length
// gen,gen,imm
// read.i,regaddr
{
+ mode[0].read_i(size);
mode[1].regaddr();
+ decode(mode, bytes);
u8 const imm = space(0).read_byte(m_pc + bytes++);
unsigned const offset = imm >> 5;
u32 const mask = ((2ULL << (imm & 31)) - 1) << offset;
- u32 const src = gen_read(mode[0], size);
- u32 const base = gen_read(mode[1], SIZE_D);
+ u32 const src = gen_read(mode[0]);
+ u32 const base = gen_read(mode[1]);
- gen_write(mode[1], SIZE_D, (base & ~mask) | ((src << offset) & mask));
+ gen_write(mode[1], (base & ~mask) | ((src << offset) & mask));
+
+ // TODO: tcy 39-49
+ tcy = 39;
}
- m_pc += bytes;
break;
case 0x3:
- // EXTSi base,dest,offset,length
+ // EXTSi base,dst,offset,length
// gen,gen,imm
// regaddr,write.i
{
mode[0].regaddr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
u8 const imm = space(0).read_byte(m_pc + bytes++);
unsigned const offset = imm >> 5;
u32 const mask = (2ULL << (imm & 31)) - 1;
- u32 const base = gen_read(mode[0], SIZE_D);
- u32 const dest = (base >> offset) & mask;
+ u32 const base = gen_read(mode[0]);
+ u32 const dst = (base >> offset) & mask;
+
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
+ // TODO: tcy 26-36
+ tcy = 26;
}
- m_pc += bytes;
break;
case 0x4:
- // MOVXBW src,dest
+ // MOVXBW src,dst
// gen,gen
// read.B,write.W
+ if (size == SIZE_B)
{
- u8 const src = gen_read(mode[0], size);
- s16 const dest = s8(src);
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_W);
+ decode(mode, bytes);
+
+ u8 const src = gen_read(mode[0]);
+ s16 const dst = s8(src);
- gen_write(mode[1], SIZE_W, dest);
+ gen_write(mode[1], dst);
+
+ tcy = 6;
}
- m_pc += bytes;
+ else
+ interrupt(UND, m_pc);
break;
case 0x5:
- // MOVZBW src,dest
+ // MOVZBW src,dst
// gen,gen
// read.B,write.W
+ if (size == SIZE_B)
{
- u8 const src = gen_read(mode[0], size);
- u16 const dest = src;
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_W);
+ decode(mode, bytes);
+
+ u8 const src = gen_read(mode[0]);
+ u16 const dst = src;
- gen_write(mode[1], SIZE_W, dest);
+ gen_write(mode[1], dst);
+
+ tcy = 5;
}
- m_pc += bytes;
+ else
+ interrupt(UND, m_pc);
break;
case 0x6:
- // MOVZiD src,dest
+ // MOVZiD src,dst
// gen,gen
// read.[BW],write.D
+ if (size == SIZE_B || size == SIZE_W)
{
- u32 const src = gen_read(mode[0], size);
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_D);
+ decode(mode, bytes);
- gen_write(mode[1], SIZE_D, src);
+ u32 const src = gen_read(mode[0]);
+
+ gen_write(mode[1], src);
+
+ tcy = 5;
}
- m_pc += bytes;
+ else
+ interrupt(UND, m_pc);
break;
case 0x7:
- // MOVXiD src,dest
+ // MOVXiD src,dst
// gen,gen
// read.[BW],write.D
+ if (size == SIZE_B || size == SIZE_W)
{
- u32 const src = gen_read(mode[0], size);
- s32 const dest = (size == SIZE_W) ? s16(src) : s8(src);
+ mode[0].read_i(size);
+ mode[1].write_i(SIZE_D);
+ decode(mode, bytes);
- gen_write(mode[1], SIZE_D, dest);
+ u32 const src = gen_read(mode[0]);
+ s32 const dst = (size == SIZE_W) ? s16(src) : s8(src);
+
+ gen_write(mode[1], dst);
+
+ tcy = 6;
}
- m_pc += bytes;
+ else
+ interrupt(UND, m_pc);
break;
case 0x8:
- // MULi src,dest
+ // MULi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = gen_read(mode[1]);
- u32 const dest = src1 * src2;
+ u32 const dst = src1 * src2;
- gen_write(mode[1], size, dest);
+ gen_write(mode[1], dst);
+
+ tcy = 15;
}
- m_pc += bytes;
break;
case 0x9:
- // MEIi src,dest
+ // MEIi src,dst
// gen,gen
// read.i,rmw.2i
{
- mode[1].rmw();
- unsigned const size2 = size * 2 + 1;
+ mode[0].read_i(size);
+ mode[1].rmw_i(size_code(size * 2 + 1));
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0], size);
- u32 const src2 = gen_read(mode[1], size);
+ u32 const src1 = gen_read(mode[0]);
+ u32 const src2 = ((mode[1].type == REG)
+ ? m_r[mode[1].gen ^ 0]
+ : gen_read(mode[1])) & size_mask[size];
- u64 const dest = mulu_32x32(src1, src2);
+ u64 const dst = mulu_32x32(src1, src2);
- gen_write(mode[1], size2, dest);
+ if (mode[1].type == REG)
+ {
+ m_r[mode[1].gen ^ 0] = (m_r[mode[1].gen ^ 0] & ~size_mask[size]) | ((dst >> 0) & size_mask[size]);
+ m_r[mode[1].gen ^ 1] = (m_r[mode[1].gen ^ 1] & ~size_mask[size]) | ((dst >> ((size + 1) * 8)) & size_mask[size]);
+ }
+ else
+ gen_write(mode[1], dst);
+
+ tcy = 23;
}
- m_pc += bytes;
break;
case 0xa:
interrupt(UND, m_pc);
break;
case 0xb:
- // DEIi src,dest
+ // DEIi src,dst
// gen,gen
// read.i,rmw.2i
{
- mode[1].rmw();
- unsigned const size2 = size * 2 + 1;
+ mode[0].read_i(size);
+ mode[1].rmw_i(size_code(size * 2 + 1));
+ decode(mode, bytes);
- u32 const src1 = gen_read(mode[0], size);
+ u32 const src1 = gen_read(mode[0]);
if (src1)
{
- u64 const src2 = gen_read(mode[1], size2);
+ u64 const src2 = (mode[1].type == REG)
+ ? (u64(m_r[mode[1].gen ^ 1] & size_mask[size]) << ((size + 1) * 8)) | (m_r[mode[1].gen ^ 0] & size_mask[size])
+ : gen_read(mode[1]);
u32 const quotient = src2 / src1;
u32 const remainder = src2 % src1;
@@ -1937,11 +2229,15 @@ void ns32000_device::execute_run()
{
m_r[mode[1].gen ^ 0] = (m_r[mode[1].gen ^ 0] & ~size_mask[size]) | (remainder & size_mask[size]);
m_r[mode[1].gen ^ 1] = (m_r[mode[1].gen ^ 1] & ~size_mask[size]) | (quotient & size_mask[size]);
+
+ tcy = 31;
}
else
- gen_write(mode[1], size2, (u64(quotient) << ((size + 1) * 8)) | remainder);
+ {
+ gen_write(mode[1], (u64(quotient) << ((size + 1) * 8)) | remainder);
- m_pc += bytes;
+ tcy = 38;
+ }
}
else
{
@@ -1954,21 +2250,25 @@ void ns32000_device::execute_run()
}
break;
case 0xc:
- // QUOi src,dest
+ // QUOi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- s32 const src1 = gen_read_sx(mode[0], size);
+ s32 const src1 = gen_read_sx(mode[0]);
if (src1)
{
- s32 const src2 = gen_read_sx(mode[1], size);
+ s32 const src2 = gen_read_sx(mode[1]);
+
+ s32 const dst = src2 / src1;
- s32 const dest = src2 / src1;
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
- m_pc += bytes;
+ // TODO: tcy 49-55
+ tcy = 49;
}
else
{
@@ -1981,21 +2281,25 @@ void ns32000_device::execute_run()
}
break;
case 0xd:
- // REMi src,dest
+ // REMi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- s32 const src1 = gen_read_sx(mode[0], size);
+ s32 const src1 = gen_read_sx(mode[0]);
if (src1)
{
- s32 const src2 = gen_read_sx(mode[1], size);
+ s32 const src2 = gen_read_sx(mode[1]);
+
+ s32 const dst = src2 % src1;
- s32 const dest = src2 % src1;
+ gen_write(mode[1], dst);
- gen_write(mode[1], size, dest);
- m_pc += bytes;
+ // TODO: tcy 57-62
+ tcy = 57;
}
else
{
@@ -2008,21 +2312,25 @@ void ns32000_device::execute_run()
}
break;
case 0xe:
- // MODi src,dest
+ // MODi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- u32 const src1 = gen_read_sx(mode[0], size);
+ s32 const src1 = gen_read_sx(mode[0]);
if (src1)
{
- u32 const src2 = gen_read_sx(mode[1], size);
+ s32 const src2 = gen_read_sx(mode[1]);
- s32 const dest = (src1 + (src2 % src1)) % src1;
+ s32 const dst = (src1 + (src2 % src1)) % src1;
- gen_write(mode[1], size, dest);
- m_pc += bytes;
+ gen_write(mode[1], dst);
+
+ // TODO: tcy 54-73
+ tcy = 54;
}
else
{
@@ -2035,26 +2343,29 @@ void ns32000_device::execute_run()
}
break;
case 0xf:
- // DIVi src,dest
+ // DIVi src,dst
// gen,gen
// read.i,rmw.i
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(size);
+ decode(mode, bytes);
- s32 const src1 = gen_read_sx(mode[0], size);
+ s32 const src1 = gen_read_sx(mode[0]);
if (src1)
{
- s32 const src2 = gen_read_sx(mode[1], size);
+ s32 const src2 = gen_read_sx(mode[1]);
s32 const quotient = src2 / src1;
s32 const remainder = src2 % src1;
if ((quotient < 0) && remainder)
- gen_write(mode[1], size, quotient - 1);
+ gen_write(mode[1], quotient - 1);
else
- gen_write(mode[1], size, quotient);
+ gen_write(mode[1], quotient);
- m_pc += bytes;
+ // TODO: tcy 58-68
+ tcy = 58;
}
else
{
@@ -2080,108 +2391,150 @@ void ns32000_device::execute_run()
addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
unsigned const reg = (opword >> 3) & 7;
- unsigned const size = opword & 3;
-
- decode(mode, size, bytes);
+ size_code const size = size_code(opword & 3);
switch ((opword & 4) | (opbyte >> 6))
{
case 0:
- // EXTi offset,base,dest,length
+ // EXTi offset,base,dst,length
// reg,gen,gen,disp
// regaddr,write.i
{
mode[0].regaddr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
s32 const offset = m_r[reg];
s32 const length = displacement(bytes);
u32 const mask = (1U << length) - 1;
- u32 dest;
+ u32 dst;
if (mode[0].type != REG)
{
u32 const base_ea = ea(mode[0]) + (offset >> 3);
u32 const base = space(0).read_dword_unaligned(base_ea);
- dest = (base >> (offset & 7));
+ dst = (base >> (offset & 7));
+
+ // TODO: tcy 17-51
+ tcy = 17;
}
else
- dest = (m_r[mode[0].gen] >> (offset & 31));
+ {
+ dst = (m_r[mode[0].gen] >> (offset & 31));
+
+ // TODO: tcy 19-29
+ tcy = 19;
+ }
- gen_write(mode[1], size, dest & mask);
+ gen_write(mode[1], dst & mask);
}
break;
case 1:
- // CVTP offset,base,dest
+ // CVTP offset,base,dst
// reg,gen,gen
// addr,write.D
+ if (size == SIZE_D)
{
- // TODO: size != SIZE_D?
mode[0].addr();
+ mode[1].write_i(size);
+ decode(mode, bytes);
s32 const offset = s32(m_r[reg]);
u32 const base = ea(mode[0]);
- gen_write(mode[1], size, base * 8 + offset);
+ gen_write(mode[1], base * 8 + offset);
+
+ tcy = 7;
}
+ else
+ interrupt(UND, m_pc);
break;
case 2:
// INSi offset,src,base,length
// reg,gen,gen,disp
// read.i,regaddr
{
+ mode[0].read_i(size);
mode[1].regaddr();
+ decode(mode, bytes);
s32 const offset = m_r[reg];
s32 const length = displacement(bytes);
- u32 const src = gen_read(mode[0], size);
+ u32 const src = gen_read(mode[0]);
- u32 dest;
+ u32 dst;
if (mode[1].type == REG)
{
u32 const base = m_r[mode[1].gen];
u32 const mask = ((1U << length) - 1) << (offset & 31);
- dest = (base & ~mask) | ((src << (offset & 31)) & mask);
+ dst = (base & ~mask) | ((src << (offset & 31)) & mask);
+
+ // TODO: tcy 29-39
+ tcy = 29;
}
else
{
- u32 const base_ea = ea(mode[0]) + (offset >> 3);
+ u32 const base_ea = ea(mode[1]) + (offset >> 3);
u32 const base = space(0).read_dword_unaligned(base_ea);
u32 const mask = ((1U << length) - 1) << (offset & 7);
- dest = (base & ~mask) | ((src << (offset & 7)) & mask);
+ dst = (base & ~mask) | ((src << (offset & 7)) & mask);
+
+ // TODO: tcy 28-96
+ tcy = 28;
}
- gen_write(mode[1], SIZE_D, dest);
+ gen_write(mode[1], dst);
}
break;
case 3:
- // CHECKi dest,bounds,src
+ // CHECKi dst,bounds,src
// reg,gen,gen
// addr,read.i
{
mode[0].addr();
+ mode[1].read_i(size);
+ decode(mode, bytes);
u32 const bounds = ea(mode[0]);
- s32 const src = gen_read_sx(mode[1], size);
+ s32 const src = gen_read_sx(mode[1]);
s32 lower = 0;
s32 upper = 0;
switch (size)
{
- case SIZE_B: lower = s8(space(0).read_byte(bounds + 0)); upper = s8(space(0).read_byte(bounds + 1)); break;
- case SIZE_W: lower = s16(space(0).read_word_unaligned(bounds + 0)); upper = s16(space(0).read_word_unaligned(bounds + 2)); break;
- case SIZE_D: lower = s32(space(0).read_dword_unaligned(bounds + 0)); upper = s32(space(0).read_dword_unaligned(bounds + 4)); break;
+ case SIZE_B:
+ upper = s8(space(0).read_byte(bounds + 0));
+ lower = s8(space(0).read_byte(bounds + 1));
+ break;
+ case SIZE_W:
+ upper = s16(space(0).read_word_unaligned(bounds + 0));
+ lower = s16(space(0).read_word_unaligned(bounds + 2));
+ break;
+ case SIZE_D:
+ upper = s32(space(0).read_dword_unaligned(bounds + 0));
+ lower = s32(space(0).read_dword_unaligned(bounds + 4));
+ break;
+ default:
+ // can't happen
+ break;
}
if (src >= lower && src <= upper)
{
m_psr &= ~PSR_F;
m_r[reg] = src - lower;
+
+ tcy = 11;
}
else
+ {
m_psr |= PSR_F;
+
+ tcy = (src >= lower) ? 7 : 10;
+ }
}
break;
case 4:
@@ -2189,10 +2542,16 @@ void ns32000_device::execute_run()
// reg,gen,gen
// read.i,read.i
{
- u32 const length = gen_read(mode[0], size);
- u32 const index = gen_read(mode[1], size);
+ mode[0].read_i(size);
+ mode[1].read_i(size);
+ decode(mode, bytes);
+
+ u32 const length = gen_read(mode[0]);
+ u32 const index = gen_read(mode[1]);
m_r[reg] = m_r[reg] * (length + 1) + index;
+
+ tcy = 25;
}
break;
case 5:
@@ -2200,10 +2559,12 @@ void ns32000_device::execute_run()
// gen,gen
// read.i,rmw.B
{
- mode[1].rmw();
+ mode[0].read_i(size);
+ mode[1].rmw_i(SIZE_B);
+ decode(mode, bytes);
- u32 const base = gen_read(mode[0], size);
- u32 offset = gen_read(mode[1], SIZE_B);
+ u32 const base = gen_read(mode[0]);
+ u32 offset = gen_read(mode[1]);
unsigned const limit = (size + 1) * 8;
m_psr |= PSR_F;
@@ -2216,39 +2577,348 @@ void ns32000_device::execute_run()
else
offset++;
- gen_write(mode[1], SIZE_B, offset & limit);
+ gen_write(mode[1], offset & (limit - 1));
+
+ // TODO: tcy 24-28
+ tcy = 24;
}
break;
case 6:
- // MOVSU/MOVUS src,dest
+ // MOVSU/MOVUS src,dst
// gen,gen
// addr,addr
{
mode[0].addr();
mode[1].addr();
+ decode(mode, bytes);
fatalerror("unimplemented: movsu/movus (%s)\n", machine().describe_context());
+
+ tcy = 33;
}
break;
}
}
- m_pc += bytes;
break;
- case 0x3e: // format 9
- // TODO: floating point
+ case 0x3e:
+ // format 9: xxxx xyyy yyoo ofii 0011 1110
+ if (m_cfg & CFG_F)
+ {
+ if (!m_fpu)
+ fatalerror("floating point unit not configured (%s)\n", machine().describe_context());
+
+ u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
+ bytes += 2;
+
+ addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
+ size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q;
+ size_code const size = size_code(opword & 3);
+
+ m_fpu->write_id(opbyte);
+ m_fpu->write_op(swapendian_int16(opword));
+
+ switch ((opword >> 3) & 7)
+ {
+ case 0:
+ // MOVif src,dst
+ // gen,gen
+ // read.i,write.f
+ mode[0].read_i(size);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 1:
+ // LFSR src
+ // gen
+ // read.D
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 2:
+ // MOVLF src,dst
+ // gen,gen
+ // read.L,write.F
+ mode[0].read_f(SIZE_Q);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 3:
+ // MOVFL src,dst
+ // gen,gen
+ // read.F,write.L
+ mode[0].read_f(SIZE_D);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 4:
+ // ROUNDfi src,dst
+ // gen,gen
+ // read.f,write.i
+ mode[0].read_f(size_f);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 5:
+ // TRUNCfi src,dst
+ // gen,gen
+ // read.f,write.i
+ mode[0].read_f(size_f);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 6:
+ // SFSR dst
+ // gen
+ // write.D
+ mode[0].write_i(size);
+ decode(mode, bytes);
+
+ if (slave(mode[1], mode[0]))
+ interrupt(FPU, m_pc);
+ break;
+ case 7:
+ // FLOORfi src,dst
+ // gen,gen
+ // read.f,write.i
+ mode[0].read_f(size_f);
+ mode[1].write_i(size);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ }
+ }
+ else
+ interrupt(UND, m_pc);
break;
case 0x7e: // format 10
interrupt(UND, m_pc);
break;
- case 0xbe: // format 11
- // TODO: floating point
+ case 0xbe:
+ // format 11: xxxx xyyy yyoo oo0f 1011 1110
+ if (m_cfg & CFG_F)
+ {
+ if (!m_fpu)
+ fatalerror("floating point unit not configured (%s)\n", machine().describe_context());
+
+ u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
+ bytes += 2;
+
+ addr_mode mode[2] = { addr_mode((opword >> 11) & 31), addr_mode((opword >> 6) & 31) };
+ size_code const size_f = BIT(opword, 0) ? SIZE_D : SIZE_Q;
+
+ m_fpu->write_id(opbyte);
+ m_fpu->write_op(swapendian_int16(opword));
+
+ switch ((opword >> 2) & 15)
+ {
+ case 0x0:
+ // ADDf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0x1:
+ // MOVf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0x2:
+ // CMPf src1,src2
+ // gen,gen
+ // read.f,read.f
+ {
+ mode[0].read_f(size_f);
+ mode[1].read_f(size_f);
+ decode(mode, bytes);
+
+ u16 const status = slave(mode[0], mode[1]);
+ if (!(status & ns32000_slave_interface::SLAVE_Q))
+ {
+ m_psr &= ~(PSR_N | PSR_Z | PSR_L);
+ m_psr |= status & (ns32000_slave_interface::SLAVE_N | ns32000_slave_interface::SLAVE_Z | ns32000_slave_interface::SLAVE_L);
+ }
+ else
+ interrupt(FPU, m_pc);
+ }
+ break;
+ case 0x3:
+ // Trap(SLAVE)
+ // operands from ns32532 datasheet
+ mode[0].read_f(size_f);
+ mode[1].read_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0x4:
+ // SUBf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0x5:
+ // NEGf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0x8:
+ // DIVf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0x9:
+ // Trap(SLAVE)
+ // operands from ns32532 datasheet
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0xc:
+ // MULf src,dst
+ // gen,gen
+ // read.f,rmw.f
+ mode[0].read_f(size_f);
+ mode[1].rmw_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ case 0xd:
+ // ABSf src,dst
+ // gen,gen
+ // read.f,write.f
+ mode[0].read_f(size_f);
+ mode[1].write_f(size_f);
+ decode(mode, bytes);
+
+ if (slave(mode[0], mode[1]))
+ interrupt(FPU, m_pc);
+ break;
+ }
+ }
+ else
+ interrupt(UND, m_pc);
break;
case 0xfe: // format 12
case 0x9e: // format 13
interrupt(UND, m_pc);
break;
- case 0x1e: // format 14
- // TODO: mmu
+ case 0x1e:
+ // format 14: xxxx xsss s0oo ooii 0001 1110
+ if (!(m_psr & PSR_U))
+ {
+ if (m_cfg & CFG_M)
+ {
+ u16 const opword = space(0).read_word_unaligned(m_pc + bytes);
+ bytes += 2;
+
+ addr_mode mode[] = { addr_mode((opword >> 11) & 31), addr_mode(0x13) };
+
+ //unsigned const quick = (opword >> 7) & 15;
+ size_code const size = size_code(opword & 3);
+
+ // TODO: mmu instructions
+ switch ((opword >> 2) & 15)
+ {
+ case 0:
+ // RDVAL loc
+ // gen
+ // addr
+ mode[0].addr();
+ decode(mode, bytes);
+
+ tcy = 21;
+ break;
+ case 1:
+ // WRVAL loc
+ // gen
+ // addr
+ mode[0].addr();
+ decode(mode, bytes);
+
+ tcy = 21;
+ break;
+ case 2:
+ // LMR mmureg,src
+ // short,gen
+ // read.D
+ mode[0].read_i(size);
+ decode(mode, bytes);
+
+ tcy = 30;
+ break;
+ case 3:
+ // SMR mmureg,dst
+ // short,gen
+ // write.D
+ mode[0].write_i(size);
+ decode(mode, bytes);
+
+ tcy = 25;
+ break;
+ default:
+ interrupt(UND, m_pc);
+ break;
+ }
+ }
+ else
+ interrupt(UND, m_pc);
+ }
+ else
+ interrupt(ILL, m_pc);
break;
case 0x16: // format 15.0
case 0x36: // format 15.1
@@ -2271,15 +2941,18 @@ void ns32000_device::execute_run()
break;
}
+ if (m_sequential)
+ m_pc += bytes;
+
// trace trap
if (m_psr & PSR_P)
interrupt(TRC, m_pc);
- m_icount--;
+ m_icount -= tcy;
}
}
-void ns32000_device::execute_set_input(int inputnum, int state)
+template <int Width> void ns32000_device<Width>::execute_set_input(int inputnum, int state)
{
if (state)
m_wait = false;
@@ -2298,7 +2971,7 @@ void ns32000_device::execute_set_input(int inputnum, int state)
}
}
-device_memory_interface::space_config_vector ns32000_device::memory_space_config() const
+template <int Width> device_memory_interface::space_config_vector ns32000_device<Width>::memory_space_config() const
{
return space_config_vector{
std::make_pair(AS_PROGRAM, &m_program_config),
@@ -2312,12 +2985,102 @@ device_memory_interface::space_config_vector ns32000_device::memory_space_config
};
}
-bool ns32000_device::memory_translate(int spacenum, int intention, offs_t &address)
+template <int Width> bool ns32000_device<Width>::memory_translate(int spacenum, int intention, offs_t &address)
{
return true;
}
-std::unique_ptr<util::disasm_interface> ns32000_device::create_disassembler()
+template <int Width> std::unique_ptr<util::disasm_interface> ns32000_device<Width>::create_disassembler()
{
return std::make_unique<ns32000_disassembler>();
}
+
+template <int Width> u16 ns32000_device<Width>::slave(addr_mode op1, addr_mode op2)
+{
+ if ((op1.access == READ || op1.access == RMW) && !(op1.type == REG && op1.slave))
+ {
+ u64 const data = gen_read(op1);
+
+ switch (op1.size)
+ {
+ case SIZE_B:
+ m_fpu->write_op(u8(data));
+ break;
+ case SIZE_W:
+ m_fpu->write_op(u16(data));
+ break;
+ case SIZE_D:
+ m_fpu->write_op(u16(data >> 0));
+ m_fpu->write_op(u16(data >> 16));
+ break;
+ case SIZE_Q:
+ m_fpu->write_op(u16(data >> 0));
+ m_fpu->write_op(u16(data >> 16));
+ m_fpu->write_op(u16(data >> 32));
+ m_fpu->write_op(u16(data >> 48));
+ break;
+ }
+ }
+
+ if ((op2.access == READ || op2.access == RMW) && !(op2.type == REG && op2.slave))
+ {
+ u64 const data = gen_read(op2);
+
+ switch (op2.size)
+ {
+ case SIZE_B:
+ m_fpu->write_op(u8(data));
+ break;
+ case SIZE_W:
+ m_fpu->write_op(u16(data));
+ break;
+ case SIZE_D:
+ m_fpu->write_op(u16(data >> 0));
+ m_fpu->write_op(u16(data >> 16));
+ break;
+ case SIZE_Q:
+ m_fpu->write_op(u16(data >> 0));
+ m_fpu->write_op(u16(data >> 16));
+ m_fpu->write_op(u16(data >> 32));
+ m_fpu->write_op(u16(data >> 48));
+ break;
+ }
+ }
+
+ u16 const status = m_fpu->read_st(&m_icount);
+
+ if (!(status & ns32000_slave_interface::SLAVE_Q))
+ {
+ if ((op2.access == WRITE || op2.access == RMW) && !(op2.type == REG && op2.slave))
+ {
+ u64 data = m_fpu->read_op();
+
+ switch (op2.size)
+ {
+ case SIZE_D:
+ data |= u64(m_fpu->read_op()) << 16;
+ break;
+ case SIZE_Q:
+ data |= u64(m_fpu->read_op()) << 16;
+ data |= u64(m_fpu->read_op()) << 32;
+ data |= u64(m_fpu->read_op()) << 48;
+ break;
+ default:
+ break;
+ }
+
+ gen_write(op2, data);
+ }
+ }
+ else
+ {
+ // restore stack pointer
+ if (op1.type == TOS && op1.access == READ)
+ SP -= op1.size + 1;
+
+ if (op2.type == TOS && op2.access == READ)
+ SP -= op2.size + 1;
+ }
+
+ return status;
+}
diff --git a/src/devices/cpu/ns32000/ns32000.h b/src/devices/cpu/ns32000/ns32000.h
index af5977fe52e..f5254fa068d 100644
--- a/src/devices/cpu/ns32000/ns32000.h
+++ b/src/devices/cpu/ns32000/ns32000.h
@@ -6,9 +6,14 @@
#pragma once
+#include "slave.h"
+
+template <int Width>
class ns32000_device : public cpu_device
{
public:
+ template <typename T> void set_fpu(T &&tag) { m_fpu.set_tag(std::forward<T>(tag)); }
+
// construction/destruction
ns32000_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock);
@@ -47,47 +52,79 @@ private:
EXT,
TOS,
};
+ enum access_class : unsigned
+ {
+ NONE,
+ READ,
+ WRITE,
+ RMW,
+ ADDR,
+ REGADDR,
+ };
+ enum size_code : unsigned
+ {
+ SIZE_B = 0,
+ SIZE_W = 1,
+ SIZE_D = 3,
+ SIZE_Q = 7,
+ };
+
struct addr_mode
{
addr_mode(unsigned gen)
: gen(gen)
+ , access(NONE)
+ , slave(false)
, base(0)
, disp(0)
+ , imm(0)
{};
- void rmw() { if (type == TOS) type = MEM; }
- void addr() { if (type == TOS) type = MEM; }
- void regaddr() { if (type == TOS) type = MEM; }
+ void read_i(size_code code) { access = READ; size = code; }
+ void read_f(size_code code) { access = READ; size = code; slave = true; }
+ void write_i(size_code code) { access = WRITE; size = code; }
+ void write_f(size_code code) { access = WRITE; size = code; slave = true; }
+ void rmw_i(size_code code) { access = RMW; size = code; }
+ void rmw_f(size_code code) { access = RMW; size = code; slave = true; }
+ void addr() { access = ADDR; size = SIZE_D; }
+ void regaddr() { access = REGADDR; size = SIZE_D; }
unsigned gen;
addr_mode_type type;
+ access_class access;
+ size_code size;
+ bool slave;
u32 base;
u32 disp;
+ u64 imm;
};
// instruction decoding helpers
s32 displacement(unsigned &bytes);
- void decode(addr_mode *mode, unsigned imm_size, unsigned &bytes);
+ void decode(addr_mode *mode, unsigned &bytes);
// operand read/write helpers
u32 ea(addr_mode const mode);
- u64 gen_read(addr_mode mode, unsigned size);
- s64 gen_read_sx(addr_mode mode, unsigned size);
- void gen_write(addr_mode mode, unsigned size, u64 data);
+ u64 gen_read(addr_mode mode);
+ s64 gen_read_sx(addr_mode mode);
+ void gen_write(addr_mode mode, u64 data);
// other execution helpers
bool condition(unsigned const cc);
void flags(u32 const src1, u32 const src2, u32 const dest, unsigned const size, bool const subtraction);
void interrupt(unsigned const vector, u32 const return_address, bool const trap = true);
+ u16 slave(addr_mode op1, addr_mode op2);
// configuration
address_space_config m_program_config;
address_space_config m_interrupt_config;
+ optional_device<ns32000_slave_interface> m_fpu;
+
// emulation state
int m_icount;
- memory_access<24, 1, 0, ENDIANNESS_LITTLE>::cache m_bus[16];
+ typename memory_access<24, Width, 0, ENDIANNESS_LITTLE>::cache m_bus[16];
u32 m_pc; // program counter
u32 m_sb; // static base
@@ -105,21 +142,22 @@ private:
bool m_nmi_line;
bool m_int_line;
bool m_wait;
+ bool m_sequential;
};
-class ns32008_device : public ns32000_device
+class ns32008_device : public ns32000_device<0>
{
public:
ns32008_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
-class ns32016_device : public ns32000_device
+class ns32016_device : public ns32000_device<1>
{
public:
ns32016_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
-class ns32032_device : public ns32000_device
+class ns32032_device : public ns32000_device<2>
{
public:
ns32032_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
diff --git a/src/devices/cpu/ns32000/ns32000dasm.cpp b/src/devices/cpu/ns32000/ns32000dasm.cpp
index 600e5f2dfb2..3f8315ec394 100644
--- a/src/devices/cpu/ns32000/ns32000dasm.cpp
+++ b/src/devices/cpu/ns32000/ns32000dasm.cpp
@@ -354,6 +354,10 @@ const char *const ns32000_disassembler::PR[] =
{
"UPSR", "DCR", "BPC", "DSR", "CAR", "", "", "", "FP", "SP", "SB", "USP", "CFG", "PSR", "INTBASE", "MOD"
};
+const char *const ns32000_disassembler::FP[] =
+{
+ "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7"
+};
int8_t ns32000_disassembler::short2int(uint8_t val)
{
@@ -508,7 +512,7 @@ inline std::string ns32000_disassembler::get_reg_list(offs_t &pc, const data_buf
return reg_list;
}
-void ns32000_disassembler::stream_gen(std::ostream &stream, u8 gen_addr, u8 op_len, operand_class op_class, offs_t &pc, const data_buffer &opcodes)
+void ns32000_disassembler::stream_gen(std::ostream &stream, u8 gen_addr, u8 op_len, operand_class op_class, offs_t &pc, const data_buffer &opcodes, bool fpreg)
{
uint8_t index_byte;
int32_t disp1, disp2;
@@ -518,7 +522,7 @@ void ns32000_disassembler::stream_gen(std::ostream &stream, u8 gen_addr, u8 op_l
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
/* Register */
if (op_class != operand_class::ADDRESS)
- util::stream_format(stream, "%s", R[gen_addr & 0x07]);
+ util::stream_format(stream, "%s", fpreg ? FP[gen_addr & 0x07] : R[gen_addr & 0x07]);
else
util::stream_format(stream, "(invalid)");
break;
@@ -541,20 +545,25 @@ void ns32000_disassembler::stream_gen(std::ostream &stream, u8 gen_addr, u8 op_l
/* Immediate */
if (op_class == operand_class::SOURCE || op_class == operand_class::BITPOS)
{
+ int64_t imm;
if (op_len == 0)
- disp1 = int8_t(opcodes.r8(pc));
+ imm = int8_t(opcodes.r8(pc));
else if (op_len == 1)
- disp1 = int16_t(swapendian_int16(opcodes.r16(pc)));
+ imm = int16_t(swapendian_int16(opcodes.r16(pc)));
+ else if (op_len == 3)
+ imm = int32_t(swapendian_int32(opcodes.r32(pc)));
else
- disp1 = swapendian_int32(opcodes.r32(pc));
+ imm = int64_t(swapendian_int64(opcodes.r64(pc)));
if (op_class == operand_class::BITPOS)
- util::stream_format(stream, "$%d", disp1);
+ util::stream_format(stream, "$%d", imm);
else if (op_len == 0)
- util::stream_format(stream, "$0x%02X", uint8_t(disp1));
+ util::stream_format(stream, "$0x%02X", uint8_t(imm));
else if (op_len == 1)
- util::stream_format(stream, "$0x%04X", uint16_t(disp1));
- else
- util::stream_format(stream, "$0x%08X", disp1);
+ util::stream_format(stream, "$0x%04X", uint16_t(imm));
+ else if (op_len == 3)
+ util::stream_format(stream, "$0x%08X", uint32_t(imm));
+ else if (op_len == 7)
+ util::stream_format(stream, "$0x%016X", imm);
pc += op_len + 1;
}
else
@@ -850,10 +859,22 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, const
mnemonic = mnemonic_index(Format9[Format9op(opcode)], iType[Format9i(opcode)], fType[Format9f(opcode)]);
switch (Format9op(opcode))
{
- case 0x00: case 0x02: case 0x03: case 0x04: case 0x05: case 0x07:
+ case 0x00:
util::stream_format(stream, "%-8s ", mnemonic);
stream_gen(stream, Format9gen1(opcode), Format9i(opcode), operand_class::SOURCE, pc, opcodes);
util::stream_format(stream, ", ");
+ stream_gen(stream, Format9gen2(opcode), Format9i(opcode), operand_class::DESTINATION, pc, opcodes, true);
+ break;
+ case 0x02: case 0x03:
+ util::stream_format(stream, "%-8s ", mnemonic);
+ stream_gen(stream, Format9gen1(opcode), Format9f(opcode) ? 7 : 3, operand_class::SOURCE, pc, opcodes, true);
+ util::stream_format(stream, ", ");
+ stream_gen(stream, Format9gen2(opcode), Format9f(opcode) ? 3 : 7, operand_class::DESTINATION, pc, opcodes, true);
+ break;
+ case 0x04: case 0x05: case 0x07:
+ util::stream_format(stream, "%-8s ", mnemonic);
+ stream_gen(stream, Format9gen1(opcode), Format9f(opcode) ? 3 : 7, operand_class::SOURCE, pc, opcodes, true);
+ util::stream_format(stream, ", ");
stream_gen(stream, Format9gen2(opcode), Format9i(opcode), operand_class::DESTINATION, pc, opcodes);
break;
case 0x01: case 0x06:
@@ -873,9 +894,9 @@ offs_t ns32000_disassembler::disassemble(std::ostream &stream, offs_t pc, const
{
case 0x00: case 0x01: case 0x02: case 0x04: case 0x05 : case 0x08: case 0x0c : case 0x0d:
util::stream_format(stream, "%-8s ", mnemonic);
- stream_gen(stream, Format11gen1(opcode), Format11f(opcode), operand_class::SOURCE, pc, opcodes);
+ stream_gen(stream, Format11gen1(opcode), Format11f(opcode) ? 3 : 7, operand_class::SOURCE, pc, opcodes, true);
util::stream_format(stream, ",");
- stream_gen(stream, Format11gen2(opcode), Format11f(opcode), operand_class::DESTINATION, pc, opcodes);
+ stream_gen(stream, Format11gen2(opcode), Format11f(opcode) ? 3 : 7, operand_class::DESTINATION, pc, opcodes, true);
break;
default: /* Trap */
util::stream_format(stream, "%-8s ", mnemonic);
diff --git a/src/devices/cpu/ns32000/ns32000dasm.h b/src/devices/cpu/ns32000/ns32000dasm.h
index 93c38c62c98..c9f470e05d3 100644
--- a/src/devices/cpu/ns32000/ns32000dasm.h
+++ b/src/devices/cpu/ns32000/ns32000dasm.h
@@ -109,6 +109,7 @@ private:
static char const *const R[];
static char const *const M[];
static char const *const PR[];
+ static char const *const FP[];
std::string mnemonic_index(std::string form, const std::string &itype, const std::string &ftype);
uint8_t opcode_format(uint8_t byte);
@@ -119,7 +120,7 @@ private:
static inline std::string get_options(uint8_t opts);
static inline std::string get_reg_list(offs_t &pc, const data_buffer &opcodes, bool reverse);
- void stream_gen(std::ostream &stream, u8 gen_addr, u8 op_len, operand_class op_class, offs_t &pc, const data_buffer &opcodes);
+ void stream_gen(std::ostream &stream, u8 gen_addr, u8 op_len, operand_class op_class, offs_t &pc, const data_buffer &opcodes, bool fpreg = false);
u32 m_base_pc;
};
diff --git a/src/devices/cpu/ns32000/slave.h b/src/devices/cpu/ns32000/slave.h
new file mode 100644
index 00000000000..43ed52ecf80
--- /dev/null
+++ b/src/devices/cpu/ns32000/slave.h
@@ -0,0 +1,45 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_CPU_NS32000_SLAVE_H
+#define MAME_CPU_NS32000_SLAVE_H
+
+#pragma once
+
+class ns32000_slave_interface : public device_interface
+{
+public:
+ auto out_scb() { return m_out_scb.bind(); }
+
+ ns32000_slave_interface(machine_config const &mconfig, device_t &device)
+ : device_interface(device, "ns32000_slave")
+ , m_out_scb(*this)
+ {
+ }
+
+ enum slave_status : u16
+ {
+ SLAVE_Q = 0x0001,
+ SLAVE_L = 0x0004,
+ SLAVE_F = 0x0020,
+ SLAVE_Z = 0x0040,
+ SLAVE_N = 0x0080,
+ };
+
+ virtual void state_add(device_state_interface &parent, int &index) = 0;
+ virtual void write_id(u16 data) = 0;
+ virtual void write_op(u16 data) = 0;
+ virtual u16 read_st(int *icount = nullptr) = 0;
+ virtual u16 read_op() = 0;
+
+protected:
+ // device_interface overrides
+ virtual void interface_post_start() override
+ {
+ m_out_scb.resolve_safe();
+ }
+
+ devcb_write_line m_out_scb;
+};
+
+#endif // MAME_CPU_NS32000_SLAVE_H
diff --git a/src/devices/cpu/pdp1/pdp1.cpp b/src/devices/cpu/pdp1/pdp1.cpp
index 2d04709a4a9..f16985610f0 100644
--- a/src/devices/cpu/pdp1/pdp1.cpp
+++ b/src/devices/cpu/pdp1/pdp1.cpp
@@ -386,6 +386,8 @@ pdp1_device::pdp1_device(const machine_config &mconfig, const char *tag, device_
, m_program_config("program", ENDIANNESS_BIG, 32, 18, -2) // data is actually 18 bits wide
, m_extern_iot(*this)
, m_io_sc_callback(*this)
+ , m_program(nullptr)
+ , m_reset_param(nullptr)
{
m_program_config.m_is_octal = true;
}
@@ -783,7 +785,7 @@ void pdp1_device::execute_run()
/* read first word as instruction */
MB = 0;
/* data will be transferred to IO register in response to RPB */
- m_extern_iot[2](2, 0, 1, IO, AC);
+ m_extern_iot[2](2, 1, MB, IO, AC);
m_rim_step = 1;
m_ios = 0;
break;
@@ -827,9 +829,8 @@ void pdp1_device::execute_run()
case 2:
/* read second word as data */
- MB = 0;
/* data will be transferred to IO register in response to RPB */
- m_extern_iot[2](2, 0, 1, IO, AC);
+ m_extern_iot[2](2, 1, MB, IO, AC);
m_rim_step = 3;
m_ios = 0;
break;
diff --git a/src/devices/cpu/pdp1/pdp1.h b/src/devices/cpu/pdp1/pdp1.h
index 0a81c8177d4..f1a4e934236 100644
--- a/src/devices/cpu/pdp1/pdp1.h
+++ b/src/devices/cpu/pdp1/pdp1.h
@@ -33,8 +33,7 @@ struct pdp1_reset_param_t
#define IOT_NO_COMPLETION_PULSE -1
-class pdp1_device : public cpu_device
- , public pdp1_reset_param_t
+class pdp1_device : public cpu_device, public pdp1_reset_param_t
{
public:
typedef device_delegate<void (int op2, int nac, int mb, int &io, int ac)> iot_delegate;
diff --git a/src/devices/cpu/pic16c5x/pic16c5x.cpp b/src/devices/cpu/pic16c5x/pic16c5x.cpp
index 715cf574ee1..1871bc260bd 100644
--- a/src/devices/cpu/pic16c5x/pic16c5x.cpp
+++ b/src/devices/cpu/pic16c5x/pic16c5x.cpp
@@ -130,9 +130,11 @@ pic16c5x_device::pic16c5x_device(const machine_config &mconfig, device_type type
, ( ( program_width == 9 ) ? address_map_constructor(FUNC(pic16c5x_device::rom_9), this): ( ( program_width == 10 ) ? address_map_constructor(FUNC(pic16c5x_device::rom_10), this) : address_map_constructor(FUNC(pic16c5x_device::rom_11), this) )))
, m_data_config("data", ENDIANNESS_LITTLE, 8, data_width, 0
, ( ( data_width == 5 ) ? address_map_constructor(FUNC(pic16c5x_device::ram_5), this) : address_map_constructor(FUNC(pic16c5x_device::ram_7), this) ) )
+ , m_internalram(nullptr)
, m_reset_vector((program_width == 9) ? 0x1ff : ((program_width == 10) ? 0x3ff : 0x7ff))
, m_picmodel(picmodel)
, m_temp_config(0)
+ , m_rtcc(0)
, m_picRAMmask((data_width == 5) ? 0x1f : 0x7f)
, m_read_a(*this)
, m_read_b(*this)
diff --git a/src/devices/cpu/t11/t11dasm.cpp b/src/devices/cpu/t11/t11dasm.cpp
index 536d811eff0..13705f53477 100644
--- a/src/devices/cpu/t11/t11dasm.cpp
+++ b/src/devices/cpu/t11/t11dasm.cpp
@@ -119,10 +119,11 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
case 000: util::stream_format(stream, "HALT"); break;
case 001: util::stream_format(stream, "WAIT"); break;
case 002: util::stream_format(stream, "RTI"); flags = STEP_OUT; break;
- case 003: util::stream_format(stream, "BPT"); break;
- case 004: util::stream_format(stream, "IOT"); break;
+ case 003: util::stream_format(stream, "BPT"); flags = STEP_OVER; break;
+ case 004: util::stream_format(stream, "IOT"); flags = STEP_OVER; break;
case 005: util::stream_format(stream, "RESET"); break;
- case 006: util::stream_format(stream, "RTT"); break;
+ case 006: util::stream_format(stream, "RTT"); flags = STEP_OUT; break;
+ case 007: util::stream_format(stream, "MFPT"); break;
default: util::stream_format(stream, ".WORD %06o", op); break;
}
break;
@@ -135,21 +136,22 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
{
case 000:
if( (lo & 7) == 7 )
- util::stream_format(stream, "RTS");
+ util::stream_format(stream, "RETURN");
else
util::stream_format(stream, "RTS %s", regs[lo & 7]);
flags = STEP_OUT;
break;
+ // 00023x: SPL (not implemented on T-11)
case 040:
case 050:
switch( lo & 15 )
{
case 000: util::stream_format(stream, "NOP"); break;
case 017: util::stream_format(stream, "CCC"); break;
- case 001: util::stream_format(stream, "CEC"); break;
- case 002: util::stream_format(stream, "CEV"); break;
- case 004: util::stream_format(stream, "CEZ"); break;
- case 010: util::stream_format(stream, "CEN"); break;
+ case 001: util::stream_format(stream, "CLC"); break;
+ case 002: util::stream_format(stream, "CLV"); break;
+ case 004: util::stream_format(stream, "CLZ"); break;
+ case 010: util::stream_format(stream, "CLN"); break;
default: util::stream_format(stream, "Ccc #%02o", lo & 15); break;
}
break;
@@ -207,7 +209,7 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
case 0004400: case 0004500: case 0004600: case 0004700:
ea1 = MakeEA<false> (lo, pc, opcodes);
if ( (hi & 7) == 7 )
- util::stream_format(stream, "JSR %s", ea1);
+ util::stream_format(stream, "CALL %s", ea1);
else
util::stream_format(stream, "JSR %s,%s", regs[hi & 7], ea1);
flags = STEP_OVER;
@@ -260,13 +262,17 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
ea1 = MakeEA<false> (lo, pc, opcodes);
util::stream_format(stream, "ASL %s", ea1);
break;
-/* case 0006400:
- util::stream_format(stream, "MARK #%o", lo);
- break;*/
+ // 0064xx: MARK (not implemented on T-11)
+ // 0065xx: MFPI (not implemented on T-11)
+ // 0066xx: MTPI (not implemented on T-11)
case 0006700:
ea1 = MakeEA<false> (lo, pc, opcodes);
util::stream_format(stream, "SXT %s", ea1);
break;
+ // 0070xx: CSM (not implemented on T-11)
+ // 0072xx: TSTSET (not implemented on T-11)
+ // 0073xx: WRTLCK (not implemented on T-11)
+
case 0010000: case 0010100: case 0010200: case 0010300: case 0010400: case 0010500: case 0010600: case 0010700:
case 0011000: case 0011100: case 0011200: case 0011300: case 0011400: case 0011500: case 0011600: case 0011700:
case 0012000: case 0012100: case 0012200: case 0012300: case 0012400: case 0012500: case 0012600: case 0012700:
@@ -277,13 +283,7 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
case 0017000: case 0017100: case 0017200: case 0017300: case 0017400: case 0017500: case 0017600: case 0017700:
ea1 = MakeEA<false> (hi, pc, opcodes);
ea2 = MakeEA<false> (lo, pc, opcodes);
- if (lo == 046) /* MOV src,-(SP) */
- util::stream_format(stream, "PUSH %s", ea1);
- else
- if (hi == 026) /* MOV (SP)+,buffer */
- util::stream_format(stream, "POP %s", ea2);
- else /* all other */
- util::stream_format(stream, "MOV %s,%s", ea1, ea2);
+ util::stream_format(stream, "MOV %s,%s", ea1, ea2);
break;
case 0020000: case 0020100: case 0020200: case 0020300: case 0020400: case 0020500: case 0020600: case 0020700:
case 0021000: case 0021100: case 0021200: case 0021300: case 0021400: case 0021500: case 0021600: case 0021700:
@@ -346,11 +346,16 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
util::stream_format(stream, "ADD %s,%s", ea1, ea2);
break;
+ // 070xxx: MUL (not implemented on T-11)
+ // 071xxx: DIV (not implemented on T-11)
+ // 072xxx: ASH (not implemented on T-11)
+ // 073xxx: ASHC (not implemented on T-11)
case 0074000: case 0074100: case 0074200: case 0074300: case 0074400: case 0074500: case 0074600: case 0074700:
ea1 = MakeEA<false> (lo, pc, opcodes);
util::stream_format(stream, "XOR %s,%s", regs[hi & 7], ea1);
break;
-
+ // 075xxx: Floating Instruction Set (not implemented on T-11)
+ // 076xxx: Commercial Instruction Set (not implemented on T-11)
case 0077000: case 0077100: case 0077200: case 0077300: case 0077400: case 0077500: case 0077600: case 0077700:
addr = (pc - 2 * lo) & 0177777;
util::stream_format(stream, "SOB %s,%06o", regs[hi & 7], addr);
@@ -390,9 +395,11 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
break;
case 0104000: case 0104100: case 0104200: case 0104300:
util::stream_format(stream, "EMT %03o", op & 0377);
+ flags = STEP_OVER;
break;
case 0104400: case 0104500: case 0104600: case 0104700:
util::stream_format(stream, "TRAP %03o", op & 0377);
+ flags = STEP_OVER;
break;
case 0105000:
@@ -447,6 +454,8 @@ offs_t t11_disassembler::disassemble(std::ostream &stream, offs_t pc, const data
ea1 = MakeEA<true> (lo, pc, opcodes);
util::stream_format(stream, "MTPS %s", ea1);
break;
+ // 1065xx: MFPD (not implemented on T-11)
+ // 1066xx: MTPD (not implemented on T-11)
case 0106700:
ea1 = MakeEA<true> (lo, pc, opcodes);
util::stream_format(stream, "MFPS %s", ea1);
diff --git a/src/devices/cpu/tms34010/tms34010.cpp b/src/devices/cpu/tms34010/tms34010.cpp
index d5fd882a484..ab820fc1599 100644
--- a/src/devices/cpu/tms34010/tms34010.cpp
+++ b/src/devices/cpu/tms34010/tms34010.cpp
@@ -1178,7 +1178,7 @@ uint32_t tms340x0_device::tms340x0_ind16(screen_device &screen, bitmap_ind16 &bi
params.heblnk = params.hsblnk = cliprect.max_x + 1;
/* blank out the blank regions */
- uint16_t *dest = &bitmap.pix16(cliprect.min_y);
+ uint16_t *dest = &bitmap.pix(cliprect.min_y);
for (x = cliprect.min_x; x < params.heblnk; x++)
dest[x] = blackpen;
for (x = params.hsblnk; x <= cliprect.max_x; x++)
@@ -1209,7 +1209,7 @@ uint32_t tms340x0_device::tms340x0_rgb32(screen_device &screen, bitmap_rgb32 &bi
params.heblnk = params.hsblnk = cliprect.max_x + 1;
/* blank out the blank regions */
- uint32_t *dest = &bitmap.pix32(cliprect.min_y);
+ uint32_t *dest = &bitmap.pix(cliprect.min_y);
for (x = cliprect.min_x; x < params.heblnk; x++)
dest[x] = blackpen;
for (x = params.hsblnk; x <= cliprect.max_x; x++)
diff --git a/src/devices/cpu/tms57002/tms57002.cpp b/src/devices/cpu/tms57002/tms57002.cpp
index c2cf28f3f92..da29f23fbcd 100644
--- a/src/devices/cpu/tms57002/tms57002.cpp
+++ b/src/devices/cpu/tms57002/tms57002.cpp
@@ -929,11 +929,10 @@ void tms57002_device::sound_stream_update(sound_stream &stream, std::vector<read
si[2] = s32(inputs[2].get(0) * in_scale) & 0xffffff;
si[3] = s32(inputs[3].get(0) * in_scale) & 0xffffff;
- stream_buffer::sample_t out_scale = 1.0 / (32768.0 * 65536.0);
- outputs[0].put(0, stream_buffer::sample_t(s32(so[0] << 8)) * out_scale);
- outputs[1].put(0, stream_buffer::sample_t(s32(so[1] << 8)) * out_scale);
- outputs[2].put(0, stream_buffer::sample_t(s32(so[2] << 8)) * out_scale);
- outputs[3].put(0, stream_buffer::sample_t(s32(so[3] << 8)) * out_scale);
+ outputs[0].put_int(0, s32(so[0] << 8) >> 1, 32768 * 32768);
+ outputs[1].put_int(0, s32(so[1] << 8) >> 1, 32768 * 32768);
+ outputs[2].put_int(0, s32(so[2] << 8) >> 1, 32768 * 32768);
+ outputs[3].put_int(0, s32(so[3] << 8) >> 1, 32768 * 32768);
sync_w(1);
}
diff --git a/src/devices/cpu/tms9900/tms9995.cpp b/src/devices/cpu/tms9900/tms9995.cpp
index 981356ebcd2..89fdcc8d817 100644
--- a/src/devices/cpu/tms9900/tms9995.cpp
+++ b/src/devices/cpu/tms9900/tms9995.cpp
@@ -220,6 +220,8 @@ void tms9995_device::device_start()
m_source_value = 0;
+ m_index = 0;
+
// add the states for the debugger
for (int i=0; i < 20; i++)
{
@@ -242,7 +244,7 @@ void tms9995_device::device_start()
save_item(NAME(PC));
save_item(NAME(ST));
// save_item(NAME(PC_debug)); // only for debugger output
- save_pointer(NAME(m_onchip_memory),256);
+ save_item(NAME(m_onchip_memory));
save_item(NAME(m_idle_state));
save_item(NAME(m_nmi_state));
save_item(NAME(m_hold_state));
@@ -285,7 +287,7 @@ void tms9995_device::device_start()
save_item(NAME(m_cru_address));
save_item(NAME(m_cru_value));
save_item(NAME(m_cru_first_read));
- save_pointer(NAME(m_flag),16);
+ save_item(NAME(m_flag));
save_item(NAME(IR));
save_item(NAME(m_pre_IR));
save_item(NAME(m_command));
diff --git a/src/devices/cpu/unsp/unsp.cpp b/src/devices/cpu/unsp/unsp.cpp
index ea416cbe05c..b285fbc3048 100644
--- a/src/devices/cpu/unsp/unsp.cpp
+++ b/src/devices/cpu/unsp/unsp.cpp
@@ -256,11 +256,11 @@ void unsp_device::device_start()
state_add(UNSP_FIQ_EN, "FIQE", m_core->m_enable_fiq).formatstr("%1u");
state_add(UNSP_FIR_MOV_EN, "FIR_MOV", m_core->m_fir_move).formatstr("%1u");
state_add(UNSP_SB, "SB", m_core->m_sb).formatstr("%1X");
- state_add(UNSP_AQ, "AQ", m_core->m_sb).formatstr("%1u");
- state_add(UNSP_FRA, "FRA", m_core->m_sb).formatstr("%1u");
- state_add(UNSP_BNK, "BNK", m_core->m_sb).formatstr("%1u");
- state_add(UNSP_INE, "INE", m_core->m_sb).formatstr("%1u");
- state_add(UNSP_PRI, "PRI", m_core->m_sb).formatstr("%1u");
+ state_add(UNSP_AQ, "AQ", m_core->m_aq).formatstr("%1u");
+ state_add(UNSP_FRA, "FRA", m_core->m_fra).formatstr("%1u");
+ state_add(UNSP_BNK, "BNK", m_core->m_bnk).formatstr("%1u");
+ state_add(UNSP_INE, "INE", m_core->m_ine).formatstr("%1u");
+ state_add(UNSP_PRI, "PRI", m_core->m_pri).formatstr("%1u");
#if UNSP_LOG_OPCODES || UNSP_LOG_REGS
state_add(UNSP_LOG_OPS,"LOG", m_log_ops).formatstr("%1u");
#endif
diff --git a/src/devices/cpu/unsp/unspdasm_extended.cpp b/src/devices/cpu/unsp/unspdasm_extended.cpp
index 3caa182b237..1655936647b 100644
--- a/src/devices/cpu/unsp/unspdasm_extended.cpp
+++ b/src/devices/cpu/unsp/unspdasm_extended.cpp
@@ -147,7 +147,7 @@ offs_t unsp_20_disassembler::disassemble_extended_group(std::ostream& stream, of
uint8_t rb = (ximm & 0x000f) >> 0;
uint8_t size = (ximm & 0x7000) >> 12;
uint8_t rx = (ximm & 0x0e00) >> 9;
-
+
if (size == 0) size = 8;
int start = (rx + 1)&7;
diff --git a/src/devices/cpu/vt50/vt50.cpp b/src/devices/cpu/vt50/vt50.cpp
index 961dca5aa2c..7a964c4be5b 100644
--- a/src/devices/cpu/vt50/vt50.cpp
+++ b/src/devices/cpu/vt50/vt50.cpp
@@ -284,7 +284,7 @@ void vt5x_cpu_device::draw_char_line()
if (xc > screen().visible_area().right() - 8)
return;
- u32 *pix = &m_bitmap.pix32(m_current_line, xc);
+ u32 *pix = &m_bitmap.pix(m_current_line, xc);
if (m_video_process && m_cursor_ff && m_cursor_active)
std::fill_n(pix, 9, rgb_t::white());
else if (!m_video_process || m_cursor_ff)
diff --git a/src/devices/cpu/x86log.cpp b/src/devices/cpu/x86log.cpp
index b97f2553f11..7c7b13d1966 100644
--- a/src/devices/cpu/x86log.cpp
+++ b/src/devices/cpu/x86log.cpp
@@ -37,7 +37,7 @@ x86log_context *x86log_create_context(const char *filename)
x86log_context *log;
/* allocate the log */
- log = global_alloc_clear<x86log_context>();
+ log = new x86log_context;
/* allocate the filename */
log->filename.assign(filename);
@@ -59,7 +59,7 @@ void x86log_free_context(x86log_context *log) noexcept
fclose(log->file);
/* free the structure */
- global_free(log);
+ delete log;
}
diff --git a/src/devices/cpu/x86log.h b/src/devices/cpu/x86log.h
index ba2a349a55f..1383295e720 100644
--- a/src/devices/cpu/x86log.h
+++ b/src/devices/cpu/x86log.h
@@ -8,10 +8,10 @@
***************************************************************************/
-#pragma once
+#ifndef MAME_CPU_X86LOG_H
+#define MAME_CPU_X86LOG_H
-#ifndef __X86LOG_H__
-#define __X86LOG_H__
+#pragma once
#include <cstdint>
#include <cassert>
@@ -38,34 +38,34 @@ typedef uint8_t x86code;
/* code logging info */
struct log_comment
{
- x86code* base;
- const char* string;
+ x86code* base = nullptr;
+ const char* string = nullptr;
};
/* data ranges */
struct data_range_t
{
- x86code* base;
- x86code* end;
- int size;
+ x86code* base = nullptr;
+ x86code* end = nullptr;
+ int size = 0;
};
/* the code logging context */
struct x86log_context
{
- std::string filename; /* name of the file */
- FILE* file; /* file we are logging to */
+ std::string filename; // name of the file
+ FILE* file = nullptr; // file we are logging to
- data_range_t data_range[MAX_DATA_RANGES]; /* list of data ranges */
- int data_range_count; /* number of data ranges */
+ data_range_t data_range[MAX_DATA_RANGES]; // list of data ranges
+ int data_range_count = 0; // number of data ranges
- log_comment comment_list[MAX_COMMENTS]; /* list of comments */
- int comment_count; /* number of live comments */
+ log_comment comment_list[MAX_COMMENTS]; // list of comments
+ int comment_count = 0; // number of live comments
- char comment_pool[COMMENT_POOL_SIZE]; /* string pool to hold comments */
- char* comment_pool_next; /* pointer to next string pool location */
+ char comment_pool[COMMENT_POOL_SIZE]; // string pool to hold comments
+ char* comment_pool_next = nullptr; // pointer to next string pool location
};
@@ -160,4 +160,4 @@ inline void x86log_printf(x86log_context* log, const char* format, Ts&&... xs)
fflush(log->file);
}
-#endif /* __X86LOG_H__ */
+#endif // MAME_CPU_X86LOG_H
diff --git a/src/devices/imagedev/cassette.cpp b/src/devices/imagedev/cassette.cpp
index c6e20ba66dd..5d17f822e60 100644
--- a/src/devices/imagedev/cassette.cpp
+++ b/src/devices/imagedev/cassette.cpp
@@ -26,8 +26,8 @@ DEFINE_DEVICE_TYPE(CASSETTE, cassette_image_device, "cassette_image", "Cassette"
// cassette_image_device - constructor
//-------------------------------------------------
-cassette_image_device::cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, CASSETTE, tag, owner, clock),
+cassette_image_device::cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, CASSETTE, tag, owner, clock),
device_image_interface(mconfig, *this),
device_sound_interface(mconfig, *this),
m_cassette(nullptr),
@@ -83,13 +83,13 @@ void cassette_image_device::update()
switch (int(m_state & CASSETTE_MASK_UISTATE)) // cast to int to suppress unhandled enum value warning
{
case CASSETTE_RECORD:
- cassette_put_sample(m_cassette, m_channel, m_position, new_position - m_position, m_value);
+ m_cassette->put_sample(m_channel, m_position, new_position - m_position, m_value);
break;
case CASSETTE_PLAY:
if (m_cassette)
{
- cassette_get_sample(m_cassette, m_channel, new_position, 0.0, &m_value);
+ m_cassette->get_sample(m_channel, new_position, 0.0, &m_value);
// See if reached end of tape
double length = get_length();
if (new_position > length)
@@ -167,9 +167,7 @@ double cassette_image_device::get_position()
double cassette_image_device::get_length()
{
- struct CassetteInfo info;
-
- cassette_get_info(m_cassette, &info);
+ cassette_image::Info info = m_cassette->get_info();
return ((double) info.sample_count) / info.sample_frequency;
}
@@ -236,7 +234,7 @@ void cassette_image_device::device_start()
m_state = m_default_state;
m_value = 0;
- stream_alloc_legacy(0, (m_stereo? 2:1), machine().sample_rate());
+ stream_alloc(0, m_stereo? 2:1, machine().sample_rate());
}
image_init_result cassette_image_device::call_create(int format_type, util::option_resolution *format_options)
@@ -258,7 +256,7 @@ image_init_result cassette_image_device::internal_load(bool is_create)
if (is_create || (length()==0)) // empty existing images are fine to write over.
{
// creating an image
- err = cassette_create((void *)image, &image_ioprocs, &wavfile_format, m_create_opts, CASSETTE_FLAG_READWRITE|CASSETTE_FLAG_SAVEONEXIT, &m_cassette);
+ err = cassette_image::create((void *)image, &image_ioprocs, &cassette_image::wavfile_format, m_create_opts, cassette_image::FLAG_READWRITE|cassette_image::FLAG_SAVEONEXIT, m_cassette);
if (err != cassette_image::error::SUCCESS)
goto error;
}
@@ -273,9 +271,9 @@ image_init_result cassette_image_device::internal_load(bool is_create)
// try opening the cassette
int cassette_flags = is_readonly()
- ? CASSETTE_FLAG_READONLY
- : (CASSETTE_FLAG_READWRITE | CASSETTE_FLAG_SAVEONEXIT);
- err = cassette_open_choices((void *)image, &image_ioprocs, filetype(), m_formats, cassette_flags, &m_cassette);
+ ? cassette_image::FLAG_READONLY
+ : (cassette_image::FLAG_READWRITE | cassette_image::FLAG_SAVEONEXIT);
+ err = cassette_image::open_choices((void *)image, &image_ioprocs, filetype(), m_formats, cassette_flags, m_cassette);
// special case - if we failed due to readwrite not being supported, make the image be read only and retry
if (err == cassette_image::error::READ_WRITE_UNSUPPORTED)
@@ -337,8 +335,7 @@ void cassette_image_device::call_unload()
update();
/* close out the cassette */
- cassette_close(m_cassette);
- m_cassette = nullptr;
+ m_cassette.reset();
/* set to default state, but only change the UI state */
change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE);
@@ -404,37 +401,29 @@ std::string cassette_image_device::call_display()
// Cassette sound
//-------------------------------------------------
-void cassette_image_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void cassette_image_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *left_buffer = outputs[0];
- stream_sample_t *right_buffer = nullptr;
-
- if (m_stereo)
- right_buffer = outputs[1];
-
cassette_state state = get_state() & (CASSETTE_MASK_UISTATE | CASSETTE_MASK_MOTOR | CASSETTE_MASK_SPEAKER);
if (exists() && (state == (CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED)))
{
cassette_image *cassette = get_image();
double time_index = get_position();
- double duration = ((double) samples) / machine().sample_rate();
+ double duration = ((double) outputs[0].samples()) / outputs[0].sample_rate();
- cassette_get_samples(cassette, 0, time_index, duration, samples, 2, left_buffer, CASSETTE_WAVEFORM_16BIT);
- if (m_stereo)
- cassette_get_samples(cassette, 1, time_index, duration, samples, 2, right_buffer, CASSETTE_WAVEFORM_16BIT);
+ if (m_samples.size() < outputs[0].samples())
+ m_samples.resize(outputs[0].samples());
- for (int i = samples - 1; i >= 0; i--)
+ for (int ch = 0; ch < outputs.size(); ch++)
{
- left_buffer[i] = ((int16_t *) left_buffer)[i];
- if (m_stereo)
- right_buffer[i] = ((int16_t *) right_buffer)[i];
+ cassette->get_samples(0, time_index, duration, outputs[0].samples(), 2, &m_samples[0], cassette_image::WAVEFORM_16BIT);
+ for (int sampindex = 0; sampindex < outputs[ch].samples(); sampindex++)
+ outputs[ch].put_int(sampindex, m_samples[sampindex], 32768);
}
}
else
{
- memset(left_buffer, 0, sizeof(*left_buffer) * samples);
- if (m_stereo)
- memset(right_buffer, 0, sizeof(*right_buffer) * samples);
+ for (int ch = 0; ch < outputs.size(); ch++)
+ outputs[ch].fill(0);
}
}
diff --git a/src/devices/imagedev/cassette.h b/src/devices/imagedev/cassette.h
index a661e8312a8..e36b61d688d 100644
--- a/src/devices/imagedev/cassette.h
+++ b/src/devices/imagedev/cassette.h
@@ -53,8 +53,8 @@ public:
cassette_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~cassette_image_device();
- void set_formats(const struct CassetteFormat* const *formats) { m_formats = formats; }
- void set_create_opts(const struct CassetteOptions *create_opts) { m_create_opts = create_opts; }
+ void set_formats(const cassette_image::Format* const *formats) { m_formats = formats; }
+ void set_create_opts(const cassette_image::Options *create_opts) { m_create_opts = create_opts; }
void set_default_state(cassette_state default_state) { m_default_state = default_state; }
void set_interface(const char *interface) { m_interface = interface; }
@@ -92,7 +92,7 @@ public:
void set_speaker(int state) { change_state(state ? CASSETTE_SPEAKER_ENABLED : CASSETTE_SPEAKER_MUTED, CASSETTE_MASK_SPEAKER); }
int speaker_on() { return ((m_state & CASSETTE_MASK_SPEAKER) == CASSETTE_SPEAKER_ENABLED) ? 1 : 0; }
- cassette_image *get_image() { return m_cassette; }
+ cassette_image *get_image() { return m_cassette.get(); }
double get_position();
double get_length();
void set_speed(double speed);
@@ -102,7 +102,7 @@ public:
void seek(double time, int origin);
// sound stream update overrides
- void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
device_sound_interface& set_stereo() { m_stereo = true; return *this; }
protected:
@@ -117,7 +117,7 @@ protected:
void update();
private:
- cassette_image *m_cassette;
+ cassette_image::ptr m_cassette;
cassette_state m_state;
double m_position;
double m_position_time;
@@ -126,13 +126,14 @@ private:
double m_speed; // speed multiplier for tape speeds other than standard 1.875ips (used in adam driver)
int m_direction; // direction select
char m_extension_list[256];
- const struct CassetteFormat* const *m_formats;
- const struct CassetteOptions *m_create_opts;
+ const cassette_image::Format* const *m_formats;
+ const cassette_image::Options *m_create_opts;
cassette_state m_default_state;
const char * m_interface;
image_init_result internal_load(bool is_create);
bool m_stereo;
+ std::vector<s16> m_samples;
};
// device type definition
diff --git a/src/devices/imagedev/floppy.cpp b/src/devices/imagedev/floppy.cpp
index 3dd96644f1a..cf3ffefd524 100644
--- a/src/devices/imagedev/floppy.cpp
+++ b/src/devices/imagedev/floppy.cpp
@@ -178,7 +178,7 @@ floppy_image_device::floppy_image_device(const machine_config &mconfig, device_t
device_image_interface(mconfig, *this),
input_format(nullptr),
output_format(nullptr),
- image(nullptr),
+ image(),
fif_list(nullptr),
index_timer(nullptr),
tracks(0),
@@ -307,7 +307,7 @@ void floppy_image_device::commit_image()
if (err != osd_file::error::NONE)
popmessage("Error, unable to truncate image: %d", int(err));
- output_format->save(&io, image);
+ output_format->save(&io, image.get());
}
//-------------------------------------------------
@@ -459,7 +459,7 @@ image_init_result floppy_image_device::call_load()
io.filler = 0xff;
int best = 0;
floppy_image_format_t *best_format = nullptr;
- for(floppy_image_format_t *format = fif_list; format; format = format->next) {
+ for (floppy_image_format_t *format = fif_list; format; format = format->next) {
int score = format->identify(&io, form_factor);
if(score > best) {
best = score;
@@ -467,18 +467,15 @@ image_init_result floppy_image_device::call_load()
}
}
- if(!best_format)
- {
+ if (!best_format) {
seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to identify the image format");
return image_init_result::FAIL;
}
- image = global_alloc(floppy_image(tracks, sides, form_factor));
- if (!best_format->load(&io, form_factor, image))
- {
+ image = std::make_unique<floppy_image>(tracks, sides, form_factor);
+ if (!best_format->load(&io, form_factor, image.get())) {
seterror(IMAGE_ERROR_UNSUPPORTED, "Incompatible image format or corrupted data");
- global_free(image);
- image = nullptr;
+ image.reset();
return image_init_result::FAIL;
}
output_format = is_readonly() ? nullptr : best_format;
@@ -501,8 +498,7 @@ void floppy_image_device::call_unload()
if (image) {
if(image_dirty)
commit_image();
- global_free(image);
- image = nullptr;
+ image.reset();
}
wpt = 1; // disk sleeve is covering the sensor
@@ -526,7 +522,7 @@ void floppy_image_device::call_unload()
image_init_result floppy_image_device::call_create(int format_type, util::option_resolution *format_options)
{
- image = global_alloc(floppy_image(tracks, sides, form_factor));
+ image = std::make_unique<floppy_image>(tracks, sides, form_factor);
output_format = nullptr;
// search for a suitable format based on the extension
@@ -1248,7 +1244,7 @@ void floppy_sound_device::device_start()
// If we don't have all samples, don't allocate a stream or access sample data.
if (m_loaded)
{
- m_sound = stream_alloc_legacy(0, 1, clock()); // per-floppy stream
+ m_sound = stream_alloc(0, 1, clock()); // per-floppy stream
}
register_for_save_states();
}
@@ -1369,21 +1365,21 @@ void floppy_sound_device::step(int zone)
}
//-------------------------------------------------
-// sound_stream_update_legacy - update the sound stream
+// sound_stream_update - update the sound stream
//-------------------------------------------------
-void floppy_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void floppy_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// We are using only one stream, unlike the parent class
// Also, there is no need for interpolation, as we only expect
// one sample rate of 44100 for all samples
int16_t out;
- stream_sample_t *samplebuffer = outputs[0];
+ auto &samplebuffer = outputs[0];
int idx = 0;
int sampleend = 0;
- while (samples-- > 0)
+ for (int sampindex = 0; sampindex < samplebuffer.samples(); sampindex++)
{
out = 0;
@@ -1477,7 +1473,7 @@ void floppy_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
}
// Write to the stream buffer
- *(samplebuffer++) = out;
+ samplebuffer.put_int(sampindex, out, 32768);
}
}
diff --git a/src/devices/imagedev/floppy.h b/src/devices/imagedev/floppy.h
index d07a12c146c..b163b0b6a42 100644
--- a/src/devices/imagedev/floppy.h
+++ b/src/devices/imagedev/floppy.h
@@ -154,7 +154,7 @@ protected:
floppy_image_format_t *input_format;
floppy_image_format_t *output_format;
- floppy_image *image;
+ std::unique_ptr<floppy_image> image;
char extension_list[256];
floppy_image_format_t *fif_list;
emu_timer *index_timer;
@@ -294,7 +294,7 @@ protected:
private:
// device_sound_interface overrides
- void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
sound_stream* m_sound;
int m_step_base;
diff --git a/src/devices/imagedev/mfmhd.cpp b/src/devices/imagedev/mfmhd.cpp
index a90cf75ea54..61eabb12217 100644
--- a/src/devices/imagedev/mfmhd.cpp
+++ b/src/devices/imagedev/mfmhd.cpp
@@ -366,7 +366,7 @@ void mfm_harddisk_device::device_start()
m_current_cylinder = m_landing_zone; // Park position
m_spinup_timer->adjust(attotime::from_msec(m_spinupms));
- m_cache = global_alloc(mfmhd_trackimage_cache(machine()));
+ m_cache = std::make_unique<mfmhd_trackimage_cache>(machine());
// In 5 second periods, check whether the cache has dirty lines
m_cache_timer->adjust(attotime::from_msec(5000), 0, attotime::from_msec(5000));
@@ -411,7 +411,7 @@ void mfm_harddisk_device::device_reset()
void mfm_harddisk_device::device_stop()
{
- if (m_cache!=nullptr) global_free(m_cache);
+ m_cache.reset();
}
/*
@@ -1010,9 +1010,8 @@ mfmhd_trackimage_cache::~mfmhd_trackimage_cache()
while (current != nullptr)
{
- global_free_array(current->encdata);
mfmhd_trackimage* currenttmp = current->next;
- global_free(current);
+ delete current;
current = currenttmp;
}
}
@@ -1025,7 +1024,7 @@ void mfmhd_trackimage_cache::write_back_one()
{
if (current->dirty)
{
- m_mfmhd->write_track(current->encdata, current->cylinder, current->head);
+ m_mfmhd->write_track(current->encdata.get(), current->cylinder, current->head);
current->dirty = false;
break;
}
@@ -1045,7 +1044,7 @@ void mfmhd_trackimage_cache::cleanup()
if (TRACE_CACHE) m_machine.logerror("[%s:cache] MFM HD cache: evict line cylinder=%d head=%d\n", m_mfmhd->tag(), current->cylinder, current->head);
if (current->dirty)
{
- m_mfmhd->write_track(current->encdata, current->cylinder, current->head);
+ m_mfmhd->write_track(current->encdata.get(), current->cylinder, current->head);
current->dirty = false;
}
mfmhd_trackimage* currenttmp = current->next;
@@ -1087,11 +1086,11 @@ void mfmhd_trackimage_cache::init(mfm_harddisk_device* mfmhd, int tracksize, int
{
if (TRACE_DETAIL) m_machine.logerror("[%s:cache] MFM HD allocate cache slot\n", mfmhd->tag());
previous = current;
- current = global_alloc(mfmhd_trackimage);
- current->encdata = global_alloc_array(uint16_t, tracksize);
+ current = new mfmhd_trackimage;
+ current->encdata = std::make_unique<uint16_t []>(tracksize);
// Load the first tracks into the slots
- state = m_mfmhd->load_track(current->encdata, cylinder, head);
+ state = m_mfmhd->load_track(current->encdata.get(), cylinder, head);
if (state != CHDERR_NONE) throw emu_fatalerror("Cannot load (c=%d,h=%d) from hard disk", cylinder, head);
current->dirty = false;
@@ -1148,7 +1147,7 @@ uint16_t* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head)
current->next = m_tracks; // put the previous head into the next field
m_tracks = current; // set this line as new head
}
- return current->encdata;
+ return current->encdata.get();
}
else
{
@@ -1168,11 +1167,11 @@ uint16_t* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head)
if (current->dirty)
{
- m_mfmhd->write_track(current->encdata, current->cylinder, current->head);
+ m_mfmhd->write_track(current->encdata.get(), current->cylinder, current->head);
current->dirty = false;
}
- state = m_mfmhd->load_track(current->encdata, cylinder, head);
+ state = m_mfmhd->load_track(current->encdata.get(), cylinder, head);
current->dirty = false;
current->cylinder = cylinder;
diff --git a/src/devices/imagedev/mfmhd.h b/src/devices/imagedev/mfmhd.h
index 2d689a168cb..007be4be420 100644
--- a/src/devices/imagedev/mfmhd.h
+++ b/src/devices/imagedev/mfmhd.h
@@ -27,7 +27,7 @@ public:
bool dirty;
int cylinder;
int head;
- uint16_t* encdata; // MFM encoding per byte
+ std::unique_ptr<uint16_t []> encdata; // MFM encoding per byte
mfmhd_trackimage* next;
};
@@ -152,7 +152,7 @@ private:
attotime m_settle_time;
attotime m_step_time;
- mfmhd_trackimage_cache* m_cache;
+ std::unique_ptr<mfmhd_trackimage_cache> m_cache;
mfmhd_image_format_t* m_format;
void head_move();
diff --git a/src/devices/imagedev/midiin.cpp b/src/devices/imagedev/midiin.cpp
index 6086cb48a3e..62c7cba52a1 100644
--- a/src/devices/imagedev/midiin.cpp
+++ b/src/devices/imagedev/midiin.cpp
@@ -26,7 +26,7 @@ midiin_device::midiin_device(const machine_config &mconfig, const char *tag, dev
: device_t(mconfig, MIDIIN, tag, owner, clock),
device_image_interface(mconfig, *this),
device_serial_interface(mconfig, *this),
- m_midi(nullptr),
+ m_midi(),
m_timer(nullptr),
m_input_cb(*this),
m_xmit_read(0),
@@ -43,7 +43,7 @@ void midiin_device::device_start()
{
m_input_cb.resolve_safe();
m_timer = timer_alloc(0);
- m_midi = nullptr;
+ m_midi.reset();
m_timer->enable(false);
}
@@ -68,7 +68,7 @@ void midiin_device::device_timer(emu_timer &timer, device_timer_id id, int param
uint8_t buf[8192*4];
int bytesRead;
- if (m_midi == nullptr) {
+ if (!m_midi) {
return;
}
@@ -91,14 +91,13 @@ void midiin_device::device_timer(emu_timer &timer, device_timer_id id, int param
call_load
-------------------------------------------------*/
-image_init_result midiin_device::call_load(void)
+image_init_result midiin_device::call_load()
{
m_midi = machine().osd().create_midi_device();
if (!m_midi->open_input(filename()))
{
- global_free(m_midi);
- m_midi = nullptr;
+ m_midi.reset();
return image_init_result::FAIL;
}
@@ -111,15 +110,14 @@ image_init_result midiin_device::call_load(void)
call_unload
-------------------------------------------------*/
-void midiin_device::call_unload(void)
+void midiin_device::call_unload()
{
if (m_midi)
{
m_midi->close();
- global_free(m_midi);
}
- m_timer->enable(false);
- m_midi = nullptr;
+ m_midi.reset();
+ m_timer->enable(false);
}
void midiin_device::tra_complete()
diff --git a/src/devices/imagedev/midiin.h b/src/devices/imagedev/midiin.h
index ad9eeabf236..dbebdfd71fc 100644
--- a/src/devices/imagedev/midiin.h
+++ b/src/devices/imagedev/midiin.h
@@ -60,7 +60,7 @@ private:
void xmit_char(uint8_t data);
- osd_midi_device *m_midi;
+ std::unique_ptr<osd_midi_device> m_midi;
emu_timer *m_timer;
devcb_write_line m_input_cb;
uint8_t m_xmitring[XMIT_RING_SIZE];
diff --git a/src/devices/imagedev/midiout.cpp b/src/devices/imagedev/midiout.cpp
index 3c0613e2015..e9551a50d17 100644
--- a/src/devices/imagedev/midiout.cpp
+++ b/src/devices/imagedev/midiout.cpp
@@ -26,7 +26,7 @@ midiout_device::midiout_device(const machine_config &mconfig, const char *tag, d
: device_t(mconfig, MIDIOUT, tag, owner, clock),
device_image_interface(mconfig, *this),
device_serial_interface(mconfig, *this),
- m_midi(nullptr)
+ m_midi()
{
}
@@ -36,7 +36,7 @@ midiout_device::midiout_device(const machine_config &mconfig, const char *tag, d
void midiout_device::device_start()
{
- m_midi = nullptr;
+ m_midi.reset();
}
void midiout_device::device_reset()
@@ -51,14 +51,13 @@ void midiout_device::device_reset()
call_load
-------------------------------------------------*/
-image_init_result midiout_device::call_load(void)
+image_init_result midiout_device::call_load()
{
m_midi = machine().osd().create_midi_device();
if (!m_midi->open_output(filename()))
{
- global_free(m_midi);
- m_midi = nullptr;
+ m_midi.reset();
return image_init_result::FAIL;
}
@@ -69,13 +68,12 @@ image_init_result midiout_device::call_load(void)
call_unload
-------------------------------------------------*/
-void midiout_device::call_unload(void)
+void midiout_device::call_unload()
{
if (m_midi)
{
m_midi->close();
- global_free(m_midi);
- m_midi = nullptr;
+ m_midi.reset();
}
}
diff --git a/src/devices/imagedev/midiout.h b/src/devices/imagedev/midiout.h
index 2b182e0273d..20bc87131c5 100644
--- a/src/devices/imagedev/midiout.h
+++ b/src/devices/imagedev/midiout.h
@@ -53,7 +53,7 @@ protected:
virtual void rcv_complete() override; // Rx completed receiving byte
private:
- osd_midi_device *m_midi;
+ std::unique_ptr<osd_midi_device> m_midi;
};
// device type definition
diff --git a/src/devices/imagedev/picture.cpp b/src/devices/imagedev/picture.cpp
index f80bfb2885e..e6736fb10c9 100644
--- a/src/devices/imagedev/picture.cpp
+++ b/src/devices/imagedev/picture.cpp
@@ -10,7 +10,7 @@
#include "emu.h"
#include "picture.h"
-#include "png.h"
+#include "rendutil.h"
/***************************************************************************
TYPE DEFINITIONS
@@ -25,8 +25,7 @@ DEFINE_DEVICE_TYPE(IMAGE_PICTURE, picture_image_device, "picture_image", "Still
picture_image_device::picture_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, IMAGE_PICTURE, tag, owner, clock),
- device_image_interface(mconfig, *this),
- m_picture(nullptr)
+ device_image_interface(mconfig, *this)
{
}
@@ -36,11 +35,6 @@ picture_image_device::picture_image_device(const machine_config &mconfig, const
picture_image_device::~picture_image_device()
{
- if (m_picture)
- {
- delete m_picture;
- m_picture = nullptr;
- }
}
@@ -50,24 +44,31 @@ void picture_image_device::device_start()
image_init_result picture_image_device::call_load()
{
- m_picture = new bitmap_argb32;
- if (png_read_bitmap(image_core_file(), *m_picture) != PNGERR_NONE)
- {
- delete m_picture;
- m_picture = nullptr;
-
- // todo: try JPEG here.
- return image_init_result::FAIL;
+ switch (render_detect_image(image_core_file()))
+ {
+ case RENDUTIL_IMGFORMAT_PNG:
+ render_load_png(m_picture, image_core_file());
+ break;
+
+ case RENDUTIL_IMGFORMAT_JPEG:
+ render_load_jpeg(m_picture, image_core_file());
+ break;
+
+ case RENDUTIL_IMGFORMAT_MSDIB:
+ render_load_msdib(m_picture, image_core_file());
+ break;
+
+ default:
+ m_picture.reset();
}
- return image_init_result::PASS;
+ return m_picture.valid() ? image_init_result::PASS : image_init_result::FAIL;
}
void picture_image_device::call_unload()
{
- if (m_picture)
+ if (m_picture.valid())
{
- delete m_picture;
- m_picture = nullptr;
+ m_picture.reset();
}
}
diff --git a/src/devices/imagedev/picture.h b/src/devices/imagedev/picture.h
index f8601345a89..1780a563318 100644
--- a/src/devices/imagedev/picture.h
+++ b/src/devices/imagedev/picture.h
@@ -41,14 +41,14 @@ public:
virtual bool is_reset_on_load() const noexcept override { return false; }
virtual const char *file_extensions() const noexcept override { return "png"; }
- bitmap_argb32 &get_bitmap() { return *m_picture; }
+ const bitmap_argb32 &get_bitmap() { return m_picture; }
protected:
// device-level overrides
virtual void device_start() override;
private:
- bitmap_argb32 *m_picture;
+ bitmap_argb32 m_picture;
};
diff --git a/src/devices/machine/6840ptm.cpp b/src/devices/machine/6840ptm.cpp
index 849e59c05a7..21d8c0d80e9 100644
--- a/src/devices/machine/6840ptm.cpp
+++ b/src/devices/machine/6840ptm.cpp
@@ -156,6 +156,11 @@ void ptm6840_device::device_reset()
}
}
+void ptm6840_device::device_resolve_objects()
+{
+ for (int i = 0; i < 3; i++)
+ m_gate[i] = 0;
+}
//-------------------------------------------------
// device_timer - handle timer callbacks
diff --git a/src/devices/machine/6840ptm.h b/src/devices/machine/6840ptm.h
index 537fd4e7c19..6836aa5d317 100644
--- a/src/devices/machine/6840ptm.h
+++ b/src/devices/machine/6840ptm.h
@@ -58,6 +58,7 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
+ virtual void device_resolve_objects() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
diff --git a/src/devices/machine/8364_paula.cpp b/src/devices/machine/8364_paula.cpp
index 1e10ca55b3e..6869ffb3395 100644
--- a/src/devices/machine/8364_paula.cpp
+++ b/src/devices/machine/8364_paula.cpp
@@ -58,7 +58,7 @@ void paula_8364_device::device_start()
}
// create the stream
- m_stream = stream_alloc_legacy(0, 4, clock() / CLOCK_DIVIDER);
+ m_stream = stream_alloc(0, 4, clock() / CLOCK_DIVIDER);
}
//-------------------------------------------------
@@ -159,10 +159,10 @@ void paula_8364_device::dma_reload(audio_channel *chan)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void paula_8364_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void paula_8364_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int channum, sampoffs = 0;
@@ -176,11 +176,11 @@ void paula_8364_device::sound_stream_update_legacy(sound_stream &stream, stream_
// clear the sample data to 0
for (channum = 0; channum < 4; channum++)
- memset(outputs[channum], 0, sizeof(stream_sample_t) * samples);
+ outputs[channum].fill(0);
return;
}
- samples *= CLOCK_DIVIDER;
+ int samples = outputs[0].samples() * CLOCK_DIVIDER;
// update the DMA states on each channel and reload if fresh
for (channum = 0; channum < 4; channum++)
@@ -215,7 +215,7 @@ void paula_8364_device::sound_stream_update_legacy(sound_stream &stream, stream_
audio_channel *chan = &m_channel[channum];
int volume = (nextvol == -1) ? chan->vol : nextvol;
int period = (nextper == -1) ? chan->per : nextper;
- stream_sample_t sample;
+ s32 sample;
int i;
// normalize the volume value
@@ -247,7 +247,7 @@ void paula_8364_device::sound_stream_update_legacy(sound_stream &stream, stream_
// fill the buffer with the sample
for (i = 0; i < ticks; i += CLOCK_DIVIDER)
- outputs[channum][(sampoffs + i) / CLOCK_DIVIDER] = sample;
+ outputs[channum].put_int((sampoffs + i) / CLOCK_DIVIDER, sample, 32768);
// account for the ticks; if we hit 0, advance
chan->curticks -= ticks;
diff --git a/src/devices/machine/8364_paula.h b/src/devices/machine/8364_paula.h
index a2ac2feab26..9fa7a6ebf38 100644
--- a/src/devices/machine/8364_paula.h
+++ b/src/devices/machine/8364_paula.h
@@ -68,7 +68,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
enum
diff --git a/src/devices/machine/acorn_vidc.cpp b/src/devices/machine/acorn_vidc.cpp
index 36733555e7d..f0ebf10f612 100644
--- a/src/devices/machine/acorn_vidc.cpp
+++ b/src/devices/machine/acorn_vidc.cpp
@@ -492,9 +492,9 @@ void acorn_vidc10_device::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect,
if (is_cursor == true && dot == 0)
continue;
dot += pen_base;
- bitmap.pix32(dsty, dstx+xi) = this->pen(dot);
+ bitmap.pix(dsty, dstx+xi) = this->pen(dot);
if (m_crtc_interlace)
- bitmap.pix32(dsty+1, dstx+xi) = this->pen(dot);
+ bitmap.pix(dsty+1, dstx+xi) = this->pen(dot);
}
}
}
diff --git a/src/devices/machine/alpha_8921.h b/src/devices/machine/alpha_8921.h
index 88ecd850eb9..a6e8ccdb0ad 100644
--- a/src/devices/machine/alpha_8921.h
+++ b/src/devices/machine/alpha_8921.h
@@ -2,7 +2,7 @@
// copyright-holders:cam900
/***************************************************************************
- Alpha denshi ALPHA-8921 emulation
+ Alpha denshi ALPHA-8921 emulation
***************************************************************************/
diff --git a/src/devices/machine/am9519.h b/src/devices/machine/am9519.h
index 315e0bd890d..ec84cd50e52 100644
--- a/src/devices/machine/am9519.h
+++ b/src/devices/machine/am9519.h
@@ -32,7 +32,7 @@
class am9519_device : public device_t
{
public:
- am9519_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ am9519_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
auto out_int_callback() { return m_out_int_func.bind(); }
diff --git a/src/devices/machine/bl_handhelds_menucontrol.cpp b/src/devices/machine/bl_handhelds_menucontrol.cpp
new file mode 100644
index 00000000000..18982731069
--- /dev/null
+++ b/src/devices/machine/bl_handhelds_menucontrol.cpp
@@ -0,0 +1,214 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+// Menu controller, stores / increments menu position etc. used on handhelds that typically have BL on the boot screen (BaoBaoLong?)
+
+#include "emu.h"
+#include "machine/bl_handhelds_menucontrol.h"
+
+DEFINE_DEVICE_TYPE(BL_HANDHELDS_MENUCONTROL, bl_handhelds_menucontrol_device, "blhandheldmenu", "BaoBaoLong Handhelds Menu Controller")
+
+bl_handhelds_menucontrol_device::bl_handhelds_menucontrol_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, BL_HANDHELDS_MENUCONTROL, tag, owner, clock),
+ m_is_unsp_type_hack(false)
+{
+}
+
+READ_LINE_MEMBER(bl_handhelds_menucontrol_device::status_r)
+{
+ return m_clockstate;
+}
+
+READ_LINE_MEMBER(bl_handhelds_menucontrol_device::data_r)
+{
+ return m_responsebit;
+}
+
+// is there some 'carry' related behavior on the add / remove, because sometimes calculations are off by 1 eg command 0x05 (subtract) subcommand 0xf0
+// edge cases to test - moving up and left off entry 0, moving next / previous page when on any entry on the first/last pages, moving down/right off last entry, crossing 255/256 game boundary
+void bl_handhelds_menucontrol_device::handle_command()
+{
+ uint8_t command = m_command;
+
+ // additions and subtractions here are likely also meant to be done as high byte and low byte
+ if (m_menustate == MENU_READY_FOR_COMMAND)
+ {
+ if (command == 0x00)
+ {
+ m_menustate = MENU_COMMAND_00_IN;
+ m_response = m_menupos & 0xff;
+ }
+ else if (command == 0x01)
+ {
+ m_menustate = MENU_COMMAND_01_IN;
+ m_response = (m_menupos >> 8) & 0xff;
+ }
+ else if (command == 0x02)
+ {
+ m_menustate = MENU_COMMAND_02_IN;
+ }
+ else if (command == 0x03)
+ {
+ m_menustate = MENU_COMMAND_03_IN;
+ }
+ else if (command == 0x04)
+ {
+ m_menustate = MENU_COMMAND_04_IN;
+ }
+ else if (command == 0x05)
+ {
+ m_menustate = MENU_COMMAND_05_IN;
+ }
+ else if (command == 0x09)
+ {
+ // ...
+ }
+ else if ((command) == 0x10)
+ {
+ // this is followed by 0x1b, written if you try to move right off last entry
+ m_menupos = 0x00;
+ }
+ else if (command == 0x30)
+ {
+ m_menupos++;
+ }
+ else if (command == 0x37)
+ {
+ m_menupos--;
+ }
+ else if (command == 0x39)
+ {
+ m_menupos -= 4;
+ }
+ else if (command == 0x2c)
+ {
+ m_menupos = 0x01;
+ }
+ else
+ {
+ logerror("handle_command %02x (unknown)\n", command);
+ }
+ }
+ else if (m_menustate == MENU_COMMAND_00_IN)
+ {
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+ else if (m_menustate == MENU_COMMAND_01_IN)
+ {
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+ else if (m_menustate == MENU_COMMAND_02_IN)
+ {
+ m_menupos = (m_menupos & 0xff00) | ((command - 0x8) & 0xff);
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+ else if (m_menustate == MENU_COMMAND_03_IN)
+ {
+ m_menupos = (m_menupos & 0x00ff) | (((command - 0x9) & 0xff) << 8);
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+ else if (m_menustate == MENU_COMMAND_04_IN)
+ {
+ // used if you try to scroll up or left past 0 and the value becomes too large (a negative number)
+ if (m_is_unsp_type_hack)
+ {
+ if (command == 0x0d)
+ m_menupos += 4;
+ else if (command == 0x0a)
+ m_menupos += 0;
+ // used if you try to scroll up or left past 0 and the value becomes too large (a negative number)
+ // actually writes 0x314 split into 2 commands, so the 2nd write to 0x04 with param then instead 0b/16 sequence of writes instead of 26/0c adds to the high byte?
+ else if (command == 0x1e)
+ m_menupos += 0x310;
+ }
+ else
+ {
+ m_menupos += (command - 0x09);
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+ else if (m_menustate == MENU_COMMAND_05_IN)
+ {
+ // used if you try to scroll down past the and the value becomes too large
+ if (m_is_unsp_type_hack)
+ {
+ // actually writes 0x313 split into 2 commands, so the 2nd write to 0x05 with param then instead 0b/16 sequence of writes instead of 26/0c subtracts from the high byte?
+ if (command == 0x0b)
+ {
+ m_menupos -= 0xdc;
+ }
+ else if (command == 0x0e)
+ {
+ m_menupos -= 0x314;
+ }
+ }
+ else
+ {
+ if (command != 0xf0)
+ m_menupos -= (command - 0x0b);
+ else
+ m_menupos -= (command - 0x0a); // dphh8630 when pressing 'right' on final menu page
+ }
+
+ m_menustate = MENU_READY_FOR_COMMAND;
+ }
+}
+
+WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::clock_w)
+{
+ if (state)
+ {
+ m_clockstate = 1;
+ }
+ else
+ {
+ m_clockstate = 0;
+ m_command <<= 1;
+ m_command |= ((m_commandbit));
+ m_responsebit = (m_response >> (7 - m_datashifterpos)) & 1;
+ m_datashifterpos++;
+
+ if (m_datashifterpos == 8)
+ {
+ m_datashifterpos = 0;
+ handle_command();
+ }
+ }
+}
+
+WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::data_w)
+{
+ m_commandbit = state;
+}
+
+WRITE_LINE_MEMBER(bl_handhelds_menucontrol_device::reset_w)
+{
+ m_datashifterpos = 0;
+}
+
+void bl_handhelds_menucontrol_device::device_start()
+{
+ m_responsebit = 0;
+ m_clockstate = 0;
+ m_command = 0;
+ m_datashifterpos = 0;
+ m_menupos = 0;
+ m_response = 0;
+ m_commandbit = 0;
+ m_menustate = MENU_READY_FOR_COMMAND;
+
+ save_item(NAME(m_menupos));
+ save_item(NAME(m_clockstate));
+ save_item(NAME(m_datashifterpos));
+ save_item(NAME(m_responsebit));
+ save_item(NAME(m_response));
+ save_item(NAME(m_commandbit));
+ save_item(NAME(m_command));
+ save_item(NAME(m_menustate));
+}
+
+void bl_handhelds_menucontrol_device::device_reset()
+{
+}
diff --git a/src/devices/machine/bl_handhelds_menucontrol.h b/src/devices/machine/bl_handhelds_menucontrol.h
new file mode 100644
index 00000000000..747a60db76b
--- /dev/null
+++ b/src/devices/machine/bl_handhelds_menucontrol.h
@@ -0,0 +1,64 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_MACHINE_BL_HANDHELDS_MENUCONTROL_H
+#define MAME_MACHINE_BL_HANDHELDS_MENUCONTROL_H
+
+#pragma once
+
+DECLARE_DEVICE_TYPE(BL_HANDHELDS_MENUCONTROL, bl_handhelds_menucontrol_device)
+
+class bl_handhelds_menucontrol_device : public device_t
+{
+public:
+ // construction/destruction
+ bl_handhelds_menucontrol_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // the chip is the same between systems, but there's some logic not fully understood that is causing off-by-1 errors on some calcs
+ void set_is_unsp_type_hack() { m_is_unsp_type_hack = true; }
+
+ DECLARE_READ_LINE_MEMBER(status_r);
+ DECLARE_READ_LINE_MEMBER(data_r);
+ DECLARE_WRITE_LINE_MEMBER(clock_w);
+ DECLARE_WRITE_LINE_MEMBER(data_w);
+ DECLARE_WRITE_LINE_MEMBER(reset_w);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ // config
+ bool m_is_unsp_type_hack;
+
+ // internal state
+ uint16_t m_menupos;
+
+ // command handling
+ uint8_t m_clockstate;
+ uint8_t m_datashifterpos;
+
+ uint8_t m_responsebit;
+ uint8_t m_response;
+
+ uint8_t m_commandbit;
+ uint8_t m_command;
+
+ void handle_command();
+
+ enum menustate : uint8_t
+ {
+ MENU_READY_FOR_COMMAND = 0,
+
+ MENU_COMMAND_00_IN,
+ MENU_COMMAND_01_IN,
+ MENU_COMMAND_02_IN,
+ MENU_COMMAND_03_IN,
+ MENU_COMMAND_04_IN,
+ MENU_COMMAND_05_IN,
+ };
+
+ uint8_t m_menustate;
+};
+
+#endif // MAME_MACHINE_BL_HANDHELDS_MENUCONTROL_H
diff --git a/src/devices/machine/bq4847.cpp b/src/devices/machine/bq4847.cpp
index 09afd9b9424..7dd9031c814 100644
--- a/src/devices/machine/bq4847.cpp
+++ b/src/devices/machine/bq4847.cpp
@@ -305,6 +305,8 @@ uint8_t bq4847_device::read(offs_t address)
set_register(reg_flags, 0xff, false);
m_interrupt_cb(intrq_r());
}
+ else
+ if (regnum == reg_unused) value = 0; // Reg 15 is locked to 0 in BQ4847
LOGMASKED(LOG_REG, "Reg %d -> %02x\n", regnum, value);
diff --git a/src/devices/machine/cs8900a.cpp b/src/devices/machine/cs8900a.cpp
index 8a33504a2d8..6f6535150f7 100644
--- a/src/devices/machine/cs8900a.cpp
+++ b/src/devices/machine/cs8900a.cpp
@@ -4,11 +4,11 @@
/*************************************************************************
- CS8900A ethernet controller implementation
+ CS8900A ethernet controller implementation
- by Rhett Aultman <roadriverrail@gmail.com>
- ported to MAME from VICE Project (https://sourceforge.net/p/vice-emu/)
- VICE CS8900 code by Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
+ by Rhett Aultman <roadriverrail@gmail.com>
+ ported to MAME from VICE Project (https://sourceforge.net/p/vice-emu/)
+ VICE CS8900 code by Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
**************************************************************************/
@@ -20,17 +20,17 @@
DEFINE_DEVICE_TYPE(CS8900A, cs8900a_device, "cs8900a", "CS8900A Crystal LAN 10Base-T Ethernet MAC")
/* warn illegal behaviour */
-#define CS8900_DEBUG_WARN_REG (1 << 1U) /* warn about invalid register accesses */
-#define CS8900_DEBUG_WARN_RXTX (1 << 2U) /* warn about invalid rx or tx conditions */
+#define CS8900_DEBUG_WARN_REG (1 << 1U) /* warn about invalid register accesses */
+#define CS8900_DEBUG_WARN_RXTX (1 << 2U) /* warn about invalid rx or tx conditions */
-#define CS8900_DEBUG (1 << 3U) /* enable to see port reads */
+#define CS8900_DEBUG (1 << 3U) /* enable to see port reads */
#define CS8900_DEBUG_INIT (1 << 4U)
-#define CS8900_DEBUG_LOAD (1 << 5U) /* enable to see port reads */
-#define CS8900_DEBUG_STORE (1 << 6U) /* enable to see port writes */
-#define CS8900_DEBUG_REGISTERS (1 << 7U) /* enable to see CS8900a register I/O */
-#define CS8900_DEBUG_RXTX_STATE (1 << 8U) /* enable to see tranceiver state changes */
-#define CS8900_DEBUG_RXTX_DATA (1 << 9U) /* enable to see data in/out flow */
-#define CS8900_DEBUG_FRAMES (1 << 10U) /* enable to see arch frame send/recv */
+#define CS8900_DEBUG_LOAD (1 << 5U) /* enable to see port reads */
+#define CS8900_DEBUG_STORE (1 << 6U) /* enable to see port writes */
+#define CS8900_DEBUG_REGISTERS (1 << 7U) /* enable to see CS8900a register I/O */
+#define CS8900_DEBUG_RXTX_STATE (1 << 8U) /* enable to see tranceiver state changes */
+#define CS8900_DEBUG_RXTX_DATA (1 << 9U) /* enable to see data in/out flow */
+#define CS8900_DEBUG_FRAMES (1 << 10U) /* enable to see arch frame send/recv */
/** #define CS8900_DEBUG_IGNORE_RXEVENT 1 **/ /* enable to ignore RXEVENT in DEBUG_REGISTERS */
#define VERBOSE 0
@@ -41,57 +41,57 @@ DEFINE_DEVICE_TYPE(CS8900A, cs8900a_device, "cs8900a", "CS8900A Crystal LAN 10Ba
/* CS8900 registers */
-/* these are the 8 16-bit-ports for "I/O space configuration"
- (see 4.10 on page 75 of cs8900a-4.pdf, the cs8900a data sheet)
+/* these are the 8 16-bit-ports for "I/O space configuration"
+ (see 4.10 on page 75 of cs8900a-4.pdf, the cs8900a data sheet)
- REMARK: The code operatoes the cs8900a in IO space configuration, as
- it generates I/OW and I/OR signals.
+ REMARK: The code operatoes the cs8900a in IO space configuration, as
+ it generates I/OW and I/OR signals.
*/
/*
- RW: RXTXDATA = DE00/DE01
- RW: RXTXDATA2 = DE02/DE03 (for 32-bit-operation)
- -W: TXCMD = DE04/DE05 (TxCMD, Transmit Command) mapped to PP + 0144 (Reg. 9, Sec. 4.4, page 46)
- -W: TXLENGTH = DE06/DE07 (TxLenght, Transmit Length) mapped to PP + 0146
- R-: INTSTQUEUE = DE08/DE09 (Interrupt Status Queue) mapped to PP + 0120 (ISQ, Sec. 5.1, page 78)
- RW: PP_PTR = DE0A/DE0B (PacketPage Pointer) (see. page 75p: Read -011.---- ----.----)
- RW: PP_DATA0 = DE0C/DE0D (PacketPage Data (Port 0))
- RW: PP_DATA1 = DE0E/DE0F (PacketPage Data (Port 1)) (for 32 bit only)
+ RW: RXTXDATA = DE00/DE01
+ RW: RXTXDATA2 = DE02/DE03 (for 32-bit-operation)
+ -W: TXCMD = DE04/DE05 (TxCMD, Transmit Command) mapped to PP + 0144 (Reg. 9, Sec. 4.4, page 46)
+ -W: TXLENGTH = DE06/DE07 (TxLenght, Transmit Length) mapped to PP + 0146
+ R-: INTSTQUEUE = DE08/DE09 (Interrupt Status Queue) mapped to PP + 0120 (ISQ, Sec. 5.1, page 78)
+ RW: PP_PTR = DE0A/DE0B (PacketPage Pointer) (see. page 75p: Read -011.---- ----.----)
+ RW: PP_DATA0 = DE0C/DE0D (PacketPage Data (Port 0))
+ RW: PP_DATA1 = DE0E/DE0F (PacketPage Data (Port 1)) (for 32 bit only)
*/
enum io_space_conf_regs_e : u8 {
- CS8900_ADDR_RXTXDATA = 0x00, /* RW */
- CS8900_ADDR_RXTXDATA2 = 0x02, /* RW 32 bit only! */
- CS8900_ADDR_TXCMD = 0x04, /* -W Maps to PP+0144 */
- CS8900_ADDR_TXLENGTH = 0x06, /* -W Maps to PP+0146 */
- CS8900_ADDR_INTSTQUEUE = 0x08, /* R- Interrupt status queue, maps to PP + 0120 */
- CS8900_ADDR_PP_PTR = 0x0a, /* RW PacketPage Pointer */
- CS8900_ADDR_PP_DATA = 0x0c, /* RW PacketPage Data, Port 0 */
- CS8900_ADDR_PP_DATA2 = 0x0e /* RW PacketPage Data, Port 1 - 32 bit only */
+ CS8900_ADDR_RXTXDATA = 0x00, /* RW */
+ CS8900_ADDR_RXTXDATA2 = 0x02, /* RW 32 bit only! */
+ CS8900_ADDR_TXCMD = 0x04, /* -W Maps to PP+0144 */
+ CS8900_ADDR_TXLENGTH = 0x06, /* -W Maps to PP+0146 */
+ CS8900_ADDR_INTSTQUEUE = 0x08, /* R- Interrupt status queue, maps to PP + 0120 */
+ CS8900_ADDR_PP_PTR = 0x0a, /* RW PacketPage Pointer */
+ CS8900_ADDR_PP_DATA = 0x0c, /* RW PacketPage Data, Port 0 */
+ CS8900_ADDR_PP_DATA2 = 0x0e /* RW PacketPage Data, Port 1 - 32 bit only */
};
/* Makros for reading and writing the visible register: */
-#define GET_CS8900_8(_xxx_) \
- (assert(_xxx_ < CS8900_COUNT_IO_REGISTER), \
- cs8900_ioregs[_xxx_] \
+#define GET_CS8900_8(_xxx_) \
+ (assert(_xxx_ < CS8900_COUNT_IO_REGISTER), \
+ cs8900_ioregs[_xxx_] \
)
-#define SET_CS8900_8(_xxx_, _val_) \
- do { \
- assert(_xxx_ < CS8900_COUNT_IO_REGISTER); \
- cs8900_ioregs[_xxx_] = (_val_) & 0xff; \
+#define SET_CS8900_8(_xxx_, _val_) \
+ do { \
+ assert(_xxx_ < CS8900_COUNT_IO_REGISTER); \
+ cs8900_ioregs[_xxx_] = (_val_) & 0xff; \
} while (0)
-#define GET_CS8900_16(_xxx_) \
- (assert(_xxx_ < CS8900_COUNT_IO_REGISTER), \
- cs8900_ioregs[_xxx_] | (cs8900_ioregs[_xxx_ + 1] << 8) \
+#define GET_CS8900_16(_xxx_) \
+ (assert(_xxx_ < CS8900_COUNT_IO_REGISTER), \
+ cs8900_ioregs[_xxx_] | (cs8900_ioregs[_xxx_ + 1] << 8) \
)
-#define SET_CS8900_16(_xxx_, _val_) \
- do { \
- assert(_xxx_ < CS8900_COUNT_IO_REGISTER); \
- cs8900_ioregs[_xxx_] = (_val_) & 0xff; \
- cs8900_ioregs[_xxx_ + 1] = (_val_ >> 8) & 0xff; \
+#define SET_CS8900_16(_xxx_, _val_) \
+ do { \
+ assert(_xxx_ < CS8900_COUNT_IO_REGISTER); \
+ cs8900_ioregs[_xxx_] = (_val_) & 0xff; \
+ cs8900_ioregs[_xxx_ + 1] = (_val_ >> 8) & 0xff; \
} while (0)
/* The PacketPage register */
@@ -99,106 +99,106 @@ enum io_space_conf_regs_e : u8 {
/* Macros for reading and writing the PacketPage register: */
-#define GET_PP_8(_xxx_) \
- (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), \
- cs8900_packetpage[_xxx_] \
+#define GET_PP_8(_xxx_) \
+ (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), \
+ cs8900_packetpage[_xxx_] \
)
-#define GET_PP_16(_xxx_) \
- (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), \
- assert((_xxx_ & 1) == 0), \
- ((u16)cs8900_packetpage[_xxx_]) \
- |((u16)cs8900_packetpage[_xxx_ + 1] << 8) \
+#define GET_PP_16(_xxx_) \
+ (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), \
+ assert((_xxx_ & 1) == 0), \
+ ((u16)cs8900_packetpage[_xxx_]) \
+ |((u16)cs8900_packetpage[_xxx_ + 1] << 8) \
)
-#define GET_PP_32(_xxx_) \
- (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), \
- assert((_xxx_ & 3) == 0), \
- (((u32)cs8900_packetpage[_xxx_])) \
- |(((u32)cs8900_packetpage[_xxx_ + 1]) << 8) \
- |(((u32)cs8900_packetpage[_xxx_ + 2]) << 16) \
- |(((u32)cs8900_packetpage[_xxx_ + 3]) << 24) \
+#define GET_PP_32(_xxx_) \
+ (assert(_xxx_ < MAX_PACKETPAGE_ARRAY), \
+ assert((_xxx_ & 3) == 0), \
+ (((u32)cs8900_packetpage[_xxx_])) \
+ |(((u32)cs8900_packetpage[_xxx_ + 1]) << 8) \
+ |(((u32)cs8900_packetpage[_xxx_ + 2]) << 16) \
+ |(((u32)cs8900_packetpage[_xxx_ + 3]) << 24) \
)
-#define SET_PP_8(_xxx_, _val_) \
- do { \
- assert(_xxx_ < MAX_PACKETPAGE_ARRAY); \
- cs8900_packetpage[_xxx_] = (_val_) & 0xFF; \
+#define SET_PP_8(_xxx_, _val_) \
+ do { \
+ assert(_xxx_ < MAX_PACKETPAGE_ARRAY); \
+ cs8900_packetpage[_xxx_] = (_val_) & 0xFF; \
} while (0)
-#define SET_PP_16(_xxx_, _val_) \
- do { \
- assert(_xxx_ < MAX_PACKETPAGE_ARRAY); \
- assert((_xxx_ & 1) == 0), \
- cs8900_packetpage[_xxx_] = (_val_) & 0xFF; \
- cs8900_packetpage[_xxx_ + 1] = (_val_ >> 8) & 0xFF; \
+#define SET_PP_16(_xxx_, _val_) \
+ do { \
+ assert(_xxx_ < MAX_PACKETPAGE_ARRAY); \
+ assert((_xxx_ & 1) == 0), \
+ cs8900_packetpage[_xxx_] = (_val_) & 0xFF; \
+ cs8900_packetpage[_xxx_ + 1] = (_val_ >> 8) & 0xFF; \
} while (0)
-#define SET_PP_32(_xxx_, _val_) \
- do { \
- assert(_xxx_ < MAX_PACKETPAGE_ARRAY); \
- assert((_xxx_ & 3) == 0), \
- cs8900_packetpage[_xxx_] = (_val_) & 0xFF; \
- cs8900_packetpage[_xxx_ + 1] = (_val_ >> 8) & 0xFF; \
- cs8900_packetpage[_xxx_ + 2] = (_val_ >> 16) & 0xFF; \
- cs8900_packetpage[_xxx_ + 3] = (_val_ >> 24) & 0xFF; \
+#define SET_PP_32(_xxx_, _val_) \
+ do { \
+ assert(_xxx_ < MAX_PACKETPAGE_ARRAY); \
+ assert((_xxx_ & 3) == 0), \
+ cs8900_packetpage[_xxx_] = (_val_) & 0xFF; \
+ cs8900_packetpage[_xxx_ + 1] = (_val_ >> 8) & 0xFF; \
+ cs8900_packetpage[_xxx_ + 2] = (_val_ >> 16) & 0xFF; \
+ cs8900_packetpage[_xxx_ + 3] = (_val_ >> 24) & 0xFF; \
} while (0)
enum packetpage_regs_e : u16 {
/* The packetpage register: see p. 39f */
- CS8900_PP_ADDR_PRODUCTID = 0x0000, /* R- - 4.3., p. 41 */
- CS8900_PP_ADDR_IOBASE = 0x0020, /* i RW - 4.3., p. 41 - 4.7., p. 72 */
- CS8900_PP_ADDR_INTNO = 0x0022, /* i RW - 3.2., p. 17 - 4.3., p. 41 */
- CS8900_PP_ADDR_DMA_CHAN = 0x0024, /* i RW - 3.2., p. 17 - 4.3., p. 41 */
- CS8900_PP_ADDR_DMA_SOF = 0x0026, /* ? R- - 4.3., p. 41 - 5.4., p. 89 */
- CS8900_PP_ADDR_DMA_FC = 0x0028, /* ? R- - 4.3., p. 41, "Receive DMA" */
- CS8900_PP_ADDR_RXDMA_BC = 0x002a, /* ? R- - 4.3., p. 41 - 5.4., p. 89 */
- CS8900_PP_ADDR_MEMBASE = 0x002c, /* i RW - 4.3., p. 41 - 4.9., p. 73 */
- CS8900_PP_ADDR_BPROM_BASE = 0x0030, /* i RW - 3.6., p. 24 - 4.3., p. 41 */
- CS8900_PP_ADDR_BPROM_MASK = 0x0034, /* i RW - 3.6., p. 24 - 4.3., p. 41 */
+ CS8900_PP_ADDR_PRODUCTID = 0x0000, /* R- - 4.3., p. 41 */
+ CS8900_PP_ADDR_IOBASE = 0x0020, /* i RW - 4.3., p. 41 - 4.7., p. 72 */
+ CS8900_PP_ADDR_INTNO = 0x0022, /* i RW - 3.2., p. 17 - 4.3., p. 41 */
+ CS8900_PP_ADDR_DMA_CHAN = 0x0024, /* i RW - 3.2., p. 17 - 4.3., p. 41 */
+ CS8900_PP_ADDR_DMA_SOF = 0x0026, /* ? R- - 4.3., p. 41 - 5.4., p. 89 */
+ CS8900_PP_ADDR_DMA_FC = 0x0028, /* ? R- - 4.3., p. 41, "Receive DMA" */
+ CS8900_PP_ADDR_RXDMA_BC = 0x002a, /* ? R- - 4.3., p. 41 - 5.4., p. 89 */
+ CS8900_PP_ADDR_MEMBASE = 0x002c, /* i RW - 4.3., p. 41 - 4.9., p. 73 */
+ CS8900_PP_ADDR_BPROM_BASE = 0x0030, /* i RW - 3.6., p. 24 - 4.3., p. 41 */
+ CS8900_PP_ADDR_BPROM_MASK = 0x0034, /* i RW - 3.6., p. 24 - 4.3., p. 41 */
/* 0x0038 - 0x003F: reserved */
- CS8900_PP_ADDR_EEPROM_CMD = 0x0040, /* i RW - 3.5., p. 23 - 4.3., p. 41 */
- CS8900_PP_ADDR_EEPROM_DATA = 0x0042, /* i RW - 3.5., p. 23 - 4.3., p. 41 */
+ CS8900_PP_ADDR_EEPROM_CMD = 0x0040, /* i RW - 3.5., p. 23 - 4.3., p. 41 */
+ CS8900_PP_ADDR_EEPROM_DATA = 0x0042, /* i RW - 3.5., p. 23 - 4.3., p. 41 */
/* 0x0044 - 0x004F: reserved */
- CS8900_PP_ADDR_REC_FRAME_BC = 0x0050, /* RW - 4.3., p. 41 - 5.2.9., p. 86 */
+ CS8900_PP_ADDR_REC_FRAME_BC = 0x0050, /* RW - 4.3., p. 41 - 5.2.9., p. 86 */
/* 0x0052 - 0x00FF: reserved */
- CS8900_PP_ADDR_CONF_CTRL = 0x0100, /* - RW - 4.4., p. 46; see below */
- CS8900_PP_ADDR_STATUS_EVENT = 0x0120, /* - R- - 4.4., p. 46; see below */
+ CS8900_PP_ADDR_CONF_CTRL = 0x0100, /* - RW - 4.4., p. 46; see below */
+ CS8900_PP_ADDR_STATUS_EVENT = 0x0120, /* - R- - 4.4., p. 46; see below */
/* 0x0140 - 0x0143: reserved */
- CS8900_PP_ADDR_TXCMD = 0x0144, /* # -W - 4.5., p. 70 - 5.7., p. 98 */
- CS8900_PP_ADDR_TXLENGTH = 0x0146, /* # -W - 4.5., p. 70 - 5.7., p. 98 */
+ CS8900_PP_ADDR_TXCMD = 0x0144, /* # -W - 4.5., p. 70 - 5.7., p. 98 */
+ CS8900_PP_ADDR_TXLENGTH = 0x0146, /* # -W - 4.5., p. 70 - 5.7., p. 98 */
/* 0x0148 - 0x014F: reserved */
- CS8900_PP_ADDR_LOG_ADDR_FILTER = 0x0150, /* RW - 4.6., p. 71 - 5.3., p. 86 */
- CS8900_PP_ADDR_MAC_ADDR = 0x0158, /* # RW - 4.6., p. 71 - 5.3., p. 86 */
+ CS8900_PP_ADDR_LOG_ADDR_FILTER = 0x0150, /* RW - 4.6., p. 71 - 5.3., p. 86 */
+ CS8900_PP_ADDR_MAC_ADDR = 0x0158, /* # RW - 4.6., p. 71 - 5.3., p. 86 */
/* 0x015E - 0x03FF: reserved */
- CS8900_PP_ADDR_RXSTATUS = 0x0400, /* R- - 4.7., p. 72 - 5.2., p. 78 */
- CS8900_PP_ADDR_RXLENGTH = 0x0402, /* R- - 4.7., p. 72 - 5.2., p. 78 */
- CS8900_PP_ADDR_RX_FRAMELOC = 0x0404, /* R- - 4.7., p. 72 - 5.2., p. 78 */
+ CS8900_PP_ADDR_RXSTATUS = 0x0400, /* R- - 4.7., p. 72 - 5.2., p. 78 */
+ CS8900_PP_ADDR_RXLENGTH = 0x0402, /* R- - 4.7., p. 72 - 5.2., p. 78 */
+ CS8900_PP_ADDR_RX_FRAMELOC = 0x0404, /* R- - 4.7., p. 72 - 5.2., p. 78 */
/* here, the received frame is stored */
- CS8900_PP_ADDR_TX_FRAMELOC = 0x0A00, /* -W - 4.7., p. 72 - 5.7., p. 98 */
+ CS8900_PP_ADDR_TX_FRAMELOC = 0x0A00, /* -W - 4.7., p. 72 - 5.7., p. 98 */
/* here, the frame to transmit is stored */
- CS8900_PP_ADDR_END = 0x1000, /* memory to CS8900_PP_ADDR_END-1 is used */
+ CS8900_PP_ADDR_END = 0x1000, /* memory to CS8900_PP_ADDR_END-1 is used */
/* CS8900_PP_ADDR_CONF_CTRL is subdivided: */
- CS8900_PP_ADDR_CC_RXCFG = 0x0102, /* # RW - 4.4.6., p. 52 - 0003 */
- CS8900_PP_ADDR_CC_RXCTL = 0x0104, /* # RW - 4.4.8., p. 54 - 0005 */
- CS8900_PP_ADDR_CC_TXCFG = 0x0106, /* RW - 4.4.9., p. 55 - 0007 */
- CS8900_PP_ADDR_CC_TXCMD = 0x0108, /* R- - 4.4.11., p. 57 - 0009 */
- CS8900_PP_ADDR_CC_BUFCFG = 0x010A, /* RW - 4.4.12., p. 58 - 000B */
- CS8900_PP_ADDR_CC_LINECTL = 0x0112, /* # RW - 4.4.16., p. 62 - 0013 */
- CS8900_PP_ADDR_CC_SELFCTL = 0x0114, /* RW - 4.4.18., p. 64 - 0015 */
- CS8900_PP_ADDR_CC_BUSCTL = 0x0116, /* RW - 4.4.20., p. 66 - 0017 */
- CS8900_PP_ADDR_CC_TESTCTL = 0x0118, /* RW - 4.4.22., p. 68 - 0019 */
+ CS8900_PP_ADDR_CC_RXCFG = 0x0102, /* # RW - 4.4.6., p. 52 - 0003 */
+ CS8900_PP_ADDR_CC_RXCTL = 0x0104, /* # RW - 4.4.8., p. 54 - 0005 */
+ CS8900_PP_ADDR_CC_TXCFG = 0x0106, /* RW - 4.4.9., p. 55 - 0007 */
+ CS8900_PP_ADDR_CC_TXCMD = 0x0108, /* R- - 4.4.11., p. 57 - 0009 */
+ CS8900_PP_ADDR_CC_BUFCFG = 0x010A, /* RW - 4.4.12., p. 58 - 000B */
+ CS8900_PP_ADDR_CC_LINECTL = 0x0112, /* # RW - 4.4.16., p. 62 - 0013 */
+ CS8900_PP_ADDR_CC_SELFCTL = 0x0114, /* RW - 4.4.18., p. 64 - 0015 */
+ CS8900_PP_ADDR_CC_BUSCTL = 0x0116, /* RW - 4.4.20., p. 66 - 0017 */
+ CS8900_PP_ADDR_CC_TESTCTL = 0x0118, /* RW - 4.4.22., p. 68 - 0019 */
/* CS8900_PP_ADDR_STATUS_EVENT is subdivided: */
- CS8900_PP_ADDR_SE_ISQ = 0x0120, /* R- - 4.4.5., p. 51 - 0000 */
- CS8900_PP_ADDR_SE_RXEVENT = 0x0124, /* # R- - 4.4.7., p. 53 - 0004 */
- CS8900_PP_ADDR_SE_TXEVENT = 0x0128, /* R- - 4.4.10., p. 56 - 0008 */
- CS8900_PP_ADDR_SE_BUFEVENT = 0x012C, /* R- - 4.4.13., p. 59 - 000C */
- CS8900_PP_ADDR_SE_RXMISS = 0x0130, /* R- - 4.4.14., p. 60 - 0010 */
- CS8900_PP_ADDR_SE_TXCOL = 0x0132, /* R- - 4.4.15., p. 61 - 0012 */
- CS8900_PP_ADDR_SE_LINEST = 0x0134, /* R- - 4.4.17., p. 63 - 0014 */
- CS8900_PP_ADDR_SE_SELFST = 0x0136, /* R- - 4.4.19., p. 65 - 0016 */
- CS8900_PP_ADDR_SE_BUSST = 0x0138, /* # R- - 4.4.21., p. 67 - 0018 */
- CS8900_PP_ADDR_SE_TDR = 0x013C /* R- - 4.4.23., p. 69 - 001C */
+ CS8900_PP_ADDR_SE_ISQ = 0x0120, /* R- - 4.4.5., p. 51 - 0000 */
+ CS8900_PP_ADDR_SE_RXEVENT = 0x0124, /* # R- - 4.4.7., p. 53 - 0004 */
+ CS8900_PP_ADDR_SE_TXEVENT = 0x0128, /* R- - 4.4.10., p. 56 - 0008 */
+ CS8900_PP_ADDR_SE_BUFEVENT = 0x012C, /* R- - 4.4.13., p. 59 - 000C */
+ CS8900_PP_ADDR_SE_RXMISS = 0x0130, /* R- - 4.4.14., p. 60 - 0010 */
+ CS8900_PP_ADDR_SE_TXCOL = 0x0132, /* R- - 4.4.15., p. 61 - 0012 */
+ CS8900_PP_ADDR_SE_LINEST = 0x0134, /* R- - 4.4.17., p. 63 - 0014 */
+ CS8900_PP_ADDR_SE_SELFST = 0x0136, /* R- - 4.4.19., p. 65 - 0016 */
+ CS8900_PP_ADDR_SE_BUSST = 0x0138, /* # R- - 4.4.21., p. 67 - 0018 */
+ CS8900_PP_ADDR_SE_TDR = 0x013C /* R- - 4.4.23., p. 69 - 001C */
};
enum tx_rx_min_max_e : u16 {
@@ -209,21 +209,21 @@ enum tx_rx_min_max_e : u16 {
};
enum cs8900_tx_state_e : u8 {
- CS8900_TX_IDLE = 0,
- CS8900_TX_GOT_CMD = 1,
- CS8900_TX_GOT_LEN = 2,
- CS8900_TX_READ_BUSST = 3
+ CS8900_TX_IDLE = 0,
+ CS8900_TX_GOT_CMD = 1,
+ CS8900_TX_GOT_LEN = 2,
+ CS8900_TX_READ_BUSST = 3
};
enum cs8900_rx_state_e : u8 {
- CS8900_RX_IDLE = 0,
- CS8900_RX_GOT_FRAME = 1
+ CS8900_RX_IDLE = 0,
+ CS8900_RX_GOT_FRAME = 1
};
enum pp_ptr_masks_e : u16 {
- PP_PTR_AUTO_INCR_FLAG = 0x8000, /* auto increment flag in package pointer */
- PP_PTR_FLAG_MASK = 0xf000, /* is always : x y 1 1 (with x=auto incr) */
- PP_PTR_ADDR_MASK = 0x0fff /* address portion of packet page pointer */
+ PP_PTR_AUTO_INCR_FLAG = 0x8000, /* auto increment flag in package pointer */
+ PP_PTR_FLAG_MASK = 0xf000, /* is always : x y 1 1 (with x=auto incr) */
+ PP_PTR_ADDR_MASK = 0x0fff /* address portion of packet page pointer */
};
#define LO_BYTE(x) (u8)((x)& 0xff)
@@ -255,10 +255,10 @@ void cs8900a_device::cs8900_set_tx_status(int ready, int error)
u16 new_status = old_status & ~0x180;
if (ready)
- new_status |= 0x100; /* set Rdy4TxNOW */
+ new_status |= 0x100; /* set Rdy4TxNOW */
if (error)
- new_status |= 0x080; /* set TxBidErr */
+ new_status |= 0x080; /* set TxBidErr */
if (new_status != old_status)
{
@@ -301,39 +301,39 @@ void cs8900a_device::device_reset()
SET_PP_16(CS8900_PP_ADDR_DMA_CHAN, 0x0003); /* xxxx xxxx xxxx xx11b */
/* according to descriptions of the registers, see definitions of
- CS8900_PP_ADDR_CC_... and CS8900_PP_ADDR_SE_... above! */
-
- SET_PP_16(CS8900_PP_ADDR_CC_RXCFG, 0x0003);
- SET_PP_16(CS8900_PP_ADDR_CC_RXCTL, 0x0005);
- SET_PP_16(CS8900_PP_ADDR_CC_TXCFG, 0x0007);
- SET_PP_16(CS8900_PP_ADDR_CC_TXCMD, 0x0009);
- SET_PP_16(CS8900_PP_ADDR_CC_BUFCFG, 0x000B);
- SET_PP_16(CS8900_PP_ADDR_CC_LINECTL, 0x0013);
- SET_PP_16(CS8900_PP_ADDR_CC_SELFCTL, 0x0015);
- SET_PP_16(CS8900_PP_ADDR_CC_BUSCTL, 0x0017);
- SET_PP_16(CS8900_PP_ADDR_CC_TESTCTL, 0x0019);
-
- SET_PP_16(CS8900_PP_ADDR_SE_ISQ, 0x0000);
- SET_PP_16(CS8900_PP_ADDR_SE_RXEVENT, 0x0004);
- SET_PP_16(CS8900_PP_ADDR_SE_TXEVENT, 0x0008);
- SET_PP_16(CS8900_PP_ADDR_SE_BUFEVENT, 0x000C);
- SET_PP_16(CS8900_PP_ADDR_SE_RXMISS, 0x0010);
- SET_PP_16(CS8900_PP_ADDR_SE_TXCOL, 0x0012);
- SET_PP_16(CS8900_PP_ADDR_SE_LINEST, 0x0014);
- SET_PP_16(CS8900_PP_ADDR_SE_SELFST, 0x0016);
- SET_PP_16(CS8900_PP_ADDR_SE_BUSST, 0x0018);
- SET_PP_16(CS8900_PP_ADDR_SE_TDR, 0x001C);
-
- SET_PP_16(CS8900_PP_ADDR_TXCMD, 0x0009);
+ CS8900_PP_ADDR_CC_... and CS8900_PP_ADDR_SE_... above! */
+
+ SET_PP_16(CS8900_PP_ADDR_CC_RXCFG, 0x0003);
+ SET_PP_16(CS8900_PP_ADDR_CC_RXCTL, 0x0005);
+ SET_PP_16(CS8900_PP_ADDR_CC_TXCFG, 0x0007);
+ SET_PP_16(CS8900_PP_ADDR_CC_TXCMD, 0x0009);
+ SET_PP_16(CS8900_PP_ADDR_CC_BUFCFG, 0x000B);
+ SET_PP_16(CS8900_PP_ADDR_CC_LINECTL, 0x0013);
+ SET_PP_16(CS8900_PP_ADDR_CC_SELFCTL, 0x0015);
+ SET_PP_16(CS8900_PP_ADDR_CC_BUSCTL, 0x0017);
+ SET_PP_16(CS8900_PP_ADDR_CC_TESTCTL, 0x0019);
+
+ SET_PP_16(CS8900_PP_ADDR_SE_ISQ, 0x0000);
+ SET_PP_16(CS8900_PP_ADDR_SE_RXEVENT, 0x0004);
+ SET_PP_16(CS8900_PP_ADDR_SE_TXEVENT, 0x0008);
+ SET_PP_16(CS8900_PP_ADDR_SE_BUFEVENT, 0x000C);
+ SET_PP_16(CS8900_PP_ADDR_SE_RXMISS, 0x0010);
+ SET_PP_16(CS8900_PP_ADDR_SE_TXCOL, 0x0012);
+ SET_PP_16(CS8900_PP_ADDR_SE_LINEST, 0x0014);
+ SET_PP_16(CS8900_PP_ADDR_SE_SELFST, 0x0016);
+ SET_PP_16(CS8900_PP_ADDR_SE_BUSST, 0x0018);
+ SET_PP_16(CS8900_PP_ADDR_SE_TDR, 0x001C);
+
+ SET_PP_16(CS8900_PP_ADDR_TXCMD, 0x0009);
/* 4.4.19 Self Status Register, p. 65
- Important: set INITD (Bit 7) to signal device is ready */
- SET_PP_16(CS8900_PP_ADDR_SE_SELFST, 0x0896);
+ Important: set INITD (Bit 7) to signal device is ready */
+ SET_PP_16(CS8900_PP_ADDR_SE_SELFST, 0x0896);
cs8900_recv_control = GET_PP_16(CS8900_PP_ADDR_CC_RXCTL);
/* spec: mac address is undefined after reset.
- real HW: keeps the last set address. */
+ real HW: keeps the last set address. */
for (int i = 0; i < 6; i++)
SET_PP_8(CS8900_PP_ADDR_MAC_ADDR + i, cs8900_ia_mac[i]);
@@ -380,13 +380,13 @@ cs8900a_device::cs8900a_device(const machine_config& mconfig, device_type type,
, device_network_interface(mconfig, *this, 10.0f)
, cs8900_ia_mac{0, 0, 0, 0, 0, 0}
, cs8900_packetpage_ptr(0)
- , cs8900_recv_control(0) /* copy of CC_RXCTL (contains all bits below) */
- , cs8900_recv_broadcast(false) /* broadcast */
- , cs8900_recv_mac(false) /* individual address (IA) */
- , cs8900_recv_multicast(false) /* multicast if address passes the hash filter */
- , cs8900_recv_correct(false) /* accept correct frames */
- , cs8900_recv_promiscuous(false) /* promiscuous mode */
- , cs8900_recv_hashfilter(false) /* accept if IA passes the hash filter */
+ , cs8900_recv_control(0) /* copy of CC_RXCTL (contains all bits below) */
+ , cs8900_recv_broadcast(false) /* broadcast */
+ , cs8900_recv_mac(false) /* individual address (IA) */
+ , cs8900_recv_multicast(false) /* multicast if address passes the hash filter */
+ , cs8900_recv_correct(false) /* accept correct frames */
+ , cs8900_recv_promiscuous(false) /* promiscuous mode */
+ , cs8900_recv_hashfilter(false) /* accept if IA passes the hash filter */
, tx_buffer(CS8900_PP_ADDR_TX_FRAMELOC)
, rx_buffer(CS8900_PP_ADDR_RXSTATUS)
, tx_count(0)
@@ -405,8 +405,8 @@ cs8900a_device::cs8900a_device(machine_config const& mconfig, char const *tag, d
{}
/*
- This is a helper for cs8900_receive() to determine if the received frame should be accepted
- according to the settings.
+ This is a helper for cs8900_receive() to determine if the received frame should be accepted
+ according to the settings.
*/
bool cs8900a_device::cs8900_should_accept(unsigned char *buffer, int length, bool *phashed, int *phash_index,
bool *pcorrect_mac, bool *pbroadcast, bool *pmulticast)
@@ -419,8 +419,8 @@ bool cs8900a_device::cs8900_should_accept(unsigned char *buffer, int length, boo
*phashed = false;
*phash_index = 0;
*pcorrect_mac = false;
- *pbroadcast = false;
- *pmulticast = false;
+ *pbroadcast = false;
+ *pmulticast = false;
LOGMASKED(CS8900_DEBUG_FRAMES, "cs8900_should_accept called with %02X:%02X:%02X:%02X:%02X:%02X, length=%4u",
cs8900_ia_mac[0], cs8900_ia_mac[1], cs8900_ia_mac[2],
@@ -496,8 +496,8 @@ u16 cs8900a_device::cs8900_receive()
u8 buffer[MAX_RXLENGTH];
int len;
- bool hashed = false;
- int hash_index = 0;
+ bool hashed = false;
+ int hash_index = 0;
bool rx_ok = false;
bool correct_mac = false;
bool broadcast = false;
@@ -536,7 +536,7 @@ u16 cs8900a_device::cs8900_receive()
{
/* we already know the type of frame: Trust it! */
LOGMASKED(CS8900_DEBUG_FRAMES, "+++ cs8900_receive(): *** hashed=%u, correct_mac=%u, "
- "broadcast=%u", hashed, correct_mac, broadcast);
+ "broadcast=%u", hashed, correct_mac, broadcast);
}
else
{
@@ -619,21 +619,21 @@ u16 cs8900a_device::cs8900_receive()
}
/* ------------------------------------------------------------------------- */
-/* reading and writing IO register functions */
+/* reading and writing IO register functions */
/*
- These registers are currently fully or partially supported:
-
- CS8900_PP_ADDR_CC_RXCFG 0x0102 * # RW - 4.4.6., p. 52 - 0003 *
- CS8900_PP_ADDR_CC_RXCTL 0x0104 * # RW - 4.4.8., p. 54 - 0005 *
- CS8900_PP_ADDR_CC_LINECTL 0x0112 * # RW - 4.4.16., p. 62 - 0013 *
- CS8900_PP_ADDR_SE_RXEVENT 0x0124 * # R- - 4.4.7., p. 53 - 0004 *
- CS8900_PP_ADDR_SE_BUSST 0x0138 * # R- - 4.4.21., p. 67 - 0018 *
- CS8900_PP_ADDR_TXCMD 0x0144 * # -W - 4.5., p. 70 - 5.7., p. 98 *
- CS8900_PP_ADDR_TXLENGTH 0x0146 * # -W - 4.5., p. 70 - 5.7., p. 98 *
- CS8900_PP_ADDR_MAC_ADDR 0x0158 * # RW - 4.6., p. 71 - 5.3., p. 86 *
- 0x015a
- 0x015c
+ These registers are currently fully or partially supported:
+
+ CS8900_PP_ADDR_CC_RXCFG 0x0102 * # RW - 4.4.6., p. 52 - 0003 *
+ CS8900_PP_ADDR_CC_RXCTL 0x0104 * # RW - 4.4.8., p. 54 - 0005 *
+ CS8900_PP_ADDR_CC_LINECTL 0x0112 * # RW - 4.4.16., p. 62 - 0013 *
+ CS8900_PP_ADDR_SE_RXEVENT 0x0124 * # R- - 4.4.7., p. 53 - 0004 *
+ CS8900_PP_ADDR_SE_BUSST 0x0138 * # R- - 4.4.21., p. 67 - 0018 *
+ CS8900_PP_ADDR_TXCMD 0x0144 * # -W - 4.5., p. 70 - 5.7., p. 98 *
+ CS8900_PP_ADDR_TXLENGTH 0x0146 * # -W - 4.5., p. 70 - 5.7., p. 98 *
+ CS8900_PP_ADDR_MAC_ADDR 0x0158 * # RW - 4.6., p. 71 - 5.3., p. 86 *
+ 0x015a
+ 0x015c
*/
/* ------------------------------------------------------------------------- */
@@ -674,7 +674,7 @@ void cs8900a_device::cs8900_write_tx_buffer(u8 value, int odd_address)
/* full frame transmitted? */
if (tx_count == tx_length)
{
- LOGMASKED(CS8900_DEBUG_FRAMES, "cs8900_arch_transmit() called with: "
+ LOGMASKED(CS8900_DEBUG_FRAMES, "cs8900_arch_transmit() called with:\t\t\t\t\t\t\t\t\t"
"length=%4u and buffer %s", tx_length,
debug_outbuffer(tx_length, &cs8900_packetpage[CS8900_PP_ADDR_TX_FRAMELOC])
);
@@ -714,19 +714,19 @@ u8 cs8900a_device::cs8900_read_rx_buffer(int odd_address)
else
{
/*
- According to the CS8900 spec, the handling is the following:
- first read H, then L (RX_STATUS), then H, then L (RX_LENGTH).
- Inside the RX frame data, we always get L then H, until the end is reached.
-
- even odd
- CS8900_PP_ADDR_RXSTATUS: - proceed
- CS8900_PP_ADDR_RXLENGTH: - proceed
- CS8900_PP_ADDR_RX_FRAMELOC: - -
- CS8900_PP_ADDR_RX_FRAMELOC+2: proceed -
- CS8900_PP_ADDR_RX_FRAMELOC+4: proceed -
+ According to the CS8900 spec, the handling is the following:
+ first read H, then L (RX_STATUS), then H, then L (RX_LENGTH).
+ Inside the RX frame data, we always get L then H, until the end is reached.
+
+ even odd
+ CS8900_PP_ADDR_RXSTATUS: - proceed
+ CS8900_PP_ADDR_RXLENGTH: - proceed
+ CS8900_PP_ADDR_RX_FRAMELOC: - -
+ CS8900_PP_ADDR_RX_FRAMELOC+2: proceed -
+ CS8900_PP_ADDR_RX_FRAMELOC+4: proceed -
*/
u16 addr = odd_address ? 1 : 0;
- u8 value;
+ u8 value;
/* read RXSTATUS or RX_LENGTH */
if (rx_count < 4)
@@ -769,7 +769,7 @@ u8 cs8900a_device::cs8900_read_rx_buffer(int odd_address)
/* handle side-effects of read and write operations */
/*
- This is called *after* the relevant octets are written
+ This is called *after* the relevant octets are written
*/
void cs8900a_device::cs8900_sideeffects_write_pp(u16 ppaddress, int odd_address)
{
@@ -934,7 +934,7 @@ void cs8900a_device::cs8900_sideeffects_write_pp(u16 ppaddress, int odd_address)
}
/*
- This is called *before* the relevant octets are read
+ This is called *before* the relevant octets are read
*/
void cs8900a_device::cs8900_sideeffects_read_pp(u16 ppaddress, int odd_address)
{
@@ -946,10 +946,10 @@ void cs8900a_device::cs8900_sideeffects_read_pp(u16 ppaddress, int odd_address)
{
int access_mask = (odd_address) ? 1 : 2;
- /* update the status register only if the full word of the last
- status was read! unfortunately different access patterns are
- possible: either the status is read LH, LH, LH...
- or HL, HL, HL, or even L, L, L or H, H, H */
+ /* update the status register only if the full word of the last
+ status was read! unfortunately different access patterns are
+ possible: either the status is read LH, LH, LH...
+ or HL, HL, HL, or even L, L, L or H, H, H */
if ((access_mask & rxevent_read_mask) != 0)
{
/* receiver is not enabled */
@@ -962,8 +962,8 @@ void cs8900a_device::cs8900_sideeffects_read_pp(u16 ppaddress, int odd_address)
/* perform frame reception */
u16 ret_val = cs8900_receive();
- /* RXSTATUS and RXEVENT are the same, except that RXSTATUS buffers
- the old value while RXEVENT sets a new value whenever it is called
+ /* RXSTATUS and RXEVENT are the same, except that RXSTATUS buffers
+ the old value while RXEVENT sets a new value whenever it is called
*/
SET_PP_16(CS8900_PP_ADDR_RXSTATUS, ret_val);
SET_PP_16(CS8900_PP_ADDR_SE_RXEVENT, ret_val);
@@ -1399,11 +1399,11 @@ void cs8900a_device::cs8900_store(u16 io_address, u8 var)
if (reg_base == CS8900_ADDR_PP_PTR)
{
- /* cv: we store the full package pointer in cs8900_packetpage_ptr variable.
- this includes the mask area (0xf000) and the addr range (0x0fff).
- we ensure that the bits 0x3000 are always set (as in real HW).
- odd values of the pointer are valid and supported.
- only register read and write have to be mapped to word boundary. */
+ /* cv: we store the full package pointer in cs8900_packetpage_ptr variable.
+ this includes the mask area (0xf000) and the addr range (0x0fff).
+ we ensure that the bits 0x3000 are always set (as in real HW).
+ odd values of the pointer are valid and supported.
+ only register read and write have to be mapped to word boundary. */
word_value |= 0x3000;
cs8900_packetpage_ptr = word_value;
LOGMASKED(CS8900_DEBUG_STORE, "set PP Ptr to $%04X.\n", cs8900_packetpage_ptr);
diff --git a/src/devices/machine/cs8900a.h b/src/devices/machine/cs8900a.h
index 69931c583e5..74e4c8b20b3 100644
--- a/src/devices/machine/cs8900a.h
+++ b/src/devices/machine/cs8900a.h
@@ -3,11 +3,11 @@
/*************************************************************************
- CS8900A ethernet controller implementation
+ CS8900A ethernet controller implementation
- by Rhett Aultman <roadriverrail@gmail.com>
- ported to MAME from VICE Project (https://sourceforge.net/p/vice-emu/)
- VICE CS8900 code by Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
+ by Rhett Aultman <roadriverrail@gmail.com>
+ ported to MAME from VICE Project (https://sourceforge.net/p/vice-emu/)
+ VICE CS8900 code by Spiro Trikaliotis <Spiro.Trikaliotis@gmx.de>
**************************************************************************/
@@ -19,7 +19,7 @@
#include <queue>
/***************************************************************************
- TYPE DEFINITIONS
+ TYPE DEFINITIONS
***************************************************************************/
class cs8900a_device : public device_t, public device_network_interface {
@@ -57,13 +57,13 @@ private:
u16 cs8900_packetpage_ptr;
/* reveiver setup */
- u16 cs8900_recv_control; /* copy of CC_RXCTL (contains all bits below) */
- bool cs8900_recv_broadcast; /* broadcast */
- bool cs8900_recv_mac; /* individual address (IA) */
- bool cs8900_recv_multicast; /* multicast if address passes the hash filter */
- bool cs8900_recv_correct; /* accept correct frames */
- bool cs8900_recv_promiscuous; /* promiscuous mode */
- bool cs8900_recv_hashfilter; /* accept if IA passes the hash filter */
+ u16 cs8900_recv_control; /* copy of CC_RXCTL (contains all bits below) */
+ bool cs8900_recv_broadcast; /* broadcast */
+ bool cs8900_recv_mac; /* individual address (IA) */
+ bool cs8900_recv_multicast; /* multicast if address passes the hash filter */
+ bool cs8900_recv_correct; /* accept correct frames */
+ bool cs8900_recv_promiscuous; /* promiscuous mode */
+ bool cs8900_recv_hashfilter; /* accept if IA passes the hash filter */
u16 tx_buffer;
u16 rx_buffer;
@@ -90,7 +90,7 @@ private:
void cs8900_set_transmitter(int enabled);
bool cs8900_should_accept(unsigned char *buffer, int length, bool *phashed, int *phash_index, bool *pcorrect_mac, bool *pbroadcast, bool *pmulticast);
u16 cs8900_receive(void);
- void cs8900_write_tx_buffer(u8 value, int odd_address);
+ void cs8900_write_tx_buffer(u8 value, int odd_address);
u8 cs8900_read_rx_buffer(int odd_address);
void cs8900_sideeffects_write_pp(u16 ppaddress, int odd_address);
void cs8900_sideeffects_read_pp(u16 ppaddress, int odd_address);
diff --git a/src/devices/machine/exorterm.cpp b/src/devices/machine/exorterm.cpp
index 0b62597e3f1..9db3f0658e4 100644
--- a/src/devices/machine/exorterm.cpp
+++ b/src/devices/machine/exorterm.cpp
@@ -348,7 +348,7 @@ u32 exorterm155_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
u16 sy = 0, ma = 0;
u8 disable_fac = m_disable_fac->read() == 0;
u8 display_fac = m_display_fac->read() == 0;
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
m_framecnt++;
@@ -356,7 +356,7 @@ u32 exorterm155_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
{
for (u8 ra = 0; ra < 12; ra++)
{
- u32 *p = &bitmap.pix32(sy++);
+ u32 *p = &bitmap.pix(sy++);
// FAC codes are cleared on horizontal sync.
u8 underline1 = 0;
u8 underline2 = 0;
diff --git a/src/devices/machine/generalplus_gpl16250soc.cpp b/src/devices/machine/generalplus_gpl16250soc.cpp
index 2548929027c..1892bbe0880 100644
--- a/src/devices/machine/generalplus_gpl16250soc.cpp
+++ b/src/devices/machine/generalplus_gpl16250soc.cpp
@@ -219,12 +219,12 @@ void sunplus_gcm394_base_device::trigger_systemm_dma(int channel)
// mem.write_word(0x4d8d4, 0x4841); // golden tee IRQ? wait hack
//if (mem.read_word(0x3510f) == 0x4845)
- // mem.write_word(0x3510f, 0x4840); // camp rock force service mode
+ // mem.write_word(0x3510f, 0x4840); // camp rock force service mode
if (mem.read_word(0x4abe7) == 0x4840)
mem.write_word(0x4abe7, 0x4841); // camp rock IRQ? wait hack
-
+
// clear params after operation
m_dma_params[0][channel] = m_dma_params[0][channel] & 0x00f7;
@@ -667,6 +667,12 @@ void sunplus_gcm394_base_device::unkarea_78b2_w(uint16_t data) { LOGMASKED(LOG_G
void sunplus_gcm394_base_device::unkarea_78b8_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78b8_w %04x\n", machine().describe_context(), data); m_78b8 = data; }
void sunplus_gcm394_base_device::unkarea_78f0_w(uint16_t data) { LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78f0_w %04x\n", machine().describe_context(), data); m_78f0 = data; }
+uint16_t sunplus_gcm394_base_device::unkarea_78c0_r()
+{
+ LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78c0_r\n", machine().describe_context());
+ return machine().rand();
+}
+
uint16_t sunplus_gcm394_base_device::unkarea_78d0_r()
{
LOGMASKED(LOG_GCM394, "%s:sunplus_gcm394_base_device::unkarea_78d0_r\n", machine().describe_context());
@@ -964,6 +970,8 @@ void sunplus_gcm394_base_device::base_internal_map(address_map &map)
map(0x0078b2, 0x0078b2).rw(FUNC(sunplus_gcm394_base_device::unkarea_78b2_r), FUNC(sunplus_gcm394_base_device::unkarea_78b2_w)); // 78b2 TimeBase C Control Register (P_TimeBaseC_Ctrl)
map(0x0078b8, 0x0078b8).w(FUNC(sunplus_gcm394_base_device::unkarea_78b8_w)); // 78b8 TimeBase Counter Reset Register (P_TimeBase_Reset)
+
+ map(0x0078c0, 0x0078c0).r(FUNC(sunplus_gcm394_base_device::unkarea_78c0_r)); // beijuehh
map(0x0078d0, 0x0078d0).r(FUNC(sunplus_gcm394_base_device::unkarea_78d0_r)); // jak_s500
map(0x0078d8, 0x0078d8).r(FUNC(sunplus_gcm394_base_device::unkarea_78d8_r)); // jak_tsh
diff --git a/src/devices/machine/generalplus_gpl16250soc.h b/src/devices/machine/generalplus_gpl16250soc.h
index 8df8e780f78..fa2b176e421 100644
--- a/src/devices/machine/generalplus_gpl16250soc.h
+++ b/src/devices/machine/generalplus_gpl16250soc.h
@@ -319,6 +319,8 @@ private:
void unkarea_78b8_w(uint16_t data);
+ uint16_t unkarea_78c0_r();
+
uint16_t unkarea_78d0_r();
uint16_t unkarea_78d8_r();
diff --git a/src/devices/machine/generalplus_gpl16250soc_video.cpp b/src/devices/machine/generalplus_gpl16250soc_video.cpp
index 37821e3a10c..ba6ca102ebf 100644
--- a/src/devices/machine/generalplus_gpl16250soc_video.cpp
+++ b/src/devices/machine/generalplus_gpl16250soc_video.cpp
@@ -1048,32 +1048,30 @@ void gcm394_base_video_device::palette_w(offs_t offset, uint16_t data)
if (m_703a_palettebank & 0xfff0)
{
- fatalerror("palette writes with m_703a_palettebank %04x\n", m_703a_palettebank);
- }
- else
- {
- offset |= (m_703a_palettebank & 0x000c) << 6;
- m_paletteram[offset] = data;
-
- // for debug
- m_palette->set_pen_color(offset, rgb_t(
- (((data >> 10) & 0x1f)<<3),
- (((data >> 5) & 0x1f)<<3),
- (((data >> 0) & 0x1f)<<3)));
+ LOGMASKED(LOG_GCM394_VIDEO_PALETTE,"palette writes with m_703a_palettebank %04x\n", m_703a_palettebank);
}
+
+
+ offset |= (m_703a_palettebank & 0x000c) << 6;
+ m_paletteram[offset] = data;
+
+ // for debug
+ m_palette->set_pen_color(offset, rgb_t(
+ (((data >> 10) & 0x1f)<<3),
+ (((data >> 5) & 0x1f)<<3),
+ (((data >> 0) & 0x1f)<<3)));
+
}
uint16_t gcm394_base_video_device::palette_r(offs_t offset)
{
if (m_703a_palettebank & 0xfff0)
{
- fatalerror("palette read with m_703a_palettebank %04x\n", m_703a_palettebank);
- }
- else
- {
- offset |= (m_703a_palettebank & 0x000c) << 6;
- return m_paletteram[offset];
+ LOGMASKED(LOG_GCM394_VIDEO_PALETTE,"palette read with m_703a_palettebank %04x\n", m_703a_palettebank);
}
+
+ offset |= (m_703a_palettebank & 0x000c) << 6;
+ return m_paletteram[offset];
}
void gcm394_base_video_device::video_701c_w(uint16_t data)
diff --git a/src/devices/machine/ie15.cpp b/src/devices/machine/ie15.cpp
index 3cdb35af145..eba7ace6fa7 100644
--- a/src/devices/machine/ie15.cpp
+++ b/src/devices/machine/ie15.cpp
@@ -637,7 +637,8 @@ void ie15_device::scanline_callback()
uint32_t ie15_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
update_leds();
- memcpy(&bitmap.pix32(0), &m_tmpbmp[0], sizeof(uint32_t) * IE15_TOTAL_HORZ * IE15_TOTAL_VERT);
+ for (int y = 0; y < IE15_TOTAL_VERT; y++)
+ std::copy_n(&m_tmpbmp[y * IE15_TOTAL_HORZ], IE15_TOTAL_HORZ, &bitmap.pix(y));
return 0;
}
diff --git a/src/devices/machine/laserdsc.cpp b/src/devices/machine/laserdsc.cpp
index ef3df359859..d04d3c1201a 100644
--- a/src/devices/machine/laserdsc.cpp
+++ b/src/devices/machine/laserdsc.cpp
@@ -308,11 +308,11 @@ void laserdisc_device::device_timer(emu_timer &timer, device_timer_id id, int pa
//-------------------------------------------------
-// sound_stream_update_legacy - audio streamer for
+// sound_stream_update - audio streamer for
// laserdiscs
//-------------------------------------------------
-void laserdisc_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void laserdisc_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// compute AND values based on the squelch
int16_t leftand = (m_audiosquelch & 1) ? 0x0000 : 0xffff;
@@ -324,12 +324,12 @@ void laserdisc_device::sound_stream_update_legacy(sound_stream &stream, stream_s
samples_avail += m_audiobufsize;
// if no attached ld, just clear the buffers
- stream_sample_t *dst0 = outputs[0];
- stream_sample_t *dst1 = outputs[1];
- if (samples_avail < samples)
+ auto &dst0 = outputs[0];
+ auto &dst1 = outputs[1];
+ if (samples_avail < outputs[0].samples())
{
- memset(dst0, 0, samples * sizeof(dst0[0]));
- memset(dst1, 0, samples * sizeof(dst1[0]));
+ dst0.fill(0);
+ dst1.fill(0);
}
// otherwise, stream from our buffer
@@ -340,10 +340,11 @@ void laserdisc_device::sound_stream_update_legacy(sound_stream &stream, stream_s
int sampout = m_audiobufout;
// copy samples, clearing behind us as we go
- while (sampout != m_audiobufin && samples-- > 0)
+ int sampindex;
+ for (sampindex = 0; sampout != m_audiobufin && sampindex < outputs[0].samples(); sampindex++)
{
- *dst0++ = buffer0[sampout] & leftand;
- *dst1++ = buffer1[sampout] & rightand;
+ dst0.put_int(sampindex, buffer0[sampout] & leftand, 32768);
+ dst1.put_int(sampindex, buffer1[sampout] & rightand, 32768);
buffer0[sampout] = 0;
buffer1[sampout] = 0;
sampout++;
@@ -353,16 +354,16 @@ void laserdisc_device::sound_stream_update_legacy(sound_stream &stream, stream_s
m_audiobufout = sampout;
// clear out the rest of the buffer
- if (samples > 0)
+ if (sampindex < outputs[0].samples())
{
sampout = (m_audiobufout == 0) ? m_audiobufsize - 1 : m_audiobufout - 1;
- stream_sample_t fill0 = buffer0[sampout] & leftand;
- stream_sample_t fill1 = buffer1[sampout] & rightand;
+ s32 fill0 = buffer0[sampout] & leftand;
+ s32 fill1 = buffer1[sampout] & rightand;
- while (samples-- > 0)
+ for ( ; sampindex < outputs[0].samples(); sampindex++)
{
- *dst0++ = fill0;
- *dst1++ = fill1;
+ dst0.put_int(sampindex, fill0, 32768);
+ dst1.put_int(sampindex, fill1, 32768);
}
}
}
@@ -712,10 +713,10 @@ void laserdisc_device::init_video()
fillbitmap_yuy16(frame.m_bitmap, 40, 109, 240);
// make a copy of the bitmap that clips out the VBI and horizontal blanking areas
- frame.m_visbitmap.wrap(&frame.m_bitmap.pix16(44, frame.m_bitmap.width() * 8 / 720),
- frame.m_bitmap.width() - 2 * frame.m_bitmap.width() * 8 / 720,
- frame.m_bitmap.height() - 44,
- frame.m_bitmap.rowpixels());
+ frame.m_visbitmap.wrap(&frame.m_bitmap.pix(
+ 44, frame.m_bitmap.width() * 8 / 720),
+ frame.m_bitmap.width() - 2 * frame.m_bitmap.width() * 8 / 720, frame.m_bitmap.height() - 44,
+ frame.m_bitmap.rowpixels());
frame.m_visbitmap.set_palette(m_videopalette);
}
@@ -762,7 +763,7 @@ void laserdisc_device::init_audio()
m_audio_callback.resolve();
// allocate a stream
- m_stream = stream_alloc_legacy(0, 2, 48000);
+ m_stream = stream_alloc(0, 2, 48000);
// allocate audio buffers
m_audiomaxsamples = ((uint64_t)m_samplerate * 1000000 + m_fps_times_1million - 1) / m_fps_times_1million;
@@ -789,7 +790,7 @@ void laserdisc_device::fillbitmap_yuy16(bitmap_yuy16 &bitmap, uint8_t yval, uint
// write 32 bits of color (2 pixels at a time)
for (int y = 0; y < bitmap.height(); y++)
{
- uint16_t *dest = &bitmap.pix16(y);
+ uint16_t *dest = &bitmap.pix(y);
for (int x = 0; x < bitmap.width() / 2; x++)
{
*dest++ = color0;
@@ -918,7 +919,8 @@ void laserdisc_device::read_track_data()
frame->m_lastfield = m_curtrack * 2 + m_fieldnum;
// set the video target information
- m_avhuff_config.video.wrap(&frame->m_bitmap.pix16(m_fieldnum), frame->m_bitmap.width(), frame->m_bitmap.height() / 2, frame->m_bitmap.rowpixels() * 2);
+ m_avhuff_video.wrap(&frame->m_bitmap.pix(m_fieldnum), frame->m_bitmap.width(), frame->m_bitmap.height() / 2, frame->m_bitmap.rowpixels() * 2);
+ m_avhuff_config.video = &m_avhuff_video;
// set the audio target information
if (m_audiobufin + m_audiomaxsamples <= m_audiobufsize)
@@ -995,13 +997,13 @@ void laserdisc_device::process_track_data()
// remove the video if we had an error
if (m_readresult != CHDERR_NONE)
- m_avhuff_config.video.reset();
+ m_avhuff_video.reset();
// count the field as read if we are successful
- if (m_avhuff_config.video.valid())
+ if (m_avhuff_video.valid())
{
m_frame[m_videoindex].m_numfields++;
- player_overlay(m_avhuff_config.video);
+ player_overlay(m_avhuff_video);
}
// pass the audio to the callback
diff --git a/src/devices/machine/laserdsc.h b/src/devices/machine/laserdsc.h
index 8ca3abad222..14594bcf7cd 100644
--- a/src/devices/machine/laserdsc.h
+++ b/src/devices/machine/laserdsc.h
@@ -220,7 +220,7 @@ protected:
virtual void device_validity_check(validity_checker &valid) const override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// subclass helpers
void set_audio_squelch(bool squelchleft, bool squelchright) { m_stream->update(); m_audiosquelch = (squelchleft ? 1 : 0) | (squelchright ? 2 : 0); }
@@ -277,28 +277,29 @@ private:
std::vector<uint8_t> m_vbidata; // pointer to precomputed VBI data
int m_width; // width of video
int m_height; // height of video
- uint32_t m_fps_times_1million; // frame rate of video
+ uint32_t m_fps_times_1million; // frame rate of video
int m_samplerate; // audio samplerate
int m_readresult; // result of the most recent read
- uint32_t m_chdtracks; // number of tracks in the CHD
- avhuff_decompress_config m_avhuff_config; // decompression configuration
+ uint32_t m_chdtracks; // number of tracks in the CHD
+ bitmap_yuy16 m_avhuff_video; // decompresed frame buffer
+ avhuff_decoder::config m_avhuff_config; // decompression configuration
// async operations
osd_work_queue * m_work_queue; // work queue
- uint32_t m_queued_hunknum; // queued hunk
+ uint32_t m_queued_hunknum; // queued hunk
// core states
- uint8_t m_audiosquelch; // audio squelch state: bit 0 = audio 1, bit 1 = audio 2
- uint8_t m_videosquelch; // video squelch state: bit 0 = on/off
- uint8_t m_fieldnum; // field number (0 or 1)
- int32_t m_curtrack; // current track at this end of this vsync
- uint32_t m_maxtrack; // maximum track number
+ uint8_t m_audiosquelch; // audio squelch state: bit 0 = audio 1, bit 1 = audio 2
+ uint8_t m_videosquelch; // video squelch state: bit 0 = on/off
+ uint8_t m_fieldnum; // field number (0 or 1)
+ int32_t m_curtrack; // current track at this end of this vsync
+ uint32_t m_maxtrack; // maximum track number
attoseconds_t m_attospertrack; // attoseconds per track, or 0 if not moving
attotime m_sliderupdate; // time of last slider update
// video data
frame_data m_frame[3]; // circular list of frames
- uint8_t m_videoindex; // index of the current video buffer
+ uint8_t m_videoindex; // index of the current video buffer
bitmap_yuy16 m_emptyframe; // blank frame
// audio data
diff --git a/src/devices/machine/ldpr8210.cpp b/src/devices/machine/ldpr8210.cpp
index fc94159ff6a..64392ed0c90 100644
--- a/src/devices/machine/ldpr8210.cpp
+++ b/src/devices/machine/ldpr8210.cpp
@@ -784,12 +784,12 @@ void pioneer_pr8210_device::overlay_draw_group(bitmap_yuy16 &bitmap, const uint8
void pioneer_pr8210_device::overlay_erase(bitmap_yuy16 &bitmap, float xstart, float xend)
{
- uint32_t xmin = (uint32_t)(xstart * 256.0f * float(bitmap.width()));
- uint32_t xmax = (uint32_t)(xend * 256.0f * float(bitmap.width()));
+ uint32_t xmin = uint32_t(xstart * 256.0f * float(bitmap.width()));
+ uint32_t xmax = uint32_t(xend * 256.0f * float(bitmap.width()));
for (uint32_t y = OVERLAY_Y; y < (OVERLAY_Y + (OVERLAY_Y_PIXELS + 2) * OVERLAY_PIXEL_HEIGHT); y++)
{
- uint16_t *dest = &bitmap.pix16(y, xmin >> 8);
+ uint16_t *dest = &bitmap.pix(y, xmin >> 8);
uint16_t ymax = *dest >> 8;
uint16_t ymin = ymax * 3 / 8;
uint16_t yres = ymin + ((ymax - ymin) * (xmin & 0xff)) / 256;
@@ -819,8 +819,8 @@ void pioneer_pr8210_device::overlay_erase(bitmap_yuy16 &bitmap, float xstart, fl
void pioneer_pr8210_device::overlay_draw_char(bitmap_yuy16 &bitmap, uint8_t ch, float xstart)
{
- uint32_t xminbase = (uint32_t)(xstart * 256.0f * float(bitmap.width()));
- uint32_t xsize = (uint32_t)(OVERLAY_PIXEL_WIDTH * 256.0f * float(bitmap.width()));
+ uint32_t xminbase = uint32_t(xstart * 256.0f * float(bitmap.width()));
+ uint32_t xsize = uint32_t(OVERLAY_PIXEL_WIDTH * 256.0f * float(bitmap.width()));
// iterate over pixels
const uint8_t *chdataptr = &text_bitmap[ch & 0x3f][0];
@@ -835,7 +835,7 @@ void pioneer_pr8210_device::overlay_draw_char(bitmap_yuy16 &bitmap, uint8_t ch,
uint32_t xmax = xmin + xsize;
for (uint32_t yy = 0; yy < OVERLAY_PIXEL_HEIGHT; yy++)
{
- uint16_t *dest = &bitmap.pix16(OVERLAY_Y + (y + 1) * OVERLAY_PIXEL_HEIGHT + yy, xmin >> 8);
+ uint16_t *dest = &bitmap.pix(OVERLAY_Y + (y + 1) * OVERLAY_PIXEL_HEIGHT + yy, xmin >> 8);
uint16_t ymax = 0xff;
uint16_t ymin = *dest >> 8;
uint16_t yres = ymin + ((ymax - ymin) * (~xmin & 0xff)) / 256;
diff --git a/src/devices/machine/m3002.cpp b/src/devices/machine/m3002.cpp
index 8bb9edda2b9..fd93666a55f 100644
--- a/src/devices/machine/m3002.cpp
+++ b/src/devices/machine/m3002.cpp
@@ -351,13 +351,13 @@ void m3002_device::irq_update()
{
LOG("IRQ occurred\n");
m_irq_active = true;
- m_irq_callback(ASSERT_LINE);
+ m_irq_callback(0);
}
else if (m_irq_active && (m_ram[0xf] & 0x0c) == 0)
{
LOG("IRQ cleared\n");
m_irq_active = false;
- m_irq_callback(CLEAR_LINE);
+ m_irq_callback(1);
}
}
diff --git a/src/devices/machine/m3002.h b/src/devices/machine/m3002.h
index d39f904fe60..ef13c360e47 100644
--- a/src/devices/machine/m3002.h
+++ b/src/devices/machine/m3002.h
@@ -37,6 +37,8 @@ public:
// device type constructor
m3002_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ auto irq_out() { return m_irq_callback.bind(); }
+
// 4-bit read/write handlers
u8 read();
void write(u8 data);
diff --git a/src/devices/machine/mc68328.cpp b/src/devices/machine/mc68328.cpp
index 3df500d2f0c..e3690287710 100644
--- a/src/devices/machine/mc68328.cpp
+++ b/src/devices/machine/mc68328.cpp
@@ -3044,20 +3044,17 @@ uint16_t mc68328_device::internal_read(offs_t offset, uint16_t mem_mask)
uint32_t mc68328_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
uint32_t vram_addr = m_regs.lssa & 0x00fffffe;
- uint16_t word;
- uint16_t *line;
- int y, x, b;
if (m_regs.lckcon & LCKCON_LCDC_EN)
{
- for (y = 0; y < 160; y++)
+ for (int y = 0; y < 160; y++)
{
- line = &bitmap.pix16(y);
+ uint16_t *const line = &bitmap.pix(y);
- for (x = 0; x < 160; x += 16, vram_addr += 2)
+ for (int x = 0; x < 160; x += 16, vram_addr += 2)
{
- word = space(AS_PROGRAM).read_word(vram_addr);
- for (b = 0; b < 16; b++)
+ uint16_t const word = space(AS_PROGRAM).read_word(vram_addr);
+ for (int b = 0; b < 16; b++)
{
line[x + b] = (word >> (15 - b)) & 0x0001;
}
@@ -3066,11 +3063,11 @@ uint32_t mc68328_device::screen_update(screen_device &screen, bitmap_ind16 &bitm
}
else
{
- for (y = 0; y < 160; y++)
+ for (int y = 0; y < 160; y++)
{
- line = &bitmap.pix16(y);
+ uint16_t *const line = &bitmap.pix(y);
- for (x = 0; x < 160; x++)
+ for (int x = 0; x < 160; x++)
{
line[x] = 0;
}
diff --git a/src/devices/machine/mm58167.cpp b/src/devices/machine/mm58167.cpp
index f226590e9d2..05aa4377ccb 100644
--- a/src/devices/machine/mm58167.cpp
+++ b/src/devices/machine/mm58167.cpp
@@ -247,10 +247,7 @@ void mm58167_device::write(offs_t offset, uint8_t data)
break;
case R_CTL_IRQCONTROL:
- if (data != 0)
- {
- logerror("MM58167: IRQs not implemented\n");
- }
+ m_regs[R_CTL_IRQCONTROL]=data;
break;
}
}
diff --git a/src/devices/machine/netlist.cpp b/src/devices/machine/netlist.cpp
index 988c21c33e1..a13349e318f 100644
--- a/src/devices/machine/netlist.cpp
+++ b/src/devices/machine/netlist.cpp
@@ -987,7 +987,6 @@ std::unique_ptr<netlist::netlist_state_t> netlist_mame_device::base_validity_che
auto lnetlist = std::make_unique<netlist::netlist_state_t>("netlist",
plib::plog_delegate(&validity_logger::log, &logger));
// enable validation mode
- lnetlist->set_extended_validation(true);
lnetlist->set_static_solver_lib(std::make_unique<plib::dynlib_static>(nullptr));
diff --git a/src/devices/machine/ns32081.cpp b/src/devices/machine/ns32081.cpp
new file mode 100644
index 00000000000..73941a85f2c
--- /dev/null
+++ b/src/devices/machine/ns32081.cpp
@@ -0,0 +1,637 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * National Semiconductor 32081 Floating-Point Unit.
+ *
+ * Sources:
+ * - http://bitsavers.org/components/national/_dataBooks/1989_National_Microprocessor_Databook_32000_NSC800.pdf
+ *
+ * TODO:
+ * - testing
+ */
+
+#include "emu.h"
+#include "ns32081.h"
+
+#include "softfloat3/source/include/softfloat.h"
+
+#define LOG_GENERAL (1U << 0)
+//#define VERBOSE (LOG_GENERAL)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(NS32081, ns32081_device, "ns32081", "National Semiconductor 32081 Floating-Point Unit")
+
+enum fsr_mask : u32
+{
+ FSR_TT = 0x00000007, // trap type
+ FSR_UEN = 0x00000008, // underflow trap enable
+ FSR_UF = 0x00000010, // underflow flag
+ FSR_IEN = 0x00000020, // inexact result trap enable
+ FSR_IF = 0x00000040, // inexact result flag
+ FSR_RM = 0x00000180, // rounding mode
+ FSR_SWF = 0x0000fe00, // software field
+};
+
+enum rm_mask : u32
+{
+ RM_N = 0x00000000, // round to nearest value
+ RM_Z = 0x00000080, // round toward zero
+ RM_U = 0x00000100, // round toward positive infinity
+ RM_D = 0x00000180, // round toward negative infinity
+};
+
+enum tt_mask : u32
+{
+ TT_UND = 0x00000001, // underflow
+ TT_OVF = 0x00000002, // overflow
+ TT_DVZ = 0x00000003, // divide by zero
+ TT_ILL = 0x00000004, // illegal instruction
+ TT_INV = 0x00000005, // invalid operation
+ TT_INX = 0x00000006, // inexact result
+ TT_RSV = 0x00000007, // reserved
+};
+
+enum state : unsigned
+{
+ IDLE = 0,
+ OPERATION = 1, // awaiting operation word
+ OPERAND = 2, // awaiting operands
+ STATUS = 4, // status word available
+ RESULT = 5, // result word available
+};
+
+enum idbyte : u8
+{
+ FORMAT_9 = 0x3e,
+ FORMAT_11 = 0xbe,
+};
+
+enum operand_length : unsigned
+{
+ LENGTH_F = 4, // single precision
+ LENGTH_L = 8, // double precision
+};
+
+enum size_code : unsigned
+{
+ SIZE_B = 0,
+ SIZE_W = 1,
+ SIZE_D = 3,
+};
+
+ns32081_device::ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NS32081, tag, owner, clock)
+ , ns32000_slave_interface(mconfig, *this)
+{
+}
+
+void ns32081_device::device_start()
+{
+ save_item(NAME(m_fsr));
+ save_item(NAME(m_f));
+
+ save_item(NAME(m_idbyte));
+ save_item(NAME(m_opword));
+ save_item(STRUCT_MEMBER(m_op, expected));
+ save_item(STRUCT_MEMBER(m_op, issued));
+ save_item(STRUCT_MEMBER(m_op, value));
+ save_item(NAME(m_status));
+
+ save_item(NAME(m_state));
+ save_item(NAME(m_tcy));
+
+ m_complete = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32081_device::complete), this));
+}
+
+void ns32081_device::device_reset()
+{
+ m_fsr = 0;
+ std::fill_n(&m_f[0], ARRAY_LENGTH(m_f), 0);
+
+ m_state = IDLE;
+}
+
+void ns32081_device::state_add(device_state_interface &parent, int &index)
+{
+ parent.state_add(index++, "FSR", m_fsr).formatstr("%04X");
+
+ for (unsigned i = 0; i < 8; i++)
+ parent.state_add(index++, util::string_format("F%d", i).c_str(), m_f[i]).formatstr("%08X");
+}
+
+u16 ns32081_device::read_st(int *icount)
+{
+ if (m_state == STATUS)
+ {
+ m_state = (m_op[2].issued == m_op[2].expected) ? IDLE : RESULT;
+
+ if (icount)
+ *icount -= m_tcy;
+
+ LOG("read_st status 0x%04x tcy %d %s (%s)\n", m_status, m_tcy,
+ (m_state == RESULT ? "results pending" : "complete"), machine().describe_context());
+
+ return m_status;
+ }
+
+ logerror("protocol error reading status word (%s)\n", machine().describe_context());
+ return 0;
+}
+
+u16 ns32081_device::read_op()
+{
+ if (m_state == RESULT && m_op[2].issued < m_op[2].expected)
+ {
+ u16 const data = u16(m_op[2].value >> (m_op[2].issued * 8));
+ LOG("read_op word %d data 0x%04x (%s)\n", m_op[2].issued >> 1, data, machine().describe_context());
+
+ m_op[2].issued += 2;
+
+ if (m_op[2].issued == m_op[2].expected)
+ {
+ LOG("read_op last result word issued\n");
+ m_state = IDLE;
+ }
+
+ return data;
+ }
+
+ logerror("protocol error reading result word (%s)\n", machine().describe_context());
+ return 0;
+}
+
+void ns32081_device::write_id(u16 data)
+{
+ bool const match = (data == FORMAT_9) || (data == FORMAT_11);
+
+ if (match)
+ {
+ LOG("write_id match 0x%04x (%s)\n", data, machine().describe_context());
+ m_state = OPERATION;
+ }
+ else
+ {
+ LOG("write_id ignore 0x%04x (%s)\n", data, machine().describe_context());
+ m_state = IDLE;
+ }
+
+ m_idbyte = u8(data);
+}
+
+void ns32081_device::write_op(u16 data)
+{
+ switch (m_state)
+ {
+ case OPERATION:
+ m_opword = swapendian_int16(data);
+ LOG("write_op opword 0x%04x (%s)\n", m_opword, machine().describe_context());
+
+ // initialize operands
+ for (operand &op : m_op)
+ {
+ op.expected = 0;
+ op.issued = 0;
+ op.value = 0;
+ }
+
+ // decode operands
+ if (m_idbyte == FORMAT_9)
+ {
+ // format 9: 1111 1222 22oo ofii
+ unsigned const f_length = BIT(m_opword, 2) ? LENGTH_F : LENGTH_L;
+ unsigned const size = m_opword & 3;
+
+ switch ((m_opword >> 3) & 7)
+ {
+ case 0: // movif
+ m_op[0].expected = size + 1;
+ m_op[2].expected = f_length;
+ break;
+ case 1: // lfsr
+ m_op[0].expected = 4;
+ break;
+ case 2: // movlf
+ m_op[0].expected = LENGTH_L;
+ m_op[2].expected = f_length;
+ break;
+ case 3: // movfl
+ m_op[0].expected = LENGTH_F;
+ m_op[2].expected = f_length;
+ break;
+ case 4: // roundfi
+ case 5: // truncfi
+ case 7: // floorfi
+ m_op[0].expected = f_length;
+ m_op[2].expected = size + 1;
+ break;
+ case 6: // sfsr
+ m_op[2].expected = 4;
+ break;
+ }
+ }
+ else if (m_idbyte == FORMAT_11)
+ {
+ // format 11: 1111 1222 22oo oo0f
+ unsigned const opcode = (m_opword >> 2) & 15;
+ unsigned const f_length = BIT(m_opword, 0) ? LENGTH_F : LENGTH_L;
+
+ m_op[0].expected = f_length;
+
+ // even opcodes have two input operands
+ if (!BIT(opcode, 0))
+ m_op[1].expected = f_length;
+
+ // all operations except CMPf issue a result
+ if (opcode != 2)
+ m_op[2].expected = f_length;
+ }
+
+ // operand 1 in register
+ if (m_op[0].expected && !(m_opword & 0xc000))
+ {
+ // exclude integer operands
+ if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) > 1)
+ {
+ unsigned const reg = (m_opword >> 11) & 7;
+ LOG("write_op read f%d\n", reg);
+
+ m_op[0].value = m_f[reg ^ 0];
+ if (m_op[0].expected == 8)
+ m_op[0].value |= u64(m_f[reg ^ 1]) << 32;
+
+ m_op[0].issued = m_op[0].expected;
+ }
+ }
+
+ // operand 2 in register
+ if (m_op[1].expected && !(m_opword & 0x0600))
+ {
+ unsigned const reg = (m_opword >> 6) & 7;
+ LOG("write_op read f%d\n", reg);
+
+ m_op[1].value = m_f[reg ^ 0];
+ if (m_op[1].expected == 8)
+ m_op[1].value |= u64(m_f[reg ^ 1]) << 32;
+
+ m_op[1].issued = m_op[1].expected;
+ }
+
+ m_state = OPERAND;
+ break;
+
+ case OPERAND:
+ // check awaiting operand word
+ if (m_op[0].issued < m_op[0].expected || m_op[1].issued < m_op[1].expected)
+ {
+ unsigned const n = (m_op[0].issued < m_op[0].expected) ? 0 : 1;
+ operand &op = m_op[n];
+
+ LOG("write_op op%d data 0x%04x (%s)\n", n, data, machine().describe_context());
+
+ // insert word into operand value
+ op.value |= u64(data) << (op.issued * 8);
+ op.issued += 2;
+ }
+ else
+ logerror("protocol error unexpected operand word 0x%04x (%s)\n", data, machine().describe_context());
+ break;
+ }
+
+ // start execution when all operands are available
+ if (m_state == OPERAND && m_op[0].issued >= m_op[0].expected && m_op[1].issued >= m_op[1].expected)
+ execute();
+}
+
+void ns32081_device::execute()
+{
+ softfloat_exceptionFlags = 0;
+ m_fsr &= ~FSR_TT;
+
+ m_status = 0;
+ m_tcy = 0;
+
+ switch (m_idbyte)
+ {
+ case FORMAT_9:
+ // format 9: 1111 1222 22oo ofii
+ {
+ bool const single = BIT(m_opword, 2);
+ unsigned const f_length = single ? LENGTH_F : LENGTH_L;
+ unsigned const size = m_opword & 3;
+
+ switch ((m_opword >> 3) & 7)
+ {
+ case 0:
+ // MOVif src,dest
+ // gen,gen
+ // read.i,write.f
+ {
+ s32 const src =
+ (size == SIZE_D) ? s32(m_op[0].value) :
+ (size == SIZE_W) ? s16(m_op[0].value) :
+ s8(m_op[0].value);
+
+ if (single)
+ m_op[2].value = i32_to_f32(src).v;
+ else
+ m_op[2].value = i32_to_f64(src).v;
+ m_op[2].expected = f_length;
+ m_tcy = 53;
+ }
+ break;
+ case 1:
+ // LFSR src
+ // gen
+ // read.D
+ m_fsr = u16(m_op[0].value);
+
+ switch (m_fsr & FSR_RM)
+ {
+ case RM_N: softfloat_roundingMode = softfloat_round_near_even; break;
+ case RM_Z: softfloat_roundingMode = softfloat_round_minMag; break;
+ case RM_U: softfloat_roundingMode = softfloat_round_max; break;
+ case RM_D: softfloat_roundingMode = softfloat_round_min; break;
+ }
+ m_tcy = 18;
+ break;
+ case 2:
+ // MOVLF src,dest
+ // gen,gen
+ // read.L,write.F
+ m_op[2].value = f64_to_f32(float64_t{ m_op[0].value }).v;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc000) ? 23 : 27;
+ break;
+ case 3:
+ // MOVFL src,dest
+ // gen,gen
+ // read.F,write.L
+ m_op[2].value = f32_to_f64(float32_t{ u32(m_op[0].value) }).v;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc000) ? 22 : 26;
+ break;
+ case 4:
+ // ROUNDfi src,dest
+ // gen,gen
+ // read.f,write.i
+ if (single)
+ m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_near_even, true);
+ else
+ m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_near_even, true);
+
+ if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
+ || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
+ || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
+ softfloat_exceptionFlags |= softfloat_flag_overflow;
+
+ m_op[2].expected = size + 1;
+ m_tcy = (m_opword & 0xc000) ? 53 : 66;
+ break;
+ case 5:
+ // TRUNCfi src,dest
+ // gen,gen
+ // read.f,write.i
+ if (single)
+ m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_minMag, true);
+ else
+ m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_minMag, true);
+
+ if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
+ || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
+ || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
+ softfloat_exceptionFlags |= softfloat_flag_overflow;
+
+ m_op[2].expected = size + 1;
+ m_tcy = (m_opword & 0xc000) ? 53 : 66;
+ break;
+ case 6:
+ // SFSR dest
+ // gen
+ // write.D
+ m_op[2].value = m_fsr;
+ m_op[2].expected = 4;
+ m_tcy = 13;
+ break;
+ case 7:
+ // FLOORfi src,dest
+ // gen,gen
+ // read.f,write.i
+ if (single)
+ m_op[2].value = f32_to_i64(float32_t{ u32(m_op[0].value) }, softfloat_round_min, true);
+ else
+ m_op[2].value = f64_to_i64(float64_t{ m_op[0].value }, softfloat_round_min, true);
+
+ if ((size == SIZE_D && s64(m_op[2].value) != s32(m_op[2].value))
+ || (size == SIZE_W && s64(m_op[2].value) != s16(m_op[2].value))
+ || (size == SIZE_B && s64(m_op[2].value) != s8(m_op[2].value)))
+ softfloat_exceptionFlags |= softfloat_flag_overflow;
+
+ m_op[2].expected = size + 1;
+ m_tcy = (m_opword & 0xc000) ? 53 : 66;
+ break;
+ }
+ }
+ break;
+
+ case FORMAT_11:
+ // format 11: 1111122222oooo0f
+ {
+ bool const single = BIT(m_opword, 0);
+ unsigned const f_length = single ? LENGTH_F : LENGTH_L;
+
+ switch ((m_opword >> 2) & 15)
+ {
+ case 0x0:
+ // ADDf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (single)
+ m_op[2].value = f32_add(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_add(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc600) ? 70 : 74;
+ break;
+ case 0x1:
+ // MOVf src,dest
+ // gen,gen
+ // read.f,write.f
+ m_op[2].value = m_op[0].value;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc000) ? 23 : 27;
+ break;
+ case 0x2:
+ // CMPf src1,src2
+ // gen,gen
+ // read.f,read.f
+ if (m_op[0].value == m_op[1].value)
+ m_status |= SLAVE_Z;
+ if ((single && f32_le(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }))
+ || (!single && f64_le(float64_t{ m_op[1].value }, float64_t{ m_op[0].value })))
+ m_status |= SLAVE_N;
+ m_tcy = (m_opword & 0xc600) ? 45 : 49;
+ break;
+ case 0x3:
+ // Trap(SLAVE)
+ m_fsr |= TT_ILL;
+ m_status = SLAVE_Q;
+ break;
+ case 0x4:
+ // SUBf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (single)
+ m_op[2].value = f32_sub(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_sub(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc600) ? 70 : 74;
+ break;
+ case 0x5:
+ // NEGf src,dest
+ // gen,gen
+ // read.f,write.f
+ if (single)
+ m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
+ else
+ m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc000) ? 20 : 24;
+ break;
+ case 0x8:
+ // DIVf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (single)
+ m_op[2].value = f32_div(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_div(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+ m_op[2].expected = f_length;
+ m_tcy = ((m_opword & 0xc600) ? 55 : 59) + (single ? 30 : 60);
+ break;
+ case 0x9:
+ // Trap(SLAVE)
+ m_fsr |= TT_ILL;
+ m_status = SLAVE_Q;
+ break;
+ case 0xc:
+ // MULf src,dest
+ // gen,gen
+ // read.f,rmw.f
+ if (single)
+ m_op[2].value = f32_mul(float32_t{ u32(m_op[1].value) }, float32_t{ u32(m_op[0].value) }).v;
+ else
+ m_op[2].value = f64_mul(float64_t{ m_op[1].value }, float64_t{ m_op[0].value }).v;
+ m_op[2].expected = f_length;
+ m_tcy = ((m_opword & 0xc600) ? 30 : 34) + (single ? 14 : 28);
+ break;
+ case 0xd:
+ // ABSf src,dest
+ // gen,gen
+ // read.f,write.f
+ if (single)
+ if (f32_lt(float32_t{ u32(m_op[0].value) }, float32_t{ 0 }))
+ m_op[2].value = f32_mul(float32_t{ u32(m_op[0].value) }, i32_to_f32(-1)).v;
+ else
+ m_op[2].value = float32_t{ u32(m_op[0].value) }.v;
+ else
+ if (f64_lt(float64_t{ m_op[0].value }, float64_t{ 0 }))
+ m_op[2].value = f64_mul(float64_t{ m_op[0].value }, i32_to_f64(-1)).v;
+ else
+ m_op[2].value = float64_t{ m_op[0].value }.v;
+ m_op[2].expected = f_length;
+ m_tcy = (m_opword & 0xc000) ? 20 : 24;
+ break;
+ }
+ }
+ break;
+ }
+
+ // check for exceptions
+ if (softfloat_exceptionFlags & softfloat_flag_underflow)
+ {
+ m_fsr |= FSR_UF | TT_UND;
+
+ if (m_fsr & FSR_UEN)
+ m_status |= SLAVE_Q;
+ else
+ m_op[2].value = 0;
+ }
+ else if (softfloat_exceptionFlags & softfloat_flag_overflow)
+ {
+ m_fsr |= TT_OVF;
+ m_status |= SLAVE_Q;
+ }
+ else if (softfloat_exceptionFlags & softfloat_flag_infinite)
+ {
+ m_fsr |= TT_DVZ;
+ m_status |= SLAVE_Q;
+ }
+ else if (softfloat_exceptionFlags & softfloat_flag_invalid)
+ m_fsr |= TT_INV;
+ else if (softfloat_exceptionFlags & softfloat_flag_inexact)
+ {
+ m_fsr |= FSR_IF | TT_INX;
+
+ if (m_fsr & FSR_IEN)
+ m_status |= SLAVE_Q;
+ }
+
+ // exceptions suppress result issue
+ if (m_status & SLAVE_Q)
+ m_op[2].expected = 0;
+
+ if (VERBOSE & LOG_GENERAL)
+ {
+ static char const *format9[] = { "movif", "lfsr", "movlf", "movfl", "roundfi", "truncfi", "sfsr", "floorfi" };
+ static char const *format11[] =
+ {
+ "addf", "movf", "cmpf", nullptr, "subf", "negf", nullptr, nullptr,
+ "divf", nullptr, nullptr, nullptr, "mulf", "absf", nullptr, nullptr
+ };
+
+ if (m_status & SLAVE_Q)
+ LOG("execute %s 0x%x,0x%x exception\n",
+ (m_idbyte == FORMAT_9)
+ ? format9[(m_opword >> 3) & 7]
+ : format11[(m_opword >> 2) & 15],
+ m_op[0].value, m_op[1].value);
+ else
+ LOG("execute %s 0x%x,0x%x result 0x%x\n",
+ (m_idbyte == FORMAT_9)
+ ? format9[(m_opword >> 3) & 7]
+ : format11[(m_opword >> 2) & 15],
+ m_op[0].value, m_op[1].value, m_op[2].value);
+ }
+
+ // write-back floating point register results
+ if (m_op[2].expected && !(m_opword & 0x0600))
+ {
+ // exclude integer results (roundfi, truncfi, sfsr, floorfi)
+ if (m_idbyte == FORMAT_11 || ((m_opword >> 3) & 7) < 4)
+ {
+ unsigned const reg = (m_opword >> 6) & 7;
+
+ LOG("execute write-back f%d\n", reg);
+
+ m_f[reg ^ 0] = u32(m_op[2].value >> 0);
+ if (m_op[2].expected == 8)
+ m_f[reg ^ 1] = u32(m_op[2].value >> 32);
+
+ m_op[2].issued = m_op[2].expected;
+ }
+ }
+
+ m_state = STATUS;
+
+ if (m_out_scb)
+ m_complete->adjust(attotime::from_ticks(m_tcy, clock()));
+}
+
+void ns32081_device::complete(void *buf, s32 param)
+{
+ m_out_scb(0);
+ m_out_scb(1);
+}
diff --git a/src/devices/machine/ns32081.h b/src/devices/machine/ns32081.h
new file mode 100644
index 00000000000..4097494c830
--- /dev/null
+++ b/src/devices/machine/ns32081.h
@@ -0,0 +1,60 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_NS32081_H
+#define MAME_MACHINE_NS32081_H
+
+#pragma once
+
+#include "cpu/ns32000/slave.h"
+
+class ns32081_device
+ : public device_t
+ , public ns32000_slave_interface
+{
+public:
+ ns32081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ virtual void state_add(device_state_interface &parent, int &index) override;
+
+ virtual u16 read_st(int *icount = nullptr) override;
+ virtual u16 read_op() override;
+
+ virtual void write_id(u16 data) override;
+ virtual void write_op(u16 data) override;
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void execute();
+ void complete(void *buf, s32 param);
+
+private:
+ emu_timer *m_complete;
+
+ // registers
+ u32 m_fsr;
+ u32 m_f[8];
+
+ // operating state
+ u8 m_idbyte;
+ u16 m_opword;
+ struct operand
+ {
+ unsigned expected;
+ unsigned issued;
+ u64 value;
+ }
+ m_op[3];
+ u16 m_status;
+
+ // implementation state
+ unsigned m_state;
+ unsigned m_tcy;
+};
+
+DECLARE_DEVICE_TYPE(NS32081, ns32081_device)
+
+#endif // MAME_MACHINE_NS32081_H
diff --git a/src/devices/machine/ns32202.cpp b/src/devices/machine/ns32202.cpp
new file mode 100644
index 00000000000..947bb6e38cd
--- /dev/null
+++ b/src/devices/machine/ns32202.cpp
@@ -0,0 +1,698 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * National Semiconductor NS32202 Interrupt Control Unit (ICU).
+ *
+ * Sources:
+ *
+ * http://bitsavers.org/components/national/_dataBooks/1989_National_Microprocessor_Databook_32000_NSC800.pdf
+ *
+ * TODO
+ * - timer/counter
+ */
+
+#include "emu.h"
+#include "ns32202.h"
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_STATE (1U << 1)
+#define LOG_REGW (1U << 2)
+#define LOG_REGR (1U << 3)
+
+//#define VERBOSE (LOG_GENERAL|LOG_STATE|LOG_REGW|LOG_REGR)
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(NS32202, ns32202_device, "ns32202", "NS32202 Interrupt Control Unit")
+
+enum mctl_mask : u8
+{
+ MCTL_T16N8 = 0x01, // data bus mode
+ MCTL_NTAR = 0x02, // not auto-rotate mode
+ MCTL_FRZ = 0x08, // freeze interrupt pending
+ MCTL_CLKM = 0x10, // clock mode (square wave/pulsed)
+ MCTL_COUTM = 0x20, // cout mode (square wave/pulsed)
+ MCTL_COUTD = 0x40, // cout/scin input/output
+ MCTL_CFRZ = 0x80, // freeze counter readings
+};
+
+enum cctl_mask : u8
+{
+ CCTL_CDCRL = 0x01, // decrement l-counter
+ CCTL_CDCRH = 0x02, // decrement h-counter
+ CCTL_CRUNL = 0x04, // l-counter running
+ CCTL_CRUNH = 0x08, // h-counter running
+ CCTL_COUT0 = 0x10, // zero detect l-counter
+ CCTL_COUT1 = 0x20, // zero detect h-counter
+ CCTL_CFNPS = 0x40, // clock not prescaled
+ CCTL_CCON = 0x80, // counters concatenated
+};
+
+enum cictl_mask : u8
+{
+ CICTL_WENL = 0x01, // l-counter write enable
+ CICTL_CIEL = 0x02, // l-counter interrupt enable
+ CICTL_CIRL = 0x04, // l-counter interrupt request
+ CICTL_CERL = 0x08, // l-counter error flag
+ CICTL_WENH = 0x10, // h-counter write enable
+ CICTL_CIEH = 0x20, // h-counter interrupt enable
+ CICTL_CIRH = 0x40, // h-counter interrupt request
+ CICTL_CERH = 0x80, // h-counter error flag
+};
+
+ns32202_device::ns32202_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, NS32202, tag, owner, clock)
+ , m_out_int(*this)
+ , m_out_cout(*this)
+ , m_out_port(*this)
+ , m_line_state(0xffff)
+ , m_out_int_state(false)
+ , m_out_cout_state(false)
+{
+}
+
+void ns32202_device::device_start()
+{
+ m_out_int.resolve_safe();
+ m_out_cout.resolve_safe();
+ m_out_port.resolve_safe();
+
+ save_item(NAME(m_hvct));
+ save_item(NAME(m_eltg));
+ save_item(NAME(m_tpl));
+ save_item(NAME(m_ipnd));
+ save_item(NAME(m_isrv));
+ save_item(NAME(m_imsk));
+ save_item(NAME(m_csrc));
+ save_item(NAME(m_fprt));
+ save_item(NAME(m_mctl));
+ save_item(NAME(m_ocasn));
+ save_item(NAME(m_ciptr));
+ save_item(NAME(m_pdat));
+ save_item(NAME(m_ips));
+ save_item(NAME(m_pdir));
+ save_item(NAME(m_cctl));
+ save_item(NAME(m_cictl));
+ save_item(NAME(m_csv));
+ save_item(NAME(m_ccv));
+
+ save_item(NAME(m_isrv_count));
+
+ save_item(NAME(m_line_state));
+ save_item(NAME(m_out_int_state));
+ save_item(NAME(m_out_cout_state));
+
+ m_interrupt = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::interrupt), this));
+ m_counter[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::counter<0>), this));
+ m_counter[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::counter<1>), this));
+}
+
+void ns32202_device::device_reset()
+{
+ m_eltg = 0xffff;
+ m_tpl = 0;
+ m_ipnd = 0;
+ m_isrv = 0;
+ m_imsk = 0xffff;
+ m_csrc = 0;
+ m_fprt = 0x0001;
+
+ m_mctl = MCTL_COUTD;
+ m_ocasn = 0;
+ m_ciptr = 0xff;
+ m_ips = 0xff;
+ m_pdir = 0xff;
+ m_cictl = 0;
+}
+
+void ns32202_device::set_int(bool int_state)
+{
+ if (int_state != m_out_int_state)
+ {
+ LOGMASKED(LOG_STATE, "int %s\n", int_state ? "asserted" : "cleared");
+
+ m_out_int_state = int_state;
+ m_out_int(!m_out_int_state);
+ }
+}
+
+void ns32202_device::set_cout(bool cout_state)
+{
+ if (cout_state != m_out_cout_state)
+ {
+ LOGMASKED(LOG_STATE, "cout %s\n", cout_state ? "asserted" : "cleared");
+
+ m_out_cout_state = cout_state;
+ m_out_cout(!m_out_cout_state);
+ }
+}
+
+template <unsigned ST1> void ns32202_device::map(address_map &map)
+{
+ map(0x00, 0x00).r(&ns32202_device::hvct_r<ST1, true>, "ns32202_device::hvct_r");
+ map(0x01, 0x01).rw(&ns32202_device::hvct_r<ST1, false>, "ns32202_device::svct_r", FUNC(ns32202_device::svct_w));
+ map(0x02, 0x02).rw(FUNC(ns32202_device::eltgl_r), FUNC(ns32202_device::eltgl_w));
+ map(0x03, 0x03).rw(FUNC(ns32202_device::eltgh_r), FUNC(ns32202_device::eltgh_w));
+ map(0x04, 0x04).rw(FUNC(ns32202_device::tpll_r), FUNC(ns32202_device::tpll_w));
+ map(0x05, 0x05).rw(FUNC(ns32202_device::tplh_r), FUNC(ns32202_device::tplh_w));
+ map(0x06, 0x06).rw(FUNC(ns32202_device::ipndl_r), FUNC(ns32202_device::ipndl_w));
+ map(0x07, 0x07).rw(FUNC(ns32202_device::ipndh_r), FUNC(ns32202_device::ipndh_w));
+ map(0x08, 0x08).rw(FUNC(ns32202_device::isrvl_r), FUNC(ns32202_device::isrvl_w));
+ map(0x09, 0x09).rw(FUNC(ns32202_device::isrvh_r), FUNC(ns32202_device::isrvh_w));
+ map(0x0a, 0x0a).rw(FUNC(ns32202_device::imskl_r), FUNC(ns32202_device::imskl_w));
+ map(0x0b, 0x0b).rw(FUNC(ns32202_device::imskh_r), FUNC(ns32202_device::imskh_w));
+ map(0x0c, 0x0c).rw(FUNC(ns32202_device::csrcl_r), FUNC(ns32202_device::csrcl_w));
+ map(0x0d, 0x0d).rw(FUNC(ns32202_device::csrch_r), FUNC(ns32202_device::csrch_w));
+ map(0x0e, 0x0e).rw(FUNC(ns32202_device::fprtl_r), FUNC(ns32202_device::fprtl_w));
+ map(0x0f, 0x0f).rw(FUNC(ns32202_device::fprth_r), FUNC(ns32202_device::fprth_w));
+ map(0x10, 0x10).rw(FUNC(ns32202_device::mctl_r), FUNC(ns32202_device::mctl_w));
+ map(0x11, 0x11).rw(FUNC(ns32202_device::ocasn_r), FUNC(ns32202_device::ocasn_w));
+ map(0x12, 0x12).rw(FUNC(ns32202_device::ciptr_r), FUNC(ns32202_device::ciptr_w));
+ map(0x13, 0x13).rw(FUNC(ns32202_device::pdat_r), FUNC(ns32202_device::pdat_w));
+ map(0x14, 0x14).rw(FUNC(ns32202_device::ips_r), FUNC(ns32202_device::ips_w));
+ map(0x15, 0x15).rw(FUNC(ns32202_device::pdir_r), FUNC(ns32202_device::pdir_w));
+ map(0x16, 0x16).rw(FUNC(ns32202_device::cctl_r), FUNC(ns32202_device::cctl_w));
+ map(0x17, 0x17).rw(FUNC(ns32202_device::cictl_r), FUNC(ns32202_device::cictl_w));
+ map(0x18, 0x18).rw(FUNC(ns32202_device::csvl_r<0>), FUNC(ns32202_device::csvl_w<0>));
+ map(0x19, 0x19).rw(FUNC(ns32202_device::csvh_r<0>), FUNC(ns32202_device::csvh_w<0>));
+ map(0x1a, 0x1a).rw(FUNC(ns32202_device::csvl_r<1>), FUNC(ns32202_device::csvl_w<1>));
+ map(0x1b, 0x1b).rw(FUNC(ns32202_device::csvh_r<1>), FUNC(ns32202_device::csvh_w<1>));
+ map(0x1c, 0x1c).rw(FUNC(ns32202_device::lccvl_r), FUNC(ns32202_device::lccvl_w));
+ map(0x1d, 0x1d).rw(FUNC(ns32202_device::lccvh_r), FUNC(ns32202_device::lccvh_w));
+ map(0x1e, 0x1e).rw(FUNC(ns32202_device::hccvl_r), FUNC(ns32202_device::hccvl_w));
+ map(0x1f, 0x1f).rw(FUNC(ns32202_device::hccvh_r), FUNC(ns32202_device::hccvh_w));
+}
+
+template void ns32202_device::map<0>(address_map &map);
+template void ns32202_device::map<1>(address_map &map);
+
+/*
+ * Set (and clear, for level-triggered interrupts) interrupt pending state
+ * based on edge/level/polarity configuration and previous/current line state,
+ * regardless of mask.
+ */
+template <unsigned Number> void ns32202_device::ir_w(int state)
+{
+ // ignore external interrupts assigned to counters
+ if (((m_cictl & CICTL_CIEL) && (m_ciptr & 15) == Number) ||
+ ((m_cictl & CICTL_CIEH) && (m_ciptr >> 4) == Number))
+ return;
+
+ u16 const mask = 1 << Number;
+
+ if (m_eltg & mask)
+ {
+ // level triggered
+ if (state == BIT(m_tpl, Number))
+ m_ipnd |= mask;
+ else
+ m_ipnd &= ~mask;
+ }
+ else
+ {
+ // edge triggered
+ if (bool(state) == BIT(m_tpl, Number) && bool(state) ^ BIT(m_line_state, Number))
+ m_ipnd |= mask;
+ }
+
+ // record input line state
+ if (state)
+ m_line_state |= mask;
+ else
+ m_line_state &= ~mask;
+
+ // datasheet states maximum 800ns
+ m_interrupt->adjust(attotime::from_nsec(600));
+}
+
+// instantiate all valid interrupt request templates
+template void ns32202_device::ir_w<0>(int state);
+template void ns32202_device::ir_w<1>(int state);
+template void ns32202_device::ir_w<2>(int state);
+template void ns32202_device::ir_w<3>(int state);
+template void ns32202_device::ir_w<4>(int state);
+template void ns32202_device::ir_w<5>(int state);
+template void ns32202_device::ir_w<6>(int state);
+template void ns32202_device::ir_w<7>(int state);
+template void ns32202_device::ir_w<8>(int state);
+template void ns32202_device::ir_w<9>(int state);
+template void ns32202_device::ir_w<10>(int state);
+template void ns32202_device::ir_w<11>(int state);
+template void ns32202_device::ir_w<12>(int state);
+template void ns32202_device::ir_w<13>(int state);
+template void ns32202_device::ir_w<14>(int state);
+template void ns32202_device::ir_w<15>(int state);
+
+/*
+ * Assert interrupt output if there are any unmasked pending interrupts; and
+ * - in auto-rotate mode and no interrupts are in-service; or
+ * - in fixed priority mode; and
+ * - no interrupts are in-service; or
+ * - unmasked pending interrupt has priority > in-service interrupt; or
+ * - unmasked pending cascade interrupt has priorty >= in-service interrupt
+ */
+void ns32202_device::interrupt(void *ptr, s32 param)
+{
+ // check for unmasked pending interrupts
+ if (!(m_ipnd & m_imsk))
+ return;
+
+ if (m_mctl & MCTL_NTAR)
+ {
+ // fixed priority mode
+ bool accept = false;
+
+ // check any interrupts in-service
+ if (m_isrv)
+ {
+ // check interrupts in descending priority order
+ u16 mask = m_fprt;
+ for (unsigned i = 0; i < 16; i++)
+ {
+ // check interrupt in-service
+ if (m_isrv & mask)
+ {
+ // check equal priority unmasked pending cascade interrupt
+ if ((m_csrc & mask) && (m_ipnd & mask) && !(m_imsk & mask))
+ {
+ LOGMASKED(LOG_STATE, "unmasked pending cascade in-service interrupt %d\n", 31 - count_leading_zeros(mask));
+ accept = true;
+ }
+
+ break;
+ }
+
+ // check unmasked pending interrupt
+ if ((m_ipnd & mask) && !(m_imsk & mask))
+ {
+ LOGMASKED(LOG_STATE, "unmasked pending interrupt %d\n", 31 - count_leading_zeros(mask));
+ accept = true;
+ break;
+ }
+
+ // rotate priority mask
+ mask = (mask << 1) | (mask >> 15);
+ }
+ }
+ else
+ accept = true;
+
+ if (!accept)
+ return;
+ }
+ else if (m_isrv)
+ return;
+
+ set_int(true);
+}
+
+u8 ns32202_device::interrupt_acknowledge(bool side_effects)
+{
+ side_effects &= !machine().side_effects_disabled();
+ u8 vector = m_hvct | 0x0f;
+
+ if ((m_ipnd & m_imsk) && m_fprt)
+ {
+ // find highest priority unmasked pending interrupt
+ u16 mask = m_fprt;
+ for (unsigned i = 0; i < 16; i++)
+ {
+ if ((m_ipnd & mask) && !(m_imsk & mask))
+ break;
+
+ // rotate priority mask
+ mask = (mask << 1) | (mask >> 15);
+ }
+
+ unsigned const number = 31 - count_leading_zeros(mask);
+ if (side_effects)
+ {
+ LOGMASKED(LOG_STATE, "acknowledge highest priority unmasked interrupt %d\n", number);
+
+ if (m_mctl & MCTL_NTAR)
+ {
+ if (m_csrc & mask)
+ m_isrv_count[number]++;
+ }
+ else
+ m_fprt = mask;
+
+ // mark interrupt in-service
+ m_isrv |= mask;
+
+ // clear interrupt pending
+ m_ipnd &= ~(mask);
+
+ // clear l-counter interrupt pending
+ if ((m_cictl & CICTL_CIEL) && (m_cictl & CICTL_CIRL) && BIT(mask, m_ciptr & 15))
+ m_cictl &= ~CICTL_CIRL;
+
+ // clear h-counter interrupt pending
+ if ((m_cictl & CICTL_CIEH) && (m_cictl & CICTL_CIRH) && BIT(mask, m_ciptr >> 4))
+ m_cictl &= ~CICTL_CIRH;
+
+ // clear interrupt output
+ set_int(false);
+ }
+
+ // compute acknowledge vector
+ if (m_csrc & mask)
+ vector = 0xf0 | number;
+ else
+ vector = m_hvct | number;
+ }
+ else if (side_effects)
+ {
+ if (m_fprt)
+ LOGMASKED(LOG_STATE, "acknowledge without unmasked interrupt pending\n");
+ else
+ LOGMASKED(LOG_STATE, "acknowledge with FPRT clear\n");
+
+ // clear pending edge for interrupt 15
+ if (!BIT(m_eltg, 15))
+ m_ipnd &= ~(1 << 15);
+
+ // clear first priority
+ if (!(m_mctl & MCTL_NTAR))
+ m_fprt = 0;
+ }
+
+ if (side_effects)
+ LOGMASKED(LOG_STATE, "acknowledge vector 0x%02x\n", vector);
+
+ return vector;
+}
+
+u8 ns32202_device::interrupt_return(bool side_effects)
+{
+ side_effects &= !machine().side_effects_disabled();
+ u8 vector = m_hvct | 0x0f;
+
+ // find highest priority in-service interrupt
+ if (m_isrv && m_fprt)
+ {
+ u16 mask = m_fprt;
+ for (unsigned i = 0; i < 16; i++)
+ {
+ if (m_isrv & mask)
+ break;
+
+ // rotate priority mask
+ mask = (mask << 1) | (mask >> 15);
+ }
+ unsigned const number = 31 - count_leading_zeros(mask);
+
+ if (side_effects)
+ {
+ LOGMASKED(LOG_STATE, "return highest priority in-service interrupt %d\n", number);
+
+ if (m_mctl & MCTL_NTAR)
+ {
+ if (m_csrc & mask)
+ {
+ m_isrv_count[number]--;
+
+ if (!m_isrv_count[number])
+ m_isrv &= ~mask;
+ }
+ else
+ // clear interrupt in-service
+ m_isrv &= ~mask;
+ }
+ else
+ {
+ // clear interrupt in-service
+ m_isrv &= ~mask;
+
+ // rotate priority mask
+ m_fprt = (m_fprt << 1) | (m_fprt >> 15);
+ }
+ }
+
+ // compute return vector
+ if (m_csrc & mask)
+ vector = 0xf0 | number;
+ else
+ vector = m_hvct | number;
+ }
+ else if (side_effects)
+ {
+ if (m_fprt)
+ LOGMASKED(LOG_STATE, "return without in-service interrupt\n");
+ else
+ LOGMASKED(LOG_STATE, "return with FPRT clear\n");
+
+ if (!(m_mctl & MCTL_NTAR))
+ // rotate priority mask
+ m_fprt = (m_fprt << 1) | (m_fprt >> 15);
+ }
+
+ if (side_effects)
+ LOGMASKED(LOG_STATE, "return vector 0x%02x\n", vector);
+
+ return vector;
+}
+
+/*
+ * Check for level-triggered interrupts which become pending due to change of
+ * edge/level or polarity registers.
+ */
+void ns32202_device::interrupt_update()
+{
+ // compute new pending state
+ u16 const ipnd = m_ipnd | (m_eltg & ~(m_line_state ^ m_tpl));
+
+ // update and assert if state changed
+ if (ipnd ^ m_ipnd)
+ {
+ m_ipnd = ipnd;
+ m_interrupt->adjust(attotime::zero);
+ }
+}
+
+// N=0 -> l-counter
+template <unsigned N> void ns32202_device::counter(void *buf, s32 param)
+{
+ u32 const scaled_clock = clock() / ((m_cctl & CCTL_CFNPS) ? 1 : 4);
+
+ // for now, assume this is the periodic timer triggered when we hit zero
+ // reload on cycle after zero
+ if (param)
+ {
+ u32 const ticks = (m_cctl & CCTL_CCON)
+ ? ((u32(m_csv[1]) << 16) | m_csv[0]) - ((u32(m_ccv[1]) << 16) | m_ccv[0])
+ : m_csv[N] - m_ccv[N];
+
+ // reload current value
+ if (m_cctl & CCTL_CCON)
+ {
+ m_ccv[0] = m_csv[0];
+ m_ccv[1] = m_csv[1];
+ }
+ else
+ m_ccv[N] = m_csv[N];
+
+ // reschedule counter
+ m_counter[N]->adjust(attotime::from_ticks(ticks, scaled_clock), 0);
+ }
+ else
+ {
+ // clear current value
+ if (m_cctl & CCTL_CCON)
+ {
+ m_ccv[0] = 0;
+ m_ccv[1] = 0;
+ }
+ else
+ m_ccv[N] = 0;
+
+ // schedule reload cycle
+ m_counter[N]->adjust(attotime::from_ticks(1, scaled_clock), 1);
+
+ // update cout
+ if (!(m_mctl & MCTL_COUTD) && (m_cctl & (CCTL_COUT0 << N)))
+ {
+ if (m_mctl & MCTL_COUTM)
+ {
+ set_cout(true);
+ set_cout(false);
+ }
+ else
+ set_cout(!m_out_cout_state);
+ }
+
+ // update port
+ if ((N == 1) && !(m_mctl & MCTL_T16N8) && (m_ocasn & 15))
+ {
+ // TODO: trigger interrupts if IPS != 0
+
+ u8 const mask = (m_ocasn & ~m_pdir) & 15;
+ if (m_mctl & MCTL_CLKM)
+ {
+ m_pdat &= ~mask;
+
+ m_out_port(0, m_ocasn & 15, mask);
+ m_out_port(0, 0, mask);
+ }
+ else
+ {
+ m_pdat ^= mask;
+
+ m_out_port(0, m_pdat, mask);
+ }
+ }
+
+ // interrupts
+ unsigned const shift = N ? 4 : 0;
+ if (m_cictl & (CICTL_CIEL << shift))
+ {
+ // check counter interrupt error
+ if (m_cictl & (CICTL_CIRL << shift))
+ m_cictl |= (CICTL_CERL << shift);
+
+ // set counter interrupt request
+ m_cictl |= (CICTL_CIRL << shift);
+
+ // raise interrupt
+ m_ipnd |= 1 << ((m_ciptr >> shift) & 15);
+ m_interrupt->adjust(attotime::zero);
+ }
+ }
+}
+
+template <unsigned ST1, bool SideEffects> u8 ns32202_device::hvct_r()
+{
+ if (!ST1)
+ return interrupt_acknowledge(SideEffects);
+ else
+ return interrupt_return(SideEffects);
+}
+
+void ns32202_device::eltgl_w(u8 data)
+{
+ m_eltg = (m_eltg & 0xff00) | data;
+
+ interrupt_update();
+}
+
+void ns32202_device::eltgh_w(u8 data)
+{
+ m_eltg = (u16(data) << 8) | u8(m_eltg);
+
+ interrupt_update();
+}
+
+void ns32202_device::tpll_w(u8 data)
+{
+ m_tpl = (m_tpl & 0xff00) | data;
+
+ interrupt_update();
+}
+
+void ns32202_device::tplh_w(u8 data)
+{
+ m_tpl = (u16(data) << 8) | u8(m_tpl);
+
+ interrupt_update();
+}
+
+void ns32202_device::csrcl_w(u8 data)
+{
+ m_csrc = (m_csrc & 0xff00) | data;
+
+ // clear in-service counters
+ for (unsigned i = 0; i < 8; i++)
+ if (!BIT(m_csrc, i))
+ m_isrv_count[i] = 0;
+}
+
+void ns32202_device::csrch_w(u8 data)
+{
+ m_csrc = (u16(data) << 8) | u8(m_csrc);
+
+ // clear in-service counters
+ for (unsigned i = 8; i < 16; i++)
+ if (!BIT(m_csrc, i))
+ m_isrv_count[i] = 0;
+}
+
+void ns32202_device::ipndl_w(u8 data)
+{
+ if (BIT(data, 6))
+ // clear all pending interrupts in register
+ m_ipnd &= 0xff00;
+ else if (BIT(data, 7))
+ {
+ // set interrupt
+ m_ipnd |= 1 << (data & 7);
+
+ m_interrupt->adjust(attotime::zero);
+ }
+ else
+ // clear interrupt
+ m_ipnd &= ~(1 << (data & 7));
+}
+
+void ns32202_device::ipndh_w(u8 data)
+{
+ if (BIT(data, 6))
+ // clear all pending interrupts in register
+ m_ipnd &= 0x00ff;
+ else if (BIT(data, 7))
+ {
+ // set interrupt
+ m_ipnd |= 256 << (data & 7);
+
+ m_interrupt->adjust(attotime::zero);
+ }
+ else
+ // clear interrupt
+ m_ipnd &= ~(256 << (data & 7));
+}
+
+void ns32202_device::fprtl_w(u8 data)
+{
+ m_fprt = 1 << (data & 15);
+}
+
+void ns32202_device::cctl_w(u8 data)
+{
+ // disable l-counter in concatenated mode
+ if ((data & CCTL_CCON) && m_counter[0]->enabled())
+ m_counter[0]->enable(false);
+
+ // compute scaled clock
+ u32 const scaled_clock = clock() / ((data & CCTL_CFNPS) ? 1 : 4);
+
+ // start/stop h-counter
+ if (!(m_cctl & CCTL_CRUNH) && (data & CCTL_CRUNH))
+ m_counter[1]->adjust(attotime::from_ticks(1, scaled_clock), 1);
+ else if ((m_cctl & CCTL_CRUNH) && !(data & CCTL_CRUNH))
+ m_counter[1]->enable(false);
+
+ if (!(data & CCTL_CRUNH) && (data & CCTL_CDCRH))
+ ; // TODO: decrement h-counter
+
+ // start/stop l-counter
+ if (!(data & CCTL_CCON))
+ {
+ if (!(m_cctl & CCTL_CRUNH) && (data & CCTL_CRUNH))
+ m_counter[0]->adjust(attotime::from_ticks(1, scaled_clock), 1);
+ else if ((m_cctl & CCTL_CRUNH) && !(data & CCTL_CRUNH))
+ m_counter[0]->enable(false);
+
+ if (!(data & CCTL_CRUNL) && (data & CCTL_CDCRL))
+ ; // TODO: decrement l-counter
+ }
+
+ m_cctl = data & ~(CCTL_CRUNH | CCTL_CRUNL);
+}
+
+void ns32202_device::cictl_w(u8 data)
+{
+ u8 const mask =
+ ((data & CICTL_WENL) ? (CICTL_CERL | CICTL_CIRL | CICTL_CIEL) : 0) |
+ ((data & CICTL_WENH) ? (CICTL_CERH | CICTL_CIRH | CICTL_CIEH) : 0);
+
+ m_cictl = (m_cictl & ~mask) | (data & mask);
+}
diff --git a/src/devices/machine/ns32202.h b/src/devices/machine/ns32202.h
new file mode 100644
index 00000000000..c6328e5fa38
--- /dev/null
+++ b/src/devices/machine/ns32202.h
@@ -0,0 +1,137 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_NS32202_H
+#define MAME_MACHINE_NS32202_H
+
+#pragma once
+
+class ns32202_device : public device_t
+{
+public:
+ auto out_int() { return m_out_int.bind(); }
+ auto out_cout() { return m_out_cout.bind(); }
+ auto out_port() { return m_out_port.bind(); }
+
+ template <unsigned Number> void ir_w(int state);
+ template <unsigned ST1> void map(address_map &map);
+
+ ns32202_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+protected:
+ // device_t overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ void set_int(bool int_state);
+ void set_cout(bool cout_state);
+
+ void interrupt(void *buf, s32 param);
+ u8 interrupt_acknowledge(bool side_effects);
+ u8 interrupt_return(bool side_effects);
+
+ void interrupt_update();
+
+ template <unsigned N> void counter(void *buf, s32 param);
+
+ template <unsigned ST1, bool SideEffects> u8 hvct_r();
+
+ u8 eltgl_r() { return u8(m_eltg); }
+ u8 eltgh_r() { return m_eltg >> 8; }
+ u8 tpll_r() { return u8(m_tpl); }
+ u8 tplh_r() { return m_tpl >> 8; }
+ u8 ipndl_r() { return u8(m_ipnd); }
+ u8 ipndh_r() { return m_ipnd >> 8; }
+ u8 isrvl_r() { return u8(m_isrv); }
+ u8 isrvh_r() { return m_isrv >> 8; }
+ u8 imskl_r() { return u8(m_imsk); }
+ u8 imskh_r() { return m_imsk >> 8; }
+ u8 csrcl_r() { return u8(m_csrc); }
+ u8 csrch_r() { return m_csrc >> 8; }
+ u8 fprtl_r() { return u8(m_fprt); }
+ u8 fprth_r() { return m_fprt >> 8; }
+ u8 mctl_r() { return m_mctl; }
+ u8 ocasn_r() { return m_ocasn; }
+ u8 ciptr_r() { return m_ciptr; }
+ u8 pdat_r() { return 0; }
+ u8 ips_r() { return m_ips; }
+ u8 pdir_r() { return m_pdir; }
+ u8 cctl_r() { return m_cctl; }
+ u8 cictl_r() { return m_cictl; }
+ template <unsigned N> u8 csvl_r() { return u8(m_csv[N]); }
+ template <unsigned N> u8 csvh_r() { return m_csv[N] >> 8; }
+ u8 lccvl_r() { return 0; }
+ u8 lccvh_r() { return 0; }
+ u8 hccvl_r() { return 0; }
+ u8 hccvh_r() { return 0; }
+
+ void svct_w(u8 data) { m_hvct = data & 0xf0; }
+
+ void eltgl_w(u8 data);
+ void eltgh_w(u8 data);
+ void tpll_w(u8 data);
+ void tplh_w(u8 data);
+ void ipndl_w(u8 data);
+ void ipndh_w(u8 data);
+ void isrvl_w(u8 data) { m_isrv = (m_isrv & 0xff00) | data; }
+ void isrvh_w(u8 data) { m_isrv = (u16(data) << 8) | u8(m_isrv); }
+ void imskl_w(u8 data) { m_imsk = (m_imsk & 0xff00) | data; m_interrupt->adjust(attotime::zero); }
+ void imskh_w(u8 data) { m_imsk = (u16(data) << 8) | u8(m_imsk); m_interrupt->adjust(attotime::zero); }
+ void csrcl_w(u8 data);
+ void csrch_w(u8 data);
+ void fprtl_w(u8 data);
+ void fprth_w(u8 data) {}
+
+ void mctl_w(u8 data) { m_mctl = data; }
+ void ocasn_w(u8 data) { m_ocasn = data; }
+ void ciptr_w(u8 data) { m_ciptr = data; }
+ void pdat_w(u8 data) {}
+ void ips_w(u8 data) { m_ips = data; }
+ void pdir_w(u8 data) { m_pdir = data; }
+ void cctl_w(u8 data);
+ void cictl_w(u8 data);
+
+ template <unsigned N> void csvl_w(u8 data) { m_csv[N] = (m_csv[N] & 0xff00) | data; }
+ template <unsigned N> void csvh_w(u8 data) { m_csv[N] = (u16(data) << 8) | u8(m_csv[N]); }
+ void lccvl_w(u8 data) {}
+ void lccvh_w(u8 data) {}
+ void hccvl_w(u8 data) {}
+ void hccvh_w(u8 data) {}
+
+private:
+ devcb_write_line m_out_int;
+ devcb_write_line m_out_cout;
+ devcb_write8 m_out_port;
+
+ emu_timer *m_interrupt;
+ emu_timer *m_counter[2];
+
+ u8 m_hvct; // hardware vector
+ u16 m_eltg; // edge/level triggering
+ u16 m_tpl; // triggering polarity
+ u16 m_ipnd; // interrupts pending
+ u16 m_isrv; // interrupts in-service
+ u16 m_imsk; // interrupt mask
+ u16 m_csrc; // cascaded source
+ u16 m_fprt; // first priority
+ u8 m_mctl; // mode control
+ u8 m_ocasn; // output clock assignment
+ u8 m_ciptr; // counter interrupt pointer
+ u8 m_pdat; // port data
+ u8 m_ips; // interrupt/port select
+ u8 m_pdir; // port direction
+ u8 m_cctl; // counter control
+ u8 m_cictl; // counter interrupt control
+ u16 m_csv[2]; // counter starting value
+ u16 m_ccv[2]; // counter current value
+
+ unsigned m_isrv_count[16];
+
+ u16 m_line_state;
+ bool m_out_int_state;
+ bool m_out_cout_state;
+};
+
+DECLARE_DEVICE_TYPE(NS32202, ns32202_device)
+
+#endif // MAME_MACHINE_NS32202_H
diff --git a/src/devices/machine/pxa255.cpp b/src/devices/machine/pxa255.cpp
index 07e7d997b8c..6bd82ec987c 100644
--- a/src/devices/machine/pxa255.cpp
+++ b/src/devices/machine/pxa255.cpp
@@ -1583,7 +1583,7 @@ uint32_t pxa255_periphs_device::screen_update(screen_device &screen, bitmap_rgb3
{
for (int y = 0; y <= (m_lcd_regs.lccr2 & PXA255_LCCR2_LPP); y++)
{
- uint32_t *dst = &bitmap.pix32(y);
+ uint32_t *dst = &bitmap.pix(y);
for (int x = 0; x <= (m_lcd_regs.lccr1 & PXA255_LCCR1_PPL); x++)
{
*dst++ = m_lcd_palette[m_lcd_framebuffer[y * ((m_lcd_regs.lccr1 & PXA255_LCCR1_PPL) + 1) + x]];
diff --git a/src/devices/machine/s2636.cpp b/src/devices/machine/s2636.cpp
index bdf95dc69d0..8ad26690bcf 100644
--- a/src/devices/machine/s2636.cpp
+++ b/src/devices/machine/s2636.cpp
@@ -203,7 +203,7 @@ void s2636_device::device_start()
save_item(NAME(m_intreq));
save_item(NAME(m_intack));
- m_stream = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_stream = stream_alloc(0, 1, machine().sample_rate());
save_item(NAME(m_sample_cnt));
save_item(NAME(m_sound_lvl));
@@ -247,7 +247,7 @@ void s2636_device::render_next_line()
// pre-clear the line for convenience
rectangle const &vis_area = screen().visible_area();
- uint16_t *const row = &m_bitmap.pix16(m_screen_line);
+ uint16_t *const row = &m_bitmap.pix(m_screen_line);
m_bitmap.plot_box(0, m_screen_line, m_bitmap.width(), 1, 0);
if ((vis_area.min_y > m_screen_line) || (vis_area.max_y < m_screen_line))
@@ -447,13 +447,14 @@ void s2636_device::write_intack(int state)
//-------------------------------------------------
-// sound_stream_update_legacy - generate audio output
+// sound_stream_update - generate audio output
//-------------------------------------------------
-void s2636_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+
+void s2636_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
- while (samples--)
+ auto &buffer = outputs[0];
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
if (!m_sample_cnt)
{
@@ -469,7 +470,7 @@ void s2636_device::sound_stream_update_legacy(sound_stream &stream, stream_sampl
}
}
- *buffer++ = m_sound_lvl ? 0x7fff : 0x0000;
+ buffer.put(sampindex, m_sound_lvl ? 1.0 : 0.0);
m_sample_cnt--;
}
}
diff --git a/src/devices/machine/s2636.h b/src/devices/machine/s2636.h
index b5e41b83499..8803c629015 100644
--- a/src/devices/machine/s2636.h
+++ b/src/devices/machine/s2636.h
@@ -58,7 +58,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
enum
diff --git a/src/devices/machine/s3c24xx.hxx b/src/devices/machine/s3c24xx.hxx
index dcff99a7b70..8fae9ee616e 100644
--- a/src/devices/machine/s3c24xx.hxx
+++ b/src/devices/machine/s3c24xx.hxx
@@ -434,7 +434,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tpal()
uint32_t color = s3c24xx_get_color_tpal();
for (int y = m_lcd.vpos_min; y <= m_lcd.vpos_max; y++)
{
- uint32_t *scanline = &bitmap.pix32(y, m_lcd.hpos_min);
+ uint32_t *scanline = &bitmap.pix(y, m_lcd.hpos_min);
for (int x = m_lcd.hpos_min; x <= m_lcd.hpos_max; x++)
{
*scanline++ = color;
@@ -445,7 +445,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tpal()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_01()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -467,7 +467,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_01()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -476,7 +476,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_01()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_02()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -490,7 +490,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_02()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -499,7 +499,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_02()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_04()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -513,7 +513,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_04()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -522,7 +522,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_04()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_08()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -536,7 +536,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_08()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -545,7 +545,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_08()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_p()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 16; i++)
{
*scanline++ = s3c24xx_get_color_stn_12(s3c24xx_lcd_dma_read_bits(12));
@@ -555,7 +555,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_p()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -563,7 +563,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_p()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_u() // not tested
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -577,7 +577,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_u() // not tested
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -586,7 +586,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_stn_12_u() // not tested
void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_01()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -600,7 +600,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_01()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -609,7 +609,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_01()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_02()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -623,7 +623,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_02()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -632,7 +632,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_02()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_04()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -646,7 +646,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_04()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -655,7 +655,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_04()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_08()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -669,7 +669,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_08()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -678,7 +678,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_08()
void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_16()
{
bitmap_rgb32 &bitmap = *m_lcd.bitmap[0];
- uint32_t *scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ uint32_t *scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
for (int i = 0; i < 4; i++)
{
uint32_t data = s3c24xx_lcd_dma_read();
@@ -692,7 +692,7 @@ void S3C24_CLASS_NAME::s3c24xx_lcd_render_tft_16()
m_lcd.vpos++;
if (m_lcd.vpos > m_lcd.vpos_max) m_lcd.vpos = m_lcd.vpos_min;
m_lcd.hpos = m_lcd.hpos_min;
- scanline = &bitmap.pix32(m_lcd.vpos, m_lcd.hpos);
+ scanline = &bitmap.pix(m_lcd.vpos, m_lcd.hpos);
}
}
}
@@ -751,9 +751,9 @@ void S3C24_CLASS_NAME::bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bit
{
for (int y = 0; y < bitmap_dst.height(); y++)
{
- uint32_t *line0 = &bitmap_src_1.pix32(y);
- uint32_t *line1 = &bitmap_src_2.pix32(y);
- uint32_t *line2 = &bitmap_dst.pix32(y);
+ uint32_t const *const line0 = &bitmap_src_1.pix(y);
+ uint32_t const *const line1 = &bitmap_src_2.pix(y);
+ uint32_t *const line2 = &bitmap_dst.pix(y);
for (int x = 0; x < bitmap_dst.width(); x++)
{
uint32_t color0 = line0[x];
@@ -764,9 +764,9 @@ void S3C24_CLASS_NAME::bitmap_blend( bitmap_rgb32 &bitmap_dst, bitmap_rgb32 &bit
uint16_t r1 = (color1 >> 16) & 0x000000ff;
uint16_t g1 = (color1 >> 8) & 0x000000ff;
uint16_t b1 = (color1 >> 0) & 0x000000ff;
- uint8_t r = (uint8_t)((r0 + r1) >> 1);
- uint8_t g = (uint8_t)((g0 + g1) >> 1);
- uint8_t b = (uint8_t)((b0 + b1) >> 1);
+ uint8_t r = uint8_t((r0 + r1) >> 1);
+ uint8_t g = uint8_t((g0 + g1) >> 1);
+ uint8_t b = uint8_t((b0 + b1) >> 1);
line2[x] = (r << 16) | (g << 8) | b;
}
}
diff --git a/src/devices/machine/s3c44b0.cpp b/src/devices/machine/s3c44b0.cpp
index 6672127e20f..bf3a1ed811c 100644
--- a/src/devices/machine/s3c44b0.cpp
+++ b/src/devices/machine/s3c44b0.cpp
@@ -17,6 +17,8 @@
#include "coreutil.h"
+#include <algorithm>
+
#define S3C44B0_INTCON (0x00 / 4) // Interrupt Control
#define S3C44B0_INTPND (0x04 / 4) // Interrupt Request Status
@@ -696,8 +698,8 @@ uint32_t s3c44b0_device::video_update(screen_device &screen, bitmap_rgb32 &bitma
{
for (int y = 0; y < screen.height(); y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
- uint8_t *vram = m_lcd.bitmap.get() + y * (m_lcd.hpos_max - m_lcd.hpos_min + 1);
+ uint32_t *scanline = &bitmap.pix(y);
+ uint8_t const *vram = m_lcd.bitmap.get() + y * (m_lcd.hpos_max - m_lcd.hpos_min + 1);
for (int x = 0; x < screen.width(); x++)
{
*scanline++ = rgb_t(vram[0], vram[1], vram[2]);
@@ -710,8 +712,7 @@ uint32_t s3c44b0_device::video_update(screen_device &screen, bitmap_rgb32 &bitma
{
for (int y = 0; y < screen.height(); y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
- memset(scanline, 0, screen.width() * 4);
+ std::fill_n(&bitmap.pix(y), screen.width(), 0);
}
}
return 0;
diff --git a/src/devices/machine/spg110_video.cpp b/src/devices/machine/spg110_video.cpp
index a76fef3bb60..daf7fa5e158 100644
--- a/src/devices/machine/spg110_video.cpp
+++ b/src/devices/machine/spg110_video.cpp
@@ -4,6 +4,9 @@
#include "emu.h"
#include "spg110_video.h"
+#include <algorithm>
+
+
DEFINE_DEVICE_TYPE(SPG110_VIDEO, spg110_video_device, "spg110_video", "SPG110 System-on-a-Chip (Video)")
spg110_video_device::spg110_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
@@ -649,9 +652,9 @@ uint32_t spg110_video_device::screen_update(screen_device &screen, bitmap_rgb32
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
- uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
- uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
- memcpy(dest, src, sizeof(uint32_t) * ((cliprect.max_x - cliprect.min_x) + 1));
+ uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
+ const uint32_t *src = &m_screenbuf[cliprect.min_x + 320 * y];
+ std::copy_n(src, cliprect.width(), dest);
}
return 0;
diff --git a/src/devices/machine/spg290_ppu.cpp b/src/devices/machine/spg290_ppu.cpp
index 8f47d61bf18..19ff7ccb1d2 100644
--- a/src/devices/machine/spg290_ppu.cpp
+++ b/src/devices/machine/spg290_ppu.cpp
@@ -354,9 +354,9 @@ inline void spg290_ppu_device::argb1555(bitmap_rgb32 &bitmap, const rectangle &c
{
rgb_t color = rgb_t(pal5bit(argb >> 10), pal5bit(argb >> 5), pal5bit(argb >> 0));
if (blend)
- color = blend_colors(bitmap.pix32(posy, posx), color, blend);
+ color = blend_colors(bitmap.pix(posy, posx), color, blend);
- bitmap.pix32(posy, posx) = color;
+ bitmap.pix(posy, posx) = color;
}
}
@@ -366,9 +366,9 @@ inline void spg290_ppu_device::rgb565(bitmap_rgb32 &bitmap, const rectangle &cli
{
rgb_t color = rgb_t(pal5bit(rgb >> 11), pal6bit(rgb >> 5), pal5bit(rgb >> 0));
if (blend)
- color = blend_colors(bitmap.pix32(posy, posx), color, blend);
+ color = blend_colors(bitmap.pix(posy, posx), color, blend);
- bitmap.pix32(posy, posx) = color;
+ bitmap.pix(posy, posx) = color;
}
}
diff --git a/src/devices/machine/spg2xx.h b/src/devices/machine/spg2xx.h
index 0eb2a29f82a..68d42675360 100644
--- a/src/devices/machine/spg2xx.h
+++ b/src/devices/machine/spg2xx.h
@@ -123,8 +123,6 @@ protected:
devcb_write8 m_chip_sel;
- emu_timer *m_screenpos_timer;
-
uint8_t m_fiq_vector;
required_device<screen_device> m_screen;
diff --git a/src/devices/machine/spg2xx_audio.cpp b/src/devices/machine/spg2xx_audio.cpp
index 07d01e88be5..2441ebf17ce 100644
--- a/src/devices/machine/spg2xx_audio.cpp
+++ b/src/devices/machine/spg2xx_audio.cpp
@@ -76,7 +76,7 @@ void spg2xx_audio_device::device_start()
m_audio_beat = timer_alloc(TIMER_BEAT);
m_audio_beat->adjust(attotime::never);
- m_stream = stream_alloc_legacy(0, 2, 281250/4);
+ m_stream = stream_alloc(0, 2, 281250/4);
m_channel_debug = -1;
@@ -887,12 +887,12 @@ void spg2xx_audio_device::audio_w(offs_t offset, uint16_t data)
}
}
-void spg2xx_audio_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void spg2xx_audio_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *out_l = outputs[0];
- stream_sample_t *out_r = outputs[1];
+ auto &out_l = outputs[0];
+ auto &out_r = outputs[1];
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < out_l.samples(); i++)
{
int32_t left_total = 0;
int32_t right_total = 0;
@@ -992,8 +992,8 @@ void spg2xx_audio_device::sound_stream_update_legacy(sound_stream &stream, strea
int32_t left_final = (int16_t)((left_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7);
int32_t right_final = (int16_t)((right_total * (int16_t)m_audio_ctrl_regs[AUDIO_MAIN_VOLUME]) >> 7);
- *out_l++ = (int16_t)left_final;
- *out_r++ = (int16_t)right_final;
+ out_l.put_int(i, int16_t(left_final), 32768);
+ out_r.put_int(i, int16_t(right_final), 32768);
}
}
diff --git a/src/devices/machine/spg2xx_audio.h b/src/devices/machine/spg2xx_audio.h
index 59d7635198d..588d49e7895 100644
--- a/src/devices/machine/spg2xx_audio.h
+++ b/src/devices/machine/spg2xx_audio.h
@@ -33,7 +33,7 @@ public:
protected:
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void audio_beat_tick();
void audio_rampdown_tick(const uint32_t channel);
diff --git a/src/devices/machine/spg_renderer.cpp b/src/devices/machine/spg_renderer.cpp
index 0b6efe58c3f..78bc26438ae 100644
--- a/src/devices/machine/spg_renderer.cpp
+++ b/src/devices/machine/spg_renderer.cpp
@@ -831,7 +831,7 @@ void spg_renderer_device::update_palette_lookup()
void spg_renderer_device::apply_saturation_and_fade(bitmap_rgb32& bitmap, const rectangle& cliprect, int scanline)
{
- uint32_t* src = &bitmap.pix32(scanline, cliprect.min_x);
+ uint32_t* src = &bitmap.pix(scanline, cliprect.min_x);
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
diff --git a/src/devices/machine/swtpc8212.cpp b/src/devices/machine/swtpc8212.cpp
index 68af9d42e07..fffd6eefe7f 100644
--- a/src/devices/machine/swtpc8212.cpp
+++ b/src/devices/machine/swtpc8212.cpp
@@ -319,7 +319,7 @@ MC6845_UPDATE_ROW(swtpc8212_device::update_row)
else
font_color = rgb_t(0x00, 0xd0, 0x00);
}
- bitmap.pix32(y, x++) = font_color;
+ bitmap.pix(y, x++) = font_color;
data <<= 1;
}
diff --git a/src/devices/machine/tc009xlvc.cpp b/src/devices/machine/tc009xlvc.cpp
index e6fcb74a181..b2d302d3922 100644
--- a/src/devices/machine/tc009xlvc.cpp
+++ b/src/devices/machine/tc009xlvc.cpp
@@ -347,7 +347,7 @@ u32 tc0090lvc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
{
const int res_x = (global_flip()) ? 320 - x : x;
- bitmap.pix16(y, x) = palette().pen(m_bitmap_ram[count + (res_x & 0x1ff)]);
+ bitmap.pix(y, x) = palette().pen(m_bitmap_ram[count + (res_x & 0x1ff)]);
}
}
}
@@ -398,7 +398,7 @@ u32 tc0091lvc_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
{
const int res_x = (global_flip()) ? 320 - x : x;
- bitmap.pix16(y, x) = palette().pen(m_bitmap_ram[count + (res_x & 0x1ff)]);
+ bitmap.pix(y, x) = palette().pen(m_bitmap_ram[count + (res_x & 0x1ff)]);
}
}
}
diff --git a/src/devices/machine/terminal.cpp b/src/devices/machine/terminal.cpp
index fd07c5bff35..ccb101d8036 100644
--- a/src/devices/machine/terminal.cpp
+++ b/src/devices/machine/terminal.cpp
@@ -276,7 +276,7 @@ uint32_t generic_terminal_device::update(screen_device &device, bitmap_rgb32 &bi
{
for (uint8_t ra = 0; ra < 10; ra++)
{
- uint32_t *p = &bitmap.pix32(sy++);
+ uint32_t *p = &bitmap.pix(sy++);
for (uint16_t x = ma; x < ma + m_width; x++)
{
diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp
index 6328ec74dab..85aabb49335 100644
--- a/src/devices/machine/upd765.cpp
+++ b/src/devices/machine/upd765.cpp
@@ -174,6 +174,7 @@ upd765_family_device::upd765_family_device(const machine_config &mconfig, device
ready_polled(true),
select_connected(true),
select_multiplexed(true),
+ has_dor(true),
external_ready(false),
recalibrate_steps(77),
mode(mode_t::AT),
@@ -181,8 +182,7 @@ upd765_family_device::upd765_family_device(const machine_config &mconfig, device
drq_cb(*this),
hdl_cb(*this),
idx_cb(*this),
- us_cb(*this),
- dor_reset(0x00)
+ us_cb(*this)
{
}
@@ -245,6 +245,7 @@ void upd765_family_device::device_start()
cur_rate = 250000;
tc = false;
selected_drive = -1;
+ dor = 0x0c;
// reset at upper levels may cause a write to tc ending up with
// live_sync, which will crash if the live structure isn't
@@ -267,7 +268,8 @@ void upd765_family_device::device_start()
void upd765_family_device::device_reset()
{
- dor = dor_reset;
+ if(has_dor)
+ dor = 0x00;
locked = false;
soft_reset();
}
@@ -304,6 +306,14 @@ void upd765_family_device::soft_reset()
set_ds(select_multiplexed ? 0 : -1);
check_irq();
+ if(BIT(dor, 2))
+ end_reset();
+ else if(ready_polled)
+ poll_timer->adjust(attotime::never);
+}
+
+void upd765_family_device::end_reset()
+{
if(ready_polled)
poll_timer->adjust(attotime::from_usec(100), 0, attotime::from_usec(1024));
}
@@ -333,6 +343,25 @@ bool upd765_family_device::get_ready(int fid)
return !external_ready;
}
+WRITE_LINE_MEMBER(upd765_family_device::reset_w)
+{
+ // This implementation is not valid for devices with DOR and possibly other extra registers.
+ // The working assumption is that no need to manipulate the RESET line directly when software can use DOR instead.
+ assert(!has_dor);
+ if(bool(state) == !BIT(dor, 2))
+ return;
+
+ LOGREGS("reset = %d\n", state);
+ if(state) {
+ dor &= 0xfb;
+ soft_reset();
+ }
+ else {
+ dor |= 0x04;
+ end_reset();
+ }
+}
+
void upd765_family_device::set_ds(int fid)
{
if(selected_drive == fid)
@@ -399,11 +428,16 @@ uint8_t upd765_family_device::dor_r()
void upd765_family_device::dor_w(uint8_t data)
{
+ assert(has_dor);
LOGREGS("dor = %02x\n", data);
uint8_t diff = dor ^ data;
dor = data;
- if(diff & 4)
- soft_reset();
+ if(BIT(diff, 2)) {
+ if(BIT(data, 2))
+ end_reset();
+ else
+ soft_reset();
+ }
for(int i=0; i<4; i++) {
floppy_info &fi = flopi[i];
@@ -513,6 +547,9 @@ uint8_t upd765_family_device::fifo_r()
void upd765_family_device::fifo_w(uint8_t data)
{
+ if(!BIT(dor, 2))
+ LOGWARN("%s: fifo_w(%02x) in reset\n", machine().describe_context(), data);
+
switch(main_phase) {
case PHASE_CMD: {
command[command_pos++] = data;
@@ -780,7 +817,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x c=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -796,7 +833,7 @@ void upd765_family_device::live_run(attotime limit)
cur_live.data_separator_phase = false;
cur_live.bit_counter = 0;
cur_live.state = READ_HEADER_BLOCK_HEADER;
- LOGLIVE("%s: Found A1\n", tts(cur_live.tm));
+ LOGLIVE("%s: Found A1\n", cur_live.tm.to_string());
}
if(!mfm && cur_live.shift_reg == 0xf57e) {
@@ -804,7 +841,7 @@ void upd765_family_device::live_run(attotime limit)
cur_live.data_separator_phase = false;
cur_live.bit_counter = 0;
cur_live.state = READ_ID_BLOCK;
- LOGLIVE("%s: Found IDAM\n", tts(cur_live.tm));
+ LOGLIVE("%s: Found IDAM\n", cur_live.tm.to_string());
}
break;
@@ -812,7 +849,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -832,11 +869,11 @@ void upd765_family_device::live_run(attotime limit)
if(cur_live.shift_reg != 0x4489)
cur_live.state = SEARCH_ADDRESS_MARK_HEADER;
else
- LOGLIVE("%s: Found A1\n", tts(cur_live.tm));
+ LOGLIVE("%s: Found A1\n", cur_live.tm.to_string());
break;
}
if(cur_live.data_reg != 0xfe) {
- LOGLIVE("%s: No ident byte found after triple-A1, continue search\n", tts(cur_live.tm));
+ LOGLIVE("%s: No ident byte found after triple-A1, continue search\n", cur_live.tm.to_string());
cur_live.state = SEARCH_ADDRESS_MARK_HEADER;
break;
}
@@ -854,7 +891,7 @@ void upd765_family_device::live_run(attotime limit)
break;
int slot = (cur_live.bit_counter >> 4)-1;
- LOGLIVE("%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm), slot, cur_live.data_reg, cur_live.crc);
+ LOGLIVE("%s: slot=%d data=%02x crc=%04x\n", cur_live.tm.to_string(), slot, cur_live.data_reg, cur_live.crc);
cur_live.idbuf[slot] = cur_live.data_reg;
if(slot == 5) {
live_delay(IDLE);
@@ -867,7 +904,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x c=%d.%x\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -912,7 +949,7 @@ void upd765_family_device::live_run(attotime limit)
if(read_one_bit(limit))
return;
- LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm), cur_live.shift_reg,
+ LOGSHIFT("%s: shift = %04x data=%02x counter=%d\n", cur_live.tm.to_string(), cur_live.shift_reg,
(cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
(cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
(cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
@@ -1218,7 +1255,7 @@ void upd765_family_device::live_run(attotime limit)
break;
default:
- LOGWARN("%s: Unknown live state %d\n", tts(cur_live.tm), cur_live.state);
+ LOGWARN("%s: Unknown live state %d\n", cur_live.tm.to_string(), cur_live.state);
return;
}
}
@@ -2412,17 +2449,6 @@ bool upd765_family_device::get_irq() const
return cur_irq;
}
-std::string upd765_family_device::tts(attotime t)
-{
- const char *sign = "";
- if(t.seconds() < 0) {
- t = attotime::zero - t;
- sign = "-";
- }
- int const nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- return util::string_format("%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
-}
-
std::string upd765_family_device::results() const
{
std::ostringstream stream;
@@ -2440,7 +2466,7 @@ std::string upd765_family_device::results() const
std::string upd765_family_device::ttsn() const
{
- return tts(machine().time());
+ return machine().time().to_string();
}
void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
@@ -2623,7 +2649,7 @@ bool upd765_family_device::write_one_bit(const attotime &limit)
void upd765_family_device::live_write_raw(uint16_t raw)
{
- LOGLIVE("%s: write %04x %04x\n", tts(cur_live.tm), raw, cur_live.crc);
+ LOGLIVE("%s: write %04x %04x\n", cur_live.tm.to_string(), raw, cur_live.crc);
cur_live.shift_reg = raw;
cur_live.data_bit_context = raw & 1;
}
@@ -2643,7 +2669,7 @@ void upd765_family_device::live_write_mfm(uint8_t mfm)
cur_live.data_reg = mfm;
cur_live.shift_reg = raw;
cur_live.data_bit_context = context;
- LOGLIVE("%s: write %02x %04x %04x\n", tts(cur_live.tm), mfm, cur_live.crc, raw);
+ LOGLIVE("%s: write %02x %04x %04x\n", cur_live.tm.to_string(), mfm, cur_live.crc, raw);
}
void upd765_family_device::live_write_fm(uint8_t fm)
@@ -2655,7 +2681,7 @@ void upd765_family_device::live_write_fm(uint8_t fm)
cur_live.data_reg = fm;
cur_live.shift_reg = raw;
cur_live.data_bit_context = fm & 1;
- LOGLIVE("%s: write %02x %04x %04x\n", tts(cur_live.tm), fm, cur_live.crc, raw);
+ LOGLIVE("%s: write %02x %04x %04x\n", cur_live.tm.to_string(), fm, cur_live.crc, raw);
}
bool upd765_family_device::sector_matches() const
@@ -2672,17 +2698,17 @@ bool upd765_family_device::sector_matches() const
upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, UPD765A, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
}
upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, UPD765B, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
}
i8272a_device::i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, I8272A, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
}
upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd72065_device(mconfig, UPD72065, tag, owner, clock)
@@ -2691,7 +2717,7 @@ upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag,
upd72065_device::upd72065_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, type, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
recalibrate_steps = 255;
}
@@ -2713,7 +2739,7 @@ upd72069_device::upd72069_device(const machine_config &mconfig, const char *tag,
i82072_device::i82072_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : upd765_family_device(mconfig, I82072, tag, owner, clock)
{
- dor_reset = 0x0c;
+ has_dor = false;
recalibrate_steps = 255;
}
@@ -3089,7 +3115,7 @@ mcs3201_device::mcs3201_device(const machine_config &mconfig, const char *tag, d
upd765_family_device(mconfig, MCS3201, tag, owner, clock),
m_input_handler(*this)
{
- dor_reset = 0x0c;
+ has_dor = true;
ready_polled = false;
ready_connected = false;
select_connected = true;
diff --git a/src/devices/machine/upd765.h b/src/devices/machine/upd765.h
index 0c81f5aaa77..0ba8aa6d1c7 100644
--- a/src/devices/machine/upd765.h
+++ b/src/devices/machine/upd765.h
@@ -49,6 +49,7 @@ public:
void ready_w(bool val);
DECLARE_WRITE_LINE_MEMBER(tc_line_w) { tc_w(state == ASSERT_LINE); }
+ DECLARE_WRITE_LINE_MEMBER(reset_w);
void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled
@@ -231,7 +232,7 @@ protected:
static constexpr int rates[4] = { 500000, 300000, 250000, 1000000 };
- bool ready_connected, ready_polled, select_connected, select_multiplexed;
+ bool ready_connected, ready_polled, select_connected, select_multiplexed, has_dor;
bool external_ready;
@@ -250,7 +251,7 @@ protected:
bool fifo_write;
uint8_t dor, dsr, msr, fifo[16], command[16], result[16];
uint8_t st1, st2, st3;
- uint8_t fifocfg, dor_reset;
+ uint8_t fifocfg;
uint8_t precomp;
uint16_t spec;
int sector_size;
@@ -259,7 +260,6 @@ protected:
emu_timer *poll_timer;
- static std::string tts(attotime t);
std::string results() const;
std::string ttsn() const;
@@ -288,6 +288,8 @@ protected:
C_INCOMPLETE
};
+ void end_reset();
+
void delay_cycles(emu_timer *tm, int cycles);
void check_irq();
void fifo_expect(int size, bool write);
diff --git a/src/devices/machine/wd1010.cpp b/src/devices/machine/wd1010.cpp
index 96fb4b5fdd0..a330d6c7671 100644
--- a/src/devices/machine/wd1010.cpp
+++ b/src/devices/machine/wd1010.cpp
@@ -16,7 +16,7 @@
#define LOG_REGS (1U << 4)
#define LOG_DATA (1U << 5)
-//#define VERBOSE (LOG_CMD | LOG_INT | LOG_SEEK | LOG_REGS | LOG_DATA)
+#define VERBOSE (LOG_CMD | LOG_INT | LOG_SEEK | LOG_REGS | LOG_DATA)
//#define LOG_OUTPUT_STREAM std::cout
#include "logmacro.h"
@@ -46,7 +46,11 @@ DEFINE_DEVICE_TYPE(WD1010, wd1010_device, "wd1010", "Western Digital WD1010-05")
wd1010_device::wd1010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, WD1010, tag, owner, clock),
m_out_intrq_cb(*this),
+ m_out_bdrq_cb(*this),
+ m_out_bcs_cb(*this),
m_out_bcr_cb(*this),
+ m_out_dirin_cb(*this),
+ m_out_wg_cb(*this),
m_in_data_cb(*this),
m_out_data_cb(*this),
m_intrq(0),
@@ -83,13 +87,18 @@ void wd1010_device::device_start()
// resolve callbacks
m_out_intrq_cb.resolve_safe();
+ m_out_bdrq_cb.resolve_safe();
+ m_out_bcs_cb.resolve_safe();
m_out_bcr_cb.resolve_safe();
+ m_out_dirin_cb.resolve_safe();
+ m_out_wg_cb.resolve_safe();
m_in_data_cb.resolve_safe(0);
m_out_data_cb.resolve_safe();
// allocate timer
m_seek_timer = timer_alloc(TIMER_SEEK);
- m_data_timer = timer_alloc(TIMER_DATA);
+ m_read_timer = timer_alloc(TIMER_READ);
+ m_write_timer = timer_alloc(TIMER_WRITE);
// register for save states
save_item(NAME(m_intrq));
@@ -156,14 +165,12 @@ void wd1010_device::device_timer(emu_timer &timer, device_timer_id tid, int para
break;
- case TIMER_DATA:
-
- // check if data is ready or continue waiting
- if (m_brdy)
- cmd_write_sector();
- else
- m_data_timer->adjust(attotime::from_usec(35));
+ case TIMER_READ:
+ cmd_read_sector();
+ break;
+ case TIMER_WRITE:
+ cmd_write_sector();
break;
}
}
@@ -207,6 +214,26 @@ void wd1010_device::set_intrq(int state)
}
//-------------------------------------------------
+// set_bdrq - set drq status
+//-------------------------------------------------
+
+void wd1010_device::set_bdrq(int state)
+{
+ if ((!(m_status & STATUS_DRQ)) && state == 1)
+ {
+ LOGINT("DRQ 1\n");
+ m_status |= STATUS_DRQ;
+ m_out_bdrq_cb(1);
+ }
+ else if ((m_status & STATUS_DRQ) && state == 0)
+ {
+ LOGINT("DRQ 0\n");
+ m_status &= ~STATUS_DRQ;
+ m_out_bdrq_cb(0);
+ }
+}
+
+//-------------------------------------------------
// get_stepping_rate - calculate stepping rate
//-------------------------------------------------
@@ -305,6 +332,16 @@ void wd1010_device::brdy_w(int state)
m_brdy = state;
}
+int wd1010_device::sc_r()
+{
+ return m_status & STATUS_SC ? 1 : 0;
+}
+
+int wd1010_device::tk000_r()
+{
+ return m_drives[drive()].cylinder == 0 ? 1 : 0;
+}
+
uint8_t wd1010_device::read(offs_t offset)
{
// if the controller is busy all reads return the status register
@@ -423,13 +460,13 @@ void wd1010_device::write(offs_t offset, uint8_t data)
if ((m_command >> 4) != CMD_SCAN_ID)
m_status &= ~STATUS_SC;
- int amount = 0;
+ int seek = 0;
int target = 0;
switch (m_command >> 4)
{
case CMD_RESTORE:
- amount = m_drives[drive()].cylinder;
+ seek = m_drives[drive()].cylinder;
target = 0;
break;
@@ -437,15 +474,17 @@ void wd1010_device::write(offs_t offset, uint8_t data)
case CMD_READ_SECTOR:
case CMD_WRITE_SECTOR:
case CMD_WRITE_FORMAT:
- amount = abs(m_drives[drive()].cylinder - m_cylinder);
+ seek = m_drives[drive()].cylinder - m_cylinder;
target = m_cylinder;
break;
}
+ m_out_dirin_cb(seek > 0 ? 1 : 0);
+
if ((m_command >> 4) != CMD_SCAN_ID)
- LOGSEEK("Seeking %d cylinders to %d\n", amount, target);
+ LOGSEEK("Seeking %d cylinders to %d\n", seek, target);
- m_seek_timer->adjust(get_stepping_rate() * amount, target);
+ m_seek_timer->adjust(get_stepping_rate() * abs(seek), target);
}
break;
@@ -465,12 +504,30 @@ void wd1010_device::cmd_restore()
void wd1010_device::cmd_read_sector()
{
+ if (m_status & STATUS_DRQ)
+ {
+ if (m_brdy)
+ {
+ set_bdrq(0);
+
+ // if there's nothing left we're done
+ if (m_sector_count == 0)
+ {
+ end_command();
+ return;
+ }
+ }
+ else
+ {
+ // continue waiting for the buffer to be ready
+ m_read_timer->adjust(attotime::from_usec(35));
+ return;
+ }
+ }
+
hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file();
hard_disk_info *info = hard_disk_get_info(file);
- m_out_bcr_cb(1);
- m_out_bcr_cb(0);
-
// verify that we can read
if (head() > info->heads)
{
@@ -479,91 +536,112 @@ void wd1010_device::cmd_read_sector()
set_error(ERR_AC);
end_command();
+ return;
}
- else
- {
- uint8_t buffer[512];
- while (m_sector_count > 0)
- {
- LOGDATA("--> Transferring sector to buffer (lba = %08x)\n", get_lbasector());
+ uint8_t buffer[512];
- hard_disk_read(file, get_lbasector(), buffer);
+ m_out_bcr_cb(1);
+ m_out_bcr_cb(0);
- for (int i = 0; i < 512; i++)
- m_out_data_cb(buffer[i]);
+ m_out_bcs_cb(1);
- m_out_bcr_cb(1);
- m_out_bcr_cb(0);
+ LOGDATA("--> Transferring sector to buffer (lba = %08x)\n", get_lbasector());
- // save last read head and sector number
- m_drives[drive()].head = head();
- m_drives[drive()].sector = m_sector_number;
+ hard_disk_read(file, get_lbasector(), buffer);
- if (BIT(m_command, 2))
- {
- m_sector_number++;
- m_sector_count--;
- }
- else
- break;
- }
+ for (int i = 0; i < 512; i++)
+ m_out_data_cb(buffer[i]);
- end_command();
+ // multi-sector read
+ if (BIT(m_command, 2))
+ {
+ m_sector_number++;
+ m_sector_count--;
+ }
+ else
+ {
+ m_sector_count = 0;
}
+
+ if (m_sector_count == 0)
+ {
+ m_out_bcr_cb(1);
+ m_out_bcr_cb(0);
+ }
+
+ m_out_bcs_cb(0);
+
+ set_bdrq(1);
+
+ // interrupt at bdrq time?
+ if (BIT(m_command, 3) == 0)
+ set_intrq(1);
+
+ // now wait for brdy
+ m_read_timer->adjust(attotime::from_usec(35));
}
void wd1010_device::cmd_write_sector()
{
- if (!(m_status & STATUS_DRQ))
- {
- LOGDATA("Setting DATA REQUEST\n");
- m_status |= STATUS_DRQ;
- m_data_timer->adjust(attotime::from_usec(35));
- return;
- }
+ set_bdrq(1);
+ // wait if the buffer isn't ready
if (m_brdy == 0)
{
- m_data_timer->adjust(attotime::from_usec(35));
+ m_write_timer->adjust(attotime::from_usec(35));
return;
}
- LOGDATA("Clearing DATA REQUEST\n");
- m_status &= ~STATUS_DRQ;
-
hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file();
uint8_t buffer[512];
- while (m_sector_count > 0)
+ set_bdrq(0);
+
+ m_out_bcr_cb(1);
+ m_out_bcr_cb(0);
+
+ m_out_bcs_cb(1);
+
+ m_out_wg_cb(1);
+
+ if ((m_command >> 4) == CMD_WRITE_FORMAT)
{
- if ((m_command >> 4) == CMD_WRITE_FORMAT)
- {
- // we ignore the format specification and fill everything with 0xe5
- std::fill(std::begin(buffer), std::end(buffer), 0xe5);
- }
- else
- {
- // get data for sector from buffer chip
- for (int i = 0; i < 512; i++)
- buffer[i] = m_in_data_cb();
- }
+ // we ignore the format specification and fill everything with 0xe5
+ std::fill(std::begin(buffer), std::end(buffer), 0xe5);
+ }
+ else
+ {
+ // get data for sector from buffer chip
+ for (int i = 0; i < 512; i++)
+ buffer[i] = m_in_data_cb();
+ }
- hard_disk_write(file, get_lbasector(), buffer);
+ hard_disk_write(file, get_lbasector(), buffer);
- // save last read head and sector number
- m_drives[drive()].head = head();
- m_drives[drive()].sector = m_sector_number;
+ // save last read head and sector number
+ m_drives[drive()].head = head();
+ m_drives[drive()].sector = m_sector_number;
- if (BIT(m_command, 2))
+ // multi-sector write
+ if (BIT(m_command, 2) && m_sector_count > 0)
+ {
+ m_sector_number++;
+ m_sector_count--;
+
+ // schedule another run if we aren't finished yet
+ if (m_sector_count > 0)
{
- m_sector_number++;
- m_sector_count--;
+ m_out_bcs_cb(0);
+ m_out_wg_cb(0);
+ m_write_timer->adjust(attotime::from_usec(35));
+ return;
}
- else
- break;
}
+ m_out_bcs_cb(0);
+ m_out_wg_cb(0);
+
end_command();
}
diff --git a/src/devices/machine/wd1010.h b/src/devices/machine/wd1010.h
index b6a637c99e9..268ab3a63ca 100644
--- a/src/devices/machine/wd1010.h
+++ b/src/devices/machine/wd1010.h
@@ -27,7 +27,11 @@ public:
wd1010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto out_intrq_callback() { return m_out_intrq_cb.bind(); }
+ auto out_bdrq_callback() { return m_out_bdrq_cb.bind(); }
+ auto out_bcs_callback() { return m_out_bcs_cb.bind(); }
auto out_bcr_callback() { return m_out_bcr_cb.bind(); }
+ auto out_dirin_callback() { return m_out_dirin_cb.bind(); }
+ auto out_wg_callback() { return m_out_wg_cb.bind(); }
auto in_data_callback() { return m_in_data_cb.bind(); }
auto out_data_callback() { return m_out_data_cb.bind(); }
@@ -37,6 +41,10 @@ public:
void drdy_w(int state);
void brdy_w(int state);
+ // actually inputs to the controller from the drive
+ int sc_r();
+ int tk000_r();
+
protected:
// device-level overrides
virtual void device_start() override;
@@ -81,11 +89,13 @@ private:
enum
{
TIMER_SEEK,
- TIMER_DATA
+ TIMER_READ,
+ TIMER_WRITE
};
void set_error(int error);
void set_intrq(int state);
+ void set_bdrq(int state);
attotime get_stepping_rate();
void start_command();
void end_command();
@@ -107,7 +117,11 @@ private:
void cmd_seek();
devcb_write_line m_out_intrq_cb;
+ devcb_write_line m_out_bdrq_cb;
+ devcb_write_line m_out_bcs_cb;
devcb_write_line m_out_bcr_cb;
+ devcb_write_line m_out_dirin_cb;
+ devcb_write_line m_out_wg_cb;
devcb_read8 m_in_data_cb;
devcb_write8 m_out_data_cb;
@@ -120,9 +134,11 @@ private:
} m_drives[4];
emu_timer *m_seek_timer;
- emu_timer *m_data_timer;
+ emu_timer *m_read_timer;
+ emu_timer *m_write_timer;
int m_intrq;
+ //int m_bdrq;
int m_brdy;
uint8_t m_stepping_rate;
uint8_t m_command;
diff --git a/src/devices/machine/z80scc.cpp b/src/devices/machine/z80scc.cpp
index 0259fb5d0b0..e3a7c8a1d00 100644
--- a/src/devices/machine/z80scc.cpp
+++ b/src/devices/machine/z80scc.cpp
@@ -724,6 +724,7 @@ uint8_t z80scc_device::modify_vector(uint8_t vec, int i, uint8_t src)
// Modify vector according to Hi/lo bit of WR9
if (m_wr9 & WR9_BIT_SHSL) // Affect V4-V6
{
+ src = bitswap<4>(src, 3, 0, 1, 2); // order switched (see table above)
vec &= 0x8f;
vec |= src << 4;
}
diff --git a/src/devices/sound/2203intf.cpp b/src/devices/sound/2203intf.cpp
index 6b579f486a3..3a1a31d26a2 100644
--- a/src/devices/sound/2203intf.cpp
+++ b/src/devices/sound/2203intf.cpp
@@ -54,13 +54,12 @@ void ym2203_device::timer_handler(int c, int count, int clock)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// stream_generate - handle a stream update
//-------------------------------------------------
-
-void ym2203_device::stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym2203_device::stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym2203_update_one(m_chip, outputs[0], samples);
+ ym2203_update_one(m_chip, outputs[0]);
}
@@ -108,7 +107,7 @@ void ym2203_device::calculate_rates()
if (m_stream != nullptr)
m_stream->set_sample_rate(rate);
else
- m_stream = machine().sound().stream_alloc_legacy(*this,0,1,rate, stream_update_legacy_delegate(&ym2203_device::stream_generate,this));
+ m_stream = machine().sound().stream_alloc(*this,0,1,rate, stream_update_delegate(&ym2203_device::stream_generate,this), STREAM_DEFAULT_FLAGS);
}
//-------------------------------------------------
diff --git a/src/devices/sound/2203intf.h b/src/devices/sound/2203intf.h
index ccb5841cd82..df10125693a 100644
--- a/src/devices/sound/2203intf.h
+++ b/src/devices/sound/2203intf.h
@@ -39,7 +39,7 @@ protected:
virtual void device_clock_changed() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- void stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples);
+ void stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs);
private:
enum
diff --git a/src/devices/sound/2608intf.cpp b/src/devices/sound/2608intf.cpp
index 4ca366fa117..b746ae15e66 100644
--- a/src/devices/sound/2608intf.cpp
+++ b/src/devices/sound/2608intf.cpp
@@ -63,12 +63,12 @@ void ym2608_device::timer_handler(int c,int count,int clock)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// stream_generate - handle a stream update
//-------------------------------------------------
-void ym2608_device::stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym2608_device::stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym2608_update_one(m_chip, outputs, samples);
+ ym2608_update_one(m_chip, outputs);
}
void ym2608_device::device_post_load()
@@ -93,7 +93,7 @@ void ym2608_device::device_start()
m_timer[1] = timer_alloc(1);
/* stream system initialize */
- m_stream = machine().sound().stream_alloc_legacy(*this,0,2,rate, stream_update_legacy_delegate(&ym2608_device::stream_generate,this));
+ m_stream = machine().sound().stream_alloc(*this,0,2,rate, stream_update_delegate(&ym2608_device::stream_generate,this), STREAM_DEFAULT_FLAGS);
/* initialize YM2608 */
m_chip = ym2608_init(this,clock(),rate,
diff --git a/src/devices/sound/2608intf.h b/src/devices/sound/2608intf.h
index c6a3fec6fc9..ca1361ba867 100644
--- a/src/devices/sound/2608intf.h
+++ b/src/devices/sound/2608intf.h
@@ -39,7 +39,7 @@ protected:
virtual void rom_bank_updated() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- void stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples);
+ void stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs);
private:
void irq_handler(int irq);
diff --git a/src/devices/sound/2610intf.cpp b/src/devices/sound/2610intf.cpp
index 2f6e3e08620..b0ee9c99d32 100644
--- a/src/devices/sound/2610intf.cpp
+++ b/src/devices/sound/2610intf.cpp
@@ -62,20 +62,20 @@ void ym2610_device::timer_handler(int c,int count,int clock)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// stream_generate - handle a stream update
//-------------------------------------------------
-void ym2610_device::stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym2610_device::stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym2610_update_one(m_chip, outputs, samples);
+ ym2610_update_one(m_chip, outputs);
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// stream_generate - handle a stream update
//-------------------------------------------------
-void ym2610b_device::stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym2610b_device::stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym2610b_update_one(m_chip, outputs, samples);
+ ym2610b_update_one(m_chip, outputs);
}
@@ -102,7 +102,7 @@ void ym2610_device::device_start()
m_timer[1] = timer_alloc(1);
/* stream system initialize */
- m_stream = machine().sound().stream_alloc_legacy(*this,0,2,rate, stream_update_legacy_delegate(&ym2610_device::stream_generate,this));
+ m_stream = machine().sound().stream_alloc(*this,0,2,rate, stream_update_delegate(&ym2610_device::stream_generate,this), STREAM_DEFAULT_FLAGS);
if (!has_configured_map(0) && !has_configured_map(1))
{
diff --git a/src/devices/sound/2610intf.h b/src/devices/sound/2610intf.h
index a305f9d352d..9125feee4d6 100644
--- a/src/devices/sound/2610intf.h
+++ b/src/devices/sound/2610intf.h
@@ -40,7 +40,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples);
+ virtual void stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs);
void * m_chip;
@@ -75,7 +75,7 @@ public:
ym2610b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
- virtual void stream_generate(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void stream_generate(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
};
diff --git a/src/devices/sound/2612intf.cpp b/src/devices/sound/2612intf.cpp
index 679333cdcf3..b856ef33e65 100644
--- a/src/devices/sound/2612intf.cpp
+++ b/src/devices/sound/2612intf.cpp
@@ -56,12 +56,12 @@ void ym2612_device::timer_handler(int c,int count,int clock)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ym2612_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym2612_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym2612_update_one(m_chip, outputs, samples, m_output_bits);
+ ym2612_update_one(m_chip, outputs, m_output_bits);
}
@@ -87,7 +87,7 @@ void ym2612_device::device_start()
m_timer[1] = timer_alloc(1);
/* stream system initialize */
- m_stream = stream_alloc_legacy(0,2,rate);
+ m_stream = stream_alloc(0,2,rate);
/**** initialize YM2612 ****/
m_chip = ym2612_init(this,clock(),rate,&ym2612_device::static_timer_handler,&ym2612_device::static_irq_handler);
@@ -108,7 +108,7 @@ void ym2612_device::calculate_rates()
if (m_stream != nullptr)
m_stream->set_sample_rate(rate);
else
- m_stream = stream_alloc_legacy(0,2,rate);
+ m_stream = stream_alloc(0,2,rate);
}
//-------------------------------------------------
diff --git a/src/devices/sound/2612intf.h b/src/devices/sound/2612intf.h
index f9447081d9b..c88b83ffef5 100644
--- a/src/devices/sound/2612intf.h
+++ b/src/devices/sound/2612intf.h
@@ -33,7 +33,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
u8 m_output_bits;
private:
diff --git a/src/devices/sound/262intf.cpp b/src/devices/sound/262intf.cpp
index 0a76cdf6d2b..616cefc6377 100644
--- a/src/devices/sound/262intf.cpp
+++ b/src/devices/sound/262intf.cpp
@@ -50,12 +50,12 @@ void ymf262_device::timer_handler(int c, const attotime &period)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ymf262_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ymf262_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ymf262_update_one(m_chip, outputs, samples);
+ ymf262_update_one(m_chip, outputs);
}
//-------------------------------------------------
@@ -81,7 +81,7 @@ void ymf262_device::device_start()
if (!m_chip)
throw emu_fatalerror("ymf262_device(%s): Error creating YMF262 chip", tag());
- m_stream = stream_alloc_legacy(0,4,rate);
+ m_stream = stream_alloc(0,4,rate);
/* YMF262 setup */
ymf262_set_timer_handler (m_chip, &ymf262_device::static_timer_handler, this);
diff --git a/src/devices/sound/262intf.h b/src/devices/sound/262intf.h
index 09ae497748d..6c2376fc960 100644
--- a/src/devices/sound/262intf.h
+++ b/src/devices/sound/262intf.h
@@ -27,7 +27,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void irq_handler(int irq);
diff --git a/src/devices/sound/3526intf.cpp b/src/devices/sound/3526intf.cpp
index dce29c78440..906c3c3fd38 100644
--- a/src/devices/sound/3526intf.cpp
+++ b/src/devices/sound/3526intf.cpp
@@ -60,12 +60,12 @@ void ym3526_device::timer_handler(int c,const attotime &period)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ym3526_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym3526_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym3526_update_one(m_chip, outputs[0], samples);
+ ym3526_update_one(m_chip, outputs[0]);
}
@@ -109,7 +109,7 @@ void ym3526_device::calculate_rates()
if (m_stream != nullptr)
m_stream->set_sample_rate(rate);
else
- m_stream = stream_alloc_legacy(0,1,rate);
+ m_stream = stream_alloc(0,1,rate);
}
//-------------------------------------------------
diff --git a/src/devices/sound/3526intf.h b/src/devices/sound/3526intf.h
index 5b425f41241..a45825b57b5 100644
--- a/src/devices/sound/3526intf.h
+++ b/src/devices/sound/3526intf.h
@@ -32,7 +32,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void irq_handler(int irq);
diff --git a/src/devices/sound/3812intf.cpp b/src/devices/sound/3812intf.cpp
index b9287f21d9e..c74c75e27b0 100644
--- a/src/devices/sound/3812intf.cpp
+++ b/src/devices/sound/3812intf.cpp
@@ -62,12 +62,12 @@ void ym3812_device::timer_handler(int c, const attotime &period)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ym3812_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym3812_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- ym3812_update_one(m_chip, outputs[0], samples);
+ ym3812_update_one(m_chip, outputs[0]);
}
//-------------------------------------------------
@@ -110,7 +110,7 @@ void ym3812_device::calculate_rates()
if (m_stream != nullptr)
m_stream->set_sample_rate(rate);
else
- m_stream = stream_alloc_legacy(0, 1, rate);
+ m_stream = stream_alloc(0, 1, rate);
}
//-------------------------------------------------
diff --git a/src/devices/sound/3812intf.h b/src/devices/sound/3812intf.h
index 46266bbbca2..5b2b4f9991a 100644
--- a/src/devices/sound/3812intf.h
+++ b/src/devices/sound/3812intf.h
@@ -30,7 +30,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
enum
diff --git a/src/devices/sound/8950intf.cpp b/src/devices/sound/8950intf.cpp
index 63056582a0e..5eed79dd138 100644
--- a/src/devices/sound/8950intf.cpp
+++ b/src/devices/sound/8950intf.cpp
@@ -56,12 +56,12 @@ void y8950_device::timer_handler(int c, const attotime &period)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void y8950_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void y8950_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- y8950_update_one(m_chip, outputs[0], samples);
+ y8950_update_one(m_chip, outputs[0]);
}
@@ -87,7 +87,7 @@ void y8950_device::device_start()
/* ADPCM ROM data */
y8950_set_delta_t_memory(m_chip, &y8950_device::static_read_byte, &y8950_device::static_write_byte);
- m_stream = stream_alloc_legacy(0,1,rate);
+ m_stream = stream_alloc(0,1,rate);
/* port and keyboard handler */
y8950_set_port_handler(m_chip, &y8950_device::static_port_handler_w, &y8950_device::static_port_handler_r, this);
y8950_set_keyboard_handler(m_chip, &y8950_device::static_keyboard_handler_w, &y8950_device::static_keyboard_handler_r, this);
diff --git a/src/devices/sound/8950intf.h b/src/devices/sound/8950intf.h
index d1ba497c08d..9ed70e7cd92 100644
--- a/src/devices/sound/8950intf.h
+++ b/src/devices/sound/8950intf.h
@@ -41,7 +41,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void irq_handler(int irq);
diff --git a/src/devices/sound/aica.cpp b/src/devices/sound/aica.cpp
index 7bedf5d660a..21d5fa081d0 100644
--- a/src/devices/sound/aica.cpp
+++ b/src/devices/sound/aica.cpp
@@ -1233,7 +1233,6 @@ void aica_device::DoMasterSamples(std::vector<read_stream_view> const &inputs, w
{
int i;
- constexpr stream_buffer::sample_t sample_scale = 1.0 / stream_buffer::sample_t(32768 << SHIFT);
for (int s = 0; s < bufl.samples(); ++s)
{
s32 smpl = 0, smpr = 0;
@@ -1293,8 +1292,8 @@ void aica_device::DoMasterSamples(std::vector<read_stream_view> const &inputs, w
smpr = clip16(smpr >> 3);
}
- bufl.put(s, stream_buffer::sample_t(smpl * m_LPANTABLE[MVOL() << 0xd]) * sample_scale);
- bufr.put(s, stream_buffer::sample_t(smpr * m_LPANTABLE[MVOL() << 0xd]) * sample_scale);
+ bufl.put_int(s, smpl * m_LPANTABLE[MVOL() << 0xd], 32768 << SHIFT);
+ bufr.put_int(s, smpr * m_LPANTABLE[MVOL() << 0xd], 32768 << SHIFT);
}
}
diff --git a/src/devices/sound/asc.cpp b/src/devices/sound/asc.cpp
index e03494040ab..23ec35a2766 100644
--- a/src/devices/sound/asc.cpp
+++ b/src/devices/sound/asc.cpp
@@ -148,7 +148,6 @@ void asc_device::sound_stream_update(sound_stream &stream, std::vector<read_stre
case 1: // FIFO mode
{
- constexpr stream_buffer::sample_t sample_scale = 64.0 / 32768.0;
for (i = 0; i < outL.samples(); i++)
{
int8_t smpll, smplr;
@@ -234,15 +233,14 @@ void asc_device::sound_stream_update(sound_stream &stream, std::vector<read_stre
break;
}
- outL.put(i, stream_buffer::sample_t(smpll) * sample_scale);
- outR.put(i, stream_buffer::sample_t(smplr) * sample_scale);
+ outL.put_int(i, smpll, 32768 / 64);
+ outR.put_int(i, smplr, 32768 / 64);
}
break;
}
case 2: // wavetable mode
{
- constexpr stream_buffer::sample_t sample_scale = 1.0 / (32768.0 * 4.0);
for (i = 0; i < outL.samples(); i++)
{
int32_t mixL, mixR;
@@ -269,8 +267,8 @@ void asc_device::sound_stream_update(sound_stream &stream, std::vector<read_stre
mixR += smpl*256;
}
- outL.put(i, stream_buffer::sample_t(mixL) * sample_scale);
- outR.put(i, stream_buffer::sample_t(mixR) * sample_scale);
+ outL.put_int(i, mixL, 32768 * 4);
+ outR.put_int(i, mixR, 32768 * 4);
}
break;
}
diff --git a/src/devices/sound/astrocde.cpp b/src/devices/sound/astrocde.cpp
index 17df6999989..91d0fdc46b9 100644
--- a/src/devices/sound/astrocde.cpp
+++ b/src/devices/sound/astrocde.cpp
@@ -126,7 +126,7 @@ void astrocade_io_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
void astrocade_io_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
@@ -146,7 +146,7 @@ void astrocade_io_device::sound_stream_update(sound_stream &stream, std::vector<
constexpr stream_buffer::sample_t sample_scale = 1.0f / 60.0f;
for (int sampindex = 0; sampindex < dest.samples(); sampindex += samples_this_time)
{
- stream_sample_t cursample = 0;
+ s32 cursample = 0;
/* compute the number of cycles until the next master oscillator reset */
/* or until the next noise boundary */
diff --git a/src/devices/sound/awacs.cpp b/src/devices/sound/awacs.cpp
index 19f734cd468..72cf31d7589 100644
--- a/src/devices/sound/awacs.cpp
+++ b/src/devices/sound/awacs.cpp
@@ -93,13 +93,12 @@ void awacs_device::sound_stream_update(sound_stream &stream, std::vector<read_st
auto &outL = outputs[0];
auto &outR = outputs[1];
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
if (m_playback_enable)
{
for (int i = 0; i < outL.samples(); i++)
{
- outL.put(i, stream_buffer::sample_t(s16(m_dma_space->read_word(offset + m_play_ptr))) * sample_scale);
- outR.put(i, stream_buffer::sample_t(s16(m_dma_space->read_word(offset + m_play_ptr + 2))) * sample_scale);
+ outL.put_int(i, s16(m_dma_space->read_word(offset + m_play_ptr)), 32768);
+ outR.put_int(i, s16(m_dma_space->read_word(offset + m_play_ptr + 2)), 32768);
m_play_ptr += 4;
}
diff --git a/src/devices/sound/ay8910.cpp b/src/devices/sound/ay8910.cpp
index 26e99cf1bc7..8ba53fb8b3f 100644
--- a/src/devices/sound/ay8910.cpp
+++ b/src/devices/sound/ay8910.cpp
@@ -1108,12 +1108,13 @@ void ay8910_device::sound_stream_update(sound_stream &stream, std::vector<read_s
for (int chan = 0; chan < NUM_CHANNELS; chan++)
{
tone = &m_tone[chan];
- tone->count++;
- if (tone->count >= tone->period)
+ const int period = std::max<int>(1,tone->period);
+ tone->count += is_expanded_mode() ? 16 : 1;
+ while (tone->count >= period)
{
tone->duty_cycle = (tone->duty_cycle - 1) & 0x1f;
- tone->output = (m_feature & PSG_HAS_EXPANDED_MODE) ? BIT(duty_cycle[tone_duty(tone)], tone->duty_cycle) : BIT(tone->duty_cycle, 0);
- tone->count = 0;
+ tone->output = is_expanded_mode() ? BIT(duty_cycle[tone_duty(tone)], tone->duty_cycle) : BIT(tone->duty_cycle, 0);
+ tone->count -= period;
}
}
@@ -1124,8 +1125,9 @@ void ay8910_device::sound_stream_update(sound_stream &stream, std::vector<read_s
* channels.
*/
m_count_noise = 0;
+ m_prescale_noise ^= 1;
- if (!m_prescale_noise)
+ if (!m_prescale_noise || is_expanded_mode()) // AY8930 noise generator rate is twice compares as compatibility mode
{
/* The Random Number Generator of the 8910 is a 17-bit shift */
/* register. The input to the shift register is bit0 XOR bit3 */
@@ -1134,9 +1136,7 @@ void ay8910_device::sound_stream_update(sound_stream &stream, std::vector<read_s
// TODO : get actually algorithm for AY8930
m_rng ^= (((m_rng & 1) ^ ((m_rng >> 3) & 1)) << 17);
m_rng >>= 1;
- m_prescale_noise = (m_feature & PSG_HAS_EXPANDED_MODE) ? 16 : 1;
}
- m_prescale_noise--;
}
for (int chan = 0; chan < NUM_CHANNELS; chan++)
@@ -1336,7 +1336,7 @@ void ay8910_device::device_start()
/* The envelope is pacing twice as fast for the YM2149 as for the AY-3-8910, */
/* This handled by the step parameter. Consequently we use a multipler of 2 here. */
- m_channel = stream_alloc(0, m_streams, (m_feature & PSG_HAS_EXPANDED_MODE) ? master_clock * 2 : master_clock / 8);
+ m_channel = stream_alloc(0, m_streams, master_clock / 8);
ay_set_clock(master_clock);
ay8910_statesave();
@@ -1389,9 +1389,9 @@ void ay8910_device::ay_set_clock(int clock)
{
// FIXME: this doesn't belong here, it should be an input pin exposed via devcb
if (((m_feature & PSG_PIN26_IS_CLKSEL) && (m_flags & YM2149_PIN26_LOW)) || (m_feature & PSG_HAS_INTERNAL_DIVIDER))
- m_channel->set_sample_rate((m_feature & PSG_HAS_EXPANDED_MODE) ? clock : clock / 16);
+ m_channel->set_sample_rate(clock / 16);
else
- m_channel->set_sample_rate((m_feature & PSG_HAS_EXPANDED_MODE) ? clock * 2 : clock / 8);
+ m_channel->set_sample_rate(clock / 8);
}
void ay8910_device::device_clock_changed()
@@ -1659,8 +1659,6 @@ void ay8910_device::set_type(psg_type_t psg_type)
m_par = &ym2149_param;
m_par_env = &ym2149_param_env;
}
- if (m_feature & PSG_HAS_EXPANDED_MODE)
- m_step *= 16;
}
DEFINE_DEVICE_TYPE(AY8912, ay8912_device, "ay8912", "AY-3-8912A PSG")
diff --git a/src/devices/sound/ay8910.h b/src/devices/sound/ay8910.h
index 373a850b662..407de93f8a3 100644
--- a/src/devices/sound/ay8910.h
+++ b/src/devices/sound/ay8910.h
@@ -268,7 +268,7 @@ private:
inline u8 get_envelope_chan(int chan) { return is_expanded_mode() ? chan : 0; }
inline bool noise_enable(int chan) { return BIT(m_regs[AY_ENABLE], 3 + chan); }
- inline u8 noise_period() { return is_expanded_mode() ? m_regs[AY_NOISEPER] & 0xff : (m_regs[AY_NOISEPER] & 0x1f) << 1; }
+ inline u8 noise_period() { return is_expanded_mode() ? m_regs[AY_NOISEPER] & 0xff : m_regs[AY_NOISEPER] & 0x1f; }
inline u8 noise_output() { return m_rng & 1; }
inline bool is_expanded_mode() { return ((m_feature & PSG_HAS_EXPANDED_MODE) && ((m_mode & 0xe) == 0xa)); }
diff --git a/src/devices/sound/c140.cpp b/src/devices/sound/c140.cpp
index 0edb1920a8c..5d0b0811854 100644
--- a/src/devices/sound/c140.cpp
+++ b/src/devices/sound/c140.cpp
@@ -77,12 +77,6 @@ DEFINE_DEVICE_TYPE(C219, c219_device, "c219", "Namco C219")
// LIVE DEVICE
//**************************************************************************
-static inline stream_buffer::sample_t limit(stream_buffer::sample_t in)
-{
- return std::max(-1.0f, std::min(1.0f, in));
-}
-
-
//-------------------------------------------------
// c140_device - constructor
//-------------------------------------------------
@@ -326,15 +320,10 @@ void c140_device::sound_stream_update(sound_stream &stream, std::vector<read_str
{
auto &dest1 = outputs[0];
auto &dest2 = outputs[1];
- constexpr stream_buffer::sample_t sample_scale = 8.0 / 32768.0;
for (int i = 0; i < samples; i++)
{
- stream_buffer::sample_t val;
-
- val = stream_buffer::sample_t(*lmix++) * sample_scale;
- dest1.put(i, limit(val));
- val = stream_buffer::sample_t(*rmix++) * sample_scale;
- dest2.put(i, limit(val));
+ dest1.put_int_clamp(i, *lmix++, 32768 / 8);
+ dest2.put_int_clamp(i, *rmix++, 32768 / 8);
}
}
}
@@ -465,15 +454,10 @@ void c219_device::sound_stream_update(sound_stream &stream, std::vector<read_str
{
auto &dest1 = outputs[0];
auto &dest2 = outputs[1];
- constexpr stream_buffer::sample_t sample_scale = 8.0 / 32768.0;
for (int i = 0; i < samples; i++)
{
- stream_buffer::sample_t val;
-
- val = stream_buffer::sample_t(*lmix++) * sample_scale;
- dest1.put(i, limit(val));
- val = stream_buffer::sample_t(*rmix++) * sample_scale;
- dest2.put(i, limit(val));
+ dest1.put_int_clamp(i, *lmix++, 32768 / 8);
+ dest2.put_int_clamp(i, *rmix++, 32768 / 8);
}
}
}
diff --git a/src/devices/sound/c352.cpp b/src/devices/sound/c352.cpp
index 826f194437a..bea5a561b59 100644
--- a/src/devices/sound/c352.cpp
+++ b/src/devices/sound/c352.cpp
@@ -129,7 +129,6 @@ void c352_device::sound_stream_update(sound_stream &stream, std::vector<read_str
auto &buffer_rl = outputs[2];
auto &buffer_rr = outputs[3];
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for (int i = 0; i < buffer_fl.samples(); i++)
{
int out[4] = { 0, 0, 0, 0 };
@@ -174,10 +173,10 @@ void c352_device::sound_stream_update(sound_stream &stream, std::vector<read_str
out[3] += (((v.flags & C352_FLG_PHASEFR) ? -s : s) * v.curr_vol[3]) >> 8;
}
- buffer_fl.put(i, stream_buffer::sample_t(s16(out[0] >> 3)) * sample_scale);
- buffer_fr.put(i, stream_buffer::sample_t(s16(out[1] >> 3)) * sample_scale);
- buffer_rl.put(i, stream_buffer::sample_t(s16(out[2] >> 3)) * sample_scale);
- buffer_rr.put(i, stream_buffer::sample_t(s16(out[3] >> 3)) * sample_scale);
+ buffer_fl.put_int(i, s16(out[0] >> 3), 32768);
+ buffer_fr.put_int(i, s16(out[1] >> 3), 32768);
+ buffer_rl.put_int(i, s16(out[2] >> 3), 32768);
+ buffer_rr.put_int(i, s16(out[3] >> 3), 32768);
}
}
diff --git a/src/devices/sound/c6280.cpp b/src/devices/sound/c6280.cpp
index d01dd74125a..1b6666455c9 100644
--- a/src/devices/sound/c6280.cpp
+++ b/src/devices/sound/c6280.cpp
@@ -51,7 +51,6 @@ void c6280_device::sound_stream_update(sound_stream &stream, std::vector<read_st
outputs[0].fill(0);
outputs[1].fill(0);
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for (int ch = 0; ch < 6; ch++)
{
channel *chan = &m_channel[ch];
@@ -88,8 +87,8 @@ void c6280_device::sound_stream_update(sound_stream &stream, std::vector<read_st
// based on Charles MacDonald's research
chan->noise_seed = (seed >> 1) | ((BIT(seed, 0) ^ BIT(seed, 1) ^ BIT(seed, 11) ^ BIT(seed, 12) ^ BIT(seed, 17)) << 17);
}
- outputs[0].add(i, stream_buffer::sample_t(s16(vll * (data - 16))) * sample_scale);
- outputs[1].add(i, stream_buffer::sample_t(s16(vlr * (data - 16))) * sample_scale);
+ outputs[0].add_int(i, s16(vll * (data - 16)), 32768);
+ outputs[1].add_int(i, s16(vlr * (data - 16)), 32768);
}
}
else
@@ -98,8 +97,8 @@ void c6280_device::sound_stream_update(sound_stream &stream, std::vector<read_st
/* DDA mode */
for (int i = 0; i < outputs[0].samples(); i++)
{
- outputs[0].add(i, stream_buffer::sample_t(s16(vll * (chan->dda - 16))) * sample_scale);
- outputs[1].add(i, stream_buffer::sample_t(s16(vlr * (chan->dda - 16))) * sample_scale);
+ outputs[0].add_int(i, s16(vll * (chan->dda - 16)), 32768);
+ outputs[1].add_int(i, s16(vlr * (chan->dda - 16)), 32768);
}
}
else
@@ -138,8 +137,8 @@ void c6280_device::sound_stream_update(sound_stream &stream, std::vector<read_st
lfo_dstchan->tick = step;
lfo_dstchan->index = (lfo_dstchan->index + 1) & 0x1f;
}
- outputs[0].add(i, stream_buffer::sample_t(s16(vll * (data - 16))) * sample_scale);
- outputs[1].add(i, stream_buffer::sample_t(s16(vlr * (data - 16))) * sample_scale);
+ outputs[0].add_int(i, s16(vll * (data - 16)), 32768);
+ outputs[1].add_int(i, s16(vlr * (data - 16)), 32768);
}
}
}
@@ -156,8 +155,8 @@ void c6280_device::sound_stream_update(sound_stream &stream, std::vector<read_st
chan->tick = step;
chan->index = (chan->index + 1) & 0x1f;
}
- outputs[0].add(i, stream_buffer::sample_t(s16(vll * (data - 16))) * sample_scale);
- outputs[1].add(i, stream_buffer::sample_t(s16(vlr * (data - 16))) * sample_scale);
+ outputs[0].add_int(i, s16(vll * (data - 16)), 32768);
+ outputs[1].add_int(i, s16(vlr * (data - 16)), 32768);
}
}
}
diff --git a/src/devices/sound/cdda.cpp b/src/devices/sound/cdda.cpp
index ca2bd280de8..e208847510e 100644
--- a/src/devices/sound/cdda.cpp
+++ b/src/devices/sound/cdda.cpp
@@ -164,7 +164,6 @@ void cdda_device::get_audio_data(write_stream_view &bufL, write_stream_view &buf
int i;
int16_t *audio_cache = (int16_t *) m_audio_cache.get();
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for (int sampindex = 0; sampindex < bufL.samples(); )
{
/* if no file, audio not playing, audio paused, or out of disc data,
@@ -191,8 +190,8 @@ void cdda_device::get_audio_data(write_stream_view &bufL, write_stream_view &buf
for (i = 0; i < samples; i++)
{
/* CD-DA data on the disc is big-endian */
- bufL.put(sampindex + i, stream_buffer::sample_t(s16(big_endianize_int16( audio_cache[ m_audio_bptr ] ))) * sample_scale); m_audio_bptr++;
- bufR.put(sampindex + i, stream_buffer::sample_t(s16(big_endianize_int16( audio_cache[ m_audio_bptr ] ))) * sample_scale); m_audio_bptr++;
+ bufL.put_int(sampindex + i, s16(big_endianize_int16( audio_cache[ m_audio_bptr ] )), 32768); m_audio_bptr++;
+ bufR.put_int(sampindex + i, s16(big_endianize_int16( audio_cache[ m_audio_bptr ] )), 32768); m_audio_bptr++;
}
sampindex += samples;
diff --git a/src/devices/sound/cdp1864.cpp b/src/devices/sound/cdp1864.cpp
index e8168004811..f4a46748593 100644
--- a/src/devices/sound/cdp1864.cpp
+++ b/src/devices/sound/cdp1864.cpp
@@ -375,7 +375,7 @@ void cdp1864_device::dma_w(uint8_t data)
color = (gdata << 2) | (bdata << 1) | rdata;
}
- m_bitmap.pix32(y, sx + x) = m_palette[color];
+ m_bitmap.pix(y, sx + x) = m_palette[color];
data <<= 1;
}
diff --git a/src/devices/sound/cdp1869.cpp b/src/devices/sound/cdp1869.cpp
index 98580d7ae54..9e28aa4c048 100644
--- a/src/devices/sound/cdp1869.cpp
+++ b/src/devices/sound/cdp1869.cpp
@@ -574,29 +574,28 @@ void cdp1869_device::sound_stream_update(sound_stream &stream, std::vector<read_
void cdp1869_device::draw_line(bitmap_rgb32 &bitmap, const rectangle &rect, int x, int y, uint8_t data, int color)
{
- int i;
- pen_t fg = m_palette->pen(color);
+ pen_t const fg = m_palette->pen(color);
data <<= 2;
- for (i = 0; i < CH_WIDTH; i++)
+ for (int i = 0; i < CH_WIDTH; i++)
{
if (data & 0x80)
{
- bitmap.pix32(y, x) = fg;
+ bitmap.pix(y, x) = fg;
if (!m_fresvert)
{
- bitmap.pix32(y + 1, x) = fg;
+ bitmap.pix(y + 1, x) = fg;
}
if (!m_freshorz)
{
- bitmap.pix32(y, x + 1) = fg;
+ bitmap.pix(y, x + 1) = fg;
if (!m_fresvert)
{
- bitmap.pix32(y + 1, x + 1) = fg;
+ bitmap.pix(y + 1, x + 1) = fg;
}
}
}
diff --git a/src/devices/sound/cem3394.cpp b/src/devices/sound/cem3394.cpp
index 5b288d2d700..e0c74635648 100644
--- a/src/devices/sound/cem3394.cpp
+++ b/src/devices/sound/cem3394.cpp
@@ -4,12 +4,7 @@
Curtis Electromusic Specialties CEM3394 µP-Controllable Synthesizer Voice
- This driver handles CEM-3394 analog synth chip. Very crudely.
-
- Still to do:
- - adjust the overall volume when multiple waves are being generated
- - filter internal sound
- - support resonance (don't understand how it works)
+ This driver handles CEM-3394 analog synth chip.
***************************************************************************/
@@ -19,6 +14,18 @@
#include <algorithm>
+// various filter implementations to play with; currently SVTRAP works best
+#define FILTER_TYPE_NONE (0)
+#define FILTER_TYPE_SVTRAP (1)
+#define FILTER_TYPE_ESQ1 (2)
+
+#define FILTER_TYPE FILTER_TYPE_SVTRAP
+
+
+// logging
+#define LOG_CONTROL_CHANGES (0)
+
+
// use 0.25 as the base volume for pulses
static constexpr double PULSE_VOLUME = 0.25;
@@ -143,37 +150,96 @@ cem3394_device::cem3394_device(const machine_config &mconfig, const char *tag, d
m_pulse_width(0),
m_inv_sample_rate(1.0/48000.0)
{
+ (void)m_filter_in;
}
//-------------------------------------------------
-// sound_stream_update - generate sound to the mix
-// buffer in mono
+// filter - apply the lowpass filter at the given
+// cutoff frequency
//-------------------------------------------------
+#if (FILTER_TYPE == FILTER_TYPE_NONE)
+
+double cem3394_device::filter(double input, double cutoff)
+{
+ return input;
+}
+
+#elif (FILTER_TYPE == FILTER_TYPE_SVTRAP)
+
+double cem3394_device::filter(double input, double cutoff)
+{
+ // clamp cutoff to useful range, 50Hz-20kHz
+ cutoff = std::min(std::max(cutoff, 50.0), 20000.0);
+
+ // clamp resonance to below 1.0 to prevent runaway behavior; when clamping,
+ // also apply an (arbitrary) scale factor to the output since we're close
+ // to resonance and the datasheet indicates there is an amplitude correction
+ // in this case
+ double outscale = 1.0;
+ double res = m_filter_resonance;
+ if (res > 0.99)
+ res = 0.99, outscale = 0.5;
+
+ // core filter implementation
+ double g = tan(M_PI * cutoff * m_inv_sample_rate);
+ double k = 2.0 - 2.0 * res;
+ double a1 = 1.0 / (1.0 + g * (g + k));
+ double a2 = g * a1;
+ double a3 = g * a2;
+ double v3 = input - m_filter_out[1];
+ double v1 = a1 * m_filter_out[0] + a2 * v3;
+ double v2 = m_filter_out[1] + a2 * m_filter_out[0] + a3 * v3;
+ m_filter_out[0] = 2 * v1 - m_filter_out[0];
+ m_filter_out[1] = 2 * v2 - m_filter_out[1];
+
+ // lowpass output is equal to v2
+ double output = v2 * outscale;
+
+ // catch any NaNs
+ if (std::isnan(output))
+ {
+ logerror("NAN - vco: %6.0f cutoff: %6.0f res: %.5f output: %.5f\n", m_vco_step / m_inv_sample_rate, cutoff, m_filter_resonance, output);
+ output = 0;
+ m_filter_out[0] = m_filter_out[1] = 0;
+ }
+
+ // if we go out of range, scale down to 1.0 and also scale our
+ // feedback terms to help us stay in control
+ else if (fabs(output) > 1.0)
+ {
+ double scale = 1.0 / fabs(output);
+ output *= scale;
+ m_filter_out[0] *= scale;
+ m_filter_out[1] *= scale;
+ }
+ return output;
+}
+
+#elif (FILTER_TYPE == FILTER_TYPE_ESQ1)
+
double cem3394_device::filter(double input, double cutoff)
{
- // clamp cutoff to useful range, 20Hz-20kHz
- cutoff = std::max(std::min(cutoff, 20000.0), 20.0);
+ // clamp cutoff to useful range, 50Hz-20kHz
+ cutoff = std::min(std::max(cutoff, 50.0), 20000.0);
// clamp resonance to 0.95 to prevent infinite gain
- double r = 4.0 * std::min(m_filter_resonance, 0.95);
+ double r = 4.0 * std::min(res, 0.95);
+ // core filter implementation
double g = 2 * M_PI * cutoff;
double zc = g / tan(g/2 * m_inv_sample_rate);
-
double gzc = zc / g;
double gzc2 = gzc * gzc;
double gzc3 = gzc2 * gzc;
double gzc4 = gzc3 * gzc;
double r1 = 1 + r;
-
double a0 = r1;
double a1 = 4 * r1;
double a2 = 6 * r1;
double a3 = 4 * r1;
double a4 = r1;
-
double b0 = r1 + 4 * gzc + 6 * gzc2 + 4 * gzc3 + gzc4;
double b1 = 4 * (r1 + 2 * gzc - 2 * gzc3 - gzc4);
double b2 = 6 * (r1 - 2 * gzc2 + gzc4);
@@ -184,15 +250,18 @@ double cem3394_device::filter(double input, double cutoff)
+ m_filter_in[0] * a1 + m_filter_in[1] * a2 + m_filter_in[2] * a3 + m_filter_in[3] * a4
- m_filter_out[0] * b1 - m_filter_out[1] * b2 - m_filter_out[2] * b3 - m_filter_out[3] * b4) / b0;
-// sound_assert(!std::isnan(output));
-// sound_assert(output >= -1.5 && output <= 1.5);
- if (output < -1.5 || output > 1.5 || std::isnan(output))
+ // catch NaNs
+ if (std::isnan(output))
{
- if (m_filter_out[0] > -1.5 && m_filter_out[0] < 1.5)
- printf("cutoff: %6.0f res: %.5f output: %.5f\n", cutoff, m_filter_resonance, output);
+ logerror("NAN - vco: %6.0f cutoff: %6.0f res: %.5f output: %.5f\n", m_vco_step / m_inv_sample_rate, cutoff, m_filter_resonance, output);
+ output = 0;
}
- if (std::isnan(output)) output = 0;
+ // if output goes significantly out of range, scale it down
+ else if (fabs(output) > 10.0)
+ output = 10.0;
+
+ // update memories
m_filter_in[3] = m_filter_in[2];
m_filter_in[2] = m_filter_in[1];
m_filter_in[1] = m_filter_in[0];
@@ -203,6 +272,7 @@ double cem3394_device::filter(double input, double cutoff)
m_filter_out[1] = m_filter_out[0];
m_filter_out[0] = output;
+ // clamp to range and return
if (output < -1.0)
output = -1.0;
else if (output > 1.0)
@@ -210,6 +280,18 @@ double cem3394_device::filter(double input, double cutoff)
return output;
}
+#else
+
+#error Unknown FILTER_TYPE
+
+#endif
+
+
+//-------------------------------------------------
+// sound_stream_update - generate sound to the mix
+// buffer in mono
+//-------------------------------------------------
+
void cem3394_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
auto &external = inputs[0];
@@ -370,6 +452,7 @@ void cem3394_device::set_voltage(int input, double voltage)
case VCO_FREQUENCY:
temp = m_vco_zero_freq * pow(2.0, -voltage * (1.0 / 0.75));
m_vco_step = temp * m_inv_sample_rate;
+ if (LOG_CONTROL_CHANGES) logerror("VCO_FREQ=%6.3fV -> freq=%f\n", voltage, temp);
break;
// wave select determines triangle/sawtooth enable
@@ -381,6 +464,7 @@ void cem3394_device::set_voltage(int input, double voltage)
m_wave_select |= WAVE_TRIANGLE | WAVE_SAWTOOTH;
else if (voltage >= 2.3 && voltage <= 3.9)
m_wave_select |= WAVE_SAWTOOTH;
+ if (LOG_CONTROL_CHANGES) logerror("WAVE_SEL=%6.3fV -> tri=%d saw=%d\n", voltage, (m_wave_select & WAVE_TRIANGLE) ? 1 : 0, (m_wave_select & WAVE_SAWTOOTH) ? 1 : 0);
break;
// pulse width determines duty cycle; 0.0 means 0%, 2.0 means 100%
@@ -397,11 +481,13 @@ void cem3394_device::set_voltage(int input, double voltage)
m_pulse_width = MINIMUM_WIDTH + (MAXIMUM_WIDTH - MINIMUM_WIDTH) * m_pulse_width;
m_wave_select |= WAVE_PULSE;
}
+ if (LOG_CONTROL_CHANGES) logerror("PULSE_WI=%6.3fV -> raw=%f adj=%f\n", voltage, voltage * 0.5, m_pulse_width);
break;
// final gain is pretty self-explanatory; 0.0 means ~90dB, 4.0 means 0dB
case FINAL_GAIN:
m_volume = compute_db_volume(voltage);
+ if (LOG_CONTROL_CHANGES) logerror("TOT_GAIN=%6.3fV -> vol=%f\n", voltage, m_volume);
break;
// mixer balance is a pan between the external input and the internal input
@@ -417,11 +503,13 @@ void cem3394_device::set_voltage(int input, double voltage)
m_mixer_internal = compute_db_volume(3.55 - 0.45 * (voltage * 0.25));
m_mixer_external = compute_db_volume(3.55 + voltage);
}
+ if (LOG_CONTROL_CHANGES) logerror(" BALANCE=%6.3fV -> int=%f ext=%f\n", voltage, m_mixer_internal, m_mixer_external);
break;
// filter frequency varies from -3.0 to +4.0, at 0.375V/octave
case FILTER_FREQENCY:
m_filter_frequency = m_filter_zero_freq * pow(2.0, -voltage * (1.0 / 0.375));
+ if (LOG_CONTROL_CHANGES) logerror("FLT_FREQ=%6.3fV -> freq=%f\n", voltage, m_filter_frequency);
break;
// modulation depth is 0.01*freq at 0V and 2.0*freq at 3.5V
@@ -432,6 +520,7 @@ void cem3394_device::set_voltage(int input, double voltage)
m_filter_modulation = 1.99;
else
m_filter_modulation = (voltage * (1.0 / 3.5)) * 1.98 + 0.01;
+ if (LOG_CONTROL_CHANGES) logerror("FLT_MODU=%6.3fV -> mod=%f\n", voltage, m_filter_modulation);
break;
// this is not yet implemented
@@ -442,6 +531,7 @@ void cem3394_device::set_voltage(int input, double voltage)
m_filter_resonance = 1.0;
else
m_filter_resonance = voltage * (1.0 / 2.5);
+ if (LOG_CONTROL_CHANGES) logerror("FLT_RESO=%6.3fV -> mod=%f\n", voltage, m_filter_resonance);
break;
}
}
diff --git a/src/devices/sound/dac76.cpp b/src/devices/sound/dac76.cpp
index bbeb5728577..1c73d7b02c1 100644
--- a/src/devices/sound/dac76.cpp
+++ b/src/devices/sound/dac76.cpp
@@ -79,7 +79,7 @@ void dac76_device::sound_stream_update(sound_stream &stream, std::vector<read_st
{
// get current output level
int step_size = (2 << m_chord);
- stream_sample_t vout = m_level[m_chord] + m_step * step_size;
+ s32 vout = m_level[m_chord] + m_step * step_size;
// apply sign bit
vout *= (m_sb ? +1 : -1);
diff --git a/src/devices/sound/dave.cpp b/src/devices/sound/dave.cpp
index f26ea891879..b7f1487c025 100644
--- a/src/devices/sound/dave.cpp
+++ b/src/devices/sound/dave.cpp
@@ -205,7 +205,6 @@ void dave_device::sound_stream_update(sound_stream &stream, std::vector<read_str
auto &buffer1 = outputs[0];
auto &buffer2 = outputs[1];
- constexpr stream_buffer::sample_t sample_scale = 1.0 / (4.0 * 32768.0);
for (int sampindex = 0; sampindex < buffer1.samples(); sampindex++)
{
int vol[4];
@@ -264,8 +263,8 @@ void dave_device::sound_stream_update(sound_stream &stream, std::vector<read_str
left_volume = output_volumes[0] + output_volumes[2] + output_volumes[4] + output_volumes[6];
right_volume = output_volumes[1] + output_volumes[3] + output_volumes[5] + output_volumes[7];
- buffer1.put(sampindex, stream_buffer::sample_t(left_volume) * sample_scale);
- buffer2.put(sampindex, stream_buffer::sample_t(right_volume) * sample_scale);
+ buffer1.put_int(sampindex, left_volume, 32768 * 4);
+ buffer2.put_int(sampindex, right_volume, 32768 * 4);
}
}
diff --git a/src/devices/sound/digitalk.cpp b/src/devices/sound/digitalk.cpp
index 9ca0e6fa5f0..2bff98478e5 100644
--- a/src/devices/sound/digitalk.cpp
+++ b/src/devices/sound/digitalk.cpp
@@ -548,7 +548,6 @@ void digitalker_device::sound_stream_update(sound_stream &stream, std::vector<re
{
auto &sout = outputs[0];
int cpos = 0;
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
while(cpos != sout.samples()) {
if(m_zero_count == 0 && m_dac_index == 128)
digitalker_step();
@@ -563,10 +562,10 @@ void digitalker_device::sound_stream_update(sound_stream &stream, std::vector<re
} else if(m_dac_index != 128) {
while(cpos != sout.samples() && m_dac_index != 128) {
- stream_buffer::sample_t v = stream_buffer::sample_t(m_dac[m_dac_index]) * sample_scale;
+ s32 v = m_dac[m_dac_index];
int pp = m_pitch_pos;
while(cpos != sout.samples() && pp != m_pitch) {
- sout.put(cpos++, v);
+ sout.put_int(cpos++, v, 32768);
pp++;
}
if(pp == m_pitch) {
diff --git a/src/devices/sound/discrete.cpp b/src/devices/sound/discrete.cpp
index 7d6a84a4fc7..47e517af633 100644
--- a/src/devices/sound/discrete.cpp
+++ b/src/devices/sound/discrete.cpp
@@ -44,9 +44,6 @@
#include <iostream>
-/* for_each collides with c++ standard libraries - include it here */
-#define for_each(_T, _e, _l) for (_T _e = (_l)->begin_ptr() ; _e <= (_l)->end_ptr(); _e++)
-
// device type definition
DEFINE_DEVICE_TYPE(DISCRETE, discrete_sound_device, "discrete", "Discrete Sound")
@@ -93,7 +90,7 @@ DEFINE_DEVICE_TYPE(DISCRETE, discrete_sound_device, "discrete", "Discrete Sound"
struct output_buffer
{
- double *node_buf;
+ std::unique_ptr<double []> node_buf;
const double *source;
volatile double *ptr;
int node_num;
@@ -110,47 +107,44 @@ class discrete_task
{
friend class discrete_device;
public:
- virtual ~discrete_task(void) { }
+ virtual ~discrete_task() { }
- inline void step_nodes(void);
+ inline void step_nodes();
inline bool lock_threadid(int32_t threadid)
{
int expected = -1;
return m_threadid.compare_exchange_weak(expected, threadid, std::memory_order_release,std::memory_order_relaxed);
}
- inline void unlock(void) { m_threadid = -1; }
+ inline void unlock() { m_threadid = -1; }
//const linked_list_entry *list;
- node_step_list_t step_list;
+ discrete_device::node_step_list_t step_list;
/* list of source nodes */
- vector_t<input_buffer> source_list; /* discrete_source_node */
+ std::vector<input_buffer> source_list; /* discrete_source_node */
- int task_group;
+ int task_group = 0;
- discrete_task(discrete_device &pdev)
- : task_group(0), m_device(pdev), m_threadid(-1), m_samples(0)
-{
- source_list.clear();
- step_list.clear();
- m_buffers.clear();
+ discrete_task(discrete_device &pdev) : m_device(pdev), m_threadid(-1)
+ {
+ // FIXME: the code expects to be able to take pointers to members of elements of this vector before it's filled
+ source_list.reserve(16);
}
protected:
static void *task_callback(void *param, int threadid);
- inline bool process(void);
+ inline bool process();
- void check(discrete_task *dest_task);
+ void check(discrete_task &dest_task);
void prepare_for_queue(int samples);
- vector_t<output_buffer> m_buffers;
+ std::vector<output_buffer> m_buffers;
discrete_device & m_device;
private:
std::atomic<int32_t> m_threadid;
- volatile int m_samples;
-
+ volatile int m_samples = 0;
};
@@ -181,29 +175,27 @@ private:
*
*************************************/
-inline void discrete_task::step_nodes(void)
+inline void discrete_task::step_nodes()
{
- for_each(input_buffer *, sn, &source_list)
+ for (input_buffer &sn : source_list)
{
- sn->buffer = *sn->ptr++;
+ sn.buffer = *sn.ptr++;
}
if (EXPECTED(!m_device.profiling()))
{
- for_each(discrete_step_interface **, entry, &step_list)
+ for (discrete_step_interface *entry : step_list)
{
/* Now step the node */
- (*entry)->step();
+ entry->step();
}
}
else
{
osd_ticks_t last = get_profile_ticks();
- for_each(discrete_step_interface **, entry, &step_list)
+ for (discrete_step_interface *node : step_list)
{
- discrete_step_interface *node = *entry;
-
node->run_time -= last;
node->step();
last = get_profile_ticks();
@@ -212,23 +204,23 @@ inline void discrete_task::step_nodes(void)
}
/* buffer the outputs */
- for_each(output_buffer *, outbuf, &m_buffers)
- *(outbuf->ptr++) = *outbuf->source;
+ for (output_buffer &outbuf : m_buffers)
+ *outbuf.ptr++ = *outbuf.source;
}
void *discrete_task::task_callback(void *param, int threadid)
{
- task_list_t *list = (task_list_t *) param;
+ const auto &list = *reinterpret_cast<const discrete_sound_device::task_list_t *>(param);
do
{
- for_each(discrete_task **, task, list)
+ for (const auto &task : list)
{
/* try to lock */
- if ((*task)->lock_threadid(threadid))
+ if (task->lock_threadid(threadid))
{
- if (!(*task)->process())
+ if (!task->process())
return nullptr;
- (*task)->unlock();
+ task->unlock();
}
}
} while (1);
@@ -236,16 +228,14 @@ void *discrete_task::task_callback(void *param, int threadid)
return nullptr;
}
-bool discrete_task::process(void)
+bool discrete_task::process()
{
int samples = std::min(int(m_samples), MAX_SAMPLES_PER_TASK_SLICE);
/* check dependencies */
- for_each(input_buffer *, sn, &source_list)
+ for (input_buffer &sn : source_list)
{
- int avail;
-
- avail = sn->linked_outbuf->ptr - sn->ptr;
+ int avail = sn.linked_outbuf->ptr - sn.ptr;
if (avail < 0)
throw emu_fatalerror("discrete_task::process: available samples are negative");
if (avail < samples)
@@ -273,33 +263,35 @@ void discrete_task::prepare_for_queue(int samples)
{
m_samples = samples;
/* set up task buffers */
- for_each(output_buffer *, ob, &m_buffers)
- ob->ptr = ob->node_buf;
+ for (output_buffer &ob : m_buffers)
+ ob.ptr = ob.node_buf.get();
/* initialize sources */
- for_each(input_buffer *, sn, &source_list)
+ for (input_buffer &sn : source_list)
{
- sn->ptr = sn->linked_outbuf->node_buf;
+ sn.ptr = sn.linked_outbuf->node_buf.get();
}
}
-void discrete_task::check(discrete_task *dest_task)
+void discrete_task::check(discrete_task &dest_task)
{
- int inputnum;
+ // FIXME: this function takes addresses of elements of a vector that has items added later
+ // 16 is enough for the systems in MAME, but the code should be fixed properly
+ m_buffers.reserve(16);
/* Determine, which nodes in the task are referenced by nodes in dest_task
* and add them to the list of nodes to be buffered for further processing
*/
- for_each(discrete_step_interface **, node_entry, &step_list)
+ for (discrete_step_interface *node_entry : step_list)
{
- discrete_base_node *task_node = (*node_entry)->self;
+ discrete_base_node *task_node = node_entry->self;
- for_each(discrete_step_interface **, step_entry, &dest_task->step_list)
+ for (discrete_step_interface *step_entry : dest_task.step_list)
{
- discrete_base_node *dest_node = (*step_entry)->self;
+ discrete_base_node *dest_node = step_entry->self;
/* loop over all active inputs */
- for (inputnum = 0; inputnum < dest_node->active_inputs(); inputnum++)
+ for (int inputnum = 0; inputnum < dest_node->active_inputs(); inputnum++)
{
int inputnode_num = dest_node->input_node(inputnum);
if IS_VALUE_A_NODE(inputnode_num)
@@ -307,11 +299,10 @@ void discrete_task::check(discrete_task *dest_task)
/* Fixme: sub nodes ! */
if (NODE_DEFAULT_NODE(task_node->block_node()) == NODE_DEFAULT_NODE(inputnode_num))
{
- input_buffer source;
- int i, found = -1;
+ int found = -1;
output_buffer *pbuf = nullptr;
- for (i = 0; i < m_buffers.count(); i++)
+ for (int i = 0; i < m_buffers.size(); i++)
// if (m_buffers[i].node->block_node() == inputnode_num)
if (m_buffers[i].node_num == inputnode_num)
{
@@ -324,28 +315,20 @@ void discrete_task::check(discrete_task *dest_task)
{
output_buffer buf;
- buf.node_buf = auto_alloc_array(m_device.machine(), double,
- ((task_node->sample_rate() + sound_manager::STREAMS_UPDATE_FREQUENCY) / sound_manager::STREAMS_UPDATE_FREQUENCY));
- buf.ptr = buf.node_buf;
+ buf.node_buf = std::make_unique<double []>((task_node->sample_rate() + sound_manager::STREAMS_UPDATE_FREQUENCY) / sound_manager::STREAMS_UPDATE_FREQUENCY);
+ buf.ptr = buf.node_buf.get();
buf.source = dest_node->m_input[inputnum];
buf.node_num = inputnode_num;
//buf.node = device->discrete_find_node(inputnode);
- m_buffers.count();
- pbuf = m_buffers.add(buf);
+ m_buffers.push_back(std::move(buf));
+ pbuf = &m_buffers.back();
}
- m_device.discrete_log("dso_task_start - buffering %d(%d) in task %p group %d referenced by %d group %d", NODE_INDEX(inputnode_num), NODE_CHILD_NODE_NUM(inputnode_num), this, task_group, dest_node->index(), dest_task->task_group);
+ m_device.discrete_log("dso_task_start - buffering %d(%d) in task %p group %d referenced by %d group %d", NODE_INDEX(inputnode_num), NODE_CHILD_NODE_NUM(inputnode_num), this, task_group, dest_node->index(), dest_task.task_group);
/* register into source list */
- //source = auto_alloc(device->machine(), discrete_source_node);
- //source.task = this;
- //source.output_node = i;
- source.linked_outbuf = pbuf;
- source.buffer = 0.0; /* please compiler */
- source.ptr = nullptr;
- dest_task->source_list.add(source);
-
- /* point the input to a buffered location */
- dest_node->m_input[inputnum] = &dest_task->source_list[dest_task->source_list.count()-1].buffer; // was copied! &source.buffer;
+ dest_task.source_list.push_back(input_buffer{ nullptr, pbuf, 0.0 });
+ // FIXME: taking address of element of vector before it's filled
+ dest_node->m_input[inputnum] = &dest_task.source_list.back().buffer;
}
}
@@ -374,7 +357,7 @@ discrete_base_node::discrete_base_node() :
}
-discrete_base_node::~discrete_base_node(void)
+discrete_base_node::~discrete_base_node()
{
/* currently noting */
}
@@ -398,7 +381,7 @@ void discrete_base_node::init(discrete_device *pdev, const discrete_block *xbloc
}
}
-void discrete_base_node::save_state(void)
+void discrete_base_node::save_state()
{
if (m_block->node != NODE_SPECIAL)
m_device->save_item(NAME(m_output), m_block->node);
@@ -410,7 +393,7 @@ discrete_base_node *discrete_device::discrete_find_node(int node)
return m_indexed_node[NODE_INDEX(node)];
}
-void discrete_base_node::resolve_input_nodes(void)
+void discrete_base_node::resolve_input_nodes()
{
int inputnum;
@@ -520,7 +503,7 @@ void discrete_device::discrete_build_list(const discrete_block *intf, sound_bloc
if (intf[node_count].type == DSS_NULL)
fatalerror("discrete_build_list: DISCRETE_REPLACE at end of node_list\n");
- for (int i=0; i < block_list.count(); i++)
+ for (int i=0; i < block_list.size(); i++)
{
const discrete_block *block = block_list[i];
@@ -540,9 +523,9 @@ void discrete_device::discrete_build_list(const discrete_block *intf, sound_bloc
}
else if (intf[node_count].type == DSO_DELETE)
{
- vector_t<int> deletethem;
+ std::vector<int> deletethem;
- for (int i=0; i<block_list.count(); i++)
+ for (int i=0; i<block_list.size(); i++)
{
const discrete_block *block = block_list[i];
@@ -550,16 +533,16 @@ void discrete_device::discrete_build_list(const discrete_block *intf, sound_bloc
(block->node <= intf[node_count].input_node[1]))
{
discrete_log("discrete_build_list() - DISCRETE_DELETE deleted NODE_%02d", NODE_INDEX(block->node) );
- deletethem.add(i);
+ deletethem.push_back(i);
}
}
- for_each (int *, i, &deletethem)
- block_list.remove(*i);
+ for (int i : deletethem)
+ block_list.erase(block_list.begin() + i); // FIXME: how is this supposed to work if there's more than one item to remove? indices are shifted back on each removal
}
else
{
discrete_log("discrete_build_list() - adding node %d\n", node_count);
- block_list.add(&intf[node_count]);
+ block_list.push_back(&intf[node_count]);
}
node_count++;
@@ -575,7 +558,7 @@ void discrete_device::discrete_sanity_check(const sound_block_list_t &block_list
int node_count = 0;
discrete_log("discrete_start() - Doing node list sanity check");
- for (int i=0; i < block_list.count(); i++)
+ for (int i=0; i < block_list.size(); i++)
{
const discrete_block *block = block_list[i];
@@ -618,61 +601,60 @@ void discrete_device::discrete_sanity_check(const sound_block_list_t &block_list
*
*************************************/
-static uint64_t list_run_time(const node_list_t &list)
+static uint64_t list_run_time(const discrete_device::node_list_t &list)
{
uint64_t total = 0;
- for_each(discrete_base_node **, node, &list)
+ for (const auto &node : list)
{
discrete_step_interface *step;
- if ((*node)->interface(step))
+ if (node->interface(step))
total += step->run_time;
}
return total;
}
-static uint64_t step_list_run_time(const node_step_list_t &list)
+static uint64_t step_list_run_time(const discrete_device::node_step_list_t &list)
{
uint64_t total = 0;
- for_each(discrete_step_interface **, node, &list)
+ for (discrete_step_interface *node : list)
{
- total += (*node)->run_time;
+ total += node->run_time;
}
return total;
}
-void discrete_device::display_profiling(void)
+void discrete_device::display_profiling()
{
int count;
uint64_t total;
uint64_t tresh;
- double tt;
/* calculate total time */
total = list_run_time(m_node_list);
- count = m_node_list.count();
+ count = m_node_list.size();
/* print statistics */
- util::stream_format(std::cout, "Total Samples : %16d\n", m_total_samples);
+ osd_printf_info("Total Samples : %16d\n", m_total_samples);
tresh = total / count;
- util::stream_format(std::cout, "Threshold (mean): %16d\n", tresh / m_total_samples );
- for_each(discrete_base_node **, node, &m_node_list)
+ osd_printf_info("Threshold (mean): %16d\n", tresh / m_total_samples);
+ for (const auto &node : m_node_list)
{
discrete_step_interface *step;
- if ((*node)->interface(step))
+ if (node->interface(step))
if (step->run_time > tresh)
- util::stream_format(std::cout, "%3d: %20s %8.2f %10.2f\n", (*node)->index(), (*node)->module_name(), double(step->run_time) / double(total) * 100.0, double(step->run_time) / double(m_total_samples));
+ osd_printf_info("%3d: %20s %8.2f %10.2f\n", node->index(), node->module_name(), double(step->run_time) / double(total) * 100.0, double(step->run_time) / double(m_total_samples));
}
/* Task information */
- for_each(discrete_task **, task, &task_list)
+ for (const auto &task : task_list)
{
- tt = step_list_run_time((*task)->step_list);
+ double tt = step_list_run_time(task->step_list);
- util::stream_format(std::cout, "Task(%d): %8.2f %15.2f\n", (*task)->task_group, tt / double(total) * 100.0, tt / double(m_total_samples));
+ osd_printf_info("Task(%d): %8.2f %15.2f\n", task->task_group, tt / double(total) * 100.0, tt / double(m_total_samples));
}
- util::stream_format(std::cout, "Average samples/double->update: %8.2f\n", double(m_total_samples) / double(m_total_stream_updates));
+ osd_printf_info("Average samples/double->update: %8.2f\n", double(m_total_samples) / double(m_total_stream_updates));
}
@@ -687,15 +669,15 @@ void discrete_device::init_nodes(const sound_block_list_t &block_list)
{
discrete_task *task = nullptr;
/* list tail pointers */
- int has_tasks = 0;
+ bool has_tasks = false;
/* check whether we have tasks ... */
if (USE_DISCRETE_TASKS)
{
- for (int i = 0; i < block_list.count(); i++)
+ for (int i = 0; !has_tasks && (i < block_list.size()); i++)
{
if (block_list[i]->type == DSO_TASK_START)
- has_tasks = 1;
+ has_tasks = true;
}
}
@@ -704,21 +686,23 @@ void discrete_device::init_nodes(const sound_block_list_t &block_list)
/* make sure we have one simple task
* No need to create a node since there are no dependencies.
*/
- task = auto_alloc_clear(machine(), <discrete_task>(*this));
- task_list.add(task);
+ task_list.push_back(std::make_unique<discrete_task>(*this));
+ task = task_list.back().get();
}
/* loop over all nodes */
- for (int i = 0; i < block_list.count(); i++)
+ for (int i = 0; i < block_list.size(); i++)
{
- const discrete_block *block = block_list[i];
+ const discrete_block &block = *block_list[i];
+
+ // add to node list
+ m_node_list.push_back(block.factory(*this, block));
+ discrete_base_node &node = *m_node_list.back();
- //discrete_base_node *node = block->factory->Create(this, block);
- discrete_base_node *node = block->factory(this, block);
- /* keep track of special nodes */
- if (block->node == NODE_SPECIAL)
+ if (block.node == NODE_SPECIAL)
{
- switch(block->type)
+ // keep track of special nodes
+ switch (block.type)
{
/* Output Node */
case DSO_OUTPUT:
@@ -739,12 +723,12 @@ void discrete_device::init_nodes(const sound_block_list_t &block_list)
{
if (task != nullptr)
fatalerror("init_nodes() - Nested DISCRETE_START_TASK.\n");
- task = auto_alloc_clear(machine(), <discrete_task>(*this));
- task->task_group = block->initial[0];
+ task_list.push_back(std::make_unique<discrete_task>(*this));
+ task = task_list.back().get();
+ task->task_group = block.initial[0];
if (task->task_group < 0 || task->task_group >= DISCRETE_MAX_TASK_GROUPS)
fatalerror("discrete_dso_task: illegal task_group %d\n", task->task_group);
- //util::stream_format(std::cout, "task group %d\n", task->task_group);
- task_list.add(task);
+ //logerror("task group %d\n", task->task_group);
}
break;
@@ -760,37 +744,33 @@ void discrete_device::init_nodes(const sound_block_list_t &block_list)
fatalerror("init_nodes() - Failed, trying to create unknown special discrete node.\n");
}
}
-
- /* otherwise, make sure we are not a duplicate, and put ourselves into the indexed list */
else
{
- if (m_indexed_node[NODE_INDEX(block->node)])
- fatalerror("init_nodes() - Duplicate entries for NODE_%02d\n", NODE_INDEX(block->node));
- m_indexed_node[NODE_INDEX(block->node)] = node;
+ // otherwise, make sure we are not a duplicate, and put ourselves into the indexed list
+ if (m_indexed_node[NODE_INDEX(block.node)])
+ fatalerror("init_nodes() - Duplicate entries for NODE_%02d\n", NODE_INDEX(block.node));
+ m_indexed_node[NODE_INDEX(block.node)] = &node;
}
- /* add to node list */
- m_node_list.add(node);
-
- /* our running order just follows the order specified */
- /* does the node step ? */
+ // our running order just follows the order specified
+ // does the node step?
discrete_step_interface *step;
- if (node->interface(step))
+ if (node.interface(step))
{
/* do we belong to a task? */
if (task == nullptr)
- fatalerror("init_nodes() - found node outside of task: %s\n", node->module_name() );
+ fatalerror("init_nodes() - found node outside of task: %s\n", node.module_name());
else
- task->step_list.add(step);
+ task->step_list.push_back(step);
}
- if (USE_DISCRETE_TASKS && block->type == DSO_TASK_END)
+ if (USE_DISCRETE_TASKS && block.type == DSO_TASK_END)
{
task = nullptr;
}
/* and register save state */
- node->save_state();
+ node.save_state();
}
if (!has_tasks)
@@ -810,11 +790,11 @@ int discrete_device::same_module_index(const discrete_base_node &node)
{
int index = 0;
- for_each(discrete_base_node **, n, &m_node_list)
+ for (const auto &n : m_node_list)
{
- if (*n == &node)
+ if (n.get() == &node)
return index;
- if ((*n)->module_type() == node.module_type())
+ if (n->module_type() == node.module_type())
index++;
}
return -1;
@@ -851,7 +831,7 @@ discrete_sound_device::discrete_sound_device(const machine_config &mconfig, cons
{
}
-discrete_device::~discrete_device(void)
+discrete_device::~discrete_device()
{
}
@@ -862,7 +842,7 @@ discrete_device::~discrete_device(void)
void discrete_device::device_start()
{
// create the stream
- //m_stream = stream_alloc_legacy(0, 2, 22257);
+ //m_stream = stream_alloc(0, 2, 22257);
const discrete_block *intf_start = m_intf;
@@ -897,33 +877,33 @@ void discrete_device::device_start()
m_node_list.clear();
/* allocate memory to hold pointers to nodes by index */
- m_indexed_node = auto_alloc_array_clear(this->machine(), discrete_base_node *, DISCRETE_MAX_NODES);
+ m_indexed_node = make_unique_clear<discrete_base_node * []>(DISCRETE_MAX_NODES);
/* initialize the node data */
init_nodes(block_list);
/* now go back and find pointers to all input nodes */
- for_each(discrete_base_node **, node, &m_node_list)
+ for (const auto &node : m_node_list)
{
- (*node)->resolve_input_nodes();
+ node->resolve_input_nodes();
}
/* allocate a queue */
m_queue = osd_work_queue_alloc(WORK_QUEUE_FLAG_MULTI | WORK_QUEUE_FLAG_HIGH_FREQ);
/* Process nodes which have a start func */
- for_each(discrete_base_node **, node, &m_node_list)
+ for (const auto &node : m_node_list)
{
- (*node)->start();
+ node->start();
}
/* Now set up tasks */
- for_each(discrete_task **, task, &task_list)
+ for (const auto &task : task_list)
{
- for_each(discrete_task **, dest_task, &task_list)
+ for (const auto &dest_task : task_list)
{
- if ((*task)->task_group > (*dest_task)->task_group)
- (*dest_task)->check((*task));
+ if (task->task_group > dest_task->task_group)
+ dest_task->check(*task);
}
}
}
@@ -942,9 +922,9 @@ void discrete_device::device_stop()
/* Process nodes which have a stop func */
- for_each(discrete_base_node **, node, &m_node_list)
+ for (const auto &node : m_node_list)
{
- (*node)->stop();
+ node->stop();
}
if (DISCRETE_DEBUGLOG)
@@ -969,31 +949,31 @@ void discrete_sound_device::device_start()
discrete_device::device_start();
/* look for input stream nodes */
- for_each(discrete_base_node **, node, &m_node_list)
+ for (const auto &node : m_node_list)
{
/* if we are an stream input node, track that */
- discrete_dss_input_stream_node *input_stream = dynamic_cast<discrete_dss_input_stream_node *>(*node);
+ discrete_dss_input_stream_node *input_stream = dynamic_cast<discrete_dss_input_stream_node *>(node.get());
if (input_stream != nullptr)
{
- m_input_stream_list.add(input_stream);
+ m_input_stream_list.push_back(input_stream);
}
/* if this is an output interface, add it the output list */
discrete_sound_output_interface *out;
- if ((*node)->interface(out))
- m_output_list.add(out);
+ if (node->interface(out))
+ m_output_list.push_back(out);
}
/* if no outputs, give an error */
- if (m_output_list.count() == 0)
+ if (m_output_list.empty())
fatalerror("init_nodes() - Couldn't find an output node\n");
/* initialize the stream(s) */
- m_stream = stream_alloc(m_input_stream_list.count(), m_output_list.count(), m_sample_rate);
+ m_stream = stream_alloc(m_input_stream_list.size(), m_output_list.size(), m_sample_rate);
/* Finalize stream_input_nodes */
- for_each(discrete_dss_input_stream_node **, node, &m_input_stream_list)
+ for (discrete_dss_input_stream_node *node : m_input_stream_list)
{
- (*node)->stream_start();
+ node->stream_start();
}
@@ -1008,12 +988,12 @@ void discrete_device::device_reset()
update_to_current_time();
/* loop over all nodes */
- for_each (discrete_base_node **, node, &m_node_list)
+ for (const auto &node : m_node_list)
{
/* Fimxe : node_level */
- (*node)->m_output[0] = 0;
+ node->m_output[0] = 0;
- (*node)->reset();
+ node->reset();
}
}
@@ -1026,7 +1006,7 @@ void discrete_sound_device::device_reset()
// discrete_device_process - process a number of
// samples.
//
-// input / output buffers are stream_sample_t
+// input / output buffers are s32
// to not to have to convert the buffers.
// a "discrete cpu" device will pass nullptr here
//-------------------------------------------------
@@ -1037,18 +1017,19 @@ void discrete_device::process(int samples)
return;
/* Setup tasks */
- for_each(discrete_task **, task, &task_list)
+ for (const auto &task : task_list)
{
/* unlock the thread */
- (*task)->unlock();
+ task->unlock();
- (*task)->prepare_for_queue(samples);
+ task->prepare_for_queue(samples);
}
- for_each(discrete_task **, task, &task_list)
+ for (const auto &task : task_list)
{
/* Fire a work item for each task */
- osd_work_item_queue(m_queue, discrete_task::task_callback, (void *) &task_list, WORK_ITEM_FLAG_AUTO_RELEASE);
+ (void)task;
+ osd_work_item_queue(m_queue, discrete_task::task_callback, (void *)&task_list, WORK_ITEM_FLAG_AUTO_RELEASE);
}
osd_work_queue_wait(m_queue, osd_ticks_per_second()*10);
@@ -1060,7 +1041,7 @@ void discrete_device::process(int samples)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
@@ -1069,17 +1050,17 @@ void discrete_sound_device::sound_stream_update(sound_stream &stream, std::vecto
int outputnum = 0;
/* Setup any output streams */
- for_each(discrete_sound_output_interface **, node, &m_output_list)
+ for (discrete_sound_output_interface *node : m_output_list)
{
- (*node)->set_output_ptr(outputs[outputnum]);
+ node->set_output_ptr(outputs[outputnum]);
outputnum++;
}
/* Setup any input streams */
- for_each(discrete_dss_input_stream_node **, node, &m_input_stream_list)
+ for (discrete_dss_input_stream_node *node : m_input_stream_list)
{
- (*node)->m_inview = &inputs[(*node)->m_stream_in_number];
- (*node)->m_inview_sample = 0;
+ node->m_inview = &inputs[node->m_stream_in_number];
+ node->m_inview_sample = 0;
}
/* just process it */
diff --git a/src/devices/sound/discrete.h b/src/devices/sound/discrete.h
index 65879da211f..20d445959fa 100644
--- a/src/devices/sound/discrete.h
+++ b/src/devices/sound/discrete.h
@@ -7,6 +7,9 @@
#include "machine/rescap.h"
+#include <vector>
+
+
/***********************************************************************
*
* MAME - Discrete sound system emulation library
@@ -3745,88 +3748,6 @@ enum
*
*************************************/
-/*
- * add and delete may be slow - the focus is on access!
- */
-
- // TODO: replace with vector from utils
-template<class _ElementType> struct vector_t
-{
-public:
- vector_t(int initial) {
- m_count = 0;
- m_allocated = initial;
- m_arr = make_unique_clear<_ElementType[]>(m_allocated);
- }
- vector_t() {
- m_count = 0;
- m_allocated = 16;
- m_arr = make_unique_clear<_ElementType[]>(m_allocated);
- }
- ~vector_t() {
- m_arr = nullptr;
- }
- _ElementType& operator [] (unsigned int index) const // get array item
- {
- return m_arr[index];
- }
-
- vector_t(const vector_t &a) // copy constructor
- {
- m_allocated = a.count();
- if (m_allocated < 16)
- m_allocated = 16;
- m_count = a.count();
- m_arr = make_unique_clear<_ElementType[]>(m_allocated);
- for (int i=0; i < m_count; i++)
- m_arr[i] = a[i];
- }
- vector_t& operator = (const vector_t &a) // assignment operator
- {
- if (this == &a) return *this;
- m_allocated = a.count();
- if (m_allocated < 16)
- m_allocated = 16;
- m_count = a.count();
- m_arr = make_unique_clear<_ElementType[]>(m_allocated);
- for (int i=0; i < m_count; i++)
- m_arr[i] = a[i];
- return *this;
- }
-
- inline _ElementType* add(_ElementType object)
- {
- if (m_count >= m_allocated)
- {
- auto oldarr = make_unique_clear<_ElementType[]>(m_allocated);
- for (int i = 0; i < m_count; i++)
- oldarr[i] = m_arr[i];
-
- m_allocated *= 2;
- m_arr = make_unique_clear<_ElementType[]>(m_allocated);
- for (int i = 0; i < m_count; i++)
- m_arr[i] = oldarr[i];
- }
- m_arr[m_count] = object;
- m_count++;
- return &m_arr[m_count-1];
- }
- inline void remove(int index)
- {
- for (int i=index+1; i < m_count; i++)
- m_arr[i-1] = m_arr[i];
- m_count--;
- }
- inline void clear(void) { m_count = 0; }
- inline int count(void) const { return m_count; }
- inline _ElementType *begin_ptr(void) const { return m_arr.get(); }
- inline _ElementType *end_ptr(void) const { return m_arr.get() + (m_count - 1); }
-private:
- std::unique_ptr<_ElementType[]> m_arr;
- int m_count;
- int m_allocated;
-};
-
/*************************************
*
* Node-specific struct types
@@ -4180,14 +4101,10 @@ enum discrete_node_type
*************************************/
struct discrete_block;
-class discrete_node_base_factory;
class discrete_task;
class discrete_base_node;
class discrete_dss_input_stream_node;
class discrete_device;
-typedef vector_t<discrete_base_node *> node_list_t;
-typedef vector_t<discrete_dss_input_stream_node *> istream_node_list_t;
-typedef vector_t<discrete_task *> task_list_t;
/*************************************
@@ -4207,7 +4124,7 @@ typedef vector_t<discrete_task *> task_list_t;
struct discrete_block
{
int node; /* Output node number */
- discrete_base_node *(*factory)(discrete_device * pdev, const discrete_block *block);
+ std::unique_ptr<discrete_base_node> (*factory)(discrete_device &pdev, const discrete_block &block);
int type; /* see defines below */
int active_inputs; /* Number of active inputs on this node type */
int input_node[DISCRETE_MAX_INPUTS];/* input/control nodes */
@@ -4216,7 +4133,6 @@ struct discrete_block
const char * name; /* Node Name */
const char * mod_name; /* Module / class name */
};
-typedef vector_t<const discrete_block *> sound_block_list_t;
/*************************************
*
@@ -4229,11 +4145,10 @@ class discrete_step_interface
public:
virtual ~discrete_step_interface() { }
- virtual void step(void) = 0;
+ virtual void step() = 0;
osd_ticks_t run_time;
discrete_base_node * self;
};
-typedef vector_t<discrete_step_interface *> node_step_list_t;
class discrete_input_interface
{
@@ -4256,7 +4171,6 @@ public:
//**************************************************************************
class discrete_sound_output_interface;
-typedef vector_t<discrete_sound_output_interface *> node_output_list_t;
// ======================> discrete_device
@@ -4270,12 +4184,16 @@ protected:
discrete_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
public:
+ typedef std::vector<std::unique_ptr<discrete_task> > task_list_t;
+ typedef std::vector<std::unique_ptr<discrete_base_node> > node_list_t;
+ typedef std::vector<discrete_step_interface *> node_step_list_t;
+
// inline configuration helpers
void set_intf(const discrete_block *intf) { m_intf = intf; }
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
- virtual ~discrete_device(void);
+ virtual ~discrete_device();
template<int DiscreteInput>
DECLARE_WRITE_LINE_MEMBER(write_line)
@@ -4285,7 +4203,7 @@ public:
/* --------------------------------- */
- virtual void update_to_current_time(void) const { }
+ virtual void update_to_current_time() const { }
/* process a number of samples */
void process(int samples);
@@ -4303,14 +4221,13 @@ public:
discrete_base_node *discrete_find_node(int node);
/* are we profiling */
- inline int profiling(void) { return m_profiling; }
+ inline int profiling() { return m_profiling; }
- inline int sample_rate(void) { return m_sample_rate; }
- inline double sample_time(void) { return m_sample_time; }
+ inline int sample_rate() { return m_sample_rate; }
+ inline double sample_time() { return m_sample_time; }
protected:
-
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
@@ -4332,13 +4249,15 @@ protected:
node_list_t m_node_list; /* node_description * */
private:
+ typedef std::vector<const discrete_block *> sound_block_list_t;
+
void discrete_build_list(const discrete_block *intf, sound_block_list_t &block_list);
void discrete_sanity_check(const sound_block_list_t &block_list);
- void display_profiling(void);
+ void display_profiling();
void init_nodes(const sound_block_list_t &block_list);
/* internal node tracking */
- discrete_base_node ** m_indexed_node;
+ std::unique_ptr<discrete_base_node * []> m_indexed_node;
/* tasks */
task_list_t task_list; /* discrete_task_context * */
@@ -4373,13 +4292,13 @@ public:
set_intf(intf);
}
discrete_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
- virtual ~discrete_sound_device(void) { };
+ virtual ~discrete_sound_device() { };
/* --------------------------------- */
- virtual void update_to_current_time(void) const override { m_stream->update(); }
+ virtual void update_to_current_time() const override { m_stream->update(); }
- sound_stream *get_stream(void) { return m_stream; }
+ sound_stream *get_stream() { return m_stream; }
protected:
// device-level overrides
@@ -4390,6 +4309,9 @@ protected:
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
+ typedef std::vector<discrete_dss_input_stream_node *> istream_node_list_t;
+ typedef std::vector<discrete_sound_output_interface *> node_output_list_t;
+
/* the output stream */
sound_stream *m_stream;
@@ -4415,13 +4337,14 @@ class discrete_base_node
friend class discrete_task;
public:
+ virtual ~discrete_base_node();
- virtual void reset(void) { }
- virtual void start(void) { }
- virtual void stop(void) { }
- virtual void save_state(void);
+ virtual void reset() { }
+ virtual void start() { }
+ virtual void stop() { }
+ virtual void save_state();
- virtual int max_output(void) { return 1; };
+ virtual int max_output() { return 1; };
inline bool interface(discrete_step_interface *&intf) const { intf = m_step_intf; return (intf != nullptr); }
inline bool interface(discrete_input_interface *&intf) const { intf = m_input_intf; return (intf != nullptr); }
@@ -4434,36 +4357,35 @@ public:
inline void set_output(int n, double val) { m_output[n] = val; }
/* Return the node index, i.e. X from NODE(X) */
- inline int index(void) { return NODE_INDEX(m_block->node); }
+ inline int index() { return NODE_INDEX(m_block->node); }
/* Return the node number, i.e. NODE(X) */
- inline int block_node(void) const { return m_block->node; }
+ inline int block_node() const { return m_block->node; }
/* Custom function specific initialisation data */
- inline const void *custom_data(void) { return m_custom; }
+ inline const void *custom_data() { return m_custom; }
inline int input_node(int inputnum) { return m_block->input_node[inputnum]; }
/* Number of active inputs on this node type */
- inline int active_inputs(void) { return m_active_inputs; }
+ inline int active_inputs() { return m_active_inputs; }
/* Bit Flags. 1 in bit location means input_is_node */
- inline int input_is_node(void) { return m_input_is_node; }
+ inline int input_is_node() { return m_input_is_node; }
- inline double sample_time(void) { return m_device->sample_time(); }
- inline int sample_rate(void) { return m_device->sample_rate(); }
+ inline double sample_time() { return m_device->sample_time(); }
+ inline int sample_rate() { return m_device->sample_rate(); }
- const char * module_name(void) { return m_block->mod_name; }
- inline int module_type(void) const { return m_block->type; }
+ const char * module_name() { return m_block->mod_name; }
+ inline int module_type() const { return m_block->type; }
protected:
discrete_base_node();
- virtual ~discrete_base_node();
/* finish node setup after allocation is complete */
void init(discrete_device * pdev, const discrete_block *block);
- void resolve_input_nodes(void);
+ void resolve_input_nodes();
double m_output[DISCRETE_MAX_OUTPUTS]; /* The node's last output value */
const double * m_input[DISCRETE_MAX_INPUTS]; /* Addresses of Input values */
@@ -4482,28 +4404,18 @@ private:
discrete_sound_output_interface * m_output_intf;
};
-class discrete_node_base_factory
-{
-public:
- virtual discrete_base_node *Create(discrete_device * pdev, const discrete_block *block) = 0;
- virtual ~discrete_node_base_factory() {}
-};
-
template <class C>
-class discrete_node_factory : public discrete_node_base_factory
+class discrete_node_factory
{
public:
- discrete_base_node *Create(discrete_device * pdev, const discrete_block *block) override;
-};
-
-template <class C>
-discrete_base_node * discrete_node_factory<C>::Create(discrete_device * pdev, const discrete_block *block)
-{
- discrete_base_node *r = auto_alloc_clear(pdev->machine(), <C>());
+ static std::unique_ptr<discrete_base_node> create(discrete_device &pdev, const discrete_block &block)
+ {
+ std::unique_ptr<discrete_base_node> r = make_unique_clear<C>();
- r->init(pdev, block);
- return r;
-}
+ r->init(&pdev, &block);
+ return r;
+ }
+};
/*************************************
*
@@ -4520,16 +4432,10 @@ discrete_base_node * discrete_node_factory<C>::Create(discrete_device * pdev, co
*
*************************************/
-template <class C>
-discrete_base_node *discrete_create_node(discrete_device * pdev, const discrete_block *block)
-{
- return discrete_node_factory< C >().Create(pdev, block);
-}
-
#define DISCRETE_SOUND_EXTERN(name) extern const discrete_block name[]
#define DISCRETE_SOUND_START(name) const discrete_block name[] = {
//#define DSC_SND_ENTRY(_nod, _class, _dss, _num, _iact, _iinit, _custom, _name) { _nod, new discrete_node_factory< DISCRETE_CLASS_NAME(_class) >, _dss, _num, _iact, _iinit, _custom, _name, # _class }
-#define DSC_SND_ENTRY(_nod, _class, _dss, _num, _iact, _iinit, _custom, _name) { _nod, &discrete_create_node< DISCRETE_CLASS_NAME(_class) >, _dss, _num, _iact, _iinit, _custom, _name, # _class }
+#define DSC_SND_ENTRY(_nod, _class, _dss, _num, _iact, _iinit, _custom, _name) { _nod, &discrete_node_factory< DISCRETE_CLASS_NAME(_class) >::create, _dss, _num, _iact, _iinit, _custom, _name, # _class }
#define DISCRETE_SOUND_END DSC_SND_ENTRY( NODE_00, special, DSS_NULL , 0, DSE( NODE_NC ), DSE( 0 ) ,nullptr ,"DISCRETE_SOUND_END" ) };
diff --git a/src/devices/sound/dmadac.cpp b/src/devices/sound/dmadac.cpp
index b3a7d84bbf5..384449fca9b 100644
--- a/src/devices/sound/dmadac.cpp
+++ b/src/devices/sound/dmadac.cpp
@@ -232,7 +232,7 @@ dmadac_sound_device::dmadac_sound_device(const machine_config &mconfig, const ch
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
void dmadac_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
diff --git a/src/devices/sound/dspv.cpp b/src/devices/sound/dspv.cpp
index 7305c1c5298..cf14ead15d3 100644
--- a/src/devices/sound/dspv.cpp
+++ b/src/devices/sound/dspv.cpp
@@ -95,6 +95,7 @@ void dspv_device::snd_w(offs_t offset, u16 data)
void dspv_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
void dspv_device::device_start()
diff --git a/src/devices/sound/es1373.cpp b/src/devices/sound/es1373.cpp
index 9475b410f0b..1c707599188 100644
--- a/src/devices/sound/es1373.cpp
+++ b/src/devices/sound/es1373.cpp
@@ -120,7 +120,7 @@ void es1373_device::device_start()
add_map(0x40, M_IO, FUNC(es1373_device::map));
// create the stream
- m_stream = stream_alloc_legacy(0, 2, 44100/2);
+ m_stream = stream_alloc(0, 2, 44100/2);
m_timer = timer_alloc(0, nullptr);
m_timer->adjust(attotime::zero, 0, attotime::from_hz(44100/2/16));
@@ -230,24 +230,27 @@ void es1373_device::device_timer(emu_timer &timer, device_timer_id tid, int para
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void es1373_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void es1373_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
if (m_dac1.enable) {
- logerror("%s: sound_stream_update_legacy DAC1 not implemented yet\n", tag());
+ logerror("%s: sound_stream_update DAC1 not implemented yet\n", tag());
}
if (m_dac2.enable) {
- send_audio_out(m_dac2, ICSTATUS_DAC2_INT_MASK, outputs[0], outputs[1], samples);
+ send_audio_out(m_dac2, ICSTATUS_DAC2_INT_MASK, outputs[0], outputs[1]);
+ } else {
+ outputs[0].fill(0);
+ outputs[1].fill(0);
}
if (m_adc.enable) {
if (m_adc.format!=SCTRL_16BIT_MONO) {
- logerror("%s: sound_stream_update_legacy Only SCTRL_16BIT_MONO recorded supported\n", tag());
+ logerror("%s: sound_stream_update Only SCTRL_16BIT_MONO recorded supported\n", tag());
} else {
- for (int i=0; i<samples; i++) {
+ for (int i=0; i<outputs[0].samples(); i++) {
if (m_adc.buf_count<=m_adc.buf_size) {
if (LOG_ES)
logerror("%s: ADC buf_count: %i buf_size: %i buf_rptr: %i buf_wptr: %i\n", machine().describe_context(),
@@ -292,7 +295,7 @@ void es1373_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
//-------------------------------------------------
// send_audio_out - Sends channel audio output data
//-------------------------------------------------
-void es1373_device::send_audio_out(chan_info& chan, uint32_t intr_mask, stream_sample_t *outL, stream_sample_t *outR, int samples)
+void es1373_device::send_audio_out(chan_info& chan, uint32_t intr_mask, write_stream_view &outL, write_stream_view &outR)
{
// Only transfer PCI data if bus mastering is enabled
// Fill initial half buffer
@@ -303,8 +306,9 @@ void es1373_device::send_audio_out(chan_info& chan, uint32_t intr_mask, stream_s
//uint32_t sample_size = calc_size(chan.format);
// Send data to sound stream
bool buf_row_done;
- for (int i=0; i<samples; i++) {
+ for (int i=0; i<outL.samples(); i++) {
buf_row_done = false;
+ int16_t lsamp = 0, rsamp = 0;
if (chan.buf_count<=chan.buf_size) {
// Only transfer PCI data if bus mastering is enabled
// Fill half-buffer when read pointer is at start of next half
@@ -314,7 +318,7 @@ void es1373_device::send_audio_out(chan_info& chan, uint32_t intr_mask, stream_s
}
if (LOG_ES && i==0)
logerror("%s: chan: %X samples: %i buf_count: %X buf_size: %X buf_rptr: %X buf_wptr: %X\n",
- machine().describe_context(), chan.number, samples, chan.buf_count, chan.buf_size, chan.buf_rptr, chan.buf_wptr);
+ machine().describe_context(), chan.number, outL.samples(), chan.buf_count, chan.buf_size, chan.buf_rptr, chan.buf_wptr);
// Buffer is 4 bytes per location, need to switch on sample mode
switch (chan.format) {
case SCTRL_8BIT_MONO:
@@ -324,28 +328,28 @@ void es1373_device::send_audio_out(chan_info& chan, uint32_t intr_mask, stream_s
logerror("es1373_device::send_audio_out SCTRL_8BIT_STEREO not implemented yet\n");
break;
case SCTRL_16BIT_MONO:
- // The sound cache is 32 bit wide fifo, so each entry is two mono 16 bit samples
- if ((chan.buf_count&0x1)) {
- // Read high 16 bits
- outL[i] = outR[i] = (int16_t)(m_sound_cache[chan.buf_rptr]>>16);
- chan.buf_rptr++;
- buf_row_done = true;
- } else {
- // Read low 16 bits
- outL[i] = outR[i] = (int16_t)(m_sound_cache[chan.buf_rptr]&0xffff);
- }
- break;
- case SCTRL_16BIT_STEREO:
- // The sound cache is 32 bit wide fifo, so each entry is one stereo 16 bit sample
- outL[i] = (int16_t) m_sound_cache[chan.buf_rptr]&0xffff;
- outR[i] = (int16_t) m_sound_cache[chan.buf_rptr]>>16;
+ // The sound cache is 32 bit wide fifo, so each entry is two mono 16 bit samples
+ if ((chan.buf_count&0x1)) {
+ // Read high 16 bits
+ lsamp = rsamp = m_sound_cache[chan.buf_rptr]>>16;
chan.buf_rptr++;
buf_row_done = true;
+ } else {
+ // Read low 16 bits
+ lsamp = rsamp = m_sound_cache[chan.buf_rptr]&0xffff;
+ }
+ break;
+ case SCTRL_16BIT_STEREO:
+ // The sound cache is 32 bit wide fifo, so each entry is one stereo 16 bit sample
+ lsamp = m_sound_cache[chan.buf_rptr]&0xffff;
+ rsamp = m_sound_cache[chan.buf_rptr]>>16;
+ chan.buf_rptr++;
+ buf_row_done = true;
break;
}
if (LOG_ES_FILE && m_tempCount<1000000) {
m_tempCount++;
- //logerror("es1373_device::sound_stream_update_legacy count: %i samp16: %X\n", i, samp16);
+ //logerror("es1373_device::sound_stream_update count: %i samp16: %X\n", i, samp16);
//if (LOG_ES_FILE && m_eslog)
//fprintf(m_eslog, "%i\n", samp16);
}
@@ -368,10 +372,9 @@ void es1373_device::send_audio_out(chan_info& chan, uint32_t intr_mask, stream_s
if (buf_row_done && !(chan.buf_rptr&0xf)) {
chan.buf_rptr -= 0x10;
}
- } else {
- // Send zeros?
- outL[i] = outR[i] = 0;
}
+ outL.put_int(i, lsamp, 32768);
+ outR.put_int(i, rsamp, 32768);
}
}
diff --git a/src/devices/sound/es1373.h b/src/devices/sound/es1373.h
index 856d90d7af8..6e3cddb8a42 100644
--- a/src/devices/sound/es1373.h
+++ b/src/devices/sound/es1373.h
@@ -29,7 +29,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_post_load() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// Sound stream
sound_stream *m_stream;
@@ -55,7 +55,7 @@ private:
void transfer_pci_audio(chan_info& chan, int type);
uint32_t calc_size(const uint8_t &format);
- void send_audio_out(chan_info& chan, uint32_t intr_mask, stream_sample_t *outL, stream_sample_t *outR, int samples);
+ void send_audio_out(chan_info& chan, uint32_t intr_mask, write_stream_view &outL, write_stream_view &outR);
uint32_t m_tempCount;
emu_timer *m_timer;
diff --git a/src/devices/sound/es5503.cpp b/src/devices/sound/es5503.cpp
index 36fcaaf8af1..f22d11473fc 100644
--- a/src/devices/sound/es5503.cpp
+++ b/src/devices/sound/es5503.cpp
@@ -2,7 +2,7 @@
// copyright-holders:R. Belmont
/*
- ES5503 - Ensoniq ES5503 "DOC" emulator v2.1.1
+ ES5503 - Ensoniq ES5503 "DOC" emulator v2.1.2
By R. Belmont.
Copyright R. Belmont.
@@ -30,6 +30,9 @@
2.0 (RB) - C++ conversion, more accurate oscillator IRQ timing
2.1 (RB) - Corrected phase when looping; synthLAB, Arkanoid, and Arkanoid II no longer go out of tune
2.1.1 (RB) - Fixed issue introduced in 2.0 where IRQs were delayed
+ 2.1.2 (RB) - Fixed SoundSmith POLY.SYNTH inst where one-shot on the even oscillator and swap on the odd should loop.
+ Conversely, the intro voice in FTA Delta Demo has swap on the even and one-shot on the odd and doesn't
+ want to loop.
*/
#include "emu.h"
@@ -88,7 +91,8 @@ void es5503_device::halt_osc(int onum, int type, uint32_t *accumulator, int ress
{
ES5503Osc *pOsc = &oscillators[onum];
ES5503Osc *pPartner = &oscillators[onum^1];
- int mode = (pOsc->control>>1) & 3;
+ const int mode = (pOsc->control>>1) & 3;
+ const int partnerMode = (pPartner->control>>1) & 3;
// if 0 found in sample data or mode is not free-run, halt this oscillator
if ((mode != MODE_FREE) || (type != 0))
@@ -112,8 +116,9 @@ void es5503_device::halt_osc(int onum, int type, uint32_t *accumulator, int ress
*accumulator = altram << resshift;
}
- // if swap mode, start the partner
- if (mode == MODE_SWAP)
+ // if we're in swap mode or we're the even oscillator and the partner is in swap mode,
+ // start the partner.
+ if ((mode == MODE_SWAP) || ((partnerMode == MODE_SWAP) && ((onum & 1)==0)))
{
pPartner->control &= ~1; // clear the halt bit
pPartner->accumulator = 0; // and make sure it starts from the top (does this also need phase preservation?)
@@ -127,16 +132,15 @@ void es5503_device::halt_osc(int onum, int type, uint32_t *accumulator, int ress
m_irq_func(1);
}
}
-
-void es5503_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void es5503_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- static int32_t mix[(44100/60)*2*8];
int32_t *mixp;
int osc, snum, i;
uint32_t ramptr;
+ int samples = outputs[0].samples();
- assert(samples < (44100/60)*2);
- memset(mix, 0, sizeof(mix));
+ assert(samples < (44100/50));
+ std::fill_n(&m_mix_buffer[0], samples*output_channels, 0);
for (int chan = 0; chan < output_channels; chan++)
{
@@ -155,7 +159,7 @@ void es5503_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
int8_t data = -128;
int resshift = resshifts[pOsc->resolution] - pOsc->wavetblsize;
uint32_t sizemask = accmasks[pOsc->wavetblsize];
- mixp = &mix[0] + chan;
+ mixp = &m_mix_buffer[0] + chan;
for (snum = 0; snum < samples; snum++)
{
@@ -197,11 +201,14 @@ void es5503_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
}
}
}
-
- mixp = &mix[0];
- for (i = 0; i < samples; i++)
- for (int chan = 0; chan < output_channels; chan++)
- outputs[chan][i] = (*mixp++)>>3;
+ mixp = &m_mix_buffer[0];
+ for (int chan = 0; chan < output_channels; chan++)
+ {
+ for (i = 0; i < outputs[chan].samples(); i++)
+ {
+ outputs[chan].put_int(i, *mixp++, 32768*8);
+ }
+ }
}
@@ -224,7 +231,7 @@ void es5503_device::device_start()
save_pointer(STRUCT_MEMBER(oscillators, irqpend), 32);
output_rate = (clock() / 8) / (2 + oscsenabled);
- m_stream = stream_alloc_legacy(0, output_channels, output_rate);
+ m_stream = stream_alloc(0, output_channels, output_rate);
m_timer = timer_alloc(0, nullptr);
attotime update_rate = output_rate ? attotime::from_hz(output_rate) : attotime::never;
@@ -236,6 +243,8 @@ void es5503_device::device_clock_changed()
output_rate = (clock() / 8) / (2 + oscsenabled);
m_stream->set_sample_rate(output_rate);
+ m_mix_buffer.resize((output_rate/50)*8);
+
attotime update_rate = output_rate ? attotime::from_hz(output_rate) : attotime::never;
m_timer->adjust(update_rate, 0, update_rate);
}
@@ -388,12 +397,11 @@ void es5503_device::write(offs_t offset, u8 data)
break;
case 0xa0: // oscillator control
- // if a fresh key-on, reset the ccumulator
+ // if a fresh key-on, reset the accumulator
if ((oscillators[osc].control & 1) && (!(data&1)))
{
oscillators[osc].accumulator = 0;
}
-
oscillators[osc].control = data;
break;
@@ -427,6 +435,8 @@ void es5503_device::write(offs_t offset, u8 data)
output_rate = (clock()/8)/(2+oscsenabled);
m_stream->set_sample_rate(output_rate);
+ m_mix_buffer.resize((output_rate/50)*8);
+
attotime update_rate = output_rate ? attotime::from_hz(output_rate) : attotime::never;
m_timer->adjust(update_rate, 0, update_rate);
break;
diff --git a/src/devices/sound/es5503.h b/src/devices/sound/es5503.h
index 1483e91c8ac..2fd316aad8e 100644
--- a/src/devices/sound/es5503.h
+++ b/src/devices/sound/es5503.h
@@ -36,7 +36,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr) override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
@@ -84,6 +84,8 @@ private:
emu_timer *m_timer;
+ std::vector<int32_t> m_mix_buffer;
+
void halt_osc(int onum, int type, uint32_t *accumulator, int resshift);
};
diff --git a/src/devices/sound/es5506.cpp b/src/devices/sound/es5506.cpp
index b238409a1fa..3ea90a97261 100644
--- a/src/devices/sound/es5506.cpp
+++ b/src/devices/sound/es5506.cpp
@@ -106,7 +106,6 @@ static constexpr u32 FINE_FILTER_BIT = 16;
static constexpr u32 FILTER_BIT = 12;
static constexpr u32 FILTER_SHIFT = FINE_FILTER_BIT - FILTER_BIT;
-static constexpr u32 MAX_SAMPLE_CHUNK = 10000;
static constexpr u32 ULAW_MAXBITS = 8;
namespace {
@@ -163,9 +162,6 @@ es550x_device::es550x_device(const machine_config &mconfig, device_type type, co
, m_mode(0)
, m_irqv(0x80)
, m_voice_index(0)
- , m_scratch(nullptr)
- , m_ulaw_lookup(nullptr)
- , m_volume_lookup(nullptr)
#if ES5506_MAKE_WAVS
, m_wavraw(nullptr)
#endif
@@ -208,9 +204,6 @@ void es550x_device::device_start()
m_sample_rate_changed_cb.resolve();
m_irqv = 0x80;
- // allocate memory
- m_scratch = make_unique_clear<s32[]>(2 * MAX_SAMPLE_CHUNK);
-
// register save
save_item(NAME(m_sample_rate));
@@ -220,8 +213,6 @@ void es550x_device::device_start()
save_item(NAME(m_irqv));
save_item(NAME(m_voice_index));
- save_pointer(NAME(m_scratch), 2 * MAX_SAMPLE_CHUNK);
-
save_item(STRUCT_MEMBER(m_voice, control));
save_item(STRUCT_MEMBER(m_voice, freqcount));
save_item(STRUCT_MEMBER(m_voice, start));
@@ -249,7 +240,7 @@ void es5506_device::device_start()
channels = m_channels;
// create the stream
- m_stream = stream_alloc_legacy(0, 2 * channels, clock() / (16*32));
+ m_stream = stream_alloc(0, 2 * channels, clock() / (16*32));
// initialize the regions
if (m_region0 && !has_configured_map(0))
@@ -378,7 +369,7 @@ void es5505_device::device_start()
channels = m_channels;
// create the stream
- m_stream = stream_alloc_legacy(0, 2 * channels, clock() / (16*32));
+ m_stream = stream_alloc(0, 2 * channels, clock() / (16*32));
// initialize the regions
if (m_region0 && !has_configured_map(0))
@@ -455,7 +446,7 @@ void es550x_device::update_internal_irq_state()
void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 mantissa_bit)
{
// allocate ulaw lookup table
- m_ulaw_lookup = make_unique_clear<s16[]>(1 << ULAW_MAXBITS);
+ m_ulaw_lookup.resize(1 << ULAW_MAXBITS);
// generate ulaw lookup table
for (int i = 0; i < (1 << ULAW_MAXBITS); i++)
@@ -465,11 +456,11 @@ void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 m
u32 mantissa = (rawval << 3) & 0xffff;
if (exponent == 0)
- m_ulaw_lookup[i] = (s16)mantissa >> 7;
+ m_ulaw_lookup[i] = s16(mantissa) >> 7;
else
{
mantissa = (mantissa >> 1) | (~mantissa & 0x8000);
- m_ulaw_lookup[i] = (s16)mantissa >> (7 - exponent);
+ m_ulaw_lookup[i] = s16(mantissa) >> (7 - exponent);
}
}
@@ -477,7 +468,7 @@ void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 m
m_volume_shift = total_volume_bit - volume_bit;
const u32 volume_len = 1 << volume_bit;
// allocate volume lookup table
- m_volume_lookup = make_unique_clear<u32[]>(volume_len);
+ m_volume_lookup.resize(volume_len);
// generate volume lookup table
const u32 exponent_shift = 1 << exponent_bit;
@@ -831,7 +822,7 @@ inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u64 &accum
***********************************************************************************************/
-void es550x_device::generate_ulaw(es550x_voice *voice, s32 *lbuffer, s32 *rbuffer, int samples)
+void es550x_device::generate_ulaw(es550x_voice *voice, s32 *dest)
{
const u32 freqcount = voice->freqcount;
u64 accum = voice->accum & m_address_acc_mask;
@@ -862,8 +853,8 @@ void es550x_device::generate_ulaw(es550x_voice *voice, s32 *lbuffer, s32 *rbuffe
update_envelopes(voice);
// apply volumes and add
- *lbuffer += get_sample(val1, voice->lvol);
- *rbuffer += get_sample(val1, voice->rvol);
+ dest[0] += get_sample(val1, voice->lvol);
+ dest[1] += get_sample(val1, voice->rvol);
// check for loop end
check_for_end_forward(voice, accum);
@@ -892,8 +883,8 @@ void es550x_device::generate_ulaw(es550x_voice *voice, s32 *lbuffer, s32 *rbuffe
update_envelopes(voice);
// apply volumes and add
- *lbuffer += get_sample(val1, voice->lvol);
- *rbuffer += get_sample(val1, voice->rvol);
+ dest[0] += get_sample(val1, voice->lvol);
+ dest[1] += get_sample(val1, voice->rvol);
// check for loop end
check_for_end_reverse(voice, accum);
@@ -917,7 +908,7 @@ void es550x_device::generate_ulaw(es550x_voice *voice, s32 *lbuffer, s32 *rbuffe
***********************************************************************************************/
-void es550x_device::generate_pcm(es550x_voice *voice, s32 *lbuffer, s32 *rbuffer, int samples)
+void es550x_device::generate_pcm(es550x_voice *voice, s32 *dest)
{
const u32 freqcount = voice->freqcount;
u64 accum = voice->accum & m_address_acc_mask;
@@ -944,8 +935,8 @@ void es550x_device::generate_pcm(es550x_voice *voice, s32 *lbuffer, s32 *rbuffer
update_envelopes(voice);
// apply volumes and add
- *lbuffer += get_sample(val1, voice->lvol);
- *rbuffer += get_sample(val1, voice->rvol);
+ dest[0] += get_sample(val1, voice->lvol);
+ dest[1] += get_sample(val1, voice->rvol);
// check for loop end
check_for_end_forward(voice, accum);
@@ -970,8 +961,8 @@ void es550x_device::generate_pcm(es550x_voice *voice, s32 *lbuffer, s32 *rbuffer
update_envelopes(voice);
// apply volumes and add
- *lbuffer += get_sample(val1, voice->lvol);
- *rbuffer += get_sample(val1, voice->rvol);
+ dest[0] += get_sample(val1, voice->lvol);
+ dest[1] += get_sample(val1, voice->rvol);
// check for loop end
check_for_end_reverse(voice, accum);
@@ -1022,22 +1013,13 @@ inline void es550x_device::generate_irq(es550x_voice *voice, int v)
***********************************************************************************************/
-void es5506_device::generate_samples(s32 * const *outputs, int offset, int samples)
+void es5506_device::generate_samples(std::vector<write_stream_view> &outputs)
{
- // skip if nothing to do
- if (!samples)
- return;
-
- // clear out the accumulators
- for (int i = 0; i < m_channels << 1; i++)
- {
- memset(outputs[i] + offset, 0, sizeof(s32) * samples);
- }
-
// loop while we still have samples to generate
- while (samples)
+ for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
{
// loop over voices
+ s32 cursample[12] = { 0 };
for (int v = 0; v <= m_active_voices; v++)
{
es550x_voice *voice = &m_voice[v];
@@ -1049,40 +1031,29 @@ void es5506_device::generate_samples(s32 * const *outputs, int offset, int sampl
const int voice_channel = get_ca(voice->control);
const int channel = voice_channel % m_channels;
const int l = channel << 1;
- const int r = l + 1;
- s32 *left = outputs[l] + offset;
- s32 *right = outputs[r] + offset;
// generate from the appropriate source
if (voice->control & CONTROL_CMPD)
- generate_ulaw(voice, left, right, samples);
+ generate_ulaw(voice, &cursample[l]);
else
- generate_pcm(voice, left, right, samples);
+ generate_pcm(voice, &cursample[l]);
// does this voice have it's IRQ bit raised?
generate_irq(voice, v);
}
- offset++;
- samples--;
+
+ for (int c = 0; c < outputs.size(); c++)
+ outputs[c].put_int(sampindex, cursample[c], 32768);
}
}
-void es5505_device::generate_samples(s32 * const *outputs, int offset, int samples)
+void es5505_device::generate_samples(std::vector<write_stream_view> &outputs)
{
- // skip if nothing to do
- if (!samples)
- return;
-
- // clear out the accumulators
- for (int i = 0; i < m_channels << 1; i++)
- {
- memset(outputs[i] + offset, 0, sizeof(s32) * samples);
- }
-
// loop while we still have samples to generate
- while (samples)
+ for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
{
// loop over voices
+ s32 cursample[12] = { 0 };
for (int v = 0; v <= m_active_voices; v++)
{
es550x_voice *voice = &m_voice[v];
@@ -1100,19 +1071,17 @@ void es5505_device::generate_samples(s32 * const *outputs, int offset, int sampl
const int voice_channel = get_ca(voice->control);
const int channel = voice_channel % m_channels;
const int l = channel << 1;
- const int r = l + 1;
- s32 *left = outputs[l] + offset;
- s32 *right = outputs[r] + offset;
// generate from the appropriate source
// no compressed sample support
- generate_pcm(voice, left, right, samples);
+ generate_pcm(voice, &cursample[l]);
// does this voice have it's IRQ bit raised?
generate_irq(voice, v);
}
- offset++;
- samples--;
+
+ for (int c = 0; c < outputs.size(); c++)
+ outputs[c].put_int(sampindex, cursample[c], 32768);
}
}
@@ -2123,10 +2092,10 @@ u16 es5505_device::read(offs_t offset)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void es550x_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void es550x_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
#if ES5506_MAKE_WAVS
// start the logging once we have a sample rate
@@ -2138,39 +2107,30 @@ void es550x_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
#endif
// loop until all samples are output
- int offset = 0;
- while (samples)
- {
- int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples;
-
- generate_samples(outputs, offset, length);
+ generate_samples(outputs);
#if ES5506_MAKE_WAVS
- // log the raw data
- if (m_wavraw)
+ // log the raw data
+ if (m_wavraw)
+ {
+ // determine left/right source data
+
+ s32 *lsrc = m_scratch, *rsrc = m_scratch + length;
+ int channel;
+ memset(lsrc, 0, sizeof(s32) * length * 2);
+ // loop over the output channels
+ for (channel = 0; channel < m_channels; channel++)
{
- // determine left/right source data
- s32 *lsrc = m_scratch, *rsrc = m_scratch + length;
- int channel;
- memset(lsrc, 0, sizeof(s32) * length * 2);
- // loop over the output channels
- for (channel = 0; channel < m_channels; channel++)
+ s32 *l = outputs[(channel << 1)] + sampindex;
+ s32 *r = outputs[(channel << 1) + 1] + sampindex;
+ // add the current channel's samples to the WAV data
+ for (samp = 0; samp < length; samp++)
{
- s32 *l = outputs[(channel << 1)] + offset;
- s32 *r = outputs[(channel << 1) + 1] + offset;
- // add the current channel's samples to the WAV data
- for (samp = 0; samp < length; samp++)
- {
- lsrc[samp] += l[samp];
- rsrc[samp] += r[samp];
- }
+ lsrc[samp] += l[samp];
+ rsrc[samp] += r[samp];
}
- wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4);
}
-#endif
-
- // account for these samples
- offset += length;
- samples -= length;
+ wav_add_data_32lr(m_wavraw, lsrc, rsrc, length, 4);
}
+#endif
}
diff --git a/src/devices/sound/es5506.h b/src/devices/sound/es5506.h
index da438066ceb..4e45617c8b7 100644
--- a/src/devices/sound/es5506.h
+++ b/src/devices/sound/es5506.h
@@ -84,7 +84,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void update_irq_state();
void update_internal_irq_state();
@@ -111,10 +111,10 @@ protected:
virtual void update_envelopes(es550x_voice *voice) = 0;
virtual void check_for_end_forward(es550x_voice *voice, u64 &accum) = 0;
virtual void check_for_end_reverse(es550x_voice *voice, u64 &accum) = 0;
- void generate_ulaw(es550x_voice *voice, s32 *lbuffer, s32 *rbuffer, int samples);
- void generate_pcm(es550x_voice *voice, s32 *lbuffer, s32 *rbuffer, int samples);
+ void generate_ulaw(es550x_voice *voice, s32 *dest);
+ void generate_pcm(es550x_voice *voice, s32 *dest);
inline void generate_irq(es550x_voice *voice, int v);
- virtual void generate_samples(s32 * const *outputs, int offset, int samples) {};
+ virtual void generate_samples(std::vector<write_stream_view> &outputs) {};
inline void update_index(es550x_voice *voice) { m_voice_index = voice->index; }
virtual inline u16 read_sample(es550x_voice *voice, offs_t addr) { return 0; }
@@ -137,12 +137,11 @@ protected:
es550x_voice m_voice[32]; // the 32 voices
- std::unique_ptr<s32[]> m_scratch;
-
- std::unique_ptr<s16[]> m_ulaw_lookup;
- std::unique_ptr<u32[]> m_volume_lookup;
+ std::vector<s16> m_ulaw_lookup;
+ std::vector<u32> m_volume_lookup;
#if ES5506_MAKE_WAVS
+ std::vector<s32> m_scratch;
void * m_wavraw; // raw waveform
#endif
@@ -190,7 +189,7 @@ protected:
virtual void update_envelopes(es550x_voice *voice) override;
virtual void check_for_end_forward(es550x_voice *voice, u64 &accum) override;
virtual void check_for_end_reverse(es550x_voice *voice, u64 &accum) override;
- virtual void generate_samples(s32 * const *outputs, int offset, int samples) override;
+ virtual void generate_samples(std::vector<write_stream_view> &outputs) override;
virtual inline u16 read_sample(es550x_voice *voice, offs_t addr) override { update_index(voice); return m_cache[get_bank(voice->control)].read_word(addr); }
@@ -244,7 +243,7 @@ protected:
virtual void update_envelopes(es550x_voice *voice) override;
virtual void check_for_end_forward(es550x_voice *voice, u64 &accum) override;
virtual void check_for_end_reverse(es550x_voice *voice, u64 &accum) override;
- virtual void generate_samples(s32 * const *outputs, int offset, int samples) override;
+ virtual void generate_samples(std::vector<write_stream_view> &outputs) override;
virtual inline u16 read_sample(es550x_voice *voice, offs_t addr) override { update_index(voice); return m_cache[get_bank(voice->control)].read_word(addr); }
diff --git a/src/devices/sound/esqpump.cpp b/src/devices/sound/esqpump.cpp
index 7b37a2c9abd..bf34520869f 100644
--- a/src/devices/sound/esqpump.cpp
+++ b/src/devices/sound/esqpump.cpp
@@ -17,24 +17,18 @@ esq_5505_5510_pump_device::esq_5505_5510_pump_device(const machine_config &mconf
: device_t(mconfig, ESQ_5505_5510_PUMP, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, m_stream(nullptr)
- , m_timer(nullptr)
, m_esp(*this, finder_base::DUMMY_TAG)
, m_esp_halted(true)
, ticks_spent_processing(0)
, samples_processed(0)
{
-#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM
- e = nullptr;
-#endif
}
void esq_5505_5510_pump_device::device_start()
{
logerror("Clock = %d\n", clock());
- m_stream = stream_alloc_legacy(8, 2, clock());
- m_timer = timer_alloc(0);
- m_timer->enable(false);
+ m_stream = stream_alloc(8, 2, clock(), STREAM_SYNCHRONOUS);
#if PUMP_DETECT_SILENCE
silent_for = 500;
@@ -51,95 +45,79 @@ void esq_5505_5510_pump_device::device_start()
#endif
#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM
- e = make_unique_clear<int16_t[]>(0x4000);
+ e.resize(0x4000);
ei = 0;
#endif
}
-void esq_5505_5510_pump_device::device_stop()
-{
- m_timer->enable(false);
-}
-
-void esq_5505_5510_pump_device::device_reset()
-{
- m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
- m_timer->enable(true);
-}
-
void esq_5505_5510_pump_device::device_clock_changed()
{
m_stream->set_sample_rate(clock());
- m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock()));
}
-void esq_5505_5510_pump_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void esq_5505_5510_pump_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- if (samples != 1) {
- logerror("Pump: request for %d samples\n", samples);
- }
+ sound_assert(outputs[0].samples() == 1);
- stream_sample_t *left = outputs[0], *right = outputs[1];
- for (int i = 0; i < samples; i++)
- {
+ auto &left = outputs[0];
+ auto &right = outputs[1];
#define SAMPLE_SHIFT 4
- // anything for the 'aux' output?
- int16_t l = inputs[0][i] >> SAMPLE_SHIFT;
- int16_t r = inputs[1][i] >> SAMPLE_SHIFT;
-
- // push the samples into the ESP
- m_esp->ser_w(0, inputs[2][i] >> SAMPLE_SHIFT);
- m_esp->ser_w(1, inputs[3][i] >> SAMPLE_SHIFT);
- m_esp->ser_w(2, inputs[4][i] >> SAMPLE_SHIFT);
- m_esp->ser_w(3, inputs[5][i] >> SAMPLE_SHIFT);
- m_esp->ser_w(4, inputs[6][i] >> SAMPLE_SHIFT);
- m_esp->ser_w(5, inputs[7][i] >> SAMPLE_SHIFT);
+ constexpr stream_buffer::sample_t input_scale = 32768.0 / (1 << SAMPLE_SHIFT);
+
+ // anything for the 'aux' output?
+ stream_buffer::sample_t l = inputs[0].get(0) * (1.0 / (1 << SAMPLE_SHIFT));
+ stream_buffer::sample_t r = inputs[1].get(0) * (1.0 / (1 << SAMPLE_SHIFT));
+
+ // push the samples into the ESP
+ m_esp->ser_w(0, s32(inputs[2].get(0) * input_scale));
+ m_esp->ser_w(1, s32(inputs[3].get(0) * input_scale));
+ m_esp->ser_w(2, s32(inputs[4].get(0) * input_scale));
+ m_esp->ser_w(3, s32(inputs[5].get(0) * input_scale));
+ m_esp->ser_w(4, s32(inputs[6].get(0) * input_scale));
+ m_esp->ser_w(5, s32(inputs[7].get(0) * input_scale));
#if PUMP_FAKE_ESP_PROCESSING
- m_esp->ser_w(6, m_esp->ser_r(0) + m_esp->ser_r(2) + m_esp->ser_r(4));
- m_esp->ser_w(7, m_esp->ser_r(1) + m_esp->ser_r(3) + m_esp->ser_r(5));
+ m_esp->ser_w(6, m_esp->ser_r(0) + m_esp->ser_r(2) + m_esp->ser_r(4));
+ m_esp->ser_w(7, m_esp->ser_r(1) + m_esp->ser_r(3) + m_esp->ser_r(5));
#else
- if (!m_esp_halted) {
- logerror("passing one sample through ESP\n");
- osd_ticks_t a = osd_ticks();
- m_esp->run_once();
- osd_ticks_t b = osd_ticks();
- ticks_spent_processing += (b - a);
- samples_processed++;
- }
+ if (!m_esp_halted) {
+ logerror("passing one sample through ESP\n");
+ osd_ticks_t a = osd_ticks();
+ m_esp->run_once();
+ osd_ticks_t b = osd_ticks();
+ ticks_spent_processing += (b - a);
+ samples_processed++;
+ }
#endif
- // read the processed result from the ESP and add to the saved AUX data
- int16_t ll = m_esp->ser_r(6);
- int16_t rr = m_esp->ser_r(7);
- l += ll;
- r += rr;
+ // read the processed result from the ESP and add to the saved AUX data
+ stream_buffer::sample_t ll = stream_buffer::sample_t(m_esp->ser_r(6)) * (1.0 / 32768.0);
+ stream_buffer::sample_t rr = stream_buffer::sample_t(m_esp->ser_r(7)) * (1.0 / 32768.0);
+ l += ll;
+ r += rr;
#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM
- // if we're processing the fake program through the ESP, the result should just be that of adding the inputs
- int32_t el = (inputs[2][i]) + (inputs[4][i]) + (inputs[6][i]);
- int32_t er = (inputs[3][i]) + (inputs[5][i]) + (inputs[7][i]);
- int32_t e_next = el + er;
- e[(ei + 0x1d0f) % 0x4000] = e_next;
-
- if (l != e[ei]) {
- util::stream_format(std::cerr, "expected (%d) but have (%d)\n", e[ei], l);
- }
- ei = (ei + 1) % 0x4000;
+ // if we're processing the fake program through the ESP, the result should just be that of adding the inputs
+ stream_buffer::sample_t el = (inputs[2].get(0)) + (inputs[4].get(0)) + (inputs[6].get(0));
+ stream_buffer::sample_t er = (inputs[3].get(0)) + (inputs[5].get(0)) + (inputs[7].get(0));
+ stream_buffer::sample_t e_next = el + er;
+ e[(ei + 0x1d0f) % 0x4000] = e_next;
+
+ if (fabs(l - e[ei]) > 1e-5) {
+ util::stream_format(std::cerr, "expected (%d) but have (%d)\n", e[ei], l);
+ }
+ ei = (ei + 1) % 0x4000;
#endif
- // write the combined data to the output
- *left++ = l;
- *right++ = r;
- }
+ // write the combined data to the output
+ left.put(0, l);
+ right.put(0, r);
#if PUMP_DETECT_SILENCE
- for (int i = 0; i < samples; i++) {
- if (outputs[0][i] == 0 && outputs[1][i] == 0) {
- silent_for++;
- } else {
- silent_for = 0;
- }
+ if (left.get(0) == 0 && right.get(0) == 0) {
+ silent_for++;
+ } else {
+ silent_for = 0;
}
bool silence = silent_for >= 500;
if (was_silence != silence) {
@@ -174,8 +152,3 @@ void esq_5505_5510_pump_device::sound_stream_update_legacy(sound_stream &stream,
}
#endif
}
-
-void esq_5505_5510_pump_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) {
- // ecery time there's a new sample period, update the stream!
- m_stream->update();
-}
diff --git a/src/devices/sound/esqpump.h b/src/devices/sound/esqpump.h
index a4fb62b60ff..897475cd8b4 100644
--- a/src/devices/sound/esqpump.h
+++ b/src/devices/sound/esqpump.h
@@ -70,24 +70,16 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void device_stop() override;
- virtual void device_reset() override;
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
-
- // timer callback overrides
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// internal state:
// sound stream
sound_stream *m_stream;
- // per-sample timer
- emu_timer *m_timer;
-
// ESP signal processor
required_device<es5510_device> m_esp;
@@ -111,7 +103,7 @@ private:
#endif
#if !PUMP_FAKE_ESP_PROCESSING && PUMP_REPLACE_ESP_PROGRAM
- std::unique_ptr<int16_t[]> e;
+ std::vector<stream_buffer::sample_t> e;
int ei;
#endif
};
diff --git a/src/devices/sound/flt_biquad.cpp b/src/devices/sound/flt_biquad.cpp
new file mode 100644
index 00000000000..a0416bfafb1
--- /dev/null
+++ b/src/devices/sound/flt_biquad.cpp
@@ -0,0 +1,487 @@
+// license:BSD-3-Clause
+// copyright-holders:K.Wilkins,Couriersud,Derrick Renaud,Frank Palazzolo,Jonathan Gevaryahu
+/*
+ This is an implementation of a Direct-form II digital biquad filter,
+ intended for use in audio paths for filtering audio to or from other
+ stream devices.
+
+ It has a number of constructor-helpers for automatically generating
+ a biquad filter equivalent to the filter response of a few standard
+ analog second order filter topographies.
+
+ This biquad filter implementation is based on one written by Frank
+ Palazzolo, K. Wilkins, Couriersud, and Derrick Renaud, with some changes:
+ * It uses the Q factor directly in the filter definitions, rather than the damping factor (1/Q)
+ * It implements every common type of digital biquad filter which I could find documentation for.
+ * The filter is Direct-form II instead of Direct-form I, which results in shorter compiled code.
+
+ Possibly useful features which aren't implemented because nothing uses them yet:
+ * More Sallen-Key filter variations (band-pass, high-pass)
+ * Direct control of the 5 normalized biquad parameters for a custom/raw parameter filter.
+*/
+#include "emu.h"
+#include "flt_biquad.h"
+
+// we need the M_SQRT2 constant
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+
+// define this to display debug info about the filters being set up
+#undef FLT_BIQUAD_DEBUG_SETUP
+
+// device type definition
+DEFINE_DEVICE_TYPE(FILTER_BIQUAD, filter_biquad_device, "filter_biquad", "Biquad Filter")
+
+// allow the enum class for the biquad filter type to be saved by the savestate system
+ALLOW_SAVE_TYPE(filter_biquad_device::biquad_type);
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// filter_biquad_device - constructor
+//-------------------------------------------------
+
+// initialize with some sane defaults for a highpass filter with a cutoff at 16hz, same as flt_rc's 'ac' mode.
+filter_biquad_device::filter_biquad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, FILTER_BIQUAD, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ m_stream(nullptr),
+ m_type(biquad_type::HIGHPASS),
+ m_last_sample_rate(0),
+ m_fc(16.0),
+ m_q(M_SQRT2/2.0),
+ m_gain(1.0),
+ m_input(0.0),
+ m_w0(0.0),
+ m_w1(0.0),
+ m_w2(0.0),
+ m_output(0.0),
+ m_a1(0.0),
+ m_a2(0.0),
+ m_b0(1.0),
+ m_b1(0.0),
+ m_b2(0.0)
+{
+}
+
+// set up the filter with the specified parameters and return a pointer to the new device
+filter_biquad_device& filter_biquad_device::setup(biquad_type type, double fc, double q, double gain)
+{
+ m_type = type;
+ m_fc = fc;
+ m_q = q;
+ m_gain = gain;
+ return *this;
+}
+
+// update an existing instance with new filter parameters
+void filter_biquad_device::update_params(biquad_type type, double fc, double q, double gain)
+{
+ m_stream->update();
+ m_type = type;
+ m_fc = fc;
+ m_q = q;
+ m_gain = gain;
+ recalc();
+}
+
+
+//-------------------------------------------------
+// Filter setup helpers for various filter models
+//-------------------------------------------------
+
+// Sallen-Key filters
+
+/* Setup a biquad filter structure based on a single op-amp Sallen-Key low-pass filter circuit.
+ *
+ * .----------------------------.
+ * | |
+ * --- c2 |
+ * --- |
+ * | |
+ * r1 | r2 |\ |
+ * In >----ZZZZ----+--ZZZZ---+--------+ | \ |
+ * | '--|+ \ |
+ * --- c1 | >--+------> out
+ * --- .--|- / |
+ * | | | / |
+ * gnd | |/ |
+ * | |
+ * | r4 |
+ * +--ZZZZ---'
+ * |
+ * Z
+ * Z r3
+ * Z
+ * |
+ * gnd
+ */
+filter_biquad_device& filter_biquad_device::opamp_sk_lowpass_setup(double r1, double r2, double r3, double r4, double c1, double c2)
+{
+ if ((r1 == 0) || (r2 == 0) || (r3 == 0) || (r4 == 0) || (c1 == 0) || (c2 == 0))
+ {
+ fatalerror("filter_biquad_device::opamp_sk_lowpass_setup() - no parameters can be 0; parameters were: r1: %f, r2: %f, r3: %f, r4: %f, c1: %f, c2: %f", r1, r2, r3, r4, c1, c2); /* Filter can not be setup. Undefined results. */
+ }
+
+ // note: if R3 doesn't exist (no link to ground), pass a value of RES_M(999.99) or the like, i.e. an 'infinite resistor'
+ double const gain = (r3 + r4) / r3;
+ double const fc = 1.0 / (2 * M_PI * sqrt(r1 * r2 * c1 * c2));
+ double const q = sqrt(r1 * r2 * c1 * c2) / ((r1 * c1) + (r2 * c1) + ((r2 * c2) * (1.0 - gain)));
+#ifdef FLT_BIQUAD_DEBUG_SETUP
+ logerror("filter_biquad_device::opamp_sk_lowpass_setup() yields: fc = %f, Q = %f, gain = %f\n", fc, q, gain);
+#endif
+ return setup(biquad_type::LOWPASS, fc, q, gain);
+}
+
+// Multiple-Feedback filters
+// (This is sometimes called a 'Rauch' filter circuit.)
+
+/* Setup a biquad filter structure based on a single op-amp Multiple-Feedback low-pass filter circuit.
+ * NOTE: vRef is not definable when setting up the filter.
+ * If the analog effects caused by vRef are important to the operation of the specific filter
+ * in question, a netlist implementation may work better under those circumstances.
+ *
+ * .--------+---------.
+ * | | |
+ * Z --- c2 |
+ * Z r3 --- |
+ * Z | |
+ * r1 | r2 | |\ |
+ * In >----ZZZZ----+---------+--ZZZZ--+ | \ |
+ * | '--|- \ |
+ * --- c1 | >--+------> out
+ * --- .--|+ /
+ * | | | /
+ * gnd vRef >---' |/
+ *
+ */
+filter_biquad_device& filter_biquad_device::opamp_mfb_lowpass_setup(double r1, double r2, double r3, double c1, double c2)
+{
+ if ((r1 == 0) || (r2 == 0) || (r3 == 0) || (c2 == 0))
+ {
+ fatalerror("filter_biquad_device::opamp_mfb_lowpass_setup() - only c1 can be 0; parameters were: r1: %f, r2: %f, r3: %f, c1: %f, c2: %f", r1, r2, r3, c1, c2); /* Filter can not be setup. Undefined results. */
+ }
+
+ double const gain = -r3 / r1;
+ double fc, q = (M_SQRT2 / 2.0);
+ if (c1 == 0) // set C1 to 0 to run this filter in a degraded single pole mode where C1 was left off the filter entirely. Certain Williams boards seem to have omitted C1, presumably by accident.
+ {
+ fc = (r1 * r3) / (2 * M_PI * ((r1 * r2) + (r1 * r3) + (r2 * r3)) * r3 * c2);
+#ifdef FLT_BIQUAD_DEBUG_SETUP
+ logerror("filter_biquad_device::opamp_mfb_lowpass_setup() in degraded mode yields: fc = %f, Q = %f(ignored), gain = %f\n", fc, q, gain);
+#endif
+ return setup(biquad_type::LOWPASS1P, fc, q, gain);
+ }
+ else
+ {
+ fc = 1.0 / (2 * M_PI * sqrt(r2 * r3 * c1 * c2));
+ q = sqrt(r2 * r3 * c1 * c2) / ((r3 * c2) + (r2 * c2) + ((r2 * c2) * -gain));
+#ifdef FLT_BIQUAD_DEBUG_SETUP
+ logerror("filter_biquad_device::opamp_mfb_lowpass_setup() yields: fc = %f, Q = %f, gain = %f\n", fc, q, gain);
+#endif
+ return setup(biquad_type::LOWPASS, fc, q, gain);
+ }
+}
+
+/* Setup a biquad filter structure based on a single op-amp Multiple-Feedback band-pass filter circuit.
+ * NOTE: vRef is not definable when setting up the filter.
+ * If the analog effects caused by vRef are important to the operation of the specific filter
+ * in question, a netlist implementation may work better under those circumstances.
+ * NOTE2: If r2 is not used, then set it to 0 ohms, the code will ignore it and assume a fixed gain of 1.
+ *
+ * .--------+---------.
+ * | | |
+ * --- c1 Z |
+ * --- Z r3 |
+ * | Z |
+ * r1 | c2 | |\ |
+ * In >----ZZZZ----+---------+--||----+ | \ |
+ * Z '--|- \ |
+ * Z r2 | >--+------> out
+ * Z .--|+ /
+ * | | | /
+ * gnd vRef >---' |/
+ *
+ */
+filter_biquad_device& filter_biquad_device::opamp_mfb_bandpass_setup(double r1, double r2, double r3, double c1, double c2)
+{
+ if ((r1 == 0) || (r3 == 0) || (c1 == 0) || (c2 == 0))
+ {
+ fatalerror("filter_biquad_device::opamp_mfb_bandpass_setup() - only r2 can be 0; parameters were: r1: %f, r2: %f, r3: %f, c1: %f, c2: %f", r1, r2, r3, c1, c2); /* Filter can not be setup. Undefined results. */
+ }
+
+ double r_in, gain;
+
+ if (r2 == 0)
+ {
+ gain = 1;
+ r_in = r1;
+ }
+ else
+ {
+ gain = r2 / (r1 + r2);
+ r_in = 1.0 / (1.0/r1 + 1.0/r2);
+ }
+
+ double const fc = 1.0 / (2 * M_PI * sqrt(r_in * r3 * c1 * c2));
+ double const q = sqrt(r3 / r_in * c1 * c2) / (c1 + c2);
+ gain *= -r3 / r_in * c2 / (c1 + c2);
+#ifdef FLT_BIQUAD_DEBUG_SETUP
+ logerror("filter_biquad_device::opamp_mfb_bandpass_setup() yields: fc = %f, Q = %f, gain = %f\n", fc, q, gain);
+#endif
+ return setup(biquad_type::BANDPASS, fc, q, gain);
+}
+
+/* Setup a biquad filter structure based on a single op-amp Multiple-Feedback high-pass filter circuit.
+ * NOTE: vRef is not definable when setting up the filter.
+ * If the analog effects caused by vRef are important to the operation of the specific filter
+ * in question, a netlist implementation may work better under those circumstances.
+ *
+ * .--------+---------.
+ * | | |
+ * --- c3 Z |
+ * --- Z r2 |
+ * | Z |
+ * c1 | c2 | |\ |
+ * In >-----||-----+---------+---||---+ | \ |
+ * Z '--|- \ |
+ * Z r1 | >--+------> out
+ * Z .--|+ /
+ * | | | /
+ * gnd vRef >---' |/
+ *
+ */
+filter_biquad_device& filter_biquad_device::opamp_mfb_highpass_setup(double r1, double r2, double c1, double c2, double c3)
+{
+ if ((r1 == 0) || (r2 == 0) || (c1 == 0) || (c2 == 0) || (c3 == 0))
+ {
+ fatalerror("filter_biquad_device::opamp_mfb_highpass_setup() - no parameters can be 0; parameters were: r1: %f, r2: %f, c1: %f, c2: %f, c3: %f", r1, r2, c1, c2, c3); /* Filter can not be setup. Undefined results. */
+ }
+ // TODO: if c1 is 0/shorted, should the circuit should work with a gain of 1 in a first order mode?
+
+ double const gain = -c1 / c3;
+ double const fc = 1.0 / (2 * M_PI * sqrt(c2 * c3 * r1 * r2));
+ double const q = sqrt(c2 * c3 * r1 * r2) / ((c2 * r1) + (c3 * r1) + ((c3 * r1) * -gain));
+#ifdef FLT_BIQUAD_DEBUG_SETUP
+ logerror("filter_biquad_device::opamp_mfb_highpass_setup() yields: fc = %f, Q = %f, gain = %f\n", fc, q, gain);
+#endif
+ return setup(biquad_type::HIGHPASS, fc, q, gain);
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void filter_biquad_device::device_start()
+{
+ m_stream = stream_alloc(1, 1, SAMPLE_RATE_OUTPUT_ADAPTIVE);
+ m_last_sample_rate = 0;
+ recalc();
+
+ save_item(NAME(m_type));
+ save_item(NAME(m_last_sample_rate));
+ save_item(NAME(m_fc));
+ save_item(NAME(m_q));
+ save_item(NAME(m_gain));
+ save_item(NAME(m_input));
+ save_item(NAME(m_w0));
+ save_item(NAME(m_w1));
+ save_item(NAME(m_w2));
+ save_item(NAME(m_output));
+ save_item(NAME(m_a1));
+ save_item(NAME(m_a2));
+ save_item(NAME(m_b0));
+ save_item(NAME(m_b1));
+ save_item(NAME(m_b2));
+}
+
+
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void filter_biquad_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ auto &src = inputs[0];
+ auto &dst = outputs[0];
+
+ if (m_last_sample_rate != m_stream->sample_rate())
+ {
+ recalc();
+ m_last_sample_rate = m_stream->sample_rate();
+ }
+
+ for (int sampindex = 0; sampindex < dst.samples(); sampindex++)
+ {
+ m_input = src.get(sampindex);
+ step();
+ dst.put(sampindex, m_output);
+ }
+}
+
+
+/* Calculate the filter context based on the passed filter type info.
+ * m_type - 1 of the 9 defined filter types
+ * m_fc - center frequency
+ * m_q - 'Q' (quality) factor of filter (1/damp)
+ * m_gain - overall filter gain. Set to 1.0 if not needed. The exact meaning of gain changes depending on the filter type.
+ */
+void filter_biquad_device::recalc()
+{
+ double const MGain = fabs(m_gain); // absolute multiplicative gain
+ double const DBGain = log10(MGain) * 20.0; // gain in dB
+ double const AMGain = pow(10, fabs(DBGain) / 20.0); // multiplicative gain of absolute DB
+ double const K = tan(M_PI * m_fc / m_stream->sample_rate());
+ double const Ksquared = K * K;
+ double const KoverQ = K / m_q;
+ double normal = 1.0 / (1.0 + KoverQ + Ksquared);
+
+ m_a1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - KoverQ + Ksquared) * normal;
+
+ switch (m_type)
+ {
+ case biquad_type::LOWPASS1P:
+ m_a1 = exp(-2.0 * M_PI * (m_fc / m_stream->sample_rate()));
+ m_b0 = 1.0 - m_a1;
+ m_a1 = -m_a1;
+ m_b1 = m_b2 = m_a2 = 0.0;
+ break;
+ case biquad_type::HIGHPASS1P:
+ m_a1 = -exp(-2.0 * M_PI * (0.5 - m_fc / m_stream->sample_rate()));
+ m_b0 = 1.0 + m_a1;
+ m_a1 = -m_a1;
+ m_b1 = m_b2 = m_a2 = 0.0;
+ break;
+ case biquad_type::LOWPASS:
+ m_b0 = Ksquared * normal;
+ m_b1 = 2.0 * m_b0;
+ m_b2 = 1.0 * m_b0;
+ m_a1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - KoverQ + Ksquared) * normal;
+ break;
+ case biquad_type::HIGHPASS:
+ m_b0 = 1.0 * normal;
+ m_b1 = -2.0 * m_b0;
+ m_b2 = 1.0 * m_b0;
+ m_a1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - KoverQ + Ksquared) * normal;
+ break;
+ case biquad_type::BANDPASS:
+ m_b0 = KoverQ * normal;
+ m_b1 = 0.0;
+ m_b2 = -1.0 * m_b0;
+ m_a1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - KoverQ + Ksquared) * normal;
+ break;
+ case biquad_type::NOTCH:
+ m_b0 = (1.0 + Ksquared) * normal;
+ m_b1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_b2 = 1.0 * m_b0;
+ m_a1 = 1.0 * m_b1;
+ m_a2 = (1.0 - KoverQ + Ksquared) * normal;
+ break;
+ case biquad_type::PEAK:
+ if (DBGain >= 0.0)
+ {
+ m_b0 = (1.0 + (AMGain * KoverQ) + Ksquared) * normal;
+ m_b1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_b2 = (1.0 - (AMGain * KoverQ) + Ksquared) * normal;
+ m_a1 = 1.0 * m_b1;
+ m_a2 = (1.0 - KoverQ + Ksquared) * normal;
+ }
+ else
+ {
+ normal = 1.0 / (1.0 + (AMGain * KoverQ) + Ksquared);
+ m_b0 = (1.0 + KoverQ + Ksquared) * normal;
+ m_b1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_b2 = (1.0 - KoverQ + Ksquared) * normal;
+ m_a1 = 1.0 * m_b1;
+ m_a2 = (1.0 - (AMGain * KoverQ) + Ksquared) * normal;
+ }
+ break;
+ case biquad_type::LOWSHELF:
+ if (DBGain >= 0.0)
+ {
+ normal = 1.0 / (1.0 + M_SQRT2 * K + Ksquared);
+ m_b0 = (1.0 + sqrt(2.0 * AMGain) * K + AMGain * Ksquared) * normal;
+ m_b1 = 2.0 * (AMGain * Ksquared - 1.0) * normal;
+ m_b2 = (1.0 - sqrt(2.0 * AMGain) * K + AMGain * Ksquared) * normal;
+ m_a1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - M_SQRT2 * K + Ksquared) * normal;
+ }
+ else
+ {
+ normal = 1.0 / (1.0 + sqrt(2.0 * AMGain) * K + AMGain * Ksquared);
+ m_b0 = (1.0 + M_SQRT2 * K + Ksquared) * normal;
+ m_b1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_b2 = (1.0 - M_SQRT2 * K + Ksquared) * normal;
+ m_a1 = 2.0 * (AMGain * Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - sqrt(2.0 * AMGain) * K + AMGain * Ksquared) * normal;
+ }
+ break;
+ case biquad_type::HIGHSHELF:
+ if (DBGain >= 0.0)
+ {
+ normal = 1.0 / (1.0 + M_SQRT2 * K + Ksquared);
+ m_b0 = (AMGain + sqrt(2.0 * AMGain) * K + Ksquared) * normal;
+ m_b1 = 2.0 * (Ksquared - AMGain) * normal;
+ m_b2 = (AMGain - sqrt(2.0 * AMGain) * K + Ksquared) * normal;
+ m_a1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_a2 = (1.0 - M_SQRT2 * K + Ksquared) * normal;
+ }
+ else
+ {
+ normal = 1.0 / (AMGain + sqrt(2.0 * AMGain) * K + Ksquared);
+ m_b0 = (1.0 + M_SQRT2 * K + Ksquared) * normal;
+ m_b1 = 2.0 * (Ksquared - 1.0) * normal;
+ m_b2 = (1.0 - M_SQRT2 * K + Ksquared) * normal;
+ m_a1 = 2.0 * (Ksquared - AMGain) * normal;
+ m_a2 = (AMGain - sqrt(2.0 * AMGain) * K + Ksquared) * normal;
+ }
+ break;
+ default:
+ fatalerror("filter_biquad_device::recalc() - Invalid filter type!");
+ break;
+ }
+#ifdef FLT_BIQUAD_DEBUG
+ logerror("Calculated Parameters:\n");
+ logerror( "Gain (dB): %f, (raw): %f\n", DBGain, MGain);
+ logerror( "k: %f\n", K);
+ logerror( "normal: %f\n", normal);
+ logerror("b0: %f\n", m_b0);
+ logerror("b1: %f\n", m_b1);
+ logerror("b2: %f\n", m_b2);
+ logerror("a1: %f\n", m_a1);
+ logerror("a2: %f\n", m_a2);
+#endif
+ // peak and shelf filters do not use gain for the entire signal, only for the peak/shelf portions
+ // side note: the first order lowpass and highpass filter analogues technically don't have gain either,
+ // but this can be 'faked' by adjusting the bx factors, so we support that anyway, even if it isn't realistic.
+ if ( (m_type != biquad_type::PEAK)
+ && (m_type != biquad_type::LOWSHELF)
+ && (m_type != biquad_type::HIGHSHELF) )
+ {
+ m_b0 *= m_gain;
+ m_b1 *= m_gain;
+ m_b2 *= m_gain;
+#ifdef FLT_BIQUAD_DEBUG
+ logerror("b0g: %f\n", m_b0);
+ logerror("b1g: %f\n", m_b1);
+ logerror("b2g: %f\n", m_b2);
+#endif
+ }
+}
+
+/* Step the filter */
+void filter_biquad_device::step()
+{
+ m_w2 = m_w1;
+ m_w1 = m_w0;
+ m_w0 = (-m_a1 * m_w1) + (-m_a2 * m_w2) + m_input;
+ m_output = (m_b0 * m_w0) + (m_b1 * m_w1) + (m_b2 * m_w2);
+}
diff --git a/src/devices/sound/flt_biquad.h b/src/devices/sound/flt_biquad.h
new file mode 100644
index 00000000000..17050c75017
--- /dev/null
+++ b/src/devices/sound/flt_biquad.h
@@ -0,0 +1,80 @@
+// license:BSD-3-Clause
+// copyright-holders:K.Wilkins,Couriersud,Derrick Renaud,Frank Palazzolo,Jonathan Gevaryahu
+#ifndef MAME_SOUND_FLT_BIQUAD_H
+#define MAME_SOUND_FLT_BIQUAD_H
+
+#pragma once
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> filter_biquad_device
+
+class filter_biquad_device : public device_t, public device_sound_interface
+{
+public:
+ enum class biquad_type : int
+ {
+ LOWPASS1P = 0,
+ HIGHPASS1P,
+ LOWPASS,
+ HIGHPASS,
+ BANDPASS,
+ NOTCH,
+ PEAK,
+ LOWSHELF,
+ HIGHSHELF
+ };
+
+ filter_biquad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
+
+ // set up the filter with the specified filter parameters and return a pointer to the new device
+ filter_biquad_device& setup(biquad_type type, double fc, double q, double gain);
+ // update an existing instance with new filter parameters
+ void update_params(biquad_type type, double fc, double q, double gain);
+
+ // helper setup functions to create common filters representable by biquad filters
+ // Sallen-Key low-pass
+ filter_biquad_device& opamp_sk_lowpass_setup(double r1, double r2, double r3, double r4, double c1, double c2);
+ // TODO when needed: Sallen-Key band-pass
+ // TODO when needed: Sallen-Key high-pass
+
+ // Multiple-Feedback low-pass
+ filter_biquad_device& opamp_mfb_lowpass_setup(double r1, double r2, double r3, double c1, double c2);
+
+ // Multiple-Feedback band-pass
+ filter_biquad_device& opamp_mfb_bandpass_setup(double r1, double r2, double r3, double c1, double c2);
+
+ // Multiple-Feedback high-pass
+ filter_biquad_device& opamp_mfb_highpass_setup(double r1, double r2, double c1, double c2, double c3);
+
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ void recalc();
+ void step();
+
+ sound_stream* m_stream;
+ biquad_type m_type;
+ int m_last_sample_rate;
+ double m_fc;
+ double m_q;
+ double m_gain;
+
+ stream_buffer::sample_t m_input;
+ double m_w0, m_w1, m_w2; /* w[k], w[k-1], w[k-2], current and previous intermediate values */
+ stream_buffer::sample_t m_output;
+ double m_a1, m_a2; /* digital filter coefficients, denominator */
+ double m_b0, m_b1, m_b2; /* digital filter coefficients, numerator */
+};
+
+DECLARE_DEVICE_TYPE(FILTER_BIQUAD, filter_biquad_device)
+
+#endif // MAME_SOUND_FLT_BIQUAD_H
diff --git a/src/devices/sound/flt_rc.cpp b/src/devices/sound/flt_rc.cpp
index 8de64b37a40..48d542283e0 100644
--- a/src/devices/sound/flt_rc.cpp
+++ b/src/devices/sound/flt_rc.cpp
@@ -23,6 +23,7 @@ filter_rc_device::filter_rc_device(const machine_config &mconfig, const char *ta
m_k(0),
m_memory(0),
m_type(LOWPASS),
+ m_last_sample_rate(0),
m_R1(1),
m_R2(1),
m_R3(1),
@@ -37,8 +38,8 @@ filter_rc_device::filter_rc_device(const machine_config &mconfig, const char *ta
void filter_rc_device::device_start()
{
- m_stream = stream_alloc_legacy(1, 1, machine().sample_rate());
- recalc();
+ m_stream = stream_alloc(1, 1, SAMPLE_RATE_OUTPUT_ADAPTIVE);
+ m_last_sample_rate = 0;
save_item(NAME(m_k));
save_item(NAME(m_memory));
@@ -51,31 +52,37 @@ void filter_rc_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void filter_rc_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void filter_rc_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t const *src = inputs[0];
- stream_sample_t *dst = outputs[0];
- int memory = m_memory;
+ auto &src = inputs[0];
+ auto &dst = outputs[0];
+ stream_buffer::sample_t memory = m_memory;
+
+ if (m_last_sample_rate != m_stream->sample_rate())
+ {
+ recalc();
+ m_last_sample_rate = m_stream->sample_rate();
+ }
switch (m_type)
{
case LOWPASS:
case LOWPASS_2C:
- while (samples--)
+ for (int sampindex = 0; sampindex < dst.samples(); sampindex++)
{
- memory += ((*src++ - memory) * m_k) / 0x10000;
- *dst++ = memory;
+ memory += (src.get(sampindex) - memory) * m_k;
+ dst.put(sampindex, memory);
}
break;
case HIGHPASS:
case AC:
- while (samples--)
+ for (int sampindex = 0; sampindex < dst.samples(); sampindex++)
{
- *dst++ = *src - memory;
- memory += ((*src++ - memory) * m_k) / 0x10000;
+ dst.put(sampindex, src.get(sampindex) - memory);
+ memory += (src.get(sampindex) - memory) * m_k;
}
break;
}
@@ -93,8 +100,8 @@ void filter_rc_device::recalc()
if (m_C == 0.0)
{
/* filter disabled */
- m_k = 0x10000;
- m_memory = 0x0;
+ m_k = 1.0;
+ m_memory = 0;
return;
}
Req = (m_R1 * (m_R2 + m_R3)) / (m_R1 + m_R2 + m_R3);
@@ -103,8 +110,8 @@ void filter_rc_device::recalc()
if (m_C == 0.0)
{
/* filter disabled */
- m_k = 0x10000;
- m_memory = 0x0;
+ m_k = 1.0;
+ m_memory = 0;
return;
}
Req = m_R1;
@@ -114,8 +121,8 @@ void filter_rc_device::recalc()
if (m_C == 0.0)
{
/* filter disabled */
- m_k = 0x0;
- m_memory = 0x0;
+ m_k = 0;
+ m_memory = 0;
return;
}
Req = m_R1;
@@ -126,5 +133,5 @@ void filter_rc_device::recalc()
/* Cut Frequency = 1/(2*Pi*Req*C) */
/* k = (1-(EXP(-TIMEDELTA/RC))) */
- m_k = 0x10000 - 0x10000 * (exp(-1 / (Req * m_C) / machine().sample_rate()));
+ m_k = 1.0 - exp(-1 / (Req * m_C) / m_stream->sample_rate());
}
diff --git a/src/devices/sound/flt_rc.h b/src/devices/sound/flt_rc.h
index 9c1bc7f3381..d06d0ff75d1 100644
--- a/src/devices/sound/flt_rc.h
+++ b/src/devices/sound/flt_rc.h
@@ -95,7 +95,7 @@ public:
{
m_stream->update();
set_rc(type, R1, R2, R3, C);
- recalc();
+ m_last_sample_rate = 0;
return *this;
}
@@ -109,16 +109,17 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void recalc();
private:
sound_stream* m_stream;
- int m_k;
- int m_memory;
+ stream_buffer::sample_t m_k;
+ stream_buffer::sample_t m_memory;
int m_type;
+ int m_last_sample_rate;
double m_R1;
double m_R2;
double m_R3;
diff --git a/src/devices/sound/flt_vol.cpp b/src/devices/sound/flt_vol.cpp
index 8b8438f9b94..e43da0a1ee6 100644
--- a/src/devices/sound/flt_vol.cpp
+++ b/src/devices/sound/flt_vol.cpp
@@ -27,21 +27,19 @@ filter_volume_device::filter_volume_device(const machine_config &mconfig, const
void filter_volume_device::device_start()
{
m_gain = 0x100;
- m_stream = stream_alloc_legacy(1, 1, machine().sample_rate());
+ m_stream = stream_alloc(1, 1, SAMPLE_RATE_OUTPUT_ADAPTIVE);
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void filter_volume_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void filter_volume_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t const *src = inputs[0];
- stream_sample_t *dst = outputs[0];
-
- while (samples--)
- *dst++ = (*src++ * m_gain) >> 8;
+ // no need to work here; just copy input stream to output and apply gain
+ outputs[0] = inputs[0];
+ outputs[0].apply_gain(m_gain);
}
@@ -49,5 +47,5 @@ void filter_volume_device::sound_stream_update_legacy(sound_stream &stream, stre
void filter_volume_device::flt_volume_set_volume(float volume)
{
m_stream->update();
- m_gain = int(volume * 256);
+ m_gain = volume;
}
diff --git a/src/devices/sound/flt_vol.h b/src/devices/sound/flt_vol.h
index 034c3a3cf79..6a3bdab17d5 100644
--- a/src/devices/sound/flt_vol.h
+++ b/src/devices/sound/flt_vol.h
@@ -24,11 +24,11 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream* m_stream;
- int m_gain;
+ stream_buffer::sample_t m_gain;
};
DECLARE_DEVICE_TYPE(FILTER_VOLUME, filter_volume_device)
diff --git a/src/devices/sound/fm.cpp b/src/devices/sound/fm.cpp
index 5679860a2f2..01d8ba11bf1 100644
--- a/src/devices/sound/fm.cpp
+++ b/src/devices/sound/fm.cpp
@@ -2111,12 +2111,11 @@ struct ym2203_state
} // anonymous namespace
/* Generate samples for one of the YM2203s */
-void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length)
+void ym2203_update_one(void *chip, write_stream_view &buf)
{
ym2203_state *F2203 = (ym2203_state *)chip;
FM_OPN *OPN = &F2203->OPN;
int i;
- FMSAMPLE *buf = buffer;
FM_CH *cch[3];
cch[0] = &F2203->CH[0];
@@ -2147,7 +2146,7 @@ void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length)
OPN->LFO_PM = 0;
/* buffering */
- for (i=0; i < length ; i++)
+ for (i=0; i < buf.samples() ; i++)
{
/* clear outputs */
OPN->out_fm[0] = 0;
@@ -2186,7 +2185,7 @@ void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length)
#endif
/* buffering */
- buf[i] = lt;
+ buf.put_int(i, lt, 32768);
}
/* timer A control */
@@ -2727,19 +2726,18 @@ static inline void YM2608IRQMaskWrite(FM_OPN *OPN, ym2608_state *F2608, int v)
}
/* Generate samples for one of the YM2608s */
-void ym2608_update_one(void *chip, FMSAMPLE * const *buffer, int length)
+void ym2608_update_one(void *chip, std::vector<write_stream_view> &buffer)
{
ym2608_state *F2608 = (ym2608_state *)chip;
FM_OPN *OPN = &F2608->OPN;
YM_DELTAT *DELTAT = &F2608->deltaT;
int i,j;
- FMSAMPLE *bufL,*bufR;
FM_CH *cch[6];
int32_t *out_fm = OPN->out_fm;
/* set bufer */
- bufL = buffer[0];
- bufR = buffer[1];
+ auto &bufL = buffer[0];
+ auto &bufR = buffer[1];
cch[0] = &F2608->CH[0];
cch[1] = &F2608->CH[1];
@@ -2770,7 +2768,7 @@ void ym2608_update_one(void *chip, FMSAMPLE * const *buffer, int length)
/* buffering */
- for(i=0; i < length ; i++)
+ for(i=0; i < bufL.samples() ; i++)
{
advance_lfo(OPN);
@@ -2840,14 +2838,9 @@ void ym2608_update_one(void *chip, FMSAMPLE * const *buffer, int length)
lt += ((out_fm[5]>>1) & OPN->pan[10]);
rt += ((out_fm[5]>>1) & OPN->pan[11]);
- lt >>= FINAL_SH;
- rt >>= FINAL_SH;
-
- Limit( lt, MAXOUT, MINOUT );
- Limit( rt, MAXOUT, MINOUT );
/* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
+ bufL.put_int_clamp(i, lt, 32768 << FINAL_SH);
+ bufR.put_int_clamp(i, rt, 32768 << FINAL_SH);
#ifdef SAVE_SAMPLE
SAVE_ALL_CHANNELS
@@ -3275,19 +3268,18 @@ int ym2608_timer_over(void *chip,int c)
/* YM2610(OPNB) */
/* Generate samples for one of the YM2610s */
-void ym2610_update_one(void *chip, FMSAMPLE * const *buffer, int length)
+void ym2610_update_one(void *chip, std::vector<write_stream_view> &buffer)
{
ym2610_state *F2610 = (ym2610_state *)chip;
FM_OPN *OPN = &F2610->OPN;
YM_DELTAT *DELTAT = &F2610->deltaT;
int i,j;
- FMSAMPLE *bufL,*bufR;
FM_CH *cch[4];
int32_t *out_fm = OPN->out_fm;
/* buffer setup */
- bufL = buffer[0];
- bufR = buffer[1];
+ auto &bufL = buffer[0];
+ auto &bufR = buffer[1];
cch[0] = &F2610->CH[1];
cch[1] = &F2610->CH[2];
@@ -3323,7 +3315,7 @@ void ym2610_update_one(void *chip, FMSAMPLE * const *buffer, int length)
refresh_fc_eg_chan( OPN, cch[3] );
/* buffering */
- for(i=0; i < length ; i++)
+ for(i=0; i < bufL.samples() ; i++)
{
advance_lfo(OPN);
@@ -3386,20 +3378,13 @@ void ym2610_update_one(void *chip, FMSAMPLE * const *buffer, int length)
lt += ((out_fm[5]>>1) & OPN->pan[10]);
rt += ((out_fm[5]>>1) & OPN->pan[11]);
-
- lt >>= FINAL_SH;
- rt >>= FINAL_SH;
-
- Limit( lt, MAXOUT, MINOUT );
- Limit( rt, MAXOUT, MINOUT );
-
#ifdef SAVE_SAMPLE
SAVE_ALL_CHANNELS
#endif
/* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
+ bufL.put_int_clamp(i, lt, 32768 << FINAL_SH);
+ bufR.put_int_clamp(i, rt, 32768 << FINAL_SH);
}
/* timer A control */
@@ -3411,19 +3396,18 @@ void ym2610_update_one(void *chip, FMSAMPLE * const *buffer, int length)
#if BUILD_YM2610B
/* Generate samples for one of the YM2610Bs */
-void ym2610b_update_one(void *chip, FMSAMPLE * const *buffer, int length)
+void ym2610b_update_one(void *chip, std::vector<write_stream_view> &buffer)
{
ym2610_state *F2610 = (ym2610_state *)chip;
FM_OPN *OPN = &F2610->OPN;
YM_DELTAT *DELTAT = &F2610->deltaT;
int i,j;
- FMSAMPLE *bufL,*bufR;
FM_CH *cch[6];
int32_t *out_fm = OPN->out_fm;
/* buffer setup */
- bufL = buffer[0];
- bufR = buffer[1];
+ auto &bufL = buffer[0];
+ auto &bufR = buffer[1];
cch[0] = &F2610->CH[0];
cch[1] = &F2610->CH[1];
@@ -3453,7 +3437,7 @@ void ym2610b_update_one(void *chip, FMSAMPLE * const *buffer, int length)
refresh_fc_eg_chan( OPN, cch[5] );
/* buffering */
- for(i=0; i < length ; i++)
+ for(i=0; i < bufL.samples() ; i++)
{
advance_lfo(OPN);
@@ -3524,20 +3508,13 @@ void ym2610b_update_one(void *chip, FMSAMPLE * const *buffer, int length)
lt += ((out_fm[5]>>1) & OPN->pan[10]);
rt += ((out_fm[5]>>1) & OPN->pan[11]);
-
- lt >>= FINAL_SH;
- rt >>= FINAL_SH;
-
- Limit( lt, MAXOUT, MINOUT );
- Limit( rt, MAXOUT, MINOUT );
-
#ifdef SAVE_SAMPLE
SAVE_ALL_CHANNELS
#endif
/* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
+ bufL.put_int_clamp(i, lt, 32768);
+ bufR.put_int_clamp(i, rt, 32768);
}
/* timer A control */
diff --git a/src/devices/sound/fm.h b/src/devices/sound/fm.h
index d5d8760a449..45381d7dda9 100644
--- a/src/devices/sound/fm.h
+++ b/src/devices/sound/fm.h
@@ -50,7 +50,7 @@ template <typename X> constexpr TIME_TYPE MULTIPLY_TIME_BY_INT(TIME_TYPE const &
#endif
-typedef stream_sample_t FMSAMPLE;
+typedef s32 FMSAMPLE;
/*
#if (FM_SAMPLE_BITS==16)
typedef int16_t FMSAMPLE;
@@ -108,7 +108,7 @@ void ym2203_reset_chip(void *chip);
/*
** update one of chip
*/
-void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length);
+void ym2203_update_one(void *chip, write_stream_view &buffer);
/*
** Write
@@ -142,7 +142,7 @@ void * ym2608_init(device_t *device, int baseclock, int rate,
void ym2608_clock_changed(void *chip, int clock, int rate);
void ym2608_shutdown(void *chip);
void ym2608_reset_chip(void *chip);
-void ym2608_update_one(void *chip, FMSAMPLE * const *buffer, int length);
+void ym2608_update_one(void *chip, std::vector<write_stream_view> &buffer);
int ym2608_write(void *chip, int a,unsigned char v);
unsigned char ym2608_read(void *chip,int a);
@@ -158,10 +158,10 @@ void * ym2610_init(device_t *device, int baseclock, int rate,
void ym2610_clock_changed(void *chip, int clock, int rate);
void ym2610_shutdown(void *chip);
void ym2610_reset_chip(void *chip);
-void ym2610_update_one(void *chip, FMSAMPLE * const *buffer, int length);
+void ym2610_update_one(void *chip, std::vector<write_stream_view> &buffer);
#if BUILD_YM2610B
-void ym2610b_update_one(void *chip, FMSAMPLE * const *buffer, int length);
+void ym2610b_update_one(void *chip, std::vector<write_stream_view> &buffer);
#endif /* BUILD_YM2610B */
int ym2610_write(void *chip, int a,unsigned char v);
@@ -176,7 +176,7 @@ void * ym2612_init(device_t *device, int baseclock, int rate,
void ym2612_clock_changed(void *chip, int clock, int rate);
void ym2612_shutdown(void *chip);
void ym2612_reset_chip(void *chip);
-void ym2612_update_one(void *chip, FMSAMPLE * const *buffer, int length, u8 output_bits);
+void ym2612_update_one(void *chip, std::vector<write_stream_view> &buffer, u8 output_bits);
int ym2612_write(void *chip, int a,unsigned char v);
unsigned char ym2612_read(void *chip,int a);
diff --git a/src/devices/sound/fm2612.cpp b/src/devices/sound/fm2612.cpp
index b3482d0ac72..4f905bf80f1 100644
--- a/src/devices/sound/fm2612.cpp
+++ b/src/devices/sound/fm2612.cpp
@@ -2174,7 +2174,7 @@ static void init_tables(void)
/*******************************************************************************/
/* Generate samples for one of the YM2612s */
-void ym2612_update_one(void *chip, FMSAMPLE * const *buffer, int length, u8 output_bits)
+void ym2612_update_one(void *chip, std::vector<write_stream_view> &buffer, u8 output_bits)
{
// TODO : 'ladder' effects for Mega Drive/Genesis
const u8 output_shift = (output_bits > 14) ? 0 : (14 - output_bits);
@@ -2183,13 +2183,12 @@ void ym2612_update_one(void *chip, FMSAMPLE * const *buffer, int length, u8 outp
fm2612_FM_OPN *OPN = &F2612->OPN;
int32_t *out_fm = OPN->out_fm;
int i;
- FMSAMPLE *bufL,*bufR;
fm2612_FM_CH *cch[6];
int lt,rt;
/* set bufer */
- bufL = buffer[0];
- bufR = buffer[1];
+ auto &bufL = buffer[0];
+ auto &bufR = buffer[1];
cch[0] = &F2612->CH[0];
cch[1] = &F2612->CH[1];
@@ -2220,7 +2219,7 @@ void ym2612_update_one(void *chip, FMSAMPLE * const *buffer, int length, u8 outp
refresh_fc_eg_chan( OPN, cch[5] );
/* buffering */
- for(i=0; i < length ; i++)
+ for(i=0; i < bufL.samples() ; i++)
{
/* clear outputs */
out_fm[0] = 0;
@@ -2302,8 +2301,8 @@ void ym2612_update_one(void *chip, FMSAMPLE * const *buffer, int length, u8 outp
#endif
/* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
+ bufL.put_int(i, lt, 32768);
+ bufR.put_int(i, rt, 32768);
/* CSM mode: if CSM Key ON has occurred, CSM Key OFF need to be sent */
/* only if Timer A does not overflow again (i.e CSM Key ON not set again) */
diff --git a/src/devices/sound/fmopl.cpp b/src/devices/sound/fmopl.cpp
index 99139310d69..cb4d5ae686e 100644
--- a/src/devices/sound/fmopl.cpp
+++ b/src/devices/sound/fmopl.cpp
@@ -1498,7 +1498,7 @@ const int8_t FM_OPL::lfo_pm_table[8*8*2] = {
int FM_OPL::num_lock = 0;
-
+#if 0
static inline int limit( int val, int max, int min ) {
if ( val > max )
val = max;
@@ -1507,7 +1507,7 @@ static inline int limit( int val, int max, int min ) {
return val;
}
-
+#endif
/* generic table initialize */
int FM_OPL::init_tables()
@@ -2206,14 +2206,13 @@ void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,device
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
-void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length)
+void ym3812_update_one(void *chip, write_stream_view &buf)
{
FM_OPL *OPL = (FM_OPL *)chip;
uint8_t rhythm = OPL->rhythm&0x20;
- OPLSAMPLE *buf = buffer;
int i;
- for( i=0; i < length ; i++ )
+ for( i=0; i < buf.samples(); i++ )
{
int lt;
@@ -2242,11 +2241,6 @@ void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length)
lt = OPL->output[0];
- lt >>= FINAL_SH;
-
- /* limit check */
- lt = limit( lt , MAXOUT, MINOUT );
-
#ifdef SAVE_SAMPLE
if (which==0)
{
@@ -2255,7 +2249,7 @@ void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length)
#endif
/* store to sound buffer */
- buf[i] = lt;
+ buf.put_int_clamp(i, lt, 32768 << FINAL_SH);
OPL->advance();
}
@@ -2335,14 +2329,13 @@ void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,device
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
-void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length)
+void ym3526_update_one(void *chip, write_stream_view &buf)
{
FM_OPL *OPL = (FM_OPL *)chip;
uint8_t rhythm = OPL->rhythm&0x20;
- OPLSAMPLE *buf = buffer;
int i;
- for( i=0; i < length ; i++ )
+ for( i=0; i < buf.samples() ; i++ )
{
int lt;
@@ -2371,11 +2364,6 @@ void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length)
lt = OPL->output[0];
- lt >>= FINAL_SH;
-
- /* limit check */
- lt = limit( lt , MAXOUT, MINOUT );
-
#ifdef SAVE_SAMPLE
if (which==0)
{
@@ -2384,7 +2372,7 @@ void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length)
#endif
/* store to sound buffer */
- buf[i] = lt;
+ buf.put_int_clamp(i, lt, 32768 << FINAL_SH);
OPL->advance();
}
@@ -2491,15 +2479,14 @@ void y8950_set_delta_t_memory(void *chip, FM_READBYTE read_byte, FM_WRITEBYTE wr
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
-void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length)
+void y8950_update_one(void *chip, write_stream_view &buf)
{
int i;
FM_OPL *OPL = (FM_OPL *)chip;
uint8_t rhythm = OPL->rhythm&0x20;
YM_DELTAT &DELTAT = *OPL->deltat;
- OPLSAMPLE *buf = buffer;
- for( i=0; i < length ; i++ )
+ for( i=0; i < buf.samples() ; i++ )
{
int lt;
@@ -2533,11 +2520,6 @@ void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length)
lt = OPL->output[0] + (OPL->output_deltat[0]>>11);
- lt >>= FINAL_SH;
-
- /* limit check */
- lt = limit( lt , MAXOUT, MINOUT );
-
#ifdef SAVE_SAMPLE
if (which==0)
{
@@ -2546,7 +2528,7 @@ void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length)
#endif
/* store to sound buffer */
- buf[i] = lt;
+ buf.put_int_clamp(i, lt, 32768 << FINAL_SH);
OPL->advance();
}
diff --git a/src/devices/sound/fmopl.h b/src/devices/sound/fmopl.h
index add973a2369..bb484b0e41b 100644
--- a/src/devices/sound/fmopl.h
+++ b/src/devices/sound/fmopl.h
@@ -16,7 +16,7 @@
/* select output bits size of output : 8 or 16 */
#define OPL_SAMPLE_BITS 16
-typedef stream_sample_t OPLSAMPLE;
+typedef s32 OPLSAMPLE;
/*
#if (OPL_SAMPLE_BITS==16)
typedef int16_t OPLSAMPLE;
@@ -44,7 +44,7 @@ void ym3812_reset_chip(void *chip);
int ym3812_write(void *chip, int a, int v);
unsigned char ym3812_read(void *chip, int a);
int ym3812_timer_over(void *chip, int c);
-void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length);
+void ym3812_update_one(void *chip, write_stream_view &buffer);
void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, device_t *device);
void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, device_t *device);
@@ -77,7 +77,7 @@ int ym3526_timer_over(void *chip, int c);
** '*buffer' is the output buffer pointer
** 'length' is the number of samples that should be generated
*/
-void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length);
+void ym3526_update_one(void *chip, write_stream_view &buffer);
void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, device_t *device);
void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, device_t *device);
@@ -100,7 +100,7 @@ void y8950_reset_chip(void *chip);
int y8950_write(void *chip, int a, int v);
unsigned char y8950_read (void *chip, int a);
int y8950_timer_over(void *chip, int c);
-void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length);
+void y8950_update_one(void *chip, write_stream_view &buffer);
void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, device_t *device);
void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, device_t *device);
diff --git a/src/devices/sound/gaelco.cpp b/src/devices/sound/gaelco.cpp
index 41fbfc0a4c4..2a213408095 100644
--- a/src/devices/sound/gaelco.cpp
+++ b/src/devices/sound/gaelco.cpp
@@ -76,10 +76,10 @@ gaelco_gae1_device::gaelco_gae1_device(const machine_config &mconfig, device_typ
Writes length bytes to the sound buffer
============================================================================*/
-void gaelco_gae1_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void gaelco_gae1_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
/* fill all data needed */
- for (int j = 0; j < samples; j++)
+ for (int j = 0; j < outputs[0].samples(); j++)
{
int output_l = 0, output_r = 0;
@@ -177,12 +177,12 @@ void gaelco_gae1_device::sound_stream_update_legacy(sound_stream &stream, stream
#endif
/* now that we have computed all channels, save current data to the output buffer */
- outputs[0][j] = output_l;
- outputs[1][j] = output_r;
+ outputs[0].put_int(j, output_l, 32768);
+ outputs[1].put_int(j, output_r, 32768);
}
- if (wavraw)
- wav_add_data_32lr(wavraw, outputs[0], outputs[1], samples, 0);
+// if (wavraw)
+// wav_add_data_buffer(wavraw, outputs[0], outputs[1]);
}
/*============================================================================
@@ -253,7 +253,7 @@ void gaelco_gae1_device::gaelcosnd_w(offs_t offset, uint16_t data, uint16_t mem_
void gaelco_gae1_device::device_start()
{
u32 rate = clock() / 128;
- m_stream = stream_alloc_legacy(0, 2, rate);
+ m_stream = stream_alloc(0, 2, rate);
/* init volume table */
for (int vol = 0; vol < VOLUME_LEVELS; vol++)
diff --git a/src/devices/sound/gaelco.h b/src/devices/sound/gaelco.h
index 4f7eeaeb7a7..a598c64345d 100644
--- a/src/devices/sound/gaelco.h
+++ b/src/devices/sound/gaelco.h
@@ -43,7 +43,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/gb.cpp b/src/devices/sound/gb.cpp
index 42944daf152..2fc1c81e5b0 100644
--- a/src/devices/sound/gb.cpp
+++ b/src/devices/sound/gb.cpp
@@ -142,7 +142,7 @@ cgb04_apu_device::cgb04_apu_device(const machine_config &mconfig, const char *ta
void gameboy_sound_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_channel = stream_alloc(0, 2, SAMPLE_RATE_OUTPUT_ADAPTIVE);
m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(gameboy_sound_device::timer_callback),this));
m_timer->adjust(clocks_to_attotime(FRAME_CYCLES/128), 0, clocks_to_attotime(FRAME_CYCLES/128));
@@ -1211,18 +1211,18 @@ void cgb04_apu_device::apu_power_off()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void gameboy_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void gameboy_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outputl = outputs[0];
- stream_sample_t *outputr = outputs[1];
- while (samples-- > 0)
+ auto &outputl = outputs[0];
+ auto &outputr = outputs[1];
+ for (int sampindex = 0; sampindex < outputl.samples(); sampindex++)
{
- stream_sample_t sample;
- stream_sample_t left = 0;
- stream_sample_t right = 0;
+ s32 sample;
+ s32 left = 0;
+ s32 right = 0;
/* Mode 1 - Wave with Envelope and Sweep */
if (m_snd_1.on)
@@ -1269,12 +1269,8 @@ void gameboy_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
left *= m_snd_control.vol_left;
right *= m_snd_control.vol_right;
- /* pump up the volume */
- left <<= 6;
- right <<= 6;
-
/* Update the buffers */
- *outputl++ = left;
- *outputr++ = right;
+ outputl.put_int(sampindex, left, 32768 / 64);
+ outputr.put_int(sampindex, right, 32768 / 64);
}
}
diff --git a/src/devices/sound/gb.h b/src/devices/sound/gb.h
index a0ea67ed0a8..fee26bd8a74 100644
--- a/src/devices/sound/gb.h
+++ b/src/devices/sound/gb.h
@@ -25,7 +25,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
protected:
enum
diff --git a/src/devices/sound/hc55516.cpp b/src/devices/sound/hc55516.cpp
index 6397d2c927c..2d96ad2cb3b 100644
--- a/src/devices/sound/hc55516.cpp
+++ b/src/devices/sound/hc55516.cpp
@@ -1,8 +1,18 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Jonathan Gevaryahu
+// thanks-to:Zonn Moore
/*****************************************************************************
- Harris HC-55516 (and related) emulator
+ Continuously Variable Slope Demodulator standalone chip emulator:
+ Harris HC-55516 (sometimes labeled HCI-55516 or HC1-55516)
+ Harris HC-55532 (sometimes labeled HCI-55532 or HC1-55532) [preliminary]
+ Motorola MC-3417/MC-34115
+ Motorola MC-3418
+ TODO: research HC-55536 and HC-55564 differences vs HC-55516 (better auto-zeroing, and removal of the encoder offset compensation DAC?)
+
+ Driver TODOs:
+ /src/mame/audio/exidy440.cpp has its own internal implementation of the MC3417 and MC3418, it should be using this file instead
+
*****************************************************************************/
@@ -10,7 +20,7 @@
#include "hc55516.h"
-/* 4x oversampling */
+/* fixed samplerate of 192khz */
#define SAMPLE_RATE (48000 * 4)
#define INTEGRATOR_LEAK_TC 0.001
@@ -18,36 +28,26 @@
#define FILTER_CHARGE_TC 0.004
#define FILTER_MIN 0.0416
#define FILTER_MAX 1.0954
-#define SAMPLE_GAIN 10000.0
-
-
-
-
-DEFINE_DEVICE_TYPE(HC55516, hc55516_device, "hc55516", "HC-55516")
-
-hc55516_device::hc55516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : hc55516_device(mconfig, HC55516, tag, owner, clock)
-{
-}
-
-hc55516_device::hc55516_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, type, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- m_channel(nullptr),
- m_active_clock_hi(0),
- m_shiftreg_mask(0),
- m_last_clock_state(0),
- m_digit(0),
- m_new_digit(0),
- m_shiftreg(0),
- m_curr_sample(0),
- m_next_sample(0),
- m_update_count(0),
- m_filter(0),
- m_integrator(0),
- m_charge(0),
- m_decay(0),
- m_leak(0)
+#define SAMPLE_GAIN (10000.0 / 32768.0)
+
+
+//#####################################
+// COMMON
+//#####################################
+cvsd_device_base::cvsd_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool active_clock_edge, uint8_t shiftreg_mask)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , m_clock_state_push_cb(*this)
+ , m_digin_pull_cb(*this)
+ , m_digout_push_cb(*this)
+ , m_active_clock_edge(active_clock_edge)
+ , m_shiftreg_mask(shiftreg_mask)
+ , m_last_clock_state(false)
+ , m_buffered_bit(false)
+ , m_shiftreg(0)
+ , m_curr_sample(0)
+ , m_next_sample(0)
+ , m_samples_generated(0)
{
}
@@ -55,240 +55,490 @@ hc55516_device::hc55516_device(const machine_config &mconfig, device_type type,
// device_start - device-specific startup
//-------------------------------------------------
-void hc55516_device::device_start()
+void cvsd_device_base::device_start()
{
- start_common(0x07, true);
+ /* create the stream */
+ m_stream = stream_alloc(0, 1, SAMPLE_RATE);
+
+ save_item(NAME(m_last_clock_state));
+ save_item(NAME(m_buffered_bit));
+ save_item(NAME(m_shiftreg));
+ save_item(NAME(m_curr_sample));
+ save_item(NAME(m_next_sample));
+ save_item(NAME(m_samples_generated));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
-void hc55516_device::device_reset()
+void cvsd_device_base::device_reset()
{
m_last_clock_state = 0;
}
-DEFINE_DEVICE_TYPE(MC3417, mc3417_device, "mc3417", "MC3417")
+//-------------------------------------------------
+// device_clock_changed - device-specific samplerate change
+//-------------------------------------------------
+/*void cvsd_device_base::device_clock_changed()
+{
+ // do nothing.
+ //m_stream->set_sample_rate(clock());
+}*/
-mc3417_device::mc3417_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : hc55516_device(mconfig, MC3417, tag, owner, clock)
+READ_LINE_MEMBER( cvsd_device_base::clock_r )
{
+ // prevent debugger from changing the internal state
+ if (!machine().side_effects_disabled())
+ m_stream->update(); /* bring up to date first */
+ return clock_state_r();
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
+WRITE_LINE_MEMBER( cvsd_device_base::mclock_w )
+{
+ clock_w(state);
+}
-void mc3417_device::device_start()
+WRITE_LINE_MEMBER( cvsd_device_base::digin_w )
{
- start_common(0x07, false);
+ digit_w(state);
}
+// the following encode related functions don't do anything yet, don't call them.
+/*void cvsd_device_base::audio_in_w(int16_t data)
+{
+ assert(0);
+}*/
-DEFINE_DEVICE_TYPE(MC3418, mc3418_device, "mc3418", "MC3418")
+WRITE_LINE_MEMBER( cvsd_device_base::dec_encq_w )
+{
+ assert(0);
+}
-mc3418_device::mc3418_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : hc55516_device(mconfig, MC3418, tag, owner, clock)
+READ_LINE_MEMBER( cvsd_device_base::digout_r )
{
+ return 0;
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
+// default and stub implementations
-void mc3418_device::device_start()
+inline bool cvsd_device_base::is_external_oscillator()
{
- start_common(0x0f, false);
+ return clock() != 0;
}
+inline bool cvsd_device_base::is_clock_changed(bool clock_state)
+{
+ return ((!m_last_clock_state && clock_state) ||
+ (m_last_clock_state && !clock_state));
+}
-void hc55516_device::start_common(uint8_t _shiftreg_mask, int _active_clock_hi)
+inline bool cvsd_device_base::is_active_clock_transition(bool clock_state)
{
- /* compute the fixed charge, decay, and leak time constants */
- m_charge = pow(exp(-1.0), 1.0 / (FILTER_CHARGE_TC * 16000.0));
- m_decay = pow(exp(-1.0), 1.0 / (FILTER_DECAY_TC * 16000.0));
- m_leak = pow(exp(-1.0), 1.0 / (INTEGRATOR_LEAK_TC * 16000.0));
+ return ((clock_state != m_last_clock_state) &&
+ (clock_state == m_active_clock_edge));
+}
- m_shiftreg_mask = _shiftreg_mask;
- m_active_clock_hi = _active_clock_hi;
- m_last_clock_state = 0;
+inline bool cvsd_device_base::current_clock_state()
+{
+ // keep track of the clock state given its previous state and the number of samples produced
+ // i.e. if we generated m_samples_generated samples, at a sample rate of SAMPLE_RATE, then are we on a positive or negative level of a squarewave at clock() hz? SAMPLE_RATE may not be an integer multiple of clock()
+ //uint64_t fractions_of_second = (((uint64_t)m_samples_generated)<<32) / SAMPLE_RATE; // 32.32 bits of seconds passed so far
+ //uint32_t clock_edges_passed = (fractions_of_second * clock() * 2)>>32
+ //return (((((uint64_t)m_samples_generated<<32) * clock() * 2 / SAMPLE_RATE)>>32) & 0x1)?true:false;
+ return (((uint64_t)m_samples_generated * clock() * 2 / SAMPLE_RATE) & 0x01)?true:false;
+}
- /* create the stream */
- m_channel = stream_alloc_legacy(0, 1, SAMPLE_RATE);
+void cvsd_device_base::digit_w(int digit)
+{
+ m_stream->update();
+ m_buffered_bit = digit ? true : false;
+}
- save_item(NAME(m_last_clock_state));
- save_item(NAME(m_digit));
- save_item(NAME(m_new_digit));
- save_item(NAME(m_shiftreg));
- save_item(NAME(m_curr_sample));
- save_item(NAME(m_next_sample));
- save_item(NAME(m_update_count));
- save_item(NAME(m_filter));
- save_item(NAME(m_integrator));
+void cvsd_device_base::clock_w(int state)
+{
+ /* update the output buffer first */
+ m_stream->update();
+ bool clock_state = state ? true : false;
+
+ /* only makes sense for setups with a software driven clock */
+ assert(!is_external_oscillator());
+
+ /* speech clock changing? */
+ if (is_clock_changed(clock_state))
+ {
+ /* clear the update count */
+ m_samples_generated = 0;
+ process_bit(m_buffered_bit, clock_state);
+ }
+
+ /* update the clock */
+ m_last_clock_state = clock_state;
}
-inline int hc55516_device::is_external_oscillator()
+int cvsd_device_base::clock_state_r()
{
- return clock() != 0;
+ /* only makes sense for setups with an external oscillator */
+ assert(is_external_oscillator());
+
+ m_stream->update();
+
+ return current_clock_state();
}
+void cvsd_device_base::process_bit(bool bit, bool clock_state)
+{
+ // stub
+}
-inline int hc55516_device::is_active_clock_transition(int clock_state)
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void cvsd_device_base::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ // Stub, just return silence
+ auto &buffer = outputs[0];
+
+ m_samples_generated += buffer.samples();
+ if (m_samples_generated >= SAMPLE_RATE)
+ m_samples_generated -= SAMPLE_RATE;
+ buffer.fill(0);
+}
+
+
+//#########################################
+// HC55516
+//#########################################
+DEFINE_DEVICE_TYPE(HC55516, hc55516_device, "hc55516", "HC-55516")
+
+hc55516_device::hc55516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : hc55516_device(mconfig, HC55516, tag, owner, clock, 0xfc0, 6, 0xfc1, 4)
+{
+}
+
+// overridable type for hc55532 etc
+hc55516_device::hc55516_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t sylmask, int32_t sylshift, int32_t syladd, int32_t intshift)
+ : cvsd_device_base(mconfig, type, tag, owner, clock, RISING, 0x7)
+ , m_agc_push_cb(*this)
+ , m_fzq_pull_cb(*this)
+ , m_sylmask(sylmask)
+ , m_sylshift(sylshift)
+ , m_syladd(syladd)
+ , m_intshift(intshift)
+ , m_sylfilter(0)
+ , m_intfilter(0)
+ , m_agc(true)
+ , m_buffered_fzq(true)
{
- return (( m_active_clock_hi && !m_last_clock_state && clock_state) ||
- (!m_active_clock_hi && m_last_clock_state && !clock_state));
}
+//-------------------------------------------------
+// device_start - device-specific start
+//-------------------------------------------------
-inline int hc55516_device::current_clock_state()
+void hc55516_device::device_start()
{
- return ((uint64_t)m_update_count * clock() * 2 / SAMPLE_RATE) & 0x01;
+ cvsd_device_base::device_start();
+ save_item(NAME(m_sylfilter));
+ save_item(NAME(m_intfilter));
+ save_item(NAME(m_agc));
+ save_item(NAME(m_buffered_fzq));
+
+ /* resolve lines */
+ m_agc_push_cb.resolve();
+ m_fzq_pull_cb.resolve();
}
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
-void hc55516_device::process_digit()
+void hc55516_device::device_reset()
{
- double integrator = m_integrator, temp;
+ cvsd_device_base::device_reset();
+ // simulate /FZ having been held for a while
+ m_sylfilter = 0x3f;
+ m_intfilter = 0;
+ m_agc = true;
+ m_buffered_fzq = true; // assuming /FZ was just released and is now high/inactive
+}
- /* shift the bit into the shift register */
- m_shiftreg = (m_shiftreg << 1) | m_digit;
+// device specific functions
- /* move the estimator up or down a step based on the bit */
- if (m_digit)
- integrator += m_filter;
- else
- integrator -= m_filter;
+WRITE_LINE_MEMBER( hc55516_device::fzq_w )
+{
+ m_buffered_fzq = state;
+}
- /* simulate leakage */
- integrator *= m_leak;
+READ_LINE_MEMBER( hc55516_device::agc_r )
+{
+ // prevent debugger from changing the internal state
+ if (!machine().side_effects_disabled())
+ m_stream->update(); /* bring up to date first */
+ return m_agc;
+}
+
+void hc55516_device::process_bit(bool bit, bool clock_state)
+{
+ bool frozen = ( ( (m_intfilter >= 0x180) && (!bit) ) ||
+ ( (m_intfilter <= -0x180) && (bit) ) );
- /* if we got all 0's or all 1's in the last n bits, bump the step up */
- if (((m_shiftreg & m_shiftreg_mask) == 0) ||
- ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
+ int32_t sum;
+ if (is_active_clock_transition(clock_state))
{
- m_filter = FILTER_MAX - ((FILTER_MAX - m_filter) * m_charge);
+ // grab the /FZ state; if the callback is present, use that, otherwise use the buffered state
+ bool fzq_state = false;
+ if (!m_fzq_pull_cb.isnull())
+ fzq_state = m_fzq_pull_cb();
+ else
+ fzq_state = m_buffered_fzq;
+
+ if (!fzq_state) // /FZ is active low, if it is active, the input bit is ignored and the inverse of the previous bit in the shifter is used instead
+ bit = !(m_shiftreg&1);
+
+ /* shift the new bit into the shift register */
+ m_shiftreg = (m_shiftreg << 1) | (bit?1:0);
+
+ /* if we got all 0's or all 1's in the last n bits... */
+ if (((m_shiftreg & m_shiftreg_mask) == 0) ||
+ ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
+ {
+ // coincidence is true
+ if (!frozen) m_sylfilter += (((~m_sylfilter) & m_sylmask) >> m_sylshift);
+ }
+ else
+ {
+ // coincidence is false
+ if (!frozen) m_sylfilter += (((~m_sylfilter) & m_sylmask) >> m_sylshift) + m_syladd;
+ }
+ m_sylfilter &= 0xfff;
- if (m_filter > FILTER_MAX)
- m_filter = FILTER_MAX;
+ sum = ( ((~m_intfilter) >> m_intshift) + 1 ) & 0x3ff;
}
-
- /* simulate decay */
- else
+ else // inactive clock transition
{
- m_filter *= m_decay;
+ if (m_shiftreg&1)
+ {
+ sum = ( ( ~std::max(2, m_sylfilter >> 6) ) + 1 ) & 0x3ff;
+ }
+ else
+ {
+ sum = std::max(2, m_sylfilter >> 6) & 0x3ff;
+ }
+ }
- if (m_filter < FILTER_MIN)
- m_filter = FILTER_MIN;
+ if (sum & 0x200)
+ sum |= ~0x3ff; // sign extend
+
+ if (!frozen)
+ {
+ m_intfilter += sum;
+ m_intfilter &= 0x3ff;
+ if (m_intfilter & 0x200) m_intfilter |= ~0x3ff; // sign extend
}
- /* compute the sample as a 32-bit word */
- temp = integrator * SAMPLE_GAIN;
- m_integrator = integrator;
+ /* scale the result (-512 to 511) to -32768 thru 32767 */
+ /*
+ F E D C B A 9 8 7 6 5 4 3 2 1 0
+ 9 8 7 6 5 4 3 2 1 0/9 8 7 6 5 4
+ */
+ m_next_sample = ( (m_intfilter << 6) | ( ((m_intfilter & 0x3ff) ^ 0x200 ) >> 4 ) );
- /* compress the sample range to fit better in a 16-bit word */
- if (temp < 0)
- m_next_sample = (int)(temp / (-temp * (1.0 / 32768.0) + 1.0));
+ // update agc state
+ if ( (m_intfilter >= 0x100) || (m_intfilter <= -0x100) )
+ m_agc = false;
else
- m_next_sample = (int)(temp / (temp * (1.0 / 32768.0) + 1.0));
+ m_agc = true;
+
+ // push agc state if a callback is present
+ if (!m_agc_push_cb.isnull())
+ m_agc_push_cb(m_agc);
}
-void hc55516_device::clock_w(int state)
+//-------------------------------------------------
+// sound_stream_update_legacy - handle a stream update
+//-------------------------------------------------
+
+void hc55516_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- uint8_t clock_state = state ? true : false;
+ auto &buffer = outputs[0];
- /* only makes sense for setups with a software driven clock */
- assert(!is_external_oscillator());
+/*
+ if (!is_external_oscillator())
+ {
+ // track how many samples we've updated without a clock; if it's been more than 1/32 of a second, output silence
+ m_samples_generated += buffer.samples();
+ if (m_samples_generated > SAMPLE_RATE / 32)
+ {
+ m_samples_generated = SAMPLE_RATE;
+ m_next_sample = 0;
+ }
+ }
+*/
- /* speech clock changing? */
- if (is_active_clock_transition(clock_state))
+ if (is_external_oscillator())
{
- /* update the output buffer before changing the registers */
- m_channel->update();
+ /* external oscillator */
+ for (int i = 0; i < buffer.samples(); i++)
+ {
+ buffer.put_int(i, m_next_sample, 32768);
- /* clear the update count */
- m_update_count = 0;
+ m_samples_generated++;
- process_digit();
+ uint8_t clock_state = current_clock_state();
+
+ /* pull in next digit on the appropriate edge of the clock */
+ if (is_clock_changed(clock_state))
+ {
+ process_bit(m_buffered_bit, clock_state);
+ }
+
+ m_last_clock_state = clock_state;
+ }
}
- /* update the clock */
- m_last_clock_state = clock_state;
+ /* software driven clock */
+ else
+ for (int i = 0; i < buffer.samples(); i++)
+ buffer.put_int(i, m_next_sample, 32768);
}
-void hc55516_device::digit_w(int digit)
+
+//#########################################
+// HC55532
+//#########################################
+DEFINE_DEVICE_TYPE(HC55532, hc55532_device, "hc55532", "HC-55532")
+
+hc55532_device::hc55532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : hc55516_device(mconfig, HC55532, tag, owner, clock, 0xf80, 7, 0xfe1, 5)
{
- if (is_external_oscillator())
- {
- m_channel->update();
- m_new_digit = digit & 1;
- }
- else
- m_digit = digit & 1;
}
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
-int hc55516_device::clock_state_r()
+void hc55532_device::device_reset()
{
- /* only makes sense for setups with an external oscillator */
- assert(is_external_oscillator());
+ cvsd_device_base::device_reset();
+ // simulate /FZ having been held for a while
+ m_sylfilter = 0x7f;
+ m_intfilter = 0;
+ m_agc = true;
+ m_buffered_fzq = true; // assuming /FZ was just released and is now high/inactive
+}
- m_channel->update();
- return current_clock_state();
+
+//##########################################
+// MC3417
+//##########################################
+DEFINE_DEVICE_TYPE(MC3417, mc3417_device, "mc3417", "MC3417")
+
+mc3417_device::mc3417_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mc3417_device(mconfig, MC3417, tag, owner, clock, 0x7)
+{
}
+// overridable type for mc3418 etc
+mc3417_device::mc3417_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t shiftreg_mask)
+ : cvsd_device_base(mconfig, type, tag, owner, clock, FALLING, shiftreg_mask)
+ , m_charge(pow(exp(-1.0), 1.0 / (FILTER_CHARGE_TC * 16000.0)))
+ , m_decay(pow(exp(-1.0), 1.0 / (FILTER_DECAY_TC * 16000.0)))
+ , m_leak(pow(exp(-1.0), 1.0 / (INTEGRATOR_LEAK_TC * 16000.0)))
+ , m_sylfilter_d(0.0)
+ , m_intfilter_d(0.0)
+{
+}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// device_start - device-specific startup
//-------------------------------------------------
-void hc55516_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mc3417_device::device_start()
{
- stream_sample_t *buffer = outputs[0];
- int i;
- int32_t sample, slope;
+ cvsd_device_base::device_start();
+ save_item(NAME(m_sylfilter_d));
+ save_item(NAME(m_intfilter_d));
+}
- /* zero-length? bail */
- if (samples == 0)
- return;
+void mc3417_device::process_bit(bool bit, bool clock_state)
+{
+ if (is_active_clock_transition(clock_state))
+ {
+
+ /* shift the new bit into the shift register */
+ m_shiftreg = (m_shiftreg << 1) | (bit?1:0);
+
+ /* move the estimator up or down a step based on the bit */
+ if (!bit)
+ m_intfilter_d += m_sylfilter_d;
+ else
+ m_intfilter_d -= m_sylfilter_d;
+
+ /* simulate leakage */
+ m_intfilter_d *= m_leak;
+
+ /* if we got all 0's or all 1's in the last n bits, bump the step up */
+ if (((m_shiftreg & m_shiftreg_mask) == 0) ||
+ ((m_shiftreg & m_shiftreg_mask) == m_shiftreg_mask))
+ {
+ // coincidence is true
+ m_sylfilter_d = FILTER_MAX - ((FILTER_MAX - m_sylfilter_d) * m_charge);
+
+ if (m_sylfilter_d > FILTER_MAX)
+ m_sylfilter_d = FILTER_MAX;
+ }
+ else
+ {
+ m_sylfilter_d *= m_decay;
+
+ if (m_sylfilter_d < FILTER_MIN)
+ m_sylfilter_d = FILTER_MIN;
+ }
+
+ /* compute the sample as a 32-bit word */
+ m_next_sample = m_intfilter_d * SAMPLE_GAIN;
+ }
+}
+
+void mc3417_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ auto &buffer = outputs[0];
if (!is_external_oscillator())
{
- /* track how many samples we've updated without a clock */
- m_update_count += samples;
- if (m_update_count > SAMPLE_RATE / 32)
+ /* track how many samples we've updated without a clock; if it's been more than 1/32 of a second, output silence */
+ m_samples_generated += buffer.samples();
+ if (m_samples_generated > SAMPLE_RATE / 32)
{
- m_update_count = SAMPLE_RATE;
+ m_samples_generated = SAMPLE_RATE;
m_next_sample = 0;
}
}
/* compute the interpolation slope */
- sample = m_curr_sample;
- slope = ((int32_t)m_next_sample - sample) / samples;
+ stream_buffer::sample_t sample = m_curr_sample;
+ stream_buffer::sample_t slope = (m_next_sample - sample) / buffer.samples();
m_curr_sample = m_next_sample;
if (is_external_oscillator())
{
/* external oscillator */
- for (i = 0; i < samples; i++, sample += slope)
+ for (int i = 0; i < buffer.samples(); i++, sample += slope)
{
- uint8_t clock_state;
-
- *buffer++ = sample;
+ buffer.put(i, sample);
- m_update_count++;
+ m_samples_generated++;
- clock_state = current_clock_state();
+ uint8_t clock_state = current_clock_state();
/* pull in next digit on the appropriate edge of the clock */
- if (is_active_clock_transition(clock_state))
+ if (is_clock_changed(clock_state))
{
- m_digit = m_new_digit;
-
- process_digit();
+ process_bit(m_buffered_bit, clock_state);
}
m_last_clock_state = clock_state;
@@ -297,16 +547,18 @@ void hc55516_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
/* software driven clock */
else
- for (i = 0; i < samples; i++, sample += slope)
- *buffer++ = sample;
+ for (int i = 0; i < buffer.samples(); i++, sample += slope)
+ buffer.put(i, sample);
}
-void mc3417_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
-{
- hc55516_device::sound_stream_update_legacy(stream, inputs, outputs, samples);
-}
-void mc3418_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+
+//##########################################
+// MC3418
+//##########################################
+DEFINE_DEVICE_TYPE(MC3418, mc3418_device, "mc3418", "MC3418")
+
+mc3418_device::mc3418_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mc3417_device(mconfig, MC3418, tag, owner, clock, 0xf)
{
- hc55516_device::sound_stream_update_legacy(stream, inputs, outputs, samples);
}
diff --git a/src/devices/sound/hc55516.h b/src/devices/sound/hc55516.h
index 96284167c52..48c1b768a4f 100644
--- a/src/devices/sound/hc55516.h
+++ b/src/devices/sound/hc55516.h
@@ -1,95 +1,176 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Jonathan Gevaryahu
+// thanks-to:Zonn Moore
#ifndef MAME_SOUND_HC55516_H
#define MAME_SOUND_HC55516_H
#pragma once
-class hc55516_device : public device_t, public device_sound_interface
+class cvsd_device_base : public device_t, public device_sound_interface
{
public:
- hc55516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
-
- /* sets the digit (0 or 1) */
- void digit_w(int digit);
-
- /* sets the clock state (0 or 1, clocked on the rising edge) */
- void clock_w(int state);
-
- /* returns whether the clock is currently LO or HI */
- int clock_state_r();
+ enum
+ {
+ RISING=true,
+ FALLING=false
+ };
+
+ auto clock_state_cb() { return m_clock_state_push_cb.bind(); } // A clock state change callback. Using this is a bad idea due to lack of synchronization to other devices. TODO: remove this.
+ auto digin_cb() { return m_digin_pull_cb.bind(); } // Digital in pull callback function, for use if a clock is specified and we need to pull in the digital in pin state, otherwise unused. TODO: this is not hooked up yet, and should be.
+ auto digout_cb() { return m_digout_push_cb.bind(); } // Digital out push callback function. TODO: this is not hooked up or implemented yet, although it is only really relevant for devices which use the CVSD chips in encode mode.
+
+ READ_LINE_MEMBER( clock_r ); // Clock pull, really only relevant of something manually polls the clock (and clock is specified), which is a very bad design pattern and will cause synchronization/missed clock transition issues. This function WILL ASSERT if it is called and the clock hz is NOT specified! TODO: remove all use of this, and remove it.
+ WRITE_LINE_MEMBER( mclock_w ); // Clock push; this function WILL ASSERT if it is called and the clock hz IS specified!
+ WRITE_LINE_MEMBER( digin_w ); // Digital in push to the pin, as a pseudo 'buffer' implemented within the cvsd device itself. This is not technically accurate to hardware, and in the future should be deprecated in favor of digin_cb once the latter is implemented.
+ WRITE_LINE_MEMBER( dec_encq_w ); //DEC/ENC decode/encode select push. This is not implemented yet, and relies on an input audio stream. TODO: implement this beyond a do-nothing stub
+ READ_LINE_MEMBER( digout_r ); // Digital out pull. TODO: this is not hooked up or implemented yet, although it is only really relevant for devices which use the CVSD chips in encode mode.
+ //void audio_in_w(stream_buffer::sample_t data); // Audio In pin, an analog value of the audio waveform being pushed to the chip. TODO: this is not hooked up or implemented yet, and this should really be handled as an input stream from a separate DAC device, not a value push function at all.
+ void digit_w(int digit); /* sets the buffered digit (0 or 1), common to all chips. TODO: replace all use of this with digin_cb once implemented */
+ void clock_w(int state); /* sets the clock state (0 or 1, clocked on the rising edge), common to all chips */
+ virtual int clock_state_r(); /* returns whether the clock is currently LO or HI, common to all chips. TODO: get rid of all use of this, then get rid of it. */
protected:
- hc55516_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+ cvsd_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool active_clock_edge, uint8_t shiftreg_mask);
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
+ //virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
- void start_common(uint8_t _shiftreg_mask, int _active_clock_hi);
+ // callbacks
+ devcb_write_line m_clock_state_push_cb; ///TODO: get rid of this, if you use it you should feel bad
+ devcb_read_line m_digin_pull_cb;
+ devcb_write_line m_digout_push_cb;
- // internal state
- sound_stream *m_channel;
- int m_active_clock_hi;
- uint8_t m_shiftreg_mask;
+ // const state defined by constructor
+ const bool m_active_clock_edge;
+ const uint8_t m_shiftreg_mask; // it may be desirable to allow this to be changed by the user under some circumstances
- uint8_t m_last_clock_state;
- uint8_t m_digit;
- uint8_t m_new_digit;
+ // internal state
+ sound_stream *m_stream;
+ bool m_last_clock_state;
+ bool m_buffered_bit;
uint8_t m_shiftreg;
+ stream_buffer::sample_t m_curr_sample;
+ stream_buffer::sample_t m_next_sample;
+ uint32_t m_samples_generated;
- int16_t m_curr_sample;
- int16_t m_next_sample;
+ // specific internal handler overrides, overridden by each chip
+ virtual void process_bit(bool bit, bool clock_state);
- uint32_t m_update_count;
+ ///TODO: get rid of these
+ inline bool is_external_oscillator();
+ inline bool is_clock_changed(bool clock_state);
+ inline bool is_active_clock_transition(bool clock_state);
+ inline bool current_clock_state();
- double m_filter;
- double m_integrator;
-
- double m_charge;
- double m_decay;
- double m_leak;
-
- inline int is_external_oscillator();
- inline int is_active_clock_transition(int clock_state);
- inline int current_clock_state();
- void process_digit();
};
-class mc3417_device : public hc55516_device
+class hc55516_device : public cvsd_device_base
{
public:
- mc3417_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ hc55516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto fzq_cb() { return m_fzq_pull_cb.bind(); } // /FZ (partial reset) pull callback, ok to leave unconnected (we assume it is pulled high)
+ auto agc_cb() { return m_agc_push_cb.bind(); } // AGC callback function, called to push the state if the AGC pin changes, ok to leave unconnected
+
+ WRITE_LINE_MEMBER( fzq_w ); // /FZ (partial reset) push
+ READ_LINE_MEMBER( agc_r ); // AGC pull
+ /* TODO: These are only relevant for encode mode, which isn't done yet! */
+ //WRITE_LINE_MEMBER( aptq_w ); // /APT (silence encoder output) push
+ //WRITE_LINE_MEMBER( dec_encq_w ); // DEC/ENC decode/encode select push
protected:
+ // overridable type for subclass
+ hc55516_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t sylmask, int32_t sylshift, int32_t syladd, int32_t intshift);
+
// device-level overrides
virtual void device_start() override;
+ virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+ // callbacks
+ devcb_write_line m_agc_push_cb;
+ devcb_read_line m_fzq_pull_cb;
+
+ // const coefficients defined by constructor
+ const uint32_t m_sylmask;
+ const int32_t m_sylshift;
+ const int32_t m_syladd;
+ const int32_t m_intshift;
+
+ // internal state
+ int32_t m_sylfilter;
+ int32_t m_intfilter;
+ bool m_agc;
+ bool m_buffered_fzq;
+
+ // internal handlers
+ virtual void process_bit(bool bit, bool clock_state) override;
};
-class mc3418_device : public hc55516_device
+class hc55532_device : public hc55516_device
{
public:
- mc3418_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ hc55532_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+protected:
+ // device-level overrides
+ virtual void device_reset() override;
+};
+
+
+class mc3417_device : public cvsd_device_base
+{
+public:
+ mc3417_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // override for clock_w
+ //virtual void clock_w(int state) override;
protected:
+ // overridable type for subclass
+ mc3417_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint8_t shiftreg_mask);
+
// device-level overrides
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+ // const coefficients defined by constructor; should these be adjustable by the user or externally defined, as they are implemented using a set of two small lowpass filters outside the chip?
+ const double m_charge;
+ const double m_decay;
+ const double m_leak;
+
+ // internal state
+ double m_sylfilter_d;
+ double m_intfilter_d;
+
+ // internal handlers
+ virtual void process_bit(bool bit, bool clock_state) override;
+};
+
+
+class mc3418_device : public mc3417_device
+{
+public:
+ mc3418_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
DECLARE_DEVICE_TYPE(HC55516, hc55516_device)
+DECLARE_DEVICE_TYPE(HC55532, hc55532_device)
+//DECLARE_DEVICE_TYPE(HC55536, hc55536_device)
+//DECLARE_DEVICE_TYPE(HC55564, hc55564_device)
DECLARE_DEVICE_TYPE(MC3417, mc3417_device)
+//DECLARE_DEVICE_TYPE(MC34115, mc34115_device)
DECLARE_DEVICE_TYPE(MC3418, mc3418_device)
#endif // MAME_SOUND_HC55516_H
diff --git a/src/devices/sound/huc6230.cpp b/src/devices/sound/huc6230.cpp
index fd2ef5b9689..31e143fea8c 100644
--- a/src/devices/sound/huc6230.cpp
+++ b/src/devices/sound/huc6230.cpp
@@ -21,12 +21,12 @@
constexpr int clamp(int val, int min, int max) { return std::min(max, std::max(min, val)); }
-void huc6230_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void huc6230_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
- outputs[0][i] = inputs[0][i];
- outputs[1][i] = inputs[1][i];
+ s32 samp0 = inputs[0].get(i) * 32768.0;
+ s32 samp1 = inputs[1].get(i) * 32768.0;
for (int adpcm = 0; adpcm < 2; adpcm++)
{
@@ -35,9 +35,12 @@ void huc6230_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
if (!channel->m_playing)
continue;
- outputs[0][i] = clamp(outputs[0][i] + ((channel->m_output * channel->m_lvol) >> 3), -32768, 32767);
- outputs[1][i] = clamp(outputs[1][i] + ((channel->m_output * channel->m_rvol) >> 3), -32768, 32767);
+ samp0 = clamp(samp0 + ((channel->m_output * channel->m_lvol) >> 3), -32768, 32767);
+ samp1 = clamp(samp1 + ((channel->m_output * channel->m_rvol) >> 3), -32768, 32767);
}
+
+ outputs[0].put_int(i, samp0, 32768);
+ outputs[1].put_int(i, samp1, 32768);
}
}
@@ -172,7 +175,7 @@ void huc6230_device::device_start()
m_vca_cb.resolve_safe();
- m_stream = stream_alloc_legacy(2, 2, clock() / 6);
+ m_stream = stream_alloc(2, 2, clock() / 6);
m_adpcm_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(huc6230_device::adpcm_timer),this));
for (int i = 0; i < 2; i++)
diff --git a/src/devices/sound/huc6230.h b/src/devices/sound/huc6230.h
index 27e67ce41a3..a2ca7824617 100644
--- a/src/devices/sound/huc6230.h
+++ b/src/devices/sound/huc6230.h
@@ -28,7 +28,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct adpcm_channel {
diff --git a/src/devices/sound/i5000.cpp b/src/devices/sound/i5000.cpp
index 747d5e96e19..6978b9336f3 100644
--- a/src/devices/sound/i5000.cpp
+++ b/src/devices/sound/i5000.cpp
@@ -44,7 +44,7 @@ void i5000snd_device::device_start()
m_lut_volume[0xff] = 0;
// create the stream
- m_stream = stream_alloc_legacy(0, 2, clock() / 0x400);
+ m_stream = stream_alloc(0, 2, clock() / 0x400);
m_rom_base = (uint16_t *)device().machine().root_device().memregion(":i5000snd")->base();
m_rom_mask = device().machine().root_device().memregion(":i5000snd")->bytes() / 2 - 1;
@@ -114,9 +114,9 @@ bool i5000snd_device::read_sample(int ch)
}
-void i5000snd_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void i5000snd_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
int32_t mix_l = 0;
int32_t mix_r = 0;
@@ -157,8 +157,8 @@ void i5000snd_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
mix_l += m_channels[ch].output_l;
}
- outputs[0][i] = mix_r / 16;
- outputs[1][i] = mix_l / 16;
+ outputs[0].put_int(i, mix_r, 32768 * 16);
+ outputs[1].put_int(i, mix_l, 32768 * 16);
}
}
diff --git a/src/devices/sound/i5000.h b/src/devices/sound/i5000.h
index 0bb994ebdb6..abd84f5ac43 100644
--- a/src/devices/sound/i5000.h
+++ b/src/devices/sound/i5000.h
@@ -33,7 +33,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
sound_stream *m_stream;
diff --git a/src/devices/sound/ics2115.cpp b/src/devices/sound/ics2115.cpp
index fa570814019..868bcb70bc4 100644
--- a/src/devices/sound/ics2115.cpp
+++ b/src/devices/sound/ics2115.cpp
@@ -63,7 +63,7 @@ void ics2115_device::device_start()
m_timer[0].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_0),this), this);
m_timer[1].timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ics2115_device::timer_cb_1),this), this);
- m_stream = stream_alloc_legacy(0, 2, clock() / (32 * 32));
+ m_stream = stream_alloc(0, 2, clock() / (32 * 32));
m_irq_cb.resolve_safe();
@@ -316,7 +316,7 @@ int ics2115_device::ics2115_voice::update_oscillator()
}
//TODO: proper interpolation for 8-bit samples (looping)
-stream_sample_t ics2115_device::get_sample(ics2115_voice& voice)
+s32 ics2115_device::get_sample(ics2115_voice& voice)
{
const u32 curaddr = voice.osc.acc >> 12;
u32 nextaddr;
@@ -385,13 +385,13 @@ void ics2115_device::ics2115_voice::update_ramp()
}
}
-int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t * const outputs[2], int samples)
+int ics2115_device::fill_output(ics2115_voice& voice, std::vector<write_stream_view> &outputs)
{
bool irq_invalid = false;
const u16 fine = 1 << (3*(voice.vol.incr >> 6));
voice.vol.add = (voice.vol.incr & 0x3f)<< (10 - fine);
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
const u32 volacc = (voice.vol.acc >> 10) & 0xffff;
const u32 volume = (m_volume[volacc >> 4] * voice.state.ramp) >> 6;
@@ -403,15 +403,15 @@ int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t * const ou
//final output, even if they are not running. This means that whatever data value
//that the voice is pointing at is contributing to the summation.
//(austere note: this will of course fix some of the glitches due to multiple transition)
- stream_sample_t sample = get_sample(voice);
+ s32 sample = get_sample(voice);
//15-bit volume + (5-bit worth of 32 channel sum) + 16-bit samples = 4-bit extra
if (!m_vmode || voice.playing())
{
/*if (voice.playing())
{*/
- outputs[0][i] += (sample * vleft) >> (5 + volume_bits - 16);
- outputs[1][i] += (sample * vright) >> (5 + volume_bits - 16);
+ outputs[0].add_int(i, (sample * vleft) >> (5 + volume_bits), 32768);
+ outputs[1].add_int(i, (sample * vright) >> (5 + volume_bits), 32768);
}
voice.update_ramp();
@@ -426,10 +426,10 @@ int ics2115_device::fill_output(ics2115_voice& voice, stream_sample_t * const ou
return irq_invalid;
}
-void ics2115_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ics2115_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- memset(outputs[0], 0, samples * sizeof(stream_sample_t));
- memset(outputs[1], 0, samples * sizeof(stream_sample_t));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
bool irq_invalid = false;
for (int osc = 0; osc <= m_active_osc; osc++)
@@ -443,11 +443,11 @@ void ics2115_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
/*
#ifdef ICS2115_DEBUG
u32 curaddr = ((voice.osc.saddr << 20) & 0xffffff) | (voice.osc.acc >> 12);
- stream_sample_t sample = get_sample(voice);
+ s32 sample = get_sample(voice);
logerror("[%06x=%04x]", curaddr, (s16)sample);
#endif
*/
- if (fill_output(voice, outputs, samples))
+ if (fill_output(voice, outputs))
irq_invalid = true;
#ifdef ICS2115_DEBUG
@@ -479,13 +479,6 @@ void ics2115_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
logerror("|");
#endif
- //rescale
- for (int i = 0; i < samples; i++)
- {
- outputs[0][i] >>= 16;
- outputs[1][i] >>= 16;
- }
-
if (irq_invalid)
recalc_irq();
diff --git a/src/devices/sound/ics2115.h b/src/devices/sound/ics2115.h
index 777ee8eabf4..5dd18fcf4ed 100644
--- a/src/devices/sound/ics2115.h
+++ b/src/devices/sound/ics2115.h
@@ -39,7 +39,7 @@ protected:
virtual void device_clock_changed() override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_memory_interface configuration
virtual space_config_vector memory_space_config() const override;
@@ -119,8 +119,8 @@ private:
void recalc_irq();
// stream helper functions
- int fill_output(ics2115_voice& voice, stream_sample_t * const outputs[2], int samples);
- stream_sample_t get_sample(ics2115_voice& voice);
+ int fill_output(ics2115_voice& voice, std::vector<write_stream_view> &outputs);
+ s32 get_sample(ics2115_voice& voice);
u8 read_sample(ics2115_voice& voice, u32 addr) { return m_cache.read_byte((voice.osc.saddr << 20) | (addr & 0xfffff)); }
sound_stream *m_stream;
diff --git a/src/devices/sound/iopspu.cpp b/src/devices/sound/iopspu.cpp
index 73399b1ef2c..0267c31eadb 100644
--- a/src/devices/sound/iopspu.cpp
+++ b/src/devices/sound/iopspu.cpp
@@ -89,9 +89,10 @@ void iop_spu_device::dma_done(int bank)
core.m_status &= ~STATUS_DMA_ACTIVE;
}
-void iop_spu_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void iop_spu_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// TODO
+ outputs[0].fill(0);
}
TIMER_CALLBACK_MEMBER(iop_spu_device::autodma_done_timer_hack)
diff --git a/src/devices/sound/iopspu.h b/src/devices/sound/iopspu.h
index 4348e471051..bea55615c04 100644
--- a/src/devices/sound/iopspu.h
+++ b/src/devices/sound/iopspu.h
@@ -48,7 +48,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// HACK: This timer is currently used to trigger an interrupt after the auto-DMA-transferred buffer would have been
// mixed and played back, as the PS2 BIOS pulls a null return address and crashes if we trigger the auto-DMA-complete
diff --git a/src/devices/sound/iremga20.cpp b/src/devices/sound/iremga20.cpp
index ba49eaa75c4..3ec07d3de35 100644
--- a/src/devices/sound/iremga20.cpp
+++ b/src/devices/sound/iremga20.cpp
@@ -73,7 +73,7 @@ iremga20_device::iremga20_device(const machine_config &mconfig, const char *tag,
void iremga20_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, clock()/4);
+ m_stream = stream_alloc(0, 2, clock()/4);
save_item(NAME(m_regs));
for (int i = 0; i < 4; i++)
@@ -126,19 +126,17 @@ void iremga20_device::rom_bank_updated()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void iremga20_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void iremga20_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outL, *outR;
+ auto &outL = outputs[0];
+ auto &outR = outputs[1];
- outL = outputs[0];
- outR = outputs[1];
-
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outL.samples(); i++)
{
- stream_sample_t sampleout = 0;
+ s32 sampleout = 0;
for (auto &ch : m_channel)
{
@@ -160,9 +158,8 @@ void iremga20_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
}
}
- sampleout >>= 2;
- outL[i] = sampleout;
- outR[i] = sampleout;
+ outL.put_int(i, sampleout, 32768 * 4);
+ outR.put_int(i, sampleout, 32768 * 4);
}
}
diff --git a/src/devices/sound/iremga20.h b/src/devices/sound/iremga20.h
index df9942c9ccb..ae60c563d78 100644
--- a/src/devices/sound/iremga20.h
+++ b/src/devices/sound/iremga20.h
@@ -36,7 +36,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/k005289.cpp b/src/devices/sound/k005289.cpp
index bf07743f7d3..00fe18e2c2f 100644
--- a/src/devices/sound/k005289.cpp
+++ b/src/devices/sound/k005289.cpp
@@ -59,9 +59,7 @@ k005289_device::k005289_device(const machine_config &mconfig, const char *tag, d
, m_sound_prom(*this, DEVICE_SELF)
, m_stream(nullptr)
, m_rate(0)
- , m_mixer_table(nullptr)
, m_mixer_lookup(nullptr)
- , m_mixer_buffer(nullptr)
{
}
@@ -74,10 +72,7 @@ void k005289_device::device_start()
{
/* get stream channels */
m_rate = clock() / CLOCK_DIVIDER;
- m_stream = stream_alloc_legacy(0, 1, m_rate);
-
- /* allocate a pair of buffers to mix into - 1 second's worth should be more than enough */
- m_mixer_buffer = std::make_unique<short[]>(2 * m_rate);
+ m_stream = stream_alloc(0, 1, m_rate);
/* build the mixer table */
make_mixer_table(2);
@@ -101,17 +96,19 @@ void k005289_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void k005289_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void k005289_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
short *mix;
int i,v,f;
/* zap the contents of the mixer buffer */
- memset(m_mixer_buffer.get(), 0, samples * sizeof(int16_t));
+ if (m_mixer_buffer.size() < buffer.samples())
+ m_mixer_buffer.resize(buffer.samples());
+ std::fill_n(&m_mixer_buffer[0], buffer.samples(), 0);
v=m_volume[0];
f=m_frequency[0];
@@ -120,10 +117,10 @@ void k005289_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
const unsigned char *w = &m_sound_prom[m_waveform[0]];
int c = m_counter[0];
- mix = m_mixer_buffer.get();
+ mix = &m_mixer_buffer[0];
/* add our contribution */
- for (i = 0; i < samples; i++)
+ for (i = 0; i < buffer.samples(); i++)
{
int offs;
@@ -143,10 +140,10 @@ void k005289_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
const unsigned char *w = &m_sound_prom[m_waveform[1]];
int c = m_counter[1];
- mix = m_mixer_buffer.get();
+ mix = &m_mixer_buffer[0];
/* add our contribution */
- for (i = 0; i < samples; i++)
+ for (i = 0; i < buffer.samples(); i++)
{
int offs;
@@ -160,9 +157,9 @@ void k005289_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
}
/* mix it down */
- mix = m_mixer_buffer.get();
- for (i = 0; i < samples; i++)
- *buffer++ = m_mixer_lookup[*mix++];
+ mix = &m_mixer_buffer[0];
+ for (i = 0; i < buffer.samples(); i++)
+ buffer.put(i, m_mixer_lookup[*mix++]);
}
@@ -174,22 +171,22 @@ void k005289_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
void k005289_device::make_mixer_table(int voices)
{
int count = voices * 128;
- int i;
int gain = 16;
/* allocate memory */
- m_mixer_table = std::make_unique<int16_t[]>(256 * voices);
+ m_mixer_table = std::make_unique<stream_buffer::sample_t []>(256 * voices);
/* find the middle of the table */
- m_mixer_lookup = m_mixer_table.get() + (128 * voices);
+ m_mixer_lookup = &m_mixer_table[128 * voices];
/* fill in the table - 16 bit case */
- for (i = 0; i < count; i++)
+ for (int i = 0; i < count; i++)
{
int val = i * gain * 16 / voices;
if (val > 32767) val = 32767;
- m_mixer_lookup[ i] = val;
- m_mixer_lookup[-i] = -val;
+ stream_buffer::sample_t fval = stream_buffer::sample_t(val) / 32768.0;
+ m_mixer_lookup[ i] = fval;
+ m_mixer_lookup[-i] = -fval;
}
}
diff --git a/src/devices/sound/k005289.h b/src/devices/sound/k005289.h
index a8dc7b1d0b0..989ab15ae6d 100644
--- a/src/devices/sound/k005289.h
+++ b/src/devices/sound/k005289.h
@@ -26,7 +26,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void make_mixer_table(int voices);
@@ -36,9 +36,9 @@ private:
int m_rate;
/* mixer tables and internal buffers */
- std::unique_ptr<int16_t[]> m_mixer_table;
- int16_t *m_mixer_lookup;
- std::unique_ptr<short[]> m_mixer_buffer;
+ std::unique_ptr<stream_buffer::sample_t []> m_mixer_table;
+ stream_buffer::sample_t *m_mixer_lookup;
+ std::vector<short> m_mixer_buffer;
uint32_t m_counter[2];
uint16_t m_frequency[2];
diff --git a/src/devices/sound/k007232.cpp b/src/devices/sound/k007232.cpp
index 3b35eeb9d5c..a8b6c135a51 100644
--- a/src/devices/sound/k007232.cpp
+++ b/src/devices/sound/k007232.cpp
@@ -86,7 +86,7 @@ void k007232_device::device_start()
for (auto & elem : m_wreg)
elem = 0;
- m_stream = stream_alloc_legacy(0, 2, clock()/128);
+ m_stream = stream_alloc(0, 2, clock()/128);
save_item(STRUCT_MEMBER(m_channel, vol));
save_item(STRUCT_MEMBER(m_channel, addr));
@@ -206,14 +206,11 @@ void k007232_device::set_bank(int chan_a_bank, int chan_b_bank)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void k007232_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void k007232_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- memset(outputs[0], 0, samples * sizeof(stream_sample_t));
- memset(outputs[1], 0, samples * sizeof(stream_sample_t));
-
if (K007232_LOG_PCM)
{
for (int i = 0; i < KDAC_A_PCM_MAX; i++)
@@ -239,8 +236,9 @@ void k007232_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
}
}
- for (int j = 0; j < samples; j++)
+ for (int j = 0; j < outputs[0].samples(); j++)
{
+ s32 lsum = 0, rsum = 0;
for (int i = 0; i < KDAC_A_PCM_MAX; i++)
{
channel_t *channel = &m_channel[i];
@@ -279,9 +277,11 @@ void k007232_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
int out = (read_sample(i, addr) & 0x7f) - 0x40;
- outputs[0][j] += out * vol_a;
- outputs[1][j] += out * vol_b;
+ lsum += out * vol_a;
+ rsum += out * vol_b;
}
}
+ outputs[0].put_int(j, lsum, 32768);
+ outputs[1].put_int(j, rsum, 32768);
}
}
diff --git a/src/devices/sound/k007232.h b/src/devices/sound/k007232.h
index e9a4ba255da..57cb72fcf7b 100644
--- a/src/devices/sound/k007232.h
+++ b/src/devices/sound/k007232.h
@@ -37,7 +37,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_memory_interface configuration
virtual space_config_vector memory_space_config() const override;
diff --git a/src/devices/sound/k051649.cpp b/src/devices/sound/k051649.cpp
index 0e39a94230a..9a1f748580e 100644
--- a/src/devices/sound/k051649.cpp
+++ b/src/devices/sound/k051649.cpp
@@ -56,7 +56,6 @@ k051649_device::k051649_device(const machine_config &mconfig, const char *tag, d
, device_sound_interface(mconfig, *this)
, m_stream(nullptr)
, m_rate(0)
- , m_mixer_table(nullptr)
, m_mixer_lookup(nullptr)
, m_test(0)
{
@@ -71,7 +70,7 @@ void k051649_device::device_start()
{
// get stream channels
m_rate = clock()/16;
- m_stream = stream_alloc_legacy(0, 1, m_rate);
+ m_stream = stream_alloc(0, 1, m_rate);
// allocate a buffer to mix into - 1 second's worth should be more than enough
m_mixer_buffer.resize(2 * m_rate);
@@ -140,10 +139,10 @@ void k051649_device::device_clock_changed()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void k051649_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void k051649_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// zap the contents of the mixer buffer
std::fill(m_mixer_buffer.begin(), m_mixer_buffer.end(), 0);
@@ -159,7 +158,7 @@ void k051649_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
const int step = voice.frequency;
// add our contribution
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
c += 32;
while (c > step)
@@ -177,9 +176,9 @@ void k051649_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
}
// mix it down
- stream_sample_t *buffer = outputs[0];
- for (int i = 0; i < samples; i++)
- *buffer++ = m_mixer_lookup[m_mixer_buffer[i]];
+ auto &buffer = outputs[0];
+ for (int i = 0; i < buffer.samples(); i++)
+ buffer.put(i, m_mixer_lookup[m_mixer_buffer[i]]);
}
@@ -309,16 +308,17 @@ u8 k051649_device::k051649_test_r()
void k051649_device::make_mixer_table(int voices)
{
// allocate memory
- m_mixer_table = std::make_unique<s16[]>(512 * voices);
+ m_mixer_table.resize(512 * voices);
// find the middle of the table
- m_mixer_lookup = m_mixer_table.get() + (256 * voices);
+ m_mixer_lookup = &m_mixer_table[256 * voices];
// fill in the table - 16 bit case
for (int i = 0; i < (voices * 256); i++)
{
const int val = std::min(32767, i * DEF_GAIN * 16 / voices);
- m_mixer_lookup[ i] = val;
- m_mixer_lookup[-i] = -val;
+ stream_buffer::sample_t fval = stream_buffer::sample_t(val) / 32768.0;
+ m_mixer_lookup[ i] = fval;
+ m_mixer_lookup[-i] = -fval;
}
}
diff --git a/src/devices/sound/k051649.h b/src/devices/sound/k051649.h
index 2fda5936685..368ef6c58a9 100644
--- a/src/devices/sound/k051649.h
+++ b/src/devices/sound/k051649.h
@@ -38,7 +38,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// Parameters for a channel
@@ -71,8 +71,8 @@ private:
int m_rate;
/* mixer tables and internal buffers */
- std::unique_ptr<s16[]> m_mixer_table;
- s16 *m_mixer_lookup;
+ std::vector<stream_buffer::sample_t> m_mixer_table;
+ stream_buffer::sample_t *m_mixer_lookup;
std::vector<s16> m_mixer_buffer;
/* chip registers */
diff --git a/src/devices/sound/k053260.cpp b/src/devices/sound/k053260.cpp
index ff2356ac600..7337b0c8b91 100644
--- a/src/devices/sound/k053260.cpp
+++ b/src/devices/sound/k053260.cpp
@@ -115,7 +115,7 @@ void k053260_device::device_start()
m_sh1_cb.resolve_safe();
m_sh2_cb.resolve_safe();
- m_stream = stream_alloc_legacy( 0, 2, clock() / CLOCKS_PER_SAMPLE );
+ m_stream = stream_alloc( 0, 2, clock() / CLOCKS_PER_SAMPLE );
/* register with the save state system */
save_item(NAME(m_portdata));
@@ -301,25 +301,17 @@ void k053260_device::write(offs_t offset, u8 data)
}
}
-static inline int limit(int val, int max, int min)
-{
- return std::max(min, std::min(max, val));
-}
-
-static constexpr s32 MAXOUT = 0x7fff;
-static constexpr s32 MINOUT = -0x8000;
-
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void k053260_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void k053260_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
if (m_mode & 2)
{
- for ( int j = 0; j < samples; j++ )
+ for ( int j = 0; j < outputs[0].samples(); j++ )
{
- stream_sample_t buffer[2] = {0, 0};
+ s32 buffer[2] = {0, 0};
for (auto & voice : m_voice)
{
@@ -327,14 +319,14 @@ void k053260_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
voice.play(buffer);
}
- outputs[0][j] = limit( buffer[0], MAXOUT, MINOUT );
- outputs[1][j] = limit( buffer[1], MAXOUT, MINOUT );
+ outputs[0].put_int_clamp(j, buffer[0], 32768);
+ outputs[1].put_int_clamp(j, buffer[1], 32768);
}
}
else
{
- std::fill_n(&outputs[0][0], samples, 0);
- std::fill_n(&outputs[1][0], samples, 0);
+ outputs[0].fill(0);
+ outputs[1].fill(0);
}
}
@@ -429,7 +421,7 @@ void k053260_device::KDSC_Voice::update_pan_volume()
void k053260_device::KDSC_Voice::key_on()
{
m_position = m_kadpcm ? 1 : 0; // for kadpcm low bit is nybble offset, so must start at 1 due to preincrement
- m_counter = 0x1000 - CLOCKS_PER_SAMPLE; // force update on next sound_stream_update_legacy
+ m_counter = 0x1000 - CLOCKS_PER_SAMPLE; // force update on next sound_stream_update
m_output = 0;
m_playing = true;
if (LOG) m_device.logerror("K053260: start = %06x, length = %06x, pitch = %04x, vol = %02x:%x, loop = %s, %s\n",
@@ -443,7 +435,7 @@ void k053260_device::KDSC_Voice::key_off()
m_playing = false;
}
-void k053260_device::KDSC_Voice::play(stream_sample_t *outputs)
+void k053260_device::KDSC_Voice::play(s32 *outputs)
{
m_counter += CLOCKS_PER_SAMPLE;
diff --git a/src/devices/sound/k053260.h b/src/devices/sound/k053260.h
index 4288b603d5a..ad14244ceb9 100644
--- a/src/devices/sound/k053260.h
+++ b/src/devices/sound/k053260.h
@@ -42,7 +42,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
@@ -79,7 +79,7 @@ private:
inline void update_pan_volume();
inline void key_on();
inline void key_off();
- inline void play(stream_sample_t *outputs);
+ inline void play(s32 *outputs);
inline bool playing() { return m_playing; }
inline u8 read_rom(bool side_effects);
diff --git a/src/devices/sound/k054539.cpp b/src/devices/sound/k054539.cpp
index 2ed7dc134a2..cba942e002f 100644
--- a/src/devices/sound/k054539.cpp
+++ b/src/devices/sound/k054539.cpp
@@ -23,7 +23,6 @@ k054539_device::k054539_device(const machine_config &mconfig, const char *tag, d
, device_sound_interface(mconfig, *this)
, device_rom_interface(mconfig, *this)
, flags(0)
- , ram(nullptr)
, reverb_pos(0)
, cur_ptr(0)
, cur_limit(0)
@@ -115,7 +114,7 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
};
- int16_t *rbase = (int16_t *)ram.get();
+ int16_t *rbase = (int16_t *)&ram[0];
if(!(regs[0x22f] & 1))
{
@@ -124,7 +123,6 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
return;
}
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for(int sample = 0; sample != outputs[0].samples(); sample++) {
double lval, rval;
if(!(flags & DISABLE_REVERB))
@@ -303,8 +301,8 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
}
}
reverb_pos = (reverb_pos + 1) & 0x1fff;
- outputs[0].put(sample, stream_buffer::sample_t(lval) * sample_scale);
- outputs[1].put(sample, stream_buffer::sample_t(rval) * sample_scale);
+ outputs[0].put_int(sample, lval, 32768);
+ outputs[1].put_int(sample, rval, 32768);
}
}
@@ -321,10 +319,11 @@ void k054539_device::init_chip()
memset(posreg_latch, 0, sizeof(posreg_latch)); //*
flags |= UPDATE_AT_KEYON; //* make it default until proven otherwise
- ram = std::make_unique<uint8_t[]>(0x4000);
+ ram = std::make_unique<uint8_t []>(0x4000);
+
reverb_pos = 0;
cur_ptr = 0;
- memset(ram.get(), 0, 0x4000);
+ memset(&ram[0], 0, 0x4000);
stream = stream_alloc(0, 2, clock() / 384);
@@ -553,7 +552,7 @@ void k054539_device::device_reset()
{
regs[0x22c] = 0;
regs[0x22f] = 0;
- memset(ram.get(), 0, 0x4000);
+ memset(&ram[0], 0, 0x4000);
m_timer->enable(false);
}
diff --git a/src/devices/sound/k054539.h b/src/devices/sound/k054539.h
index 6e4b6c10c8c..6c79ac6d0be 100644
--- a/src/devices/sound/k054539.h
+++ b/src/devices/sound/k054539.h
@@ -88,7 +88,7 @@ private:
int flags;
unsigned char regs[0x230];
- std::unique_ptr<uint8_t[]> ram;
+ std::unique_ptr<uint8_t []> ram;
int reverb_pos;
int32_t cur_ptr;
diff --git a/src/devices/sound/ks0164.cpp b/src/devices/sound/ks0164.cpp
index 5280af611f6..2086b014478 100644
--- a/src/devices/sound/ks0164.cpp
+++ b/src/devices/sound/ks0164.cpp
@@ -50,7 +50,7 @@ void ks0164_device::device_start()
space().install_rom(0, rend, ((1 << 23) - 1) ^ rmask, m_mem_region->base());
}
- m_stream = stream_alloc_legacy(0, 2, clock()/3/2/2/32);
+ m_stream = stream_alloc(0, 2, clock()/3/2/2/32);
space().cache(m_mem_cache);
m_timer = timer_alloc(0);
@@ -368,9 +368,9 @@ u16 ks0164_device::uncomp_8_16(u8 value)
return o;
}
-void ks0164_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ks0164_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for(int sample = 0; sample != samples; sample++) {
+ for(int sample = 0; sample != outputs[0].samples(); sample++) {
s32 suml = 0, sumr = 0;
for(int voice = 0; voice < 0x20; voice++) {
u16 *regs = m_sregs[voice];
@@ -415,7 +415,7 @@ void ks0164_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
sumr += samp;
}
}
- outputs[0][sample] = suml >> 5;
- outputs[1][sample] = sumr >> 5;
+ outputs[0].put_int(sample, suml, 32768 * 32);
+ outputs[1].put_int(sample, sumr, 32768 * 32);
}
}
diff --git a/src/devices/sound/ks0164.h b/src/devices/sound/ks0164.h
index a668753f250..cc707699f2e 100644
--- a/src/devices/sound/ks0164.h
+++ b/src/devices/sound/ks0164.h
@@ -23,7 +23,7 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void device_add_mconfig(machine_config &config) override;
virtual space_config_vector memory_space_config() const override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
diff --git a/src/devices/sound/l7a1045_l6028_dsp_a.cpp b/src/devices/sound/l7a1045_l6028_dsp_a.cpp
index 280d12a20d9..7f567f86cbb 100644
--- a/src/devices/sound/l7a1045_l6028_dsp_a.cpp
+++ b/src/devices/sound/l7a1045_l6028_dsp_a.cpp
@@ -117,7 +117,7 @@ l7a1045_sound_device::l7a1045_sound_device(const machine_config &mconfig, const
void l7a1045_sound_device::device_start()
{
/* Allocate the stream */
- m_stream = stream_alloc_legacy(0, 2, 66150); //clock() / 384);
+ m_stream = stream_alloc(0, 2, 66150); //clock() / 384);
for (int voice = 0; voice < 32; voice++)
{
@@ -143,14 +143,14 @@ void l7a1045_sound_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void l7a1045_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void l7a1045_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
/* Clear the buffers */
- memset(outputs[0], 0, samples*sizeof(*outputs[0]));
- memset(outputs[1], 0, samples*sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
for (int i = 0; i < 32; i++)
{
@@ -165,7 +165,7 @@ void l7a1045_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
uint32_t pos = vptr->pos;
uint32_t frac = vptr->frac;
- for (int j = 0; j < samples; j++)
+ for (int j = 0; j < outputs[0].samples(); j++)
{
int32_t sample;
uint8_t data;
@@ -192,8 +192,8 @@ void l7a1045_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
sample = ((int8_t)(data & 0xfc)) << (3 - (data & 3));
frac += step;
- outputs[0][j] += ((sample * vptr->l_volume) >> 9);
- outputs[1][j] += ((sample * vptr->r_volume) >> 9);
+ outputs[0].add_int(j, sample * vptr->l_volume, 32768 * 512);
+ outputs[1].add_int(j, sample * vptr->r_volume, 32768 * 512);
}
vptr->pos = pos;
diff --git a/src/devices/sound/l7a1045_l6028_dsp_a.h b/src/devices/sound/l7a1045_l6028_dsp_a.h
index bc9c3b5d500..542b6aad386 100644
--- a/src/devices/sound/l7a1045_l6028_dsp_a.h
+++ b/src/devices/sound/l7a1045_l6028_dsp_a.h
@@ -33,7 +33,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct l7a1045_voice
diff --git a/src/devices/sound/lmc1992.cpp b/src/devices/sound/lmc1992.cpp
index ad412395d9d..cf0d8f35d33 100644
--- a/src/devices/sound/lmc1992.cpp
+++ b/src/devices/sound/lmc1992.cpp
@@ -171,12 +171,13 @@ void lmc1992_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void lmc1992_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void lmc1992_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
diff --git a/src/devices/sound/lmc1992.h b/src/devices/sound/lmc1992.h
index cfaffc1f13f..beb893d9983 100644
--- a/src/devices/sound/lmc1992.h
+++ b/src/devices/sound/lmc1992.h
@@ -71,7 +71,7 @@ protected:
virtual void device_start() override;
// internal callbacks
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
inline void execute_command(int addr, int data);
diff --git a/src/devices/sound/mas3507d.cpp b/src/devices/sound/mas3507d.cpp
index 641ec52a06e..a5b7a7917d2 100644
--- a/src/devices/sound/mas3507d.cpp
+++ b/src/devices/sound/mas3507d.cpp
@@ -29,7 +29,7 @@ mas3507d_device::mas3507d_device(const machine_config &mconfig, const char *tag,
void mas3507d_device::device_start()
{
current_rate = 44100;
- stream = stream_alloc_legacy(0, 2, current_rate);
+ stream = stream_alloc(0, 2, current_rate);
cb_sample.resolve();
}
@@ -359,11 +359,8 @@ void mas3507d_device::fill_buffer()
}
}
-void mas3507d_device::append_buffer(stream_sample_t * const *outputs, int &pos, int scount)
+void mas3507d_device::append_buffer(std::vector<write_stream_view> &outputs, int &pos, int scount)
{
- if(!sample_count)
- return;
-
buffered_frame_count = scount;
int s1 = scount - pos;
@@ -372,14 +369,13 @@ void mas3507d_device::append_buffer(stream_sample_t * const *outputs, int &pos,
if(mp3_info.channels == 1) {
for(int i=0; i<s1; i++) {
- stream_sample_t v = samples[i];
- outputs[0][i+pos] = v;
- outputs[1][i+pos] = v;
+ outputs[0].put_int(i+pos, samples[i], 32768);
+ outputs[1].put_int(i+pos, samples[i], 32768);
}
} else {
for(int i=0; i<s1; i++) {
- outputs[0][i+pos] = samples[i*2];
- outputs[1][i+pos] = samples[i*2+1];
+ outputs[0].put_int(i+pos, samples[i*2], 32768);
+ outputs[1].put_int(i+pos, samples[i*2+1], 32768);
}
}
@@ -400,8 +396,9 @@ void mas3507d_device::append_buffer(stream_sample_t * const *outputs, int &pos,
total_frame_count += s1;
}
-void mas3507d_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int csamples)
+void mas3507d_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ int csamples = outputs[0].samples();
int pos = 0;
append_buffer(outputs, pos, csamples);
@@ -419,10 +416,8 @@ void mas3507d_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
total_frame_count = 0;
buffered_frame_count = 0;
- for(int i=pos; i != csamples; i++) {
- outputs[0][i] = 0;
- outputs[1][i] = 0;
- }
+ outputs[0].fill(0, pos);
+ outputs[1].fill(0, pos);
return;
}
append_buffer(outputs, pos, csamples);
diff --git a/src/devices/sound/mas3507d.h b/src/devices/sound/mas3507d.h
index 31410fa576e..b04e157e2f2 100644
--- a/src/devices/sound/mas3507d.h
+++ b/src/devices/sound/mas3507d.h
@@ -27,7 +27,7 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
devcb_read16 cb_sample;
@@ -63,7 +63,7 @@ private:
void reg_write(uint32_t adr, uint32_t val);
void fill_buffer();
- void append_buffer(stream_sample_t * const *outputs, int &pos, int samples);
+ void append_buffer(std::vector<write_stream_view> &outputs, int &pos, int samples);
};
diff --git a/src/devices/sound/mea8000.cpp b/src/devices/sound/mea8000.cpp
index 4f7fbc453ac..3cf2ad51a6e 100644
--- a/src/devices/sound/mea8000.cpp
+++ b/src/devices/sound/mea8000.cpp
@@ -134,7 +134,7 @@ void mea8000_device::device_start()
init_tables();
- m_stream = stream_alloc_legacy(0, 1, clock() / 60);
+ m_stream = stream_alloc(0, 1, clock() / 60);
save_item(NAME(m_output));
m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mea8000_device::timer_expire),this));
@@ -422,12 +422,9 @@ void mea8000_device::stop_frame()
-void mea8000_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mea8000_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int samp = 0; samp < samples; samp++)
- {
- outputs[0][samp] = m_output;
- }
+ outputs[0].fill(stream_buffer::sample_t(m_output) * (1.0 / 32768.0));
}
/* next sample in frame, sampling at 64 kHz */
diff --git a/src/devices/sound/mea8000.h b/src/devices/sound/mea8000.h
index 14cb0384d09..7538bffa62c 100644
--- a/src/devices/sound/mea8000.h
+++ b/src/devices/sound/mea8000.h
@@ -29,7 +29,7 @@ public:
protected:
// device-level overrides
virtual void device_start() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
/* filter coefficients from frequencies */
@@ -111,7 +111,7 @@ private:
emu_timer *m_timer = nullptr;
sound_stream * m_stream = nullptr;
- stream_sample_t m_output = 0;
+ int32_t m_output = 0;
int m_cos_table[TABLE_LEN]; /* fm => cos coefficient */
int m_exp_table[TABLE_LEN]; /* bw => exp coefficient */
diff --git a/src/devices/sound/mm5837.cpp b/src/devices/sound/mm5837.cpp
index 7b59758fdcd..6049b64d0fe 100644
--- a/src/devices/sound/mm5837.cpp
+++ b/src/devices/sound/mm5837.cpp
@@ -13,21 +13,15 @@
//**************************************************************************
-// CONSTEXPR DEFINITIONS
-//**************************************************************************
-
-constexpr int mm5837_device::m_frequency[];
-
-
-//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(MM5837, mm5837_device, "mm5837", "MM5837 Digital Noise Source")
+DEFINE_DEVICE_TYPE(MM5837_STREAM, mm5837_stream_device, "mm5837_stream", "MM5837 Digital Noise Stream")
//**************************************************************************
-// LIVE DEVICE
+// MM5837 DEVICE
//**************************************************************************
//-------------------------------------------------
@@ -37,12 +31,12 @@ DEFINE_DEVICE_TYPE(MM5837, mm5837_device, "mm5837", "MM5837 Digital Noise Source
mm5837_device::mm5837_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, MM5837, tag, owner, clock),
m_output_cb(*this),
- m_vdd(0),
m_timer(nullptr),
- m_shift(0)
+ m_vdd(-12)
{
}
+
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
@@ -56,36 +50,70 @@ void mm5837_device::device_start()
m_timer = timer_alloc(0);
// register for save states
- save_item(NAME(m_shift));
+ save_item(NAME(m_source.m_shift));
}
+
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void mm5837_device::device_reset()
{
- // initialize with something
- m_shift = 123456;
+ m_source.reset();
if (m_vdd < 16)
- m_timer->adjust(attotime::zero, 0, attotime::from_hz(m_frequency[m_vdd]));
+ m_timer->adjust(attotime::zero, 0, attotime::from_hz(mm5837_source::frequency(m_vdd)));
else
throw emu_fatalerror("%s: Invalid voltage: %d\n", tag(), m_vdd);
}
+
//-------------------------------------------------
// device_timer - handle timer callbacks
//-------------------------------------------------
void mm5837_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- int tap_14 = BIT(m_shift, 13);
- int tap_17 = BIT(m_shift, 16);
- int zero = (m_shift == 0) ? 1 : 0;
+ m_output_cb(m_source.clock());
+}
+
+
+
+//**************************************************************************
+// MM5837 STREAM DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mm5837_stream_device - constructor
+//-------------------------------------------------
+
+mm5837_stream_device::mm5837_stream_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MM5837_STREAM, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ m_stream(nullptr),
+ m_vdd(-12)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mm5837_stream_device::device_start()
+{
+ m_stream = stream_alloc(0, 1, mm5837_source::frequency(m_vdd));
+ save_item(NAME(m_source.m_shift));
+}
- m_shift <<= 1;
- m_shift |= tap_14 ^ tap_17 ^ zero;
- m_output_cb(BIT(m_shift, 16));
+//-------------------------------------------------
+// sound_stream_update - fill the sound buffer
+//-------------------------------------------------
+
+void mm5837_stream_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
+ outputs[0].put(sampindex, m_source.clock() ? 1.0 : 0.0);
}
diff --git a/src/devices/sound/mm5837.h b/src/devices/sound/mm5837.h
index 8c7f8287db6..49374537b9c 100644
--- a/src/devices/sound/mm5837.h
+++ b/src/devices/sound/mm5837.h
@@ -94,6 +94,66 @@
// TYPE DEFINITIONS
//**************************************************************************
+// ======================> mm5837_source
+
+class mm5837_source
+{
+public:
+ // construction/destruction
+ mm5837_source() :
+ m_shift(0x1ffff)
+ {
+ }
+
+ // reset to base state
+ void reset()
+ {
+ m_shift = 0x1ffff;
+ }
+
+ // clock one time and return the shift value
+ u8 clock()
+ {
+ int tap_14 = BIT(m_shift, 13);
+ int tap_17 = BIT(m_shift, 16);
+ int zero = (m_shift == 0) ? 1 : 0;
+
+ m_shift <<= 1;
+ m_shift |= tap_14 ^ tap_17 ^ zero;
+
+ return BIT(m_shift, 16);
+ }
+
+ // taken from the book 'mims circuit scrapbook, vol. 1'
+ static u32 frequency(double vdd)
+ {
+ // Vdd should be negative -6.2..-15V
+ if (vdd > -6.2 || vdd < -15)
+ throw emu_fatalerror("mm5837 frequency should be -6.2V .. -15V");
+
+ // curve fitting done in excel from this table:
+ // { 0, 0, 0, 0, 0, 0, 1, 2267, 8731, 16382, 23531, 32564, 38347, 40010, 37800, 33173 }
+ double result = 191.98*vdd*vdd*vdd + 5448.4*vdd*vdd + 43388*vdd + 105347;
+
+ // datasheet claims frequency range 24-56kHz at Vdd=-14V, but also lists
+ // maximum cycle times as ranging from 1.1-2.4s; since the 17-bit shift
+ // register cycles after 131072 clocks, we would expect the actual cycle
+ // times to be 2.34-5.46s at the 24-56kHz frequency range, so I'm presuming
+ // that it ticks 2x per "clock", effectively running at 2x the frequency
+ result *= 2;
+
+ // make sure the result isn't TOO crazy
+ result = std::max(result, 100.0);
+ return u32(result);
+ }
+
+ // leave this public for easy saving
+ u32 m_shift;
+};
+
+
+// ======================> mm5837_device
+
class mm5837_device : public device_t
{
public:
@@ -101,7 +161,7 @@ public:
mm5837_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// configuration
- void set_vdd_voltage(int voltage) { m_vdd = voltage; }
+ void set_vdd(double voltage) { m_vdd = voltage; }
auto output_callback() { return m_output_cb.bind(); }
protected:
@@ -111,24 +171,42 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
- // taken from the book 'mims circuit scrapbook, vol. 1'
- // this is the frequency the chip runs at when given a vdd voltage of -0 to -15
- static constexpr int m_frequency[16] = { 0, 0, 0, 0, 0, 0, 1, 2267, 8731, 16382, 23531, 32564, 38347, 40010, 37800, 33173 };
+ // internal state
+ devcb_write_line m_output_cb; // output callback
+ emu_timer *m_timer; // output timer
+ double m_vdd; // configured voltage
+ mm5837_source m_source; // noise source
+};
- // callbacks
- devcb_write_line m_output_cb;
- // voltage (as positive number)
- int m_vdd;
+// ======================> mm5837_stream_device
- // output timer
- emu_timer *m_timer;
+class mm5837_stream_device : public device_t, public device_sound_interface
+{
+public:
+ // construction/destruction
+ mm5837_stream_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // configuration
+ void set_vdd(double voltage) { m_vdd = voltage; }
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
- // state
- uint32_t m_shift;
+private:
+ sound_stream *m_stream; // sound stream
+ double m_vdd; // configured voltage
+ mm5837_source m_source; // noise source
};
-// device type definition
+
+// device type definitions
DECLARE_DEVICE_TYPE(MM5837, mm5837_device)
+DECLARE_DEVICE_TYPE(MM5837_STREAM, mm5837_stream_device)
+
#endif // MAME_SOUND_MM5837_H
diff --git a/src/devices/sound/mos6560.cpp b/src/devices/sound/mos6560.cpp
index 05ab0bcd08e..fadef01dd20 100644
--- a/src/devices/sound/mos6560.cpp
+++ b/src/devices/sound/mos6560.cpp
@@ -173,20 +173,18 @@ inline uint8_t mos6560_device::read_colorram(offs_t offset)
void mos6560_device::draw_character( int ybegin, int yend, int ch, int yoff, int xoff, uint16_t *color )
{
- int y, code;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
- code = read_videoram((m_chargenaddr + ch * m_charheight + y) & 0x3fff);
-
- m_bitmap.pix32(y + yoff, xoff + 0) = PALETTE_MOS[color[code >> 7]];
- m_bitmap.pix32(y + yoff, xoff + 1) = PALETTE_MOS[color[(code >> 6) & 1]];
- m_bitmap.pix32(y + yoff, xoff + 2) = PALETTE_MOS[color[(code >> 5) & 1]];
- m_bitmap.pix32(y + yoff, xoff + 3) = PALETTE_MOS[color[(code >> 4) & 1]];
- m_bitmap.pix32(y + yoff, xoff + 4) = PALETTE_MOS[color[(code >> 3) & 1]];
- m_bitmap.pix32(y + yoff, xoff + 5) = PALETTE_MOS[color[(code >> 2) & 1]];
- m_bitmap.pix32(y + yoff, xoff + 6) = PALETTE_MOS[color[(code >> 1) & 1]];
- m_bitmap.pix32(y + yoff, xoff + 7) = PALETTE_MOS[color[code & 1]];
+ int code = read_videoram((m_chargenaddr + ch * m_charheight + y) & 0x3fff);
+
+ m_bitmap.pix(y + yoff, xoff + 0) = PALETTE_MOS[color[BIT(code, 7)]];
+ m_bitmap.pix(y + yoff, xoff + 1) = PALETTE_MOS[color[BIT(code, 6)]];
+ m_bitmap.pix(y + yoff, xoff + 2) = PALETTE_MOS[color[BIT(code, 5)]];
+ m_bitmap.pix(y + yoff, xoff + 3) = PALETTE_MOS[color[BIT(code, 4)]];
+ m_bitmap.pix(y + yoff, xoff + 4) = PALETTE_MOS[color[BIT(code, 3)]];
+ m_bitmap.pix(y + yoff, xoff + 5) = PALETTE_MOS[color[BIT(code, 2)]];
+ m_bitmap.pix(y + yoff, xoff + 6) = PALETTE_MOS[color[BIT(code, 1)]];
+ m_bitmap.pix(y + yoff, xoff + 7) = PALETTE_MOS[color[BIT(code, 0)]];
}
}
@@ -197,20 +195,18 @@ void mos6560_device::draw_character( int ybegin, int yend, int ch, int yoff, int
void mos6560_device::draw_character_multi( int ybegin, int yend, int ch, int yoff, int xoff, uint16_t *color )
{
- int y, code;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
- code = read_videoram((m_chargenaddr + ch * m_charheight + y) & 0x3fff);
-
- m_bitmap.pix32(y + yoff, xoff + 0) =
- m_bitmap.pix32(y + yoff, xoff + 1) = PALETTE_MOS[color[code >> 6]];
- m_bitmap.pix32(y + yoff, xoff + 2) =
- m_bitmap.pix32(y + yoff, xoff + 3) = PALETTE_MOS[color[(code >> 4) & 3]];
- m_bitmap.pix32(y + yoff, xoff + 4) =
- m_bitmap.pix32(y + yoff, xoff + 5) = PALETTE_MOS[color[(code >> 2) & 3]];
- m_bitmap.pix32(y + yoff, xoff + 6) =
- m_bitmap.pix32(y + yoff, xoff + 7) = PALETTE_MOS[color[code & 3]];
+ int code = read_videoram((m_chargenaddr + ch * m_charheight + y) & 0x3fff);
+
+ m_bitmap.pix(y + yoff, xoff + 0) = m_bitmap.pix(y + yoff, xoff + 1) =
+ PALETTE_MOS[color[code >> 6]];
+ m_bitmap.pix(y + yoff, xoff + 2) = m_bitmap.pix(y + yoff, xoff + 3) =
+ PALETTE_MOS[color[(code >> 4) & 3]];
+ m_bitmap.pix(y + yoff, xoff + 4) = m_bitmap.pix(y + yoff, xoff + 5) =
+ PALETTE_MOS[color[(code >> 2) & 3]];
+ m_bitmap.pix(y + yoff, xoff + 6) = m_bitmap.pix(y + yoff, xoff + 7) =
+ PALETTE_MOS[color[code & 3]];
}
}
@@ -221,9 +217,7 @@ void mos6560_device::draw_character_multi( int ybegin, int yend, int ch, int yof
void mos6560_device::drawlines( int first, int last )
{
- int line, vline;
- int offs, yoff, xoff, ybegin, yend, i, j;
- int attr, ch;
+ int line;
m_lastline = last;
if (first >= last)
@@ -231,12 +225,13 @@ void mos6560_device::drawlines( int first, int last )
for (line = first; (line < m_ypos) && (line < last); line++)
{
- for (j = 0; j < m_total_xsize; j++)
- m_bitmap.pix32(line, j) = PALETTE_MOS[m_framecolor];
+ for (int j = 0; j < m_total_xsize; j++)
+ m_bitmap.pix(line, j) = PALETTE_MOS[m_framecolor];
}
- for (vline = line - m_ypos; (line < last) && (line < m_ypos + m_ysize);)
+ for (int vline = line - m_ypos; (line < last) && (line < m_ypos + m_ysize);)
{
+ int offs, yoff, xoff, ybegin, yend;
if (m_matrix8x16)
{
offs = (vline >> 4) * m_chars_x;
@@ -254,16 +249,16 @@ void mos6560_device::drawlines( int first, int last )
if (m_xpos > 0)
{
- for (i = ybegin; i <= yend; i++)
- for (j = 0; j < m_xpos; j++)
- m_bitmap.pix32(yoff + i, j) = PALETTE_MOS[m_framecolor];
+ for (int i = ybegin; i <= yend; i++)
+ for (int j = 0; j < m_xpos; j++)
+ m_bitmap.pix(yoff + i, j) = PALETTE_MOS[m_framecolor];
}
for (xoff = m_xpos; (xoff < m_xpos + m_xsize) && (xoff < m_total_xsize); xoff += 8, offs++)
{
- ch = read_videoram((m_videoaddr + offs) & 0x3fff);
+ int ch = read_videoram((m_videoaddr + offs) & 0x3fff);
- attr = (read_colorram((m_videoaddr + offs) & 0x3fff)) & 0xf;
+ int attr = (read_colorram((m_videoaddr + offs) & 0x3fff)) & 0xf;
if (m_variant == TYPE_ATTACK_UFO)
{
@@ -301,9 +296,9 @@ void mos6560_device::drawlines( int first, int last )
if (xoff < m_total_xsize)
{
- for (i = ybegin; i <= yend; i++)
- for (j = xoff; j < m_total_xsize; j++)
- m_bitmap.pix32(yoff + i, j) = PALETTE_MOS[m_framecolor];
+ for (int i = ybegin; i <= yend; i++)
+ for (int j = xoff; j < m_total_xsize; j++)
+ m_bitmap.pix(yoff + i, j) = PALETTE_MOS[m_framecolor];
}
if (m_matrix8x16)
@@ -319,8 +314,8 @@ void mos6560_device::drawlines( int first, int last )
}
for (; line < last; line++)
- for (j = 0; j < m_total_xsize; j++)
- m_bitmap.pix32(line, j) = PALETTE_MOS[m_framecolor];
+ for (int j = 0; j < m_total_xsize; j++)
+ m_bitmap.pix(line, j) = PALETTE_MOS[m_framecolor];
}
@@ -620,20 +615,17 @@ void mos6560_device::soundport_w( int offset, int data )
void mos6560_device::sound_start()
{
- int i;
-
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
/* buffer for fastest played sample for 5 second so we have enough data for min 5 second */
m_noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC;
- m_noise = std::make_unique<int8_t[]>(m_noisesize);
+ m_noise = std::make_unique<int8_t []>(m_noisesize);
{
int noiseshift = 0x7ffff8;
- char data;
- for (i = 0; i < m_noisesize; i++)
+ for (int i = 0; i < m_noisesize; i++)
{
- data = 0;
+ char data = 0;
if (noiseshift & 0x400000)
data |= 0x80;
if (noiseshift & 0x100000)
@@ -661,17 +653,13 @@ void mos6560_device::sound_start()
if (m_tonesize > 0)
{
- m_tone = std::make_unique<int16_t[]>(m_tonesize);
+ m_tone = std::make_unique<int16_t []>(m_tonesize);
- for (i = 0; i < m_tonesize; i++)
+ for (int i = 0; i < m_tonesize; i++)
{
- m_tone[i] = (int16_t)(sin (2 * M_PI * i / m_tonesize) * 127 + 0.5);
+ m_tone[i] = int16_t(sin (2 * M_PI * i / m_tonesize) * 127 + 0.5);
}
}
- else
- {
- m_tone = nullptr;
- }
}
@@ -888,15 +876,15 @@ void mos6560_device::device_timer(emu_timer &timer, device_timer_id id, int para
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void mos6560_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mos6560_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i, v;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
- for (i = 0; i < samples; i++)
+ for (i = 0; i < buffer.samples(); i++)
{
v = 0;
if (TONE1_ON /*||(m_tone1pos != 0) */ )
@@ -909,7 +897,7 @@ void mos6560_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
if (m_tone1pos >= m_tone1samples)
{
m_tone1pos = 0;
- m_tone1samples = machine().sample_rate() / TONE1_FREQUENCY;
+ m_tone1samples = buffer.sample_rate() / TONE1_FREQUENCY;
if (m_tone1samples == 0)
m_tone1samples = 1;
}
@@ -925,7 +913,7 @@ void mos6560_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
if (m_tone2pos >= m_tone2samples)
{
m_tone2pos = 0;
- m_tone2samples = machine().sample_rate() / TONE2_FREQUENCY;
+ m_tone2samples = buffer.sample_rate() / TONE2_FREQUENCY;
if (m_tone2samples == 0)
m_tone2samples = 1;
}
@@ -941,7 +929,7 @@ void mos6560_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
if (m_tone3pos >= m_tone3samples)
{
m_tone3pos = 0;
- m_tone3samples = machine().sample_rate() / TONE3_FREQUENCY;
+ m_tone3samples = buffer.sample_rate() / TONE3_FREQUENCY;
if (m_tone3samples == 0)
m_tone3samples = 1;
}
@@ -956,12 +944,11 @@ void mos6560_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
m_noisepos = 0;
}
}
- v = (v * VOLUME) << 2;
- if (v > 32767)
- buffer[i] = 32767;
- else if (v < -32767)
- buffer[i] = -32767;
- else
- buffer[i] = v;
+ v *= VOLUME;
+ if (v > 8191)
+ v = 8191;
+ else if (v < -8191)
+ v = -8191;
+ buffer.put_int(i, v, 8192);
}
}
diff --git a/src/devices/sound/mos6560.h b/src/devices/sound/mos6560.h
index cf657255198..182cba47dba 100644
--- a/src/devices/sound/mos6560.h
+++ b/src/devices/sound/mos6560.h
@@ -124,7 +124,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
inline uint8_t read_videoram(offs_t offset);
inline uint8_t read_colorram(offs_t offset);
@@ -176,8 +176,8 @@ protected:
m_noisesamples; /* count of samples to give out per tone */
sound_stream *m_channel;
- std::unique_ptr<int16_t[]> m_tone;
- std::unique_ptr<int8_t[]> m_noise;
+ std::unique_ptr<int16_t []> m_tone;
+ std::unique_ptr<int8_t []> m_noise;
emu_timer *m_line_timer;
};
diff --git a/src/devices/sound/mos6581.cpp b/src/devices/sound/mos6581.cpp
index 2fe073a1347..4ee3ddd7ebd 100644
--- a/src/devices/sound/mos6581.cpp
+++ b/src/devices/sound/mos6581.cpp
@@ -199,7 +199,7 @@ void mos6581_device::device_start()
m_read_poty.resolve_safe(0xff);
// create sound stream
- m_stream = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_stream = stream_alloc(0, 1, machine().sample_rate());
// initialize SID engine
m_token->device = this;
@@ -235,13 +235,13 @@ void mos6581_device::device_post_load()
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void mos6581_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mos6581_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- m_token->fill_buffer(outputs[0], samples);
+ m_token->fill_buffer(outputs[0]);
}
diff --git a/src/devices/sound/mos6581.h b/src/devices/sound/mos6581.h
index 47e5959ef41..de05db489d3 100644
--- a/src/devices/sound/mos6581.h
+++ b/src/devices/sound/mos6581.h
@@ -65,7 +65,7 @@ protected:
virtual void device_post_load() override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void save_state(SID6581_t *token);
private:
diff --git a/src/devices/sound/mos7360.cpp b/src/devices/sound/mos7360.cpp
index 9105fd656e3..aa9604b3a78 100644
--- a/src/devices/sound/mos7360.cpp
+++ b/src/devices/sound/mos7360.cpp
@@ -297,7 +297,7 @@ void mos7360_device::device_start()
screen().register_screen_bitmap(m_bitmap);
// create sound stream
- m_stream = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_stream = stream_alloc(0, 1, machine().sample_rate());
// buffer for fastest played sample for 5 second so we have enough data for min 5 second
m_noisesize = NOISE_FREQUENCY_MAX * NOISE_BUFFER_SIZE_SEC;
@@ -454,16 +454,16 @@ void mos7360_device::device_timer(emu_timer &timer, device_timer_id id, int para
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void mos7360_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mos7360_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i, v, a;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
- for (i = 0; i < samples; i++)
+ for (i = 0; i < buffer.samples(); i++)
{
v = 0;
@@ -506,113 +506,100 @@ void mos7360_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
v = v * a;
- buffer[i] = v;
+ buffer.put_int(i, v, 32768);
}
}
void mos7360_device::draw_character(int ybegin, int yend, int ch, int yoff, int xoff, uint16_t *color)
{
- int y, code;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
+ int code;
if (INROM)
code = read_rom(m_chargenaddr + ch * 8 + y);
else
code = read_ram(m_chargenaddr + ch * 8 + y);
- m_bitmap.pix32(y + yoff, 0 + xoff) = PALETTE_MOS[color[code >> 7]];
- m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[color[(code >> 6) & 1]];
- m_bitmap.pix32(y + yoff, 2 + xoff) = PALETTE_MOS[color[(code >> 5) & 1]];
- m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[color[(code >> 4) & 1]];
- m_bitmap.pix32(y + yoff, 4 + xoff) = PALETTE_MOS[color[(code >> 3) & 1]];
- m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[color[(code >> 2) & 1]];
- m_bitmap.pix32(y + yoff, 6 + xoff) = PALETTE_MOS[color[(code >> 1) & 1]];
- m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[color[code & 1]];
+ m_bitmap.pix(y + yoff, 0 + xoff) = PALETTE_MOS[color[BIT(code, 7)]];
+ m_bitmap.pix(y + yoff, 1 + xoff) = PALETTE_MOS[color[BIT(code, 6)]];
+ m_bitmap.pix(y + yoff, 2 + xoff) = PALETTE_MOS[color[BIT(code, 5)]];
+ m_bitmap.pix(y + yoff, 3 + xoff) = PALETTE_MOS[color[BIT(code, 4)]];
+ m_bitmap.pix(y + yoff, 4 + xoff) = PALETTE_MOS[color[BIT(code, 3)]];
+ m_bitmap.pix(y + yoff, 5 + xoff) = PALETTE_MOS[color[BIT(code, 2)]];
+ m_bitmap.pix(y + yoff, 6 + xoff) = PALETTE_MOS[color[BIT(code, 1)]];
+ m_bitmap.pix(y + yoff, 7 + xoff) = PALETTE_MOS[color[BIT(code, 0)]];
}
}
void mos7360_device::draw_character_multi(int ybegin, int yend, int ch, int yoff, int xoff)
{
- int y, code;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
+ int code;
if (INROM)
code = read_rom(m_chargenaddr + ch * 8 + y);
else
code = read_ram(m_chargenaddr + ch * 8 + y);
- m_bitmap.pix32(y + yoff, 0 + xoff) =
- m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[m_multi[code >> 6]];
- m_bitmap.pix32(y + yoff, 2 + xoff) =
- m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[m_multi[(code >> 4) & 3]];
- m_bitmap.pix32(y + yoff, 4 + xoff) =
- m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[m_multi[(code >> 2) & 3]];
- m_bitmap.pix32(y + yoff, 6 + xoff) =
- m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[m_multi[code & 3]];
+ m_bitmap.pix(y + yoff, 0 + xoff) = m_bitmap.pix(y + yoff, 1 + xoff) =
+ PALETTE_MOS[m_multi[code >> 6]];
+ m_bitmap.pix(y + yoff, 2 + xoff) = m_bitmap.pix(y + yoff, 3 + xoff) =
+ PALETTE_MOS[m_multi[(code >> 4) & 3]];
+ m_bitmap.pix(y + yoff, 4 + xoff) = m_bitmap.pix(y + yoff, 5 + xoff) =
+ PALETTE_MOS[m_multi[(code >> 2) & 3]];
+ m_bitmap.pix(y + yoff, 6 + xoff) = m_bitmap.pix(y + yoff, 7 + xoff) =
+ PALETTE_MOS[m_multi[code & 3]];
}
}
void mos7360_device::draw_bitmap(int ybegin, int yend, int ch, int yoff, int xoff)
{
- int y, code;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
- code = read_ram(m_bitmapaddr + ch * 8 + y);
-
- m_bitmap.pix32(y + yoff, 0 + xoff) = PALETTE_MOS[m_c16_bitmap[code >> 7]];
- m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 6) & 1]];
- m_bitmap.pix32(y + yoff, 2 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 5) & 1]];
- m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 4) & 1]];
- m_bitmap.pix32(y + yoff, 4 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 3) & 1]];
- m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 2) & 1]];
- m_bitmap.pix32(y + yoff, 6 + xoff) = PALETTE_MOS[m_c16_bitmap[(code >> 1) & 1]];
- m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[m_c16_bitmap[code & 1]];
+ int code = read_ram(m_bitmapaddr + ch * 8 + y);
+
+ m_bitmap.pix(y + yoff, 0 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 7)]];
+ m_bitmap.pix(y + yoff, 1 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 6)]];
+ m_bitmap.pix(y + yoff, 2 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 5)]];
+ m_bitmap.pix(y + yoff, 3 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 4)]];
+ m_bitmap.pix(y + yoff, 4 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 3)]];
+ m_bitmap.pix(y + yoff, 5 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 2)]];
+ m_bitmap.pix(y + yoff, 6 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 1)]];
+ m_bitmap.pix(y + yoff, 7 + xoff) = PALETTE_MOS[m_c16_bitmap[BIT(code, 0)]];
}
}
void mos7360_device::draw_bitmap_multi(int ybegin, int yend, int ch, int yoff, int xoff)
{
- int y, code;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
- code = read_ram(m_bitmapaddr + ch * 8 + y);
-
- m_bitmap.pix32(y + yoff, 0 + xoff) =
- m_bitmap.pix32(y + yoff, 1 + xoff) = PALETTE_MOS[m_bitmapmulti[code >> 6]];
- m_bitmap.pix32(y + yoff, 2 + xoff) =
- m_bitmap.pix32(y + yoff, 3 + xoff) = PALETTE_MOS[m_bitmapmulti[(code >> 4) & 3]];
- m_bitmap.pix32(y + yoff, 4 + xoff) =
- m_bitmap.pix32(y + yoff, 5 + xoff) = PALETTE_MOS[m_bitmapmulti[(code >> 2) & 3]];
- m_bitmap.pix32(y + yoff, 6 + xoff) =
- m_bitmap.pix32(y + yoff, 7 + xoff) = PALETTE_MOS[m_bitmapmulti[code & 3]];
+ int code = read_ram(m_bitmapaddr + ch * 8 + y);
+
+ m_bitmap.pix(y + yoff, 0 + xoff) = m_bitmap.pix(y + yoff, 1 + xoff) =
+ PALETTE_MOS[m_bitmapmulti[code >> 6]];
+ m_bitmap.pix(y + yoff, 2 + xoff) = m_bitmap.pix(y + yoff, 3 + xoff) =
+ PALETTE_MOS[m_bitmapmulti[(code >> 4) & 3]];
+ m_bitmap.pix(y + yoff, 4 + xoff) = m_bitmap.pix(y + yoff, 5 + xoff) =
+ PALETTE_MOS[m_bitmapmulti[(code >> 2) & 3]];
+ m_bitmap.pix(y + yoff, 6 + xoff) = m_bitmap.pix(y + yoff, 7 + xoff) =
+ PALETTE_MOS[m_bitmapmulti[code & 3]];
}
}
void mos7360_device::draw_cursor(int ybegin, int yend, int yoff, int xoff, int color)
{
- int y;
-
- for (y = ybegin; y <= yend; y++)
+ for (int y = ybegin; y <= yend; y++)
{
for (int x = 0; x < 8; x++)
{
- m_bitmap.pix32(y + yoff, x + xoff) = PALETTE_MOS[color];
+ m_bitmap.pix(y + yoff, x + xoff) = PALETTE_MOS[color];
}
}
}
void mos7360_device::drawlines(int first, int last)
{
- int line, vline, end;
- int attr, ch, c1, c2, ecm;
- int offs, yoff, xoff, ybegin, yend, xbegin, xend;
- int i;
-
m_lastline = last;
/* top part of display not rastered */
@@ -625,34 +612,44 @@ void mos7360_device::drawlines(int first, int last)
if (!SCREENON)
{
- for (line = first; (line < last) && (line < m_bitmap.height()); line++)
+ for (int line = first; (line < last) && (line < m_bitmap.height()); line++)
{
for (int x = 0; x < m_bitmap.width(); x++)
{
- m_bitmap.pix32(line, x) = PALETTE_MOS[FRAMECOLOR];
+ m_bitmap.pix(line, x) = PALETTE_MOS[FRAMECOLOR];
}
}
return;
}
+ int xbegin, xend;
if (COLUMNS40)
- xbegin = XPOS, xend = xbegin + 320;
+ {
+ xbegin = XPOS;
+ xend = xbegin + 320;
+ }
else
- xbegin = XPOS + 7, xend = xbegin + 304;
+ {
+ xbegin = XPOS + 7;
+ xend = xbegin + 304;
+ }
+ int end;
if (last < m_y_begin)
end = last;
else
end = m_y_begin + YPOS;
+
+ int line;
+ for (line = first; line < end; line++)
{
- for (line = first; line < end; line++)
+ for (int x = 0; x < m_bitmap.width(); x++)
{
- for (int x = 0; x < m_bitmap.width(); x++)
- {
- m_bitmap.pix32(line, x) = PALETTE_MOS[FRAMECOLOR];
- }
+ m_bitmap.pix(line, x) = PALETTE_MOS[FRAMECOLOR];
}
}
+
+ int vline;
if (LINES25)
vline = line - m_y_begin - YPOS;
else
@@ -663,23 +660,23 @@ void mos7360_device::drawlines(int first, int last)
else
end = m_y_end + YPOS;
- for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin)
+ for (int ybegin, yend; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin)
{
- offs = (vline >> 3) * 40;
+ int offs = (vline >> 3) * 40;
ybegin = vline & 7;
- yoff = line - ybegin;
+ int yoff = line - ybegin;
yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
/* rendering 39 characters */
/* left and right borders are overwritten later */
- for (xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++)
+ for (int xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++)
{
if (HIRESON)
{
- ch = read_ram((m_videoaddr | 0x400) + offs);
- attr = read_ram(m_videoaddr + offs);
- c1 = ((ch >> 4) & 0xf) | (attr << 4);
- c2 = (ch & 0xf) | (attr & 0x70);
+ int ch = read_ram((m_videoaddr | 0x400) + offs);
+ int attr = read_ram(m_videoaddr + offs);
+ int c1 = ((ch >> 4) & 0xf) | (attr << 4);
+ int c2 = (ch & 0xf) | (attr & 0x70);
m_bitmapmulti[1] = m_c16_bitmap[1] = c1 & 0x7f;
m_bitmapmulti[2] = m_c16_bitmap[0] = c2 & 0x7f;
if (MULTICOLORON)
@@ -693,13 +690,13 @@ void mos7360_device::drawlines(int first, int last)
}
else
{
- ch = read_ram((m_videoaddr | 0x400) + offs);
- attr = read_ram(m_videoaddr + offs);
+ int ch = read_ram((m_videoaddr | 0x400) + offs);
+ int attr = read_ram(m_videoaddr + offs);
// levente harsfalvi's docu says cursor off in ecm and multicolor
if (ECMON)
{
// hardware reverse off
- ecm = ch >> 6;
+ int ecm = ch >> 6;
m_ecmcolor[0] = m_colors[ecm];
m_ecmcolor[1] = attr & 0x7f;
draw_character(ybegin, yend, ch & ~0xc0, yoff, xoff, m_ecmcolor);
@@ -741,16 +738,16 @@ void mos7360_device::drawlines(int first, int last)
}
}
- for (i = ybegin; i <= yend; i++)
+ for (int i = ybegin; i <= yend; i++)
{
for (int x = 0; x < xbegin; x++)
{
- m_bitmap.pix32(yoff + i, x) = PALETTE_MOS[FRAMECOLOR];
+ m_bitmap.pix(yoff + i, x) = PALETTE_MOS[FRAMECOLOR];
}
for (int x = xend; x < m_bitmap.width(); x++)
{
- m_bitmap.pix32(yoff + i, x) = PALETTE_MOS[FRAMECOLOR];
+ m_bitmap.pix(yoff + i, x) = PALETTE_MOS[FRAMECOLOR];
}
}
}
@@ -764,7 +761,7 @@ void mos7360_device::drawlines(int first, int last)
{
for (int x = 0; x < m_bitmap.width(); x++)
{
- m_bitmap.pix32(line, x) = PALETTE_MOS[FRAMECOLOR];
+ m_bitmap.pix(line, x) = PALETTE_MOS[FRAMECOLOR];
}
}
}
diff --git a/src/devices/sound/mos7360.h b/src/devices/sound/mos7360.h
index 7e41bddb7c6..c8733dc3e46 100644
--- a/src/devices/sound/mos7360.h
+++ b/src/devices/sound/mos7360.h
@@ -110,7 +110,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_sound_interface callbacks
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
inline void set_interrupt(int mask);
inline void clear_interrupt(int mask);
diff --git a/src/devices/sound/msm5232.cpp b/src/devices/sound/msm5232.cpp
index da8fc499dc7..972b83a8c53 100644
--- a/src/devices/sound/msm5232.cpp
+++ b/src/devices/sound/msm5232.cpp
@@ -34,7 +34,7 @@ void msm5232_device::device_start()
init(clock(), rate);
- m_stream = stream_alloc_legacy(0, 11, rate);
+ m_stream = stream_alloc(0, 11, rate);
/* register with the save state system */
save_item(NAME(m_EN_out16));
@@ -725,34 +725,34 @@ void msm5232_device::set_clock(int clock)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void msm5232_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void msm5232_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buf1 = outputs[0];
- stream_sample_t *buf2 = outputs[1];
- stream_sample_t *buf3 = outputs[2];
- stream_sample_t *buf4 = outputs[3];
- stream_sample_t *buf5 = outputs[4];
- stream_sample_t *buf6 = outputs[5];
- stream_sample_t *buf7 = outputs[6];
- stream_sample_t *buf8 = outputs[7];
- stream_sample_t *bufsolo1 = outputs[8];
- stream_sample_t *bufsolo2 = outputs[9];
- stream_sample_t *bufnoise = outputs[10];
+ auto &buf1 = outputs[0];
+ auto &buf2 = outputs[1];
+ auto &buf3 = outputs[2];
+ auto &buf4 = outputs[3];
+ auto &buf5 = outputs[4];
+ auto &buf6 = outputs[5];
+ auto &buf7 = outputs[6];
+ auto &buf8 = outputs[7];
+ auto &bufsolo1 = outputs[8];
+ auto &bufsolo2 = outputs[9];
+ auto &bufnoise = outputs[10];
int i;
- for (i=0; i<samples; i++)
+ for (i=0; i<buf1.samples(); i++)
{
/* calculate all voices' envelopes */
EG_voices_advance();
TG_group_advance(0); /* calculate tones group 1 */
- buf1[i] = o2;
- buf2[i] = o4;
- buf3[i] = o8;
- buf4[i] = o16;
+ buf1.put_int(i, o2, 32768);
+ buf2.put_int(i, o4, 32768);
+ buf3.put_int(i, o8, 32768);
+ buf4.put_int(i, o16, 32768);
SAVE_SINGLE_CHANNEL(0,o2)
SAVE_SINGLE_CHANNEL(1,o4)
@@ -760,13 +760,13 @@ void msm5232_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
SAVE_SINGLE_CHANNEL(3,o16)
TG_group_advance(1); /* calculate tones group 2 */
- buf5[i] = o2;
- buf6[i] = o4;
- buf7[i] = o8;
- buf8[i] = o16;
+ buf5.put_int(i, o2, 32768);
+ buf6.put_int(i, o4, 32768);
+ buf7.put_int(i, o8, 32768);
+ buf8.put_int(i, o16, 32768);
- bufsolo1[i] = solo8;
- bufsolo2[i] = solo16;
+ bufsolo1.put_int(i, solo8, 32768);
+ bufsolo2.put_int(i, solo16, 32768);
SAVE_SINGLE_CHANNEL(4,o2)
SAVE_SINGLE_CHANNEL(5,o4)
@@ -794,6 +794,6 @@ void msm5232_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
}
}
- bufnoise[i] = (m_noise_rng & (1<<16)) ? 32767 : 0;
+ bufnoise.put(i, (m_noise_rng & (1<<16)) ? 1.0 : 0.0);
}
}
diff --git a/src/devices/sound/msm5232.h b/src/devices/sound/msm5232.h
index 364f944353b..552cd7669e3 100644
--- a/src/devices/sound/msm5232.h
+++ b/src/devices/sound/msm5232.h
@@ -26,7 +26,7 @@ protected:
virtual void device_post_load() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct VOICE {
diff --git a/src/devices/sound/multipcm.cpp b/src/devices/sound/multipcm.cpp
index c4a5892990f..4ea099b947a 100644
--- a/src/devices/sound/multipcm.cpp
+++ b/src/devices/sound/multipcm.cpp
@@ -479,7 +479,7 @@ void multipcm_device::device_start()
const float clock_divider = 180.0f;
m_rate = (float)clock() / clock_divider;
- m_stream = stream_alloc_legacy(0, 2, m_rate);
+ m_stream = stream_alloc(0, 2, m_rate);
// Volume + pan table
m_left_pan_table = make_unique_clear<int32_t[]>(0x800);
@@ -575,7 +575,7 @@ void multipcm_device::device_start()
save_item(NAME(m_address));
// Slots
- m_slots = make_unique_clear<slot_t []>(28);
+ m_slots = std::make_unique<slot_t []>(28);
save_pointer(STRUCT_MEMBER(m_slots, m_regs), 28);
save_pointer(STRUCT_MEMBER(m_slots, m_playing), 28);
@@ -628,22 +628,10 @@ void multipcm_device::device_clock_changed()
}
//-----------------------------------------------------
-// clamp_to_int16 - clamp a 32-bit value to 16 bits
+// convert_to_stream_sample - clamp a 32-bit value to
+// 16 bits and convert to a stream_buffer::sample_t
//-----------------------------------------------------
-int16_t multipcm_device::clamp_to_int16(int32_t value)
-{
- if (value < -32768)
- {
- return -32768;
- }
- else if (value > 32767)
- {
- return 32767;
- }
- return (int16_t)value;
-}
-
#if MULTIPCM_LOG_SAMPLES
void multipcm_device::dump_sample(slot_t &slot)
{
@@ -677,20 +665,12 @@ void multipcm_device::dump_sample(slot_t &slot)
#endif
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void multipcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int32_t samples)
+void multipcm_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *datap[2];
-
- datap[0] = outputs[0];
- datap[1] = outputs[1];
-
- memset(datap[0], 0, sizeof(*datap[0]) * samples);
- memset(datap[1], 0, sizeof(*datap[1]) * samples);
-
- for (int32_t i = 0; i < samples; ++i)
+ for (int32_t i = 0; i < outputs[0].samples(); ++i)
{
int32_t smpl = 0;
int32_t smpr = 0;
@@ -741,8 +721,8 @@ void multipcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
}
}
- datap[0][i] = clamp_to_int16(smpl);
- datap[1][i] = clamp_to_int16(smpr);
+ outputs[0].put_int_clamp(i, smpl, 32768);
+ outputs[1].put_int_clamp(i, smpr, 32768);
}
}
diff --git a/src/devices/sound/multipcm.h b/src/devices/sound/multipcm.h
index 4308703b9dc..e8de5a06851 100644
--- a/src/devices/sound/multipcm.h
+++ b/src/devices/sound/multipcm.h
@@ -29,7 +29,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
@@ -37,17 +37,17 @@ protected:
private:
struct sample_t
{
- uint32_t m_start;
- uint32_t m_loop;
- uint32_t m_end;
- uint8_t m_attack_reg;
- uint8_t m_decay1_reg;
- uint8_t m_decay2_reg;
- uint8_t m_decay_level;
- uint8_t m_release_reg;
- uint8_t m_key_rate_scale;
- uint8_t m_lfo_vibrato_reg;
- uint8_t m_lfo_amplitude_reg;
+ uint32_t m_start = 0;
+ uint32_t m_loop = 0;
+ uint32_t m_end = 0;
+ uint8_t m_attack_reg = 0;
+ uint8_t m_decay1_reg = 0;
+ uint8_t m_decay2_reg = 0;
+ uint8_t m_decay_level = 0;
+ uint8_t m_release_reg = 0;
+ uint8_t m_key_rate_scale = 0;
+ uint8_t m_lfo_vibrato_reg = 0;
+ uint8_t m_lfo_amplitude_reg = 0;
};
enum class state_t : u8
@@ -60,38 +60,38 @@ private:
struct envelope_gen_t
{
- int32_t m_volume;
- state_t m_state;
- int32_t step;
+ int32_t m_volume = 0;
+ state_t m_state = state_t::ATTACK;
+ int32_t step = 0;
//step vals
- int32_t m_attack_rate; // Attack
- int32_t m_decay1_rate; // Decay1
- int32_t m_decay2_rate; // Decay2
- int32_t m_release_rate; // Release
- int32_t m_decay_level; // Decay level
+ int32_t m_attack_rate = 0; // Attack
+ int32_t m_decay1_rate = 0; // Decay1
+ int32_t m_decay2_rate = 0; // Decay2
+ int32_t m_release_rate = 0; // Release
+ int32_t m_decay_level = 0; // Decay level
};
struct lfo_t
{
- uint16_t m_phase;
- uint32_t m_phase_step;
- int32_t *m_table;
- int32_t *m_scale;
+ uint16_t m_phase = 0;
+ uint32_t m_phase_step = 0;
+ int32_t *m_table = nullptr;
+ int32_t *m_scale = nullptr;
};
struct slot_t
{
- uint8_t m_regs[8];
- bool m_playing;
+ uint8_t m_regs[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ bool m_playing = false;
sample_t m_sample;
- uint32_t m_base;
- uint32_t m_offset;
- uint32_t m_step;
- uint32_t m_pan;
- uint32_t m_total_level;
- uint32_t m_dest_total_level;
- int32_t m_total_level_step;
- int32_t m_prev_sample;
+ uint32_t m_base = 0;
+ uint32_t m_offset = 0;
+ uint32_t m_step = 0;
+ uint32_t m_pan = 0;
+ uint32_t m_total_level = 0;
+ uint32_t m_dest_total_level = 0;
+ int32_t m_total_level_step = 0;
+ int32_t m_prev_sample = 0;
envelope_gen_t m_envelope_gen;
lfo_t m_pitch_lfo; // Pitch lfo
lfo_t m_amplitude_lfo; // AM lfo
@@ -135,7 +135,7 @@ private:
void write_slot(slot_t &slot, int32_t reg, uint8_t data);
- int16_t clamp_to_int16(int32_t value);
+ stream_buffer::sample_t convert_to_stream_sample(int32_t value);
#if MULTIPCM_LOG_SAMPLES
void dump_sample(slot_t &slot);
diff --git a/src/devices/sound/n63701x.cpp b/src/devices/sound/n63701x.cpp
index f9dea8e4509..6f16c988d8e 100644
--- a/src/devices/sound/n63701x.cpp
+++ b/src/devices/sound/n63701x.cpp
@@ -46,7 +46,7 @@ namco_63701x_device::namco_63701x_device(const machine_config &mconfig, const ch
void namco_63701x_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, clock()/1000);
+ m_stream = stream_alloc(0, 2, clock()/1000);
for (int i = 0; i < 2; i++)
{
@@ -61,16 +61,16 @@ void namco_63701x_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void namco_63701x_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void namco_63701x_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int ch;
for (ch = 0;ch < 2;ch++)
{
- stream_sample_t *buf = outputs[ch];
+ auto &buf = outputs[ch];
voice_63701x *v = &m_voices[ch];
if (v->playing)
@@ -80,12 +80,12 @@ void namco_63701x_device::sound_stream_update_legacy(sound_stream &stream, strea
int vol = vol_table[v->volume];
int p;
- for (p = 0;p < samples;p++)
+ for (p = 0;p < buf.samples();p++)
{
if (v->silence_counter)
{
v->silence_counter--;
- *(buf++) = 0;
+ buf.put(p, 0);
}
else
{
@@ -94,17 +94,18 @@ void namco_63701x_device::sound_stream_update_legacy(sound_stream &stream, strea
if (data == 0xff) /* end of sample */
{
v->playing = 0;
+ buf.fill(0, p);
break;
}
else if (data == 0x00) /* silence compression */
{
data = base[(pos++) & 0xffff];
v->silence_counter = data;
- *(buf++) = 0;
+ buf.put(p, 0);
}
else
{
- *(buf++) = vol * (data - 0x80);
+ buf.put_int(p, vol * (data - 0x80), 32768);
}
}
}
@@ -112,7 +113,7 @@ void namco_63701x_device::sound_stream_update_legacy(sound_stream &stream, strea
v->position = pos;
}
else
- memset(buf, 0, samples * sizeof(*buf));
+ buf.fill(0);
}
}
diff --git a/src/devices/sound/n63701x.h b/src/devices/sound/n63701x.h
index 4992065d7bf..3ca5411df6d 100644
--- a/src/devices/sound/n63701x.h
+++ b/src/devices/sound/n63701x.h
@@ -25,7 +25,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct voice_63701x
diff --git a/src/devices/sound/namco.cpp b/src/devices/sound/namco.cpp
index 830f3713b45..694dad0cd29 100644
--- a/src/devices/sound/namco.cpp
+++ b/src/devices/sound/namco.cpp
@@ -43,8 +43,6 @@
/* a position of waveform sample */
#define WAVEFORM_POSITION(n) (((n) >> m_f_fracbits) & 0x1f)
-static constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
-
DEFINE_DEVICE_TYPE(NAMCO, namco_device, "namco", "Namco")
DEFINE_DEVICE_TYPE(NAMCO_15XX, namco_15xx_device, "namco_15xx", "Namco 15xx")
DEFINE_DEVICE_TYPE(NAMCO_CUS30, namco_cus30_device, "namco_cus30", "Namco CUS30")
@@ -54,7 +52,6 @@ namco_audio_device::namco_audio_device(const machine_config &mconfig, device_typ
, device_sound_interface(mconfig, *this)
, m_wave_ptr(*this, DEVICE_SELF)
, m_last_channel(nullptr)
- , m_soundregs(nullptr)
, m_wavedata(nullptr)
, m_wave_size(0)
, m_sound_enable(false)
@@ -69,11 +66,13 @@ namco_audio_device::namco_audio_device(const machine_config &mconfig, device_typ
namco_device::namco_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: namco_audio_device(mconfig, NAMCO, tag, owner, clock)
+ , m_soundregs(nullptr)
{
}
namco_15xx_device::namco_15xx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
:namco_audio_device(mconfig, NAMCO_15XX, tag, owner, clock)
+ , m_soundregs(nullptr)
{
}
@@ -89,13 +88,9 @@ namco_cus30_device::namco_cus30_device(const machine_config &mconfig, const char
void namco_audio_device::device_start()
{
- sound_channel *voice;
-
/* extract globals from the interface */
m_last_channel = m_channel_list + m_voices;
- m_soundregs = auto_alloc_array_clear(machine(), uint8_t, 0x400);
-
/* build the waveform table */
build_decoded_waveform(m_wave_ptr);
@@ -109,20 +104,17 @@ void namco_audio_device::device_start()
m_sound_enable = true;
/* register with the save state system */
- save_pointer(NAME(m_soundregs), 0x400);
-
if (m_wave_ptr == nullptr)
save_pointer(NAME(m_wavedata), 0x400);
save_item(NAME(m_voices));
save_item(NAME(m_sound_enable));
- save_pointer(NAME(m_waveform[0]), MAX_VOLUME * 32 * 8 * (1+m_wave_size));
+ for (int v = 0; v < MAX_VOLUME; v++)
+ save_pointer(NAME(m_waveform[v]), 32 * 8 * (1+m_wave_size), v);
/* reset all the voices */
- for (voice = m_channel_list; voice < m_last_channel; voice++)
+ for (sound_channel *voice = m_channel_list; voice < m_last_channel; voice++)
{
- int voicenum = voice - m_channel_list;
-
voice->frequency = 0;
voice->volume[0] = voice->volume[1] = 0;
voice->waveform_select = 0;
@@ -132,18 +124,36 @@ void namco_audio_device::device_start()
voice->noise_seed = 1;
voice->noise_counter = 0;
voice->noise_hold = 0;
-
- /* register with the save state system */
- save_item(NAME(voice->frequency), voicenum);
- save_item(NAME(voice->counter), voicenum);
- save_item(NAME(voice->volume), voicenum);
- save_item(NAME(voice->noise_sw), voicenum);
- save_item(NAME(voice->noise_state), voicenum);
- save_item(NAME(voice->noise_seed), voicenum);
- save_item(NAME(voice->noise_hold), voicenum);
- save_item(NAME(voice->noise_counter), voicenum);
- save_item(NAME(voice->waveform_select), voicenum);
}
+
+ /* register with the save state system */
+ save_pointer(STRUCT_MEMBER(m_channel_list, frequency), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, counter), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, volume), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, noise_sw), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, noise_state), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, noise_seed), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, noise_hold), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, noise_counter), m_voices);
+ save_pointer(STRUCT_MEMBER(m_channel_list, waveform_select), m_voices);
+}
+
+
+void namco_device::device_start()
+{
+ namco_audio_device::device_start();
+
+ m_soundregs = make_unique_clear<uint8_t[]>(0x400);
+ save_pointer(NAME(m_soundregs), 0x400);
+}
+
+
+void namco_15xx_device::device_start()
+{
+ namco_audio_device::device_start();
+
+ m_soundregs = make_unique_clear<uint8_t[]>(0x400);
+ save_pointer(NAME(m_soundregs), 0x400);
}
@@ -198,14 +208,16 @@ void namco_audio_device::update_namco_waveform(int offset, uint8_t data)
/* build the decoded waveform table */
void namco_audio_device::build_decoded_waveform(uint8_t *rgnbase)
{
- int16_t *p;
- int size;
- int offset;
- int v;
-
- m_wavedata = (rgnbase != nullptr) ? rgnbase : auto_alloc_array_clear(machine(), uint8_t, 0x400);
+ if (rgnbase != nullptr)
+ m_wavedata = rgnbase;
+ else
+ {
+ m_waveram_alloc = make_unique_clear<uint8_t[]>(0x400);
+ m_wavedata = m_waveram_alloc.get();
+ }
/* 20pacgal has waves in RAM but old sound system */
+ int size;
if (rgnbase == nullptr && m_voices != 3)
{
m_wave_size = 1;
@@ -217,20 +229,11 @@ void namco_audio_device::build_decoded_waveform(uint8_t *rgnbase)
size = 32 * 8; /* 32 samples, 8 waveforms */
}
- p = auto_alloc_array(machine(), int16_t, size * MAX_VOLUME);
-
- for (v = 0; v < MAX_VOLUME; v++)
- {
- m_waveform[v] = p;
- p += size;
- }
+ for (int v = 0; v < MAX_VOLUME; v++)
+ m_waveform[v] = std::make_unique<int16_t[]>(size);
- /* We need waveform data. It fails if region is not specified. */
- if (m_wavedata)
- {
- for (offset = 0; offset < 256; offset++)
- update_namco_waveform(offset, m_wavedata[offset]);
- }
+ for (int offset = 0; offset < 256; offset++)
+ update_namco_waveform(offset, m_wavedata[offset]);
}
@@ -239,7 +242,7 @@ uint32_t namco_audio_device::namco_update_one(write_stream_view &buffer, const i
{
for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
- buffer.add(sampindex, stream_buffer::sample_t(wave[WAVEFORM_POSITION(counter)]) * sample_scale);
+ buffer.add_int(sampindex, wave[WAVEFORM_POSITION(counter)], 32768);
counter += freq;
}
@@ -329,15 +332,17 @@ void namco_cus30_device::pacman_sound_w(offs_t offset, uint8_t data)
sound_channel *voice;
int ch;
+ uint8_t *soundregs = &m_wavedata[0x100];
+
data &= 0x0f;
- if (m_soundregs[offset] == data)
+ if (soundregs[offset] == data)
return;
/* update the streams */
m_stream->update();
/* set the register */
- m_soundregs[offset] = data;
+ soundregs[offset] = data;
if (offset < 0x10)
ch = (offset - 5) / 5;
@@ -364,11 +369,11 @@ void namco_cus30_device::pacman_sound_w(offs_t offset, uint8_t data)
case 0x14:
/* the frequency has 20 bits */
/* the first voice has extra frequency bits */
- voice->frequency = (ch == 0) ? m_soundregs[0x10] : 0;
- voice->frequency += (m_soundregs[ch * 5 + 0x11] << 4);
- voice->frequency += (m_soundregs[ch * 5 + 0x12] << 8);
- voice->frequency += (m_soundregs[ch * 5 + 0x13] << 12);
- voice->frequency += (m_soundregs[ch * 5 + 0x14] << 16); /* always 0 */
+ voice->frequency = (ch == 0) ? soundregs[0x10] : 0;
+ voice->frequency += (soundregs[ch * 5 + 0x11] << 4);
+ voice->frequency += (soundregs[ch * 5 + 0x12] << 8);
+ voice->frequency += (soundregs[ch * 5 + 0x13] << 12);
+ voice->frequency += (soundregs[ch * 5 + 0x14] << 16); /* always 0 */
break;
case 0x15:
@@ -568,16 +573,16 @@ void namco_cus30_device::namcos1_sound_w(offs_t offset, uint8_t data)
return;
}
- m_soundregs = m_wavedata + 0x100;
+ uint8_t *soundregs = &m_wavedata[0x100];
- if (m_soundregs[offset] == data)
+ if (soundregs[offset] == data)
return;
/* update the streams */
m_stream->update();
/* set the register */
- m_soundregs[offset] = data;
+ soundregs[offset] = data;
ch = offset / 8;
if (ch >= m_voices)
@@ -596,9 +601,9 @@ void namco_cus30_device::namcos1_sound_w(offs_t offset, uint8_t data)
case 0x02:
case 0x03:
/* the frequency has 20 bits */
- voice->frequency = (m_soundregs[ch * 8 + 0x01] & 15) << 16; /* high bits are from here */
- voice->frequency += m_soundregs[ch * 8 + 0x02] << 8;
- voice->frequency += m_soundregs[ch * 8 + 0x03];
+ voice->frequency = (soundregs[ch * 8 + 0x01] & 15) << 16; /* high bits are from here */
+ voice->frequency += soundregs[ch * 8 + 0x02] << 8;
+ voice->frequency += soundregs[ch * 8 + 0x03];
break;
case 0x04:
@@ -699,13 +704,13 @@ void namco_audio_device::sound_stream_update(sound_stream &stream, std::vector<r
if (voice->noise_state)
{
- lmix.add(i, stream_buffer::sample_t(l_noise_data) * sample_scale);
- rmix.add(i, stream_buffer::sample_t(r_noise_data) * sample_scale);
+ lmix.add_int(i, l_noise_data, 32768);
+ rmix.add_int(i, r_noise_data, 32768);
}
else
{
- lmix.add(i, stream_buffer::sample_t(-l_noise_data) * sample_scale);
- rmix.add(i, stream_buffer::sample_t(-r_noise_data) * sample_scale);
+ lmix.add_int(i, -l_noise_data, 32768);
+ rmix.add_int(i, -r_noise_data, 32768);
}
if (hold)
@@ -799,9 +804,9 @@ void namco_audio_device::sound_stream_update(sound_stream &stream, std::vector<r
int cnt;
if (voice->noise_state)
- buffer.add(i, stream_buffer::sample_t(noise_data) * sample_scale);
+ buffer.add_int(i, noise_data, 32768);
else
- buffer.add(i, stream_buffer::sample_t(-noise_data) * sample_scale);
+ buffer.add_int(i, -noise_data, 32768);
if (hold)
{
diff --git a/src/devices/sound/namco.h b/src/devices/sound/namco.h
index 6b3cee6a1f5..f032a71a536 100644
--- a/src/devices/sound/namco.h
+++ b/src/devices/sound/namco.h
@@ -52,7 +52,6 @@ protected:
/* data about the sound system */
sound_channel m_channel_list[MAX_VOICES];
sound_channel *m_last_channel;
- uint8_t *m_soundregs;
uint8_t *m_wavedata;
/* global sound parameters */
@@ -66,8 +65,10 @@ protected:
int m_voices; /* number of voices */
bool m_stereo; /* set to indicate stereo (e.g., System 1) */
+ std::unique_ptr<uint8_t[]> m_waveram_alloc;
+
/* decoded waveform table */
- int16_t *m_waveform[MAX_VOLUME];
+ std::unique_ptr<int16_t[]> m_waveform[MAX_VOLUME];
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
};
@@ -79,13 +80,17 @@ public:
void pacman_sound_w(offs_t offset, uint8_t data);
- void polepos_sound_enable(int enable);
-
uint8_t polepos_sound_r(offs_t offset);
void polepos_sound_w(offs_t offset, uint8_t data);
protected:
+ // device-level overrides
+ virtual void device_start() override;
+
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ std::unique_ptr<uint8_t[]> m_soundregs;
};
@@ -99,7 +104,13 @@ public:
void sharedram_w(offs_t offset, uint8_t data);
protected:
+ // device-level overrides
+ virtual void device_start() override;
+
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ std::unique_ptr<uint8_t[]> m_soundregs;
};
diff --git a/src/devices/sound/namco_163.cpp b/src/devices/sound/namco_163.cpp
index 153b0bfe042..08daf720d17 100644
--- a/src/devices/sound/namco_163.cpp
+++ b/src/devices/sound/namco_163.cpp
@@ -11,13 +11,14 @@
#include "emu.h"
#include "namco_163.h"
+#include <algorithm>
+
DEFINE_DEVICE_TYPE(NAMCO_163, namco_163_sound_device, "namco_163_sound", "Namco 163 (Sound)")
namco_163_sound_device::namco_163_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, NAMCO_163, tag, owner, clock)
, device_sound_interface(mconfig, *this)
- , m_ram(nullptr)
, m_reg_addr(0x78)
, m_addr(0)
, m_inc(false)
@@ -33,10 +34,11 @@ namco_163_sound_device::namco_163_sound_device(const machine_config &mconfig, co
void namco_163_sound_device::device_start()
{
- m_ram = make_unique_clear<u8[]>(0x80);
- m_stream = stream_alloc_legacy(0, 1, clock() / 15);
+ std::fill(std::begin(m_ram), std::end(m_ram), 0);
+
+ m_stream = stream_alloc(0, 1, clock() / 15);
- save_pointer(NAME(m_ram), 0x80);
+ save_item(NAME(m_ram));
save_item(NAME(m_reg_addr));
save_item(NAME(m_addr));
save_item(NAME(m_inc));
@@ -143,15 +145,16 @@ u8 namco_163_sound_device::data_r()
}
-void namco_163_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void namco_163_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- std::fill_n(&outputs[0][0], samples, 0);
-
if (m_disable)
+ {
+ outputs[0].fill(0);
return;
+ }
// Slightly noisy but closer to real hardware behavior
- for (int s = 0; s < samples; s++)
+ for (int s = 0; s < outputs[0].samples(); s++)
{
u32 phase = (m_ram[m_reg_addr + 5] << 16) | (m_ram[m_reg_addr + 3] << 8) | m_ram[m_reg_addr + 1];
const u32 freq = ((m_ram[m_reg_addr + 4] & 0x3) << 16) | (m_ram[m_reg_addr + 2] << 8) | m_ram[m_reg_addr + 0];
@@ -171,6 +174,6 @@ void namco_163_sound_device::sound_stream_update_legacy(sound_stream &stream, st
{
m_reg_addr = 0x78 - ((m_ram[0x7f] & 0x70) >> 1);
}
- outputs[0][s] = (output << 8);
+ outputs[0].put_int(s, output, 128);
}
}
diff --git a/src/devices/sound/namco_163.h b/src/devices/sound/namco_163.h
index 74d2ceacb68..f3a7428300d 100644
--- a/src/devices/sound/namco_163.h
+++ b/src/devices/sound/namco_163.h
@@ -24,7 +24,7 @@ protected:
virtual void device_clock_changed() override;
// global sound parameters
- std::unique_ptr<u8[]> m_ram;
+ u8 m_ram[0x80];
u8 m_reg_addr;
u8 m_addr;
bool m_inc;
@@ -34,7 +34,7 @@ protected:
// internals
inline s8 get_sample(u16 addr);
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
};
DECLARE_DEVICE_TYPE(NAMCO_163, namco_163_sound_device)
diff --git a/src/devices/sound/nes_apu.cpp b/src/devices/sound/nes_apu.cpp
index 1e79304fb3a..483b337475f 100644
--- a/src/devices/sound/nes_apu.cpp
+++ b/src/devices/sound/nes_apu.cpp
@@ -83,8 +83,8 @@ void nesapu_device::create_syncs(unsigned long sps)
DEFINE_DEVICE_TYPE(NES_APU, nesapu_device, "nesapu", "N2A03 APU")
-nesapu_device::nesapu_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : device_t(mconfig, NES_APU, tag, owner, clock)
+nesapu_device::nesapu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, m_samps_per_sync(0)
, m_buffer_size(0)
@@ -108,6 +108,11 @@ nesapu_device::nesapu_device(const machine_config &mconfig, const char *tag, dev
}
}
+nesapu_device::nesapu_device(const machine_config& mconfig, const char* tag, device_t* owner, u32 clock)
+ : nesapu_device(mconfig, NES_APU, tag, owner, clock)
+{
+}
+
void nesapu_device::device_reset()
{
write(0x15, 0x00);
@@ -134,7 +139,7 @@ void nesapu_device::calculate_rates()
if (m_stream != nullptr)
m_stream->set_sample_rate(rate);
else
- m_stream = stream_alloc_legacy(0, 1, rate);
+ m_stream = stream_alloc(0, 1, rate);
}
//-------------------------------------------------
@@ -725,16 +730,15 @@ void nesapu_device::write(offs_t address, u8 value)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void nesapu_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void nesapu_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int accum;
- stream_sample_t *output = outputs[0];
- memset( output, 0, samples*sizeof(*output) );
+ auto &output = outputs[0];
- while (samples--)
+ for (int sampindex = 0; sampindex < output.samples(); sampindex++)
{
accum = apu_square(&m_APU.squ[0]);
accum += apu_square(&m_APU.squ[1]);
@@ -742,12 +746,6 @@ void nesapu_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
accum += apu_noise(&m_APU.noi);
accum += apu_dpcm(&m_APU.dpcm);
- /* 8-bit clamps */
- if (accum > 127)
- accum = 127;
- else if (accum < -128)
- accum = -128;
-
- *output++=accum<<8;
+ output.put_int_clamp(sampindex, accum, 128);
}
}
diff --git a/src/devices/sound/nes_apu.h b/src/devices/sound/nes_apu.h
index c0e2e02244b..673c967fec7 100644
--- a/src/devices/sound/nes_apu.h
+++ b/src/devices/sound/nes_apu.h
@@ -56,11 +56,13 @@ public:
void write(offs_t offset, u8 data);
protected:
+ nesapu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
// device-level overrides
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
/* GLOBAL CONSTANTS */
diff --git a/src/devices/sound/nes_apu_vt.cpp b/src/devices/sound/nes_apu_vt.cpp
new file mode 100644
index 00000000000..f93c3203bac
--- /dev/null
+++ b/src/devices/sound/nes_apu_vt.cpp
@@ -0,0 +1,28 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+// The XOP is the NES APU type found in VT platforms, it roughly doubles the functionality of the APU
+// but in ways that means simply installing 2 APU devices isn't entirely correct (registers on one
+// APU module having an effect on the other)
+
+// TODO: everything
+
+#include "emu.h"
+#include "sound/nes_apu_vt.h"
+
+DEFINE_DEVICE_TYPE(NES_APU_VT, nes_apu_vt_device, "nes_apu_vt", "XOP APU")
+
+nes_apu_vt_device::nes_apu_vt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nesapu_device(mconfig, NES_APU_VT, tag, owner, clock)
+{
+}
+
+void nes_apu_vt_device::device_start()
+{
+ nesapu_device::device_start();
+}
+
+void nes_apu_vt_device::device_reset()
+{
+ nesapu_device::device_reset();
+}
diff --git a/src/devices/sound/nes_apu_vt.h b/src/devices/sound/nes_apu_vt.h
new file mode 100644
index 00000000000..f93616673fa
--- /dev/null
+++ b/src/devices/sound/nes_apu_vt.h
@@ -0,0 +1,26 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_AUDIO_NES_VT_APU_H
+#define MAME_AUDIO_NES_VT_APU_H
+
+#pragma once
+
+#include "sound/nes_apu.h"
+
+DECLARE_DEVICE_TYPE(NES_APU_VT, nes_apu_vt_device)
+
+class nes_apu_vt_device : public nesapu_device
+{
+public:
+ // construction/destruction
+ nes_apu_vt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+};
+
+#endif // MAME_AUDIO_NES_VT_APU_H
diff --git a/src/devices/sound/nile.cpp b/src/devices/sound/nile.cpp
index aeaeeaca59c..345c88f2bf0 100644
--- a/src/devices/sound/nile.cpp
+++ b/src/devices/sound/nile.cpp
@@ -68,7 +68,7 @@ nile_device::nile_device(const machine_config &mconfig, const char *tag, device_
void nile_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, 44100);
+ m_stream = stream_alloc(0, 2, 44100);
save_item(NAME(m_sound_regs));
save_item(NAME(m_vpos));
save_item(NAME(m_frac));
@@ -78,23 +78,24 @@ void nile_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests
+// sound_stream_update - handle update requests
// for our sound stream
//-------------------------------------------------
-void nile_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void nile_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
uint8_t *sound_ram = &m_sound_ram[0];
int v, i, snum;
uint16_t *slot;
- int32_t mix[48000*2];
+ int32_t mix[4800*2];
int32_t *mixp;
int16_t sample;
int sptr, eptr, freq, lsptr, leptr;
lsptr=leptr=0;
- memset(mix, 0, sizeof(mix[0])*samples*2);
+ sound_assert(outputs[0].samples() * 2 < ARRAY_LENGTH(mix));
+ std::fill_n(&mix[0], outputs[0].samples()*2, 0);
for (v = 0; v < NILE_VOICES; v++)
{
@@ -111,7 +112,7 @@ void nile_device::sound_stream_update_legacy(sound_stream &stream, stream_sample
lsptr = slot[NILE_REG_LSPTR_HI]<<16 | slot[NILE_REG_LSPTR_LO];
leptr = slot[NILE_REG_LEPTR_HI]<<16 | slot[NILE_REG_LEPTR_LO];
- for (snum = 0; snum < samples; snum++)
+ for (snum = 0; snum < outputs[0].samples(); snum++)
{
sample = sound_ram[sptr + m_vpos[v]]<<8;
@@ -159,10 +160,10 @@ void nile_device::sound_stream_update_legacy(sound_stream &stream, stream_sample
}
}
mixp = &mix[0];
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
- outputs[0][i] = (*mixp++)>>4;
- outputs[1][i] = (*mixp++)>>4;
+ outputs[0].put_int(i, *mixp++, 32768 * 16);
+ outputs[1].put_int(i, *mixp++, 32768 * 16);
}
}
diff --git a/src/devices/sound/nile.h b/src/devices/sound/nile.h
index a87fb875c11..61add38d44e 100644
--- a/src/devices/sound/nile.h
+++ b/src/devices/sound/nile.h
@@ -23,7 +23,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
public:
void nile_snd_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
diff --git a/src/devices/sound/okim6258.cpp b/src/devices/sound/okim6258.cpp
index 5f063f4cd87..349fe9ca13c 100644
--- a/src/devices/sound/okim6258.cpp
+++ b/src/devices/sound/okim6258.cpp
@@ -114,7 +114,7 @@ void okim6258_device::device_start()
m_divider = dividers[m_start_divider];
- m_stream = stream_alloc_legacy(0, 1, clock()/m_divider);
+ m_stream = stream_alloc(0, 1, clock()/m_divider);
m_signal = -2;
m_step = 0;
@@ -138,20 +138,18 @@ void okim6258_device::device_reset()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void okim6258_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void okim6258_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
-
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+ auto &buffer = outputs[0];
if (m_status & STATUS_PLAYING)
{
int nibble_shift = m_nibble_shift;
- while (samples)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
/* Compute the new amplitude and update the current step */
int nibble = (m_data_in >> nibble_shift) & 0xf;
@@ -161,8 +159,7 @@ void okim6258_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
nibble_shift ^= 4;
- *buffer++ = sample;
- samples--;
+ buffer.put_int(sampindex, sample, 32768);
}
/* Update the parameters */
@@ -170,9 +167,7 @@ void okim6258_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
}
else
{
- /* Fill with 0 */
- while (samples--)
- *buffer++ = 0;
+ buffer.fill(0);
}
}
diff --git a/src/devices/sound/okim6258.h b/src/devices/sound/okim6258.h
index c8397b998bf..95189f0ef3c 100644
--- a/src/devices/sound/okim6258.h
+++ b/src/devices/sound/okim6258.h
@@ -47,7 +47,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void state_save_register();
diff --git a/src/devices/sound/okim6295.cpp b/src/devices/sound/okim6295.cpp
index c3aee26e52e..a6acbe12e9b 100644
--- a/src/devices/sound/okim6295.cpp
+++ b/src/devices/sound/okim6295.cpp
@@ -344,7 +344,6 @@ void okim6295_device::okim_voice::generate_adpcm(device_rom_interface &rom, writ
return;
// loop while we still have samples to generate
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 2048.0;
for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
// fetch the next sample byte
@@ -352,7 +351,7 @@ void okim6295_device::okim_voice::generate_adpcm(device_rom_interface &rom, writ
// output to the buffer, scaling by the volume
// signal in range -2048..2047
- buffer.add(sampindex, m_adpcm.clock(nibble) * sample_scale * m_volume);
+ buffer.add_int(sampindex, m_adpcm.clock(nibble) * m_volume, 2048);
// next!
if (++m_sample >= m_count)
diff --git a/src/devices/sound/okim6376.cpp b/src/devices/sound/okim6376.cpp
index 3cb3e6fc17b..d7cd143e003 100644
--- a/src/devices/sound/okim6376.cpp
+++ b/src/devices/sound/okim6376.cpp
@@ -169,7 +169,7 @@ void okim6376_device::device_start()
m_ch2_update = 0;
m_st_pulses = 0;
/* generate the name and create the stream */
- m_stream = stream_alloc_legacy(0, 1, get_sample_rate());
+ m_stream = stream_alloc(0, 1, get_sample_rate());
/* initialize the voices */
for (voice = 0; voice < OKIM6376_VOICES; voice++)
@@ -578,21 +578,18 @@ void okim6376_device::write(uint8_t data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void okim6376_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void okim6376_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int i;
-
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+ outputs[0].fill(0);
- for (i = 0; i < OKIM6376_VOICES; i++)
+ for (int i = 0; i < OKIM6376_VOICES; i++)
{
struct ADPCMVoice *voice = &m_voice[i];
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
int16_t sample_data[MAX_SAMPLE_CHUNK];
- int remaining = samples;
if (i == 0) //channel 1 is the only channel to affect NAR
{
if (m_nartimer > 0)
@@ -606,16 +603,16 @@ void okim6376_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
}
/* loop while we have samples remaining */
- while (remaining)
+ for (int sampindex = 0; sampindex < buffer.samples(); )
{
+ int remaining = buffer.samples() - sampindex;
int samples = (remaining > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : remaining;
- int samp;
generate_adpcm(voice, sample_data, samples,i);
- for (samp = 0; samp < samples; samp++)
- *buffer++ += sample_data[samp];
+ for (int samp = 0; samp < samples; samp++)
+ buffer.add_int(sampindex + samp, sample_data[samp], 32768);
- remaining -= samples;
+ sampindex += samples;
}
}
}
diff --git a/src/devices/sound/okim6376.h b/src/devices/sound/okim6376.h
index 83be973fadf..34a23764e3a 100644
--- a/src/devices/sound/okim6376.h
+++ b/src/devices/sound/okim6376.h
@@ -32,7 +32,7 @@ protected:
virtual void device_post_load() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/okim9810.cpp b/src/devices/sound/okim9810.cpp
index a28cfb1af79..21e2624cd80 100644
--- a/src/devices/sound/okim9810.cpp
+++ b/src/devices/sound/okim9810.cpp
@@ -112,7 +112,7 @@ okim9810_device::okim9810_device(const machine_config &mconfig, const char *tag,
void okim9810_device::device_start()
{
// create the stream
- m_stream = stream_alloc_legacy(0, 2, clock());
+ m_stream = stream_alloc(0, 2, clock());
// save state stuff
save_item(NAME(m_TMP_register));
@@ -214,15 +214,15 @@ void okim9810_device::rom_bank_updated()
// our sound stream
//-------------------------------------------------
-void okim9810_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void okim9810_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// reset the output streams
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
// iterate over voices and accumulate sample data
for (auto & elem : m_voice)
- elem.generate_audio(*this, outputs, samples, m_global_volume, m_filter_type);
+ elem.generate_audio(*this, outputs, m_global_volume, m_filter_type);
}
@@ -613,8 +613,7 @@ okim9810_device::okim_voice::okim_voice()
//-------------------------------------------------
void okim9810_device::okim_voice::generate_audio(device_rom_interface &rom,
- stream_sample_t * const *buffers,
- int samples,
+ std::vector<write_stream_view> &outputs,
const uint8_t global_volume,
const uint8_t filter_type)
{
@@ -623,8 +622,8 @@ void okim9810_device::okim_voice::generate_audio(device_rom_interface &rom,
return;
// separate out left and right channels
- stream_sample_t *outL = buffers[0];
- stream_sample_t *outR = buffers[1];
+ auto &outL = outputs[0];
+ auto &outR = outputs[1];
// get left and right volumes
uint8_t volume_scale_left = volume_scale(global_volume, m_channel_volume, m_pan_volume_left);
@@ -636,7 +635,7 @@ void okim9810_device::okim_voice::generate_audio(device_rom_interface &rom,
return;
// loop while we still have samples to generate
- while (samples-- != 0)
+ for (int sampindex = 0; sampindex < outL.samples(); sampindex++)
{
// If interpSampleNum == 0, we are at the beginning of a new interp chunk, gather data
if (m_interpSampleNum == 0)
@@ -747,11 +746,11 @@ void okim9810_device::okim_voice::generate_audio(device_rom_interface &rom,
// output to the stereo buffers, scaling by the volume
// signal in range -2048..2047, volume in range 2..128 => signal * volume / 8 in range -32768..32767
- int32_t interpValueL = (interpValue * (int32_t)volume_scale_left) / 8;
- *outL++ += interpValueL;
+ int32_t interpValueL = (interpValue * (int32_t)volume_scale_left);
+ outL.add_int(sampindex, interpValueL, 32768 * 8);
- int32_t interpValueR = (interpValue * (int32_t)volume_scale_right) / 8;
- *outR++ += interpValueR;
+ int32_t interpValueR = (interpValue * (int32_t)volume_scale_right);
+ outR.add_int(sampindex, interpValueR, 32768 * 8);
// if the interpsample has reached its end, move on to the next sample
m_interpSampleNum++;
diff --git a/src/devices/sound/okim9810.h b/src/devices/sound/okim9810.h
index dfb4cd047aa..01977b23e2b 100644
--- a/src/devices/sound/okim9810.h
+++ b/src/devices/sound/okim9810.h
@@ -30,7 +30,7 @@
class okim9810_device : public device_t,
public device_sound_interface,
- public device_rom_interface<24>
+ public device_rom_interface<24, 0, 0, ENDIANNESS_BIG>
{
public:
// construction/destruction
@@ -87,7 +87,7 @@ protected:
virtual void device_clock_changed() override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
@@ -98,8 +98,7 @@ protected:
public:
okim_voice();
void generate_audio(device_rom_interface &rom,
- stream_sample_t * const *buffers,
- int samples,
+ std::vector<write_stream_view> &buffers,
const uint8_t global_volume,
const uint8_t filter_type);
diff --git a/src/devices/sound/pcd3311.cpp b/src/devices/sound/pcd3311.cpp
index deae4f61062..4b5a4fb87f5 100644
--- a/src/devices/sound/pcd3311.cpp
+++ b/src/devices/sound/pcd3311.cpp
@@ -48,10 +48,11 @@ void pcd3311_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void pcd3311_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void pcd3311_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
diff --git a/src/devices/sound/pcd3311.h b/src/devices/sound/pcd3311.h
index f56d63633ba..5d5b8870008 100644
--- a/src/devices/sound/pcd3311.h
+++ b/src/devices/sound/pcd3311.h
@@ -48,7 +48,7 @@ protected:
virtual void device_start() override;
// internal callbacks
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
int m_a0;
diff --git a/src/devices/sound/qs1000.cpp b/src/devices/sound/qs1000.cpp
index 5674ab6db18..23b0ee76a44 100644
--- a/src/devices/sound/qs1000.cpp
+++ b/src/devices/sound/qs1000.cpp
@@ -229,7 +229,7 @@ void qs1000_device::device_start()
// The QS1000 operates at 24MHz. Creating a stream at that rate
// would be overkill so we opt for a fraction of that rate which
// gives reasonable results
- m_stream = stream_alloc_legacy(0, 2, clock() / 32);
+ m_stream = stream_alloc(0, 2, clock() / 32);
// Resolve CPU port callbacks
m_in_p1_cb.resolve_safe(0);
@@ -466,13 +466,13 @@ void qs1000_device::wave_w(offs_t offset, uint8_t data)
//-------------------------------------------------
-// sound_stream_update_legacy -
+// sound_stream_update -
//-------------------------------------------------
-void qs1000_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void qs1000_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// Rset the output stream
- memset(outputs[0], 0x0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0x0, samples * sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
// Iterate over voices and accumulate sample data
for (auto & chan : m_channels)
@@ -485,7 +485,7 @@ void qs1000_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
{
if (chan.m_flags & QS1000_ADPCM)
{
- for (int samp = 0; samp < samples; samp++)
+ for (int samp = 0; samp < outputs[0].samples(); samp++)
{
if (chan.m_addr >= chan.m_loop_end)
{
@@ -529,13 +529,13 @@ void qs1000_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
chan.m_addr = (chan.m_addr + (chan.m_acc >> 18)) & QS1000_ADDRESS_MASK;
chan.m_acc &= ((1 << 18) - 1);
- outputs[0][samp] += (result * 4 * lvol * vol) >> 12;
- outputs[1][samp] += (result * 4 * rvol * vol) >> 12;
+ outputs[0].add_int(samp, result * 4 * lvol * vol, 32768 << 12);
+ outputs[1].add_int(samp, result * 4 * rvol * vol, 32768 << 12);
}
}
else
{
- for (int samp = 0; samp < samples; samp++)
+ for (int samp = 0; samp < outputs[0].samples(); samp++)
{
if (chan.m_addr >= chan.m_loop_end)
{
@@ -558,8 +558,8 @@ void qs1000_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
chan.m_addr = (chan.m_addr + (chan.m_acc >> 18)) & QS1000_ADDRESS_MASK;
chan.m_acc &= ((1 << 18) - 1);
- outputs[0][samp] += (result * lvol * vol) >> 12;
- outputs[1][samp] += (result * rvol * vol) >> 12;
+ outputs[0].add_int(samp, result * lvol * vol, 32768 << 12);
+ outputs[1].add_int(samp, result * rvol * vol, 32768 << 12);
}
}
}
diff --git a/src/devices/sound/qs1000.h b/src/devices/sound/qs1000.h
index 0c16e69b193..aad353962a5 100644
--- a/src/devices/sound/qs1000.h
+++ b/src/devices/sound/qs1000.h
@@ -73,7 +73,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/qsound.cpp b/src/devices/sound/qsound.cpp
index 232e367f1d2..29b2661add5 100644
--- a/src/devices/sound/qsound.cpp
+++ b/src/devices/sound/qsound.cpp
@@ -207,7 +207,7 @@ void qsound_device::device_add_mconfig(machine_config &config)
void qsound_device::device_start()
{
// hope we get good synchronisation between the DSP and the sound system
- m_stream = stream_alloc_legacy(0, 2, clock() / 2 / 1248);
+ m_stream = stream_alloc(0, 2, clock() / 2 / 1248);
// save DSP communication state
save_item(NAME(m_rom_bank));
@@ -251,13 +251,13 @@ void qsound_device::device_reset()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void qsound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void qsound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- std::fill_n(outputs[0], samples, m_samples[0]);
- std::fill_n(outputs[1], samples, m_samples[1]);
+ outputs[0].fill(stream_buffer::sample_t(m_samples[0]) * (1.0 / 32768.0));
+ outputs[1].fill(stream_buffer::sample_t(m_samples[1]) * (1.0 / 32768.0));
}
diff --git a/src/devices/sound/qsound.h b/src/devices/sound/qsound.h
index ac0a1053ffe..6a9be5dfbc2 100644
--- a/src/devices/sound/qsound.h
+++ b/src/devices/sound/qsound.h
@@ -32,7 +32,7 @@ protected:
virtual void device_reset() override;
// device_sound_interface implementation
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface implementation
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/qsoundhle.cpp b/src/devices/sound/qsoundhle.cpp
index 9ff99ee8cab..913d22baed1 100644
--- a/src/devices/sound/qsoundhle.cpp
+++ b/src/devices/sound/qsoundhle.cpp
@@ -64,7 +64,7 @@ void qsound_hle_device::rom_bank_updated()
void qsound_hle_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, clock() / 2 / 1248); // DSP program uses 1248 machine cycles per iteration
+ m_stream = stream_alloc(0, 2, clock() / 2 / 1248); // DSP program uses 1248 machine cycles per iteration
init_register_map();
@@ -158,20 +158,16 @@ void qsound_hle_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void qsound_hle_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void qsound_hle_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- // Clear the buffers
- std::fill_n(outputs[0], samples, 0);
- std::fill_n(outputs[1], samples, 0);
-
- for (int i = 0; i < samples; i ++)
+ for (int i = 0; i < outputs[0].samples(); i ++)
{
update_sample();
- outputs[0][i] = m_out[0];
- outputs[1][i] = m_out[1];
+ outputs[0].put_int(i, m_out[0], 32768);
+ outputs[1].put_int(i, m_out[1], 32768);
}
}
diff --git a/src/devices/sound/qsoundhle.h b/src/devices/sound/qsoundhle.h
index 23b92738b9b..4d6f61e0c7d 100644
--- a/src/devices/sound/qsoundhle.h
+++ b/src/devices/sound/qsoundhle.h
@@ -30,7 +30,7 @@ protected:
virtual void device_reset() override;
// device_sound_interface implementation
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface implementation
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/rf5c400.cpp b/src/devices/sound/rf5c400.cpp
index b8de150f7f6..7495e484540 100644
--- a/src/devices/sound/rf5c400.cpp
+++ b/src/devices/sound/rf5c400.cpp
@@ -180,7 +180,7 @@ void rf5c400_device::device_start()
save_item(STRUCT_MEMBER(m_channels, env_step));
save_item(STRUCT_MEMBER(m_channels, env_scale));
- m_stream = stream_alloc_legacy(0, 2, clock() / 384);
+ m_stream = stream_alloc(0, 2, clock() / 384);
}
//-------------------------------------------------
@@ -195,10 +195,10 @@ void rf5c400_device::device_clock_changed()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void rf5c400_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void rf5c400_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i, ch;
uint64_t end, loop;
@@ -207,14 +207,14 @@ void rf5c400_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
uint8_t env_phase;
double env_level, env_step, env_rstep;
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
for (ch=0; ch < 32; ch++)
{
rf5c400_channel *channel = &m_channels[ch];
- stream_sample_t *buf0 = outputs[0];
- stream_sample_t *buf1 = outputs[1];
+ auto &buf0 = outputs[0];
+ auto &buf1 = outputs[1];
// start = ((channel->startH & 0xFF00) << 8) | channel->startL;
end = ((channel->endHloopH & 0xFF) << 16) | channel->endL;
@@ -230,7 +230,7 @@ void rf5c400_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
env_step = channel->env_step;
env_rstep = env_step * channel->env_scale;
- for (i=0; i < samples; i++)
+ for (i=0; i < buf0.samples(); i++)
{
int16_t tmp;
int32_t sample;
@@ -300,8 +300,8 @@ void rf5c400_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
sample *= volume_table[vol];
sample = (sample >> 9) * env_level;
- *buf0++ += sample * pan_table[lvol];
- *buf1++ += sample * pan_table[rvol];
+ buf0.add_int(i, sample * pan_table[lvol], 32768);
+ buf1.add_int(i, sample * pan_table[rvol], 32768);
pos += channel->step;
if ((pos>>16) > end)
diff --git a/src/devices/sound/rf5c400.h b/src/devices/sound/rf5c400.h
index fdd82910b76..6e729daad0a 100644
--- a/src/devices/sound/rf5c400.h
+++ b/src/devices/sound/rf5c400.h
@@ -34,7 +34,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/rf5c68.cpp b/src/devices/sound/rf5c68.cpp
index 1c00941000b..f91e370b95f 100644
--- a/src/devices/sound/rf5c68.cpp
+++ b/src/devices/sound/rf5c68.cpp
@@ -81,7 +81,7 @@ void rf5c68_device::device_start()
m_sample_end_cb.resolve();
/* allocate the stream */
- m_stream = stream_alloc_legacy(0, 2, clock() / 384);
+ m_stream = stream_alloc(0, 2, clock() / 384);
save_item(STRUCT_MEMBER(m_chan, enable));
save_item(STRUCT_MEMBER(m_chan, env));
@@ -116,21 +116,29 @@ device_memory_interface::space_config_vector rf5c68_device::memory_space_config(
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void rf5c68_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void rf5c68_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *left = outputs[0];
- stream_sample_t *right = outputs[1];
-
- /* start with clean buffers */
- memset(left, 0, samples * sizeof(*left));
- memset(right, 0, samples * sizeof(*right));
+ auto &left = outputs[0];
+ auto &right = outputs[1];
/* bail if not enabled */
if (!m_enable)
+ {
+ left.fill(0);
+ right.fill(0);
return;
+ }
+
+ if (m_mixleft.size() < left.samples())
+ m_mixleft.resize(left.samples());
+ if (m_mixright.size() < right.samples())
+ m_mixright.resize(right.samples());
+
+ std::fill_n(&m_mixleft[0], left.samples(), 0);
+ std::fill_n(&m_mixright[0], right.samples(), 0);
/* loop over channels */
for (pcm_channel &chan : m_chan)
@@ -142,7 +150,7 @@ void rf5c68_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
int rv = ((chan.pan >> 4) & 0x0f) * chan.env;
/* loop over the sample buffer */
- for (int j = 0; j < samples; j++)
+ for (int j = 0; j < left.samples(); j++)
{
int sample;
@@ -170,13 +178,13 @@ void rf5c68_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
if (sample & 0x80)
{
sample &= 0x7f;
- left[j] += (sample * lv) >> 5;
- right[j] += (sample * rv) >> 5;
+ m_mixleft[j] += (sample * lv) >> 5;
+ m_mixright[j] += (sample * rv) >> 5;
}
else
{
- left[j] -= (sample * lv) >> 5;
- right[j] -= (sample * rv) >> 5;
+ m_mixleft[j] -= (sample * lv) >> 5;
+ m_mixright[j] -= (sample * rv) >> 5;
}
}
}
@@ -188,19 +196,10 @@ void rf5c68_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
*/
const u8 output_shift = (m_output_bits > 16) ? 0 : (16 - m_output_bits);
const s32 output_nandmask = (1 << output_shift) - 1;
- for (int j = 0; j < samples; j++)
+ for (int j = 0; j < left.samples(); j++)
{
- stream_sample_t temp;
-
- temp = left[j];
- if (temp > 32767) temp = 32767;
- else if (temp < -32768) temp = -32768;
- left[j] = temp & ~output_nandmask;
-
- temp = right[j];
- if (temp > 32767) temp = 32767;
- else if (temp < -32768) temp = -32768;
- right[j] = temp & ~output_nandmask;
+ left.put_int_clamp(j, m_mixleft[j] & ~output_nandmask, 32768);
+ right.put_int_clamp(j, m_mixright[j] & ~output_nandmask, 32768);
}
}
diff --git a/src/devices/sound/rf5c68.h b/src/devices/sound/rf5c68.h
index 4a1d465e291..d78f378faaf 100644
--- a/src/devices/sound/rf5c68.h
+++ b/src/devices/sound/rf5c68.h
@@ -45,7 +45,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_memory_interface configuration
virtual space_config_vector memory_space_config() const override;
@@ -75,6 +75,8 @@ private:
u16 m_wbank;
u8 m_enable;
int m_output_bits;
+ std::vector<s32> m_mixleft;
+ std::vector<s32> m_mixright;
sample_end_cb_delegate m_sample_end_cb;
};
diff --git a/src/devices/sound/rolandpcm.cpp b/src/devices/sound/rolandpcm.cpp
index 4916605dd7e..d3393785f88 100644
--- a/src/devices/sound/rolandpcm.cpp
+++ b/src/devices/sound/rolandpcm.cpp
@@ -61,7 +61,7 @@ void mb87419_mb87420_device::device_start()
m_clock = clock() / 2;
m_rate = m_clock / 512; // usually 32 KHz
- m_stream = stream_alloc_legacy(0, 2, m_rate);
+ m_stream = stream_alloc(0, 2, m_rate);
logerror("Roland PCM: Clock %u, Rate %u\n", m_clock, m_rate);
}
@@ -266,29 +266,29 @@ void mb87419_mb87420_device::write(offs_t offset, u8 data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void mb87419_mb87420_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void mb87419_mb87420_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- memset(outputs[0], 0, samples * sizeof(stream_sample_t));
- memset(outputs[1], 0, samples * sizeof(stream_sample_t));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
for (auto& chn : m_chns)
{
if (! chn.enable || chn.play_dir == 0)
continue;
- for (int smpl = 0; smpl < samples; smpl ++)
+ for (int smpl = 0; smpl < outputs[0].samples(); smpl ++)
{
- stream_sample_t smp_data;
+ s32 smp_data;
if (chn.play_dir > 0)
smp_data = sample_interpolate(chn.smpl_cur, chn.smpl_nxt, chn.addr & 0x3FFF);
else
smp_data = sample_interpolate(chn.smpl_nxt, chn.smpl_cur, chn.addr & 0x3FFF);
- smp_data = (smp_data * chn.volume) >> 14; // >>14 results in a good overall volume
- outputs[0][smpl] += smp_data;
- outputs[1][smpl] += smp_data;
+ smp_data = smp_data * chn.volume;
+ outputs[0].add_int(smpl, smp_data, 32768 << 14); // >>14 results in a good overall volume
+ outputs[1].add_int(smpl, smp_data, 32768 << 14);
uint32_t old_addr = chn.addr;
if (chn.play_dir > 0)
diff --git a/src/devices/sound/rolandpcm.h b/src/devices/sound/rolandpcm.h
index 5d1e814d517..1c77be39b98 100644
--- a/src/devices/sound/rolandpcm.h
+++ b/src/devices/sound/rolandpcm.h
@@ -24,7 +24,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/rp2c33_snd.cpp b/src/devices/sound/rp2c33_snd.cpp
index 57e60cf9fb5..d0701041a6b 100644
--- a/src/devices/sound/rp2c33_snd.cpp
+++ b/src/devices/sound/rp2c33_snd.cpp
@@ -56,7 +56,7 @@ void rp2c33_sound_device::device_start()
for (int i = 0; i < 4; i++)
m_mvol_table[i] = int((65536.0 / (32.0 * 64.0)) * 2.0 / double(i + 2));
- m_stream = stream_alloc_legacy(0, 1, clock());
+ m_stream = stream_alloc(0, 1, clock());
// save states
save_item(NAME(m_regs));
@@ -218,12 +218,12 @@ void rp2c33_sound_device::write(offs_t offset, u8 data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void rp2c33_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void rp2c33_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
m_output = 0;
if (!m_env_halt && !m_wave_halt)
@@ -234,7 +234,7 @@ void rp2c33_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
exec_mod();
exec_wave();
/* Update the buffers */
- outputs[0][i] = m_output * m_mvol_table[m_mvol];
+ outputs[0].put_int(i, m_output * m_mvol_table[m_mvol], 32768);
}
}
diff --git a/src/devices/sound/rp2c33_snd.h b/src/devices/sound/rp2c33_snd.h
index 73b737409c2..bdb32e58f60 100644
--- a/src/devices/sound/rp2c33_snd.h
+++ b/src/devices/sound/rp2c33_snd.h
@@ -43,7 +43,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_stream = nullptr;
diff --git a/src/devices/sound/s14001a.cpp b/src/devices/sound/s14001a.cpp
index 5230a66b534..aa4506ba1c8 100644
--- a/src/devices/sound/s14001a.cpp
+++ b/src/devices/sound/s14001a.cpp
@@ -226,7 +226,7 @@ ALLOW_SAVE_TYPE(s14001a_device::states); // allow save_item on a non-fundamental
void s14001a_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 1, clock() ? clock() : machine().sample_rate());
+ m_stream = stream_alloc(0, 1, clock() ? clock() : machine().sample_rate());
// resolve callbacks
m_ext_read_handler.resolve();
@@ -311,16 +311,16 @@ void s14001a_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void s14001a_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void s14001a_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
Clock();
int16_t sample = m_uOutputP2 - 7; // range -7..8
- outputs[0][i] = sample * 0xf00;
+ outputs[0].put_int(i, sample, 8);
}
}
diff --git a/src/devices/sound/s14001a.h b/src/devices/sound/s14001a.h
index 09f985a51dc..511503d9daa 100644
--- a/src/devices/sound/s14001a.h
+++ b/src/devices/sound/s14001a.h
@@ -31,7 +31,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
uint8_t readmem(uint16_t offset, bool phase);
diff --git a/src/devices/sound/s_dsp.cpp b/src/devices/sound/s_dsp.cpp
index 9385273ba66..98cd204b503 100644
--- a/src/devices/sound/s_dsp.cpp
+++ b/src/devices/sound/s_dsp.cpp
@@ -160,7 +160,7 @@ void s_dsp_device::device_start()
space().cache(m_cache);
space().specific(m_data);
- m_channel = stream_alloc_legacy(0, 2, clock() / 64);
+ m_channel = stream_alloc(0, 2, clock() / 64);
state_register();
}
@@ -1061,20 +1061,20 @@ void s_dsp_device::state_register()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void s_dsp_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void s_dsp_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
s16 mix[2];
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
mix[0] = mix[1] = 0;
dsp_update(mix);
/* Update the buffers */
- outputs[0][i] = (stream_sample_t)mix[0];
- outputs[1][i] = (stream_sample_t)mix[1];
+ outputs[0].put_int(i, (s32)mix[0], 32768);
+ outputs[1].put_int(i, (s32)mix[1], 32768);
}
}
diff --git a/src/devices/sound/s_dsp.h b/src/devices/sound/s_dsp.h
index 4ab841d0ebd..00097b17303 100644
--- a/src/devices/sound/s_dsp.h
+++ b/src/devices/sound/s_dsp.h
@@ -30,7 +30,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_memory_interface configuration
virtual space_config_vector memory_space_config() const override;
diff --git a/src/devices/sound/saa1099.cpp b/src/devices/sound/saa1099.cpp
index cad84d184bb..080ebabe89c 100644
--- a/src/devices/sound/saa1099.cpp
+++ b/src/devices/sound/saa1099.cpp
@@ -161,7 +161,7 @@ saa1099_device::saa1099_device(const machine_config &mconfig, const char *tag, d
void saa1099_device::device_start()
{
/* for each chip allocate one stream */
- m_stream = stream_alloc_legacy(0, 2, clock()/clock_divider);
+ m_stream = stream_alloc(0, 2, clock()/clock_divider);
save_item(NAME(m_noise_params));
save_item(NAME(m_env_enable));
@@ -200,18 +200,18 @@ void saa1099_device::device_clock_changed()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void saa1099_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void saa1099_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int j, ch;
/* if the channels are disabled we're done */
if (!m_all_ch_enable)
{
/* init output data */
- memset(outputs[LEFT],0,samples*sizeof(*outputs[LEFT]));
- memset(outputs[RIGHT],0,samples*sizeof(*outputs[RIGHT]));
+ outputs[LEFT].fill(0);
+ outputs[RIGHT].fill(0);
return;
}
@@ -227,7 +227,7 @@ void saa1099_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
}
/* fill all data needed */
- for( j = 0; j < samples; j++ )
+ for( j = 0; j < outputs[0].samples(); j++ )
{
int output_l = 0, output_r = 0;
@@ -285,8 +285,8 @@ void saa1099_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
m_noise[ch].counter -= clock_divider;
}
/* write sound data to the buffer */
- outputs[LEFT][j] = output_l / 6;
- outputs[RIGHT][j] = output_r / 6;
+ outputs[LEFT].put_int(j, output_l, 32768 * 6);
+ outputs[RIGHT].put_int(j, output_r, 32768 * 6);
}
}
diff --git a/src/devices/sound/saa1099.h b/src/devices/sound/saa1099.h
index 2f9361d5ce8..87f5b58f48a 100644
--- a/src/devices/sound/saa1099.h
+++ b/src/devices/sound/saa1099.h
@@ -32,7 +32,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct saa1099_channel
diff --git a/src/devices/sound/scsp.cpp b/src/devices/sound/scsp.cpp
index 143be37ca40..b340da3d237 100644
--- a/src/devices/sound/scsp.cpp
+++ b/src/devices/sound/scsp.cpp
@@ -36,9 +36,6 @@
#include <algorithm>
-static constexpr s32 clip16(int x) { return std::min(32767, std::max(-32768, x)); }
-static constexpr s32 clip18(int x) { return std::min(131071, std::max(-131072, x)); }
-
#define SHIFT 12
#define LFO_SHIFT 8
#define FIX(v) ((u32) ((float) (1 << SHIFT) * (v)))
@@ -165,11 +162,6 @@ scsp_device::scsp_device(const machine_config &mconfig, const char *tag, device_
m_timerC(nullptr),
m_mcieb(0),
m_mcipd(0),
- m_bufferl(nullptr),
- m_bufferr(nullptr),
- m_exts0(nullptr),
- m_exts1(nullptr),
- m_length(0),
m_RBUFDST(nullptr)
{
std::fill(std::begin(m_RINGBUF), std::end(m_RINGBUF), 0);
@@ -212,7 +204,7 @@ void scsp_device::device_start()
m_main_irq_cb.resolve_safe();
// Stereo output with EXTS0,1 Input (External digital audio output)
- m_stream = stream_alloc_legacy(2, 2, clock() / 512);
+ m_stream = stream_alloc(2, 2, clock() / 512);
for (int slot = 0; slot < 32; slot++)
{
@@ -317,17 +309,12 @@ void scsp_device::rom_bank_updated()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void scsp_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void scsp_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- m_exts0 = inputs[0];
- m_exts1 = inputs[1];
- m_bufferl = outputs[0];
- m_bufferr = outputs[1];
- m_length = samples;
- DoMasterSamples(samples);
+ DoMasterSamples(inputs, outputs);
}
u8 scsp_device::DecodeSCI(u8 irq)
@@ -1276,17 +1263,12 @@ inline s32 scsp_device::UpdateSlot(SCSP_SLOT *slot)
return sample;
}
-void scsp_device::DoMasterSamples(int nsamples)
+void scsp_device::DoMasterSamples(std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *bufr,*bufl;
- stream_sample_t const *exts[2];
-
- bufr = m_bufferr;
- bufl = m_bufferl;
- exts[0] = m_exts0;
- exts[1] = m_exts1;
+ auto &bufr = outputs[1];
+ auto &bufl = outputs[0];
- for (int s = 0; s < nsamples; ++s)
+ for (int s = 0; s < bufl.samples(); ++s)
{
s32 smpl = 0, smpr = 0;
@@ -1342,7 +1324,7 @@ void scsp_device::DoMasterSamples(int nsamples)
SCSP_SLOT *slot = m_Slots + i + 16; // 100217, 100237 EFSDL, EFPAN for EXTS0/1
if (EFSDL(slot))
{
- m_DSP.EXTS[i] = exts[i][s];
+ m_DSP.EXTS[i] = s32(inputs[i].get(s) * 32768.0);
u16 Enc = ((EFPAN(slot)) << 0x8) | ((EFSDL(slot)) << 0xd);
smpl += (m_DSP.EXTS[i] * m_LPANTABLE[Enc]) >> SHIFT;
smpr += (m_DSP.EXTS[i] * m_RPANTABLE[Enc]) >> SHIFT;
@@ -1351,17 +1333,14 @@ void scsp_device::DoMasterSamples(int nsamples)
if (DAC18B())
{
- smpl = clip18(smpl);
- smpr = clip18(smpr);
+ bufl.put_int_clamp(s, smpl, 131072);
+ bufr.put_int_clamp(s, smpr, 131072);
}
else
{
- smpl = clip16(smpl >> 2);
- smpr = clip16(smpr >> 2);
+ bufl.put_int_clamp(s, smpl >> 2, 32768);
+ bufr.put_int_clamp(s, smpr >> 2, 32768);
}
-
- *bufl++ = smpl;
- *bufr++ = smpr;
}
}
diff --git a/src/devices/sound/scsp.h b/src/devices/sound/scsp.h
index 4fe8c5e2a91..7ff91fdb576 100644
--- a/src/devices/sound/scsp.h
+++ b/src/devices/sound/scsp.h
@@ -45,7 +45,7 @@ protected:
virtual void rom_bank_updated() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
enum SCSP_STATE { SCSP_ATTACK, SCSP_DECAY1, SCSP_DECAY2, SCSP_RELEASE };
@@ -148,13 +148,6 @@ private:
SCSPDSP m_DSP;
- stream_sample_t *m_bufferl;
- stream_sample_t *m_bufferr;
- stream_sample_t const *m_exts0;
- stream_sample_t const *m_exts1;
-
- int m_length;
-
s16 *m_RBUFDST; //this points to where the sample will be stored in the RingBuf
//LFO
@@ -187,7 +180,7 @@ private:
void w16(u32 addr, u16 val);
u16 r16(u32 addr);
inline s32 UpdateSlot(SCSP_SLOT *slot);
- void DoMasterSamples(int nsamples);
+ void DoMasterSamples(std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs);
//LFO
void LFO_Init();
diff --git a/src/devices/sound/segapcm.cpp b/src/devices/sound/segapcm.cpp
index e93bbaec7ee..9b4d7a9c803 100644
--- a/src/devices/sound/segapcm.cpp
+++ b/src/devices/sound/segapcm.cpp
@@ -39,7 +39,7 @@ void segapcm_device::device_start()
std::fill(&m_ram[0], &m_ram[0x800], 0xff);
- m_stream = stream_alloc_legacy(0, 2, clock() / 128);
+ m_stream = stream_alloc(0, 2, clock() / 128);
save_item(NAME(m_low));
save_pointer(NAME(m_ram), 0x800);
@@ -68,14 +68,14 @@ void segapcm_device::rom_bank_updated()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void segapcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void segapcm_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
/* clear the buffers */
- memset(outputs[0], 0, samples*sizeof(*outputs[0]));
- memset(outputs[1], 0, samples*sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
// reg function
// ------------------------------------------------
@@ -113,7 +113,7 @@ void segapcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
int i;
/* loop over samples on this channel */
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
int8_t v;
@@ -132,8 +132,8 @@ void segapcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
v = read_byte(offset + (addr >> 8)) - 0x80;
/* apply panning and advance */
- outputs[0][i] += v * (regs[2] & 0x7f);
- outputs[1][i] += v * (regs[3] & 0x7f);
+ outputs[0].add_int(i, v * (regs[2] & 0x7f), 32768);
+ outputs[1].add_int(i, v * (regs[3] & 0x7f), 32768);
addr = (addr + regs[7]) & 0xffffff;
}
diff --git a/src/devices/sound/segapcm.h b/src/devices/sound/segapcm.h
index 8b9942a5727..f9869f2211f 100644
--- a/src/devices/sound/segapcm.h
+++ b/src/devices/sound/segapcm.h
@@ -41,7 +41,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/sid.cpp b/src/devices/sound/sid.cpp
index 26ba13a1f4b..86264810fda 100644
--- a/src/devices/sound/sid.cpp
+++ b/src/devices/sound/sid.cpp
@@ -29,34 +29,10 @@ float filterResTable[16];
#define maxLogicalVoices 4
-const int mix16monoMiddleIndex = 256*maxLogicalVoices/2;
-uint16_t mix16mono[256*maxLogicalVoices];
-
-uint16_t zero16bit = 0; /* either signed or unsigned */
-//uint32_t splitBufferLen;
-
-void MixerInit(int threeVoiceAmplify)
+inline stream_buffer::sample_t mix_mono(uint16_t usum)
{
- long si;
- uint16_t ui;
- long ampDiv = maxLogicalVoices;
-
- if (threeVoiceAmplify)
- {
- ampDiv = (maxLogicalVoices-1);
- }
-
- /* Mixing formulas are optimized by sample input value. */
-
- si = (-128*maxLogicalVoices) * 256;
- for (ui = 0; ui < sizeof(mix16mono)/sizeof(uint16_t); ui++)
- {
- mix16mono[ui] = (uint16_t)(si/ampDiv) + zero16bit;
- si+=256;
- }
-
+ return stream_buffer::sample_t(int16_t(usum - maxLogicalVoices*128)) * (1.0 / (256 * maxLogicalVoices));
}
-
} // anonymous namespace
@@ -85,22 +61,22 @@ inline void SID6581_t::syncEm()
}
-void SID6581_t::fill_buffer(stream_sample_t *buffer, uint32_t bufferLen)
+void SID6581_t::fill_buffer(write_stream_view &buffer)
{
//void* SID6581_t::fill16bitMono(void* buffer, uint32_t numberOfSamples)
- for (; bufferLen > 0; bufferLen--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
- *buffer++ = (int16_t) mix16mono[unsigned(mix16monoMiddleIndex
- +(*optr[0].outProc)(&optr[0])
+ buffer.put(sampindex, mix_mono(
+ (*optr[0].outProc)(&optr[0])
+(*optr[1].outProc)(&optr[1])
- +(optr[2].outProc(&optr[2])&optr3_outputmask)
+ +((*optr[2].outProc)(&optr[2])&optr3_outputmask)
/* hack for digi sounds
does n't seam to come from a tone operator
ghostbusters and goldrunner everything except volume zeroed */
+(masterVolume<<2)
// +(*sampleEmuRout)()
- )];
+ ));
syncEm();
}
}
@@ -227,8 +203,6 @@ void SID6581_t::init()
enveEmuInit(PCMfreq, true);
- MixerInit(0);
-
reset();
}
diff --git a/src/devices/sound/sid.h b/src/devices/sound/sid.h
index 6e5ad1dfa3f..ecf27c2b300 100644
--- a/src/devices/sound/sid.h
+++ b/src/devices/sound/sid.h
@@ -63,7 +63,7 @@ struct SID6581_t
int port_r(running_machine &machine, int offset);
void port_w(int offset, int data);
- void fill_buffer(stream_sample_t *buffer, uint32_t bufferLen);
+ void fill_buffer(write_stream_view &buffer);
private:
void syncEm();
diff --git a/src/devices/sound/sn76477.cpp b/src/devices/sound/sn76477.cpp
index 2903af1904b..b8db037e26b 100644
--- a/src/devices/sound/sn76477.cpp
+++ b/src/devices/sound/sn76477.cpp
@@ -203,7 +203,7 @@ sn76477_device::sn76477_device(const machine_config &mconfig, const char *tag, d
void sn76477_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
if (clock() > 0)
{
@@ -1698,10 +1698,10 @@ void sn76477_device::state_save_register()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void sn76477_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void sn76477_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
double one_shot_cap_charging_step;
double one_shot_cap_discharging_step;
@@ -1720,7 +1720,7 @@ void sn76477_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
double voltage_out;
double center_to_peak_voltage_out;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
/* compute charging values, doing it here ensures that we always use the latest values */
one_shot_cap_charging_step = compute_one_shot_cap_charging_rate() / m_our_sample_rate;
@@ -1744,7 +1744,7 @@ void sn76477_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
/* process 'samples' number of samples */
- while (samples--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
/* update the one-shot cap voltage */
if (!m_one_shot_cap_voltage_ext)
@@ -1993,10 +1993,10 @@ void sn76477_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
32767 = 2 * OUT_CENTER_LEVEL_VOLTAGE + OUT_LOW_CLIP_THRESHOLD
/ Vout - Vmin \
- sample = | ----------- - 1 | * 32767
+ sample = | ----------- - 1 |
\ Vcen - Vmin /
*/
- *buffer++ = (((voltage_out - OUT_LOW_CLIP_THRESHOLD) / (OUT_CENTER_LEVEL_VOLTAGE - OUT_LOW_CLIP_THRESHOLD)) - 1) * 32767;
+ buffer.put(sampindex, ((voltage_out - OUT_LOW_CLIP_THRESHOLD) / (OUT_CENTER_LEVEL_VOLTAGE - OUT_LOW_CLIP_THRESHOLD)) - 1);
if (LOG_WAV && (!m_enable || !LOG_WAV_ENABLED_ONLY))
{
diff --git a/src/devices/sound/sn76477.h b/src/devices/sound/sn76477.h
index 42fa82e5efc..094f8e78e1b 100644
--- a/src/devices/sound/sn76477.h
+++ b/src/devices/sound/sn76477.h
@@ -147,7 +147,7 @@ protected:
virtual void device_stop() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
/* chip's external interface */
diff --git a/src/devices/sound/sn76496.cpp b/src/devices/sound/sn76496.cpp
index 9bc686dedb2..eac04a2d99f 100644
--- a/src/devices/sound/sn76496.cpp
+++ b/src/devices/sound/sn76496.cpp
@@ -378,7 +378,6 @@ void sn76496_base_device::sound_stream_update(sound_stream &stream, std::vector<
int16_t out;
int16_t out2 = 0;
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for (int sampindex = 0; sampindex < lbuffer->samples(); sampindex++)
{
// clock chip once
@@ -445,9 +444,9 @@ void sn76496_base_device::sound_stream_update(sound_stream &stream, std::vector<
if (m_negate) { out = -out; out2 = -out2; }
- lbuffer->put(sampindex, stream_buffer::sample_t(out) * sample_scale);
+ lbuffer->put_int(sampindex, out, 32768);
if (m_stereo)
- rbuffer->put(sampindex, stream_buffer::sample_t(out2) * sample_scale);
+ rbuffer->put_int(sampindex, out2, 32768);
}
}
diff --git a/src/devices/sound/snkwave.cpp b/src/devices/sound/snkwave.cpp
index 718dde017fb..44e6ba51466 100644
--- a/src/devices/sound/snkwave.cpp
+++ b/src/devices/sound/snkwave.cpp
@@ -44,7 +44,7 @@ void snkwave_device::device_start()
m_sample_rate = m_external_clock >> CLOCK_SHIFT;
/* get stream channels */
- m_stream = stream_alloc_legacy(0, 1, m_sample_rate);
+ m_stream = stream_alloc(0, 1, m_sample_rate);
/* reset all the voices */
m_frequency = 0;
@@ -60,26 +60,26 @@ void snkwave_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests
+// sound_stream_update - handle update requests
// for our sound stream
//-------------------------------------------------
-void snkwave_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void snkwave_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
-
- /* zap the contents of the buffer */
- memset(buffer, 0, samples * sizeof(*buffer));
+ auto &buffer = outputs[0];
assert(m_counter < 0x1000);
assert(m_frequency < 0x1000);
/* if no sound, we're done */
if (m_frequency == 0xfff)
+ {
+ buffer.fill(0);
return;
+ }
/* generate sound into buffer while updating the counter */
- while (samples-- > 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int loops;
int16_t out = 0;
@@ -104,7 +104,7 @@ void snkwave_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
}
}
- *buffer++ = out;
+ buffer.put_int(sampindex, out, 32768);
}
}
diff --git a/src/devices/sound/snkwave.h b/src/devices/sound/snkwave.h
index 2ecb5f7715d..bf40a33e500 100644
--- a/src/devices/sound/snkwave.h
+++ b/src/devices/sound/snkwave.h
@@ -26,7 +26,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
static constexpr unsigned WAVEFORM_LENGTH = 16;
diff --git a/src/devices/sound/sp0250.cpp b/src/devices/sound/sp0250.cpp
index e18143a29b0..862b3781a7c 100644
--- a/src/devices/sound/sp0250.cpp
+++ b/src/devices/sound/sp0250.cpp
@@ -258,9 +258,8 @@ void sp0250_device::sound_stream_update(sound_stream &stream, std::vector<read_s
if (!m_pwm_mode)
{
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 128.0;
for (int sampindex = 0; sampindex < output.samples(); sampindex++)
- output.put(sampindex, stream_buffer::sample_t(next()) * sample_scale);
+ output.put_int(sampindex, next(), 128);
}
else
{
diff --git a/src/devices/sound/sp0256.cpp b/src/devices/sound/sp0256.cpp
index b4d18e6d6d3..5188d3bc31f 100644
--- a/src/devices/sound/sp0256.cpp
+++ b/src/devices/sound/sp0256.cpp
@@ -74,7 +74,7 @@ void sp0256_device::device_start()
m_drq_cb(1);
m_sby_cb(1);
- m_stream = stream_alloc_legacy(0, 1, clock() / CLOCK_DIVIDER);
+ m_stream = stream_alloc(0, 1, clock() / CLOCK_DIVIDER);
/* -------------------------------------------------------------------- */
/* Configure our internal variables. */
@@ -1260,16 +1260,16 @@ TIMER_CALLBACK_MEMBER(sp0256_device::set_lrq_timer_proc)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void sp0256_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void sp0256_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *output = outputs[0];
+ auto &output = outputs[0];
int output_index = 0;
int length, did_samp/*, old_idx*/;
- while (output_index < samples)
+ while (output_index < output.samples())
{
/* ---------------------------------------------------------------- */
/* First, drain as much of our scratch buffer as we can into the */
@@ -1278,20 +1278,20 @@ void sp0256_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
while (m_sc_tail != m_sc_head)
{
- output[output_index++] = m_scratch[m_sc_tail++ & SCBUF_MASK];
+ output.put_int(output_index++, m_scratch[m_sc_tail++ & SCBUF_MASK], 32768);
m_sc_tail &= SCBUF_MASK;
- if (output_index > samples)
+ if (output_index >= output.samples())
break;
}
/* ---------------------------------------------------------------- */
/* If output outputs is full, then we're done. */
/* ---------------------------------------------------------------- */
- if (output_index > samples)
+ if (output_index > output.samples())
break;
- length = samples - output_index;
+ length = output.samples() - output_index;
/* ---------------------------------------------------------------- */
/* Process the current set of filter coefficients as long as the */
diff --git a/src/devices/sound/sp0256.h b/src/devices/sound/sp0256.h
index 3720b3429ed..d1e1d5612cf 100644
--- a/src/devices/sound/sp0256.h
+++ b/src/devices/sound/sp0256.h
@@ -61,7 +61,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct lpc12_t
diff --git a/src/devices/sound/spkrdev.cpp b/src/devices/sound/spkrdev.cpp
index 3fc3467771e..184a628fe73 100644
--- a/src/devices/sound/spkrdev.cpp
+++ b/src/devices/sound/spkrdev.cpp
@@ -76,7 +76,7 @@
#include "sound/spkrdev.h"
-static constexpr int16_t default_levels[2] = {0, 32767};
+static constexpr double default_levels[2] = {0.0, 1.0};
// Internal oversampling factor (interm. samples vs stream samples)
static constexpr int RATE_MULTIPLIER = 4;
@@ -102,7 +102,7 @@ void speaker_sound_device::device_start()
int i;
double x;
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
m_level = 0;
for (i = 0; i < FILTER_LENGTH; i++)
@@ -198,23 +198,23 @@ void speaker_sound_device::device_post_load()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
// This can be triggered by the core (based on emulated time) or via level_w().
-void speaker_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void speaker_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
- int volume = m_levels[m_level];
+ auto &buffer = outputs[0];
+ double volume = m_levels[m_level];
double filtered_volume;
attotime sampled_time = attotime::zero;
- if (samples > 0)
+ if (buffer.samples() > 0)
{
/* Prepare to update time state */
sampled_time = attotime(0, m_channel_sample_period);
- if (samples > 1)
- sampled_time *= samples;
+ if (buffer.samples() > 1)
+ sampled_time *= buffer.samples();
/* Note: since the stream is in the process of being updated,
* stream->sample_time() will return the time before the update! (MAME 0.130)
@@ -222,19 +222,19 @@ void speaker_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
*/
}
- if (samples-- > 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); )
{
/* Note that first interm. sample may be composed... */
filtered_volume = update_interm_samples_get_filtered_volume(volume);
/* Composite volume is now quantized to the stream resolution */
- *buffer++ = (stream_sample_t)filtered_volume;
+ buffer.put(sampindex++, filtered_volume);
/* Any additional samples will be homogeneous, however may need filtering across samples: */
- while (samples-- > 0)
+ while (sampindex < buffer.samples())
{
filtered_volume = update_interm_samples_get_filtered_volume(volume);
- *buffer++ = (stream_sample_t)filtered_volume;
+ buffer.put(sampindex++, filtered_volume);
}
/* Update the time state */
@@ -322,7 +322,7 @@ void speaker_sound_device::update_interm_samples(const attotime &time, int volum
}
-double speaker_sound_device::update_interm_samples_get_filtered_volume(int volume)
+double speaker_sound_device::update_interm_samples_get_filtered_volume(double volume)
{
double filtered_volume, tempx;
@@ -355,7 +355,7 @@ double speaker_sound_device::update_interm_samples_get_filtered_volume(int volum
}
-void speaker_sound_device::finalize_interm_sample(int volume)
+void speaker_sound_device::finalize_interm_sample(double volume)
{
double fraction;
@@ -401,7 +401,7 @@ double speaker_sound_device::get_filtered_volume()
{
if (i >= FILTER_LENGTH) i = 0;
filtered_volume += m_composed_volume[i] * m_ampl[c];
- ampsum += m_ampl[c];
+ ampsum += std::abs(m_ampl[c]);
}
filtered_volume /= ampsum;
diff --git a/src/devices/sound/spkrdev.h b/src/devices/sound/spkrdev.h
index 7411e47170d..596a4f94854 100644
--- a/src/devices/sound/spkrdev.h
+++ b/src/devices/sound/spkrdev.h
@@ -21,7 +21,7 @@ public:
~speaker_sound_device() {}
// configuration
- void set_levels(int num_levels, const int16_t *levels) { m_num_levels = num_levels; m_levels = levels; }
+ void set_levels(int num_levels, const double *levels) { m_num_levels = num_levels; m_levels = levels; }
void level_w(int new_level); // can use as writeline
@@ -32,7 +32,7 @@ protected:
virtual void device_post_load() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// Length of anti-aliasing filter kernel, measured in number of intermediate samples
@@ -47,9 +47,9 @@ private:
void update_interm_samples(const attotime &time, int volume);
// Updates the composed volume array and returns final filtered volume of next stream sample
- double update_interm_samples_get_filtered_volume(int volume);
+ double update_interm_samples_get_filtered_volume(double volume);
- void finalize_interm_sample(int volume);
+ void finalize_interm_sample(double volume);
void init_next_interm_sample();
inline double make_fraction(const attotime &a, const attotime &b, double timediv);
double get_filtered_volume();
@@ -80,7 +80,7 @@ private:
double m_prevx, m_prevy;
int m_num_levels; /* optional: number of levels (if not two) */
- const int16_t *m_levels; /* optional: pointer to level lookup table */
+ const double *m_levels; /* optional: pointer to level lookup table */
};
DECLARE_DEVICE_TYPE(SPEAKER_SOUND, speaker_sound_device)
diff --git a/src/devices/sound/spu.cpp b/src/devices/sound/spu.cpp
index 82f5d3973ac..9a8f503cf04 100644
--- a/src/devices/sound/spu.cpp
+++ b/src/devices/sound/spu.cpp
@@ -272,7 +272,8 @@ public:
invalid_end,
loopaddr,
last_update_end;
- signed short *data,*loop,*dend;
+ std::unique_ptr<signed short []> data;
+ signed short *loop,*dend;
adpcm_decoder decoder, update_decoder;
mutable int ref_count;
bool valid,
@@ -301,8 +302,8 @@ public:
ref_count--;
if (ref_count==0)
{
- cache_size-=(dend-data)<<1;
- global_free(this);
+ cache_size-=(dend-data.get())<<1;
+ delete this;
}
}
@@ -521,7 +522,7 @@ public:
head=xam->offset;
marker_tail=xam->prev;
if (marker_tail) marker_tail->next=nullptr;
- global_free(xam);
+ delete xam;
}
// Set marker head to nullptr if the list is now empty
@@ -544,7 +545,7 @@ public:
{
stream_marker *m=marker_head;
marker_head=marker_head->next;
- global_free(m);
+ delete m;
}
marker_head=marker_tail=nullptr;
@@ -566,7 +567,7 @@ public:
stream_marker *xam=marker_head;
marker_head=xam->next;
- global_free(xam);
+ delete xam;
if (marker_head) marker_head->prev=nullptr;
}
@@ -606,12 +607,12 @@ static inline int clamp(const int v)
spu_device::sample_cache::~sample_cache()
{
- global_free_array(data);
+ data.reset();
while (loop_cache)
{
sample_loop_cache *lc=loop_cache;
loop_cache=lc->next;
- global_free(lc);
+ delete lc;
}
}
@@ -623,7 +624,7 @@ signed short *spu_device::sample_cache::get_sample_pointer(const unsigned int ad
{
if ((addr>=start) && (addr<end))
{
- return data+(((addr-start)>>4)*28);
+ return &data[((addr-start)>>4)*28];
} else
{
return nullptr;
@@ -668,9 +669,9 @@ bool spu_device::sample_cache::get_loop_pointer(cache_pointer *cp)
unsigned int spu_device::sample_cache::get_sample_address(const signed short *ptr) const
{
- if ((ptr>=data) && (ptr<=dend))
+ if ((ptr>=data.get()) && (ptr<=dend))
{
- return start+(((ptr-data)/28)<<4);
+ return start+(((ptr-data.get())/28)<<4);
} else
{
return -1;
@@ -705,7 +706,7 @@ void spu_device::sample_cache::add_loop_cache(sample_loop_cache *lc)
bool spu_device::sample_cache::is_valid_pointer(signed short *ptr) const
{
- if ((ptr>=data) && (data<=dend)) return true;
+ if ((ptr>=data.get()) && (data.get()<=dend)) return true;
for (sample_loop_cache *slc=loop_cache; slc; slc=slc->next)
if ((ptr>=slc->data) && (ptr<(slc->data+num_loop_cache_samples)))
return true;
@@ -720,7 +721,7 @@ bool spu_device::sample_cache::try_update(spu_device *spu)
{
if ((invalid_start>=start) && (invalid_end<=end))
{
- adpcm_packet *ap=(adpcm_packet *)(spu->spu_ram+start);
+ adpcm_packet *ap=(adpcm_packet *)&spu->spu_ram[start];
unsigned int a;
unsigned int loop=0;
@@ -756,8 +757,8 @@ bool spu_device::sample_cache::try_update(spu_device *spu)
printf("\n");
#endif
- signed short *dp=data+(((invalid_start-start)>>4)*28);
- ap=(adpcm_packet *)(spu->spu_ram+invalid_start);
+ signed short *dp=&data[((invalid_start-start)>>4)*28];
+ ap=(adpcm_packet *)&spu->spu_ram[invalid_start];
for (a=invalid_start; a<invalid_end; a+=16, ap++)
dp=update_decoder.decode_packet(ap,dp);
@@ -779,7 +780,7 @@ bool spu_device::sample_cache::try_update(spu_device *spu)
signed short *dpend=dp+lc->len;
unsigned int adr=lc->loopstart;
for (unsigned int i=0; ((i<num_loop_cache_packets) && (dp<dpend)); i++, adr+=16)
- dp=tmp.decode_packet((adpcm_packet *)(spu->spu_ram+adr),dp);
+ dp=tmp.decode_packet((adpcm_packet *)&spu->spu_ram[adr],dp);
}
}
@@ -847,7 +848,7 @@ bool spu_device::cache_pointer::update(spu_device *spu)
// Cache is invalid, calculate play address offset from start of
// old cache block
- unsigned int off=ptr-cache->data,
+ unsigned int off=ptr-cache->data.get(),
addr=cache->start;
// Release cache block and get updated one
@@ -856,7 +857,7 @@ bool spu_device::cache_pointer::update(spu_device *spu)
// Calculate play address in new cache block
- ptr=cache->data+off;
+ ptr=&cache->data[off];
if (ptr>=cache->dend)
{
@@ -870,7 +871,7 @@ bool spu_device::cache_pointer::update(spu_device *spu)
// Return false if we do not have a cache block or the play address is invalid
- if ((cache) && ((ptr>=cache->data) && (ptr<cache->dend)))
+ if ((cache) && ((ptr>=cache->data.get()) && (ptr<cache->dend)))
{
return true;
} else
@@ -967,15 +968,15 @@ void spu_device::device_start()
m_irq_handler.resolve_safe();
voice=new voiceinfo [24];
- spu_ram=new unsigned char [spu_ram_size];
+ spu_ram=std::make_unique<unsigned char []>(spu_ram_size);
xa_buffer=new spu_stream_buffer(xa_sector_size,xa_buffer_sectors);
cdda_buffer=new spu_stream_buffer(cdda_sector_size,cdda_buffer_sectors);
init_stream();
- cache=new sample_cache *[spu_ram_size>>4];
- memset(cache,0,(spu_ram_size>>4)*sizeof(sample_cache *));
+ cache=std::make_unique<sample_cache * []>(spu_ram_size>>4);
+ std::fill_n(cache.get(), spu_ram_size>>4, nullptr);
// register save state stuff
save_item(NAME(reg)); // this covers all spureg.* plus the reverb parameter block
@@ -1031,16 +1032,16 @@ void spu_device::device_reset()
cdda_playing=false;
m_cd_out_ptr = 0;
- memset(spu_ram,0,spu_ram_size);
+ memset(spu_ram.get(),0,spu_ram_size);
memset(reg,0,0x200);
memset(voice,0,sizeof(voiceinfo)*24);
spureg.status|=(1<<7)|(1<<10);
- memset(cache,0,(spu_ram_size>>4)*sizeof(sample_cache *));
+ std::fill_n(cache.get(), spu_ram_size>>4, nullptr);
for (auto & elem : output_buf)
- elem=new unsigned char [output_buffer_size];
+ elem=std::make_unique<unsigned char []>(output_buffer_size);
output_head=output_tail=output_size=0;
noise_t=0;
@@ -1058,7 +1059,7 @@ void spu_device::device_post_load()
dirty_flags = -1;
// kill and reallocate reverb to avoid artifacts
- global_free(rev);
+ delete rev;
rev = new reverb(44100);
// and do some update processing
@@ -1074,16 +1075,16 @@ void spu_device::device_post_load()
void spu_device::device_stop()
{
for (auto & elem : output_buf)
- global_free_array(elem);
+ elem.reset();
kill_stream();
- global_free_array(spu_ram);
+ spu_ram.reset();
invalidate_cache(0,spu_ram_size);
- global_free_array(cache);
- global_free(xa_buffer);
- global_free(cdda_buffer);
- global_free_array(voice);
+ cache.reset();
+ delete xa_buffer;
+ delete cdda_buffer;
+ delete [] voice;
}
//
//
@@ -1093,7 +1094,7 @@ void spu_device::init_stream()
{
const unsigned int hz=44100;
- m_stream = stream_alloc_legacy(0, 2, hz);
+ m_stream = stream_alloc(0, 2, hz);
rev=new reverb(hz);
@@ -1107,7 +1108,7 @@ void spu_device::init_stream()
void spu_device::kill_stream()
{
- global_free(rev);
+ delete rev;
rev=nullptr;
}
@@ -1262,7 +1263,7 @@ void spu_device::write_data(const unsigned short data)
assert(taddr<spu_ram_size);
if (cache[taddr>>4]) flush_cache(cache[taddr>>4],taddr,taddr+2);
- *((unsigned short *)(spu_ram+taddr))=data;
+ *((unsigned short *)&spu_ram[taddr])=data;
taddr+=2;
}
@@ -1342,7 +1343,7 @@ spu_device::sample_cache *spu_device::get_sample_cache(const unsigned int addr)
sc->start=addr;
sc->loop=nullptr;
- adpcm_packet *ap=(adpcm_packet *)(spu_ram+sc->start);
+ adpcm_packet *ap=(adpcm_packet *)&spu_ram[sc->start];
unsigned int a;
for (a=addr; a<(512*1024); a+=16, ap++)
{
@@ -1358,13 +1359,13 @@ spu_device::sample_cache *spu_device::get_sample_cache(const unsigned int addr)
sc->end=(std::min)(spu_ram_size,a+16);
unsigned int sz=((sc->end-sc->start)>>4)*28;
- sc->data=new signed short [sz];
+ sc->data=std::make_unique<signed short []>(sz);
sample_cache::cache_size+=sz<<1;
sc->loopaddr=loop;
- if (loop) sc->loop=sc->data+(((loop-sc->start)>>4)*28);
+ if (loop) sc->loop=&sc->data[((loop-sc->start)>>4)*28];
- signed short *dp=sc->data;
- ap=(adpcm_packet *)(spu_ram+sc->start);
+ signed short *dp=sc->data.get();
+ ap=(adpcm_packet *)&spu_ram[sc->start];
for (a=sc->start; a<sc->end; a+=16, ap++)
dp=sc->decoder.decode_packet(ap,dp);
@@ -1389,7 +1390,7 @@ bool spu_device::translate_sample_addr(const unsigned int addr, cache_pointer *c
cp->reset();
if ((cp->cache=get_sample_cache(addr)))
{
- cp->ptr=cp->cache->data+(((addr-cp->cache->start)>>4)*28);
+ cp->ptr=&cp->cache->data[((addr-cp->cache->start)>>4)*28];
cp->cache->add_ref();
return true;
}
@@ -1530,7 +1531,7 @@ spu_device::sample_loop_cache *spu_device::get_loop_cache(sample_cache *cache, c
signed short *dp=lc->data;
for (unsigned int i=0; ((i<num_loop_cache_packets) &&
(adr<lpcache->end)); i++, adr+=16)
- dp=tmp.decode_packet((adpcm_packet *)(spu_ram+adr),dp);
+ dp=tmp.decode_packet((adpcm_packet *)&spu_ram[adr],dp);
#ifdef log_loop_cache
log(log_spu,"spu: add loop cache %08x %08x->%08x (end at %08x)\n",lc,lpen,lpst,adr);
@@ -1572,7 +1573,7 @@ void spu_device::update_voice_loop(const unsigned int v)
{
ra=spureg.voice[v].repaddr<<3;
ra=(ra+0xf)&~0xf;
- const adpcm_packet *ap=ra?(adpcm_packet *)(spu_ram+ra):nullptr;
+ const adpcm_packet *ap=ra?(adpcm_packet *)&spu_ram[ra]:nullptr;
if (ap)
{
@@ -2393,8 +2394,8 @@ void spu_device::generate_xa(void *ptr, const unsigned int sz)
// Write to SPU XA buffer (for emulation purposes - some games read this
// back to do analysers, etc...)
- *(signed short *)(spu_ram+xa_out_ptr)=vl;
- *(signed short *)(spu_ram+xa_out_ptr+0x800)=vr;
+ *(signed short *)&spu_ram[xa_out_ptr]=vl;
+ *(signed short *)&spu_ram[xa_out_ptr+0x800]=vr;
xa_out_ptr=(xa_out_ptr+2)&0x7ff;
// Mix samples into output buffer
@@ -2430,7 +2431,7 @@ void spu_device::generate_xa(void *ptr, const unsigned int sz)
{
xa_playing=false;
- memset(spu_ram,0,0x1000);
+ memset(spu_ram.get(),0,0x1000);
xa_out_ptr=0;
}
}
@@ -2465,8 +2466,8 @@ void spu_device::generate_cdda(void *ptr, const unsigned int sz)
int16_t vr = ((sp[1]*volr)>>15);
// if the volume adjusted samples are stored here, vibribbon does nothing
- *(signed short *)(spu_ram+m_cd_out_ptr)=sp[0];
- *(signed short *)(spu_ram+m_cd_out_ptr+0x400)=sp[1];
+ *(signed short *)&spu_ram[m_cd_out_ptr]=sp[0];
+ *(signed short *)&spu_ram[m_cd_out_ptr+0x400]=sp[1];
m_cd_out_ptr=(m_cd_out_ptr+2)&0x3ff;
//if((m_cd_out_ptr == ((spureg.irq_addr << 3) & ~0x400)) && (spureg.ctrl & spuctrl_irq_enable))
@@ -2575,10 +2576,10 @@ void spu_device::generate(void *ptr, const unsigned int sz)
while ((left) && (output_size))
{
unsigned int n=(std::min)((std::min)(left,output_buffer_size-output_head),output_size);
- memcpy(dp,output_buf[0]+output_head,n);
+ memcpy(dp,&output_buf[0][output_head],n);
rev->process((signed short *)dp,
- (signed short *)(output_buf[1]+output_head),
+ (signed short *)&output_buf[1][output_head],
spu_reverb_cfg,
(signed short)spureg.rvol_l,
(signed short)spureg.rvol_r,
@@ -2683,10 +2684,10 @@ void spu_device::process_until(const unsigned int tsample)
process_samples=(std::min)(process_samples,
(output_buffer_size-output_tail)>>2);
- unsigned char *outptr=output_buf[0]+output_tail,
- *reverbptr=output_buf[1]+output_tail,
- *fmptr=output_buf[2]+output_tail,
- *noiseptr=output_buf[3]+output_tail;
+ unsigned char *outptr=&output_buf[0][output_tail],
+ *reverbptr=&output_buf[1][output_tail],
+ *fmptr=&output_buf[2][output_tail],
+ *noiseptr=&output_buf[3][output_tail];
output_tail+=process_samples<<2;
output_tail&=(output_buffer_size-1);
@@ -2761,21 +2762,20 @@ void spu_device::update_timing()
//
//
-void spu_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void spu_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outL, *outR;
int16_t temp[44100], *src;
- outL = outputs[0];
- outR = outputs[1];
+ auto &outL = outputs[0];
+ auto &outR = outputs[1];
- generate(temp, samples*4); // second parameter is bytes, * 2 (size of int16_t) * 2 (stereo)
+ generate(temp, outputs[0].samples()*4); // second parameter is bytes, * 2 (size of int16_t) * 2 (stereo)
src = &temp[0];
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
- *outL++ = *src++;
- *outR++ = *src++;
+ outL.put_int(i, *src++, 32768);
+ outR.put_int(i, *src++, 32768);
}
}
@@ -2797,13 +2797,13 @@ void spu_device::start_dma(uint8_t *mainram, bool to_spu, uint32_t size)
{
invalidate_cache(st,en);
- memcpy(spu_ram+(spureg.trans_addr<<3), mainram, size);
+ memcpy(&spu_ram[spureg.trans_addr<<3], mainram, size);
dirty_flags|=dirtyflag_ram;
}
else
{
- memcpy(mainram, spu_ram+(spureg.trans_addr<<3), size);
+ memcpy(mainram, &spu_ram[spureg.trans_addr<<3], size);
}
}
@@ -3034,7 +3034,7 @@ bool spu_device::play_cdda(const unsigned int sector, const unsigned char *cdda)
flip[i] = flip[i+1];
flip[i+1] = temp;
}
- // this should be done in generate but sound_stream_update_legacy may not be called frequently enough
+ // this should be done in generate but sound_stream_update may not be called frequently enough
if(((spureg.irq_addr << 3) < 0x800) && (spureg.ctrl & spuctrl_irq_enable))
m_irq_handler(1);
diff --git a/src/devices/sound/spu.h b/src/devices/sound/spu.h
index 7913670c667..7aee602e38c 100644
--- a/src/devices/sound/spu.h
+++ b/src/devices/sound/spu.h
@@ -35,7 +35,7 @@ protected:
virtual void device_post_load() override;
virtual void device_stop() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
static constexpr float ms_to_rate(float ms) { return 1.0f / (ms * (float(spu_base_frequency_hz) / 1000.0f)); }
static constexpr float s_to_rate(float s) { return ms_to_rate(s * 1000.0f); }
@@ -49,7 +49,7 @@ protected:
// internal state
devcb_write_line m_irq_handler;
- unsigned char *spu_ram;
+ std::unique_ptr<unsigned char []> spu_ram;
reverb *rev;
unsigned int taddr;
unsigned int sample_t;
@@ -73,13 +73,13 @@ protected:
bool status_enabled, xa_playing, cdda_playing;
int xa_voll, xa_volr, changed_xa_vol;
voiceinfo *voice;
- sample_cache **cache;
+ std::unique_ptr<sample_cache * []> cache;
float samples_per_frame;
float samples_per_cycle;
static float freq_multiplier;
- unsigned char *output_buf[4];
+ std::unique_ptr<unsigned char []> output_buf[4];
unsigned int output_head;
unsigned int output_tail;
unsigned int output_size;
diff --git a/src/devices/sound/spureverb.cpp b/src/devices/sound/spureverb.cpp
index cf747af1acb..e57c33d448d 100644
--- a/src/devices/sound/spureverb.cpp
+++ b/src/devices/sound/spureverb.cpp
@@ -34,15 +34,11 @@ spu_device::reverb::reverb(const int hz, const int maxdelay)
for (int c=0; c<2; c++)
{
for (int f=0; f<4; f++) {
- y[c][f]=new signed short [maxdelay];
- memset(y[c][f], 0, sizeof(signed short) * maxdelay);
+ y[c][f]=make_unique_clear<signed short []>(maxdelay);
}
- x[c]=new signed short [maxdelay];
- memset(x[c], 0, sizeof(signed short) * maxdelay);
- ax[c]=new signed short [maxdelay];
- memset(ax[c], 0, sizeof(signed short) * maxdelay);
- ay[c]=new signed short [maxdelay];
- memset(ay[c], 0, sizeof(signed short) * maxdelay);
+ x[c]=make_unique_clear<signed short []>(maxdelay);
+ ax[c]=make_unique_clear<signed short []>(maxdelay);
+ ay[c]=make_unique_clear<signed short []>(maxdelay);
}
memset(bx1,0,sizeof(bx1));
memset(by1,0,sizeof(by1));
@@ -54,14 +50,6 @@ spu_device::reverb::reverb(const int hz, const int maxdelay)
spu_device::reverb::~reverb()
{
- for (int c=0; c<2; c++)
- {
- for (int f=0; f<4; f++)
- global_free_array(y[c][f]);
- global_free_array(x[c]);
- global_free_array(ax[c]);
- global_free_array(ay[c]);
- }
}
//
diff --git a/src/devices/sound/spureverb.h b/src/devices/sound/spureverb.h
index 64b174bcfb6..d87c3a6b4b8 100644
--- a/src/devices/sound/spureverb.h
+++ b/src/devices/sound/spureverb.h
@@ -29,12 +29,12 @@ struct spu_device::reverb_preset
class spu_device::reverb
{
- signed short
- *y[2][4],
- *x[2],
- *ax[2],
- *ay[2],
- bx1[2][2],by1[2];
+ std::unique_ptr<signed short []>
+ y[2][4],
+ x[2],
+ ax[2],
+ ay[2];
+ signed short bx1[2][2],by1[2];
int yp, max_delay, sound_hz;
typedef int comb_param[2][4];
diff --git a/src/devices/sound/st0016.cpp b/src/devices/sound/st0016.cpp
index e0318eca466..d13dfd7cacc 100644
--- a/src/devices/sound/st0016.cpp
+++ b/src/devices/sound/st0016.cpp
@@ -43,7 +43,7 @@ st0016_device::st0016_device(const machine_config &mconfig, const char *tag, dev
void st0016_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, 44100);
+ m_stream = stream_alloc(0, 2, 44100);
m_ram_read_cb.resolve_safe(0);
save_item(NAME(m_vpos));
@@ -54,10 +54,10 @@ void st0016_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void st0016_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void st0016_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int v, i, snum;
unsigned char *slot;
@@ -66,7 +66,7 @@ void st0016_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
int16_t sample;
int sptr, eptr, freq, lsptr, leptr;
- memset(mix, 0, sizeof(mix[0])*samples*2);
+ memset(mix, 0, sizeof(mix[0])*outputs[0].samples()*2);
for (v = 0; v < 8; v++)
{
@@ -82,7 +82,7 @@ void st0016_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
lsptr = slot[0x06]<<16 | slot[0x05]<<8 | slot[0x04];
leptr = slot[0x0a]<<16 | slot[0x09]<<8 | slot[0x08];
- for (snum = 0; snum < samples; snum++)
+ for (snum = 0; snum < outputs[0].samples(); snum++)
{
sample = m_ram_read_cb((sptr + m_vpos[v]) & 0x1fffff) << 8;
@@ -124,10 +124,10 @@ void st0016_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
}
mixp = &mix[0];
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
- outputs[0][i] = (*mixp++)>>4;
- outputs[1][i] = (*mixp++)>>4;
+ outputs[0].put_int(i, *mixp++, 32768<<4);
+ outputs[1].put_int(i, *mixp++, 32768<<4);
}
}
diff --git a/src/devices/sound/st0016.h b/src/devices/sound/st0016.h
index 21dd14e07c7..b18317da348 100644
--- a/src/devices/sound/st0016.h
+++ b/src/devices/sound/st0016.h
@@ -27,7 +27,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_stream;
diff --git a/src/devices/sound/swp00.cpp b/src/devices/sound/swp00.cpp
index d4d323af0a5..f94006a1868 100644
--- a/src/devices/sound/swp00.cpp
+++ b/src/devices/sound/swp00.cpp
@@ -21,7 +21,7 @@ void swp00_device::device_add_mconfig(machine_config &config)
void swp00_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, 44100);
+ m_stream = stream_alloc(0, 2, 44100);
}
void swp00_device::device_reset()
@@ -97,6 +97,8 @@ void swp00_device::snd_w(offs_t offset, u8 data)
// Synthesis
-void swp00_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
+ outputs[1].fill(0);
}
diff --git a/src/devices/sound/swp00.h b/src/devices/sound/swp00.h
index 0bf2d8b43d3..ae732979606 100644
--- a/src/devices/sound/swp00.h
+++ b/src/devices/sound/swp00.h
@@ -21,7 +21,7 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void rom_bank_updated() override;
virtual void device_add_mconfig(machine_config &config) override;
diff --git a/src/devices/sound/swp20.cpp b/src/devices/sound/swp20.cpp
index c1c92c8cb27..a9de3851fef 100644
--- a/src/devices/sound/swp20.cpp
+++ b/src/devices/sound/swp20.cpp
@@ -69,7 +69,8 @@ void swp20_device::snd_w(offs_t offset, u8 data)
logerror("w %02x, %02x %s\n", offset, data, machine().describe_context());
}
-void swp20_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void swp20_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
diff --git a/src/devices/sound/swp20.h b/src/devices/sound/swp20.h
index a65bae793a3..7323dd64f17 100644
--- a/src/devices/sound/swp20.h
+++ b/src/devices/sound/swp20.h
@@ -20,7 +20,7 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void rom_bank_updated() override;
private:
diff --git a/src/devices/sound/swp30.cpp b/src/devices/sound/swp30.cpp
index 849af9f9946..aec573aa07a 100644
--- a/src/devices/sound/swp30.cpp
+++ b/src/devices/sound/swp30.cpp
@@ -163,7 +163,7 @@ void swp30_device::device_add_mconfig(machine_config &config)
void swp30_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 2, 44100);
+ m_stream = stream_alloc(0, 2, 44100);
// Attenuantion for panning is 4.4 floating point. That means 0
// to -96.3dB. Since it's a nice range, we assume it's the same
@@ -761,12 +761,12 @@ void swp30_device::snd_w(offs_t offset, u16 data)
// Synthesis
-void swp30_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void swp30_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// Loop first on the samples and not on the channels otherwise
// effects will be annoying to implement.
- for(int sample = 0; sample < samples; sample++) {
+ for(int sample = 0; sample < outputs[0].samples(); sample++) {
// Accumulate on 64 bits, shift/clamp at the end
s64 acc_left = 0, acc_right = 0;
@@ -871,17 +871,9 @@ void swp30_device::sound_stream_update_legacy(sound_stream &stream, stream_sampl
// Global EQ is missing (it's done in the MEG)
acc_left >>= (16+6);
- if(acc_left < -0x8000)
- acc_left = -0x8000;
- else if(acc_left > 0x7fff)
- acc_left = 0x7fff;
- outputs[0][sample] = acc_left;
+ outputs[0].put_int_clamp(sample, acc_left, 32768);
acc_right >>= (16+6);
- if(acc_right < -0x8000)
- acc_right = -0x8000;
- else if(acc_right > 0x7fff)
- acc_right = 0x7fff;
- outputs[1][sample] = acc_right;
+ outputs[1].put_int_clamp(sample, acc_right, 32768);
}
}
diff --git a/src/devices/sound/swp30.h b/src/devices/sound/swp30.h
index fc8424b66d2..1eb68270626 100644
--- a/src/devices/sound/swp30.h
+++ b/src/devices/sound/swp30.h
@@ -21,7 +21,7 @@ public:
protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void rom_bank_updated() override;
virtual void device_add_mconfig(machine_config &config) override;
diff --git a/src/devices/sound/t6721a.cpp b/src/devices/sound/t6721a.cpp
index 7c0c07544e0..2c29e31dc62 100644
--- a/src/devices/sound/t6721a.cpp
+++ b/src/devices/sound/t6721a.cpp
@@ -56,17 +56,18 @@ void t6721a_device::device_start()
m_write_apd.resolve_safe();
// create sound stream
- m_stream = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_stream = stream_alloc(0, 1, machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void t6721a_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void t6721a_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
diff --git a/src/devices/sound/t6721a.h b/src/devices/sound/t6721a.h
index 208cd7e8896..52a76393894 100644
--- a/src/devices/sound/t6721a.h
+++ b/src/devices/sound/t6721a.h
@@ -65,7 +65,7 @@ protected:
virtual void device_start() override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
enum
diff --git a/src/devices/sound/t6w28.cpp b/src/devices/sound/t6w28.cpp
index 6c024c37757..9525794e489 100644
--- a/src/devices/sound/t6w28.cpp
+++ b/src/devices/sound/t6w28.cpp
@@ -101,14 +101,14 @@ void t6w28_device::write(offs_t offset, uint8_t data)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void t6w28_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void t6w28_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i;
- stream_sample_t *buffer0 = outputs[0];
- stream_sample_t *buffer1 = outputs[1];
+ auto &buffer0 = outputs[0];
+ auto &buffer1 = outputs[1];
/* If the volume is 0, increase the counter */
@@ -119,11 +119,11 @@ void t6w28_device::sound_stream_update_legacy(sound_stream &stream, stream_sampl
/* note that I do count += samples, NOT count = samples + 1. You might think */
/* it's the same since the volume is 0, but doing the latter could cause */
/* interferencies when the program is rapidly modulating the volume. */
- if (m_count[i] <= samples*STEP) m_count[i] += samples*STEP;
+ if (m_count[i] <= buffer0.samples()*STEP) m_count[i] += buffer0.samples()*STEP;
}
}
- while (samples > 0)
+ for (int sampindex = 0; sampindex < buffer0.samples(); sampindex++)
{
int vol[8];
unsigned int out0, out1;
@@ -252,10 +252,8 @@ void t6w28_device::sound_stream_update_legacy(sound_stream &stream, stream_sampl
if (out0 > MAX_OUTPUT * STEP) out0 = MAX_OUTPUT * STEP;
if (out1 > MAX_OUTPUT * STEP) out1 = MAX_OUTPUT * STEP;
- *(buffer0++) = out0 / STEP;
- *(buffer1++) = out1 / STEP;
-
- samples--;
+ buffer0.put_int(sampindex, out0 / STEP, 32768);
+ buffer1.put_int(sampindex, out1 / STEP, 32768);
}
}
@@ -296,7 +294,7 @@ void t6w28_device::device_start()
int i;
m_sample_rate = clock() / 16;
- m_channel = stream_alloc_legacy(0, 2, m_sample_rate);
+ m_channel = stream_alloc(0, 2, m_sample_rate);
for (i = 0;i < 8;i++) m_volume[i] = 0;
diff --git a/src/devices/sound/t6w28.h b/src/devices/sound/t6w28.h
index f1112f58839..6b953449f87 100644
--- a/src/devices/sound/t6w28.h
+++ b/src/devices/sound/t6w28.h
@@ -18,7 +18,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void set_gain(int gain);
diff --git a/src/devices/sound/tc8830f.cpp b/src/devices/sound/tc8830f.cpp
index e387cc746f7..85635f2f466 100644
--- a/src/devices/sound/tc8830f.cpp
+++ b/src/devices/sound/tc8830f.cpp
@@ -46,7 +46,7 @@ tc8830f_device::tc8830f_device(const machine_config &mconfig, const char *tag, d
void tc8830f_device::device_start()
{
// create the stream
- m_stream = stream_alloc_legacy(0, 1, clock() / 0x10);
+ m_stream = stream_alloc(0, 1, clock() / 0x10);
// register for savestates
save_item(NAME(m_playing));
@@ -79,11 +79,11 @@ void tc8830f_device::device_clock_changed()
-void tc8830f_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tc8830f_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int32_t mix = 0;
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
if (m_playing)
{
@@ -125,7 +125,7 @@ void tc8830f_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
mix = m_output;
}
- outputs[0][i] = mix;
+ outputs[0].put_int(i, mix, 32768);
}
}
diff --git a/src/devices/sound/tc8830f.h b/src/devices/sound/tc8830f.h
index e0e715ccbef..0a447b02dba 100644
--- a/src/devices/sound/tc8830f.h
+++ b/src/devices/sound/tc8830f.h
@@ -32,7 +32,7 @@ protected:
virtual void device_post_load() override;
virtual void device_clock_changed() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_stream;
diff --git a/src/devices/sound/tiaintf.cpp b/src/devices/sound/tiaintf.cpp
index 5c85db19b91..5a64db7bb4c 100644
--- a/src/devices/sound/tiaintf.cpp
+++ b/src/devices/sound/tiaintf.cpp
@@ -31,7 +31,7 @@ tia_device::tia_device(const machine_config &mconfig, const char *tag, device_t
void tia_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 1, clock());
+ m_channel = stream_alloc(0, 1, clock());
m_chip = tia_sound_init(this, clock(), clock(), 16);
if (!m_chip)
throw emu_fatalerror("tia_device(%s): Error creating TIA chip", tag());
@@ -49,12 +49,12 @@ void tia_device::device_stop()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void tia_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tia_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- tia_process(m_chip, outputs[0], samples);
+ tia_process(m_chip, outputs[0]);
}
diff --git a/src/devices/sound/tiaintf.h b/src/devices/sound/tiaintf.h
index c86be7173a9..8ef5d0341f7 100644
--- a/src/devices/sound/tiaintf.h
+++ b/src/devices/sound/tiaintf.h
@@ -24,7 +24,7 @@ protected:
virtual void device_stop() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_channel;
diff --git a/src/devices/sound/tiasound.cpp b/src/devices/sound/tiasound.cpp
index 0e8275fb33f..87fa657bfab 100644
--- a/src/devices/sound/tiasound.cpp
+++ b/src/devices/sound/tiasound.cpp
@@ -90,16 +90,127 @@
namespace {
-struct tia
+class tia
{
- /* structures to hold the 6 tia sound control bytes */
- uint8_t AUDC[2]; /* AUDCx (15, 16) */
- uint8_t AUDF[2]; /* AUDFx (17, 18) */
- int16_t AUDV[2]; /* AUDVx (19, 1A) */
+public:
+ tia(device_t &device, int clock, int sample_rate, int gain) :
+ tia_gain(gain) // set the gain factor (normally use TIA_DEFAULT_GAIN)
+ {
+ // fill the polynomials
+ poly_init(Bit4, 4, 4, 3);
+ poly_init(Bit5, 5, 5, 3);
+ poly_init(Bit9, 9, 9, 5);
+
+ // calculate the sample 'divide by N' value based on the playback freq.
+ Samp_n_max = ((uint16_t)(uint32_t)clock << 8) / sample_rate;
+ Samp_n_cnt = Samp_n_max; /* initialize all bits of the sample counter */
+
+ if (Samp_n_max < 256) // we need to use oversampling for sample_rate > clock_rate
+ {
+ Samp_n_max = ((uint16_t)(uint32_t)sample_rate << 8) / clock;
+ Samp_n_cnt = Samp_n_max;
+ oversampling = true;
+ }
+
+ device.save_item(NAME(AUDC));
+ device.save_item(NAME(AUDF));
+ device.save_item(NAME(AUDV));
+ device.save_item(NAME(Outvol));
+ device.save_item(NAME(P4));
+ device.save_item(NAME(P5));
+ device.save_item(NAME(P9));
+ device.save_item(NAME(Div_n_cnt));
+ device.save_item(NAME(Div_n_max));
+ device.save_item(NAME(Div_3_cnt));
+ device.save_item(NAME(Samp_n_cnt));
+ device.save_item(NAME(oversampling));
+ }
+
+ void write(offs_t offset, uint8_t data)
+ {
+ // determine which address was changed
+ uint8_t chan;
+ switch (offset)
+ {
+ case AUDC0:
+ AUDC[0] = data & 0x0f;
+ chan = 0;
+ break;
+
+ case AUDC1:
+ AUDC[1] = data & 0x0f;
+ chan = 1;
+ break;
+
+ case AUDF0:
+ AUDF[0] = data & 0x1f;
+ chan = 0;
+ break;
+
+ case AUDF1:
+ AUDF[1] = data & 0x1f;
+ chan = 1;
+ break;
+
+ case AUDV0:
+ AUDV[0] = ((data & 0x0f) << AUDV_SHIFT);
+ chan = 0;
+ break;
+
+ case AUDV1:
+ AUDV[1] = ((data & 0x0f) << AUDV_SHIFT);
+ chan = 1;
+ break;
+
+ default:
+ return;
+ }
+
+ // an AUDC value of 0 is a special case
+ uint16_t new_val;
+ if (AUDC[chan] == SET_TO_1 || AUDC[chan] == POLY5_POLY5)
+ {
+ // indicate the clock is zero so no processing will occur
+ new_val = 0;
+
+ // and set the output to the selected volume
+ Outvol[chan] = AUDV[chan];
+ }
+ else
+ {
+ // otherwise calculate the 'divide by N' value
+ new_val = AUDF[chan] + 1;
+
+ // if bits 2 & 3 are set, then multiply the 'div by n' count by 3
+ if ((AUDC[chan] & DIV3_MASK) == DIV3_MASK && AUDC[chan] != POLY5_DIV3)
+ {
+ new_val *= 3;
+ }
+ }
- int16_t Outvol[2]; /* last output volume for each channel */
+ // only reset those channels that have changed
+ if (new_val != Div_n_max[chan])
+ {
+ // reset the divide by n counters
+ Div_n_max[chan] = new_val;
- int tia_gain; /* initialized in tia_sound_init() */
+ // if the channel is now volume only or was volume only
+ if ((Div_n_cnt[chan] == 0) || (new_val == 0))
+ {
+ // reset the counter (otherwise let it complete the previous)
+ Div_n_cnt[chan] = new_val;
+ }
+ }
+ }
+
+ // structures to hold the 6 tia sound control bytes
+ uint8_t AUDC[2] = { 0, 0 }; // AUDCx (15, 16)
+ uint8_t AUDF[2] = { 0, 0 }; // AUDFx (17, 18)
+ int16_t AUDV[2] = { 0, 0 }; // AUDVx (19, 1A)
+
+ int16_t Outvol[2] = { 0, 0 }; // last output volume for each channel
+
+ int tia_gain; // initialized in tia_sound_init()
/* Initialze the bit patterns for the polynomials. */
@@ -115,23 +226,41 @@ struct tia
uint8_t Bit9[POLY9_SIZE];
- uint8_t P4[2]; /* Position pointer for the 4-bit POLY array */
- uint8_t P5[2]; /* Position pointer for the 5-bit POLY array */
- uint16_t P9[2]; /* Position pointer for the 9-bit POLY array */
+ uint8_t P4[2] = { 0, 0 }; // Position pointer for the 4-bit POLY array
+ uint8_t P5[2] = { 0, 0 }; // Position pointer for the 5-bit POLY array
+ uint16_t P9[2] = { 0, 0 }; // Position pointer for the 9-bit POLY array
- uint8_t Div_n_cnt[2]; /* Divide by n counter. one for each channel */
- uint8_t Div_n_max[2]; /* Divide by n maximum, one for each channel */
- uint8_t Div_3_cnt[2]; /* Div 3 counter, used for POLY5_DIV3 mode */
+ uint8_t Div_n_cnt[2] = { 0, 0 }; // Divide by n counter. one for each channel
+ uint8_t Div_n_max[2] = { 0, 0 }; // Divide by n maximum, one for each channel
+ uint8_t Div_3_cnt[2] = { 3, 3 }; // Div 3 counter, used for POLY5_DIV3 mode
/* In my routines, I treat the sample output as another divide by N counter. */
/* For better accuracy, the Samp_n_cnt has a fixed binary decimal point */
/* which has 8 binary digits to the right of the decimal point. */
- uint16_t Samp_n_max; /* Sample max, multiplied by 256 */
- uint16_t Samp_n_cnt; /* Sample cnt. */
+ uint16_t Samp_n_max; // Sample max, multiplied by 256
+ uint16_t Samp_n_cnt; // Sample cnt.
+
+ bool oversampling = false; // Added oversampling for sample_rate > clock_rate
+
+private:
+ template <unsigned N>
+ static void poly_init(uint8_t (&poly)[N], int size, int f0, int f1)
+ {
+ const int mask = (1 << size) - 1;
+ int x = mask;
+
+ for (int i = 0; i < mask; i++)
+ {
+ const int bit0 = ((size - f0) ? (x >> (size - f0)) : x) & 0x01;
+ const int bit1 = ((size - f1) ? (x >> (size - f1)) : x) & 0x01;
+ poly[i] = x & 1;
+ /* calculate next bit */
+ x = (x >> 1) | ((bit0 ^ bit1) << ( size - 1) );
+ }
+ }
- int oversampling; /* Added oversampling for sample_rate > clock_rate */
};
@@ -163,88 +292,9 @@ constexpr uint8_t Div31[POLY5_SIZE] =
/* */
/*****************************************************************************/
-void tia_write(void *_chip, offs_t offset, uint8_t data)
+void tia_write(void *chip, offs_t offset, uint8_t data)
{
- struct tia *chip = (struct tia *)_chip;
- uint16_t new_val;
- uint8_t chan;
-
- /* determine which address was changed */
- switch (offset)
- {
- case AUDC0:
- chip->AUDC[0] = data & 0x0f;
- chan = 0;
- break;
-
- case AUDC1:
- chip->AUDC[1] = data & 0x0f;
- chan = 1;
- break;
-
- case AUDF0:
- chip->AUDF[0] = data & 0x1f;
- chan = 0;
- break;
-
- case AUDF1:
- chip->AUDF[1] = data & 0x1f;
- chan = 1;
- break;
-
- case AUDV0:
- chip->AUDV[0] = ((data & 0x0f) << AUDV_SHIFT);
- chan = 0;
- break;
-
- case AUDV1:
- chip->AUDV[1] = ((data & 0x0f) << AUDV_SHIFT);
- chan = 1;
- break;
-
- default:
- chan = 255;
- break;
- }
-
- /* if the output value changed */
- if (chan != 255)
- {
- /* an AUDC value of 0 is a special case */
- if (chip->AUDC[chan] == SET_TO_1 || chip->AUDC[chan] == POLY5_POLY5)
- {
- /* indicate the clock is zero so no processing will occur */
- new_val = 0;
-
- /* and set the output to the selected volume */
- chip->Outvol[chan] = chip->AUDV[chan];
- }
- else
- {
- /* otherwise calculate the 'divide by N' value */
- new_val = chip->AUDF[chan] + 1;
-
- /* if bits 2 & 3 are set, then multiply the 'div by n' count by 3 */
- if ((chip->AUDC[chan] & DIV3_MASK) == DIV3_MASK && chip->AUDC[chan] != POLY5_DIV3)
- {
- new_val *= 3;
- }
- }
-
- /* only reset those channels that have changed */
- if (new_val != chip->Div_n_max[chan])
- {
- /* reset the divide by n counters */
- chip->Div_n_max[chan] = new_val;
-
- /* if the channel is now volume only or was volume only */
- if ((chip->Div_n_cnt[chan] == 0) || (new_val == 0))
- {
- /* reset the counter (otherwise let it complete the previous) */
- chip->Div_n_cnt[chan] = new_val;
- }
- }
- }
+ reinterpret_cast<tia *>(chip)->write(offset, data);
}
@@ -264,9 +314,9 @@ void tia_write(void *_chip, offs_t offset, uint8_t data)
/* */
/*****************************************************************************/
-void tia_process(void *_chip, stream_sample_t *buffer, int length)
+void tia_process(void *_chip, write_stream_view &buffer)
{
- struct tia *chip = (struct tia *)_chip;
+ tia *chip = (tia *)_chip;
uint8_t audc0, audc1;
uint8_t div_n_cnt0, div_n_cnt1;
uint8_t p5_0, p5_1;
@@ -286,7 +336,7 @@ void tia_process(void *_chip, stream_sample_t *buffer, int length)
div_n_cnt1 = chip->Div_n_cnt[1];
/* loop until the buffer is filled */
- while (length > 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); )
{
/* Process channel 0 */
if (div_n_cnt0 > 1)
@@ -482,10 +532,7 @@ void tia_process(void *_chip, stream_sample_t *buffer, int length)
chip->Samp_n_cnt += chip->Samp_n_max;
/* calculate the latest output value and place in buffer */
- *buffer++ = outvol_0 + outvol_1;
-
- /* and indicate one less byte to process */
- length--;
+ buffer.put_int(sampindex++, outvol_0 + outvol_1, 32768);
}
}
else
@@ -496,10 +543,9 @@ void tia_process(void *_chip, stream_sample_t *buffer, int length)
* byte contains the fractional part */
chip->Samp_n_cnt -= 256;
/* calculate the latest output value and place in buffer */
- *buffer++ = outvol_0 + outvol_1;
- length--;
+ buffer.put_int(sampindex++, outvol_0 + outvol_1, 32768);
}
- while ((chip->Samp_n_cnt >= 256) && (length > 0));
+ while ((chip->Samp_n_cnt >= 256) && (sampindex < buffer.samples()));
/* adjust the sample counter if necessary */
if (chip->Samp_n_cnt < 256)
@@ -517,37 +563,6 @@ void tia_process(void *_chip, stream_sample_t *buffer, int length)
}
-static void poly_init(uint8_t *poly, int size, int f0, int f1)
-{
- int mask = (1 << size) - 1;
- int i, x = mask;
-
- for (i = 0; i < mask; i++)
- {
- int bit0 = ( ( size - f0 ) ? ( x >> ( size - f0 ) ) : x ) & 0x01;
- int bit1 = ( ( size - f1 ) ? ( x >> ( size - f1 ) ) : x ) & 0x01;
- poly[i] = x & 1;
- /* calculate next bit */
- x = ( x >> 1 ) | ( ( bit0 ^ bit1 ) << ( size - 1) );
- }
-}
-
-static void tia_save_state(device_t *device, tia *tia)
-{
- device->save_item(NAME(tia->AUDC));
- device->save_item(NAME(tia->AUDF));
- device->save_item(NAME(tia->AUDV));
- device->save_item(NAME(tia->Outvol));
- device->save_item(NAME(tia->P4));
- device->save_item(NAME(tia->P5));
- device->save_item(NAME(tia->P9));
- device->save_item(NAME(tia->Div_n_cnt));
- device->save_item(NAME(tia->Div_n_max));
- device->save_item(NAME(tia->Div_3_cnt));
- device->save_item(NAME(tia->Samp_n_cnt));
- device->save_item(NAME(tia->oversampling));
-}
-
/*****************************************************************************/
/* Module: tia_sh_start() */
/* Purpose: to handle the power-up initialization functions */
@@ -565,52 +580,11 @@ static void tia_save_state(device_t *device, tia *tia)
void *tia_sound_init(device_t *device, int clock, int sample_rate, int gain)
{
- struct tia *chip;
- int chan;
-
- chip = global_alloc_clear<struct tia>();
-
- /* set the gain factor (normally use TIA_DEFAULT_GAIN) */
- chip->tia_gain = gain;
-
- /* fill the polynomials */
- poly_init(chip->Bit4, 4, 4, 3);
- poly_init(chip->Bit5, 5, 5, 3);
- poly_init(chip->Bit9, 9, 9, 5);
-
- /* calculate the sample 'divide by N' value based on the playback freq. */
- chip->Samp_n_max = ((uint16_t)(uint32_t)clock << 8) / sample_rate;
- chip->Samp_n_cnt = chip->Samp_n_max; /* initialize all bits of the sample counter */
-
- if (chip->Samp_n_max < 256) /* we need to use oversampling for sample_rate > clock_rate */
- {
- chip->Samp_n_max = ((uint16_t)(uint32_t)sample_rate << 8) / clock;
- chip->Samp_n_cnt = chip->Samp_n_max;
- chip->oversampling = 1;
- }
-
- /* initialize the local globals */
- for (chan = CHAN1; chan <= CHAN2; chan++)
- {
- chip->Outvol[chan] = 0;
- chip->Div_n_cnt[chan] = 0;
- chip->Div_n_max[chan] = 0;
- chip->Div_3_cnt[chan] = 3;
- chip->AUDC[chan] = 0;
- chip->AUDF[chan] = 0;
- chip->AUDV[chan] = 0;
- chip->P4[chan] = 0;
- chip->P5[chan] = 0;
- chip->P9[chan] = 0;
- }
-
- tia_save_state(device, chip);
-
- return chip;
+ return new tia(*device, clock, sample_rate, gain);
}
void tia_sound_free(void *chip)
{
- global_free((struct tia *)chip);
+ delete(reinterpret_cast<tia *>(chip));
}
diff --git a/src/devices/sound/tiasound.h b/src/devices/sound/tiasound.h
index b406bf14598..2edafdda912 100644
--- a/src/devices/sound/tiasound.h
+++ b/src/devices/sound/tiasound.h
@@ -41,7 +41,7 @@
void *tia_sound_init(device_t *device, int clock, int sample_rate, int gain);
void tia_sound_free(void *chip);
-void tia_process(void *chip, stream_sample_t *buffer, int length);
+void tia_process(void *chip, write_stream_view &buffer);
void tia_write(void *chip, offs_t offset, uint8_t data);
#endif // MAME_SOUND_TIASOUND_H
diff --git a/src/devices/sound/tms3615.cpp b/src/devices/sound/tms3615.cpp
index e59c64eab04..3f595c8a97b 100644
--- a/src/devices/sound/tms3615.cpp
+++ b/src/devices/sound/tms3615.cpp
@@ -46,7 +46,7 @@ void tms3615_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
void tms3615_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
diff --git a/src/devices/sound/tms36xx.cpp b/src/devices/sound/tms36xx.cpp
index 73ec59b4121..08df1d03f51 100644
--- a/src/devices/sound/tms36xx.cpp
+++ b/src/devices/sound/tms36xx.cpp
@@ -355,7 +355,7 @@ void tms36xx_device::device_start()
{
int enable = 0;
- m_channel = stream_alloc_legacy(0, 1, clock() * 64);
+ m_channel = stream_alloc(0, 1, clock() * 64);
m_samplerate = clock() * 64;
m_basefreq = clock();
@@ -394,23 +394,22 @@ void tms36xx_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void tms36xx_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tms36xx_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int samplerate = m_samplerate;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
/* no tune played? */
if( !tunes[m_tune_num] || m_voices == 0 )
{
- while (--samples >= 0)
- buffer[samples] = 0;
+ buffer.fill(0);
return;
}
- while( samples-- > 0 )
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int sum = 0;
@@ -444,7 +443,7 @@ void tms36xx_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
TONE( 0) TONE( 1) TONE( 2) TONE( 3) TONE( 4) TONE( 5)
TONE( 6) TONE( 7) TONE( 8) TONE( 9) TONE(10) TONE(11)
- *buffer++ = sum / m_voices;
+ buffer.put_int(sampindex, sum, 32768 * m_voices);
}
}
diff --git a/src/devices/sound/tms36xx.h b/src/devices/sound/tms36xx.h
index 03dd5dc2412..5693e3b8e7c 100644
--- a/src/devices/sound/tms36xx.h
+++ b/src/devices/sound/tms36xx.h
@@ -63,7 +63,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
public:
// MM6221AA interface functions
diff --git a/src/devices/sound/tms5110.cpp b/src/devices/sound/tms5110.cpp
index 73f5244738e..5782aa905af 100644
--- a/src/devices/sound/tms5110.cpp
+++ b/src/devices/sound/tms5110.cpp
@@ -1048,7 +1048,7 @@ void tms5110_device::device_start()
m_data_cb.resolve();
/* initialize a stream */
- m_stream = stream_alloc_legacy(0, 1, clock() / 80);
+ m_stream = stream_alloc(0, 1, clock() / 80);
m_state = CTL_STATE_INPUT; /* most probably not defined */
m_romclk_hack_timer = timer_alloc(0);
@@ -1220,27 +1220,25 @@ int tms5110_device::romclk_hack_r()
******************************************************************************/
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void tms5110_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tms5110_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int16_t sample_data[MAX_SAMPLE_CHUNK];
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
/* loop while we still have samples to generate */
- while (samples)
+ for (int sampindex = 0; sampindex < buffer.samples(); )
{
- int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples;
- int index;
+ int length = buffer.samples() - sampindex;
+ if (length > MAX_SAMPLE_CHUNK)
+ length = MAX_SAMPLE_CHUNK;
/* generate the samples and copy to the target buffer */
process(sample_data, length);
- for (index = 0; index < length; index++)
- *buffer++ = sample_data[index];
-
- /* account for the samples */
- samples -= length;
+ for (int index = 0; index < length; index++)
+ buffer.put_int(sampindex++, sample_data[index], 32768);
}
}
diff --git a/src/devices/sound/tms5110.h b/src/devices/sound/tms5110.h
index 84c7f68fc73..e3bb2078075 100644
--- a/src/devices/sound/tms5110.h
+++ b/src/devices/sound/tms5110.h
@@ -60,7 +60,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
uint8_t TALK_STATUS() const { return m_SPEN | m_TALKD; }
diff --git a/src/devices/sound/tms5220.cpp b/src/devices/sound/tms5220.cpp
index 9c4974c34e2..d0afb710f46 100644
--- a/src/devices/sound/tms5220.cpp
+++ b/src/devices/sound/tms5220.cpp
@@ -2061,7 +2061,6 @@ void tms5220_device::sound_stream_update(sound_stream &stream, std::vector<read_
auto &output = outputs[0];
/* loop while we still have samples to generate */
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for (int sampindex = 0; sampindex < output.samples(); )
{
int length = (output.samples() > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : output.samples();
@@ -2069,7 +2068,7 @@ void tms5220_device::sound_stream_update(sound_stream &stream, std::vector<read_
/* generate the samples and copy to the target buffer */
process(sample_data, length);
for (int index = 0; index < length; index++)
- output.put(sampindex++, sample_data[index] * sample_scale);
+ output.put_int(sampindex++, sample_data[index], 32768);
}
}
diff --git a/src/devices/sound/upd1771.cpp b/src/devices/sound/upd1771.cpp
index bb8e61f2d00..2ec1d767ba0 100644
--- a/src/devices/sound/upd1771.cpp
+++ b/src/devices/sound/upd1771.cpp
@@ -255,7 +255,7 @@ void upd1771c_device::device_start()
m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd1771c_device::ack_callback),this));
- m_channel = stream_alloc_legacy(0, 1, clock() / 4);
+ m_channel = stream_alloc(0, 1, clock() / 4);
save_item(NAME(m_packet));
save_item(NAME(m_index));
@@ -476,12 +476,12 @@ TIMER_CALLBACK_MEMBER( upd1771c_device::ack_callback )
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void upd1771c_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void upd1771c_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
switch (m_state)
{
@@ -489,9 +489,9 @@ void upd1771c_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
//logerror( "upd1771_STATE_TONE samps:%d %d %d %d %d %d\n",(int)samples,
// (int)m_t_timbre,(int)m_t_offset,(int)m_t_volume,(int)m_t_period,(int)m_t_tpos);
- while (--samples >= 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
- *buffer++ = (WAVEFORMS[m_t_timbre][m_t_tpos]) * m_t_volume * 2;
+ buffer.put_int(sampindex, (WAVEFORMS[m_t_timbre][m_t_tpos]) * m_t_volume, 32768 / 2);
m_t_ppos++;
if (m_t_ppos >= m_t_period)
@@ -506,10 +506,8 @@ void upd1771c_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
break;
case STATE_NOISE:
- while (--samples >= 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
- *buffer = 0;
-
//"wavetable-LFSR" component
int wlfsr_val = ((int)noise_tbl[m_nw_tpos]) - 127;//data too wide
@@ -535,23 +533,18 @@ void upd1771c_device::sound_stream_update_legacy(sound_stream &stream, stream_sa
}
}
//not quite, but close.
- *buffer+= (
+ buffer.put_int(sampindex,
(wlfsr_val * m_nw_volume) |
(res[0] * m_n_volume[0]) |
(res[1] * m_n_volume[1]) |
- (res[2] * m_n_volume[2])
- ) ;
-
- buffer++;
+ (res[2] * m_n_volume[2]),
+ 32768) ;
}
break;
default:
//fill buffer with silence
- while (--samples >= 0)
- {
- *buffer++ = 0;
- }
+ buffer.fill(0);
break;
}
}
diff --git a/src/devices/sound/upd1771.h b/src/devices/sound/upd1771.h
index 9fe86b58c1d..7c5cc5f7f95 100644
--- a/src/devices/sound/upd1771.h
+++ b/src/devices/sound/upd1771.h
@@ -32,7 +32,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
static constexpr unsigned MAX_PACKET_SIZE = 0x8000;
diff --git a/src/devices/sound/upd7752.cpp b/src/devices/sound/upd7752.cpp
index 19977dcafdc..7c063fbee95 100644
--- a/src/devices/sound/upd7752.cpp
+++ b/src/devices/sound/upd7752.cpp
@@ -72,7 +72,7 @@ device_memory_interface::space_config_vector upd7752_device::memory_space_config
void upd7752_device::device_start()
{
/* TODO: clock */
- m_stream = stream_alloc_legacy(0, 1, clock() / 64);
+ m_stream = stream_alloc(0, 1, clock() / 64);
m_status = 0;
}
@@ -96,11 +96,12 @@ void upd7752_device::device_stop()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void upd7752_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void upd7752_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
//**************************************************************************
diff --git a/src/devices/sound/upd7752.h b/src/devices/sound/upd7752.h
index b65048624f1..9693ee99f4d 100644
--- a/src/devices/sound/upd7752.h
+++ b/src/devices/sound/upd7752.h
@@ -30,7 +30,7 @@ protected:
virtual void device_stop() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual space_config_vector memory_space_config() const override;
private:
diff --git a/src/devices/sound/upd934g.cpp b/src/devices/sound/upd934g.cpp
index fecb6fc8a18..fc25628abbd 100644
--- a/src/devices/sound/upd934g.cpp
+++ b/src/devices/sound/upd934g.cpp
@@ -49,7 +49,7 @@ upd934g_device::upd934g_device(const machine_config &mconfig, const char *tag, d
void upd934g_device::device_start()
{
// create sound stream
- m_stream = stream_alloc_legacy(0, 4, 20000);
+ m_stream = stream_alloc(0, 4, 20000);
// resolve callbacks
m_data_cb.resolve_safe(0);
@@ -81,32 +81,33 @@ void upd934g_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void upd934g_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void upd934g_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
for (unsigned ch = 0; ch < 4; ch++)
{
- std::fill(&outputs[ch][0], &outputs[ch][samples], 0);
-
if (m_ready && m_channel[ch].playing != -1)
{
uint16_t end = m_addr[m_channel[ch].playing + 1] - 1;
- for (unsigned i = 0; i < samples; i++)
+ for (unsigned i = 0; i < outputs[ch].samples(); i++)
{
int8_t raw = static_cast<int8_t>(m_data_cb(m_channel[ch].pos));
- outputs[ch][i] = raw * (m_channel[ch].volume + 1) * 64;
+ outputs[ch].put_int(i, raw * (m_channel[ch].volume + 1), 32768 / 64);
if (++m_channel[ch].pos >= end)
{
m_channel[ch].playing = -1;
+ outputs[ch].fill(0, i + 1);
break;
}
}
}
+ else
+ outputs[ch].fill(0);
}
}
diff --git a/src/devices/sound/upd934g.h b/src/devices/sound/upd934g.h
index ed145671c38..c61ac5a4910 100644
--- a/src/devices/sound/upd934g.h
+++ b/src/devices/sound/upd934g.h
@@ -36,7 +36,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
devcb_read8 m_data_cb;
diff --git a/src/devices/sound/vgm_visualizer.cpp b/src/devices/sound/vgm_visualizer.cpp
index c1f438f2b2c..bab3c909ddf 100644
--- a/src/devices/sound/vgm_visualizer.cpp
+++ b/src/devices/sound/vgm_visualizer.cpp
@@ -158,7 +158,7 @@ void vgmviz_device::apply_fft()
void vgmviz_device::apply_waterfall()
{
- int total_bars = FFT_LENGTH / 2;
+ const int total_bars = FFT_LENGTH / 2;
WDL_FFT_COMPLEX* bins[2] = { (WDL_FFT_COMPLEX*)m_fft_buf[0], (WDL_FFT_COMPLEX*)m_fft_buf[1] };
for (int bar = 0; bar < std::min<int>(total_bars, SCREEN_HEIGHT); bar++)
{
@@ -555,7 +555,7 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
m_clear_pending = false;
}
- const pen_t *pal = m_palette->pens();
+ pen_t const *const pal = m_palette->pens();
int width = SCREEN_WIDTH;
switch (SpecMode)
@@ -563,31 +563,26 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
case SPEC_VIZ_PILLAR:
for (int y = 2; y < SCREEN_HEIGHT; y++)
{
- uint32_t *src = &m_bitmap.pix32(y);
- uint32_t *dst = &bitmap.pix32(y - 2);
+ uint32_t const *const src = &m_bitmap.pix(y);
+ uint32_t *const dst = &bitmap.pix(y - 2);
for (int x = SCREEN_WIDTH - 1; x >= 1; x--)
{
dst[x] = src[x - 1];
}
}
- width = (int)(SCREEN_WIDTH * 0.75f);
+ width = int(SCREEN_WIDTH * 0.75f);
break;
case SPEC_VIZ_TOP:
for (int y = 1; y < SCREEN_HEIGHT; y++)
{
- uint32_t *src = &m_bitmap.pix32(y);
- uint32_t *dst = &bitmap.pix32(y - 1);
- for (int x = 0; x < SCREEN_WIDTH; x++)
- {
- dst[x] = src[x];
- }
+ std::copy_n(&m_bitmap.pix(y), SCREEN_WIDTH, &bitmap.pix(y - 1));
}
break;
default:
break;
}
- int total_bars = FFT_LENGTH / 2;
+ const int total_bars = FFT_LENGTH / 2;
WDL_FFT_COMPLEX *bins[2] = { (WDL_FFT_COMPLEX *)m_fft_buf[0], (WDL_FFT_COMPLEX *)m_fft_buf[1] };
for (int bar = 2; bar < total_bars && bar < width; bar += BarSize)
@@ -614,8 +609,8 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
}
for (int y = 0; y < SCREEN_HEIGHT; y++)
{
- int bar_y = SCREEN_HEIGHT - y;
- uint32_t *line = &bitmap.pix32(y);
+ const int bar_y = SCREEN_HEIGHT - y;
+ uint32_t *const line = &bitmap.pix(y);
for (int x = 0; x < BarSize; x++)
{
line[(bar - 2) + x] = bar_y <= level ? pal[256 + pal_index] : pal[black_index];
@@ -631,8 +626,8 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
for (int y = 0; y < SCREEN_HEIGHT; y++)
{
- int bar_y = SCREEN_HEIGHT - y;
- uint32_t *line = &bitmap.pix32(y);
+ const int bar_y = SCREEN_HEIGHT - y;
+ uint32_t *const line = &bitmap.pix(y);
line[0] = 0;
if (bar_y > level)
{
@@ -643,9 +638,9 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
{
if (bar_y < (level - 1))
{
- const uint8_t r = (uint8_t)(((entry >> 16) & 0xff) * 0.75f);
- const uint8_t g = (uint8_t)(((entry >> 8) & 0xff) * 0.75f);
- const uint8_t b = (uint8_t)(((entry >> 0) & 0xff) * 0.75f);
+ const uint8_t r = uint8_t(((entry >> 16) & 0xff) * 0.75f);
+ const uint8_t g = uint8_t(((entry >> 8) & 0xff) * 0.75f);
+ const uint8_t b = uint8_t(((entry >> 0) & 0xff) * 0.75f);
line[(bar - 2) + x] = 0xff000000 | (r << 16) | (g << 8) | b;
}
else
@@ -653,9 +648,9 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
line[(bar - 2) + x] = pal[256 + pal_index];
}
}
- const uint8_t r = (uint8_t)(((entry >> 16) & 0xff) * 0.5f);
- const uint8_t g = (uint8_t)(((entry >> 8) & 0xff) * 0.5f);
- const uint8_t b = (uint8_t)(((entry >> 0) & 0xff) * 0.5f);
+ const uint8_t r = uint8_t(((entry >> 16) & 0xff) * 0.5f);
+ const uint8_t g = uint8_t(((entry >> 8) & 0xff) * 0.5f);
+ const uint8_t b = uint8_t(((entry >> 0) & 0xff) * 0.5f);
line[(bar - 2) + (BarSize - 1)] = 0xff000000 | (r << 16) | (g << 8) | b;
if (bar_y < level)
{
@@ -664,10 +659,11 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
}
for (int x = 0; x < SCREEN_WIDTH; x++)
{
- bitmap.pix32(SCREEN_HEIGHT - 1, x) = 0;
- bitmap.pix32(SCREEN_HEIGHT - 2, x) = 0;
+ bitmap.pix(SCREEN_HEIGHT - 1, x) = 0;
+ bitmap.pix(SCREEN_HEIGHT - 2, x) = 0;
}
- memcpy(&m_bitmap.pix32(0), &bitmap.pix32(0), sizeof(uint32_t) * SCREEN_WIDTH * SCREEN_HEIGHT);
+ for (int y = 0; y < SCREEN_HEIGHT; y++)
+ std::copy_n(&bitmap.pix(y), SCREEN_WIDTH, &m_bitmap.pix(y));
break;
case SPEC_VIZ_TOP:
level = int(raw_level * 63.0f);
@@ -678,10 +674,11 @@ template <int BarSize, int SpecMode> void vgmviz_device::draw_spectrogram(bitmap
for (int x = 0; x < BarSize; x++)
{
- bitmap.pix32(SCREEN_HEIGHT - 1, (bar - 2) + x) = level > 0 ? pal[256 + pal_index] : pal[black_index];
+ bitmap.pix(SCREEN_HEIGHT - 1, (bar - 2) + x) = level > 0 ? pal[256 + pal_index] : pal[black_index];
}
- memcpy(&m_bitmap.pix32(0), &bitmap.pix32(0), sizeof(uint32_t) * SCREEN_WIDTH * SCREEN_HEIGHT);
+ for (int y = 0; y < SCREEN_HEIGHT; y++)
+ std::copy_n(&bitmap.pix(y), SCREEN_WIDTH, &m_bitmap.pix(y));
break;
}
}
@@ -700,7 +697,7 @@ void vgmviz_device::draw_waterfall(bitmap_rgb32 &bitmap)
const int v0_index = (int)v0h;
const int v1_index = (int)v1h;
const float interp = v0h - (float)v0_index;
- uint32_t* line = &bitmap.pix32(y);
+ uint32_t* line = &bitmap.pix(y);
for (int x = 0; x < SCREEN_WIDTH; x++)
{
if (m_waterfall_length < SCREEN_WIDTH)
@@ -736,8 +733,8 @@ void vgmviz_device::draw_waveform(bitmap_rgb32 &bitmap)
for (int x = 0; x < SCREEN_WIDTH; x++)
{
- bitmap.pix32(CHANNEL_CENTER, x) = MED_GRAY;
- bitmap.pix32(CHANNEL_HEIGHT + 1 + CHANNEL_CENTER, x) = MED_GRAY;
+ bitmap.pix(CHANNEL_CENTER, x) = MED_GRAY;
+ bitmap.pix(CHANNEL_HEIGHT + 1 + CHANNEL_CENTER, x) = MED_GRAY;
const float raw_l = m_audio_buf[1 - m_audio_fill_index][0][((int)m_history_length + 1 + x) % FFT_LENGTH];
const int sample_l = (int)((raw_l - 0.5f) * (CHANNEL_HEIGHT - 1));
@@ -746,7 +743,7 @@ void vgmviz_device::draw_waveform(bitmap_rgb32 &bitmap)
int y = endy_l - sample_l;
do
{
- bitmap.pix32(y, x) = LEFT_COLOR;
+ bitmap.pix(y, x) = LEFT_COLOR;
y += dy_l;
} while(y != endy_l);
@@ -757,11 +754,11 @@ void vgmviz_device::draw_waveform(bitmap_rgb32 &bitmap)
y = endy_r - sample_r;
do
{
- bitmap.pix32(y, x) = RIGHT_COLOR;
+ bitmap.pix(y, x) = RIGHT_COLOR;
y += dy_r;
} while(y != endy_r);
- bitmap.pix32(CHANNEL_HEIGHT, x) = WHITE;
- bitmap.pix32(CHANNEL_HEIGHT + 1, x) = WHITE;
+ bitmap.pix(CHANNEL_HEIGHT, x) = WHITE;
+ bitmap.pix(CHANNEL_HEIGHT + 1, x) = WHITE;
}
}
diff --git a/src/devices/sound/vlm5030.cpp b/src/devices/sound/vlm5030.cpp
index 3d3cc7863fd..71dd026000c 100644
--- a/src/devices/sound/vlm5030.cpp
+++ b/src/devices/sound/vlm5030.cpp
@@ -214,7 +214,7 @@ void vlm5030_device::device_start()
device_reset();
m_phase = PH_IDLE;
- m_channel = stream_alloc_legacy(0, 1, clock() / 440);
+ m_channel = stream_alloc(0, 1, clock() / 440);
save_item(NAME(m_address));
save_item(NAME(m_pin_BSY));
@@ -491,22 +491,22 @@ if( m_interp_step != 1)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void vlm5030_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void vlm5030_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int buf_count=0;
int interp_effect;
int i;
int u[11];
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
/* running */
+ int sampindex = 0;
if( m_phase == PH_RUN || m_phase == PH_STOP )
{
/* playing speech */
- while (samples > 0)
+ for ( ; sampindex < buffer.samples(); sampindex++)
{
int current_val;
@@ -592,13 +592,7 @@ void vlm5030_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
m_x[0] = u[0];
/* clipping, buffering */
- if (u[0] > 511)
- buffer[buf_count] = 511<<6;
- else if (u[0] < -511)
- buffer[buf_count] = uint32_t(-511)<<6;
- else
- buffer[buf_count] = (u[0] << 6);
- buf_count++;
+ buffer.put_int_clamp(sampindex, u[0], 512);
/* sample count */
m_sample_count--;
@@ -607,7 +601,6 @@ void vlm5030_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
if (m_pitch_count >= m_current_pitch )
m_pitch_count = 0;
/* size */
- samples--;
}
/* return;*/
}
@@ -616,7 +609,7 @@ phase_stop:
switch( m_phase )
{
case PH_SETUP:
- if( m_sample_count <= samples)
+ if( m_sample_count <= buffer.samples())
{
m_sample_count = 0;
/* logerror("VLM5030 BSY=H\n" ); */
@@ -625,11 +618,11 @@ phase_stop:
}
else
{
- m_sample_count -= samples;
+ m_sample_count -= buffer.samples();
}
break;
case PH_END:
- if( m_sample_count <= samples)
+ if( m_sample_count <= buffer.samples())
{
m_sample_count = 0;
/* logerror("VLM5030 BSY=L\n" ); */
@@ -638,13 +631,9 @@ phase_stop:
}
else
{
- m_sample_count -= samples;
+ m_sample_count -= buffer.samples();
}
}
/* silent buffering */
- while (samples > 0)
- {
- buffer[buf_count++] = 0x00;
- samples--;
- }
+ buffer.fill(0, sampindex);
}
diff --git a/src/devices/sound/vlm5030.h b/src/devices/sound/vlm5030.h
index 7520bf76007..4675d99fce4 100644
--- a/src/devices/sound/vlm5030.h
+++ b/src/devices/sound/vlm5030.h
@@ -34,7 +34,7 @@ protected:
virtual void device_post_load() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/votrax.cpp b/src/devices/sound/votrax.cpp
index 000a568d2a3..067e639ed78 100644
--- a/src/devices/sound/votrax.cpp
+++ b/src/devices/sound/votrax.cpp
@@ -489,7 +489,7 @@ void votrax_sc01_device::chip_update()
m_noise = ((m_noise << 1) & 0x7ffe) | inp;
m_cur_noise = !(((m_noise >> 14) ^ (m_noise >> 13)) & 1);
- // logerror("%s tick %02x.%03x 625=%d 208=%d pitch=%02x.%x ns=%04x ni=%d noise=%d cl=%x.%x clf=%d/%d\n", machine().time().to_string(), m_ticks, m_phonetick, tick_625, tick_208, m_pitch >> 3, m_pitch & 7, m_noise, inp, m_cur_noise, m_closure >> 2, m_closure & 3, m_rom_closure, m_cur_closure);
+ // logerror("%s tick %02x.%03x 625=%d 208=%d pitch=%02x.%x ns=%04x ni=%d noise=%d cl=%x.%x clf=%d/%d\n", machine().time().to_string(), m_ticks, m_phonetick, tick_625, tick_208, m_pitch >> 3, m_pitch & 7, m_noise, inp, m_cur_noise, m_closure >> 2, m_closure & 3, m_rom_closure, m_cur_closure);
}
void votrax_sc01_device::filters_commit(bool force)
@@ -877,8 +877,11 @@ void votrax_sc01_device::build_lowpass_filter(double *a, double *b,
double c1t, // Unswitched cap, over amp-op, top
double c1b) // Switched cap, over amp-op, bottom
{
+ // The caps values puts the cutoff at around 150Hz, put that's no good.
+ // Recordings shows we want it around 4K, so fuzz it.
+
// Compute the only coefficient we care about
- double k = c1b / (m_cclock * c1t);
+ double k = c1b / (m_cclock * c1t) * (150.0/4000.0);
// Compute the filter cutoff frequency
double fpeak = 1/(2*M_PI*k);
@@ -1001,7 +1004,7 @@ void votrax_sc01_device::build_injection_filter(double *a, double *b,
b[1] = k1 + m;
// That ends up in a numerically unstable filter. Neutralize it for now.
- a[0] = 1;
+ a[0] = 0;
a[1] = 0;
b[0] = 1;
b[1] = 0;
diff --git a/src/devices/sound/vrc6.cpp b/src/devices/sound/vrc6.cpp
index 58022411766..d9b36f5b8a6 100644
--- a/src/devices/sound/vrc6.cpp
+++ b/src/devices/sound/vrc6.cpp
@@ -45,7 +45,7 @@ vrc6snd_device::vrc6snd_device(const machine_config &mconfig, const char *tag, d
void vrc6snd_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 1, clock());
+ m_stream = stream_alloc(0, 1, clock());
m_freqctrl = m_pulsectrl[0] = m_pulsectrl[1] = 0;
m_pulsefrql[0] = m_pulsefrql[1] = m_pulsefrqh[0] = m_pulsefrqh[1] = 0;
@@ -89,19 +89,20 @@ void vrc6snd_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void vrc6snd_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void vrc6snd_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- std::fill_n(&outputs[0][0], samples, 0);
-
// check global halt bit
if (m_freqctrl & 1)
+ {
+ outputs[0].fill(0);
return;
+ }
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
// update pulse1
if (m_pulsefrqh[0] & 0x80)
@@ -198,9 +199,8 @@ void vrc6snd_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
// sum 2 4-bit pulses, 1 5-bit saw = unsigned 6 bit output
s16 tmp = (s16)(u8)(m_output[0] + m_output[1] + m_output[2]);
- tmp <<= 8;
- outputs[0][i] = tmp;
+ outputs[0].put_int(i, tmp, 128);
}
}
diff --git a/src/devices/sound/vrc6.h b/src/devices/sound/vrc6.h
index 0c1dd422d14..eb17dabff82 100644
--- a/src/devices/sound/vrc6.h
+++ b/src/devices/sound/vrc6.h
@@ -31,7 +31,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
u8 m_freqctrl, m_pulsectrl[2], m_sawrate, m_master_freq;
diff --git a/src/devices/sound/vrender0.cpp b/src/devices/sound/vrender0.cpp
index 09fb0f14940..fd86b56adea 100644
--- a/src/devices/sound/vrender0.cpp
+++ b/src/devices/sound/vrender0.cpp
@@ -148,7 +148,7 @@ void vr0sound_device::device_start()
for (auto &elem : m_channel)
elem.Cache = &m_fbcache;
- m_stream = stream_alloc_legacy(0, 2, clock() / 972); // TODO : Correct source / divider?
+ m_stream = stream_alloc(0, 2, clock() / 972); // TODO : Correct source / divider?
save_item(STRUCT_MEMBER(m_channel, CurSAddr));
save_item(STRUCT_MEMBER(m_channel, EnvVol));
@@ -208,13 +208,13 @@ device_memory_interface::space_config_vector vr0sound_device::memory_space_confi
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests
+// sound_stream_update - handle update requests
// for our sound stream
//-------------------------------------------------
-void vr0sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void vr0sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- VR0_RenderAudio(samples, outputs[0], outputs[1]);
+ VR0_RenderAudio(outputs[0], outputs[1]);
}
u16 vr0sound_device::channel_r(offs_t offset)
@@ -500,7 +500,7 @@ void vr0sound_device::channel_t::write(offs_t offset, u16 data, u16 mem_mask)
}
}
-void vr0sound_device::VR0_RenderAudio(int nsamples, stream_sample_t *l, stream_sample_t *r)
+void vr0sound_device::VR0_RenderAudio(write_stream_view &l, write_stream_view &r)
{
int div;
if (m_ChnClkNum)
@@ -508,7 +508,7 @@ void vr0sound_device::VR0_RenderAudio(int nsamples, stream_sample_t *l, stream_s
else
div = 1 << 16;
- for (int s = 0; s < nsamples; s++)
+ for (int s = 0; s < l.samples(); s++)
{
s32 lsample = 0, rsample = 0;
for (int i = 0; i <= m_MaxChn; i++)
@@ -590,7 +590,7 @@ void vr0sound_device::VR0_RenderAudio(int nsamples, stream_sample_t *l, stream_s
lsample += (sample * channel->LChnVol) >> 8;
rsample += (sample * channel->RChnVol) >> 8;
}
- l[s] = std::max(-32768, std::min(32767, lsample));
- r[s] = std::max(-32768, std::min(32767, rsample));
+ l.put_int_clamp(s, lsample, 32768);
+ r.put_int_clamp(s, rsample, 32768);
}
}
diff --git a/src/devices/sound/vrender0.h b/src/devices/sound/vrender0.h
index 99e2235a1be..1e234232c69 100644
--- a/src/devices/sound/vrender0.h
+++ b/src/devices/sound/vrender0.h
@@ -78,7 +78,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_memory_interface configuration
virtual space_config_vector memory_space_config() const override;
@@ -151,7 +151,7 @@ private:
u8 m_MaxChn = 0x1f; // Max Channels - 1
u8 m_ChnClkNum = 0; // Clock Number per Channel
u16 m_Ctrl = 0; // 0x602 Control Functions
- void VR0_RenderAudio(int nsamples, stream_sample_t *l, stream_sample_t *r);
+ void VR0_RenderAudio(write_stream_view &l, write_stream_view &r);
};
DECLARE_DEVICE_TYPE(SOUND_VRENDER0, vr0sound_device)
diff --git a/src/devices/sound/wave.cpp b/src/devices/sound/wave.cpp
index 27407a2dbd2..99c56615171 100644
--- a/src/devices/sound/wave.cpp
+++ b/src/devices/sound/wave.cpp
@@ -40,51 +40,36 @@ wave_device::wave_device(const machine_config &mconfig, const char *tag, device_
void wave_device::device_start()
{
- speaker_device_iterator spkiter(*owner());
- int speakers = spkiter.count();
- if (speakers > 1)
- stream_alloc_legacy(0, 2, machine().sample_rate());
- else
- stream_alloc_legacy(0, 1, machine().sample_rate());
+ stream_alloc(0, 2, machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void wave_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void wave_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *left_buffer = outputs[0];
- stream_sample_t *right_buffer = nullptr;
-
- speaker_device_iterator spkiter(*owner());
- int speakers = spkiter.count();
- if (speakers > 1)
- right_buffer = outputs[1];
-
cassette_state state = m_cass->get_state() & (CASSETTE_MASK_UISTATE | CASSETTE_MASK_MOTOR | CASSETTE_MASK_SPEAKER);
if (m_cass->exists() && (ALWAYS_PLAY_SOUND || (state == (CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED))))
{
cassette_image *cassette = m_cass->get_image();
double time_index = m_cass->get_position();
- double duration = double(samples) / m_cass->machine().sample_rate();
+ double duration = double(outputs[0].samples()) / outputs[0].sample_rate();
- cassette_get_samples(cassette, 0, time_index, duration, samples, 2, left_buffer, CASSETTE_WAVEFORM_16BIT);
- if (speakers > 1)
- cassette_get_samples(cassette, 1, time_index, duration, samples, 2, right_buffer, CASSETTE_WAVEFORM_16BIT);
+ if (m_sample_buf.size() < outputs[0].samples())
+ m_sample_buf.resize(outputs[0].samples());
- for (int i = samples - 1; i >= 0; i--)
+ for (int ch = 0; ch < 2; ch++)
{
- left_buffer[i] = ((int16_t *) left_buffer)[i];
- if (speakers > 1)
- right_buffer[i] = ((int16_t *) right_buffer)[i];
+ cassette->get_samples(ch, time_index, duration, outputs[ch].samples(), 2, &m_sample_buf[0], cassette_image::WAVEFORM_16BIT);
+ for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
+ outputs[ch].put_int(sampindex, m_sample_buf[sampindex], 32768);
}
}
else
{
- memset(left_buffer, 0, sizeof(*left_buffer) * samples);
- if (speakers > 1)
- memset(right_buffer, 0, sizeof(*right_buffer) * samples);
+ outputs[0].fill(0);
+ outputs[1].fill(0);
}
}
diff --git a/src/devices/sound/wave.h b/src/devices/sound/wave.h
index 9f2a834d6c1..e81379ee93a 100644
--- a/src/devices/sound/wave.h
+++ b/src/devices/sound/wave.h
@@ -30,10 +30,11 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
required_device<cassette_image_device> m_cass;
+ std::vector<s16> m_sample_buf;
};
DECLARE_DEVICE_TYPE(WAVE, wave_device)
diff --git a/src/devices/sound/x1_010.cpp b/src/devices/sound/x1_010.cpp
index 8334db4a299..b54fa6bd6cf 100644
--- a/src/devices/sound/x1_010.cpp
+++ b/src/devices/sound/x1_010.cpp
@@ -119,7 +119,7 @@ void x1_010_device::device_start()
LOG_SOUND("masterclock = %d rate = %d\n", clock(), m_rate);
/* get stream channels */
- m_stream = stream_alloc_legacy(0, 2, m_rate);
+ m_stream = stream_alloc(0, 2, m_rate);
m_reg = make_unique_clear<u8[]>(0x2000);
m_HI_WORD_BUF = make_unique_clear<u8[]>(0x2000);
@@ -204,14 +204,14 @@ void x1_010_device::word_w(offs_t offset, u16 data)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void x1_010_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void x1_010_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// mixer buffer zero clear
- memset(outputs[0], 0, samples*sizeof(*outputs[0]));
- memset(outputs[1], 0, samples*sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
// if (m_sound_enable == 0) return;
@@ -220,8 +220,8 @@ void x1_010_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
X1_010_CHANNEL *reg = (X1_010_CHANNEL *)&(m_reg[ch*sizeof(X1_010_CHANNEL)]);
if ((reg->status & 1) != 0) // Key On
{
- stream_sample_t *bufL = outputs[0];
- stream_sample_t *bufR = outputs[1];
+ auto &bufL = outputs[0];
+ auto &bufR = outputs[1];
const int div = (reg->status & 0x80) ? 1 : 0;
if ((reg->status & 2) == 0) // PCM sampling
{
@@ -240,7 +240,7 @@ void x1_010_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
LOG_SOUND("Play sample %p - %p, channel %X volume %d:%d freq %X step %X offset %X\n",
start, end, ch, volL, volR, freq, smp_step, smp_offs);
}
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < bufL.samples(); i++)
{
const u32 delta = smp_offs >> 4;
// sample ended?
@@ -250,8 +250,8 @@ void x1_010_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
break;
}
const s8 data = (s8)(read_byte(start+delta));
- *bufL++ += (data * volL / 256);
- *bufR++ += (data * volR / 256);
+ bufL.add_int(i, data * volL, 32768 * 256);
+ bufR.add_int(i, data * volR, 32768 * 256);
smp_offs += smp_step;
}
m_smp_offset[ch] = smp_offs;
@@ -272,7 +272,7 @@ void x1_010_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
LOG_SOUND("Play waveform %X, channel %X volume %X freq %4X step %X offset %X\n",
reg->volume, ch, reg->end, freq, smp_step, smp_offs);
}
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < bufL.samples(); i++)
{
const u32 delta = env_offs >> 10;
// Envelope one shot mode
@@ -285,8 +285,8 @@ void x1_010_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
const int volL = ((vol >> 4) & 0xf) * VOL_BASE;
const int volR = ((vol >> 0) & 0xf) * VOL_BASE;
const s8 data = (s8)(m_reg[start + ((smp_offs >> 10) & 0x7f)]);
- *bufL++ += (data * volL / 256);
- *bufR++ += (data * volR / 256);
+ bufL.add_int(i, data * volL, 32768 * 256);
+ bufR.add_int(i, data * volR, 32768 * 256);
smp_offs += smp_step;
env_offs += env_step;
}
diff --git a/src/devices/sound/x1_010.h b/src/devices/sound/x1_010.h
index 3c8f1e60dc6..b6b266b0ba0 100644
--- a/src/devices/sound/x1_010.h
+++ b/src/devices/sound/x1_010.h
@@ -26,7 +26,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/ym2151.cpp b/src/devices/sound/ym2151.cpp
index b519d9a1224..74cfa9643ae 100644
--- a/src/devices/sound/ym2151.cpp
+++ b/src/devices/sound/ym2151.cpp
@@ -1845,7 +1845,6 @@ void ym2151_device::sound_stream_update(sound_stream &stream, std::vector<read_s
return;
}
- constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
for (int sampindex=0; sampindex<outputs[0].samples(); sampindex++)
{
advance_eg();
@@ -1864,16 +1863,8 @@ void ym2151_device::sound_stream_update(sound_stream &stream, std::vector<read_s
outr += chanout[ch] & pan[2*ch+1];
}
- if (outl > 32767)
- outl = 32767;
- else if (outl < -32768)
- outl = -32768;
- if (outr > 32767)
- outr = 32767;
- else if (outr < -32768)
- outr = -32768;
- outputs[0].put(sampindex, stream_buffer::sample_t(outl) * sample_scale);
- outputs[1].put(sampindex, stream_buffer::sample_t(outr) * sample_scale);
+ outputs[0].put_int_clamp(sampindex, outl, 32768);
+ outputs[1].put_int_clamp(sampindex, outr, 32768);
advance();
}
diff --git a/src/devices/sound/ym2413.cpp b/src/devices/sound/ym2413.cpp
index ca4a9acb874..28cf77c097b 100644
--- a/src/devices/sound/ym2413.cpp
+++ b/src/devices/sound/ym2413.cpp
@@ -1470,12 +1470,12 @@ void ym2413_device::write_reg(int r, int v)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ym2413_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ym2413_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for(int i=0; i < samples ; i++ )
+ for(int i=0; i < outputs[0].samples() ; i++ )
{
output[0] = 0;
output[1] = 0;
@@ -1496,8 +1496,8 @@ void ym2413_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
rhythm_calc(&P_CH[0], noise_rng & 1 );
}
- outputs[0][i] = limit( output[0] , 32767, -32768 );
- outputs[1][i] = limit( output[1] , 32767, -32768 );
+ outputs[0].put_int_clamp(i, output[0], 32768);
+ outputs[1].put_int_clamp(i, output[1], 32768);
advance();
}
@@ -1511,7 +1511,7 @@ void ym2413_device::device_start()
{
int rate = clock()/72;
- m_stream = stream_alloc_legacy(0,2,rate);
+ m_stream = stream_alloc(0,2,rate);
for (int x=0; x<TL_RES_LEN; x++)
{
diff --git a/src/devices/sound/ym2413.h b/src/devices/sound/ym2413.h
index 2e1db357150..27174977332 100644
--- a/src/devices/sound/ym2413.h
+++ b/src/devices/sound/ym2413.h
@@ -25,7 +25,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
uint8_t m_inst_table[19][8];
diff --git a/src/devices/sound/ymf262.cpp b/src/devices/sound/ymf262.cpp
index 6ec8e081021..708970a7c0b 100644
--- a/src/devices/sound/ymf262.cpp
+++ b/src/devices/sound/ymf262.cpp
@@ -639,6 +639,7 @@ static inline void OPL3_SLOT_CONNECT(OPL3 *chip, OPL3_SLOT *slot) {
}
}
+#if 0
static inline int limit( int val, int max, int min ) {
if ( val > max )
val = max;
@@ -647,7 +648,7 @@ static inline int limit( int val, int max, int min ) {
return val;
}
-
+#endif
/* status set and IRQ handling */
static inline void OPL3_STATUS_SET(OPL3 *chip,int flag)
@@ -2618,19 +2619,19 @@ void ymf262_set_update_handler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, dev
** '**buffers' is table of 4 pointers to the buffers: CH.A, CH.B, CH.C and CH.D
** 'length' is the number of samples that should be generated
*/
-void ymf262_update_one(void *_chip, OPL3SAMPLE * const *buffers, int length)
+void ymf262_update_one(void *_chip, std::vector<write_stream_view> &buffers)
{
int i;
OPL3 *chip = (OPL3 *)_chip;
signed int *chanout = chip->chanout;
uint8_t rhythm = chip->rhythm&0x20;
- OPL3SAMPLE *ch_a = buffers[0]; // DO2 (mixed) left output for OPL4
- OPL3SAMPLE *ch_b = buffers[1]; // DO2 (mixed) right output for OPL4
- OPL3SAMPLE *ch_c = buffers[2]; // DO0 (FM only) left output for OPL4
- OPL3SAMPLE *ch_d = buffers[3]; // DO0 (FM only) right output for OPL4
+ auto &ch_a = buffers[0]; // DO2 (mixed) left output for OPL4
+ auto &ch_b = buffers[1]; // DO2 (mixed) right output for OPL4
+ auto &ch_c = buffers[2]; // DO0 (FM only) left output for OPL4
+ auto &ch_d = buffers[3]; // DO0 (FM only) right output for OPL4
- for( i=0; i < length ; i++ )
+ for( i=0; i < ch_a.samples() ; i++ )
{
int a,b,c,d;
@@ -2782,16 +2783,6 @@ void ymf262_update_one(void *_chip, OPL3SAMPLE * const *buffers, int length)
c += chanout[17] & chip->pan[70];
d += chanout[17] & chip->pan[71];
#endif
- a >>= FINAL_SH;
- b >>= FINAL_SH;
- c >>= FINAL_SH;
- d >>= FINAL_SH;
-
- /* limit check */
- a = limit( a , MAXOUT, MINOUT );
- b = limit( b , MAXOUT, MINOUT );
- c = limit( c , MAXOUT, MINOUT );
- d = limit( d , MAXOUT, MINOUT );
#ifdef SAVE_SAMPLE
if (which==0)
@@ -2801,10 +2792,10 @@ void ymf262_update_one(void *_chip, OPL3SAMPLE * const *buffers, int length)
#endif
/* store to sound buffer */
- ch_a[i] = a;
- ch_b[i] = b;
- ch_c[i] = c;
- ch_d[i] = d;
+ ch_a.put_int_clamp(i, a, 32768 << FINAL_SH);
+ ch_b.put_int_clamp(i, a, 32768 << FINAL_SH);
+ ch_c.put_int_clamp(i, a, 32768 << FINAL_SH);
+ ch_d.put_int_clamp(i, a, 32768 << FINAL_SH);
advance(chip);
}
diff --git a/src/devices/sound/ymf262.h b/src/devices/sound/ymf262.h
index d459a9a68ee..fe131169fcf 100644
--- a/src/devices/sound/ymf262.h
+++ b/src/devices/sound/ymf262.h
@@ -8,7 +8,7 @@
/* select number of output bits: 8 or 16 */
#define OPL3_SAMPLE_BITS 16
-typedef stream_sample_t OPL3SAMPLE;
+typedef s32 OPL3SAMPLE;
/*
#if (OPL3_SAMPLE_BITS==16)
typedef int16_t OPL3SAMPLE;
@@ -33,7 +33,7 @@ void ymf262_reset_chip(void *chip);
int ymf262_write(void *chip, int a, int v);
unsigned char ymf262_read(void *chip, int a);
int ymf262_timer_over(void *chip, int c);
-void ymf262_update_one(void *chip, OPL3SAMPLE * const *buffers, int length);
+void ymf262_update_one(void *chip, std::vector<write_stream_view> &buffers);
void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER TimerHandler, device_t *device);
void ymf262_set_irq_handler(void *chip, OPL3_IRQHANDLER IRQHandler, device_t *device);
diff --git a/src/devices/sound/ymf271.cpp b/src/devices/sound/ymf271.cpp
index 03ca33a2382..a473705b065 100644
--- a/src/devices/sound/ymf271.cpp
+++ b/src/devices/sound/ymf271.cpp
@@ -563,10 +563,10 @@ void ymf271_device::set_feedback(int slotnum, int64_t inp)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ymf271_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ymf271_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i, j;
int op;
@@ -599,7 +599,7 @@ void ymf271_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
if (m_slots[slot1].active)
{
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
int64_t output1 = 0, output2 = 0, output3 = 0, output4 = 0;
int64_t phase_mod1, phase_mod2, phase_mod3;
@@ -833,7 +833,7 @@ void ymf271_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
mixp = &m_mix_buffer[0];
if (m_slots[slot1].active)
{
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
int64_t output1 = 0, output3 = 0;
int64_t phase_mod1, phase_mod3;
@@ -900,7 +900,7 @@ void ymf271_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
if (m_slots[slot1].active)
{
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
int64_t output1 = 0, output2 = 0, output3 = 0;
int64_t phase_mod1, phase_mod3;
@@ -1006,29 +1006,29 @@ void ymf271_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
}
mixp = &m_mix_buffer[0];
- update_pcm(j + (3*12), mixp, samples);
+ update_pcm(j + (3*12), mixp, outputs[0].samples());
break;
}
// PCM
case 3:
{
- update_pcm(j + (0*12), mixp, samples);
- update_pcm(j + (1*12), mixp, samples);
- update_pcm(j + (2*12), mixp, samples);
- update_pcm(j + (3*12), mixp, samples);
+ update_pcm(j + (0*12), mixp, outputs[0].samples());
+ update_pcm(j + (1*12), mixp, outputs[0].samples());
+ update_pcm(j + (2*12), mixp, outputs[0].samples());
+ update_pcm(j + (3*12), mixp, outputs[0].samples());
break;
}
}
}
mixp = &m_mix_buffer[0];
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
- outputs[0][i] = (*mixp++)>>2;
- outputs[1][i] = (*mixp++)>>2;
- outputs[2][i] = (*mixp++)>>2;
- outputs[3][i] = (*mixp++)>>2;
+ outputs[0].put_int(i, *mixp++, 32768 << 2);
+ outputs[1].put_int(i, *mixp++, 32768 << 2);
+ outputs[2].put_int(i, *mixp++, 32768 << 2);
+ outputs[3].put_int(i, *mixp++, 32768 << 2);
}
}
@@ -1520,8 +1520,11 @@ u8 ymf271_device::read(offs_t offset)
return 0xff;
uint8_t ret = m_ext_readlatch;
- m_ext_address = (m_ext_address + 1) & 0x7fffff;
- m_ext_readlatch = read_byte(m_ext_address);
+ if (!machine().side_effects_disabled())
+ {
+ m_ext_address = (m_ext_address + 1) & 0x7fffff;
+ m_ext_readlatch = read_byte(m_ext_address);
+ }
return ret;
}
@@ -1660,64 +1663,56 @@ void ymf271_device::calculate_clock_correction()
void ymf271_device::init_state()
{
- int i;
-
- for (i = 0; i < ARRAY_LENGTH(m_slots); i++)
- {
- save_item(NAME(m_slots[i].ext_en), i);
- save_item(NAME(m_slots[i].ext_out), i);
- save_item(NAME(m_slots[i].lfoFreq), i);
- save_item(NAME(m_slots[i].pms), i);
- save_item(NAME(m_slots[i].ams), i);
- save_item(NAME(m_slots[i].detune), i);
- save_item(NAME(m_slots[i].multiple), i);
- save_item(NAME(m_slots[i].tl), i);
- save_item(NAME(m_slots[i].keyscale), i);
- save_item(NAME(m_slots[i].ar), i);
- save_item(NAME(m_slots[i].decay1rate), i);
- save_item(NAME(m_slots[i].decay2rate), i);
- save_item(NAME(m_slots[i].decay1lvl), i);
- save_item(NAME(m_slots[i].relrate), i);
- save_item(NAME(m_slots[i].block), i);
- save_item(NAME(m_slots[i].fns_hi), i);
- save_item(NAME(m_slots[i].fns), i);
- save_item(NAME(m_slots[i].feedback), i);
- save_item(NAME(m_slots[i].waveform), i);
- save_item(NAME(m_slots[i].accon), i);
- save_item(NAME(m_slots[i].algorithm), i);
- save_item(NAME(m_slots[i].ch0_level), i);
- save_item(NAME(m_slots[i].ch1_level), i);
- save_item(NAME(m_slots[i].ch2_level), i);
- save_item(NAME(m_slots[i].ch3_level), i);
- save_item(NAME(m_slots[i].startaddr), i);
- save_item(NAME(m_slots[i].loopaddr), i);
- save_item(NAME(m_slots[i].endaddr), i);
- save_item(NAME(m_slots[i].altloop), i);
- save_item(NAME(m_slots[i].fs), i);
- save_item(NAME(m_slots[i].srcnote), i);
- save_item(NAME(m_slots[i].srcb), i);
- save_item(NAME(m_slots[i].step), i);
- save_item(NAME(m_slots[i].stepptr), i);
- save_item(NAME(m_slots[i].active), i);
- save_item(NAME(m_slots[i].bits), i);
- save_item(NAME(m_slots[i].volume), i);
- save_item(NAME(m_slots[i].env_state), i);
- save_item(NAME(m_slots[i].env_attack_step), i);
- save_item(NAME(m_slots[i].env_decay1_step), i);
- save_item(NAME(m_slots[i].env_decay2_step), i);
- save_item(NAME(m_slots[i].env_release_step), i);
- save_item(NAME(m_slots[i].feedback_modulation0), i);
- save_item(NAME(m_slots[i].feedback_modulation1), i);
- save_item(NAME(m_slots[i].lfo_phase), i);
- save_item(NAME(m_slots[i].lfo_step), i);
- save_item(NAME(m_slots[i].lfo_amplitude), i);
- }
-
- for (i = 0; i < ARRAY_LENGTH(m_groups); i++)
- {
- save_item(NAME(m_groups[i].sync), i);
- save_item(NAME(m_groups[i].pfm), i);
- }
+ save_item(STRUCT_MEMBER(m_slots, ext_en));
+ save_item(STRUCT_MEMBER(m_slots, ext_out));
+ save_item(STRUCT_MEMBER(m_slots, lfoFreq));
+ save_item(STRUCT_MEMBER(m_slots, pms));
+ save_item(STRUCT_MEMBER(m_slots, ams));
+ save_item(STRUCT_MEMBER(m_slots, detune));
+ save_item(STRUCT_MEMBER(m_slots, multiple));
+ save_item(STRUCT_MEMBER(m_slots, tl));
+ save_item(STRUCT_MEMBER(m_slots, keyscale));
+ save_item(STRUCT_MEMBER(m_slots, ar));
+ save_item(STRUCT_MEMBER(m_slots, decay1rate));
+ save_item(STRUCT_MEMBER(m_slots, decay2rate));
+ save_item(STRUCT_MEMBER(m_slots, decay1lvl));
+ save_item(STRUCT_MEMBER(m_slots, relrate));
+ save_item(STRUCT_MEMBER(m_slots, block));
+ save_item(STRUCT_MEMBER(m_slots, fns_hi));
+ save_item(STRUCT_MEMBER(m_slots, fns));
+ save_item(STRUCT_MEMBER(m_slots, feedback));
+ save_item(STRUCT_MEMBER(m_slots, waveform));
+ save_item(STRUCT_MEMBER(m_slots, accon));
+ save_item(STRUCT_MEMBER(m_slots, algorithm));
+ save_item(STRUCT_MEMBER(m_slots, ch0_level));
+ save_item(STRUCT_MEMBER(m_slots, ch1_level));
+ save_item(STRUCT_MEMBER(m_slots, ch2_level));
+ save_item(STRUCT_MEMBER(m_slots, ch3_level));
+ save_item(STRUCT_MEMBER(m_slots, startaddr));
+ save_item(STRUCT_MEMBER(m_slots, loopaddr));
+ save_item(STRUCT_MEMBER(m_slots, endaddr));
+ save_item(STRUCT_MEMBER(m_slots, altloop));
+ save_item(STRUCT_MEMBER(m_slots, fs));
+ save_item(STRUCT_MEMBER(m_slots, srcnote));
+ save_item(STRUCT_MEMBER(m_slots, srcb));
+ save_item(STRUCT_MEMBER(m_slots, step));
+ save_item(STRUCT_MEMBER(m_slots, stepptr));
+ save_item(STRUCT_MEMBER(m_slots, active));
+ save_item(STRUCT_MEMBER(m_slots, bits));
+ save_item(STRUCT_MEMBER(m_slots, volume));
+ save_item(STRUCT_MEMBER(m_slots, env_state));
+ save_item(STRUCT_MEMBER(m_slots, env_attack_step));
+ save_item(STRUCT_MEMBER(m_slots, env_decay1_step));
+ save_item(STRUCT_MEMBER(m_slots, env_decay2_step));
+ save_item(STRUCT_MEMBER(m_slots, env_release_step));
+ save_item(STRUCT_MEMBER(m_slots, feedback_modulation0));
+ save_item(STRUCT_MEMBER(m_slots, feedback_modulation1));
+ save_item(STRUCT_MEMBER(m_slots, lfo_phase));
+ save_item(STRUCT_MEMBER(m_slots, lfo_step));
+ save_item(STRUCT_MEMBER(m_slots, lfo_amplitude));
+
+ save_item(STRUCT_MEMBER(m_groups, sync));
+ save_item(STRUCT_MEMBER(m_groups, pfm));
save_item(NAME(m_regs_main));
save_item(NAME(m_timerA));
@@ -1748,7 +1743,7 @@ void ymf271_device::device_start()
init_state();
m_mix_buffer.resize(m_master_clock/(384/4));
- m_stream = stream_alloc_legacy(0, 4, m_master_clock/384);
+ m_stream = stream_alloc(0, 4, m_master_clock/384);
}
//-------------------------------------------------
diff --git a/src/devices/sound/ymf271.h b/src/devices/sound/ymf271.h
index 87f06eb8e73..1c628f34cf1 100644
--- a/src/devices/sound/ymf271.h
+++ b/src/devices/sound/ymf271.h
@@ -28,7 +28,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/ymf278b.cpp b/src/devices/sound/ymf278b.cpp
index 7bda7b6b8ef..f9f308a4892 100644
--- a/src/devices/sound/ymf278b.cpp
+++ b/src/devices/sound/ymf278b.cpp
@@ -212,10 +212,10 @@ void ymf278b_device::compute_envelope(YMF278BSlot *slot)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ymf278b_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ymf278b_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i, j;
YMF278BSlot *slot;
@@ -223,14 +223,14 @@ void ymf278b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
int32_t *mixp;
int32_t vl, vr;
- ymf262_update_one(m_ymf262, outputs, samples);
- vl = m_mix_level[m_fm_l];
- vr = m_mix_level[m_fm_r];
- for (i = 0; i < samples; i++)
+ ymf262_update_one(m_ymf262, outputs);
+ stream_buffer::sample_t fvl = stream_buffer::sample_t(m_mix_level[m_fm_l]) * (1.0 / 65536.0);
+ stream_buffer::sample_t fvr = stream_buffer::sample_t(m_mix_level[m_fm_r]) * (1.0 / 65536.0);
+ for (i = 0; i < outputs[0].samples(); i++)
{
// DO2 mixing
- outputs[0][i] = (outputs[0][i] * vl) >> 16;
- outputs[1][i] = (outputs[1][i] * vr) >> 16;
+ outputs[0].put(i, outputs[0].get(i) * fvl);
+ outputs[1].put(i, outputs[1].get(i) * fvr);
}
std::fill(m_mix_buffer.begin(), m_mix_buffer.end(), 0);
@@ -243,7 +243,7 @@ void ymf278b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
{
mixp = &m_mix_buffer[0];
- for (j = 0; j < samples; j++)
+ for (j = 0; j < outputs[0].samples(); j++)
{
if (slot->stepptr >= slot->endaddr)
{
@@ -316,12 +316,12 @@ void ymf278b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
mixp = &m_mix_buffer[0];
vl = m_mix_level[m_pcm_l];
vr = m_mix_level[m_pcm_r];
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
- outputs[0][i] += (*mixp++ * vl) >> 16;
- outputs[1][i] += (*mixp++ * vr) >> 16;
- outputs[4][i] = *mixp++;
- outputs[5][i] = *mixp++;
+ outputs[0].add_int(i, (*mixp++ * vl) >> 16, 32768);
+ outputs[1].add_int(i, (*mixp++ * vr) >> 16, 32768);
+ outputs[4].put_int(i, *mixp++, 32768);
+ outputs[5].put_int(i, *mixp++, 32768);
}
}
@@ -1009,7 +1009,7 @@ void ymf278b_device::device_start()
m_slots[i].num = i;
}
- m_stream = stream_alloc_legacy(0, 6, m_rate);
+ m_stream = stream_alloc(0, 6, m_rate);
m_mix_buffer.resize(m_rate*4,0);
// rate tables
diff --git a/src/devices/sound/ymf278b.h b/src/devices/sound/ymf278b.h
index 03fa9880442..d872ce13e38 100644
--- a/src/devices/sound/ymf278b.h
+++ b/src/devices/sound/ymf278b.h
@@ -29,7 +29,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/ymz280b.cpp b/src/devices/sound/ymz280b.cpp
index 94ef134bd4c..b2836c74967 100644
--- a/src/devices/sound/ymz280b.cpp
+++ b/src/devices/sound/ymz280b.cpp
@@ -412,18 +412,18 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void ymz280b_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ymz280b_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *lacc = outputs[0];
- stream_sample_t *racc = outputs[1];
+ auto &lacc = outputs[0];
+ auto &racc = outputs[1];
int v;
/* clear out the accumulator */
- memset(lacc, 0, samples * sizeof(lacc[0]));
- memset(racc, 0, samples * sizeof(racc[0]));
+ lacc.fill(0);
+ racc.fill(0);
/* loop over voices */
for (v = 0; v < 8; v++)
@@ -432,11 +432,10 @@ void ymz280b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
s16 prev = voice->last_sample;
s16 curr = voice->curr_sample;
s16 *curr_data = m_scratch.get();
- s32 *ldest = lacc;
- s32 *rdest = racc;
+ s32 sampindex = 0;
u32 new_samples, samples_left;
u32 final_pos;
- int remaining = samples;
+ int remaining = lacc.samples();
int lvol = voice->output_left;
int rvol = voice->output_right;
@@ -453,8 +452,9 @@ void ymz280b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
while (remaining > 0 && voice->output_pos < FRAC_ONE)
{
int interp_sample = ((s32(prev) * (FRAC_ONE - voice->output_pos)) + (s32(curr) * voice->output_pos)) >> FRAC_BITS;
- *ldest++ += interp_sample * lvol;
- *rdest++ += interp_sample * rvol;
+ lacc.add_int(sampindex, interp_sample * lvol, 32768 * 256);
+ racc.add_int(sampindex, interp_sample * rvol, 32768 * 256);
+ sampindex++;
voice->output_pos += voice->output_step;
remaining--;
}
@@ -517,8 +517,9 @@ void ymz280b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
while (remaining > 0 && voice->output_pos < FRAC_ONE)
{
int interp_sample = ((s32(prev) * (FRAC_ONE - voice->output_pos)) + (s32(curr) * voice->output_pos)) >> FRAC_BITS;
- *ldest++ += interp_sample * lvol;
- *rdest++ += interp_sample * rvol;
+ lacc.add_int(sampindex, interp_sample * lvol, 32768 * 256);
+ racc.add_int(sampindex, interp_sample * rvol, 32768 * 256);
+ sampindex++;
voice->output_pos += voice->output_step;
remaining--;
}
@@ -536,12 +537,6 @@ void ymz280b_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
voice->last_sample = prev;
voice->curr_sample = curr;
}
-
- for (v = 0; v < samples; v++)
- {
- outputs[0][v] /= 256;
- outputs[1][v] /= 256;
- }
}
@@ -565,7 +560,7 @@ void ymz280b_device::device_start()
}
/* create the stream */
- m_stream = stream_alloc_legacy(0, 2, INTERNAL_SAMPLE_RATE);
+ m_stream = stream_alloc(0, 2, INTERNAL_SAMPLE_RATE);
/* allocate memory */
assert(MAX_SAMPLE_CHUNK < 0x10000);
diff --git a/src/devices/sound/ymz280b.h b/src/devices/sound/ymz280b.h
index ccbcb393bd8..5da3ea46cc3 100644
--- a/src/devices/sound/ymz280b.h
+++ b/src/devices/sound/ymz280b.h
@@ -36,7 +36,7 @@ protected:
virtual void device_clock_changed() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
// device_rom_interface overrides
virtual void rom_bank_updated() override;
diff --git a/src/devices/sound/ymz770.cpp b/src/devices/sound/ymz770.cpp
index 3934c6ac6dd..9d489d8a89d 100644
--- a/src/devices/sound/ymz770.cpp
+++ b/src/devices/sound/ymz770.cpp
@@ -77,7 +77,7 @@ ymz770_device::ymz770_device(const machine_config &mconfig, device_type type, co
void ymz770_device::device_start()
{
// create the stream
- m_stream = stream_alloc_legacy(0, 2, m_sclock);
+ m_stream = stream_alloc(0, 2, m_sclock);
for (auto & channel : m_channels)
{
@@ -178,18 +178,16 @@ void ymz770_device::device_reset()
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void ymz770_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void ymz770_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outL, *outR;
+ auto &outL = outputs[0];
+ auto &outR = outputs[1];
- outL = outputs[0];
- outR = outputs[1];
-
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outL.samples(); i++)
{
sequencer();
@@ -282,8 +280,8 @@ retry:
}
if (m_mute)
mixr = mixl = 0;
- outL[i] = mixl;
- outR[i] = mixr;
+ outL.put_int(i, mixl, 32768);
+ outR.put_int(i, mixr, 32768);
}
}
diff --git a/src/devices/sound/ymz770.h b/src/devices/sound/ymz770.h
index ade24f61501..6c87cef8de4 100644
--- a/src/devices/sound/ymz770.h
+++ b/src/devices/sound/ymz770.h
@@ -33,7 +33,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void internal_reg_write(uint8_t reg, uint8_t data);
virtual uint32_t get_phrase_offs(int phrase) { return m_rom[(4 * phrase) + 1] << 16 | m_rom[(4 * phrase) + 2] << 8 | m_rom[(4 * phrase) + 3]; };
diff --git a/src/devices/sound/zsg2.cpp b/src/devices/sound/zsg2.cpp
index b964bce5f14..2fa01cfb3a5 100644
--- a/src/devices/sound/zsg2.cpp
+++ b/src/devices/sound/zsg2.cpp
@@ -134,7 +134,7 @@ void zsg2_device::device_start()
memset(&m_chan, 0, sizeof(m_chan));
- m_stream = stream_alloc_legacy(0, 4, clock() / 768);
+ m_stream = stream_alloc(0, 4, clock() / 768);
m_mem_blocks = m_mem_base.length();
m_mem_copy = make_unique_clear<uint32_t[]>(m_mem_blocks);
@@ -280,12 +280,12 @@ void zsg2_device::filter_samples(zchan *ch)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void zsg2_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void zsg2_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
int32_t mix[4] = {};
@@ -355,8 +355,7 @@ void zsg2_device::sound_stream_update_legacy(sound_stream &stream, stream_sample
}
for(int output=0; output<4; output++)
- outputs[output][i] = std::min<int32_t>(std::max<int32_t>(mix[output], -32768), 32767);
-
+ outputs[output].put_int_clamp(i, mix[output], 32768);
}
m_sample_count++;
}
diff --git a/src/devices/sound/zsg2.h b/src/devices/sound/zsg2.h
index 592cbf83787..0239f6ff03d 100644
--- a/src/devices/sound/zsg2.h
+++ b/src/devices/sound/zsg2.h
@@ -29,7 +29,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
const uint16_t STATUS_ACTIVE = 0x8000;
diff --git a/src/devices/video/315_5124.cpp b/src/devices/video/315_5124.cpp
index 4e7d04bcab6..9a3a0f8c339 100644
--- a/src/devices/video/315_5124.cpp
+++ b/src/devices/video/315_5124.cpp
@@ -1723,8 +1723,8 @@ void sega315_5124_device::draw_scanline(int pixel_offset_x, int pixel_plot_y, in
void sega315_5124_device::blit_scanline(int *line_buffer, int *priority_selected, int pixel_offset_x, int pixel_plot_y, int line)
{
- u32 *p_bitmap = &m_tmpbitmap.pix32(pixel_plot_y + line, pixel_offset_x);
- u8 *p_y1 = &m_y1_bitmap.pix8(pixel_plot_y + line, pixel_offset_x);
+ u32 *const p_bitmap = &m_tmpbitmap.pix(pixel_plot_y + line, pixel_offset_x);
+ u8 *const p_y1 = &m_y1_bitmap.pix(pixel_plot_y + line, pixel_offset_x);
int x = 0;
if (m_vdp_mode == 4 && BIT(m_reg[0x00], 5))
@@ -1755,8 +1755,8 @@ void sega315_5377_device::blit_scanline(int *line_buffer, int *priority_selected
}
else
{
- u32 *p_bitmap = &m_tmpbitmap.pix32(pixel_plot_y + line, pixel_offset_x);
- u8 *p_y1 = &m_y1_bitmap.pix8(pixel_plot_y + line, pixel_offset_x);
+ u32 *const p_bitmap = &m_tmpbitmap.pix(pixel_plot_y + line, pixel_offset_x);
+ u8 *const p_y1 = &m_y1_bitmap.pix(pixel_plot_y + line, pixel_offset_x);
int x = 0;
/* border on left side of the GG active screen */
diff --git a/src/devices/video/315_5313.cpp b/src/devices/video/315_5313.cpp
index 77bd8a9094a..4360a4e78a1 100644
--- a/src/devices/video/315_5313.cpp
+++ b/src/devices/video/315_5313.cpp
@@ -2108,7 +2108,7 @@ void sega315_5313_device::render_videobuffer_to_screenbuffer(int scanline)
if (scanline >= m_render_bitmap->height()) // safety, shouldn't happen now we allocate a fixed amount tho
return;
- lineptr = &m_render_bitmap->pix32(scanline);
+ lineptr = &m_render_bitmap->pix(scanline);
}
else
lineptr = m_render_line.get();
diff --git a/src/devices/video/cdp1861.cpp b/src/devices/video/cdp1861.cpp
index 6a79087990d..03bcd3e0e90 100644
--- a/src/devices/video/cdp1861.cpp
+++ b/src/devices/video/cdp1861.cpp
@@ -248,12 +248,11 @@ void cdp1861_device::dma_w(uint8_t data)
{
int sx = screen().hpos() + 4;
int y = screen().vpos();
- int x;
- for (x = 0; x < 8; x++)
+ for (int x = 0; x < 8; x++)
{
pen_t color = BIT(data, 7) ? rgb_t::white() : rgb_t::black();
- m_bitmap.pix32(y, sx + x) = color;
+ m_bitmap.pix(y, sx + x) = color;
data <<= 1;
}
}
diff --git a/src/devices/video/cdp1862.cpp b/src/devices/video/cdp1862.cpp
index 977615955fe..66fa8d9e684 100644
--- a/src/devices/video/cdp1862.cpp
+++ b/src/devices/video/cdp1862.cpp
@@ -131,7 +131,6 @@ void cdp1862_device::dma_w(uint8_t data)
int rd = 1, bd = 1, gd = 1;
int sx = screen().hpos() + 4;
int y = screen().vpos();
- int x;
if (!m_con)
{
@@ -140,7 +139,7 @@ void cdp1862_device::dma_w(uint8_t data)
gd = m_read_gd();
}
- for (x = 0; x < 8; x++)
+ for (int x = 0; x < 8; x++)
{
int color = CDP1862_BACKGROUND_COLOR_SEQUENCE[m_bgcolor] + 8;
@@ -149,7 +148,7 @@ void cdp1862_device::dma_w(uint8_t data)
color = (gd << 2) | (bd << 1) | rd;
}
- m_bitmap.pix32(y, sx + x) = m_palette[color];
+ m_bitmap.pix(y, sx + x) = m_palette[color];
data <<= 1;
}
diff --git a/src/devices/video/cesblit.cpp b/src/devices/video/cesblit.cpp
index 4cea7aef4f5..7e0e6a2085b 100644
--- a/src/devices/video/cesblit.cpp
+++ b/src/devices/video/cesblit.cpp
@@ -213,8 +213,6 @@ void cesblit_device::do_blit()
// Draw
bitmap_ind16 &bitmap = m_bitmap[layer][buffer];
- int x,y;
- uint16_t pen;
switch (mode & 0x20)
{
@@ -227,17 +225,17 @@ void cesblit_device::do_blit()
uint8_t dst_pen = (m_color >> 8) & 0xff;
uint8_t src_pen = (m_color >> 0) & 0xff;
- for (y = y0; y != y1; y += dy)
+ for (int y = y0; y != y1; y += dy)
{
- for (x = x0; x != x1; x += dx)
+ for (int x = x0; x != x1; x += dx)
{
- pen = m_space->read_byte(addr);
+ uint16_t pen = m_space->read_byte(addr);
if (pen == src_pen)
pen = dst_pen;
if (pen != 0xff)
- bitmap.pix16((sy + y) & 0x1ff, (sx + x) & 0x1ff) = pen + color;
+ bitmap.pix((sy + y) & 0x1ff, (sx + x) & 0x1ff) = pen + color;
++addr;
}
@@ -247,14 +245,14 @@ void cesblit_device::do_blit()
{
// copy from ROM as is
- for (y = y0; y != y1; y += dy)
+ for (int y = y0; y != y1; y += dy)
{
- for (x = x0; x != x1; x += dx)
+ for (int x = x0; x != x1; x += dx)
{
- pen = m_space->read_byte(addr);
+ uint16_t pen = m_space->read_byte(addr);
if (pen != 0xff)
- bitmap.pix16((sy + y) & 0x1ff, (sx + x) & 0x1ff) = pen + color;
+ bitmap.pix((sy + y) & 0x1ff, (sx + x) & 0x1ff) = pen + color;
++addr;
}
@@ -263,16 +261,18 @@ void cesblit_device::do_blit()
break;
case 0x20: // solid fill
- pen = ((m_addr_hi >> 8) & 0xff) + color;
+ {
+ uint16_t pen = ((m_addr_hi >> 8) & 0xff) + color;
- if ((pen & 0xff) == 0xff)
- pen = 0xff;
+ if ((pen & 0xff) == 0xff)
+ pen = 0xff;
- for (y = y0; y != y1; y += dy)
- {
- for (x = x0; x != x1; x += dx)
+ for (int y = y0; y != y1; y += dy)
{
- bitmap.pix16((sy + y) & 0x1ff, (sx + x) & 0x1ff) = pen;
+ for (int x = x0; x != x1; x += dx)
+ {
+ bitmap.pix((sy + y) & 0x1ff, (sx + x) & 0x1ff) = pen;
+ }
}
}
break;
diff --git a/src/devices/video/clgd542x.cpp b/src/devices/video/clgd542x.cpp
index ace2e7a4820..eff9f5473c8 100644
--- a/src/devices/video/clgd542x.cpp
+++ b/src/devices/video/clgd542x.cpp
@@ -134,7 +134,6 @@ void cirrus_gd5428_device::device_reset()
uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,bit;
uint32_t ptr = (vga.svga_intf.vram_size - 0x4000); // cursor patterns are stored in the last 16kB of VRAM
svga_device::screen_update(screen, bitmap, cliprect);
@@ -145,11 +144,11 @@ uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32
if(m_cursor_attr & 0x04) // 64x64
{
ptr += ((m_cursor_addr & 0x3c) * 256);
- for(y=0;y<64;y++)
+ for(int y=0;y<64;y++)
{
- for(x=0;x<64;x+=8)
+ for(int x=0;x<64;x+=8)
{
- for(bit=0;bit<8;bit++)
+ for(int bit=0;bit<8;bit++)
{
uint8_t pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit);
uint8_t pixel2 = vga.memory[(ptr+512) % vga.svga_intf.vram_size] >> (7-bit);
@@ -159,13 +158,13 @@ uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32
case 0: // transparent - do nothing
break;
case 1: // background
- bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 16) | (m_ext_palette[0].green << 8) | (m_ext_palette[0].blue);
+ bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 16) | (m_ext_palette[0].green << 8) | (m_ext_palette[0].blue);
break;
case 2: // XOR
- bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit);
+ bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit);
break;
case 3: // foreground
- bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 16) | (m_ext_palette[15].green << 8) | (m_ext_palette[15].blue);
+ bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 16) | (m_ext_palette[15].green << 8) | (m_ext_palette[15].blue);
break;
}
}
@@ -175,11 +174,11 @@ uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32
else
{
ptr += ((m_cursor_addr & 0x3f) * 256);
- for(y=0;y<32;y++)
+ for(int y=0;y<32;y++)
{
- for(x=0;x<32;x+=8)
+ for(int x=0;x<32;x+=8)
{
- for(bit=0;bit<8;bit++)
+ for(int bit=0;bit<8;bit++)
{
uint8_t pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit);
uint8_t pixel2 = vga.memory[(ptr+128) % vga.svga_intf.vram_size] >> (7-bit);
@@ -189,13 +188,13 @@ uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32
case 0: // transparent - do nothing
break;
case 1: // background
- bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 18) | (m_ext_palette[0].green << 10) | (m_ext_palette[0].blue << 2);
+ bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 18) | (m_ext_palette[0].green << 10) | (m_ext_palette[0].blue << 2);
break;
case 2: // XOR
- bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit);
+ bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit);
break;
case 3: // foreground
- bitmap.pix32(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 18) | (m_ext_palette[15].green << 10) | (m_ext_palette[15].blue << 2);
+ bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 18) | (m_ext_palette[15].green << 10) | (m_ext_palette[15].blue << 2);
break;
}
}
diff --git a/src/devices/video/ef9340_1.cpp b/src/devices/video/ef9340_1.cpp
index 9cc05ab747b..f58106fb5c4 100644
--- a/src/devices/video/ef9340_1.cpp
+++ b/src/devices/video/ef9340_1.cpp
@@ -16,7 +16,6 @@ This is implemented with a callback. The datasheet explains how to hook up
TODO:
- busy state (right now it is immediate)
- internal display timing (on g7400, most of it is done externally)
-- read slice from internal ROM
- window boxing
- Y zoom
@@ -35,7 +34,7 @@ TODO:
DEFINE_DEVICE_TYPE(EF9340_1, ef9340_1_device, "ef9340_1", "Thomson EF9340+EF9341")
-ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, EF9340_1, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_charset(*this, "ef9340_1")
@@ -46,7 +45,7 @@ ef9340_1_device::ef9340_1_device(const machine_config &mconfig, const char *tag,
ROM_START( ef9340_1 )
- ROM_REGION( 0xA00, "ef9340_1", 0 )
+ ROM_REGION( 0xa00, "ef9340_1", 0 )
ROM_LOAD( "charset_ef9340_1.rom", 0x0000, 0x0a00, BAD_DUMP CRC(8de85988) SHA1(f8e3892234da6626eb4302e171179ada5a51fca8) ) // taken from datasheet
ROM_END
@@ -66,10 +65,10 @@ void ef9340_1_device::device_start()
screen().register_screen_bitmap(m_tmp_bitmap);
m_line_timer = timer_alloc(TIMER_LINE);
- m_line_timer->adjust( screen().time_until_pos(0, 0), 0, screen().scan_period() );
+ m_line_timer->adjust(screen().time_until_pos(0, 0), 0, screen().scan_period());
m_blink_timer = timer_alloc(TIMER_BLINK);
- m_blink_timer->adjust( screen().time_until_pos(0, 0), 0, screen().frame_period() );
+ m_blink_timer->adjust(screen().time_until_pos(0, 0), 0, screen().frame_period());
// zerofill
m_ef9341.TA = 0;
@@ -109,7 +108,7 @@ void ef9340_1_device::device_start()
void ef9340_1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- switch ( id )
+ switch (id)
{
case TIMER_LINE:
ef9340_scanline(screen().vpos());
@@ -129,27 +128,27 @@ void ef9340_1_device::device_timer(emu_timer &timer, device_timer_id id, int par
}
-uint16_t ef9340_1_device::ef9340_get_c_addr(uint8_t x, uint8_t y)
+u16 ef9340_1_device::ef9340_get_c_addr(u8 x, u8 y)
{
- if ( ( y & 0x18 ) == 0x18 )
+ if ((y & 0x18) == 0x18)
{
- return 0x318 | ( ( x & 0x38 ) << 2 ) | ( x & 0x07 );
+ return 0x318 | ((x & 0x38) << 2) | (x & 0x07);
}
- if ( x & 0x20 )
+ if (x & 0x20)
{
- return 0x300 | ( ( y & 0x07 ) << 5 ) | ( y & 0x18 ) | ( x & 0x07 );
+ return 0x300 | ((y & 0x07) << 5) | (y & 0x18) | (x & 0x07);
}
- return ( y & 0x1f ) << 5 | ( x & 0x1f );
+ return (y & 0x1f) << 5 | (x & 0x1f);
}
void ef9340_1_device::ef9340_inc_c()
{
m_ef9340.X++;
- if ( m_ef9340.X == 40 || m_ef9340.X == 48 || m_ef9340.X == 56 || m_ef9340.X == 64 )
+ if (m_ef9340.X == 40 || m_ef9340.X == 48 || m_ef9340.X == 56 || m_ef9340.X == 64)
{
- m_ef9340.Y = ( m_ef9340.Y + 1 ) & 0x1f;
- if ( m_ef9340.Y == 24 )
+ m_ef9340.Y = (m_ef9340.Y + 1) & 0x1f;
+ if (m_ef9340.Y == 24)
{
m_ef9340.Y = 0;
}
@@ -158,27 +157,27 @@ void ef9340_1_device::ef9340_inc_c()
}
-void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data )
+void ef9340_1_device::ef9341_write(u8 command, u8 b, u8 data)
{
- LOG("ef9341 %s write, t%s, data %02X\n", command ? "command" : "data", b ? "B" : "A", data );
+ LOG("ef9341 %s write, t%s, data %02X\n", command ? "command" : "data", b ? "B" : "A", data);
- if ( command )
+ if (command)
{
- if ( b )
+ if (b)
{
m_ef9341.TB = data;
m_ef9341.busy = true;
- switch( m_ef9341.TB & 0xE0 )
+ switch (m_ef9341.TB & 0xe0)
{
case 0x00: /* Begin row */
m_ef9340.X = 0;
- m_ef9340.Y = m_ef9341.TA & 0x1F;
+ m_ef9340.Y = m_ef9341.TA & 0x1f;
break;
case 0x20: /* Load Y */
- m_ef9340.Y = m_ef9341.TA & 0x1F;
+ m_ef9340.Y = m_ef9341.TA & 0x1f;
break;
case 0x40: /* Load X */
- m_ef9340.X = m_ef9341.TA & 0x3F;
+ m_ef9340.X = m_ef9341.TA & 0x3f;
break;
case 0x60: /* INC C */
ef9340_inc_c();
@@ -186,13 +185,13 @@ void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data )
case 0x80: /* Load M */
m_ef9340.M = m_ef9341.TA;
break;
- case 0xA0: /* Load R */
+ case 0xa0: /* Load R */
m_ef9340.R = m_ef9341.TA;
break;
- case 0xC0: /* Load Y0 */
- m_ef9340.Y0 = m_ef9341.TA & 0x3F;
+ case 0xc0: /* Load Y0 */
+ m_ef9340.Y0 = m_ef9341.TA & 0x3f;
break;
- case 0xE0: /* Not interpreted */
+ case 0xe0: /* Not interpreted */
break;
}
m_ef9341.busy = false;
@@ -204,13 +203,13 @@ void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data )
}
else
{
- if ( b )
+ if (b)
{
- uint16_t addr = ef9340_get_c_addr( m_ef9340.X, m_ef9340.Y ) & 0x3ff;
+ u16 addr = ef9340_get_c_addr(m_ef9340.X, m_ef9340.Y) & 0x3ff;
m_ef9341.TB = data;
m_ef9341.busy = true;
- switch ( m_ef9340.M & 0xE0 )
+ switch (m_ef9340.M & 0xe0)
{
case 0x00: /* Write */
m_ram_a[addr] = m_ef9341.TA;
@@ -225,15 +224,15 @@ void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data )
case 0x80: /* Write slice */
{
- uint8_t a = m_ram_a[addr];
- uint8_t b = m_ram_b[addr];
- uint8_t slice = m_ef9340.M & 0x0f;
+ u8 a = m_ram_a[addr];
+ u8 b = m_ram_b[addr];
+ u8 slice = m_ef9340.M & 0x0f;
if (b >= 0xa0)
m_write_exram(a << 12 | b << 4 | slice, m_ef9341.TA);
// Increment slice number
- m_ef9340.M = ( m_ef9340.M & 0xf0) | ( ( slice + 1 ) % 10 );
+ m_ef9340.M = (m_ef9340.M & 0xf0) | ((slice + 1) % 10);
}
break;
@@ -250,15 +249,15 @@ void ef9340_1_device::ef9341_write( uint8_t command, uint8_t b, uint8_t data )
}
-uint8_t ef9340_1_device::ef9341_read( uint8_t command, uint8_t b )
+u8 ef9340_1_device::ef9341_read(u8 command, u8 b)
{
- uint8_t data;
+ u8 data;
- LOG("ef9341 %s read, t%s\n", command ? "command" : "data", b ? "B" : "A" );
+ LOG("ef9341 %s read, t%s\n", command ? "command" : "data", b ? "B" : "A");
- if ( command )
+ if (command)
{
- if ( b )
+ if (b)
{
data = 0;
}
@@ -269,13 +268,13 @@ uint8_t ef9340_1_device::ef9341_read( uint8_t command, uint8_t b )
}
else
{
- if ( b )
+ if (b)
{
- uint16_t addr = ef9340_get_c_addr( m_ef9340.X, m_ef9340.Y ) & 0x3ff;
+ u16 addr = ef9340_get_c_addr(m_ef9340.X, m_ef9340.Y) & 0x3ff;
data = m_ef9341.TB;
m_ef9341.busy = true;
- switch ( m_ef9340.M & 0xE0 )
+ switch (m_ef9340.M & 0xe0)
{
case 0x20: /* Read */
m_ef9341.TA = m_ram_a[addr];
@@ -288,22 +287,22 @@ uint8_t ef9340_1_device::ef9341_read( uint8_t command, uint8_t b )
m_ef9341.TB = m_ram_b[addr];
break;
- case 0xA0: /* Read slice */
+ case 0xa0: /* Read slice */
{
- uint8_t a = m_ram_a[addr];
- uint8_t b = m_ram_b[addr];
- uint8_t slice = m_ef9340.M & 0x0f;
+ u8 a = m_ram_a[addr];
+ u8 b = m_ram_b[addr];
+ u8 slice = m_ef9340.M & 0x0f;
m_ef9341.TA = 0xff;
m_ef9341.TB = 0xff;
if (b >= 0xa0)
m_ef9341.TA = m_read_exram(a << 12 | b << 4 | slice);
- else
- logerror("ef9341 read slice from internal\n");
+ else if (b < 0x80 && slice < 10)
+ m_ef9341.TA = m_charset[(((a & 0x80) | (b & 0x7f)) * 10) + slice];
// Increment slice number
- m_ef9340.M = ( m_ef9340.M & 0xf0) | ( ( slice + 1 ) % 10 );
+ m_ef9340.M = (m_ef9340.M & 0xf0) | ((slice + 1) % 10);
}
break;
@@ -338,14 +337,14 @@ void ef9340_1_device::ef9340_scanline(int vpos)
if (m_ef9340.R & 0x01 && vpos < max_vpos)
{
int y_row = 0;
- uint16_t char_data = 0x00;
- uint8_t fg = 0;
- uint8_t bg = 0;
+ u16 char_data = 0x00;
+ u8 fg = 0;
+ u8 bg = 0;
bool underline = false;
bool blank = false;
bool w_parity = false;
- if ( vpos < 10 )
+ if (vpos < 10)
{
// Service row
if (m_ef9340.R & 0x08)
@@ -357,7 +356,7 @@ void ef9340_1_device::ef9340_scanline(int vpos)
{
// Service row is disabled
for (int i = 0; i < 40 * 8; i++)
- m_tmp_bitmap.pix16(m_offset_y + vpos, m_offset_x + i) = 8;
+ m_tmp_bitmap.pix(m_offset_y + vpos, m_offset_x + i) = 8;
return;
}
}
@@ -370,9 +369,9 @@ void ef9340_1_device::ef9340_scanline(int vpos)
for (int x = 0; x < 40; x++)
{
int s = slice;
- uint16_t addr = ef9340_get_c_addr(x, y_row);
- uint8_t a = m_ram_a[addr];
- uint8_t b = m_ram_b[addr];
+ u16 addr = ef9340_get_c_addr(x, y_row);
+ u8 a = m_ram_a[addr];
+ u8 b = m_ram_b[addr];
bool blink = m_ef9340.R & 0x80 && m_ef9340.blink;
bool cursor = m_ef9340.R & 0x10 && x == m_ef9340.X && y_row == m_ef9340.Y;
bool invert = cursor && !blink;
@@ -465,8 +464,8 @@ void ef9340_1_device::ef9340_scanline(int vpos)
for (int i = 0; i < 8; i++)
{
- uint16_t d = blank ? 0 : (char_data & 1) ? fg : bg;
- m_tmp_bitmap.pix16(m_offset_y + vpos, m_offset_x + x*8 + i) = d | 8;
+ u16 d = blank ? 0 : (char_data & 1) ? fg : bg;
+ m_tmp_bitmap.pix(m_offset_y + vpos, m_offset_x + x*8 + i) = d | 8;
char_data >>= 1;
}
@@ -480,7 +479,7 @@ void ef9340_1_device::ef9340_scanline(int vpos)
else
{
for (int i = 0; i < 40 * 8; i++)
- m_tmp_bitmap.pix16(m_offset_y + vpos, m_offset_x + i) = 0;
+ m_tmp_bitmap.pix(m_offset_y + vpos, m_offset_x + i) = 0;
}
// determine next h parity
@@ -494,12 +493,12 @@ void ef9340_1_device::ef9340_scanline(int vpos)
}
-uint32_t ef9340_1_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+u32 ef9340_1_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// note: palette d3 is transparency (datasheet calls it "I"), this handler masks it off
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
- bitmap.pix16(y, x) = m_tmp_bitmap.pix16(y, x) & 7;
+ bitmap.pix(y, x) = m_tmp_bitmap.pix(y, x) & 7;
return 0;
}
diff --git a/src/devices/video/ef9340_1.h b/src/devices/video/ef9340_1.h
index 61d1eb6d584..2d9a6671d27 100644
--- a/src/devices/video/ef9340_1.h
+++ b/src/devices/video/ef9340_1.h
@@ -18,7 +18,7 @@ class ef9340_1_device : public device_t,
public:
// construction/destruction
template <typename T>
- ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&screen_tag)
+ ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, T &&screen_tag)
: ef9340_1_device(mconfig, tag, owner, clock)
{
set_screen(std::forward<T>(screen_tag));
@@ -29,13 +29,13 @@ public:
auto write_exram() { return m_write_exram.bind(); } // ADR0-ADR3 in a0-a3, B in a4-a11, A in a12-a19
auto read_exram() { return m_read_exram.bind(); } // "
- ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ ef9340_1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
inline bitmap_ind16 *get_bitmap() { return &m_tmp_bitmap; }
- uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- void ef9341_write( uint8_t command, uint8_t b, uint8_t data );
- uint8_t ef9341_read( uint8_t command, uint8_t b );
+ void ef9341_write(u8 command, u8 b, u8 data);
+ u8 ef9341_read(u8 command, u8 b);
protected:
// device-level overrides
@@ -43,7 +43,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual const tiny_rom_entry *device_rom_region() const override;
- inline uint16_t ef9340_get_c_addr(uint8_t x, uint8_t y);
+ inline u16 ef9340_get_c_addr(u8 x, u8 y);
inline void ef9340_inc_c();
void ef9340_scanline(int vpos);
@@ -55,7 +55,7 @@ protected:
emu_timer *m_line_timer;
emu_timer *m_blink_timer;
- required_region_ptr<uint8_t> m_charset;
+ required_region_ptr<u8> m_charset;
bitmap_ind16 m_tmp_bitmap;
@@ -64,25 +64,25 @@ protected:
struct
{
- uint8_t TA;
- uint8_t TB;
+ u8 TA;
+ u8 TB;
bool busy;
} m_ef9341;
struct
{
- uint8_t X;
- uint8_t Y;
- uint8_t Y0;
- uint8_t R;
- uint8_t M;
+ u8 X;
+ u8 Y;
+ u8 Y0;
+ u8 R;
+ u8 M;
bool blink;
int blink_prescaler;
bool h_parity;
} m_ef9340;
- uint8_t m_ram_a[0x400];
- uint8_t m_ram_b[0x400];
+ u8 m_ram_a[0x400];
+ u8 m_ram_b[0x400];
devcb_write8 m_write_exram;
devcb_read8 m_read_exram;
diff --git a/src/devices/video/ef9345.cpp b/src/devices/video/ef9345.cpp
index 74aa3334c1c..4b8907d0da7 100644
--- a/src/devices/video/ef9345.cpp
+++ b/src/devices/video/ef9345.cpp
@@ -225,7 +225,7 @@ void ef9345_device::draw_char_40(uint8_t *c, uint16_t x, uint16_t y)
for(int i = 0; i < scan_ysize; i++)
for(int j = 0; j < scan_xsize; j++)
- m_screen_out.pix32(y * 10 + i, x * 8 + j) = palette[c[8 * i + j] & 0x07];
+ m_screen_out.pix(y * 10 + i, x * 8 + j) = palette[c[8 * i + j] & 0x07];
}
// draw a char in 80 char line mode
@@ -237,7 +237,7 @@ void ef9345_device::draw_char_80(uint8_t *c, uint16_t x, uint16_t y)
for(int i = 0; i < scan_ysize; i++)
for(int j = 0; j < scan_xsize; j++)
- m_screen_out.pix32(y * 10 + i, x * 6 + j) = palette[c[6 * i + j] & 0x07];
+ m_screen_out.pix(y * 10 + i, x * 6 + j) = palette[c[6 * i + j] & 0x07];
}
diff --git a/src/devices/video/ef9364.cpp b/src/devices/video/ef9364.cpp
index 858b7309ca6..cef0a33664e 100644
--- a/src/devices/video/ef9364.cpp
+++ b/src/devices/video/ef9364.cpp
@@ -178,30 +178,27 @@ void ef9364_device::draw_border(uint16_t line)
uint32_t ef9364_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,r;
- unsigned char c;
-
- for( r = 0 ; r < NB_OF_ROWS ; r++ )
+ for( int r = 0 ; r < NB_OF_ROWS ; r++ )
{
- for( y = 0 ; y < 8 ; y++ )
+ for( int y = 0 ; y < 8 ; y++ )
{
- for( x = 0 ; x < NB_OF_COLUMNS * 8 ; x++ )
+ for( int x = 0 ; x < NB_OF_COLUMNS * 8 ; x++ )
{
if( ( ( x >> 3 ) != x_curs_pos ) || ( r != y_curs_pos ) || !cursor_state)
{
- c = m_textram->read_byte( ( r * NB_OF_COLUMNS ) + ( x>>3 ) );
+ unsigned char c = m_textram->read_byte( ( r * NB_OF_COLUMNS ) + ( x>>3 ) );
if( m_charset[((c&0x7F)<<3) + y] & (0x80>>(x&7)) )
- m_screen_out.pix32((r*12)+y, x) = palette[1];
+ m_screen_out.pix((r*12)+y, x) = palette[1];
else
- m_screen_out.pix32((r*12)+y, x) = palette[0];
+ m_screen_out.pix((r*12)+y, x) = palette[0];
}
else
{
if(y != 7)
- m_screen_out.pix32((r*12)+y, x) = palette[0];
+ m_screen_out.pix((r*12)+y, x) = palette[0];
else
- m_screen_out.pix32((r*12)+y, x) = palette[1];
+ m_screen_out.pix((r*12)+y, x) = palette[1];
}
}
}
diff --git a/src/devices/video/ef9365.cpp b/src/devices/video/ef9365.cpp
index a24783298d1..7697e6885e6 100644
--- a/src/devices/video/ef9365.cpp
+++ b/src/devices/video/ef9365.cpp
@@ -1156,18 +1156,15 @@ void ef9365_device::ef9365_exec(uint8_t cmd)
uint32_t ef9365_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int i,j,ptr,p;
- unsigned char color_index;
-
- for(j=0;j<bitplane_yres;j++)
+ for(int j=0;j<bitplane_yres;j++)
{
- for(i=0;i<bitplane_xres;i++)
+ for(int i=0;i<bitplane_xres;i++)
{
- color_index = 0x00;
+ unsigned char color_index = 0x00;
- ptr = ( bitplane_xres * j ) + i;
+ int ptr = ( bitplane_xres * j ) + i;
- for( p = 0; p < nb_of_bitplanes; p++)
+ for(int p = 0; p < nb_of_bitplanes; p++)
{
if( m_videoram->read_byte( (BITPLANE_MAX_SIZE*p) + (ptr>>3)) & (0x80>>(ptr&7)))
{
@@ -1175,7 +1172,7 @@ uint32_t ef9365_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
}
}
- m_screen_out.pix32(j, i) = m_palette->pen( color_index );
+ m_screen_out.pix(j, i) = m_palette->pen( color_index );
}
}
diff --git a/src/devices/video/fixfreq.cpp b/src/devices/video/fixfreq.cpp
index 3810dc76a76..5de27dc0b08 100644
--- a/src/devices/video/fixfreq.cpp
+++ b/src/devices/video/fixfreq.cpp
@@ -14,10 +14,11 @@
***************************************************************************/
#include "emu.h"
-#include "ui/uimain.h"
-#include "rendutil.h"
#include "fixfreq.h"
+#include "render.h"
+#include "ui/uimain.h"
+
// for quick and dirty debugging
#define VERBOSE 0
#define LOG_OUTPUT_STREAM std::cerr
diff --git a/src/devices/video/gb_lcd.cpp b/src/devices/video/gb_lcd.cpp
index 4f02d39bfab..06cceeca7b0 100644
--- a/src/devices/video/gb_lcd.cpp
+++ b/src/devices/video/gb_lcd.cpp
@@ -671,7 +671,7 @@ void cgb_ppu_device::device_reset()
inline void dmg_ppu_device::plot_pixel(int x, int y, uint16_t color)
{
- m_bitmap.pix16(y, x) = color;
+ m_bitmap.pix(y, x) = color;
}
diff --git a/src/devices/video/gba_lcd.cpp b/src/devices/video/gba_lcd.cpp
index ab71569a9fe..e3e46b5ceae 100644
--- a/src/devices/video/gba_lcd.cpp
+++ b/src/devices/video/gba_lcd.cpp
@@ -267,7 +267,7 @@ inline void gba_lcd_device::update_mask(uint8_t* mask, int y)
void gba_lcd_device::draw_scanline(int y)
{
- uint16_t *scanline = &m_bitmap.pix16(y);
+ uint16_t *const scanline = &m_bitmap.pix(y);
if (is_set(dispcnt::forced_blank))
{
diff --git a/src/devices/video/gf4500.cpp b/src/devices/video/gf4500.cpp
index e8c35e7ff25..b703e7cb8c3 100644
--- a/src/devices/video/gf4500.cpp
+++ b/src/devices/video/gf4500.cpp
@@ -89,12 +89,11 @@ static rgb_t gf4500_get_color_16( uint16_t data )
uint32_t gf4500_device::screen_update(screen_device &device, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint16_t *vram = (uint16_t *)(m_data.get() + GF4500_FRAMEBUF_OFFSET / 4);
- int x, y;
- for (y = 0; y < 240; y++)
+ uint16_t const *vram = (uint16_t *)(m_data.get() + GF4500_FRAMEBUF_OFFSET / 4);
+ for (int y = 0; y < 240; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
- for (x = 0; x < 320; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 320; x++)
{
*scanline++ = gf4500_get_color_16(*vram++);
}
diff --git a/src/devices/video/hd44102.cpp b/src/devices/video/hd44102.cpp
index 3b05f1e5e69..1bb8cbf5a4d 100644
--- a/src/devices/video/hd44102.cpp
+++ b/src/devices/video/hd44102.cpp
@@ -268,7 +268,7 @@ uint32_t hd44102_device::screen_update(screen_device &screen, bitmap_ind16 &bitm
{
int color = (m_status & STATUS_DISPLAY_OFF) ? 0 : BIT(data, z % 8);
- bitmap.pix16(sy, sx) = color;
+ bitmap.pix(sy, sx) = color;
}
z++;
diff --git a/src/devices/video/hd44352.cpp b/src/devices/video/hd44352.cpp
index 7fa4b53f1d0..1ca378723f3 100644
--- a/src/devices/video/hd44352.cpp
+++ b/src/devices/video/hd44352.cpp
@@ -152,7 +152,7 @@ uint32_t hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitm
uint8_t d = compute_newval((m_cursor_status>>5) & 0x07, m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48], m_cursor[c]);
for (int b=0; b<8; b++)
{
- bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
+ bitmap.pix(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
}
}
}
@@ -163,7 +163,7 @@ uint32_t hd44352_device::screen_update(screen_device &screen, bitmap_ind16 &bitm
uint8_t d = m_video_ram[a][py*16*cw + px*cw + c + m_scroll * 48];
for (int b=0; b<8; b++)
{
- bitmap.pix16(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
+ bitmap.pix(py*8 + b, a*cw*16 + px*cw + c) = BIT(d, 7-b);
}
}
}
diff --git a/src/devices/video/hd44780.cpp b/src/devices/video/hd44780.cpp
index 7abf8e0a979..8d6db247ba7 100644
--- a/src/devices/video/hd44780.cpp
+++ b/src/devices/video/hd44780.cpp
@@ -274,7 +274,7 @@ inline void hd44780_device::pixel_update(bitmap_ind16 &bitmap, u8 line, u8 pos,
if (m_lines <= 2)
{
if (pos < m_chars)
- bitmap.pix16(line * (line_height + 1) + y, pos * 6 + x) = state;
+ bitmap.pix(line * (line_height + 1) + y, pos * 6 + x) = state;
}
else if (m_lines <= 4)
{
@@ -287,7 +287,7 @@ inline void hd44780_device::pixel_update(bitmap_ind16 &bitmap, u8 line, u8 pos,
}
if (line < m_lines)
- bitmap.pix16(line * (line_height + 1) + y, pos * 6 + x) = state;
+ bitmap.pix(line * (line_height + 1) + y, pos * 6 + x) = state;
}
}
else
diff --git a/src/devices/video/hd61830.cpp b/src/devices/video/hd61830.cpp
index 26ee97cb22f..55bf2bbd588 100644
--- a/src/devices/video/hd61830.cpp
+++ b/src/devices/video/hd61830.cpp
@@ -360,9 +360,9 @@ uint16_t hd61830_device::draw_scanline(bitmap_ind16 &bitmap, const rectangle &cl
if(y >= 0 && y < bitmap.height())
{
if(((sx * m_hp) + x) >= 0 && ((sx * m_hp) + x) < bitmap.width())
- bitmap.pix16(y, (sx * m_hp) + x) = BIT(data1, x);
+ bitmap.pix(y, (sx * m_hp) + x) = BIT(data1, x);
if(((sx * m_hp) + x + m_hp) >= 0 && ((sx * m_hp) + x + m_hp) < bitmap.width())
- bitmap.pix16(y, (sx * m_hp) + x + m_hp) = BIT(data2, x);
+ bitmap.pix(y, (sx * m_hp) + x + m_hp) = BIT(data2, x);
}
}
}
@@ -454,7 +454,7 @@ void hd61830_device::draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect,
}
if (sy < screen().height() && sx < screen().width())
- bitmap.pix16(sy, sx) = pixel;
+ bitmap.pix(sy, sx) = pixel;
}
}
}
diff --git a/src/devices/video/hd63484.cpp b/src/devices/video/hd63484.cpp
index e0b08389492..a740aaa93f9 100644
--- a/src/devices/video/hd63484.cpp
+++ b/src/devices/video/hd63484.cpp
@@ -2107,7 +2107,7 @@ void hd63484_device::draw_graphics_line(bitmap_ind16 &bitmap, const rectangle &c
if (!m_display_cb.isnull())
m_display_cb(bitmap, cliprect, y, px, data & mask);
else if (cliprect.contains(px, y))
- bitmap.pix16(y, px) = data & mask;
+ bitmap.pix(y, px) = data & mask;
data >>= bpp;
}
diff --git a/src/devices/video/hd66421.cpp b/src/devices/video/hd66421.cpp
index 22efe3689e8..6be96c81e1f 100644
--- a/src/devices/video/hd66421.cpp
+++ b/src/devices/video/hd66421.cpp
@@ -208,7 +208,7 @@ void hd66421_device::reg_dat_w(uint8_t data)
void hd66421_device::plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color)
{
- bitmap.pix16(y, x) = (uint16_t)color;
+ bitmap.pix(y, x) = (uint16_t)color;
}
uint32_t hd66421_device::update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
diff --git a/src/devices/video/hp1ll3.cpp b/src/devices/video/hp1ll3.cpp
index 9a1952d8c25..006b8823122 100644
--- a/src/devices/video/hp1ll3.cpp
+++ b/src/devices/video/hp1ll3.cpp
@@ -810,14 +810,14 @@ uint32_t hp1ll3_device::screen_update(screen_device &screen, bitmap_ind16 &bitma
{
if (!m_enable_video)
{
- bitmap.fill(rgb_t::black());
+ bitmap.fill(0);
return 0;
}
for (int y = 0; y < m_vert_pix_total; y++)
{
int const offset = m_sad + y*m_conf[CONF_WPL];
- uint16_t *p = &m_bitmap.pix16(y);
+ uint16_t *p = &m_bitmap.pix(y);
for (int x = offset; x < offset + m_horiz_pix_total / 16; x++)
{
diff --git a/src/devices/video/huc6260.cpp b/src/devices/video/huc6260.cpp
index 1160f7edf13..08ca9abc5d9 100644
--- a/src/devices/video/huc6260.cpp
+++ b/src/devices/video/huc6260.cpp
@@ -69,7 +69,7 @@ void huc6260_device::device_timer(emu_timer &timer, device_timer_id id, int para
int hpos = screen().hpos();
int h = m_last_h;
int v = m_last_v;
- uint16_t *bitmap_line = &m_bmp->pix16(v);
+ uint16_t *bitmap_line = &m_bmp->pix(v);
while ( h != hpos || v != vpos )
{
@@ -112,7 +112,7 @@ void huc6260_device::device_timer(emu_timer &timer, device_timer_id id, int para
m_hsync_changed_cb( 1 );
m_pixel_clock = 0;
v = ( v + 1 ) % m_height;
- bitmap_line = &m_bmp->pix16(v);
+ bitmap_line = &m_bmp->pix(v);
break;
case HUC6260_HSYNC_START + 30: /* End/Start of VSync */
diff --git a/src/devices/video/huc6261.cpp b/src/devices/video/huc6261.cpp
index 42568090447..4ff0080777a 100644
--- a/src/devices/video/huc6261.cpp
+++ b/src/devices/video/huc6261.cpp
@@ -100,7 +100,7 @@ void huc6261_device::device_timer(emu_timer &timer, device_timer_id id, int para
int hpos = screen().hpos();
int h = m_last_h;
int v = m_last_v;
- uint32_t *bitmap_line = &m_bmp->pix32(v);
+ uint32_t *bitmap_line = &m_bmp->pix(v);
while ( h != hpos || v != vpos )
{
@@ -153,7 +153,7 @@ void huc6261_device::device_timer(emu_timer &timer, device_timer_id id, int para
m_huc6270_b->hsync_changed( 1 );
m_pixel_clock = 0;
v = ( v + 1 ) % m_height;
- bitmap_line = &m_bmp->pix32(v);
+ bitmap_line = &m_bmp->pix(v);
break;
case HUC6261_HSYNC_START + 30: /* End/Start of VSync */
diff --git a/src/devices/video/i8244.cpp b/src/devices/video/i8244.cpp
index 8288dd9e552..4272f3dfeac 100644
--- a/src/devices/video/i8244.cpp
+++ b/src/devices/video/i8244.cpp
@@ -24,13 +24,13 @@ DEFINE_DEVICE_TYPE(I8245, i8245_device, "i8245", "Intel 8245")
// i8244_device - constructor
//-------------------------------------------------
-i8244_device::i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+i8244_device::i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: i8244_device(mconfig, I8244, tag, owner, clock)
{
}
-i8244_device::i8244_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+i8244_device::i8244_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, type, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, device_video_interface(mconfig, *this)
@@ -40,7 +40,7 @@ i8244_device::i8244_device(const machine_config &mconfig, device_type type, cons
}
-i8245_device::i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+i8245_device::i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: i8244_device(mconfig, I8245, tag, owner, clock)
{
}
@@ -135,7 +135,7 @@ void i8244_device::device_start()
memset(m_vdc.reg, 0, 0x100);
save_pointer(NAME(m_vdc.reg), 0x100);
- memset( m_collision_map, 0, sizeof( m_collision_map ) );
+ memset(m_collision_map, 0, sizeof(m_collision_map));
save_item(NAME(m_collision_map));
save_item(NAME(m_x_beam_pos));
@@ -174,13 +174,13 @@ void i8244_device::i8244_palette(palette_device &palette) const
{ 0xff, 0xff, 0xff } // I R G B
};
- palette.set_pen_colors( 0, i8244_colors );
+ palette.set_pen_colors(0, i8244_colors);
}
void i8244_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- switch ( id )
+ switch (id)
{
case TIMER_HBLANK_START:
// hblank starts (updates sound shift register)
@@ -199,25 +199,25 @@ void i8244_device::device_timer(emu_timer &timer, device_timer_id id, int param,
}
-offs_t i8244_device::fix_register_mirrors( offs_t offset )
+offs_t i8244_device::fix_register_mirrors(offs_t offset)
{
// quad x/y registers are mirrored for each quad
- if ( ( offset & 0xC2 ) == 0x40 )
+ if ((offset & 0xc2) == 0x40)
{
- offset &= ~0x0C;
+ offset &= ~0x0c;
}
// registers $A0-$AF are mirrored at $B0-$BF
- if ( ( offset & 0xE0 ) == 0xA0 )
+ if ((offset & 0xe0) == 0xa0)
{
offset &= ~0x10;
}
- return offset & 0xFF;
+ return offset & 0xff;
}
-bool i8244_device::invalid_register( offs_t offset, bool rw )
+bool i8244_device::invalid_register(offs_t offset, bool rw)
{
// object x/y/attr registers are not accessible when display is enabled
// (sprite shape registers still are)
@@ -280,9 +280,9 @@ bool i8244_device::invalid_register( offs_t offset, bool rw )
}
-uint8_t i8244_device::read(offs_t offset)
+u8 i8244_device::read(offs_t offset)
{
- uint8_t data;
+ u8 data;
offset = fix_register_mirrors(offset);
@@ -337,7 +337,7 @@ uint8_t i8244_device::read(offs_t offset)
}
-void i8244_device::write(offs_t offset, uint8_t data)
+void i8244_device::write(offs_t offset, u8 data)
{
offset = fix_register_mirrors(offset);
@@ -470,7 +470,7 @@ void i8244_device::write_cx(int x, bool cx)
}
-uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+u32 i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
/* Draw background color */
bitmap.fill(bitswap<3>(m_vdc.s.color,3,4,5), cliprect);
@@ -478,28 +478,28 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
for (int scanline = cliprect.min_y; scanline <= cliprect.max_y; scanline++)
{
/* Clear collision map */
- memset( m_collision_map, 0, sizeof( m_collision_map ) );
+ memset(m_collision_map, 0, sizeof(m_collision_map));
/* Display grid if enabled */
- if ( m_vdc.s.control & 0x08 )
+ if (m_vdc.s.control & 0x08)
{
- uint16_t color = bitswap<4>(m_vdc.s.color,6,0,1,2);
+ u16 color = bitswap<4>(m_vdc.s.color,6,0,1,2);
int x_grid_offset = 13;
int y_grid_offset = 24;
int width = 16;
int height = 24;
- int w = ( m_vdc.s.control & 0x80 ) ? width : 2;
+ int w = (m_vdc.s.control & 0x80) ? width : 2;
/* Draw horizontal part of the grid */
- for ( int y = 0; y < 9; y++ )
+ for (int y = 0; y < 9; y++)
{
- if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3 )
+ if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3)
{
- for ( int i = 0; i < 9; i++ )
+ for (int i = 0; i < 9; i++)
{
- if ( BIT(m_vdc.s.hgrid[1][i] << 8 | m_vdc.s.hgrid[0][i], y) )
+ if (BIT(m_vdc.s.hgrid[1][i] << 8 | m_vdc.s.hgrid[0][i], y))
{
- for ( int k = 0; k < width + 2; k++ )
+ for (int k = 0; k < width + 2; k++)
{
int x = (x_grid_offset + i * width + k) * 2;
@@ -507,8 +507,8 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
{
if (cliprect.contains(px, scanline))
{
- m_collision_map[ px ] |= 0x20;
- bitmap.pix16( scanline, px ) = color;
+ m_collision_map[px] |= 0x20;
+ bitmap.pix(scanline, px) = color;
}
}
}
@@ -518,15 +518,15 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
/* Draw dots part of the grid */
- if ( m_vdc.s.control & 0x40 )
+ if (m_vdc.s.control & 0x40)
{
- for ( int y = 0; y < 9; y++ )
+ for (int y = 0; y < 9; y++)
{
- if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3 )
+ if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + y * height + 3)
{
- for ( int i = 0; i < 10; i++ )
+ for (int i = 0; i < 10; i++)
{
- for ( int k = 0; k < 2; k++ )
+ for (int k = 0; k < 2; k++)
{
int x = (x_grid_offset + i * width + k) * 2;
@@ -534,8 +534,8 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
{
if (cliprect.contains(px, scanline))
{
- m_collision_map[ px ] |= 0x20;
- bitmap.pix16( scanline, px ) = color;
+ m_collision_map[px] |= 0x20;
+ bitmap.pix(scanline, px) = color;
}
}
}
@@ -545,15 +545,15 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
/* Draw vertical part of the grid */
- for( int j = 1, y = 0; y < 8; y++, j <<= 1 )
+ for (int j = 1, y = 0; y < 8; y++, j <<= 1)
{
- if ( y_grid_offset + y * height <= scanline && scanline < y_grid_offset + ( y + 1 ) * height )
+ if (y_grid_offset + y * height <= scanline && scanline < y_grid_offset + (y + 1) * height)
{
- for ( int i = 0; i < 10; i++ )
+ for (int i = 0; i < 10; i++)
{
- if ( m_vdc.s.vgrid[i] & j )
+ if (m_vdc.s.vgrid[i] & j)
{
- for ( int k = 0; k < w; k++ )
+ for (int k = 0; k < w; k++)
{
int x = (x_grid_offset + i * width + k) * 2;
@@ -561,8 +561,8 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
{
if (cliprect.contains(px, scanline))
{
- m_collision_map[ px ] |= 0x10;
- bitmap.pix16( scanline, px ) = color;
+ m_collision_map[px] |= 0x10;
+ bitmap.pix(scanline, px) = color;
}
}
}
@@ -573,37 +573,37 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
/* Display objects if enabled */
- if ( m_vdc.s.control & 0x20 && scanline <= 242 )
+ if (m_vdc.s.control & 0x20 && scanline <= 242)
{
/* Quad objects */
- for ( int i = ARRAY_LENGTH( m_vdc.s.quad ) - 1; i >= 0; i-- )
+ for (int i = ARRAY_LENGTH(m_vdc.s.quad) - 1; i >= 0; i--)
{
int y = m_vdc.s.quad[i].single[0].y;
// Character height is always determined by the height of the 4th character
- int height = 8 - ( ( ( y >> 1 ) + m_vdc.s.quad[i].single[3].ptr ) & 7 );
+ int height = 8 - (((y >> 1) + m_vdc.s.quad[i].single[3].ptr) & 7);
if (height == 1) height = 8;
- if ( y <= scanline && scanline < y + height * 2 )
+ if (y <= scanline && scanline < y + height * 2)
{
int x = (m_vdc.s.quad[i].single[0].x + 5) * 2;
- for ( int j = 0; j < ARRAY_LENGTH( m_vdc.s.quad[0].single ); j++, x += 16 )
+ for (int j = 0; j < ARRAY_LENGTH(m_vdc.s.quad[0].single); j++, x += 16)
{
- uint16_t color = 8 + ( ( m_vdc.s.quad[i].single[j].color >> 1 ) & 0x07 );
- int offset = ( m_vdc.s.quad[i].single[j].ptr | ( ( m_vdc.s.quad[i].single[j].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 );
- uint8_t chr = m_charset[ offset & 0x1FF ];
+ u16 color = 8 + ((m_vdc.s.quad[i].single[j].color >> 1) & 0x07);
+ int offset = (m_vdc.s.quad[i].single[j].ptr | ((m_vdc.s.quad[i].single[j].color & 0x01) << 8)) + (y >> 1) + ((scanline - y) >> 1);
+ u8 chr = m_charset[offset & 0x1ff];
- for ( uint8_t m = 0x80; m > 0; m >>= 1, x += 2 )
+ for (u8 m = 0x80; m > 0; m >>= 1, x += 2)
{
- if ( chr & m )
+ if (chr & m)
{
for (int px = x; px < x + 2; px++)
{
if (cliprect.contains(px, scanline))
{
// Check collision with self
- u8 colx = m_collision_map[ px ];
+ u8 colx = m_collision_map[px];
if (colx & 0x80)
{
colx &= ~0x80;
@@ -618,8 +618,8 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
if (m_vdc.s.collision & 0x80)
m_collision_status |= colx;
- m_collision_map[ px ] |= 0x80;
- bitmap.pix16( scanline, px ) = color;
+ m_collision_map[px] |= 0x80;
+ bitmap.pix(scanline, px) = color;
}
}
}
@@ -629,29 +629,29 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
/* Regular foreground objects */
- for ( int i = ARRAY_LENGTH( m_vdc.s.foreground ) - 1; i >= 0; i-- )
+ for (int i = ARRAY_LENGTH(m_vdc.s.foreground) - 1; i >= 0; i--)
{
int y = m_vdc.s.foreground[i].y;
- int height = 8 - ( ( ( y >> 1 ) + m_vdc.s.foreground[i].ptr ) & 7 );
+ int height = 8 - (((y >> 1) + m_vdc.s.foreground[i].ptr) & 7);
if (height == 1) height = 8;
- if ( y <= scanline && scanline < y + height * 2 )
+ if (y <= scanline && scanline < y + height * 2)
{
- uint16_t color = 8 + ( ( m_vdc.s.foreground[i].color >> 1 ) & 0x07 );
- int offset = ( m_vdc.s.foreground[i].ptr | ( ( m_vdc.s.foreground[i].color & 0x01 ) << 8 ) ) + ( y >> 1 ) + ( ( scanline - y ) >> 1 );
- uint8_t chr = m_charset[ offset & 0x1FF ];
+ u16 color = 8 + ((m_vdc.s.foreground[i].color >> 1) & 0x07);
+ int offset = (m_vdc.s.foreground[i].ptr | ((m_vdc.s.foreground[i].color & 0x01) << 8)) + (y >> 1) + ((scanline - y) >> 1);
+ u8 chr = m_charset[offset & 0x1ff];
int x = (m_vdc.s.foreground[i].x + 5) * 2;
- for ( uint8_t m = 0x80; m > 0; m >>= 1, x += 2 )
+ for (u8 m = 0x80; m > 0; m >>= 1, x += 2)
{
- if ( chr & m )
+ if (chr & m)
{
for (int px = x; px < x + 2; px++)
{
if (cliprect.contains(px, scanline))
{
// Check collision with self
- u8 colx = m_collision_map[ px ];
+ u8 colx = m_collision_map[px];
if (colx & 0x80)
{
colx &= ~0x80;
@@ -666,8 +666,8 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
if (m_vdc.s.collision & 0x80)
m_collision_status |= colx;
- m_collision_map[ px ] |= 0x80;
- bitmap.pix16( scanline, px ) = color;
+ m_collision_map[px] |= 0x80;
+ bitmap.pix(scanline, px) = color;
}
}
}
@@ -676,30 +676,30 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
/* Sprites */
- for ( int i = ARRAY_LENGTH( m_vdc.s.sprites ) - 1; i >= 0; i-- )
+ for (int i = ARRAY_LENGTH(m_vdc.s.sprites) - 1; i >= 0; i--)
{
int y = m_vdc.s.sprites[i].y;
int height = 8;
bool zoom_enable = bool(m_vdc.s.sprites[i].color & 4);
int zoom_px = zoom_enable ? 4 : 2;
- if ( y <= scanline && scanline < y + height * zoom_px )
+ if (y <= scanline && scanline < y + height * zoom_px)
{
- uint16_t color = 8 + ( ( m_vdc.s.sprites[i].color >> 3 ) & 0x07 );
- uint8_t chr = m_vdc.s.shape[i][ ( ( scanline - y ) / zoom_px ) ];
+ u16 color = 8 + ((m_vdc.s.sprites[i].color >> 3) & 0x07);
+ u8 chr = m_vdc.s.shape[i][((scanline - y) / zoom_px)];
int x = (m_vdc.s.sprites[i].x + 5) * 2;
int x_shift = 0;
- switch ( m_vdc.s.sprites[i].color & 0x03 )
+ switch (m_vdc.s.sprites[i].color & 0x03)
{
case 1: // Xg attribute set
x_shift = 1;
break;
case 2: // S attribute set
- x_shift = ( ( ( scanline - y ) / zoom_px ) & 0x01 ) ^ 0x01;
+ x_shift = (((scanline - y) / zoom_px) & 0x01) ^ 0x01;
break;
case 3: // Xg and S attributes set
- x_shift = ( ( scanline - y ) / zoom_px ) & 0x01;
+ x_shift = ((scanline - y) / zoom_px) & 0x01;
break;
default:
break;
@@ -707,9 +707,9 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
x += x_shift * (zoom_px / 2);
- for ( uint8_t m = 0x01; m > 0; m <<= 1, x += zoom_px )
+ for (u8 m = 0x01; m > 0; m <<= 1, x += zoom_px)
{
- if ( chr & m )
+ if (chr & m)
{
for (int px = x; px < x + zoom_px; px++)
{
@@ -718,15 +718,15 @@ uint32_t i8244_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
u8 mask = 1 << i;
// Check if we collide with an already drawn source object
- if (m_vdc.s.collision & m_collision_map[ px ])
+ if (m_vdc.s.collision & m_collision_map[px])
m_collision_status |= mask;
// Check if an already drawn object would collide with us
if (m_vdc.s.collision & mask)
- m_collision_status |= m_collision_map[ px ];
+ m_collision_status |= m_collision_map[px];
- m_collision_map[ px ] |= mask;
- bitmap.pix16( scanline, px ) = color;
+ m_collision_map[px] |= mask;
+ bitmap.pix(scanline, px) = color;
}
}
}
@@ -783,9 +783,9 @@ void i8244_device::sound_update()
// loop sound
signal |= feedback << 23;
- m_vdc.s.shift3 = signal & 0xFF;
- m_vdc.s.shift2 = ( signal >> 8 ) & 0xFF;
- m_vdc.s.shift1 = ( signal >> 16 ) & 0xFF;
+ m_vdc.s.shift3 = signal & 0xff;
+ m_vdc.s.shift2 = (signal >> 8) & 0xff;
+ m_vdc.s.shift1 = (signal >> 16) & 0xff;
// sound interrupt
if (++m_sh_count == 24)
diff --git a/src/devices/video/i8244.h b/src/devices/video/i8244.h
index 3568f5a613d..565ed13826f 100644
--- a/src/devices/video/i8244.h
+++ b/src/devices/video/i8244.h
@@ -27,68 +27,68 @@ class i8244_device : public device_t
{
public:
// construction/destruction
- i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ i8244_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// configuration helpers
auto irq_cb() { return m_irq_func.bind(); }
i8244_device &set_screen_size(int width, int height, int cropx = 0, int cropy = 0);
- uint8_t read(offs_t offset);
- void write(offs_t offset, uint8_t data);
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
void write_cx(int x, bool cx); // CX pin on current scanline
int vblank();
int hblank();
void i8244_palette(palette_device &palette) const;
- uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
protected:
union vdc_t {
- uint8_t reg[0x100];
+ u8 reg[0x100];
struct {
// 0x00
struct {
- uint8_t y,x,color,unused;
+ u8 y,x,color,unused;
} sprites[4];
// 0x10
struct {
- uint8_t y,x,ptr,color;
+ u8 y,x,ptr,color;
} foreground[12];
// 0x40
struct {
struct {
- uint8_t y,x,ptr,color;
+ u8 y,x,ptr,color;
} single[4];
} quad[4];
// 0x80
- uint8_t shape[4][8];
+ u8 shape[4][8];
// 0xa0
- uint8_t control;
- uint8_t status;
- uint8_t collision;
- uint8_t color;
- uint8_t y;
- uint8_t x;
- uint8_t unused;
- uint8_t shift1;
- uint8_t shift2;
- uint8_t shift3;
- uint8_t sound;
- uint8_t unused2[5+0x10];
+ u8 control;
+ u8 status;
+ u8 collision;
+ u8 color;
+ u8 y;
+ u8 x;
+ u8 unused;
+ u8 shift1;
+ u8 shift2;
+ u8 shift3;
+ u8 sound;
+ u8 unused2[5+0x10];
// 0xc0
- uint8_t hgrid[2][0x10];
- uint8_t vgrid[0x10];
- uint8_t unused3[0x10];
+ u8 hgrid[2][0x10];
+ u8 vgrid[0x10];
+ u8 unused3[0x10];
} s;
};
- i8244_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+ i8244_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
// device-level overrides
virtual void device_config_complete() override;
@@ -103,8 +103,8 @@ protected:
int get_y_beam();
int get_x_beam();
- offs_t fix_register_mirrors( offs_t offset );
- bool invalid_register( offs_t offset, bool rw );
+ offs_t fix_register_mirrors(offs_t offset);
+ bool invalid_register(offs_t offset, bool rw);
/* timers */
static constexpr device_timer_id TIMER_VBLANK_START = 0;
@@ -113,7 +113,7 @@ protected:
// callbacks
devcb_write_line m_irq_func;
- required_region_ptr<uint8_t> m_charset;
+ required_region_ptr<u8> m_charset;
emu_timer *m_hblank_timer;
emu_timer *m_vblank_timer;
@@ -135,12 +135,12 @@ protected:
int m_bgate_start;
vdc_t m_vdc;
- uint8_t m_collision_map[0x200];
+ u8 m_collision_map[0x200];
- uint8_t m_x_beam_pos = 0;
- uint8_t m_y_beam_pos = 0;
- uint8_t m_control_status = 0;
- uint8_t m_collision_status = 0;
+ u8 m_x_beam_pos = 0;
+ u8 m_y_beam_pos = 0;
+ u8 m_control_status = 0;
+ u8 m_collision_status = 0;
bool m_sh_written = false;
bool m_sh_pending = false;
@@ -155,7 +155,7 @@ class i8245_device : public i8244_device
{
public:
// construction/destruction
- i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ i8245_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
virtual void set_default_params() override;
diff --git a/src/devices/video/imagetek_i4100.cpp b/src/devices/video/imagetek_i4100.cpp
index 030314636c1..8c0eaff1011 100644
--- a/src/devices/video/imagetek_i4100.cpp
+++ b/src/devices/video/imagetek_i4100.cpp
@@ -59,7 +59,7 @@
8 to 64 (independently for width and height) with an 8 pixel
granularity. The "tile" address is a multiple of 8x8 pixels.
- Each sprite can be shrinked to ~1/4 or enlarged to ~32x following
+ Each sprite can be shrunk to ~1/4 or enlarged to ~32x following
an exponential curve of sizes (with one zoom value for both width
and height)
@@ -295,7 +295,7 @@ imagetek_i4300_device::imagetek_i4300_device(const machine_config &mconfig, cons
//-------------------------------------------------
// device_add_mconfig - device-specific machine
-// configuration addiitons
+// configuration additions
//-------------------------------------------------
void imagetek_i4100_device::device_add_mconfig(machine_config &config)
@@ -331,6 +331,10 @@ void imagetek_i4100_device::expand_gfx1()
void imagetek_i4100_device::device_start()
{
m_inited_hack = false;
+
+ m_screen_blank = false;
+ m_screen_flip = false;
+
save_item(NAME(m_rombank));
save_item(NAME(m_crtc_unlock));
save_item(NAME(m_sprite_count));
@@ -395,7 +399,7 @@ void imagetek_i4100_device::vram_2_w(offs_t offset, uint16_t data, uint16_t mem_
/* Some game uses almost only the blitter to write to the tilemaps.
The CPU can only access a "window" of 512x256 pixels in the upper
left corner of the big tilemap */
-// TODO: Puzzlet, Sankokushi & Lady Killer contradicts with aformentioned description (more like RMW?)
+// TODO: Puzzlet, Sankokushi & Lady Killer contradicts with aforementioned description (more like RMW?)
static inline offs_t RMW_OFFS(offs_t offset)
{
@@ -923,8 +927,8 @@ void imagetek_i4100_device::draw_spritegfx(screen_device &screen, bitmap_rgb32 &
for (int y = sy; y < ey; y++)
{
const u8 *source = source_base + (y_index >> 16) * width;
- u32 *dest = &bitmap.pix32(y);
- u8 *pri = &priority_bitmap.pix8(y);
+ u32 *dest = &bitmap.pix(y);
+ u8 *pri = &priority_bitmap.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
{
@@ -1200,8 +1204,8 @@ void imagetek_i4100_device::draw_tilemap(screen_device &screen, bitmap_rgb32 &bi
int const srctilerow = srcline >> tileshift;
srcline &= tilemask;
- u32 *dst = &bitmap.pix32(y);
- u8 *priority_baseaddr = &priority_bitmap.pix8(y);
+ u32 *dst = &bitmap.pix(y);
+ u8 *priority_baseaddr = &priority_bitmap.pix(y);
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
diff --git a/src/devices/video/m50458.cpp b/src/devices/video/m50458.cpp
index 97e67af8a75..e2404684700 100644
--- a/src/devices/video/m50458.cpp
+++ b/src/devices/video/m50458.cpp
@@ -204,21 +204,19 @@ void m50458_device::device_validity_check(validity_checker &valid) const
void m50458_device::device_start()
{
- uint16_t tmp;
- uint8_t *pcg = memregion("m50458")->base();
- int tile;
- int yi;
- uint16_t src,dst;
+ uint8_t const *const pcg = memregion("m50458")->base();
/* Create an array for shadow gfx */
/* this will spread the source ROM into four directions (up-left, up-right, down-left, down-right) thus creating a working shadow copy */
m_shadow_gfx = make_unique_clear<uint8_t[]>(0x1200);
- for(tile=0;tile<0x80;tile++)
+ for(int tile=0;tile<0x80;tile++)
{
- for(yi=1;yi<17;yi++)
+ for(int yi=1;yi<17;yi++)
{
- src = (tile & 0x7f)*36+yi*2; /* source offset */
+ uint16_t tmp, dst;
+
+ uint16_t const src = (tile & 0x7f)*36+yi*2; /* source offset */
dst = (tile & 0x7f)*36+(yi-1)*2; /* destination offset */
@@ -331,40 +329,34 @@ WRITE_LINE_MEMBER( m50458_device::set_clock_line )
uint32_t m50458_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y;
- uint8_t *pcg = memregion("m50458")->base();
- uint8_t bg_r,bg_g,bg_b;
+ uint8_t const *const pcg = memregion("m50458")->base();
/* TODO: there's probably a way to control the brightness in this */
- bg_r = m_phase & 1 ? 0xdf : 0;
- bg_g = m_phase & 2 ? 0xdf : 0;
- bg_b = m_phase & 4 ? 0xdf : 0;
+ uint8_t const bg_r = m_phase & 1 ? 0xdf : 0;
+ uint8_t const bg_g = m_phase & 2 ? 0xdf : 0;
+ uint8_t const bg_b = m_phase & 4 ? 0xdf : 0;
bitmap.fill(rgb_t(0xff,bg_r,bg_g,bg_b),cliprect);
- for(y=0;y<12;y++)
+ for(int y=0;y<12;y++)
{
- for(x=0;x<24;x++)
+ for(int x=0;x<24;x++)
{
- int xi,yi;
- uint16_t tile;
int y_base = y;
if(y != 0 && m_scrr > 1) { y_base+=(m_scrr - 1); }
if(y_base > 11) { y_base -= 11; }
if(m_scrr && y == 11) { y_base = 0; } /* Guess: repeat line 0 if scrolling is active */
- tile = read_word(x+y_base*24);
+ uint16_t const tile = read_word(x+y_base*24);
- for(yi=0;yi<18;yi++)
+ for(int yi=0;yi<18;yi++)
{
- for(xi=4;xi<16;xi++) /* TODO: remove 4 / 16 / -4 offset once that the ROM is fixed */
+ for(int xi=4;xi<16;xi++) /* TODO: remove 4 / 16 / -4 offset once that the ROM is fixed */
{
- uint8_t pix;
- uint8_t color = (tile & 0x700) >> 8;
- uint16_t offset = ((tile & 0x7f)*36+yi*2);
- int res_y,res_x;
- uint8_t xh,yh;
+ uint8_t const color = (tile & 0x700) >> 8;
+ uint16_t const offset = ((tile & 0x7f)*36+yi*2);
+ uint8_t pix;
if(xi>=8)
pix = ((pcg[offset+1] >> (7-(xi & 0x7))) & 1) << 1;
else
@@ -382,8 +374,8 @@ uint32_t m50458_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
if(yi == 17 && tile & 0x1000) /* underline? */
pix |= 1;
- res_y = y*18+yi;
- res_x = x*12+(xi-4);
+ int res_y = y*18+yi;
+ int res_x = x*12+(xi-4);
if(y != 0 && y != 11)
{
@@ -419,9 +411,9 @@ uint32_t m50458_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
if(res_y > 215 || res_x > 288)
continue;
- for(yh=0;yh<m_vsz1+1;yh++)
- for(xh=0;xh<m_hsz1+1;xh++)
- bitmap.pix32(res_y+yh,res_x+xh) = r << 16 | g << 8 | b;
+ for(uint8_t yh=0;yh<m_vsz1+1;yh++)
+ for(uint8_t xh=0;xh<m_hsz1+1;xh++)
+ bitmap.pix(res_y+yh,res_x+xh) = r << 16 | g << 8 | b;
}
else if(y_base == 11)
{
@@ -432,9 +424,9 @@ uint32_t m50458_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
if(res_y > 215 || res_x > 288)
continue;
- for(yh=0;yh<m_vsz3+1;yh++)
- for(xh=0;xh<m_hsz3+1;xh++)
- bitmap.pix32(res_y+yh,res_x+xh) = r << 16 | g << 8 | b;
+ for(uint8_t yh=0;yh<m_vsz3+1;yh++)
+ for(uint8_t xh=0;xh<m_hsz3+1;xh++)
+ bitmap.pix(res_y+yh,res_x+xh) = r << 16 | g << 8 | b;
}
else
{
@@ -444,9 +436,9 @@ uint32_t m50458_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
if(res_y > 215 || res_x > 288)
continue;
- for(yh=0;yh<m_vsz2+1;yh++)
- for(xh=0;xh<m_hsz2+1;xh++)
- bitmap.pix32(res_y+yh,res_x+xh) = r << 16 | g << 8 | b;
+ for(uint8_t yh=0;yh<m_vsz2+1;yh++)
+ for(uint8_t xh=0;xh<m_hsz2+1;xh++)
+ bitmap.pix(res_y+yh,res_x+xh) = r << 16 | g << 8 | b;
}
}
}
diff --git a/src/devices/video/mb88303.cpp b/src/devices/video/mb88303.cpp
index 1112012db1d..16a24122306 100644
--- a/src/devices/video/mb88303.cpp
+++ b/src/devices/video/mb88303.cpp
@@ -339,7 +339,7 @@ void mb88303_device::update_bitmap(bitmap_rgb32 &bitmap, const rectangle &clipre
const uint32_t color = BIT(gfx[row], bit) ? 0xffffffff : 0;
if (!show_background() && !color)
continue;
- bitmap.pix32(bitmap_y + row + m_vert_display_pos, bitmap_x + (6 - bit) + m_horiz_display_pos) = color;
+ bitmap.pix(bitmap_y + row + m_vert_display_pos, bitmap_x + (6 - bit) + m_horiz_display_pos) = color;
}
}
}
diff --git a/src/devices/video/mb90082.cpp b/src/devices/video/mb90082.cpp
index b56e4e61409..27ef9238ec6 100644
--- a/src/devices/video/mb90082.cpp
+++ b/src/devices/video/mb90082.cpp
@@ -207,44 +207,37 @@ void mb90082_device::write(uint8_t data)
uint32_t mb90082_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y;
- uint8_t *pcg = memregion("mb90082")->base();
- uint16_t tile,attr;
- uint8_t bg_r,bg_g,bg_b;
+ uint8_t const *const pcg = memregion("mb90082")->base();
/* TODO: there's probably a way to control the brightness in this */
- bg_b = m_uc & 1 ? 0xdf : 0;
- bg_g = m_uc & 2 ? 0xdf : 0;
- bg_r = m_uc & 4 ? 0xdf : 0;
+ uint8_t const bg_b = m_uc & 1 ? 0xdf : 0;
+ uint8_t const bg_g = m_uc & 2 ? 0xdf : 0;
+ uint8_t const bg_r = m_uc & 4 ? 0xdf : 0;
bitmap.fill(rgb_t(0xff,bg_r,bg_g,bg_b),cliprect);
- for(y=0;y<12;y++)
+ for(int y=0;y<12;y++)
{
- for(x=0;x<24;x++)
+ for(int x=0;x<24;x++)
{
- int xi,yi;
-
- tile = read_word(x+y*24);
- attr = read_word((x+y*24)|0x200);
+ uint16_t tile = read_word(x+y*24);
+ uint16_t attr = read_word((x+y*24)|0x200);
/* TODO: charset hook-up is obviously WRONG so following mustn't be trusted at all */
- for(yi=0;yi<16;yi++)
+ for(int yi=0;yi<16;yi++)
{
- for(xi=0;xi<16;xi++)
+ for(int xi=0;xi<16;xi++)
{
- uint8_t pix;
- uint8_t color = (attr & 0x70) >> 4;
- uint8_t r,g,b;
+ uint8_t const color = (attr & 0x70) >> 4;
- pix = (pcg[(tile*8)+(yi >> 1)] >> (7-(xi >> 1))) & 1;
+ uint8_t const pix = (pcg[(tile*8)+(yi >> 1)] >> (7-(xi >> 1))) & 1;
/* TODO: check this */
- b = (color & 1) ? 0xff : 0;
- g = (color & 2) ? 0xff : 0;
- r = (color & 4) ? 0xff : 0;
+ uint8_t const b = (color & 1) ? 0xff : 0;
+ uint8_t const g = (color & 2) ? 0xff : 0;
+ uint8_t const r = (color & 4) ? 0xff : 0;
if(tile != 0xff && pix != 0)
- bitmap.pix32(y*16+yi,x*16+xi) = r << 16 | g << 8 | b;
+ bitmap.pix(y*16+yi,x*16+xi) = r << 16 | g << 8 | b;
}
}
}
diff --git a/src/devices/video/mb_vcu.cpp b/src/devices/video/mb_vcu.cpp
index 745675243e6..09ac807f13a 100644
--- a/src/devices/video/mb_vcu.cpp
+++ b/src/devices/video/mb_vcu.cpp
@@ -526,36 +526,33 @@ void mb_vcu_device::vbank_clear_w(uint8_t data)
uint32_t mb_vcu_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y;
- uint8_t dot;
-
bitmap.fill(m_palette->pen(0x100),cliprect);
- for(y=0;y<256;y++)
+ for(int y=0;y<256;y++)
{
- for(x=0;x<256;x++)
+ for(int x=0;x<256;x++)
{
- dot = read_byte((x >> 0)|(y<<8)|1<<16|(m_vbank ^ 1)<<18);
+ uint8_t dot = read_byte((x >> 0)|(y<<8)|1<<16|(m_vbank ^ 1)<<18);
//if(dot != 0xf)
{
dot|= m_vregs[1] << 4;
- bitmap.pix32(y,x) = m_palette->pen(dot);
+ bitmap.pix(y,x) = m_palette->pen(dot);
}
}
}
- for(y=0;y<256;y++)
+ for(int y=0;y<256;y++)
{
- for(x=0;x<256;x++)
+ for(int x=0;x<256;x++)
{
- dot = read_byte((x >> 0)|(y<<8)|0<<16|(m_vbank ^ 1)<<18);
+ uint8_t dot = read_byte((x >> 0)|(y<<8)|0<<16|(m_vbank ^ 1)<<18);
if(dot != 0xf)
{
dot|= m_vregs[1] << 4;
- bitmap.pix32(y,x) = m_palette->pen(dot);
+ bitmap.pix(y,x) = m_palette->pen(dot);
}
}
}
diff --git a/src/devices/video/mc6845.cpp b/src/devices/video/mc6845.cpp
index b8cc7148243..abf5692b7c7 100644
--- a/src/devices/video/mc6845.cpp
+++ b/src/devices/video/mc6845.cpp
@@ -108,6 +108,7 @@ mc6845_device::mc6845_device(const machine_config &mconfig, device_type type, co
: device_t(mconfig, type, tag, owner, clock)
, device_video_interface(mconfig, *this, false)
, m_show_border_area(true)
+ , m_noninterlace_adjust(0)
, m_interlace_adjust(0)
, m_clk_scale(1)
, m_visarea_adjust_min_x(0)
@@ -188,7 +189,7 @@ void mc6845_device::transparent_update()
{
m_update_addr++;
m_update_addr &= 0x3fff;
- call_on_update_address(0);
+ call_on_update_address(MODE_UPDATE_STROBE);
}
else
{
@@ -267,7 +268,7 @@ void mc6845_device::register_w(uint8_t data)
{
m_update_addr = ((data & 0x3f) << 8) | (m_update_addr & 0x00ff);
if(MODE_TRANSPARENT_PHI2)
- call_on_update_address(0);
+ call_on_update_address(MODE_UPDATE_STROBE);
}
break;
case 0x13:
@@ -275,7 +276,7 @@ void mc6845_device::register_w(uint8_t data)
{
m_update_addr = ((data & 0xff) << 0) | (m_update_addr & 0xff00);
if(MODE_TRANSPARENT_PHI2)
- call_on_update_address(0);
+ call_on_update_address(MODE_UPDATE_STROBE);
}
break;
case 0x1f: transparent_update(); break;
@@ -993,7 +994,7 @@ void mc6845_device::device_timer(emu_timer &timer, device_timer_id id, int param
case TIMER_UPD_ADR:
/* fire a update address strobe */
- call_on_update_address(0);
+ call_on_update_address(MODE_UPDATE_STROBE);
break;
case TIMER_UPD_TRANS:
@@ -1122,7 +1123,7 @@ uint8_t mc6845_device::draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangl
// is in units of characters and is relative to the start of the
// displayable area, not relative to the screen bitmap origin.
int8_t cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1;
- int de = (y < m_max_visible_y) ? 1 : 0;
+ int de = (y <= m_max_visible_y) ? 1 : 0;
int vbp = m_vert_pix_total - m_vsync_off_pos;
if (vbp < 0) vbp = 0;
int hbp = m_horiz_pix_total - m_hsync_off_pos;
@@ -1250,6 +1251,7 @@ void mc6845_device::device_start()
m_horiz_char_total = 0xff;
m_max_ras_addr = 0x1f;
m_vert_char_total = 0x7f;
+ m_mode_control = 0x00;
m_supports_disp_start_addr_r = false; // MC6845 can not read Display Start (double checked on datasheet)
m_supports_vert_sync_width = false;
@@ -1779,7 +1781,7 @@ MC6845_UPDATE_ROW( mos8563_device::vdc_update_row )
if (x < 0) x = 0;
int color = BIT(code, 7) ? fg : bg;
- bitmap.pix32(vbp + y, hbp + x) = pen(de ? color : 0);
+ bitmap.pix(vbp + y, hbp + x) = pen(de ? color : 0);
}
}
else
@@ -1815,7 +1817,7 @@ MC6845_UPDATE_ROW( mos8563_device::vdc_update_row )
if (x < 0) x = 0;
int color = BIT(data, 7) ? fg : bg;
- bitmap.pix32(vbp + y, hbp + x) = pen(de ? color : 0);
+ bitmap.pix(vbp + y, hbp + x) = pen(de ? color : 0);
if ((bit < 8) || !HSS_SEMI) data <<= 1;
}
diff --git a/src/devices/video/mc6847.h b/src/devices/video/mc6847.h
index 78a8ad57345..78fe0eac5f3 100644
--- a/src/devices/video/mc6847.h
+++ b/src/devices/video/mc6847.h
@@ -81,7 +81,7 @@ protected:
pixel_t *bitmap_addr(bitmap_rgb32 &bitmap, int y, int x)
{
- return &bitmap.pix32(y, x);
+ return &bitmap.pix(y, x);
}
static uint8_t simplify_mode(uint8_t data, uint8_t mode)
@@ -183,8 +183,8 @@ protected:
if( (mode & MODE_AS) || ((mode & (MODE_AG|MODE_GM0) ) == MODE_AG) )
{
- pixel_t *line1 = &bitmap.pix32(y + base_y, base_x);
- pixel_t *line2 = &bitmap.pix32(y + base_y + 1, base_x);
+ pixel_t *line1 = &bitmap.pix(y + base_y, base_x);
+ pixel_t *line2 = &bitmap.pix(y + base_y + 1, base_x);
std::map<std::pair<pixel_t,pixel_t>,pixel_t>::const_iterator newColor;
for( int pixel = 0; pixel < bitmap.width() - (base_x * 2); ++pixel )
diff --git a/src/devices/video/mos6566.cpp b/src/devices/video/mos6566.cpp
index b88cad06c64..a6e3c246a76 100644
--- a/src/devices/video/mos6566.cpp
+++ b/src/devices/video/mos6566.cpp
@@ -515,55 +515,37 @@ inline void mos6566_device::draw_background()
inline void mos6566_device::draw_mono( uint16_t p, uint8_t c0, uint8_t c1 )
{
- uint8_t c[2];
+ uint8_t const c[2] = { c0, c1 };
uint8_t data = m_gfx_data;
- c[0] = c0;
- c[1] = c1;
-
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 7] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 6] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 5] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 4] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 3] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 2] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[c[data & 1]];
- m_fore_coll_buf[p + 1] = data & 1; data >>= 1;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[c[data]];
- m_fore_coll_buf[p + 0] = data & 1;
+ for (unsigned i = 0; i < 8; i++)
+ {
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 7 - i) = PALETTE_MOS[c[data & 1]];
+ m_fore_coll_buf[p + 7 - i] = data & 1;
+ data >>= 1;
+ }
}
inline void mos6566_device::draw_multi( uint16_t p, uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3 )
{
- uint8_t c[4];
+ uint8_t const c[4] = { c0, c1, c2, c3 };
uint8_t data = m_gfx_data;
- c[0] = c0;
- c[1] = c1;
- c[2] = c2;
- c[3] = c3;
-
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[c[data & 3]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[c[data & 3]];
m_fore_coll_buf[p + 7] = data & 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[c[data & 3]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[c[data & 3]];
m_fore_coll_buf[p + 6] = data & 2; data >>= 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[c[data & 3]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[c[data & 3]];
m_fore_coll_buf[p + 5] = data & 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[c[data & 3]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[c[data & 3]];
m_fore_coll_buf[p + 4] = data & 2; data >>= 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[c[data & 3]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[c[data & 3]];
m_fore_coll_buf[p + 3] = data & 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[c[data & 3]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[c[data & 3]];
m_fore_coll_buf[p + 2] = data & 2; data >>= 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[c[data]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[c[data]];
m_fore_coll_buf[p + 1] = data & 2;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[c[data]];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[c[data]];
m_fore_coll_buf[p + 0] = data & 2;
}
@@ -2078,57 +2060,23 @@ void mos6566_device::draw_graphics()
draw_mono(p, tmp_col, m_color_data & 0x0f);
break;
case 5:
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 7] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 6] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 5] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 4] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 3] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 2] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 1] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 0] = 0;
- break;
case 6:
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 7] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 6] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 5] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 4] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 3] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 2] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 1] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0];
- m_fore_coll_buf[p + 0] = 0;
- break;
case 7:
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 7) = PALETTE_MOS[0];
m_fore_coll_buf[p + 7] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 6) = PALETTE_MOS[0];
m_fore_coll_buf[p + 6] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 5) = PALETTE_MOS[0];
m_fore_coll_buf[p + 5] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 4) = PALETTE_MOS[0];
m_fore_coll_buf[p + 4] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 3) = PALETTE_MOS[0];
m_fore_coll_buf[p + 3] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 2) = PALETTE_MOS[0];
m_fore_coll_buf[p + 2] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 1) = PALETTE_MOS[0];
m_fore_coll_buf[p + 1] = 0;
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + 0) = PALETTE_MOS[0];
m_fore_coll_buf[p + 0] = 0;
break;
}
@@ -2203,12 +2151,12 @@ void mos6566_device::draw_sprites()
if (SPRITE_PRIORITY(snum))
{
if (m_fore_coll_buf[p + i] == 0)
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
m_spr_coll_buf[p + i] = sbit;
}
else
{
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
m_spr_coll_buf[p + i] = sbit;
}
}
@@ -2251,12 +2199,12 @@ void mos6566_device::draw_sprites()
if (SPRITE_PRIORITY(snum))
{
if (m_fore_coll_buf[p + i] == 0)
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
m_spr_coll_buf[p + i] = sbit;
}
else
{
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
m_spr_coll_buf[p + i] = sbit;
}
}
@@ -2282,12 +2230,12 @@ void mos6566_device::draw_sprites()
if (SPRITE_PRIORITY(snum))
{
if (m_fore_coll_buf[p + i] == 0)
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
m_spr_coll_buf[p + i] = sbit;
}
else
{
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
m_spr_coll_buf[p + i] = sbit;
}
}
@@ -2308,12 +2256,12 @@ void mos6566_device::draw_sprites()
if (SPRITE_PRIORITY(snum))
{
if (m_fore_coll_buf[p + i] == 0)
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
m_spr_coll_buf[p + i] = sbit;
}
else
{
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
m_spr_coll_buf[p + i] = sbit;
}
}
@@ -2363,12 +2311,12 @@ void mos6566_device::draw_sprites()
if (SPRITE_PRIORITY(snum))
{
if (m_fore_coll_buf[p + i] == 0)
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
m_spr_coll_buf[p + i] = sbit;
}
else
{
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[col];
m_spr_coll_buf[p + i] = sbit;
}
}
@@ -2393,12 +2341,12 @@ void mos6566_device::draw_sprites()
if (SPRITE_PRIORITY(snum))
{
if (m_fore_coll_buf[p + i] == 0)
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
m_spr_coll_buf[p + i] = sbit;
}
else
{
- m_bitmap.pix32(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
+ m_bitmap.pix(VIC2_RASTER_2_EMU(m_rasterline), p + i) = PALETTE_MOS[color];
m_spr_coll_buf[p + i] = sbit;
}
}
diff --git a/src/devices/video/msm6255.cpp b/src/devices/video/msm6255.cpp
index f7f0ee2928a..de34d079cde 100644
--- a/src/devices/video/msm6255.cpp
+++ b/src/devices/video/msm6255.cpp
@@ -328,9 +328,7 @@ void msm6255_device::draw_scanline(bitmap_ind16 &bitmap, const rectangle &clipre
uint8_t cpd = m_cpr & CPR_CPD_MASK;
uint16_t car = (m_cur << 8) | m_clr;
- int sx, x;
-
- for (sx = 0; sx < hn; sx++)
+ for (int sx = 0; sx < hn; sx++)
{
uint8_t data = read_byte(ma, ra);
@@ -345,9 +343,9 @@ void msm6255_device::draw_scanline(bitmap_ind16 &bitmap, const rectangle &clipre
}
}
- for (x = 0; x < hp; x++)
+ for (int x = 0; x < hp; x++)
{
- bitmap.pix16(y, (sx * hp) + x) = BIT(data, 7);
+ bitmap.pix(y, (sx * hp) + x) = BIT(data, 7);
data <<= 1;
}
diff --git a/src/devices/video/nt7534.cpp b/src/devices/video/nt7534.cpp
index e777aac55dc..15fd1fb41e5 100644
--- a/src/devices/video/nt7534.cpp
+++ b/src/devices/video/nt7534.cpp
@@ -148,7 +148,7 @@ uint32_t nt7534_device::screen_update(screen_device &screen, bitmap_ind16 &bitma
{
uint8_t py = (y + m_display_start_line - 32) % 65;
uint8_t page = py/8;
- bitmap.pix16(y, x) = BIT(m_ddram[page*132 + px], py%8);
+ bitmap.pix(y, x) = BIT(m_ddram[page*132 + px], py%8);
}
}
diff --git a/src/devices/video/pc_vga.cpp b/src/devices/video/pc_vga.cpp
index 33f2f48d999..9f0bf5c48a7 100644
--- a/src/devices/video/pc_vga.cpp
+++ b/src/devices/video/pc_vga.cpp
@@ -449,42 +449,37 @@ uint32_t vga_device::start_addr()
void vga_device::vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t ch, attr;
- uint8_t bits;
- uint32_t font_base;
- uint32_t *bitmapline;
int width=VGA_CH_WIDTH, height = (vga.crtc.maximum_scan_line) * (vga.crtc.scan_doubling + 1);
- int pos, line, column, mask, w, h, addr;
- uint8_t blink_en,fore_col,back_col;
- pen_t pen;
if(vga.crtc.cursor_enable)
vga.cursor.visible = screen().frame_number() & 0x10;
else
vga.cursor.visible = 0;
- for (addr = vga.crtc.start_addr, line = -vga.crtc.preset_row_scan; line < TEXT_LINES;
+ for (int addr = vga.crtc.start_addr, line = -vga.crtc.preset_row_scan; line < TEXT_LINES;
line += height, addr += (offset()>>1))
{
- for (pos = addr, column=0; column<TEXT_COLUMNS; column++, pos++)
+ for (int pos = addr, column=0; column<TEXT_COLUMNS; column++, pos++)
{
- ch = vga.memory[(pos<<1) + 0];
- attr = vga.memory[(pos<<1) + 1];
- font_base = 0x20000+(ch<<5);
+ uint8_t ch = vga.memory[(pos<<1) + 0];
+ uint8_t attr = vga.memory[(pos<<1) + 1];
+ uint32_t font_base = 0x20000+(ch<<5);
font_base += ((attr & 8) ? vga.sequencer.char_sel.A : vga.sequencer.char_sel.B)*0x2000;
- blink_en = (vga.attribute.data[0x10]&8&&screen().frame_number() & 0x20) ? attr & 0x80 : 0;
+ uint8_t blink_en = (vga.attribute.data[0x10]&8&&screen().frame_number() & 0x20) ? attr & 0x80 : 0;
- fore_col = attr & 0xf;
- back_col = (attr & 0x70) >> 4;
+ uint8_t fore_col = attr & 0xf;
+ uint8_t back_col = (attr & 0x70) >> 4;
back_col |= (vga.attribute.data[0x10]&8) ? 0 : ((attr & 0x80) >> 4);
- for (h = std::max(-line, 0); (h < height) && (line+h < std::min(TEXT_LINES, bitmap.height())); h++)
+ for (int h = std::max(-line, 0); (h < height) && (line+h < std::min(TEXT_LINES, bitmap.height())); h++)
{
- bitmapline = &bitmap.pix32(line+h);
- bits = vga.memory[font_base+(h>>(vga.crtc.scan_doubling))];
+ uint32_t *const bitmapline = &bitmap.pix(line+h);
+ uint8_t bits = vga.memory[font_base+(h>>(vga.crtc.scan_doubling))];
+ int mask, w;
for (mask=0x80, w=0; (w<width)&&(w<8); w++, mask>>=1)
{
+ pen_t pen;
if (bits&mask)
pen = vga.pens[blink_en ? back_col : fore_col];
else
@@ -498,6 +493,7 @@ void vga_device::vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
if (w<width)
{
/* 9 column */
+ pen_t pen;
if (TEXT_COPY_9COLUMN(ch)&&(bits&1))
pen = vga.pens[blink_en ? back_col : fore_col];
else
@@ -510,7 +506,7 @@ void vga_device::vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
}
if (vga.cursor.visible&&(pos==vga.crtc.cursor_addr))
{
- for (h=vga.crtc.cursor_scan_start;
+ for (int h=vga.crtc.cursor_scan_start;
(h<=vga.crtc.cursor_scan_end)&&(h<height)&&(line+h<TEXT_LINES);
h++)
{
@@ -525,34 +521,29 @@ void vga_device::vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void vga_device::vga_vh_ega(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int pos, line, column, c, addr, i, yi;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- uint32_t *bitmapline;
- pen_t pen;
int pel_shift = (vga.attribute.pel_shift & 7);
// popmessage("%08x %02x",EGA_START_ADDRESS,pel_shift);
/**/
- for (addr=EGA_START_ADDRESS, pos=0, line=0; line<LINES;
- line += height, addr += offset())
+ for (int addr=EGA_START_ADDRESS, line=0; line<LINES; line += height, addr += offset())
{
- for(yi=0;yi<height;yi++)
+ for (int yi=0;yi<height;yi++)
{
- bitmapline = &bitmap.pix32(line + yi);
+ uint32_t *const bitmapline = &bitmap.pix(line + yi);
- for (pos=addr, c=0, column=0; column<EGA_COLUMNS+1; column++, c+=8, pos=(pos+1)&0xffff)
+ for (int pos=addr, c=0, column=0; column<EGA_COLUMNS+1; column++, c+=8, pos=(pos+1)&0xffff)
{
- int data[4];
+ int data[4] = {
+ vga.memory[(pos & 0xffff)],
+ vga.memory[(pos & 0xffff)+0x10000]<<1,
+ vga.memory[(pos & 0xffff)+0x20000]<<2,
+ vga.memory[(pos & 0xffff)+0x30000]<<3 };
- data[0]=vga.memory[(pos & 0xffff)];
- data[1]=vga.memory[(pos & 0xffff)+0x10000]<<1;
- data[2]=vga.memory[(pos & 0xffff)+0x20000]<<2;
- data[3]=vga.memory[(pos & 0xffff)+0x30000]<<3;
-
- for (i = 7; i >= 0; i--)
+ for (int i = 7; i >= 0; i--)
{
- pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)];
+ pen_t pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)];
data[0]>>=1;
data[1]>>=1;
@@ -571,26 +562,21 @@ void vga_device::vga_vh_ega(bitmap_rgb32 &bitmap, const rectangle &cliprect)
/* TODO: I'm guessing that in 256 colors mode every pixel actually outputs two pixels. Is it right? */
void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int pos, line, column, c, addr, curr_addr;
- uint32_t *bitmapline;
- uint16_t mask_comp;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- int yi;
- int xi;
int pel_shift = (vga.attribute.pel_shift & 6);
int addrmask = vga.crtc.no_wrap ? -1 : 0xffff;
/* line compare is screen sensitive */
- mask_comp = 0x3ff; //| (LINES & 0x300);
+ uint16_t mask_comp = 0x3ff; //| (LINES & 0x300);
// popmessage("%02x %02x",vga.attribute.pel_shift,vga.sequencer.data[4] & 0x08);
- curr_addr = 0;
+ int curr_addr = 0;
if(!(vga.sequencer.data[4] & 0x08))
{
- for (addr = start_addr(), line=0; line<LINES; line+=height, addr+=offset(), curr_addr+=offset())
+ for (int addr = start_addr(), line=0; line<LINES; line+=height, addr+=offset(), curr_addr+=offset())
{
- for(yi = 0;yi < height; yi++)
+ for(int yi = 0;yi < height; yi++)
{
if((line + yi) < (vga.crtc.line_compare & mask_comp))
curr_addr = addr;
@@ -599,15 +585,15 @@ void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect)
curr_addr = 0;
pel_shift = 0;
}
- bitmapline = &bitmap.pix32(line + yi);
- for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS+1; column++, c+=8, pos++)
+ uint32_t *const bitmapline = &bitmap.pix(line + yi);
+ for (int pos=curr_addr, c=0, column=0; column<VGA_COLUMNS+1; column++, c+=8, pos++)
{
if(pos > 0x80000/4)
return;
- for(xi=0;xi<8;xi++)
+ for(int xi=0;xi<8;xi++)
{
- if(!screen().visible_area().contains(c+xi-(pel_shift), line + yi))
+ if (!screen().visible_area().contains(c+xi-(pel_shift), line + yi))
continue;
bitmapline[c+xi-(pel_shift)] = pen(vga.memory[(pos & addrmask)+((xi >> 1)*0x10000)]);
}
@@ -617,22 +603,22 @@ void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect)
}
else
{
- for (addr = start_addr(), line=0; line<LINES; line+=height, addr+=offset(), curr_addr+=offset())
+ for (int addr = start_addr(), line=0; line<LINES; line+=height, addr+=offset(), curr_addr+=offset())
{
- for(yi = 0;yi < height; yi++)
+ for(int yi = 0;yi < height; yi++)
{
if((line + yi) < (vga.crtc.line_compare & mask_comp))
curr_addr = addr;
if((line + yi) == (vga.crtc.line_compare & mask_comp))
curr_addr = 0;
- bitmapline = &bitmap.pix32(line + yi);
+ uint32_t *const bitmapline = &bitmap.pix(line + yi);
//addr %= 0x80000;
- for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS+1; column++, c+=0x10, pos+=0x8)
+ for (int pos=curr_addr, c=0, column=0; column<VGA_COLUMNS+1; column++, c+=0x10, pos+=0x8)
{
if(pos + 0x08 > 0x80000)
return;
- for(xi=0;xi<0x10;xi++)
+ for (int xi=0;xi<0x10;xi++)
{
if(!screen().visible_area().contains(c+xi-(pel_shift), line + yi))
continue;
@@ -646,28 +632,23 @@ void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void vga_device::vga_vh_cga(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *bitmapline;
int height = (vga.crtc.scan_doubling + 1);
- int x,xi,y,yi;
- uint32_t addr;
- pen_t pen;
- int width;
- width = (vga.crtc.horz_disp_end + 1) * 8;
+ int width = (vga.crtc.horz_disp_end + 1) * 8;
- for(y=0;y<LINES;y++)
+ for(int y=0;y<LINES;y++)
{
- addr = ((y & 1) * 0x2000) + (((y & ~1) >> 1) * width/4);
+ uint32_t addr = ((y & 1) * 0x2000) + (((y & ~1) >> 1) * width/4);
- for(x=0;x<width;x+=4)
+ for(int x=0;x<width;x+=4)
{
- for(yi=0;yi<height;yi++)
+ for(int yi=0;yi<height;yi++)
{
- bitmapline = &bitmap.pix32(y * height + yi);
+ uint32_t *const bitmapline = &bitmap.pix(y * height + yi);
- for(xi=0;xi<4;xi++)
+ for(int xi=0;xi<4;xi++)
{
- pen = vga.pens[(vga.memory[addr] >> (6-xi*2)) & 3];
+ pen_t pen = vga.pens[(vga.memory[addr] >> (6-xi*2)) & 3];
if(!screen().visible_area().contains(x+xi, y * height + yi))
continue;
bitmapline[x+xi] = pen;
@@ -681,28 +662,23 @@ void vga_device::vga_vh_cga(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void vga_device::vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *bitmapline;
int height = (vga.crtc.scan_doubling + 1);
- int x,xi,y,yi;
- uint32_t addr;
- pen_t pen;
- int width;
- width = (vga.crtc.horz_disp_end + 1) * 8;
+ int width = (vga.crtc.horz_disp_end + 1) * 8;
- for(y=0;y<LINES;y++)
+ for(int y=0;y<LINES;y++)
{
- addr = ((y & 1) * 0x2000) + (((y & ~1) >> 1) * width/8);
+ uint32_t addr = ((y & 1) * 0x2000) + (((y & ~1) >> 1) * width/8);
- for(x=0;x<width;x+=8)
+ for(int x=0;x<width;x+=8)
{
- for(yi=0;yi<height;yi++)
+ for(int yi=0;yi<height;yi++)
{
- bitmapline = &bitmap.pix32(y * height + yi);
+ uint32_t *const bitmapline = &bitmap.pix(y * height + yi);
- for(xi=0;xi<8;xi++)
+ for(int xi=0;xi<8;xi++)
{
- pen = vga.pens[(vga.memory[addr] >> (7-xi)) & 1];
+ pen_t pen = vga.pens[(vga.memory[addr] >> (7-xi)) & 1];
if(!screen().visible_area().contains(x+xi, y * height + yi))
continue;
bitmapline[x+xi] = pen;
@@ -716,18 +692,12 @@ void vga_device::vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void svga_device::svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int pos, line, column, c, addr, curr_addr;
- uint32_t *bitmapline;
- uint16_t mask_comp;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- int yi;
- int xi;
- uint8_t start_shift;
-// uint16_t line_length;
/* line compare is screen sensitive */
- mask_comp = 0x3ff;
- curr_addr = 0;
+ uint16_t mask_comp = 0x3ff;
+ int curr_addr = 0;
+// uint16_t line_length;
// if(vga.crtc.dw)
// line_length = vga.crtc.offset << 3; // doubleword mode
// else
@@ -735,29 +705,27 @@ void svga_device::svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect)
// line_length = vga.crtc.offset << 4;
// }
- start_shift = (!(vga.sequencer.data[4] & 0x08)) ? 2 : 0;
+ uint8_t start_shift = (!(vga.sequencer.data[4] & 0x08)) ? 2 : 0;
+ for (int addr = VGA_START_ADDRESS << start_shift, line=0; line<LINES; line+=height, addr+=offset(), curr_addr+=offset())
{
- for (addr = VGA_START_ADDRESS << start_shift, line=0; line<LINES; line+=height, addr+=offset(), curr_addr+=offset())
+ for (int yi = 0;yi < height; yi++)
{
- for(yi = 0;yi < height; yi++)
+ if((line + yi) < (vga.crtc.line_compare & mask_comp))
+ curr_addr = addr;
+ if((line + yi) == (vga.crtc.line_compare & mask_comp))
+ curr_addr = 0;
+ uint32_t *const bitmapline = &bitmap.pix(line + yi);
+ addr %= vga.svga_intf.vram_size;
+ for (int pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=8, pos+=0x8)
{
- if((line + yi) < (vga.crtc.line_compare & mask_comp))
- curr_addr = addr;
- if((line + yi) == (vga.crtc.line_compare & mask_comp))
- curr_addr = 0;
- bitmapline = &bitmap.pix32(line + yi);
- addr %= vga.svga_intf.vram_size;
- for (pos=curr_addr, c=0, column=0; column<VGA_COLUMNS; column++, c+=8, pos+=0x8)
- {
- if(pos + 0x08 >= vga.svga_intf.vram_size)
- return;
+ if(pos + 0x08 >= vga.svga_intf.vram_size)
+ return;
- for(xi=0;xi<8;xi++)
- {
- if(!screen().visible_area().contains(c+xi, line + yi))
- continue;
- bitmapline[c+xi] = pen(vga.memory[(pos+(xi))]);
- }
+ for (int xi=0;xi<8;xi++)
+ {
+ if(!screen().visible_area().contains(c+xi, line + yi))
+ continue;
+ bitmapline[c+xi] = pen(vga.memory[(pos+(xi))]);
}
}
}
@@ -767,38 +735,29 @@ void svga_device::svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void svga_device::svga_vh_rgb15(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
#define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8))
- #define IV 0xff000000
+ constexpr uint32_t IV = 0xff000000;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- int xi;
- int yi;
- int xm;
- int pos, line, column, c, addr, curr_addr;
-
- uint32_t *bitmapline;
-// uint16_t mask_comp;
/* line compare is screen sensitive */
-// mask_comp = 0xff | (TLINES & 0x300);
- curr_addr = 0;
- yi=0;
- for (addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=offset(), curr_addr+=offset())
+// uint16_t mask_comp = 0xff | (TLINES & 0x300);
+ int curr_addr = 0;
+ int yi=0;
+ for (int addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=offset(), curr_addr+=offset())
{
- bitmapline = &bitmap.pix32(line);
+ uint32_t *const bitmapline = &bitmap.pix(line);
addr %= vga.svga_intf.vram_size;
- for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x10)
+ for (int pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x10)
{
if(pos + 0x10 >= vga.svga_intf.vram_size)
return;
- for(xi=0,xm=0;xi<8;xi++,xm+=2)
+ for(int xi=0,xm=0;xi<8;xi++,xm+=2)
{
- int r,g,b;
-
if(!screen().visible_area().contains(c+xi, line + yi))
continue;
- r = (MV(pos+xm)&0x7c00)>>10;
- g = (MV(pos+xm)&0x03e0)>>5;
- b = (MV(pos+xm)&0x001f)>>0;
+ int r = (MV(pos+xm)&0x7c00)>>10;
+ int g = (MV(pos+xm)&0x03e0)>>5;
+ int b = (MV(pos+xm)&0x001f)>>0;
r = (r << 3) | (r & 0x7);
g = (g << 3) | (g & 0x7);
b = (b << 3) | (b & 0x7);
@@ -811,38 +770,29 @@ void svga_device::svga_vh_rgb15(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void svga_device::svga_vh_rgb16(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
#define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8))
- #define IV 0xff000000
+ constexpr uint32_t IV = 0xff000000;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- int xi;
- int yi;
- int xm;
- int pos, line, column, c, addr, curr_addr;
-
- uint32_t *bitmapline;
-// uint16_t mask_comp;
/* line compare is screen sensitive */
-// mask_comp = 0xff | (TLINES & 0x300);
- curr_addr = 0;
- yi=0;
- for (addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=offset(), curr_addr+=offset())
+// uint16_t mask_comp = 0xff | (TLINES & 0x300);
+ int curr_addr = 0;
+ int yi=0;
+ for (int addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=offset(), curr_addr+=offset())
{
- bitmapline = &bitmap.pix32(line);
+ uint32_t *const bitmapline = &bitmap.pix(line);
addr %= vga.svga_intf.vram_size;
- for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x10)
+ for (int pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x10)
{
if(pos + 0x10 >= vga.svga_intf.vram_size)
return;
- for(xi=0,xm=0;xi<8;xi++,xm+=2)
+ for (int xi=0,xm=0;xi<8;xi++,xm+=2)
{
- int r,g,b;
-
if(!screen().visible_area().contains(c+xi, line + yi))
continue;
- r = (MV(pos+xm)&0xf800)>>11;
- g = (MV(pos+xm)&0x07e0)>>5;
- b = (MV(pos+xm)&0x001f)>>0;
+ int r = (MV(pos+xm)&0xf800)>>11;
+ int g = (MV(pos+xm)&0x07e0)>>5;
+ int b = (MV(pos+xm)&0x001f)>>0;
r = (r << 3) | (r & 0x7);
g = (g << 2) | (g & 0x3);
b = (b << 3) | (b & 0x7);
@@ -855,39 +805,30 @@ void svga_device::svga_vh_rgb16(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void svga_device::svga_vh_rgb24(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
#define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16))
- #define ID 0xff000000
+ constexpr uint32_t ID = 0xff000000;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- int xi;
- int yi;
- int xm;
- int pos, line, column, c, addr, curr_addr;
- uint32_t *bitmapline;
-
-// uint16_t mask_comp;
/* line compare is screen sensitive */
-// mask_comp = 0xff | (TLINES & 0x300);
- curr_addr = 0;
- yi=0;
- for (addr = TGA_START_ADDRESS<<1, line=0; line<TLINES; line+=height, addr+=offset(), curr_addr+=offset())
+// uint16_t mask_comp = 0xff | (TLINES & 0x300);
+ int curr_addr = 0;
+ int yi=0;
+ for (int addr = TGA_START_ADDRESS<<1, line=0; line<TLINES; line+=height, addr+=offset(), curr_addr+=offset())
{
- bitmapline = &bitmap.pix32(line);
+ uint32_t *const bitmapline = &bitmap.pix(line);
addr %= vga.svga_intf.vram_size;
- for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=24)
+ for (int pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=24)
{
if(pos + 24 >= vga.svga_intf.vram_size)
return;
- for(xi=0,xm=0;xi<8;xi++,xm+=3)
+ for (int xi=0,xm=0;xi<8;xi++,xm+=3)
{
- int r,g,b;
-
if(!screen().visible_area().contains(c+xi, line + yi))
continue;
- r = (MD(pos+xm)&0xff0000)>>16;
- g = (MD(pos+xm)&0x00ff00)>>8;
- b = (MD(pos+xm)&0x0000ff)>>0;
- bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0);
+ int r = (MD(pos+xm)&0xff0000)>>16;
+ int g = (MD(pos+xm)&0x00ff00)>>8;
+ int b = (MD(pos+xm)&0x0000ff)>>0;
+ bitmapline[c+xi] = ID|(r<<16)|(g<<8)|(b<<0);
}
}
}
@@ -896,39 +837,32 @@ void svga_device::svga_vh_rgb24(bitmap_rgb32 &bitmap, const rectangle &cliprect)
void svga_device::svga_vh_rgb32(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
#define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16))
- #define ID 0xff000000
+ constexpr uint32_t ID = 0xff000000;
int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1);
- int xi;
- int yi;
- int xm;
- int pos, line, column, c, addr, curr_addr;
- uint32_t *bitmapline;
// uint16_t mask_comp;
/* line compare is screen sensitive */
// mask_comp = 0xff | (TLINES & 0x300);
- curr_addr = 0;
- yi=0;
- for (addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=(offset()), curr_addr+=(offset()))
+ int curr_addr = 0;
+ int yi=0;
+ for (int addr = TGA_START_ADDRESS, line=0; line<TLINES; line+=height, addr+=(offset()), curr_addr+=(offset()))
{
- bitmapline = &bitmap.pix32(line);
+ uint32_t *const bitmapline = &bitmap.pix(line);
addr %= vga.svga_intf.vram_size;
- for (pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x20)
+ for (int pos=addr, c=0, column=0; column<TGA_COLUMNS; column++, c+=8, pos+=0x20)
{
if(pos + 0x20 >= vga.svga_intf.vram_size)
return;
- for(xi=0,xm=0;xi<8;xi++,xm+=4)
+ for (int xi=0,xm=0;xi<8;xi++,xm+=4)
{
- int r,g,b;
-
if(!screen().visible_area().contains(c+xi, line + yi))
continue;
- r = (MD(pos+xm)&0xff0000)>>16;
- g = (MD(pos+xm)&0x00ff00)>>8;
- b = (MD(pos+xm)&0x0000ff)>>0;
- bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0);
+ int r = (MD(pos+xm)&0xff0000)>>16;
+ int g = (MD(pos+xm)&0x00ff00)>>8;
+ int b = (MD(pos+xm)&0x0000ff)>>0;
+ bitmapline[c+xi] = ID|(r<<16)|(g<<8)|(b<<0);
}
}
}
@@ -936,13 +870,11 @@ void svga_device::svga_vh_rgb32(bitmap_rgb32 &bitmap, const rectangle &cliprect)
uint8_t vga_device::pc_vga_choosevideomode()
{
- int i;
-
if (vga.crtc.sync_en)
{
if (vga.dac.dirty)
{
- for (i=0; i<256;i++)
+ for (int i=0; i<256;i++)
{
/* TODO: color shifters? */
set_pen_color(i, (vga.dac.color[3*(i & vga.dac.mask)] & 0x3f) << 2,
@@ -954,7 +886,7 @@ uint8_t vga_device::pc_vga_choosevideomode()
if (vga.attribute.data[0x10] & 0x80)
{
- for (i=0; i<16;i++)
+ for (int i=0; i<16;i++)
{
vga.pens[i] = pen((vga.attribute.data[i]&0x0f)
|((vga.attribute.data[0x14]&0xf)<<4));
@@ -962,7 +894,7 @@ uint8_t vga_device::pc_vga_choosevideomode()
}
else
{
- for (i=0; i<16;i++)
+ for (int i=0; i<16;i++)
{
vga.pens[i] = pen((vga.attribute.data[i]&0x3f)
|((vga.attribute.data[0x14]&0xc)<<4));
@@ -997,13 +929,11 @@ uint8_t vga_device::pc_vga_choosevideomode()
uint8_t svga_device::pc_vga_choosevideomode()
{
- int i;
-
if (vga.crtc.sync_en)
{
if (vga.dac.dirty)
{
- for (i=0; i<256;i++)
+ for (int i=0; i<256;i++)
{
/* TODO: color shifters? */
set_pen_color(i, (vga.dac.color[3*(i & vga.dac.mask)] & 0x3f) << 2,
@@ -1015,7 +945,7 @@ uint8_t svga_device::pc_vga_choosevideomode()
if (vga.attribute.data[0x10] & 0x80)
{
- for (i=0; i<16;i++)
+ for (int i=0; i<16;i++)
{
vga.pens[i] = pen((vga.attribute.data[i]&0x0f)
|((vga.attribute.data[0x14]&0xf)<<4));
@@ -1023,7 +953,7 @@ uint8_t svga_device::pc_vga_choosevideomode()
}
else
{
- for (i=0; i<16;i++)
+ for (int i=0; i<16;i++)
{
vga.pens[i] = pen((vga.attribute.data[i]&0x3f)
|((vga.attribute.data[0x14]&0xc)<<4));
@@ -1132,32 +1062,26 @@ uint32_t svga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
uint32_t s3_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t cur_mode;
-
svga_device::screen_update(screen, bitmap, cliprect);
- cur_mode = pc_vga_choosevideomode();
+ uint8_t cur_mode = pc_vga_choosevideomode();
// draw hardware graphics cursor
// TODO: support 16 bit and greater video modes
if(s3.cursor_mode & 0x01) // if cursor is enabled
{
- uint32_t src;
- uint32_t* dst;
- uint8_t val;
- int x,y;
uint16_t cx = s3.cursor_x & 0x07ff;
uint16_t cy = s3.cursor_y & 0x07ff;
- uint32_t bg_col;
- uint32_t fg_col;
- int r,g,b;
- uint32_t datax;
if(cur_mode == SCREEN_OFF || cur_mode == TEXT_MODE || cur_mode == MONO_MODE || cur_mode == CGA_MODE || cur_mode == EGA_MODE)
return 0; // cursor only works in VGA or SVGA modes
- src = s3.cursor_start_addr * 1024; // start address is in units of 1024 bytes
+ uint32_t src = s3.cursor_start_addr * 1024; // start address is in units of 1024 bytes
+ uint32_t bg_col;
+ uint32_t fg_col;
+ int r,g,b;
+ uint32_t datax;
switch(cur_mode)
{
case RGB15_MODE:
@@ -1204,16 +1128,16 @@ uint32_t s3_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma
// ,(s3.cursor_fg[0])|(s3.cursor_fg[1]<<8)|(s3.cursor_fg[2]<<16)|(s3.cursor_fg[3]<<24));
// for(x=0;x<64;x++)
// printf("%08x: %02x %02x %02x %02x\n",src+x*4,vga.memory[src+x*4],vga.memory[src+x*4+1],vga.memory[src+x*4+2],vga.memory[src+x*4+3]);
- for(y=0;y<64;y++)
+ for(int y=0;y<64;y++)
{
if(cy + y < cliprect.max_y && cx < cliprect.max_x)
{
- dst = &bitmap.pix32(cy + y, cx);
- for(x=0;x<64;x++)
+ uint32_t *const dst = &bitmap.pix(cy + y, cx);
+ for(int x=0;x<64;x++)
{
uint16_t bita = (vga.memory[(src+1) % vga.svga_intf.vram_size] | ((vga.memory[(src+0) % vga.svga_intf.vram_size]) << 8)) >> (15-(x % 16));
uint16_t bitb = (vga.memory[(src+3) % vga.svga_intf.vram_size] | ((vga.memory[(src+2) % vga.svga_intf.vram_size]) << 8)) >> (15-(x % 16));
- val = ((bita & 0x01) << 1) | (bitb & 0x01);
+ uint8_t val = ((bita & 0x01) << 1) | (bitb & 0x01);
if(s3.extended_dac_ctrl & 0x10)
{ // X11 mode
switch(val)
diff --git a/src/devices/video/ppu2c0x.cpp b/src/devices/video/ppu2c0x.cpp
index bad650cf0a6..d769ff54162 100644
--- a/src/devices/video/ppu2c0x.cpp
+++ b/src/devices/video/ppu2c0x.cpp
@@ -30,37 +30,6 @@
#include "screen.h"
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* default monochromatic colortable */
-static const pen_t default_colortable_mono[] =
-{
- 0,1,2,3,
- 0,1,2,3,
- 0,1,2,3,
- 0,1,2,3,
- 0,1,2,3,
- 0,1,2,3,
- 0,1,2,3,
- 0,1,2,3,
-};
-
-/* default colortable */
-static const pen_t default_colortable[] =
-{
- 0,1,2,3,
- 0,5,6,7,
- 0,9,10,11,
- 0,13,14,15,
- 0,17,18,19,
- 0,21,22,23,
- 0,25,26,27,
- 0,29,30,31,
-};
-
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -119,7 +88,6 @@ ppu2c0x_device::ppu2c0x_device(const machine_config& mconfig, device_type type,
device_t(mconfig, type, tag, owner, clock),
device_memory_interface(mconfig, *this),
device_video_interface(mconfig, *this),
- device_palette_interface(mconfig, *this),
m_space_config("videoram", ENDIANNESS_LITTLE, 8, 17, 0, internal_map),
m_cpu(*this, finder_base::DUMMY_TAG),
m_scanline(0), // reset the scanline count
@@ -234,7 +202,7 @@ ppu2c05_04_device::ppu2c05_04_device(const machine_config& mconfig, const char*
// device_start - device-specific startup
//-------------------------------------------------
-void ppu2c0x_device::device_start()
+void ppu2c0x_device::start_nopalram()
{
// bind our handler
m_int_callback.resolve_safe();
@@ -252,25 +220,8 @@ void ppu2c0x_device::device_start()
/* allocate a screen bitmap, videomem and spriteram, a dirtychar array and the monochromatic colortable */
m_bitmap = std::make_unique<bitmap_rgb32>(VISIBLE_SCREEN_WIDTH, VISIBLE_SCREEN_HEIGHT);
m_spriteram = make_unique_clear<uint8_t[]>(SPRITERAM_SIZE);
- m_colortable = std::make_unique<pen_t[]>(ARRAY_LENGTH(default_colortable));
- m_colortable_mono = std::make_unique<pen_t[]>(ARRAY_LENGTH(default_colortable_mono));
-
- m_palette_ram.resize(0x20);
-
- for (int i = 0; i < 0x20; i++)
- m_palette_ram[i] = 0x00;
-
- /* initialize the color tables */
- for (int i = 0; i < ARRAY_LENGTH(default_colortable_mono); i++)
- {
- /* monochromatic table */
- m_colortable_mono[i] = default_colortable_mono[i];
-
- /* color table */
- m_colortable[i] = default_colortable[i];
- }
- init_palette();
+ init_palette_tables();
// register for state saving
save_item(NAME(m_scanline));
@@ -289,15 +240,25 @@ void ppu2c0x_device::device_start()
save_item(NAME(m_scanlines_per_frame));
save_item(NAME(m_vblank_first_scanline));
save_item(NAME(m_regs));
- save_item(NAME(m_palette_ram));
save_item(NAME(m_draw_phase));
save_item(NAME(m_tilecount));
save_pointer(NAME(m_spriteram), SPRITERAM_SIZE);
- save_pointer(NAME(m_colortable), ARRAY_LENGTH(default_colortable));
- save_pointer(NAME(m_colortable_mono), ARRAY_LENGTH(default_colortable_mono));
+
save_item(NAME(*m_bitmap));
}
+void ppu2c0x_device::device_start()
+{
+ start_nopalram();
+
+ m_palette_ram.resize(0x20);
+
+ for (int i = 0; i < 0x20; i++)
+ m_palette_ram[i] = 0x00;
+
+ save_item(NAME(m_palette_ram));
+}
+
//**************************************************************************
// INLINE HELPERS
//**************************************************************************
@@ -332,12 +293,49 @@ inline void ppu2c0x_device::writebyte(offs_t address, uint8_t data)
*
*************************************/
-void ppu2c0x_device::init_palette()
+void ppu2c0x_device::apply_color_emphasis_and_clamp(bool is_pal_or_dendy, int color_emphasis, double& R, double& G, double& B)
{
- init_palette(false);
+ if (is_pal_or_dendy) // PAL machines swap the colour emphasis bits, this means the red/blue highlighting on rampart tally bar doesn't look as good
+ {
+ color_emphasis = bitswap<3>(color_emphasis, 2, 0, 1);
+ }
+
+ double r_mod = 0.0;
+ double g_mod = 0.0;
+ double b_mod = 0.0;
+
+ switch (color_emphasis)
+ {
+ case 0: r_mod = 1.0; g_mod = 1.0; b_mod = 1.0; break;
+ case 1: r_mod = 1.24; g_mod = .915; b_mod = .743; break;
+ case 2: r_mod = .794; g_mod = 1.09; b_mod = .882; break;
+ case 3: r_mod = .905; g_mod = 1.03; b_mod = 1.28; break;
+ case 4: r_mod = .741; g_mod = .987; b_mod = 1.0; break;
+ case 5: r_mod = 1.02; g_mod = .908; b_mod = .979; break;
+ case 6: r_mod = 1.02; g_mod = .98; b_mod = .653; break;
+ case 7: r_mod = .75; g_mod = .75; b_mod = .75; break;
+ }
+
+ R = R * r_mod;
+ G = G * g_mod;
+ B = B * b_mod;
+
+ /* Clipping, in case of saturation */
+ if (R < 0)
+ R = 0;
+ if (R > 255)
+ R = 255;
+ if (G < 0)
+ G = 0;
+ if (G > 255)
+ G = 255;
+ if (B < 0)
+ B = 0;
+ if (B > 255)
+ B = 255;
}
-rgb_t ppu2c0x_device::nespal_to_RGB(int color_intensity, int color_num)
+rgb_t ppu2c0x_device::nespal_to_RGB(int color_intensity, int color_num, int color_emphasis, bool is_pal_or_dendy)
{
const double tint = 0.22; /* adjust to taste */
const double hue = 287.0;
@@ -390,25 +388,15 @@ rgb_t ppu2c0x_device::nespal_to_RGB(int color_intensity, int color_num)
double G = (y - (Kb * Ku * u + Kr * Kv * v) / (1 - Kb - Kr)) * 255.0;
double B = (y + Ku * u) * 255.0;
- /* Clipping, in case of saturation */
- if (R < 0)
- R = 0;
- if (R > 255)
- R = 255;
- if (G < 0)
- G = 0;
- if (G > 255)
- G = 255;
- if (B < 0)
- B = 0;
- if (B > 255)
- B = 255;
+ apply_color_emphasis_and_clamp(is_pal_or_dendy, color_emphasis, R, G, B);
return rgb_t(floor(R + .5), floor(G + .5), floor(B + .5));
}
-void ppu2c0x_device::init_palette(bool indirect)
+void ppu2c0x_device::init_palette_tables()
{
+ bool is_pal = m_scanlines_per_frame != NTSC_SCANLINES_PER_FRAME;
+
/* This routine builds a palette using a transformation from */
/* the YUV (Y, B-Y, R-Y) to the RGB color space */
@@ -421,45 +409,23 @@ void ppu2c0x_device::init_palette(bool indirect)
/* Loop through the emphasis modes (8 total) */
for (int color_emphasis = 0; color_emphasis < 8; color_emphasis++)
{
- /*
- double r_mod = 0.0;
- double g_mod = 0.0;
- double b_mod = 0.0;
-
- switch (color_emphasis)
- {
- case 0: r_mod = 1.0; g_mod = 1.0; b_mod = 1.0; break;
- case 1: r_mod = 1.24; g_mod = .915; b_mod = .743; break;
- case 2: r_mod = .794; g_mod = 1.09; b_mod = .882; break;
- case 3: r_mod = .905; g_mod = 1.03; b_mod = 1.28; break;
- case 4: r_mod = .741; g_mod = .987; b_mod = 1.0; break;
- case 5: r_mod = 1.02; g_mod = .908; b_mod = .979; break;
- case 6: r_mod = 1.02; g_mod = .98; b_mod = .653; break;
- case 7: r_mod = .75; g_mod = .75; b_mod = .75; break;
- }
- */
-
/* loop through the 4 intensities */
for (int color_intensity = 0; color_intensity < 4; color_intensity++)
{
/* loop through the 16 colors */
for (int color_num = 0; color_num < 16; color_num++)
{
- rgb_t col = nespal_to_RGB(color_intensity, color_num);
+ rgb_t col = nespal_to_RGB(color_intensity, color_num, color_emphasis, is_pal);
+
+ m_nespens[entry] = (uint32_t)col;
+ entry++;
- /* Round, and set the value */
- if (indirect)
- set_indirect_color(entry++, col);
- else
- set_pen_color(entry++, col);
}
}
}
-
- /* color tables are modified at run-time, and are initialized on 'ppu2c0x_reset' */
}
-void ppu2c0x_rgb_device::init_palette()
+void ppu2c0x_rgb_device::init_palette_tables()
{
/* Loop through the emphasis modes (8 total) */
int entry = 0;
@@ -471,27 +437,14 @@ void ppu2c0x_rgb_device::init_palette()
int G = ((color_emphasis & 2) ? 7 : m_palette_data[color_num * 3 + 1]);
int B = ((color_emphasis & 4) ? 7 : m_palette_data[color_num * 3 + 2]);
- set_pen_color(entry++, pal3bit(R), pal3bit(G), pal3bit(B));
+ m_nespens[entry] = (pal3bit(R)<<16) | (pal3bit(G)<<8) | pal3bit(B);
+
+ //set_pen_color(entry++, pal3bit(R), pal3bit(G), pal3bit(B));
+ entry++;
}
}
-
- /* color tables are modified at run-time, and are initialized on 'ppu2c0x_reset' */
}
-#if 0
-/* the charlayout we use for the chargen */
-static const gfx_layout ppu_charlayout =
-{
- 8, 8, /* 8*8 characters */
- 0,
- 2, /* 2 bits per pixel */
- { 8*8, 0 }, /* the two bitplanes are separated */
- { 0, 1, 2, 3, 4, 5, 6, 7 },
- { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
- 16*8 /* every char takes 16 consecutive bytes */
-};
-#endif
-
/*************************************
*
* PPU Initialization and Disposal
@@ -609,24 +562,34 @@ void ppu2c0x_device::shift_tile_plane_data(uint8_t& pix)
m_planebuf[1] = m_planebuf[1] << 1;
}
-void ppu2c0x_device::draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uint32_t*& dest, const pen_t* color_table)
+void ppu2c0x_device::draw_tile_pixel(uint8_t pix, int color, uint32_t back_pen, uint32_t*& dest)
{
- pen_t pen;
+ uint32_t usepen;
if (pix)
{
- const pen_t* paldata = &color_table[4 * color];
- pen = this->pen(paldata[pix]);
+ uint8_t pen = ((4 * color) + pix) & 0x1f;
+ uint16_t palval = m_palette_ram[pen];
+
+ if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ palval &= 0x30;
+
+ // apply colour emphasis
+ palval |= ((m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) << 1);
+
+ usepen = m_nespens[palval];
}
else
{
- pen = back_pen;
+ usepen = m_nespens[back_pen];
}
- *dest = pen;
+
+
+ *dest = usepen;
}
-void ppu2c0x_device::draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, pen_t back_pen, uint32_t*& dest, const pen_t* color_table)
+void ppu2c0x_device::draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, uint32_t back_pen, uint32_t*& dest)
{
int color = (((color_byte >> color_bits) & 0x03));
@@ -640,7 +603,7 @@ void ppu2c0x_device::draw_tile(uint8_t* line_priority, int color_byte, int color
if ((start_x + i) >= 0 && (start_x + i) < VISIBLE_SCREEN_WIDTH)
{
- draw_tile_pixel(pix, color, back_pen, dest, color_table);
+ draw_tile_pixel(pix, color, back_pen, dest);
// priority marking
if (pix)
@@ -659,24 +622,6 @@ void ppu2c0x_device::draw_background(uint8_t* line_priority)
{
bitmap_rgb32& bitmap = *m_bitmap;
- uint8_t color_mask;
- const pen_t* color_table;
-
- /* setup the color mask and colortable to use */
- if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
- {
- color_mask = 0xf0;
- color_table = m_colortable_mono.get();
- }
- else
- {
- color_mask = 0xff;
- color_table = m_colortable.get();
- }
-
- /* cache the background pen */
- pen_t back_pen = pen(m_back_color & color_mask);
-
/* determine where in the nametable to start drawing from */
/* based on the current scanline and scroll regs */
uint8_t scroll_x_coarse = m_refresh_data & 0x001f;
@@ -691,7 +636,7 @@ void ppu2c0x_device::draw_background(uint8_t* line_priority)
/* set up dest */
int start_x = (m_x_fine ^ 0x07) - 7;
- uint32_t* dest = &bitmap.pix32(m_scanline, start_x);
+ uint32_t* dest = &bitmap.pix(m_scanline, start_x);
m_tilecount = 0;
@@ -730,7 +675,7 @@ void ppu2c0x_device::draw_background(uint8_t* line_priority)
// plus something that accounts for y
address += scroll_y_fine;
- draw_tile(line_priority, color_byte, color_bits, address, start_x, back_pen, dest, color_table);
+ draw_tile(line_priority, color_byte, color_bits, address, start_x, m_back_color, dest);
start_x += 8;
@@ -748,28 +693,32 @@ void ppu2c0x_device::draw_background(uint8_t* line_priority)
/* if the left 8 pixels for the background are off, blank 'em */
if (!(m_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND_L8))
{
- dest = &bitmap.pix32(m_scanline);
+ dest = &bitmap.pix(m_scanline);
for (int i = 0; i < 8; i++)
{
- *(dest++) = back_pen;
+ draw_back_pen(dest, m_back_color);
+ dest++;
+
line_priority[i] ^= 0x02;
}
}
}
+void ppu2c0x_device::draw_back_pen(uint32_t* dst, int back_pen)
+{
+ *dst = m_nespens[back_pen];
+}
+
void ppu2c0x_device::draw_background_pen()
{
bitmap_rgb32& bitmap = *m_bitmap;
/* setup the color mask and colortable to use */
- uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0xf0 : 0xff;
-
- /* cache the background pen */
- pen_t back_pen = pen(m_back_color & color_mask);
+ uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0x30 : 0x3f;
// Fill this scanline with the background pen.
for (int i = 0; i < bitmap.width(); i++)
- bitmap.pix32(m_scanline, i) = back_pen;
+ draw_back_pen(&bitmap.pix(m_scanline, i), m_back_color & color_mask);
}
void ppu2c0x_device::read_sprite_plane_data(int address)
@@ -796,8 +745,16 @@ void ppu2c0x_device::make_sprite_pixel_data(uint8_t& pixel_data, int flipx)
void ppu2c0x_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32& bitmap)
{
- const pen_t* paldata = &m_colortable[4 * color];
- bitmap.pix32(m_scanline, sprite_xpos + pixel) = pen(paldata[pixel_data]);
+ uint16_t palval = m_palette_ram[((4 * color) | pixel_data) & 0x1f];
+
+ if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ palval &= 0x30;
+
+ // apply colour emphasis
+ palval |= ((m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) << 1);
+
+ uint32_t pix = m_nespens[palval];
+ bitmap.pix(m_scanline, sprite_xpos + pixel) = pix;
}
void ppu2c0x_device::read_extra_sprite_bits(int sprite_index)
@@ -1074,12 +1031,14 @@ void ppu2c0x_device::update_visible_enabled_scanline()
void ppu2c0x_device::update_visible_disabled_scanline()
{
bitmap_rgb32& bitmap = *m_bitmap;
- pen_t back_pen;
+ uint32_t back_pen;
/* setup the color mask and colortable to use */
- uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0xf0 : 0xff;
+ uint8_t color_mask = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO) ? 0x30 : 0x3f;
+
+ uint16_t palval = m_back_color & color_mask;
- back_pen = pen(m_back_color & color_mask);
+ back_pen = palval;
if (m_paletteram_in_ppuspace)
{
@@ -1092,13 +1051,13 @@ void ppu2c0x_device::update_visible_disabled_scanline()
// pen. Micro Machines makes use of this feature.
int pen_num = m_palette_ram[(m_videomem_addr & 0x03) ? (m_videomem_addr & 0x1f) : 0];
- back_pen = pen(pen_num);
+ back_pen = pen_num;
}
}
// Fill this scanline with the background pen.
for (int i = 0; i < bitmap.width(); i++)
- bitmap.pix32(m_scanline, i) = back_pen;
+ draw_back_pen(&bitmap.pix(m_scanline, i), back_pen);
}
void ppu2c0x_device::update_visible_scanline()
@@ -1135,29 +1094,20 @@ void ppu2c0x_device::update_scanline()
void ppu2c0x_device::palette_write(offs_t offset, uint8_t data)
{
- int color_emphasis = (m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) * 2;
-
// palette RAM is only 6 bits wide
data &= 0x3f;
- // transparent pens are mirrored!
if (offset & 0x3)
{
+ // regular pens, no mirroring
m_palette_ram[offset & 0x1f] = data;
- m_colortable[offset & 0x1f] = data + color_emphasis;
- m_colortable_mono[offset & 0x1f] = (data & 0xf0) + color_emphasis;
}
else
{
- int i;
+ // transparent pens are mirrored!
if (0 == (offset & 0xf))
{
m_back_color = data;
- for (i = 0; i < 32; i += 4)
- {
- m_colortable[i] = data + color_emphasis;
- m_colortable_mono[i] = (data & 0xf0) + color_emphasis;
- }
}
m_palette_ram[offset & 0xf] = m_palette_ram[(offset & 0xf) + 0x10] = data;
}
@@ -1279,18 +1229,6 @@ void ppu2c0x_device::write(offs_t offset, uint8_t data)
break;
case PPU_CONTROL1: /* 1 */
- /* if color intensity has changed, change all the color tables to reflect them */
- if ((data & PPU_CONTROL1_COLOR_EMPHASIS) != (m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS))
- {
- int i;
- for (i = 0; i <= 0x1f; i++)
- {
- uint8_t oldColor = m_palette_ram[i];
-
- m_colortable[i] = oldColor + (data & PPU_CONTROL1_COLOR_EMPHASIS) * 2;
- }
- }
-
//logerror("control1 write: %02x (scanline: %d)\n", data, m_scanline);
m_regs[PPU_CONTROL1] = data;
break;
diff --git a/src/devices/video/ppu2c0x.h b/src/devices/video/ppu2c0x.h
index fcd53435809..9d8fa0f5351 100644
--- a/src/devices/video/ppu2c0x.h
+++ b/src/devices/video/ppu2c0x.h
@@ -42,8 +42,7 @@
class ppu2c0x_device : public device_t,
public device_memory_interface,
- public device_video_interface,
- public device_palette_interface
+ public device_video_interface
{
public:
typedef device_delegate<void (int scanline, int vblank, int blanked)> scanline_delegate;
@@ -76,16 +75,16 @@ public:
auto int_callback() { return m_int_callback.bind(); }
/* routines */
- rgb_t nespal_to_RGB(int color_intensity, int color_num);
- virtual void init_palette();
- void init_palette(bool indirect);
- virtual uint32_t palette_entries() const override { return 4*16*8; }
+ void apply_color_emphasis_and_clamp(bool is_pal_or_dendy, int color_emphasis, double& R, double& G, double& B);
+ rgb_t nespal_to_RGB(int color_intensity, int color_num, int color_emphasis, bool is_pal_or_dendy);
+ virtual void init_palette_tables();
virtual void read_tile_plane_data(int address, int color);
virtual void shift_tile_plane_data(uint8_t &pix);
- virtual void draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uint32_t *&dest, const pen_t *color_table);
- virtual void draw_tile(uint8_t *line_priority, int color_byte, int color_bits, int address, int start_x, pen_t back_pen, uint32_t *&dest, const pen_t *color_table);
+ virtual void draw_tile_pixel(uint8_t pix, int color, uint32_t back_pen, uint32_t *&dest);
+ virtual void draw_tile(uint8_t *line_priority, int color_byte, int color_bits, int address, int start_x, uint32_t back_pen, uint32_t *&dest);
virtual void draw_background( uint8_t *line_priority );
+ virtual void draw_back_pen(uint32_t* dst, int back_pen);
void draw_background_pen();
virtual void read_sprite_plane_data(int address);
@@ -131,6 +130,8 @@ public:
void set_vram_dest(uint16_t dest);
void ppu2c0x(address_map &map);
+
+ bool in_vblanking() { return (m_scanline >= m_vblank_first_scanline - 1); }
protected:
ppu2c0x_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock, address_map_constructor internal_map);
@@ -184,6 +185,8 @@ protected:
required_device<cpu_device> m_cpu;
+ void start_nopalram();
+
int m_scanlines_per_frame; /* number of scanlines per frame */
int m_security_value; /* 2C05 protection */
int m_vblank_first_scanline; /* the very first scanline where VBLANK occurs */
@@ -205,12 +208,12 @@ protected:
int m_refresh_data; /* refresh-related */
int m_x_fine; /* refresh-related */
int m_tilecount; /* MMC5 can change attributes to subsets of the 34 visible tiles */
- std::unique_ptr<pen_t[]> m_colortable; /* color table modified at run time */
- std::unique_ptr<pen_t[]> m_colortable_mono; /* monochromatic color table modified at run time */
latch_delegate m_latch;
uint8_t readbyte(offs_t address);
+
+ uint32_t m_nespens[0x40*8];
private:
static constexpr device_timer_id TIMER_HBLANK = 0;
static constexpr device_timer_id TIMER_NMI = 1;
@@ -246,7 +249,7 @@ class ppu2c0x_rgb_device : public ppu2c0x_device {
protected:
ppu2c0x_rgb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0);
- virtual void init_palette() override;
+ virtual void init_palette_tables() override;
private:
required_region_ptr<uint8_t> m_palette_data;
diff --git a/src/devices/video/ppu2c0x_sh6578.cpp b/src/devices/video/ppu2c0x_sh6578.cpp
index c74fa5e54fb..a63fa2a5162 100644
--- a/src/devices/video/ppu2c0x_sh6578.cpp
+++ b/src/devices/video/ppu2c0x_sh6578.cpp
@@ -51,12 +51,14 @@ void ppu_sh6578_device::ppu_internal_map(address_map& map)
void ppu_sh6578_device::device_start()
{
- ppu2c0x_device::device_start();
+ start_nopalram();
m_palette_ram.resize(0x40);
for (int i = 0; i < 0x40; i++)
m_palette_ram[i] = 0x00;
+
+ save_item(NAME(m_palette_ram));
}
void ppu_sh6578_device::device_reset()
@@ -89,7 +91,7 @@ void ppu_sh6578_device::scanline_increment_fine_ycounter()
void ppu_sh6578_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32& bitmap)
{
uint8_t palval = m_palette_ram[(pixel_data | color << 2)] & 0x3f;
- bitmap.pix32(m_scanline, sprite_xpos + pixel) = this->pen(palval);
+ bitmap.pix(m_scanline, sprite_xpos + pixel) = m_nespens[palval];
}
void ppu_sh6578_device::read_tile_plane_data(int address, int color)
@@ -97,15 +99,25 @@ void ppu_sh6578_device::read_tile_plane_data(int address, int color)
m_planebuf[0] = readbyte(address);
m_planebuf[1] = readbyte(address + 8);
- m_extplanebuf[0] = readbyte(address + 16);
- m_extplanebuf[1] = readbyte(address + 24);
+ if (m_colsel_pntstart & 0x80)
+ {
+ m_extplanebuf[0] = readbyte(address + 16);
+ m_extplanebuf[1] = readbyte(address + 24);
+ }
}
-void ppu_sh6578_device::draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, pen_t back_pen, uint32_t*& dest, const pen_t* color_table)
+void ppu_sh6578_device::draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, uint32_t back_pen, uint32_t*& dest)
{
int color = color_byte;
- color &= 0xc;
+ if (m_colsel_pntstart & 0x80)
+ {
+ color &= 0xc;
+ }
+ else
+ {
+ color &= 0xf;
+ }
read_tile_plane_data(address, color);
@@ -116,19 +128,29 @@ void ppu_sh6578_device::draw_tile(uint8_t* line_priority, int color_byte, int co
pix = ((m_planebuf[0] & 0x80) >> 7);
pix |= ((m_planebuf[1] & 0x80) >> 6);
- pix |= ((m_extplanebuf[0] & 0x80) >> 5);
- pix |= ((m_extplanebuf[1] & 0x80) >> 4);
+
+ if (m_colsel_pntstart & 0x80)
+ {
+ pix |= ((m_extplanebuf[0] & 0x80) >> 5);
+ pix |= ((m_extplanebuf[1] & 0x80) >> 4);
+ }
m_planebuf[0] <<= 1;
m_planebuf[1] <<= 1;
- m_extplanebuf[0] <<= 1;
- m_extplanebuf[1] <<= 1;
+
+ if (m_colsel_pntstart & 0x80)
+ {
+ m_extplanebuf[0] <<= 1;
+ m_extplanebuf[1] <<= 1;
+ }
if ((start_x + i) >= 0 && (start_x + i) < VISIBLE_SCREEN_WIDTH)
{
pen_t pen;
- uint8_t palval = m_palette_ram[(pix | color << 2)] & 0x3f;
+ uint8_t palval;
+
+ palval = m_palette_ram[(pix | color << 2)] & 0x3f;
bool trans = false;
if ((palval & 0x1f) == 0x1f)
@@ -136,12 +158,12 @@ void ppu_sh6578_device::draw_tile(uint8_t* line_priority, int color_byte, int co
if (!trans)
{
- pen = this->pen(palval);
+ pen = m_nespens[palval];
}
else
{
uint8_t palval = m_palette_ram[0x0] & 0x3f;
- pen = this->pen(palval);
+ pen = m_nespens[palval];
}
*dest = pen;
@@ -158,23 +180,24 @@ void ppu_sh6578_device::draw_background(uint8_t* line_priority)
{
bitmap_rgb32& bitmap = *m_bitmap;
- uint8_t color_mask;
- const pen_t* color_table;
+ uint8_t color_mask = 0xff;
+ //const pen_t* color_table;
/* setup the color mask and colortable to use */
+
+ //TODO FIX
if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
{
color_mask = 0xf0;
- color_table = m_colortable_mono.get();
}
else
{
color_mask = 0xff;
- color_table = m_colortable.get();
}
+
/* cache the background pen */
- pen_t back_pen = pen(m_back_color & color_mask);
+ pen_t back_pen = m_nespens[m_back_color & color_mask];
/* determine where in the nametable to start drawing from */
/* based on the current scanline and scroll regs */
@@ -190,7 +213,7 @@ void ppu_sh6578_device::draw_background(uint8_t* line_priority)
/* set up dest */
int start_x = (m_x_fine ^ 0x07) - 7;
- uint32_t* dest = &bitmap.pix32(m_scanline, start_x);
+ uint32_t* dest = &bitmap.pix(m_scanline, start_x);
m_tilecount = 0;
@@ -225,7 +248,7 @@ void ppu_sh6578_device::draw_background(uint8_t* line_priority)
// plus something that accounts for y
address += scroll_y_fine;
- draw_tile(line_priority, (color_byte >> 4) & 0xf, 0, address, start_x, back_pen, dest, color_table);
+ draw_tile(line_priority, (color_byte >> 4) & 0xf, 0, address, start_x, back_pen, dest);
start_x += 8;
@@ -243,7 +266,7 @@ void ppu_sh6578_device::draw_background(uint8_t* line_priority)
/* if the left 8 pixels for the background are off, blank 'em */
if (!(m_regs[PPU_CONTROL1] & PPU_CONTROL1_BACKGROUND_L8))
{
- dest = &bitmap.pix32(m_scanline);
+ dest = &bitmap.pix(m_scanline);
for (int i = 0; i < 8; i++)
{
*(dest++) = back_pen;
diff --git a/src/devices/video/ppu2c0x_sh6578.h b/src/devices/video/ppu2c0x_sh6578.h
index 9671bf00dfb..34448ac9dfa 100644
--- a/src/devices/video/ppu2c0x_sh6578.h
+++ b/src/devices/video/ppu2c0x_sh6578.h
@@ -33,7 +33,7 @@ private:
void scanline_increment_fine_ycounter() override;
void read_tile_plane_data(int address, int color) override;
- void draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, pen_t back_pen, uint32_t*& dest, const pen_t* color_table) override;
+ void draw_tile(uint8_t* line_priority, int color_byte, int color_bits, int address, int start_x, uint32_t back_pen, uint32_t*& dest) override;
virtual void draw_sprite_pixel(int sprite_xpos, int color, int pixel, uint8_t pixel_data, bitmap_rgb32& bitmap) override;
//virtual void draw_sprites(uint8_t* line_priority) override;
diff --git a/src/devices/video/ppu2c0x_vt.cpp b/src/devices/video/ppu2c0x_vt.cpp
index 04da1b8740b..2b8b9b6e3dd 100644
--- a/src/devices/video/ppu2c0x_vt.cpp
+++ b/src/devices/video/ppu2c0x_vt.cpp
@@ -47,14 +47,10 @@ ppu_vt03pal_device::ppu_vt03pal_device(const machine_config& mconfig, const char
uint8_t ppu_vt03_device::palette_read(offs_t offset)
{
- if (m_201x_regs[0] & 0x80)
- {
- return m_newpal[offset];
- }
- else
- {
+ if (offset < 0x20)
return ppu2c0x_device::palette_read(offset);
- }
+ else
+ return m_palette_ram[offset];
}
void ppu_vt03_device::set_201x_descramble(uint8_t reg0, uint8_t reg1, uint8_t reg2, uint8_t reg3, uint8_t reg4, uint8_t reg5)
@@ -67,110 +63,17 @@ void ppu_vt03_device::set_201x_descramble(uint8_t reg0, uint8_t reg1, uint8_t re
m_2012_2017_descramble[5] = reg5;
}
-void ppu_vt03_device::set_new_pen(int i)
-{
- if ((i < 0x20) && ((i & 0x3) == 0))
- {
- set_pen_color(i & 0x7f, rgb_t(0, 0, 0));
- }
- else
- {
- if (m_pal_mode == PAL_MODE_NEW_RGB)
- {
- uint16_t rgbval = (m_newpal[i & 0x7f] & 0xff) | ((m_newpal[(i & 0x7f) + 0x80] & 0xff) << 8);
- uint8_t blue = (rgbval & 0x001f) << 3;
- uint8_t green = (rgbval & 0x3e0) >> 2;
- uint8_t red = (rgbval & 0x7C00) >> 7;
- set_pen_color(i & 0x7f, rgb_t(red, green, blue));
- }
- else if (m_pal_mode == PAL_MODE_NEW_RGB12)
- {
- uint16_t rgbval = (m_newpal[i & 0x7f] & 0x3f) | ((m_newpal[(i & 0x7f) + 0x80] & 0x3f) << 6);
- uint8_t red = (rgbval & 0x000f) << 4;
- uint8_t green = (rgbval & 0x0f0);
- uint8_t blue = (rgbval & 0xf00) >> 4;
- set_pen_color(i & 0x7f, rgb_t(red, green, blue));
- }
- else
- {
- // Credit to NewRisingSun
- uint16_t palval = (m_newpal[i & 0x7f] & 0x3f) | ((m_newpal[(i & 0x7f) + 0x80] & 0x3f) << 6);
- int nPhase = (palval >> 0) & 0xF;
- int nLuma = (palval >> 4) & 0xF;
- int nChroma = (palval >> 8) & 0xF;
- float phaseOffset = -11.0;
- //bool inverted = false;
- if ((nLuma < (nChroma + 1) >> 1 || nLuma > 15 - (nChroma >> 1)) && (m_pal_mode != PAL_MODE_NEW_VG))
- {
- //inverted = true;
- // Strange color number wrap-around. Is this for protection reasons, or a bug of the original hardware?
- // The VT03 data sheet advises programmers that 4 <= nLuma*2 +nChroma <= 0x1F, which does not correspond exactly to this condition.
- static const unsigned char altPhases[16] = { 13, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 0, 14, 15 };
- static const float altPhaseOffset[16] = { -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, 0, -5, -5, -5 }; // Slight tweak in phase 6 for Z-Dog
- phaseOffset += altPhaseOffset[nPhase]; // These "alternative" colors seem to be slightly shifted in addition to being wrapped-around, at least in EmuVT.
- nPhase = altPhases[nPhase];
- nChroma = 16 - nChroma;
- nLuma = (nLuma - 8) & 0xF;
- }
-
- float fLuma = (nLuma - 4) / 9.625; // Value determined from matching saturation =0 phases 1-12
- float fChroma = nChroma / 18.975; // Value determined from matching phases 0 and 13 across all luminance and saturation levels
- float fPhase = ((nPhase - 2) * 30.0 + phaseOffset) * M_PI / 180.0;
-
- if (m_pal_mode == PAL_MODE_NEW_VG)
- {
- if (fPhase > 0 && fPhase < 13)
- {
- fLuma /= 1.5;
- fChroma /= 2;
- }
- }
-
- float Y = fLuma;
- float C = fChroma;
- if (nPhase == 0 || nPhase > 12) C = 0.0;// Phases 0 and 13-15 are grays
- if (nPhase == 0) Y += fChroma; // Phase 0 is the upper bound of the waveform
- if (nPhase == 13) Y -= fChroma; // Phase 13 is the lower bound of the waveform
- if (nPhase >= 14) Y = 0.0; // Phases 14 and 15 always black
-
- float V = sin(fPhase) * C * 1.05; // 1.05 needed to get closer to EmuVT palette's color levels in phases 1-12
- float U = cos(fPhase) * C * 1.05;
- float R = Y + 1.1400 * V + 0.0000 * U;
- float G = Y - 0.5807 * V - 0.3940 * U;
- float B = Y - 0.0000 * V + 2.0290 * U;
- if (R < 0.0) R = 0.0;
- if (R > 1.0) R = 1.0;
- if (G < 0.0) G = 0.0;
- if (G > 1.0) G = 1.0;
- if (B < 0.0) B = 0.0;
- if (B > 1.0) B = 1.0;
- int RV = R * 255.0;
- int GV = G * 255.0;
- int BV = B * 255.0;
-
- set_pen_color(i & 0x7f, rgb_t(RV, GV, BV));
- }
- }
-}
-
void ppu_vt03_device::palette_write(offs_t offset, uint8_t data)
{
- //logerror("pal write %d %02x\n", offset, data);
- // why is the check pal_mask = (m_pal_mode == PAL_MODE_NEW_VG) ? 0x08 : 0x80 in set_2010_reg and 0x04 : 0x80 here?
- uint8_t pal_mask = (m_pal_mode == PAL_MODE_NEW_VG) ? 0x04 : 0x80;
-
- if (m_201x_regs[0] & pal_mask)
+ if (offset < 0x20)
{
- m_newpal[offset & 0xff] = data;
- set_new_pen(offset);
+ ppu2c0x_device::palette_write(offset, data);
}
else
{
- //if(m_pal_mode == PAL_MODE_NEW_VG) // ddrdismx writes the palette before setting the register but doesn't use 'PAL_MODE_NEW_VG', Konami logo is missing if you don't allow writes to be stored for when we switch
- m_newpal[offset & 0xff] = data;
- ppu2c0x_device::palette_write(offset, data);
+ m_palette_ram[offset] = data;
}
}
@@ -235,20 +138,131 @@ uint8_t ppu_vt03_device::read_extended(offs_t offset)
}
-void ppu_vt03_device::init_palette()
+
+void ppu_vt03_device::init_vtxx_rgb555_palette_tables()
{
- // todo, work out the format of the 12 palette bits instead of just calling the main init
- ppu2c0x_device::init_palette(true);
+ int entry = 0;
+ for (int emp = 0; emp < 8; emp++)
+ {
+ for (int palval = 0; palval < 0x8000; palval++)
+ {
+ // uint16_t rgbval = (m_palette_ram[i & 0x7f] & 0xff) | ((m_palette_ram[(i & 0x7f) + 0x80] & 0xff) << 8);
+ uint8_t blue = (palval & 0x001f) << 3;
+ uint8_t green = (palval & 0x3e0) >> 2;
+ uint8_t red = (palval & 0x7C00) >> 7;
+
+ // TODO: apply emphasis values if they work in this mode
+ m_vtpens_rgb555[entry] = rgb_t(red, green, blue);
+ entry++;
+ }
+ }
+}
+
+void ppu_vt03_device::init_vtxx_rgb444_palette_tables()
+{
+ int entry = 0;
+ for (int emp = 0; emp < 8; emp++)
+ {
+ for (int palval = 0; palval < 0x1000; palval++)
+ {
+ //uint16_t rgbval = (m_palette_ram[i & 0x7f] & 0x3f) | ((m_palette_ram[(i & 0x7f) + 0x80] & 0x3f) << 6);
+ uint8_t red = (palval & 0x000f) << 4;
+ uint8_t green = (palval & 0x0f0);
+ uint8_t blue = (palval & 0xf00) >> 4;
+
+ // TODO: apply emphasis values if they work in this mode
+ m_vtpens_rgb444[entry] = rgb_t(red, green, blue);
+ entry++;
+ }
+ }
+}
+// what cases are palmode 1 anyway?
+void ppu_vt03_device::init_vt03_palette_tables(int palmode)
+{
+ // the 12-bit VT HSV format, Credit to NewRisingSun
+ int entry = 0;
+ for (int color_emphasis = 0; color_emphasis < 8; color_emphasis++)
+ {
+ for (int palval = 0; palval < 0x1000; palval++)
+ {
+ int nPhase = (palval >> 0) & 0xF;
+ int nLuma = (palval >> 4) & 0xF;
+ int nChroma = (palval >> 8) & 0xF;
+ float phaseOffset = -11.0;
+ //bool inverted = false;
+ if ((nLuma < (nChroma + 1) >> 1 || nLuma > 15 - (nChroma >> 1)) && (palmode != 1))
+ {
+ //inverted = true;
+ // Strange color number wrap-around. Is this for protection reasons, or a bug of the original hardware?
+ // The VT03 data sheet advises programmers that 4 <= nLuma*2 +nChroma <= 0x1F, which does not correspond exactly to this condition.
+ static const unsigned char altPhases[16] = { 13, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 0, 14, 15 };
+ static const float altPhaseOffset[16] = { -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, 0, -5, -5, -5 }; // Slight tweak in phase 6 for Z-Dog
+ phaseOffset += altPhaseOffset[nPhase]; // These "alternative" colors seem to be slightly shifted in addition to being wrapped-around, at least in EmuVT.
+ nPhase = altPhases[nPhase];
+ nChroma = 16 - nChroma;
+ nLuma = (nLuma - 8) & 0xF;
+ }
+
+ float fLuma = (nLuma - 4) / 9.625; // Value determined from matching saturation =0 phases 1-12
+ float fChroma = nChroma / 18.975; // Value determined from matching phases 0 and 13 across all luminance and saturation levels
+ float fPhase = ((nPhase - 2) * 30.0 + phaseOffset) * M_PI / 180.0;
+
+ if (palmode == 1)
+ {
+ if (fPhase > 0 && fPhase < 13)
+ {
+ fLuma /= 1.5;
+ fChroma /= 2;
+ }
+ }
+
+ float Y = fLuma;
+ float C = fChroma;
+ if (nPhase == 0 || nPhase > 12) C = 0.0;// Phases 0 and 13-15 are grays
+ if (nPhase == 0) Y += fChroma; // Phase 0 is the upper bound of the waveform
+ if (nPhase == 13) Y -= fChroma; // Phase 13 is the lower bound of the waveform
+ if (nPhase >= 14) Y = 0.0; // Phases 14 and 15 always black
+
+ float V = sin(fPhase) * C * 1.05; // 1.05 needed to get closer to EmuVT palette's color levels in phases 1-12
+ float U = cos(fPhase) * C * 1.05;
+ float R = Y + 1.1400 * V + 0.0000 * U;
+ float G = Y - 0.5807 * V - 0.3940 * U;
+ float B = Y - 0.0000 * V + 2.0290 * U;
+ if (R < 0.0) R = 0.0;
+ if (R > 1.0) R = 1.0;
+ if (G < 0.0) G = 0.0;
+ if (G > 1.0) G = 1.0;
+ if (B < 0.0) B = 0.0;
+ if (B > 1.0) B = 1.0;
+ int RV = R * 255.0;
+ int GV = G * 255.0;
+ int BV = B * 255.0;
+
+ // does this really apply to the VT palette?
+ //bool is_pal = m_scanlines_per_frame != NTSC_SCANLINES_PER_FRAME;
+ //apply_color_emphasis_and_clamp(is_pal, color_emphasis, R, G, B);
+
+ m_vtpens[entry] = rgb_t(RV, GV, BV);
+ entry++;
+ }
+ }
}
void ppu_vt03_device::device_start()
{
- ppu2c0x_device::device_start();
+ start_nopalram();
+
+ m_palette_ram.resize(0x100);
- m_newpal = std::make_unique<uint8_t[]>(0x100);
- save_pointer(NAME(m_newpal), 0x100);
+ for (int i = 0; i < 0x100; i++)
+ m_palette_ram[i] = 0x00;
+ save_item(NAME(m_palette_ram));
save_item(NAME(m_201x_regs));
+
+ init_vt03_palette_tables(0);
+ init_vtxx_rgb555_palette_tables();
+ init_vtxx_rgb444_palette_tables();
}
uint8_t ppu_vt03_device::get_201x_reg(int reg)
@@ -270,16 +284,12 @@ void ppu_vt03_device::device_reset()
m_read_bg.resolve_safe(0);
m_read_sp.resolve_safe(0);
for (int i = 0; i < 0xff; i++)
- m_newpal[i] = 0x0;
+ m_palette_ram[i] = 0x0;
// todo: what are the actual defaults for these?
for (int i = 0; i < 0x20; i++)
set_201x_reg(i, 0x00);
- //m_201x_regs[0] = 0x86; // alt fix for ddrdismx would be to set the default palette mode here
-
- init_palette();
-
m_read_bg4_bg3 = 0;
m_va34 = 0;
}
@@ -353,7 +363,8 @@ void ppu_vt03_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, u
{
if (!is16pix)
{
- bitmap.pix32(m_scanline, sprite_xpos + pixel) = pen(pixel_data + (4 * color));
+ uint8_t pen = pixel_data + (4 * color);
+ draw_tile_pixel_inner(pen, &bitmap.pix(m_scanline, sprite_xpos + pixel));
}
else
{
@@ -361,9 +372,16 @@ void ppu_vt03_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, u
we probably need to split them out again and draw them at xpos+8 with a
cliprect - not seen used yet */
if ((pixel_data & 0x03) != 0)
- bitmap.pix32(m_scanline, sprite_xpos + pixel) = pen((pixel_data & 0x03) + (4 * color));
+ {
+ uint8_t pen = (pixel_data & 0x03) + (4 * color);
+ draw_tile_pixel_inner(pen, &bitmap.pix(m_scanline, sprite_xpos + pixel));
+ }
+
if (((pixel_data >> 5) & 0x03) != 0)
- bitmap.pix32(m_scanline, sprite_xpos + pixel + 8) = pen(((pixel_data >> 5) & 0x03) + (4 * color));
+ {
+ uint8_t pen = ((pixel_data >> 5) & 0x03) + (4 * color);
+ draw_tile_pixel_inner(pen, &bitmap.pix(m_scanline, sprite_xpos + pixel + 8));
+ }
//ppu2c0x_device::draw_sprite_pixel(sprite_xpos, color, pixel, pixel_data & 0x03, bitmap);
//ppu2c0x_device::draw_sprite_pixel(sprite_xpos, color, pixel + 8, (pixel_data >> 5) & 0x03, bitmap);
}
@@ -414,13 +432,100 @@ void ppu_vt03_device::shift_tile_plane_data(uint8_t& pix)
}
}
-void ppu_vt03_device::draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uint32_t*& dest, const pen_t* color_table)
+
+void ppu_vt03_device::draw_back_pen(uint32_t* dst, int back_pen)
+{
+ if (m_201x_regs[0] & 0x80)
+ {
+ // is the back_pen always just pen 0 in VT modes? (using last data written to a transparent pen as per NES logic doesn't work as writes are split across 2 bytes)
+ draw_tile_pixel_inner(0, dst);
+ }
+ else
+ {
+ // in normal modes we still have the data from the palette writes as the 'backpen' so treat it as before
+ uint32_t pix;
+ pix = m_nespens[back_pen & 0x1ff];
+ *dst = pix;
+ }
+}
+
+
+void ppu_vt03_device::draw_tile_pixel_inner(uint8_t pen, uint32_t *dest)
+{
+ if (m_201x_regs[0] & 0x80)
+ {
+ if (m_pal_mode == PAL_MODE_NEW_RGB) // unknown newer VT mode
+ {
+ uint32_t palval;
+ palval = (m_palette_ram[pen & 0x7f] & 0xff) | ((m_palette_ram[(pen & 0x7f) + 0x80] & 0x7f) << 8);
+
+ // does grayscale mode exist here? (we haven't calculated any colours for it)
+ //if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ // palval &= 0x30;
+
+ // apply colour emphasis (does it really exist here?) (we haven't calculated any colours for it, so ths has no effect)
+ palval |= ((m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) << 10);
+
+ uint32_t pix;
+ pix = m_vtpens_rgb555[palval & 0x3ffff];
+ *dest = pix;
+ }
+ else if (m_pal_mode == PAL_MODE_NEW_RGB12) // unknown newer VT mode
+ {
+ uint32_t palval;
+ palval = (m_palette_ram[pen & 0x7f] & 0x3f) | ((m_palette_ram[(pen & 0x7f) + 0x80] & 0x3f) << 6);
+
+ // does grayscale mode exist here? (we haven't calculated any colours for it)
+ //if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ // palval &= 0x30;
+
+ // apply colour emphasis (does it really exist here?) (we haven't calculated any colours for it, so ths has no effect)
+ palval |= ((m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) << 7);
+
+ uint32_t pix;
+ pix = m_vtpens_rgb444[palval & 0x7fff];
+ *dest = pix;
+ }
+ else // VT03 mode
+ {
+ uint32_t palval;
+ palval = (m_palette_ram[pen & 0x7f] & 0x3f) | ((m_palette_ram[(pen & 0x7f) + 0x80] & 0x3f) << 6);
+
+ // does grayscale mode exist here? (we haven't calculated any colours for it)
+ //if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ // palval &= 0x30;
+
+ // apply colour emphasis (does it really exist here?) (we calculate values for it when building the palette lookup)
+ palval |= ((m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) << 7);
+
+ uint32_t pix;
+ pix = m_vtpens[palval & 0x7fff];
+ *dest = pix;
+ }
+ }
+ else // old colour compatible mode
+ {
+ uint16_t palval;
+ palval = (m_palette_ram[pen & 0x7f] & 0x3f);
+
+ if (m_regs[PPU_CONTROL1] & PPU_CONTROL1_DISPLAY_MONO)
+ palval &= 0x30;
+
+ // apply colour emphasis
+ palval |= ((m_regs[PPU_CONTROL1] & PPU_CONTROL1_COLOR_EMPHASIS) << 1);
+
+ uint32_t pix;
+ pix = m_nespens[palval & 0x1ff];
+ *dest = pix;
+ }
+}
+void ppu_vt03_device::draw_tile_pixel(uint8_t pix, int color, uint32_t back_pen, uint32_t*& dest)
{
int is4bpp = get_201x_reg(0x0) & 0x02;
if (!is4bpp)
{
- ppu2c0x_device::draw_tile_pixel(pix, color, back_pen, dest, color_table);
+ ppu2c0x_device::draw_tile_pixel(pix, color, back_pen, dest);
}
else
{
@@ -442,9 +547,10 @@ void ppu_vt03_device::draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, ui
}
else
{
- pen = 0; // fixme backpen logic probably differs on vt03 due to extra colours
+ pen = 0; // back_pen; // fixme backpen logic probably differs on vt03 due to extra colours
}
- *dest = this->pen(pen);
+
+ draw_tile_pixel_inner(pen, dest);
}
}
@@ -468,24 +574,6 @@ void ppu_vt03_device::set_2010_reg(uint8_t data)
2 : SP16EN
1 : BK16EN
0 : PIX16EN */
- uint8_t pal_mask = (m_pal_mode == PAL_MODE_NEW_VG) ? 0x08 : 0x80;
- if ((m_201x_regs[0x0] & pal_mask) != (data & pal_mask))
- {
- if (data & pal_mask)
- {
- for (int i = 0; i < 256; i++)
- {
- set_new_pen(i);
- }
- }
- else
- {
- for (int i = 0; i < 256; i++)
- {
- set_pen_indirect(i, i);
- }
- }
- }
m_201x_regs[0x0] = data;
}
diff --git a/src/devices/video/ppu2c0x_vt.h b/src/devices/video/ppu2c0x_vt.h
index c238f91b031..f63da1ebdf1 100644
--- a/src/devices/video/ppu2c0x_vt.h
+++ b/src/devices/video/ppu2c0x_vt.h
@@ -19,7 +19,6 @@
enum vtxx_pal_mode {
PAL_MODE_VT0x,
PAL_MODE_NEW_RGB,
- PAL_MODE_NEW_VG,
PAL_MODE_NEW_RGB12,
};
@@ -40,13 +39,15 @@ public:
virtual uint8_t palette_read(offs_t offset) override;
virtual void palette_write(offs_t offset, uint8_t data) override;
- virtual uint32_t palette_entries() const override { return 256; }
- virtual uint32_t palette_indirect_entries() const override { return 4*16*8; }
- virtual void init_palette() override;
+ void init_vt03_palette_tables(int palmode);
+ void init_vtxx_rgb555_palette_tables();
+ void init_vtxx_rgb444_palette_tables();
virtual void read_tile_plane_data(int address, int color) override;
virtual void shift_tile_plane_data(uint8_t &pix) override;
- virtual void draw_tile_pixel(uint8_t pix, int color, pen_t back_pen, uint32_t *&dest, const pen_t *color_table) override;
+ virtual void draw_tile_pixel(uint8_t pix, int color, uint32_t back_pen, uint32_t *&dest) override;
+ inline void draw_tile_pixel_inner(uint8_t pen, uint32_t *dest);
+ virtual void draw_back_pen(uint32_t* dst, int back_pen) override;
virtual void read_sprite_plane_data(int address) override;
virtual void make_sprite_pixel_data(uint8_t &pixel_data, int flipx) override;
@@ -70,12 +71,14 @@ protected:
bool m_is_pal;
bool m_is_50hz;
+ uint32_t m_vtpens[0x1000*8];
+ uint32_t m_vtpens_rgb555[0x8000*8];
+ uint32_t m_vtpens_rgb444[0x1000*8];
+
private:
devcb_read8 m_read_bg;
devcb_read8 m_read_sp;
- std::unique_ptr<uint8_t[]> m_newpal;
-
int m_read_bg4_bg3;
int m_va34;
@@ -89,8 +92,6 @@ private:
vtxx_pal_mode m_pal_mode = PAL_MODE_VT0x;
void set_2010_reg(uint8_t data);
-
- void set_new_pen(int i);
};
class ppu_vt03pal_device : public ppu_vt03_device {
diff --git a/src/devices/video/psx.cpp b/src/devices/video/psx.cpp
index 83cd0e5c02d..b73adb2a319 100644
--- a/src/devices/video/psx.cpp
+++ b/src/devices/video/psx.cpp
@@ -265,8 +265,8 @@ void psxgpu_device::DebugMesh( int n_coordx, int n_coordy )
(int16_t)n_x.w.h <= width - 1 &&
(int16_t)n_y.w.h <= height - 1 )
{
- if( m_debug.mesh->pix16( n_y.w.h, n_x.w.h ) != 0xffff )
- m_debug.mesh->pix16( n_y.w.h, n_x.w.h ) = n_colour;
+ if( m_debug.mesh->pix( n_y.w.h, n_x.w.h ) != 0xffff )
+ m_debug.mesh->pix( n_y.w.h, n_x.w.h ) = n_colour;
}
n_x.d += n_dx;
@@ -364,7 +364,7 @@ int psxgpu_device::DebugMeshDisplay( bitmap_rgb32 &bitmap, const rectangle &clip
if( m_debug.b_mesh )
{
for( int y = cliprect.min_y; y <= cliprect.max_y; y++ )
- draw_scanline16( bitmap, cliprect.min_x, y, cliprect.max_x + 1 - cliprect.min_x, &m_debug.mesh->pix16( y ), pens() );
+ draw_scanline16( bitmap, cliprect.min_x, y, cliprect.max_x + 1 - cliprect.min_x, &m_debug.mesh->pix( y ), pens() );
}
m_debug.b_clear = 1;
@@ -772,7 +772,7 @@ uint32_t psxgpu_device::update_screen(screen_device &screen, bitmap_rgb32 &bitma
while( n_line > 0 )
{
uint16_t *p_n_src = p_p_vram[ n_y + n_displaystarty ] + 3 * n_x + n_displaystartx;
- uint32_t *p_n_dest = &bitmap.pix32(n_y + n_top, n_x + n_left);
+ uint32_t *p_n_dest = &bitmap.pix(n_y + n_top, n_x + n_left);
n_column = n_columns;
while( n_column > 0 )
diff --git a/src/devices/video/saa5050.cpp b/src/devices/video/saa5050.cpp
index 77af6be01ea..b873edfbbb9 100644
--- a/src/devices/video/saa5050.cpp
+++ b/src/devices/video/saa5050.cpp
@@ -661,9 +661,7 @@ uint32_t saa5050_device::screen_update(screen_device &screen, bitmap_rgb32 &bitm
int g = BIT(color, 1) * 0xff;
int b = BIT(color, 2) * 0xff;
- rgb_t rgb = rgb_t(r, g, b);
-
- bitmap.pix32(y, x++) = rgb;
+ bitmap.pix(y, x++) = rgb_t(r, g, b);
}
}
}
diff --git a/src/devices/video/scn2674.cpp b/src/devices/video/scn2674.cpp
index 17fc68c6b9a..96e1e7d3ca5 100644
--- a/src/devices/video/scn2674.cpp
+++ b/src/devices/video/scn2674.cpp
@@ -1178,7 +1178,7 @@ TIMER_CALLBACK_MEMBER(scn2674_device::scanline_timer)
}
if (!m_display_enabled)
- std::fill_n(&m_bitmap.pix32(m_linecounter), m_character_per_row * m_hpixels_per_column, rgb_t::black());
+ std::fill_n(&m_bitmap.pix(m_linecounter), m_character_per_row * m_hpixels_per_column, rgb_t::black());
if (m_gfx_enabled || (charrow == (m_scanline_per_char_row - 1)))
m_address = address;
diff --git a/src/devices/video/sed1330.cpp b/src/devices/video/sed1330.cpp
index 101ebe72944..37d95caac7b 100644
--- a/src/devices/video/sed1330.cpp
+++ b/src/devices/video/sed1330.cpp
@@ -605,7 +605,7 @@ void sed1330_device::data_w(uint8_t data)
void sed1330_device::draw_text_scanline(bitmap_ind16 &bitmap, const rectangle &cliprect, int y, int r, uint16_t va, bool cursor)
{
- uint16_t *p = &bitmap.pix16(y, 0);
+ uint16_t *p = &bitmap.pix(y);
for (int sx = 0; sx < m_cr; sx++, p += m_fx)
{
@@ -653,7 +653,7 @@ void sed1330_device::draw_graphics_scanline(bitmap_ind16 &bitmap, const rectangl
for (int x = 0; x < m_fx; x++)
{
- bitmap.pix16(y, (sx * m_fx) + x) = BIT(data, 7);
+ bitmap.pix(y, (sx * m_fx) + x) = BIT(data, 7);
data <<= 1;
}
}
diff --git a/src/devices/video/snes_ppu.cpp b/src/devices/video/snes_ppu.cpp
index a74f7af905d..e0b4eb544b1 100644
--- a/src/devices/video/snes_ppu.cpp
+++ b/src/devices/video/snes_ppu.cpp
@@ -1251,7 +1251,7 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
if (m_screen_disabled) /* screen is forced blank */
for (int x = 0; x < SNES_SCR_WIDTH * 2; x++)
- bitmap.pix32(0, x) = rgb_t::black();
+ bitmap.pix(0, x) = rgb_t::black();
else
{
uint8_t window_above[256];
@@ -1323,8 +1323,8 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
const int g = (c & 0x3e0) >> 5;
const int b = (c & 0x7c00) >> 10;
- bitmap.pix32(0, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
- bitmap.pix32(0, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
+ bitmap.pix(0, x * 2 + 0) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
+ bitmap.pix(0, x * 2 + 1) = rgb_t(pal5bit(r), pal5bit(g), pal5bit(b));
}
else if (!blurring)
{
@@ -1337,8 +1337,8 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
const int b0 = (c0 & 0x7c00) >> 10;
const int b1 = (c1 & 0x7c00) >> 10;
- bitmap.pix32(0, x * 2 + 0) = rgb_t(pal5bit(r0), pal5bit(g0), pal5bit(b0));
- bitmap.pix32(0, x * 2 + 1) = rgb_t(pal5bit(r1), pal5bit(g1), pal5bit(b1));
+ bitmap.pix(0, x * 2 + 0) = rgb_t(pal5bit(r0), pal5bit(g0), pal5bit(b0));
+ bitmap.pix(0, x * 2 + 1) = rgb_t(pal5bit(r1), pal5bit(g1), pal5bit(b1));
}
else
{
@@ -1348,7 +1348,7 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
const int r0 = (c0 & 0x1f);
const int g0 = (c0 & 0x3e0) >> 5;
const int b0 = (c0 & 0x7c00) >> 10;
- bitmap.pix32(0, x * 2 + 0) = rgb_t(pal5bit(r0), pal5bit(g0), pal5bit(b0));
+ bitmap.pix(0, x * 2 + 0) = rgb_t(pal5bit(r0), pal5bit(g0), pal5bit(b0));
prev = curr;
curr = luma[pixel(x, above, below, window_above, window_below)];
@@ -1357,7 +1357,7 @@ void snes_ppu_device::refresh_scanline( bitmap_rgb32 &bitmap, uint16_t curline )
const int r1 = (c1 & 0x1f);
const int g1 = (c1 & 0x3e0) >> 5;
const int b1 = (c1 & 0x7c00) >> 10;
- bitmap.pix32(0, x * 2 + 1) = rgb_t(pal5bit(r1), pal5bit(g1), pal5bit(b1));
+ bitmap.pix(0, x * 2 + 1) = rgb_t(pal5bit(r1), pal5bit(g1), pal5bit(b1));
prev = curr;
}
diff --git a/src/devices/video/stvvdp2.cpp b/src/devices/video/stvvdp2.cpp
index 473fa710f7d..f79f0aec207 100644
--- a/src/devices/video/stvvdp2.cpp
+++ b/src/devices/video/stvvdp2.cpp
@@ -2530,11 +2530,11 @@ void saturn_state::stv_vdp2_drawgfxzoom(
{
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = source_base + (y_index>>16) * gfx->rowbytes();
- uint32_t *dest = &dest_bmp.pix32(y);
+ uint8_t const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
if(stv_vdp2_window_process(x,y))
{
@@ -2552,11 +2552,11 @@ void saturn_state::stv_vdp2_drawgfxzoom(
{
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = source_base + (y_index>>16) * gfx->rowbytes();
- uint32_t *dest = &dest_bmp.pix32(y);
+ uint8_t const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
if(stv_vdp2_window_process(x,y))
{
@@ -2574,11 +2574,11 @@ void saturn_state::stv_vdp2_drawgfxzoom(
{
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = source_base + (y_index>>16) * gfx->rowbytes();
- uint32_t *dest = &dest_bmp.pix32(y);
+ uint8_t const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
if(stv_vdp2_window_process(x,y))
{
@@ -2716,17 +2716,16 @@ void saturn_state::stv_vdp2_drawgfxzoom_rgb555(
{
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = gfxdata + (y_index>>16)*16;
- uint32_t *dest = &dest_bmp.pix32(y);
- int r,g,b,data;
+ uint8_t const *const source = gfxdata + (y_index>>16)*16;
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
- data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
- b = pal5bit((data & 0x7c00) >> 10);
- g = pal5bit((data & 0x03e0) >> 5);
- r = pal5bit( data & 0x001f);
+ int data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
+ int b = pal5bit((data & 0x7c00) >> 10);
+ int g = pal5bit((data & 0x03e0) >> 5);
+ int r = pal5bit( data & 0x001f);
if(stv2_current_tilemap.fade_control & 1)
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
@@ -2743,17 +2742,16 @@ void saturn_state::stv_vdp2_drawgfxzoom_rgb555(
{
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = gfxdata + (y_index>>16)*16;
- uint32_t *dest = &dest_bmp.pix32(y);
- int r,g,b,data;
+ uint8_t const *const source = gfxdata + (y_index>>16)*16;
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
- data = (source[(x_index*2+0)>>16]<<0)|(source[(x_index*2+1)>>16]<<8);
- b = pal5bit((data & 0x7c00) >> 10);
- g = pal5bit((data & 0x03e0) >> 5);
- r = pal5bit( data & 0x001f);
+ int data = (source[(x_index*2+0)>>16]<<0)|(source[(x_index*2+1)>>16]<<8);
+ int b = pal5bit((data & 0x7c00) >> 10);
+ int g = pal5bit((data & 0x03e0) >> 5);
+ int r = pal5bit( data & 0x001f);
if(stv2_current_tilemap.fade_control & 1)
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
@@ -2770,17 +2768,16 @@ void saturn_state::stv_vdp2_drawgfxzoom_rgb555(
{
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = gfxdata + (y_index>>16)*16;
- uint32_t *dest = &dest_bmp.pix32(y);
- int r,g,b,data;
+ uint8_t const *const source = gfxdata + (y_index>>16)*16;
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
- data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
- b = pal5bit((data & 0x7c00) >> 10);
- g = pal5bit((data & 0x03e0) >> 5);
- r = pal5bit( data & 0x001f);
+ int data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
+ int b = pal5bit((data & 0x7c00) >> 10);
+ int g = pal5bit((data & 0x03e0) >> 5);
+ int r = pal5bit( data & 0x001f);
if(stv2_current_tilemap.fade_control & 1)
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
@@ -2877,21 +2874,18 @@ void saturn_state::stv_vdp2_drawgfx_rgb555( bitmap_rgb32 &dest_bmp, const rectan
for( y=sy; y<ey; y++ )
{
- const uint8_t *source = gfxdata + (y_index>>16)*16;
- uint32_t *dest = &dest_bmp.pix32(y);
- uint16_t data;
+ uint8_t const *const source = gfxdata + (y_index>>16)*16;
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ int x_index = x_index_base;
+ for( int x=sx; x<ex; x++ )
{
- int r,g,b;
-
- data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
+ uint16_t data = (source[(x_index>>16)*2] << 8) | source[(x_index>>16)*2+1];
if ((data & 0x8000) || (transparency & STV_TRANSPARENCY_NONE))
{
- b = pal5bit((data & 0x7c00) >> 10);
- g = pal5bit((data & 0x03e0) >> 5);
- r = pal5bit( data & 0x001f);
+ int b = pal5bit((data & 0x7c00) >> 10);
+ int g = pal5bit((data & 0x03e0) >> 5);
+ int r = pal5bit( data & 0x001f);
if(stv2_current_tilemap.fade_control & 1)
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
@@ -2986,26 +2980,21 @@ void saturn_state::stv_vdp2_drawgfx_rgb888( bitmap_rgb32 &dest_bmp, const rectan
if( ex>sx )
{ /* skip if inner loop doesn't draw anything */
- int y;
-
- for( y=sy; y<ey; y++ )
+ for( int y=sy; y<ey; y++ )
{
- const uint8_t *source = gfxdata + (y_index>>16)*32;
- uint32_t *dest = &dest_bmp.pix32(y);
- uint32_t data;
+ uint8_t const *const source = gfxdata + (y_index>>16)*32;
+ uint32_t *const dest = &dest_bmp.pix(y);
- int x, x_index = x_index_base;
+ int x_index = x_index_base;
- for( x=sx; x<ex; x++ )
+ for( int x=sx; x<ex; x++ )
{
- int r,g,b;
-
- data = (source[(x_index>>16)*4+0] << 24) | (source[(x_index>>16)*4+1] << 16) | (source[(x_index>>16)*4+2] << 8) | (source[(x_index>>16)*4+3] << 0);
+ uint32_t data = (source[(x_index>>16)*4+0] << 24) | (source[(x_index>>16)*4+1] << 16) | (source[(x_index>>16)*4+2] << 8) | (source[(x_index>>16)*4+3] << 0);
if ((data & 0x80000000) || (transparency & STV_TRANSPARENCY_NONE))
{
- b = (data & 0xff0000) >> 16;
- g = (data & 0x00ff00) >> 8;
- r = (data & 0x0000ff);
+ int b = (data & 0xff0000) >> 16;
+ int g = (data & 0x00ff00) >> 8;
+ int r = (data & 0x0000ff);
if(stv2_current_tilemap.fade_control & 1)
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
@@ -3078,27 +3067,23 @@ void saturn_state::stv_vdp2_drawgfx_alpha(bitmap_rgb32 &dest_bmp,const rectangle
/* skip if inner loop doesn't draw anything */
if (ex > sx)
{
- int x, y;
-
+ for (int y = sy; y < ey; y++)
{
- for (y = sy; y < ey; y++)
+ uint8_t const *const source = source_base + y_index*gfx->rowbytes();
+ uint32_t *const dest = &dest_bmp.pix(y);
+ int x_index = x_index_base;
+ for (int x = sx; x < ex; x++)
{
- const uint8_t *source = source_base + y_index*gfx->rowbytes();
- uint32_t *dest = &dest_bmp.pix32(y);
- int x_index = x_index_base;
- for (x = sx; x < ex; x++)
+ if(stv_vdp2_window_process(x,y))
{
- if(stv_vdp2_window_process(x,y))
- {
- int c = (source[x_index]);
- if ((transparency & STV_TRANSPARENCY_NONE) || (c != 0))
- dest[x] = alpha_blend_r32( dest[x], pal[c], alpha );
- }
-
- x_index += xinc;
+ int c = (source[x_index]);
+ if ((transparency & STV_TRANSPARENCY_NONE) || (c != 0))
+ dest[x] = alpha_blend_r32( dest[x], pal[c], alpha );
}
- y_index += yinc;
+
+ x_index += xinc;
}
+ y_index += yinc;
}
}
}
@@ -3155,27 +3140,23 @@ void saturn_state::stv_vdp2_drawgfx_transpen(bitmap_rgb32 &dest_bmp,const rectan
/* skip if inner loop doesn't draw anything */
if (ex > sx)
{
- int x, y;
-
+ for (int y = sy; y < ey; y++)
{
- for (y = sy; y < ey; y++)
+ uint8_t const *const source = source_base + y_index*gfx->rowbytes();
+ uint32_t *const dest = &dest_bmp.pix(y);
+ int x_index = x_index_base;
+ for (int x = sx; x < ex; x++)
{
- const uint8_t *source = source_base + y_index*gfx->rowbytes();
- uint32_t *dest = &dest_bmp.pix32(y);
- int x_index = x_index_base;
- for (x = sx; x < ex; x++)
+ if(stv_vdp2_window_process(x,y))
{
- if(stv_vdp2_window_process(x,y))
- {
- int c = (source[x_index]);
- if ((transparency & STV_TRANSPARENCY_NONE) || (c != 0))
- dest[x] = pal[c];
- }
-
- x_index += xinc;
+ int c = (source[x_index]);
+ if ((transparency & STV_TRANSPARENCY_NONE) || (c != 0))
+ dest[x] = pal[c];
}
- y_index += yinc;
+
+ x_index += xinc;
}
+ y_index += yinc;
}
}
}
@@ -3227,9 +3208,9 @@ void saturn_state::draw_4bpp_bitmap(bitmap_rgb32 &bitmap, const rectangle &clipr
dot_data += pal_bank;
if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
- bitmap.pix32(ydst, xdst) = m_palette->pen(dot_data);
+ bitmap.pix(ydst, xdst) = m_palette->pen(dot_data);
else
- bitmap.pix32(ydst, xdst) = alpha_blend_r32(bitmap.pix32(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha);
+ bitmap.pix(ydst, xdst) = alpha_blend_r32(bitmap.pix(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha);
}
}
}
@@ -3287,9 +3268,9 @@ void saturn_state::draw_8bpp_bitmap(bitmap_rgb32 &bitmap, const rectangle &clipr
dot_data += pal_bank;
if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
- bitmap.pix32(ydst, xdst) = m_palette->pen(dot_data);
+ bitmap.pix(ydst, xdst) = m_palette->pen(dot_data);
else
- bitmap.pix32(ydst, xdst) = alpha_blend_r32(bitmap.pix32(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha);
+ bitmap.pix(ydst, xdst) = alpha_blend_r32(bitmap.pix(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha);
}
}
}
@@ -3344,9 +3325,9 @@ void saturn_state::draw_11bpp_bitmap(bitmap_rgb32 &bitmap, const rectangle &clip
dot_data += pal_bank;
if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
- bitmap.pix32(ydst, xdst) = m_palette->pen(dot_data);
+ bitmap.pix(ydst, xdst) = m_palette->pen(dot_data);
else
- bitmap.pix32(ydst, xdst) = alpha_blend_r32(bitmap.pix32(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha);
+ bitmap.pix(ydst, xdst) = alpha_blend_r32(bitmap.pix(ydst, xdst), m_palette->pen(dot_data), stv2_current_tilemap.alpha);
}
}
}
@@ -3403,9 +3384,9 @@ void saturn_state::draw_rgb15_bitmap(bitmap_rgb32 &bitmap, const rectangle &clip
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
- bitmap.pix32(ydst, xdst) = rgb_t(r, g, b);
+ bitmap.pix(ydst, xdst) = rgb_t(r, g, b);
else
- bitmap.pix32(ydst, xdst) = alpha_blend_r32( bitmap.pix32(ydst, xdst), rgb_t(r, g, b), stv2_current_tilemap.alpha );
+ bitmap.pix(ydst, xdst) = alpha_blend_r32( bitmap.pix(ydst, xdst), rgb_t(r, g, b), stv2_current_tilemap.alpha );
}
}
}
@@ -3461,9 +3442,9 @@ void saturn_state::draw_rgb32_bitmap(bitmap_rgb32 &bitmap, const rectangle &clip
stv_vdp2_compute_color_offset(&r,&g,&b,stv2_current_tilemap.fade_control & 2);
if ( stv2_current_tilemap.colour_calculation_enabled == 0 )
- bitmap.pix32(ydst, xdst) = rgb_t(r, g, b);
+ bitmap.pix(ydst, xdst) = rgb_t(r, g, b);
else
- bitmap.pix32(ydst, xdst) = alpha_blend_r32( bitmap.pix32(ydst, xdst), rgb_t(r, g, b), stv2_current_tilemap.alpha );
+ bitmap.pix(ydst, xdst) = alpha_blend_r32( bitmap.pix(ydst, xdst), rgb_t(r, g, b), stv2_current_tilemap.alpha );
}
}
}
@@ -4354,9 +4335,9 @@ void saturn_state::stv_vdp2_draw_line(bitmap_rgb32 &bitmap, const rectangle &cli
uint16_t pen;
pen = (gfxdata[base_offs+0]<<8)|gfxdata[base_offs+1];
- pix = bitmap.pix32(y, x);
+ pix = bitmap.pix(y, x);
- bitmap.pix32(y, x) = add_blend_r32(m_palette->pen(pen & 0x7ff),pix);
+ bitmap.pix(y, x) = add_blend_r32(m_palette->pen(pen & 0x7ff),pix);
}
}
}
@@ -4364,12 +4345,8 @@ void saturn_state::stv_vdp2_draw_line(bitmap_rgb32 &bitmap, const rectangle &cli
void saturn_state::stv_vdp2_draw_mosaic(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint8_t is_roz)
{
- int x,y,xi,yi;
- uint8_t h_size,v_size;
- uint32_t pix;
-
- h_size = STV_VDP2_MZSZH+1;
- v_size = STV_VDP2_MZSZV+1;
+ uint8_t h_size = STV_VDP2_MZSZH+1;
+ uint8_t v_size = STV_VDP2_MZSZV+1;
if(is_roz)
v_size = 1;
@@ -4380,15 +4357,15 @@ void saturn_state::stv_vdp2_draw_mosaic(bitmap_rgb32 &bitmap, const rectangle &c
if(STV_VDP2_LSMD == 3)
v_size <<= 1;
- for(y=cliprect.top();y<=cliprect.bottom();y+=v_size)
+ for(int y=cliprect.top();y<=cliprect.bottom();y+=v_size)
{
- for(x=cliprect.left();x<=cliprect.right();x+=h_size)
+ for(int x=cliprect.left();x<=cliprect.right();x+=h_size)
{
- pix = bitmap.pix32(y, x);
+ uint32_t pix = bitmap.pix(y, x);
- for(yi=0;yi<v_size;yi++)
- for(xi=0;xi<h_size;xi++)
- bitmap.pix32(y+yi, x+xi) = pix;
+ for(int yi=0;yi<v_size;yi++)
+ for(int xi=0;xi<h_size;xi++)
+ bitmap.pix(y+yi, x+xi) = pix;
}
}
}
@@ -4726,7 +4703,7 @@ void saturn_state::stv_vdp2_copy_roz_bitmap(bitmap_rgb32 &bitmap,
//dx = (RP.A * RP.dx) + (RP.B * RP.dy);
//dy = (RP.D * RP.dx) + (RP.E * RP.dy);
- line = &bitmap.pix32(vcnt);
+ line = &bitmap.pix(vcnt);
// TODO: nuke this spaghetti code
if ( !use_coeff_table || RP.dkax == 0 )
@@ -4814,7 +4791,7 @@ void saturn_state::stv_vdp2_copy_roz_bitmap(bitmap_rgb32 &bitmap,
continue;
}
- pix = roz_bitmap.pix32(y & planerenderedsizey, x & planerenderedsizex);
+ pix = roz_bitmap.pix(y & planerenderedsizey, x & planerenderedsizex);
if (stv2_current_tilemap.transparency & STV_TRANSPARENCY_ALPHA)
{
if ((stv2_current_tilemap.transparency & STV_TRANSPARENCY_NONE) || (pix & 0xffffff))
@@ -4918,7 +4895,7 @@ void saturn_state::stv_vdp2_copy_roz_bitmap(bitmap_rgb32 &bitmap,
if ( x & clipxmask || y & clipymask ) continue;
- pix = roz_bitmap.pix32(y & planerenderedsizey, x & planerenderedsizex);
+ pix = roz_bitmap.pix(y & planerenderedsizey, x & planerenderedsizex);
if (stv2_current_tilemap.transparency & STV_TRANSPARENCY_ALPHA)
{
if ((stv2_current_tilemap.transparency & STV_TRANSPARENCY_NONE) || (pix & 0xffffff))
@@ -5753,12 +5730,9 @@ void saturn_state::stv_vdp2_draw_RBG0(bitmap_rgb32 &bitmap, const rectangle &cli
void saturn_state::stv_vdp2_draw_back(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y;
- uint8_t* gfxdata = m_vdp2.gfx_decode.get();
- uint32_t base_offs,base_mask;
- uint8_t interlace;
+ uint8_t const *const gfxdata = m_vdp2.gfx_decode.get();
- interlace = (STV_VDP2_LSMD == 3)+1;
+ uint8_t interlace = (STV_VDP2_LSMD == 3)+1;
// popmessage("Back screen %08x %08x %08x",STV_VDP2_BDCLMD,STV_VDP2_BKCLMD,STV_VDP2_BKTA);
@@ -5767,27 +5741,24 @@ void saturn_state::stv_vdp2_draw_back(bitmap_rgb32 &bitmap, const rectangle &cli
bitmap.fill(m_palette->black_pen(), cliprect);
else
{
- base_mask = STV_VDP2_VRAMSZ ? 0x7ffff : 0x3ffff;
+ uint32_t base_mask = STV_VDP2_VRAMSZ ? 0x7ffff : 0x3ffff;
- for(y=cliprect.top();y<=cliprect.bottom();y++)
+ for(int y=cliprect.top();y<=cliprect.bottom();y++)
{
- base_offs = ((STV_VDP2_BKTA ) & base_mask) << 1;
+ uint32_t base_offs = ((STV_VDP2_BKTA ) & base_mask) << 1;
if(STV_VDP2_BKCLMD)
base_offs += ((y / interlace) << 1);
- for(x=cliprect.left();x<=cliprect.right();x++)
+ for(int x=cliprect.left();x<=cliprect.right();x++)
{
- int r,g,b;
- uint16_t dot;
-
- dot = (gfxdata[base_offs+0]<<8)|gfxdata[base_offs+1];
- b = pal5bit((dot & 0x7c00) >> 10);
- g = pal5bit((dot & 0x03e0) >> 5);
- r = pal5bit( dot & 0x001f);
+ uint16_t dot = (gfxdata[base_offs+0]<<8)|gfxdata[base_offs+1];
+ int b = pal5bit((dot & 0x7c00) >> 10);
+ int g = pal5bit((dot & 0x03e0) >> 5);
+ int r = pal5bit( dot & 0x001f);
if(STV_VDP2_BKCOEN)
stv_vdp2_compute_color_offset( &r, &g, &b, STV_VDP2_BKCOSL );
- bitmap.pix32(y, x) = rgb_t(r, g, b);
+ bitmap.pix(y, x) = rgb_t(r, g, b);
}
}
}
@@ -6737,7 +6708,7 @@ void saturn_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect,
continue;
framebuffer_line = m_vdp1.framebuffer_display_lines[y];
- bitmap_line = &bitmap.pix32(y);
+ bitmap_line = &bitmap.pix(y);
for ( x = cliprect.left(); x <= cliprect.right(); x++ )
{
@@ -6830,7 +6801,7 @@ void saturn_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect,
continue;
framebuffer_line = m_vdp1.framebuffer_display_lines[y];
- bitmap_line = &bitmap.pix32(y);
+ bitmap_line = &bitmap.pix(y);
for ( x = cliprect.left(); x <= cliprect.right(); x++ )
{
@@ -6941,12 +6912,12 @@ void saturn_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect,
framebuffer_line = m_vdp1.framebuffer_display_lines[y];
if ( interlace_framebuffer == 0 )
{
- bitmap_line = &bitmap.pix32(y);
+ bitmap_line = &bitmap.pix(y);
}
else
{
- bitmap_line = &bitmap.pix32(2*y);
- bitmap_line2 = &bitmap.pix32(2*y + 1);
+ bitmap_line = &bitmap.pix(2*y);
+ bitmap_line2 = &bitmap.pix(2*y + 1);
}
for ( x = cliprect.left(); x <= cliprect.right() /(double_x+1) ; x++ )
diff --git a/src/devices/video/t6963c.cpp b/src/devices/video/t6963c.cpp
index 96995f62c68..215911ed3ff 100644
--- a/src/devices/video/t6963c.cpp
+++ b/src/devices/video/t6963c.cpp
@@ -346,7 +346,7 @@ uint32_t t6963c_device::screen_update(screen_device &screen, bitmap_ind16 &bitma
data = m_display_ram->read_byte(m_cgram_offset + c * 8 + cy);
for(int cx=0; cx<m_font_size; cx++)
- bitmap.pix16(y * 8 + cy, x * m_font_size + cx) = BIT(data, m_font_size - 1 - cx);
+ bitmap.pix(y * 8 + cy, x * m_font_size + cx) = BIT(data, m_font_size - 1 - cx);
}
}
@@ -362,13 +362,13 @@ uint32_t t6963c_device::screen_update(screen_device &screen, bitmap_ind16 &bitma
switch(m_mode & 7)
{
case 0: // OR
- bitmap.pix16(y, x * m_font_size + i) |= pix;
+ bitmap.pix(y, x * m_font_size + i) |= pix;
break;
case 1: // EXOR
- bitmap.pix16(y, x * m_font_size + i) ^= pix;
+ bitmap.pix(y, x * m_font_size + i) ^= pix;
break;
case 3: // AND
- bitmap.pix16(y, x * m_font_size + i) &= pix;
+ bitmap.pix(y, x * m_font_size + i) &= pix;
break;
case 4: // Text attribute
logerror("%s: Unimplemented Text attribute\n", machine().describe_context());
diff --git a/src/devices/video/t6963c.h b/src/devices/video/t6963c.h
index 33b748e38c3..aaaeb7c3e57 100644
--- a/src/devices/video/t6963c.h
+++ b/src/devices/video/t6963c.h
@@ -45,7 +45,7 @@ public:
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- static constexpr feature_type unemulated_features() { return feature::GRAPHICS; }
+ static constexpr feature_type imperfect_features() { return feature::GRAPHICS; }
protected:
// device-specific overrides
diff --git a/src/devices/video/t6a04.cpp b/src/devices/video/t6a04.cpp
index 8b55f8ce153..a5dc8bfa928 100644
--- a/src/devices/video/t6a04.cpp
+++ b/src/devices/video/t6a04.cpp
@@ -110,7 +110,7 @@ uint32_t t6a04_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap
for (int b=7; b>=0; b--)
{
- bitmap.pix16(x&0x3f, y*8+b) = data & 1;
+ bitmap.pix(x&0x3f, y*8+b) = data & 1;
data>>=1;
}
}
diff --git a/src/devices/video/tms3556.cpp b/src/devices/video/tms3556.cpp
index dbd45105a97..3088e02e685 100644
--- a/src/devices/video/tms3556.cpp
+++ b/src/devices/video/tms3556.cpp
@@ -573,12 +573,12 @@ void tms3556_device::draw_line(bitmap_ind16 &bmp, int line)
// if (m_control_regs[4] & 0x??)
// { // interlaced mode
-// ln = &bmp->pix16(line, m_field);
+// ln = &bmp->pix(line, m_field);
// }
// else
{ /* non-interlaced mode */
- ln = &bmp.pix16(line);
- ln2 = &bmp.pix16(line, 1);
+ ln = &bmp.pix(line);
+ ln2 = &bmp.pix(line, 1);
double_lines = 1;
}
diff --git a/src/devices/video/tms9928a.cpp b/src/devices/video/tms9928a.cpp
index 129b364e860..27395fecacb 100644
--- a/src/devices/video/tms9928a.cpp
+++ b/src/devices/video/tms9928a.cpp
@@ -365,7 +365,7 @@ void tms9928a_device::device_timer(emu_timer &timer, device_timer_id id, int par
int raw_vpos = screen().vpos();
int vpos = raw_vpos * m_vertical_size / screen().height();
uint16_t BackColour = m_Regs[7] & 15;
- uint32_t *p = &m_tmpbmp.pix32(vpos);
+ uint32_t *p = &m_tmpbmp.pix(vpos);
int y = vpos - m_top_border;
diff --git a/src/devices/video/v9938.cpp b/src/devices/video/v9938.cpp
index 0876a3b9923..e82858056e7 100644
--- a/src/devices/video/v9938.cpp
+++ b/src/devices/video/v9938.cpp
@@ -1863,12 +1863,12 @@ void v99x8_device::refresh_32(int line)
if (m_cont_reg[9] & 0x08)
{
- ln = &m_bitmap.pix32(m_scanline*2+((m_stat_reg[2]>>1)&1));
+ ln = &m_bitmap.pix(m_scanline*2+((m_stat_reg[2]>>1)&1));
}
else
{
- ln = &m_bitmap.pix32(m_scanline*2);
- ln2 = &m_bitmap.pix32(m_scanline*2+1);
+ ln = &m_bitmap.pix(m_scanline*2);
+ ln2 = &m_bitmap.pix(m_scanline*2+1);
double_lines = true;
}
diff --git a/src/devices/video/vector.cpp b/src/devices/video/vector.cpp
index 28b507323d5..46a21b535be 100644
--- a/src/devices/video/vector.cpp
+++ b/src/devices/video/vector.cpp
@@ -42,10 +42,11 @@
**************************************************************************** */
#include "emu.h"
-#include "emuopts.h"
-#include "rendutil.h"
#include "vector.h"
+#include "emuopts.h"
+#include "render.h"
+
#define VECTOR_WIDTH_DENOM 512
@@ -85,7 +86,7 @@ void vector_device::device_start()
m_vector_index = 0;
/* allocate memory for tables */
- m_vector_list = make_unique_clear<point[]>(MAX_POINTS);
+ m_vector_list = std::make_unique<point[]>(MAX_POINTS);
}
/*
diff --git a/src/devices/video/vic4567.cpp b/src/devices/video/vic4567.cpp
index c493e3d3a05..6b8cae5f04f 100644
--- a/src/devices/video/vic4567.cpp
+++ b/src/devices/video/vic4567.cpp
@@ -20,6 +20,8 @@
#include "screen.h"
+#include <algorithm>
+
/*****************************************************************************
CONSTANTS
@@ -424,105 +426,93 @@ TIMER_CALLBACK_MEMBER( vic3_device::timer_timeout )
void vic3_device::draw_character( int ybegin, int yend, int ch, int yoff, int xoff, uint16_t *color, int start_x, int end_x )
{
- int code;
-
for (int y = ybegin; y <= yend; y++)
{
- code = m_dma_read_cb(m_chargenaddr + ch * 8 + y);
+ int code = m_dma_read_cb(m_chargenaddr + ch * 8 + y);
m_screenptr[y + yoff][xoff >> 3] = code;
- if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = color[code >> 7];
- if ((xoff + 1 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = color[(code >> 6) & 1];
- if ((xoff + 2 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = color[(code >> 5) & 1];
- if ((xoff + 3 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = color[(code >> 4) & 1];
- if ((xoff + 4 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = color[(code >> 3) & 1];
- if ((xoff + 5 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = color[(code >> 2) & 1];
- if ((xoff + 6 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = color[(code >> 1) & 1];
- if ((xoff + 7 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = color[code & 1];
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = color[code >> 7];
+ if ((xoff + 1 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = color[(code >> 6) & 1];
+ if ((xoff + 2 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = color[(code >> 5) & 1];
+ if ((xoff + 3 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = color[(code >> 4) & 1];
+ if ((xoff + 4 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = color[(code >> 3) & 1];
+ if ((xoff + 5 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = color[(code >> 2) & 1];
+ if ((xoff + 6 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = color[(code >> 1) & 1];
+ if ((xoff + 7 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = color[code & 1];
}
}
void vic3_device::draw_character_multi( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
{
- int code;
-
for (int y = ybegin; y <= yend; y++)
{
- code = m_dma_read_cb(m_chargenaddr + ch * 8 + y);
+ int code = m_dma_read_cb(m_chargenaddr + ch * 8 + y);
m_screenptr[y + yoff][xoff >> 3] = m_foreground[code];
- if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = m_multi[code >> 6];
- if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = m_multi[code >> 6];
- if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = m_multi[(code >> 4) & 3];
- if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = m_multi[(code >> 4) & 3];
- if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = m_multi[(code >> 2) & 3];
- if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = m_multi[(code >> 2) & 3];
- if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = m_multi[code & 3];
- if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = m_multi[code & 3];
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = m_multi[code >> 6];
+ if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = m_multi[code >> 6];
+ if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = m_multi[(code >> 4) & 3];
+ if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = m_multi[(code >> 4) & 3];
+ if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = m_multi[(code >> 2) & 3];
+ if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = m_multi[(code >> 2) & 3];
+ if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = m_multi[code & 3];
+ if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = m_multi[code & 3];
}
}
void vic3_device::draw_bitmap( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
{
- int code;
-
for (int y = ybegin; y <= yend; y++)
{
- code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y);
+ int code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y);
m_screenptr[y + yoff][xoff >> 3] = code;
- if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = m_c64_bitmap[code >> 7];
- if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = m_c64_bitmap[(code >> 6) & 1];
- if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = m_c64_bitmap[(code >> 5) & 1];
- if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = m_c64_bitmap[(code >> 4) & 1];
- if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = m_c64_bitmap[(code >> 3) & 1];
- if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = m_c64_bitmap[(code >> 2) & 1];
- if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = m_c64_bitmap[(code >> 1) & 1];
- if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = m_c64_bitmap[code & 1];
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = m_c64_bitmap[code >> 7];
+ if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = m_c64_bitmap[(code >> 6) & 1];
+ if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = m_c64_bitmap[(code >> 5) & 1];
+ if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = m_c64_bitmap[(code >> 4) & 1];
+ if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = m_c64_bitmap[(code >> 3) & 1];
+ if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = m_c64_bitmap[(code >> 2) & 1];
+ if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = m_c64_bitmap[(code >> 1) & 1];
+ if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = m_c64_bitmap[code & 1];
}
}
void vic3_device::draw_bitmap_multi( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
{
- int code;
-
for (int y = ybegin; y <= yend; y++)
{
- code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y);
+ int code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y);
m_screenptr[y + yoff][xoff >> 3] = m_foreground[code];
- if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 0) = m_bitmapmulti[code >> 6];
- if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 1) = m_bitmapmulti[code >> 6];
- if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 2) = m_bitmapmulti[(code >> 4) & 3];
- if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 3) = m_bitmapmulti[(code >> 4) & 3];
- if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 4) = m_bitmapmulti[(code >> 2) & 3];
- if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 5) = m_bitmapmulti[(code >> 2) & 3];
- if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 6) = m_bitmapmulti[code & 3];
- if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix16(y + yoff + FIRSTLINE, xoff + 7) = m_bitmapmulti[code & 3];
+ if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = m_bitmapmulti[code >> 6];
+ if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = m_bitmapmulti[code >> 6];
+ if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = m_bitmapmulti[(code >> 4) & 3];
+ if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = m_bitmapmulti[(code >> 4) & 3];
+ if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = m_bitmapmulti[(code >> 2) & 3];
+ if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = m_bitmapmulti[(code >> 2) & 3];
+ if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = m_bitmapmulti[code & 3];
+ if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = m_bitmapmulti[code & 3];
}
}
void vic3_device::draw_sprite_code( int y, int xbegin, int code, int color, int start_x, int end_x )
{
- int mask, x;
-
if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)))
return;
- for (x = 0, mask = 0x80; x < 8; x++, mask >>= 1)
+ for (int x = 0, mask = 0x80; x < 8; x++, mask >>= 1)
{
if (code & mask)
{
if ((xbegin + x > start_x) && (xbegin + x < end_x))
- m_bitmap->pix16(y + FIRSTLINE, xbegin + x) = color;
+ m_bitmap->pix(y + FIRSTLINE, xbegin + x) = color;
}
}
}
void vic3_device::draw_sprite_code_multi( int y, int xbegin, int code, int prior, int start_x, int end_x )
{
- int x, mask, shift;
-
if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)))
return;
- for (x = 0, mask = 0xc0, shift = 6; x < 8; x += 2, mask >>= 2, shift -= 2)
+ for (int x = 0, mask = 0xc0, shift = 6; x < 8; x += 2, mask >>= 2, shift -= 2)
{
if (code & mask)
{
@@ -530,17 +520,17 @@ void vic3_device::draw_sprite_code_multi( int y, int xbegin, int code, int prior
{
case 1:
if ((xbegin + x + 1 > start_x) && (xbegin + x + 1 < end_x))
- m_bitmap->pix16(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3];
+ m_bitmap->pix(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3];
break;
case 2:
if ((xbegin + x > start_x) && (xbegin + x < end_x))
- m_bitmap->pix16(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3];
+ m_bitmap->pix(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3];
break;
case 3:
if ((xbegin + x > start_x) && (xbegin + x < end_x))
- m_bitmap->pix16(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3];
+ m_bitmap->pix(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3];
if ((xbegin + x + 1> start_x) && (xbegin + x + 1< end_x))
- m_bitmap->pix16(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3];
+ m_bitmap->pix(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3];
break;
}
}
@@ -549,8 +539,6 @@ void vic3_device::draw_sprite_code_multi( int y, int xbegin, int code, int prior
void vic3_device::sprite_collision( int nr, int y, int x, int mask )
{
- int value, xdiff;
-
for (int i = 7; i > nr; i--)
{
if (!SPRITEON(i) || !m_sprites[i].paintedline[y] || (SPRITE_COLLISION(i) && SPRITE_COLLISION(nr)))
@@ -559,8 +547,9 @@ void vic3_device::sprite_collision( int nr, int y, int x, int mask )
if ((x + 7 < SPRITE_X_POS(i)) || (x >= SPRITE_X_POS(i) + SPRITE_X_SIZE(i)))
continue;
- xdiff = x - SPRITE_X_POS(i);
+ int xdiff = x - SPRITE_X_POS(i);
+ int value;
if ((x & 7) == (SPRITE_X_POS(i) & 7))
value = m_sprites[i].bitmap[y][xdiff >> 3];
else if (xdiff < 0)
@@ -785,17 +774,6 @@ void vic3_device::draw_sprite_multi( int nr, int yoff, int ybegin, int yend, int
}
}
-#ifndef memset16
-static void *memset16(void *dest, int value, size_t size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- ((short *) dest)[i] = value;
- return dest;
-}
-#endif
-
void vic3_device::drawlines( int first, int last, int start_x, int end_x )
{
int line, vline, end;
@@ -825,7 +803,7 @@ void vic3_device::drawlines( int first, int last, int start_x, int end_x )
{
for (line = first; (line < last) && (line < m_bitmap->height()); line++)
{
- memset16(&m_bitmap->pix16(line + FIRSTLINE), 0, m_bitmap->width());
+ std::fill_n(&m_bitmap->pix(line + FIRSTLINE), m_bitmap->width(), 0);
}
return;
}
@@ -841,7 +819,7 @@ void vic3_device::drawlines( int first, int last, int start_x, int end_x )
for (line = first; line < end; line++)
{
- memset16(&m_bitmap->pix16(line + FIRSTLINE), FRAMECOLOR, m_bitmap->width());
+ std::fill_n(&m_bitmap->pix(line + FIRSTLINE), m_bitmap->width(), FRAMECOLOR);
}
if (LINES25)
@@ -1013,20 +991,14 @@ void vic3_device::drawlines( int first, int last, int start_x, int end_x )
for (; line < end; line++)
{
- memset16(&m_bitmap->pix16(line + FIRSTLINE), FRAMECOLOR, m_bitmap->width());
+ std::fill_n(&m_bitmap->pix(line + FIRSTLINE), m_bitmap->width(), FRAMECOLOR);
}
}
void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
{
- int line, vline, end;
- int attr, ch, ecm;
- int syend;
- int offs, yoff, xoff, ybegin, yend, xbegin, xend;
- int i;
-
if (VIC3_BITPLANES)
- return ;
+ return;
/* temporary allowing vic3 displaying 80 columns */
if (m_reg[0x31] & 0x80)
@@ -1040,8 +1012,8 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
/* top part of display not rastered */
first -= VIC2_YPOS - YPOS;
- xbegin = VIC2_STARTVISIBLECOLUMNS;
- xend = xbegin + VIC2_VISIBLECOLUMNS;
+ int xbegin = VIC2_STARTVISIBLECOLUMNS;
+ int xend = xbegin + VIC2_VISIBLECOLUMNS;
if (!SCREENON)
{
xbegin = VIC2_STARTVISIBLECOLUMNS;
@@ -1068,12 +1040,13 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
xend = xbegin + 304;
}
+ int end;
if (first + 1 < m_y_begin)
end = first + 1;
else
end = m_y_begin + YPOS;
- line = first;
+ int line = first;
// top border
if (line < end)
{
@@ -1088,7 +1061,7 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
line = end;
}
- vline = line - YPOS + 3 - VERTICALPOS;
+ int vline = line - YPOS + 3 - VERTICALPOS;
if (first + 1 < m_y_end + YPOS)
end = first + 1;
@@ -1097,23 +1070,23 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
if (line < end)
{
- offs = (vline >> 3) * 40;
- ybegin = vline & 7;
- yoff = line - ybegin;
- yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
+ int offs = (vline >> 3) * 40;
+ int ybegin = vline & 7;
+ int yoff = line - ybegin;
+ int yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
/* rendering 39 characters */
/* left and right borders are overwritten later */
m_shift[line] = HORIZONTALPOS;
- for (xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++)
+ for (int xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++)
{
- ch = m_dma_read_cb(m_videoaddr + offs);
+ int ch = m_dma_read_cb(m_videoaddr + offs);
#if 0
- attr = m_dma_read_color_cb(m_videoaddr + offs);
+ int attr = m_dma_read_color_cb(m_videoaddr + offs);
#else
/* temporary until vic3 finished */
- attr = m_dma_read_color_cb((m_videoaddr + offs)&0x3ff)&0x0f;
+ int attr = m_dma_read_color_cb((m_videoaddr + offs)&0x3ff)&0x0f;
#endif
if (HIRESON)
{
@@ -1131,7 +1104,7 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
}
else if (ECMON)
{
- ecm = ch >> 6;
+ int ecm = ch >> 6;
m_ecmcolor[0] = m_colors[ecm];
m_ecmcolor[1] = attr;
draw_character(ybegin, yend, ch & ~0xC0, yoff, xoff, m_ecmcolor, start_x, end_x);
@@ -1149,7 +1122,7 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
}
/* sprite priority, sprite overwrites lowerprior pixels */
- for (i = 7; i >= 0; i--)
+ for (int i = 7; i >= 0; i--)
{
if (SPRITEON (i) &&
(yoff + ybegin >= SPRITE_Y_POS (i)) &&
@@ -1158,7 +1131,7 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
{
int wrapped = - SPRITE_Y_POS (i) + 6;
- syend = yend;
+ int syend = yend;
if (SPRITE_Y_EXPAND (i))
{
@@ -1187,7 +1160,7 @@ void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
{
int wrapped = yoff + ybegin - SPRITE_Y_POS (i);
- syend = yend;
+ int syend = yend;
if (SPRITE_Y_EXPAND (i))
{
@@ -1659,77 +1632,76 @@ uint8_t vic3_device::port_r(offs_t offset)
}
-#define VIC3_MASK(M) \
- if (M) \
- { \
- if (M & 0x01) \
- colors[0] = m_c64_mem_r_cb(VIC3_ADDR(0) + offset); \
- if (M & 0x02) \
- colors[1] = m_c64_mem_r_cb(VIC3_ADDR(1) + offset) << 1; \
- if (M & 0x04) \
- colors[2] = m_c64_mem_r_cb(VIC3_ADDR(2) + offset) << 2; \
- if (M & 0x08) \
- colors[3] = m_c64_mem_r_cb(VIC3_ADDR(3) + offset) << 3; \
- if (M & 0x10) \
- colors[4] = m_c64_mem_r_cb(VIC3_ADDR(4) + offset) << 4; \
- if (M & 0x20) \
- colors[5] = m_c64_mem_r_cb(VIC3_ADDR(5) + offset) << 5; \
- if (M & 0x40) \
- colors[6] = m_c64_mem_r_cb(VIC3_ADDR(6) + offset) << 6; \
- if (M & 0x80) \
- colors[7] = m_c64_mem_r_cb(VIC3_ADDR(7) + offset) << 7; \
- for (i = 7; i >= 0; i--) \
- { \
- p = 0; \
- if (M & 0x01) \
- { \
- p = colors[0] & 0x01; \
- colors[0] >>= 1; \
- } \
- if (M & 0x02) \
- { \
- p |= colors[1] & 0x02; \
- colors[1] >>= 1; \
- } \
- if (M & 0x04) \
- { \
- p |= colors[2] & 0x04; \
- colors[2] >>= 1; \
- } \
- if (M & 0x08) \
- { \
- p |= colors[3] & 0x08; \
- colors[3] >>= 1; \
- } \
- if (M & 0x10) \
- { \
- p |= colors[4] & 0x10; \
- colors[4] >>= 1; \
- } \
- if (M & 0x20) \
- { \
- p |= colors[5] & 0x20; \
- colors[5] >>= 1; \
- } \
- if (M & 0x40) \
- { \
- p |= colors[6] & 0x40; \
- colors[6] >>= 1; \
- } \
- if (M & 0x80) \
- { \
- p |= colors[7] & 0x80; \
- colors[7] >>= 1; \
- } \
- m_bitmap->pix16(YPOS + y, XPOS + x + i) = p; \
- } \
+#define VIC3_MASK(M) \
+ if (M) \
+ { \
+ if (M & 0x01) \
+ colors[0] = m_c64_mem_r_cb(VIC3_ADDR(0) + offset); \
+ if (M & 0x02) \
+ colors[1] = m_c64_mem_r_cb(VIC3_ADDR(1) + offset) << 1; \
+ if (M & 0x04) \
+ colors[2] = m_c64_mem_r_cb(VIC3_ADDR(2) + offset) << 2; \
+ if (M & 0x08) \
+ colors[3] = m_c64_mem_r_cb(VIC3_ADDR(3) + offset) << 3; \
+ if (M & 0x10) \
+ colors[4] = m_c64_mem_r_cb(VIC3_ADDR(4) + offset) << 4; \
+ if (M & 0x20) \
+ colors[5] = m_c64_mem_r_cb(VIC3_ADDR(5) + offset) << 5; \
+ if (M & 0x40) \
+ colors[6] = m_c64_mem_r_cb(VIC3_ADDR(6) + offset) << 6; \
+ if (M & 0x80) \
+ colors[7] = m_c64_mem_r_cb(VIC3_ADDR(7) + offset) << 7; \
+ for (int i = 7; i >= 0; i--) \
+ { \
+ int p = 0; \
+ if (M & 0x01) \
+ { \
+ p = colors[0] & 0x01; \
+ colors[0] >>= 1; \
+ } \
+ if (M & 0x02) \
+ { \
+ p |= colors[1] & 0x02; \
+ colors[1] >>= 1; \
+ } \
+ if (M & 0x04) \
+ { \
+ p |= colors[2] & 0x04; \
+ colors[2] >>= 1; \
+ } \
+ if (M & 0x08) \
+ { \
+ p |= colors[3] & 0x08; \
+ colors[3] >>= 1; \
+ } \
+ if (M & 0x10) \
+ { \
+ p |= colors[4] & 0x10; \
+ colors[4] >>= 1; \
+ } \
+ if (M & 0x20) \
+ { \
+ p |= colors[5] & 0x20; \
+ colors[5] >>= 1; \
+ } \
+ if (M & 0x40) \
+ { \
+ p |= colors[6] & 0x40; \
+ colors[6] >>= 1; \
+ } \
+ if (M & 0x80) \
+ { \
+ p |= colors[7] & 0x80; \
+ colors[7] >>= 1; \
+ } \
+ m_bitmap->pix(YPOS + y, XPOS + x + i) = p; \
+ } \
}
#define VIC3_ADDR(a) VIC3_BITPLANE_IADDR(a)
void vic3_device::interlace_draw_block( int x, int y, int offset )
{
int colors[8] = {0};
- int i, p;
switch (VIC3_BITPLANES_MASK)
{
@@ -1776,13 +1748,13 @@ void vic3_device::interlace_draw_block( int x, int y, int offset )
if (VIC3_BITPLANES_MASK & 0x80)
colors[7] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(7) + offset) << 7;
- for (i = 7; i >= 0; i--)
+ for (int i = 7; i >= 0; i--)
{
- m_bitmap->pix16(YPOS + y, XPOS + x + i) =
- (colors[0] & 0x01) | (colors[1] & 0x02)
- | (colors[2] & 0x04) | (colors[3] & 0x08)
- | (colors[4] & 0x10) | (colors[5] & 0x20)
- | (colors[6] & 0x40) | (colors[7] & 0x80);
+ m_bitmap->pix(YPOS + y, XPOS + x + i) =
+ (colors[0] & 0x01) | (colors[1] & 0x02) |
+ (colors[2] & 0x04) | (colors[3] & 0x08) |
+ (colors[4] & 0x10) | (colors[5] & 0x20) |
+ (colors[6] & 0x40) | (colors[7] & 0x80);
colors[0] >>= 1;
colors[1] >>= 1;
colors[2] >>= 1;
@@ -1800,7 +1772,6 @@ void vic3_device::interlace_draw_block( int x, int y, int offset )
void vic3_device::draw_block( int x, int y, int offset )
{
int colors[8] = {0};
- int i, p;
switch (VIC3_BITPLANES_MASK)
{
@@ -1847,13 +1818,13 @@ void vic3_device::draw_block( int x, int y, int offset )
if (VIC3_BITPLANES_MASK & 0x80)
colors[7] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(7) + offset) << 7;
- for (i = 7; i >= 0; i--)
+ for (int i = 7; i >= 0; i--)
{
- m_bitmap->pix16(YPOS + y, XPOS + x + i) =
- (colors[0] & 0x01) | (colors[1] & 0x02)
- | (colors[2] & 0x04) | (colors[3] & 0x08)
- | (colors[4] & 0x10) | (colors[5] & 0x20)
- | (colors[6] & 0x40) | (colors[7] & 0x80);
+ m_bitmap->pix(YPOS + y, XPOS + x + i) =
+ (colors[0] & 0x01) | (colors[1] & 0x02) |
+ (colors[2] & 0x04) | (colors[3] & 0x08) |
+ (colors[4] & 0x10) | (colors[5] & 0x20) |
+ (colors[6] & 0x40) | (colors[7] & 0x80);
colors[0] >>= 1;
colors[1] >>= 1;
colors[2] >>= 1;
@@ -1869,17 +1840,15 @@ void vic3_device::draw_block( int x, int y, int offset )
void vic3_device::draw_bitplanes()
{
- int x, y, y1s, offset;
- rectangle vis;
const rectangle &visarea = screen().visible_area();
if (VIC3_LINES == 400)
{ /* interlaced! */
- for (y1s = 0, offset = 0; y1s < 400; y1s += 16)
+ for (int y1s = 0, offset = 0; y1s < 400; y1s += 16)
{
- for (x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
+ for (int x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
{
- for (y = y1s; y < y1s + 16; y += 2, offset++)
+ for (int y = y1s; y < y1s + 16; y += 2, offset++)
{
if (m_interlace)
draw_block(x, y, offset);
@@ -1892,11 +1861,11 @@ void vic3_device::draw_bitplanes()
}
else
{
- for (y1s = 0, offset = 0; y1s < 200; y1s += 8)
+ for (int y1s = 0, offset = 0; y1s < 200; y1s += 8)
{
- for (x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
+ for (int x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
{
- for (y = y1s; y < y1s + 8; y++, offset++)
+ for (int y = y1s; y < y1s + 8; y++, offset++)
{
draw_block(x, y, offset);
}
@@ -1906,25 +1875,25 @@ void vic3_device::draw_bitplanes()
if (XPOS > 0)
{
- vis.set(0, XPOS - 1, 0, visarea.bottom());
+ rectangle vis(0, XPOS - 1, 0, visarea.bottom());
m_bitmap->fill(FRAMECOLOR, vis);
}
if (XPOS + VIC3_BITPLANES_WIDTH < visarea.right())
{
- vis.set(XPOS + VIC3_BITPLANES_WIDTH, visarea.right(), 0, visarea.bottom());
+ rectangle vis(XPOS + VIC3_BITPLANES_WIDTH, visarea.right(), 0, visarea.bottom());
m_bitmap->fill(FRAMECOLOR, vis);
}
if (YPOS > 0)
{
- vis.set(0, visarea.right(), 0, YPOS - 1);
+ rectangle vis(0, visarea.right(), 0, YPOS - 1);
m_bitmap->fill(FRAMECOLOR, vis);
}
if (YPOS + VIC3_LINES < visarea.bottom())
{
- vis.set(0, visarea.right(), YPOS + VIC3_LINES, visarea.bottom());
+ rectangle vis(0, visarea.right(), YPOS + VIC3_LINES, visarea.bottom());
m_bitmap->fill(FRAMECOLOR, vis);
}
}
diff --git a/src/devices/video/voodoo.cpp b/src/devices/video/voodoo.cpp
index 72ef43032ef..ebc9555f25c 100644
--- a/src/devices/video/voodoo.cpp
+++ b/src/devices/video/voodoo.cpp
@@ -917,8 +917,8 @@ int voodoo_device::voodoo_update(bitmap_rgb32 &bitmap, const rectangle &cliprect
for (y = cliprect.min_y; y <= cliprect.max_y; y++)
if (y >= fbi.yoffs)
{
- uint16_t *src = (uint16_t *)(fbi.ram + fbi.rgboffs[drawbuf]) + (y - fbi.yoffs) * fbi.rowpixels - fbi.xoffs;
- uint32_t *dst = &bitmap.pix32(y);
+ uint16_t const *const src = (uint16_t *)(fbi.ram + fbi.rgboffs[drawbuf]) + (y - fbi.yoffs) * fbi.rowpixels - fbi.xoffs;
+ uint32_t *const dst = &bitmap.pix(y);
for (x = cliprect.min_x; x <= cliprect.max_x; x++)
dst[x] = fbi.pen[src[x]];
}
@@ -944,8 +944,8 @@ int voodoo_device::voodoo_update(bitmap_rgb32 &bitmap, const rectangle &cliprect
{
for (y = cliprect.min_y; y <= cliprect.max_y; y++)
{
- uint16_t* src = (uint16_t*)(fbi.ram + fbi.auxoffs) + (y - fbi.yoffs) * fbi.rowpixels - fbi.xoffs;
- uint32_t* dst = &bitmap.pix32(y);
+ uint16_t const *const src = (uint16_t*)(fbi.ram + fbi.auxoffs) + (y - fbi.yoffs) * fbi.rowpixels - fbi.xoffs;
+ uint32_t *const dst = &bitmap.pix(y);
for (x = cliprect.min_x; x <= cliprect.max_x; x++)
dst[x] = ((src[x] << 8) & 0xff0000) | ((src[x] >> 0) & 0xff00) | ((src[x] >> 8) & 0xff);
}
diff --git a/src/devices/video/vrender0.cpp b/src/devices/video/vrender0.cpp
index f2bb5c74ac1..8a0e7c9319c 100644
--- a/src/devices/video/vrender0.cpp
+++ b/src/devices/video/vrender0.cpp
@@ -716,7 +716,7 @@ uint32_t vr0video_device::screen_update(screen_device &screen, bitmap_ind16 &bit
uint32_t const dx = cliprect.left();
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
- std::copy_n(&m_DisplayDest[(y * 1024) + dx], width, &bitmap.pix16(y, dx));
+ std::copy_n(&m_DisplayDest[(y * 1024) + dx], width, &bitmap.pix(y, dx));
return 0;
}
diff --git a/src/devices/video/zeus2.cpp b/src/devices/video/zeus2.cpp
index 0c6c34e3fcc..c585373c74e 100644
--- a/src/devices/video/zeus2.cpp
+++ b/src/devices/video/zeus2.cpp
@@ -8,6 +8,9 @@
#include "emu.h"
#include "zeus2.h"
+#include <algorithm>
+
+
#define LOG_REGS 1
// Setting ALWAYS_LOG_FIFO will always log the fifo versus having to hold 'L'
#define ALWAYS_LOG_FIFO 0
@@ -236,10 +239,7 @@ uint32_t zeus2_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
for (y = cliprect.min_y; y <= cliprect.max_y; y++)
{
uint32_t *colorptr = &m_frameColor[frame_addr_from_xy(0, y, false)];
- uint32_t *dest = &bitmap.pix32(y);
- for (x = cliprect.min_x; x <= cliprect.max_x; x++) {
- dest[x] = colorptr[x];
- }
+ std::copy(colorptr + cliprect.min_x, colorptr + cliprect.max_x + 1, &bitmap.pix(y, cliprect.min_x));
}
}
@@ -265,7 +265,7 @@ uint32_t zeus2_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
int xoffs = screen.visible_area().min_x;
for (y = cliprect.min_y; y <= cliprect.max_y; y++)
{
- uint32_t *dest = &bitmap.pix32(y);
+ uint32_t *const dest = &bitmap.pix(y);
for (x = cliprect.min_x; x <= cliprect.max_x; x++)
{
if (1) {
diff --git a/src/emu/addrmap.cpp b/src/emu/addrmap.cpp
index 61f7375d236..604e05ab864 100644
--- a/src/emu/addrmap.cpp
+++ b/src/emu/addrmap.cpp
@@ -873,7 +873,7 @@ void address_map::global_mask(offs_t mask)
address_map_entry &address_map::operator()(offs_t start, offs_t end)
{
- address_map_entry *ptr = global_alloc(address_map_entry(*m_device, *this, start, end));
+ address_map_entry *ptr = new address_map_entry(*m_device, *this, start, end);
m_entrylist.append(*ptr);
return *ptr;
}
diff --git a/src/emu/crsshair.cpp b/src/emu/crsshair.cpp
index 6145e668a23..027d8828e32 100644
--- a/src/emu/crsshair.cpp
+++ b/src/emu/crsshair.cpp
@@ -9,11 +9,15 @@
***************************************************************************/
#include "emu.h"
+#include "crsshair.h"
+
+#include "config.h"
#include "emuopts.h"
+#include "render.h"
#include "rendutil.h"
-#include "config.h"
+#include "screen.h"
+
#include "xmlfile.h"
-#include "crsshair.h"
@@ -168,32 +172,45 @@ void render_crosshair::set_default_bitmap()
void render_crosshair::create_bitmap()
{
- int x, y;
rgb_t color = m_player < ARRAY_LENGTH(crosshair_colors) ? crosshair_colors[m_player] : rgb_t::white();
// if we have a bitmap and texture for this player, kill it
- if (m_bitmap == nullptr)
+ if (!m_bitmap)
{
m_bitmap = std::make_unique<bitmap_argb32>();
m_texture = m_machine.render().texture_alloc(render_texture::hq_scale);
}
+ else
+ {
+ m_bitmap->reset();
+ }
emu_file crossfile(m_machine.options().crosshair_path(), OPEN_FLAG_READ);
if (!m_name.empty())
{
// look for user specified file
- std::string filename = m_name + ".png";
- render_load_png(*m_bitmap, crossfile, nullptr, filename.c_str());
+ if (crossfile.open(m_name + ".png") == osd_file::error::NONE)
+ {
+ render_load_png(*m_bitmap, crossfile);
+ crossfile.close();
+ }
}
else
{
// look for default cross?.png in crsshair/game dir
- std::string filename = string_format("cross%d.png", m_player + 1);
- render_load_png(*m_bitmap, crossfile, m_machine.system().name, filename.c_str());
+ std::string const filename = string_format("cross%d.png", m_player + 1);
+ if (crossfile.open(m_machine.system().name + (PATH_SEPARATOR + filename)) == osd_file::error::NONE)
+ {
+ render_load_png(*m_bitmap, crossfile);
+ crossfile.close();
+ }
// look for default cross?.png in crsshair dir
- if (!m_bitmap->valid())
- render_load_png(*m_bitmap, crossfile, nullptr, filename.c_str());
+ if (!m_bitmap->valid() && (crossfile.open(filename) == osd_file::error::NONE))
+ {
+ render_load_png(*m_bitmap, crossfile);
+ crossfile.close();
+ }
}
/* if that didn't work, use the built-in one */
@@ -204,14 +221,14 @@ void render_crosshair::create_bitmap()
m_bitmap->fill(rgb_t(0x00,0xff,0xff,0xff));
/* extract the raw source data to it */
- for (y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++)
+ for (int y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++)
{
/* assume it is mirrored vertically */
- u32 *dest0 = &m_bitmap->pix32(y);
- u32 *dest1 = &m_bitmap->pix32(CROSSHAIR_RAW_SIZE - 1 - y);
+ u32 *const dest0 = &m_bitmap->pix(y);
+ u32 *const dest1 = &m_bitmap->pix(CROSSHAIR_RAW_SIZE - 1 - y);
/* extract to two rows simultaneously */
- for (x = 0; x < CROSSHAIR_RAW_SIZE; x++)
+ for (int x = 0; x < CROSSHAIR_RAW_SIZE; x++)
if ((crosshair_raw_top[y * CROSSHAIR_RAW_ROWBYTES + x / 8] << (x % 8)) & 0x80)
dest0[x] = dest1[x] = rgb_t(0xff,0x00,0x00,0x00) | color;
}
@@ -328,6 +345,7 @@ void render_crosshair::draw(render_container &container, u8 fade)
crosshair_manager::crosshair_manager(running_machine &machine)
: m_machine(machine)
, m_usage(false)
+ , m_fade(0)
, m_animation_counter(0)
, m_auto_time(CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT)
{
diff --git a/src/emu/debug/debugcmd.cpp b/src/emu/debug/debugcmd.cpp
index c6dda192e59..9b33eac7b45 100644
--- a/src/emu/debug/debugcmd.cpp
+++ b/src/emu/debug/debugcmd.cpp
@@ -122,6 +122,11 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
symtable.add("min", 2, 2, std::bind(&debugger_commands::execute_min, this, _1, _2));
symtable.add("max", 2, 2, std::bind(&debugger_commands::execute_max, this, _1, _2));
symtable.add("if", 3, 3, std::bind(&debugger_commands::execute_if, this, _1, _2));
+ symtable.add("abs", 1, 1, std::bind(&debugger_commands::execute_abs, this, _1, _2));
+ symtable.add("bit", 2, 3, std::bind(&debugger_commands::execute_bit, this, _1, _2));
+ symtable.add("s8", 1, 1, std::bind(&debugger_commands::execute_s8, this, _1, _2));
+ symtable.add("s16", 1, 1, std::bind(&debugger_commands::execute_s16, this, _1, _2));
+ symtable.add("s32", 1, 1, std::bind(&debugger_commands::execute_s32, this, _1, _2));
symtable.add("cpunum", std::bind(&debugger_commands::get_cpunum, this));
/* add all single-entry save state globals */
@@ -322,9 +327,9 @@ debugger_commands::debugger_commands(running_machine& machine, debugger_cpu& cpu
m_cheat.cpu[0] = m_cheat.cpu[1] = 0;
}
-/*-------------------------------------------------
- execute_min - return the minimum of two values
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_min - return the minimum of two values
+//-------------------------------------------------
u64 debugger_commands::execute_min(int params, const u64 *param)
{
@@ -332,9 +337,9 @@ u64 debugger_commands::execute_min(int params, const u64 *param)
}
-/*-------------------------------------------------
- execute_max - return the maximum of two values
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_max - return the maximum of two values
+//-------------------------------------------------
u64 debugger_commands::execute_max(int params, const u64 *param)
{
@@ -342,9 +347,9 @@ u64 debugger_commands::execute_max(int params, const u64 *param)
}
-/*-------------------------------------------------
- execute_if - if (a) return b; else return c;
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_if - if (a) return b; else return c;
+//-------------------------------------------------
u64 debugger_commands::execute_if(int params, const u64 *param)
{
@@ -353,6 +358,59 @@ u64 debugger_commands::execute_if(int params, const u64 *param)
//-------------------------------------------------
+// execute_abs - return the absolute value
+//-------------------------------------------------
+
+u64 debugger_commands::execute_abs(int params, const u64 *param)
+{
+ return std::abs(s64(param[0]));
+}
+
+
+//-------------------------------------------------
+// execute_bit - extract bit field from value
+//-------------------------------------------------
+
+u64 debugger_commands::execute_bit(int params, const u64 *param)
+{
+ if (params == 2)
+ return BIT(param[0], param[1]);
+ else
+ return BIT(param[0], param[1], param[2]);
+}
+
+
+//-------------------------------------------------
+// execute_s8 - sign-extend from 8 bits
+//-------------------------------------------------
+
+u64 debugger_commands::execute_s8(int params, const u64 *param)
+{
+ return s8(param[0]);
+}
+
+
+//-------------------------------------------------
+// execute_s16 - sign-extend from 16 bits
+//-------------------------------------------------
+
+u64 debugger_commands::execute_s16(int params, const u64 *param)
+{
+ return s16(param[0]);
+}
+
+
+//-------------------------------------------------
+// execute_s32 - sign-extend from 32 bits
+//-------------------------------------------------
+
+u64 debugger_commands::execute_s32(int params, const u64 *param)
+{
+ return s32(param[0]);
+}
+
+
+//-------------------------------------------------
// get_cpunum - getter callback for the
// 'cpunum' symbol
//-------------------------------------------------
@@ -592,12 +650,12 @@ bool debugger_commands::debug_command_parameter_command(const char *param)
/* validate the comment; success if no error */
CMDERR err = m_console.validate_command(param);
- if (err == CMDERR_NONE)
+ if (err.error_class() == CMDERR::NONE)
return true;
/* output an error */
m_console.printf("Error in command: %s\n", param);
- m_console.printf(" %*s^", CMDERR_ERROR_OFFSET(err), "");
+ m_console.printf(" %*s^", err.error_offset(), "");
m_console.printf("%s\n", debugger_console::cmderr_to_string(err));
return 0;
}
diff --git a/src/emu/debug/debugcmd.h b/src/emu/debug/debugcmd.h
index dad1979da39..e2ebec7e2fc 100644
--- a/src/emu/debug/debugcmd.h
+++ b/src/emu/debug/debugcmd.h
@@ -87,6 +87,11 @@ private:
u64 execute_min(int params, const u64 *param);
u64 execute_max(int params, const u64 *param);
u64 execute_if(int params, const u64 *param);
+ u64 execute_abs(int params, const u64 *param);
+ u64 execute_bit(int params, const u64 *param);
+ u64 execute_s8(int params, const u64 *param);
+ u64 execute_s16(int params, const u64 *param);
+ u64 execute_s32(int params, const u64 *param);
u64 get_cpunum();
u64 global_get(global_entry *global);
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp
index b547b1b536c..500310bd459 100644
--- a/src/emu/debug/debugcon.cpp
+++ b/src/emu/debug/debugcon.cpp
@@ -86,24 +86,15 @@ debugger_console::debugger_console(running_machine &machine)
void debugger_console::exit()
{
- /* free allocated memory */
- if (m_console_textbuf)
- {
- text_buffer_free(m_console_textbuf);
- }
- m_console_textbuf = nullptr;
-
- if (m_errorlog_textbuf)
- {
- text_buffer_free(m_errorlog_textbuf);
- }
- m_errorlog_textbuf = nullptr;
+ // free allocated memory
+ m_console_textbuf.reset();
+ m_errorlog_textbuf.reset();
- /* free the command list */
+ // free the command list
m_commandlist.clear();
- /* close the logfile, if any */
- m_logfile = nullptr;
+ // close the logfile, if any
+ m_logfile.reset();
}
@@ -167,7 +158,7 @@ void debugger_console::execute_condump(int ref, const std::vector<std::string>&
return;
}
- for (auto line_info : text_buffer_get_lines(m_console_textbuf))
+ for (auto line_info : text_buffer_lines(*m_console_textbuf))
{
fwrite(line_info.text, sizeof(char), line_info.length, f);
fputc('\n', f);
@@ -259,7 +250,7 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
/* no params is an error */
if (params == 0)
- return CMDERR_NONE;
+ return CMDERR::none();
/* the first parameter has the command and the real first parameter; separate them */
for (p = param[0]; *p && isspace(u8(*p)); p++) { }
@@ -296,9 +287,9 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
/* error if not found */
if (!found)
- return MAKE_CMDERR_UNKNOWN_COMMAND(0);
+ return CMDERR::unknown_command(0);
if (foundcount > 1)
- return MAKE_CMDERR_AMBIGUOUS_COMMAND(0);
+ return CMDERR::ambiguous_command(0);
/* NULL-terminate and trim space around all the parameters */
for (i = 1; i < params; i++)
@@ -310,9 +301,9 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
/* see if we have the right number of parameters */
if (params < found->minparams)
- return MAKE_CMDERR_NOT_ENOUGH_PARAMS(0);
+ return CMDERR::not_enough_params(0);
if (params > found->maxparams)
- return MAKE_CMDERR_TOO_MANY_PARAMS(0);
+ return CMDERR::too_many_params(0);
/* execute the handler */
if (execute)
@@ -320,7 +311,7 @@ CMDERR debugger_console::internal_execute_command(bool execute, int params, char
std::vector<std::string> params_vec(param, param + params);
found->handler(found->ref, params_vec);
}
- return CMDERR_NONE;
+ return CMDERR::none();
}
@@ -333,7 +324,6 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
{
char command[MAX_COMMAND_LENGTH], parens[MAX_COMMAND_LENGTH];
char *params[MAX_COMMAND_PARAMS] = { nullptr };
- CMDERR result;
char *command_start;
char *p, c = 0;
@@ -363,9 +353,9 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
case '(':
case '[':
case '{': parens[parendex++] = c; break;
- case ')': if (parendex == 0 || parens[--parendex] != '(') return MAKE_CMDERR_UNBALANCED_PARENS(p - command); break;
- case ']': if (parendex == 0 || parens[--parendex] != '[') return MAKE_CMDERR_UNBALANCED_PARENS(p - command); break;
- case '}': if (parendex == 0 || parens[--parendex] != '{') return MAKE_CMDERR_UNBALANCED_PARENS(p - command); break;
+ case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::unbalanced_parens(p - command); break;
+ case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::unbalanced_parens(p - command); break;
+ case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::unbalanced_parens(p - command); break;
case ',': if (parendex == 0) params[paramcount++] = p; break;
case ';': if (parendex == 0) foundend = true; break;
case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = true; *p = c; break;
@@ -379,9 +369,9 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
/* check for unbalanced parentheses or quotes */
if (instring)
- return MAKE_CMDERR_UNBALANCED_QUOTES(p - command);
+ return CMDERR::unbalanced_quotes(p - command);
if (parendex != 0)
- return MAKE_CMDERR_UNBALANCED_PARENS(p - command);
+ return CMDERR::unbalanced_parens(p - command);
/* NULL-terminate if we ended in a semicolon */
p--;
@@ -406,17 +396,17 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
}
catch (expression_error &err)
{
- return MAKE_CMDERR_EXPRESSION_ERROR(err);
+ return CMDERR::expression_error(err);
}
}
else
{
- result = internal_execute_command(execute, paramcount, &params[0]);
- if (result != CMDERR_NONE)
- return MAKE_CMDERR(CMDERR_ERROR_CLASS(result), command_start - command);
+ const CMDERR result = internal_execute_command(execute, paramcount, &params[0]);
+ if (result.error_class() != CMDERR::NONE)
+ return CMDERR(result.error_class(), command_start - command);
}
}
- return CMDERR_NONE;
+ return CMDERR::none();
}
@@ -426,21 +416,19 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm
CMDERR debugger_console::execute_command(const std::string &command, bool echo)
{
- CMDERR result;
-
/* echo if requested */
if (echo)
printf(">%s\n", command.c_str());
/* parse and execute */
- result = internal_parse_command(command, true);
+ const CMDERR result = internal_parse_command(command, true);
/* display errors */
- if (result != CMDERR_NONE)
+ if (result.error_class() != CMDERR::NONE)
{
if (!echo)
printf(">%s\n", command.c_str());
- printf(" %*s^\n", CMDERR_ERROR_OFFSET(result), "");
+ printf(" %*s^\n", result.error_offset(), "");
printf("%s\n", cmderr_to_string(result).c_str());
}
@@ -559,16 +547,16 @@ void debugger_console::process_source_file()
std::string debugger_console::cmderr_to_string(CMDERR error)
{
- int offset = CMDERR_ERROR_OFFSET(error);
- switch (CMDERR_ERROR_CLASS(error))
+ const int offset = error.error_offset();
+ switch (error.error_class())
{
- case CMDERR_UNKNOWN_COMMAND: return "unknown command";
- case CMDERR_AMBIGUOUS_COMMAND: return "ambiguous command";
- case CMDERR_UNBALANCED_PARENS: return "unbalanced parentheses";
- case CMDERR_UNBALANCED_QUOTES: return "unbalanced quotes";
- case CMDERR_NOT_ENOUGH_PARAMS: return "not enough parameters for command";
- case CMDERR_TOO_MANY_PARAMS: return "too many parameters for command";
- case CMDERR_EXPRESSION_ERROR: return string_format("error in assignment expression: %s",
+ case CMDERR::UNKNOWN_COMMAND: return "unknown command";
+ case CMDERR::AMBIGUOUS_COMMAND: return "ambiguous command";
+ case CMDERR::UNBALANCED_PARENS: return "unbalanced parentheses";
+ case CMDERR::UNBALANCED_QUOTES: return "unbalanced quotes";
+ case CMDERR::NOT_ENOUGH_PARAMS: return "not enough parameters for command";
+ case CMDERR::TOO_MANY_PARAMS: return "too many parameters for command";
+ case CMDERR::EXPRESSION_ERROR: return string_format("error in assignment expression: %s",
expression_error(static_cast<expression_error::error_code>(offset)).code_string());
default: return "unknown error";
}
@@ -591,7 +579,7 @@ std::string debugger_console::cmderr_to_string(CMDERR error)
void debugger_console::print_core(const char *text)
{
// FIXME: this invokes strlen() twice; compute it once and pass it to text_buffer_print
- text_buffer_print(m_console_textbuf, text);
+ text_buffer_print(*m_console_textbuf, text);
if (m_logfile)
m_logfile->write(text, strlen(text));
}
@@ -605,7 +593,7 @@ void debugger_console::print_core_wrap(const char *text, int wrapcol)
{
// FIXME: this invokes strlen() twice; compute it once and pass it to text_buffer_print
// FIXME: also look into honoring wrapcol for the logfile
- text_buffer_print_wrap(m_console_textbuf, text, wrapcol);
+ text_buffer_print_wrap(*m_console_textbuf, text, wrapcol);
if (m_logfile)
m_logfile->write(text, strlen(text));
}
@@ -627,7 +615,7 @@ void debugger_console::vprintf(util::format_argument_pack<std::ostream> &&args)
{
print_core(util::string_format(std::move(args)).c_str());
- /* force an update of any console views */
+ // force an update of any console views
m_machine.debug_view().update_all(DVT_CONSOLE);
}
@@ -641,7 +629,7 @@ void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std:
{
print_core_wrap(util::string_format(args).c_str(), wrapcol);
- /* force an update of any console views */
+ // force an update of any console views
m_machine.debug_view().update_all(DVT_CONSOLE);
}
@@ -649,7 +637,7 @@ void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std:
{
print_core_wrap(util::string_format(std::move(args)).c_str(), wrapcol);
- /* force an update of any console views */
+ // force an update of any console views
m_machine.debug_view().update_all(DVT_CONSOLE);
}
@@ -662,10 +650,8 @@ void debugger_console::vprintf_wrap(int wrapcol, util::format_argument_pack<std:
void debugger_console::errorlog_write_line(const char *line)
{
if (m_errorlog_textbuf)
- {
- text_buffer_print(m_errorlog_textbuf, line);
- }
+ text_buffer_print(*m_errorlog_textbuf, line);
- /* force an update of any log views */
+ // force an update of any log views
m_machine.debug_view().update_all(DVT_LOG);
}
diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h
index 949b236774a..2d811523650 100644
--- a/src/emu/debug/debugcon.h
+++ b/src/emu/debug/debugcon.h
@@ -25,20 +25,10 @@
#define MAX_COMMAND_LENGTH 4096
#define MAX_COMMAND_PARAMS 128
-/* flags for command parsing */
-#define CMDFLAG_NONE (0x0000)
-#define CMDFLAG_KEEP_QUOTES (0x0001)
-#define CMDFLAG_CUSTOM_HELP (0x0002)
-
-/* values for the error code in a command error */
-#define CMDERR_NONE (0)
-#define CMDERR_UNKNOWN_COMMAND (1)
-#define CMDERR_AMBIGUOUS_COMMAND (2)
-#define CMDERR_UNBALANCED_PARENS (3)
-#define CMDERR_UNBALANCED_QUOTES (4)
-#define CMDERR_NOT_ENOUGH_PARAMS (5)
-#define CMDERR_TOO_MANY_PARAMS (6)
-#define CMDERR_EXPRESSION_ERROR (7)
+// flags for command parsing
+constexpr u32 CMDFLAG_NONE = 0x0000;
+constexpr u32 CMDFLAG_KEEP_QUOTES = 0x0001;
+constexpr u32 CMDFLAG_CUSTOM_HELP = 0x0002;
/* parameter separator macros */
#define CMDPARAM_SEPARATOR "\0"
@@ -47,53 +37,66 @@
/***************************************************************************
- MACROS
+ TYPE DEFINITIONS
***************************************************************************/
-/* command error assembly/disassembly macros */
-#define CMDERR_ERROR_CLASS(x) ((x) >> 16)
-#define CMDERR_ERROR_OFFSET(x) ((x) & 0xffff)
-#define MAKE_CMDERR(a,b) (((a) << 16) | ((b) & 0xffff))
-
-/* macros to assemble specific error conditions */
-#define MAKE_CMDERR_UNKNOWN_COMMAND(x) MAKE_CMDERR(CMDERR_UNKNOWN_COMMAND, (x))
-#define MAKE_CMDERR_AMBIGUOUS_COMMAND(x) MAKE_CMDERR(CMDERR_AMBIGUOUS_COMMAND, (x))
-#define MAKE_CMDERR_UNBALANCED_PARENS(x) MAKE_CMDERR(CMDERR_UNBALANCED_PARENS, (x))
-#define MAKE_CMDERR_UNBALANCED_QUOTES(x) MAKE_CMDERR(CMDERR_UNBALANCED_QUOTES, (x))
-#define MAKE_CMDERR_NOT_ENOUGH_PARAMS(x) MAKE_CMDERR(CMDERR_NOT_ENOUGH_PARAMS, (x))
-#define MAKE_CMDERR_TOO_MANY_PARAMS(x) MAKE_CMDERR(CMDERR_TOO_MANY_PARAMS, (x))
-#define MAKE_CMDERR_EXPRESSION_ERROR(x) MAKE_CMDERR(CMDERR_EXPRESSION_ERROR, (x))
+// CMDERR is an error code for command evaluation
+class CMDERR
+{
+public:
+ // values for the error code in a command error
+ static constexpr u16 NONE = 0;
+ static constexpr u16 UNKNOWN_COMMAND = 1;
+ static constexpr u16 AMBIGUOUS_COMMAND = 2;
+ static constexpr u16 UNBALANCED_PARENS = 3;
+ static constexpr u16 UNBALANCED_QUOTES = 4;
+ static constexpr u16 NOT_ENOUGH_PARAMS = 5;
+ static constexpr u16 TOO_MANY_PARAMS = 6;
+ static constexpr u16 EXPRESSION_ERROR = 7;
+
+ // command error assembly/disassembly
+ constexpr CMDERR(u16 c, u16 o) : m_error_class(c), m_error_offset(o) { }
+ constexpr u16 error_class() const { return m_error_class; }
+ constexpr u16 error_offset() const { return m_error_offset; }
+
+ // assemble specific error conditions
+ static constexpr CMDERR none() { return CMDERR(NONE, 0); }
+ static constexpr CMDERR unknown_command(u16 x) { return CMDERR(UNKNOWN_COMMAND, x); }
+ static constexpr CMDERR ambiguous_command(u16 x) { return CMDERR(AMBIGUOUS_COMMAND, x); }
+ static constexpr CMDERR unbalanced_parens(u16 x) { return CMDERR(UNBALANCED_PARENS, x); }
+ static constexpr CMDERR unbalanced_quotes(u16 x) { return CMDERR(UNBALANCED_QUOTES, x); }
+ static constexpr CMDERR not_enough_params(u16 x) { return CMDERR(NOT_ENOUGH_PARAMS, x); }
+ static constexpr CMDERR too_many_params(u16 x) { return CMDERR(TOO_MANY_PARAMS, x); }
+ static constexpr CMDERR expression_error(u16 x) { return CMDERR(EXPRESSION_ERROR, x); }
+private:
+ u16 m_error_class, m_error_offset;
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
+};
-/* CMDERR is an error code for command evaluation */
-typedef u32 CMDERR;
class debugger_console
{
public:
debugger_console(running_machine &machine);
- /* command handling */
+ // command handling
CMDERR execute_command(const std::string &command, bool echo);
CMDERR validate_command(const char *command);
void register_command(const char *command, u32 flags, int ref, int minparams, int maxparams, std::function<void(int, const std::vector<std::string> &)> handler);
void source_script(const char *file);
void process_source_file();
- /* console management */
- void vprintf(util::format_argument_pack<std::ostream> const &args);
- void vprintf(util::format_argument_pack<std::ostream> &&args);
- void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args);
- void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args);
- text_buffer * get_console_textbuf() const { return m_console_textbuf; }
+ // console management
+ void vprintf(util::format_argument_pack<std::ostream> const &args);
+ void vprintf(util::format_argument_pack<std::ostream> &&args);
+ void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> const &args);
+ void vprintf_wrap(int wrapcol, util::format_argument_pack<std::ostream> &&args);
+ text_buffer &get_console_textbuf() const { return *m_console_textbuf; }
/* errorlog management */
- void errorlog_write_line(const char *line);
- text_buffer * get_errorlog_textbuf() const { return m_errorlog_textbuf; }
+ void errorlog_write_line(const char *line);
+ text_buffer &get_errorlog_textbuf() const { return *m_errorlog_textbuf; }
/* convenience templates */
template <typename Format, typename... Params>
@@ -143,10 +146,10 @@ private:
running_machine &m_machine;
// visible CPU device (the one that commands should apply to)
- device_t *m_visiblecpu;
+ device_t *m_visiblecpu;
- text_buffer *m_console_textbuf;
- text_buffer *m_errorlog_textbuf;
+ text_buffer_ptr m_console_textbuf;
+ text_buffer_ptr m_errorlog_textbuf;
std::forward_list<debug_command> m_commandlist;
diff --git a/src/emu/debug/debugvw.cpp b/src/emu/debug/debugvw.cpp
index 1d88f0485e2..a104bb82529 100644
--- a/src/emu/debug/debugvw.cpp
+++ b/src/emu/debug/debugvw.cpp
@@ -326,7 +326,7 @@ debug_view_manager::~debug_view_manager()
{
debug_view *oldhead = m_viewlist;
m_viewlist = oldhead->m_next;
- global_free(oldhead);
+ delete oldhead;
}
}
@@ -340,25 +340,25 @@ debug_view *debug_view_manager::alloc_view(debug_view_type type, debug_view_osd_
switch (type)
{
case DVT_CONSOLE:
- return append(global_alloc(debug_view_console(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_console(machine(), osdupdate, osdprivate));
case DVT_STATE:
- return append(global_alloc(debug_view_state(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_state(machine(), osdupdate, osdprivate));
case DVT_DISASSEMBLY:
- return append(global_alloc(debug_view_disasm(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_disasm(machine(), osdupdate, osdprivate));
case DVT_MEMORY:
- return append(global_alloc(debug_view_memory(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_memory(machine(), osdupdate, osdprivate));
case DVT_LOG:
- return append(global_alloc(debug_view_log(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_log(machine(), osdupdate, osdprivate));
case DVT_BREAK_POINTS:
- return append(global_alloc(debug_view_breakpoints(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_breakpoints(machine(), osdupdate, osdprivate));
case DVT_WATCH_POINTS:
- return append(global_alloc(debug_view_watchpoints(machine(), osdupdate, osdprivate)));
+ return append(new debug_view_watchpoints(machine(), osdupdate, osdprivate));
default:
fatalerror("Attempt to create invalid debug view type %d\n", type);
@@ -378,7 +378,7 @@ void debug_view_manager::free_view(debug_view &view)
if (*viewptr == &view)
{
*viewptr = view.m_next;
- global_free(&view);
+ delete &view;
break;
}
}
diff --git a/src/emu/debug/dvtext.cpp b/src/emu/debug/dvtext.cpp
index 63ad674ec10..6a4d2893562 100644
--- a/src/emu/debug/dvtext.cpp
+++ b/src/emu/debug/dvtext.cpp
@@ -9,10 +9,12 @@
***************************************************************************/
#include "emu.h"
-#include "debugvw.h"
#include "dvtext.h"
+
#include "debugcon.h"
#include "debugger.h"
+#include "debugvw.h"
+
//**************************************************************************
// DEBUG VIEW TEXTBUF
@@ -22,11 +24,16 @@
// debug_view_textbuf - constructor
//-------------------------------------------------
-debug_view_textbuf::debug_view_textbuf(running_machine &machine, debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate, text_buffer &textbuf)
- : debug_view(machine, type, osdupdate, osdprivate),
- m_textbuf(textbuf),
- m_at_bottom(true),
- m_topseq(0)
+debug_view_textbuf::debug_view_textbuf(
+ running_machine &machine,
+ debug_view_type type,
+ debug_view_osd_update_func osdupdate,
+ void *osdprivate,
+ text_buffer &textbuf)
+ : debug_view(machine, type, osdupdate, osdprivate)
+ , m_textbuf(textbuf)
+ , m_at_bottom(true)
+ , m_topseq(0)
{
}
@@ -47,7 +54,7 @@ debug_view_textbuf::~debug_view_textbuf()
void debug_view_textbuf::clear()
{
begin_update();
- text_buffer_clear(&m_textbuf);
+ text_buffer_clear(m_textbuf);
m_at_bottom = true;
m_topseq = 0;
end_update();
@@ -61,8 +68,8 @@ void debug_view_textbuf::clear()
void debug_view_textbuf::view_update()
{
// update the console info
- m_total.x = text_buffer_max_width(&m_textbuf);
- m_total.y = text_buffer_num_lines(&m_textbuf);
+ m_total.x = text_buffer_max_width(m_textbuf);
+ m_total.y = text_buffer_num_lines(m_textbuf);
if (m_total.x < 80)
m_total.x = 80;
@@ -71,24 +78,24 @@ void debug_view_textbuf::view_update()
if (!m_at_bottom)
{
curseq = m_topseq;
- if (!text_buffer_get_seqnum_line(&m_textbuf, curseq))
+ if (!text_buffer_get_seqnum_line(m_textbuf, curseq))
m_at_bottom = true;
}
if (m_at_bottom)
{
- curseq = text_buffer_line_index_to_seqnum(&m_textbuf, m_total.y - 1);
+ curseq = text_buffer_line_index_to_seqnum(m_textbuf, m_total.y - 1);
if (m_total.y < m_visible.y)
curseq -= m_total.y - 1;
else
curseq -= m_visible.y - 1;
}
- m_topleft.y = curseq - text_buffer_line_index_to_seqnum(&m_textbuf, 0);
+ m_topleft.y = curseq - text_buffer_line_index_to_seqnum(m_textbuf, 0);
// loop over visible rows
debug_view_char *dest = &m_viewdata[0];
for (u32 row = 0; row < m_visible.y; row++)
{
- const char *line = text_buffer_get_seqnum_line(&m_textbuf, curseq++);
+ const char *line = text_buffer_get_seqnum_line(m_textbuf, curseq++);
u32 col = 0;
// if this visible row is valid, add it to the buffer
@@ -133,7 +140,7 @@ void debug_view_textbuf::view_notify(debug_view_notification type)
/* otherwise, track the seqence number of the top line */
if (!m_at_bottom)
- m_topseq = text_buffer_line_index_to_seqnum(&m_textbuf, m_topleft.y);
+ m_topseq = text_buffer_line_index_to_seqnum(m_textbuf, m_topleft.y);
}
}
@@ -148,7 +155,7 @@ void debug_view_textbuf::view_notify(debug_view_notification type)
//-------------------------------------------------
debug_view_console::debug_view_console(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
- : debug_view_textbuf(machine, DVT_CONSOLE, osdupdate, osdprivate, *machine.debugger().console().get_console_textbuf())
+ : debug_view_textbuf(machine, DVT_CONSOLE, osdupdate, osdprivate, machine.debugger().console().get_console_textbuf())
{
}
@@ -163,6 +170,6 @@ debug_view_console::debug_view_console(running_machine &machine, debug_view_osd_
//-------------------------------------------------
debug_view_log::debug_view_log(running_machine &machine, debug_view_osd_update_func osdupdate, void *osdprivate)
- : debug_view_textbuf(machine, DVT_LOG, osdupdate, osdprivate, *machine.debugger().console().get_errorlog_textbuf())
+ : debug_view_textbuf(machine, DVT_LOG, osdupdate, osdprivate, machine.debugger().console().get_errorlog_textbuf())
{
}
diff --git a/src/emu/debug/dvtext.h b/src/emu/debug/dvtext.h
index 14a323794db..e6b65c137b3 100644
--- a/src/emu/debug/dvtext.h
+++ b/src/emu/debug/dvtext.h
@@ -31,7 +31,12 @@ public:
protected:
// construction/destruction
- debug_view_textbuf(running_machine &machine, debug_view_type type, debug_view_osd_update_func osdupdate, void *osdprivate, text_buffer &textbuf);
+ debug_view_textbuf(
+ running_machine &machine,
+ debug_view_type type,
+ debug_view_osd_update_func osdupdate,
+ void *osdprivate,
+ text_buffer &textbuf);
virtual ~debug_view_textbuf();
protected:
@@ -41,9 +46,9 @@ protected:
private:
// internal state
- text_buffer & m_textbuf; /* pointer to the text buffer */
- bool m_at_bottom; /* are we tracking new stuff being added? */
- u32 m_topseq; /* sequence number of the top line */
+ text_buffer & m_textbuf; // pointer to the text buffer
+ bool m_at_bottom; // are we tracking new stuff being added?
+ u32 m_topseq; // sequence number of the top line
};
diff --git a/src/emu/debug/express.h b/src/emu/debug/express.h
index ea445c4b14a..e9e8a86ab78 100644
--- a/src/emu/debug/express.h
+++ b/src/emu/debug/express.h
@@ -248,8 +248,6 @@ private:
// a single token
class parse_token
{
- friend class simple_list<parse_token>;
-
// operator flags
enum
{
diff --git a/src/emu/debug/textbuf.cpp b/src/emu/debug/textbuf.cpp
index 395a58482a7..ab7bf6505b3 100644
--- a/src/emu/debug/textbuf.cpp
+++ b/src/emu/debug/textbuf.cpp
@@ -35,24 +35,17 @@ struct text_buffer
, linesize(lineoffs ? lines : 0)
{
}
- ~text_buffer()
- {
- if (buffer)
- delete [] buffer;
- if (lineoffs)
- delete [] lineoffs;
- }
- char *const buffer;
- s32 *const lineoffs;
- s32 const bufsize;
- s32 bufstart = 0;
- s32 bufend = 0;
- s32 const linesize;
- s32 linestart = 0;
- s32 lineend = 0;
- u32 linestartseq = 0;
- s32 maxwidth = 0;
+ std::unique_ptr<char []> const buffer;
+ std::unique_ptr<s32 []> const lineoffs;
+ s32 const bufsize;
+ s32 bufstart = 0;
+ s32 bufend = 0;
+ s32 const linesize;
+ s32 linestart = 0;
+ s32 lineend = 0;
+ u32 linestartseq = 0;
+ s32 maxwidth = 0;
/*-------------------------------------------------
buffer_used - return the number of bytes
@@ -88,22 +81,19 @@ struct text_buffer
text_buffer_alloc - allocate a new text buffer
-------------------------------------------------*/
-text_buffer *text_buffer_alloc(u32 bytes, u32 lines)
+text_buffer_ptr text_buffer_alloc(u32 bytes, u32 lines)
{
// allocate memory for the text buffer object
- text_buffer *const text(new (std::nothrow) text_buffer(bytes, lines));
+ text_buffer_ptr text(new (std::nothrow) text_buffer(bytes, lines));
if (!text)
return nullptr;
if (!text->buffer || !text->lineoffs)
- {
- delete text;
return nullptr;
- }
// initialize the buffer description
- text_buffer_clear(text);
+ text_buffer_clear(*text);
return text;
}
@@ -114,7 +104,7 @@ text_buffer *text_buffer_alloc(u32 bytes, u32 lines)
text buffer
-------------------------------------------------*/
-void text_buffer_free(text_buffer *text)
+void text_buffer_deleter::operator()(text_buffer *text) const
{
delete text;
}
@@ -124,21 +114,21 @@ void text_buffer_free(text_buffer *text)
text_buffer_clear - clear a text buffer
-------------------------------------------------*/
-void text_buffer_clear(text_buffer *text)
+void text_buffer_clear(text_buffer &text)
{
- /* reset all the buffer pointers and other bits */
- text->bufstart = 0;
- text->bufend = 0;
+ // reset all the buffer pointers and other bits
+ text.bufstart = 0;
+ text.bufend = 0;
- text->linestart = 0;
- text->lineend = 0;
- text->linestartseq = 0;
+ text.linestart = 0;
+ text.lineend = 0;
+ text.linestartseq = 0;
- text->maxwidth = 0;
+ text.maxwidth = 0;
- /* create the initial line */
- text->lineoffs[0] = 0;
- text->buffer[text->lineoffs[0]] = 0;
+ // create the initial line
+ text.lineoffs[0] = 0;
+ text.buffer[text.lineoffs[0]] = 0;
}
@@ -154,9 +144,9 @@ void text_buffer_clear(text_buffer *text)
buffer
-------------------------------------------------*/
-void text_buffer_print(text_buffer *text, const char *data)
+void text_buffer_print(text_buffer &text, const char *data)
{
- text_buffer_print_wrap(text, data, 10000);
+ text_buffer_print_wrap(text, data, MAX_LINE_LENGTH);
}
@@ -166,21 +156,21 @@ void text_buffer_print(text_buffer *text, const char *data)
column
-------------------------------------------------*/
-void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol)
+void text_buffer_print_wrap(text_buffer &text, const char *data, int wrapcol)
{
- s32 stopcol = (wrapcol < MAX_LINE_LENGTH) ? wrapcol : MAX_LINE_LENGTH;
+ s32 const stopcol = (wrapcol < MAX_LINE_LENGTH) ? wrapcol : MAX_LINE_LENGTH;
s32 needed_space;
/* we need to ensure there is enough space for this string plus enough for the max line length */
needed_space = s32(strlen(data)) + MAX_LINE_LENGTH;
/* make space in the buffer if we need to */
- while (text->buffer_space() < needed_space && text->linestart != text->lineend)
+ while (text.buffer_space() < needed_space && text.linestart != text.lineend)
{
- text->linestartseq++;
- if (++text->linestart >= text->linesize)
- text->linestart = 0;
- text->bufstart = text->lineoffs[text->linestart];
+ text.linestartseq++;
+ if (++text.linestart >= text.linesize)
+ text.linestart = 0;
+ text.bufstart = text.lineoffs[text.linestart];
}
/* now add the data */
@@ -191,14 +181,14 @@ void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol)
/* a CR resets our position */
if (ch == '\r')
- text->bufend = text->lineoffs[text->lineend];
+ text.bufend = text.lineoffs[text.lineend];
/* non-CR data is just characters */
else if (ch != '\n')
- text->buffer[text->bufend++] = ch;
+ text.buffer[text.bufend++] = ch;
/* an explicit newline or line-too-long condition inserts a newline */
- linelen = text->bufend - text->lineoffs[text->lineend];
+ linelen = text.bufend - text.lineoffs[text.lineend];
if (ch == '\n' || linelen >= stopcol)
{
int overflow = 0;
@@ -208,7 +198,7 @@ void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol)
{
/* scan backwards, removing characters along the way */
overflow = 1;
- while (overflow < linelen && text->buffer[text->bufend - overflow] != ' ')
+ while (overflow < linelen && text.buffer[text.bufend - overflow] != ' ')
overflow++;
/* if we found a space, take it; otherwise, reset and pretend we didn't try */
@@ -219,39 +209,39 @@ void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol)
}
/* did we beat the max width */
- if (linelen > text->maxwidth)
- text->maxwidth = linelen;
+ if (linelen > text.maxwidth)
+ text.maxwidth = linelen;
/* append a terminator */
if (overflow == 0)
- text->buffer[text->bufend++] = 0;
+ text.buffer[text.bufend++] = 0;
else
- text->buffer[text->bufend - overflow] = 0;
+ text.buffer[text.bufend - overflow] = 0;
/* determine what the next line will be */
- if (++text->lineend >= text->linesize)
- text->lineend = 0;
+ if (++text.lineend >= text.linesize)
+ text.lineend = 0;
/* if we're out of lines, consume the next one */
- if (text->lineend == text->linestart)
+ if (text.lineend == text.linestart)
{
- text->linestartseq++;
- if (++text->linestart >= text->linesize)
- text->linestart = 0;
- text->bufstart = text->lineoffs[text->linestart];
+ text.linestartseq++;
+ if (++text.linestart >= text.linesize)
+ text.linestart = 0;
+ text.bufstart = text.lineoffs[text.linestart];
}
/* if we don't have enough room in the buffer for a max line, wrap to the start */
- if (text->bufend + MAX_LINE_LENGTH + 1 >= text->bufsize)
- text->bufend = 0;
+ if (text.bufend + MAX_LINE_LENGTH + 1 >= text.bufsize)
+ text.bufend = 0;
/* create a new empty line */
- text->lineoffs[text->lineend] = text->bufend - (overflow ? (overflow - 1) : 0);
+ text.lineoffs[text.lineend] = text.bufend - (overflow ? (overflow - 1) : 0);
}
}
/* nullptr terminate what we have on this line */
- text->buffer[text->bufend] = 0;
+ text.buffer[text.bufend] = 0;
}
@@ -267,9 +257,9 @@ void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol)
width of all lines seen so far
-------------------------------------------------*/
-u32 text_buffer_max_width(text_buffer *text)
+u32 text_buffer_max_width(text_buffer const &text)
{
- return text->maxwidth;
+ return text.maxwidth;
}
@@ -278,12 +268,10 @@ u32 text_buffer_max_width(text_buffer *text)
lines in the text buffer
-------------------------------------------------*/
-u32 text_buffer_num_lines(text_buffer *text)
+u32 text_buffer_num_lines(text_buffer const &text)
{
- s32 lines = text->lineend + 1 - text->linestart;
- if (lines <= 0)
- lines += text->linesize;
- return lines;
+ s32 const lines = text.lineend + 1 - text.linestart;
+ return (lines <= 0) ? (lines + text.linesize) : lines;
}
@@ -292,9 +280,9 @@ u32 text_buffer_num_lines(text_buffer *text)
line index into a sequence number
-------------------------------------------------*/
-u32 text_buffer_line_index_to_seqnum(text_buffer *text, u32 index)
+u32 text_buffer_line_index_to_seqnum(text_buffer const &text, u32 index)
{
- return text->linestartseq + index;
+ return text.linestartseq + index;
}
@@ -303,18 +291,13 @@ u32 text_buffer_line_index_to_seqnum(text_buffer *text, u32 index)
an indexed line in the buffer
-------------------------------------------------*/
-const char *text_buffer_get_seqnum_line(text_buffer *text, u32 seqnum)
+const char *text_buffer_get_seqnum_line(text_buffer const &text, u32 seqnum)
{
- u32 numlines = text_buffer_num_lines(text);
- u32 index = seqnum - text->linestartseq;
+ u32 const numlines = text_buffer_num_lines(text);
+ u32 const index = seqnum - text.linestartseq;
if (index >= numlines)
return nullptr;
- return &text->buffer[text->lineoffs[(text->linestart + index) % text->linesize]];
-}
-
-text_buffer_lines text_buffer_get_lines(text_buffer *text)
-{
- return text_buffer_lines(*text);
+ return &text.buffer[text.lineoffs[(text.linestart + index) % text.linesize]];
}
/*---------------------------------------------------------------------
@@ -324,22 +307,21 @@ text_buffer_lines text_buffer_get_lines(text_buffer *text)
text_buffer_line text_buffer_lines::text_buffer_line_iterator::operator*() const
{
- const char *line = &m_buffer.buffer[m_buffer.lineoffs[m_lineptr]];
+ char const *const line = &m_buffer.buffer[m_buffer.lineoffs[m_lineptr]];
auto next_lineptr = m_lineptr + 1;
if (next_lineptr == m_buffer.linesize)
next_lineptr = 0;
- const char *nextline = &m_buffer.buffer[m_buffer.lineoffs[next_lineptr]];
-
- /* -1 for the '\0' at the end of line */
+ char const *const nextline = &m_buffer.buffer[m_buffer.lineoffs[next_lineptr]];
+ // -1 for the '\0' at the end of line
ptrdiff_t difference = (nextline - line) - 1;
if (difference < 0)
difference += m_buffer.bufsize;
- return text_buffer_line{ line, (size_t)difference };
+ return text_buffer_line{ line, size_t(difference) };
}
/*---------------------------------------------------------------------
diff --git a/src/emu/debug/textbuf.h b/src/emu/debug/textbuf.h
index f7514701eec..20ad94139bb 100644
--- a/src/emu/debug/textbuf.h
+++ b/src/emu/debug/textbuf.h
@@ -11,8 +11,11 @@
#ifndef MAME_EMU_DEBUG_TEXTBUF_H
#define MAME_EMU_DEBUG_TEXTBUF_H
+#include <memory>
+
#include "emucore.h"
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
@@ -25,29 +28,27 @@ struct text_buffer_line
size_t length;
};
-/* helper class that makes it possible to iterate over the lines of a text_buffer */
+// helper class for iterating over the lines of a text_buffer
class text_buffer_lines
{
private:
- text_buffer &m_buffer;
+ const text_buffer &m_buffer;
public:
- text_buffer_lines(text_buffer& buffer) : m_buffer(buffer) { }
+ text_buffer_lines(const text_buffer& buffer) : m_buffer(buffer) { }
class text_buffer_line_iterator
{
- text_buffer &m_buffer;
+ const text_buffer &m_buffer;
s32 m_lineptr;
public:
- text_buffer_line_iterator(text_buffer &buffer, s32 lineptr) :
+ text_buffer_line_iterator(const text_buffer &buffer, s32 lineptr) :
m_buffer(buffer),
m_lineptr(lineptr)
{
}
- /* technically this isn't a valid forward iterator, because
- * operator * doesn't return a reference
- */
+ // technically this isn't a valid forward iterator, because operator * doesn't return a reference
text_buffer_line operator*() const;
text_buffer_line_iterator &operator++();
@@ -55,7 +56,7 @@ public:
{
return m_lineptr != rhs.m_lineptr;
}
- /* according to C++ spec, only != is needed; == is present for completeness. */
+ // according to C++ spec, only != is needed; == is present for completeness.
bool operator==(const text_buffer_line_iterator& rhs) { return !operator!=(rhs); }
};
@@ -70,34 +71,32 @@ public:
FUNCTION PROTOTYPES
***************************************************************************/
-/* allocate a new text buffer */
-text_buffer *text_buffer_alloc(u32 bytes, u32 lines);
-
-/* free a text buffer */
-void text_buffer_free(text_buffer *text);
+// free a text buffer
+struct text_buffer_deleter { void operator()(text_buffer *text) const; };
+using text_buffer_ptr = std::unique_ptr<text_buffer, text_buffer_deleter>;
-/* clear a text buffer */
-void text_buffer_clear(text_buffer *text);
+// allocate a new text buffer
+text_buffer_ptr text_buffer_alloc(u32 bytes, u32 lines);
-/* "print" data to a text buffer */
-void text_buffer_print(text_buffer *text, const char *data);
+// clear a text buffer
+void text_buffer_clear(text_buffer &text);
-/* "print" data to a text buffer with word wrapping to a given column */
-void text_buffer_print_wrap(text_buffer *text, const char *data, int wrapcol);
+// "print" data to a text buffer
+void text_buffer_print(text_buffer &text, const char *data);
-/* get the maximum width of lines seen so far */
-u32 text_buffer_max_width(text_buffer *text);
+// "print" data to a text buffer with word wrapping to a given column
+void text_buffer_print_wrap(text_buffer &text, const char *data, int wrapcol);
-/* get the current number of lines in the buffer */
-u32 text_buffer_num_lines(text_buffer *text);
+// get the maximum width of lines seen so far
+u32 text_buffer_max_width(const text_buffer &text);
-/* get an absolute sequence number for a given line */
-u32 text_buffer_line_index_to_seqnum(text_buffer *text, u32 index);
+// get the current number of lines in the buffer
+u32 text_buffer_num_lines(const text_buffer &text);
-/* get a sequenced line from the text buffer */
-const char *text_buffer_get_seqnum_line(text_buffer *text, u32 seqnum);
+// get an absolute sequence number for a given line
+u32 text_buffer_line_index_to_seqnum(const text_buffer &text, u32 index);
-/* get an iterable container of the lines in the buffer */
-text_buffer_lines text_buffer_get_lines(text_buffer* text);
+// get a sequenced line from the text buffer
+const char *text_buffer_get_seqnum_line(const text_buffer &text, u32 seqnum);
-#endif /* MAME_EMU_DEBUG_TEXTBUF_H */
+#endif // MAME_EMU_DEBUG_TEXTBUF_H
diff --git a/src/emu/device.h b/src/emu/device.h
index 55c3641f678..53534fe60d5 100644
--- a/src/emu/device.h
+++ b/src/emu/device.h
@@ -205,7 +205,7 @@ private:
template <typename DeviceClass>
static std::unique_ptr<device_t> create_device(device_type_impl_base const &type, machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
{
- return make_unique_clear<DeviceClass>(mconfig, tag, owner, clock);
+ return std::make_unique<DeviceClass>(mconfig, tag, owner, clock);
}
template <typename DriverClass>
@@ -298,7 +298,7 @@ public:
template <typename... Params>
std::unique_ptr<DeviceClass> create(machine_config &mconfig, char const *tag, device_t *owner, Params &&... args) const
{
- return make_unique_clear<DeviceClass>(mconfig, tag, owner, std::forward<Params>(args)...);
+ return std::make_unique<DeviceClass>(mconfig, tag, owner, std::forward<Params>(args)...);
}
template <typename... Params> DeviceClass &operator()(machine_config &mconfig, char const *tag, Params &&... args) const;
diff --git a/src/emu/disound.cpp b/src/emu/disound.cpp
index d2c063ff205..10d16150b76 100644
--- a/src/emu/disound.cpp
+++ b/src/emu/disound.cpp
@@ -66,15 +66,10 @@ device_sound_interface &device_sound_interface::add_route(u32 output, device_t &
//-------------------------------------------------
-// stream_alloc_legacy - allocate a stream implicitly
+// stream_alloc - allocate a stream implicitly
// associated with this device
//-------------------------------------------------
-sound_stream *device_sound_interface::stream_alloc_legacy(int inputs, int outputs, int sample_rate)
-{
- return device().machine().sound().stream_alloc_legacy(*this, inputs, outputs, sample_rate, stream_update_legacy_delegate(&device_sound_interface::sound_stream_update_legacy, this));
-}
-
sound_stream *device_sound_interface::stream_alloc(int inputs, int outputs, int sample_rate)
{
return device().machine().sound().stream_alloc(*this, inputs, outputs, sample_rate, stream_update_delegate(&device_sound_interface::sound_stream_update, this), STREAM_DEFAULT_FLAGS);
@@ -382,17 +377,6 @@ void device_sound_interface::interface_pre_reset()
//-------------------------------------------------
-// sound_stream_update_legacy - implementation
-// that should be overridden by legacy devices
-//-------------------------------------------------
-
-void device_sound_interface::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
-{
- throw emu_fatalerror("sound_stream_update_legacy called but not overridden by owning class");
-}
-
-
-//-------------------------------------------------
// sound_stream_update - default implementation
// that should be overridden
//-------------------------------------------------
diff --git a/src/emu/disound.h b/src/emu/disound.h
index d6135123ddb..2e4546da52c 100644
--- a/src/emu/disound.h
+++ b/src/emu/disound.h
@@ -77,11 +77,9 @@ public:
device_sound_interface &reset_routes() { m_route_list.clear(); return *this; }
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples);
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs);
// stream creation
- sound_stream *stream_alloc_legacy(int inputs, int outputs, int sample_rate);
sound_stream *stream_alloc(int inputs, int outputs, int sample_rate);
sound_stream *stream_alloc(int inputs, int outputs, int sample_rate, sound_stream_flags flags);
@@ -138,7 +136,7 @@ protected:
// internal state
u8 m_outputs; // number of outputs
std::vector<u8> m_outputmap; // map of inputs to outputs
- std::vector<bool> m_output_clear; // flag for tracking cleared buffers
+ std::vector<bool> m_output_clear; // flag for tracking cleared buffers
sound_stream *m_mixer_stream; // mixing stream
};
diff --git a/src/emu/distate.cpp b/src/emu/distate.cpp
index ae8ba0b0e63..06e3d1947af 100644
--- a/src/emu/distate.cpp
+++ b/src/emu/distate.cpp
@@ -56,8 +56,7 @@ device_state_entry::device_state_entry(int index, const char *symbol, u8 size, u
m_datasize(size),
m_flags(flags),
m_symbol(symbol),
- m_default_format(true),
- m_sizemask(sizemask)
+ m_default_format(true)
{
assert(size == 1 || size == 2 || size == 4 || size == 8 || (flags & DSF_FLOATING_POINT) != 0);
@@ -79,8 +78,7 @@ device_state_entry::device_state_entry(int index, device_state_interface *dev)
m_datasize(0),
m_flags(DSF_DIVIDER | DSF_READONLY),
m_symbol(),
- m_default_format(true),
- m_sizemask(0)
+ m_default_format(true)
{
}
diff --git a/src/emu/distate.h b/src/emu/distate.h
index 5ab34a24cf9..5888313440e 100644
--- a/src/emu/distate.h
+++ b/src/emu/distate.h
@@ -119,7 +119,6 @@ private:
std::string m_symbol; // symbol for display; all lower-case version for expressions
std::string m_format; // supported formats
bool m_default_format; // true if we are still using default format
- u64 m_sizemask; // mask derived from the data size
};
diff --git a/src/emu/emualloc.cpp b/src/emu/emualloc.cpp
index bc08416abb9..1dd78feaeed 100644
--- a/src/emu/emualloc.cpp
+++ b/src/emu/emualloc.cpp
@@ -143,7 +143,7 @@ void resource_pool::remove(void *ptr)
// delete the object and break
if (LOG_ALLOCS)
fprintf(stderr, "#%06d, delete %d bytes\n", u32(deleteme->m_id), u32(deleteme->m_size));
- global_free(deleteme);
+ delete deleteme;
break;
}
}
diff --git a/src/emu/emualloc.h b/src/emu/emualloc.h
index 0ed7cc7ea75..630c3d0a1fd 100644
--- a/src/emu/emualloc.h
+++ b/src/emu/emualloc.h
@@ -26,10 +26,10 @@
//**************************************************************************
// pool allocation helpers
-#define pool_alloc(_pool, _type) (_pool).add_object(global_alloc(_type))
-#define pool_alloc_clear(_pool, _type) (_pool).add_object(global_alloc_clear _type)
-#define pool_alloc_array(_pool, _type, _num) (_pool).add_array(global_alloc_array(_type,_num), (_num))
-#define pool_alloc_array_clear(_pool, _type, _num) (_pool).add_array(global_alloc_array_clear<_type>(_num), (_num))
+#define pool_alloc(_pool, _type) (_pool).add_object(new _type)
+#define pool_alloc_clear(_pool, _type) (_pool).add_object(make_unique_clear _type .release())
+#define pool_alloc_array(_pool, _type, _num) (_pool).add_array(new _type [_num], (_num))
+#define pool_alloc_array_clear(_pool, _type, _num) (_pool).add_array(make_unique_clear<_type []>(_num).release(), (_num))
#define pool_free(_pool, v) (_pool).remove(v)
diff --git a/src/emu/emucore.h b/src/emu/emucore.h
index b03612512cd..5a2446637c8 100644
--- a/src/emu/emucore.h
+++ b/src/emu/emucore.h
@@ -85,9 +85,6 @@ typedef void genf(void);
// pen_t is used to represent pixel values in bitmaps
typedef u32 pen_t;
-// stream_sample_t is used to represent a single sample in a sound stream
-typedef s32 stream_sample_t;
-
//**************************************************************************
diff --git a/src/emu/fileio.cpp b/src/emu/fileio.cpp
index 2233586fe6b..2a2682874c4 100644
--- a/src/emu/fileio.cpp
+++ b/src/emu/fileio.cpp
@@ -762,16 +762,21 @@ osd_file::error emu_file::attempt_zipped()
int header = -1;
// see if we can find a file with the right name and (if available) CRC
- if (m_openflags & OPEN_FLAG_HAS_CRC) header = zip->search(m_crc, filename, false);
- if (header < 0 && (m_openflags & OPEN_FLAG_HAS_CRC)) header = zip->search(m_crc, filename, true);
+ if (m_openflags & OPEN_FLAG_HAS_CRC)
+ header = zip->search(m_crc, filename, false);
+ if (header < 0 && (m_openflags & OPEN_FLAG_HAS_CRC))
+ header = zip->search(m_crc, filename, true);
// if that failed, look for a file with the right CRC, but the wrong filename
- if (header < 0 && (m_openflags & OPEN_FLAG_HAS_CRC)) header = zip->search(m_crc);
+ if (header < 0 && (m_openflags & OPEN_FLAG_HAS_CRC))
+ header = zip->search(m_crc);
// if that failed, look for a file with the right name;
// reporting a bad checksum is more helpful and less confusing than reporting "ROM not found"
- if (header < 0) header = zip->search(filename, false);
- if (header < 0) header = zip->search(filename, true);
+ if (header < 0)
+ header = zip->search(filename, false);
+ if (header < 0)
+ header = zip->search(filename, true);
// if we got it, read the data
if (header >= 0)
@@ -782,6 +787,7 @@ osd_file::error emu_file::attempt_zipped()
// build a hash with just the CRC
m_hashes.reset();
m_hashes.add_crc(m_zipfile->current_crc());
+ m_fullpath = savepath;
return (m_openflags & OPEN_FLAG_NO_PRELOAD) ? osd_file::error::NONE : load_zipped_file();
}
diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp
index f406ee6420b..e9fd8d7b6d7 100644
--- a/src/emu/ioport.cpp
+++ b/src/emu/ioport.cpp
@@ -1282,7 +1282,7 @@ void ioport_field::expand_diplocation(const char *location, std::string &errorbu
errorbuf.append(string_format("Switch location '%s' has invalid format!\n", location));
// allocate a new entry
- m_diploclist.append(*global_alloc(ioport_diplocation(name.c_str(), swnum, invert)));
+ m_diploclist.append(*new ioport_diplocation(name.c_str(), swnum, invert));
entries++;
// advance to the next item
@@ -1618,15 +1618,15 @@ ioport_port_live::ioport_port_live(ioport_port &port)
// allocate analog state if it's analog
analog_field *analog = nullptr;
if (field.is_analog())
- analog = &analoglist.append(*global_alloc(analog_field(field)));
+ analog = &analoglist.append(*new analog_field(field));
// allocate a dynamic field for reading
if (field.has_dynamic_read())
- readlist.append(*global_alloc(dynamic_field(field)));
+ readlist.append(*new dynamic_field(field));
// allocate a dynamic field for writing
if (field.has_dynamic_write())
- writelist.append(*global_alloc(dynamic_field(field)));
+ writelist.append(*new dynamic_field(field));
// let the field initialize its live state
field.init_live_state(analog);
@@ -1694,9 +1694,10 @@ time_t ioport_manager::initialize()
if (&port.second->device() == &device)
{
for (ioport_field &field : port.second->fields())
- if (field.type_class()==INPUT_CLASS_CONTROLLER)
+ if (field.type_class() == INPUT_CLASS_CONTROLLER)
{
- if (players < field.player() + 1) players = field.player() + 1;
+ if (players < field.player() + 1)
+ players = field.player() + 1;
field.set_player(field.player() + player_offset);
}
}
@@ -1956,7 +1957,7 @@ digital_joystick &ioport_manager::digjoystick(int player, int number)
return joystick;
// create a new one
- return m_joystick_list.append(*global_alloc(digital_joystick(player, number)));
+ return m_joystick_list.append(*new digital_joystick(player, number));
}
@@ -2120,6 +2121,67 @@ void ioport_manager::load_config(config_type cfg_type, util::xml::data_node cons
for (input_type_entry &entry : m_typelist)
for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; ++seqtype)
entry.defseq(seqtype) = entry.seq(seqtype);
+
+ // load keyboard enable/disable state
+ if (cfg_type == config_type::GAME)
+ {
+ std::vector<bool> kbd_enable_set;
+ bool keyboard_enabled = false, missing_enabled = false;
+ for (util::xml::data_node const *kbdnode = parentnode->get_child("keyboard"); kbdnode; kbdnode = kbdnode->get_next_sibling("keyboard"))
+ {
+ char const *const tag = kbdnode->get_attribute_string("tag", nullptr);
+ int const enabled = kbdnode->get_attribute_int("enabled", -1);
+ if (tag && (0 <= enabled))
+ {
+ size_t i;
+ for (i = 0; natkeyboard().keyboard_count() > i; ++i)
+ {
+ if (!strcmp(natkeyboard().keyboard_device(i).tag(), tag))
+ {
+ if (kbd_enable_set.empty())
+ kbd_enable_set.resize(natkeyboard().keyboard_count(), false);
+ kbd_enable_set[i] = true;
+ if (enabled)
+ {
+ if (!natkeyboard().keyboard_is_keypad(i))
+ keyboard_enabled = true;
+ natkeyboard().enable_keyboard(i);
+ }
+ else
+ {
+ natkeyboard().disable_keyboard(i);
+ }
+ break;
+ }
+ }
+ missing_enabled = missing_enabled || (enabled && (natkeyboard().keyboard_count() <= i));
+ }
+ }
+
+ // if keyboard enable configuration was loaded, patch it up for principle of least surprise
+ if (!kbd_enable_set.empty())
+ {
+ for (size_t i = 0; natkeyboard().keyboard_count() > i; ++i)
+ {
+ if (!natkeyboard().keyboard_is_keypad(i))
+ {
+ if (!keyboard_enabled && missing_enabled)
+ {
+ natkeyboard().enable_keyboard(i);
+ keyboard_enabled = true;
+ }
+ else if (!kbd_enable_set[i])
+ {
+ if (keyboard_enabled)
+ natkeyboard().disable_keyboard(i);
+ else
+ natkeyboard().enable_keyboard(i);
+ keyboard_enabled = true;
+ }
+ }
+ }
+ }
+ }
}
@@ -2358,6 +2420,14 @@ void ioport_manager::save_default_inputs(util::xml::data_node &parentnode)
void ioport_manager::save_game_inputs(util::xml::data_node &parentnode)
{
+ // save keyboard enable/disable state
+ for (size_t i = 0; natkeyboard().keyboard_count() > i; ++i)
+ {
+ util::xml::data_node *const kbdnode = parentnode.add_child("keyboard", nullptr);
+ kbdnode->set_attribute("tag", natkeyboard().keyboard_device(i).tag());
+ kbdnode->set_attribute_int("enabled", natkeyboard().keyboard_enabled(i));
+ }
+
// iterate over ports
for (auto &port : m_portlist)
for (ioport_field &field : port.second->fields())
@@ -3011,7 +3081,7 @@ ioport_configurer& ioport_configurer::field_alloc(ioport_type type, ioport_value
// append the field
if (type != IPT_UNKNOWN && type != IPT_UNUSED)
m_curport->m_active |= mask;
- m_curfield = &m_curport->m_fieldlist.append(*global_alloc(ioport_field(*m_curport, type, defval, mask, string_from_token(name))));
+ m_curfield = &m_curport->m_fieldlist.append(*new ioport_field(*m_curport, type, defval, mask, string_from_token(name)));
// reset the current setting
m_cursetting = nullptr;
@@ -3068,7 +3138,7 @@ ioport_configurer& ioport_configurer::setting_alloc(ioport_value value, const ch
if (m_curfield == nullptr)
throw emu_fatalerror("alloc_setting called with no active field (value=%X name=%s)\n", value, name);
- m_cursetting = global_alloc(ioport_setting(*m_curfield, value & m_curfield->mask(), string_from_token(name)));
+ m_cursetting = new ioport_setting(*m_curfield, value & m_curfield->mask(), string_from_token(name));
// append a new setting
m_curfield->m_settinglist.append(*m_cursetting);
return *this;
diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp
index ada0f04672e..246cca0dd3e 100644
--- a/src/emu/machine.cpp
+++ b/src/emu/machine.cpp
@@ -199,7 +199,7 @@ void running_machine::start()
m_soft_reset_timer = m_scheduler.timer_alloc(timer_expired_delegate(FUNC(running_machine::soft_reset), this));
// initialize UI input
- m_ui_input = make_unique_clear<ui_input_manager>(*this);
+ m_ui_input = std::make_unique<ui_input_manager>(*this);
// init the osd layer
m_manager.osd().init(*this);
@@ -230,7 +230,7 @@ void running_machine::start()
// needs rom bases), and finally initialize CPUs (which needs
// complete address spaces). These operations must proceed in this
// order
- m_rom_load = make_unique_clear<rom_load_manager>(*this);
+ m_rom_load = std::make_unique<rom_load_manager>(*this);
m_memory.initialize();
// save the random seed or save states might be broken in drivers that use the rand() method
@@ -239,7 +239,7 @@ void running_machine::start()
// initialize image devices
m_image = std::make_unique<image_manager>(*this);
m_tilemap = std::make_unique<tilemap_manager>(*this);
- m_crosshair = make_unique_clear<crosshair_manager>(*this);
+ m_crosshair = std::make_unique<crosshair_manager>(*this);
m_network = std::make_unique<network_manager>(*this);
// initialize the debugger
diff --git a/src/emu/natkeyboard.cpp b/src/emu/natkeyboard.cpp
index 53a95f46a4b..85c1b986205 100644
--- a/src/emu/natkeyboard.cpp
+++ b/src/emu/natkeyboard.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles,Vas Crabb
/***************************************************************************
natkeyboard.cpp
@@ -12,6 +12,9 @@
#include "natkeyboard.h"
#include "emuopts.h"
+#include <algorithm>
+#include <cstring>
+
//**************************************************************************
// DEBUGGING
@@ -317,9 +320,11 @@ const char_info charinfo[] =
natural_keyboard::natural_keyboard(running_machine &machine)
: m_machine(machine)
+ , m_have_charkeys(false)
, m_in_use(false)
, m_bufbegin(0)
, m_bufend(0)
+ , m_current_code(nullptr)
, m_fieldnum(0)
, m_status_keydown(false)
, m_last_cr(false)
@@ -330,8 +335,8 @@ natural_keyboard::natural_keyboard(running_machine &machine)
, m_charqueue_empty()
{
// try building a list of keycodes; if none are available, don't bother
- build_codes(machine.ioport());
- if (!m_keycode_map.empty())
+ build_codes();
+ if (m_have_charkeys)
{
m_buffer.resize(KEY_BUFFER_SIZE);
m_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(natural_keyboard::timer), this));
@@ -370,16 +375,18 @@ void natural_keyboard::set_in_use(bool usage)
machine().options().set_value(OPTION_NATURAL_KEYBOARD, usage, OPTION_PRIORITY_CMDLINE);
// lock out (or unlock) all keyboard inputs
- for (auto &port : machine().ioport().ports())
- for (ioport_field &field : port.second->fields())
- if (field.type() == IPT_KEYBOARD)
- {
- field.live().lockout = usage;
+ for (kbd_dev_info &devinfo : m_keyboards)
+ {
+ for (ioport_field &field : devinfo.keyfields)
+ {
+ bool const is_keyboard(field.type() == IPT_KEYBOARD);
+ field.live().lockout = !devinfo.enabled || (is_keyboard && usage);
- // clear pressed status when going out of use
- if (!usage)
- field.set_value(0);
- }
+ // clear pressed status when going out of use
+ if (is_keyboard && !usage)
+ field.set_value(0);
+ }
+ }
}
}
@@ -413,19 +420,24 @@ void natural_keyboard::post_char(char32_t ch, bool normalize_crlf)
machine().logerror("natural_keyboard::post_char(): code=%i (%s) field.name='%s'\n", int(ch), unicode_to_string(ch).c_str(), (code != nullptr && code->field[0] != nullptr) ? code->field[0]->name() : "<null>");
}
- // can we post this key in the queue directly?
if (can_post_directly(ch))
+ {
+ // can post this key in the queue directly
internal_post(ch);
-
- // can we post this key with an alternate representation?
+ }
else if (can_post_alternate(ch))
{
- const char_info *info = char_info::find(ch);
+ // can post this key with an alternate representation
+ char_info const *const info = char_info::find(ch);
assert(info != nullptr && info->alternate != nullptr);
- const char *altstring = info->alternate;
- while (*altstring != 0)
+ char const *altstring = info->alternate;
+ unsigned remain(std::strlen(altstring));
+ while (remain)
{
- altstring += uchar_from_utf8(&ch, altstring, strlen(altstring));
+ int const used(uchar_from_utf8(&ch, altstring, remain));
+ assert(0 < used);
+ altstring += used;
+ remain -= used;
internal_post(ch);
}
}
@@ -601,16 +613,60 @@ void natural_keyboard::paste()
// chars
//-------------------------------------------------
-void natural_keyboard::build_codes(ioport_manager &manager)
+void natural_keyboard::build_codes()
{
- // find all shift keys
- unsigned mask = 0;
- std::array<ioport_field *, SHIFT_COUNT> shift;
- std::fill(std::begin(shift), std::end(shift), nullptr);
+ ioport_manager &manager(machine().ioport());
+
+ // find all the devices with keyboard or keypad inputs
for (auto const &port : manager.ports())
{
+ auto devinfo(
+ std::find_if(
+ m_keyboards.begin(),
+ m_keyboards.end(),
+ [&port] (kbd_dev_info const &info)
+ {
+ return &port.second->device() == &info.device.get();
+ }));
for (ioport_field &field : port.second->fields())
{
+ bool const is_keyboard(field.type() == IPT_KEYBOARD);
+ if (is_keyboard || (field.type() == IPT_KEYPAD))
+ {
+ if (m_keyboards.end() == devinfo)
+ devinfo = m_keyboards.emplace(devinfo, port.second->device());
+ devinfo->keyfields.emplace_back(field);
+ if (is_keyboard)
+ devinfo->keyboard = true;
+ else
+ devinfo->keypad = true;
+ }
+ }
+ }
+ std::sort(
+ std::begin(m_keyboards),
+ std::end(m_keyboards),
+ [] (kbd_dev_info const &l, kbd_dev_info const &r)
+ {
+ return 0 > std::strcmp(l.device.get().tag(), r.device.get().tag());
+ });
+
+ // set up key mappings for each keyboard
+ std::array<ioport_field *, SHIFT_COUNT> shift;
+ unsigned mask;
+ bool have_keyboard(false);
+ for (kbd_dev_info &devinfo : m_keyboards)
+ {
+ // enable all pure keypads and the first keyboard
+ if (!devinfo.keyboard || !have_keyboard)
+ devinfo.enabled = true;
+ have_keyboard = have_keyboard || devinfo.keyboard;
+
+ // find all shift keys
+ std::fill(std::begin(shift), std::end(shift), nullptr);
+ mask = 0;
+ for (ioport_field &field : devinfo.keyfields)
+ {
if (field.type() == IPT_KEYBOARD)
{
std::vector<char32_t> const codes = field.keyboard_codes(0);
@@ -624,13 +680,11 @@ void natural_keyboard::build_codes(ioport_manager &manager)
}
}
}
- }
- // iterate over ports and fields
- for (auto const &port : manager.ports())
- {
- for (ioport_field &field : port.second->fields())
+ // iterate over keyboard/keypad fields
+ for (ioport_field &field : devinfo.keyfields)
{
+ field.live().lockout = !devinfo.enabled;
if (field.type() == IPT_KEYBOARD)
{
// iterate over all shift states
@@ -644,13 +698,14 @@ void natural_keyboard::build_codes(ioport_manager &manager)
{
if (((code < UCHAR_SHIFT_BEGIN) || (code > UCHAR_SHIFT_END)) && (code != 0))
{
- keycode_map::iterator const found(m_keycode_map.find(code));
+ m_have_charkeys = true;
+ keycode_map::iterator const found(devinfo.codemap.find(code));
keycode_map_entry newcode;
std::fill(std::begin(newcode.field), std::end(newcode.field), nullptr);
newcode.shift = curshift;
newcode.condition = field.condition();
- unsigned fieldnum = 0;
+ unsigned fieldnum(0);
for (unsigned i = 0, bits = curshift; (i < SHIFT_COUNT) && bits; ++i, bits >>= 1)
{
if (BIT(bits, 0))
@@ -658,11 +713,11 @@ void natural_keyboard::build_codes(ioport_manager &manager)
}
newcode.field[fieldnum] = &field;
- if (m_keycode_map.end() == found)
+ if (devinfo.codemap.end() == found)
{
keycode_map_entries entries;
entries.emplace_back(newcode);
- m_keycode_map.emplace(code, std::move(entries));
+ devinfo.codemap.emplace(code, std::move(entries));
}
else
found->second.emplace_back(newcode);
@@ -670,7 +725,7 @@ void natural_keyboard::build_codes(ioport_manager &manager)
if (LOG_NATURAL_KEYBOARD)
{
machine().logerror("natural_keyboard: code=%u (%s) port=%p field.name='%s'\n",
- code, unicode_to_string(code), (void *)&port, field.name());
+ code, unicode_to_string(code), (void *)&field.port(), field.name());
}
}
}
@@ -678,15 +733,31 @@ void natural_keyboard::build_codes(ioport_manager &manager)
}
}
}
+
+ // sort mapping entries by shift state
+ for (auto &mapping : devinfo.codemap)
+ {
+ std::sort(
+ mapping.second.begin(),
+ mapping.second.end(),
+ [] (keycode_map_entry const &x, keycode_map_entry const &y) { return x.shift < y.shift; });
+ }
}
+}
- // sort mapping entries by shift state
- for (auto &mapping : m_keycode_map)
+
+//-------------------------------------------------
+// set_keyboard_enabled - enable or disable a
+// device with key inputs
+//-------------------------------------------------
+
+void natural_keyboard::set_keyboard_enabled(size_t n, bool enable)
+{
+ if (enable != m_keyboards[n].enabled)
{
- std::sort(
- mapping.second.begin(),
- mapping.second.end(),
- [] (keycode_map_entry const &x, keycode_map_entry const &y) { return x.shift < y.shift; });
+ m_keyboards[n].enabled = enable;
+ for (ioport_field &field : m_keyboards[n].keyfields)
+ field.live().lockout = !enable || ((field.type() == IPT_KEYBOARD) && in_use());
}
}
@@ -801,13 +872,15 @@ void natural_keyboard::timer(void *ptr, int param)
// the driver does not have a queue_chars handler
// loop through this character's component codes
- const keycode_map_entry *const code = find_code(m_buffer[m_bufbegin]);
+ if (!m_fieldnum)
+ m_current_code = find_code(m_buffer[m_bufbegin]);
bool advance;
- if (code)
+ if (m_current_code)
{
+ keycode_map_entry const code(*m_current_code);
do
{
- ioport_field *const field = code->field[m_fieldnum];
+ ioport_field *const field = code.field[m_fieldnum];
if (field)
{
// special handling for toggle fields
@@ -817,8 +890,8 @@ void natural_keyboard::timer(void *ptr, int param)
field->set_value(!field->digital_value());
}
}
- while (code->field[m_fieldnum] && (++m_fieldnum < code->field.size()) && m_status_keydown);
- advance = (m_fieldnum >= code->field.size()) || !code->field[m_fieldnum];
+ while (code.field[m_fieldnum] && (++m_fieldnum < code.field.size()) && m_status_keydown);
+ advance = (m_fieldnum >= code.field.size()) || !code.field[m_fieldnum];
}
else
{
@@ -888,13 +961,20 @@ std::string natural_keyboard::unicode_to_string(char32_t ch) const
const natural_keyboard::keycode_map_entry *natural_keyboard::find_code(char32_t ch) const
{
- keycode_map::const_iterator const found(m_keycode_map.find(ch));
- if (m_keycode_map.end() == found)
- return nullptr;
- for (keycode_map_entry const &entry : found->second)
+ for (kbd_dev_info const &devinfo : m_keyboards)
{
- if (entry.condition.eval())
- return &entry;
+ if (devinfo.enabled)
+ {
+ keycode_map::const_iterator const found(devinfo.codemap.find(ch));
+ if (devinfo.codemap.end() != found)
+ {
+ for (keycode_map_entry const &entry : found->second)
+ {
+ if (entry.condition.eval())
+ return &entry;
+ }
+ }
+ }
}
return nullptr;
}
@@ -908,25 +988,43 @@ void natural_keyboard::dump(std::ostream &str) const
{
constexpr size_t left_column_width = 24;
- // loop through all codes
- bool first(true);
- for (auto &code : m_keycode_map)
+ // loop through all devices
+ bool firstdev(true);
+ for (kbd_dev_info const &devinfo : m_keyboards)
{
- // describe the character code
- std::string const description(string_format("%08X (%s) ", code.first, unicode_to_string(code.first)));
+ if (!firstdev)
+ str << '\n';
+ util::stream_format(
+ str,
+ "%s(%s) - %s%s%s %sabled\n",
+ devinfo.device.get().type().shortname(),
+ devinfo.device.get().tag(),
+ devinfo.keyboard ? "keyboard" : "",
+ (devinfo.keyboard && devinfo.keypad) ? "/" : "",
+ devinfo.keypad ? "keypad" : "",
+ devinfo.enabled ? "en" : "dis");
+ firstdev = false;
+
+ // loop through all codes
+ bool firstkey(true);
+ for (auto &code : devinfo.codemap)
+ {
+ // describe the character code
+ std::string const description(string_format("%08X (%s) ", code.first, unicode_to_string(code.first)));
- // pad with spaces
- util::stream_format(str, "%-*s", left_column_width, description);
+ // pad with spaces
+ util::stream_format(str, "%-*s", left_column_width, description);
- for (auto &entry : code.second)
- {
- // identify the keys used
- for (std::size_t field = 0; (entry.field.size() > field) && entry.field[field]; ++field)
- util::stream_format(str, "%s'%s'", first ? "" : ", ", entry.field[field]->name());
+ for (auto &entry : code.second)
+ {
+ // identify the keys used
+ for (std::size_t field = 0; (entry.field.size() > field) && entry.field[field]; ++field)
+ util::stream_format(str, "%s'%s'", firstkey ? "" : ", ", entry.field[field]->name());
- // carriage return
- str << '\n';
- first = false;
+ // carriage return
+ str << '\n';
+ firstkey = false;
+ }
}
}
}
diff --git a/src/emu/natkeyboard.h b/src/emu/natkeyboard.h
index d411eb74173..c3454ee8dd4 100644
--- a/src/emu/natkeyboard.h
+++ b/src/emu/natkeyboard.h
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles,Vas Crabb
/***************************************************************************
natkeyboard.h
@@ -12,8 +12,12 @@
#pragma once
+#include <array>
+#include <functional>
#include <iosfwd>
+#include <string>
#include <unordered_map>
+#include <vector>
//**************************************************************************
@@ -21,9 +25,9 @@
//**************************************************************************
// keyboard helper function delegates
-typedef delegate<int (const char32_t *, size_t)> ioport_queue_chars_delegate;
-typedef delegate<bool (char32_t)> ioport_accept_char_delegate;
-typedef delegate<bool ()> ioport_charqueue_empty_delegate;
+using ioport_queue_chars_delegate = delegate<int (const char32_t *, size_t)>;
+using ioport_accept_char_delegate = delegate<bool (char32_t)>;
+using ioport_charqueue_empty_delegate = delegate<bool ()>;
// ======================> natural_keyboard
@@ -41,13 +45,19 @@ public:
running_machine &machine() const { return m_machine; }
bool empty() const { return (m_bufbegin == m_bufend); }
bool full() const { return ((m_bufend + 1) % m_buffer.size()) == m_bufbegin; }
- bool can_post() const { return (!m_queue_chars.isnull() || !m_keycode_map.empty()); }
+ bool can_post() const { return m_have_charkeys || !m_queue_chars.isnull(); }
bool is_posting() const { return (!empty() || (!m_charqueue_empty.isnull() && !m_charqueue_empty())); }
bool in_use() const { return m_in_use; }
// configuration
void configure(ioport_queue_chars_delegate queue_chars, ioport_accept_char_delegate accept_char, ioport_charqueue_empty_delegate charqueue_empty);
void set_in_use(bool usage);
+ size_t keyboard_count() const { return m_keyboards.size(); }
+ device_t &keyboard_device(size_t n) const { return m_keyboards[n].device; }
+ bool keyboard_is_keypad(size_t n) const { return !m_keyboards[n].keyboard; }
+ bool keyboard_enabled(size_t n) const { return m_keyboards[n].enabled; }
+ void enable_keyboard(size_t n) { set_keyboard_enabled(n, true); }
+ void disable_keyboard(size_t n) { set_keyboard_enabled(n, false); }
// posting
void post_char(char32_t ch, bool normalize_crlf = false);
@@ -74,13 +84,27 @@ private:
{
std::array<ioport_field *, SHIFT_COUNT + 1> field;
unsigned shift;
- ioport_condition condition;
+ ioport_condition condition;
};
typedef std::vector<keycode_map_entry> keycode_map_entries;
typedef std::unordered_map<char32_t, keycode_map_entries> keycode_map;
+ // per-device character-to-key mapping
+ struct kbd_dev_info
+ {
+ kbd_dev_info(device_t &dev) : device(dev) { }
+
+ std::reference_wrapper<device_t> device;
+ std::vector<std::reference_wrapper<ioport_field> > keyfields;
+ keycode_map codemap;
+ bool keyboard = false;
+ bool keypad = false;
+ bool enabled = false;
+ };
+
// internal helpers
- void build_codes(ioport_manager &manager);
+ void build_codes();
+ void set_keyboard_enabled(size_t n, bool enable);
bool can_post_directly(char32_t ch);
bool can_post_alternate(char32_t ch);
attotime choose_delay(char32_t ch);
@@ -90,11 +114,14 @@ private:
const keycode_map_entry *find_code(char32_t ch) const;
// internal state
+ std::vector<kbd_dev_info> m_keyboards; // info on keyboard devices in system
running_machine & m_machine; // reference to our machine
+ bool m_have_charkeys; // are there keys with character?
bool m_in_use; // is natural keyboard in use?
u32 m_bufbegin; // index of starting character
u32 m_bufend; // index of ending character
std::vector<char32_t> m_buffer; // actual buffer
+ keycode_map_entry const * m_current_code; // current code being typed
unsigned m_fieldnum; // current step in multi-key sequence
bool m_status_keydown; // current keydown status
bool m_last_cr; // was the last char a CR?
@@ -103,7 +130,6 @@ private:
ioport_queue_chars_delegate m_queue_chars; // queue characters callback
ioport_accept_char_delegate m_accept_char; // accept character callback
ioport_charqueue_empty_delegate m_charqueue_empty; // character queue empty callback
- keycode_map m_keycode_map; // keycode map
};
diff --git a/src/emu/recording.cpp b/src/emu/recording.cpp
index 2e134f03f4a..dd75c27d62f 100644
--- a/src/emu/recording.cpp
+++ b/src/emu/recording.cpp
@@ -248,7 +248,7 @@ mng_movie_recording::mng_movie_recording(screen_device *screen, std::map<std::st
mng_movie_recording::~mng_movie_recording()
{
if (m_mng_file)
- mng_capture_stop(*m_mng_file);
+ util::mng_capture_stop(*m_mng_file);
}
@@ -264,10 +264,10 @@ bool mng_movie_recording::initialize(std::unique_ptr<emu_file> &&file, bitmap_t
set_frame_period(attotime::from_hz(rate));
m_mng_file = std::move(file);
- png_error pngerr = mng_capture_start(*m_mng_file, snap_bitmap, rate);
- if (pngerr != PNGERR_NONE)
- osd_printf_error("Error capturing MNG, png_error=%d\n", pngerr);
- return pngerr == PNGERR_NONE;
+ util::png_error pngerr = util::mng_capture_start(*m_mng_file, snap_bitmap, rate);
+ if (pngerr != util::png_error::NONE)
+ osd_printf_error("Error capturing MNG, png_error=%d\n", std::underlying_type_t<util::png_error>(pngerr));
+ return pngerr == util::png_error::NONE;
}
@@ -278,15 +278,15 @@ bool mng_movie_recording::initialize(std::unique_ptr<emu_file> &&file, bitmap_t
bool mng_movie_recording::append_single_video_frame(bitmap_rgb32 &bitmap, const rgb_t *palette, int palette_entries)
{
// set up the text fields in the movie info
- png_info pnginfo;
+ util::png_info pnginfo;
if (current_frame() == 0)
{
for (auto &ent : m_info_fields)
pnginfo.add_text(ent.first.c_str(), ent.second.c_str());
}
- png_error error = mng_capture_frame(*m_mng_file, pnginfo, bitmap, palette_entries, palette);
- return error == png_error::PNGERR_NONE;
+ util::png_error error = util::mng_capture_frame(*m_mng_file, pnginfo, bitmap, palette_entries, palette);
+ return error == util::png_error::NONE;
}
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 46123a02b3f..9c7e808bc9f 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -337,11 +337,10 @@ void render_texture::reset(render_manager &manager, texture_scaler_func scaler,
void render_texture::release()
{
// free all scaled versions
- for (auto & elem : m_scaled)
+ for (auto &elem : m_scaled)
{
- m_manager->invalidate_all(elem.bitmap);
- global_free(elem.bitmap);
- elem.bitmap = nullptr;
+ m_manager->invalidate_all(elem.bitmap.get());
+ elem.bitmap.reset();
elem.seqid = 0;
}
@@ -378,12 +377,9 @@ void render_texture::set_bitmap(bitmap_t &bitmap, const rectangle &sbounds, text
// invalidate all scaled versions
for (auto & elem : m_scaled)
{
- if (elem.bitmap != nullptr)
- {
- m_manager->invalidate_all(elem.bitmap);
- global_free(elem.bitmap);
- }
- elem.bitmap = nullptr;
+ if (elem.bitmap)
+ m_manager->invalidate_all(elem.bitmap.get());
+ elem.bitmap.reset();
elem.seqid = 0;
}
}
@@ -460,21 +456,21 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo
// didn't find one -- take the entry with the lowest seqnum
for (scalenum = 0; scalenum < ARRAY_LENGTH(m_scaled); scalenum++)
- if ((lowest == -1 || m_scaled[scalenum].seqid < m_scaled[lowest].seqid) && !primlist.has_reference(m_scaled[scalenum].bitmap))
+ if ((lowest == -1 || m_scaled[scalenum].seqid < m_scaled[lowest].seqid) && !primlist.has_reference(m_scaled[scalenum].bitmap.get()))
lowest = scalenum;
if (-1 == lowest)
throw emu_fatalerror("render_texture::get_scaled: Too many live texture instances!");
// throw out any existing entries
scaled = &m_scaled[lowest];
- if (scaled->bitmap != nullptr)
+ if (scaled->bitmap)
{
- m_manager->invalidate_all(scaled->bitmap);
- global_free(scaled->bitmap);
+ m_manager->invalidate_all(scaled->bitmap.get());
+ scaled->bitmap.reset();
}
// allocate a new bitmap
- scaled->bitmap = global_alloc(bitmap_argb32(dwidth, dheight));
+ scaled->bitmap = std::make_unique<bitmap_argb32>(dwidth, dheight);
scaled->seqid = ++m_curseq;
// let the scaler do the work
@@ -482,8 +478,8 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo
}
// finally fill out the new info
- primlist.add_reference(scaled->bitmap);
- texinfo.base = &scaled->bitmap->pix32(0);
+ primlist.add_reference(scaled->bitmap.get());
+ texinfo.base = &scaled->bitmap->pix(0);
texinfo.rowpixels = scaled->bitmap->rowpixels();
texinfo.width = dwidth;
texinfo.height = dheight;
@@ -718,8 +714,8 @@ void render_container::overlay_scale(bitmap_argb32 &dest, bitmap_argb32 &source,
// simply replicate the source bitmap over the target
for (int y = 0; y < dest.height(); y++)
{
- u32 *src = &source.pix32(y % source.height());
- u32 *dst = &dest.pix32(y);
+ u32 const *const src = &source.pix(y % source.height());
+ u32 *dst = &dest.pix(y);
int sx = 0;
// loop over columns
@@ -1022,6 +1018,7 @@ void render_target::set_view(unsigned viewindex)
{
m_curview = viewindex;
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ current_view().preload();
}
}
@@ -1051,6 +1048,7 @@ void render_target::set_visibility_toggle(unsigned index, bool enable)
else
m_views[m_curview].second &= ~(u32(1) << index);
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ current_view().preload();
}
@@ -1086,13 +1084,14 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i
screen_device const &screen = screens[index() % screens.size()];
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
{
- for (screen_device const &viewscreen : m_views[i].first.get().screens())
+ for (layout_view::item &viewitem : m_views[i].first.get().items())
{
- if (&viewscreen == &screen)
+ screen_device const *const viewscreen(viewitem.screen());
+ if (viewscreen == &screen)
{
view = &m_views[i].first.get();
}
- else
+ else if (viewscreen)
{
view = nullptr;
break;
@@ -1107,9 +1106,8 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
{
layout_view &curview = m_views[i].first;
- if (curview.screen_count() >= screens.size())
- if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end())
- view = &curview;
+ if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end())
+ view = &curview;
}
}
}
@@ -1345,43 +1343,37 @@ render_primitive_list &render_target::get_primitives()
if (m_manager.machine().phase() >= machine_phase::RESET)
{
// we're running - iterate over items in the view
- for (layout_view::item &curitem : current_view().items())
+ for (layout_view::item &curitem : current_view().visible_items())
{
- if ((visibility_mask() & curitem.visibility_mask()) == curitem.visibility_mask())
- {
- // first apply orientation to the bounds
- render_bounds bounds = curitem.bounds();
- apply_orientation(bounds, root_xform.orientation);
- normalize_bounds(bounds);
-
- // apply the transform to the item
- object_transform item_xform;
- item_xform.xoffs = root_xform.xoffs + bounds.x0 * root_xform.xscale;
- item_xform.yoffs = root_xform.yoffs + bounds.y0 * root_xform.yscale;
- item_xform.xscale = (bounds.x1 - bounds.x0) * root_xform.xscale;
- item_xform.yscale = (bounds.y1 - bounds.y0) * root_xform.yscale;
- item_xform.color.r = curitem.color().r * root_xform.color.r;
- item_xform.color.g = curitem.color().g * root_xform.color.g;
- item_xform.color.b = curitem.color().b * root_xform.color.b;
- item_xform.color.a = curitem.color().a * root_xform.color.a;
- item_xform.orientation = orientation_add(curitem.orientation(), root_xform.orientation);
- item_xform.no_center = false;
-
- // if there is no associated element, it must be a screen element
- if (curitem.screen())
- add_container_primitives(list, root_xform, item_xform, curitem.screen()->container(), curitem.blend_mode());
- else
- add_element_primitives(list, item_xform, *curitem.element(), curitem.state(), curitem.blend_mode());
- }
+ // first apply orientation to the bounds
+ render_bounds bounds = curitem.bounds();
+ apply_orientation(bounds, root_xform.orientation);
+ normalize_bounds(bounds);
+
+ // apply the transform to the item
+ object_transform item_xform;
+ item_xform.xoffs = root_xform.xoffs + bounds.x0 * root_xform.xscale;
+ item_xform.yoffs = root_xform.yoffs + bounds.y0 * root_xform.yscale;
+ item_xform.xscale = (bounds.x1 - bounds.x0) * root_xform.xscale;
+ item_xform.yscale = (bounds.y1 - bounds.y0) * root_xform.yscale;
+ item_xform.color = curitem.color() * root_xform.color;
+ item_xform.orientation = orientation_add(curitem.orientation(), root_xform.orientation);
+ item_xform.no_center = false;
+
+ // if there is no associated element, it must be a screen element
+ if (curitem.screen())
+ add_container_primitives(list, root_xform, item_xform, curitem.screen()->container(), curitem.blend_mode());
+ else
+ add_element_primitives(list, item_xform, *curitem.element(), curitem.state(), curitem.blend_mode());
}
}
else
{
// if we are not in the running stage, draw an outer box
render_primitive *prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_xy(prim->bounds, 0.0f, 0.0f, (float)m_width, (float)m_height);
+ prim->bounds.set_xy(0.0f, 0.0f, (float)m_width, (float)m_height);
prim->full_bounds = prim->bounds;
- set_render_color(&prim->color, 1.0f, 0.1f, 0.1f, 0.1f);
+ prim->color.set(1.0f, 0.1f, 0.1f, 0.1f);
prim->texture.base = nullptr;
prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
list.append(*prim);
@@ -1389,9 +1381,9 @@ render_primitive_list &render_target::get_primitives()
if (m_width > 1 && m_height > 1)
{
prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_xy(prim->bounds, 1.0f, 1.0f, (float)(m_width - 1), (float)(m_height - 1));
+ prim->bounds.set_xy(1.0f, 1.0f, float(m_width - 1), float(m_height - 1));
prim->full_bounds = prim->bounds;
- set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->color.set(1.0f, 0.0f, 0.0f, 0.0f);
prim->texture.base = nullptr;
prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
list.append(*prim);
@@ -1471,7 +1463,7 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
std::swap(target_f.first, target_f.second);
// try to find the right container
- auto const &items(current_view().screen_items());
+ auto const &items(current_view().visible_screen_items());
auto const found(std::find_if(
items.begin(),
items.end(),
@@ -1479,11 +1471,12 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
if (items.end() != found)
{
layout_view::item &item(*found);
- if (item.bounds().includes(target_f.first, target_f.second))
+ render_bounds const bounds(item.bounds());
+ if (bounds.includes(target_f.first, target_f.second))
{
// point successfully mapped
- container_x = (target_f.first - item.bounds().x0) / item.bounds().width();
- container_y = (target_f.second - item.bounds().y0) / item.bounds().height();
+ container_x = (target_f.first - bounds.x0) / bounds.width();
+ container_y = (target_f.second - bounds.y0) / bounds.height();
return true;
}
}
@@ -1536,17 +1529,21 @@ bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&in
if (m_hit_test[i] && m_hit_test[items.size() + i])
{
layout_view::item &item(items[i]);
- if (item.has_input())
- {
- // point successfully mapped
- input_port = item.input_tag_and_mask(input_mask);
- input_x = (target_f.first - item.bounds().x0) / item.bounds().width();
- input_y = (target_f.second - item.bounds().y0) / item.bounds().height();
- return true;
- }
- else
+ render_bounds const bounds(item.bounds());
+ if (bounds.includes(target_f.first, target_f.second))
{
- break;
+ if (item.has_input())
+ {
+ // point successfully mapped
+ std::tie(input_port, input_mask) = item.input_tag_and_mask();
+ input_x = (target_f.first - bounds.x0) / bounds.width();
+ input_y = (target_f.second - bounds.y0) / bounds.height();
+ return true;
+ }
+ else
+ {
+ break;
+ }
}
}
}
@@ -1623,7 +1620,10 @@ void render_target::resolve_tags()
{
view.resolve_tags();
if (&current_view() == &view)
+ {
view.recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ view.preload();
+ }
}
}
}
@@ -1665,7 +1665,7 @@ void render_target::load_layout_files(util::xml::data_node const &rootnode, bool
// if there's an explicit file, load that first
const std::string &basename = m_manager.machine().basename();
- have_artwork |= load_layout_file(m_manager.machine().root_device(), basename.c_str(), rootnode);
+ have_artwork |= load_layout_file(m_manager.machine().root_device(), rootnode, m_manager.machine().options().art_path(), basename.c_str());
// if we're only loading this file, we know our final result
if (!singlefile)
@@ -1909,20 +1909,17 @@ void render_target::load_additional_layout_files(const char *basename, bool have
int viewindex(0);
for (layout_view *view = nth_view(viewindex); need_tiles && view; view = nth_view(++viewindex))
{
- if (view->screen_count() >= screens.size())
+ bool screen_missing(false);
+ for (screen_device &screen : iter)
{
- bool screen_missing(false);
- for (screen_device &screen : iter)
+ if (!view->has_screen(screen))
{
- if (!view->has_screen(screen))
- {
- screen_missing = true;
- break;
- }
+ screen_missing = true;
+ break;
}
- if (!screen_missing)
- need_tiles = false;
}
+ if (!screen_missing)
+ need_tiles = false;
}
}
if (need_tiles)
@@ -2087,7 +2084,7 @@ void render_target::load_additional_layout_files(const char *basename, bool have
}
// try to parse it
- if (!load_layout_file(m_manager.machine().root_device(), nullptr, *root))
+ if (!load_layout_file(m_manager.machine().root_device(), *root, m_manager.machine().options().art_path(), nullptr))
throw emu_fatalerror("Couldn't parse generated layout??");
}
}
@@ -2114,7 +2111,7 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
zerr = inflateInit(&stream);
if (zerr != Z_OK)
{
- fatalerror("could not inflateInit");
+ osd_printf_error("render_target::load_layout_file: zlib initialization error\n");
return false;
}
@@ -2130,23 +2127,21 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
}
else if (zerr != Z_OK)
{
- fatalerror("decompression error\n");
+ osd_printf_error("render_target::load_layout_file: zlib decompression error\n");
+ inflateEnd(&stream);
return false;
}
// clean up
zerr = inflateEnd(&stream);
if (zerr != Z_OK)
- {
- fatalerror("inflateEnd error\n");
- return false;
- }
+ osd_printf_error("render_target::load_layout_file: zlib cleanup error\n");
util::xml::file::ptr rootnode(util::xml::file::string_read(reinterpret_cast<char const *>(tempout.get()), nullptr));
tempout.reset();
// if we didn't get a properly-formatted XML file, record a warning and exit
- if (!load_layout_file(device ? *device : m_manager.machine().root_device(), dirname, *rootnode))
+ if (!load_layout_file(device ? *device : m_manager.machine().root_device(), *rootnode, m_manager.machine().options().art_path(), dirname))
{
osd_printf_warning("Improperly formatted XML string, ignoring\n");
return false;
@@ -2160,28 +2155,39 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout
bool render_target::load_layout_file(const char *dirname, const char *filename)
{
// build the path and optionally prepend the directory
- std::string fname = std::string(filename).append(".lay");
+ std::string fname;
if (dirname)
- fname.insert(0, PATH_SEPARATOR).insert(0, dirname);
+ fname.append(dirname).append(PATH_SEPARATOR);
+ fname.append(filename).append(".lay");
- // attempt to open the file; bail if we can't
- emu_file layoutfile(m_manager.machine().options().art_path(), OPEN_FLAG_READ);
- layoutfile.set_restrict_to_mediapath(1);
- osd_file::error const filerr(layoutfile.open(fname));
- if (filerr != osd_file::error::NONE)
- return false;
-
- // read the file
+ // attempt to open matching files
util::xml::parse_options parseopt;
util::xml::parse_error parseerr;
parseopt.error = &parseerr;
- util::xml::file::ptr rootnode(util::xml::file::read(layoutfile, &parseopt));
- if (!rootnode)
+ emu_file layoutfile(m_manager.machine().options().art_path(), OPEN_FLAG_READ);
+ layoutfile.set_restrict_to_mediapath(1);
+ bool result(false);
+ for (osd_file::error filerr = layoutfile.open(fname); osd_file::error::NONE == filerr; filerr = layoutfile.open_next())
{
- if (parseerr.error_message)
+ // read the file and parse as XML
+ util::xml::file::ptr const rootnode(util::xml::file::read(layoutfile, &parseopt));
+ if (rootnode)
+ {
+ // extract directory name from location of layout file
+ std::string artdir(layoutfile.fullpath());
+ auto const dirsep(std::find_if(artdir.rbegin(), artdir.rend(), &util::is_directory_separator));
+ artdir.erase(dirsep.base(), artdir.end());
+
+ // record a warning if we didn't get a properly-formatted XML file
+ if (!load_layout_file(m_manager.machine().root_device(), *rootnode, nullptr, artdir.c_str()))
+ osd_printf_warning("Improperly formatted XML layout file '%s', ignoring\n", filename);
+ else
+ result = true;
+ }
+ else if (parseerr.error_message)
{
osd_printf_warning(
- "Error parsing XML file '%s' at line %d column %d: %s, ignoring\n",
+ "Error parsing XML layout file '%s' at line %d column %d: %s, ignoring\n",
filename,
parseerr.error_line,
parseerr.error_column,
@@ -2189,29 +2195,18 @@ bool render_target::load_layout_file(const char *dirname, const char *filename)
}
else
{
- osd_printf_warning("Error parsing XML file '%s', ignorning\n", filename);
+ osd_printf_warning("Error parsing XML layout file '%s', ignorning\n", filename);
}
- return false;
- }
-
- // if we didn't get a properly-formatted XML file, record a warning and exit
- if (!load_layout_file(m_manager.machine().root_device(), dirname, *rootnode))
- {
- osd_printf_warning("Improperly formatted XML file '%s', ignoring\n", filename);
- return false;
- }
- else
- {
- return true;
}
+ return result;
}
-bool render_target::load_layout_file(device_t &device, const char *dirname, util::xml::data_node const &rootnode)
+bool render_target::load_layout_file(device_t &device, util::xml::data_node const &rootnode, const char *searchpath, const char *dirname)
{
// parse and catch any errors
try
{
- m_filelist.emplace_back(device, rootnode, dirname);
+ m_filelist.emplace_back(device, rootnode, searchpath, dirname);
}
catch (emu_fatalerror &)
{
@@ -2240,7 +2235,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
cliprect.y0 = xform.yoffs;
cliprect.x1 = xform.xoffs + xform.xscale;
cliprect.y1 = xform.yoffs + xform.yscale;
- sect_render_bounds(cliprect, m_bounds);
+ cliprect &= m_bounds;
float root_xoffs = root_xform.xoffs + fabsf(root_xform.xscale - xform.xscale) * 0.5f;
float root_yoffs = root_xform.yoffs + fabsf(root_xform.yscale - xform.yscale) * 0.5f;
@@ -2250,7 +2245,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
root_cliprect.y0 = root_yoffs;
root_cliprect.x1 = root_xoffs + root_xform.xscale;
root_cliprect.y1 = root_yoffs + root_xform.yscale;
- sect_render_bounds(root_cliprect, m_bounds);
+ root_cliprect &= m_bounds;
// compute the container transform
object_transform container_xform;
@@ -2480,7 +2475,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const
// allocate a primitive
render_primitive *prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_wh(prim->bounds, xform.xoffs, xform.yoffs, xform.xscale, xform.yscale);
+ prim->bounds.set_wh(xform.xoffs, xform.yoffs, xform.xscale, xform.yscale);
prim->full_bounds = prim->bounds;
prim->color = container_xform.color;
width = render_round_nearest(prim->bounds.x1) - render_round_nearest(prim->bounds.x0);
@@ -2528,24 +2523,18 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
// compute the bounds
s32 width = render_round_nearest(xform.xscale);
s32 height = render_round_nearest(xform.yscale);
- set_render_bounds_wh(prim->bounds, render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), (float) width, (float) height);
+ prim->bounds.set_wh(render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), float(width), float(height));
prim->full_bounds = prim->bounds;
if (xform.orientation & ORIENTATION_SWAP_XY)
std::swap(width, height);
- width = std::min(width, m_maxtexwidth);
- height = std::min(height, m_maxtexheight);
+ width = (std::min)(width, m_maxtexwidth);
+ height = (std::min)(height, m_maxtexheight);
// get the scaled texture and append it
-
texture->get_scaled(width, height, prim->texture, list, prim->flags);
// compute the clip rect
- render_bounds cliprect;
- cliprect.x0 = render_round_nearest(xform.xoffs);
- cliprect.y0 = render_round_nearest(xform.yoffs);
- cliprect.x1 = render_round_nearest(xform.xoffs + xform.xscale);
- cliprect.y1 = render_round_nearest(xform.yoffs + xform.yscale);
- sect_render_bounds(cliprect, m_bounds);
+ render_bounds cliprect = prim->bounds & m_bounds;
// determine UV coordinates and apply clipping
prim->texcoords = oriented_texcoords[xform.orientation];
@@ -2694,7 +2683,10 @@ void render_target::config_load(util::xml::data_node const &targetnode)
}
if (&current_view() == &view->first.get())
+ {
current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen());
+ current_view().preload();
+ }
}
}
@@ -2956,9 +2948,9 @@ void render_target::add_clear_extents(render_primitive_list &list)
if (x1 - x0 > 0)
{
render_primitive *prim = list.alloc(render_primitive::QUAD);
- set_render_bounds_xy(prim->bounds, (float)x0, (float)y0, (float)x1, (float)y1);
+ prim->bounds.set_xy(float(x0), float(y0), float(x1), float(y1));
prim->full_bounds = prim->bounds;
- set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim->color.set(1.0f, 0.0f, 0.0f, 0.0f);
prim->texture.base = nullptr;
prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA);
clearlist.append(*prim);
@@ -3012,7 +3004,7 @@ void render_target::add_clear_and_optimize_primitive_list(render_primitive_list
if (PRIMFLAG_GET_BLENDMODE(prim.flags) == BLENDMODE_RGB_MULTIPLY)
{
// RGB multiply will multiply against 0, leaving nothing
- set_render_color(&prim.color, 1.0f, 0.0f, 0.0f, 0.0f);
+ prim.color.set(1.0f, 0.0f, 0.0f, 0.0f);
prim.texture.base = nullptr;
prim.flags = (prim.flags & ~PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE);
}
@@ -3051,11 +3043,11 @@ done:
//-------------------------------------------------
render_manager::render_manager(running_machine &machine)
- : m_machine(machine),
- m_ui_target(nullptr),
- m_live_textures(0),
- m_texture_id(0),
- m_ui_container(global_alloc(render_container(*this)))
+ : m_machine(machine)
+ , m_ui_target(nullptr)
+ , m_live_textures(0)
+ , m_texture_id(0)
+ , m_ui_container(new render_container(*this))
{
// register callbacks
machine.configuration().config_register("video", config_load_delegate(&render_manager::config_load, this), config_save_delegate(&render_manager::config_save, this));
@@ -3093,7 +3085,7 @@ bool render_manager::is_live(screen_device &screen) const
if (!target.hidden())
{
layout_view const *view = &target.current_view();
- if (view->has_screen(screen))
+ if (view->has_visible_screen(screen))
return true;
}
}
@@ -3129,12 +3121,12 @@ float render_manager::max_update_rate() const
render_target *render_manager::target_alloc(const internal_layout *layoutfile, u32 flags)
{
- return &m_targetlist.append(*global_alloc(render_target(*this, layoutfile, flags)));
+ return &m_targetlist.append(*new render_target(*this, layoutfile, flags));
}
render_target *render_manager::target_alloc(util::xml::data_node const &layout, u32 flags)
{
- return &m_targetlist.append(*global_alloc(render_target(*this, layout, flags)));
+ return &m_targetlist.append(*new render_target(*this, layout, flags));
}
@@ -3251,19 +3243,9 @@ void render_manager::texture_free(render_texture *texture)
// font_alloc - allocate a new font instance
//-------------------------------------------------
-render_font *render_manager::font_alloc(const char *filename)
-{
- return global_alloc(render_font(*this, filename));
-}
-
-
-//-------------------------------------------------
-// font_free - release a font instance
-//-------------------------------------------------
-
-void render_manager::font_free(render_font *font)
+std::unique_ptr<render_font> render_manager::font_alloc(const char *filename)
{
- global_free(font);
+ return std::unique_ptr<render_font>(new render_font(*this, filename));
}
@@ -3301,7 +3283,7 @@ void render_manager::resolve_tags()
render_container *render_manager::container_alloc(screen_device *screen)
{
- auto container = global_alloc(render_container(*this, screen));
+ auto container = new render_container(*this, screen);
if (screen != nullptr)
m_screen_container_list.append(*container);
return container;
diff --git a/src/emu/render.h b/src/emu/render.h
index 1545a3f041d..41cf1e42e1c 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -46,6 +46,7 @@
#ifndef MAME_EMU_RENDER_H
#define MAME_EMU_RENDER_H
+#include "rendertypes.h"
#include "screen.h"
#include <array>
@@ -61,29 +62,10 @@
#include <vector>
-namespace emu { namespace render { namespace detail {
-
-class layout_environment;
-class view_environment;
-
-} } } // namespace emu::render::detail
-
-
//**************************************************************************
// CONSTANTS
//**************************************************************************
-// blending modes
-enum
-{
- BLENDMODE_NONE = 0, // no blending
- BLENDMODE_ALPHA, // standard alpha blend
- BLENDMODE_RGB_MULTIPLY, // apply source alpha to source pix, then multiply RGB values
- BLENDMODE_ADD, // apply source alpha to source pix, then add to destination
-
- BLENDMODE_COUNT
-};
-
// render creation flags
constexpr u8 RENDER_CREATE_NO_ART = 0x01; // ignore any views that have art in them
@@ -174,48 +156,6 @@ constexpr u32 PRIMFLAG_GET_VECTORBUF(u32 x) { return (x & PRIMFLAG_VECTORBUF_MAS
// texture scaling callback
typedef void (*texture_scaler_func)(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);
-// render_bounds - floating point bounding rectangle
-struct render_bounds
-{
- float x0; // leftmost X coordinate
- float y0; // topmost Y coordinate
- float x1; // rightmost X coordinate
- float y1; // bottommost Y coordinate
-
- constexpr float width() const { return x1 - x0; }
- constexpr float height() const { return y1 - y0; }
- constexpr float aspect() const { return width() / height(); }
- constexpr bool includes(float x, float y) const { return (x >= x0) && (x <= x1) && (y >= y0) && (y <= y1); }
-};
-
-
-// render_color - floating point set of ARGB values
-struct render_color
-{
- float a; // alpha component (0.0 = transparent, 1.0 = opaque)
- float r; // red component (0.0 = none, 1.0 = max)
- float g; // green component (0.0 = none, 1.0 = max)
- float b; // blue component (0.0 = none, 1.0 = max)
-};
-
-
-// render_texuv - floating point set of UV texture coordinates
-struct render_texuv
-{
- float u; // U coordinate (0.0-1.0)
- float v; // V coordinate (0.0-1.0)
-};
-
-
-// render_quad_texuv - floating point set of UV texture coordinates
-struct render_quad_texuv
-{
- render_texuv tl; // top-left UV coordinate
- render_texuv tr; // top-right UV coordinate
- render_texuv bl; // bottom-left UV coordinate
- render_texuv br; // bottom-right UV coordinate
-};
-
// render_texinfo - texture information
struct render_texinfo
@@ -232,6 +172,31 @@ struct render_texinfo
};
+namespace emu { namespace render { namespace detail {
+
+struct bounds_step
+{
+ int state;
+ render_bounds bounds;
+ render_bounds delta;
+};
+using bounds_vector = std::vector<bounds_step>;
+
+struct color_step
+{
+ int state;
+ render_color color;
+ render_color delta;
+};
+using color_vector = std::vector<color_step>;
+
+
+class layout_environment;
+class view_environment;
+
+} } } // namespace emu::render::detail
+
+
// ======================> render_layer_config
// render_layer_config - describes the state of layers
@@ -411,8 +376,8 @@ private:
// a scaled_texture contains a single scaled entry for a texture
struct scaled_texture
{
- bitmap_argb32 * bitmap; // final bitmap
- u32 seqid; // sequence number
+ std::unique_ptr<bitmap_argb32> bitmap; // final bitmap
+ u32 seqid; // sequence number
};
// internal state
@@ -573,7 +538,7 @@ public:
using environment = emu::render::detail::layout_environment;
// construction/destruction
- layout_element(environment &env, util::xml::data_node const &elemnode, const char *dirname);
+ layout_element(environment &env, util::xml::data_node const &elemnode);
virtual ~layout_element();
// getters
@@ -581,6 +546,9 @@ public:
int default_state() const { return m_defstate; }
render_texture *state_texture(int state);
+ // operations
+ void preload();
+
private:
/// \brief An image, rectangle, or disk in an element
///
@@ -595,7 +563,7 @@ private:
typedef std::unique_ptr<component> ptr;
// construction/destruction
- component(environment &env, util::xml::data_node const &compnode, const char *dirname);
+ component(environment &env, util::xml::data_node const &compnode);
virtual ~component() = default;
// setup
@@ -610,11 +578,13 @@ private:
render_color color(int state) const;
// operations
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) = 0;
+ virtual void preload(running_machine &machine);
+ virtual void draw(running_machine &machine, bitmap_argb32 &dest, int state);
protected:
- // helper
- virtual int maxstate() const { return -1; }
+ // helpers
+ virtual int maxstate() const;
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state);
// drawing helpers
void draw_text(render_font &font, bitmap_argb32 &dest, const rectangle &bounds, const char *str, int align, const render_color &color);
@@ -629,21 +599,8 @@ private:
void apply_skew(bitmap_argb32 &dest, int skewwidth);
private:
- struct bounds_step
- {
- int state;
- render_bounds bounds;
- render_bounds delta;
- };
- using bounds_vector = std::vector<bounds_step>;
-
- struct color_step
- {
- int state;
- render_color color;
- render_color delta;
- };
- using color_vector = std::vector<color_step>;
+ using bounds_vector = emu::render::detail::bounds_vector;
+ using color_vector = emu::render::detail::color_vector;
// internal state
int const m_statemask; // bits of state used to control visibility
@@ -685,13 +642,13 @@ private:
int m_state; // associated state number
};
- typedef component::ptr (*make_component_func)(environment &env, util::xml::data_node const &compnode, const char *dirname);
+ typedef component::ptr (*make_component_func)(environment &env, util::xml::data_node const &compnode);
typedef std::map<std::string, make_component_func> make_component_map;
// internal helpers
static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);
- template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode, const char *dirname);
- template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname);
+ template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode);
+ template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode);
static make_component_map const s_make_component; // maps component XML names to creator functions
@@ -787,16 +744,16 @@ public:
// getters
layout_element *element() const { return m_element; }
screen_device *screen() { return m_screen; }
- const render_bounds &bounds() const { return m_bounds; }
- const render_color &color() const { return m_color; }
+ render_bounds bounds() const;
+ render_color color() const;
int blend_mode() const { return m_blend_mode; }
u32 visibility_mask() const { return m_visibility_mask; }
int orientation() const { return m_orientation; }
- render_container *screen_container(running_machine &machine) const;
+ render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }
// interactivity
bool has_input() const { return bool(m_input_port); }
- ioport_port *input_tag_and_mask(ioport_value &mask) const { mask = m_input_mask; return m_input_port; };
+ std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
bool clickthrough() const { return m_clickthrough; }
// fetch state based on configured source
@@ -806,16 +763,30 @@ public:
void resolve_tags();
private:
+ using bounds_vector = emu::render::detail::bounds_vector;
+ using color_vector = emu::render::detail::color_vector;
+
+ int animation_state() const;
+
static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
- static render_bounds make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
+ static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
+ static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);
+ static std::string make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode);
+ static std::string make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode);
+ static ioport_value make_animmask(view_environment &env, util::xml::data_node const &itemnode);
static std::string make_input_tag(view_environment &env, util::xml::data_node const &itemnode);
static int get_blend_mode(view_environment &env, util::xml::data_node const &itemnode);
- static unsigned get_input_shift(ioport_value mask);
+ static unsigned get_state_shift(ioport_value mask);
// internal state
layout_element *const m_element; // pointer to the associated element (non-screens only)
output_finder<> m_output; // associated output
+ output_finder<> m_animoutput; // associated output for animation if different
bool const m_have_output; // whether we actually have an output
+ bool const m_have_animoutput; // whether we actually have an output for animation
+ ioport_port * m_animinput_port; // input port used for animation
+ ioport_value const m_animmask; // mask for animation state
+ u8 const m_animshift; // shift for animation state
ioport_port * m_input_port; // input port of this item
ioport_field const * m_input_field; // input port field of this item
ioport_value const m_input_mask; // input mask of this item
@@ -824,14 +795,15 @@ public:
bool m_clickthrough; // should click pass through to lower elements
screen_device * m_screen; // pointer to screen
int m_orientation; // orientation of this item
- render_bounds m_bounds; // bounds of the item
- render_color m_color; // color of the item
+ bounds_vector m_bounds; // bounds of the item
+ color_vector const m_color; // color of the item
int m_blend_mode; // blending mode to use when drawing
u32 m_visibility_mask; // combined mask of parent visibility groups
// cold items
std::string const m_input_tag; // input tag of this item
- render_bounds const m_rawbounds; // raw (original) bounds of the item
+ std::string const m_animinput_tag; // tag of input port for animation state
+ bounds_vector const m_rawbounds; // raw (original) bounds of the item
bool const m_has_clickthrough; // whether clickthrough was explicitly configured
};
using item_list = std::list<item>;
@@ -901,22 +873,25 @@ public:
// getters
item_list &items() { return m_items; }
+ bool has_screen(screen_device &screen);
const std::string &name() const { return m_name; }
- size_t screen_count() const { return m_screens.size(); }
+ size_t visible_screen_count() const { return m_screens.size(); }
float effective_aspect() const { return m_effaspect; }
const render_bounds &bounds() const { return m_bounds; }
- bool has_screen(screen_device &screen) const;
- const item_ref_vector &screen_items() const { return m_screen_items; }
+ bool has_visible_screen(screen_device &screen) const;
+ const item_ref_vector &visible_items() const { return m_visible_items; }
+ const item_ref_vector &visible_screen_items() const { return m_screen_items; }
const item_ref_vector &interactive_items() const { return m_interactive_items; }
const edge_vector &interactive_edges_x() const { return m_interactive_edges_x; }
const edge_vector &interactive_edges_y() const { return m_interactive_edges_y; }
- const screen_ref_vector &screens() const { return m_screens; }
+ const screen_ref_vector &visible_screens() const { return m_screens; }
const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; }
u32 default_visibility_mask() const { return m_defvismask; }
bool has_art() const { return m_has_art; }
// operations
void recompute(u32 visibility_mask, bool zoom_to_screens);
+ void preload();
// resolve tags, if any
void resolve_tags();
@@ -945,6 +920,7 @@ private:
float m_effaspect; // X/Y of the layout in current configuration
render_bounds m_bounds; // computed bounds of the view in current configuration
item_list m_items; // list of layout items
+ item_ref_vector m_visible_items; // all visible items
item_ref_vector m_screen_items; // visible items that represent screens to draw
item_ref_vector m_interactive_items;// visible items that can accept pointer input
edge_vector m_interactive_edges_x;
@@ -971,7 +947,7 @@ public:
using view_list = std::list<layout_view>;
// construction/destruction
- layout_file(device_t &device, util::xml::data_node const &rootnode, char const *dirname);
+ layout_file(device_t &device, util::xml::data_node const &rootnode, char const *searchpath, char const *dirname);
~layout_file();
// getters
@@ -984,7 +960,6 @@ private:
// add elements and parameters
void add_elements(
- char const *dirname,
environment &env,
util::xml::data_node const &parentnode,
group_map &groupmap,
@@ -1093,7 +1068,7 @@ private:
void load_additional_layout_files(const char *basename, bool have_artwork);
bool load_layout_file(const char *dirname, const char *filename);
bool load_layout_file(const char *dirname, const internal_layout &layout_data, device_t *device = nullptr);
- bool load_layout_file(device_t &device, const char *dirname, util::xml::data_node const &rootnode);
+ bool load_layout_file(device_t &device, util::xml::data_node const &rootnode, const char *searchpath, const char *dirname);
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode);
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);
@@ -1192,8 +1167,7 @@ public:
void texture_free(render_texture *texture);
// fonts
- render_font *font_alloc(const char *filename = nullptr);
- void font_free(render_font *font);
+ std::unique_ptr<render_font> font_alloc(const char *filename = nullptr);
// reference tracking
void invalidate_all(void *refptr);
diff --git a/src/emu/rendertypes.h b/src/emu/rendertypes.h
new file mode 100644
index 00000000000..0fa698cc931
--- /dev/null
+++ b/src/emu/rendertypes.h
@@ -0,0 +1,153 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Vas Crabb
+/***************************************************************************
+
+ render.h
+
+ Core renderer constants and structures for MAME.
+
+***************************************************************************/
+#ifndef MAME_EMU_RENDERTYPES_H
+#define MAME_EMU_RENDERTYPES_H
+
+#pragma once
+
+#include <algorithm>
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+
+// blending modes
+enum
+{
+ BLENDMODE_NONE = 0, // no blending
+ BLENDMODE_ALPHA, // standard alpha blend
+ BLENDMODE_RGB_MULTIPLY, // apply source alpha to source pix, then multiply RGB values
+ BLENDMODE_ADD, // apply source alpha to source pix, then add to destination
+
+ BLENDMODE_COUNT
+};
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// render_bounds - floating point bounding rectangle
+struct render_bounds
+{
+ float x0; // leftmost X coordinate
+ float y0; // topmost Y coordinate
+ float x1; // rightmost X coordinate
+ float y1; // bottommost Y coordinate
+
+ constexpr float width() const { return x1 - x0; }
+ constexpr float height() const { return y1 - y0; }
+ constexpr float aspect() const { return width() / height(); }
+ constexpr bool includes(float x, float y) const { return (x >= x0) && (x <= x1) && (y >= y0) && (y <= y1); }
+
+ // intersection
+ constexpr render_bounds operator&(render_bounds const &b) const
+ {
+ return render_bounds{ (std::max)(x0, b.x0), (std::max)(y0, b.y0), (std::min)(x1, b.x1), (std::min)(y1, b.y1) };
+ }
+
+ render_bounds &operator&=(render_bounds const &b)
+ {
+ x0 = (std::max)(x0, b.x0);
+ y0 = (std::max)(y0, b.y0);
+ x1 = (std::min)(x1, b.x1);
+ y1 = (std::min)(y1, b.y1);
+ return *this;
+ }
+
+ // union
+ constexpr render_bounds operator|(render_bounds const &b) const
+ {
+ return render_bounds{ (std::min)(x0, b.x0), (std::min)(y0, b.y0), (std::max)(x1, b.x1), (std::max)(y1, b.y1) };
+ }
+
+ render_bounds &operator|=(render_bounds const &b)
+ {
+ x0 = (std::min)(x0, b.x0);
+ y0 = (std::min)(y0, b.y0);
+ x1 = (std::max)(x1, b.x1);
+ y1 = (std::max)(y1, b.y1);
+ return *this;
+ }
+
+ render_bounds &set_xy(float left, float top, float right, float bottom)
+ {
+ x0 = left;
+ y0 = top;
+ x1 = right;
+ y1 = bottom;
+ return *this;
+ }
+
+ render_bounds &set_wh(float left, float top, float width, float height)
+ {
+ x0 = left;
+ y0 = top;
+ x1 = left + width;
+ y1 = top + height;
+ return *this;
+ }
+};
+
+
+// render_color - floating point set of ARGB values
+struct render_color
+{
+ float a; // alpha component (0.0 = transparent, 1.0 = opaque)
+ float r; // red component (0.0 = none, 1.0 = max)
+ float g; // green component (0.0 = none, 1.0 = max)
+ float b; // blue component (0.0 = none, 1.0 = max)
+
+ constexpr render_color operator*(render_color const &c) const
+ {
+ return render_color{ a * c.a, r * c.r, g * c.g, b * c.b };
+ }
+
+ render_color &operator*=(render_color const &c)
+ {
+ a *= c.a;
+ r *= c.r;
+ g *= c.g;
+ b *= c.b;
+ return *this;
+ }
+
+ render_color &set(float alpha, float red, float green, float blue)
+ {
+ a = alpha;
+ r = red;
+ g = green;
+ b = blue;
+ return *this;
+ }
+};
+
+
+// render_texuv - floating point set of UV texture coordinates
+struct render_texuv
+{
+ float u; // U coordinate (0.0-1.0)
+ float v; // V coordinate (0.0-1.0)
+};
+
+
+// render_quad_texuv - floating point set of UV texture coordinates
+struct render_quad_texuv
+{
+ render_texuv tl; // top-left UV coordinate
+ render_texuv tr; // top-right UV coordinate
+ render_texuv bl; // bottom-left UV coordinate
+ render_texuv br; // bottom-right UV coordinate
+};
+
+#endif // MAME_EMU_RENDERTYPES_H
diff --git a/src/emu/rendfont.cpp b/src/emu/rendfont.cpp
index 7b69a6e97e5..13249a083fc 100644
--- a/src/emu/rendfont.cpp
+++ b/src/emu/rendfont.cpp
@@ -664,7 +664,7 @@ void render_font::char_expand(char32_t chnum, glyph &gl)
for (int y = 0; y < gl.bmheight; y++)
{
int desty = y + m_height_cmd + m_yoffs_cmd - gl.yoffs - gl.bmheight;
- u32 *dest = (desty >= 0 && desty < m_height_cmd) ? &gl.bitmap.pix32(desty, 0) : nullptr;
+ u32 *dest = (desty >= 0 && desty < m_height_cmd) ? &gl.bitmap.pix(desty, 0) : nullptr;
{
for (int x = 0; x < gl.bmwidth; x++)
{
@@ -723,7 +723,7 @@ void render_font::char_expand(char32_t chnum, glyph &gl)
for (int y = 0; y < gl.bmheight; ++y)
{
int const desty(y + m_height + m_yoffs - gl.yoffs - gl.bmheight);
- u32 *dest(((0 <= desty) && (m_height > desty)) ? &gl.bitmap.pix32(desty) : nullptr);
+ u32 *dest(((0 <= desty) && (m_height > desty)) ? &gl.bitmap.pix(desty) : nullptr);
if (m_format == format::TEXT)
{
@@ -1531,7 +1531,7 @@ bool render_font::save_cached(const char *filename, u64 length, u32 hash)
for (int y = 0; y < gl.bmheight; y++)
{
int desty = y + m_height + m_yoffs - gl.yoffs - gl.bmheight;
- const u32 *src = (desty >= 0 && desty < m_height) ? &gl.bitmap.pix32(desty) : nullptr;
+ u32 const *const src = (desty >= 0 && desty < m_height) ? &gl.bitmap.pix(desty) : nullptr;
for (int x = 0; x < gl.bmwidth; x++)
{
if (src != nullptr && rgb_t(src[x]).a() != 0)
diff --git a/src/emu/rendfont.h b/src/emu/rendfont.h
index aa04a094d75..fc0c4853733 100644
--- a/src/emu/rendfont.h
+++ b/src/emu/rendfont.h
@@ -27,9 +27,10 @@ class render_font
// construction/destruction
render_font(render_manager &manager, const char *filename);
- virtual ~render_font();
public:
+ virtual ~render_font();
+
// getters
render_manager &manager() const { return m_manager; }
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index 198fa03998a..1f10941bbab 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -17,6 +17,7 @@
#include "rendutil.h"
#include "video/rgbutil.h"
+#include "nanosvg.h"
#include "vecstream.h"
#include "xmlfile.h"
@@ -27,6 +28,7 @@
#include <cstdio>
#include <cstring>
#include <iomanip>
+#include <limits>
#include <locale>
#include <sstream>
#include <stdexcept>
@@ -36,8 +38,9 @@
#define LOG_GROUP_BOUNDS_RESOLUTION (1U << 1)
#define LOG_INTERACTIVE_ITEMS (1U << 2)
+#define LOG_IMAGE_LOAD (1U << 3)
-//#define VERBOSE (LOG_GROUP_BOUNDS_RESOLUTION | LOG_INTERACTIVE_ITEMS)
+//#define VERBOSE (LOG_GROUP_BOUNDS_RESOLUTION | LOG_INTERACTIVE_ITEMS | LOG_IMAGE_LOAD)
#define LOG_OUTPUT_FUNC osd_printf_verbose
#include "logmacro.h"
@@ -77,8 +80,6 @@ enum
LINE_CAP_END = 2
};
-std::locale const f_portable_locale("C");
-
constexpr layout_group::transform identity_transform{{ {{ 1.0F, 0.0F, 0.0F }}, {{ 0.0F, 1.0F, 0.0F }}, {{ 0.0F, 0.0F, 1.0F }} }};
@@ -96,9 +97,27 @@ inline void render_bounds_transform(render_bounds &bounds, layout_group::transfo
(bounds.x1 * trans[1][0]) + (bounds.y1 * trans[1][1]) + trans[1][2] };
}
-constexpr render_color render_color_multiply(render_color const &x, render_color const &y)
+inline void alpha_blend(u32 &dest, u32 a, u32 r, u32 g, u32 b, u32 inva)
{
- return render_color{ x.a * y.a, x.r * y.r, x.g * y.g, x.b * y.b };
+ rgb_t const dpix(dest);
+ u32 const da(dpix.a());
+ u32 const finala((a * 255) + (da * inva));
+ u32 const finalr(r + (u32(dpix.r()) * da * inva));
+ u32 const finalg(g + (u32(dpix.g()) * da * inva));
+ u32 const finalb(b + (u32(dpix.b()) * da * inva));
+ dest = rgb_t(finala / 255, finalr / finala, finalg / finala, finalb / finala);
+}
+
+inline void alpha_blend(u32 &dest, render_color const &c, float fill)
+{
+ u32 const a(c.a * fill * 255.0F);
+ if (a)
+ {
+ u32 const r(u32(c.r * (255.0F * 255.0F)) * a);
+ u32 const g(u32(c.g * (255.0F * 255.0F)) * a);
+ u32 const b(u32(c.b * (255.0F * 255.0F)) * a);
+ alpha_blend(dest, a, r, g, b, 255 - a);
+ }
}
@@ -213,7 +232,7 @@ private:
if (m_text_valid && !m_float_valid)
{
std::istringstream stream(m_text);
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
if (m_text[0] == '$')
{
stream.get();
@@ -249,7 +268,7 @@ private:
if (m_text_valid && !m_int_valid && !m_float_valid)
{
std::istringstream stream(m_text);
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
if (m_text[0] == '$')
{
stream.get();
@@ -308,7 +327,7 @@ private:
if (m_text_valid && !m_int_valid)
{
std::istringstream stream(m_text);
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
if (m_text[0] == '$')
{
stream.get();
@@ -530,7 +549,7 @@ private:
int parse_int(char const *begin, char const *end, int defvalue)
{
std::istringstream stream;
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
int result;
if (begin[0] == '$')
{
@@ -584,25 +603,37 @@ private:
entry_vector m_entries;
util::ovectorstream m_buffer;
+ std::shared_ptr<NSVGrasterizer> const m_svg_rasterizer;
device_t &m_device;
+ char const *const m_search_path;
+ char const *const m_directory_name;
layout_environment *const m_next = nullptr;
bool m_cached = false;
public:
- explicit layout_environment(device_t &device)
- : m_device(device)
+ layout_environment(device_t &device, char const *searchpath, char const *dirname)
+ : m_svg_rasterizer(nsvgCreateRasterizer(), util::nsvg_deleter())
+ , m_device(device)
+ , m_search_path(searchpath)
+ , m_directory_name(dirname)
{
}
explicit layout_environment(layout_environment &next)
- : m_device(next.m_device)
+ : m_svg_rasterizer(next.m_svg_rasterizer)
+ , m_device(next.m_device)
+ , m_search_path(next.m_search_path)
+ , m_directory_name(next.m_directory_name)
, m_next(&next)
{
}
layout_environment(layout_environment const &) = delete;
- device_t &device() { return m_device; }
- running_machine &machine() { return device().machine(); }
- bool is_root_device() { return &device() == &machine().root_device(); }
+ device_t &device() const { return m_device; }
+ running_machine &machine() const { return device().machine(); }
+ bool is_root_device() const { return &device() == &machine().root_device(); }
+ char const *search_path() const { return m_search_path; }
+ char const *directory_name() const { return m_directory_name; }
+ std::shared_ptr<NSVGrasterizer> const &svg_rasterizer() const { return m_svg_rasterizer; }
void set_parameter(std::string &&name, std::string &&value)
{
@@ -660,7 +691,7 @@ public:
unsigned const decprefix((expanded.first[0] == '#') ? 1U : 0U);
bool const floatchars(std::find_if(expanded.first, expanded.second, [] (char ch) { return ('.' == ch) || ('e' == ch) || ('E' == ch); }) != expanded.second);
std::istringstream stream(std::string(expanded.first + hexprefix + decprefix, expanded.second));
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
if (!hexprefix && !decprefix && floatchars)
{
stream >> floatincrement;
@@ -767,7 +798,7 @@ public:
// similar to what XML nodes do
std::pair<char const *, char const *> const expanded(expand(attrib));
std::istringstream stream(std::string(expanded.first, expanded.second));
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
float result;
return (stream >> result) ? result : defvalue;
}
@@ -791,34 +822,44 @@ public:
void parse_bounds(util::xml::data_node const *node, render_bounds &result)
{
- // default to unit rectangle
if (!node)
{
+ // default to unit rectangle
result.x0 = result.y0 = 0.0F;
result.x1 = result.y1 = 1.0F;
}
else
{
- // parse attributes
+ // horizontal position/size
if (node->has_attribute("left"))
{
- // left/right/top/bottom format
result.x0 = get_attribute_float(*node, "left", 0.0F);
result.x1 = get_attribute_float(*node, "right", 1.0F);
- result.y0 = get_attribute_float(*node, "top", 0.0F);
- result.y1 = get_attribute_float(*node, "bottom", 1.0F);
}
- else if (node->has_attribute("x"))
+ else
{
- // x/y/width/height format
- result.x0 = get_attribute_float(*node, "x", 0.0F);
- result.x1 = result.x0 + get_attribute_float(*node, "width", 1.0F);
- result.y0 = get_attribute_float(*node, "y", 0.0F);
- result.y1 = result.y0 + get_attribute_float(*node, "height", 1.0F);
+ float const width = get_attribute_float(*node, "width", 1.0F);
+ if (node->has_attribute("xc"))
+ result.x0 = get_attribute_float(*node, "xc", 0.0F) - (width / 2.0F);
+ else
+ result.x0 = get_attribute_float(*node, "x", 0.0F);
+ result.x1 = result.x0 + width;
+ }
+
+ // vertical position/size
+ if (node->has_attribute("top"))
+ {
+ result.y0 = get_attribute_float(*node, "top", 0.0F);
+ result.y1 = get_attribute_float(*node, "bottom", 1.0F);
}
else
{
- throw layout_syntax_error("bounds element requires either left or x attribute");
+ float const height = get_attribute_float(*node, "height", 1.0F);
+ if (node->has_attribute("yc"))
+ result.y0 = get_attribute_float(*node, "yc", 0.0F) - (height / 2.0F);
+ else
+ result.y0 = get_attribute_float(*node, "y", 0.0F);
+ result.y1 = result.y0 + height;
}
// check for errors
@@ -911,6 +952,175 @@ public:
} } } // namespace emu::render::detail
+namespace {
+
+bool add_bounds_step(emu::render::detail::layout_environment &env, emu::render::detail::bounds_vector &steps, util::xml::data_node const &node)
+{
+ int const state(env.get_attribute_int(node, "state", 0));
+ auto const pos(
+ std::lower_bound(
+ steps.begin(),
+ steps.end(),
+ state,
+ [] (emu::render::detail::bounds_step const &lhs, int rhs) { return lhs.state < rhs; }));
+ if ((steps.end() != pos) && (state == pos->state))
+ return false;
+
+ auto &ins(*steps.emplace(pos, emu::render::detail::bounds_step{ state, { 0.0F, 0.0F, 0.0F, 0.0F }, { 0.0F, 0.0F, 0.0F, 0.0F } }));
+ env.parse_bounds(&node, ins.bounds);
+ return true;
+}
+
+void set_bounds_deltas(emu::render::detail::bounds_vector &steps)
+{
+ if (steps.empty())
+ {
+ steps.emplace_back(emu::render::detail::bounds_step{ 0, { 0.0F, 0.0F, 1.0F, 1.0F }, { 0.0F, 0.0F, 0.0F, 0.0F } });
+ }
+ else
+ {
+ auto i(steps.begin());
+ auto j(i);
+ while (steps.end() != ++j)
+ {
+ assert(j->state > i->state);
+
+ i->delta.x0 = (j->bounds.x0 - i->bounds.x0) / (j->state - i->state);
+ i->delta.x1 = (j->bounds.x1 - i->bounds.x1) / (j->state - i->state);
+ i->delta.y0 = (j->bounds.y0 - i->bounds.y0) / (j->state - i->state);
+ i->delta.y1 = (j->bounds.y1 - i->bounds.y1) / (j->state - i->state);
+
+ i = j;
+ }
+ }
+}
+
+void normalize_bounds(emu::render::detail::bounds_vector &steps, float x0, float y0, float xoffs, float yoffs, float xscale, float yscale)
+{
+ auto i(steps.begin());
+ i->bounds.x0 = x0 + (i->bounds.x0 - xoffs) * xscale;
+ i->bounds.x1 = x0 + (i->bounds.x1 - xoffs) * xscale;
+ i->bounds.y0 = y0 + (i->bounds.y0 - yoffs) * yscale;
+ i->bounds.y1 = y0 + (i->bounds.y1 - yoffs) * yscale;
+
+ auto j(i);
+ while (steps.end() != ++j)
+ {
+ j->bounds.x0 = x0 + (j->bounds.x0 - xoffs) * xscale;
+ j->bounds.x1 = x0 + (j->bounds.x1 - xoffs) * xscale;
+ j->bounds.y0 = y0 + (j->bounds.y0 - yoffs) * yscale;
+ j->bounds.y1 = y0 + (j->bounds.y1 - yoffs) * yscale;
+
+ i->delta.x0 = (j->bounds.x0 - i->bounds.x0) / (j->state - i->state);
+ i->delta.x1 = (j->bounds.x1 - i->bounds.x1) / (j->state - i->state);
+ i->delta.y0 = (j->bounds.y0 - i->bounds.y0) / (j->state - i->state);
+ i->delta.y1 = (j->bounds.y1 - i->bounds.y1) / (j->state - i->state);
+
+ i = j;
+ }
+}
+
+render_bounds accumulate_bounds(emu::render::detail::bounds_vector const &steps)
+{
+ auto i(steps.begin());
+ render_bounds result(i->bounds);
+ while (steps.end() != ++i)
+ result |= i->bounds;
+ return result;
+}
+
+inline render_bounds interpolate_bounds(emu::render::detail::bounds_vector const &steps, int state)
+{
+ auto pos(
+ std::lower_bound(
+ steps.begin(),
+ steps.end(),
+ state,
+ [] (emu::render::detail::bounds_step const &lhs, int rhs) { return lhs.state < rhs; }));
+ if (steps.begin() == pos)
+ {
+ return pos->bounds;
+ }
+ else
+ {
+ --pos;
+ render_bounds result(pos->bounds);
+ result.x0 += pos->delta.x0 * (state - pos->state);
+ result.x1 += pos->delta.x1 * (state - pos->state);
+ result.y0 += pos->delta.y0 * (state - pos->state);
+ result.y1 += pos->delta.y1 * (state - pos->state);
+ return result;
+ }
+}
+
+
+bool add_color_step(emu::render::detail::layout_environment &env, emu::render::detail::color_vector &steps, util::xml::data_node const &node)
+{
+ int const state(env.get_attribute_int(node, "state", 0));
+ auto const pos(
+ std::lower_bound(
+ steps.begin(),
+ steps.end(),
+ state,
+ [] (emu::render::detail::color_step const &lhs, int rhs) { return lhs.state < rhs; }));
+ if ((steps.end() != pos) && (state == pos->state))
+ return false;
+
+ steps.emplace(pos, emu::render::detail::color_step{ state, env.parse_color(&node), { 0.0F, 0.0F, 0.0F, 0.0F } });
+ return true;
+}
+
+void set_color_deltas(emu::render::detail::color_vector &steps)
+{
+ if (steps.empty())
+ {
+ steps.emplace_back(emu::render::detail::color_step{ 0, { 1.0F, 1.0F, 1.0F, 1.0F }, { 0.0F, 0.0F, 0.0F, 0.0F } });
+ }
+ else
+ {
+ auto i(steps.begin());
+ auto j(i);
+ while (steps.end() != ++j)
+ {
+ assert(j->state > i->state);
+
+ i->delta.a = (j->color.a - i->color.a) / (j->state - i->state);
+ i->delta.r = (j->color.r - i->color.r) / (j->state - i->state);
+ i->delta.g = (j->color.g - i->color.g) / (j->state - i->state);
+ i->delta.b = (j->color.b - i->color.b) / (j->state - i->state);
+
+ i = j;
+ }
+ }
+}
+
+inline render_color interpolate_color(emu::render::detail::color_vector const &steps, int state)
+{
+ auto pos(
+ std::lower_bound(
+ steps.begin(),
+ steps.end(),
+ state,
+ [] (emu::render::detail::color_step const &lhs, int rhs) { return lhs.state < rhs; }));
+ if (steps.begin() == pos)
+ {
+ return pos->color;
+ }
+ else
+ {
+ --pos;
+ render_color result(pos->color);
+ result.a += pos->delta.a * (state - pos->state);
+ result.r += pos->delta.r * (state - pos->state);
+ result.g += pos->delta.g * (state - pos->state);
+ result.b += pos->delta.b * (state - pos->state);
+ return result;
+ }
+}
+
+} // anonymous namespace
+
+
//**************************************************************************
// LAYOUT ELEMENT
@@ -938,7 +1148,7 @@ layout_element::make_component_map const layout_element::s_make_component{
// layout_element - constructor
//-------------------------------------------------
-layout_element::layout_element(environment &env, util::xml::data_node const &elemnode, const char *dirname)
+layout_element::layout_element(environment &env, util::xml::data_node const &elemnode)
: m_machine(env.machine())
, m_defstate(env.get_attribute_int(elemnode, "defstate", -1))
, m_statemask(0)
@@ -954,13 +1164,13 @@ layout_element::layout_element(environment &env, util::xml::data_node const &ele
throw layout_syntax_error(util::string_format("unknown element component %s", compnode->get_name()));
// insert the new component into the list
- component const &newcomp(**m_complist.emplace(m_complist.end(), make_func->second(env, *compnode, dirname)));
+ component const &newcomp(**m_complist.emplace(m_complist.end(), make_func->second(env, *compnode)));
// accumulate bounds
if (first)
bounds = newcomp.overall_bounds();
else
- union_render_bounds(bounds, newcomp.overall_bounds());
+ bounds |= newcomp.overall_bounds();
first = false;
// determine the maximum state
@@ -1123,7 +1333,7 @@ void layout_group::resolve_bounds(environment &env, group_map &groupmap, std::ve
seen.push_back(this);
if (!m_bounds_resolved)
{
- set_render_bounds_xy(m_bounds, 0.0F, 0.0F, 1.0F, 1.0F);
+ m_bounds.set_xy(0.0F, 0.0F, 1.0F, 1.0F);
environment local(env);
bool empty(true);
resolve_bounds(local, m_groupnode, groupmap, seen, empty, false, false, true);
@@ -1177,11 +1387,22 @@ void layout_group::resolve_bounds(
!strcmp(itemnode->get_name(), "marquee"))
{
render_bounds itembounds;
- env.parse_bounds(itemnode->get_child("bounds"), itembounds);
+ util::xml::data_node const *boundsnode = itemnode->get_child("bounds");
+ env.parse_bounds(boundsnode, itembounds);
+ while (boundsnode)
+ {
+ boundsnode = boundsnode->get_next_sibling("bounds");
+ if (boundsnode)
+ {
+ render_bounds b;
+ env.parse_bounds(boundsnode, b);
+ itembounds |= b;
+ }
+ }
if (empty)
m_bounds = itembounds;
else
- union_render_bounds(m_bounds, itembounds);
+ m_bounds |= itembounds;
empty = false;
LOGMASKED(LOG_GROUP_BOUNDS_RESOLUTION, "Accumulate item bounds (%s %s %s %s) -> (%s %s %s %s)\n",
itembounds.x0, itembounds.y0, itembounds.x1, itembounds.y1,
@@ -1197,7 +1418,7 @@ void layout_group::resolve_bounds(
if (empty)
m_bounds = itembounds;
else
- union_render_bounds(m_bounds, itembounds);
+ m_bounds |= itembounds;
empty = false;
LOGMASKED(LOG_GROUP_BOUNDS_RESOLUTION, "Accumulate group '%s' reference explicit bounds (%s %s %s %s) -> (%s %s %s %s)\n",
itemnode->get_attribute_string("ref", ""),
@@ -1225,7 +1446,7 @@ void layout_group::resolve_bounds(
if (empty)
m_bounds = itembounds;
else
- union_render_bounds(m_bounds, itembounds);
+ m_bounds |= itembounds;
empty = false;
unresolved = false;
LOGMASKED(LOG_GROUP_BOUNDS_RESOLUTION, "Accumulate group '%s' reference computed bounds (%s %s %s %s) -> (%s %s %s %s)\n",
@@ -1302,6 +1523,18 @@ render_texture *layout_element::state_texture(int state)
//-------------------------------------------------
+// preload - perform expensive loading upfront
+// for all components
+//-------------------------------------------------
+
+void layout_element::preload()
+{
+ for (component::ptr const &curcomp : m_complist)
+ curcomp->preload(machine());
+}
+
+
+//-------------------------------------------------
// element_scale - scale an element by rendering
// all the components at the appropriate
// resolution
@@ -1311,23 +1544,11 @@ void layout_element::element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, c
{
texture const &elemtex(*reinterpret_cast<texture const *>(param));
- // iterate over components that are part of the current state
+ // draw components that are visible in the current state
for (auto const &curcomp : elemtex.m_element->m_complist)
{
if ((elemtex.m_state & curcomp->statemask()) == curcomp->stateval())
- {
- // get the local scaled bounds
- render_bounds const compbounds(curcomp->bounds(elemtex.m_state));
- rectangle bounds(
- render_round_nearest(compbounds.x0 * dest.width()),
- render_round_nearest(compbounds.x1 * dest.width()),
- render_round_nearest(compbounds.y0 * dest.height()),
- render_round_nearest(compbounds.y1 * dest.height()));
- bounds &= dest.cliprect();
-
- // based on the component type, add to the texture
- curcomp->draw(elemtex.m_element->machine(), dest, bounds, elemtex.m_state);
- }
+ curcomp->draw(elemtex.m_element->machine(), dest, elemtex.m_state);
}
}
@@ -1337,54 +1558,46 @@ class layout_element::image_component : public component
{
public:
// construction/destruction
- image_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
- , m_dirname(dirname ? dirname : "")
+ image_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
+ , m_rasterizer(env.svg_rasterizer())
+ , m_searchpath(env.search_path() ? env.search_path() : "")
+ , m_dirname(env.directory_name() ? env.directory_name() : "")
, m_imagefile(env.get_attribute_string(compnode, "file", ""))
, m_alphafile(env.get_attribute_string(compnode, "alphafile", ""))
+ , m_data(get_data(compnode))
{
}
-protected:
// overrides
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void preload(running_machine &machine) override
{
- if (!m_bitmap.valid())
- load_bitmap(machine);
+ if (!m_bitmap.valid() && !m_svg)
+ load_image(machine);
+ }
+protected:
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, rectangle const &bounds, int state) override
+ {
+ if (!m_bitmap.valid() && !m_svg)
+ load_image(machine);
+
+ if (m_bitmap.valid())
+ draw_bitmap(dest, bounds, state);
+ else if (m_svg)
+ draw_svg(dest, bounds, state);
+ }
+
+private:
+ // internal helpers
+ void draw_bitmap(bitmap_argb32 &dest, rectangle const &bounds, int state)
+ {
render_color const c(color(state));
if (m_hasalpha || (1.0F > c.a))
{
bitmap_argb32 tempbitmap(dest.width(), dest.height());
render_resample_argb_bitmap_hq(tempbitmap, m_bitmap, c);
- for (s32 y0 = 0, y1 = bounds.top(); bounds.bottom() >= y1; ++y0, ++y1)
- {
- u32 const *src(&tempbitmap.pix(y0, 0));
- u32 *dst(&dest.pix(y1, bounds.left()));
- for (s32 x1 = bounds.left(); bounds.right() >= x1; ++x1, ++src, ++dst)
- {
- rgb_t const a(*src);
- u32 const aa(a.a());
- if (aa)
- {
- rgb_t const b(*dst);
- u32 const ba(b.a());
- if (ba)
- {
- u32 const ca((aa * 255) + (ba * (255 - aa)));
- *dst = rgb_t(
- u8(ca / 255),
- u8(((a.r() * aa * 255) + (b.r() * ba * (255 - aa))) / ca),
- u8(((a.g() * aa * 255) + (b.g() * ba * (255 - aa))) / ca),
- u8(((a.b() * aa * 255) + (b.b() * ba * (255 - aa))) / ca));
- }
- else
- {
- *dst = *src;
- }
- }
- }
- }
+ alpha_blend(tempbitmap, dest, bounds);
}
else
{
@@ -1393,57 +1606,362 @@ protected:
}
}
-private:
- // internal helpers
- void load_bitmap(running_machine &machine)
+ void draw_svg(bitmap_argb32 &dest, rectangle const &bounds, int state)
{
- emu_file file(machine.options().art_path(), OPEN_FLAG_READ);
+ // rasterise into a temporary bitmap
+ float const xscale(bounds.width() / m_svg->width);
+ float const yscale(bounds.height() / m_svg->height);
+ float const drawscale((std::max)(xscale, yscale));
+ bitmap_argb32 tempbitmap(int(m_svg->width * drawscale), int(m_svg->height * drawscale));
+ nsvgRasterize(
+ m_rasterizer.get(),
+ m_svg.get(),
+ 0, 0, drawscale,
+ reinterpret_cast<unsigned char *>(&tempbitmap.pix(0)),
+ tempbitmap.width(), tempbitmap.height(),
+ tempbitmap.rowbytes());
+
+ // correct colour format and multiply by state colour
+ bool havealpha(false);
+ render_color const c(color(state));
+ for (s32 y = 0; tempbitmap.height() > y; ++y)
+ {
+ u32 *dst(&tempbitmap.pix(y));
+ for (s32 x = 0; tempbitmap.width() > x; ++x, ++dst)
+ {
+ u8 const *const src(reinterpret_cast<u8 const *>(dst));
+ rgb_t const d(
+ u8((float(src[3]) * c.a) + 0.5),
+ u8((float(src[0]) * c.r) + 0.5),
+ u8((float(src[1]) * c.g) + 0.5),
+ u8((float(src[2]) * c.b) + 0.5));
+ *dst = d;
+ havealpha = havealpha || (d.a() < 255U);
+ }
+ }
- ru_imgformat const format = render_detect_image(file, m_dirname.c_str(), m_imagefile.c_str());
- switch (format)
+ // find most efficient way to insert it in the target bitmap
+ if (!havealpha)
{
- case RENDUTIL_IMGFORMAT_ERROR:
- break;
+ if ((tempbitmap.width() == bounds.width()) && (tempbitmap.height() == bounds.height()))
+ {
+ for (s32 y = 0; tempbitmap.height() > y; ++y)
+ std::copy_n(&tempbitmap.pix(y), bounds.width(), &dest.pix(y + bounds.top(), bounds.left()));
+ }
+ else
+ {
+ bitmap_argb32 destsub(dest, bounds);
+ render_resample_argb_bitmap_hq(destsub, tempbitmap, render_color{ 1.0F, 1.0F, 1.0F, 1.0F });
+ }
+ }
+ else if ((tempbitmap.width() == bounds.width()) && (tempbitmap.height() == bounds.height()))
+ {
+ alpha_blend(tempbitmap, dest, bounds);
+ }
+ else
+ {
+ bitmap_argb32 scaled(bounds.width(), bounds.height());
+ render_resample_argb_bitmap_hq(scaled, tempbitmap, render_color{ 1.0F, 1.0F, 1.0F, 1.0F });
+ tempbitmap.reset();
+ alpha_blend(scaled, dest, bounds);
+ }
+ }
- case RENDUTIL_IMGFORMAT_PNG:
- // load the basic bitmap
- m_hasalpha = render_load_png(m_bitmap, file, m_dirname.c_str(), m_imagefile.c_str());
- break;
+ void alpha_blend(bitmap_argb32 const &srcbitmap, bitmap_argb32 &dstbitmap, rectangle const &bounds)
+ {
+ for (s32 y0 = 0, y1 = bounds.top(); bounds.bottom() >= y1; ++y0, ++y1)
+ {
+ u32 const *src(&srcbitmap.pix(y0, 0));
+ u32 *dst(&dstbitmap.pix(y1, bounds.left()));
+ for (s32 x1 = bounds.left(); bounds.right() >= x1; ++x1, ++src, ++dst)
+ {
+ rgb_t const a(*src);
+ u32 const aa(a.a());
+ if (255 == aa)
+ {
+ *dst = *src;
+ }
+ else if (aa)
+ {
+ rgb_t const b(*dst);
+ u32 const ba(b.a());
+ if (ba)
+ {
+ u32 const ca((aa * 255) + (ba * (255 - aa)));
+ *dst = rgb_t(
+ u8(ca / 255),
+ u8(((a.r() * aa * 255) + (b.r() * ba * (255 - aa))) / ca),
+ u8(((a.g() * aa * 255) + (b.g() * ba * (255 - aa))) / ca),
+ u8(((a.b() * aa * 255) + (b.b() * ba * (255 - aa))) / ca));
+ }
+ else
+ {
+ *dst = *src;
+ }
+ }
+ }
+ }
+ }
- default:
- // try JPG
- render_load_jpeg(m_bitmap, file, m_dirname.c_str(), m_imagefile.c_str());
- break;
+ void load_image(running_machine &machine)
+ {
+ // if we have a filename, go with that
+ emu_file file(m_searchpath.empty() ? m_dirname : m_searchpath, OPEN_FLAG_READ);
+ if (!m_imagefile.empty())
+ {
+ std::string filename;
+ if (!m_searchpath.empty())
+ filename = m_dirname;
+ if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
+ filename.append(PATH_SEPARATOR);
+ filename.append(m_imagefile);
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load image file '%s'\n", filename);
+ osd_file::error const imgerr = file.open(filename);
+ if (osd_file::error::NONE == imgerr)
+ {
+ if (!load_bitmap(file))
+ {
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component will attempt to parse file as SVG\n");
+ load_svg(file);
+ }
+ file.close();
+ }
+ else
+ {
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open image file '%s'\n", filename);
+ }
+ }
+ else if (!m_data.empty())
+ {
+ load_image_data();
}
// load the alpha bitmap if specified
- if (m_bitmap.valid() && !m_alphafile.empty())
- render_load_png(m_bitmap, file, m_dirname.c_str(), m_alphafile.c_str(), true);
+ if (!m_alphafile.empty())
+ {
+ if (m_bitmap.valid())
+ {
+ std::string filename;
+ if (!m_searchpath.empty())
+ filename = m_dirname;
+ if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
+ filename.append(PATH_SEPARATOR);
+ filename.append(m_alphafile);
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component attempt to load alpha channel from file '%s'\n", filename);
+ osd_file::error const alferr = file.open(filename);
+ if (osd_file::error::NONE == alferr)
+ {
+ // TODO: no way to detect corner case where we had alpha from the image but the alpha PNG makes it entirely opaque
+ if (render_load_png(m_bitmap, file, true))
+ m_hasalpha = true;
+ file.close();
+ }
+ else
+ {
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component unable to open alpha channel file '%s'\n", filename);
+ }
+ }
+ else if (m_svg)
+ {
+ osd_printf_warning("Component alpha channel file '%s' ignored for SVG image '%s'\n", m_alphafile, m_imagefile);
+ }
+ }
- // if we can't load the bitmap, allocate a dummy one and report an error
- if (!m_bitmap.valid())
+ // if we can't load an image, allocate a dummy one and report an error
+ if (!m_bitmap.valid() && !m_svg)
{
// draw some stripes in the bitmap
m_bitmap.allocate(100, 100);
m_bitmap.fill(0);
for (int step = 0; step < 100; step += 25)
for (int line = 0; line < 100; line++)
- m_bitmap.pix32((step + line) % 100, line % 100) = rgb_t(0xff,0xff,0xff,0xff);
+ m_bitmap.pix((step + line) % 100, line % 100) = rgb_t(0xff,0xff,0xff,0xff);
// log an error
if (m_alphafile.empty())
- osd_printf_warning("Unable to load component bitmap '%s'\n", m_imagefile);
+ osd_printf_warning("Unable to load component image '%s'\n", m_imagefile);
else
- osd_printf_warning("Unable to load component bitmap '%s'/'%s'\n", m_imagefile, m_alphafile);
+ osd_printf_warning("Unable to load component image '%s'/'%s'\n", m_imagefile, m_alphafile);
}
+
+ // clear out this stuff in case it's large
+ if (!m_svg)
+ m_rasterizer.reset();
+ m_searchpath.clear();
+ m_dirname.clear();
+ m_imagefile.clear();
+ m_alphafile.clear();
+ m_data.clear();
+ }
+
+ void load_image_data()
+ {
+ // in-place Base64 decode
+ static constexpr char base64chars[] =
+ "\t\n\v\f\r +/0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+ static constexpr char base64tail[] =
+ "\t\n\v\f\r =";
+ std::string::size_type const tail(m_data.find_first_not_of(base64chars));
+ std::string::size_type const end(m_data.find_first_not_of(base64tail, tail));
+ if (std::string::npos == end)
+ {
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component decoding Base64 image data\n");
+ char *dst(&m_data[0]);
+ unsigned trailing(0U);
+ for (std::string::size_type i = 0U; (m_data.size() > i) && ('=' != m_data[i]); ++i)
+ {
+ u8 sym;
+ if (('A' <= m_data[i]) && ('Z' >= m_data[i]))
+ sym = m_data[i] - 'A';
+ else if (('a' <= m_data[i]) && ('z' >= m_data[i]))
+ sym = m_data[i] - 'a' + 26;
+ else if (('0' <= m_data[i]) && ('9' >= m_data[i]))
+ sym = m_data[i] - '0' + 52;
+ else if ('+' == m_data[i])
+ sym = 62;
+ else if ('/' == m_data[i])
+ sym = 63;
+ else
+ continue;
+ if (trailing)
+ *dst |= (sym << 2) >> trailing;
+ else
+ *dst = sym << 2;
+ if (trailing >= 2U)
+ ++dst;
+ trailing = (trailing + 6U) & 7U;
+ if (trailing)
+ *dst = sym << (8U - trailing);
+ }
+ m_data.resize(dst - &m_data[0]);
+ }
+
+ // make a file wrapper for the data and see if it looks like a bitmap
+ util::core_file::ptr file;
+ osd_file::error const filerr(util::core_file::open_ram(m_data.c_str(), m_data.size(), OPEN_FLAG_READ, file));
+ bool const bitmapdata((osd_file::error::NONE == filerr) && file && load_bitmap(*file));
+ file.reset();
+
+ // if it didn't look like a bitmap, see if it looks like it might be XML and hence SVG
+ if (!bitmapdata)
+ {
+ bool const utf16be((0xfe == u8(m_data[0])) && (0xff == u8(m_data[1])));
+ bool const utf16le((0xff == u8(m_data[0])) && (0xfe == u8(m_data[1])));
+ bool const utf8((0xef == u8(m_data[0])) && (0xbb == u8(m_data[1])) && (0xbf == u8(m_data[2])));
+ std::string::size_type const found(m_data.find_first_not_of("\t\n\v\f\r "));
+ bool const xmltag((std::string::npos != found) && ('<' == m_data[found]));
+ if (utf16be || utf16le || utf8 || xmltag)
+ {
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component will attempt to parse data as SVG\n");
+ parse_svg(&m_data[0]);
+ }
+ }
+ }
+
+ bool load_bitmap(util::core_file &file)
+ {
+ ru_imgformat const format = render_detect_image(file);
+ switch (format)
+ {
+ case RENDUTIL_IMGFORMAT_ERROR:
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component error detecting image file format\n");
+ return false;
+
+ case RENDUTIL_IMGFORMAT_PNG:
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component detected PNG file format\n");
+ m_hasalpha = render_load_png(m_bitmap, file);
+ return true;
+
+ case RENDUTIL_IMGFORMAT_JPEG:
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component detected JPEG file format\n");
+ render_load_jpeg(m_bitmap, file);
+ return true;
+
+ case RENDUTIL_IMGFORMAT_MSDIB:
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component detected Microsoft DIB file format\n");
+ render_load_msdib(m_bitmap, file);
+ return true;
+
+ default:
+ LOGMASKED(LOG_IMAGE_LOAD, "Image component failed to detect bitmap file format\n");
+ return false;
+ }
+ }
+
+ void load_svg(util::core_file &file)
+ {
+ u64 len(file.size());
+ if ((std::numeric_limits<size_t>::max() - 1) < len)
+ {
+ osd_printf_warning("Component image '%s' is too large to read into memory\n", m_imagefile);
+ return;
+ }
+ std::unique_ptr<char []> svgbuf(new (std::nothrow) char [size_t(len) + 1]);
+ if (!svgbuf)
+ {
+ osd_printf_warning("Error allocating memory to read component image '%s'\n", m_imagefile);
+ return;
+ }
+ svgbuf[len] = '\0';
+ for (char *ptr = svgbuf.get(); len; )
+ {
+ u32 const block(u32(std::min<u64>(std::numeric_limits<u32>::max(), len)));
+ u32 const read(file.read(ptr, block));
+ if (!read)
+ {
+ osd_printf_warning("Error reading component image '%s'\n", m_imagefile);
+ return;
+ }
+ ptr += read;
+ len -= read;
+ }
+ parse_svg(svgbuf.get());
+ }
+
+ void parse_svg(char *svgdata)
+ {
+ if (!m_rasterizer)
+ {
+ osd_printf_warning("No SVG rasteriser available, won't attempt to parse component image '%s' as SVG\n", m_imagefile);
+ return;
+ }
+ m_svg.reset(nsvgParse(svgdata, "px", 72));
+ if (!m_svg)
+ {
+ osd_printf_warning("Failed to parse component image '%s' as SVG\n", m_imagefile);
+ return;
+ }
+ if ((0.0F >= m_svg->width) || (0.0F >= m_svg->height))
+ {
+ osd_printf_warning("Parsing component image '%s' as SVG produced empty image\n", m_imagefile);
+ m_svg.reset();
+ return;
+ }
+ }
+
+ static std::string get_data(util::xml::data_node const &compnode)
+ {
+ util::xml::data_node const *datanode(compnode.get_child("data"));
+ if (datanode && datanode->get_value())
+ return datanode->get_value();
+ else
+ return "";
}
// internal state
- bitmap_argb32 m_bitmap; // source bitmap for images
- std::string const m_dirname; // directory name of image file (for lazy loading)
- std::string const m_imagefile; // name of the image file (for lazy loading)
- std::string const m_alphafile; // name of the alpha file (for lazy loading)
- bool m_hasalpha = false; // is there any alpha component present?
+ util::nsvg_image_ptr m_svg; // parsed SVG image
+ std::shared_ptr<NSVGrasterizer> m_rasterizer; // SVG rasteriser
+ bitmap_argb32 m_bitmap; // source bitmap for images
+ bool m_hasalpha = false; // is there any alpha component present?
+
+ // cold state
+ std::string m_searchpath; // asset search path (for lazy loading)
+ std::string m_dirname; // directory name of image file (for lazy loading)
+ std::string m_imagefile; // name of the image file (for lazy loading)
+ std::string m_alphafile; // name of the alpha file (for lazy loading)
+ std::string m_data; // embedded image data
};
@@ -1452,42 +1970,39 @@ class layout_element::rect_component : public component
{
public:
// construction/destruction
- rect_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ rect_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
protected:
// overrides
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
- // compute premultiplied colors
- render_color const c = color(state);
- u32 const r = c.r * c.a * 255.0f;
- u32 const g = c.g * c.a * 255.0f;
- u32 const b = c.b * c.a * 255.0f;
- u32 const inva = (1.0f - c.a) * 255.0f;
-
- // iterate over X and Y
- for (u32 y = bounds.top(); y <= bounds.bottom(); y++)
+ render_color const c(color(state));
+ if (1.0f <= c.a)
{
- for (u32 x = bounds.left(); x <= bounds.right(); x++)
+ // optimise opaque pixels
+ u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255)));
+ s32 const width(bounds.width());
+ for (u32 y = bounds.top(); y <= bounds.bottom(); ++y)
+ std::fill_n(&dest.pix(y, bounds.left()), width, f);
+ }
+ else if (c.a)
+ {
+ // compute premultiplied colors
+ u32 const a(c.a * 255.0F);
+ u32 const r(u32(c.r * (255.0F * 255.0F)) * a);
+ u32 const g(u32(c.g * (255.0F * 255.0F)) * a);
+ u32 const b(u32(c.b * (255.0F * 255.0F)) * a);
+ u32 const inva(255 - a);
+
+ // we're translucent, add in the destination pixel contribution
+ for (u32 y = bounds.top(); y <= bounds.bottom(); ++y)
{
- u32 finalr = r;
- u32 finalg = g;
- u32 finalb = b;
-
- // if we're translucent, add in the destination pixel contribution
- if (inva > 0)
- {
- rgb_t dpix = dest.pix32(y, x);
- finalr += (dpix.r() * inva) >> 8;
- finalg += (dpix.g() * inva) >> 8;
- finalb += (dpix.b() * inva) >> 8;
- }
-
- // store the target pixel, dividing the RGBA values by the overall scale factor
- dest.pix32(y, x) = rgb_t(finalr, finalg, finalb);
+ u32 *dst(&dest.pix(y, bounds.left()));
+ for (u32 x = bounds.left(); x <= bounds.right(); ++x, ++dst)
+ alpha_blend(*dst, a, r, g, b, inva);
}
}
}
@@ -1499,60 +2014,261 @@ class layout_element::disk_component : public component
{
public:
// construction/destruction
- disk_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ disk_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
-protected:
// overrides
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw(running_machine &machine, bitmap_argb32 &dest, int state) override
{
- // compute premultiplied colors
+ // compute premultiplied color
render_color const c(color(state));
- u32 const r = c.r * c.a * 255.0f;
- u32 const g = c.g * c.a * 255.0f;
- u32 const b = c.b * c.a * 255.0f;
- u32 const inva = (1.0f - c.a) * 255.0f;
-
- // find the center
- float const xcenter = float(bounds.xcenter());
- float const ycenter = float(bounds.ycenter());
- float const xradius = float(bounds.width()) * 0.5f;
- float const yradius = float(bounds.height()) * 0.5f;
- float const ooyradius2 = 1.0f / (yradius * yradius);
-
- // iterate over y
- for (u32 y = bounds.top(); y <= bounds.bottom(); y++)
- {
- float ycoord = ycenter - (float(y) + 0.5f);
- float xval = xradius * sqrtf(1.0f - (ycoord * ycoord) * ooyradius2);
+ u32 const f(rgb_t(u8(c.r * 255), u8(c.g * 255), u8(c.b * 255)));
+ u32 const a(c.a * 255.0F);
+ u32 const r(c.r * c.a * (255.0F * 255.0F * 255.0F));
+ u32 const g(c.g * c.a * (255.0F * 255.0F * 255.0F));
+ u32 const b(c.b * c.a * (255.0F * 255.0F * 255.0F));
+ u32 const inva(255 - a);
+ if (!a)
+ return;
- // compute left/right coordinates
- s32 left = s32(xcenter - xval + 0.5f);
- s32 right = s32(xcenter + xval + 0.5f);
+ // calculate the position and size
+ render_bounds const curbounds = bounds(state);
+ float const xcenter = (curbounds.x0 + curbounds.x1) * float(dest.width()) * 0.5F;
+ float const ycenter = (curbounds.y0 + curbounds.y1) * float(dest.height()) * 0.5F;
+ float const xradius = curbounds.width() * float(dest.width()) * 0.5F;
+ float const yradius = curbounds.height() * float(dest.height()) * 0.5F;
+ s32 const miny = s32(curbounds.y0 * float(dest.height()));
+ s32 const maxy = s32(std::ceil(curbounds.y1 * float(dest.height()))) - 1;
- // draw this scanline
- for (u32 x = left; x < right; x++)
+ if (miny == maxy)
+ {
+ // fits in a single row of pixels - integrate entire area of ellipse
+ float const scale = xradius * yradius * 0.5F;
+ s32 const minx = s32(curbounds.x0 * float(dest.width()));
+ s32 const maxx = s32(std::ceil(curbounds.x1 * float(dest.width()))) - 1;
+ float x1 = (float(minx) - xcenter) / xradius;
+ u32 *dst = &dest.pix(miny, minx);
+ for (s32 x = minx; maxx >= x; ++x, ++dst)
{
- u32 finalr = r;
- u32 finalg = g;
- u32 finalb = b;
+ float const x0 = x1;
+ x1 = (float(x + 1) - xcenter) / xradius;
+ float const val = integral((std::max)(x0, -1.0F), (std::min)(x1, 1.0F)) * scale;
+ alpha_blend(*dst, c, val);
+ }
+ }
+ else
+ {
+ float const scale = xradius * yradius * 0.25F;
+ float const ooyradius2 = 1.0F / (yradius * yradius);
+ auto const draw_edge_row =
+ [&dest, &c, &curbounds, xcenter, xradius, scale, ooyradius2] (s32 row, float ycoord, bool cross_axis)
+ {
+ float const xval = xradius * std::sqrt((std::max)(1.0F - (ycoord * ycoord) * ooyradius2, 0.0F));
+ float const l = xcenter - xval;
+ float const r = xcenter + xval;
+ if (!cross_axis)
+ {
+ s32 minx = s32(l);
+ s32 maxx = s32(std::ceil(r)) - 1;
+ float x1 = float(minx) - xcenter;
+ u32 *dst = &dest.pix(row, minx);
+ for (s32 x = minx; maxx >= x; ++x, ++dst)
+ {
+ float const x0 = x1;
+ x1 = float(x + 1) - xcenter;
+ float val = integral((std::max)(x0, -xval) / xradius, (std::min)(x1, xval) / xradius) * scale;
+ val -= ((std::min)(float(x + 1), r) - (std::max)(float(x), l)) * ycoord;
+ alpha_blend(*dst, c, val);
+ }
+ }
+ else
+ {
+ s32 const minx = s32(curbounds.x0 * float(dest.width()));
+ s32 const maxx = s32(std::ceil(curbounds.x1 * float(dest.width()))) - 1;
+ float x1 = (float(minx) - xcenter) / xradius;
+ u32 *dst = &dest.pix(row, minx);
+ for (s32 x = minx; maxx >= x; ++x, ++dst)
+ {
+ float const x0 = x1;
+ x1 = (float(x + 1) - xcenter) / xradius;
+ float val = integral((std::max)(x0, -1.0F), (std::min)(x1, 1.0F));
+ if (float(x + 1) <= l)
+ val += integral((std::max)(x0, -1.0F), x1);
+ else if (float(x) <= l)
+ val += integral((std::max)(x0, -1.0F), -xval / xradius);
+ if (float(x) >= r)
+ val += integral(x0, (std::min)(x1, 1.0F));
+ else if (float(x + 1) >= r)
+ val += integral(xval / xradius, (std::min)(x1, 1.0F));
+ val *= scale;
+ val -= (std::max)(((std::min)(float(x + 1), r) - (std::max)(float(x), l)), 0.0F) * ycoord;
+ alpha_blend(*dst, c, val);
+ }
+ }
+ };
+
+ // draw the top row - in a thin ellipse it may extend below the axis
+ draw_edge_row(miny, ycenter - float(miny + 1), float(miny + 1) > ycenter);
+
+ // draw rows above the axis
+ s32 y = miny + 1;
+ float ycoord1 = ycenter - float(y);
+ float xval1 = xradius * std::sqrt((std::max)(1.0F - (ycoord1 * ycoord1) * ooyradius2, 0.0F));
+ float l1 = xcenter - xval1;
+ float r1 = xcenter + xval1;
+ for ( ; (maxy > y) && (float(y + 1) <= ycenter); ++y)
+ {
+ float const l0 = l1;
+ float const r0 = r1;
+ ycoord1 = ycenter - float(y + 1);
+ xval1 = xradius * std::sqrt((std::max)(1.0F - (ycoord1 * ycoord1) * ooyradius2, 0.0F));
+ l1 = xcenter - xval1;
+ r1 = xcenter + xval1;
+ s32 minx = int(l1);
+ s32 maxx = int(std::ceil(r1)) - 1;
+ u32 *dst = &dest.pix(y, minx);
+ for (s32 x = minx; maxx >= x; ++x, ++dst)
+ {
+ if ((float(x) >= l0) && (float(x + 1) <= r0))
+ {
+ if (255 <= a)
+ *dst = f;
+ else
+ alpha_blend(*dst, a, r, g, b, inva);
+ }
+ else
+ {
+ float val = 0.0F;
+ if (float(x + 1) <= l0)
+ val += integral((xcenter - float(x + 1)) / xradius, (xcenter - (std::max)(float(x), l1)) / xradius);
+ else if (float(x) <= l0)
+ val += integral((xcenter - l0) / xradius, (xcenter - (std::max)(float(x), l1)) / xradius);
+ else if (float(x) >= r0)
+ val += integral((float(x) - xcenter) / xradius, ((std::min)(float(x + 1), r1) - xcenter) / xradius);
+ else if (float(x + 1) >= r0)
+ val += integral((r0 - xcenter) / xradius, ((std::min)(float(x + 1), r1) - xcenter) / xradius);
+ val *= scale;
+ if (float(x) <= l0)
+ val -= ((std::min)(float(x + 1), l0) - (std::max)(float(x), l1)) * ycoord1;
+ else if (float(x + 1) >= r0)
+ val -= ((std::min)(float(x + 1), r1) - (std::max)(float(x), r0)) * ycoord1;
+ val += (std::max)((std::min)(float(x + 1), r0) - (std::max)(float(x), l0), 0.0F);
+ alpha_blend(*dst, c, val);
+ }
+ }
+ }
- // if we're translucent, add in the destination pixel contribution
- if (inva > 0)
+ // row spanning the axis
+ if ((maxy > y) && (float(y) < ycenter))
+ {
+ float const l0 = l1;
+ float const r0 = r1;
+ ycoord1 = float(y + 1) - ycenter;
+ xval1 = xradius * std::sqrt((std::max)(1.0F - (ycoord1 * ycoord1) * ooyradius2, 0.0F));
+ l1 = xcenter - xval1;
+ r1 = xcenter + xval1;
+ s32 const minx = int(curbounds.x0 * float(dest.width()));
+ s32 const maxx = int(std::ceil(curbounds.x1 * float(dest.width()))) - 1;
+ u32 *dst = &dest.pix(y, minx);
+ for (s32 x = minx; maxx >= x; ++x, ++dst)
{
- rgb_t dpix = dest.pix32(y, x);
- finalr += (dpix.r() * inva) >> 8;
- finalg += (dpix.g() * inva) >> 8;
- finalb += (dpix.b() * inva) >> 8;
+ if ((float(x) >= (std::max)(l0, l1)) && (float(x + 1) <= (std::min)(r0, r1)))
+ {
+ if (255 <= a)
+ *dst = f;
+ else
+ alpha_blend(*dst, a, r, g, b, inva);
+ }
+ else
+ {
+ float val = 0.0F;
+ if (float(x + 1) <= l0)
+ val += integral((xcenter - float(x + 1)) / xradius, (std::min)((xcenter - float(x)) / xradius, 1.0F));
+ else if (float(x) <= l0)
+ val += integral((xcenter - l0) / xradius, (std::min)((xcenter - float(x)) / xradius, 1.0F));
+ else if (float(x) >= r0)
+ val += integral((float(x) - xcenter) / xradius, (std::min)((float(x + 1) - xcenter) / xradius, 1.0F));
+ else if (float(x + 1) >= r0)
+ val += integral((r0 - xcenter) / xradius, (std::min)((float(x + 1) - xcenter) / xradius, 1.0F));
+ if (float(x + 1) <= l1)
+ val += integral((xcenter - float(x + 1)) / xradius, (std::min)((xcenter - float(x)) / xradius, 1.0F));
+ else if (float(x) <= l1)
+ val += integral((xcenter - l1) / xradius, (std::min)((xcenter - float(x)) / xradius, 1.0F));
+ else if (float(x) >= r1)
+ val += integral((float(x) - xcenter) / xradius, (std::min)((float(x + 1) - xcenter) / xradius, 1.0F));
+ else if (float(x + 1) >= r1)
+ val += integral((r1 - xcenter) / xradius, (std::min)((float(x + 1) - xcenter) / xradius, 1.0F));
+ val *= scale;
+ val += (std::max)(((std::min)(float(x + 1), r0) - (std::max)(float(x), l0)), 0.0F) * (ycenter - float(y));
+ val += (std::max)(((std::min)(float(x + 1), r1) - (std::max)(float(x), l1)), 0.0F) * (float(y + 1) - ycenter);
+ alpha_blend(*dst, c, val);
+ }
}
+ ++y;
+ }
- // store the target pixel, dividing the RGBA values by the overall scale factor
- dest.pix32(y, x) = rgb_t(finalr, finalg, finalb);
+ // draw rows below the axis
+ for ( ; maxy > y; ++y)
+ {
+ float const ycoord0 = ycoord1;
+ float const l0 = l1;
+ float const r0 = r1;
+ ycoord1 = float(y + 1) - ycenter;
+ xval1 = xradius * std::sqrt((std::max)(1.0F - (ycoord1 * ycoord1) * ooyradius2, 0.0F));
+ l1 = xcenter - xval1;
+ r1 = xcenter + xval1;
+ s32 minx = int(l0);
+ s32 maxx = int(std::ceil(r0)) - 1;
+ u32 *dst = &dest.pix(y, minx);
+ for (s32 x = minx; maxx >= x; ++x, ++dst)
+ {
+ if ((float(x) >= l1) && (float(x + 1) <= r1))
+ {
+ if (255 <= a)
+ *dst = f;
+ else
+ alpha_blend(*dst, a, r, g, b, inva);
+ }
+ else
+ {
+ float val = 0.0F;
+ if (float(x + 1) <= l1)
+ val += integral((xcenter - float(x + 1)) / xradius, (xcenter - (std::max)(float(x), l0)) / xradius);
+ else if (float(x) <= l1)
+ val += integral((xcenter - l1) / xradius, (xcenter - (std::max)(float(x), l0)) / xradius);
+ else if (float(x) >= r1)
+ val += integral((float(x) - xcenter) / xradius, ((std::min)(float(x + 1), r0) - xcenter) / xradius);
+ else if (float(x + 1) >= r1)
+ val += integral((r1 - xcenter) / xradius, ((std::min)(float(x + 1), r0) - xcenter) / xradius);
+ val *= scale;
+ if (float(x) <= l1)
+ val -= ((std::min)(float(x + 1), l1) - (std::max)(float(x), l0)) * ycoord0;
+ else if (float(x + 1) >= r1)
+ val -= ((std::min)(float(x + 1), r0) - (std::max)(float(x), r1)) * ycoord0;
+ val += (std::max)((std::min)(float(x + 1), r1) - (std::max)(float(x), l1), 0.0F);
+ alpha_blend(*dst, c, val);
+ }
+ }
}
+
+ // last row is an inversion of the first
+ draw_edge_row(maxy, float(maxy) - ycenter, float(maxy) < ycenter);
}
}
+
+private:
+ static float integral(float x0, float x1)
+ {
+ return integral(x1) - integral(x0);
+ }
+
+ static float integral(float x)
+ {
+ float const u(2.0F * std::asin(x));
+ return u + std::sin(u);
+ };
};
@@ -1561,8 +2277,8 @@ class layout_element::text_component : public component
{
public:
// construction/destruction
- text_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ text_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
m_string = env.get_attribute_string(compnode, "string", "");
m_textalign = env.get_attribute_int(compnode, "align", 0);
@@ -1570,11 +2286,10 @@ public:
protected:
// overrides
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
- render_font *font = machine.render().font_alloc("default");
+ auto font = machine.render().font_alloc("default");
draw_text(*font, dest, bounds, m_string.c_str(), m_textalign, color(state));
- machine.render().font_free(font);
}
private:
@@ -1589,8 +2304,8 @@ class layout_element::led7seg_component : public component
{
public:
// construction/destruction
- led7seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ led7seg_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
@@ -1598,7 +2313,7 @@ protected:
// overrides
virtual int maxstate() const override { return 255; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
@@ -1651,8 +2366,8 @@ class layout_element::led8seg_gts1_component : public component
{
public:
// construction/destruction
- led8seg_gts1_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ led8seg_gts1_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
@@ -1660,7 +2375,7 @@ protected:
// overrides
virtual int maxstate() const override { return 255; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
@@ -1719,8 +2434,8 @@ class layout_element::led14seg_component : public component
{
public:
// construction/destruction
- led14seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ led14seg_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
@@ -1728,7 +2443,7 @@ protected:
// overrides
virtual int maxstate() const override { return 16383; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
@@ -1831,8 +2546,8 @@ class layout_element::led16seg_component : public component
{
public:
// construction/destruction
- led16seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ led16seg_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
@@ -1840,7 +2555,7 @@ protected:
// overrides
virtual int maxstate() const override { return 65535; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
const rgb_t onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
const rgb_t offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
@@ -1953,8 +2668,8 @@ class layout_element::led14segsc_component : public component
{
public:
// construction/destruction
- led14segsc_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ led14segsc_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
@@ -1962,7 +2677,7 @@ protected:
// overrides
virtual int maxstate() const override { return 65535; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
@@ -2076,8 +2791,8 @@ class layout_element::led16segsc_component : public component
{
public:
// construction/destruction
- led16segsc_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ led16segsc_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
{
}
@@ -2085,7 +2800,7 @@ protected:
// overrides
virtual int maxstate() const override { return 262143; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
rgb_t const onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
rgb_t const offpen = rgb_t(0x20, 0xff, 0xff, 0xff);
@@ -2208,8 +2923,8 @@ class layout_element::dotmatrix_component : public component
{
public:
// construction/destruction
- dotmatrix_component(int dots, environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ dotmatrix_component(int dots, environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
, m_dots(dots)
{
}
@@ -2218,7 +2933,7 @@ protected:
// overrides
virtual int maxstate() const override { return (1 << m_dots) - 1; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
const rgb_t onpen = rgb_t(0xff, 0xff, 0xff, 0xff);
const rgb_t offpen = rgb_t(0xff, 0x20, 0x20, 0x20);
@@ -2249,8 +2964,8 @@ class layout_element::simplecounter_component : public component
{
public:
// construction/destruction
- simplecounter_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ simplecounter_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
, m_digits(env.get_attribute_int(compnode, "digits", 2))
, m_textalign(env.get_attribute_int(compnode, "align", 0))
, m_maxstate(env.get_attribute_int(compnode, "maxstate", 999))
@@ -2261,11 +2976,10 @@ protected:
// overrides
virtual int maxstate() const override { return m_maxstate; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
- render_font *const font = machine.render().font_alloc("default");
+ auto font = machine.render().font_alloc("default");
draw_text(*font, dest, bounds, string_format("%0*d", m_digits, state).c_str(), m_textalign, color(state));
- machine.render().font_free(font);
}
private:
@@ -2283,49 +2997,30 @@ class layout_element::reel_component : public component
public:
// construction/destruction
- reel_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
- : component(env, compnode, dirname)
+ reel_component(environment &env, util::xml::data_node const &compnode)
+ : component(env, compnode)
+ , m_searchpath(env.search_path() ? env.search_path() : "")
+ , m_dirname(env.directory_name() ? env.directory_name() : "")
{
- for (auto & elem : m_hasalpha)
- elem = false;
-
std::string symbollist = env.get_attribute_string(compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15");
// split out position names from string and figure out our number of symbols
- int location;
m_numstops = 0;
- location=symbollist.find(',');
- while (location!=-1)
+ for (std::string::size_type location = symbollist.find(','); std::string::npos != location; location = symbollist.find(','))
{
- m_stopnames[m_numstops] = symbollist;
- m_stopnames[m_numstops] = m_stopnames[m_numstops].substr(0, location);
- symbollist = symbollist.substr(location+1, symbollist.length()-(location-1));
+ m_stopnames[m_numstops] = symbollist.substr(0, location);
+ symbollist.erase(0, location + 1);
m_numstops++;
- location=symbollist.find(',');
}
m_stopnames[m_numstops++] = symbollist;
- // careful, dirname is nullptr if we're coming from internal layout, and our string assignment doesn't like that
- if (dirname != nullptr)
- m_dirname = dirname;
-
- for (int i=0;i<m_numstops;i++)
+ for (int i = 0; i < m_numstops; i++)
{
- location=m_stopnames[i].find(':');
- if (location!=-1)
+ std::string::size_type const location = m_stopnames[i].find(':');
+ if (location != std::string::npos)
{
- m_imagefile[i] = m_stopnames[i];
- m_stopnames[i] = m_stopnames[i].substr(0, location);
- m_imagefile[i] = m_imagefile[i].substr(location+1, m_imagefile[i].length()-(location-1));
-
- //m_alphafile[i] =
- m_file[i] = std::make_unique<emu_file>(env.machine().options().art_path(), OPEN_FLAG_READ);
- }
- else
- {
- //m_imagefile[i] = 0;
- //m_alphafile[i] = 0;
- m_file[i].reset();
+ m_imagefile[i] = m_stopnames[i].substr(location + 1);
+ m_stopnames[i].erase(location);
}
}
@@ -2335,10 +3030,21 @@ public:
m_beltreel = env.get_attribute_int(compnode, "beltreel", 0);
}
-protected:
// overrides
+ virtual void preload(running_machine &machine) override
+ {
+ for (int i = 0; i < m_numstops; i++)
+ {
+ if (!m_imagefile[i].empty() && !m_bitmap[i].valid())
+ load_reel_bitmap(i);
+ }
+
+ }
+
+protected:
virtual int maxstate() const override { return 65535; }
- virtual void draw(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
+
+ virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state) override
{
if (m_beltreel)
{
@@ -2359,16 +3065,12 @@ protected:
u32 const b = c.b * 255.0f;
u32 const a = c.a * 255.0f;
- // get the width of the string
- render_font *font = machine.render().font_alloc("default");
- float aspect = 1.0f;
- s32 width;
-
int curry = 0;
int num_shown = m_numsymbolsvisible;
int ourheight = bounds.height();
+ auto font = machine.render().font_alloc("default");
for (int fruit = 0;fruit<m_numstops;fruit++)
{
int basey;
@@ -2393,47 +3095,31 @@ protected:
// only render the symbol / text if it's actually in view because the code is SLOW
if ((endpos >= bounds.top()) && (basey <= bounds.bottom()))
{
- while (1)
- {
- width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit].c_str());
- if (width < bounds.width())
- break;
- aspect *= 0.9f;
- }
+ if (!m_imagefile[fruit].empty() && !m_bitmap[fruit].valid())
+ load_reel_bitmap(fruit);
- s32 curx;
- curx = bounds.left() + (bounds.width() - width) / 2;
-
- if (m_file[fruit])
- if (!m_bitmap[fruit].valid())
- load_reel_bitmap(fruit);
-
- if (m_file[fruit]) // render gfx
+ if (m_bitmap[fruit].valid()) // render gfx
{
bitmap_argb32 tempbitmap2(dest.width(), ourheight/num_shown);
+ render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
- if (m_bitmap[fruit].valid())
+ for (int y = 0; y < ourheight/num_shown; y++)
{
- render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
+ int effy = basey + y;
- for (int y = 0; y < ourheight/num_shown; y++)
+ if (effy >= bounds.top() && effy <= bounds.bottom())
{
- int effy = basey + y;
-
- if (effy >= bounds.top() && effy <= bounds.bottom())
+ u32 const *const src = &tempbitmap2.pix(y);
+ u32 *const d = &dest.pix(effy);
+ for (int x = 0; x < dest.width(); x++)
{
- u32 *src = &tempbitmap2.pix32(y);
- u32 *d = &dest.pix32(effy);
- for (int x = 0; x < dest.width(); x++)
+ int effx = x;
+ if (effx >= bounds.left() && effx <= bounds.right())
{
- int effx = x;
- if (effx >= bounds.left() && effx <= bounds.right())
+ u32 spix = rgb_t(src[x]).a();
+ if (spix != 0)
{
- u32 spix = rgb_t(src[x]).a();
- if (spix != 0)
- {
- d[effx] = src[x];
- }
+ d[effx] = src[x];
}
}
}
@@ -2450,6 +3136,20 @@ protected:
const char *s = origs;
char32_t schar;
+ // get the width of the string
+ float aspect = 1.0f;
+ s32 width;
+
+ while (1)
+ {
+ width = font->string_width(ourheight / num_shown, aspect, m_stopnames[fruit].c_str());
+ if (width < bounds.width())
+ break;
+ aspect *= 0.9f;
+ }
+
+ s32 curx = bounds.left() + (bounds.width() - width) / 2;
+
// loop over characters
while (*s != 0)
{
@@ -2469,8 +3169,8 @@ protected:
if (effy >= bounds.top() && effy <= bounds.bottom())
{
- u32 *src = &tempbitmap.pix32(y);
- u32 *d = &dest.pix32(effy);
+ u32 const *const src = &tempbitmap.pix(y);
+ u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
int effx = curx + x + chbounds.left();
@@ -2502,7 +3202,6 @@ protected:
}
// free the temporary bitmap and font
- machine.render().font_free(font);
}
private:
@@ -2521,15 +3220,12 @@ private:
u32 const b = c.b * 255.0f;
u32 const a = c.a * 255.0f;
- // get the width of the string
- render_font *font = machine.render().font_alloc("default");
- float aspect = 1.0f;
- s32 width;
int currx = 0;
int num_shown = m_numsymbolsvisible;
int ourwidth = bounds.width();
+ auto font = machine.render().font_alloc("default");
for (int fruit = 0;fruit<m_numstops;fruit++)
{
int basex;
@@ -2553,56 +3249,53 @@ private:
// only render the symbol / text if it's actually in view because the code is SLOW
if ((endpos >= bounds.left()) && (basex <= bounds.right()))
{
- while (1)
- {
- width = font->string_width(dest.height(), aspect, m_stopnames[fruit].c_str());
- if (width < bounds.width())
- break;
- aspect *= 0.9f;
- }
-
- s32 curx;
- curx = bounds.left();
+ if (!m_imagefile[fruit].empty() && !m_bitmap[fruit].valid())
+ load_reel_bitmap(fruit);
- if (m_file[fruit])
- if (!m_bitmap[fruit].valid())
- load_reel_bitmap(fruit);
-
- if (m_file[fruit]) // render gfx
+ if (m_bitmap[fruit].valid()) // render gfx
{
bitmap_argb32 tempbitmap2(ourwidth/num_shown, dest.height());
+ render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
- if (m_bitmap[fruit].valid())
+ for (int y = 0; y < dest.height(); y++)
{
- render_resample_argb_bitmap_hq(tempbitmap2, m_bitmap[fruit], c);
+ int effy = y;
- for (int y = 0; y < dest.height(); y++)
+ if (effy >= bounds.top() && effy <= bounds.bottom())
{
- int effy = y;
-
- if (effy >= bounds.top() && effy <= bounds.bottom())
+ u32 const *const src = &tempbitmap2.pix(y);
+ u32 *const d = &dest.pix(effy);
+ for (int x = 0; x < ourwidth/num_shown; x++)
{
- u32 *src = &tempbitmap2.pix32(y);
- u32 *d = &dest.pix32(effy);
- for (int x = 0; x < ourwidth/num_shown; x++)
+ int effx = basex + x;
+ if (effx >= bounds.left() && effx <= bounds.right())
{
- int effx = basex + x;
- if (effx >= bounds.left() && effx <= bounds.right())
+ u32 spix = rgb_t(src[x]).a();
+ if (spix != 0)
{
- u32 spix = rgb_t(src[x]).a();
- if (spix != 0)
- {
- d[effx] = src[x];
- }
+ d[effx] = src[x];
}
}
}
-
}
+
}
}
else // render text (fallback)
{
+ // get the width of the string
+ float aspect = 1.0f;
+ s32 width;
+ while (1)
+ {
+ width = font->string_width(dest.height(), aspect, m_stopnames[fruit].c_str());
+ if (width < bounds.width())
+ break;
+ aspect *= 0.9f;
+ }
+
+ s32 curx = bounds.left();
+
// allocate a temporary bitmap
bitmap_argb32 tempbitmap(dest.width(), dest.height());
@@ -2630,8 +3323,8 @@ private:
if (effy >= bounds.top() && effy <= bounds.bottom())
{
- u32 *src = &tempbitmap.pix32(y);
- u32 *d = &dest.pix32(effy);
+ u32 const *const src = &tempbitmap.pix(y);
+ u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
int effx = basex + curx + x;
@@ -2663,35 +3356,33 @@ private:
}
// free the temporary bitmap and font
- machine.render().font_free(font);
}
void load_reel_bitmap(int number)
{
- // load the basic bitmap
- assert(m_file != nullptr);
- /*m_hasalpha[number] = */ render_load_png(m_bitmap[number], *m_file[number], m_dirname.c_str(), m_imagefile[number].c_str());
+ emu_file file(m_searchpath.empty() ? m_dirname : m_searchpath, OPEN_FLAG_READ);
+ std::string filename;
+ if (!m_searchpath.empty())
+ filename = m_dirname;
+ if (!filename.empty() && !util::is_directory_separator(filename[filename.size() - 1]))
+ filename.append(PATH_SEPARATOR);
+ filename.append(m_imagefile[number]);
- // load the alpha bitmap if specified
- //if (m_bitmap[number].valid() && m_alphafile[number])
- // render_load_png(m_bitmap[number], *m_file[number], m_dirname, m_alphafile[number], true);
+ // load the basic bitmap
+ if (file.open(filename) == osd_file::error::NONE)
+ render_load_png(m_bitmap[number], file);
// if we can't load the bitmap just use text rendering
if (!m_bitmap[number].valid())
- {
- // fallback to text rendering
- m_file[number].reset();
- }
+ m_imagefile[number].clear();
}
// internal state
bitmap_argb32 m_bitmap[MAX_BITMAPS]; // source bitmap for images
+ std::string m_searchpath; // asset search path (for lazy loading)
std::string m_dirname; // directory name of image file (for lazy loading)
- std::unique_ptr<emu_file> m_file[MAX_BITMAPS]; // file object for reading image/alpha files
std::string m_imagefile[MAX_BITMAPS]; // name of the image file (for lazy loading)
- std::string m_alphafile[MAX_BITMAPS]; // name of the alpha file (for lazy loading)
- bool m_hasalpha[MAX_BITMAPS]; // is there any alpha component present?
// basically made up of multiple text strings / gfx
int m_numstops;
@@ -2708,9 +3399,9 @@ private:
//-------------------------------------------------
template <typename T>
-layout_element::component::ptr layout_element::make_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
+layout_element::component::ptr layout_element::make_component(environment &env, util::xml::data_node const &compnode)
{
- return std::make_unique<T>(env, compnode, dirname);
+ return std::make_unique<T>(env, compnode);
}
@@ -2720,9 +3411,9 @@ layout_element::component::ptr layout_element::make_component(environment &env,
//-------------------------------------------------
template <int D>
-layout_element::component::ptr layout_element::make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname)
+layout_element::component::ptr layout_element::make_dotmatrix_component(environment &env, util::xml::data_node const &compnode)
{
- return std::make_unique<dotmatrix_component>(D, env, compnode, dirname);
+ return std::make_unique<dotmatrix_component>(D, env, compnode);
}
@@ -2783,7 +3474,7 @@ layout_element::texture &layout_element::texture::operator=(texture &&that)
// component - constructor
//-------------------------------------------------
-layout_element::component::component(environment &env, util::xml::data_node const &compnode, const char *dirname)
+layout_element::component::component(environment &env, util::xml::data_node const &compnode)
: m_statemask(env.get_attribute_int(compnode, "statemask", env.get_attribute_string(compnode, "state", "")[0] ? ~0 : 0))
, m_stateval(env.get_attribute_int(compnode, "state", m_statemask) & m_statemask)
{
@@ -2791,84 +3482,37 @@ layout_element::component::component(environment &env, util::xml::data_node cons
{
if (!strcmp(child->get_name(), "bounds"))
{
- int const state(env.get_attribute_int(*child, "state", 0));
- auto const pos(
- std::lower_bound(
- m_bounds.begin(),
- m_bounds.end(),
- state,
- [] (bounds_step const &lhs, int rhs) { return lhs.state < rhs; }));
- if ((m_bounds.end() != pos) && (state == pos->state))
+ if (!add_bounds_step(env, m_bounds, *child))
{
throw layout_syntax_error(
util::string_format(
- "%s component has duplicate bounds for state %d",
- compnode.get_name(),
- state));
+ "%s component has duplicate bounds for state",
+ compnode.get_name()));
}
- bounds_step &ins(*m_bounds.emplace(pos, bounds_step{ state, { 0.0F, 0.0F, 0.0F, 0.0F }, { 0.0F, 0.0F, 0.0F, 0.0F } }));
- env.parse_bounds(child, ins.bounds);
}
else if (!strcmp(child->get_name(), "color"))
{
- int const state(env.get_attribute_int(*child, "state", 0));
- auto const pos(
- std::lower_bound(
- m_color.begin(),
- m_color.end(),
- state,
- [] (color_step const &lhs, int rhs) { return lhs.state < rhs; }));
- if ((m_color.end() != pos) && (state == pos->state))
+ if (!add_color_step(env, m_color, *child))
{
throw layout_syntax_error(
util::string_format(
- "%s component has duplicate color for state %d",
- compnode.get_name(),
- state));
+ "%s component has duplicate color for state",
+ compnode.get_name()));
}
- m_color.emplace(pos, color_step{ state, env.parse_color(child), { 0.0F, 0.0F, 0.0F, 0.0F } });
}
}
- if (m_bounds.empty())
- {
- m_bounds.emplace_back(bounds_step{ 0, { 0.0F, 0.0F, 1.0F, 1.0F }, { 0.0F, 0.0F, 0.0F, 0.0F } });
- }
- else
- {
- auto i(m_bounds.begin());
- auto j(i);
- while (m_bounds.end() != ++j)
- {
- assert(j->state > i->state);
-
- i->delta.x0 = (j->bounds.x0 - i->bounds.x0) / (j->state - i->state);
- i->delta.x1 = (j->bounds.x1 - i->bounds.x1) / (j->state - i->state);
- i->delta.y0 = (j->bounds.y0 - i->bounds.y0) / (j->state - i->state);
- i->delta.y1 = (j->bounds.y1 - i->bounds.y1) / (j->state - i->state);
+ set_bounds_deltas(m_bounds);
+ set_color_deltas(m_color);
+}
- i = j;
- }
- }
- if (m_color.empty())
- {
- m_color.emplace_back(color_step{ 0, { 1.0F, 1.0F, 1.0F, 1.0F }, { 0.0F, 0.0F, 0.0F, 0.0F } });
- }
- else
- {
- auto i(m_color.begin());
- auto j(i);
- while (m_color.end() != ++j)
- {
- assert(j->state > i->state);
- i->delta.a = (j->color.a - i->color.a) / (j->state - i->state);
- i->delta.r = (j->color.r - i->color.r) / (j->state - i->state);
- i->delta.g = (j->color.g - i->color.g) / (j->state - i->state);
- i->delta.b = (j->color.b - i->color.b) / (j->state - i->state);
+//-------------------------------------------------
+// normalize_bounds - normalize component bounds
+//-------------------------------------------------
- i = j;
- }
- }
+void layout_element::component::normalize_bounds(float xoffs, float yoffs, float xscale, float yscale)
+{
+ ::normalize_bounds(m_bounds, 0.0F, 0.0F, xoffs, yoffs, xscale, yscale);
}
@@ -2921,11 +3565,7 @@ std::pair<int, bool> layout_element::component::statewrap() const
render_bounds layout_element::component::overall_bounds() const
{
- auto i(m_bounds.begin());
- render_bounds result(i->bounds);
- while (m_bounds.end() != ++i)
- union_render_bounds(result, i->bounds);
- return result;
+ return accumulate_bounds(m_bounds);
}
@@ -2935,26 +3575,7 @@ render_bounds layout_element::component::overall_bounds() const
render_bounds layout_element::component::bounds(int state) const
{
- auto pos(
- std::lower_bound(
- m_bounds.begin(),
- m_bounds.end(),
- state,
- [] (bounds_step const &lhs, int rhs) { return lhs.state < rhs; }));
- if (m_bounds.begin() == pos)
- {
- return pos->bounds;
- }
- else
- {
- --pos;
- render_bounds result(pos->bounds);
- result.x0 += pos->delta.x0 * (state - pos->state);
- result.x1 += pos->delta.x1 * (state - pos->state);
- result.y0 += pos->delta.y0 * (state - pos->state);
- result.y1 += pos->delta.y1 * (state - pos->state);
- return result;
- }
+ return interpolate_bounds(m_bounds, state);
}
@@ -2964,56 +3585,54 @@ render_bounds layout_element::component::bounds(int state) const
render_color layout_element::component::color(int state) const
{
- auto pos(
- std::lower_bound(
- m_color.begin(),
- m_color.end(),
- state,
- [] (color_step const &lhs, int rhs) { return lhs.state < rhs; }));
- if (m_color.begin() == pos)
- {
- return pos->color;
- }
- else
- {
- --pos;
- render_color result(pos->color);
- result.a += pos->delta.a * (state - pos->state);
- result.r += pos->delta.r * (state - pos->state);
- result.g += pos->delta.g * (state - pos->state);
- result.b += pos->delta.b * (state - pos->state);
- return result;
- }
+ return interpolate_color(m_color, state);
}
//-------------------------------------------------
-// normalize_bounds - normalize component bounds
+// preload - perform expensive operations upfront
//-------------------------------------------------
-void layout_element::component::normalize_bounds(float xoffs, float yoffs, float xscale, float yscale)
+void layout_element::component::preload(running_machine &machine)
{
- auto i(m_bounds.begin());
- i->bounds.x0 = (i->bounds.x0 - xoffs) * xscale;
- i->bounds.x1 = (i->bounds.x1 - xoffs) * xscale;
- i->bounds.y0 = (i->bounds.y0 - yoffs) * yscale;
- i->bounds.y1 = (i->bounds.y1 - yoffs) * yscale;
+}
- auto j(i);
- while (m_bounds.end() != ++j)
- {
- j->bounds.x0 = (j->bounds.x0 - xoffs) * xscale;
- j->bounds.x1 = (j->bounds.x1 - xoffs) * xscale;
- j->bounds.y0 = (j->bounds.y0 - yoffs) * yscale;
- j->bounds.y1 = (j->bounds.y1 - yoffs) * yscale;
- i->delta.x0 = (j->bounds.x0 - i->bounds.x0) / (j->state - i->state);
- i->delta.x1 = (j->bounds.x1 - i->bounds.x1) / (j->state - i->state);
- i->delta.y0 = (j->bounds.y0 - i->bounds.y0) / (j->state - i->state);
- i->delta.y1 = (j->bounds.y1 - i->bounds.y1) / (j->state - i->state);
+//-------------------------------------------------
+// draw - draw element to texture for a given
+// state
+//-------------------------------------------------
- i = j;
- }
+void layout_element::component::draw(running_machine &machine, bitmap_argb32 &dest, int state)
+{
+ // get the local scaled bounds
+ render_bounds const curbounds(bounds(state));
+ rectangle pixelbounds(
+ s32(curbounds.x0 * float(dest.width()) + 0.5F),
+ s32(floorf(curbounds.x1 * float(dest.width()) - 0.5F)),
+ s32(curbounds.y0 * float(dest.height()) + 0.5F),
+ s32(floorf(curbounds.y1 * float(dest.height()) - 0.5F)));
+
+ // based on the component type, add to the texture
+ if (!pixelbounds.empty())
+ draw_aligned(machine, dest, pixelbounds, state);
+}
+
+
+void layout_element::component::draw_aligned(running_machine &machine, bitmap_argb32 &dest, rectangle const &bounds, int state)
+{
+ // derived classes must override one form or other
+ throw false;
+}
+
+
+//-------------------------------------------------
+// maxstate - maximum state drawn differently
+//-------------------------------------------------
+
+int layout_element::component::maxstate() const
+{
+ return -1;
}
@@ -3094,8 +3713,8 @@ void layout_element::component::draw_text(
int effy = bounds.top() + y;
if (effy >= bounds.top() && effy <= bounds.bottom())
{
- u32 *src = &tempbitmap.pix32(y);
- u32 *d = &dest.pix32(effy);
+ u32 const *const src = &tempbitmap.pix(y);
+ u32 *const d = &dest.pix(effy);
for (int x = 0; x < chbounds.width(); x++)
{
int effx = curx + x + chbounds.left();
@@ -3134,8 +3753,8 @@ void layout_element::component::draw_segment_horizontal_caps(bitmap_argb32 &dest
// loop over the width of the segment
for (int y = 0; y < width / 2; y++)
{
- u32 *d0 = &dest.pix32(midy - y);
- u32 *d1 = &dest.pix32(midy + y);
+ u32 *const d0 = &dest.pix(midy - y);
+ u32 *const d1 = &dest.pix(midy + y);
int ty = (y < width / 8) ? width / 8 : y;
// loop over the length of the segment
@@ -3167,8 +3786,8 @@ void layout_element::component::draw_segment_vertical_caps(bitmap_argb32 &dest,
// loop over the width of the segment
for (int x = 0; x < width / 2; x++)
{
- u32 *d0 = &dest.pix32(0, midx - x);
- u32 *d1 = &dest.pix32(0, midx + x);
+ u32 *const d0 = &dest.pix(0, midx - x);
+ u32 *const d1 = &dest.pix(0, midx + x);
int tx = (x < width / 8) ? width / 8 : x;
// loop over the length of the segment
@@ -3204,7 +3823,7 @@ void layout_element::component::draw_segment_diagonal_1(bitmap_argb32 &dest, int
for (int x = minx; x < maxx; x++)
if (x >= 0 && x < dest.width())
{
- u32 *d = &dest.pix32(0, x);
+ u32 *const d = &dest.pix(0, x);
int step = (x - minx) * ratio;
for (int y = maxy - width - step; y < maxy - step; y++)
@@ -3229,7 +3848,7 @@ void layout_element::component::draw_segment_diagonal_2(bitmap_argb32 &dest, int
for (int x = minx; x < maxx; x++)
if (x >= 0 && x < dest.width())
{
- u32 *d = &dest.pix32(0, x);
+ u32 *const d = &dest.pix(0, x);
int step = (x - minx) * ratio;
for (int y = miny + step; y < miny + step + width; y++)
@@ -3252,8 +3871,8 @@ void layout_element::component::draw_segment_decimal(bitmap_argb32 &dest, int mi
// iterate over y
for (u32 y = 0; y <= width; y++)
{
- u32 *d0 = &dest.pix32(midy - y);
- u32 *d1 = &dest.pix32(midy + y);
+ u32 *const d0 = &dest.pix(midy - y);
+ u32 *const d1 = &dest.pix(midy + y);
float xval = width * sqrt(1.0f - (float)(y * y) * ooradius2);
s32 left, right;
@@ -3281,7 +3900,7 @@ void layout_element::component::draw_segment_comma(bitmap_argb32 &dest, int minx
// draw line
for (int x = minx; x < maxx; x++)
{
- u32 *d = &dest.pix32(0, x);
+ u32 *const d = &dest.pix(0, x);
int step = (x - minx) * ratio;
for (int y = maxy; y < maxy - width - step; y--)
@@ -3298,7 +3917,7 @@ void layout_element::component::apply_skew(bitmap_argb32 &dest, int skewwidth)
{
for (int y = 0; y < dest.height(); y++)
{
- u32 *destrow = &dest.pix32(y);
+ u32 *const destrow = &dest.pix(y);
int offs = skewwidth * (dest.height() - y) / dest.height();
for (int x = dest.width() - skewwidth - 1; x >= 0; x--)
destrow[x + offs] = destrow[x];
@@ -3435,7 +4054,18 @@ layout_view::~layout_view()
// the given screen
//-------------------------------------------------
-bool layout_view::has_screen(screen_device &screen) const
+bool layout_view::has_screen(screen_device &screen)
+{
+ return std::find_if(m_items.begin(), m_items.end(), [&screen] (auto &itm) { return itm.screen() == &screen; }) != m_items.end();
+}
+
+
+//-------------------------------------------------
+// has_visible_screen - return true if this view
+// has the given screen visble
+//-------------------------------------------------
+
+bool layout_view::has_visible_screen(screen_device &screen) const
{
return std::find_if(m_screens.begin(), m_screens.end(), [&screen] (auto const &scr) { return &scr.get() == &screen; }) != m_screens.end();
}
@@ -3451,6 +4081,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// reset the bounds and collected active items
render_bounds scrbounds{ 0.0f, 0.0f, 0.0f, 0.0f };
m_bounds = scrbounds;
+ m_visible_items.clear();
m_screen_items.clear();
m_interactive_items.clear();
m_interactive_edges_x.clear();
@@ -3464,20 +4095,23 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
{
if ((visibility_mask & curitem.visibility_mask()) == curitem.visibility_mask())
{
+ render_bounds const rawbounds = accumulate_bounds(curitem.m_rawbounds);
+
// accumulate bounds
+ m_visible_items.emplace_back(curitem);
if (first)
- m_bounds = curitem.m_rawbounds;
+ m_bounds = rawbounds;
else
- union_render_bounds(m_bounds, curitem.m_rawbounds);
+ m_bounds |= rawbounds;
first = false;
// accumulate visible screens and their bounds bounds
if (curitem.screen())
{
if (scrfirst)
- scrbounds = curitem.m_rawbounds;
+ scrbounds = rawbounds;
else
- union_render_bounds(scrbounds, curitem.m_rawbounds);
+ scrbounds |= rawbounds;
scrfirst = false;
// accumulate active screens
@@ -3522,10 +4156,8 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// normalize all the item bounds
for (item &curitem : items())
{
- curitem.m_bounds.x0 = target_bounds.x0 + (curitem.m_rawbounds.x0 - xoffs) * xscale;
- curitem.m_bounds.x1 = target_bounds.x0 + (curitem.m_rawbounds.x1 - xoffs) * xscale;
- curitem.m_bounds.y0 = target_bounds.y0 + (curitem.m_rawbounds.y0 - yoffs) * yscale;
- curitem.m_bounds.y1 = target_bounds.y0 + (curitem.m_rawbounds.y1 - yoffs) * yscale;
+ curitem.m_bounds = curitem.m_rawbounds;
+ normalize_bounds(curitem.m_bounds, target_bounds.x0, target_bounds.y0, xoffs, yoffs, xscale, yscale);
}
// sort edges of interactive items
@@ -3536,12 +4168,13 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
for (unsigned i = 0; m_interactive_items.size() > i; ++i)
{
item &curitem(m_interactive_items[i]);
+ render_bounds const curbounds(accumulate_bounds(curitem.m_bounds));
LOGMASKED(LOG_INTERACTIVE_ITEMS, "%u: (%s %s %s %s) hasinput=%s clickthrough=%s\n",
- i, curitem.bounds().x0, curitem.bounds().y0, curitem.bounds().x1, curitem.bounds().y1, curitem.has_input(), curitem.clickthrough());
- m_interactive_edges_x.emplace_back(i, curitem.bounds().x0, false);
- m_interactive_edges_x.emplace_back(i, curitem.bounds().x1, true);
- m_interactive_edges_y.emplace_back(i, curitem.bounds().y0, false);
- m_interactive_edges_y.emplace_back(i, curitem.bounds().y1, true);
+ i, curbounds.x0, curbounds.y0, curbounds.x1, curbounds.y1, curitem.has_input(), curitem.clickthrough());
+ m_interactive_edges_x.emplace_back(i, curbounds.x0, false);
+ m_interactive_edges_x.emplace_back(i, curbounds.x1, true);
+ m_interactive_edges_y.emplace_back(i, curbounds.y0, false);
+ m_interactive_edges_y.emplace_back(i, curbounds.y1, true);
}
std::sort(m_interactive_edges_x.begin(), m_interactive_edges_x.end());
std::sort(m_interactive_edges_y.begin(), m_interactive_edges_y.end());
@@ -3555,6 +4188,20 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
}
}
+//-------------------------------------------------
+// preload - perform expensive loading upfront
+// for visible elements
+//-------------------------------------------------
+
+void layout_view::preload()
+{
+ for (item &curitem : m_visible_items)
+ {
+ if (curitem.element())
+ curitem.element()->preload();
+ }
+}
+
//-------------------------------------------------
// resolve_tags - resolve tags
@@ -3688,7 +4335,7 @@ void layout_view::add_items(
groupmap,
orientation_add(grouporient, orientation),
grouptrans,
- render_color_multiply(env.parse_color(itemnode->get_child("color")), color),
+ env.parse_color(itemnode->get_child("color")) * color,
false,
false,
true);
@@ -3771,19 +4418,25 @@ layout_view::item::item(
render_color const &color)
: m_element(find_element(env, itemnode, elemmap))
, m_output(env.device(), env.get_attribute_string(itemnode, "name", ""))
+ , m_animoutput(env.device(), make_animoutput_tag(env, itemnode))
, m_have_output(env.get_attribute_string(itemnode, "name", "")[0])
+ , m_have_animoutput(!make_animoutput_tag(env, itemnode).empty())
+ , m_animinput_port(nullptr)
+ , m_animmask(make_animmask(env, itemnode))
+ , m_animshift(get_state_shift(m_animmask))
, m_input_port(nullptr)
, m_input_field(nullptr)
, m_input_mask(env.get_attribute_int(itemnode, "inputmask", 0))
- , m_input_shift(get_input_shift(m_input_mask))
+ , m_input_shift(get_state_shift(m_input_mask))
, m_input_raw(env.get_attribute_bool(itemnode, "inputraw", 0))
, m_clickthrough(env.get_attribute_bool(itemnode, "clickthrough", "yes"))
, m_screen(nullptr)
, m_orientation(orientation_add(env.parse_orientation(itemnode.get_child("orientation")), orientation))
- , m_color(render_color_multiply(env.parse_color(itemnode.get_child("color")), color))
+ , m_color(make_color(env, itemnode, color))
, m_blend_mode(get_blend_mode(env, itemnode))
, m_visibility_mask(env.visibility_mask())
, m_input_tag(make_input_tag(env, itemnode))
+ , m_animinput_tag(make_animinput_tag(env, itemnode))
, m_rawbounds(make_bounds(env, itemnode, trans))
, m_has_clickthrough(env.get_attribute_string(itemnode, "clickthrough", "")[0])
{
@@ -3824,13 +4477,28 @@ layout_view::item::~item()
//-------------------------------------------------
-// screen_container - retrieve screen container
+// bounds - get bounds for current state
//-------------------------------------------------
+render_bounds layout_view::item::bounds() const
+{
+ if (m_bounds.size() == 1U)
+ return m_bounds.front().bounds;
+ else
+ return interpolate_bounds(m_bounds, animation_state());
+}
-render_container *layout_view::item::screen_container(running_machine &machine) const
+
+//-------------------------------------------------
+// color - get color for current state
+//-------------------------------------------------
+
+render_color layout_view::item::color() const
{
- return (m_screen != nullptr) ? &m_screen->container() : nullptr;
+ if (m_color.size() == 1U)
+ return m_color.front().color;
+ else
+ return interpolate_color(m_color, animation_state());
}
@@ -3880,6 +4548,12 @@ void layout_view::item::resolve_tags()
m_output = m_element->default_state();
}
+ if (m_have_animoutput)
+ m_animoutput.resolve();
+
+ if (!m_animinput_tag.empty())
+ m_animinput_port = m_element->machine().root_device().ioport(m_animinput_tag);
+
if (!m_input_tag.empty())
{
m_input_port = m_element->machine().root_device().ioport(m_input_tag);
@@ -3908,6 +4582,21 @@ void layout_view::item::resolve_tags()
// find_element - find element definition
//---------------------------------------------
+inline int layout_view::item::animation_state() const
+{
+ if (m_have_animoutput)
+ return (s32(m_animoutput) & m_animmask) >> m_animshift;
+ else if (m_animinput_port)
+ return (m_animinput_port->read() & m_animmask) >> m_animshift;
+ else
+ return state();
+}
+
+
+//---------------------------------------------
+// find_element - find element definition
+//---------------------------------------------
+
layout_element *layout_view::item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
{
char const *const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element", nullptr));
@@ -3927,19 +4616,105 @@ layout_element *layout_view::item::find_element(view_environment &env, util::xml
// make_bounds - get transformed bounds
//---------------------------------------------
-render_bounds layout_view::item::make_bounds(
+layout_view::item::bounds_vector layout_view::item::make_bounds(
view_environment &env,
util::xml::data_node const &itemnode,
layout_group::transform const &trans)
{
- render_bounds bounds;
- env.parse_bounds(itemnode.get_child("bounds"), bounds);
- render_bounds_transform(bounds, trans);
- if (bounds.x0 > bounds.x1)
- std::swap(bounds.x0, bounds.x1);
- if (bounds.y0 > bounds.y1)
- std::swap(bounds.y0, bounds.y1);
- return bounds;
+ bounds_vector result;
+ for (util::xml::data_node const *bounds = itemnode.get_child("bounds"); bounds; bounds = bounds->get_next_sibling("bounds"))
+ {
+ if (!add_bounds_step(env, result, *bounds))
+ {
+ throw layout_syntax_error(
+ util::string_format(
+ "%s item has duplicate bounds for state",
+ itemnode.get_name()));
+ }
+ }
+ for (emu::render::detail::bounds_step &step : result)
+ {
+ render_bounds_transform(step.bounds, trans);
+ if (step.bounds.x0 > step.bounds.x1)
+ std::swap(step.bounds.x0, step.bounds.x1);
+ if (step.bounds.y0 > step.bounds.y1)
+ std::swap(step.bounds.y0, step.bounds.y1);
+ }
+ set_bounds_deltas(result);
+ return result;
+}
+
+
+//---------------------------------------------
+// make_color - get color inflection points
+//---------------------------------------------
+
+layout_view::item::color_vector layout_view::item::make_color(
+ view_environment &env,
+ util::xml::data_node const &itemnode,
+ render_color const &mult)
+{
+ color_vector result;
+ for (util::xml::data_node const *color = itemnode.get_child("color"); color; color = color->get_next_sibling("color"))
+ {
+ if (!add_color_step(env, result, *color))
+ {
+ throw layout_syntax_error(
+ util::string_format(
+ "%s item has duplicate color for state",
+ itemnode.get_name()));
+ }
+ }
+ if (result.empty())
+ {
+ result.emplace_back(emu::render::detail::color_step{ 0, mult, { 0.0F, 0.0F, 0.0F, 0.0F } });
+ }
+ else
+ {
+ for (emu::render::detail::color_step &step : result)
+ step.color *= mult;
+ set_color_deltas(result);
+ }
+ return result;
+}
+
+
+//---------------------------------------------
+// make_animoutput_tag - get animation output
+// tag
+//---------------------------------------------
+
+std::string layout_view::item::make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode)
+{
+ util::xml::data_node const *const animate(itemnode.get_child("animate"));
+ if (animate)
+ return env.get_attribute_string(*animate, "name", "");
+ else
+ return std::string();
+}
+
+
+//---------------------------------------------
+// make_animmask - get animation state mask
+//---------------------------------------------
+
+ioport_value layout_view::item::make_animmask(view_environment &env, util::xml::data_node const &itemnode)
+{
+ util::xml::data_node const *const animate(itemnode.get_child("animate"));
+ return animate ? env.get_attribute_int(*animate, "mask", ~ioport_value(0)) : ~ioport_value(0);
+}
+
+
+//---------------------------------------------
+// make_animinput_tag - get absolute tag for
+// animation input
+//---------------------------------------------
+
+std::string layout_view::item::make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode)
+{
+ util::xml::data_node const *const animate(itemnode.get_child("animate"));
+ char const *tag(animate ? env.get_attribute_string(*animate, "inputtag", nullptr) : nullptr);
+ return tag ? env.device().subtag(tag) : std::string();
}
@@ -3987,10 +4762,10 @@ int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_nod
//---------------------------------------------
-// get_input_shift - shift to right-align LSB
+// get_state_shift - shift to right-align LSB
//---------------------------------------------
-unsigned layout_view::item::get_input_shift(ioport_value mask)
+unsigned layout_view::item::get_state_shift(ioport_value mask)
{
unsigned result(0U);
while (mask && !BIT(mask, 0))
@@ -4028,13 +4803,17 @@ layout_view::visibility_toggle::visibility_toggle(std::string &&name, u32 mask)
// layout_file - constructor
//-------------------------------------------------
-layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode, char const *dirname)
+layout_file::layout_file(
+ device_t &device,
+ util::xml::data_node const &rootnode,
+ char const *searchpath,
+ char const *dirname)
: m_elemmap()
, m_viewlist()
{
try
{
- environment env(device);
+ environment env(device, searchpath, dirname);
// find the layout node
util::xml::data_node const *const mamelayoutnode = rootnode.get_child("mamelayout");
@@ -4048,7 +4827,7 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode,
// parse all the parameters, elements and groups
group_map groupmap;
- add_elements(dirname, env, *mamelayoutnode, groupmap, false, true);
+ add_elements(env, *mamelayoutnode, groupmap, false, true);
// parse all the views
for (util::xml::data_node const *viewnode = mamelayoutnode->get_child("view"); viewnode != nullptr; viewnode = viewnode->get_next_sibling("view"))
@@ -4085,7 +4864,6 @@ layout_file::~layout_file()
void layout_file::add_elements(
- char const *dirname,
environment &env,
util::xml::data_node const &parentnode,
group_map &groupmap,
@@ -4106,7 +4884,7 @@ void layout_file::add_elements(
char const *const name(env.get_attribute_string(*childnode, "name", nullptr));
if (!name)
throw layout_syntax_error("element lacks name attribute");
- if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(env, *childnode, dirname)).second)
+ if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(env, *childnode)).second)
throw layout_syntax_error(util::string_format("duplicate element name %s", name));
}
else if (!strcmp(childnode->get_name(), "group"))
@@ -4125,7 +4903,7 @@ void layout_file::add_elements(
environment local(env);
for (int i = 0; count > i; ++i)
{
- add_elements(dirname, local, *childnode, groupmap, true, !i);
+ add_elements(local, *childnode, groupmap, true, !i);
local.increment_parameters();
}
}
diff --git a/src/emu/rendutil.cpp b/src/emu/rendutil.cpp
index f3e4950f598..64887d111bd 100644
--- a/src/emu/rendutil.cpp
+++ b/src/emu/rendutil.cpp
@@ -11,9 +11,109 @@
#include "emu.h"
#include "rendutil.h"
+#include "msdib.h"
#include "png.h"
#include "jpeglib.h"
+#include "jerror.h"
+
+
+namespace {
+
+struct jpeg_corefile_source : public jpeg_source_mgr
+{
+ static void source(j_decompress_ptr cinfo, util::core_file &file);
+
+private:
+ static constexpr unsigned INPUT_BUF_SIZE = 4096;
+
+ static void do_init(j_decompress_ptr cinfo)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+ src.start_of_file = true;
+ }
+
+ static boolean do_fill(j_decompress_ptr cinfo)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+
+ size_t nbytes = src.infile->read(src.buffer, INPUT_BUF_SIZE);
+
+ if (0 >= nbytes)
+ {
+ if (src.start_of_file)
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ src.buffer[0] = JOCTET(0xff);
+ src.buffer[1] = JOCTET(JPEG_EOI);
+ nbytes = 2;
+ }
+
+ src.next_input_byte = src.buffer;
+ src.bytes_in_buffer = nbytes;
+ src.start_of_file = false;
+
+ return TRUE;
+ }
+
+ static void do_skip(j_decompress_ptr cinfo, long num_bytes)
+ {
+ jpeg_corefile_source &src = *static_cast<jpeg_corefile_source *>(cinfo->src);
+
+ if (0 < num_bytes)
+ {
+ while (long(src.bytes_in_buffer) < num_bytes)
+ {
+ num_bytes -= long(src.bytes_in_buffer);
+ (void)(*src.fill_input_buffer)(cinfo);
+ }
+ src.next_input_byte += size_t(num_bytes);
+ src.bytes_in_buffer -= size_t(num_bytes);
+ }
+ }
+
+ static void do_term(j_decompress_ptr cinfo)
+ {
+ }
+
+ util::core_file *infile;
+ JOCTET *buffer;
+ bool start_of_file;
+};
+
+void jpeg_corefile_source::source(j_decompress_ptr cinfo, util::core_file &file)
+{
+ jpeg_corefile_source *src;
+ if (!cinfo->src)
+ {
+ src = reinterpret_cast<jpeg_corefile_source *>(
+ (*cinfo->mem->alloc_small)(
+ reinterpret_cast<j_common_ptr>(cinfo),
+ JPOOL_PERMANENT,
+ sizeof(jpeg_corefile_source)));
+ cinfo->src = src;
+ src->buffer = reinterpret_cast<JOCTET *>(
+ (*cinfo->mem->alloc_small)(
+ reinterpret_cast<j_common_ptr>(cinfo),
+ JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * sizeof(JOCTET)));
+ }
+ else
+ {
+ src = static_cast<jpeg_corefile_source *>(cinfo->src);
+ }
+
+ src->init_source = &jpeg_corefile_source::do_init;
+ src->fill_input_buffer = &jpeg_corefile_source::do_fill;
+ src->skip_input_data = &jpeg_corefile_source::do_skip;
+ src->resync_to_restart = jpeg_resync_to_restart;
+ src->term_source = &jpeg_corefile_source::do_term;
+ src->infile = &file;
+ src->bytes_in_buffer = 0;
+ src->next_input_byte = nullptr;
+}
+
+} // anonymous namespace
/***************************************************************************
@@ -23,7 +123,7 @@
/* utilities */
static void resample_argb_bitmap_average(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
static void resample_argb_bitmap_bilinear(u32 *dest, u32 drowpixels, u32 dwidth, u32 dheight, const u32 *source, u32 srowpixels, u32 swidth, u32 sheight, const render_color &color, u32 dx, u32 dy);
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png);
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png);
@@ -42,7 +142,7 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source,
return;
/* adjust the source base */
- const u32 *sbase = &source.pix32(0);
+ const u32 *sbase = &source.pix(0);
/* determine the steppings */
u32 swidth = source.width();
@@ -543,81 +643,103 @@ void render_line_to_quad(const render_bounds *bounds, float width, float length_
/*-------------------------------------------------
- render_load_jpeg - load a JPG file into a
- bitmap
+ render_load_msdib - load a Microsoft DIB file
+ into a bitmap
-------------------------------------------------*/
-void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename)
+void render_load_msdib(bitmap_argb32 &bitmap, util::core_file &file)
{
// deallocate previous bitmap
bitmap.reset();
- // define file's full name
- std::string fname;
+ // read the DIB data
+ util::msdib_error const result = util::msdib_read_bitmap(file, bitmap);
+ if (result != util::msdib_error::NONE)
+ {
+ osd_printf_error("Error reading Microsoft DIB file\n");
+ bitmap.reset();
+ }
+}
- if (dirname == nullptr)
- fname = filename;
- else
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- if (file.open(fname) != osd_file::error::NONE)
- return;
+/*-------------------------------------------------
+ render_load_jpeg - load a JPEG file into a
+ bitmap
+-------------------------------------------------*/
+
+void render_load_jpeg(bitmap_argb32 &bitmap, util::core_file &file)
+{
+ // deallocate previous bitmap
+ bitmap.reset();
- // define standard JPEG structures
+ // create a JPEG source for the file
jpeg_decompress_struct cinfo;
jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
-
- // allocates a buffer for the image
- u32 jpg_size = file.size();
- std::unique_ptr<unsigned char[]> jpg_buffer = std::make_unique<unsigned char[]>(jpg_size);
-
- // read data from the file and set them in the buffer
- file.read(jpg_buffer.get(), jpg_size);
- jpeg_mem_src(&cinfo, jpg_buffer.get(), jpg_size);
-
- // read JPEG header and start decompression
- jpeg_read_header(&cinfo, TRUE);
- jpeg_start_decompress(&cinfo);
-
- // allocates the destination bitmap
- int w = cinfo.output_width;
- int h = cinfo.output_height;
- int s = cinfo.output_components;
- bitmap.allocate(w, h);
-
- // allocates a buffer to receive the information and copy them into the bitmap
- int row_stride = cinfo.output_width * cinfo.output_components;
- JSAMPARRAY buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
- buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * row_stride);
-
- while ( cinfo.output_scanline < cinfo.output_height )
+ jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ JSAMPARRAY buffer = nullptr;
+ try
{
- int j = cinfo.output_scanline;
- jpeg_read_scanlines(&cinfo, buffer, 1);
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+
+ // read JPEG header and start decompression
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ // allocates the destination bitmap
+ int w = cinfo.output_width;
+ int h = cinfo.output_height;
+ int s = cinfo.output_components;
+ bitmap.allocate(w, h);
+
+ // allocates a buffer to receive the information and copy them into the bitmap
+ int row_stride = cinfo.output_width * cinfo.output_components;
+ JSAMPARRAY buffer = reinterpret_cast<JSAMPARRAY>(malloc(sizeof(JSAMPROW)));
+ buffer[0] = reinterpret_cast<JSAMPROW>(malloc(sizeof(JSAMPLE) * row_stride));
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ int j = cinfo.output_scanline;
+ jpeg_read_scanlines(&cinfo, buffer, 1);
- if (s == 1)
- for (int i = 0; i < w; ++i)
- bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
+ if (s == 1)
+ {
+ for (int i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i], buffer[0][i], buffer[0][i]);
- else if (s == 3)
- for (int i = 0; i < w; ++i)
- bitmap.pix32(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
- else
- {
- osd_printf_error("Cannot read JPEG data from %s file.\n", fname);
- bitmap.reset();
- break;
+ }
+ else if (s == 3)
+ {
+ for (int i = 0; i < w; ++i)
+ bitmap.pix(j, i) = rgb_t(0xFF, buffer[0][i * s], buffer[0][i * s + 1], buffer[0][i * s + 2]);
+ }
+ else
+ {
+ osd_printf_error("Cannot read JPEG data from file.\n");
+ bitmap.reset();
+ break;
+ }
}
- }
- // finish decompression and frees the memory
- jpeg_finish_decompress(&cinfo);
+ // finish decompression and frees the memory
+ jpeg_finish_decompress(&cinfo);
+ }
+ catch (jpeg_error_mgr *)
+ {
+ char msg[1024];
+ (cinfo.err->format_message)(reinterpret_cast<j_common_ptr>(&cinfo), msg);
+ osd_printf_error("JPEG error reading data from file: %s\n", msg);
+ bitmap.reset();
+ }
jpeg_destroy_decompress(&cinfo);
- file.close();
- free(buffer[0]);
- free(buffer);
+ if (buffer)
+ {
+ if (buffer[0])
+ free(buffer[0]);
+ free(buffer);
+ }
}
@@ -626,36 +748,25 @@ void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname
bitmap
-------------------------------------------------*/
-bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing)
+bool render_load_png(bitmap_argb32 &bitmap, util::core_file &file, bool load_as_alpha_to_existing)
{
// deallocate if we're not overlaying alpha
if (!load_as_alpha_to_existing)
bitmap.reset();
- // open the file
- std::string fname;
- if (dirname)
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- else
- fname.assign(filename);
- osd_file::error const filerr = file.open(fname);
- if (filerr != osd_file::error::NONE)
- return false;
-
// read the PNG data
- png_info png;
- png_error const result = png.read_file(file);
- file.close();
- if (result != PNGERR_NONE)
+ util::png_info png;
+ util::png_error const result = png.read_file(file);
+ if (result != util::png_error::NONE)
{
- osd_printf_error("%s: Error reading PNG file\n", filename);
+ osd_printf_error("Error reading PNG file\n");
return false;
}
// if less than 8 bits, upsample
- if (PNGERR_NONE != png.expand_buffer_8bit())
+ if (util::png_error::NONE != png.expand_buffer_8bit())
{
- osd_printf_error("%s: Error upsampling PNG bitmap\n", filename);
+ osd_printf_error("Error upsampling PNG bitmap\n");
return false;
}
@@ -663,9 +774,9 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
if (!load_as_alpha_to_existing)
{
// non-alpha case
- if (PNGERR_NONE != png.copy_to_bitmap(bitmap, hasalpha))
+ if (util::png_error::NONE != png.copy_to_bitmap(bitmap, hasalpha))
{
- osd_printf_error("%s: Error copying PNG bitmap to MAME bitmap\n", filename);
+ osd_printf_error("Error copying PNG bitmap to MAME bitmap\n");
return false;
}
}
@@ -674,7 +785,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
// verify we can handle this PNG
if (png.bit_depth > 8)
{
- osd_printf_error("%s: Unsupported bit depth %d (8 bit max)\n", filename, png.bit_depth);
+ osd_printf_error("Unsupported bit depth %d (8 bit max)\n", png.bit_depth);
return false;
}
@@ -692,7 +803,7 @@ bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname,
to the alpha channel of a bitmap
-------------------------------------------------*/
-static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
+static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const util::png_info &png)
{
// FIXME: this function is basically copy/pasted from the PNG code in util, and should be unified with it
u8 accumalpha = 0xff;
@@ -726,7 +837,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
{
for (u32 x = 0; width > x; ++x, ++src)
{
- bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x));
+ bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix(y_trans(y), x_trans(x)) : bitmap.pix(y, x));
rgb_t const pixel(dest);
u8 const alpha(rgb_t(png.palette[*src * 3], png.palette[*src * 3 + 1], png.palette[*src * 3 + 2]).brightness());
accumalpha &= alpha;
@@ -741,7 +852,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
{
for (u32 x = 0; width > x; ++x, ++src)
{
- bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x));
+ bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix(y_trans(y), x_trans(x)) : bitmap.pix(y, x));
rgb_t const pixel(dest);
accumalpha &= *src;
dest = rgb_t(*src, pixel.r(), pixel.g(), pixel.b());
@@ -755,7 +866,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
{
for (u32 x = 0; width > x; ++x, src += 2)
{
- bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x));
+ bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix(y_trans(y), x_trans(x)) : bitmap.pix(y, x));
rgb_t const pixel(dest);
accumalpha &= *src;
dest = rgb_t(*src, pixel.r(), pixel.g(), pixel.b());
@@ -769,7 +880,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
{
for (u32 x = 0; width > x; ++x, src += 3)
{
- bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x));
+ bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix(y_trans(y), x_trans(x)) : bitmap.pix(y, x));
rgb_t const pixel(dest);
u8 const alpha(rgb_t(src[0], src[1], src[2]).brightness());
accumalpha &= alpha;
@@ -784,7 +895,7 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
{
for (u32 x = 0; width > x; ++x, src += 4)
{
- bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix32(y_trans(y), x_trans(x)) : bitmap.pix32(y, x));
+ bitmap_argb32::pixel_t &dest(png.interlace_method ? bitmap.pix(y_trans(y), x_trans(x)) : bitmap.pix(y, x));
rgb_t const pixel(dest);
u8 const alpha(rgb_t(src[0], src[1], src[2]).brightness());
accumalpha &= alpha;
@@ -803,29 +914,41 @@ static bool copy_png_alpha_to_bitmap(bitmap_argb32 &bitmap, const png_info &png)
render_detect_image - detect image format
-------------------------------------------------*/
-ru_imgformat render_detect_image(emu_file &file, const char *dirname, const char *filename)
+ru_imgformat render_detect_image(util::core_file &file)
{
- // open the file
- std::string fname;
- if (dirname)
- fname.assign(dirname).append(PATH_SEPARATOR).append(filename);
- else
- fname.assign(filename);
- osd_file::error const filerr = file.open(fname);
- if (filerr != osd_file::error::NONE)
- return RENDUTIL_IMGFORMAT_ERROR;
-
// PNG: check for valid header
- png_error const result = png_info::verify_header(file);
- if (result == PNGERR_NONE)
- {
- file.close();
+ util::png_error const png = util::png_info::verify_header(file);
+ file.seek(0, SEEK_SET);
+ if (util::png_error::NONE == png)
return RENDUTIL_IMGFORMAT_PNG;
- }
+ // JPEG: attempt to read header with libjpeg
+ jpeg_decompress_struct cinfo;
+ jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jerr.error_exit = [] (j_common_ptr cinfo) { throw cinfo->err; };
+ try
+ {
+ jpeg_create_decompress(&cinfo);
+ cinfo.mem->max_memory_to_use = 128 * 1024 * 1024;
+ jpeg_corefile_source::source(&cinfo, file);
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_destroy_decompress(&cinfo);
+ file.seek(0, SEEK_SET);
+ return RENDUTIL_IMGFORMAT_JPEG;
+ }
+ catch (jpeg_error_mgr *)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ file.seek(0, SEEK_SET);
+ }
+
+ // Microsoft DIB: check for valid header
+ util::msdib_error const msdib = util::msdib_verify_header(file);
file.seek(0, SEEK_SET);
- // TODO: add more when needed
+ if (util::msdib_error::NONE == msdib)
+ return RENDUTIL_IMGFORMAT_MSDIB;
- file.close();
+ // TODO: add more as necessary
return RENDUTIL_IMGFORMAT_UNKNOWN;
}
diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h
index b5c06d6d0fc..9208d729352 100644
--- a/src/emu/rendutil.h
+++ b/src/emu/rendutil.h
@@ -13,7 +13,7 @@
#pragma once
-#include "render.h"
+#include "rendertypes.h"
#include <cmath>
@@ -23,6 +23,8 @@
enum ru_imgformat
{
RENDUTIL_IMGFORMAT_PNG,
+ RENDUTIL_IMGFORMAT_JPEG,
+ RENDUTIL_IMGFORMAT_MSDIB,
RENDUTIL_IMGFORMAT_UNKNOWN,
RENDUTIL_IMGFORMAT_ERROR
@@ -40,9 +42,10 @@ void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source,
bool render_clip_line(render_bounds *bounds, const render_bounds *clip);
bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords);
void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1);
-void render_load_jpeg(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename);
-bool render_load_png(bitmap_argb32 &bitmap, emu_file &file, const char *dirname, const char *filename, bool load_as_alpha_to_existing = false);
-ru_imgformat render_detect_image(emu_file &file, const char *dirname, const char *filename);
+void render_load_msdib(bitmap_argb32 &bitmap, util::core_file &file);
+void render_load_jpeg(bitmap_argb32 &bitmap, util::core_file &file);
+bool render_load_png(bitmap_argb32 &bitmap, util::core_file &file, bool load_as_alpha_to_existing = false);
+ru_imgformat render_detect_image(util::core_file &file);
@@ -57,76 +60,7 @@ ru_imgformat render_detect_image(emu_file &file, const char *dirname, const char
static inline float render_round_nearest(float f)
{
- return floor(f + 0.5f);
-}
-
-
-/*-------------------------------------------------
- set_render_bounds_xy - cleaner way to set the
- bounds
--------------------------------------------------*/
-
-static inline void set_render_bounds_xy(render_bounds &bounds, float x0, float y0, float x1, float y1)
-{
- bounds.x0 = x0;
- bounds.y0 = y0;
- bounds.x1 = x1;
- bounds.y1 = y1;
-}
-
-
-/*-------------------------------------------------
- set_render_bounds_wh - cleaner way to set the
- bounds
--------------------------------------------------*/
-
-static inline void set_render_bounds_wh(render_bounds &bounds, float x0, float y0, float width, float height)
-{
- bounds.x0 = x0;
- bounds.y0 = y0;
- bounds.x1 = x0 + width;
- bounds.y1 = y0 + height;
-}
-
-
-/*-------------------------------------------------
- sect_render_bounds - compute the intersection
- of two render_bounds
--------------------------------------------------*/
-
-static inline void sect_render_bounds(render_bounds &dest, const render_bounds &src)
-{
- dest.x0 = (std::max)(dest.x0, src.x0);
- dest.x1 = (std::min)(dest.x1, src.x1);
- dest.y0 = (std::max)(dest.y0, src.y0);
- dest.y1 = (std::min)(dest.y1, src.y1);
-}
-
-
-/*-------------------------------------------------
- union_render_bounds - compute the union of two
- render_bounds
--------------------------------------------------*/
-
-static inline void union_render_bounds(render_bounds &dest, const render_bounds &src)
-{
- dest.x0 = (std::min)(dest.x0, src.x0);
- dest.x1 = (std::max)(dest.x1, src.x1);
- dest.y0 = (std::min)(dest.y0, src.y0);
- dest.y1 = (std::max)(dest.y1, src.y1);
-}
-
-
-/*-------------------------------------------------
- set_render_color - cleaner way to set a color
--------------------------------------------------*/
-
-static inline void set_render_color(render_color *color, float a, float r, float g, float b)
-{
- color->a = a;
- color->r = r;
- color->g = g;
- color->b = b;
+ return floorf(f + 0.5f);
}
@@ -213,5 +147,4 @@ static inline u8 apply_brightness_contrast_gamma(u8 src, float brightness, float
return u8(result * 255.0f);
}
-
#endif // MAME_EMU_RENDUTIL_H
diff --git a/src/emu/romload.cpp b/src/emu/romload.cpp
index ee8cd2feb2a..a728a6a7660 100644
--- a/src/emu/romload.cpp
+++ b/src/emu/romload.cpp
@@ -192,7 +192,11 @@ chd_error do_open_disk(const emu_options &options, std::initializer_list<std::re
const rom_entry *rom_first_region(const device_t &device)
{
- const rom_entry *romp = &device.rom_region_vector().front();
+ return rom_first_region(&device.rom_region_vector().front());
+}
+
+const rom_entry *rom_first_region(const rom_entry *romp)
+{
while (ROMENTRY_ISPARAMETER(romp) || ROMENTRY_ISSYSTEM_BIOS(romp) || ROMENTRY_ISDEFAULT_BIOS(romp))
romp++;
return !ROMENTRY_ISEND(romp) ? romp : nullptr;
@@ -1418,6 +1422,17 @@ void rom_load_manager::process_region_list()
rom_load_manager::rom_load_manager(running_machine &machine)
: m_machine(machine)
+ , m_warnings(0)
+ , m_knownbad(0)
+ , m_errors(0)
+ , m_romsloaded(0)
+ , m_romstotal(0)
+ , m_romsloadedsize(0)
+ , m_romstotalsize(0)
+ , m_chd_list()
+ , m_region(nullptr)
+ , m_errorstring()
+ , m_softwarningstring()
{
// figure out which BIOS we are using
std::map<std::string, std::string> card_bios;
diff --git a/src/emu/romload.h b/src/emu/romload.h
index 0a558a790b1..2b9955a1590 100644
--- a/src/emu/romload.h
+++ b/src/emu/romload.h
@@ -479,6 +479,7 @@ private:
/* return pointer to the first ROM region within a source */
const rom_entry *rom_first_region(const device_t &device);
+const rom_entry *rom_first_region(const rom_entry *romp);
/* return pointer to the next ROM region within a source */
const rom_entry *rom_next_region(const rom_entry *romp);
diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp
index 8c6e69c0059..c265b14e31b 100644
--- a/src/emu/screen.cpp
+++ b/src/emu/screen.cpp
@@ -9,14 +9,15 @@
***************************************************************************/
#include "emu.h"
+#include "screen.h"
+
#include "emuopts.h"
-#include "png.h"
+#include "render.h"
#include "rendutil.h"
-#include <nanosvg/src/nanosvg.h>
-#include <nanosvg/src/nanosvgrast.h>
+#include "nanosvg.h"
+#include "png.h"
-#include <clocale>
#include <set>
@@ -43,7 +44,6 @@ u32 screen_device::m_id_counter = 0;
class screen_device::svg_renderer {
public:
svg_renderer(memory_region *region);
- ~svg_renderer();
int width() const;
int height() const;
@@ -69,8 +69,8 @@ private:
int x0, y0, x1, y1;
};
- NSVGimage *m_image;
- NSVGrasterizer *m_rasterizer;
+ util::nsvg_image_ptr m_image;
+ util::nsvg_rasterizer_ptr m_rasterizer;
std::vector<bool> m_key_state;
std::vector<std::vector<NSVGshape *>> m_keyed_shapes;
std::unordered_map<std::string, int> m_key_ids;
@@ -94,20 +94,11 @@ private:
screen_device::svg_renderer::svg_renderer(memory_region *region)
{
- // nanosvg makes assumptions about the global locale
- {
- const std::unique_ptr<char []> s(new char[region->bytes() + 1]);
- memcpy(s.get(), region->base(), region->bytes());
- s[region->bytes()] = 0;
- const std::string lcctype(std::setlocale(LC_CTYPE, nullptr));
- const std::string lcnumeric(std::setlocale(LC_NUMERIC, nullptr));
- std::setlocale(LC_CTYPE, "C");
- std::setlocale(LC_NUMERIC, "C");
- m_image = nsvgParse(s.get(), "px", 72);
- std::setlocale(LC_CTYPE, lcctype.c_str());
- std::setlocale(LC_NUMERIC, lcnumeric.c_str());
- }
- m_rasterizer = nsvgCreateRasterizer();
+ const std::unique_ptr<char []> s(new char[region->bytes() + 1]);
+ memcpy(s.get(), region->base(), region->bytes());
+ s[region->bytes()] = 0;
+ m_image.reset(nsvgParse(s.get(), "px", 72));
+ m_rasterizer.reset(nsvgCreateRasterizer());
m_key_count = 0;
@@ -132,12 +123,6 @@ screen_device::svg_renderer::svg_renderer(memory_region *region)
osd_printf_verbose("Parsed SVG '%s', aspect ratio %f\n", region->name(), (m_image->height == 0.0f) ? 0 : m_image->width / m_image->height);
}
-screen_device::svg_renderer::~svg_renderer()
-{
- nsvgDeleteRasterizer(m_rasterizer);
- nsvgDelete(m_image);
-}
-
int screen_device::svg_renderer::width() const
{
return int(m_image->width + 0.5);
@@ -159,7 +144,7 @@ void screen_device::svg_renderer::render_state(std::vector<u32> &dest, const std
s->flags &= ~NSVG_FLAGS_VISIBLE;
}
- nsvgRasterize(m_rasterizer, m_image, 0, 0, m_scale, (unsigned char *)&dest[0], m_sx, m_sy, m_sx*4);
+ nsvgRasterize(m_rasterizer.get(), m_image.get(), 0, 0, m_scale, (unsigned char *)&dest[0], m_sx, m_sy, m_sx*4);
// Nanosvg generates non-premultiplied alpha, so remultiply by
// alpha to "blend" against a black background. Plus align the
@@ -1730,9 +1715,9 @@ void screen_device::create_composited_bitmap()
{
for (int y = 0; y < dstheight; y++)
{
- bitmap_ind16 &srcbitmap = *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y];
- u16 *dst = &curbitmap.as_ind16().pix16(y);
- const u16 *src = &srcbitmap.pix16(0);
+ const bitmap_ind16 &srcbitmap = *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y];
+ u16 *dst = &curbitmap.as_ind16().pix(y);
+ const u16 *src = &srcbitmap.pix(0);
const int dx = (m_scan_widths[y] << 15) / dstwidth;
for (int x = 0; x < m_scan_widths[y]; x += dx)
{
@@ -1746,9 +1731,9 @@ void screen_device::create_composited_bitmap()
{
for (int y = 0; y < dstheight; y++)
{
- bitmap_rgb32 &srcbitmap = *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y];
- u32 *dst = &curbitmap.as_rgb32().pix32(y);
- const u32 *src = &srcbitmap.pix32(0);
+ const bitmap_rgb32 &srcbitmap = *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y];
+ u32 *dst = &curbitmap.as_rgb32().pix(y);
+ const u32 *src = &srcbitmap.pix(0);
const int dx = (m_scan_widths[y] << 15) / dstwidth;
for (int x = 0; x < dstwidth << 15; x += dx)
{
@@ -1837,10 +1822,10 @@ void screen_device::update_burnin()
// iterate over rows in the destination
for (int y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
{
- bitmap_ind16 &srcbitmap = per_scanline ? *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_ind16();
- u64 *dst = &m_burnin.pix64(y);
- const u16 *src = &srcbitmap.pix16(per_scanline ? 0 : (srcy >> 16));
- const rgb_t *palette = m_palette->palette()->entry_list_adjusted();
+ const bitmap_ind16 &srcbitmap = per_scanline ? *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_ind16();
+ u64 *const dst = &m_burnin.pix(y);
+ u16 const *const src = &srcbitmap.pix(per_scanline ? 0 : (srcy >> 16));
+ rgb_t const *const palette = m_palette->palette()->entry_list_adjusted();
for (int x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
{
rgb_t pixel = palette[src[srcx >> 16]];
@@ -1855,9 +1840,9 @@ void screen_device::update_burnin()
// iterate over rows in the destination
for (int y = 0, srcy = ystart; y < dstheight; y++, srcy += ystep)
{
- bitmap_rgb32 &srcbitmap = per_scanline ? *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_rgb32();
- u64 *dst = &m_burnin.pix64(y);
- const u32 *src = &srcbitmap.pix32(per_scanline ? 0 : (srcy >> 16));
+ const bitmap_rgb32 &srcbitmap = per_scanline ? *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y] : curbitmap.as_rgb32();
+ u64 *const dst = &m_burnin.pix(y);
+ u32 const *const src = &srcbitmap.pix(per_scanline ? 0 : (srcy >> 16));
for (int x = 0, srcx = xstart; x < dstwidth; x++, srcx += xstep)
{
rgb_t pixel = src[srcx >> 16];
@@ -1900,7 +1885,7 @@ void screen_device::finalize_burnin()
u64 maxval = 0;
for (int y = 0; y < srcheight; y++)
{
- u64 *src = &m_burnin.pix64(y);
+ u64 const *const src = &m_burnin.pix(y);
for (int x = 0; x < srcwidth; x++)
{
minval = std::min(minval, src[x]);
@@ -1914,8 +1899,8 @@ void screen_device::finalize_burnin()
// now normalize and convert to RGB
for (int y = 0, srcy = 0; y < dstheight; y++, srcy += ystep)
{
- u64 *src = &m_burnin.pix64(srcy >> 16);
- u32 *dst = &finalmap.pix32(y);
+ u64 const *const src = &m_burnin.pix(srcy >> 16);
+ u32 *const dst = &finalmap.pix(y);
for (int x = 0, srcx = 0; x < dstwidth; x++, srcx += xstep)
{
int brightness = u64(maxval - src[srcx >> 16]) * 255 / (maxval - minval);
@@ -1930,14 +1915,14 @@ void screen_device::finalize_burnin()
osd_file::error filerr = file.open(util::string_format("%s" PATH_SEPARATOR "burnin-%s.png", machine().basename(), tag() + 1));
if (filerr == osd_file::error::NONE)
{
- png_info pnginfo;
+ util::png_info pnginfo;
// add two text entries describing the image
pnginfo.add_text("Software", util::string_format("%s %s", emulator_info::get_appname(), emulator_info::get_build_version()).c_str());
pnginfo.add_text("System", util::string_format("%s %s", machine().system().manufacturer, machine().system().type.fullname()).c_str());
// now do the actual work
- png_write_bitmap(file, &pnginfo, finalmap, 0, nullptr);
+ util::png_write_bitmap(file, &pnginfo, finalmap, 0, nullptr);
}
}
@@ -1956,8 +1941,13 @@ void screen_device::load_effect_overlay(const char *filename)
fullname.append(".png");
// load the file
+ m_screen_overlay_bitmap.reset();
emu_file file(machine().options().art_path(), OPEN_FLAG_READ);
- render_load_png(m_screen_overlay_bitmap, file, nullptr, fullname.c_str());
+ if (file.open(fullname) == osd_file::error::NONE)
+ {
+ render_load_png(m_screen_overlay_bitmap, file);
+ file.close();
+ }
if (m_screen_overlay_bitmap.valid())
m_container->set_overlay(&m_screen_overlay_bitmap);
else
diff --git a/src/emu/sound.cpp b/src/emu/sound.cpp
index 6b54797de36..8063db03959 100644
--- a/src/emu/sound.cpp
+++ b/src/emu/sound.cpp
@@ -88,9 +88,9 @@ void stream_buffer::set_sample_rate(u32 rate, bool resample)
if (rate == m_sample_rate)
return;
- // force resampling off if coming to or from an invalid rate
+ // force resampling off if coming to or from an invalid rate, or if we're at time 0 (startup)
sound_assert(rate >= SAMPLE_RATE_MINIMUM - 1);
- if (rate < SAMPLE_RATE_MINIMUM || m_sample_rate < SAMPLE_RATE_MINIMUM)
+ if (rate < SAMPLE_RATE_MINIMUM || m_sample_rate < SAMPLE_RATE_MINIMUM || (m_end_second == 0 && m_end_sample == 0))
resample = false;
// note the time and period of the current buffer (end_time is AFTER the final sample)
@@ -123,7 +123,14 @@ void stream_buffer::set_sample_rate(u32 rate, bool resample)
for (int index = 0; index < buffered_samples; index++)
{
end = prev_index(end);
- buffer[index] = get(end);
+#if (SOUND_DEBUG)
+ // multiple resamples can occur before clearing out old NaNs so
+ // neuter them for this specific case
+ if (std::isnan(m_buffer[end]))
+ buffer[index] = 0;
+ else
+#endif
+ buffer[index] = get(end);
}
}
}
@@ -386,7 +393,7 @@ void sound_stream_output::init(sound_stream &stream, u32 index, char const *tag)
#if (LOG_OUTPUT_WAV)
std::string filename = stream.device().machine().basename();
- filename += stream.device().tag();
+ filename += stream.device().tag();
for (int index = 0; index < filename.size(); index++)
if (filename[index] == ':')
filename[index] = '_';
@@ -571,12 +578,10 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
m_resampling_disabled((flags & STREAM_DISABLE_INPUT_RESAMPLING) != 0),
m_sync_timer(nullptr),
m_input(inputs),
- m_input_array(inputs),
m_input_view(inputs),
m_empty_buffer(100),
m_output_base(output_base),
m_output(outputs),
- m_output_array(outputs),
m_output_view(outputs)
{
sound_assert(outputs > 0);
@@ -621,21 +626,7 @@ sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output
//-------------------------------------------------
-// sound_stream - constructor with old-style
-// callback
-//-------------------------------------------------
-
-sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output_base, u32 sample_rate, stream_update_legacy_delegate callback, sound_stream_flags flags) :
- sound_stream(device, inputs, outputs, output_base, sample_rate, flags)
-{
- m_callback = std::move(callback);
- m_callback_ex = stream_update_delegate(&sound_stream::stream_update_legacy, this);
-}
-
-
-//-------------------------------------------------
-// sound_stream - constructor with new-style
-// callback
+// sound_stream - constructor
//-------------------------------------------------
sound_stream::sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output_base, u32 sample_rate, stream_update_delegate callback, sound_stream_flags flags) :
@@ -840,7 +831,7 @@ void sound_stream::apply_sample_rate_changes(u32 updatenum, u32 downstream_rate)
#if (SOUND_DEBUG)
void sound_stream::print_graph_recursive(int indent, int index)
{
- osd_printf_info("%c %*s%s Ch.%d @ %d\n", m_callback.isnull() ? ' ' : '!', indent, "", name().c_str(), index + m_output_base, sample_rate());
+ osd_printf_info("%*s%s Ch.%d @ %d\n", indent, "", name().c_str(), index + m_output_base, sample_rate());
for (int index = 0; index < m_input.size(); index++)
if (m_input[index].valid())
{
@@ -917,57 +908,6 @@ void sound_stream::sync_update(void *, s32)
//-------------------------------------------------
-// stream_update_legacy - new-style callback which
-// forwards on to the old-style traditional
-// callback, converting to/from floats
-//-------------------------------------------------
-
-void sound_stream::stream_update_legacy(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
-{
- // temporary buffer to hold stream_sample_t inputs and outputs
- stream_sample_t temp_buffer[1024];
- int chunksize = ARRAY_LENGTH(temp_buffer) / (inputs.size() + outputs.size());
- int chunknum = 0;
-
- // create the arrays to pass to the callback
- stream_sample_t **inputptr = m_input.empty() ? nullptr : &m_input_array[0];
- stream_sample_t **outputptr = &m_output_array[0];
- for (unsigned int inputnum = 0; inputnum < inputs.size(); inputnum++)
- inputptr[inputnum] = &temp_buffer[chunksize * chunknum++];
- for (unsigned int outputnum = 0; outputnum < m_output.size(); outputnum++)
- outputptr[outputnum] = &temp_buffer[chunksize * chunknum++];
-
- // loop until all chunks done
- for (int baseindex = 0; baseindex < outputs[0].samples(); baseindex += chunksize)
- {
- // determine the number of samples to process this time
- int cursamples = outputs[0].samples() - baseindex;
- if (cursamples > chunksize)
- cursamples = chunksize;
-
- // copy in the input data
- for (unsigned int inputnum = 0; inputnum < inputs.size(); inputnum++)
- {
- stream_sample_t *dest = inputptr[inputnum];
- for (int index = 0; index < cursamples; index++)
- dest[index] = stream_sample_t(inputs[inputnum].get(baseindex + index) * stream_buffer::sample_t(32768.0));
- }
-
- // run the callback
- m_callback(*this, inputptr, outputptr, cursamples);
-
- // copy out the output data
- for (unsigned int outputnum = 0; outputnum < m_output.size(); outputnum++)
- {
- stream_sample_t *src = outputptr[outputnum];
- for (int index = 0; index < cursamples; index++)
- outputs[outputnum].put(baseindex + index, stream_buffer::sample_t(src[index]) * stream_buffer::sample_t(1.0 / 32768.0));
- }
- }
-}
-
-
-//-------------------------------------------------
// empty_view - return an empty view covering the
// given time period as a substitute for invalid
// inputs
@@ -1074,6 +1014,7 @@ void default_resampler_stream::resampler_sound_update(sound_stream &stream, std:
for ( ; dstindex < numsamples; dstindex++)
{
// if still within the current sample, just replicate
+ srcpos += step;
if (srcpos <= 1.0)
output.put(dstindex, cursample);
@@ -1086,7 +1027,6 @@ void default_resampler_stream::resampler_sound_update(sound_stream &stream, std:
cursample = rebased.get(srcindex++);
output.put(dstindex, stepinv * (prevsample * (step - srcpos) + srcpos * cursample));
}
- srcpos += step;
}
sound_assert(srcindex <= rebased.samples());
}
@@ -1193,23 +1133,6 @@ sound_manager::~sound_manager()
//-------------------------------------------------
-// stream_alloc_legacy - allocate a new stream
-//-------------------------------------------------
-
-sound_stream *sound_manager::stream_alloc_legacy(device_t &device, u32 inputs, u32 outputs, u32 sample_rate, stream_update_legacy_delegate callback)
-{
- // determine output base
- u32 output_base = 0;
- for (auto &stream : m_stream_list)
- if (&stream->device() == &device)
- output_base += stream->output_count();
-
- m_stream_list.push_back(std::make_unique<sound_stream>(device, inputs, outputs, output_base, sample_rate, callback));
- return m_stream_list.back().get();
-}
-
-
-//-------------------------------------------------
// stream_alloc - allocate a new stream with the
// new-style callback and flags
//-------------------------------------------------
diff --git a/src/emu/sound.h b/src/emu/sound.h
index c3027b28ba6..25944847565 100644
--- a/src/emu/sound.h
+++ b/src/emu/sound.h
@@ -8,47 +8,47 @@
****************************************************************************
- In MAME, sound is represented as a graph of sound "streams". Each
- stream has a fixed number of inputs and outputs, and is responsible
- for producing sound on demand.
-
- The graph is driven from the outputs, which are speaker devices.
- These devices are updated on a regular basis (~50 times per second),
- and when an update occurs, the graph is walked from the speaker
- through each input, until all connected streams are up to date.
-
- Individual streams can also be updated manually. This is important
- for sound chips and CPU-driven devices, who should force any
- affected streams to update prior to making changes.
-
- Sound streams are *not* part of the device execution model. This is
- very important to understand. If the process of producing the ouput
- stream affects state that might be consumed by an executing device
- (e.g., a CPU), then care must be taken to ensure that the stream is
- updated frequently enough
-
- The model for timing sound samples is very important and explained
- here. Each stream source has a clock (aka sample rate). Each clock
- edge represents a sample that is held for the duration of one clock
- period. This model has interesting effects:
-
- For example, if you have a 10Hz clock, and call stream.update() at
- t=0.91, it will compute 10 samples (for clock edges 0.0, 0.1, 0.2,
- ..., 0.7, 0.8, and 0.9). And then if you ask the stream what its
- current end time is (via stream.sample_time()), it will say t=1.0,
- which is in the future, because it knows it will hold that last
- sample until 1.0s.
-
- Sound generation callbacks are presented with a std::vector of inputs
- and outputs. The vectors contain objects of read_stream_view and
- write_stream_view respectively, which wrap access to a circular buffer
- of samples. Sound generation callbacks are expected to fill all the
- samples described by the outputs' write_stream_view objects. At the
- moment, all outputs have the same sample rate, so the number of samples
- that need to be generated will be consistent across all outputs.
-
- By default, the inputs will have been resampled to match the output
- sample rate, unless otherwise specified.
+ In MAME, sound is represented as a graph of sound "streams". Each
+ stream has a fixed number of inputs and outputs, and is responsible
+ for producing sound on demand.
+
+ The graph is driven from the outputs, which are speaker devices.
+ These devices are updated on a regular basis (~50 times per second),
+ and when an update occurs, the graph is walked from the speaker
+ through each input, until all connected streams are up to date.
+
+ Individual streams can also be updated manually. This is important
+ for sound chips and CPU-driven devices, who should force any
+ affected streams to update prior to making changes.
+
+ Sound streams are *not* part of the device execution model. This is
+ very important to understand. If the process of producing the ouput
+ stream affects state that might be consumed by an executing device
+ (e.g., a CPU), then care must be taken to ensure that the stream is
+ updated frequently enough
+
+ The model for timing sound samples is very important and explained
+ here. Each stream source has a clock (aka sample rate). Each clock
+ edge represents a sample that is held for the duration of one clock
+ period. This model has interesting effects:
+
+ For example, if you have a 10Hz clock, and call stream.update() at
+ t=0.91, it will compute 10 samples (for clock edges 0.0, 0.1, 0.2,
+ ..., 0.7, 0.8, and 0.9). And then if you ask the stream what its
+ current end time is (via stream.sample_time()), it will say t=1.0,
+ which is in the future, because it knows it will hold that last
+ sample until 1.0s.
+
+ Sound generation callbacks are presented with a std::vector of inputs
+ and outputs. The vectors contain objects of read_stream_view and
+ write_stream_view respectively, which wrap access to a circular buffer
+ of samples. Sound generation callbacks are expected to fill all the
+ samples described by the outputs' write_stream_view objects. At the
+ moment, all outputs have the same sample rate, so the number of samples
+ that need to be generated will be consistent across all outputs.
+
+ By default, the inputs will have been resampled to match the output
+ sample rate, unless otherwise specified.
***************************************************************************/
@@ -81,7 +81,11 @@ constexpr u32 SAMPLE_RATE_MINIMUM = 50;
//**************************************************************************
// turn this on to enable aggressive assertions and other checks
+#ifdef MAME_DEBUG
#define SOUND_DEBUG (1)
+#else
+#define SOUND_DEBUG (0)
+#endif
// if SOUND_DEBUG is on, make assertions fire regardless of MAME_DEBUG
#if (SOUND_DEBUG)
@@ -346,6 +350,7 @@ protected:
class write_stream_view : public read_stream_view
{
+
public:
// empty constructor so we can live in an array or vector
write_stream_view()
@@ -364,7 +369,7 @@ public:
{
}
- // safely write a gain-applied sample to the buffer
+ // safely write a sample to the buffer
void put(s32 index, sample_t sample)
{
sound_assert(u32(index) < samples());
@@ -374,7 +379,33 @@ public:
m_buffer->put(index, sample);
}
- // safely add a gain-applied sample to the buffer
+ // write a sample to the buffer, clamping to +/- the clamp value
+ void put_clamp(s32 index, sample_t sample, sample_t clamp = 1.0)
+ {
+ if (sample > clamp)
+ sample = clamp;
+ if (sample < -clamp)
+ sample = -clamp;
+ put(index, sample);
+ }
+
+ // write a sample to the buffer, converting from an integer with the given maximum
+ void put_int(s32 index, s32 sample, s32 max)
+ {
+ put(index, sample_t(sample) * (1.0f / sample_t(max)));
+ }
+
+ // write a sample to the buffer, converting from an integer with the given maximum
+ void put_int_clamp(s32 index, s32 sample, s32 maxclamp)
+ {
+ if (sample > maxclamp)
+ sample = maxclamp;
+ else if (sample < -maxclamp)
+ sample = -maxclamp;
+ put_int(index, sample, maxclamp);
+ }
+
+ // safely add a sample to the buffer
void add(s32 index, sample_t sample)
{
sound_assert(u32(index) < samples());
@@ -384,6 +415,12 @@ public:
m_buffer->put(index, m_buffer->get(index) + sample);
}
+ // add a sample to the buffer, converting from an integer with the given maximum
+ void add_int(s32 index, s32 sample, s32 max)
+ {
+ add(index, sample_t(sample) * (1.0f / sample_t(max)));
+ }
+
// fill part of the view with the given value
void fill(sample_t value, s32 start, s32 count)
{
@@ -539,10 +576,7 @@ private:
};
-// ======================> stream_update_legacy_delegate/stream_update_delegate
-
-// old-style callback; eventually should be deprecated
-using stream_update_legacy_delegate = delegate<void (sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)>;
+// ======================> stream_update_delegate
// new-style callback
using stream_update_delegate = delegate<void (sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)>;
@@ -577,7 +611,6 @@ class sound_stream
public:
// construction/destruction
- sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output_base, u32 sample_rate, stream_update_legacy_delegate callback, sound_stream_flags flags = STREAM_DEFAULT_FLAGS);
sound_stream(device_t &device, u32 inputs, u32 outputs, u32 output_base, u32 sample_rate, stream_update_delegate callback, sound_stream_flags flags = STREAM_DEFAULT_FLAGS);
virtual ~sound_stream();
@@ -643,9 +676,6 @@ private:
// timer callback for synchronous streams
void sync_update(void *, s32);
- // new callback which wrapps calls through to the old-style callbacks
- void stream_update_legacy(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs);
-
// return a view of 0 data covering the given time period
read_stream_view empty_view(attotime start, attotime end);
@@ -665,7 +695,6 @@ private:
// input information
std::vector<sound_stream_input> m_input; // list of streams we directly depend upon
- std::vector<stream_sample_t *> m_input_array; // array of inputs for passing to the callback
std::vector<read_stream_view> m_input_view; // array of output views for passing to the callback
std::vector<std::unique_ptr<sound_stream>> m_resampler_list; // internal list of resamplers
stream_buffer m_empty_buffer; // empty buffer for invalid inputs
@@ -673,12 +702,10 @@ private:
// output information
u32 m_output_base; // base index of our outputs, relative to our device
std::vector<sound_stream_output> m_output; // list of streams which directly depend upon us
- std::vector<stream_sample_t *> m_output_array; // array of outputs for passing to the callback
std::vector<write_stream_view> m_output_view; // array of output views for passing to the callback
// callback information
- stream_update_legacy_delegate m_callback; // callback function
- stream_update_delegate m_callback_ex; // extended callback function
+ stream_update_delegate m_callback_ex; // extended callback function
};
@@ -737,9 +764,6 @@ public:
int sample_count() const { return m_samples_this_update; }
int unique_id() { return m_unique_id++; }
- // allocate a new stream with the old-style callback
- sound_stream *stream_alloc_legacy(device_t &device, u32 inputs, u32 outputs, u32 sample_rate, stream_update_legacy_delegate callback);
-
// allocate a new stream with a new-style callback
sound_stream *stream_alloc(device_t &device, u32 inputs, u32 outputs, u32 sample_rate, stream_update_delegate callback, sound_stream_flags flags);
diff --git a/src/emu/tilemap.cpp b/src/emu/tilemap.cpp
index fab04e8f162..5757f35341f 100644
--- a/src/emu/tilemap.cpp
+++ b/src/emu/tilemap.cpp
@@ -860,8 +860,8 @@ u8 tilemap_t::tile_draw(const u8 *pendata, u32 x0, u32 y0, u32 palette_base, u8
u8 andmask = ~0, ormask = 0;
for (u16 ty = 0; ty < m_tileheight; ty++)
{
- u16 *pixptr = &m_pixmap.pix16(y0, x0);
- u8 *flagsptr = &m_flagsmap.pix8(y0, x0);
+ u16 *pixptr = &m_pixmap.pix(y0, x0);
+ u8 *flagsptr = &m_flagsmap.pix(y0, x0);
// pre-advance to the next row
y0 += dy0;
@@ -913,7 +913,7 @@ u8 tilemap_t::tile_apply_bitmask(const u8 *maskdata, u32 x0, u32 y0, u8 category
for (u16 ty = 0; ty < m_tileheight; ty++)
{
// pre-advance to the next row
- u8 *flagsptr = &m_flagsmap.pix8(y0, x0);
+ u8 *flagsptr = &m_flagsmap.pix(y0, x0);
y0 += dy0;
// anywhere the bitmask is 0 should be transparent
@@ -1182,7 +1182,7 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
// look up priority and destination base addresses for y1
bitmap_ind8 &priority_bitmap = *blit.priority;
- u8 *priority_baseaddr = &priority_bitmap.pix8(y1, xpos);
+ u8 *priority_baseaddr = &priority_bitmap.pix(y1, xpos);
typename _BitmapClass::pixel_t *dest_baseaddr = nullptr;
int dest_rowpixels = 0;
if (dest.valid())
@@ -1198,8 +1198,8 @@ void tilemap_t::draw_instance(screen_device &screen, _BitmapClass &dest, const b
y2 -= ypos;
// get tilemap pixels
- const u16 *source_baseaddr = &m_pixmap.pix16(y1);
- const u8 *mask_baseaddr = &m_flagsmap.pix8(y1);
+ const u16 *source_baseaddr = &m_pixmap.pix(y1);
+ const u8 *mask_baseaddr = &m_flagsmap.pix(y1);
// get start/stop columns, rounding outward
int mincol = x1 / m_tilewidth;
@@ -1396,9 +1396,9 @@ void tilemap_t::draw_roz_core(screen_device &screen, _BitmapClass &destbitmap, c
u32 cy = starty >> 16;
// get source and priority pointers
- u8 *pri = (priority != 0xff00) ? &priority_bitmap.pix8(sy, sx) : nullptr;
- const u16 *src = &m_pixmap.pix16(cy);
- const u8 *maskptr = &m_flagsmap.pix8(cy);
+ u8 *pri = (priority != 0xff00) ? &priority_bitmap.pix(sy, sx) : nullptr;
+ const u16 *src = &m_pixmap.pix(cy);
+ const u8 *maskptr = &m_flagsmap.pix(cy);
typename _BitmapClass::pixel_t *dest = &destbitmap.pix(sy, sx);
// loop over columns
@@ -1440,15 +1440,15 @@ void tilemap_t::draw_roz_core(screen_device &screen, _BitmapClass &destbitmap, c
// get dest and priority pointers
typename _BitmapClass::pixel_t *dest = &destbitmap.pix(sy, sx);
- u8 *pri = (priority != 0xff00) ? &priority_bitmap.pix8(sy, sx) : nullptr;
+ u8 *pri = (priority != 0xff00) ? &priority_bitmap.pix(sy, sx) : nullptr;
// loop over columns
while (x <= ex)
{
// plot if we match the mask
- if ((m_flagsmap.pix8((cy >> 16) & ymask, (cx >> 16) & xmask) & mask) == value)
+ if ((m_flagsmap.pix((cy >> 16) & ymask, (cx >> 16) & xmask) & mask) == value)
{
- ROZ_PLOT_PIXEL(m_pixmap.pix16((cy >> 16) & ymask, (cx >> 16) & xmask));
+ ROZ_PLOT_PIXEL(m_pixmap.pix((cy >> 16) & ymask, (cx >> 16) & xmask));
if (priority != 0xff00)
*pri = (*pri & (priority >> 8)) | priority;
}
@@ -1482,16 +1482,16 @@ void tilemap_t::draw_roz_core(screen_device &screen, _BitmapClass &destbitmap, c
// get dest and priority pointers
typename _BitmapClass::pixel_t *dest = &destbitmap.pix(sy, sx);
- u8 *pri = (priority != 0xff00) ? &priority_bitmap.pix8(sy, sx) : nullptr;
+ u8 *pri = (priority != 0xff00) ? &priority_bitmap.pix(sy, sx) : nullptr;
// loop over columns
while (x <= ex)
{
// plot if we're within the bitmap and we match the mask
if (cx < widthshifted && cy < heightshifted)
- if ((m_flagsmap.pix8(cy >> 16, cx >> 16) & mask) == value)
+ if ((m_flagsmap.pix(cy >> 16, cx >> 16) & mask) == value)
{
- ROZ_PLOT_PIXEL(m_pixmap.pix16(cy >> 16, cx >> 16));
+ ROZ_PLOT_PIXEL(m_pixmap.pix(cy >> 16, cx >> 16));
if (priority != 0xff00)
*pri = (*pri & (priority >> 8)) | priority;
}
@@ -1611,14 +1611,14 @@ tilemap_manager::~tilemap_manager()
tilemap_t &tilemap_manager::create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_mapper_delegate mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated)
{
if (!allocated)
- allocated = global_alloc(tilemap_t)(machine().root_device());
+ allocated = new tilemap_t(machine().root_device());
return m_tilemap_list.append(allocated->init(*this, decoder, tile_get_info, mapper, tilewidth, tileheight, cols, rows));
}
tilemap_t &tilemap_manager::create(device_gfx_interface &decoder, tilemap_get_info_delegate tile_get_info, tilemap_standard_mapper mapper, u16 tilewidth, u16 tileheight, u32 cols, u32 rows, tilemap_t *allocated)
{
if (!allocated)
- allocated = global_alloc(tilemap_t)(machine().root_device());
+ allocated = new tilemap_t(machine().root_device());
return m_tilemap_list.append(allocated->init(*this, decoder, tile_get_info, mapper, tilewidth, tileheight, cols, rows));
}
diff --git a/src/emu/uiinput.cpp b/src/emu/uiinput.cpp
index 99ccc8b536f..a5470505f12 100644
--- a/src/emu/uiinput.cpp
+++ b/src/emu/uiinput.cpp
@@ -37,14 +37,15 @@ ui_input_manager::ui_input_manager(running_machine &machine)
: m_machine(machine)
, m_presses_enabled(true)
, m_current_mouse_target(nullptr)
+ , m_current_mouse_x(-1)
+ , m_current_mouse_y(-1)
, m_current_mouse_down(false)
, m_current_mouse_field(nullptr)
, m_events_start(0)
, m_events_end(0)
{
- // create the private data
- m_current_mouse_x = -1;
- m_current_mouse_y = -1;
+ std::fill(std::begin(m_next_repeat), std::end(m_next_repeat), 0);
+ std::fill(std::begin(m_seqpressed), std::end(m_seqpressed), 0);
// add a frame callback to poll inputs
machine.add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&ui_input_manager::frame_update, this));
@@ -108,13 +109,13 @@ bool ui_input_manager::push_event(ui_event evt)
// some pre-processing (this is an icky place to do this stuff!)
switch (evt.event_type)
{
- case ui_event::MOUSE_MOVE:
+ case ui_event::type::MOUSE_MOVE:
m_current_mouse_target = evt.target;
m_current_mouse_x = evt.mouse_x;
m_current_mouse_y = evt.mouse_y;
break;
- case ui_event::MOUSE_LEAVE:
+ case ui_event::type::MOUSE_LEAVE:
if (m_current_mouse_target == evt.target)
{
m_current_mouse_target = nullptr;
@@ -123,11 +124,11 @@ bool ui_input_manager::push_event(ui_event evt)
}
break;
- case ui_event::MOUSE_DOWN:
+ case ui_event::type::MOUSE_DOWN:
m_current_mouse_down = true;
break;
- case ui_event::MOUSE_UP:
+ case ui_event::type::MOUSE_UP:
m_current_mouse_down = false;
break;
@@ -300,8 +301,8 @@ g_profiler.stop();
void ui_input_manager::push_mouse_move_event(render_target* target, s32 x, s32 y)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_MOVE;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_MOVE;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
@@ -315,8 +316,8 @@ void ui_input_manager::push_mouse_move_event(render_target* target, s32 x, s32 y
void ui_input_manager::push_mouse_leave_event(render_target* target)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_LEAVE;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_LEAVE;
event.target = target;
push_event(event);
}
@@ -328,8 +329,8 @@ void ui_input_manager::push_mouse_leave_event(render_target* target)
void ui_input_manager::push_mouse_down_event(render_target* target, s32 x, s32 y)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_DOWN;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_DOWN;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
@@ -343,8 +344,8 @@ void ui_input_manager::push_mouse_down_event(render_target* target, s32 x, s32 y
void ui_input_manager::push_mouse_up_event(render_target* target, s32 x, s32 y)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_UP;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_UP;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
@@ -358,8 +359,8 @@ down event to the specified render_target
void ui_input_manager::push_mouse_rdown_event(render_target* target, s32 x, s32 y)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_RDOWN;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_RDOWN;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
@@ -373,8 +374,8 @@ down event to the specified render_target
void ui_input_manager::push_mouse_rup_event(render_target* target, s32 x, s32 y)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_RUP;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_RUP;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
@@ -388,8 +389,8 @@ void ui_input_manager::push_mouse_rup_event(render_target* target, s32 x, s32 y)
-------------------------------------------------*/
void ui_input_manager::push_mouse_double_click_event(render_target* target, s32 x, s32 y)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_DOUBLE_CLICK;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_DOUBLE_CLICK;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
@@ -402,8 +403,8 @@ void ui_input_manager::push_mouse_double_click_event(render_target* target, s32
-------------------------------------------------*/
void ui_input_manager::push_char_event(render_target* target, char32_t ch)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::IME_CHAR;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::IME_CHAR;
event.target = target;
event.ch = ch;
push_event(event);
@@ -416,8 +417,8 @@ void ui_input_manager::push_char_event(render_target* target, char32_t ch)
void ui_input_manager::push_mouse_wheel_event(render_target *target, s32 x, s32 y, short delta, int ucNumLines)
{
- ui_event event = { ui_event::NONE };
- event.event_type = ui_event::MOUSE_WHEEL;
+ ui_event event = { ui_event::type::NONE };
+ event.event_type = ui_event::type::MOUSE_WHEEL;
event.target = target;
event.mouse_x = x;
event.mouse_y = y;
diff --git a/src/emu/uiinput.h b/src/emu/uiinput.h
index 85f4eb7cebd..17747fc9f98 100644
--- a/src/emu/uiinput.h
+++ b/src/emu/uiinput.h
@@ -26,7 +26,7 @@
struct ui_event
{
- enum type
+ enum class type
{
NONE,
MOUSE_MOVE,
@@ -60,37 +60,36 @@ public:
void frame_update();
- /* pushes a single event onto the queue */
+ // pushes a single event onto the queue
bool push_event(ui_event event);
- /* pops an event off of the queue */
+ // pops an event off of the queue
bool pop_event(ui_event *event);
- /* check the next event type without removing it */
- ui_event::type peek_event_type() const { return (m_events_start != m_events_end) ? m_events[m_events_start].event_type : ui_event::NONE; }
+ // check the next event type without removing it
+ ui_event::type peek_event_type() const { return (m_events_start != m_events_end) ? m_events[m_events_start].event_type : ui_event::type::NONE; }
- /* clears all outstanding events */
+ // clears all outstanding events
void reset();
- /* retrieves the current location of the mouse */
+ // retrieves the current location of the mouse
render_target *find_mouse(s32 *x, s32 *y, bool *button) const;
ioport_field *find_mouse_field() const;
- /* return true if a key down for the given user interface sequence is detected */
+ // return true if a key down for the given user interface sequence is detected
bool pressed(int code);
// enable/disable UI key presses
bool presses_enabled() const { return m_presses_enabled; }
void set_presses_enabled(bool enabled) { m_presses_enabled = enabled; }
- /* return true if a key down for the given user interface sequence is detected, or if
- autorepeat at the given speed is triggered */
+ // return true if a key down for the given user interface sequence is detected, or if autorepeat at the given speed is triggered
bool pressed_repeat(int code, int speed);
// getters
running_machine &machine() const { return m_machine; }
-
+ // queueing events
void push_mouse_move_event(render_target* target, s32 x, s32 y);
void push_mouse_leave_event(render_target* target);
void push_mouse_down_event(render_target* target, s32 x, s32 y);
@@ -108,19 +107,19 @@ private:
// internal state
running_machine & m_machine; // reference to our machine
- /* pressed states; retrieved with ui_input_pressed() */
+ // pressed states; retrieved with ui_input_pressed()
bool m_presses_enabled;
osd_ticks_t m_next_repeat[IPT_COUNT];
u8 m_seqpressed[IPT_COUNT];
- /* mouse position/info */
+ // mouse position/info
render_target * m_current_mouse_target;
s32 m_current_mouse_x;
s32 m_current_mouse_y;
bool m_current_mouse_down;
ioport_field * m_current_mouse_field;
- /* popped states; ring buffer of ui_events */
+ // popped states; ring buffer of ui_events
ui_event m_events[EVENT_QUEUE_SIZE];
int m_events_start;
int m_events_end;
diff --git a/src/emu/video.cpp b/src/emu/video.cpp
index e28e6aa1bae..56d60ba1661 100644
--- a/src/emu/video.cpp
+++ b/src/emu/video.cpp
@@ -329,16 +329,16 @@ void video_manager::save_snapshot(screen_device *screen, emu_file &file)
// add two text entries describing the image
std::string text1 = std::string(emulator_info::get_appname()).append(" ").append(emulator_info::get_build_version());
std::string text2 = std::string(machine().system().manufacturer).append(" ").append(machine().system().type.fullname());
- png_info pnginfo;
+ util::png_info pnginfo;
pnginfo.add_text("Software", text1.c_str());
pnginfo.add_text("System", text2.c_str());
// now do the actual work
const rgb_t *palette = (screen != nullptr && screen->has_palette()) ? screen->palette().palette()->entry_list_adjusted() : nullptr;
int entries = (screen != nullptr && screen->has_palette()) ? screen->palette().entries() : 0;
- png_error error = png_write_bitmap(file, &pnginfo, m_snap_bitmap, entries, palette);
- if (error != PNGERR_NONE)
- osd_printf_error("Error generating PNG for snapshot: png_error = %d\n", error);
+ util::png_error error = util::png_write_bitmap(file, &pnginfo, m_snap_bitmap, entries, palette);
+ if (error != util::png_error::NONE)
+ osd_printf_error("Error generating PNG for snapshot: png_error = %d\n", std::underlying_type_t<util::png_error>(error));
}
@@ -1075,9 +1075,9 @@ void video_manager::create_snapshot_bitmap(screen_device *screen)
render_primitive_list &primlist = m_snap_target->get_primitives();
primlist.acquire_lock();
if (machine().options().snap_bilinear())
- snap_renderer_bilinear::draw_primitives(primlist, &m_snap_bitmap.pix32(0), width, height, m_snap_bitmap.rowpixels());
+ snap_renderer_bilinear::draw_primitives(primlist, &m_snap_bitmap.pix(0), width, height, m_snap_bitmap.rowpixels());
else
- snap_renderer::draw_primitives(primlist, &m_snap_bitmap.pix32(0), width, height, m_snap_bitmap.rowpixels());
+ snap_renderer::draw_primitives(primlist, &m_snap_bitmap.pix(0), width, height, m_snap_bitmap.rowpixels());
primlist.release_lock();
}
diff --git a/src/frontend/mame/audit.cpp b/src/frontend/mame/audit.cpp
index f8d2cbdd9d4..6509b264e49 100644
--- a/src/frontend/mame/audit.cpp
+++ b/src/frontend/mame/audit.cpp
@@ -22,6 +22,111 @@
#include <algorithm>
+//#define VERBOSE 1
+#define LOG_OUTPUT_FUNC osd_printf_verbose
+#include "logmacro.h"
+
+
+namespace {
+
+struct parent_rom
+{
+ parent_rom(device_type t, rom_entry const *r) : type(t), name(ROM_GETNAME(r)), hashes(ROM_GETHASHDATA(r)), length(rom_file_size(r)) { }
+
+ std::reference_wrapper<std::remove_reference_t<device_type> > type;
+ std::string name;
+ util::hash_collection hashes;
+ uint64_t length;
+};
+
+
+class parent_rom_vector : public std::vector<parent_rom>
+{
+public:
+ using std::vector<parent_rom>::vector;
+
+ std::add_pointer_t<device_type> find_shared_device(device_t &current, char const *name, util::hash_collection const &hashes, uint64_t length) const
+ {
+ // if we're examining a child device, it will always have a perfect match
+ if (current.owner())
+ return &current.type();
+
+ // scan backwards through parents for a matching definition
+ bool const dumped(!hashes.flag(util::hash_collection::FLAG_NO_DUMP));
+ std::add_pointer_t<device_type> best(nullptr);
+ for (const_reverse_iterator it = crbegin(); crend() != it; ++it)
+ {
+ if (it->length == length)
+ {
+ if (dumped)
+ {
+ if (it->hashes == hashes)
+ return &it->type.get();
+ }
+ else if (it->name == name)
+ {
+ if (it->hashes.flag(util::hash_collection::FLAG_NO_DUMP))
+ return &it->type.get();
+ else if (!best)
+ best = &it->type.get();
+ }
+ }
+ }
+ return best;
+ }
+
+ std::pair<std::add_pointer_t<device_type>, bool> actual_matches_shared(device_t &current, media_auditor::audit_record const &record)
+ {
+ // no result if no matching file was found
+ if ((record.status() != media_auditor::audit_status::GOOD) && (record.status() != media_auditor::audit_status::FOUND_INVALID))
+ return std::make_pair(nullptr, false);
+
+ // if we're examining a child device, scan it first
+ bool matches_device_undumped(false);
+ if (current.owner())
+ {
+ for (const rom_entry *region = rom_first_region(current); region; region = rom_next_region(region))
+ {
+ for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ if (rom_file_size(rom) == record.actual_length())
+ {
+ util::hash_collection const hashes(ROM_GETHASHDATA(rom));
+ if (hashes == record.actual_hashes())
+ return std::make_pair(&current.type(), empty());
+ else if (hashes.flag(util::hash_collection::FLAG_NO_DUMP) && (rom->name() == record.name()))
+ matches_device_undumped = true;
+ }
+ }
+ }
+ }
+
+ // look for a matching parent ROM
+ std::add_pointer_t<device_type> closest_bad(nullptr);
+ for (const_reverse_iterator it = crbegin(); crend() != it; ++it)
+ {
+ if (it->length == record.actual_length())
+ {
+ if (it->hashes == record.actual_hashes())
+ return std::make_pair(&it->type.get(), it->type.get() == front().type.get());
+ else if (it->hashes.flag(util::hash_collection::FLAG_NO_DUMP) && (it->name == record.name()))
+ closest_bad = &it->type.get();
+ }
+ }
+
+ // fall back to the nearest bad dump
+ if (closest_bad)
+ return std::make_pair(closest_bad, front().type.get() == *closest_bad);
+ else if (matches_device_undumped)
+ return std::make_pair(&current.type(), empty());
+ else
+ return std::make_pair(nullptr, false);
+ }
+};
+
+} // anonymous namespace
+
+
//**************************************************************************
// CORE FUNCTIONS
@@ -51,10 +156,29 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
// store validation for later
m_validation = validation;
- std::size_t found = 0;
- std::size_t required = 0;
- std::size_t shared_found = 0;
- std::size_t shared_required = 0;
+ // first walk the parent chain for required ROMs
+ parent_rom_vector parentroms;
+ for (auto drvindex = m_enumerator.find(m_enumerator.driver().parent); 0 <= drvindex; drvindex = m_enumerator.find(m_enumerator.driver(drvindex).parent))
+ {
+ game_driver const &parent(m_enumerator.driver(drvindex));
+ LOG("Checking parent %s for ROM files\n", parent.type.shortname());
+ std::vector<rom_entry> const roms(rom_build_entries(parent.rom));
+ for (rom_entry const *region = rom_first_region(&roms.front()); region; region = rom_next_region(region))
+ {
+ for (rom_entry const *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
+ {
+ LOG("Adding parent ROM %s\n", rom->name());
+ parentroms.emplace_back(parent.type, rom);
+ }
+ }
+ }
+
+ // count ROMs required/found
+ std::size_t found(0);
+ std::size_t required(0);
+ std::size_t shared_found(0);
+ std::size_t shared_required(0);
+ std::size_t parent_found(0);
// iterate over devices and regions
std::vector<std::string> searchpath;
@@ -68,12 +192,20 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
{
if (searchpath.empty())
+ {
+ LOG("Audit media for device %s(%s)\n", device.shortname(), device.tag());
searchpath = device.searchpath();
+ }
+ // look for a matching parent or device ROM
char const *const name(ROM_GETNAME(rom));
util::hash_collection const hashes(ROM_GETHASHDATA(rom));
- device_t *const shared_device(find_shared_device(device, name, hashes, rom_file_size(rom)));
- const auto dumped(!hashes.flag(util::hash_collection::FLAG_NO_DUMP));
+ bool const dumped(!hashes.flag(util::hash_collection::FLAG_NO_DUMP));
+ std::add_pointer_t<device_type> const shared_device(parentroms.find_shared_device(device, name, hashes, rom_file_size(rom)));
+ if (shared_device)
+ LOG("File '%s' %s%sdumped shared with %s\n", name, ROM_ISOPTIONAL(rom) ? "optional " : "", dumped ? "" : "un", shared_device->shortname());
+ else
+ LOG("File '%s' %s%sdumped\n", name, ROM_ISOPTIONAL(rom) ? "optional " : "", dumped ? "" : "un");
// count the number of files with hashes
if (dumped && !ROM_ISOPTIONAL(rom))
@@ -83,7 +215,7 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
shared_required++;
}
- audit_record *record = nullptr;
+ audit_record *record(nullptr);
if (ROMREGION_ISROMDATA(region))
record = &audit_one_rom(searchpath, rom);
else if (ROMREGION_ISDISKDATA(region))
@@ -91,22 +223,32 @@ media_auditor::summary media_auditor::audit_media(const char *validation)
if (record)
{
+ // see if the actual content found belongs to a parent
+ auto const matchesshared(parentroms.actual_matches_shared(device, *record));
+ if (matchesshared.first)
+ LOG("Actual ROM file shared with %sparent %s\n", matchesshared.second ? "immediate " : "", matchesshared.first->shortname());
+
// count the number of files that are found.
- if (!device.owner() && ((record->status() == audit_status::GOOD && dumped) || (record->status() == audit_status::FOUND_INVALID && !find_shared_device(device, name, record->actual_hashes(), record->actual_length()))))
+ if ((record->status() == audit_status::GOOD) || ((record->status() == audit_status::FOUND_INVALID) && !matchesshared.first))
{
found++;
if (shared_device)
shared_found++;
+ if (matchesshared.second)
+ parent_found++;
}
record->set_shared_device(shared_device);
}
}
}
+
+ if (!searchpath.empty())
+ LOG("Total required=%u (shared=%u) found=%u (shared=%u parent=%u)\n", required, shared_required, found, shared_found, parent_found);
}
// if we only find files that are in the parent & either the set has no unique files or the parent is not found, then assume we don't have the set at all
- if ((found == shared_found) && (required > 0) && ((required != shared_required) || (shared_found == 0)))
+ if ((found == shared_found) && required && ((required != shared_required) || !parent_found))
{
m_record_list.clear();
return NOTFOUND;
@@ -341,7 +483,7 @@ media_auditor::summary media_auditor::summarize(const char *name, std::ostream *
case audit_substatus::NOT_FOUND:
if (output)
{
- device_t *const shared_device = record.shared_device();
+ std::add_pointer_t<device_type> const shared_device = record.shared_device();
if (shared_device)
util::stream_format(*output, "NOT FOUND (%s)\n", shared_device->shortname());
else
@@ -500,59 +642,6 @@ void media_auditor::compute_status(audit_record &record, const rom_entry *rom, b
//-------------------------------------------------
-// find_shared_device - return the source that
-// shares a media entry with the same hashes
-//-------------------------------------------------
-
-device_t *media_auditor::find_shared_device(device_t &device, const char *name, const util::hash_collection &romhashes, uint64_t romlength)
-{
- bool const dumped = !romhashes.flag(util::hash_collection::FLAG_NO_DUMP);
-
- // special case for non-root devices
- device_t *highest_device = nullptr;
- if (device.owner())
- {
- for (const rom_entry *region = rom_first_region(device); region; region = rom_next_region(region))
- {
- for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
- {
- if (rom_file_size(rom) == romlength)
- {
- util::hash_collection hashes(ROM_GETHASHDATA(rom));
- if ((dumped && hashes == romhashes) || (!dumped && ROM_GETNAME(rom) == name))
- highest_device = &device;
- }
- }
- }
- }
- else
- {
- // iterate up the parent chain
- for (auto drvindex = m_enumerator.find(m_enumerator.driver().parent); drvindex >= 0; drvindex = m_enumerator.find(m_enumerator.driver(drvindex).parent))
- {
- for (device_t &scandevice : device_iterator(m_enumerator.config(drvindex)->root_device()))
- {
- for (const rom_entry *region = rom_first_region(scandevice); region; region = rom_next_region(region))
- {
- for (const rom_entry *rom = rom_first_file(region); rom; rom = rom_next_file(rom))
- {
- if (rom_file_size(rom) == romlength)
- {
- util::hash_collection hashes(ROM_GETHASHDATA(rom));
- if ((dumped && hashes == romhashes) || (!dumped && ROM_GETNAME(rom) == name))
- highest_device = &scandevice;
- }
- }
- }
- }
- }
- }
-
- return highest_device;
-}
-
-
-//-------------------------------------------------
// audit_record - constructor
//-------------------------------------------------
diff --git a/src/frontend/mame/audit.h b/src/frontend/mame/audit.h
index d336f6e5ae4..d1904820f03 100644
--- a/src/frontend/mame/audit.h
+++ b/src/frontend/mame/audit.h
@@ -107,7 +107,7 @@ public:
uint64_t actual_length() const { return m_length; }
const util::hash_collection &expected_hashes() const { return m_exphashes; }
const util::hash_collection &actual_hashes() const { return m_hashes; }
- device_t *shared_device() const { return m_shared_device; }
+ std::add_pointer_t<device_type> shared_device() const { return m_shared_device; }
// setters
void set_status(audit_status status, audit_substatus substatus)
@@ -128,22 +128,22 @@ public:
m_length = length;
}
- void set_shared_device(device_t *shared_device)
+ void set_shared_device(std::add_pointer_t<device_type> shared_device)
{
m_shared_device = shared_device;
}
private:
// internal state
- media_type m_type; // type of item that was audited
- audit_status m_status; // status of audit on this item
- audit_substatus m_substatus; // finer-detail status
- const char * m_name; // name of item
- uint64_t m_explength; // expected length of item
- uint64_t m_length; // actual length of item
- util::hash_collection m_exphashes; // expected hash data
- util::hash_collection m_hashes; // actual hash information
- device_t * m_shared_device; // device that shares the rom
+ media_type m_type; // type of item that was audited
+ audit_status m_status; // status of audit on this item
+ audit_substatus m_substatus; // finer-detail status
+ const char * m_name; // name of item
+ uint64_t m_explength; // expected length of item
+ uint64_t m_length; // actual length of item
+ util::hash_collection m_exphashes; // expected hash data
+ util::hash_collection m_hashes; // actual hash information
+ std::add_pointer_t<device_type> m_shared_device; // device that shares the ROM
};
using record_list = std::list<audit_record>;
@@ -166,7 +166,6 @@ private:
audit_record &audit_one_rom(const std::vector<std::string> &searchpath, const rom_entry *rom);
template <typename... T> audit_record &audit_one_disk(const rom_entry *rom, T &&... args);
void compute_status(audit_record &record, const rom_entry *rom, bool found);
- device_t *find_shared_device(device_t &device, const char *name, const util::hash_collection &romhashes, uint64_t romlength);
// internal state
record_list m_record_list;
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 4785b718d68..978227bade0 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -343,7 +343,7 @@ int cli_frontend::execute(std::vector<std::string> &args)
}
util::archive_file::cache_clear();
- global_free(manager);
+ delete manager;
return m_result;
}
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 4f44c3ad9d4..9afe6827cfd 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -1570,7 +1570,7 @@ void lua_engine::initialize()
* debugger.execution_state - accessor for active cpu run state
*/
- struct wrap_textbuf { wrap_textbuf(text_buffer *buf) { textbuf = buf; }; text_buffer *textbuf; };
+ struct wrap_textbuf { wrap_textbuf(const text_buffer &buf) : textbuf(buf) { } std::reference_wrapper<const text_buffer> textbuf; };
auto debugger_type = sol().registry().create_simple_usertype<debugger_manager>("new", sol::no_constructor);
debugger_type.set("command", [](debugger_manager &debug, const std::string &cmd) { debug.console().execute_command(cmd, false); });
diff --git a/src/frontend/mame/mame.cpp b/src/frontend/mame/mame.cpp
index 908da0e2bf6..b996bae1dc0 100644
--- a/src/frontend/mame/mame.cpp
+++ b/src/frontend/mame/mame.cpp
@@ -10,38 +10,44 @@
#include "emu.h"
#include "mame.h"
+
+#include "ui/inifile.h"
+#include "ui/selgame.h"
+#include "ui/simpleselgame.h"
+#include "ui/ui.h"
+
+#include "cheat.h"
+#include "clifront.h"
#include "emuopts.h"
+#include "luaengine.h"
#include "mameopts.h"
#include "pluginopts.h"
-#include "osdepend.h"
#include "validity.h"
-#include "clifront.h"
-#include "luaengine.h"
-#include <ctime>
-#include "ui/ui.h"
-#include "ui/selgame.h"
-#include "ui/simpleselgame.h"
-#include "cheat.h"
-#include "ui/inifile.h"
+
#include "xmlfile.h"
+#include "osdepend.h"
+
+#include <ctime>
+
+
//**************************************************************************
// MACHINE MANAGER
//**************************************************************************
-mame_machine_manager* mame_machine_manager::m_manager = nullptr;
+mame_machine_manager *mame_machine_manager::s_manager = nullptr;
mame_machine_manager* mame_machine_manager::instance(emu_options &options, osd_interface &osd)
{
- if (!m_manager)
- m_manager = global_alloc(mame_machine_manager(options, osd));
+ if (!s_manager)
+ s_manager = new mame_machine_manager(options, osd);
- return m_manager;
+ return s_manager;
}
mame_machine_manager* mame_machine_manager::instance()
{
- return m_manager;
+ return s_manager;
}
//-------------------------------------------------
@@ -51,7 +57,7 @@ mame_machine_manager* mame_machine_manager::instance()
mame_machine_manager::mame_machine_manager(emu_options &options,osd_interface &osd) :
machine_manager(options, osd),
m_plugins(std::make_unique<plugin_options>()),
- m_lua(global_alloc(lua_engine)),
+ m_lua(std::make_unique<lua_engine>()),
m_new_driver_pending(nullptr),
m_firstrun(true),
m_autoboot_timer(nullptr)
@@ -65,8 +71,8 @@ mame_machine_manager::mame_machine_manager(emu_options &options,osd_interface &o
mame_machine_manager::~mame_machine_manager()
{
- global_free(m_lua);
- m_manager = nullptr;
+ m_lua.reset();
+ s_manager = nullptr;
}
diff --git a/src/frontend/mame/mame.h b/src/frontend/mame/mame.h
index 041612de758..037d714b39c 100644
--- a/src/frontend/mame/mame.h
+++ b/src/frontend/mame/mame.h
@@ -35,7 +35,7 @@ public:
~mame_machine_manager();
plugin_options &plugins() const { return *m_plugins; }
- lua_engine *lua() { return m_lua; }
+ lua_engine *lua() { return m_lua.get(); }
virtual void update_machine() override;
@@ -72,12 +72,12 @@ private:
mame_machine_manager &operator=(mame_machine_manager &&) = delete;
std::unique_ptr<plugin_options> m_plugins; // pointer to plugin options
- lua_engine * m_lua;
+ std::unique_ptr<lua_engine> m_lua;
const game_driver * m_new_driver_pending; // pointer to the next pending driver
bool m_firstrun;
- static mame_machine_manager* m_manager;
+ static mame_machine_manager *s_manager;
emu_timer *m_autoboot_timer; // autoboot timer
std::unique_ptr<mame_ui_manager> m_ui; // internal data from ui.cpp
std::unique_ptr<cheat_manager> m_cheat; // internal data from cheat.cpp
diff --git a/src/frontend/mame/ui/icorender.cpp b/src/frontend/mame/ui/icorender.cpp
index bea85f9dd60..5bda0836838 100644
--- a/src/frontend/mame/ui/icorender.cpp
+++ b/src/frontend/mame/ui/icorender.cpp
@@ -19,6 +19,7 @@
#include "emu.h"
#include "icorender.h"
+#include "util/msdib.h"
#include "util/png.h"
#include <algorithm>
@@ -26,11 +27,10 @@
#include <cstdint>
#include <cstring>
-// need to set LOG_OUTPUT_STREAM because there's no logerror outside devices
-#define LOG_OUTPUT_STREAM std::cerr
+// need to set LOG_OUTPUT_FUNC or LOG_OUTPUT_STREAM because there's no logerror outside devices
+#define LOG_OUTPUT_FUNC osd_printf_verbose
#define LOG_GENERAL (1U << 0)
-#define LOG_DIB (1U << 1)
//#define VERBOSE (LOG_GENERAL | LOG_DIB)
@@ -41,16 +41,6 @@ namespace ui {
namespace {
-// DIB compression schemes
-enum : uint32_t
-{
- DIB_COMP_NONE = 0,
- DIB_COMP_RLE8 = 1,
- DIB_COMP_RLE4 = 2,
- DIB_COMP_BITFIELDS = 3
-};
-
-
// ICO file header
struct icon_dir_t
{
@@ -83,67 +73,6 @@ struct icon_dir_entry_t
uint32_t offset; // offset to image data from start of file
};
-// old-style DIB header
-struct bitmap_core_header_t
-{
- uint32_t size; // size of the header (12, 16 or 64)
- int16_t width; // width of bitmap in pixels
- int16_t height; // height of the image in pixels
- uint16_t planes; // number of colour planes (must be 1)
- uint16_t bpp; // bits per pixel
-};
-
-// new-style DIB header
-struct bitmap_info_header_t
-{
- uint32_t size; // size of the header
- int32_t width; // width of bitmap in pixels
- int32_t height; // height of bitmap in pixels
- uint16_t planes; // number of colour planes (must be 1)
- uint16_t bpp; // bits per pixel
- uint32_t comp; // compression method
- uint32_t rawsize; // size of bitmap data after decompression or 0 if uncompressed
- int32_t hres; // horizontal resolution in pixels/metre
- int32_t vres; // horizontal resolution in pixels/metre
- uint32_t colors; // number of colours or 0 for 1 << bpp
- uint32_t important; // number of important colours or 0 if all important
- uint32_t red; // red field mask - must be contiguous
- uint32_t green; // green field mask - must be contiguous
- uint32_t blue; // blue field mask - must be contiguous
- uint32_t alpha; // alpha field mask - must be contiguous
-};
-
-
-bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits)
-{
- shift = count_leading_zeros(mask);
- mask <<= shift;
- bits = count_leading_ones(mask);
- mask <<= shift;
- shift = 32 - shift - bits;
- return !mask;
-}
-
-
-void dib_truncate_channel(unsigned &shift, unsigned &bits)
-{
- if (8U < bits)
- {
- unsigned const excess(bits - 8);
- shift += excess;
- bits -= excess;
- }
-}
-
-
-uint8_t dib_splat_sample(uint8_t val, unsigned bits)
-{
- assert(8U >= bits);
- for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1)
- val |= val >> bits;
- return val;
-}
-
bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
{
@@ -151,10 +80,10 @@ bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb3
if (9U >= dir.size)
return false;
fp.seek(dir.offset, SEEK_SET);
- png_error const err(png_read_bitmap(fp, bitmap));
+ util::png_error const err(util::png_read_bitmap(fp, bitmap));
switch (err)
{
- case PNGERR_NONE:
+ case util::png_error::NONE:
// found valid PNG image
assert(bitmap.valid());
if ((dir.get_width() == bitmap.width()) && ((dir.get_height() == bitmap.height())))
@@ -172,7 +101,7 @@ bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb3
}
return true;
- case PNGERR_BAD_SIGNATURE:
+ case util::png_error::BAD_SIGNATURE:
// doesn't look like PNG data - just fall back to DIB without the file header
return false;
@@ -190,426 +119,37 @@ bool load_ico_png(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb3
bool load_ico_dib(util::core_file &fp, icon_dir_entry_t const &dir, bitmap_argb32 &bitmap)
{
- // check that these things haven't been padded somehow
- static_assert(sizeof(bitmap_core_header_t) == 12U, "compiler has applied padding to bitmap_core_header_t");
- static_assert(sizeof(bitmap_info_header_t) == 56U, "compiler has applied padding to bitmap_info_header_t");
-
- // ensure the header fits in the space for the image data
- union { bitmap_core_header_t core; bitmap_info_header_t info; } header;
- assert(&header.core.size == &header.info.size);
- if (sizeof(header.core) > dir.size)
- return false;
- std::memset(&header, 0, sizeof(header));
fp.seek(dir.offset, SEEK_SET);
- if (fp.read(&header.core.size, sizeof(header.core.size)) != sizeof(header.core.size))
- {
- LOG(
- "Error reading DIB header size from ICO file at offset %u (directory size %u)\n",
- dir.offset,
- dir.size);
- return false;
- }
- header.core.size = little_endianize_int32(header.core.size);
- if (dir.size < header.core.size)
- {
- LOG(
- "ICO file image data at %u (%u bytes) is too small for DIB header (%u bytes)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
- }
-
- // identify and read the header - convert OS/2 headers to Windows 3 format
- unsigned palette_bytes(4U);
- switch (header.core.size)
+ util::msdib_error const err(util::msdib_read_bitmap_data(fp, bitmap, dir.size, dir.get_height()));
+ switch (err)
{
- case 16U:
- case 64U:
- // extended OS/2 bitmap header with support for compression
- LOG(
- "ICO image data at %u (%u bytes) uses unsupported OS/2 DIB header (size %u)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
-
- case 12U:
- // introduced in OS/2 and Windows 2.0
+ case util::msdib_error::NONE:
+ // found valid DIB image
+ assert(bitmap.valid());
+ if ((dir.get_width() == bitmap.width()) && ((dir.get_height() == bitmap.height())))
{
- palette_bytes = 3U;
- uint32_t const header_read(std::min<uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size));
- if (fp.read(&header.core.width, header_read) != header_read)
- {
- LOG("Error reading DIB core header from ICO file image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR);
- header.core.width = little_endianize_int16(header.core.width);
- header.core.height = little_endianize_int16(header.core.height);
- header.core.planes = little_endianize_int16(header.core.planes);
- header.core.bpp = little_endianize_int16(header.core.bpp);
- LOGMASKED(
- LOG_DIB,
- "Read DIB core header from ICO file image data at %u: %d*%d, %u planes, %u bpp\n",
- dir.offset,
- header.core.width,
- header.core.height,
- header.core.planes,
- header.core.bpp);
-
- // this works because the core header only aliases the width/height of the info header
- header.info.bpp = header.core.bpp;
- header.info.planes = header.core.planes;
- header.info.height = header.core.height;
- header.info.width = header.core.width;
- header.info.size = 40U;
+ LOG("Loaded %d*%d pixel DIB image from ICO file\n", bitmap.width(), bitmap.height());
}
- break;
-
- default:
- // the next version will be longer
- if (124U >= header.core.size)
+ else
{
LOG(
- "ICO image data at %u (%u bytes) uses unsupported DIB header format (size %u)\n",
- dir.offset,
- dir.size,
- header.core.size);
- return false;
- }
- // fall through
- case 40U:
- case 52U:
- case 56U:
- case 108U:
- case 124U:
- // the Windows 3 bitmap header with optional extensions
- {
- palette_bytes = 4U;
- uint32_t const header_read(std::min<uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size));
- if (fp.read(&header.info.width, header_read) != header_read)
- {
- LOG("Error reading DIB info header from ICO file image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR);
- header.info.width = little_endianize_int32(header.info.width);
- header.info.height = little_endianize_int32(header.info.height);
- header.info.planes = little_endianize_int16(header.info.planes);
- header.info.bpp = little_endianize_int16(header.info.bpp);
- header.info.comp = little_endianize_int32(header.info.comp);
- header.info.rawsize = little_endianize_int32(header.info.rawsize);
- header.info.hres = little_endianize_int32(header.info.hres);
- header.info.vres = little_endianize_int32(header.info.vres);
- header.info.colors = little_endianize_int32(header.info.colors);
- header.info.important = little_endianize_int32(header.info.important);
- header.info.red = little_endianize_int32(header.info.red);
- header.info.green = little_endianize_int32(header.info.green);
- header.info.blue = little_endianize_int32(header.info.blue);
- header.info.alpha = little_endianize_int32(header.info.alpha);
- LOGMASKED(
- LOG_DIB,
- "Read DIB info header from ICO file image data at %u: %d*%d (%d*%d ppm), %u planes, %u bpp %u/%s%u colors\n",
- dir.offset,
- header.info.width,
- header.info.height,
- header.info.hres,
- header.info.vres,
- header.info.planes,
- header.info.bpp,
- header.info.important,
- header.info.colors ? "" : "2^",
- header.info.colors ? header.info.colors : header.info.bpp);
- }
- break;
- }
-
- // check for unsupported planes/bit depth
- if ((1U != header.info.planes) || !header.info.bpp || (32U < header.info.bpp) || ((8U < header.info.bpp) ? (header.info.bpp % 8) : (8 % header.info.bpp)))
- {
- LOG(
- "ICO file DIB image data at %u uses unsupported planes/bits per pixel %u*%u\n",
- dir.offset,
- header.info.planes,
- header.info.bpp);
- return false;
- }
-
- // check dimensions
- if ((0 >= header.info.width) || (0 == header.info.height))
- {
- LOG(
- "ICO file DIB image data at %u has invalid dimensions %u*%u\n",
- dir.offset,
- header.info.width,
- header.info.height);
- return false;
- }
- bool const top_down(0 > header.info.height);
- if (top_down)
- header.info.height = -header.info.height;
- bool have_and_mask((2 * dir.get_height()) == header.info.height);
- if (!have_and_mask && (dir.get_height() != header.info.height))
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu height %ld doesn't match directory height %u with or without AND mask\n",
- (unsigned long)dir.offset,
- (long)header.info.height,
- dir.get_height());
- return false;
- }
- if (have_and_mask)
- header.info.height >>= 1;
-
- // ensure compression scheme is supported
- bool indexed(true), no_palette(false);
- switch (header.info.comp)
- {
- case DIB_COMP_NONE:
- // uncompressed - direct colour with implied bitfields if more than eight bits/pixel
- indexed = 8U >= header.info.bpp;
- if (indexed)
- {
- if ((1U << header.info.bpp) < header.info.colors)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu has oversized palette with %lu entries for %u bits per pixel\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.colors,
- (unsigned)header.info.bpp);
- }
- }
- if (!indexed)
- {
- no_palette = true;
- switch(header.info.bpp)
- {
- case 16U:
- header.info.red = 0x00007c00;
- header.info.green = 0x000003e0;
- header.info.blue = 0x0000001f;
- header.info.alpha = 0x00000000;
- break;
- case 24U:
- case 32U:
- header.info.red = 0x00ff0000;
- header.info.green = 0x0000ff00;
- header.info.blue = 0x000000ff;
- header.info.alpha = 0x00000000;
- break;
- }
- }
- break;
-
- case DIB_COMP_BITFIELDS:
- // uncompressed direct colour with explicitly-specified bitfields
- indexed = false;
- if (offsetof(bitmap_info_header_t, alpha) > header.info.size)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu specifies bit masks but is too small (size %lu)\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.size);
- return false;
+ "Loaded %d*%d pixel DIB image from ICO file (directory indicated %u*%u)\n",
+ bitmap.width(),
+ bitmap.height(),
+ dir.get_width(),
+ dir.get_height());
}
- break;
+ return true;
default:
- LOG("ICO file DIB image data at %u uses unsupported compression scheme %u\n", header.info.comp);
- return false;
- }
-
- // we can now calculate the size of the palette and row data
- size_t const palette_entries(
- indexed
- ? ((1U == header.info.bpp) ? 2U : header.info.colors ? header.info.colors : (1U << header.info.bpp))
- : (no_palette ? 0U : header.info.colors));
- size_t const palette_size(palette_bytes * palette_entries);
- size_t const row_bytes(((31 + (header.info.width * header.info.bpp)) >> 5) << 2);
- size_t const mask_row_bytes(((31 + header.info.width) >> 5) << 2);
- size_t const required_size(
- header.info.size +
- palette_size +
- ((row_bytes + (have_and_mask ? mask_row_bytes : 0U)) * header.info.height));
- if (required_size > dir.size)
- {
+ // invalid DIB data or I/O error
LOG(
- "ICO file image data at %u (%u bytes) smaller than calculated DIB data size (%u bytes)\n",
+ "Error %u reading DIB image data from ICO file at offset %u (directory size %u)\n",
+ unsigned(err),
dir.offset,
- dir.size,
- required_size);
+ dir.size);
return false;
}
-
- // load the palette for indexed colour formats or the shifts for direct colour formats
- unsigned red_shift(0), green_shift(0), blue_shift(0), alpha_shift(0);
- unsigned red_bits(0), green_bits(0), blue_bits(0), alpha_bits(0);
- std::unique_ptr<rgb_t []> palette;
- if (indexed)
- {
- // read palette and convert
- std::unique_ptr<uint8_t []> palette_data(new uint8_t [palette_size]);
- if (fp.read(palette_data.get(), palette_size) != palette_size)
- {
- LOG("Error reading palette from ICO file DIB image data at %u (%u bytes)\n", dir.offset, dir.size);
- return false;
- }
- size_t const palette_usable(std::min<size_t>(palette_entries, size_t(1) << header.info.bpp));
- palette.reset(new rgb_t [palette_usable]);
- uint8_t const *ptr(palette_data.get());
- for (size_t i = 0; palette_usable > i; ++i, ptr += palette_bytes)
- palette[i] = rgb_t(ptr[2], ptr[1], ptr[0]);
- }
- else
- {
- // skip over the palette if necessary
- if (palette_entries)
- fp.seek(palette_bytes * palette_entries, SEEK_CUR);
-
- // convert masks to shifts
- bool const masks_contiguous(
- dib_parse_mask(header.info.red, red_shift, red_bits) &&
- dib_parse_mask(header.info.green, green_shift, green_bits) &&
- dib_parse_mask(header.info.blue, blue_shift, blue_bits) &&
- dib_parse_mask(header.info.alpha, alpha_shift, alpha_bits));
- if (!masks_contiguous)
- {
- osd_printf_verbose(
- "ICO file DIB image data at %lu specifies non-contiguous channel masks 0x%lx | 0x%lx | 0x%lx | 0x%lx\n",
- (unsigned long)dir.offset,
- (unsigned long)header.info.red,
- (unsigned long)header.info.green,
- (unsigned long)header.info.blue,
- (unsigned long)header.info.alpha);
- }
- if ((32U != header.info.bpp) && ((header.info.red | header.info.green | header.info.blue | header.info.alpha) >> header.info.bpp))
- {
- LOG(
- "ICO file DIB image data at %lu specifies channel masks 0x%x | 0x%x | 0x%x | 0x%x that exceed %u bits per pixel\n",
- dir.offset,
- header.info.red,
- header.info.green,
- header.info.blue,
- header.info.alpha,
- header.info.bpp);
- return false;
- }
- LOGMASKED(
- LOG_DIB,
- "DIB from ICO file image data at %1$u using channels: R((x >> %3$u) & 0x%4$0*2$x) G((x >> %5$u) & 0x%6$0*2$x) B((x >> %7$u) & 0x%8$0*2$x) A((x >> %9$u) & 0x%10$0*2$x)\n",
- dir.offset,
- (header.info.bpp + 3) >> 2,
- red_shift,
- (uint32_t(1) << red_bits) - 1,
- green_shift,
- (uint32_t(1) << green_bits) - 1,
- blue_shift,
- (uint32_t(1) << blue_bits) - 1,
- alpha_shift,
- (uint32_t(1) << alpha_bits) - 1);
-
- // the MAME bitmap only supports 8 bits/sample maximum
- dib_truncate_channel(red_shift, red_bits);
- dib_truncate_channel(green_shift, green_bits);
- dib_truncate_channel(blue_shift, blue_bits);
- dib_truncate_channel(alpha_shift, alpha_bits);
- }
-
- // allocate the bitmap and process row data
- std::unique_ptr<uint8_t []> row_data(new uint8_t [row_bytes]);
- bitmap.allocate(header.info.width, header.info.height);
- int const y_inc(top_down ? 1 : -1);
- for (int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
- {
- if (fp.read(row_data.get(), row_bytes) != row_bytes)
- {
- LOG("Error reading DIB row %d data from ICO image data at %u\n", i, dir.offset);
- return false;
- }
- uint8_t *src(row_data.get());
- uint32_t *dest(&bitmap.pix(y));
- unsigned shift(0U);
- for (int32_t x = 0; header.info.width > x; ++x, ++dest)
- {
- // extract or compose a pixel
- uint32_t pix(0U);
- if (8U >= header.info.bpp)
- {
- assert(8U > shift);
- pix = *src >> (8U - header.info.bpp);
- *src <<= header.info.bpp;
- shift += header.info.bpp;
- if (8U <= shift)
- {
- shift = 0U;
- ++src;
- }
- }
- else for (shift = 0; header.info.bpp > shift; shift += 8U, ++src)
- {
- pix |= uint32_t(*src) << shift;
- }
-
- // convert to RGB
- if (indexed)
- {
- if (palette_entries > pix)
- {
- *dest = palette[pix];
- }
- else
- {
- *dest = rgb_t::transparent();
- osd_printf_verbose(
- "ICO file DIB image data at %lu has out-of-range color %lu at (%ld, %ld) with %lu palette entries\n",
- (unsigned long)dir.offset,
- (unsigned long)pix,
- (long)x,
- (long)y,
- (unsigned long)palette_entries);
- }
- }
- else
- {
- uint8_t r(dib_splat_sample((pix >> red_shift) & ((uint32_t(1) << red_bits) - 1), red_bits));
- uint8_t g(dib_splat_sample((pix >> green_shift) & ((uint32_t(1) << green_bits) - 1), green_bits));
- uint8_t b(dib_splat_sample((pix >> blue_shift) & ((uint32_t(1) << blue_bits) - 1), blue_bits));
- uint8_t a(dib_splat_sample((pix >> alpha_shift) & ((uint32_t(1) << alpha_bits) - 1), alpha_bits));
- *dest = rgb_t(alpha_bits ? a : 255, r, g, b);
- }
- }
- }
-
- // process the AND mask if present
- if (have_and_mask)
- {
- for (int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
- {
- if (fp.read(row_data.get(), mask_row_bytes) != mask_row_bytes)
- {
- LOG("Error reading DIB mask row %d data from ICO image data at %u\n", i, dir.offset);
- return false;
- }
- uint8_t *src(row_data.get());
- uint32_t *dest(&bitmap.pix(y));
- unsigned shift(0U);
- for (int32_t x = 0; header.info.width > x; ++x, ++dest)
- {
- assert(8U > shift);
- rgb_t pix(*dest);
- *dest = pix.set_a(BIT(*src, 7U - shift) ? 0U : pix.a());
- if (8U <= ++shift)
- {
- shift = 0U;
- ++src;
- }
- }
- }
- }
-
- // we're done!
- return true;
}
diff --git a/src/frontend/mame/ui/inputmap.cpp b/src/frontend/mame/ui/inputmap.cpp
index 33cbd9223e0..bfb68e40da0 100644
--- a/src/frontend/mame/ui/inputmap.cpp
+++ b/src/frontend/mame/ui/inputmap.cpp
@@ -93,7 +93,7 @@ void menu_input_general::populate(float &customtop, float &custombottom)
item.type = ioport_manager::type_is_analog(entry.type()) ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL;
item.is_optional = false;
item.name = entry.name();
- item.owner_name = nullptr;
+ item.owner = nullptr;
// stop after one, unless we're analog
if (item.type == INPUT_TYPE_DIGITAL)
@@ -164,7 +164,7 @@ void menu_input_specific::populate(float &customtop, float &custombottom)
item.type = field.is_analog() ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL;
item.is_optional = field.optional();
item.name = field.name();
- item.owner_name = field.device().tag();
+ item.owner = &field.device();
// stop after one, unless we're analog
if (item.type == INPUT_TYPE_DIGITAL)
@@ -180,7 +180,7 @@ void menu_input_specific::populate(float &customtop, float &custombottom)
data.end(),
[] (const input_item_data &i1, const input_item_data &i2)
{
- int cmp = strcmp(i1.owner_name, i2.owner_name);
+ int cmp = strcmp(i1.owner->tag(), i2.owner->tag());
if (cmp < 0)
return true;
if (cmp > 0)
@@ -431,21 +431,24 @@ void menu_input::populate_sorted(float &customtop, float &custombottom)
// build the menu
std::string text, subtext;
- std::string prev_owner;
+ const device_t *prev_owner = nullptr;
bool first_entry = true;
for (input_item_data &item : data)
{
// generate the name of the item itself, based off the base name and the type
assert(nameformat[item.type] != nullptr);
- if (item.owner_name && strcmp(item.owner_name, prev_owner.c_str()) != 0)
+ if (item.owner && (item.owner != prev_owner))
{
if (first_entry)
first_entry = false;
else
item_append(menu_item_type::SEPARATOR);
- item_append(string_format("[root%s]", item.owner_name), "", 0, nullptr);
- prev_owner.assign(item.owner_name);
+ if (item.owner->owner())
+ item_append(string_format(_("%1$s [root%2$s]"), item.owner->type().fullname(), item.owner->tag()), "", 0, nullptr);
+ else
+ item_append(string_format(_("[root%1$s]"), item.owner->tag()), "", 0, nullptr);
+ prev_owner = item.owner;
}
text = string_format(nameformat[item.type], item.name);
diff --git a/src/frontend/mame/ui/inputmap.h b/src/frontend/mame/ui/inputmap.h
index d2e41780211..01649b0b1ef 100644
--- a/src/frontend/mame/ui/inputmap.h
+++ b/src/frontend/mame/ui/inputmap.h
@@ -55,7 +55,7 @@ protected:
input_seq seq; // copy of the live sequence
const input_seq * defseq = nullptr; // pointer to the default sequence
const char * name = nullptr; // pointer to the base name of the item
- const char * owner_name = nullptr; // pointer to the name of the owner of the item
+ const device_t * owner = nullptr; // pointer to the owner of the item
ioport_group group = IPG_INVALID; // group type
uint8_t type = 0U; // type of port
bool is_optional = false; // true if this input is considered optional
diff --git a/src/frontend/mame/ui/keyboard.cpp b/src/frontend/mame/ui/keyboard.cpp
new file mode 100644
index 00000000000..3d58d28d2d9
--- /dev/null
+++ b/src/frontend/mame/ui/keyboard.cpp
@@ -0,0 +1,98 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ui/keyboard.cpp
+
+ Keyboard mode menu.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ui/keyboard.h"
+
+#include "natkeyboard.h"
+
+
+namespace ui {
+
+namespace {
+
+constexpr uintptr_t ITEM_KBMODE = 0x00000100;
+constexpr uintptr_t ITEM_KBDEV_FIRST = 0x00000200;
+
+} // anonymous namespace
+
+
+menu_keyboard_mode::menu_keyboard_mode(mame_ui_manager &mui, render_container &container) : menu(mui, container)
+{
+}
+
+void menu_keyboard_mode::populate(float &customtop, float &custombottom)
+{
+ natural_keyboard &natkbd(machine().ioport().natkeyboard());
+
+ if (natkbd.can_post())
+ {
+ bool const natmode(natkbd.in_use());
+ item_append(
+ _("Keyboard Mode"),
+ natmode ? _("Natural") : _("Emulated"),
+ natmode ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW,
+ reinterpret_cast<void *>(ITEM_KBMODE));
+ item_append(menu_item_type::SEPARATOR);
+ }
+
+ uintptr_t ref(ITEM_KBDEV_FIRST);
+ for (size_t i = 0; natkbd.keyboard_count() > i; ++i, ++ref)
+ {
+ device_t &kbddev(natkbd.keyboard_device(i));
+ bool const enabled(natkbd.keyboard_enabled(i));
+ item_append(
+ util::string_format(
+ kbddev.owner() ? _("%1$s [root%2$s]") : _("[root%2$s]"),
+ kbddev.type().fullname(),
+ kbddev.tag()),
+ enabled ? _("Enabled") : _("Disabled"),
+ enabled ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW,
+ reinterpret_cast<void *>(ref));
+ }
+ item_append(menu_item_type::SEPARATOR);
+}
+
+menu_keyboard_mode::~menu_keyboard_mode()
+{
+}
+
+void menu_keyboard_mode::handle()
+{
+ event const *const menu_event(process(0));
+ if (menu_event && uintptr_t(menu_event->itemref))
+ {
+ natural_keyboard &natkbd(machine().ioport().natkeyboard());
+ uintptr_t const ref(uintptr_t(menu_event->itemref));
+ bool const left(IPT_UI_LEFT == menu_event->iptkey);
+ bool const right(IPT_UI_RIGHT == menu_event->iptkey);
+ if (ITEM_KBMODE == ref)
+ {
+ if ((left || right) && (natkbd.in_use() != right))
+ {
+ natkbd.set_in_use(right);
+ reset(reset_options::REMEMBER_REF);
+ }
+ }
+ else if (ITEM_KBDEV_FIRST <= ref)
+ {
+ if ((left || right) && (natkbd.keyboard_enabled(ref - ITEM_KBDEV_FIRST) != right))
+ {
+ if (right)
+ natkbd.enable_keyboard(ref - ITEM_KBDEV_FIRST);
+ else
+ natkbd.disable_keyboard(ref - ITEM_KBDEV_FIRST);
+ reset(reset_options::REMEMBER_REF);
+ }
+ }
+ }
+}
+
+} // namespace ui
diff --git a/src/frontend/mame/ui/keyboard.h b/src/frontend/mame/ui/keyboard.h
new file mode 100644
index 00000000000..899385e74c2
--- /dev/null
+++ b/src/frontend/mame/ui/keyboard.h
@@ -0,0 +1,33 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ui/keyboard.h
+
+ Keyboard mode menu.
+
+***************************************************************************/
+#ifndef MAME_FRONTEND_UI_KEYBOARD_H
+#define MAME_FRONTEND_UI_KEYBOARD_H
+
+#pragma once
+
+#include "ui/menu.h"
+
+
+namespace ui {
+
+class menu_keyboard_mode : public menu
+{
+public:
+ menu_keyboard_mode(mame_ui_manager &mui, render_container &container);
+ virtual ~menu_keyboard_mode();
+
+private:
+ virtual void populate(float &customtop, float &custombottom) override;
+ virtual void handle() override;
+};
+
+} // namespace ui
+
+#endif // MAME_FRONTEND_UI_KEYBOARD_H
diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp
index bd7f274da29..b1a0e238935 100644
--- a/src/frontend/mame/ui/mainmenu.cpp
+++ b/src/frontend/mame/ui/mainmenu.cpp
@@ -22,6 +22,7 @@
#include "ui/info_pty.h"
#include "ui/inifile.h"
#include "ui/inputmap.h"
+#include "ui/keyboard.h"
#include "ui/miscmenu.h"
#include "ui/pluginopt.h"
#include "ui/selgame.h"
@@ -108,7 +109,7 @@ void menu_main::populate(float &customtop, float &custombottom)
if (network_interface_iterator(machine().root_device()).first() != nullptr)
item_append(_("Network Devices"), "", 0, (void*)NETWORK_DEVICES);
- if (ui().machine_info().has_keyboard() && machine().ioport().natkeyboard().can_post())
+ if (machine().ioport().natkeyboard().keyboard_count())
item_append(_("Keyboard Mode"), "", 0, (void *)KEYBOARD_MODE);
item_append(_("Slider Controls"), "", 0, (void *)SLIDERS);
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index 7ce0beb0fb1..b0a84d3a95c 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -92,10 +92,17 @@ menu::global_state::global_state(running_machine &machine, ui_options const &opt
{
m_bgrnd_bitmap = std::make_unique<bitmap_argb32>(0, 0);
emu_file backgroundfile(".", OPEN_FLAG_READ);
- render_load_jpeg(*m_bgrnd_bitmap, backgroundfile, nullptr, "background.jpg");
+ if (backgroundfile.open("background.jpg") == osd_file::error::NONE)
+ {
+ render_load_jpeg(*m_bgrnd_bitmap, backgroundfile);
+ backgroundfile.close();
+ }
- if (!m_bgrnd_bitmap->valid())
- render_load_png(*m_bgrnd_bitmap, backgroundfile, nullptr, "background.png");
+ if (!m_bgrnd_bitmap->valid() && (backgroundfile.open("background.png") == osd_file::error::NONE))
+ {
+ render_load_png(*m_bgrnd_bitmap, backgroundfile);
+ backgroundfile.close();
+ }
if (m_bgrnd_bitmap->valid())
m_bgrnd_texture->set_bitmap(*m_bgrnd_bitmap, m_bgrnd_bitmap->cliprect(), TEXFORMAT_ARGB32);
@@ -904,110 +911,110 @@ void menu::handle_events(uint32_t flags, event &ev)
{
switch (local_menu_event.event_type)
{
- // if we are hovering over a valid item, select it with a single click
- case ui_event::MOUSE_DOWN:
- if (custom_mouse_down())
- return;
+ // if we are hovering over a valid item, select it with a single click
+ case ui_event::type::MOUSE_DOWN:
+ if (custom_mouse_down())
+ return;
- if ((flags & PROCESS_ONLYCHAR) == 0)
+ if ((flags & PROCESS_ONLYCHAR) == 0)
+ {
+ if (m_hover >= 0 && m_hover < m_items.size())
+ m_selected = m_hover;
+ else if (m_hover == HOVER_ARROW_UP)
{
- if (m_hover >= 0 && m_hover < m_items.size())
- m_selected = m_hover;
- else if (m_hover == HOVER_ARROW_UP)
+ if ((flags & FLAG_UI_DATS) != 0)
{
- if ((flags & FLAG_UI_DATS) != 0)
- {
- top_line -= m_visible_items - (last_item_visible() ? 1 : 0);
- return;
- }
- m_selected -= m_visible_items;
- if (m_selected < 0)
- m_selected = 0;
top_line -= m_visible_items - (last_item_visible() ? 1 : 0);
+ return;
}
- else if (m_hover == HOVER_ARROW_DOWN)
+ m_selected -= m_visible_items;
+ if (m_selected < 0)
+ m_selected = 0;
+ top_line -= m_visible_items - (last_item_visible() ? 1 : 0);
+ }
+ else if (m_hover == HOVER_ARROW_DOWN)
+ {
+ if ((flags & FLAG_UI_DATS) != 0)
{
- if ((flags & FLAG_UI_DATS) != 0)
- {
- top_line += m_visible_lines - 2;
- return;
- }
- m_selected += m_visible_lines - 2 + is_first_selected();
- if (m_selected > m_items.size() - 1)
- m_selected = m_items.size() - 1;
top_line += m_visible_lines - 2;
+ return;
}
+ m_selected += m_visible_lines - 2 + is_first_selected();
+ if (m_selected > m_items.size() - 1)
+ m_selected = m_items.size() - 1;
+ top_line += m_visible_lines - 2;
}
- break;
+ }
+ break;
- // if we are hovering over a valid item, fake a UI_SELECT with a double-click
- case ui_event::MOUSE_DOUBLE_CLICK:
- if (!(flags & PROCESS_ONLYCHAR) && m_hover >= 0 && m_hover < m_items.size())
+ // if we are hovering over a valid item, fake a UI_SELECT with a double-click
+ case ui_event::type::MOUSE_DOUBLE_CLICK:
+ if (!(flags & PROCESS_ONLYCHAR) && m_hover >= 0 && m_hover < m_items.size())
+ {
+ m_selected = m_hover;
+ ev.iptkey = IPT_UI_SELECT;
+ if (is_last_selected())
{
- m_selected = m_hover;
- ev.iptkey = IPT_UI_SELECT;
- if (is_last_selected())
+ ev.iptkey = IPT_UI_CANCEL;
+ stack_pop();
+ }
+ stop = true;
+ }
+ break;
+
+ // caught scroll event
+ case ui_event::type::MOUSE_WHEEL:
+ if (!(flags & PROCESS_ONLYCHAR))
+ {
+ if (local_menu_event.zdelta > 0)
+ {
+ if ((flags & FLAG_UI_DATS) != 0)
{
- ev.iptkey = IPT_UI_CANCEL;
- stack_pop();
+ top_line -= local_menu_event.num_lines;
+ return;
}
- stop = true;
+ if (is_first_selected())
+ select_last_item();
+ else
+ {
+ m_selected -= local_menu_event.num_lines;
+ validate_selection(-1);
+ }
+ top_line -= (m_selected <= top_line && top_line != 0);
+ if (m_selected <= top_line && m_visible_items != m_visible_lines)
+ top_line -= local_menu_event.num_lines;
}
- break;
-
- // caught scroll event
- case ui_event::MOUSE_WHEEL:
- if (!(flags & PROCESS_ONLYCHAR))
+ else
{
- if (local_menu_event.zdelta > 0)
+ if ((flags & FLAG_UI_DATS))
{
- if ((flags & FLAG_UI_DATS) != 0)
- {
- top_line -= local_menu_event.num_lines;
- return;
- }
- if (is_first_selected())
- select_last_item();
- else
- {
- m_selected -= local_menu_event.num_lines;
- validate_selection(-1);
- }
- top_line -= (m_selected <= top_line && top_line != 0);
- if (m_selected <= top_line && m_visible_items != m_visible_lines)
- top_line -= local_menu_event.num_lines;
+ top_line += local_menu_event.num_lines;
+ return;
}
+ if (is_last_selected())
+ select_first_item();
else
{
- if ((flags & FLAG_UI_DATS))
- {
- top_line += local_menu_event.num_lines;
- return;
- }
- if (is_last_selected())
- select_first_item();
- else
- {
- m_selected += local_menu_event.num_lines;
- validate_selection(1);
- }
- top_line += (m_selected >= top_line + m_visible_items + (top_line != 0));
- if (m_selected >= (top_line + m_visible_items + (top_line != 0)))
- top_line += local_menu_event.num_lines;
+ m_selected += local_menu_event.num_lines;
+ validate_selection(1);
}
+ top_line += (m_selected >= top_line + m_visible_items + (top_line != 0));
+ if (m_selected >= (top_line + m_visible_items + (top_line != 0)))
+ top_line += local_menu_event.num_lines;
}
- break;
+ }
+ break;
- // translate CHAR events into specials
- case ui_event::IME_CHAR:
- ev.iptkey = IPT_SPECIAL;
- ev.unichar = local_menu_event.ch;
- stop = true;
- break;
+ // translate CHAR events into specials
+ case ui_event::type::IME_CHAR:
+ ev.iptkey = IPT_SPECIAL;
+ ev.unichar = local_menu_event.ch;
+ stop = true;
+ break;
- // ignore everything else
- default:
- break;
+ // ignore everything else
+ default:
+ break;
}
}
}
@@ -1234,7 +1241,7 @@ uint32_t menu::ui_handler(render_container &container, mame_ui_manager &mui)
// if we have no menus stacked up, start with the main menu
if (!state->topmost_menu<menu>())
- state->stack_push(std::unique_ptr<menu>(global_alloc_clear<menu_main>(mui, container)));
+ state->stack_push(std::unique_ptr<menu>(make_unique_clear<menu_main>(mui, container)));
// update the menu state
if (state->topmost_menu<menu>())
diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h
index 800b0b6ca7b..5a7d4374bf6 100644
--- a/src/frontend/mame/ui/menu.h
+++ b/src/frontend/mame/ui/menu.h
@@ -100,12 +100,12 @@ public:
template <typename T, typename... Params>
static void stack_push(Params &&... args)
{
- stack_push(std::unique_ptr<menu>(global_alloc_clear<T>(std::forward<Params>(args)...)));
+ stack_push(std::unique_ptr<menu>(make_unique_clear<T>(std::forward<Params>(args)...)));
}
template <typename T, typename... Params>
static void stack_push_special_main(Params &&... args)
{
- std::unique_ptr<menu> ptr(global_alloc_clear<T>(std::forward<Params>(args)...));
+ std::unique_ptr<menu> ptr(make_unique_clear<T>(std::forward<Params>(args)...));
ptr->set_special_main_menu(true);
stack_push(std::move(ptr));
}
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index 82b7916e3a5..f0ab531360e 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -23,7 +23,6 @@
#include "mameopts.h"
#include "pluginopts.h"
#include "drivenum.h"
-#include "natkeyboard.h"
#include "romload.h"
#include "uiinput.h"
@@ -41,42 +40,6 @@ namespace ui {
***************************************************************************/
/*-------------------------------------------------
- menu_keyboard_mode - menu that
--------------------------------------------------*/
-
-menu_keyboard_mode::menu_keyboard_mode(mame_ui_manager &mui, render_container &container) : menu(mui, container)
-{
-}
-
-void menu_keyboard_mode::populate(float &customtop, float &custombottom)
-{
- bool natural = machine().ioport().natkeyboard().in_use();
- item_append(_("Keyboard Mode:"), natural ? _("Natural") : _("Emulated"), natural ? FLAG_LEFT_ARROW : FLAG_RIGHT_ARROW, nullptr);
-}
-
-menu_keyboard_mode::~menu_keyboard_mode()
-{
-}
-
-void menu_keyboard_mode::handle()
-{
- bool natural = machine().ioport().natkeyboard().in_use();
-
- /* process the menu */
- const event *menu_event = process(0);
-
- if (menu_event != nullptr)
- {
- if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
- {
- machine().ioport().natkeyboard().set_in_use(!natural);
- reset(reset_options::REMEMBER_REF);
- }
- }
-}
-
-
-/*-------------------------------------------------
menu_bios_selection - populates the main
bios selection menu
-------------------------------------------------*/
diff --git a/src/frontend/mame/ui/miscmenu.h b/src/frontend/mame/ui/miscmenu.h
index acff544dee6..c8d833ae4e2 100644
--- a/src/frontend/mame/ui/miscmenu.h
+++ b/src/frontend/mame/ui/miscmenu.h
@@ -7,7 +7,6 @@
Internal MAME menus for the user interface.
***************************************************************************/
-
#ifndef MAME_FRONTEND_UI_MISCMENU_H
#define MAME_FRONTEND_UI_MISCMENU_H
@@ -24,17 +23,6 @@
namespace ui {
-class menu_keyboard_mode : public menu
-{
-public:
- menu_keyboard_mode(mame_ui_manager &mui, render_container &container);
- virtual ~menu_keyboard_mode();
-
-private:
- virtual void populate(float &customtop, float &custombottom) override;
- virtual void handle() override;
-};
-
class menu_network_devices : public menu
{
public:
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index 6944031e344..13a63965f65 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -786,32 +786,33 @@ void menu_select_game::inkey_select(const event *menu_event)
else
{
// anything else is a driver
-
- // audit the game first to see if we're going to work
driver_enumerator enumerator(machine().options(), *driver);
enumerator.next();
+
+ // if there are software entries, show a software selection menu
+ for (software_list_device &swlistdev : software_list_device_iterator(enumerator.config()->root_device()))
+ {
+ if (!swlistdev.get_info().empty())
+ {
+ menu::stack_push<menu_select_software>(ui(), container(), *driver);
+ return;
+ }
+ }
+
+ // audit the system ROMs first to see if we're going to work
media_auditor auditor(enumerator);
media_auditor::summary const summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
// if everything looks good, schedule the new driver
if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
{
- for (software_list_device &swlistdev : software_list_device_iterator(enumerator.config()->root_device()))
- {
- if (!swlistdev.get_info().empty())
- {
- menu::stack_push<menu_select_software>(ui(), container(), *driver);
- return;
- }
- }
-
if (!select_bios(*driver, false))
launch_system(*driver);
}
else
{
// otherwise, display an error
- set_error(reset_options::REMEMBER_REF, make_error_text(media_auditor::NOTFOUND != summary, auditor));
+ set_error(reset_options::REMEMBER_REF, make_audit_fail_text(media_auditor::NOTFOUND != summary, auditor));
}
}
}
@@ -858,23 +859,25 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
}
else if (ui_swinfo->startempty == 1)
{
- // audit the game first to see if we're going to work
driver_enumerator enumerator(machine().options(), *ui_swinfo->driver);
enumerator.next();
- media_auditor auditor(enumerator);
- media_auditor::summary const summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
- if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
+ // if there are software entries, show a software selection menu
+ for (software_list_device &swlistdev : software_list_device_iterator(enumerator.config()->root_device()))
{
- for (software_list_device &swlistdev : software_list_device_iterator(enumerator.config()->root_device()))
+ if (!swlistdev.get_info().empty())
{
- if (!swlistdev.get_info().empty())
- {
- menu::stack_push<menu_select_software>(ui(), container(), *ui_swinfo->driver);
- return;
- }
+ menu::stack_push<menu_select_software>(ui(), container(), *ui_swinfo->driver);
+ return;
}
+ }
+
+ // audit the system ROMs first to see if we're going to work
+ media_auditor auditor(enumerator);
+ media_auditor::summary const summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
+ if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
+ {
// if everything looks good, schedule the new driver
if (!select_bios(*ui_swinfo->driver, false))
{
@@ -885,7 +888,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
else
{
// otherwise, display an error
- set_error(reset_options::REMEMBER_REF, make_error_text(media_auditor::NOTFOUND != summary, auditor));
+ set_error(reset_options::REMEMBER_REF, make_audit_fail_text(media_auditor::NOTFOUND != summary, auditor));
}
}
else
@@ -907,7 +910,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event)
else
{
// otherwise, display an error
- set_error(reset_options::REMEMBER_POSITION, make_error_text(media_auditor::NOTFOUND != summary, auditor));
+ set_error(reset_options::REMEMBER_POSITION, make_audit_fail_text(media_auditor::NOTFOUND != summary, auditor));
}
}
}
@@ -1455,18 +1458,4 @@ void menu_select_game::filter_selected()
}
}
-
-std::string menu_select_game::make_error_text(bool summary, media_auditor const &auditor)
-{
- std::ostringstream str;
- str << _("The selected machine is missing one or more required ROM or CHD images. Please select a different machine.\n\n");
- if (summary)
- {
- auditor.summarize(nullptr, &str);
- str << "\n";
- }
- str << _("Press any key to continue.");
- return str.str();
-}
-
} // namespace ui
diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h
index da65fee98ce..13bfd1170ac 100644
--- a/src/frontend/mame/ui/selgame.h
+++ b/src/frontend/mame/ui/selgame.h
@@ -18,8 +18,6 @@
#include <functional>
-class media_auditor;
-
namespace ui {
class menu_select_game : public menu_select_launch
@@ -86,8 +84,6 @@ private:
bool load_available_machines();
void load_custom_filters();
- static std::string make_error_text(bool summary, media_auditor const &auditor);
-
// General info
virtual void general_info(const game_driver *driver, std::string &buffer) override;
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index 92bdd3ada64..9a58691b988 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -20,6 +20,7 @@
#include "ui/starimg.ipp"
#include "ui/toolbar.ipp"
+#include "audit.h"
#include "cheat.h"
#include "mame.h"
#include "mameopts.h"
@@ -94,6 +95,62 @@ char const *const hover_msg[] = {
__("Show DATs view"),
};
+
+void load_image(bitmap_argb32 &bitmap, emu_file &file, std::string const &base)
+{
+ if (file.open(base + ".png") == osd_file::error::NONE)
+ {
+ render_load_png(bitmap, file);
+ file.close();
+ }
+
+ if (!bitmap.valid() && (file.open(base + ".jpg") == osd_file::error::NONE))
+ {
+ render_load_jpeg(bitmap, file);
+ file.close();
+ }
+
+ if (!bitmap.valid() && (file.open(base + ".bmp") == osd_file::error::NONE))
+ {
+ render_load_msdib(bitmap, file);
+ file.close();
+ }
+}
+
+
+void load_driver_image(bitmap_argb32 &bitmap, emu_file &file, game_driver const &driver)
+{
+ // try to load snapshot first from saved "0000.png" file
+ std::string fullname = driver.name;
+ load_image(bitmap, file, fullname + PATH_SEPARATOR + "0000");
+
+ // if fail, attempt to load from standard file
+ if (!bitmap.valid())
+ load_image(bitmap, file, fullname);
+
+ // if fail again, attempt to load from parent file
+ if (!bitmap.valid())
+ {
+ // ignore BIOS sets
+ bool isclone = strcmp(driver.parent, "0") != 0;
+ if (isclone)
+ {
+ int const cx = driver_list::find(driver.parent);
+ if ((0 <= cx) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
+ isclone = false;
+ }
+
+ if (isclone)
+ {
+ fullname = driver.parent;
+ load_image(bitmap, file, fullname + PATH_SEPARATOR + "0000");
+
+ if (!bitmap.valid())
+ load_image(bitmap, file, fullname);
+ }
+ }
+}
+
} // anonymous namespace
constexpr std::size_t menu_select_launch::MAX_VISIBLE_SEARCH; // stupid non-inline semantics
@@ -392,9 +449,9 @@ menu_select_launch::cache::cache(running_machine &machine)
// create a texture for snapshot
m_snapx_texture.reset(render.texture_alloc(render_texture::hq_scale));
- std::memcpy(&m_no_avail_bitmap.pix32(0), no_avail_bmp, 256 * 256 * sizeof(uint32_t));
+ std::memcpy(&m_no_avail_bitmap.pix(0), no_avail_bmp, 256 * 256 * sizeof(uint32_t));
- std::memcpy(&m_star_bitmap.pix32(0), favorite_star_bmp, 32 * 32 * sizeof(uint32_t));
+ std::memcpy(&m_star_bitmap.pix(0), favorite_star_bmp, 32 * 32 * sizeof(uint32_t));
m_star_texture.reset(render.texture_alloc());
m_star_texture->set_bitmap(m_star_bitmap, m_star_bitmap.cliprect(), TEXFORMAT_ARGB32);
@@ -410,7 +467,7 @@ menu_select_launch::cache::cache(running_machine &machine)
m_toolbar_texture.emplace_back(render.texture_alloc(), render);
m_sw_toolbar_texture.emplace_back(render.texture_alloc(), render);
- std::memcpy(&m_toolbar_bitmap.back().pix32(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
+ std::memcpy(&m_toolbar_bitmap.back().pix(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
if (m_toolbar_bitmap.back().valid())
m_toolbar_texture.back()->set_bitmap(m_toolbar_bitmap.back(), m_toolbar_bitmap.back().cliprect(), TEXFORMAT_ARGB32);
else
@@ -418,7 +475,7 @@ menu_select_launch::cache::cache(running_machine &machine)
if ((i == 0U) || (i == 2U))
{
- std::memcpy(&m_sw_toolbar_bitmap.back().pix32(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
+ std::memcpy(&m_sw_toolbar_bitmap.back().pix(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
if (m_sw_toolbar_bitmap.back().valid())
m_sw_toolbar_texture.back()->set_bitmap(m_sw_toolbar_bitmap.back(), m_sw_toolbar_bitmap.back().cliprect(), TEXFORMAT_ARGB32);
else
@@ -1147,7 +1204,7 @@ bool menu_select_launch::scale_icon(bitmap_argb32 &&src, texture_and_bitmap &dst
dst.bitmap.allocate(max_width, max_height);
for (int y = 0; tmp.height() > y; ++y)
for (int x = 0; tmp.width() > x; ++x)
- dst.bitmap.pix32(y, x) = tmp.pix32(y, x);
+ dst.bitmap.pix(y, x) = tmp.pix(y, x);
dst.texture->set_bitmap(dst.bitmap, dst.bitmap.cliprect(), TEXFORMAT_ARGB32);
return true;
}
@@ -1604,7 +1661,7 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
switch (local_menu_event.event_type)
{
// if we are hovering over a valid item, select it with a single click
- case ui_event::MOUSE_DOWN:
+ case ui_event::type::MOUSE_DOWN:
if (m_ui_error)
{
ev.iptkey = IPT_OTHER;
@@ -1704,7 +1761,7 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
break;
// if we are hovering over a valid item, fake a UI_SELECT with a double-click
- case ui_event::MOUSE_DOUBLE_CLICK:
+ case ui_event::type::MOUSE_DOUBLE_CLICK:
if (hover() >= 0 && hover() < item_count())
{
set_selected_index(hover());
@@ -1720,7 +1777,7 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
break;
// caught scroll event
- case ui_event::MOUSE_WHEEL:
+ case ui_event::type::MOUSE_WHEEL:
if (hover() >= 0 && hover() < item_count() - skip_main_items - 1)
{
if (local_menu_event.zdelta > 0)
@@ -1750,7 +1807,7 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
break;
// translate CHAR events into specials
- case ui_event::IME_CHAR:
+ case ui_event::type::IME_CHAR:
if (exclusive_input_pressed(ev.iptkey, IPT_UI_FOCUS_NEXT, 0) || exclusive_input_pressed(ev.iptkey, IPT_UI_FOCUS_PREV, 0))
{
stop = true;
@@ -1767,7 +1824,7 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
}
break;
- case ui_event::MOUSE_RDOWN:
+ case ui_event::type::MOUSE_RDOWN:
if (hover() >= 0 && hover() < item_count() - skip_main_items - 1)
{
set_selected_index(hover());
@@ -1790,18 +1847,18 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
{
switch (machine().ui_input().peek_event_type())
{
- case ui_event::MOUSE_DOWN:
- case ui_event::MOUSE_RDOWN:
- case ui_event::MOUSE_DOUBLE_CLICK:
- case ui_event::MOUSE_WHEEL:
+ case ui_event::type::MOUSE_DOWN:
+ case ui_event::type::MOUSE_RDOWN:
+ case ui_event::type::MOUSE_DOUBLE_CLICK:
+ case ui_event::type::MOUSE_WHEEL:
stop = true;
break;
- case ui_event::NONE:
- case ui_event::MOUSE_MOVE:
- case ui_event::MOUSE_LEAVE:
- case ui_event::MOUSE_UP:
- case ui_event::MOUSE_RUP:
- case ui_event::IME_CHAR:
+ case ui_event::type::NONE:
+ case ui_event::type::MOUSE_MOVE:
+ case ui_event::type::MOUSE_LEAVE:
+ case ui_event::type::MOUSE_UP:
+ case ui_event::type::MOUSE_RUP:
+ case ui_event::type::IME_CHAR:
break;
}
}
@@ -2225,41 +2282,16 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
if (software->startempty == 1)
{
// Load driver snapshot
- std::string fullname = std::string(software->driver->name) + ".png";
- render_load_png(tmp_bitmap, snapfile, nullptr, fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(software->driver->name).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, nullptr, fullname.c_str());
- }
+ load_driver_image(tmp_bitmap, snapfile, *software->driver);
}
else
{
// First attempt from name list
- std::string pathname = software->listname;
- std::string fullname = software->shortname + ".png";
- render_load_png(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
+ load_image(tmp_bitmap, snapfile, software->listname + PATH_SEPARATOR + software->shortname);
+ // Second attempt from driver name + part name
if (!tmp_bitmap.valid())
- {
- fullname.assign(software->shortname).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
- }
-
- if (!tmp_bitmap.valid())
- {
- // Second attempt from driver name + part name
- pathname.assign(software->driver->name).append(software->part);
- fullname.assign(software->shortname).append(".png");
- render_load_png(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(software->shortname).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, pathname.c_str(), fullname.c_str());
- }
- }
+ load_image(tmp_bitmap, snapfile, software->driver->name + software->part + PATH_SEPARATOR + software->shortname);
}
m_cache->set_snapx_software(software);
@@ -2284,51 +2316,7 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
{
emu_file snapfile(searchstr, OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
-
- // try to load snapshot first from saved "0000.png" file
- std::string fullname(driver->name);
- render_load_png(tmp_bitmap, snapfile, fullname.c_str(), "0000.png");
-
- if (!tmp_bitmap.valid())
- render_load_jpeg(tmp_bitmap, snapfile, fullname.c_str(), "0000.jpg");
-
- // if fail, attemp to load from standard file
- if (!tmp_bitmap.valid())
- {
- fullname.assign(driver->name).append(".png");
- render_load_png(tmp_bitmap, snapfile, nullptr, fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(driver->name).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, nullptr, fullname.c_str());
- }
- }
-
- // if fail again, attemp to load from parent file
- if (!tmp_bitmap.valid())
- {
- // set clone status
- bool cloneof = strcmp(driver->parent, "0");
- if (cloneof)
- {
- int cx = driver_list::find(driver->parent);
- if ((cx >= 0) && (driver_list::driver(cx).flags & machine_flags::IS_BIOS_ROOT))
- cloneof = false;
- }
-
- if (cloneof)
- {
- fullname.assign(driver->parent).append(".png");
- render_load_png(tmp_bitmap, snapfile, nullptr, fullname.c_str());
-
- if (!tmp_bitmap.valid())
- {
- fullname.assign(driver->parent).append(".jpg");
- render_load_jpeg(tmp_bitmap, snapfile, nullptr, fullname.c_str());
- }
- }
- }
+ load_driver_image(tmp_bitmap, snapfile, *driver);
m_cache->set_snapx_driver(driver);
m_switch_image = false;
@@ -2412,7 +2400,7 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
for (int x = 0; x < 256; x++)
{
for (int y = 0; y < 256; y++)
- tmp_bitmap.pix32(y, x) = src.pix32(y, x);
+ tmp_bitmap.pix(y, x) = src.pix(y, x);
}
no_available = true;
}
@@ -2475,7 +2463,7 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
for (int x = 0; x < dest_xPixel; x++)
for (int y = 0; y < dest_yPixel; y++)
- snapx_bitmap.pix32(y + y1, x + x1) = dest_bitmap.pix32(y, x);
+ snapx_bitmap.pix(y + y1, x + x1) = dest_bitmap.pix(y, x);
// apply bitmap
m_cache->snapx_texture()->set_bitmap(snapx_bitmap, snapx_bitmap.cliprect(), TEXFORMAT_ARGB32);
@@ -2508,6 +2496,20 @@ void menu_select_launch::draw_snapx(float origx1, float origy1, float origx2, fl
}
+std::string menu_select_launch::make_audit_fail_text(bool found, media_auditor const &auditor)
+{
+ std::ostringstream str;
+ str << _("The selected machine is missing one or more required ROM or CHD images. Please select a different machine.\n\n");
+ if (found)
+ {
+ auditor.summarize(nullptr, &str);
+ str << "\n";
+ }
+ str << _("Press any key to continue.");
+ return str.str();
+}
+
+
//-------------------------------------------------
// get bios count
//-------------------------------------------------
diff --git a/src/frontend/mame/ui/selmenu.h b/src/frontend/mame/ui/selmenu.h
index e3d532e9cc3..5a3bee798f7 100644
--- a/src/frontend/mame/ui/selmenu.h
+++ b/src/frontend/mame/ui/selmenu.h
@@ -20,6 +20,7 @@
#include <vector>
+class media_auditor;
struct ui_software_info;
namespace ui {
@@ -155,6 +156,8 @@ protected:
return (uintptr_t(selected_ref) > skip_main_items) ? selected_ref : m_prev_selected;
}
+ static std::string make_audit_fail_text(bool found, media_auditor const &auditor);
+
int m_available_items;
int skip_main_items;
void *m_prev_selected;
diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp
index 84fa109bea6..5a14e3dac7f 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -468,8 +468,17 @@ void menu_select_software::build_software_list()
void menu_select_software::inkey_select(const event *menu_event)
{
ui_software_info *ui_swinfo = (ui_software_info *)menu_event->itemref;
+ driver_enumerator drivlist(machine().options(), *ui_swinfo->driver);
+ media_auditor auditor(drivlist);
+ drivlist.next();
- if (ui_swinfo->startempty == 1)
+ // audit the system ROMs first to see if we're going to work
+ media_auditor::summary const sysaudit = auditor.audit_media(AUDIT_VALIDATE_FAST);
+ if (sysaudit != media_auditor::CORRECT && sysaudit != media_auditor::BEST_AVAILABLE && sysaudit != media_auditor::NONE_NEEDED)
+ {
+ set_error(reset_options::REMEMBER_REF, make_audit_fail_text(media_auditor::NOTFOUND != sysaudit, auditor));
+ }
+ else if (ui_swinfo->startempty == 1)
{
if (!select_bios(*ui_swinfo->driver, true))
{
@@ -479,16 +488,13 @@ void menu_select_software::inkey_select(const event *menu_event)
}
else
{
- // first validate
- driver_enumerator drivlist(machine().options(), *ui_swinfo->driver);
- media_auditor auditor(drivlist);
- drivlist.next();
+ // first audit the software
software_list_device *swlist = software_list_device::find_by_name(*drivlist.config(), ui_swinfo->listname);
const software_info *swinfo = swlist->find(ui_swinfo->shortname);
- media_auditor::summary const summary = auditor.audit_software(*swlist, *swinfo, AUDIT_VALIDATE_FAST);
+ media_auditor::summary const swaudit = auditor.audit_software(*swlist, *swinfo, AUDIT_VALIDATE_FAST);
- if (summary == media_auditor::CORRECT || summary == media_auditor::BEST_AVAILABLE || summary == media_auditor::NONE_NEEDED)
+ if (swaudit == media_auditor::CORRECT || swaudit == media_auditor::BEST_AVAILABLE || swaudit == media_auditor::NONE_NEEDED)
{
if (!select_bios(*ui_swinfo, false) && !select_part(*swinfo, *ui_swinfo))
{
@@ -500,11 +506,11 @@ void menu_select_software::inkey_select(const event *menu_event)
{
// otherwise, display an error
std::ostringstream str;
- str << _("The selected software is missing one or more required files. Please select a different software.\n\n");
- if (media_auditor::NOTFOUND != summary)
+ str << _("The selected software is missing one or more required files. Please select a different software item.\n\n");
+ if (media_auditor::NOTFOUND != swaudit)
{
auditor.summarize(nullptr, &str);
- str << "\n";
+ str << '\n';
}
str << _("Press any key to continue."),
set_error(reset_options::REMEMBER_POSITION, str.str());
diff --git a/src/frontend/mame/ui/slider.h b/src/frontend/mame/ui/slider.h
index 7785518d093..56da6849e81 100644
--- a/src/frontend/mame/ui/slider.h
+++ b/src/frontend/mame/ui/slider.h
@@ -25,12 +25,12 @@ typedef std::function<std::int32_t (running_machine &, void *, int, std::string
struct slider_state
{
slider_update update; // callback
- void * arg; // argument
- std::int32_t minval; // minimum value
- std::int32_t defval; // default value
- std::int32_t maxval; // maximum value
- std::int32_t incval; // increment value
- int id;
+ void * arg = nullptr; // argument
+ std::int32_t minval = 0; // minimum value
+ std::int32_t defval = 0; // default value
+ std::int32_t maxval = 0; // maximum value
+ std::int32_t incval = 0; // increment value
+ int id = 0;
std::string description; // textual description
};
diff --git a/src/frontend/mame/ui/text.cpp b/src/frontend/mame/ui/text.cpp
index 6df9ff29049..0e61b1710db 100644
--- a/src/frontend/mame/ui/text.cpp
+++ b/src/frontend/mame/ui/text.cpp
@@ -295,7 +295,7 @@ float text_layout::actual_height() const
void text_layout::start_new_line(text_layout::text_justify justify, float height)
{
// create a new line
- std::unique_ptr<line> new_line(global_alloc_clear<line>(*this, justify, actual_height(), height * yscale()));
+ std::unique_ptr<line> new_line(std::make_unique<line>(*this, justify, actual_height(), height * yscale()));
// update the current line
m_current_line = new_line.get();
@@ -303,7 +303,7 @@ void text_layout::start_new_line(text_layout::text_justify justify, float height
m_truncating = false;
// append it
- m_lines.push_back(std::move(new_line));
+ m_lines.emplace_back(std::move(new_line));
}
diff --git a/src/frontend/mame/ui/text.h b/src/frontend/mame/ui/text.h
index c5755c39813..fdf000c850a 100644
--- a/src/frontend/mame/ui/text.h
+++ b/src/frontend/mame/ui/text.h
@@ -7,16 +7,17 @@
Text functionality for MAME's crude user interface
***************************************************************************/
+#ifndef MAME_FRONTEND_UI_TEXT_H
+#define MAME_FRONTEND_UI_TEXT_H
#pragma once
-#ifndef MAME_FRONTEND_UI_TEXT_H
-#define MAME_FRONTEND_UI_TEXT_H
class render_font;
class render_container;
namespace ui {
+
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp
index ff16d117117..90efcb04b7c 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -164,7 +164,7 @@ static uint32_t const mouse_bitmap[32*32] =
mame_ui_manager::mame_ui_manager(running_machine &machine)
: ui_manager(machine)
- , m_font(nullptr)
+ , m_font()
, m_handler_callback(nullptr)
, m_handler_callback_type(ui_callback_type::GENERAL)
, m_handler_param(0)
@@ -216,7 +216,7 @@ void mame_ui_manager::init()
config_save_delegate(&mame_ui_manager::config_save, this));
// create mouse bitmap
- uint32_t *dst = &m_mouse_bitmap.pix32(0);
+ uint32_t *dst = &m_mouse_bitmap.pix(0);
memcpy(dst,mouse_bitmap,32*32*sizeof(uint32_t));
m_mouse_arrow_texture = machine().render().texture_alloc();
m_mouse_arrow_texture->set_bitmap(m_mouse_bitmap, m_mouse_bitmap.cliprect(), TEXFORMAT_ARGB32);
@@ -244,11 +244,7 @@ void mame_ui_manager::exit()
m_mouse_arrow_texture = nullptr;
// free the font
- if (m_font != nullptr)
- {
- machine().render().font_free(m_font);
- m_font = nullptr;
- }
+ m_font.reset();
}
@@ -640,9 +636,9 @@ void mame_ui_manager::update_and_render(render_container &container)
render_font *mame_ui_manager::get_font()
{
// allocate the font and messagebox string
- if (m_font == nullptr)
+ if (!m_font)
m_font = machine().render().font_alloc(machine().options().ui_font());
- return m_font;
+ return m_font.get();
}
@@ -1008,7 +1004,7 @@ void mame_ui_manager::process_natural_keyboard()
while (machine().ui_input().pop_event(&event))
{
// if this was a UI_EVENT_CHAR event, post it
- if (event.event_type == ui_event::IME_CHAR)
+ if (event.event_type == ui_event::type::IME_CHAR)
machine().ioport().natkeyboard().post_char(event.ch);
}
@@ -1487,7 +1483,7 @@ std::vector<ui::menu_item>& mame_ui_manager::get_slider_list(void)
std::unique_ptr<slider_state> mame_ui_manager::slider_alloc(int id, const char *title, int32_t minval, int32_t defval, int32_t maxval, int32_t incval, void *arg)
{
- auto state = make_unique_clear<slider_state>();
+ auto state = std::make_unique<slider_state>();
state->minval = minval;
state->defval = defval;
diff --git a/src/frontend/mame/ui/ui.h b/src/frontend/mame/ui/ui.h
index 8c0504464d3..af9ad03efcc 100644
--- a/src/frontend/mame/ui/ui.h
+++ b/src/frontend/mame/ui/ui.h
@@ -271,7 +271,7 @@ private:
using device_feature_set = std::set<std::pair<std::string, std::string> >;
// instance variables
- render_font * m_font;
+ std::unique_ptr<render_font> m_font;
handler_callback_func m_handler_callback;
ui_callback_type m_handler_callback_type;
uint32_t m_handler_param;
diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp
index 58818328d41..2a876c5a1af 100644
--- a/src/frontend/mame/ui/videoopt.cpp
+++ b/src/frontend/mame/ui/videoopt.cpp
@@ -141,7 +141,7 @@ void menu_video_options::handle()
// process the menu
event const *const menu_event(process(0));
- if (menu_event && menu_event->itemref)
+ if (menu_event && uintptr_t(menu_event->itemref))
{
switch (reinterpret_cast<uintptr_t>(menu_event->itemref))
{
diff --git a/src/frontend/mame/ui/viewgfx.cpp b/src/frontend/mame/ui/viewgfx.cpp
index 5b4d187bc95..bc6dee9cd47 100644
--- a/src/frontend/mame/ui/viewgfx.cpp
+++ b/src/frontend/mame/ui/viewgfx.cpp
@@ -994,18 +994,16 @@ static void gfxset_draw_item(running_machine &machine, gfx_element &gfx, int ind
{
int width = (rotate & ORIENTATION_SWAP_XY) ? gfx.height() : gfx.width();
int height = (rotate & ORIENTATION_SWAP_XY) ? gfx.width() : gfx.height();
- const rgb_t *palette = dpalette->palette()->entry_list_raw() + gfx.colorbase() + color * gfx.granularity();
-
- int x, y;
+ rgb_t const *const palette = dpalette->palette()->entry_list_raw() + gfx.colorbase() + color * gfx.granularity();
// loop over rows in the cell
- for (y = 0; y < height; y++)
+ for (int y = 0; y < height; y++)
{
- uint32_t *dest = &bitmap.pix32(dsty + y, dstx);
+ uint32_t *dest = &bitmap.pix(dsty + y, dstx);
const uint8_t *src = gfx.get_data(index);
// loop over columns in the cell
- for (x = 0; x < width; x++)
+ for (int x = 0; x < width; x++)
{
int effx = x, effy = y;
const uint8_t *s;
diff --git a/src/frontend/mame/ui/widgets.cpp b/src/frontend/mame/ui/widgets.cpp
index d8907303b36..59fda0f203c 100644
--- a/src/frontend/mame/ui/widgets.cpp
+++ b/src/frontend/mame/ui/widgets.cpp
@@ -36,7 +36,7 @@ widgets_manager::widgets_manager(running_machine &machine)
for (unsigned x = 0; x < 256; ++x)
{
unsigned const alpha((x < 25) ? (0xff * x / 25) : (x >(256 - 25)) ? (0xff * (255 - x) / 25) : 0xff);
- m_hilight_bitmap->pix32(0, x) = rgb_t(alpha, 0xff, 0xff, 0xff);
+ m_hilight_bitmap->pix(0, x) = rgb_t(alpha, 0xff, 0xff, 0xff);
}
m_hilight_texture.reset(render.texture_alloc());
m_hilight_texture->set_bitmap(*m_hilight_bitmap, m_hilight_bitmap->cliprect(), TEXFORMAT_ARGB32);
@@ -49,7 +49,7 @@ widgets_manager::widgets_manager(running_machine &machine)
unsigned const r = r1 + (y * (r2 - r1) / 128);
unsigned const g = g1 + (y * (g2 - g1) / 128);
unsigned const b = b1 + (y * (b2 - b1) / 128);
- m_hilight_main_bitmap->pix32(y, 0) = rgb_t(r, g, b);
+ m_hilight_main_bitmap->pix(y, 0) = rgb_t(r, g, b);
}
m_hilight_main_texture.reset(render.texture_alloc());
m_hilight_main_texture->set_bitmap(*m_hilight_main_bitmap, m_hilight_main_bitmap->cliprect(), TEXFORMAT_ARGB32);
@@ -67,18 +67,17 @@ widgets_manager::widgets_manager(running_machine &machine)
void widgets_manager::render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param)
{
- int halfwidth = dest.width() / 2;
- int height = dest.height();
- int x, y;
+ int const halfwidth = dest.width() / 2;
+ int const height = dest.height();
// start with all-transparent
dest.fill(rgb_t(0x00, 0x00, 0x00, 0x00));
// render from the tip to the bottom
- for (y = 0; y < height; y++)
+ for (int y = 0; y < height; y++)
{
int linewidth = (y * (halfwidth - 1) + (height / 2)) * 255 * 2 / height;
- uint32_t *target = &dest.pix32(y, halfwidth);
+ uint32_t *const target = &dest.pix(y, halfwidth);
// don't antialias if height < 12
if (dest.height() < 12)
@@ -89,25 +88,23 @@ void widgets_manager::render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source
}
// loop while we still have data to generate
- for (x = 0; linewidth > 0; x++)
+ for (int x = 0; linewidth > 0; x++)
{
int dalpha;
-
- // first column we only consume one pixel
if (x == 0)
{
+ // first column we only consume one pixel
dalpha = std::min(0xff, linewidth);
target[x] = rgb_t(dalpha, 0xff, 0xff, 0xff);
}
-
- // remaining columns consume two pixels, one on each side
else
{
+ // remaining columns consume two pixels, one on each side
dalpha = std::min(0x1fe, linewidth);
target[x] = target[-x] = rgb_t(dalpha / 2, 0xff, 0xff, 0xff);
}
- // account for the weight we consumed */
+ // account for the weight we consumed
linewidth -= dalpha;
}
}
diff --git a/src/lib/formats/a26_cas.cpp b/src/lib/formats/a26_cas.cpp
index 0074da6aba3..09d7e2479e5 100644
--- a/src/lib/formats/a26_cas.cpp
+++ b/src/lib/formats/a26_cas.cpp
@@ -6,10 +6,10 @@ Atari 2600 SuperCharger support
*/
-#include <cassert>
-
#include "formats/a26_cas.h"
+#include <cassert>
+
#define A26_CAS_SIZE 8448
#define A26_WAV_FREQUENCY 44100
@@ -132,7 +132,7 @@ static int a26_cas_to_wav_size( const uint8_t *casdata, int caslen ) {
return a26_cas_do_work( nullptr, casdata );
}
-static const struct CassetteLegacyWaveFiller a26_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller a26_legacy_fill_wave = {
a26_cas_fill_wave,
-1,
0,
@@ -142,21 +142,21 @@ static const struct CassetteLegacyWaveFiller a26_legacy_fill_wave = {
0
};
-static cassette_image::error a26_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
+static cassette_image::error a26_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
uint64_t size;
- size = cassette_image_size( cassette );
+ size = cassette->image_size( );
if ( size == A26_CAS_SIZE ) {
- return cassette_legacy_identify( cassette, opts, &a26_legacy_fill_wave );
+ return cassette->legacy_identify( opts, &a26_legacy_fill_wave );
}
return cassette_image::error::INVALID_IMAGE;
}
static cassette_image::error a26_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &a26_legacy_fill_wave );
+ return cassette->legacy_construct( &a26_legacy_fill_wave );
}
-static const struct CassetteFormat a26_cassette_format = {
+static const cassette_image::Format a26_cassette_format = {
"a26",
a26_cassette_identify,
a26_cassette_load,
diff --git a/src/lib/formats/ace_tap.cpp b/src/lib/formats/ace_tap.cpp
index 522050f612a..1619280b66b 100644
--- a/src/lib/formats/ace_tap.cpp
+++ b/src/lib/formats/ace_tap.cpp
@@ -10,10 +10,10 @@ For more information see:
********************************************************************/
-#include <cassert>
-
#include "ace_tap.h"
+#include <cassert>
+
#define SMPLO -32768
#define SILENCE 0
@@ -155,7 +155,7 @@ static int ace_tap_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller ace_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller ace_legacy_fill_wave =
{
ace_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -167,19 +167,19 @@ static const struct CassetteLegacyWaveFiller ace_legacy_fill_wave =
};
-static cassette_image::error ace_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error ace_tap_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &ace_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &ace_legacy_fill_wave);
}
static cassette_image::error ace_tap_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &ace_legacy_fill_wave);
+ return cassette->legacy_construct(&ace_legacy_fill_wave);
}
-static const struct CassetteFormat ace_tap_format =
+static const cassette_image::Format ace_tap_format =
{
"tap",
ace_tap_identify,
diff --git a/src/lib/formats/adam_cas.cpp b/src/lib/formats/adam_cas.cpp
index 5d24eed2543..4c678bb0796 100644
--- a/src/lib/formats/adam_cas.cpp
+++ b/src/lib/formats/adam_cas.cpp
@@ -1,10 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Curt Coder
+#include "adam_cas.h"
#include <cassert>
-#include "cassimg.h"
-#include "adam_cas.h"
// This code will reproduce the timing of an adam tape played back on a standard tape deck with a 1 7/8ips speed.
#define CASS_AMP 0x1fffffff
@@ -50,7 +49,7 @@ Data is phase encoded, with 70us bit cells with a transition at 31us for a 1 and
****************************************************************/
-static cassette_image::error coladam_ddp_identify ( cassette_image *cass, struct CassetteOptions *opts )
+static cassette_image::error coladam_ddp_identify ( cassette_image *cass, cassette_image::Options *opts )
{
opts -> bits_per_sample = 16;
opts -> channels = 2;
@@ -67,14 +66,14 @@ cassette_image::error coladam_put_byte(cassette_image *cass, int channel, double
{
if(byte & 0x80)
{
- err = cassette_put_sample( cass, channel, *time_index, COL_ADAM_PERIOD1, -CASS_AMP*(*prev_sign) );
+ err = cass->put_sample( channel, *time_index, COL_ADAM_PERIOD1, -CASS_AMP*(*prev_sign) );
(*time_index) += COL_ADAM_PERIOD1;
- err = cassette_put_sample( cass, channel, *time_index, COL_ADAM_PERIOD2, CASS_AMP*(*prev_sign) );
+ err = cass->put_sample( channel, *time_index, COL_ADAM_PERIOD2, CASS_AMP*(*prev_sign) );
(*time_index) += COL_ADAM_PERIOD2;
}
else
{
- err = cassette_put_sample( cass, channel, *time_index, COL_ADAM_PERIOD, -CASS_AMP*(*prev_sign) );
+ err = cass->put_sample( channel, *time_index, COL_ADAM_PERIOD, -CASS_AMP*(*prev_sign) );
(*prev_sign) *=-1;
(*time_index) += COL_ADAM_PERIOD;
}
@@ -146,12 +145,12 @@ static cassette_image::error coladam_ddp_load( cassette_image *cass )
for (block = 0; block < 128; block++)
{
- cassette_image_read( cass, buffer, 0x20000+0x400*block, 0x400 );
+ cass->image_read( buffer, 0x20000+0x400*block, 0x400 );
err = coladam_put_block(cass, 0, &time, &prev_sign, block, buffer, layout_type);
}
for (block = 128; block < 131; block++)
{
- cassette_image_read( cass, buffer, 0x3f400+0x400*(block-128), 0x400 );
+ cass->image_read( buffer, 0x3f400+0x400*(block-128), 0x400 );
err = coladam_put_block(cass, 0, &time, &prev_sign, block, buffer, layout_type);
}
@@ -165,17 +164,17 @@ static cassette_image::error coladam_ddp_load( cassette_image *cass )
{
for (block = 0; block < 64; block++)
{
- cassette_image_read( cass, buffer, 0x10000+0x400*block, 0x400 );
+ cass->image_read( buffer, 0x10000+0x400*block, 0x400 );
err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
}
for (block = 64; block < 128; block++)
{
- cassette_image_read( cass, buffer, 0x00000+0x400*(block-64), 0x400 );
+ cass->image_read( buffer, 0x00000+0x400*(block-64), 0x400 );
err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
}
for (block = 128; block < 131; block++)
{
- cassette_image_read( cass, buffer, 0x0f400+0x400*(block-128), 0x400 );
+ cass->image_read( buffer, 0x0f400+0x400*(block-128), 0x400 );
err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
}
}
@@ -188,12 +187,12 @@ static cassette_image::error coladam_ddp_load( cassette_image *cass )
}
for (block = 0; block < 128; block++)
{
- cassette_image_read( cass, buffer, 0x400*block, 0x400 );
+ cass->image_read( buffer, 0x400*block, 0x400 );
err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
}
for (block = 128; block < 131; block++)
{
- cassette_image_read( cass, buffer, 0x1f400+0x400*(block-128), 0x400 );
+ cass->image_read( buffer, 0x1f400+0x400*(block-128), 0x400 );
err = coladam_put_block(cass, 1, &time, &prev_sign, block, buffer, layout_type);
}
}
@@ -203,7 +202,7 @@ static cassette_image::error coladam_ddp_load( cassette_image *cass )
-static const struct CassetteFormat coladam_ddp =
+static const cassette_image::Format coladam_ddp =
{ "ddp", coladam_ddp_identify, coladam_ddp_load, nullptr /* no save */ };
CASSETTE_FORMATLIST_START(coleco_adam_cassette_formats)
diff --git a/src/lib/formats/apf_apt.cpp b/src/lib/formats/apf_apt.cpp
index 28793f0f853..e820090ef04 100644
--- a/src/lib/formats/apf_apt.cpp
+++ b/src/lib/formats/apf_apt.cpp
@@ -34,10 +34,10 @@ e. A checksum byte (8-bit addition)
********************************************************************/
-#include <cassert>
-
#include "formats/apf_apt.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -184,7 +184,7 @@ static int apf_cpf_calculate_size_in_samples(const uint8_t *bytes, int length)
//*********************************************************************************
-static const struct CassetteLegacyWaveFiller apf_cpf_fill_intf =
+static const cassette_image::LegacyWaveFiller apf_cpf_fill_intf =
{
apf_cpf_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -195,17 +195,17 @@ static const struct CassetteLegacyWaveFiller apf_cpf_fill_intf =
0 /* trailer_samples */
};
-static cassette_image::error apf_cpf_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error apf_cpf_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &apf_cpf_fill_intf);
+ return cassette->legacy_identify(opts, &apf_cpf_fill_intf);
}
static cassette_image::error apf_cpf_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &apf_cpf_fill_intf);
+ return cassette->legacy_construct(&apf_cpf_fill_intf);
}
-static const struct CassetteFormat apf_cpf_format =
+static const cassette_image::Format apf_cpf_format =
{
"cas,cpf",
apf_cpf_identify,
@@ -215,7 +215,7 @@ static const struct CassetteFormat apf_cpf_format =
//*********************************************************************************
-static const struct CassetteLegacyWaveFiller apf_apt_fill_intf =
+static const cassette_image::LegacyWaveFiller apf_apt_fill_intf =
{
apf_apt_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -226,17 +226,17 @@ static const struct CassetteLegacyWaveFiller apf_apt_fill_intf =
0 /* trailer_samples */
};
-static cassette_image::error apf_apt_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error apf_apt_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &apf_apt_fill_intf);
+ return cassette->legacy_identify(opts, &apf_apt_fill_intf);
}
static cassette_image::error apf_apt_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &apf_apt_fill_intf);
+ return cassette->legacy_construct(&apf_apt_fill_intf);
}
-static const struct CassetteFormat apf_apt_format =
+static const cassette_image::Format apf_apt_format =
{
"apt",
apf_apt_identify,
diff --git a/src/lib/formats/apridisk.cpp b/src/lib/formats/apridisk.cpp
index bb53006f188..aad688167cf 100644
--- a/src/lib/formats/apridisk.cpp
+++ b/src/lib/formats/apridisk.cpp
@@ -48,8 +48,8 @@ int apridisk_format::identify(io_generic *io, uint32_t form_factor)
bool apridisk_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
{
desc_pc_sector sectors[80][2][18];
- uint8_t sector_data[MAX_SECTORS * SECTOR_SIZE];
- uint8_t *data_ptr = sector_data;
+ std::unique_ptr<uint8_t []> sector_data(new uint8_t [MAX_SECTORS * SECTOR_SIZE]);
+ uint8_t *data_ptr = sector_data.get();
int track_count = 0, head_count = 0, sector_count = 0;
uint64_t file_size = io_generic_size(io);
diff --git a/src/lib/formats/atom_tap.cpp b/src/lib/formats/atom_tap.cpp
index 212208a6d37..cfe83bc1bae 100644
--- a/src/lib/formats/atom_tap.cpp
+++ b/src/lib/formats/atom_tap.cpp
@@ -40,11 +40,12 @@
*/
-#include <cassert>
-
#include "atom_tap.h"
#include "csw_cas.h"
#include "uef_cas.h"
+
+#include <cassert>
+
/***************************************************************************
PARAMETERS
***************************************************************************/
@@ -59,9 +60,9 @@
CassetteModulation atom_tap_modulation
-------------------------------------------------*/
-static const struct CassetteModulation atom_tap_modulation =
+static const cassette_image::Modulation atom_tap_modulation =
{
- CASSETTE_MODULATION_SINEWAVE,
+ cassette_image::MODULATION_SINEWAVE,
1200.0 - 300, 1200.0, 1200.0 + 300,
2400.0 - 600, 2400.0, 2400.0 + 600
};
@@ -73,7 +74,7 @@ static const struct CassetteModulation atom_tap_modulation =
static uint8_t cassette_image_read_uint8(cassette_image *cassette, uint64_t offset)
{
uint8_t data;
- cassette_image_read(cassette, &data, offset, 1);
+ cassette->image_read(&data, offset, 1);
return data;
}
@@ -81,9 +82,9 @@ static uint8_t cassette_image_read_uint8(cassette_image *cassette, uint64_t offs
atom_tap_identify - identify cassette
-------------------------------------------------*/
-static cassette_image::error atom_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error atom_tap_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_modulation_identify( cassette, &atom_tap_modulation, opts);
+ return cassette->modulation_identify(atom_tap_modulation, opts);
}
/*-------------------------------------------------
@@ -92,7 +93,7 @@ static cassette_image::error atom_tap_identify(cassette_image *cassette, struct
#define MODULATE(_value) \
for (int i = 0; i < (_value ? 8 : 4); i++) { \
- err = cassette_put_modulated_data_bit(cassette, 0, time_index, _value, &atom_tap_modulation, &time_displacement);\
+ err = cassette->put_modulated_data_bit(0, time_index, _value, atom_tap_modulation, &time_displacement);\
if (err != cassette_image::error::SUCCESS) return err;\
time_index += time_displacement;\
}
@@ -102,7 +103,7 @@ static cassette_image::error atom_tap_identify(cassette_image *cassette, struct
static cassette_image::error atom_tap_load(cassette_image *cassette)
{
cassette_image::error err;
- uint64_t image_size = cassette_image_size(cassette);
+ uint64_t image_size = cassette->image_size();
uint64_t image_pos = 0;
double time_index = 0.0;
double time_displacement;
@@ -134,7 +135,7 @@ static cassette_image::error atom_tap_load(cassette_image *cassette)
CassetteFormat atom_tap_cassette_format
-------------------------------------------------*/
-const struct CassetteFormat atom_tap_format =
+const cassette_image::Format atom_tap_format =
{
"tap",
atom_tap_identify,
diff --git a/src/lib/formats/camplynx_cas.cpp b/src/lib/formats/camplynx_cas.cpp
index e802be4426f..5945650ca0a 100644
--- a/src/lib/formats/camplynx_cas.cpp
+++ b/src/lib/formats/camplynx_cas.cpp
@@ -191,7 +191,7 @@ static int camplynx_cassette_calculate_size_in_samples(const uint8_t *bytes, int
return camplynx_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller lynx48k_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller lynx48k_legacy_fill_wave =
{
camplynx_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -202,7 +202,7 @@ static const struct CassetteLegacyWaveFiller lynx48k_legacy_fill_wave =
0 /* trailer_samples */
};
-static const struct CassetteLegacyWaveFiller lynx128k_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller lynx128k_legacy_fill_wave =
{
camplynx_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -213,27 +213,27 @@ static const struct CassetteLegacyWaveFiller lynx128k_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error lynx48k_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error lynx48k_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &lynx48k_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &lynx48k_legacy_fill_wave);
}
-static cassette_image::error lynx128k_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error lynx128k_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &lynx128k_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &lynx128k_legacy_fill_wave);
}
static cassette_image::error lynx48k_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &lynx48k_legacy_fill_wave);
+ return cassette->legacy_construct(&lynx48k_legacy_fill_wave);
}
static cassette_image::error lynx128k_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &lynx128k_legacy_fill_wave);
+ return cassette->legacy_construct(&lynx128k_legacy_fill_wave);
}
-static const struct CassetteFormat lynx48k_cassette_image_format =
+static const cassette_image::Format lynx48k_cassette_image_format =
{
"tap",
lynx48k_cassette_identify,
@@ -241,7 +241,7 @@ static const struct CassetteFormat lynx48k_cassette_image_format =
nullptr
};
-static const struct CassetteFormat lynx128k_cassette_image_format =
+static const cassette_image::Format lynx128k_cassette_image_format =
{
"tap",
lynx128k_cassette_identify,
diff --git a/src/lib/formats/cassimg.cpp b/src/lib/formats/cassimg.cpp
index 4f5d9320754..25b060e0311 100644
--- a/src/lib/formats/cassimg.cpp
+++ b/src/lib/formats/cassimg.cpp
@@ -8,12 +8,12 @@
*********************************************************************/
-#include <cstring>
-#include <cassert>
-
-#include "imageutl.h"
#include "cassimg.h"
+#include "imageutl.h"
+
#include <algorithm>
+#include <cassert>
+#include <cstring>
/* debugging parameters */
@@ -28,21 +28,22 @@ CASSETTE_FORMATLIST_START(cassette_default_formats)
CASSETTE_FORMATLIST_END
+namespace {
/*********************************************************************
helper code
*********************************************************************/
-static double map_double(double d, uint64_t low, uint64_t high, uint64_t value)
+constexpr double map_double(double d, uint64_t low, uint64_t high, uint64_t value)
{
return d * (value - low) / (high - low);
}
-static size_t waveform_bytes_per_sample(int waveform_flags)
+constexpr size_t waveform_bytes_per_sample(int waveform_flags)
{
- return (size_t) (1 << ((waveform_flags & 0x06) / 2));
+ return size_t(1 << ((waveform_flags & 0x06) / 2));
}
@@ -51,361 +52,319 @@ static size_t waveform_bytes_per_sample(int waveform_flags)
extrapolation and interpolation
*********************************************************************/
-static int32_t extrapolate8(int8_t value)
+constexpr int32_t extrapolate8(int8_t value)
{
- return ((int32_t) value) << 24;
+ return int32_t(value) << 24;
}
-static int32_t extrapolate16(int16_t value)
+constexpr int32_t extrapolate16(int16_t value)
{
- return ((int32_t) value) << 16;
+ return int32_t(value) << 16;
}
-static int8_t interpolate8(int32_t value)
+constexpr int8_t interpolate8(int32_t value)
{
- return (int8_t) (value >> 24);
+ return int8_t(value >> 24);
}
-static int16_t interpolate16(int32_t value)
+constexpr int16_t interpolate16(int32_t value)
{
- return (int16_t) (value >> 16);
+ return int16_t(value >> 16);
}
-/*********************************************************************
- initialization and termination
-*********************************************************************/
-
-static cassette_image *cassette_init(const struct CassetteFormat *format, void *file, const struct io_procs *procs, int flags)
+constexpr size_t my_round(double d)
{
- cassette_image *cassette;
-
- cassette = global_alloc_clear<cassette_image>();
- cassette->format = format;
- cassette->io.file = file;
- cassette->io.procs = procs;
- cassette->flags = flags;
- return cassette;
+ return size_t(d + 0.5);
}
-static void cassette_finishinit(cassette_image::error err, cassette_image *cassette, cassette_image **outcassette)
+/*********************************************************************
+ waveform accesses to/from the raw image
+*********************************************************************/
+
+const int8_t *choose_wave(const cassette_image::Modulation &modulation, size_t &wave_bytes_length)
{
- if (cassette && ((err != cassette_image::error::SUCCESS) || !outcassette))
+ static const int8_t square_wave[] = { -128, 127 };
+ static const int8_t sine_wave[] = { 0, 48, 89, 117, 127, 117, 89, 48, 0, -48, -89, -117, -127, -117, -89, -48 };
+
+ if (modulation.flags & cassette_image::MODULATION_SINEWAVE)
+ {
+ wave_bytes_length = ARRAY_LENGTH(sine_wave);
+ return sine_wave;
+ }
+ else
{
- cassette_close(cassette);
- cassette = nullptr;
+ wave_bytes_length = ARRAY_LENGTH(square_wave);
+ return square_wave;
}
- if (outcassette)
- *outcassette = cassette;
}
+} // anonymous namespace
-static cassette_image::error try_identify_format(const struct CassetteFormat &format, cassette_image *image, const std::string &extension, int flags, struct CassetteOptions &opts)
+
+/*********************************************************************
+ initialization and termination
+*********************************************************************/
+
+cassette_image::error cassette_image::try_identify_format(const Format &format, const std::string &extension, int flags, Options &opts)
{
// is this the right extension?
if (!extension.empty() && !image_find_extension(format.extensions, extension.c_str()))
- return cassette_image::error::INVALID_IMAGE;
+ return error::INVALID_IMAGE;
// invoke format->identify
- memset(&opts, 0, sizeof(opts));
- cassette_image::error err = format.identify(image, &opts);
- if (err != cassette_image::error::SUCCESS)
+ opts = Options();
+ error err = format.identify(this, &opts);
+ if (err != error::SUCCESS)
return err;
// is this a read only format, but the cassette was not opened read only?
- if (((flags & CASSETTE_FLAG_READONLY) == 0) && (format.save == nullptr))
- return cassette_image::error::READ_WRITE_UNSUPPORTED;
+ if (((flags & FLAG_READONLY) == 0) && (format.save == nullptr))
+ return error::READ_WRITE_UNSUPPORTED;
// success!
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
+}
+
+
+cassette_image::error cassette_image::perform_save()
+{
+ Info info = get_info();
+ return m_format->save(this, &info);
}
-cassette_image::error cassette_open_choices(void *file, const struct io_procs *procs, const std::string &extension,
- const struct CassetteFormat *const *formats, int flags, cassette_image **outcassette)
+/*********************************************************************
+ waveform accesses
+*********************************************************************/
+
+struct cassette_image::manipulation_ranges
{
- cassette_image::error err;
- cassette_image *cassette;
- const struct CassetteFormat *format;
- struct CassetteOptions opts = {0, };
- int i;
+ int channel_first;
+ int channel_last;
+ size_t sample_first;
+ size_t sample_last;
+};
- /* if not specified, use the dummy arguments */
- if (!formats)
- formats = cassette_default_formats;
- /* create the cassette object */
- cassette = cassette_init(nullptr, file, procs, flags);
- if (!cassette)
- {
- err = cassette_image::error::OUT_OF_MEMORY;
- goto done;
- }
- /* identify the image */
- format = nullptr;
- for (i = 0; !format && formats[i]; i++)
+cassette_image::error cassette_image::compute_manipulation_ranges(int channel,
+ double time_index, double sample_period, manipulation_ranges &ranges) const
+{
+ if (channel < 0)
{
- // try this format
- err = try_identify_format(*formats[i], cassette, extension, flags, opts);
- if (err != cassette_image::error::SUCCESS && err != cassette_image::error::INVALID_IMAGE)
- goto done;
-
- // did we succeed?
- if (err == cassette_image::error::SUCCESS)
- format = formats[i];
+ ranges.channel_first = 0;
+ ranges.channel_last = m_channels - 1;
}
-
- /* have we found a proper format */
- if (!format)
+ else
{
- err = cassette_image::error::INVALID_IMAGE;
- goto done;
+ ranges.channel_first = channel;
+ ranges.channel_last = channel;
}
- cassette->format = format;
-
- /* read the options */
- cassette->channels = opts.channels;
- cassette->sample_frequency = opts.sample_frequency;
- /* load the image */
- err = format->load(cassette);
- if (err != cassette_image::error::SUCCESS)
- goto done;
+ ranges.sample_first = my_round(time_index * m_sample_frequency);
+ ranges.sample_last = my_round((time_index + sample_period) * m_sample_frequency);
- /* success */
- cassette->flags &= ~CASSETTE_FLAG_DIRTY;
- err = cassette_image::error::SUCCESS;
+ if (ranges.sample_last > ranges.sample_first)
+ ranges.sample_last--;
-done:
- cassette_finishinit(err, cassette, outcassette);
- return err;
+ return error::SUCCESS;
}
-cassette_image::error cassette_open(void *file, const struct io_procs *procs,
- const struct CassetteFormat *format, int flags, cassette_image **outcassette)
+cassette_image::error cassette_image::lookup_sample(int channel, size_t sample, int32_t *&ptr)
{
- const struct CassetteFormat *formats[2];
- formats[0] = format;
- formats[1] = nullptr;
- return cassette_open_choices(file, procs, nullptr, formats, flags, outcassette);
-}
-
+ ptr = nullptr;
+ size_t sample_blocknum = (sample / SAMPLES_PER_BLOCK) * m_channels + channel;
+ size_t sample_index = sample % SAMPLES_PER_BLOCK;
+ // is this block beyond the edge of our waveform?
+ if (sample_blocknum >= m_blocks.size())
+ m_blocks.resize(sample_blocknum + 1);
-cassette_image::error cassette_create(void *file, const struct io_procs *procs, const struct CassetteFormat *format,
- const struct CassetteOptions *opts, int flags, cassette_image **outcassette)
-{
- cassette_image::error err;
- cassette_image *cassette;
- static const struct CassetteOptions default_options = { 1, 16, 44100 };
+ if (!m_blocks[sample_blocknum])
+ m_blocks[sample_blocknum] = make_unique_clear<int32_t []>(SAMPLES_PER_BLOCK);
- /* cannot create to a read only image */
- if (flags & CASSETTE_FLAG_READONLY)
- return cassette_image::error::INVALID_IMAGE;
+ ptr = &m_blocks[sample_blocknum][sample_index];
+ return error::SUCCESS;
+}
- /* is this a good format? */
- if (format->save == nullptr)
- return cassette_image::error::INVALID_IMAGE;
- /* normalize arguments */
- if (!opts)
- opts = &default_options;
- /* create the cassette object */
- cassette = cassette_init(format, file, procs, flags);
- if (!cassette)
- {
- err = cassette_image::error::OUT_OF_MEMORY;
- goto done;
- }
+cassette_image::cassette_image(const Format *format, void *file, const io_procs *procs, int flags)
+{
+ m_format = format;
+ m_io.file = file;
+ m_io.procs = procs;
+ m_flags = flags;
+}
- /* read the options */
- cassette->channels = opts->channels;
- cassette->sample_frequency = opts->sample_frequency;
- err = cassette_image::error::SUCCESS;
-done:
- cassette_finishinit(err, cassette, outcassette);
- return err;
+cassette_image::~cassette_image()
+{
+ if ((m_flags & CASSETTE_FLAG_DIRTY) && (m_flags & FLAG_SAVEONEXIT))
+ save();
}
-static cassette_image::error cassette_perform_save(cassette_image *cassette)
+cassette_image::error cassette_image::open(void *file, const io_procs *procs,
+ const Format *format, int flags, ptr &outcassette)
{
- struct CassetteInfo info;
- cassette_get_info(cassette, &info);
- return cassette->format->save(cassette, &info);
+ const Format *const formats[2] = { format, nullptr };
+ return open_choices(file, procs, nullptr, formats, flags, outcassette);
}
-cassette_image::error cassette_save(cassette_image *cassette)
+cassette_image::error cassette_image::open_choices(void *file, const io_procs *procs, const std::string &extension,
+ const Format *const *formats, int flags, ptr &outcassette)
{
- cassette_image::error err;
+ // if not specified, use the dummy arguments
+ if (!formats)
+ formats = cassette_default_formats;
- if (!cassette->format || !cassette->format->save)
- return cassette_image::error::UNSUPPORTED;
+ // create the cassette object
+ ptr cassette;
+ try { cassette.reset(new cassette_image(nullptr, file, procs, flags)); }
+ catch (std::bad_alloc const &) { return error::OUT_OF_MEMORY; }
- err = cassette_perform_save(cassette);
- if (err != cassette_image::error::SUCCESS)
+ // identify the image
+ const Format *format = nullptr;
+ Options opts;
+ for (int i = 0; !format && formats[i]; i++)
+ {
+ // try this format
+ error err = cassette->try_identify_format(*formats[i], extension, flags, opts);
+ if (err != error::SUCCESS && err != error::INVALID_IMAGE)
+ return err;
+
+ // did we succeed?
+ if (err == error::SUCCESS)
+ format = formats[i];
+ }
+
+ // have we found a proper format
+ if (!format)
+ return error::INVALID_IMAGE;
+ cassette->m_format = format;
+
+ // read the options
+ cassette->m_channels = opts.channels;
+ cassette->m_sample_frequency = opts.sample_frequency;
+
+ // load the image
+ error err = format->load(cassette.get());
+ if (err != error::SUCCESS)
return err;
- cassette->flags &= ~CASSETTE_FLAG_DIRTY;
- return cassette_image::error::SUCCESS;
+ /* success */
+ cassette->m_flags &= ~CASSETTE_FLAG_DIRTY;
+ outcassette = std::move(cassette);
+ return error::SUCCESS;
}
-void cassette_get_info(cassette_image *cassette, struct CassetteInfo *info)
+cassette_image::error cassette_image::create(void *file, const io_procs *procs, const Format *format,
+ const Options *opts, int flags, ptr &outcassette)
{
- memset(info, 0, sizeof(*info));
- info->channels = cassette->channels;
- info->sample_count = cassette->sample_count;
- info->sample_frequency = cassette->sample_frequency;
- info->bits_per_sample = (int) waveform_bytes_per_sample(cassette->flags) * 8;
-}
+ static const Options default_options = { 1, 16, 44100 };
+ // cannot create to a read only image
+ if (flags & FLAG_READONLY)
+ return error::INVALID_IMAGE;
+ // is this a good format?
+ if (format->save == nullptr)
+ return error::INVALID_IMAGE;
-void cassette_close(cassette_image *cassette)
-{
- if (cassette)
- {
- if ((cassette->flags & CASSETTE_FLAG_DIRTY) && (cassette->flags & CASSETTE_FLAG_SAVEONEXIT))
- cassette_save(cassette);
- for (auto & elem : cassette->blocks)
- {
- global_free(elem);
- }
- global_free(cassette);
- }
-}
+ // normalize arguments
+ if (!opts)
+ opts = &default_options;
+ // create the cassette object
+ ptr cassette;
+ try { cassette.reset(new cassette_image(format, file, procs, flags)); }
+ catch (std::bad_alloc const &) { return error::OUT_OF_MEMORY; }
+ // read the options
+ cassette->m_channels = opts->channels;
+ cassette->m_sample_frequency = opts->sample_frequency;
-void cassette_change(cassette_image *cassette, void *file, const struct io_procs *procs, const struct CassetteFormat *format, int flags)
-{
- if ((flags & CASSETTE_FLAG_READONLY) == 0)
- flags |= CASSETTE_FLAG_DIRTY;
- cassette->io.file = file;
- cassette->io.procs = procs;
- cassette->format = format;
- cassette->flags = flags;
+ outcassette = std::move(cassette);
+ return error::SUCCESS;
}
-/*********************************************************************
- calls for accessing the raw cassette image
-*********************************************************************/
-
-void cassette_image_read(cassette_image *cassette, void *buffer, uint64_t offset, size_t length)
+cassette_image::error cassette_image::save()
{
- io_generic_read(&cassette->io, buffer, offset, length);
+ if (!m_format || !m_format->save)
+ return error::UNSUPPORTED;
+
+ error err = perform_save();
+ if (err != error::SUCCESS)
+ return err;
+
+ m_flags &= ~CASSETTE_FLAG_DIRTY;
+ return error::SUCCESS;
}
-void cassette_image_write(cassette_image *cassette, const void *buffer, uint64_t offset, size_t length)
+cassette_image::Info cassette_image::get_info() const
{
- io_generic_write(&cassette->io, buffer, offset, length);
+ Info result;
+ result.channels = m_channels;
+ result.sample_count = m_sample_count;
+ result.sample_frequency = m_sample_frequency;
+ result.bits_per_sample = (int)waveform_bytes_per_sample(m_flags) * 8;
+ return result;
}
-uint64_t cassette_image_size(cassette_image *cassette)
+void cassette_image::change(void *file, const io_procs *procs, const Format *format, int flags)
{
- return io_generic_size(&cassette->io);
+ if ((flags & FLAG_READONLY) == 0)
+ flags |= CASSETTE_FLAG_DIRTY;
+ m_io.file = file;
+ m_io.procs = procs;
+ m_format = format;
+ m_flags = flags;
}
/*********************************************************************
- waveform accesses
+ calls for accessing the raw cassette image
*********************************************************************/
-struct manipulation_ranges
+void cassette_image::image_read(void *buffer, uint64_t offset, size_t length)
{
- int channel_first;
- int channel_last;
- size_t sample_first;
- size_t sample_last;
-};
-
-
-
-static size_t my_round(double d)
-{
- size_t result;
- d += 0.5;
- result = (size_t) d;
- return result;
+ io_generic_read(&m_io, buffer, offset, length);
}
-static cassette_image::error compute_manipulation_ranges(cassette_image *cassette, int channel,
- double time_index, double sample_period, struct manipulation_ranges *ranges)
+void cassette_image::image_write(const void *buffer, uint64_t offset, size_t length)
{
- if (channel < 0)
- {
- ranges->channel_first = 0;
- ranges->channel_last = cassette->channels - 1;
- }
- else
- {
- ranges->channel_first = channel;
- ranges->channel_last = channel;
- }
-
- ranges->sample_first = my_round(time_index * cassette->sample_frequency);
- ranges->sample_last = my_round((time_index + sample_period) * cassette->sample_frequency);
-
- if (ranges->sample_last > ranges->sample_first)
- ranges->sample_last--;
-
- return cassette_image::error::SUCCESS;
+ io_generic_write(&m_io, buffer, offset, length);
}
-static cassette_image::error lookup_sample(cassette_image *cassette, int channel, size_t sample, int32_t **ptr)
+uint64_t cassette_image::image_size()
{
- *ptr = nullptr;
- size_t sample_blocknum = (sample / SAMPLES_PER_BLOCK) * cassette->channels + channel;
- size_t sample_index = sample % SAMPLES_PER_BLOCK;
-
- /* is this block beyond the edge of our waveform? */
- if (sample_blocknum >= cassette->blocks.size()) {
- size_t osize = cassette->blocks.size();
- cassette->blocks.resize(sample_blocknum + 1);
- memset(&cassette->blocks[osize], 0, (cassette->blocks.size()-osize)*sizeof(cassette->blocks[0]));
- }
-
- if (cassette->blocks[sample_blocknum] == nullptr)
- cassette->blocks[sample_blocknum] = global_alloc(sample_block);
-
- sample_block &block = *cassette->blocks[sample_blocknum];
-
- /* is this sample access off the current block? */
- if (sample_index >= block.size()) {
- size_t osize = block.size();
- block.resize(SAMPLES_PER_BLOCK);
- memset(&block[osize], 0, (SAMPLES_PER_BLOCK-osize)*sizeof(block[0]));
- }
-
- *ptr = &block[sample_index];
- return cassette_image::error::SUCCESS;
+ return io_generic_size(&m_io);
}
@@ -417,38 +376,29 @@ static cassette_image::error lookup_sample(cassette_image *cassette, int channel
// Note: In normal use, the sample_spacing is the same as the sample size (in bytes)
// But it can be larger to help do an interleaved write to samples
// (see cassette_write_samples)
-cassette_image::error cassette_get_samples(cassette_image *cassette, int channel,
+cassette_image::error cassette_image::get_samples(int channel,
double time_index, double sample_period, size_t sample_count, size_t sample_spacing,
void *samples, int waveform_flags)
{
- cassette_image::error err;
- struct manipulation_ranges ranges;
- size_t sample_index;
- size_t cassette_sample_index;
- uint8_t *dest_ptr;
- const int32_t *source_ptr;
- double d;
- int16_t word;
- int32_t dword;
- int64_t sum;
-
- assert(cassette);
-
- err = compute_manipulation_ranges(cassette, channel, time_index, sample_period, &ranges);
- if (err != cassette_image::error::SUCCESS)
+ error err;
+ manipulation_ranges ranges;
+ int32_t *source_ptr;
+
+ err = compute_manipulation_ranges(channel, time_index, sample_period, ranges);
+ if (err != error::SUCCESS)
return err;
- for (sample_index = 0; sample_index < sample_count; sample_index++)
+ for (size_t sample_index = 0; sample_index < sample_count; sample_index++)
{
- sum = 0;
+ int64_t sum = 0;
for (channel = ranges.channel_first; channel <= ranges.channel_last; channel++)
{
/* find the sample that we are putting */
- d = map_double(ranges.sample_last + 1 - ranges.sample_first, 0, sample_count, sample_index) + ranges.sample_first;
- cassette_sample_index = (size_t) d;
- err = lookup_sample(cassette, channel, cassette_sample_index, (int32_t **) &source_ptr);
- if (err != cassette_image::error::SUCCESS)
+ double d = map_double(ranges.sample_last + 1 - ranges.sample_first, 0, sample_count, sample_index) + ranges.sample_first;
+ size_t cassette_sample_index = (size_t) d;
+ err = lookup_sample(channel, cassette_sample_index, source_ptr);
+ if (err != error::SUCCESS)
return err;
sum += *source_ptr;
@@ -458,61 +408,54 @@ cassette_image::error cassette_get_samples(cassette_image *cassette, int channel
sum /= (ranges.channel_last + 1 - ranges.channel_first);
/* and write out the result */
- dest_ptr = (uint8_t*)samples;
+ uint8_t *dest_ptr = (uint8_t*)samples;
dest_ptr += sample_index * sample_spacing;
- switch(waveform_bytes_per_sample(waveform_flags))
+ int16_t word;
+ int32_t dword;
+ switch (waveform_bytes_per_sample(waveform_flags))
{
- case 1:
- *((int8_t *) dest_ptr) = interpolate8(sum);
- break;
- case 2:
- word = interpolate16(sum);
- if (waveform_flags & CASSETTE_WAVEFORM_ENDIAN_FLIP)
- word = swapendian_int16(word);
- *((int16_t *) dest_ptr) = word;
- break;
- case 4:
- dword = sum;
- if (waveform_flags & CASSETTE_WAVEFORM_ENDIAN_FLIP)
- dword = swapendian_int32(dword);
- *((int32_t *) dest_ptr) = dword;
- break;
+ case 1:
+ *((int8_t *) dest_ptr) = interpolate8(sum);
+ break;
+ case 2:
+ word = interpolate16(sum);
+ if (waveform_flags & WAVEFORM_ENDIAN_FLIP)
+ word = swapendian_int16(word);
+ *((int16_t *) dest_ptr) = word;
+ break;
+ case 4:
+ dword = sum;
+ if (waveform_flags & WAVEFORM_ENDIAN_FLIP)
+ dword = swapendian_int32(dword);
+ *((int32_t *) dest_ptr) = dword;
+ break;
}
}
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
}
// Note: In normal use, the sample_spacing is the same as the sample size (in bytes)
// But it can be larger to help do an interleaved read from samples
// (see cassette_read_samples)
-cassette_image::error cassette_put_samples(cassette_image *cassette, int channel,
+cassette_image::error cassette_image::put_samples(int channel,
double time_index, double sample_period, size_t sample_count, size_t sample_spacing,
const void *samples, int waveform_flags)
{
- cassette_image::error err;
- struct manipulation_ranges ranges;
- size_t sample_index;
+ error err;
+ manipulation_ranges ranges;
int32_t *dest_ptr;
- int32_t dest_value;
- int16_t word;
- int32_t dword;
- const uint8_t *source_ptr;
- double d;
-
- if (!cassette)
- return cassette_image::error::SUCCESS;
if (sample_period == 0)
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
- err = compute_manipulation_ranges(cassette, channel, time_index, sample_period, &ranges);
- if (err != cassette_image::error::SUCCESS)
+ err = compute_manipulation_ranges(channel, time_index, sample_period, ranges);
+ if (err != error::SUCCESS)
return err;
- if (cassette->sample_count < ranges.sample_last+1)
- cassette->sample_count = ranges.sample_last + 1;
- cassette->flags |= CASSETTE_FLAG_DIRTY;
+ if (m_sample_count < ranges.sample_last+1)
+ m_sample_count = ranges.sample_last + 1;
+ m_flags |= CASSETTE_FLAG_DIRTY;
if (LOG_PUT_SAMPLES)
{
@@ -521,65 +464,68 @@ cassette_image::error cassette_put_samples(cassette_image *cassette, int channel
(int)ranges.sample_first, (int)ranges.sample_last);
}
- for (sample_index = ranges.sample_first; sample_index <= ranges.sample_last; sample_index++)
+ for (size_t sample_index = ranges.sample_first; sample_index <= ranges.sample_last; sample_index++)
{
/* figure out the source pointer */
- d = map_double(sample_count, ranges.sample_first, ranges.sample_last + 1, sample_index);
- source_ptr = (const uint8_t*)samples;
+ double d = map_double(sample_count, ranges.sample_first, ranges.sample_last + 1, sample_index);
+ const uint8_t *source_ptr = (const uint8_t*)samples;
source_ptr += ((size_t) d) * sample_spacing;
/* compute the value that we are writing */
+ int32_t dest_value;
+ int16_t word;
+ int32_t dword;
switch(waveform_bytes_per_sample(waveform_flags)) {
case 1:
- if (waveform_flags & CASSETTE_WAVEFORM_UNSIGNED)
+ if (waveform_flags & WAVEFORM_UNSIGNED)
dest_value = extrapolate8((int8_t)(*source_ptr - 128));
else
dest_value = extrapolate8(*((int8_t *) source_ptr));
break;
case 2:
word = *((int16_t *) source_ptr);
- if (waveform_flags & CASSETTE_WAVEFORM_ENDIAN_FLIP)
+ if (waveform_flags & WAVEFORM_ENDIAN_FLIP)
word = swapendian_int16(word);
dest_value = extrapolate16(word);
break;
case 4:
dword = *((int32_t *) source_ptr);
- if (waveform_flags & CASSETTE_WAVEFORM_ENDIAN_FLIP)
+ if (waveform_flags & WAVEFORM_ENDIAN_FLIP)
dword = swapendian_int32(dword);
dest_value = dword;
break;
default:
- return cassette_image::error::INTERNAL;
+ return error::INTERNAL;
}
for (channel = ranges.channel_first; channel <= ranges.channel_last; channel++)
{
/* find the sample that we are putting */
- err = lookup_sample(cassette, channel, sample_index, &dest_ptr);
- if (err != cassette_image::error::SUCCESS)
+ err = lookup_sample(channel, sample_index, dest_ptr);
+ if (err != error::SUCCESS)
return err;
*dest_ptr = dest_value;
}
}
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
}
-cassette_image::error cassette_get_sample(cassette_image *cassette, int channel,
+cassette_image::error cassette_image::get_sample(int channel,
double time_index, double sample_period, int32_t *sample)
{
- return cassette_get_samples(cassette, channel, time_index,
- sample_period, 1, 0, sample, CASSETTE_WAVEFORM_32BIT);
+ return get_samples(channel, time_index,
+ sample_period, 1, 0, sample, WAVEFORM_32BIT);
}
-cassette_image::error cassette_put_sample(cassette_image *cassette, int channel,
+cassette_image::error cassette_image::put_sample(int channel,
double time_index, double sample_period, int32_t sample)
{
- return cassette_put_samples(cassette, channel, time_index,
- sample_period, 1, 0, &sample, CASSETTE_WAVEFORM_32BIT);
+ return put_samples(channel, time_index,
+ sample_period, 1, 0, &sample, WAVEFORM_32BIT);
}
@@ -588,153 +534,112 @@ cassette_image::error cassette_put_sample(cassette_image *cassette, int channel,
waveform accesses to/from the raw image
*********************************************************************/
-cassette_image::error cassette_read_samples(cassette_image *cassette, int channels, double time_index,
+cassette_image::error cassette_image::read_samples(int channels, double time_index,
double sample_period, size_t sample_count, uint64_t offset, int waveform_flags)
{
- cassette_image::error err;
- size_t chunk_sample_count;
- size_t bytes_per_sample;
- size_t sample_spacing;
+ error err;
size_t samples_loaded = 0;
- double chunk_time_index;
- double chunk_sample_period;
- int channel;
uint8_t buffer[8192];
- bytes_per_sample = waveform_bytes_per_sample(waveform_flags);
- sample_spacing = bytes_per_sample * channels;
+ size_t bytes_per_sample = waveform_bytes_per_sample(waveform_flags);
+ size_t sample_spacing = bytes_per_sample * channels;
- while(samples_loaded < sample_count)
+ while (samples_loaded < sample_count)
{
- chunk_sample_count = std::min(sizeof(buffer) / sample_spacing, (sample_count - samples_loaded));
- chunk_sample_period = map_double(sample_period, 0, sample_count, chunk_sample_count);
- chunk_time_index = time_index + map_double(sample_period, 0, sample_count, samples_loaded);
+ size_t chunk_sample_count = std::min(sizeof(buffer) / sample_spacing, (sample_count - samples_loaded));
+ double chunk_sample_period = map_double(sample_period, 0, sample_count, chunk_sample_count);
+ double chunk_time_index = time_index + map_double(sample_period, 0, sample_count, samples_loaded);
- cassette_image_read(cassette, buffer, offset, chunk_sample_count * sample_spacing);
+ image_read(buffer, offset, chunk_sample_count * sample_spacing);
- for (channel = 0; channel < channels; channel++)
+ for (int channel = 0; channel < channels; channel++)
{
- err = cassette_put_samples(cassette, channel, chunk_time_index, chunk_sample_period,
+ err = put_samples(channel, chunk_time_index, chunk_sample_period,
chunk_sample_count, sample_spacing, &buffer[channel * bytes_per_sample], waveform_flags);
- if (err != cassette_image::error::SUCCESS)
+ if (err != error::SUCCESS)
return err;
}
offset += chunk_sample_count * sample_spacing;
samples_loaded += chunk_sample_count;
}
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
}
-cassette_image::error cassette_write_samples(cassette_image *cassette, int channels, double time_index,
+cassette_image::error cassette_image::write_samples(int channels, double time_index,
double sample_period, size_t sample_count, uint64_t offset, int waveform_flags)
{
- cassette_image::error err;
- size_t chunk_sample_count;
- size_t bytes_per_sample;
- size_t sample_spacing;
+ error err;
size_t samples_saved = 0;
- double chunk_time_index;
- double chunk_sample_period;
- int channel;
uint8_t buffer[8192];
- bytes_per_sample = waveform_bytes_per_sample(waveform_flags);
- sample_spacing = bytes_per_sample * channels;
+ size_t bytes_per_sample = waveform_bytes_per_sample(waveform_flags);
+ size_t sample_spacing = bytes_per_sample * channels;
- while(samples_saved < sample_count)
+ while (samples_saved < sample_count)
{
- chunk_sample_count = std::min(sizeof(buffer) / sample_spacing, (sample_count - samples_saved));
- chunk_sample_period = map_double(sample_period, 0, sample_count, chunk_sample_count);
- chunk_time_index = time_index + map_double(sample_period, 0, sample_count, samples_saved);
+ size_t chunk_sample_count = std::min(sizeof(buffer) / sample_spacing, (sample_count - samples_saved));
+ double chunk_sample_period = map_double(sample_period, 0, sample_count, chunk_sample_count);
+ double chunk_time_index = time_index + map_double(sample_period, 0, sample_count, samples_saved);
- for (channel = 0; channel < channels; channel++)
+ for (int channel = 0; channel < channels; channel++)
{
- err = cassette_get_samples(cassette, channel, chunk_time_index, chunk_sample_period,
+ err = get_samples(channel, chunk_time_index, chunk_sample_period,
chunk_sample_count, sample_spacing, &buffer[channel * bytes_per_sample], waveform_flags);
- if (err != cassette_image::error::SUCCESS)
+ if (err != error::SUCCESS)
return err;
}
- cassette_image_write(cassette, buffer, offset, chunk_sample_count * sample_spacing);
+ image_write(buffer, offset, chunk_sample_count * sample_spacing);
offset += chunk_sample_count * sample_spacing;
samples_saved += chunk_sample_count;
}
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
}
-/*********************************************************************
- waveform accesses to/from the raw image
-*********************************************************************/
-
-static const int8_t *choose_wave(const struct CassetteModulation *modulation, size_t *wave_bytes_length)
-{
- static const int8_t square_wave[] = { -128, 127 };
- static const int8_t sine_wave[] = { 0, 48, 89, 117, 127, 117, 89, 48, 0, -48, -89, -117, -127, -117, -89, -48 };
-
- if (modulation->flags & CASSETTE_MODULATION_SINEWAVE)
- {
- *wave_bytes_length = ARRAY_LENGTH(sine_wave);
- return sine_wave;
- }
- else
- {
- *wave_bytes_length = ARRAY_LENGTH(square_wave);
- return square_wave;
- }
-}
-
-
-
-cassette_image::error cassette_modulation_identify(cassette_image *cassette, const struct CassetteModulation *modulation,
- struct CassetteOptions *opts)
+cassette_image::error cassette_image::modulation_identify(const Modulation &modulation, Options *opts)
{
size_t wave_bytes_length;
- choose_wave(modulation, &wave_bytes_length);
+ choose_wave(modulation, wave_bytes_length);
opts->bits_per_sample = 8;
opts->channels = 1;
- opts->sample_frequency = (uint32_t) (std::max(modulation->zero_frequency_high, modulation->one_frequency_high) * wave_bytes_length * 2);
- return cassette_image::error::SUCCESS;
+ opts->sample_frequency = uint32_t(std::max(modulation.zero_frequency_high, modulation.one_frequency_high) * wave_bytes_length * 2);
+ return error::SUCCESS;
}
-cassette_image::error cassette_put_modulated_data(cassette_image *cassette, int channel, double time_index,
- const void *data, size_t data_length, const struct CassetteModulation *modulation,
+cassette_image::error cassette_image::put_modulated_data(int channel, double time_index,
+ const void *data, size_t data_length, const Modulation &modulation,
double *time_displacement)
{
- cassette_image::error err;
+ error err;
const uint8_t *data_bytes = (const uint8_t *)data;
- const int8_t *wave_bytes;
size_t wave_bytes_length;
double total_displacement = 0.0;
- double pulse_period;
- double pulse_frequency;
- uint8_t b;
- int i;
- wave_bytes = choose_wave(modulation, &wave_bytes_length);
+ const int8_t *wave_bytes = choose_wave(modulation, wave_bytes_length);
- while(data_length--)
+ while (data_length--)
{
- b = *(data_bytes++);
- for (i = 0; i < 8; i++)
+ uint8_t b = *(data_bytes++);
+ for (int i = 0; i < 8; i++)
{
- pulse_frequency = (b & (1 << i)) ? modulation->one_frequency_canonical : modulation->zero_frequency_canonical;
- pulse_period = 1 / pulse_frequency;
- err = cassette_put_samples(cassette, 0, time_index, pulse_period, wave_bytes_length, 1, wave_bytes, CASSETTE_WAVEFORM_8BIT);
- if (err != cassette_image::error::SUCCESS)
+ double pulse_frequency = (b & (1 << i)) ? modulation.one_frequency_canonical : modulation.zero_frequency_canonical;
+ double pulse_period = 1 / pulse_frequency;
+ err = put_samples(0, time_index, pulse_period, wave_bytes_length, 1, wave_bytes, WAVEFORM_8BIT);
+ if (err != error::SUCCESS)
goto done;
time_index += pulse_period;
total_displacement += pulse_period;
}
}
- err = cassette_image::error::SUCCESS;
+ err = error::SUCCESS;
done:
if (time_displacement)
@@ -744,18 +649,18 @@ done:
-cassette_image::error cassette_put_modulated_filler(cassette_image *cassette, int channel, double time_index,
- uint8_t filler, size_t filler_length, const struct CassetteModulation *modulation,
+cassette_image::error cassette_image::put_modulated_filler(int channel, double time_index,
+ uint8_t filler, size_t filler_length, const Modulation &modulation,
double *time_displacement)
{
- cassette_image::error err;
+ error err;
double delta;
double total_displacement = 0.0;
- while(filler_length--)
+ while (filler_length--)
{
- err = cassette_put_modulated_data(cassette, channel, time_index, &filler, 1, modulation, &delta);
- if (err != cassette_image::error::SUCCESS)
+ err = put_modulated_data(channel, time_index, &filler, 1, modulation, &delta);
+ if (err != error::SUCCESS)
return err;
total_displacement += delta;
time_index += delta;
@@ -763,24 +668,19 @@ cassette_image::error cassette_put_modulated_filler(cassette_image *cassette, in
if (time_displacement)
*time_displacement = total_displacement;
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
}
-cassette_image::error cassette_read_modulated_data(cassette_image *cassette, int channel, double time_index,
- uint64_t offset, uint64_t length, const struct CassetteModulation *modulation,
+cassette_image::error cassette_image::read_modulated_data(int channel, double time_index,
+ uint64_t offset, uint64_t length, const Modulation &modulation,
double *time_displacement)
{
- cassette_image::error err;
- uint8_t buffer_stack[1024];
uint8_t *buffer;
- uint8_t *alloc_buffer = nullptr;
- double delta;
- double total_displacement = 0.0;
- size_t this_length;
+ uint8_t buffer_stack[1024];
+ std::unique_ptr<uint8_t []> alloc_buffer;
size_t buffer_length;
-
if (length <= sizeof(buffer_stack))
{
buffer = buffer_stack;
@@ -789,23 +689,21 @@ cassette_image::error cassette_read_modulated_data(cassette_image *cassette, int
else
{
buffer_length = std::min<uint64_t>(length, 100000);
- alloc_buffer = (uint8_t*)malloc(buffer_length);
- if (!alloc_buffer)
- {
- err = cassette_image::error::OUT_OF_MEMORY;
- goto done;
- }
- buffer = alloc_buffer;
+ try { alloc_buffer = std::make_unique<uint8_t []>(buffer_length); }
+ catch (std::bad_alloc const &) { return error::OUT_OF_MEMORY; }
+ buffer = alloc_buffer.get();
}
- while(length > 0)
+ double delta;
+ double total_displacement = 0.0;
+ while (length > 0)
{
- this_length = (std::min<uint64_t>)(length, buffer_length);
- cassette_image_read(cassette, buffer, offset, this_length);
+ size_t this_length = std::min<uint64_t>(length, buffer_length);
+ image_read(buffer, offset, this_length);
- err = cassette_put_modulated_data(cassette, channel, time_index, buffer, this_length, modulation, &delta);
- if (err != cassette_image::error::SUCCESS)
- goto done;
+ error err = put_modulated_data(channel, time_index, buffer, this_length, modulation, &delta);
+ if (err != error::SUCCESS)
+ return err;
total_displacement += delta;
time_index += delta;
length -= this_length;
@@ -813,38 +711,30 @@ cassette_image::error cassette_read_modulated_data(cassette_image *cassette, int
if (time_displacement)
*time_displacement = total_displacement;
- err = cassette_image::error::SUCCESS;
-
-done:
- if (alloc_buffer)
- free(alloc_buffer);
- return err;
+ return error::SUCCESS;
}
-cassette_image::error cassette_put_modulated_data_bit(cassette_image *cassette, int channel, double time_index,
- uint8_t data, const struct CassetteModulation *modulation,
+cassette_image::error cassette_image::put_modulated_data_bit(int channel, double time_index,
+ uint8_t data, const Modulation &modulation,
double *time_displacement)
{
- cassette_image::error err;
- const int8_t *wave_bytes;
+ error err;
size_t wave_bytes_length;
double total_displacement = 0.0;
- double pulse_period;
- double pulse_frequency;
- wave_bytes = choose_wave(modulation, &wave_bytes_length);
+ const int8_t *wave_bytes = choose_wave(modulation, wave_bytes_length);
- pulse_frequency = (data) ? modulation->one_frequency_canonical : modulation->zero_frequency_canonical;
- pulse_period = 1 / pulse_frequency;
- err = cassette_put_samples(cassette, 0, time_index, pulse_period, wave_bytes_length, 1, wave_bytes, CASSETTE_WAVEFORM_8BIT);
- if (err != cassette_image::error::SUCCESS)
+ double pulse_frequency = (data) ? modulation.one_frequency_canonical : modulation.zero_frequency_canonical;
+ double pulse_period = 1 / pulse_frequency;
+ err = put_samples(0, time_index, pulse_period, wave_bytes_length, 1, wave_bytes, WAVEFORM_8BIT);
+ if (err != error::SUCCESS)
goto done;
time_index += pulse_period;
total_displacement += pulse_period;
- err = cassette_image::error::SUCCESS;
+ err = error::SUCCESS;
done:
if (time_displacement)
@@ -858,67 +748,63 @@ done:
waveform accesses to/from the raw image
*********************************************************************/
-cassette_image::error cassette_legacy_identify(cassette_image *cassette, struct CassetteOptions *opts,
- const struct CassetteLegacyWaveFiller *legacy_args)
+cassette_image::error cassette_image::legacy_identify(Options *opts,
+ const LegacyWaveFiller *legacy_args)
{
opts->channels = 1;
opts->bits_per_sample = 16;
opts->sample_frequency = legacy_args->sample_frequency;
- return cassette_image::error::SUCCESS;
+ return error::SUCCESS;
}
-cassette_image::error cassette_legacy_construct(cassette_image *cassette,
- const struct CassetteLegacyWaveFiller *legacy_args)
+cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *legacy_args)
{
- cassette_image::error err;
+ error err;
int length;
int sample_count;
std::vector<uint8_t> bytes;
- std::vector<uint8_t> chunk;
std::vector<int16_t> samples;
int pos = 0;
uint64_t offset = 0;
- uint64_t size;
- struct CassetteLegacyWaveFiller args;
/* sanity check the args */
assert(legacy_args->header_samples >= -1);
assert(legacy_args->trailer_samples >= 0);
assert(legacy_args->fill_wave);
- size = cassette_image_size(cassette);
+ uint64_t size = image_size();
/* normalize the args */
- args = *legacy_args;
+ LegacyWaveFiller args = *legacy_args;
if (args.chunk_size == 0)
args.chunk_size = 1;
else if (args.chunk_size < 0)
- args.chunk_size = cassette_image_size(cassette);
+ args.chunk_size = image_size();
if (args.sample_frequency == 0)
args.sample_frequency = 11025;
/* allocate a buffer for the binary data */
- chunk.resize(args.chunk_size);
+ std::vector<uint8_t> chunk(args.chunk_size);
/* determine number of samples */
if (args.chunk_sample_calc != nullptr)
{
if (size > 0x7FFFFFFF)
{
- err = cassette_image::error::OUT_OF_MEMORY;
+ err = error::OUT_OF_MEMORY;
goto done;
}
bytes.resize(size);
- cassette_image_read(cassette, &bytes[0], 0, size);
+ image_read(&bytes[0], 0, size);
sample_count = args.chunk_sample_calc(&bytes[0], (int)size);
// chunk_sample_calc functions report errors by returning negative numbers
if (sample_count < 0)
{
- err = cassette_image::error::INVALID_IMAGE;
+ err = error::INVALID_IMAGE;
goto done;
}
@@ -941,22 +827,22 @@ cassette_image::error cassette_legacy_construct(cassette_image *cassette,
length = args.fill_wave(&samples[pos], sample_count - pos, CODE_HEADER);
if (length < 0)
{
- err = cassette_image::error::INVALID_IMAGE;
+ err = error::INVALID_IMAGE;
goto done;
}
pos += length;
}
/* convert the file data to samples */
- while((pos < sample_count) && (offset < size))
+ while ((pos < sample_count) && (offset < size))
{
- cassette_image_read(cassette, &chunk[0], offset, args.chunk_size);
+ image_read(&chunk[0], offset, args.chunk_size);
offset += args.chunk_size;
length = args.fill_wave(&samples[pos], sample_count - pos, &chunk[0]);
if (length < 0)
{
- err = cassette_image::error::INVALID_IMAGE;
+ err = error::INVALID_IMAGE;
goto done;
}
pos += length;
@@ -970,23 +856,23 @@ cassette_image::error cassette_legacy_construct(cassette_image *cassette,
length = args.fill_wave(&samples[pos], sample_count - pos, CODE_TRAILER);
if (length < 0)
{
- err = cassette_image::error::INVALID_IMAGE;
+ err = error::INVALID_IMAGE;
goto done;
}
pos += length;
}
/* specify the wave */
- err = cassette_put_samples(cassette, 0, 0.0, ((double) pos) / args.sample_frequency,
- pos, 2, &samples[0], CASSETTE_WAVEFORM_16BIT);
- if (err != cassette_image::error::SUCCESS)
+ err = put_samples(0, 0.0, ((double) pos) / args.sample_frequency,
+ pos, 2, &samples[0], WAVEFORM_16BIT);
+ if (err != error::SUCCESS)
goto done;
/* success! */
- err = cassette_image::error::SUCCESS;
+ err = error::SUCCESS;
#if DUMP_CASSETTES
- cassette_dump(cassette, "C:\\TEMP\\CASDUMP.WAV");
+ dump("C:\\TEMP\\CASDUMP.WAV");
#endif
done:
@@ -1001,26 +887,22 @@ done:
A debugging call to dump a cassette image to a disk based wave file
*********************************************************************/
-void cassette_dump(cassette_image *image, const char *filename)
+void cassette_image::dump(const char *filename)
{
- FILE *f;
- struct io_generic saved_io;
- const struct CassetteFormat *saved_format;
-
- f = fopen(filename, "wb");
+ FILE *f = fopen(filename, "wb");
if (!f)
return;
- memcpy(&saved_io, &image->io, sizeof(saved_io));
- saved_format = image->format;
+ io_generic saved_io = m_io;
+ const Format *saved_format = m_format;
- image->io.file = f;
- image->io.procs = &stdio_ioprocs_noclose;
- image->format = &wavfile_format;
- cassette_perform_save(image);
+ m_io.file = f;
+ m_io.procs = &stdio_ioprocs_noclose;
+ m_format = &wavfile_format;
+ perform_save();
- memcpy(&image->io, &saved_io, sizeof(saved_io));
- image->format = saved_format;
+ m_io = saved_io;
+ m_format = saved_format;
fclose(f);
}
diff --git a/src/lib/formats/cassimg.h b/src/lib/formats/cassimg.h
index 5199c0e4a04..ed71c49cbf5 100644
--- a/src/lib/formats/cassimg.h
+++ b/src/lib/formats/cassimg.h
@@ -14,14 +14,15 @@
#include "ioprocs.h"
-#include "osdcore.h"
#include "coretmpl.h"
+#include "osdcore.h"
+#include <memory>
#include <string>
#include <vector>
#ifndef LOG_FORMATS
-#define LOG_FORMATS if (0) printf
+#define LOG_FORMATS(...) do { if (0) osd_printf_info(__VA_ARGS__); } while (false)
#endif
// hack to get around rogues that define this
@@ -31,65 +32,51 @@
/***************************************************************************
- Constants
+ Type definitions
***************************************************************************/
-#define CASSETTE_FLAG_READWRITE 0
-#define CASSETTE_FLAG_READONLY 1
-#define CASSETTE_FLAG_NOSAVEONEXIT 0
-#define CASSETTE_FLAG_SAVEONEXIT 2
-
-#define CASSETTE_WAVEFORM_8BIT 0
-#define CASSETTE_WAVEFORM_16BIT 2
-#define CASSETTE_WAVEFORM_16BIT_FLIP 3
-#define CASSETTE_WAVEFORM_32BIT 4
-#define CASSETTE_WAVEFORM_32BIT_FLIP 5
-#define CASSETTE_WAVEFORM_ENDIAN_FLIP 1
-#define CASSETTE_WAVEFORM_UNSIGNED 8
-
-#define CASSETTE_MODULATION_SQUAREWAVE 0
-#define CASSETTE_MODULATION_SINEWAVE 1
+class cassette_image
+{
+public:
+ enum : int
+ {
+ FLAG_READWRITE = 0,
+ FLAG_READONLY = 1,
+ FLAG_NOSAVEONEXIT = 0,
+ FLAG_SAVEONEXIT = 2
+ };
+ enum : int
+ {
+ WAVEFORM_8BIT = 0,
+ WAVEFORM_16BIT = 2,
+ WAVEFORM_16BIT_FLIP = 3,
+ WAVEFORM_32BIT = 4,
+ WAVEFORM_32BIT_FLIP = 5,
+ WAVEFORM_ENDIAN_FLIP = 1,
+ WAVEFORM_UNSIGNED = 8,
#ifdef LSB_FIRST
-#define CASSETTE_WAVEFORM_16BITBE CASSETTE_WAVEFORM_16BIT_FLIP
-#define CASSETTE_WAVEFORM_16BITLE CASSETTE_WAVEFORM_16BIT
-#define CASSETTE_WAVEFORM_32BITBE CASSETTE_WAVEFORM_32BIT_FLIP
-#define CASSETTE_WAVEFORM_32BITLE CASSETTE_WAVEFORM_32BIT
+ WAVEFORM_16BITBE = WAVEFORM_16BIT_FLIP,
+ WAVEFORM_16BITLE = WAVEFORM_16BIT,
+ WAVEFORM_32BITBE = WAVEFORM_32BIT_FLIP,
+ WAVEFORM_32BITLE = WAVEFORM_32BIT
#else
-#define CASSETTE_WAVEFORM_16BITBE CASSETTE_WAVEFORM_16BIT
-#define CASSETTE_WAVEFORM_16BITLE CASSETTE_WAVEFORM_16BIT_FLIP
-#define CASSETTE_WAVEFORM_32BITBE CASSETTE_WAVEFORM_32BIT
-#define CASSETTE_WAVEFORM_32BITLE CASSETTE_WAVEFORM_32BIT_FLIP
+ WAVEFORM_16BITBE = WAVEFORM_16BIT,
+ WAVEFORM_16BITLE = WAVEFORM_16BIT_FLIP,
+ WAVEFORM_32BITBE = WAVEFORM_32BIT,
+ WAVEFORM_32BITLE = WAVEFORM_32BIT_FLIP
#endif
+ };
+ enum : int
+ {
+ MODULATION_SQUAREWAVE = 0,
+ MODULATION_SINEWAVE = 1
+ };
-/***************************************************************************
-
- Type definitions
-
-***************************************************************************/
-
-typedef std::vector<int32_t> sample_block;
-
-struct CassetteOptions
-{
- int channels;
- int bits_per_sample;
- uint32_t sample_frequency;
-};
-
-struct CassetteInfo
-{
- int channels;
- int bits_per_sample;
- uint32_t sample_frequency;
- size_t sample_count;
-};
-struct cassette_image
-{
enum class error
{
SUCCESS, // no error
@@ -100,133 +87,156 @@ struct cassette_image
READ_WRITE_UNSUPPORTED // read/write is not supported by this image format
};
- const struct CassetteFormat *format;
- struct io_generic io;
+ using ptr = std::unique_ptr<cassette_image>;
- int channels;
- int flags;
- uint32_t sample_frequency;
+ struct Options
+ {
+ int channels = 0;
+ int bits_per_sample = 0;
+ uint32_t sample_frequency = 0;
+ };
- std::vector<sample_block *> blocks;
- size_t sample_count;
-};
+ struct Info
+ {
+ int channels = 0;
+ int bits_per_sample = 0;
+ uint32_t sample_frequency = 0;
+ size_t sample_count = 0;
+ };
-struct CassetteFormat
-{
- const char *extensions;
- cassette_image::error (*identify)(cassette_image *cassette, struct CassetteOptions *opts);
- cassette_image::error (*load)(cassette_image *cassette);
- cassette_image::error (*save)(cassette_image *cassette, const struct CassetteInfo *info);
-};
+ struct Format
+ {
+ const char *extensions = nullptr;
+ error (*identify)(cassette_image *cassette, Options *opts) = nullptr;
+ error (*load)(cassette_image *cassette) = nullptr;
+ error (*save)(cassette_image *cassette, const Info *info) = nullptr;
+ };
-/* used for the core modulation code */
-struct CassetteModulation
-{
- int flags;
- double zero_frequency_low;
- double zero_frequency_canonical;
- double zero_frequency_high;
- double one_frequency_low;
- double one_frequency_canonical;
- double one_frequency_high;
-};
+ /* used for the core modulation code */
+ struct Modulation
+ {
+ int flags = 0;
+ double zero_frequency_low = 0;
+ double zero_frequency_canonical = 0;
+ double zero_frequency_high = 0;
+ double one_frequency_low = 0;
+ double one_frequency_canonical = 0;
+ double one_frequency_high = 0;
+ };
-/* code to adapt existing legacy fill_wave functions */
-struct CassetteLegacyWaveFiller
-{
- int (*fill_wave)(int16_t *, int, uint8_t *);
- int chunk_size;
- int chunk_samples;
- int (*chunk_sample_calc)(const uint8_t *bytes, int length);
- uint32_t sample_frequency;
- int header_samples;
- int trailer_samples;
-};
+ /* code to adapt existing legacy fill_wave functions */
+ struct LegacyWaveFiller
+ {
+ int (*fill_wave)(int16_t *, int, uint8_t *) = nullptr;
+ int chunk_size = 0;
+ int chunk_samples = 0;
+ int (*chunk_sample_calc)(const uint8_t *bytes, int length) = nullptr;
+ uint32_t sample_frequency = 0;
+ int header_samples = 0;
+ int trailer_samples = 0;
+ };
+
+ ~cassette_image();
+
+ // calls for accessing the raw cassette image
+ void image_read(void *buffer, uint64_t offset, size_t length);
+ void image_write(const void *buffer, uint64_t offset, size_t length);
+ uint64_t image_size();
+
+ // waveform accesses
+ error get_samples(int channel,
+ double time_index, double sample_period, size_t sample_count, size_t sample_spacing,
+ void *samples, int waveform_flags);
+ error put_samples(int channel,
+ double time_index, double sample_period, size_t sample_count, size_t sample_spacing,
+ const void *samples, int waveform_flags);
+ error get_sample(int channel, double time_index, double sample_period, int32_t *sample);
+ error put_sample(int channel, double time_index, double sample_period, int32_t sample);
+
+ // waveform accesses to/from the raw image - these are only used by lib\formats\wavfile.cpp
+ error read_samples(int channels, double time_index,
+ double sample_period, size_t sample_count, uint64_t offset, int waveform_flags);
+ error write_samples(int channels, double time_index,
+ double sample_period, size_t sample_count, uint64_t offset, int waveform_flags);
+
+ // modulation support
+ error modulation_identify(const Modulation &modulation,
+ Options *opts);
+ error put_modulated_data(int channel, double time_index,
+ const void *data, size_t data_length, const Modulation &modulation,
+ double *time_displacement);
+ error put_modulated_filler(int channel, double time_index,
+ uint8_t filler, size_t filler_length, const Modulation &modulation,
+ double *time_displacement);
+ error read_modulated_data(int channel, double time_index,
+ uint64_t offset, uint64_t length, const Modulation &modulation,
+ double *time_displacement);
+ error put_modulated_data_bit(int channel, double time_index,
+ uint8_t data, const Modulation &modulation,
+ double *time_displacement);
+
+ /* legacy code support */
+#define CODE_HEADER ((uint8_t*)-1)
+#define CODE_TRAILER ((uint8_t*)-2)
+ error legacy_identify(Options *opts, const LegacyWaveFiller *legacy_args);
+ error legacy_construct(const LegacyWaveFiller *legacy_args);
+
+ /* debug calls */
+ void dump(const char *filename);
+
+ error save();
+ void change(void *file, const io_procs *procs, const Format *format, int flags);
+ Info get_info() const;
+
+ static error open(void *file, const io_procs *procs,
+ const Format *format, int flags, ptr &outcassette);
+ static error open_choices(void *file, const io_procs *procs, const std::string &extension,
+ const Format *const *formats, int flags, ptr &outcassette);
+ static error create(void *file, const io_procs *procs, const cassette_image::Format *format,
+ const cassette_image::Options *opts, int flags, ptr &outcassette);
-/* builtin formats */
-extern const struct CassetteFormat wavfile_format;
+ // builtin formats
+ static const Format wavfile_format;
+
+private:
+ struct manipulation_ranges;
+
+ cassette_image(const Format *format, void *file, const io_procs *procs, int flags);
+ cassette_image(const cassette_image &) = delete;
+ cassette_image(cassette_image &&) = delete;
+ cassette_image &operator=(const cassette_image &) = delete;
+ cassette_image &operator=(cassette_image &&) = delete;
+
+ error try_identify_format(const Format &format, const std::string &extension, int flags, Options &opts);
+ error perform_save();
+ error compute_manipulation_ranges(int channel, double time_index, double sample_period, manipulation_ranges &ranges) const;
+ error lookup_sample(int channel, size_t sample, int32_t *&ptr);
+
+ const Format *m_format = nullptr;
+ io_generic m_io;
+
+ int m_channels = 0;
+ int m_flags = 0;
+ uint32_t m_sample_frequency = 0;
+
+ std::vector<std::unique_ptr<int32_t []> > m_blocks;
+ size_t m_sample_count = 0;
+};
/* macros for specifying format lists */
#define CASSETTE_FORMATLIST_EXTERN(name) \
- extern const struct CassetteFormat *const name[]
+ extern const cassette_image::Format *const name[]
#define CASSETTE_FORMATLIST_START(name) \
- const struct CassetteFormat *const name[] = \
+ const cassette_image::Format *const name[] = \
{ \
- &wavfile_format,
+ &cassette_image::wavfile_format,
#define CASSETTE_FORMAT(name) \
&(name),
#define CASSETTE_FORMATLIST_END \
- nullptr \
+ nullptr \
};
CASSETTE_FORMATLIST_EXTERN(cassette_default_formats);
-/***************************************************************************
-
- Prototypes
-
-***************************************************************************/
-
-cassette_image::error cassette_open(void *file, const struct io_procs *procs,
- const struct CassetteFormat *format, int flags, cassette_image **outcassette);
-cassette_image::error cassette_open_choices(void *file, const struct io_procs *procs, const std::string &extension,
- const struct CassetteFormat *const *formats, int flags, cassette_image **outcassette);
-cassette_image::error cassette_create(void *file, const struct io_procs *procs, const struct CassetteFormat *format,
- const struct CassetteOptions *opts, int flags, cassette_image **outcassette);
-cassette_image::error cassette_save(cassette_image *cassette);
-void cassette_close(cassette_image *cassette);
-void cassette_change(cassette_image *cassette, void *file, const struct io_procs *procs, const struct CassetteFormat *format, int flags);
-void cassette_get_info(cassette_image *cassette, struct CassetteInfo *info);
-
-/* calls for accessing the raw cassette image */
-void cassette_image_read(cassette_image *cassette, void *buffer, uint64_t offset, size_t length);
-void cassette_image_write(cassette_image *cassette, const void *buffer, uint64_t offset, size_t length);
-uint64_t cassette_image_size(cassette_image *cassette);
-
-/* waveform accesses */
-cassette_image::error cassette_get_samples(cassette_image *cassette, int channel,
- double time_index, double sample_period, size_t sample_count, size_t sample_spacing,
- void *samples, int waveform_flags);
-cassette_image::error cassette_put_samples(cassette_image *cassette, int channel,
- double time_index, double sample_period, size_t sample_count, size_t sample_spacing,
- const void *samples, int waveform_flags);
-cassette_image::error cassette_get_sample(cassette_image *cassette, int channel,
- double time_index, double sample_period, int32_t *sample);
-cassette_image::error cassette_put_sample(cassette_image *cassette, int channel,
- double time_index, double sample_period, int32_t sample);
-
-/* waveform accesses to/from the raw image - these are only used by lib\formats\wavfile.cpp */
-cassette_image::error cassette_read_samples(cassette_image *cassette, int channels, double time_index,
- double sample_period, size_t sample_count, uint64_t offset, int waveform_flags);
-cassette_image::error cassette_write_samples(cassette_image *cassette, int channels, double time_index,
- double sample_period, size_t sample_count, uint64_t offset, int waveform_flags);
-
-/* modulation support */
-cassette_image::error cassette_modulation_identify(cassette_image *cassette, const struct CassetteModulation *modulation,
- struct CassetteOptions *opts);
-cassette_image::error cassette_put_modulated_data(cassette_image *cassette, int channel, double time_index,
- const void *data, size_t data_length, const struct CassetteModulation *modulation,
- double *time_displacement);
-cassette_image::error cassette_put_modulated_filler(cassette_image *cassette, int channel, double time_index,
- uint8_t filler, size_t filler_length, const struct CassetteModulation *modulation,
- double *time_displacement);
-cassette_image::error cassette_read_modulated_data(cassette_image *cassette, int channel, double time_index,
- uint64_t offset, uint64_t length, const struct CassetteModulation *modulation,
- double *time_displacement);
-cassette_image::error cassette_put_modulated_data_bit(cassette_image *cassette, int channel, double time_index,
- uint8_t data, const struct CassetteModulation *modulation,
- double *time_displacement);
-
-/* debug calls */
-void cassette_dump(cassette_image *image, const char *filename);
-
-/* legacy code support */
-#define CODE_HEADER ((uint8_t*)-1)
-#define CODE_TRAILER ((uint8_t*)-2)
-cassette_image::error cassette_legacy_identify(cassette_image *cassette, struct CassetteOptions *opts,
- const struct CassetteLegacyWaveFiller *legacy_args);
-cassette_image::error cassette_legacy_construct(cassette_image *cassette,
- const struct CassetteLegacyWaveFiller *legacy_args);
-
#endif // MAME_FORMATS_CASSIMG_H
diff --git a/src/lib/formats/cbm_tap.cpp b/src/lib/formats/cbm_tap.cpp
index 7ef8015c6f9..542c0c3ea87 100644
--- a/src/lib/formats/cbm_tap.cpp
+++ b/src/lib/formats/cbm_tap.cpp
@@ -339,7 +339,7 @@ static int cbm_tap_fill_wave( int16_t *buffer, int length, uint8_t *bytes )
-static const struct CassetteLegacyWaveFiller cbm_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller cbm_legacy_fill_wave = {
cbm_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -350,19 +350,19 @@ static const struct CassetteLegacyWaveFiller cbm_legacy_fill_wave = {
};
-static cassette_image::error cbm_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts )
+static cassette_image::error cbm_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )
{
- return cassette_legacy_identify( cassette, opts, &cbm_legacy_fill_wave );
+ return cassette->legacy_identify( opts, &cbm_legacy_fill_wave );
}
static cassette_image::error cbm_cassette_load( cassette_image *cassette )
{
- return cassette_legacy_construct( cassette, &cbm_legacy_fill_wave );
+ return cassette->legacy_construct( &cbm_legacy_fill_wave );
}
-static const struct CassetteFormat cbm_tap_cassette_format = {
+static const cassette_image::Format cbm_tap_cassette_format = {
"tap",
cbm_cassette_identify,
cbm_cassette_load,
diff --git a/src/lib/formats/cgen_cas.cpp b/src/lib/formats/cgen_cas.cpp
index de47a45375d..8a208044960 100644
--- a/src/lib/formats/cgen_cas.cpp
+++ b/src/lib/formats/cgen_cas.cpp
@@ -18,10 +18,10 @@ NOTE: There exist multiples type of .cas files for Colour Genie
We now support these three types below...
********************************************************************/
+#include "formats/cgen_cas.h"
#include <cassert>
-#include "formats/cgen_cas.h"
#define TAPE_HEADER "Colour Genie - Virtual Tape File"
@@ -124,7 +124,7 @@ static int cgenie_cas_to_wav_size(const uint8_t *casdata, int caslen)
return cgenie_handle_cas(nullptr, casdata);
}
-static const struct CassetteLegacyWaveFiller cgenie_cas_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller cgenie_cas_legacy_fill_wave =
{
cgenie_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -136,19 +136,19 @@ static const struct CassetteLegacyWaveFiller cgenie_cas_legacy_fill_wave =
};
-static cassette_image::error cgenie_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error cgenie_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &cgenie_cas_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &cgenie_cas_legacy_fill_wave);
}
static cassette_image::error cgenie_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &cgenie_cas_legacy_fill_wave);
+ return cassette->legacy_construct(&cgenie_cas_legacy_fill_wave);
}
-static const struct CassetteFormat cgenie_cas_format =
+static const cassette_image::Format cgenie_cas_format =
{
"cas",
cgenie_cas_identify,
diff --git a/src/lib/formats/coco_cas.cpp b/src/lib/formats/coco_cas.cpp
index f3df09266b0..c0ed5d616ff 100644
--- a/src/lib/formats/coco_cas.cpp
+++ b/src/lib/formats/coco_cas.cpp
@@ -47,18 +47,18 @@
static int synccount;
-const struct CassetteModulation coco_cas_modulation =
+const cassette_image::Modulation coco_cas_modulation =
{
- CASSETTE_MODULATION_SINEWAVE,
+ cassette_image::MODULATION_SINEWAVE,
600.0, 1200.0, 1500.0,
1500.0, 2400.0, 3000.0
};
-static cassette_image::error coco_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error coco_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_modulation_identify(cassette, &coco_cas_modulation, opts);
+ return cassette->modulation_identify(coco_cas_modulation, opts);
}
@@ -76,12 +76,12 @@ static bool get_cas_block(cassette_image *cassette, uint64_t *offset, uint8_t *b
synccount = 0;
p.w.l = 0;
- image_size = cassette_image_size(cassette);
+ image_size = cassette->image_size();
current_offset = *offset;
while(current_offset < image_size)
{
- cassette_image_read(cassette, &p.b.h, current_offset, 1);
+ cassette->image_read(&p.b.h, current_offset, 1);
current_offset++;
for (i = 0; i < 8; i++)
@@ -192,18 +192,18 @@ static cassette_image::error cas_load(cassette_image *cassette, uint8_t silence)
0x3C, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A
};
time_index = 10.0;
- return cassette_put_modulated_data(cassette, 0, time_index, dummy_bytes, sizeof(dummy_bytes), &coco_cas_modulation, &time_displacement);
+ return cassette_put_modulated_data(cassette, 0, time_index, dummy_bytes, sizeof(dummy_bytes), coco_cas_modulation, &time_displacement);
}
#endif
- err = cassette_put_sample(cassette, 0, time_index, COCO_WAVESAMPLES_HEADER, 0);
+ err = cassette->put_sample(0, time_index, COCO_WAVESAMPLES_HEADER, 0);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += COCO_WAVESAMPLES_HEADER;
offset = 0;
last_blocktype = 0;
- image_size = cassette_image_size(cassette);
+ image_size = cassette->image_size();
/* try to find a block that we can untangle */
while(get_cas_block(cassette, &offset, block, &block_length))
@@ -214,13 +214,13 @@ static cassette_image::error cas_load(cassette_image *cassette, uint8_t silence)
if ((last_blocktype == 0) || (last_blocktype == 0xFF) || (block[0] == 0))
{
/* silence */
- err = cassette_put_sample(cassette, 0, time_index, silence, 0);
+ err = cassette->put_sample(0, time_index, silence, 0);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += silence;
/* sync data */
- err = cassette_put_modulated_filler(cassette, 0, time_index, 0x55, 128, &coco_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_filler(0, time_index, 0x55, 128, coco_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += time_displacement;
@@ -228,26 +228,26 @@ static cassette_image::error cas_load(cassette_image *cassette, uint8_t silence)
else if (synccount != 0) /* If we have multiple sync bytes in cas file, make sure they */
{ /* are passed through */
/* sync data */
- err = cassette_put_modulated_filler(cassette, 0, time_index, 0x55, synccount, &coco_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_filler(0, time_index, 0x55, synccount, coco_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += time_displacement;
}
/* now fill in the magic bytes */
- err = cassette_put_modulated_data(cassette, 0, time_index, magic_bytes, sizeof(magic_bytes), &coco_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_data(0, time_index, magic_bytes, sizeof(magic_bytes), coco_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += time_displacement;
/* now fill in the block */
- err = cassette_put_modulated_data(cassette, 0, time_index, block, block_length, &coco_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_data(0, time_index, block, block_length, coco_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += time_displacement;
/* and the last magic byte */
- err = cassette_put_modulated_filler(cassette, 0, time_index, 0x55, 1, &coco_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_filler(0, time_index, 0x55, 1, coco_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += time_displacement;
@@ -256,7 +256,7 @@ static cassette_image::error cas_load(cassette_image *cassette, uint8_t silence)
}
/* all futher data is undecipherable, so output it verbatim */
- err = cassette_read_modulated_data(cassette, 0, time_index, offset, image_size - offset, &coco_cas_modulation, &time_displacement);
+ err = cassette->read_modulated_data(0, time_index, offset, image_size - offset, coco_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS)
return err;
time_index += time_displacement;
@@ -274,7 +274,7 @@ static cassette_image::error alice32_cas_load(cassette_image *cassette)
return cas_load(cassette, ALICE32_WAVESAMPLES_HEADER);
}
-const struct CassetteFormat coco_cas_format =
+const cassette_image::Format coco_cas_format =
{
"cas",
coco_cas_identify,
@@ -282,7 +282,7 @@ const struct CassetteFormat coco_cas_format =
nullptr
};
-const struct CassetteFormat alice32_cas_format =
+const cassette_image::Format alice32_cas_format =
{
"cas,c10,k7",
coco_cas_identify,
diff --git a/src/lib/formats/csw_cas.cpp b/src/lib/formats/csw_cas.cpp
index 9edea5c3ff7..3db3eb70c34 100644
--- a/src/lib/formats/csw_cas.cpp
+++ b/src/lib/formats/csw_cas.cpp
@@ -1,294 +1,218 @@
// license:BSD-3-Clause
-// copyright-holders:Gordon Jefferyes
+// copyright-holders:Nigel Barnes
/*
-CSW format
-----------
-Header Description
-
-Offset Value Type Description
-0x00 (note) ASCII 22 bytes "Compressed Square Wave" signature
-0x16 0x1A BYTE Terminator code
-0x17 0x02 BYTE CSW major revision number
-0x18 0x00 BYTE CSW minor revision number
-0x19 DWORD Sample rate
-0x1D DWORD Total number of pulses (after decompression)
-0x21 BYTE Compression type 0x01: RLE 0x02: Z-RLE
-0x22 BYTE Flags b0: initial polarity: if set, the signal starts at logical high
-0x23 HDR BYTE Header extension length in bytes (0x00)
-0x24 ASCII 16 bytes free use
-0x34 BYTE Start of Header is HDR>0
-
-
-
+ CSW format
+ ----------
+ Header Description
+
+ Offset Value Type Description
+ 0x00 (note) ASCII 22 bytes "Compressed Square Wave" signature
+ 0x16 0x1A BYTE Terminator code
+ 0x17 0x02 BYTE CSW major revision number
+ 0x18 0x00 BYTE CSW minor revision number
+ 0x19 DWORD Sample rate
+ 0x1D DWORD Total number of pulses (after decompression)
+ 0x21 BYTE Compression type 0x01: RLE 0x02: Z-RLE
+ 0x22 BYTE Flags b0: initial polarity; if set, the signal starts at logical high
+ 0x23 HDR BYTE Header extension length in bytes (0x00)
+ 0x24 ASCII Encoding application description
+ 0x34 BYTE Header extension data (if present HDR>0)
+ 0x34+HDR CSW data
*/
-#include <cstring>
+#include "csw_cas.h"
+#include "uef_cas.h"
#include <zlib.h>
-#include <cassert>
-#include "uef_cas.h"
-#include "csw_cas.h"
+#include <cassert>
+#include <cstring>
-#define CSW_WAV_FREQUENCY 44100
static const uint8_t CSW_HEADER[] = { "Compressed Square Wave" };
-static uint32_t get_leuint32(const void *ptr)
-{
- uint32_t value;
- memcpy(&value, ptr, sizeof(value));
- return little_endianize_int32(value);
-}
-static int mycaslen;
+/*-------------------------------------------------
+ csw_cassette_identify - identify cassette
+-------------------------------------------------*/
-static int csw_cas_to_wav_size( const uint8_t *casdata, int caslen )
+static cassette_image::error csw_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- uint8_t MajorRevision;
- uint8_t MinorRevision;
- uint8_t HeaderExtensionLength;
- std::vector<uint8_t> gz_ptr;
-
- int total_size;
- z_stream d_stream;
- int err;
- uint8_t *in_ptr;
- int bsize=0;
-
- if ( memcmp( casdata, CSW_HEADER, sizeof(CSW_HEADER)-1 ) )
- {
- LOG_FORMATS( "csw_cas_to_wav_size: cassette image has incompatible header\n" );
- goto cleanup;
- }
+ uint8_t header[0x34];
- if (casdata[0x16]!=0x1a)
- {
- LOG_FORMATS( "csw_cas_to_wav_size: Terminator Code Not Found\n" );
- goto cleanup;
+ cassette->image_read(header, 0, sizeof(header));
+ if (memcmp(&header[0], CSW_HEADER, sizeof(CSW_HEADER) - 1)) {
+ return cassette_image::error::INVALID_IMAGE;
}
- MajorRevision=casdata[0x17];
- MinorRevision=casdata[0x18];
+ opts->bits_per_sample = 8;
+ opts->channels = 1;
+ opts->sample_frequency = little_endianize_int16(*(uint32_t*)(header + 0x19));
+ return cassette_image::error::SUCCESS;
+}
+
- LOG_FORMATS("Version %d : %d\n",MajorRevision,MinorRevision);
+/*-------------------------------------------------
+ csw_cassette_load - load cassette
+-------------------------------------------------*/
- if (casdata[0x17]!=2)
+static cassette_image::error csw_cassette_load(cassette_image *cassette)
+{
+ uint8_t header[0x34];
+ uint64_t image_size = cassette->image_size();
+ std::vector<uint8_t> image_data(image_size);
+
+ int8_t bit;
+ uint8_t compression;
+ int bsize = 0;
+ size_t csw_data = 0;
+ size_t sample_count = 0;
+ uint32_t sample_rate;
+ std::vector<int8_t> samples;
+
+ /* csw header */
+ cassette->image_read(header, 0, sizeof(header));
+
+ if (header[0x16] != 0x1a)
{
- LOG_FORMATS( "csw_cas_to_wav_size: Unsuported Major Version\n" );
- goto cleanup;
+ LOG_FORMATS("csw_cassette_load: Terminator Code Not Found\n");
+ return cassette_image::error::INVALID_IMAGE;
}
- HeaderExtensionLength=casdata[0x23];
-
- mycaslen=caslen;
- //from here on down for now I am assuming it is compressed csw file.
- in_ptr = (uint8_t*) casdata+0x34+HeaderExtensionLength;
-
- gz_ptr.resize( 8 );
-
- d_stream.next_in = (unsigned char *)in_ptr;
- d_stream.avail_in = caslen - ( in_ptr - casdata );
- d_stream.total_in=0;
-
- d_stream.next_out = &gz_ptr[0];
- d_stream.avail_out = 1;
- d_stream.total_out=0;
-
- d_stream.zalloc = nullptr;
- d_stream.zfree = nullptr;
- d_stream.opaque = nullptr;
- d_stream.data_type=0;
-
- err = inflateInit( &d_stream );
- if ( err != Z_OK )
+ LOG_FORMATS("CSW Version %d.%d\n", header[0x17], header[0x18]);
+ switch (header[0x17])
{
- LOG_FORMATS( "inflateInit2 error: %d\n", err );
- goto cleanup;
+ case 1:
+ sample_rate = little_endianize_int16(*(uint32_t*)(header + 0x19));
+ compression = header[0x1b];
+ bit = (header[0x1c] & 1) ? 127 : -128;
+ csw_data = 0x20;
+
+ LOG_FORMATS("Sample Rate: %u\n", sample_rate);
+ LOG_FORMATS("CompressionType: %u Flags: %u\n", header[0x1b], header[0x1c]);
+ break;
+
+ case 2:
+ sample_rate = little_endianize_int32(*(uint32_t*)(header + 0x19));
+ compression = header[0x21];
+ bit = (header[0x22] & 1) ? 127 : -128;
+ csw_data = (size_t) header[0x23] + 0x34;
+
+ LOG_FORMATS("Sample Rate: %u\n", sample_rate);
+ LOG_FORMATS("Number of Pulses: %u\n", little_endianize_int32(*(uint32_t *)(header + 0x1d)));
+ LOG_FORMATS("CompressionType: %u Flags: %u\n", header[0x21], header[0x22]);
+ LOG_FORMATS("Encoder: ");
+ for (int i = 0; i < 16; i++)
+ LOG_FORMATS("%c", header[0x24 + i]);
+ LOG_FORMATS("\n");
+ break;
+
+ default:
+ LOG_FORMATS("Unsupported Major Version\n");
+ return cassette_image::error::INVALID_IMAGE;
}
-
-
- total_size=1;
- do
+
+ /* csw data */
+ switch (compression)
{
- d_stream.next_out = &gz_ptr[0];
- d_stream.avail_out=1;
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- if (err==Z_OK)
+ case 0x01:
+ /* RLE (Run Length Encoding) */
+ for (size_t pos = csw_data; pos < image_size; pos++)
{
- bsize=gz_ptr[0];
- if (bsize==0)
+ bsize = image_data[pos];
+ if (bsize == 0)
+ {
+ bsize = little_endianize_int32(*(uint32_t *)(&image_data[pos + 1]));
+ pos += 4;
+ }
+ for (int i = 0; i < bsize; i++)
{
- d_stream.avail_out=4;
- d_stream.next_out = &gz_ptr[0];
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- bsize=get_leuint32(&gz_ptr[0]);
+ samples.resize(sample_count + 1);
+ samples[sample_count++] = bit;
}
- total_size=total_size+bsize;
+ bit ^= 0xff;
}
- }
- while (err==Z_OK);
-
- if ( err != Z_STREAM_END )
- {
- LOG_FORMATS( "inflate error: %d\n", err );
- goto cleanup;
- }
-
- err = inflateEnd( &d_stream );
- if ( err != Z_OK )
- {
- LOG_FORMATS( "inflateEnd error: %d\n", err );
- goto cleanup;
- }
-
- return total_size;
-
-cleanup:
- return -1;
-}
-
-static int csw_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes )
-{
- uint32_t SampleRate;
- uint32_t NumberOfPulses;
- uint8_t CompressionType;
- uint8_t Flags;
- uint8_t HeaderExtensionLength;
- int8_t Bit;
-
- std::vector<uint8_t> gz_ptr;
- int total_size;
- z_stream d_stream;
- int err;
- uint8_t *in_ptr;
- int bsize=0;
- int i;
-
- LOG_FORMATS("Length %d\n",length);
-
- SampleRate=get_leuint32(bytes+0x19);
- LOG_FORMATS("Sample rate %u\n",SampleRate);
-
- NumberOfPulses=get_leuint32(bytes+0x1d);
- LOG_FORMATS("Number Of Pulses %u\n",NumberOfPulses);
-
- CompressionType=bytes[0x21];
- Flags=bytes[0x22];
- HeaderExtensionLength=bytes[0x23];
-
- Bit = (Flags & 1) ? 100 : -100;
-
- LOG_FORMATS("CompressionType %u Flags %u HeaderExtensionLength %u\n",CompressionType,Flags,HeaderExtensionLength);
-
- LOG_FORMATS("Encoder: ");
- for (i = 0; i < 16; i++)
- LOG_FORMATS("%c", bytes[0x24 + i]);
- LOG_FORMATS("\n");
-
- LOG_FORMATS("Header: ");
- for (i = 0; i < HeaderExtensionLength; i++)
- LOG_FORMATS("%c", bytes[0x34 + i]);
- LOG_FORMATS("\n");
-
- //from here on down for now I am assuming it is compressed csw file.
- in_ptr = (uint8_t*) bytes+0x34+HeaderExtensionLength;
-
- gz_ptr.resize( 8 );
-
- d_stream.next_in = (unsigned char *)in_ptr;
- d_stream.avail_in = mycaslen - ( in_ptr - bytes );
- d_stream.total_in=0;
-
- d_stream.next_out = &gz_ptr[0];
- d_stream.avail_out = 1;
- d_stream.total_out=0;
-
- d_stream.zalloc = nullptr;
- d_stream.zfree = nullptr;
- d_stream.opaque = nullptr;
- d_stream.data_type=0;
+ break;
+
+ case 0x02:
+ /* Z-RLE (CSW v2.xx only) */
+ cassette->image_read(&image_data[0], 0, image_size);
+
+ std::vector<uint8_t> gz_ptr;
+ z_stream d_stream;
+ int err;
+
+ gz_ptr.resize(8);
+
+ d_stream.next_in = (unsigned char *) &image_data[csw_data];
+ d_stream.avail_in = image_size - 0x34 - header[0x23];
+ d_stream.total_in = 0;
+
+ d_stream.next_out = &gz_ptr[0];
+ d_stream.avail_out = 1;
+ d_stream.total_out = 0;
- err = inflateInit( &d_stream );
- if ( err != Z_OK )
- {
- LOG_FORMATS( "inflateInit2 error: %d\n", err );
- goto cleanup;
- }
+ d_stream.zalloc = nullptr;
+ d_stream.zfree = nullptr;
+ d_stream.opaque = nullptr;
+ d_stream.data_type = 0;
- total_size=0;
+ err = inflateInit(&d_stream);
+ if (err != Z_OK)
+ {
+ LOG_FORMATS("inflateInit error: %d\n", err);
+ return cassette_image::error::INVALID_IMAGE;
+ }
- do
- {
- d_stream.next_out = &gz_ptr[0];
- d_stream.avail_out=1;
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- if (err==Z_OK)
+ do
{
- bsize=gz_ptr[0];
- if (bsize==0)
+ d_stream.next_out = &gz_ptr[0];
+ d_stream.avail_out = 1;
+ err = inflate(&d_stream, Z_SYNC_FLUSH);
+ if (err == Z_OK)
{
- d_stream.avail_out=4;
- d_stream.next_out = &gz_ptr[0];
- err=inflate( &d_stream, Z_SYNC_FLUSH );
- bsize=get_leuint32(&gz_ptr[0]);
+ bsize = gz_ptr[0];
+ if (bsize == 0)
+ {
+ d_stream.avail_out = 4;
+ d_stream.next_out = &gz_ptr[0];
+ err = inflate(&d_stream, Z_SYNC_FLUSH);
+ bsize = little_endianize_int32(*(uint32_t *)(&gz_ptr[0]));
+ }
+ for (int i = 0; i < bsize; i++)
+ {
+ samples.resize(sample_count + 1);
+ samples[sample_count++] = bit;
+ }
+ bit ^= 0xff;
}
- for (i=0;i<bsize;i++)
- {
- buffer[total_size++]=Bit;
- }
- Bit=-Bit;
- }
- }
- while (err==Z_OK);
+ }
+ while (err == Z_OK);
- if ( err != Z_STREAM_END )
- {
- LOG_FORMATS( "inflate error: %d\n", err );
- goto cleanup;
- }
+ if (err != Z_STREAM_END)
+ {
+ LOG_FORMATS("inflate error: %d\n", err);
+ return cassette_image::error::INVALID_IMAGE;
+ }
- err = inflateEnd( &d_stream );
- if ( err != Z_OK )
- {
- LOG_FORMATS( "inflateEnd error: %d\n", err );
- goto cleanup;
+ err = inflateEnd(&d_stream);
+ if (err != Z_OK)
+ {
+ LOG_FORMATS("inflateEnd error: %d\n", err);
+ return cassette_image::error::INVALID_IMAGE;
+ }
+ break;
}
- return length;
-
-cleanup:
- return -1;
+ return cassette->put_samples(0, 0.0, (double) sample_count / sample_rate, sample_count, 1, &samples[0], cassette_image::WAVEFORM_8BIT);
}
-static const struct CassetteLegacyWaveFiller csw_legacy_fill_wave = {
- csw_cas_fill_wave, /* fill_wave */
- -1, /* chunk_size */
- 0, /* chunk_samples */
- csw_cas_to_wav_size, /* chunk_sample_calc */
- CSW_WAV_FREQUENCY, /* sample_frequency */
- 0, /* header_samples */
- 0 /* trailer_samples */
-};
-
-static cassette_image::error csw_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts )
-{
- uint8_t header[22];
-
- cassette_image_read(cassette, header, 0, sizeof(header));
- if (memcmp(&header[0], CSW_HEADER, sizeof(CSW_HEADER) - 1)) {
- return cassette_image::error::INVALID_IMAGE;
- }
- return cassette_legacy_identify( cassette, opts, &csw_legacy_fill_wave );
-}
-
-static cassette_image::error csw_cassette_load( cassette_image *cassette )
-{
- return cassette_legacy_construct( cassette, &csw_legacy_fill_wave );
-}
+/*-------------------------------------------------
+ CassetteFormat csw_cassette_format
+-------------------------------------------------*/
-const struct CassetteFormat csw_cassette_format = {
+const cassette_image::Format csw_cassette_format = {
"csw",
csw_cassette_identify,
csw_cassette_load,
diff --git a/src/lib/formats/csw_cas.h b/src/lib/formats/csw_cas.h
index e6e5a62d764..270d85bcd37 100644
--- a/src/lib/formats/csw_cas.h
+++ b/src/lib/formats/csw_cas.h
@@ -12,7 +12,7 @@
#include "cassimg.h"
-extern const struct CassetteFormat csw_cassette_format;
+extern const cassette_image::Format csw_cassette_format;
CASSETTE_FORMATLIST_EXTERN(csw_cassette_formats);
CASSETTE_FORMATLIST_EXTERN(bbc_cassette_formats);
diff --git a/src/lib/formats/fc100_cas.cpp b/src/lib/formats/fc100_cas.cpp
index 42b99ad3f0e..56c7b8294db 100644
--- a/src/lib/formats/fc100_cas.cpp
+++ b/src/lib/formats/fc100_cas.cpp
@@ -10,10 +10,10 @@ it's all a guess.
********************************************************************/
-#include <cassert>
-
#include "fc100_cas.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -21,7 +21,7 @@ it's all a guess.
#define FC100_HEADER_BYTES 16
// image size
-static int fc100_image_size;
+static int fc100_image_size; // FIXME: global variable prevents multiple instances
static int fc100_put_samples(int16_t *buffer, int sample_pos, int count, int level)
{
@@ -122,7 +122,7 @@ static int fc100_cassette_calculate_size_in_samples(const uint8_t *bytes, int le
return fc100_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller fc100_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller fc100_legacy_fill_wave =
{
fc100_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -133,17 +133,17 @@ static const struct CassetteLegacyWaveFiller fc100_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error fc100_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error fc100_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &fc100_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &fc100_legacy_fill_wave);
}
static cassette_image::error fc100_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &fc100_legacy_fill_wave);
+ return cassette->legacy_construct(&fc100_legacy_fill_wave);
}
-static const struct CassetteFormat fc100_cassette_image_format =
+static const cassette_image::Format fc100_cassette_image_format =
{
"cas",
fc100_cassette_identify,
diff --git a/src/lib/formats/fm7_cas.cpp b/src/lib/formats/fm7_cas.cpp
index f275866d31b..a0c0151be7b 100644
--- a/src/lib/formats/fm7_cas.cpp
+++ b/src/lib/formats/fm7_cas.cpp
@@ -4,14 +4,14 @@
* Fujitsu FM-7 series cassette handling
*/
-#include <cassert>
-
#include "fm7_cas.h"
+#include <cassert>
+
#define WAVE_HIGH 0x5a9e
#define WAVE_LOW -0x5a9e
-static int cas_size;
+static int cas_size; // FIXME: global variable prevents multiple instances
static int fm7_fill_wave(int16_t* buffer, uint8_t high, uint8_t low, int sample_pos)
{
@@ -76,7 +76,7 @@ static int fm7_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes)
return fm7_handle_t77(buffer,bytes);
}
-static const struct CassetteLegacyWaveFiller fm7_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller fm7_legacy_fill_wave =
{
fm7_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -87,20 +87,20 @@ static const struct CassetteLegacyWaveFiller fm7_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error fm7_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error fm7_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &fm7_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &fm7_legacy_fill_wave);
}
static cassette_image::error fm7_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &fm7_legacy_fill_wave);
+ return cassette->legacy_construct(&fm7_legacy_fill_wave);
}
-static const struct CassetteFormat fm7_cassette_format = {
+static const cassette_image::Format fm7_cassette_format = {
"t77",
fm7_cas_identify,
fm7_cas_load,
diff --git a/src/lib/formats/fmsx_cas.cpp b/src/lib/formats/fmsx_cas.cpp
index 3b00b81dc92..7bda85782b5 100644
--- a/src/lib/formats/fmsx_cas.cpp
+++ b/src/lib/formats/fmsx_cas.cpp
@@ -104,7 +104,7 @@ static int fmsx_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes)
}
-static const struct CassetteLegacyWaveFiller fmsx_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller fmsx_legacy_fill_wave =
{
fmsx_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -117,21 +117,21 @@ static const struct CassetteLegacyWaveFiller fmsx_legacy_fill_wave =
-static cassette_image::error fmsx_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error fmsx_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &fmsx_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &fmsx_legacy_fill_wave);
}
static cassette_image::error fmsx_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &fmsx_legacy_fill_wave);
+ return cassette->legacy_construct(&fmsx_legacy_fill_wave);
}
-static const struct CassetteFormat fmsx_cas_format =
+static const cassette_image::Format fmsx_cas_format =
{
"tap,cas",
fmsx_cas_identify,
diff --git a/src/lib/formats/gtp_cas.cpp b/src/lib/formats/gtp_cas.cpp
index 0a5c34d140c..f8ac6917d64 100644
--- a/src/lib/formats/gtp_cas.cpp
+++ b/src/lib/formats/gtp_cas.cpp
@@ -6,10 +6,10 @@
Miodrag Milanovic
*/
-#include <cassert>
-
#include "gtp_cas.h"
+#include <cassert>
+
#define GTP_WAV_FREQUENCY 44100
#define WAVE_LOW -0x5a9e
@@ -20,7 +20,7 @@
#define GTP_BLOCK_TURBO 0x01
#define GTP_BLOCK_NAME 0x10
-static int16_t wave_data;
+static int16_t wave_data; // FIXME: global variable prevent multiple instances
static int16_t len;
#define PULSE_WIDTH 30
@@ -164,7 +164,7 @@ static int gtp_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) {
-static const struct CassetteLegacyWaveFiller gtp_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller gtp_legacy_fill_wave = {
gtp_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -176,19 +176,19 @@ static const struct CassetteLegacyWaveFiller gtp_legacy_fill_wave = {
-static cassette_image::error gtp_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &gtp_legacy_fill_wave );
+static cassette_image::error gtp_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
+ return cassette->legacy_identify( opts, &gtp_legacy_fill_wave );
}
static cassette_image::error gtp_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &gtp_legacy_fill_wave );
+ return cassette->legacy_construct( &gtp_legacy_fill_wave );
}
-static const struct CassetteFormat gtp_cassette_format = {
+static const cassette_image::Format gtp_cassette_format = {
"gtp",
gtp_cassette_identify,
gtp_cassette_load,
diff --git a/src/lib/formats/h8_cas.cpp b/src/lib/formats/h8_cas.cpp
index ec92a94b10f..80ad3e07f5a 100644
--- a/src/lib/formats/h8_cas.cpp
+++ b/src/lib/formats/h8_cas.cpp
@@ -11,17 +11,17 @@ We output a leader, followed by the contents of the H8T file.
********************************************************************/
-#include <cassert>
-
#include "h8_cas.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
#define H8_WAV_FREQUENCY 9600
// image size
-static int h8_image_size;
+static int h8_image_size; // FIXME: global variable prevents multiple instances
static int h8_put_samples(int16_t *buffer, int sample_pos, int count, int level)
{
@@ -115,7 +115,7 @@ static int h8_cassette_calculate_size_in_samples(const uint8_t *bytes, int lengt
return h8_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller h8_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller h8_legacy_fill_wave =
{
h8_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -126,17 +126,17 @@ static const struct CassetteLegacyWaveFiller h8_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error h8_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error h8_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &h8_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &h8_legacy_fill_wave);
}
static cassette_image::error h8_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &h8_legacy_fill_wave);
+ return cassette->legacy_construct(&h8_legacy_fill_wave);
}
-static const struct CassetteFormat h8_cassette_image_format =
+static const cassette_image::Format h8_cassette_image_format =
{
"h8t",
h8_cassette_identify,
diff --git a/src/lib/formats/hect_tap.cpp b/src/lib/formats/hect_tap.cpp
index 78f1bad2e42..a450b9507b4 100644
--- a/src/lib/formats/hect_tap.cpp
+++ b/src/lib/formats/hect_tap.cpp
@@ -24,7 +24,7 @@ Updated 3/1/10 : use real value for timing.
#define SMPHI 32767
-static int cas_size;
+static int cas_size; // FIXME: global variable prevents multiple instances
enum
@@ -240,7 +240,7 @@ static int hector_tap_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller hector_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller hector_legacy_fill_wave =
{
hector_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -251,7 +251,7 @@ static const struct CassetteLegacyWaveFiller hector_legacy_fill_wave =
0 /* trailer_samples */
};
-static const struct CassetteLegacyWaveFiller hector_forth_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller hector_forth_legacy_fill_wave =
{
hector_tap_forth_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -263,30 +263,30 @@ static const struct CassetteLegacyWaveFiller hector_forth_legacy_fill_wave =
};
-static cassette_image::error hector_k7_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error hector_k7_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &hector_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &hector_legacy_fill_wave);
}
static cassette_image::error hector_k7_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &hector_legacy_fill_wave);
+ return cassette->legacy_construct(&hector_legacy_fill_wave);
}
-static cassette_image::error hector_k7forth_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error hector_k7forth_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &hector_forth_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &hector_forth_legacy_fill_wave);
}
static cassette_image::error hector_k7forth_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &hector_forth_legacy_fill_wave);
+ return cassette->legacy_construct(&hector_forth_legacy_fill_wave);
}
-static const struct CassetteFormat hector_k7_format =
+static const cassette_image::Format hector_k7_format =
{
"k7,cin",
hector_k7_identify,
@@ -294,7 +294,7 @@ static const struct CassetteFormat hector_k7_format =
nullptr
};
-static const struct CassetteFormat hector_k7Forth_format =
+static const cassette_image::Format hector_k7Forth_format =
{
"for",
hector_k7forth_identify,
diff --git a/src/lib/formats/imd_dsk.cpp b/src/lib/formats/imd_dsk.cpp
index 4a42d1c80c8..631eac9b297 100644
--- a/src/lib/formats/imd_dsk.cpp
+++ b/src/lib/formats/imd_dsk.cpp
@@ -158,18 +158,18 @@ static floperr_t imd_expand_file(floppy_image_legacy *floppy , uint64_t offset ,
return FLOPPY_ERROR_SUCCESS;
}
- auto buffer = global_alloc_array(uint8_t , size_after_off);
+ auto buffer = std::make_unique<uint8_t []>(size_after_off);
// Read the part of file after offset
- floppy_image_read(floppy , buffer , offset , size_after_off);
+ floppy_image_read(floppy, buffer.get(), offset, size_after_off);
// Add zeroes
- floppy_image_write_filler(floppy , 0 , offset , amount);
+ floppy_image_write_filler(floppy, 0, offset, amount);
// Write back the part of file after offset
- floppy_image_write(floppy, buffer, offset + amount, size_after_off);
+ floppy_image_write(floppy, buffer.get(), offset + amount, size_after_off);
- global_free_array(buffer);
+ buffer.reset();
// Update track offsets
struct imddsk_tag *tag = get_tag(floppy);
@@ -439,6 +439,12 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
int tracks, heads;
image->get_maximal_geometry(tracks, heads);
+ m_mode.clear();
+ m_track.clear();
+ m_head.clear();
+ m_sector_count.clear();
+ m_ssize.clear();
+
while(pos < size) {
m_mode.push_back(img[pos++]);
m_track.push_back(img[pos++]);
@@ -522,7 +528,7 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
sects[i].bad_crc = stype == 5 || stype == 6 || stype == 7 || stype == 8;
if(stype == 2 || stype == 4 || stype == 6 || stype == 8) {
- sects[i].data = global_alloc_array(uint8_t, actual_size);
+ sects[i].data = new uint8_t [actual_size];
memset(sects[i].data, img[pos++], actual_size);
} else {
sects[i].data = &img[pos];
@@ -541,7 +547,7 @@ bool imd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image)
for(int i=0; i< m_sector_count.back(); i++)
if(sects[i].data && (sects[i].data < &img[0] || sects[i].data >= (&img[0] + size)))
- global_free_array(sects[i].data);
+ delete [] sects[i].data;
}
return true;
diff --git a/src/lib/formats/ioprocs.h b/src/lib/formats/ioprocs.h
index 5b45b4a1450..1244873f14c 100644
--- a/src/lib/formats/ioprocs.h
+++ b/src/lib/formats/ioprocs.h
@@ -25,20 +25,20 @@
struct io_procs
{
- void (*closeproc)(void *file);
- int (*seekproc)(void *file, int64_t offset, int whence);
- size_t (*readproc)(void *file, void *buffer, size_t length);
- size_t (*writeproc)(void *file, const void *buffer, size_t length);
- uint64_t (*filesizeproc)(void *file);
+ void (*closeproc)(void *file) = nullptr;
+ int (*seekproc)(void *file, int64_t offset, int whence) = nullptr;
+ size_t (*readproc)(void *file, void *buffer, size_t length) = nullptr;
+ size_t (*writeproc)(void *file, const void *buffer, size_t length) = nullptr;
+ uint64_t (*filesizeproc)(void *file) = nullptr;
};
struct io_generic
{
- const struct io_procs *procs;
- void *file;
- uint8_t filler;
+ const struct io_procs *procs = nullptr;
+ void *file = nullptr;
+ uint8_t filler = 0;
};
@@ -48,10 +48,10 @@ struct io_generic
***************************************************************************/
-extern const struct io_procs stdio_ioprocs;
-extern const struct io_procs stdio_ioprocs_noclose;
-extern const struct io_procs corefile_ioprocs;
-extern const struct io_procs corefile_ioprocs_noclose;
+extern const io_procs stdio_ioprocs;
+extern const io_procs stdio_ioprocs_noclose;
+extern const io_procs corefile_ioprocs;
+extern const io_procs corefile_ioprocs_noclose;
diff --git a/src/lib/formats/ipf_dsk.cpp b/src/lib/formats/ipf_dsk.cpp
index ed6505fd385..fc81ffe66ce 100644
--- a/src/lib/formats/ipf_dsk.cpp
+++ b/src/lib/formats/ipf_dsk.cpp
@@ -1,12 +1,27 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
-#include <cassert>
#include "ipf_dsk.h"
+#include <cassert>
+
+
const floppy_format_type FLOPPY_IPF_FORMAT = &floppy_image_format_creator<ipf_format>;
-ipf_format::ipf_format(): tinfos(nullptr), tcount(0), type(0), release(0), revision(0), encoder_type(0),
-encoder_revision(0), origin(0), min_cylinder(0), max_cylinder(0), min_head(0), max_head(0), credit_day(0), credit_time(0)
+ipf_format::ipf_format() :
+ tinfos(),
+ tcount(0),
+ type(0),
+ release(0),
+ revision(0),
+ encoder_type(0),
+ encoder_revision(0),
+ origin(0),
+ min_cylinder(0),
+ max_cylinder(0),
+ min_head(0),
+ max_head(0),
+ credit_day(0),
+ credit_time(0)
{
}
@@ -84,12 +99,11 @@ bool ipf_format::parse(std::vector<uint8_t> &data, floppy_image *image)
{
image->set_variant(floppy_image::DSDD); // Not handling anything else yet
tcount = 84*2+1; // Usual max
- tinfos = global_alloc_array_clear<track_info>(tcount);
+ tinfos.resize(tcount);
bool res = scan_all_tags(data);
if(res)
res = generate_tracks(image);
- global_free_array(tinfos);
- tinfos = nullptr;
+ tinfos.clear();
return res;
}
@@ -121,14 +135,11 @@ ipf_format::track_info *ipf_format::get_index(uint32_t idx)
if(idx > 1000)
return nullptr;
if(idx >= tcount) {
- auto ti1 = global_alloc_array_clear<track_info>(idx+1);
- memcpy(ti1, tinfos, tcount*sizeof(tinfos));
- global_free_array(tinfos);
+ tinfos.resize(idx+1);
tcount = idx+1;
- tinfos = ti1;
}
- return tinfos+idx;
+ return &tinfos[idx];
}
bool ipf_format::parse_imge(const uint8_t *imge)
@@ -246,7 +257,7 @@ bool ipf_format::scan_all_tags(std::vector<uint8_t> &data)
bool ipf_format::generate_tracks(floppy_image *image)
{
for(uint32_t i = 0; i != tcount; i++) {
- track_info *t = tinfos + i;
+ track_info *t = &tinfos[i];
if(t->info_set && t->data) {
if(!generate_track(t, image))
return false;
diff --git a/src/lib/formats/ipf_dsk.h b/src/lib/formats/ipf_dsk.h
index 7db2415afd4..e026cab2c4c 100644
--- a/src/lib/formats/ipf_dsk.h
+++ b/src/lib/formats/ipf_dsk.h
@@ -24,22 +24,22 @@ public:
private:
struct track_info {
- uint32_t cylinder, head, type;
- uint32_t sigtype, process, reserved[3];
- uint32_t size_bytes, size_cells;
- uint32_t index_bytes, index_cells;
- uint32_t datasize_cells, gapsize_cells;
- uint32_t block_count, weak_bits;
+ uint32_t cylinder = 0, head = 0, type = 0;
+ uint32_t sigtype = 0, process = 0, reserved[3] = { 0, 0, 0 };
+ uint32_t size_bytes = 0, size_cells = 0;
+ uint32_t index_bytes = 0, index_cells = 0;
+ uint32_t datasize_cells = 0, gapsize_cells = 0;
+ uint32_t block_count = 0, weak_bits = 0;
- uint32_t data_size_bits;
+ uint32_t data_size_bits = 0;
- bool info_set;
+ bool info_set = false;
- const uint8_t *data;
- uint32_t data_size;
+ const uint8_t *data = nullptr;
+ uint32_t data_size = 0;
};
- track_info *tinfos;
+ std::vector<track_info> tinfos;
uint32_t tcount;
uint32_t type, release, revision;
diff --git a/src/lib/formats/kc_cas.cpp b/src/lib/formats/kc_cas.cpp
index ee3d392e86f..74397e3f89a 100644
--- a/src/lib/formats/kc_cas.cpp
+++ b/src/lib/formats/kc_cas.cpp
@@ -13,10 +13,10 @@
********************************************************************/
-#include <cassert>
-
#include "kc_cas.h"
+#include <cassert>
+
#define SMPLO -32768
#define SMPHI 32767
#define SILENCE 0
@@ -38,7 +38,7 @@ enum
};
// image size
-static int kc_image_size;
+static int kc_image_size; // FIXME: global variable prevents multiple instances
/*******************************************************************
Generate one high-low cycle of sample data
@@ -249,7 +249,7 @@ static int kc_kcc_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller kc_kcc_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller kc_kcc_legacy_fill_wave =
{
kc_kcc_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -260,19 +260,19 @@ static const struct CassetteLegacyWaveFiller kc_kcc_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error kc_kcc_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error kc_kcc_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &kc_kcc_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &kc_kcc_legacy_fill_wave);
}
static cassette_image::error kc_kcc_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &kc_kcc_legacy_fill_wave);
+ return cassette->legacy_construct(&kc_kcc_legacy_fill_wave);
}
-static const struct CassetteFormat kc_kcc_format =
+static const cassette_image::Format kc_kcc_format =
{
"kcc,kcb",
kc_kcc_identify,
@@ -301,7 +301,7 @@ static int kc_tap_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller kc_tap_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller kc_tap_legacy_fill_wave =
{
kc_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -312,19 +312,19 @@ static const struct CassetteLegacyWaveFiller kc_tap_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error kc_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error kc_tap_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &kc_tap_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &kc_tap_legacy_fill_wave);
}
static cassette_image::error kc_tap_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &kc_tap_legacy_fill_wave);
+ return cassette->legacy_construct(&kc_tap_legacy_fill_wave);
}
-static const struct CassetteFormat kc_tap_format =
+static const cassette_image::Format kc_tap_format =
{
"tap,853,854,855,tp2,kcm",
kc_tap_identify,
@@ -353,7 +353,7 @@ static int kc_sss_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller kc_sss_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller kc_sss_legacy_fill_wave =
{
kc_sss_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -364,18 +364,18 @@ static const struct CassetteLegacyWaveFiller kc_sss_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error kc_sss_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error kc_sss_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &kc_sss_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &kc_sss_legacy_fill_wave);
}
static cassette_image::error kc_sss_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &kc_sss_legacy_fill_wave);
+ return cassette->legacy_construct(&kc_sss_legacy_fill_wave);
}
-static const struct CassetteFormat kc_sss_format =
+static const cassette_image::Format kc_sss_format =
{
"sss",
kc_sss_identify,
diff --git a/src/lib/formats/kim1_cas.cpp b/src/lib/formats/kim1_cas.cpp
index b7853ee967e..0ae96280ee3 100644
--- a/src/lib/formats/kim1_cas.cpp
+++ b/src/lib/formats/kim1_cas.cpp
@@ -1,14 +1,14 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
-#include <cassert>
-
#include "kim1_cas.h"
+#include <cassert>
+
#define SMPLO -32768
#define SMPHI 32767
-static int cas_size;
+static int cas_size; // FIXME: global variable prevents multiple instances
static inline int kim1_output_signal( int16_t *buffer, int sample_pos, int high )
@@ -159,7 +159,7 @@ static int kim1_kim_to_wav_size(const uint8_t *casdata, int caslen)
return kim1_handle_kim( nullptr, casdata );
}
-static const struct CassetteLegacyWaveFiller kim1_kim_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller kim1_kim_legacy_fill_wave =
{
kim1_kim_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -171,19 +171,19 @@ static const struct CassetteLegacyWaveFiller kim1_kim_legacy_fill_wave =
};
-static cassette_image::error kim1_kim_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error kim1_kim_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &kim1_kim_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &kim1_kim_legacy_fill_wave);
}
static cassette_image::error kim1_kim_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &kim1_kim_legacy_fill_wave);
+ return cassette->legacy_construct(&kim1_kim_legacy_fill_wave);
}
-static const struct CassetteFormat kim1_kim_format =
+static const cassette_image::Format kim1_kim_format =
{
"kim,kim1",
kim1_kim_identify,
diff --git a/src/lib/formats/lviv_lvt.cpp b/src/lib/formats/lviv_lvt.cpp
index 3a94114d421..3725c181f3c 100644
--- a/src/lib/formats/lviv_lvt.cpp
+++ b/src/lib/formats/lviv_lvt.cpp
@@ -1,10 +1,10 @@
// license:BSD-3-Clause
// copyright-holders:Krzysztof Strzecha
/* .LVT tape images */
-#include <cassert>
-
#include "lviv_lvt.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -19,9 +19,7 @@
static int16_t *lviv_emit_level(int16_t *p, int count, int level)
{
- int i;
-
- for (i=0; i<count; i++)
+ for (int i=0; i<count; i++)
{
*(p++) = level;
}
@@ -47,11 +45,9 @@ static int16_t* lviv_output_bit(int16_t *p, uint8_t b)
static int16_t* lviv_output_byte(int16_t *p, uint8_t byte)
{
- int i;
-
p = lviv_output_bit (p, 0);
- for (i=0; i<8; i++)
+ for (int i=0; i<8; i++)
p = lviv_output_bit(p,(byte>>i) & 0x01);
p = lviv_output_bit (p, 1);
@@ -78,23 +74,22 @@ static int lviv_cassette_calculate_size_in_samples(const uint8_t *bytes, int len
static int lviv_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
{
- int i;
int16_t * p = buffer;
int data_size;
- for (i=0; i<LVIV_LVT_HEADER_PILOT_LENGTH; i++)
+ for (int i=0; i<LVIV_LVT_HEADER_PILOT_LENGTH; i++)
p = lviv_output_bit (p, 1);
- for (i=0; i<10; i++)
+ for (int i=0; i<10; i++)
p = lviv_output_byte (p, bytes[0x09]);
- for (i=0; i<6; i++)
+ for (int i=0; i<6; i++)
p = lviv_output_byte (p, bytes[0x0a+i]);
p = lviv_emit_level (p, LVIV_LVT_PAUSE_SAMPLES, WAVEENTRY_HIGH);
- for (i=0; i<LVIV_LVT_BLOCK_PILOT_LENGTH; i++)
+ for (int i=0; i<LVIV_LVT_BLOCK_PILOT_LENGTH; i++)
p = lviv_output_bit (p, 1);
data_size = length - ( LVIV_LVT_HEADER_PILOT_SAMPLES +
@@ -103,7 +98,7 @@ static int lviv_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
LVIV_LVT_BLOCK_PILOT_SAMPLES );
data_size/=660;
- for (i=0; i<data_size; i++)
+ for (int i=0; i<data_size; i++)
p = lviv_output_byte (p, bytes[0x10+i]);
return p - buffer;
@@ -111,7 +106,7 @@ static int lviv_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
-static const struct CassetteLegacyWaveFiller lviv_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller lviv_legacy_fill_wave =
{
lviv_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -124,21 +119,21 @@ static const struct CassetteLegacyWaveFiller lviv_legacy_fill_wave =
-static cassette_image::error lviv_lvt_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error lviv_lvt_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &lviv_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &lviv_legacy_fill_wave);
}
static cassette_image::error lviv_lvt_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &lviv_legacy_fill_wave);
+ return cassette->legacy_construct(&lviv_legacy_fill_wave);
}
-static const struct CassetteFormat lviv_lvt_image_format =
+static const cassette_image::Format lviv_lvt_image_format =
{
"lvt,lvr,lv0,lv1,lv2,lv3",
lviv_lvt_identify,
diff --git a/src/lib/formats/mbee_cas.cpp b/src/lib/formats/mbee_cas.cpp
index 181bca6aac0..855b4757581 100644
--- a/src/lib/formats/mbee_cas.cpp
+++ b/src/lib/formats/mbee_cas.cpp
@@ -227,7 +227,7 @@ static int mbee_tap_calculate_size_in_samples(const uint8_t *bytes, int length)
return mbee_handle_tap(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller mbee_tap_config =
+static const cassette_image::LegacyWaveFiller mbee_tap_config =
{
mbee_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -238,17 +238,17 @@ static const struct CassetteLegacyWaveFiller mbee_tap_config =
0 /* trailer_samples */
};
-static cassette_image::error mbee_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error mbee_tap_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &mbee_tap_config);
+ return cassette->legacy_identify(opts, &mbee_tap_config);
}
static cassette_image::error mbee_tap_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &mbee_tap_config);
+ return cassette->legacy_construct(&mbee_tap_config);
}
-static const struct CassetteFormat mbee_tap_image_format =
+static const cassette_image::Format mbee_tap_image_format =
{
"tap",
mbee_tap_identify,
diff --git a/src/lib/formats/mfi_dsk.cpp b/src/lib/formats/mfi_dsk.cpp
index 0f118ce620f..eb86d8d80da 100644
--- a/src/lib/formats/mfi_dsk.cpp
+++ b/src/lib/formats/mfi_dsk.cpp
@@ -187,8 +187,8 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
int pos = sizeof(header) + (tracks << resolution)*heads*sizeof(entry);
int epos = 0;
- auto precomp = global_alloc_array(uint32_t, max_track_size);
- auto postcomp = global_alloc_array(uint8_t, max_track_size*4 + 1000);
+ auto precomp = std::make_unique<uint32_t []>(max_track_size);
+ auto postcomp = std::make_unique<uint8_t []>(max_track_size*4 + 1000);
for(int track=0; track <= (tracks-1) << 2; track += 4 >> resolution)
for(int head=0; head<heads; head++) {
@@ -199,7 +199,7 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
continue;
}
- memcpy(precomp, &buffer[0], tsize*4);
+ memcpy(&precomp[0], &buffer[0], tsize*4);
for(int j=0; j<tsize-1; j++)
precomp[j] = (precomp[j] & floppy_image::MG_MASK) |
((precomp[j+1] & floppy_image::TIME_MASK) -
@@ -208,11 +208,8 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
(200000000 - (precomp[tsize-1] & floppy_image::TIME_MASK));
uLongf csize = max_track_size*4 + 1000;
- if(compress(postcomp, &csize, (const Bytef *)precomp, tsize*4) != Z_OK) {
- global_free_array(precomp);
- global_free_array(postcomp);
+ if(compress(postcomp.get(), &csize, (const Bytef *)precomp.get(), tsize*4) != Z_OK)
return false;
- }
entries[epos].offset = pos;
entries[epos].uncompressed_size = tsize*4;
@@ -220,13 +217,11 @@ bool mfi_format::save(io_generic *io, floppy_image *image)
entries[epos].write_splice = image->get_write_splice_position(track >> 2, head, track & 3);
epos++;
- io_generic_write(io, postcomp, pos, csize);
+ io_generic_write(io, postcomp.get(), pos, csize);
pos += csize;
}
io_generic_write(io, entries, sizeof(header), (tracks << resolution)*heads*sizeof(entry));
- global_free_array(precomp);
- global_free_array(postcomp);
return true;
}
diff --git a/src/lib/formats/mz_cas.cpp b/src/lib/formats/mz_cas.cpp
index e7af23aafb4..0ab4cec8e84 100644
--- a/src/lib/formats/mz_cas.cpp
+++ b/src/lib/formats/mz_cas.cpp
@@ -1,8 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Nathan Woods
+#include "mz_cas.h"
+
#include <cstring>
#include <cassert>
-#include "mz_cas.h"
#ifndef VERBOSE
#define VERBOSE 0
@@ -301,7 +302,7 @@ static int fill_wave(int16_t *buffer, int length, uint8_t *code)
-static const struct CassetteLegacyWaveFiller mz700_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller mz700_legacy_fill_wave =
{
fill_wave, /* fill_wave */
1, /* chunk_size */
@@ -314,21 +315,21 @@ static const struct CassetteLegacyWaveFiller mz700_legacy_fill_wave =
-static cassette_image::error mz700_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error mz700_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &mz700_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &mz700_legacy_fill_wave);
}
static cassette_image::error mz700_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &mz700_legacy_fill_wave);
+ return cassette->legacy_construct(&mz700_legacy_fill_wave);
}
-static const struct CassetteFormat mz700_cas_format =
+static const cassette_image::Format mz700_cas_format =
{
"m12,mzf,mzt",
mz700_cas_identify,
diff --git a/src/lib/formats/orao_cas.cpp b/src/lib/formats/orao_cas.cpp
index 9a2ac05547e..a9c3f7473d4 100644
--- a/src/lib/formats/orao_cas.cpp
+++ b/src/lib/formats/orao_cas.cpp
@@ -5,10 +5,10 @@
Tape support for Orao TAP format
*/
-#include <cassert>
-
#include "orao_cas.h"
+#include <cassert>
+
#define ORAO_WAV_FREQUENCY 44100
#define WAVE_HIGH -32768
@@ -19,7 +19,7 @@
#define ORAO_HEADER_SIZE 360
-static int16_t wave_data;
+static int16_t wave_data; // FIXME: global variables prevent multiple instances
static int len;
static void orao_output_wave( int16_t **buffer, int length ) {
@@ -85,7 +85,7 @@ static int orao_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) {
-static const struct CassetteLegacyWaveFiller orao_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller orao_legacy_fill_wave = {
orao_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -97,19 +97,19 @@ static const struct CassetteLegacyWaveFiller orao_legacy_fill_wave = {
-static cassette_image::error orao_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &orao_legacy_fill_wave );
+static cassette_image::error orao_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
+ return cassette->legacy_identify( opts, &orao_legacy_fill_wave );
}
static cassette_image::error orao_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &orao_legacy_fill_wave );
+ return cassette->legacy_construct( &orao_legacy_fill_wave );
}
-static const struct CassetteFormat orao_cassette_format = {
+static const cassette_image::Format orao_cassette_format = {
"tap",
orao_cassette_identify,
orao_cassette_load,
diff --git a/src/lib/formats/oric_tap.cpp b/src/lib/formats/oric_tap.cpp
index dcee2f0bd2d..9dc98239fac 100644
--- a/src/lib/formats/oric_tap.cpp
+++ b/src/lib/formats/oric_tap.cpp
@@ -1,8 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Kevin Thacker
+#include "oric_tap.h"
+
#include <cassert>
-#include "oric_tap.h"
#define ORIC_WAV_DEBUG 0
#define LOG(x) do { if (ORIC_WAV_DEBUG) printf x; } while (0)
@@ -481,7 +482,7 @@ static int oric_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
-static const struct CassetteLegacyWaveFiller oric_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller oric_legacy_fill_wave =
{
oric_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -494,21 +495,21 @@ static const struct CassetteLegacyWaveFiller oric_legacy_fill_wave =
-static cassette_image::error oric_tap_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error oric_tap_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &oric_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &oric_legacy_fill_wave);
}
static cassette_image::error oric_tap_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &oric_legacy_fill_wave);
+ return cassette->legacy_construct(&oric_legacy_fill_wave);
}
-static const struct CassetteFormat oric_tap_format =
+static const cassette_image::Format oric_tap_format =
{
"tap",
oric_tap_identify,
diff --git a/src/lib/formats/p2000t_cas.cpp b/src/lib/formats/p2000t_cas.cpp
index e3351dc99dc..7bc0c6b21a9 100644
--- a/src/lib/formats/p2000t_cas.cpp
+++ b/src/lib/formats/p2000t_cas.cpp
@@ -1,12 +1,12 @@
// license:BSD-3-Clause
// copyright-holders:Curt Coder
-#include <cassert>
-
-#include "cassimg.h"
#include "p2000t_cas.h"
+
+#include <cassert>
#include <ostream>
+
// This code will reproduce the timing of a P2000 mini cassette tape.
constexpr double P2000_CLOCK_PERIOD = 0.000084;
constexpr double P2000_BOT_GAP = 1;
@@ -153,10 +153,10 @@ struct P2000T_Header
std::ostream &operator<<(std::ostream &os, P2000T_Header const &hdr)
{
return os << "File: " << std::string(hdr.file_name, 8) << '.'
- << std::string(hdr.ext, 3) << " " << hdr.file_length;
+ << std::string(hdr.ext, 3) << " " << hdr.file_length;
}
-static cassette_image::error p2000t_cas_identify(cassette_image *cass, struct CassetteOptions *opts)
+static cassette_image::error p2000t_cas_identify(cassette_image *cass, cassette_image::Options *opts)
{
opts->bits_per_sample = 32;
opts->channels = 1;
@@ -189,36 +189,36 @@ void update_chksum(uint16_t *de, bool bit)
}
/*
- A transition on a clock boundary from low to high is a 1.
- A transition on a clock boundary from high to low is a 0
- An intermediate transition halfway between the clock boundary
- can occur when there are consecutive 0s or 1s. See the example
- below where the clock is marked by a |
-
-
- 1 0 1 1 0 0
- RDA: _|----|____|--__|----|__--|__--
- RDC: _|-___|-___|-___|-___|-___|-___
- ^ ^
- |-- clock signal |-- intermediate transition.
-
- This signal can be written by a simple algorithm where the first bit
- is always false (transition to low, half clock). Now only one bit is needed
- to determine what the next partial clock should look like.
-
- This works because we are always guaranteed that a block starts with 0xAA,
- and hence will ALWAYS find a signal like this on tape: _-- (low, high, high)
- after a gap. This is guaranteed when the tape is moving forward as well as
- backwards.
+ A transition on a clock boundary from low to high is a 1.
+ A transition on a clock boundary from high to low is a 0
+ An intermediate transition halfway between the clock boundary
+ can occur when there are consecutive 0s or 1s. See the example
+ below where the clock is marked by a |
+
+
+ 1 0 1 1 0 0
+ RDA: _|----|____|--__|----|__--|__--
+ RDC: _|-___|-___|-___|-___|-___|-___
+ ^ ^
+ |-- clock signal |-- intermediate transition.
+
+ This signal can be written by a simple algorithm where the first bit
+ is always false (transition to low, half clock). Now only one bit is needed
+ to determine what the next partial clock should look like.
+
+ This works because we are always guaranteed that a block starts with 0xAA,
+ and hence will ALWAYS find a signal like this on tape: _-- (low, high, high)
+ after a gap. This is guaranteed when the tape is moving forward as well as
+ backwards.
*/
cassette_image::error p2000t_put_bit(cassette_image *cass, double *time_index, bool bit)
{
const int channel = 0;
cassette_image::error err = cassette_image::error::SUCCESS;
- CHR(cassette_put_sample(cass, channel, *time_index, P2000_CLOCK_PERIOD, bit ? P2000_HIGH : P2000_LOW));
+ CHR(cass->put_sample(channel, *time_index, P2000_CLOCK_PERIOD, bit ? P2000_HIGH : P2000_LOW));
*time_index += P2000_CLOCK_PERIOD;
- CHR(cassette_put_sample(cass, channel, *time_index, P2000_CLOCK_PERIOD, bit ? P2000_LOW : P2000_HIGH));
+ CHR(cass->put_sample(channel, *time_index, P2000_CLOCK_PERIOD, bit ? P2000_LOW : P2000_HIGH));
*time_index += P2000_CLOCK_PERIOD;
return err;
}
@@ -251,7 +251,7 @@ cassette_image::error p2000t_silence(cassette_image *cassette,
double *time_index,
double time)
{
- auto err = cassette_put_sample(cassette, 0, *time_index, time, 0);
+ auto err = cassette->put_sample(0, *time_index, time, 0);
*time_index += time;
return err;
}
@@ -259,21 +259,21 @@ double time)
static cassette_image::error p2000t_cas_load(cassette_image *cassette)
{
cassette_image::error err = cassette_image::error::SUCCESS;
- uint64_t image_size = cassette_image_size(cassette);
+ uint64_t image_size = cassette->image_size();
constexpr int CAS_BLOCK = 1280;
/*
- The cas format is pretty simple. it consists of a sequence of blocks,
- where a block consists of the following:
+ The cas format is pretty simple. it consists of a sequence of blocks,
+ where a block consists of the following:
- [0-256] P2000 memory address 0x6000 - 0x6100
- .... Nonsense (keyboard status etc.)
- 0x30 P200T_Header
- 0x50
- ... Nonsense..
- [0-1024] Data block
+ [0-256] P2000 memory address 0x6000 - 0x6100
+ .... Nonsense (keyboard status etc.)
+ 0x30 P200T_Header
+ 0x50
+ ... Nonsense..
+ [0-1024] Data block
- This means that one block gets stored in 1280 bytes.
+ This means that one block gets stored in 1280 bytes.
*/
if (image_size % CAS_BLOCK != 0)
{
@@ -290,7 +290,7 @@ static cassette_image::error p2000t_cas_load(cassette_image *cassette)
for (int i = 0; i < blocks; i++)
{
uint16_t crc = 0, unused = 0;
- cassette_image_read(cassette, &block, CAS_BLOCK * i, CAS_BLOCK);
+ cassette->image_read(&block, CAS_BLOCK * i, CAS_BLOCK);
// Insert sync header.. 0xAA, 0x00, 0x00, 0xAA
CHR(p2000t_silence(cassette, &time_idx, P2000_BOB_GAP));
@@ -312,7 +312,7 @@ static cassette_image::error p2000t_cas_load(cassette_image *cassette)
return p2000t_silence(cassette, &time_idx, P2000_EOT_GAP);
}
-static const struct CassetteFormat p2000t_cas = {
+static const cassette_image::Format p2000t_cas = {
"cas", p2000t_cas_identify, p2000t_cas_load, nullptr /* no save */
};
diff --git a/src/lib/formats/p6001_cas.cpp b/src/lib/formats/p6001_cas.cpp
index 3319e377b3d..425a4e8dd2c 100644
--- a/src/lib/formats/p6001_cas.cpp
+++ b/src/lib/formats/p6001_cas.cpp
@@ -4,22 +4,21 @@
* NEC PC-6001 cassette format handling
*/
-#include <cassert>
-
#include "p6001_cas.h"
+#include <cassert>
+
#define WAVE_HIGH 0x5a9e
#define WAVE_LOW -0x5a9e
-static int cas_size;
+static int cas_size; // FIXME: global variable prevents multiple instances
static int pc6001_fill_wave(int16_t* buffer, uint8_t data, int sample_pos)
{
- int x;
int sample_count = 0;
// one byte = 8 samples
- for(x=0;x<8;x++)
+ for(int x=0;x<8;x++)
{
if(buffer)
buffer[sample_pos+x] = ((data >> (7-x)) & 1) ? WAVE_HIGH : WAVE_LOW;
@@ -61,7 +60,7 @@ static int pc6001_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *byte
return pc6001_handle_cas(buffer,bytes);
}
-static const struct CassetteLegacyWaveFiller pc6001_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller pc6001_legacy_fill_wave =
{
pc6001_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -72,20 +71,20 @@ static const struct CassetteLegacyWaveFiller pc6001_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error pc6001_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error pc6001_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &pc6001_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &pc6001_legacy_fill_wave);
}
static cassette_image::error pc6001_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &pc6001_legacy_fill_wave);
+ return cassette->legacy_construct(&pc6001_legacy_fill_wave);
}
-static const struct CassetteFormat pc6001_cassette_format = {
+static const cassette_image::Format pc6001_cassette_format = {
"cas",
pc6001_cas_identify,
pc6001_cas_load,
diff --git a/src/lib/formats/phc25_cas.cpp b/src/lib/formats/phc25_cas.cpp
index 197c3db50ae..ee8864adbb5 100644
--- a/src/lib/formats/phc25_cas.cpp
+++ b/src/lib/formats/phc25_cas.cpp
@@ -29,10 +29,10 @@ enough to make it work.
********************************************************************/
-#include <cassert>
-
#include "phc25_cas.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -40,7 +40,7 @@ enough to make it work.
#define PHC25_HEADER_BYTES 16
// image size
-static int phc25_image_size;
+static int phc25_image_size; // FIXME: global variable prevents multiple instances
static int phc25_put_samples(int16_t *buffer, int sample_pos, int count, int level)
{
@@ -147,7 +147,7 @@ static int phc25_cassette_calculate_size_in_samples(const uint8_t *bytes, int le
return phc25_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller phc25_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller phc25_legacy_fill_wave =
{
phc25_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -158,17 +158,17 @@ static const struct CassetteLegacyWaveFiller phc25_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error phc25_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error phc25_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &phc25_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &phc25_legacy_fill_wave);
}
static cassette_image::error phc25_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &phc25_legacy_fill_wave);
+ return cassette->legacy_construct(&phc25_legacy_fill_wave);
}
-static const struct CassetteFormat phc25_cassette_image_format =
+static const cassette_image::Format phc25_cassette_image_format =
{
"phc",
phc25_cassette_identify,
diff --git a/src/lib/formats/pmd_cas.cpp b/src/lib/formats/pmd_cas.cpp
index a046580bc17..20e4a64bbe1 100644
--- a/src/lib/formats/pmd_cas.cpp
+++ b/src/lib/formats/pmd_cas.cpp
@@ -10,10 +10,10 @@
********************************************************************/
-#include <cassert>
-
#include "pmd_cas.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -26,7 +26,7 @@
#define PMD85_BITS_PER_BYTE 11
// image size
-static int pmd85_image_size;
+static int pmd85_image_size; // FIXME: global variable prevents multiple instances
static int pmd85_emit_level(int16_t *buffer, int sample_pos, int count, int level)
{
@@ -184,7 +184,7 @@ static int pmd85_cassette_calculate_size_in_samples(const uint8_t *bytes, int le
return pmd85_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller pmd85_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller pmd85_legacy_fill_wave =
{
pmd85_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -195,17 +195,17 @@ static const struct CassetteLegacyWaveFiller pmd85_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error pmd85_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error pmd85_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &pmd85_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &pmd85_legacy_fill_wave);
}
static cassette_image::error pmd85_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &pmd85_legacy_fill_wave);
+ return cassette->legacy_construct(&pmd85_legacy_fill_wave);
}
-static const struct CassetteFormat pmd85_cassette_image_format =
+static const cassette_image::Format pmd85_cassette_image_format =
{
"pmd,tap,ptp",
pmd85_cassette_identify,
diff --git a/src/lib/formats/primoptp.cpp b/src/lib/formats/primoptp.cpp
index 906a08239a6..6e04f01bc62 100644
--- a/src/lib/formats/primoptp.cpp
+++ b/src/lib/formats/primoptp.cpp
@@ -2,11 +2,10 @@
// copyright-holders:Krzysztof Strzecha
/* .PTP Microkey Primo tape images */
+#include "primoptp.h"
#include <cassert>
-#include "primoptp.h"
-
#define PRIMO_WAVEENTRY_LOW -32768
#define PRIMO_WAVEENTRY_HIGH 32767
@@ -30,9 +29,7 @@ static uint32_t primo_tape_image_length;
static int16_t *primo_emit_level(int16_t *p, int count, int level)
{
- int i;
-
- for (i=0; i<count; i++) *(p++) = level;
+ for (int i=0; i<count; i++) *(p++) = level;
return p;
}
@@ -215,7 +212,7 @@ static int primo_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
return p - buffer;
}
-static const struct CassetteLegacyWaveFiller primo_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller primo_legacy_fill_wave =
{
primo_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -226,17 +223,17 @@ static const struct CassetteLegacyWaveFiller primo_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error primo_ptp_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error primo_ptp_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &primo_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &primo_legacy_fill_wave);
}
static cassette_image::error primo_ptp_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &primo_legacy_fill_wave);
+ return cassette->legacy_construct(&primo_legacy_fill_wave);
}
-static const struct CassetteFormat primo_ptp_image_format =
+static const cassette_image::Format primo_ptp_image_format =
{
"ptp",
primo_ptp_identify,
diff --git a/src/lib/formats/rk_cas.cpp b/src/lib/formats/rk_cas.cpp
index b522fea2f3b..a31c47592db 100644
--- a/src/lib/formats/rk_cas.cpp
+++ b/src/lib/formats/rk_cas.cpp
@@ -5,10 +5,10 @@
Tape support for RK format
*/
-#include <cassert>
-
#include "rk_cas.h"
+#include <cassert>
+
#define RK_WAV_FREQUENCY 44000
#define WAVE_HIGH 32767
@@ -20,13 +20,12 @@
#define RK_SIZE_22 22
#define RK_SIZE_60 60
-static int data_size;
+static int data_size; // FIXME: global variable prevents multiple instances
static int16_t *rk_emit_level(int16_t *p, int count, int level)
{
- int i;
- for (i=0; i<count; i++)
+ for (int i=0; i<count; i++)
{
*(p++) = level;
}
@@ -141,7 +140,7 @@ static int gam_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes ) {
return p - buffer;
}
-static const struct CassetteLegacyWaveFiller rk20_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller rk20_legacy_fill_wave = {
rk20_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -151,15 +150,15 @@ static const struct CassetteLegacyWaveFiller rk20_legacy_fill_wave = {
0 /* trailer_samples */
};
-static cassette_image::error rk20_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &rk20_legacy_fill_wave );
+static cassette_image::error rk20_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
+ return cassette->legacy_identify( opts, &rk20_legacy_fill_wave );
}
static cassette_image::error rk20_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &rk20_legacy_fill_wave );
+ return cassette->legacy_construct( &rk20_legacy_fill_wave );
}
-static const struct CassetteLegacyWaveFiller rk22_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller rk22_legacy_fill_wave = {
rk22_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -169,15 +168,15 @@ static const struct CassetteLegacyWaveFiller rk22_legacy_fill_wave = {
0 /* trailer_samples */
};
-static cassette_image::error rk22_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &rk22_legacy_fill_wave );
+static cassette_image::error rk22_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
+ return cassette->legacy_identify( opts, &rk22_legacy_fill_wave );
}
static cassette_image::error rk22_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &rk22_legacy_fill_wave );
+ return cassette->legacy_construct( &rk22_legacy_fill_wave );
}
-static const struct CassetteLegacyWaveFiller gam_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller gam_legacy_fill_wave = {
gam_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -187,15 +186,15 @@ static const struct CassetteLegacyWaveFiller gam_legacy_fill_wave = {
0 /* trailer_samples */
};
-static cassette_image::error gam_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &gam_legacy_fill_wave );
+static cassette_image::error gam_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
+ return cassette->legacy_identify( opts, &gam_legacy_fill_wave );
}
static cassette_image::error gam_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &gam_legacy_fill_wave );
+ return cassette->legacy_construct( &gam_legacy_fill_wave );
}
-static const struct CassetteLegacyWaveFiller rk60_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller rk60_legacy_fill_wave = {
rk60_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -205,71 +204,71 @@ static const struct CassetteLegacyWaveFiller rk60_legacy_fill_wave = {
0 /* trailer_samples */
};
-static cassette_image::error rk60_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
- return cassette_legacy_identify( cassette, opts, &rk60_legacy_fill_wave );
+static cassette_image::error rk60_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
+ return cassette->legacy_identify( opts, &rk60_legacy_fill_wave );
}
static cassette_image::error rk60_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &rk60_legacy_fill_wave );
+ return cassette->legacy_construct( &rk60_legacy_fill_wave );
}
-static const struct CassetteFormat rku_cassette_format = {
+static const cassette_image::Format rku_cassette_format = {
"rku",
rk20_cassette_identify,
rk20_cassette_load,
nullptr
};
-static const struct CassetteFormat rk8_cassette_format = {
+static const cassette_image::Format rk8_cassette_format = {
"rk8",
rk60_cassette_identify,
rk60_cassette_load,
nullptr
};
-static const struct CassetteFormat rks_cassette_format = {
+static const cassette_image::Format rks_cassette_format = {
"rks",
rk20_cassette_identify,
rk20_cassette_load,
nullptr
};
-static const struct CassetteFormat rko_cassette_format = {
+static const cassette_image::Format rko_cassette_format = {
"rko",
rk20_cassette_identify,
rk20_cassette_load,
nullptr
};
-static const struct CassetteFormat rkr_cassette_format = {
+static const cassette_image::Format rkr_cassette_format = {
"rk,rkr",
rk20_cassette_identify,
rk20_cassette_load,
nullptr
};
-static const struct CassetteFormat rka_cassette_format = {
+static const cassette_image::Format rka_cassette_format = {
"rka",
rk20_cassette_identify,
rk20_cassette_load,
nullptr
};
-static const struct CassetteFormat rkm_cassette_format = {
+static const cassette_image::Format rkm_cassette_format = {
"rkm",
rk22_cassette_identify,
rk22_cassette_load,
nullptr
};
-static const struct CassetteFormat rkp_cassette_format = {
+static const cassette_image::Format rkp_cassette_format = {
"rkp",
rk20_cassette_identify,
rk20_cassette_load,
nullptr
};
-static const struct CassetteFormat gam_cassette_format = {
+static const cassette_image::Format gam_cassette_format = {
"gam,g16,pki",
gam_cassette_identify,
gam_cassette_load,
diff --git a/src/lib/formats/sc3000_bit.cpp b/src/lib/formats/sc3000_bit.cpp
index 6e3600b7aeb..ab0828e709a 100644
--- a/src/lib/formats/sc3000_bit.cpp
+++ b/src/lib/formats/sc3000_bit.cpp
@@ -7,10 +7,10 @@
Cassette code for Sega SC-3000 *.bit files
*********************************************************************/
+#include "sc3000_bit.h"
#include <cassert>
-#include "sc3000_bit.h"
/***************************************************************************
PARAMETERS
@@ -26,9 +26,9 @@
CassetteModulation sc3000_bit_modulation
-------------------------------------------------*/
-static const struct CassetteModulation sc3000_bit_modulation =
+static const cassette_image::Modulation sc3000_bit_modulation =
{
- CASSETTE_MODULATION_SINEWAVE,
+ cassette_image::MODULATION_SINEWAVE,
1200.0 - 300, 1200.0, 1200.0 + 300,
2400.0 - 600, 2400.0, 2400.0 + 600
};
@@ -37,9 +37,9 @@ static const struct CassetteModulation sc3000_bit_modulation =
sc3000_bit_identify - identify cassette
-------------------------------------------------*/
-static cassette_image::error sc3000_bit_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error sc3000_bit_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_modulation_identify( cassette, &sc3000_bit_modulation, opts);
+ return cassette->modulation_identify(sc3000_bit_modulation, opts);
}
/*-------------------------------------------------
@@ -48,7 +48,7 @@ static cassette_image::error sc3000_bit_identify(cassette_image *cassette, struc
#define MODULATE(_value) \
for (int i = 0; i < (_value ? 2 : 1); i++) { \
- err = cassette_put_modulated_data_bit(cassette, 0, time_index, _value, &sc3000_bit_modulation, &time_displacement);\
+ err = cassette->put_modulated_data_bit(0, time_index, _value, sc3000_bit_modulation, &time_displacement);\
if (err != cassette_image::error::SUCCESS) return err;\
time_index += time_displacement;\
}
@@ -56,7 +56,7 @@ static cassette_image::error sc3000_bit_identify(cassette_image *cassette, struc
static cassette_image::error sc3000_bit_load(cassette_image *cassette)
{
cassette_image::error err;
- uint64_t image_size = cassette_image_size(cassette);
+ uint64_t image_size = cassette->image_size();
uint64_t image_pos = 0;
double time_index = 0.0;
double time_displacement;
@@ -64,7 +64,7 @@ static cassette_image::error sc3000_bit_load(cassette_image *cassette)
while (image_pos < image_size)
{
- cassette_image_read(cassette, &data, image_pos, 1);
+ cassette->image_read(&data, image_pos, 1);
switch (data)
{
@@ -77,7 +77,7 @@ static cassette_image::error sc3000_bit_load(cassette_image *cassette)
break;
case ' ':
- err = cassette_put_sample( cassette, 0, time_index, 1/1200.0, 0);
+ err = cassette->put_sample(0, time_index, 1/1200.0, 0);
if (err != cassette_image::error::SUCCESS) return err;
time_index += 1/1200.0;
break;
@@ -93,7 +93,7 @@ static cassette_image::error sc3000_bit_load(cassette_image *cassette)
CassetteFormat sc3000_bit_cassette_format
-------------------------------------------------*/
-const struct CassetteFormat sc3000_bit_format =
+const cassette_image::Format sc3000_bit_format =
{
"bit",
sc3000_bit_identify,
diff --git a/src/lib/formats/sol_cas.cpp b/src/lib/formats/sol_cas.cpp
index 4672ff95080..a48a5b918fd 100644
--- a/src/lib/formats/sol_cas.cpp
+++ b/src/lib/formats/sol_cas.cpp
@@ -33,10 +33,10 @@ SVT - The full explanation may be found on the Solace web site,
escaped characters
********************************************************************/
+#include "sol_cas.h"
#include <cassert>
-#include "sol_cas.h"
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -44,7 +44,7 @@ SVT - The full explanation may be found on the Solace web site,
#define SOL20_WAV_FREQUENCY 4800
// image size
-static uint32_t sol20_image_size;
+static uint32_t sol20_image_size; // FIXME: global variable prevent multiple instances
static bool level;
static uint8_t sol20_cksm_byte;
static uint32_t sol20_byte_num;
@@ -356,7 +356,7 @@ static int sol20_cassette_calculate_size_in_samples(const uint8_t *bytes, int le
return sol20_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller sol20_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller sol20_legacy_fill_wave =
{
sol20_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -367,17 +367,17 @@ static const struct CassetteLegacyWaveFiller sol20_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error sol20_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error sol20_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &sol20_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &sol20_legacy_fill_wave);
}
static cassette_image::error sol20_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &sol20_legacy_fill_wave);
+ return cassette->legacy_construct(&sol20_legacy_fill_wave);
}
-static const struct CassetteFormat sol20_cassette_image_format =
+static const cassette_image::Format sol20_cassette_image_format =
{
"svt",
sol20_cassette_identify,
diff --git a/src/lib/formats/sorc_cas.cpp b/src/lib/formats/sorc_cas.cpp
index 50585d444c7..21b3f8b5c2c 100644
--- a/src/lib/formats/sorc_cas.cpp
+++ b/src/lib/formats/sorc_cas.cpp
@@ -24,10 +24,10 @@ header and leader bytes.
********************************************************************/
+#include "sorc_cas.h"
#include <cassert>
-#include "sorc_cas.h"
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -124,7 +124,7 @@ static int sorcerer_cassette_calculate_size_in_samples(const uint8_t *bytes, int
return sorcerer_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller sorcerer_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller sorcerer_legacy_fill_wave =
{
sorcerer_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -135,17 +135,17 @@ static const struct CassetteLegacyWaveFiller sorcerer_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error sorcerer_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error sorcerer_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &sorcerer_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &sorcerer_legacy_fill_wave);
}
static cassette_image::error sorcerer_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &sorcerer_legacy_fill_wave);
+ return cassette->legacy_construct(&sorcerer_legacy_fill_wave);
}
-static const struct CassetteFormat sorcerer_cassette_image_format =
+static const cassette_image::Format sorcerer_cassette_image_format =
{
"tape",
sorcerer_cassette_identify,
diff --git a/src/lib/formats/sord_cas.cpp b/src/lib/formats/sord_cas.cpp
index 145cd3c3221..f90daafd248 100644
--- a/src/lib/formats/sord_cas.cpp
+++ b/src/lib/formats/sord_cas.cpp
@@ -7,10 +7,10 @@
Format code for Sord M5 cassette files
**************************************************************************/
+#include "sord_cas.h"
#include <cstring>
#include <cassert>
-#include "sord_cas.h"
#define SORDM5_WAVESAMPLES_HEADER 1
#define SORDM5_WAVESAMPLES_TRAILER 1
@@ -18,9 +18,9 @@
static const uint8_t SORDM5_CAS_HEADER[6] = { 'S', 'O', 'R', 'D', 'M', '5'};
-static const struct CassetteModulation sordm5_cas_modulation =
+static const cassette_image::Modulation sordm5_cas_modulation =
{
- CASSETTE_MODULATION_SINEWAVE,
+ cassette_image::MODULATION_SINEWAVE,
1575.0 - 300, 1575.0, 1575.0 + 300,
3150.0 - 600, 3150.0, 3150.0 + 600
};
@@ -28,13 +28,13 @@ static const struct CassetteModulation sordm5_cas_modulation =
static uint8_t cassette_image_read_uint8( cassette_image *cassette, uint64_t offset)
{
uint8_t data;
- cassette_image_read( cassette, &data, offset, 1);
+ cassette->image_read(&data, offset, 1);
return data;
}
-static cassette_image::error sordm5_tap_identify( cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error sordm5_tap_identify( cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_modulation_identify( cassette, &sordm5_cas_modulation, opts);
+ return cassette->modulation_identify(sordm5_cas_modulation, opts);
}
static cassette_image::error sordm5_tap_load( cassette_image *cassette)
@@ -49,44 +49,44 @@ static cassette_image::error sordm5_tap_load( cassette_image *cassette)
uint32_t block_size, i, j;
size_t filler_length;
// init
- image_size = cassette_image_size(cassette);
+ image_size = cassette->image_size();
image_pos = 0;
// read/check header
if (image_size < 16) return cassette_image::error::INVALID_IMAGE;
- cassette_image_read( cassette, &header, image_pos, 16);
+ cassette->image_read(&header, image_pos, 16);
image_pos += 16;
if (memcmp( header, SORDM5_CAS_HEADER, sizeof(SORDM5_CAS_HEADER)) != 0) return cassette_image::error::INVALID_IMAGE;
// add silence (header)
- err = cassette_put_sample( cassette, 0, time_index, SORDM5_WAVESAMPLES_HEADER, 0);
+ err = cassette->put_sample(0, time_index, SORDM5_WAVESAMPLES_HEADER, 0);
if (err != cassette_image::error::SUCCESS) return err;
time_index += SORDM5_WAVESAMPLES_HEADER;
// process blocks
while (image_pos < image_size)
{
// read block type
- block_type = cassette_image_read_uint8( cassette, image_pos + 0);
+ block_type = cassette_image_read_uint8(cassette, image_pos + 0);
if ((block_type != 'H') && (block_type != 'D')) return cassette_image::error::INVALID_IMAGE;
// read block size
- block_size = cassette_image_read_uint8( cassette, image_pos + 1);
+ block_size = cassette_image_read_uint8(cassette, image_pos + 1);
if (block_size == 0) block_size = 0x100;
block_size += 3;
// add silence (header block)
if (block_type == 'H')
{
- err = cassette_put_sample( cassette, 0, time_index, SORDM5_WAVESAMPLES_BLOCK, 0);
+ err = cassette->put_sample(0, time_index, SORDM5_WAVESAMPLES_BLOCK, 0);
if (err != cassette_image::error::SUCCESS) return err;
time_index += SORDM5_WAVESAMPLES_BLOCK;
}
// add sync
if (block_type == 'H') filler_length = 2.4 * (3150 / 8); else filler_length = 0.15 * (3150 / 8);
- err = cassette_put_modulated_filler(cassette, 0, time_index, 0xFF, filler_length, &sordm5_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_filler(0, time_index, 0xFF, filler_length, sordm5_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS) return err;
time_index += time_displacement;
// process block
for (i=0;i<block_size;i++)
{
// read byte
- byte = cassette_image_read_uint8( cassette, image_pos + i);
+ byte = cassette_image_read_uint8(cassette, image_pos + i);
// calc/check checksum
#if 0
if (i == block_size)
@@ -108,27 +108,27 @@ static cassette_image::error sordm5_tap_load( cassette_image *cassette)
bit = (byte >> (j-2)) & 1;
}
// add bit
- err = cassette_put_modulated_data_bit( cassette, 0, time_index, bit, &sordm5_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_data_bit(0, time_index, bit, sordm5_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS) return err;
time_index += time_displacement;
}
}
// mark end of block
- err = cassette_put_modulated_data_bit( cassette, 0, time_index, 1, &sordm5_cas_modulation, &time_displacement);
+ err = cassette->put_modulated_data_bit(0, time_index, 1, sordm5_cas_modulation, &time_displacement);
if (err != cassette_image::error::SUCCESS) return err;
time_index += time_displacement;
// next block
image_pos += block_size;
}
// add silence (trailer)
- err = cassette_put_sample( cassette, 0, time_index, SORDM5_WAVESAMPLES_TRAILER, 0);
+ err = cassette->put_sample(0, time_index, SORDM5_WAVESAMPLES_TRAILER, 0);
if (err != cassette_image::error::SUCCESS) return err;
time_index += SORDM5_WAVESAMPLES_TRAILER;
//
return cassette_image::error::SUCCESS;
}
-static const struct CassetteFormat sordm5_cas_format =
+static const cassette_image::Format sordm5_cas_format =
{
"cas",
sordm5_tap_identify,
diff --git a/src/lib/formats/spc1000_cas.cpp b/src/lib/formats/spc1000_cas.cpp
index 2e48980da3d..e5d4bc1d0c3 100644
--- a/src/lib/formats/spc1000_cas.cpp
+++ b/src/lib/formats/spc1000_cas.cpp
@@ -20,10 +20,10 @@ STA: This format has not been investigated yet, but is assumed to
IPL: This seems a quickload format containing RAM dump, not a real tape
********************************************************************/
+#include "spc1000_cas.h"
#include <cassert>
-#include "spc1000_cas.h"
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -31,7 +31,7 @@ IPL: This seems a quickload format containing RAM dump, not a real tape
#define SPC1000_WAV_FREQUENCY 17000
// image size
-static int spc1000_image_size;
+static int spc1000_image_size; // FIXME: global variable prevents multiple instances
static int spc1000_put_samples(int16_t *buffer, int sample_pos, int count, int level)
{
@@ -125,7 +125,7 @@ static int spc1000_cas_calculate_size_in_samples(const uint8_t *bytes, int lengt
// TAP
-static const struct CassetteLegacyWaveFiller spc1000_tap_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller spc1000_tap_legacy_fill_wave =
{
spc1000_tap_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -136,17 +136,17 @@ static const struct CassetteLegacyWaveFiller spc1000_tap_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error spc1000_tap_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error spc1000_tap_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &spc1000_tap_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &spc1000_tap_legacy_fill_wave);
}
static cassette_image::error spc1000_tap_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &spc1000_tap_legacy_fill_wave);
+ return cassette->legacy_construct(&spc1000_tap_legacy_fill_wave);
}
-static const struct CassetteFormat spc1000_tap_cassette_image_format =
+static const cassette_image::Format spc1000_tap_cassette_image_format =
{
"tap",
spc1000_tap_cassette_identify,
@@ -156,7 +156,7 @@ static const struct CassetteFormat spc1000_tap_cassette_image_format =
// CAS
-static const struct CassetteLegacyWaveFiller spc1000_cas_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller spc1000_cas_legacy_fill_wave =
{
spc1000_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -167,17 +167,17 @@ static const struct CassetteLegacyWaveFiller spc1000_cas_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error spc1000_cas_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error spc1000_cas_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &spc1000_cas_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &spc1000_cas_legacy_fill_wave);
}
static cassette_image::error spc1000_cas_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &spc1000_cas_legacy_fill_wave);
+ return cassette->legacy_construct(&spc1000_cas_legacy_fill_wave);
}
-static const struct CassetteFormat spc1000_cas_cassette_image_format =
+static const cassette_image::Format spc1000_cas_cassette_image_format =
{
"cas",
spc1000_cas_cassette_identify,
diff --git a/src/lib/formats/svi_cas.cpp b/src/lib/formats/svi_cas.cpp
index fcb2142c4e3..dfd695dd5ec 100644
--- a/src/lib/formats/svi_cas.cpp
+++ b/src/lib/formats/svi_cas.cpp
@@ -1,9 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Sean Young
-#include <cassert>
-
#include "svi_cas.h"
+#include <cassert>
+
#define CAS_PERIOD_0 (37)
#define CAS_PERIOD_1 (18)
#define CAS_HEADER_PERIODS (1600)
@@ -19,7 +19,7 @@ static const uint8_t CasHeader[17] =
#define SMPLO -32768
#define SMPHI 32767
-static int cas_size;
+static int cas_size; // FIXME: global variable prevents multiple instances
/*******************************************************************
Generate samples for the tape image
@@ -171,7 +171,7 @@ static int svi_cas_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller svi_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller svi_legacy_fill_wave =
{
svi_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -184,21 +184,21 @@ static const struct CassetteLegacyWaveFiller svi_legacy_fill_wave =
-static cassette_image::error svi_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error svi_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &svi_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &svi_legacy_fill_wave);
}
static cassette_image::error svi_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &svi_legacy_fill_wave);
+ return cassette->legacy_construct(&svi_legacy_fill_wave);
}
-static const struct CassetteFormat svi_cas_format =
+static const cassette_image::Format svi_cas_format =
{
"cas",
svi_cas_identify,
diff --git a/src/lib/formats/thom_cas.cpp b/src/lib/formats/thom_cas.cpp
index a00c2c3234b..0d0cc4fc4eb 100644
--- a/src/lib/formats/thom_cas.cpp
+++ b/src/lib/formats/thom_cas.cpp
@@ -8,12 +8,11 @@
**********************************************************************/
-#include <cmath>
-#include <cassert>
-
-#include "pool.h"
-#include "cassimg.h"
#include "thom_cas.h"
+#include "pool.h"
+
+#include <cassert>
+#include <cmath>
/***************************** configuration **************************/
@@ -86,18 +85,18 @@ static uint8_t* to7_k7_bits;
-static const struct CassetteModulation to7_k7_modulation =
+static const cassette_image::Modulation to7_k7_modulation =
{
- CASSETTE_MODULATION_SQUAREWAVE,
+ cassette_image::MODULATION_SQUAREWAVE,
4000.0, 4500.0, 5000.0,
5500.0, 6300.0, 7500.0
};
-static cassette_image::error to7_k7_identify ( cassette_image *cass, struct CassetteOptions *opts )
+static cassette_image::error to7_k7_identify ( cassette_image *cass, cassette_image::Options *opts )
{
- cassette_image::error e = cassette_modulation_identify( cass, &to7_k7_modulation, opts );
+ cassette_image::error e = cass->modulation_identify( to7_k7_modulation, opts );
return e;
}
@@ -109,7 +108,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
static const int8_t square_wave[] = { -128, 127 };
double time = 0.;
#endif
- size_t size = cassette_image_size( cass ), pos = 0;
+ size_t size = cass->image_size( ), pos = 0;
int i, sz, sz2, bitmax = 1024, invalid = 0;
uint8_t in, typ, block[264];
@@ -133,8 +132,8 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
do \
{ \
cassette_image::error err; \
- err = cassette_put_samples( cass, 0, time, (PERIOD), 2, 1, \
- square_wave, CASSETTE_WAVEFORM_8BIT ); \
+ err = cass->put_samples( 0, time, (PERIOD), 2, 1, \
+ square_wave, cassette_image::WAVEFORM_8BIT ); \
if ( err != cassette_image::error::SUCCESS ) \
return err; \
time += (PERIOD); \
@@ -202,7 +201,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
} while (0)
/* check format */
- cassette_image_read( cass, block, 0, 64 );
+ cass->image_read( block, 0, 64 );
for ( i = 3; ; i++ )
{
if ( ( i >= size ) || ( i >= 64 ) )
@@ -227,7 +226,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
/* skip to first 0xff filler */
for ( sz = 0; pos < size; pos++, sz++ )
{
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
if ( in == 0xff )
break;
}
@@ -241,7 +240,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
/* skip 0xff filler */
for ( sz = 0; pos < size; pos++, sz++ )
{
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
/* actually, we are bit laxist and treat as 0xff bytes with at least
5 bits out of 8 set to 1
*/
@@ -257,7 +256,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
pos -= sz;
break;
}
- cassette_image_read( cass, block, pos, 4 );
+ cass->image_read( block, pos, 4 );
typ = block[2];
sz2 = block[3]+1;
if ( block[0] != 0x01 || block[1] != 0x3c || ( typ != 0x00 && typ != 0x01 && typ != 0xff ) )
@@ -268,7 +267,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
pos += 4;
/* get block */
- cassette_image_read( cass, block+4, pos, sz2 );
+ cass->image_read( block+4, pos, sz2 );
pos += sz2;
/* 1-filler and 0xff-filler */
@@ -323,17 +322,17 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
/* put block */
for (; pos < size; pos++ )
{
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
for ( sz = 0; pos < size && in == 0xff; sz++ )
{
pos++;
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
}
if ( invalid < 10 && sz > 4 && in == 0x01 && pos + 4 <= size )
{
uint8_t in1,in2;
- cassette_image_read( cass, &in1, pos+1, 1 );
- cassette_image_read( cass, &in2, pos+2, 1 );
+ cass->image_read( &in1, pos+1, 1 );
+ cass->image_read( &in2, pos+2, 1 );
if ( (in1 == 0x3c) && ((in2 == 0x00) || (in2 == 0x01) ) )
{
/* seems we have a regular block hidden in raw data => rebounce */
@@ -365,7 +364,7 @@ static cassette_image::error to7_k7_load( cassette_image *cass )
-static const struct CassetteFormat to7_k7 =
+static const cassette_image::Format to7_k7 =
{ "k7", to7_k7_identify, to7_k7_load, nullptr /* no save */ };
@@ -375,9 +374,9 @@ static const struct CassetteFormat to7_k7 =
static cassette_image::error to7_wav_identify ( cassette_image *cass,
- struct CassetteOptions *opts )
+ cassette_image::Options *opts )
{
- cassette_image::error e = wavfile_format.identify( cass, opts );
+ cassette_image::error e = cassette_image::wavfile_format.identify( cass, opts );
return e;
}
@@ -385,9 +384,7 @@ static cassette_image::error to7_wav_identify ( cassette_image *cass,
static cassette_image::error to7_wav_load ( cassette_image *cass )
{
- cassette_image::error e = wavfile_format.load( cass );
- struct CassetteInfo info;
- double len;
+ cassette_image::error e = cassette_image::wavfile_format.load( cass );
if ( to7_k7_bits )
{
@@ -398,9 +395,9 @@ static cassette_image::error to7_wav_load ( cassette_image *cass )
if ( e != cassette_image::error::SUCCESS )
return e;
- cassette_get_info( cass, &info );
+ cassette_image::Info info = cass->get_info( );
- len = (double) info.sample_count / info.sample_frequency;
+ double len = (double) info.sample_count / info.sample_frequency;
PRINT (( "to7_wav_load: loading cassette, length %imn %is, %i Hz, %i bps, %i bits\n",
(int) len / 60, (int) len % 60,
@@ -412,17 +409,17 @@ static cassette_image::error to7_wav_load ( cassette_image *cass )
-static cassette_image::error to7_wav_save ( cassette_image *cass, const struct CassetteInfo *info )
+static cassette_image::error to7_wav_save ( cassette_image *cass, const cassette_image::Info *info )
{
int len = info->sample_count / info->sample_frequency;
PRINT (( "to7_wav_save: saving cassette, length %imn %is, %i Hz, %i bps\n", len / 60, len % 60, info->sample_frequency, info->bits_per_sample ));
- return wavfile_format.save( cass, info );
+ return cassette_image::wavfile_format.save( cass, info );
}
/* overloaded wav: dump info */
-static const struct CassetteFormat to7_wav =
+static const cassette_image::Format to7_wav =
{ "wav", to7_wav_identify, to7_wav_load, to7_wav_save };
@@ -432,7 +429,7 @@ static const struct CassetteFormat to7_wav =
static cassette_image::error mo5_k5_identify ( cassette_image *cass,
- struct CassetteOptions *opts )
+ cassette_image::Options *opts )
{
opts -> bits_per_sample = 8;
opts -> channels = 1;
@@ -464,7 +461,7 @@ static cassette_image::error mo5_k5_identify ( cassette_image *cass,
static cassette_image::error mo5_k5_load( cassette_image *cass )
{
- size_t size = cassette_image_size( cass ), pos = 0;
+ size_t size = cass->image_size( ), pos = 0;
int i, sz, sz2, hbit = 0;
uint8_t in, in2, in3, typ, block[264], sum;
int invalid = 0, hbitsize = 0, dcmoto = 0;
@@ -476,7 +473,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
#define K5_PUT_HBIT \
do \
{ \
- cassette_put_sample ( cass, 0, hbitsize * MO5_HBIT_LENGTH, MO5_HBIT_LENGTH, (hbit ? 1 : -1) << 30 ); \
+ cass->put_sample ( 0, hbitsize * MO5_HBIT_LENGTH, MO5_HBIT_LENGTH, (hbit ? 1 : -1) << 30 ); \
hbitsize++; \
} while ( 0 )
@@ -534,7 +531,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
} while (0)
/* check format */
- cassette_image_read( cass, block, 0, 64 );
+ cass->image_read( block, 0, 64 );
for ( i = 3; ; i++ )
{
if ( ( i >= size ) || ( i >= 64 ) )
@@ -556,7 +553,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
}
}
- cassette_image_read( cass, block, pos, 6 );
+ cass->image_read( block, pos, 6 );
if ( ! memcmp( block, "DCMOTO", 6 ) || ! memcmp( block, "DCMO5", 5 ) || ! memcmp( block, "DCMO6", 5 ) )
dcmoto = 1;
@@ -567,7 +564,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
/* skip DCMOTO header*/
if ( dcmoto )
{
- cassette_image_read( cass, block, pos, 6 );
+ cass->image_read( block, pos, 6 );
if ( ! memcmp( block, "DCMOTO", 6 ) )
{
LOG (( "mo5_k5_load: DCMOTO signature found at off=$%x\n", (int)pos ));
@@ -583,7 +580,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
/* skip 0x01 filler */
for ( sz = 0; pos < size; pos++, sz++ )
{
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
if ( in != 0x01 )
break;
}
@@ -594,7 +591,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
pos -= sz;
break;
}
- cassette_image_read( cass, block, pos, 4 );
+ cass->image_read( block, pos, 4 );
typ = block[2];
sz2 = (uint8_t) (block[3]-1);
if ( block[0] != 0x3c || block[1] != 0x5a || ( typ != 0x00 && typ != 0x01 && typ != 0xff ) || pos+sz2 > size )
@@ -605,7 +602,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
pos += 4;
/* get block */
- cassette_image_read( cass, block+4, pos, sz2 );
+ cass->image_read( block+4, pos, sz2 );
pos += sz2;
/* 0-fillers and 0x01-fillers */
@@ -665,33 +662,33 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
LOG (( "mo5_k5_load: trailing trash off=$%x size=%i hbitstart=%i\n", (int) pos, (int) (size-pos), hbitsize ));
for ( ; pos < size; pos++ )
{
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
if ( dcmoto && in=='D' )
{
/* skip DCMOTO header*/
- cassette_image_read( cass, block, pos, 6 );
+ cass->image_read( block, pos, 6 );
if ( ! memcmp( block, "DCMOTO", 6 ) )
{
LOG (( "mo5_k5_load: DCMOTO signature found at off=$%x\n", (int)pos ));
pos += 6;
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
}
else if ( ! memcmp( block, "DCMO", 4 ) )
{
LOG (( "mo5_k5_load: DCMO* signature found at off=$%x\n", (int)pos ));
pos += 5;
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
}
}
for ( sz = 0; pos < size && in == 0x01; sz++ )
{
pos++;
- cassette_image_read( cass, &in, pos, 1 );
+ cass->image_read( &in, pos, 1 );
}
if ( sz > 6 )
{
- cassette_image_read( cass, &in2, pos+1, 1 );
- cassette_image_read( cass, &in3, pos+2, 1 );
+ cass->image_read( &in2, pos+1, 1 );
+ cass->image_read( &in3, pos+2, 1 );
if ( invalid < 10 && in == 0x3c && in2 == 0x5a && (in3 == 0x00 || in3 == 0x01 || in3 == 0xff ) )
{
/* regular block found */
@@ -729,7 +726,7 @@ static cassette_image::error mo5_k5_load( cassette_image *cass )
-static const struct CassetteFormat mo5_k5 =
+static const cassette_image::Format mo5_k5 =
{ "k5,k7", mo5_k5_identify, mo5_k5_load, nullptr /* no save */ };
@@ -738,9 +735,9 @@ static const struct CassetteFormat mo5_k5 =
static cassette_image::error mo5_wav_identify ( cassette_image *cass,
- struct CassetteOptions *opts )
+ cassette_image::Options *opts )
{
- cassette_image::error e = wavfile_format.identify( cass, opts );
+ cassette_image::error e = cassette_image::wavfile_format.identify( cass, opts );
return e;
}
@@ -748,13 +745,11 @@ static cassette_image::error mo5_wav_identify ( cassette_image *cass,
static cassette_image::error mo5_wav_load ( cassette_image *cass )
{
- cassette_image::error e = wavfile_format.load( cass );
- struct CassetteInfo info;
- int len;
+ cassette_image::error e = cassette_image::wavfile_format.load( cass );
if ( e == cassette_image::error::SUCCESS )
{
- cassette_get_info( cass, &info );
- len = info.sample_count / info.sample_frequency;
+ cassette_image::Info info = cass->get_info( );
+ int len = info.sample_count / info.sample_frequency;
PRINT (( "mo5_wav_load: loading cassette, length %imn %is, %i Hz, %i bps\n", len / 60, len % 60, info.sample_frequency, info.bits_per_sample ));
}
return e;
@@ -762,17 +757,17 @@ static cassette_image::error mo5_wav_load ( cassette_image *cass )
-static cassette_image::error mo5_wav_save ( cassette_image *cass, const struct CassetteInfo *info )
+static cassette_image::error mo5_wav_save ( cassette_image *cass, const cassette_image::Info *info )
{
int len = info->sample_count / info->sample_frequency;
PRINT (( "mo5_wav_save: saving cassette, length %imn %is, %i Hz, %i bps\n", len / 60, len % 60, info->sample_frequency, info->bits_per_sample ));
- return wavfile_format.save( cass, info );
+ return cassette_image::wavfile_format.save( cass, info );
}
/* overloaded wav: dump info */
-static const struct CassetteFormat mo5_wav =
+static const cassette_image::Format mo5_wav =
{ "wav", mo5_wav_identify, mo5_wav_load, mo5_wav_save };
@@ -780,9 +775,9 @@ static const struct CassetteFormat mo5_wav =
/********************* formats ************************/
-const struct CassetteFormat *const to7_cassette_formats[] =
+const cassette_image::Format *const to7_cassette_formats[] =
{ &to7_wav, &to7_k7, nullptr };
-const struct CassetteFormat *const mo5_cassette_formats[] =
+const cassette_image::Format *const mo5_cassette_formats[] =
{ &mo5_wav, &mo5_k5, nullptr };
diff --git a/src/lib/formats/trs_cas.cpp b/src/lib/formats/trs_cas.cpp
index 582abf8869c..7556c392427 100644
--- a/src/lib/formats/trs_cas.cpp
+++ b/src/lib/formats/trs_cas.cpp
@@ -5,17 +5,17 @@
Support for TRS80 .cas cassette images
********************************************************************/
+#include "formats/trs_cas.h"
#include <cassert>
-#include "formats/trs_cas.h"
#define SILENCE 0
#define SMPLO -32768
#define SMPHI 32767
-static int cas_size;
+static int cas_size; // FIXME: global variable prevents mutliple instances
/*******************************************************************
@@ -99,7 +99,7 @@ static int trs80l2_cas_to_wav_size(const uint8_t *casdata, int caslen)
return trs80l2_handle_cas( nullptr, casdata );
}
-static const struct CassetteLegacyWaveFiller trs80l2_cas_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller trs80l2_cas_legacy_fill_wave =
{
trs80l2_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -111,19 +111,19 @@ static const struct CassetteLegacyWaveFiller trs80l2_cas_legacy_fill_wave =
};
-static cassette_image::error trs80l2_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error trs80l2_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &trs80l2_cas_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &trs80l2_cas_legacy_fill_wave);
}
static cassette_image::error trs80l2_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &trs80l2_cas_legacy_fill_wave);
+ return cassette->legacy_construct(&trs80l2_cas_legacy_fill_wave);
}
-static const struct CassetteFormat trs80l2_cas_format =
+static const cassette_image::Format trs80l2_cas_format =
{
"cas",
trs80l2_cas_identify,
diff --git a/src/lib/formats/tvc_cas.cpp b/src/lib/formats/tvc_cas.cpp
index 3cea37cc1bf..e6d05451d9d 100644
--- a/src/lib/formats/tvc_cas.cpp
+++ b/src/lib/formats/tvc_cas.cpp
@@ -7,10 +7,10 @@
http://tvc.homeserver.hu/html/konvertformatum.html
********************************************************************/
+#include "tvc_cas.h"
#include <cassert>
-#include "tvc_cas.h"
#define TVC64_BIT0_FREQ 1812
#define TVC64_BIT1_FREQ 2577
@@ -24,7 +24,7 @@
static void tvc64_emit_level(cassette_image *cass, double &time, int freq, int level)
{
double period = 1.0 / freq;
- cassette_put_sample(cass, 0, time, period, level * WAVE_AMPLITUDE);
+ cass->put_sample(0, time, period, level * WAVE_AMPLITUDE);
time += period;
}
@@ -89,7 +89,7 @@ static cassette_image::error tvc64_cassette_load(cassette_image *cassette)
double time = 0.0;
uint8_t header[TVC64_HEADER_BYTES];
- cassette_image_read(cassette, header, 0, TVC64_HEADER_BYTES);
+ cassette->image_read(header, 0, TVC64_HEADER_BYTES);
uint16_t cas_size = (header[0x83]<<8) | header[0x82];
// tape header
@@ -172,7 +172,7 @@ static cassette_image::error tvc64_cassette_load(cassette_image *cassette)
// sector data
int sector_size = (i == sector_num) ? (cas_size % 256) : 256;
for (int z=0; z < sector_size; z++)
- cassette_image_read(cassette, &tmp_buff[buff_idx++], TVC64_HEADER_BYTES + i*256 + z, 1);
+ cassette->image_read(&tmp_buff[buff_idx++], TVC64_HEADER_BYTES + i*256 + z, 1);
if (i == sector_num || ((i+1) == sector_num && (cas_size % 256 ) == 0))
tmp_buff[buff_idx++] = 0xff; // last sector
@@ -200,10 +200,10 @@ static cassette_image::error tvc64_cassette_load(cassette_image *cassette)
return cassette_image::error::SUCCESS;
}
-static cassette_image::error tvc64_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error tvc64_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
uint8_t byte;
- cassette_image_read(cassette, &byte, 0, 1);
+ cassette->image_read(&byte, 0, 1);
if (byte == 0x11)
{
@@ -216,7 +216,7 @@ static cassette_image::error tvc64_cassette_identify(cassette_image *cassette, s
return cassette_image::error::INVALID_IMAGE;
}
-static const struct CassetteFormat tvc64_cassette_image_format =
+static const cassette_image::Format tvc64_cassette_image_format =
{
"cas",
tvc64_cassette_identify,
diff --git a/src/lib/formats/tzx_cas.cpp b/src/lib/formats/tzx_cas.cpp
index e1ced8175f0..1804e89b1b6 100644
--- a/src/lib/formats/tzx_cas.cpp
+++ b/src/lib/formats/tzx_cas.cpp
@@ -52,7 +52,7 @@ static const uint8_t TZX_HEADER[8] = { 'Z','X','T','a','p','e','!',0x1a };
Initialized by tzx_cas_get_wave_size, used (and cleaned up) by tzx_cas_fill_wave
*/
-static int16_t wave_data = 0;
+static int16_t wave_data = 0; // FIXME: global variables prevent multiple instances
static int block_count = 0;
static uint8_t** blocks = nullptr;
static float t_scale = 1; /* for scaling T-states to the 4MHz CPC */
@@ -831,7 +831,7 @@ static int tap_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes )
return size;
}
-static const struct CassetteLegacyWaveFiller tzx_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller tzx_legacy_fill_wave =
{
tzx_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -842,7 +842,7 @@ static const struct CassetteLegacyWaveFiller tzx_legacy_fill_wave =
0 /* trailer_samples */
};
-static const struct CassetteLegacyWaveFiller tap_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller tap_legacy_fill_wave =
{
tap_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -853,7 +853,7 @@ static const struct CassetteLegacyWaveFiller tap_legacy_fill_wave =
0 /* trailer_samples */
};
-static const struct CassetteLegacyWaveFiller cdt_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller cdt_legacy_fill_wave =
{
cdt_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -864,24 +864,24 @@ static const struct CassetteLegacyWaveFiller cdt_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error tzx_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts )
+static cassette_image::error tzx_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )
{
- return cassette_legacy_identify(cassette, opts, &tzx_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &tzx_legacy_fill_wave);
}
-static cassette_image::error tap_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts )
+static cassette_image::error tap_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )
{
- return cassette_legacy_identify(cassette, opts, &tap_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &tap_legacy_fill_wave);
}
-static cassette_image::error cdt_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts )
+static cassette_image::error cdt_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )
{
- return cassette_legacy_identify(cassette, opts, &cdt_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &cdt_legacy_fill_wave);
}
static cassette_image::error tzx_cassette_load( cassette_image *cassette )
{
- cassette_image::error err = cassette_legacy_construct(cassette, &tzx_legacy_fill_wave);
+ cassette_image::error err = cassette->legacy_construct(&tzx_legacy_fill_wave);
free(blocks);
blocks = nullptr;
return err;
@@ -889,18 +889,18 @@ static cassette_image::error tzx_cassette_load( cassette_image *cassette )
static cassette_image::error tap_cassette_load( cassette_image *cassette )
{
- return cassette_legacy_construct(cassette, &tap_legacy_fill_wave);
+ return cassette->legacy_construct(&tap_legacy_fill_wave);
}
static cassette_image::error cdt_cassette_load( cassette_image *cassette )
{
- cassette_image::error err = cassette_legacy_construct(cassette, &cdt_legacy_fill_wave);
+ cassette_image::error err = cassette->legacy_construct(&cdt_legacy_fill_wave);
free(blocks);
blocks = nullptr;
return err;
}
-const struct CassetteFormat tzx_cassette_format =
+const cassette_image::Format tzx_cassette_format =
{
"tzx",
tzx_cassette_identify,
@@ -908,7 +908,7 @@ const struct CassetteFormat tzx_cassette_format =
nullptr
};
-static const struct CassetteFormat tap_cassette_format =
+static const cassette_image::Format tap_cassette_format =
{
"tap,blk",
tap_cassette_identify,
@@ -916,7 +916,7 @@ static const struct CassetteFormat tap_cassette_format =
nullptr
};
-static const struct CassetteFormat cdt_cassette_format =
+static const cassette_image::Format cdt_cassette_format =
{
"cdt",
cdt_cassette_identify,
diff --git a/src/lib/formats/tzx_cas.h b/src/lib/formats/tzx_cas.h
index 2410ea57523..b7e620b1683 100644
--- a/src/lib/formats/tzx_cas.h
+++ b/src/lib/formats/tzx_cas.h
@@ -13,7 +13,7 @@
#include "cassimg.h"
-extern const struct CassetteFormat tzx_cassette_format;
+extern const cassette_image::Format tzx_cassette_format;
CASSETTE_FORMATLIST_EXTERN(tzx_cassette_formats);
CASSETTE_FORMATLIST_EXTERN(cdt_cassette_formats);
diff --git a/src/lib/formats/uef_cas.cpp b/src/lib/formats/uef_cas.cpp
index d19eb9b2e47..1b4fb1bc271 100644
--- a/src/lib/formats/uef_cas.cpp
+++ b/src/lib/formats/uef_cas.cpp
@@ -17,13 +17,13 @@ the size of memory to alloc for the decoding.
Not nice, but it works...
*/
-
-#include <cstring>
-#include <cmath>
-#include <cassert>
+#include "uef_cas.h"
#include <zlib.h>
-#include "uef_cas.h"
+
+#include <cassert>
+#include <cmath>
+#include <cstring>
#define UEF_WAV_FREQUENCY 4800
@@ -334,7 +334,7 @@ static int uef_cas_fill_wave( int16_t *buffer, int length, uint8_t *bytes )
return p - buffer;
}
-static const struct CassetteLegacyWaveFiller uef_legacy_fill_wave = {
+static const cassette_image::LegacyWaveFiller uef_legacy_fill_wave = {
uef_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
@@ -344,21 +344,21 @@ static const struct CassetteLegacyWaveFiller uef_legacy_fill_wave = {
0 /* trailer_samples */
};
-static cassette_image::error uef_cassette_identify( cassette_image *cassette, struct CassetteOptions *opts ) {
+static cassette_image::error uef_cassette_identify( cassette_image *cassette, cassette_image::Options *opts ) {
uint8_t header[10];
- cassette_image_read(cassette, header, 0, sizeof(header));
+ cassette->image_read(header, 0, sizeof(header));
if (memcmp(&header[0], GZ_HEADER, sizeof(GZ_HEADER)) && memcmp(&header[0], UEF_HEADER, sizeof(UEF_HEADER))) {
return cassette_image::error::INVALID_IMAGE;
}
- return cassette_legacy_identify( cassette, opts, &uef_legacy_fill_wave );
+ return cassette->legacy_identify( opts, &uef_legacy_fill_wave );
}
static cassette_image::error uef_cassette_load( cassette_image *cassette ) {
- return cassette_legacy_construct( cassette, &uef_legacy_fill_wave );
+ return cassette->legacy_construct( &uef_legacy_fill_wave );
}
-const struct CassetteFormat uef_cassette_format = {
+const cassette_image::Format uef_cassette_format = {
"uef",
uef_cassette_identify,
uef_cassette_load,
diff --git a/src/lib/formats/uef_cas.h b/src/lib/formats/uef_cas.h
index 73aa2fe8ae2..f6bcff94ca1 100644
--- a/src/lib/formats/uef_cas.h
+++ b/src/lib/formats/uef_cas.h
@@ -12,7 +12,7 @@
#include "cassimg.h"
-extern const struct CassetteFormat uef_cassette_format;
+extern const cassette_image::Format uef_cassette_format;
CASSETTE_FORMATLIST_EXTERN(uef_cassette_formats);
diff --git a/src/lib/formats/vg5k_cas.cpp b/src/lib/formats/vg5k_cas.cpp
index 97d7421f622..f73049299b1 100644
--- a/src/lib/formats/vg5k_cas.cpp
+++ b/src/lib/formats/vg5k_cas.cpp
@@ -5,17 +5,17 @@
Support for VG-5000 .k7 cassette images
********************************************************************/
-#include <cassert>
-
#include "vg5k_cas.h"
+#include <cassert>
+
#define SMPLO -32768
#define SILENCE 0
#define SMPHI 32767
-static int k7_size;
+static int k7_size; // FIXME: global variable prevents multiple instances
/*******************************************************************
Generate one high-low cycle of sample data
@@ -200,7 +200,7 @@ static int vg5k_k7_to_wav_size(const uint8_t *casdata, int caslen)
}
-static const struct CassetteLegacyWaveFiller vg5k_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller vg5k_legacy_fill_wave =
{
vg5k_k7_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -211,19 +211,19 @@ static const struct CassetteLegacyWaveFiller vg5k_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error vg5k_k7_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error vg5k_k7_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &vg5k_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &vg5k_legacy_fill_wave);
}
static cassette_image::error vg5k_k7_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &vg5k_legacy_fill_wave);
+ return cassette->legacy_construct(&vg5k_legacy_fill_wave);
}
-static const struct CassetteFormat vg5k_k7_format =
+static const cassette_image::Format vg5k_k7_format =
{
"k7",
vg5k_k7_identify,
@@ -234,5 +234,5 @@ static const struct CassetteFormat vg5k_k7_format =
CASSETTE_FORMATLIST_START(vg5k_cassette_formats)
CASSETTE_FORMAT(vg5k_k7_format)
- CASSETTE_FORMAT(wavfile_format)
+ CASSETTE_FORMAT(cassette_image::wavfile_format)
CASSETTE_FORMATLIST_END
diff --git a/src/lib/formats/vt_cas.cpp b/src/lib/formats/vt_cas.cpp
index a8c30f8d25f..735ec067d7b 100644
--- a/src/lib/formats/vt_cas.cpp
+++ b/src/lib/formats/vt_cas.cpp
@@ -1,9 +1,9 @@
// license:GPL-2.0+
// copyright-holders:Juergen Buchmueller
-#include <cassert>
-
#include "formats/vt_cas.h"
+#include <cassert>
+
/*********************************************************************
vtech 1/2 agnostic
*********************************************************************/
@@ -97,28 +97,28 @@ static int vtech1_cassette_fill_wave(int16_t *buffer, int length, uint8_t *code)
return generic_fill_wave(buffer, length, code, V1_BITSAMPLES, V1_BYTESAMPLES, V1_LO, vtech1_fill_wave_byte);
}
-static const struct CassetteLegacyWaveFiller vtech1_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller vtech1_legacy_fill_wave =
{
- vtech1_cassette_fill_wave, /* fill_wave */
- 1, /* chunk_size */
- V1_BYTESAMPLES, /* chunk_samples */
- nullptr, /* chunk_sample_calc */
- 600*V1_BITSAMPLES, /* sample_frequency */
- 600*V1_BITSAMPLES, /* header_samples */
- 600*V1_BITSAMPLES /* trailer_samples */
+ vtech1_cassette_fill_wave, // fill_wave
+ 1, // chunk_size
+ V1_BYTESAMPLES, // chunk_samples
+ nullptr, // chunk_sample_calc
+ 600*V1_BITSAMPLES, // sample_frequency
+ 600*V1_BITSAMPLES, // header_samples
+ 600*V1_BITSAMPLES // trailer_samples
};
-static cassette_image::error vtech1_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error vtech1_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &vtech1_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &vtech1_legacy_fill_wave);
}
static cassette_image::error vtech1_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &vtech1_legacy_fill_wave);
+ return cassette->legacy_construct(&vtech1_legacy_fill_wave);
}
-static const struct CassetteFormat vtech1_cas_format =
+static const cassette_image::Format vtech1_cas_format =
{
"cas",
vtech1_cas_identify,
@@ -192,7 +192,7 @@ static int vtech2_cassette_fill_wave(int16_t *buffer, int length, uint8_t *code)
return generic_fill_wave(buffer, length, code, VT2_BITSAMPLES, VT2_BYTESAMPLES, VT2_LO, vtech2_fill_wave_byte);
}
-static const struct CassetteLegacyWaveFiller vtech2_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller vtech2_legacy_fill_wave =
{
vtech2_cassette_fill_wave, /* fill_wave */
1, /* chunk_size */
@@ -203,17 +203,17 @@ static const struct CassetteLegacyWaveFiller vtech2_legacy_fill_wave =
600*VT2_BITSAMPLES /* trailer_samples */
};
-static cassette_image::error vtech2_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error vtech2_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &vtech2_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &vtech2_legacy_fill_wave);
}
static cassette_image::error vtech2_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &vtech2_legacy_fill_wave);
+ return cassette->legacy_construct(&vtech2_legacy_fill_wave);
}
-static const struct CassetteFormat vtech2_cas_format =
+static const cassette_image::Format vtech2_cas_format =
{
"cas",
vtech2_cas_identify,
diff --git a/src/lib/formats/wavfile.cpp b/src/lib/formats/wavfile.cpp
index 1408984079c..74976ef997e 100644
--- a/src/lib/formats/wavfile.cpp
+++ b/src/lib/formats/wavfile.cpp
@@ -8,12 +8,11 @@
*********************************************************************/
+#include "wavfile.h"
+
#include <cstdio>
#include <cassert>
-#include "wavfile.h"
-#include "cassimg.h"
-
static const char magic1[4] = { 'R', 'I', 'F', 'F' };
static const char magic2[4] = { 'W', 'A', 'V', 'E' };
static const char format_tag_id[4] = { 'f', 'm', 't', ' ' };
@@ -57,7 +56,7 @@ static void put_leuint16(void *ptr, uint16_t value)
-static cassette_image::error wavfile_process(cassette_image *cassette, struct CassetteOptions *opts,
+static cassette_image::error wavfile_process(cassette_image *cassette, cassette_image::Options *opts,
bool read_waveform)
{
uint8_t file_header[12];
@@ -76,7 +75,7 @@ static cassette_image::error wavfile_process(cassette_image *cassette, struct Ca
int waveform_flags = 0;
/* read header */
- cassette_image_read(cassette, file_header, 0, sizeof(file_header));
+ cassette->image_read(file_header, 0, sizeof(file_header));
offset = sizeof(file_header);
/* check magic numbers */
@@ -87,13 +86,13 @@ static cassette_image::error wavfile_process(cassette_image *cassette, struct Ca
/* read and sanity check size */
stated_size = get_leuint32(&file_header[4]) + 8;
- file_size = cassette_image_size(cassette);
+ file_size = cassette->image_size();
if (stated_size > file_size)
stated_size = (uint32_t) file_size;
while(offset < stated_size)
{
- cassette_image_read(cassette, tag_header, offset, sizeof(tag_header));
+ cassette->image_read(tag_header, offset, sizeof(tag_header));
tag_size = get_leuint32(&tag_header[4]);
offset += sizeof(tag_header);
@@ -104,7 +103,7 @@ static cassette_image::error wavfile_process(cassette_image *cassette, struct Ca
return cassette_image::error::INVALID_IMAGE;
format_specified = true;
- cassette_image_read(cassette, format_tag, offset, sizeof(format_tag));
+ cassette->image_read(format_tag, offset, sizeof(format_tag));
format_type = get_leuint16(&format_tag[0]);
opts->channels = get_leuint16(&format_tag[2]);
@@ -121,13 +120,13 @@ static cassette_image::error wavfile_process(cassette_image *cassette, struct Ca
switch(opts->bits_per_sample)
{
case 8:
- waveform_flags = CASSETTE_WAVEFORM_8BIT | CASSETTE_WAVEFORM_UNSIGNED; // 8-bits wav are stored unsigned
+ waveform_flags = cassette_image::WAVEFORM_8BIT | cassette_image::WAVEFORM_UNSIGNED; // 8-bits wav are stored unsigned
break;
case 16:
- waveform_flags = CASSETTE_WAVEFORM_16BITLE;
+ waveform_flags = cassette_image::WAVEFORM_16BITLE;
break;
case 32:
- waveform_flags = CASSETTE_WAVEFORM_32BITLE;
+ waveform_flags = cassette_image::WAVEFORM_32BITLE;
break;
default:
return cassette_image::error::INVALID_IMAGE;
@@ -142,7 +141,7 @@ static cassette_image::error wavfile_process(cassette_image *cassette, struct Ca
if (read_waveform)
{
tag_samples = tag_size / (opts->bits_per_sample / 8) / opts->channels;
- cassette_read_samples(cassette, opts->channels, 0.0, tag_samples / ((double) opts->sample_frequency),
+ cassette->read_samples(opts->channels, 0.0, tag_samples / ((double) opts->sample_frequency),
tag_samples, offset, waveform_flags);
}
}
@@ -158,7 +157,7 @@ static cassette_image::error wavfile_process(cassette_image *cassette, struct Ca
-static cassette_image::error wavfile_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error wavfile_identify(cassette_image *cassette, cassette_image::Options *opts)
{
return wavfile_process(cassette, opts, false);
}
@@ -167,14 +166,14 @@ static cassette_image::error wavfile_identify(cassette_image *cassette, struct C
static cassette_image::error wavfile_load(cassette_image *cassette)
{
- struct CassetteOptions opts;
+ cassette_image::Options opts;
memset(&opts, 0, sizeof(opts));
return wavfile_process(cassette, &opts, true);
}
-static cassette_image::error wavfile_save(cassette_image *cassette, const struct CassetteInfo *info)
+static cassette_image::error wavfile_save(cassette_image *cassette, const cassette_image::Info *info)
{
cassette_image::error err;
uint8_t consolidated_header[12 + 8 + 16 + 8];
@@ -187,7 +186,7 @@ static cassette_image::error wavfile_save(cassette_image *cassette, const struct
uint16_t bits_per_sample;
uint32_t data_size;
size_t bytes_per_sample = 2;
- int waveform_flags = CASSETTE_WAVEFORM_16BITLE;
+ int waveform_flags = cassette_image::WAVEFORM_16BITLE;
uint16_t block_align;
bits_per_sample = (uint16_t) (bytes_per_sample * 8);
@@ -216,10 +215,10 @@ static cassette_image::error wavfile_save(cassette_image *cassette, const struct
put_leuint32(&data_tag_header[4], data_size);
/* write consolidated header */
- cassette_image_write(cassette, consolidated_header, 0, sizeof(consolidated_header));
+ cassette->image_write(consolidated_header, 0, sizeof(consolidated_header));
/* write out the actual data */
- err = cassette_write_samples(cassette, info->channels, 0.0, info->sample_count
+ err = cassette->write_samples(info->channels, 0.0, info->sample_count
/ (double) info->sample_frequency, info->sample_count, sizeof(consolidated_header),
waveform_flags);
if (err != cassette_image::error::SUCCESS)
@@ -230,7 +229,7 @@ static cassette_image::error wavfile_save(cassette_image *cassette, const struct
-const struct CassetteFormat wavfile_format =
+const cassette_image::Format cassette_image::wavfile_format =
{
"wav",
wavfile_identify,
@@ -264,7 +263,7 @@ void wavfile_testload(const char *fname)
if (!f)
return;
- if (cassette_open(f, &stdio_ioprocs, &wavfile_format, CASSETTE_FLAG_READONLY, &cassette))
+ if (cassette_open(f, &stdio_ioprocs, &wavfile_format, cassette_image::FLAG_READONLY, &cassette))
{
fclose(f);
return;
diff --git a/src/lib/formats/wavfile.h b/src/lib/formats/wavfile.h
index 0f48b8378b0..397d502a0ec 100644
--- a/src/lib/formats/wavfile.h
+++ b/src/lib/formats/wavfile.h
@@ -14,6 +14,4 @@
#include "cassimg.h"
-extern const struct CassetteFormat wavfile_format;
-
#endif // MAME_FORMATS_WAVFILE_H
diff --git a/src/lib/formats/x07_cas.cpp b/src/lib/formats/x07_cas.cpp
index 131693f2da1..182a1303cd8 100644
--- a/src/lib/formats/x07_cas.cpp
+++ b/src/lib/formats/x07_cas.cpp
@@ -6,10 +6,10 @@
********************************************************************/
-#include <cassert>
-
#include "x07_cas.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -19,7 +19,7 @@
#define X07_HEADER_BYTES 16
// image size
-static int x07_image_size;
+static int x07_image_size; // FIXME: global variable prevents multiple instances
static int x07_put_samples(int16_t *buffer, int sample_pos, int count, int level)
{
@@ -140,7 +140,7 @@ static int x07_cassette_calculate_size_in_samples(const uint8_t *bytes, int leng
return x07_handle_cassette(nullptr, bytes);
}
-static const struct CassetteLegacyWaveFiller x07_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller x07_legacy_fill_wave =
{
x07_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -151,17 +151,17 @@ static const struct CassetteLegacyWaveFiller x07_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error x07_cassette_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error x07_cassette_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &x07_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &x07_legacy_fill_wave);
}
static cassette_image::error x07_cassette_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &x07_legacy_fill_wave);
+ return cassette->legacy_construct(&x07_legacy_fill_wave);
}
-static const struct CassetteFormat x07_cassette_image_format =
+static const cassette_image::Format x07_cassette_image_format =
{
"k7,lst,cas",
x07_cassette_identify,
diff --git a/src/lib/formats/x1_tap.cpp b/src/lib/formats/x1_tap.cpp
index 88c962bf53b..cbd261f6610 100644
--- a/src/lib/formats/x1_tap.cpp
+++ b/src/lib/formats/x1_tap.cpp
@@ -20,15 +20,15 @@
* 0x00: Sampling rate (4 bytes)
*
*/
+#include "x1_tap.h"
#include <cassert>
-#include "x1_tap.h"
#define WAVE_HIGH 0x5a9e
#define WAVE_LOW -0x5a9e
-static int cas_size;
+static int cas_size; // FIXME: global variables prevent multiple instances
static int samplerate;
static int new_format;
@@ -103,7 +103,7 @@ static int x1_cas_fill_wave(int16_t *buffer, int sample_count, uint8_t *bytes)
return x1_handle_tap(buffer,bytes);
}
-static const struct CassetteLegacyWaveFiller x1_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller x1_legacy_fill_wave =
{
x1_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -114,20 +114,20 @@ static const struct CassetteLegacyWaveFiller x1_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error x1_cas_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error x1_cas_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &x1_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &x1_legacy_fill_wave);
}
static cassette_image::error x1_cas_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &x1_legacy_fill_wave);
+ return cassette->legacy_construct(&x1_legacy_fill_wave);
}
-static const struct CassetteFormat x1_cassette_format = {
+static const cassette_image::Format x1_cassette_format = {
"tap",
x1_cas_identify,
x1_cas_load,
diff --git a/src/lib/formats/zx81_p.cpp b/src/lib/formats/zx81_p.cpp
index 709bdccfc4c..186815507fe 100644
--- a/src/lib/formats/zx81_p.cpp
+++ b/src/lib/formats/zx81_p.cpp
@@ -31,11 +31,11 @@ medium transfer rate is approx. 307 bps (38 bytes/sec) for files that contain
*****************************************************************************/
-#include <cassert>
-
#include "zx81_p.h"
#include "tzx_cas.h"
+#include <cassert>
+
#define WAVEENTRY_LOW -32768
#define WAVEENTRY_HIGH 32767
@@ -56,7 +56,7 @@ medium transfer rate is approx. 307 bps (38 bytes/sec) for files that contain
#define ZX81_DATA_LENGTH_OFFSET 0x0b
#define ZX80_DATA_LENGTH_OFFSET 0x04
-static uint8_t zx_file_name[128];
+static uint8_t zx_file_name[128]; // FIXME: global variables prevent multiple instances
static uint16_t real_data_length = 0;
static uint8_t zx_file_name_length = 0;
@@ -64,9 +64,7 @@ static uint8_t zx_file_name_length = 0;
static int16_t *zx81_emit_level(int16_t *p, int count, int level)
{
- int i;
-
- for (i=0; i<count; i++) *(p++) = level;
+ for (int i=0; i<count; i++) *(p++) = level;
return p;
}
@@ -196,7 +194,7 @@ static int zx81_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
return p - buffer;
}
-static const struct CassetteLegacyWaveFiller zx81_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller zx81_legacy_fill_wave =
{
zx81_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -207,9 +205,9 @@ static const struct CassetteLegacyWaveFiller zx81_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error zx81_p_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error zx81_p_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &zx81_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &zx81_legacy_fill_wave);
}
static cassette_image::error zx81_p_load(cassette_image *cassette)
@@ -219,10 +217,10 @@ static cassette_image::error zx81_p_load(cassette_image *cassette)
Hardcoding this to "cassette".
*/
zx81_fill_file_name ("cassette" /*image_basename_noext(device_list_find_by_tag( Machine->config->m_devicelist, CASSETTE, "cassette" ))*/ );
- return cassette_legacy_construct(cassette, &zx81_legacy_fill_wave);
+ return cassette->legacy_construct(&zx81_legacy_fill_wave);
}
-static const struct CassetteFormat zx81_p_image_format =
+static const cassette_image::Format zx81_p_image_format =
{
"p,81",
zx81_p_identify,
@@ -269,7 +267,7 @@ static int zx80_cassette_fill_wave(int16_t *buffer, int length, uint8_t *bytes)
return p - buffer;
}
-static const struct CassetteLegacyWaveFiller zx80_legacy_fill_wave =
+static const cassette_image::LegacyWaveFiller zx80_legacy_fill_wave =
{
zx80_cassette_fill_wave, /* fill_wave */
-1, /* chunk_size */
@@ -280,17 +278,17 @@ static const struct CassetteLegacyWaveFiller zx80_legacy_fill_wave =
0 /* trailer_samples */
};
-static cassette_image::error zx80_o_identify(cassette_image *cassette, struct CassetteOptions *opts)
+static cassette_image::error zx80_o_identify(cassette_image *cassette, cassette_image::Options *opts)
{
- return cassette_legacy_identify(cassette, opts, &zx80_legacy_fill_wave);
+ return cassette->legacy_identify(opts, &zx80_legacy_fill_wave);
}
static cassette_image::error zx80_o_load(cassette_image *cassette)
{
- return cassette_legacy_construct(cassette, &zx80_legacy_fill_wave);
+ return cassette->legacy_construct(&zx80_legacy_fill_wave);
}
-static const struct CassetteFormat zx80_o_image_format =
+static const cassette_image::Format zx80_o_image_format =
{
"o,80",
zx80_o_identify,
diff --git a/src/lib/netlist/analog/nlid_fourterm.h b/src/lib/netlist/analog/nlid_fourterm.h
index 02ca5a9563b..8656cf7e32f 100644
--- a/src/lib/netlist/analog/nlid_fourterm.h
+++ b/src/lib/netlist/analog/nlid_fourterm.h
@@ -39,16 +39,20 @@ namespace analog {
NETLIB_CONSTRUCTOR_EX(VCCS, nl_fptype ri = nlconst::magic(1e9))
, m_G(*this, "G", nlconst::one())
, m_RI(*this, "RI", ri)
- , m_OP(*this, "OP", &m_IP, NETLIB_DELEGATE(termhandler))
- , m_ON(*this, "ON", &m_IP, NETLIB_DELEGATE(termhandler))
- , m_IP(*this, "IP", &m_IN, NETLIB_DELEGATE(termhandler)) // <= this should be NULL and terminal be filtered out prior to solving...
- , m_IN(*this, "IN", &m_IP, NETLIB_DELEGATE(termhandler)) // <= this should be NULL and terminal be filtered out prior to solving...
+ , m_OP(*this, "OP", &m_IP, {&m_ON, &m_IN}, NETLIB_DELEGATE(termhandler))
+ , m_ON(*this, "ON", &m_IP, {&m_OP, &m_IN}, NETLIB_DELEGATE(termhandler))
+ , m_IP(*this, "IP", &m_IN, {&m_OP, &m_ON}, NETLIB_DELEGATE(termhandler))
+ , m_IN(*this, "IN", &m_IP, {&m_OP, &m_ON}, NETLIB_DELEGATE(termhandler))
, m_OP1(*this, "_OP1", &m_IN, NETLIB_DELEGATE(termhandler))
, m_ON1(*this, "_ON1", &m_IN, NETLIB_DELEGATE(termhandler))
+ //, m_IPx(*this, "_IPx", &m_OP, NETLIB_DELEGATE(termhandler)) // <= this should be NULL and terminal be filtered out prior to solving...
+ //, m_INx(*this, "_INx", &m_ON, NETLIB_DELEGATE(termhandler)) // <= this should be NULL and terminal be filtered out prior to solving...
, m_gfac(nlconst::one())
{
connect(m_OP, m_OP1);
connect(m_ON, m_ON1);
+ //connect(m_IP, m_IPx);
+ //connect(m_IN, m_INx);
}
NETLIB_RESETI();
@@ -82,6 +86,9 @@ namespace analog {
terminal_t m_OP1;
terminal_t m_ON1;
+ //terminal_t m_IPx;
+ //terminal_t m_INx;
+
private:
nl_fptype m_gfac;
};
diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h
index fbf7b24b502..615bb7e19b3 100644
--- a/src/lib/netlist/analog/nlid_twoterm.h
+++ b/src/lib/netlist/analog/nlid_twoterm.h
@@ -54,7 +54,7 @@ namespace analog
// -----------------------------------------------------------------------------
template <class C>
- inline core_device_t &bselect(bool b, C &d1, core_device_t &d2)
+ static inline core_device_t &bselect(bool b, C &d1, core_device_t &d2)
{
auto *h = dynamic_cast<core_device_t *>(&d1);
return b ? *h : d2;
diff --git a/src/lib/netlist/buildVS/netlistlib.vcxproj b/src/lib/netlist/buildVS/netlistlib.vcxproj
index 543d7680f29..1344d71ba50 100755
--- a/src/lib/netlist/buildVS/netlistlib.vcxproj
+++ b/src/lib/netlist/buildVS/netlistlib.vcxproj
@@ -114,10 +114,13 @@
<ClCompile Include="..\analog\nlid_fourterm.cpp" />
<ClCompile Include="..\analog\nlid_twoterm.cpp" />
<ClCompile Include="..\devices\net_lib.cpp" />
- <ClCompile Include="..\devices\nld_2102A.cpp" />
+ <ClCompile Include="..\devices\nld_2102a.cpp" />
<ClCompile Include="..\devices\nld_4006.cpp" />
<ClCompile Include="..\devices\nld_4017.cpp" />
+ <ClCompile Include="..\devices\nld_4029.cpp" />
+ <ClCompile Include="..\devices\nld_4042.cpp" />
<ClCompile Include="..\devices\nld_4053.cpp" />
+ <ClCompile Include="..\devices\nld_4076.cpp" />
<ClCompile Include="..\devices\nld_74125.cpp" />
<ClCompile Include="..\devices\nld_74163.cpp" />
<ClCompile Include="..\devices\nld_74377.cpp" />
@@ -157,8 +160,8 @@
<ClCompile Include="..\devices\nld_7490.cpp" />
<ClCompile Include="..\devices\nld_7493.cpp" />
<ClCompile Include="..\devices\nld_74ls629.cpp" />
- <ClCompile Include="..\devices\nld_82S115.cpp" />
- <ClCompile Include="..\devices\nld_82S16.cpp" />
+ <ClCompile Include="..\devices\nld_82s115.cpp" />
+ <ClCompile Include="..\devices\nld_82s16.cpp" />
<ClCompile Include="..\devices\nld_9310.cpp" />
<ClCompile Include="..\devices\nld_9316.cpp" />
<ClCompile Include="..\devices\nld_9322.cpp" />
@@ -176,7 +179,9 @@
<ClCompile Include="..\devices\nlid_truthtable.cpp" />
<ClCompile Include="..\generated\nlm_modules_lib.cpp" />
<ClCompile Include="..\generated\static_solvers.cpp" />
- <ClCompile Include="..\macro\modules\nlmod_RTEST.cpp" />
+ <ClCompile Include="..\macro\modules\nlmod_icl8038_dip.cpp" />
+ <ClCompile Include="..\macro\modules\nlmod_ne556_dip.cpp" />
+ <ClCompile Include="..\macro\modules\nlmod_rtest.cpp" />
<ClCompile Include="..\macro\nlm_base_lib.cpp" />
<ClCompile Include="..\macro\nlm_cd4xxx_lib.cpp" />
<ClCompile Include="..\macro\nlm_opamp_lib.cpp" />
diff --git a/src/lib/netlist/buildVS/netlistlib.vcxproj.filters b/src/lib/netlist/buildVS/netlistlib.vcxproj.filters
index f858a2b9932..68df009f9ec 100755
--- a/src/lib/netlist/buildVS/netlistlib.vcxproj.filters
+++ b/src/lib/netlist/buildVS/netlistlib.vcxproj.filters
@@ -87,9 +87,6 @@
<ClCompile Include="..\devices\nld_7483.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\devices\nld_82S115.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\devices\nld_4013.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -129,9 +126,6 @@
<ClCompile Include="..\devices\nld_74153.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\devices\nld_82S16.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\devices\nld_74123.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -189,9 +183,6 @@
<ClCompile Include="..\devices\nld_74174.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\devices\nld_2102A.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\devices\nld_4316.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -291,7 +282,31 @@
<ClCompile Include="..\generated\nlm_modules_lib.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\macro\modules\nlmod_RTEST.cpp">
+ <ClCompile Include="..\devices\nld_4042.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\devices\nld_4076.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\devices\nld_4029.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\devices\nld_2102a.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\devices\nld_82s16.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\devices\nld_82s115.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\macro\modules\nlmod_icl8038_dip.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\macro\modules\nlmod_ne556_dip.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\macro\modules\nlmod_rtest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
diff --git a/src/lib/netlist/core/analog.h b/src/lib/netlist/core/analog.h
index 4bc986f48fc..d6f217210c4 100644
--- a/src/lib/netlist/core/analog.h
+++ b/src/lib/netlist/core/analog.h
@@ -61,6 +61,9 @@ namespace netlist
/// @param otherterm pointer to the sibling terminal
terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm, nldelegate delegate);
+ terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm,
+ const std::array<terminal_t *, 2> &splitterterms, nldelegate delegate);
+
/// \brief Returns voltage of connected net
///
/// @return voltage of net this terminal is connected to
diff --git a/src/lib/netlist/core/base_objects.h b/src/lib/netlist/core/base_objects.h
index 140fde1149e..edde9fa0f0f 100644
--- a/src/lib/netlist/core/base_objects.h
+++ b/src/lib/netlist/core/base_objects.h
@@ -239,7 +239,7 @@ namespace netlist
void set_net(net_t *anet) noexcept { m_net = anet; }
void clear_net() noexcept { m_net = nullptr; }
- bool has_net() const noexcept { return (m_net != nullptr); }
+ constexpr bool has_net() const noexcept { return (m_net != nullptr); }
net_t & net() const noexcept { return *m_net;}
@@ -251,8 +251,8 @@ namespace netlist
bool is_analog_input() const noexcept;
bool is_analog_output() const noexcept;
- bool is_state(state_e astate) const noexcept { return (m_state == astate); }
- state_e terminal_state() const noexcept { return m_state; }
+ constexpr bool is_state(state_e astate) const noexcept { return (m_state == astate); }
+ constexpr const state_e &terminal_state() const noexcept { return m_state; }
void set_state(state_e astate) noexcept { m_state = astate; }
void reset() noexcept { set_state(is_type(terminal_type::OUTPUT) ? STATE_OUT : STATE_INP_ACTIVE); }
@@ -265,12 +265,12 @@ namespace netlist
state_var_sig m_Q;
#else
- void set_copied_input(netlist_sig_t val) const noexcept { plib::unused_var(val); } // NOLINT: static means more message elsewhere
+ void set_copied_input(const netlist_sig_t &val) const noexcept { plib::unused_var(val); } // NOLINT: static means more message elsewhere
#endif
void set_delegate(const nldelegate &delegate) noexcept { m_delegate = delegate; }
const nldelegate &delegate() const noexcept { return m_delegate; }
- inline void run_delegate() noexcept { return m_delegate(); }
+ void run_delegate() const noexcept { return m_delegate(); }
private:
nldelegate m_delegate;
net_t * m_net;
diff --git a/src/lib/netlist/core/core_device.h b/src/lib/netlist/core/core_device.h
index 2e511ce6c9b..edfe25b6ec0 100644
--- a/src/lib/netlist/core/core_device.h
+++ b/src/lib/netlist/core/core_device.h
@@ -31,23 +31,27 @@ namespace netlist
void do_inc_active() noexcept
{
- if (m_hint_deactivate)
+ gsl_Expects(m_active_outputs >= 0);
+
+ if (m_activate && m_hint_deactivate)
{
if (++m_active_outputs == 1)
{
if (m_stats)
m_stats->m_stat_inc_active.inc();
- inc_active();
+ m_activate(true);//inc_active();
}
}
}
void do_dec_active() noexcept
{
- if (m_hint_deactivate)
+ gsl_Expects(m_active_outputs >= 1);
+
+ if (m_activate && m_hint_deactivate)
if (--m_active_outputs == 0)
{
- dec_active();
+ m_activate(false); //dec_active();
}
}
@@ -74,9 +78,9 @@ namespace netlist
}
protected:
+ using activate_delegate = plib::pmfp<void, bool>;
- virtual void inc_active() noexcept { }
- virtual void dec_active() noexcept { }
+ activate_delegate m_activate;
log_type & log();
diff --git a/src/lib/netlist/core/exec.h b/src/lib/netlist/core/exec.h
index 307baa6b0f2..50c718e3da6 100644
--- a/src/lib/netlist/core/exec.h
+++ b/src/lib/netlist/core/exec.h
@@ -33,15 +33,13 @@ namespace netlist
// run functions
- netlist_time_ext time() const noexcept { return m_time; }
+ const netlist_time_ext &time() const noexcept { return m_time; }
void process_queue(netlist_time_ext delta) noexcept;
void abort_current_queue_slice() noexcept
{
- if (!NL_USE_QUEUE_STATS || !m_use_stats)
- m_queue.retime<false>(detail::queue_t::entry_t(m_time, nullptr));
- else
- m_queue.retime<true>(detail::queue_t::entry_t(m_time, nullptr));
+ qremove(nullptr);
+ qpush(m_time, nullptr);
}
const detail::queue_t &queue() const noexcept { return m_queue; }
@@ -49,19 +47,27 @@ namespace netlist
template<typename... Args>
void qpush(Args&&...args) noexcept
{
- if (!NL_USE_QUEUE_STATS || !m_use_stats)
+#if (!NL_USE_QUEUE_STATS)
+ m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
+#else
+ if (!m_use_stats)
m_queue.emplace<false>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
else
m_queue.emplace<true>(std::forward<Args>(args)...); // NOLINT(performance-move-const-arg)
+#endif
}
template <class R>
void qremove(const R &elem) noexcept
{
- if (!NL_USE_QUEUE_STATS || !m_use_stats)
+#if (!NL_USE_QUEUE_STATS)
+ m_queue.remove<false>(elem);
+#else
+ if (!m_use_stats)
m_queue.remove<false>(elem);
else
m_queue.remove<true>(elem);
+#endif
}
// Control functions
@@ -87,9 +93,8 @@ namespace netlist
const log_type &log() const noexcept { return m_state.log(); }
void print_stats() const;
- bool use_stats() const { return m_use_stats; }
- bool stats_enabled() const noexcept { return m_use_stats; }
+ constexpr bool stats_enabled() const noexcept { return m_use_stats; }
void enable_stats(bool val) noexcept { m_use_stats = val; }
private:
@@ -107,8 +112,8 @@ namespace netlist
//PALIGNAS_CACHELINE()
//PALIGNAS(16)
- detail::queue_t m_queue;
bool m_use_stats;
+ detail::queue_t m_queue;
// performance
plib::pperftime_t<true> m_stat_mainloop;
plib::pperfcount_t<true> m_perf_out_processed;
diff --git a/src/lib/netlist/core/logic.h b/src/lib/netlist/core/logic.h
index c8ff979cc65..7bbcf5811d7 100644
--- a/src/lib/netlist/core/logic.h
+++ b/src/lib/netlist/core/logic.h
@@ -36,7 +36,7 @@ namespace netlist
{
return plib::downcast<logic_net_t &>(core_terminal_t::net());
}
- const logic_net_t & net() const noexcept
+ const logic_net_t & net() const noexcept
{
return plib::downcast<const logic_net_t &>(core_terminal_t::net());
}
@@ -52,9 +52,9 @@ namespace netlist
logic_input_t(device_t &dev, const pstring &aname,
nldelegate delegate);
- inline netlist_sig_t operator()() const noexcept
+ const netlist_sig_t &operator()() const noexcept
{
- nl_assert(terminal_state() != STATE_INP_PASSIVE);
+ gsl_Expects(terminal_state() != STATE_INP_PASSIVE);
#if NL_USE_COPY_INSTEAD_OF_REFERENCE
return m_Q;
#else
@@ -120,12 +120,14 @@ namespace netlist
void initial(netlist_sig_t val) noexcept;
- inline void push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept
+ void push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept
{
+ gsl_Expects(delay >= netlist_time::zero());
+
m_my_net.set_Q_and_push(newQ, delay); // take the shortcut
}
- inline void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept
+ void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept
{
m_my_net.set_Q_time(newQ, at); // take the shortcut
}
diff --git a/src/lib/netlist/core/netlist_state.h b/src/lib/netlist/core/netlist_state.h
index 137f264ddfd..fd0a1449217 100644
--- a/src/lib/netlist/core/netlist_state.h
+++ b/src/lib/netlist/core/netlist_state.h
@@ -76,7 +76,7 @@ namespace netlist
/// \return vector with pointers to devices
template<class C>
- inline std::vector<C *> get_device_list() const
+ std::vector<C *> get_device_list() const
{
std::vector<C *> tmp;
for (const auto &d : m_devices)
@@ -112,13 +112,13 @@ namespace netlist
template<typename O, typename C>
void save(O &owner, C &state, const pstring &module, const pstring &stname)
{
- this->run_state_manager().save_item(static_cast<void *>(&owner), state, module + "." + stname);
+ this->run_state_manager().save_item(plib::void_ptr_cast(&owner), state, module + "." + stname);
}
template<typename O, typename C>
void save(O &owner, C *state, const pstring &module, const pstring &stname, const std::size_t count)
{
- this->run_state_manager().save_state_ptr(static_cast<void *>(&owner), module + "." + stname, plib::state_manager_t::dtype<C>(), count, state);
+ this->run_state_manager().save_state_ptr(plib::void_ptr_cast(&owner), module + "." + stname, plib::state_manager_t::dtype<C>(), count, state);
}
// FIXME: only used by queue_t save state
@@ -217,24 +217,6 @@ namespace netlist
device_arena &pool() noexcept { return m_pool; }
const device_arena &pool() const noexcept { return m_pool; }
- /// \brief set extended validation mode.
- ///
- /// The extended validation mode is not intended for running.
- /// The intention is to identify power pins which are not properly
- /// connected. The downside is that this mode creates a netlist which
- /// is different (and not able to run).
- ///
- /// Extended validation is supported by nltool validate option.
- ///
- /// \param val Boolean value enabling/disabling extended validation mode
- void set_extended_validation(bool val) { m_extended_validation = val; }
-
- /// \brief State of extended validation mode.
- ///
- /// \returns boolean value indicating if extended validation mode is
- /// turned on.
- bool is_extended_validation() const { return m_extended_validation; }
-
struct stats_info
{
const detail::queue_t &m_queue;// performance
@@ -254,6 +236,11 @@ namespace netlist
///
void free_setup_resources();
+ std::vector<detail::core_terminal_t *> &core_terms(const detail::net_t &net) noexcept
+ {
+ return m_core_terms[&net];
+ }
+
private:
device_arena m_pool; // must be deleted last!
@@ -263,7 +250,7 @@ namespace netlist
plib::state_manager_t m_state;
log_type m_log;
- // FIXME: should only be available during device construcion
+ // FIXME: should only be available during device construction
host_arena::unique_ptr<setup_t> m_setup;
nets_collection_type m_nets;
@@ -271,8 +258,8 @@ namespace netlist
devices_collection_type m_devices;
// sole use is to manage lifetime of family objects
family_collection_type m_family_cache;
- bool m_extended_validation;
-
+ // all terms for a net
+ std::unordered_map<const detail::net_t *, std::vector<detail::core_terminal_t *>> m_core_terms;
// dummy version
int m_dummy_version;
};
diff --git a/src/lib/netlist/core/nets.h b/src/lib/netlist/core/nets.h
index db28687e5d0..7062f1572aa 100644
--- a/src/lib/netlist/core/nets.h
+++ b/src/lib/netlist/core/nets.h
@@ -17,6 +17,12 @@
#include "../plib/plists.h"
#include "../plib/pstring.h"
+// Enable the setting below to avoid queue pushes were at execution
+// no action will be taken. This is academically cleaner, but slower than
+// allowing this to happen and filter it during during "process".
+
+#define AVOID_NOOP_QUEUE_PUSHES (0)
+
namespace netlist
{
@@ -61,49 +67,80 @@ namespace netlist
void push_to_queue(const netlist_time &delay) noexcept
{
- if (has_connections())
- {
- if (!!is_queued())
- exec().qremove(this);
-
- const auto nst(exec().time() + delay);
- m_next_scheduled_time = nst;
-
- if (!m_list_active.empty())
- {
- m_in_queue = queue_status::QUEUED;
- exec().qpush(nst, this);
- }
+ if (!!is_queued())
+ exec().qremove(this);
+
+ m_next_scheduled_time = exec().time() + delay;
+#if (AVOID_NOOP_QUEUE_PUSHES)
+ m_in_queue = (m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE
+ : (m_new_Q != m_cur_Q ? queue_status::QUEUED : queue_status::DELIVERED));
+ if (m_in_queue == queue_status::QUEUED)
+ exec().qpush(m_next_scheduled_time, this);
else
- {
- m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
update_inputs();
- }
- }
+#else
+ m_in_queue = m_list_active.empty() ? queue_status::DELAYED_DUE_TO_INACTIVE : queue_status::QUEUED;
+ if (m_in_queue == queue_status::QUEUED)
+ exec().qpush(m_next_scheduled_time, this);
+ else
+ update_inputs();
+#endif
}
- NVCC_CONSTEXPR bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; }
+ constexpr bool is_queued() const noexcept { return m_in_queue == queue_status::QUEUED; }
+
+ // -----------------------------------------------------------------------------
+ // Very hot
+ // -----------------------------------------------------------------------------
template <bool KEEP_STATS>
- inline void update_devs() noexcept
+ void update_devs() noexcept
{
- nl_assert(this->is_rail_net());
+ gsl_Expects(this->is_rail_net());
m_in_queue = queue_status::DELIVERED; // mark as taken ...
- if (m_new_Q ^ m_cur_Q)
+
+ const netlist_sig_t new_Q(m_new_Q);
+ const netlist_sig_t cur_Q(m_cur_Q);
+#if (!AVOID_NOOP_QUEUE_PUSHES)
+ if (new_Q ^ cur_Q)
+#endif
{
- process<KEEP_STATS>((m_new_Q << core_terminal_t::INP_LH_SHIFT)
- | (m_cur_Q << core_terminal_t::INP_HL_SHIFT), m_new_Q);
+ const auto mask = (new_Q << core_terminal_t::INP_LH_SHIFT)
+ | (cur_Q << core_terminal_t::INP_HL_SHIFT);
+ m_cur_Q = new_Q;
+
+ if (!KEEP_STATS)
+ {
+ for (auto &p : m_list_active)
+ {
+ p.set_copied_input(new_Q);
+ if ((p.terminal_state() & mask) != 0)
+ p.run_delegate();
+ }
+ }
+ else
+ {
+ for (auto & p : m_list_active)
+ {
+ p.set_copied_input(new_Q);
+ auto *stats(p.device().stats());
+ stats->m_stat_call_count.inc();
+ if ((p.terminal_state() & mask))
+ {
+ auto g(stats->m_stat_total_time.guard());
+ p.run_delegate();
+ }
+ }
+ }
}
}
- netlist_time_ext next_scheduled_time() const noexcept { return m_next_scheduled_time; }
+ constexpr const netlist_time_ext &next_scheduled_time() const noexcept { return m_next_scheduled_time; }
void set_next_scheduled_time(netlist_time_ext ntime) noexcept { m_next_scheduled_time = ntime; }
- NVCC_CONSTEXPR bool is_rail_net() const noexcept { return !(m_railterminal == nullptr); }
+ bool is_rail_net() const noexcept { return !(m_railterminal == nullptr); }
core_terminal_t & railterminal() const noexcept { return *m_railterminal; }
- bool has_connections() const noexcept { return !m_core_terms.empty(); }
-
void add_to_active_list(core_terminal_t &term) noexcept
{
if (!m_list_active.empty())
@@ -117,7 +154,12 @@ namespace netlist
railterminal().device().do_inc_active();
if (m_in_queue == queue_status::DELAYED_DUE_TO_INACTIVE)
{
+#if (AVOID_NOOP_QUEUE_PUSHES)
+ if (m_next_scheduled_time > exec().time()
+ && (m_cur_Q != m_new_Q))
+#else
if (m_next_scheduled_time > exec().time())
+#endif
{
m_in_queue = queue_status::QUEUED; // pending
exec().qpush(m_next_scheduled_time, this);
@@ -139,7 +181,16 @@ namespace netlist
gsl_Expects(!m_list_active.empty());
m_list_active.remove(&term);
if (m_list_active.empty())
+ {
+#if (AVOID_NOOP_QUEUE_PUSHES)
+ if (!!is_queued())
+ {
+ exec().qremove(this);
+ m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
+ }
+#endif
railterminal().device().do_dec_active();
+ }
}
// -----------------------------------------------------------------------------
@@ -151,7 +202,7 @@ namespace netlist
void rebuild_list(); // rebuild m_list after a load
- std::vector<core_terminal_t *> &core_terms() noexcept { return m_core_terms; }
+ //std::vector<core_terminal_t *> &core_terms() noexcept { return state().m_core_terms[this]; }
void update_inputs() noexcept
{
@@ -165,7 +216,7 @@ namespace netlist
protected:
// only used for logic nets
- NVCC_CONSTEXPR netlist_sig_t Q() const noexcept { return m_cur_Q; }
+ constexpr const netlist_sig_t &Q() const noexcept { return m_cur_Q; }
// only used for logic nets
void initial(netlist_sig_t val) noexcept
@@ -175,8 +226,10 @@ namespace netlist
}
// only used for logic nets
- inline void set_Q_and_push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept
+ void set_Q_and_push(const netlist_sig_t &newQ, const netlist_time &delay) noexcept
{
+ gsl_Expects(delay >= netlist_time::zero());
+
if (newQ != m_new_Q)
{
m_new_Q = newQ;
@@ -185,8 +238,10 @@ namespace netlist
}
// only used for logic nets
- inline void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept
+ void set_Q_time(const netlist_sig_t &newQ, const netlist_time_ext &at) noexcept
{
+ gsl_Expects(at >= netlist_time_ext::zero());
+
if (newQ != m_new_Q)
{
m_in_queue = queue_status::DELAYED_DUE_TO_INACTIVE;
@@ -205,45 +260,12 @@ namespace netlist
state_var<netlist_sig_t> m_new_Q;
state_var<netlist_sig_t> m_cur_Q;
state_var<queue_status> m_in_queue;
+ plib::linkedlist_t<core_terminal_t> m_list_active;
state_var<netlist_time_ext> m_next_scheduled_time;
core_terminal_t * m_railterminal;
- plib::linkedlist_t<core_terminal_t> m_list_active;
- std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
-
- // -----------------------------------------------------------------------------
- // Very hot
- // -----------------------------------------------------------------------------
-
- template <bool KEEP_STATS, typename T, typename S>
- void process(T mask, const S &sig) noexcept
- {
- m_cur_Q = sig;
+ //std::vector<core_terminal_t *> m_core_terms; // save post-start m_list ...
- if (KEEP_STATS)
- {
- for (auto & p : m_list_active)
- {
- p.set_copied_input(sig);
- auto *stats(p.device().stats());
- stats->m_stat_call_count.inc();
- if ((p.terminal_state() & mask))
- {
- auto g(stats->m_stat_total_time.guard());
- p.run_delegate();
- }
- }
- }
- else
- {
- for (auto &p : m_list_active)
- {
- p.set_copied_input(sig);
- if ((p.terminal_state() & mask) != 0)
- p.run_delegate();
- }
- }
- }
};
} // namespace detail
@@ -255,10 +277,10 @@ namespace netlist
void reset() noexcept override;
- nl_fptype Q_Analog() const noexcept { return m_cur_Analog; }
+ const nl_fptype &Q_Analog() const noexcept { return m_cur_Analog; }
void set_Q_Analog(nl_fptype v) noexcept { m_cur_Analog = v; }
// used by solver code ...
- nl_fptype *Q_Analog_state_ptr() noexcept { return &m_cur_Analog(); }
+ nl_fptype *Q_Analog_state_ptr() noexcept { return *m_cur_Analog; }
//FIXME: needed by current solver code
solver::matrix_solver_t *solver() const noexcept { return m_solver; }
diff --git a/src/lib/netlist/core/object_array.h b/src/lib/netlist/core/object_array.h
index 0079d819c3e..f8b811482fc 100644
--- a/src/lib/netlist/core/object_array.h
+++ b/src/lib/netlist/core/object_array.h
@@ -133,7 +133,7 @@ namespace netlist
private:
template <std::size_t P>
- inline constexpr value_type e() const { return (*this)[P](); }
+ constexpr const value_type &e() const { return (*this)[P](); }
};
template<std::size_t N>
@@ -144,7 +144,7 @@ namespace netlist
using base_type::base_type;
template <typename T>
- inline void push(const T &v, const netlist_time &t)
+ void push(const T &v, const netlist_time &t)
{
if (N >= 1) (*this)[0].push((v >> 0) & 1, t);
if (N >= 2) (*this)[1].push((v >> 1) & 1, t);
@@ -197,7 +197,7 @@ namespace netlist
using base_type::base_type;
template <typename T>
- inline void push(const T &v, const netlist_time &t)
+ void push(const T &v, const netlist_time &t)
{
if (N >= 1) (*this)[0].push((v >> 0) & 1, t);
if (N >= 2) (*this)[1].push((v >> 1) & 1, t);
diff --git a/src/lib/netlist/core/param.h b/src/lib/netlist/core/param.h
index 2007d1f844d..dbabef073e7 100644
--- a/src/lib/netlist/core/param.h
+++ b/src/lib/netlist/core/param.h
@@ -79,8 +79,8 @@ namespace netlist
param_num_t(core_device_t &device, const pstring &name, T val) noexcept(false);
- T operator()() const noexcept { return m_param; }
- operator T() const noexcept { return m_param; }
+ constexpr const T &operator()() const noexcept { return m_param; }
+ constexpr operator const T& () const noexcept { return m_param; }
void set(const T &param) noexcept { set_and_update_param(m_param, param); }
diff --git a/src/lib/netlist/core/queue.h b/src/lib/netlist/core/queue.h
index 7e38c3f0ef9..350329ed3f1 100644
--- a/src/lib/netlist/core/queue.h
+++ b/src/lib/netlist/core/queue.h
@@ -21,12 +21,13 @@
#include <unordered_map>
#include <utility>
#include <vector>
+#include <queue>
namespace netlist
{
namespace detail {
// Use timed_queue_heap to use stdc++ heap functions instead of linear processing.
- // This slows down processing by about 25% on a Kaby Lake.
+ // This slows down processing by about 35% on a Kaby Lake.
// template <class T, bool TS>
// using timed_queue = plib::timed_queue_heap<T, TS>;
diff --git a/src/lib/netlist/core/setup.h b/src/lib/netlist/core/setup.h
index 8b8a49dbc34..1c8fc5742f9 100644
--- a/src/lib/netlist/core/setup.h
+++ b/src/lib/netlist/core/setup.h
@@ -144,13 +144,21 @@ namespace netlist
pstring get_initial_param_val(const pstring &name, const pstring &def) const;
void register_term(detail::core_terminal_t &term);
- void register_term(terminal_t &term, terminal_t &other_term);
+ void register_term(terminal_t &term, terminal_t *other_term, const std::array<terminal_t *, 2> &splitter_terms);
- // called from net_splitter
+ // called from matrix_solver_t::get_connected_net
+ // returns the terminal being part of a two terminal device.
terminal_t *get_connected_terminal(const terminal_t &term) const noexcept
{
auto ret(m_connected_terminals.find(&term));
- return (ret != m_connected_terminals.end()) ? ret->second : nullptr;
+ return (ret != m_connected_terminals.end()) ? ret->second[0] : nullptr;
+ }
+
+ // called from net_splitter
+ const std::array<terminal_t *, 4> *get_connected_terminals(const terminal_t &term) const noexcept
+ {
+ auto ret(m_connected_terminals.find(&term));
+ return (ret != m_connected_terminals.end()) ? &ret->second : nullptr;
}
// get family -> truthtable
@@ -223,7 +231,9 @@ namespace netlist
// FIXME: can be cleared before run
std::unordered_map<pstring, detail::core_terminal_t *> m_terminals;
- std::unordered_map<const terminal_t *, terminal_t *> m_connected_terminals;
+ // FIXME: Limited to 3 additional terminals
+ std::unordered_map<const terminal_t *,
+ std::array<terminal_t *, 4>> m_connected_terminals;
std::unordered_map<pstring, param_ref_t> m_params;
std::unordered_map<const detail::core_terminal_t *,
devices::nld_base_proxy *> m_proxies;
@@ -294,8 +304,9 @@ namespace netlist
{
public:
- explicit source_pattern_t(const pstring &pat)
+ explicit source_pattern_t(const pstring &pat, bool force_lowercase)
: m_pattern(pat)
+ , m_force_lowercase(force_lowercase)
{
}
@@ -304,6 +315,7 @@ namespace netlist
private:
pstring m_pattern;
+ bool m_force_lowercase;
};
class source_mem_t : public source_netlist_t
diff --git a/src/lib/netlist/core/state_var.h b/src/lib/netlist/core/state_var.h
index 55db73c1ac2..5839de26748 100644
--- a/src/lib/netlist/core/state_var.h
+++ b/src/lib/netlist/core/state_var.h
@@ -61,7 +61,8 @@ namespace netlist
//! Assignment operator to assign value of type T.
constexpr state_var &operator=(const T &rhs) noexcept { m_value = rhs; return *this; }
//! Assignment move operator to assign value of type T.
- constexpr state_var &operator=(T &&rhs) noexcept { std::swap(m_value, rhs); return *this; }
+ //constexpr state_var &operator=(T &&rhs) noexcept { std::swap(m_value, rhs); return *this; }
+ constexpr state_var &operator=(T &&rhs) noexcept { m_value = std::move(rhs); return *this; }
//! Return non-const value of state variable.
constexpr operator T & () noexcept { return m_value; }
//! Return const value of state variable.
@@ -78,6 +79,10 @@ namespace netlist
constexpr T * operator->() noexcept { return &m_value; }
//! Access state variable by const ->.
constexpr const T * operator->() const noexcept{ return &m_value; }
+ //! Access state variable by *.
+ constexpr T * operator *() noexcept { return &m_value; }
+ //! Access state variable by const *.
+ constexpr const T * operator *() const noexcept{ return &m_value; }
private:
T m_value;
diff --git a/src/lib/netlist/devices/nld_2102A.cpp b/src/lib/netlist/devices/nld_2102a.cpp
index 91c7c6b7ee0..91c7c6b7ee0 100644..100755
--- a/src/lib/netlist/devices/nld_2102A.cpp
+++ b/src/lib/netlist/devices/nld_2102a.cpp
diff --git a/src/lib/netlist/devices/nld_4029.cpp b/src/lib/netlist/devices/nld_4029.cpp
new file mode 100644
index 00000000000..4582746bf24
--- /dev/null
+++ b/src/lib/netlist/devices/nld_4029.cpp
@@ -0,0 +1,272 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud, Jonathan Gevaryahu
+/*
+ * nld_4029.cpp
+ *
+ * CD4029BM/CD4029BC Presettable Binary/Decade Up/Down Counter
+ *
+ * +--------------+
+ * PE |1 ++ 16| VDD
+ * Q4 |2 15| CLK
+ * J4 |3 14| Q3
+ * J1 |4 4029 13| J3
+ * CI |5 12| J2
+ * Q1 |6 11| Q2
+ * CO |7 10| U/D
+ * VSS |8 9| B/D
+ * +--------------+
+ *
+ * Counter Sequences:
+ *
+ * B/D high (Binary), U/D high (Up)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || A |
+ * | A || 1 | 0 | 1 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 | 1 || C |
+ * | C || 1 | 1 | 0 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 | 1 || E |
+ * | E || 1 | 1 | 1 | 0 | 1 || F |
+ * | F || 1 | 1 | 1 | 1 |0|CI|| 0 |
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * B/D high (Binary), U/D low (Down)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | F || 1 | 1 | 1 | 1 | 1 || E |
+ * | E || 1 | 1 | 1 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 | 1 || C |
+ * | C || 1 | 1 | 0 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 | 1 || A |
+ * | A || 1 | 0 | 1 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 0 |
+ * | 0 || 0 | 0 | 0 | 0 |0|CI|| F |
+ * | F || 1 | 1 | 1 | 1 | 1 || E |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * B/D low (Decimal), U/D high (Up)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 |0|CI|| 0 |
+ * | A || 1 | 0 | 1 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 |0|CI|| 6 |
+ * | C || 1 | 1 | 0 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 |0|CI|| 4 |
+ * | E || 1 | 1 | 1 | 0 | 1 || F |
+ * | F || 1 | 1 | 1 | 1 |0|CI|| 2 |
+ * | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * B/D low (Decimal), U/D low (Down)
+ * +-------++----+----+----+----+----++-------+
+ * | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+ * +=======++====+====+====+====+====++=======+
+ * | F || 1 | 1 | 1 | 1 | 1 || E |
+ * | E || 1 | 1 | 1 | 0 | 1 || D |
+ * | D || 1 | 1 | 0 | 1 | 1 || C |
+ * | C || 1 | 1 | 0 | 0 | 1 || B |
+ * | B || 1 | 0 | 1 | 1 | 1 || A |
+ * | A || 1 | 0 | 1 | 0 | 1 || 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+ * | 8 || 1 | 0 | 0 | 0 | 1 || 7 |
+ * | 7 || 0 | 1 | 1 | 1 | 1 || 6 |
+ * | 6 || 0 | 1 | 1 | 0 | 1 || 5 |
+ * | 5 || 0 | 1 | 0 | 1 | 1 || 4 |
+ * | 4 || 0 | 1 | 0 | 0 | 1 || 3 |
+ * | 3 || 0 | 0 | 1 | 1 | 1 || 2 |
+ * | 2 || 0 | 0 | 1 | 0 | 1 || 1 |
+ * | 1 || 0 | 0 | 0 | 1 | 1 || 0 |
+ * | 0 || 0 | 0 | 0 | 0 |0|CI|| 9 |
+ * | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+ * +-------++----+----+----+----+----++-------+
+ *
+ * Note that in all cases where Carry-out is generating a non-1 signal (0 | Carry-in),
+ * this signal is asynchronous, so if carry-in changes the carry-out value will
+ * change immediately.
+ *
+ *
+ * Preset/Carry in function table
+ * +-----+-----+-----++----+----+----+----+
+ * | PE | CLK | CI || Q1 | Q2 | Q3 | Q4 |
+ * +=====+=====+=====++====+====+====+====+
+ * | 1 | X | X || J1 | J2 | J3 | J4 |
+ * | 0 | X | 1 || Q1 | Q2 | Q3 | Q4 |
+ * | 0 | ./` | 0 || COUNT |
+ * +-----+-----+-----++----+----+----+----+
+ *
+ * Naming conventions follow National Semiconductor datasheet
+ *
+ */
+
+#include "nl_base.h"
+
+namespace netlist
+{
+namespace devices
+{
+
+ NETLIB_OBJECT(CD4029)
+ {
+ NETLIB_CONSTRUCTOR_MODEL(CD4029, "CD4XXX")
+ , m_PE(*this, "PE", NETLIB_DELEGATE(inputs))
+ , m_J(*this, {"J1", "J2", "J3", "J4"}, NETLIB_DELEGATE(inputs))
+ , m_CI(*this, "CI", NETLIB_DELEGATE(inputs))
+ , m_UD(*this, "UD", NETLIB_DELEGATE(inputs))
+ , m_BD(*this, "BD", NETLIB_DELEGATE(inputs))
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(clk))
+ , m_clk_old(*this, "m_clk_old", false)
+ , m_Q(*this, {"Q1", "Q2", "Q3", "Q4"})
+ , m_CO(*this, "CO", false)
+ , m_cnt(*this, "m_cnt", 0)
+ , m_power_pins(*this)
+ {
+ }
+
+ private:
+ NETLIB_HANDLERI(inputs) // pe causes an asynchronous counter load on level so has to be handled separately; if pe is high, then J changing will asynchronously change the Q state. changing J in this state does affect CO as well; CI will affect CO asynchronously if there is currently a carry
+ {
+ if (m_PE())
+ {
+ m_cnt = m_J()&0xf;
+ }
+ m_Q.push(m_cnt, NLTIME_FROM_NS(200));
+ // figure out CO
+ if (!m_UD()) // downward is the same for binary and decimal
+ {
+ m_CO.push(m_cnt||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // upward mode differs
+ {
+ if (!m_BD()) // decimal mode
+ {
+ m_CO.push((m_cnt<8)||(~m_cnt&1)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // binary mode
+ {
+ m_CO.push((m_cnt!=0xf)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ }
+ }
+
+ NETLIB_HANDLERI(clk)
+ {
+ // clocking only happens if m_clk_old was low, m_CLK is high, m_PE is NOT high, and m_CI is NOT high.
+ if (!m_PE() && !m_CI() && !m_clk_old && m_CLK())
+ {
+ if (m_BD()) // binary
+ {
+ m_cnt += (m_UD() ? 1 : -1);
+ m_cnt &= 0xf;
+ }
+ else // decimal
+ {
+ if (m_UD()) // upward
+ {
+ switch(m_cnt)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ case 8: case 0xa: case 0xc: case 0xe:
+ m_cnt++;
+ break;
+ case 9:
+ m_cnt = 0;
+ break;
+ case 0xb:
+ m_cnt = 6;
+ break;
+ case 0xd:
+ m_cnt = 4;
+ break;
+ case 0xf:
+ m_cnt = 2;
+ break;
+ }
+ }
+ else // downward
+ {
+ if (m_cnt>0)
+ {
+ m_cnt--;
+ }
+ else // m_cnt == 0
+ {
+ m_cnt = 9;
+ }
+ }
+ }
+ }
+ m_clk_old = m_CLK();
+ m_Q.push(m_cnt, NLTIME_FROM_NS(200));
+ // figure out CO
+ if (!m_UD()) // downward is the same for binary and decimal
+ {
+ m_CO.push(m_cnt||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // upward mode differs
+ {
+ if (!m_BD()) // decimal mode
+ {
+ m_CO.push((m_cnt<8)||(~m_cnt&1)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ else // binary mode
+ {
+ m_CO.push((m_cnt!=0xf)||m_CI(),NLTIME_FROM_NS(320));
+ }
+ }
+ }
+
+ NETLIB_RESETI()
+ {
+ m_cnt = 0;
+ m_clk_old = false;
+ }
+
+ logic_input_t m_PE;
+ object_array_t<logic_input_t, 4> m_J;
+ logic_input_t m_CI;
+ logic_input_t m_UD;
+ logic_input_t m_BD;
+ logic_input_t m_CLK;
+
+ state_var<netlist_sig_t> m_clk_old;
+ object_array_t<logic_output_t, 4> m_Q;
+ logic_output_t m_CO;
+ state_var_u8 m_cnt;
+ nld_power_pins m_power_pins;
+ };
+
+ NETLIB_DEVICE_IMPL(CD4029, "CD4029", "+PE,+J1,+J2,+J3,+J4,+CI,+UD,+BD,+CLK,@VCC,@GND")
+
+} // namespace devices
+} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_4042.cpp b/src/lib/netlist/devices/nld_4042.cpp
new file mode 100644
index 00000000000..a000d2e8af8
--- /dev/null
+++ b/src/lib/netlist/devices/nld_4042.cpp
@@ -0,0 +1,120 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud, Jonathan Gevaryahu
+/*
+ * nld_4042.cpp
+ *
+ * CD4042BM/CD4042BC Quad Clocked D Latch
+ *
+ * +--------------+
+ * Q4 |1 ++ 16| VDD
+ * Q1 |2 15| Q4Q
+ * Q1Q |3 14| D4
+ * D1 |4 4042 13| D3
+ * CLK |5 12| Q3Q
+ * POL |6 11| Q3
+ * D2 |7 10| Q2
+ * VSS |8 9| Q2Q
+ * +--------------+
+ *
+ *
+ * Function table
+ * +-----+-----+----++----+-----+
+ * | POL | CLK | Dx || Qx | QQx |
+ * +=====+=====+====++====+=====+
+ * | 0 | 0 | X || Qx | /Qx |
+ * | 0 | 1 | D || D | /D |
+ * | 1 | 1 | X || Qx | /Qx |
+ * | 1 | 0 | D || D | /D |
+ * +-----+-----+----++----+-----+
+ * Note that since this is a level triggered transparent latch,
+ * as long as POL ^ CLK == true, the latch is transparent, and
+ * if D changes Q and QQ(/Q) will instantly change.
+ *
+ * Naming conventions follow National Semiconductor datasheet
+ *
+ * National Semiconductor Datasheet: http://pdf.datasheetcatalog.com/datasheet/nationalsemiconductor/DS005966.PDF
+ * TI Datasheet: https://www.ti.com/lit/ds/symlink/cd4042b.pdf
+ */
+
+#include "nl_base.h"
+
+namespace netlist
+{
+namespace devices
+{
+
+
+ NETLIB_OBJECT(CD4042)
+ {
+ NETLIB_CONSTRUCTOR_MODEL(CD4042, "CD4XXX")
+ , m_D(*this, {"D1", "D2", "D3", "D4"}, NETLIB_DELEGATE(inputs))
+ , m_POL(*this, "POL", NETLIB_DELEGATE(clk))
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(clk))
+ , m_Q(*this, {"Q1", "Q2", "Q3", "Q4"})
+ , m_QQ(*this, {"Q1Q", "Q2Q", "Q3Q", "Q4Q"})
+ , m_latch(*this, "m_latch", 0)
+ , m_tpdq(*this, "m_tpd", netlist_time::from_nsec(175))
+ , m_tpdqq(*this, "m_tpd", netlist_time::from_nsec(150))
+ , m_tpcq(*this, "m_tpc", netlist_time::from_nsec(250))
+ , m_tpcqq(*this, "m_tpc", netlist_time::from_nsec(250))
+ , m_power_pins(*this, NETLIB_DELEGATE(vdd_vss))
+ {
+ }
+
+ private:
+ NETLIB_HANDLERI(clk)
+ {
+ if (m_POL() ^ m_CLK()) // are we in transparent mode? if so latch the data and push it.
+ {
+ m_latch = m_D()&0xf;
+ m_Q.push(m_latch&0xf, m_tpcq);
+ m_QQ.push((~m_latch)&0xf, m_tpcqq);
+ }
+ // if not, the data inputs are ignored and just do nothing
+ }
+
+ NETLIB_HANDLERI(inputs)
+ {
+ if ((m_POL() ^ m_CLK())&&(m_latch != (m_D()&0xf))) // are we in transparent mode? if so latch the data and push it. only do this if the data actually changed
+ {
+ m_latch = m_D()&0xf;
+ m_Q.push(m_latch&0xf, m_tpdq);
+ m_QQ.push((~m_latch)&0xf, m_tpdqq);
+ }
+ }
+
+ NETLIB_HANDLERI(vdd_vss)
+ {
+ auto d = m_power_pins.VCC()() - m_power_pins.GND()();
+ if (d > 0.1) // avoid unrealistic values
+ {
+ m_tpdq = netlist_time::from_nsec(gsl::narrow_cast<unsigned>(894.0 / d - 6.0));
+ m_tpdqq = netlist_time::from_nsec(gsl::narrow_cast<unsigned>(750.0 / d + 0.0));
+ m_tpcq = netlist_time::from_nsec(gsl::narrow_cast<unsigned>(1327.0 / d - 18.8));
+ m_tpcqq = netlist_time::from_nsec(gsl::narrow_cast<unsigned>(1234.5 / d + 0.8));
+ }
+ }
+
+ NETLIB_RESETI()
+ {
+ m_latch = 0;
+ }
+
+ object_array_t<logic_input_t, 4> m_D;
+ logic_input_t m_POL;
+ logic_input_t m_CLK;
+
+ object_array_t<logic_output_t, 4> m_Q;
+ object_array_t<logic_output_t, 4> m_QQ;
+ state_var_u8 m_latch;
+ state_var<netlist_time> m_tpdq; // propagation time for data alone when in transparent mode, Q
+ state_var<netlist_time> m_tpdqq; // propagation time for data alone when in transparent mode, /Q
+ state_var<netlist_time> m_tpcq; // propagation time for data vs CLK, Q
+ state_var<netlist_time> m_tpcqq; // propagation time for data vs CLK, /Q
+ nld_power_pins m_power_pins;
+ };
+
+ NETLIB_DEVICE_IMPL(CD4042, "CD4042", "+D1,+D2,+D3,+D4,+POL,+CLK,@VCC,@GND")
+
+} // namespace devices
+} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_4076.cpp b/src/lib/netlist/devices/nld_4076.cpp
new file mode 100644
index 00000000000..a69d02e2d54
--- /dev/null
+++ b/src/lib/netlist/devices/nld_4076.cpp
@@ -0,0 +1,132 @@
+// license:GPL-2.0+
+// copyright-holders:Couriersud, Jonathan Gevaryahu
+/*
+ * nld_4076.cpp
+ *
+ * CD4076BM/CD4076BC TRI-STATE(R) Quad D Flip-Flop
+ *
+ * +--------------+
+ * OD1 |1 ++ 16| VDD
+ * OD2 |2 15| CLR
+ * OA |3 14| IA
+ * OB |4 4076 13| IB
+ * OC |5 12| IC
+ * OD |6 11| ID
+ * CLK |7 10| ID2
+ * VSS |8 9| ID1
+ * +--------------+
+ *
+ *
+ * Function table for ID1/2 pins
+ * +-----+-----+-----+----+-----++-----+
+ * | ID1 | ID2 | CLR | Ix | CLK || iOx |
+ * +=====+=====+=====+====+=====++=====+
+ * | X | X | 0 | X | 0 || iOx |
+ * | X | X | 0 | X | 1 || iOx |
+ * | 1 | X | 0 | X | 0>1 || iOx |
+ * | X | 1 | 0 | X | 0>1 || iOx |
+ * | 0 | 0 | 0 | 0 | 0>1 || 0 |
+ * | 0 | 0 | 0 | 1 | 0>1 || 1 |
+ * | X | X | 1 | X | X || 0 |
+ * +-----+-----+-----+----+-----++-----+
+ * Note: iOX is an internal signal, the output of each D-latch
+ *
+ * Function table for OD1/2 pins vs output of the internal D-latches
+ * +-----+-----+-----++-----+
+ * | OD1 | OD2 | iOx || Ox |
+ * +=====+=====+=====++=====+
+ * | 1 | X | X || Z |
+ * | X | 1 | X || Z |
+ * | 0 | 0 | 0 || 0 |
+ * | 0 | 0 | 1 || 1 |
+ * +-----+-----+-----++-----+
+ *
+ * Naming conventions follow National Semiconductor datasheet
+ * http://www.bitsavers.org/components/national/_dataBooks/1981_Natonal_CMOS_Databook.pdf 5-186 (pdf page 567)
+ *
+ * TODO: the 74C173 is 100% identical to this CMOS part.
+ */
+
+#include "nl_base.h"
+
+namespace netlist
+{
+namespace devices
+{
+
+
+ NETLIB_OBJECT(CD4076)
+ {
+ NETLIB_CONSTRUCTOR_MODEL(CD4076, "CD4XXX")
+ , m_I(*this, {"IA", "IB", "IC", "ID"}, NETLIB_DELEGATE(id)) // if the d-pins change absolutely nothing happens, as they are clock-latched.
+ , m_ID1(*this, "ID1", NETLIB_DELEGATE(id))
+ , m_ID2(*this, "ID2", NETLIB_DELEGATE(id))
+ , m_enable_in(*this, "m_enable_in", true)
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(clk))
+ , m_clk_old(*this, "m_clk_old", 0)
+ , m_OD1(*this, "OD1", NETLIB_DELEGATE(od)) // if the OD pins change nothing about the internal state changes directly, but the outputs can change from driven to tri-state or vice-versa
+ , m_OD2(*this, "OD2", NETLIB_DELEGATE(od)) // ""
+ , m_enable_out(*this, "m_enable_out", true)
+ , m_O(*this, {"OA", "OB", "OC", "OD"})
+ , m_latch(*this, "m_latch", 0)
+ , m_power_pins(*this)
+ {
+ }
+
+ private:
+ NETLIB_HANDLERI(id)
+ {
+ m_enable_in = (!(m_ID1() || m_ID2()));
+ }
+
+ NETLIB_HANDLERI(clk)
+ {
+ if ((!m_clk_old) && m_CLK() && m_enable_in) // clock rising edge and input is enabled; otherwise the latch just re-latches its own value
+ {
+ m_latch = m_I()&0xf;
+ }
+ m_clk_old = m_CLK();
+ // update the pin output state
+ for (std::size_t i=0; i<4; i++)
+ {
+ m_O.set_tristate(m_enable_out, NLTIME_FROM_NS(170), NLTIME_FROM_NS(170));
+ m_O[i].push((m_latch >> i) & 1, NLTIME_FROM_NS(220));
+ }
+ }
+
+ NETLIB_HANDLERI(od)
+ {
+ m_enable_out = (!(m_OD1() || m_OD2()));
+ // update the pin output state
+ for (std::size_t i=0; i<4; i++)
+ {
+ m_O.set_tristate(m_enable_out, NLTIME_FROM_NS(170), NLTIME_FROM_NS(170));
+ m_O[i].push((m_latch >> i) & 1, NLTIME_FROM_NS(220));
+ }
+ }
+
+ NETLIB_RESETI()
+ {
+ m_latch = 0;
+ m_enable_in = true;
+ m_enable_out = true;
+ }
+
+ object_array_t<logic_input_t, 4> m_I;
+ logic_input_t m_ID1;
+ logic_input_t m_ID2;
+ state_var<bool> m_enable_in;
+ logic_input_t m_CLK;
+ state_var<netlist_sig_t> m_clk_old;
+ logic_input_t m_OD1;
+ logic_input_t m_OD2;
+ state_var<bool> m_enable_out;
+ object_array_t<logic_output_t, 4> m_O;
+ state_var_u8 m_latch;
+ nld_power_pins m_power_pins;
+ };
+
+ NETLIB_DEVICE_IMPL(CD4076, "CD4076", "+I1,+I2,+I3,+I4,+ID1,+ID2,+OD1,+OD2,@VCC,@GND")
+
+} // namespace devices
+} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_7448.cpp b/src/lib/netlist/devices/nld_7448.cpp
index 992caf9d814..f4acbc432bd 100644
--- a/src/lib/netlist/devices/nld_7448.cpp
+++ b/src/lib/netlist/devices/nld_7448.cpp
@@ -54,7 +54,7 @@ namespace netlist
private:
void update_outputs(unsigned v) noexcept
{
- nl_assert(v<16);
+ gsl_Expects(v<16);
if (v != m_state)
{
// max transfer time is 100 NS */
diff --git a/src/lib/netlist/devices/nld_7493.cpp b/src/lib/netlist/devices/nld_7493.cpp
index c52418f8d2e..54d44dc1fea 100644
--- a/src/lib/netlist/devices/nld_7493.cpp
+++ b/src/lib/netlist/devices/nld_7493.cpp
@@ -62,22 +62,19 @@ namespace netlist
namespace devices
{
- static constexpr const netlist_time out_delay = NLTIME_FROM_NS(18);
- static constexpr const netlist_time out_delay2 = NLTIME_FROM_NS(36);
- static constexpr const netlist_time out_delay3 = NLTIME_FROM_NS(54);
+ static constexpr std::array<netlist_time, 3> out_delay { NLTIME_FROM_NS(18), NLTIME_FROM_NS(36), NLTIME_FROM_NS(54) };
NETLIB_OBJECT(7493)
{
NETLIB_CONSTRUCTOR(7493)
- , m_R1(*this, "R1", NETLIB_DELEGATE(inputs))
- , m_R2(*this, "R2", NETLIB_DELEGATE(inputs))
- , m_a(*this, "_m_a", 0)
- , m_bcd(*this, "_m_b", 0)
- , m_r(*this, "_m_r", 0)
, m_CLKA(*this, "CLKA", NETLIB_DELEGATE(updA))
, m_CLKB(*this, "CLKB", NETLIB_DELEGATE(updB))
, m_QA(*this, "QA")
, m_QB(*this, {"QB", "QC", "QD"})
+ , m_a(*this, "m_a", 0)
+ , m_bcd(*this, "m_b", 0)
+ , m_R1(*this, "R1", NETLIB_DELEGATE(inputs))
+ , m_R2(*this, "R2", NETLIB_DELEGATE(inputs))
, m_power_pins(*this)
{
}
@@ -110,30 +107,27 @@ namespace netlist
NETLIB_HANDLERI(updA)
{
m_a ^= 1;
- m_QA.push(m_a, out_delay);
+ m_QA.push(m_a, out_delay[0]);
}
NETLIB_HANDLERI(updB)
{
const auto cnt(++m_bcd &= 0x07);
-
- m_QB[2].push((cnt >> 2) & 1, out_delay3);
- m_QB[1].push((cnt >> 1) & 1, out_delay2);
- m_QB[0].push(cnt & 1, out_delay);
+ m_QB.push(cnt, out_delay);
}
- logic_input_t m_R1;
- logic_input_t m_R2;
-
- state_var_sig m_a;
- state_var_sig m_bcd;
- state_var_sig m_r;
-
logic_input_t m_CLKA;
logic_input_t m_CLKB;
logic_output_t m_QA;
object_array_t<logic_output_t, 3> m_QB;
+
+ state_var<unsigned> m_a;
+ state_var<unsigned> m_bcd;
+
+ logic_input_t m_R1;
+ logic_input_t m_R2;
+
nld_power_pins m_power_pins;
};
diff --git a/src/lib/netlist/devices/nld_82S115.cpp b/src/lib/netlist/devices/nld_82s115.cpp
index f1e49bd9f83..f1e49bd9f83 100644..100755
--- a/src/lib/netlist/devices/nld_82S115.cpp
+++ b/src/lib/netlist/devices/nld_82s115.cpp
diff --git a/src/lib/netlist/devices/nld_82S16.cpp b/src/lib/netlist/devices/nld_82s16.cpp
index 2fc92adfe30..2fc92adfe30 100644..100755
--- a/src/lib/netlist/devices/nld_82S16.cpp
+++ b/src/lib/netlist/devices/nld_82s16.cpp
diff --git a/src/lib/netlist/devices/nld_9316_base.hxx b/src/lib/netlist/devices/nld_9316_base.hxx
index 3e8e977cb87..e0659493cf1 100644
--- a/src/lib/netlist/devices/nld_9316_base.hxx
+++ b/src/lib/netlist/devices/nld_9316_base.hxx
@@ -14,10 +14,10 @@ namespace netlist
{
template <unsigned N>
- static constexpr unsigned rollover(unsigned v) { return v <= N ? v : 0; }
+ static constexpr unsigned rollover(unsigned v) noexcept { return v <= N ? v : 0; }
template <>
- constexpr unsigned rollover<15>(unsigned v) { return v & 15; }
+ constexpr unsigned rollover<15>(unsigned v) noexcept { return v & 15; }
template <typename D>
NETLIB_OBJECT(9316_base)
@@ -25,11 +25,11 @@ namespace netlist
NETLIB_CONSTRUCTOR(9316_base)
, m_CLK(*this, "CLK", NETLIB_DELEGATE(clk))
, m_ENT(*this, "ENT", NETLIB_DELEGATE(other))
- , m_RC(*this, "RC")
, m_LOADQ(*this, "LOADQ", NETLIB_DELEGATE(other))
, m_ENP(*this, "ENP", NETLIB_DELEGATE(other))
, m_CLRQ(*this, "CLRQ", NETLIB_DELEGATE(other))
, m_ABCD(*this, {"A", "B", "C", "D"}, NETLIB_DELEGATE(abcd))
+ , m_RC(*this, "RC")
, m_Q(*this, { "QA", "QB", "QC", "QD" })
, m_cnt(*this, "m_cnt", 0)
, m_abcd(*this, "m_abcd", 0)
@@ -73,15 +73,15 @@ namespace netlist
{
if (!D::ASYNC::value && !m_CLRQ())
{
+ m_Q.push(0, D::tCLR::value(0));
m_cnt = 0;
- m_Q.push(m_cnt, D::tCLR::value(0));
}
else
{
- const auto cnt = (m_loadq ? rollover<D::MAXCNT::value>(m_cnt + 1) : m_abcd);
+ const unsigned cnt(m_loadq ? rollover<D::MAXCNT::value>(m_cnt + 1) : m_abcd);
m_RC.push(m_ent && (cnt == D::MAXCNT::value), D::tRC::value(0));
m_Q.push(cnt, D::tLDCNT::value(0));
- m_cnt = static_cast<unsigned>(cnt);
+ m_cnt = cnt;
}
}
@@ -93,22 +93,22 @@ namespace netlist
logic_input_t m_CLK;
logic_input_t m_ENT;
- logic_output_t m_RC;
-
logic_input_t m_LOADQ;
logic_input_t m_ENP;
logic_input_t m_CLRQ;
object_array_t<logic_input_t, 4> m_ABCD;
+
+ logic_output_t m_RC;
object_array_t<logic_output_t, 4> m_Q;
/* counter state */
state_var<unsigned> m_cnt;
/* cached pins */
state_var<unsigned> m_abcd;
- state_var_sig m_loadq;
- state_var_sig m_ent;
+ state_var<unsigned> m_loadq;
+ state_var<unsigned> m_ent;
nld_power_pins m_power_pins;
};
diff --git a/src/lib/netlist/devices/nld_9321.cpp b/src/lib/netlist/devices/nld_9321.cpp
index 5adffc3a313..29d63b2b3fc 100644
--- a/src/lib/netlist/devices/nld_9321.cpp
+++ b/src/lib/netlist/devices/nld_9321.cpp
@@ -50,7 +50,7 @@ namespace netlist
NETLIB_HANDLERI(e)
{
- m_enable = m_E() ? 0 : 1;
+ m_enable = m_E() ? false : true;
m_o = (m_A[1]() << 1) | m_A[0]();
for (std::size_t i=0; i<4; i++)
m_D[i].push((i == m_o && m_enable) ? 0 : 1, NLTIME_FROM_NS(18));
diff --git a/src/lib/netlist/devices/nld_log.cpp b/src/lib/netlist/devices/nld_log.cpp
index 75a22ddca32..c2a6523f64a 100644
--- a/src/lib/netlist/devices/nld_log.cpp
+++ b/src/lib/netlist/devices/nld_log.cpp
@@ -116,8 +116,8 @@ namespace netlist
netlist_time_ext t;
nl_fptype v;
};
- static const std::size_t BUF_SIZE=16384;
- static const std::size_t BUFFERS=4;
+ static constexpr std::size_t BUF_SIZE=16384;
+ static constexpr std::size_t BUFFERS=4;
analog_input_t m_I;
plib::ofstream m_strm;
plib::putf8_writer m_writer;
diff --git a/src/lib/netlist/devices/nld_roms.cpp b/src/lib/netlist/devices/nld_roms.cpp
index de440b4a8d2..e2e4ba4eb77 100644
--- a/src/lib/netlist/devices/nld_roms.cpp
+++ b/src/lib/netlist/devices/nld_roms.cpp
@@ -41,7 +41,7 @@ namespace netlist
}
private:
- inline NETLIB_HANDLERI(oe1)
+ NETLIB_HANDLERI(oe1)
{
m_enable_lo = m_OE1();
uint8_t o = m_enable_lo ? m_latched_rom : 0;
@@ -52,7 +52,7 @@ namespace netlist
}
}
- inline NETLIB_HANDLERI(oe2)
+ NETLIB_HANDLERI(oe2)
{
m_enable_hi = m_OE2();
uint8_t o = m_enable_hi ? m_latched_rom : 0;
@@ -63,7 +63,7 @@ namespace netlist
}
}
- inline NETLIB_HANDLERI(addr)
+ NETLIB_HANDLERI(addr)
{
if (!m_ARQ())
{
@@ -96,6 +96,72 @@ namespace netlist
nld_power_pins m_power_pins;
};
+ NETLIB_OBJECT(mcm14524_rom)
+ {
+ NETLIB_CONSTRUCTOR_MODEL(mcm14524_rom, "CD4XXX")
+ , m_enabled(*this, "m_enabled", true)
+ , m_latched_rom(*this, "m_latched_rom", 0)
+ , m_A(*this, 1, "A{}", NETLIB_DELEGATE(addr))
+ , m_CLK(*this, "CLK", NETLIB_DELEGATE(addr))
+ , m_clk_old(*this, "m_clk_old", true)
+ , m_EN(*this, "EN", NETLIB_DELEGATE(en))
+ , m_B(*this, 1, "B{}", 0)
+ , m_ROM(*this, "ROM")
+ , m_taccc(*this, "m_taccc", netlist_time::from_nsec(1350))
+ , m_taccen(*this, "m_taccen", netlist_time::from_nsec(245))
+ , m_power_pins(*this, NETLIB_DELEGATE(vdd_vss))
+ {
+ }
+
+ private:
+ NETLIB_HANDLERI(en)
+ {
+ m_enabled = m_EN();
+ uint8_t o = m_enabled ? m_latched_rom : 0; // outputs are forced to 0 by enable going low; this chip does not have tri-state outputs!
+ for (std::size_t i=0; i<4; i++)
+ {
+ m_B[i].push((o >> i) & 1, m_taccen);
+ }
+ }
+
+ NETLIB_HANDLERI(addr)
+ {
+ if (!m_CLK() && m_clk_old) // latch on falling edge
+ {
+ const auto addr = m_A();
+ m_latched_rom = m_ROM[addr];
+ }
+ m_clk_old = m_CLK();
+ uint8_t o = m_enabled ? m_latched_rom : 0; // outputs are forced to 0 by enable going low; this chip does not have tri-state outputs!
+ for (std::size_t i=0; i<4; i++)
+ {
+ m_B[i].push((o >> i) & 1, m_taccc);
+ }
+ }
+
+ NETLIB_HANDLERI(vdd_vss)
+ {
+ auto d = m_power_pins.VCC()() - m_power_pins.GND()();
+ if (d > 0.1) // avoid unrealistic values
+ {
+ m_taccc = netlist_time::from_nsec(gsl::narrow_cast<unsigned>(7615.5 / d - 181));
+ m_taccen = netlist_time::from_nsec(gsl::narrow_cast<unsigned>(1292.5 / d - 14.6));
+ }
+ }
+
+ state_var<bool> m_enabled;
+ state_var<uint8_t> m_latched_rom;
+ object_array_t<logic_input_t, 8> m_A;
+ logic_input_t m_CLK;
+ state_var<bool> m_clk_old;
+ logic_input_t m_EN;
+ object_array_t<tristate_output_t, 4> m_B;
+ param_rom_t<uint8_t, 8, 4> m_ROM;
+ state_var<netlist_time> m_taccc; // propagation time for data vs CLK
+ state_var<netlist_time> m_taccen; // propagation time for data vs /EN
+ nld_power_pins m_power_pins;
+ };
+
template <typename D>
NETLIB_OBJECT(generic_prom)
{
@@ -119,7 +185,7 @@ namespace netlist
private:
template <std::size_t N>
- inline NETLIB_HANDLERI(ce)
+ NETLIB_HANDLERI(ce)
{
using cet = typename D::chip_enable_time;
m_enabled = (m_CEQ() == D::chip_enable_mask::value);
@@ -148,7 +214,6 @@ namespace netlist
}
- inline
NETLIB_HANDLERI(addr)
{
if (m_enabled)
@@ -230,12 +295,14 @@ namespace netlist
using NETLIB_NAME(74S287) = NETLIB_NAME(generic_prom)<desc_74S287>; // 1024 bits, 32x32, used as 256x4
using NETLIB_NAME(2716) = NETLIB_NAME(generic_prom)<desc_2716>; // CE2Q = OE, CE1Q = CE
using NETLIB_NAME(MK28000) = NETLIB_NAME(mk28000_prom); // 16384 bits, either 2048x8 or 4096x4, determined by OE1/OE2 use
+ using NETLIB_NAME(MCM14524) = NETLIB_NAME(mcm14524_rom); // 1024 bits, 256x4, latched address
NETLIB_DEVICE_IMPL(82S126, "PROM_82S126", "+CE1Q,+CE2Q,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,@VCC,@GND")
NETLIB_DEVICE_IMPL(74S287, "PROM_74S287", "+CE1Q,+CE2Q,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,@VCC,@GND")
NETLIB_DEVICE_IMPL(82S123, "PROM_82S123", "+CEQ,+A0,+A1,+A2,+A3,+A4,@VCC,@GND")
NETLIB_DEVICE_IMPL(2716, "EPROM_2716", "+CE2Q,+CE1Q,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10,@VCC,@GND")
NETLIB_DEVICE_IMPL(MK28000, "PROM_MK28000", "+OE1,+OE2,+ARQ,+A1,+A2,+A3,+A4,+A5,+A6,+A7,+A8,+A9,+A10,+A11,@VCC,@GND")
+ NETLIB_DEVICE_IMPL(MCM14524, "ROM_MCM14524", "+EN,+CLK,+A0,+A1,+A2,+A3,+A4,+A5,+A6,+A7,@VCC,@GND")
} //namespace devices
} // namespace netlist
diff --git a/src/lib/netlist/devices/nld_system.cpp b/src/lib/netlist/devices/nld_system.cpp
index c3f4cd5d270..36ae9bc6e35 100644
--- a/src/lib/netlist/devices/nld_system.cpp
+++ b/src/lib/netlist/devices/nld_system.cpp
@@ -62,7 +62,7 @@ namespace devices
NETLIB_RESETI()
{
m_cnt = 0;
- m_off = netlist_time::from_fp<decltype(m_offset())>(m_offset());
+ m_off = netlist_time::from_fp<param_fp_t::value_type>(m_offset());
m_feedback.set_delegate(NETLIB_DELEGATE(first));
}
//NETLIB_UPDATE_PARAMI();
diff --git a/src/lib/netlist/devices/nlid_proxy.cpp b/src/lib/netlist/devices/nlid_proxy.cpp
index 51eb0fbf5cd..e8cc27fc987 100644
--- a/src/lib/netlist/devices/nlid_proxy.cpp
+++ b/src/lib/netlist/devices/nlid_proxy.cpp
@@ -21,7 +21,7 @@ namespace netlist
// nld_base_proxy
// -----------------------------------------------------------------------------
- static const std::array<std::pair<const char *, const char *>, 3> power_syms = {{ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}};
+ static constexpr std::array<std::pair<const char *, const char *>, 3> power_syms = {{ {"VCC", "VEE"}, {"VCC", "GND"}, {"VDD", "VSS"}}};
nld_base_proxy::nld_base_proxy(netlist_state_t &anetlist, const pstring &name,
const logic_t *inout_proxied)
@@ -124,19 +124,9 @@ namespace netlist
{
register_subalias("Q", "RN.1");
- log().verbose("D/A Proxy: Found power terminals on device {1}", out_proxied->device().name());
- if (anetlist.is_extended_validation())
- {
- // During validation, don't connect to terminals found
- // This will cause terminals not connected to a rail net to
- // fail connection stage.
- connect(m_RN.N(), m_RP.P());
- }
- else
- {
- connect(m_RN.N(), *m_tn);
- connect(m_RP.P(), *m_tp);
- }
+ connect(m_RN.N(), *m_tn);
+ connect(m_RP.P(), *m_tp);
+
connect(m_RN.P(), m_RP.N());
}
diff --git a/src/lib/netlist/devices/nlid_system.h b/src/lib/netlist/devices/nlid_system.h
index 0e2857a3508..c1c44e764e1 100644
--- a/src/lib/netlist/devices/nlid_system.h
+++ b/src/lib/netlist/devices/nlid_system.h
@@ -196,10 +196,10 @@ namespace devices
/// Consider the following mixing stage
///
/// R1
- /// S1 >-----1RRRR2---------+
+ /// I1 >-----1RRRR2---------+
/// |
/// R2 |
- /// S2 >-----1RRRR2---------+----------> Out
+ /// I2 >-----1RRRR2---------+----------> Out
/// |
/// R
/// R3 R
@@ -207,45 +207,37 @@ namespace devices
/// |
/// GND
///
- /// With OPTIMIZE_FRONTIER(R2.2, R3, R2) this becomes:
+ /// With OPTIMIZE_FRONTIER(R2.1, R2, RX) where RX is the impedance of the
+ /// output connected to I2 this becomes:
///
/// R1
- /// S1 >-----1RRRR2--------------------------------+
+ /// I1 >-----1RRRR2--------------------------------+
/// |
- /// ########################## |
- /// R2 # R2 # |
- /// S2 >-----1RRRR2-----+-->AnIn AnOut>--RRRR------+----------> Out
- /// # | # |
- /// # R # R
- /// # R R3 # R3 R
- /// # R # R
- /// # | # |
- /// # GND Frontier # GND
- /// # #
- /// ##########################
+ /// ########################## |
+ /// # RX # R2 |
+ /// I2 >----->--+-AnIn AnOut>--RRRR--->---1RRRR2---+----------> Out
+ /// # | # |
+ /// # R # R
+ /// # R R2 # R3 R
+ /// # R # R
+ /// # | # |
+ /// # GND Frontier # GND
+ /// # #
+ /// ##########################
///
/// As a result, provided there are no other connections between the parts
/// generating S1 and S2 the "S2 part" will now have a separate solver.
///
- /// The size (aka number of nets) of the solver for S1 will be smaller.
- /// The size of the solver for S2 and the rest of the circuit will be smaller
+ /// The size (aka number of nets) of the solver for I1 will be smaller.
+ /// The size of the solver for I2 and the rest of the circuit will be smaller
/// as well.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
NETLIB_OBJECT(frontier)
{
NETLIB_CONSTRUCTOR(frontier)
- , m_RIN(*this, "m_RIN", NETLIB_DELEGATE(input))
- , m_ROUT(*this, "m_ROUT", NETLIB_DELEGATE(input))
+ , m_RIN(*this, "m_RIN", NETLIB_DELEGATE(input)) // FIXME: does not look right
+ , m_ROUT(*this, "m_ROUT", NETLIB_DELEGATE(input)) // FIXME: does not look right
, m_I(*this, "_I", NETLIB_DELEGATE(input))
, m_Q(*this, "_Q")
, m_p_RIN(*this, "RIN", nlconst::magic(1.0e6))
@@ -264,6 +256,7 @@ namespace devices
private:
NETLIB_RESETI()
{
+ //printf("%s: in %f out %f\n", name().c_str(), m_p_RIN(), m_p_ROUT());
m_RIN.set_G_V_I(plib::reciprocal(m_p_RIN()),0,0);
m_ROUT.set_G_V_I(plib::reciprocal(m_p_ROUT()),0,0);
}
@@ -566,7 +559,7 @@ namespace devices
private:
NETLIB_HANDLERI(input)
{
- nl_fptype val = m_dis.var()(m_mt.var());
+ nl_fptype val = m_dis()(m_mt());
m_T.change_state([this, val]()
{
m_T.set_G_V_I(plib::reciprocal(m_RI()), val, nlconst::zero());
diff --git a/src/lib/netlist/devices/nlid_truthtable.cpp b/src/lib/netlist/devices/nlid_truthtable.cpp
index 8b5e3a937c2..db2471a704e 100644
--- a/src/lib/netlist/devices/nlid_truthtable.cpp
+++ b/src/lib/netlist/devices/nlid_truthtable.cpp
@@ -52,6 +52,8 @@ namespace devices
/* FIXME: the family should provide the names of the power-terminals! */
, m_power_pins(*this)
{
+ m_activate = activate_delegate(& NETLIB_NAME(truthtable_t) :: incdec_active, this);
+ set_hint_deactivate(true);
init(desc);
}
@@ -73,7 +75,7 @@ namespace devices
#endif
}
for (auto &q : m_Q)
- if (q.has_net() && q.net().has_connections())
+ if (q.has_net() && !exec().nlstate().core_terms(q.net()).empty())
active_outputs++;
set_active_outputs(active_outputs);
}
@@ -100,16 +102,18 @@ namespace devices
}
#endif
- void inc_active() noexcept override
+ void incdec_active(bool a) noexcept
{
- process<false>();
- }
-
- void dec_active() noexcept override
- {
- for (std::size_t i = 0; i< m_NI; i++)
- m_I[i].inactivate();
- m_ign = (1<<m_NI)-1;
+ if (a)
+ {
+ process<false>();
+ }
+ else
+ {
+ for (std::size_t i = 0; i< m_NI; i++)
+ m_I[i].inactivate();
+ m_ign = (1<<m_NI)-1;
+ }
}
template<bool doOUT>
@@ -371,8 +375,6 @@ namespace devices
template<std::size_t m_NI, std::size_t m_NO>
void NETLIB_NAME(truthtable_t)<m_NI, m_NO>::init(const std::vector<pstring> &desc)
{
- set_hint_deactivate(true);
-
pstring header = desc[0];
std::vector<pstring> io(plib::psplit(header,'|'));
diff --git a/src/lib/netlist/examples/2N6027.cpp b/src/lib/netlist/examples/2n6027.cpp
index bfad3c065ec..bfad3c065ec 100644
--- a/src/lib/netlist/examples/2N6027.cpp
+++ b/src/lib/netlist/examples/2n6027.cpp
diff --git a/src/lib/netlist/examples/LM3900_test.cpp b/src/lib/netlist/examples/lm3900_test.cpp
index a48a2cd8a78..a48a2cd8a78 100644
--- a/src/lib/netlist/examples/LM3900_test.cpp
+++ b/src/lib/netlist/examples/lm3900_test.cpp
diff --git a/src/lib/netlist/generated/lib_entries.hxx b/src/lib/netlist/generated/lib_entries.hxx
index da6ad55a0a3..debc626fd47 100755
--- a/src/lib/netlist/generated/lib_entries.hxx
+++ b/src/lib/netlist/generated/lib_entries.hxx
@@ -60,14 +60,18 @@ LIB_ENTRY(CD4017)
LIB_ENTRY(CD4020)
LIB_ENTRY(CD4022)
LIB_ENTRY(CD4024)
+LIB_ENTRY(CD4029)
+LIB_ENTRY(CD4042)
LIB_ENTRY(CD4053_GATE)
LIB_ENTRY(CD4066_GATE)
+LIB_ENTRY(CD4076)
LIB_ENTRY(CD4316_GATE)
LIB_ENTRY(CS)
LIB_ENTRY(D)
LIB_ENTRY(L)
LIB_ENTRY(LVCCS)
LIB_ENTRY(MC1455P)
+LIB_ENTRY(MCM14524)
LIB_ENTRY(MK28000)
LIB_ENTRY(MM5837)
LIB_ENTRY(MOSFET)
diff --git a/src/lib/netlist/generated/nld_devinc.h b/src/lib/netlist/generated/nld_devinc.h
index f5b14563db8..53a496be2d8 100755
--- a/src/lib/netlist/generated/nld_devinc.h
+++ b/src/lib/netlist/generated/nld_devinc.h
@@ -103,7 +103,7 @@
NET_REGISTER_DEVEXT(CS, __VA_ARGS__)
// ---------------------------------------------------------------------
-// Source: ../devices/nld_2102A.cpp
+// Source: ../devices/nld_2102a.cpp
// ---------------------------------------------------------------------
// usage : RAM_2102A(name, CEQ, A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, RWQ, DI)
@@ -154,6 +154,24 @@
NET_REGISTER_DEVEXT(CD4024, __VA_ARGS__)
// ---------------------------------------------------------------------
+// Source: ../devices/nld_4029.cpp
+// ---------------------------------------------------------------------
+
+// usage : CD4029(name, PE, J1, J2, J3, J4, CI, UD, BD, CLK)
+// auto connect: VCC, GND
+#define CD4029(...) \
+ NET_REGISTER_DEVEXT(CD4029, __VA_ARGS__)
+
+// ---------------------------------------------------------------------
+// Source: ../devices/nld_4042.cpp
+// ---------------------------------------------------------------------
+
+// usage : CD4042(name, D1, D2, D3, D4, POL, CLK)
+// auto connect: VCC, GND
+#define CD4042(...) \
+ NET_REGISTER_DEVEXT(CD4042, __VA_ARGS__)
+
+// ---------------------------------------------------------------------
// Source: ../devices/nld_4053.cpp
// ---------------------------------------------------------------------
@@ -170,6 +188,15 @@
NET_REGISTER_DEVEXT(CD4066_GATE, __VA_ARGS__)
// ---------------------------------------------------------------------
+// Source: ../devices/nld_4076.cpp
+// ---------------------------------------------------------------------
+
+// usage : CD4076(name, I1, I2, I3, I4, ID1, ID2, OD1, OD2)
+// auto connect: VCC, GND
+#define CD4076(...) \
+ NET_REGISTER_DEVEXT(CD4076, __VA_ARGS__)
+
+// ---------------------------------------------------------------------
// Source: ../devices/nld_4316.cpp
// ---------------------------------------------------------------------
@@ -493,7 +520,7 @@
NET_REGISTER_DEVEXT(TTL_8277, __VA_ARGS__)
// ---------------------------------------------------------------------
-// Source: ../devices/nld_82S115.cpp
+// Source: ../devices/nld_82s115.cpp
// ---------------------------------------------------------------------
// usage : PROM_82S115(name, CE1Q, CE2, A0, A1, A2, A3, A4, A5, A6, A7, A8, STROBE)
@@ -502,7 +529,7 @@
NET_REGISTER_DEVEXT(PROM_82S115, __VA_ARGS__)
// ---------------------------------------------------------------------
-// Source: ../devices/nld_82S16.cpp
+// Source: ../devices/nld_82s16.cpp
// ---------------------------------------------------------------------
// usage : TTL_82S16(name, )
@@ -652,6 +679,11 @@
#define PROM_MK28000(...) \
NET_REGISTER_DEVEXT(PROM_MK28000, __VA_ARGS__)
+// usage : ROM_MCM14524(name, EN, CLK, A0, A1, A2, A3, A4, A5, A6, A7)
+// auto connect: VCC, GND
+#define ROM_MCM14524(...) \
+ NET_REGISTER_DEVEXT(ROM_MCM14524, __VA_ARGS__)
+
// ---------------------------------------------------------------------
// Source: ../devices/nld_schmitt.cpp
// ---------------------------------------------------------------------
@@ -769,6 +801,14 @@
#define CD4011_GATE(...) \
NET_REGISTER_DEVEXT(CD4011_GATE, __VA_ARGS__)
+// usage : CD4030_GATE(name, )
+#define CD4030_GATE(...) \
+ NET_REGISTER_DEVEXT(CD4030_GATE, __VA_ARGS__)
+
+// usage : CD4049_GATE(name, )
+#define CD4049_GATE(...) \
+ NET_REGISTER_DEVEXT(CD4049_GATE, __VA_ARGS__)
+
// usage : CD4069_GATE(name, )
#define CD4069_GATE(...) \
NET_REGISTER_DEVEXT(CD4069_GATE, __VA_ARGS__)
@@ -777,6 +817,14 @@
#define CD4070_GATE(...) \
NET_REGISTER_DEVEXT(CD4070_GATE, __VA_ARGS__)
+// usage : CD4071_GATE(name, )
+#define CD4071_GATE(...) \
+ NET_REGISTER_DEVEXT(CD4071_GATE, __VA_ARGS__)
+
+// usage : CD4081_GATE(name, )
+#define CD4081_GATE(...) \
+ NET_REGISTER_DEVEXT(CD4081_GATE, __VA_ARGS__)
+
// usage : CD4001_DIP(name, )
#define CD4001_DIP(...) \
NET_REGISTER_DEVEXT(CD4001_DIP, __VA_ARGS__)
@@ -785,6 +833,14 @@
#define CD4011_DIP(...) \
NET_REGISTER_DEVEXT(CD4011_DIP, __VA_ARGS__)
+// usage : CD4030_DIP(name, )
+#define CD4030_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4030_DIP, __VA_ARGS__)
+
+// usage : CD4049_DIP(name, )
+#define CD4049_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4049_DIP, __VA_ARGS__)
+
// usage : CD4069_DIP(name, )
#define CD4069_DIP(...) \
NET_REGISTER_DEVEXT(CD4069_DIP, __VA_ARGS__)
@@ -793,6 +849,14 @@
#define CD4070_DIP(...) \
NET_REGISTER_DEVEXT(CD4070_DIP, __VA_ARGS__)
+// usage : CD4071_DIP(name, )
+#define CD4071_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4071_DIP, __VA_ARGS__)
+
+// usage : CD4081_DIP(name, )
+#define CD4081_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4081_DIP, __VA_ARGS__)
+
// usage : CD4006_DIP(name, )
#define CD4006_DIP(...) \
NET_REGISTER_DEVEXT(CD4006_DIP, __VA_ARGS__)
@@ -817,6 +881,14 @@
#define CD4024_DIP(...) \
NET_REGISTER_DEVEXT(CD4024_DIP, __VA_ARGS__)
+// usage : CD4029_DIP(name, )
+#define CD4029_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4029_DIP, __VA_ARGS__)
+
+// usage : CD4042_DIP(name, )
+#define CD4042_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4042_DIP, __VA_ARGS__)
+
// usage : CD4053_DIP(name, )
#define CD4053_DIP(...) \
NET_REGISTER_DEVEXT(CD4053_DIP, __VA_ARGS__)
@@ -829,6 +901,10 @@
#define CD4016_DIP(...) \
NET_REGISTER_DEVEXT(CD4016_DIP, __VA_ARGS__)
+// usage : CD4076_DIP(name, )
+#define CD4076_DIP(...) \
+ NET_REGISTER_DEVEXT(CD4076_DIP, __VA_ARGS__)
+
// usage : CD4316_DIP(name, )
#define CD4316_DIP(...) \
NET_REGISTER_DEVEXT(CD4316_DIP, __VA_ARGS__)
@@ -893,6 +969,10 @@
#define LM324_DIP(...) \
NET_REGISTER_DEVEXT(LM324_DIP, __VA_ARGS__)
+// usage : LM348_DIP(name, )
+#define LM348_DIP(...) \
+ NET_REGISTER_DEVEXT(LM348_DIP, __VA_ARGS__)
+
// usage : LM358_DIP(name, )
#define LM358_DIP(...) \
NET_REGISTER_DEVEXT(LM358_DIP, __VA_ARGS__)
@@ -989,6 +1069,10 @@
#define PROM_MK28000_DIP(...) \
NET_REGISTER_DEVEXT(PROM_MK28000_DIP, __VA_ARGS__)
+// usage : ROM_MCM14524_DIP(name, )
+#define ROM_MCM14524_DIP(...) \
+ NET_REGISTER_DEVEXT(ROM_MCM14524_DIP, __VA_ARGS__)
+
// usage : RAM_2102A_DIP(name, )
#define RAM_2102A_DIP(...) \
NET_REGISTER_DEVEXT(RAM_2102A_DIP, __VA_ARGS__)
diff --git a/src/lib/netlist/generated/nlm_modules_lib.cpp b/src/lib/netlist/generated/nlm_modules_lib.cpp
index 7f91075ac40..7162c84023d 100755
--- a/src/lib/netlist/generated/nlm_modules_lib.cpp
+++ b/src/lib/netlist/generated/nlm_modules_lib.cpp
@@ -1,7 +1,7 @@
// license:CC0
// copyright-holders:Couriersud
-// File programmatically created Sun Sep 13 20:49:39 2020
+// File programmatically created Wed Sep 30 11:02:38 2020
#include "devices/net_lib.h"
diff --git a/src/lib/netlist/generated/static_solvers.cpp b/src/lib/netlist/generated/static_solvers.cpp
index 367af35bbb9..ce58a075fa7 100644
--- a/src/lib/netlist/generated/static_solvers.cpp
+++ b/src/lib/netlist/generated/static_solvers.cpp
@@ -393,6 +393,1021 @@ static void nl_gcr_1250f340dea396ae_22_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// astrob
+static void nl_gcr_13833bf8c127deaa_154_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ double m_A89(0.0);
+ double m_A90(0.0);
+ double m_A91(0.0);
+ double m_A92(0.0);
+ double m_A93(0.0);
+ double m_A94(0.0);
+ double m_A95(0.0);
+ double m_A96(0.0);
+ double m_A97(0.0);
+ double m_A98(0.0);
+ double m_A99(0.0);
+ double m_A100(0.0);
+ double m_A101(0.0);
+ double m_A102(0.0);
+ double m_A103(0.0);
+ double m_A104(0.0);
+ double m_A105(0.0);
+ double m_A106(0.0);
+ double m_A107(0.0);
+ double m_A108(0.0);
+ double m_A109(0.0);
+ double m_A110(0.0);
+ double m_A111(0.0);
+ double m_A112(0.0);
+ double m_A113(0.0);
+ double m_A114(0.0);
+ double m_A115(0.0);
+ double m_A116(0.0);
+ double m_A117(0.0);
+ double m_A118(0.0);
+ double m_A119(0.0);
+ double m_A120(0.0);
+ double m_A121(0.0);
+ double m_A122(0.0);
+ double m_A123(0.0);
+ double m_A124(0.0);
+ double m_A125(0.0);
+ double m_A126(0.0);
+ double m_A127(0.0);
+ double m_A128(0.0);
+ double m_A129(0.0);
+ double m_A130(0.0);
+ double m_A131(0.0);
+ double m_A132(0.0);
+ double m_A133(0.0);
+ double m_A134(0.0);
+ double m_A135(0.0);
+ double m_A136(0.0);
+ double m_A137(0.0);
+ double m_A138(0.0);
+ double m_A139(0.0);
+ double m_A140(0.0);
+ double m_A141(0.0);
+ double m_A142(0.0);
+ double m_A143(0.0);
+ double m_A144(0.0);
+ double m_A145(0.0);
+ double m_A146(0.0);
+ double m_A147(0.0);
+ double m_A148(0.0);
+ double m_A149(0.0);
+ double m_A150(0.0);
+ double m_A151(0.0);
+ double m_A152(0.0);
+ double m_A153(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A3 += go[2];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ RHS1 -= go[3] * *cnV[3];
+ m_A4 += gt[4];
+ m_A4 += gt[5];
+ m_A5 += go[4];
+ double RHS2 = Idr[4];
+ RHS2 += Idr[5];
+ RHS2 -= go[5] * *cnV[5];
+ m_A6 += gt[6];
+ m_A6 += gt[7];
+ m_A7 += go[6];
+ double RHS3 = Idr[6];
+ RHS3 += Idr[7];
+ RHS3 -= go[7] * *cnV[7];
+ m_A8 += gt[8];
+ m_A8 += gt[9];
+ m_A9 += go[8];
+ m_A10 += go[9];
+ double RHS4 = Idr[8];
+ RHS4 += Idr[9];
+ m_A11 += gt[10];
+ m_A11 += gt[11];
+ m_A11 += gt[12];
+ m_A12 += go[10];
+ double RHS5 = Idr[10];
+ RHS5 += Idr[11];
+ RHS5 += Idr[12];
+ RHS5 -= go[11] * *cnV[11];
+ RHS5 -= go[12] * *cnV[12];
+ m_A13 += gt[13];
+ m_A13 += gt[14];
+ m_A13 += gt[15];
+ m_A13 += gt[16];
+ m_A14 += go[13];
+ m_A14 += go[14];
+ m_A15 += go[15];
+ double RHS6 = Idr[13];
+ RHS6 += Idr[14];
+ RHS6 += Idr[15];
+ RHS6 += Idr[16];
+ RHS6 -= go[16] * *cnV[16];
+ m_A16 += gt[17];
+ m_A16 += gt[18];
+ m_A16 += gt[19];
+ m_A16 += gt[20];
+ m_A16 += gt[21];
+ m_A16 += gt[22];
+ m_A18 += go[17];
+ m_A17 += go[18];
+ double RHS7 = Idr[17];
+ RHS7 += Idr[18];
+ RHS7 += Idr[19];
+ RHS7 += Idr[20];
+ RHS7 += Idr[21];
+ RHS7 += Idr[22];
+ RHS7 -= go[19] * *cnV[19];
+ RHS7 -= go[20] * *cnV[20];
+ RHS7 -= go[21] * *cnV[21];
+ RHS7 -= go[22] * *cnV[22];
+ m_A19 += gt[23];
+ m_A19 += gt[24];
+ m_A19 += gt[25];
+ m_A20 += go[23];
+ double RHS8 = Idr[23];
+ RHS8 += Idr[24];
+ RHS8 += Idr[25];
+ RHS8 -= go[24] * *cnV[24];
+ RHS8 -= go[25] * *cnV[25];
+ m_A21 += gt[26];
+ m_A21 += gt[27];
+ m_A21 += gt[28];
+ m_A22 += go[26];
+ double RHS9 = Idr[26];
+ RHS9 += Idr[27];
+ RHS9 += Idr[28];
+ RHS9 -= go[27] * *cnV[27];
+ RHS9 -= go[28] * *cnV[28];
+ m_A23 += gt[29];
+ m_A23 += gt[30];
+ m_A23 += gt[31];
+ m_A24 += go[29];
+ double RHS10 = Idr[29];
+ RHS10 += Idr[30];
+ RHS10 += Idr[31];
+ RHS10 -= go[30] * *cnV[30];
+ RHS10 -= go[31] * *cnV[31];
+ m_A25 += gt[32];
+ m_A25 += gt[33];
+ m_A25 += gt[34];
+ m_A26 += go[32];
+ double RHS11 = Idr[32];
+ RHS11 += Idr[33];
+ RHS11 += Idr[34];
+ RHS11 -= go[33] * *cnV[33];
+ RHS11 -= go[34] * *cnV[34];
+ m_A27 += gt[35];
+ m_A27 += gt[36];
+ m_A27 += gt[37];
+ m_A28 += go[35];
+ double RHS12 = Idr[35];
+ RHS12 += Idr[36];
+ RHS12 += Idr[37];
+ RHS12 -= go[36] * *cnV[36];
+ RHS12 -= go[37] * *cnV[37];
+ m_A29 += gt[38];
+ m_A29 += gt[39];
+ m_A30 += go[38];
+ double RHS13 = Idr[38];
+ RHS13 += Idr[39];
+ RHS13 -= go[39] * *cnV[39];
+ m_A31 += gt[40];
+ m_A31 += gt[41];
+ m_A31 += gt[42];
+ m_A32 += go[40];
+ double RHS14 = Idr[40];
+ RHS14 += Idr[41];
+ RHS14 += Idr[42];
+ RHS14 -= go[41] * *cnV[41];
+ RHS14 -= go[42] * *cnV[42];
+ m_A33 += gt[43];
+ m_A33 += gt[44];
+ m_A34 += go[43];
+ double RHS15 = Idr[43];
+ RHS15 += Idr[44];
+ RHS15 -= go[44] * *cnV[44];
+ m_A35 += gt[45];
+ m_A35 += gt[46];
+ m_A36 += go[45];
+ double RHS16 = Idr[45];
+ RHS16 += Idr[46];
+ RHS16 -= go[46] * *cnV[46];
+ m_A37 += gt[47];
+ m_A37 += gt[48];
+ m_A38 += go[47];
+ double RHS17 = Idr[47];
+ RHS17 += Idr[48];
+ RHS17 -= go[48] * *cnV[48];
+ m_A39 += gt[49];
+ m_A39 += gt[50];
+ m_A40 += go[49];
+ double RHS18 = Idr[49];
+ RHS18 += Idr[50];
+ RHS18 -= go[50] * *cnV[50];
+ m_A41 += gt[51];
+ m_A41 += gt[52];
+ m_A42 += go[51];
+ double RHS19 = Idr[51];
+ RHS19 += Idr[52];
+ RHS19 -= go[52] * *cnV[52];
+ m_A43 += gt[53];
+ m_A43 += gt[54];
+ m_A44 += go[53];
+ double RHS20 = Idr[53];
+ RHS20 += Idr[54];
+ RHS20 -= go[54] * *cnV[54];
+ m_A45 += gt[55];
+ m_A45 += gt[56];
+ m_A45 += gt[57];
+ m_A45 += gt[58];
+ m_A45 += gt[59];
+ m_A46 += go[55];
+ m_A48 += go[56];
+ m_A47 += go[57];
+ double RHS21 = Idr[55];
+ RHS21 += Idr[56];
+ RHS21 += Idr[57];
+ RHS21 += Idr[58];
+ RHS21 += Idr[59];
+ RHS21 -= go[58] * *cnV[58];
+ RHS21 -= go[59] * *cnV[59];
+ m_A49 += gt[60];
+ m_A49 += gt[61];
+ m_A49 += gt[62];
+ m_A50 += go[60];
+ double RHS22 = Idr[60];
+ RHS22 += Idr[61];
+ RHS22 += Idr[62];
+ RHS22 -= go[61] * *cnV[61];
+ RHS22 -= go[62] * *cnV[62];
+ m_A51 += gt[63];
+ m_A51 += gt[64];
+ m_A52 += go[63];
+ double RHS23 = Idr[63];
+ RHS23 += Idr[64];
+ RHS23 -= go[64] * *cnV[64];
+ m_A55 += gt[65];
+ m_A55 += gt[66];
+ m_A55 += gt[67];
+ m_A55 += gt[68];
+ m_A54 += go[65];
+ m_A53 += go[66];
+ double RHS24 = Idr[65];
+ RHS24 += Idr[66];
+ RHS24 += Idr[67];
+ RHS24 += Idr[68];
+ RHS24 -= go[67] * *cnV[67];
+ RHS24 -= go[68] * *cnV[68];
+ m_A57 += gt[69];
+ m_A57 += gt[70];
+ m_A58 += go[69];
+ double RHS25 = Idr[69];
+ RHS25 += Idr[70];
+ RHS25 -= go[70] * *cnV[70];
+ m_A59 += gt[71];
+ m_A59 += gt[72];
+ m_A59 += gt[73];
+ m_A60 += go[71];
+ double RHS26 = Idr[71];
+ RHS26 += Idr[72];
+ RHS26 += Idr[73];
+ RHS26 -= go[72] * *cnV[72];
+ RHS26 -= go[73] * *cnV[73];
+ m_A61 += gt[74];
+ m_A61 += gt[75];
+ m_A61 += gt[76];
+ m_A62 += go[74];
+ double RHS27 = Idr[74];
+ RHS27 += Idr[75];
+ RHS27 += Idr[76];
+ RHS27 -= go[75] * *cnV[75];
+ RHS27 -= go[76] * *cnV[76];
+ m_A63 += gt[77];
+ m_A63 += gt[78];
+ m_A63 += gt[79];
+ m_A64 += go[77];
+ double RHS28 = Idr[77];
+ RHS28 += Idr[78];
+ RHS28 += Idr[79];
+ RHS28 -= go[78] * *cnV[78];
+ RHS28 -= go[79] * *cnV[79];
+ m_A65 += gt[80];
+ m_A65 += gt[81];
+ m_A67 += go[80];
+ m_A66 += go[81];
+ double RHS29 = Idr[80];
+ RHS29 += Idr[81];
+ m_A68 += gt[82];
+ m_A68 += gt[83];
+ m_A70 += go[82];
+ m_A69 += go[83];
+ double RHS30 = Idr[82];
+ RHS30 += Idr[83];
+ m_A71 += gt[84];
+ m_A71 += gt[85];
+ m_A73 += go[84];
+ m_A72 += go[85];
+ double RHS31 = Idr[84];
+ RHS31 += Idr[85];
+ m_A77 += gt[86];
+ m_A77 += gt[87];
+ m_A77 += gt[88];
+ m_A77 += gt[89];
+ m_A77 += gt[90];
+ m_A77 += gt[91];
+ m_A77 += gt[92];
+ m_A74 += go[86];
+ m_A75 += go[87];
+ m_A75 += go[88];
+ m_A78 += go[89];
+ m_A78 += go[90];
+ double RHS32 = Idr[86];
+ RHS32 += Idr[87];
+ RHS32 += Idr[88];
+ RHS32 += Idr[89];
+ RHS32 += Idr[90];
+ RHS32 += Idr[91];
+ RHS32 += Idr[92];
+ RHS32 -= go[91] * *cnV[91];
+ RHS32 -= go[92] * *cnV[92];
+ m_A83 += gt[93];
+ m_A83 += gt[94];
+ m_A83 += gt[95];
+ m_A83 += gt[96];
+ m_A83 += gt[97];
+ m_A83 += gt[98];
+ m_A83 += gt[99];
+ m_A83 += gt[100];
+ m_A83 += gt[101];
+ m_A85 += go[93];
+ m_A85 += go[94];
+ m_A84 += go[95];
+ m_A84 += go[96];
+ m_A82 += go[97];
+ m_A81 += go[98];
+ m_A80 += go[99];
+ m_A79 += go[100];
+ double RHS33 = Idr[93];
+ RHS33 += Idr[94];
+ RHS33 += Idr[95];
+ RHS33 += Idr[96];
+ RHS33 += Idr[97];
+ RHS33 += Idr[98];
+ RHS33 += Idr[99];
+ RHS33 += Idr[100];
+ RHS33 += Idr[101];
+ RHS33 -= go[101] * *cnV[101];
+ m_A92 += gt[102];
+ m_A92 += gt[103];
+ m_A92 += gt[104];
+ m_A92 += gt[105];
+ m_A92 += gt[106];
+ m_A92 += gt[107];
+ m_A91 += go[102];
+ m_A90 += go[103];
+ m_A89 += go[104];
+ m_A88 += go[105];
+ m_A87 += go[106];
+ m_A86 += go[107];
+ double RHS34 = Idr[102];
+ RHS34 += Idr[103];
+ RHS34 += Idr[104];
+ RHS34 += Idr[105];
+ RHS34 += Idr[106];
+ RHS34 += Idr[107];
+ m_A95 += gt[108];
+ m_A95 += gt[109];
+ m_A95 += gt[110];
+ m_A95 += gt[111];
+ m_A95 += gt[112];
+ m_A95 += gt[113];
+ m_A95 += gt[114];
+ m_A97 += go[108];
+ m_A94 += go[109];
+ double RHS35 = Idr[108];
+ RHS35 += Idr[109];
+ RHS35 += Idr[110];
+ RHS35 += Idr[111];
+ RHS35 += Idr[112];
+ RHS35 += Idr[113];
+ RHS35 += Idr[114];
+ RHS35 -= go[110] * *cnV[110];
+ RHS35 -= go[111] * *cnV[111];
+ RHS35 -= go[112] * *cnV[112];
+ RHS35 -= go[113] * *cnV[113];
+ RHS35 -= go[114] * *cnV[114];
+ m_A99 += gt[115];
+ m_A99 += gt[116];
+ m_A98 += go[115];
+ m_A100 += go[116];
+ double RHS36 = Idr[115];
+ RHS36 += Idr[116];
+ m_A107 += gt[117];
+ m_A107 += gt[118];
+ m_A107 += gt[119];
+ m_A107 += gt[120];
+ m_A107 += gt[121];
+ m_A107 += gt[122];
+ m_A106 += go[117];
+ m_A105 += go[118];
+ m_A104 += go[119];
+ m_A103 += go[120];
+ m_A102 += go[121];
+ m_A101 += go[122];
+ double RHS37 = Idr[117];
+ RHS37 += Idr[118];
+ RHS37 += Idr[119];
+ RHS37 += Idr[120];
+ RHS37 += Idr[121];
+ RHS37 += Idr[122];
+ m_A112 += gt[123];
+ m_A112 += gt[124];
+ m_A112 += gt[125];
+ m_A112 += gt[126];
+ m_A112 += gt[127];
+ m_A111 += go[123];
+ m_A110 += go[124];
+ m_A109 += go[125];
+ double RHS38 = Idr[123];
+ RHS38 += Idr[124];
+ RHS38 += Idr[125];
+ RHS38 += Idr[126];
+ RHS38 += Idr[127];
+ RHS38 -= go[126] * *cnV[126];
+ RHS38 -= go[127] * *cnV[127];
+ m_A118 += gt[128];
+ m_A118 += gt[129];
+ m_A118 += gt[130];
+ m_A118 += gt[131];
+ m_A118 += gt[132];
+ m_A118 += gt[133];
+ m_A118 += gt[134];
+ m_A118 += gt[135];
+ m_A118 += gt[136];
+ m_A119 += go[128];
+ m_A115 += go[129];
+ m_A114 += go[130];
+ m_A116 += go[131];
+ m_A116 += go[132];
+ m_A117 += go[133];
+ m_A117 += go[134];
+ double RHS39 = Idr[128];
+ RHS39 += Idr[129];
+ RHS39 += Idr[130];
+ RHS39 += Idr[131];
+ RHS39 += Idr[132];
+ RHS39 += Idr[133];
+ RHS39 += Idr[134];
+ RHS39 += Idr[135];
+ RHS39 += Idr[136];
+ RHS39 -= go[135] * *cnV[135];
+ RHS39 -= go[136] * *cnV[136];
+ m_A121 += gt[137];
+ m_A121 += gt[138];
+ m_A120 += go[137];
+ m_A122 += go[138];
+ double RHS40 = Idr[137];
+ RHS40 += Idr[138];
+ m_A127 += gt[139];
+ m_A127 += gt[140];
+ m_A127 += gt[141];
+ m_A127 += gt[142];
+ m_A127 += gt[143];
+ m_A126 += go[139];
+ m_A125 += go[140];
+ m_A124 += go[141];
+ m_A123 += go[142];
+ m_A128 += go[143];
+ double RHS41 = Idr[139];
+ RHS41 += Idr[140];
+ RHS41 += Idr[141];
+ RHS41 += Idr[142];
+ RHS41 += Idr[143];
+ m_A134 += gt[144];
+ m_A134 += gt[145];
+ m_A134 += gt[146];
+ m_A134 += gt[147];
+ m_A134 += gt[148];
+ m_A134 += gt[149];
+ m_A130 += go[144];
+ m_A129 += go[145];
+ m_A133 += go[146];
+ m_A131 += go[147];
+ m_A131 += go[148];
+ double RHS42 = Idr[144];
+ RHS42 += Idr[145];
+ RHS42 += Idr[146];
+ RHS42 += Idr[147];
+ RHS42 += Idr[148];
+ RHS42 += Idr[149];
+ RHS42 -= go[149] * *cnV[149];
+ m_A137 += gt[150];
+ m_A137 += gt[151];
+ m_A136 += go[150];
+ m_A138 += go[151];
+ double RHS43 = Idr[150];
+ RHS43 += Idr[151];
+ m_A153 += gt[152];
+ m_A153 += gt[153];
+ m_A153 += gt[154];
+ m_A153 += gt[155];
+ m_A153 += gt[156];
+ m_A153 += gt[157];
+ m_A153 += gt[158];
+ m_A153 += gt[159];
+ m_A152 += go[152];
+ m_A140 += go[153];
+ m_A141 += go[154];
+ m_A142 += go[155];
+ m_A149 += go[156];
+ m_A145 += go[157];
+ m_A150 += go[158];
+ m_A139 += go[159];
+ double RHS44 = Idr[152];
+ RHS44 += Idr[153];
+ RHS44 += Idr[154];
+ RHS44 += Idr[155];
+ RHS44 += Idr[156];
+ RHS44 += Idr[157];
+ RHS44 += Idr[158];
+ RHS44 += Idr[159];
+ const double f0 = 1.0 / m_A0;
+ const double f0_33 = -f0 * m_A79;
+ m_A83 += m_A1 * f0_33;
+ RHS33 += f0_33 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_33 = -f1 * m_A80;
+ m_A83 += m_A3 * f1_33;
+ RHS33 += f1_33 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_33 = -f2 * m_A81;
+ m_A83 += m_A5 * f2_33;
+ RHS33 += f2_33 * RHS2;
+ const double f3 = 1.0 / m_A6;
+ const double f3_33 = -f3 * m_A82;
+ m_A83 += m_A7 * f3_33;
+ RHS33 += f3_33 * RHS3;
+ const double f4 = 1.0 / m_A8;
+ const double f4_24 = -f4 * m_A53;
+ m_A55 += m_A9 * f4_24;
+ m_A56 += m_A10 * f4_24;
+ RHS24 += f4_24 * RHS4;
+ const double f4_32 = -f4 * m_A74;
+ m_A76 += m_A9 * f4_32;
+ m_A77 += m_A10 * f4_32;
+ RHS32 += f4_32 * RHS4;
+ const double f5 = 1.0 / m_A11;
+ const double f5_24 = -f5 * m_A54;
+ m_A55 += m_A12 * f5_24;
+ RHS24 += f5_24 * RHS5;
+ const double f6 = 1.0 / m_A13;
+ const double f6_32 = -f6 * m_A75;
+ m_A77 += m_A14 * f6_32;
+ m_A78 += m_A15 * f6_32;
+ RHS32 += f6_32 * RHS6;
+ const double f6_39 = -f6 * m_A114;
+ m_A116 += m_A14 * f6_39;
+ m_A118 += m_A15 * f6_39;
+ RHS39 += f6_39 * RHS6;
+ const double f7 = 1.0 / m_A16;
+ const double f7_35 = -f7 * m_A94;
+ m_A96 += m_A17 * f7_35;
+ m_A97 += m_A18 * f7_35;
+ RHS35 += f7_35 * RHS7;
+ const double f7_39 = -f7 * m_A115;
+ m_A118 += m_A17 * f7_39;
+ m_A119 += m_A18 * f7_39;
+ RHS39 += f7_39 * RHS7;
+ const double f7_42 = -f7 * m_A129;
+ m_A133 += m_A17 * f7_42;
+ m_A134 += m_A18 * f7_42;
+ RHS42 += f7_42 * RHS7;
+ const double f8 = 1.0 / m_A19;
+ const double f8_37 = -f8 * m_A101;
+ m_A107 += m_A20 * f8_37;
+ RHS37 += f8_37 * RHS8;
+ const double f9 = 1.0 / m_A21;
+ const double f9_37 = -f9 * m_A102;
+ m_A107 += m_A22 * f9_37;
+ RHS37 += f9_37 * RHS9;
+ const double f10 = 1.0 / m_A23;
+ const double f10_37 = -f10 * m_A103;
+ m_A107 += m_A24 * f10_37;
+ RHS37 += f10_37 * RHS10;
+ const double f11 = 1.0 / m_A25;
+ const double f11_37 = -f11 * m_A104;
+ m_A107 += m_A26 * f11_37;
+ RHS37 += f11_37 * RHS11;
+ const double f12 = 1.0 / m_A27;
+ const double f12_37 = -f12 * m_A105;
+ m_A107 += m_A28 * f12_37;
+ RHS37 += f12_37 * RHS12;
+ const double f13 = 1.0 / m_A29;
+ const double f13_38 = -f13 * m_A109;
+ m_A112 += m_A30 * f13_38;
+ RHS38 += f13_38 * RHS13;
+ const double f14 = 1.0 / m_A31;
+ const double f14_34 = -f14 * m_A86;
+ m_A92 += m_A32 * f14_34;
+ RHS34 += f14_34 * RHS14;
+ const double f15 = 1.0 / m_A33;
+ const double f15_41 = -f15 * m_A123;
+ m_A127 += m_A34 * f15_41;
+ RHS41 += f15_41 * RHS15;
+ const double f16 = 1.0 / m_A35;
+ const double f16_36 = -f16 * m_A98;
+ m_A99 += m_A36 * f16_36;
+ RHS36 += f16_36 * RHS16;
+ const double f17 = 1.0 / m_A37;
+ const double f17_40 = -f17 * m_A120;
+ m_A121 += m_A38 * f17_40;
+ RHS40 += f17_40 * RHS17;
+ const double f18 = 1.0 / m_A39;
+ const double f18_41 = -f18 * m_A124;
+ m_A127 += m_A40 * f18_41;
+ RHS41 += f18_41 * RHS18;
+ const double f19 = 1.0 / m_A41;
+ const double f19_41 = -f19 * m_A125;
+ m_A127 += m_A42 * f19_41;
+ RHS41 += f19_41 * RHS19;
+ const double f20 = 1.0 / m_A43;
+ const double f20_41 = -f20 * m_A126;
+ m_A127 += m_A44 * f20_41;
+ RHS41 += f20_41 * RHS20;
+ const double f21 = 1.0 / m_A45;
+ const double f21_42 = -f21 * m_A130;
+ m_A132 += m_A46 * f21_42;
+ m_A134 += m_A47 * f21_42;
+ m_A135 += m_A48 * f21_42;
+ RHS42 += f21_42 * RHS21;
+ const double f21_44 = -f21 * m_A139;
+ m_A144 += m_A46 * f21_44;
+ m_A151 += m_A47 * f21_44;
+ m_A153 += m_A48 * f21_44;
+ RHS44 += f21_44 * RHS21;
+ const double f22 = 1.0 / m_A49;
+ const double f22_34 = -f22 * m_A87;
+ m_A92 += m_A50 * f22_34;
+ RHS34 += f22_34 * RHS22;
+ const double f23 = 1.0 / m_A51;
+ const double f23_43 = -f23 * m_A136;
+ m_A137 += m_A52 * f23_43;
+ RHS43 += f23_43 * RHS23;
+ const double f24 = 1.0 / m_A55;
+ const double f24_32 = -f24 * m_A76;
+ m_A77 += m_A56 * f24_32;
+ RHS32 += f24_32 * RHS24;
+ const double f25 = 1.0 / m_A57;
+ const double f25_38 = -f25 * m_A110;
+ m_A112 += m_A58 * f25_38;
+ RHS38 += f25_38 * RHS25;
+ const double f26 = 1.0 / m_A59;
+ const double f26_34 = -f26 * m_A88;
+ m_A92 += m_A60 * f26_34;
+ RHS34 += f26_34 * RHS26;
+ const double f27 = 1.0 / m_A61;
+ const double f27_34 = -f27 * m_A89;
+ m_A92 += m_A62 * f27_34;
+ RHS34 += f27_34 * RHS27;
+ const double f28 = 1.0 / m_A63;
+ const double f28_34 = -f28 * m_A90;
+ m_A92 += m_A64 * f28_34;
+ RHS34 += f28_34 * RHS28;
+ const double f29 = 1.0 / m_A65;
+ const double f29_34 = -f29 * m_A91;
+ m_A92 += m_A66 * f29_34;
+ m_A93 += m_A67 * f29_34;
+ RHS34 += f29_34 * RHS29;
+ const double f29_44 = -f29 * m_A140;
+ m_A143 += m_A66 * f29_44;
+ m_A153 += m_A67 * f29_44;
+ RHS44 += f29_44 * RHS29;
+ const double f30 = 1.0 / m_A68;
+ const double f30_37 = -f30 * m_A106;
+ m_A107 += m_A69 * f30_37;
+ m_A108 += m_A70 * f30_37;
+ RHS37 += f30_37 * RHS30;
+ const double f30_44 = -f30 * m_A141;
+ m_A146 += m_A69 * f30_44;
+ m_A153 += m_A70 * f30_44;
+ RHS44 += f30_44 * RHS30;
+ const double f31 = 1.0 / m_A71;
+ const double f31_38 = -f31 * m_A111;
+ m_A112 += m_A72 * f31_38;
+ m_A113 += m_A73 * f31_38;
+ RHS38 += f31_38 * RHS31;
+ const double f31_44 = -f31 * m_A142;
+ m_A147 += m_A72 * f31_44;
+ m_A153 += m_A73 * f31_44;
+ RHS44 += f31_44 * RHS31;
+ const double f32 = 1.0 / m_A77;
+ const double f32_39 = -f32 * m_A116;
+ m_A118 += m_A78 * f32_39;
+ RHS39 += f32_39 * RHS32;
+ const double f33 = 1.0 / m_A83;
+ const double f33_39 = -f33 * m_A117;
+ m_A118 += m_A84 * f33_39;
+ m_A119 += m_A85 * f33_39;
+ RHS39 += f33_39 * RHS33;
+ const double f33_42 = -f33 * m_A131;
+ m_A133 += m_A84 * f33_42;
+ m_A134 += m_A85 * f33_42;
+ RHS42 += f33_42 * RHS33;
+ const double f34 = 1.0 / m_A92;
+ const double f34_44 = -f34 * m_A143;
+ m_A153 += m_A93 * f34_44;
+ RHS44 += f34_44 * RHS34;
+ const double f35 = 1.0 / m_A95;
+ const double f35_42 = -f35 * m_A132;
+ m_A133 += m_A96 * f35_42;
+ m_A134 += m_A97 * f35_42;
+ RHS42 += f35_42 * RHS35;
+ const double f35_44 = -f35 * m_A144;
+ m_A148 += m_A96 * f35_44;
+ m_A151 += m_A97 * f35_44;
+ RHS44 += f35_44 * RHS35;
+ const double f36 = 1.0 / m_A99;
+ const double f36_44 = -f36 * m_A145;
+ m_A153 += m_A100 * f36_44;
+ RHS44 += f36_44 * RHS36;
+ const double f37 = 1.0 / m_A107;
+ const double f37_44 = -f37 * m_A146;
+ m_A153 += m_A108 * f37_44;
+ RHS44 += f37_44 * RHS37;
+ const double f38 = 1.0 / m_A112;
+ const double f38_44 = -f38 * m_A147;
+ m_A153 += m_A113 * f38_44;
+ RHS44 += f38_44 * RHS38;
+ const double f39 = 1.0 / m_A118;
+ const double f39_42 = -f39 * m_A133;
+ m_A134 += m_A119 * f39_42;
+ RHS42 += f39_42 * RHS39;
+ const double f39_44 = -f39 * m_A148;
+ m_A151 += m_A119 * f39_44;
+ RHS44 += f39_44 * RHS39;
+ const double f40 = 1.0 / m_A121;
+ const double f40_44 = -f40 * m_A149;
+ m_A153 += m_A122 * f40_44;
+ RHS44 += f40_44 * RHS40;
+ const double f41 = 1.0 / m_A127;
+ const double f41_44 = -f41 * m_A150;
+ m_A153 += m_A128 * f41_44;
+ RHS44 += f41_44 * RHS41;
+ const double f42 = 1.0 / m_A134;
+ const double f42_44 = -f42 * m_A151;
+ m_A153 += m_A135 * f42_44;
+ RHS44 += f42_44 * RHS42;
+ const double f43 = 1.0 / m_A137;
+ const double f43_44 = -f43 * m_A152;
+ m_A153 += m_A138 * f43_44;
+ RHS44 += f43_44 * RHS43;
+ V[44] = RHS44 / m_A153;
+ double tmp43 = 0.0;
+ tmp43 += m_A138 * V[44];
+ V[43] = (RHS43 - tmp43) / m_A137;
+ double tmp42 = 0.0;
+ tmp42 += m_A135 * V[44];
+ V[42] = (RHS42 - tmp42) / m_A134;
+ double tmp41 = 0.0;
+ tmp41 += m_A128 * V[44];
+ V[41] = (RHS41 - tmp41) / m_A127;
+ double tmp40 = 0.0;
+ tmp40 += m_A122 * V[44];
+ V[40] = (RHS40 - tmp40) / m_A121;
+ double tmp39 = 0.0;
+ tmp39 += m_A119 * V[42];
+ V[39] = (RHS39 - tmp39) / m_A118;
+ double tmp38 = 0.0;
+ tmp38 += m_A113 * V[44];
+ V[38] = (RHS38 - tmp38) / m_A112;
+ double tmp37 = 0.0;
+ tmp37 += m_A108 * V[44];
+ V[37] = (RHS37 - tmp37) / m_A107;
+ double tmp36 = 0.0;
+ tmp36 += m_A100 * V[44];
+ V[36] = (RHS36 - tmp36) / m_A99;
+ double tmp35 = 0.0;
+ tmp35 += m_A96 * V[39];
+ tmp35 += m_A97 * V[42];
+ V[35] = (RHS35 - tmp35) / m_A95;
+ double tmp34 = 0.0;
+ tmp34 += m_A93 * V[44];
+ V[34] = (RHS34 - tmp34) / m_A92;
+ double tmp33 = 0.0;
+ tmp33 += m_A84 * V[39];
+ tmp33 += m_A85 * V[42];
+ V[33] = (RHS33 - tmp33) / m_A83;
+ double tmp32 = 0.0;
+ tmp32 += m_A78 * V[39];
+ V[32] = (RHS32 - tmp32) / m_A77;
+ double tmp31 = 0.0;
+ tmp31 += m_A72 * V[38];
+ tmp31 += m_A73 * V[44];
+ V[31] = (RHS31 - tmp31) / m_A71;
+ double tmp30 = 0.0;
+ tmp30 += m_A69 * V[37];
+ tmp30 += m_A70 * V[44];
+ V[30] = (RHS30 - tmp30) / m_A68;
+ double tmp29 = 0.0;
+ tmp29 += m_A66 * V[34];
+ tmp29 += m_A67 * V[44];
+ V[29] = (RHS29 - tmp29) / m_A65;
+ double tmp28 = 0.0;
+ tmp28 += m_A64 * V[34];
+ V[28] = (RHS28 - tmp28) / m_A63;
+ double tmp27 = 0.0;
+ tmp27 += m_A62 * V[34];
+ V[27] = (RHS27 - tmp27) / m_A61;
+ double tmp26 = 0.0;
+ tmp26 += m_A60 * V[34];
+ V[26] = (RHS26 - tmp26) / m_A59;
+ double tmp25 = 0.0;
+ tmp25 += m_A58 * V[38];
+ V[25] = (RHS25 - tmp25) / m_A57;
+ double tmp24 = 0.0;
+ tmp24 += m_A56 * V[32];
+ V[24] = (RHS24 - tmp24) / m_A55;
+ double tmp23 = 0.0;
+ tmp23 += m_A52 * V[43];
+ V[23] = (RHS23 - tmp23) / m_A51;
+ double tmp22 = 0.0;
+ tmp22 += m_A50 * V[34];
+ V[22] = (RHS22 - tmp22) / m_A49;
+ double tmp21 = 0.0;
+ tmp21 += m_A46 * V[35];
+ tmp21 += m_A47 * V[42];
+ tmp21 += m_A48 * V[44];
+ V[21] = (RHS21 - tmp21) / m_A45;
+ double tmp20 = 0.0;
+ tmp20 += m_A44 * V[41];
+ V[20] = (RHS20 - tmp20) / m_A43;
+ double tmp19 = 0.0;
+ tmp19 += m_A42 * V[41];
+ V[19] = (RHS19 - tmp19) / m_A41;
+ double tmp18 = 0.0;
+ tmp18 += m_A40 * V[41];
+ V[18] = (RHS18 - tmp18) / m_A39;
+ double tmp17 = 0.0;
+ tmp17 += m_A38 * V[40];
+ V[17] = (RHS17 - tmp17) / m_A37;
+ double tmp16 = 0.0;
+ tmp16 += m_A36 * V[36];
+ V[16] = (RHS16 - tmp16) / m_A35;
+ double tmp15 = 0.0;
+ tmp15 += m_A34 * V[41];
+ V[15] = (RHS15 - tmp15) / m_A33;
+ double tmp14 = 0.0;
+ tmp14 += m_A32 * V[34];
+ V[14] = (RHS14 - tmp14) / m_A31;
+ double tmp13 = 0.0;
+ tmp13 += m_A30 * V[38];
+ V[13] = (RHS13 - tmp13) / m_A29;
+ double tmp12 = 0.0;
+ tmp12 += m_A28 * V[37];
+ V[12] = (RHS12 - tmp12) / m_A27;
+ double tmp11 = 0.0;
+ tmp11 += m_A26 * V[37];
+ V[11] = (RHS11 - tmp11) / m_A25;
+ double tmp10 = 0.0;
+ tmp10 += m_A24 * V[37];
+ V[10] = (RHS10 - tmp10) / m_A23;
+ double tmp9 = 0.0;
+ tmp9 += m_A22 * V[37];
+ V[9] = (RHS9 - tmp9) / m_A21;
+ double tmp8 = 0.0;
+ tmp8 += m_A20 * V[37];
+ V[8] = (RHS8 - tmp8) / m_A19;
+ double tmp7 = 0.0;
+ tmp7 += m_A17 * V[39];
+ tmp7 += m_A18 * V[42];
+ V[7] = (RHS7 - tmp7) / m_A16;
+ double tmp6 = 0.0;
+ tmp6 += m_A14 * V[32];
+ tmp6 += m_A15 * V[39];
+ V[6] = (RHS6 - tmp6) / m_A13;
+ double tmp5 = 0.0;
+ tmp5 += m_A12 * V[24];
+ V[5] = (RHS5 - tmp5) / m_A11;
+ double tmp4 = 0.0;
+ tmp4 += m_A9 * V[24];
+ tmp4 += m_A10 * V[32];
+ V[4] = (RHS4 - tmp4) / m_A8;
+ double tmp3 = 0.0;
+ tmp3 += m_A7 * V[33];
+ V[3] = (RHS3 - tmp3) / m_A6;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[33];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[33];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[33];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// pongf
static void nl_gcr_13e7b5ac1a260dbf_10_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -1369,74 +2384,6 @@ static void nl_gcr_15e8f6fb021de0f9_28_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
-// armora
-static void nl_gcr_1692de755a535408_9_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
-
-{
-
- plib::unused_var(cnV);
- double m_A0(0.0);
- double m_A1(0.0);
- double m_A2(0.0);
- double m_A3(0.0);
- double m_A4(0.0);
- double m_A5(0.0);
- double m_A6(0.0);
- double m_A7(0.0);
- double m_A8(0.0);
- m_A0 += gt[0];
- m_A0 += gt[1];
- m_A0 += gt[2];
- m_A2 += go[0];
- m_A1 += go[1];
- m_A1 += go[2];
- double RHS0 = Idr[0];
- RHS0 += Idr[1];
- RHS0 += Idr[2];
- m_A4 += gt[3];
- m_A4 += gt[4];
- m_A4 += gt[5];
- m_A4 += gt[6];
- m_A5 += go[3];
- m_A5 += go[4];
- m_A3 += go[5];
- m_A3 += go[6];
- double RHS1 = Idr[3];
- RHS1 += Idr[4];
- RHS1 += Idr[5];
- RHS1 += Idr[6];
- m_A8 += gt[7];
- m_A8 += gt[8];
- m_A8 += gt[9];
- m_A7 += go[7];
- m_A7 += go[8];
- m_A6 += go[9];
- double RHS2 = Idr[7];
- RHS2 += Idr[8];
- RHS2 += Idr[9];
- const double f0 = 1.0 / m_A0;
- const double f0_1 = -f0 * m_A3;
- m_A4 += m_A1 * f0_1;
- m_A5 += m_A2 * f0_1;
- RHS1 += f0_1 * RHS0;
- const double f0_2 = -f0 * m_A6;
- m_A7 += m_A1 * f0_2;
- m_A8 += m_A2 * f0_2;
- RHS2 += f0_2 * RHS0;
- const double f1 = 1.0 / m_A4;
- const double f1_2 = -f1 * m_A7;
- m_A8 += m_A5 * f1_2;
- RHS2 += f1_2 * RHS1;
- V[2] = RHS2 / m_A8;
- double tmp1 = 0.0;
- tmp1 += m_A5 * V[2];
- V[1] = (RHS1 - tmp1) / m_A4;
- double tmp0 = 0.0;
- tmp0 += m_A1 * V[1];
- tmp0 += m_A2 * V[2];
- V[0] = (RHS0 - tmp0) / m_A0;
-}
-
// dpatrol
static void nl_gcr_18f4d9160b51d613_20_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -2092,6 +3039,246 @@ static void nl_gcr_1fad5cda2646cf42_30_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_1fec893028a7b809_34_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A3 += go[2];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ RHS1 -= go[3] * *cnV[3];
+ m_A4 += gt[4];
+ m_A4 += gt[5];
+ m_A5 += go[4];
+ double RHS2 = Idr[4];
+ RHS2 += Idr[5];
+ RHS2 -= go[5] * *cnV[5];
+ m_A6 += gt[6];
+ m_A6 += gt[7];
+ m_A7 += go[6];
+ double RHS3 = Idr[6];
+ RHS3 += Idr[7];
+ RHS3 -= go[7] * *cnV[7];
+ m_A8 += gt[8];
+ m_A8 += gt[9];
+ m_A9 += go[8];
+ double RHS4 = Idr[8];
+ RHS4 += Idr[9];
+ RHS4 -= go[9] * *cnV[9];
+ m_A10 += gt[10];
+ m_A10 += gt[11];
+ m_A11 += go[10];
+ double RHS5 = Idr[10];
+ RHS5 += Idr[11];
+ RHS5 -= go[11] * *cnV[11];
+ m_A12 += gt[12];
+ m_A12 += gt[13];
+ m_A13 += go[12];
+ double RHS6 = Idr[12];
+ RHS6 += Idr[13];
+ RHS6 -= go[13] * *cnV[13];
+ m_A14 += gt[14];
+ m_A14 += gt[15];
+ m_A15 += go[14];
+ double RHS7 = Idr[14];
+ RHS7 += Idr[15];
+ RHS7 -= go[15] * *cnV[15];
+ m_A16 += gt[16];
+ m_A16 += gt[17];
+ m_A17 += go[16];
+ double RHS8 = Idr[16];
+ RHS8 += Idr[17];
+ RHS8 -= go[17] * *cnV[17];
+ m_A18 += gt[18];
+ m_A18 += gt[19];
+ m_A18 += gt[20];
+ m_A18 += gt[21];
+ m_A18 += gt[22];
+ m_A18 += gt[23];
+ m_A18 += gt[24];
+ m_A19 += go[18];
+ double RHS9 = Idr[18];
+ RHS9 += Idr[19];
+ RHS9 += Idr[20];
+ RHS9 += Idr[21];
+ RHS9 += Idr[22];
+ RHS9 += Idr[23];
+ RHS9 += Idr[24];
+ RHS9 -= go[19] * *cnV[19];
+ RHS9 -= go[20] * *cnV[20];
+ RHS9 -= go[21] * *cnV[21];
+ RHS9 -= go[22] * *cnV[22];
+ RHS9 -= go[23] * *cnV[23];
+ RHS9 -= go[24] * *cnV[24];
+ m_A28 += gt[25];
+ m_A28 += gt[26];
+ m_A28 += gt[27];
+ m_A28 += gt[28];
+ m_A28 += gt[29];
+ m_A28 += gt[30];
+ m_A28 += gt[31];
+ m_A28 += gt[32];
+ m_A28 += gt[33];
+ m_A28 += gt[34];
+ m_A29 += go[25];
+ m_A27 += go[26];
+ m_A26 += go[27];
+ m_A25 += go[28];
+ m_A24 += go[29];
+ m_A23 += go[30];
+ m_A22 += go[31];
+ m_A21 += go[32];
+ m_A20 += go[33];
+ double RHS10 = Idr[25];
+ RHS10 += Idr[26];
+ RHS10 += Idr[27];
+ RHS10 += Idr[28];
+ RHS10 += Idr[29];
+ RHS10 += Idr[30];
+ RHS10 += Idr[31];
+ RHS10 += Idr[32];
+ RHS10 += Idr[33];
+ RHS10 += Idr[34];
+ RHS10 -= go[34] * *cnV[34];
+ m_A33 += gt[35];
+ m_A33 += gt[36];
+ m_A33 += gt[37];
+ m_A33 += gt[38];
+ m_A33 += gt[39];
+ m_A31 += go[35];
+ m_A30 += go[36];
+ m_A32 += go[37];
+ double RHS11 = Idr[35];
+ RHS11 += Idr[36];
+ RHS11 += Idr[37];
+ RHS11 += Idr[38];
+ RHS11 += Idr[39];
+ RHS11 -= go[38] * *cnV[38];
+ RHS11 -= go[39] * *cnV[39];
+ const double f0 = 1.0 / m_A0;
+ const double f0_10 = -f0 * m_A20;
+ m_A28 += m_A1 * f0_10;
+ RHS10 += f0_10 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_10 = -f1 * m_A21;
+ m_A28 += m_A3 * f1_10;
+ RHS10 += f1_10 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_11 = -f2 * m_A30;
+ m_A33 += m_A5 * f2_11;
+ RHS11 += f2_11 * RHS2;
+ const double f3 = 1.0 / m_A6;
+ const double f3_10 = -f3 * m_A22;
+ m_A28 += m_A7 * f3_10;
+ RHS10 += f3_10 * RHS3;
+ const double f4 = 1.0 / m_A8;
+ const double f4_10 = -f4 * m_A23;
+ m_A28 += m_A9 * f4_10;
+ RHS10 += f4_10 * RHS4;
+ const double f5 = 1.0 / m_A10;
+ const double f5_10 = -f5 * m_A24;
+ m_A28 += m_A11 * f5_10;
+ RHS10 += f5_10 * RHS5;
+ const double f6 = 1.0 / m_A12;
+ const double f6_10 = -f6 * m_A25;
+ m_A28 += m_A13 * f6_10;
+ RHS10 += f6_10 * RHS6;
+ const double f7 = 1.0 / m_A14;
+ const double f7_10 = -f7 * m_A26;
+ m_A28 += m_A15 * f7_10;
+ RHS10 += f7_10 * RHS7;
+ const double f8 = 1.0 / m_A16;
+ const double f8_10 = -f8 * m_A27;
+ m_A28 += m_A17 * f8_10;
+ RHS10 += f8_10 * RHS8;
+ const double f9 = 1.0 / m_A18;
+ const double f9_11 = -f9 * m_A31;
+ m_A32 += m_A19 * f9_11;
+ RHS11 += f9_11 * RHS9;
+ const double f10 = 1.0 / m_A28;
+ const double f10_11 = -f10 * m_A32;
+ m_A33 += m_A29 * f10_11;
+ RHS11 += f10_11 * RHS10;
+ V[11] = RHS11 / m_A33;
+ double tmp10 = 0.0;
+ tmp10 += m_A29 * V[11];
+ V[10] = (RHS10 - tmp10) / m_A28;
+ double tmp9 = 0.0;
+ tmp9 += m_A19 * V[10];
+ V[9] = (RHS9 - tmp9) / m_A18;
+ double tmp8 = 0.0;
+ tmp8 += m_A17 * V[10];
+ V[8] = (RHS8 - tmp8) / m_A16;
+ double tmp7 = 0.0;
+ tmp7 += m_A15 * V[10];
+ V[7] = (RHS7 - tmp7) / m_A14;
+ double tmp6 = 0.0;
+ tmp6 += m_A13 * V[10];
+ V[6] = (RHS6 - tmp6) / m_A12;
+ double tmp5 = 0.0;
+ tmp5 += m_A11 * V[10];
+ V[5] = (RHS5 - tmp5) / m_A10;
+ double tmp4 = 0.0;
+ tmp4 += m_A9 * V[10];
+ V[4] = (RHS4 - tmp4) / m_A8;
+ double tmp3 = 0.0;
+ tmp3 += m_A7 * V[10];
+ V[3] = (RHS3 - tmp3) / m_A6;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[11];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[10];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[10];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// sspeedr
static void nl_gcr_2294220d3c91e762_176_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -3198,6 +4385,718 @@ static void nl_gcr_2294220d3c91e762_176_double_double(double * __restrict V, con
V[0] = (RHS0 - tmp0) / m_A0;
}
+// headon
+static void nl_gcr_24023c8529f6bdb3_97_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ double m_A89(0.0);
+ double m_A90(0.0);
+ double m_A91(0.0);
+ double m_A92(0.0);
+ double m_A93(0.0);
+ double m_A94(0.0);
+ double m_A95(0.0);
+ double m_A96(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A2 += gt[7];
+ m_A2 += gt[8];
+ m_A2 += gt[9];
+ m_A3 += go[3];
+ m_A3 += go[4];
+ m_A3 += go[5];
+ m_A4 += go[6];
+ m_A4 += go[7];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 += Idr[7];
+ RHS1 += Idr[8];
+ RHS1 += Idr[9];
+ RHS1 -= go[8] * *cnV[8];
+ RHS1 -= go[9] * *cnV[9];
+ m_A5 += gt[10];
+ m_A5 += gt[11];
+ m_A6 += go[10];
+ double RHS2 = Idr[10];
+ RHS2 += Idr[11];
+ RHS2 -= go[11] * *cnV[11];
+ m_A7 += gt[12];
+ m_A7 += gt[13];
+ m_A8 += go[12];
+ double RHS3 = Idr[12];
+ RHS3 += Idr[13];
+ RHS3 -= go[13] * *cnV[13];
+ m_A9 += gt[14];
+ m_A9 += gt[15];
+ m_A9 += gt[16];
+ m_A9 += gt[17];
+ m_A9 += gt[18];
+ m_A11 += go[14];
+ m_A10 += go[15];
+ m_A12 += go[16];
+ m_A12 += go[17];
+ double RHS4 = Idr[14];
+ RHS4 += Idr[15];
+ RHS4 += Idr[16];
+ RHS4 += Idr[17];
+ RHS4 += Idr[18];
+ RHS4 -= go[18] * *cnV[18];
+ m_A13 += gt[19];
+ m_A13 += gt[20];
+ m_A13 += gt[21];
+ m_A14 += go[19];
+ double RHS5 = Idr[19];
+ RHS5 += Idr[20];
+ RHS5 += Idr[21];
+ RHS5 -= go[20] * *cnV[20];
+ RHS5 -= go[21] * *cnV[21];
+ m_A15 += gt[22];
+ m_A15 += gt[23];
+ m_A15 += gt[24];
+ m_A15 += gt[25];
+ m_A15 += gt[26];
+ m_A15 += gt[27];
+ m_A15 += gt[28];
+ m_A16 += go[22];
+ m_A16 += go[23];
+ m_A16 += go[24];
+ m_A17 += go[25];
+ m_A17 += go[26];
+ double RHS6 = Idr[22];
+ RHS6 += Idr[23];
+ RHS6 += Idr[24];
+ RHS6 += Idr[25];
+ RHS6 += Idr[26];
+ RHS6 += Idr[27];
+ RHS6 += Idr[28];
+ RHS6 -= go[27] * *cnV[27];
+ RHS6 -= go[28] * *cnV[28];
+ m_A18 += gt[29];
+ m_A18 += gt[30];
+ m_A19 += go[29];
+ double RHS7 = Idr[29];
+ RHS7 += Idr[30];
+ RHS7 -= go[30] * *cnV[30];
+ m_A20 += gt[31];
+ m_A20 += gt[32];
+ m_A21 += go[31];
+ double RHS8 = Idr[31];
+ RHS8 += Idr[32];
+ RHS8 -= go[32] * *cnV[32];
+ m_A22 += gt[33];
+ m_A22 += gt[34];
+ m_A22 += gt[35];
+ m_A23 += go[33];
+ double RHS9 = Idr[33];
+ RHS9 += Idr[34];
+ RHS9 += Idr[35];
+ RHS9 -= go[34] * *cnV[34];
+ RHS9 -= go[35] * *cnV[35];
+ m_A24 += gt[36];
+ m_A24 += gt[37];
+ m_A24 += gt[38];
+ m_A24 += gt[39];
+ m_A24 += gt[40];
+ m_A25 += go[36];
+ m_A26 += go[37];
+ m_A27 += go[38];
+ m_A27 += go[39];
+ double RHS10 = Idr[36];
+ RHS10 += Idr[37];
+ RHS10 += Idr[38];
+ RHS10 += Idr[39];
+ RHS10 += Idr[40];
+ RHS10 -= go[40] * *cnV[40];
+ m_A29 += gt[41];
+ m_A29 += gt[42];
+ m_A29 += gt[43];
+ m_A29 += gt[44];
+ m_A29 += gt[45];
+ m_A29 += gt[46];
+ m_A29 += gt[47];
+ m_A30 += go[41];
+ m_A30 += go[42];
+ m_A30 += go[43];
+ m_A28 += go[44];
+ double RHS11 = Idr[41];
+ RHS11 += Idr[42];
+ RHS11 += Idr[43];
+ RHS11 += Idr[44];
+ RHS11 += Idr[45];
+ RHS11 += Idr[46];
+ RHS11 += Idr[47];
+ RHS11 -= go[45] * *cnV[45];
+ RHS11 -= go[46] * *cnV[46];
+ RHS11 -= go[47] * *cnV[47];
+ m_A31 += gt[48];
+ m_A31 += gt[49];
+ m_A31 += gt[50];
+ m_A31 += gt[51];
+ m_A31 += gt[52];
+ m_A31 += gt[53];
+ m_A32 += go[48];
+ m_A32 += go[49];
+ m_A32 += go[50];
+ m_A33 += go[51];
+ m_A34 += go[52];
+ double RHS12 = Idr[48];
+ RHS12 += Idr[49];
+ RHS12 += Idr[50];
+ RHS12 += Idr[51];
+ RHS12 += Idr[52];
+ RHS12 += Idr[53];
+ RHS12 -= go[53] * *cnV[53];
+ m_A37 += gt[54];
+ m_A37 += gt[55];
+ m_A37 += gt[56];
+ m_A37 += gt[57];
+ m_A37 += gt[58];
+ m_A36 += go[54];
+ m_A35 += go[55];
+ m_A35 += go[56];
+ m_A35 += go[57];
+ m_A39 += go[58];
+ double RHS13 = Idr[54];
+ RHS13 += Idr[55];
+ RHS13 += Idr[56];
+ RHS13 += Idr[57];
+ RHS13 += Idr[58];
+ m_A42 += gt[59];
+ m_A42 += gt[60];
+ m_A42 += gt[61];
+ m_A42 += gt[62];
+ m_A42 += gt[63];
+ m_A42 += gt[64];
+ m_A42 += gt[65];
+ m_A43 += go[59];
+ m_A43 += go[60];
+ m_A43 += go[61];
+ m_A41 += go[62];
+ double RHS14 = Idr[59];
+ RHS14 += Idr[60];
+ RHS14 += Idr[61];
+ RHS14 += Idr[62];
+ RHS14 += Idr[63];
+ RHS14 += Idr[64];
+ RHS14 += Idr[65];
+ RHS14 -= go[63] * *cnV[63];
+ RHS14 -= go[64] * *cnV[64];
+ RHS14 -= go[65] * *cnV[65];
+ m_A47 += gt[66];
+ m_A47 += gt[67];
+ m_A47 += gt[68];
+ m_A47 += gt[69];
+ m_A47 += gt[70];
+ m_A44 += go[66];
+ m_A45 += go[67];
+ m_A49 += go[68];
+ m_A49 += go[69];
+ double RHS15 = Idr[66];
+ RHS15 += Idr[67];
+ RHS15 += Idr[68];
+ RHS15 += Idr[69];
+ RHS15 += Idr[70];
+ RHS15 -= go[70] * *cnV[70];
+ m_A52 += gt[71];
+ m_A52 += gt[72];
+ m_A52 += gt[73];
+ m_A52 += gt[74];
+ m_A52 += gt[75];
+ m_A52 += gt[76];
+ m_A52 += gt[77];
+ m_A51 += go[71];
+ m_A51 += go[72];
+ m_A51 += go[73];
+ m_A50 += go[74];
+ double RHS16 = Idr[71];
+ RHS16 += Idr[72];
+ RHS16 += Idr[73];
+ RHS16 += Idr[74];
+ RHS16 += Idr[75];
+ RHS16 += Idr[76];
+ RHS16 += Idr[77];
+ RHS16 -= go[75] * *cnV[75];
+ RHS16 -= go[76] * *cnV[76];
+ RHS16 -= go[77] * *cnV[77];
+ m_A57 += gt[78];
+ m_A57 += gt[79];
+ m_A57 += gt[80];
+ m_A57 += gt[81];
+ m_A57 += gt[82];
+ m_A55 += go[78];
+ m_A56 += go[79];
+ m_A59 += go[80];
+ m_A59 += go[81];
+ double RHS17 = Idr[78];
+ RHS17 += Idr[79];
+ RHS17 += Idr[80];
+ RHS17 += Idr[81];
+ RHS17 += Idr[82];
+ RHS17 -= go[82] * *cnV[82];
+ m_A64 += gt[83];
+ m_A64 += gt[84];
+ m_A64 += gt[85];
+ m_A64 += gt[86];
+ m_A64 += gt[87];
+ m_A64 += gt[88];
+ m_A64 += gt[89];
+ m_A64 += gt[90];
+ m_A62 += go[83];
+ m_A65 += go[84];
+ m_A60 += go[85];
+ m_A60 += go[86];
+ m_A61 += go[87];
+ m_A61 += go[88];
+ m_A61 += go[89];
+ double RHS18 = Idr[83];
+ RHS18 += Idr[84];
+ RHS18 += Idr[85];
+ RHS18 += Idr[86];
+ RHS18 += Idr[87];
+ RHS18 += Idr[88];
+ RHS18 += Idr[89];
+ RHS18 += Idr[90];
+ RHS18 -= go[90] * *cnV[90];
+ m_A69 += gt[91];
+ m_A69 += gt[92];
+ m_A69 += gt[93];
+ m_A69 += gt[94];
+ m_A69 += gt[95];
+ m_A67 += go[91];
+ m_A66 += go[92];
+ m_A66 += go[93];
+ m_A66 += go[94];
+ m_A71 += go[95];
+ double RHS19 = Idr[91];
+ RHS19 += Idr[92];
+ RHS19 += Idr[93];
+ RHS19 += Idr[94];
+ RHS19 += Idr[95];
+ m_A78 += gt[96];
+ m_A78 += gt[97];
+ m_A78 += gt[98];
+ m_A78 += gt[99];
+ m_A78 += gt[100];
+ m_A78 += gt[101];
+ m_A78 += gt[102];
+ m_A74 += go[96];
+ m_A76 += go[97];
+ m_A76 += go[98];
+ m_A73 += go[99];
+ m_A73 += go[100];
+ m_A72 += go[101];
+ m_A80 += go[102];
+ double RHS20 = Idr[96];
+ RHS20 += Idr[97];
+ RHS20 += Idr[98];
+ RHS20 += Idr[99];
+ RHS20 += Idr[100];
+ RHS20 += Idr[101];
+ RHS20 += Idr[102];
+ m_A89 += gt[103];
+ m_A89 += gt[104];
+ m_A89 += gt[105];
+ m_A89 += gt[106];
+ m_A89 += gt[107];
+ m_A89 += gt[108];
+ m_A89 += gt[109];
+ m_A83 += go[103];
+ m_A85 += go[104];
+ m_A85 += go[105];
+ m_A82 += go[106];
+ m_A82 += go[107];
+ m_A81 += go[108];
+ m_A87 += go[109];
+ double RHS21 = Idr[103];
+ RHS21 += Idr[104];
+ RHS21 += Idr[105];
+ RHS21 += Idr[106];
+ RHS21 += Idr[107];
+ RHS21 += Idr[108];
+ RHS21 += Idr[109];
+ m_A96 += gt[110];
+ m_A96 += gt[111];
+ m_A96 += gt[112];
+ m_A96 += gt[113];
+ m_A96 += gt[114];
+ m_A96 += gt[115];
+ m_A96 += gt[116];
+ m_A96 += gt[117];
+ m_A93 += go[110];
+ m_A94 += go[111];
+ m_A91 += go[112];
+ m_A91 += go[113];
+ m_A92 += go[114];
+ m_A92 += go[115];
+ m_A92 += go[116];
+ double RHS22 = Idr[110];
+ RHS22 += Idr[111];
+ RHS22 += Idr[112];
+ RHS22 += Idr[113];
+ RHS22 += Idr[114];
+ RHS22 += Idr[115];
+ RHS22 += Idr[116];
+ RHS22 += Idr[117];
+ RHS22 -= go[117] * *cnV[117];
+ const double f0 = 1.0 / m_A0;
+ const double f0_11 = -f0 * m_A28;
+ m_A29 += m_A1 * f0_11;
+ RHS11 += f0_11 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_13 = -f1 * m_A35;
+ m_A37 += m_A3 * f1_13;
+ m_A39 += m_A4 * f1_13;
+ RHS13 += f1_13 * RHS1;
+ const double f1_18 = -f1 * m_A60;
+ m_A62 += m_A3 * f1_18;
+ m_A64 += m_A4 * f1_18;
+ RHS18 += f1_18 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_21 = -f2 * m_A81;
+ m_A89 += m_A6 * f2_21;
+ RHS21 += f2_21 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_15 = -f3 * m_A44;
+ m_A47 += m_A8 * f3_15;
+ RHS15 += f3_15 * RHS3;
+ const double f4 = 1.0 / m_A9;
+ const double f4_13 = -f4 * m_A36;
+ m_A37 += m_A10 * f4_13;
+ m_A38 += m_A11 * f4_13;
+ m_A40 += m_A12 * f4_13;
+ RHS13 += f4_13 * RHS4;
+ const double f4_15 = -f4 * m_A45;
+ m_A46 += m_A10 * f4_15;
+ m_A47 += m_A11 * f4_15;
+ m_A49 += m_A12 * f4_15;
+ RHS15 += f4_15 * RHS4;
+ const double f4_21 = -f4 * m_A82;
+ m_A84 += m_A10 * f4_21;
+ m_A85 += m_A11 * f4_21;
+ m_A89 += m_A12 * f4_21;
+ RHS21 += f4_21 * RHS4;
+ const double f5 = 1.0 / m_A13;
+ const double f5_14 = -f5 * m_A41;
+ m_A42 += m_A14 * f5_14;
+ RHS14 += f5_14 * RHS5;
+ const double f6 = 1.0 / m_A15;
+ const double f6_19 = -f6 * m_A66;
+ m_A69 += m_A16 * f6_19;
+ m_A71 += m_A17 * f6_19;
+ RHS19 += f6_19 * RHS6;
+ const double f6_22 = -f6 * m_A91;
+ m_A93 += m_A16 * f6_22;
+ m_A96 += m_A17 * f6_22;
+ RHS22 += f6_22 * RHS6;
+ const double f7 = 1.0 / m_A18;
+ const double f7_17 = -f7 * m_A55;
+ m_A57 += m_A19 * f7_17;
+ RHS17 += f7_17 * RHS7;
+ const double f8 = 1.0 / m_A20;
+ const double f8_20 = -f8 * m_A72;
+ m_A78 += m_A21 * f8_20;
+ RHS20 += f8_20 * RHS8;
+ const double f9 = 1.0 / m_A22;
+ const double f9_16 = -f9 * m_A50;
+ m_A52 += m_A23 * f9_16;
+ RHS16 += f9_16 * RHS9;
+ const double f10 = 1.0 / m_A24;
+ const double f10_17 = -f10 * m_A56;
+ m_A57 += m_A25 * f10_17;
+ m_A58 += m_A26 * f10_17;
+ m_A59 += m_A27 * f10_17;
+ RHS17 += f10_17 * RHS10;
+ const double f10_19 = -f10 * m_A67;
+ m_A68 += m_A25 * f10_19;
+ m_A69 += m_A26 * f10_19;
+ m_A70 += m_A27 * f10_19;
+ RHS19 += f10_19 * RHS10;
+ const double f10_20 = -f10 * m_A73;
+ m_A76 += m_A25 * f10_20;
+ m_A77 += m_A26 * f10_20;
+ m_A78 += m_A27 * f10_20;
+ RHS20 += f10_20 * RHS10;
+ const double f11 = 1.0 / m_A29;
+ const double f11_18 = -f11 * m_A61;
+ m_A64 += m_A30 * f11_18;
+ RHS18 += f11_18 * RHS11;
+ const double f12 = 1.0 / m_A31;
+ const double f12_16 = -f12 * m_A51;
+ m_A52 += m_A32 * f12_16;
+ m_A53 += m_A33 * f12_16;
+ m_A54 += m_A34 * f12_16;
+ RHS16 += f12_16 * RHS12;
+ const double f12_20 = -f12 * m_A74;
+ m_A75 += m_A32 * f12_20;
+ m_A78 += m_A33 * f12_20;
+ m_A79 += m_A34 * f12_20;
+ RHS20 += f12_20 * RHS12;
+ const double f12_21 = -f12 * m_A83;
+ m_A86 += m_A32 * f12_21;
+ m_A88 += m_A33 * f12_21;
+ m_A89 += m_A34 * f12_21;
+ RHS21 += f12_21 * RHS12;
+ const double f13 = 1.0 / m_A37;
+ const double f13_15 = -f13 * m_A46;
+ m_A47 += m_A38 * f13_15;
+ m_A48 += m_A39 * f13_15;
+ m_A49 += m_A40 * f13_15;
+ RHS15 += f13_15 * RHS13;
+ const double f13_18 = -f13 * m_A62;
+ m_A63 += m_A38 * f13_18;
+ m_A64 += m_A39 * f13_18;
+ m_A65 += m_A40 * f13_18;
+ RHS18 += f13_18 * RHS13;
+ const double f13_21 = -f13 * m_A84;
+ m_A85 += m_A38 * f13_21;
+ m_A87 += m_A39 * f13_21;
+ m_A89 += m_A40 * f13_21;
+ RHS21 += f13_21 * RHS13;
+ const double f14 = 1.0 / m_A42;
+ const double f14_22 = -f14 * m_A92;
+ m_A96 += m_A43 * f14_22;
+ RHS22 += f14_22 * RHS14;
+ const double f15 = 1.0 / m_A47;
+ const double f15_18 = -f15 * m_A63;
+ m_A64 += m_A48 * f15_18;
+ m_A65 += m_A49 * f15_18;
+ RHS18 += f15_18 * RHS15;
+ const double f15_21 = -f15 * m_A85;
+ m_A87 += m_A48 * f15_21;
+ m_A89 += m_A49 * f15_21;
+ RHS21 += f15_21 * RHS15;
+ const double f16 = 1.0 / m_A52;
+ const double f16_20 = -f16 * m_A75;
+ m_A78 += m_A53 * f16_20;
+ m_A79 += m_A54 * f16_20;
+ RHS20 += f16_20 * RHS16;
+ const double f16_21 = -f16 * m_A86;
+ m_A88 += m_A53 * f16_21;
+ m_A89 += m_A54 * f16_21;
+ RHS21 += f16_21 * RHS16;
+ const double f17 = 1.0 / m_A57;
+ const double f17_19 = -f17 * m_A68;
+ m_A69 += m_A58 * f17_19;
+ m_A70 += m_A59 * f17_19;
+ RHS19 += f17_19 * RHS17;
+ const double f17_20 = -f17 * m_A76;
+ m_A77 += m_A58 * f17_20;
+ m_A78 += m_A59 * f17_20;
+ RHS20 += f17_20 * RHS17;
+ const double f18 = 1.0 / m_A64;
+ const double f18_21 = -f18 * m_A87;
+ m_A89 += m_A65 * f18_21;
+ RHS21 += f18_21 * RHS18;
+ const double f19 = 1.0 / m_A69;
+ const double f19_20 = -f19 * m_A77;
+ m_A78 += m_A70 * f19_20;
+ m_A80 += m_A71 * f19_20;
+ RHS20 += f19_20 * RHS19;
+ const double f19_22 = -f19 * m_A93;
+ m_A94 += m_A70 * f19_22;
+ m_A96 += m_A71 * f19_22;
+ RHS22 += f19_22 * RHS19;
+ const double f20 = 1.0 / m_A78;
+ const double f20_21 = -f20 * m_A88;
+ m_A89 += m_A79 * f20_21;
+ m_A90 += m_A80 * f20_21;
+ RHS21 += f20_21 * RHS20;
+ const double f20_22 = -f20 * m_A94;
+ m_A95 += m_A79 * f20_22;
+ m_A96 += m_A80 * f20_22;
+ RHS22 += f20_22 * RHS20;
+ const double f21 = 1.0 / m_A89;
+ const double f21_22 = -f21 * m_A95;
+ m_A96 += m_A90 * f21_22;
+ RHS22 += f21_22 * RHS21;
+ V[22] = RHS22 / m_A96;
+ double tmp21 = 0.0;
+ tmp21 += m_A90 * V[22];
+ V[21] = (RHS21 - tmp21) / m_A89;
+ double tmp20 = 0.0;
+ tmp20 += m_A79 * V[21];
+ tmp20 += m_A80 * V[22];
+ V[20] = (RHS20 - tmp20) / m_A78;
+ double tmp19 = 0.0;
+ tmp19 += m_A70 * V[20];
+ tmp19 += m_A71 * V[22];
+ V[19] = (RHS19 - tmp19) / m_A69;
+ double tmp18 = 0.0;
+ tmp18 += m_A65 * V[21];
+ V[18] = (RHS18 - tmp18) / m_A64;
+ double tmp17 = 0.0;
+ tmp17 += m_A58 * V[19];
+ tmp17 += m_A59 * V[20];
+ V[17] = (RHS17 - tmp17) / m_A57;
+ double tmp16 = 0.0;
+ tmp16 += m_A53 * V[20];
+ tmp16 += m_A54 * V[21];
+ V[16] = (RHS16 - tmp16) / m_A52;
+ double tmp15 = 0.0;
+ tmp15 += m_A48 * V[18];
+ tmp15 += m_A49 * V[21];
+ V[15] = (RHS15 - tmp15) / m_A47;
+ double tmp14 = 0.0;
+ tmp14 += m_A43 * V[22];
+ V[14] = (RHS14 - tmp14) / m_A42;
+ double tmp13 = 0.0;
+ tmp13 += m_A38 * V[15];
+ tmp13 += m_A39 * V[18];
+ tmp13 += m_A40 * V[21];
+ V[13] = (RHS13 - tmp13) / m_A37;
+ double tmp12 = 0.0;
+ tmp12 += m_A32 * V[16];
+ tmp12 += m_A33 * V[20];
+ tmp12 += m_A34 * V[21];
+ V[12] = (RHS12 - tmp12) / m_A31;
+ double tmp11 = 0.0;
+ tmp11 += m_A30 * V[18];
+ V[11] = (RHS11 - tmp11) / m_A29;
+ double tmp10 = 0.0;
+ tmp10 += m_A25 * V[17];
+ tmp10 += m_A26 * V[19];
+ tmp10 += m_A27 * V[20];
+ V[10] = (RHS10 - tmp10) / m_A24;
+ double tmp9 = 0.0;
+ tmp9 += m_A23 * V[16];
+ V[9] = (RHS9 - tmp9) / m_A22;
+ double tmp8 = 0.0;
+ tmp8 += m_A21 * V[20];
+ V[8] = (RHS8 - tmp8) / m_A20;
+ double tmp7 = 0.0;
+ tmp7 += m_A19 * V[17];
+ V[7] = (RHS7 - tmp7) / m_A18;
+ double tmp6 = 0.0;
+ tmp6 += m_A16 * V[19];
+ tmp6 += m_A17 * V[22];
+ V[6] = (RHS6 - tmp6) / m_A15;
+ double tmp5 = 0.0;
+ tmp5 += m_A14 * V[14];
+ V[5] = (RHS5 - tmp5) / m_A13;
+ double tmp4 = 0.0;
+ tmp4 += m_A10 * V[13];
+ tmp4 += m_A11 * V[15];
+ tmp4 += m_A12 * V[21];
+ V[4] = (RHS4 - tmp4) / m_A9;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[15];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[21];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[13];
+ tmp1 += m_A4 * V[18];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[11];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// 280zzzap
static void nl_gcr_24643c159711f292_95_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -3851,6 +5750,438 @@ static void nl_gcr_24643c159711f292_95_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// frogs
+static void nl_gcr_263b618097fad01_38_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ m_A2 += go[1];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[2] * *cnV[2];
+ m_A3 += gt[3];
+ m_A3 += gt[4];
+ m_A4 += go[3];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 -= go[4] * *cnV[4];
+ m_A5 += gt[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A7 += go[5];
+ m_A6 += go[6];
+ double RHS2 = Idr[5];
+ RHS2 += Idr[6];
+ RHS2 += Idr[7];
+ RHS2 -= go[7] * *cnV[7];
+ m_A8 += gt[8];
+ m_A8 += gt[9];
+ m_A8 += gt[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A9 += go[8];
+ double RHS3 = Idr[8];
+ RHS3 += Idr[9];
+ RHS3 += Idr[10];
+ RHS3 += Idr[11];
+ RHS3 += Idr[12];
+ RHS3 += Idr[13];
+ RHS3 += Idr[14];
+ RHS3 -= go[9] * *cnV[9];
+ RHS3 -= go[10] * *cnV[10];
+ RHS3 -= go[11] * *cnV[11];
+ RHS3 -= go[12] * *cnV[12];
+ RHS3 -= go[13] * *cnV[13];
+ RHS3 -= go[14] * *cnV[14];
+ m_A10 += gt[15];
+ m_A10 += gt[16];
+ m_A10 += gt[17];
+ m_A11 += go[15];
+ m_A12 += go[16];
+ double RHS4 = Idr[15];
+ RHS4 += Idr[16];
+ RHS4 += Idr[17];
+ RHS4 -= go[17] * *cnV[17];
+ m_A14 += gt[18];
+ m_A14 += gt[19];
+ m_A14 += gt[20];
+ m_A14 += gt[21];
+ m_A16 += go[18];
+ m_A13 += go[19];
+ double RHS5 = Idr[18];
+ RHS5 += Idr[19];
+ RHS5 += Idr[20];
+ RHS5 += Idr[21];
+ RHS5 -= go[20] * *cnV[20];
+ RHS5 -= go[21] * *cnV[21];
+ m_A19 += gt[22];
+ m_A19 += gt[23];
+ m_A19 += gt[24];
+ m_A21 += go[22];
+ m_A17 += go[23];
+ double RHS6 = Idr[22];
+ RHS6 += Idr[23];
+ RHS6 += Idr[24];
+ RHS6 -= go[24] * *cnV[24];
+ m_A24 += gt[25];
+ m_A24 += gt[26];
+ m_A24 += gt[27];
+ m_A24 += gt[28];
+ m_A24 += gt[29];
+ m_A22 += go[25];
+ m_A23 += go[26];
+ m_A25 += go[27];
+ double RHS7 = Idr[25];
+ RHS7 += Idr[26];
+ RHS7 += Idr[27];
+ RHS7 += Idr[28];
+ RHS7 += Idr[29];
+ RHS7 -= go[28] * *cnV[28];
+ RHS7 -= go[29] * *cnV[29];
+ m_A30 += gt[30];
+ m_A30 += gt[31];
+ m_A30 += gt[32];
+ m_A30 += gt[33];
+ m_A30 += gt[34];
+ m_A30 += gt[35];
+ m_A30 += gt[36];
+ m_A27 += go[30];
+ m_A31 += go[31];
+ m_A26 += go[32];
+ m_A28 += go[33];
+ double RHS8 = Idr[30];
+ RHS8 += Idr[31];
+ RHS8 += Idr[32];
+ RHS8 += Idr[33];
+ RHS8 += Idr[34];
+ RHS8 += Idr[35];
+ RHS8 += Idr[36];
+ RHS8 -= go[34] * *cnV[34];
+ RHS8 -= go[35] * *cnV[35];
+ RHS8 -= go[36] * *cnV[36];
+ m_A37 += gt[37];
+ m_A37 += gt[38];
+ m_A37 += gt[39];
+ m_A37 += gt[40];
+ m_A37 += gt[41];
+ m_A35 += go[37];
+ m_A33 += go[38];
+ m_A32 += go[39];
+ m_A36 += go[40];
+ m_A34 += go[41];
+ double RHS9 = Idr[37];
+ RHS9 += Idr[38];
+ RHS9 += Idr[39];
+ RHS9 += Idr[40];
+ RHS9 += Idr[41];
+ const double f0 = 1.0 / m_A0;
+ const double f0_5 = -f0 * m_A13;
+ m_A14 += m_A1 * f0_5;
+ m_A15 += m_A2 * f0_5;
+ RHS5 += f0_5 * RHS0;
+ const double f0_6 = -f0 * m_A17;
+ m_A18 += m_A1 * f0_6;
+ m_A19 += m_A2 * f0_6;
+ RHS6 += f0_6 * RHS0;
+ const double f1 = 1.0 / m_A3;
+ const double f1_8 = -f1 * m_A26;
+ m_A30 += m_A4 * f1_8;
+ RHS8 += f1_8 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_8 = -f2 * m_A27;
+ m_A30 += m_A6 * f2_8;
+ m_A31 += m_A7 * f2_8;
+ RHS8 += f2_8 * RHS2;
+ const double f2_9 = -f2 * m_A32;
+ m_A36 += m_A6 * f2_9;
+ m_A37 += m_A7 * f2_9;
+ RHS9 += f2_9 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_7 = -f3 * m_A22;
+ m_A23 += m_A9 * f3_7;
+ RHS7 += f3_7 * RHS3;
+ const double f4 = 1.0 / m_A10;
+ const double f4_7 = -f4 * m_A23;
+ m_A24 += m_A11 * f4_7;
+ m_A25 += m_A12 * f4_7;
+ RHS7 += f4_7 * RHS4;
+ const double f4_9 = -f4 * m_A33;
+ m_A35 += m_A11 * f4_9;
+ m_A37 += m_A12 * f4_9;
+ RHS9 += f4_9 * RHS4;
+ const double f5 = 1.0 / m_A14;
+ const double f5_6 = -f5 * m_A18;
+ m_A19 += m_A15 * f5_6;
+ m_A20 += m_A16 * f5_6;
+ RHS6 += f5_6 * RHS5;
+ const double f5_8 = -f5 * m_A28;
+ m_A29 += m_A15 * f5_8;
+ m_A30 += m_A16 * f5_8;
+ RHS8 += f5_8 * RHS5;
+ const double f6 = 1.0 / m_A19;
+ const double f6_8 = -f6 * m_A29;
+ m_A30 += m_A20 * f6_8;
+ m_A31 += m_A21 * f6_8;
+ RHS8 += f6_8 * RHS6;
+ const double f6_9 = -f6 * m_A34;
+ m_A36 += m_A20 * f6_9;
+ m_A37 += m_A21 * f6_9;
+ RHS9 += f6_9 * RHS6;
+ const double f7 = 1.0 / m_A24;
+ const double f7_9 = -f7 * m_A35;
+ m_A37 += m_A25 * f7_9;
+ RHS9 += f7_9 * RHS7;
+ const double f8 = 1.0 / m_A30;
+ const double f8_9 = -f8 * m_A36;
+ m_A37 += m_A31 * f8_9;
+ RHS9 += f8_9 * RHS8;
+ V[9] = RHS9 / m_A37;
+ double tmp8 = 0.0;
+ tmp8 += m_A31 * V[9];
+ V[8] = (RHS8 - tmp8) / m_A30;
+ double tmp7 = 0.0;
+ tmp7 += m_A25 * V[9];
+ V[7] = (RHS7 - tmp7) / m_A24;
+ double tmp6 = 0.0;
+ tmp6 += m_A20 * V[8];
+ tmp6 += m_A21 * V[9];
+ V[6] = (RHS6 - tmp6) / m_A19;
+ double tmp5 = 0.0;
+ tmp5 += m_A15 * V[6];
+ tmp5 += m_A16 * V[8];
+ V[5] = (RHS5 - tmp5) / m_A14;
+ double tmp4 = 0.0;
+ tmp4 += m_A11 * V[7];
+ tmp4 += m_A12 * V[9];
+ V[4] = (RHS4 - tmp4) / m_A10;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[4];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[8];
+ tmp2 += m_A7 * V[9];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A4 * V[8];
+ V[1] = (RHS1 - tmp1) / m_A3;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[5];
+ tmp0 += m_A2 * V[6];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
+// brdrline
+static void nl_gcr_2753fc1815ce0cba_23_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A3 += go[3];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 -= go[4] * *cnV[4];
+ RHS1 -= go[5] * *cnV[5];
+ RHS1 -= go[6] * *cnV[6];
+ m_A4 += gt[7];
+ m_A4 += gt[8];
+ m_A4 += gt[9];
+ m_A4 += gt[10];
+ m_A5 += go[7];
+ m_A6 += go[8];
+ double RHS2 = Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 -= go[9] * *cnV[9];
+ RHS2 -= go[10] * *cnV[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A8 += gt[15];
+ m_A8 += gt[16];
+ m_A8 += gt[17];
+ m_A9 += go[11];
+ m_A7 += go[12];
+ double RHS3 = Idr[11];
+ RHS3 += Idr[12];
+ RHS3 += Idr[13];
+ RHS3 += Idr[14];
+ RHS3 += Idr[15];
+ RHS3 += Idr[16];
+ RHS3 += Idr[17];
+ RHS3 -= go[13] * *cnV[13];
+ RHS3 -= go[14] * *cnV[14];
+ RHS3 -= go[15] * *cnV[15];
+ RHS3 -= go[16] * *cnV[16];
+ RHS3 -= go[17] * *cnV[17];
+ m_A11 += gt[18];
+ m_A11 += gt[19];
+ m_A11 += gt[20];
+ m_A11 += gt[21];
+ m_A13 += go[18];
+ m_A12 += go[19];
+ m_A10 += go[20];
+ double RHS4 = Idr[18];
+ RHS4 += Idr[19];
+ RHS4 += Idr[20];
+ RHS4 += Idr[21];
+ RHS4 -= go[21] * *cnV[21];
+ m_A16 += gt[22];
+ m_A16 += gt[23];
+ m_A16 += gt[24];
+ m_A14 += go[22];
+ m_A15 += go[23];
+ double RHS5 = Idr[22];
+ RHS5 += Idr[23];
+ RHS5 += Idr[24];
+ RHS5 -= go[24] * *cnV[24];
+ m_A22 += gt[25];
+ m_A22 += gt[26];
+ m_A18 += go[25];
+ m_A20 += go[26];
+ double RHS6 = Idr[25];
+ RHS6 += Idr[26];
+ const double f0 = 1.0 / m_A0;
+ const double f0_3 = -f0 * m_A7;
+ m_A9 += m_A1 * f0_3;
+ RHS3 += f0_3 * RHS0;
+ const double f0_4 = -f0 * m_A10;
+ m_A11 += m_A1 * f0_4;
+ RHS4 += f0_4 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_5 = -f1 * m_A14;
+ m_A16 += m_A3 * f1_5;
+ RHS5 += f1_5 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_6 = -f2 * m_A18;
+ m_A19 += m_A5 * f2_6;
+ m_A22 += m_A6 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_6 = -f3 * m_A19;
+ m_A20 += m_A9 * f3_6;
+ RHS6 += f3_6 * RHS3;
+ const double f4 = 1.0 / m_A11;
+ const double f4_5 = -f4 * m_A15;
+ m_A16 += m_A12 * f4_5;
+ m_A17 += m_A13 * f4_5;
+ RHS5 += f4_5 * RHS4;
+ const double f4_6 = -f4 * m_A20;
+ m_A21 += m_A12 * f4_6;
+ m_A22 += m_A13 * f4_6;
+ RHS6 += f4_6 * RHS4;
+ const double f5 = 1.0 / m_A16;
+ const double f5_6 = -f5 * m_A21;
+ m_A22 += m_A17 * f5_6;
+ RHS6 += f5_6 * RHS5;
+ V[6] = RHS6 / m_A22;
+ double tmp5 = 0.0;
+ tmp5 += m_A17 * V[6];
+ V[5] = (RHS5 - tmp5) / m_A16;
+ double tmp4 = 0.0;
+ tmp4 += m_A12 * V[5];
+ tmp4 += m_A13 * V[6];
+ V[4] = (RHS4 - tmp4) / m_A11;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[4];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[3];
+ tmp2 += m_A6 * V[6];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[5];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[4];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// zac1b11142
static void nl_gcr_287a160e7c36b5b0_96_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -5687,8 +8018,8 @@ static void nl_gcr_2f84bc98d737730b_22_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
-// astrob
-static void nl_gcr_30fc51fe03b164cb_178_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+// brdrline
+static void nl_gcr_30923b54310ae144_8_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
{
@@ -5701,1173 +8032,63 @@ static void nl_gcr_30fc51fe03b164cb_178_double_double(double * __restrict V, con
double m_A5(0.0);
double m_A6(0.0);
double m_A7(0.0);
- double m_A8(0.0);
- double m_A9(0.0);
- double m_A10(0.0);
- double m_A11(0.0);
- double m_A12(0.0);
- double m_A13(0.0);
- double m_A14(0.0);
- double m_A15(0.0);
- double m_A16(0.0);
- double m_A17(0.0);
- double m_A18(0.0);
- double m_A19(0.0);
- double m_A20(0.0);
- double m_A21(0.0);
- double m_A22(0.0);
- double m_A23(0.0);
- double m_A24(0.0);
- double m_A25(0.0);
- double m_A26(0.0);
- double m_A27(0.0);
- double m_A28(0.0);
- double m_A29(0.0);
- double m_A30(0.0);
- double m_A31(0.0);
- double m_A32(0.0);
- double m_A33(0.0);
- double m_A34(0.0);
- double m_A35(0.0);
- double m_A36(0.0);
- double m_A37(0.0);
- double m_A38(0.0);
- double m_A39(0.0);
- double m_A40(0.0);
- double m_A41(0.0);
- double m_A42(0.0);
- double m_A43(0.0);
- double m_A44(0.0);
- double m_A45(0.0);
- double m_A46(0.0);
- double m_A47(0.0);
- double m_A48(0.0);
- double m_A49(0.0);
- double m_A50(0.0);
- double m_A51(0.0);
- double m_A52(0.0);
- double m_A53(0.0);
- double m_A54(0.0);
- double m_A55(0.0);
- double m_A56(0.0);
- double m_A57(0.0);
- double m_A58(0.0);
- double m_A59(0.0);
- double m_A60(0.0);
- double m_A61(0.0);
- double m_A62(0.0);
- double m_A63(0.0);
- double m_A64(0.0);
- double m_A65(0.0);
- double m_A66(0.0);
- double m_A67(0.0);
- double m_A68(0.0);
- double m_A69(0.0);
- double m_A70(0.0);
- double m_A71(0.0);
- double m_A72(0.0);
- double m_A73(0.0);
- double m_A74(0.0);
- double m_A75(0.0);
- double m_A76(0.0);
- double m_A77(0.0);
- double m_A78(0.0);
- double m_A79(0.0);
- double m_A80(0.0);
- double m_A81(0.0);
- double m_A82(0.0);
- double m_A83(0.0);
- double m_A84(0.0);
- double m_A85(0.0);
- double m_A86(0.0);
- double m_A87(0.0);
- double m_A88(0.0);
- double m_A89(0.0);
- double m_A90(0.0);
- double m_A91(0.0);
- double m_A92(0.0);
- double m_A93(0.0);
- double m_A94(0.0);
- double m_A95(0.0);
- double m_A96(0.0);
- double m_A97(0.0);
- double m_A98(0.0);
- double m_A99(0.0);
- double m_A100(0.0);
- double m_A101(0.0);
- double m_A102(0.0);
- double m_A103(0.0);
- double m_A104(0.0);
- double m_A105(0.0);
- double m_A106(0.0);
- double m_A107(0.0);
- double m_A108(0.0);
- double m_A109(0.0);
- double m_A110(0.0);
- double m_A111(0.0);
- double m_A112(0.0);
- double m_A113(0.0);
- double m_A114(0.0);
- double m_A115(0.0);
- double m_A116(0.0);
- double m_A117(0.0);
- double m_A118(0.0);
- double m_A119(0.0);
- double m_A120(0.0);
- double m_A121(0.0);
- double m_A122(0.0);
- double m_A123(0.0);
- double m_A124(0.0);
- double m_A125(0.0);
- double m_A126(0.0);
- double m_A127(0.0);
- double m_A128(0.0);
- double m_A129(0.0);
- double m_A130(0.0);
- double m_A131(0.0);
- double m_A132(0.0);
- double m_A133(0.0);
- double m_A134(0.0);
- double m_A135(0.0);
- double m_A136(0.0);
- double m_A137(0.0);
- double m_A138(0.0);
- double m_A139(0.0);
- double m_A140(0.0);
- double m_A141(0.0);
- double m_A142(0.0);
- double m_A143(0.0);
- double m_A144(0.0);
- double m_A145(0.0);
- double m_A146(0.0);
- double m_A147(0.0);
- double m_A148(0.0);
- double m_A149(0.0);
- double m_A150(0.0);
- double m_A151(0.0);
- double m_A152(0.0);
- double m_A153(0.0);
- double m_A154(0.0);
- double m_A155(0.0);
- double m_A156(0.0);
- double m_A157(0.0);
- double m_A158(0.0);
- double m_A159(0.0);
- double m_A160(0.0);
- double m_A161(0.0);
- double m_A162(0.0);
- double m_A163(0.0);
- double m_A164(0.0);
- double m_A165(0.0);
- double m_A166(0.0);
- double m_A167(0.0);
- double m_A168(0.0);
- double m_A169(0.0);
- double m_A170(0.0);
- double m_A171(0.0);
- double m_A172(0.0);
- double m_A173(0.0);
- double m_A174(0.0);
- double m_A175(0.0);
- double m_A176(0.0);
- double m_A177(0.0);
m_A0 += gt[0];
m_A0 += gt[1];
m_A0 += gt[2];
- m_A0 += gt[3];
- m_A0 += gt[4];
- m_A0 += gt[5];
- m_A0 += gt[6];
m_A1 += go[0];
double RHS0 = Idr[0];
RHS0 += Idr[1];
RHS0 += Idr[2];
- RHS0 += Idr[3];
- RHS0 += Idr[4];
- RHS0 += Idr[5];
- RHS0 += Idr[6];
RHS0 -= go[1] * *cnV[1];
RHS0 -= go[2] * *cnV[2];
- RHS0 -= go[3] * *cnV[3];
- RHS0 -= go[4] * *cnV[4];
- RHS0 -= go[5] * *cnV[5];
- RHS0 -= go[6] * *cnV[6];
- m_A2 += gt[7];
- m_A2 += gt[8];
- m_A2 += gt[9];
- m_A4 += go[7];
- m_A3 += go[8];
- double RHS1 = Idr[7];
- RHS1 += Idr[8];
- RHS1 += Idr[9];
- RHS1 -= go[9] * *cnV[9];
- m_A5 += gt[10];
- m_A5 += gt[11];
- m_A5 += gt[12];
- m_A5 += gt[13];
- m_A5 += gt[14];
- m_A5 += gt[15];
- m_A5 += gt[16];
- m_A6 += go[10];
- double RHS2 = Idr[10];
+ m_A3 += gt[3];
+ m_A3 += gt[4];
+ m_A3 += gt[5];
+ m_A3 += gt[6];
+ m_A4 += go[3];
+ m_A2 += go[4];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 -= go[5] * *cnV[5];
+ RHS1 -= go[6] * *cnV[6];
+ m_A7 += gt[7];
+ m_A7 += gt[8];
+ m_A7 += gt[9];
+ m_A7 += gt[10];
+ m_A7 += gt[11];
+ m_A7 += gt[12];
+ m_A7 += gt[13];
+ m_A5 += go[7];
+ m_A6 += go[8];
+ double RHS2 = Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
RHS2 += Idr[11];
RHS2 += Idr[12];
RHS2 += Idr[13];
- RHS2 += Idr[14];
- RHS2 += Idr[15];
- RHS2 += Idr[16];
+ RHS2 -= go[9] * *cnV[9];
+ RHS2 -= go[10] * *cnV[10];
RHS2 -= go[11] * *cnV[11];
RHS2 -= go[12] * *cnV[12];
RHS2 -= go[13] * *cnV[13];
- RHS2 -= go[14] * *cnV[14];
- RHS2 -= go[15] * *cnV[15];
- RHS2 -= go[16] * *cnV[16];
- m_A7 += gt[17];
- m_A7 += gt[18];
- m_A7 += gt[19];
- m_A7 += gt[20];
- m_A9 += go[17];
- m_A10 += go[18];
- m_A8 += go[19];
- double RHS3 = Idr[17];
- RHS3 += Idr[18];
- RHS3 += Idr[19];
- RHS3 += Idr[20];
- RHS3 -= go[20] * *cnV[20];
- m_A11 += gt[21];
- m_A11 += gt[22];
- m_A11 += gt[23];
- m_A11 += gt[24];
- m_A12 += go[21];
- m_A12 += go[22];
- m_A13 += go[23];
- double RHS4 = Idr[21];
- RHS4 += Idr[22];
- RHS4 += Idr[23];
- RHS4 += Idr[24];
- RHS4 -= go[24] * *cnV[24];
- m_A14 += gt[25];
- m_A14 += gt[26];
- m_A15 += go[25];
- m_A16 += go[26];
- double RHS5 = Idr[25];
- RHS5 += Idr[26];
- m_A17 += gt[27];
- m_A17 += gt[28];
- m_A17 += gt[29];
- m_A18 += go[27];
- double RHS6 = Idr[27];
- RHS6 += Idr[28];
- RHS6 += Idr[29];
- RHS6 -= go[28] * *cnV[28];
- RHS6 -= go[29] * *cnV[29];
- m_A19 += gt[30];
- m_A19 += gt[31];
- m_A19 += gt[32];
- m_A19 += gt[33];
- m_A19 += gt[34];
- m_A19 += gt[35];
- m_A20 += go[30];
- m_A20 += go[31];
- m_A22 += go[32];
- m_A22 += go[33];
- m_A21 += go[34];
- double RHS7 = Idr[30];
- RHS7 += Idr[31];
- RHS7 += Idr[32];
- RHS7 += Idr[33];
- RHS7 += Idr[34];
- RHS7 += Idr[35];
- RHS7 -= go[35] * *cnV[35];
- m_A23 += gt[36];
- m_A23 += gt[37];
- m_A23 += gt[38];
- m_A23 += gt[39];
- m_A23 += gt[40];
- m_A23 += gt[41];
- m_A24 += go[36];
- m_A25 += go[37];
- double RHS8 = Idr[36];
- RHS8 += Idr[37];
- RHS8 += Idr[38];
- RHS8 += Idr[39];
- RHS8 += Idr[40];
- RHS8 += Idr[41];
- RHS8 -= go[38] * *cnV[38];
- RHS8 -= go[39] * *cnV[39];
- RHS8 -= go[40] * *cnV[40];
- RHS8 -= go[41] * *cnV[41];
- m_A26 += gt[42];
- m_A26 += gt[43];
- m_A26 += gt[44];
- m_A27 += go[42];
- double RHS9 = Idr[42];
- RHS9 += Idr[43];
- RHS9 += Idr[44];
- RHS9 -= go[43] * *cnV[43];
- RHS9 -= go[44] * *cnV[44];
- m_A28 += gt[45];
- m_A28 += gt[46];
- m_A28 += gt[47];
- m_A29 += go[45];
- double RHS10 = Idr[45];
- RHS10 += Idr[46];
- RHS10 += Idr[47];
- RHS10 -= go[46] * *cnV[46];
- RHS10 -= go[47] * *cnV[47];
- m_A30 += gt[48];
- m_A30 += gt[49];
- m_A30 += gt[50];
- m_A31 += go[48];
- double RHS11 = Idr[48];
- RHS11 += Idr[49];
- RHS11 += Idr[50];
- RHS11 -= go[49] * *cnV[49];
- RHS11 -= go[50] * *cnV[50];
- m_A32 += gt[51];
- m_A32 += gt[52];
- m_A32 += gt[53];
- m_A33 += go[51];
- double RHS12 = Idr[51];
- RHS12 += Idr[52];
- RHS12 += Idr[53];
- RHS12 -= go[52] * *cnV[52];
- RHS12 -= go[53] * *cnV[53];
- m_A34 += gt[54];
- m_A34 += gt[55];
- m_A34 += gt[56];
- m_A35 += go[54];
- double RHS13 = Idr[54];
- RHS13 += Idr[55];
- RHS13 += Idr[56];
- RHS13 -= go[55] * *cnV[55];
- RHS13 -= go[56] * *cnV[56];
- m_A36 += gt[57];
- m_A36 += gt[58];
- m_A37 += go[57];
- double RHS14 = Idr[57];
- RHS14 += Idr[58];
- RHS14 -= go[58] * *cnV[58];
- m_A38 += gt[59];
- m_A38 += gt[60];
- m_A38 += gt[61];
- m_A39 += go[59];
- double RHS15 = Idr[59];
- RHS15 += Idr[60];
- RHS15 += Idr[61];
- RHS15 -= go[60] * *cnV[60];
- RHS15 -= go[61] * *cnV[61];
- m_A40 += gt[62];
- m_A40 += gt[63];
- m_A41 += go[62];
- double RHS16 = Idr[62];
- RHS16 += Idr[63];
- RHS16 -= go[63] * *cnV[63];
- m_A42 += gt[64];
- m_A42 += gt[65];
- m_A43 += go[64];
- double RHS17 = Idr[64];
- RHS17 += Idr[65];
- RHS17 -= go[65] * *cnV[65];
- m_A44 += gt[66];
- m_A44 += gt[67];
- m_A45 += go[66];
- double RHS18 = Idr[66];
- RHS18 += Idr[67];
- RHS18 -= go[67] * *cnV[67];
- m_A46 += gt[68];
- m_A46 += gt[69];
- m_A47 += go[68];
- double RHS19 = Idr[68];
- RHS19 += Idr[69];
- RHS19 -= go[69] * *cnV[69];
- m_A48 += gt[70];
- m_A48 += gt[71];
- m_A49 += go[70];
- double RHS20 = Idr[70];
- RHS20 += Idr[71];
- RHS20 -= go[71] * *cnV[71];
- m_A50 += gt[72];
- m_A50 += gt[73];
- m_A51 += go[72];
- double RHS21 = Idr[72];
- RHS21 += Idr[73];
- RHS21 -= go[73] * *cnV[73];
- m_A52 += gt[74];
- m_A52 += gt[75];
- m_A52 += gt[76];
- m_A52 += gt[77];
- m_A52 += gt[78];
- m_A53 += go[74];
- m_A55 += go[75];
- m_A54 += go[76];
- double RHS22 = Idr[74];
- RHS22 += Idr[75];
- RHS22 += Idr[76];
- RHS22 += Idr[77];
- RHS22 += Idr[78];
- RHS22 -= go[77] * *cnV[77];
- RHS22 -= go[78] * *cnV[78];
- m_A56 += gt[79];
- m_A56 += gt[80];
- m_A58 += go[79];
- m_A57 += go[80];
- double RHS23 = Idr[79];
- RHS23 += Idr[80];
- m_A59 += gt[81];
- m_A59 += gt[82];
- m_A60 += go[81];
- double RHS24 = Idr[81];
- RHS24 += Idr[82];
- RHS24 -= go[82] * *cnV[82];
- m_A61 += gt[83];
- m_A61 += gt[84];
- m_A62 += go[83];
- double RHS25 = Idr[83];
- RHS25 += Idr[84];
- RHS25 -= go[84] * *cnV[84];
- m_A63 += gt[85];
- m_A63 += gt[86];
- m_A63 += gt[87];
- m_A64 += go[85];
- double RHS26 = Idr[85];
- RHS26 += Idr[86];
- RHS26 += Idr[87];
- RHS26 -= go[86] * *cnV[86];
- RHS26 -= go[87] * *cnV[87];
- m_A68 += gt[88];
- m_A68 += gt[89];
- m_A68 += gt[90];
- m_A68 += gt[91];
- m_A68 += gt[92];
- m_A65 += go[88];
- m_A67 += go[89];
- m_A66 += go[90];
- double RHS27 = Idr[88];
- RHS27 += Idr[89];
- RHS27 += Idr[90];
- RHS27 += Idr[91];
- RHS27 += Idr[92];
- RHS27 -= go[91] * *cnV[91];
- RHS27 -= go[92] * *cnV[92];
- m_A71 += gt[93];
- m_A71 += gt[94];
- m_A71 += gt[95];
- m_A72 += go[93];
- double RHS28 = Idr[93];
- RHS28 += Idr[94];
- RHS28 += Idr[95];
- RHS28 -= go[94] * *cnV[94];
- RHS28 -= go[95] * *cnV[95];
- m_A73 += gt[96];
- m_A73 += gt[97];
- m_A73 += gt[98];
- m_A74 += go[96];
- double RHS29 = Idr[96];
- RHS29 += Idr[97];
- RHS29 += Idr[98];
- RHS29 -= go[97] * *cnV[97];
- RHS29 -= go[98] * *cnV[98];
- m_A75 += gt[99];
- m_A75 += gt[100];
- m_A75 += gt[101];
- m_A76 += go[99];
- double RHS30 = Idr[99];
- RHS30 += Idr[100];
- RHS30 += Idr[101];
- RHS30 -= go[100] * *cnV[100];
- RHS30 -= go[101] * *cnV[101];
- m_A77 += gt[102];
- m_A77 += gt[103];
- m_A79 += go[102];
- m_A78 += go[103];
- double RHS31 = Idr[102];
- RHS31 += Idr[103];
- m_A80 += gt[104];
- m_A80 += gt[105];
- m_A82 += go[104];
- m_A81 += go[105];
- double RHS32 = Idr[104];
- RHS32 += Idr[105];
- m_A85 += gt[106];
- m_A85 += gt[107];
- m_A85 += gt[108];
- m_A85 += gt[109];
- m_A84 += go[106];
- m_A83 += go[107];
- double RHS33 = Idr[106];
- RHS33 += Idr[107];
- RHS33 += Idr[108];
- RHS33 += Idr[109];
- RHS33 -= go[108] * *cnV[108];
- RHS33 -= go[109] * *cnV[109];
- m_A93 += gt[110];
- m_A93 += gt[111];
- m_A93 += gt[112];
- m_A93 += gt[113];
- m_A93 += gt[114];
- m_A93 += gt[115];
- m_A92 += go[110];
- m_A91 += go[111];
- m_A90 += go[112];
- m_A89 += go[113];
- m_A88 += go[114];
- m_A87 += go[115];
- double RHS34 = Idr[110];
- RHS34 += Idr[111];
- RHS34 += Idr[112];
- RHS34 += Idr[113];
- RHS34 += Idr[114];
- RHS34 += Idr[115];
- m_A97 += gt[116];
- m_A97 += gt[117];
- m_A97 += gt[118];
- m_A98 += go[116];
- m_A95 += go[117];
- double RHS35 = Idr[116];
- RHS35 += Idr[117];
- RHS35 += Idr[118];
- RHS35 -= go[118] * *cnV[118];
- m_A102 += gt[119];
- m_A102 += gt[120];
- m_A102 += gt[121];
- m_A102 += gt[122];
- m_A102 += gt[123];
- m_A102 += gt[124];
- m_A102 += gt[125];
- m_A100 += go[119];
- m_A99 += go[120];
- m_A99 += go[121];
- m_A103 += go[122];
- m_A103 += go[123];
- double RHS36 = Idr[119];
- RHS36 += Idr[120];
- RHS36 += Idr[121];
- RHS36 += Idr[122];
- RHS36 += Idr[123];
- RHS36 += Idr[124];
- RHS36 += Idr[125];
- RHS36 -= go[124] * *cnV[124];
- RHS36 -= go[125] * *cnV[125];
- m_A105 += gt[126];
- m_A105 += gt[127];
- m_A105 += gt[128];
- m_A105 += gt[129];
- m_A105 += gt[130];
- m_A105 += gt[131];
- m_A105 += gt[132];
- m_A106 += go[126];
- m_A104 += go[127];
- double RHS37 = Idr[126];
- RHS37 += Idr[127];
- RHS37 += Idr[128];
- RHS37 += Idr[129];
- RHS37 += Idr[130];
- RHS37 += Idr[131];
- RHS37 += Idr[132];
- RHS37 -= go[128] * *cnV[128];
- RHS37 -= go[129] * *cnV[129];
- RHS37 -= go[130] * *cnV[130];
- RHS37 -= go[131] * *cnV[131];
- RHS37 -= go[132] * *cnV[132];
- m_A109 += gt[133];
- m_A109 += gt[134];
- m_A108 += go[133];
- m_A110 += go[134];
- double RHS38 = Idr[133];
- RHS38 += Idr[134];
- m_A117 += gt[135];
- m_A117 += gt[136];
- m_A117 += gt[137];
- m_A117 += gt[138];
- m_A117 += gt[139];
- m_A117 += gt[140];
- m_A116 += go[135];
- m_A115 += go[136];
- m_A114 += go[137];
- m_A113 += go[138];
- m_A112 += go[139];
- m_A111 += go[140];
- double RHS39 = Idr[135];
- RHS39 += Idr[136];
- RHS39 += Idr[137];
- RHS39 += Idr[138];
- RHS39 += Idr[139];
- RHS39 += Idr[140];
- m_A120 += gt[141];
- m_A120 += gt[142];
- m_A119 += go[141];
- m_A121 += go[142];
- double RHS40 = Idr[141];
- RHS40 += Idr[142];
- m_A126 += gt[143];
- m_A126 += gt[144];
- m_A126 += gt[145];
- m_A126 += gt[146];
- m_A126 += gt[147];
- m_A125 += go[143];
- m_A124 += go[144];
- m_A123 += go[145];
- m_A122 += go[146];
- m_A127 += go[147];
- double RHS41 = Idr[143];
- RHS41 += Idr[144];
- RHS41 += Idr[145];
- RHS41 += Idr[146];
- RHS41 += Idr[147];
- m_A131 += gt[148];
- m_A131 += gt[149];
- m_A131 += gt[150];
- m_A131 += gt[151];
- m_A131 += gt[152];
- m_A130 += go[148];
- m_A129 += go[149];
- m_A128 += go[150];
- double RHS42 = Idr[148];
- RHS42 += Idr[149];
- RHS42 += Idr[150];
- RHS42 += Idr[151];
- RHS42 += Idr[152];
- RHS42 -= go[151] * *cnV[151];
- RHS42 -= go[152] * *cnV[152];
- m_A137 += gt[153];
- m_A137 += gt[154];
- m_A137 += gt[155];
- m_A137 += gt[156];
- m_A137 += gt[157];
- m_A137 += gt[158];
- m_A135 += go[153];
- m_A134 += go[154];
- m_A139 += go[155];
- m_A133 += go[156];
- m_A133 += go[157];
- double RHS43 = Idr[153];
- RHS43 += Idr[154];
- RHS43 += Idr[155];
- RHS43 += Idr[156];
- RHS43 += Idr[157];
- RHS43 += Idr[158];
- RHS43 -= go[158] * *cnV[158];
- m_A148 += gt[159];
- m_A148 += gt[160];
- m_A148 += gt[161];
- m_A148 += gt[162];
- m_A148 += gt[163];
- m_A148 += gt[164];
- m_A148 += gt[165];
- m_A142 += go[159];
- m_A144 += go[160];
- m_A146 += go[161];
- m_A143 += go[162];
- m_A141 += go[163];
- double RHS44 = Idr[159];
- RHS44 += Idr[160];
- RHS44 += Idr[161];
- RHS44 += Idr[162];
- RHS44 += Idr[163];
- RHS44 += Idr[164];
- RHS44 += Idr[165];
- RHS44 -= go[164] * *cnV[164];
- RHS44 -= go[165] * *cnV[165];
- m_A157 += gt[166];
- m_A157 += gt[167];
- m_A157 += gt[168];
- m_A157 += gt[169];
- m_A157 += gt[170];
- m_A157 += gt[171];
- m_A157 += gt[172];
- m_A157 += gt[173];
- m_A157 += gt[174];
- m_A155 += go[166];
- m_A153 += go[167];
- m_A151 += go[168];
- m_A154 += go[169];
- m_A154 += go[170];
- m_A152 += go[171];
- m_A152 += go[172];
- double RHS45 = Idr[166];
- RHS45 += Idr[167];
- RHS45 += Idr[168];
- RHS45 += Idr[169];
- RHS45 += Idr[170];
- RHS45 += Idr[171];
- RHS45 += Idr[172];
- RHS45 += Idr[173];
- RHS45 += Idr[174];
- RHS45 -= go[173] * *cnV[173];
- RHS45 -= go[174] * *cnV[174];
- m_A160 += gt[175];
- m_A160 += gt[176];
- m_A159 += go[175];
- m_A161 += go[176];
- double RHS46 = Idr[175];
- RHS46 += Idr[176];
- m_A177 += gt[177];
- m_A177 += gt[178];
- m_A177 += gt[179];
- m_A177 += gt[180];
- m_A177 += gt[181];
- m_A177 += gt[182];
- m_A177 += gt[183];
- m_A177 += gt[184];
- m_A176 += go[177];
- m_A164 += go[178];
- m_A163 += go[179];
- m_A165 += go[180];
- m_A170 += go[181];
- m_A168 += go[182];
- m_A171 += go[183];
- m_A162 += go[184];
- double RHS47 = Idr[177];
- RHS47 += Idr[178];
- RHS47 += Idr[179];
- RHS47 += Idr[180];
- RHS47 += Idr[181];
- RHS47 += Idr[182];
- RHS47 += Idr[183];
- RHS47 += Idr[184];
const double f0 = 1.0 / m_A0;
- const double f0_27 = -f0 * m_A65;
- m_A66 += m_A1 * f0_27;
- RHS27 += f0_27 * RHS0;
- const double f1 = 1.0 / m_A2;
- const double f1_27 = -f1 * m_A66;
- m_A68 += m_A3 * f1_27;
- m_A70 += m_A4 * f1_27;
- RHS27 += f1_27 * RHS1;
- const double f1_44 = -f1 * m_A141;
- m_A145 += m_A3 * f1_44;
- m_A148 += m_A4 * f1_44;
- RHS44 += f1_44 * RHS1;
- const double f2 = 1.0 / m_A5;
- const double f2_44 = -f2 * m_A142;
- m_A146 += m_A6 * f2_44;
- RHS44 += f2_44 * RHS2;
- const double f3 = 1.0 / m_A7;
- const double f3_27 = -f3 * m_A67;
- m_A68 += m_A8 * f3_27;
- m_A69 += m_A9 * f3_27;
- m_A70 += m_A10 * f3_27;
- RHS27 += f3_27 * RHS3;
- const double f3_35 = -f3 * m_A95;
- m_A96 += m_A8 * f3_35;
- m_A97 += m_A9 * f3_35;
- m_A98 += m_A10 * f3_35;
- RHS35 += f3_35 * RHS3;
- const double f3_44 = -f3 * m_A143;
- m_A145 += m_A8 * f3_44;
- m_A146 += m_A9 * f3_44;
- m_A148 += m_A10 * f3_44;
- RHS44 += f3_44 * RHS3;
- const double f4 = 1.0 / m_A11;
- const double f4_36 = -f4 * m_A99;
- m_A102 += m_A12 * f4_36;
- m_A103 += m_A13 * f4_36;
- RHS36 += f4_36 * RHS4;
- const double f4_45 = -f4 * m_A151;
- m_A154 += m_A12 * f4_45;
- m_A157 += m_A13 * f4_45;
- RHS45 += f4_45 * RHS4;
- const double f5 = 1.0 / m_A14;
- const double f5_33 = -f5 * m_A83;
- m_A85 += m_A15 * f5_33;
- m_A86 += m_A16 * f5_33;
- RHS33 += f5_33 * RHS5;
- const double f5_36 = -f5 * m_A100;
- m_A101 += m_A15 * f5_36;
- m_A102 += m_A16 * f5_36;
- RHS36 += f5_36 * RHS5;
- const double f6 = 1.0 / m_A17;
- const double f6_33 = -f6 * m_A84;
- m_A85 += m_A18 * f6_33;
- RHS33 += f6_33 * RHS6;
- const double f7 = 1.0 / m_A19;
- const double f7_43 = -f7 * m_A133;
- m_A137 += m_A20 * f7_43;
- m_A138 += m_A21 * f7_43;
- m_A139 += m_A22 * f7_43;
- RHS43 += f7_43 * RHS7;
- const double f7_44 = -f7 * m_A144;
- m_A147 += m_A20 * f7_44;
- m_A148 += m_A21 * f7_44;
- m_A149 += m_A22 * f7_44;
- RHS44 += f7_44 * RHS7;
- const double f7_45 = -f7 * m_A152;
- m_A155 += m_A20 * f7_45;
- m_A156 += m_A21 * f7_45;
- m_A157 += m_A22 * f7_45;
- RHS45 += f7_45 * RHS7;
- const double f8 = 1.0 / m_A23;
- const double f8_37 = -f8 * m_A104;
- m_A106 += m_A24 * f8_37;
- m_A107 += m_A25 * f8_37;
- RHS37 += f8_37 * RHS8;
- const double f8_43 = -f8 * m_A134;
- m_A137 += m_A24 * f8_43;
- m_A139 += m_A25 * f8_43;
- RHS43 += f8_43 * RHS8;
- const double f8_45 = -f8 * m_A153;
- m_A155 += m_A24 * f8_45;
- m_A157 += m_A25 * f8_45;
- RHS45 += f8_45 * RHS8;
- const double f9 = 1.0 / m_A26;
- const double f9_34 = -f9 * m_A87;
- m_A93 += m_A27 * f9_34;
- RHS34 += f9_34 * RHS9;
- const double f10 = 1.0 / m_A28;
- const double f10_34 = -f10 * m_A88;
- m_A93 += m_A29 * f10_34;
- RHS34 += f10_34 * RHS10;
- const double f11 = 1.0 / m_A30;
- const double f11_34 = -f11 * m_A89;
- m_A93 += m_A31 * f11_34;
- RHS34 += f11_34 * RHS11;
- const double f12 = 1.0 / m_A32;
- const double f12_34 = -f12 * m_A90;
- m_A93 += m_A33 * f12_34;
- RHS34 += f12_34 * RHS12;
- const double f13 = 1.0 / m_A34;
- const double f13_34 = -f13 * m_A91;
- m_A93 += m_A35 * f13_34;
- RHS34 += f13_34 * RHS13;
- const double f14 = 1.0 / m_A36;
- const double f14_42 = -f14 * m_A128;
- m_A131 += m_A37 * f14_42;
- RHS42 += f14_42 * RHS14;
- const double f15 = 1.0 / m_A38;
- const double f15_39 = -f15 * m_A111;
- m_A117 += m_A39 * f15_39;
- RHS39 += f15_39 * RHS15;
- const double f16 = 1.0 / m_A40;
- const double f16_41 = -f16 * m_A122;
- m_A126 += m_A41 * f16_41;
- RHS41 += f16_41 * RHS16;
- const double f17 = 1.0 / m_A42;
- const double f17_38 = -f17 * m_A108;
- m_A109 += m_A43 * f17_38;
- RHS38 += f17_38 * RHS17;
- const double f18 = 1.0 / m_A44;
- const double f18_40 = -f18 * m_A119;
- m_A120 += m_A45 * f18_40;
- RHS40 += f18_40 * RHS18;
- const double f19 = 1.0 / m_A46;
- const double f19_41 = -f19 * m_A123;
- m_A126 += m_A47 * f19_41;
- RHS41 += f19_41 * RHS19;
- const double f20 = 1.0 / m_A48;
- const double f20_41 = -f20 * m_A124;
- m_A126 += m_A49 * f20_41;
- RHS41 += f20_41 * RHS20;
- const double f21 = 1.0 / m_A50;
- const double f21_41 = -f21 * m_A125;
- m_A126 += m_A51 * f21_41;
- RHS41 += f21_41 * RHS21;
- const double f22 = 1.0 / m_A52;
- const double f22_43 = -f22 * m_A135;
- m_A136 += m_A53 * f22_43;
- m_A137 += m_A54 * f22_43;
- m_A140 += m_A55 * f22_43;
- RHS43 += f22_43 * RHS22;
- const double f22_47 = -f22 * m_A162;
- m_A167 += m_A53 * f22_47;
- m_A173 += m_A54 * f22_47;
- m_A177 += m_A55 * f22_47;
- RHS47 += f22_47 * RHS22;
- const double f23 = 1.0 / m_A56;
- const double f23_34 = -f23 * m_A92;
- m_A93 += m_A57 * f23_34;
- m_A94 += m_A58 * f23_34;
- RHS34 += f23_34 * RHS23;
- const double f23_47 = -f23 * m_A163;
- m_A166 += m_A57 * f23_47;
- m_A177 += m_A58 * f23_47;
- RHS47 += f23_47 * RHS23;
- const double f24 = 1.0 / m_A59;
- const double f24_46 = -f24 * m_A159;
- m_A160 += m_A60 * f24_46;
- RHS46 += f24_46 * RHS24;
- const double f25 = 1.0 / m_A61;
- const double f25_42 = -f25 * m_A129;
- m_A131 += m_A62 * f25_42;
- RHS42 += f25_42 * RHS25;
- const double f26 = 1.0 / m_A63;
- const double f26_39 = -f26 * m_A112;
- m_A117 += m_A64 * f26_39;
- RHS39 += f26_39 * RHS26;
- const double f27 = 1.0 / m_A68;
- const double f27_35 = -f27 * m_A96;
- m_A97 += m_A69 * f27_35;
- m_A98 += m_A70 * f27_35;
- RHS35 += f27_35 * RHS27;
- const double f27_44 = -f27 * m_A145;
- m_A146 += m_A69 * f27_44;
- m_A148 += m_A70 * f27_44;
- RHS44 += f27_44 * RHS27;
- const double f28 = 1.0 / m_A71;
- const double f28_39 = -f28 * m_A113;
- m_A117 += m_A72 * f28_39;
- RHS39 += f28_39 * RHS28;
- const double f29 = 1.0 / m_A73;
- const double f29_39 = -f29 * m_A114;
- m_A117 += m_A74 * f29_39;
- RHS39 += f29_39 * RHS29;
- const double f30 = 1.0 / m_A75;
- const double f30_39 = -f30 * m_A115;
- m_A117 += m_A76 * f30_39;
- RHS39 += f30_39 * RHS30;
- const double f31 = 1.0 / m_A77;
- const double f31_39 = -f31 * m_A116;
- m_A117 += m_A78 * f31_39;
- m_A118 += m_A79 * f31_39;
- RHS39 += f31_39 * RHS31;
- const double f31_47 = -f31 * m_A164;
- m_A169 += m_A78 * f31_47;
- m_A177 += m_A79 * f31_47;
- RHS47 += f31_47 * RHS31;
- const double f32 = 1.0 / m_A80;
- const double f32_42 = -f32 * m_A130;
- m_A131 += m_A81 * f32_42;
- m_A132 += m_A82 * f32_42;
- RHS42 += f32_42 * RHS32;
- const double f32_47 = -f32 * m_A165;
- m_A172 += m_A81 * f32_47;
- m_A177 += m_A82 * f32_47;
- RHS47 += f32_47 * RHS32;
- const double f33 = 1.0 / m_A85;
- const double f33_36 = -f33 * m_A101;
- m_A102 += m_A86 * f33_36;
- RHS36 += f33_36 * RHS33;
- const double f34 = 1.0 / m_A93;
- const double f34_47 = -f34 * m_A166;
- m_A177 += m_A94 * f34_47;
- RHS47 += f34_47 * RHS34;
- const double f35 = 1.0 / m_A97;
- const double f35_44 = -f35 * m_A146;
- m_A148 += m_A98 * f35_44;
- RHS44 += f35_44 * RHS35;
- const double f36 = 1.0 / m_A102;
- const double f36_45 = -f36 * m_A154;
- m_A157 += m_A103 * f36_45;
- RHS45 += f36_45 * RHS36;
- const double f37 = 1.0 / m_A105;
- const double f37_43 = -f37 * m_A136;
- m_A137 += m_A106 * f37_43;
- m_A139 += m_A107 * f37_43;
- RHS43 += f37_43 * RHS37;
- const double f37_47 = -f37 * m_A167;
- m_A173 += m_A106 * f37_47;
- m_A175 += m_A107 * f37_47;
- RHS47 += f37_47 * RHS37;
- const double f38 = 1.0 / m_A109;
- const double f38_47 = -f38 * m_A168;
- m_A177 += m_A110 * f38_47;
- RHS47 += f38_47 * RHS38;
- const double f39 = 1.0 / m_A117;
- const double f39_47 = -f39 * m_A169;
- m_A177 += m_A118 * f39_47;
- RHS47 += f39_47 * RHS39;
- const double f40 = 1.0 / m_A120;
- const double f40_47 = -f40 * m_A170;
- m_A177 += m_A121 * f40_47;
- RHS47 += f40_47 * RHS40;
- const double f41 = 1.0 / m_A126;
- const double f41_47 = -f41 * m_A171;
- m_A177 += m_A127 * f41_47;
- RHS47 += f41_47 * RHS41;
- const double f42 = 1.0 / m_A131;
- const double f42_47 = -f42 * m_A172;
- m_A177 += m_A132 * f42_47;
- RHS47 += f42_47 * RHS42;
- const double f43 = 1.0 / m_A137;
- const double f43_44 = -f43 * m_A147;
- m_A148 += m_A138 * f43_44;
- m_A149 += m_A139 * f43_44;
- m_A150 += m_A140 * f43_44;
- RHS44 += f43_44 * RHS43;
- const double f43_45 = -f43 * m_A155;
- m_A156 += m_A138 * f43_45;
- m_A157 += m_A139 * f43_45;
- m_A158 += m_A140 * f43_45;
- RHS45 += f43_45 * RHS43;
- const double f43_47 = -f43 * m_A173;
- m_A174 += m_A138 * f43_47;
- m_A175 += m_A139 * f43_47;
- m_A177 += m_A140 * f43_47;
- RHS47 += f43_47 * RHS43;
- const double f44 = 1.0 / m_A148;
- const double f44_45 = -f44 * m_A156;
- m_A157 += m_A149 * f44_45;
- m_A158 += m_A150 * f44_45;
- RHS45 += f44_45 * RHS44;
- const double f44_47 = -f44 * m_A174;
- m_A175 += m_A149 * f44_47;
- m_A177 += m_A150 * f44_47;
- RHS47 += f44_47 * RHS44;
- const double f45 = 1.0 / m_A157;
- const double f45_47 = -f45 * m_A175;
- m_A177 += m_A158 * f45_47;
- RHS47 += f45_47 * RHS45;
- const double f46 = 1.0 / m_A160;
- const double f46_47 = -f46 * m_A176;
- m_A177 += m_A161 * f46_47;
- RHS47 += f46_47 * RHS46;
- V[47] = RHS47 / m_A177;
- double tmp46 = 0.0;
- tmp46 += m_A161 * V[47];
- V[46] = (RHS46 - tmp46) / m_A160;
- double tmp45 = 0.0;
- tmp45 += m_A158 * V[47];
- V[45] = (RHS45 - tmp45) / m_A157;
- double tmp44 = 0.0;
- tmp44 += m_A149 * V[45];
- tmp44 += m_A150 * V[47];
- V[44] = (RHS44 - tmp44) / m_A148;
- double tmp43 = 0.0;
- tmp43 += m_A138 * V[44];
- tmp43 += m_A139 * V[45];
- tmp43 += m_A140 * V[47];
- V[43] = (RHS43 - tmp43) / m_A137;
- double tmp42 = 0.0;
- tmp42 += m_A132 * V[47];
- V[42] = (RHS42 - tmp42) / m_A131;
- double tmp41 = 0.0;
- tmp41 += m_A127 * V[47];
- V[41] = (RHS41 - tmp41) / m_A126;
- double tmp40 = 0.0;
- tmp40 += m_A121 * V[47];
- V[40] = (RHS40 - tmp40) / m_A120;
- double tmp39 = 0.0;
- tmp39 += m_A118 * V[47];
- V[39] = (RHS39 - tmp39) / m_A117;
- double tmp38 = 0.0;
- tmp38 += m_A110 * V[47];
- V[38] = (RHS38 - tmp38) / m_A109;
- double tmp37 = 0.0;
- tmp37 += m_A106 * V[43];
- tmp37 += m_A107 * V[45];
- V[37] = (RHS37 - tmp37) / m_A105;
- double tmp36 = 0.0;
- tmp36 += m_A103 * V[45];
- V[36] = (RHS36 - tmp36) / m_A102;
- double tmp35 = 0.0;
- tmp35 += m_A98 * V[44];
- V[35] = (RHS35 - tmp35) / m_A97;
- double tmp34 = 0.0;
- tmp34 += m_A94 * V[47];
- V[34] = (RHS34 - tmp34) / m_A93;
- double tmp33 = 0.0;
- tmp33 += m_A86 * V[36];
- V[33] = (RHS33 - tmp33) / m_A85;
- double tmp32 = 0.0;
- tmp32 += m_A81 * V[42];
- tmp32 += m_A82 * V[47];
- V[32] = (RHS32 - tmp32) / m_A80;
- double tmp31 = 0.0;
- tmp31 += m_A78 * V[39];
- tmp31 += m_A79 * V[47];
- V[31] = (RHS31 - tmp31) / m_A77;
- double tmp30 = 0.0;
- tmp30 += m_A76 * V[39];
- V[30] = (RHS30 - tmp30) / m_A75;
- double tmp29 = 0.0;
- tmp29 += m_A74 * V[39];
- V[29] = (RHS29 - tmp29) / m_A73;
- double tmp28 = 0.0;
- tmp28 += m_A72 * V[39];
- V[28] = (RHS28 - tmp28) / m_A71;
- double tmp27 = 0.0;
- tmp27 += m_A69 * V[35];
- tmp27 += m_A70 * V[44];
- V[27] = (RHS27 - tmp27) / m_A68;
- double tmp26 = 0.0;
- tmp26 += m_A64 * V[39];
- V[26] = (RHS26 - tmp26) / m_A63;
- double tmp25 = 0.0;
- tmp25 += m_A62 * V[42];
- V[25] = (RHS25 - tmp25) / m_A61;
- double tmp24 = 0.0;
- tmp24 += m_A60 * V[46];
- V[24] = (RHS24 - tmp24) / m_A59;
- double tmp23 = 0.0;
- tmp23 += m_A57 * V[34];
- tmp23 += m_A58 * V[47];
- V[23] = (RHS23 - tmp23) / m_A56;
- double tmp22 = 0.0;
- tmp22 += m_A53 * V[37];
- tmp22 += m_A54 * V[43];
- tmp22 += m_A55 * V[47];
- V[22] = (RHS22 - tmp22) / m_A52;
- double tmp21 = 0.0;
- tmp21 += m_A51 * V[41];
- V[21] = (RHS21 - tmp21) / m_A50;
- double tmp20 = 0.0;
- tmp20 += m_A49 * V[41];
- V[20] = (RHS20 - tmp20) / m_A48;
- double tmp19 = 0.0;
- tmp19 += m_A47 * V[41];
- V[19] = (RHS19 - tmp19) / m_A46;
- double tmp18 = 0.0;
- tmp18 += m_A45 * V[40];
- V[18] = (RHS18 - tmp18) / m_A44;
- double tmp17 = 0.0;
- tmp17 += m_A43 * V[38];
- V[17] = (RHS17 - tmp17) / m_A42;
- double tmp16 = 0.0;
- tmp16 += m_A41 * V[41];
- V[16] = (RHS16 - tmp16) / m_A40;
- double tmp15 = 0.0;
- tmp15 += m_A39 * V[39];
- V[15] = (RHS15 - tmp15) / m_A38;
- double tmp14 = 0.0;
- tmp14 += m_A37 * V[42];
- V[14] = (RHS14 - tmp14) / m_A36;
- double tmp13 = 0.0;
- tmp13 += m_A35 * V[34];
- V[13] = (RHS13 - tmp13) / m_A34;
- double tmp12 = 0.0;
- tmp12 += m_A33 * V[34];
- V[12] = (RHS12 - tmp12) / m_A32;
- double tmp11 = 0.0;
- tmp11 += m_A31 * V[34];
- V[11] = (RHS11 - tmp11) / m_A30;
- double tmp10 = 0.0;
- tmp10 += m_A29 * V[34];
- V[10] = (RHS10 - tmp10) / m_A28;
- double tmp9 = 0.0;
- tmp9 += m_A27 * V[34];
- V[9] = (RHS9 - tmp9) / m_A26;
- double tmp8 = 0.0;
- tmp8 += m_A24 * V[43];
- tmp8 += m_A25 * V[45];
- V[8] = (RHS8 - tmp8) / m_A23;
- double tmp7 = 0.0;
- tmp7 += m_A20 * V[43];
- tmp7 += m_A21 * V[44];
- tmp7 += m_A22 * V[45];
- V[7] = (RHS7 - tmp7) / m_A19;
- double tmp6 = 0.0;
- tmp6 += m_A18 * V[33];
- V[6] = (RHS6 - tmp6) / m_A17;
- double tmp5 = 0.0;
- tmp5 += m_A15 * V[33];
- tmp5 += m_A16 * V[36];
- V[5] = (RHS5 - tmp5) / m_A14;
- double tmp4 = 0.0;
- tmp4 += m_A12 * V[36];
- tmp4 += m_A13 * V[45];
- V[4] = (RHS4 - tmp4) / m_A11;
- double tmp3 = 0.0;
- tmp3 += m_A8 * V[27];
- tmp3 += m_A9 * V[35];
- tmp3 += m_A10 * V[44];
- V[3] = (RHS3 - tmp3) / m_A7;
- double tmp2 = 0.0;
- tmp2 += m_A6 * V[35];
- V[2] = (RHS2 - tmp2) / m_A5;
+ const double f0_1 = -f0 * m_A2;
+ m_A3 += m_A1 * f0_1;
+ RHS1 += f0_1 * RHS0;
+ const double f0_2 = -f0 * m_A5;
+ m_A6 += m_A1 * f0_2;
+ RHS2 += f0_2 * RHS0;
+ const double f1 = 1.0 / m_A3;
+ const double f1_2 = -f1 * m_A6;
+ m_A7 += m_A4 * f1_2;
+ RHS2 += f1_2 * RHS1;
+ V[2] = RHS2 / m_A7;
double tmp1 = 0.0;
- tmp1 += m_A3 * V[27];
- tmp1 += m_A4 * V[44];
- V[1] = (RHS1 - tmp1) / m_A2;
+ tmp1 += m_A4 * V[2];
+ V[1] = (RHS1 - tmp1) / m_A3;
double tmp0 = 0.0;
tmp0 += m_A1 * V[1];
V[0] = (RHS0 - tmp0) / m_A0;
@@ -9295,6 +10516,575 @@ static void nl_gcr_34e910fc1896999f_76_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_3c79fd354e01fa8c_89_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A3 += go[3];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 -= go[4] * *cnV[4];
+ RHS1 -= go[5] * *cnV[5];
+ RHS1 -= go[6] * *cnV[6];
+ m_A4 += gt[7];
+ m_A4 += gt[8];
+ m_A4 += gt[9];
+ m_A4 += gt[10];
+ m_A6 += go[7];
+ m_A7 += go[8];
+ m_A5 += go[9];
+ double RHS2 = Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 -= go[10] * *cnV[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A8 += gt[15];
+ m_A11 += go[11];
+ m_A10 += go[12];
+ m_A9 += go[13];
+ double RHS3 = Idr[11];
+ RHS3 += Idr[12];
+ RHS3 += Idr[13];
+ RHS3 += Idr[14];
+ RHS3 += Idr[15];
+ RHS3 -= go[14] * *cnV[14];
+ RHS3 -= go[15] * *cnV[15];
+ m_A12 += gt[16];
+ m_A12 += gt[17];
+ m_A12 += gt[18];
+ m_A13 += go[16];
+ double RHS4 = Idr[16];
+ RHS4 += Idr[17];
+ RHS4 += Idr[18];
+ RHS4 -= go[17] * *cnV[17];
+ RHS4 -= go[18] * *cnV[18];
+ m_A14 += gt[19];
+ m_A14 += gt[20];
+ m_A14 += gt[21];
+ m_A14 += gt[22];
+ m_A15 += go[19];
+ double RHS5 = Idr[19];
+ RHS5 += Idr[20];
+ RHS5 += Idr[21];
+ RHS5 += Idr[22];
+ RHS5 -= go[20] * *cnV[20];
+ RHS5 -= go[21] * *cnV[21];
+ RHS5 -= go[22] * *cnV[22];
+ m_A16 += gt[23];
+ m_A16 += gt[24];
+ m_A16 += gt[25];
+ m_A16 += gt[26];
+ m_A16 += gt[27];
+ m_A16 += gt[28];
+ m_A17 += go[23];
+ m_A19 += go[24];
+ m_A20 += go[25];
+ m_A18 += go[26];
+ double RHS6 = Idr[23];
+ RHS6 += Idr[24];
+ RHS6 += Idr[25];
+ RHS6 += Idr[26];
+ RHS6 += Idr[27];
+ RHS6 += Idr[28];
+ RHS6 -= go[27] * *cnV[27];
+ RHS6 -= go[28] * *cnV[28];
+ m_A21 += gt[29];
+ m_A21 += gt[30];
+ m_A21 += gt[31];
+ m_A21 += gt[32];
+ m_A21 += gt[33];
+ m_A22 += go[29];
+ m_A24 += go[30];
+ m_A23 += go[31];
+ double RHS7 = Idr[29];
+ RHS7 += Idr[30];
+ RHS7 += Idr[31];
+ RHS7 += Idr[32];
+ RHS7 += Idr[33];
+ RHS7 -= go[32] * *cnV[32];
+ RHS7 -= go[33] * *cnV[33];
+ m_A27 += gt[34];
+ m_A27 += gt[35];
+ m_A27 += gt[36];
+ m_A26 += go[34];
+ m_A25 += go[35];
+ double RHS8 = Idr[34];
+ RHS8 += Idr[35];
+ RHS8 += Idr[36];
+ RHS8 -= go[36] * *cnV[36];
+ m_A32 += gt[37];
+ m_A32 += gt[38];
+ m_A32 += gt[39];
+ m_A30 += go[37];
+ double RHS9 = Idr[37];
+ RHS9 += Idr[38];
+ RHS9 += Idr[39];
+ RHS9 -= go[38] * *cnV[38];
+ RHS9 -= go[39] * *cnV[39];
+ m_A38 += gt[40];
+ m_A38 += gt[41];
+ m_A34 += go[40];
+ m_A35 += go[41];
+ double RHS10 = Idr[40];
+ RHS10 += Idr[41];
+ m_A42 += gt[42];
+ m_A42 += gt[43];
+ m_A42 += gt[44];
+ m_A42 += gt[45];
+ m_A42 += gt[46];
+ m_A42 += gt[47];
+ m_A42 += gt[48];
+ m_A41 += go[42];
+ m_A43 += go[43];
+ double RHS11 = Idr[42];
+ RHS11 += Idr[43];
+ RHS11 += Idr[44];
+ RHS11 += Idr[45];
+ RHS11 += Idr[46];
+ RHS11 += Idr[47];
+ RHS11 += Idr[48];
+ RHS11 -= go[44] * *cnV[44];
+ RHS11 -= go[45] * *cnV[45];
+ RHS11 -= go[46] * *cnV[46];
+ RHS11 -= go[47] * *cnV[47];
+ RHS11 -= go[48] * *cnV[48];
+ m_A49 += gt[49];
+ m_A49 += gt[50];
+ m_A49 += gt[51];
+ m_A45 += go[49];
+ m_A46 += go[50];
+ m_A44 += go[51];
+ double RHS12 = Idr[49];
+ RHS12 += Idr[50];
+ RHS12 += Idr[51];
+ m_A53 += gt[52];
+ m_A53 += gt[53];
+ m_A53 += gt[54];
+ m_A53 += gt[55];
+ m_A53 += gt[56];
+ m_A53 += gt[57];
+ m_A53 += gt[58];
+ m_A54 += go[52];
+ m_A55 += go[53];
+ double RHS13 = Idr[52];
+ RHS13 += Idr[53];
+ RHS13 += Idr[54];
+ RHS13 += Idr[55];
+ RHS13 += Idr[56];
+ RHS13 += Idr[57];
+ RHS13 += Idr[58];
+ RHS13 -= go[54] * *cnV[54];
+ RHS13 -= go[55] * *cnV[55];
+ RHS13 -= go[56] * *cnV[56];
+ RHS13 -= go[57] * *cnV[57];
+ RHS13 -= go[58] * *cnV[58];
+ m_A57 += gt[59];
+ m_A57 += gt[60];
+ m_A57 += gt[61];
+ m_A58 += go[59];
+ m_A56 += go[60];
+ double RHS14 = Idr[59];
+ RHS14 += Idr[60];
+ RHS14 += Idr[61];
+ RHS14 -= go[61] * *cnV[61];
+ m_A62 += gt[62];
+ m_A62 += gt[63];
+ m_A60 += go[62];
+ m_A59 += go[63];
+ double RHS15 = Idr[62];
+ RHS15 += Idr[63];
+ m_A68 += gt[64];
+ m_A68 += gt[65];
+ m_A68 += gt[66];
+ m_A70 += go[64];
+ m_A65 += go[65];
+ double RHS16 = Idr[64];
+ RHS16 += Idr[65];
+ RHS16 += Idr[66];
+ RHS16 -= go[66] * *cnV[66];
+ m_A77 += gt[67];
+ m_A77 += gt[68];
+ m_A77 += gt[69];
+ m_A77 += gt[70];
+ m_A77 += gt[71];
+ m_A77 += gt[72];
+ m_A77 += gt[73];
+ m_A73 += go[67];
+ m_A71 += go[68];
+ double RHS17 = Idr[67];
+ RHS17 += Idr[68];
+ RHS17 += Idr[69];
+ RHS17 += Idr[70];
+ RHS17 += Idr[71];
+ RHS17 += Idr[72];
+ RHS17 += Idr[73];
+ RHS17 -= go[69] * *cnV[69];
+ RHS17 -= go[70] * *cnV[70];
+ RHS17 -= go[71] * *cnV[71];
+ RHS17 -= go[72] * *cnV[72];
+ RHS17 -= go[73] * *cnV[73];
+ m_A88 += gt[74];
+ m_A88 += gt[75];
+ m_A88 += gt[76];
+ m_A88 += gt[77];
+ m_A86 += go[74];
+ m_A84 += go[75];
+ m_A79 += go[76];
+ m_A80 += go[77];
+ double RHS18 = Idr[74];
+ RHS18 += Idr[75];
+ RHS18 += Idr[76];
+ RHS18 += Idr[77];
+ const double f0 = 1.0 / m_A0;
+ const double f0_15 = -f0 * m_A59;
+ m_A62 += m_A1 * f0_15;
+ RHS15 += f0_15 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_8 = -f1 * m_A25;
+ m_A27 += m_A3 * f1_8;
+ RHS8 += f1_8 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_8 = -f2 * m_A26;
+ m_A27 += m_A5 * f2_8;
+ m_A28 += m_A6 * f2_8;
+ m_A29 += m_A7 * f2_8;
+ RHS8 += f2_8 * RHS2;
+ const double f2_9 = -f2 * m_A30;
+ m_A31 += m_A5 * f2_9;
+ m_A32 += m_A6 * f2_9;
+ m_A33 += m_A7 * f2_9;
+ RHS9 += f2_9 * RHS2;
+ const double f2_10 = -f2 * m_A34;
+ m_A36 += m_A5 * f2_10;
+ m_A37 += m_A6 * f2_10;
+ m_A38 += m_A7 * f2_10;
+ RHS10 += f2_10 * RHS2;
+ const double f2_17 = -f2 * m_A71;
+ m_A72 += m_A5 * f2_17;
+ m_A73 += m_A6 * f2_17;
+ m_A74 += m_A7 * f2_17;
+ RHS17 += f2_17 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_10 = -f3 * m_A35;
+ m_A38 += m_A9 * f3_10;
+ m_A39 += m_A10 * f3_10;
+ m_A40 += m_A11 * f3_10;
+ RHS10 += f3_10 * RHS3;
+ const double f3_12 = -f3 * m_A44;
+ m_A47 += m_A9 * f3_12;
+ m_A49 += m_A10 * f3_12;
+ m_A51 += m_A11 * f3_12;
+ RHS12 += f3_12 * RHS3;
+ const double f4 = 1.0 / m_A12;
+ const double f4_11 = -f4 * m_A41;
+ m_A43 += m_A13 * f4_11;
+ RHS11 += f4_11 * RHS4;
+ const double f4_12 = -f4 * m_A45;
+ m_A49 += m_A13 * f4_12;
+ RHS12 += f4_12 * RHS4;
+ const double f5 = 1.0 / m_A14;
+ const double f5_14 = -f5 * m_A56;
+ m_A57 += m_A15 * f5_14;
+ RHS14 += f5_14 * RHS5;
+ const double f6 = 1.0 / m_A16;
+ const double f6_12 = -f6 * m_A46;
+ m_A48 += m_A17 * f6_12;
+ m_A49 += m_A18 * f6_12;
+ m_A50 += m_A19 * f6_12;
+ m_A52 += m_A20 * f6_12;
+ RHS12 += f6_12 * RHS6;
+ const double f6_16 = -f6 * m_A65;
+ m_A66 += m_A17 * f6_16;
+ m_A67 += m_A18 * f6_16;
+ m_A68 += m_A19 * f6_16;
+ m_A70 += m_A20 * f6_16;
+ RHS16 += f6_16 * RHS6;
+ const double f6_18 = -f6 * m_A79;
+ m_A81 += m_A17 * f6_18;
+ m_A82 += m_A18 * f6_18;
+ m_A86 += m_A19 * f6_18;
+ m_A88 += m_A20 * f6_18;
+ RHS18 += f6_18 * RHS6;
+ const double f7 = 1.0 / m_A21;
+ const double f7_15 = -f7 * m_A60;
+ m_A61 += m_A22 * f7_15;
+ m_A62 += m_A23 * f7_15;
+ m_A64 += m_A24 * f7_15;
+ RHS15 += f7_15 * RHS7;
+ const double f7_18 = -f7 * m_A80;
+ m_A83 += m_A22 * f7_18;
+ m_A85 += m_A23 * f7_18;
+ m_A88 += m_A24 * f7_18;
+ RHS18 += f7_18 * RHS7;
+ const double f8 = 1.0 / m_A27;
+ const double f8_9 = -f8 * m_A31;
+ m_A32 += m_A28 * f8_9;
+ m_A33 += m_A29 * f8_9;
+ RHS9 += f8_9 * RHS8;
+ const double f8_10 = -f8 * m_A36;
+ m_A37 += m_A28 * f8_10;
+ m_A38 += m_A29 * f8_10;
+ RHS10 += f8_10 * RHS8;
+ const double f8_17 = -f8 * m_A72;
+ m_A73 += m_A28 * f8_17;
+ m_A74 += m_A29 * f8_17;
+ RHS17 += f8_17 * RHS8;
+ const double f9 = 1.0 / m_A32;
+ const double f9_10 = -f9 * m_A37;
+ m_A38 += m_A33 * f9_10;
+ RHS10 += f9_10 * RHS9;
+ const double f9_17 = -f9 * m_A73;
+ m_A74 += m_A33 * f9_17;
+ RHS17 += f9_17 * RHS9;
+ const double f10 = 1.0 / m_A38;
+ const double f10_12 = -f10 * m_A47;
+ m_A49 += m_A39 * f10_12;
+ m_A51 += m_A40 * f10_12;
+ RHS12 += f10_12 * RHS10;
+ const double f10_17 = -f10 * m_A74;
+ m_A75 += m_A39 * f10_17;
+ m_A77 += m_A40 * f10_17;
+ RHS17 += f10_17 * RHS10;
+ const double f11 = 1.0 / m_A42;
+ const double f11_12 = -f11 * m_A48;
+ m_A49 += m_A43 * f11_12;
+ RHS12 += f11_12 * RHS11;
+ const double f11_16 = -f11 * m_A66;
+ m_A67 += m_A43 * f11_16;
+ RHS16 += f11_16 * RHS11;
+ const double f11_18 = -f11 * m_A81;
+ m_A82 += m_A43 * f11_18;
+ RHS18 += f11_18 * RHS11;
+ const double f12 = 1.0 / m_A49;
+ const double f12_16 = -f12 * m_A67;
+ m_A68 += m_A50 * f12_16;
+ m_A69 += m_A51 * f12_16;
+ m_A70 += m_A52 * f12_16;
+ RHS16 += f12_16 * RHS12;
+ const double f12_17 = -f12 * m_A75;
+ m_A76 += m_A50 * f12_17;
+ m_A77 += m_A51 * f12_17;
+ m_A78 += m_A52 * f12_17;
+ RHS17 += f12_17 * RHS12;
+ const double f12_18 = -f12 * m_A82;
+ m_A86 += m_A50 * f12_18;
+ m_A87 += m_A51 * f12_18;
+ m_A88 += m_A52 * f12_18;
+ RHS18 += f12_18 * RHS12;
+ const double f13 = 1.0 / m_A53;
+ const double f13_15 = -f13 * m_A61;
+ m_A63 += m_A54 * f13_15;
+ m_A64 += m_A55 * f13_15;
+ RHS15 += f13_15 * RHS13;
+ const double f13_18 = -f13 * m_A83;
+ m_A86 += m_A54 * f13_18;
+ m_A88 += m_A55 * f13_18;
+ RHS18 += f13_18 * RHS13;
+ const double f14 = 1.0 / m_A57;
+ const double f14_18 = -f14 * m_A84;
+ m_A88 += m_A58 * f14_18;
+ RHS18 += f14_18 * RHS14;
+ const double f15 = 1.0 / m_A62;
+ const double f15_18 = -f15 * m_A85;
+ m_A86 += m_A63 * f15_18;
+ m_A88 += m_A64 * f15_18;
+ RHS18 += f15_18 * RHS15;
+ const double f16 = 1.0 / m_A68;
+ const double f16_17 = -f16 * m_A76;
+ m_A77 += m_A69 * f16_17;
+ m_A78 += m_A70 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f16_18 = -f16 * m_A86;
+ m_A87 += m_A69 * f16_18;
+ m_A88 += m_A70 * f16_18;
+ RHS18 += f16_18 * RHS16;
+ const double f17 = 1.0 / m_A77;
+ const double f17_18 = -f17 * m_A87;
+ m_A88 += m_A78 * f17_18;
+ RHS18 += f17_18 * RHS17;
+ V[18] = RHS18 / m_A88;
+ double tmp17 = 0.0;
+ tmp17 += m_A78 * V[18];
+ V[17] = (RHS17 - tmp17) / m_A77;
+ double tmp16 = 0.0;
+ tmp16 += m_A69 * V[17];
+ tmp16 += m_A70 * V[18];
+ V[16] = (RHS16 - tmp16) / m_A68;
+ double tmp15 = 0.0;
+ tmp15 += m_A63 * V[16];
+ tmp15 += m_A64 * V[18];
+ V[15] = (RHS15 - tmp15) / m_A62;
+ double tmp14 = 0.0;
+ tmp14 += m_A58 * V[18];
+ V[14] = (RHS14 - tmp14) / m_A57;
+ double tmp13 = 0.0;
+ tmp13 += m_A54 * V[16];
+ tmp13 += m_A55 * V[18];
+ V[13] = (RHS13 - tmp13) / m_A53;
+ double tmp12 = 0.0;
+ tmp12 += m_A50 * V[16];
+ tmp12 += m_A51 * V[17];
+ tmp12 += m_A52 * V[18];
+ V[12] = (RHS12 - tmp12) / m_A49;
+ double tmp11 = 0.0;
+ tmp11 += m_A43 * V[12];
+ V[11] = (RHS11 - tmp11) / m_A42;
+ double tmp10 = 0.0;
+ tmp10 += m_A39 * V[12];
+ tmp10 += m_A40 * V[17];
+ V[10] = (RHS10 - tmp10) / m_A38;
+ double tmp9 = 0.0;
+ tmp9 += m_A33 * V[10];
+ V[9] = (RHS9 - tmp9) / m_A32;
+ double tmp8 = 0.0;
+ tmp8 += m_A28 * V[9];
+ tmp8 += m_A29 * V[10];
+ V[8] = (RHS8 - tmp8) / m_A27;
+ double tmp7 = 0.0;
+ tmp7 += m_A22 * V[13];
+ tmp7 += m_A23 * V[15];
+ tmp7 += m_A24 * V[18];
+ V[7] = (RHS7 - tmp7) / m_A21;
+ double tmp6 = 0.0;
+ tmp6 += m_A17 * V[11];
+ tmp6 += m_A18 * V[12];
+ tmp6 += m_A19 * V[16];
+ tmp6 += m_A20 * V[18];
+ V[6] = (RHS6 - tmp6) / m_A16;
+ double tmp5 = 0.0;
+ tmp5 += m_A15 * V[14];
+ V[5] = (RHS5 - tmp5) / m_A14;
+ double tmp4 = 0.0;
+ tmp4 += m_A13 * V[12];
+ V[4] = (RHS4 - tmp4) / m_A12;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[10];
+ tmp3 += m_A10 * V[12];
+ tmp3 += m_A11 * V[17];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[8];
+ tmp2 += m_A6 * V[9];
+ tmp2 += m_A7 * V[10];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[8];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[15];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// sspeedr
static void nl_gcr_3e833834e5ce5aee_13_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -12934,6 +14724,514 @@ static void nl_gcr_4334c95878d1be92_399_double_double(double * __restrict V, con
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_437326911721091_77_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A4 += go[2];
+ m_A5 += go[3];
+ m_A3 += go[4];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 -= go[5] * *cnV[5];
+ RHS1 -= go[6] * *cnV[6];
+ m_A6 += gt[7];
+ m_A6 += gt[8];
+ m_A6 += gt[9];
+ m_A7 += go[7];
+ double RHS2 = Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 -= go[8] * *cnV[8];
+ RHS2 -= go[9] * *cnV[9];
+ m_A8 += gt[10];
+ m_A8 += gt[11];
+ m_A10 += go[10];
+ m_A9 += go[11];
+ double RHS3 = Idr[10];
+ RHS3 += Idr[11];
+ m_A11 += gt[12];
+ m_A11 += gt[13];
+ m_A11 += gt[14];
+ m_A11 += gt[15];
+ m_A12 += go[12];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ RHS4 += Idr[14];
+ RHS4 += Idr[15];
+ RHS4 -= go[13] * *cnV[13];
+ RHS4 -= go[14] * *cnV[14];
+ RHS4 -= go[15] * *cnV[15];
+ m_A13 += gt[16];
+ m_A13 += gt[17];
+ m_A13 += gt[18];
+ m_A13 += gt[19];
+ m_A13 += gt[20];
+ m_A16 += go[16];
+ m_A15 += go[17];
+ m_A14 += go[18];
+ double RHS5 = Idr[16];
+ RHS5 += Idr[17];
+ RHS5 += Idr[18];
+ RHS5 += Idr[19];
+ RHS5 += Idr[20];
+ RHS5 -= go[19] * *cnV[19];
+ RHS5 -= go[20] * *cnV[20];
+ m_A17 += gt[21];
+ m_A17 += gt[22];
+ m_A17 += gt[23];
+ m_A18 += go[21];
+ double RHS6 = Idr[21];
+ RHS6 += Idr[22];
+ RHS6 += Idr[23];
+ RHS6 -= go[22] * *cnV[22];
+ RHS6 -= go[23] * *cnV[23];
+ m_A19 += gt[24];
+ m_A19 += gt[25];
+ m_A19 += gt[26];
+ m_A19 += gt[27];
+ m_A20 += go[24];
+ double RHS7 = Idr[24];
+ RHS7 += Idr[25];
+ RHS7 += Idr[26];
+ RHS7 += Idr[27];
+ RHS7 -= go[25] * *cnV[25];
+ RHS7 -= go[26] * *cnV[26];
+ RHS7 -= go[27] * *cnV[27];
+ m_A23 += gt[28];
+ m_A23 += gt[29];
+ m_A23 += gt[30];
+ m_A21 += go[28];
+ m_A22 += go[29];
+ double RHS8 = Idr[28];
+ RHS8 += Idr[29];
+ RHS8 += Idr[30];
+ RHS8 -= go[30] * *cnV[30];
+ m_A28 += gt[31];
+ m_A28 += gt[32];
+ m_A28 += gt[33];
+ m_A28 += gt[34];
+ m_A28 += gt[35];
+ m_A28 += gt[36];
+ m_A28 += gt[37];
+ m_A29 += go[31];
+ m_A26 += go[32];
+ double RHS9 = Idr[31];
+ RHS9 += Idr[32];
+ RHS9 += Idr[33];
+ RHS9 += Idr[34];
+ RHS9 += Idr[35];
+ RHS9 += Idr[36];
+ RHS9 += Idr[37];
+ RHS9 -= go[33] * *cnV[33];
+ RHS9 -= go[34] * *cnV[34];
+ RHS9 -= go[35] * *cnV[35];
+ RHS9 -= go[36] * *cnV[36];
+ RHS9 -= go[37] * *cnV[37];
+ m_A31 += gt[38];
+ m_A31 += gt[39];
+ m_A31 += gt[40];
+ m_A31 += gt[41];
+ m_A31 += gt[42];
+ m_A31 += gt[43];
+ m_A31 += gt[44];
+ m_A32 += go[38];
+ m_A30 += go[39];
+ double RHS10 = Idr[38];
+ RHS10 += Idr[39];
+ RHS10 += Idr[40];
+ RHS10 += Idr[41];
+ RHS10 += Idr[42];
+ RHS10 += Idr[43];
+ RHS10 += Idr[44];
+ RHS10 -= go[40] * *cnV[40];
+ RHS10 -= go[41] * *cnV[41];
+ RHS10 -= go[42] * *cnV[42];
+ RHS10 -= go[43] * *cnV[43];
+ RHS10 -= go[44] * *cnV[44];
+ m_A35 += gt[45];
+ m_A35 += gt[46];
+ m_A35 += gt[47];
+ m_A35 += gt[48];
+ m_A36 += go[45];
+ m_A34 += go[46];
+ m_A33 += go[47];
+ double RHS11 = Idr[45];
+ RHS11 += Idr[46];
+ RHS11 += Idr[47];
+ RHS11 += Idr[48];
+ RHS11 -= go[48] * *cnV[48];
+ m_A42 += gt[49];
+ m_A42 += gt[50];
+ m_A42 += gt[51];
+ m_A39 += go[49];
+ m_A45 += go[50];
+ m_A38 += go[51];
+ double RHS12 = Idr[49];
+ RHS12 += Idr[50];
+ RHS12 += Idr[51];
+ m_A48 += gt[52];
+ m_A48 += gt[53];
+ m_A46 += go[52];
+ m_A51 += go[53];
+ double RHS13 = Idr[52];
+ RHS13 += Idr[53];
+ m_A53 += gt[54];
+ m_A53 += gt[55];
+ m_A53 += gt[56];
+ m_A53 += gt[57];
+ m_A53 += gt[58];
+ m_A53 += gt[59];
+ m_A53 += gt[60];
+ m_A54 += go[54];
+ m_A52 += go[55];
+ double RHS14 = Idr[54];
+ RHS14 += Idr[55];
+ RHS14 += Idr[56];
+ RHS14 += Idr[57];
+ RHS14 += Idr[58];
+ RHS14 += Idr[59];
+ RHS14 += Idr[60];
+ RHS14 -= go[56] * *cnV[56];
+ RHS14 -= go[57] * *cnV[57];
+ RHS14 -= go[58] * *cnV[58];
+ RHS14 -= go[59] * *cnV[59];
+ RHS14 -= go[60] * *cnV[60];
+ m_A56 += gt[61];
+ m_A56 += gt[62];
+ m_A56 += gt[63];
+ m_A55 += go[61];
+ m_A57 += go[62];
+ double RHS15 = Idr[61];
+ RHS15 += Idr[62];
+ RHS15 += Idr[63];
+ RHS15 -= go[63] * *cnV[63];
+ m_A60 += gt[64];
+ m_A60 += gt[65];
+ m_A60 += gt[66];
+ m_A58 += go[64];
+ m_A59 += go[65];
+ double RHS16 = Idr[64];
+ RHS16 += Idr[65];
+ RHS16 += Idr[66];
+ RHS16 -= go[66] * *cnV[66];
+ m_A69 += gt[67];
+ m_A69 += gt[68];
+ m_A69 += gt[69];
+ m_A69 += gt[70];
+ m_A69 += gt[71];
+ m_A63 += go[67];
+ m_A62 += go[68];
+ m_A65 += go[69];
+ double RHS17 = Idr[67];
+ RHS17 += Idr[68];
+ RHS17 += Idr[69];
+ RHS17 += Idr[70];
+ RHS17 += Idr[71];
+ RHS17 -= go[70] * *cnV[70];
+ RHS17 -= go[71] * *cnV[71];
+ m_A76 += gt[72];
+ m_A76 += gt[73];
+ m_A76 += gt[74];
+ m_A76 += gt[75];
+ m_A74 += go[72];
+ m_A72 += go[73];
+ m_A71 += go[74];
+ double RHS18 = Idr[72];
+ RHS18 += Idr[73];
+ RHS18 += Idr[74];
+ RHS18 += Idr[75];
+ RHS18 -= go[75] * *cnV[75];
+ const double f0 = 1.0 / m_A0;
+ const double f0_8 = -f0 * m_A21;
+ m_A23 += m_A1 * f0_8;
+ RHS8 += f0_8 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_8 = -f1 * m_A22;
+ m_A23 += m_A3 * f1_8;
+ m_A24 += m_A4 * f1_8;
+ m_A25 += m_A5 * f1_8;
+ RHS8 += f1_8 * RHS1;
+ const double f1_9 = -f1 * m_A26;
+ m_A27 += m_A3 * f1_9;
+ m_A28 += m_A4 * f1_9;
+ m_A29 += m_A5 * f1_9;
+ RHS9 += f1_9 * RHS1;
+ const double f1_12 = -f1 * m_A38;
+ m_A40 += m_A3 * f1_12;
+ m_A41 += m_A4 * f1_12;
+ m_A42 += m_A5 * f1_12;
+ RHS12 += f1_12 * RHS1;
+ const double f2 = 1.0 / m_A6;
+ const double f2_10 = -f2 * m_A30;
+ m_A32 += m_A7 * f2_10;
+ RHS10 += f2_10 * RHS2;
+ const double f2_11 = -f2 * m_A33;
+ m_A35 += m_A7 * f2_11;
+ RHS11 += f2_11 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_11 = -f3 * m_A34;
+ m_A35 += m_A9 * f3_11;
+ m_A37 += m_A10 * f3_11;
+ RHS11 += f3_11 * RHS3;
+ const double f3_17 = -f3 * m_A62;
+ m_A64 += m_A9 * f3_17;
+ m_A69 += m_A10 * f3_17;
+ RHS17 += f3_17 * RHS3;
+ const double f4 = 1.0 / m_A11;
+ const double f4_16 = -f4 * m_A58;
+ m_A60 += m_A12 * f4_16;
+ RHS16 += f4_16 * RHS4;
+ const double f5 = 1.0 / m_A13;
+ const double f5_12 = -f5 * m_A39;
+ m_A42 += m_A14 * f5_12;
+ m_A43 += m_A15 * f5_12;
+ m_A44 += m_A16 * f5_12;
+ RHS12 += f5_12 * RHS5;
+ const double f5_13 = -f5 * m_A46;
+ m_A47 += m_A14 * f5_13;
+ m_A48 += m_A15 * f5_13;
+ m_A49 += m_A16 * f5_13;
+ RHS13 += f5_13 * RHS5;
+ const double f6 = 1.0 / m_A17;
+ const double f6_14 = -f6 * m_A52;
+ m_A54 += m_A18 * f6_14;
+ RHS14 += f6_14 * RHS6;
+ const double f6_18 = -f6 * m_A71;
+ m_A76 += m_A18 * f6_18;
+ RHS18 += f6_18 * RHS6;
+ const double f7 = 1.0 / m_A19;
+ const double f7_15 = -f7 * m_A55;
+ m_A56 += m_A20 * f7_15;
+ RHS15 += f7_15 * RHS7;
+ const double f8 = 1.0 / m_A23;
+ const double f8_9 = -f8 * m_A27;
+ m_A28 += m_A24 * f8_9;
+ m_A29 += m_A25 * f8_9;
+ RHS9 += f8_9 * RHS8;
+ const double f8_12 = -f8 * m_A40;
+ m_A41 += m_A24 * f8_12;
+ m_A42 += m_A25 * f8_12;
+ RHS12 += f8_12 * RHS8;
+ const double f9 = 1.0 / m_A28;
+ const double f9_12 = -f9 * m_A41;
+ m_A42 += m_A29 * f9_12;
+ RHS12 += f9_12 * RHS9;
+ const double f10 = 1.0 / m_A31;
+ const double f10_17 = -f10 * m_A63;
+ m_A64 += m_A32 * f10_17;
+ RHS17 += f10_17 * RHS10;
+ const double f11 = 1.0 / m_A35;
+ const double f11_16 = -f11 * m_A59;
+ m_A60 += m_A36 * f11_16;
+ m_A61 += m_A37 * f11_16;
+ RHS16 += f11_16 * RHS11;
+ const double f11_17 = -f11 * m_A64;
+ m_A68 += m_A36 * f11_17;
+ m_A69 += m_A37 * f11_17;
+ RHS17 += f11_17 * RHS11;
+ const double f12 = 1.0 / m_A42;
+ const double f12_13 = -f12 * m_A47;
+ m_A48 += m_A43 * f12_13;
+ m_A49 += m_A44 * f12_13;
+ m_A50 += m_A45 * f12_13;
+ RHS13 += f12_13 * RHS12;
+ const double f12_17 = -f12 * m_A65;
+ m_A66 += m_A43 * f12_17;
+ m_A67 += m_A44 * f12_17;
+ m_A69 += m_A45 * f12_17;
+ RHS17 += f12_17 * RHS12;
+ const double f13 = 1.0 / m_A48;
+ const double f13_17 = -f13 * m_A66;
+ m_A67 += m_A49 * f13_17;
+ m_A69 += m_A50 * f13_17;
+ m_A70 += m_A51 * f13_17;
+ RHS17 += f13_17 * RHS13;
+ const double f13_18 = -f13 * m_A72;
+ m_A73 += m_A49 * f13_18;
+ m_A75 += m_A50 * f13_18;
+ m_A76 += m_A51 * f13_18;
+ RHS18 += f13_18 * RHS13;
+ const double f14 = 1.0 / m_A53;
+ const double f14_17 = -f14 * m_A67;
+ m_A70 += m_A54 * f14_17;
+ RHS17 += f14_17 * RHS14;
+ const double f14_18 = -f14 * m_A73;
+ m_A76 += m_A54 * f14_18;
+ RHS18 += f14_18 * RHS14;
+ const double f15 = 1.0 / m_A56;
+ const double f15_18 = -f15 * m_A74;
+ m_A76 += m_A57 * f15_18;
+ RHS18 += f15_18 * RHS15;
+ const double f16 = 1.0 / m_A60;
+ const double f16_17 = -f16 * m_A68;
+ m_A69 += m_A61 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f17 = 1.0 / m_A69;
+ const double f17_18 = -f17 * m_A75;
+ m_A76 += m_A70 * f17_18;
+ RHS18 += f17_18 * RHS17;
+ V[18] = RHS18 / m_A76;
+ double tmp17 = 0.0;
+ tmp17 += m_A70 * V[18];
+ V[17] = (RHS17 - tmp17) / m_A69;
+ double tmp16 = 0.0;
+ tmp16 += m_A61 * V[17];
+ V[16] = (RHS16 - tmp16) / m_A60;
+ double tmp15 = 0.0;
+ tmp15 += m_A57 * V[18];
+ V[15] = (RHS15 - tmp15) / m_A56;
+ double tmp14 = 0.0;
+ tmp14 += m_A54 * V[18];
+ V[14] = (RHS14 - tmp14) / m_A53;
+ double tmp13 = 0.0;
+ tmp13 += m_A49 * V[14];
+ tmp13 += m_A50 * V[17];
+ tmp13 += m_A51 * V[18];
+ V[13] = (RHS13 - tmp13) / m_A48;
+ double tmp12 = 0.0;
+ tmp12 += m_A43 * V[13];
+ tmp12 += m_A44 * V[14];
+ tmp12 += m_A45 * V[17];
+ V[12] = (RHS12 - tmp12) / m_A42;
+ double tmp11 = 0.0;
+ tmp11 += m_A36 * V[16];
+ tmp11 += m_A37 * V[17];
+ V[11] = (RHS11 - tmp11) / m_A35;
+ double tmp10 = 0.0;
+ tmp10 += m_A32 * V[11];
+ V[10] = (RHS10 - tmp10) / m_A31;
+ double tmp9 = 0.0;
+ tmp9 += m_A29 * V[12];
+ V[9] = (RHS9 - tmp9) / m_A28;
+ double tmp8 = 0.0;
+ tmp8 += m_A24 * V[9];
+ tmp8 += m_A25 * V[12];
+ V[8] = (RHS8 - tmp8) / m_A23;
+ double tmp7 = 0.0;
+ tmp7 += m_A20 * V[15];
+ V[7] = (RHS7 - tmp7) / m_A19;
+ double tmp6 = 0.0;
+ tmp6 += m_A18 * V[18];
+ V[6] = (RHS6 - tmp6) / m_A17;
+ double tmp5 = 0.0;
+ tmp5 += m_A14 * V[12];
+ tmp5 += m_A15 * V[13];
+ tmp5 += m_A16 * V[14];
+ V[5] = (RHS5 - tmp5) / m_A13;
+ double tmp4 = 0.0;
+ tmp4 += m_A12 * V[16];
+ V[4] = (RHS4 - tmp4) / m_A11;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[11];
+ tmp3 += m_A10 * V[17];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A7 * V[11];
+ V[2] = (RHS2 - tmp2) / m_A6;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[8];
+ tmp1 += m_A4 * V[9];
+ tmp1 += m_A5 * V[12];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[8];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// kidniki
static void nl_gcr_43f7ff9bc651cc7a_198_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -14306,6 +16604,550 @@ static void nl_gcr_491f95430bfdfd05_19_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// frogs
+static void nl_gcr_494f233b1a947be1_88_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A0 += gt[3];
+ m_A0 += gt[4];
+ m_A1 += go[0];
+ m_A1 += go[1];
+ m_A2 += go[2];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 += Idr[3];
+ RHS0 += Idr[4];
+ RHS0 -= go[3] * *cnV[3];
+ RHS0 -= go[4] * *cnV[4];
+ m_A3 += gt[5];
+ m_A3 += gt[6];
+ m_A3 += gt[7];
+ m_A3 += gt[8];
+ m_A5 += go[5];
+ m_A4 += go[6];
+ double RHS1 = Idr[5];
+ RHS1 += Idr[6];
+ RHS1 += Idr[7];
+ RHS1 += Idr[8];
+ RHS1 -= go[7] * *cnV[7];
+ RHS1 -= go[8] * *cnV[8];
+ m_A6 += gt[9];
+ m_A6 += gt[10];
+ m_A7 += go[9];
+ double RHS2 = Idr[9];
+ RHS2 += Idr[10];
+ RHS2 -= go[10] * *cnV[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A10 += go[11];
+ m_A9 += go[12];
+ double RHS3 = Idr[11];
+ RHS3 += Idr[12];
+ RHS3 += Idr[13];
+ RHS3 -= go[13] * *cnV[13];
+ m_A11 += gt[14];
+ m_A11 += gt[15];
+ m_A13 += go[14];
+ m_A12 += go[15];
+ double RHS4 = Idr[14];
+ RHS4 += Idr[15];
+ m_A14 += gt[16];
+ m_A14 += gt[17];
+ m_A15 += go[16];
+ m_A16 += go[17];
+ double RHS5 = Idr[16];
+ RHS5 += Idr[17];
+ m_A17 += gt[18];
+ m_A17 += gt[19];
+ m_A17 += gt[20];
+ m_A20 += go[18];
+ m_A18 += go[19];
+ m_A19 += go[20];
+ double RHS6 = Idr[18];
+ RHS6 += Idr[19];
+ RHS6 += Idr[20];
+ m_A21 += gt[21];
+ m_A21 += gt[22];
+ m_A23 += go[21];
+ m_A22 += go[22];
+ double RHS7 = Idr[21];
+ RHS7 += Idr[22];
+ m_A24 += gt[23];
+ m_A24 += gt[24];
+ m_A24 += gt[25];
+ m_A24 += gt[26];
+ m_A24 += gt[27];
+ m_A24 += gt[28];
+ m_A24 += gt[29];
+ m_A25 += go[23];
+ double RHS8 = Idr[23];
+ RHS8 += Idr[24];
+ RHS8 += Idr[25];
+ RHS8 += Idr[26];
+ RHS8 += Idr[27];
+ RHS8 += Idr[28];
+ RHS8 += Idr[29];
+ RHS8 -= go[24] * *cnV[24];
+ RHS8 -= go[25] * *cnV[25];
+ RHS8 -= go[26] * *cnV[26];
+ RHS8 -= go[27] * *cnV[27];
+ RHS8 -= go[28] * *cnV[28];
+ RHS8 -= go[29] * *cnV[29];
+ m_A28 += gt[30];
+ m_A28 += gt[31];
+ m_A28 += gt[32];
+ m_A28 += gt[33];
+ m_A27 += go[30];
+ m_A26 += go[31];
+ m_A26 += go[32];
+ double RHS9 = Idr[30];
+ RHS9 += Idr[31];
+ RHS9 += Idr[32];
+ RHS9 += Idr[33];
+ RHS9 -= go[33] * *cnV[33];
+ m_A33 += gt[34];
+ m_A33 += gt[35];
+ m_A31 += go[34];
+ double RHS10 = Idr[34];
+ RHS10 += Idr[35];
+ RHS10 -= go[35] * *cnV[35];
+ m_A39 += gt[36];
+ m_A39 += gt[37];
+ m_A39 += gt[38];
+ m_A36 += go[36];
+ m_A35 += go[37];
+ double RHS11 = Idr[36];
+ RHS11 += Idr[37];
+ RHS11 += Idr[38];
+ RHS11 -= go[38] * *cnV[38];
+ m_A43 += gt[39];
+ m_A43 += gt[40];
+ m_A43 += gt[41];
+ m_A44 += go[39];
+ m_A42 += go[40];
+ m_A41 += go[41];
+ double RHS12 = Idr[39];
+ RHS12 += Idr[40];
+ RHS12 += Idr[41];
+ m_A47 += gt[42];
+ m_A47 += gt[43];
+ m_A47 += gt[44];
+ m_A47 += gt[45];
+ m_A47 += gt[46];
+ m_A47 += gt[47];
+ m_A47 += gt[48];
+ m_A48 += go[42];
+ m_A45 += go[43];
+ double RHS13 = Idr[42];
+ RHS13 += Idr[43];
+ RHS13 += Idr[44];
+ RHS13 += Idr[45];
+ RHS13 += Idr[46];
+ RHS13 += Idr[47];
+ RHS13 += Idr[48];
+ RHS13 -= go[44] * *cnV[44];
+ RHS13 -= go[45] * *cnV[45];
+ RHS13 -= go[46] * *cnV[46];
+ RHS13 -= go[47] * *cnV[47];
+ RHS13 -= go[48] * *cnV[48];
+ m_A51 += gt[49];
+ m_A51 += gt[50];
+ m_A51 += gt[51];
+ m_A50 += go[49];
+ m_A49 += go[50];
+ double RHS14 = Idr[49];
+ RHS14 += Idr[50];
+ RHS14 += Idr[51];
+ RHS14 -= go[51] * *cnV[51];
+ m_A59 += gt[52];
+ m_A59 += gt[53];
+ m_A59 += gt[54];
+ m_A59 += gt[55];
+ m_A59 += gt[56];
+ m_A56 += go[52];
+ m_A55 += go[53];
+ double RHS15 = Idr[52];
+ RHS15 += Idr[53];
+ RHS15 += Idr[54];
+ RHS15 += Idr[55];
+ RHS15 += Idr[56];
+ RHS15 -= go[54] * *cnV[54];
+ RHS15 -= go[55] * *cnV[55];
+ RHS15 -= go[56] * *cnV[56];
+ m_A66 += gt[57];
+ m_A66 += gt[58];
+ m_A66 += gt[59];
+ m_A63 += go[57];
+ m_A62 += go[58];
+ double RHS16 = Idr[57];
+ RHS16 += Idr[58];
+ RHS16 += Idr[59];
+ RHS16 -= go[59] * *cnV[59];
+ m_A71 += gt[60];
+ m_A71 += gt[61];
+ m_A71 += gt[62];
+ m_A73 += go[60];
+ m_A69 += go[61];
+ double RHS17 = Idr[60];
+ RHS17 += Idr[61];
+ RHS17 += Idr[62];
+ RHS17 -= go[62] * *cnV[62];
+ m_A82 += gt[63];
+ m_A82 += gt[64];
+ m_A82 += gt[65];
+ m_A82 += gt[66];
+ m_A82 += gt[67];
+ m_A82 += gt[68];
+ m_A77 += go[63];
+ m_A75 += go[64];
+ m_A74 += go[65];
+ m_A76 += go[66];
+ double RHS18 = Idr[63];
+ RHS18 += Idr[64];
+ RHS18 += Idr[65];
+ RHS18 += Idr[66];
+ RHS18 += Idr[67];
+ RHS18 += Idr[68];
+ RHS18 -= go[67] * *cnV[67];
+ RHS18 -= go[68] * *cnV[68];
+ m_A87 += gt[69];
+ m_A87 += gt[70];
+ m_A87 += gt[71];
+ m_A87 += gt[72];
+ m_A84 += go[69];
+ m_A85 += go[70];
+ double RHS19 = Idr[69];
+ RHS19 += Idr[70];
+ RHS19 += Idr[71];
+ RHS19 += Idr[72];
+ RHS19 -= go[71] * *cnV[71];
+ RHS19 -= go[72] * *cnV[72];
+ const double f0 = 1.0 / m_A0;
+ const double f0_9 = -f0 * m_A26;
+ m_A28 += m_A1 * f0_9;
+ m_A30 += m_A2 * f0_9;
+ RHS9 += f0_9 * RHS0;
+ const double f0_11 = -f0 * m_A35;
+ m_A37 += m_A1 * f0_11;
+ m_A39 += m_A2 * f0_11;
+ RHS11 += f0_11 * RHS0;
+ const double f1 = 1.0 / m_A3;
+ const double f1_9 = -f1 * m_A27;
+ m_A28 += m_A4 * f1_9;
+ m_A29 += m_A5 * f1_9;
+ RHS9 += f1_9 * RHS1;
+ const double f1_10 = -f1 * m_A31;
+ m_A32 += m_A4 * f1_10;
+ m_A33 += m_A5 * f1_10;
+ RHS10 += f1_10 * RHS1;
+ const double f2 = 1.0 / m_A6;
+ const double f2_12 = -f2 * m_A41;
+ m_A43 += m_A7 * f2_12;
+ RHS12 += f2_12 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_12 = -f3 * m_A42;
+ m_A43 += m_A9 * f3_12;
+ m_A44 += m_A10 * f3_12;
+ RHS12 += f3_12 * RHS3;
+ const double f3_13 = -f3 * m_A45;
+ m_A46 += m_A9 * f3_13;
+ m_A48 += m_A10 * f3_13;
+ RHS13 += f3_13 * RHS3;
+ const double f3_18 = -f3 * m_A74;
+ m_A76 += m_A9 * f3_18;
+ m_A82 += m_A10 * f3_18;
+ RHS18 += f3_18 * RHS3;
+ const double f4 = 1.0 / m_A11;
+ const double f4_11 = -f4 * m_A36;
+ m_A39 += m_A12 * f4_11;
+ m_A40 += m_A13 * f4_11;
+ RHS11 += f4_11 * RHS4;
+ const double f4_15 = -f4 * m_A55;
+ m_A57 += m_A12 * f4_15;
+ m_A59 += m_A13 * f4_15;
+ RHS15 += f4_15 * RHS4;
+ const double f5 = 1.0 / m_A14;
+ const double f5_14 = -f5 * m_A49;
+ m_A51 += m_A15 * f5_14;
+ m_A54 += m_A16 * f5_14;
+ RHS14 += f5_14 * RHS5;
+ const double f5_18 = -f5 * m_A75;
+ m_A78 += m_A15 * f5_18;
+ m_A82 += m_A16 * f5_18;
+ RHS18 += f5_18 * RHS5;
+ const double f6 = 1.0 / m_A17;
+ const double f6_14 = -f6 * m_A50;
+ m_A51 += m_A18 * f6_14;
+ m_A52 += m_A19 * f6_14;
+ m_A53 += m_A20 * f6_14;
+ RHS14 += f6_14 * RHS6;
+ const double f6_15 = -f6 * m_A56;
+ m_A58 += m_A18 * f6_15;
+ m_A59 += m_A19 * f6_15;
+ m_A60 += m_A20 * f6_15;
+ RHS15 += f6_15 * RHS6;
+ const double f6_16 = -f6 * m_A62;
+ m_A64 += m_A18 * f6_16;
+ m_A65 += m_A19 * f6_16;
+ m_A66 += m_A20 * f6_16;
+ RHS16 += f6_16 * RHS6;
+ const double f7 = 1.0 / m_A21;
+ const double f7_16 = -f7 * m_A63;
+ m_A66 += m_A22 * f7_16;
+ m_A67 += m_A23 * f7_16;
+ RHS16 += f7_16 * RHS7;
+ const double f7_17 = -f7 * m_A69;
+ m_A70 += m_A22 * f7_17;
+ m_A71 += m_A23 * f7_17;
+ RHS17 += f7_17 * RHS7;
+ const double f8 = 1.0 / m_A24;
+ const double f8_19 = -f8 * m_A84;
+ m_A85 += m_A25 * f8_19;
+ RHS19 += f8_19 * RHS8;
+ const double f9 = 1.0 / m_A28;
+ const double f9_10 = -f9 * m_A32;
+ m_A33 += m_A29 * f9_10;
+ m_A34 += m_A30 * f9_10;
+ RHS10 += f9_10 * RHS9;
+ const double f9_11 = -f9 * m_A37;
+ m_A38 += m_A29 * f9_11;
+ m_A39 += m_A30 * f9_11;
+ RHS11 += f9_11 * RHS9;
+ const double f10 = 1.0 / m_A33;
+ const double f10_11 = -f10 * m_A38;
+ m_A39 += m_A34 * f10_11;
+ RHS11 += f10_11 * RHS10;
+ const double f11 = 1.0 / m_A39;
+ const double f11_15 = -f11 * m_A57;
+ m_A59 += m_A40 * f11_15;
+ RHS15 += f11_15 * RHS11;
+ const double f12 = 1.0 / m_A43;
+ const double f12_13 = -f12 * m_A46;
+ m_A48 += m_A44 * f12_13;
+ RHS13 += f12_13 * RHS12;
+ const double f12_18 = -f12 * m_A76;
+ m_A82 += m_A44 * f12_18;
+ RHS18 += f12_18 * RHS12;
+ const double f13 = 1.0 / m_A47;
+ const double f13_18 = -f13 * m_A77;
+ m_A82 += m_A48 * f13_18;
+ RHS18 += f13_18 * RHS13;
+ const double f14 = 1.0 / m_A51;
+ const double f14_15 = -f14 * m_A58;
+ m_A59 += m_A52 * f14_15;
+ m_A60 += m_A53 * f14_15;
+ m_A61 += m_A54 * f14_15;
+ RHS15 += f14_15 * RHS14;
+ const double f14_16 = -f14 * m_A64;
+ m_A65 += m_A52 * f14_16;
+ m_A66 += m_A53 * f14_16;
+ m_A68 += m_A54 * f14_16;
+ RHS16 += f14_16 * RHS14;
+ const double f14_18 = -f14 * m_A78;
+ m_A79 += m_A52 * f14_18;
+ m_A80 += m_A53 * f14_18;
+ m_A82 += m_A54 * f14_18;
+ RHS18 += f14_18 * RHS14;
+ const double f15 = 1.0 / m_A59;
+ const double f15_16 = -f15 * m_A65;
+ m_A66 += m_A60 * f15_16;
+ m_A68 += m_A61 * f15_16;
+ RHS16 += f15_16 * RHS15;
+ const double f15_18 = -f15 * m_A79;
+ m_A80 += m_A60 * f15_18;
+ m_A82 += m_A61 * f15_18;
+ RHS18 += f15_18 * RHS15;
+ const double f16 = 1.0 / m_A66;
+ const double f16_17 = -f16 * m_A70;
+ m_A71 += m_A67 * f16_17;
+ m_A72 += m_A68 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f16_18 = -f16 * m_A80;
+ m_A81 += m_A67 * f16_18;
+ m_A82 += m_A68 * f16_18;
+ RHS18 += f16_18 * RHS16;
+ const double f17 = 1.0 / m_A71;
+ const double f17_18 = -f17 * m_A81;
+ m_A82 += m_A72 * f17_18;
+ m_A83 += m_A73 * f17_18;
+ RHS18 += f17_18 * RHS17;
+ const double f17_19 = -f17 * m_A85;
+ m_A86 += m_A72 * f17_19;
+ m_A87 += m_A73 * f17_19;
+ RHS19 += f17_19 * RHS17;
+ const double f18 = 1.0 / m_A82;
+ const double f18_19 = -f18 * m_A86;
+ m_A87 += m_A83 * f18_19;
+ RHS19 += f18_19 * RHS18;
+ V[19] = RHS19 / m_A87;
+ double tmp18 = 0.0;
+ tmp18 += m_A83 * V[19];
+ V[18] = (RHS18 - tmp18) / m_A82;
+ double tmp17 = 0.0;
+ tmp17 += m_A72 * V[18];
+ tmp17 += m_A73 * V[19];
+ V[17] = (RHS17 - tmp17) / m_A71;
+ double tmp16 = 0.0;
+ tmp16 += m_A67 * V[17];
+ tmp16 += m_A68 * V[18];
+ V[16] = (RHS16 - tmp16) / m_A66;
+ double tmp15 = 0.0;
+ tmp15 += m_A60 * V[16];
+ tmp15 += m_A61 * V[18];
+ V[15] = (RHS15 - tmp15) / m_A59;
+ double tmp14 = 0.0;
+ tmp14 += m_A52 * V[15];
+ tmp14 += m_A53 * V[16];
+ tmp14 += m_A54 * V[18];
+ V[14] = (RHS14 - tmp14) / m_A51;
+ double tmp13 = 0.0;
+ tmp13 += m_A48 * V[18];
+ V[13] = (RHS13 - tmp13) / m_A47;
+ double tmp12 = 0.0;
+ tmp12 += m_A44 * V[18];
+ V[12] = (RHS12 - tmp12) / m_A43;
+ double tmp11 = 0.0;
+ tmp11 += m_A40 * V[15];
+ V[11] = (RHS11 - tmp11) / m_A39;
+ double tmp10 = 0.0;
+ tmp10 += m_A34 * V[11];
+ V[10] = (RHS10 - tmp10) / m_A33;
+ double tmp9 = 0.0;
+ tmp9 += m_A29 * V[10];
+ tmp9 += m_A30 * V[11];
+ V[9] = (RHS9 - tmp9) / m_A28;
+ double tmp8 = 0.0;
+ tmp8 += m_A25 * V[17];
+ V[8] = (RHS8 - tmp8) / m_A24;
+ double tmp7 = 0.0;
+ tmp7 += m_A22 * V[16];
+ tmp7 += m_A23 * V[17];
+ V[7] = (RHS7 - tmp7) / m_A21;
+ double tmp6 = 0.0;
+ tmp6 += m_A18 * V[14];
+ tmp6 += m_A19 * V[15];
+ tmp6 += m_A20 * V[16];
+ V[6] = (RHS6 - tmp6) / m_A17;
+ double tmp5 = 0.0;
+ tmp5 += m_A15 * V[14];
+ tmp5 += m_A16 * V[18];
+ V[5] = (RHS5 - tmp5) / m_A14;
+ double tmp4 = 0.0;
+ tmp4 += m_A12 * V[11];
+ tmp4 += m_A13 * V[15];
+ V[4] = (RHS4 - tmp4) / m_A11;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[12];
+ tmp3 += m_A10 * V[18];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A7 * V[12];
+ V[2] = (RHS2 - tmp2) / m_A6;
+ double tmp1 = 0.0;
+ tmp1 += m_A4 * V[9];
+ tmp1 += m_A5 * V[10];
+ V[1] = (RHS1 - tmp1) / m_A3;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[9];
+ tmp0 += m_A2 * V[11];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// sspeedr
static void nl_gcr_4a8e2b707bbac8a6_95_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -18279,7 +21121,102 @@ static void nl_gcr_546396f65ce48700_12_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
-// dpatrol
+// brdrline
+static void nl_gcr_576f391d0418cb76_13_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A3 += go[3];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[4] * *cnV[4];
+ RHS1 -= go[5] * *cnV[5];
+ m_A4 += gt[6];
+ m_A4 += gt[7];
+ m_A4 += gt[8];
+ m_A5 += go[6];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 -= go[7] * *cnV[7];
+ RHS2 -= go[8] * *cnV[8];
+ m_A6 += gt[9];
+ m_A7 += go[9];
+ double RHS3 = Idr[9];
+ m_A12 += gt[10];
+ m_A12 += gt[11];
+ m_A12 += gt[12];
+ m_A12 += gt[13];
+ m_A12 += gt[14];
+ m_A11 += go[10];
+ m_A10 += go[11];
+ m_A9 += go[12];
+ m_A8 += go[13];
+ double RHS4 = Idr[10];
+ RHS4 += Idr[11];
+ RHS4 += Idr[12];
+ RHS4 += Idr[13];
+ RHS4 += Idr[14];
+ RHS4 -= go[14] * *cnV[14];
+ const double f0 = 1.0 / m_A0;
+ const double f0_4 = -f0 * m_A8;
+ m_A12 += m_A1 * f0_4;
+ RHS4 += f0_4 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_4 = -f1 * m_A9;
+ m_A12 += m_A3 * f1_4;
+ RHS4 += f1_4 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_4 = -f2 * m_A10;
+ m_A12 += m_A5 * f2_4;
+ RHS4 += f2_4 * RHS2;
+ const double f3 = 1.0 / m_A6;
+ const double f3_4 = -f3 * m_A11;
+ m_A12 += m_A7 * f3_4;
+ RHS4 += f3_4 * RHS3;
+ V[4] = RHS4 / m_A12;
+ double tmp3 = 0.0;
+ tmp3 += m_A7 * V[4];
+ V[3] = (RHS3 - tmp3) / m_A6;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[4];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[4];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[4];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
+// brdrline
static void nl_gcr_59cb6bf7cb9d17dc_7_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
{
@@ -20656,6 +23593,221 @@ static void nl_gcr_6041272373b8603c_178_double_double(double * __restrict V, con
V[0] = (RHS0 - tmp0) / m_A0;
}
+// astrob
+static void nl_gcr_62464664b1c5aa1e_27_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A0 += gt[3];
+ m_A0 += gt[4];
+ m_A0 += gt[5];
+ m_A0 += gt[6];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 += Idr[3];
+ RHS0 += Idr[4];
+ RHS0 += Idr[5];
+ RHS0 += Idr[6];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ RHS0 -= go[3] * *cnV[3];
+ RHS0 -= go[4] * *cnV[4];
+ RHS0 -= go[5] * *cnV[5];
+ RHS0 -= go[6] * *cnV[6];
+ m_A2 += gt[7];
+ m_A2 += gt[8];
+ m_A2 += gt[9];
+ m_A4 += go[7];
+ m_A3 += go[8];
+ double RHS1 = Idr[7];
+ RHS1 += Idr[8];
+ RHS1 += Idr[9];
+ RHS1 -= go[9] * *cnV[9];
+ m_A5 += gt[10];
+ m_A5 += gt[11];
+ m_A5 += gt[12];
+ m_A5 += gt[13];
+ m_A5 += gt[14];
+ m_A5 += gt[15];
+ m_A5 += gt[16];
+ m_A6 += go[10];
+ double RHS2 = Idr[10];
+ RHS2 += Idr[11];
+ RHS2 += Idr[12];
+ RHS2 += Idr[13];
+ RHS2 += Idr[14];
+ RHS2 += Idr[15];
+ RHS2 += Idr[16];
+ RHS2 -= go[11] * *cnV[11];
+ RHS2 -= go[12] * *cnV[12];
+ RHS2 -= go[13] * *cnV[13];
+ RHS2 -= go[14] * *cnV[14];
+ RHS2 -= go[15] * *cnV[15];
+ RHS2 -= go[16] * *cnV[16];
+ m_A7 += gt[17];
+ m_A7 += gt[18];
+ m_A7 += gt[19];
+ m_A7 += gt[20];
+ m_A9 += go[17];
+ m_A10 += go[18];
+ m_A8 += go[19];
+ double RHS3 = Idr[17];
+ RHS3 += Idr[18];
+ RHS3 += Idr[19];
+ RHS3 += Idr[20];
+ RHS3 -= go[20] * *cnV[20];
+ m_A14 += gt[21];
+ m_A14 += gt[22];
+ m_A14 += gt[23];
+ m_A14 += gt[24];
+ m_A14 += gt[25];
+ m_A11 += go[21];
+ m_A13 += go[22];
+ m_A12 += go[23];
+ double RHS4 = Idr[21];
+ RHS4 += Idr[22];
+ RHS4 += Idr[23];
+ RHS4 += Idr[24];
+ RHS4 += Idr[25];
+ RHS4 -= go[24] * *cnV[24];
+ RHS4 -= go[25] * *cnV[25];
+ m_A19 += gt[26];
+ m_A19 += gt[27];
+ m_A19 += gt[28];
+ m_A20 += go[26];
+ m_A17 += go[27];
+ double RHS5 = Idr[26];
+ RHS5 += Idr[27];
+ RHS5 += Idr[28];
+ RHS5 -= go[28] * *cnV[28];
+ m_A26 += gt[29];
+ m_A26 += gt[30];
+ m_A26 += gt[31];
+ m_A26 += gt[32];
+ m_A26 += gt[33];
+ m_A26 += gt[34];
+ m_A26 += gt[35];
+ m_A26 += gt[36];
+ m_A22 += go[29];
+ m_A25 += go[30];
+ m_A23 += go[31];
+ m_A21 += go[32];
+ double RHS6 = Idr[29];
+ RHS6 += Idr[30];
+ RHS6 += Idr[31];
+ RHS6 += Idr[32];
+ RHS6 += Idr[33];
+ RHS6 += Idr[34];
+ RHS6 += Idr[35];
+ RHS6 += Idr[36];
+ RHS6 -= go[33] * *cnV[33];
+ RHS6 -= go[34] * *cnV[34];
+ RHS6 -= go[35] * *cnV[35];
+ RHS6 -= go[36] * *cnV[36];
+ const double f0 = 1.0 / m_A0;
+ const double f0_4 = -f0 * m_A11;
+ m_A12 += m_A1 * f0_4;
+ RHS4 += f0_4 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_4 = -f1 * m_A12;
+ m_A14 += m_A3 * f1_4;
+ m_A16 += m_A4 * f1_4;
+ RHS4 += f1_4 * RHS1;
+ const double f1_6 = -f1 * m_A21;
+ m_A24 += m_A3 * f1_6;
+ m_A26 += m_A4 * f1_6;
+ RHS6 += f1_6 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_6 = -f2 * m_A22;
+ m_A25 += m_A6 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_4 = -f3 * m_A13;
+ m_A14 += m_A8 * f3_4;
+ m_A15 += m_A9 * f3_4;
+ m_A16 += m_A10 * f3_4;
+ RHS4 += f3_4 * RHS3;
+ const double f3_5 = -f3 * m_A17;
+ m_A18 += m_A8 * f3_5;
+ m_A19 += m_A9 * f3_5;
+ m_A20 += m_A10 * f3_5;
+ RHS5 += f3_5 * RHS3;
+ const double f3_6 = -f3 * m_A23;
+ m_A24 += m_A8 * f3_6;
+ m_A25 += m_A9 * f3_6;
+ m_A26 += m_A10 * f3_6;
+ RHS6 += f3_6 * RHS3;
+ const double f4 = 1.0 / m_A14;
+ const double f4_5 = -f4 * m_A18;
+ m_A19 += m_A15 * f4_5;
+ m_A20 += m_A16 * f4_5;
+ RHS5 += f4_5 * RHS4;
+ const double f4_6 = -f4 * m_A24;
+ m_A25 += m_A15 * f4_6;
+ m_A26 += m_A16 * f4_6;
+ RHS6 += f4_6 * RHS4;
+ const double f5 = 1.0 / m_A19;
+ const double f5_6 = -f5 * m_A25;
+ m_A26 += m_A20 * f5_6;
+ RHS6 += f5_6 * RHS5;
+ V[6] = RHS6 / m_A26;
+ double tmp5 = 0.0;
+ tmp5 += m_A20 * V[6];
+ V[5] = (RHS5 - tmp5) / m_A19;
+ double tmp4 = 0.0;
+ tmp4 += m_A15 * V[5];
+ tmp4 += m_A16 * V[6];
+ V[4] = (RHS4 - tmp4) / m_A14;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[4];
+ tmp3 += m_A9 * V[5];
+ tmp3 += m_A10 * V[6];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[5];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[4];
+ tmp1 += m_A4 * V[6];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[1];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// solarq
static void nl_gcr_62612f71055b8fd4_303_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -28820,6 +31972,757 @@ static void nl_gcr_743595e64cee0a5e_112_double_double(double * __restrict V, con
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_75400df5d559a266_75_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A3 += go[3];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[4] * *cnV[4];
+ RHS1 -= go[5] * *cnV[5];
+ m_A4 += gt[6];
+ m_A4 += gt[7];
+ m_A4 += gt[8];
+ m_A4 += gt[9];
+ m_A5 += go[6];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 -= go[7] * *cnV[7];
+ RHS2 -= go[8] * *cnV[8];
+ RHS2 -= go[9] * *cnV[9];
+ m_A6 += gt[10];
+ m_A6 += gt[11];
+ m_A8 += go[10];
+ m_A7 += go[11];
+ double RHS3 = Idr[10];
+ RHS3 += Idr[11];
+ m_A9 += gt[12];
+ m_A9 += gt[13];
+ m_A9 += gt[14];
+ m_A10 += go[12];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ RHS4 += Idr[14];
+ RHS4 -= go[13] * *cnV[13];
+ RHS4 -= go[14] * *cnV[14];
+ m_A11 += gt[15];
+ m_A11 += gt[16];
+ m_A11 += gt[17];
+ m_A11 += gt[18];
+ m_A11 += gt[19];
+ m_A11 += gt[20];
+ m_A12 += go[15];
+ m_A15 += go[16];
+ m_A14 += go[17];
+ m_A13 += go[18];
+ double RHS5 = Idr[15];
+ RHS5 += Idr[16];
+ RHS5 += Idr[17];
+ RHS5 += Idr[18];
+ RHS5 += Idr[19];
+ RHS5 += Idr[20];
+ RHS5 -= go[19] * *cnV[19];
+ RHS5 -= go[20] * *cnV[20];
+ m_A16 += gt[21];
+ m_A16 += gt[22];
+ m_A16 += gt[23];
+ m_A16 += gt[24];
+ m_A16 += gt[25];
+ m_A16 += gt[26];
+ m_A16 += gt[27];
+ m_A18 += go[21];
+ m_A17 += go[22];
+ double RHS6 = Idr[21];
+ RHS6 += Idr[22];
+ RHS6 += Idr[23];
+ RHS6 += Idr[24];
+ RHS6 += Idr[25];
+ RHS6 += Idr[26];
+ RHS6 += Idr[27];
+ RHS6 -= go[23] * *cnV[23];
+ RHS6 -= go[24] * *cnV[24];
+ RHS6 -= go[25] * *cnV[25];
+ RHS6 -= go[26] * *cnV[26];
+ RHS6 -= go[27] * *cnV[27];
+ m_A19 += gt[28];
+ m_A19 += gt[29];
+ m_A19 += gt[30];
+ m_A19 += gt[31];
+ m_A20 += go[28];
+ double RHS7 = Idr[28];
+ RHS7 += Idr[29];
+ RHS7 += Idr[30];
+ RHS7 += Idr[31];
+ RHS7 -= go[29] * *cnV[29];
+ RHS7 -= go[30] * *cnV[30];
+ RHS7 -= go[31] * *cnV[31];
+ m_A22 += gt[32];
+ m_A22 += gt[33];
+ m_A22 += gt[34];
+ m_A22 += gt[35];
+ m_A22 += gt[36];
+ m_A22 += gt[37];
+ m_A22 += gt[38];
+ m_A23 += go[32];
+ m_A21 += go[33];
+ double RHS8 = Idr[32];
+ RHS8 += Idr[33];
+ RHS8 += Idr[34];
+ RHS8 += Idr[35];
+ RHS8 += Idr[36];
+ RHS8 += Idr[37];
+ RHS8 += Idr[38];
+ RHS8 -= go[34] * *cnV[34];
+ RHS8 -= go[35] * *cnV[35];
+ RHS8 -= go[36] * *cnV[36];
+ RHS8 -= go[37] * *cnV[37];
+ RHS8 -= go[38] * *cnV[38];
+ m_A25 += gt[39];
+ m_A25 += gt[40];
+ m_A25 += gt[41];
+ m_A24 += go[39];
+ m_A26 += go[40];
+ double RHS9 = Idr[39];
+ RHS9 += Idr[40];
+ RHS9 += Idr[41];
+ RHS9 -= go[41] * *cnV[41];
+ m_A28 += gt[42];
+ m_A28 += gt[43];
+ m_A28 += gt[44];
+ m_A28 += gt[45];
+ m_A28 += gt[46];
+ m_A28 += gt[47];
+ m_A28 += gt[48];
+ m_A29 += go[42];
+ m_A27 += go[43];
+ double RHS10 = Idr[42];
+ RHS10 += Idr[43];
+ RHS10 += Idr[44];
+ RHS10 += Idr[45];
+ RHS10 += Idr[46];
+ RHS10 += Idr[47];
+ RHS10 += Idr[48];
+ RHS10 -= go[44] * *cnV[44];
+ RHS10 -= go[45] * *cnV[45];
+ RHS10 -= go[46] * *cnV[46];
+ RHS10 -= go[47] * *cnV[47];
+ RHS10 -= go[48] * *cnV[48];
+ m_A33 += gt[49];
+ m_A33 += gt[50];
+ m_A33 += gt[51];
+ m_A31 += go[49];
+ m_A30 += go[50];
+ m_A35 += go[51];
+ double RHS11 = Idr[49];
+ RHS11 += Idr[50];
+ RHS11 += Idr[51];
+ m_A40 += gt[52];
+ m_A40 += gt[53];
+ m_A40 += gt[54];
+ m_A42 += go[52];
+ m_A37 += go[53];
+ double RHS12 = Idr[52];
+ RHS12 += Idr[53];
+ RHS12 += Idr[54];
+ RHS12 -= go[54] * *cnV[54];
+ m_A44 += gt[55];
+ m_A44 += gt[56];
+ m_A45 += go[55];
+ m_A43 += go[56];
+ double RHS13 = Idr[55];
+ RHS13 += Idr[56];
+ m_A47 += gt[57];
+ m_A47 += gt[58];
+ m_A47 += gt[59];
+ m_A46 += go[57];
+ m_A48 += go[58];
+ double RHS14 = Idr[57];
+ RHS14 += Idr[58];
+ RHS14 += Idr[59];
+ RHS14 -= go[59] * *cnV[59];
+ m_A52 += gt[60];
+ m_A52 += gt[61];
+ m_A52 += gt[62];
+ m_A52 += gt[63];
+ m_A51 += go[60];
+ m_A50 += go[61];
+ m_A49 += go[62];
+ double RHS15 = Idr[60];
+ RHS15 += Idr[61];
+ RHS15 += Idr[62];
+ RHS15 += Idr[63];
+ RHS15 -= go[63] * *cnV[63];
+ m_A59 += gt[64];
+ m_A59 += gt[65];
+ m_A59 += gt[66];
+ m_A59 += gt[67];
+ m_A59 += gt[68];
+ m_A55 += go[64];
+ m_A56 += go[65];
+ m_A54 += go[66];
+ double RHS16 = Idr[64];
+ RHS16 += Idr[65];
+ RHS16 += Idr[66];
+ RHS16 += Idr[67];
+ RHS16 += Idr[68];
+ RHS16 -= go[67] * *cnV[67];
+ RHS16 -= go[68] * *cnV[68];
+ m_A65 += gt[69];
+ m_A65 += gt[70];
+ m_A65 += gt[71];
+ m_A65 += gt[72];
+ m_A65 += gt[73];
+ m_A61 += go[69];
+ m_A66 += go[70];
+ m_A63 += go[71];
+ double RHS17 = Idr[69];
+ RHS17 += Idr[70];
+ RHS17 += Idr[71];
+ RHS17 += Idr[72];
+ RHS17 += Idr[73];
+ RHS17 -= go[72] * *cnV[72];
+ RHS17 -= go[73] * *cnV[73];
+ m_A74 += gt[74];
+ m_A74 += gt[75];
+ m_A74 += gt[76];
+ m_A74 += gt[77];
+ m_A73 += go[74];
+ m_A71 += go[75];
+ m_A70 += go[76];
+ m_A67 += go[77];
+ double RHS18 = Idr[74];
+ RHS18 += Idr[75];
+ RHS18 += Idr[76];
+ RHS18 += Idr[77];
+ const double f0 = 1.0 / m_A0;
+ const double f0_13 = -f0 * m_A43;
+ m_A44 += m_A1 * f0_13;
+ RHS13 += f0_13 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_8 = -f1 * m_A21;
+ m_A23 += m_A3 * f1_8;
+ RHS8 += f1_8 * RHS1;
+ const double f1_15 = -f1 * m_A49;
+ m_A52 += m_A3 * f1_15;
+ RHS15 += f1_15 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_9 = -f2 * m_A24;
+ m_A25 += m_A5 * f2_9;
+ RHS9 += f2_9 * RHS2;
+ const double f3 = 1.0 / m_A6;
+ const double f3_15 = -f3 * m_A50;
+ m_A52 += m_A7 * f3_15;
+ m_A53 += m_A8 * f3_15;
+ RHS15 += f3_15 * RHS3;
+ const double f3_16 = -f3 * m_A54;
+ m_A58 += m_A7 * f3_16;
+ m_A59 += m_A8 * f3_16;
+ RHS16 += f3_16 * RHS3;
+ const double f4 = 1.0 / m_A9;
+ const double f4_10 = -f4 * m_A27;
+ m_A29 += m_A10 * f4_10;
+ RHS10 += f4_10 * RHS4;
+ const double f4_11 = -f4 * m_A30;
+ m_A33 += m_A10 * f4_11;
+ RHS11 += f4_11 * RHS4;
+ const double f5 = 1.0 / m_A11;
+ const double f5_11 = -f5 * m_A31;
+ m_A32 += m_A12 * f5_11;
+ m_A33 += m_A13 * f5_11;
+ m_A34 += m_A14 * f5_11;
+ m_A36 += m_A15 * f5_11;
+ RHS11 += f5_11 * RHS5;
+ const double f5_12 = -f5 * m_A37;
+ m_A38 += m_A12 * f5_12;
+ m_A39 += m_A13 * f5_12;
+ m_A40 += m_A14 * f5_12;
+ m_A42 += m_A15 * f5_12;
+ RHS12 += f5_12 * RHS5;
+ const double f5_18 = -f5 * m_A67;
+ m_A68 += m_A12 * f5_18;
+ m_A69 += m_A13 * f5_18;
+ m_A70 += m_A14 * f5_18;
+ m_A74 += m_A15 * f5_18;
+ RHS18 += f5_18 * RHS5;
+ const double f6 = 1.0 / m_A16;
+ const double f6_17 = -f6 * m_A61;
+ m_A62 += m_A17 * f6_17;
+ m_A66 += m_A18 * f6_17;
+ RHS17 += f6_17 * RHS6;
+ const double f7 = 1.0 / m_A19;
+ const double f7_14 = -f7 * m_A46;
+ m_A47 += m_A20 * f7_14;
+ RHS14 += f7_14 * RHS7;
+ const double f8 = 1.0 / m_A22;
+ const double f8_16 = -f8 * m_A55;
+ m_A58 += m_A23 * f8_16;
+ RHS16 += f8_16 * RHS8;
+ const double f9 = 1.0 / m_A25;
+ const double f9_15 = -f9 * m_A51;
+ m_A52 += m_A26 * f9_15;
+ RHS15 += f9_15 * RHS9;
+ const double f10 = 1.0 / m_A28;
+ const double f10_11 = -f10 * m_A32;
+ m_A33 += m_A29 * f10_11;
+ RHS11 += f10_11 * RHS10;
+ const double f10_12 = -f10 * m_A38;
+ m_A39 += m_A29 * f10_12;
+ RHS12 += f10_12 * RHS10;
+ const double f10_18 = -f10 * m_A68;
+ m_A69 += m_A29 * f10_18;
+ RHS18 += f10_18 * RHS10;
+ const double f11 = 1.0 / m_A33;
+ const double f11_12 = -f11 * m_A39;
+ m_A40 += m_A34 * f11_12;
+ m_A41 += m_A35 * f11_12;
+ m_A42 += m_A36 * f11_12;
+ RHS12 += f11_12 * RHS11;
+ const double f11_16 = -f11 * m_A56;
+ m_A57 += m_A34 * f11_16;
+ m_A59 += m_A35 * f11_16;
+ m_A60 += m_A36 * f11_16;
+ RHS16 += f11_16 * RHS11;
+ const double f11_18 = -f11 * m_A69;
+ m_A70 += m_A34 * f11_18;
+ m_A72 += m_A35 * f11_18;
+ m_A74 += m_A36 * f11_18;
+ RHS18 += f11_18 * RHS11;
+ const double f12 = 1.0 / m_A40;
+ const double f12_16 = -f12 * m_A57;
+ m_A59 += m_A41 * f12_16;
+ m_A60 += m_A42 * f12_16;
+ RHS16 += f12_16 * RHS12;
+ const double f12_17 = -f12 * m_A62;
+ m_A64 += m_A41 * f12_17;
+ m_A66 += m_A42 * f12_17;
+ RHS17 += f12_17 * RHS12;
+ const double f12_18 = -f12 * m_A70;
+ m_A72 += m_A41 * f12_18;
+ m_A74 += m_A42 * f12_18;
+ RHS18 += f12_18 * RHS12;
+ const double f13 = 1.0 / m_A44;
+ const double f13_17 = -f13 * m_A63;
+ m_A65 += m_A45 * f13_17;
+ RHS17 += f13_17 * RHS13;
+ const double f14 = 1.0 / m_A47;
+ const double f14_18 = -f14 * m_A71;
+ m_A74 += m_A48 * f14_18;
+ RHS18 += f14_18 * RHS14;
+ const double f15 = 1.0 / m_A52;
+ const double f15_16 = -f15 * m_A58;
+ m_A59 += m_A53 * f15_16;
+ RHS16 += f15_16 * RHS15;
+ const double f16 = 1.0 / m_A59;
+ const double f16_17 = -f16 * m_A64;
+ m_A66 += m_A60 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f16_18 = -f16 * m_A72;
+ m_A74 += m_A60 * f16_18;
+ RHS18 += f16_18 * RHS16;
+ const double f17 = 1.0 / m_A65;
+ const double f17_18 = -f17 * m_A73;
+ m_A74 += m_A66 * f17_18;
+ RHS18 += f17_18 * RHS17;
+ V[18] = RHS18 / m_A74;
+ double tmp17 = 0.0;
+ tmp17 += m_A66 * V[18];
+ V[17] = (RHS17 - tmp17) / m_A65;
+ double tmp16 = 0.0;
+ tmp16 += m_A60 * V[18];
+ V[16] = (RHS16 - tmp16) / m_A59;
+ double tmp15 = 0.0;
+ tmp15 += m_A53 * V[16];
+ V[15] = (RHS15 - tmp15) / m_A52;
+ double tmp14 = 0.0;
+ tmp14 += m_A48 * V[18];
+ V[14] = (RHS14 - tmp14) / m_A47;
+ double tmp13 = 0.0;
+ tmp13 += m_A45 * V[17];
+ V[13] = (RHS13 - tmp13) / m_A44;
+ double tmp12 = 0.0;
+ tmp12 += m_A41 * V[16];
+ tmp12 += m_A42 * V[18];
+ V[12] = (RHS12 - tmp12) / m_A40;
+ double tmp11 = 0.0;
+ tmp11 += m_A34 * V[12];
+ tmp11 += m_A35 * V[16];
+ tmp11 += m_A36 * V[18];
+ V[11] = (RHS11 - tmp11) / m_A33;
+ double tmp10 = 0.0;
+ tmp10 += m_A29 * V[11];
+ V[10] = (RHS10 - tmp10) / m_A28;
+ double tmp9 = 0.0;
+ tmp9 += m_A26 * V[15];
+ V[9] = (RHS9 - tmp9) / m_A25;
+ double tmp8 = 0.0;
+ tmp8 += m_A23 * V[15];
+ V[8] = (RHS8 - tmp8) / m_A22;
+ double tmp7 = 0.0;
+ tmp7 += m_A20 * V[14];
+ V[7] = (RHS7 - tmp7) / m_A19;
+ double tmp6 = 0.0;
+ tmp6 += m_A17 * V[12];
+ tmp6 += m_A18 * V[18];
+ V[6] = (RHS6 - tmp6) / m_A16;
+ double tmp5 = 0.0;
+ tmp5 += m_A12 * V[10];
+ tmp5 += m_A13 * V[11];
+ tmp5 += m_A14 * V[12];
+ tmp5 += m_A15 * V[18];
+ V[5] = (RHS5 - tmp5) / m_A11;
+ double tmp4 = 0.0;
+ tmp4 += m_A10 * V[11];
+ V[4] = (RHS4 - tmp4) / m_A9;
+ double tmp3 = 0.0;
+ tmp3 += m_A7 * V[15];
+ tmp3 += m_A8 * V[16];
+ V[3] = (RHS3 - tmp3) / m_A6;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[9];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[15];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[13];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
+// frogs
+static void nl_gcr_75852e71cc632a65_33_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A4 += go[2];
+ m_A3 += go[3];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[4] * *cnV[4];
+ RHS1 -= go[5] * *cnV[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A5 += gt[8];
+ m_A7 += go[6];
+ m_A6 += go[7];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 -= go[8] * *cnV[8];
+ m_A8 += gt[9];
+ m_A8 += gt[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A8 += gt[15];
+ m_A9 += go[9];
+ double RHS3 = Idr[9];
+ RHS3 += Idr[10];
+ RHS3 += Idr[11];
+ RHS3 += Idr[12];
+ RHS3 += Idr[13];
+ RHS3 += Idr[14];
+ RHS3 += Idr[15];
+ RHS3 -= go[10] * *cnV[10];
+ RHS3 -= go[11] * *cnV[11];
+ RHS3 -= go[12] * *cnV[12];
+ RHS3 -= go[13] * *cnV[13];
+ RHS3 -= go[14] * *cnV[14];
+ RHS3 -= go[15] * *cnV[15];
+ m_A10 += gt[16];
+ m_A10 += gt[17];
+ m_A10 += gt[18];
+ m_A11 += go[16];
+ m_A12 += go[17];
+ double RHS4 = Idr[16];
+ RHS4 += Idr[17];
+ RHS4 += Idr[18];
+ RHS4 -= go[18] * *cnV[18];
+ m_A14 += gt[19];
+ m_A14 += gt[20];
+ m_A14 += gt[21];
+ m_A16 += go[19];
+ m_A13 += go[20];
+ double RHS5 = Idr[19];
+ RHS5 += Idr[20];
+ RHS5 += Idr[21];
+ RHS5 -= go[21] * *cnV[21];
+ m_A21 += gt[22];
+ m_A21 += gt[23];
+ m_A21 += gt[24];
+ m_A21 += gt[25];
+ m_A21 += gt[26];
+ m_A21 += gt[27];
+ m_A21 += gt[28];
+ m_A21 += gt[29];
+ m_A19 += go[22];
+ m_A22 += go[23];
+ m_A18 += go[24];
+ m_A17 += go[25];
+ double RHS6 = Idr[22];
+ RHS6 += Idr[23];
+ RHS6 += Idr[24];
+ RHS6 += Idr[25];
+ RHS6 += Idr[26];
+ RHS6 += Idr[27];
+ RHS6 += Idr[28];
+ RHS6 += Idr[29];
+ RHS6 -= go[26] * *cnV[26];
+ RHS6 -= go[27] * *cnV[27];
+ RHS6 -= go[28] * *cnV[28];
+ RHS6 -= go[29] * *cnV[29];
+ m_A25 += gt[30];
+ m_A25 += gt[31];
+ m_A25 += gt[32];
+ m_A25 += gt[33];
+ m_A25 += gt[34];
+ m_A23 += go[30];
+ m_A24 += go[31];
+ m_A26 += go[32];
+ double RHS7 = Idr[30];
+ RHS7 += Idr[31];
+ RHS7 += Idr[32];
+ RHS7 += Idr[33];
+ RHS7 += Idr[34];
+ RHS7 -= go[33] * *cnV[33];
+ RHS7 -= go[34] * *cnV[34];
+ m_A32 += gt[35];
+ m_A32 += gt[36];
+ m_A32 += gt[37];
+ m_A32 += gt[38];
+ m_A32 += gt[39];
+ m_A31 += go[35];
+ m_A28 += go[36];
+ m_A27 += go[37];
+ m_A30 += go[38];
+ m_A29 += go[39];
+ double RHS8 = Idr[35];
+ RHS8 += Idr[36];
+ RHS8 += Idr[37];
+ RHS8 += Idr[38];
+ RHS8 += Idr[39];
+ const double f0 = 1.0 / m_A0;
+ const double f0_6 = -f0 * m_A17;
+ m_A21 += m_A1 * f0_6;
+ RHS6 += f0_6 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_5 = -f1 * m_A13;
+ m_A14 += m_A3 * f1_5;
+ m_A15 += m_A4 * f1_5;
+ RHS5 += f1_5 * RHS1;
+ const double f1_6 = -f1 * m_A18;
+ m_A20 += m_A3 * f1_6;
+ m_A21 += m_A4 * f1_6;
+ RHS6 += f1_6 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_6 = -f2 * m_A19;
+ m_A21 += m_A6 * f2_6;
+ m_A22 += m_A7 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f2_8 = -f2 * m_A27;
+ m_A30 += m_A6 * f2_8;
+ m_A32 += m_A7 * f2_8;
+ RHS8 += f2_8 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_7 = -f3 * m_A23;
+ m_A24 += m_A9 * f3_7;
+ RHS7 += f3_7 * RHS3;
+ const double f4 = 1.0 / m_A10;
+ const double f4_7 = -f4 * m_A24;
+ m_A25 += m_A11 * f4_7;
+ m_A26 += m_A12 * f4_7;
+ RHS7 += f4_7 * RHS4;
+ const double f4_8 = -f4 * m_A28;
+ m_A31 += m_A11 * f4_8;
+ m_A32 += m_A12 * f4_8;
+ RHS8 += f4_8 * RHS4;
+ const double f5 = 1.0 / m_A14;
+ const double f5_6 = -f5 * m_A20;
+ m_A21 += m_A15 * f5_6;
+ m_A22 += m_A16 * f5_6;
+ RHS6 += f5_6 * RHS5;
+ const double f5_8 = -f5 * m_A29;
+ m_A30 += m_A15 * f5_8;
+ m_A32 += m_A16 * f5_8;
+ RHS8 += f5_8 * RHS5;
+ const double f6 = 1.0 / m_A21;
+ const double f6_8 = -f6 * m_A30;
+ m_A32 += m_A22 * f6_8;
+ RHS8 += f6_8 * RHS6;
+ const double f7 = 1.0 / m_A25;
+ const double f7_8 = -f7 * m_A31;
+ m_A32 += m_A26 * f7_8;
+ RHS8 += f7_8 * RHS7;
+ V[8] = RHS8 / m_A32;
+ double tmp7 = 0.0;
+ tmp7 += m_A26 * V[8];
+ V[7] = (RHS7 - tmp7) / m_A25;
+ double tmp6 = 0.0;
+ tmp6 += m_A22 * V[8];
+ V[6] = (RHS6 - tmp6) / m_A21;
+ double tmp5 = 0.0;
+ tmp5 += m_A15 * V[6];
+ tmp5 += m_A16 * V[8];
+ V[5] = (RHS5 - tmp5) / m_A14;
+ double tmp4 = 0.0;
+ tmp4 += m_A11 * V[7];
+ tmp4 += m_A12 * V[8];
+ V[4] = (RHS4 - tmp4) / m_A10;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[4];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[6];
+ tmp2 += m_A7 * V[8];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[5];
+ tmp1 += m_A4 * V[6];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[6];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// ripoff
static void nl_gcr_76c9e236353caed1_35_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -30817,6 +34720,89 @@ static void nl_gcr_80b4b1e5cc58d303_29_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// frogs
+static void nl_gcr_815733e3f2e05029_9_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A0 += gt[3];
+ m_A0 += gt[4];
+ m_A2 += go[0];
+ m_A1 += go[1];
+ m_A1 += go[2];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 += Idr[3];
+ RHS0 += Idr[4];
+ RHS0 -= go[3] * *cnV[3];
+ RHS0 -= go[4] * *cnV[4];
+ m_A4 += gt[5];
+ m_A4 += gt[6];
+ m_A4 += gt[7];
+ m_A4 += gt[8];
+ m_A4 += gt[9];
+ m_A4 += gt[10];
+ m_A5 += go[5];
+ m_A5 += go[6];
+ m_A3 += go[7];
+ m_A3 += go[8];
+ double RHS1 = Idr[5];
+ RHS1 += Idr[6];
+ RHS1 += Idr[7];
+ RHS1 += Idr[8];
+ RHS1 += Idr[9];
+ RHS1 += Idr[10];
+ RHS1 -= go[9] * *cnV[9];
+ RHS1 -= go[10] * *cnV[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A7 += go[11];
+ m_A7 += go[12];
+ m_A6 += go[13];
+ double RHS2 = Idr[11];
+ RHS2 += Idr[12];
+ RHS2 += Idr[13];
+ RHS2 += Idr[14];
+ RHS2 -= go[14] * *cnV[14];
+ const double f0 = 1.0 / m_A0;
+ const double f0_1 = -f0 * m_A3;
+ m_A4 += m_A1 * f0_1;
+ m_A5 += m_A2 * f0_1;
+ RHS1 += f0_1 * RHS0;
+ const double f0_2 = -f0 * m_A6;
+ m_A7 += m_A1 * f0_2;
+ m_A8 += m_A2 * f0_2;
+ RHS2 += f0_2 * RHS0;
+ const double f1 = 1.0 / m_A4;
+ const double f1_2 = -f1 * m_A7;
+ m_A8 += m_A5 * f1_2;
+ RHS2 += f1_2 * RHS1;
+ V[2] = RHS2 / m_A8;
+ double tmp1 = 0.0;
+ tmp1 += m_A5 * V[2];
+ V[1] = (RHS1 - tmp1) / m_A4;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[1];
+ tmp0 += m_A2 * V[2];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// elim
static void nl_gcr_81f40a54af2ca202_10_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -30902,6 +34888,75 @@ static void nl_gcr_81f40a54af2ca202_10_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// frogs
+static void nl_gcr_84425fea9033e75d_7_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A3 += go[3];
+ m_A3 += go[4];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 -= go[5] * *cnV[5];
+ RHS1 -= go[6] * *cnV[6];
+ m_A6 += gt[7];
+ m_A6 += gt[8];
+ m_A6 += gt[9];
+ m_A6 += gt[10];
+ m_A6 += gt[11];
+ m_A6 += gt[12];
+ m_A5 += go[7];
+ m_A5 += go[8];
+ m_A4 += go[9];
+ double RHS2 = Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 += Idr[11];
+ RHS2 += Idr[12];
+ RHS2 -= go[10] * *cnV[10];
+ RHS2 -= go[11] * *cnV[11];
+ RHS2 -= go[12] * *cnV[12];
+ const double f0 = 1.0 / m_A0;
+ const double f0_2 = -f0 * m_A4;
+ m_A6 += m_A1 * f0_2;
+ RHS2 += f0_2 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_2 = -f1 * m_A5;
+ m_A6 += m_A3 * f1_2;
+ RHS2 += f1_2 * RHS1;
+ V[2] = RHS2 / m_A6;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[2];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[2];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// sundance
static void nl_gcr_8446e63d7842f6a6_70_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -41554,6 +45609,1130 @@ static void nl_gcr_aa07266ef5d420d1_11_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_aa68b74ffdea9bd8_47_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A2 += gt[7];
+ m_A2 += gt[8];
+ m_A3 += go[2];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 += Idr[7];
+ RHS1 += Idr[8];
+ RHS1 -= go[3] * *cnV[3];
+ RHS1 -= go[4] * *cnV[4];
+ RHS1 -= go[5] * *cnV[5];
+ RHS1 -= go[6] * *cnV[6];
+ RHS1 -= go[7] * *cnV[7];
+ RHS1 -= go[8] * *cnV[8];
+ m_A4 += gt[9];
+ m_A4 += gt[10];
+ m_A4 += gt[11];
+ m_A6 += go[9];
+ m_A5 += go[10];
+ double RHS2 = Idr[9];
+ RHS2 += Idr[10];
+ RHS2 += Idr[11];
+ RHS2 -= go[11] * *cnV[11];
+ m_A7 += gt[12];
+ m_A7 += gt[13];
+ m_A7 += gt[14];
+ m_A8 += go[12];
+ m_A9 += go[13];
+ double RHS3 = Idr[12];
+ RHS3 += Idr[13];
+ RHS3 += Idr[14];
+ RHS3 -= go[14] * *cnV[14];
+ m_A10 += gt[15];
+ m_A10 += gt[16];
+ m_A10 += gt[17];
+ m_A10 += gt[18];
+ m_A10 += gt[19];
+ m_A10 += gt[20];
+ m_A13 += go[15];
+ m_A12 += go[16];
+ m_A11 += go[17];
+ m_A14 += go[18];
+ double RHS4 = Idr[15];
+ RHS4 += Idr[16];
+ RHS4 += Idr[17];
+ RHS4 += Idr[18];
+ RHS4 += Idr[19];
+ RHS4 += Idr[20];
+ RHS4 -= go[19] * *cnV[19];
+ RHS4 -= go[20] * *cnV[20];
+ m_A17 += gt[21];
+ m_A17 += gt[22];
+ m_A16 += go[21];
+ m_A15 += go[22];
+ double RHS5 = Idr[21];
+ RHS5 += Idr[22];
+ m_A21 += gt[23];
+ m_A21 += gt[24];
+ m_A21 += gt[25];
+ m_A20 += go[23];
+ m_A19 += go[24];
+ double RHS6 = Idr[23];
+ RHS6 += Idr[24];
+ RHS6 += Idr[25];
+ RHS6 -= go[25] * *cnV[25];
+ m_A28 += gt[26];
+ m_A28 += gt[27];
+ m_A28 += gt[28];
+ m_A28 += gt[29];
+ m_A28 += gt[30];
+ m_A25 += go[26];
+ m_A29 += go[27];
+ m_A26 += go[28];
+ double RHS7 = Idr[26];
+ RHS7 += Idr[27];
+ RHS7 += Idr[28];
+ RHS7 += Idr[29];
+ RHS7 += Idr[30];
+ RHS7 -= go[29] * *cnV[29];
+ RHS7 -= go[30] * *cnV[30];
+ m_A32 += gt[31];
+ m_A32 += gt[32];
+ m_A32 += gt[33];
+ m_A30 += go[31];
+ double RHS8 = Idr[31];
+ RHS8 += Idr[32];
+ RHS8 += Idr[33];
+ RHS8 -= go[32] * *cnV[32];
+ RHS8 -= go[33] * *cnV[33];
+ m_A38 += gt[34];
+ m_A38 += gt[35];
+ m_A38 += gt[36];
+ m_A38 += gt[37];
+ m_A38 += gt[38];
+ m_A38 += gt[39];
+ m_A38 += gt[40];
+ m_A36 += go[34];
+ m_A35 += go[35];
+ double RHS9 = Idr[34];
+ RHS9 += Idr[35];
+ RHS9 += Idr[36];
+ RHS9 += Idr[37];
+ RHS9 += Idr[38];
+ RHS9 += Idr[39];
+ RHS9 += Idr[40];
+ RHS9 -= go[36] * *cnV[36];
+ RHS9 -= go[37] * *cnV[37];
+ RHS9 -= go[38] * *cnV[38];
+ RHS9 -= go[39] * *cnV[39];
+ RHS9 -= go[40] * *cnV[40];
+ m_A46 += gt[41];
+ m_A46 += gt[42];
+ m_A46 += gt[43];
+ m_A41 += go[41];
+ m_A40 += go[42];
+ m_A43 += go[43];
+ double RHS10 = Idr[41];
+ RHS10 += Idr[42];
+ RHS10 += Idr[43];
+ const double f0 = 1.0 / m_A0;
+ const double f0_5 = -f0 * m_A15;
+ m_A17 += m_A1 * f0_5;
+ RHS5 += f0_5 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_7 = -f1 * m_A25;
+ m_A26 += m_A3 * f1_7;
+ RHS7 += f1_7 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_5 = -f2 * m_A16;
+ m_A17 += m_A5 * f2_5;
+ m_A18 += m_A6 * f2_5;
+ RHS5 += f2_5 * RHS2;
+ const double f2_7 = -f2 * m_A26;
+ m_A27 += m_A5 * f2_7;
+ m_A28 += m_A6 * f2_7;
+ RHS7 += f2_7 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_6 = -f3 * m_A19;
+ m_A21 += m_A8 * f3_6;
+ m_A24 += m_A9 * f3_6;
+ RHS6 += f3_6 * RHS3;
+ const double f3_9 = -f3 * m_A35;
+ m_A36 += m_A8 * f3_9;
+ m_A39 += m_A9 * f3_9;
+ RHS9 += f3_9 * RHS3;
+ const double f3_10 = -f3 * m_A40;
+ m_A42 += m_A8 * f3_10;
+ m_A46 += m_A9 * f3_10;
+ RHS10 += f3_10 * RHS3;
+ const double f4 = 1.0 / m_A10;
+ const double f4_6 = -f4 * m_A20;
+ m_A21 += m_A11 * f4_6;
+ m_A22 += m_A12 * f4_6;
+ m_A23 += m_A13 * f4_6;
+ m_A24 += m_A14 * f4_6;
+ RHS6 += f4_6 * RHS4;
+ const double f4_8 = -f4 * m_A30;
+ m_A31 += m_A11 * f4_8;
+ m_A32 += m_A12 * f4_8;
+ m_A33 += m_A13 * f4_8;
+ m_A34 += m_A14 * f4_8;
+ RHS8 += f4_8 * RHS4;
+ const double f4_10 = -f4 * m_A41;
+ m_A42 += m_A11 * f4_10;
+ m_A44 += m_A12 * f4_10;
+ m_A45 += m_A13 * f4_10;
+ m_A46 += m_A14 * f4_10;
+ RHS10 += f4_10 * RHS4;
+ const double f5 = 1.0 / m_A17;
+ const double f5_7 = -f5 * m_A27;
+ m_A28 += m_A18 * f5_7;
+ RHS7 += f5_7 * RHS5;
+ const double f6 = 1.0 / m_A21;
+ const double f6_8 = -f6 * m_A31;
+ m_A32 += m_A22 * f6_8;
+ m_A33 += m_A23 * f6_8;
+ m_A34 += m_A24 * f6_8;
+ RHS8 += f6_8 * RHS6;
+ const double f6_9 = -f6 * m_A36;
+ m_A37 += m_A22 * f6_9;
+ m_A38 += m_A23 * f6_9;
+ m_A39 += m_A24 * f6_9;
+ RHS9 += f6_9 * RHS6;
+ const double f6_10 = -f6 * m_A42;
+ m_A44 += m_A22 * f6_10;
+ m_A45 += m_A23 * f6_10;
+ m_A46 += m_A24 * f6_10;
+ RHS10 += f6_10 * RHS6;
+ const double f7 = 1.0 / m_A28;
+ const double f7_10 = -f7 * m_A43;
+ m_A46 += m_A29 * f7_10;
+ RHS10 += f7_10 * RHS7;
+ const double f8 = 1.0 / m_A32;
+ const double f8_9 = -f8 * m_A37;
+ m_A38 += m_A33 * f8_9;
+ m_A39 += m_A34 * f8_9;
+ RHS9 += f8_9 * RHS8;
+ const double f8_10 = -f8 * m_A44;
+ m_A45 += m_A33 * f8_10;
+ m_A46 += m_A34 * f8_10;
+ RHS10 += f8_10 * RHS8;
+ const double f9 = 1.0 / m_A38;
+ const double f9_10 = -f9 * m_A45;
+ m_A46 += m_A39 * f9_10;
+ RHS10 += f9_10 * RHS9;
+ V[10] = RHS10 / m_A46;
+ double tmp9 = 0.0;
+ tmp9 += m_A39 * V[10];
+ V[9] = (RHS9 - tmp9) / m_A38;
+ double tmp8 = 0.0;
+ tmp8 += m_A33 * V[9];
+ tmp8 += m_A34 * V[10];
+ V[8] = (RHS8 - tmp8) / m_A32;
+ double tmp7 = 0.0;
+ tmp7 += m_A29 * V[10];
+ V[7] = (RHS7 - tmp7) / m_A28;
+ double tmp6 = 0.0;
+ tmp6 += m_A22 * V[8];
+ tmp6 += m_A23 * V[9];
+ tmp6 += m_A24 * V[10];
+ V[6] = (RHS6 - tmp6) / m_A21;
+ double tmp5 = 0.0;
+ tmp5 += m_A18 * V[7];
+ V[5] = (RHS5 - tmp5) / m_A17;
+ double tmp4 = 0.0;
+ tmp4 += m_A11 * V[6];
+ tmp4 += m_A12 * V[8];
+ tmp4 += m_A13 * V[9];
+ tmp4 += m_A14 * V[10];
+ V[4] = (RHS4 - tmp4) / m_A10;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[6];
+ tmp3 += m_A9 * V[10];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[5];
+ tmp2 += m_A6 * V[7];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[2];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[5];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
+// frogs
+static void nl_gcr_ab8d1ff6aa7499d8_119_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ double m_A89(0.0);
+ double m_A90(0.0);
+ double m_A91(0.0);
+ double m_A92(0.0);
+ double m_A93(0.0);
+ double m_A94(0.0);
+ double m_A95(0.0);
+ double m_A96(0.0);
+ double m_A97(0.0);
+ double m_A98(0.0);
+ double m_A99(0.0);
+ double m_A100(0.0);
+ double m_A101(0.0);
+ double m_A102(0.0);
+ double m_A103(0.0);
+ double m_A104(0.0);
+ double m_A105(0.0);
+ double m_A106(0.0);
+ double m_A107(0.0);
+ double m_A108(0.0);
+ double m_A109(0.0);
+ double m_A110(0.0);
+ double m_A111(0.0);
+ double m_A112(0.0);
+ double m_A113(0.0);
+ double m_A114(0.0);
+ double m_A115(0.0);
+ double m_A116(0.0);
+ double m_A117(0.0);
+ double m_A118(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A0 += gt[3];
+ m_A2 += go[0];
+ m_A1 += go[1];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 += Idr[3];
+ RHS0 -= go[2] * *cnV[2];
+ RHS0 -= go[3] * *cnV[3];
+ m_A3 += gt[4];
+ m_A3 += gt[5];
+ m_A4 += go[4];
+ double RHS1 = Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[5] * *cnV[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A5 += gt[8];
+ m_A5 += gt[9];
+ m_A5 += gt[10];
+ m_A5 += gt[11];
+ m_A5 += gt[12];
+ m_A6 += go[6];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 += Idr[11];
+ RHS2 += Idr[12];
+ RHS2 -= go[7] * *cnV[7];
+ RHS2 -= go[8] * *cnV[8];
+ RHS2 -= go[9] * *cnV[9];
+ RHS2 -= go[10] * *cnV[10];
+ RHS2 -= go[11] * *cnV[11];
+ RHS2 -= go[12] * *cnV[12];
+ m_A7 += gt[13];
+ m_A7 += gt[14];
+ m_A7 += gt[15];
+ m_A7 += gt[16];
+ m_A10 += go[13];
+ m_A9 += go[14];
+ m_A8 += go[15];
+ double RHS3 = Idr[13];
+ RHS3 += Idr[14];
+ RHS3 += Idr[15];
+ RHS3 += Idr[16];
+ RHS3 -= go[16] * *cnV[16];
+ m_A11 += gt[17];
+ m_A11 += gt[18];
+ m_A11 += gt[19];
+ m_A11 += gt[20];
+ m_A11 += gt[21];
+ m_A11 += gt[22];
+ m_A14 += go[17];
+ m_A14 += go[18];
+ m_A13 += go[19];
+ m_A13 += go[20];
+ m_A12 += go[21];
+ double RHS4 = Idr[17];
+ RHS4 += Idr[18];
+ RHS4 += Idr[19];
+ RHS4 += Idr[20];
+ RHS4 += Idr[21];
+ RHS4 += Idr[22];
+ RHS4 -= go[22] * *cnV[22];
+ m_A15 += gt[23];
+ m_A15 += gt[24];
+ m_A15 += gt[25];
+ m_A15 += gt[26];
+ m_A15 += gt[27];
+ m_A15 += gt[28];
+ m_A18 += go[23];
+ m_A18 += go[24];
+ m_A17 += go[25];
+ m_A17 += go[26];
+ m_A16 += go[27];
+ double RHS5 = Idr[23];
+ RHS5 += Idr[24];
+ RHS5 += Idr[25];
+ RHS5 += Idr[26];
+ RHS5 += Idr[27];
+ RHS5 += Idr[28];
+ RHS5 -= go[28] * *cnV[28];
+ m_A19 += gt[29];
+ m_A19 += gt[30];
+ m_A20 += go[29];
+ m_A21 += go[30];
+ double RHS6 = Idr[29];
+ RHS6 += Idr[30];
+ m_A22 += gt[31];
+ m_A22 += gt[32];
+ m_A22 += gt[33];
+ m_A22 += gt[34];
+ m_A22 += gt[35];
+ m_A22 += gt[36];
+ m_A22 += gt[37];
+ m_A23 += go[31];
+ m_A24 += go[32];
+ double RHS7 = Idr[31];
+ RHS7 += Idr[32];
+ RHS7 += Idr[33];
+ RHS7 += Idr[34];
+ RHS7 += Idr[35];
+ RHS7 += Idr[36];
+ RHS7 += Idr[37];
+ RHS7 -= go[33] * *cnV[33];
+ RHS7 -= go[34] * *cnV[34];
+ RHS7 -= go[35] * *cnV[35];
+ RHS7 -= go[36] * *cnV[36];
+ RHS7 -= go[37] * *cnV[37];
+ m_A25 += gt[38];
+ m_A25 += gt[39];
+ m_A25 += gt[40];
+ m_A25 += gt[41];
+ m_A25 += gt[42];
+ m_A25 += gt[43];
+ m_A26 += go[38];
+ m_A26 += go[39];
+ m_A27 += go[40];
+ m_A28 += go[41];
+ double RHS8 = Idr[38];
+ RHS8 += Idr[39];
+ RHS8 += Idr[40];
+ RHS8 += Idr[41];
+ RHS8 += Idr[42];
+ RHS8 += Idr[43];
+ RHS8 -= go[42] * *cnV[42];
+ RHS8 -= go[43] * *cnV[43];
+ m_A29 += gt[44];
+ m_A29 += gt[45];
+ m_A29 += gt[46];
+ m_A29 += gt[47];
+ m_A29 += gt[48];
+ m_A29 += gt[49];
+ m_A29 += gt[50];
+ m_A30 += go[44];
+ double RHS9 = Idr[44];
+ RHS9 += Idr[45];
+ RHS9 += Idr[46];
+ RHS9 += Idr[47];
+ RHS9 += Idr[48];
+ RHS9 += Idr[49];
+ RHS9 += Idr[50];
+ RHS9 -= go[45] * *cnV[45];
+ RHS9 -= go[46] * *cnV[46];
+ RHS9 -= go[47] * *cnV[47];
+ RHS9 -= go[48] * *cnV[48];
+ RHS9 -= go[49] * *cnV[49];
+ RHS9 -= go[50] * *cnV[50];
+ m_A31 += gt[51];
+ m_A31 += gt[52];
+ m_A31 += gt[53];
+ m_A31 += gt[54];
+ m_A34 += go[51];
+ m_A32 += go[52];
+ m_A33 += go[53];
+ double RHS10 = Idr[51];
+ RHS10 += Idr[52];
+ RHS10 += Idr[53];
+ RHS10 += Idr[54];
+ RHS10 -= go[54] * *cnV[54];
+ m_A37 += gt[55];
+ m_A37 += gt[56];
+ m_A37 += gt[57];
+ m_A36 += go[55];
+ m_A35 += go[56];
+ double RHS11 = Idr[55];
+ RHS11 += Idr[56];
+ RHS11 += Idr[57];
+ RHS11 -= go[57] * *cnV[57];
+ m_A43 += gt[58];
+ m_A43 += gt[59];
+ m_A43 += gt[60];
+ m_A45 += go[58];
+ m_A41 += go[59];
+ double RHS12 = Idr[58];
+ RHS12 += Idr[59];
+ RHS12 += Idr[60];
+ RHS12 -= go[60] * *cnV[60];
+ m_A51 += gt[61];
+ m_A51 += gt[62];
+ m_A51 += gt[63];
+ m_A51 += gt[64];
+ m_A51 += gt[65];
+ m_A48 += go[61];
+ m_A47 += go[62];
+ m_A46 += go[63];
+ double RHS13 = Idr[61];
+ RHS13 += Idr[62];
+ RHS13 += Idr[63];
+ RHS13 += Idr[64];
+ RHS13 += Idr[65];
+ RHS13 -= go[64] * *cnV[64];
+ RHS13 -= go[65] * *cnV[65];
+ m_A57 += gt[66];
+ m_A57 += gt[67];
+ m_A57 += gt[68];
+ m_A57 += gt[69];
+ m_A59 += go[66];
+ m_A55 += go[67];
+ m_A55 += go[68];
+ double RHS14 = Idr[66];
+ RHS14 += Idr[67];
+ RHS14 += Idr[68];
+ RHS14 += Idr[69];
+ RHS14 -= go[69] * *cnV[69];
+ m_A61 += gt[70];
+ m_A61 += gt[71];
+ m_A60 += go[70];
+ double RHS15 = Idr[70];
+ RHS15 += Idr[71];
+ RHS15 -= go[71] * *cnV[71];
+ m_A66 += gt[72];
+ m_A66 += gt[73];
+ m_A66 += gt[74];
+ m_A66 += gt[75];
+ m_A66 += gt[76];
+ m_A66 += gt[77];
+ m_A63 += go[72];
+ m_A64 += go[73];
+ m_A64 += go[74];
+ m_A68 += go[75];
+ m_A68 += go[76];
+ double RHS16 = Idr[72];
+ RHS16 += Idr[73];
+ RHS16 += Idr[74];
+ RHS16 += Idr[75];
+ RHS16 += Idr[76];
+ RHS16 += Idr[77];
+ RHS16 -= go[77] * *cnV[77];
+ m_A71 += gt[78];
+ m_A71 += gt[79];
+ m_A71 += gt[80];
+ m_A71 += gt[81];
+ m_A71 += gt[82];
+ m_A71 += gt[83];
+ m_A72 += go[78];
+ m_A69 += go[79];
+ m_A73 += go[80];
+ double RHS17 = Idr[78];
+ RHS17 += Idr[79];
+ RHS17 += Idr[80];
+ RHS17 += Idr[81];
+ RHS17 += Idr[82];
+ RHS17 += Idr[83];
+ RHS17 -= go[81] * *cnV[81];
+ RHS17 -= go[82] * *cnV[82];
+ RHS17 -= go[83] * *cnV[83];
+ m_A75 += gt[84];
+ m_A75 += gt[85];
+ m_A75 += gt[86];
+ m_A77 += go[84];
+ m_A74 += go[85];
+ double RHS18 = Idr[84];
+ RHS18 += Idr[85];
+ RHS18 += Idr[86];
+ RHS18 -= go[86] * *cnV[86];
+ m_A85 += gt[87];
+ m_A85 += gt[88];
+ m_A85 += gt[89];
+ m_A85 += gt[90];
+ m_A85 += gt[91];
+ m_A85 += gt[92];
+ m_A78 += go[87];
+ m_A80 += go[88];
+ m_A82 += go[89];
+ m_A79 += go[90];
+ double RHS19 = Idr[87];
+ RHS19 += Idr[88];
+ RHS19 += Idr[89];
+ RHS19 += Idr[90];
+ RHS19 += Idr[91];
+ RHS19 += Idr[92];
+ RHS19 -= go[91] * *cnV[91];
+ RHS19 -= go[92] * *cnV[92];
+ m_A94 += gt[93];
+ m_A94 += gt[94];
+ m_A94 += gt[95];
+ m_A94 += gt[96];
+ m_A94 += gt[97];
+ m_A88 += go[93];
+ m_A90 += go[94];
+ m_A92 += go[95];
+ double RHS20 = Idr[93];
+ RHS20 += Idr[94];
+ RHS20 += Idr[95];
+ RHS20 += Idr[96];
+ RHS20 += Idr[97];
+ RHS20 -= go[96] * *cnV[96];
+ RHS20 -= go[97] * *cnV[97];
+ m_A102 += gt[98];
+ m_A102 += gt[99];
+ m_A102 += gt[100];
+ m_A102 += gt[101];
+ m_A102 += gt[102];
+ m_A102 += gt[103];
+ m_A102 += gt[104];
+ m_A103 += go[98];
+ m_A98 += go[99];
+ m_A98 += go[100];
+ m_A100 += go[101];
+ m_A97 += go[102];
+ m_A97 += go[103];
+ double RHS21 = Idr[98];
+ RHS21 += Idr[99];
+ RHS21 += Idr[100];
+ RHS21 += Idr[101];
+ RHS21 += Idr[102];
+ RHS21 += Idr[103];
+ RHS21 += Idr[104];
+ RHS21 -= go[104] * *cnV[104];
+ m_A108 += gt[105];
+ m_A108 += gt[106];
+ m_A108 += gt[107];
+ m_A108 += gt[108];
+ m_A108 += gt[109];
+ m_A108 += gt[110];
+ m_A104 += go[105];
+ m_A106 += go[106];
+ m_A105 += go[107];
+ double RHS22 = Idr[105];
+ RHS22 += Idr[106];
+ RHS22 += Idr[107];
+ RHS22 += Idr[108];
+ RHS22 += Idr[109];
+ RHS22 += Idr[110];
+ RHS22 -= go[108] * *cnV[108];
+ RHS22 -= go[109] * *cnV[109];
+ RHS22 -= go[110] * *cnV[110];
+ m_A118 += gt[111];
+ m_A118 += gt[112];
+ m_A118 += gt[113];
+ m_A118 += gt[114];
+ m_A118 += gt[115];
+ m_A118 += gt[116];
+ m_A118 += gt[117];
+ m_A118 += gt[118];
+ m_A118 += gt[119];
+ m_A112 += go[111];
+ m_A112 += go[112];
+ m_A111 += go[113];
+ m_A113 += go[114];
+ m_A116 += go[115];
+ m_A110 += go[116];
+ m_A110 += go[117];
+ double RHS23 = Idr[111];
+ RHS23 += Idr[112];
+ RHS23 += Idr[113];
+ RHS23 += Idr[114];
+ RHS23 += Idr[115];
+ RHS23 += Idr[116];
+ RHS23 += Idr[117];
+ RHS23 += Idr[118];
+ RHS23 += Idr[119];
+ RHS23 -= go[118] * *cnV[118];
+ RHS23 -= go[119] * *cnV[119];
+ const double f0 = 1.0 / m_A0;
+ const double f0_11 = -f0 * m_A35;
+ m_A37 += m_A1 * f0_11;
+ m_A39 += m_A2 * f0_11;
+ RHS11 += f0_11 * RHS0;
+ const double f0_13 = -f0 * m_A46;
+ m_A49 += m_A1 * f0_13;
+ m_A51 += m_A2 * f0_13;
+ RHS13 += f0_13 * RHS0;
+ const double f1 = 1.0 / m_A3;
+ const double f1_13 = -f1 * m_A47;
+ m_A51 += m_A4 * f1_13;
+ RHS13 += f1_13 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_19 = -f2 * m_A78;
+ m_A82 += m_A6 * f2_19;
+ RHS19 += f2_19 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_11 = -f3 * m_A36;
+ m_A37 += m_A8 * f3_11;
+ m_A38 += m_A9 * f3_11;
+ m_A40 += m_A10 * f3_11;
+ RHS11 += f3_11 * RHS3;
+ const double f3_12 = -f3 * m_A41;
+ m_A42 += m_A8 * f3_12;
+ m_A43 += m_A9 * f3_12;
+ m_A45 += m_A10 * f3_12;
+ RHS12 += f3_12 * RHS3;
+ const double f3_19 = -f3 * m_A79;
+ m_A81 += m_A8 * f3_19;
+ m_A82 += m_A9 * f3_19;
+ m_A85 += m_A10 * f3_19;
+ RHS19 += f3_19 * RHS3;
+ const double f4 = 1.0 / m_A11;
+ const double f4_13 = -f4 * m_A48;
+ m_A51 += m_A12 * f4_13;
+ m_A52 += m_A13 * f4_13;
+ m_A54 += m_A14 * f4_13;
+ RHS13 += f4_13 * RHS4;
+ const double f4_14 = -f4 * m_A55;
+ m_A56 += m_A12 * f4_14;
+ m_A57 += m_A13 * f4_14;
+ m_A59 += m_A14 * f4_14;
+ RHS14 += f4_14 * RHS4;
+ const double f4_21 = -f4 * m_A97;
+ m_A99 += m_A12 * f4_21;
+ m_A100 += m_A13 * f4_21;
+ m_A102 += m_A14 * f4_21;
+ RHS21 += f4_21 * RHS4;
+ const double f5 = 1.0 / m_A15;
+ const double f5_19 = -f5 * m_A80;
+ m_A85 += m_A16 * f5_19;
+ m_A86 += m_A17 * f5_19;
+ m_A87 += m_A18 * f5_19;
+ RHS19 += f5_19 * RHS5;
+ const double f5_21 = -f5 * m_A98;
+ m_A101 += m_A16 * f5_21;
+ m_A102 += m_A17 * f5_21;
+ m_A103 += m_A18 * f5_21;
+ RHS21 += f5_21 * RHS5;
+ const double f5_23 = -f5 * m_A110;
+ m_A114 += m_A16 * f5_23;
+ m_A116 += m_A17 * f5_23;
+ m_A118 += m_A18 * f5_23;
+ RHS23 += f5_23 * RHS5;
+ const double f6 = 1.0 / m_A19;
+ const double f6_15 = -f6 * m_A60;
+ m_A61 += m_A20 * f6_15;
+ m_A62 += m_A21 * f6_15;
+ RHS15 += f6_15 * RHS6;
+ const double f6_16 = -f6 * m_A63;
+ m_A65 += m_A20 * f6_16;
+ m_A66 += m_A21 * f6_16;
+ RHS16 += f6_16 * RHS6;
+ const double f7 = 1.0 / m_A22;
+ const double f7_20 = -f7 * m_A88;
+ m_A89 += m_A23 * f7_20;
+ m_A92 += m_A24 * f7_20;
+ RHS20 += f7_20 * RHS7;
+ const double f8 = 1.0 / m_A25;
+ const double f8_16 = -f8 * m_A64;
+ m_A66 += m_A26 * f8_16;
+ m_A67 += m_A27 * f8_16;
+ m_A68 += m_A28 * f8_16;
+ RHS16 += f8_16 * RHS8;
+ const double f8_17 = -f8 * m_A69;
+ m_A70 += m_A26 * f8_17;
+ m_A71 += m_A27 * f8_17;
+ m_A73 += m_A28 * f8_17;
+ RHS17 += f8_17 * RHS8;
+ const double f8_20 = -f8 * m_A89;
+ m_A91 += m_A26 * f8_20;
+ m_A92 += m_A27 * f8_20;
+ m_A96 += m_A28 * f8_20;
+ RHS20 += f8_20 * RHS8;
+ const double f8_23 = -f8 * m_A111;
+ m_A112 += m_A26 * f8_23;
+ m_A113 += m_A27 * f8_23;
+ m_A118 += m_A28 * f8_23;
+ RHS23 += f8_23 * RHS8;
+ const double f9 = 1.0 / m_A29;
+ const double f9_22 = -f9 * m_A104;
+ m_A106 += m_A30 * f9_22;
+ RHS22 += f9_22 * RHS9;
+ const double f10 = 1.0 / m_A31;
+ const double f10_18 = -f10 * m_A74;
+ m_A75 += m_A32 * f10_18;
+ m_A76 += m_A33 * f10_18;
+ m_A77 += m_A34 * f10_18;
+ RHS18 += f10_18 * RHS10;
+ const double f10_20 = -f10 * m_A90;
+ m_A93 += m_A32 * f10_20;
+ m_A94 += m_A33 * f10_20;
+ m_A95 += m_A34 * f10_20;
+ RHS20 += f10_20 * RHS10;
+ const double f10_22 = -f10 * m_A105;
+ m_A106 += m_A32 * f10_22;
+ m_A107 += m_A33 * f10_22;
+ m_A108 += m_A34 * f10_22;
+ RHS22 += f10_22 * RHS10;
+ const double f11 = 1.0 / m_A37;
+ const double f11_12 = -f11 * m_A42;
+ m_A43 += m_A38 * f11_12;
+ m_A44 += m_A39 * f11_12;
+ m_A45 += m_A40 * f11_12;
+ RHS12 += f11_12 * RHS11;
+ const double f11_13 = -f11 * m_A49;
+ m_A50 += m_A38 * f11_13;
+ m_A51 += m_A39 * f11_13;
+ m_A53 += m_A40 * f11_13;
+ RHS13 += f11_13 * RHS11;
+ const double f11_19 = -f11 * m_A81;
+ m_A82 += m_A38 * f11_19;
+ m_A83 += m_A39 * f11_19;
+ m_A85 += m_A40 * f11_19;
+ RHS19 += f11_19 * RHS11;
+ const double f12 = 1.0 / m_A43;
+ const double f12_13 = -f12 * m_A50;
+ m_A51 += m_A44 * f12_13;
+ m_A53 += m_A45 * f12_13;
+ RHS13 += f12_13 * RHS12;
+ const double f12_19 = -f12 * m_A82;
+ m_A83 += m_A44 * f12_19;
+ m_A85 += m_A45 * f12_19;
+ RHS19 += f12_19 * RHS12;
+ const double f13 = 1.0 / m_A51;
+ const double f13_14 = -f13 * m_A56;
+ m_A57 += m_A52 * f13_14;
+ m_A58 += m_A53 * f13_14;
+ m_A59 += m_A54 * f13_14;
+ RHS14 += f13_14 * RHS13;
+ const double f13_19 = -f13 * m_A83;
+ m_A84 += m_A52 * f13_19;
+ m_A85 += m_A53 * f13_19;
+ m_A86 += m_A54 * f13_19;
+ RHS19 += f13_19 * RHS13;
+ const double f13_21 = -f13 * m_A99;
+ m_A100 += m_A52 * f13_21;
+ m_A101 += m_A53 * f13_21;
+ m_A102 += m_A54 * f13_21;
+ RHS21 += f13_21 * RHS13;
+ const double f14 = 1.0 / m_A57;
+ const double f14_19 = -f14 * m_A84;
+ m_A85 += m_A58 * f14_19;
+ m_A86 += m_A59 * f14_19;
+ RHS19 += f14_19 * RHS14;
+ const double f14_21 = -f14 * m_A100;
+ m_A101 += m_A58 * f14_21;
+ m_A102 += m_A59 * f14_21;
+ RHS21 += f14_21 * RHS14;
+ const double f15 = 1.0 / m_A61;
+ const double f15_16 = -f15 * m_A65;
+ m_A66 += m_A62 * f15_16;
+ RHS16 += f15_16 * RHS15;
+ const double f16 = 1.0 / m_A66;
+ const double f16_17 = -f16 * m_A70;
+ m_A71 += m_A67 * f16_17;
+ m_A73 += m_A68 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f16_20 = -f16 * m_A91;
+ m_A92 += m_A67 * f16_20;
+ m_A96 += m_A68 * f16_20;
+ RHS20 += f16_20 * RHS16;
+ const double f16_23 = -f16 * m_A112;
+ m_A113 += m_A67 * f16_23;
+ m_A118 += m_A68 * f16_23;
+ RHS23 += f16_23 * RHS16;
+ const double f17 = 1.0 / m_A71;
+ const double f17_20 = -f17 * m_A92;
+ m_A94 += m_A72 * f17_20;
+ m_A96 += m_A73 * f17_20;
+ RHS20 += f17_20 * RHS17;
+ const double f17_23 = -f17 * m_A113;
+ m_A115 += m_A72 * f17_23;
+ m_A118 += m_A73 * f17_23;
+ RHS23 += f17_23 * RHS17;
+ const double f18 = 1.0 / m_A75;
+ const double f18_20 = -f18 * m_A93;
+ m_A94 += m_A76 * f18_20;
+ m_A95 += m_A77 * f18_20;
+ RHS20 += f18_20 * RHS18;
+ const double f18_22 = -f18 * m_A106;
+ m_A107 += m_A76 * f18_22;
+ m_A108 += m_A77 * f18_22;
+ RHS22 += f18_22 * RHS18;
+ const double f19 = 1.0 / m_A85;
+ const double f19_21 = -f19 * m_A101;
+ m_A102 += m_A86 * f19_21;
+ m_A103 += m_A87 * f19_21;
+ RHS21 += f19_21 * RHS19;
+ const double f19_23 = -f19 * m_A114;
+ m_A116 += m_A86 * f19_23;
+ m_A118 += m_A87 * f19_23;
+ RHS23 += f19_23 * RHS19;
+ const double f20 = 1.0 / m_A94;
+ const double f20_22 = -f20 * m_A107;
+ m_A108 += m_A95 * f20_22;
+ m_A109 += m_A96 * f20_22;
+ RHS22 += f20_22 * RHS20;
+ const double f20_23 = -f20 * m_A115;
+ m_A117 += m_A95 * f20_23;
+ m_A118 += m_A96 * f20_23;
+ RHS23 += f20_23 * RHS20;
+ const double f21 = 1.0 / m_A102;
+ const double f21_23 = -f21 * m_A116;
+ m_A118 += m_A103 * f21_23;
+ RHS23 += f21_23 * RHS21;
+ const double f22 = 1.0 / m_A108;
+ const double f22_23 = -f22 * m_A117;
+ m_A118 += m_A109 * f22_23;
+ RHS23 += f22_23 * RHS22;
+ V[23] = RHS23 / m_A118;
+ double tmp22 = 0.0;
+ tmp22 += m_A109 * V[23];
+ V[22] = (RHS22 - tmp22) / m_A108;
+ double tmp21 = 0.0;
+ tmp21 += m_A103 * V[23];
+ V[21] = (RHS21 - tmp21) / m_A102;
+ double tmp20 = 0.0;
+ tmp20 += m_A95 * V[22];
+ tmp20 += m_A96 * V[23];
+ V[20] = (RHS20 - tmp20) / m_A94;
+ double tmp19 = 0.0;
+ tmp19 += m_A86 * V[21];
+ tmp19 += m_A87 * V[23];
+ V[19] = (RHS19 - tmp19) / m_A85;
+ double tmp18 = 0.0;
+ tmp18 += m_A76 * V[20];
+ tmp18 += m_A77 * V[22];
+ V[18] = (RHS18 - tmp18) / m_A75;
+ double tmp17 = 0.0;
+ tmp17 += m_A72 * V[20];
+ tmp17 += m_A73 * V[23];
+ V[17] = (RHS17 - tmp17) / m_A71;
+ double tmp16 = 0.0;
+ tmp16 += m_A67 * V[17];
+ tmp16 += m_A68 * V[23];
+ V[16] = (RHS16 - tmp16) / m_A66;
+ double tmp15 = 0.0;
+ tmp15 += m_A62 * V[16];
+ V[15] = (RHS15 - tmp15) / m_A61;
+ double tmp14 = 0.0;
+ tmp14 += m_A58 * V[19];
+ tmp14 += m_A59 * V[21];
+ V[14] = (RHS14 - tmp14) / m_A57;
+ double tmp13 = 0.0;
+ tmp13 += m_A52 * V[14];
+ tmp13 += m_A53 * V[19];
+ tmp13 += m_A54 * V[21];
+ V[13] = (RHS13 - tmp13) / m_A51;
+ double tmp12 = 0.0;
+ tmp12 += m_A44 * V[13];
+ tmp12 += m_A45 * V[19];
+ V[12] = (RHS12 - tmp12) / m_A43;
+ double tmp11 = 0.0;
+ tmp11 += m_A38 * V[12];
+ tmp11 += m_A39 * V[13];
+ tmp11 += m_A40 * V[19];
+ V[11] = (RHS11 - tmp11) / m_A37;
+ double tmp10 = 0.0;
+ tmp10 += m_A32 * V[18];
+ tmp10 += m_A33 * V[20];
+ tmp10 += m_A34 * V[22];
+ V[10] = (RHS10 - tmp10) / m_A31;
+ double tmp9 = 0.0;
+ tmp9 += m_A30 * V[18];
+ V[9] = (RHS9 - tmp9) / m_A29;
+ double tmp8 = 0.0;
+ tmp8 += m_A26 * V[16];
+ tmp8 += m_A27 * V[17];
+ tmp8 += m_A28 * V[23];
+ V[8] = (RHS8 - tmp8) / m_A25;
+ double tmp7 = 0.0;
+ tmp7 += m_A23 * V[8];
+ tmp7 += m_A24 * V[17];
+ V[7] = (RHS7 - tmp7) / m_A22;
+ double tmp6 = 0.0;
+ tmp6 += m_A20 * V[15];
+ tmp6 += m_A21 * V[16];
+ V[6] = (RHS6 - tmp6) / m_A19;
+ double tmp5 = 0.0;
+ tmp5 += m_A16 * V[19];
+ tmp5 += m_A17 * V[21];
+ tmp5 += m_A18 * V[23];
+ V[5] = (RHS5 - tmp5) / m_A15;
+ double tmp4 = 0.0;
+ tmp4 += m_A12 * V[13];
+ tmp4 += m_A13 * V[14];
+ tmp4 += m_A14 * V[21];
+ V[4] = (RHS4 - tmp4) / m_A11;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[11];
+ tmp3 += m_A9 * V[12];
+ tmp3 += m_A10 * V[19];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[12];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A4 * V[13];
+ V[1] = (RHS1 - tmp1) / m_A3;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[11];
+ tmp0 += m_A2 * V[13];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// 280zzzap
static void nl_gcr_ab9144d965a37e4_113_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -44954,6 +50133,633 @@ static void nl_gcr_b22769fbf3159a8d_21_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_b66df357763b1dce_97_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ double m_A89(0.0);
+ double m_A90(0.0);
+ double m_A91(0.0);
+ double m_A92(0.0);
+ double m_A93(0.0);
+ double m_A94(0.0);
+ double m_A95(0.0);
+ double m_A96(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A2 += gt[7];
+ m_A5 += go[3];
+ m_A4 += go[4];
+ m_A3 += go[5];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 += Idr[7];
+ RHS1 -= go[6] * *cnV[6];
+ RHS1 -= go[7] * *cnV[7];
+ m_A6 += gt[8];
+ m_A6 += gt[9];
+ m_A6 += gt[10];
+ m_A7 += go[8];
+ double RHS2 = Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 -= go[9] * *cnV[9];
+ RHS2 -= go[10] * *cnV[10];
+ m_A8 += gt[11];
+ m_A8 += gt[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A8 += gt[15];
+ m_A8 += gt[16];
+ m_A9 += go[11];
+ m_A10 += go[12];
+ m_A12 += go[13];
+ m_A11 += go[14];
+ double RHS3 = Idr[11];
+ RHS3 += Idr[12];
+ RHS3 += Idr[13];
+ RHS3 += Idr[14];
+ RHS3 += Idr[15];
+ RHS3 += Idr[16];
+ RHS3 -= go[15] * *cnV[15];
+ RHS3 -= go[16] * *cnV[16];
+ m_A13 += gt[17];
+ m_A13 += gt[18];
+ m_A13 += gt[19];
+ m_A14 += go[17];
+ double RHS4 = Idr[17];
+ RHS4 += Idr[18];
+ RHS4 += Idr[19];
+ RHS4 -= go[18] * *cnV[18];
+ RHS4 -= go[19] * *cnV[19];
+ m_A15 += gt[20];
+ m_A15 += gt[21];
+ m_A15 += gt[22];
+ m_A15 += gt[23];
+ m_A16 += go[20];
+ double RHS5 = Idr[20];
+ RHS5 += Idr[21];
+ RHS5 += Idr[22];
+ RHS5 += Idr[23];
+ RHS5 -= go[21] * *cnV[21];
+ RHS5 -= go[22] * *cnV[22];
+ RHS5 -= go[23] * *cnV[23];
+ m_A17 += gt[24];
+ m_A17 += gt[25];
+ m_A17 += gt[26];
+ m_A17 += gt[27];
+ m_A17 += gt[28];
+ m_A17 += gt[29];
+ m_A18 += go[24];
+ m_A21 += go[25];
+ m_A20 += go[26];
+ m_A19 += go[27];
+ double RHS6 = Idr[24];
+ RHS6 += Idr[25];
+ RHS6 += Idr[26];
+ RHS6 += Idr[27];
+ RHS6 += Idr[28];
+ RHS6 += Idr[29];
+ RHS6 -= go[28] * *cnV[28];
+ RHS6 -= go[29] * *cnV[29];
+ m_A22 += gt[30];
+ m_A22 += gt[31];
+ m_A22 += gt[32];
+ m_A22 += gt[33];
+ m_A22 += gt[34];
+ m_A22 += gt[35];
+ m_A22 += gt[36];
+ m_A24 += go[30];
+ m_A23 += go[31];
+ double RHS7 = Idr[30];
+ RHS7 += Idr[31];
+ RHS7 += Idr[32];
+ RHS7 += Idr[33];
+ RHS7 += Idr[34];
+ RHS7 += Idr[35];
+ RHS7 += Idr[36];
+ RHS7 -= go[32] * *cnV[32];
+ RHS7 -= go[33] * *cnV[33];
+ RHS7 -= go[34] * *cnV[34];
+ RHS7 -= go[35] * *cnV[35];
+ RHS7 -= go[36] * *cnV[36];
+ m_A25 += gt[37];
+ m_A25 += gt[38];
+ m_A26 += go[37];
+ m_A27 += go[38];
+ double RHS8 = Idr[37];
+ RHS8 += Idr[38];
+ m_A30 += gt[39];
+ m_A30 += gt[40];
+ m_A30 += gt[41];
+ m_A29 += go[39];
+ m_A28 += go[40];
+ double RHS9 = Idr[39];
+ RHS9 += Idr[40];
+ RHS9 += Idr[41];
+ RHS9 -= go[41] * *cnV[41];
+ m_A34 += gt[42];
+ m_A34 += gt[43];
+ m_A34 += gt[44];
+ m_A34 += gt[45];
+ m_A34 += gt[46];
+ m_A34 += gt[47];
+ m_A34 += gt[48];
+ m_A35 += go[42];
+ m_A33 += go[43];
+ double RHS10 = Idr[42];
+ RHS10 += Idr[43];
+ RHS10 += Idr[44];
+ RHS10 += Idr[45];
+ RHS10 += Idr[46];
+ RHS10 += Idr[47];
+ RHS10 += Idr[48];
+ RHS10 -= go[44] * *cnV[44];
+ RHS10 -= go[45] * *cnV[45];
+ RHS10 -= go[46] * *cnV[46];
+ RHS10 -= go[47] * *cnV[47];
+ RHS10 -= go[48] * *cnV[48];
+ m_A37 += gt[49];
+ m_A37 += gt[50];
+ m_A37 += gt[51];
+ m_A37 += gt[52];
+ m_A37 += gt[53];
+ m_A37 += gt[54];
+ m_A37 += gt[55];
+ m_A38 += go[49];
+ m_A36 += go[50];
+ double RHS11 = Idr[49];
+ RHS11 += Idr[50];
+ RHS11 += Idr[51];
+ RHS11 += Idr[52];
+ RHS11 += Idr[53];
+ RHS11 += Idr[54];
+ RHS11 += Idr[55];
+ RHS11 -= go[51] * *cnV[51];
+ RHS11 -= go[52] * *cnV[52];
+ RHS11 -= go[53] * *cnV[53];
+ RHS11 -= go[54] * *cnV[54];
+ RHS11 -= go[55] * *cnV[55];
+ m_A44 += gt[56];
+ m_A44 += gt[57];
+ m_A44 += gt[58];
+ m_A41 += go[56];
+ m_A40 += go[57];
+ m_A39 += go[58];
+ double RHS12 = Idr[56];
+ RHS12 += Idr[57];
+ RHS12 += Idr[58];
+ m_A54 += gt[59];
+ m_A54 += gt[60];
+ m_A54 += gt[61];
+ m_A56 += go[59];
+ m_A50 += go[60];
+ m_A49 += go[61];
+ double RHS13 = Idr[59];
+ RHS13 += Idr[60];
+ RHS13 += Idr[61];
+ m_A59 += gt[62];
+ m_A59 += gt[63];
+ m_A59 += gt[64];
+ m_A58 += go[62];
+ m_A60 += go[63];
+ double RHS14 = Idr[62];
+ RHS14 += Idr[63];
+ RHS14 += Idr[64];
+ RHS14 -= go[64] * *cnV[64];
+ m_A65 += gt[65];
+ m_A65 += gt[66];
+ m_A65 += gt[67];
+ m_A67 += go[65];
+ m_A61 += go[66];
+ double RHS15 = Idr[65];
+ RHS15 += Idr[66];
+ RHS15 += Idr[67];
+ RHS15 -= go[67] * *cnV[67];
+ m_A69 += gt[68];
+ m_A69 += gt[69];
+ m_A69 += gt[70];
+ m_A68 += go[68];
+ double RHS16 = Idr[68];
+ RHS16 += Idr[69];
+ RHS16 += Idr[70];
+ RHS16 -= go[69] * *cnV[69];
+ RHS16 -= go[70] * *cnV[70];
+ m_A79 += gt[71];
+ m_A79 += gt[72];
+ m_A79 += gt[73];
+ m_A79 += gt[74];
+ m_A79 += gt[75];
+ m_A72 += go[71];
+ m_A73 += go[72];
+ m_A77 += go[73];
+ m_A71 += go[74];
+ double RHS17 = Idr[71];
+ RHS17 += Idr[72];
+ RHS17 += Idr[73];
+ RHS17 += Idr[74];
+ RHS17 += Idr[75];
+ RHS17 -= go[75] * *cnV[75];
+ m_A86 += gt[76];
+ m_A86 += gt[77];
+ m_A86 += gt[78];
+ m_A86 += gt[79];
+ m_A86 += gt[80];
+ m_A81 += go[76];
+ m_A82 += go[77];
+ m_A87 += go[78];
+ double RHS18 = Idr[76];
+ RHS18 += Idr[77];
+ RHS18 += Idr[78];
+ RHS18 += Idr[79];
+ RHS18 += Idr[80];
+ RHS18 -= go[79] * *cnV[79];
+ RHS18 -= go[80] * *cnV[80];
+ m_A96 += gt[81];
+ m_A96 += gt[82];
+ m_A96 += gt[83];
+ m_A96 += gt[84];
+ m_A95 += go[81];
+ m_A92 += go[82];
+ m_A93 += go[83];
+ m_A88 += go[84];
+ double RHS19 = Idr[81];
+ RHS19 += Idr[82];
+ RHS19 += Idr[83];
+ RHS19 += Idr[84];
+ const double f0 = 1.0 / m_A0;
+ const double f0_9 = -f0 * m_A28;
+ m_A30 += m_A1 * f0_9;
+ RHS9 += f0_9 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_9 = -f1 * m_A29;
+ m_A30 += m_A3 * f1_9;
+ m_A31 += m_A4 * f1_9;
+ m_A32 += m_A5 * f1_9;
+ RHS9 += f1_9 * RHS1;
+ const double f1_13 = -f1 * m_A49;
+ m_A51 += m_A3 * f1_13;
+ m_A54 += m_A4 * f1_13;
+ m_A56 += m_A5 * f1_13;
+ RHS13 += f1_13 * RHS1;
+ const double f1_17 = -f1 * m_A71;
+ m_A74 += m_A3 * f1_17;
+ m_A77 += m_A4 * f1_17;
+ m_A79 += m_A5 * f1_17;
+ RHS17 += f1_17 * RHS1;
+ const double f2 = 1.0 / m_A6;
+ const double f2_11 = -f2 * m_A36;
+ m_A38 += m_A7 * f2_11;
+ RHS11 += f2_11 * RHS2;
+ const double f2_17 = -f2 * m_A72;
+ m_A79 += m_A7 * f2_17;
+ RHS17 += f2_17 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_12 = -f3 * m_A39;
+ m_A43 += m_A9 * f3_12;
+ m_A44 += m_A10 * f3_12;
+ m_A45 += m_A11 * f3_12;
+ m_A47 += m_A12 * f3_12;
+ RHS12 += f3_12 * RHS3;
+ const double f3_13 = -f3 * m_A50;
+ m_A52 += m_A9 * f3_13;
+ m_A53 += m_A10 * f3_13;
+ m_A54 += m_A11 * f3_13;
+ m_A56 += m_A12 * f3_13;
+ RHS13 += f3_13 * RHS3;
+ const double f3_17 = -f3 * m_A73;
+ m_A75 += m_A9 * f3_17;
+ m_A76 += m_A10 * f3_17;
+ m_A77 += m_A11 * f3_17;
+ m_A79 += m_A12 * f3_17;
+ RHS17 += f3_17 * RHS3;
+ const double f4 = 1.0 / m_A13;
+ const double f4_10 = -f4 * m_A33;
+ m_A35 += m_A14 * f4_10;
+ RHS10 += f4_10 * RHS4;
+ const double f4_12 = -f4 * m_A40;
+ m_A44 += m_A14 * f4_12;
+ RHS12 += f4_12 * RHS4;
+ const double f5 = 1.0 / m_A15;
+ const double f5_14 = -f5 * m_A58;
+ m_A59 += m_A16 * f5_14;
+ RHS14 += f5_14 * RHS5;
+ const double f6 = 1.0 / m_A17;
+ const double f6_12 = -f6 * m_A41;
+ m_A42 += m_A18 * f6_12;
+ m_A44 += m_A19 * f6_12;
+ m_A46 += m_A20 * f6_12;
+ m_A48 += m_A21 * f6_12;
+ RHS12 += f6_12 * RHS6;
+ const double f6_15 = -f6 * m_A61;
+ m_A62 += m_A18 * f6_15;
+ m_A63 += m_A19 * f6_15;
+ m_A65 += m_A20 * f6_15;
+ m_A67 += m_A21 * f6_15;
+ RHS15 += f6_15 * RHS6;
+ const double f6_19 = -f6 * m_A88;
+ m_A89 += m_A18 * f6_19;
+ m_A90 += m_A19 * f6_19;
+ m_A93 += m_A20 * f6_19;
+ m_A96 += m_A21 * f6_19;
+ RHS19 += f6_19 * RHS6;
+ const double f7 = 1.0 / m_A22;
+ const double f7_18 = -f7 * m_A81;
+ m_A83 += m_A23 * f7_18;
+ m_A87 += m_A24 * f7_18;
+ RHS18 += f7_18 * RHS7;
+ const double f8 = 1.0 / m_A25;
+ const double f8_16 = -f8 * m_A68;
+ m_A69 += m_A26 * f8_16;
+ m_A70 += m_A27 * f8_16;
+ RHS16 += f8_16 * RHS8;
+ const double f8_18 = -f8 * m_A82;
+ m_A84 += m_A26 * f8_18;
+ m_A86 += m_A27 * f8_18;
+ RHS18 += f8_18 * RHS8;
+ const double f9 = 1.0 / m_A30;
+ const double f9_13 = -f9 * m_A51;
+ m_A54 += m_A31 * f9_13;
+ m_A56 += m_A32 * f9_13;
+ RHS13 += f9_13 * RHS9;
+ const double f9_17 = -f9 * m_A74;
+ m_A77 += m_A31 * f9_17;
+ m_A79 += m_A32 * f9_17;
+ RHS17 += f9_17 * RHS9;
+ const double f10 = 1.0 / m_A34;
+ const double f10_12 = -f10 * m_A42;
+ m_A44 += m_A35 * f10_12;
+ RHS12 += f10_12 * RHS10;
+ const double f10_15 = -f10 * m_A62;
+ m_A63 += m_A35 * f10_15;
+ RHS15 += f10_15 * RHS10;
+ const double f10_19 = -f10 * m_A89;
+ m_A90 += m_A35 * f10_19;
+ RHS19 += f10_19 * RHS10;
+ const double f11 = 1.0 / m_A37;
+ const double f11_12 = -f11 * m_A43;
+ m_A47 += m_A38 * f11_12;
+ RHS12 += f11_12 * RHS11;
+ const double f11_13 = -f11 * m_A52;
+ m_A56 += m_A38 * f11_13;
+ RHS13 += f11_13 * RHS11;
+ const double f11_17 = -f11 * m_A75;
+ m_A79 += m_A38 * f11_17;
+ RHS17 += f11_17 * RHS11;
+ const double f12 = 1.0 / m_A44;
+ const double f12_13 = -f12 * m_A53;
+ m_A54 += m_A45 * f12_13;
+ m_A55 += m_A46 * f12_13;
+ m_A56 += m_A47 * f12_13;
+ m_A57 += m_A48 * f12_13;
+ RHS13 += f12_13 * RHS12;
+ const double f12_15 = -f12 * m_A63;
+ m_A64 += m_A45 * f12_15;
+ m_A65 += m_A46 * f12_15;
+ m_A66 += m_A47 * f12_15;
+ m_A67 += m_A48 * f12_15;
+ RHS15 += f12_15 * RHS12;
+ const double f12_17 = -f12 * m_A76;
+ m_A77 += m_A45 * f12_17;
+ m_A78 += m_A46 * f12_17;
+ m_A79 += m_A47 * f12_17;
+ m_A80 += m_A48 * f12_17;
+ RHS17 += f12_17 * RHS12;
+ const double f12_19 = -f12 * m_A90;
+ m_A91 += m_A45 * f12_19;
+ m_A93 += m_A46 * f12_19;
+ m_A94 += m_A47 * f12_19;
+ m_A96 += m_A48 * f12_19;
+ RHS19 += f12_19 * RHS12;
+ const double f13 = 1.0 / m_A54;
+ const double f13_15 = -f13 * m_A64;
+ m_A65 += m_A55 * f13_15;
+ m_A66 += m_A56 * f13_15;
+ m_A67 += m_A57 * f13_15;
+ RHS15 += f13_15 * RHS13;
+ const double f13_17 = -f13 * m_A77;
+ m_A78 += m_A55 * f13_17;
+ m_A79 += m_A56 * f13_17;
+ m_A80 += m_A57 * f13_17;
+ RHS17 += f13_17 * RHS13;
+ const double f13_19 = -f13 * m_A91;
+ m_A93 += m_A55 * f13_19;
+ m_A94 += m_A56 * f13_19;
+ m_A96 += m_A57 * f13_19;
+ RHS19 += f13_19 * RHS13;
+ const double f14 = 1.0 / m_A59;
+ const double f14_19 = -f14 * m_A92;
+ m_A96 += m_A60 * f14_19;
+ RHS19 += f14_19 * RHS14;
+ const double f15 = 1.0 / m_A65;
+ const double f15_17 = -f15 * m_A78;
+ m_A79 += m_A66 * f15_17;
+ m_A80 += m_A67 * f15_17;
+ RHS17 += f15_17 * RHS15;
+ const double f15_18 = -f15 * m_A83;
+ m_A85 += m_A66 * f15_18;
+ m_A87 += m_A67 * f15_18;
+ RHS18 += f15_18 * RHS15;
+ const double f15_19 = -f15 * m_A93;
+ m_A94 += m_A66 * f15_19;
+ m_A96 += m_A67 * f15_19;
+ RHS19 += f15_19 * RHS15;
+ const double f16 = 1.0 / m_A69;
+ const double f16_18 = -f16 * m_A84;
+ m_A86 += m_A70 * f16_18;
+ RHS18 += f16_18 * RHS16;
+ const double f17 = 1.0 / m_A79;
+ const double f17_18 = -f17 * m_A85;
+ m_A87 += m_A80 * f17_18;
+ RHS18 += f17_18 * RHS17;
+ const double f17_19 = -f17 * m_A94;
+ m_A96 += m_A80 * f17_19;
+ RHS19 += f17_19 * RHS17;
+ const double f18 = 1.0 / m_A86;
+ const double f18_19 = -f18 * m_A95;
+ m_A96 += m_A87 * f18_19;
+ RHS19 += f18_19 * RHS18;
+ V[19] = RHS19 / m_A96;
+ double tmp18 = 0.0;
+ tmp18 += m_A87 * V[19];
+ V[18] = (RHS18 - tmp18) / m_A86;
+ double tmp17 = 0.0;
+ tmp17 += m_A80 * V[19];
+ V[17] = (RHS17 - tmp17) / m_A79;
+ double tmp16 = 0.0;
+ tmp16 += m_A70 * V[18];
+ V[16] = (RHS16 - tmp16) / m_A69;
+ double tmp15 = 0.0;
+ tmp15 += m_A66 * V[17];
+ tmp15 += m_A67 * V[19];
+ V[15] = (RHS15 - tmp15) / m_A65;
+ double tmp14 = 0.0;
+ tmp14 += m_A60 * V[19];
+ V[14] = (RHS14 - tmp14) / m_A59;
+ double tmp13 = 0.0;
+ tmp13 += m_A55 * V[15];
+ tmp13 += m_A56 * V[17];
+ tmp13 += m_A57 * V[19];
+ V[13] = (RHS13 - tmp13) / m_A54;
+ double tmp12 = 0.0;
+ tmp12 += m_A45 * V[13];
+ tmp12 += m_A46 * V[15];
+ tmp12 += m_A47 * V[17];
+ tmp12 += m_A48 * V[19];
+ V[12] = (RHS12 - tmp12) / m_A44;
+ double tmp11 = 0.0;
+ tmp11 += m_A38 * V[17];
+ V[11] = (RHS11 - tmp11) / m_A37;
+ double tmp10 = 0.0;
+ tmp10 += m_A35 * V[12];
+ V[10] = (RHS10 - tmp10) / m_A34;
+ double tmp9 = 0.0;
+ tmp9 += m_A31 * V[13];
+ tmp9 += m_A32 * V[17];
+ V[9] = (RHS9 - tmp9) / m_A30;
+ double tmp8 = 0.0;
+ tmp8 += m_A26 * V[16];
+ tmp8 += m_A27 * V[18];
+ V[8] = (RHS8 - tmp8) / m_A25;
+ double tmp7 = 0.0;
+ tmp7 += m_A23 * V[15];
+ tmp7 += m_A24 * V[19];
+ V[7] = (RHS7 - tmp7) / m_A22;
+ double tmp6 = 0.0;
+ tmp6 += m_A18 * V[10];
+ tmp6 += m_A19 * V[12];
+ tmp6 += m_A20 * V[15];
+ tmp6 += m_A21 * V[19];
+ V[6] = (RHS6 - tmp6) / m_A17;
+ double tmp5 = 0.0;
+ tmp5 += m_A16 * V[14];
+ V[5] = (RHS5 - tmp5) / m_A15;
+ double tmp4 = 0.0;
+ tmp4 += m_A14 * V[12];
+ V[4] = (RHS4 - tmp4) / m_A13;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[11];
+ tmp3 += m_A10 * V[12];
+ tmp3 += m_A11 * V[13];
+ tmp3 += m_A12 * V[17];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A7 * V[17];
+ V[2] = (RHS2 - tmp2) / m_A6;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[9];
+ tmp1 += m_A4 * V[13];
+ tmp1 += m_A5 * V[17];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[9];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// breakout
static void nl_gcr_b66ff415b228d5f8_10_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -49110,6 +54916,907 @@ static void nl_gcr_bff07f8d339f7cc4_89_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_c05df522276e65fd_134_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ double m_A89(0.0);
+ double m_A90(0.0);
+ double m_A91(0.0);
+ double m_A92(0.0);
+ double m_A93(0.0);
+ double m_A94(0.0);
+ double m_A95(0.0);
+ double m_A96(0.0);
+ double m_A97(0.0);
+ double m_A98(0.0);
+ double m_A99(0.0);
+ double m_A100(0.0);
+ double m_A101(0.0);
+ double m_A102(0.0);
+ double m_A103(0.0);
+ double m_A104(0.0);
+ double m_A105(0.0);
+ double m_A106(0.0);
+ double m_A107(0.0);
+ double m_A108(0.0);
+ double m_A109(0.0);
+ double m_A110(0.0);
+ double m_A111(0.0);
+ double m_A112(0.0);
+ double m_A113(0.0);
+ double m_A114(0.0);
+ double m_A115(0.0);
+ double m_A116(0.0);
+ double m_A117(0.0);
+ double m_A118(0.0);
+ double m_A119(0.0);
+ double m_A120(0.0);
+ double m_A121(0.0);
+ double m_A122(0.0);
+ double m_A123(0.0);
+ double m_A124(0.0);
+ double m_A125(0.0);
+ double m_A126(0.0);
+ double m_A127(0.0);
+ double m_A128(0.0);
+ double m_A129(0.0);
+ double m_A130(0.0);
+ double m_A131(0.0);
+ double m_A132(0.0);
+ double m_A133(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A4 += go[3];
+ m_A3 += go[4];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[5] * *cnV[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A5 += gt[8];
+ m_A5 += gt[9];
+ m_A5 += gt[10];
+ m_A5 += gt[11];
+ m_A5 += gt[12];
+ m_A7 += go[6];
+ m_A6 += go[7];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 += Idr[11];
+ RHS2 += Idr[12];
+ RHS2 -= go[8] * *cnV[8];
+ RHS2 -= go[9] * *cnV[9];
+ RHS2 -= go[10] * *cnV[10];
+ RHS2 -= go[11] * *cnV[11];
+ RHS2 -= go[12] * *cnV[12];
+ m_A8 += gt[13];
+ m_A8 += gt[14];
+ m_A8 += gt[15];
+ m_A9 += go[13];
+ double RHS3 = Idr[13];
+ RHS3 += Idr[14];
+ RHS3 += Idr[15];
+ RHS3 -= go[14] * *cnV[14];
+ RHS3 -= go[15] * *cnV[15];
+ m_A10 += gt[16];
+ m_A10 += gt[17];
+ m_A10 += gt[18];
+ m_A10 += gt[19];
+ m_A11 += go[16];
+ double RHS4 = Idr[16];
+ RHS4 += Idr[17];
+ RHS4 += Idr[18];
+ RHS4 += Idr[19];
+ RHS4 -= go[17] * *cnV[17];
+ RHS4 -= go[18] * *cnV[18];
+ RHS4 -= go[19] * *cnV[19];
+ m_A12 += gt[20];
+ m_A12 += gt[21];
+ m_A12 += gt[22];
+ m_A12 += gt[23];
+ m_A12 += gt[24];
+ m_A12 += gt[25];
+ m_A12 += gt[26];
+ m_A14 += go[20];
+ m_A13 += go[21];
+ double RHS5 = Idr[20];
+ RHS5 += Idr[21];
+ RHS5 += Idr[22];
+ RHS5 += Idr[23];
+ RHS5 += Idr[24];
+ RHS5 += Idr[25];
+ RHS5 += Idr[26];
+ RHS5 -= go[22] * *cnV[22];
+ RHS5 -= go[23] * *cnV[23];
+ RHS5 -= go[24] * *cnV[24];
+ RHS5 -= go[25] * *cnV[25];
+ RHS5 -= go[26] * *cnV[26];
+ m_A15 += gt[27];
+ m_A15 += gt[28];
+ m_A15 += gt[29];
+ m_A16 += go[27];
+ m_A17 += go[28];
+ double RHS6 = Idr[27];
+ RHS6 += Idr[28];
+ RHS6 += Idr[29];
+ RHS6 -= go[29] * *cnV[29];
+ m_A18 += gt[30];
+ m_A18 += gt[31];
+ m_A18 += gt[32];
+ m_A18 += gt[33];
+ m_A19 += go[30];
+ double RHS7 = Idr[30];
+ RHS7 += Idr[31];
+ RHS7 += Idr[32];
+ RHS7 += Idr[33];
+ RHS7 -= go[31] * *cnV[31];
+ RHS7 -= go[32] * *cnV[32];
+ RHS7 -= go[33] * *cnV[33];
+ m_A20 += gt[34];
+ m_A20 += gt[35];
+ m_A20 += gt[36];
+ m_A21 += go[34];
+ m_A22 += go[35];
+ double RHS8 = Idr[34];
+ RHS8 += Idr[35];
+ RHS8 += Idr[36];
+ RHS8 -= go[36] * *cnV[36];
+ m_A23 += gt[37];
+ m_A23 += gt[38];
+ m_A23 += gt[39];
+ m_A23 += gt[40];
+ m_A23 += gt[41];
+ m_A24 += go[37];
+ m_A25 += go[38];
+ m_A26 += go[39];
+ double RHS9 = Idr[37];
+ RHS9 += Idr[38];
+ RHS9 += Idr[39];
+ RHS9 += Idr[40];
+ RHS9 += Idr[41];
+ RHS9 -= go[40] * *cnV[40];
+ RHS9 -= go[41] * *cnV[41];
+ m_A27 += gt[42];
+ m_A27 += gt[43];
+ m_A27 += gt[44];
+ m_A28 += go[42];
+ double RHS10 = Idr[42];
+ RHS10 += Idr[43];
+ RHS10 += Idr[44];
+ RHS10 -= go[43] * *cnV[43];
+ RHS10 -= go[44] * *cnV[44];
+ m_A29 += gt[45];
+ m_A29 += gt[46];
+ m_A30 += go[45];
+ double RHS11 = Idr[45];
+ RHS11 += Idr[46];
+ RHS11 -= go[46] * *cnV[46];
+ m_A31 += gt[47];
+ m_A31 += gt[48];
+ m_A32 += go[47];
+ double RHS12 = Idr[47];
+ RHS12 += Idr[48];
+ RHS12 -= go[48] * *cnV[48];
+ m_A33 += gt[49];
+ m_A33 += gt[50];
+ m_A33 += gt[51];
+ m_A34 += go[49];
+ m_A35 += go[50];
+ double RHS13 = Idr[49];
+ RHS13 += Idr[50];
+ RHS13 += Idr[51];
+ RHS13 -= go[51] * *cnV[51];
+ m_A36 += gt[52];
+ m_A36 += gt[53];
+ m_A36 += gt[54];
+ m_A36 += gt[55];
+ m_A36 += gt[56];
+ m_A36 += gt[57];
+ m_A37 += go[52];
+ m_A39 += go[53];
+ m_A39 += go[54];
+ m_A38 += go[55];
+ double RHS14 = Idr[52];
+ RHS14 += Idr[53];
+ RHS14 += Idr[54];
+ RHS14 += Idr[55];
+ RHS14 += Idr[56];
+ RHS14 += Idr[57];
+ RHS14 -= go[56] * *cnV[56];
+ RHS14 -= go[57] * *cnV[57];
+ m_A40 += gt[58];
+ m_A40 += gt[59];
+ m_A40 += gt[60];
+ m_A40 += gt[61];
+ m_A41 += go[58];
+ double RHS15 = Idr[58];
+ RHS15 += Idr[59];
+ RHS15 += Idr[60];
+ RHS15 += Idr[61];
+ RHS15 -= go[59] * *cnV[59];
+ RHS15 -= go[60] * *cnV[60];
+ RHS15 -= go[61] * *cnV[61];
+ m_A44 += gt[62];
+ m_A44 += gt[63];
+ m_A43 += go[62];
+ m_A42 += go[63];
+ double RHS16 = Idr[62];
+ RHS16 += Idr[63];
+ m_A48 += gt[64];
+ m_A48 += gt[65];
+ m_A48 += gt[66];
+ m_A49 += go[64];
+ m_A46 += go[65];
+ double RHS17 = Idr[64];
+ RHS17 += Idr[65];
+ RHS17 += Idr[66];
+ RHS17 -= go[66] * *cnV[66];
+ m_A51 += gt[67];
+ m_A51 += gt[68];
+ m_A51 += gt[69];
+ m_A51 += gt[70];
+ m_A51 += gt[71];
+ m_A51 += gt[72];
+ m_A51 += gt[73];
+ m_A52 += go[67];
+ m_A50 += go[68];
+ double RHS18 = Idr[67];
+ RHS18 += Idr[68];
+ RHS18 += Idr[69];
+ RHS18 += Idr[70];
+ RHS18 += Idr[71];
+ RHS18 += Idr[72];
+ RHS18 += Idr[73];
+ RHS18 -= go[69] * *cnV[69];
+ RHS18 -= go[70] * *cnV[70];
+ RHS18 -= go[71] * *cnV[71];
+ RHS18 -= go[72] * *cnV[72];
+ RHS18 -= go[73] * *cnV[73];
+ m_A54 += gt[74];
+ m_A54 += gt[75];
+ m_A54 += gt[76];
+ m_A53 += go[74];
+ m_A55 += go[75];
+ double RHS19 = Idr[74];
+ RHS19 += Idr[75];
+ RHS19 += Idr[76];
+ RHS19 -= go[76] * *cnV[76];
+ m_A57 += gt[77];
+ m_A57 += gt[78];
+ m_A57 += gt[79];
+ m_A56 += go[77];
+ m_A58 += go[78];
+ double RHS20 = Idr[77];
+ RHS20 += Idr[78];
+ RHS20 += Idr[79];
+ RHS20 -= go[79] * *cnV[79];
+ m_A61 += gt[80];
+ m_A61 += gt[81];
+ m_A61 += gt[82];
+ m_A61 += gt[83];
+ m_A61 += gt[84];
+ m_A59 += go[80];
+ m_A62 += go[81];
+ m_A63 += go[82];
+ double RHS21 = Idr[80];
+ RHS21 += Idr[81];
+ RHS21 += Idr[82];
+ RHS21 += Idr[83];
+ RHS21 += Idr[84];
+ RHS21 -= go[83] * *cnV[83];
+ RHS21 -= go[84] * *cnV[84];
+ m_A66 += gt[85];
+ m_A66 += gt[86];
+ m_A66 += gt[87];
+ m_A66 += gt[88];
+ m_A66 += gt[89];
+ m_A66 += gt[90];
+ m_A66 += gt[91];
+ m_A67 += go[85];
+ m_A65 += go[86];
+ double RHS22 = Idr[85];
+ RHS22 += Idr[86];
+ RHS22 += Idr[87];
+ RHS22 += Idr[88];
+ RHS22 += Idr[89];
+ RHS22 += Idr[90];
+ RHS22 += Idr[91];
+ RHS22 -= go[87] * *cnV[87];
+ RHS22 -= go[88] * *cnV[88];
+ RHS22 -= go[89] * *cnV[89];
+ RHS22 -= go[90] * *cnV[90];
+ RHS22 -= go[91] * *cnV[91];
+ m_A70 += gt[92];
+ m_A70 += gt[93];
+ m_A70 += gt[94];
+ m_A70 += gt[95];
+ m_A70 += gt[96];
+ m_A70 += gt[97];
+ m_A70 += gt[98];
+ m_A71 += go[92];
+ m_A69 += go[93];
+ double RHS23 = Idr[92];
+ RHS23 += Idr[93];
+ RHS23 += Idr[94];
+ RHS23 += Idr[95];
+ RHS23 += Idr[96];
+ RHS23 += Idr[97];
+ RHS23 += Idr[98];
+ RHS23 -= go[94] * *cnV[94];
+ RHS23 -= go[95] * *cnV[95];
+ RHS23 -= go[96] * *cnV[96];
+ RHS23 -= go[97] * *cnV[97];
+ RHS23 -= go[98] * *cnV[98];
+ m_A77 += gt[99];
+ m_A77 += gt[100];
+ m_A77 += gt[101];
+ m_A77 += gt[102];
+ m_A77 += gt[103];
+ m_A74 += go[99];
+ m_A73 += go[100];
+ m_A75 += go[101];
+ double RHS24 = Idr[99];
+ RHS24 += Idr[100];
+ RHS24 += Idr[101];
+ RHS24 += Idr[102];
+ RHS24 += Idr[103];
+ RHS24 -= go[102] * *cnV[102];
+ RHS24 -= go[103] * *cnV[103];
+ m_A81 += gt[104];
+ m_A81 += gt[105];
+ m_A81 += gt[106];
+ m_A83 += go[104];
+ m_A80 += go[105];
+ m_A82 += go[106];
+ double RHS25 = Idr[104];
+ RHS25 += Idr[105];
+ RHS25 += Idr[106];
+ m_A88 += gt[107];
+ m_A88 += gt[108];
+ m_A88 += gt[109];
+ m_A88 += gt[110];
+ m_A88 += gt[111];
+ m_A85 += go[107];
+ m_A85 += go[108];
+ m_A89 += go[109];
+ m_A84 += go[110];
+ m_A90 += go[111];
+ double RHS26 = Idr[107];
+ RHS26 += Idr[108];
+ RHS26 += Idr[109];
+ RHS26 += Idr[110];
+ RHS26 += Idr[111];
+ m_A95 += gt[112];
+ m_A95 += gt[113];
+ m_A95 += gt[114];
+ m_A92 += go[112];
+ m_A91 += go[113];
+ m_A93 += go[114];
+ double RHS27 = Idr[112];
+ RHS27 += Idr[113];
+ RHS27 += Idr[114];
+ m_A104 += gt[115];
+ m_A104 += gt[116];
+ m_A104 += gt[117];
+ m_A104 += gt[118];
+ m_A100 += go[115];
+ m_A101 += go[116];
+ m_A99 += go[117];
+ m_A106 += go[118];
+ double RHS28 = Idr[115];
+ RHS28 += Idr[116];
+ RHS28 += Idr[117];
+ RHS28 += Idr[118];
+ m_A112 += gt[119];
+ m_A112 += gt[120];
+ m_A112 += gt[121];
+ m_A112 += gt[122];
+ m_A109 += go[119];
+ m_A108 += go[120];
+ m_A107 += go[121];
+ m_A113 += go[122];
+ double RHS29 = Idr[119];
+ RHS29 += Idr[120];
+ RHS29 += Idr[121];
+ RHS29 += Idr[122];
+ m_A117 += gt[123];
+ m_A117 += gt[124];
+ m_A117 += gt[125];
+ m_A117 += gt[126];
+ m_A117 += gt[127];
+ m_A114 += go[123];
+ m_A116 += go[124];
+ m_A115 += go[125];
+ double RHS30 = Idr[123];
+ RHS30 += Idr[124];
+ RHS30 += Idr[125];
+ RHS30 += Idr[126];
+ RHS30 += Idr[127];
+ RHS30 -= go[126] * *cnV[126];
+ RHS30 -= go[127] * *cnV[127];
+ m_A121 += gt[128];
+ m_A121 += gt[129];
+ m_A121 += gt[130];
+ m_A119 += go[128];
+ m_A120 += go[129];
+ double RHS31 = Idr[128];
+ RHS31 += Idr[129];
+ RHS31 += Idr[130];
+ RHS31 -= go[130] * *cnV[130];
+ m_A133 += gt[131];
+ m_A133 += gt[132];
+ m_A133 += gt[133];
+ m_A133 += gt[134];
+ m_A133 += gt[135];
+ m_A133 += gt[136];
+ m_A133 += gt[137];
+ m_A133 += gt[138];
+ m_A133 += gt[139];
+ m_A133 += gt[140];
+ m_A126 += go[131];
+ m_A128 += go[132];
+ m_A125 += go[133];
+ m_A129 += go[134];
+ m_A124 += go[135];
+ m_A130 += go[136];
+ m_A123 += go[137];
+ m_A127 += go[138];
+ double RHS32 = Idr[131];
+ RHS32 += Idr[132];
+ RHS32 += Idr[133];
+ RHS32 += Idr[134];
+ RHS32 += Idr[135];
+ RHS32 += Idr[136];
+ RHS32 += Idr[137];
+ RHS32 += Idr[138];
+ RHS32 += Idr[139];
+ RHS32 += Idr[140];
+ RHS32 -= go[139] * *cnV[139];
+ RHS32 -= go[140] * *cnV[140];
+ const double f0 = 1.0 / m_A0;
+ const double f0_16 = -f0 * m_A42;
+ m_A44 += m_A1 * f0_16;
+ RHS16 += f0_16 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_16 = -f1 * m_A43;
+ m_A44 += m_A3 * f1_16;
+ m_A45 += m_A4 * f1_16;
+ RHS16 += f1_16 * RHS1;
+ const double f1_17 = -f1 * m_A46;
+ m_A47 += m_A3 * f1_17;
+ m_A48 += m_A4 * f1_17;
+ RHS17 += f1_17 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_30 = -f2 * m_A114;
+ m_A115 += m_A6 * f2_30;
+ m_A117 += m_A7 * f2_30;
+ RHS30 += f2_30 * RHS2;
+ const double f3 = 1.0 / m_A8;
+ const double f3_18 = -f3 * m_A50;
+ m_A52 += m_A9 * f3_18;
+ RHS18 += f3_18 * RHS3;
+ const double f3_25 = -f3 * m_A80;
+ m_A81 += m_A9 * f3_25;
+ RHS25 += f3_25 * RHS3;
+ const double f4 = 1.0 / m_A10;
+ const double f4_19 = -f4 * m_A53;
+ m_A54 += m_A11 * f4_19;
+ RHS19 += f4_19 * RHS4;
+ const double f5 = 1.0 / m_A12;
+ const double f5_21 = -f5 * m_A59;
+ m_A60 += m_A13 * f5_21;
+ m_A63 += m_A14 * f5_21;
+ RHS21 += f5_21 * RHS5;
+ const double f6 = 1.0 / m_A15;
+ const double f6_21 = -f6 * m_A60;
+ m_A63 += m_A16 * f6_21;
+ m_A64 += m_A17 * f6_21;
+ RHS21 += f6_21 * RHS6;
+ const double f6_29 = -f6 * m_A107;
+ m_A112 += m_A16 * f6_29;
+ m_A113 += m_A17 * f6_29;
+ RHS29 += f6_29 * RHS6;
+ const double f6_32 = -f6 * m_A123;
+ m_A130 += m_A16 * f6_32;
+ m_A133 += m_A17 * f6_32;
+ RHS32 += f6_32 * RHS6;
+ const double f7 = 1.0 / m_A18;
+ const double f7_20 = -f7 * m_A56;
+ m_A57 += m_A19 * f7_20;
+ RHS20 += f7_20 * RHS7;
+ const double f8 = 1.0 / m_A20;
+ const double f8_22 = -f8 * m_A65;
+ m_A67 += m_A21 * f8_22;
+ m_A68 += m_A22 * f8_22;
+ RHS22 += f8_22 * RHS8;
+ const double f8_28 = -f8 * m_A99;
+ m_A104 += m_A21 * f8_28;
+ m_A106 += m_A22 * f8_28;
+ RHS28 += f8_28 * RHS8;
+ const double f8_32 = -f8 * m_A124;
+ m_A129 += m_A21 * f8_32;
+ m_A133 += m_A22 * f8_32;
+ RHS32 += f8_32 * RHS8;
+ const double f9 = 1.0 / m_A23;
+ const double f9_27 = -f9 * m_A91;
+ m_A94 += m_A24 * f9_27;
+ m_A95 += m_A25 * f9_27;
+ m_A96 += m_A26 * f9_27;
+ RHS27 += f9_27 * RHS9;
+ const double f9_28 = -f9 * m_A100;
+ m_A102 += m_A24 * f9_28;
+ m_A103 += m_A25 * f9_28;
+ m_A104 += m_A26 * f9_28;
+ RHS28 += f9_28 * RHS9;
+ const double f10 = 1.0 / m_A27;
+ const double f10_27 = -f10 * m_A92;
+ m_A95 += m_A28 * f10_27;
+ RHS27 += f10_27 * RHS10;
+ const double f11 = 1.0 / m_A29;
+ const double f11_24 = -f11 * m_A73;
+ m_A77 += m_A30 * f11_24;
+ RHS24 += f11_24 * RHS11;
+ const double f12 = 1.0 / m_A31;
+ const double f12_24 = -f12 * m_A74;
+ m_A77 += m_A32 * f12_24;
+ RHS24 += f12_24 * RHS12;
+ const double f13 = 1.0 / m_A33;
+ const double f13_23 = -f13 * m_A69;
+ m_A71 += m_A34 * f13_23;
+ m_A72 += m_A35 * f13_23;
+ RHS23 += f13_23 * RHS13;
+ const double f13_26 = -f13 * m_A84;
+ m_A88 += m_A34 * f13_26;
+ m_A90 += m_A35 * f13_26;
+ RHS26 += f13_26 * RHS13;
+ const double f13_32 = -f13 * m_A125;
+ m_A128 += m_A34 * f13_32;
+ m_A133 += m_A35 * f13_32;
+ RHS32 += f13_32 * RHS13;
+ const double f14 = 1.0 / m_A36;
+ const double f14_24 = -f14 * m_A75;
+ m_A76 += m_A37 * f14_24;
+ m_A77 += m_A38 * f14_24;
+ m_A78 += m_A39 * f14_24;
+ RHS24 += f14_24 * RHS14;
+ const double f14_26 = -f14 * m_A85;
+ m_A86 += m_A37 * f14_26;
+ m_A87 += m_A38 * f14_26;
+ m_A88 += m_A39 * f14_26;
+ RHS26 += f14_26 * RHS14;
+ const double f15 = 1.0 / m_A40;
+ const double f15_31 = -f15 * m_A119;
+ m_A121 += m_A41 * f15_31;
+ RHS31 += f15_31 * RHS15;
+ const double f16 = 1.0 / m_A44;
+ const double f16_17 = -f16 * m_A47;
+ m_A48 += m_A45 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f17 = 1.0 / m_A48;
+ const double f17_30 = -f17 * m_A115;
+ m_A117 += m_A49 * f17_30;
+ RHS30 += f17_30 * RHS17;
+ const double f18 = 1.0 / m_A51;
+ const double f18_32 = -f18 * m_A126;
+ m_A127 += m_A52 * f18_32;
+ RHS32 += f18_32 * RHS18;
+ const double f19 = 1.0 / m_A54;
+ const double f19_29 = -f19 * m_A108;
+ m_A112 += m_A55 * f19_29;
+ RHS29 += f19_29 * RHS19;
+ const double f20 = 1.0 / m_A57;
+ const double f20_28 = -f20 * m_A101;
+ m_A104 += m_A58 * f20_28;
+ RHS28 += f20_28 * RHS20;
+ const double f21 = 1.0 / m_A61;
+ const double f21_27 = -f21 * m_A93;
+ m_A95 += m_A62 * f21_27;
+ m_A97 += m_A63 * f21_27;
+ m_A98 += m_A64 * f21_27;
+ RHS27 += f21_27 * RHS21;
+ const double f21_29 = -f21 * m_A109;
+ m_A110 += m_A62 * f21_29;
+ m_A112 += m_A63 * f21_29;
+ m_A113 += m_A64 * f21_29;
+ RHS29 += f21_29 * RHS21;
+ const double f22 = 1.0 / m_A66;
+ const double f22_27 = -f22 * m_A94;
+ m_A96 += m_A67 * f22_27;
+ m_A98 += m_A68 * f22_27;
+ RHS27 += f22_27 * RHS22;
+ const double f22_28 = -f22 * m_A102;
+ m_A104 += m_A67 * f22_28;
+ m_A106 += m_A68 * f22_28;
+ RHS28 += f22_28 * RHS22;
+ const double f23 = 1.0 / m_A70;
+ const double f23_24 = -f23 * m_A76;
+ m_A78 += m_A71 * f23_24;
+ m_A79 += m_A72 * f23_24;
+ RHS24 += f23_24 * RHS23;
+ const double f23_26 = -f23 * m_A86;
+ m_A88 += m_A71 * f23_26;
+ m_A90 += m_A72 * f23_26;
+ RHS26 += f23_26 * RHS23;
+ const double f24 = 1.0 / m_A77;
+ const double f24_26 = -f24 * m_A87;
+ m_A88 += m_A78 * f24_26;
+ m_A90 += m_A79 * f24_26;
+ RHS26 += f24_26 * RHS24;
+ const double f25 = 1.0 / m_A81;
+ const double f25_30 = -f25 * m_A116;
+ m_A117 += m_A82 * f25_30;
+ m_A118 += m_A83 * f25_30;
+ RHS30 += f25_30 * RHS25;
+ const double f25_32 = -f25 * m_A127;
+ m_A131 += m_A82 * f25_32;
+ m_A133 += m_A83 * f25_32;
+ RHS32 += f25_32 * RHS25;
+ const double f26 = 1.0 / m_A88;
+ const double f26_31 = -f26 * m_A120;
+ m_A121 += m_A89 * f26_31;
+ m_A122 += m_A90 * f26_31;
+ RHS31 += f26_31 * RHS26;
+ const double f26_32 = -f26 * m_A128;
+ m_A132 += m_A89 * f26_32;
+ m_A133 += m_A90 * f26_32;
+ RHS32 += f26_32 * RHS26;
+ const double f27 = 1.0 / m_A95;
+ const double f27_28 = -f27 * m_A103;
+ m_A104 += m_A96 * f27_28;
+ m_A105 += m_A97 * f27_28;
+ m_A106 += m_A98 * f27_28;
+ RHS28 += f27_28 * RHS27;
+ const double f27_29 = -f27 * m_A110;
+ m_A111 += m_A96 * f27_29;
+ m_A112 += m_A97 * f27_29;
+ m_A113 += m_A98 * f27_29;
+ RHS29 += f27_29 * RHS27;
+ const double f28 = 1.0 / m_A104;
+ const double f28_29 = -f28 * m_A111;
+ m_A112 += m_A105 * f28_29;
+ m_A113 += m_A106 * f28_29;
+ RHS29 += f28_29 * RHS28;
+ const double f28_32 = -f28 * m_A129;
+ m_A130 += m_A105 * f28_32;
+ m_A133 += m_A106 * f28_32;
+ RHS32 += f28_32 * RHS28;
+ const double f29 = 1.0 / m_A112;
+ const double f29_32 = -f29 * m_A130;
+ m_A133 += m_A113 * f29_32;
+ RHS32 += f29_32 * RHS29;
+ const double f30 = 1.0 / m_A117;
+ const double f30_32 = -f30 * m_A131;
+ m_A133 += m_A118 * f30_32;
+ RHS32 += f30_32 * RHS30;
+ const double f31 = 1.0 / m_A121;
+ const double f31_32 = -f31 * m_A132;
+ m_A133 += m_A122 * f31_32;
+ RHS32 += f31_32 * RHS31;
+ V[32] = RHS32 / m_A133;
+ double tmp31 = 0.0;
+ tmp31 += m_A122 * V[32];
+ V[31] = (RHS31 - tmp31) / m_A121;
+ double tmp30 = 0.0;
+ tmp30 += m_A118 * V[32];
+ V[30] = (RHS30 - tmp30) / m_A117;
+ double tmp29 = 0.0;
+ tmp29 += m_A113 * V[32];
+ V[29] = (RHS29 - tmp29) / m_A112;
+ double tmp28 = 0.0;
+ tmp28 += m_A105 * V[29];
+ tmp28 += m_A106 * V[32];
+ V[28] = (RHS28 - tmp28) / m_A104;
+ double tmp27 = 0.0;
+ tmp27 += m_A96 * V[28];
+ tmp27 += m_A97 * V[29];
+ tmp27 += m_A98 * V[32];
+ V[27] = (RHS27 - tmp27) / m_A95;
+ double tmp26 = 0.0;
+ tmp26 += m_A89 * V[31];
+ tmp26 += m_A90 * V[32];
+ V[26] = (RHS26 - tmp26) / m_A88;
+ double tmp25 = 0.0;
+ tmp25 += m_A82 * V[30];
+ tmp25 += m_A83 * V[32];
+ V[25] = (RHS25 - tmp25) / m_A81;
+ double tmp24 = 0.0;
+ tmp24 += m_A78 * V[26];
+ tmp24 += m_A79 * V[32];
+ V[24] = (RHS24 - tmp24) / m_A77;
+ double tmp23 = 0.0;
+ tmp23 += m_A71 * V[26];
+ tmp23 += m_A72 * V[32];
+ V[23] = (RHS23 - tmp23) / m_A70;
+ double tmp22 = 0.0;
+ tmp22 += m_A67 * V[28];
+ tmp22 += m_A68 * V[32];
+ V[22] = (RHS22 - tmp22) / m_A66;
+ double tmp21 = 0.0;
+ tmp21 += m_A62 * V[27];
+ tmp21 += m_A63 * V[29];
+ tmp21 += m_A64 * V[32];
+ V[21] = (RHS21 - tmp21) / m_A61;
+ double tmp20 = 0.0;
+ tmp20 += m_A58 * V[28];
+ V[20] = (RHS20 - tmp20) / m_A57;
+ double tmp19 = 0.0;
+ tmp19 += m_A55 * V[29];
+ V[19] = (RHS19 - tmp19) / m_A54;
+ double tmp18 = 0.0;
+ tmp18 += m_A52 * V[25];
+ V[18] = (RHS18 - tmp18) / m_A51;
+ double tmp17 = 0.0;
+ tmp17 += m_A49 * V[30];
+ V[17] = (RHS17 - tmp17) / m_A48;
+ double tmp16 = 0.0;
+ tmp16 += m_A45 * V[17];
+ V[16] = (RHS16 - tmp16) / m_A44;
+ double tmp15 = 0.0;
+ tmp15 += m_A41 * V[31];
+ V[15] = (RHS15 - tmp15) / m_A40;
+ double tmp14 = 0.0;
+ tmp14 += m_A37 * V[23];
+ tmp14 += m_A38 * V[24];
+ tmp14 += m_A39 * V[26];
+ V[14] = (RHS14 - tmp14) / m_A36;
+ double tmp13 = 0.0;
+ tmp13 += m_A34 * V[26];
+ tmp13 += m_A35 * V[32];
+ V[13] = (RHS13 - tmp13) / m_A33;
+ double tmp12 = 0.0;
+ tmp12 += m_A32 * V[24];
+ V[12] = (RHS12 - tmp12) / m_A31;
+ double tmp11 = 0.0;
+ tmp11 += m_A30 * V[24];
+ V[11] = (RHS11 - tmp11) / m_A29;
+ double tmp10 = 0.0;
+ tmp10 += m_A28 * V[27];
+ V[10] = (RHS10 - tmp10) / m_A27;
+ double tmp9 = 0.0;
+ tmp9 += m_A24 * V[22];
+ tmp9 += m_A25 * V[27];
+ tmp9 += m_A26 * V[28];
+ V[9] = (RHS9 - tmp9) / m_A23;
+ double tmp8 = 0.0;
+ tmp8 += m_A21 * V[28];
+ tmp8 += m_A22 * V[32];
+ V[8] = (RHS8 - tmp8) / m_A20;
+ double tmp7 = 0.0;
+ tmp7 += m_A19 * V[20];
+ V[7] = (RHS7 - tmp7) / m_A18;
+ double tmp6 = 0.0;
+ tmp6 += m_A16 * V[29];
+ tmp6 += m_A17 * V[32];
+ V[6] = (RHS6 - tmp6) / m_A15;
+ double tmp5 = 0.0;
+ tmp5 += m_A13 * V[6];
+ tmp5 += m_A14 * V[29];
+ V[5] = (RHS5 - tmp5) / m_A12;
+ double tmp4 = 0.0;
+ tmp4 += m_A11 * V[19];
+ V[4] = (RHS4 - tmp4) / m_A10;
+ double tmp3 = 0.0;
+ tmp3 += m_A9 * V[25];
+ V[3] = (RHS3 - tmp3) / m_A8;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[17];
+ tmp2 += m_A7 * V[30];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[16];
+ tmp1 += m_A4 * V[17];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[16];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// fireone
static void nl_gcr_c1d22fe6e895255d_79_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -50037,6 +56744,153 @@ static void nl_gcr_c4cec7aed23b7b94_23_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_c5b523ed6a9677e6_21_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A4 += go[2];
+ m_A3 += go[3];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ m_A5 += gt[4];
+ m_A5 += gt[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A5 += gt[8];
+ m_A5 += gt[9];
+ m_A5 += gt[10];
+ m_A6 += go[4];
+ double RHS2 = Idr[4];
+ RHS2 += Idr[5];
+ RHS2 += Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 += Idr[10];
+ RHS2 -= go[5] * *cnV[5];
+ RHS2 -= go[6] * *cnV[6];
+ RHS2 -= go[7] * *cnV[7];
+ RHS2 -= go[8] * *cnV[8];
+ RHS2 -= go[9] * *cnV[9];
+ RHS2 -= go[10] * *cnV[10];
+ m_A7 += gt[11];
+ m_A8 += go[11];
+ double RHS3 = Idr[11];
+ m_A11 += gt[12];
+ m_A11 += gt[13];
+ m_A11 += gt[14];
+ m_A10 += go[12];
+ m_A9 += go[13];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ RHS4 += Idr[14];
+ RHS4 -= go[14] * *cnV[14];
+ m_A15 += gt[15];
+ m_A15 += gt[16];
+ m_A15 += gt[17];
+ m_A16 += go[15];
+ m_A13 += go[16];
+ double RHS5 = Idr[15];
+ RHS5 += Idr[16];
+ RHS5 += Idr[17];
+ RHS5 -= go[17] * *cnV[17];
+ m_A20 += gt[18];
+ m_A20 += gt[19];
+ m_A20 += gt[20];
+ m_A20 += gt[21];
+ m_A20 += gt[22];
+ m_A17 += go[18];
+ m_A18 += go[19];
+ m_A19 += go[20];
+ double RHS6 = Idr[18];
+ RHS6 += Idr[19];
+ RHS6 += Idr[20];
+ RHS6 += Idr[21];
+ RHS6 += Idr[22];
+ RHS6 -= go[21] * *cnV[21];
+ RHS6 -= go[22] * *cnV[22];
+ const double f0 = 1.0 / m_A0;
+ const double f0_4 = -f0 * m_A9;
+ m_A11 += m_A1 * f0_4;
+ RHS4 += f0_4 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_4 = -f1 * m_A10;
+ m_A11 += m_A3 * f1_4;
+ m_A12 += m_A4 * f1_4;
+ RHS4 += f1_4 * RHS1;
+ const double f1_5 = -f1 * m_A13;
+ m_A14 += m_A3 * f1_5;
+ m_A15 += m_A4 * f1_5;
+ RHS5 += f1_5 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_6 = -f2 * m_A17;
+ m_A19 += m_A6 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_6 = -f3 * m_A18;
+ m_A20 += m_A8 * f3_6;
+ RHS6 += f3_6 * RHS3;
+ const double f4 = 1.0 / m_A11;
+ const double f4_5 = -f4 * m_A14;
+ m_A15 += m_A12 * f4_5;
+ RHS5 += f4_5 * RHS4;
+ const double f5 = 1.0 / m_A15;
+ const double f5_6 = -f5 * m_A19;
+ m_A20 += m_A16 * f5_6;
+ RHS6 += f5_6 * RHS5;
+ V[6] = RHS6 / m_A20;
+ double tmp5 = 0.0;
+ tmp5 += m_A16 * V[6];
+ V[5] = (RHS5 - tmp5) / m_A15;
+ double tmp4 = 0.0;
+ tmp4 += m_A12 * V[5];
+ V[4] = (RHS4 - tmp4) / m_A11;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[6];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[5];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[4];
+ tmp1 += m_A4 * V[5];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[4];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// segausb
static void nl_gcr_c61e08cf5e35918_84_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -50975,6 +57829,2216 @@ static void nl_gcr_c74b1a65978d7121_7_double_double(double * __restrict V, const
V[0] = (RHS0 - tmp0) / m_A0;
}
+// headon
+static void nl_gcr_c90daff82be2d052_350_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ double m_A83(0.0);
+ double m_A84(0.0);
+ double m_A85(0.0);
+ double m_A86(0.0);
+ double m_A87(0.0);
+ double m_A88(0.0);
+ double m_A89(0.0);
+ double m_A90(0.0);
+ double m_A91(0.0);
+ double m_A92(0.0);
+ double m_A93(0.0);
+ double m_A94(0.0);
+ double m_A95(0.0);
+ double m_A96(0.0);
+ double m_A97(0.0);
+ double m_A98(0.0);
+ double m_A99(0.0);
+ double m_A100(0.0);
+ double m_A101(0.0);
+ double m_A102(0.0);
+ double m_A103(0.0);
+ double m_A104(0.0);
+ double m_A105(0.0);
+ double m_A106(0.0);
+ double m_A107(0.0);
+ double m_A108(0.0);
+ double m_A109(0.0);
+ double m_A110(0.0);
+ double m_A111(0.0);
+ double m_A112(0.0);
+ double m_A113(0.0);
+ double m_A114(0.0);
+ double m_A115(0.0);
+ double m_A116(0.0);
+ double m_A117(0.0);
+ double m_A118(0.0);
+ double m_A119(0.0);
+ double m_A120(0.0);
+ double m_A121(0.0);
+ double m_A122(0.0);
+ double m_A123(0.0);
+ double m_A124(0.0);
+ double m_A125(0.0);
+ double m_A126(0.0);
+ double m_A127(0.0);
+ double m_A128(0.0);
+ double m_A129(0.0);
+ double m_A130(0.0);
+ double m_A131(0.0);
+ double m_A132(0.0);
+ double m_A133(0.0);
+ double m_A134(0.0);
+ double m_A135(0.0);
+ double m_A136(0.0);
+ double m_A137(0.0);
+ double m_A138(0.0);
+ double m_A139(0.0);
+ double m_A140(0.0);
+ double m_A141(0.0);
+ double m_A142(0.0);
+ double m_A143(0.0);
+ double m_A144(0.0);
+ double m_A145(0.0);
+ double m_A146(0.0);
+ double m_A147(0.0);
+ double m_A148(0.0);
+ double m_A149(0.0);
+ double m_A150(0.0);
+ double m_A151(0.0);
+ double m_A152(0.0);
+ double m_A153(0.0);
+ double m_A154(0.0);
+ double m_A155(0.0);
+ double m_A156(0.0);
+ double m_A157(0.0);
+ double m_A158(0.0);
+ double m_A159(0.0);
+ double m_A160(0.0);
+ double m_A161(0.0);
+ double m_A162(0.0);
+ double m_A163(0.0);
+ double m_A164(0.0);
+ double m_A165(0.0);
+ double m_A166(0.0);
+ double m_A167(0.0);
+ double m_A168(0.0);
+ double m_A169(0.0);
+ double m_A170(0.0);
+ double m_A171(0.0);
+ double m_A172(0.0);
+ double m_A173(0.0);
+ double m_A174(0.0);
+ double m_A175(0.0);
+ double m_A176(0.0);
+ double m_A177(0.0);
+ double m_A178(0.0);
+ double m_A179(0.0);
+ double m_A180(0.0);
+ double m_A181(0.0);
+ double m_A182(0.0);
+ double m_A183(0.0);
+ double m_A184(0.0);
+ double m_A185(0.0);
+ double m_A186(0.0);
+ double m_A187(0.0);
+ double m_A188(0.0);
+ double m_A189(0.0);
+ double m_A190(0.0);
+ double m_A191(0.0);
+ double m_A192(0.0);
+ double m_A193(0.0);
+ double m_A194(0.0);
+ double m_A195(0.0);
+ double m_A196(0.0);
+ double m_A197(0.0);
+ double m_A198(0.0);
+ double m_A199(0.0);
+ double m_A200(0.0);
+ double m_A201(0.0);
+ double m_A202(0.0);
+ double m_A203(0.0);
+ double m_A204(0.0);
+ double m_A205(0.0);
+ double m_A206(0.0);
+ double m_A207(0.0);
+ double m_A208(0.0);
+ double m_A209(0.0);
+ double m_A210(0.0);
+ double m_A211(0.0);
+ double m_A212(0.0);
+ double m_A213(0.0);
+ double m_A214(0.0);
+ double m_A215(0.0);
+ double m_A216(0.0);
+ double m_A217(0.0);
+ double m_A218(0.0);
+ double m_A219(0.0);
+ double m_A220(0.0);
+ double m_A221(0.0);
+ double m_A222(0.0);
+ double m_A223(0.0);
+ double m_A224(0.0);
+ double m_A225(0.0);
+ double m_A226(0.0);
+ double m_A227(0.0);
+ double m_A228(0.0);
+ double m_A229(0.0);
+ double m_A230(0.0);
+ double m_A231(0.0);
+ double m_A232(0.0);
+ double m_A233(0.0);
+ double m_A234(0.0);
+ double m_A235(0.0);
+ double m_A236(0.0);
+ double m_A237(0.0);
+ double m_A238(0.0);
+ double m_A239(0.0);
+ double m_A240(0.0);
+ double m_A241(0.0);
+ double m_A242(0.0);
+ double m_A243(0.0);
+ double m_A244(0.0);
+ double m_A245(0.0);
+ double m_A246(0.0);
+ double m_A247(0.0);
+ double m_A248(0.0);
+ double m_A249(0.0);
+ double m_A250(0.0);
+ double m_A251(0.0);
+ double m_A252(0.0);
+ double m_A253(0.0);
+ double m_A254(0.0);
+ double m_A255(0.0);
+ double m_A256(0.0);
+ double m_A257(0.0);
+ double m_A258(0.0);
+ double m_A259(0.0);
+ double m_A260(0.0);
+ double m_A261(0.0);
+ double m_A262(0.0);
+ double m_A263(0.0);
+ double m_A264(0.0);
+ double m_A265(0.0);
+ double m_A266(0.0);
+ double m_A267(0.0);
+ double m_A268(0.0);
+ double m_A269(0.0);
+ double m_A270(0.0);
+ double m_A271(0.0);
+ double m_A272(0.0);
+ double m_A273(0.0);
+ double m_A274(0.0);
+ double m_A275(0.0);
+ double m_A276(0.0);
+ double m_A277(0.0);
+ double m_A278(0.0);
+ double m_A279(0.0);
+ double m_A280(0.0);
+ double m_A281(0.0);
+ double m_A282(0.0);
+ double m_A283(0.0);
+ double m_A284(0.0);
+ double m_A285(0.0);
+ double m_A286(0.0);
+ double m_A287(0.0);
+ double m_A288(0.0);
+ double m_A289(0.0);
+ double m_A290(0.0);
+ double m_A291(0.0);
+ double m_A292(0.0);
+ double m_A293(0.0);
+ double m_A294(0.0);
+ double m_A295(0.0);
+ double m_A296(0.0);
+ double m_A297(0.0);
+ double m_A298(0.0);
+ double m_A299(0.0);
+ double m_A300(0.0);
+ double m_A301(0.0);
+ double m_A302(0.0);
+ double m_A303(0.0);
+ double m_A304(0.0);
+ double m_A305(0.0);
+ double m_A306(0.0);
+ double m_A307(0.0);
+ double m_A308(0.0);
+ double m_A309(0.0);
+ double m_A310(0.0);
+ double m_A311(0.0);
+ double m_A312(0.0);
+ double m_A313(0.0);
+ double m_A314(0.0);
+ double m_A315(0.0);
+ double m_A316(0.0);
+ double m_A317(0.0);
+ double m_A318(0.0);
+ double m_A319(0.0);
+ double m_A320(0.0);
+ double m_A321(0.0);
+ double m_A322(0.0);
+ double m_A323(0.0);
+ double m_A324(0.0);
+ double m_A325(0.0);
+ double m_A326(0.0);
+ double m_A327(0.0);
+ double m_A328(0.0);
+ double m_A329(0.0);
+ double m_A330(0.0);
+ double m_A331(0.0);
+ double m_A332(0.0);
+ double m_A333(0.0);
+ double m_A334(0.0);
+ double m_A335(0.0);
+ double m_A336(0.0);
+ double m_A337(0.0);
+ double m_A338(0.0);
+ double m_A339(0.0);
+ double m_A340(0.0);
+ double m_A341(0.0);
+ double m_A342(0.0);
+ double m_A343(0.0);
+ double m_A344(0.0);
+ double m_A345(0.0);
+ double m_A346(0.0);
+ double m_A347(0.0);
+ double m_A348(0.0);
+ double m_A349(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A3 += go[3];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 -= go[4] * *cnV[4];
+ m_A4 += gt[5];
+ m_A4 += gt[6];
+ m_A4 += gt[7];
+ m_A4 += gt[8];
+ m_A6 += go[5];
+ m_A5 += go[6];
+ m_A5 += go[7];
+ double RHS2 = Idr[5];
+ RHS2 += Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 -= go[8] * *cnV[8];
+ m_A7 += gt[9];
+ m_A7 += gt[10];
+ m_A8 += go[9];
+ double RHS3 = Idr[9];
+ RHS3 += Idr[10];
+ RHS3 -= go[10] * *cnV[10];
+ m_A9 += gt[11];
+ m_A9 += gt[12];
+ m_A9 += gt[13];
+ m_A10 += go[11];
+ m_A11 += go[12];
+ double RHS4 = Idr[11];
+ RHS4 += Idr[12];
+ RHS4 += Idr[13];
+ RHS4 -= go[13] * *cnV[13];
+ m_A12 += gt[14];
+ m_A12 += gt[15];
+ m_A13 += go[14];
+ double RHS5 = Idr[14];
+ RHS5 += Idr[15];
+ RHS5 -= go[15] * *cnV[15];
+ m_A14 += gt[16];
+ m_A14 += gt[17];
+ m_A15 += go[16];
+ double RHS6 = Idr[16];
+ RHS6 += Idr[17];
+ RHS6 -= go[17] * *cnV[17];
+ m_A16 += gt[18];
+ m_A16 += gt[19];
+ m_A17 += go[18];
+ double RHS7 = Idr[18];
+ RHS7 += Idr[19];
+ RHS7 -= go[19] * *cnV[19];
+ m_A18 += gt[20];
+ m_A18 += gt[21];
+ m_A19 += go[20];
+ double RHS8 = Idr[20];
+ RHS8 += Idr[21];
+ RHS8 -= go[21] * *cnV[21];
+ m_A20 += gt[22];
+ m_A20 += gt[23];
+ m_A20 += gt[24];
+ m_A20 += gt[25];
+ m_A21 += go[22];
+ m_A22 += go[23];
+ m_A23 += go[24];
+ double RHS9 = Idr[22];
+ RHS9 += Idr[23];
+ RHS9 += Idr[24];
+ RHS9 += Idr[25];
+ RHS9 -= go[25] * *cnV[25];
+ m_A24 += gt[26];
+ m_A24 += gt[27];
+ m_A24 += gt[28];
+ m_A24 += gt[29];
+ m_A24 += gt[30];
+ m_A25 += go[26];
+ m_A27 += go[27];
+ m_A26 += go[28];
+ double RHS10 = Idr[26];
+ RHS10 += Idr[27];
+ RHS10 += Idr[28];
+ RHS10 += Idr[29];
+ RHS10 += Idr[30];
+ RHS10 -= go[29] * *cnV[29];
+ RHS10 -= go[30] * *cnV[30];
+ m_A28 += gt[31];
+ m_A28 += gt[32];
+ m_A28 += gt[33];
+ m_A28 += gt[34];
+ m_A28 += gt[35];
+ m_A28 += gt[36];
+ m_A28 += gt[37];
+ m_A29 += go[31];
+ m_A30 += go[32];
+ double RHS11 = Idr[31];
+ RHS11 += Idr[32];
+ RHS11 += Idr[33];
+ RHS11 += Idr[34];
+ RHS11 += Idr[35];
+ RHS11 += Idr[36];
+ RHS11 += Idr[37];
+ RHS11 -= go[33] * *cnV[33];
+ RHS11 -= go[34] * *cnV[34];
+ RHS11 -= go[35] * *cnV[35];
+ RHS11 -= go[36] * *cnV[36];
+ RHS11 -= go[37] * *cnV[37];
+ m_A31 += gt[38];
+ m_A31 += gt[39];
+ m_A31 += gt[40];
+ m_A31 += gt[41];
+ m_A33 += go[38];
+ m_A34 += go[39];
+ m_A32 += go[40];
+ double RHS12 = Idr[38];
+ RHS12 += Idr[39];
+ RHS12 += Idr[40];
+ RHS12 += Idr[41];
+ RHS12 -= go[41] * *cnV[41];
+ m_A35 += gt[42];
+ m_A35 += gt[43];
+ m_A35 += gt[44];
+ m_A37 += go[42];
+ m_A36 += go[43];
+ double RHS13 = Idr[42];
+ RHS13 += Idr[43];
+ RHS13 += Idr[44];
+ RHS13 -= go[44] * *cnV[44];
+ m_A38 += gt[45];
+ m_A38 += gt[46];
+ m_A38 += gt[47];
+ m_A38 += gt[48];
+ m_A38 += gt[49];
+ m_A38 += gt[50];
+ m_A38 += gt[51];
+ m_A39 += go[45];
+ double RHS14 = Idr[45];
+ RHS14 += Idr[46];
+ RHS14 += Idr[47];
+ RHS14 += Idr[48];
+ RHS14 += Idr[49];
+ RHS14 += Idr[50];
+ RHS14 += Idr[51];
+ RHS14 -= go[46] * *cnV[46];
+ RHS14 -= go[47] * *cnV[47];
+ RHS14 -= go[48] * *cnV[48];
+ RHS14 -= go[49] * *cnV[49];
+ RHS14 -= go[50] * *cnV[50];
+ RHS14 -= go[51] * *cnV[51];
+ m_A40 += gt[52];
+ m_A40 += gt[53];
+ m_A40 += gt[54];
+ m_A40 += gt[55];
+ m_A43 += go[52];
+ m_A42 += go[53];
+ m_A41 += go[54];
+ double RHS15 = Idr[52];
+ RHS15 += Idr[53];
+ RHS15 += Idr[54];
+ RHS15 += Idr[55];
+ RHS15 -= go[55] * *cnV[55];
+ m_A44 += gt[56];
+ m_A44 += gt[57];
+ m_A45 += go[56];
+ m_A46 += go[57];
+ double RHS16 = Idr[56];
+ RHS16 += Idr[57];
+ m_A47 += gt[58];
+ m_A47 += gt[59];
+ m_A48 += go[58];
+ m_A49 += go[59];
+ double RHS17 = Idr[58];
+ RHS17 += Idr[59];
+ m_A50 += gt[60];
+ m_A50 += gt[61];
+ m_A50 += gt[62];
+ m_A50 += gt[63];
+ m_A50 += gt[64];
+ m_A50 += gt[65];
+ m_A50 += gt[66];
+ m_A51 += go[60];
+ double RHS18 = Idr[60];
+ RHS18 += Idr[61];
+ RHS18 += Idr[62];
+ RHS18 += Idr[63];
+ RHS18 += Idr[64];
+ RHS18 += Idr[65];
+ RHS18 += Idr[66];
+ RHS18 -= go[61] * *cnV[61];
+ RHS18 -= go[62] * *cnV[62];
+ RHS18 -= go[63] * *cnV[63];
+ RHS18 -= go[64] * *cnV[64];
+ RHS18 -= go[65] * *cnV[65];
+ RHS18 -= go[66] * *cnV[66];
+ m_A52 += gt[67];
+ m_A52 += gt[68];
+ m_A52 += gt[69];
+ m_A53 += go[67];
+ double RHS19 = Idr[67];
+ RHS19 += Idr[68];
+ RHS19 += Idr[69];
+ RHS19 -= go[68] * *cnV[68];
+ RHS19 -= go[69] * *cnV[69];
+ m_A54 += gt[70];
+ m_A54 += gt[71];
+ m_A54 += gt[72];
+ m_A54 += gt[73];
+ m_A54 += gt[74];
+ m_A56 += go[70];
+ m_A55 += go[71];
+ m_A55 += go[72];
+ double RHS20 = Idr[70];
+ RHS20 += Idr[71];
+ RHS20 += Idr[72];
+ RHS20 += Idr[73];
+ RHS20 += Idr[74];
+ RHS20 -= go[73] * *cnV[73];
+ RHS20 -= go[74] * *cnV[74];
+ m_A57 += gt[75];
+ m_A57 += gt[76];
+ m_A57 += gt[77];
+ m_A57 += gt[78];
+ m_A57 += gt[79];
+ m_A59 += go[75];
+ m_A58 += go[76];
+ m_A58 += go[77];
+ double RHS21 = Idr[75];
+ RHS21 += Idr[76];
+ RHS21 += Idr[77];
+ RHS21 += Idr[78];
+ RHS21 += Idr[79];
+ RHS21 -= go[78] * *cnV[78];
+ RHS21 -= go[79] * *cnV[79];
+ m_A60 += gt[80];
+ m_A60 += gt[81];
+ m_A60 += gt[82];
+ m_A60 += gt[83];
+ m_A62 += go[80];
+ m_A63 += go[81];
+ m_A61 += go[82];
+ double RHS22 = Idr[80];
+ RHS22 += Idr[81];
+ RHS22 += Idr[82];
+ RHS22 += Idr[83];
+ RHS22 -= go[83] * *cnV[83];
+ m_A64 += gt[84];
+ m_A64 += gt[85];
+ m_A64 += gt[86];
+ m_A65 += go[84];
+ double RHS23 = Idr[84];
+ RHS23 += Idr[85];
+ RHS23 += Idr[86];
+ RHS23 -= go[85] * *cnV[85];
+ RHS23 -= go[86] * *cnV[86];
+ m_A66 += gt[87];
+ m_A66 += gt[88];
+ m_A66 += gt[89];
+ m_A66 += gt[90];
+ m_A66 += gt[91];
+ m_A67 += go[87];
+ double RHS24 = Idr[87];
+ RHS24 += Idr[88];
+ RHS24 += Idr[89];
+ RHS24 += Idr[90];
+ RHS24 += Idr[91];
+ RHS24 -= go[88] * *cnV[88];
+ RHS24 -= go[89] * *cnV[89];
+ RHS24 -= go[90] * *cnV[90];
+ RHS24 -= go[91] * *cnV[91];
+ m_A68 += gt[92];
+ m_A69 += go[92];
+ double RHS25 = Idr[92];
+ m_A70 += gt[93];
+ m_A70 += gt[94];
+ m_A70 += gt[95];
+ m_A70 += gt[96];
+ m_A72 += go[93];
+ m_A71 += go[94];
+ m_A71 += go[95];
+ double RHS26 = Idr[93];
+ RHS26 += Idr[94];
+ RHS26 += Idr[95];
+ RHS26 += Idr[96];
+ RHS26 -= go[96] * *cnV[96];
+ m_A73 += gt[97];
+ m_A73 += gt[98];
+ m_A73 += gt[99];
+ m_A73 += gt[100];
+ m_A75 += go[97];
+ m_A76 += go[98];
+ m_A74 += go[99];
+ double RHS27 = Idr[97];
+ RHS27 += Idr[98];
+ RHS27 += Idr[99];
+ RHS27 += Idr[100];
+ RHS27 -= go[100] * *cnV[100];
+ m_A77 += gt[101];
+ m_A77 += gt[102];
+ m_A78 += go[101];
+ double RHS28 = Idr[101];
+ RHS28 += Idr[102];
+ RHS28 -= go[102] * *cnV[102];
+ m_A79 += gt[103];
+ m_A79 += gt[104];
+ m_A79 += gt[105];
+ m_A80 += go[103];
+ double RHS29 = Idr[103];
+ RHS29 += Idr[104];
+ RHS29 += Idr[105];
+ RHS29 -= go[104] * *cnV[104];
+ RHS29 -= go[105] * *cnV[105];
+ m_A83 += gt[106];
+ m_A83 += gt[107];
+ m_A83 += gt[108];
+ m_A83 += gt[109];
+ m_A83 += gt[110];
+ m_A83 += gt[111];
+ m_A82 += go[106];
+ m_A82 += go[107];
+ m_A81 += go[108];
+ double RHS30 = Idr[106];
+ RHS30 += Idr[107];
+ RHS30 += Idr[108];
+ RHS30 += Idr[109];
+ RHS30 += Idr[110];
+ RHS30 += Idr[111];
+ RHS30 -= go[109] * *cnV[109];
+ RHS30 -= go[110] * *cnV[110];
+ RHS30 -= go[111] * *cnV[111];
+ m_A86 += gt[112];
+ m_A86 += gt[113];
+ m_A85 += go[112];
+ double RHS31 = Idr[112];
+ RHS31 += Idr[113];
+ RHS31 -= go[113] * *cnV[113];
+ m_A89 += gt[114];
+ m_A89 += gt[115];
+ m_A89 += gt[116];
+ m_A88 += go[114];
+ m_A90 += go[115];
+ double RHS32 = Idr[114];
+ RHS32 += Idr[115];
+ RHS32 += Idr[116];
+ RHS32 -= go[116] * *cnV[116];
+ m_A93 += gt[117];
+ m_A93 += gt[118];
+ m_A92 += go[117];
+ m_A91 += go[118];
+ double RHS33 = Idr[117];
+ RHS33 += Idr[118];
+ m_A98 += gt[119];
+ m_A98 += gt[120];
+ m_A98 += gt[121];
+ m_A97 += go[119];
+ m_A99 += go[120];
+ double RHS34 = Idr[119];
+ RHS34 += Idr[120];
+ RHS34 += Idr[121];
+ RHS34 -= go[121] * *cnV[121];
+ m_A101 += gt[122];
+ m_A101 += gt[123];
+ m_A101 += gt[124];
+ m_A101 += gt[125];
+ m_A101 += gt[126];
+ m_A103 += go[122];
+ m_A100 += go[123];
+ m_A102 += go[124];
+ double RHS35 = Idr[122];
+ RHS35 += Idr[123];
+ RHS35 += Idr[124];
+ RHS35 += Idr[125];
+ RHS35 += Idr[126];
+ RHS35 -= go[125] * *cnV[125];
+ RHS35 -= go[126] * *cnV[126];
+ m_A105 += gt[127];
+ m_A105 += gt[128];
+ m_A105 += gt[129];
+ m_A105 += gt[130];
+ m_A105 += gt[131];
+ m_A105 += gt[132];
+ m_A105 += gt[133];
+ m_A106 += go[127];
+ m_A104 += go[128];
+ double RHS36 = Idr[127];
+ RHS36 += Idr[128];
+ RHS36 += Idr[129];
+ RHS36 += Idr[130];
+ RHS36 += Idr[131];
+ RHS36 += Idr[132];
+ RHS36 += Idr[133];
+ RHS36 -= go[129] * *cnV[129];
+ RHS36 -= go[130] * *cnV[130];
+ RHS36 -= go[131] * *cnV[131];
+ RHS36 -= go[132] * *cnV[132];
+ RHS36 -= go[133] * *cnV[133];
+ m_A112 += gt[134];
+ m_A112 += gt[135];
+ m_A112 += gt[136];
+ m_A110 += go[134];
+ m_A109 += go[135];
+ m_A115 += go[136];
+ double RHS37 = Idr[134];
+ RHS37 += Idr[135];
+ RHS37 += Idr[136];
+ m_A119 += gt[137];
+ m_A119 += gt[138];
+ m_A119 += gt[139];
+ m_A119 += gt[140];
+ m_A118 += go[137];
+ m_A121 += go[138];
+ m_A117 += go[139];
+ m_A116 += go[140];
+ double RHS38 = Idr[137];
+ RHS38 += Idr[138];
+ RHS38 += Idr[139];
+ RHS38 += Idr[140];
+ m_A123 += gt[141];
+ m_A123 += gt[142];
+ m_A123 += gt[143];
+ m_A123 += gt[144];
+ m_A123 += gt[145];
+ m_A123 += gt[146];
+ m_A123 += gt[147];
+ m_A125 += go[141];
+ m_A122 += go[142];
+ double RHS39 = Idr[141];
+ RHS39 += Idr[142];
+ RHS39 += Idr[143];
+ RHS39 += Idr[144];
+ RHS39 += Idr[145];
+ RHS39 += Idr[146];
+ RHS39 += Idr[147];
+ RHS39 -= go[143] * *cnV[143];
+ RHS39 -= go[144] * *cnV[144];
+ RHS39 -= go[145] * *cnV[145];
+ RHS39 -= go[146] * *cnV[146];
+ RHS39 -= go[147] * *cnV[147];
+ m_A130 += gt[148];
+ m_A130 += gt[149];
+ m_A130 += gt[150];
+ m_A133 += go[148];
+ m_A127 += go[149];
+ m_A126 += go[150];
+ double RHS40 = Idr[148];
+ RHS40 += Idr[149];
+ RHS40 += Idr[150];
+ m_A138 += gt[151];
+ m_A138 += gt[152];
+ m_A138 += gt[153];
+ m_A138 += gt[154];
+ m_A138 += gt[155];
+ m_A134 += go[151];
+ m_A136 += go[152];
+ m_A141 += go[153];
+ double RHS41 = Idr[151];
+ RHS41 += Idr[152];
+ RHS41 += Idr[153];
+ RHS41 += Idr[154];
+ RHS41 += Idr[155];
+ RHS41 -= go[154] * *cnV[154];
+ RHS41 -= go[155] * *cnV[155];
+ m_A145 += gt[156];
+ m_A145 += gt[157];
+ m_A145 += gt[158];
+ m_A148 += go[156];
+ m_A143 += go[157];
+ double RHS42 = Idr[156];
+ RHS42 += Idr[157];
+ RHS42 += Idr[158];
+ RHS42 -= go[158] * *cnV[158];
+ m_A150 += gt[159];
+ m_A150 += gt[160];
+ m_A150 += gt[161];
+ m_A150 += gt[162];
+ m_A150 += gt[163];
+ m_A150 += gt[164];
+ m_A151 += go[159];
+ m_A151 += go[160];
+ m_A149 += go[161];
+ m_A149 += go[162];
+ double RHS43 = Idr[159];
+ RHS43 += Idr[160];
+ RHS43 += Idr[161];
+ RHS43 += Idr[162];
+ RHS43 += Idr[163];
+ RHS43 += Idr[164];
+ RHS43 -= go[163] * *cnV[163];
+ RHS43 -= go[164] * *cnV[164];
+ m_A153 += gt[165];
+ m_A153 += gt[166];
+ m_A153 += gt[167];
+ m_A153 += gt[168];
+ m_A153 += gt[169];
+ m_A153 += gt[170];
+ m_A154 += go[165];
+ m_A154 += go[166];
+ m_A152 += go[167];
+ m_A152 += go[168];
+ double RHS44 = Idr[165];
+ RHS44 += Idr[166];
+ RHS44 += Idr[167];
+ RHS44 += Idr[168];
+ RHS44 += Idr[169];
+ RHS44 += Idr[170];
+ RHS44 -= go[169] * *cnV[169];
+ RHS44 -= go[170] * *cnV[170];
+ m_A158 += gt[171];
+ m_A158 += gt[172];
+ m_A155 += go[171];
+ m_A156 += go[172];
+ double RHS45 = Idr[171];
+ RHS45 += Idr[172];
+ m_A164 += gt[173];
+ m_A164 += gt[174];
+ m_A164 += gt[175];
+ m_A164 += gt[176];
+ m_A164 += gt[177];
+ m_A164 += gt[178];
+ m_A163 += go[173];
+ m_A163 += go[174];
+ m_A162 += go[175];
+ double RHS46 = Idr[173];
+ RHS46 += Idr[174];
+ RHS46 += Idr[175];
+ RHS46 += Idr[176];
+ RHS46 += Idr[177];
+ RHS46 += Idr[178];
+ RHS46 -= go[176] * *cnV[176];
+ RHS46 -= go[177] * *cnV[177];
+ RHS46 -= go[178] * *cnV[178];
+ m_A172 += gt[179];
+ m_A172 += gt[180];
+ m_A172 += gt[181];
+ m_A172 += gt[182];
+ m_A172 += gt[183];
+ m_A166 += go[179];
+ m_A167 += go[180];
+ m_A168 += go[181];
+ double RHS47 = Idr[179];
+ RHS47 += Idr[180];
+ RHS47 += Idr[181];
+ RHS47 += Idr[182];
+ RHS47 += Idr[183];
+ RHS47 -= go[182] * *cnV[182];
+ RHS47 -= go[183] * *cnV[183];
+ m_A181 += gt[184];
+ m_A181 += gt[185];
+ m_A181 += gt[186];
+ m_A181 += gt[187];
+ m_A181 += gt[188];
+ m_A182 += go[184];
+ m_A178 += go[185];
+ m_A179 += go[186];
+ double RHS48 = Idr[184];
+ RHS48 += Idr[185];
+ RHS48 += Idr[186];
+ RHS48 += Idr[187];
+ RHS48 += Idr[188];
+ RHS48 -= go[187] * *cnV[187];
+ RHS48 -= go[188] * *cnV[188];
+ m_A183 += gt[189];
+ m_A183 += gt[190];
+ m_A183 += gt[191];
+ m_A184 += go[189];
+ double RHS49 = Idr[189];
+ RHS49 += Idr[190];
+ RHS49 += Idr[191];
+ RHS49 -= go[190] * *cnV[190];
+ RHS49 -= go[191] * *cnV[191];
+ m_A192 += gt[192];
+ m_A192 += gt[193];
+ m_A192 += gt[194];
+ m_A192 += gt[195];
+ m_A192 += gt[196];
+ m_A191 += go[192];
+ m_A186 += go[193];
+ m_A190 += go[194];
+ m_A189 += go[195];
+ m_A185 += go[196];
+ double RHS50 = Idr[192];
+ RHS50 += Idr[193];
+ RHS50 += Idr[194];
+ RHS50 += Idr[195];
+ RHS50 += Idr[196];
+ m_A201 += gt[197];
+ m_A201 += gt[198];
+ m_A201 += gt[199];
+ m_A201 += gt[200];
+ m_A197 += go[197];
+ m_A195 += go[198];
+ m_A194 += go[199];
+ m_A196 += go[200];
+ double RHS51 = Idr[197];
+ RHS51 += Idr[198];
+ RHS51 += Idr[199];
+ RHS51 += Idr[200];
+ m_A214 += gt[201];
+ m_A214 += gt[202];
+ m_A214 += gt[203];
+ m_A214 += gt[204];
+ m_A214 += gt[205];
+ m_A214 += gt[206];
+ m_A209 += go[201];
+ m_A207 += go[202];
+ m_A206 += go[203];
+ m_A210 += go[204];
+ double RHS52 = Idr[201];
+ RHS52 += Idr[202];
+ RHS52 += Idr[203];
+ RHS52 += Idr[204];
+ RHS52 += Idr[205];
+ RHS52 += Idr[206];
+ RHS52 -= go[205] * *cnV[205];
+ RHS52 -= go[206] * *cnV[206];
+ m_A225 += gt[207];
+ m_A225 += gt[208];
+ m_A225 += gt[209];
+ m_A225 += gt[210];
+ m_A225 += gt[211];
+ m_A231 += go[207];
+ m_A231 += go[208];
+ m_A220 += go[209];
+ m_A229 += go[210];
+ m_A221 += go[211];
+ double RHS53 = Idr[207];
+ RHS53 += Idr[208];
+ RHS53 += Idr[209];
+ RHS53 += Idr[210];
+ RHS53 += Idr[211];
+ m_A240 += gt[212];
+ m_A240 += gt[213];
+ m_A240 += gt[214];
+ m_A234 += go[212];
+ m_A232 += go[213];
+ m_A233 += go[214];
+ double RHS54 = Idr[212];
+ RHS54 += Idr[213];
+ RHS54 += Idr[214];
+ m_A257 += gt[215];
+ m_A257 += gt[216];
+ m_A257 += gt[217];
+ m_A257 += gt[218];
+ m_A257 += gt[219];
+ m_A257 += gt[220];
+ m_A246 += go[215];
+ m_A248 += go[216];
+ m_A250 += go[217];
+ m_A247 += go[218];
+ double RHS55 = Idr[215];
+ RHS55 += Idr[216];
+ RHS55 += Idr[217];
+ RHS55 += Idr[218];
+ RHS55 += Idr[219];
+ RHS55 += Idr[220];
+ RHS55 -= go[219] * *cnV[219];
+ RHS55 -= go[220] * *cnV[220];
+ m_A270 += gt[221];
+ m_A270 += gt[222];
+ m_A270 += gt[223];
+ m_A270 += gt[224];
+ m_A275 += go[221];
+ m_A262 += go[222];
+ m_A272 += go[223];
+ m_A263 += go[224];
+ double RHS56 = Idr[221];
+ RHS56 += Idr[222];
+ RHS56 += Idr[223];
+ RHS56 += Idr[224];
+ m_A282 += gt[225];
+ m_A282 += gt[226];
+ m_A282 += gt[227];
+ m_A282 += gt[228];
+ m_A282 += gt[229];
+ m_A278 += go[225];
+ m_A277 += go[226];
+ m_A277 += go[227];
+ m_A276 += go[228];
+ double RHS57 = Idr[225];
+ RHS57 += Idr[226];
+ RHS57 += Idr[227];
+ RHS57 += Idr[228];
+ RHS57 += Idr[229];
+ RHS57 -= go[229] * *cnV[229];
+ m_A287 += gt[230];
+ m_A287 += gt[231];
+ m_A287 += gt[232];
+ m_A288 += go[230];
+ double RHS58 = Idr[230];
+ RHS58 += Idr[231];
+ RHS58 += Idr[232];
+ RHS58 -= go[231] * *cnV[231];
+ RHS58 -= go[232] * *cnV[232];
+ m_A293 += gt[233];
+ m_A293 += gt[234];
+ m_A293 += gt[235];
+ m_A293 += gt[236];
+ m_A293 += gt[237];
+ m_A291 += go[233];
+ m_A290 += go[234];
+ m_A290 += go[235];
+ m_A289 += go[236];
+ double RHS59 = Idr[233];
+ RHS59 += Idr[234];
+ RHS59 += Idr[235];
+ RHS59 += Idr[236];
+ RHS59 += Idr[237];
+ RHS59 -= go[237] * *cnV[237];
+ m_A297 += gt[238];
+ m_A297 += gt[239];
+ m_A297 += gt[240];
+ m_A298 += go[238];
+ double RHS60 = Idr[238];
+ RHS60 += Idr[239];
+ RHS60 += Idr[240];
+ RHS60 -= go[239] * *cnV[239];
+ RHS60 -= go[240] * *cnV[240];
+ m_A299 += gt[241];
+ m_A299 += gt[242];
+ m_A299 += gt[243];
+ m_A300 += go[241];
+ double RHS61 = Idr[241];
+ RHS61 += Idr[242];
+ RHS61 += Idr[243];
+ RHS61 -= go[242] * *cnV[242];
+ RHS61 -= go[243] * *cnV[243];
+ m_A301 += gt[244];
+ m_A301 += gt[245];
+ m_A301 += gt[246];
+ m_A302 += go[244];
+ double RHS62 = Idr[244];
+ RHS62 += Idr[245];
+ RHS62 += Idr[246];
+ RHS62 -= go[245] * *cnV[245];
+ RHS62 -= go[246] * *cnV[246];
+ m_A314 += gt[247];
+ m_A314 += gt[248];
+ m_A314 += gt[249];
+ m_A314 += gt[250];
+ m_A314 += gt[251];
+ m_A303 += go[247];
+ m_A317 += go[248];
+ m_A304 += go[249];
+ double RHS63 = Idr[247];
+ RHS63 += Idr[248];
+ RHS63 += Idr[249];
+ RHS63 += Idr[250];
+ RHS63 += Idr[251];
+ RHS63 -= go[250] * *cnV[250];
+ RHS63 -= go[251] * *cnV[251];
+ m_A320 += gt[252];
+ m_A320 += gt[253];
+ m_A320 += gt[254];
+ m_A321 += go[252];
+ m_A318 += go[253];
+ m_A319 += go[254];
+ double RHS64 = Idr[252];
+ RHS64 += Idr[253];
+ RHS64 += Idr[254];
+ m_A329 += gt[255];
+ m_A329 += gt[256];
+ m_A329 += gt[257];
+ m_A331 += go[255];
+ m_A322 += go[256];
+ m_A322 += go[257];
+ double RHS65 = Idr[255];
+ RHS65 += Idr[256];
+ RHS65 += Idr[257];
+ m_A337 += gt[258];
+ m_A337 += gt[259];
+ m_A337 += gt[260];
+ m_A337 += gt[261];
+ m_A338 += go[258];
+ m_A332 += go[259];
+ double RHS66 = Idr[258];
+ RHS66 += Idr[259];
+ RHS66 += Idr[260];
+ RHS66 += Idr[261];
+ RHS66 -= go[260] * *cnV[260];
+ RHS66 -= go[261] * *cnV[261];
+ m_A349 += gt[262];
+ m_A349 += gt[263];
+ m_A349 += gt[264];
+ m_A349 += gt[265];
+ m_A349 += gt[266];
+ m_A349 += gt[267];
+ m_A349 += gt[268];
+ m_A349 += gt[269];
+ m_A349 += gt[270];
+ m_A349 += gt[271];
+ m_A346 += go[262];
+ m_A347 += go[263];
+ m_A348 += go[264];
+ m_A345 += go[265];
+ m_A344 += go[266];
+ m_A343 += go[267];
+ m_A342 += go[268];
+ m_A341 += go[269];
+ m_A340 += go[270];
+ m_A339 += go[271];
+ double RHS67 = Idr[262];
+ RHS67 += Idr[263];
+ RHS67 += Idr[264];
+ RHS67 += Idr[265];
+ RHS67 += Idr[266];
+ RHS67 += Idr[267];
+ RHS67 += Idr[268];
+ RHS67 += Idr[269];
+ RHS67 += Idr[270];
+ RHS67 += Idr[271];
+ const double f0 = 1.0 / m_A0;
+ const double f0_30 = -f0 * m_A81;
+ m_A83 += m_A1 * f0_30;
+ RHS30 += f0_30 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_32 = -f1 * m_A88;
+ m_A89 += m_A3 * f1_32;
+ RHS32 += f1_32 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_30 = -f2 * m_A82;
+ m_A83 += m_A5 * f2_30;
+ m_A84 += m_A6 * f2_30;
+ RHS30 += f2_30 * RHS2;
+ const double f2_50 = -f2 * m_A185;
+ m_A187 += m_A5 * f2_50;
+ m_A192 += m_A6 * f2_50;
+ RHS50 += f2_50 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_34 = -f3 * m_A97;
+ m_A98 += m_A8 * f3_34;
+ RHS34 += f3_34 * RHS3;
+ const double f4 = 1.0 / m_A9;
+ const double f4_31 = -f4 * m_A85;
+ m_A86 += m_A10 * f4_31;
+ m_A87 += m_A11 * f4_31;
+ RHS31 += f4_31 * RHS4;
+ const double f4_50 = -f4 * m_A186;
+ m_A188 += m_A10 * f4_50;
+ m_A192 += m_A11 * f4_50;
+ RHS50 += f4_50 * RHS4;
+ const double f5 = 1.0 / m_A12;
+ const double f5_35 = -f5 * m_A100;
+ m_A101 += m_A13 * f5_35;
+ RHS35 += f5_35 * RHS5;
+ const double f6 = 1.0 / m_A14;
+ const double f6_38 = -f6 * m_A116;
+ m_A119 += m_A15 * f6_38;
+ RHS38 += f6_38 * RHS6;
+ const double f7 = 1.0 / m_A16;
+ const double f7_51 = -f7 * m_A194;
+ m_A201 += m_A17 * f7_51;
+ RHS51 += f7_51 * RHS7;
+ const double f8 = 1.0 / m_A18;
+ const double f8_38 = -f8 * m_A117;
+ m_A119 += m_A19 * f8_38;
+ RHS38 += f8_38 * RHS8;
+ const double f9 = 1.0 / m_A20;
+ const double f9_36 = -f9 * m_A104;
+ m_A106 += m_A21 * f9_36;
+ m_A107 += m_A22 * f9_36;
+ m_A108 += m_A23 * f9_36;
+ RHS36 += f9_36 * RHS9;
+ const double f9_37 = -f9 * m_A109;
+ m_A112 += m_A21 * f9_37;
+ m_A114 += m_A22 * f9_37;
+ m_A115 += m_A23 * f9_37;
+ RHS37 += f9_37 * RHS9;
+ const double f9_47 = -f9 * m_A166;
+ m_A169 += m_A21 * f9_47;
+ m_A172 += m_A22 * f9_47;
+ m_A173 += m_A23 * f9_47;
+ RHS47 += f9_47 * RHS9;
+ const double f9_51 = -f9 * m_A195;
+ m_A197 += m_A21 * f9_51;
+ m_A199 += m_A22 * f9_51;
+ m_A201 += m_A23 * f9_51;
+ RHS51 += f9_51 * RHS9;
+ const double f10 = 1.0 / m_A24;
+ const double f10_37 = -f10 * m_A110;
+ m_A111 += m_A25 * f10_37;
+ m_A112 += m_A26 * f10_37;
+ m_A113 += m_A27 * f10_37;
+ RHS37 += f10_37 * RHS10;
+ const double f10_40 = -f10 * m_A126;
+ m_A128 += m_A25 * f10_40;
+ m_A129 += m_A26 * f10_40;
+ m_A130 += m_A27 * f10_40;
+ RHS40 += f10_40 * RHS10;
+ const double f11 = 1.0 / m_A28;
+ const double f11_41 = -f11 * m_A134;
+ m_A135 += m_A29 * f11_41;
+ m_A141 += m_A30 * f11_41;
+ RHS41 += f11_41 * RHS11;
+ const double f12 = 1.0 / m_A31;
+ const double f12_38 = -f12 * m_A118;
+ m_A119 += m_A32 * f12_38;
+ m_A120 += m_A33 * f12_38;
+ m_A121 += m_A34 * f12_38;
+ RHS38 += f12_38 * RHS12;
+ const double f12_41 = -f12 * m_A135;
+ m_A137 += m_A32 * f12_41;
+ m_A140 += m_A33 * f12_41;
+ m_A141 += m_A34 * f12_41;
+ RHS41 += f12_41 * RHS12;
+ const double f12_47 = -f12 * m_A167;
+ m_A170 += m_A32 * f12_47;
+ m_A172 += m_A33 * f12_47;
+ m_A176 += m_A34 * f12_47;
+ RHS47 += f12_47 * RHS12;
+ const double f12_54 = -f12 * m_A232;
+ m_A233 += m_A32 * f12_54;
+ m_A236 += m_A33 * f12_54;
+ m_A240 += m_A34 * f12_54;
+ RHS54 += f12_54 * RHS12;
+ const double f13 = 1.0 / m_A35;
+ const double f13_39 = -f13 * m_A122;
+ m_A124 += m_A36 * f13_39;
+ m_A125 += m_A37 * f13_39;
+ RHS39 += f13_39 * RHS13;
+ const double f13_40 = -f13 * m_A127;
+ m_A130 += m_A36 * f13_40;
+ m_A133 += m_A37 * f13_40;
+ RHS40 += f13_40 * RHS13;
+ const double f13_52 = -f13 * m_A206;
+ m_A210 += m_A36 * f13_52;
+ m_A214 += m_A37 * f13_52;
+ RHS52 += f13_52 * RHS13;
+ const double f14 = 1.0 / m_A38;
+ const double f14_55 = -f14 * m_A246;
+ m_A250 += m_A39 * f14_55;
+ RHS55 += f14_55 * RHS14;
+ const double f15 = 1.0 / m_A40;
+ const double f15_41 = -f15 * m_A136;
+ m_A138 += m_A41 * f15_41;
+ m_A139 += m_A42 * f15_41;
+ m_A142 += m_A43 * f15_41;
+ RHS41 += f15_41 * RHS15;
+ const double f15_42 = -f15 * m_A143;
+ m_A144 += m_A41 * f15_42;
+ m_A145 += m_A42 * f15_42;
+ m_A148 += m_A43 * f15_42;
+ RHS42 += f15_42 * RHS15;
+ const double f15_55 = -f15 * m_A247;
+ m_A249 += m_A41 * f15_55;
+ m_A250 += m_A42 * f15_55;
+ m_A257 += m_A43 * f15_55;
+ RHS55 += f15_55 * RHS15;
+ const double f16 = 1.0 / m_A44;
+ const double f16_33 = -f16 * m_A91;
+ m_A93 += m_A45 * f16_33;
+ m_A95 += m_A46 * f16_33;
+ RHS33 += f16_33 * RHS16;
+ const double f16_52 = -f16 * m_A207;
+ m_A208 += m_A45 * f16_52;
+ m_A214 += m_A46 * f16_52;
+ RHS52 += f16_52 * RHS16;
+ const double f17 = 1.0 / m_A47;
+ const double f17_45 = -f17 * m_A155;
+ m_A158 += m_A48 * f17_45;
+ m_A160 += m_A49 * f17_45;
+ RHS45 += f17_45 * RHS17;
+ const double f17_55 = -f17 * m_A248;
+ m_A251 += m_A48 * f17_55;
+ m_A257 += m_A49 * f17_55;
+ RHS55 += f17_55 * RHS17;
+ const double f18 = 1.0 / m_A50;
+ const double f18_63 = -f18 * m_A303;
+ m_A304 += m_A51 * f18_63;
+ RHS63 += f18_63 * RHS18;
+ const double f19 = 1.0 / m_A52;
+ const double f19_46 = -f19 * m_A162;
+ m_A164 += m_A53 * f19_46;
+ RHS46 += f19_46 * RHS19;
+ const double f20 = 1.0 / m_A54;
+ const double f20_43 = -f20 * m_A149;
+ m_A150 += m_A55 * f20_43;
+ m_A151 += m_A56 * f20_43;
+ RHS43 += f20_43 * RHS20;
+ const double f20_59 = -f20 * m_A289;
+ m_A290 += m_A55 * f20_59;
+ m_A293 += m_A56 * f20_59;
+ RHS59 += f20_59 * RHS20;
+ const double f21 = 1.0 / m_A57;
+ const double f21_44 = -f21 * m_A152;
+ m_A153 += m_A58 * f21_44;
+ m_A154 += m_A59 * f21_44;
+ RHS44 += f21_44 * RHS21;
+ const double f21_57 = -f21 * m_A276;
+ m_A277 += m_A58 * f21_57;
+ m_A282 += m_A59 * f21_57;
+ RHS57 += f21_57 * RHS21;
+ const double f22 = 1.0 / m_A60;
+ const double f22_33 = -f22 * m_A92;
+ m_A93 += m_A61 * f22_33;
+ m_A94 += m_A62 * f22_33;
+ m_A96 += m_A63 * f22_33;
+ RHS33 += f22_33 * RHS22;
+ const double f22_45 = -f22 * m_A156;
+ m_A157 += m_A61 * f22_45;
+ m_A158 += m_A62 * f22_45;
+ m_A161 += m_A63 * f22_45;
+ RHS45 += f22_45 * RHS22;
+ const double f22_63 = -f22 * m_A304;
+ m_A305 += m_A61 * f22_63;
+ m_A306 += m_A62 * f22_63;
+ m_A314 += m_A63 * f22_63;
+ RHS63 += f22_63 * RHS22;
+ const double f23 = 1.0 / m_A64;
+ const double f23_56 = -f23 * m_A262;
+ m_A270 += m_A65 * f23_56;
+ RHS56 += f23_56 * RHS23;
+ const double f24 = 1.0 / m_A66;
+ const double f24_53 = -f24 * m_A220;
+ m_A225 += m_A67 * f24_53;
+ RHS53 += f24_53 * RHS24;
+ const double f25 = 1.0 / m_A68;
+ const double f25_48 = -f25 * m_A178;
+ m_A181 += m_A69 * f25_48;
+ RHS48 += f25_48 * RHS25;
+ const double f26 = 1.0 / m_A70;
+ const double f26_46 = -f26 * m_A163;
+ m_A164 += m_A71 * f26_46;
+ m_A165 += m_A72 * f26_46;
+ RHS46 += f26_46 * RHS26;
+ const double f26_48 = -f26 * m_A179;
+ m_A180 += m_A71 * f26_48;
+ m_A181 += m_A72 * f26_48;
+ RHS48 += f26_48 * RHS26;
+ const double f27 = 1.0 / m_A73;
+ const double f27_47 = -f27 * m_A168;
+ m_A172 += m_A74 * f27_47;
+ m_A175 += m_A75 * f27_47;
+ m_A177 += m_A76 * f27_47;
+ RHS47 += f27_47 * RHS27;
+ const double f27_53 = -f27 * m_A221;
+ m_A222 += m_A74 * f27_53;
+ m_A225 += m_A75 * f27_53;
+ m_A228 += m_A76 * f27_53;
+ RHS53 += f27_53 * RHS27;
+ const double f27_56 = -f27 * m_A263;
+ m_A264 += m_A74 * f27_56;
+ m_A267 += m_A75 * f27_56;
+ m_A270 += m_A76 * f27_56;
+ RHS56 += f27_56 * RHS27;
+ const double f28 = 1.0 / m_A77;
+ const double f28_64 = -f28 * m_A318;
+ m_A320 += m_A78 * f28_64;
+ RHS64 += f28_64 * RHS28;
+ const double f29 = 1.0 / m_A79;
+ const double f29_67 = -f29 * m_A339;
+ m_A349 += m_A80 * f29_67;
+ RHS67 += f29_67 * RHS29;
+ const double f30 = 1.0 / m_A83;
+ const double f30_50 = -f30 * m_A187;
+ m_A192 += m_A84 * f30_50;
+ RHS50 += f30_50 * RHS30;
+ const double f31 = 1.0 / m_A86;
+ const double f31_50 = -f31 * m_A188;
+ m_A192 += m_A87 * f31_50;
+ RHS50 += f31_50 * RHS31;
+ const double f32 = 1.0 / m_A89;
+ const double f32_50 = -f32 * m_A189;
+ m_A192 += m_A90 * f32_50;
+ RHS50 += f32_50 * RHS32;
+ const double f33 = 1.0 / m_A93;
+ const double f33_45 = -f33 * m_A157;
+ m_A158 += m_A94 * f33_45;
+ m_A159 += m_A95 * f33_45;
+ m_A161 += m_A96 * f33_45;
+ RHS45 += f33_45 * RHS33;
+ const double f33_52 = -f33 * m_A208;
+ m_A211 += m_A94 * f33_52;
+ m_A214 += m_A95 * f33_52;
+ m_A219 += m_A96 * f33_52;
+ RHS52 += f33_52 * RHS33;
+ const double f33_63 = -f33 * m_A305;
+ m_A306 += m_A94 * f33_63;
+ m_A307 += m_A95 * f33_63;
+ m_A314 += m_A96 * f33_63;
+ RHS63 += f33_63 * RHS33;
+ const double f34 = 1.0 / m_A98;
+ const double f34_50 = -f34 * m_A190;
+ m_A192 += m_A99 * f34_50;
+ RHS50 += f34_50 * RHS34;
+ const double f35 = 1.0 / m_A101;
+ const double f35_50 = -f35 * m_A191;
+ m_A192 += m_A102 * f35_50;
+ m_A193 += m_A103 * f35_50;
+ RHS50 += f35_50 * RHS35;
+ const double f35_51 = -f35 * m_A196;
+ m_A200 += m_A102 * f35_51;
+ m_A201 += m_A103 * f35_51;
+ RHS51 += f35_51 * RHS35;
+ const double f36 = 1.0 / m_A105;
+ const double f36_37 = -f36 * m_A111;
+ m_A112 += m_A106 * f36_37;
+ m_A114 += m_A107 * f36_37;
+ m_A115 += m_A108 * f36_37;
+ RHS37 += f36_37 * RHS36;
+ const double f36_40 = -f36 * m_A128;
+ m_A129 += m_A106 * f36_40;
+ m_A131 += m_A107 * f36_40;
+ m_A132 += m_A108 * f36_40;
+ RHS40 += f36_40 * RHS36;
+ const double f37 = 1.0 / m_A112;
+ const double f37_40 = -f37 * m_A129;
+ m_A130 += m_A113 * f37_40;
+ m_A131 += m_A114 * f37_40;
+ m_A132 += m_A115 * f37_40;
+ RHS40 += f37_40 * RHS37;
+ const double f37_47 = -f37 * m_A169;
+ m_A171 += m_A113 * f37_47;
+ m_A172 += m_A114 * f37_47;
+ m_A173 += m_A115 * f37_47;
+ RHS47 += f37_47 * RHS37;
+ const double f37_51 = -f37 * m_A197;
+ m_A198 += m_A113 * f37_51;
+ m_A199 += m_A114 * f37_51;
+ m_A201 += m_A115 * f37_51;
+ RHS51 += f37_51 * RHS37;
+ const double f38 = 1.0 / m_A119;
+ const double f38_41 = -f38 * m_A137;
+ m_A140 += m_A120 * f38_41;
+ m_A141 += m_A121 * f38_41;
+ RHS41 += f38_41 * RHS38;
+ const double f38_47 = -f38 * m_A170;
+ m_A172 += m_A120 * f38_47;
+ m_A176 += m_A121 * f38_47;
+ RHS47 += f38_47 * RHS38;
+ const double f38_54 = -f38 * m_A233;
+ m_A236 += m_A120 * f38_54;
+ m_A240 += m_A121 * f38_54;
+ RHS54 += f38_54 * RHS38;
+ const double f39 = 1.0 / m_A123;
+ const double f39_52 = -f39 * m_A209;
+ m_A210 += m_A124 * f39_52;
+ m_A214 += m_A125 * f39_52;
+ RHS52 += f39_52 * RHS39;
+ const double f40 = 1.0 / m_A130;
+ const double f40_47 = -f40 * m_A171;
+ m_A172 += m_A131 * f40_47;
+ m_A173 += m_A132 * f40_47;
+ m_A174 += m_A133 * f40_47;
+ RHS47 += f40_47 * RHS40;
+ const double f40_51 = -f40 * m_A198;
+ m_A199 += m_A131 * f40_51;
+ m_A201 += m_A132 * f40_51;
+ m_A202 += m_A133 * f40_51;
+ RHS51 += f40_51 * RHS40;
+ const double f40_52 = -f40 * m_A210;
+ m_A212 += m_A131 * f40_52;
+ m_A213 += m_A132 * f40_52;
+ m_A214 += m_A133 * f40_52;
+ RHS52 += f40_52 * RHS40;
+ const double f41 = 1.0 / m_A138;
+ const double f41_42 = -f41 * m_A144;
+ m_A145 += m_A139 * f41_42;
+ m_A146 += m_A140 * f41_42;
+ m_A147 += m_A141 * f41_42;
+ m_A148 += m_A142 * f41_42;
+ RHS42 += f41_42 * RHS41;
+ const double f41_54 = -f41 * m_A234;
+ m_A235 += m_A139 * f41_54;
+ m_A236 += m_A140 * f41_54;
+ m_A240 += m_A141 * f41_54;
+ m_A241 += m_A142 * f41_54;
+ RHS54 += f41_54 * RHS41;
+ const double f41_55 = -f41 * m_A249;
+ m_A250 += m_A139 * f41_55;
+ m_A252 += m_A140 * f41_55;
+ m_A256 += m_A141 * f41_55;
+ m_A257 += m_A142 * f41_55;
+ RHS55 += f41_55 * RHS41;
+ const double f42 = 1.0 / m_A145;
+ const double f42_54 = -f42 * m_A235;
+ m_A236 += m_A146 * f42_54;
+ m_A240 += m_A147 * f42_54;
+ m_A241 += m_A148 * f42_54;
+ RHS54 += f42_54 * RHS42;
+ const double f42_55 = -f42 * m_A250;
+ m_A252 += m_A146 * f42_55;
+ m_A256 += m_A147 * f42_55;
+ m_A257 += m_A148 * f42_55;
+ RHS55 += f42_55 * RHS42;
+ const double f43 = 1.0 / m_A150;
+ const double f43_59 = -f43 * m_A290;
+ m_A293 += m_A151 * f43_59;
+ RHS59 += f43_59 * RHS43;
+ const double f44 = 1.0 / m_A153;
+ const double f44_57 = -f44 * m_A277;
+ m_A282 += m_A154 * f44_57;
+ RHS57 += f44_57 * RHS44;
+ const double f45 = 1.0 / m_A158;
+ const double f45_52 = -f45 * m_A211;
+ m_A214 += m_A159 * f45_52;
+ m_A217 += m_A160 * f45_52;
+ m_A219 += m_A161 * f45_52;
+ RHS52 += f45_52 * RHS45;
+ const double f45_55 = -f45 * m_A251;
+ m_A254 += m_A159 * f45_55;
+ m_A257 += m_A160 * f45_55;
+ m_A260 += m_A161 * f45_55;
+ RHS55 += f45_55 * RHS45;
+ const double f45_63 = -f45 * m_A306;
+ m_A307 += m_A159 * f45_63;
+ m_A310 += m_A160 * f45_63;
+ m_A314 += m_A161 * f45_63;
+ RHS63 += f45_63 * RHS45;
+ const double f46 = 1.0 / m_A164;
+ const double f46_48 = -f46 * m_A180;
+ m_A181 += m_A165 * f46_48;
+ RHS48 += f46_48 * RHS46;
+ const double f47 = 1.0 / m_A172;
+ const double f47_51 = -f47 * m_A199;
+ m_A201 += m_A173 * f47_51;
+ m_A202 += m_A174 * f47_51;
+ m_A203 += m_A175 * f47_51;
+ m_A204 += m_A176 * f47_51;
+ m_A205 += m_A177 * f47_51;
+ RHS51 += f47_51 * RHS47;
+ const double f47_52 = -f47 * m_A212;
+ m_A213 += m_A173 * f47_52;
+ m_A214 += m_A174 * f47_52;
+ m_A215 += m_A175 * f47_52;
+ m_A216 += m_A176 * f47_52;
+ m_A218 += m_A177 * f47_52;
+ RHS52 += f47_52 * RHS47;
+ const double f47_53 = -f47 * m_A222;
+ m_A223 += m_A173 * f47_53;
+ m_A224 += m_A174 * f47_53;
+ m_A225 += m_A175 * f47_53;
+ m_A226 += m_A176 * f47_53;
+ m_A228 += m_A177 * f47_53;
+ RHS53 += f47_53 * RHS47;
+ const double f47_54 = -f47 * m_A236;
+ m_A237 += m_A173 * f47_54;
+ m_A238 += m_A174 * f47_54;
+ m_A239 += m_A175 * f47_54;
+ m_A240 += m_A176 * f47_54;
+ m_A242 += m_A177 * f47_54;
+ RHS54 += f47_54 * RHS47;
+ const double f47_55 = -f47 * m_A252;
+ m_A253 += m_A173 * f47_55;
+ m_A254 += m_A174 * f47_55;
+ m_A255 += m_A175 * f47_55;
+ m_A256 += m_A176 * f47_55;
+ m_A258 += m_A177 * f47_55;
+ RHS55 += f47_55 * RHS47;
+ const double f47_56 = -f47 * m_A264;
+ m_A265 += m_A173 * f47_56;
+ m_A266 += m_A174 * f47_56;
+ m_A267 += m_A175 * f47_56;
+ m_A268 += m_A176 * f47_56;
+ m_A270 += m_A177 * f47_56;
+ RHS56 += f47_56 * RHS47;
+ const double f48 = 1.0 / m_A181;
+ const double f48_64 = -f48 * m_A319;
+ m_A320 += m_A182 * f48_64;
+ RHS64 += f48_64 * RHS48;
+ const double f49 = 1.0 / m_A183;
+ const double f49_67 = -f49 * m_A340;
+ m_A349 += m_A184 * f49_67;
+ RHS67 += f49_67 * RHS49;
+ const double f50 = 1.0 / m_A192;
+ const double f50_51 = -f50 * m_A200;
+ m_A201 += m_A193 * f50_51;
+ RHS51 += f50_51 * RHS50;
+ const double f51 = 1.0 / m_A201;
+ const double f51_52 = -f51 * m_A213;
+ m_A214 += m_A202 * f51_52;
+ m_A215 += m_A203 * f51_52;
+ m_A216 += m_A204 * f51_52;
+ m_A218 += m_A205 * f51_52;
+ RHS52 += f51_52 * RHS51;
+ const double f51_53 = -f51 * m_A223;
+ m_A224 += m_A202 * f51_53;
+ m_A225 += m_A203 * f51_53;
+ m_A226 += m_A204 * f51_53;
+ m_A228 += m_A205 * f51_53;
+ RHS53 += f51_53 * RHS51;
+ const double f51_54 = -f51 * m_A237;
+ m_A238 += m_A202 * f51_54;
+ m_A239 += m_A203 * f51_54;
+ m_A240 += m_A204 * f51_54;
+ m_A242 += m_A205 * f51_54;
+ RHS54 += f51_54 * RHS51;
+ const double f51_55 = -f51 * m_A253;
+ m_A254 += m_A202 * f51_55;
+ m_A255 += m_A203 * f51_55;
+ m_A256 += m_A204 * f51_55;
+ m_A258 += m_A205 * f51_55;
+ RHS55 += f51_55 * RHS51;
+ const double f51_56 = -f51 * m_A265;
+ m_A266 += m_A202 * f51_56;
+ m_A267 += m_A203 * f51_56;
+ m_A268 += m_A204 * f51_56;
+ m_A270 += m_A205 * f51_56;
+ RHS56 += f51_56 * RHS51;
+ const double f52 = 1.0 / m_A214;
+ const double f52_53 = -f52 * m_A224;
+ m_A225 += m_A215 * f52_53;
+ m_A226 += m_A216 * f52_53;
+ m_A227 += m_A217 * f52_53;
+ m_A228 += m_A218 * f52_53;
+ m_A230 += m_A219 * f52_53;
+ RHS53 += f52_53 * RHS52;
+ const double f52_54 = -f52 * m_A238;
+ m_A239 += m_A215 * f52_54;
+ m_A240 += m_A216 * f52_54;
+ m_A241 += m_A217 * f52_54;
+ m_A242 += m_A218 * f52_54;
+ m_A244 += m_A219 * f52_54;
+ RHS54 += f52_54 * RHS52;
+ const double f52_55 = -f52 * m_A254;
+ m_A255 += m_A215 * f52_55;
+ m_A256 += m_A216 * f52_55;
+ m_A257 += m_A217 * f52_55;
+ m_A258 += m_A218 * f52_55;
+ m_A260 += m_A219 * f52_55;
+ RHS55 += f52_55 * RHS52;
+ const double f52_56 = -f52 * m_A266;
+ m_A267 += m_A215 * f52_56;
+ m_A268 += m_A216 * f52_56;
+ m_A269 += m_A217 * f52_56;
+ m_A270 += m_A218 * f52_56;
+ m_A273 += m_A219 * f52_56;
+ RHS56 += f52_56 * RHS52;
+ const double f52_63 = -f52 * m_A307;
+ m_A308 += m_A215 * f52_63;
+ m_A309 += m_A216 * f52_63;
+ m_A310 += m_A217 * f52_63;
+ m_A311 += m_A218 * f52_63;
+ m_A314 += m_A219 * f52_63;
+ RHS63 += f52_63 * RHS52;
+ const double f53 = 1.0 / m_A225;
+ const double f53_54 = -f53 * m_A239;
+ m_A240 += m_A226 * f53_54;
+ m_A241 += m_A227 * f53_54;
+ m_A242 += m_A228 * f53_54;
+ m_A243 += m_A229 * f53_54;
+ m_A244 += m_A230 * f53_54;
+ m_A245 += m_A231 * f53_54;
+ RHS54 += f53_54 * RHS53;
+ const double f53_55 = -f53 * m_A255;
+ m_A256 += m_A226 * f53_55;
+ m_A257 += m_A227 * f53_55;
+ m_A258 += m_A228 * f53_55;
+ m_A259 += m_A229 * f53_55;
+ m_A260 += m_A230 * f53_55;
+ m_A261 += m_A231 * f53_55;
+ RHS55 += f53_55 * RHS53;
+ const double f53_56 = -f53 * m_A267;
+ m_A268 += m_A226 * f53_56;
+ m_A269 += m_A227 * f53_56;
+ m_A270 += m_A228 * f53_56;
+ m_A271 += m_A229 * f53_56;
+ m_A273 += m_A230 * f53_56;
+ m_A274 += m_A231 * f53_56;
+ RHS56 += f53_56 * RHS53;
+ const double f53_57 = -f53 * m_A278;
+ m_A279 += m_A226 * f53_57;
+ m_A280 += m_A227 * f53_57;
+ m_A281 += m_A228 * f53_57;
+ m_A282 += m_A229 * f53_57;
+ m_A284 += m_A230 * f53_57;
+ m_A285 += m_A231 * f53_57;
+ RHS57 += f53_57 * RHS53;
+ const double f53_63 = -f53 * m_A308;
+ m_A309 += m_A226 * f53_63;
+ m_A310 += m_A227 * f53_63;
+ m_A311 += m_A228 * f53_63;
+ m_A312 += m_A229 * f53_63;
+ m_A314 += m_A230 * f53_63;
+ m_A315 += m_A231 * f53_63;
+ RHS63 += f53_63 * RHS53;
+ const double f53_65 = -f53 * m_A322;
+ m_A323 += m_A226 * f53_65;
+ m_A324 += m_A227 * f53_65;
+ m_A325 += m_A228 * f53_65;
+ m_A326 += m_A229 * f53_65;
+ m_A328 += m_A230 * f53_65;
+ m_A329 += m_A231 * f53_65;
+ RHS65 += f53_65 * RHS53;
+ const double f54 = 1.0 / m_A240;
+ const double f54_55 = -f54 * m_A256;
+ m_A257 += m_A241 * f54_55;
+ m_A258 += m_A242 * f54_55;
+ m_A259 += m_A243 * f54_55;
+ m_A260 += m_A244 * f54_55;
+ m_A261 += m_A245 * f54_55;
+ RHS55 += f54_55 * RHS54;
+ const double f54_56 = -f54 * m_A268;
+ m_A269 += m_A241 * f54_56;
+ m_A270 += m_A242 * f54_56;
+ m_A271 += m_A243 * f54_56;
+ m_A273 += m_A244 * f54_56;
+ m_A274 += m_A245 * f54_56;
+ RHS56 += f54_56 * RHS54;
+ const double f54_57 = -f54 * m_A279;
+ m_A280 += m_A241 * f54_57;
+ m_A281 += m_A242 * f54_57;
+ m_A282 += m_A243 * f54_57;
+ m_A284 += m_A244 * f54_57;
+ m_A285 += m_A245 * f54_57;
+ RHS57 += f54_57 * RHS54;
+ const double f54_63 = -f54 * m_A309;
+ m_A310 += m_A241 * f54_63;
+ m_A311 += m_A242 * f54_63;
+ m_A312 += m_A243 * f54_63;
+ m_A314 += m_A244 * f54_63;
+ m_A315 += m_A245 * f54_63;
+ RHS63 += f54_63 * RHS54;
+ const double f54_65 = -f54 * m_A323;
+ m_A324 += m_A241 * f54_65;
+ m_A325 += m_A242 * f54_65;
+ m_A326 += m_A243 * f54_65;
+ m_A328 += m_A244 * f54_65;
+ m_A329 += m_A245 * f54_65;
+ RHS65 += f54_65 * RHS54;
+ const double f55 = 1.0 / m_A257;
+ const double f55_56 = -f55 * m_A269;
+ m_A270 += m_A258 * f55_56;
+ m_A271 += m_A259 * f55_56;
+ m_A273 += m_A260 * f55_56;
+ m_A274 += m_A261 * f55_56;
+ RHS56 += f55_56 * RHS55;
+ const double f55_57 = -f55 * m_A280;
+ m_A281 += m_A258 * f55_57;
+ m_A282 += m_A259 * f55_57;
+ m_A284 += m_A260 * f55_57;
+ m_A285 += m_A261 * f55_57;
+ RHS57 += f55_57 * RHS55;
+ const double f55_63 = -f55 * m_A310;
+ m_A311 += m_A258 * f55_63;
+ m_A312 += m_A259 * f55_63;
+ m_A314 += m_A260 * f55_63;
+ m_A315 += m_A261 * f55_63;
+ RHS63 += f55_63 * RHS55;
+ const double f55_65 = -f55 * m_A324;
+ m_A325 += m_A258 * f55_65;
+ m_A326 += m_A259 * f55_65;
+ m_A328 += m_A260 * f55_65;
+ m_A329 += m_A261 * f55_65;
+ RHS65 += f55_65 * RHS55;
+ const double f56 = 1.0 / m_A270;
+ const double f56_57 = -f56 * m_A281;
+ m_A282 += m_A271 * f56_57;
+ m_A283 += m_A272 * f56_57;
+ m_A284 += m_A273 * f56_57;
+ m_A285 += m_A274 * f56_57;
+ m_A286 += m_A275 * f56_57;
+ RHS57 += f56_57 * RHS56;
+ const double f56_59 = -f56 * m_A291;
+ m_A292 += m_A271 * f56_59;
+ m_A293 += m_A272 * f56_59;
+ m_A294 += m_A273 * f56_59;
+ m_A295 += m_A274 * f56_59;
+ m_A296 += m_A275 * f56_59;
+ RHS59 += f56_59 * RHS56;
+ const double f56_63 = -f56 * m_A311;
+ m_A312 += m_A271 * f56_63;
+ m_A313 += m_A272 * f56_63;
+ m_A314 += m_A273 * f56_63;
+ m_A315 += m_A274 * f56_63;
+ m_A316 += m_A275 * f56_63;
+ RHS63 += f56_63 * RHS56;
+ const double f56_65 = -f56 * m_A325;
+ m_A326 += m_A271 * f56_65;
+ m_A327 += m_A272 * f56_65;
+ m_A328 += m_A273 * f56_65;
+ m_A329 += m_A274 * f56_65;
+ m_A330 += m_A275 * f56_65;
+ RHS65 += f56_65 * RHS56;
+ const double f56_66 = -f56 * m_A332;
+ m_A333 += m_A271 * f56_66;
+ m_A334 += m_A272 * f56_66;
+ m_A335 += m_A273 * f56_66;
+ m_A336 += m_A274 * f56_66;
+ m_A337 += m_A275 * f56_66;
+ RHS66 += f56_66 * RHS56;
+ const double f57 = 1.0 / m_A282;
+ const double f57_59 = -f57 * m_A292;
+ m_A293 += m_A283 * f57_59;
+ m_A294 += m_A284 * f57_59;
+ m_A295 += m_A285 * f57_59;
+ m_A296 += m_A286 * f57_59;
+ RHS59 += f57_59 * RHS57;
+ const double f57_63 = -f57 * m_A312;
+ m_A313 += m_A283 * f57_63;
+ m_A314 += m_A284 * f57_63;
+ m_A315 += m_A285 * f57_63;
+ m_A316 += m_A286 * f57_63;
+ RHS63 += f57_63 * RHS57;
+ const double f57_65 = -f57 * m_A326;
+ m_A327 += m_A283 * f57_65;
+ m_A328 += m_A284 * f57_65;
+ m_A329 += m_A285 * f57_65;
+ m_A330 += m_A286 * f57_65;
+ RHS65 += f57_65 * RHS57;
+ const double f57_66 = -f57 * m_A333;
+ m_A334 += m_A283 * f57_66;
+ m_A335 += m_A284 * f57_66;
+ m_A336 += m_A285 * f57_66;
+ m_A337 += m_A286 * f57_66;
+ RHS66 += f57_66 * RHS57;
+ const double f58 = 1.0 / m_A287;
+ const double f58_67 = -f58 * m_A341;
+ m_A349 += m_A288 * f58_67;
+ RHS67 += f58_67 * RHS58;
+ const double f59 = 1.0 / m_A293;
+ const double f59_63 = -f59 * m_A313;
+ m_A314 += m_A294 * f59_63;
+ m_A315 += m_A295 * f59_63;
+ m_A316 += m_A296 * f59_63;
+ RHS63 += f59_63 * RHS59;
+ const double f59_65 = -f59 * m_A327;
+ m_A328 += m_A294 * f59_65;
+ m_A329 += m_A295 * f59_65;
+ m_A330 += m_A296 * f59_65;
+ RHS65 += f59_65 * RHS59;
+ const double f59_66 = -f59 * m_A334;
+ m_A335 += m_A294 * f59_66;
+ m_A336 += m_A295 * f59_66;
+ m_A337 += m_A296 * f59_66;
+ RHS66 += f59_66 * RHS59;
+ const double f60 = 1.0 / m_A297;
+ const double f60_67 = -f60 * m_A342;
+ m_A349 += m_A298 * f60_67;
+ RHS67 += f60_67 * RHS60;
+ const double f61 = 1.0 / m_A299;
+ const double f61_67 = -f61 * m_A343;
+ m_A349 += m_A300 * f61_67;
+ RHS67 += f61_67 * RHS61;
+ const double f62 = 1.0 / m_A301;
+ const double f62_67 = -f62 * m_A344;
+ m_A349 += m_A302 * f62_67;
+ RHS67 += f62_67 * RHS62;
+ const double f63 = 1.0 / m_A314;
+ const double f63_65 = -f63 * m_A328;
+ m_A329 += m_A315 * f63_65;
+ m_A330 += m_A316 * f63_65;
+ m_A331 += m_A317 * f63_65;
+ RHS65 += f63_65 * RHS63;
+ const double f63_66 = -f63 * m_A335;
+ m_A336 += m_A315 * f63_66;
+ m_A337 += m_A316 * f63_66;
+ m_A338 += m_A317 * f63_66;
+ RHS66 += f63_66 * RHS63;
+ const double f63_67 = -f63 * m_A345;
+ m_A347 += m_A315 * f63_67;
+ m_A348 += m_A316 * f63_67;
+ m_A349 += m_A317 * f63_67;
+ RHS67 += f63_67 * RHS63;
+ const double f64 = 1.0 / m_A320;
+ const double f64_67 = -f64 * m_A346;
+ m_A349 += m_A321 * f64_67;
+ RHS67 += f64_67 * RHS64;
+ const double f65 = 1.0 / m_A329;
+ const double f65_66 = -f65 * m_A336;
+ m_A337 += m_A330 * f65_66;
+ m_A338 += m_A331 * f65_66;
+ RHS66 += f65_66 * RHS65;
+ const double f65_67 = -f65 * m_A347;
+ m_A348 += m_A330 * f65_67;
+ m_A349 += m_A331 * f65_67;
+ RHS67 += f65_67 * RHS65;
+ const double f66 = 1.0 / m_A337;
+ const double f66_67 = -f66 * m_A348;
+ m_A349 += m_A338 * f66_67;
+ RHS67 += f66_67 * RHS66;
+ V[67] = RHS67 / m_A349;
+ double tmp66 = 0.0;
+ tmp66 += m_A338 * V[67];
+ V[66] = (RHS66 - tmp66) / m_A337;
+ double tmp65 = 0.0;
+ tmp65 += m_A330 * V[66];
+ tmp65 += m_A331 * V[67];
+ V[65] = (RHS65 - tmp65) / m_A329;
+ double tmp64 = 0.0;
+ tmp64 += m_A321 * V[67];
+ V[64] = (RHS64 - tmp64) / m_A320;
+ double tmp63 = 0.0;
+ tmp63 += m_A315 * V[65];
+ tmp63 += m_A316 * V[66];
+ tmp63 += m_A317 * V[67];
+ V[63] = (RHS63 - tmp63) / m_A314;
+ double tmp62 = 0.0;
+ tmp62 += m_A302 * V[67];
+ V[62] = (RHS62 - tmp62) / m_A301;
+ double tmp61 = 0.0;
+ tmp61 += m_A300 * V[67];
+ V[61] = (RHS61 - tmp61) / m_A299;
+ double tmp60 = 0.0;
+ tmp60 += m_A298 * V[67];
+ V[60] = (RHS60 - tmp60) / m_A297;
+ double tmp59 = 0.0;
+ tmp59 += m_A294 * V[63];
+ tmp59 += m_A295 * V[65];
+ tmp59 += m_A296 * V[66];
+ V[59] = (RHS59 - tmp59) / m_A293;
+ double tmp58 = 0.0;
+ tmp58 += m_A288 * V[67];
+ V[58] = (RHS58 - tmp58) / m_A287;
+ double tmp57 = 0.0;
+ tmp57 += m_A283 * V[59];
+ tmp57 += m_A284 * V[63];
+ tmp57 += m_A285 * V[65];
+ tmp57 += m_A286 * V[66];
+ V[57] = (RHS57 - tmp57) / m_A282;
+ double tmp56 = 0.0;
+ tmp56 += m_A271 * V[57];
+ tmp56 += m_A272 * V[59];
+ tmp56 += m_A273 * V[63];
+ tmp56 += m_A274 * V[65];
+ tmp56 += m_A275 * V[66];
+ V[56] = (RHS56 - tmp56) / m_A270;
+ double tmp55 = 0.0;
+ tmp55 += m_A258 * V[56];
+ tmp55 += m_A259 * V[57];
+ tmp55 += m_A260 * V[63];
+ tmp55 += m_A261 * V[65];
+ V[55] = (RHS55 - tmp55) / m_A257;
+ double tmp54 = 0.0;
+ tmp54 += m_A241 * V[55];
+ tmp54 += m_A242 * V[56];
+ tmp54 += m_A243 * V[57];
+ tmp54 += m_A244 * V[63];
+ tmp54 += m_A245 * V[65];
+ V[54] = (RHS54 - tmp54) / m_A240;
+ double tmp53 = 0.0;
+ tmp53 += m_A226 * V[54];
+ tmp53 += m_A227 * V[55];
+ tmp53 += m_A228 * V[56];
+ tmp53 += m_A229 * V[57];
+ tmp53 += m_A230 * V[63];
+ tmp53 += m_A231 * V[65];
+ V[53] = (RHS53 - tmp53) / m_A225;
+ double tmp52 = 0.0;
+ tmp52 += m_A215 * V[53];
+ tmp52 += m_A216 * V[54];
+ tmp52 += m_A217 * V[55];
+ tmp52 += m_A218 * V[56];
+ tmp52 += m_A219 * V[63];
+ V[52] = (RHS52 - tmp52) / m_A214;
+ double tmp51 = 0.0;
+ tmp51 += m_A202 * V[52];
+ tmp51 += m_A203 * V[53];
+ tmp51 += m_A204 * V[54];
+ tmp51 += m_A205 * V[56];
+ V[51] = (RHS51 - tmp51) / m_A201;
+ double tmp50 = 0.0;
+ tmp50 += m_A193 * V[51];
+ V[50] = (RHS50 - tmp50) / m_A192;
+ double tmp49 = 0.0;
+ tmp49 += m_A184 * V[67];
+ V[49] = (RHS49 - tmp49) / m_A183;
+ double tmp48 = 0.0;
+ tmp48 += m_A182 * V[64];
+ V[48] = (RHS48 - tmp48) / m_A181;
+ double tmp47 = 0.0;
+ tmp47 += m_A173 * V[51];
+ tmp47 += m_A174 * V[52];
+ tmp47 += m_A175 * V[53];
+ tmp47 += m_A176 * V[54];
+ tmp47 += m_A177 * V[56];
+ V[47] = (RHS47 - tmp47) / m_A172;
+ double tmp46 = 0.0;
+ tmp46 += m_A165 * V[48];
+ V[46] = (RHS46 - tmp46) / m_A164;
+ double tmp45 = 0.0;
+ tmp45 += m_A159 * V[52];
+ tmp45 += m_A160 * V[55];
+ tmp45 += m_A161 * V[63];
+ V[45] = (RHS45 - tmp45) / m_A158;
+ double tmp44 = 0.0;
+ tmp44 += m_A154 * V[57];
+ V[44] = (RHS44 - tmp44) / m_A153;
+ double tmp43 = 0.0;
+ tmp43 += m_A151 * V[59];
+ V[43] = (RHS43 - tmp43) / m_A150;
+ double tmp42 = 0.0;
+ tmp42 += m_A146 * V[47];
+ tmp42 += m_A147 * V[54];
+ tmp42 += m_A148 * V[55];
+ V[42] = (RHS42 - tmp42) / m_A145;
+ double tmp41 = 0.0;
+ tmp41 += m_A139 * V[42];
+ tmp41 += m_A140 * V[47];
+ tmp41 += m_A141 * V[54];
+ tmp41 += m_A142 * V[55];
+ V[41] = (RHS41 - tmp41) / m_A138;
+ double tmp40 = 0.0;
+ tmp40 += m_A131 * V[47];
+ tmp40 += m_A132 * V[51];
+ tmp40 += m_A133 * V[52];
+ V[40] = (RHS40 - tmp40) / m_A130;
+ double tmp39 = 0.0;
+ tmp39 += m_A124 * V[40];
+ tmp39 += m_A125 * V[52];
+ V[39] = (RHS39 - tmp39) / m_A123;
+ double tmp38 = 0.0;
+ tmp38 += m_A120 * V[47];
+ tmp38 += m_A121 * V[54];
+ V[38] = (RHS38 - tmp38) / m_A119;
+ double tmp37 = 0.0;
+ tmp37 += m_A113 * V[40];
+ tmp37 += m_A114 * V[47];
+ tmp37 += m_A115 * V[51];
+ V[37] = (RHS37 - tmp37) / m_A112;
+ double tmp36 = 0.0;
+ tmp36 += m_A106 * V[37];
+ tmp36 += m_A107 * V[47];
+ tmp36 += m_A108 * V[51];
+ V[36] = (RHS36 - tmp36) / m_A105;
+ double tmp35 = 0.0;
+ tmp35 += m_A102 * V[50];
+ tmp35 += m_A103 * V[51];
+ V[35] = (RHS35 - tmp35) / m_A101;
+ double tmp34 = 0.0;
+ tmp34 += m_A99 * V[50];
+ V[34] = (RHS34 - tmp34) / m_A98;
+ double tmp33 = 0.0;
+ tmp33 += m_A94 * V[45];
+ tmp33 += m_A95 * V[52];
+ tmp33 += m_A96 * V[63];
+ V[33] = (RHS33 - tmp33) / m_A93;
+ double tmp32 = 0.0;
+ tmp32 += m_A90 * V[50];
+ V[32] = (RHS32 - tmp32) / m_A89;
+ double tmp31 = 0.0;
+ tmp31 += m_A87 * V[50];
+ V[31] = (RHS31 - tmp31) / m_A86;
+ double tmp30 = 0.0;
+ tmp30 += m_A84 * V[50];
+ V[30] = (RHS30 - tmp30) / m_A83;
+ double tmp29 = 0.0;
+ tmp29 += m_A80 * V[67];
+ V[29] = (RHS29 - tmp29) / m_A79;
+ double tmp28 = 0.0;
+ tmp28 += m_A78 * V[64];
+ V[28] = (RHS28 - tmp28) / m_A77;
+ double tmp27 = 0.0;
+ tmp27 += m_A74 * V[47];
+ tmp27 += m_A75 * V[53];
+ tmp27 += m_A76 * V[56];
+ V[27] = (RHS27 - tmp27) / m_A73;
+ double tmp26 = 0.0;
+ tmp26 += m_A71 * V[46];
+ tmp26 += m_A72 * V[48];
+ V[26] = (RHS26 - tmp26) / m_A70;
+ double tmp25 = 0.0;
+ tmp25 += m_A69 * V[48];
+ V[25] = (RHS25 - tmp25) / m_A68;
+ double tmp24 = 0.0;
+ tmp24 += m_A67 * V[53];
+ V[24] = (RHS24 - tmp24) / m_A66;
+ double tmp23 = 0.0;
+ tmp23 += m_A65 * V[56];
+ V[23] = (RHS23 - tmp23) / m_A64;
+ double tmp22 = 0.0;
+ tmp22 += m_A61 * V[33];
+ tmp22 += m_A62 * V[45];
+ tmp22 += m_A63 * V[63];
+ V[22] = (RHS22 - tmp22) / m_A60;
+ double tmp21 = 0.0;
+ tmp21 += m_A58 * V[44];
+ tmp21 += m_A59 * V[57];
+ V[21] = (RHS21 - tmp21) / m_A57;
+ double tmp20 = 0.0;
+ tmp20 += m_A55 * V[43];
+ tmp20 += m_A56 * V[59];
+ V[20] = (RHS20 - tmp20) / m_A54;
+ double tmp19 = 0.0;
+ tmp19 += m_A53 * V[46];
+ V[19] = (RHS19 - tmp19) / m_A52;
+ double tmp18 = 0.0;
+ tmp18 += m_A51 * V[22];
+ V[18] = (RHS18 - tmp18) / m_A50;
+ double tmp17 = 0.0;
+ tmp17 += m_A48 * V[45];
+ tmp17 += m_A49 * V[55];
+ V[17] = (RHS17 - tmp17) / m_A47;
+ double tmp16 = 0.0;
+ tmp16 += m_A45 * V[33];
+ tmp16 += m_A46 * V[52];
+ V[16] = (RHS16 - tmp16) / m_A44;
+ double tmp15 = 0.0;
+ tmp15 += m_A41 * V[41];
+ tmp15 += m_A42 * V[42];
+ tmp15 += m_A43 * V[55];
+ V[15] = (RHS15 - tmp15) / m_A40;
+ double tmp14 = 0.0;
+ tmp14 += m_A39 * V[42];
+ V[14] = (RHS14 - tmp14) / m_A38;
+ double tmp13 = 0.0;
+ tmp13 += m_A36 * V[40];
+ tmp13 += m_A37 * V[52];
+ V[13] = (RHS13 - tmp13) / m_A35;
+ double tmp12 = 0.0;
+ tmp12 += m_A32 * V[38];
+ tmp12 += m_A33 * V[47];
+ tmp12 += m_A34 * V[54];
+ V[12] = (RHS12 - tmp12) / m_A31;
+ double tmp11 = 0.0;
+ tmp11 += m_A29 * V[12];
+ tmp11 += m_A30 * V[54];
+ V[11] = (RHS11 - tmp11) / m_A28;
+ double tmp10 = 0.0;
+ tmp10 += m_A25 * V[36];
+ tmp10 += m_A26 * V[37];
+ tmp10 += m_A27 * V[40];
+ V[10] = (RHS10 - tmp10) / m_A24;
+ double tmp9 = 0.0;
+ tmp9 += m_A21 * V[37];
+ tmp9 += m_A22 * V[47];
+ tmp9 += m_A23 * V[51];
+ V[9] = (RHS9 - tmp9) / m_A20;
+ double tmp8 = 0.0;
+ tmp8 += m_A19 * V[38];
+ V[8] = (RHS8 - tmp8) / m_A18;
+ double tmp7 = 0.0;
+ tmp7 += m_A17 * V[51];
+ V[7] = (RHS7 - tmp7) / m_A16;
+ double tmp6 = 0.0;
+ tmp6 += m_A15 * V[38];
+ V[6] = (RHS6 - tmp6) / m_A14;
+ double tmp5 = 0.0;
+ tmp5 += m_A13 * V[35];
+ V[5] = (RHS5 - tmp5) / m_A12;
+ double tmp4 = 0.0;
+ tmp4 += m_A10 * V[31];
+ tmp4 += m_A11 * V[50];
+ V[4] = (RHS4 - tmp4) / m_A9;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[34];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[30];
+ tmp2 += m_A6 * V[50];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[32];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[30];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// stuntcyc
static void nl_gcr_c924fe5960b1479e_20_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -57960,6 +67024,215 @@ static void nl_gcr_d4c34516ff6aa139_46_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_d5e1c37cfa2d2853_30_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A0 += gt[3];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 += Idr[3];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ RHS0 -= go[3] * *cnV[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A3 += go[4];
+ m_A4 += go[5];
+ double RHS1 = Idr[4];
+ RHS1 += Idr[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A5 += gt[8];
+ m_A6 += go[6];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 -= go[7] * *cnV[7];
+ RHS2 -= go[8] * *cnV[8];
+ m_A7 += gt[9];
+ m_A7 += gt[10];
+ m_A7 += gt[11];
+ m_A8 += go[9];
+ m_A9 += go[10];
+ double RHS3 = Idr[9];
+ RHS3 += Idr[10];
+ RHS3 += Idr[11];
+ RHS3 -= go[11] * *cnV[11];
+ m_A11 += gt[12];
+ m_A11 += gt[13];
+ m_A10 += go[12];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ RHS4 -= go[13] * *cnV[13];
+ m_A14 += gt[14];
+ m_A14 += gt[15];
+ m_A14 += gt[16];
+ m_A15 += go[14];
+ m_A13 += go[15];
+ double RHS5 = Idr[14];
+ RHS5 += Idr[15];
+ RHS5 += Idr[16];
+ RHS5 -= go[16] * *cnV[16];
+ m_A17 += gt[17];
+ m_A17 += gt[18];
+ m_A17 += gt[19];
+ m_A17 += gt[20];
+ m_A17 += gt[21];
+ m_A17 += gt[22];
+ m_A17 += gt[23];
+ m_A16 += go[17];
+ m_A18 += go[18];
+ double RHS6 = Idr[17];
+ RHS6 += Idr[18];
+ RHS6 += Idr[19];
+ RHS6 += Idr[20];
+ RHS6 += Idr[21];
+ RHS6 += Idr[22];
+ RHS6 += Idr[23];
+ RHS6 -= go[19] * *cnV[19];
+ RHS6 -= go[20] * *cnV[20];
+ RHS6 -= go[21] * *cnV[21];
+ RHS6 -= go[22] * *cnV[22];
+ RHS6 -= go[23] * *cnV[23];
+ m_A22 += gt[24];
+ m_A22 += gt[25];
+ m_A22 += gt[26];
+ m_A22 += gt[27];
+ m_A20 += go[24];
+ m_A19 += go[25];
+ m_A21 += go[26];
+ double RHS7 = Idr[24];
+ RHS7 += Idr[25];
+ RHS7 += Idr[26];
+ RHS7 += Idr[27];
+ RHS7 -= go[27] * *cnV[27];
+ m_A29 += gt[28];
+ m_A29 += gt[29];
+ m_A29 += gt[30];
+ m_A29 += gt[31];
+ m_A29 += gt[32];
+ m_A27 += go[28];
+ m_A25 += go[29];
+ m_A24 += go[30];
+ double RHS8 = Idr[28];
+ RHS8 += Idr[29];
+ RHS8 += Idr[30];
+ RHS8 += Idr[31];
+ RHS8 += Idr[32];
+ RHS8 -= go[31] * *cnV[31];
+ RHS8 -= go[32] * *cnV[32];
+ const double f0 = 1.0 / m_A0;
+ const double f0_5 = -f0 * m_A13;
+ m_A14 += m_A1 * f0_5;
+ RHS5 += f0_5 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_7 = -f1 * m_A19;
+ m_A22 += m_A3 * f1_7;
+ m_A23 += m_A4 * f1_7;
+ RHS7 += f1_7 * RHS1;
+ const double f1_8 = -f1 * m_A24;
+ m_A28 += m_A3 * f1_8;
+ m_A29 += m_A4 * f1_8;
+ RHS8 += f1_8 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_6 = -f2 * m_A16;
+ m_A18 += m_A6 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f2_7 = -f2 * m_A20;
+ m_A22 += m_A6 * f2_7;
+ RHS7 += f2_7 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_4 = -f3 * m_A10;
+ m_A11 += m_A8 * f3_4;
+ m_A12 += m_A9 * f3_4;
+ RHS4 += f3_4 * RHS3;
+ const double f3_8 = -f3 * m_A25;
+ m_A26 += m_A8 * f3_8;
+ m_A29 += m_A9 * f3_8;
+ RHS8 += f3_8 * RHS3;
+ const double f4 = 1.0 / m_A11;
+ const double f4_8 = -f4 * m_A26;
+ m_A29 += m_A12 * f4_8;
+ RHS8 += f4_8 * RHS4;
+ const double f5 = 1.0 / m_A14;
+ const double f5_7 = -f5 * m_A21;
+ m_A22 += m_A15 * f5_7;
+ RHS7 += f5_7 * RHS5;
+ const double f6 = 1.0 / m_A17;
+ const double f6_8 = -f6 * m_A27;
+ m_A28 += m_A18 * f6_8;
+ RHS8 += f6_8 * RHS6;
+ const double f7 = 1.0 / m_A22;
+ const double f7_8 = -f7 * m_A28;
+ m_A29 += m_A23 * f7_8;
+ RHS8 += f7_8 * RHS7;
+ V[8] = RHS8 / m_A29;
+ double tmp7 = 0.0;
+ tmp7 += m_A23 * V[8];
+ V[7] = (RHS7 - tmp7) / m_A22;
+ double tmp6 = 0.0;
+ tmp6 += m_A18 * V[7];
+ V[6] = (RHS6 - tmp6) / m_A17;
+ double tmp5 = 0.0;
+ tmp5 += m_A15 * V[7];
+ V[5] = (RHS5 - tmp5) / m_A14;
+ double tmp4 = 0.0;
+ tmp4 += m_A12 * V[8];
+ V[4] = (RHS4 - tmp4) / m_A11;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[4];
+ tmp3 += m_A9 * V[8];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[7];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[7];
+ tmp1 += m_A4 * V[8];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[5];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// boxingb
static void nl_gcr_d7d45dc58b08cab9_10_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -58279,6 +67552,133 @@ static void nl_gcr_d8c511d38cef5f6f_34_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
+// frogs
+static void nl_gcr_d97fd7ecc1ebba3d_19_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A3 += go[2];
+ double RHS1 = Idr[2];
+ RHS1 += Idr[3];
+ RHS1 -= go[3] * *cnV[3];
+ m_A4 += gt[4];
+ m_A4 += gt[5];
+ m_A5 += go[4];
+ double RHS2 = Idr[4];
+ RHS2 += Idr[5];
+ RHS2 -= go[5] * *cnV[5];
+ m_A6 += gt[6];
+ m_A6 += gt[7];
+ m_A7 += go[6];
+ double RHS3 = Idr[6];
+ RHS3 += Idr[7];
+ RHS3 -= go[7] * *cnV[7];
+ m_A8 += gt[8];
+ m_A8 += gt[9];
+ m_A9 += go[8];
+ double RHS4 = Idr[8];
+ RHS4 += Idr[9];
+ RHS4 -= go[9] * *cnV[9];
+ m_A10 += gt[10];
+ m_A10 += gt[11];
+ m_A11 += go[10];
+ double RHS5 = Idr[10];
+ RHS5 += Idr[11];
+ RHS5 -= go[11] * *cnV[11];
+ m_A18 += gt[12];
+ m_A18 += gt[13];
+ m_A18 += gt[14];
+ m_A18 += gt[15];
+ m_A18 += gt[16];
+ m_A18 += gt[17];
+ m_A18 += gt[18];
+ m_A17 += go[12];
+ m_A16 += go[13];
+ m_A15 += go[14];
+ m_A14 += go[15];
+ m_A13 += go[16];
+ m_A12 += go[17];
+ double RHS6 = Idr[12];
+ RHS6 += Idr[13];
+ RHS6 += Idr[14];
+ RHS6 += Idr[15];
+ RHS6 += Idr[16];
+ RHS6 += Idr[17];
+ RHS6 += Idr[18];
+ RHS6 -= go[18] * *cnV[18];
+ const double f0 = 1.0 / m_A0;
+ const double f0_6 = -f0 * m_A12;
+ m_A18 += m_A1 * f0_6;
+ RHS6 += f0_6 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_6 = -f1 * m_A13;
+ m_A18 += m_A3 * f1_6;
+ RHS6 += f1_6 * RHS1;
+ const double f2 = 1.0 / m_A4;
+ const double f2_6 = -f2 * m_A14;
+ m_A18 += m_A5 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f3 = 1.0 / m_A6;
+ const double f3_6 = -f3 * m_A15;
+ m_A18 += m_A7 * f3_6;
+ RHS6 += f3_6 * RHS3;
+ const double f4 = 1.0 / m_A8;
+ const double f4_6 = -f4 * m_A16;
+ m_A18 += m_A9 * f4_6;
+ RHS6 += f4_6 * RHS4;
+ const double f5 = 1.0 / m_A10;
+ const double f5_6 = -f5 * m_A17;
+ m_A18 += m_A11 * f5_6;
+ RHS6 += f5_6 * RHS5;
+ V[6] = RHS6 / m_A18;
+ double tmp5 = 0.0;
+ tmp5 += m_A11 * V[6];
+ V[5] = (RHS5 - tmp5) / m_A10;
+ double tmp4 = 0.0;
+ tmp4 += m_A9 * V[6];
+ V[4] = (RHS4 - tmp4) / m_A8;
+ double tmp3 = 0.0;
+ tmp3 += m_A7 * V[6];
+ V[3] = (RHS3 - tmp3) / m_A6;
+ double tmp2 = 0.0;
+ tmp2 += m_A5 * V[6];
+ V[2] = (RHS2 - tmp2) / m_A4;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[6];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[6];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// warrior
static void nl_gcr_da598f43329e823_27_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -59694,6 +69094,148 @@ static void nl_gcr_e02a162cb515a958_100_double_double(double * __restrict V, con
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_e03f0bc5ac056326_20_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A4 += go[3];
+ m_A3 += go[4];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[5] * *cnV[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A5 += gt[8];
+ m_A5 += gt[9];
+ m_A7 += go[6];
+ m_A6 += go[7];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 += Idr[8];
+ RHS2 += Idr[9];
+ RHS2 -= go[8] * *cnV[8];
+ RHS2 -= go[9] * *cnV[9];
+ m_A10 += gt[10];
+ m_A10 += gt[11];
+ m_A9 += go[10];
+ m_A8 += go[11];
+ double RHS3 = Idr[10];
+ RHS3 += Idr[11];
+ m_A15 += gt[12];
+ m_A15 += gt[13];
+ m_A15 += gt[14];
+ m_A13 += go[12];
+ m_A12 += go[13];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ RHS4 += Idr[14];
+ RHS4 -= go[14] * *cnV[14];
+ m_A19 += gt[15];
+ m_A19 += gt[16];
+ m_A19 += gt[17];
+ m_A19 += gt[18];
+ m_A19 += gt[19];
+ m_A19 += gt[20];
+ m_A19 += gt[21];
+ m_A17 += go[15];
+ m_A18 += go[16];
+ double RHS5 = Idr[15];
+ RHS5 += Idr[16];
+ RHS5 += Idr[17];
+ RHS5 += Idr[18];
+ RHS5 += Idr[19];
+ RHS5 += Idr[20];
+ RHS5 += Idr[21];
+ RHS5 -= go[17] * *cnV[17];
+ RHS5 -= go[18] * *cnV[18];
+ RHS5 -= go[19] * *cnV[19];
+ RHS5 -= go[20] * *cnV[20];
+ RHS5 -= go[21] * *cnV[21];
+ const double f0 = 1.0 / m_A0;
+ const double f0_3 = -f0 * m_A8;
+ m_A10 += m_A1 * f0_3;
+ RHS3 += f0_3 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_3 = -f1 * m_A9;
+ m_A10 += m_A3 * f1_3;
+ m_A11 += m_A4 * f1_3;
+ RHS3 += f1_3 * RHS1;
+ const double f1_4 = -f1 * m_A12;
+ m_A14 += m_A3 * f1_4;
+ m_A15 += m_A4 * f1_4;
+ RHS4 += f1_4 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_4 = -f2 * m_A13;
+ m_A15 += m_A6 * f2_4;
+ m_A16 += m_A7 * f2_4;
+ RHS4 += f2_4 * RHS2;
+ const double f2_5 = -f2 * m_A17;
+ m_A18 += m_A6 * f2_5;
+ m_A19 += m_A7 * f2_5;
+ RHS5 += f2_5 * RHS2;
+ const double f3 = 1.0 / m_A10;
+ const double f3_4 = -f3 * m_A14;
+ m_A15 += m_A11 * f3_4;
+ RHS4 += f3_4 * RHS3;
+ const double f4 = 1.0 / m_A15;
+ const double f4_5 = -f4 * m_A18;
+ m_A19 += m_A16 * f4_5;
+ RHS5 += f4_5 * RHS4;
+ V[5] = RHS5 / m_A19;
+ double tmp4 = 0.0;
+ tmp4 += m_A16 * V[5];
+ V[4] = (RHS4 - tmp4) / m_A15;
+ double tmp3 = 0.0;
+ tmp3 += m_A11 * V[4];
+ V[3] = (RHS3 - tmp3) / m_A10;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[4];
+ tmp2 += m_A7 * V[5];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[3];
+ tmp1 += m_A4 * V[4];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[3];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// speedfrk
static void nl_gcr_e07b5b086812756c_7_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -66198,8 +75740,8 @@ static void nl_gcr_ef2f49641f433a74_94_double_double(double * __restrict V, cons
V[0] = (RHS0 - tmp0) / m_A0;
}
-// astrob
-static void nl_gcr_efd052e6829c33e_9_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+// frogs
+static void nl_gcr_f153eda877c6e8ed_30_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
{
@@ -66213,44 +75755,568 @@ static void nl_gcr_efd052e6829c33e_9_double_double(double * __restrict V, const
double m_A6(0.0);
double m_A7(0.0);
double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
m_A0 += gt[0];
m_A0 += gt[1];
- m_A2 += go[0];
- m_A1 += go[1];
+ m_A0 += gt[2];
+ m_A0 += gt[3];
+ m_A1 += go[0];
double RHS0 = Idr[0];
RHS0 += Idr[1];
- m_A4 += gt[2];
- m_A4 += gt[3];
- m_A5 += go[2];
+ RHS0 += Idr[2];
+ RHS0 += Idr[3];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ RHS0 -= go[3] * *cnV[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A2 += gt[6];
+ m_A2 += gt[7];
+ m_A2 += gt[8];
+ m_A2 += gt[9];
+ m_A2 += gt[10];
+ m_A5 += go[4];
+ m_A5 += go[5];
+ m_A4 += go[6];
+ m_A4 += go[7];
+ m_A3 += go[8];
+ m_A3 += go[9];
+ double RHS1 = Idr[4];
+ RHS1 += Idr[5];
+ RHS1 += Idr[6];
+ RHS1 += Idr[7];
+ RHS1 += Idr[8];
+ RHS1 += Idr[9];
+ RHS1 += Idr[10];
+ RHS1 -= go[10] * *cnV[10];
+ m_A6 += gt[11];
+ m_A6 += gt[12];
+ m_A6 += gt[13];
+ m_A6 += gt[14];
+ m_A7 += go[11];
+ m_A8 += go[12];
+ m_A8 += go[13];
+ double RHS2 = Idr[11];
+ RHS2 += Idr[12];
+ RHS2 += Idr[13];
+ RHS2 += Idr[14];
+ RHS2 -= go[14] * *cnV[14];
+ m_A9 += gt[15];
+ m_A10 += go[15];
+ double RHS3 = Idr[15];
+ m_A13 += gt[16];
+ m_A13 += gt[17];
+ m_A13 += gt[18];
+ m_A13 += gt[19];
+ m_A13 += gt[20];
+ m_A12 += go[16];
+ m_A12 += go[17];
+ m_A11 += go[18];
+ double RHS4 = Idr[16];
+ RHS4 += Idr[17];
+ RHS4 += Idr[18];
+ RHS4 += Idr[19];
+ RHS4 += Idr[20];
+ RHS4 -= go[19] * *cnV[19];
+ RHS4 -= go[20] * *cnV[20];
+ m_A18 += gt[21];
+ m_A18 += gt[22];
+ m_A18 += gt[23];
+ m_A18 += gt[24];
+ m_A19 += go[21];
+ m_A16 += go[22];
+ m_A16 += go[23];
+ double RHS5 = Idr[21];
+ RHS5 += Idr[22];
+ RHS5 += Idr[23];
+ RHS5 += Idr[24];
+ RHS5 -= go[24] * *cnV[24];
+ m_A22 += gt[25];
+ m_A22 += gt[26];
+ m_A22 += gt[27];
+ m_A22 += gt[28];
+ m_A22 += gt[29];
+ m_A22 += gt[30];
+ m_A21 += go[25];
+ m_A20 += go[26];
+ m_A23 += go[27];
+ m_A23 += go[28];
+ double RHS6 = Idr[25];
+ RHS6 += Idr[26];
+ RHS6 += Idr[27];
+ RHS6 += Idr[28];
+ RHS6 += Idr[29];
+ RHS6 += Idr[30];
+ RHS6 -= go[29] * *cnV[29];
+ RHS6 -= go[30] * *cnV[30];
+ m_A29 += gt[31];
+ m_A29 += gt[32];
+ m_A29 += gt[33];
+ m_A29 += gt[34];
+ m_A29 += gt[35];
+ m_A29 += gt[36];
+ m_A29 += gt[37];
+ m_A29 += gt[38];
+ m_A28 += go[31];
+ m_A28 += go[32];
+ m_A25 += go[33];
+ m_A25 += go[34];
+ m_A27 += go[35];
+ m_A24 += go[36];
+ m_A24 += go[37];
+ double RHS7 = Idr[31];
+ RHS7 += Idr[32];
+ RHS7 += Idr[33];
+ RHS7 += Idr[34];
+ RHS7 += Idr[35];
+ RHS7 += Idr[36];
+ RHS7 += Idr[37];
+ RHS7 += Idr[38];
+ RHS7 -= go[38] * *cnV[38];
+ const double f0 = 1.0 / m_A0;
+ const double f0_4 = -f0 * m_A11;
+ m_A13 += m_A1 * f0_4;
+ RHS4 += f0_4 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_4 = -f1 * m_A12;
+ m_A13 += m_A3 * f1_4;
+ m_A14 += m_A4 * f1_4;
+ m_A15 += m_A5 * f1_4;
+ RHS4 += f1_4 * RHS1;
+ const double f1_5 = -f1 * m_A16;
+ m_A17 += m_A3 * f1_5;
+ m_A18 += m_A4 * f1_5;
+ m_A19 += m_A5 * f1_5;
+ RHS5 += f1_5 * RHS1;
+ const double f1_7 = -f1 * m_A24;
+ m_A26 += m_A3 * f1_7;
+ m_A27 += m_A4 * f1_7;
+ m_A29 += m_A5 * f1_7;
+ RHS7 += f1_7 * RHS1;
+ const double f2 = 1.0 / m_A6;
+ const double f2_6 = -f2 * m_A20;
+ m_A22 += m_A7 * f2_6;
+ m_A23 += m_A8 * f2_6;
+ RHS6 += f2_6 * RHS2;
+ const double f2_7 = -f2 * m_A25;
+ m_A28 += m_A7 * f2_7;
+ m_A29 += m_A8 * f2_7;
+ RHS7 += f2_7 * RHS2;
+ const double f3 = 1.0 / m_A9;
+ const double f3_6 = -f3 * m_A21;
+ m_A22 += m_A10 * f3_6;
+ RHS6 += f3_6 * RHS3;
+ const double f4 = 1.0 / m_A13;
+ const double f4_5 = -f4 * m_A17;
+ m_A18 += m_A14 * f4_5;
+ m_A19 += m_A15 * f4_5;
+ RHS5 += f4_5 * RHS4;
+ const double f4_7 = -f4 * m_A26;
+ m_A27 += m_A14 * f4_7;
+ m_A29 += m_A15 * f4_7;
+ RHS7 += f4_7 * RHS4;
+ const double f5 = 1.0 / m_A18;
+ const double f5_7 = -f5 * m_A27;
+ m_A29 += m_A19 * f5_7;
+ RHS7 += f5_7 * RHS5;
+ const double f6 = 1.0 / m_A22;
+ const double f6_7 = -f6 * m_A28;
+ m_A29 += m_A23 * f6_7;
+ RHS7 += f6_7 * RHS6;
+ V[7] = RHS7 / m_A29;
+ double tmp6 = 0.0;
+ tmp6 += m_A23 * V[7];
+ V[6] = (RHS6 - tmp6) / m_A22;
+ double tmp5 = 0.0;
+ tmp5 += m_A19 * V[7];
+ V[5] = (RHS5 - tmp5) / m_A18;
+ double tmp4 = 0.0;
+ tmp4 += m_A14 * V[5];
+ tmp4 += m_A15 * V[7];
+ V[4] = (RHS4 - tmp4) / m_A13;
+ double tmp3 = 0.0;
+ tmp3 += m_A10 * V[6];
+ V[3] = (RHS3 - tmp3) / m_A9;
+ double tmp2 = 0.0;
+ tmp2 += m_A7 * V[6];
+ tmp2 += m_A8 * V[7];
+ V[2] = (RHS2 - tmp2) / m_A6;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[4];
+ tmp1 += m_A4 * V[5];
+ tmp1 += m_A5 * V[7];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[4];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
+// frogs
+static void nl_gcr_f2de20e827252602_53_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 -= go[1] * *cnV[1];
+ m_A2 += gt[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A4 += go[2];
m_A3 += go[3];
+ m_A3 += go[4];
double RHS1 = Idr[2];
RHS1 += Idr[3];
- m_A8 += gt[4];
- m_A8 += gt[5];
- m_A7 += go[4];
- m_A6 += go[5];
- double RHS2 = Idr[4];
- RHS2 += Idr[5];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[5] * *cnV[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A6 += go[6];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 -= go[7] * *cnV[7];
+ m_A7 += gt[8];
+ m_A7 += gt[9];
+ m_A7 += gt[10];
+ m_A7 += gt[11];
+ m_A8 += go[8];
+ m_A8 += go[9];
+ double RHS3 = Idr[8];
+ RHS3 += Idr[9];
+ RHS3 += Idr[10];
+ RHS3 += Idr[11];
+ RHS3 -= go[10] * *cnV[10];
+ RHS3 -= go[11] * *cnV[11];
+ m_A9 += gt[12];
+ m_A9 += gt[13];
+ m_A10 += go[12];
+ m_A11 += go[13];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ m_A12 += gt[14];
+ m_A12 += gt[15];
+ m_A13 += go[14];
+ double RHS5 = Idr[14];
+ RHS5 += Idr[15];
+ RHS5 -= go[15] * *cnV[15];
+ m_A14 += gt[16];
+ m_A14 += gt[17];
+ m_A14 += gt[18];
+ m_A15 += go[16];
+ m_A16 += go[17];
+ double RHS6 = Idr[16];
+ RHS6 += Idr[17];
+ RHS6 += Idr[18];
+ RHS6 -= go[18] * *cnV[18];
+ m_A17 += gt[19];
+ m_A17 += gt[20];
+ m_A17 += gt[21];
+ m_A17 += gt[22];
+ m_A19 += go[19];
+ m_A18 += go[20];
+ double RHS7 = Idr[19];
+ RHS7 += Idr[20];
+ RHS7 += Idr[21];
+ RHS7 += Idr[22];
+ RHS7 -= go[21] * *cnV[21];
+ RHS7 -= go[22] * *cnV[22];
+ m_A22 += gt[23];
+ m_A22 += gt[24];
+ m_A22 += gt[25];
+ m_A22 += gt[26];
+ m_A22 += gt[27];
+ m_A22 += gt[28];
+ m_A21 += go[23];
+ m_A21 += go[24];
+ m_A20 += go[25];
+ double RHS8 = Idr[23];
+ RHS8 += Idr[24];
+ RHS8 += Idr[25];
+ RHS8 += Idr[26];
+ RHS8 += Idr[27];
+ RHS8 += Idr[28];
+ RHS8 -= go[26] * *cnV[26];
+ RHS8 -= go[27] * *cnV[27];
+ RHS8 -= go[28] * *cnV[28];
+ m_A27 += gt[29];
+ m_A27 += gt[30];
+ m_A27 += gt[31];
+ m_A27 += gt[32];
+ m_A25 += go[29];
+ m_A28 += go[30];
+ m_A24 += go[31];
+ double RHS9 = Idr[29];
+ RHS9 += Idr[30];
+ RHS9 += Idr[31];
+ RHS9 += Idr[32];
+ RHS9 -= go[32] * *cnV[32];
+ m_A30 += gt[33];
+ m_A30 += gt[34];
+ m_A30 += gt[35];
+ m_A30 += gt[36];
+ m_A29 += go[33];
+ m_A29 += go[34];
+ m_A31 += go[35];
+ double RHS10 = Idr[33];
+ RHS10 += Idr[34];
+ RHS10 += Idr[35];
+ RHS10 += Idr[36];
+ RHS10 -= go[36] * *cnV[36];
+ m_A34 += gt[37];
+ m_A34 += gt[38];
+ m_A33 += go[37];
+ m_A32 += go[38];
+ double RHS11 = Idr[37];
+ RHS11 += Idr[38];
+ m_A38 += gt[39];
+ m_A38 += gt[40];
+ m_A38 += gt[41];
+ m_A37 += go[39];
+ m_A36 += go[40];
+ double RHS12 = Idr[39];
+ RHS12 += Idr[40];
+ RHS12 += Idr[41];
+ RHS12 -= go[41] * *cnV[41];
+ m_A47 += gt[42];
+ m_A47 += gt[43];
+ m_A47 += gt[44];
+ m_A47 += gt[45];
+ m_A42 += go[42];
+ m_A41 += go[43];
+ m_A44 += go[44];
+ m_A43 += go[45];
+ double RHS13 = Idr[42];
+ RHS13 += Idr[43];
+ RHS13 += Idr[44];
+ RHS13 += Idr[45];
+ m_A52 += gt[46];
+ m_A52 += gt[47];
+ m_A52 += gt[48];
+ m_A52 += gt[49];
+ m_A52 += gt[50];
+ m_A52 += gt[51];
+ m_A52 += gt[52];
+ m_A50 += go[46];
+ m_A49 += go[47];
+ double RHS14 = Idr[46];
+ RHS14 += Idr[47];
+ RHS14 += Idr[48];
+ RHS14 += Idr[49];
+ RHS14 += Idr[50];
+ RHS14 += Idr[51];
+ RHS14 += Idr[52];
+ RHS14 -= go[48] * *cnV[48];
+ RHS14 -= go[49] * *cnV[49];
+ RHS14 -= go[50] * *cnV[50];
+ RHS14 -= go[51] * *cnV[51];
+ RHS14 -= go[52] * *cnV[52];
const double f0 = 1.0 / m_A0;
- const double f0_1 = -f0 * m_A3;
- m_A4 += m_A1 * f0_1;
- m_A5 += m_A2 * f0_1;
- RHS1 += f0_1 * RHS0;
- const double f0_2 = -f0 * m_A6;
- m_A7 += m_A1 * f0_2;
- m_A8 += m_A2 * f0_2;
- RHS2 += f0_2 * RHS0;
- const double f1 = 1.0 / m_A4;
- const double f1_2 = -f1 * m_A7;
- m_A8 += m_A5 * f1_2;
- RHS2 += f1_2 * RHS1;
- V[2] = RHS2 / m_A8;
+ const double f0_8 = -f0 * m_A20;
+ m_A22 += m_A1 * f0_8;
+ RHS8 += f0_8 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_8 = -f1 * m_A21;
+ m_A22 += m_A3 * f1_8;
+ m_A23 += m_A4 * f1_8;
+ RHS8 += f1_8 * RHS1;
+ const double f1_9 = -f1 * m_A24;
+ m_A26 += m_A3 * f1_9;
+ m_A27 += m_A4 * f1_9;
+ RHS9 += f1_9 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_9 = -f2 * m_A25;
+ m_A27 += m_A6 * f2_9;
+ RHS9 += f2_9 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_10 = -f3 * m_A29;
+ m_A30 += m_A8 * f3_10;
+ RHS10 += f3_10 * RHS3;
+ const double f4 = 1.0 / m_A9;
+ const double f4_11 = -f4 * m_A32;
+ m_A34 += m_A10 * f4_11;
+ m_A35 += m_A11 * f4_11;
+ RHS11 += f4_11 * RHS4;
+ const double f4_13 = -f4 * m_A41;
+ m_A45 += m_A10 * f4_13;
+ m_A47 += m_A11 * f4_13;
+ RHS13 += f4_13 * RHS4;
+ const double f5 = 1.0 / m_A12;
+ const double f5_11 = -f5 * m_A33;
+ m_A34 += m_A13 * f5_11;
+ RHS11 += f5_11 * RHS5;
+ const double f6 = 1.0 / m_A14;
+ const double f6_12 = -f6 * m_A36;
+ m_A38 += m_A15 * f6_12;
+ m_A39 += m_A16 * f6_12;
+ RHS12 += f6_12 * RHS6;
+ const double f6_13 = -f6 * m_A42;
+ m_A46 += m_A15 * f6_13;
+ m_A47 += m_A16 * f6_13;
+ RHS13 += f6_13 * RHS6;
+ const double f6_14 = -f6 * m_A49;
+ m_A50 += m_A15 * f6_14;
+ m_A51 += m_A16 * f6_14;
+ RHS14 += f6_14 * RHS6;
+ const double f7 = 1.0 / m_A17;
+ const double f7_12 = -f7 * m_A37;
+ m_A38 += m_A18 * f7_12;
+ m_A40 += m_A19 * f7_12;
+ RHS12 += f7_12 * RHS7;
+ const double f8 = 1.0 / m_A22;
+ const double f8_9 = -f8 * m_A26;
+ m_A27 += m_A23 * f8_9;
+ RHS9 += f8_9 * RHS8;
+ const double f9 = 1.0 / m_A27;
+ const double f9_13 = -f9 * m_A43;
+ m_A47 += m_A28 * f9_13;
+ RHS13 += f9_13 * RHS9;
+ const double f10 = 1.0 / m_A30;
+ const double f10_13 = -f10 * m_A44;
+ m_A47 += m_A31 * f10_13;
+ RHS13 += f10_13 * RHS10;
+ const double f11 = 1.0 / m_A34;
+ const double f11_13 = -f11 * m_A45;
+ m_A47 += m_A35 * f11_13;
+ RHS13 += f11_13 * RHS11;
+ const double f12 = 1.0 / m_A38;
+ const double f12_13 = -f12 * m_A46;
+ m_A47 += m_A39 * f12_13;
+ m_A48 += m_A40 * f12_13;
+ RHS13 += f12_13 * RHS12;
+ const double f12_14 = -f12 * m_A50;
+ m_A51 += m_A39 * f12_14;
+ m_A52 += m_A40 * f12_14;
+ RHS14 += f12_14 * RHS12;
+ const double f13 = 1.0 / m_A47;
+ const double f13_14 = -f13 * m_A51;
+ m_A52 += m_A48 * f13_14;
+ RHS14 += f13_14 * RHS13;
+ V[14] = RHS14 / m_A52;
+ double tmp13 = 0.0;
+ tmp13 += m_A48 * V[14];
+ V[13] = (RHS13 - tmp13) / m_A47;
+ double tmp12 = 0.0;
+ tmp12 += m_A39 * V[13];
+ tmp12 += m_A40 * V[14];
+ V[12] = (RHS12 - tmp12) / m_A38;
+ double tmp11 = 0.0;
+ tmp11 += m_A35 * V[13];
+ V[11] = (RHS11 - tmp11) / m_A34;
+ double tmp10 = 0.0;
+ tmp10 += m_A31 * V[13];
+ V[10] = (RHS10 - tmp10) / m_A30;
+ double tmp9 = 0.0;
+ tmp9 += m_A28 * V[13];
+ V[9] = (RHS9 - tmp9) / m_A27;
+ double tmp8 = 0.0;
+ tmp8 += m_A23 * V[9];
+ V[8] = (RHS8 - tmp8) / m_A22;
+ double tmp7 = 0.0;
+ tmp7 += m_A18 * V[12];
+ tmp7 += m_A19 * V[14];
+ V[7] = (RHS7 - tmp7) / m_A17;
+ double tmp6 = 0.0;
+ tmp6 += m_A15 * V[12];
+ tmp6 += m_A16 * V[13];
+ V[6] = (RHS6 - tmp6) / m_A14;
+ double tmp5 = 0.0;
+ tmp5 += m_A13 * V[11];
+ V[5] = (RHS5 - tmp5) / m_A12;
+ double tmp4 = 0.0;
+ tmp4 += m_A10 * V[11];
+ tmp4 += m_A11 * V[13];
+ V[4] = (RHS4 - tmp4) / m_A9;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[10];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[9];
+ V[2] = (RHS2 - tmp2) / m_A5;
double tmp1 = 0.0;
- tmp1 += m_A5 * V[2];
- V[1] = (RHS1 - tmp1) / m_A4;
+ tmp1 += m_A3 * V[8];
+ tmp1 += m_A4 * V[9];
+ V[1] = (RHS1 - tmp1) / m_A2;
double tmp0 = 0.0;
- tmp0 += m_A1 * V[1];
- tmp0 += m_A2 * V[2];
+ tmp0 += m_A1 * V[8];
V[0] = (RHS0 - tmp0) / m_A0;
}
@@ -69647,6 +79713,560 @@ static void nl_gcr_f8f6a951fd1af6bc_7_double_double(double * __restrict V, const
V[0] = (RHS0 - tmp0) / m_A0;
}
+// brdrline
+static void nl_gcr_f99b1245e708ec85_83_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
+
+{
+
+ plib::unused_var(cnV);
+ double m_A0(0.0);
+ double m_A1(0.0);
+ double m_A2(0.0);
+ double m_A3(0.0);
+ double m_A4(0.0);
+ double m_A5(0.0);
+ double m_A6(0.0);
+ double m_A7(0.0);
+ double m_A8(0.0);
+ double m_A9(0.0);
+ double m_A10(0.0);
+ double m_A11(0.0);
+ double m_A12(0.0);
+ double m_A13(0.0);
+ double m_A14(0.0);
+ double m_A15(0.0);
+ double m_A16(0.0);
+ double m_A17(0.0);
+ double m_A18(0.0);
+ double m_A19(0.0);
+ double m_A20(0.0);
+ double m_A21(0.0);
+ double m_A22(0.0);
+ double m_A23(0.0);
+ double m_A24(0.0);
+ double m_A25(0.0);
+ double m_A26(0.0);
+ double m_A27(0.0);
+ double m_A28(0.0);
+ double m_A29(0.0);
+ double m_A30(0.0);
+ double m_A31(0.0);
+ double m_A32(0.0);
+ double m_A33(0.0);
+ double m_A34(0.0);
+ double m_A35(0.0);
+ double m_A36(0.0);
+ double m_A37(0.0);
+ double m_A38(0.0);
+ double m_A39(0.0);
+ double m_A40(0.0);
+ double m_A41(0.0);
+ double m_A42(0.0);
+ double m_A43(0.0);
+ double m_A44(0.0);
+ double m_A45(0.0);
+ double m_A46(0.0);
+ double m_A47(0.0);
+ double m_A48(0.0);
+ double m_A49(0.0);
+ double m_A50(0.0);
+ double m_A51(0.0);
+ double m_A52(0.0);
+ double m_A53(0.0);
+ double m_A54(0.0);
+ double m_A55(0.0);
+ double m_A56(0.0);
+ double m_A57(0.0);
+ double m_A58(0.0);
+ double m_A59(0.0);
+ double m_A60(0.0);
+ double m_A61(0.0);
+ double m_A62(0.0);
+ double m_A63(0.0);
+ double m_A64(0.0);
+ double m_A65(0.0);
+ double m_A66(0.0);
+ double m_A67(0.0);
+ double m_A68(0.0);
+ double m_A69(0.0);
+ double m_A70(0.0);
+ double m_A71(0.0);
+ double m_A72(0.0);
+ double m_A73(0.0);
+ double m_A74(0.0);
+ double m_A75(0.0);
+ double m_A76(0.0);
+ double m_A77(0.0);
+ double m_A78(0.0);
+ double m_A79(0.0);
+ double m_A80(0.0);
+ double m_A81(0.0);
+ double m_A82(0.0);
+ m_A0 += gt[0];
+ m_A0 += gt[1];
+ m_A0 += gt[2];
+ m_A1 += go[0];
+ double RHS0 = Idr[0];
+ RHS0 += Idr[1];
+ RHS0 += Idr[2];
+ RHS0 -= go[1] * *cnV[1];
+ RHS0 -= go[2] * *cnV[2];
+ m_A2 += gt[3];
+ m_A2 += gt[4];
+ m_A2 += gt[5];
+ m_A4 += go[3];
+ m_A3 += go[4];
+ double RHS1 = Idr[3];
+ RHS1 += Idr[4];
+ RHS1 += Idr[5];
+ RHS1 -= go[5] * *cnV[5];
+ m_A5 += gt[6];
+ m_A5 += gt[7];
+ m_A6 += go[6];
+ double RHS2 = Idr[6];
+ RHS2 += Idr[7];
+ RHS2 -= go[7] * *cnV[7];
+ m_A7 += gt[8];
+ m_A7 += gt[9];
+ m_A7 += gt[10];
+ m_A7 += gt[11];
+ m_A8 += go[8];
+ double RHS3 = Idr[8];
+ RHS3 += Idr[9];
+ RHS3 += Idr[10];
+ RHS3 += Idr[11];
+ RHS3 -= go[9] * *cnV[9];
+ RHS3 -= go[10] * *cnV[10];
+ RHS3 -= go[11] * *cnV[11];
+ m_A9 += gt[12];
+ m_A9 += gt[13];
+ m_A9 += gt[14];
+ m_A10 += go[12];
+ double RHS4 = Idr[12];
+ RHS4 += Idr[13];
+ RHS4 += Idr[14];
+ RHS4 -= go[13] * *cnV[13];
+ RHS4 -= go[14] * *cnV[14];
+ m_A11 += gt[15];
+ m_A11 += gt[16];
+ m_A11 += gt[17];
+ m_A11 += gt[18];
+ m_A11 += gt[19];
+ m_A11 += gt[20];
+ m_A14 += go[15];
+ m_A13 += go[16];
+ m_A15 += go[17];
+ m_A12 += go[18];
+ double RHS5 = Idr[15];
+ RHS5 += Idr[16];
+ RHS5 += Idr[17];
+ RHS5 += Idr[18];
+ RHS5 += Idr[19];
+ RHS5 += Idr[20];
+ RHS5 -= go[19] * *cnV[19];
+ RHS5 -= go[20] * *cnV[20];
+ m_A16 += gt[21];
+ m_A16 += gt[22];
+ m_A16 += gt[23];
+ m_A17 += go[21];
+ double RHS6 = Idr[21];
+ RHS6 += Idr[22];
+ RHS6 += Idr[23];
+ RHS6 -= go[22] * *cnV[22];
+ RHS6 -= go[23] * *cnV[23];
+ m_A18 += gt[24];
+ m_A18 += gt[25];
+ m_A18 += gt[26];
+ m_A18 += gt[27];
+ m_A19 += go[24];
+ double RHS7 = Idr[24];
+ RHS7 += Idr[25];
+ RHS7 += Idr[26];
+ RHS7 += Idr[27];
+ RHS7 -= go[25] * *cnV[25];
+ RHS7 -= go[26] * *cnV[26];
+ RHS7 -= go[27] * *cnV[27];
+ m_A22 += gt[28];
+ m_A22 += gt[29];
+ m_A22 += gt[30];
+ m_A20 += go[28];
+ m_A21 += go[29];
+ double RHS8 = Idr[28];
+ RHS8 += Idr[29];
+ RHS8 += Idr[30];
+ RHS8 -= go[30] * *cnV[30];
+ m_A27 += gt[31];
+ m_A27 += gt[32];
+ m_A27 += gt[33];
+ m_A27 += gt[34];
+ m_A27 += gt[35];
+ m_A27 += gt[36];
+ m_A28 += go[31];
+ m_A29 += go[32];
+ m_A29 += go[33];
+ m_A26 += go[34];
+ double RHS9 = Idr[31];
+ RHS9 += Idr[32];
+ RHS9 += Idr[33];
+ RHS9 += Idr[34];
+ RHS9 += Idr[35];
+ RHS9 += Idr[36];
+ RHS9 -= go[35] * *cnV[35];
+ RHS9 -= go[36] * *cnV[36];
+ m_A31 += gt[37];
+ m_A31 += gt[38];
+ m_A31 += gt[39];
+ m_A31 += gt[40];
+ m_A31 += gt[41];
+ m_A31 += gt[42];
+ m_A31 += gt[43];
+ m_A33 += go[37];
+ m_A30 += go[38];
+ double RHS10 = Idr[37];
+ RHS10 += Idr[38];
+ RHS10 += Idr[39];
+ RHS10 += Idr[40];
+ RHS10 += Idr[41];
+ RHS10 += Idr[42];
+ RHS10 += Idr[43];
+ RHS10 -= go[39] * *cnV[39];
+ RHS10 -= go[40] * *cnV[40];
+ RHS10 -= go[41] * *cnV[41];
+ RHS10 -= go[42] * *cnV[42];
+ RHS10 -= go[43] * *cnV[43];
+ m_A35 += gt[44];
+ m_A35 += gt[45];
+ m_A35 += gt[46];
+ m_A35 += gt[47];
+ m_A35 += gt[48];
+ m_A35 += gt[49];
+ m_A36 += go[44];
+ m_A37 += go[45];
+ m_A38 += go[46];
+ m_A34 += go[47];
+ double RHS11 = Idr[44];
+ RHS11 += Idr[45];
+ RHS11 += Idr[46];
+ RHS11 += Idr[47];
+ RHS11 += Idr[48];
+ RHS11 += Idr[49];
+ RHS11 -= go[48] * *cnV[48];
+ RHS11 -= go[49] * *cnV[49];
+ m_A40 += gt[50];
+ m_A40 += gt[51];
+ m_A40 += gt[52];
+ m_A39 += go[50];
+ m_A41 += go[51];
+ double RHS12 = Idr[50];
+ RHS12 += Idr[51];
+ RHS12 += Idr[52];
+ RHS12 -= go[52] * *cnV[52];
+ m_A43 += gt[53];
+ m_A43 += gt[54];
+ m_A43 += gt[55];
+ m_A43 += gt[56];
+ m_A43 += gt[57];
+ m_A43 += gt[58];
+ m_A43 += gt[59];
+ m_A44 += go[53];
+ m_A42 += go[54];
+ double RHS13 = Idr[53];
+ RHS13 += Idr[54];
+ RHS13 += Idr[55];
+ RHS13 += Idr[56];
+ RHS13 += Idr[57];
+ RHS13 += Idr[58];
+ RHS13 += Idr[59];
+ RHS13 -= go[55] * *cnV[55];
+ RHS13 -= go[56] * *cnV[56];
+ RHS13 -= go[57] * *cnV[57];
+ RHS13 -= go[58] * *cnV[58];
+ RHS13 -= go[59] * *cnV[59];
+ m_A47 += gt[60];
+ m_A47 += gt[61];
+ m_A50 += go[60];
+ m_A45 += go[61];
+ double RHS14 = Idr[60];
+ RHS14 += Idr[61];
+ m_A52 += gt[62];
+ m_A52 += gt[63];
+ m_A52 += gt[64];
+ m_A52 += gt[65];
+ m_A52 += gt[66];
+ m_A52 += gt[67];
+ m_A52 += gt[68];
+ m_A51 += go[62];
+ m_A53 += go[63];
+ double RHS15 = Idr[62];
+ RHS15 += Idr[63];
+ RHS15 += Idr[64];
+ RHS15 += Idr[65];
+ RHS15 += Idr[66];
+ RHS15 += Idr[67];
+ RHS15 += Idr[68];
+ RHS15 -= go[64] * *cnV[64];
+ RHS15 -= go[65] * *cnV[65];
+ RHS15 -= go[66] * *cnV[66];
+ RHS15 -= go[67] * *cnV[67];
+ RHS15 -= go[68] * *cnV[68];
+ m_A61 += gt[69];
+ m_A61 += gt[70];
+ m_A61 += gt[71];
+ m_A54 += go[69];
+ m_A55 += go[70];
+ m_A57 += go[71];
+ double RHS16 = Idr[69];
+ RHS16 += Idr[70];
+ RHS16 += Idr[71];
+ m_A71 += gt[72];
+ m_A71 += gt[73];
+ m_A71 += gt[74];
+ m_A71 += gt[75];
+ m_A71 += gt[76];
+ m_A68 += go[72];
+ m_A64 += go[73];
+ m_A67 += go[74];
+ m_A65 += go[75];
+ m_A65 += go[76];
+ double RHS17 = Idr[72];
+ RHS17 += Idr[73];
+ RHS17 += Idr[74];
+ RHS17 += Idr[75];
+ RHS17 += Idr[76];
+ m_A74 += gt[77];
+ m_A74 += gt[78];
+ m_A74 += gt[79];
+ m_A73 += go[77];
+ m_A75 += go[78];
+ double RHS18 = Idr[77];
+ RHS18 += Idr[78];
+ RHS18 += Idr[79];
+ RHS18 -= go[79] * *cnV[79];
+ m_A82 += gt[80];
+ m_A82 += gt[81];
+ m_A82 += gt[82];
+ m_A82 += gt[83];
+ m_A81 += go[80];
+ m_A76 += go[81];
+ m_A77 += go[82];
+ double RHS19 = Idr[80];
+ RHS19 += Idr[81];
+ RHS19 += Idr[82];
+ RHS19 += Idr[83];
+ RHS19 -= go[83] * *cnV[83];
+ const double f0 = 1.0 / m_A0;
+ const double f0_9 = -f0 * m_A26;
+ m_A27 += m_A1 * f0_9;
+ RHS9 += f0_9 * RHS0;
+ const double f1 = 1.0 / m_A2;
+ const double f1_10 = -f1 * m_A30;
+ m_A32 += m_A3 * f1_10;
+ m_A33 += m_A4 * f1_10;
+ RHS10 += f1_10 * RHS1;
+ const double f1_11 = -f1 * m_A34;
+ m_A35 += m_A3 * f1_11;
+ m_A38 += m_A4 * f1_11;
+ RHS11 += f1_11 * RHS1;
+ const double f1_17 = -f1 * m_A64;
+ m_A67 += m_A3 * f1_17;
+ m_A71 += m_A4 * f1_17;
+ RHS17 += f1_17 * RHS1;
+ const double f2 = 1.0 / m_A5;
+ const double f2_8 = -f2 * m_A20;
+ m_A22 += m_A6 * f2_8;
+ RHS8 += f2_8 * RHS2;
+ const double f3 = 1.0 / m_A7;
+ const double f3_12 = -f3 * m_A39;
+ m_A40 += m_A8 * f3_12;
+ RHS12 += f3_12 * RHS3;
+ const double f4 = 1.0 / m_A9;
+ const double f4_13 = -f4 * m_A42;
+ m_A44 += m_A10 * f4_13;
+ RHS13 += f4_13 * RHS4;
+ const double f4_16 = -f4 * m_A54;
+ m_A61 += m_A10 * f4_16;
+ RHS16 += f4_16 * RHS4;
+ const double f5 = 1.0 / m_A11;
+ const double f5_8 = -f5 * m_A21;
+ m_A22 += m_A12 * f5_8;
+ m_A23 += m_A13 * f5_8;
+ m_A24 += m_A14 * f5_8;
+ m_A25 += m_A15 * f5_8;
+ RHS8 += f5_8 * RHS5;
+ const double f5_14 = -f5 * m_A45;
+ m_A46 += m_A12 * f5_14;
+ m_A47 += m_A13 * f5_14;
+ m_A48 += m_A14 * f5_14;
+ m_A49 += m_A15 * f5_14;
+ RHS14 += f5_14 * RHS5;
+ const double f5_16 = -f5 * m_A55;
+ m_A56 += m_A12 * f5_16;
+ m_A59 += m_A13 * f5_16;
+ m_A60 += m_A14 * f5_16;
+ m_A61 += m_A15 * f5_16;
+ RHS16 += f5_16 * RHS5;
+ const double f6 = 1.0 / m_A16;
+ const double f6_15 = -f6 * m_A51;
+ m_A53 += m_A17 * f6_15;
+ RHS15 += f6_15 * RHS6;
+ const double f6_19 = -f6 * m_A76;
+ m_A82 += m_A17 * f6_19;
+ RHS19 += f6_19 * RHS6;
+ const double f7 = 1.0 / m_A18;
+ const double f7_18 = -f7 * m_A73;
+ m_A74 += m_A19 * f7_18;
+ RHS18 += f7_18 * RHS7;
+ const double f8 = 1.0 / m_A22;
+ const double f8_14 = -f8 * m_A46;
+ m_A47 += m_A23 * f8_14;
+ m_A48 += m_A24 * f8_14;
+ m_A49 += m_A25 * f8_14;
+ RHS14 += f8_14 * RHS8;
+ const double f8_16 = -f8 * m_A56;
+ m_A59 += m_A23 * f8_16;
+ m_A60 += m_A24 * f8_16;
+ m_A61 += m_A25 * f8_16;
+ RHS16 += f8_16 * RHS8;
+ const double f9 = 1.0 / m_A27;
+ const double f9_17 = -f9 * m_A65;
+ m_A66 += m_A28 * f9_17;
+ m_A71 += m_A29 * f9_17;
+ RHS17 += f9_17 * RHS9;
+ const double f10 = 1.0 / m_A31;
+ const double f10_17 = -f10 * m_A66;
+ m_A67 += m_A32 * f10_17;
+ m_A71 += m_A33 * f10_17;
+ RHS17 += f10_17 * RHS10;
+ const double f11 = 1.0 / m_A35;
+ const double f11_16 = -f11 * m_A57;
+ m_A58 += m_A36 * f11_16;
+ m_A61 += m_A37 * f11_16;
+ m_A62 += m_A38 * f11_16;
+ RHS16 += f11_16 * RHS11;
+ const double f11_17 = -f11 * m_A67;
+ m_A69 += m_A36 * f11_17;
+ m_A70 += m_A37 * f11_17;
+ m_A71 += m_A38 * f11_17;
+ RHS17 += f11_17 * RHS11;
+ const double f12 = 1.0 / m_A40;
+ const double f12_17 = -f12 * m_A68;
+ m_A71 += m_A41 * f12_17;
+ RHS17 += f12_17 * RHS12;
+ const double f13 = 1.0 / m_A43;
+ const double f13_16 = -f13 * m_A58;
+ m_A61 += m_A44 * f13_16;
+ RHS16 += f13_16 * RHS13;
+ const double f13_17 = -f13 * m_A69;
+ m_A70 += m_A44 * f13_17;
+ RHS17 += f13_17 * RHS13;
+ const double f14 = 1.0 / m_A47;
+ const double f14_16 = -f14 * m_A59;
+ m_A60 += m_A48 * f14_16;
+ m_A61 += m_A49 * f14_16;
+ m_A63 += m_A50 * f14_16;
+ RHS16 += f14_16 * RHS14;
+ const double f14_19 = -f14 * m_A77;
+ m_A78 += m_A48 * f14_19;
+ m_A79 += m_A49 * f14_19;
+ m_A82 += m_A50 * f14_19;
+ RHS19 += f14_19 * RHS14;
+ const double f15 = 1.0 / m_A52;
+ const double f15_16 = -f15 * m_A60;
+ m_A63 += m_A53 * f15_16;
+ RHS16 += f15_16 * RHS15;
+ const double f15_19 = -f15 * m_A78;
+ m_A82 += m_A53 * f15_19;
+ RHS19 += f15_19 * RHS15;
+ const double f16 = 1.0 / m_A61;
+ const double f16_17 = -f16 * m_A70;
+ m_A71 += m_A62 * f16_17;
+ m_A72 += m_A63 * f16_17;
+ RHS17 += f16_17 * RHS16;
+ const double f16_19 = -f16 * m_A79;
+ m_A80 += m_A62 * f16_19;
+ m_A82 += m_A63 * f16_19;
+ RHS19 += f16_19 * RHS16;
+ const double f17 = 1.0 / m_A71;
+ const double f17_19 = -f17 * m_A80;
+ m_A82 += m_A72 * f17_19;
+ RHS19 += f17_19 * RHS17;
+ const double f18 = 1.0 / m_A74;
+ const double f18_19 = -f18 * m_A81;
+ m_A82 += m_A75 * f18_19;
+ RHS19 += f18_19 * RHS18;
+ V[19] = RHS19 / m_A82;
+ double tmp18 = 0.0;
+ tmp18 += m_A75 * V[19];
+ V[18] = (RHS18 - tmp18) / m_A74;
+ double tmp17 = 0.0;
+ tmp17 += m_A72 * V[19];
+ V[17] = (RHS17 - tmp17) / m_A71;
+ double tmp16 = 0.0;
+ tmp16 += m_A62 * V[17];
+ tmp16 += m_A63 * V[19];
+ V[16] = (RHS16 - tmp16) / m_A61;
+ double tmp15 = 0.0;
+ tmp15 += m_A53 * V[19];
+ V[15] = (RHS15 - tmp15) / m_A52;
+ double tmp14 = 0.0;
+ tmp14 += m_A48 * V[15];
+ tmp14 += m_A49 * V[16];
+ tmp14 += m_A50 * V[19];
+ V[14] = (RHS14 - tmp14) / m_A47;
+ double tmp13 = 0.0;
+ tmp13 += m_A44 * V[16];
+ V[13] = (RHS13 - tmp13) / m_A43;
+ double tmp12 = 0.0;
+ tmp12 += m_A41 * V[17];
+ V[12] = (RHS12 - tmp12) / m_A40;
+ double tmp11 = 0.0;
+ tmp11 += m_A36 * V[13];
+ tmp11 += m_A37 * V[16];
+ tmp11 += m_A38 * V[17];
+ V[11] = (RHS11 - tmp11) / m_A35;
+ double tmp10 = 0.0;
+ tmp10 += m_A32 * V[11];
+ tmp10 += m_A33 * V[17];
+ V[10] = (RHS10 - tmp10) / m_A31;
+ double tmp9 = 0.0;
+ tmp9 += m_A28 * V[10];
+ tmp9 += m_A29 * V[17];
+ V[9] = (RHS9 - tmp9) / m_A27;
+ double tmp8 = 0.0;
+ tmp8 += m_A23 * V[14];
+ tmp8 += m_A24 * V[15];
+ tmp8 += m_A25 * V[16];
+ V[8] = (RHS8 - tmp8) / m_A22;
+ double tmp7 = 0.0;
+ tmp7 += m_A19 * V[18];
+ V[7] = (RHS7 - tmp7) / m_A18;
+ double tmp6 = 0.0;
+ tmp6 += m_A17 * V[19];
+ V[6] = (RHS6 - tmp6) / m_A16;
+ double tmp5 = 0.0;
+ tmp5 += m_A12 * V[8];
+ tmp5 += m_A13 * V[14];
+ tmp5 += m_A14 * V[15];
+ tmp5 += m_A15 * V[16];
+ V[5] = (RHS5 - tmp5) / m_A11;
+ double tmp4 = 0.0;
+ tmp4 += m_A10 * V[16];
+ V[4] = (RHS4 - tmp4) / m_A9;
+ double tmp3 = 0.0;
+ tmp3 += m_A8 * V[12];
+ V[3] = (RHS3 - tmp3) / m_A7;
+ double tmp2 = 0.0;
+ tmp2 += m_A6 * V[8];
+ V[2] = (RHS2 - tmp2) / m_A5;
+ double tmp1 = 0.0;
+ tmp1 += m_A3 * V[11];
+ tmp1 += m_A4 * V[17];
+ V[1] = (RHS1 - tmp1) / m_A2;
+ double tmp0 = 0.0;
+ tmp0 += m_A1 * V[9];
+ V[0] = (RHS0 - tmp0) / m_A0;
+}
+
// zektor
static void nl_gcr_fbff020f5f5d5a5_144_double_double(double * __restrict V, const double * __restrict go, const double * __restrict gt, const double * __restrict Idr, const double * const * __restrict cnV)
@@ -72420,401 +83040,449 @@ const plib::dynlib_static_sym nl_static_solver_syms[] = {
#if !defined(__EMSCRIPTEN__)
// elim
- {"nl_gcr_11c2ae166b240b6e_10_double_double", reinterpret_cast<void *>(&nl_gcr_11c2ae166b240b6e_10_double_double)},
+ {"nl_gcr_11c2ae166b240b6e_10_double_double", reinterpret_cast<void *>(&nl_gcr_11c2ae166b240b6e_10_double_double)}, // NOLINT
// tankbatt
- {"nl_gcr_124f7aa10f044582_16_double_double", reinterpret_cast<void *>(&nl_gcr_124f7aa10f044582_16_double_double)},
+ {"nl_gcr_124f7aa10f044582_16_double_double", reinterpret_cast<void *>(&nl_gcr_124f7aa10f044582_16_double_double)}, // NOLINT
// armora
- {"nl_gcr_1250f340dea396ae_22_double_double", reinterpret_cast<void *>(&nl_gcr_1250f340dea396ae_22_double_double)},
+ {"nl_gcr_1250f340dea396ae_22_double_double", reinterpret_cast<void *>(&nl_gcr_1250f340dea396ae_22_double_double)}, // NOLINT
+// astrob
+ {"nl_gcr_13833bf8c127deaa_154_double_double", reinterpret_cast<void *>(&nl_gcr_13833bf8c127deaa_154_double_double)}, // NOLINT
// pongf
- {"nl_gcr_13e7b5ac1a260dbf_10_double_double", reinterpret_cast<void *>(&nl_gcr_13e7b5ac1a260dbf_10_double_double)},
+ {"nl_gcr_13e7b5ac1a260dbf_10_double_double", reinterpret_cast<void *>(&nl_gcr_13e7b5ac1a260dbf_10_double_double)}, // NOLINT
// tailg
- {"nl_gcr_144ed14e6bafdb_119_double_double", reinterpret_cast<void *>(&nl_gcr_144ed14e6bafdb_119_double_double)},
+ {"nl_gcr_144ed14e6bafdb_119_double_double", reinterpret_cast<void *>(&nl_gcr_144ed14e6bafdb_119_double_double)}, // NOLINT
// spacewar
- {"nl_gcr_15e8f6fb021de0f9_28_double_double", reinterpret_cast<void *>(&nl_gcr_15e8f6fb021de0f9_28_double_double)},
-// armora
- {"nl_gcr_1692de755a535408_9_double_double", reinterpret_cast<void *>(&nl_gcr_1692de755a535408_9_double_double)},
+ {"nl_gcr_15e8f6fb021de0f9_28_double_double", reinterpret_cast<void *>(&nl_gcr_15e8f6fb021de0f9_28_double_double)}, // NOLINT
// dpatrol
- {"nl_gcr_18f4d9160b51d613_20_double_double", reinterpret_cast<void *>(&nl_gcr_18f4d9160b51d613_20_double_double)},
+ {"nl_gcr_18f4d9160b51d613_20_double_double", reinterpret_cast<void *>(&nl_gcr_18f4d9160b51d613_20_double_double)}, // NOLINT
// starhawk
- {"nl_gcr_1f1086787c94f97c_40_double_double", reinterpret_cast<void *>(&nl_gcr_1f1086787c94f97c_40_double_double)},
+ {"nl_gcr_1f1086787c94f97c_40_double_double", reinterpret_cast<void *>(&nl_gcr_1f1086787c94f97c_40_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_1fad5cda2646cf42_30_double_double", reinterpret_cast<void *>(&nl_gcr_1fad5cda2646cf42_30_double_double)},
+ {"nl_gcr_1fad5cda2646cf42_30_double_double", reinterpret_cast<void *>(&nl_gcr_1fad5cda2646cf42_30_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_1fec893028a7b809_34_double_double", reinterpret_cast<void *>(&nl_gcr_1fec893028a7b809_34_double_double)}, // NOLINT
// sspeedr
- {"nl_gcr_2294220d3c91e762_176_double_double", reinterpret_cast<void *>(&nl_gcr_2294220d3c91e762_176_double_double)},
+ {"nl_gcr_2294220d3c91e762_176_double_double", reinterpret_cast<void *>(&nl_gcr_2294220d3c91e762_176_double_double)}, // NOLINT
+// headon
+ {"nl_gcr_24023c8529f6bdb3_97_double_double", reinterpret_cast<void *>(&nl_gcr_24023c8529f6bdb3_97_double_double)}, // NOLINT
// 280zzzap
- {"nl_gcr_24643c159711f292_95_double_double", reinterpret_cast<void *>(&nl_gcr_24643c159711f292_95_double_double)},
+ {"nl_gcr_24643c159711f292_95_double_double", reinterpret_cast<void *>(&nl_gcr_24643c159711f292_95_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_263b618097fad01_38_double_double", reinterpret_cast<void *>(&nl_gcr_263b618097fad01_38_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_2753fc1815ce0cba_23_double_double", reinterpret_cast<void *>(&nl_gcr_2753fc1815ce0cba_23_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_287a160e7c36b5b0_96_double_double", reinterpret_cast<void *>(&nl_gcr_287a160e7c36b5b0_96_double_double)},
+ {"nl_gcr_287a160e7c36b5b0_96_double_double", reinterpret_cast<void *>(&nl_gcr_287a160e7c36b5b0_96_double_double)}, // NOLINT
// elim
- {"nl_gcr_28b736fe552777a9_45_double_double", reinterpret_cast<void *>(&nl_gcr_28b736fe552777a9_45_double_double)},
+ {"nl_gcr_28b736fe552777a9_45_double_double", reinterpret_cast<void *>(&nl_gcr_28b736fe552777a9_45_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_294dde1e0ecca6d0_37_double_double", reinterpret_cast<void *>(&nl_gcr_294dde1e0ecca6d0_37_double_double)},
+ {"nl_gcr_294dde1e0ecca6d0_37_double_double", reinterpret_cast<void *>(&nl_gcr_294dde1e0ecca6d0_37_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_295cf2e2f3d489bf_12_double_double", reinterpret_cast<void *>(&nl_gcr_295cf2e2f3d489bf_12_double_double)},
+ {"nl_gcr_295cf2e2f3d489bf_12_double_double", reinterpret_cast<void *>(&nl_gcr_295cf2e2f3d489bf_12_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_2a153513d3e8e2cc_53_double_double", reinterpret_cast<void *>(&nl_gcr_2a153513d3e8e2cc_53_double_double)},
+ {"nl_gcr_2a153513d3e8e2cc_53_double_double", reinterpret_cast<void *>(&nl_gcr_2a153513d3e8e2cc_53_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_2f84bc98d737730b_22_double_double", reinterpret_cast<void *>(&nl_gcr_2f84bc98d737730b_22_double_double)},
-// astrob
- {"nl_gcr_30fc51fe03b164cb_178_double_double", reinterpret_cast<void *>(&nl_gcr_30fc51fe03b164cb_178_double_double)},
+ {"nl_gcr_2f84bc98d737730b_22_double_double", reinterpret_cast<void *>(&nl_gcr_2f84bc98d737730b_22_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_30923b54310ae144_8_double_double", reinterpret_cast<void *>(&nl_gcr_30923b54310ae144_8_double_double)}, // NOLINT
// tankbatt
- {"nl_gcr_328d886b444b586b_137_double_double", reinterpret_cast<void *>(&nl_gcr_328d886b444b586b_137_double_double)},
+ {"nl_gcr_328d886b444b586b_137_double_double", reinterpret_cast<void *>(&nl_gcr_328d886b444b586b_137_double_double)}, // NOLINT
// astrob
- {"nl_gcr_339c6b457f339538_159_double_double", reinterpret_cast<void *>(&nl_gcr_339c6b457f339538_159_double_double)},
+ {"nl_gcr_339c6b457f339538_159_double_double", reinterpret_cast<void *>(&nl_gcr_339c6b457f339538_159_double_double)}, // NOLINT
// solarq
- {"nl_gcr_34e910fc1896999f_76_double_double", reinterpret_cast<void *>(&nl_gcr_34e910fc1896999f_76_double_double)},
+ {"nl_gcr_34e910fc1896999f_76_double_double", reinterpret_cast<void *>(&nl_gcr_34e910fc1896999f_76_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_3c79fd354e01fa8c_89_double_double", reinterpret_cast<void *>(&nl_gcr_3c79fd354e01fa8c_89_double_double)}, // NOLINT
// sspeedr
- {"nl_gcr_3e833834e5ce5aee_13_double_double", reinterpret_cast<void *>(&nl_gcr_3e833834e5ce5aee_13_double_double)},
+ {"nl_gcr_3e833834e5ce5aee_13_double_double", reinterpret_cast<void *>(&nl_gcr_3e833834e5ce5aee_13_double_double)}, // NOLINT
// astrob
- {"nl_gcr_41c6441d98369158_20_double_double", reinterpret_cast<void *>(&nl_gcr_41c6441d98369158_20_double_double)},
+ {"nl_gcr_41c6441d98369158_20_double_double", reinterpret_cast<void *>(&nl_gcr_41c6441d98369158_20_double_double)}, // NOLINT
// warrior
- {"nl_gcr_42a31ce5c187b308_12_double_double", reinterpret_cast<void *>(&nl_gcr_42a31ce5c187b308_12_double_double)},
+ {"nl_gcr_42a31ce5c187b308_12_double_double", reinterpret_cast<void *>(&nl_gcr_42a31ce5c187b308_12_double_double)}, // NOLINT
// 280zzzap
- {"nl_gcr_42c57d523cac30d0_122_double_double", reinterpret_cast<void *>(&nl_gcr_42c57d523cac30d0_122_double_double)},
+ {"nl_gcr_42c57d523cac30d0_122_double_double", reinterpret_cast<void *>(&nl_gcr_42c57d523cac30d0_122_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_43188bf576854ae0_10_double_double", reinterpret_cast<void *>(&nl_gcr_43188bf576854ae0_10_double_double)},
+ {"nl_gcr_43188bf576854ae0_10_double_double", reinterpret_cast<void *>(&nl_gcr_43188bf576854ae0_10_double_double)}, // NOLINT
// destroyr
- {"nl_gcr_4334c95878d1be92_399_double_double", reinterpret_cast<void *>(&nl_gcr_4334c95878d1be92_399_double_double)},
+ {"nl_gcr_4334c95878d1be92_399_double_double", reinterpret_cast<void *>(&nl_gcr_4334c95878d1be92_399_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_437326911721091_77_double_double", reinterpret_cast<void *>(&nl_gcr_437326911721091_77_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_43f7ff9bc651cc7a_198_double_double", reinterpret_cast<void *>(&nl_gcr_43f7ff9bc651cc7a_198_double_double)},
+ {"nl_gcr_43f7ff9bc651cc7a_198_double_double", reinterpret_cast<void *>(&nl_gcr_43f7ff9bc651cc7a_198_double_double)}, // NOLINT
// gamemachine
- {"nl_gcr_491f95430bfdfd05_19_double_double", reinterpret_cast<void *>(&nl_gcr_491f95430bfdfd05_19_double_double)},
+ {"nl_gcr_491f95430bfdfd05_19_double_double", reinterpret_cast<void *>(&nl_gcr_491f95430bfdfd05_19_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_494f233b1a947be1_88_double_double", reinterpret_cast<void *>(&nl_gcr_494f233b1a947be1_88_double_double)}, // NOLINT
// sspeedr
- {"nl_gcr_4a8e2b707bbac8a6_95_double_double", reinterpret_cast<void *>(&nl_gcr_4a8e2b707bbac8a6_95_double_double)},
+ {"nl_gcr_4a8e2b707bbac8a6_95_double_double", reinterpret_cast<void *>(&nl_gcr_4a8e2b707bbac8a6_95_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_4b5ecfbb8f9fa97b_29_double_double", reinterpret_cast<void *>(&nl_gcr_4b5ecfbb8f9fa97b_29_double_double)},
+ {"nl_gcr_4b5ecfbb8f9fa97b_29_double_double", reinterpret_cast<void *>(&nl_gcr_4b5ecfbb8f9fa97b_29_double_double)}, // NOLINT
// gtrak10
- {"nl_gcr_4c46fdf7c0037727_43_double_double", reinterpret_cast<void *>(&nl_gcr_4c46fdf7c0037727_43_double_double)},
+ {"nl_gcr_4c46fdf7c0037727_43_double_double", reinterpret_cast<void *>(&nl_gcr_4c46fdf7c0037727_43_double_double)}, // NOLINT
// solarq
- {"nl_gcr_4cb524006206eb1a_25_double_double", reinterpret_cast<void *>(&nl_gcr_4cb524006206eb1a_25_double_double)},
+ {"nl_gcr_4cb524006206eb1a_25_double_double", reinterpret_cast<void *>(&nl_gcr_4cb524006206eb1a_25_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_4dbd0f2aec7ef707_110_double_double", reinterpret_cast<void *>(&nl_gcr_4dbd0f2aec7ef707_110_double_double)},
+ {"nl_gcr_4dbd0f2aec7ef707_110_double_double", reinterpret_cast<void *>(&nl_gcr_4dbd0f2aec7ef707_110_double_double)}, // NOLINT
// solarq
- {"nl_gcr_4e4931ccbfb7a3c_70_double_double", reinterpret_cast<void *>(&nl_gcr_4e4931ccbfb7a3c_70_double_double)},
+ {"nl_gcr_4e4931ccbfb7a3c_70_double_double", reinterpret_cast<void *>(&nl_gcr_4e4931ccbfb7a3c_70_double_double)}, // NOLINT
// fireone
- {"nl_gcr_4f2b2f3cdc384f75_41_double_double", reinterpret_cast<void *>(&nl_gcr_4f2b2f3cdc384f75_41_double_double)},
+ {"nl_gcr_4f2b2f3cdc384f75_41_double_double", reinterpret_cast<void *>(&nl_gcr_4f2b2f3cdc384f75_41_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_50f5194a994d56ec_16_double_double", reinterpret_cast<void *>(&nl_gcr_50f5194a994d56ec_16_double_double)},
+ {"nl_gcr_50f5194a994d56ec_16_double_double", reinterpret_cast<void *>(&nl_gcr_50f5194a994d56ec_16_double_double)}, // NOLINT
// starhawk
- {"nl_gcr_528a27fe9ed07d67_45_double_double", reinterpret_cast<void *>(&nl_gcr_528a27fe9ed07d67_45_double_double)},
+ {"nl_gcr_528a27fe9ed07d67_45_double_double", reinterpret_cast<void *>(&nl_gcr_528a27fe9ed07d67_45_double_double)}, // NOLINT
// astrob
- {"nl_gcr_536c3652eb3bc075_46_double_double", reinterpret_cast<void *>(&nl_gcr_536c3652eb3bc075_46_double_double)},
+ {"nl_gcr_536c3652eb3bc075_46_double_double", reinterpret_cast<void *>(&nl_gcr_536c3652eb3bc075_46_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_53e1117fdb16f546_23_double_double", reinterpret_cast<void *>(&nl_gcr_53e1117fdb16f546_23_double_double)},
+ {"nl_gcr_53e1117fdb16f546_23_double_double", reinterpret_cast<void *>(&nl_gcr_53e1117fdb16f546_23_double_double)}, // NOLINT
// cheekyms
- {"nl_gcr_546396f65ce48700_12_double_double", reinterpret_cast<void *>(&nl_gcr_546396f65ce48700_12_double_double)},
-// dpatrol
- {"nl_gcr_59cb6bf7cb9d17dc_7_double_double", reinterpret_cast<void *>(&nl_gcr_59cb6bf7cb9d17dc_7_double_double)},
+ {"nl_gcr_546396f65ce48700_12_double_double", reinterpret_cast<void *>(&nl_gcr_546396f65ce48700_12_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_576f391d0418cb76_13_double_double", reinterpret_cast<void *>(&nl_gcr_576f391d0418cb76_13_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_59cb6bf7cb9d17dc_7_double_double", reinterpret_cast<void *>(&nl_gcr_59cb6bf7cb9d17dc_7_double_double)}, // NOLINT
// breakout
- {"nl_gcr_5a3419e2809520de_13_double_double", reinterpret_cast<void *>(&nl_gcr_5a3419e2809520de_13_double_double)},
+ {"nl_gcr_5a3419e2809520de_13_double_double", reinterpret_cast<void *>(&nl_gcr_5a3419e2809520de_13_double_double)}, // NOLINT
// segausb
- {"nl_gcr_5b73834d5f313d38_12_double_double", reinterpret_cast<void *>(&nl_gcr_5b73834d5f313d38_12_double_double)},
+ {"nl_gcr_5b73834d5f313d38_12_double_double", reinterpret_cast<void *>(&nl_gcr_5b73834d5f313d38_12_double_double)}, // NOLINT
// tailg
- {"nl_gcr_5ccf7da1202da2e5_31_double_double", reinterpret_cast<void *>(&nl_gcr_5ccf7da1202da2e5_31_double_double)},
+ {"nl_gcr_5ccf7da1202da2e5_31_double_double", reinterpret_cast<void *>(&nl_gcr_5ccf7da1202da2e5_31_double_double)}, // NOLINT
// starcas
- {"nl_gcr_5d550fc7441617a2_109_double_double", reinterpret_cast<void *>(&nl_gcr_5d550fc7441617a2_109_double_double)},
+ {"nl_gcr_5d550fc7441617a2_109_double_double", reinterpret_cast<void *>(&nl_gcr_5d550fc7441617a2_109_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_6041272373b8603c_178_double_double", reinterpret_cast<void *>(&nl_gcr_6041272373b8603c_178_double_double)},
+ {"nl_gcr_6041272373b8603c_178_double_double", reinterpret_cast<void *>(&nl_gcr_6041272373b8603c_178_double_double)}, // NOLINT
+// astrob
+ {"nl_gcr_62464664b1c5aa1e_27_double_double", reinterpret_cast<void *>(&nl_gcr_62464664b1c5aa1e_27_double_double)}, // NOLINT
// solarq
- {"nl_gcr_62612f71055b8fd4_303_double_double", reinterpret_cast<void *>(&nl_gcr_62612f71055b8fd4_303_double_double)},
+ {"nl_gcr_62612f71055b8fd4_303_double_double", reinterpret_cast<void *>(&nl_gcr_62612f71055b8fd4_303_double_double)}, // NOLINT
// konami1x
- {"nl_gcr_62b99b9904a8c804_49_double_double", reinterpret_cast<void *>(&nl_gcr_62b99b9904a8c804_49_double_double)},
+ {"nl_gcr_62b99b9904a8c804_49_double_double", reinterpret_cast<void *>(&nl_gcr_62b99b9904a8c804_49_double_double)}, // NOLINT
// fireone
- {"nl_gcr_643133e86b2b1628_73_double_double", reinterpret_cast<void *>(&nl_gcr_643133e86b2b1628_73_double_double)},
+ {"nl_gcr_643133e86b2b1628_73_double_double", reinterpret_cast<void *>(&nl_gcr_643133e86b2b1628_73_double_double)}, // NOLINT
// starfire
- {"nl_gcr_649ebca7fa6793ed_27_double_double", reinterpret_cast<void *>(&nl_gcr_649ebca7fa6793ed_27_double_double)},
+ {"nl_gcr_649ebca7fa6793ed_27_double_double", reinterpret_cast<void *>(&nl_gcr_649ebca7fa6793ed_27_double_double)}, // NOLINT
// armora
- {"nl_gcr_64e460d8f716cd89_58_double_double", reinterpret_cast<void *>(&nl_gcr_64e460d8f716cd89_58_double_double)},
+ {"nl_gcr_64e460d8f716cd89_58_double_double", reinterpret_cast<void *>(&nl_gcr_64e460d8f716cd89_58_double_double)}, // NOLINT
// flyball
- {"nl_gcr_6622b53554e3776_291_double_double", reinterpret_cast<void *>(&nl_gcr_6622b53554e3776_291_double_double)},
+ {"nl_gcr_6622b53554e3776_291_double_double", reinterpret_cast<void *>(&nl_gcr_6622b53554e3776_291_double_double)}, // NOLINT
// solarq
- {"nl_gcr_66496d6073aca98e_20_double_double", reinterpret_cast<void *>(&nl_gcr_66496d6073aca98e_20_double_double)},
+ {"nl_gcr_66496d6073aca98e_20_double_double", reinterpret_cast<void *>(&nl_gcr_66496d6073aca98e_20_double_double)}, // NOLINT
// starhawk
- {"nl_gcr_67838e11f714c455_12_double_double", reinterpret_cast<void *>(&nl_gcr_67838e11f714c455_12_double_double)},
+ {"nl_gcr_67838e11f714c455_12_double_double", reinterpret_cast<void *>(&nl_gcr_67838e11f714c455_12_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_698d5dd47fb16d5_16_double_double", reinterpret_cast<void *>(&nl_gcr_698d5dd47fb16d5_16_double_double)},
+ {"nl_gcr_698d5dd47fb16d5_16_double_double", reinterpret_cast<void *>(&nl_gcr_698d5dd47fb16d5_16_double_double)}, // NOLINT
// astrob
- {"nl_gcr_6c24726f30e8dc34_15_double_double", reinterpret_cast<void *>(&nl_gcr_6c24726f30e8dc34_15_double_double)},
+ {"nl_gcr_6c24726f30e8dc34_15_double_double", reinterpret_cast<void *>(&nl_gcr_6c24726f30e8dc34_15_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_6eae7b15cd376318_43_double_double", reinterpret_cast<void *>(&nl_gcr_6eae7b15cd376318_43_double_double)},
+ {"nl_gcr_6eae7b15cd376318_43_double_double", reinterpret_cast<void *>(&nl_gcr_6eae7b15cd376318_43_double_double)}, // NOLINT
// barrier
- {"nl_gcr_6ef39a62161d596c_47_double_double", reinterpret_cast<void *>(&nl_gcr_6ef39a62161d596c_47_double_double)},
+ {"nl_gcr_6ef39a62161d596c_47_double_double", reinterpret_cast<void *>(&nl_gcr_6ef39a62161d596c_47_double_double)}, // NOLINT
// starhawk
- {"nl_gcr_723fa454468a93d_7_double_double", reinterpret_cast<void *>(&nl_gcr_723fa454468a93d_7_double_double)},
+ {"nl_gcr_723fa454468a93d_7_double_double", reinterpret_cast<void *>(&nl_gcr_723fa454468a93d_7_double_double)}, // NOLINT
// cheekyms
- {"nl_gcr_733c72a820fdbd1f_7_double_double", reinterpret_cast<void *>(&nl_gcr_733c72a820fdbd1f_7_double_double)},
+ {"nl_gcr_733c72a820fdbd1f_7_double_double", reinterpret_cast<void *>(&nl_gcr_733c72a820fdbd1f_7_double_double)}, // NOLINT
// tailg
- {"nl_gcr_7388106355fb27c3_12_double_double", reinterpret_cast<void *>(&nl_gcr_7388106355fb27c3_12_double_double)},
+ {"nl_gcr_7388106355fb27c3_12_double_double", reinterpret_cast<void *>(&nl_gcr_7388106355fb27c3_12_double_double)}, // NOLINT
// tp1985
- {"nl_gcr_73f2ba8ad4a45b26_10_double_double", reinterpret_cast<void *>(&nl_gcr_73f2ba8ad4a45b26_10_double_double)},
+ {"nl_gcr_73f2ba8ad4a45b26_10_double_double", reinterpret_cast<void *>(&nl_gcr_73f2ba8ad4a45b26_10_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_7425594cec8024ad_30_double_double", reinterpret_cast<void *>(&nl_gcr_7425594cec8024ad_30_double_double)},
+ {"nl_gcr_7425594cec8024ad_30_double_double", reinterpret_cast<void *>(&nl_gcr_7425594cec8024ad_30_double_double)}, // NOLINT
// tp1985
- {"nl_gcr_74349e9889a2630b_7_double_double", reinterpret_cast<void *>(&nl_gcr_74349e9889a2630b_7_double_double)},
+ {"nl_gcr_74349e9889a2630b_7_double_double", reinterpret_cast<void *>(&nl_gcr_74349e9889a2630b_7_double_double)}, // NOLINT
// gunfight
- {"nl_gcr_743595e64cee0a5e_112_double_double", reinterpret_cast<void *>(&nl_gcr_743595e64cee0a5e_112_double_double)},
+ {"nl_gcr_743595e64cee0a5e_112_double_double", reinterpret_cast<void *>(&nl_gcr_743595e64cee0a5e_112_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_75400df5d559a266_75_double_double", reinterpret_cast<void *>(&nl_gcr_75400df5d559a266_75_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_75852e71cc632a65_33_double_double", reinterpret_cast<void *>(&nl_gcr_75852e71cc632a65_33_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_76c9e236353caed1_35_double_double", reinterpret_cast<void *>(&nl_gcr_76c9e236353caed1_35_double_double)},
+ {"nl_gcr_76c9e236353caed1_35_double_double", reinterpret_cast<void *>(&nl_gcr_76c9e236353caed1_35_double_double)}, // NOLINT
// gamemachine
- {"nl_gcr_782d79b5cbe953b1_7_double_double", reinterpret_cast<void *>(&nl_gcr_782d79b5cbe953b1_7_double_double)},
+ {"nl_gcr_782d79b5cbe953b1_7_double_double", reinterpret_cast<void *>(&nl_gcr_782d79b5cbe953b1_7_double_double)}, // NOLINT
// barrier
- {"nl_gcr_79e756c5892cf87d_31_double_double", reinterpret_cast<void *>(&nl_gcr_79e756c5892cf87d_31_double_double)},
+ {"nl_gcr_79e756c5892cf87d_31_double_double", reinterpret_cast<void *>(&nl_gcr_79e756c5892cf87d_31_double_double)}, // NOLINT
// breakout
- {"nl_gcr_7a42b97d838ca073_7_double_double", reinterpret_cast<void *>(&nl_gcr_7a42b97d838ca073_7_double_double)},
+ {"nl_gcr_7a42b97d838ca073_7_double_double", reinterpret_cast<void *>(&nl_gcr_7a42b97d838ca073_7_double_double)}, // NOLINT
// fireone
- {"nl_gcr_7aee4423e3fdbfda_128_double_double", reinterpret_cast<void *>(&nl_gcr_7aee4423e3fdbfda_128_double_double)},
+ {"nl_gcr_7aee4423e3fdbfda_128_double_double", reinterpret_cast<void *>(&nl_gcr_7aee4423e3fdbfda_128_double_double)}, // NOLINT
// astrob
- {"nl_gcr_7c86a9bc1c6aef4c_7_double_double", reinterpret_cast<void *>(&nl_gcr_7c86a9bc1c6aef4c_7_double_double)},
+ {"nl_gcr_7c86a9bc1c6aef4c_7_double_double", reinterpret_cast<void *>(&nl_gcr_7c86a9bc1c6aef4c_7_double_double)}, // NOLINT
// solarq
- {"nl_gcr_7caaa135bff3d9f3_15_double_double", reinterpret_cast<void *>(&nl_gcr_7caaa135bff3d9f3_15_double_double)},
+ {"nl_gcr_7caaa135bff3d9f3_15_double_double", reinterpret_cast<void *>(&nl_gcr_7caaa135bff3d9f3_15_double_double)}, // NOLINT
// warrior
- {"nl_gcr_8003d4625273fa4d_10_double_double", reinterpret_cast<void *>(&nl_gcr_8003d4625273fa4d_10_double_double)},
+ {"nl_gcr_8003d4625273fa4d_10_double_double", reinterpret_cast<void *>(&nl_gcr_8003d4625273fa4d_10_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_8046625a0fe0959_21_double_double", reinterpret_cast<void *>(&nl_gcr_8046625a0fe0959_21_double_double)},
+ {"nl_gcr_8046625a0fe0959_21_double_double", reinterpret_cast<void *>(&nl_gcr_8046625a0fe0959_21_double_double)}, // NOLINT
// mario
- {"nl_gcr_80b4b1e5cc58d303_29_double_double", reinterpret_cast<void *>(&nl_gcr_80b4b1e5cc58d303_29_double_double)},
+ {"nl_gcr_80b4b1e5cc58d303_29_double_double", reinterpret_cast<void *>(&nl_gcr_80b4b1e5cc58d303_29_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_815733e3f2e05029_9_double_double", reinterpret_cast<void *>(&nl_gcr_815733e3f2e05029_9_double_double)}, // NOLINT
// elim
- {"nl_gcr_81f40a54af2ca202_10_double_double", reinterpret_cast<void *>(&nl_gcr_81f40a54af2ca202_10_double_double)},
+ {"nl_gcr_81f40a54af2ca202_10_double_double", reinterpret_cast<void *>(&nl_gcr_81f40a54af2ca202_10_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_84425fea9033e75d_7_double_double", reinterpret_cast<void *>(&nl_gcr_84425fea9033e75d_7_double_double)}, // NOLINT
// sundance
- {"nl_gcr_8446e63d7842f6a6_70_double_double", reinterpret_cast<void *>(&nl_gcr_8446e63d7842f6a6_70_double_double)},
+ {"nl_gcr_8446e63d7842f6a6_70_double_double", reinterpret_cast<void *>(&nl_gcr_8446e63d7842f6a6_70_double_double)}, // NOLINT
// dpatrol
- {"nl_gcr_85652d3e3ada285a_10_double_double", reinterpret_cast<void *>(&nl_gcr_85652d3e3ada285a_10_double_double)},
+ {"nl_gcr_85652d3e3ada285a_10_double_double", reinterpret_cast<void *>(&nl_gcr_85652d3e3ada285a_10_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_861d39f81d29d51_12_double_double", reinterpret_cast<void *>(&nl_gcr_861d39f81d29d51_12_double_double)},
+ {"nl_gcr_861d39f81d29d51_12_double_double", reinterpret_cast<void *>(&nl_gcr_861d39f81d29d51_12_double_double)}, // NOLINT
// 280zzzap
- {"nl_gcr_864a61c57bac9c38_123_double_double", reinterpret_cast<void *>(&nl_gcr_864a61c57bac9c38_123_double_double)},
+ {"nl_gcr_864a61c57bac9c38_123_double_double", reinterpret_cast<void *>(&nl_gcr_864a61c57bac9c38_123_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_87cb2c78a2628efd_7_double_double", reinterpret_cast<void *>(&nl_gcr_87cb2c78a2628efd_7_double_double)},
+ {"nl_gcr_87cb2c78a2628efd_7_double_double", reinterpret_cast<void *>(&nl_gcr_87cb2c78a2628efd_7_double_double)}, // NOLINT
// starcas
- {"nl_gcr_88a8ef5f6bd43d48_12_double_double", reinterpret_cast<void *>(&nl_gcr_88a8ef5f6bd43d48_12_double_double)},
+ {"nl_gcr_88a8ef5f6bd43d48_12_double_double", reinterpret_cast<void *>(&nl_gcr_88a8ef5f6bd43d48_12_double_double)}, // NOLINT
// breakout
- {"nl_gcr_8a1565d1413f42f7_31_double_double", reinterpret_cast<void *>(&nl_gcr_8a1565d1413f42f7_31_double_double)},
+ {"nl_gcr_8a1565d1413f42f7_31_double_double", reinterpret_cast<void *>(&nl_gcr_8a1565d1413f42f7_31_double_double)}, // NOLINT
// starhawk
- {"nl_gcr_8b1ac1e181eec3fc_40_double_double", reinterpret_cast<void *>(&nl_gcr_8b1ac1e181eec3fc_40_double_double)},
+ {"nl_gcr_8b1ac1e181eec3fc_40_double_double", reinterpret_cast<void *>(&nl_gcr_8b1ac1e181eec3fc_40_double_double)}, // NOLINT
// rebound
- {"nl_gcr_8bec817b324dcc3_28_double_double", reinterpret_cast<void *>(&nl_gcr_8bec817b324dcc3_28_double_double)},
+ {"nl_gcr_8bec817b324dcc3_28_double_double", reinterpret_cast<void *>(&nl_gcr_8bec817b324dcc3_28_double_double)}, // NOLINT
// cocoloco
- {"nl_gcr_8c0f7f2284333de5_16_double_double", reinterpret_cast<void *>(&nl_gcr_8c0f7f2284333de5_16_double_double)},
+ {"nl_gcr_8c0f7f2284333de5_16_double_double", reinterpret_cast<void *>(&nl_gcr_8c0f7f2284333de5_16_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_8c1dd4afcf0f8ea2_15_double_double", reinterpret_cast<void *>(&nl_gcr_8c1dd4afcf0f8ea2_15_double_double)},
+ {"nl_gcr_8c1dd4afcf0f8ea2_15_double_double", reinterpret_cast<void *>(&nl_gcr_8c1dd4afcf0f8ea2_15_double_double)}, // NOLINT
// fireone
- {"nl_gcr_8c512fd6a6dabc50_35_double_double", reinterpret_cast<void *>(&nl_gcr_8c512fd6a6dabc50_35_double_double)},
+ {"nl_gcr_8c512fd6a6dabc50_35_double_double", reinterpret_cast<void *>(&nl_gcr_8c512fd6a6dabc50_35_double_double)}, // NOLINT
// segausb
- {"nl_gcr_8cc4eb213eaeef9b_30_double_double", reinterpret_cast<void *>(&nl_gcr_8cc4eb213eaeef9b_30_double_double)},
+ {"nl_gcr_8cc4eb213eaeef9b_30_double_double", reinterpret_cast<void *>(&nl_gcr_8cc4eb213eaeef9b_30_double_double)}, // NOLINT
// starcrus
- {"nl_gcr_8d7bddf33d942482_129_double_double", reinterpret_cast<void *>(&nl_gcr_8d7bddf33d942482_129_double_double)},
+ {"nl_gcr_8d7bddf33d942482_129_double_double", reinterpret_cast<void *>(&nl_gcr_8d7bddf33d942482_129_double_double)}, // NOLINT
// tank
- {"nl_gcr_930b64361c2cdba8_328_double_double", reinterpret_cast<void *>(&nl_gcr_930b64361c2cdba8_328_double_double)},
+ {"nl_gcr_930b64361c2cdba8_328_double_double", reinterpret_cast<void *>(&nl_gcr_930b64361c2cdba8_328_double_double)}, // NOLINT
// gamemachine
- {"nl_gcr_934712b55bb3b2b2_10_double_double", reinterpret_cast<void *>(&nl_gcr_934712b55bb3b2b2_10_double_double)},
+ {"nl_gcr_934712b55bb3b2b2_10_double_double", reinterpret_cast<void *>(&nl_gcr_934712b55bb3b2b2_10_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_9a5874c8e2da79d2_37_double_double", reinterpret_cast<void *>(&nl_gcr_9a5874c8e2da79d2_37_double_double)},
+ {"nl_gcr_9a5874c8e2da79d2_37_double_double", reinterpret_cast<void *>(&nl_gcr_9a5874c8e2da79d2_37_double_double)}, // NOLINT
// fireone
- {"nl_gcr_9aa159329f86ca8b_70_double_double", reinterpret_cast<void *>(&nl_gcr_9aa159329f86ca8b_70_double_double)},
+ {"nl_gcr_9aa159329f86ca8b_70_double_double", reinterpret_cast<void *>(&nl_gcr_9aa159329f86ca8b_70_double_double)}, // NOLINT
// warrior
- {"nl_gcr_9c975530a1a529d6_7_double_double", reinterpret_cast<void *>(&nl_gcr_9c975530a1a529d6_7_double_double)},
+ {"nl_gcr_9c975530a1a529d6_7_double_double", reinterpret_cast<void *>(&nl_gcr_9c975530a1a529d6_7_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_9f141889c2091efc_24_double_double", reinterpret_cast<void *>(&nl_gcr_9f141889c2091efc_24_double_double)},
+ {"nl_gcr_9f141889c2091efc_24_double_double", reinterpret_cast<void *>(&nl_gcr_9f141889c2091efc_24_double_double)}, // NOLINT
// segas16b_audio
- {"nl_gcr_9f7104c5e25c87dd_111_double_double", reinterpret_cast<void *>(&nl_gcr_9f7104c5e25c87dd_111_double_double)},
+ {"nl_gcr_9f7104c5e25c87dd_111_double_double", reinterpret_cast<void *>(&nl_gcr_9f7104c5e25c87dd_111_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_a0bf548977306172_25_double_double", reinterpret_cast<void *>(&nl_gcr_a0bf548977306172_25_double_double)},
+ {"nl_gcr_a0bf548977306172_25_double_double", reinterpret_cast<void *>(&nl_gcr_a0bf548977306172_25_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_a1132c8737d5d463_96_double_double", reinterpret_cast<void *>(&nl_gcr_a1132c8737d5d463_96_double_double)},
+ {"nl_gcr_a1132c8737d5d463_96_double_double", reinterpret_cast<void *>(&nl_gcr_a1132c8737d5d463_96_double_double)}, // NOLINT
// astrob
- {"nl_gcr_a41a44bd5c424f88_13_double_double", reinterpret_cast<void *>(&nl_gcr_a41a44bd5c424f88_13_double_double)},
+ {"nl_gcr_a41a44bd5c424f88_13_double_double", reinterpret_cast<void *>(&nl_gcr_a41a44bd5c424f88_13_double_double)}, // NOLINT
// tp1985
- {"nl_gcr_a4540ffea06b4346_26_double_double", reinterpret_cast<void *>(&nl_gcr_a4540ffea06b4346_26_double_double)},
+ {"nl_gcr_a4540ffea06b4346_26_double_double", reinterpret_cast<void *>(&nl_gcr_a4540ffea06b4346_26_double_double)}, // NOLINT
// tailg
- {"nl_gcr_a46301cd3479b8db_15_double_double", reinterpret_cast<void *>(&nl_gcr_a46301cd3479b8db_15_double_double)},
+ {"nl_gcr_a46301cd3479b8db_15_double_double", reinterpret_cast<void *>(&nl_gcr_a46301cd3479b8db_15_double_double)}, // NOLINT
// barrier
- {"nl_gcr_a50a4b733e95414a_10_double_double", reinterpret_cast<void *>(&nl_gcr_a50a4b733e95414a_10_double_double)},
+ {"nl_gcr_a50a4b733e95414a_10_double_double", reinterpret_cast<void *>(&nl_gcr_a50a4b733e95414a_10_double_double)}, // NOLINT
// starcas
- {"nl_gcr_a582a424cb61c678_62_double_double", reinterpret_cast<void *>(&nl_gcr_a582a424cb61c678_62_double_double)},
+ {"nl_gcr_a582a424cb61c678_62_double_double", reinterpret_cast<void *>(&nl_gcr_a582a424cb61c678_62_double_double)}, // NOLINT
// tank
- {"nl_gcr_a63d1344e34bef4b_36_double_double", reinterpret_cast<void *>(&nl_gcr_a63d1344e34bef4b_36_double_double)},
+ {"nl_gcr_a63d1344e34bef4b_36_double_double", reinterpret_cast<void *>(&nl_gcr_a63d1344e34bef4b_36_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_a6b734322b3ea924_22_double_double", reinterpret_cast<void *>(&nl_gcr_a6b734322b3ea924_22_double_double)},
+ {"nl_gcr_a6b734322b3ea924_22_double_double", reinterpret_cast<void *>(&nl_gcr_a6b734322b3ea924_22_double_double)}, // NOLINT
// armora
- {"nl_gcr_a6cfda6668b153c2_22_double_double", reinterpret_cast<void *>(&nl_gcr_a6cfda6668b153c2_22_double_double)},
+ {"nl_gcr_a6cfda6668b153c2_22_double_double", reinterpret_cast<void *>(&nl_gcr_a6cfda6668b153c2_22_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_a6f74be7f61e6db2_29_double_double", reinterpret_cast<void *>(&nl_gcr_a6f74be7f61e6db2_29_double_double)},
+ {"nl_gcr_a6f74be7f61e6db2_29_double_double", reinterpret_cast<void *>(&nl_gcr_a6f74be7f61e6db2_29_double_double)}, // NOLINT
// carpolo
- {"nl_gcr_a8f1d076330f06b7_34_double_double", reinterpret_cast<void *>(&nl_gcr_a8f1d076330f06b7_34_double_double)},
+ {"nl_gcr_a8f1d076330f06b7_34_double_double", reinterpret_cast<void *>(&nl_gcr_a8f1d076330f06b7_34_double_double)}, // NOLINT
// breakout
- {"nl_gcr_a971eeb2ef76f75f_13_double_double", reinterpret_cast<void *>(&nl_gcr_a971eeb2ef76f75f_13_double_double)},
+ {"nl_gcr_a971eeb2ef76f75f_13_double_double", reinterpret_cast<void *>(&nl_gcr_a971eeb2ef76f75f_13_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_aa07266ef5d420d1_11_double_double", reinterpret_cast<void *>(&nl_gcr_aa07266ef5d420d1_11_double_double)},
+ {"nl_gcr_aa07266ef5d420d1_11_double_double", reinterpret_cast<void *>(&nl_gcr_aa07266ef5d420d1_11_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_aa68b74ffdea9bd8_47_double_double", reinterpret_cast<void *>(&nl_gcr_aa68b74ffdea9bd8_47_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_ab8d1ff6aa7499d8_119_double_double", reinterpret_cast<void *>(&nl_gcr_ab8d1ff6aa7499d8_119_double_double)}, // NOLINT
// 280zzzap
- {"nl_gcr_ab9144d965a37e4_113_double_double", reinterpret_cast<void *>(&nl_gcr_ab9144d965a37e4_113_double_double)},
+ {"nl_gcr_ab9144d965a37e4_113_double_double", reinterpret_cast<void *>(&nl_gcr_ab9144d965a37e4_113_double_double)}, // NOLINT
// sspeedr
- {"nl_gcr_ac1e401ddf971e15_10_double_double", reinterpret_cast<void *>(&nl_gcr_ac1e401ddf971e15_10_double_double)},
+ {"nl_gcr_ac1e401ddf971e15_10_double_double", reinterpret_cast<void *>(&nl_gcr_ac1e401ddf971e15_10_double_double)}, // NOLINT
// starfire
- {"nl_gcr_aceb6035dfb557c9_12_double_double", reinterpret_cast<void *>(&nl_gcr_aceb6035dfb557c9_12_double_double)},
+ {"nl_gcr_aceb6035dfb557c9_12_double_double", reinterpret_cast<void *>(&nl_gcr_aceb6035dfb557c9_12_double_double)}, // NOLINT
// sundance
- {"nl_gcr_ad6dba01ff2425c3_12_double_double", reinterpret_cast<void *>(&nl_gcr_ad6dba01ff2425c3_12_double_double)},
+ {"nl_gcr_ad6dba01ff2425c3_12_double_double", reinterpret_cast<void *>(&nl_gcr_ad6dba01ff2425c3_12_double_double)}, // NOLINT
// rebound
- {"nl_gcr_ae15f7f8a55fc96_7_double_double", reinterpret_cast<void *>(&nl_gcr_ae15f7f8a55fc96_7_double_double)},
+ {"nl_gcr_ae15f7f8a55fc96_7_double_double", reinterpret_cast<void *>(&nl_gcr_ae15f7f8a55fc96_7_double_double)}, // NOLINT
// armora
- {"nl_gcr_afcde432efdafb81_56_double_double", reinterpret_cast<void *>(&nl_gcr_afcde432efdafb81_56_double_double)},
+ {"nl_gcr_afcde432efdafb81_56_double_double", reinterpret_cast<void *>(&nl_gcr_afcde432efdafb81_56_double_double)}, // NOLINT
// mario
- {"nl_gcr_afce66fb47d3c5f3_62_double_double", reinterpret_cast<void *>(&nl_gcr_afce66fb47d3c5f3_62_double_double)},
+ {"nl_gcr_afce66fb47d3c5f3_62_double_double", reinterpret_cast<void *>(&nl_gcr_afce66fb47d3c5f3_62_double_double)}, // NOLINT
// spacewar
- {"nl_gcr_b09deef9a25aecaf_24_double_double", reinterpret_cast<void *>(&nl_gcr_b09deef9a25aecaf_24_double_double)},
+ {"nl_gcr_b09deef9a25aecaf_24_double_double", reinterpret_cast<void *>(&nl_gcr_b09deef9a25aecaf_24_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_b1db23287df1da54_175_double_double", reinterpret_cast<void *>(&nl_gcr_b1db23287df1da54_175_double_double)},
+ {"nl_gcr_b1db23287df1da54_175_double_double", reinterpret_cast<void *>(&nl_gcr_b1db23287df1da54_175_double_double)}, // NOLINT
// segaspeech
- {"nl_gcr_b22769fbf3159a8d_21_double_double", reinterpret_cast<void *>(&nl_gcr_b22769fbf3159a8d_21_double_double)},
+ {"nl_gcr_b22769fbf3159a8d_21_double_double", reinterpret_cast<void *>(&nl_gcr_b22769fbf3159a8d_21_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_b66df357763b1dce_97_double_double", reinterpret_cast<void *>(&nl_gcr_b66df357763b1dce_97_double_double)}, // NOLINT
// breakout
- {"nl_gcr_b66ff415b228d5f8_10_double_double", reinterpret_cast<void *>(&nl_gcr_b66ff415b228d5f8_10_double_double)},
+ {"nl_gcr_b66ff415b228d5f8_10_double_double", reinterpret_cast<void *>(&nl_gcr_b66ff415b228d5f8_10_double_double)}, // NOLINT
// starcas
- {"nl_gcr_b7344e05aac90017_65_double_double", reinterpret_cast<void *>(&nl_gcr_b7344e05aac90017_65_double_double)},
+ {"nl_gcr_b7344e05aac90017_65_double_double", reinterpret_cast<void *>(&nl_gcr_b7344e05aac90017_65_double_double)}, // NOLINT
// starfire
- {"nl_gcr_b75e0baeb501e907_23_double_double", reinterpret_cast<void *>(&nl_gcr_b75e0baeb501e907_23_double_double)},
+ {"nl_gcr_b75e0baeb501e907_23_double_double", reinterpret_cast<void *>(&nl_gcr_b75e0baeb501e907_23_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_b7b209d222c0a9a6_91_double_double", reinterpret_cast<void *>(&nl_gcr_b7b209d222c0a9a6_91_double_double)},
+ {"nl_gcr_b7b209d222c0a9a6_91_double_double", reinterpret_cast<void *>(&nl_gcr_b7b209d222c0a9a6_91_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_b8d6d148a50bdb8f_55_double_double", reinterpret_cast<void *>(&nl_gcr_b8d6d148a50bdb8f_55_double_double)},
+ {"nl_gcr_b8d6d148a50bdb8f_55_double_double", reinterpret_cast<void *>(&nl_gcr_b8d6d148a50bdb8f_55_double_double)}, // NOLINT
// 280zzzap
- {"nl_gcr_bb501e6a23177009_57_double_double", reinterpret_cast<void *>(&nl_gcr_bb501e6a23177009_57_double_double)},
+ {"nl_gcr_bb501e6a23177009_57_double_double", reinterpret_cast<void *>(&nl_gcr_bb501e6a23177009_57_double_double)}, // NOLINT
// elim
- {"nl_gcr_bb56fa5325163fc3_15_double_double", reinterpret_cast<void *>(&nl_gcr_bb56fa5325163fc3_15_double_double)},
+ {"nl_gcr_bb56fa5325163fc3_15_double_double", reinterpret_cast<void *>(&nl_gcr_bb56fa5325163fc3_15_double_double)}, // NOLINT
// starfire
- {"nl_gcr_bd1514d7defd4062_9_double_double", reinterpret_cast<void *>(&nl_gcr_bd1514d7defd4062_9_double_double)},
+ {"nl_gcr_bd1514d7defd4062_9_double_double", reinterpret_cast<void *>(&nl_gcr_bd1514d7defd4062_9_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_be7c805100c522fd_59_double_double", reinterpret_cast<void *>(&nl_gcr_be7c805100c522fd_59_double_double)},
+ {"nl_gcr_be7c805100c522fd_59_double_double", reinterpret_cast<void *>(&nl_gcr_be7c805100c522fd_59_double_double)}, // NOLINT
// elim
- {"nl_gcr_be831e5faa508573_150_double_double", reinterpret_cast<void *>(&nl_gcr_be831e5faa508573_150_double_double)},
+ {"nl_gcr_be831e5faa508573_150_double_double", reinterpret_cast<void *>(&nl_gcr_be831e5faa508573_150_double_double)}, // NOLINT
// warrior
- {"nl_gcr_bff07f8d339f7cc4_89_double_double", reinterpret_cast<void *>(&nl_gcr_bff07f8d339f7cc4_89_double_double)},
+ {"nl_gcr_bff07f8d339f7cc4_89_double_double", reinterpret_cast<void *>(&nl_gcr_bff07f8d339f7cc4_89_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_c05df522276e65fd_134_double_double", reinterpret_cast<void *>(&nl_gcr_c05df522276e65fd_134_double_double)}, // NOLINT
// fireone
- {"nl_gcr_c1d22fe6e895255d_79_double_double", reinterpret_cast<void *>(&nl_gcr_c1d22fe6e895255d_79_double_double)},
+ {"nl_gcr_c1d22fe6e895255d_79_double_double", reinterpret_cast<void *>(&nl_gcr_c1d22fe6e895255d_79_double_double)}, // NOLINT
// starcrus
- {"nl_gcr_c2e616f3de30f15b_31_double_double", reinterpret_cast<void *>(&nl_gcr_c2e616f3de30f15b_31_double_double)},
+ {"nl_gcr_c2e616f3de30f15b_31_double_double", reinterpret_cast<void *>(&nl_gcr_c2e616f3de30f15b_31_double_double)}, // NOLINT
// tailg
- {"nl_gcr_c4cec7aed23b7b94_23_double_double", reinterpret_cast<void *>(&nl_gcr_c4cec7aed23b7b94_23_double_double)},
+ {"nl_gcr_c4cec7aed23b7b94_23_double_double", reinterpret_cast<void *>(&nl_gcr_c4cec7aed23b7b94_23_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_c5b523ed6a9677e6_21_double_double", reinterpret_cast<void *>(&nl_gcr_c5b523ed6a9677e6_21_double_double)}, // NOLINT
// segausb
- {"nl_gcr_c61e08cf5e35918_84_double_double", reinterpret_cast<void *>(&nl_gcr_c61e08cf5e35918_84_double_double)},
+ {"nl_gcr_c61e08cf5e35918_84_double_double", reinterpret_cast<void *>(&nl_gcr_c61e08cf5e35918_84_double_double)}, // NOLINT
// popeye
- {"nl_gcr_c6f25bb06e161d1c_50_double_double", reinterpret_cast<void *>(&nl_gcr_c6f25bb06e161d1c_50_double_double)},
+ {"nl_gcr_c6f25bb06e161d1c_50_double_double", reinterpret_cast<void *>(&nl_gcr_c6f25bb06e161d1c_50_double_double)}, // NOLINT
// flyball
- {"nl_gcr_c74b1a65978d7121_7_double_double", reinterpret_cast<void *>(&nl_gcr_c74b1a65978d7121_7_double_double)},
+ {"nl_gcr_c74b1a65978d7121_7_double_double", reinterpret_cast<void *>(&nl_gcr_c74b1a65978d7121_7_double_double)}, // NOLINT
+// headon
+ {"nl_gcr_c90daff82be2d052_350_double_double", reinterpret_cast<void *>(&nl_gcr_c90daff82be2d052_350_double_double)}, // NOLINT
// stuntcyc
- {"nl_gcr_c924fe5960b1479e_20_double_double", reinterpret_cast<void *>(&nl_gcr_c924fe5960b1479e_20_double_double)},
+ {"nl_gcr_c924fe5960b1479e_20_double_double", reinterpret_cast<void *>(&nl_gcr_c924fe5960b1479e_20_double_double)}, // NOLINT
// dpatrol
- {"nl_gcr_ca68d70bd8f2f62e_22_double_double", reinterpret_cast<void *>(&nl_gcr_ca68d70bd8f2f62e_22_double_double)},
+ {"nl_gcr_ca68d70bd8f2f62e_22_double_double", reinterpret_cast<void *>(&nl_gcr_ca68d70bd8f2f62e_22_double_double)}, // NOLINT
// breakout
- {"nl_gcr_cb2aae3366e0ac1c_7_double_double", reinterpret_cast<void *>(&nl_gcr_cb2aae3366e0ac1c_7_double_double)},
+ {"nl_gcr_cb2aae3366e0ac1c_7_double_double", reinterpret_cast<void *>(&nl_gcr_cb2aae3366e0ac1c_7_double_double)}, // NOLINT
// barrier
- {"nl_gcr_cc913f9c3f9293e7_19_double_double", reinterpret_cast<void *>(&nl_gcr_cc913f9c3f9293e7_19_double_double)},
+ {"nl_gcr_cc913f9c3f9293e7_19_double_double", reinterpret_cast<void *>(&nl_gcr_cc913f9c3f9293e7_19_double_double)}, // NOLINT
// fireone
- {"nl_gcr_cca3d1a4219e2ec0_153_double_double", reinterpret_cast<void *>(&nl_gcr_cca3d1a4219e2ec0_153_double_double)},
+ {"nl_gcr_cca3d1a4219e2ec0_153_double_double", reinterpret_cast<void *>(&nl_gcr_cca3d1a4219e2ec0_153_double_double)}, // NOLINT
// 1942
- {"nl_gcr_ce766957cb26ff3e_90_double_double", reinterpret_cast<void *>(&nl_gcr_ce766957cb26ff3e_90_double_double)},
+ {"nl_gcr_ce766957cb26ff3e_90_double_double", reinterpret_cast<void *>(&nl_gcr_ce766957cb26ff3e_90_double_double)}, // NOLINT
// astrob
- {"nl_gcr_cf1018e7ed626623_43_double_double", reinterpret_cast<void *>(&nl_gcr_cf1018e7ed626623_43_double_double)},
+ {"nl_gcr_cf1018e7ed626623_43_double_double", reinterpret_cast<void *>(&nl_gcr_cf1018e7ed626623_43_double_double)}, // NOLINT
// zac1b11142
- {"nl_gcr_cfd3bbf5fbba4765_71_double_double", reinterpret_cast<void *>(&nl_gcr_cfd3bbf5fbba4765_71_double_double)},
+ {"nl_gcr_cfd3bbf5fbba4765_71_double_double", reinterpret_cast<void *>(&nl_gcr_cfd3bbf5fbba4765_71_double_double)}, // NOLINT
// gunfight
- {"nl_gcr_d05b3dbe370c7904_14_double_double", reinterpret_cast<void *>(&nl_gcr_d05b3dbe370c7904_14_double_double)},
+ {"nl_gcr_d05b3dbe370c7904_14_double_double", reinterpret_cast<void *>(&nl_gcr_d05b3dbe370c7904_14_double_double)}, // NOLINT
// barrier
- {"nl_gcr_d06bd7ddbfd17b5e_15_double_double", reinterpret_cast<void *>(&nl_gcr_d06bd7ddbfd17b5e_15_double_double)},
+ {"nl_gcr_d06bd7ddbfd17b5e_15_double_double", reinterpret_cast<void *>(&nl_gcr_d06bd7ddbfd17b5e_15_double_double)}, // NOLINT
// elim
- {"nl_gcr_d13f9c6838af6aeb_13_double_double", reinterpret_cast<void *>(&nl_gcr_d13f9c6838af6aeb_13_double_double)},
+ {"nl_gcr_d13f9c6838af6aeb_13_double_double", reinterpret_cast<void *>(&nl_gcr_d13f9c6838af6aeb_13_double_double)}, // NOLINT
// elim
- {"nl_gcr_d190a0e3b8e1f4a7_7_double_double", reinterpret_cast<void *>(&nl_gcr_d190a0e3b8e1f4a7_7_double_double)},
+ {"nl_gcr_d190a0e3b8e1f4a7_7_double_double", reinterpret_cast<void *>(&nl_gcr_d190a0e3b8e1f4a7_7_double_double)}, // NOLINT
// elim
- {"nl_gcr_d224211d1af6811d_12_double_double", reinterpret_cast<void *>(&nl_gcr_d224211d1af6811d_12_double_double)},
+ {"nl_gcr_d224211d1af6811d_12_double_double", reinterpret_cast<void *>(&nl_gcr_d224211d1af6811d_12_double_double)}, // NOLINT
// armora
- {"nl_gcr_d27a39bc93616187_45_double_double", reinterpret_cast<void *>(&nl_gcr_d27a39bc93616187_45_double_double)},
+ {"nl_gcr_d27a39bc93616187_45_double_double", reinterpret_cast<void *>(&nl_gcr_d27a39bc93616187_45_double_double)}, // NOLINT
// elim
- {"nl_gcr_d2ea3f267b959e8b_20_double_double", reinterpret_cast<void *>(&nl_gcr_d2ea3f267b959e8b_20_double_double)},
+ {"nl_gcr_d2ea3f267b959e8b_20_double_double", reinterpret_cast<void *>(&nl_gcr_d2ea3f267b959e8b_20_double_double)}, // NOLINT
// starfire
- {"nl_gcr_d32effa2b0ea54a1_438_double_double", reinterpret_cast<void *>(&nl_gcr_d32effa2b0ea54a1_438_double_double)},
+ {"nl_gcr_d32effa2b0ea54a1_438_double_double", reinterpret_cast<void *>(&nl_gcr_d32effa2b0ea54a1_438_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_d4c34516ff6aa139_46_double_double", reinterpret_cast<void *>(&nl_gcr_d4c34516ff6aa139_46_double_double)},
+ {"nl_gcr_d4c34516ff6aa139_46_double_double", reinterpret_cast<void *>(&nl_gcr_d4c34516ff6aa139_46_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_d5e1c37cfa2d2853_30_double_double", reinterpret_cast<void *>(&nl_gcr_d5e1c37cfa2d2853_30_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_d7d45dc58b08cab9_10_double_double", reinterpret_cast<void *>(&nl_gcr_d7d45dc58b08cab9_10_double_double)},
+ {"nl_gcr_d7d45dc58b08cab9_10_double_double", reinterpret_cast<void *>(&nl_gcr_d7d45dc58b08cab9_10_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_d8c511d38cef5f6f_34_double_double", reinterpret_cast<void *>(&nl_gcr_d8c511d38cef5f6f_34_double_double)},
+ {"nl_gcr_d8c511d38cef5f6f_34_double_double", reinterpret_cast<void *>(&nl_gcr_d8c511d38cef5f6f_34_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_d97fd7ecc1ebba3d_19_double_double", reinterpret_cast<void *>(&nl_gcr_d97fd7ecc1ebba3d_19_double_double)}, // NOLINT
// warrior
- {"nl_gcr_da598f43329e823_27_double_double", reinterpret_cast<void *>(&nl_gcr_da598f43329e823_27_double_double)},
+ {"nl_gcr_da598f43329e823_27_double_double", reinterpret_cast<void *>(&nl_gcr_da598f43329e823_27_double_double)}, // NOLINT
// pongf
- {"nl_gcr_dbafc5ddaf7a08f8_35_double_double", reinterpret_cast<void *>(&nl_gcr_dbafc5ddaf7a08f8_35_double_double)},
+ {"nl_gcr_dbafc5ddaf7a08f8_35_double_double", reinterpret_cast<void *>(&nl_gcr_dbafc5ddaf7a08f8_35_double_double)}, // NOLINT
// fireone
- {"nl_gcr_dcbecbc127c5868f_36_double_double", reinterpret_cast<void *>(&nl_gcr_dcbecbc127c5868f_36_double_double)},
+ {"nl_gcr_dcbecbc127c5868f_36_double_double", reinterpret_cast<void *>(&nl_gcr_dcbecbc127c5868f_36_double_double)}, // NOLINT
// sundance
- {"nl_gcr_e02a162cb515a958_100_double_double", reinterpret_cast<void *>(&nl_gcr_e02a162cb515a958_100_double_double)},
+ {"nl_gcr_e02a162cb515a958_100_double_double", reinterpret_cast<void *>(&nl_gcr_e02a162cb515a958_100_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_e03f0bc5ac056326_20_double_double", reinterpret_cast<void *>(&nl_gcr_e03f0bc5ac056326_20_double_double)}, // NOLINT
// speedfrk
- {"nl_gcr_e07b5b086812756c_7_double_double", reinterpret_cast<void *>(&nl_gcr_e07b5b086812756c_7_double_double)},
+ {"nl_gcr_e07b5b086812756c_7_double_double", reinterpret_cast<void *>(&nl_gcr_e07b5b086812756c_7_double_double)}, // NOLINT
// solarq
- {"nl_gcr_e081f90c2e0313f6_45_double_double", reinterpret_cast<void *>(&nl_gcr_e081f90c2e0313f6_45_double_double)},
+ {"nl_gcr_e081f90c2e0313f6_45_double_double", reinterpret_cast<void *>(&nl_gcr_e081f90c2e0313f6_45_double_double)}, // NOLINT
// spacewar
- {"nl_gcr_e0b492db40bba291_20_double_double", reinterpret_cast<void *>(&nl_gcr_e0b492db40bba291_20_double_double)},
+ {"nl_gcr_e0b492db40bba291_20_double_double", reinterpret_cast<void *>(&nl_gcr_e0b492db40bba291_20_double_double)}, // NOLINT
// flyball
- {"nl_gcr_e15d9316d59cdad9_7_double_double", reinterpret_cast<void *>(&nl_gcr_e15d9316d59cdad9_7_double_double)},
+ {"nl_gcr_e15d9316d59cdad9_7_double_double", reinterpret_cast<void *>(&nl_gcr_e15d9316d59cdad9_7_double_double)}, // NOLINT
// speedfrk
- {"nl_gcr_e4f2ffbf201a3d0c_37_double_double", reinterpret_cast<void *>(&nl_gcr_e4f2ffbf201a3d0c_37_double_double)},
+ {"nl_gcr_e4f2ffbf201a3d0c_37_double_double", reinterpret_cast<void *>(&nl_gcr_e4f2ffbf201a3d0c_37_double_double)}, // NOLINT
// pongf
- {"nl_gcr_e51b463cd890ef6d_7_double_double", reinterpret_cast<void *>(&nl_gcr_e51b463cd890ef6d_7_double_double)},
+ {"nl_gcr_e51b463cd890ef6d_7_double_double", reinterpret_cast<void *>(&nl_gcr_e51b463cd890ef6d_7_double_double)}, // NOLINT
// sundance
- {"nl_gcr_e5b7711fac1ea80c_8_double_double", reinterpret_cast<void *>(&nl_gcr_e5b7711fac1ea80c_8_double_double)},
+ {"nl_gcr_e5b7711fac1ea80c_8_double_double", reinterpret_cast<void *>(&nl_gcr_e5b7711fac1ea80c_8_double_double)}, // NOLINT
// ripoff
- {"nl_gcr_e60314070a75e121_20_double_double", reinterpret_cast<void *>(&nl_gcr_e60314070a75e121_20_double_double)},
+ {"nl_gcr_e60314070a75e121_20_double_double", reinterpret_cast<void *>(&nl_gcr_e60314070a75e121_20_double_double)}, // NOLINT
// cheekyms
- {"nl_gcr_e75302e17c866419_150_double_double", reinterpret_cast<void *>(&nl_gcr_e75302e17c866419_150_double_double)},
+ {"nl_gcr_e75302e17c866419_150_double_double", reinterpret_cast<void *>(&nl_gcr_e75302e17c866419_150_double_double)}, // NOLINT
// elim
- {"nl_gcr_e76692c10e79997e_36_double_double", reinterpret_cast<void *>(&nl_gcr_e76692c10e79997e_36_double_double)},
+ {"nl_gcr_e76692c10e79997e_36_double_double", reinterpret_cast<void *>(&nl_gcr_e76692c10e79997e_36_double_double)}, // NOLINT
// fireone
- {"nl_gcr_e7fb484f621b3ab9_7_double_double", reinterpret_cast<void *>(&nl_gcr_e7fb484f621b3ab9_7_double_double)},
+ {"nl_gcr_e7fb484f621b3ab9_7_double_double", reinterpret_cast<void *>(&nl_gcr_e7fb484f621b3ab9_7_double_double)}, // NOLINT
// elim
- {"nl_gcr_e8aeb165b69427ec_18_double_double", reinterpret_cast<void *>(&nl_gcr_e8aeb165b69427ec_18_double_double)},
+ {"nl_gcr_e8aeb165b69427ec_18_double_double", reinterpret_cast<void *>(&nl_gcr_e8aeb165b69427ec_18_double_double)}, // NOLINT
// spacewar
- {"nl_gcr_e9e8211f43d8f4b3_22_double_double", reinterpret_cast<void *>(&nl_gcr_e9e8211f43d8f4b3_22_double_double)},
+ {"nl_gcr_e9e8211f43d8f4b3_22_double_double", reinterpret_cast<void *>(&nl_gcr_e9e8211f43d8f4b3_22_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_ea2b6e3a05e6ef0b_23_double_double", reinterpret_cast<void *>(&nl_gcr_ea2b6e3a05e6ef0b_23_double_double)},
+ {"nl_gcr_ea2b6e3a05e6ef0b_23_double_double", reinterpret_cast<void *>(&nl_gcr_ea2b6e3a05e6ef0b_23_double_double)}, // NOLINT
// starcas
- {"nl_gcr_ec4f6d2dad5961b9_64_double_double", reinterpret_cast<void *>(&nl_gcr_ec4f6d2dad5961b9_64_double_double)},
+ {"nl_gcr_ec4f6d2dad5961b9_64_double_double", reinterpret_cast<void *>(&nl_gcr_ec4f6d2dad5961b9_64_double_double)}, // NOLINT
// barrier
- {"nl_gcr_ecf17036ce1c07cf_10_double_double", reinterpret_cast<void *>(&nl_gcr_ecf17036ce1c07cf_10_double_double)},
+ {"nl_gcr_ecf17036ce1c07cf_10_double_double", reinterpret_cast<void *>(&nl_gcr_ecf17036ce1c07cf_10_double_double)}, // NOLINT
// armora
- {"nl_gcr_ee2cacaa15d32491_67_double_double", reinterpret_cast<void *>(&nl_gcr_ee2cacaa15d32491_67_double_double)},
+ {"nl_gcr_ee2cacaa15d32491_67_double_double", reinterpret_cast<void *>(&nl_gcr_ee2cacaa15d32491_67_double_double)}, // NOLINT
// astrob
- {"nl_gcr_ee61dcaa355fc625_285_double_double", reinterpret_cast<void *>(&nl_gcr_ee61dcaa355fc625_285_double_double)},
+ {"nl_gcr_ee61dcaa355fc625_285_double_double", reinterpret_cast<void *>(&nl_gcr_ee61dcaa355fc625_285_double_double)}, // NOLINT
// starcrus
- {"nl_gcr_ef2f49641f433a74_94_double_double", reinterpret_cast<void *>(&nl_gcr_ef2f49641f433a74_94_double_double)},
-// astrob
- {"nl_gcr_efd052e6829c33e_9_double_double", reinterpret_cast<void *>(&nl_gcr_efd052e6829c33e_9_double_double)},
+ {"nl_gcr_ef2f49641f433a74_94_double_double", reinterpret_cast<void *>(&nl_gcr_ef2f49641f433a74_94_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_f153eda877c6e8ed_30_double_double", reinterpret_cast<void *>(&nl_gcr_f153eda877c6e8ed_30_double_double)}, // NOLINT
+// frogs
+ {"nl_gcr_f2de20e827252602_53_double_double", reinterpret_cast<void *>(&nl_gcr_f2de20e827252602_53_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_f365c3863b050e35_45_double_double", reinterpret_cast<void *>(&nl_gcr_f365c3863b050e35_45_double_double)},
+ {"nl_gcr_f365c3863b050e35_45_double_double", reinterpret_cast<void *>(&nl_gcr_f365c3863b050e35_45_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_f3c9a6d53371d709_227_double_double", reinterpret_cast<void *>(&nl_gcr_f3c9a6d53371d709_227_double_double)},
+ {"nl_gcr_f3c9a6d53371d709_227_double_double", reinterpret_cast<void *>(&nl_gcr_f3c9a6d53371d709_227_double_double)}, // NOLINT
// barrier
- {"nl_gcr_f425d4008ae1d2c6_13_double_double", reinterpret_cast<void *>(&nl_gcr_f425d4008ae1d2c6_13_double_double)},
+ {"nl_gcr_f425d4008ae1d2c6_13_double_double", reinterpret_cast<void *>(&nl_gcr_f425d4008ae1d2c6_13_double_double)}, // NOLINT
// boxingb
- {"nl_gcr_f43cf2a28a5a5561_23_double_double", reinterpret_cast<void *>(&nl_gcr_f43cf2a28a5a5561_23_double_double)},
+ {"nl_gcr_f43cf2a28a5a5561_23_double_double", reinterpret_cast<void *>(&nl_gcr_f43cf2a28a5a5561_23_double_double)}, // NOLINT
// spacfury
- {"nl_gcr_f4da1503eabe16cf_16_double_double", reinterpret_cast<void *>(&nl_gcr_f4da1503eabe16cf_16_double_double)},
+ {"nl_gcr_f4da1503eabe16cf_16_double_double", reinterpret_cast<void *>(&nl_gcr_f4da1503eabe16cf_16_double_double)}, // NOLINT
// elim
- {"nl_gcr_f4f4e2ee05cb584e_13_double_double", reinterpret_cast<void *>(&nl_gcr_f4f4e2ee05cb584e_13_double_double)},
+ {"nl_gcr_f4f4e2ee05cb584e_13_double_double", reinterpret_cast<void *>(&nl_gcr_f4f4e2ee05cb584e_13_double_double)}, // NOLINT
// konami2x
- {"nl_gcr_f6900d3f36a91049_85_double_double", reinterpret_cast<void *>(&nl_gcr_f6900d3f36a91049_85_double_double)},
+ {"nl_gcr_f6900d3f36a91049_85_double_double", reinterpret_cast<void *>(&nl_gcr_f6900d3f36a91049_85_double_double)}, // NOLINT
// breakout
- {"nl_gcr_f7dc4f87b5a8ba93_7_double_double", reinterpret_cast<void *>(&nl_gcr_f7dc4f87b5a8ba93_7_double_double)},
+ {"nl_gcr_f7dc4f87b5a8ba93_7_double_double", reinterpret_cast<void *>(&nl_gcr_f7dc4f87b5a8ba93_7_double_double)}, // NOLINT
// fireone
- {"nl_gcr_f8f6a951fd1af6bc_7_double_double", reinterpret_cast<void *>(&nl_gcr_f8f6a951fd1af6bc_7_double_double)},
+ {"nl_gcr_f8f6a951fd1af6bc_7_double_double", reinterpret_cast<void *>(&nl_gcr_f8f6a951fd1af6bc_7_double_double)}, // NOLINT
+// brdrline
+ {"nl_gcr_f99b1245e708ec85_83_double_double", reinterpret_cast<void *>(&nl_gcr_f99b1245e708ec85_83_double_double)}, // NOLINT
// zektor
- {"nl_gcr_fbff020f5f5d5a5_144_double_double", reinterpret_cast<void *>(&nl_gcr_fbff020f5f5d5a5_144_double_double)},
+ {"nl_gcr_fbff020f5f5d5a5_144_double_double", reinterpret_cast<void *>(&nl_gcr_fbff020f5f5d5a5_144_double_double)}, // NOLINT
// kidniki
- {"nl_gcr_fc02559fdbfb0e10_67_double_double", reinterpret_cast<void *>(&nl_gcr_fc02559fdbfb0e10_67_double_double)},
+ {"nl_gcr_fc02559fdbfb0e10_67_double_double", reinterpret_cast<void *>(&nl_gcr_fc02559fdbfb0e10_67_double_double)}, // NOLINT
// 280zzzap
- {"nl_gcr_fc9971724787b82b_149_double_double", reinterpret_cast<void *>(&nl_gcr_fc9971724787b82b_149_double_double)},
+ {"nl_gcr_fc9971724787b82b_149_double_double", reinterpret_cast<void *>(&nl_gcr_fc9971724787b82b_149_double_double)}, // NOLINT
// elim
- {"nl_gcr_fcce97532ad2f49d_18_double_double", reinterpret_cast<void *>(&nl_gcr_fcce97532ad2f49d_18_double_double)},
+ {"nl_gcr_fcce97532ad2f49d_18_double_double", reinterpret_cast<void *>(&nl_gcr_fcce97532ad2f49d_18_double_double)}, // NOLINT
// fireone
- {"nl_gcr_fd2796828f1ebd00_36_double_double", reinterpret_cast<void *>(&nl_gcr_fd2796828f1ebd00_36_double_double)},
+ {"nl_gcr_fd2796828f1ebd00_36_double_double", reinterpret_cast<void *>(&nl_gcr_fd2796828f1ebd00_36_double_double)}, // NOLINT
// starfire
- {"nl_gcr_feae15b80dd73620_7_double_double", reinterpret_cast<void *>(&nl_gcr_feae15b80dd73620_7_double_double)},
+ {"nl_gcr_feae15b80dd73620_7_double_double", reinterpret_cast<void *>(&nl_gcr_feae15b80dd73620_7_double_double)}, // NOLINT
#endif
{"", nullptr}
diff --git a/src/lib/netlist/macro/modules/nlmod_ICL8038_DIP.cpp b/src/lib/netlist/macro/modules/nlmod_icl8038_dip.cpp
index 05a4d300099..05a4d300099 100644..100755
--- a/src/lib/netlist/macro/modules/nlmod_ICL8038_DIP.cpp
+++ b/src/lib/netlist/macro/modules/nlmod_icl8038_dip.cpp
diff --git a/src/lib/netlist/macro/modules/nlmod_NE556_DIP.cpp b/src/lib/netlist/macro/modules/nlmod_ne556_dip.cpp
index 7f278a18b6d..7f278a18b6d 100644..100755
--- a/src/lib/netlist/macro/modules/nlmod_NE556_DIP.cpp
+++ b/src/lib/netlist/macro/modules/nlmod_ne556_dip.cpp
diff --git a/src/lib/netlist/macro/modules/nlmod_RTEST.cpp b/src/lib/netlist/macro/modules/nlmod_rtest.cpp
index c2ad129c6e3..c2ad129c6e3 100644..100755
--- a/src/lib/netlist/macro/modules/nlmod_RTEST.cpp
+++ b/src/lib/netlist/macro/modules/nlmod_rtest.cpp
diff --git a/src/lib/netlist/macro/nlm_cd4xxx_lib.cpp b/src/lib/netlist/macro/nlm_cd4xxx_lib.cpp
index 13c80aa391b..35f5cae6374 100644
--- a/src/lib/netlist/macro/nlm_cd4xxx_lib.cpp
+++ b/src/lib/netlist/macro/nlm_cd4xxx_lib.cpp
@@ -268,6 +268,251 @@ static NETLIST_START(CD4024_DIP)
/* +--------------+ */)
NETLIST_END()
+//- Identifier: CD4029_DIP
+//- Title: CD4029BM/CD4029BC Presettable Binary/Decade Up/Down Counter
+//- Pinalias: PE,Q4,J4,J1,CI,Q1,CO,VSS,BD,UD,Q2,J2,J3,Q3,CLK,VDD
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- Limitations:
+//- Voltage-dependent timing is not implemented.
+//- FunctionTable:
+//- http://pdf.datasheetcatalog.com/datasheets/166/108968_DS.pdf
+//- See nld_4029.cpp for tables explaining the counting order for all states
+//-
+//- Counter Sequences:
+//-
+//- B/D high (Binary), U/D high (Up)
+//- +-------++----+----+----+----+----++-------+
+//- | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+//- +=======++====+====+====+====+====++=======+
+//- | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+//- | 1 || 0 | 0 | 0 | 1 | 1 || 2 |
+//- | 2 || 0 | 0 | 1 | 0 | 1 || 3 |
+//- | 3 || 0 | 0 | 1 | 1 | 1 || 4 |
+//- | 4 || 0 | 1 | 0 | 0 | 1 || 5 |
+//- | 5 || 0 | 1 | 0 | 1 | 1 || 6 |
+//- | 6 || 0 | 1 | 1 | 0 | 1 || 7 |
+//- | 7 || 0 | 1 | 1 | 1 | 1 || 8 |
+//- | 8 || 1 | 0 | 0 | 0 | 1 || 9 |
+//- | 9 || 1 | 0 | 0 | 1 | 1 || A |
+//- | A || 1 | 0 | 1 | 0 | 1 || B |
+//- | B || 1 | 0 | 1 | 1 | 1 || C |
+//- | C || 1 | 1 | 0 | 0 | 1 || D |
+//- | D || 1 | 1 | 0 | 1 | 1 || E |
+//- | E || 1 | 1 | 1 | 0 | 1 || F |
+//- | F || 1 | 1 | 1 | 1 |0|CI|| 0 |
+//- | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+//- +-------++----+----+----+----+----++-------+
+//-
+//- B/D high (Binary), U/D low (Down)
+//- +-------++----+----+----+----+----++-------+
+//- | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+//- +=======++====+====+====+====+====++=======+
+//- | F || 1 | 1 | 1 | 1 | 1 || E |
+//- | E || 1 | 1 | 1 | 0 | 1 || D |
+//- | D || 1 | 1 | 0 | 1 | 1 || C |
+//- | C || 1 | 1 | 0 | 0 | 1 || B |
+//- | B || 1 | 0 | 1 | 1 | 1 || A |
+//- | A || 1 | 0 | 1 | 0 | 1 || 9 |
+//- | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+//- | 8 || 1 | 0 | 0 | 0 | 1 || 7 |
+//- | 7 || 0 | 1 | 1 | 1 | 1 || 6 |
+//- | 6 || 0 | 1 | 1 | 0 | 1 || 5 |
+//- | 5 || 0 | 1 | 0 | 1 | 1 || 4 |
+//- | 4 || 0 | 1 | 0 | 0 | 1 || 3 |
+//- | 3 || 0 | 0 | 1 | 1 | 1 || 2 |
+//- | 2 || 0 | 0 | 1 | 0 | 1 || 1 |
+//- | 1 || 0 | 0 | 0 | 1 | 1 || 0 |
+//- | 0 || 0 | 0 | 0 | 0 |0|CI|| F |
+//- | F || 1 | 1 | 1 | 1 | 1 || E |
+//- +-------++----+----+----+----+----++-------+
+//-
+//- B/D low (Decimal), U/D high (Up)
+//- +-------++----+----+----+----+----++-------+
+//- | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+//- +=======++====+====+====+====+====++=======+
+//- | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+//- | 1 || 0 | 0 | 0 | 1 | 1 || 2 |
+//- | 2 || 0 | 0 | 1 | 0 | 1 || 3 |
+//- | 3 || 0 | 0 | 1 | 1 | 1 || 4 |
+//- | 4 || 0 | 1 | 0 | 0 | 1 || 5 |
+//- | 5 || 0 | 1 | 0 | 1 | 1 || 6 |
+//- | 6 || 0 | 1 | 1 | 0 | 1 || 7 |
+//- | 7 || 0 | 1 | 1 | 1 | 1 || 8 |
+//- | 8 || 1 | 0 | 0 | 0 | 1 || 9 |
+//- | 9 || 1 | 0 | 0 | 1 |0|CI|| 0 |
+//- | A || 1 | 0 | 1 | 0 | 1 || B |
+//- | B || 1 | 0 | 1 | 1 |0|CI|| 6 |
+//- | C || 1 | 1 | 0 | 0 | 1 || D |
+//- | D || 1 | 1 | 0 | 1 |0|CI|| 4 |
+//- | E || 1 | 1 | 1 | 0 | 1 || F |
+//- | F || 1 | 1 | 1 | 1 |0|CI|| 2 |
+//- | 0 || 0 | 0 | 0 | 0 | 1 || 1 |
+//- +-------++----+----+----+----+----++-------+
+//-
+//- B/D low (Decimal), U/D low (Down)
+//- +-------++----+----+----+----+----++-------+
+//- | COUNT || Q4 | Q3 | Q2 | Q1 | CO || NEXT |
+//- +=======++====+====+====+====+====++=======+
+//- | F || 1 | 1 | 1 | 1 | 1 || E |
+//- | E || 1 | 1 | 1 | 0 | 1 || D |
+//- | D || 1 | 1 | 0 | 1 | 1 || C |
+//- | C || 1 | 1 | 0 | 0 | 1 || B |
+//- | B || 1 | 0 | 1 | 1 | 1 || A |
+//- | A || 1 | 0 | 1 | 0 | 1 || 9 |
+//- | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+//- | 8 || 1 | 0 | 0 | 0 | 1 || 7 |
+//- | 7 || 0 | 1 | 1 | 1 | 1 || 6 |
+//- | 6 || 0 | 1 | 1 | 0 | 1 || 5 |
+//- | 5 || 0 | 1 | 0 | 1 | 1 || 4 |
+//- | 4 || 0 | 1 | 0 | 0 | 1 || 3 |
+//- | 3 || 0 | 0 | 1 | 1 | 1 || 2 |
+//- | 2 || 0 | 0 | 1 | 0 | 1 || 1 |
+//- | 1 || 0 | 0 | 0 | 1 | 1 || 0 |
+//- | 0 || 0 | 0 | 0 | 0 |0|CI|| 9 |
+//- | 9 || 1 | 0 | 0 | 1 | 1 || 8 |
+//- +-------++----+----+----+----+----++-------+
+//-
+//- Note that in all cases where Carry-out is generating a non-1 signal (0 | Carry-in),
+//- this signal is asynchronous, so if carry-in changes the carry-out value will
+//- change immediately.
+//-
+//- Preset/Carry in function table
+//- +-----+-----+-----++----+----+----+----+
+//- | PE | CLK | CI || Q1 | Q2 | Q3 | Q4 |
+//- +=====+=====+=====++====+====+====+====+
+//- | 1 | X | X || J1 | J2 | J3 | J4 |
+//- | 0 | X | 1 || Q1 | Q2 | Q3 | Q4 |
+//- | 0 | ./` | 0 || COUNT |
+//- +-----+-----+-----++----+----+----+----+
+//-
+static NETLIST_START(CD4029_DIP)
+ CD4029(A)
+
+ DIPPINS( /* +--------------+ */
+ A.PE, /* PE |1 ++ 16| VDD */ A.VDD,
+ A.Q4, /* Q4 |2 15| CLK */ A.CLK,
+ A.J4, /* J4 |3 14| Q3 */ A.Q3,
+ A.J1, /* J1 |4 4029 13| J3 */ A.J3,
+ A.CI, /* CI |5 12| J2 */ A.J2,
+ A.Q1, /* Q1 |6 11| Q2 */ A.Q2,
+ A.CO, /* CO |7 10| U/D */ A.UD,
+ A.VSS, /* VSS |8 9| B/D */ A.BD
+ /* +--------------+ */)
+NETLIST_END()
+
+//- Identifier: CD4030_DIP
+//- Title: CD4030M/CD4030C Quad EXCLUSIVE-OR Gate
+//- Pinalias: A1,B1,Y1,Y2,A2,B2,VSS,A3,B3,Y3,Y4,A4,B4,VDD
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- Limitations:
+//- Voltage-dependent timing is not implemented.
+//- FunctionTable:
+//- https://www.uni-kl.de/elektronik-lager/418055
+//-
+static NETLIST_START(CD4030_DIP)
+ CD4030_GATE(A)
+ CD4030_GATE(B)
+ CD4030_GATE(C)
+ CD4030_GATE(D)
+
+ DIPPINS( /* +--------------+ */
+ A.A, /* A1 |1 ++ 14| VDD */ A.VDD,
+ A.B, /* B1 |2 13| B4 */ D.B,
+ A.Q, /* Y1 |3 12| A4 */ D.A,
+ B.Q, /* Y2 |4 4030 11| Y4 */ D.Q,
+ B.A, /* A2 |5 10| Y3 */ C.Q,
+ B.B, /* B2 |6 9| B3 */ C.B,
+ A.VSS, /* VSS |7 8| A3 */ C.A
+ /* +--------------+ */
+ )
+NETLIST_END()
+
+//- Identifier: CD4042_DIP
+//- Title: CD4042BM/CD4042BC Quad Clocked D Latch
+//- Pinalias: Q4,Q1,QQ1,D1,CLK,POL,D2,VSS,QQ2,Q2,Q3,QQ3,D3,D4,QQ4,VDD
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- Limitations:
+//- Voltage-dependent timing is partially implemented.
+//- FunctionTable:
+//- http://pdf.datasheetcatalog.com/datasheet/nationalsemiconductor/DS005966.PDF
+//-
+//- +-----+-----+----++----+-----+
+//- | POL | CLK | Dx || Qx | QQx |
+//- +=====+=====+====++====+=====+
+//- | 0 | 0 | X || Qx | /Qx |
+//- | 0 | 1 | D || D | /D |
+//- | 1 | 1 | X || Qx | /Qx |
+//- | 1 | 0 | D || D | /D |
+//- +-----+-----+----++----+-----+
+//- Note that since this is a level triggered transparent latch,
+//- as long as POL ^ CLK == true, the latch is transparent, and
+//- if D changes Q and QQ(/Q) will instantly change.
+//-
+static NETLIST_START(CD4042_DIP)
+ CD4042(A)
+
+ DIPPINS( /* +--------------+ */
+ A.Q4, /* Q4 |1 ++ 16| VDD */ A.VDD,
+ A.Q1, /* Q1 |2 15| Q4Q */ A.Q4Q,
+ A.Q1Q, /* Q1Q |3 14| D4 */ A.D4,
+ A.D1, /* D1 |4 4042 13| D3 */ A.D3,
+ A.CLK, /* CLK |5 12| Q3Q */ A.Q3Q,
+ A.POL, /* POL |6 11| Q3 */ A.Q3,
+ A.D2, /* D2 |7 10| Q2 */ A.Q2,
+ A.VSS, /* VSS |8 9| Q2Q */ A.Q2Q
+ /* +--------------+ */
+ )
+NETLIST_END()
+
+//- Identifier: CD4049_DIP
+//- Title: CD4049UBM/CD4049UBC Hex Inverting Buffer
+//- Pinalias: VDD,G,A,H,B,I,C,VSS,D,J,E,K,NC,F,L,NC
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- Limitations:
+//- Voltage-dependent timing is not implemented.
+//- FunctionTable:
+//- http://pdf.datasheetcatalog.com/datasheets/134/109125_DS.pdf
+//-
+static NETLIST_START(CD4049_DIP)
+ CD4049_GATE(A)
+ CD4049_GATE(B)
+ CD4049_GATE(C)
+ CD4049_GATE(D)
+ CD4049_GATE(E)
+ CD4049_GATE(F)
+ NC_PIN(NC)
+
+ NET_C(A.VDD, B.VDD, C.VDD, D.VDD, E.VDD, F.VDD)
+ NET_C(A.VSS, B.VSS, C.VSS, D.VSS, E.VSS, F.VSS)
+
+ //DIPPINS( /* +--------------+ */
+ // A.VDD, /* VCC |1 ++ 16| NC */ NC.I,
+ // A.G, /*G=/A |2 15| L=/F*/ F.L,
+ // A.A, /* A |3 14| F */ F.F,
+ // B.H, /*H=/B |4 13| NC */ NC.I,
+ // B.B, /* B |5 4049 12| K=/E*/ E.K,
+ // C.I, /*I=/C |6 11| E */ E.E,
+ // C.C, /* C |7 10| J=/D*/ D.J,
+ // A.VSS, /* VSS |8 9| D */ D.D
+ // /* +--------------+ */
+ //)
+ DIPPINS( /* +--------------+ */
+ A.VDD, /* VCC |1 ++ 16| NC */ NC.I,
+ A.Q, /*G=/A |2 15| L=/F*/ F.Q,
+ A.A, /* A |3 14| F */ F.A,
+ B.Q, /*H=/B |4 13| NC */ NC.I,
+ B.A, /* B |5 4049 12| K=/E*/ E.Q,
+ C.Q, /*I=/C |6 11| E */ E.A,
+ C.A, /* C |7 10| J=/D*/ D.Q,
+ A.VSS, /* VSS |8 9| D */ D.A
+ /* +--------------+ */
+ )
+NETLIST_END()
+
//- Identifier: CD4053_DIP
//- Title: CD4053BM/CD4053BC Triple 2-Channel AnalogMultiplexer/Demultiplexer
//- Pinalias: INOUTBY,INOUTBX,INOUTCY,OUTINC,INOUTCX,INH,VEE,VSS,C,B,A,INOUTAX,INOUTAY,OUTINA,OUTINB,VDD
@@ -397,6 +642,114 @@ static NETLIST_START(CD4070_DIP)
)
NETLIST_END()
+//- Identifier: CD4071_DIP
+//- Title: CD4071BC Quad 2-Input OR Buffered B Series Gate
+//- Pinalias: A,B,J,K,C,D,VSS,E,F,L,M,G,H,VDD
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- FunctionTable:
+//- pdf.datasheetcatalog.com/datasheets/185/109289_DS.pdf
+//-
+static NETLIST_START(CD4071_DIP)
+ CD4071_GATE(A)
+ CD4071_GATE(B)
+ CD4071_GATE(C)
+ CD4071_GATE(D)
+
+ NET_C(A.VDD, B.VDD, C.VDD, D.VDD)
+ NET_C(A.VSS, B.VSS, C.VSS, D.VSS)
+
+ DIPPINS( /* +--------------+ */
+ A.A, /* A |1 ++ 14| VDD */ A.VDD,
+ A.B, /* B |2 13| H */ D.B,
+ A.Q, /* J |3 12| G */ D.A,
+ B.Q, /* K |4 4071 11| M */ D.Q,
+ B.A, /* C |5 10| L */ C.Q,
+ B.B, /* D |6 9| F */ C.B,
+ A.VSS, /* VSS |7 8| E */ C.A
+ /* +--------------+ */
+ )
+NETLIST_END()
+
+//- Identifier: CD4076_DIP
+//- Title: CD4076BM/CD4076BC TRI-STATE(R) Quad D Flip-Flop
+//- Pinalias: OD1,OD2,OA,OB,OC,OD,CLK,VSS,ID1,ID2,ID,IC,IB,IA,CLR,VDD
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- Limitations:
+//- Voltage-dependent timing is not implemented.
+//- FunctionTable:
+//- http://www.bitsavers.org/components/national/_dataBooks/1981_Natonal_CMOS_Databook.pdf 5-186 (pdf page 567)
+//-
+//- Function table for ID1/2 pins
+//- +-----+-----+-----+----+-----++-----+
+//- | ID1 | ID2 | CLR | Ix | CLK || iOx |
+//- +=====+=====+=====+====+=====++=====+
+//- | X | X | 0 | X | 0 || iOx |
+//- | X | X | 0 | X | 1 || iOx |
+//- | 1 | X | 0 | X | 0>1 || iOx |
+//- | X | 1 | 0 | X | 0>1 || iOx |
+//- | 0 | 0 | 0 | 0 | 0>1 || 0 |
+//- | 0 | 0 | 0 | 1 | 0>1 || 1 |
+//- | X | X | 1 | X | X || 0 |
+//- +-----+-----+-----+----+-----++-----+
+//- Note: iOX is an internal signal, the output of each D-latch
+//-
+//- Function table for OD1/2 pins vs output of the internal D-latches
+//- +-----+-----+-----++-----+
+//- | OD1 | OD2 | iOx || Ox |
+//- +=====+=====+=====++=====+
+//- | 1 | X | X || Z |
+//- | X | 1 | X || Z |
+//- | 0 | 0 | 0 || 0 |
+//- | 0 | 0 | 1 || 1 |
+//- +-----+-----+-----++-----+
+//-
+static NETLIST_START(CD4076_DIP)
+ CD4076(A)
+
+ DIPPINS( /* +--------------+ */
+ A.OD1, /* OD1 |1 ++ 16| VDD */ A.VDD,
+ A.OD2, /* OD2 |2 15| CLR */ A.CLR,
+ A.OA, /* OA |3 14| IA */ A.IA,
+ A.OB, /* OB |4 4076 13| IB */ A.IB,
+ A.OC, /* OC |5 12| IC */ A.IC,
+ A.OD, /* OD |6 11| ID */ A.ID,
+ A.CLK, /* CLK |7 10| ID2 */ A.ID2,
+ A.VSS, /* VSS |8 9| ID1 */ A.ID1
+ /* +--------------+ */
+ )
+NETLIST_END()
+
+//- Identifier: CD4081_DIP
+//- Title: CD4081BC Quad 2-Input AND Buffered B Series Gate
+//- Pinalias: A,B,J,K,C,D,VSS,E,F,L,M,G,H,VDD
+//- Package: DIP
+//- NamingConvention: Naming conventions follow National Semiconductor datasheet
+//- FunctionTable:
+//- pdf.datasheetcatalog.com/datasheets/185/109289_DS.pdf
+//-
+static NETLIST_START(CD4081_DIP)
+ CD4081_GATE(A)
+ CD4081_GATE(B)
+ CD4081_GATE(C)
+ CD4081_GATE(D)
+
+ NET_C(A.VDD, B.VDD, C.VDD, D.VDD)
+ NET_C(A.VSS, B.VSS, C.VSS, D.VSS)
+
+ DIPPINS( /* +--------------+ */
+ A.A, /* A |1 ++ 14| VDD */ A.VDD,
+ A.B, /* B |2 13| H */ D.B,
+ A.Q, /* J |3 12| G */ D.A,
+ B.Q, /* K |4 4081 11| M */ D.Q,
+ B.A, /* C |5 10| L */ C.Q,
+ B.B, /* D |6 9| F */ C.B,
+ A.VSS, /* VSS |7 8| E */ C.A
+ /* +--------------+ */
+ )
+NETLIST_END()
+
//- Identifier: CD4316_DIP
//- Title: 74HC/HCT4316 Quad bilateral switches
//- Pinalias: 1Z,1Y,2Y,2Z,2S,3S,EQ,GND,VEE,3Z,3Y,4Y,4Z,4S,1S,VCC
@@ -501,6 +854,22 @@ static TRUTHTABLE_START(CD4011_GATE, 2, 1, "")
TT_FAMILY("CD4XXX")
TRUTHTABLE_END()
+static TRUTHTABLE_START(CD4030_GATE, 2, 1, "")
+ TT_HEAD("A,B|Q ")
+ TT_LINE("0,0|0|100")
+ TT_LINE("0,1|1|100")
+ TT_LINE("1,0|1|100")
+ TT_LINE("1,1|0|100")
+ TT_FAMILY("CD4XXX")
+TRUTHTABLE_END()
+
+static TRUTHTABLE_START(CD4049_GATE, 1, 1, "")
+ TT_HEAD("A|Q ")
+ TT_LINE("0|1|45")
+ TT_LINE("1|0|45")
+ TT_FAMILY("CD4XXX")
+TRUTHTABLE_END()
+
static TRUTHTABLE_START(CD4069_GATE, 1, 1, "")
TT_HEAD("A|Q ")
TT_LINE("0|1|55")
@@ -517,17 +886,43 @@ static TRUTHTABLE_START(CD4070_GATE, 2, 1, "")
TT_FAMILY("CD4XXX")
TRUTHTABLE_END()
+static TRUTHTABLE_START(CD4071_GATE, 2, 1, "")
+ TT_HEAD("A,B|Q ")
+ TT_LINE("0,0|0|200")
+ TT_LINE("0,1|1|200")
+ TT_LINE("1,0|1|200")
+ TT_LINE("1,1|1|200")
+ TT_FAMILY("CD4XXX")
+TRUTHTABLE_END()
+
+static TRUTHTABLE_START(CD4081_GATE, 2, 1, "")
+ TT_HEAD("A,B|Q ")
+ TT_LINE("0,0|0|200")
+ TT_LINE("0,1|0|200")
+ TT_LINE("1,0|0|200")
+ TT_LINE("1,1|1|200")
+ TT_FAMILY("CD4XXX")
+TRUTHTABLE_END()
+
NETLIST_START(cd4xxx_lib)
TRUTHTABLE_ENTRY(CD4001_GATE)
TRUTHTABLE_ENTRY(CD4011_GATE)
+ TRUTHTABLE_ENTRY(CD4030_GATE)
+ TRUTHTABLE_ENTRY(CD4049_GATE)
TRUTHTABLE_ENTRY(CD4069_GATE)
TRUTHTABLE_ENTRY(CD4070_GATE)
+ TRUTHTABLE_ENTRY(CD4071_GATE)
+ TRUTHTABLE_ENTRY(CD4081_GATE)
LOCAL_LIB_ENTRY(CD4001_DIP)
LOCAL_LIB_ENTRY(CD4011_DIP)
+ LOCAL_LIB_ENTRY(CD4030_DIP)
+ LOCAL_LIB_ENTRY(CD4049_DIP)
LOCAL_LIB_ENTRY(CD4069_DIP)
LOCAL_LIB_ENTRY(CD4070_DIP)
+ LOCAL_LIB_ENTRY(CD4071_DIP)
+ LOCAL_LIB_ENTRY(CD4081_DIP)
/* DIP ONLY */
LOCAL_LIB_ENTRY(CD4006_DIP)
@@ -536,9 +931,12 @@ NETLIST_START(cd4xxx_lib)
LOCAL_LIB_ENTRY(CD4022_DIP)
LOCAL_LIB_ENTRY(CD4020_DIP)
LOCAL_LIB_ENTRY(CD4024_DIP)
+ LOCAL_LIB_ENTRY(CD4029_DIP)
+ LOCAL_LIB_ENTRY(CD4042_DIP)
LOCAL_LIB_ENTRY(CD4053_DIP)
LOCAL_LIB_ENTRY(CD4066_DIP)
LOCAL_LIB_ENTRY(CD4016_DIP)
+ LOCAL_LIB_ENTRY(CD4076_DIP)
LOCAL_LIB_ENTRY(CD4316_DIP)
LOCAL_LIB_ENTRY(CD4538_DIP)
diff --git a/src/lib/netlist/macro/nlm_opamp_lib.cpp b/src/lib/netlist/macro/nlm_opamp_lib.cpp
index 0d1a77a87b8..db5fba1888c 100644
--- a/src/lib/netlist/macro/nlm_opamp_lib.cpp
+++ b/src/lib/netlist/macro/nlm_opamp_lib.cpp
@@ -353,6 +353,16 @@ static NETLIST_START(LM2902_DIP)
NETLIST_END()
+static NETLIST_START(LM348_DIP)
+ OPAMP(A, "UA741")
+ OPAMP(B, "UA741")
+ OPAMP(C, "UA741")
+ OPAMP(D, "UA741")
+
+ INCLUDE(opamp_layout_4_4_11)
+
+NETLIST_END()
+
static NETLIST_START(LM358_DIP)
OPAMP(A, "LM358")
OPAMP(B, "LM358")
@@ -632,6 +642,7 @@ NETLIST_START(opamp_lib)
LOCAL_LIB_ENTRY(TL082_DIP)
LOCAL_LIB_ENTRY(TL084_DIP)
LOCAL_LIB_ENTRY(LM324_DIP)
+ LOCAL_LIB_ENTRY(LM348_DIP)
LOCAL_LIB_ENTRY(LM358_DIP)
LOCAL_LIB_ENTRY(LM2902_DIP)
LOCAL_LIB_ENTRY(UA741_DIP8)
diff --git a/src/lib/netlist/macro/nlm_roms_lib.cpp b/src/lib/netlist/macro/nlm_roms_lib.cpp
index 4e8ab22a910..d728078c87f 100644
--- a/src/lib/netlist/macro/nlm_roms_lib.cpp
+++ b/src/lib/netlist/macro/nlm_roms_lib.cpp
@@ -342,6 +342,39 @@ static NETLIST_START(PROM_MK28000_DIP)
ALIAS(24, A.OE1)
NETLIST_END()
+//- Identifier: ROM_MCM14524_DIP
+//- Title: MCM14524 1024-BIT READ ONLY MEMORY
+//- Pinalias: CLK,EN,B0,B1,B2,B3,A2,GND,A3,A4,A5,A6,A7,A1,A0,VCC
+//- Package: DIP
+//- Param: ROM
+//- The name of the source to load the rom content from
+//- NamingConvention: Naming conventions follow Motorola datasheet
+//- Limitations:
+//- Voltage-dependent timing is partially implemented.
+//- FunctionTable:
+//- http://www.bitsavers.org/components/motorola/_dataBooks/1978_Motorola_CMOS_Data_Book.pdf 7-439 (pdf page 488)
+
+static NETLIST_START(ROM_MCM14524_DIP)
+
+ ROM_MCM14524(A)
+
+ DEFPARAM(ROM, "unknown")
+ PARAM(A.ROM, "$(@.ROM)")
+
+ /* Motorola MCM14524: */
+ DIPPINS( /* +-----..-----+ */
+ A.CLK, /* /CLK |1 16| VDD */ A.VCC,
+ A.EN, /* CE |2 15| A0 */ A.A0,
+ A.B0, /* B0 |3 MCM 14| A1 */ A.A1,
+ A.B1, /* B1 |4 14524 13| A7 */ A.A7,
+ A.B2, /* B2 |5 12| A6 */ A.A6,
+ A.B3, /* B3 |6 11| A5 */ A.A5,
+ A.A2, /* A2 |7 10| A4 */ A.A4,
+ A.GND, /* VSS |8 9| A3 */ A.A3
+ /* +------------+ */
+ )
+NETLIST_END()
+
/* 2102: 1024 x 1-bit Static RAM
*
* +--------------+
@@ -402,6 +435,7 @@ NETLIST_START(roms_lib)
LOCAL_LIB_ENTRY(TTL_82S16_DIP)
LOCAL_LIB_ENTRY(PROM_82S115_DIP)
LOCAL_LIB_ENTRY(PROM_MK28000_DIP)
+ LOCAL_LIB_ENTRY(ROM_MCM14524_DIP)
LOCAL_LIB_ENTRY(RAM_2102A_DIP)
LOCAL_LIB_ENTRY(ROM_TMS4800_DIP)
NETLIST_END()
diff --git a/src/lib/netlist/nl_base.cpp b/src/lib/netlist/nl_base.cpp
index d0a0e707aaf..d92b8e505c5 100644
--- a/src/lib/netlist/nl_base.cpp
+++ b/src/lib/netlist/nl_base.cpp
@@ -86,14 +86,14 @@ namespace netlist
// ----------------------------------------------------------------------------------------
netlist_t::netlist_t(netlist_state_t &state, const pstring &aname)
- : m_state(state)
- , m_solver(nullptr)
- , m_time(netlist_time_ext::zero())
- , m_mainclock(nullptr)
- , m_queue(config::MAX_QUEUE_SIZE::value,
- detail::queue_t::id_delegate(&netlist_state_t :: find_net_id, &state),
- detail::queue_t::obj_delegate(&netlist_state_t :: net_by_id, &state))
- , m_use_stats(false)
+ : m_state(state)
+ , m_solver(nullptr)
+ , m_time(netlist_time_ext::zero())
+ , m_mainclock(nullptr)
+ , m_use_stats(false)
+ , m_queue(config::MAX_QUEUE_SIZE::value,
+ detail::queue_t::id_delegate(&netlist_state_t :: find_net_id, &state),
+ detail::queue_t::obj_delegate(&netlist_state_t :: net_by_id, &state))
{
state.save(*this, static_cast<plib::state_manager_t::callback_t &>(m_queue), aname, "m_queue");
state.save(*this, m_time, aname, "m_time");
@@ -106,7 +106,6 @@ namespace netlist
netlist_state_t::netlist_state_t(const pstring &name,
plib::plog_delegate logger)
: m_log(logger)
- , m_extended_validation(false)
, m_dummy_version(1)
{
m_setup = plib::make_unique<setup_t, host_arena>(*this);
@@ -141,9 +140,9 @@ namespace netlist
//m_setup->parser().register_source<source_pattern_t>("../macro/nlm_{1}.cpp");
#else
#if 1
- m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/macro/nlm_{1}.cpp");
- m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/generated/nlm_{1}.cpp");
- m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/macro/modules/nlmod_{1}.cpp");
+ m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/macro/nlm_{1}.cpp", true);
+ m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/generated/nlm_{1}.cpp", true);
+ m_setup->parser().register_source<source_pattern_t>("src/lib/netlist/macro/modules/nlmod_{1}.cpp", true);
m_setup->parser().include("base_lib");
#else
// FIXME: This is very slow - need optimized parsing scanning
@@ -246,6 +245,7 @@ namespace netlist
ENTRY_EX(sizeof(base_device_t))
ENTRY_EX(sizeof(device_t))
+ ENTRY_EX(sizeof(logic_t))
ENTRY_EX(sizeof(logic_input_t))
ENTRY_EX(sizeof(logic_output_t))
ENTRY_EX(sizeof(param_model_t))
@@ -253,6 +253,7 @@ namespace netlist
ENTRY_EX(sizeof(state_var<int>))
ENTRY_EX(sizeof(pstring))
ENTRY_EX(sizeof(core_device_t::stats_t))
+ ENTRY_EX(sizeof(std::vector<detail::core_terminal_t *>))
ENTRY_EX(sizeof(plib::plog_level))
ENTRY_EX(sizeof(nldelegate))
@@ -338,7 +339,7 @@ namespace netlist
for (auto &n : m_nets)
{
n->update_inputs(); // only used if USE_COPY_INSTEAD_OF_REFERENCE == 1
- for (auto & term : n->core_terms())
+ for (auto & term : core_terms(*n))
{
if (!plib::container::contains(t, &term->delegate()))
{
@@ -432,7 +433,6 @@ namespace netlist
log().verbose("Queue Pushes {1:15}", si.m_queue.m_prof_call());
log().verbose("Queue Moves {1:15}", si.m_queue.m_prof_sortmove());
log().verbose("Queue Removes {1:15}", si.m_queue.m_prof_remove());
- log().verbose("Queue Retimes {1:15}", si.m_queue.m_prof_retime());
log().verbose("");
log().verbose("Take the next lines with a grain of salt. They depend on the measurement implementation.");
@@ -619,7 +619,7 @@ namespace netlist
// rebuild m_list
m_list_active.clear();
- for (auto & term : core_terms())
+ for (auto & term : exec().nlstate().core_terms(*this))
if (term->terminal_state() != logic_t::STATE_INP_PASSIVE)
{
m_list_active.push_back(term);
@@ -644,7 +644,7 @@ namespace netlist
// rebuild m_list and reset terminals to active or analog out state
m_list_active.clear();
- for (core_terminal_t *ct : core_terms())
+ for (core_terminal_t *ct : exec().nlstate().core_terms(*this))
{
ct->reset();
if (ct->terminal_state() != logic_t::STATE_INP_PASSIVE)
@@ -704,13 +704,21 @@ namespace netlist
// terminal_t
// ----------------------------------------------------------------------------------------
- terminal_t::terminal_t(core_device_t &dev, const pstring &aname, terminal_t *otherterm, nldelegate delegate)
+ terminal_t::terminal_t(core_device_t &dev, const pstring &aname,
+ terminal_t *otherterm, nldelegate delegate)
+ : terminal_t(dev, aname, otherterm, { nullptr, nullptr }, delegate)
+ {
+ }
+
+ terminal_t::terminal_t(core_device_t &dev, const pstring &aname,
+ terminal_t *otherterm, const std::array<terminal_t *, 2> &splitterterms,
+ nldelegate delegate)
: analog_t(dev, aname, STATE_BIDIR, delegate)
, m_Idr(nullptr)
, m_go(nullptr)
, m_gt(nullptr)
{
- state().setup().register_term(*this, *otherterm);
+ state().setup().register_term(*this, otherterm, splitterterms);
}
void terminal_t::set_ptrs(nl_fptype *gt, nl_fptype *go, nl_fptype *Idr) noexcept(false)
@@ -1029,12 +1037,14 @@ namespace netlist
}
m_time = top->exec_time();
- auto *const obj(top->object());
+ detail::net_t *const obj(top->object());
m_queue.pop();
- if (obj != nullptr)
- obj->template update_devs<KEEP_STATS>();
- else
+
+ if (!!(obj == nullptr))
break;
+
+ obj->template update_devs<KEEP_STATS>();
+
if (KEEP_STATS)
m_perf_out_processed.inc();
} while (true);
diff --git a/src/lib/netlist/nl_config.h b/src/lib/netlist/nl_config.h
index 6d4c572eb08..3bd57c2771d 100644
--- a/src/lib/netlist/nl_config.h
+++ b/src/lib/netlist/nl_config.h
@@ -242,14 +242,14 @@ namespace netlist
template <>
struct fp_constants<long double>
{
- static inline constexpr long double DIODE_MAXDIFF() noexcept { return 1e100L; } // NOLINT
- static inline constexpr long double DIODE_MAXVOLT() noexcept { return 300.0L; } // NOLINT
+ static constexpr long double DIODE_MAXDIFF() noexcept { return 1e100L; } // NOLINT
+ static constexpr long double DIODE_MAXVOLT() noexcept { return 300.0L; } // NOLINT
- static inline constexpr long double TIMESTEP_MAXDIFF() noexcept { return 1e100L; } // NOLINT
- static inline constexpr long double TIMESTEP_MINDIV() noexcept { return 1e-60L; } // NOLINT
+ static constexpr long double TIMESTEP_MAXDIFF() noexcept { return 1e100L; } // NOLINT
+ static constexpr long double TIMESTEP_MINDIV() noexcept { return 1e-60L; } // NOLINT
- static inline constexpr const char * name() noexcept { return "long double"; }
- static inline constexpr const char * suffix() noexcept { return "L"; }
+ static constexpr const char * name() noexcept { return "long double"; }
+ static constexpr const char * suffix() noexcept { return "L"; }
};
/// \brief Specific constants for double floating point type
@@ -257,14 +257,14 @@ namespace netlist
template <>
struct fp_constants<double>
{
- static inline constexpr double DIODE_MAXDIFF() noexcept { return 1e100; } // NOLINT
- static inline constexpr double DIODE_MAXVOLT() noexcept { return 300.0; } // NOLINT
+ static constexpr double DIODE_MAXDIFF() noexcept { return 1e100; } // NOLINT
+ static constexpr double DIODE_MAXVOLT() noexcept { return 300.0; } // NOLINT
- static inline constexpr double TIMESTEP_MAXDIFF() noexcept { return 1e100; } // NOLINT
- static inline constexpr double TIMESTEP_MINDIV() noexcept { return 1e-60; } // NOLINT
+ static constexpr double TIMESTEP_MAXDIFF() noexcept { return 1e100; } // NOLINT
+ static constexpr double TIMESTEP_MINDIV() noexcept { return 1e-60; } // NOLINT
- static inline constexpr const char * name() noexcept { return "double"; }
- static inline constexpr const char * suffix() noexcept { return ""; }
+ static constexpr const char * name() noexcept { return "double"; }
+ static constexpr const char * suffix() noexcept { return ""; }
};
/// \brief Specific constants for float floating point type
@@ -272,14 +272,14 @@ namespace netlist
template <>
struct fp_constants<float>
{
- static inline constexpr float DIODE_MAXDIFF() noexcept { return 1e20F; } // NOLINT
- static inline constexpr float DIODE_MAXVOLT() noexcept { return 90.0F; } // NOLINT
+ static constexpr float DIODE_MAXDIFF() noexcept { return 1e20F; } // NOLINT
+ static constexpr float DIODE_MAXVOLT() noexcept { return 90.0F; } // NOLINT
- static inline constexpr float TIMESTEP_MAXDIFF() noexcept { return 1e30F; } // NOLINT
- static inline constexpr float TIMESTEP_MINDIV() noexcept { return 1e-8F; } // NOLINT
+ static constexpr float TIMESTEP_MAXDIFF() noexcept { return 1e30F; } // NOLINT
+ static constexpr float TIMESTEP_MINDIV() noexcept { return 1e-8F; } // NOLINT
- static inline constexpr const char * name() noexcept { return "float"; }
- static inline constexpr const char * suffix() noexcept { return "f"; }
+ static constexpr const char * name() noexcept { return "float"; }
+ static constexpr const char * suffix() noexcept { return "f"; }
};
#if (NL_USE_FLOAT128)
@@ -290,23 +290,23 @@ namespace netlist
{
#if 0
// MAME compile doesn't support Q
- static inline constexpr FLOAT128 DIODE_MAXDIFF() noexcept { return 1e100Q; }
- static inline constexpr FLOAT128 DIODE_MAXVOLT() noexcept { return 300.0Q; }
+ static constexpr FLOAT128 DIODE_MAXDIFF() noexcept { return 1e100Q; }
+ static constexpr FLOAT128 DIODE_MAXVOLT() noexcept { return 300.0Q; }
- static inline constexpr FLOAT128 TIMESTEP_MAXDIFF() noexcept { return 1e100Q; }
- static inline constexpr FLOAT128 TIMESTEP_MINDIV() noexcept { return 1e-60Q; }
+ static constexpr FLOAT128 TIMESTEP_MAXDIFF() noexcept { return 1e100Q; }
+ static constexpr FLOAT128 TIMESTEP_MINDIV() noexcept { return 1e-60Q; }
- static inline constexpr const char * name() noexcept { return "FLOAT128"; }
- static inline constexpr const char * suffix() noexcept { return "Q"; }
+ static constexpr const char * name() noexcept { return "FLOAT128"; }
+ static constexpr const char * suffix() noexcept { return "Q"; }
#else
- static inline constexpr FLOAT128 DIODE_MAXDIFF() noexcept { return static_cast<FLOAT128>(1e100L); }
- static inline constexpr FLOAT128 DIODE_MAXVOLT() noexcept { return static_cast<FLOAT128>(300.0L); }
+ static constexpr FLOAT128 DIODE_MAXDIFF() noexcept { return static_cast<FLOAT128>(1e100L); }
+ static constexpr FLOAT128 DIODE_MAXVOLT() noexcept { return static_cast<FLOAT128>(300.0L); }
- static inline constexpr FLOAT128 TIMESTEP_MAXDIFF() noexcept { return static_cast<FLOAT128>(1e100L); }
- static inline constexpr FLOAT128 TIMESTEP_MINDIV() noexcept { return static_cast<FLOAT128>(1e-60L); }
+ static constexpr FLOAT128 TIMESTEP_MAXDIFF() noexcept { return static_cast<FLOAT128>(1e100L); }
+ static constexpr FLOAT128 TIMESTEP_MINDIV() noexcept { return static_cast<FLOAT128>(1e-60L); }
- static inline constexpr const char * name() noexcept { return "__float128"; }
- static inline constexpr const char * suffix() noexcept { return "Q"; }
+ static constexpr const char * name() noexcept { return "__float128"; }
+ static constexpr const char * suffix() noexcept { return "Q"; }
#endif
};
diff --git a/src/lib/netlist/nl_errstr.h b/src/lib/netlist/nl_errstr.h
index 4b44fb7b963..f60287e7a2d 100644
--- a/src/lib/netlist/nl_errstr.h
+++ b/src/lib/netlist/nl_errstr.h
@@ -150,6 +150,17 @@ namespace netlist
PERRMSGV(MI_NO_SPECIFIC_SOLVER, 1, "No specific solver found for netlist of size {1}")
PERRMSGV(MW_SOLVER_METHOD_NOT_SUPPORTED, 2, "Solver method {1} not supported. Falling back to {2}")
+ PERRMSGV(ME_SOLVER_CONSISTENCY_NOT_ANALOG_NET, 1, "Solver consistency: {1} is not an analog net")
+ PERRMSGV(ME_SOLVER_CONSISTENCY_RAIL_NET, 1, "Solver consistency: {1} is a rail net")
+ PERRMSGV(ME_SOLVER_TERMINAL_NO_NET, 1, "Solver consistency: Terminal {1} has no net")
+ PERRMSGV(ME_SOLVER_NO_RAIL_TERMINAL, 1, "Solver consistency: No rail terminals in group with nets: {1}\n"
+ "At least one rail terminal (like ANALOG_INPUT) needs to be part of a group of nets\n"
+ "solved by a solver. Without a singular matrix would be created\n"
+ "which has the potential to cause a crash now or in the future.\n"
+ "A common cause of this error are BJT or FET devices which\n"
+ "are defined but not used in the netlist.")
+ PERRMSGV(MF_SOLVER_CONSISTENCY_ERRORS, 1, "Found {1} errors during solver consistency test")
+
// nld_mm5837.cpp
PERRMSGV(MW_FREQUENCY_OUTSIDE_OF_SPECS_1, 1, "MM5837: Frequency outside of specs: {1}")
diff --git a/src/lib/netlist/nl_parser.h b/src/lib/netlist/nl_parser.h
index cbc757307d5..06bcf4395e7 100644
--- a/src/lib/netlist/nl_parser.h
+++ b/src/lib/netlist/nl_parser.h
@@ -8,8 +8,8 @@
#ifndef NL_PARSER_H_
#define NL_PARSER_H_
-#include "nltypes.h" // for setup_t
#include "core/setup.h"
+#include "nltypes.h" // for setup_t
#include "plib/ptokenizer.h"
#include <unordered_map>
diff --git a/src/lib/netlist/nl_setup.cpp b/src/lib/netlist/nl_setup.cpp
index 9af1ec92d51..ab6626acde1 100644
--- a/src/lib/netlist/nl_setup.cpp
+++ b/src/lib/netlist/nl_setup.cpp
@@ -6,6 +6,7 @@
#include "devices/nlid_proxy.h"
#include "devices/nlid_truthtable.h"
#include "nl_base.h"
+#include "nl_errstr.h"
#include "nl_factory.h"
#include "nl_parser.h"
#include "nl_setup.h"
@@ -164,7 +165,7 @@ namespace netlist
void nlparse_t::register_link(const pstring &sin, const pstring &sout)
{
- register_link_fqn(build_fqn(sin), build_fqn(sout));
+ register_link_fqn(build_fqn(plib::trim(sin)), build_fqn(plib::trim(sout)));
}
void nlparse_t::register_link_arr(const pstring &terms)
@@ -551,10 +552,10 @@ void setup_t::register_term(detail::core_terminal_t &term)
}
}
-void setup_t::register_term(terminal_t &term, terminal_t &other_term)
+void setup_t::register_term(terminal_t &term, terminal_t *other_term, const std::array<terminal_t *, 2> &splitter_terms)
{
this->register_term(term);
- m_connected_terminals.insert({&term, &other_term});
+ m_connected_terminals.insert({&term, {other_term, splitter_terms[0], splitter_terms[1], nullptr}});
}
void setup_t::register_param_t(param_t &param)
@@ -716,7 +717,7 @@ param_ref_t setup_t::find_param(const pstring &param_in) const
//NOLINTNEXTLINE(misc-no-recursion)
devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &out)
{
- nl_assert(out.is_logic());
+ gsl_Expects(out.is_logic());
const auto &out_cast = dynamic_cast<const logic_output_t &>(out);
auto iter_proxy(m_proxies.find(&out));
@@ -731,7 +732,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &o
m_proxy_cnt++;
// connect all existing terminals to new net
- for (auto & p : out.net().core_terms())
+ for (auto & p : nlstate().core_terms(out.net()))
{
p->clear_net(); // de-link from all nets ...
if (!connect(new_proxy->proxy_term(), *p))
@@ -742,7 +743,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &o
new_proxy->proxy_term().name(), (*p).name()));
}
}
- out.net().core_terms().clear();
+ nlstate().core_terms(out.net()).clear();
add_terminal(out.net(), new_proxy->in());
@@ -759,7 +760,7 @@ devices::nld_base_proxy *setup_t::get_d_a_proxy(const detail::core_terminal_t &o
//NOLINTNEXTLINE(misc-no-recursion)
devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
{
- nl_assert(inp.is_logic());
+ gsl_Expects(inp.is_logic());
const auto &incast = dynamic_cast<const logic_input_t &>(inp);
@@ -783,7 +784,7 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
if (inp.has_net())
{
- for (detail::core_terminal_t * p : inp.net().core_terms())
+ for (detail::core_terminal_t * p : nlstate().core_terms(inp.net()))
{
// inp may already belongs to the logic net. Thus skip it here.
// It will be removed by the clear further down.
@@ -799,7 +800,7 @@ devices::nld_base_proxy *setup_t::get_a_d_proxy(detail::core_terminal_t &inp)
}
}
}
- inp.net().core_terms().clear(); // clear the list
+ nlstate().core_terms(inp.net()).clear(); // clear the list
}
inp.clear_net();
add_terminal(ret->out().net(), inp);
@@ -973,7 +974,7 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term
ret = connect(t2, t1.net().railterminal());
if (!ret)
{
- for (auto & t : t1.net().core_terms())
+ for (auto & t : nlstate().core_terms(t1.net()))
{
if (t->is_type(detail::terminal_type::TERMINAL))
ret = connect(t2, *t);
@@ -988,7 +989,7 @@ bool setup_t::connect_input_input(detail::core_terminal_t &t1, detail::core_term
ret = connect(t1, t2.net().railterminal());
if (!ret)
{
- for (auto & t : t2.net().core_terms())
+ for (auto & t : nlstate().core_terms(t2.net()))
{
if (t->is_type(detail::terminal_type::TERMINAL))
ret = connect(t1, *t);
@@ -1174,7 +1175,7 @@ void setup_t::resolve_inputs()
log().error(ME_TERMINAL_1_WITHOUT_NET(name_da));
err = true;
}
- else if (!term->net().has_connections())
+ else if (nlstate().core_terms(term->net()).empty())
{
if (term->is_logic_input())
log().warning(MW_LOGIC_INPUT_1_WITHOUT_CONNECTIONS(name_da));
@@ -1192,6 +1193,7 @@ void setup_t::resolve_inputs()
log().warning(MW_TERMINAL_1_WITHOUT_CONNECTIONS(name_da));
}
}
+
log().verbose("checking tristate consistency ...");
for (auto & i : m_terminals)
{
@@ -1224,7 +1226,7 @@ void setup_t::resolve_inputs()
void setup_t::add_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false)
{
- for (auto &t : net.core_terms())
+ for (auto &t : nlstate().core_terms(net))
if (t == &terminal)
{
log().fatal(MF_NET_1_DUPLICATE_TERMINAL_2(net.name(), t->name()));
@@ -1233,15 +1235,15 @@ void setup_t::add_terminal(detail::net_t &net, detail::core_terminal_t &terminal
terminal.set_net(&net);
- net.core_terms().push_back(&terminal);
+ nlstate().core_terms(net).push_back(&terminal);
}
void setup_t::remove_terminal(detail::net_t &net, detail::core_terminal_t &terminal) noexcept(false)
{
- if (plib::container::contains(net.core_terms(), &terminal))
+ if (plib::container::contains(nlstate().core_terms(net), &terminal))
{
terminal.set_net(nullptr);
- plib::container::remove(net.core_terms(), &terminal);
+ plib::container::remove(nlstate().core_terms(net), &terminal);
}
else
{
@@ -1252,9 +1254,9 @@ void setup_t::remove_terminal(detail::net_t &net, detail::core_terminal_t &termi
void setup_t::move_connections(detail::net_t &net, detail::net_t &dest_net)
{
- for (auto &ct : net.core_terms())
+ for (auto &ct : nlstate().core_terms(net))
add_terminal(dest_net, *ct);
- net.core_terms().clear();
+ nlstate().core_terms(net).clear();
}
@@ -1305,7 +1307,7 @@ void models_t::model_parse(const pstring &model_in, map_t &map)
if (!plib::endsWith(remainder, ")"))
throw nl_exception(MF_MODEL_ERROR_1(model));
// FIMXE: Not optimal
- remainder = plib::left(remainder, remainder.size() - 1);
+ remainder = plib::left(remainder, remainder.length() - 1);
const auto pairs(plib::psplit(remainder,' ', true));
for (const pstring &pe : pairs)
@@ -1353,7 +1355,7 @@ nl_fptype models_t::model_t::value(const pstring &entity) const
pstring tmp = value_str(entity);
nl_fptype factor = nlconst::one();
- auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.size() - 1));
+ auto p = std::next(tmp.begin(), plib::narrow_cast<pstring::difference_type>(tmp.length() - 1));
switch (*p)
{
case 'M': factor = nlconst::magic(1e6); break; // NOLINT
@@ -1370,7 +1372,7 @@ nl_fptype models_t::model_t::value(const pstring &entity) const
throw nl_exception(MF_UNKNOWN_NUMBER_FACTOR_IN_2(m_model, entity));
}
if (factor != nlconst::one())
- tmp = plib::left(tmp, tmp.size() - 1);
+ tmp = plib::left(tmp, tmp.length() - 1);
// FIXME: check for errors
bool err(false);
auto val = plib::pstonum_ne<nl_fptype>(tmp, err);
@@ -1529,8 +1531,9 @@ void setup_t::delete_empty_nets()
std::remove_if(m_nlstate.nets().begin(), m_nlstate.nets().end(),
[](device_arena::owned_ptr<detail::net_t> &net)
{
- if (!net->has_connections())
+ if (net->state().core_terms(*net).empty())
{
+ // FIXME: need to remove from state->m_core_terms as well.
net->state().log().verbose("Deleting net {1} ...", net->name());
net->state().run_state_manager().remove_save_items(net.get());
return true;
@@ -1607,13 +1610,10 @@ void setup_t::prepare_to_run()
if (p != m_abstract.m_hints.end())
{
p->second = true; // mark as used
- if (use_deactivate)
- d.second->set_hint_deactivate(false);
- else
- d.second->set_hint_deactivate(true);
+ d.second->set_hint_deactivate(false);
}
else
- d.second->set_hint_deactivate(true);
+ d.second->set_hint_deactivate(use_deactivate);
}
if (errcnt > 0)
@@ -1684,7 +1684,7 @@ void setup_t::prepare_to_run()
for (auto &n : m_nlstate.nets())
{
- for (auto & term : n->core_terms())
+ for (auto & term : m_nlstate.core_terms(*n))
if (!term->delegate())
{
log().fatal(MF_DELEGATE_NOT_SET_1(term->name()));
@@ -1734,7 +1734,7 @@ plib::istream_uptr source_file_t::stream(const pstring &name)
plib::istream_uptr source_pattern_t::stream(const pstring &name)
{
- pstring filename = plib::pfmt(m_pattern)(name);
+ pstring filename = plib::pfmt(m_pattern)(m_force_lowercase ? plib::lcase(name) : name);
auto f = std::make_unique<plib::ifstream>(plib::filesystem::u8path(filename));
if (f->is_open())
{
diff --git a/src/lib/netlist/nl_setup.h b/src/lib/netlist/nl_setup.h
index fd9cb11afab..81f3e769a1d 100644
--- a/src/lib/netlist/nl_setup.h
+++ b/src/lib/netlist/nl_setup.h
@@ -23,7 +23,7 @@
#include <vector>
//============================================================
-// MACROS / inline netlist definitions
+// MACROS - netlist definitions
//============================================================
#define NET_STR(x) # x
@@ -274,10 +274,6 @@ namespace netlist
unsigned m_frontier_cnt;
};
- // -----------------------------------------------------------------------------
- // inline implementations
- // -----------------------------------------------------------------------------
-
} // namespace netlist
diff --git a/src/lib/netlist/nltypes.h b/src/lib/netlist/nltypes.h
index 5781619af1a..548d64613f5 100644
--- a/src/lib/netlist/nltypes.h
+++ b/src/lib/netlist/nltypes.h
@@ -98,10 +98,10 @@ namespace netlist
{
using BC = plib::constants<T>;
- static inline constexpr T np_VT(T n=BC::one(), T temp=BC::T0()) noexcept
+ static constexpr T np_VT(T n=BC::one(), T temp=BC::T0()) noexcept
{ return n * temp * BC::k_b() / BC::Q_e(); }
- static inline constexpr T np_Is() noexcept { return static_cast<T>(1e-15); } // NOLINT
+ static constexpr T np_Is() noexcept { return static_cast<T>(1e-15); } // NOLINT
/// \brief constant startup gmin
///
@@ -109,19 +109,19 @@ namespace netlist
/// conductivities with a reasonable value.
/// During reset, the object should than make use of exec().gmin()
/// to use the actual gmin() value.
- static inline constexpr T cgmin() noexcept { return BC::magic(1e-9); } // NOLINT
+ static constexpr T cgmin() noexcept { return BC::magic(1e-9); } // NOLINT
// FIXME: Some objects used 1e-15 for initial gmin. Needs to be
// aligned with cgmin
- static inline constexpr T cgminalt() noexcept { return BC::magic(1e-15); } // NOLINT
+ static constexpr T cgminalt() noexcept { return BC::magic(1e-15); } // NOLINT
/// \brief Multiplier applied to VT in np diode models to determine range for constant model
///
- static inline constexpr T diode_min_cutoff_mult() noexcept { return BC::magic(-5.0); } // NOLINT
+ static constexpr T diode_min_cutoff_mult() noexcept { return BC::magic(-5.0); } // NOLINT
/// \brief Startup voltage used by np diode models
///
- static inline constexpr T diode_start_voltage() noexcept { return BC::magic(0.7); } // NOLINT
+ static constexpr T diode_start_voltage() noexcept { return BC::magic(0.7); } // NOLINT
};
@@ -191,9 +191,9 @@ namespace netlist
// MACROS
//============================================================
- template <typename T> inline constexpr netlist_time NLTIME_FROM_NS(T &&t) noexcept { return netlist_time::from_nsec(t); }
- template <typename T> inline constexpr netlist_time NLTIME_FROM_US(T &&t) noexcept { return netlist_time::from_usec(t); }
- template <typename T> inline constexpr netlist_time NLTIME_FROM_MS(T &&t) noexcept { return netlist_time::from_msec(t); }
+ template <typename T> constexpr netlist_time NLTIME_FROM_NS(T &&t) noexcept { return netlist_time::from_nsec(t); }
+ template <typename T> constexpr netlist_time NLTIME_FROM_US(T &&t) noexcept { return netlist_time::from_usec(t); }
+ template <typename T> constexpr netlist_time NLTIME_FROM_MS(T &&t) noexcept { return netlist_time::from_msec(t); }
struct desc_base
{
diff --git a/src/lib/netlist/plib/gmres.h b/src/lib/netlist/plib/gmres.h
index df0fc787c52..1709d1bb510 100644
--- a/src/lib/netlist/plib/gmres.h
+++ b/src/lib/netlist/plib/gmres.h
@@ -8,9 +8,9 @@
/// \file gmres.h
///
-#include "mat_cr.h"
#include "parray.h"
#include "pconfig.h"
+#include "pmatrix_cr.h"
#include "vector_ops.h"
#include <algorithm>
@@ -33,11 +33,11 @@ namespace plib
template <typename FT, int SIZE>
struct mat_precondition_ILU
{
- using mat_type = plib::pmatrix_cr_t<FT, SIZE>;
- using matLU_type = plib::pLUmatrix_cr_t<mat_type>;
+ using mat_type = plib::pmatrix_cr<FT, SIZE>;
+ using matLU_type = plib::pLUmatrix_cr<mat_type>;
mat_precondition_ILU(std::size_t size, std::size_t ilu_scale = 4
- , std::size_t bw = plib::pmatrix_cr_t<FT, SIZE>::FILL_INFINITY)
+ , std::size_t bw = plib::pmatrix_cr<FT, SIZE>::FILL_INFINITY)
: m_mat(narrow_cast<typename mat_type::index_type>(size))
, m_LU(narrow_cast<typename mat_type::index_type>(size))
, m_ILU_scale(narrow_cast<std::size_t>(ilu_scale))
@@ -167,7 +167,7 @@ namespace plib
v[i] = v[i] * m_diag[i];
}
- plib::pmatrix_cr_t<FT, SIZE> m_mat;
+ plib::pmatrix_cr<FT, SIZE> m_mat;
plib::parray<FT, SIZE> m_diag;
plib::parray<std::vector<std::size_t>, SIZE > nzcol;
};
@@ -203,19 +203,23 @@ namespace plib
plib::unused_var(v);
}
- plib::pmatrix_cr_t<FT, SIZE> m_mat;
+ plib::pmatrix_cr<FT, SIZE> m_mat;
};
// FIXME: hardcoding RESTART to 20 becomes an issue on very large
// systems.
- template <typename FT, int SIZE, int RESTART = 16>
+ template <typename FT, int SIZE, int RESTARTMAX = 16>
struct gmres_t
{
public:
using float_type = FT;
+ //constexpr static int RESTART = RESTARTMAX;
+ constexpr static const int RESTART = (SIZE > 0) ? ((SIZE < RESTARTMAX) ? SIZE : RESTARTMAX)
+ : ((SIZE < 0) ? ((-SIZE < RESTARTMAX) ? -SIZE : RESTARTMAX) : RESTARTMAX);
+
explicit gmres_t(std::size_t size)
: residual(size)
, Ax(size)
@@ -226,83 +230,8 @@ namespace plib
{
}
- void givens_mult( const FT c, const FT s, FT & g0, FT & g1 )
- {
- const FT g0_last(g0);
-
- g0 = c * g0 - s * g1;
- g1 = s * g0_last + c * g1;
- }
-
std::size_t size() const { return (SIZE<=0) ? m_size : narrow_cast<std::size_t>(SIZE); }
- template <int k, typename OPS, typename VT>
- bool do_k(OPS &ops, VT &x, std::size_t &itr_used, FT rho_delta, bool dummy)
- {
- plib::unused_var(dummy);
- if (do_k<k-1, OPS>(ops, x, itr_used, rho_delta, do_khelper<k-1>::value))
- return true;
-
- const std::size_t kp1 = k + 1;
- const std::size_t n = size();
-
- ops.calc_rhs(m_v[kp1], m_v[k]);
- ops.solve_inplace(m_v[kp1]);
-
- for (std::size_t j = 0; j <= k; j++)
- {
- m_ht[j][k] = vec_mult<FT>(n, m_v[kp1], m_v[j]);
- vec_add_mult_scalar(n, m_v[kp1], m_v[j], -m_ht[j][k]);
- }
- m_ht[kp1][k] = plib::sqrt(vec_mult2<FT>(n, m_v[kp1]));
-
- // FIXME: comparison to zero
- if (m_ht[kp1][k] != plib::constants<FT>::zero())
- vec_scale(n, m_v[kp1], reciprocal(m_ht[kp1][k]));
-
- for (std::size_t j = 0; j < k; j++)
- givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]);
-
- const float_type mu = reciprocal(plib::hypot(m_ht[k][k], m_ht[kp1][k]));
-
- m_c[k] = m_ht[k][k] * mu;
- m_s[k] = -m_ht[kp1][k] * mu;
- m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[kp1][k];
- m_ht[kp1][k] = plib::constants<FT>::zero();
-
- givens_mult(m_c[k], m_s[k], m_g[k], m_g[kp1]);
-
- FT rho = plib::abs(m_g[kp1]);
-
- // FIXME ..
- itr_used = itr_used + 1;
-
- if (rho <= rho_delta || k == RESTART-1)
- {
- // Solve the system H * y = g
- // x += m_v[j] * m_y[j]
- for (std::size_t i = k + 1; i-- > 0;)
- {
- auto tmp(m_g[i]);
- for (std::size_t j = i + 1; j <= k; j++)
- tmp -= m_ht[i][j] * m_y[j];
- m_y[i] = tmp / m_ht[i][i];
- }
-
- for (std::size_t i = 0; i <= k; i++)
- vec_add_mult_scalar(n, x, m_v[i], m_y[i]);
- return true;
- }
- return false;
- }
-
- template <int k, typename OPS, typename VT>
- bool do_k(OPS &ops, VT &x, std::size_t &itr_used, FT rho_delta, float dummy)
- {
- plib::unused_var(ops, x, itr_used, rho_delta, dummy);
- return false;
- }
-
template <typename OPS, typename VT, typename VRHS>
std::size_t solve(OPS &ops, VT &x, const VRHS & rhs, const std::size_t itr_max, float_type accuracy)
{
@@ -348,19 +277,23 @@ namespace plib
// differently: The invest doesn't pay off.
//
- vec_set_scalar(n, residual, accuracy);
+ vec_set_scalar(residual, accuracy);
ops.calc_rhs(Ax, residual);
ops.solve_inplace(Ax);
- const float_type rho_to_accuracy = plib::sqrt(vec_mult2<FT>(n, Ax)) / accuracy;
+ const float_type rho_to_accuracy = plib::sqrt(vec_mult2<FT>(Ax)) / accuracy;
rho_delta = accuracy * rho_to_accuracy;
}
else
+ //rho_delta = accuracy * plib::sqrt(vec_mult2<FT>(n, rhs))
+ // + 1e-4 * std::sqrt(n);
rho_delta = accuracy * plib::sqrt(narrow_cast<FT>(n));
//
+ // LU x = b; solve for x;
+ //
// Using
//
// vec_set(n, x, rhs);
@@ -368,9 +301,6 @@ namespace plib
//
// to get a starting point for x degrades convergence speed compared
// to using the last solution for x.
- //
- // LU x = b; solve for x;
- //
while (itr_used < itr_max)
{
@@ -378,11 +308,11 @@ namespace plib
ops.calc_rhs(Ax, x);
- vec_sub(n, residual, rhs, Ax);
+ vec_sub(residual, rhs, Ax);
ops.solve_inplace(residual);
- rho = plib::sqrt(vec_mult2<FT>(n, residual));
+ rho = plib::sqrt(vec_mult2<FT>(residual));
if (rho < rho_delta)
return itr_used + 1;
@@ -391,10 +321,10 @@ namespace plib
// on some systems / compiler versions. Issue reported by
// AJR, no details known yet.
- vec_set_scalar(RESTART+1, m_g, +constants<FT>::zero());
+ vec_set_scalar(m_g, +constants<FT>::zero());
m_g[0] = rho;
- vec_mult_scalar(n, m_v[0], residual, reciprocal(rho));
+ vec_mult_scalar(m_v[0], residual, plib::reciprocal(rho));
if (do_k<RESTART-1>(ops, x, itr_used, rho_delta, true))
// converged
@@ -405,6 +335,83 @@ namespace plib
private:
+ static void givens_mult(FT c, FT s, FT & g0, FT & g1 )
+ {
+ const FT g0_last(g0);
+
+ g0 = c * g0 - s * g1;
+ g1 = s * g0_last + c * g1;
+ }
+
+ template <int k, typename OPS, typename VT>
+ bool do_k(OPS &ops, VT &x, std::size_t &itr_used, FT rho_delta, bool dummy)
+ {
+ plib::unused_var(dummy);
+ if (do_k<k-1, OPS>(ops, x, itr_used, rho_delta, do_khelper<k-1>::value))
+ return true;
+
+ constexpr const std::size_t kp1 = k + 1;
+ //const std::size_t n = size();
+
+ ops.calc_rhs(m_v[kp1], m_v[k]);
+ ops.solve_inplace(m_v[kp1]);
+
+ for (std::size_t j = 0; j <= k; j++)
+ {
+ m_ht[j][k] = vec_mult<FT>(m_v[kp1], m_v[j]);
+ vec_add_mult_scalar(m_v[kp1], m_v[j], -m_ht[j][k]);
+ }
+ m_ht[kp1][k] = plib::sqrt(vec_mult2<FT>(m_v[kp1]));
+
+ // FIXME: comparison to zero
+ if (m_ht[kp1][k] != plib::constants<FT>::zero())
+ vec_scale(m_v[kp1], reciprocal(m_ht[kp1][k]));
+
+ for (std::size_t j = 0; j < k; j++)
+ givens_mult(m_c[j], m_s[j], m_ht[j][k], m_ht[j+1][k]);
+
+ const float_type mu = reciprocal(plib::hypot(m_ht[k][k], m_ht[kp1][k]));
+
+ m_c[k] = m_ht[k][k] * mu;
+ m_s[k] = -m_ht[kp1][k] * mu;
+ m_ht[k][k] = m_c[k] * m_ht[k][k] - m_s[k] * m_ht[kp1][k];
+ m_ht[kp1][k] = plib::constants<FT>::zero();
+
+ givens_mult(m_c[k], m_s[k], m_g[k], m_g[kp1]);
+
+ const float_type rho = plib::abs(m_g[kp1]);
+
+ // FIXME ..
+ itr_used = itr_used + 1;
+
+ if (rho <= rho_delta || k == RESTART-1)
+ {
+ // Solve the system H * y = g
+ // x += m_v[j] * m_y[j]
+ for (std::size_t i = k + 1; i-- > 0;)
+ {
+ auto tmp(m_g[i]);
+ const auto htii=plib::reciprocal(m_ht[i][i]);
+ for (std::size_t j = i + 1; j <= k; j++)
+ tmp -= m_ht[i][j] * m_y[j];
+ m_y[i] = tmp * htii;
+ vec_add_mult_scalar(x, m_v[i], m_y[i]);
+ }
+
+ //for (std::size_t i = 0; i <= k; i++)
+ // vec_add_mult_scalar(n, x, m_v[i], m_y[i]);
+ return true;
+ }
+ return false;
+ }
+
+ template <int k, typename OPS, typename VT>
+ bool do_k(OPS &ops, VT &x, std::size_t &itr_used, FT rho_delta, float dummy)
+ {
+ plib::unused_var(ops, x, itr_used, rho_delta, dummy);
+ return false;
+ }
+
plib::parray<float_type, SIZE> residual;
plib::parray<float_type, SIZE> Ax;
diff --git a/src/lib/netlist/plib/palloc.h b/src/lib/netlist/plib/palloc.h
index 50507d10eea..9243645f781 100644
--- a/src/lib/netlist/plib/palloc.h
+++ b/src/lib/netlist/plib/palloc.h
@@ -256,7 +256,10 @@ namespace plib {
~arena_allocator() noexcept = default;
- PCOPYASSIGNMOVE(arena_allocator, default)
+ arena_allocator(const arena_allocator &) = default;
+ arena_allocator &operator=(const arena_allocator &) = default;
+ arena_allocator(arena_allocator &&) noexcept = default;
+ arena_allocator &operator=(arena_allocator &&) noexcept = default;
explicit arena_allocator(arena_type & a) noexcept : m_a(a)
{
@@ -288,7 +291,7 @@ namespace plib {
void construct(U* p, Args&&... args)
{
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
- ::new (static_cast<void *>(p)) U(std::forward<Args>(args)...);
+ ::new (void_ptr_cast(p)) U(std::forward<Args>(args)...);
}
template<typename U>
diff --git a/src/lib/netlist/plib/parray.h b/src/lib/netlist/plib/parray.h
index 514c231025b..54d72484ac2 100644
--- a/src/lib/netlist/plib/parray.h
+++ b/src/lib/netlist/plib/parray.h
@@ -105,12 +105,9 @@ namespace plib {
{
}
- // osx clang doesn't like COPYASSIGNMOVE(parray, default)
- // it will generate some weird error messages about move assignment
- // constructor having a different noexcept status.
-
parray(const parray &rhs) : m_a(rhs.m_a), m_size(rhs.m_size) {}
parray(parray &&rhs) noexcept : m_a(std::move(rhs.m_a)), m_size(std::move(rhs.m_size)) {}
+
parray &operator=(const parray &rhs) noexcept // NOLINT(bugprone-unhandled-self-assignment, cert-oop54-cpp)
{
if (this == &rhs)
@@ -127,7 +124,7 @@ namespace plib {
base_type &as_base() noexcept { return m_a; }
- inline size_type size() const noexcept { return SIZE <= 0 ? m_size : SIZEABS(); }
+ constexpr size_type size() const noexcept { return SIZE <= 0 ? m_size : SIZEABS(); }
constexpr size_type max_size() const noexcept { return base_type::max_size(); }
@@ -135,11 +132,11 @@ namespace plib {
constexpr reference operator[](size_type i) noexcept
{
- return data()[i];
+ return m_a[i];
}
constexpr const_reference operator[](size_type i) const noexcept
{
- return data()[i];
+ return m_a[i];
}
pointer data() noexcept { return m_a.data(); }
@@ -157,6 +154,7 @@ namespace plib {
public:
using size_type = std::size_t;
+ using base_type = parray<parray<FT, SIZE2>, SIZE1>;
parray2D(size_type size1, size_type size2)
: parray<parray<FT, SIZE2>, SIZE1>(size1)
@@ -168,7 +166,10 @@ namespace plib {
}
}
- PCOPYASSIGNMOVE(parray2D, default)
+ parray2D(const parray2D &) = default;
+ parray2D &operator=(const parray2D &) = default;
+ parray2D(parray2D &&) noexcept(std::is_nothrow_move_constructible<base_type>::value) = default;
+ parray2D &operator=(parray2D &&) noexcept(std::is_nothrow_move_assignable<base_type>::value) = default;
~parray2D() noexcept = default;
diff --git a/src/lib/netlist/plib/pchrono.h b/src/lib/netlist/plib/pchrono.h
index 6695f238290..813c3e651f3 100644..100755
--- a/src/lib/netlist/plib/pchrono.h
+++ b/src/lib/netlist/plib/pchrono.h
@@ -20,9 +20,9 @@ namespace plib {
struct sys_ticks
{
using type = typename T::rep;
- static inline constexpr type start() noexcept { return T::now().time_since_epoch().count(); }
- static inline constexpr type stop() noexcept { return T::now().time_since_epoch().count(); }
- static inline constexpr type per_second() noexcept { return T::period::den / T::period::num; }
+ static constexpr type start() noexcept { return T::now().time_since_epoch().count(); }
+ static constexpr type stop() noexcept { return T::now().time_since_epoch().count(); }
+ static constexpr type per_second() noexcept { return T::period::den / T::period::num; }
};
using hires_ticks = sys_ticks<std::chrono::high_resolution_clock>;
@@ -194,29 +194,32 @@ namespace plib {
struct guard_t
{
guard_t() = delete;
- explicit guard_t(timer &m) noexcept : m_m(m) { m_m.m_time -= T::start(); }
- ~guard_t() noexcept { m_m.m_time += T::stop(); ++m_m.m_count; }
+ explicit constexpr guard_t(timer &m) noexcept : m_m(&m) { m_m->m_time -= T::start(); }
+ ~guard_t() noexcept { m_m->m_time += T::stop(); ++m_m->m_count; }
- PCOPYASSIGNMOVE(guard_t, default)
+ constexpr guard_t(const guard_t &) = default;
+ constexpr guard_t &operator=(const guard_t &) = default;
+ constexpr guard_t(guard_t &&) noexcept = default;
+ constexpr guard_t &operator=(guard_t &&) noexcept = default;
private:
- timer &m_m;
+ timer *m_m;
};
- timer() : m_time(0), m_count(0) { }
+ constexpr timer() : m_time(0), m_count(0) { }
- type operator()() const { return m_time; }
+ constexpr type operator()() const { return m_time; }
void reset() noexcept { m_time = 0; m_count = 0; }
- type average() const noexcept { return (m_count == 0) ? 0 : m_time / m_count; }
- type total() const noexcept { return m_time; }
- ctype count() const noexcept { return m_count; }
+ constexpr type average() const noexcept { return (m_count == 0) ? 0 : m_time / m_count; }
+ constexpr type total() const noexcept { return m_time; }
+ constexpr ctype count() const noexcept { return m_count; }
template <typename S>
- S as_seconds() const noexcept { return narrow_cast<S>(total())
+ constexpr S as_seconds() const noexcept { return narrow_cast<S>(total())
/ narrow_cast<S>(T::per_second()); }
- guard_t guard() noexcept { return guard_t(*this); }
+ constexpr guard_t guard() noexcept { return guard_t(*this); }
// pause must be followed by cont(inue)
void stop() noexcept { m_time += T::stop(); }
@@ -236,8 +239,13 @@ namespace plib {
struct guard_t
{
- guard_t() = default;
- PCOPYASSIGNMOVE(guard_t, default)
+ constexpr guard_t() = default;
+
+ constexpr guard_t(const guard_t &) = default;
+ constexpr guard_t &operator=(const guard_t &) = default;
+ constexpr guard_t(guard_t &&) noexcept = default;
+ constexpr guard_t &operator=(guard_t &&) noexcept = default;
+
// using default constructor will trigger warning on
// unused local variable.
@@ -251,7 +259,7 @@ namespace plib {
constexpr type total() const noexcept { return 0; }
constexpr ctype count() const noexcept { return 0; }
template <typename S>
- S as_seconds() const noexcept { return narrow_cast<S>(0); }
+ constexpr S as_seconds() const noexcept { return narrow_cast<S>(0); }
constexpr static bool enabled = false;
guard_t guard() { return guard_t(); }
};
diff --git a/src/lib/netlist/plib/pconfig.h b/src/lib/netlist/plib/pconfig.h
index c80f1bbadd6..4253ff355b1 100644
--- a/src/lib/netlist/plib/pconfig.h
+++ b/src/lib/netlist/plib/pconfig.h
@@ -8,7 +8,7 @@
/// \file pconfig.h
///
-/// \brief More accurate measurements if you processor supports RDTSCP.
+/// \brief More accurate measurements the processor supports RDTSCP.
///
#ifndef PHAS_RDTSCP
#define PHAS_RDTSCP (0)
@@ -75,8 +75,13 @@
#define PALIGN_MIN_SIZE (16)
+#if (PUSE_ALIGNED_OPTIMIZATIONS)
#define PALIGNAS_CACHELINE() PALIGNAS(PALIGN_CACHELINE)
#define PALIGNAS_VECTOROPT() PALIGNAS(PALIGN_VECTOROPT)
+#else
+#define PALIGNAS_CACHELINE()
+#define PALIGNAS_VECTOROPT()
+#endif
// FIXME: Breaks mame build on windows mingw due to -Wattribute
// also triggers -Wattribute on ARM
diff --git a/src/lib/netlist/plib/pexception.cpp b/src/lib/netlist/plib/pexception.cpp
index 56ef7f93efb..d974c6b9a4e 100644
--- a/src/lib/netlist/plib/pexception.cpp
+++ b/src/lib/netlist/plib/pexception.cpp
@@ -102,7 +102,7 @@ namespace plib {
}
- bool fpsignalenabler::m_enable = false;
+ bool fpsignalenabler::m_enable = false; // NOLINT
//FIXME: mingw needs to be compiled with "-fnon-call-exceptions"
@@ -117,7 +117,8 @@ namespace plib {
if (fpexceptions & plib::FP_UNDERFLOW) b = b | FE_UNDERFLOW;
if (fpexceptions & plib::FP_OVERFLOW) b = b | FE_OVERFLOW;
if (fpexceptions & plib::FP_INVALID) b = b | FE_INVALID;
- m_last_enabled = feenableexcept(b);
+ if ((b & m_last_enabled) != b)
+ m_last_enabled = feenableexcept(b);
}
#elif defined(_WIN32) && defined(_EM_INEXACT)
if (m_enable)
@@ -136,7 +137,6 @@ namespace plib {
#endif
}
-
fpsignalenabler::~fpsignalenabler()
{
#if HAS_FEENABLE_EXCEPT
diff --git a/src/lib/netlist/plib/pexception.h b/src/lib/netlist/plib/pexception.h
index 709f8810b83..efed23d6178 100644
--- a/src/lib/netlist/plib/pexception.h
+++ b/src/lib/netlist/plib/pexception.h
@@ -39,7 +39,7 @@ namespace plib {
public:
explicit pexception(const pstring &text);
- const pstring &text() const noexcept { return m_text; }
+ const putf8string &text() const noexcept { return m_text; }
const char* what() const noexcept override { return m_text.c_str(); }
private:
@@ -125,7 +125,7 @@ namespace plib {
private:
int m_last_enabled;
- static bool m_enable;
+ static bool m_enable; // NOLINT
};
diff --git a/src/lib/netlist/plib/pfmtlog.cpp b/src/lib/netlist/plib/pfmtlog.cpp
index ddb9b5dd2e5..32468752658 100644
--- a/src/lib/netlist/plib/pfmtlog.cpp
+++ b/src/lib/netlist/plib/pfmtlog.cpp
@@ -47,7 +47,7 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec)
rtype r;
- r.sl = search.size();
+ r.sl = search.length();
r.p = m_str.find(search + ':');
r.sl++; // ":"
if (r.p == pstring::npos) // no further specifiers
@@ -94,11 +94,12 @@ pfmt::rtype pfmt::setfmt(std::stringstream &strm, char32_t cfmt_spec)
int width(0);
if (!fmt.empty() && pstring("duxofge").find(static_cast<pstring::value_type>(cfmt_spec)) != pstring::npos)
{
- pend = static_cast<char32_t>(fmt.at(fmt.size() - 1));
+ //pend = static_cast<char32_t>(fmt.at(fmt.size() - 1));
+ pend = plib::right(fmt, 1).at(0);
if (pstring("duxofge").find(static_cast<pstring::value_type>(pend)) == pstring::npos)
pend = cfmt_spec;
else
- fmt = plib::left(fmt, fmt.size() - 1);
+ fmt = plib::left(fmt, fmt.length() - 1);
}
else
// FIXME: Error
diff --git a/src/lib/netlist/plib/pfmtlog.h b/src/lib/netlist/plib/pfmtlog.h
index 45f7d3e4fc1..fd04f58bc73 100644
--- a/src/lib/netlist/plib/pfmtlog.h
+++ b/src/lib/netlist/plib/pfmtlog.h
@@ -9,6 +9,7 @@
#define PFMTLOG_H_
#include "penum.h"
+#include "pgsl.h"
#include "ppmf.h"
#include "pstring.h"
#include "ptypes.h"
@@ -40,7 +41,7 @@ namespace plib {
{
static constexpr const bool is_signed = std::numeric_limits<T>::is_signed;
static char32_t fmt_spec() { return 'u'; }
- static inline void streamify(std::ostream &s, const T &v)
+ static void streamify(std::ostream &s, const T &v)
{
s << v;
}
@@ -53,7 +54,7 @@ namespace plib {
// FIXME: need native support at some time
static constexpr const bool is_signed = true;
static char32_t fmt_spec() { return 'f'; }
- static inline void streamify(std::ostream &s, const FLOAT128 &v)
+ static void streamify(std::ostream &s, const FLOAT128 &v)
{
s << narrow_cast<long double>(v);
}
@@ -64,6 +65,19 @@ namespace plib {
struct ptype_traits;
template<>
+ struct ptype_traits<compile_info::int128_type>
+ {
+ // FIXME: need native support at some time
+ static constexpr const bool is_signed = true;
+ static char32_t fmt_spec() { return 'd'; }
+ template <typename T, typename = std::enable_if_t<plib::is_arithmetic<T>::value>>
+ static void streamify(std::ostream &s, const T &v)
+ {
+ s << narrow_cast<long long>(v);
+ }
+ };
+
+ template<>
struct ptype_traits<bool> : ptype_traits_base<bool>
{
};
@@ -160,6 +174,7 @@ namespace plib {
};
#endif
+
template<>
struct ptype_traits<char *> : ptype_traits_base<char *>
{
@@ -176,7 +191,7 @@ namespace plib {
struct ptype_traits<const char16_t *> : ptype_traits_base<const char16_t *>
{
static char32_t fmt_spec() { return 's'; }
- static inline void streamify(std::ostream &s, const char16_t *v)
+ static void streamify(std::ostream &s, const char16_t *v)
{
const putf16string su16(v);
s << putf8string(su16).c_str();
@@ -187,7 +202,7 @@ namespace plib {
struct ptype_traits<const char32_t *> : ptype_traits_base<const char32_t *>
{
static char32_t fmt_spec() { return 's'; }
- static inline void streamify(std::ostream &s, const char32_t *v)
+ static void streamify(std::ostream &s, const char32_t *v)
{
const putf32string su32(v);
s << putf8string(su32).c_str();
@@ -210,7 +225,7 @@ namespace plib {
struct ptype_traits<putf16string> : ptype_traits_base<putf16string>
{
static char32_t fmt_spec() { return 's'; }
- static inline void streamify(std::ostream &s, const putf16string &v)
+ static void streamify(std::ostream &s, const putf16string &v)
{
s << putf8string(v).c_str();
}
@@ -436,7 +451,7 @@ namespace plib {
fatal(logger)
{}
- PCOPYASSIGNMOVE(plog_base, default)
+ PCOPYASSIGNMOVE(plog_base, delete)
virtual ~plog_base() noexcept = default;
plog_channel<plog_level::DEBUG, debug_enabled> debug;
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp
index 5a00844becc..d592a90d670 100644
--- a/src/lib/netlist/plib/pfunction.cpp
+++ b/src/lib/netlist/plib/pfunction.cpp
@@ -118,7 +118,7 @@ namespace plib {
auto p = pcmds().find(cmd);
if (p != pcmds().end())
{
- rc.m_cmd = p->second.cmd;
+ rc = rpn_inst(p->second.cmd);
stk -= p->second.adj;
}
else
@@ -127,23 +127,20 @@ namespace plib {
{
if (inputs[i] == cmd)
{
- rc.m_cmd = PUSH_INPUT;
- rc.m_param.index = i;
+ rc = rpn_inst(PUSH_INPUT, i);
stk += 1;
break;
}
}
- if (rc.m_cmd != PUSH_INPUT)
+ if (rc.cmd() != PUSH_INPUT)
{
- using fl_t = decltype(rc.m_param.val);
- rc.m_cmd = PUSH_CONST;
bool err(false);
auto rs(plib::right(cmd,1));
- auto r=units_si<fl_t>().find(rs);
- if (r == units_si<fl_t>().end())
- rc.m_param.val = plib::pstonum_ne<fl_t>(cmd, err);
+ auto r=units_si<NT>().find(rs);
+ if (r == units_si<NT>().end())
+ rc = rpn_inst(plib::pstonum_ne<NT>(cmd, err));
else
- rc.m_param.val = plib::pstonum_ne<fl_t>(plib::left(cmd, cmd.size()-1), err) * r->second;
+ rc = rpn_inst(plib::pstonum_ne<NT>(plib::left(cmd, cmd.length()-1), err) * r->second);
if (err)
throw pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
stk += 1;
@@ -153,10 +150,13 @@ namespace plib {
throw pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
if (stk >= narrow_cast<int>(MAX_STACK))
throw pexception(plib::pfmt("pfunction: stack overflow on token <{1}> in <{2}>")(cmd)(expr));
+ if (rc.cmd() == LP || rc.cmd() == RP)
+ throw pexception(plib::pfmt("pfunction: parenthesis inequality on token <{1}> in <{2}>")(cmd)(expr));
m_precompiled.push_back(rc);
}
if (stk != 1)
throw pexception(plib::pfmt("pfunction: stack count {1} different to one on <{2}>")(stk, expr));
+ compress();
}
static bool is_number(const pstring &n)
@@ -339,27 +339,105 @@ namespace plib {
return narrow_cast<NT>(lfsr);
}
#endif
- #define ST0 stack[ptr+1]
- #define ST1 stack[ptr]
- #define ST2 stack[ptr-1]
+ #define ST0 *(ptr+1)
+ #define ST1 *ptr
+ #define ST2 *(ptr-1)
#define OP(OP, ADJ, EXPR) \
case OP: \
ptr-= (ADJ); \
- stack[ptr-1] = (EXPR); \
+ *(ptr-1) = (EXPR); \
+ break;
+
+ #define OP0(OP, EXPR) \
+ case OP: \
+ *(ptr++) = (EXPR); \
break;
template <typename NT>
NT pfunction<NT>::evaluate(const values_container &values) noexcept
{
- std::array<value_type, MAX_STACK> stack = { plib::constants<value_type>::zero() };
+ std::array<value_type, MAX_STACK> stack; // NOLINT
+ value_type *ptr = stack.data();
+ constexpr const auto zero = plib::constants<value_type>::zero();
+ constexpr const auto one = plib::constants<value_type>::one();
+ for (const auto &rc : m_precompiled)
+ {
+ switch (rc.cmd())
+ {
+ OP(ADD, 1, ST2 + ST1)
+ OP(MULT, 1, ST2 * ST1)
+ OP(SUB, 1, ST2 - ST1)
+ OP(DIV, 1, ST2 / ST1)
+ OP(EQ, 1, ST2 == ST1 ? one : zero)
+ OP(NE, 1, ST2 != ST1 ? one : zero)
+ OP(GT, 1, ST2 > ST1 ? one : zero)
+ OP(LT, 1, ST2 < ST1 ? one : zero)
+ OP(LE, 1, ST2 <= ST1 ? one : zero)
+ OP(GE, 1, ST2 >= ST1 ? one : zero)
+ OP(IF, 2, (ST2 != zero) ? ST1 : ST0)
+ OP(NEG, 0, -ST2)
+ OP(POW, 1, plib::pow(ST2, ST1))
+ OP(LOG, 0, plib::log(ST2))
+ OP(SIN, 0, plib::sin(ST2))
+ OP(COS, 0, plib::cos(ST2))
+ OP(MAX, 1, std::max(ST2, ST1))
+ OP(MIN, 1, std::min(ST2, ST1))
+ OP(TRUNC, 0, plib::trunc(ST2))
+ OP0(RAND, lfsr_random<value_type>(m_lfsr))
+ OP0(PUSH_INPUT, values[rc.index()])
+ OP0(PUSH_CONST, rc.value())
+ // please compiler
+ case LP:
+ case RP:
+ break;
+ }
+ }
+ return *(ptr-1);
+ }
+
+#undef ST0
+#undef ST1
+#undef ST2
+#undef OP
+#undef OP0
+
+#define ST0 m_precompiled[ptr+0].value()
+#define ST1 m_precompiled[ptr-1].value()
+#define ST2 m_precompiled[ptr-2].value()
+
+#define OP(OP, ADJ, EXPR) \
+ case OP: \
+ if (ADJ == 2) {\
+ if (m_precompiled[ptr-3].cmd() == PUSH_CONST && m_precompiled[ptr-2].cmd() == PUSH_CONST && m_precompiled[ptr-1].cmd() == PUSH_CONST) \
+ { ptr--; m_precompiled[ptr-2] = rpn_inst(EXPR); n -= 3; ptr++; std::copy(m_precompiled.begin()+(ptr+1), m_precompiled.end(), m_precompiled.begin()+(ptr-2)); ptr-=2;} \
+ else { ptr++; } \
+ } else if (ADJ == 1) {\
+ if (m_precompiled[ptr-2].cmd() == PUSH_CONST && m_precompiled[ptr-1].cmd() == PUSH_CONST) \
+ { m_precompiled[ptr-2] = rpn_inst(EXPR); n -= 2; std::copy(m_precompiled.begin()+(ptr+1), m_precompiled.end(), m_precompiled.begin()+(ptr-1)); ptr--;} \
+ else { ptr++; } \
+ } else if (ADJ == 0) {\
+ if (m_precompiled[ptr-1].cmd() == PUSH_CONST) \
+ { ptr++; m_precompiled[ptr-2] = rpn_inst(EXPR); n -= 1; ptr--; std::copy(m_precompiled.begin()+(ptr+1), m_precompiled.end(), m_precompiled.begin()+(ptr)); } \
+ else { ptr++; } \
+ } else ptr++; \
+ break;
+
+#define OP0(OP, EXPR) \
+ case OP: \
+ ptr++; \
+ break;
+
+ template <typename NT>
+ void pfunction<NT>::compress()
+ {
+ constexpr const auto zero = plib::constants<value_type>::zero();
+ constexpr const auto one = plib::constants<value_type>::one();
unsigned ptr = 0;
- constexpr auto zero = plib::constants<value_type>::zero();
- constexpr auto one = plib::constants<value_type>::one();
- stack[0] = plib::constants<value_type>::zero();
- for (auto &rc : m_precompiled)
+ auto n = m_precompiled.size();
+ for (; ptr < n; )
{
- switch (rc.m_cmd)
+ switch (m_precompiled[ptr].cmd())
{
OP(ADD, 1, ST2 + ST1)
OP(MULT, 1, ST2 * ST1)
@@ -380,22 +458,17 @@ namespace plib {
OP(MAX, 1, std::max(ST2, ST1))
OP(MIN, 1, std::min(ST2, ST1))
OP(TRUNC, 0, plib::trunc(ST2))
- case RAND:
- stack[ptr++] = lfsr_random<value_type>(m_lfsr);
- break;
- case PUSH_INPUT:
- stack[ptr++] = values[rc.m_param.index];
- break;
- case PUSH_CONST:
- stack[ptr++] = rc.m_param.val;
- break;
+ OP0(RAND, lfsr_random<value_type>(m_lfsr))
+ OP0(PUSH_INPUT, values[rc.index()])
+ OP0(PUSH_CONST, rc.value())
// please compiler
case LP:
case RP:
break;
}
}
- return stack[ptr-1];
+ //printf("func %lld %lld\n", m_precompiled.size(), n);
+ m_precompiled.resize(n);
}
template class pfunction<float>;
diff --git a/src/lib/netlist/plib/pfunction.h b/src/lib/netlist/plib/pfunction.h
index 0178e81c04e..9c2450d427c 100644
--- a/src/lib/netlist/plib/pfunction.h
+++ b/src/lib/netlist/plib/pfunction.h
@@ -58,10 +58,32 @@ namespace plib {
{
struct rpn_inst
{
- rpn_inst() : m_cmd(ADD)
+ constexpr rpn_inst() : m_cmd(ADD)
{
m_param.val = plib::constants<NT>::zero();
}
+ constexpr rpn_inst(rpn_cmd cmd, std::size_t index = 0)
+ : m_cmd(cmd)
+ {
+ m_param.index = index;
+ }
+ constexpr rpn_inst(NT v) : m_cmd(PUSH_CONST)
+ {
+ m_param.val = v;
+ }
+ constexpr const rpn_cmd &cmd() const noexcept
+ {
+ return m_cmd;
+ }
+ constexpr const NT &value() const noexcept
+ {
+ return m_param.val; // NOLINT
+ }
+ constexpr const std::size_t &index() const noexcept
+ {
+ return m_param.index; // NOLINT
+ }
+ private:
rpn_cmd m_cmd;
union
{
@@ -138,6 +160,7 @@ namespace plib {
private:
+ void compress();
void compile_postfix(const inputs_container &inputs,
const std::vector<pstring> &cmds, const pstring &expr);
diff --git a/src/lib/netlist/plib/pgsl.h b/src/lib/netlist/plib/pgsl.h
index ab7798071a5..cb95ecc334c 100644
--- a/src/lib/netlist/plib/pgsl.h
+++ b/src/lib/netlist/plib/pgsl.h
@@ -25,6 +25,8 @@
#if defined(__has_builtin) // clang and gcc 10
#if __has_builtin(__builtin_unreachable)
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable())
+ #else
+ #define gsl_Expects(e) ((e) ? static_cast<void>(0) : static_cast<void>(0))
#endif
#elif defined(__GNUC__) && !(defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ))
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : __builtin_unreachable())
@@ -34,8 +36,24 @@
#define gsl_Expects(e) ((e) ? static_cast<void>(0) : static_cast<void>(0))
#endif
+#if 1
+// FIXME: __builtin_unreachable contrary to google sources does not seem to be of
+// any use and decreases performance slightly. Convert gsl_Expects to a noop
+// and revisit in the future.
#undef gsl_Expects
#define gsl_Expects(e) do {} while (0)
+
+#if 0
+// Alternative and c++ style implementation. Suffers from the same drawbacks
+// like __builtin_unreachable
+static constexpr inline void gsl_Expects(const bool &e)
+{
+ if (!e)
+ __builtin_unreachable();
+}
+#endif
+#endif
+
#define gsl_Ensures(e) gsl_Expects(e)
namespace plib {
@@ -52,7 +70,7 @@ namespace plib {
/// \brief perform a narrowing cast without checks
///
template <typename T, typename O>
- inline constexpr T narrow_cast(O && v) noexcept
+ constexpr T narrow_cast(O && v) noexcept
{
static_assert(plib::is_arithmetic<T>::value && std::is_convertible<std::remove_reference_t<O>, T>::value, "narrow cast expects conversion between arithmetic types");
return static_cast<T>(std::forward<O>(v));
@@ -62,7 +80,7 @@ namespace plib {
///
/// The c++ core guidelines require the narrow function to raise an error
/// This will make narrow noexcept(false). This has shown to have a
- /// measurable impact on performance and thus we deviate we deviate from
+ /// measurable impact on performance and thus we deviate from
/// the standard here.
///
template <typename T, typename O>
@@ -82,14 +100,14 @@ namespace plib {
} // namespace pgsl
- /// \brief downcast from base tpye to derived type
+ /// \brief downcast from base type to derived type
///
/// The cpp core guidelines require a very careful use of static cast
/// for downcast operations. This template is used to identify these uses
/// and later for debug builds use dynamic_cast.
///
template <typename D, typename B>
- inline constexpr D downcast(B && b) noexcept
+ constexpr D downcast(B && b) noexcept
{
static_assert(std::is_pointer<D>::value || std::is_reference<D>::value, "downcast only supports pointers or reference for derived");
static_assert(std::is_pointer<B>::value || std::is_reference<B>::value, "downcast only supports pointers or reference for base");
@@ -97,6 +115,15 @@ namespace plib {
}
using pgsl::narrow_cast;
+
+ /// \brief cast to void *
+ ///
+ /// The purpose here is to help identifiy casts to void in the code.
+ /// These case usuallyindicate some wizard assumptioms which should be easily
+ /// be easy to identify.
+ template <typename T>
+ constexpr void * void_ptr_cast(T *ptr) noexcept { return static_cast<void *>(ptr); }
+
} // namespace plib
//FIXME: This is the place to use more complete implementations
diff --git a/src/lib/netlist/plib/plists.h b/src/lib/netlist/plib/plists.h
index 328f0b1ad23..41f68d989c2 100755
--- a/src/lib/netlist/plib/plists.h
+++ b/src/lib/netlist/plib/plists.h
@@ -42,7 +42,11 @@ namespace plib {
//uninitialised_array_t() noexcept = default;
uninitialised_array() noexcept = default;
- PCOPYASSIGNMOVE(uninitialised_array, delete)
+ uninitialised_array(const uninitialised_array &) = default;
+ uninitialised_array &operator=(const uninitialised_array &) = default;
+ uninitialised_array(uninitialised_array &&) noexcept = default;
+ uninitialised_array &operator=(uninitialised_array &&) noexcept = default;
+
~uninitialised_array() noexcept = default;
constexpr size_t size() const noexcept { return N; }
@@ -111,7 +115,11 @@ namespace plib {
{
}
- PCOPYASSIGNMOVE(static_vector, delete)
+ static_vector(const static_vector &) = default;
+ static_vector &operator=(const static_vector &) = default;
+ static_vector(static_vector &&) noexcept = default;
+ static_vector &operator=(static_vector &&) noexcept = default;
+
~static_vector() noexcept
{
clear();
@@ -172,7 +180,7 @@ namespace plib {
/// \brief a simple linked list.
///
- /// The list allows insertions deletions whilst being processed.
+ /// The list allows insertions and deletions whilst being processed.
///
template <class LC>
class linkedlist_t
@@ -187,10 +195,13 @@ namespace plib {
constexpr element_t() : m_next(nullptr), m_prev(nullptr) {}
~element_t() noexcept = default;
- PCOPYASSIGNMOVE(element_t, delete)
+ element_t(const element_t &) = default; \
+ element_t &operator=(const element_t &) = default;
+ element_t(element_t &&) noexcept = default;
+ element_t &operator=(element_t &&) noexcept = default;
- constexpr LC *next() const noexcept { return m_next; }
- constexpr LC *prev() const noexcept { return m_prev; }
+ constexpr LC * &next() noexcept { return m_next; }
+ constexpr LC * &prev() noexcept { return m_prev; }
private:
LC * m_next;
LC * m_prev;
@@ -202,22 +213,14 @@ namespace plib {
LC* p;
public:
explicit constexpr iter_t(LC* x) noexcept : p(x) { }
- constexpr iter_t(iter_t &rhs) noexcept : p(rhs.p) { }
- iter_t(iter_t &&rhs) noexcept { std::swap(*this, rhs); }
-
- iter_t& operator=(const iter_t &rhs) noexcept // NOLINT(bugprone-unhandled-self-assignment, cert-oop54-cpp)
- {
- if (this == &rhs)
- return *this;
-
- p = rhs.p;
- return *this;
- }
+ constexpr iter_t(const iter_t &rhs) noexcept = default;
+ iter_t(iter_t &&rhs) noexcept = default;
- iter_t& operator=(iter_t &&rhs) noexcept { std::swap(*this, rhs); return *this; }
- ~iter_t() = default;
+ iter_t& operator=(const iter_t &rhs) noexcept = default;
+ iter_t& operator=(iter_t &&rhs) noexcept = default;
+ ~iter_t() noexcept = default;
- iter_t& operator++() noexcept { p = p->next();return *this; }
+ iter_t& operator++() noexcept { p = p->next(); return *this; }
// NOLINTNEXTLINE(cert-dcl21-cpp)
iter_t operator++(int) & noexcept { const iter_t tmp(*this); operator++(); return tmp; }
diff --git a/src/lib/netlist/plib/pmath.h b/src/lib/netlist/plib/pmath.h
index 02d634529a0..a59f566a91d 100644
--- a/src/lib/netlist/plib/pmath.h
+++ b/src/lib/netlist/plib/pmath.h
@@ -30,50 +30,50 @@ namespace plib
template <typename T>
struct constants
{
- static inline constexpr T zero() noexcept { return static_cast<T>(0); } // NOLINT
- static inline constexpr T half() noexcept { return static_cast<T>(0.5); } // NOLINT
- static inline constexpr T one() noexcept { return static_cast<T>(1); } // NOLINT
- static inline constexpr T two() noexcept { return static_cast<T>(2); } // NOLINT
- static inline constexpr T three() noexcept { return static_cast<T>(3); } // NOLINT
- static inline constexpr T four() noexcept { return static_cast<T>(4); } // NOLINT
- static inline constexpr T hundred()noexcept { return static_cast<T>(100); } // NOLINT
-
- static inline constexpr T one_thirds() noexcept { return fraction(one(), three()); }
- static inline constexpr T two_thirds() noexcept { return fraction(two(), three()); }
-
- static inline constexpr T ln2() noexcept { return static_cast<T>(0.6931471805599453094172321214581766L); } // NOLINT
- static inline constexpr T sqrt2() noexcept { return static_cast<T>(1.4142135623730950488016887242096982L); } // NOLINT
- static inline constexpr T sqrt3() noexcept { return static_cast<T>(1.7320508075688772935274463415058723L); } // NOLINT
- static inline constexpr T sqrt3_2() noexcept { return static_cast<T>(0.8660254037844386467637231707529362L); } // NOLINT
- static inline constexpr T pi() noexcept { return static_cast<T>(3.1415926535897932384626433832795029L); } // NOLINT
+ static constexpr T zero() noexcept { return static_cast<T>(0); } // NOLINT
+ static constexpr T half() noexcept { return static_cast<T>(0.5); } // NOLINT
+ static constexpr T one() noexcept { return static_cast<T>(1); } // NOLINT
+ static constexpr T two() noexcept { return static_cast<T>(2); } // NOLINT
+ static constexpr T three() noexcept { return static_cast<T>(3); } // NOLINT
+ static constexpr T four() noexcept { return static_cast<T>(4); } // NOLINT
+ static constexpr T hundred()noexcept { return static_cast<T>(100); } // NOLINT
+
+ static constexpr T one_thirds() noexcept { return fraction(one(), three()); }
+ static constexpr T two_thirds() noexcept { return fraction(two(), three()); }
+
+ static constexpr T ln2() noexcept { return static_cast<T>(0.6931471805599453094172321214581766L); } // NOLINT
+ static constexpr T sqrt2() noexcept { return static_cast<T>(1.4142135623730950488016887242096982L); } // NOLINT
+ static constexpr T sqrt3() noexcept { return static_cast<T>(1.7320508075688772935274463415058723L); } // NOLINT
+ static constexpr T sqrt3_2() noexcept { return static_cast<T>(0.8660254037844386467637231707529362L); } // NOLINT
+ static constexpr T pi() noexcept { return static_cast<T>(3.1415926535897932384626433832795029L); } // NOLINT
/// \brief Electric constant of vacuum
///
- static inline constexpr T eps_0() noexcept { return static_cast<T>(8.854187817e-12); } // NOLINT
+ static constexpr T eps_0() noexcept { return static_cast<T>(8.854187817e-12); } // NOLINT
// \brief Relative permittivity of Silicon dioxide
///
- static inline constexpr T eps_SiO2() noexcept { return static_cast<T>(3.9); } // NOLINT
+ static constexpr T eps_SiO2() noexcept { return static_cast<T>(3.9); } // NOLINT
/// \brief Relative permittivity of Silicon
///
- static inline constexpr T eps_Si() noexcept { return static_cast<T>(11.7); } // NOLINT
+ static constexpr T eps_Si() noexcept { return static_cast<T>(11.7); } // NOLINT
/// \brief Boltzmann constant
///
- static inline constexpr T k_b() noexcept { return static_cast<T>(1.38064852e-23); } // NOLINT
+ static constexpr T k_b() noexcept { return static_cast<T>(1.38064852e-23); } // NOLINT
/// \brief room temperature (gives VT = 0.02585 at T=300)
///
- static inline constexpr T T0() noexcept { return static_cast<T>(300); } // NOLINT
+ static constexpr T T0() noexcept { return static_cast<T>(300); } // NOLINT
/// \brief Elementary charge
///
- static inline constexpr T Q_e() noexcept { return static_cast<T>(1.6021765314e-19); } // NOLINT
+ static constexpr T Q_e() noexcept { return static_cast<T>(1.6021765314e-19); } // NOLINT
/// \brief Intrinsic carrier concentration in 1/m^3 of Silicon
///
- static inline constexpr T NiSi() noexcept { return static_cast<T>(1.45e16); } // NOLINT
+ static constexpr T NiSi() noexcept { return static_cast<T>(1.45e16); } // NOLINT
/// \brief clearly identify magic numbers in code
///
@@ -82,10 +82,10 @@ namespace plib
/// later.
///
template <typename V>
- static inline constexpr T magic(V &&v) noexcept { return static_cast<T>(v); }
+ static constexpr T magic(V &&v) noexcept { return static_cast<T>(v); }
template <typename V>
- static inline constexpr T fraction(V &&v1, V &&v2) noexcept { return static_cast<T>(v1 / v2); }
+ static constexpr T fraction(V &&v1, V &&v2) noexcept { return static_cast<T>(v1 / v2); }
};
/// \brief typesafe reciprocal function
@@ -95,7 +95,7 @@ namespace plib
/// \return reciprocal of argument
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
reciprocal(T v) noexcept
{
return constants<T>::one() / v;
@@ -108,7 +108,7 @@ namespace plib
/// \return absolute value of argument
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
abs(T v) noexcept
{
return std::abs(v);
@@ -121,7 +121,7 @@ namespace plib
/// \return absolute value of argument
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
sqrt(T v) noexcept
{
return std::sqrt(v);
@@ -135,7 +135,7 @@ namespace plib
/// \return sqrt(v1*v1+v2*v2)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
hypot(T v1, T v2) noexcept
{
return std::hypot(v1, v2);
@@ -148,7 +148,7 @@ namespace plib
/// \return exp(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
exp(T v) noexcept
{
return std::exp(v);
@@ -161,7 +161,7 @@ namespace plib
/// \return log(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
log(T v) noexcept
{
return std::log(v);
@@ -174,7 +174,7 @@ namespace plib
/// \return tanh(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
tanh(T v) noexcept
{
return std::tanh(v);
@@ -187,7 +187,7 @@ namespace plib
/// \return floor(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
floor(T v) noexcept
{
return std::floor(v);
@@ -200,7 +200,7 @@ namespace plib
/// \return log(1 + v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
log1p(T v) noexcept
{
return std::log1p(v);
@@ -213,7 +213,7 @@ namespace plib
/// \return sin(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
sin(T v) noexcept
{
return std::sin(v);
@@ -226,7 +226,7 @@ namespace plib
/// \return cos(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
cos(T v) noexcept
{
return std::cos(v);
@@ -239,7 +239,7 @@ namespace plib
/// \return trunc(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
trunc(T v) noexcept
{
return std::trunc(v);
@@ -253,7 +253,7 @@ namespace plib
/// \return signum(v)
///
template <typename T>
- static inline constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
+ static constexpr std::enable_if_t<std::is_floating_point<T>::value, T>
signum(T v, T r = static_cast<T>(1))
{
constexpr const auto z(static_cast<T>(0));
@@ -278,73 +278,73 @@ namespace plib
}
#if (PUSE_FLOAT128)
- static inline constexpr FLOAT128 reciprocal(FLOAT128 v) noexcept
+ static constexpr FLOAT128 reciprocal(FLOAT128 v) noexcept
{
return constants<FLOAT128>::one() / v;
}
- static inline FLOAT128 abs(FLOAT128 v) noexcept
+ static FLOAT128 abs(FLOAT128 v) noexcept
{
return fabsq(v);
}
- static inline FLOAT128 sqrt(FLOAT128 v) noexcept
+ static FLOAT128 sqrt(FLOAT128 v) noexcept
{
return sqrtq(v);
}
- static inline FLOAT128 hypot(FLOAT128 v1, FLOAT128 v2) noexcept
+ static FLOAT128 hypot(FLOAT128 v1, FLOAT128 v2) noexcept
{
return hypotq(v1, v2);
}
- static inline FLOAT128 exp(FLOAT128 v) noexcept
+ static FLOAT128 exp(FLOAT128 v) noexcept
{
return expq(v);
}
- static inline FLOAT128 log(FLOAT128 v) noexcept
+ static FLOAT128 log(FLOAT128 v) noexcept
{
return logq(v);
}
- static inline FLOAT128 tanh(FLOAT128 v) noexcept
+ static FLOAT128 tanh(FLOAT128 v) noexcept
{
return tanhq(v);
}
- static inline FLOAT128 floor(FLOAT128 v) noexcept
+ static FLOAT128 floor(FLOAT128 v) noexcept
{
return floorq(v);
}
- static inline FLOAT128 log1p(FLOAT128 v) noexcept
+ static FLOAT128 log1p(FLOAT128 v) noexcept
{
return log1pq(v);
}
- static inline FLOAT128 sin(FLOAT128 v) noexcept
+ static FLOAT128 sin(FLOAT128 v) noexcept
{
return sinq(v);
}
- static inline FLOAT128 cos(FLOAT128 v) noexcept
+ static FLOAT128 cos(FLOAT128 v) noexcept
{
return cosq(v);
}
- static inline FLOAT128 trunc(FLOAT128 v) noexcept
+ static FLOAT128 trunc(FLOAT128 v) noexcept
{
return truncq(v);
}
template <typename T>
- static inline FLOAT128 pow(FLOAT128 v, T p) noexcept
+ static FLOAT128 pow(FLOAT128 v, T p) noexcept
{
return powq(v, static_cast<FLOAT128>(p));
}
- static inline FLOAT128 pow(FLOAT128 v, int p) noexcept
+ static FLOAT128 pow(FLOAT128 v, int p) noexcept
{
if (p==2)
return v*v;
diff --git a/src/lib/netlist/plib/pmatrix2d.h b/src/lib/netlist/plib/pmatrix2d.h
index d0fbac26194..d0ce462ebfa 100755
--- a/src/lib/netlist/plib/pmatrix2d.h
+++ b/src/lib/netlist/plib/pmatrix2d.h
@@ -51,7 +51,10 @@ namespace plib
::new(&m_v[i]) T();
}
- PCOPYASSIGNMOVE(pmatrix2d, delete)
+ pmatrix2d(const pmatrix2d &) = delete;
+ pmatrix2d &operator=(const pmatrix2d &) = delete;
+ pmatrix2d(pmatrix2d &&) = delete;
+ pmatrix2d &operator=(pmatrix2d &&) = delete;
~pmatrix2d()
{
@@ -157,7 +160,11 @@ namespace plib
m_v.resize(N); //FIXME
}
- PCOPYASSIGNMOVE(pmatrix2d_vrl, default)
+ pmatrix2d_vrl(const pmatrix2d_vrl &) = default;
+ pmatrix2d_vrl &operator=(const pmatrix2d_vrl &) = default;
+ pmatrix2d_vrl(pmatrix2d_vrl &&) = default;
+ pmatrix2d_vrl &operator=(pmatrix2d_vrl &&) = default;
+
~pmatrix2d_vrl() = default;
void resize(size_type N, size_type M)
diff --git a/src/lib/netlist/plib/mat_cr.h b/src/lib/netlist/plib/pmatrix_cr.h
index 17ce140c6e5..05ba82f1b0e 100644
--- a/src/lib/netlist/plib/mat_cr.h
+++ b/src/lib/netlist/plib/pmatrix_cr.h
@@ -1,11 +1,11 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
-#ifndef MAT_CR_H_
-#define MAT_CR_H_
+#ifndef PMATRIX_CR_H_
+#define PMATRIX_CR_H_
///
-/// \file mat_cr.h
+/// \file pmatrix_cr.h
///
/// Compressed row format matrices
///
@@ -16,9 +16,7 @@
#include "pmath.h"
#include "pmatrix2d.h"
#include "pomp.h"
-#include "pstate.h"
#include "ptypes.h"
-#include "putil.h"
#include <algorithm>
#include <array>
@@ -29,7 +27,7 @@ namespace plib
{
template<typename T, int N, typename C = uint16_t>
- struct pmatrix_cr_t
+ struct pmatrix_cr
{
using index_type = C;
using value_type = T;
@@ -37,7 +35,10 @@ namespace plib
static constexpr const int NSQ = (N < 0 ? -N * N : N * N);
static constexpr const int Np1 = (N == 0) ? 0 : (N < 0 ? N - 1 : N + 1);
- PCOPYASSIGNMOVE(pmatrix_cr_t, default)
+ pmatrix_cr(const pmatrix_cr &) = default;
+ pmatrix_cr &operator=(const pmatrix_cr &) = default;
+ pmatrix_cr(pmatrix_cr &&) noexcept(std::is_nothrow_move_constructible<parray<value_type, NSQ>>::value) = default;
+ pmatrix_cr &operator=(pmatrix_cr &&) noexcept(std::is_nothrow_move_assignable<parray<value_type, NSQ>>::value && std::is_nothrow_move_assignable<pmatrix2d_vrl<index_type>>::value) = default;
enum constants_e
{
@@ -56,7 +57,7 @@ namespace plib
// NOLINTNEXTLINE
std::size_t nz_num;
- explicit pmatrix_cr_t(std::size_t n)
+ explicit pmatrix_cr(std::size_t n)
: diag(n)
, row_idx(n+1)
, col_idx(n*n)
@@ -72,7 +73,7 @@ namespace plib
}
}
- ~pmatrix_cr_t() = default;
+ ~pmatrix_cr() = default;
constexpr std::size_t size() const noexcept { return (N>0) ? narrow_cast<std::size_t>(N) : m_size; }
@@ -149,17 +150,10 @@ namespace plib
for (std::size_t k=0; k < size(); k++)
{
-#if 0
- for (std::size_t j=k + 1; j < size(); j++)
- if (f[j][k] < FILL_INFINITY)
- m_nzbd[k].push_back(narrow_cast<C>(j));
- m_nzbd[k].push_back(0); // end of sequence
-#else
for (std::size_t j=k + 1; j < size(); j++)
if (f[j][k] < FILL_INFINITY)
m_nzbd.set(k, m_nzbd.colcount(k), narrow_cast<C>(j));
m_nzbd.set(k, m_nzbd.colcount(k), 0); // end of sequence
-#endif
}
}
@@ -169,17 +163,6 @@ namespace plib
{
// res = A * x
-#if 0
- //plib::omp::set_num_threads(4);
- plib::omp::for_static(0, constants<std::size_t>::zero(), m_size, [this, &res, &x](std::size_t row)
- {
- T tmp(0.0);
- const std::size_t e(row_idx[row+1]);
- for (std::size_t k = row_idx[row]; k < e; k++)
- tmp += A[k] * x[col_idx[k]];
- res[row] = tmp;
- });
-#else
// this is a bit faster than the version above
std::size_t row = 0;
std::size_t k = 0;
@@ -192,7 +175,6 @@ namespace plib
tmp += A[k] * x[col_idx[k]];
res[row++] = tmp;
}
-#endif
}
// throws error if P(source)>P(destination)
@@ -262,19 +244,22 @@ namespace plib
};
template<typename B>
- struct pGEmatrix_cr_t : public B
+ struct pGEmatrix_cr : public B
{
- using base = B;
- using index_type = typename base::index_type;
+ using base_type = B;
+ using index_type = typename base_type::index_type;
- PCOPYASSIGNMOVE(pGEmatrix_cr_t, default)
+ pGEmatrix_cr(const pGEmatrix_cr &) = default;
+ pGEmatrix_cr &operator=(const pGEmatrix_cr &) = default;
+ pGEmatrix_cr(pGEmatrix_cr &&) noexcept(std::is_nothrow_move_constructible<base_type>::value) = default;
+ pGEmatrix_cr &operator=(pGEmatrix_cr &&) noexcept(std::is_nothrow_move_assignable<base_type>::value) = default;
- explicit pGEmatrix_cr_t(std::size_t n)
+ explicit pGEmatrix_cr(std::size_t n)
: B(n)
{
}
- ~pGEmatrix_cr_t() = default;
+ ~pGEmatrix_cr() = default;
template <typename M>
std::pair<std::size_t, std::size_t> gaussian_extend_fill_mat(M &fill)
@@ -287,14 +272,14 @@ namespace plib
ops++; // 1/A(k,k)
for (std::size_t row = k + 1; row < fill.size(); row++)
{
- if (fill[row][k] < base::FILL_INFINITY)
+ if (fill[row][k] < base_type::FILL_INFINITY)
{
ops++;
for (std::size_t col = k + 1; col < fill[row].size(); col++)
//if (fill[k][col] < FILL_INFINITY)
{
auto f = std::min(fill[row][col], 1 + fill[row][k] + fill[k][col]);
- if (f < base::FILL_INFINITY)
+ if (f < base_type::FILL_INFINITY)
{
if (f > fill_max)
fill_max = f;
@@ -312,37 +297,37 @@ namespace plib
template <typename V>
void gaussian_elimination(V & RHS)
{
- const std::size_t iN = base::size();
+ const std::size_t iN = base_type::size();
for (std::size_t i = 0; i < iN - 1; i++)
{
std::size_t nzbdp = 0;
- std::size_t pi = base::diag[i];
- auto f = reciprocal(base::A[pi++]);
- const std::size_t piie = base::row_idx[i+1];
+ std::size_t pi = base_type::diag[i];
+ auto f = reciprocal(base_type::A[pi++]);
+ const std::size_t piie = base_type::row_idx[i+1];
- const auto *nz = base::m_nzbd[i];
+ const auto *nz = base_type::m_nzbd[i];
while (auto j = nz[nzbdp++]) // NOLINT(bugprone-infinite-loop)
{
// proceed to column i
- std::size_t pj = base::row_idx[j];
- std::size_t pje = base::row_idx[j+1];
+ std::size_t pj = base_type::row_idx[j];
+ std::size_t pje = base_type::row_idx[j+1];
- while (base::col_idx[pj] < i)
+ while (base_type::col_idx[pj] < i)
pj++;
- const typename base::value_type f1 = - base::A[pj++] * f;
+ const typename base_type::value_type f1 = - base_type::A[pj++] * f;
// subtract row i from j
// fill-in available assumed, i.e. matrix was prepared
for (std::size_t pii = pi; pii<piie && pj < pje; pii++)
{
- while (base::col_idx[pj] < base::col_idx[pii])
+ while (base_type::col_idx[pj] < base_type::col_idx[pii])
pj++;
- if (base::col_idx[pj] == base::col_idx[pii])
- base::A[pj++] += base::A[pii] * f1;
+ if (base_type::col_idx[pj] == base_type::col_idx[pii])
+ base_type::A[pj++] += base_type::A[pii] * f1;
}
RHS[j] += f1 * RHS[i];
@@ -363,35 +348,35 @@ namespace plib
{
//printf("omp: %ld %d %d\n", m_ge_par.size(), nz_num, (int)m_ge_par[m_ge_par.size()-2].size());
for (auto l = 0UL; l < m_ge_par.size(); l++)
- plib::omp::for_static(base::nz_num, 0UL, m_ge_par[l].size(), [this, &RHS, &l] (unsigned ll)
+ plib::omp::for_static(base_type::nz_num, 0UL, m_ge_par[l].size(), [this, &RHS, &l] (unsigned ll)
{
auto &i = m_ge_par[l][ll];
{
std::size_t nzbdp = 0;
- std::size_t pi = base::diag[i];
- const auto f = reciprocal(base::A[pi++]);
- const std::size_t piie = base::row_idx[i+1];
- const auto &nz = base::nzbd[i];
+ std::size_t pi = base_type::diag[i];
+ const auto f = reciprocal(base_type::A[pi++]);
+ const std::size_t piie = base_type::row_idx[i+1];
+ const auto &nz = base_type::nzbd[i];
while (auto j = nz[nzbdp++])
{
// proceed to column i
- std::size_t pj = base::row_idx[j];
+ std::size_t pj = base_type::row_idx[j];
- while (base::col_idx[pj] < i)
+ while (base_type::col_idx[pj] < i)
pj++;
- auto f1 = - base::A[pj++] * f;
+ auto f1 = - base_type::A[pj++] * f;
// subtract row i from j
// fill-in available assumed, i.e. matrix was prepared
for (std::size_t pii = pi; pii<piie; pii++)
{
- while (base::col_idx[pj] < base::col_idx[pii])
+ while (base_type::col_idx[pj] < base_type::col_idx[pii])
pj++;
- if (base::col_idx[pj] == base::col_idx[pii])
- base::A[pj++] += base::A[pii] * f1;
+ if (base_type::col_idx[pj] == base_type::col_idx[pii])
+ base_type::A[pj++] += base_type::A[pii] * f1;
}
RHS[j] += f1 * RHS[i];
}
@@ -402,36 +387,36 @@ namespace plib
template <typename V1, typename V2>
void gaussian_back_substitution(V1 &V, const V2 &RHS)
{
- const std::size_t iN = base::size();
+ const std::size_t iN = base_type::size();
// row n-1
- V[iN - 1] = RHS[iN - 1] / base::A[base::diag[iN - 1]];
+ V[iN - 1] = RHS[iN - 1] / base_type::A[base_type::diag[iN - 1]];
for (std::size_t j = iN - 1; j-- > 0;)
{
- typename base::value_type tmp = 0;
- const auto jdiag = base::diag[j];
- const std::size_t e = base::row_idx[j+1];
+ typename base_type::value_type tmp = 0;
+ const auto jdiag = base_type::diag[j];
+ const std::size_t e = base_type::row_idx[j+1];
for (std::size_t pk = jdiag + 1; pk < e; pk++)
- tmp += base::A[pk] * V[base::col_idx[pk]];
- V[j] = (RHS[j] - tmp) / base::A[jdiag];
+ tmp += base_type::A[pk] * V[base_type::col_idx[pk]];
+ V[j] = (RHS[j] - tmp) / base_type::A[jdiag];
}
}
template <typename V1>
void gaussian_back_substitution(V1 &V)
{
- const std::size_t iN = base::size();
+ const std::size_t iN = base_type::size();
// row n-1
- V[iN - 1] = V[iN - 1] / base::A[base::diag[iN - 1]];
+ V[iN - 1] = V[iN - 1] / base_type::A[base_type::diag[iN - 1]];
for (std::size_t j = iN - 1; j-- > 0;)
{
- typename base::value_type tmp = 0;
- const auto jdiag = base::diag[j];
- const std::size_t e = base::row_idx[j+1];
+ typename base_type::value_type tmp = 0;
+ const auto jdiag = base_type::diag[j];
+ const std::size_t e = base_type::row_idx[j+1];
for (std::size_t pk = jdiag + 1; pk < e; pk++)
- tmp += base::A[pk] * V[base::col_idx[pk]];
- V[j] = (V[j] - tmp) / base::A[jdiag];
+ tmp += base_type::A[pk] * V[base_type::col_idx[pk]];
+ V[j] = (V[j] - tmp) / base_type::A[jdiag];
}
}
@@ -440,27 +425,27 @@ namespace plib
void build_parallel_gaussian_execution_scheme(const M &fill)
{
// calculate parallel scheme for gaussian elimination
- std::vector<std::vector<std::size_t>> rt(base::size());
- for (std::size_t k = 0; k < base::size(); k++)
+ std::vector<std::vector<std::size_t>> rt(base_type::size());
+ for (std::size_t k = 0; k < base_type::size(); k++)
{
- for (std::size_t j = k+1; j < base::size(); j++)
+ for (std::size_t j = k+1; j < base_type::size(); j++)
{
- if (fill[j][k] < base::FILL_INFINITY)
+ if (fill[j][k] < base_type::FILL_INFINITY)
{
rt[k].push_back(j);
}
}
}
- std::vector<std::size_t> levGE(base::size(), 0);
+ std::vector<std::size_t> levGE(base_type::size(), 0);
std::size_t cl = 0;
- for (std::size_t k = 0; k < base::size(); k++ )
+ for (std::size_t k = 0; k < base_type::size(); k++ )
{
if (levGE[k] >= cl)
{
std::vector<std::size_t> t = rt[k];
- for (std::size_t j = k+1; j < base::size(); j++ )
+ for (std::size_t j = k+1; j < base_type::size(); j++ )
{
bool overlap = false;
// is there overlap
@@ -487,7 +472,7 @@ namespace plib
m_ge_par.clear();
m_ge_par.resize(cl+1);
- for (std::size_t k = 0; k < base::size(); k++)
+ for (std::size_t k = 0; k < base_type::size(); k++)
m_ge_par[levGE[k]].push_back(k);
//for (std::size_t k = 0; k < m_ge_par.size(); k++)
// printf("%d %d\n", (int) k, (int) m_ge_par[k].size());
@@ -496,21 +481,24 @@ namespace plib
};
template<typename B>
- struct pLUmatrix_cr_t : public B
+ struct pLUmatrix_cr : public B
{
- using base = B;
- using index_type = typename base::index_type;
+ using base_type = B;
+ using index_type = typename base_type::index_type;
- PCOPYASSIGNMOVE(pLUmatrix_cr_t, default)
+ pLUmatrix_cr(const pLUmatrix_cr &) = default;
+ pLUmatrix_cr &operator=(const pLUmatrix_cr &) = default;
+ pLUmatrix_cr(pLUmatrix_cr &&) noexcept(std::is_nothrow_move_constructible<base_type>::value) = default;
+ pLUmatrix_cr &operator=(pLUmatrix_cr &&) noexcept(std::is_nothrow_move_assignable<base_type>::value) = default;
- explicit pLUmatrix_cr_t(std::size_t n)
+ explicit pLUmatrix_cr(std::size_t n)
: B(n)
, ilu_rows(n+1)
, m_ILUp(0)
{
}
- ~pLUmatrix_cr_t() = default;
+ ~pLUmatrix_cr() = default;
template <typename M>
void build(M &fill, std::size_t ilup)
@@ -560,7 +548,7 @@ namespace plib
/// k=k+1
/// i=i+1
///
- void incomplete_LU_factorization(const base &mat)
+ void incomplete_LU_factorization(const base_type &mat)
{
if (m_ILUp < 1)
this->raw_copy_from(mat);
@@ -570,27 +558,27 @@ namespace plib
std::size_t p(0);
while (auto i = ilu_rows[p++]) // NOLINT(bugprone-infinite-loop)
{
- const auto p_i_end = base::row_idx[i + 1];
+ const auto p_i_end = base_type::row_idx[i + 1];
// loop over all columns k left of diag in row i
//if (row_idx[i] < diag[i])
// printf("occ %d\n", (int)i);
- for (auto i_k = base::row_idx[i]; i_k < base::diag[i]; i_k++)
+ for (auto i_k = base_type::row_idx[i]; i_k < base_type::diag[i]; i_k++)
{
- const auto k(base::col_idx[i_k]);
- const auto p_k_end(base::row_idx[k + 1]);
- const typename base::value_type LUp_i_k = base::A[i_k] = base::A[i_k] / base::A[base::diag[k]];
+ const auto k(base_type::col_idx[i_k]);
+ const auto p_k_end(base_type::row_idx[k + 1]);
+ const typename base_type::value_type LUp_i_k = base_type::A[i_k] = base_type::A[i_k] / base_type::A[base_type::diag[k]];
- std::size_t k_j(base::diag[k] + 1);
+ std::size_t k_j(base_type::diag[k] + 1);
std::size_t i_j(i_k + 1);
while (i_j < p_i_end && k_j < p_k_end ) // pj = (i, j)
{
// we can assume that within a row ja increases continuously
- const std::size_t c_i_j(base::col_idx[i_j]); // row i, column j
- const auto c_k_j(base::col_idx[k_j]); // row k, column j
+ const std::size_t c_i_j(base_type::col_idx[i_j]); // row i, column j
+ const auto c_k_j(base_type::col_idx[k_j]); // row k, column j
if (c_k_j == c_i_j)
- base::A[i_j] -= LUp_i_k * base::A[k_j];
+ base_type::A[i_j] -= LUp_i_k * base_type::A[k_j];
k_j += (c_k_j <= c_i_j ? 1 : 0);
i_j += (c_k_j >= c_i_j ? 1 : 0);
@@ -625,32 +613,32 @@ namespace plib
template <typename R>
void solveLU (R &r)
{
- for (std::size_t i = 1; i < base::size(); ++i )
+ for (std::size_t i = 1; i < base_type::size(); ++i )
{
- typename base::value_type tmp(0);
- const auto j1(base::row_idx[i]);
- const auto j2(base::diag[i]);
+ typename base_type::value_type tmp(0);
+ const auto j1(base_type::row_idx[i]);
+ const auto j2(base_type::diag[i]);
for (auto j = j1; j < j2; ++j )
- tmp += base::A[j] * r[base::col_idx[j]];
+ tmp += base_type::A[j] * r[base_type::col_idx[j]];
r[i] -= tmp;
}
// i now is equal to n;
- for (std::size_t i = base::size(); i-- > 0; )
+ for (std::size_t i = base_type::size(); i-- > 0; )
{
- typename base::value_type tmp(0);
- const auto di(base::diag[i]);
- const auto j2(base::row_idx[i+1]);
+ typename base_type::value_type tmp(0);
+ const auto di(base_type::diag[i]);
+ const auto j2(base_type::row_idx[i+1]);
for (std::size_t j = di + 1; j < j2; j++ )
- tmp += base::A[j] * r[base::col_idx[j]];
- r[i] = (r[i] - tmp) / base::A[di];
+ tmp += base_type::A[j] * r[base_type::col_idx[j]];
+ r[i] = (r[i] - tmp) / base_type::A[di];
}
}
private:
- parray<index_type, base::Np1> ilu_rows;
+ parray<index_type, base_type::Np1> ilu_rows;
std::size_t m_ILUp;
};
} // namespace plib
-#endif // MAT_CR_H_
+#endif // PMATRIX_CR_H_
diff --git a/src/lib/netlist/plib/pmempool.h b/src/lib/netlist/plib/pmempool.h
index 4e678cb09d6..b83f08e0f49 100644
--- a/src/lib/netlist/plib/pmempool.h
+++ b/src/lib/netlist/plib/pmempool.h
@@ -168,8 +168,11 @@ namespace plib {
struct info
{
info(block *b, size_type p) : m_block(b), m_pos(p) { }
+ info(const info &) = default;
+ info &operator=(const info &) = default;
+ info(info &&) noexcept = default;
+ info &operator=(info &&) noexcept = default;
~info() = default;
- PCOPYASSIGNMOVE(info, default)
block * m_block;
size_type m_pos;
diff --git a/src/lib/netlist/plib/pmulti_threading.h b/src/lib/netlist/plib/pmulti_threading.h
index 9f470054e2d..7c58a936636 100644
--- a/src/lib/netlist/plib/pmulti_threading.h
+++ b/src/lib/netlist/plib/pmulti_threading.h
@@ -23,9 +23,9 @@ namespace plib {
struct pspin_mutex
{
public:
- pspin_mutex() noexcept = default;
- void lock() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } }
- void unlock() noexcept { m_lock.clear(std::memory_order_release); }
+ inline pspin_mutex() noexcept = default;
+ inline void lock() noexcept{ while (m_lock.test_and_set(std::memory_order_acquire)) { } }
+ inline void unlock() noexcept { m_lock.clear(std::memory_order_release); }
private:
PALIGNAS_CACHELINE()
std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
@@ -35,8 +35,9 @@ namespace plib {
struct pspin_mutex<false>
{
public:
- void lock() const noexcept { }
- void unlock() const noexcept { }
+ inline pspin_mutex() noexcept = default;
+ static inline void lock() /*const*/ noexcept { }
+ static inline void unlock() /*const*/ noexcept { }
};
class psemaphore
diff --git a/src/lib/netlist/plib/poptions.h b/src/lib/netlist/plib/poptions.h
index 714a357da86..a0368ebdc09 100644
--- a/src/lib/netlist/plib/poptions.h
+++ b/src/lib/netlist/plib/poptions.h
@@ -261,12 +261,12 @@ namespace plib {
return nullptr;
}
- option *getopt_short(const pstring &arg) const;
- option *getopt_long(const pstring &arg) const;
+ option *getopt_short(const pstring &arg) const;
+ option *getopt_long(const pstring &arg) const;
- std::vector<option_base *> m_opts;
- pstring m_app;
- option_args * m_other_args;
+ std::vector<option_base *> m_opts;
+ pstring m_app;
+ option_args * m_other_args;
};
} // namespace plib
diff --git a/src/lib/netlist/plib/ppmf.h b/src/lib/netlist/plib/ppmf.h
index e86c94ff4c9..e37f970cc05 100644
--- a/src/lib/netlist/plib/ppmf.h
+++ b/src/lib/netlist/plib/ppmf.h
@@ -377,7 +377,7 @@ namespace plib {
bind<specific_member_function<O>>(object, &mftp);
}
- inline R operator()(Targs... args) const noexcept(true)
+ R operator()(Targs... args) const noexcept(true)
{
return this->call(std::forward<Targs>(args)...);
}
diff --git a/src/lib/netlist/plib/ppreprocessor.cpp b/src/lib/netlist/plib/ppreprocessor.cpp
index 320cbe23857..c203fea1753 100644
--- a/src/lib/netlist/plib/ppreprocessor.cpp
+++ b/src/lib/netlist/plib/ppreprocessor.cpp
@@ -245,10 +245,10 @@ namespace plib {
else
{
pstring tok=tmp[pi];
- if (tok.size() >= 2 && pi < tmp.size() - 2 )
+ if (tok.length() >= 2 && pi < tmp.size() - 2 )
{
auto sc=tok.substr(0,1);
- auto ec=tok.substr(tok.size()-1, 1);
+ auto ec=tok.substr(tok.length()-1, 1);
if ((sc == "." || (sc>="0" && sc<="9")) && (ec=="e" || ec=="E"))
{
// looks like an incomplete float due splitting by - or +
@@ -496,7 +496,7 @@ namespace plib {
{
bool line_cont = plib::right(line_in, 1) == "\\";
- pstring line = line_cont ? plib::left(line_in, line_in.size() - 1) : line_in;
+ pstring line = line_cont ? plib::left(line_in, line_in.length() - 1) : line_in;
if (m_state == LINE_CONTINUATION)
m_line += line;
diff --git a/src/lib/netlist/plib/prandom.h b/src/lib/netlist/plib/prandom.h
index b2f9c89a9cf..669228f23fe 100644
--- a/src/lib/netlist/plib/prandom.h
+++ b/src/lib/netlist/plib/prandom.h
@@ -101,7 +101,7 @@ namespace plib
}
private:
- void twist()
+ void twist() noexcept
{
const T lowest_w(~T(0) >> (sizeof(T)*8 - w));
const T lower_mask((T(1) << r) - 1); // That is, the binary number of r 1's
@@ -121,10 +121,10 @@ namespace plib
};
template <typename FT, typename T>
- FT normalize_uniform(T &p, FT m = constants<FT>::one(), FT b = constants<FT>::zero())
+ FT normalize_uniform(T &p, FT m = constants<FT>::one(), FT b = constants<FT>::zero()) noexcept
{
- const auto mmin(narrow_cast<FT>(p.min()));
- const auto mmax(narrow_cast<FT>(p.max()));
+ constexpr const auto mmin(narrow_cast<FT>(T::min()));
+ constexpr const auto mmax(narrow_cast<FT>(T::max()));
// -> 0 to a
return (narrow_cast<FT>(p())- mmin) / (mmax - mmin) * m - b;
}
diff --git a/src/lib/netlist/plib/pstream.h b/src/lib/netlist/plib/pstream.h
index 65d95293298..bdbcb34b099 100644
--- a/src/lib/netlist/plib/pstream.h
+++ b/src/lib/netlist/plib/pstream.h
@@ -28,7 +28,7 @@ namespace plib {
/// \brief wrapper around isteam read
///
template <typename S, typename T>
- static inline S & istream_read(S &is, T * data, size_t len)
+ static S & istream_read(S &is, T * data, size_t len)
{
using ct = typename S::char_type;
static_assert((sizeof(T) % sizeof(ct)) == 0, "istream_read sizeof issue");
@@ -39,7 +39,7 @@ namespace plib {
/// \brief wrapper around osteam write
///
template <typename S, typename T>
- static inline S & ostream_write(S &os, const T * data, size_t len)
+ static S & ostream_write(S &os, const T * data, size_t len)
{
using ct = typename S::char_type;
static_assert((sizeof(T) % sizeof(ct)) == 0, "ostream_write sizeof issue");
@@ -64,7 +64,7 @@ namespace plib {
}
istream_uptr(const istream_uptr &) = delete;
istream_uptr &operator=(const istream_uptr &) = delete;
- istream_uptr(istream_uptr &&rhs)
+ istream_uptr(istream_uptr &&rhs) noexcept
{
m_strm = std::move(rhs.m_strm);
m_filename = std::move(rhs.m_filename);
@@ -228,7 +228,7 @@ public:
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
const putf8string conv_utf8(text);
//m_strm->write(conv_utf8.c_str(), static_cast<std::streamsize>(plib::strlen(conv_utf8.c_str() )));
- ostream_write(*m_strm, conv_utf8.c_str(), string_info<putf8string>::mem_size(conv_utf8));
+ ostream_write(*m_strm, conv_utf8.c_str(), conv_utf8.size());
}
void write(const pstring::value_type c) const
@@ -290,7 +290,7 @@ public:
{
const auto *sm = s.c_str();
//const auto sl(std::char_traits<pstring::mem_t>::length(sm));
- const auto sl(string_info<pstring>::mem_size(s));
+ const auto sl(s.size());
write(sl);
ostream_write(m_strm, sm, sl);
}
diff --git a/src/lib/netlist/plib/pstring.h b/src/lib/netlist/plib/pstring.h
index 9a58e75fbd3..6af155a640c 100644
--- a/src/lib/netlist/plib/pstring.h
+++ b/src/lib/netlist/plib/pstring.h
@@ -178,11 +178,23 @@ public:
const_iterator cend() const noexcept { return const_iterator(m_str.end()); }
// C string conversion helpers
- const mem_t *c_str() const noexcept { return static_cast<const mem_t *>(m_str.c_str()); }
- const mem_t *data() const noexcept { return c_str(); }
-
+ const mem_t *c_str() const noexcept { return static_cast<const mem_t *>(m_str.c_str()); }
+ const mem_t *data() const noexcept { return c_str(); }
+
+ /// \brief return number of codes in the string
+ ///
+ /// This may report a number less than what \ref size reports. pstrings
+ /// operate on character codes. In the case of utf pstrings thus the physical size
+ /// may be bigger than the logical size.
size_type length() const noexcept { return traits_type::len(m_str); }
- size_type size() const noexcept { return traits_type::len(m_str); }
+
+ /// \brief return number of memory units in the string
+ ///
+ /// This function returns the number of memory units used by a string.
+ /// Depending on the string type the size may be reported as bytes, words
+ /// or quad-words.
+ size_type size() const noexcept { return m_str.size(); }
+
bool empty() const noexcept { return m_str.empty(); }
void clear() noexcept { m_str.clear(); }
@@ -478,14 +490,18 @@ namespace plib
struct string_info<pstring_t<T>>
{
using mem_t = typename T::mem_t;
+#if 0
static std::size_t mem_size(const pstring_t<T> &s) { return s.mem_t_size(); }
+#endif
};
template<typename T>
struct string_info<std::basic_string<T>>
{
using mem_t = T;
+#if 0
static std::size_t mem_size(const std::basic_string<T> &s) { return s.size(); }
+#endif
};
} // namespace plib
diff --git a/src/lib/netlist/plib/ptests.h b/src/lib/netlist/plib/ptests.h
index 191233f26fa..b72ef38fc5c 100644
--- a/src/lib/netlist/plib/ptests.h
+++ b/src/lib/netlist/plib/ptests.h
@@ -83,8 +83,8 @@ namespace testing
Test(const Test &) = delete;
Test &operator=(const Test &) = delete;
- Test(Test &&) noexcept = delete;
- Test &operator=(Test &&) noexcept = delete;
+ Test(Test &&) = delete;
+ Test &operator=(Test &&) = delete;
virtual void run() {}
virtual void SetUp() {}
@@ -102,8 +102,8 @@ namespace testing
reg_entry_base(const reg_entry_base &) = delete;
reg_entry_base &operator=(const reg_entry_base &) = delete;
- reg_entry_base(reg_entry_base &&) noexcept = delete;
- reg_entry_base &operator=(reg_entry_base &&) noexcept = delete;
+ reg_entry_base(reg_entry_base &&) = delete;
+ reg_entry_base &operator=(reg_entry_base &&) = delete;
virtual ~reg_entry_base() = default;
diff --git a/src/lib/netlist/plib/ptime.h b/src/lib/netlist/plib/ptime.h
index 0f88449500b..528a0bbd503 100644
--- a/src/lib/netlist/plib/ptime.h
+++ b/src/lib/netlist/plib/ptime.h
@@ -53,12 +53,19 @@ namespace plib
constexpr explicit ptime(const internal_type nom, const internal_type den) noexcept
: m_time(nom * (RES / den)) { }
- template <typename O>
- constexpr explicit ptime(const ptime<O, RES> &rhs) noexcept
+ template <typename O, typename = std::enable_if_t<ptime_le<ptime<O, RES>, ptime>::value>>
+ constexpr ptime(const ptime<O, RES> &rhs) noexcept
: m_time(static_cast<TYPE>(rhs.m_time))
{
}
+ template <typename O, typename T = std::enable_if_t<!ptime_le<ptime<O, RES>, ptime>::value, int>>
+ constexpr explicit ptime(const ptime<O, RES> &rhs, T dummy = 0) noexcept
+ : m_time(static_cast<TYPE>(rhs.m_time))
+ {
+ plib::unused_var(dummy);
+ }
+
template <typename O>
constexpr ptime &operator+=(const ptime<O, RES> &rhs) noexcept
{
@@ -90,7 +97,7 @@ namespace plib
}
template <typename O>
- constexpr ptime operator+(const ptime<O, RES> &rhs) const noexcept
+ constexpr ptime operator+(ptime<O, RES> rhs) const noexcept
{
static_assert(ptime_le<ptime<O, RES>, ptime>::value, "Invalid ptime type");
return ptime(m_time + rhs.m_time);
@@ -128,7 +135,8 @@ namespace plib
template <typename O>
friend constexpr bool operator>(const ptime &lhs, const ptime<O, RES> &rhs) noexcept
{
- return (rhs < lhs);
+ static_assert(ptime_le<ptime<O, RES>, ptime>::value, "Invalid ptime type");
+ return (lhs.m_time > rhs.as_raw());
}
template <typename O>
@@ -146,7 +154,7 @@ namespace plib
template <typename O>
friend constexpr bool operator==(const ptime &lhs, const ptime<O, RES> &rhs) noexcept
{
- return lhs.m_time == rhs.m_time;
+ return lhs.m_time == rhs.as_raw();
}
template <typename O>
@@ -173,9 +181,7 @@ namespace plib
constexpr ptime shr(unsigned shift) const noexcept { return ptime(m_time >> shift); }
// for save states ....
-#if 0
- constexpr internal_type *get_internaltype_ptr() noexcept { return &m_time; }
-#endif
+
template <typename ST>
void save_state(ST &&st)
{
diff --git a/src/lib/netlist/plib/ptimed_queue.h b/src/lib/netlist/plib/ptimed_queue.h
index dc8db7c9bcc..33c14f3bdb9 100644
--- a/src/lib/netlist/plib/ptimed_queue.h
+++ b/src/lib/netlist/plib/ptimed_queue.h
@@ -36,9 +36,12 @@ namespace plib {
struct pqentry_t final
{
constexpr pqentry_t() noexcept : m_exec_time(), m_object(nullptr) { }
- constexpr pqentry_t(Time t, Element o) noexcept : m_exec_time(t), m_object(o) { }
+ constexpr pqentry_t(const Time &t, const Element &o) noexcept : m_exec_time(t), m_object(o) { }
- PCOPYASSIGNMOVE(pqentry_t, default)
+ pqentry_t(const pqentry_t &) = default;
+ pqentry_t &operator=(const pqentry_t &) = default;
+ pqentry_t(pqentry_t &&) noexcept = default;
+ pqentry_t &operator=(pqentry_t &&) noexcept = default;
~pqentry_t() = default;
@@ -64,8 +67,8 @@ namespace plib {
static constexpr pqentry_t never() noexcept { return pqentry_t(Time::never(), nullptr); }
- constexpr Time exec_time() const noexcept { return m_exec_time; }
- constexpr Element object() const noexcept { return m_object; }
+ constexpr const Time &exec_time() const noexcept { return m_exec_time; }
+ constexpr const Element &object() const noexcept { return m_object; }
private:
Time m_exec_time;
Element m_object;
@@ -147,6 +150,7 @@ namespace plib {
}
void pop() noexcept { --m_end; }
+
const T &top() const noexcept { return *(m_end-1); }
template <bool KEEPSTAT, class R>
@@ -165,34 +169,7 @@ namespace plib {
return;
}
}
- }
-
- template <bool KEEPSTAT, class R>
- void retime(R && elem) noexcept
- {
- // Lock
- lock_guard_type lck(m_lock);
- if (KEEPSTAT)
- m_prof_retime.inc();
-
- for (R * i = m_end - 1; i > &m_list[0]; --i)
- {
- if (*i == elem) // partial equal!
- {
- *i = std::forward<R>(elem);
- while (*(i-1) < *i)
- {
- std::swap(*(i-1), *i);
- --i;
- }
- while (i < m_end && *i < *(i+1))
- {
- std::swap(*(i+1), *i);
- ++i;
- }
- return;
- }
- }
+ //printf("Element not found in delete %s\n", elem->name().c_str());
}
void clear() noexcept
@@ -226,7 +203,6 @@ namespace plib {
pperfcount_t<true> m_prof_sortmove; // NOLINT
pperfcount_t<true> m_prof_call; // NOLINT
pperfcount_t<true> m_prof_remove; // NOLINT
- pperfcount_t<true> m_prof_retime; // NOLINT
};
template <class T, bool TS>
@@ -236,7 +212,7 @@ namespace plib {
struct compare
{
- constexpr bool operator()(const T &a, const T &b) const { return b <= a; }
+ constexpr bool operator()(const T &a, const T &b) const noexcept { return b <= a; }
};
explicit timed_queue_heap(const std::size_t list_size)
@@ -251,6 +227,17 @@ namespace plib {
std::size_t capacity() const noexcept { return m_list.capacity(); }
bool empty() const noexcept { return &m_list[0] == m_end; }
+ template<bool KEEPSTAT, typename... Args>
+ void emplace(Args&&... args) noexcept
+ {
+ // Lock
+ lock_guard_type lck(m_lock);
+ *m_end++ = T(std::forward<Args>(args)...);
+ std::push_heap(&m_list[0], m_end, compare());
+ if (KEEPSTAT)
+ m_prof_call.inc();
+ }
+
template <bool KEEPSTAT>
void push(T &&e) noexcept
{
@@ -262,12 +249,10 @@ namespace plib {
m_prof_call.inc();
}
- T pop() noexcept
+ void pop() noexcept
{
- T ret(m_list[0]);
std::pop_heap(&m_list[0], m_end, compare());
m_end--;
- return ret;
}
const T &top() const noexcept { return m_list[0]; }
@@ -291,24 +276,6 @@ namespace plib {
}
}
- template <bool KEEPSTAT>
- void retime(const T &elem) noexcept
- {
- // Lock
- lock_guard_type lck(m_lock);
- if (KEEPSTAT)
- m_prof_retime.inc();
- for (T * i = m_end - 1; i >= &m_list[0]; i--)
- {
- if (*i == elem) // partial equal!
- {
- *i = elem;
- std::make_heap(&m_list[0], m_end, compare());
- return;
- }
- }
- }
-
void clear()
{
lock_guard_type lck(m_lock);
@@ -325,19 +292,17 @@ namespace plib {
using mutex_type = pspin_mutex<TS>;
using lock_guard_type = std::lock_guard<mutex_type>;
- mutex_type m_lock;
- std::vector<T> m_list;
- T *m_end;
+ mutex_type m_lock;
+ T * m_end;
+ aligned_vector<T> m_list;
public:
// profiling
pperfcount_t<true> m_prof_sortmove; // NOLINT
pperfcount_t<true> m_prof_call; // NOLINT
pperfcount_t<true> m_prof_remove; // NOLINT
- pperfcount_t<true> m_prof_retime; // NOLINT
};
} // namespace plib
#endif // PTIMED_QUEUE_H_
-#include <cstdlib>
diff --git a/src/lib/netlist/plib/vector_ops.h b/src/lib/netlist/plib/vector_ops.h
index 6d20b9213a7..86c860b71cb 100644
--- a/src/lib/netlist/plib/vector_ops.h
+++ b/src/lib/netlist/plib/vector_ops.h
@@ -11,6 +11,7 @@
///
///
#include "pconfig.h"
+#include "pgsl.h"
#include "pmath.h"
#include <algorithm>
@@ -27,75 +28,76 @@
namespace plib
{
template<typename VT, typename T>
- void vec_set_scalar(const std::size_t n, VT &v, T && scalar) noexcept
+ void vec_set_scalar(VT &v, T && scalar) noexcept
{
+ const std::size_t n(v.size());
const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
for ( std::size_t i = 0; i < n; i++ )
v[i] = s;
}
template<typename VT, typename VS>
- void vec_set(const std::size_t n, VT &v, const VS & source) noexcept
+ void vec_set(VT &v, const VS & source) noexcept
{
+ const std::size_t n(v.size());
+ gsl_Expects(n <= source.size());
for ( std::size_t i = 0; i < n; i++ )
v[i] = source[i];
}
template<typename T, typename V1, typename V2>
- T vec_mult(const std::size_t n, const V1 & v1, const V2 & v2 ) noexcept
+ T vec_mult(const V1 & v1, const V2 & v2 ) noexcept
{
- using b8 = std::array<T, 8>; // NOLINT
- PALIGNAS_VECTOROPT() b8 value = {0};
+ const std::size_t n(v1.size());
+ gsl_Expects(n <= v2.size());
+ T ret(plib::constants<T>::zero());
for (std::size_t i = 0; i < n ; i++ )
{
- value[i & 7] += v1[i] * v2[i]; // NOLINT
+ ret += v1[i] * v2[i]; // NOLINT
}
- return value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7]; // NOLINT
+ return ret;
}
template<typename T, typename VT>
- T vec_mult2(const std::size_t n, const VT &v) noexcept
+ T vec_mult2(const VT &v) noexcept
{
- using b8 = std::array<T, 8>;
- PALIGNAS_VECTOROPT() b8 value = {0};
+ const std::size_t n(v.size());
+ T ret(plib::constants<T>::zero());
for (std::size_t i = 0; i < n ; i++ )
{
- value[i & 7] += v[i] * v[i];
+ ret += v[i] * v[i];
}
- return value[0] + value[1] + value[2] + value[3] + value[4] + value[5] + value[6] + value[7];
+ return ret;
}
template<typename T, typename VT>
- T vec_sum(const std::size_t n, const VT &v) noexcept
+ T vec_sum(const VT &v) noexcept
{
- if (n<8)
+ const std::size_t n(v.size());
+ T ret(plib::constants<T>::zero());
+ for (std::size_t i = 0; i < n ; i++ )
{
- T value(0);
- for (std::size_t i = 0; i < n ; i++ )
- value += v[i];
-
- return value;
+ ret += v[i];
}
- using b8 = std::array<T, 8>;
- PALIGNAS_VECTOROPT() b8 value = {0};
- for (std::size_t i = 0; i < n ; i++ )
- value[i & 7] += v[i];
-
- return ((value[0] + value[1]) + (value[2] + value[3])) + ((value[4] + value[5]) + (value[6] + value[7]));
+ return ret;
}
template<typename VV, typename T, typename VR>
- void vec_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) noexcept
+ void vec_mult_scalar(VR & result, const VV & v, T && scalar) noexcept
{
+ const std::size_t n(result.size());
+ gsl_Expects(n <= v.size());
const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
for ( std::size_t i = 0; i < n; i++ )
result[i] = s * v[i];
}
template<typename VR, typename VV, typename T>
- void vec_add_mult_scalar(const std::size_t n, VR & result, const VV & v, T && scalar) noexcept
+ void vec_add_mult_scalar(VR & result, const VV & v, T && scalar) noexcept
{
+ const std::size_t n(result.size());
+ gsl_Expects(n <= v.size());
const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
for ( std::size_t i = 0; i < n; i++ )
result[i] += s * v[i];
@@ -109,31 +111,38 @@ namespace plib
}
template<typename R, typename V>
- void vec_add_ip(const std::size_t n, R & result, const V & v) noexcept
+ void vec_add_ip(R & result, const V & v) noexcept
{
+ const std::size_t n(result.size());
+ gsl_Expects(n <= v.size());
for ( std::size_t i = 0; i < n; i++ )
result[i] += v[i];
}
template<typename VR, typename V1, typename V2>
- void vec_sub(const std::size_t n, VR & result, const V1 &v1, const V2 & v2) noexcept
+ void vec_sub(VR & result, const V1 &v1, const V2 & v2) noexcept
{
+ const std::size_t n(result.size());
+ gsl_Expects(n <= v1.size());
+ gsl_Expects(n <= v2.size());
for ( std::size_t i = 0; i < n; i++ )
result[i] = v1[i] - v2[i];
}
template<typename V, typename T>
- void vec_scale(const std::size_t n, V & v, T &&scalar) noexcept
+ void vec_scale(V & v, T &&scalar) noexcept
{
+ const std::size_t n(v.size());
const typename std::remove_reference<decltype(v[0])>::type s(std::forward<T>(scalar));
for ( std::size_t i = 0; i < n; i++ )
v[i] *= s;
}
template<typename T, typename V>
- T vec_maxabs(const std::size_t n, const V & v) noexcept
+ T vec_maxabs(const V & v) noexcept
{
- T ret = 0.0;
+ const std::size_t n(v.size());
+ T ret(plib::constants<T>::zero());
for ( std::size_t i = 0; i < n; i++ )
ret = std::max(ret, plib::abs(v[i]));
diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp
index 44b96bf0d6d..21f1f0725fa 100644
--- a/src/lib/netlist/prg/nltool.cpp
+++ b/src/lib/netlist/prg/nltool.cpp
@@ -82,7 +82,6 @@ public:
opt_type(*this, "y", "type", 0, std::vector<pstring>({"spice","eagle","rinf"}), "type of file to be converted: spice,eagle,rinf"),
opt_grp6(*this, "Options for validate command", "These options are only used by the validate command."),
- opt_extended_validation(*this, "", "extended", "Identify issues with power terminals."),
opt_grp7(*this, "Options for header command", "These options are only used by the header command."),
opt_tabwidth(*this, "", "tab-width", 4, "Tab width for output."),
@@ -153,7 +152,6 @@ private:
plib::option_str_limit<unsigned> opt_type;
plib::option_group opt_grp6;
- plib::option_bool opt_extended_validation;
plib::option_group opt_grp7;
plib::option_num<unsigned> opt_tabwidth;
plib::option_num<unsigned> opt_linewidth;
@@ -548,8 +546,6 @@ void tool_app_t::validate()
m_errors = 0;
m_warnings = 0;
- nt.set_extended_validation(opt_extended_validation());
-
try
{
nt.read_netlist(opt_files()[0], opt_name(),
@@ -707,7 +703,7 @@ void tool_app_t::static_compile()
for (auto &e : map)
{
sout << "// " << putf8string(e.second.m_module) << "\n";
- sout << "\t{\"" << putf8string(e.first) << "\", reinterpret_cast<void *>(&" << putf8string(e.first) << ")},\n";
+ sout << "\t{\"" << putf8string(e.first) << "\", reinterpret_cast<void *>(&" << putf8string(e.first) << ")}, // NOLINT\n";
}
sout << "#endif\n\n";
sout << "{\"\", nullptr}\n";
@@ -1178,7 +1174,7 @@ void tool_app_t::listmodels()
{
auto model = nt.setup().models().get_model(e);
- elems.push_back({model.type(), e});
+ elems.emplace_back(model.type(), e);
}
std::sort(elems.begin(), elems.end(), comp);
diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp
index 4076de4bd12..944234fa8c8 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.cpp
+++ b/src/lib/netlist/solver/nld_matrix_solver.cpp
@@ -86,15 +86,15 @@ namespace solver
for (std::size_t k = 0; k < nets.size(); k++)
{
- analog_net_t *net = nets[k];
+ analog_net_t &net = *nets[k];
- log().debug("adding net with {1} populated connections\n", net->core_terms().size());
+ log().debug("adding net with {1} populated connections\n", setup.nlstate().core_terms(net).size());
- net->set_solver(this);
+ net.set_solver(this);
- for (auto &p : net->core_terms())
+ for (auto &p : setup.nlstate().core_terms(net))
{
- log().debug("{1} {2} {3}\n", p->name(), net->name(), net->is_rail_net());
+ log().debug("{1} {2} {3}\n", p->name(), net.name(), net.is_rail_net());
switch (p->type())
{
case detail::terminal_type::TERMINAL:
@@ -476,7 +476,7 @@ namespace solver
resched = solve_nr_base();
// update timestep calculation
next_time_step = compute_next_timestep(m_params.m_min_ts_ts(), m_params.m_min_ts_ts(), m_params.m_max_timestep);
- delta -= netlist_time_ext::from_fp(m_params.m_min_ts_ts());
+ delta -= netlist_time::from_fp(m_params.m_min_ts_ts());
}
// try remaining time using compute_next_timestep
while (delta > netlist_time::zero())
@@ -507,13 +507,13 @@ namespace solver
netlist_time matrix_solver_t::solve(netlist_time_ext now, const char *source)
{
- netlist_time_ext delta = now - m_last_step();
+ netlist_time delta = static_cast<netlist_time>(now - m_last_step());
PFDEBUG(printf("solve %.10f\n", delta.as_double());)
plib::unused_var(source);
// We are already up to date. Avoid oscillations.
// FIXME: Make this a parameter!
- if (delta < netlist_time_ext::quantum())
+ if (delta < netlist_time::quantum())
{
//printf("solve return %s at %f\n", source, now.as_double());
return timestep_device_count() > 0 ? netlist_time::from_fp(m_params.m_min_timestep) : netlist_time::zero();
diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h
index 4e392c88770..1ba3b99e012 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.h
+++ b/src/lib/netlist/solver/nld_matrix_solver.h
@@ -10,10 +10,10 @@
#include "nl_base.h"
#include "nl_errstr.h"
-#include "plib/mat_cr.h"
#include "plib/palloc.h"
#include "plib/penum.h"
#include "plib/pmatrix2d.h"
+#include "plib/pmatrix_cr.h"
#include "plib/pmempool.h"
#include "plib/putil.h"
#include "plib/vector_ops.h"
@@ -74,7 +74,7 @@ namespace solver
constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
constexpr std::size_t m_nr_loops() { return 250; }
- constexpr std::size_t m_gs_loops() { return 9; }
+ constexpr std::size_t m_gs_loops() { return 50; }
// general parameters
constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
diff --git a/src/lib/netlist/solver/nld_ms_gcr.h b/src/lib/netlist/solver/nld_ms_gcr.h
index 61bfa012fa7..73f9eb83c0d 100644
--- a/src/lib/netlist/solver/nld_ms_gcr.h
+++ b/src/lib/netlist/solver/nld_ms_gcr.h
@@ -10,12 +10,10 @@
/// Gaussian elimination using compressed row format.
///
-#include "plib/mat_cr.h"
-
-//#include "nld_ms_direct.h"
#include "nld_matrix_solver_ext.h"
#include "nld_solver.h"
#include "plib/pdynlib.h"
+#include "plib/pmatrix_cr.h"
#include "plib/pstream.h"
#include "plib/vector_ops.h"
@@ -31,7 +29,7 @@ namespace solver
{
public:
- using mat_type = plib::pGEmatrix_cr_t<plib::pmatrix_cr_t<FT, SIZE>>;
+ using mat_type = plib::pGEmatrix_cr<plib::pmatrix_cr<FT, SIZE>>;
using base_type = matrix_solver_ext_t<FT, SIZE>;
using fptype = typename base_type::fptype;
@@ -95,10 +93,7 @@ namespace solver
// FIXME: Move me
//
- // During extended validation there is no reason to check for
- // differences in the generated code since during
- // extended validation this will be different (and non-functional)
- if (!this->state().is_extended_validation() && this->state().static_solver_lib().isLoaded())
+ if (this->state().static_solver_lib().isLoaded())
{
pstring symname = static_compile_name();
m_proc.load(this->state().static_solver_lib(), symname);
@@ -119,7 +114,7 @@ namespace solver
private:
- using mat_index_type = typename plib::pmatrix_cr_t<FT, SIZE>::index_type;
+ using mat_index_type = typename plib::pmatrix_cr<FT, SIZE>::index_type;
void generate_code(plib::putf8_fmt_writer &strm);
diff --git a/src/lib/netlist/solver/nld_ms_gmres.h b/src/lib/netlist/solver/nld_ms_gmres.h
index c702d2e3ba6..da18050dca8 100644
--- a/src/lib/netlist/solver/nld_ms_gmres.h
+++ b/src/lib/netlist/solver/nld_ms_gmres.h
@@ -12,8 +12,8 @@
#include "nld_ms_direct.h"
#include "nld_solver.h"
#include "plib/gmres.h"
-#include "plib/mat_cr.h"
#include "plib/parray.h"
+#include "plib/pmatrix_cr.h"
#include "plib/vector_ops.h"
#include <algorithm>
@@ -83,7 +83,7 @@ namespace solver
private:
- using mattype = typename plib::pmatrix_cr_t<FT, SIZE>::index_type;
+ using mattype = typename plib::pmatrix_cr<FT, SIZE>::index_type;
//plib::mat_precondition_none<FT, SIZE> m_ops;
plib::mat_precondition_ILU<FT, SIZE> m_ops;
diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp
index 9ea31925b98..b475b282eb8 100644
--- a/src/lib/netlist/solver/nld_solver.cpp
+++ b/src/lib/netlist/solver/nld_solver.cpp
@@ -4,6 +4,7 @@
#include "nl_factory.h"
#include "core/setup.h"
+#include "nl_errstr.h"
#include "nl_setup.h" // FIXME: only needed for splitter code
#include "nld_matrix_solver.h"
#include "nld_ms_direct.h"
@@ -33,7 +34,7 @@ namespace devices
NETLIB_RESET(solver)
{
- if (exec().use_stats())
+ if (exec().stats_enabled())
m_fb_step.set_delegate(NETLIB_DELEGATE(fb_step<true>));
for (auto &s : m_mat_solvers)
s->reset();
@@ -113,7 +114,7 @@ namespace devices
}
}
if (!m_queue.empty())
- m_Q_step.net().toggle_and_push_to_queue(m_queue.top().exec_time() - now);
+ m_Q_step.net().toggle_and_push_to_queue(static_cast<netlist_time>(m_queue.top().exec_time() - now));
}
void NETLIB_NAME(solver) :: reschedule(solver::matrix_solver_t *solv, netlist_time ts)
@@ -277,20 +278,20 @@ namespace devices
struct net_splitter
{
- void run(netlist_state_t &netlist)
+ void run(netlist_state_t &nlstate)
{
- for (auto & net : netlist.nets())
+ for (auto & net : nlstate.nets())
{
- netlist.log().verbose("processing {1}", net->name());
- if (!net->is_rail_net() && net->has_connections())
+ nlstate.log().verbose("processing {1}", net->name());
+ if (!net->is_rail_net() && !nlstate.core_terms(*net).empty())
{
- netlist.log().verbose(" ==> not a rail net");
+ nlstate.log().verbose(" ==> not a rail net");
// Must be an analog net
auto &n = dynamic_cast<analog_net_t &>(*net);
if (!already_processed(n))
{
groupspre.emplace_back(NETLIB_NAME(solver)::net_list_t());
- process_net(netlist, n);
+ process_net(nlstate, n);
}
}
}
@@ -343,27 +344,31 @@ namespace devices
}
// NOLINTNEXTLINE(misc-no-recursion)
- void process_net(netlist_state_t &netlist, analog_net_t &n)
+ void process_net(netlist_state_t &nlstate, analog_net_t &n)
{
// ignore empty nets. FIXME: print a warning message
- netlist.log().verbose("Net {}", n.name());
- if (n.has_connections())
+ nlstate.log().verbose("Net {}", n.name());
+ if (!nlstate.core_terms(n).empty())
{
// add the net
groupspre.back().push_back(&n);
// process all terminals connected to this net
- for (auto &term : n.core_terms())
+ for (auto &term : nlstate.core_terms(n))
{
- netlist.log().verbose("Term {} {}", term->name(), static_cast<int>(term->type()));
+ nlstate.log().verbose("Term {} {}", term->name(), static_cast<int>(term->type()));
// only process analog terminals
if (term->is_type(detail::terminal_type::TERMINAL))
{
auto &pt = dynamic_cast<terminal_t &>(*term);
// check the connected terminal
- analog_net_t &connected_net = netlist.setup().get_connected_terminal(pt)->net();
- netlist.log().verbose(" Connected net {}", connected_net.name());
- if (!check_if_processed_and_join(connected_net))
- process_net(netlist, connected_net);
+ const auto *const connected_terminals = nlstate.setup().get_connected_terminals(pt);
+ for (auto ct = connected_terminals->begin(); *ct != nullptr; ct++)
+ {
+ analog_net_t &connected_net = (*ct)->net();
+ nlstate.log().verbose(" Connected net {}", connected_net.name());
+ if (!check_if_processed_and_join(connected_net))
+ process_net(nlstate, connected_net);
+ }
}
}
}
@@ -380,9 +385,55 @@ namespace devices
net_splitter splitter;
splitter.run(state());
+ log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size());
+
+ int num_errors = 0;
+
+ log().verbose("checking net consistency ...");
+ for (const auto &grp : splitter.groups)
+ {
+ int railterms = 0;
+ pstring nets_in_grp;
+ for (const auto &n : grp)
+ {
+ nets_in_grp += (n->name() + " ");
+ if (!n->is_analog())
+ {
+ state().log().error(ME_SOLVER_CONSISTENCY_NOT_ANALOG_NET(n->name()));
+ num_errors++;
+ }
+ if (n->is_rail_net())
+ {
+ state().log().error(ME_SOLVER_CONSISTENCY_RAIL_NET(n->name()));
+ num_errors++;
+ }
+ for (const auto &t : state().core_terms(*n))
+ {
+ if (!t->has_net())
+ {
+ state().log().error(ME_SOLVER_TERMINAL_NO_NET(t->name()));
+ num_errors++;
+ }
+ else
+ {
+ auto *otherterm = dynamic_cast<terminal_t *>(t);
+ if (otherterm != nullptr)
+ if (state().setup().get_connected_terminal(*otherterm)->net().is_rail_net())
+ railterms++;
+ }
+ }
+ }
+ if (railterms == 0)
+ {
+ state().log().error(ME_SOLVER_NO_RAIL_TERMINAL(nets_in_grp));
+ num_errors++;
+ }
+ }
+ if (num_errors > 0)
+ throw nl_exception(MF_SOLVER_CONSISTENCY_ERRORS(num_errors));
+
// setup the solvers
- log().verbose("Found {1} net groups in {2} nets\n", splitter.groups.size(), state().nets().size());
for (auto & grp : splitter.groups)
{
solver_ptr ms;
@@ -421,9 +472,9 @@ namespace devices
for (auto &n : grp)
{
log().verbose("Net {1}", n->name());
- for (const auto &pcore : n->core_terms())
+ for (const auto &t : state().core_terms(*n))
{
- log().verbose(" {1}", pcore->name());
+ log().verbose(" {1}", t->name());
}
}
diff --git a/src/lib/netlist/tests/test_pfunction.cpp b/src/lib/netlist/tests/test_pfunction.cpp
index 56923be8149..21dc33f28ac 100644
--- a/src/lib/netlist/tests/test_pfunction.cpp
+++ b/src/lib/netlist/tests/test_pfunction.cpp
@@ -50,6 +50,11 @@ PTEST(pfunction, unary_minus)
PFUNCEXPECT("3*-trunc(3.2)", -9.0);
PFUNCEXPECT("3*-(3*2)", -18.0);
PFUNCEXPECT("3*-(2*1)^2", -12.0);
+ PEXPECT_NO_THROW(plib::pfunction<double>("(-3)")()); // fail
+}
+PTEST(pfunction, expect_throw)
+{
PEXPECT_THROW(plib::pfunction<double>("(3, 4)")(), plib::pexception);
- PEXPECT_NO_THROW(plib::pfunction<double>("(3)")()); // fail
+ PEXPECT_THROW(plib::pfunction<double>("((3)")(), plib::pexception);
+ PEXPECT_THROW(plib::pfunction<double>("(3))")(), plib::pexception);
}
diff --git a/src/lib/util/avhuff.cpp b/src/lib/util/avhuff.cpp
index 50eea9f24dc..ac5cea71526 100644
--- a/src/lib/util/avhuff.cpp
+++ b/src/lib/util/avhuff.cpp
@@ -691,24 +691,19 @@ avhuff_decoder::avhuff_decoder()
}
/**
- * @fn void avhuff_decoder::configure(const avhuff_decompress_config &config)
+ * @fn void avhuff_decoder::configure(const config &cfg)
*
* @brief -------------------------------------------------
* configure - configure decompression parameters
* -------------------------------------------------.
*
- * @param config The configuration.
+ * @param cfg The configuration.
*/
-void avhuff_decoder::configure(const avhuff_decompress_config &config)
+void avhuff_decoder::configure(const config &cfg)
{
- m_config.video.wrap(config.video, config.video.cliprect());
- m_config.maxsamples = config.maxsamples;
- m_config.actsamples = config.actsamples;
- memcpy(m_config.audio, config.audio, sizeof(m_config.audio));
- m_config.maxmetalength = config.maxmetalength;
- m_config.actmetalength = config.actmetalength;
- m_config.metadata = config.metadata;
+ m_video.wrap(*cfg.video, cfg.video->cliprect());
+ m_config = cfg;
}
/**
@@ -792,9 +787,9 @@ avhuff_error avhuff_decoder::decode_data(const uint8_t *source, uint32_t complen
// determine the start of each piece of data
metastart = m_config.metadata;
for (int chnum = 0; chnum < channels; chnum++)
- audiostart[chnum] = (uint8_t *)m_config.audio[chnum];
- videostart = (m_config.video.valid()) ? reinterpret_cast<uint8_t *>(&m_config.video.pix(0)) : nullptr;
- videostride = (m_config.video.valid()) ? m_config.video.rowpixels() * 2 : 0;
+ audiostart[chnum] = reinterpret_cast<uint8_t *>(m_config.audio[chnum]);
+ videostart = m_video.valid() ? reinterpret_cast<uint8_t *>(&m_video.pix(0)) : nullptr;
+ videostride = m_video.valid() ? m_video.rowpixels() * 2 : 0;
// data is assumed to be native-endian
uint16_t betest = 0;
@@ -802,7 +797,7 @@ avhuff_error avhuff_decoder::decode_data(const uint8_t *source, uint32_t complen
audioxor = videoxor = (betest == 1) ? 1 : 0;
// verify against sizes
- if (m_config.video.valid() && (m_config.video.width() < width || m_config.video.height() < height))
+ if (m_video.valid() && (m_video.width() < width || m_video.height() < height))
return AVHERR_VIDEO_TOO_LARGE;
for (int chnum = 0; chnum < channels; chnum++)
if (m_config.audio[chnum] != nullptr && m_config.maxsamples < samples)
diff --git a/src/lib/util/avhuff.h b/src/lib/util/avhuff.h
index 90ef43e977f..83b46195d6b 100644
--- a/src/lib/util/avhuff.h
+++ b/src/lib/util/avhuff.h
@@ -19,6 +19,8 @@
#include "huffman.h"
#include "flac.h"
+#include <algorithm>
+
//**************************************************************************
// CONSTANTS
@@ -49,32 +51,6 @@ enum avhuff_error
// TYPE DEFINITIONS
//**************************************************************************
-// ======================> av_codec_decompress_config
-
-// decompression configuration
-class avhuff_decompress_config
-{
-public:
- avhuff_decompress_config()
- : maxsamples(0),
- actsamples(nullptr),
- maxmetalength(0),
- actmetalength(nullptr),
- metadata(nullptr)
- {
- memset(audio, 0, sizeof(audio));
- }
-
- bitmap_yuy16 video; // pointer to video bitmap
- uint32_t maxsamples; // maximum number of samples per channel
- uint32_t * actsamples; // actual number of samples per channel
- int16_t * audio[16]; // pointer to individual audio channels
- uint32_t maxmetalength; // maximum length of metadata
- uint32_t * actmetalength; // actual length of metadata
- uint8_t * metadata; // pointer to metadata buffer
-};
-
-
// ======================> avhuff_encoder
// core state for the codec
@@ -98,8 +74,7 @@ private:
{
public:
// construction/destruction
- deltarle_encoder()
- : m_rlecount(0) { }
+ deltarle_encoder() { }
// histogramming
uint16_t *rle_and_histo_bitmap(const uint8_t *source, uint32_t items_per_row, uint32_t item_advance, uint32_t row_count);
@@ -111,7 +86,7 @@ private:
private:
// internal state
- int m_rlecount;
+ int m_rlecount = 0;
huffman_encoder<256 + 16> m_encoder;
std::vector<uint16_t> m_rlebuffer;
};
@@ -143,11 +118,30 @@ private:
class avhuff_decoder
{
public:
+ // decompression configuration
+ class config
+ {
+ public:
+ config()
+ {
+ std::fill(std::begin(audio), std::end(audio), nullptr);
+ }
+
+ bitmap_yuy16 * video = nullptr; // pointer to video bitmap
+ uint32_t maxsamples = 0; // maximum number of samples per channel
+ uint32_t * actsamples = nullptr; // actual number of samples per channel
+ int16_t * audio[16]; // pointer to individual audio channels
+ uint32_t maxmetalength = 0; // maximum length of metadata
+ uint32_t * actmetalength = nullptr; // actual length of metadata
+ uint8_t * metadata = nullptr; // pointer to metadata buffer
+ };
+
+
// construction/destruction
avhuff_decoder();
// configuration
- void configure(const avhuff_decompress_config &config);
+ void configure(const config &cfg);
// encode/decode
avhuff_error decode_data(const uint8_t *source, uint32_t complength, uint8_t *dest);
@@ -158,8 +152,7 @@ private:
{
public:
// construction/destruction
- deltarle_decoder()
- : m_rlecount(0), m_prevdata(0) { }
+ deltarle_decoder() { }
// general
void reset() { m_rlecount = m_prevdata = 0; }
@@ -171,8 +164,8 @@ private:
private:
// internal state
- int m_rlecount;
- uint8_t m_prevdata;
+ int m_rlecount = 0;
+ uint8_t m_prevdata = 0;
huffman_decoder<256 + 16> m_decoder;
};
@@ -183,7 +176,8 @@ private:
avhuff_error decode_video_lossless(int width, int height, const uint8_t *source, uint32_t complength, uint8_t *dest, uint32_t dstride, uint32_t dxor);
// internal state
- avhuff_decompress_config m_config;
+ bitmap_yuy16 m_video;
+ config m_config;
// video decoding contexts
deltarle_decoder m_ycontext;
diff --git a/src/lib/util/aviio.cpp b/src/lib/util/aviio.cpp
index 8722017d3e8..7f74920f06b 100644
--- a/src/lib/util/aviio.cpp
+++ b/src/lib/util/aviio.cpp
@@ -999,7 +999,7 @@ avi_file::error avi_stream::rgb32_compress_to_rgb(const bitmap_rgb32 &bitmap, st
/* compressed video */
for (y = 0; y < height; y++)
{
- const std::uint32_t *source = &bitmap.pix32(y);
+ const std::uint32_t *source = &bitmap.pix(y);
std::uint8_t *dest = data + (m_height - 1 - y) * m_width * 3;
for (x = 0; x < width && dest < dataend; x++)
@@ -1062,7 +1062,7 @@ avi_file::error avi_stream::yuv_decompress_to_yuy16(const std::uint8_t *data, st
for (y = 0; y < m_height; y++)
{
const std::uint16_t *source = reinterpret_cast<const std::uint16_t *>(data) + y * m_width;
- std::uint16_t *dest = &bitmap.pix16(y);
+ std::uint16_t *dest = &bitmap.pix(y);
/* switch off the compression */
switch (m_format)
@@ -1113,7 +1113,7 @@ avi_file::error avi_stream::yuy16_compress_to_yuy(const bitmap_yuy16 &bitmap, st
/* compressed video */
for (y = 0; y < m_height; y++)
{
- const std::uint16_t *source = &bitmap.pix16(y);
+ const std::uint16_t *source = &bitmap.pix(y);
std::uint16_t *dest = reinterpret_cast<std::uint16_t *>(data) + y * m_width;
/* switch off the compression */
@@ -1298,7 +1298,7 @@ avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data
/* compressed video */
for (y = 0; y < m_height; y++)
{
- std::uint16_t *dest = &bitmap.pix16(y);
+ std::uint16_t *dest = &bitmap.pix(y);
/* handle the first four bytes independently */
x = 0;
@@ -1386,8 +1386,8 @@ avi_file::error avi_stream::huffyuv_decompress_to_yuy16(const std::uint8_t *data
lastprevy = lastprevcb = lastprevcr = 0;
for (y = 0; y < m_height; y++)
{
- std::uint16_t *prevrow = &bitmap.pix16(y - prevlines);
- std::uint16_t *dest = &bitmap.pix16(y);
+ std::uint16_t *prevrow = &bitmap.pix(y - prevlines);
+ std::uint16_t *dest = &bitmap.pix(y);
/* handle the first four bytes independently */
x = 0;
@@ -1500,7 +1500,7 @@ avi_file::error avi_stream::uncompressed_rgb24_to_argb32(const std::uint8_t *dat
/* uncompressed video */
for (int y = 0; y < m_height; y++)
{
- std::uint32_t *dest = &bitmap.pix32(y);
+ std::uint32_t *dest = &bitmap.pix(y);
/* loop over pixels */
for (int x = 0; x < m_width; x++)
@@ -1530,7 +1530,7 @@ avi_file::error avi_stream::uncompressed_yuv420p_to_argb32(const std::uint8_t *d
/* uncompressed video */
for (int y = 0; y < m_height; y++)
{
- std::uint32_t *dest = &bitmap.pix32(y);
+ std::uint32_t *dest = &bitmap.pix(y);
/* loop over pixels */
for (int x = 0; x < m_width; x++)
diff --git a/src/lib/util/bitmap.cpp b/src/lib/util/bitmap.cpp
index ed814aae218..fc05b89f1b6 100644
--- a/src/lib/util/bitmap.cpp
+++ b/src/lib/util/bitmap.cpp
@@ -8,14 +8,12 @@
***************************************************************************/
-#include <cassert>
-
#include "bitmap.h"
+#include <cassert>
#include <new>
-
//**************************************************************************
// INLINE HELPERS
//**************************************************************************
@@ -361,7 +359,7 @@ void bitmap_t::wrap(void *base, int width, int height, int rowpixels)
* @param subrect The subrect.
*/
-void bitmap_t::wrap(const bitmap_t &source, const rectangle &subrect)
+void bitmap_t::wrap(bitmap_t &source, const rectangle &subrect)
{
assert(m_format == source.m_format);
assert(m_bpp == source.m_bpp);
@@ -407,7 +405,7 @@ void bitmap_t::set_palette(palette_t *palette)
}
/**
- * @fn void bitmap_t::fill(uint32_t color, const rectangle &cliprect)
+ * @fn void bitmap_t::fill(uint64_t color, const rectangle &bounds)
*
* @brief -------------------------------------------------
* fill -- fill a bitmap with a solid color
@@ -417,93 +415,45 @@ void bitmap_t::set_palette(palette_t *palette)
* @param cliprect The cliprect.
*/
-void bitmap_t::fill(uint32_t color, const rectangle &cliprect)
+void bitmap_t::fill(uint64_t color, const rectangle &bounds)
{
// if we have a cliprect, intersect with that
- rectangle fill = cliprect;
+ rectangle fill(bounds);
fill &= m_cliprect;
- if (fill.empty())
- return;
-
- // based on the bpp go from there
- switch (m_bpp)
+ if (!fill.empty())
{
+ // based on the bpp go from there
+ switch (m_bpp)
+ {
case 8:
- // 8bpp always uses memset
for (int32_t y = fill.top(); y <= fill.bottom(); y++)
- memset(raw_pixptr(y, fill.left()), uint8_t(color), fill.width());
+ std::fill_n(&pixt<uint8_t>(y, fill.left()), fill.width(), uint8_t(color));
break;
case 16:
- // 16bpp can use memset if the bytes are equal
- if (uint8_t(color >> 8) == uint8_t(color))
- {
- for (int32_t y = fill.top(); y <= fill.bottom(); y++)
- memset(raw_pixptr(y, fill.left()), uint8_t(color), fill.width() * 2);
- }
- else
- {
- // Fill the first line the hard way
- uint16_t *destrow = &pixt<uint16_t>(fill.top());
- for (int32_t x = fill.left(); x <= fill.right(); x++)
- destrow[x] = uint16_t(color);
-
- // For the other lines, just copy the first one
- void *destrow0 = &pixt<uint16_t>(fill.top(), fill.left());
- for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++)
- {
- destrow = &pixt<uint16_t>(y, fill.left());
- memcpy(destrow, destrow0, fill.width() * 2);
- }
- }
+ for (int32_t y = fill.top(); y <= fill.bottom(); ++y)
+ std::fill_n(&pixt<uint16_t>(y, fill.left()), fill.width(), uint16_t(color));
break;
case 32:
- // 32bpp can use memset if the bytes are equal
- if ((uint8_t)(color >> 8) == (uint8_t)color && (uint16_t)(color >> 16) == (uint16_t)color)
- {
- for (int32_t y = fill.top(); y <= fill.bottom(); y++)
- memset(&pixt<uint32_t>(y, fill.left()), uint8_t(color), fill.width() * 4);
- }
- else
- {
- // Fill the first line the hard way
- uint32_t *destrow = &pixt<uint32_t>(fill.top());
- for (int32_t x = fill.left(); x <= fill.right(); x++)
- destrow[x] = uint32_t(color);
-
- // For the other lines, just copy the first one
- uint32_t *destrow0 = &pixt<uint32_t>(fill.top(), fill.left());
- for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++)
- {
- destrow = &pixt<uint32_t>(y, fill.left());
- memcpy(destrow, destrow0, fill.width() * 4);
- }
- }
+ for (int32_t y = fill.top(); y <= fill.bottom(); ++y)
+ std::fill_n(&pixt<uint32_t>(y, fill.left()), fill.width(), uint32_t(color));
break;
case 64:
- // 64bpp can use memset if the bytes are equal
- if (uint8_t(color >> 8) == uint8_t(color) && uint16_t(color >> 16) == uint16_t(color)) // FIXME: really? wat about the upper bits that would be zeroed when done the "hard way"?
- {
- for (int32_t y = fill.top(); y <= fill.bottom(); y++)
- memset(&pixt<uint64_t>(y, fill.left()), uint8_t(color), fill.width() * 8);
- }
- else
- {
- // Fill the first line the hard way
- uint64_t *destrow = &pixt<uint64_t>(fill.top());
- for (int32_t x = fill.left(); x <= fill.right(); x++)
- destrow[x] = uint64_t(color);
-
- // For the other lines, just copy the first one
- uint64_t *destrow0 = &pixt<uint64_t>(fill.top(), fill.left());
- for (int32_t y = fill.top() + 1; y <= fill.bottom(); y++)
- {
- destrow = &pixt<uint64_t>(y, fill.left());
- memcpy(destrow, destrow0, fill.width() * 8);
- }
- }
+ for (int32_t y = fill.top(); y <= fill.bottom(); ++y)
+ std::fill_n(&pixt<uint64_t>(y, fill.left()), fill.width(), uint64_t(color));
break;
+ }
}
}
+
+
+//**************************************************************************
+// EXPLICIT TEMPLATE INSTANTIATIONS
+//**************************************************************************
+
+template class bitmap_specific<uint8_t>;
+template class bitmap_specific<uint16_t>;
+template class bitmap_specific<uint32_t>;
+template class bitmap_specific<uint64_t>;
diff --git a/src/lib/util/bitmap.h b/src/lib/util/bitmap.h
index ed6a5382a61..57ed0bc1775 100644
--- a/src/lib/util/bitmap.h
+++ b/src/lib/util/bitmap.h
@@ -16,6 +16,9 @@
#include "osdcore.h"
#include "palette.h"
+#include <algorithm>
+#include <memory>
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -151,23 +154,23 @@ public:
// operations
void set_palette(palette_t *palette);
- void fill(uint32_t color) { fill(color, m_cliprect); }
- void fill(uint32_t color, const rectangle &cliprect);
- void plot_box(int x, int y, int width, int height, uint32_t color)
+ void fill(uint64_t color) { fill(color, m_cliprect); }
+ void fill(uint64_t color, const rectangle &bounds);
+ void plot_box(int32_t x, int32_t y, int32_t width, int32_t height, uint64_t color)
{
- rectangle clip(x, x + width - 1, y, y + height - 1);
- fill(color, clip);
+ fill(color, rectangle(x, x + width - 1, y, y + height - 1));
}
// pixel access
- template<typename PixelType>
- PixelType &pixt(int32_t y, int32_t x = 0) const { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); }
- void *raw_pixptr(int32_t y, int32_t x = 0) const { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; }
+ void *raw_pixptr(int32_t y, int32_t x = 0) { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; }
+ void const *raw_pixptr(int32_t y, int32_t x = 0) const { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; }
protected:
// for use by subclasses only to ensure type correctness
+ template <typename PixelType> PixelType &pixt(int32_t y, int32_t x = 0) { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); }
+ template <typename PixelType> PixelType const &pixt(int32_t y, int32_t x = 0) const { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); }
void wrap(void *base, int width, int height, int rowpixels);
- void wrap(const bitmap_t &source, const rectangle &subrect);
+ void wrap(bitmap_t &source, const rectangle &subrect);
private:
// internal helpers
@@ -191,17 +194,17 @@ private:
// ======================> bitmap_specific, bitmap8_t, bitmap16_t, bitmap32_t, bitmap64_t
-template<typename PixelType>
+template <typename PixelType>
class bitmap_specific : public bitmap_t
{
- static constexpr int PixelBits = 8 * sizeof(PixelType);
+ static constexpr int PIXEL_BITS = 8 * sizeof(PixelType);
protected:
// construction/destruction -- subclasses only
bitmap_specific(bitmap_specific<PixelType> &&) = default;
- bitmap_specific(bitmap_format format, int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap_t(format, PixelBits, width, height, xslop, yslop) { }
- bitmap_specific(bitmap_format format, PixelType *base, int width, int height, int rowpixels) : bitmap_t(format, PixelBits, base, width, height, rowpixels) { }
- bitmap_specific(bitmap_format format, bitmap_specific<PixelType> &source, const rectangle &subrect) : bitmap_t(format, PixelBits, source, subrect) { }
+ bitmap_specific(bitmap_format format, int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap_t(format, PIXEL_BITS, width, height, xslop, yslop) { }
+ bitmap_specific(bitmap_format format, PixelType *base, int width, int height, int rowpixels) : bitmap_t(format, PIXEL_BITS, base, width, height, rowpixels) { }
+ bitmap_specific(bitmap_format format, bitmap_specific<PixelType> &source, const rectangle &subrect) : bitmap_t(format, PIXEL_BITS, source, subrect) { }
bitmap_specific<PixelType> &operator=(bitmap_specific<PixelType> &&) = default;
@@ -209,27 +212,46 @@ public:
using pixel_t = PixelType;
// getters
- uint8_t bpp() const { return PixelBits; }
+ uint8_t bpp() const { return PIXEL_BITS; }
// pixel accessors
- PixelType &pix(int32_t y, int32_t x = 0) const { return pixt<PixelType>(y, x); }
- PixelType &pix8(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 8, "must be 8bpp"); return pixt<PixelType>(y, x); }
- PixelType &pix16(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 16, "must be 16bpp"); return pixt<PixelType>(y, x); }
- PixelType &pix32(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 32, "must be 32bpp"); return pixt<PixelType>(y, x); }
- PixelType &pix64(int32_t y, int32_t x = 0) const { static_assert(PixelBits == 64, "must be 64bpp"); return pixt<PixelType>(y, x); }
+ PixelType &pix(int32_t y, int32_t x = 0) { return pixt<PixelType>(y, x); }
+ PixelType const &pix(int32_t y, int32_t x = 0) const { return pixt<PixelType>(y, x); }
+
+ // operations
+ void fill(PixelType color) { fill(color, cliprect()); }
+ void fill(PixelType color, const rectangle &bounds)
+ {
+ // if we have a cliprect, intersect with that
+ rectangle fill(bounds);
+ fill &= cliprect();
+ if (!fill.empty())
+ {
+ for (int32_t y = fill.top(); y <= fill.bottom(); y++)
+ std::fill_n(&pix(y, fill.left()), fill.width(), color);
+ }
+ }
+ void plot_box(int32_t x, int32_t y, int32_t width, int32_t height, PixelType color)
+ {
+ fill(color, rectangle(x, x + width - 1, y, y + height - 1));
+ }
};
// 8bpp bitmaps
using bitmap8_t = bitmap_specific<uint8_t>;
+extern template class bitmap_specific<uint8_t>;
// 16bpp bitmaps
using bitmap16_t = bitmap_specific<uint16_t>;
+extern template class bitmap_specific<uint16_t>;
// 32bpp bitmaps
using bitmap32_t = bitmap_specific<uint32_t>;
+extern template class bitmap_specific<uint32_t>;
// 64bpp bitmaps
using bitmap64_t = bitmap_specific<uint64_t>;
+extern template class bitmap_specific<uint64_t>;
// ======================> bitmap_ind8, bitmap_ind16, bitmap_ind32, bitmap_ind64
@@ -246,7 +268,7 @@ public:
bitmap_ind8(uint8_t *base, int width, int height, int rowpixels) : bitmap8_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind8(bitmap_ind8 &source, const rectangle &subrect) : bitmap8_t(k_bitmap_format, source, subrect) { }
void wrap(uint8_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -266,7 +288,7 @@ public:
bitmap_ind16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind16(bitmap_ind16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -286,7 +308,7 @@ public:
bitmap_ind32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind32(bitmap_ind32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -306,7 +328,7 @@ public:
bitmap_ind64(uint64_t *base, int width, int height, int rowpixels) : bitmap64_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind64(bitmap_ind64 &source, const rectangle &subrect) : bitmap64_t(k_bitmap_format, source, subrect) { }
void wrap(uint64_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -329,7 +351,7 @@ public:
bitmap_yuy16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_yuy16(bitmap_yuy16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -349,7 +371,7 @@ public:
bitmap_rgb32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_rgb32(bitmap_rgb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -369,7 +391,7 @@ public:
bitmap_argb32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_argb32(bitmap_argb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
- void wrap(const bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<const bitmap_t &>(source), subrect); }
+ void wrap(bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
@@ -377,5 +399,4 @@ public:
bitmap_argb32 &operator=(bitmap_argb32 &&) = default;
};
-
-#endif // MAME_UTIL_BITMAP_H
+#endif // MAME_UTIL_BITMAP_H
diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp
index 58f7b4291db..7f6e0f018cd 100644
--- a/src/lib/util/chdcodec.cpp
+++ b/src/lib/util/chdcodec.cpp
@@ -1786,7 +1786,7 @@ void chd_avhuff_decompressor::configure(int param, void *config)
{
// if we're getting the decompression configuration, apply it now
if (param == AVHUFF_CODEC_DECOMPRESS_CONFIG)
- m_decoder.configure(*reinterpret_cast<avhuff_decompress_config *>(config));
+ m_decoder.configure(*reinterpret_cast<avhuff_decoder::config const *>(config));
// anything else is invalid
else
diff --git a/src/lib/util/corealloc.h b/src/lib/util/corealloc.h
index 5d1f055e19b..db8aacf6cb2 100644
--- a/src/lib/util/corealloc.h
+++ b/src/lib/util/corealloc.h
@@ -8,54 +8,24 @@
***************************************************************************/
-#pragma once
-
#ifndef MAME_LIB_UTIL_COREALLOC_H
#define MAME_LIB_UTIL_COREALLOC_H
-#include "osdcore.h"
+#pragma once
-#include <cstdlib>
+#include "osdcore.h"
#include <cstddef>
+#include <cstdlib>
#include <cstring>
-#include <new>
#include <memory>
+#include <new>
#include <type_traits>
#include <utility>
-//**************************************************************************
-// MACROS
-//**************************************************************************
-
-// global allocation helpers -- use these instead of new and delete
-#define global_alloc(Type) new Type
-#define global_alloc_array(Type, Num) new Type[Num]
-#define global_free(Ptr) do { delete Ptr; } while (0)
-#define global_free_array(Ptr) do { delete[] Ptr; } while (0)
-
-
-
-template<typename T, typename... Params>
-inline T* global_alloc_clear(Params &&... args)
-{
- void *const ptr = ::operator new(sizeof(T)); // allocate memory
- std::memset(ptr, 0, sizeof(T));
- return new(ptr) T(std::forward<Params>(args)...);
-}
-
-template<typename T>
-inline T* global_alloc_array_clear(std::size_t num)
-{
- auto const size = sizeof(T) * num;
- void *const ptr = new unsigned char[size]; // allocate memory
- std::memset(ptr, 0, size);
- return new(ptr) T[num]();
-}
-
-
+// global allocation helpers
template<typename Tp> struct MakeUniqClearT { typedef std::unique_ptr<Tp> single_object; };
diff --git a/src/lib/util/coretmpl.h b/src/lib/util/coretmpl.h
index 95d8230f565..a06c4fb8a46 100644
--- a/src/lib/util/coretmpl.h
+++ b/src/lib/util/coretmpl.h
@@ -202,7 +202,7 @@ public:
if (m_tail == &toreplace)
m_tail = &object;
object.m_next = toreplace.m_next;
- global_free(&toreplace);
+ delete &toreplace;
return object;
}
return append(object);
@@ -253,7 +253,7 @@ public:
// remove the given object and free its memory
void remove(ElementType &object) noexcept
{
- global_free(&detach(object));
+ delete &detach(object);
}
// find an object by index in the list
@@ -305,7 +305,7 @@ public:
{
ItemType *result = m_freelist.detach_head();
if (result == nullptr)
- result = global_alloc(ItemType);
+ result = new ItemType;
return result;
}
diff --git a/src/lib/util/msdib.cpp b/src/lib/util/msdib.cpp
new file mode 100644
index 00000000000..a1ae5eaddf0
--- /dev/null
+++ b/src/lib/util/msdib.cpp
@@ -0,0 +1,642 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ msdib.h
+
+ Microsoft Device-Independent Bitmap file loading.
+
+***************************************************************************/
+
+#include "msdib.h"
+
+#include "eminline.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_DIB (1U << 1)
+
+//#define VERBOSE (LOG_GENERAL | LOG_DIB)
+
+#define LOG_OUTPUT_FUNC osd_printf_verbose
+
+#ifndef VERBOSE
+#define VERBOSE 0
+#endif
+
+#define LOGMASKED(mask, ...) do { if (VERBOSE & (mask)) (LOG_OUTPUT_FUNC)(__VA_ARGS__); } while (false)
+
+#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__)
+
+
+namespace util {
+
+namespace {
+
+// DIB compression schemes
+enum : std::uint32_t
+{
+ DIB_COMP_NONE = 0,
+ DIB_COMP_RLE8 = 1,
+ DIB_COMP_RLE4 = 2,
+ DIB_COMP_BITFIELDS = 3
+};
+
+
+// file header doesn't use natural alignment
+using bitmap_file_header = std::uint8_t [14];
+
+
+// old-style DIB header
+struct bitmap_core_header
+{
+ std::uint32_t size; // size of the header (12, 16 or 64)
+ std::int16_t width; // width of bitmap in pixels
+ std::int16_t height; // height of the image in pixels
+ std::uint16_t planes; // number of colour planes (must be 1)
+ std::uint16_t bpp; // bits per pixel
+};
+
+// new-style DIB header
+struct bitmap_info_header
+{
+ std::uint32_t size; // size of the header
+ std::int32_t width; // width of bitmap in pixels
+ std::int32_t height; // height of bitmap in pixels
+ std::uint16_t planes; // number of colour planes (must be 1)
+ std::uint16_t bpp; // bits per pixel
+ std::uint32_t comp; // compression method
+ std::uint32_t rawsize; // size of bitmap data after decompression or 0 if uncompressed
+ std::int32_t hres; // horizontal resolution in pixels/metre
+ std::int32_t vres; // horizontal resolution in pixels/metre
+ std::uint32_t colors; // number of colours or 0 for 1 << bpp
+ std::uint32_t important; // number of important colours or 0 if all important
+ std::uint32_t red; // red field mask - must be contiguous
+ std::uint32_t green; // green field mask - must be contiguous
+ std::uint32_t blue; // blue field mask - must be contiguous
+ std::uint32_t alpha; // alpha field mask - must be contiguous
+};
+
+
+union bitmap_headers
+{
+ bitmap_core_header core;
+ bitmap_info_header info;
+};
+
+
+bool dib_parse_mask(uint32_t mask, unsigned &shift, unsigned &bits)
+{
+ shift = count_leading_zeros(mask);
+ mask <<= shift;
+ bits = count_leading_ones(mask);
+ mask <<= shift;
+ shift = 32 - shift - bits;
+ return !mask;
+}
+
+
+void dib_truncate_channel(unsigned &shift, unsigned &bits)
+{
+ if (8U < bits)
+ {
+ unsigned const excess(bits - 8);
+ shift += excess;
+ bits -= excess;
+ }
+}
+
+
+uint8_t dib_splat_sample(uint8_t val, unsigned bits)
+{
+ assert(8U >= bits);
+ for (val <<= (8U - bits); bits && (8U > bits); bits <<= 1)
+ val |= val >> bits;
+ return val;
+}
+
+
+msdib_error dib_read_file_header(core_file &fp, std::uint32_t &filelen)
+{
+ // the bitmap file header doesn't use natural alignment
+ bitmap_file_header file_header;
+ if (fp.read(file_header, sizeof(file_header)) != sizeof(file_header))
+ {
+ LOG("Error reading DIB file header\n");
+ return msdib_error::FILE_TRUNCATED;
+ }
+
+ // only support Windows bitmaps for now
+ if ((0x42 != file_header[0]) || (0x4d != file_header[1]))
+ return msdib_error::BAD_SIGNATURE;
+
+ // do a very basic check on the file length
+ std::uint32_t const file_length(
+ (std::uint32_t(file_header[2]) << 0) |
+ (std::uint32_t(file_header[3]) << 8) |
+ (std::uint32_t(file_header[4]) << 16) |
+ (std::uint32_t(file_header[5]) << 24));
+ if ((sizeof(file_header) + sizeof(bitmap_core_header)) > file_length)
+ return msdib_error::FILE_CORRUPT;
+
+ // check that the offset to the pixel data looks half sane
+ std::uint32_t const pixel_offset(
+ (std::uint32_t(file_header[10]) << 0) |
+ (std::uint32_t(file_header[11]) << 8) |
+ (std::uint32_t(file_header[12]) << 16) |
+ (std::uint32_t(file_header[13]) << 24));
+ if (((sizeof(file_header) + sizeof(bitmap_core_header)) > pixel_offset) || (file_length < pixel_offset))
+ return msdib_error::FILE_CORRUPT;
+
+ // looks OK enough
+ filelen = file_length;
+ return msdib_error::NONE;
+}
+
+
+msdib_error dib_read_bitmap_header(
+ core_file &fp,
+ bitmap_headers &header,
+ unsigned &palette_bytes,
+ bool &indexed,
+ std::size_t &palette_entries,
+ std::size_t &palette_size,
+ std::size_t &row_bytes,
+ std::uint32_t length)
+{
+ // check that these things haven't been padded somehow
+ static_assert(sizeof(bitmap_core_header) == 12U, "compiler has applied padding to bitmap_core_header");
+ static_assert(sizeof(bitmap_info_header) == 56U, "compiler has applied padding to bitmap_info_header");
+
+ // ensure the header fits in the space for the image data
+ assert(&header.core.size == &header.info.size);
+ if (sizeof(header.core) > length)
+ return msdib_error::FILE_TRUNCATED;
+ std::memset(&header, 0, sizeof(header));
+ if (fp.read(&header.core.size, sizeof(header.core.size)) != sizeof(header.core.size))
+ {
+ LOG("Error reading DIB header size (length %u)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ header.core.size = little_endianize_int32(header.core.size);
+ if (length < header.core.size)
+ {
+ LOG("DIB image data (%u bytes) is too small for DIB header (%u bytes)\n", length, header.core.size);
+ return msdib_error::FILE_CORRUPT;
+ }
+
+ // identify and read the header - convert OS/2 headers to Windows 3 format
+ palette_bytes = 4U;
+ switch (header.core.size)
+ {
+ case 16U:
+ case 64U:
+ // extended OS/2 bitmap header with support for compression
+ LOG(
+ "DIB image data (%u bytes) uses unsupported OS/2 DIB header (size %u)\n",
+ length,
+ header.core.size);
+ return msdib_error::UNSUPPORTED_FORMAT;
+
+ case 12U:
+ // introduced in OS/2 and Windows 2.0
+ {
+ palette_bytes = 3U;
+ std::uint32_t const header_read(std::min<std::uint32_t>(header.core.size, sizeof(header.core)) - sizeof(header.core.size));
+ if (fp.read(&header.core.width, header_read) != header_read)
+ {
+ LOG("Error reading DIB core header from image data (%u bytes)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ fp.seek(header.core.size - sizeof(header.core.size) - header_read, SEEK_CUR);
+ header.core.width = little_endianize_int16(header.core.width);
+ header.core.height = little_endianize_int16(header.core.height);
+ header.core.planes = little_endianize_int16(header.core.planes);
+ header.core.bpp = little_endianize_int16(header.core.bpp);
+ LOGMASKED(
+ LOG_DIB,
+ "Read DIB core header from image data : %d*%d, %u planes, %u bpp\n",
+ header.core.width,
+ header.core.height,
+ header.core.planes,
+ header.core.bpp);
+
+ // this works because the core header only aliases the width/height of the info header
+ header.info.bpp = header.core.bpp;
+ header.info.planes = header.core.planes;
+ header.info.height = header.core.height;
+ header.info.width = header.core.width;
+ header.info.size = 40U;
+ }
+ break;
+
+ default:
+ // the next version will be longer
+ if (124U >= header.core.size)
+ {
+ LOG(
+ "DIB image data (%u bytes) uses unsupported DIB header format (size %u)\n",
+ length,
+ header.core.size);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+ // fall through
+ case 40U:
+ case 52U:
+ case 56U:
+ case 108U:
+ case 124U:
+ // the Windows 3 bitmap header with optional extensions
+ {
+ palette_bytes = 4U;
+ std::uint32_t const header_read(std::min<std::uint32_t>(header.info.size, sizeof(header.info)) - sizeof(header.info.size));
+ if (fp.read(&header.info.width, header_read) != header_read)
+ {
+ LOG("Error reading DIB info header from image data (%u bytes)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ fp.seek(header.info.size - sizeof(header.info.size) - header_read, SEEK_CUR);
+ header.info.width = little_endianize_int32(header.info.width);
+ header.info.height = little_endianize_int32(header.info.height);
+ header.info.planes = little_endianize_int16(header.info.planes);
+ header.info.bpp = little_endianize_int16(header.info.bpp);
+ header.info.comp = little_endianize_int32(header.info.comp);
+ header.info.rawsize = little_endianize_int32(header.info.rawsize);
+ header.info.hres = little_endianize_int32(header.info.hres);
+ header.info.vres = little_endianize_int32(header.info.vres);
+ header.info.colors = little_endianize_int32(header.info.colors);
+ header.info.important = little_endianize_int32(header.info.important);
+ header.info.red = little_endianize_int32(header.info.red);
+ header.info.green = little_endianize_int32(header.info.green);
+ header.info.blue = little_endianize_int32(header.info.blue);
+ header.info.alpha = little_endianize_int32(header.info.alpha);
+ LOGMASKED(
+ LOG_DIB,
+ "Read DIB info header from image data: %d*%d (%d*%d ppm), %u planes, %u bpp %u/%s%u colors\n",
+ header.info.width,
+ header.info.height,
+ header.info.hres,
+ header.info.vres,
+ header.info.planes,
+ header.info.bpp,
+ header.info.important,
+ header.info.colors ? "" : "2^",
+ header.info.colors ? header.info.colors : header.info.bpp);
+ }
+ break;
+ }
+
+ // check for unsupported planes/bit depth
+ if ((1U != header.info.planes) || !header.info.bpp || (32U < header.info.bpp) || ((8U < header.info.bpp) ? (header.info.bpp % 8) : (8 % header.info.bpp)))
+ {
+ LOG("DIB image data uses unsupported planes/bits per pixel %u*%u\n", header.info.planes, header.info.bpp);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+
+ // check dimensions
+ if ((0 >= header.info.width) || (0 == header.info.height))
+ {
+ LOG("DIB image data has invalid dimensions %u*%u\n", header.info.width, header.info.height);
+ return msdib_error::FILE_CORRUPT;
+ }
+
+ // ensure compression scheme is supported
+ bool no_palette(false);
+ indexed = true;
+ switch (header.info.comp)
+ {
+ case DIB_COMP_NONE:
+ // uncompressed - direct colour with implied bitfields if more than eight bits/pixel
+ indexed = 8U >= header.info.bpp;
+ if (indexed)
+ {
+ if ((1U << header.info.bpp) < header.info.colors)
+ {
+ osd_printf_verbose(
+ "DIB image data has oversized palette with %u entries for %u bits per pixel\n",
+ header.info.colors,
+ header.info.bpp);
+ }
+ }
+ if (!indexed)
+ {
+ no_palette = true;
+ switch(header.info.bpp)
+ {
+ case 16U:
+ header.info.red = 0x00007c00;
+ header.info.green = 0x000003e0;
+ header.info.blue = 0x0000001f;
+ header.info.alpha = 0x00000000;
+ break;
+ case 24U:
+ case 32U:
+ header.info.red = 0x00ff0000;
+ header.info.green = 0x0000ff00;
+ header.info.blue = 0x000000ff;
+ header.info.alpha = 0x00000000;
+ break;
+ }
+ }
+ break;
+
+ case DIB_COMP_BITFIELDS:
+ // uncompressed direct colour with explicitly-specified bitfields
+ indexed = false;
+ if (offsetof(bitmap_info_header, alpha) > header.info.size)
+ {
+ osd_printf_verbose(
+ "DIB image data specifies bit masks but is too small (size %u)\n",
+ header.info.size);
+ return msdib_error::FILE_CORRUPT;
+ }
+ break;
+
+ default:
+ LOG("DIB image data uses unsupported compression scheme %u\n", header.info.comp);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+
+ // we can now calculate the size of the palette and row data
+ palette_entries =
+ indexed
+ ? ((1U == header.info.bpp) ? 2U : header.info.colors ? header.info.colors : (1U << header.info.bpp))
+ : (no_palette ? 0U : header.info.colors);
+ palette_size = palette_bytes * palette_entries;
+ row_bytes = ((31 + (header.info.width * header.info.bpp)) >> 5) << 2;
+
+ // header looks OK
+ return msdib_error::NONE;
+}
+
+} // anonymous namespace
+
+
+
+msdib_error msdib_verify_header(core_file &fp)
+{
+ msdib_error err;
+
+ // file header
+ std::uint32_t file_length;
+ err = dib_read_file_header(fp, file_length);
+ if (msdib_error::NONE != err)
+ return err;
+
+ // bitmap header
+ bitmap_headers header;
+ unsigned palette_bytes;
+ bool indexed;
+ std::size_t palette_entries, palette_size, row_bytes;
+ err = dib_read_bitmap_header(
+ fp,
+ header,
+ palette_bytes,
+ indexed,
+ palette_entries,
+ palette_size,
+ row_bytes,
+ file_length - sizeof(bitmap_file_header));
+ if (msdib_error::NONE != err)
+ return err;
+
+ // check length
+ std::size_t const required_size(
+ sizeof(bitmap_file_header) +
+ header.info.size +
+ palette_size +
+ (row_bytes * std::abs(header.info.height)));
+ if (required_size > file_length)
+ return msdib_error::FILE_TRUNCATED;
+
+ // good chance this file is supported
+ return msdib_error::NONE;
+}
+
+
+msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap)
+{
+ std::uint32_t file_length;
+ msdib_error const headerr(dib_read_file_header(fp, file_length));
+ if (msdib_error::NONE != headerr)
+ return headerr;
+
+ return msdib_read_bitmap_data(fp, bitmap, file_length - sizeof(bitmap_file_header), 0U);
+}
+
+
+msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight)
+{
+ // read the bitmap header
+ bitmap_headers header;
+ unsigned palette_bytes;
+ bool indexed;
+ std::size_t palette_entries, palette_size, row_bytes;
+ msdib_error const head_error(dib_read_bitmap_header(fp, header, palette_bytes, indexed, palette_entries, palette_size, row_bytes, length));
+ if (msdib_error::NONE != head_error)
+ return head_error;
+
+ // check dimensions
+ bool const top_down(0 > header.info.height);
+ if (top_down)
+ header.info.height = -header.info.height;
+ bool have_and_mask((2 * dirheight) == header.info.height);
+ if (!have_and_mask && (0 < dirheight) && (dirheight != header.info.height))
+ {
+ osd_printf_verbose(
+ "DIB image data height %d doesn't match directory height %u with or without AND mask\n",
+ header.info.height,
+ dirheight);
+ return msdib_error::UNSUPPORTED_FORMAT;
+ }
+ if (have_and_mask)
+ header.info.height >>= 1;
+
+ // we can now calculate the size of the image data
+ std::size_t const mask_row_bytes(((31 + header.info.width) >> 5) << 2);
+ std::size_t const required_size(
+ header.info.size +
+ palette_size +
+ ((row_bytes + (have_and_mask ? mask_row_bytes : 0U)) * header.info.height));
+ if (required_size > length)
+ {
+ LOG("DIB image data (%u bytes) smaller than calculated DIB data size (%u bytes)\n", length, required_size);
+ return msdib_error::FILE_TRUNCATED;
+ }
+
+ // load the palette for indexed colour formats or the shifts for direct colour formats
+ unsigned red_shift(0), green_shift(0), blue_shift(0), alpha_shift(0);
+ unsigned red_bits(0), green_bits(0), blue_bits(0), alpha_bits(0);
+ std::unique_ptr<rgb_t []> palette;
+ if (indexed)
+ {
+ // read palette and convert
+ std::unique_ptr<std::uint8_t []> palette_data;
+ try { palette_data.reset(new std::uint8_t [palette_size]); }
+ catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; }
+ if (fp.read(palette_data.get(), palette_size) != palette_size)
+ {
+ LOG("Error reading palette from DIB image data (%u bytes)\n", length);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ std::size_t const palette_usable(std::min<std::size_t>(palette_entries, std::size_t(1) << header.info.bpp));
+ try { palette.reset(new rgb_t [palette_usable]); }
+ catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; }
+ std::uint8_t const *ptr(palette_data.get());
+ for (std::size_t i = 0; palette_usable > i; ++i, ptr += palette_bytes)
+ palette[i] = rgb_t(ptr[2], ptr[1], ptr[0]);
+ }
+ else
+ {
+ // skip over the palette if necessary
+ if (palette_entries)
+ fp.seek(palette_bytes * palette_entries, SEEK_CUR);
+
+ // convert masks to shifts
+ bool const masks_contiguous(
+ dib_parse_mask(header.info.red, red_shift, red_bits) &&
+ dib_parse_mask(header.info.green, green_shift, green_bits) &&
+ dib_parse_mask(header.info.blue, blue_shift, blue_bits) &&
+ dib_parse_mask(header.info.alpha, alpha_shift, alpha_bits));
+ if (!masks_contiguous)
+ {
+ osd_printf_verbose(
+ "DIB image data specifies non-contiguous channel masks 0x%x | 0x%x | 0x%x | 0x%x\n",
+ header.info.red,
+ header.info.green,
+ header.info.blue,
+ header.info.alpha);
+ }
+ if ((32U != header.info.bpp) && ((header.info.red | header.info.green | header.info.blue | header.info.alpha) >> header.info.bpp))
+ {
+ LOG(
+ "DIB image data specifies channel masks 0x%x | 0x%x | 0x%x | 0x%x that exceed %u bits per pixel\n",
+ header.info.red,
+ header.info.green,
+ header.info.blue,
+ header.info.alpha,
+ header.info.bpp);
+ return msdib_error::FILE_CORRUPT;
+ }
+ LOGMASKED(
+ LOG_DIB,
+ "DIB image data using channels: R((x >> %2$u) & 0x%3$0*1$x) G((x >> %4$u) & 0x%5$0*1$x) B((x >> %6$u) & 0x%7$0*1$x) A((x >> %8$u) & 0x%9$0*1$x)\n",
+ (header.info.bpp + 3) >> 2,
+ red_shift,
+ (std::uint32_t(1) << red_bits) - 1,
+ green_shift,
+ (std::uint32_t(1) << green_bits) - 1,
+ blue_shift,
+ (std::uint32_t(1) << blue_bits) - 1,
+ alpha_shift,
+ (std::uint32_t(1) << alpha_bits) - 1);
+
+ // the MAME bitmap only supports 8 bits/sample maximum
+ dib_truncate_channel(red_shift, red_bits);
+ dib_truncate_channel(green_shift, green_bits);
+ dib_truncate_channel(blue_shift, blue_bits);
+ dib_truncate_channel(alpha_shift, alpha_bits);
+ }
+
+ // allocate the bitmap and process row data
+ std::unique_ptr<std::uint8_t []> row_data;
+ try {row_data.reset(new std::uint8_t [row_bytes]); }
+ catch (std::bad_alloc const &) { return msdib_error::OUT_OF_MEMORY; }
+ bitmap.allocate(header.info.width, header.info.height);
+ int const y_inc(top_down ? 1 : -1);
+ for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
+ {
+ if (fp.read(row_data.get(), row_bytes) != row_bytes)
+ {
+ LOG("Error reading DIB row %d data from image data\n", i);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ std::uint8_t *src(row_data.get());
+ std::uint32_t *dest(&bitmap.pix(y));
+ unsigned shift(0U);
+ for (std::int32_t x = 0; header.info.width > x; ++x, ++dest)
+ {
+ // extract or compose a pixel
+ std::uint32_t pix(0U);
+ if (8U >= header.info.bpp)
+ {
+ assert(8U > shift);
+ pix = *src >> (8U - header.info.bpp);
+ *src <<= header.info.bpp;
+ shift += header.info.bpp;
+ if (8U <= shift)
+ {
+ shift = 0U;
+ ++src;
+ }
+ }
+ else for (shift = 0; header.info.bpp > shift; shift += 8U, ++src)
+ {
+ pix |= std::uint32_t(*src) << shift;
+ }
+
+ // convert to RGB
+ if (indexed)
+ {
+ if (palette_entries > pix)
+ {
+ *dest = palette[pix];
+ }
+ else
+ {
+ *dest = rgb_t::transparent();
+ osd_printf_verbose(
+ "DIB image data has out-of-range color %u at (%d, %d) with %u palette entries\n",
+ pix,
+ x,
+ y,
+ palette_entries);
+ }
+ }
+ else
+ {
+ std::uint8_t r(dib_splat_sample((pix >> red_shift) & ((std::uint32_t(1) << red_bits) - 1), red_bits));
+ std::uint8_t g(dib_splat_sample((pix >> green_shift) & ((std::uint32_t(1) << green_bits) - 1), green_bits));
+ std::uint8_t b(dib_splat_sample((pix >> blue_shift) & ((std::uint32_t(1) << blue_bits) - 1), blue_bits));
+ std::uint8_t a(dib_splat_sample((pix >> alpha_shift) & ((std::uint32_t(1) << alpha_bits) - 1), alpha_bits));
+ *dest = rgb_t(alpha_bits ? a : 255, r, g, b);
+ }
+ }
+ }
+
+ // process the AND mask if present
+ if (have_and_mask)
+ {
+ for (std::int32_t i = 0, y = top_down ? 0 : (header.info.height - 1); header.info.height > i; ++i, y += y_inc)
+ {
+ if (fp.read(row_data.get(), mask_row_bytes) != mask_row_bytes)
+ {
+ LOG("Error reading DIB mask row %d data from image data\n", i);
+ return msdib_error::FILE_TRUNCATED;
+ }
+ std::uint8_t *src(row_data.get());
+ std::uint32_t *dest(&bitmap.pix(y));
+ unsigned shift(0U);
+ for (std::int32_t x = 0; header.info.width > x; ++x, ++dest)
+ {
+ assert(8U > shift);
+ rgb_t pix(*dest);
+ *dest = pix.set_a(BIT(*src, 7U - shift) ? 0U : pix.a());
+ if (8U <= ++shift)
+ {
+ shift = 0U;
+ ++src;
+ }
+ }
+ }
+ }
+
+ // we're done!
+ return msdib_error::NONE;
+}
+
+} // namespace util
diff --git a/src/lib/util/msdib.h b/src/lib/util/msdib.h
new file mode 100644
index 00000000000..54767e216fb
--- /dev/null
+++ b/src/lib/util/msdib.h
@@ -0,0 +1,46 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ msdib.h
+
+ Microsoft Device-Independent Bitmap file loading.
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_MSDIB_H
+#define MAME_LIB_UTIL_MSDIB_H
+
+#pragma once
+
+#include "bitmap.h"
+#include "corefile.h"
+#include "osdcore.h"
+
+#include <cstdint>
+
+
+namespace util {
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+// Error types
+enum class msdib_error
+{
+ NONE,
+ OUT_OF_MEMORY,
+ FILE_ERROR,
+ BAD_SIGNATURE,
+ FILE_TRUNCATED,
+ FILE_CORRUPT,
+ UNSUPPORTED_FORMAT
+};
+
+msdib_error msdib_verify_header(core_file &fp);
+msdib_error msdib_read_bitmap(core_file &fp, bitmap_argb32 &bitmap);
+msdib_error msdib_read_bitmap_data(core_file &fp, bitmap_argb32 &bitmap, std::uint32_t length, std::uint32_t dirheight = 0U);
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_MSDIB_H
diff --git a/src/lib/util/nanosvg.cpp b/src/lib/util/nanosvg.cpp
index 09973865675..0cb05308d19 100644
--- a/src/lib/util/nanosvg.cpp
+++ b/src/lib/util/nanosvg.cpp
@@ -1,6 +1,10 @@
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#define NANOSVG_ALL_COLOR_KEYWORDS
#define NANOSVG_IMPLEMENTATION
#define NANOSVGRAST_IMPLEMENTATION
-#define NANOSVG_ALL_COLOR_KEYWORDS
#include <nanosvg/src/nanosvg.h>
#include <nanosvg/src/nanosvgrast.h>
diff --git a/src/lib/util/nanosvg.h b/src/lib/util/nanosvg.h
new file mode 100644
index 00000000000..49940f0b9be
--- /dev/null
+++ b/src/lib/util/nanosvg.h
@@ -0,0 +1,33 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ nanosvg.h
+
+ NanoSVG helpers.
+
+***************************************************************************/
+#ifndef MAME_LIB_UTIL_NANOSVG_H
+#define MAME_LIB_UTIL_NANOSVG_H
+
+#include <nanosvg/src/nanosvg.h>
+#include <nanosvg/src/nanosvgrast.h>
+
+#include <memory>
+
+
+namespace util {
+
+struct nsvg_deleter
+{
+ void operator()(NSVGimage *ptr) const { nsvgDelete(ptr); }
+ void operator()(NSVGrasterizer *ptr) const { nsvgDeleteRasterizer(ptr); }
+};
+
+
+using nsvg_image_ptr = std::unique_ptr<NSVGimage, nsvg_deleter>;
+using nsvg_rasterizer_ptr = std::unique_ptr<NSVGrasterizer, nsvg_deleter>;
+
+} // namespace util
+
+#endif // MAME_LIB_UTIL_NANOSVG_H
diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp
index 6b59436750c..50aeb28c5fe 100644
--- a/src/lib/util/png.cpp
+++ b/src/lib/util/png.cpp
@@ -2,7 +2,7 @@
// copyright-holders:Aaron Giles, Vas Crabb
/*********************************************************************
- png.c
+ png.cpp
PNG reading functions.
@@ -16,34 +16,13 @@
#include <algorithm>
#include <cassert>
-#include <cstdint>
-#include <cstring>
-#include <cmath>
-#include <new>
-
#include <cmath>
#include <cstdlib>
+#include <cstring>
+#include <new>
-
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
-
-static const int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-static inline int compute_rowbytes(const png_info &pnginfo)
-{
- return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8;
-}
-
-
+namespace util {
/***************************************************************************
GENERAL FUNCTIONS
@@ -66,6 +45,12 @@ void png_info::free_data()
namespace {
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+constexpr int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
+
constexpr std::uint8_t PNG_SIGNATURE[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
#define MNG_Signature "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A"
@@ -101,6 +86,12 @@ constexpr std::uint8_t PNG_PF_Average = 3;
constexpr std::uint8_t PNG_PF_Paeth = 4;
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+inline int compute_rowbytes(const png_info &pnginfo) { return (pnginfo.width * samples[pnginfo.color_type] * pnginfo.bit_depth + 7) / 8; }
+
inline uint8_t fetch_8bit(uint8_t const *v) { return *v; }
inline uint16_t fetch_16bit(uint8_t const *v) { return big_endianize_int16(*reinterpret_cast<uint16_t const *>(v)); }
inline uint32_t fetch_32bit(uint8_t const *v) { return big_endianize_int32(*reinterpret_cast<uint32_t const *>(v)); }
@@ -132,11 +123,11 @@ private:
{
// do some basic checks for unsupported images
if (!pnginfo.bit_depth || (ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour format
+ return png_error::UNSUPPORTED_FORMAT; // unknown colour format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
if ((3 == pnginfo.color_type) && (!pnginfo.num_palette || !pnginfo.palette))
- return PNGERR_FILE_CORRUPT; // indexed colour with no palette
+ return png_error::FILE_CORRUPT; // indexed colour with no palette
// calculate the offset for each pass of the interlace
unsigned const pass_count(get_pass_count());
@@ -146,13 +137,13 @@ private:
// allocate memory for the filtered image
try { pnginfo.image.reset(new std::uint8_t [pass_offset[pass_count]]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
// decompress image data
- png_error error = PNGERR_NONE;
+ png_error error = png_error::NONE;
error = decompress(idata, pass_offset[pass_count]);
std::uint32_t const bpp(get_bytes_per_pixel());
- for (unsigned pass = 0; (pass_count > pass) && (PNGERR_NONE == error); ++pass)
+ for (unsigned pass = 0; (pass_count > pass) && (png_error::NONE == error); ++pass)
{
// compute some basic parameters
std::pair<std::uint32_t, std::uint32_t> const dimensions(get_pass_dimensions(pass));
@@ -161,7 +152,7 @@ private:
// we de-filter in place, stripping the filter bytes off the rows
uint8_t *dst(&pnginfo.image[pass_offset[pass]]);
uint8_t const *src(dst);
- for (std::uint32_t y = 0; (dimensions.second > y) && (PNGERR_NONE == error); ++y)
+ for (std::uint32_t y = 0; (dimensions.second > y) && (png_error::NONE == error); ++y)
{
// first byte of each row is the filter type
uint8_t const filter(*src++);
@@ -172,7 +163,7 @@ private:
}
// if we errored, free the image data
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
pnginfo.image.reset();
return error;
@@ -182,7 +173,7 @@ private:
{
// only deflate is permitted
if (0 != pnginfo.compression_method)
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
// allocate zlib stream
z_stream stream;
@@ -195,7 +186,7 @@ private:
stream.next_in = Z_NULL;
zerr = inflateInit(&stream);
if (Z_OK != zerr)
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
// decompress IDAT blocks
stream.next_out = pnginfo.image.get();
@@ -217,28 +208,28 @@ private:
// it's all good if we got end-of-stream or we have with no data remaining
if ((Z_OK == inflateEnd(&stream)) && ((Z_STREAM_END == zerr) || ((Z_OK == zerr) && (idata.end() == it) && !stream.avail_in)))
- return PNGERR_NONE;
+ return png_error::NONE;
else
- return PNGERR_DECOMPRESS_ERROR;
+ return png_error::DECOMPRESS_ERROR;
}
png_error unfilter_row(std::uint8_t type, uint8_t const *src, uint8_t *dst, uint8_t const *dstprev, int bpp, std::uint32_t rowbytes)
{
if (0 != pnginfo.filter_method)
- return PNGERR_UNKNOWN_FILTER;
+ return png_error::UNKNOWN_FILTER;
switch (type)
{
case PNG_PF_None: // no filter, just copy
std::copy_n(src, rowbytes, dst);
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Sub: // SUB = previous pixel
dst = std::copy_n(src, bpp, dst);
src += bpp;
for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst)
*dst = *src + dst[-bpp];
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Up: // UP = pixel above
if (dstprev)
@@ -250,7 +241,7 @@ private:
{
std::copy_n(src, rowbytes, dst);
}
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Average: // AVERAGE = average of pixel above and previous pixel
if (dstprev)
@@ -267,7 +258,7 @@ private:
for (std::uint32_t x = bpp; rowbytes > x; ++x, ++src, ++dst)
*dst = *src + (dst[-bpp] >> 1);
}
- return PNGERR_NONE;
+ return png_error::NONE;
case PNG_PF_Paeth: // PAETH = special filter
for (std::uint32_t x = 0; rowbytes > x; ++x, ++src, ++dst)
@@ -281,10 +272,10 @@ private:
int32_t const dc(std::abs(prediction - pc));
*dst = ((da <= db) && (da <= dc)) ? (*src + pa) : (db <= dc) ? (*src + pb) : (*src + pc);
}
- return PNGERR_NONE;
+ return png_error::NONE;
default: // unknown filter type
- return PNGERR_UNKNOWN_FILTER;
+ return png_error::UNKNOWN_FILTER;
}
}
@@ -294,7 +285,7 @@ private:
{
case PNG_CN_IHDR: // image header
if (13 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.width = fetch_32bit(&data[0]);
pnginfo.height = fetch_32bit(&data[4]);
pnginfo.bit_depth = fetch_8bit(&data[8]);
@@ -307,31 +298,31 @@ private:
case PNG_CN_PLTE: // palette
pnginfo.num_palette = length / 3;
if ((length % 3) || ((3 == pnginfo.color_type) && ((1 << pnginfo.bit_depth) < pnginfo.num_palette)))
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.palette = std::move(data);
break;
case PNG_CN_tRNS: // transparency information
if (((0 == pnginfo.color_type) && (2 > length)) || ((2 == pnginfo.color_type) && (6 > length)))
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.num_trans = length;
pnginfo.trans = std::move(data);
break;
case PNG_CN_IDAT: // image data
try { idata.emplace_back(length, std::move(data)); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
break;
case PNG_CN_gAMA: // gamma
if (4 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.source_gamma = fetch_32bit(data.get()) / 100000.0;
break;
case PNG_CN_pHYs: // physical information
if (9 > length)
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
pnginfo.xres = fetch_32bit(&data[0]);
pnginfo.yres = fetch_32bit(&data[4]);
pnginfo.resolution_unit = fetch_8bit(&data[8]);
@@ -361,17 +352,17 @@ private:
}
catch (std::bad_alloc const &)
{
- return PNGERR_OUT_OF_MEMORY;
+ return png_error::OUT_OF_MEMORY;
}
break;
/* anything else */
default:
if ((type & 0x20000000) == 0)
- return PNGERR_UNKNOWN_CHUNK;
+ return png_error::UNKNOWN_CHUNK;
break;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
unsigned get_pass_count() const
@@ -413,23 +404,23 @@ private:
return ((samples[pnginfo.color_type] * pnginfo.bit_depth) + 7) >> 3;
}
- static png_error read_chunk(util::core_file &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length)
+ static png_error read_chunk(core_file &fp, std::unique_ptr<std::uint8_t []> &data, std::uint32_t &type, std::uint32_t &length)
{
std::uint8_t tempbuff[4];
/* fetch the length of this chunk */
if (fp.read(tempbuff, 4) != 4)
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
length = fetch_32bit(tempbuff);
/* fetch the type of this chunk */
if (fp.read(tempbuff, 4) != 4)
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
type = fetch_32bit(tempbuff);
/* stop when we hit an IEND chunk */
if (type == PNG_CN_IEND)
- return PNGERR_NONE;
+ return png_error::NONE;
/* start the CRC with the chunk type (but not the length) */
std::uint32_t crc = crc32(0, tempbuff, 4);
@@ -439,13 +430,13 @@ private:
{
/* allocate memory for this chunk */
try { data.reset(new std::uint8_t [length]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
/* read the data from the file */
if (fp.read(data.get(), length) != length)
{
data.reset();
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
}
/* update the CRC */
@@ -456,7 +447,7 @@ private:
if (fp.read(tempbuff, 4) != 4)
{
data.reset();
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
}
std::uint32_t const chunk_crc = fetch_32bit(tempbuff);
@@ -464,10 +455,10 @@ private:
if (crc != chunk_crc)
{
data.reset();
- return PNGERR_FILE_CORRUPT;
+ return png_error::FILE_CORRUPT;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
png_info & pnginfo;
@@ -481,13 +472,13 @@ public:
{
// do some basic checks for unsupported images
if ((8 > pnginfo.bit_depth) || (pnginfo.bit_depth % 8))
- return PNGERR_UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
+ return png_error::UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
if ((ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour sample format
+ return png_error::UNSUPPORTED_FORMAT; // unknown colour sample format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
if ((3 == pnginfo.color_type) && (8 != pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
+ return png_error::UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
// everything looks sane, allocate the bitmap and deinterlace into it
bitmap.allocate(pnginfo.width, pnginfo.height);
@@ -519,7 +510,7 @@ public:
accumalpha &= alpha;
std::uint16_t const paloffs(std::uint16_t(*src) * 3);
rgb_t const pix(alpha, pnginfo.palette[paloffs], pnginfo.palette[paloffs + 1], pnginfo.palette[paloffs + 2]);
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
@@ -537,7 +528,7 @@ public:
std::uint8_t const a_val((pnginfo.trans && (transpen == i_val)) ? 0x00 : 0xff);
i_val >>= samp_shift;
accumalpha &= a_val;
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, i_val, i_val, i_val);
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, i_val, i_val, i_val);
}
}
}
@@ -552,7 +543,7 @@ public:
{
accumalpha &= src[a];
rgb_t const pix(src[a], src[i], src[i], src[i]);
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
@@ -578,7 +569,7 @@ public:
g_val >>= samp_shift;
b_val >>= samp_shift;
accumalpha &= a_val;
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, r_val, g_val, b_val);
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = rgb_t(a_val, r_val, g_val, b_val);
}
}
}
@@ -595,7 +586,7 @@ public:
{
accumalpha &= src[a];
rgb_t const pix(src[a], src[r], src[g], src[b]);
- bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
+ bitmap.pix((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
@@ -603,22 +594,22 @@ public:
// set hasalpha flag and return
hasalpha = 0xffU != accumalpha;
- return PNGERR_NONE;
+ return png_error::NONE;
}
png_error expand_buffer_8bit()
{
// nothing to do if we're at 8 or greater already
if (pnginfo.bit_depth >= 8)
- return PNGERR_NONE;
+ return png_error::NONE;
// do some basic checks for unsupported images
if (!pnginfo.bit_depth || (8 % pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
+ return png_error::UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
if ((0 != pnginfo.color_type) && (3 != pnginfo.color_type))
- return PNGERR_UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
+ return png_error::UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
+ return png_error::UNSUPPORTED_FORMAT; // unknown interlace method
// calculate the offset for each pass of the interlace on the input and output
unsigned const pass_count(get_pass_count());
@@ -633,7 +624,7 @@ public:
// allocate a new buffer at 8-bit
std::unique_ptr<std::uint8_t []> outbuf;
try { outbuf.reset(new std::uint8_t [outp_offset[pass_count]]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
// upsample bitmap
std::uint8_t const bytesamples(8 / pnginfo.bit_depth);
@@ -687,13 +678,13 @@ public:
pnginfo.image = std::move(outbuf);
pnginfo.bit_depth = 8;
- return PNGERR_NONE;
+ return png_error::NONE;
}
- png_error read_file(util::core_file &fp)
+ png_error read_file(core_file &fp)
{
// initialize the data structures
- png_error error = PNGERR_NONE;
+ png_error error = png_error::NONE;
pnginfo.reset();
std::list<image_data_chunk> idata;
@@ -701,13 +692,13 @@ public:
error = verify_header(fp);
// loop until we hit an IEND chunk
- while (PNGERR_NONE == error)
+ while (png_error::NONE == error)
{
// read a chunk
std::unique_ptr<std::uint8_t []> chunk_data;
std::uint32_t chunk_type = 0, chunk_length;
error = read_chunk(fp, chunk_data, chunk_type, chunk_length);
- if (PNGERR_NONE == error)
+ if (png_error::NONE == error)
{
if (chunk_type == PNG_CN_IEND)
break; // stop when we hit an IEND chunk
@@ -717,29 +708,29 @@ public:
}
// finish processing the image
- if (PNGERR_NONE == error)
+ if (png_error::NONE == error)
error = process(idata);
// if we have an error, free all the output data
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
pnginfo.reset();
return error;
}
- static png_error verify_header(util::core_file &fp)
+ static png_error verify_header(core_file &fp)
{
EQUIVALENT_ARRAY(PNG_SIGNATURE, std::uint8_t) signature;
// read 8 bytes
if (fp.read(signature, sizeof(signature)) != sizeof(signature))
- return PNGERR_FILE_TRUNCATED;
+ return png_error::FILE_TRUNCATED;
// return an error if we don't match
if (std::memcmp(signature, PNG_SIGNATURE, sizeof(PNG_SIGNATURE)))
- return PNGERR_BAD_SIGNATURE;
+ return png_error::BAD_SIGNATURE;
- return PNGERR_NONE;
+ return png_error::NONE;
}
};
@@ -760,7 +751,7 @@ constexpr unsigned png_private::ADAM7_Y_OFFS[7];
core stream
-------------------------------------------------*/
-png_error png_info::verify_header(util::core_file &fp)
+png_error png_info::verify_header(core_file &fp)
{
return png_private::verify_header(fp);
}
@@ -770,7 +761,7 @@ png_error png_info::verify_header(util::core_file &fp)
read_file - read a PNG from a core stream
-------------------------------------------------*/
-png_error png_info::read_file(util::core_file &fp)
+png_error png_info::read_file(core_file &fp)
{
return png_private(*this).read_file(fp);
}
@@ -781,7 +772,7 @@ png_error png_info::read_file(util::core_file &fp)
bitmap
-------------------------------------------------*/
-png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
+png_error png_read_bitmap(core_file &fp, bitmap_argb32 &bitmap)
{
png_error result;
png_info pnginfo;
@@ -789,12 +780,12 @@ png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap)
// read the PNG data
result = png.read_file(fp);
- if (PNGERR_NONE != result)
+ if (png_error::NONE != result)
return result;
// resample to 8bpp if necessary
result = png.expand_buffer_8bit();
- if (PNGERR_NONE != result)
+ if (png_error::NONE != result)
{
pnginfo.free_data();
return result;
@@ -848,13 +839,13 @@ png_error png_info::add_text(const char *keyword, const char *text)
char32_t ch;
int const len(uchar_from_utf8(&ch, ptr, kwend - ptr));
if ((0 >= len) || (32 > ch) || (255 < ch) || ((126 < ch) && (161 > ch)) || (((32 == prev) || (keyword == ptr)) && (32 == ch)))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
prev = ch;
++cnt;
ptr += len;
}
if ((32 == prev) || (1 > cnt) || (79 < cnt))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
// apply rules to text
char const *const textend(text + std::strlen(text));
@@ -863,14 +854,14 @@ png_error png_info::add_text(const char *keyword, const char *text)
char32_t ch;
int const len(uchar_from_utf8(&ch, ptr, textend - ptr));
if ((0 >= len) || (1 > ch) || (255 < ch))
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
ptr += len;
}
// allocate a new text element
try { textlist.emplace_back(std::piecewise_construct, std::forward_as_tuple(keyword, kwend), std::forward_as_tuple(text, textend)); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
- return PNGERR_NONE;
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
+ return png_error::NONE;
}
@@ -879,7 +870,7 @@ png_error png_info::add_text(const char *keyword, const char *text)
the given file
-------------------------------------------------*/
-static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t type, uint32_t length)
+static png_error write_chunk(core_file &fp, const uint8_t *data, uint32_t type, uint32_t length)
{
uint8_t tempbuff[8];
uint32_t crc;
@@ -891,22 +882,22 @@ static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t
/* write that data */
if (fp.write(tempbuff, 8) != 8)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* append the actual data */
if (length > 0)
{
if (fp.write(data, length) != length)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
crc = crc32(crc, data, length);
}
/* write the CRC */
put_32bit(tempbuff, crc);
if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -915,7 +906,7 @@ static png_error write_chunk(util::core_file &fp, const uint8_t *data, uint32_t
chunk to the given file by deflating it
-------------------------------------------------*/
-static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32_t type, uint32_t length)
+static png_error write_deflated_chunk(core_file &fp, uint8_t *data, uint32_t type, uint32_t length)
{
uint64_t lengthpos = fp.tell();
uint8_t tempbuff[8192];
@@ -931,7 +922,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
/* write that data */
if (fp.write(tempbuff, 8) != 8)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* initialize the stream */
memset(&stream, 0, sizeof(stream));
@@ -939,7 +930,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
stream.avail_in = length;
zerr = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
if (zerr != Z_OK)
- return PNGERR_COMPRESS_ERROR;
+ return png_error::COMPRESS_ERROR;
/* now loop until we run out of data */
for ( ; ; )
@@ -956,7 +947,7 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
if (fp.write(tempbuff, bytes) != bytes)
{
deflateEnd(&stream);
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
}
crc = crc32(crc, tempbuff, bytes);
zlength += bytes;
@@ -970,29 +961,29 @@ static png_error write_deflated_chunk(util::core_file &fp, uint8_t *data, uint32
if (zerr != Z_OK)
{
deflateEnd(&stream);
- return PNGERR_COMPRESS_ERROR;
+ return png_error::COMPRESS_ERROR;
}
}
/* clean up deflater(maus) */
zerr = deflateEnd(&stream);
if (zerr != Z_OK)
- return PNGERR_COMPRESS_ERROR;
+ return png_error::COMPRESS_ERROR;
/* write the CRC */
put_32bit(tempbuff, crc);
if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* seek back and update the length */
fp.seek(lengthpos, SEEK_SET);
put_32bit(tempbuff + 0, zlength);
if (fp.write(tempbuff, 4) != 4)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* return to the end */
fp.seek(lengthpos + 8 + zlength + 4, SEEK_SET);
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -1016,7 +1007,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
/* allocate memory for the palette */
try { pnginfo.palette.reset(new std::uint8_t [3 * 256]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
/* build the palette */
std::fill_n(pnginfo.palette.get(), 3 * 256, 0);
@@ -1036,13 +1027,13 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
catch (std::bad_alloc const &)
{
pnginfo.palette.reset();
- return PNGERR_OUT_OF_MEMORY;
+ return png_error::OUT_OF_MEMORY;
}
/* copy in the pixels, specifying a nullptr filter */
for (y = 0; y < pnginfo.height; y++)
{
- auto *src = reinterpret_cast<uint16_t *>(bitmap.raw_pixptr(y));
+ uint16_t const *src = reinterpret_cast<uint16_t const *>(bitmap.raw_pixptr(y));
uint8_t *dst = &pnginfo.image[y * (rowbytes + 1)];
/* store the filter byte, then copy the data */
@@ -1051,7 +1042,7 @@ static png_error convert_bitmap_to_image_palette(png_info &pnginfo, const bitmap
*dst++ = *src++;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -1075,7 +1066,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* allocate memory for the image */
try { pnginfo.image.reset(new std::uint8_t [pnginfo.height * (rowbytes + 1)]); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
/* copy in the pixels, specifying a nullptr filter */
for (y = 0; y < pnginfo.height; y++)
@@ -1088,7 +1079,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* 16bpp palettized format */
if (bitmap.format() == BITMAP_FORMAT_IND16)
{
- auto *src16 = reinterpret_cast<uint16_t *>(bitmap.raw_pixptr(y));
+ uint16_t const *src16 = reinterpret_cast<uint16_t const *>(bitmap.raw_pixptr(y));
for (x = 0; x < pnginfo.width; x++)
{
rgb_t color = palette[*src16++];
@@ -1101,7 +1092,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* 32-bit RGB direct */
else if (bitmap.format() == BITMAP_FORMAT_RGB32)
{
- auto *src32 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y));
+ uint32_t const *src32 = reinterpret_cast<uint32_t const *>(bitmap.raw_pixptr(y));
for (x = 0; x < pnginfo.width; x++)
{
rgb_t raw = *src32++;
@@ -1114,7 +1105,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* 32-bit ARGB direct */
else if (bitmap.format() == BITMAP_FORMAT_ARGB32)
{
- auto *src32 = reinterpret_cast<uint32_t *>(bitmap.raw_pixptr(y));
+ uint32_t const *src32 = reinterpret_cast<uint32_t const *>(bitmap.raw_pixptr(y));
for (x = 0; x < pnginfo.width; x++)
{
rgb_t raw = *src32++;
@@ -1127,10 +1118,10 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
/* unsupported format */
else
- return PNGERR_UNSUPPORTED_FORMAT;
+ return png_error::UNSUPPORTED_FORMAT;
}
- return PNGERR_NONE;
+ return png_error::NONE;
}
@@ -1139,7 +1130,7 @@ static png_error convert_bitmap_to_image_rgb(png_info &pnginfo, const bitmap_t &
chunks to the given file
-------------------------------------------------*/
-static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+static png_error write_png_stream(core_file &fp, png_info &pnginfo, const bitmap_t &bitmap, int palette_length, const rgb_t *palette)
{
uint8_t tempbuff[16];
png_error error;
@@ -1149,7 +1140,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
error = convert_bitmap_to_image_palette(pnginfo, bitmap, palette_length, palette);
else
error = convert_bitmap_to_image_rgb(pnginfo, bitmap, palette_length, palette);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
// if we wanted to get clever and do filtering, we would do it here
@@ -1163,18 +1154,18 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
put_8bit(tempbuff + 11, pnginfo.filter_method);
put_8bit(tempbuff + 12, pnginfo.interlace_method);
error = write_chunk(fp, tempbuff, PNG_CN_IHDR, 13);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
// write the PLTE chunk
if (pnginfo.num_palette > 0)
error = write_chunk(fp, pnginfo.palette.get(), PNG_CN_PLTE, pnginfo.num_palette * 3);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
- // write a single IDAT chunk */
+ // write a single IDAT chunk
error = write_deflated_chunk(fp, pnginfo.image.get(), PNG_CN_IDAT, pnginfo.height * (compute_rowbytes(pnginfo) + 1));
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
// write TEXT chunks
@@ -1182,7 +1173,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
for (png_info::png_text const &text : pnginfo.textlist)
{
try { textbuf.resize(text.first.length() + 1 + text.second.length()); }
- catch (std::bad_alloc const &) { return PNGERR_OUT_OF_MEMORY; }
+ catch (std::bad_alloc const &) { return png_error::OUT_OF_MEMORY; }
std::uint8_t *dst(&textbuf[0]);
// convert keyword to ISO-8859-1
@@ -1213,7 +1204,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
}
error = write_chunk(fp, &textbuf[0], PNG_CN_tEXt, dst - &textbuf[0]);
- if (error != PNGERR_NONE)
+ if (error != png_error::NONE)
return error;
}
@@ -1222,7 +1213,7 @@ static png_error write_png_stream(util::core_file &fp, png_info &pnginfo, const
}
-png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
+png_error png_write_bitmap(core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
{
// use a dummy pnginfo if none passed to us
png_info pnginfo;
@@ -1231,7 +1222,7 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
// write the PNG signature
if (fp.write(PNG_SIGNATURE, sizeof(PNG_SIGNATURE)) != sizeof(PNG_SIGNATURE))
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
/* write the rest of the PNG data */
return write_png_stream(fp, *info, bitmap, palette_length, palette);
@@ -1246,7 +1237,7 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
********************************************************************************/
/**
- * @fn png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate)
+ * @fn png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate)
*
* @brief Mng capture start.
*
@@ -1257,12 +1248,12 @@ png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &
* @return A png_error.
*/
-png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate)
+png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate)
{
uint8_t mhdr[28];
if (fp.write(MNG_Signature, 8) != 8)
- return PNGERR_FILE_ERROR;
+ return png_error::FILE_ERROR;
memset(mhdr, 0, 28);
put_32bit(mhdr + 0, bitmap.width());
@@ -1273,7 +1264,7 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate
}
/**
- * @fn png_error mng_capture_frame(util::core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
+ * @fn png_error mng_capture_frame(core_file &fp, png_info *info, bitmap_t &bitmap, int palette_length, const rgb_t *palette)
*
* @brief Mng capture frame.
*
@@ -1286,13 +1277,13 @@ png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate
* @return A png_error.
*/
-png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
+png_error mng_capture_frame(core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette)
{
return write_png_stream(fp, info, bitmap, palette_length, palette);
}
/**
- * @fn png_error mng_capture_stop(util::core_file &fp)
+ * @fn png_error mng_capture_stop(core_file &fp)
*
* @brief Mng capture stop.
*
@@ -1301,7 +1292,9 @@ png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const
* @return A png_error.
*/
-png_error mng_capture_stop(util::core_file &fp)
+png_error mng_capture_stop(core_file &fp)
{
return write_chunk(fp, nullptr, MNG_CN_MEND, 0);
}
+
+} // namespace util
diff --git a/src/lib/util/png.h b/src/lib/util/png.h
index 5f852fd8c16..784c92646e6 100644
--- a/src/lib/util/png.h
+++ b/src/lib/util/png.h
@@ -17,31 +17,33 @@
#include "corefile.h"
#include "osdcore.h"
+#include <cstdint>
#include <list>
#include <memory>
#include <string>
#include <utility>
+namespace util {
/***************************************************************************
CONSTANTS
***************************************************************************/
/* Error types */
-enum png_error
+enum class png_error
{
- PNGERR_NONE,
- PNGERR_OUT_OF_MEMORY,
- PNGERR_UNKNOWN_FILTER,
- PNGERR_FILE_ERROR,
- PNGERR_BAD_SIGNATURE,
- PNGERR_DECOMPRESS_ERROR,
- PNGERR_FILE_TRUNCATED,
- PNGERR_FILE_CORRUPT,
- PNGERR_UNKNOWN_CHUNK,
- PNGERR_COMPRESS_ERROR,
- PNGERR_UNSUPPORTED_FORMAT
+ NONE,
+ OUT_OF_MEMORY,
+ UNKNOWN_FILTER,
+ FILE_ERROR,
+ BAD_SIGNATURE,
+ DECOMPRESS_ERROR,
+ FILE_TRUNCATED,
+ FILE_CORRUPT,
+ UNKNOWN_CHUNK,
+ COMPRESS_ERROR,
+ UNSUPPORTED_FORMAT
};
@@ -57,7 +59,7 @@ public:
~png_info() { free_data(); }
- png_error read_file(util::core_file &fp);
+ png_error read_file(core_file &fp);
png_error copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha);
png_error expand_buffer_8bit();
@@ -66,7 +68,7 @@ public:
void free_data();
void reset() { free_data(); operator=(png_info()); }
- static png_error verify_header(util::core_file &fp);
+ static png_error verify_header(core_file &fp);
std::unique_ptr<std::uint8_t []> image;
std::uint32_t width, height;
@@ -99,12 +101,14 @@ private:
FUNCTION PROTOTYPES
***************************************************************************/
-png_error png_read_bitmap(util::core_file &fp, bitmap_argb32 &bitmap);
+png_error png_read_bitmap(core_file &fp, bitmap_argb32 &bitmap);
-png_error png_write_bitmap(util::core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
+png_error png_write_bitmap(core_file &fp, png_info *info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
-png_error mng_capture_start(util::core_file &fp, bitmap_t &bitmap, unsigned rate);
-png_error mng_capture_frame(util::core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
-png_error mng_capture_stop(util::core_file &fp);
+png_error mng_capture_start(core_file &fp, bitmap_t &bitmap, unsigned rate);
+png_error mng_capture_frame(core_file &fp, png_info &info, bitmap_t const &bitmap, int palette_length, const rgb_t *palette);
+png_error mng_capture_stop(core_file &fp);
+
+} // namespace util
#endif // MAME_LIB_UTIL_PNG_H
diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp
index a61c20d2e3c..8ee3c33fe26 100644
--- a/src/lib/util/xmlfile.cpp
+++ b/src/lib/util/xmlfile.cpp
@@ -31,7 +31,6 @@ namespace {
***************************************************************************/
constexpr unsigned TEMP_BUFFER_SIZE(4096U);
-std::locale const f_portable_locale("C");
/***************************************************************************
@@ -629,7 +628,7 @@ long long data_node::get_attribute_int(const char *attribute, long long defvalue
return defvalue;
std::istringstream stream;
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
long long result;
if (string[0] == '$')
{
@@ -694,7 +693,7 @@ float data_node::get_attribute_float(const char *attribute, float defvalue) cons
return defvalue;
std::istringstream stream(string);
- stream.imbue(f_portable_locale);
+ stream.imbue(std::locale::classic());
float result;
return (stream >> result) ? result : defvalue;
}
@@ -732,7 +731,7 @@ void data_node::set_attribute(const char *name, const char *value)
void data_node::set_attribute_int(const char *name, long long value)
{
- set_attribute(name, string_format(f_portable_locale, "%d", value).c_str());
+ set_attribute(name, string_format(std::locale::classic(), "%d", value).c_str());
}
@@ -743,7 +742,7 @@ void data_node::set_attribute_int(const char *name, long long value)
void data_node::set_attribute_float(const char *name, float value)
{
- set_attribute(name, string_format(f_portable_locale, "%f", value).c_str());
+ set_attribute(name, string_format(std::locale::classic(), "%f", value).c_str());
}
diff --git a/src/mame/arcade.flt b/src/mame/arcade.flt
index a8440e9cd36..a1bed00117f 100644
--- a/src/mame/arcade.flt
+++ b/src/mame/arcade.flt
@@ -258,6 +258,7 @@ cops.cpp
copsnrob.cpp
corona.cpp
cosmic.cpp
+cowtipping.cpp
cps1.cpp
cps1bl_5205.cpp
cps1bl_pic.cpp
diff --git a/src/mame/audio/arcadia.cpp b/src/mame/audio/arcadia.cpp
index 19adb9fac4e..46c7c9ee64f 100644
--- a/src/mame/audio/arcadia.cpp
+++ b/src/mame/audio/arcadia.cpp
@@ -59,7 +59,7 @@ arcadia_sound_device::arcadia_sound_device(const machine_config &mconfig, const
//-------------------------------------------------
void arcadia_sound_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 1, UVI_PAL*OSAMP);
+ m_channel = stream_alloc(0, 1, UVI_PAL*OSAMP);
m_lfsr = LFSR_INIT;
m_tval = 1;
logerror("arcadia_sound start\n");
@@ -76,18 +76,18 @@ void arcadia_sound_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void arcadia_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void arcadia_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
- for (i = 0; i < samples; i++, buffer++)
+ for (i = 0; i < buffer.samples(); i++)
{
- *buffer = 0;
+ s32 result = 0;
//if minimal pitch ?
if (m_reg[1]){
@@ -97,17 +97,17 @@ void arcadia_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
//tone only
case 1:
- *buffer = m_volume * m_tval;
+ result = m_volume * m_tval;
break;
//noise only
case 2:
- *buffer = m_volume * m_nval;
+ result = m_volume * m_nval;
break;
//tone AND noise (bitwise and)
case 3:
- *buffer = m_volume * (m_tval & m_nval);
+ result = m_volume * (m_tval & m_nval);
break;
}
@@ -132,6 +132,7 @@ void arcadia_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
m_pos = 0;
}
}
+ buffer.put_int(i, result, 32768);
}
}
diff --git a/src/mame/audio/arcadia.h b/src/mame/audio/arcadia.h
index de67b71705d..6eb25f9e970 100644
--- a/src/mame/audio/arcadia.h
+++ b/src/mame/audio/arcadia.h
@@ -21,7 +21,7 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
sound_stream *m_channel;
uint8_t m_reg[3];
diff --git a/src/mame/audio/channelf.cpp b/src/mame/audio/channelf.cpp
index 5003f28ae3a..ec4971d35df 100644
--- a/src/mame/audio/channelf.cpp
+++ b/src/mame/audio/channelf.cpp
@@ -30,7 +30,7 @@ void channelf_sound_device::device_start()
{
int rate;
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
rate = machine().sample_rate();
/*
@@ -67,19 +67,18 @@ void channelf_sound_device::device_start()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void channelf_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void channelf_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
uint32_t mask = 0, target = 0;
- stream_sample_t *buffer = outputs[0];
- stream_sample_t *sample = buffer;
+ auto &buffer = outputs[0];
switch( m_sound_mode )
{
case 0: /* sound off */
- memset(buffer,0,sizeof(*buffer)*samples);
+ buffer.fill(0);
return;
case 1: /* high tone (2V) - 1000Hz */
@@ -96,12 +95,12 @@ void channelf_sound_device::sound_stream_update_legacy(sound_stream &stream, str
break;
}
- while (samples-- > 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
if ((m_forced_ontime > 0) || ((m_sample_counter & mask) == target)) // change made for improved sound
- *sample++ = m_envelope;
+ buffer.put_int(sampindex, m_envelope, 32768);
else
- *sample++ = 0;
+ buffer.put(sampindex, 0);
m_sample_counter += m_incr;
m_envelope *= m_decay_mult;
if (m_forced_ontime > 0) // added for improved sound
diff --git a/src/mame/audio/channelf.h b/src/mame/audio/channelf.h
index 36c98aa47ed..ce1231c3951 100644
--- a/src/mame/audio/channelf.h
+++ b/src/mame/audio/channelf.h
@@ -20,7 +20,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// internal state
sound_stream *m_channel;
diff --git a/src/mame/audio/cinemat.cpp b/src/mame/audio/cinemat.cpp
index 4b9168aa949..3d9cb981888 100644
--- a/src/mame/audio/cinemat.cpp
+++ b/src/mame/audio/cinemat.cpp
@@ -45,16 +45,17 @@
*
*************************************/
-cinemat_audio_device_base::cinemat_audio_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 inputs_mask, void (*netlist)(netlist::nlparse_t &), double output_scale)
- : device_t(mconfig, type, tag, owner, clock)
- , m_out_input(*this, "sound_nl:out_%u", 0)
- , m_inputs_mask(inputs_mask)
- , m_netlist(netlist)
- , m_output_scale(output_scale)
+cinemat_audio_device_base::cinemat_audio_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 inputs_mask, void (*netlist)(netlist::nlparse_t &), double output_scale) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_mixer_interface(mconfig, *this),
+ m_out_input(*this, "sound_nl:out_%u", 0),
+ m_inputs_mask(inputs_mask),
+ m_netlist(netlist),
+ m_output_scale(output_scale)
{
}
-void cinemat_audio_device_base::configure_latch_inputs(ls259_device &latch, u8 mask)
+cinemat_audio_device_base &cinemat_audio_device_base::configure_latch_inputs(ls259_device &latch, u8 mask)
{
if (mask == 0)
mask = m_inputs_mask;
@@ -70,48 +71,34 @@ void cinemat_audio_device_base::configure_latch_inputs(ls259_device &latch, u8 m
latch.q_out_cb<4>().set(write_line_delegate(*this, FUNC(cinemat_audio_device_base::sound_w<4>)));
if (BIT(mask, 7))
latch.q_out_cb<7>().set(write_line_delegate(*this, FUNC(cinemat_audio_device_base::sound_w<7>)));
+ return *this;
}
void cinemat_audio_device_base::device_add_mconfig(machine_config &config)
{
- SPEAKER(config, "mono").front_center();
+ NETLIST_SOUND(config, "sound_nl", 48000)
+ .set_source(m_netlist)
+ .add_route(ALL_OUTPUTS, *this, 1.0);
- if (m_netlist != nullptr)
- {
- NETLIST_SOUND(config, "sound_nl", 48000)
- .set_source(m_netlist)
- .add_route(ALL_OUTPUTS, "mono", 1.0);
-
- if ((m_inputs_mask & 0x01) != 0)
- NETLIST_LOGIC_INPUT(config, m_out_input[0], "I_OUT_0.IN", 0);
- if ((m_inputs_mask & 0x02) != 0)
- NETLIST_LOGIC_INPUT(config, m_out_input[1], "I_OUT_1.IN", 0);
- if ((m_inputs_mask & 0x04) != 0)
- NETLIST_LOGIC_INPUT(config, m_out_input[2], "I_OUT_2.IN", 0);
- if ((m_inputs_mask & 0x08) != 0)
- NETLIST_LOGIC_INPUT(config, m_out_input[3], "I_OUT_3.IN", 0);
- if ((m_inputs_mask & 0x10) != 0)
- NETLIST_LOGIC_INPUT(config, m_out_input[4], "I_OUT_4.IN", 0);
- if ((m_inputs_mask & 0x80) != 0)
- NETLIST_LOGIC_INPUT(config, m_out_input[7], "I_OUT_7.IN", 0);
-
- NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(m_output_scale, 0.0);
- }
-}
+ if ((m_inputs_mask & 0x01) != 0)
+ NETLIST_LOGIC_INPUT(config, m_out_input[0], "I_OUT_0.IN", 0);
+ if ((m_inputs_mask & 0x02) != 0)
+ NETLIST_LOGIC_INPUT(config, m_out_input[1], "I_OUT_1.IN", 0);
+ if ((m_inputs_mask & 0x04) != 0)
+ NETLIST_LOGIC_INPUT(config, m_out_input[2], "I_OUT_2.IN", 0);
+ if ((m_inputs_mask & 0x08) != 0)
+ NETLIST_LOGIC_INPUT(config, m_out_input[3], "I_OUT_3.IN", 0);
+ if ((m_inputs_mask & 0x10) != 0)
+ NETLIST_LOGIC_INPUT(config, m_out_input[4], "I_OUT_4.IN", 0);
+ if ((m_inputs_mask & 0x80) != 0)
+ NETLIST_LOGIC_INPUT(config, m_out_input[7], "I_OUT_7.IN", 0);
-void cinemat_audio_device_base::device_start()
-{
-#if ENABLE_NETLIST_LOGGING
- m_logfile = fopen("cinemat.csv", "w");
-#endif
+ NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(m_output_scale, 0.0);
}
-void cinemat_audio_device_base::device_stop()
+void cinemat_audio_device_base::device_start()
{
-#if ENABLE_NETLIST_LOGGING
- if (m_logfile != nullptr)
- fclose(m_logfile);
-#endif
+ save_item(NAME(m_inputs));
}
void cinemat_audio_device_base::input_set(int bit, int state)
@@ -119,18 +106,9 @@ void cinemat_audio_device_base::input_set(int bit, int state)
u8 oldvals = m_inputs;
m_inputs = (m_inputs & ~(1 << bit)) | ((state & 1) << bit);
if (oldvals != m_inputs)
- {
-#if ENABLE_NETLIST_LOGGING
- attotime time = machine().scheduler().time();
- for (int bit = 0; bit < 8; bit++)
- if (((m_inputs_mask >> bit) & 1) != 0)
- if ((((m_inputs ^ oldvals) >> bit) & 1) != 0)
- fprintf(m_logfile, "%s,I_OUT_%u.IN,%d\n", time.as_string(), bit, (m_inputs >> bit) & 1);
-#endif
for (int index = 0; index < 8; index++)
if (m_out_input[index] != nullptr)
m_out_input[index]->write_line(BIT(m_inputs, index));
- }
}
diff --git a/src/mame/audio/cinemat.h b/src/mame/audio/cinemat.h
index 6859154850d..dd7791668f9 100644
--- a/src/mame/audio/cinemat.h
+++ b/src/mame/audio/cinemat.h
@@ -9,21 +9,17 @@
#include "machine/netlist.h"
#include "netlist/nl_setup.h"
-// log to cinemat.csv for nltool playback/analysis
-#define ENABLE_NETLIST_LOGGING (0)
-
-class cinemat_audio_device_base : public device_t
+class cinemat_audio_device_base : public device_t, public device_mixer_interface
{
public:
- void configure_latch_inputs(ls259_device &latch, u8 mask = 0);
+ cinemat_audio_device_base &configure_latch_inputs(ls259_device &latch, u8 mask = 0);
protected:
cinemat_audio_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 inputs_mask, void (*netlist)(netlist::nlparse_t &), double output_scale);
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
- virtual void device_stop() override;
template<int _Index> DECLARE_WRITE_LINE_MEMBER(sound_w) { input_set(_Index, state); }
void input_set(int bit, int state);
@@ -35,11 +31,6 @@ private:
u8 const m_inputs_mask;
void (*const m_netlist)(netlist::nlparse_t &);
double const m_output_scale;
-
-#if ENABLE_NETLIST_LOGGING
- FILE *m_logfile = nullptr;
-#endif
-
};
diff --git a/src/mame/audio/cmi01a.cpp b/src/mame/audio/cmi01a.cpp
index dbb180c2247..f99eccb71c9 100644
--- a/src/mame/audio/cmi01a.cpp
+++ b/src/mame/audio/cmi01a.cpp
@@ -132,7 +132,7 @@ void cmi01a_device::device_add_mconfig(machine_config &config)
}
-void cmi01a_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void cmi01a_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
if (m_run)
{
@@ -140,23 +140,21 @@ void cmi01a_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
int addr = m_segment_cnt;
uint8_t *wave_ptr = &m_wave_ram[m_segment_cnt & 0x3fff];
- stream_sample_t *buf = outputs[0];
+ auto &buf = outputs[0];
- while (samples--)
+ for (int sampindex = 0; sampindex < buf.samples(); sampindex++)
{
const uint8_t sample8 = wave_ptr[addr++ & 0x3fff];
- int32_t sample = (int32_t)(int8_t)(sample8 ^ 0x80) * m_env * m_vol_latch;
+ s32 sample = (int32_t)(int8_t)(sample8 ^ 0x80) * m_env * m_vol_latch;
if (m_channel == 5) printf("%08x:%02x:%02x:%02x", (uint32_t)sample, sample8, m_env, m_vol_latch);
- *buf++ = (int16_t)(sample >> 8);
+ buf.put_int(sampindex, (int16_t)(sample >> 8), 32768);
}
if (m_channel == 5) printf("\n");
m_segment_cnt = (m_segment_cnt & ~mask) | addr;
}
else
- {
- memset(outputs[0], 0, samples * sizeof(stream_sample_t));
- }
+ outputs[0].fill(0);
}
void cmi01a_device::device_resolve_objects()
@@ -175,7 +173,7 @@ void cmi01a_device::device_start()
m_zx_timer->adjust(attotime::never);
m_eosi_timer->adjust(attotime::never);
- m_stream = stream_alloc_legacy(0, 1, 44100);
+ m_stream = stream_alloc(0, 1, 44100);
m_ptm->set_external_clocks(clock() / 8, clock() / 4, clock() / 4);
diff --git a/src/mame/audio/cmi01a.h b/src/mame/audio/cmi01a.h
index 7e5da0b56a8..743c50e5829 100644
--- a/src/mame/audio/cmi01a.h
+++ b/src/mame/audio/cmi01a.h
@@ -34,7 +34,7 @@ public:
void write(offs_t offset, uint8_t data);
uint8_t read(offs_t offset);
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
protected:
virtual void device_resolve_objects() override;
diff --git a/src/mame/audio/cps3.cpp b/src/mame/audio/cps3.cpp
index aa7eb8340f0..bbefabf4d50 100644
--- a/src/mame/audio/cps3.cpp
+++ b/src/mame/audio/cps3.cpp
@@ -39,7 +39,7 @@ cps3_sound_device::cps3_sound_device(const machine_config &mconfig, const char *
void cps3_sound_device::device_start()
{
/* Allocate the stream */
- m_stream = stream_alloc_legacy(0, 2, clock() / 384);
+ m_stream = stream_alloc(0, 2, clock() / 384);
save_item(NAME(m_key));
for (int i = 0; i < 16; i++)
@@ -52,14 +52,14 @@ void cps3_sound_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void cps3_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void cps3_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
/* Clear the buffers */
- memset(outputs[0], 0, samples*sizeof(*outputs[0]));
- memset(outputs[1], 0, samples*sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
for (int i = 0; i < 16; i ++)
{
@@ -103,7 +103,7 @@ void cps3_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_
loop -= 0x400000;
/* Go through the buffer and add voice contributions */
- for (int j = 0; j < samples; j++)
+ for (int j = 0; j < outputs[0].samples(); j++)
{
int32_t sample;
@@ -127,8 +127,8 @@ void cps3_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_
sample = m_base[BYTE4_XOR_LE(start + pos)];
frac += step;
- outputs[0][j] += ((sample * vol_l) >> 8);
- outputs[1][j] += ((sample * vol_r) >> 8);
+ outputs[0].add_int(j, sample * vol_l, 32768 << 8);
+ outputs[1].add_int(j, sample * vol_r, 32768 << 8);
}
vptr->pos = pos;
diff --git a/src/mame/audio/cps3.h b/src/mame/audio/cps3.h
index 4e3fe471c8d..101fa8903ce 100644
--- a/src/mame/audio/cps3.h
+++ b/src/mame/audio/cps3.h
@@ -46,7 +46,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_stream;
diff --git a/src/mame/audio/dai_snd.cpp b/src/mame/audio/dai_snd.cpp
index 37004da5644..52334c699f8 100644
--- a/src/mame/audio/dai_snd.cpp
+++ b/src/mame/audio/dai_snd.cpp
@@ -33,7 +33,7 @@ dai_sound_device::dai_sound_device(const machine_config &mconfig, const char *ta
void dai_sound_device::device_start()
{
- m_mixer_channel = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_mixer_channel = stream_alloc(0, 2, machine().sample_rate());
}
//-------------------------------------------------
@@ -115,27 +115,27 @@ WRITE_LINE_MEMBER(dai_sound_device::set_input_ch2)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void dai_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void dai_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *sample_left = outputs[0];
- stream_sample_t *sample_right = outputs[1];
+ auto &sample_left = outputs[0];
+ auto &sample_right = outputs[1];
int16_t channel_0_signal = m_dai_input[0] ? s_osc_volume_table[m_osc_volume[0]] : -s_osc_volume_table[m_osc_volume[0]];
int16_t channel_1_signal = m_dai_input[1] ? s_osc_volume_table[m_osc_volume[1]] : -s_osc_volume_table[m_osc_volume[1]];
int16_t channel_2_signal = m_dai_input[2] ? s_osc_volume_table[m_osc_volume[2]] : -s_osc_volume_table[m_osc_volume[2]];
- while (samples--)
+ for (int sampindex = 0; sampindex < sample_left.samples(); sampindex++)
{
int16_t noise = machine().rand()&0x01 ? s_noise_volume_table[m_noise_volume] : -s_noise_volume_table[m_noise_volume];
/* channel 0 + channel 1 + noise */
- *sample_left++ = channel_0_signal + channel_1_signal + noise;
+ sample_left.put_int(sampindex, channel_0_signal + channel_1_signal + noise, 32768);
/* channel 1 + channel 2 + noise */
- *sample_right++ = channel_1_signal + channel_2_signal + noise;
+ sample_right.put_int(sampindex, channel_1_signal + channel_2_signal + noise, 32768);
}
}
diff --git a/src/mame/audio/dai_snd.h b/src/mame/audio/dai_snd.h
index cea0e1c6c71..f34bed0199d 100644
--- a/src/mame/audio/dai_snd.h
+++ b/src/mame/audio/dai_snd.h
@@ -27,7 +27,7 @@ protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream * m_mixer_channel;
diff --git a/src/mame/audio/dsbz80.cpp b/src/mame/audio/dsbz80.cpp
index 7643face54b..ad7f25bbfcd 100644
--- a/src/mame/audio/dsbz80.cpp
+++ b/src/mame/audio/dsbz80.cpp
@@ -85,7 +85,7 @@ void dsbz80_device::device_start()
m_rxd_handler.resolve_safe();
uint8_t *rom_base = machine().root_device().memregion("mpeg")->base();
decoder = new mpeg_audio(rom_base, mpeg_audio::L2, false, 0);
- stream_alloc_legacy(0, 2, 32000);
+ stream_alloc(0, 2, 32000);
}
//-------------------------------------------------
@@ -232,11 +232,13 @@ void dsbz80_device::mpeg_stereo_w(uint8_t data)
mp_pan = data & 3; // 0 = stereo, 1 = left on both channels, 2 = right on both channels
}
-void dsbz80_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void dsbz80_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *out_l = outputs[0];
- stream_sample_t *out_r = outputs[1];
+ auto &out_l = outputs[0];
+ auto &out_r = outputs[1];
+ int samples = out_l.samples();
+ int sampindex = 0;
for(;;)
{
while(samples && audio_pos < audio_avail)
@@ -244,18 +246,21 @@ void dsbz80_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
switch (mp_pan)
{
case 0: // stereo
- *out_l++ = audio_buf[audio_pos*2];
- *out_r++ = audio_buf[audio_pos*2+1];
+ out_l.put_int(sampindex, audio_buf[audio_pos*2], 32768);
+ out_r.put_int(sampindex, audio_buf[audio_pos*2+1], 32768);
+ sampindex++;
break;
case 1: // left only
- *out_l++ = audio_buf[audio_pos*2];
- *out_r++ = audio_buf[audio_pos*2];
+ out_l.put_int(sampindex, audio_buf[audio_pos*2], 32768);
+ out_r.put_int(sampindex, audio_buf[audio_pos*2], 32768);
+ sampindex++;
break;
case 2: // right only
- *out_l++ = audio_buf[audio_pos*2+1];
- *out_r++ = audio_buf[audio_pos*2+1];
+ out_l.put_int(sampindex, audio_buf[audio_pos*2+1], 32768);
+ out_r.put_int(sampindex, audio_buf[audio_pos*2+1], 32768);
+ sampindex++;
break;
}
audio_pos++;
@@ -269,11 +274,8 @@ void dsbz80_device::sound_stream_update_legacy(sound_stream &stream, stream_samp
if(mp_state == 0)
{
- for(int i=0; i != samples; i++)
- {
- *out_l++ = 0;
- *out_r++ = 0;
- }
+ out_l.fill(0, sampindex);
+ out_r.fill(0, sampindex);
break;
}
diff --git a/src/mame/audio/dsbz80.h b/src/mame/audio/dsbz80.h
index 92e0c4f3f2f..6f135454524 100644
--- a/src/mame/audio/dsbz80.h
+++ b/src/mame/audio/dsbz80.h
@@ -37,7 +37,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
mpeg_audio *decoder;
diff --git a/src/mame/audio/elan_eu3a05.cpp b/src/mame/audio/elan_eu3a05.cpp
index 39ab90a08fb..1922ee3b1da 100644
--- a/src/mame/audio/elan_eu3a05.cpp
+++ b/src/mame/audio/elan_eu3a05.cpp
@@ -54,7 +54,7 @@ void elan_eu3a05_sound_device::map(address_map &map)
void elan_eu3a05_sound_device::device_start()
{
m_space_read_cb.resolve_safe(0);
- m_stream = stream_alloc_legacy(0, 1, 8000);
+ m_stream = stream_alloc(0, 1, 8000);
m_sound_end_cb.resolve_all_safe();
@@ -92,18 +92,19 @@ void elan_eu3a05_sound_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void elan_eu3a05_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void elan_eu3a05_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// reset the output stream
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+ outputs[0].fill(0);
int volume = m_volumes[0] | (m_volumes[1] << 8);
int outpos = 0;
// loop while we still have samples to generate
+ int samples = outputs[0].samples();
while (samples-- != 0)
{
int total = 0;
@@ -142,7 +143,7 @@ void elan_eu3a05_sound_device::sound_stream_update_legacy(sound_stream &stream,
//LOGMASKED( LOG_AUDIO, "m_isstopped %02x channel %d is NOT active %08x %06x\n", m_isstopped, channel, m_sound_byte_address[channel], m_sound_current_nib_pos[channel]);
}
}
- outputs[0][outpos] = total / 6;
+ outputs[0].put_int(outpos, total, 32768 * 6);
outpos++;
}
}
diff --git a/src/mame/audio/elan_eu3a05.h b/src/mame/audio/elan_eu3a05.h
index c9ef2e83ab3..692d685cf64 100644
--- a/src/mame/audio/elan_eu3a05.h
+++ b/src/mame/audio/elan_eu3a05.h
@@ -30,7 +30,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual space_config_vector memory_space_config() const override;
const address_space_config m_space_config;
diff --git a/src/mame/audio/exidy.cpp b/src/mame/audio/exidy.cpp
index 8220c3e1af7..6c107bf15fe 100644
--- a/src/mame/audio/exidy.cpp
+++ b/src/mame/audio/exidy.cpp
@@ -180,7 +180,7 @@ void exidy_sound_device::common_sh_start()
m_sh6840_clocks_per_sample = (int)(SH6840_CLOCK.dvalue() / (double)sample_rate * (double)(1 << 24));
/* allocate the stream */
- m_stream = stream_alloc_legacy(0, 1, sample_rate);
+ m_stream = stream_alloc(0, 1, sample_rate);
sh6840_register_state_globals();
}
@@ -196,6 +196,8 @@ exidy_sh8253_sound_device::exidy_sh8253_sound_device(const machine_config &mconf
: exidy_sound_device(mconfig, type, tag, owner, clock),
m_riot(*this, "riot"),
m_cvsd(*this, "cvsd"),
+ m_cvsd_filter(*this, "cvsd_filter"),
+ m_cvsd_filter2(*this, "cvsd_filter2"),
m_cvsdcpu(*this, "cvsdcpu"),
m_tms(*this, "tms"),
m_pia(*this, "pia")
@@ -239,23 +241,23 @@ void exidy_sound_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void exidy_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void exidy_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
sh6840_timer_channel *sh6840_timer = m_sh6840_timer;
/* hack to skip the expensive lfsr noise generation unless at least one of the 3 channels actually depends on it being generated */
int noisy = ((sh6840_timer[0].cr & sh6840_timer[1].cr & sh6840_timer[2].cr & 0x02) == 0);
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
/* loop over samples */
- while (samples--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
sh6840_timer_channel *t;
int clocks;
- stream_sample_t sample = 0;
+ s32 sample = 0;
/* determine how many 6840 clocks this sample */
m_sh6840_clock_count += m_sh6840_clocks_per_sample;
@@ -310,19 +312,19 @@ void exidy_sound_device::sound_stream_update_legacy(sound_stream &stream, stream
sample += generate_music_sample();
/* stash */
- *buffer++ = sample;
+ buffer.put_int(sampindex, sample, 32768);
}
}
-stream_sample_t exidy_sound_device::generate_music_sample()
+s32 exidy_sound_device::generate_music_sample()
{
return 0;
}
-stream_sample_t exidy_sh8253_sound_device::generate_music_sample()
+s32 exidy_sh8253_sound_device::generate_music_sample()
{
sh8253_timer_channel *c;
- stream_sample_t sample = 0;
+ s32 sample = 0;
/* music channel 0 */
c = &m_sh8253_timer[0];
@@ -788,9 +790,33 @@ DEFINE_DEVICE_TYPE(EXIDY_MTRAP, mtrap_sound_device, "mtrap_sound", "Exidy SFX+PS
mtrap_sound_device::mtrap_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: venture_sound_device(mconfig, EXIDY_MTRAP, tag, owner, clock)
+ , m_cvsd_timer(*this,"cvsd_timer")
+ , m_cvsd_clk(false)
{
}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mtrap_sound_device::device_start()
+{
+ common_sh_start();
+
+ /* 8253 */
+ m_freq_to_step = (1 << 24) / SH8253_CLOCK;
+
+ sh8253_register_state_globals();
+
+ save_item(NAME(m_cvsd_clk));
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER(mtrap_sound_device::cvsd_timer)
+{
+ m_cvsd_clk = !m_cvsd_clk;
+ m_cvsd->clock_w(m_cvsd_clk);
+}
+
void mtrap_sound_device::voiceio_w(offs_t offset, uint8_t data)
{
if (!(offset & 0x10))
@@ -803,19 +829,24 @@ void mtrap_sound_device::voiceio_w(offs_t offset, uint8_t data)
uint8_t mtrap_sound_device::voiceio_r(offs_t offset)
{
+ uint8_t retval = 0xff; // this should probably be open bus
if (!(offset & 0x80))
{
+ retval &= 0xf0;
uint8_t porta = m_riot->porta_out_get();
uint8_t data = (porta & 0x06) >> 1;
data |= (porta & 0x01) << 2;
data |= (porta & 0x08);
- return data;
+ retval |= data;
}
if (!(offset & 0x40))
- return m_cvsd->clock_state_r() << 7;
+ {
+ retval &= 0x7f;
+ retval |= (m_cvsd_clk << 7);
+ }
- return 0;
+ return retval;
}
@@ -841,8 +872,15 @@ void mtrap_sound_device::device_add_mconfig(machine_config &config)
m_cvsdcpu->set_addrmap(AS_PROGRAM, &mtrap_sound_device::cvsd_map);
m_cvsdcpu->set_addrmap(AS_IO, &mtrap_sound_device::cvsd_iomap);
+ TIMER(config, m_cvsd_timer).configure_periodic(FUNC(mtrap_sound_device::cvsd_timer), attotime::from_hz(CVSD_CLOCK*2.0)); // this is a 555 timer with 53% duty cycle, within margin of error of 50% duty cycle; the handler clocks on both clock edges, hence * 2.0
+
/* audio hardware */
- MC3417(config, m_cvsd, CVSD_CLOCK).add_route(ALL_OUTPUTS, "mono", 0.80);
+ FILTER_BIQUAD(config, m_cvsd_filter2).opamp_mfb_lowpass_setup(RES_K(10), RES_K(3.9), RES_K(18), CAP_N(20), CAP_N(2.2));
+ m_cvsd_filter2->add_route(ALL_OUTPUTS, "mono", 1.0);
+ FILTER_BIQUAD(config, m_cvsd_filter).opamp_mfb_lowpass_setup(RES_K(10), RES_K(3.9), RES_K(18), CAP_N(20), CAP_N(2.2));
+ m_cvsd_filter->add_route(ALL_OUTPUTS, m_cvsd_filter2, 1.0);
+ MC3417(config, m_cvsd, 0).add_route(ALL_OUTPUTS, m_cvsd_filter, 0.3086); // each filter has gain of 1.8 for total gain of 3.24, 0.3086 cancels this out. was 0.8
+
}
diff --git a/src/mame/audio/exidy.h b/src/mame/audio/exidy.h
index 86ed7b145cd..8e3ee42916a 100644
--- a/src/mame/audio/exidy.h
+++ b/src/mame/audio/exidy.h
@@ -7,6 +7,8 @@
#include "machine/6532riot.h"
#include "machine/6821pia.h"
+#include "machine/timer.h"
+#include "sound/flt_biquad.h"
#include "sound/hc55516.h"
#include "sound/tms5220.h"
@@ -54,8 +56,8 @@ protected:
void sh6840_register_state_globals();
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
- virtual stream_sample_t generate_music_sample();
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+ virtual s32 generate_music_sample();
static inline void sh6840_apply_clock(sh6840_timer_channel *t, int clocks);
@@ -102,7 +104,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- virtual stream_sample_t generate_music_sample() override;
+ virtual s32 generate_music_sample() override;
void r6532_porta_w(uint8_t data);
uint8_t r6532_porta_r();
@@ -120,7 +122,9 @@ protected:
required_device<riot6532_device> m_riot;
/* 5220/CVSD variables */
- optional_device<hc55516_device> m_cvsd;
+ optional_device<mc3417_device> m_cvsd;
+ optional_device<filter_biquad_device> m_cvsd_filter;
+ optional_device<filter_biquad_device> m_cvsd_filter2;
optional_device<cpu_device> m_cvsdcpu;
optional_device<tms5220_device> m_tms;
required_device<pia6821_device> m_pia;
@@ -177,11 +181,15 @@ public:
protected:
// device-level overrides
+ virtual void device_start() override;
virtual void device_add_mconfig(machine_config &config) override;
private:
+ required_device<timer_device> m_cvsd_timer;
+ TIMER_DEVICE_CALLBACK_MEMBER(cvsd_timer);
void voiceio_w(offs_t offset, uint8_t data);
uint8_t voiceio_r(offs_t offset);
+ bool m_cvsd_clk;
void cvsd_map(address_map &map);
void cvsd_iomap(address_map &map);
diff --git a/src/mame/audio/exidy440.cpp b/src/mame/audio/exidy440.cpp
index a4ca2d10339..a5a40cae628 100644
--- a/src/mame/audio/exidy440.cpp
+++ b/src/mame/audio/exidy440.cpp
@@ -74,8 +74,6 @@ exidy440_sound_device::exidy440_sound_device(const machine_config &mconfig, cons
m_samples(*this, "samples"),
m_sound_command(0),
m_sound_command_ack(0),
- m_mixer_buffer_left(nullptr),
- m_mixer_buffer_right(nullptr),
m_sound_cache(nullptr),
m_sound_cache_end(nullptr),
m_sound_cache_max(nullptr),
@@ -146,7 +144,7 @@ void exidy440_sound_device::device_start()
m_channel_frequency[3] = clock()/2;
/* get stream channels */
- m_stream = stream_alloc_legacy(0, 2, clock());
+ m_stream = stream_alloc(0, 2, clock());
/* allocate the sample cache */
length = m_samples.bytes() * 16 + MAX_CACHE_ENTRIES * sizeof(sound_cache_entry);
@@ -157,8 +155,8 @@ void exidy440_sound_device::device_start()
reset_sound_cache();
/* allocate the mixer buffer */
- m_mixer_buffer_left = make_unique_clear<int32_t[]>(clock());
- m_mixer_buffer_right = make_unique_clear<int32_t[]>(clock());
+ m_mixer_buffer_left.resize(clock()/50);
+ m_mixer_buffer_right.resize(clock()/50);
if (SOUND_LOG)
m_debuglog = fopen("sound.log", "w");
@@ -224,24 +222,15 @@ void exidy440_sound_device::add_and_scale_samples(int ch, int32_t *dest, int sam
*
*************************************/
-void exidy440_sound_device::mix_to_16(int length, stream_sample_t *dest_left, stream_sample_t *dest_right)
+void exidy440_sound_device::mix_to_16(write_stream_view &dest_left, write_stream_view &dest_right)
{
- int32_t *mixer_left = m_mixer_buffer_left.get();
- int32_t *mixer_right = m_mixer_buffer_right.get();
- int i, clippers = 0;
+ int32_t *mixer_left = &m_mixer_buffer_left[0];
+ int32_t *mixer_right = &m_mixer_buffer_right[0];
- for (i = 0; i < length; i++)
+ for (int i = 0; i < dest_left.samples(); i++)
{
- int32_t sample_left = *mixer_left++;
- int32_t sample_right = *mixer_right++;
-
- if (sample_left < -32768) { sample_left = -32768; clippers++; }
- else if (sample_left > 32767) { sample_left = 32767; clippers++; }
- if (sample_right < -32768) { sample_right = -32768; clippers++; }
- else if (sample_right > 32767) { sample_right = 32767; clippers++; }
-
- *dest_left++ = sample_left;
- *dest_right++ = sample_right;
+ dest_left.put_int_clamp(i, *mixer_left++, 32768);
+ dest_right.put_int_clamp(i, *mixer_right++, 32768);
}
}
@@ -836,22 +825,22 @@ void exidy440_sound_device::sound_banks_w(offs_t offset, uint8_t data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void exidy440_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void exidy440_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int ch;
/* reset the mixer buffers */
- memset(m_mixer_buffer_left.get(), 0, samples * sizeof(int32_t));
- memset(m_mixer_buffer_right.get(), 0, samples * sizeof(int32_t));
+ std::fill_n(&m_mixer_buffer_left[0], outputs[0].samples(), 0);
+ std::fill_n(&m_mixer_buffer_right[0], outputs[0].samples(), 0);
/* loop over channels */
for (ch = 0; ch < 4; ch++)
{
sound_channel_data *channel = &m_sound_channel[ch];
- int length, volume, left = samples;
+ int length, volume, left = outputs[0].samples();
int effective_offset;
/* if we're not active, bail */
@@ -864,12 +853,12 @@ void exidy440_sound_device::sound_stream_update_legacy(sound_stream &stream, str
/* get a pointer to the sample data and copy to the left */
volume = m_sound_volume[2 * ch + 0];
if (volume)
- add_and_scale_samples(ch, m_mixer_buffer_left.get(), length, volume);
+ add_and_scale_samples(ch, &m_mixer_buffer_left[0], length, volume);
/* get a pointer to the sample data and copy to the left */
volume = m_sound_volume[2 * ch + 1];
if (volume)
- add_and_scale_samples(ch, m_mixer_buffer_right.get(), length, volume);
+ add_and_scale_samples(ch, &m_mixer_buffer_right[0], length, volume);
/* update our counters */
channel->offset += length;
@@ -889,5 +878,5 @@ void exidy440_sound_device::sound_stream_update_legacy(sound_stream &stream, str
}
/* all done, time to mix it */
- mix_to_16(samples, outputs[0], outputs[1]);
+ mix_to_16(outputs[0], outputs[1]);
}
diff --git a/src/mame/audio/exidy440.h b/src/mame/audio/exidy440.h
index 9f8861bdfe3..e3920be90a2 100644
--- a/src/mame/audio/exidy440.h
+++ b/src/mame/audio/exidy440.h
@@ -29,7 +29,7 @@ protected:
virtual void device_stop() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void exidy440_audio_map(address_map &map);
@@ -76,8 +76,8 @@ private:
uint8_t m_sound_banks[4];
//uint8_t m_m6844_data[0x20];
uint8_t m_sound_volume[0x10];
- std::unique_ptr<int32_t[]> m_mixer_buffer_left;
- std::unique_ptr<int32_t[]> m_mixer_buffer_right;
+ std::vector<int32_t> m_mixer_buffer_left;
+ std::vector<int32_t> m_mixer_buffer_right;
sound_cache_entry *m_sound_cache;
sound_cache_entry *m_sound_cache_end;
sound_cache_entry *m_sound_cache_max;
@@ -111,7 +111,7 @@ private:
void fir_filter(int32_t *input, int16_t *output, int count);
void add_and_scale_samples(int ch, int32_t *dest, int samples, int volume);
- void mix_to_16(int length, stream_sample_t *dest_left, stream_sample_t *dest_right);
+ void mix_to_16(write_stream_view &dest_left, write_stream_view &dest_right);
uint8_t sound_command_r();
uint8_t sound_volume_r(offs_t offset);
diff --git a/src/mame/audio/flower.cpp b/src/mame/audio/flower.cpp
index 4ade0d864a9..99806a0c6b6 100644
--- a/src/mame/audio/flower.cpp
+++ b/src/mame/audio/flower.cpp
@@ -48,9 +48,7 @@ flower_sound_device::flower_sound_device(const machine_config &mconfig, const ch
device_memory_interface(mconfig, *this),
m_io_space_config("io", ENDIANNESS_LITTLE, 8, 7, 0, address_map_constructor(FUNC(flower_sound_device::regs_map), this)),
m_stream(nullptr),
- m_mixer_table(nullptr),
m_mixer_lookup(nullptr),
- m_mixer_buffer(nullptr),
m_last_channel(nullptr)
{
}
@@ -63,9 +61,9 @@ flower_sound_device::flower_sound_device(const machine_config &mconfig, const ch
void flower_sound_device::device_start()
{
m_iospace = &space(AS_IO);
- m_stream = stream_alloc_legacy(0, 1, clock()/2);
+ m_stream = stream_alloc(0, 1, clock()/2);
- m_mixer_buffer = make_unique_clear<short[]>(clock()/2);
+ m_mixer_buffer.resize(clock()/50);
make_mixer_table(MAX_VOICES, defgain);
m_last_channel = m_channel_list + MAX_VOICES;
@@ -94,10 +92,10 @@ void flower_sound_device::device_start()
void flower_sound_device::make_mixer_table(int voices, int gain)
{
/* allocate memory */
- m_mixer_table = make_unique_clear<int16_t[]>(256 * voices);
+ m_mixer_table.resize(256 * voices);
/* find the middle of the table */
- m_mixer_lookup = m_mixer_table.get() + (128 * voices);
+ m_mixer_lookup = &m_mixer_table[128 * voices];
/* fill in the table - 16 bit case */
for (int i = 0; i < voices * 128; i++)
@@ -127,13 +125,13 @@ void flower_sound_device::device_reset()
}
}
-void flower_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void flower_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
short *mix;
uint8_t raw_sample;
- memset(m_mixer_buffer.get(), 0, samples * sizeof(short));
+ std::fill_n(&m_mixer_buffer[0], buffer.samples(), 0);
for (fl_sound_channel *voice = m_channel_list; voice < m_last_channel; voice++)
{
@@ -143,9 +141,9 @@ void flower_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
if (voice->enable == false)
continue;
- mix = m_mixer_buffer.get();
+ mix = &m_mixer_buffer[0];
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < buffer.samples(); i++)
{
if (voice->repeat == true)
{
@@ -174,9 +172,9 @@ void flower_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
}
/* mix it down */
- mix = m_mixer_buffer.get();
- for (int i = 0; i < samples; i++)
- *buffer++ = m_mixer_lookup[*mix++];
+ mix = &m_mixer_buffer[0];
+ for (int i = 0; i < buffer.samples(); i++)
+ buffer.put_int(i, m_mixer_lookup[*mix++], 32768);
}
//-------------------------------------------------
diff --git a/src/mame/audio/flower.h b/src/mame/audio/flower.h
index 8fad33679c6..44787c6f30d 100644
--- a/src/mame/audio/flower.h
+++ b/src/mame/audio/flower.h
@@ -39,7 +39,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual space_config_vector memory_space_config() const override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
address_space *m_iospace;
private:
@@ -50,9 +50,9 @@ private:
static constexpr unsigned MAX_VOICES = 8;
static constexpr int defgain = 48;
- std::unique_ptr<int16_t[]> m_mixer_table;
+ std::vector<int16_t> m_mixer_table;
int16_t *m_mixer_lookup;
- std::unique_ptr<short[]> m_mixer_buffer;
+ std::vector<short> m_mixer_buffer;
struct fl_sound_channel
{
diff --git a/src/mame/audio/geebee.cpp b/src/mame/audio/geebee.cpp
index 63859916d7c..01858b5ecad 100644
--- a/src/mame/audio/geebee.cpp
+++ b/src/mame/audio/geebee.cpp
@@ -42,7 +42,7 @@ void geebee_sound_device::device_start()
m_decay[0x7fff - i] = (int16_t) (0x7fff/exp(1.0*i/4096));
/* 1V = HSYNC = 18.432MHz / 3 / 2 / 384 = 8000Hz */
- m_channel = stream_alloc_legacy(0, 1, clock() / 3 / 2 / 384);
+ m_channel = stream_alloc(0, 1, clock() / 3 / 2 / 384);
m_vcount = 0;
m_volume_timer = timer_alloc(TIMER_VOLUME_DECAY);
@@ -103,16 +103,16 @@ void geebee_sound_device::sound_w(u8 data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void geebee_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
- {
- stream_sample_t *buffer = outputs[0];
+void geebee_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ auto &buffer = outputs[0];
- while (samples--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
- *buffer++ = m_sound_signal;
+ buffer.put_int(sampindex, m_sound_signal, 32768);
/* 1V = HSYNC = 18.432MHz / 3 / 2 / 384 = 8000Hz */
{
m_vcount++;
diff --git a/src/mame/audio/geebee.h b/src/mame/audio/geebee.h
index 1cca0fc6dd0..1bbddf36bba 100644
--- a/src/mame/audio/geebee.h
+++ b/src/mame/audio/geebee.h
@@ -22,7 +22,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
diff --git a/src/mame/audio/gomoku.cpp b/src/mame/audio/gomoku.cpp
index 6aeb288f6db..632b016441e 100644
--- a/src/mame/audio/gomoku.cpp
+++ b/src/mame/audio/gomoku.cpp
@@ -11,8 +11,6 @@
#include "emu.h"
#include "audio/gomoku.h"
-constexpr int DEFGAIN = 48;
-
// device type definition
DEFINE_DEVICE_TYPE(GOMOKU_SOUND, gomoku_sound_device, "gomoku_sound", "Gomoku Narabe Renju Custom Sound")
@@ -32,10 +30,6 @@ gomoku_sound_device::gomoku_sound_device(const machine_config &mconfig, const ch
, m_sound_rom(*this, DEVICE_SELF)
, m_sound_enable(0)
, m_stream(nullptr)
- , m_mixer_table(nullptr)
- , m_mixer_lookup(nullptr)
- , m_mixer_buffer(nullptr)
- , m_mixer_buffer_2(nullptr)
{
std::fill(std::begin(m_soundregs1), std::end(m_soundregs1), 0);
std::fill(std::begin(m_soundregs2), std::end(m_soundregs2), 0);
@@ -52,14 +46,10 @@ void gomoku_sound_device::device_start()
int ch;
// get stream channels
- m_stream = stream_alloc_legacy(0, 1, clock());
-
- // allocate a pair of buffers to mix into - 1 second's worth should be more than enough
- m_mixer_buffer = std::make_unique<short[]>(2 * clock());
- m_mixer_buffer_2 = m_mixer_buffer.get() + clock(); // this is never used?
+ m_stream = stream_alloc(0, 1, clock());
- // build the mixer table
- make_mixer_table(8, DEFGAIN);
+ // allocate a buffer to mix into - 1 second's worth should be more than enough
+ m_mixer_buffer.resize(clock()/50);
// start with sound enabled, many games don't have a sound enable register
m_sound_enable = 1;
@@ -76,7 +66,6 @@ void gomoku_sound_device::device_start()
save_item(NAME(m_soundregs1));
save_item(NAME(m_soundregs2));
- save_pointer(NAME(m_mixer_buffer), 2 * clock());
// save_item(NAME(m_sound_enable)); // set to 1 at device start and never updated?
save_item(STRUCT_MEMBER(m_channel_list, channel));
save_item(STRUCT_MEMBER(m_channel_list, frequency));
@@ -87,12 +76,12 @@ void gomoku_sound_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update in mono
+// sound_stream_update - handle a stream update in mono
//-------------------------------------------------
-void gomoku_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void gomoku_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
sound_channel *voice;
short *mix;
int ch;
@@ -100,12 +89,12 @@ void gomoku_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
// if no sound, we're done
if (m_sound_enable == 0)
{
- memset(buffer, 0, samples * sizeof(*buffer));
+ buffer.fill(0);
return;
}
// zap the contents of the mixer buffer
- memset(m_mixer_buffer.get(), 0, samples * sizeof(short));
+ std::fill_n(&m_mixer_buffer[0], buffer.samples(), 0);
// loop over each voice and add its contribution
for (ch = 0, voice = std::begin(m_channel_list); voice < std::end(m_channel_list); ch++, voice++)
@@ -124,10 +113,10 @@ void gomoku_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
else
w_base = 0x100 * (m_soundregs2[0x1d] & 0x0f);
- mix = m_mixer_buffer.get();
+ mix = &m_mixer_buffer[0];
// add our contribution
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < buffer.samples(); i++)
{
c += f;
@@ -167,31 +156,9 @@ void gomoku_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
}
// mix it down
- mix = m_mixer_buffer.get();
- for (int i = 0; i < samples; i++)
- *buffer++ = m_mixer_lookup[*mix++];
-}
-
-
-// build a table to divide by the number of voices; gain is specified as gain*16
-void gomoku_sound_device::make_mixer_table(int voices, int gain)
-{
- int count = voices * 128;
-
- // allocate memory
- m_mixer_table = std::make_unique<int16_t[]>(256 * voices);
-
- // find the middle of the table
- m_mixer_lookup = m_mixer_table.get() + (128 * voices);
-
- // fill in the table - 16 bit case
- for (int i = 0; i < count; i++)
- {
- int val = i * gain * 16 / voices;
- if (val > 32767) val = 32767;
- m_mixer_lookup[ i] = val;
- m_mixer_lookup[-i] = -val;
- }
+ mix = &m_mixer_buffer[0];
+ for (int i = 0; i < buffer.samples(); i++)
+ buffer.put_int(i, *mix++, 128 * MAX_VOICES);
}
diff --git a/src/mame/audio/gomoku.h b/src/mame/audio/gomoku.h
index 75de8a2c09c..0c077de96bd 100644
--- a/src/mame/audio/gomoku.h
+++ b/src/mame/audio/gomoku.h
@@ -23,7 +23,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void make_mixer_table(int voices, int gain);
@@ -52,10 +52,7 @@ private:
sound_stream *m_stream;
// mixer tables and internal buffers
- std::unique_ptr<int16_t[]> m_mixer_table;
- int16_t *m_mixer_lookup;
- std::unique_ptr<short[]> m_mixer_buffer;
- short *m_mixer_buffer_2;
+ std::vector<short> m_mixer_buffer;
uint8_t m_soundregs1[0x20];
uint8_t m_soundregs2[0x20];
diff --git a/src/mame/audio/gottlieb.cpp b/src/mame/audio/gottlieb.cpp
index db7d34b0ccc..69dbeb41a1d 100644
--- a/src/mame/audio/gottlieb.cpp
+++ b/src/mame/audio/gottlieb.cpp
@@ -379,7 +379,7 @@ void gottlieb_sound_r1_with_votrax_device::speech_clock_dac_w(uint8_t data)
logerror("clock = %02X\n", data);
// totally random guesswork; would like to get real measurements on a board
- m_votrax->set_unscaled_clock(900000 + (data - 0xa0) * 9000);
+ m_votrax->set_unscaled_clock(950000 + (data - 0xa0) * 5500);
m_last_speech_clock = data;
}
}
diff --git a/src/mame/audio/gridlee.cpp b/src/mame/audio/gridlee.cpp
index 429518b39d0..2f6904c4efc 100644
--- a/src/mame/audio/gridlee.cpp
+++ b/src/mame/audio/gridlee.cpp
@@ -43,26 +43,26 @@ gridlee_sound_device::gridlee_sound_device(const machine_config &mconfig, const
void gridlee_sound_device::device_start()
{
/* allocate the stream */
- m_stream = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_stream = stream_alloc(0, 1, machine().sample_rate());
m_freq_to_step = (double)(1 << 24) / (double)machine().sample_rate();
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void gridlee_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void gridlee_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
/* loop over samples */
- while (samples--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
/* tone channel */
m_tone_fraction += m_tone_step;
- *buffer++ = (m_tone_fraction & 0x0800000) ? (m_tone_volume << 6) : 0;
+ buffer.put_int(sampindex, (m_tone_fraction & 0x0800000) ? m_tone_volume : 0, 32768 >> 6);
}
}
diff --git a/src/mame/audio/hyprolyb.cpp b/src/mame/audio/hyprolyb.cpp
index 77ff8034ae5..c97d5612d03 100644
--- a/src/mame/audio/hyprolyb.cpp
+++ b/src/mame/audio/hyprolyb.cpp
@@ -8,7 +8,6 @@ DEFINE_DEVICE_TYPE(HYPROLYB_ADPCM, hyprolyb_adpcm_device, "hyprolyb_adpcm", "Hyp
hyprolyb_adpcm_device::hyprolyb_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, HYPROLYB_ADPCM, tag, owner, clock)
- , device_sound_interface(mconfig, *this)
, m_audiocpu(*this, ":audiocpu")
, m_soundlatch2(*this, ":soundlatch2")
, m_msm(*this, ":msm")
@@ -80,13 +79,3 @@ void hyprolyb_adpcm_device::vck_callback( int st )
{
m_vck_ready = 0x80;
}
-
-//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
-//-------------------------------------------------
-
-void hyprolyb_adpcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update_legacy called; not applicable to legacy sound devices\n");
-}
diff --git a/src/mame/audio/hyprolyb.h b/src/mame/audio/hyprolyb.h
index ac2687b40e4..5d9ce541551 100644
--- a/src/mame/audio/hyprolyb.h
+++ b/src/mame/audio/hyprolyb.h
@@ -8,7 +8,7 @@
#include "machine/gen_latch.h"
#include "sound/msm5205.h"
-class hyprolyb_adpcm_device : public device_t, public device_sound_interface
+class hyprolyb_adpcm_device : public device_t
{
public:
hyprolyb_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -27,9 +27,6 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- // sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
-
private:
// internal state
required_device<cpu_device> m_audiocpu;
diff --git a/src/mame/audio/lynx.cpp b/src/mame/audio/lynx.cpp
index 40369d86d1d..d839a4c1704 100644
--- a/src/mame/audio/lynx.cpp
+++ b/src/mame/audio/lynx.cpp
@@ -172,7 +172,7 @@ void lynx_sound_device::init()
void lynx_sound_device::device_start()
{
- m_mixer_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_mixer_channel = stream_alloc(0, 1, machine().sample_rate());
m_usec_per_sample = 1000000 / machine().sample_rate();
m_timer_delegate.resolve();
init();
@@ -182,7 +182,7 @@ void lynx_sound_device::device_start()
void lynx2_sound_device::device_start()
{
- m_mixer_channel = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_mixer_channel = stream_alloc(0, 2, machine().sample_rate());
m_usec_per_sample = 1000000 / machine().sample_rate();
m_timer_delegate.resolve();
init();
@@ -467,39 +467,41 @@ void lynx_sound_device::write(offs_t offset, uint8_t data)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void lynx_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void lynx_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int v;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
- for (int i = 0; i < samples; i++, buffer++)
+ for (int i = 0; i < buffer.samples(); i++)
{
- *buffer = 0;
+ s32 result = 0;
for (int channel = 0; channel < LYNX_AUDIO_CHANNELS; channel++)
{
execute(channel);
v = m_audio[channel].reg.output;
- *buffer += v * 15; // where does the *15 come from?
+ result += v * 15; // where does the *15 come from?
}
+ buffer.put_int(i, result, 32768);
}
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void lynx2_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void lynx2_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *left=outputs[0], *right=outputs[1];
+ auto &left=outputs[0];
+ auto &right=outputs[1];
int v;
- for (int i = 0; i < samples; i++, left++, right++)
+ for (int i = 0; i < left.samples(); i++)
{
- *left = 0;
- *right= 0;
+ s32 lsum = 0;
+ s32 rsum = 0;
for (int channel = 0; channel < LYNX_AUDIO_CHANNELS; channel++)
{
execute(channel);
@@ -507,17 +509,19 @@ void lynx2_sound_device::sound_stream_update_legacy(sound_stream &stream, stream
if (!(m_master_enable & (0x10 << channel)))
{
if (m_attenuation_enable & (0x10 << channel))
- *left += v * (m_audio[channel].attenuation >> 4);
+ lsum += v * (m_audio[channel].attenuation >> 4);
else
- *left += v * 15;
+ lsum += v * 15;
}
if (!(m_master_enable & (1 << channel)))
{
if (m_attenuation_enable & (1 << channel))
- *right += v * (m_audio[channel].attenuation & 0xf);
+ rsum += v * (m_audio[channel].attenuation & 0xf);
else
- *right += v * 15;
+ rsum += v * 15;
}
}
+ left.put_int(i, lsum, 32768);
+ right.put_int(i, rsum, 32768);
}
}
diff --git a/src/mame/audio/lynx.h b/src/mame/audio/lynx.h
index 11b983089a7..07bfef1a98b 100644
--- a/src/mame/audio/lynx.h
+++ b/src/mame/audio/lynx.h
@@ -45,7 +45,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void reset_channel(LYNX_AUDIO *channel);
void shift(int chan_nr);
@@ -75,7 +75,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
};
diff --git a/src/mame/audio/micro3d.cpp b/src/mame/audio/micro3d.cpp
index 52f723ef55f..5f38bdad788 100644
--- a/src/mame/audio/micro3d.cpp
+++ b/src/mame/audio/micro3d.cpp
@@ -68,9 +68,9 @@ void micro3d_sound_device::lp_filter::init(double fsval)
proto_coef[1].b1 = 1.847759;
proto_coef[1].b2 = 1.0;
- coef = make_unique_clear<float[]>(4 * 2 + 1);
+ std::fill(std::begin(coef), std::end(coef), 0);
fs = fsval;
- history = make_unique_clear<float[]>(2 * 2);
+ std::fill(std::begin(history), std::end(history), 0);
}
static void prewarp(double *a0, double *a1, double *a2,double fc, double fs)
@@ -104,7 +104,7 @@ static void bilinear(double a0, double a1, double a2,
void micro3d_sound_device::lp_filter::recompute(double k, double q, double fc)
{
- float *c = coef.get() + 1;
+ float *c = &coef[1];
for (int nInd = 0; nInd < 2; nInd++)
{
@@ -182,7 +182,7 @@ micro3d_sound_device::micro3d_sound_device(const machine_config &mconfig, const
void micro3d_sound_device::device_start()
{
/* Allocate the stream */
- m_stream = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_stream = stream_alloc(0, 2, machine().sample_rate());
m_filter.init(machine().sample_rate());
m_noise_filters[0].configure(2.7e3 + 2.7e3, 1.0e-6);
@@ -206,20 +206,20 @@ void micro3d_sound_device::device_reset()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void micro3d_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void micro3d_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
lp_filter *iir = &m_filter;
float pan_l, pan_r;
- stream_sample_t *fl = &outputs[0][0];
- stream_sample_t *fr = &outputs[1][0];
+ auto &fl = outputs[0];
+ auto &fr = outputs[1];
/* Clear the buffers */
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+ fl.fill(0);
+ fr.fill(0);
if (m_gain == 0)
return;
@@ -227,7 +227,7 @@ void micro3d_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
pan_l = (float)(255 - m_dac[PAN]) / 255.0f;
pan_r = (float)(m_dac[PAN]) / 255.0f;
- while (samples--)
+ for (int sampindex = 0; sampindex < fl.samples(); sampindex++)
{
unsigned int i;
float *hist1_ptr,*hist2_ptr,*coef_ptr;
@@ -255,9 +255,9 @@ void micro3d_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
input += white;
input *= 200.0f;
- coef_ptr = iir->coef.get();
+ coef_ptr = &iir->coef[0];
- hist1_ptr = iir->history.get();
+ hist1_ptr = &iir->history[0];
hist2_ptr = hist1_ptr + 1;
/* 1st number of coefficients array is overall input scale factor, * or filter gain */
@@ -279,15 +279,9 @@ void micro3d_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
hist1_ptr++;
hist2_ptr++;
}
- output *= 3.5f;
+ output *= 3.5f / 32768.f;
- /* Clip */
- if (output > 32767)
- output = 32767;
- else if (output < -32768)
- output = -32768;
-
- *fl++ = output * pan_l;
- *fr++ = output * pan_r;
+ fl.put_clamp(sampindex, output * pan_l, 1.0);
+ fr.put_clamp(sampindex, output * pan_r, 1.0);
}
}
diff --git a/src/mame/audio/micro3d.h b/src/mame/audio/micro3d.h
index 937d1fbed74..04b2b284deb 100644
--- a/src/mame/audio/micro3d.h
+++ b/src/mame/audio/micro3d.h
@@ -24,7 +24,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
enum dac_registers {
@@ -45,8 +45,8 @@ private:
void init(double fs);
void recompute(double k, double q, double fc);
- std::unique_ptr<float[]> history;
- std::unique_ptr<float[]> coef;
+ float history[2 * 2];
+ float coef[4 * 2 + 1];
double fs;
biquad proto_coef[2];
};
diff --git a/src/mame/audio/nl_armora.cpp b/src/mame/audio/nl_armora.cpp
index 53b102be96b..05775622295 100644
--- a/src/mame/audio/nl_armora.cpp
+++ b/src/mame/audio/nl_armora.cpp
@@ -224,7 +224,7 @@ NETLIST_START(armora)
D_1N914(D8)
- Q_2N3904(Q1) // NPN
+// Q_2N3904(Q1) // NPN -- not used
Q_2N3906(Q2) // PNP
Q_2N3906(Q3) // PNP
Q_2N3906(Q4) // PNP
diff --git a/src/mame/audio/nl_astrob.cpp b/src/mame/audio/nl_astrob.cpp
index ee158301c29..9633191499a 100644
--- a/src/mame/audio/nl_astrob.cpp
+++ b/src/mame/audio/nl_astrob.cpp
@@ -30,7 +30,8 @@
#define HLE_LASER_1_VCO (1)
#define HLE_LASER_2_VCO (1)
-#define SIMPLIFY_SONAR (1)
+#define SIMPLIFY_SONAR (0) // only use one oscillator
+#define ENABLE_SONAR_ALT (1) // use frontiers to separate oscillators, modify UGF
#define ENABLE_FRONTIERS (1)
#define UNDERCLOCK_NOISE_GEN (1)
@@ -58,7 +59,28 @@
#define TTL_74LS00_DIP TTL_7400_DIP
#define TTL_74LS04_DIP TTL_7404_DIP
-
+// Define some random factors (5%)
+
+#define FRND1 1.023
+#define FRND2 1.017
+#define FRND3 1.005
+#define FRND4 1.014
+#define FRND5 1.049
+#define FRND6 1.044
+#define FRND7 1.016
+#define FRND8 1.037
+#define FRND9 1.030
+#define FRND10 1.001
+#define FRND11 1.034
+#define FRND12 1.043
+#define FRND13 1.011
+#define FRND14 1.016
+#define FRND15 1.011
+#define FRND16 1.006
+#define FRND17 1.009
+#define FRND18 1.007
+#define FRND19 1.035
+#define FRND20 1.004
//
// Main netlist
@@ -71,9 +93,11 @@ NETLIST_START(astrob)
PARAM(Solver.DYNAMIC_TS, 1)
PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 4e-5)
#if (SIMPLIFY_SONAR)
- PARAM(Solver.Solver_54.DYNAMIC_MIN_TIMESTEP, 7e-6) // gets rid of NR loops failure
+ PARAM(Solver.Solver_54.DYNAMIC_MIN_TIMESTEP, 4e-6) // gets rid of NR loops failure
#else
- PARAM(Solver.Solver_40.DYNAMIC_MIN_TIMESTEP, 7e-6) // gets rid of NR loops failure
+#if !(ENABLE_SONAR_ALT)
+ PARAM(Solver.Solver_41.DYNAMIC_MIN_TIMESTEP, 6e-6) // gets rid of NR loops failure
+#endif
#endif
#else
SOLVER(Solver, 48000)
@@ -145,15 +169,15 @@ NETLIST_START(astrob)
ANALOG_INPUT(I_V12, 12)
ANALOG_INPUT(I_VM12, -12)
- RES(R1, RES_K(100))
- RES(R2, RES_K(1.5))
- RES(R3, RES_K(330))
- RES(R4, RES_K(10))
+ RES(R1, RES_K(100) * FRND1) // part of SONAR circuit that relies on subtle part differences
+ RES(R2, RES_K(1.5) * FRND2) // part of SONAR circuit that relies on subtle part differences
+ RES(R3, RES_K(330) * FRND3) // part of SONAR circuit that relies on subtle part differences
+ RES(R4, RES_K(10) * FRND4) // part of SONAR circuit that relies on subtle part differences
#if (SIMPLIFY_SONAR)
// use less resistance to account for only emulating 1/4 identical circuits
- RES(R5, RES_K(17))
+ RES(R5, RES_K(17)) // part of SONAR circuit that relies on subtle part differences
#else
- RES(R5, RES_K(68))
+ RES(R5, RES_K(68) * FRND5) // part of SONAR circuit that relies on subtle part differences
#endif
RES(R6, RES_K(68))
RES(R7, RES_K(22))
@@ -185,11 +209,11 @@ NETLIST_START(astrob)
RES(R33, RES_K(39))
RES(R34, RES_K(4.7))
RES(R35, RES_K(4.7))
- RES(R36, RES_K(100.1)) // part of SONAR circuit that relies on subtle part differences
- RES(R37, RES_K(1.51)) // part of SONAR circuit that relies on subtle part differences
- RES(R38, RES_K(330.1)) // part of SONAR circuit that relies on subtle part differences
- RES(R39, RES_K(10.1)) // part of SONAR circuit that relies on subtle part differences
- RES(R40, RES_K(68.1)) // part of SONAR circuit that relies on subtle part differences
+ RES(R36, RES_K(100) * FRND6) // part of SONAR circuit that relies on subtle part differences
+ RES(R37, RES_K(1.5) * FRND7) // part of SONAR circuit that relies on subtle part differences
+ RES(R38, RES_K(330) * FRND8) // part of SONAR circuit that relies on subtle part differences
+ RES(R39, RES_K(10) * FRND9) // part of SONAR circuit that relies on subtle part differences
+ RES(R40, RES_K(68) * FRND10) // part of SONAR circuit that relies on subtle part differences
RES(R41, RES_K(10))
RES(R42, RES_K(100))
RES(R43, RES_K(470))
@@ -211,11 +235,11 @@ NETLIST_START(astrob)
RES(R59, RES_K(100))
RES(R60, RES_K(10))
RES(R61, RES_K(100))
- RES(R62, RES_K(99.9)) // part of SONAR circuit that relies on subtle part differences
- RES(R63, RES_K(1.49)) // part of SONAR circuit that relies on subtle part differences
- RES(R64, RES_K(329.9)) // part of SONAR circuit that relies on subtle part differences
- RES(R65, RES_K(9.9)) // part of SONAR circuit that relies on subtle part differences
- RES(R66, RES_K(67.9)) // part of SONAR circuit that relies on subtle part differences
+ RES(R62, RES_K(100) * FRND11) // part of SONAR circuit that relies on subtle part differences
+ RES(R63, RES_K(1.5) * FRND12) // part of SONAR circuit that relies on subtle part differences
+ RES(R64, RES_K(330) * FRND13) // part of SONAR circuit that relies on subtle part differences
+ RES(R65, RES_K(10) * FRND14) // part of SONAR circuit that relies on subtle part differences
+ RES(R66, RES_K(68) * FRND15) // part of SONAR circuit that relies on subtle part differences
RES(R67, RES_K(10))
RES(R68, RES_K(82))
RES(R69, RES_K(470))
@@ -240,11 +264,11 @@ NETLIST_START(astrob)
RES(R88, RES_K(100))
RES(R89, RES_K(10))
RES(R90, RES_K(100))
- RES(R91, RES_K(100.2)) // part of SONAR circuit that relies on subtle part differences
- RES(R92, RES_K(1.52)) // part of SONAR circuit that relies on subtle part differences
- RES(R93, RES_K(330.2)) // part of SONAR circuit that relies on subtle part differences
- RES(R94, RES_K(10.2)) // part of SONAR circuit that relies on subtle part differences
- RES(R95, RES_K(68.2)) // part of SONAR circuit that relies on subtle part differences
+ RES(R91, RES_K(100) * FRND16) // part of SONAR circuit that relies on subtle part differences
+ RES(R92, RES_K(1.5) * FRND17) // part of SONAR circuit that relies on subtle part differences
+ RES(R93, RES_K(330) * FRND18) // part of SONAR circuit that relies on subtle part differences
+ RES(R94, RES_K(10) * FRND19) // part of SONAR circuit that relies on subtle part differences
+ RES(R95, RES_K(68) * FRND20) // part of SONAR circuit that relies on subtle part differences
RES(R96, RES_K(10))
RES(R97, RES_K(4.7))
RES(R98, RES_M(1))
@@ -455,7 +479,7 @@ NETLIST_START(astrob)
Q_2N4403(Q1)
Q_2N4403(Q2)
Q_2N4403(Q3)
- Q_2N4093(Q4)
+ //Q_2N4093(Q4) // avoid singular matrix being created
Q_2N4093(Q5)
Q_2N4093(Q6)
Q_2N4403(Q7)
@@ -471,6 +495,18 @@ NETLIST_START(astrob)
NET_C(U2.4, I_V12)
NET_C(U2.11, I_VM12)
+#if (ENABLE_SONAR_ALT)
+ // Oscillators are of order 1kHz. No need to to have UGF in MHz range
+ PARAM(U1.A.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U1.B.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U1.C.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U1.D.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U2.A.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U2.B.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U2.C.MODEL, "TL084(TYPE=3 UGF=10k)")
+ PARAM(U2.D.MODEL, "TL084(TYPE=3 UGF=10k)")
+#endif
+
CD4017_DIP(U3) // Decade Counter/Divider
NET_C(U3.8, GND)
NET_C(U3.16, I_V12)
@@ -640,7 +676,7 @@ NETLIST_START(astrob)
NET_C(U2.3, GND)
NET_C(U2.2, D6.A, R65.1)
- NET_C(U2.14, D6.K, R62.1)
+ NET_C(U2.1, D6.K, R62.1)
NET_C(R62.2, R63.2, C24.1, C25.1)
NET_C(R63.1, GND)
NET_C(R65.2, R64.2, U2.7, C25.2, R66.2)
@@ -657,6 +693,29 @@ NETLIST_START(astrob)
NET_C(U2.10, GND)
NET_C(R5.1, R40.1, R114.1, Q3.B, R95.1, R66.1)
+
+#if (ENABLE_SONAR_ALT)
+ // The oscillators need a small offset voltage to start oscillating.
+ // Without frontiers I assume the offset voltage is created due to the
+ // slight differences in resistor values in the four (now connected)
+ // oscillators.
+
+ ANALOG_INPUT(I_VOFF, 0.1)
+ RES(RDUM1, RES_M(1))
+ RES(RDUM2, RES_M(1))
+ RES(RDUM3, RES_M(1))
+ RES(RDUM4, RES_M(1))
+ NET_C(R5.2, RDUM1.1)
+ NET_C(R40.2, RDUM2.1)
+ NET_C(R95.2, RDUM3.1)
+ NET_C(R66.2, RDUM4.1)
+ NET_C(I_VOFF, RDUM1.2, RDUM2.2, RDUM3.2, RDUM4.2)
+
+ OPTIMIZE_FRONTIER(R5.2, RES_K(68), 192)
+ OPTIMIZE_FRONTIER(R40.2, RES_K(68), 192)
+ OPTIMIZE_FRONTIER(R95.2, RES_K(68), 192)
+ OPTIMIZE_FRONTIER(R66.2, RES_K(68), 192)
+#endif
#endif
NET_C(R114.2, GND)
diff --git a/src/mame/audio/nl_barrier.cpp b/src/mame/audio/nl_barrier.cpp
index edd7c3d71a3..929e666eb08 100644
--- a/src/mame/audio/nl_barrier.cpp
+++ b/src/mame/audio/nl_barrier.cpp
@@ -123,11 +123,13 @@ NETLIST_START(barrier)
D_1N914(CR5)
D_1N914(CR6)
+#if !(HLE_NOISE_GEN)
Q_2N3906(Q1) // PNP
Q_2N3904(Q2) // NPN
+#endif
Q_2N6426(Q3) // NPN Darlington
- Q_2N6292(Q4) // NPN
- Q_2N6107(Q5) // PNP
+// Q_2N6292(Q4) // NPN -- not used
+// Q_2N6107(Q5) // PNP -- not used
Q_2N6426(Q6) // NPN Darlington
Q_2N3904(Q7) // NPN
diff --git a/src/mame/audio/nl_boxingb.cpp b/src/mame/audio/nl_boxingb.cpp
index 39be6050b19..6d80f60f1b2 100644
--- a/src/mame/audio/nl_boxingb.cpp
+++ b/src/mame/audio/nl_boxingb.cpp
@@ -362,31 +362,41 @@ NETLIST_START(boxingb)
Q_2N3906(Q3) // PNP
Q_2N3906(Q4) // PNP
Q_2N3904(Q5) // NPN
+#if !(HLE_CHIRPING_VCO)
Q_2N3904(Q6) // NPN
+#endif
Q_2N3906(Q7) // PNP
Q_2N3904(Q8) // NPN
+#if !(HLE_DYING_BUG_VCO)
Q_2N3904(Q9) // NPN
+#endif
Q_2N3906(Q10) // PNP
Q_2N3904(Q11) // NPN
+#if !(HLE_CRACKING_VCO)
Q_2N3904(Q12) // NPN
+#endif
Q_2N3906(Q13) // PNP
Q_2N3904(Q14) // NPN
+#if !(HLE_BEETLE_VCO)
Q_2N3904(Q15) // NPN
+#endif
Q_2N3906(Q16) // PNP
Q_2N3904(Q17) // NPN
Q_2N3906(Q18) // PNP
Q_2N3906(Q19) // PNP
Q_2N3906(Q20) // PNP
Q_2N3904(Q21) // NPN
+#if !(HLE_CANNON_VCO)
Q_2N3904(Q22) // NPN
+#endif
Q_2N3906(Q23) // PNP
Q_2N3906(Q24) // PNP
Q_2N3906(Q25) // PNP
Q_2N3906(Q26) // PNP
// Q_2N6292(Q27) // PNP -- part of final amp (not emulated)
// Q_2N6107(Q28) // NPN -- part of final amp (not emulated)
- Q_2N5210(Q29) // NPN
- Q_2N5210(Q30) // NPN
+// Q_2N5210(Q29) // NPN -- not used
+// Q_2N5210(Q30) // NPN -- not used
Q_2N3906(Q31) // PNP
Q_2N3906(Q32) // PNP
Q_2N3906(Q33) // PNP
@@ -1171,7 +1181,7 @@ NETLIST_START(boxingb)
// R2 = 0.97985: HP = (0.0000369937*A0*A0*A0*A0) - (0.000849582*A0*A0*A0) - (0.00300315*A0*A0) + (0.185593*A0) - 1.090973
// R2 = 0.24613: HP = (-0.000199982*A0*A0*A0*A0*A0) + (0.0134882*A0*A0*A0*A0) - (0.362557*A0*A0*A0) + (4.857498*A0*A0) - (32.45284*A0) + 86.5278
//
- VARCLOCK(BOUNCECLK, 1, "max(0.000001,min(0.1,((0.00115078*A0*A0*A0) - (0.0435380*A0*A0) + (0.550407*A0) - 2.321385))")
+ VARCLOCK(BOUNCECLK, 1, "max(0.000001,min(0.1,((0.00115078*A0*A0*A0) - (0.0435380*A0*A0) + (0.550407*A0) - 2.321385)))")
NET_C(BOUNCECLK.GND, GND)
NET_C(BOUNCECLK.VCC, I_V5)
NET_C(BOUNCECLK.A0, C39.2)
diff --git a/src/mame/audio/nl_brdrline.cpp b/src/mame/audio/nl_brdrline.cpp
new file mode 100644
index 00000000000..e08121f90fa
--- /dev/null
+++ b/src/mame/audio/nl_brdrline.cpp
@@ -0,0 +1,1721 @@
+// license:CC0
+// copyright-holders: beta-tester (https://github.com/beta-tester)
+
+//NL_CONTAINS brdrline
+
+//
+// Netlist for Borderline (brdrline)
+//
+// Derived from the schematics in the Borderline Quest Owner's Manual.
+//
+// Known problems/issues:
+//
+// * all transistors in schematics of sound genertors were drawn
+// in a wrong orientation.
+// base and collectors were swaped
+//
+// * MB4391 is missing. a fake substitution is used
+//
+// * it takes up to 30seconds to charge C24 to its working point
+// in ANIMAL_SOUND
+//
+// * noise generation with MM5837_DIP eats a lot of CPU power
+//
+
+
+// ---------------------------------------------------------------------------
+// Borderline
+// Owner's Manual
+// Sega/Gremlin, Manual Part No. 420-0613
+//
+// ...........................................................................
+// Page 26
+// Sound Board Assembly
+// Drawing No. 834-0055, Rev. A, Sheet 6 of 7
+// () = location in schematics
+// ...........................................................................
+// GUN_TRG (C8); GUN_SOUND (D6); (C8,D8,C7,D7,C6,D6)
+// JEEP_ON (C8); JEEP_SOUND (C6); (C8,B8,C7,B7,C6,B6)
+// POINT_TRG (A8); POINT_SOUND (B3); (A8,B8,A7,B7,A6,B6,A5,B5,C5,D5,A4,B4,C5,
+// D4,B3)
+// HIT_TRG (A8); HIT_SOUND (A4); (A8,A7,A6,A5,A4,B4,C4,D4,A3,B4,C3,D3)
+//
+// ...........................................................................
+// Page 27
+// Sound Board Assembly
+// Drawing No. 834-0055, Rev. A, Sheet 7 of 7
+// () = location in schematics
+// ...........................................................................
+// ANIMAL_TRG (D8); ANIMAL_SOUND (C6); (D8,C8,B8,A8,D7,C7,B7,A8,D6,C6,D5,C5)
+// EMAR_TRG (A8); EMAR_SOUND (C5); (A8,A7,B7,C6,B6,B5,C5,B4,C4,D4,D3)
+// WALK_TRG (A8); WALK_SOUND (B5); (A8,A7,A6,B6,B5)
+// CRY_TRG (A8); CRY_SOUND (C1); (A8,A7,A6,A5,A4,A3,B3,C3,A2,B2,C2,A1,
+// B1,C1)
+// ---------------------------------------------------------------------------
+
+
+// dry run:
+// X=SOUND_OUT; ./nltool -q -c run --progress -t 50 -n brdrline -l $X -i ./src/mame/audio/nl_brdrline.csv ./src/mame/audio/nl_brdrline.cpp && ./nlwav -f tab -i 0.001 -s 1 -n -1 log_$X.log | gnuplot -p -e "reset; plot '-' using 1 with lines"
+// X=SOUND_OUT; ./nltool -v -s -c run --progress -t 50 -n brdrline -l $X -i ./src/mame/audio/nl_brdrline.csv ./src/mame/audio/nl_brdrline.cpp | tee ./nl_brdrline.txt && ./nlwav -f tab -i 0.001 -s 1 -n -1 log_$X.log | gnuplot -p -e "reset; plot '-' using 1 with lines"
+//
+// X=SOUND_OUT; ./nlwav -f wav32f -a 0.5 -o ../$X.wav log_$X.log
+
+
+#include "netlist/devices/net_lib.h"
+
+#define ENABLE_FRONTIERS (1)
+
+
+/* ----------------------------------------------------------------------------
+ * Library section content START
+ * ---------------------------------------------------------------------------*/
+#if 0
+//
+// WARNING: fake implementation for MB4391 based on guesses only
+// MB4391_DIP
+// MB4391(A)
+// +--------------+
+// .1/*IN1*/ |1 ++ 16| .16/*VCC1*/
+// .2/*CON1*/ |2 15| .15/*OUT1*/
+// .3/*GND1*/ |3 14| .14/*RO1*/
+// |4 MB4391 13|
+// .5/*IN2*/ |5 12| .12/*VCC2*/
+// .6/*CON2*/ |6 11| .11/*OUT2*/
+// .7/*GND2*/ |7 10| .10/*RO2*/
+// |8 9|
+// +--------------+
+/*
+ * VCC -----+-----------+-------------- VCC
+ * | |
+ * +-+ |
+ * |R| |
+ * |1| 2|
+ * +-+ +-------+-+
+ * | 0| AFUNC |Q +----+
+ * IN -----+---+ +---|Rout|--- OUT
+ * | | fx | +----+
+ * +-+ +-+--+--+-+
+ * |R| 1| 4| 3|
+ * |2| | | |
+ * +-+ | | |
+ * | | | |
+ * GND -----+-----|--|--+-------------- GND
+ * | |
+ * CON -----------+ |
+ * |
+ * RO --------------+
+ *
+ */
+#endif
+static NETLIST_START(_MB4391)
+ // MB4391 (fake implementation)
+ // 2020 by beta-tester (https://github.com/beta-tester)
+ //
+ // values by guesses
+ // for brdrline schematics only
+ //
+ // Vmix = -(Vcon - 4.759384) / (4.759384 - 2.839579)
+ // Vmix2 = pow(Vmix, 2)
+ // Vout = Vin * Vmix2
+ //
+ // Vcon(max) = 4.759384
+ // Vcon(min) = 2.839584...2.839579 (@3.002360417e+01)(@3.152360417e+01)
+ //AFUNC(fx, 5, "(A1)")
+ //
+ //AFUNC(fx, 5, "min(1, max(0, -(A1 - 4.759384) / (4.759384 - 2.839579)))")
+ //AFUNC(fx, 5, "min(1, max(0, -(A1 - (A2-0.24)) / ((A2-0.24) - (A2/2+0.34))))")
+ //
+ // Vin(offset)=2.5 (VCC/2)
+ //AFUNC(fx, 5, "(A0)")
+ //AFUNC(fx, 5, "(A0-2.5)")
+ //AFUNC(fx, 5, "(A0-(A2/2))")
+ //
+ // vin * mix
+ //AFUNC(fx, 5, "(A0-(A2/2)) * (min(1, max(0, -(A1 - 4.759384) / (4.759384 - 2.839579))))")
+ //
+ // vin * pow(mix, 2)
+ AFUNC(fx, 5, "(A0-(A2/2)) * pow((min(1, max(0, -(A1 - 4.759384) / (4.759384 - 2.839579))), 2))")
+
+ RES(R1, RES_K(10))
+ RES(R2, RES_K(10))
+ NET_C(VCC, R1.1)
+ NET_C(IN, R1.2, R2.1)
+ NET_C(R2.2, GND)
+
+ RES(Rout, RES_K(1))
+ NET_C(fx.Q, Rout.1) // fx(IN, CON, VCC, GND, RO) = OUT
+
+ // INPUT
+ ALIAS(IN, fx.A0) // IN
+ ALIAS(CON, fx.A1) // CON
+ ALIAS(VCC, fx.A2) // VCC
+ ALIAS(GND, fx.A3) // GND
+ ALIAS(RO, fx.A4) // RO
+
+ // OUTPUT
+ ALIAS(OUT, Rout.2) // OUT
+NETLIST_END()
+
+
+static NETLIST_START(_MB4391_DIP)
+ SUBMODEL(_MB4391, A)
+ SUBMODEL(_MB4391, B)
+
+ NC_PIN(NC)
+
+ DIPPINS( /* +--------------+ */
+ A.IN, /* IN1 |1 ++ 16| VCC1 */ A.VCC,
+ A.CON, /* CON1 |2 15| OUT1 */ A.OUT,
+ A.GND, /* GND1 |3 14| RO1 */ A.RO,
+ NC.I, /* |4 MB4391 13| */ NC.I,
+ B.IN, /* IN2 |5 12| VCC2 */ B.VCC,
+ B.CON, /* CON2 |6 11| OUT2 */ B.OUT,
+ B.GND, /* GND2 |7 10| RO2 */ B.RO,
+ NC.I, /* |8 9| */ NC.I
+ /* +--------------+ */
+ )
+NETLIST_END()
+/* ----------------------------------------------------------------------------
+ * Library section content END
+ * ---------------------------------------------------------------------------*/
+
+
+
+
+/*
+ * hack
+ *
+ * terminates unused parts of a DIP
+ * WARNING: eats CPU time
+ *
+ * REQUIREMENT:
+ * - definition of a voltage splitter and a given alias UNUSED_OP_REF as
+ */
+#define UNUSED_TTL_Q(_name) HINT(_name, NC)
+#define UNUSED_TTL_I(_name) NET_C(_name, GND)
+#define UNUSED_OP_OUT_MINUS(_name_out, _name_minus) \
+ NET_C(_name_out, _name_minus)
+#define UNUSED_OP_PLUS(_name_plus) \
+ NET_C(UNUSED_OP_REF, _name_plus)
+
+/*
+ * hack
+ */
+#define NC_(_name) HINT(_name, NC)
+#define GND_(_name) NET_C(_name, GND)
+#define TMP_(_name) NET_C(_name, GND)
+
+/*
+ * hack
+ */
+// diode MA150 (nothing special, only for quick discharging caps)
+#define MA150(_name) \
+ DIODE(_name, "D")
+
+// npn transistor 2SC458
+#define C458(_name) \
+ QBJT_EB(_name, "NPN")
+
+// MB4391 one half of
+//#define MB4391(_name) NET_REGISTER_DEV_X(MB4391, _name)
+#define MB4391(_name) \
+ SUBMODEL(_MB4391, _name)
+
+// MB4391 full dip
+//#define MB4391_DIP(_name) NET_REGISTER_DEV_X(MB4391_DIP, _name)
+#define MB4391_DIP(_name) \
+ SUBMODEL(_MB4391_DIP, _name)
+
+
+
+
+// ---------------------------------------------------------------------------
+// Borderline
+// Owner's Manual
+// Sega/Gremlin, Manual Part No. 420-0613
+//
+// ...........................................................................
+// Page 26
+// Sound Board Assembly
+// Drawing No. 834-0055, Rev. A, Sheet 6 of 7
+// () = location in schematics
+// ...........................................................................
+// GUN_TRG (C8); GUN_SOUND (D6); (C8,D8,C7,D7,C6,D6)
+// JEEP_ON (C8); JEEP_SOUND (C6); (C8,B8,C7,B7,C6,B6)
+// POINT_TRG (A8); POINT_SOUND (B3); (A8,B8,A7,B7,A6,B6,A5,B5,C5,D5,A4,B4,C5,
+// D4,B3)
+// HIT_TRG (A8); HIT_SOUND (A4); (A8,A7,A6,A5,A4,B4,C4,D4,A3,B4,C3,D3)
+//
+// ...........................................................................
+// Page 27
+// Sound Board Assembly
+// Drawing No. 834-0055, Rev. A, Sheet 7 of 7
+// () = location in schematics
+// ...........................................................................
+// ANIMAL_TRG (D8); ANIMAL_SOUND (C6); (D8,C8,B8,A8,D7,C7,B7,A8,D6,C6,D5,C5)
+// EMAR_TRG (A8); EMAR_SOUND (C5); (A8,A7,B7,C6,B6,B5,C5,B4,C4,D4,D3)
+// WALK_TRG (A8); WALK_SOUND (B5); (A8,A7,A6,B6,B5)
+// CRY_TRG (A8); CRY_SOUND (C1); (A8,A7,A6,A5,A4,A3,B3,C3,A2,B2,C2,A1,
+// B1,C1)
+// ---------------------------------------------------------------------------
+static NETLIST_START(brdrline_schematics)
+
+ /* ------------------------------------------------------------------------
+ * UNUSED_OP_REF
+ * -----------------------------------------------------------------------*/
+ // UNUSED_OP_REF
+ POT(UNUSED_OP_RES, RES_K(20))
+ PARAM(UNUSED_OP_RES.DIAL, 0.5)
+ NET_C(V12, UNUSED_OP_RES.1)
+ NET_C(GND, UNUSED_OP_RES.3)
+ ALIAS(UNUSED_OP_REF, UNUSED_OP_RES.2)
+
+
+ /* ------------------------------------------------------------------------
+ * RST (RESET for sound)
+ * t(0s) = lo, t(2s) = high, t(infinite) = high
+ * -----------------------------------------------------------------------*/
+ RES(R171, RES_K(47))
+ CAP(C78, CAP_U(47))
+
+ TTL_74123_DIP(IC37) // shared by GUN_SOUND, RST
+ NET_C(GND, IC37.8/*GND*/)
+ NET_C(V5, IC37.16/*VCC*/)
+
+ NET_C(GND, IC37.9/*A2*/)
+ NET_C(V5, IC37.10/*B2*/, IC37.11/*CLRQ2*/, R171.1)
+ NET_C(IC37.6/*C2*/, C78.1)
+ NET_C(IC37.7/*RC2*/, C78.2, R171.2)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC37.5/*Q2*/)
+
+ // --------------------------------
+ // OUTPUT
+ ALIAS(RST, IC37.12/*QQ2*/)
+
+
+ /* ------------------------------------------------------------------------
+ * GUN_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(GUN_TRG, R156.2)
+
+ // --------------------------------
+ // TRG -> CON
+ MA150(D1)
+ RES(R156, RES_K(1))
+ RES(R155, RES_K(47))
+ RES(R89, 470)
+ RES(R90, RES_K(470))
+ RES(R91, RES_K(470))
+ CAP(C73, CAP_U(1))
+ CAP(C45, CAP_U(1))
+ NET_C(GND, C45.2)
+ NET_C(V5, IC37.2/*B1*/, IC37.3/*CLRQ1*/
+ , R156.1, R155.1, R91.1)
+ NET_C(R156.2, IC37.1/*A1*/)
+ NET_C(IC37.14/*C1*/, C73.1)
+ NET_C(IC37.15/*RC1*/, C73.2, R155.2)
+ NET_C(IC37.4/*QQ1*/, D1.K)
+ NET_C(D1.A, R89.1)
+ NET_C(R89.2, C45.1, R90.2)
+ NET_C(R91.2, R90.1, IC27.12/*PLUS4*/)
+ NET_C(IC27.14/*OUT4*/, IC27.13/*MINUS4*/, IC20.2/*CON1*/)
+
+ // --------------------------------
+ // NOISE
+ RES(R132, RES_K(220))
+ RES(R133, RES_K(22))
+ RES(R134, RES_K(15))
+ RES(R93, RES_K(15))
+ RES(R92, RES_K(150))
+ RES(R88, RES_K(100))
+ CAP(C62, CAP_U(2.2))
+ CAP(C63, CAP_U(0.01))
+ CAP(C48, CAP_U(0.01))
+
+ MM5837(IC26)
+ PARAM(IC26.FREQ, 24000)
+ NET_C(GND, IC26.VDD/*1*/, IC26.VGG/*2*/)
+ NET_C(V12, IC26.VSS/*4*/) // left out decoupling caps (0.1uF & 22uF parallel to GND)
+
+ LM324_DIP(IC27) // shared by GUN_SOUND, _, GUN_SOUND, GUN_SOUND
+ NET_C(GND, IC27.11/*GND*/)
+ NET_C(V12, IC27.4/*VCC*/)
+
+ NET_C(IC26.OUT/*3*/, C62.1)
+ NET_C(C62.2, R132.1)
+ NET_C(R132.2, IC27.2/*MINUS1*/, R133.1)
+ NET_C(IC27.3/*PLUS1*/, V6)
+ NET_C(IC27.1/*OUT1*/, R133.2, R134.1)
+ NET_C(R134.2, R93.1, C63.1)
+ NET_C(R93.2, C48.1, IC27.10/*PLUS3*/)
+ NET_C(C48.2, GND)
+ NET_C(IC27.8/*OUT3*/, C63.2, R92.1, C46.1)
+ NET_C(IC27.9/*MINUS3*/, R92.2, R88.1)
+ NET_C(R88.2, V6)
+
+ // --------------------------------
+ // CON, MIX -> OUT
+ MB4391_DIP(IC20) // shared by GUN_SOUND, CRY_SOUND
+ NET_C(GND, IC20.3/*GND1*/, IC20.7/*GND2*/)
+ NET_C(V5, IC20.16/*VCC1*/, IC20.12/*VCC2*/)
+ CAP(C46, CAP_U(2.2))
+ CAP(C25, CAP_U(2.2))
+ CAP(C26, CAP_P(680))
+ NET_C(C26.2, GND)
+ NET_C(IC20.14/*RO1*/, C26.1)
+ NET_C(IC20.1/*IN1*/, C46.2)
+ NET_C(IC20.15/*OUT1*/, C25.1)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC37.13/*Q1*/)
+
+ UNUSED_OP_OUT_MINUS(IC27.7/*OUT2*/, IC27.6/*MINUS2*/)
+ UNUSED_OP_PLUS(IC27.5/*PLUS2*/)
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(GUN_SOUND, C25.2)
+
+
+ /* ------------------------------------------------------------------------
+ * JEEP_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(JEEP_ON, R151.2)
+
+ // --------------------------------
+ TTL_7408_DIP(IC29) // shared by _, JEEP_SOUND, _, _
+ NET_C(GND, IC29.7/*GND*/)
+ NET_C(V5, IC29.14/*VCC*/)
+
+ TTL_7416_DIP(IC36) // shared by _, _, JEEP_SOUND, _, _, _
+ NET_C(GND, IC36.7/*GND*/)
+ NET_C(V5, IC36.14/*VCC*/)
+
+ TTL_7474_DIP(IC30)
+ NET_C(GND, IC30.7/*GND*/)
+ NET_C(V5, IC30.14/*VCC*/)
+
+ TTL_7474_DIP(IC32)
+ NET_C(GND, IC32.7/*GND*/)
+ NET_C(V5, IC32.14/*VCC*/)
+
+ NE555(IC31)
+ NET_C(GND, IC31.GND/*1*/)
+ NET_C(V5, IC31.VCC/*8*/)
+
+ RES(R123, RES_K(51))
+ RES(R150, RES_K(1))
+ RES(R151, RES_K(1))
+ RES(R152, RES_K(1))
+ RES(R153, RES_K(33))
+ RES(R154, RES_K(1))
+ RES(R157, RES_K(51))
+ RES(R158, RES_K(51))
+ CAP(C58, CAP_U(0.047))
+ CAP(C59, CAP_U(2.2))
+ CAP(C72, CAP_U(0.1))
+
+ NET_C(GND, C72.2, C58.2)
+ NET_C(V5, R150.1, R152.1, R154.1, R151.1
+ , IC30.1/*CLR1*/, IC30.4/*PR1*/, IC30.10/*PR2*/, IC30.13/*CLR2*/
+ , IC32.1/*CLR1*/, IC32.4/*PR1*/, IC32.10/*PR2*/, IC32.13/*CLR2*/
+ )
+ NET_C(IC36.5/*A3*/, R151.2)
+ NET_C(IC36.6/*Q3*/, R152.2
+ , IC31.RESET/*4*/
+ )
+ NET_C(IC31.DISCH/*7*/, R150.2, R153.1)
+ NET_C(IC31.THRESH/*6*/, IC31.TRIG/*2*/, R153.2, C72.1)
+ NET_C(IC31.OUT/*3*/, R154.2
+ , IC32.3/*CLK1*/, IC30.3/*CLK1*/, IC30.11/*CLK2*/
+ )
+ NET_C(IC32.6/*QQ1*/, R157.1
+ , IC32.2/*D1*/, IC32.11/*CLK2*/
+ )
+ NET_C(IC32.8/*QQ2*/, IC32.12/*D2*/, R158.1)
+ NET_C(IC29.6/*Q2*/, IC30.2/*D1*/)
+ NET_C(IC30.5/*Q1*/, IC30.12/*D2*/)
+ NET_C(IC30.6/*QQ1*/, IC29.4/*A2*/)
+ NET_C(IC30.8/*QQ2*/, IC29.5/*B2*/, R123.1)
+ NET_C(R123.2, R157.2, R158.2, C58.1, C59.1)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC30.9/*Q2*/)
+
+ NC_(IC31.CONT/*5*/)
+
+ NC_(IC32.5/*Q1*/)
+ NC_(IC32.9/*Q2*/)
+
+ UNUSED_TTL_I(IC29.1/*A1*/)
+ UNUSED_TTL_I(IC29.2/*B1*/)
+ UNUSED_TTL_Q(IC29.3/*Q1*/)
+ UNUSED_TTL_Q(IC29.8/*Q3*/)
+ UNUSED_TTL_I(IC29.9/*A3*/)
+ UNUSED_TTL_I(IC29.10/*B3*/)
+ UNUSED_TTL_Q(IC29.11/*Q4*/)
+ UNUSED_TTL_I(IC29.12/*A4*/)
+ UNUSED_TTL_I(IC29.13/*B4*/)
+
+ UNUSED_TTL_I(IC36.1/*A1*/)
+ UNUSED_TTL_Q(IC36.2/*Q1*/)
+ UNUSED_TTL_I(IC36.3/*A2*/)
+ UNUSED_TTL_Q(IC36.4/*Q2*/)
+ UNUSED_TTL_Q(IC36.8/*Q4*/)
+ UNUSED_TTL_I(IC36.9/*A4*/)
+ UNUSED_TTL_Q(IC36.10/*Q5*/)
+ UNUSED_TTL_I(IC36.11/*A5*/)
+ UNUSED_TTL_Q(IC36.12/*Q6*/)
+ UNUSED_TTL_I(IC36.13/*A6*/)
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(JEEP_SOUND, C59.2)
+
+
+ /* ------------------------------------------------------------------------
+ * POINT_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(POINT_TRG, R148.2)
+
+ // --------------------------------
+ // TRG -> CON
+ RES(R148, RES_K(1))
+ RES(R149, RES_K(47))
+ MA150(D5)
+ RES(R159, 470)
+ RES(R164, RES_K(470))
+ RES(R165, RES_K(470))
+ RES(R163, RES_K(27))
+ RES(R166, RES_K(12))
+ RES(R169, RES_K(30))
+ RES(R168, RES_K(10))
+ CAP(C71, CAP_U(1))
+ CAP(C74, CAP_U(1))
+ NET_C(R148.1, V5)
+ NET_C(IC35.9/*A2*/, R148.2)
+ NET_C(IC35.10/*B2*/, IC35.11/*CLRQ2*/, V5)
+ NET_C(IC35.6/*C2*/, C71.1)
+ NET_C(IC35.7/*RC2*/, C71.2, R149.2)
+ NET_C(R149.1, V5)
+ NET_C(IC35.12/*QQ2*/, D5.K)
+ NET_C(D5.A, R159.1)
+ NET_C(R159.2, C74.1, R165.2)
+ NET_C(C74.2, GND)
+ NET_C(IC38.12/*PLUS4*/, R165.1, R164.2)
+ NET_C(R164.1, V5)
+ NET_C(IC38.14/*OUT4*/, IC38.13/*MINUS4*/, R166.1)
+ NET_C(R163.1, V12)
+ NET_C(IC38.10/*PLUS3*/, R163.2, R168.1)
+ NET_C(R168.2, GND)
+ NET_C(IC38.9/*MINUS3*/, R166.2, R169.1)
+ NET_C(IC38.8/*OUT3*/, R169.2)
+
+ // --------------------------------
+ // UPPER STAGE -> MIX
+ RES(R79, RES_K(30))
+ RES(R80, RES_K(51))
+ RES(R81, RES_K(51))
+ RES(R78, RES_K(15))
+ RES(R32, RES_K(30))
+ RES(R33, RES_K(10))
+ CAP(C43, CAP_U(0.022))
+ C458(TR13)
+ NE555(IC18)
+ NET_C(GND, IC18.GND/*1*/)
+ NET_C(V5, IC18.VCC/*8*/)
+ LM324_DIP(IC25) // shared by ANIMAL_SOUND, POINT_SOUND, POINT_SOUND, POINT_SOUND
+ NET_C(GND, IC25.11/*GND*/)
+ NET_C(V12, IC25.4/*VCC*/)
+ NET_C(IC38.8/*OUT3*/, R79.1, R80.1)
+ NET_C(IC25.12/*PLUS4*/, R80.2, R81.1)
+ NET_C(R81.2, GND)
+ NET_C(IC25.13/*MINUS4*/, R79.2, C43.1, R78.1)
+ NET_C(IC18.RESET/*4*/, RST)
+ NET_C(R33.1, V5)
+ NET_C(IC18.DISCH/*7*/, R33.2)
+ NET_C(TR13.B, IC18.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR13.C, R78.2) // B & C swapped, wrong in schematics
+ NET_C(TR13.E, GND)
+ NET_C(IC25.14/*OUT4*/, IC18.TRIG/*2*/, IC18.THRESH/*6*/, C43.2, R32.1)
+
+ // --------------------------------
+ // MIDDLE STAGE -> UPPER STAGE
+ RES(R84, RES_K(30))
+ RES(R83, RES_K(51))
+ RES(R82, RES_K(51))
+ RES(R85, RES_K(15))
+ RES(R35, RES_K(30))
+ RES(R36, RES_K(10))
+ RES(R37, RES_K(2.2))
+ CAP(C44, CAP_P(6800))
+ C458(TR14)
+ NE555(IC19)
+ NET_C(GND, IC19.GND/*1*/)
+ NET_C(V5, IC19.VCC/*8*/)
+ NET_C(IC38.8/*OUT3*/, R83.1, R84.1)
+ NET_C(IC25.10/*PLUS3*/, R83.2, R82.1)
+ NET_C(R82.2, GND)
+ NET_C(IC25.9/*MINUS3*/, R84.2, C44.1, R85.1)
+ NET_C(IC19.RESET/*4*/, RST)
+ NET_C(R36.1, V5)
+ NET_C(IC19.DISCH/*7*/, R36.2)
+ NET_C(TR14.B, IC19.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR14.C, R85.2) // B & C swapped, wrong in schematics
+ NET_C(TR14.E, GND)
+ NET_C(IC25.8/*OUT3*/, IC19.TRIG/*2*/, IC19.THRESH/*6*/, C44.2, R35.2)
+ NET_C(R35.1, R32.2)
+ NET_C(R37.1, IC18.CONT/*5*/, IC19.CONT/*5*/)
+
+ // --------------------------------
+ // LOWER STAGE -> UPPER STAGE
+ RES(R130, RES_K(30))
+ RES(R129, RES_K(51))
+ RES(R128, RES_K(51))
+ RES(R131, RES_K(15))
+ RES(R34, RES_K(10))
+ CAP(C61, CAP_U(0.068))
+ CAP(C60, CAP_U(0.022))
+ CAP(C23, CAP_U(0.01))
+ C458(TR4)
+ NE555(IC8)
+ NET_C(GND, IC8.GND/*1*/)
+ NET_C(V5, IC8.VCC/*8*/)
+ NET_C(IC38.8/*OUT3*/, R130.1, R129.1)
+ NET_C(IC25.5/*PLUS2*/, R129.2, R128.1)
+ NET_C(R128.2, GND)
+ NET_C(IC25.6/*MINUS2*/, R130.2, C60.1, C61.1, R131.1)
+ NET_C(IC8.RESET/*4*/, RST)
+ NET_C(IC8.CONT/*5*/, C23.1)
+ NET_C(C23.2, GND)
+ NET_C(R34.1, V5)
+ NET_C(IC8.DISCH/*7*/, R34.2)
+ NET_C(TR4.B, IC8.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR4.C, R131.2) // B & C swapped, wrong in schematics
+ NET_C(TR4.E, GND)
+ NET_C(IC25.7/*OUT2*/, IC8.TRIG/*2*/, IC8.THRESH/*6*/, C61.2, C60.2, R37.2)
+
+ // --------------------------------
+ // CON, MIX -> OUT
+ CAP(C15, CAP_U(2.2))
+ CAP(C16, CAP_P(680))
+ CAP(C13, CAP_U(2.2))
+ NET_C(R32.2, C13.1)
+ NET_C(IC5.1/*IN1*/, C13.2)
+ NET_C(IC5.15/*OUT1*/, C15.1)
+ NET_C(IC5.14/*RO1*/, C16.1)
+ NET_C(C16.2, GND)
+ NET_C(IC38.14/*OUT4*/, IC5.2/*CON1*/)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC35.5/*Q2*/)
+
+ NET_C(IC8.OUT/*3*/, NC_IC8_OUT.1) // not connected in schematics
+ RES(NC_IC8_OUT, RES_M(1))
+ NET_C(NC_IC8_OUT.2, GND)
+ NET_C(IC18.OUT/*3*/, NC_IC18_OUT.1) // not connected in schematics
+ RES(NC_IC18_OUT, RES_M(1))
+ NET_C(NC_IC18_OUT.2, GND)
+ NET_C(IC19.OUT/*3*/, NC_IC19_OUT.1) // not connected in schematics
+ RES(NC_IC19_OUT, RES_M(1))
+ NET_C(NC_IC19_OUT.2, GND)
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(POINT_SOUND, C15.2)
+
+
+ /* ------------------------------------------------------------------------
+ * HIT_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(HIT_TRG, R147.1)
+
+ // --------------------------------
+ // TRG -> CON
+ TTL_74123_DIP(IC35) // shared by HIT_SOUND, POINT_SOUND
+ NET_C(GND, IC35.8/*GND*/)
+ NET_C(V5, IC35.16/*VCC*/)
+ RES(R147, RES_K(1))
+ RES(R146, RES_K(47))
+ RES(R160, 470)
+ RES(R161, RES_K(470))
+ RES(R162, RES_K(470))
+ CAP(C70, CAP_U(1))
+ CAP(C75, CAP_U(1))
+ MA150(D6)
+ NET_C(IC35.1/*A1*/, R147.1)
+ NET_C(R147.2, V5)
+ NET_C(IC35.2/*B1*/, IC35.3/*CLRQ1*/, V5)
+ NET_C(IC35.14/*C1*/, C70.1)
+ NET_C(IC35.15/*RC1*/, C70.2, R146.2)
+ NET_C(R146.1, V5)
+ NET_C(IC35.4/*QQ1*/, D6.K)
+ NET_C(D6.A, R160.1)
+ NET_C(R160.2, C75.1, R161.2)
+ NET_C(C75.2, GND)
+ NET_C(IC38.3/*PLUS1*/, R161.1, R162.2)
+ NET_C(R162.1, V5)
+ NET_C(IC38.1/*OUT1*/, IC38.2/*MINUS1*/)
+
+ // --------------------------------
+ // CON, MIX -> OUT
+ MB4391_DIP(IC5) // shared by POINT_SOUND, HIT_SOUND
+ NET_C(GND, IC5.3/*GND1*/, IC5.7/*GND2*/)
+ NET_C(V5, IC5.16/*VCC1*/, IC5.12/*VCC2*/)
+ CAP(C18, CAP_P(680))
+ NET_C(C18.1, IC5.10/*RO2*/)
+ NET_C(C18.2, GND)
+ CAP(C14, CAP_U(2.2))
+ CAP(C17, CAP_U(2.2))
+ NET_C(IC5.6/*CON2*/, IC38.1/*OUT1*/)
+ NET_C(IC5.11/*OUT2*/, C17.1)
+ NET_C(IC5.5/*IN2*/, C14.2)
+
+ // --------------------------------
+ // LOWER STAGE -> MIX
+ C458(TR11)
+ NE555(IC16)
+ NET_C(GND, IC16.GND/*1*/)
+ NET_C(V5, IC16.VCC/*8*/)
+ RES(R71, RES_K(51))
+ RES(R70, RES_K(30))
+ RES(R72, RES_K(51))
+ RES(R69, RES_K(15))
+ RES(R28, RES_K(10))
+ RES(R76, RES_K(1))
+ CAP(C39, CAP_U(0.01))
+ CAP(C40, CAP_U(0.0033))
+ NET_C(IC24.14/*OUT4*/, C14.1)
+ NET_C(IC24.7/*OUT2*/, R70.1, R71.1)
+ NET_C(IC24.12/*PLUS4*/, R71.2, R72.1)
+ NET_C(R72.2, GND)
+ NET_C(IC24.13/*MINUS4*/, R70.2, C39.1, C40.1, R69.1)
+ NET_C(IC24.14/*OUT4*/, IC16.TRIG/*2*/, IC16.THRESH/*6*/, C39.2, C40.2)
+ NET_C(IC16.RESET/*4*/, RST)
+ NET_C(IC16.CONT/*5*/, R76.2)
+ NET_C(R28.1, V5)
+ NET_C(TR11.B, IC16.DISCH/*7*/, R28.2) // B & C swapped, wrong in schematics
+ NET_C(TR11.C, R69.2) // B & C swapped, wrong in schematics
+ NET_C(TR11.E, GND)
+
+ NET_C(IC24.8/*OUT3*/, R76.1)
+
+ RES(R119, RES_K(10))
+ RES(R120, RES_K(39))
+ RES(R121, RES_K(47))
+ RES(R122, RES_K(15))
+
+ LM324_DIP(IC24) // shared by EMAR_SOUND, HIT_SOUND, HIT_SOUND, HIT_SOUND
+ NET_C(GND, IC24.11/*GND*/)
+ NET_C(V12, IC24.4/*VCC*/)
+
+ NET_C(V12, R120.1)
+ NET_C(R120.2, R119.1)
+ NET_C(IC24.5/*PLUS2*/, R120.2)
+ NET_C(R119.2, GND)
+ NET_C(IC24.6/*MINUS2*/, R122.2, R121.1)
+ NET_C(IC24.7/*OUT2*/, R121.2)
+
+ NET_C(IC24.8/*OUT3*/, R122.1)
+
+ // --------------------------------
+ // UPPER STAGE -> LOWER STAGE
+ C458(TR12)
+ NE555(IC17)
+ NET_C(GND, IC17.GND/*1*/)
+ NET_C(V5, IC17.VCC/*8*/)
+ RES(R75, RES_K(470))
+ RES(R74, RES_K(51))
+ RES(R73, RES_K(51))
+ RES(R77, RES_K(5.1))
+ RES(R30, RES_K(10))
+ CAP(C41, CAP_U(2.2))
+ CAP(C42, CAP_U(2.2))
+ CAP(C21, CAP_U(0.01))
+ NET_C(V6, R75.1, R74.1)
+ NET_C(C41.1, C42.1)
+ NET_C(IC24.9/*MINUS3*/, R75.2, R77.1, C41.2)
+ NET_C(IC24.10/*PLUS3*/, R74.2, R73.1)
+ NET_C(R73.2, GND)
+ NET_C(IC17.RESET/*4*/, RST)
+ NET_C(R30.1, V5)
+ NET_C(IC17.DISCH/*7*/, R30.2)
+ NET_C(IC17.CONT/*5*/, C21.1)
+ NET_C(C21.2, GND)
+ NET_C(TR12.B, IC17.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR12.C, R77.2) // B & C swapped, wrong in schematics
+ NET_C(TR12.E, GND)
+ NET_C(IC24.8/*OUT3*/, IC17.TRIG/*2*/, IC17.THRESH/*6*/, C42.2)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC35.13/*Q1*/)
+
+ NET_C(IC17.OUT/*3*/, NC_IC17_OUT.1) // not connected in schematics
+ RES(NC_IC17_OUT, RES_M(1))
+ NET_C(NC_IC17_OUT.2, GND)
+ NET_C(IC16.OUT/*3*/, NC_IC16_OUT.1) // not connected in schematics
+ RES(NC_IC16_OUT, RES_M(1))
+ NET_C(NC_IC16_OUT.2, GND)
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(HIT_SOUND, C17.2)
+
+
+ /* ------------------------------------------------------------------------
+ * ANIMAL_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(ANIMAL_TRG, R145.2)
+
+ // --------------------------------
+ // TGG -> TRG2 -> CON
+ RES(R145, RES_K(1))
+ RES(R143, RES_K(47))
+ RES(R144, RES_K(47))
+ RES(R106, 470)
+ RES(R108, RES_K(470))
+ RES(R107, RES_K(470))
+ CAP(C67, CAP_U(47))
+ CAP(C66, CAP_U(47))
+ CAP(C69, CAP_U(1))
+ CAP(C53, CAP_U(1))
+ MA150(D4)
+ TTL_74123_DIP(IC34) // shared by ANIMAL_SOUND, ANIMAL_SOUND
+ NET_C(GND, IC34.8/*GND*/)
+ NET_C(V5, IC34.16/*VCC*/)
+ NET_C(R145.1, V5)
+ NET_C(IC34.1/*A1*/, R145.2)
+ NET_C(IC34.2/*B1*/, IC34.3/*CLRQ1*/, V5)
+ NET_C(IC34.14/*C1*/, C67.2, C66.2)
+ NET_C(IC34.15/*RC1*/, C67.1, C66.1, R143.2)
+ NET_C(R143.1, V5)
+ NET_C(IC34.1/*A1*/, IC34.9/*A2*/)
+ NET_C(IC34.13/*Q1*/, IC34.10/*B2*/, IC34.11/*CLRQ2*/)
+ NET_C(IC34.6/*C2*/, C69.2)
+ NET_C(IC34.7/*RC2*/, C69.1, R144.2)
+ NET_C(R144.1, V5)
+ NET_C(IC34.12/*QQ2*/, D4.K)
+ NET_C(D4.A, R106.1)
+ NET_C(R106.2, C53.1, R107.2)
+ NET_C(C53.2, GND)
+ NET_C(IC23.3/*PLUS1*/, R107.1, R108.2)
+ NET_C(R108.1, V5)
+ NET_C(IC23.1/*OUT1*/, IC23.2/*MINUS1*/, IC4.6/*CON2*/)
+
+ // --------------------------------
+ C458(TR16)
+ RES(R110, RES_K(10))
+ NET_C(IC34.13/*Q1*/, R110.1)
+ NET_C(TR16.B, R110.2) // B & C swapped, wrong in schematics
+ NET_C(TR16.C, R109.2) // B & C swapped, wrong in schematics
+ NET_C(TR16.E, GND)
+
+ C458(TR15)
+ RES(R109, RES_K(1))
+ RES(R44, 220)
+ NET_C(R109.1, V5)
+ NET_C(TR15.B, R109.2) // B & C swapped, wrong in schematics
+ NET_C(TR15.C, C24.1) // B & C swapped, wrong in schematics
+ NET_C(TR15.E, R44.1)
+ NET_C(R44.2, C24.2)
+
+ // --------------------------------
+ // UPPER STAGE -> MIDDLE STAGE
+ RES(R39, RES_K(51))
+ RES(R38, RES_K(22))
+ RES(R15, RES_K(51))
+ RES(R41, RES_K(22))
+ RES(R42, RES_K(36))
+ RES(R43, RES_K(10))
+ RES(R40, RES_M(1))
+ CAP(C24, CAP_U(100))
+ LM324_DIP(IC9) // shared by ANIMAL_SOUND, ANIMAL_SOUND, ANIMAL_SOUND, ANIMAL_SOUND
+ NET_C(GND, IC9.11/*GND*/)
+ NET_C(V12, IC9.4/*VCC*/)
+ NET_C(R40.1, R39.1, V12)
+ NET_C(IC9.5/*PLUS2*/, R39.2, R15.1)
+ NET_C(R15.2, GND)
+ NET_C(IC9.6/*MINUS2*/, R40.2, C24.1)
+ NET_C(IC9.7/*OUT2*/, C24.2, R38.1)
+ NET_C(R42.1, V12)
+ NET_C(IC9.3/*PLUS1*/, R42.2, R43.1)
+ NET_C(R43.2, GND)
+ NET_C(IC9.2/*MINUS1*/, R38.2, R41.1)
+ NET_C(IC9.1/*OUT1*/, R41.2)
+
+ // --------------------------------
+ // MIDDLE STAGE -> MIX
+ RES(R11, RES_K(30))
+ RES(R12, RES_K(51))
+ RES(R13, RES_K(51))
+ RES(R10, RES_K(1))
+ RES(R9, RES_K(10))
+ RES(R14, RES_K(5.1))
+ RES(R16, RES_K(10))
+ CAP(C1, CAP_U(0.033))
+ C458(TR1)
+ NE555(IC1)
+ NET_C(GND, IC1.GND/*1*/)
+ NET_C(V5, IC1.VCC/*8*/)
+ NET_C(IC9.1/*OUT1*/, R11.1, R12.1)
+ NET_C(IC9.12/*PLUS4*/, R12.2, R13.1)
+ NET_C(R13.2, GND)
+ NET_C(IC9.13/*MINUS4*/, R11.2, C1.1, R10.1)
+ NET_C(IC1.RESET/*4*/, RST)
+ NET_C(IC1.DISCH/*7*/, R9.2)
+ NET_C(R9.1, V5)
+ NET_C(TR1.B, IC1.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR1.C, R10.2) // B & C swapped, wrong in schematics
+ NET_C(TR1.E, GND)
+ NET_C(IC9.14/*OUT4*/, IC1.TRIG/*2*/, IC1.THRESH/*6*/, C1.2)
+ NET_C(IC9.14/*OUT4*/, R16.1)
+ NET_C(IC1.CONT/*5*/, R14.1)
+
+ RES(R17, RES_K(5.1))
+ RES(R18, RES_K(3.3))
+ NET_C(IC9.8/*OUT3*/, IC9.9/*MINUS3*/, R14.2)
+ NET_C(IC9.10/*PLUS3*/, R17.2, R18.2)
+
+ // --------------------------------
+ // LOWER STAGE -> MIDDLE STAGE
+ RES(R59, RES_K(560))
+ RES(R58, RES_K(51))
+ RES(R57, RES_K(51))
+ RES(R60, RES_K(5.1))
+ RES(R23, RES_K(10))
+ CAP(C34, CAP_U(1))
+ CAP(C35, CAP_U(1))
+ CAP(C7, CAP_U(0.01))
+ C458(TR8)
+ NE555(IC13)
+ NET_C(GND, IC13.GND/*1*/)
+ NET_C(V5, IC13.VCC/*8*/)
+ NET_C(R59.1, R58.1, V6)
+ NET_C(IC22.10/*PLUS3*/, R58.2, R57.1)
+ NET_C(R57.2, GND)
+ NET_C(IC22.9/*MINUS3*/, R59.2, C34.2, R60.1)
+ NET_C(C34.1, C35.1)
+ NET_C(IC13.RESET/*4*/, RST)
+ NET_C(IC13.DISCH/*7*/, R23.2)
+ NET_C(R23.1, V5)
+ NET_C(IC13.CONT/*5*/, C7.1)
+ NET_C(C7.2, GND)
+ NET_C(TR8.B, IC13.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR8.C, R60.2) // B & C swapped, wrong in schematics
+ NET_C(TR8.E, GND)
+ NET_C(IC22.8/*OUT3*/, IC13.TRIG/*2*/, IC13.THRESH/*6*/, C35.2, R18.1)
+
+ // --------------------------------
+ // BOTTOM STAGE -> MIDDLE STAGE
+ RES(R127, RES_K(56))
+ RES(R125, RES_K(51))
+ RES(R124, RES_K(51))
+ RES(R126, RES_K(30))
+ RES(R31, RES_K(10))
+ CAP(C57, CAP_U(1))
+ CAP(C56, CAP_U(1))
+ CAP(C22, CAP_U(0.01))
+ C458(TR3)
+ NE555(IC7)
+ NET_C(GND, IC7.GND/*1*/)
+ NET_C(V5, IC7.VCC/*8*/)
+ NET_C(R127.1, R125.1, V6)
+ NET_C(IC25.3/*PLUS1*/, R125.2, R124.1)
+ NET_C(R124.2, GND)
+ NET_C(IC25.2/*MINUS1*/, R127.2, C57.2, R126.1)
+ NET_C(C57.1, C56.1)
+ NET_C(IC7.RESET/*4*/, RST)
+ NET_C(IC7.CONT/*5*/, C22.1)
+ NET_C(C22.2, GND)
+ NET_C(IC7.DISCH/*7*/, R31.2)
+ NET_C(R31.1, V5)
+ NET_C(TR3.B, IC7.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR3.C, R126.2) // B & C swapped, wrong in schematics
+ NET_C(TR3.E, GND)
+ NET_C(IC25.1/*OUT1*/, IC7.TRIG/*2*/, IC7.THRESH/*6*/, C56.2)
+ NET_C(IC25.1/*OUT1*/, R17.1)
+
+ // --------------------------------
+ // CON, MIX -> OUT
+ CAP(C6, CAP_U(2.2))
+ CAP(C11, CAP_U(2.2))
+ CAP(C12, CAP_P(680))
+ NET_C(IC4.10/*RO2*/, C12.1)
+ NET_C(C12.2, GND)
+ NET_C(R16.2, C6.1)
+ NET_C(IC4.5/*IN2*/, C6.2)
+ NET_C(IC4.11/*OUT2*/, C11.1)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC34.4/*QQ1*/)
+ NC_(IC34.5/*Q2*/)
+
+ NET_C(IC1.OUT/*3*/, NC_IC1_OUT.1) // not connected in schematics
+ RES(NC_IC1_OUT, RES_M(1))
+ NET_C(NC_IC1_OUT.2, GND)
+
+ NET_C(IC13.OUT/*3*/, NC_IC13_OUT.1) // not connected in schematics
+ RES(NC_IC13_OUT, RES_M(1))
+ NET_C(NC_IC13_OUT.2, GND)
+
+ NET_C(IC7.OUT/*3*/, NC_IC7_OUT.1) // not connected in schematics
+ RES(NC_IC7_OUT, RES_M(1))
+ NET_C(NC_IC7_OUT.2, GND)
+
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(ANIMAL_SOUND, C11.2)
+
+
+ /* ------------------------------------------------------------------------
+ * EMAR_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(EMAR_TRG, R142.2)
+
+ // --------------------------------
+ // TRG -> CON
+ RES(R142, RES_K(1))
+ RES(R141, RES_K(47))
+ MA150(D3)
+ RES(R103, 470)
+ RES(R105, RES_K(470))
+ RES(R104, RES_K(470))
+ CAP(C68, CAP_U(1))
+ CAP(C52, CAP_U(1))
+ NET_C(IC33.9/*A2*/, R142.2)
+ NET_C(R142.1, V5)
+ NET_C(IC33.10/*B2*/, IC33.11/*CLRQ2*/, V5)
+ NET_C(IC33.6/*C2*/, C68.1)
+ NET_C(IC33.7/*RC2*/, C68.2, R141.2)
+ NET_C(R141.1, V5)
+ NET_C(IC33.12/*QQ2*/, D3.K)
+ NET_C(D3.A, R103.1)
+ NET_C(R103.2, C52.1, R105.2)
+ NET_C(C52.2, GND)
+ NET_C(IC22.5/*PLUS2*/, R105.1, R104.2)
+ NET_C(R104.1, V5)
+ NET_C(IC22.7/*OUT2*/, IC22.6/*MINUS2*/)
+
+ // --------------------------------
+ // CON, MIX -> OUT
+ MB4391_DIP(IC4) // shared by EMAR_SOUND, ANIMAL_SOUND
+ NET_C(GND, IC4.3/*GND1*/, IC4.7/*GND2*/)
+ NET_C(V5, IC4.16/*VCC1*/, IC4.12/*VCC2*/)
+ RES(R24, RES_K(10))
+ CAP(C8, CAP_U(2.2))
+ CAP(C9, CAP_U(2.2))
+ CAP(C10, CAP_P(680))
+ NET_C(IC22.7/*OUT2*/, IC4.2/*CON1*/)
+ NET_C(IC4.14/*RO1*/, C10.1)
+ NET_C(C10.2, GND)
+ NET_C(IC4.15/*OUT1*/, C9.1)
+ NET_C(IC4.1/*IN1*/, C8.2)
+ NET_C(R24.2, C8.1)
+
+ LM324_DIP(IC23) // shared by ANIMAL_SOUND, EMAR_SOUND, EMAR_SOUND, EMAR_SOUND
+ NET_C(GND, IC23.11/*GND*/)
+ NET_C(V12, IC23.4/*VCC*/)
+
+ // --------------------------------
+ // LOWER STAGE -> UPPER STAGE
+ C458(TR2)
+ NE555(IC6)
+ NET_C(GND, IC6.GND/*1*/)
+ NET_C(V5, IC6.VCC/*8*/)
+ RES(R116, RES_K(470))
+ RES(R117, RES_K(51))
+ RES(R118, RES_K(51))
+ RES(R115, RES_K(51))
+ RES(R29, RES_K(10))
+ CAP(C55, CAP_U(3.3))
+ CAP(C54, CAP_U(3.3))
+ CAP(C20, CAP_U(0.01))
+ NET_C(R116.1, R117.1, V6)
+ NET_C(IC24.3/*PLUS1*/, R117.2, R118.1)
+ NET_C(R118.2, GND)
+ NET_C(IC24.2/*MINUS1*/, R116.2, C55.2, R115.1)
+ NET_C(C55.1, C54.1)
+ NET_C(IC6.RESET/*4*/, RST)
+ NET_C(IC6.CONT/*5*/, C20.1)
+ NET_C(C20.2, GND)
+ NET_C(IC6.DISCH/*7*/, R29.2)
+ NET_C(R29.1, V5)
+ NET_C(TR2.B, IC6.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR2.C, R115.2) // B & C swapped, wrong in schematics
+ NET_C(TR2.E, GND)
+ NET_C(IC24.1/*OUT1*/, IC6.TRIG/*2*/, IC6.THRESH/*6*/, C54.2)
+
+ NET_C(IC24.1/*OUT1*/, R113.1)
+ RES(R113, RES_K(22))
+ RES(R111, RES_K(27))
+ RES(R112, RES_K(10))
+ RES(R114, RES_K(22))
+ NET_C(R111.1, V12)
+ NET_C(IC23.5/*PLUS2*/, R111.2, R112.1)
+ NET_C(R112.2, GND)
+ NET_C(IC23.6/*MINUS2*/, R113.2, R114.1)
+ NET_C(IC23.7/*OUT2*/, R114.2)
+
+ // --------------------------------
+ // MIDDLE STAGE -> UPPER STAGE
+ C458(TR10)
+ NE555(IC15)
+ NET_C(GND, IC15.GND/*1*/)
+ NET_C(V5, IC15.VCC/*8*/)
+ RES(R67, RES_K(220))
+ RES(R66, RES_K(51))
+ RES(R65, RES_K(51))
+ RES(R68, RES_K(100))
+ RES(R27, RES_K(10))
+ RES(R26, RES_K(33))
+ CAP(C38, CAP_U(1))
+ CAP(C37, CAP_U(1))
+ CAP(C19, CAP_U(0.01))
+ NET_C(R67.1, R66.1, V6)
+ NET_C(IC23.10/*PLUS3*/, R66.2, R65.1)
+ NET_C(R65.2, GND)
+ NET_C(IC23.9/*MINUS3*/, R67.2, C37.2, R68.1)
+ NET_C(IC15.RESET/*4*/, RST)
+ NET_C(IC15.CONT/*5*/, C19.1)
+ NET_C(C19.2, GND)
+ NET_C(IC15.DISCH/*7*/, R27.2)
+ NET_C(R27.1, V5)
+ NET_C(TR10.B, IC15.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR10.C, R68.2) // B & C swapped, wrong in schematics
+ NET_C(TR10.E, GND)
+ NET_C(IC23.8/*OUT3*/, IC15.TRIG/*2*/, IC15.THRESH/*6*/, C38.2)
+ NET_C(C38.1, C37.1)
+ NET_C(IC15.OUT/*3*/, R26.2)
+
+ // --------------------------------
+ // UPPER STAGE -> MIX
+ C458(TR9)
+ NE555(IC14)
+ NET_C(GND, IC14.GND/*1*/)
+ NET_C(V5, IC14.VCC/*8*/)
+ RES(R62, RES_K(30))
+ RES(R63, RES_K(51))
+ RES(R64, RES_K(51))
+ RES(R61, RES_K(15))
+ RES(R25, RES_K(10))
+ CAP(C36, CAP_U(0.022))
+ CAP(C2, CAP_U(1)) // ? maybe 0.01uF
+ NET_C(IC23.7/*OUT2*/, R62.1, R63.1)
+ NET_C(IC23.12/*PLUS4*/, R63.2, R64.1)
+ NET_C(R64.2, GND)
+ NET_C(IC23.13/*MINUS4*/, R62.2, C36.1, R61.1)
+ NET_C(IC14.RESET/*4*/, RST)
+ NET_C(IC14.DISCH/*7*/, R25.2)
+ NET_C(R25.1, V5)
+ NET_C(IC14.CONT/*5*/, C2.1, R26.1)
+ NET_C(C2.2, GND)
+ NET_C(TR9.B, IC14.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR9.C, R61.2) // B & C swapped, wrong in schematics
+ NET_C(TR9.E, GND)
+ NET_C(IC23.14/*OUT4*/, IC14.TRIG/*2*/, IC14.THRESH/*6*/, C36.2)
+ NET_C(IC23.14/*OUT4*/, R24.1)
+
+ // --------------------------------
+ // UNUSED PINS
+ NC_(IC33.5/*Q2*/)
+
+ NET_C(IC6.OUT/*3*/, NC_IC6_OUT.1) // not connected in schematics
+ RES(NC_IC6_OUT, RES_M(1))
+ NET_C(NC_IC6_OUT.2, GND)
+ NET_C(IC14.OUT/*3*/, NC_IC14_OUT.1) // not connected in schematics
+ RES(NC_IC14_OUT, RES_M(1))
+ NET_C(NC_IC14_OUT.2, GND)
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(EMAR_SOUND, C9.2)
+
+
+ /* ------------------------------------------------------------------------
+ * WALK_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(WALK_TRG, R140.2)
+
+ // --------------------------------
+ NE555(IC28)
+ NET_C(GND, IC28.GND/*1*/)
+ NET_C(V5, IC28.VCC/*8*/)
+
+ LM324_DIP(IC21) // shared by CRY_SOUND, WALK_SOUND, CRY_SOUND, CRY_SOUND
+ NET_C(GND, IC21.11/*GND*/)
+ NET_C(V12, IC21.4/*VCC*/)
+
+ RES(R95, RES_K(100))
+ RES(R96, RES_K(22))
+ RES(R98, RES_K(27))
+ RES(R137, RES_K(22))
+ RES(R140, RES_K(1))
+ CAP(C3, CAP_U(2.2))
+ CAP(C50, CAP_U(0.1))
+ CAP(C51, CAP_U(2.2))
+ CAP(C65, CAP_U(0.01))
+ CAP(C77, CAP_U(2.2))
+
+ NET_C(GND, C65.2, C77.2, C50.2)
+ NET_C(V6, IC21.5/*PLUS2*/)
+ NET_C(V5, R140.1, R137.1)
+ NET_C(R140.2, IC28.TRIG/*2*/)
+ NET_C(C65.1, IC28.CONT/*5*/)
+ NET_C(IC28.THRESH/*6*/, IC28.DISCH/*7*/, R137.2, C77.1)
+ NET_C(IC28.OUT/*3*/ , R98.1)
+ NET_C(R98.2, C50.1, C51.1)
+ NET_C(C51.2, R96.1)
+ NET_C(R96.2, R95.1, IC21.6/*MINUS2*/)
+ NET_C(IC21.7/*OUT2*/, R95.2, C3.1)
+
+ // --------------------------------
+ // UNUSED PINS
+ NET_C(V5, IC28.RESET/*4*/) // not connected on schematic
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(WALK_SOUND, C3.2)
+
+
+ /* ------------------------------------------------------------------------
+ * CRY_SOUND
+ * -----------------------------------------------------------------------*/
+ // INPUT
+ NET_C(CRY_TRG, R139.2)
+
+ // --------------------------------
+ // TRG -> CON
+ TTL_74123_DIP(IC33) // shared by CRY_SOUND, EMAR_SOUND
+ NET_C(GND, IC33.8/*GND*/)
+ NET_C(V5, IC33.16/*VCC*/)
+ LM324_DIP(IC22) // shared by CRY_SOUND, EMAR_SOUND, ANIMAL_SOUND, CRY_SOUND
+ NET_C(GND, IC22.11/*GND*/)
+ NET_C(V12, IC22.4/*VCC*/)
+ MA150(D2)
+ RES(R139, RES_K(1))
+ RES(R138, RES_K(47))
+ RES(R97, 470)
+ RES(R87, RES_K(470))
+ RES(R94, RES_K(470))
+ CAP(C64, CAP_U(1))
+ NET_C(V5, R139.1, R138.1, R87.1)
+ NET_C(GND, C49.2)
+ NET_C(R139.2, IC33.1/*A1*/)
+ NET_C(V5, IC33.2/*B1*/, IC33.3/*CLRQ1*/)
+ NET_C(IC33.14/*C1*/, C64.1)
+ NET_C(IC33.15/*RC1*/, C64.2, R138.2)
+ NET_C(IC33.4/*QQ1*/, D2.K)
+ NC_(IC33.13/*Q1*/)
+ NET_C(D2.A, R97.1)
+ NET_C(R97.2, C49.1, R94.2)
+ NET_C(IC21.3/*PLUS1*/, R87.2, R94.1)
+ NET_C(IC21.1/*OUT1*/, IC21.2/*MINUS1*/, IC20.6/*CON2*/)
+
+ // --------------------------------
+ // CON, MIX -> OUT
+ RES(R86, RES_K(10))
+ CAP(C47, CAP_U(2.2))
+ CAP(C49, CAP_U(1))
+ CAP(C28, CAP_P(680))
+ CAP(C27, CAP_U(2.2))
+ NET_C(IC21.14/*OUT4*/, R86.1)
+ NET_C(R86.2, C47.1)
+ NET_C(IC20.5/*IN2*/, C47.2)
+ NET_C(IC20.10/*RO2*/, C28.1)
+ NET_C(C28.2, GND)
+ NET_C(IC20.11/*OUT2*/, C27.1)
+
+ // --------------------------------
+ // UPPER STAGE -> MIDDLE STAGE
+ C458(TR7)
+ NE555(IC12)
+ NET_C(GND, IC12.GND/*1*/)
+ NET_C(V5, IC12.VCC/*8*/)
+ NET_C(RST, IC12.RESET/*4*/)
+ RES(R22, RES_K(10))
+ RES(R55, RES_K(51))
+ RES(R54, RES_K(220))
+ RES(R56, RES_K(51))
+ RES(R53, RES_K(100))
+ CAP(C33, CAP_U(0.22))
+ CAP(C32, CAP_U(0.22))
+ CAP(C5, CAP_U(0.01))
+ NET_C(TR7.B, IC12.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR7.C, R53.2) // B & C swapped, wrong in schematics
+ NET_C(TR7.E, GND)
+ NET_C(V5, R22.1)
+ NET_C(IC12.DISCH/*7*/, R22.2)
+ NET_C(IC22.14/*OUT4*/, IC12.TRIG/*2*/, IC12.THRESH/*6*/)
+ NET_C(IC22.14/*OUT4*/, C32.2)
+ NET_C(C32.1, C33.1)
+ NET_C(IC22.13/*MINUS4*/, R53.1, R54.2, C33.2)
+ NET_C(IC22.12/*PLUS4*/, R55.2, R56.1)
+ NET_C(R56.2, GND)
+ NET_C(R54.1, R55.1, V6)
+ NET_C(IC12.CONT/*5*/, C5.1)
+ NET_C(C5.2, GND)
+
+ RES(R99, RES_K(22))
+ RES(R100, RES_K(100))
+ RES(R101, RES_K(15))
+ RES(R102, RES_K(33))
+ NET_C(IC22.14/*OUT4*/, R100.1)
+ NET_C(IC22.1/*OUT1*/, R102.2)
+ NET_C(IC22.2/*MINUS1*/, R100.2, R102.1)
+ NET_C(IC22.3/*PLUS1*/, R99.2, R101.1)
+ NET_C(R99.1, V12)
+ NET_C(R101.2, GND)
+
+ // --------------------------------
+ // LOWER STAGE -> MIDDLE STAGE
+ C458(TR6)
+ NE555(IC11)
+ NET_C(GND, IC11.GND/*1*/)
+ NET_C(V5, IC11.VCC/*8*/)
+ NET_C(RST, IC11.RESET/*4*/)
+ RES(R21, RES_K(10))
+ RES(R49, RES_K(51))
+ RES(R50, RES_K(51))
+ RES(R51, RES_K(470))
+ RES(R52, RES_K(5.1))
+ CAP(C30, CAP_U(2.2))
+ CAP(C31, CAP_U(2.2))
+ CAP(C4, CAP_U(0.01))
+ NET_C(TR6.B, IC11.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR6.C, R52.2) // B & C swapped, wrong in schematics
+ NET_C(TR6.E, GND)
+ NET_C(V5, R21.1)
+ NET_C(IC11.DISCH/*7*/, R21.2)
+ NET_C(IC21.8/*OUT3*/, IC11.TRIG/*2*/, IC11.THRESH/*6*/)
+ NET_C(IC21.9/*MINUS3*/, R52.1, R51.2, C30.2)
+ NET_C(C30.1, C31.1)
+ NET_C(IC21.8/*OUT3*/, C31.2)
+ NET_C(IC21.10/*PLUS3*/, R50.2, R49.1)
+ NET_C(R49.2, GND)
+ NET_C(V6, R51.1, R50.1)
+ NET_C(IC11.CONT/*5*/, C4.1)
+ NET_C(C4.2, GND)
+ NET_C(IC21.8/*OUT3*/, R20.1)
+ NET_C(IC10.CONT/*5*/, R20.2)
+
+ // --------------------------------
+ // MIDDLE STAGE -> MIX
+ C458(TR5)
+ NE555(IC10)
+ NET_C(GND, IC10.GND/*1*/)
+ NET_C(V5, IC10.VCC/*8*/)
+ NET_C(RST, IC10.RESET/*4*/)
+ RES(R19, RES_K(10))
+ RES(R45, RES_K(15))
+ RES(R46, RES_K(30))
+ RES(R47, RES_K(51))
+ RES(R48, RES_K(51))
+ CAP(C29, CAP_U(0.022))
+ RES(R20, RES_K(1))
+
+ NET_C(TR5.B, IC10.DISCH/*7*/) // B & C swapped, wrong in schematics
+ NET_C(TR5.C, R45.2) // B & C swapped, wrong in schematics
+ NET_C(TR5.E, GND)
+ NET_C(V5, R19.1)
+ NET_C(IC10.DISCH/*7*/, R19.2)
+ NET_C(IC21.14/*OUT4*/, IC10.TRIG/*2*/, IC10.THRESH/*6*/)
+ NET_C(IC21.13/*MINUS4*/, R45.1, R46.2, C29.1)
+ NET_C(IC21.12/*PLUS4*/, R47.2, R48.1)
+ NET_C(R48.2, GND)
+ NET_C(IC22.1/*OUT1*/, R46.1, R47.1)
+ NET_C(IC21.14/*OUT4*/, C29.2)
+
+ // --------------------------------
+ // UNUSED PINS
+ NET_C(IC10.OUT/*3*/, NC_IC10_OUT.1) // not connected in schematics
+ RES(NC_IC10_OUT, RES_M(1))
+ NET_C(NC_IC10_OUT.2, GND)
+ NET_C(IC11.OUT/*3*/, NC_IC11_OUT.1) // not connected in schematics
+ RES(NC_IC11_OUT, RES_M(1))
+ NET_C(NC_IC11_OUT.2, GND)
+ NET_C(IC12.OUT/*3*/, NC_IC12_OUT.1) // not connected in schematics
+ RES(NC_IC12_OUT, RES_M(1))
+ NET_C(NC_IC12_OUT.2, GND)
+
+ // --------------------------------
+ // OUTPUT
+ NET_C(CRY_SOUND, C27.2)
+
+NETLIST_END()
+
+
+
+
+static NETLIST_START(brdrline_sound_out)
+ LM324_DIP(IC38) // shared by HIT_SOUND, SOUND_OUT, POINT_SOUND, POINT_SOUND
+ NET_C(GND, IC38.11/*GND*/)
+ NET_C(V12, IC38.4/*VCC*/)
+
+ POT(VR8, RES_K(200))
+ POT(VR1, RES_K(200))
+ POT(VR6, RES_K(200))
+ POT(VR7, RES_K(200))
+ POT(VR5, RES_K(500))
+ POT(VR4, RES_K(200))
+ POT(VR3, RES_K(200))
+ POT(VR2, RES_K(200))
+
+ PARAM(VR1.DIAL, 0.350) // GUN_SOUND
+ PARAM(VR8.DIAL, 0.000) // JEEP_SOUND
+ PARAM(VR6.DIAL, 0.985) // POINT_SOUND
+ PARAM(VR7.DIAL, 0.640) // HIT_SOUND
+ PARAM(VR5.DIAL, 0.960) // ANIMAL_SOUND
+ PARAM(VR4.DIAL, 0.900) // EMAR_SOUND
+ PARAM(VR3.DIAL, 0.000) // WALK_SOUND
+ PARAM(VR2.DIAL, 0.900) // CRY_SOUND
+
+ RES(R8, RES_K(22))
+ RES(R1, RES_K(22))
+ RES(R6, RES_K(22))
+ RES(R7, RES_K(22))
+ RES(R5, RES_K(22))
+ RES(R4, RES_K(22))
+ RES(R3, RES_K(22))
+ RES(R2, RES_K(22))
+ RES(R167, RES_K(10))
+
+ CAP(C76, CAP_U(10))
+
+ NET_C(VR8.1, VR8.2)
+ NET_C(VR1.1, VR1.2)
+ NET_C(VR6.1, VR6.2)
+ NET_C(VR7.1, VR7.2)
+ NET_C(VR5.1, VR5.2)
+ NET_C(VR4.1, VR4.2)
+ NET_C(VR3.1, VR3.2)
+ NET_C(VR2.1, VR2.2)
+
+ NET_C(VR8.3, R8.1)
+ NET_C(VR1.3, R1.1)
+ NET_C(VR6.3, R6.1)
+ NET_C(VR7.3, R7.1)
+ NET_C(VR5.3, R5.1)
+ NET_C(VR4.3, R4.1)
+ NET_C(VR3.3, R3.1)
+ NET_C(VR2.3, R2.1)
+
+ NET_C(R1.2, R2.2, R3.2, R4.2, R5.2, R6.2, R7.2, R8.2
+ , IC38.6/*MINUS2*/
+ , R167.1
+ )
+ NET_C(V6, IC38.5/*PLUS2*/)
+ NET_C(IC38.7/*OUT2*/, R167.2, C76.1)
+
+ // --------------------------------
+ // INPUT
+#if (ENABLE_FRONTIERS)
+ // using AFUNCs here tends to remove the DC bias, so add
+ // it back in manually
+ AFUNC(JEEP_F, 1, "5+A0")
+ ALIAS(JEEP_SOUND, JEEP_F.A0)
+ NET_C(JEEP_F.Q, VR8.1)
+
+ AFUNC(GUN_F, 1, "6+A0")
+ ALIAS(GUN_SOUND, GUN_F.A0)
+ NET_C(GUN_F.Q, VR1.1)
+
+ AFUNC(POINT_F, 1, "6+A0")
+ ALIAS(POINT_SOUND, POINT_F.A0)
+ NET_C(POINT_F.Q, VR6.1)
+
+ AFUNC(HIT_F, 1, "6+A0")
+ ALIAS(HIT_SOUND, HIT_F.A0)
+ NET_C(HIT_F.Q, VR7.1)
+
+ AFUNC(ANIMAL_F, 1, "6+A0")
+ ALIAS(ANIMAL_SOUND, ANIMAL_F.A0)
+ NET_C(ANIMAL_F.Q, VR5.1)
+
+ AFUNC(EMAR_F, 1, "6+A0")
+ ALIAS(EMAR_SOUND, EMAR_F.A0)
+ NET_C(EMAR_F.Q, VR4.1)
+
+ AFUNC(WALK_F, 1, "A0")
+ ALIAS(WALK_SOUND, WALK_F.A0)
+ NET_C(WALK_F.Q, VR3.1)
+
+ AFUNC(CRY_F, 1, "6+A0")
+ ALIAS(CRY_SOUND, CRY_F.A0)
+ NET_C(CRY_F.Q, VR2.1)
+#else
+ ALIAS(JEEP_SOUND, VR8.1)
+ ALIAS(GUN_SOUND, VR1.1)
+ ALIAS(POINT_SOUND, VR6.1)
+ ALIAS(HIT_SOUND, VR7.1)
+ ALIAS(ANIMAL_SOUND, VR5.1)
+ ALIAS(EMAR_SOUND, VR4.1)
+ ALIAS(WALK_SOUND, VR3.1)
+ ALIAS(CRY_SOUND, VR2.1)
+#endif
+
+ // --------------------------------
+ // OUTPUT
+ RES(Rsound, RES_K(1)) // dummy load
+ NET_C(C76.2, Rsound.1)
+ NET_C(GND, Rsound.2)
+#if 0
+ // for test only
+ AFUNC(CLIPPING, 1, "max(-0.11,min(0.11, A0))")
+ NET_C(C76.2, CLIPPING.A0)
+#else
+ ALIAS(SOUND_OUT, Rsound.1)
+#endif
+
+NETLIST_END()
+
+
+
+
+NETLIST_START(brdrline)
+
+#if 1
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 4e-5)
+#else
+ SOLVER(solver, 48000)
+#endif
+
+ LOCAL_SOURCE(_MB4391)
+ LOCAL_SOURCE(_MB4391_DIP)
+
+ LOCAL_SOURCE(brdrline_schematics)
+ LOCAL_SOURCE(brdrline_sound_out)
+
+ // --------------------------------
+ // VOLTAGE SOURCES
+ ANALOG_INPUT(V12, 12)
+ ANALOG_INPUT(V5, 5)
+ ANALOG_INPUT(V6, 6)
+
+ // --------------------------------
+ INCLUDE(brdrline_schematics)
+
+ // --------------------------------
+ TTL_INPUT(I_SOUND_0, 1) // active low
+ NET_C(GND, I_SOUND_0.GND)
+ NET_C(V5, I_SOUND_0.VCC)
+
+ TTL_INPUT(I_SOUND_1, 1) // active low
+ NET_C(GND, I_SOUND_1.GND)
+ NET_C(V5, I_SOUND_1.VCC)
+
+ TTL_INPUT(I_SOUND_2, 1) // active low
+ NET_C(GND, I_SOUND_2.GND)
+ NET_C(V5, I_SOUND_2.VCC)
+
+ TTL_INPUT(I_SOUND_3, 1) // active low
+ NET_C(GND, I_SOUND_3.GND)
+ NET_C(V5, I_SOUND_3.VCC)
+
+ TTL_INPUT(I_SOUND_4, 1) // active low
+ NET_C(GND, I_SOUND_4.GND)
+ NET_C(V5, I_SOUND_4.VCC)
+
+ TTL_INPUT(I_SOUND_5, 1) // active low
+ NET_C(GND, I_SOUND_5.GND)
+ NET_C(V5, I_SOUND_5.VCC)
+
+ TTL_INPUT(I_SOUND_6, 1) // active low
+ NET_C(GND, I_SOUND_6.GND)
+ NET_C(V5, I_SOUND_6.VCC)
+
+ TTL_INPUT(I_SOUND_7, 1) // active low
+ NET_C(GND, I_SOUND_7.GND)
+ NET_C(V5, I_SOUND_7.VCC)
+
+
+#if 1
+ // {---(A5)Logic Board---}{-(C1/2)Top-}{-Sound Board-}
+ // D0 -> LS374( 3- 2) -> 40 -> PNK -> 9 -> ANIMAL_TRG
+ // D1 -> LS374(18-19) -> 35 -> BRN -> 12 -> CRY_TRG
+ // D2 -> LS374( 4- 5) -> 33 -> ORN -> 11 -> WALK_TRG
+ // D3 -> LS374(17-16) -> 34 -> YEL -> 10 -> EMAR_TRG
+ // D4 -> LS374( 7- 6) -> 32 -> BLU -> 8 -> HIT_TRG
+ // D5 -> LS374(14-15) -> 31 -> GRY -> 7 -> POINT_TRG
+ // D6 -> LS374( 8- 9) -> 30 -> WHT -> 6 -> JEEP_ON
+ // D7 -> LS374(13-12) -> 29 -> GRN -> 5 -> GUN_TRG
+ ALIAS(GUN_TRG, I_SOUND_7.Q)
+ ALIAS(JEEP_ON, I_SOUND_6.Q)
+ ALIAS(POINT_TRG, I_SOUND_5.Q)
+ ALIAS(HIT_TRG, I_SOUND_4.Q)
+ ALIAS(ANIMAL_TRG, I_SOUND_0.Q)
+ ALIAS(EMAR_TRG, I_SOUND_3.Q)
+ ALIAS(WALK_TRG, I_SOUND_2.Q)
+ ALIAS(CRY_TRG, I_SOUND_1.Q)
+#else
+ /*
+ * 2020-10-06 by 'beta-tester'
+ * | | ||personal |personal |
+ * | | ||assignment |assignment |
+ * |brdrline |starrkr ||NL SOUND |plausibility |note
+ * ---+-------------------------+------------------++-------------+-------------+----
+ * D0 | |fire, jeep_field ||POINT_TRG.IN | |
+ * D1 |next_sector, hit_rocket2 |hit_animal ||HIT_TRG.IN |+ |
+ * D2 | |fire, next_sector ||WALK_TRG.IN | |
+ * D3 | |fire ||CRY_TRG.IN | |
+ * D4 |jeep_field | ||ANIMAL_TRG.IN|+++ |see note 1
+ * D5 |fire | ||GUN_TRG.IN |++ |
+ * D6 |jeep_path |jeep_path? ||JEEP_ON.IN |++ |
+ * D7 |hit_animal | ||EMAR_TRG.IN |+ |
+ *
+ * note 1: as far as i remember (from the early 1980'th) it was triggered more often while crawling through the field at sector2 & 3,
+ * issue in schematic/netlist?
+ * or trigger?
+ * or were the acrade what i played in the past a modified bootleg?
+ * or is it only in my head?
+ */
+ ALIAS(GUN_TRG, I_SOUND_5.Q)
+ ALIAS(JEEP_ON, I_SOUND_6.Q)
+ ALIAS(POINT_TRG, I_SOUND_0.Q)
+ ALIAS(HIT_TRG, I_SOUND_1.Q)
+ ALIAS(ANIMAL_TRG, I_SOUND_4.Q)
+ ALIAS(EMAR_TRG, I_SOUND_7.Q)
+ ALIAS(WALK_TRG, I_SOUND_2.Q)
+ ALIAS(CRY_TRG, I_SOUND_3.Q)
+#endif
+
+ // --------------------------------
+ INCLUDE(brdrline_sound_out)
+
+
+ // --------------------------------
+ ALIAS(OUTPUT, SOUND_OUT)
+
+NETLIST_END()
+
+
+
+
+#if 0
+~/mame/src/lib/netlist/devices/nld_ne555.cpp
+NE555()
+ * +--------------+
+ * .GND/*1*/ |1 ++ 8| .VCC/*8*/
+ * .TRIG/*2*/ |2 7| .DISCH/*7*/
+ * .OUT/*3*/ |3 6| .THRESH/*6*/
+ * .RESET/*4*/ |4 NE555 5| .CONT/*5*/
+ * +--------------+
+#endif
+
+#if 0
+~/mame/src/lib/netlist/devices/nld_74123.cpp
+TTL_74123_DIP()
+ * +--------------+
+ * .1/*A1*/ |1 ++ 16| .16/*VCC*/
+ * .2/*B1*/ |2 15| .15/*RC1*/
+ * .3/*CLRQ1*/ |3 14| .14/*C1*/
+ * .4/*QQ1*/ |4 74123 13| .13/*Q1*/
+ * .5/*Q2*/ |5 12| .12/*QQ2*/
+ * .6/*C2*/ |6 11| .11/*CLRQ2*/
+ * .7/*RC2*/ |7 10| .10/*B2*/
+ * .8/*GND*/ |8 9| .9/*A2*/
+ * +--------------+
+#endif
+
+#if 0
+~/mame/src/lib/netlist/macro/nlm_opamp_lib.cpp
+LM324_DIP()
+OPAMP(A, "LM324")
+ * +--------------+
+ * .1/*OUT1*/ |1 ++ 14| .14/*OUT4*/
+ * .2/*MINUS1*/ |2 13| .13/*MINUS4*/
+ * .3/*PLUS1*/ |3 12| .12/*PLUS4*/
+ * .4/*VCC*/ |4 11| .11/*GND*/
+ * .5/*PLUS2*/ |5 10| .10/*PLUS3*/
+ * .6/*MINUS2*/ |6 9| .9/*MINUS3*/
+ * .7/*OUT2*/ |7 LM324 8| .8/*OUT3*/
+ * +--------------+
+#endif
+
+#if 0
+WARNING: fake implementation for MB4391 based on guesses only
+MB4391_DIP
+MB4391(A)
+ * +--------------+
+ * .1/*IN1*/ |1 ++ 16| .16/*VCC1*/
+ * .2/*CON1*/ |2 15| .15/*OUT1*/
+ * .3/*GND1*/ |3 14| .14/*RO1*/
+ * |4 MB4391 13|
+ * .5/*IN2*/ |5 12| .12/*VCC2*/
+ * .6/*CON2*/ |6 11| .11/*OUT2*/
+ * .7/*GND2*/ |7 10| .10/*RO2*/
+ * |8 9|
+ * +--------------+
+#endif
+
+#if 0
+~/mame/src/lib/netlist/devices/nld_7474.cpp
+TTL_7474_DIP() - have to use pin numbers... why?
+ * +--------------+
+ * .1/*CLR1*/ |1 ++ 14| .14/*VCC*/
+ * .2/*D1*/ |2 13| .13/*CLR2*/
+ * .3/*CLK1*/ |3 12| .12/*D2*/
+ * .4/*PR1*/ |4 7474 11| .11/*CLK2*/
+ * .5/*Q1*/ |5 10| .10/*PR2*/
+ * .6/*QQ1*/ |6 9| .9/*Q2*/
+ * .7/*GND*/ |7 8| .8/*QQ2*/
+ * +--------------+
+#endif
+
+#if 0
+~/mame/src/lib/netlist/devices/nld_mm5837.cpp
+MM5837()
+ * +--------------+
+ * .VDD/*1*/ |1 ++ 8| .NC
+ * .VGG/*2*/ |2 7| .NC
+ * .OUT/*3*/ |3 6| .NC
+ * .VSS/*4*/ |4 MM5837 5| .NC
+ * +--------------+
+#endif
+
+#if 0
+~/mame/src/lib/netlist/macro/nlm_ttl74xx_lib.cpp
+TTL_7408_DIP()
+TTL_7408_AND(A)
+ * +--------------+
+ * .1/*A1*/ |1 ++ 14| .14/*VCC*/
+ * .2/*B1*/ |2 13| .13/*B4*/
+ * .3/*Q1*/ |3 12| .12/*A4*/
+ * .4/*A2*/ |4 7408 11| .11/*Q4*/
+ * .5/*B2*/ |5 10| .10/*B3*/
+ * .6/*Q2*/ |6 9| .9/*A3*/
+ * .7/*GND*/ |7 8| .8/*Q3*/
+ * +--------------+
+#endif
+
+#if 0
+TTL_7416_DIP()
+TTL_7416_GATE(A)
+ * +--------------+
+ * .1/*A1*/ |1 ++ 14| .14/*VCC*/
+ * .2/*Q1*/ |2 13| .13/*A6*/
+ * .3/*A2*/ |3 12| .12/*Q6*/
+ * .4/*Q2*/ |4 7416 11| .11/*A5*/
+ * .5/*A3*/ |5 10| .10/*Q5*/
+ * .6/*Q3*/ |6 9| .9/*A4*/
+ * .7/*GND*/ |7 8| .8/*Q4*/
+ * +--------------+
+#endif
+
diff --git a/src/mame/audio/nl_brdrline.h b/src/mame/audio/nl_brdrline.h
new file mode 100644
index 00000000000..66317699377
--- /dev/null
+++ b/src/mame/audio/nl_brdrline.h
@@ -0,0 +1,11 @@
+// license:CC0
+// copyright-holders: beta-tester (https://github.com/beta-tester)
+
+#ifndef MAME_AUDIO_NL_BRDRLINE_H
+#define MAME_AUDIO_NL_BRDRLINE_H
+
+#pragma once
+
+NETLIST_EXTERNAL(brdrline)
+
+#endif // MAME_AUDIO_NL_BRDRLINE_H
diff --git a/src/mame/audio/nl_frogs.cpp b/src/mame/audio/nl_frogs.cpp
new file mode 100644
index 00000000000..dc9ebe90a84
--- /dev/null
+++ b/src/mame/audio/nl_frogs.cpp
@@ -0,0 +1,567 @@
+// license:CC0
+// copyright-holders:Aaron Giles
+
+//
+// Netlist for Frogs
+//
+// Derived from the schematics in the Frogs manual.
+//
+// Known problems/issues:
+//
+// * Croak sound should have a little bit more tonality.
+//
+// * Performance work needed
+//
+
+#include "netlist/devices/net_lib.h"
+#include "nl_frogs.h"
+
+
+//
+// Optimizations
+//
+
+#define ENABLE_FRONTIERS (1)
+#define UNDERCLOCK_NOISE_GEN (1)
+
+
+
+//
+// Hacks
+//
+
+
+
+//
+// Main netlist
+//
+
+#define D_1N914(name) DIODE(name, "1N914")
+
+#define Q_2N4401(name) QBJT_EB(name, "2N4401")
+#define Q_2N4403(name) QBJT_EB(name, "2N4403")
+
+// JFET transistors not supported, but this should do the trick
+#define Q_2N4093(name) MOSFET(name, "NMOS(VTO=-1 CAPMOD=0)")
+
+#define LM741_DIP UA741_DIP8
+
+NETLIST_START(frogs)
+
+ SOLVER(Solver, 1000)
+ PARAM(Solver.DYNAMIC_TS, 1)
+ PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 4e-6)
+
+ TTL_INPUT(I_SOUND_0, 0)
+ TTL_INPUT(I_SOUND_1, 0)
+ TTL_INPUT(I_SOUND_2, 0)
+ TTL_INPUT(I_SOUND_3, 0)
+ TTL_INPUT(I_SOUND_4, 0)
+ TTL_INPUT(I_SOUND_5, 0)
+ TTL_INPUT(I_SOUND_6, 0)
+ TTL_INPUT(I_SOUND_7, 0)
+
+ NET_C(GND, I_SOUND_0.GND, I_SOUND_1.GND, I_SOUND_2.GND, I_SOUND_3.GND, I_SOUND_4.GND, I_SOUND_5.GND, I_SOUND_6.GND, I_SOUND_7.GND)
+ NET_C(I_V5, I_SOUND_0.VCC, I_SOUND_1.VCC, I_SOUND_2.VCC, I_SOUND_3.VCC, I_SOUND_4.VCC, I_SOUND_5.VCC, I_SOUND_6.VCC, I_SOUND_7.VCC)
+
+ ALIAS(I_HOP, I_SOUND_0)
+ ALIAS(I_JUMP, I_SOUND_1)
+ ALIAS(I_TONGUE, I_SOUND_2)
+ ALIAS(I_CAPTURE, I_SOUND_3)
+ ALIAS(I_FLY, I_SOUND_4)
+ ALIAS(I_SPLASH, I_SOUND_7)
+
+ ANALOG_INPUT(I_V5, 5)
+ ANALOG_INPUT(I_V12, 12)
+ ANALOG_INPUT(I_VM12, -12)
+
+ RES(R1, RES_K(3.3)) // SPLASH
+ RES(R2, RES_K(3.3)) // SPLASH
+ RES(R3, RES_K(3.3)) // CAPTURE
+ RES(R4, RES_K(3.3)) // CAPTURE
+ RES(R5, RES_K(3.3)) // TONGUE
+ RES(R6, RES_K(3.3)) // TONGUE
+ RES(R7, RES_K(3.3)) // HOP
+ RES(R8, RES_K(3.3)) // HOP
+ RES(R9, RES_K(3.3)) // JUMP
+ RES(R10, RES_K(3.3)) // JUMP
+ RES(R11, RES_K(3.3)) // FLY
+ RES(R12, RES_K(10)) // FLY
+ RES(R13, RES_K(10)) // SPLASH
+ RES(R14, RES_K(4.7)) // SPLASH
+ RES(R15, RES_K(100)) // SPLASH
+ RES(R16, RES_K(4.7)) // CAPTURE
+ RES(R17, RES_K(330)) // CAPTURE
+ RES(R18, RES_K(4.7)) // TONGUE
+ RES(R19, RES_K(100)) // TONGUE
+ RES(R20, RES_K(4.7)) // HOP
+ RES(R21, RES_K(3.3)) // HOP
+ RES(R22, RES_K(4.7)) // JUMP
+ RES(R23, RES_K(150)) // JUMP
+ RES(R24, RES_K(4.7)) // FLY
+ RES(R25, RES_K(22)) // SPLASH
+ RES(R26, 51) // HOP
+ RES(R27, RES_K(10)) // FLY
+ RES(R28, RES_K(22)) // TONGUE
+ RES(R29, RES_K(100)) // TONGUE
+ RES(R30, RES_K(470)) // HOP
+ RES(R31, 220) // HOP
+ RES(R32, RES_K(33)) // HOP (mislabelled R22)
+ RES(R33, 330) // JUMP
+ RES(R34, 820) // JUMP
+ RES(R35, RES_K(100)) // FLY
+ RES(R36, RES_K(2.2)) // FLY
+ RES(R37, RES_K(2.2)) // SPLASH
+ RES(R38, RES_K(10)) // SPLASH
+ RES(R39, RES_K(10)) // SPLASH
+ RES(R40, RES_K(68)) // CAPTURE
+ RES(R41, RES_K(4.7)) // CAPTURE
+ RES(R42, RES_K(1)) // TONGUE
+ RES(R43, RES_K(82)) // HOP
+ RES(R44, RES_K(3.3)) // FLY
+ RES(R45, RES_K(100)) // FLY
+ RES(R46, RES_K(3.3)) // FLY
+ POT(R47, RES_K(50)) // SPLASH
+ RES(R48, RES_K(47)) // CAPTURE
+ RES(R49, RES_K(3.3)) // CAPTURE
+ RES(R50, RES_K(100)) // CAPTURE
+ RES(R51, RES_K(39)) // TONGUE
+ RES(R52, 51) // HOP
+ RES(R53, RES_K(62))
+ RES(R54, 470) // JUMP
+ RES(R55, RES_K(22)) // JUMP
+ RES(R56, RES_M(2.2)) // JUMP
+ RES(R57, RES_K(22))
+ RES(R58, RES_K(22))
+ RES(R59, RES_K(3.3)) // FLY
+// RES(R60, RES_K(10)) -- final amp
+ RES(R61, RES_K(100)) // SPLASH
+ RES(R62, RES_K(47)) // SPLASH
+ RES(R63, RES_K(33)) // SPLASH
+ RES(R64, RES_K(820)) // CAPTURE
+ RES(R65, RES_K(150)) // CAPTURE
+ RES(R66, 51) // CAPTURE
+ RES(R67, 51) // CAPTURE
+ RES(R68, RES_K(1)) // JUMP
+ RES(R69, RES_K(82)) // JUMP
+ RES(R70, 51) // JUMP
+ RES(R71, RES_K(4.7)) // JUMP
+ RES(R72, RES_K(27)) // FLY
+ RES(R73, RES_K(10)) // FLY
+ RES(R74, RES_K(1)) // FLY
+ RES(R75, RES_K(10)) // JUMP
+ RES(R76, RES_K(10)) // JUMP
+ RES(R77, 560) // JUMP
+ RES(R78, RES_K(10)) // JUMP
+ RES(R79, RES_K(10)) // JUMP
+ RES(R80, RES_K(39)) // FLY
+ RES(R81, RES_K(100)) // FLY
+ RES(R82, RES_K(10)) // FLY
+ RES(R83, RES_K(100)) // JUMP
+ RES(R84, RES_K(1)) // JUMP
+ RES(R85, RES_K(10)) // JUMP
+ RES(R86, RES_K(1)) // FLY
+ RES(R87, RES_K(100)) // FLY
+ RES(R88, RES_K(82)) // FLY
+ RES(R90, RES_K(56)) // MIXER
+ POT(R91, RES_K(100))
+ POT(R92, RES_M(1))
+ POT(R93, RES_M(1))
+ POT(R94, RES_M(1))
+ POT(R95, RES_M(1))
+ POT(R96, RES_K(50))
+
+// CAP(C1, CAP_U(10))
+// CAP(C2, CAP_U(10))
+ CAP(C3, CAP_U(0.047))
+ CAP(C4, CAP_U(1))
+ CAP(C5, CAP_U(1))
+ CAP(C6, CAP_U(0.1))
+ CAP(C7, CAP_U(0.1))
+ CAP(C8, CAP_U(1))
+ CAP(C9, CAP_U(0.1))
+ CAP(C10, CAP_U(0.1))
+ CAP(C11, CAP_U(0.05))
+ CAP(C12, CAP_U(0.05))
+ CAP(C13, CAP_U(0.05))
+ CAP(C14, CAP_U(0.05))
+ CAP(C15, CAP_U(0.05))
+ CAP(C16, CAP_U(0.05))
+ CAP(C17, CAP_U(0.05))
+ CAP(C18, CAP_U(0.05))
+ CAP(C19, CAP_U(0.05))
+ CAP(C20, CAP_U(0.05))
+ CAP(C21, CAP_U(0.05))
+ CAP(C22, CAP_U(2.2))
+ CAP(C23, CAP_U(10))
+ CAP(C24, CAP_U(0.1))
+ CAP(C25, CAP_U(4.7))
+ CAP(C26, CAP_U(0.05))
+ CAP(C27, CAP_U(1))
+ CAP(C28, CAP_U(0.05))
+ CAP(C29, CAP_U(0.047))
+ CAP(C30, CAP_U(10))
+ CAP(C31, CAP_U(0.47))
+ CAP(C32, CAP_U(0.47))
+ CAP(C33, CAP_U(0.05))
+// CAP(C34, CAP_U(0.05)) -- final amp
+// CAP(C35, CAP_U(0.05)) -- final amp
+ CAP(C36, CAP_U(0.05))
+ CAP(C37, CAP_U(0.05))
+ CAP(C38, CAP_U(0.05))
+ CAP(C39, CAP_U(0.1))
+ CAP(C40, CAP_U(0.1))
+ CAP(C41, CAP_U(0.05))
+ CAP(C42, CAP_U(0.05))
+ CAP(C43, CAP_U(0.05))
+ CAP(C44, CAP_U(10))
+ CAP(C45, CAP_U(0.01))
+ CAP(C46, CAP_U(0.01))
+ CAP(C47, CAP_U(1))
+ CAP(C48, CAP_U(0.05))
+ CAP(C49, CAP_U(0.1))
+ CAP(C50, CAP_U(0.01))
+ CAP(C51, CAP_U(0.01))
+ CAP(C52, CAP_U(0.1))
+ CAP(C53, CAP_U(0.05))
+ CAP(C54, CAP_U(0.01))
+ CAP(C55, CAP_U(0.05))
+ CAP(C56, CAP_U(0.05))
+ CAP(C57, CAP_U(2.2))
+// CAP(C58, CAP_U(0.1)) -- final amp
+ CAP(C59, CAP_U(0.05))
+ CAP(C60, CAP_U(0.05))
+ CAP(C61, CAP_U(0.05))
+ CAP(C62, CAP_U(0.1))
+ CAP(C63, CAP_U(0.05))
+ CAP(C64, CAP_U(0.05))
+ CAP(C65, CAP_U(0.1))
+ CAP(C66, CAP_U(2.2))
+ CAP(C67, CAP_U(0.05))
+ CAP(C68, CAP_U(0.05))
+ CAP(C69, CAP_U(0.05))
+ CAP(C70, CAP_U(0.05))
+ CAP(C71, CAP_U(0.05))
+ CAP(C72, CAP_U(1))
+ CAP(C73, CAP_U(0.047))
+ CAP(C74, CAP_U(0.05))
+
+ D_1N914(D1)
+ D_1N914(D2)
+ D_1N914(D3)
+ D_1N914(D4)
+ D_1N914(D5)
+ D_1N914(D6)
+ D_1N914(D7)
+ D_1N914(D8)
+ D_1N914(D9)
+
+ Q_2N4401(Q1)
+ Q_2N4401(Q2)
+ Q_2N4401(Q3)
+ Q_2N4401(Q4)
+ Q_2N4401(Q5)
+ Q_2N4401(Q6)
+ Q_2N4401(Q7)
+ Q_2N4403(Q8)
+ Q_2N4403(Q9)
+ Q_2N4093(Q10)
+ Q_2N4401(Q11)
+ Q_2N4401(Q12)
+ Q_2N4403(Q13)
+ Q_2N4401(Q14)
+ Q_2N4403(Q15)
+ Q_2N4401(Q16)
+ Q_2N4403(Q17)
+ Q_2N4093(Q18)
+ Q_2N4401(Q19)
+ Q_2N4401(Q20)
+ Q_2N4401(Q21)
+
+ MM5837_DIP(U1) // Noise Generator
+#if (UNDERCLOCK_NOISE_GEN)
+ PARAM(U1.FREQ, 24000)
+#endif
+ NE555_DIP(U2) // Timer
+ NE555_DIP(U3) // Timer
+ NE555_DIP(U4) // Timer
+ NE555_DIP(U5) // Timer
+ NE555_DIP(U6) // Timer
+ NE555_DIP(U7) // Timer
+ LM741_DIP(U8) // Op. Amp.
+ NE555_DIP(U9) // Timer
+ LM741_DIP(U10) // Op. Amp.
+ LM741_DIP(U11) // Op. Amp.
+ NE555_DIP(U12) // Timer
+// LM741_DIP(U13) // Op. Amp. -- final amp
+ LM741_DIP(U14) // Op. Amp.
+ NE555_DIP(U15) // Timer
+ LM741_DIP(U16) // Op. Amp.
+ LM741_DIP(U17) // Op. Amp.
+ LM741_DIP(U18) // Op. Amp.
+ NE555_DIP(U19) // Timer
+ LM741_DIP(U20) // Op. Amp.
+
+ //
+ // JUMP
+ //
+
+ NET_C(I_V12, R22.2, U6.4, U6.8, C68.2, R23.2)
+ NET_C(GND, R10.1, Q2.E, C15.1, U6.1, C7.1, R34.1, U11.3, C71.1, C70.1, R54.1, Q19.B, D7.A, R84.1, R75.1, C64.1, R77.1, U19.1, C53.1, C52.1, U16.3)
+ NET_C(I_JUMP, R9.1)
+ NET_C(R9.2, R10.2, Q2.B)
+ NET_C(Q2.C, R22.1, U6.2)
+ NET_C(C15.2, U6.5)
+ NET_C(C68.1, GND)
+ NET_C(R23.1, U6.7, U6.6, C7.2)
+ NET_C(U6.3, C22.1, R33.1)
+ NET_C(R33.2, Q8.E)
+ NET_C(Q8.B, GND)
+ NET_C(Q8.C, C44.1, R57.1)
+ NET_C(C44.2, R70.1)
+ NET_C(R57.2, R58.2, Q16.B)
+ NET_C(Q16.E, R71.2)
+ NET_C(R71.1, R58.1, R70.2, I_VM12)
+ NET_C(R34.2, C22.2, C32.1, C31.1)
+ NET_C(C32.2, R56.1, U11.2)
+ NET_C(R56.2, C31.2, U11.6, R55.1)
+ NET_C(I_V12, C70.2, U11.7)
+ NET_C(I_VM12, U11.4, C71.2)
+ NET_C(R55.2, R54.2, Q21.B)
+ NET_C(Q21.E, D7.K, Q16.C)
+ NET_C(Q19.E, Q21.C, Q20.E)
+ NET_C(Q19.C, R76.1, R85.1, U20.2)
+ NET_C(I_V12, R76.2, R78.2)
+ NET_C(R78.1, Q20.C, U20.3, R75.2)
+ NET_C(Q20.B, R84.2, R83.1)
+ NET_C(R85.2, U20.6, R79.1)
+ NET_C(I_V12, U20.7, C63.2)
+ NET_C(C63.1, GND)
+ NET_C(I_VM12, U20.4, C64.2)
+ NET_C(R83.2, C62.1)
+ NET_C(R79.2, R77.2, C54.1, C51.1)
+ NET_C(C62.2, U19.3)
+ NET_C(I_V12, U19.4, C61.2, U19.8, R68.2)
+ NET_C(C61.1, GND)
+ NET_C(C53.2, U19.5)
+ NET_C(U19.2, U19.6, R69.1, C52.2)
+ NET_C(U19.7, R69.2, R68.1)
+ NET_C(C54.2, U16.2, R53.1)
+ NET_C(R53.2, U16.6, C51.2)
+ NET_C(I_V12, U16.7, C42.2)
+ NET_C(C42.1, GND)
+ NET_C(I_VM12, U16.4, C43.2)
+ NET_C(C43.1, GND)
+ ALIAS(BOING, U16.6)
+
+ //
+ // TONGUE
+ //
+
+ NET_C(I_V12, C20.2, R18.2, U4.4, U4.8, R19.2, Q11.C, R28.2, R42.2, U15.4, U15.8, C48.2)
+ NET_C(GND, R6.1, Q4.E, C13.1, U4.1, C5.2, R51.1, C49.1, U15.1, C41.1, C48.1)
+ NET_C(I_TONGUE, R5.1)
+ NET_C(R5.2, R6.2, Q4.B)
+ NET_C(C20.1, GND)
+ NET_C(Q4.C, R18.1, U4.2)
+ NET_C(C13.2, U4.5)
+ NET_C(C5.1, U4.7, U4.6, R19.1, R29.1)
+ RES(RU4, RES_K(100)) // netlist doesn't like unconnected
+ NET_C(RU4.1, U4.3) // 555 outputs, so run it through
+ NET_C(RU4.2, GND) // a 100k resistor to ground
+ NET_C(R29.2, Q11.B)
+ NET_C(Q11.E, Q12.B)
+ NET_C(Q12.E, R51.2)
+ NET_C(Q12.C, R28.1, Q13.B)
+ NET_C(Q13.E, R42.1)
+ NET_C(Q13.C, C49.2, U15.2, U15.6, U15.7, C50.1)
+ NET_C(U15.5, C41.2)
+ RES(RU15, RES_K(100)) // netlist doesn't like unconnected
+ NET_C(RU15.1, U15.3) // 555 outputs, so run it through
+ NET_C(RU15.2, GND) // a 100k resistor to ground
+ ALIAS(ZIP, C50.2)
+
+ //
+ // HOP
+ //
+
+ NET_C(I_V12, C69.2, R20.2, U5.4, U5.8, R21.2)
+ NET_C(GND, R8.1, Q3.E, C14.1, U5.1, C6.1, C30.2, Q9.B, R52.1, U10.3)
+ NET_C(I_HOP, R7.1)
+ NET_C(R7.2, R8.2, Q3.B)
+ NET_C(C69.1, GND)
+ NET_C(Q3.C, R20.1, U5.2)
+ NET_C(U5.5, C14.2)
+ NET_C(R21.1, U5.6, U5.7, C6.2)
+ NET_C(U5.3, D2.A, R31.1)
+ NET_C(D2.K, R32.2, C30.1)
+ NET_C(R32.1, Q9.E)
+ NET_C(Q9.C, C72.1, R43.2, Q10.G)
+ NET_C(C72.2, R26.2)
+ NET_C(I_VM12, R26.1, R43.1)
+ NET_C(R31.2, Q10.D, C29.1, C73.1)
+ NET_C(Q10.S, R52.2)
+ NET_C(C29.2, U10.2, R30.1)
+ NET_C(C73.2, R30.2, U10.6)
+ NET_C(I_V12, U10.7, C28.2)
+ NET_C(I_VM12, U10.4, C21.2)
+ NET_C(C21.1, GND)
+ NET_C(C28.1, GND)
+ ALIAS(HOP, U10.6)
+
+ //
+ // CAPTURE
+ //
+
+ NET_C(I_V12, R16.2, C18.2, U3.4, U3.8, R17.2, C74.2, U9.8, R41.2)
+ NET_C(GND, R4.1, Q5.E, C12.1, U3.1, C4.2, C19.1, U9.1, C27.2, R65.1, Q17.B, R66.1, U8.3, C18.1)
+ NET_C(I_CAPTURE, R3.1)
+ NET_C(R3.2, R4.2, Q5.B)
+ NET_C(Q5.C, R16.1, U3.2)
+ NET_C(U3.5, C12.2)
+ NET_C(R17.1, U3.6, U3.7, C4.1)
+ NET_C(U3.3, U9.4)
+ NET_C(C74.1, GND)
+ NET_C(C19.2, U9.5)
+ NET_C(R41.1, R48.2, D4.A, U9.7)
+ NET_C(U9.2, U9.6, R48.1, D4.K, C27.1)
+ NET_C(U9.3, R50.2, R49.1)
+ NET_C(R65.2, R64.2, C47.1, Q17.C, Q18.G)
+ NET_C(I_VM12, R64.1, R67.1)
+ NET_C(R67.2, C47.2)
+ NET_C(R50.1, Q17.E)
+ NET_C(R49.2, Q18.D, C39.1, C40.1)
+ NET_C(Q18.S, R66.2)
+ NET_C(C39.2, R40.1, U8.2)
+ NET_C(C40.2, R40.2, U8.6)
+ NET_C(I_V12, U8.7, C38.2)
+ NET_C(C38.1, GND)
+ NET_C(I_VM12, U8.4, C26.2)
+ NET_C(C26.1, GND)
+ ALIAS(CROAK, U8.6)
+
+ //
+ // SPLASH
+ //
+
+ NET_C(I_V12, R14.2, C17.2, U2.4, U2.8, R15.2, C25.1, R47.3, Q15.E, U1.4)
+ NET_C(GND, R2.1, Q6.E, C11.1, U2.1, C3.1, R38.1, Q14.E, U1.1, R62.1, R63.1, C37.1)
+ NET_C(I_SPLASH, R1.1)
+ NET_C(R1.2, R2.2, Q6.B)
+ NET_C(Q6.C, R14.1, U2.2)
+ NET_C(U2.5, C11.2)
+ NET_C(C17.1, GND)
+ NET_C(U2.6, U2.7, R15.1, C3.2)
+ NET_C(U2.3, R39.1)
+ NET_C(R39.2, R38.2, Q14.B)
+ NET_C(Q14.C, R37.1)
+ NET_C(R37.2, C25.2, R47.1, R25.1)
+ NET_C(R25.2, C10.1, R13.2, C9.1)
+ NET_C(Q15.C, C10.2)
+ NET_C(R13.1, D1.K)
+ NET_C(D1.A, D5.K)
+ NET_C(D5.A, U1.3)
+ NET_C(U1.2, I_VM12)
+ NET_C(C9.2, R63.2, U14.3)
+ NET_C(R62.2, U14.2, R61.1)
+ NET_C(R61.2, U14.6)
+ NET_C(I_V12, U14.7, C36.2)
+ NET_C(C36.1, GND)
+ NET_C(I_VM12, C37.2, U14.4)
+ ALIAS(SPLASH, U14.6)
+
+ //
+ // FLY
+ //
+
+ NET_C(I_V12, R12.2, R24.2, C67.2, U7.8, R35.2, C33.2, U12.8, R44.2, U17.7, C55.2, R87.2)
+ NET_C(GND, R11.1, C16.1, U7.1, C8.2, Q7.E, C23.2, U12.1, C24.1, R72.1, C56.1, R74.1, R88.1, C66.2, R86.1, U18.3, C60.1)
+ NET_C(I_FLY, Q1.E)
+ NET_C(R11.2, R12.1, Q1.B)
+ NET_C(Q1.C, R24.1, U7.2, U7.4, U12.4)
+ NET_C(C16.2, U7.5)
+ NET_C(C67.1, GND)
+ NET_C(R35.1, U7.6, U7.7, C8.1)
+ NET_C(U7.3, R27.1, D3.A)
+ NET_C(R27.2, Q7.B)
+ NET_C(Q7.C, R36.1)
+ NET_C(R36.2, C23.1, U12.5)
+ NET_C(C33.1, GND)
+ NET_C(U12.2, U12.6, D6.K, R45.1, C24.2)
+ NET_C(U12.7, D6.A, R45.2, R44.1)
+ NET_C(U12.3, C46.1)
+ NET_C(C46.2, C45.1, R59.1)
+ NET_C(C45.2, R72.2, U17.3)
+ NET_C(R59.2, U17.2, U17.6, C57.1)
+ NET_C(I_VM12, U17.4, C56.2)
+ NET_C(C55.1, GND)
+ NET_C(C57.2, R73.1)
+ NET_C(D3.K, R46.1)
+ NET_C(R46.2, R87.1, R80.2, R88.2, C66.1)
+ NET_C(R73.2, R74.2, D8.K)
+ NET_C(D8.A, R80.1, D9.A)
+ NET_C(D9.K, R86.2, C65.1)
+ NET_C(C65.2, R82.1)
+ NET_C(R82.2, U18.2, R81.1)
+ NET_C(R81.2, U18.6)
+ NET_C(I_V12, U18.7, C59.2)
+ NET_C(I_VM12, U18.4, C60.2)
+ NET_C(C59.1, GND)
+ ALIAS(BUZZZ, U18.6)
+
+ //
+ // Mixer
+ //
+
+#if (ENABLE_FRONTIERS)
+ AFUNC(BOING_F, 1, "A0")
+ NET_C(BOING, BOING_F.A0)
+ NET_C(BOING_F.Q, R95.1)
+
+ AFUNC(ZIP_F, 1, "A0")
+ NET_C(ZIP, ZIP_F.A0)
+ NET_C(ZIP_F.Q, R93.1)
+
+ AFUNC(HOP_F, 1, "A0")
+ NET_C(HOP, HOP_F.A0)
+ NET_C(HOP_F.Q, R94.1)
+
+ AFUNC(CROAK_F, 1, "A0")
+ NET_C(CROAK, CROAK_F.A0)
+ NET_C(CROAK_F.Q, R92.1)
+
+ AFUNC(SPLASH_F, 1, "A0")
+ NET_C(SPLASH, SPLASH_F.A0)
+ NET_C(SPLASH_F.Q, R91.1)
+
+ AFUNC(BUZZZ_F, 1, "A0")
+ NET_C(BUZZZ, BUZZZ_F.A0)
+ NET_C(BUZZZ_F.Q, R96.1)
+#else
+ NET_C(BOING, R95.1)
+ NET_C(ZIP, R93.1)
+ NET_C(HOP, R94.1)
+ NET_C(CROAK, R92.1)
+ NET_C(SPLASH, R91.1)
+ NET_C(BUZZZ, R96.1)
+#endif
+
+ NET_C(R95.3, R93.3, R94.3, R92.3, R91.3, R96.3, R90.1)
+ ALIAS(OUTPUT, R90.1)
+ NET_C(R90.2, GND)
+
+ //
+ // Unconnected inputs
+ //
+
+
+ //
+ // Unconnected outputs
+ //
+
+#if (ENABLE_FRONTIERS)
+#define RXX 192
+ OPTIMIZE_FRONTIER(BOING, RES_M(1), RXX)
+#endif
+
+NETLIST_END()
diff --git a/src/mame/audio/nl_frogs.h b/src/mame/audio/nl_frogs.h
new file mode 100644
index 00000000000..c1a2cedc56b
--- /dev/null
+++ b/src/mame/audio/nl_frogs.h
@@ -0,0 +1,10 @@
+// license:CC0
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_NL_FROGS_H
+#define MAME_AUDIO_NL_FROGS_H
+
+#pragma once
+
+NETLIST_EXTERNAL(frogs)
+
+#endif // MAME_AUDIO_NL_FROGS_H
diff --git a/src/mame/audio/nl_ripoff.cpp b/src/mame/audio/nl_ripoff.cpp
index 84ccfea212a..60e525cb615 100644
--- a/src/mame/audio/nl_ripoff.cpp
+++ b/src/mame/audio/nl_ripoff.cpp
@@ -239,9 +239,15 @@ NETLIST_START(ripoff)
Q_2N3906(Q5) // PNP
// Q_2N6292(Q6) // PNP -- part of final amp (not emulated)
// Q_2N6107(Q7) // PNP -- part of final amp (not emulated)
+#if !(HLE_LASER_VCO)
Q_2N3904(Q8) // NPN
+#endif
+#if !(HLE_TORPEDO_VCO)
Q_2N3904(Q9) // NPN
+#endif
+#if !(HLE_BACKGROUND_VCOS)
Q_2N3904(Q10) // NPN
+#endif
AMI_S2688(IC1) // Noise generator
diff --git a/src/mame/audio/nl_solarq.cpp b/src/mame/audio/nl_solarq.cpp
index be6ef4bca6f..ec7795e1cfa 100644
--- a/src/mame/audio/nl_solarq.cpp
+++ b/src/mame/audio/nl_solarq.cpp
@@ -298,7 +298,9 @@ NETLIST_START(solarq)
Q_2N3906(Q10) // PNP
Q_2N3906(Q11) // PNP
Q_2N3904(Q12) // NPN
+#if !(HLE_CAPTURE_VCO)
Q_2N3904(Q13) // NPN
+#endif
Q_2N3906(Q14) // PNP
Q_2N3906(Q15) // PNP
Q_2N3906(Q16) // PNP
diff --git a/src/mame/audio/nl_spacewar.cpp b/src/mame/audio/nl_spacewar.cpp
index 778906b31ad..1d1d9e7df40 100644
--- a/src/mame/audio/nl_spacewar.cpp
+++ b/src/mame/audio/nl_spacewar.cpp
@@ -128,11 +128,13 @@ NETLIST_START(spacewar)
D_1N914(CR5)
D_1N914(CR6)
+#if !(HLE_NOISE_GEN)
Q_2N3906(Q1) // PNP
Q_2N3904(Q2) // NPN
+#endif
Q_2N6426(Q3) // NPN Darlington
- Q_2N6292(Q4) // NPN
- Q_2N6107(Q5) // PNP
+// Q_2N6292(Q4) // NPN -- not used
+// Q_2N6107(Q5) // PNP -- not used
Q_2N6426(Q6) // NPN Darlington
Q_2N3904(Q7) // NPN
diff --git a/src/mame/audio/nl_starcas.cpp b/src/mame/audio/nl_starcas.cpp
index fd6dee8d968..1792217fd01 100644
--- a/src/mame/audio/nl_starcas.cpp
+++ b/src/mame/audio/nl_starcas.cpp
@@ -281,11 +281,15 @@ NETLIST_START(wotw)
D_1N914B(D9)
D_1N914B(D10)
+#if !(HLE_BACKGROUND_VCO)
Q_2N3904(Q1) // NPN
+#endif
Q_2N3904(Q2) // NPN
Q_2N3906(Q3) // PNP
Q_2N3904(Q4) // NPN
+#if !(HLE_LASER_VCO)
Q_2N3904(Q5) // NPN
+#endif
Q_2N3906(Q6) // PNP
Q_2N3906(Q7) // PNP
Q_2N3906(Q8) // PNP
diff --git a/src/mame/audio/nl_tailg.cpp b/src/mame/audio/nl_tailg.cpp
index fab4b88bf9c..63c01ae4cf7 100644
--- a/src/mame/audio/nl_tailg.cpp
+++ b/src/mame/audio/nl_tailg.cpp
@@ -204,8 +204,8 @@ NETLIST_START(tailg)
D_1N914(D8)
D_1N914(D9)
- Q_2N3904(Q1) // NPN
- Q_2N3904(Q2) // NPN
+// Q_2N3904(Q1) // NPN -- not used
+// Q_2N3904(Q2) // NPN -- not used
Q_2N3906(Q3) // PNP
Q_2N3906(Q4) // PNP
Q_2N3906(Q5) // PNP
diff --git a/src/mame/audio/nl_warrior.cpp b/src/mame/audio/nl_warrior.cpp
index d5403559420..cd439d0fff4 100644
--- a/src/mame/audio/nl_warrior.cpp
+++ b/src/mame/audio/nl_warrior.cpp
@@ -168,7 +168,9 @@ NETLIST_START(warrior)
Q_2N3906(Q2) // PNP
Q_2N3906(Q3) // PNP
Q_2N3906(Q4) // PNP
+#if !(HLE_PITFALL_VCO)
Q_2N3904(Q5) // NPN
+#endif
// Q_2N5878(Q6) // NPN -- part of final amp (not emulated)
// Q_2N5876(Q7) // PNP -- part of final amp (not emulated)
diff --git a/src/mame/audio/phoenix.cpp b/src/mame/audio/phoenix.cpp
index 7c43519c186..772f4bb889a 100644
--- a/src/mame/audio/phoenix.cpp
+++ b/src/mame/audio/phoenix.cpp
@@ -89,7 +89,7 @@ void phoenix_sound_device::device_start()
m_poly18[i] = bits;
}
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
save_item(NAME(m_sound_latch_a));
save_item(NAME(m_c24_state.counter));
@@ -101,7 +101,6 @@ void phoenix_sound_device::device_start()
save_item(NAME(m_noise_state.polyoffs));
save_item(NAME(m_noise_state.lowpass_counter));
save_item(NAME(m_noise_state.lowpass_polybit));
- save_pointer(NAME(m_poly18), (1ul << (18-5)));
}
int phoenix_sound_device::update_c24(int samplerate)
@@ -520,18 +519,18 @@ void phoenix_sound_device::control_b_w(uint8_t data)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void phoenix_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void phoenix_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int samplerate = machine().sample_rate();
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
+ int samplerate = buffer.sample_rate();
- while( samples-- > 0 )
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int sum = 0;
sum = noise(samplerate) / 2;
- *buffer++ = sum < 32768 ? sum > -32768 ? sum : -32768 : 32767;
+ buffer.put_int_clamp(sampindex, sum, 32768);
}
}
diff --git a/src/mame/audio/phoenix.h b/src/mame/audio/phoenix.h
index 6a02220c30e..30e6edfef10 100644
--- a/src/mame/audio/phoenix.h
+++ b/src/mame/audio/phoenix.h
@@ -22,7 +22,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct c_state
@@ -46,7 +46,7 @@ private:
struct n_state m_noise_state;
uint8_t m_sound_latch_a;
sound_stream * m_channel;
- std::unique_ptr<uint32_t[]> m_poly18;
+ std::unique_ptr<uint32_t[]> m_poly18;
required_device<discrete_device> m_discrete;
required_device<tms36xx_device> m_tms;
diff --git a/src/mame/audio/pleiads.cpp b/src/mame/audio/pleiads.cpp
index ee69320e7d6..965b445f67a 100644
--- a/src/mame/audio/pleiads.cpp
+++ b/src/mame/audio/pleiads.cpp
@@ -642,7 +642,7 @@ void pleiads_sound_device::common_start()
m_poly18[i] = bits;
}
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
save_item(NAME(m_sound_latch_a));
save_item(NAME(m_sound_latch_b));
@@ -691,27 +691,27 @@ void pleiads_sound_device::common_start()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void pleiads_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void pleiads_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int rate = machine().sample_rate();
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
+ int rate = buffer.sample_rate();
- while( samples-- > 0 )
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int sum = tone1(rate)/2 + tone23(rate)/2 + tone4(rate) + noise(rate);
- *buffer++ = sum < 32768 ? sum > -32768 ? sum : -32768 : 32767;
+ buffer.put_int_clamp(sampindex, sum, 32768);
}
}
-void naughtyb_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void naughtyb_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- pleiads_sound_device::sound_stream_update_legacy(stream, inputs, outputs, samples);
+ pleiads_sound_device::sound_stream_update(stream, inputs, outputs);
}
-void popflame_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void popflame_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- pleiads_sound_device::sound_stream_update_legacy(stream, inputs, outputs, samples);
+ pleiads_sound_device::sound_stream_update(stream, inputs, outputs);
}
diff --git a/src/mame/audio/pleiads.h b/src/mame/audio/pleiads.h
index 0c4ef99b4a9..9dd77f6e857 100644
--- a/src/mame/audio/pleiads.h
+++ b/src/mame/audio/pleiads.h
@@ -51,7 +51,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void common_start();
inline int tone1(int samplerate);
@@ -105,7 +105,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
};
@@ -119,7 +119,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
};
diff --git a/src/mame/audio/polepos.cpp b/src/mame/audio/polepos.cpp
index 48865d300e0..a1dd8bc24dc 100644
--- a/src/mame/audio/polepos.cpp
+++ b/src/mame/audio/polepos.cpp
@@ -225,7 +225,7 @@ polepos_sound_device::polepos_sound_device(const machine_config &mconfig, const
void polepos_sound_device::device_start()
{
- m_stream = stream_alloc_legacy(0, 1, OUTPUT_RATE);
+ m_stream = stream_alloc(0, 1, OUTPUT_RATE);
m_sample_msb = m_sample_lsb = 0;
m_sample_enable = 0;
@@ -251,21 +251,21 @@ void polepos_sound_device::device_reset()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void polepos_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void polepos_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
uint32_t step, clock, slot;
uint8_t *base;
double volume, i_total;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
int loop;
/* if we're not enabled, just fill with 0 */
if (!m_sample_enable)
{
- memset(buffer, 0, samples * sizeof(*buffer));
+ buffer.fill(0);
return;
}
@@ -279,7 +279,7 @@ void polepos_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
base = &machine().root_device().memregion("engine")->base()[slot * 0x800];
/* fill in the sample */
- while (samples--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
m_filter_engine[0].x0 = (3.4 / 255 * base[(m_current_position >> 12) & 0x7ff] - 2) * volume;
m_filter_engine[1].x0 = m_filter_engine[0].x0;
@@ -296,9 +296,9 @@ void polepos_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
i_total += m_filter_engine[loop].y0 / r_filt_out[loop];
}
- i_total *= r_filt_total * 32000/2; /* now contains voltage adjusted by final gain */
+ i_total *= r_filt_total/2; /* now contains voltage adjusted by final gain */
- *buffer++ = (int)i_total;
+ buffer.put(sampindex, i_total);
m_current_position += step;
}
}
diff --git a/src/mame/audio/polepos.h b/src/mame/audio/polepos.h
index 430078088b2..b8611218284 100644
--- a/src/mame/audio/polepos.h
+++ b/src/mame/audio/polepos.h
@@ -19,7 +19,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
public:
DECLARE_WRITE_LINE_MEMBER(clson_w);
diff --git a/src/mame/audio/redbaron.cpp b/src/mame/audio/redbaron.cpp
index c08036c7d3b..51586a809fd 100644
--- a/src/mame/audio/redbaron.cpp
+++ b/src/mame/audio/redbaron.cpp
@@ -102,19 +102,19 @@ void redbaron_sound_device::device_start()
m_vol_crash[i] = 32767 * r0 / (r0 + r1);
}
- m_channel = stream_alloc_legacy(0, 1, OUTPUT_RATE);
+ m_channel = stream_alloc(0, 1, OUTPUT_RATE);
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void redbaron_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void redbaron_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
- while( samples-- )
+ auto &buffer = outputs[0];
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int sum = 0;
@@ -214,7 +214,7 @@ void redbaron_sound_device::sound_stream_update_legacy(sound_stream &stream, str
if( m_squeal_out )
sum += 32767 * 40 / 100;
- *buffer++ = sum;
+ buffer.put_int(sampindex, sum, 32768);
}
}
diff --git a/src/mame/audio/redbaron.h b/src/mame/audio/redbaron.h
index a66b74dff21..71f072ff44f 100644
--- a/src/mame/audio/redbaron.h
+++ b/src/mame/audio/redbaron.h
@@ -21,7 +21,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
std::unique_ptr<int16_t[]> m_vol_lookup;
diff --git a/src/mame/audio/s11c_bg.cpp b/src/mame/audio/s11c_bg.cpp
index fef33ee26b9..33fd826e1b8 100644
--- a/src/mame/audio/s11c_bg.cpp
+++ b/src/mame/audio/s11c_bg.cpp
@@ -232,6 +232,8 @@ s11c_bg_device::s11c_bg_device(const machine_config &mconfig, const char *tag, d
, m_dac(*this, "dac")
, m_ym2151(*this, "ym2151")
, m_cvsd(*this, "hc55516")
+ , m_cvsd_filter(*this, "cvsd_filter")
+ , m_cvsd_filter2(*this, "cvsd_filter2")
, m_pia40(*this, "pia40")
, m_cpubank(*this, "bgbank")
, m_cb2_cb(*this)
@@ -248,6 +250,8 @@ s11c_bg_device::s11c_bg_device(const machine_config &mconfig, device_type type,
, m_dac(*this, "dac")
, m_ym2151(*this, "ym2151")
, m_cvsd(*this, "hc55516")
+ , m_cvsd_filter(*this, "cvsd_filter")
+ , m_cvsd_filter2(*this, "cvsd_filter2")
, m_pia40(*this, "pia40")
, m_cpubank(*this, "bgbank")
, m_cb2_cb(*this)
@@ -390,7 +394,18 @@ void s11c_bg_device::s11_bg_ym(machine_config &config)
// add a CVSD chip for boards which have it
void s11c_bg_device::s11_bg_cvsd(machine_config &config)
{
- HC55516(config, m_cvsd, 0);
+ // m_cvsd_filter is the first 'half' of U18(MC1458), with R32, R30, R29, no capacitor to ground(!?!) and C9, output feeding the second half
+ // m_cvsd_filter2 is the second 'half' of U18(MC1458), with R20, R15, R19, C10 and C7, output feeding the final mixer
+ // Note that the (intended 1800uf according to Sinistar/System 6) capacitor
+ // to ground for m_cvsd_filter is COMPLETELY MISSING, and hence this
+ // filter section behaves very oddly under simulation, retaining a
+ // gain but having a first-order falloff response!
+ // This was presumably a design error, and not intended, given the
+ // strange filter response. We emulate this weird circuit as it existed.
+ FILTER_BIQUAD(config, m_cvsd_filter2).opamp_mfb_lowpass_setup(RES_K(27), RES_K(15), RES_K(27), CAP_P(4700), CAP_P(1200));
+ FILTER_BIQUAD(config, m_cvsd_filter).opamp_mfb_lowpass_setup(RES_K(43), RES_K(36), RES_K(180), CAP_P(0), CAP_P(180)); // note the first capacitor is 0pf meaning it doesn't exist
+ m_cvsd_filter->add_route(ALL_OUTPUTS, m_cvsd_filter2, 1.0);
+ HC55516(config, m_cvsd, 0).add_route(ALL_OUTPUTS, m_cvsd_filter, 1.0/4.0); // to prevent massive clipping issues, we divide the signal by 4 here before going into the filters, then multiply it by 4 after it comes out the other end
}
@@ -405,11 +420,13 @@ void s11c_bg_device::device_add_mconfig(machine_config &config)
// 1/resistance * 57990 is 4.460769, 2.8895, 2.8895, 11.62124
// the sum of the previous 4 values is 21.88101; 100/21.88101 = 4.570173
// the 4 (1/r)*rtotal numbers * 4.570173 are 20.38649, 13.25122, 13.25122 and 53.11108 respectively
- // NOTE: audio passthrough from the mainboard is 4.7kohm
- m_dac->add_route(ALL_OUTPUTS, *this, 0.2038); // 13Kohm
- m_ym2151->add_route(1, *this, 0.1325); // 20kohm
- m_ym2151->add_route(0, *this, 0.1325); // 20kohm
- m_cvsd->add_route(ALL_OUTPUTS, *this, 0.5311); // 4.99kohm
+ // NOTE: Multiply all numbers here or the final output by 1/0.6395 = 1.5638 to get the relative
+ // volume values if there is no audio input used at all
+ // audio passthrough resistor from the mainboard input is 4.7kohm, 0.3605 in files sending audio into this device
+ m_dac->add_route(ALL_OUTPUTS, *this, 0.1304); // 13Kohm
+ m_ym2151->add_route(1, *this, 0.08473); // 20kohm
+ m_ym2151->add_route(0, *this, 0.08473); // 20kohm
+ m_cvsd_filter2->add_route(ALL_OUTPUTS, *this, 0.3396*4.0); // 4.99kohm
}
// D-11581 (without the W10/W11 jumpers)
@@ -423,11 +440,13 @@ void s11_bg_device::device_add_mconfig(machine_config &config)
// 1/resistance * 57990 is 4.9666, 3.129, 3.129, 6.2705
// the sum of the previous 4 values is 17.49521; 100/17.49521 = 5.715851
// the 4 (1/r)*rtotal numbers * 5.715851 are 28.38873, 17.8849, 17.8849, and 35.84148 respectively
- // NOTE: audio passthrough from the mainboard is 2.2kohm
- m_dac->add_route(ALL_OUTPUTS, *this, 0.2839); // 6.3Kohm
- m_ym2151->add_route(1, *this, 0.1788); // 10kohm
- m_ym2151->add_route(0, *this, 0.1788); // 10kohm
- m_cvsd->add_route(ALL_OUTPUTS, *this, 0.3584); // 4.99kohm
+ // NOTE: Multiply all numbers here or the final output by 1/0.5516 = 1.8129 to get the relative
+ // volume values correct if there is no audio input used at all
+ // NOTE: audio passthrough from the mainboard is 2.2kohm, 0.4484 in files sending audio into this device
+ m_dac->add_route(ALL_OUTPUTS, *this, 0.1566); // 6.3Kohm
+ m_ym2151->add_route(1, *this, 0.0987); // 10kohm
+ m_ym2151->add_route(0, *this, 0.0987); // 10kohm
+ m_cvsd_filter2->add_route(ALL_OUTPUTS, *this, 0.1977*4.0); // 4.99kohm
}
// D-11297 or D-11298
@@ -441,11 +460,13 @@ void s11_obg_device::device_add_mconfig(machine_config &config)
// 1/resistance * 40000 is 4.0, 4.0, 4.0, 4.0
// the sum of the previous 4 values is 16.0; 100/16 = 6.25
// the 4 (1/r)*rtotal numbers * 6.25 are 25.0, 25.0, 25.0, 25.0 respectively
- // NOTE: audio passthrough from the mainboard is 2.2kohm
- m_dac->add_route(ALL_OUTPUTS, *this, 0.25); // 10Kohm
- m_ym2151->add_route(1, *this, 0.25); // 10kohm
- m_ym2151->add_route(0, *this, 0.25); // 10kohm
- m_cvsd->add_route(ALL_OUTPUTS, *this, 0.25); // 10kohm
+ // NOTE: Multiply all numbers here or the final output by 1/0.468 = 2.1368 to get the relative
+ // volume values correct if there is no audio input used at all
+ // NOTE: audio passthrough from the mainboard is 2.2kohm, 0.5319 in files sending audio into this device
+ m_dac->add_route(ALL_OUTPUTS, *this, 0.1170); // 10Kohm
+ m_ym2151->add_route(1, *this, 0.1170); // 10kohm
+ m_ym2151->add_route(0, *this, 0.1170); // 10kohm
+ m_cvsd_filter2->add_route(ALL_OUTPUTS, *this, 0.1170*4.0); // 10kohm
}
// D-11197
@@ -459,10 +480,12 @@ void s11_bgm_device::device_add_mconfig(machine_config &config)
// 1/resistance * 40000 is 4.0, 4.0, 4.0, 4.0
// the sum of the previous 4 values is 16.0; 100/16 = 6.25
// the 4 (1/r)*rtotal numbers * 6.25 are 25.0, 25.0, 25.0, 25.0 respectively
- // NOTE: audio passthrough from the mainboard is 2.2kohm
- m_dac->add_route(ALL_OUTPUTS, *this, 0.25); // 10Kohm
- m_ym2151->add_route(1, *this, 0.25); // 10kohm
- m_ym2151->add_route(0, *this, 0.25); // 10kohm
+ // NOTE: Multiply all numbers here or the final output by 1/0.468 = 2.1368 to get the relative
+ // volume values correct if there is no audio input used at all
+ // NOTE: audio passthrough from the mainboard is 2.2kohm, 0.5319 in files sending audio into this device
+ m_dac->add_route(ALL_OUTPUTS, *this, 0.1170); // 10Kohm
+ m_ym2151->add_route(1, *this, 0.1170); // 10kohm
+ m_ym2151->add_route(0, *this, 0.1170); // 10kohm
// interestingly, there is no cvsd, but a fourth 10k resistor here, but it is tied to ground. this makes the board quieter than it would otherwise be, presumably.
}
@@ -473,8 +496,8 @@ void s11_bgs_device::device_add_mconfig(machine_config &config)
m_cpu->set_addrmap(AS_PROGRAM, &s11c_bg_device::s11c_bgs_map);
// volume mixer stuff
// the sum of all resistances is 10k + 10k = 20k
- // NOTE: audio passthrough from the mainboard is 10k
- m_dac->add_route(ALL_OUTPUTS, *this, 1.00); // 10Kohm
+ // NOTE: audio passthrough from the mainboard is 10k, 0.50 in files sending audio to this device
+ m_dac->add_route(ALL_OUTPUTS, *this, 0.50); // 10Kohm
}
void s11c_bg_device::device_start()
diff --git a/src/mame/audio/s11c_bg.h b/src/mame/audio/s11c_bg.h
index cab8d03defd..756b71c89f7 100644
--- a/src/mame/audio/s11c_bg.h
+++ b/src/mame/audio/s11c_bg.h
@@ -13,7 +13,9 @@
#include "cpu/m6809/m6809.h"
#include "machine/6821pia.h"
+#include "machine/rescap.h"
#include "sound/dac.h"
+#include "sound/flt_biquad.h"
#include "sound/hc55516.h"
#include "sound/ym2151.h"
@@ -63,6 +65,8 @@ protected:
required_device<mc1408_device> m_dac;
optional_device<ym2151_device> m_ym2151;
optional_device<hc55516_device> m_cvsd;
+ optional_device<filter_biquad_device> m_cvsd_filter;
+ optional_device<filter_biquad_device> m_cvsd_filter2;
required_device<pia6821_device> m_pia40;
required_memory_bank m_cpubank;
diff --git a/src/mame/audio/segag80r.cpp b/src/mame/audio/segag80r.cpp
index 90a8463cbad..4acd7c2104a 100644
--- a/src/mame/audio/segag80r.cpp
+++ b/src/mame/audio/segag80r.cpp
@@ -46,7 +46,7 @@ void sega005_sound_device::device_start()
segag80r_state *state = machine().driver_data<segag80r_state>();
/* create the stream */
- m_sega005_stream = stream_alloc_legacy(0, 1, SEGA005_COUNTER_FREQ);
+ m_sega005_stream = stream_alloc(0, 1, SEGA005_COUNTER_FREQ);
/* create a timer for the 555 */
m_sega005_sound_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sega005_sound_device::sega005_auto_timer), this));
@@ -57,17 +57,17 @@ void sega005_sound_device::device_start()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void sega005_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void sega005_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
segag80r_state *state = machine().driver_data<segag80r_state>();
const uint8_t *sound_prom = state->memregion("proms")->base();
int i;
/* no implementation yet */
- for (i = 0; i < samples; i++)
+ for (i = 0; i < outputs[0].samples(); i++)
{
if (!(state->m_sound_state[1] & 0x10) && (++state->m_square_count & 0xff) == 0)
{
@@ -78,7 +78,7 @@ void sega005_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
state->m_square_state += 2;
}
- outputs[0][i] = (state->m_square_state & 2) ? 0x7fff : 0x0000;
+ outputs[0].put(i, (state->m_square_state & 2) ? 1.0 : 0.0);
}
}
diff --git a/src/mame/audio/segausb.cpp b/src/mame/audio/segausb.cpp
index ef6343e945d..dc87b73ae8c 100644
--- a/src/mame/audio/segausb.cpp
+++ b/src/mame/audio/segausb.cpp
@@ -100,7 +100,7 @@ void usb_sound_device::device_start()
#else
- m_stream = stream_alloc_legacy(0, 1, USB_2MHZ_CLOCK);
+ m_stream = stream_alloc(0, 1, USB_2MHZ_CLOCK);
m_noise_shift = 0x15555;
@@ -451,15 +451,15 @@ void usb_sound_device::env_w(int which, u8 offset, u8 data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void usb_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void usb_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *dest = outputs[0];
+ auto &dest = outputs[0];
// iterate over samples
- while (samples--)
+ for (int sampindex = 0; sampindex < dest.samples(); sampindex++)
{
/*----------------
Noise Source
@@ -590,7 +590,7 @@ void usb_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_s
WEIGHT
*/
- *dest++ = 3000 * m_final_filter.step_cr(sample);
+ dest.put(sampindex, 0.1 * m_final_filter.step_cr(sample));
}
}
diff --git a/src/mame/audio/segausb.h b/src/mame/audio/segausb.h
index e34d892142d..e1e4a581782 100644
--- a/src/mame/audio/segausb.h
+++ b/src/mame/audio/segausb.h
@@ -62,7 +62,7 @@ protected:
#if (!ENABLE_SEGAUSB_NETLIST)
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
#endif
private:
diff --git a/src/mame/audio/seibu.cpp b/src/mame/audio/seibu.cpp
index 17075367960..57c6253fe9b 100644
--- a/src/mame/audio/seibu.cpp
+++ b/src/mame/audio/seibu.cpp
@@ -385,7 +385,7 @@ seibu_adpcm_device::seibu_adpcm_device(const machine_config &mconfig, const char
void seibu_adpcm_device::device_start()
{
m_playing = 0;
- m_stream = stream_alloc_legacy(0, 1, clock());
+ m_stream = stream_alloc(0, 1, clock());
m_adpcm.reset();
save_item(NAME(m_current));
@@ -443,14 +443,15 @@ void seibu_adpcm_device::ctl_w(u8 data)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void seibu_adpcm_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void seibu_adpcm_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *dest = outputs[0];
+ auto &dest = outputs[0];
- while (m_playing && samples > 0)
+ int sampindex;
+ for (sampindex = 0; m_playing && sampindex < dest.samples(); sampindex++)
{
int val = (m_base[m_current] >> m_nibble) & 15;
@@ -462,12 +463,7 @@ void seibu_adpcm_device::sound_stream_update_legacy(sound_stream &stream, stream
m_playing = 0;
}
- *dest++ = m_adpcm.clock(val) << 4;
- samples--;
- }
- while (samples > 0)
- {
- *dest++ = 0;
- samples--;
+ dest.put_int(sampindex, m_adpcm.clock(val), 32768 >> 4);
}
+ dest.fill(0, sampindex);
}
diff --git a/src/mame/audio/seibu.h b/src/mame/audio/seibu.h
index 9954b462205..1c53beb7746 100644
--- a/src/mame/audio/seibu.h
+++ b/src/mame/audio/seibu.h
@@ -145,7 +145,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// internal state
diff --git a/src/mame/audio/sente6vb.cpp b/src/mame/audio/sente6vb.cpp
index 22c9721a18a..de06af02feb 100644
--- a/src/mame/audio/sente6vb.cpp
+++ b/src/mame/audio/sente6vb.cpp
@@ -55,6 +55,7 @@
***************************************************************************/
#include "emu.h"
+#include "sound/mm5837.h"
#include "audio/sente6vb.h"
#include "cpu/z80/z80.h"
#include "machine/clock.h"
@@ -66,53 +67,6 @@
DEFINE_DEVICE_TYPE(SENTE6VB, sente6vb_device, "sente6vb", "Bally Sente 6VB Audio Board")
-/*************************************
-*
-* Trivial sound device to spew
-* a MM5837 noise stream to CEM3394
-* inputs
-*
-*************************************/
-
-DECLARE_DEVICE_TYPE(MM5837_NOISE_SOURCE, mm5837_noise_source)
-
-class mm5837_noise_source : public device_t, public device_sound_interface
-{
-public:
- mm5837_noise_source(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, MM5837_NOISE_SOURCE, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- m_stream(nullptr),
- m_noise_state(0x1ffff)
- {
- }
-
-protected:
- // device-level overrides
- virtual void device_start() override
- {
- m_stream = stream_alloc(0, 1, clock());
- save_item(NAME(m_noise_state));
- }
-
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override
- {
- for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
- {
- outputs[0].put(sampindex, BIT(m_noise_state, 0) ? 1.0 : 0.0);
- m_noise_state = (m_noise_state >> 1) | ((BIT(m_noise_state, 0) ^ BIT(m_noise_state, 3)) << 16);
- }
- }
-
-private:
- sound_stream *m_stream; // sound stream
- u32 m_noise_state; // noise state
-};
-
-DEFINE_DEVICE_TYPE(MM5837_NOISE_SOURCE, mm5837_noise_source, "mm5837noise", "MM5837")
-
-
/*************************************
*
@@ -172,7 +126,9 @@ void sente6vb_device::device_add_mconfig(machine_config &config)
SPEAKER(config, "mono").front_center();
- mm5837_noise_source &noise(MM5837_NOISE_SOURCE(config, "noise", 100000));
+ mm5837_stream_device &noise(MM5837_STREAM(config, "noise", 0));
+// noise.set_vdd(-6.5); // seems too low -- possible the mapping in mm5837 is wrong
+ noise.set_vdd(-8.0);
for (auto &cem_device : m_cem_device)
{
@@ -180,7 +136,7 @@ void sente6vb_device::device_add_mconfig(machine_config &config)
cem_device->set_vco_zero_freq(431.894);
cem_device->set_filter_zero_freq(1300.0);
cem_device->add_route(ALL_OUTPUTS, "mono", 0.90);
- noise.add_route(0, *cem_device, 1.0);
+ noise.add_route(0, *cem_device, 0.5);
}
}
diff --git a/src/mame/audio/snk6502.cpp b/src/mame/audio/snk6502.cpp
index 4d5550e08c3..0dc3b1868a5 100644
--- a/src/mame/audio/snk6502.cpp
+++ b/src/mame/audio/snk6502.cpp
@@ -165,7 +165,7 @@ void snk6502_sound_device::device_start()
// 38.99 Hz update (according to schematic)
set_music_clock(M_LN2 * (RES_K(18) * 2 + RES_K(1)) * CAP_U(1));
- m_tone_stream = stream_alloc_legacy(0, 1, SAMPLE_RATE);
+ m_tone_stream = stream_alloc(0, 1, SAMPLE_RATE);
for (int i = 0; i < NUM_CHANNELS; i++)
{
@@ -509,17 +509,17 @@ void snk6502_sound_device::speech_w(uint8_t data, const uint16_t *table, int sta
*/
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void snk6502_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void snk6502_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
for (int i = 0; i < NUM_CHANNELS; i++)
validate_tone_channel(i);
- while (samples-- > 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int32_t data = 0;
@@ -541,7 +541,7 @@ void snk6502_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
}
}
- *buffer++ = data;
+ buffer.put_int(sampindex, data, 3768);
m_tone_clock += FRAC_ONE;
if (m_tone_clock >= m_tone_clock_expire)
diff --git a/src/mame/audio/snk6502.h b/src/mame/audio/snk6502.h
index 99c0178120c..54474aa8207 100644
--- a/src/mame/audio/snk6502.h
+++ b/src/mame/audio/snk6502.h
@@ -40,7 +40,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
static constexpr unsigned NUM_CHANNELS = 3;
diff --git a/src/mame/audio/socrates.cpp b/src/mame/audio/socrates.cpp
index 4b49ec0b5bd..4f9731494eb 100644
--- a/src/mame/audio/socrates.cpp
+++ b/src/mame/audio/socrates.cpp
@@ -43,20 +43,20 @@ void socrates_snd_device::device_start()
m_DAC_output = 0x00; /* output */
m_state[0] = m_state[1] = m_state[2] = 0;
m_accum[0] = m_accum[1] = m_accum[2] = 0xFF;
- m_stream = stream_alloc_legacy(0, 1, clock() ? clock() : machine().sample_rate());
+ m_stream = stream_alloc(0, 1, clock() ? clock() : machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void socrates_snd_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void socrates_snd_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- for (int i = 0; i < samples; i++)
+ for (int i = 0; i < outputs[0].samples(); i++)
{
snd_clock();
- outputs[0][i] = ((int)m_DAC_output<<4);
+ outputs[0].put_int(i, (int)m_DAC_output, 32768 >> 4);
}
}
diff --git a/src/mame/audio/socrates.h b/src/mame/audio/socrates.h
index cd2d240079c..a75e5c1ca6f 100644
--- a/src/mame/audio/socrates.h
+++ b/src/mame/audio/socrates.h
@@ -22,7 +22,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void snd_clock();
static const uint8_t s_volumeLUT[];
diff --git a/src/mame/audio/special.cpp b/src/mame/audio/special.cpp
index 9a1383bfec0..40442b2cfb2 100644
--- a/src/mame/audio/special.cpp
+++ b/src/mame/audio/special.cpp
@@ -41,41 +41,24 @@ specimx_sound_device::specimx_sound_device(const machine_config &mconfig, const
void specimx_sound_device::device_start()
{
m_specimx_input[0] = m_specimx_input[1] = m_specimx_input[2] = 0;
- m_mixer_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_mixer_channel = stream_alloc(0, 1, machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void specimx_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void specimx_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int16_t channel_0_signal;
- int16_t channel_1_signal;
- int16_t channel_2_signal;
+ auto &sample_left = outputs[0];
- stream_sample_t *sample_left = outputs[0];
+ stream_buffer::sample_t channel_0_signal = m_specimx_input[0] ? 0.1 : -0.1;
+ stream_buffer::sample_t channel_1_signal = m_specimx_input[1] ? 0.1 : -0.1;
+ stream_buffer::sample_t channel_2_signal = m_specimx_input[2] ? 0.1 : -0.1;
+ stream_buffer::sample_t sum = channel_0_signal + channel_1_signal + channel_2_signal;
- channel_0_signal = m_specimx_input[0] ? 3000 : -3000;
- channel_1_signal = m_specimx_input[1] ? 3000 : -3000;
- channel_2_signal = m_specimx_input[2] ? 3000 : -3000;
-
- while (samples--)
- {
- *sample_left = 0;
-
- /* music channel 0 */
- *sample_left += channel_0_signal;
-
- /* music channel 1 */
- *sample_left += channel_1_signal;
-
- /* music channel 2 */
- *sample_left += channel_2_signal;
-
- sample_left++;
- }
+ sample_left.fill(sum);
}
diff --git a/src/mame/audio/special.h b/src/mame/audio/special.h
index daaa983a2d7..51dca82f12f 100644
--- a/src/mame/audio/special.h
+++ b/src/mame/audio/special.h
@@ -26,7 +26,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_mixer_channel;
diff --git a/src/mame/audio/svis_snd.cpp b/src/mame/audio/svis_snd.cpp
index 91fdd2dcce1..ed80d459821 100644
--- a/src/mame/audio/svis_snd.cpp
+++ b/src/mame/audio/svis_snd.cpp
@@ -45,22 +45,23 @@ void svision_sound_device::device_start()
memset(&m_noise, 0, sizeof(m_noise));
memset(m_channel, 0, sizeof(m_channel));
- m_mixer_channel = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_mixer_channel = stream_alloc(0, 2, machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void svision_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void svision_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *left=outputs[0], *right=outputs[1];
+ auto &left=outputs[0];
+ auto &right=outputs[1];
- for (int i = 0; i < samples; i++, left++, right++)
+ for (int i = 0; i < left.samples(); i++)
{
- *left = 0;
- *right = 0;
+ s32 lsum = 0;
+ s32 rsum = 0;
for (int j = 0; j < ARRAY_LENGTH(m_channel); j++)
{
CHANNEL &channel(m_channel[j]);
@@ -88,9 +89,9 @@ void svision_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
{
int16_t s = on ? channel.volume << 8 : 0;
if (j == 0)
- *right += s;
+ rsum += s;
else
- *left += s;
+ lsum += s;
}
}
channel.pos++;
@@ -103,9 +104,9 @@ void svision_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
int16_t s = (m_noise.value ? 1 << 8: 0) * m_noise.volume;
int b1, b2;
if (m_noise.left)
- *left += s;
+ lsum += s;
if (m_noise.right)
- *right += s;
+ rsum += s;
m_noise.pos += m_noise.step;
if (m_noise.pos >= 1.0)
{
@@ -146,9 +147,9 @@ void svision_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
s = (sample & 0xf0) >> 4;
s <<= 8;
if (m_dma.left)
- *left += s;
+ lsum += s;
if (m_dma.right)
- *right += s;
+ rsum += s;
m_dma.pos += m_dma.step;
if (m_dma.pos >= m_dma.size)
{
@@ -157,6 +158,8 @@ void svision_sound_device::sound_stream_update_legacy(sound_stream &stream, stre
m_irq_cb(1);
}
}
+ left.put_int(i, lsum, 32768);
+ right.put_int(i, rsum, 32768);
}
}
diff --git a/src/mame/audio/svis_snd.h b/src/mame/audio/svis_snd.h
index 9b7efad6353..d080976261b 100644
--- a/src/mame/audio/svis_snd.h
+++ b/src/mame/audio/svis_snd.h
@@ -41,7 +41,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct NOISE
diff --git a/src/mame/audio/tiamc1.cpp b/src/mame/audio/tiamc1.cpp
index d99de897c22..67049496ceb 100644
--- a/src/mame/audio/tiamc1.cpp
+++ b/src/mame/audio/tiamc1.cpp
@@ -77,7 +77,7 @@ void tiamc1_sound_device::device_start()
timer8253_reset(&m_timer0);
timer8253_reset(&m_timer1);
- m_channel = stream_alloc_legacy(0, 1, clock() / CLOCK_DIVIDER);
+ m_channel = stream_alloc(0, 1, clock() / CLOCK_DIVIDER);
m_timer1_divider = 0;
@@ -104,14 +104,14 @@ void tiamc1_sound_device::device_start()
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void tiamc1_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tiamc1_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int count, o0, o1, o2, len, orval = 0;
- len = samples * CLOCK_DIVIDER;
+ len = outputs[0].samples() * CLOCK_DIVIDER;
for (count = 0; count < len; count++)
{
@@ -140,7 +140,7 @@ void tiamc1_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
if ((count + 1) % CLOCK_DIVIDER == 0)
{
- outputs[0][count / CLOCK_DIVIDER] = orval ? 0x2828 : 0;
+ outputs[0].put(count / CLOCK_DIVIDER, orval ? 0.3 : 0.0);
orval = 0;
}
}
diff --git a/src/mame/audio/tiamc1.h b/src/mame/audio/tiamc1.h
index d8834816899..f469e8a40e0 100644
--- a/src/mame/audio/tiamc1.h
+++ b/src/mame/audio/tiamc1.h
@@ -25,7 +25,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct timer8253chan
diff --git a/src/mame/audio/timeplt.cpp b/src/mame/audio/timeplt.cpp
index 7fe94dd46c7..f626a8f98f9 100644
--- a/src/mame/audio/timeplt.cpp
+++ b/src/mame/audio/timeplt.cpp
@@ -34,7 +34,6 @@ locomotn_audio_device::locomotn_audio_device(const machine_config &mconfig, cons
timeplt_audio_device::timeplt_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
- , device_sound_interface(mconfig, *this)
, m_soundcpu(*this, "tpsound")
, m_soundlatch(*this, "soundlatch")
, m_filter_0(*this, "filter.0.%u", 0)
@@ -226,13 +225,3 @@ void locomotn_audio_device::device_add_mconfig(machine_config &config)
/* basic machine hardware */
m_soundcpu->set_addrmap(AS_PROGRAM, &locomotn_audio_device::locomotn_sound_map);
}
-
-//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
-//-------------------------------------------------
-
-void timeplt_audio_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update_legacy called; not applicable to legacy sound devices\n");
-}
diff --git a/src/mame/audio/timeplt.h b/src/mame/audio/timeplt.h
index 8e69d20caa1..b4e5b7c0677 100644
--- a/src/mame/audio/timeplt.h
+++ b/src/mame/audio/timeplt.h
@@ -10,7 +10,7 @@
#include "sound/ay8910.h"
#include "sound/flt_rc.h"
-class timeplt_audio_device : public device_t, public device_sound_interface
+class timeplt_audio_device : public device_t
{
public:
timeplt_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 14'318'181);
@@ -26,9 +26,6 @@ protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_start() override;
- // sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
-
void filter_w(offs_t offset, uint8_t data);
uint8_t portB_r();
diff --git a/src/mame/audio/trackfld.cpp b/src/mame/audio/trackfld.cpp
index bf139f858e9..9a8a863d551 100644
--- a/src/mame/audio/trackfld.cpp
+++ b/src/mame/audio/trackfld.cpp
@@ -15,7 +15,6 @@ DEFINE_DEVICE_TYPE(TRACKFLD_AUDIO, trackfld_audio_device, "trackfld_audio", "Tra
trackfld_audio_device::trackfld_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, TRACKFLD_AUDIO, tag, owner, clock)
- , device_sound_interface(mconfig, *this)
, m_audiocpu(*this, finder_base::DUMMY_TAG)
, m_vlm(*this, finder_base::DUMMY_TAG)
, m_last_addr(0)
@@ -130,13 +129,3 @@ WRITE_LINE_MEMBER(trackfld_audio_device::sh_irqtrigger_w)
m_last_irq = state;
}
-
-//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
-//-------------------------------------------------
-
-void trackfld_audio_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update_legacy called; not applicable to legacy sound devices\n");
-}
diff --git a/src/mame/audio/trackfld.h b/src/mame/audio/trackfld.h
index f1502443562..141916cec65 100644
--- a/src/mame/audio/trackfld.h
+++ b/src/mame/audio/trackfld.h
@@ -8,7 +8,7 @@
#include "sound/vlm5030.h"
#include "cpu/m6800/m6800.h"
-class trackfld_audio_device : public device_t, public device_sound_interface
+class trackfld_audio_device : public device_t
{
public:
template <typename T, typename U>
@@ -33,9 +33,6 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
- // sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
-
private:
optional_device<cpu_device> m_audiocpu;
optional_device<vlm5030_device> m_vlm;
diff --git a/src/mame/audio/tranqgun.cpp b/src/mame/audio/tranqgun.cpp
deleted file mode 100644
index afa28fe3591..00000000000
--- a/src/mame/audio/tranqgun.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Zsolt Vasvari, Jim Hernandez
-/*
- * Tranquillizer Gun audio routines
- */
-
-#include "emu.h"
-#include "includes/vicdual.h"
-
-/* output port 0x01 definitions - sound effect drive outputs */
-#define OUT_PORT_1_ANIMAL 0x01
-#define OUT_PORT_1_CRY 0x02
-#define OUT_PORT_1_WALK 0x04
-#define OUT_PORT_1_EMAR 0x08
-#define OUT_PORT_1_ANIMALHIT 0x10
-#define OUT_PORT_1_POINT 0x20
-#define OUT_PORT_1_JEEP 0x40
-#define OUT_PORT_1_GUN 0x80
-
-
-#define PLAY(samp,id,loop) samp->start( id, id, loop )
-#define STOP(samp,id) samp->stop( id )
-
-
-/* sample file names */
-static const char *const tranqgun_sample_names[] =
-{
- "*tranqgun",
- "cry",
- "walk",
- "emar",
- "animalhit",
- "point",
- "jeep",
- "gun",
- "animal",
- nullptr
-};
-
-
-/* sample IDs - must match sample file name table above */
-enum
-{
- SND_CRY = 0,
- SND_WALK,
- SND_EMAR,
- SND_ANIMALHIT,
- SND_POINT,
- SND_JEEP,
- SND_GUN,
- SND_ANIMAL,
-};
-
-
-void vicdual_state::tranqgun_audio_w(uint8_t data)
-{
- int bitsChanged;
- int bitsGoneHigh;
- int bitsGoneLow;
-
- bitsChanged = m_port1State ^ data;
- bitsGoneHigh = bitsChanged & data;
- bitsGoneLow = bitsChanged & ~data;
-
- m_port1State = data;
-
- if ( bitsGoneHigh & OUT_PORT_1_ANIMAL )
- {
- PLAY( m_samples, SND_ANIMAL, 0 );
- }
- if ( bitsGoneLow & OUT_PORT_1_ANIMAL )
- {
- STOP( m_samples, SND_ANIMAL );
- }
-
- if ( bitsGoneHigh & OUT_PORT_1_CRY )
- {
- PLAY( m_samples, SND_CRY, 0 );
- }
- if ( bitsGoneLow & OUT_PORT_1_CRY )
- {
- STOP( m_samples, SND_CRY );
- }
-
- if ( bitsGoneHigh & OUT_PORT_1_WALK )
- {
- PLAY( m_samples, SND_WALK, 0 );
- }
- if ( bitsGoneLow & OUT_PORT_1_WALK )
- {
- STOP( m_samples, SND_WALK );
- }
-
- if ( bitsGoneLow & OUT_PORT_1_ANIMAL )
- {
- PLAY( m_samples, SND_ANIMAL,0 );
- }
-
- if ( bitsGoneHigh & OUT_PORT_1_ANIMALHIT )
- {
- PLAY( m_samples, SND_ANIMALHIT, 0 );
- }
- if ( bitsGoneLow & OUT_PORT_1_ANIMALHIT )
- {
- STOP( m_samples, SND_ANIMALHIT );
- }
-
- if ( bitsGoneHigh & OUT_PORT_1_POINT )
- {
- PLAY( m_samples, SND_POINT, 0 );
- }
- if ( bitsGoneLow & OUT_PORT_1_POINT )
- {
- STOP( m_samples, SND_POINT );
- }
-
- if ( bitsGoneLow & OUT_PORT_1_JEEP )
- {
- PLAY( m_samples, SND_JEEP, 1 );
-
- }
- if ( bitsGoneHigh & OUT_PORT_1_JEEP )
- {
- STOP( m_samples, SND_JEEP );
- }
-
- if ( bitsGoneLow & OUT_PORT_1_EMAR )
- {
- PLAY( m_samples, SND_EMAR, 0 );
- }
-
- if ( bitsGoneHigh & OUT_PORT_1_GUN )
- {
- PLAY( m_samples, SND_GUN, 0 );
- }
- if ( bitsGoneLow & OUT_PORT_1_GUN )
- {
- STOP( m_samples, SND_GUN );
- }
-}
-
-
-void vicdual_state::tranqgun_audio(machine_config &config)
-{
- /* samples */
- SAMPLES(config, m_samples);
- m_samples->set_channels(8);
- m_samples->set_samples_names(tranqgun_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "mono", 0.5);
-}
diff --git a/src/mame/audio/turrett.cpp b/src/mame/audio/turrett.cpp
index 4d8414b0118..a2f9ecdb5af 100644
--- a/src/mame/audio/turrett.cpp
+++ b/src/mame/audio/turrett.cpp
@@ -47,7 +47,7 @@ void turrett_device::device_start()
space().cache(m_cache);
// Create the sound stream
- m_stream = stream_alloc_legacy(0, 2, 44100);
+ m_stream = stream_alloc(0, 2, 44100);
// Create the volume table
for (int i = 0; i < 0x4f; ++i)
@@ -78,20 +78,17 @@ void turrett_device::device_reset()
//-------------------------------------------------
-// sound_stream_update_legacy - update sound stream
+// sound_stream_update - update sound stream
//-------------------------------------------------
-void turrett_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void turrett_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// Silence the buffers
- memset(outputs[0], 0x00, sizeof(stream_sample_t) * samples);
- memset(outputs[1], 0x00, sizeof(stream_sample_t) * samples);
+ outputs[0].fill(0);
+ outputs[1].fill(0);
for (int ch = 0; ch < SOUND_CHANNELS; ++ch)
{
- stream_sample_t *l = outputs[0];
- stream_sample_t *r = outputs[1];
-
if (m_channels[ch].m_playing)
{
uint32_t &addr = m_channels[ch].m_address;
@@ -104,7 +101,7 @@ void turrett_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
// Channels 30 and 31 expect interleaved stereo samples
uint32_t incr = (ch >= 30) ? 2 : 1;
- for (int s = 0; s < samples; ++s)
+ for (int s = 0; s < outputs[0].samples(); ++s)
{
int16_t sample = m_cache.read_word(addr << 1);
@@ -116,8 +113,8 @@ void turrett_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
addr += incr;
- *l++ += (sample * lvol) >> 17;
- *r++ += (sample * rvol) >> 17;
+ outputs[0].add_int(s, (sample * lvol) >> 17, 32768);
+ outputs[1].add_int(s, (sample * rvol) >> 17, 32768);
}
}
}
diff --git a/src/mame/audio/tvc.cpp b/src/mame/audio/tvc.cpp
index e30c79ef959..84495e0838b 100644
--- a/src/mame/audio/tvc.cpp
+++ b/src/mame/audio/tvc.cpp
@@ -31,7 +31,7 @@ void tvc_sound_device::device_start()
// resolve callbacks
m_write_sndint.resolve_safe();
- m_stream = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_stream = stream_alloc(0, 1, machine().sample_rate());
m_sndint_timer = timer_alloc(TIMER_SNDINT);
}
@@ -58,19 +58,19 @@ void tvc_sound_device::device_timer(emu_timer &timer, device_timer_id id, int pa
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void tvc_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tvc_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int rate = machine().sample_rate() / 2;
- stream_sample_t *output = outputs[0];
+ auto &output = outputs[0];
+ int rate = output.sample_rate() / 2;
if (m_enabled && m_freq)
{
- while( samples-- > 0 )
+ for (int sampindex = 0; sampindex < output.samples(); sampindex++)
{
- *output++ = m_signal * (m_volume * 0x0800);
+ output.put_int(sampindex, m_signal * m_volume, 32768 / 0x0800);
m_incr -= m_freq;
while(m_incr < 0)
{
@@ -82,7 +82,7 @@ void tvc_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_s
else
{
// fill output with 0 if the sound is disabled
- memset(output, 0, samples * sizeof(stream_sample_t));
+ output.fill(0);
}
}
diff --git a/src/mame/audio/tvc.h b/src/mame/audio/tvc.h
index 669184a0a2b..004ed6975bf 100644
--- a/src/mame/audio/tvc.h
+++ b/src/mame/audio/tvc.h
@@ -34,7 +34,7 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
static const device_timer_id TIMER_SNDINT = 0;
diff --git a/src/mame/audio/tx1.cpp b/src/mame/audio/tx1.cpp
index a6dd9d2aeb6..22f3e23ec5b 100644
--- a/src/mame/audio/tx1.cpp
+++ b/src/mame/audio/tx1.cpp
@@ -111,7 +111,7 @@ void tx1_sound_device::device_start()
/* Allocate the stream */
- m_stream = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_stream = stream_alloc(0, 2, machine().sample_rate());
m_freq_to_step = (double)(1 << TX1_FRAC) / (double)machine().sample_rate();
/* Compute the engine resistor weights */
@@ -356,20 +356,16 @@ static inline void update_engine(int eng[4])
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void tx1_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void tx1_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
uint32_t step_0, step_1, step_2;
double /*gain_0, gain_1,*/ gain_2, gain_3;
- stream_sample_t *fl = &outputs[0][0];
- stream_sample_t *fr = &outputs[1][0];
-
- /* Clear the buffers */
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+ auto &fl = outputs[0];
+ auto &fr = outputs[1];
/* 8253 outputs for the player/opponent engine sounds. */
step_0 = m_pit8253.counts[0].val ? (TX1_PIT_CLOCK / m_pit8253.counts[0].val * m_freq_to_step) : 0;
@@ -381,7 +377,7 @@ void tx1_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_s
gain_2 = tx1_engine_gains[m_ay_outputb & 0xf];
gain_3 = BIT(m_ay_outputb, 5) ? 1.0f : 1.5f;
- while (samples--)
+ for (int sampindex = 0; sampindex < fl.samples(); sampindex++)
{
if (m_step0 & ((1 << TX1_FRAC)))
{
@@ -404,8 +400,8 @@ void tx1_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_s
m_step2 &= ((1 << TX1_FRAC) - 1);
}
- *fl++ = (m_pit0 + m_pit1)*gain_3 + 2*m_pit2*gain_2;
- *fr++ = (m_pit0 + m_pit1)*gain_3 + 2*m_pit2*gain_2;
+ fl.put_int(sampindex, (m_pit0 + m_pit1)*gain_3 + 2*m_pit2*gain_2, 32768);
+ fr.put_int(sampindex, (m_pit0 + m_pit1)*gain_3 + 2*m_pit2*gain_2, 32768);
m_step0 += step_0;
m_step1 += step_1;
@@ -662,7 +658,7 @@ void buggyboy_sound_device::device_start()
m_eng_voltages[i] = combine_weights(aweights, BIT(tmp[i], 0), BIT(tmp[i], 1), BIT(tmp[i], 2), BIT(tmp[i], 3));
/* Allocate the stream */
- m_stream = stream_alloc_legacy(0, 2, machine().sample_rate());
+ m_stream = stream_alloc(0, 2, machine().sample_rate());
m_freq_to_step = (double)(1 << 24) / (double)machine().sample_rate();
}
@@ -763,10 +759,10 @@ void buggyboy_sound_device::ym2_b_w(uint8_t data)
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void buggyboy_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void buggyboy_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
/* This is admittedly a bit of a hack job... */
@@ -774,12 +770,8 @@ void buggyboy_sound_device::sound_stream_update_legacy(sound_stream &stream, str
int n1_en, n2_en;
double gain0, gain1_l, gain1_r;
- stream_sample_t *fl = &outputs[0][0];
- stream_sample_t *fr = &outputs[1][0];
-
- /* Clear the buffers */
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+ auto &fl = outputs[0];
+ auto &fr = outputs[1];
/* 8253 outputs for the player/opponent buggy engine sounds. */
step_0 = m_pit8253.counts[0].val ? (BUGGYBOY_PIT_CLOCK / m_pit8253.counts[0].val * m_freq_to_step) : 0;
@@ -796,10 +788,10 @@ void buggyboy_sound_device::sound_stream_update_legacy(sound_stream &stream, str
gain1_l = bb_engine_gains[m_ym2_outputa >> 4] * 5;
gain1_r = bb_engine_gains[m_ym2_outputa & 0xf] * 5;
- while (samples--)
+ for (int sampindex = 0; sampindex < fl.samples(); sampindex++)
{
int i;
- stream_sample_t pit0, pit1, n1, n2;
+ s32 pit0, pit1, n1, n2;
pit0 = m_eng_voltages[(m_step0 >> 24) & 0xf];
pit1 = m_eng_voltages[(m_step1 >> 24) & 0xf];
@@ -839,8 +831,8 @@ void buggyboy_sound_device::sound_stream_update_legacy(sound_stream &stream, str
else
n2 = 8192;
- *fl++ = n1 + n2 + (pit0 * gain0) + (pit1 * gain1_l);
- *fr++ = n1 + n2 + (pit0 * gain0) + (pit1 * gain1_r);
+ fl.put_int(sampindex, n1 + n2 + (pit0 * gain0) + (pit1 * gain1_l), 32768);
+ fr.put_int(sampindex, n1 + n2 + (pit0 * gain0) + (pit1 * gain1_r), 32768);
m_step0 += step_0;
m_step1 += step_1;
diff --git a/src/mame/audio/tx1.h b/src/mame/audio/tx1.h
index 71e228e324c..8d8e4d49739 100644
--- a/src/mame/audio/tx1.h
+++ b/src/mame/audio/tx1.h
@@ -73,7 +73,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void tx1_sound_io(address_map &map);
void tx1_sound_prg(address_map &map);
@@ -104,9 +104,9 @@ protected:
uint8_t m_ppi_latch_b = 0;
uint32_t m_ts = 0;
- stream_sample_t m_pit0 = 0;
- stream_sample_t m_pit1 = 0;
- stream_sample_t m_pit2 = 0;
+ s32 m_pit0 = 0;
+ s32 m_pit1 = 0;
+ s32 m_pit2 = 0;
double m_weights0[4] = { 0, 0, 0, 0 };
double m_weights1[3] = { 0, 0, 0 };
@@ -155,7 +155,7 @@ protected:
virtual void device_reset() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void ym1_a_w(uint8_t data);
diff --git a/src/mame/audio/vboy.cpp b/src/mame/audio/vboy.cpp
index 37eec2ee80b..56aa88e9054 100644
--- a/src/mame/audio/vboy.cpp
+++ b/src/mame/audio/vboy.cpp
@@ -209,7 +209,7 @@ void vboysnd_device::device_start()
{
uint32_t rate = clock() / 120;
// create the stream
- m_stream = stream_alloc_legacy(0, 2, rate);
+ m_stream = stream_alloc(0, 2, rate);
m_timer = timer_alloc(0, nullptr);
m_timer->adjust(attotime::zero, 0, rate ? attotime::from_hz(rate / 4) : attotime::never);
@@ -265,19 +265,18 @@ void vboysnd_device::device_timer(emu_timer &timer, device_timer_id tid, int par
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle update requests for
+// sound_stream_update - handle update requests for
// our sound stream
//-------------------------------------------------
-void vboysnd_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void vboysnd_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *outL, *outR;
int len, i, j, channel;
- outL = outputs[0];
- outR = outputs[1];
+ auto &outL = outputs[0];
+ auto &outR = outputs[1];
- len = samples;
+ len = outL.samples();
// if (mgetb(m_aram+SST0P) & 0x1) // Sound Stop Reg
// goto end;
@@ -384,13 +383,9 @@ void vboysnd_device::sound_stream_update_legacy(sound_stream &stream, stream_sam
// scale to 16 bits
note_left = (note_left << 5) | ((note_left >> 6) & 0x1f);
note_right = (note_right << 5) | ((note_right >> 6) & 0x1f);
- if (note_left < -32767) note_left = -32767;
- if (note_left > 32767) note_left = 32767;
- if (note_right < -32767) note_right = -32767;
- if (note_right > 32767) note_right = 32767;
- *(outL++) = ((int16_t)note_left);
- *(outR++) = ((int16_t)note_right);
+ outL.put_int_clamp(j, (int16_t)note_left, 32768);
+ outR.put_int_clamp(j, (int16_t)note_right, 32768);
}
}
diff --git a/src/mame/audio/vboy.h b/src/mame/audio/vboy.h
index f8d3a050272..ca4de746db3 100644
--- a/src/mame/audio/vboy.h
+++ b/src/mame/audio/vboy.h
@@ -72,7 +72,7 @@ protected:
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
s_snd_channel snd_channel[5];
diff --git a/src/mame/audio/vc4000.cpp b/src/mame/audio/vc4000.cpp
index 84c19a2d942..0454af936a5 100644
--- a/src/mame/audio/vc4000.cpp
+++ b/src/mame/audio/vc4000.cpp
@@ -31,26 +31,22 @@ vc4000_sound_device::vc4000_sound_device(const machine_config &mconfig, const ch
void vc4000_sound_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 1, machine().sample_rate());
+ m_channel = stream_alloc(0, 1, machine().sample_rate());
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void vc4000_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void vc4000_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
int i;
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
- for (i = 0; i < samples; i++, buffer++)
+ for (i = 0; i < buffer.samples(); i++)
{
- *buffer = 0;
- if (m_reg[0] && m_pos <= m_size / 2)
- {
- *buffer = 0x7fff;
- }
+ buffer.put(i, (m_reg[0] && m_pos <= m_size / 2) ? 1.0 : 0.0);
if (m_pos <= m_size)
m_pos++;
if (m_pos > m_size)
diff --git a/src/mame/audio/vc4000.h b/src/mame/audio/vc4000.h
index 3917ffa2776..2dad7a87d27 100644
--- a/src/mame/audio/vc4000.h
+++ b/src/mame/audio/vc4000.h
@@ -28,7 +28,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
public:
void soundport_w(int mode, int data);
diff --git a/src/mame/audio/vicdual.cpp b/src/mame/audio/vicdual.cpp
index b3bd59c288f..2c44cd6107c 100644
--- a/src/mame/audio/vicdual.cpp
+++ b/src/mame/audio/vicdual.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Derrick Renaud, Couriersud
+// copyright-holders:Derrick Renaud, Couriersud, Aaron Giles
/*************************************************************************
VIC Dual Game board
@@ -9,187 +9,8 @@
#include "emu.h"
#include "includes/vicdual.h"
-
-/************************************************************************
- * frogs Sound System Analog emulation
- * Oct 2004, Derrick Renaud
- ************************************************************************/
-
-
-/* Discrete Sound Input Nodes */
-#define FROGS_FLY_EN NODE_01
-#define FROGS_JUMP_EN NODE_03
-#define FROGS_HOP_EN NODE_04
-#define FROGS_TONGUE_EN NODE_05
-#define FROGS_CAPTURE_EN NODE_06
-#define FROGS_SPLASH_EN NODE_08
-
-/* Nodes - Sounds */
-#define FROGS_BUZZZ_SND NODE_11
-#define FROGS_BOING_SND NODE_13
-#define FROGS_HOP_SND NODE_14
-#define FROGS_ZIP_SND NODE_15
-#define FROGS_CROAK_SND NODE_16
-#define FROGS_SPLASH_SND NODE_18
-/* VRs */
-#define FROGS_R93 NODE_25
-
-static const discrete_555_desc frogsZip555m =
-{
- DISC_555_OUT_CAP | DISC_555_OUT_DC | DISC_555_TRIGGER_IS_LOGIC,
- 12, // B+ voltage of 555
- DEFAULT_555_VALUES
-};
-
-static const discrete_555_cc_desc frogsZip555cc =
-{
- DISC_555_OUT_CAP | DISC_555_OUT_DC,
- 12, // B+ voltage of 555
- DEFAULT_555_VALUES,
- 0.6 // Q13 Vbe
-};
-
-static const discrete_mixer_desc frogsMixer =
-{
- DISC_MIXER_IS_OP_AMP,
- {RES_K(1), RES_K(5)},
- {FROGS_R93, 0},
- {CAP_U(0.01), CAP_U(0.01)},
- 0, RES_K(56), 0, CAP_U(0.1), 0, 10000
-};
-
-static DISCRETE_SOUND_START(frogs_discrete)
- /************************************************
- * Input register mapping for frogs
- *
- * All inputs are inverted by initial transistor.
- ************************************************/
- DISCRETE_INPUT_LOGIC(FROGS_FLY_EN)
- DISCRETE_INPUT_NOT(FROGS_JUMP_EN)
- DISCRETE_INPUT_NOT(FROGS_HOP_EN)
- DISCRETE_INPUT_NOT(FROGS_TONGUE_EN)
- DISCRETE_INPUT_NOT(FROGS_CAPTURE_EN)
- DISCRETE_INPUT_NOT(FROGS_SPLASH_EN)
-
- DISCRETE_ADJUSTMENT(FROGS_R93, RES_M(1), RES_K(10), DISC_LOGADJ, "R93")
-
- DISCRETE_555_MSTABLE(NODE_30, 1, FROGS_TONGUE_EN, RES_K(100), CAP_U(1), &frogsZip555m)
-
- /* Q11 & Q12 transform the voltage from the oneshot U4, to what is
- * needed by the 555CC circuit. Vin to R29 must be > 1V for things
- * to change. <=1 then The Vout of this circuit is 12V.
- * The Current through R28 equals current through R51. iR28 = iR51
- * So when Vin>.5, iR51 = (Vin-.5)/39k. =0 when Vin<=.5
- * So the voltage drop across R28 is vR28 = iR51 * 22k.
- * Finally the Vout = 12 - vR28.
- * Note this formula only works when Vin < 39/(22+39)*12V+1.
- * Which it always is, due to the 555 clamping to 12V*2/3.
- * The Zip effect is hard to emulate 100% due to loading effects
- * of the output stage on the charge stage. So I added some values
- * to get a similar waveshape to the breadboarded circuit.
- */
- DISCRETE_TRANSFORM5(NODE_31, 12, NODE_30, .5, RES_K(22)/RES_K(39), 0, "012-P4>*3*-")
-
- DISCRETE_555_CC(NODE_32, 1, NODE_31, RES_K(1.1), CAP_U(0.14), 0, RES_K(100), 500, &frogsZip555cc)
-
- DISCRETE_MIXER2(NODE_90, 1, NODE_32, 0, &frogsMixer)
-
- DISCRETE_OUTPUT(NODE_90, 1)
-
-DISCRETE_SOUND_END
-
-static const char *const frogs_sample_names[] =
-{
- "*frogs",
- "boing",
- "buzzz",
- "croak",
- "hop",
- "splash",
- "zip",
- nullptr
-};
-
-
-void vicdual_state::frogs_audio(machine_config &config)
-{
- SAMPLES(config, m_samples);
- m_samples->set_channels(5);
- m_samples->set_samples_names(frogs_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "mono", 0.35);
-
- DISCRETE(config, m_discrete, frogs_discrete);
- m_discrete->add_route(ALL_OUTPUTS, "mono", 1.0);
-}
-
-
-TIMER_CALLBACK_MEMBER( vicdual_state::frogs_croak_callback )
-{
- m_samples->stop(2);
-}
-
-
-MACHINE_START_MEMBER(vicdual_state,frogs_audio)
-{
- m_frogs_croak_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vicdual_state::frogs_croak_callback), this));
-
- machine_start();
-}
-
-
-void vicdual_state::frogs_audio_w(uint8_t data)
-{
- static int last_croak = 0;
- static int last_buzzz = 0;
- int new_croak = data & 0x08;
- int new_buzzz = data & 0x10;
-
-// m_discrete->write(FROGS_HOP_EN, data & 0x01);
-// m_discrete->write(FROGS_JUMP_EN, data & 0x02);
- m_discrete->write(FROGS_TONGUE_EN, data & 0x04);
-// m_discrete->write(FROGS_CAPTURE_EN, data & 0x08);
-// m_discrete->write(FROGS_FLY_EN, data & 0x10);
-// m_discrete->write(FROGS_SPLASH_EN, data & 0x80);
-
- if (data & 0x01)
- m_samples->start(3, 3); // Hop
- if (data & 0x02)
- m_samples->start(0, 0); // Boing
- if (new_croak)
- m_samples->start(2, 2); // Croak
- else
- {
- if (last_croak)
- {
- /* The croak will keep playing until .429s after being disabled */
- m_frogs_croak_timer->adjust(attotime::from_double(1.1 * RES_K(390) * CAP_U(1)));
- }
- }
- if (new_buzzz)
- {
- /* The Buzzz sound starts off a little louder in volume then
- * settles down to a steady buzzz. Whenever the trigger goes
- * low, the sound is disabled. If it then goes high, the buzzz
- * then starts off louder again. The games does this every time
- * the fly moves.
- * So I made the sample start with the louder effect and then play
- * for 12 seconds. A fly should move before this. If not the
- * sample loops, adding the loud part as if the fly moved.
- * This is obviously incorrect, but a fly never stands still for
- * 12 seconds.
- */
- if (!last_buzzz)
- m_samples->start(1, 1, true); // Buzzz
- }
- else
- m_samples->stop(1);
- if (data & 0x80)
- m_samples->start(4, 4); // Splash
-
- last_croak = new_croak;
- last_buzzz = new_buzzz;
-}
-
+#include "audio/nl_brdrline.h"
+#include "audio/nl_frogs.h"
/************************************************************************
@@ -479,154 +300,90 @@ void vicdual_state::invho2_audio_w(uint8_t data)
}
-/************************************************************************
- * brdrline Sound System Analog emulation
- * May 2006, Derrick Renaud
- ************************************************************************/
-#if 0
-
-
-/* Discrete Sound Input Nodes */
-#define BRDRLINE_GUN_TRG_EN NODE_01
-#define BRDRLINE_JEEP_ON_EN NODE_02
-#define BRDRLINE_POINT_TRG_EN NODE_03
-#define BRDRLINE_HIT_TRG_EN NODE_04
-#define BRDRLINE_ANIMAL_TRG_EN NODE_05
-#define BRDRLINE_EMAR_TRG_EN NODE_06
-#define BRDRLINE_WALK_TRG_EN NODE_07
-#define BRDRLINE_CRY_TRG_EN NODE_08
-
-/* Nodes - Sounds */
-#define BRDRLINE_GUN_TRG_SND NODE_91
-#define BRDRLINE_JEEP_ON_SND NODE_92
-#define BRDRLINE_POINT_TRG_SND NODE_93
-#define BRDRLINE_HIT_TRG_SND NODE_94
-#define BRDRLINE_ANIMAL_TRG_SND NODE_95
-#define BRDRLINE_EMAR_TRG_SND NODE_96
-#define BRDRLINE_WALK_TRG_SND NODE_97
-#define BRDRLINE_CRY_TRG_SND NODE_98
-
-DISCRETE_SOUND_START(brdrline_discrete)
- /************************************************
- * Input register mapping
- ************************************************/
- DISCRETE_INPUT_LOGIC(BRDRLINE_GUN_TRG_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_JEEP_ON_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_POINT_TRG_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_HIT_TRG_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_ANIMAL_TRG_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_EMAR_TRG_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_WALK_TRG_EN)
- DISCRETE_INPUT_LOGIC(BRDRLINE_CRY_TRG_EN)
-
- /************************************************
- * GUN TRG
- ************************************************/
- DISCRETE_LFSR_NOISE(NODE_10, 1, 1,CLK,AMPL,FEED,BIAS,LFSRTB)
- DISCRETE_MIXER2(NODE_11, 1, NODE_10,IN1,INFO)
- DISCRETE_FILTER2(NODE_12, 1, NODE_11,FREQ,DAMP,TYPE)
- DISCRETE_ONESHOT(NODE_13, BRDRLINE_GUN_TRG_EN, DEFAULT_TTL_V_LOGIC_1,
- TIME_OF_74LS123(RES_K(47), CAP_U(1)), // R155, C73
- DISC_ONESHOT_FEDGE | DISC_ONESHOT_RETRIG | DISC_OUT_ACTIVE_LOW)
- DISCRETE_RCDISC4(NODE_14, 1, NODE_13,RVAL0,RVAL1,RVAL2,CVAL,VP,TYPE)
- DISCRETE_VCA(BRDRLINE_GUN_TRG_SND, 1, NODE_12, NODE_14,TYPE)
-
- /************************************************
- * JEEP ON
- ************************************************/
- DISCRETE_555_ASTABLE(NODE_20, BRDRLINE_JEEP_ON_EN,
- RES_K(1), // R150
- RES_K(33), // R153
- CAP_U(.1), // C72
- OPTIONS)
- DISCRETE_COUNTER(NODE_21, 1, 1, NODE_20,MIN,MAX,DIR,INIT0, DISC_CLK_BY_COUNT)
- DISCRETE_COUNTER(NODE_22, 1, 1, NODE_20,MIN,MAX,DIR,INIT0, DISC_CLK_BY_COUNT)
- DISCRETE_TRANSFORM3(NODE,INP0,INP1,INP2,FUNCT)
- DISCRETE_DAC_R1(NODE,DATA,VDATA,LADDER)
-
- /************************************************
- * POINT TRG
- ************************************************/
-
- /************************************************
- * HIT TRG
- ************************************************/
-
- /************************************************
- * ANIMAL TRG
- ************************************************/
-
- /************************************************
- * EMAR TRG
- ************************************************/
-
- /************************************************
- * WALK TRG
- ************************************************/
- /************************************************
- * CRY TRG
- ************************************************/
-
- /************************************************
- * Mixer
- ************************************************/
-
- DISCRETE_OUTPUT(NODE_90, 1)
-
-DISCRETE_SOUND_END
-#endif
-
-static const char *const brdrline_sample_names[] =
+/*************************************
+ *
+ * Netlist-based Vic Dual Audio
+ *
+ *************************************/
+
+vicdual_audio_device_base::vicdual_audio_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 inputs_mask, void (*netlist)(netlist::nlparse_t &), double output_scale) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_mixer_interface(mconfig, *this),
+ m_input_line(*this, "sound_nl:in_%u", 0),
+ m_inputs_mask(inputs_mask),
+ m_netlist(netlist),
+ m_output_scale(output_scale)
{
- "*brdrline",
- "boot_and_start",
- "coin",
- "crashes",
- "end_level",
- "engine_noise",
- "field",
- "fire",
- nullptr
-};
+}
+void vicdual_audio_device_base::device_add_mconfig(machine_config &config)
+{
+ NETLIST_SOUND(config, "sound_nl", 48000)
+ .set_source(m_netlist)
+ .add_route(ALL_OUTPUTS, *this, 1.0);
+
+ if (BIT(m_inputs_mask, 0))
+ NETLIST_LOGIC_INPUT(config, m_input_line[0], "I_SOUND_0.IN", 0);
+ if (BIT(m_inputs_mask, 1))
+ NETLIST_LOGIC_INPUT(config, m_input_line[1], "I_SOUND_1.IN", 0);
+ if (BIT(m_inputs_mask, 2))
+ NETLIST_LOGIC_INPUT(config, m_input_line[2], "I_SOUND_2.IN", 0);
+ if (BIT(m_inputs_mask, 3))
+ NETLIST_LOGIC_INPUT(config, m_input_line[3], "I_SOUND_3.IN", 0);
+ if (BIT(m_inputs_mask, 4))
+ NETLIST_LOGIC_INPUT(config, m_input_line[4], "I_SOUND_4.IN", 0);
+ if (BIT(m_inputs_mask, 5))
+ NETLIST_LOGIC_INPUT(config, m_input_line[5], "I_SOUND_5.IN", 0);
+ if (BIT(m_inputs_mask, 6))
+ NETLIST_LOGIC_INPUT(config, m_input_line[6], "I_SOUND_6.IN", 0);
+ if (BIT(m_inputs_mask, 7))
+ NETLIST_LOGIC_INPUT(config, m_input_line[7], "I_SOUND_7.IN", 0);
+
+ NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(m_output_scale, 0.0);
+}
-void vicdual_state::brdrline_audio(machine_config &config)
+void vicdual_audio_device_base::device_start()
{
- SAMPLES(config, m_samples);
- m_samples->set_channels(7);
- m_samples->set_samples_names(brdrline_sample_names);
- m_samples->add_route(ALL_OUTPUTS, "mono", 0.35);
+ save_item(NAME(m_input_state));
}
-void vicdual_state::brdrline_audio_w(uint8_t data)
+void vicdual_audio_device_base::write(u8 value)
{
- uint8_t res = data ^ 0xff;
+ if (value != m_input_state)
+ {
+ m_input_state = value;
+ for (int index = 0; index < 8; index++)
+ if (m_input_line[index] != nullptr)
+ m_input_line[index]->write_line(BIT(m_input_state, index));
+ }
+}
-// if(res & 2) // low fuel, MISSING
- if(res & 8) // end level
- m_samples->start(3, 3);
+/*************************************
+ *
+ * Borderline/Tranquilizer Gun
+ *
+ *************************************/
- if(res & 0x10) // moving in the brush
- m_samples->start(5, 5);
+DEFINE_DEVICE_TYPE(BORDERLINE_AUDIO, borderline_audio_device, "borderline_audio", "Borderline Sound Board")
- if(res & 0x20) // fire
- m_samples->start(6, 6);
+borderline_audio_device::borderline_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ vicdual_audio_device_base(mconfig, BORDERLINE_AUDIO, tag, owner, clock, 0xff, NETLIST_NAME(brdrline), 1.0)
+{
+}
- if(res & 0x40) // car engine noise
- m_samples->start(4, 4);
- if(res & 0x80) // crashes
- m_samples->start(2, 2);
- //printf("%02x\n",res);
-}
+/*************************************
+ *
+ * Frogs
+ *
+ *************************************/
+
+DEFINE_DEVICE_TYPE(FROGS_AUDIO, frogs_audio_device, "frogs_audio", "Frogs Sound Board")
-void vicdual_state::brdrline_audio_aux_w(uint8_t data)
+frogs_audio_device::frogs_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ vicdual_audio_device_base(mconfig, FROGS_AUDIO, tag, owner, clock, 0xff, NETLIST_NAME(frogs), 1.0)
{
- if(data & 0xfc) // coin, unknown which is the trigger
- m_samples->start(1, 1);
- else // boot sample
- m_samples->start(0, 0);
}
diff --git a/src/mame/audio/vicdual.h b/src/mame/audio/vicdual.h
new file mode 100644
index 00000000000..e0a918899e2
--- /dev/null
+++ b/src/mame/audio/vicdual.h
@@ -0,0 +1,49 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+#ifndef MAME_AUDIO_VICDUAL_H
+#define MAME_AUDIO_VICDUAL_H
+
+#pragma once
+
+#include "machine/netlist.h"
+#include "netlist/nl_setup.h"
+
+
+class vicdual_audio_device_base : public device_t, public device_mixer_interface
+{
+protected:
+ vicdual_audio_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 inputs_mask, void (*netlist)(netlist::nlparse_t &), double output_scale);
+
+ virtual void device_add_mconfig(machine_config &config) override;
+ virtual void device_start() override;
+
+public:
+ void write(u8 data);
+
+private:
+ optional_device_array<netlist_mame_logic_input_device, 8> m_input_line;
+ u8 m_input_state = 0xff;
+ u8 const m_inputs_mask;
+ void (*const m_netlist)(netlist::nlparse_t &);
+ double const m_output_scale;
+};
+
+
+class borderline_audio_device : public vicdual_audio_device_base
+{
+public:
+ borderline_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+
+class frogs_audio_device : public vicdual_audio_device_base
+{
+public:
+ frogs_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+
+DECLARE_DEVICE_TYPE(BORDERLINE_AUDIO, borderline_audio_device)
+DECLARE_DEVICE_TYPE(FROGS_AUDIO, frogs_audio_device)
+
+#endif // MAME_AUDIO_VICDUAL_H
diff --git a/src/mame/audio/warpwarp.cpp b/src/mame/audio/warpwarp.cpp
index 9e00ff069fd..5ef7e52659c 100644
--- a/src/mame/audio/warpwarp.cpp
+++ b/src/mame/audio/warpwarp.cpp
@@ -52,7 +52,7 @@ void warpwarp_sound_device::device_start()
m_clock_16h = clock() / 3 / 2 / 16;
m_clock_1v = clock() / 3 / 2 / 384;
- m_channel = stream_alloc_legacy(0, 1, m_clock_16h);
+ m_channel = stream_alloc(0, 1, m_clock_16h);
m_sound_volume_timer = timer_alloc(TIMER_SOUND_VOLUME_DECAY);
m_music_volume_timer = timer_alloc(TIMER_MUSIC_VOLUME_DECAY);
@@ -169,16 +169,16 @@ void warpwarp_sound_device::music2_w(u8 data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void warpwarp_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
- {
- stream_sample_t *buffer = outputs[0];
+void warpwarp_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ auto &buffer = outputs[0];
- while (samples--)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
- *buffer++ = (m_sound_signal + m_music_signal) / 2;
+ buffer.put_int(sampindex, m_sound_signal + m_music_signal, 32768 * 2);
/*
* The music signal is selected at a rate of 2H (1.536MHz) from the
diff --git a/src/mame/audio/warpwarp.h b/src/mame/audio/warpwarp.h
index 7bf06a4dc25..d4bcdc15d23 100644
--- a/src/mame/audio/warpwarp.h
+++ b/src/mame/audio/warpwarp.h
@@ -27,7 +27,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
diff --git a/src/mame/audio/williams.cpp b/src/mame/audio/williams.cpp
index b685d102652..e20ef10f8ed 100644
--- a/src/mame/audio/williams.cpp
+++ b/src/mame/audio/williams.cpp
@@ -76,6 +76,7 @@ williams_cvsd_sound_device::williams_cvsd_sound_device(const machine_config &mco
device_mixer_interface(mconfig, *this),
m_cpu(*this, "cpu"),
m_pia(*this, "pia"),
+ m_ym2151(*this, "ym2151"),
m_hc55516(*this, "cvsd"),
m_rombank(*this, "rombank"),
m_talkback(0)
@@ -185,12 +186,13 @@ void williams_cvsd_sound_device::device_add_mconfig(machine_config &config)
PIA6821(config, m_pia, 0);
m_pia->writepa_handler().set("dac", FUNC(dac_byte_interface::data_w));
m_pia->writepb_handler().set(FUNC(williams_cvsd_sound_device::talkback_w));
+ m_pia->ca2_handler().set(m_ym2151, FUNC(ym2151_device::reset_w));
m_pia->irqa_handler().set_inputline(m_cpu, M6809_FIRQ_LINE);
m_pia->irqb_handler().set_inputline(m_cpu, INPUT_LINE_NMI);
- ym2151_device &ym(YM2151(config, "ym2151", CVSD_FM_CLOCK));
- ym.irq_handler().set(m_pia, FUNC(pia6821_device::ca1_w)).invert(); // IRQ is not true state
- ym.add_route(ALL_OUTPUTS, *this, 0.10);
+ YM2151(config, m_ym2151, CVSD_FM_CLOCK);
+ m_ym2151->irq_handler().set(m_pia, FUNC(pia6821_device::ca1_w)).invert(); // IRQ is not true state
+ m_ym2151->add_route(ALL_OUTPUTS, *this, 0.10);
MC1408(config, "dac", 0).add_route(ALL_OUTPUTS, *this, 0.25);
voltage_regulator_device &vref(VOLTAGE_REGULATOR(config, "vref"));
diff --git a/src/mame/audio/williams.h b/src/mame/audio/williams.h
index a14e1d57d06..78006b1800d 100644
--- a/src/mame/audio/williams.h
+++ b/src/mame/audio/williams.h
@@ -63,6 +63,7 @@ private:
// devices
required_device<mc6809e_device> m_cpu;
required_device<pia6821_device> m_pia;
+ required_device<ym2151_device> m_ym2151;
required_device<hc55516_device> m_hc55516;
required_memory_bank m_rombank;
diff --git a/src/mame/audio/wiping.cpp b/src/mame/audio/wiping.cpp
index 0b83b88f8ac..3ce7f02e096 100644
--- a/src/mame/audio/wiping.cpp
+++ b/src/mame/audio/wiping.cpp
@@ -11,8 +11,6 @@
#include "emu.h"
#include "audio/wiping.h"
-static constexpr int defgain = 48;
-
DEFINE_DEVICE_TYPE(WIPING_CUSTOM, wiping_sound_device, "wiping_sound", "Wiping Custom Sound")
wiping_sound_device::wiping_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
@@ -23,10 +21,7 @@ wiping_sound_device::wiping_sound_device(const machine_config &mconfig, const ch
m_sound_rom(nullptr),
m_num_voices(0),
m_sound_enable(0),
- m_stream(nullptr),
- m_mixer_table(nullptr),
- m_mixer_lookup(nullptr),
- m_mixer_buffer(nullptr)
+ m_stream(nullptr)
{
memset(m_channel_list, 0, sizeof(wp_sound_channel)*MAX_VOICES);
memset(m_soundregs, 0, sizeof(uint8_t)*0x4000);
@@ -42,13 +37,10 @@ void wiping_sound_device::device_start()
wp_sound_channel *voice;
/* get stream channels */
- m_stream = stream_alloc_legacy(0, 1, clock()/2);
+ m_stream = stream_alloc(0, 1, clock()/2);
/* allocate a buffer to mix into - 1 second's worth should be more than enough */
- m_mixer_buffer = make_unique_clear<short[]>(clock()/2);
-
- /* build the mixer table */
- make_mixer_table(8, defgain);
+ m_mixer_buffer.resize(clock()/2);
/* extract globals from the interface */
m_num_voices = 8;
@@ -81,26 +73,6 @@ void wiping_sound_device::device_start()
}
}
-/* build a table to divide by the number of voices; gain is specified as gain*16 */
-void wiping_sound_device::make_mixer_table(int voices, int gain)
-{
- /* allocate memory */
- m_mixer_table = make_unique_clear<int16_t[]>(256 * voices);
-
- /* find the middle of the table */
- m_mixer_lookup = m_mixer_table.get() + (128 * voices);
-
- /* fill in the table - 16 bit case */
- for (int i = 0; i < voices * 128; i++)
- {
- int val = i * gain * 16 / voices;
- if (val > 32767) val = 32767;
- m_mixer_lookup[ i] = val;
- m_mixer_lookup[-i] = -val;
- }
-}
-
-
/********************************************************************************/
void wiping_sound_device::sound_w(offs_t offset, uint8_t data)
@@ -150,12 +122,12 @@ void wiping_sound_device::sound_w(offs_t offset, uint8_t data)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void wiping_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void wiping_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *buffer = outputs[0];
+ auto &buffer = outputs[0];
wp_sound_channel *voice;
short *mix;
int i;
@@ -163,12 +135,12 @@ void wiping_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
/* if no sound, we're done */
if (m_sound_enable == 0)
{
- memset(buffer, 0, samples * sizeof(*buffer));
+ buffer.fill(0);
return;
}
/* zap the contents of the mixer buffer */
- memset(m_mixer_buffer.get(), 0, samples * sizeof(short));
+ std::fill_n(&m_mixer_buffer[0], buffer.samples(), 0);
/* loop over each voice and add its contribution */
for (voice = m_channel_list; voice < m_last_channel; voice++)
@@ -182,10 +154,10 @@ void wiping_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
const uint8_t *w = voice->wave;
int c = voice->counter;
- mix = m_mixer_buffer.get();
+ mix = &m_mixer_buffer[0];
/* add our contribution */
- for (i = 0; i < samples; i++)
+ for (i = 0; i < buffer.samples(); i++)
{
int offs;
@@ -229,7 +201,7 @@ void wiping_sound_device::sound_stream_update_legacy(sound_stream &stream, strea
}
/* mix it down */
- mix = m_mixer_buffer.get();
- for (i = 0; i < samples; i++)
- *buffer++ = m_mixer_lookup[*mix++];
+ mix = &m_mixer_buffer[0];
+ for (i = 0; i < buffer.samples(); i++)
+ buffer.put_int(i, *mix++, 128 * MAX_VOICES);
}
diff --git a/src/mame/audio/wiping.h b/src/mame/audio/wiping.h
index d10a26d2848..1f50683387e 100644
--- a/src/mame/audio/wiping.h
+++ b/src/mame/audio/wiping.h
@@ -17,7 +17,7 @@ protected:
virtual void device_start() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
/* 8 voices max */
@@ -48,10 +48,7 @@ private:
sound_stream *m_stream;
/* mixer tables and internal buffers */
- std::unique_ptr<int16_t[]> m_mixer_table;
- int16_t *m_mixer_lookup;
- std::unique_ptr<short[]> m_mixer_buffer;
- std::unique_ptr<short[]> m_mixer_buffer_2;
+ std::vector<short> m_mixer_buffer;
uint8_t m_soundregs[0x4000];
diff --git a/src/mame/audio/wswan.cpp b/src/mame/audio/wswan.cpp
index 0e6442cea6d..6f956ffb57c 100644
--- a/src/mame/audio/wswan.cpp
+++ b/src/mame/audio/wswan.cpp
@@ -62,7 +62,7 @@ constexpr int clk_div = 64;
void wswan_sound_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 2, clock() / clk_div);
+ m_channel = stream_alloc(0, 2, clock() / clk_div);
save_item(NAME(m_sweep_step));
save_item(NAME(m_sweep_time));
@@ -164,16 +164,16 @@ int wswan_sound_device::fetch_sample(int channel, int offset)
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void wswan_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void wswan_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t sample, left, right;
+ s32 sample, left, right;
- stream_sample_t *outputl = outputs[0];
- stream_sample_t *outputr = outputs[1];
- while( samples-- > 0 )
+ auto &outputl = outputs[0];
+ auto &outputr = outputs[1];
+ for (int sampindex = 0; sampindex < outputl.samples(); sampindex++)
{
left = right = 0;
@@ -268,11 +268,8 @@ void wswan_sound_device::sound_stream_update_legacy(sound_stream &stream, stream
right += m_audio4.vol_right * sample;
}
- left <<= 5;
- right <<= 5;
-
- *outputl++ = left;
- *outputr++ = right;
+ outputl.put_int(sampindex, left, 32768 >> 5);
+ outputr.put_int(sampindex, right, 32768 >> 5);
}
}
diff --git a/src/mame/audio/wswan.h b/src/mame/audio/wswan.h
index e3c4974bf54..f21ad6adbc5 100644
--- a/src/mame/audio/wswan.h
+++ b/src/mame/audio/wswan.h
@@ -59,7 +59,7 @@ protected:
virtual void rom_bank_updated() override;
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
void wswan_ch_set_freq( CHAN *ch, uint16_t freq );
diff --git a/src/mame/audio/xavix.cpp b/src/mame/audio/xavix.cpp
index a4b2d12dccb..ab5b2387a86 100644
--- a/src/mame/audio/xavix.cpp
+++ b/src/mame/audio/xavix.cpp
@@ -27,7 +27,7 @@ void xavix_sound_device::device_start()
m_readregs_cb.resolve_safe(0xff);
m_readsamples_cb.resolve_safe(0x80);
- m_stream = stream_alloc_legacy(0, 2, 163840);
+ m_stream = stream_alloc(0, 2, 163840);
}
void xavix_sound_device::device_reset()
@@ -43,14 +43,15 @@ void xavix_sound_device::device_reset()
}
-void xavix_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void xavix_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
// reset the output stream
- memset(outputs[0], 0, samples * sizeof(*outputs[0]));
- memset(outputs[1], 0, samples * sizeof(*outputs[1]));
+ outputs[0].fill(0);
+ outputs[1].fill(0);
int outpos = 0;
// loop while we still have samples to generate
+ int samples = outputs[0].samples();
while (samples-- != 0)
{
for (int channel = 0; channel < 2; channel++)
@@ -83,7 +84,7 @@ void xavix_sound_device::sound_stream_update_legacy(sound_stream &stream, stream
*/
}
- outputs[channel][outpos] += sample * (m_voice[v].vol + 1);
+ outputs[channel].add_int(outpos, sample * (m_voice[v].vol + 1), 32768);
m_voice[v].position[channel] += m_voice[v].rate;
}
else
diff --git a/src/mame/drivers/1945kiii.cpp b/src/mame/drivers/1945kiii.cpp
index db424a83f54..1f78b084df1 100644
--- a/src/mame/drivers/1945kiii.cpp
+++ b/src/mame/drivers/1945kiii.cpp
@@ -234,8 +234,8 @@ void k3_state::k3_drawgfx(bitmap_ind16 &dest_bmp,const rectangle &clip,gfx_eleme
{ // skip if inner loop doesn't draw anything
for (int y = sy; y < ey; y++)
{
- const u8 *source = source_base + y_index * gfx->rowbytes();
- u16 *dest = &dest_bmp.pix16(y);
+ u8 const *const source = source_base + y_index * gfx->rowbytes();
+ u16 *const dest = &dest_bmp.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
{
diff --git a/src/mame/drivers/5clown.cpp b/src/mame/drivers/5clown.cpp
index 1d8ca3d4af0..387a2362366 100644
--- a/src/mame/drivers/5clown.cpp
+++ b/src/mame/drivers/5clown.cpp
@@ -553,7 +553,7 @@ MC6845_UPDATE_ROW(_5clown_state::update_row)
x--- ---- Extra color for 7's.
*/
- uint32_t *pix = &bitmap.pix32(y);
+ uint32_t *pix = &bitmap.pix(y);
ra &= 0x07;
for (int x = 0; x < x_count; x++)
diff --git a/src/mame/drivers/8080bw.cpp b/src/mame/drivers/8080bw.cpp
index fce3ba4df08..ff08f30ba54 100644
--- a/src/mame/drivers/8080bw.cpp
+++ b/src/mame/drivers/8080bw.cpp
@@ -5720,10 +5720,10 @@ GAME( 1979, sflush, 0, sflush, sflush, _8080bw_state, empty_i
GAME( 1980, lupin3, 0, lupin3, lupin3, _8080bw_state, empty_init, ROT270, "Taito", "Lupin III (set 1)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND )
GAME( 1980, lupin3a, lupin3, lupin3a, lupin3a, _8080bw_state, empty_init, ROT270, "Taito", "Lupin III (set 2)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND )
-GAME( 1980, polaris, 0, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (Latest version)", MACHINE_SUPPORTS_SAVE )
-GAME( 1980, polarisa, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (Second revision)", MACHINE_SUPPORTS_SAVE )
-GAME( 1980, polarisb, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (First revision)", MACHINE_SUPPORTS_SAVE )
-GAME( 1980, polariso, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (Original version)", MACHINE_SUPPORTS_SAVE )
+GAME( 1980, polaris, 0, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (latest version)", MACHINE_SUPPORTS_SAVE )
+GAME( 1980, polarisa, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (second revision)", MACHINE_SUPPORTS_SAVE )
+GAME( 1980, polarisb, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (first revision)", MACHINE_SUPPORTS_SAVE )
+GAME( 1980, polariso, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito", "Polaris (original version)", MACHINE_SUPPORTS_SAVE )
GAME( 1981, polarisbr, polaris, polaris, polaris, _8080bw_state, empty_init, ROT270, "Taito do Brasil", "Polaris (Brazil)", MACHINE_SUPPORTS_SAVE )
GAME( 1980, ballbomb, 0, ballbomb, ballbomb, _8080bw_state, empty_init, ROT270, "Taito", "Balloon Bomber", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS ) /* missing clouds */
diff --git a/src/mame/drivers/a5105.cpp b/src/mame/drivers/a5105.cpp
index d8ffbbcc55c..3525ce5b51d 100644
--- a/src/mame/drivers/a5105.cpp
+++ b/src/mame/drivers/a5105.cpp
@@ -120,7 +120,7 @@ UPD7220_DISPLAY_PIXELS_MEMBER( a5105_state::hgdc_display_pixels )
{
int const pen = ((gfx >> xi) & 1) ? 7 : 0;
- bitmap.pix32(y, x + xi) = palette[pen];
+ bitmap.pix(y, x + xi) = palette[pen];
}
}
@@ -151,7 +151,7 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( a5105_state::hgdc_draw_text )
pen = 0;
if (m_screen->visible_area().contains(res_x+0, res_y))
- bitmap.pix32(res_y, res_x) = palette[pen];
+ bitmap.pix(res_y, res_x) = palette[pen];
}
}
}
diff --git a/src/mame/drivers/a7150.cpp b/src/mame/drivers/a7150.cpp
index 66250419e21..92a3327b452 100644
--- a/src/mame/drivers/a7150.cpp
+++ b/src/mame/drivers/a7150.cpp
@@ -122,18 +122,17 @@ private:
uint32_t a7150_state::screen_update_k7072(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int y, x, b;
int addr = 0;
- for (y = 0; y < 400; y++)
+ for (int y = 0; y < 400; y++)
{
int horpos = 0;
- for (x = 0; x < 80; x++)
+ for (int x = 0; x < 80; x++)
{
uint8_t code = m_video_ram[addr++];
- for (b = 0; b < 8; b++)
+ for (int b = 0; b < 8; b++)
{
- bitmap.pix16(y, horpos++) = ((code >> (7 - b)) & 0x01) ? 1 : 0;
+ bitmap.pix(y, horpos++) = ((code >> (7 - b)) & 0x01) ? 1 : 0;
}
}
}
diff --git a/src/mame/drivers/abc1600.cpp b/src/mame/drivers/abc1600.cpp
index d0a9e05dd02..0f59fbd87b9 100644
--- a/src/mame/drivers/abc1600.cpp
+++ b/src/mame/drivers/abc1600.cpp
@@ -34,20 +34,20 @@
TODO:
- - sas/format/format in abcenix tries to access the SASI card using a memory location mapped for task 0, when the process is run as task 1
-
- [:mac] ':3f' (0009E) ff800:4f TASK 0 SEGMENT 15 PAGE 15 MEM 7f800-7ffff 1ff800
- [:mac] ':3f' (0009E) ff801:ff TASK 0 SEGMENT 15 PAGE 15 MEM 7f800-7ffff 1ff800
- [:mac] ':3f' (0009E) ff000:4f TASK 0 SEGMENT 15 PAGE 14 MEM 7f000-7f7ff 1ff000
- [:mac] ':3f' (0009E) ff001:fe TASK 0 SEGMENT 15 PAGE 14 MEM 7f000-7f7ff 1ff000
- [:mac] ':3f' (0009E) fe800:4f TASK 0 SEGMENT 15 PAGE 13 MEM 7e800-7efff 1fe800
- [:mac] ':3f' (0009E) fe801:fd TASK 0 SEGMENT 15 PAGE 13 MEM 7e800-7efff 1fe800
- [:mac] ':3f' (0009E) fe000:4f TASK 0 SEGMENT 15 PAGE 12 MEM 7e000-7e7ff 1fe000
- [:mac] ':3f' (0009E) fe001:fc TASK 0 SEGMENT 15 PAGE 12 MEM 7e000-7e7ff 1fe000
-
- [:mac] ':3f' (08A98) MAC 7e4a2:0004a2 (SEGA 02f SEGD 09 PGA 09c PGD 8000 NONX 1 WP 0 TASK 1 FC 1)
- should be
- [:mac] ':3f' (089A8) MAC 7e4a2:1fe4a2 (SEGA 00f SEGD 0f PGA 0fc PGD 43fc NONX 0 WP 1 TASK 0 FC 5)
+ - sas/format/format in abcenix tries to access the SASI card using a memory location mapped for task 0, when the process is run as task 1
+
+ [:mac] ':3f' (0009E) ff800:4f TASK 0 SEGMENT 15 PAGE 15 MEM 7f800-7ffff 1ff800
+ [:mac] ':3f' (0009E) ff801:ff TASK 0 SEGMENT 15 PAGE 15 MEM 7f800-7ffff 1ff800
+ [:mac] ':3f' (0009E) ff000:4f TASK 0 SEGMENT 15 PAGE 14 MEM 7f000-7f7ff 1ff000
+ [:mac] ':3f' (0009E) ff001:fe TASK 0 SEGMENT 15 PAGE 14 MEM 7f000-7f7ff 1ff000
+ [:mac] ':3f' (0009E) fe800:4f TASK 0 SEGMENT 15 PAGE 13 MEM 7e800-7efff 1fe800
+ [:mac] ':3f' (0009E) fe801:fd TASK 0 SEGMENT 15 PAGE 13 MEM 7e800-7efff 1fe800
+ [:mac] ':3f' (0009E) fe000:4f TASK 0 SEGMENT 15 PAGE 12 MEM 7e000-7e7ff 1fe000
+ [:mac] ':3f' (0009E) fe001:fc TASK 0 SEGMENT 15 PAGE 12 MEM 7e000-7e7ff 1fe000
+
+ [:mac] ':3f' (08A98) MAC 7e4a2:0004a2 (SEGA 02f SEGD 09 PGA 09c PGD 8000 NONX 1 WP 0 TASK 1 FC 1)
+ should be
+ [:mac] ':3f' (089A8) MAC 7e4a2:1fe4a2 (SEGA 00f SEGD 0f PGA 0fc PGD 43fc NONX 0 WP 1 TASK 0 FC 5)
- short/long reset (RSTBUT)
- CIO
diff --git a/src/mame/drivers/ac1.cpp b/src/mame/drivers/ac1.cpp
index cf6f2bf9658..ea8fae0c277 100644
--- a/src/mame/drivers/ac1.cpp
+++ b/src/mame/drivers/ac1.cpp
@@ -254,9 +254,9 @@ static INPUT_PORTS_START( ac1 )
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x')
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHAR('y')
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z')
- PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR(']')
+ PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
- PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('{') PORT_CHAR('}')
+ PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_CHAR('^') PORT_CHAR('~')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_CHAR('_') PORT_CHAR(127)
diff --git a/src/mame/drivers/accomm.cpp b/src/mame/drivers/accomm.cpp
index f93a40832ae..6a1c050195e 100644
--- a/src/mame/drivers/accomm.cpp
+++ b/src/mame/drivers/accomm.cpp
@@ -234,7 +234,7 @@ inline uint8_t accomm_state::read_vram(uint16_t addr)
inline void accomm_state::plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color)
{
- bitmap.pix16(y, x) = (uint16_t)color;
+ bitmap.pix(y, x) = (uint16_t)color;
}
uint32_t accomm_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
diff --git a/src/mame/drivers/acefruit.cpp b/src/mame/drivers/acefruit.cpp
index c41d958d314..f8fc8e8b065 100644
--- a/src/mame/drivers/acefruit.cpp
+++ b/src/mame/drivers/acefruit.cpp
@@ -149,16 +149,14 @@ uint32_t acefruit_state::screen_update_acefruit(screen_device &screen, bitmap_in
{
int startrow = cliprect.min_y / 8;
int endrow = cliprect.max_y / 8;
- int row;
- int col;
- for( row = startrow; row <= endrow; row++ )
+ for( int row = startrow; row <= endrow; row++ )
{
int spriterow = 0;
int spriteindex = 0;
int spriteparameter = 0;
- for( col = 0; col < 32; col++ )
+ for( int col = 0; col < 32; col++ )
{
int tile_index = ( col * 32 ) + row;
int code = m_videoram[ tile_index ];
@@ -170,20 +168,18 @@ uint32_t acefruit_state::screen_update_acefruit(screen_device &screen, bitmap_in
}
else if( color >= 0x5 && color <= 0x7 )
{
- int y;
- int x;
static const int spriteskip[] = { 1, 2, 4 };
int spritesize = spriteskip[ color - 5 ];
gfx_element *gfx = m_gfxdecode->gfx(0);
- for( x = 0; x < 16; x++ )
+ for( int x = 0; x < 16; x++ )
{
int sprite = ( m_spriteram[ ( spriteindex / 64 ) % 6 ] & 0xf ) ^ 0xf;
const uint8_t *gfxdata = gfx->get_data(sprite);
- for( y = 0; y < 8; y++ )
+ for( int y = 0; y < 8; y++ )
{
- uint16_t *dst = &bitmap.pix16(y + ( row * 8 ), x + ( col * 16 ) );
+ uint16_t *dst = &bitmap.pix(y + ( row * 8 ), x + ( col * 16 ) );
*( dst ) = *( gfxdata + ( ( spriterow + y ) * gfx->rowbytes() ) + ( ( spriteindex % 64 ) >> 1 ) );
}
@@ -192,14 +188,11 @@ uint32_t acefruit_state::screen_update_acefruit(screen_device &screen, bitmap_in
}
else
{
- int y;
- int x;
-
- for( x = 0; x < 16; x++ )
+ for( int x = 0; x < 16; x++ )
{
- for( y = 0; y < 8; y++ )
+ for( int y = 0; y < 8; y++ )
{
- uint16_t *dst = &bitmap.pix16(y + ( row * 8 ), x + ( col * 16 ) );
+ uint16_t *dst = &bitmap.pix(y + ( row * 8 ), x + ( col * 16 ) );
*( dst ) = 0;
}
}
diff --git a/src/mame/drivers/adacp150.cpp b/src/mame/drivers/adacp150.cpp
new file mode 100644
index 00000000000..1243bf7a279
--- /dev/null
+++ b/src/mame/drivers/adacp150.cpp
@@ -0,0 +1,229 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/***************************************************************************
+
+ Preliminary driver for Adacom IBM 3287 ASCII printer adapters.
+
+ Currently this does not much more than pass the extensive self-test.
+
+ TODO: make this a bus device in the eventuality of synchronous
+ communications and a 3270-compatible host both being emulated.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "bus/rs232/rs232.h"
+#include "cpu/bcp/dp8344.h"
+#include "cpu/z80/z80.h"
+#include "machine/nvram.h"
+#include "machine/z80ctc.h"
+#include "machine/z80pio.h"
+#include "machine/z80sio.h"
+#include "video/hd44780.h"
+#include "emupal.h"
+#include "screen.h"
+
+class adacp150_state : public driver_device
+{
+public:
+ adacp150_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_bcp(*this, "bcp")
+ , m_lcdc(*this, "lcdc")
+ , m_leds(*this, "led%u", 0U)
+ , m_bcp_cmd(false)
+ {
+ }
+
+ void adacp150(machine_config &config);
+
+protected:
+ virtual void machine_start() override;
+
+private:
+ HD44780_PIXEL_UPDATE(pixel_update);
+ void palette_init(palette_device &palette);
+
+ u8 bcp_ram_r(offs_t offset);
+ void bcp_ram_w(offs_t offset, u8 data);
+ void output_control_w(u8 data);
+
+ void z80_mem_map(address_map &map);
+ void z80_io_map(address_map &map);
+ void bcp_prog_map(address_map &map);
+ void bcp_data_map(address_map &map);
+
+ required_device<z80_device> m_maincpu;
+ required_device<dp8344_device> m_bcp;
+ required_device<hd44780_device> m_lcdc;
+ output_finder<4> m_leds;
+
+ bool m_bcp_cmd;
+};
+
+void adacp150_state::machine_start()
+{
+ m_leds.resolve();
+
+ m_lcdc->rw_w(0);
+
+ save_item(NAME(m_bcp_cmd));
+}
+
+HD44780_PIXEL_UPDATE(adacp150_state::pixel_update)
+{
+ if (x < 5 && y < 8 && line < 2 && pos < 16)
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
+}
+
+
+u8 adacp150_state::bcp_ram_r(offs_t offset)
+{
+ if (m_bcp_cmd)
+ return m_bcp->cmd_r();
+ else
+ return m_bcp->remote_read(offset | 0x4000);
+}
+
+void adacp150_state::bcp_ram_w(offs_t offset, u8 data)
+{
+ if (m_bcp_cmd)
+ m_bcp->cmd_w(data);
+ else
+ m_bcp->remote_write(offset | 0x4000, data);
+}
+
+void adacp150_state::output_control_w(u8 data)
+{
+ for (int n = 0; n < 4; n++)
+ m_leds[n] = BIT(data, n);
+
+ m_bcp_cmd = BIT(data, 4);
+ m_lcdc->rs_w(BIT(data, 6));
+ m_lcdc->e_w(BIT(data, 5));
+}
+
+
+void adacp150_state::z80_mem_map(address_map &map)
+{
+ map(0x0000, 0xbfff).rom().region("program", 0);
+ map(0xc000, 0xffff).rw(FUNC(adacp150_state::bcp_ram_r), FUNC(adacp150_state::bcp_ram_w));
+}
+
+void adacp150_state::z80_io_map(address_map &map)
+{
+ map.global_mask(0xff);
+ map(0x00, 0x03).rw("pio", FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
+ map(0x04, 0x07).rw("ctc", FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
+ map(0x08, 0x0b).rw("sio", FUNC(z80sio_device::ba_cd_r), FUNC(z80sio_device::ba_cd_w));
+ map(0x80, 0x80).portr("IN0");
+ map(0xa0, 0xa0).portr("IN1");
+ map(0xc0, 0xc0).w(FUNC(adacp150_state::output_control_w));
+ map(0xe0, 0xe0).w(m_lcdc, FUNC(hd44780_device::db_w));
+}
+
+void adacp150_state::bcp_prog_map(address_map &map)
+{
+ map(0x0000, 0x07ff).ram(); // 2x CXK5814P-35L
+}
+
+void adacp150_state::bcp_data_map(address_map &map)
+{
+ map(0x0000, 0x7fff).ram().share("nvram");
+}
+
+
+static INPUT_PORTS_START(adacp150)
+ PORT_START("IN0") // not verified
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Save")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Select")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Roll")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Set-Up")
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Reset")
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Cancel")
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Reprint")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PA 1")
+
+ PORT_START("IN1") // not verified
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("PA 2")
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("LF")
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("FF")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hold")
+ PORT_BIT(0xf0, IP_ACTIVE_HIGH, IPT_UNUSED)
+INPUT_PORTS_END
+
+void adacp150_state::palette_init(palette_device &palette)
+{
+ palette.set_pen_color(0, rgb_t(131, 136, 139));
+ palette.set_pen_color(1, rgb_t( 92, 83, 88));
+}
+
+static const z80_daisy_config daisy_chain[] =
+{
+ { "ctc" },
+ { "sio" },
+ { "pio" },
+ { nullptr }
+};
+
+void adacp150_state::adacp150(machine_config &config)
+{
+ auto MAIN_CLOCK = 18.8696_MHz_XTAL / 6;
+
+ Z80(config, m_maincpu, MAIN_CLOCK); // Zilog Z84C0006PEC
+ m_maincpu->set_addrmap(AS_PROGRAM, &adacp150_state::z80_mem_map);
+ m_maincpu->set_addrmap(AS_IO, &adacp150_state::z80_io_map);
+ m_maincpu->set_daisy_config(daisy_chain);
+
+ DP8344A(config, m_bcp, 18.8696_MHz_XTAL); // DP8344AV
+ m_bcp->set_addrmap(AS_PROGRAM, &adacp150_state::bcp_prog_map);
+ m_bcp->set_addrmap(AS_DATA, &adacp150_state::bcp_data_map);
+ m_bcp->set_auto_start(false);
+
+ NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // CXK58257P-10L + battery
+
+ z80ctc_device &ctc(Z80CTC(config, "ctc", MAIN_CLOCK)); // TODO: part of Zilog Z84C9008VSC Z80 KIO
+ ctc.set_clk<0>(2.4576_MHz_XTAL / 2);
+ ctc.set_clk<1>(2.4576_MHz_XTAL / 2);
+ ctc.zc_callback<0>().set("sio", FUNC(z80sio_device::rxca_w));
+ ctc.zc_callback<0>().append("sio", FUNC(z80sio_device::txca_w));
+ ctc.zc_callback<1>().set("sio", FUNC(z80sio_device::rxcb_w));
+ ctc.zc_callback<1>().append("sio", FUNC(z80sio_device::txcb_w));
+ ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+
+ z80pio_device &pio(Z80PIO(config, "pio", MAIN_CLOCK)); // TODO: part of Zilog Z84C9008VSC Z80 KIO
+ pio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+
+ z80sio_device &sio(Z80SIO(config, "sio", MAIN_CLOCK)); // TODO: part of Zilog Z84C9008VSC Z80 KIO
+ sio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+ sio.out_txda_callback().set("printer", FUNC(rs232_port_device::write_txd));
+ sio.out_txdb_callback().set("host", FUNC(rs232_port_device::write_txd));
+
+ rs232_port_device &printer(RS232_PORT(config, "printer", default_rs232_devices, nullptr));
+ printer.rxd_handler().set("sio", FUNC(z80sio_device::rxa_w));
+
+ rs232_port_device &host(RS232_PORT(config, "host", default_rs232_devices, nullptr));
+ host.rxd_handler().set("sio", FUNC(z80sio_device::rxb_w));
+
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
+ screen.set_refresh_hz(50);
+ screen.set_screen_update(m_lcdc, FUNC(hd44780_device::screen_update));
+ screen.set_size(16*6, 16);
+ screen.set_visarea(0, 16*6-1, 0, 16-1);
+ screen.set_palette("palette");
+
+ HD44780(config, m_lcdc);
+ m_lcdc->set_lcd_size(2, 20);
+ m_lcdc->set_pixel_update_cb(FUNC(adacp150_state::pixel_update));
+
+ PALETTE(config, "palette", FUNC(adacp150_state::palette_init), 2);
+}
+
+ROM_START(adacp150p)
+ ROM_REGION(0xc000, "program", 0)
+ ROM_LOAD("pa_2436__rev-4.52.u11", 0x0000, 0x8000, CRC(a381674c) SHA1(1d3cb4ca3ead40da67a353efe7553ea953fa929d)) // Intel D27C256
+ ROM_LOAD("pa_2437__rev-4.52.u22", 0x8000, 0x4000, CRC(eb468ad0) SHA1(881a90a6aa89d7e289d7adbec46d007a8cfa5351)) // Intel D27C128
+ROM_END
+
+SYST(1989, adacp150p, 0, 0, adacp150, adacp150, adacp150_state, empty_init, "Adacom", "CP-150 Plus", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW)
diff --git a/src/mame/drivers/adm11.cpp b/src/mame/drivers/adm11.cpp
index f976f7da444..e21e34ee018 100644
--- a/src/mame/drivers/adm11.cpp
+++ b/src/mame/drivers/adm11.cpp
@@ -93,7 +93,7 @@ SCN2674_DRAW_CHARACTER_MEMBER(adm11_state::draw_character)
for (int i = 0; i < 9; i++)
{
- bitmap.pix32(y, x++) = BIT(dots, 8) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y, x++) = BIT(dots, 8) ? rgb_t::white() : rgb_t::black();
dots <<= 1;
}
}
diff --git a/src/mame/drivers/aleck64.cpp b/src/mame/drivers/aleck64.cpp
index 48eb265d078..b0d380bffe0 100644
--- a/src/mame/drivers/aleck64.cpp
+++ b/src/mame/drivers/aleck64.cpp
@@ -1085,10 +1085,6 @@ uint32_t aleck64_state::screen_update_e90(screen_device &screen, bitmap_rgb32 &b
for(int offs=0;offs<0x1000/4;offs+=2)
{
- int xi,yi;
- int r,g,b;
- int pal_offs;
- int pal_shift;
// 0x400 is another enable? end code if off?
//uint16_t tile = m_e90_vram[offs] >> 16;
@@ -1113,28 +1109,26 @@ uint32_t aleck64_state::screen_update_e90(screen_device &screen, bitmap_rgb32 &b
// some pieces needs this color adjustment (see T piece / 5 block version of I piece)
pal |= (attr & 0xc0) >> 4;
- for(yi=0;yi<8;yi++)
+ for(int yi=0;yi<8;yi++)
{
- for(xi=0;xi<8;xi++)
+ for(int xi=0;xi<8;xi++)
{
- int res_x,res_y;
- uint16_t raw_rgb;
- res_x = x+xi + 4;
- res_y = (y & 0xff)+yi + 7;
+ int res_x = x+xi + 4;
+ int res_y = (y & 0xff)+yi + 7;
- pal_offs = (pal*0x10);
+ int pal_offs = (pal*0x10);
pal_offs+= pal_table[xi+yi*8];
- pal_shift = pal_offs & 1 ? 0 : 16;
- raw_rgb = m_e90_pal[pal_offs>>1] >> pal_shift;
- r = (raw_rgb & 0x001f) >> 0;
- g = (raw_rgb & 0x03e0) >> 5;
- b = (raw_rgb & 0x7c00) >> 10;
+ int pal_shift = pal_offs & 1 ? 0 : 16;
+ uint16_t raw_rgb = m_e90_pal[pal_offs>>1] >> pal_shift;
+ int r = (raw_rgb & 0x001f) >> 0;
+ int g = (raw_rgb & 0x03e0) >> 5;
+ int b = (raw_rgb & 0x7c00) >> 10;
r = pal5bit(r);
g = pal5bit(g);
b = pal5bit(b);
if(cliprect.contains(res_x, res_y))
- bitmap.pix32(res_y, res_x) = r << 16 | g << 8 | b;
+ bitmap.pix(res_y, res_x) = r << 16 | g << 8 | b;
}
}
}
diff --git a/src/mame/drivers/alesis.cpp b/src/mame/drivers/alesis.cpp
index 36759cd6af8..1b02744e3bb 100644
--- a/src/mame/drivers/alesis.cpp
+++ b/src/mame/drivers/alesis.cpp
@@ -411,7 +411,7 @@ HD44780_PIXEL_UPDATE(alesis_state::sr16_pixel_update)
if (line == 1 && pos >= 6 && pos < 8) // last 2 characters of the second line are used to control the LCD symbols
update_lcd_symbols(bitmap, pos, y, x, state);
else if (pos < 8)
- bitmap.pix16(line*9 + y, pos*6 + x) = state;
+ bitmap.pix(line*9 + y, pos*6 + x) = state;
}
void alesis_state::hr16(machine_config &config)
diff --git a/src/mame/drivers/alfaskop41xx.cpp b/src/mame/drivers/alfaskop41xx.cpp
index 30bb0733266..103f9897616 100644
--- a/src/mame/drivers/alfaskop41xx.cpp
+++ b/src/mame/drivers/alfaskop41xx.cpp
@@ -285,14 +285,14 @@ template <unsigned N> void alfaskop4110_state::irq_w(int state)
/* Simplified chargen, no attributes or special formats/features yet */
MC6845_UPDATE_ROW( alfaskop4110_state::crtc_update_row )
{
- offs_t base = ma + 0x4000;
- u32 *px = &bitmap.pix32(y);
+ offs_t const base = ma + 0x4000;
+ u32 *px = &bitmap.pix(y);
for (int i = 0; i < x_count; i++)
{
u8 chr = m_vram[(base + i) & 0x07ff] & 0x7f;
- rgb_t bg = rgb_t::white();
- rgb_t fg = rgb_t::black();
+ rgb_t const bg = rgb_t::white();
+ rgb_t const fg = rgb_t::black();
u8 dots = m_chargen[chr * 16 + ra];
diff --git a/src/mame/drivers/alg.cpp b/src/mame/drivers/alg.cpp
index 73189abc79e..9e42a1ce7e5 100644
--- a/src/mame/drivers/alg.cpp
+++ b/src/mame/drivers/alg.cpp
@@ -30,7 +30,6 @@
#include "machine/ldp1450.h"
#include "machine/nvram.h"
#include "machine/amigafdc.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/alinvade.cpp b/src/mame/drivers/alinvade.cpp
index ce86f28db3a..a13baceb064 100644
--- a/src/mame/drivers/alinvade.cpp
+++ b/src/mame/drivers/alinvade.cpp
@@ -177,23 +177,19 @@ void alinvade_state::machine_reset()
uint32_t alinvade_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- int i;
-
uint8_t x = (offs << 3)&0x7f;
int y = (offs >> 4)&0x7f;
uint8_t data = m_videoram[offs];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
pen_t pen = (data & 0x01) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- data = data >> 1;
- x = x + 1;
+ data >>= 1;
+ x++;
}
}
diff --git a/src/mame/drivers/alphajuno.cpp b/src/mame/drivers/alphajuno.cpp
index 95800a634b9..13f09295084 100644
--- a/src/mame/drivers/alphajuno.cpp
+++ b/src/mame/drivers/alphajuno.cpp
@@ -58,7 +58,7 @@ void alphajuno_state::machine_reset()
HD44780_PIXEL_UPDATE(alphajuno_state::lcd_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 8)
- bitmap.pix16(y, (line * 8 + pos) * 6 + x) = state;
+ bitmap.pix(y, (line * 8 + pos) * 6 + x) = state;
}
diff --git a/src/mame/drivers/alphatpx.cpp b/src/mame/drivers/alphatpx.cpp
index 08a9c361569..68a3936f12c 100644
--- a/src/mame/drivers/alphatpx.cpp
+++ b/src/mame/drivers/alphatpx.cpp
@@ -903,31 +903,31 @@ static const gfx_layout extcharlayout =
u32 alphatp_12_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const pen_t *pen = m_palette->pens();
- int start = m_crtc->upscroll_offset();
+ pen_t const *const pen = m_palette->pens();
+ int const start = m_crtc->upscroll_offset();
rectangle cursor;
m_crtc->cursor_bounds(cursor);
for (int y = 0; y < 24; y++)
{
- int vramy = (start + y) % 24;
+ int const vramy = (start + y) % 24;
for (int x = 0; x < 80; x++)
{
u8 code = m_vram[(vramy * 128) + x]; // helwie44 must be 128d is 080h physical display-ram step line
// draw 12 lines of the character
- bool cursoren = cursor.contains(x * 8, y * 12);
+ bool const cursoren = cursor.contains(x * 8, y * 12);
for (int line = 0; line < 12; line++)
{
u8 data = m_gfx[((code & 0x7f) * 16) + line];
if (cursoren)
data ^= 0xff;
- bitmap.pix32(y * 12 + line, x * 8 + 0) = pen[BIT(data, 0) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 1) = pen[BIT(data, 1) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 2) = pen[BIT(data, 2) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 3) = pen[BIT(data, 3) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 4) = pen[BIT(data, 4) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 5) = pen[BIT(data, 5) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 6) = pen[BIT(data, 6) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 7) = pen[BIT(data, 7) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 0) = pen[BIT(data, 0) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 1) = pen[BIT(data, 1) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 2) = pen[BIT(data, 2) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 3) = pen[BIT(data, 3) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 4) = pen[BIT(data, 4) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 5) = pen[BIT(data, 5) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 6) = pen[BIT(data, 6) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 7) = pen[BIT(data, 7) ^ BIT(code, 7)];
}
}
}
@@ -945,23 +945,23 @@ GFXDECODE_END
u32 alphatp_34_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const pen_t *pen = m_palette->pens();
- int start = m_crtc->upscroll_offset();
+ pen_t const *const pen = m_palette->pens();
+ int const start = m_crtc->upscroll_offset();
rectangle cursor;
m_crtc->cursor_bounds(cursor);
- bool scrext = m_scncfg->read() ? true : false;
+ bool const scrext = m_scncfg->read() ? true : false;
for (int y = 0; y < 24; y++)
{
- int vramy = (start + y) % 24;
+ int const vramy = (start + y) % 24;
for (int x = 0; x < 80; x++)
{
u8 code = m_vram[(vramy * 128) + x]; // helwie44 must be 128d is 080h physical display-ram step line
// draw 12 lines of the character
- bool cursoren = cursor.contains(x * 8, y * 12);
+ bool const cursoren = cursor.contains(x * 8, y * 12);
for (int line = 0; line < 12; line++)
{
u8 data = 0;
- if(scrext)
+ if (scrext)
{
offs_t offset = (((vramy * 12) + line) * 80) + x;
if(offset < (371 * 80))
@@ -974,14 +974,14 @@ u32 alphatp_34_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
if (cursoren)
data ^= 0xff;
}
- bitmap.pix32(y * 12 + line, x * 8 + 0) = pen[BIT(data, 0) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 1) = pen[BIT(data, 1) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 2) = pen[BIT(data, 2) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 3) = pen[BIT(data, 3) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 4) = pen[BIT(data, 4) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 5) = pen[BIT(data, 5) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 6) = pen[BIT(data, 6) ^ BIT(code, 7)];
- bitmap.pix32(y * 12 + line, x * 8 + 7) = pen[BIT(data, 7) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 0) = pen[BIT(data, 0) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 1) = pen[BIT(data, 1) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 2) = pen[BIT(data, 2) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 3) = pen[BIT(data, 3) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 4) = pen[BIT(data, 4) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 5) = pen[BIT(data, 5) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 6) = pen[BIT(data, 6) ^ BIT(code, 7)];
+ bitmap.pix(y * 12 + line, x * 8 + 7) = pen[BIT(data, 7) ^ BIT(code, 7)];
}
}
}
diff --git a/src/mame/drivers/alphatro.cpp b/src/mame/drivers/alphatro.cpp
index 0070adcf3d6..912dc35452f 100644
--- a/src/mame/drivers/alphatro.cpp
+++ b/src/mame/drivers/alphatro.cpp
@@ -340,22 +340,19 @@ void alphatro_state::portf0_w(uint8_t data)
MC6845_UPDATE_ROW( alphatro_state::crtc_update_row )
{
- const rgb_t *pens = m_palette->palette()->entry_list_raw();
+ rgb_t const *const pens = m_palette->palette()->entry_list_raw();
bool palette = BIT(m_config->read(), 5);
if (y==0) m_flashcnt++;
- bool inv;
- u8 chr,gfx,attr,bg,fg;
- u16 mem,x;
- u32 *p = &bitmap.pix32(y);
+ u32 *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- inv = (x == cursor_x);
- mem = (ma + x) & 0x7ff;
- chr = m_p_videoram[mem];
- attr = m_p_videoram[mem | 0x800];
- bg = (palette) ? 8 : attr & 7; // amber or RGB
- fg = (palette) ? 0 : (attr & 0x38) >> 3;
+ bool inv = (x == cursor_x);
+ u16 mem = (ma + x) & 0x7ff;
+ u8 chr = m_p_videoram[mem];
+ u8 attr = m_p_videoram[mem | 0x800];
+ u8 bg = (palette) ? 8 : attr & 7; // amber or RGB
+ u8 fg = (palette) ? 0 : (attr & 0x38) >> 3;
if (BIT(attr, 7)) // reverse video
{
@@ -369,7 +366,7 @@ MC6845_UPDATE_ROW( alphatro_state::crtc_update_row )
}
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<4) | ra];
+ u8 gfx = m_p_chargen[(chr<<4) | ra];
if (inv)
{
diff --git a/src/mame/drivers/amust.cpp b/src/mame/drivers/amust.cpp
index 1c7d01dd4d8..e62018b31fa 100644
--- a/src/mame/drivers/amust.cpp
+++ b/src/mame/drivers/amust.cpp
@@ -85,6 +85,7 @@ ToDo:
#include "bus/rs232/rs232.h"
#include "machine/upd765.h"
#include "sound/beep.h"
+#include "machine/timer.h"
#include "video/mc6845.h"
#include "emupal.h"
#include "screen.h"
@@ -106,16 +107,12 @@ public:
, m_fdc (*this, "fdc")
, m_floppy0(*this, "fdc:0")
, m_floppy1(*this, "fdc:1")
+ , m_beep_timer(*this, "beep_timer")
{ }
void amust(machine_config &config);
private:
- enum
- {
- TIMER_BEEP_OFF
- };
-
u8 port04_r();
void port04_w(u8 data);
u8 port05_r();
@@ -133,6 +130,7 @@ private:
DECLARE_WRITE_LINE_MEMBER(intrq_w);
void kbd_put(u8 data);
MC6845_UPDATE_ROW(crtc_update_row);
+ TIMER_DEVICE_CALLBACK_MEMBER(beep_timer);
void io_map(address_map &map);
void mem_map(address_map &map);
@@ -151,7 +149,6 @@ private:
bool m_hsync;
bool m_vsync;
std::unique_ptr<u8[]> m_vram;
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
memory_passthrough_handler *m_rom_shadow_tap;
required_device<palette_device> m_palette;
required_device<cpu_device> m_maincpu;
@@ -163,18 +160,12 @@ private:
required_device<upd765a_device> m_fdc;
required_device<floppy_connector> m_floppy0;
required_device<floppy_connector> m_floppy1;
+ required_device<timer_device> m_beep_timer;
};
-void amust_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_DEVICE_CALLBACK_MEMBER(amust_state::beep_timer)
{
- switch (id)
- {
- case TIMER_BEEP_OFF:
- m_beep->set_state(0);
- break;
- default:
- throw emu_fatalerror("Unknown id in amust_state::device_timer");
- }
+ m_beep->set_state(0);
}
//void amust_state::port00_w(u8 data)
@@ -346,7 +337,7 @@ void amust_state::port0a_w(u8 data)
if (!BIT(data, 4))
{
m_beep->set_state(1);
- timer_set(attotime::from_msec(150), TIMER_BEEP_OFF);
+ m_beep_timer->adjust(attotime::from_msec(150));
}
floppy_image_device *floppy = m_floppy0->get_device();
m_fdc->set_floppy(floppy);
@@ -384,16 +375,15 @@ GFXDECODE_END
MC6845_UPDATE_ROW( amust_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx,inv;
- u16 mem,x;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u32 *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- inv = (x == cursor_x) ? 0xff : 0;
- mem = (ma + x) & 0x7ff;
- chr = m_vram[mem];
+ u8 inv = (x == cursor_x) ? 0xff : 0;
+ u16 mem = (ma + x) & 0x7ff;
+ u8 chr = m_vram[mem];
+ u8 gfx;
if (ra < 8)
gfx = m_p_chargen[(chr<<3) | ra] ^ inv;
else
@@ -481,6 +471,7 @@ void amust_state::amust(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
BEEP(config, m_beep, 800).add_route(ALL_OUTPUTS, "mono", 0.50);
+ TIMER(config, m_beep_timer).configure_generic(FUNC(amust_state::beep_timer));
/* Devices */
hd6845s_device &crtc(HD6845S(config, "crtc", XTAL(14'318'181) / 8));
diff --git a/src/mame/drivers/apc.cpp b/src/mame/drivers/apc.cpp
index 9c010c25bbb..cf3686b1730 100644
--- a/src/mame/drivers/apc.cpp
+++ b/src/mame/drivers/apc.cpp
@@ -207,51 +207,38 @@ UPD7220_DISPLAY_PIXELS_MEMBER( apc_state::hgdc_display_pixels )
UPD7220_DRAW_TEXT_LINE_MEMBER( apc_state::hgdc_draw_text )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int xi,yi,yi_trans;
- int x;
- uint8_t char_size;
-// uint8_t interlace_on;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
// if(m_video_ff[DISPLAY_REG] == 0) //screen is off
// return;
-// interlace_on = m_video_reg[2] == 0x10; /* TODO: correct? */
- char_size = 19;
+// uint8_t interlace_on = m_video_reg[2] == 0x10; /* TODO: correct? */
+ uint8_t char_size = 19;
- for(x=0;x<pitch;x++)
+ for(int x=0;x<pitch;x++)
{
- uint8_t tile_data;
- uint8_t u_line, o_line, v_line, reverse, blink;
- uint8_t color;
- uint8_t tile,attr,pen;
- uint32_t tile_addr;
- uint8_t tile_sel;
-
-// tile_addr = addr+(x*(m_video_ff[WIDTH40_REG]+1));
- tile_addr = addr+(x*(1));
-
- tile = (m_video_ram_1[((tile_addr*2) & 0x1fff) >> 1] >> 8) & 0x00ff;
- tile_sel = m_video_ram_1[((tile_addr*2) & 0x1fff) >> 1] & 0x00ff;
- attr = (m_video_ram_1[((tile_addr*2 & 0x1fff) | 0x2000) >> 1] & 0x00ff);
-
- u_line = attr & 0x01;
- o_line = attr & 0x02;
- v_line = attr & 0x04;
- blink = attr & 0x08;
- reverse = attr & 0x10;
+// uint32_t tile_addr = addr+(x*(m_video_ff[WIDTH40_REG]+1));
+ uint32_t tile_addr = addr+(x*(1));
+
+ uint8_t tile = (m_video_ram_1[((tile_addr*2) & 0x1fff) >> 1] >> 8) & 0x00ff;
+ uint8_t tile_sel = m_video_ram_1[((tile_addr*2) & 0x1fff) >> 1] & 0x00ff;
+ uint8_t attr = (m_video_ram_1[((tile_addr*2 & 0x1fff) | 0x2000) >> 1] & 0x00ff);
+
+ uint8_t u_line = attr & 0x01;
+ uint8_t o_line = attr & 0x02;
+ uint8_t v_line = attr & 0x04;
+ uint8_t blink = attr & 0x08;
+ uint8_t reverse = attr & 0x10;
// secret= (attr & 1) ^ 1;
- color = (attr & 0xe0) >> 5;
+ uint8_t color = (attr & 0xe0) >> 5;
- for(yi=0;yi<lr;yi++)
+ for(int yi=0;yi<lr;yi++)
{
- yi_trans = (yi==0)?lr-1:yi-1;
- for(xi=0;xi<8;xi++)
+ int yi_trans = (yi==0)?lr-1:yi-1;
+ for(int xi=0;xi<8;xi++)
{
- int res_x,res_y;
-
- res_x = (x*8+xi);
- res_y = y+yi;
+ int res_x = (x*8+xi);
+ int res_y = y+yi;
if(!m_screen->visible_area().contains(res_x, res_y))
continue;
@@ -272,6 +259,7 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( apc_state::hgdc_draw_text )
Data bus: 76543210 = pixels, in left->01234567->right order
*/
+ uint8_t tile_data;
if(tile_sel == 0x89)// Aux character RAM select TODO: correct triggering?
{
if(yi & 0x10)
@@ -291,13 +279,14 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( apc_state::hgdc_draw_text )
if(cursor_on && cursor_addr == tile_addr && m_screen->frame_number() & 0x10)
tile_data^=0xff;
+ uint8_t pen;
if(yi >= char_size)
pen = 0;
else
pen = (tile_data >> (xi) & 1) ? color : 0;
if(pen)
- bitmap.pix32(res_y, res_x) = palette[pen];
+ bitmap.pix(res_y, res_x) = palette[pen];
}
}
}
diff --git a/src/mame/drivers/apf.cpp b/src/mame/drivers/apf.cpp
index d04c8e164a7..66fcf6af6b8 100644
--- a/src/mame/drivers/apf.cpp
+++ b/src/mame/drivers/apf.cpp
@@ -34,6 +34,16 @@ RAM switch
- Basic will work with 8K or 16K.
+The monitor
+-----------
+From Basic, do CALL 28672 to enter the monitor - you get a * prompt. Commands:
+D nnnn - display memory
+G nnnn - goto an address
+M nnnn - modify memory
+Type the command letter, then all 4 digits, no need to hit Enter.
+To exit back to Basic, do G 8894 (Basic has no prompt).
+
+
Status of cart-based games
--------------------------
backgammon - works, needs offset of 0x120, bottom line is coming from 0x3E0, should be 0x380
diff --git a/src/mame/drivers/apogee.cpp b/src/mame/drivers/apogee.cpp
index e89e0ba03b0..6284114c8e6 100644
--- a/src/mame/drivers/apogee.cpp
+++ b/src/mame/drivers/apogee.cpp
@@ -153,7 +153,7 @@ static INPUT_PORTS_START( apogee )
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Rus/Lat") PORT_CODE(KEYCODE_LALT) PORT_CODE(KEYCODE_RALT)
INPUT_PORTS_END
-static const int16_t speaker_levels[] = {-32767, -10922, 10922, 32767};
+static const double speaker_levels[] = {-1.0, -0.33333, 0.33333, 1.0};
WRITE_LINE_MEMBER(apogee_state::pit8253_out0_changed)
{
@@ -216,7 +216,7 @@ I8275_DRAW_CHARACTER_MEMBER(apogee_state::display_pixels)
pixels ^= 0xff;
for(int i=0;i<6;i++)
- bitmap.pix32(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
+ bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}
/* F4 Character Displayer */
diff --git a/src/mame/drivers/apple1.cpp b/src/mame/drivers/apple1.cpp
index 5cf5e9c3e95..cdc46753200 100644
--- a/src/mame/drivers/apple1.cpp
+++ b/src/mame/drivers/apple1.cpp
@@ -324,24 +324,21 @@ void apple1_state::poll_keyboard()
void apple1_state::plot_text_character(bitmap_ind16 &bitmap, int xpos, int ypos, int xscale, uint32_t code,
const uint8_t *textgfx_data, uint32_t textgfx_datalen)
{
- int x, y, i;
- const uint8_t *chardata;
- uint16_t color;
int fg = 1, bg = 0;
- int charcode = (code & 0x1f) | (((code ^ 0x40) & 0x40) >> 1);
+ int const charcode = (code & 0x1f) | (((code ^ 0x40) & 0x40) >> 1);
/* look up the character data */
- chardata = &textgfx_data[(charcode * 8)];
+ uint8_t const *const chardata = &textgfx_data[(charcode * 8)];
- for (y = 0; y < 8; y++)
+ for (int y = 0; y < 8; y++)
{
- for (x = 0; x < 7; x++)
+ for (int x = 0; x < 7; x++)
{
- color = (chardata[y] & (1 << (6-x))) ? fg : bg;
+ uint16_t const color = (chardata[y] & (1 << (6-x))) ? fg : bg;
- for (i = 0; i < xscale; i++)
+ for (int i = 0; i < xscale; i++)
{
- bitmap.pix16(ypos + y, xpos + (x * xscale) + i) = color;
+ bitmap.pix(ypos + y, xpos + (x * xscale) + i) = color;
}
}
}
diff --git a/src/mame/drivers/apple2.cpp b/src/mame/drivers/apple2.cpp
index 48df76ff6b4..2f33aeece2c 100644
--- a/src/mame/drivers/apple2.cpp
+++ b/src/mame/drivers/apple2.cpp
@@ -803,14 +803,11 @@ void apple2_state::inh_w(offs_t offset, uint8_t data)
}
}
-// floating bus code from old machine/apple2: needs to be reworked based on real beam position to enable e.g. Bob Bishop's screen splitter
+// floating bus code from old machine/apple2: now works reasonably well with French Touch and Deater "vapor lock" stuff
uint8_t apple2_state::read_floatingbus()
{
enum
{
- // scanner types
- kScannerNone = 0, kScannerApple2, kScannerApple2e,
-
// scanner constants
kHBurstClock = 53, // clock when Color Burst starts
kHBurstClocks = 4, // clocks per Color Burst duration
@@ -855,8 +852,7 @@ uint8_t apple2_state::read_floatingbus()
// ScanCycles = ScanLines * kHClocks;
// calculate horizontal scanning state
- //
- h_clock = (i + kHPEClock) % kHClocks; // which horizontal scanning clock
+ h_clock = (i + 63) % kHClocks; // which horizontal scanning clock
h_state = kHClock0State + h_clock; // H state bits
if (h_clock >= kHPresetClock) // check for horizontal preset
{
@@ -871,7 +867,7 @@ uint8_t apple2_state::read_floatingbus()
// calculate vertical scanning state
//
- v_line = (i / kHClocks) + 188; // which vertical scanning line
+ v_line = (i / kHClocks) + 192; // which vertical scanning line
v_state = kVLine0State + v_line; // V state bits
if ((v_line >= kVPresetLine)) // check for previous vertical state preset
{
@@ -922,15 +918,14 @@ uint8_t apple2_state::read_floatingbus()
{
// N: text, so no higher address bits unless Apple ][, not Apple //e
//
- if ((1) && // Apple ][? // FIX: check for Apple ][? (FB is most useful in old games)
- (kHPEClock <= h_clock) && // Y: HBL?
+ if ((kHPEClock <= h_clock) && // Y: HBL?
(h_clock <= (kHClocks - 1)))
{
address |= 1 << 12; // Y: a12 (add $1000 to address!)
}
}
- return m_ram_ptr[address % m_ram_size]; // FIX: this seems to work, but is it right!?
+ return m_ram_ptr[address % m_ram_size];
}
/***************************************************************************
@@ -1063,6 +1058,15 @@ WRITE_LINE_MEMBER(apple2_state::ay3600_data_ready_w)
if (state == ASSERT_LINE)
{
int mod = 0;
+
+ // if the user presses a valid key to start the driver from the info screen,
+ // we will see that key. ignore keys in the first 25,000 cycles (in my tests,
+ // the unwanted key shows up at 17030 cycles)
+ if (m_maincpu->total_cycles() < 25000)
+ {
+ return;
+ }
+
m_lastchar = m_ay3600->b_r();
mod = (m_kbspecial->read() & 0x06) ? 0x01 : 0x00;
@@ -1344,7 +1348,7 @@ void apple2_state::apple2_common(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
- SPEAKER_SOUND(config, A2_SPEAKER_TAG).add_route(ALL_OUTPUTS, "mono", 1.00);
+ SPEAKER_SOUND(config, A2_SPEAKER_TAG).add_route(ALL_OUTPUTS, "mono", 0.4);
/* /INH banking */
ADDRESS_MAP_BANK(config, A2_UPPERBANK_TAG).set_map(&apple2_state::inhbank_map).set_options(ENDIANNESS_LITTLE, 8, 32, 0x3000);
diff --git a/src/mame/drivers/apple2e.cpp b/src/mame/drivers/apple2e.cpp
index 891e8dbe22c..4a244d12f2f 100644
--- a/src/mame/drivers/apple2e.cpp
+++ b/src/mame/drivers/apple2e.cpp
@@ -176,6 +176,7 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele
#include "bus/a2bus/byte8251.h"
#include "bus/a2bus/a2iwm.h"
#include "bus/a2bus/uthernet.h"
+#include "bus/a2bus/sider.h"
#include "bus/a2gameio/gameio.h"
#include "bus/rs232/rs232.h"
@@ -187,7 +188,6 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele
#include "formats/ap2_dsk.h"
#include "formats/ap_dsk35.h"
-
#define A2_CPU_TAG "maincpu"
#define A2_KBDC_TAG "ay3600"
#define A2_BUS_TAG "a2bus"
@@ -271,6 +271,13 @@ public:
m_ds1315(*this, "nsc")
{
m_accel_laser = false;
+ m_isiic = false;
+ m_isiicplus = false;
+ m_iscec = false;
+ m_iscecm = false;
+ m_iscec2000 = false;
+ m_spectrum_text = false;
+ m_pal = false;
}
required_device<cpu_device> m_maincpu;
@@ -402,10 +409,12 @@ public:
void cec(machine_config &config);
void mprof3(machine_config &config);
void apple2e(machine_config &config);
+ void apple2epal(machine_config &config);
void apple2ep(machine_config &config);
void apple2c(machine_config &config);
void tk3000(machine_config &config);
void apple2ee(machine_config &config);
+ void apple2eepal(machine_config &config);
void apple2c_map(address_map &map);
void apple2c_memexp_map(address_map &map);
void apple2e_map(address_map &map);
@@ -425,6 +434,7 @@ public:
void spectred_keyb_map(address_map &map);
void init_128ex();
void init_spect();
+ void init_pal();
bool m_35sel, m_hdsel, m_intdrive;
@@ -466,7 +476,7 @@ private:
bool m_mockingboard4c;
bool m_intc8rom;
- bool m_isiic, m_isiicplus, m_iscec, m_iscecm, m_iscec2000, m_spectrum_text;
+ bool m_isiic, m_isiicplus, m_iscec, m_iscecm, m_iscec2000, m_spectrum_text, m_pal;
uint8_t m_migram[0x800];
uint16_t m_migpage;
@@ -1014,6 +1024,8 @@ void apple2e_state::machine_reset()
m_slotc3rom = false;
m_romswitch = false;
m_irqmask = 0;
+ m_strobe = 0;
+ m_transchar = 0;
m_anykeydown = false;
m_repeatdelay = 10;
m_xy = false;
@@ -1105,6 +1117,11 @@ void apple2e_state::init_spect()
m_spectrum_text = true;
}
+void apple2e_state::init_pal()
+{
+ m_pal = true;
+}
+
void apple2e_state::raise_irq(int irq)
{
m_irqmask |= (1 << irq);
@@ -1760,7 +1777,7 @@ void apple2e_state::do_io(int offset, bool is_iic)
uint8_t apple2e_state::c000_r(offs_t offset)
{
if(machine().side_effects_disabled()) return read_floatingbus();
- u8 uFloatingBus7 = read_floatingbus() & 0x7f;
+ const u8 uFloatingBus7 = read_floatingbus() & 0x7f;
if ((offset & 0xf0) == 0x00) // keyboard latch, $C000 is really 00-0F
{
@@ -2153,7 +2170,7 @@ uint8_t apple2e_state::c000_iic_r(offs_t offset)
return m_y0edge ? 0x80 : 0x00;
case 0x60: // 40/80 column switch (IIc only)
- return ((m_sysconfig->read() & 0x04) ? 0x80 : 0) | uFloatingBus7;
+ return ((m_sysconfig->read() & 0x40) ? 0x80 : 0) | uFloatingBus7;
case 0x61: // button 0 or Open Apple or mouse button 1
case 0x69:
@@ -2362,7 +2379,7 @@ void apple2e_state::update_iic_mouse()
{
int new_mx, new_my;
- // read the axes
+ // read the axes and check for changes
new_mx = m_mousex->read();
new_my = m_mousey->read();
@@ -2373,9 +2390,16 @@ void apple2e_state::update_iic_mouse()
/* check for wrap */
if (diff > 0x80)
- diff = 0x100-diff;
- if (diff < -0x80)
- diff = -0x100-diff;
+ {
+ diff -= 0x100;
+ }
+ else
+ {
+ if (diff < -0x80)
+ {
+ diff += 0x100;
+ }
+ }
count_x += diff;
last_mx = new_mx;
@@ -2388,9 +2412,16 @@ void apple2e_state::update_iic_mouse()
/* check for wrap */
if (diff > 0x80)
- diff = 0x100-diff;
- if (diff < -0x80)
- diff = -0x100-diff;
+ {
+ diff -= 0x100;
+ }
+ else
+ {
+ if (diff < -0x80)
+ {
+ diff += 0x100;
+ }
+ }
count_y += diff;
last_my = new_my;
@@ -2895,14 +2926,11 @@ void apple2e_state::lc_w(offs_t offset, uint8_t data)
}
}
-// floating bus code from old machine/apple2: needs to be reworked based on real beam position to enable e.g. Bob Bishop's screen splitter
+// floating bus code from old machine/apple2: now works reasonably well with French Touch and Deater "vapor lock" stuff
uint8_t apple2e_state::read_floatingbus()
{
enum
{
- // scanner types
- kScannerNone = 0, kScannerApple2, kScannerApple2e,
-
// scanner constants
kHBurstClock = 53, // clock when Color Burst starts
kHBurstClocks = 4, // clocks per Color Burst duration
@@ -2919,9 +2947,10 @@ uint8_t apple2e_state::read_floatingbus()
kVLine0State = 0x100, // V[543210CBA] = 100000000
kVPresetLine = 256, // line when V state presets
kVSyncLines = 4, // lines per VSync duration
- kClocksPerVSync = kHClocks * kNTSCScanLines // FIX: NTSC only?
};
+ const int kClocksPerVSync = kHClocks * (m_pal ? kPALScanLines : kNTSCScanLines);
+
// vars
//
int i, Hires, Mixed, Page2, _80Store, ScanLines, /* VSyncLine, ScanCycles,*/
@@ -2941,14 +2970,11 @@ uint8_t apple2e_state::read_floatingbus()
_80Store = m_80store ? 1 : 0;
// calculate video parameters according to display standard
- //
- ScanLines = 1 ? kNTSCScanLines : kPALScanLines; // FIX: NTSC only?
- // VSyncLine = 1 ? kNTSCVSyncLine : kPALVSyncLine; // FIX: NTSC only?
- // ScanCycles = ScanLines * kHClocks;
+ // we call this "PAL", but it's also for SECAM
+ ScanLines = m_pal ? kPALScanLines : kNTSCScanLines;
// calculate horizontal scanning state
- //
- h_clock = (i + kHPEClock) % kHClocks; // which horizontal scanning clock
+ h_clock = (i + 63) % kHClocks; // which horizontal scanning clock
h_state = kHClock0State + h_clock; // H state bits
if (h_clock >= kHPresetClock) // check for horizontal preset
{
@@ -2963,7 +2989,7 @@ uint8_t apple2e_state::read_floatingbus()
// calculate vertical scanning state
//
- v_line = (i / kHClocks) + 188; // which vertical scanning line (MAME starts at blank, not the beginning of the scanning area)
+ v_line = (i / kHClocks) + 192; // which vertical scanning line (MAME starts at blank, not the beginning of the scanning area)
v_state = kVLine0State + v_line; // V state bits
if ((v_line >= kVPresetLine)) // check for previous vertical state preset
{
@@ -3010,19 +3036,8 @@ uint8_t apple2e_state::read_floatingbus()
address |= (1 ^ (Page2 & (1 ^ _80Store))) << 13; // a13
address |= (Page2 & (1 ^ _80Store)) << 14; // a14
}
- else
- {
- // N: text, so no higher address bits unless Apple ][, not Apple //e
- //
- if ((1) && // Apple ][? // FIX: check for Apple ][? (FB is most useful in old games)
- (kHPEClock <= h_clock) && // Y: HBL?
- (h_clock <= (kHClocks - 1)))
- {
- address |= 1 << 12; // Y: a12 (add $1000 to address!)
- }
- }
- return m_ram_ptr[address % m_ram_size]; // FIX: this seems to work, but is it right!?
+ return m_ram_ptr[address % m_ram_size];
}
/***************************************************************************
@@ -3290,6 +3305,14 @@ WRITE_LINE_MEMBER(apple2e_state::ay3600_data_ready_w)
uint8_t *decode = m_kbdrom->base();
uint16_t trans;
+ // if the user presses a valid key to start the driver from the info screen,
+ // we will see that key. ignore keys in the first 25,000 cycles (in my tests,
+ // the unwanted key shows up at 17030 cycles)
+ if (m_maincpu->total_cycles() < 25000)
+ {
+ return;
+ }
+
m_lastchar = m_ay3600->b_r();
trans = m_lastchar & ~(0x1c0); // clear the 3600's control/shift stuff
@@ -3309,7 +3332,7 @@ WRITE_LINE_MEMBER(apple2e_state::ay3600_data_ready_w)
if (m_isiic)
{
- if (m_sysconfig->read() & 0x08)
+ if (m_sysconfig->read() & 0x80)
{
trans += 0x400; // go to DVORAK half of the ROM
}
@@ -3381,17 +3404,18 @@ INPUT_PORTS_END
static INPUT_PORTS_START( apple2c_sysconfig )
PORT_START("a2_config")
- PORT_CONFNAME(0x03, 0x00, "Composite monitor type")
+ PORT_CONFNAME(0x07, 0x00, "Composite monitor type")
PORT_CONFSETTING(0x00, "Color")
PORT_CONFSETTING(0x01, "B&W")
PORT_CONFSETTING(0x02, "Green")
PORT_CONFSETTING(0x03, "Amber")
- PORT_CONFNAME(0x04, 0x04, "40/80 Columns")
+
+ PORT_CONFNAME(0x40, 0x40, "40/80 Columns")
PORT_CONFSETTING(0x00, "80 columns")
- PORT_CONFSETTING(0x04, "40 columns")
- PORT_CONFNAME(0x08, 0x00, "QWERTY/DVORAK")
+ PORT_CONFSETTING(0x40, "40 columns")
+ PORT_CONFNAME(0x80, 0x00, "QWERTY/DVORAK")
PORT_CONFSETTING(0x00, "QWERTY")
- PORT_CONFSETTING(0x08, "DVORAK")
+ PORT_CONFSETTING(0x80, "DVORAK")
PORT_CONFNAME(0x10, 0x00, "CPU type")
PORT_CONFSETTING(0x00, "Standard")
@@ -4502,6 +4526,8 @@ static void apple2_cards(device_slot_interface &device)
device.option_add("byte8251", A2BUS_BYTE8251); /* BYTE Magazine 8251 serial card */
device.option_add("cmsscsi", A2BUS_CMSSCSI); /* CMS Apple II SCSI Card */
device.option_add("uthernet", A2BUS_UTHERNET); /* A2RetroSystems Uthernet card */
+ device.option_add("sider2", A2BUS_SIDER2); /* Advanced Tech Systems / First Class Peripherals Sider 2 SASI card */
+ device.option_add("sider1", A2BUS_SIDER1); /* Advanced Tech Systems / First Class Peripherals Sider 1 SASI card */
}
static void apple2eaux_cards(device_slot_interface &device)
@@ -4533,7 +4559,7 @@ void apple2e_state::apple2e(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
- SPEAKER_SOUND(config, A2_SPEAKER_TAG).add_route(ALL_OUTPUTS, "mono", 1.00);
+ SPEAKER_SOUND(config, A2_SPEAKER_TAG).add_route(ALL_OUTPUTS, "mono", 0.4);
/* DS1315 for no-slot clock */
DS1315(config, m_ds1315, 0).read_backing().set(FUNC(apple2e_state::nsc_backing_r));
@@ -4631,6 +4657,12 @@ void apple2e_state::apple2e(machine_config &config)
m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05);
}
+void apple2e_state::apple2epal(machine_config &config)
+{
+ apple2e(config);
+ m_screen->set_raw(1021800*14, (65*7)*2, 0, (40*7)*2, 312, 0, 192);
+}
+
void apple2e_state::mprof3(machine_config &config)
{
apple2e(config);
@@ -4648,6 +4680,12 @@ void apple2e_state::apple2ee(machine_config &config)
m_maincpu->set_dasm_override(FUNC(apple2e_state::dasm_trampoline));
}
+void apple2e_state::apple2eepal(machine_config &config)
+{
+ apple2ee(config);
+ m_screen->set_raw(1021800*14, (65*7)*2, 0, (40*7)*2, 312, 0, 192);
+}
+
void apple2e_state::spectred(machine_config &config)
{
apple2e(config);
@@ -5342,12 +5380,12 @@ ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
COMP( 1983, apple2e, 0, apple2, apple2e, apple2e, apple2e_state, empty_init, "Apple Computer", "Apple //e", MACHINE_SUPPORTS_SAVE )
-COMP( 1983, apple2euk, apple2e, 0, apple2e, apple2euk, apple2e_state, empty_init, "Apple Computer", "Apple //e (UK)", MACHINE_SUPPORTS_SAVE )
-COMP( 1983, apple2ees, apple2e, 0, apple2e, apple2ees, apple2e_state, empty_init, "Apple Computer", "Apple //e (Spain)", MACHINE_SUPPORTS_SAVE )
+COMP( 1983, apple2euk, apple2e, 0, apple2epal, apple2euk, apple2e_state, init_pal, "Apple Computer", "Apple //e (UK)", MACHINE_SUPPORTS_SAVE )
+COMP( 1983, apple2ees, apple2e, 0, apple2epal, apple2ees, apple2e_state, init_pal, "Apple Computer", "Apple //e (Spain)", MACHINE_SUPPORTS_SAVE )
COMP( 1983, mprof3, apple2e, 0, mprof3, apple2e, apple2e_state, empty_init, "Multitech", "Microprofessor III", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
COMP( 1985, apple2ee, apple2e, 0, apple2ee, apple2e, apple2e_state, empty_init, "Apple Computer", "Apple //e (enhanced)", MACHINE_SUPPORTS_SAVE )
-COMP( 1985, apple2eeuk, apple2e, 0, apple2ee, apple2euk, apple2e_state, empty_init, "Apple Computer", "Apple //e (enhanced, UK)", MACHINE_SUPPORTS_SAVE )
-COMP( 1985, apple2eefr, apple2e, 0, apple2ee, apple2efr, apple2e_state, empty_init, "Apple Computer", "Apple //e (enhanced, France)", MACHINE_SUPPORTS_SAVE )
+COMP( 1985, apple2eeuk, apple2e, 0, apple2eepal, apple2euk, apple2e_state, init_pal, "Apple Computer", "Apple //e (enhanced, UK)", MACHINE_SUPPORTS_SAVE )
+COMP( 1985, apple2eefr, apple2e, 0, apple2eepal, apple2efr, apple2e_state, init_pal, "Apple Computer", "Apple //e (enhanced, France)", MACHINE_SUPPORTS_SAVE )
COMP( 1987, apple2ep, apple2e, 0, apple2ep, apple2ep, apple2e_state, empty_init, "Apple Computer", "Apple //e (Platinum)", MACHINE_SUPPORTS_SAVE )
COMP( 1984, apple2c, 0, apple2, apple2c, apple2c, apple2e_state, empty_init, "Apple Computer", "Apple //c" , MACHINE_SUPPORTS_SAVE )
COMP( 1985?,spectred, apple2e, 0, spectred, apple2e, apple2e_state, init_spect, "Scopus/Spectrum", "Spectrum ED" , MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/apple2gs.cpp b/src/mame/drivers/apple2gs.cpp
index 6f9e3e8402b..28f1296e22c 100644
--- a/src/mame/drivers/apple2gs.cpp
+++ b/src/mame/drivers/apple2gs.cpp
@@ -109,6 +109,7 @@
//#include "bus/a2bus/hostram.h"
//#include "bus/a2bus/ramfast.h"
#include "bus/a2bus/uthernet.h"
+#include "bus/a2bus/sider.h"
#include "bus/a2gameio/gameio.h"
@@ -783,6 +784,14 @@ WRITE_LINE_MEMBER(apple2gs_state::ay3600_data_ready_w)
uint8_t *decode = m_kbdrom->base();
uint16_t trans;
+ // if the user presses a valid key to start the driver from the info screen,
+ // we will see that key. ignore keys in the first 25,000 cycles (in my tests,
+ // the unwanted key shows up at 17030 cycles)
+ if (m_maincpu->total_cycles() < 25000)
+ {
+ return;
+ }
+
m_lastchar = m_ay3600->b_r();
trans = m_lastchar & ~(0x1c0); // clear the 3600's control/shift stuff
@@ -1232,10 +1241,11 @@ void apple2gs_state::machine_start()
// setup speaker toggle volumes. this should be done mathematically probably,
// but these ad-hoc values aren't too bad.
- static const int16_t lvlTable[16] =
+#define LVL(x) (double(x) / 32768.0)
+ static const double lvlTable[16] =
{
- 0x0000, 0x03ff, 0x04ff, 0x05ff, 0x06ff, 0x07ff, 0x08ff, 0x09ff,
- 0x0aff, 0x0bff, 0x0cff, 0x0fff, 0x1fff, 0x3fff, 0x5fff, 0x7fff
+ LVL(0x0000), LVL(0x03ff), LVL(0x04ff), LVL(0x05ff), LVL(0x06ff), LVL(0x07ff), LVL(0x08ff), LVL(0x09ff),
+ LVL(0x0aff), LVL(0x0bff), LVL(0x0cff), LVL(0x0fff), LVL(0x1fff), LVL(0x3fff), LVL(0x5fff), LVL(0x7fff)
};
m_speaker->set_levels(16, lvlTable);
@@ -2281,6 +2291,9 @@ uint8_t apple2gs_state::c000_r(offs_t offset)
case 0x31: // DISKREG
return m_diskreg;
+ case 0x32: // VGCINTCLEAR
+ return 0;
+
case 0x33: // CLOCKDATA
return m_clkdata;
@@ -2508,12 +2521,12 @@ void apple2gs_state::c000_w(offs_t offset, uint8_t data)
break;
case 0x23: // VGCINT
- if ((m_vgcint & VGCINT_SECOND) && !(data & VGCINT_SECOND))
+ if ((m_vgcint & VGCINT_SECOND) && !(data & VGCINT_SECONDENABLE))
{
lower_irq(IRQS_SECOND);
m_vgcint &= ~(VGCINT_SECOND);
}
- if ((m_vgcint & VGCINT_SCANLINE) && !(data & VGCINT_SCANLINE))
+ if ((m_vgcint & VGCINT_SCANLINE) && !(data & VGCINT_SCANLINEEN))
{
lower_irq(IRQS_SCAN);
m_vgcint &= ~(VGCINT_SCANLINE);
@@ -2563,14 +2576,14 @@ void apple2gs_state::c000_w(offs_t offset, uint8_t data)
case 0x32: // VGCINTCLEAR
//printf("%02x to VGCINTCLEAR\n", data);
// one second
- if ((m_vgcint & VGCINT_SECOND) && !(data & VGCINT_SECOND))
+ if (m_vgcint & VGCINT_SECOND)
{
lower_irq(IRQS_SECOND);
m_vgcint &= ~(VGCINT_SECOND|VGCINT_ANYVGCINT);
}
// scanline
- if ((m_vgcint & VGCINT_SCANLINE) && !(data & VGCINT_SCANLINE))
+ if (m_vgcint & VGCINT_SCANLINE)
{
lower_irq(IRQS_SCAN);
m_vgcint &= ~(VGCINT_SCANLINE|VGCINT_ANYVGCINT);
@@ -4577,7 +4590,9 @@ static void apple2_cards(device_slot_interface &device)
// device.option_add("hostram", A2BUS_HOSTRAM); /* Slot 7 RAM for GS Plus host protocol */
// device.option_add("ramfast", A2BUS_RAMFAST); /* C.V. Technologies RAMFast SCSI card */
device.option_add("cmsscsi", A2BUS_CMSSCSI); /* CMS Apple II SCSI Card */
- device.option_add("uthernet", A2BUS_UTHERNET); /* CMS Apple II SCSI Card */
+ device.option_add("uthernet", A2BUS_UTHERNET); /* A2RetroSystems Uthernet card */
+ device.option_add("sider2", A2BUS_SIDER2); /* Advanced Tech Systems / First Class Peripherals Sider 2 SASI card */
+ device.option_add("sider1", A2BUS_SIDER1); /* Advanced Tech Systems / First Class Peripherals Sider 1 SASI card */
}
void apple2gs_state::apple2gs(machine_config &config)
diff --git a/src/mame/drivers/apple3.cpp b/src/mame/drivers/apple3.cpp
index c38c1939b74..b0c79838079 100644
--- a/src/mame/drivers/apple3.cpp
+++ b/src/mame/drivers/apple3.cpp
@@ -103,7 +103,7 @@ void apple3_state::apple3(machine_config &config)
m_a2bus->set_space(m_maincpu, AS_PROGRAM);
m_a2bus->irq_w().set(FUNC(apple3_state::a2bus_irq_w));
m_a2bus->nmi_w().set(FUNC(apple3_state::a2bus_nmi_w));
- //m_a2bus->inh_w().set(FUNC(apple3_state::a2bus_inh_w));
+ m_a2bus->inh_w().set(FUNC(apple3_state::a2bus_inh_w));
m_a2bus->dma_w().set_inputline(m_maincpu, INPUT_LINE_HALT);
A2BUS_SLOT(config, "sl1", m_a2bus, apple3_cards, nullptr);
A2BUS_SLOT(config, "sl2", m_a2bus, apple3_cards, nullptr);
@@ -139,6 +139,7 @@ void apple3_state::apple3(machine_config &config)
/* rtc */
MM58167(config, m_rtc, 32.768_kHz_XTAL);
+ m_rtc->irq().set(m_via[1], FUNC(via6522_device::write_ca1));
/* via */
VIA6522(config, m_via[0], 14.318181_MHz_XTAL / 14);
@@ -357,10 +358,10 @@ INPUT_PORTS_END
ROM_START(apple3)
ROM_REGION(0x1000,"maincpu",0)
ROM_SYSTEM_BIOS(0, "original", "Apple /// boot ROM")
- ROMX_LOAD( "apple3.rom", 0x0000, 0x1000, CRC(55e8eec9) SHA1(579ee4cd2b208d62915a0aa482ddc2744ff5e967), ROM_BIOS(1))
+ ROMX_LOAD( "apple3.rom", 0x0000, 0x1000, CRC(55e8eec9) SHA1(579ee4cd2b208d62915a0aa482ddc2744ff5e967), ROM_BIOS(0))
ROM_SYSTEM_BIOS(1, "soshd", "Rob Justice SOSHDBOOT")
- ROMX_LOAD( "soshdboot.bin", 0x000000, 0x001000, CRC(fd5ac9e2) SHA1(ba466a54ddb7f618c4f18f344754343c5945b417), ROM_BIOS(0))
+ ROMX_LOAD( "soshdboot.bin", 0x000000, 0x001000, CRC(fd5ac9e2) SHA1(ba466a54ddb7f618c4f18f344754343c5945b417), ROM_BIOS(1))
ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
diff --git a/src/mame/drivers/applix.cpp b/src/mame/drivers/applix.cpp
index 1c3c9182cdc..14c28072e3a 100644
--- a/src/mame/drivers/applix.cpp
+++ b/src/mame/drivers/applix.cpp
@@ -517,22 +517,22 @@ void applix_state::keytronic_pc3270_io(address_map &map)
/* Input ports */
static INPUT_PORTS_START( applix )
PORT_START( "K0f" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') /* 06 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') /* 05 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T') /* 14 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R') /* 13 */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G') /* 22 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') /* 21 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') /* 06 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') /* 05 */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') /* 14 */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') /* 13 */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') /* 22 */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') /* 21 */
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F7 (IRMA)") /* 41 */
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6a?") /* 6a */
PORT_START( "K30_0" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N') /* 31 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M') /* 32 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') /* 30 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V') /* 2f */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') /* 2e */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') /* 33 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') /* 31 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') /* 32 */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') /* 30 */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') /* 2f */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') /* 2e */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') /* 33 */
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K30_1" )
@@ -546,31 +546,31 @@ static INPUT_PORTS_START( applix )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F8 (IRMA)") /* 42 */
PORT_START( "K31_0" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') /* 07 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') /* 08 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') /* 15 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U') /* 16 */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H') /* 23 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J') /* 24 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') /* 07 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') /* 08 */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') /* 15 */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') /* 16 */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') /* 23 */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') /* 24 */
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K31_1" )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) /* 37 */
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) /* 5f */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_NAME("LShift") /* 2a */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_NAME("LShift") PORT_CHAR(UCHAR_SHIFT_1) /* 2a */
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("<") /* 70 */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') /* 2c */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') /* 2d */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') /* 2c */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') /* 2d */
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?6c?") /* 6c */
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F9 (IRMA)") /* 43 */
PORT_START( "K32_0" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') /* 0a */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') /* 09 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') /* 18 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') /* 17 */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') /* 26 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') /* 25 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') /* 0a */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') /* 09 */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') /* 18 */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') /* 17 */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') /* 26 */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') /* 25 */
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K32_1" )
@@ -592,40 +592,40 @@ static INPUT_PORTS_START( applix )
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K33_1" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') /* 02 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') /* 29 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') /* 10 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') /* 02 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') /* 29 */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') /* 10 */
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) /* 0f */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') /* 1e */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') /* 1e */
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CAPSLOCK) PORT_NAME("Caps") /* 3a */
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?68?") /* 68 */
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F5 (IRMA)") /* 3f */
PORT_START( "K34_0" )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') /* 35 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') /* 35 */
PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) /* 36 */
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Left") /* 56 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') /* 34 */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') /* 34 */
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K34_1" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') /* 02 */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') /* 03 */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W') /* 11 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') /* 12 */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S') /* 1f */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') /* 20 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') /* 02 */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') /* 03 */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') /* 11 */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') /* 12 */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') /* 1f */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') /* 20 */
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("?67?") /* 67 */
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F4 (IRMA)") /* 3e */
PORT_START( "K35_0" )
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') /* 0b */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') /* 0c */
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') /* 19 */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') /* 1a */
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') /* 27 */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') /* 28 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') /* 0b */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') /* 0c */
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') /* 19 */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') /* 1a */
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') /* 27 */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') /* 28 */
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K35_1" )
@@ -635,10 +635,10 @@ static INPUT_PORTS_START( applix )
PORT_START( "K36_0" )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) /* 0e */
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') /* 0d */
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') /* 0d */
PORT_BIT( 0x14, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) /* 1c */
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') /* 2b */
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') /* 1b */
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') /* 2b */
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') /* 1b */
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START( "K36_1" )
@@ -818,7 +818,7 @@ MC6845_UPDATE_ROW( applix_state::crtc_update_row )
// The 6845 cursor signal is not used at all.
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u32 const vidbase = (m_video_latch & 15) << 14 | (ra & 7) << 12;
- u32 *p = &bitmap.pix32(y + vbp, hbp);
+ u32 *p = &bitmap.pix(y + vbp, hbp);
for (u16 x = 0; x < x_count; x++)
{
diff --git a/src/mame/drivers/apricot.cpp b/src/mame/drivers/apricot.cpp
index d782dd9111d..60a80be6f72 100644
--- a/src/mame/drivers/apricot.cpp
+++ b/src/mame/drivers/apricot.cpp
@@ -298,14 +298,14 @@ MC6845_UPDATE_ROW( apricot_state::crtc_update_row )
{
int color = fill ? 1 : BIT(data, x);
color ^= BIT(code, 15); // reverse?
- bitmap.pix32(y, x + i*10) = pen[color ? 1 + BIT(code, 14) : 0];
+ bitmap.pix(y, x + i*10) = pen[color ? 1 + BIT(code, 14) : 0];
}
}
else
{
// draw 16 pixels of the cell
for (int x = 0; x <= 16; x++)
- bitmap.pix32(y, x + i*16) = pen[BIT(data, x)];
+ bitmap.pix(y, x + i*16) = pen[BIT(data, x)];
}
}
}
diff --git a/src/mame/drivers/apricotf.cpp b/src/mame/drivers/apricotf.cpp
index d7ee2f5d1d1..f3d59584e27 100644
--- a/src/mame/drivers/apricotf.cpp
+++ b/src/mame/drivers/apricotf.cpp
@@ -149,7 +149,7 @@ u32 f1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const r
{
int color = (BIT(data, 15) << 1) | BIT(data, 7);
- bitmap.pix16(y, (sx * 8) + x) = color;
+ bitmap.pix(y, (sx * 8) + x) = color;
data <<= 1;
}
@@ -160,8 +160,8 @@ u32 f1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const r
{
int color = (BIT(data, 15) << 3) | (BIT(data, 14) << 2) | (BIT(data, 7) << 1) | BIT(data, 6);
- bitmap.pix16(y, (sx * 8) + (x * 2)) = color;
- bitmap.pix16(y, (sx * 8) + (x * 2) + 1) = color;
+ bitmap.pix(y, (sx * 8) + (x * 2)) = color;
+ bitmap.pix(y, (sx * 8) + (x * 2) + 1) = color;
data <<= 2;
}
diff --git a/src/mame/drivers/apricotp.cpp b/src/mame/drivers/apricotp.cpp
index a2d356486da..8e6b94d197d 100644
--- a/src/mame/drivers/apricotp.cpp
+++ b/src/mame/drivers/apricotp.cpp
@@ -190,7 +190,7 @@ uint32_t fp_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
{
int color = BIT(data, 15);
- bitmap.pix16(y, (sx * 16) + x) = color;
+ bitmap.pix(y, (sx * 16) + x) = color;
data <<= 1;
}
diff --git a/src/mame/drivers/argo.cpp b/src/mame/drivers/argo.cpp
index 090172d407f..9a85211d859 100644
--- a/src/mame/drivers/argo.cpp
+++ b/src/mame/drivers/argo.cpp
@@ -267,7 +267,7 @@ I8275_DRAW_CHARACTER_MEMBER(argo_state::display_pixels)
gfx ^= 0xff;
for(u8 i=0;i<7;i++)
- bitmap.pix32(y, x + i) = palette[BIT(gfx, 6-i) ? (hlgt ? 2 : 1) : 0];
+ bitmap.pix(y, x + i) = palette[BIT(gfx, 6-i) ? (hlgt ? 2 : 1) : 0];
}
static constexpr rgb_t argo_pens[3] =
diff --git a/src/mame/drivers/aristmk4.cpp b/src/mame/drivers/aristmk4.cpp
index 8264d8cf124..0220a60610e 100644
--- a/src/mame/drivers/aristmk4.cpp
+++ b/src/mame/drivers/aristmk4.cpp
@@ -2342,47 +2342,49 @@ ROM_END
ROM_START( fhunter )
ROM_REGION(0x10000, "maincpu", 0 )
/* VIDEO AND SOUND EPROM */
- ROM_LOAD("2vas004.u59", 0x02000, 0x2000, CRC(84226547) SHA1(df9c2c01a7ac4d930c06a8c4863853ddb1a2adbe))
-
+ ROM_LOAD("2vas004.u59", 0x02000, 0x2000, CRC(84226547) SHA1(df9c2c01a7ac4d930c06a8c4863853ddb1a2adbe)) // VIDEO SOUND 2VA/S004 U59/7 1AAA/FP34/8E00
+ // Alternate label: VIDEO SOUND 2VA/S004/MEM/59/7 FP34/8E00
/* GAME EPROMs */
ROM_LOAD("2xf5196i01.u87", 0x06000, 0x2000, CRC(f9e6b760) SHA1(af7f16727e84ba8f07400f7f02302862e02d1af4))
ROM_LOAD("2xf5196i01.u86", 0x08000, 0x8000, CRC(6971ccee) SHA1(1292cfa8125cbaec3bcd9d136cb385a3574bfa4a))
/* SHAPE EPROMs */
ROM_REGION(0xc000, "tile_gfx", 0 )
- ROM_LOAD("2xf5196.u20", 0x00000, 0x2000, CRC(96c81134) SHA1(e5e75e8b4897ee7cd9c27b0546fe4006cf384cba)) // unknown EPROM names, should contain VLSH or VL/SH letters on sticker
- ROM_LOAD("2xf5196.u21", 0x02000, 0x2000, CRC(ad7bc6a0) SHA1(145e9a094212841e8a684136ea813bd1bea070fb))
- ROM_LOAD("2xf5196.u22", 0x04000, 0x2000, CRC(450d47bb) SHA1(219a0eeca3989da8cec68405466c9a20f2ee9bfa))
- ROM_LOAD("2xf5196.u45", 0x06000, 0x2000, CRC(560b2417) SHA1(1ed26ceaff87150d2f0115825f952348e34e0414))
- ROM_LOAD("2xf5196.u46", 0x08000, 0x2000, CRC(7704c13f) SHA1(4cfca6ee9e2e543714e8bf0c6de4d9e9406ce250))
- ROM_LOAD("2xf5196.u47", 0x0a000, 0x2000, CRC(a9e6da98) SHA1(3b7d8920d3ef4ae17a55d2e1968318eb3c70264d))
+ ROM_LOAD("1vlsh293.u20", 0x00000, 0x2000, CRC(96c81134) SHA1(e5e75e8b4897ee7cd9c27b0546fe4006cf384cba)) // F. HUNTER BLU-L 1VL/SH293 U20/8 516C/3780/8F37
+ ROM_LOAD("1vlsh293.u21", 0x02000, 0x2000, CRC(ad7bc6a0) SHA1(145e9a094212841e8a684136ea813bd1bea070fb)) // F. HUNTER GRN-L 1VL/SH293 U21/10 PC01/0649/05A6
+ ROM_LOAD("1vlsh293.u22", 0x04000, 0x2000, CRC(450d47bb) SHA1(219a0eeca3989da8cec68405466c9a20f2ee9bfa)) // F. HUNTER RED-L 1VL/SH293 U22/12 2H12/6AH8/EA7A
+ ROM_LOAD("1vlsh293.u45", 0x06000, 0x2000, CRC(560b2417) SHA1(1ed26ceaff87150d2f0115825f952348e34e0414)) // F. HUNTER BLU-M 1VL/SH293 U45/9 A0C8/0A1F/88C5
+ ROM_LOAD("1vlsh293.u46", 0x08000, 0x2000, CRC(7704c13f) SHA1(4cfca6ee9e2e543714e8bf0c6de4d9e9406ce250)) // F. HUNTER GRN-M 1VL/SH293 U46/11 2648/8H31/CEDD
+ ROM_LOAD("1vlsh293.u47", 0x0a000, 0x2000, CRC(a9e6da98) SHA1(3b7d8920d3ef4ae17a55d2e1968318eb3c70264d)) // F. HUNTER RED-M 1VL/SH293 U47/13 FFP8/AA7A/F5AD
/* COLOR PROM */
ROM_REGION(0x200, "proms", 0 )
- ROM_LOAD("1cm48.u71", 0x0000, 0x0200, CRC(81daeeb0) SHA1(7dfe198c6def5c4ae4ecac488d65c2911fb3a890))
+ ROM_LOAD("1cm48.u71", 0x0000, 0x0200, CRC(81daeeb0) SHA1(7dfe198c6def5c4ae4ecac488d65c2911fb3a890)) // FORTUNE HUNTER 1CM48 8CFA U71/40
+ // Alternate label: FH/3BF/LGF 1CM48 8CFA U71/40
ROM_END
ROM_START( fhuntera )
ROM_REGION(0x10000, "maincpu", 0 )
/* VIDEO AND SOUND EPROM */
- ROM_LOAD("2vas004.u59", 0x02000, 0x2000, CRC(84226547) SHA1(df9c2c01a7ac4d930c06a8c4863853ddb1a2adbe))
-
+ ROM_LOAD("2vas004.u59", 0x02000, 0x2000, CRC(84226547) SHA1(df9c2c01a7ac4d930c06a8c4863853ddb1a2adbe)) // VIDEO SOUND 2VA/S004 U59/7 1AAA/FP34/8E00
+ // Alternate label: VIDEO SOUND 2VA/S004/MEM/59/7 FP34/8E00
/* GAME EPROMs */
ROM_LOAD("2xf5196i02.u87", 0x06000, 0x2000, CRC(4b532a14) SHA1(98d1753ad1d0d041f81a535947ed501d0eb1d85c))
ROM_LOAD("2xf5196i01.u86", 0x08000, 0x8000, CRC(6971ccee) SHA1(1292cfa8125cbaec3bcd9d136cb385a3574bfa4a))
/* SHAPE EPROMs */
ROM_REGION(0xc000, "tile_gfx", 0 )
- ROM_LOAD("2xf5196.u20", 0x00000, 0x2000, CRC(96c81134) SHA1(e5e75e8b4897ee7cd9c27b0546fe4006cf384cba)) // unknown EPROM names, should contain VLSH or VL/SH letters on sticker
- ROM_LOAD("2xf5196.u21", 0x02000, 0x2000, CRC(ad7bc6a0) SHA1(145e9a094212841e8a684136ea813bd1bea070fb))
- ROM_LOAD("2xf5196.u22", 0x04000, 0x2000, CRC(450d47bb) SHA1(219a0eeca3989da8cec68405466c9a20f2ee9bfa))
- ROM_LOAD("2xf5196.u45", 0x06000, 0x2000, CRC(560b2417) SHA1(1ed26ceaff87150d2f0115825f952348e34e0414))
- ROM_LOAD("2xf5196.u46", 0x08000, 0x2000, CRC(7704c13f) SHA1(4cfca6ee9e2e543714e8bf0c6de4d9e9406ce250))
- ROM_LOAD("2xf5196.u47", 0x0a000, 0x2000, CRC(a9e6da98) SHA1(3b7d8920d3ef4ae17a55d2e1968318eb3c70264d))
+ ROM_LOAD("1vlsh293.u20", 0x00000, 0x2000, CRC(96c81134) SHA1(e5e75e8b4897ee7cd9c27b0546fe4006cf384cba)) // F. HUNTER BLU-L 1VL/SH293 U20/8 516C/3780/8F37
+ ROM_LOAD("1vlsh293.u21", 0x02000, 0x2000, CRC(ad7bc6a0) SHA1(145e9a094212841e8a684136ea813bd1bea070fb)) // F. HUNTER GRN-L 1VL/SH293 U21/10 PC01/0649/05A6
+ ROM_LOAD("1vlsh293.u22", 0x04000, 0x2000, CRC(450d47bb) SHA1(219a0eeca3989da8cec68405466c9a20f2ee9bfa)) // F. HUNTER RED-L 1VL/SH293 U22/12 2H12/6AH8/EA7A
+ ROM_LOAD("1vlsh293.u45", 0x06000, 0x2000, CRC(560b2417) SHA1(1ed26ceaff87150d2f0115825f952348e34e0414)) // F. HUNTER BLU-M 1VL/SH293 U45/9 A0C8/0A1F/88C5
+ ROM_LOAD("1vlsh293.u46", 0x08000, 0x2000, CRC(7704c13f) SHA1(4cfca6ee9e2e543714e8bf0c6de4d9e9406ce250)) // F. HUNTER GRN-M 1VL/SH293 U46/11 2648/8H31/CEDD
+ ROM_LOAD("1vlsh293.u47", 0x0a000, 0x2000, CRC(a9e6da98) SHA1(3b7d8920d3ef4ae17a55d2e1968318eb3c70264d)) // F. HUNTER RED-M 1VL/SH293 U47/13 FFP8/AA7A/F5AD
/* COLOR PROM */
ROM_REGION(0x200, "proms", 0 )
- ROM_LOAD("1cm48.u71", 0x0000, 0x0200, CRC(81daeeb0) SHA1(7dfe198c6def5c4ae4ecac488d65c2911fb3a890))
+ ROM_LOAD("1cm48.u71", 0x0000, 0x0200, CRC(81daeeb0) SHA1(7dfe198c6def5c4ae4ecac488d65c2911fb3a890)) // FORTUNE HUNTER 1CM48 8CFA U71/40
+ // Alternate label: FH/3BF/LGF 1CM48 8CFA U71/40
ROM_END
ROM_START( arcwins )
diff --git a/src/mame/drivers/aristmk6.cpp b/src/mame/drivers/aristmk6.cpp
index 3e90126427d..b0e332129fe 100644
--- a/src/mame/drivers/aristmk6.cpp
+++ b/src/mame/drivers/aristmk6.cpp
@@ -173,7 +173,7 @@ uint32_t aristmk6_state::screen_update_aristmk6(screen_device &screen, bitmap_rg
b = (b << 3) | (b & 0x7);
if(cliprect.contains(x, y))
- bitmap.pix32(y, x) = r | g<<8 | b<<16;
+ bitmap.pix(y, x) = r | g<<8 | b<<16;
count+=2;
}
@@ -184,7 +184,7 @@ uint32_t aristmk6_state::screen_update_aristmk6(screen_device &screen, bitmap_rg
color = blit_ram[count];
if(cliprect.contains(x, y))
- bitmap.pix32(y, x) = m_palette->pen(color);
+ bitmap.pix(y, x) = m_palette->pen(color);
count++;
}
@@ -205,12 +205,12 @@ uint32_t aristmk6_state::screen_update_aristmk6(screen_device &screen, bitmap_rg
pix1 = pix & 0xffffffff;
col = 0;
if (pix1) col = 1;
- bitmap.pix32(y, x*2) = m_palette->pen(col);
+ bitmap.pix(y, x*2) = m_palette->pen(col);
pix1 = pix >> 32;
col = 0;
if (pix1) col = 1;
- bitmap.pix32(y, x*2+1) = m_palette->pen(col);
+ bitmap.pix(y, x*2+1) = m_palette->pen(col);
count++;
diff --git a/src/mame/drivers/astinvad.cpp b/src/mame/drivers/astinvad.cpp
index 0a23d19cbf5..86d1dc1502f 100644
--- a/src/mame/drivers/astinvad.cpp
+++ b/src/mame/drivers/astinvad.cpp
@@ -168,14 +168,14 @@ void astinvad_state::plot_byte( bitmap_rgb32 &bitmap, uint8_t y, uint8_t x, uint
{
uint8_t flip_xor = m_screen_flip & 7;
- bitmap.pix32(y, x + (0 ^ flip_xor)) = (data & 0x01) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (1 ^ flip_xor)) = (data & 0x02) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (2 ^ flip_xor)) = (data & 0x04) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (3 ^ flip_xor)) = (data & 0x08) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (4 ^ flip_xor)) = (data & 0x10) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (5 ^ flip_xor)) = (data & 0x20) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (6 ^ flip_xor)) = (data & 0x40) ? m_palette->pen_color(color) : rgb_t::black();
- bitmap.pix32(y, x + (7 ^ flip_xor)) = (data & 0x80) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (0 ^ flip_xor)) = (data & 0x01) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (1 ^ flip_xor)) = (data & 0x02) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (2 ^ flip_xor)) = (data & 0x04) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (3 ^ flip_xor)) = (data & 0x08) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (4 ^ flip_xor)) = (data & 0x10) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (5 ^ flip_xor)) = (data & 0x20) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (6 ^ flip_xor)) = (data & 0x40) ? m_palette->pen_color(color) : rgb_t::black();
+ bitmap.pix(y, x + (7 ^ flip_xor)) = (data & 0x80) ? m_palette->pen_color(color) : rgb_t::black();
}
diff --git a/src/mame/drivers/astrof.cpp b/src/mame/drivers/astrof.cpp
index 9992933eac3..d04d0c8d672 100644
--- a/src/mame/drivers/astrof.cpp
+++ b/src/mame/drivers/astrof.cpp
@@ -356,14 +356,9 @@ void astrof_state::tomahawk_video_control_2_w(uint8_t data)
void astrof_state::video_update_common( bitmap_rgb32 &bitmap, const rectangle &cliprect, pen_t *pens, int num_pens )
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- uint8_t data;
- int i;
-
- uint8_t color = m_colorram[offs >> 1];
+ uint8_t const color = m_colorram[offs >> 1];
pen_t back_pen = pens[(color & (num_pens-1)) | 0x00];
pen_t fore_pen = pens[(color & (num_pens-1)) | 0x01];
@@ -377,22 +372,23 @@ void astrof_state::video_update_common( bitmap_rgb32 &bitmap, const rectangle &c
if ((y <= cliprect.top()) || (y >= cliprect.bottom()))
continue;
+ uint8_t data;
if (m_screen_off)
data = 0;
else
data = m_videoram[offs];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
- pen_t pen = (data & 0x01) ? fore_pen : back_pen;
+ pen_t const pen = (data & 0x01) ? fore_pen : back_pen;
if (m_flipscreen)
- bitmap.pix32(y, 255 - x) = pen;
+ bitmap.pix(y, 255 - x) = pen;
else
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- x = x + 1;
- data = data >> 1;
+ x++;
+ data >>= 1;
}
}
}
@@ -1048,7 +1044,7 @@ ROM_START( astrof3 )
ROM_LOAD( "astrf.clr", 0x0000, 0x0020, CRC(61329fd1) SHA1(15782d8757d4dda5a8b97815e94c90218f0e08dd) )
ROM_END
-
+// Famaresa "500" PCB set (500-001, 500-002, 500-003 and 500-004).
ROM_START( astroff )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "b.4a", 0xd000, 0x0400, CRC(18bdc2d9) SHA1(1fc93de1212f04f04acc224d91c2308758f5d5ca) )
@@ -1065,7 +1061,27 @@ ROM_START( astroff )
ROM_LOAD( "0.5k", 0xfc00, 0x0400, CRC(c63a9c80) SHA1(f51694912d823a5ae7883c603915b9c1aa0e0733) )
ROM_REGION( 0x0020, "proms", 0 )
- ROM_LOAD( "im5610-82s123.2f", 0x0000, 0x0020, CRC(61329fd1) SHA1(15782d8757d4dda5a8b97815e94c90218f0e08dd) )
+ ROM_LOAD( "im5610-82s123.2f", 0x0000, 0x0020, CRC(61329fd1) SHA1(15782d8757d4dda5a8b97815e94c90218f0e08dd) )
+ROM_END
+
+// Famaresa "500" PCB set (500-001, 500-002, 500-003 and 500-004). Tested, shows a black background.
+ROM_START( astroff2 )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "b.4a", 0xd000, 0x0400, CRC(18bdc2d9) SHA1(1fc93de1212f04f04acc224d91c2308758f5d5ca) )
+ ROM_LOAD( "a.4c", 0xd400, 0x0400, CRC(2344521c) SHA1(7f50890df10219b51bf4cf617e8ffb4336e19ae3) )
+ ROM_LOAD( "9.5a", 0xd800, 0x0400, CRC(9bd0e10d) SHA1(0170f56ce0c7a3827548bdd954acb2c0e4a2cb24) )
+ ROM_LOAD( "8r.5c", 0xdc00, 0x0400, CRC(06ff0192) SHA1(f581eb508364b44e51aa998b7dba6a97578a3a92) )
+ ROM_LOAD( "7.4d", 0xe000, 0x0400, CRC(6cd01b9e) SHA1(597db331008a4a561bc8d9bbd42ffde9bcd565dc) )
+ ROM_LOAD( "6.4f", 0xe400, 0x0400, CRC(69cd2604) SHA1(09201ae691330e3bd788f9c714f6dcbb7e8335d0) )
+ ROM_LOAD( "5.5d", 0xe800, 0x0400, CRC(14a4118f) SHA1(d99876f405dd646a7f0e85e584f2509d9cf17372) )
+ ROM_LOAD( "4.5f", 0xec00, 0x0400, CRC(0513bc92) SHA1(dbf774e8353c966c303e02ce8196b888d235bdb2) )
+ ROM_LOAD( "3.4h", 0xf000, 0x0400, CRC(e01713bd) SHA1(e0370a070c727f8f7ff767fdd84f7aeef31c8347) )
+ ROM_LOAD( "2.4k", 0xf400, 0x0400, CRC(24ab94d5) SHA1(1e0a61d83fa67340d4b1477377ed9d65cf826f53) )
+ ROM_LOAD( "1.5h", 0xf800, 0x0400, CRC(142bbc5d) SHA1(55017fd88a19d09943cde16d583db00cf4c3218b) )
+ ROM_LOAD( "0.5k", 0xfc00, 0x0400, CRC(c63a9c80) SHA1(f51694912d823a5ae7883c603915b9c1aa0e0733) )
+
+ ROM_REGION( 0x0020, "proms", 0 )
+ ROM_LOAD( "im5610-82s123.2f", 0x0000, 0x0020, CRC(61329fd1) SHA1(15782d8757d4dda5a8b97815e94c90218f0e08dd) )
ROM_END
@@ -1135,6 +1151,29 @@ ROM_START( afire )
ROM_END
+ROM_START( asterion )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "asterion eprom 12.bin", 0xd000, 0x0400, CRC(9ba57987) SHA1(becf89b7d474f86839f13f9be5502c91491e8584) )
+ ROM_LOAD( "asterion eprom 11.bin", 0xd400, 0x0400, CRC(8974715e) SHA1(1a4a576d51a0788dd973de5c5fde5131a940d3f0) )
+ ROM_LOAD( "asterion eprom 10.bin", 0xd800, 0x0400, CRC(354cf432) SHA1(138956ea8064eba0dcd8b2f175d4981b689a2077) )
+ ROM_LOAD( "asterion eprom 9.bin", 0xdc00, 0x0400, CRC(4cee0c8b) SHA1(98bfdda9d2d368db16d6e9090536b09d8337c0e5) )
+ ROM_LOAD( "asterion eprom 5.bin", 0xe000, 0x0400, CRC(9cb477f3) SHA1(6866264aa8d0479cee237a00e4a919e3981144a5) )
+ ROM_LOAD( "asterion eprom 7.bin", 0xe400, 0x0400, CRC(272de8f1) SHA1(e917b3b8bb96fedacd6d5cb3d1c30977818f2e85) )
+ ROM_LOAD( "asterion eprom 6.bin", 0xe800, 0x0400, CRC(ff25acaa) SHA1(5cb360c556c9b36039ae05702e6900b82fe5676b) )
+ ROM_LOAD( "asterion eprom 4.bin", 0xec00, 0x0400, CRC(6edf202d) SHA1(a4cab2f10a99e0a4b1c571168e17cbee1d18cf06) )
+ ROM_LOAD( "asterion eprom 8.bin", 0xf000, 0x0400, CRC(47dccb04) SHA1(b6b6c6685c93ac9531efb970b2e82ad68eea87ba) )
+ ROM_LOAD( "asterion eprom 2.bin", 0xf400, 0x0400, CRC(86c6ae5c) SHA1(c5d8dab0ef3168884ae6fe7099708a290daba2ba) )
+ ROM_LOAD( "asterion eprom 3.bin", 0xf800, 0x0400, CRC(b206deda) SHA1(9ab52920c06ed6beb38bc7f97ffd00e8ad46c17d) )
+ ROM_LOAD( "asterion eprom 1.bin", 0xfc00, 0x0400, CRC(99008e90) SHA1(bfa1c3a66992f432fad37203f052f820b098e05f) )
+
+ ROM_REGION( 0x0100, "proms", 0 )
+ ROM_LOAD( "sn74s470.bin", 0x0000, 0x0100, CRC(3bf3ccb0) SHA1(d61d19d38045f42a9adecf295e479fee239bed48) )
+
+ ROM_REGION( 0x0200, "user1", 0 ) // data relevant for the decryption is the same as the one for abattle, but it's on a larger PROM
+ ROM_LOAD( "sn74s472.bin", 0x0000, 0x0200, CRC(d437a9d8) SHA1(32e3513ab2ce1cde5196d80c53f5aa98b339929f) )
+ROM_END
+
+
/* This is a newer revision of "Astro Combat" (most probably manufactured by Sidam),
with correct spelling for FUEL and the main boss sporting "CB". */
ROM_START( acombat )
@@ -1397,28 +1436,48 @@ void astrof_state::init_acombat3()
}
+void astrof_state::init_asterion()
+{
+ // use the protection PROM to decrypt the ROMs
+ uint8_t *rom = memregion("maincpu")->base();
+ uint8_t *prom = memregion("user1")->base();
+
+ for (int i = 0xd000; i < 0x10000; i++)
+ {
+ rom[i] = prom[(rom[i] & 0x1f) + ((rom[i] & 0xe0) << 1)];
+ }
+
+ // set up protection handlers
+ m_maincpu->space(AS_PROGRAM).install_read_handler(0xa003, 0xa003, read8smo_delegate(*this, FUNC(astrof_state::shoot_r)));
+ m_maincpu->space(AS_PROGRAM).install_read_handler(0xa004, 0xa004, read8smo_delegate(*this, FUNC(astrof_state::abattle_coin_prot_r)));
+}
+
+
/*************************************
*
* Game drivers
*
*************************************/
-GAME( 1979, astrof, 0, astrof, astrof, astrof_state, empty_init, ROT90, "Data East", "Astro Fighter (set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, astrof2, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "Data East", "Astro Fighter (set 2)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, astrof3, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "Data East", "Astro Fighter (set 3)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, astroff, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "bootleg? (Famaresa)", "Astro Fighter (set 4)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, abattle, astrof, abattle, abattle, astrof_state, init_abattle, ROT90, "bootleg? (Sidam)", "Astro Battle (set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, abattle2, astrof, abattle, abattle, astrof_state, init_abattle, ROT90, "bootleg? (Sidam)", "Astro Battle (set 2)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, afire, astrof, abattle, abattle, astrof_state, init_afire, ROT90, "bootleg (Rene Pierre)", "Astro Fire", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, acombat, astrof, abattle, abattle, astrof_state, init_afire, ROT90, "bootleg", "Astro Combat (newer, CB)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, acombato, astrof, abattle, abattle, astrof_state, init_afire, ROT90, "bootleg", "Astro Combat (older, PZ)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, acombat3, astrof, abattle, abattle, astrof_state, init_acombat3, ROT90, "bootleg (Proel)", "Astro Combat (unencrypted)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, acombat4, astrof, abattle, abattle, astrof_state, init_abattle, ROT90, "bootleg (Proel)", "Astro Combat (encrypted)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, astrof, 0, astrof, astrof, astrof_state, empty_init, ROT90, "Data East", "Astro Fighter (set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, astrof2, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "Data East", "Astro Fighter (set 2)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, astrof3, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "Data East", "Astro Fighter (set 3)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, astroff, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "bootleg (Famaresa)", "Astro Fighter (Famaresa bootleg, set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, astroff2, astrof, astrof, astrof, astrof_state, empty_init, ROT90, "bootleg (Famaresa)", "Astro Fighter (Famaresa bootleg, set 2)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, abattle, astrof, abattle, abattle, astrof_state, init_abattle, ROT90, "bootleg? (Sidam)", "Astro Battle (set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, abattle2, astrof, abattle, abattle, astrof_state, init_abattle, ROT90, "bootleg? (Sidam)", "Astro Battle (set 2)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, afire, astrof, abattle, abattle, astrof_state, init_afire, ROT90, "bootleg (Rene Pierre)", "Astro Fire", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1980, asterion, astrof, abattle, abattle, astrof_state, init_asterion, ROT90, "bootleg? (Olympia)", "Asterion", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, acombat, astrof, abattle, abattle, astrof_state, init_afire, ROT90, "bootleg", "Astro Combat (newer, CB)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, acombato, astrof, abattle, abattle, astrof_state, init_afire, ROT90, "bootleg", "Astro Combat (older, PZ)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, acombat3, astrof, abattle, abattle, astrof_state, init_acombat3, ROT90, "bootleg (Proel)", "Astro Combat (unencrypted)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, acombat4, astrof, abattle, abattle, astrof_state, init_abattle, ROT90, "bootleg (Proel)", "Astro Combat (encrypted)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+
GAME( 1979, strfight, astrof, abattle, abattle, astrof_state, init_acombat3, ROT90, "bootleg (VGG)", "Star Fighter (bootleg of Astro Fighter)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, sstarbtl, astrof, abattle, abattle, astrof_state, init_sstarbtl, ROT90, "bootleg", "Super Star Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, sstarbtl, astrof, abattle, abattle, astrof_state, init_sstarbtl, ROT90, "bootleg (SG-Florence)", "Super Star Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, spfghmk2, 0, spfghmk2, spfghmk2, astrof_state, empty_init, ROT90, "Data East", "Space Fighter Mark II (set 1)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1979, spfghmk22, spfghmk2, spfghmk2, spfghmk22, astrof_state, empty_init, ROT90, "Data East", "Space Fighter Mark II (set 2)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, spfghmk2, 0, spfghmk2, spfghmk2, astrof_state, empty_init, ROT90, "Data East", "Space Fighter Mark II (set 1)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1979, spfghmk22, spfghmk2, spfghmk2, spfghmk22, astrof_state, empty_init, ROT90, "Data East", "Space Fighter Mark II (set 2)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1980, tomahawk, 0, tomahawk, tomahawk, astrof_state, empty_init, ROT90, "Data East", "Tomahawk 777 (rev 5)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
-GAME( 1980, tomahawk1, tomahawk, tomahawk, tomahawk1, astrof_state, empty_init, ROT90, "Data East", "Tomahawk 777 (rev 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1980, tomahawk, 0, tomahawk, tomahawk, astrof_state, empty_init, ROT90, "Data East", "Tomahawk 777 (rev 5)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
+GAME( 1980, tomahawk1, tomahawk, tomahawk, tomahawk1, astrof_state, empty_init, ROT90, "Data East", "Tomahawk 777 (rev 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/at.cpp b/src/mame/drivers/at.cpp
index 879f53f6a69..e1c1436c6aa 100644
--- a/src/mame/drivers/at.cpp
+++ b/src/mame/drivers/at.cpp
@@ -4334,7 +4334,7 @@ ROM_END
// 40-040A-001291-00101111-111192-OP495SLC-0 / 486DX-OP-WBq-25/33/50-K2-ZZ
ROM_START( nat48pv )
ROM_REGION32_LE(0x20000, "bios", 0)
- ROM_LOAD( "amibios_aa5312581.bin", 0x10000, 0x10000, CRC(8A788C79) SHA1(050972B7A369A463D6654EC52C0804002E9BCB37))
+ ROM_LOAD( "amibios_aa5312581.bin", 0x10000, 0x10000, CRC(8a788c79) SHA1(050972b7a369a463d6654ec52c0804002e9bcb37))
ROM_END
diff --git a/src/mame/drivers/atarisy4.cpp b/src/mame/drivers/atarisy4.cpp
index 8da5a02d553..1dfd60758f8 100644
--- a/src/mame/drivers/atarisy4.cpp
+++ b/src/mame/drivers/atarisy4.cpp
@@ -231,7 +231,6 @@ void atarisy4_state::video_reset()
uint32_t atarisy4_state::screen_update_atarisy4(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int y;
uint32_t offset = 0;
if (m_gpu.bcrw & 0x80)
@@ -245,15 +244,14 @@ uint32_t atarisy4_state::screen_update_atarisy4(screen_device &screen, bitmap_rg
//uint32_t offset = m_gpu.dpr << 5;
- for (y = cliprect.top(); y <= cliprect.bottom(); ++y)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); ++y)
{
- uint16_t *src = &m_screen_ram[(offset + (4096 * y)) / 2];
- uint32_t *dest = &bitmap.pix32(y, cliprect.left());
- int x;
+ uint16_t const *src = &m_screen_ram[(offset + (4096 * y)) / 2];
+ uint32_t *dest = &bitmap.pix(y, cliprect.left());
- for (x = cliprect.left(); x < cliprect.right(); x += 2)
+ for (int x = cliprect.left(); x < cliprect.right(); x += 2)
{
- uint16_t data = *src++;
+ uint16_t const data = *src++;
*dest++ = m_palette->pen(data & 0xff);
*dest++ = m_palette->pen(data >> 8);
diff --git a/src/mame/drivers/atom.cpp b/src/mame/drivers/atom.cpp
index 524f1679e10..7f4d8036c51 100644
--- a/src/mame/drivers/atom.cpp
+++ b/src/mame/drivers/atom.cpp
@@ -343,81 +343,81 @@ static INPUT_PORTS_START( atom )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(UCHAR_MAMEKEY(ESC))
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(UCHAR_MAMEKEY(ESC),27)
PORT_START("Y1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('\"')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
PORT_START("Y2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x87\x95") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
PORT_START("Y3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x87\x94") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(':') PORT_CHAR('*')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
PORT_START("Y4")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DELETE") PORT_CODE(KEYCODE_DEL) PORT_CHAR(8)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
PORT_START("Y5")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('^')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("COPY") PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB))
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
PORT_START("Y6")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
PORT_START("Y7")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('\\')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
PORT_START("Y8")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('[')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
PORT_START("Y9")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(32)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
PORT_START("Y10")
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
@@ -426,8 +426,8 @@ static INPUT_PORTS_START( atom )
PORT_START("Y11")
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("REPT") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL))
- PORT_START("BRK")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_CHANGED_MEMBER(DEVICE_SELF, atom_state, trigger_reset, 0)
+ PORT_START("BRK") // This is a full reset - program in memory is lost
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHANGED_MEMBER(DEVICE_SELF, atom_state, trigger_reset, 0)
PORT_START("ECONET")
// station ID (0-255)
diff --git a/src/mame/drivers/atronic.cpp b/src/mame/drivers/atronic.cpp
index 5d73e60b702..19fe4c15a7e 100644
--- a/src/mame/drivers/atronic.cpp
+++ b/src/mame/drivers/atronic.cpp
@@ -423,8 +423,8 @@ TMS340X0_FROM_SHIFTREG_CB_MEMBER(atronic_state::from_shiftreg)
TMS340X0_SCANLINE_RGB32_CB_MEMBER(atronic_state::scanline_update)
{
uint32_t fulladdr = ((params->rowaddr << 16) | params->coladdr) >> 5;
- uint32_t* bg0_base = &m_vidram[(fulladdr & 0x7fe00)]; // this probably isn't screen ram, but some temp gfx are copied on startup
- uint32_t* dst = &bitmap.pix32(scanline);
+ uint32_t const *const bg0_base = &m_vidram[(fulladdr & 0x7fe00)]; // this probably isn't screen ram, but some temp gfx are copied on startup
+ uint32_t *const dst = &bitmap.pix(scanline);
int coladdr = fulladdr & 0x1ff;
const pen_t *pens = m_palette->pens();
diff --git a/src/mame/drivers/att4425.cpp b/src/mame/drivers/att4425.cpp
index e574f006e55..b2033aa5f05 100644
--- a/src/mame/drivers/att4425.cpp
+++ b/src/mame/drivers/att4425.cpp
@@ -131,26 +131,26 @@ void att4425_state::video_start()
uint32_t att4425_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y, ra, gfx, fg, bg, chr, attr;
- uint16_t sy = 0, ma, x, ca;
+ uint16_t sy = 0;
- fg = 2;
- bg = 0;
+ uint8_t fg = 2;
+ uint8_t bg = 0;
- for (y = 0; y < 27; y++)
+ for (uint8_t y = 0; y < 27; y++)
{
- ma = 0x7e9c + 4 * (81 - 27 + y);
+ uint16_t ma = 0x7e9c + 4 * (81 - 27 + y);
ma = (m_p_videoram[ma] << 8) + m_p_videoram[ma + 1] - 0x8000;
- for (ra = 0; ra < 13; ra++)
+ for (uint8_t ra = 0; ra < 13; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 160; x += 2)
+ for (uint16_t x = ma; x < ma + 160; x += 2)
{
- chr = m_p_videoram[x + 1];
- attr = m_p_videoram[x];
- ca = (chr << 4) & 0x7f0;
+ uint8_t const chr = m_p_videoram[x + 1];
+ uint8_t const attr = m_p_videoram[x];
+ uint16_t ca = (chr << 4) & 0x7f0;
+ uint8_t gfx;
// font 2
if (attr & 0x01)
@@ -178,9 +178,8 @@ uint32_t att4425_state::screen_update(screen_device &screen, bitmap_ind16 &bitma
/* Display a scanline of a character */
for (int i = 7; i >= 0; i--)
- {
*p++ = BIT(gfx, i) ? fg : bg;
- }
+
*p++ = bg;
}
}
diff --git a/src/mame/drivers/att630.cpp b/src/mame/drivers/att630.cpp
index 96e0626ea4a..bcedcd25c15 100644
--- a/src/mame/drivers/att630.cpp
+++ b/src/mame/drivers/att630.cpp
@@ -54,7 +54,7 @@ u32 att630_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, con
{
for (int y = 0; y < 1024; y++)
for (int x = 0; x < 1024; x++)
- bitmap.pix32(y, x) = BIT(m_vram[y * (1024 / 16) + x / 16], 15 - (x % 16)) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y, x) = BIT(m_vram[y * (1024 / 16) + x / 16], 15 - (x % 16)) ? rgb_t::white() : rgb_t::black();
return 0;
}
diff --git a/src/mame/drivers/attache.cpp b/src/mame/drivers/attache.cpp
index 7f42d3e551a..17f434fce48 100644
--- a/src/mame/drivers/attache.cpp
+++ b/src/mame/drivers/attache.cpp
@@ -299,39 +299,35 @@ private:
// bit 7 = subscript (superscript and subscript combined produces strikethrough)
uint32_t attache_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t x,y,vy,start,bit,scan,data;
- uint8_t dbl_mode = 0; // detemines which half of character to display when using double size attribute,
- // as it can start on either odd or even character cells.
-
// Graphics output (if enabled)
if(m_gfx_enabled)
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
- for(y=0;y<(bitmap.height()-1)/10;y++)
+ for(uint8_t y=0;y<(bitmap.height()-1)/10;y++)
{
- for(x=0;x<(bitmap.width()-1)/8;x++)
+ for(uint8_t x=0;x<(bitmap.width()-1)/8;x++)
{
// graphics pixels use half the clock of text, so 4 graphics pixels per character
- for(scan=0;scan<10;scan+=2)
+ for(uint8_t scan=0;scan<10;scan+=2)
{
- data = m_gfx_ram[(128*32*(scan/2))+(y*128+x)];
- bitmap.pix32(y*10+scan,x*8) = pen[BIT(data,7)];
- bitmap.pix32(y*10+scan,x*8+1) = pen[BIT(data,7)];
- bitmap.pix32(y*10+scan,x*8+2) = pen[BIT(data,6)];
- bitmap.pix32(y*10+scan,x*8+3) = pen[BIT(data,6)];
- bitmap.pix32(y*10+scan,x*8+4) = pen[BIT(data,5)];
- bitmap.pix32(y*10+scan,x*8+5) = pen[BIT(data,5)];
- bitmap.pix32(y*10+scan,x*8+6) = pen[BIT(data,4)];
- bitmap.pix32(y*10+scan,x*8+7) = pen[BIT(data,4)];
- bitmap.pix32(y*10+scan+1,x*8) = pen[BIT(data,3)];
- bitmap.pix32(y*10+scan+1,x*8+1) = pen[BIT(data,3)];
- bitmap.pix32(y*10+scan+1,x*8+2) = pen[BIT(data,2)];
- bitmap.pix32(y*10+scan+1,x*8+3) = pen[BIT(data,2)];
- bitmap.pix32(y*10+scan+1,x*8+4) = pen[BIT(data,1)];
- bitmap.pix32(y*10+scan+1,x*8+5) = pen[BIT(data,1)];
- bitmap.pix32(y*10+scan+1,x*8+6) = pen[BIT(data,0)];
- bitmap.pix32(y*10+scan+1,x*8+7) = pen[BIT(data,0)];
+ uint8_t const data = m_gfx_ram[(128*32*(scan/2))+(y*128+x)];
+ bitmap.pix(y*10+scan,x*8) = pen[BIT(data,7)];
+ bitmap.pix(y*10+scan,x*8+1) = pen[BIT(data,7)];
+ bitmap.pix(y*10+scan,x*8+2) = pen[BIT(data,6)];
+ bitmap.pix(y*10+scan,x*8+3) = pen[BIT(data,6)];
+ bitmap.pix(y*10+scan,x*8+4) = pen[BIT(data,5)];
+ bitmap.pix(y*10+scan,x*8+5) = pen[BIT(data,5)];
+ bitmap.pix(y*10+scan,x*8+6) = pen[BIT(data,4)];
+ bitmap.pix(y*10+scan,x*8+7) = pen[BIT(data,4)];
+ bitmap.pix(y*10+scan+1,x*8) = pen[BIT(data,3)];
+ bitmap.pix(y*10+scan+1,x*8+1) = pen[BIT(data,3)];
+ bitmap.pix(y*10+scan+1,x*8+2) = pen[BIT(data,2)];
+ bitmap.pix(y*10+scan+1,x*8+3) = pen[BIT(data,2)];
+ bitmap.pix(y*10+scan+1,x*8+4) = pen[BIT(data,1)];
+ bitmap.pix(y*10+scan+1,x*8+5) = pen[BIT(data,1)];
+ bitmap.pix(y*10+scan+1,x*8+6) = pen[BIT(data,0)];
+ bitmap.pix(y*10+scan+1,x*8+7) = pen[BIT(data,0)];
}
}
}
@@ -340,12 +336,14 @@ uint32_t attache_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma
bitmap.fill(0);
// Text output
- for(y=0;y<(bitmap.height()-1)/10;y++) // lines
+ uint8_t dbl_mode = 0; // detemines which half of character to display when using double size attribute,
+ // as it can start on either odd or even character cells.
+ for(uint8_t y=0;y<(bitmap.height()-1)/10;y++) // lines
{
- start = m_crtc->upscroll_offset();
- vy = (start + y) % 24;
+ uint8_t const start = m_crtc->upscroll_offset();
+ uint8_t const vy = (start + y) % 24;
- for(x=0;x<(bitmap.width()-1)/8;x++) // columns
+ for(uint8_t x=0;x<(bitmap.width()-1)/8;x++) // columns
{
assert(((y*128)+x) >= 0 && ((y*128)+x) < ARRAY_LENGTH(m_char_ram));
assert(((vy*128)+x) >= 0 && ((vy*128)+x) < ARRAY_LENGTH(m_char_ram));
@@ -356,9 +354,9 @@ uint32_t attache_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma
else
dbl_mode = 0;
- for(scan=0;scan<10;scan++) // 10 scanlines per line
+ for(uint8_t scan=0;scan<10;scan++) // 10 scanlines per line
{
- data = m_char_rom->base()[(ch*16+scan)];
+ uint8_t data = m_char_rom->base()[(ch*16+scan)];
if((m_attr_ram[(vy*128)+x] & 0xc0) != 0xc0) // if not strikethrough
{
if(m_attr_ram[(vy*128)+x] & 0x40) // superscript
@@ -402,13 +400,13 @@ uint32_t attache_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma
data = newdata;
}
- for(bit=0;bit<8;bit++) // 8 pixels per character
+ for(uint8_t bit=0;bit<8;bit++) // 8 pixels per character
{
- uint16_t xpos = x*8+bit;
- uint16_t ypos = y*10+scan;
+ uint16_t const xpos = x*8+bit;
+ uint16_t const ypos = y*10+scan;
if(BIT(data,7-bit))
- bitmap.pix32(ypos,xpos) = fg;
+ bitmap.pix(ypos,xpos) = fg;
}
}
}
diff --git a/src/mame/drivers/avalnche.cpp b/src/mame/drivers/avalnche.cpp
index 5b3f930a43e..7c8896238b9 100644
--- a/src/mame/drivers/avalnche.cpp
+++ b/src/mame/drivers/avalnche.cpp
@@ -48,17 +48,13 @@
uint32_t avalnche_state::screen_update_avalnche(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- int i;
-
uint8_t x = offs << 3;
- int y = offs >> 5;
+ int const y = offs >> 5;
uint8_t data = m_videoram[offs];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
pen_t pen;
@@ -67,10 +63,10 @@ uint32_t avalnche_state::screen_update_avalnche(screen_device &screen, bitmap_rg
else
pen = (data & 0x80) ? rgb_t::black() : rgb_t::white();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- data = data << 1;
- x = x + 1;
+ data <<= 1;
+ x++;
}
}
diff --git a/src/mame/drivers/b16.cpp b/src/mame/drivers/b16.cpp
index a156c83826d..d4a864b0a77 100644
--- a/src/mame/drivers/b16.cpp
+++ b/src/mame/drivers/b16.cpp
@@ -97,18 +97,17 @@ uint32_t b16_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, c
{
for(int x=0;x<mc6845_h_display;x++)
{
- int tile = m_vram[x+y*mc6845_h_display] & 0xff;
- int color = (m_vram[x+y*mc6845_h_display] & 0x700) >> 8;
- int pen;
+ int const tile = m_vram[x+y*mc6845_h_display] & 0xff;
+ int const color = (m_vram[x+y*mc6845_h_display] & 0x700) >> 8;
for(int yi=0;yi<mc6845_tile_height;yi++)
{
for(int xi=0;xi<8;xi++)
{
- pen = (m_char_rom[tile*16+yi] >> (7-xi) & 1) ? color : 0;
+ int const pen = (m_char_rom[tile*16+yi] >> (7-xi) & 1) ? color : 0;
if(y*mc6845_tile_height < 400 && x*8+xi < 640) /* TODO: safety check */
- bitmap.pix16(y*mc6845_tile_height+yi, x*8+xi) = m_palette->pen(pen);
+ bitmap.pix(y*mc6845_tile_height+yi, x*8+xi) = m_palette->pen(pen);
}
}
}
diff --git a/src/mame/drivers/bagman.cpp b/src/mame/drivers/bagman.cpp
index 56c0a514555..0c7d093797e 100644
--- a/src/mame/drivers/bagman.cpp
+++ b/src/mame/drivers/bagman.cpp
@@ -137,10 +137,10 @@ void bagman_state::main_map(address_map &map)
map(0x9c00, 0x9fff).nopw(); // Written to, but unused
map(0xa000, 0xa000).r(FUNC(bagman_state::pal16r6_r));
map(0xa000, 0xa007).w("mainlatch", FUNC(ls259_device::write_d0));
- map(0xc000, 0xffff).rom(); // Super Bagman only
map(0xa800, 0xa807).w(FUNC(bagman_state::ls259_w)); // TMS5110 driving state machine
map(0xb000, 0xb000).portr("DSW");
map(0xb800, 0xb800).nopr(); // Looks like watchdog from schematics
+ map(0xc000, 0xffff).rom(); // Super Bagman only
#if 0
map(0xb000, 0xb000).nopw(); // ????
@@ -748,7 +748,7 @@ ROM_START( bagnardi ) // 1983
ROM_REGION (0x104, "plds", 0)
ROM_LOAD( "lebag_itisa_pal16r6cn.p6", 0x000, 0x104, CRC(13f14bbf) SHA1(b8c4ddf61609465f3a3699dd42796f15a7b17979) )
-
+
ROM_END
ROM_START( bagnardio ) // 1982, based on bagnard set with mods for license text
@@ -780,93 +780,127 @@ ROM_START( bagnardio ) // 1982, based on bagnard set with mods for license text
ROM_LOAD( "bagnardi_12.t9", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) ) // == t9_b12.bin
ROM_END
+/*
+Stern Bagman ROM labels follow this format:
+
+BAGMAN (c)
+A5 9F <-- Revision level and PCB location
+1983 STERN
+*/
ROM_START( bagmans )
ROM_REGION( 0x10000, "maincpu", 0 )
- ROM_LOAD( "a4_9e.bin", 0x0000, 0x1000, CRC(5fb0a1a3) SHA1(849cd60b58de9585a78a1c4c1747f666a4a4fcc3) )
- ROM_LOAD( "a5-9f", 0x1000, 0x1000, CRC(2ddf6bb9) SHA1(151068dddc55163bb6f925f68e5d04e347ded6a5) )
- ROM_LOAD( "a4_9j.bin", 0x2000, 0x1000, CRC(b2da8b77) SHA1(ea36cd6be42c5548a9a91054aeebb4b985ba15c9) )
- ROM_LOAD( "a5-9k", 0x3000, 0x1000, CRC(f91d617b) SHA1(a3323b51277e08747701cc4e2d3a9c466e96d4c1) )
- ROM_LOAD( "a4_9m.bin", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) )
- ROM_LOAD( "a5-9n", 0x5000, 0x1000, CRC(68e4b64d) SHA1(55950d7c07c621cafa001d5d3bfec6bbc02712e2) )
+ ROM_LOAD( "bagman_a4_9e.9e", 0x0000, 0x1000, CRC(5fb0a1a3) SHA1(849cd60b58de9585a78a1c4c1747f666a4a4fcc3) )
+ ROM_LOAD( "bagman_a5_9f.9f", 0x1000, 0x1000, CRC(2ddf6bb9) SHA1(151068dddc55163bb6f925f68e5d04e347ded6a5) )
+ ROM_LOAD( "bagman_a4_9j.9j", 0x2000, 0x1000, CRC(b2da8b77) SHA1(ea36cd6be42c5548a9a91054aeebb4b985ba15c9) )
+ ROM_LOAD( "bagman_a5_9k.9k", 0x3000, 0x1000, CRC(f91d617b) SHA1(a3323b51277e08747701cc4e2d3a9c466e96d4c1) )
+ ROM_LOAD( "bagman_a4_9m.9m", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) ) // == bagman_a2_9m.9m
+ ROM_LOAD( "bagman_a5_9n.9n", 0x5000, 0x1000, CRC(68e4b64d) SHA1(55950d7c07c621cafa001d5d3bfec6bbc02712e2) )
ROM_REGION( 0x2000, "gfx1", 0 )
- ROM_LOAD( "a2_1e.bin", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) )
- ROM_LOAD( "j1_b04.bin", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) )
+ ROM_LOAD( "bagman_a2_1e.1e", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) )
+ ROM_LOAD( "bagman_a2_1j.1j", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) )
ROM_REGION( 0x2000, "gfx2", 0 )
- ROM_LOAD( "a2_1c.bin", 0x0000, 0x1000, CRC(f3e11bd7) SHA1(43ee00ff777008c89f619eb183e7c5e63f6c7694) )
- ROM_LOAD( "a2_1f.bin", 0x1000, 0x1000, CRC(d0f7105b) SHA1(fb382703850a4ded567706e02ebb7f3e22531b7c) )
+ ROM_LOAD( "bagman_a2_1c.1c", 0x0000, 0x1000, CRC(f3e11bd7) SHA1(43ee00ff777008c89f619eb183e7c5e63f6c7694) )
+ ROM_LOAD( "bagman_a2_1f.1f", 0x1000, 0x1000, CRC(d0f7105b) SHA1(fb382703850a4ded567706e02ebb7f3e22531b7c) )
- // according to MT #02508 Stern/Seeburg logos should have different colors.
ROM_REGION( 0x0040, "proms", 0 )
- ROM_LOAD( "p3.bin", 0x0000, 0x0020, BAD_DUMP CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
- ROM_LOAD( "r3.bin", 0x0020, 0x0020, BAD_DUMP CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
+ ROM_LOAD( "bagman_color_3pa2.3p", 0x0000, 0x0020, CRC(47504204) SHA1(7524ed766cc6d9a158327717d2cf53346ace2392) ) // MMI 6331 BPROM
+ ROM_LOAD( "bagman_color_3ra1.3r", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) ) // MMI 6331 BPROM
ROM_REGION( 0x0020, "5110ctrl", 0)
- ROM_LOAD( "r6.bin", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
+ ROM_LOAD( "bagman_sound_6ra2.6r", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110 - MMI 6331 BPROM
ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
- ROM_LOAD( "r9_b11.bin", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
- ROM_LOAD( "t9_b12.bin", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
+ ROM_LOAD( "bagman_a1_9r.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
+ ROM_LOAD( "bagman_a1_9t.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
ROM_END
-ROM_START( bagmans2 )
+ROM_START( bagmans4 )
ROM_REGION( 0x10000, "maincpu", 0 )
- ROM_LOAD( "a4_9e.bin", 0x0000, 0x1000, CRC(5fb0a1a3) SHA1(849cd60b58de9585a78a1c4c1747f666a4a4fcc3) )
- ROM_LOAD( "a4_9f.bin", 0x1000, 0x1000, CRC(7871206e) SHA1(14d9b7a0779d59a870e0d4b911797dff5435a16c) )
- ROM_LOAD( "a4_9j.bin", 0x2000, 0x1000, CRC(b2da8b77) SHA1(ea36cd6be42c5548a9a91054aeebb4b985ba15c9) )
- ROM_LOAD( "a4_9k.bin", 0x3000, 0x1000, CRC(36b6a944) SHA1(270dd2566b36129366adcbdd5a8db396bec7631f) )
- ROM_LOAD( "a4_9m.bin", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) )
- ROM_LOAD( "a4_9n.bin", 0x5000, 0x1000, CRC(83fccb1c) SHA1(7225d738b64a2cdaaec8860017de4229f2852ed2) )
+ ROM_LOAD( "bagman_a4_9e.9e", 0x0000, 0x1000, CRC(5fb0a1a3) SHA1(849cd60b58de9585a78a1c4c1747f666a4a4fcc3) )
+ ROM_LOAD( "bagman_a4_9f.9f", 0x1000, 0x1000, CRC(7871206e) SHA1(14d9b7a0779d59a870e0d4b911797dff5435a16c) )
+ ROM_LOAD( "bagman_a4_9j.9j", 0x2000, 0x1000, CRC(b2da8b77) SHA1(ea36cd6be42c5548a9a91054aeebb4b985ba15c9) )
+ ROM_LOAD( "bagman_a4_9k.9k", 0x3000, 0x1000, CRC(36b6a944) SHA1(270dd2566b36129366adcbdd5a8db396bec7631f) )
+ ROM_LOAD( "bagman_a4_9m.9m", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) ) // == bagman_a2_9m.9m
+ ROM_LOAD( "bagman_a4_9n.9n", 0x5000, 0x1000, CRC(83fccb1c) SHA1(7225d738b64a2cdaaec8860017de4229f2852ed2) )
ROM_REGION( 0x2000, "gfx1", 0 )
- ROM_LOAD( "a2_1e.bin", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) )
- ROM_LOAD( "j1_b04.bin", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) )
+ ROM_LOAD( "bagman_a2_1e.1e", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) )
+ ROM_LOAD( "bagman_a2_1j.1j", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) )
ROM_REGION( 0x2000, "gfx2", 0 )
- ROM_LOAD( "a2_1c.bin", 0x0000, 0x1000, CRC(f3e11bd7) SHA1(43ee00ff777008c89f619eb183e7c5e63f6c7694) )
- ROM_LOAD( "a2_1f.bin", 0x1000, 0x1000, CRC(d0f7105b) SHA1(fb382703850a4ded567706e02ebb7f3e22531b7c) )
+ ROM_LOAD( "bagman_a2_1c.1c", 0x0000, 0x1000, CRC(f3e11bd7) SHA1(43ee00ff777008c89f619eb183e7c5e63f6c7694) )
+ ROM_LOAD( "bagman_a2_1f.1f", 0x1000, 0x1000, CRC(d0f7105b) SHA1(fb382703850a4ded567706e02ebb7f3e22531b7c) )
- // according to MT #02508 Stern/Seeburg logos should have different colors.
ROM_REGION( 0x0040, "proms", 0 )
- ROM_LOAD( "p3.bin", 0x0000, 0x0020, BAD_DUMP CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
- ROM_LOAD( "r3.bin", 0x0020, 0x0020, BAD_DUMP CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
+ ROM_LOAD( "bagman_color_3pa2.3p", 0x0000, 0x0020, CRC(47504204) SHA1(7524ed766cc6d9a158327717d2cf53346ace2392) ) // MMI 6331 BPROM
+ ROM_LOAD( "bagman_color_3ra1.3r", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) ) // MMI 6331 BPROM
ROM_REGION( 0x0020, "5110ctrl", 0)
- ROM_LOAD( "r6.bin", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
+ ROM_LOAD( "bagman_sound_6ra2.6r", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110 - MMI 6331 BPROM
ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
- ROM_LOAD( "r9_b11.bin", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
- ROM_LOAD( "t9_b12.bin", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
+ ROM_LOAD( "bagman_a1_9r.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
+ ROM_LOAD( "bagman_a1_9t.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
ROM_END
-ROM_START( bagmanj )
+ROM_START( bagmans3 ) // not compatible with the PAL16R6 emulator in ../mame/machine/bagman.cpp??
ROM_REGION( 0x10000, "maincpu", 0 )
- ROM_LOAD( "bf8_06.e9", 0x0000, 0x1000, CRC(5fb0a1a3) SHA1(849cd60b58de9585a78a1c4c1747f666a4a4fcc3) ) // 2732
- ROM_LOAD( "bf8_07.f9", 0x1000, 0x1000, CRC(7871206e) SHA1(14d9b7a0779d59a870e0d4b911797dff5435a16c) ) // 2732
- ROM_LOAD( "bf8_08.j9", 0x2000, 0x1000, CRC(ae037d0a) SHA1(57d287b3968a4e7fdee2a98014dbdf4fae93d157) ) // 2732
- ROM_LOAD( "bf8_09.k9", 0x3000, 0x1000, CRC(36b6a944) SHA1(270dd2566b36129366adcbdd5a8db396bec7631f) ) // 2732
- ROM_LOAD( "bf8_10.m9", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) ) // 2732
- ROM_LOAD( "bf8_11.n9", 0x5000, 0x1000, CRC(83fccb1c) SHA1(7225d738b64a2cdaaec8860017de4229f2852ed2) ) // 2732
+ ROM_LOAD( "bagman_a2_9e.9e", 0x0000, 0x1000, CRC(5f04d805) SHA1(84bcdfd25634879438429d2b41c491e092388add) )
+ ROM_LOAD( "bagman_a3_9f.9f", 0x1000, 0x1000, CRC(136a78aa) SHA1(14e6a556e00b6ebe718f2fe119b372dc7bfa78d9) )
+ ROM_LOAD( "bagman_a2_9j.9j", 0x2000, 0x1000, CRC(f94f5626) SHA1(0ec41c4957833e84e9e498fb4269dfd701a2e5b3) )
+ ROM_LOAD( "bagman_a2_9k.9k", 0x3000, 0x1000, CRC(31788fc1) SHA1(959af99490b96c390a43c76dc4e09b35ebda3a24) )
+ ROM_LOAD( "bagman_a2_9m.9m", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) )
+ ROM_LOAD( "bagman_a3_9n.9n", 0x5000, 0x1000, CRC(ab66d4c1) SHA1(b90ffc7a8e16abcb88bb5d4705622cfafdf08c81) )
ROM_REGION( 0x2000, "gfx1", 0 )
- ROM_LOAD( "bf8_03.e1", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) ) // 2732
- ROM_LOAD( "bf8_05.j1", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) ) // 2732
+ ROM_LOAD( "bagman_a2_1e.1e", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) )
+ ROM_LOAD( "bagman_a2_1j.1j", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) )
+
+ ROM_REGION( 0x2000, "gfx2", 0 )
+ ROM_LOAD( "bagman_a2_1c.1c", 0x0000, 0x1000, CRC(f3e11bd7) SHA1(43ee00ff777008c89f619eb183e7c5e63f6c7694) )
+ ROM_LOAD( "bagman_a2_1f.1f", 0x1000, 0x1000, CRC(d0f7105b) SHA1(fb382703850a4ded567706e02ebb7f3e22531b7c) )
+
+ ROM_REGION( 0x0040, "proms", 0 )
+ ROM_LOAD( "bagman_color_3pa2.3p", 0x0000, 0x0020, CRC(47504204) SHA1(7524ed766cc6d9a158327717d2cf53346ace2392) ) // MMI 6331 BPROM
+ ROM_LOAD( "bagman_color_3ra1.3r", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) ) // MMI 6331 BPROM
+
+ ROM_REGION( 0x0020, "5110ctrl", 0)
+ ROM_LOAD( "bagman_sound_6ra2.6r", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110 - MMI 6331 BPROM
+
+ ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
+ ROM_LOAD( "bagman_a1_9r.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
+ ROM_LOAD( "bagman_a1_9t.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
+ROM_END
+
+ROM_START( bagmanj ) // based on Stern's Bagman revision A4 set (bagmans4)
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "bf8_06.e9", 0x0000, 0x1000, CRC(5fb0a1a3) SHA1(849cd60b58de9585a78a1c4c1747f666a4a4fcc3) ) // 2732 == bagman_a4_9e.9e
+ ROM_LOAD( "bf8_07.f9", 0x1000, 0x1000, CRC(7871206e) SHA1(14d9b7a0779d59a870e0d4b911797dff5435a16c) ) // 2732 == bagman_a4_9f.9f
+ ROM_LOAD( "bf8_08.j9", 0x2000, 0x1000, CRC(ae037d0a) SHA1(57d287b3968a4e7fdee2a98014dbdf4fae93d157) ) // 2732
+ ROM_LOAD( "bf8_09.k9", 0x3000, 0x1000, CRC(36b6a944) SHA1(270dd2566b36129366adcbdd5a8db396bec7631f) ) // 2732 == bagman_a4_9k.9k
+ ROM_LOAD( "bf8_10.m9", 0x4000, 0x1000, CRC(b8e75eb6) SHA1(433fd736512f10bc0879b15821eb55cc41d58d33) ) // 2732 == bagman_a2_9m.9m
+ ROM_LOAD( "bf8_11.n9", 0x5000, 0x1000, CRC(83fccb1c) SHA1(7225d738b64a2cdaaec8860017de4229f2852ed2) ) // 2732 == bagman_a4_9n.9n
+
+ ROM_REGION( 0x2000, "gfx1", 0 )
+ ROM_LOAD( "bf8_03.e1", 0x0000, 0x1000, CRC(f217ac09) SHA1(a9716674401dff27344a01df8121b6b648688680) ) // 2732 == bagman_a2_1e.1e
+ ROM_LOAD( "bf8_05.j1", 0x1000, 0x1000, CRC(c680ef04) SHA1(79406bc786374abfcd9f548268c445b5c8d8858d) ) // 2732 == bagman_a2_1j.1j
ROM_REGION( 0x2000, "gfx2", 0 )
ROM_LOAD( "bf8_02.c1", 0x0000, 0x1000, CRC(404283ed) SHA1(18613670cf23181089812c02429e222db0340a60) ) // 2732
ROM_LOAD( "bf8_04-1.f1", 0x1000, 0x1000, CRC(3f5c991e) SHA1(853c629ba0b4739dcb1af669fd600a3d83fb2072) ) // 2732
ROM_REGION( 0x0040, "proms", 0 ) // not dumped for this set
- ROM_LOAD( "p3.bin", 0x0000, 0x0020, BAD_DUMP CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
- ROM_LOAD( "r3.bin", 0x0020, 0x0020, BAD_DUMP CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
+ ROM_LOAD( "bagman_color_3pa2.3p", 0x0000, 0x0020, BAD_DUMP CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
+ ROM_LOAD( "bagman_color_3ra1.3r", 0x0020, 0x0020, BAD_DUMP CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
ROM_REGION( 0x0020, "5110ctrl", 0) // not dumped for this set
- ROM_LOAD( "r6.bin", 0x0000, 0x0020, BAD_DUMP CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
+ ROM_LOAD( "bagman_sound_6ra2.6r", 0x0000, 0x0020, BAD_DUMP CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
- ROM_LOAD( "bf8_12.r9", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) ) // 2732
- ROM_LOAD( "bf8_13.t9", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) ) // 2732
+ ROM_LOAD( "bf8_12.r9", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) ) // 2732 == bagman_a1_9r.9r
+ ROM_LOAD( "bf8_13.t9", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) ) // 2732 == bagman_a1_9t.9t
ROM_END
ROM_START( botanic2 ) // PCB has Valadon logo with 'bajo licencia Itisa (Palamos)'.
@@ -921,23 +955,23 @@ ROM_START( sbagman )
ROM_CONTINUE( 0xce00, 0x0200 )
ROM_REGION( 0x2000, "gfx1", 0 )
- ROM_LOAD( "sb2v3.1e", 0x0000, 0x1000, CRC(f4d3d4e6) SHA1(167ad0259578966fe86384df844e69cf2cc77443) )
- ROM_LOAD( "sb4v3.1j", 0x1000, 0x1000, CRC(2c6a510d) SHA1(304064f11e80f4ec471174823b8aaf59844061ac) )
+ ROM_LOAD( "sb2v3.1e", 0x0000, 0x1000, CRC(f4d3d4e6) SHA1(167ad0259578966fe86384df844e69cf2cc77443) )
+ ROM_LOAD( "sb4v3.1j", 0x1000, 0x1000, CRC(2c6a510d) SHA1(304064f11e80f4ec471174823b8aaf59844061ac) )
ROM_REGION( 0x2000, "gfx2", 0 )
- ROM_LOAD( "sb1v3.1c", 0x0000, 0x1000, CRC(a046ff44) SHA1(af319cfb74e5efe435c26e971de13bd390f4b378) )
- ROM_LOAD( "sb3v3.1f", 0x1000, 0x1000, CRC(a4422da4) SHA1(3aa55ca8c99566c1c9eb097b6d645c4216e09dfb) )
+ ROM_LOAD( "sb1v3.1c", 0x0000, 0x1000, CRC(a046ff44) SHA1(af319cfb74e5efe435c26e971de13bd390f4b378) )
+ ROM_LOAD( "sb3v3.1f", 0x1000, 0x1000, CRC(a4422da4) SHA1(3aa55ca8c99566c1c9eb097b6d645c4216e09dfb) )
ROM_REGION( 0x0040, "proms", 0 ) // not dumped for this set
- ROM_LOAD( "p3.bin", 0x0000, 0x0020, BAD_DUMP CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
- ROM_LOAD( "r3.bin", 0x0020, 0x0020, BAD_DUMP CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
+ ROM_LOAD( "p3.bin", 0x0000, 0x0020, BAD_DUMP CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
+ ROM_LOAD( "r3.bin", 0x0020, 0x0020, BAD_DUMP CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
ROM_REGION( 0x0020, "5110ctrl", 0) // not dumped for this set
- ROM_LOAD( "r6.bin", 0x0000, 0x0020, BAD_DUMP CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
+ ROM_LOAD( "r6.bin", 0x0000, 0x0020, BAD_DUMP CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
- ROM_LOAD( "b11v3.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
- ROM_LOAD( "b12v3.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
+ ROM_LOAD( "b11v3.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
+ ROM_LOAD( "b12v3.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
ROM_END
ROM_START( sbagman2 )
@@ -945,41 +979,51 @@ ROM_START( sbagman2 )
ROM_LOAD( "5.9e", 0x0000, 0x1000, CRC(1b1d6b0a) SHA1(549161f6adc88fa16339815e05af33ca57815660) )
ROM_LOAD( "6.9f", 0x1000, 0x1000, CRC(ac49cb82) SHA1(5affa0c03bedf2c9d5368c7f075818e1760c12ae) )
ROM_LOAD( "7.9j", 0x2000, 0x1000, CRC(9a1c778d) SHA1(a655e25dc9efdf60cc5b34e42c93c4acaa4a7922) )
- ROM_LOAD( "8.9k", 0x3000, 0x1000, CRC(b94fbb73) SHA1(5d676c5d1d864d70d98f0137c4072062a781b3a0) )
- ROM_LOAD( "9.9m", 0x4000, 0x1000, CRC(601f34ba) SHA1(1b7ee61a341b9a87abe4fe10b0c647a9b0b97d38) )
- ROM_LOAD( "10.9n", 0x5000, 0x1000, CRC(5f750918) SHA1(3dc44f259e88999dbb95b4d4376281cc81c1ab87) )
+ ROM_LOAD( "sb8v3.9k", 0x3000, 0x1000, CRC(b94fbb73) SHA1(5d676c5d1d864d70d98f0137c4072062a781b3a0) )
+ ROM_LOAD( "sb9v3.9m", 0x4000, 0x1000, CRC(601f34ba) SHA1(1b7ee61a341b9a87abe4fe10b0c647a9b0b97d38) )
+ ROM_LOAD( "sb10v3.9n", 0x5000, 0x1000, CRC(5f750918) SHA1(3dc44f259e88999dbb95b4d4376281cc81c1ab87) )
ROM_LOAD( "13.8d", 0xc000, 0x0e00, CRC(944a4453) SHA1(cd64d9267d2c5cea39464ba9308752c690e7fd24) )
ROM_CONTINUE( 0xfe00, 0x0200 )
- ROM_LOAD( "14.8f", 0xd000, 0x0400, CRC(83b10139) SHA1(8a1880c6ab8a345676fe30465351d69cc1b416b2) )
+ ROM_LOAD( "sb14v3.8f", 0xd000, 0x0400, CRC(83b10139) SHA1(8a1880c6ab8a345676fe30465351d69cc1b416b2) )
ROM_CONTINUE( 0xe400, 0x0200 )
ROM_CONTINUE( 0xd600, 0x0a00 )
- ROM_LOAD( "15.8j", 0xe000, 0x0400, CRC(fe924879) SHA1(b80cbf9cba91e553f7685aef348854c02f0619c7) )
+ ROM_LOAD( "sb15v3.8j", 0xe000, 0x0400, CRC(fe924879) SHA1(b80cbf9cba91e553f7685aef348854c02f0619c7) )
ROM_CONTINUE( 0xd400, 0x0200 )
ROM_CONTINUE( 0xe600, 0x0a00 )
- ROM_LOAD( "16.8k", 0xf000, 0x0e00, CRC(b77eb1f5) SHA1(ef94c1b449e3fa230491052fc3bd4db3f1239263) )
+ ROM_LOAD( "sb16v3.8k", 0xf000, 0x0e00, CRC(b77eb1f5) SHA1(ef94c1b449e3fa230491052fc3bd4db3f1239263) )
ROM_CONTINUE( 0xce00, 0x0200 )
ROM_REGION( 0x2000, "gfx1", 0 )
- ROM_LOAD( "2.1e", 0x0000, 0x1000, CRC(f4d3d4e6) SHA1(167ad0259578966fe86384df844e69cf2cc77443) )
- ROM_LOAD( "4.1j", 0x1000, 0x1000, CRC(2c6a510d) SHA1(304064f11e80f4ec471174823b8aaf59844061ac) )
+ ROM_LOAD( "sb2v3.1e", 0x0000, 0x1000, CRC(f4d3d4e6) SHA1(167ad0259578966fe86384df844e69cf2cc77443) )
+ ROM_LOAD( "sb4v3.1j", 0x1000, 0x1000, CRC(2c6a510d) SHA1(304064f11e80f4ec471174823b8aaf59844061ac) )
ROM_REGION( 0x2000, "gfx2", 0 )
- ROM_LOAD( "1.1c", 0x0000, 0x1000, CRC(a046ff44) SHA1(af319cfb74e5efe435c26e971de13bd390f4b378) )
- ROM_LOAD( "3.1f", 0x1000, 0x1000, CRC(a4422da4) SHA1(3aa55ca8c99566c1c9eb097b6d645c4216e09dfb) )
+ ROM_LOAD( "sb1v3.1c", 0x0000, 0x1000, CRC(a046ff44) SHA1(af319cfb74e5efe435c26e971de13bd390f4b378) )
+ ROM_LOAD( "sb3v3.1f", 0x1000, 0x1000, CRC(a4422da4) SHA1(3aa55ca8c99566c1c9eb097b6d645c4216e09dfb) )
ROM_REGION( 0x0040, "proms", 0 )
- ROM_LOAD( "p3.bin", 0x0000, 0x0020, CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
- ROM_LOAD( "r3.bin", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
+ ROM_LOAD( "p3.bin", 0x0000, 0x0020, CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
+ ROM_LOAD( "r3.bin", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
ROM_REGION( 0x0020, "5110ctrl", 0)
- ROM_LOAD( "r6.bin", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
+ ROM_LOAD( "r6.bin", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
- ROM_LOAD( "11.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
- ROM_LOAD( "12.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
+ ROM_LOAD( "b11v3.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
+ ROM_LOAD( "b12v3.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
ROM_END
-ROM_START( sbagmans )
+/*
+Stern Super Bagman ROM labels follow this format:
+
+S. BAGMAN (c)
+A1 1F <-- Revision level and PCB location
+1984 STERN
+
+Most examples/photos of the PCB show several hand written labels.
+
+*/
+ROM_START( sbagmans ) // known to come in the form of a Bagman to Super Bagman conversion kit
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "sbag_9e.bin", 0x0000, 0x1000, CRC(c19696f2) SHA1(3a40202a97201a123033358f7afcb06f8ac15063) )
ROM_LOAD( "6.9f", 0x1000, 0x1000, CRC(ac49cb82) SHA1(5affa0c03bedf2c9d5368c7f075818e1760c12ae) )
@@ -999,23 +1043,23 @@ ROM_START( sbagmans )
ROM_CONTINUE( 0xce00, 0x0200 )
ROM_REGION( 0x2000, "gfx1", 0 )
- ROM_LOAD( "2.1e", 0x0000, 0x1000, CRC(f4d3d4e6) SHA1(167ad0259578966fe86384df844e69cf2cc77443) )
- ROM_LOAD( "4.1j", 0x1000, 0x1000, CRC(2c6a510d) SHA1(304064f11e80f4ec471174823b8aaf59844061ac) )
+ ROM_LOAD( "sb2v3.1e", 0x0000, 0x1000, CRC(f4d3d4e6) SHA1(167ad0259578966fe86384df844e69cf2cc77443) ) // hand written: SB #3 Ver3
+ ROM_LOAD( "sb4v3.1j", 0x1000, 0x1000, CRC(2c6a510d) SHA1(304064f11e80f4ec471174823b8aaf59844061ac) ) // hand written: SB #4 Ver3
ROM_REGION( 0x2000, "gfx2", 0 )
- ROM_LOAD( "sbag_1c.bin", 0x0000, 0x1000, CRC(262f870a) SHA1(90877b869a7e927cfa4f9729ec3d6eac3a95dc8f) )
- ROM_LOAD( "sbag_1f.bin", 0x1000, 0x1000, CRC(350ed0fb) SHA1(c7804e9618ebc88a1e3684a92a98d9a181441a1f) )
+ ROM_LOAD( "s._bagman_a1_1c.1c", 0x0000, 0x1000, CRC(262f870a) SHA1(90877b869a7e927cfa4f9729ec3d6eac3a95dc8f) )
+ ROM_LOAD( "s._bagman_a1_1f.1f", 0x1000, 0x1000, CRC(350ed0fb) SHA1(c7804e9618ebc88a1e3684a92a98d9a181441a1f) )
ROM_REGION( 0x0040, "proms", 0 )
- ROM_LOAD( "p3.bin", 0x0000, 0x0020, CRC(2a855523) SHA1(91e032233fee397c90b7c1662934aca9e0671482) )
- ROM_LOAD( "r3.bin", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) )
+ ROM_LOAD( "bagman_color_3pa2.3p", 0x0000, 0x0020, CRC(47504204) SHA1(7524ed766cc6d9a158327717d2cf53346ace2392) ) // MMI 6331 BPROM
+ ROM_LOAD( "bagman_color_3ra1.3r", 0x0020, 0x0020, CRC(ae6f1019) SHA1(fd711882b670380cb4bd909c840ba06277b8fbe3) ) // MMI 6331 BPROM
ROM_REGION( 0x0020, "5110ctrl", 0)
- ROM_LOAD( "r6.bin", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110
+ ROM_LOAD( "bagman_sound_6ra2.6r", 0x0000, 0x0020, CRC(c58a4f6a) SHA1(35ef244b3e94032df2610aa594ea5670b91e1449) ) // State machine driving TMS5110 - MMI 6331 BPROM
ROM_REGION( 0x2000, "tmsprom", 0 ) // Data for the TMS5110 speech chip
- ROM_LOAD( "11.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
- ROM_LOAD( "12.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
+ ROM_LOAD( "bagman_a1_9r.9r", 0x0000, 0x1000, CRC(2e0057ff) SHA1(33e3ffa6418f86864eb81e5e9bda4bf540c143a6) )
+ ROM_LOAD( "bagman_a1_9t.9t", 0x1000, 0x1000, CRC(b2120edd) SHA1(52b89dbcc749b084331fa82b13d0876e911fce52) )
ROM_END
/*
@@ -1182,24 +1226,31 @@ ROM_START( squaitsa )
ROM_END
-GAME( 1982, bagman, 0, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Bagman", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, bagnard, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Le Bagnard (set 1)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, bagnarda, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Le Bagnard (set 2)", MACHINE_SUPPORTS_SAVE )
-GAME( 1983, bagnardi, bagman, bagman, bagman, bagman_state, empty_init, ROT90, "Valadon Automation (Itisa license)", "Le Bagnard (Itisa, Spain)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, bagnardio, bagman, bagman, bagman, bagman_state, empty_init, ROT90, "Valadon Automation (Itisa license)", "Le Bagnard (Itisa, Spain, older)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, bagmans, bagman, bagman, bagmans, bagman_state, empty_init, ROT270, "Valadon Automation (Stern Electronics license)", "Bagman (Stern Electronics, set 1)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, bagmans2, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation (Stern Electronics license)", "Bagman (Stern Electronics, set 2)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, bagmanj, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation (Taito license)", "Bagman (Taito)", MACHINE_SUPPORTS_SAVE ) // Title screen actually doesn't mention Valadon, only Stern and Taito
+void bagman_state::init_bagmans3()
+{
+ // this earlier version has extra code at 0x5f98 - 0x5fa5 that reads a value from $ed01. Returning 0x01 allows starting a game and gives correct music tempo. TODO: What happens here? Fix this workaround
+ m_maincpu->space(AS_PROGRAM).install_read_handler(0xed01, 0xed01, read8smo_delegate(*this, []() { return 0x01; }, "hack_r"));
+}
+
+GAME( 1982, bagman, 0, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Bagman", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, bagnard, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Le Bagnard (set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, bagnarda, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Le Bagnard (set 2)", MACHINE_SUPPORTS_SAVE )
+GAME( 1983, bagnardi, bagman, bagman, bagman, bagman_state, empty_init, ROT90, "Valadon Automation (Itisa license)", "Le Bagnard (Itisa, Spain)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, bagnardio, bagman, bagman, bagman, bagman_state, empty_init, ROT90, "Valadon Automation (Itisa license)", "Le Bagnard (Itisa, Spain, older)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, bagmans, bagman, bagman, bagmans, bagman_state, empty_init, ROT270, "Valadon Automation (Stern Electronics license)", "Bagman (Stern Electronics, revision A5)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, bagmans4, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation (Stern Electronics license)", "Bagman (Stern Electronics, revision A4)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, bagmans3, bagman, bagman, bagman, bagman_state, init_bagmans3, ROT270, "Valadon Automation (Stern Electronics license)", "Bagman (Stern Electronics, revision A3)", MACHINE_UNEMULATED_PROTECTION | MACHINE_SUPPORTS_SAVE ) // see init_bagmans3(). Not sure it's actually protection
+GAME( 1982, bagmanj, bagman, bagman, bagman, bagman_state, empty_init, ROT270, "Valadon Automation (Taito license)", "Bagman (Taito)", MACHINE_SUPPORTS_SAVE ) // Title screen actually doesn't mention Valadon, only Stern and Taito
-GAME( 1984, sbagman, 0, sbagman, sbagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Super Bagman (version 5)", MACHINE_SUPPORTS_SAVE )
-GAME( 1984, sbagman2, sbagman, sbagman, sbagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Super Bagman (version 3?)", MACHINE_SUPPORTS_SAVE )
-GAME( 1984, sbagmani, sbagman, sbagmani, sbagman, bagman_state, empty_init, ROT90, "Valadon Automation (Itisa license)", "Super Bagman (Itisa, Spain)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // Different color PROMs, needs correct decoding
-GAME( 1984, sbagmans, sbagman, sbagman, sbagman, bagman_state, empty_init, ROT270, "Valadon Automation (Stern Electronics license)", "Super Bagman (Stern Electronics)", MACHINE_SUPPORTS_SAVE )
+GAME( 1984, sbagman, 0, sbagman, sbagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Super Bagman (version 5)", MACHINE_SUPPORTS_SAVE )
+GAME( 1984, sbagman2, sbagman, sbagman, sbagman, bagman_state, empty_init, ROT270, "Valadon Automation", "Super Bagman (version 3?)", MACHINE_SUPPORTS_SAVE )
+GAME( 1984, sbagmani, sbagman, sbagmani, sbagman, bagman_state, empty_init, ROT90, "Valadon Automation (Itisa license)", "Super Bagman (Itisa, Spain)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // Different color PROMs, needs correct decoding
+GAME( 1984, sbagmans, sbagman, sbagman, sbagman, bagman_state, empty_init, ROT270, "Valadon Automation (Stern Electronics license)", "Super Bagman (Stern Electronics)", MACHINE_SUPPORTS_SAVE )
-GAME( 1983, pickin, 0, pickin, pickin, bagman_state, empty_init, ROT270, "Valadon Automation", "Pickin'", MACHINE_SUPPORTS_SAVE )
+GAME( 1983, pickin, 0, pickin, pickin, bagman_state, empty_init, ROT270, "Valadon Automation", "Pickin'", MACHINE_SUPPORTS_SAVE )
-GAME( 1983, botanic, 0, botanic, botanici, bagman_state, empty_init, ROT90, "Itisa", "Botanic (English / Spanish, set 1)", MACHINE_SUPPORTS_SAVE )
-GAME( 1983, botanic2, botanic, bagman, botanici2, bagman_state, empty_init, ROT90, "Itisa", "Botanic (English / Spanish, set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // At the title screen, Botanic in corrupted in the first loop, OK from the second on. Colors likely wrong, too. Has a leftover 5110.
-GAME( 1984, botanicf, botanic, botanic, botanicf, bagman_state, empty_init, ROT270, "Itisa (Valadon Automation license)", "Botanic (French)", MACHINE_SUPPORTS_SAVE )
+GAME( 1983, botanic, 0, botanic, botanici, bagman_state, empty_init, ROT90, "Itisa", "Botanic (English / Spanish, set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1983, botanic2, botanic, bagman, botanici2, bagman_state, empty_init, ROT90, "Itisa", "Botanic (English / Spanish, set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // At the title screen, Botanic in corrupted in the first loop, OK from the second on. Colors likely wrong, too. Has a leftover 5110.
+GAME( 1984, botanicf, botanic, botanic, botanicf, bagman_state, empty_init, ROT270, "Itisa (Valadon Automation license)", "Botanic (French)", MACHINE_SUPPORTS_SAVE )
-GAME( 1984, squaitsa, 0, botanic, squaitsa, squaitsa_state, empty_init, ROT0, "Itisa", "Squash (Itisa)", MACHINE_SUPPORTS_SAVE )
+GAME( 1984, squaitsa, 0, botanic, squaitsa, squaitsa_state, empty_init, ROT0, "Itisa", "Squash (Itisa)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/banctec.cpp b/src/mame/drivers/banctec.cpp
index 8d5857a7a1f..220ad278819 100644
--- a/src/mame/drivers/banctec.cpp
+++ b/src/mame/drivers/banctec.cpp
@@ -87,16 +87,14 @@ void banctec_state::videoram_w(u8 data)
MC6845_UPDATE_ROW( banctec_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx;
- u16 mem,x;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u32 *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- mem = (ma + x) & 0xff;
- chr = m_videoram[mem];
- gfx = m_p_chargen[chr | (ra << 8)] ^ ((x == cursor_x) ? 0xff : 0);
+ u16 const mem = (ma + x) & 0xff;
+ u8 const chr = m_videoram[mem];
+ u8 const gfx = m_p_chargen[chr | (ra << 8)] ^ ((x == cursor_x) ? 0xff : 0);
/* Display a scanline of a character (8 pixels) */
*p++ = palette[BIT(gfx, 7)];
diff --git a/src/mame/drivers/bbc.cpp b/src/mame/drivers/bbc.cpp
index ce3ab361072..f29d8ad55dd 100644
--- a/src/mame/drivers/bbc.cpp
+++ b/src/mame/drivers/bbc.cpp
@@ -1181,6 +1181,8 @@ void bbc_state::bbcb(machine_config &config)
m_via6522_1->writepb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_w));
m_via6522_1->writepb_handler().append(m_internal, FUNC(bbc_internal_slot_device::latch_fe60_w));
m_via6522_1->ca2_handler().set("printer", FUNC(centronics_device::write_strobe));
+ m_via6522_1->cb1_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb1));
+ m_via6522_1->cb2_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb2));
m_via6522_1->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<2>));
/* adc */
@@ -1403,6 +1405,33 @@ void bbcbp_state::bbcbp128(machine_config &config)
}
+void bbcbp_state::cfa3000bp(machine_config &config)
+{
+ bbcbp(config);
+
+ /* fdc */
+ m_wd_fdc->subdevice<floppy_connector>("0")->set_default_option(nullptr);
+ m_wd_fdc->subdevice<floppy_connector>("1")->set_default_option(nullptr);
+
+ /* keyboard */
+ m_userport->set_default_option("cfa3000kbd");
+ m_userport->set_fixed(true);
+
+ /* option board */
+ m_1mhzbus->set_default_option("cfa3000opt");
+ m_1mhzbus->set_fixed(true);
+
+ /* analogue dials/sensors */
+ m_analog->set_default_option("cfa3000a");
+ m_analog->set_fixed(true);
+
+ /* software lists */
+ config.device_remove("cass_ls");
+ config.device_remove("flop_ls_b");
+ config.device_remove("flop_ls_b_orig");
+}
+
+
/***************************************************************************
Acorn Business Computers
@@ -1651,6 +1680,8 @@ void bbcm_state::bbcm(machine_config &config)
m_via6522_1->readpb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_r));
m_via6522_1->writepb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_w));
m_via6522_1->ca2_handler().set("printer", FUNC(centronics_device::write_strobe));
+ m_via6522_1->cb1_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb1));
+ m_via6522_1->cb2_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb2));
m_via6522_1->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<2>));
/* fdc */
@@ -1974,6 +2005,8 @@ void bbcm_state::bbcmc(machine_config &config)
m_via6522_1->readpb_handler().append(m_exp, FUNC(bbc_exp_slot_device::pb_r)).mask(0xe0);
m_via6522_1->writepb_handler().set(m_joyport, FUNC(bbc_joyport_slot_device::pb_w)).mask(0x1f);
m_via6522_1->writepb_handler().append(m_exp, FUNC(bbc_exp_slot_device::pb_w)).mask(0xe0);
+ m_via6522_1->cb1_handler().set(m_joyport, FUNC(bbc_joyport_slot_device::write_cb1));
+ m_via6522_1->cb2_handler().set(m_joyport, FUNC(bbc_joyport_slot_device::write_cb2));
/* cartridge sockets */
config.device_remove("cartslot1");
@@ -2864,11 +2897,60 @@ ROM_START(mpc900gx)
ROM_END
+ROM_START(cfa3000bp)
+ ROM_REGION(0x44000, "swr", ROMREGION_ERASEFF) /* Sideways ROMs */
+ ROM_LOAD("bpos2.ic71", 0x3c000, 0x8000, CRC(9f356396) SHA1(ea7d3a7e3ee1ecfaa1483af994048057362b01f2))
+ /* rom page 0 00000 SWRAM (B+ 128K only) */
+ /* rom page 1 04000 SWRAM (B+ 128K only) */
+ /* rom page 2 08000 IC35 32K IN PAGE 3 */
+ /* rom page 3 0c000 IC35 SPARE SOCKET */
+ /* rom page 4 10000 IC44 32K IN PAGE 5 */
+ /* rom page 5 14000 IC44 SPARE SOCKET */
+ /* rom page 6 18000 IC57 32K IN PAGE 7 */
+ /* rom page 7 1c000 IC57 SPARE SOCKET */
+ /* rom page 8 20000 IC62 32K IN PAGE 9 */
+ /* rom page 9 24000 IC62 SPARE SOCKET */
+ /* rom page 10 28000 IC68 32K IN PAGE 11 */
+ /* rom page 11 2c000 IC68 SPARE SOCKET */
+ /* rom page 12 30000 SWRAM (B+ 128K only) */
+ /* rom page 13 34000 SWRAM (B+ 128K only) */
+ /* rom page 14 38000 IC71 32K IN PAGE 15 */
+ /* rom page 15 3C000 IC71 BASIC */
+ ROM_SYSTEM_BIOS(0, "4", "Issue 4")
+ ROMX_LOAD("cfa3000_3.rom", 0x14000, 0x4000, CRC(4f246cd5) SHA1(6ba9625248c585deed5c651a889eecc86384a60d), ROM_BIOS(0))
+ ROMX_LOAD("cfa3000_4.rom", 0x1c000, 0x4000, CRC(ca0e30fd) SHA1(abddc7ba6d16855ebda2ef55fe8662bc545ae755), ROM_BIOS(0))
+ ROMX_LOAD("cfa3000_s.rom", 0x24000, 0x4000, CRC(71fd4c8a) SHA1(5bad70ee55403bc0191f6b189c9b6e5effdbca4c), ROM_BIOS(0))
+
+ /* link S13 set for BASIC to take low priority ROM numbers 0/1 */
+ ROM_COPY("swr", 0x3c000, 0x4000, 0x4000)
+ ROM_FILL(0x3c000, 0x4000, 0xff)
+
+ ROM_REGION(0x4000, "mos", 0)
+ ROM_COPY("swr", 0x40000, 0, 0x4000)
+
+ ROM_REGION(0x4000, "vsm", 0) /* system speech PHROM */
+ ROM_LOAD("phroma.bin", 0x0000, 0x4000, CRC(98e1bf9e) SHA1(b369809275cb67dfd8a749265e91adb2d2558ae6))
+ROM_END
+
+
ROM_START(cfa3000)
ROM_REGION(0x44000, "swr", ROMREGION_ERASEFF) /* Sideways ROMs */
- ROM_LOAD("cfa3000_3_4_iss10.3.ic41", 0x10000, 0x08000, CRC(ecb385ab) SHA1(eafa9b34cb1cf63790f74332bb7d85ee356b6973))
- ROM_LOAD("cfa3000_sm_iss10.3.ic37", 0x18000, 0x08000, CRC(c07aee5f) SHA1(1994e3755dc15d1ea7e105bc19cd57893b719779))
- ROM_LOAD("acorn_mos,tinsley_64k,iss10.3.ic24", 0x20000, 0x10000, CRC(4413c3ee) SHA1(76d0462b4dabe2461010fce2341570ff3d606d54))
+ ROM_SYSTEM_BIOS(0, "103", "Issue 10.3")
+ ROMX_LOAD("cfa3000_3m4_iss10.3.ic41", 0x10000, 0x08000, CRC(ecb385ab) SHA1(eafa9b34cb1cf63790f74332bb7d85ee356b6973), ROM_BIOS(0))
+ ROMX_LOAD("cfa3000_sm_iss10.3.ic37", 0x18000, 0x08000, CRC(c07aee5f) SHA1(1994e3755dc15d1ea7e105bc19cd57893b719779), ROM_BIOS(0))
+ ROMX_LOAD("acorn_mos,tinsley_64k,iss10.3.ic24", 0x20000, 0x10000, CRC(4413c3ee) SHA1(76d0462b4dabe2461010fce2341570ff3d606d54), ROM_BIOS(0))
+ ROM_SYSTEM_BIOS(1, "102", " Issue 10.2")
+ ROMX_LOAD("cfa3000_3m4_iss10.2.ic41", 0x10000, 0x08000, CRC(ecb385ab) SHA1(eafa9b34cb1cf63790f74332bb7d85ee356b6973), ROM_BIOS(1))
+ ROMX_LOAD("cfa3000_sm_iss10.2.ic37", 0x18000, 0x08000, CRC(e733d5b3) SHA1(07e89943c6ac0953b75686ee06e947f33119dbed), ROM_BIOS(1))
+ ROMX_LOAD("acorn_mos,tinsley_64k,iss10.2.ic24", 0x20000, 0x10000, CRC(4413c3ee) SHA1(76d0462b4dabe2461010fce2341570ff3d606d54), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(2, "9", " Issue 9")
+ ROMX_LOAD("cfa3000_3m4_iss9.ic41", 0x10000, 0x08000, CRC(a4bd5d53) SHA1(90747ff7bd81ac1e124bae964c206d8df163e1d6), ROM_BIOS(2))
+ ROMX_LOAD("cfa3000_sm_iss9.ic37", 0x18000, 0x08000, CRC(559d1fae) SHA1(271e1ab9b53e82028e92e7cdb8c517df06e76477), ROM_BIOS(2))
+ ROMX_LOAD("acorn_mos,tinsley_64k,iss9.ic24", 0x20000, 0x10000, CRC(4413c3ee) SHA1(76d0462b4dabe2461010fce2341570ff3d606d54), ROM_BIOS(2))
+ ROM_SYSTEM_BIOS(3, "7", "Issue 7")
+ ROMX_LOAD("cfa3000_3m4_iss7.ic41", 0x10000, 0x08000, CRC(a0b32288) SHA1(83b047e9eb35f0644bd8f0acb1a56e1428bacc0b), ROM_BIOS(3))
+ ROMX_LOAD("cfa3000_sm_iss7.ic37", 0x18000, 0x08000, CRC(3cd42bbd) SHA1(17f6c66039d20a364cc9e1377c7ced14d5302603), ROM_BIOS(3))
+ ROMX_LOAD("acorn_mos,tinsley_64k,iss7.ic24", 0x20000, 0x10000, CRC(4413c3ee) SHA1(76d0462b4dabe2461010fce2341570ff3d606d54), ROM_BIOS(3))
ROM_COPY("swr", 0x20000, 0x30000, 0x10000) /* Mirror MOS */
ROM_COPY("swr", 0x30000, 0x40000, 0x04000) /* Move loaded roms into place */
ROM_FILL(0x30000, 0x4000, 0xff)
@@ -2902,39 +2984,50 @@ ROM_END
#define rom_ltmpm rom_bbcm
-/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
-COMP ( 1981, bbcb, 0, bbca, bbcb, bbcb, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model B", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1981, bbca, bbcb, 0, bbca, bbca, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model A", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1982, bbcb_de, bbcb, 0, bbcb_de, bbcb, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model B (German)", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1983, bbcb_us, bbcb, 0, bbcb_us, bbcb, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model B (US)", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1982, torchf, bbcb, 0, torchf, torchb, torch_state, init_bbc, "Torch Computers", "Torch CF240", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1983, torchh, bbcb, 0, torchh, torchb, torch_state, init_bbc, "Torch Computers", "Torch CH240", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1984, torch301, bbcb, 0, torch301, torchi, torch_state, init_bbc, "Torch Computers", "Torch Model 301", MACHINE_NOT_WORKING)
-COMP ( 1984, torch725, bbcb, 0, torch725, torchi, torch_state, init_bbc, "Torch Computers", "Torch Model 725", MACHINE_NOT_WORKING)
-COMP ( 1985, bbcbp, 0, bbcb, bbcbp, bbcbp, bbcbp_state, init_bbc, "Acorn Computers", "BBC Micro Model B+ 64K", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1985, bbcbp128, bbcbp, 0, bbcbp128, bbcbp, bbcbp_state, init_bbc, "Acorn Computers", "BBC Micro Model B+ 128K", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1985, abc110, bbcbp, 0, abc110, abc, bbcbp_state, init_bbc, "Acorn Computers", "ABC 110", MACHINE_NOT_WORKING)
-COMP ( 1985, acw443, bbcbp, 0, acw443, abc, bbcbp_state, init_bbc, "Acorn Computers", "ABC 210/Cambridge Workstation", MACHINE_NOT_WORKING)
-COMP ( 1985, abc310, bbcbp, 0, abc310, abc, bbcbp_state, init_bbc, "Acorn Computers", "ABC 310", MACHINE_NOT_WORKING)
-COMP ( 1985, ltmpbp, bbcbp, 0, bbcbp, ltmpbp, bbcbp_state, init_ltmp, "Lawrie T&M Ltd.", "LTM Portable (B+)", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1985, reutapm, bbcbp, 0, reutapm, bbcb, bbcbp_state, init_bbc, "Acorn Computers", "Reuters APM", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING)
-COMP ( 1986, econx25, bbcbp, 0, econx25, bbcbp, bbcbp_state, init_bbc, "Acorn Computers", "Econet X25 Gateway", MACHINE_NOT_WORKING)
-COMP ( 1986, bbcm, 0, bbcb, bbcm, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master 128", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1986, bbcmt, bbcm, 0, bbcmt, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master Turbo", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1986, bbcmaiv, bbcm, 0, bbcmaiv, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master AIV", MACHINE_NOT_WORKING)
-COMP ( 1986, bbcmet, bbcm, 0, bbcmet, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master ET", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1986, bbcm512, bbcm, 0, bbcm512, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master 512", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1986, bbcmarm, bbcm, 0, bbcmarm, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master (ARM Evaluation)", MACHINE_NOT_WORKING)
-COMP ( 1986, ltmpm, bbcm, 0, bbcm, ltmpm, bbcm_state, init_ltmp, "Lawrie T&M Ltd.", "LTM Portable (Master)", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1987, daisy, bbcm, 0, daisy, bbcm, bbcm_state, init_bbc, "Comus Instruments Ltd.", "Comus Daisy", MACHINE_NOT_WORKING)
-COMP ( 1986, bbcmc, 0, bbcm, bbcmc, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master Compact", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1986, bbcmc_ar, bbcmc, 0, bbcmc, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master Compact (Arabic)", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1987, pro128s, bbcmc, 0, pro128s, bbcm, bbcm_state, init_bbc, "Olivetti", "Prodest PC 128S", MACHINE_IMPERFECT_GRAPHICS)
-COMP ( 1988, autoc15, bbcmc, 0, autoc15, autoc, bbcm_state, init_bbc, "Autocue Ltd.", "Autocue 1500 Telepromter", MACHINE_NOT_WORKING)
-COMP ( 1988, discmon, bbcm, 0, discmon, bbcm, bbcm_state, init_bbc, "Arbiter Leisure", "Arbiter Discmonitor A-01", MACHINE_NOT_WORKING)
-COMP ( 1988, discmate, bbcm, 0, discmate, bbcm, bbcm_state, init_bbc, "Arbiter Leisure", "Arbiter Discmate A-02", MACHINE_NOT_WORKING)
-//COMP ( 1988, discmast, bbcm, 0, discmast, bbcm, bbcm_state, init_bbc, "Arbiter Leisure", "Arbiter Discmaster A-03", MACHINE_NOT_WORKING)
-COMP ( 1987, mpc800, bbcm, 0, mpc800, bbcm, bbcm_state, init_bbc, "G2 Systems", "MasterPieCe 800 Series", MACHINE_NOT_WORKING)
-COMP ( 1988, mpc900, bbcm, 0, mpc900, bbcm, bbcm_state, init_bbc, "G2 Systems", "MasterPieCe 900 Series", MACHINE_NOT_WORKING)
-COMP ( 1990, mpc900gx, bbcm, 0, mpc900gx, bbcm, bbcm_state, init_bbc, "G2 Systems", "MasterPieCe 900GX Series", MACHINE_NOT_WORKING)
-COMP ( 1989, cfa3000, bbcm, 0, cfa3000, bbcm, bbcm_state, init_cfa, "Tinsley Medical Instruments", "Henson CFA 3000", MACHINE_NOT_WORKING)
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
+
+/* Acorn Computers */
+COMP( 1981, bbcb, 0, bbca, bbcb, bbcb, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model B", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1981, bbca, bbcb, 0, bbca, bbca, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model A", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1982, bbcb_de, bbcb, 0, bbcb_de, bbcb, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model B (German)", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1983, bbcb_us, bbcb, 0, bbcb_us, bbcb, bbc_state, init_bbc, "Acorn Computers", "BBC Micro Model B (US)", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1985, bbcbp, 0, bbcb, bbcbp, bbcbp, bbcbp_state, init_bbc, "Acorn Computers", "BBC Micro Model B+ 64K", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1985, bbcbp128, bbcbp, 0, bbcbp128, bbcbp, bbcbp_state, init_bbc, "Acorn Computers", "BBC Micro Model B+ 128K", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1985, abc110, bbcbp, 0, abc110, abc, bbcbp_state, init_bbc, "Acorn Computers", "ABC 110", MACHINE_NOT_WORKING )
+COMP( 1985, acw443, bbcbp, 0, acw443, abc, bbcbp_state, init_bbc, "Acorn Computers", "ABC 210/Cambridge Workstation", MACHINE_NOT_WORKING )
+COMP( 1985, abc310, bbcbp, 0, abc310, abc, bbcbp_state, init_bbc, "Acorn Computers", "ABC 310", MACHINE_NOT_WORKING )
+COMP( 1985, reutapm, bbcbp, 0, reutapm, bbcb, bbcbp_state, init_bbc, "Acorn Computers", "Reuters APM", MACHINE_NO_SOUND_HW | MACHINE_NOT_WORKING )
+COMP( 1986, econx25, bbcbp, 0, econx25, bbcbp, bbcbp_state, init_bbc, "Acorn Computers", "Econet X25 Gateway", MACHINE_NOT_WORKING )
+COMP( 1986, bbcm, 0, bbcb, bbcm, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master 128", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1986, bbcmt, bbcm, 0, bbcmt, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master Turbo", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1986, bbcmaiv, bbcm, 0, bbcmaiv, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master AIV", MACHINE_NOT_WORKING )
+COMP( 1986, bbcmet, bbcm, 0, bbcmet, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master ET", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1986, bbcm512, bbcm, 0, bbcm512, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master 512", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1986, bbcmarm, bbcm, 0, bbcmarm, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master (ARM Evaluation)", MACHINE_NOT_WORKING )
+COMP( 1986, bbcmc, 0, bbcm, bbcmc, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master Compact", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1986, bbcmc_ar, bbcmc, 0, bbcmc, bbcm, bbcm_state, init_bbc, "Acorn Computers", "BBC Master Compact (Arabic)", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1987, pro128s, bbcmc, 0, pro128s, bbcm, bbcm_state, init_bbc, "Olivetti", "Prodest PC 128S", MACHINE_IMPERFECT_GRAPHICS )
+
+/* Torch Computers */
+COMP( 1982, torchf, bbcb, 0, torchf, torchb, torch_state, init_bbc, "Torch Computers", "Torch CF240", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1983, torchh, bbcb, 0, torchh, torchb, torch_state, init_bbc, "Torch Computers", "Torch CH240", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1984, torch301, bbcb, 0, torch301, torchi, torch_state, init_bbc, "Torch Computers", "Torch Model 301", MACHINE_NOT_WORKING )
+COMP( 1984, torch725, bbcb, 0, torch725, torchi, torch_state, init_bbc, "Torch Computers", "Torch Model 725", MACHINE_NOT_WORKING )
+
+/* TV Production */
+COMP( 1988, autoc15, bbcmc, 0, autoc15, autoc, bbcm_state, init_bbc, "Autocue Ltd.", "Autocue 1500 Teleprompter", MACHINE_NOT_WORKING )
+COMP( 1987, mpc800, bbcm, 0, mpc800, bbcm, bbcm_state, init_bbc, "G2 Systems", "MasterPieCe 800 Series", MACHINE_NOT_WORKING )
+COMP( 1988, mpc900, bbcm, 0, mpc900, bbcm, bbcm_state, init_bbc, "G2 Systems", "MasterPieCe 900 Series", MACHINE_NOT_WORKING )
+COMP( 1990, mpc900gx, bbcm, 0, mpc900gx, bbcm, bbcm_state, init_bbc, "G2 Systems", "MasterPieCe 900GX Series", MACHINE_NOT_WORKING )
+
+/* Jukeboxes */
+COMP( 1988, discmon, bbcm, 0, discmon, bbcm, bbcm_state, init_bbc, "Arbiter Leisure", "Arbiter Discmonitor A-01", MACHINE_NOT_WORKING )
+COMP( 1988, discmate, bbcm, 0, discmate, bbcm, bbcm_state, init_bbc, "Arbiter Leisure", "Arbiter Discmate A-02", MACHINE_NOT_WORKING )
+//COMP( 1988, discmast, bbcm, 0, discmast, bbcm, bbcm_state, init_bbc, "Arbiter Leisure", "Arbiter Discmaster A-03", MACHINE_NOT_WORKING )
+
+/* Industrial */
+COMP( 1985, ltmpbp, bbcbp, 0, bbcbp, ltmpbp, bbcbp_state, init_ltmp, "Lawrie T&M Ltd.", "LTM Portable (B+)", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1986, ltmpm, bbcm, 0, bbcm, ltmpm, bbcm_state, init_ltmp, "Lawrie T&M Ltd.", "LTM Portable (Master)", MACHINE_IMPERFECT_GRAPHICS )
+COMP( 1987, daisy, bbcm, 0, daisy, bbcm, bbcm_state, init_bbc, "Comus Instruments Ltd.", "Comus Daisy", MACHINE_NOT_WORKING )
+COMP( 198?, cfa3000bp, bbcbp, 0, cfa3000bp, bbcbp, bbcbp_state, init_cfa, "Tinsley Medical Instruments", "Henson CFA 3000 (B+)", MACHINE_NOT_WORKING )
+COMP( 1989, cfa3000, bbcm, 0, cfa3000, bbcm, bbcm_state, init_cfa, "Tinsley Medical Instruments", "Henson CFA 3000 (Master)", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/bcs3.cpp b/src/mame/drivers/bcs3.cpp
index 8660ded8640..1bb81ef9fc7 100644
--- a/src/mame/drivers/bcs3.cpp
+++ b/src/mame/drivers/bcs3.cpp
@@ -265,24 +265,24 @@ INPUT_PORTS_END
// Official version
u32 bcs3_state::screen_update_bcs3(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx,rat;
- u16 sy=0,ma=0x50,x;
+ u16 sy=0,ma=0x50;
- for (y = 0; y < 12; y++)
+ for (u8 y = 0; y < 12; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (u8 ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
- rat = (ra + 1) & 7;
+ uint16_t *p = &bitmap.pix(sy++);
+ u8 const rat = (ra + 1) & 7;
- for (x = ma; x < ma + 28; x++)
+ for (u16 x = ma; x < ma + 28; x++)
{
+ u8 gfx;
if (ra < 8)
{
- chr = m_p_videoram[x] & 0x7f;
+ u8 const chr = m_p_videoram[x] & 0x7f;
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<3) | rat ] ^ 0xff;
+ gfx = m_p_chargen[(chr<<3) | rat] ^ 0xff;
}
else
gfx = 0xff;
@@ -307,27 +307,27 @@ u32 bcs3_state::screen_update_bcs3(screen_device &screen, bitmap_ind16 &bitmap,
I'm assuming that it only shows a portion of this, with the cursor always in sight. */
u32 bcs3_state::screen_update_bcs3a(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx,rat;
- u16 sy = 0, ma = s_init, x;
- u16 cursor = (m_p_videoram[s_curs] | (m_p_videoram[s_curs+1] << 8)) - 0x3c00 - ma; // get cursor relative position
- rat = cursor / (s_cols+1);
- if (rat > (s_rows-1)) ma += (rat-(s_rows-1)) * (s_cols+1);
+ u16 sy = 0, ma = s_init;
+ u16 const cursor = (m_p_videoram[s_curs] | (m_p_videoram[s_curs+1] << 8)) - 0x3c00 - ma; // get cursor relative position
+ u8 const cw = cursor / (s_cols+1);
+ if (cw > (s_rows-1)) ma += (cw-(s_rows-1)) * (s_cols+1);
- for (y = 0; y < s_rows; y++)
+ for (u8 y = 0; y < s_rows; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (u8 ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
- rat = (ra + 1) & 7;
+ uint16_t *p = &bitmap.pix(sy++);
+ u8 const rat = (ra + 1) & 7;
- for (x = ma; x < ma + s_cols; x++)
+ for (u16 x = ma; x < ma + s_cols; x++)
{
+ u8 gfx;
if (ra < 8)
{
- chr = m_p_videoram[x] & 0x7f;
+ u8 const chr = m_p_videoram[x] & 0x7f;
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<3) | rat ] ^ 0xff;
+ gfx = m_p_chargen[(chr<<3) | rat] ^ 0xff;
}
else
gfx = 0xff;
diff --git a/src/mame/drivers/beaminv.cpp b/src/mame/drivers/beaminv.cpp
index e323210244f..91b9e7b664d 100644
--- a/src/mame/drivers/beaminv.cpp
+++ b/src/mame/drivers/beaminv.cpp
@@ -186,23 +186,19 @@ void beaminv_state::machine_reset()
uint32_t beaminv_state::screen_update_beaminv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- int i;
-
uint8_t y = offs;
uint8_t x = offs >> 8 << 3;
uint8_t data = m_videoram[offs];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
pen_t pen = (data & 0x01) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- data = data >> 1;
- x = x + 1;
+ data >>= 1;
+ x++;
}
}
diff --git a/src/mame/drivers/beezer.cpp b/src/mame/drivers/beezer.cpp
index 64ccb3971e9..4d6a88944ce 100644
--- a/src/mame/drivers/beezer.cpp
+++ b/src/mame/drivers/beezer.cpp
@@ -257,8 +257,8 @@ uint32_t beezer_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap
{
for (int x = cliprect.min_x; x <= cliprect.max_x; x += 2)
{
- bitmap.pix16(y, x + 1) = m_videoram[0x80 * x + y] & 0x0f;
- bitmap.pix16(y, x + 0) = m_videoram[0x80 * x + y] >> 4;
+ bitmap.pix(y, x + 1) = m_videoram[0x80 * x + y] & 0x0f;
+ bitmap.pix(y, x + 0) = m_videoram[0x80 * x + y] >> 4;
}
}
@@ -554,7 +554,7 @@ void beezer_state::beezer(machine_config &config)
// schematics show an input labeled VCO to channel 2, but the source is unknown
mm5837_device &noise(MM5837(config, "noise"));
- noise.set_vdd_voltage(12);
+ noise.set_vdd(-12);
noise.output_callback().set(FUNC(beezer_state::noise_w));
SPEAKER(config, "speaker").front_center();
diff --git a/src/mame/drivers/berzerk.cpp b/src/mame/drivers/berzerk.cpp
index 778046da173..6d45d41f3aa 100644
--- a/src/mame/drivers/berzerk.cpp
+++ b/src/mame/drivers/berzerk.cpp
@@ -492,30 +492,30 @@ uint32_t berzerk_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma
for (int offs = 0; offs < m_videoram.bytes(); offs++)
{
- int i;
-
uint8_t data = m_videoram[offs];
uint8_t color = m_colorram[((offs >> 2) & 0x07e0) | (offs & 0x001f)];
uint8_t y = offs >> 5;
uint8_t x = offs << 3;
+ int i;
+
for (i = 0; i < 4; i++)
{
rgb_t pen = (data & 0x80) ? pens[color >> 4] : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- x = x + 1;
- data = data << 1;
+ x++;
+ data <<= 1;
}
for (; i < 8; i++)
{
rgb_t pen = (data & 0x80) ? pens[color & 0x0f] : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- x = x + 1;
- data = data << 1;
+ x++;
+ data <<= 1;
}
}
diff --git a/src/mame/drivers/bfcobra.cpp b/src/mame/drivers/bfcobra.cpp
index ccbefc4235f..c960664c5f8 100644
--- a/src/mame/drivers/bfcobra.cpp
+++ b/src/mame/drivers/bfcobra.cpp
@@ -415,20 +415,16 @@ void bfcobra_state::video_start()
uint32_t bfcobra_state::screen_update_bfcobra(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x, y;
- uint8_t *src;
- uint32_t *dest;
- uint32_t offset;
- uint8_t *hirescol;
- uint8_t *lorescol;
-
/* Select screen has to be programmed into two registers */
/* No idea what happens if the registers are different */
+ uint32_t offset;
if (m_flip_8 & 0x40 && m_flip_22 & 0x40)
offset = 0x10000;
else
offset = 0;
+ uint8_t const *hirescol;
+ uint8_t const *lorescol;
if(m_videomode & 0x20)
{
hirescol = m_col3bit;
@@ -445,16 +441,16 @@ uint32_t bfcobra_state::screen_update_bfcobra(screen_device &screen, bitmap_rgb3
lorescol = m_col8bit;
}
- for (y = cliprect.top(); y <= cliprect.bottom(); ++y)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); ++y)
{
uint16_t y_offset = (y + m_v_scroll) * 256;
- src = &m_video_ram[offset + y_offset];
- dest = &bitmap.pix32(y);
+ uint8_t const *const src = &m_video_ram[offset + y_offset];
+ uint32_t *dest = &bitmap.pix(y);
- for (x = cliprect.left(); x <= cliprect.right() / 2; ++x)
+ for (int x = cliprect.left(); x <= cliprect.right() / 2; ++x)
{
- uint8_t x_offset = x + m_h_scroll;
- uint8_t pen = *(src + x_offset);
+ uint8_t const x_offset = x + m_h_scroll;
+ uint8_t const pen = *(src + x_offset);
if ( ( m_videomode & 0x81 ) == 1 || (m_videomode & 0x80 && pen & 0x80) )
{
@@ -2323,21 +2319,16 @@ void bfcobjam_state::chipset_w(offs_t offset, uint8_t data)
uint32_t bfcobjam_state::screen_update_bfcobjam(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x, y;
- uint8_t *src;
- uint32_t *dest;
- uint32_t offset;
- uint8_t *hirescol;
- uint8_t *lorescol;
-
-
/* Select screen has to be programmed into two registers */
/* No idea what happens if the registers are different */
+ uint32_t offset;
if (m_flip_8 & 0x40 && m_flip_22 & 0x40)
offset = 0x10000;
else
offset = 0;
+ uint8_t const *hirescol;
+ uint8_t const *lorescol;
if(m_videomode & 0x20)
{
hirescol = m_col3bit;
@@ -2354,16 +2345,16 @@ uint32_t bfcobjam_state::screen_update_bfcobjam(screen_device &screen, bitmap_rg
lorescol = m_col8bit;
}
- for (y = cliprect.top(); y <= cliprect.bottom(); ++y)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); ++y)
{
- uint16_t y_offset = (y + m_v_scroll) * 256;
- src = &m_video_ram[offset + y_offset];
- dest = &bitmap.pix32(y);
+ uint16_t const y_offset = (y + m_v_scroll) * 256;
+ uint8_t const *const src = &m_video_ram[offset + y_offset];
+ uint32_t *dest = &bitmap.pix(y);
- for (x = cliprect.left(); x <= cliprect.right() / 2; ++x)
+ for (int x = cliprect.left(); x <= cliprect.right() / 2; ++x)
{
- uint8_t x_offset = x + m_h_scroll;
- uint8_t pen = *(src + x_offset);
+ uint8_t const x_offset = x + m_h_scroll;
+ uint8_t const pen = *(src + x_offset);
if ( ( m_videomode & 0x81 ) == 1 || (m_videomode & 0x80 && pen & 0x80) )
{
diff --git a/src/mame/drivers/bigbord2.cpp b/src/mame/drivers/bigbord2.cpp
index dc597cba79d..a80176597bc 100644
--- a/src/mame/drivers/bigbord2.cpp
+++ b/src/mame/drivers/bigbord2.cpp
@@ -554,21 +554,19 @@ u8 bigbord2_state::crt8002(u8 ac_ra, u8 ac_chr, u8 ac_attr, uint16_t ac_cnt, boo
MC6845_UPDATE_ROW( bigbord2_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx,attr;
- uint16_t mem,x;
- uint32_t *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
ra &= 15;
m_cnt++;
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- mem = (ma + x) & 0x7ff;
- attr = m_aram[mem];
- chr = m_vram[mem];
+ u16 mem = (ma + x) & 0x7ff;
+ u8 attr = m_aram[mem];
+ u8 chr = m_vram[mem];
/* process attributes */
- gfx = crt8002(ra, chr, attr, m_cnt, (x==cursor_x));
+ u8 gfx = crt8002(ra, chr, attr, m_cnt, (x==cursor_x));
/* Display a scanline of a character */
*p++ = palette[BIT( gfx, 7 )];
diff --git a/src/mame/drivers/bingor.cpp b/src/mame/drivers/bingor.cpp
index 63a39cc8c05..1d20658a6e3 100644
--- a/src/mame/drivers/bingor.cpp
+++ b/src/mame/drivers/bingor.cpp
@@ -564,37 +564,32 @@ void bingor_state::video_start()
uint32_t bingor_state::screen_update_bingor(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,count;
-
bitmap.fill(m_palette->black_pen(), cliprect);
- count = (0x2000 / 2);
-
- for(y = 0; y < 256; y++)
+ int count = (0x2000 / 2);
+ for(int y = 0; y < 256; y++)
{
- for(x = 0; x < 286; x += 4)
+ for(int x = 0; x < 286; x += 4)
{
- uint32_t color;
-
- color = (m_blit_ram[count] & 0xf000) >> 12;
+ uint32_t color = (m_blit_ram[count] & 0xf000) >> 12;
if(cliprect.contains(x + 3, y))
- bitmap.pix32(y, x + 3) = m_palette->pen(color);
+ bitmap.pix(y, x + 3) = m_palette->pen(color);
color = (m_blit_ram[count] & 0x0f00) >> 8;
if(cliprect.contains(x + 2, y))
- bitmap.pix32(y, x + 2) = m_palette->pen(color);
+ bitmap.pix(y, x + 2) = m_palette->pen(color);
color = (m_blit_ram[count] & 0x00f0) >> 4;
if(cliprect.contains(x + 1, y))
- bitmap.pix32(y, x + 1) = m_palette->pen(color);
+ bitmap.pix(y, x + 1) = m_palette->pen(color);
color = (m_blit_ram[count] & 0x000f) >> 0;
if(cliprect.contains(x + 0, y))
- bitmap.pix32(y, x + 0) = m_palette->pen(color);
+ bitmap.pix(y, x + 0) = m_palette->pen(color);
count++;
}
diff --git a/src/mame/drivers/bitgraph.cpp b/src/mame/drivers/bitgraph.cpp
index 89207357183..52279795d3c 100644
--- a/src/mame/drivers/bitgraph.cpp
+++ b/src/mame/drivers/bitgraph.cpp
@@ -384,16 +384,13 @@ void bitgraph_state::adlc_w(offs_t offset, uint8_t data)
uint32_t bitgraph_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t gfx = 0;
- int x, y;
-
- for (y = 0; y < 768; y++)
+ for (int y = 0; y < 768; y++)
{
- uint16_t *p = &bitmap.pix16(y);
+ uint16_t *p = &bitmap.pix(y);
- for (x = 0; x < 1024 / 8; x += 2)
+ for (int x = 0; x < 1024 / 8; x += 2)
{
- gfx = m_videoram[(x + 1) | (y << 7)];
+ uint8_t gfx = m_videoram[(x + 1) | (y << 7)];
for (int i = 7; i >= 0; i--)
{
*p++ = BIT(gfx, i);
diff --git a/src/mame/drivers/blitz68k.cpp b/src/mame/drivers/blitz68k.cpp
index 8b7a6c96874..2fdfb11ef41 100644
--- a/src/mame/drivers/blitz68k.cpp
+++ b/src/mame/drivers/blitz68k.cpp
@@ -12,6 +12,7 @@ Year Game Manufacturer
----------------------------------------------------------------------
1990 Mega Double Poker Blitz Systems Inc.
1990 Mega Double Poker Jackpot Blitz Systems Inc.
+1992 Mega Double Strip Blitz Systems Inc.
1993 Bank Robbery Entertainment Technology Corp.
1993? Poker 52 Blitz Systems Inc.
1993 Strip Teaser <unknown>
@@ -94,6 +95,7 @@ public:
void init_megadblj();
void init_hermit();
void init_dualgame();
+ void init_megastrp();
void hermit(machine_config &config);
void bankrob(machine_config &config);
@@ -274,13 +276,13 @@ VIDEO_START_MEMBER(blitz68k_state,blitz68k_addr_factor1)
uint32_t blitz68k_state::screen_update_blitz68k(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint8_t *src = m_blit_buffer.get();
+ const uint8_t *src = m_blit_buffer.get();
for(int y = 0; y < 256; y++)
{
for(int x = 0; x < 512; x++)
{
- bitmap.pix32(y, x) = m_palette->pen(*src++);
+ bitmap.pix(y, x) = m_palette->pen(*src++);
}
}
@@ -292,17 +294,17 @@ uint32_t blitz68k_state::screen_update_blitz68k(screen_device &screen, bitmap_rg
uint32_t blitz68k_state::screen_update_blitz68k_noblit(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint16_t *src = m_frame_buffer;
+ const uint16_t *src = m_frame_buffer;
for(int y = 0; y < 256; y++)
{
for(int x = 0; x < 512; )
{
- uint16_t pen = *src++;
- bitmap.pix32(y, x++) = m_palette->pen((pen >> 8) & 0xf);
- bitmap.pix32(y, x++) = m_palette->pen((pen >> 12) & 0xf);
- bitmap.pix32(y, x++) = m_palette->pen((pen >> 0) & 0xf);
- bitmap.pix32(y, x++) = m_palette->pen((pen >> 4) & 0xf);
+ const uint16_t pen = *src++;
+ bitmap.pix(y, x++) = m_palette->pen((pen >> 8) & 0xf);
+ bitmap.pix(y, x++) = m_palette->pen((pen >> 12) & 0xf);
+ bitmap.pix(y, x++) = m_palette->pen((pen >> 0) & 0xf);
+ bitmap.pix(y, x++) = m_palette->pen((pen >> 4) & 0xf);
}
}
@@ -2211,6 +2213,32 @@ ROM_START( bankrobb ) // DK-B main PCB + 8L74 sub PCB
ROM_LOAD( "palce16v8h.u71", 0x000, 0x117, NO_DUMP )
ROM_END
+// Mega Strip on ROM labels
+// Maxi Strip Poker and both copyright 91 and 1992 in ROMs
+// Mega Double Strip on title screen, 1992 copyright on following screen
+// English and French strings in ROMs
+// Main PCB: DK-B Copyright 1991 Blitz System inc.
+// Sub PCB: BLZ AB1 Copyright 1992, Blitz System Inc.
+
+ROM_START( megastrp )
+ ROM_REGION( 0x40000, "maincpu", 0 ) // 68000 code, on main board
+ ROM_LOAD16_BYTE( "1992_mega_strip_1.10b_b.u32", 0x00000, 0x20000, CRC(aaac8916) SHA1(74320bdf8b0f4de8a571fc6494252f01eff32cf9) ) // 1xxxxxxxxxxxxxxxx = 0xFF
+ ROM_LOAD16_BYTE( "1992_mega_strip_1.10b_a.u31", 0x00001, 0x20000, CRC(7661bd45) SHA1(b25b20b893ca428e0364f6b6d0ad435354958c31) ) // 1xxxxxxxxxxxxxxxx = 0xFF
+
+ ROM_REGION( 0x2000, "mcu1", 0 ) // 68HC705C8P code, on main board
+ ROM_LOAD( "1992_mega_strip_control_1.0.u2", 0x0000, 0x2000, NO_DUMP )
+
+ ROM_REGION( 0x2000, "mcu2", 0 ) // 68HC705C8P code, on sub board
+ ROM_LOAD( "blz_10b-4.01.u2", 0x0000, 0x2000, NO_DUMP )
+
+ ROM_REGION16_BE( 0x100000, "blitter", 0 ) // on main board
+ ROM_LOAD( "1992_mega_strip_1.10b_c.u46", 0x00000, 0x80000, CRC(d3813101) SHA1(80c6311ddea1b161a03fcd69c1b8d4e8a2d99636) )
+ ROM_LOAD( "1992_mega_strip_1.10b_d.u51", 0x80000, 0x80000, CRC(ee45ca2f) SHA1(9d1faeac17f60f1ea72d3fd3355544ea2d89a2bb) )
+
+ ROM_REGION( 0x80000, "samples", 0 ) // on main board
+ ROM_LOAD( "1992_mega_strip_1.10_sound.u18", 0x00000, 0x80000, CRC(8c345dc2) SHA1(2ad9dea4543d2c16f42a38653d740ff0c0fa1798) )
+ROM_END
+
/*************************************************************************************************************
Triple Play
@@ -3018,11 +3046,22 @@ void blitz68k_state::init_megadble()
ROM[0x1d40/2] = 0x4e71;
}
+void blitz68k_state::init_megastrp()
+{
+ uint16_t *ROM = (uint16_t *)memregion("maincpu")->base();
+
+ // skip loops until the MCUs are dumped and the hardware better understood
+ ROM[0x1678/2] = 0x4e71;
+
+ ROM[0x10c80/2] = 0x4e71;
+}
+
GAME( 1992, maxidbl, 0, maxidbl, maxidbl, blitz68k_state, init_maxidbl, ROT0, "Blitz Systems Inc.", "Maxi Double Poker (Ver. 1.10)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND | MACHINE_WRONG_COLORS )
GAME( 1990, megadblj, 0, maxidbl, maxidbl, blitz68k_state, init_megadblj, ROT0, "Blitz Systems Inc.", "Mega Double Poker Jackpot (Ver. 1.26)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND ) // JUNE 28TH, 1993
GAME( 1990, megadble, 0, maxidbl, maxidbl, blitz68k_state, init_megadble, ROT0, "Blitz Systems Inc.", "Mega Double Poker (Ver. 1.63 Espagnol)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND | MACHINE_WRONG_COLORS ) // NOVEMBER 1994
+GAME( 1992, megastrp, 0, bankroba, bankrob, blitz68k_state, init_megastrp, ROT0, "Blitz Systems Inc.", "Mega Double Strip (Ver. 1.10b)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND ) // @ 1993 BLITZ SYSTEM INC
GAME( 1993, steaser, 0, steaser, steaser, blitz68k_state, empty_init, ROT0, "<unknown>", "Strip Teaser (Italy, Ver. 1.22)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND ) // In-game strings are in Italian but service mode is half English / half French?
GAME( 1993, bankrob, 0, bankrob, bankrob, blitz68k_state, init_bankrob, ROT0, "Entertainment Technology Corp.", "Bank Robbery (Ver. 3.32)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND ) // BLITZ SYSTEM INC APRIL 1995
GAME( 1993, bankroba, bankrob, bankroba, bankrob, blitz68k_state, init_bankroba, ROT0, "Entertainment Technology Corp.", "Bank Robbery (Ver. 2.00)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION | MACHINE_NO_SOUND ) // BLITZ SYSTEM INC MAY 10TH, 1993
diff --git a/src/mame/drivers/blw700i.cpp b/src/mame/drivers/blw700i.cpp
index c5c8a0fd9b7..3552b957a64 100644
--- a/src/mame/drivers/blw700i.cpp
+++ b/src/mame/drivers/blw700i.cpp
@@ -122,29 +122,24 @@ void lw700i_state::video_start()
uint32_t lw700i_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels;
static const uint32_t palette[2] = { 0xffffff, 0 };
- uint8_t *pVRAM = (uint8_t *)m_mainram.target();
+ uint8_t const *const pVRAM = (uint8_t *)m_mainram.target() + 0x3e200;
- pVRAM += 0x3e200;
-
- for (y = 0; y < 128; y++)
+ for (int y = 0; y < 128; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 480/8; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 480/8; x++)
{
- pixels = pVRAM[(y * (480/8)) + (BYTE_XOR_BE(x))];
-
- *scanline++ = palette[(pixels>>7)&1];
- *scanline++ = palette[(pixels>>6)&1];
- *scanline++ = palette[(pixels>>5)&1];
- *scanline++ = palette[(pixels>>4)&1];
- *scanline++ = palette[(pixels>>3)&1];
- *scanline++ = palette[(pixels>>2)&1];
- *scanline++ = palette[(pixels>>1)&1];
- *scanline++ = palette[(pixels&1)];
+ uint8_t const pixels = pVRAM[(y * (480/8)) + (BYTE_XOR_BE(x))];
+
+ *scanline++ = palette[BIT(pixels, 7)];
+ *scanline++ = palette[BIT(pixels, 6)];
+ *scanline++ = palette[BIT(pixels, 5)];
+ *scanline++ = palette[BIT(pixels, 4)];
+ *scanline++ = palette[BIT(pixels, 3)];
+ *scanline++ = palette[BIT(pixels, 2)];
+ *scanline++ = palette[BIT(pixels, 1)];
+ *scanline++ = palette[BIT(pixels, 0)];
}
}
diff --git a/src/mame/drivers/bmcbowl.cpp b/src/mame/drivers/bmcbowl.cpp
index 847acd2b025..79970bf864b 100644
--- a/src/mame/drivers/bmcbowl.cpp
+++ b/src/mame/drivers/bmcbowl.cpp
@@ -167,41 +167,42 @@ uint32_t bmcbowl_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma
missing scroll and priorities (maybe fixed ones)
*/
- int x,y,z,pixdat;
bitmap.fill(rgb_t::black(), cliprect);
- z=0;
- for (y=0;y<230;y++)
+ int z=0;
+ for (int y=0; y<230; y++)
{
- for (x=0;x<280;x+=2)
+ for (int x=0; x<280; x+=2)
{
+ int pixdat;
+
pixdat = m_vid2[0x8000+z];
if(pixdat&0xff)
- bitmap.pix32(y, x+1) = m_palette->pen(pixdat&0xff);
+ bitmap.pix(y, x+1) = m_palette->pen(pixdat&0xff);
if(pixdat>>8)
- bitmap.pix32(y, x) = m_palette->pen(pixdat>>8);
+ bitmap.pix(y, x) = m_palette->pen(pixdat>>8);
pixdat = m_vid2[z];
if(pixdat&0xff)
- bitmap.pix32(y, x+1) = m_palette->pen(pixdat&0xff);
+ bitmap.pix(y, x+1) = m_palette->pen(pixdat&0xff);
if(pixdat>>8)
- bitmap.pix32(y, x) = m_palette->pen(pixdat>>8);
+ bitmap.pix(y, x) = m_palette->pen(pixdat>>8);
pixdat = m_vid1[0x8000+z];
if(pixdat&0xff)
- bitmap.pix32(y, x+1) = m_palette->pen(pixdat&0xff);
+ bitmap.pix(y, x+1) = m_palette->pen(pixdat&0xff);
if(pixdat>>8)
- bitmap.pix32(y, x) = m_palette->pen(pixdat>>8);
+ bitmap.pix(y, x) = m_palette->pen(pixdat>>8);
pixdat = m_vid1[z];
if(pixdat&0xff)
- bitmap.pix32(y, x+1) = m_palette->pen(pixdat&0xff);
+ bitmap.pix(y, x+1) = m_palette->pen(pixdat&0xff);
if(pixdat>>8)
- bitmap.pix32(y, x) = m_palette->pen(pixdat>>8);
+ bitmap.pix(y, x) = m_palette->pen(pixdat>>8);
z++;
}
diff --git a/src/mame/drivers/bmcpokr.cpp b/src/mame/drivers/bmcpokr.cpp
index 05700c64b71..094dde0f078 100644
--- a/src/mame/drivers/bmcpokr.cpp
+++ b/src/mame/drivers/bmcpokr.cpp
@@ -147,21 +147,21 @@ void bmcpokr_state::pixram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
COMBINE_DATA(&m_pixram[offset]);
- int x = (offset & 0xff) << 2;
- int y = (offset >> 8);
+ int const x = (offset & 0xff) << 2;
+ int const y = (offset >> 8);
- uint16_t pixpal = (m_pixpal & 0xf) << 4;
+ uint16_t const pixpal = (m_pixpal & 0xf) << 4;
uint16_t pen;
if (ACCESSING_BITS_8_15)
{
- pen = (data >> 12) & 0xf; m_pixbitmap->pix16(y, x + 0) = pen ? pixpal + pen : 0;
- pen = (data >> 8) & 0xf; m_pixbitmap->pix16(y, x + 1) = pen ? pixpal + pen : 0;
+ pen = (data >> 12) & 0xf; m_pixbitmap->pix(y, x + 0) = pen ? pixpal + pen : 0;
+ pen = (data >> 8) & 0xf; m_pixbitmap->pix(y, x + 1) = pen ? pixpal + pen : 0;
}
if (ACCESSING_BITS_0_7)
{
- pen = (data >> 4) & 0xf; m_pixbitmap->pix16(y, x + 2) = pen ? pixpal + pen : 0;
- pen = (data >> 0) & 0xf; m_pixbitmap->pix16(y, x + 3) = pen ? pixpal + pen : 0;
+ pen = (data >> 4) & 0xf; m_pixbitmap->pix(y, x + 2) = pen ? pixpal + pen : 0;
+ pen = (data >> 0) & 0xf; m_pixbitmap->pix(y, x + 3) = pen ? pixpal + pen : 0;
}
}
@@ -173,12 +173,12 @@ void bmcpokr_state::pixbitmap_redraw()
{
for (int x = 0; x < 1024; x += 4)
{
- uint16_t data = m_pixram[offset++];
+ uint16_t const data = m_pixram[offset++];
uint16_t pen;
- pen = (data >> 12) & 0xf; m_pixbitmap->pix16(y, x + 0) = pen ? pixpal + pen : 0;
- pen = (data >> 8) & 0xf; m_pixbitmap->pix16(y, x + 1) = pen ? pixpal + pen : 0;
- pen = (data >> 4) & 0xf; m_pixbitmap->pix16(y, x + 2) = pen ? pixpal + pen : 0;
- pen = (data >> 0) & 0xf; m_pixbitmap->pix16(y, x + 3) = pen ? pixpal + pen : 0;
+ pen = (data >> 12) & 0xf; m_pixbitmap->pix(y, x + 0) = pen ? pixpal + pen : 0;
+ pen = (data >> 8) & 0xf; m_pixbitmap->pix(y, x + 1) = pen ? pixpal + pen : 0;
+ pen = (data >> 4) & 0xf; m_pixbitmap->pix(y, x + 2) = pen ? pixpal + pen : 0;
+ pen = (data >> 0) & 0xf; m_pixbitmap->pix(y, x + 3) = pen ? pixpal + pen : 0;
}
}
}
diff --git a/src/mame/drivers/bmjr.cpp b/src/mame/drivers/bmjr.cpp
index 081e5feff2b..93f0fedcf4c 100644
--- a/src/mame/drivers/bmjr.cpp
+++ b/src/mame/drivers/bmjr.cpp
@@ -71,20 +71,20 @@ private:
u32 bmjr_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx,fg=4;
- u16 sy=0,ma=0x100,x;
- u8 inv = (m_xor_display) ? 0xff : 0;
+ u8 fg=4;
+ u16 sy=0,ma=0x100;
+ u8 const inv = (m_xor_display) ? 0xff : 0;
- for(y = 0; y < 24; y++ )
+ for(u8 y = 0; y < 24; y++ )
{
- for (ra = 0; ra < 8; ra++)
+ for (u8 ra = 0; ra < 8; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 32; x++)
+ for (u16 x = ma; x < ma + 32; x++)
{
- chr = m_p_wram[x];
- gfx = m_p_chargen[(chr<<3) | ra] ^ inv;
+ u8 const chr = m_p_wram[x];
+ u8 const gfx = m_p_chargen[(chr<<3) | ra] ^ inv;
/* Display a scanline of a character */
*p++ = BIT(gfx, 7) ? fg : 0;
diff --git a/src/mame/drivers/bml3.cpp b/src/mame/drivers/bml3.cpp
index 12e600ee196..5636185c513 100644
--- a/src/mame/drivers/bml3.cpp
+++ b/src/mame/drivers/bml3.cpp
@@ -97,6 +97,7 @@ public:
void bml3mk5(machine_config &config);
void bml3(machine_config &config);
void bml3_common(machine_config &config);
+ DECLARE_INPUT_CHANGED_MEMBER(nmi_button);
private:
void bml3_mem(address_map &map);
@@ -159,6 +160,7 @@ private:
std::unique_ptr<u8[]> m_aram;
u8 m_firq_mask;
u8 m_firq_status;
+ u8 m_nmi;
required_device<cpu_device> m_maincpu;
required_region_ptr<u8> m_p_chargen;
required_device<bml3bus_device> m_bml3bus;
@@ -336,7 +338,7 @@ void bml3_state::relay_w(u8 data)
u8 bml3_state::keyb_nmi_r()
{
- return 0; // bit 7 used to signal a BREAK key pressure
+ return m_nmi; // bit 7 used to signal a BREAK key pressure
}
void bml3_state::firq_mask_w(u8 data)
@@ -472,100 +474,108 @@ static INPUT_PORTS_START( bml3 )
PORT_START("key1") //0x00-0x1f
PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
- PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP)
- PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("? PAD") PORT_CHAR('?')
- PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT)
- PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN)
- PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("? PAD")
+ PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_LCONTROL)
- PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Shift")PORT_CODE(KEYCODE_LSHIFT)
+ PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("X2") // ???
PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK)
PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Kana Lock") PORT_CODE(KEYCODE_NUMLOCK)
PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Kana Shift") PORT_CODE(KEYCODE_LALT)
- PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC)
- PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8 PAD") PORT_CODE(KEYCODE_8_PAD) PORT_CHAR('8')
- PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9 PAD") PORT_CODE(KEYCODE_9_PAD) PORT_CHAR('9')
- PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("*") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR('*')
- PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7')
- PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
- PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
- PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
+ PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
+ PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8 PAD") PORT_CODE(KEYCODE_8_PAD)
+ PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9 PAD") PORT_CODE(KEYCODE_9_PAD)
+ PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("*") PORT_CODE(KEYCODE_ASTERISK)
+ PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR(39)
+ PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
- PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("^") PORT_CODE(KEYCODE_BACKSLASH)
- PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
- PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
- PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_BACKSPACE)
- PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
- PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
- PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
- PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
- PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7 PAD") PORT_CODE(KEYCODE_7_PAD) PORT_CHAR('7')
+ PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("^") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('^')
+ PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
+ PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+ PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7 PAD") PORT_CODE(KEYCODE_7_PAD)
PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Delete PAD") //backspace
PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xC2\xA5") PORT_CODE(KEYCODE_TAB) // yen sign
PORT_START("key2") //0x20-0x3f
- PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U)
- PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R)
- PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y)
- PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I)
- PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P)
- PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE)
- PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("@") PORT_CODE(KEYCODE_EQUALS)
- PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0 PAD") PORT_CODE(KEYCODE_0_PAD) PORT_CHAR('0')
- PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q)
- PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T)
- PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W)
- PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E)
- PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O)
- PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(". PAD") PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR('.')
+ PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHAR('u')
+ PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CHAR('r')
+ PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHAR('y')
+ PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHAR('i')
+ PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p')
+ PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[')
+ PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("@") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('@')
+ PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0 PAD") PORT_CODE(KEYCODE_0_PAD)
+ PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CHAR('q')
+ PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CHAR('t')
+ PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CHAR('w')
+ PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CHAR('e')
+ PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('o')
+ PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(". PAD") PORT_CODE(KEYCODE_DEL_PAD)
PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME) //or cls?
- PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER)
- PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J)
- PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F)
- PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H)
- PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K)
- PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON)
- PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("]") PORT_CODE(KEYCODE_CLOSEBRACE)
- PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(":") PORT_CODE(KEYCODE_QUOTE)
- PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4 PAD") PORT_CODE(KEYCODE_4_PAD) PORT_CHAR('4')
- PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A)
- PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G)
- PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S)
- PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D)
- PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L)
- PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5 PAD") PORT_CODE(KEYCODE_5_PAD) PORT_CHAR('5')
- PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6 PAD") PORT_CODE(KEYCODE_6_PAD) PORT_CHAR('6')
- PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("- PAD") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR('-')
+ PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j')
+ PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CHAR('f')
+ PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CHAR('h')
+ PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHAR('k')
+ PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+ PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']')
+ PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(":") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4 PAD") PORT_CODE(KEYCODE_4_PAD)
+ PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a')
+ PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CHAR('g')
+ PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHAR('s')
+ PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d')
+ PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('l')
+ PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5 PAD") PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6 PAD") PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("- PAD") PORT_CODE(KEYCODE_MINUS_PAD)
PORT_START("key3") //0x40-0x5f
- PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M)
- PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V)
- PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N)
- PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA)
- PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH)
- PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/ PAD") PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR('/')
- PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("_") PORT_CODE(KEYCODE_TILDE)
- PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1 PAD") PORT_CODE(KEYCODE_1_PAD) PORT_CHAR('1')
- PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)
- PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B)
- PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X)
- PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C)
- PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP)
- PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2 PAD") PORT_CODE(KEYCODE_2_PAD) PORT_CHAR('2')
- PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3 PAD") PORT_CODE(KEYCODE_3_PAD) PORT_CHAR('3')
+ PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CHAR('m')
+ PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CHAR('v')
+ PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CHAR('n')
+ PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/ PAD") PORT_CODE(KEYCODE_SLASH_PAD)
+ PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("_") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('_')
+ PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1 PAD") PORT_CODE(KEYCODE_1_PAD)
+ PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z')
+ PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CHAR('b')
+ PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x')
+ PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c')
+ PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2 PAD") PORT_CODE(KEYCODE_2_PAD)
+ PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3 PAD") PORT_CODE(KEYCODE_3_PAD)
PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("+") PORT_CODE(KEYCODE_PLUS_PAD)
- PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1)
- PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2)
- PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3)
- PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4)
- PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5)
+ PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F10))
PORT_BIT(0xffe00000,IP_ACTIVE_HIGH,IPT_UNKNOWN)
+
+ PORT_START("key4")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Break") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) PORT_CHANGED_MEMBER(DEVICE_SELF, bml3_state, nmi_button, 0)
INPUT_PORTS_END
+INPUT_CHANGED_MEMBER(bml3_state::nmi_button)
+{
+ m_nmi = newval ? 0x80 : 0;
+}
+
MC6845_UPDATE_ROW( bml3_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
// The MB-6890 has a 5-bit colour RAM region. The meaning of the bits are:
// 0: blue
// 1: red
@@ -573,13 +583,9 @@ MC6845_UPDATE_ROW( bml3_state::crtc_update_row )
// 3: reverse/inverse video
// 4: graphic (not character)
- u8 x=0,hf=0,xi=0,interlace=0,bgcolor=0,rawbits=0,dots[2]={0,0},color=0,pen=0;
- bool reverse=0,graphic=0,lowres=0;
- u16 mem=0;
-
- interlace = (m_crtc_vreg[8] & 3) ? 1 : 0;
- lowres = BIT(m_hres_reg, 6);
- bgcolor = m_hres_reg & 7;
+ u8 const interlace = (m_crtc_vreg[8] & 3) ? 1 : 0;
+ bool const lowres = BIT(m_hres_reg, 6);
+ u8 const bgcolor = m_hres_reg & 7;
if (interlace)
{
@@ -587,19 +593,21 @@ MC6845_UPDATE_ROW( bml3_state::crtc_update_row )
if (y > 0x191) return;
}
- for(x=0; x<x_count; x++)
+ for(u8 x=0; x<x_count; x++)
{
+ u16 mem;
if (lowres)
mem = (ma + x - 0x400) & 0x3fff;
else
mem = (ma + x + ra * x_count/40 * 0x400 -0x400) & 0x3fff;
- color = m_aram[mem] & 7;
- reverse = BIT(m_aram[mem], 3) ^ (x == cursor_x);
- graphic = BIT(m_aram[mem], 4);
+ u8 const color = m_aram[mem] & 7;
+ bool const reverse = BIT(m_aram[mem], 3) ^ (x == cursor_x);
+ bool const graphic = BIT(m_aram[mem], 4);
- rawbits = m_vram[mem];
+ u8 const rawbits = m_vram[mem];
+ u8 dots[2] = { 0, 0 };
if (graphic)
{
if (lowres)
@@ -619,8 +627,8 @@ MC6845_UPDATE_ROW( bml3_state::crtc_update_row )
else
{
// character mode
- int tile = rawbits & 0x7f;
- int tile_bank = BIT(rawbits, 7);
+ int const tile = rawbits & 0x7f;
+ int const tile_bank = BIT(rawbits, 7);
if (interlace)
{
dots[0] = m_p_chargen[(tile_bank<<11)|(tile<<4)|(ra<<1)];
@@ -632,18 +640,19 @@ MC6845_UPDATE_ROW( bml3_state::crtc_update_row )
}
}
- for(hf=0;hf<=interlace;hf++)
+ for(u8 hf=0;hf<=interlace;hf++)
{
- for(xi=0;xi<8;xi++)
+ for(u8 xi=0;xi<8;xi++)
{
+ u8 pen;
if(reverse)
pen = (dots[hf] >> (7-xi) & 1) ? bgcolor : color;
else
pen = (dots[hf] >> (7-xi) & 1) ? color : bgcolor;
- bitmap.pix32(y, x*8+xi) = palette[pen];
+ bitmap.pix(y, x*8+xi) = palette[pen];
// when the mc6845 device gains full interlace&video support, replace the line above with the line below
- // bitmap.pix32(y*(interlace+1)+hf, x*8+xi) = palette[pen];
+ // bitmap.pix(y*(interlace+1)+hf, x*8+xi) = palette[pen];
}
}
}
@@ -759,6 +768,7 @@ void bml3_state::machine_start()
save_item(NAME(m_crtc_index));
save_item(NAME(m_firq_mask));
save_item(NAME(m_firq_status));
+ save_item(NAME(m_nmi));
u8 *r = m_extram.get();
u8 *m = memregion("maincpu")->base();
@@ -799,6 +809,7 @@ void bml3_state::machine_reset()
m_firq_status = 0;
m_cassbit = 0;
m_cassold = 0;
+ m_nmi = 0;
}
void bml3_state::piaA_w(uint8_t data)
diff --git a/src/mame/drivers/bw12.cpp b/src/mame/drivers/bw12.cpp
index 93337ce0e5b..d9928ac612c 100644
--- a/src/mame/drivers/bw12.cpp
+++ b/src/mame/drivers/bw12.cpp
@@ -302,13 +302,12 @@ INPUT_PORTS_END
MC6845_UPDATE_ROW( bw12_state::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
- int column, bit;
+ pen_t const *const pen = m_palette->pens();
- for (column = 0; column < x_count; column++)
+ for (int column = 0; column < x_count; column++)
{
- uint8_t code = m_video_ram[((ma + column) & BW12_VIDEORAM_MASK)];
- uint16_t addr = code << 4 | (ra & 0x0f);
+ uint8_t const code = m_video_ram[((ma + column) & BW12_VIDEORAM_MASK)];
+ uint16_t const addr = code << 4 | (ra & 0x0f);
uint8_t data = m_char_rom->base()[addr & BW12_CHARROM_MASK];
if (column == cursor_x)
@@ -316,12 +315,12 @@ MC6845_UPDATE_ROW( bw12_state::crtc_update_row )
data = 0xff;
}
- for (bit = 0; bit < 8; bit++)
+ for (int bit = 0; bit < 8; bit++)
{
- int x = (column * 8) + bit;
- int color = BIT(data, 7) && de;
+ int const x = (column * 8) + bit;
+ int const color = BIT(data, 7) && de;
- bitmap.pix32(vbp + y, hbp + x) = pen[color];
+ bitmap.pix(vbp + y, hbp + x) = pen[color];
data <<= 1;
}
diff --git a/src/mame/drivers/bw2.cpp b/src/mame/drivers/bw2.cpp
index 9a1d03e82bd..7f1ff1234fd 100644
--- a/src/mame/drivers/bw2.cpp
+++ b/src/mame/drivers/bw2.cpp
@@ -450,7 +450,7 @@ uint8_t bw2_state::ppi_pc_r()
*/
- uint8_t data = 0;
+ uint8_t data = m_bank;
// centronics busy
data |= m_centronics_busy << 4;
@@ -459,7 +459,7 @@ uint8_t bw2_state::ppi_pc_r()
data |= m_mfdbk << 5;
// write protect
- if (m_floppy) data |= m_floppy->wpt_r() << 7;
+ if (m_floppy) data |= !m_floppy->wpt_r() << 7;
return data;
}
diff --git a/src/mame/drivers/by17.cpp b/src/mame/drivers/by17.cpp
index b8832806c8d..33074d0e79b 100644
--- a/src/mame/drivers/by17.cpp
+++ b/src/mame/drivers/by17.cpp
@@ -26,7 +26,6 @@ ToDo:
#include "by17.lh"
#include "by17_pwerplay.lh"
#include "by17_matahari.lh"
-#include "render.h"
class by17_state : public genpin_class
{
@@ -980,10 +979,6 @@ void by17_state::machine_reset()
{
genpin_class::machine_reset();
- render_target *target = machine().render().first_target();
-
- target->set_view(0);
-
m_u10a = 0;
m_u10b = 0;
m_u11a = 0;
diff --git a/src/mame/drivers/by35.cpp b/src/mame/drivers/by35.cpp
index e4f3aab38a6..70d15834ce1 100644
--- a/src/mame/drivers/by35.cpp
+++ b/src/mame/drivers/by35.cpp
@@ -73,7 +73,6 @@ ToDo:
#include "machine/6821pia.h"
#include "machine/timer.h"
#include "audio/bally.h"
-#include "render.h"
#include "speaker.h"
//#define VERBOSE 1
@@ -1441,10 +1440,6 @@ void by35_state::machine_reset()
{
genpin_class::machine_reset();
- render_target *target = machine().render().first_target();
-
- target->set_view(0);
-
m_u10a = 0;
m_u10b = 0;
m_u11a = 0;
diff --git a/src/mame/drivers/c10.cpp b/src/mame/drivers/c10.cpp
index 628082f4987..fd7e5f5945b 100644
--- a/src/mame/drivers/c10.cpp
+++ b/src/mame/drivers/c10.cpp
@@ -98,24 +98,23 @@ void c10_state::machine_reset()
uint32_t c10_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
//static uint8_t framecnt=0;
- uint8_t y,ra,chr,gfx;
- uint16_t sy=0,ma=0,x,xx;
+ uint16_t sy=0,ma=0;
//framecnt++;
- for (y = 0; y < 25; y++)
+ for (uint8_t y = 0; y < 25; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (uint8_t ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- xx = ma;
- for (x = ma; x < ma + 80; x++)
+ uint16_t xx = ma;
+ for (uint16_t x = ma; x < ma + 80; x++)
{
- gfx = 0;
+ uint8_t gfx = 0;
if (ra < 9)
{
- chr = m_vram[xx++];
+ uint8_t chr = m_vram[xx++];
// /* Take care of flashing characters */
// if ((chr < 0x80) && (framecnt & 0x08))
diff --git a/src/mame/drivers/c128.cpp b/src/mame/drivers/c128.cpp
index 0774ac43835..47843515c0c 100644
--- a/src/mame/drivers/c128.cpp
+++ b/src/mame/drivers/c128.cpp
@@ -783,7 +783,7 @@ static INPUT_PORTS_START( c128 )
PORT_START( "ROW6" )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91 Pi") PORT_CODE(KEYCODE_DEL) PORT_CHAR(0x2191) PORT_CHAR(0x03C0)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("\xE2\x86\x91 Pi") PORT_CODE(KEYCODE_DEL) PORT_CHAR(0x2191,'^') PORT_CHAR(0x03C0)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('=')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CLR HOME") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(HOME))
diff --git a/src/mame/drivers/c65.cpp b/src/mame/drivers/c65.cpp
index c918bf97d04..b4bd8c4ec75 100644
--- a/src/mame/drivers/c65.cpp
+++ b/src/mame/drivers/c65.cpp
@@ -178,7 +178,7 @@ uint32_t c65_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap,
if (attr & 0x10) enable_dot = 0;
//if(cliprect.contains(x, y))
- bitmap.pix16(y, x) = m_palette->pen(highlight_color + ((enable_dot) ? foreground_color : background_color));
+ bitmap.pix(y, x) = m_palette->pen(highlight_color + ((enable_dot) ? foreground_color : background_color));
//gfx->opaque(bitmap,cliprect,tile,0,0,0,x*8,y*8);
diff --git a/src/mame/drivers/calcune.cpp b/src/mame/drivers/calcune.cpp
index 64dc5f6453d..f58fbd9f63e 100644
--- a/src/mame/drivers/calcune.cpp
+++ b/src/mame/drivers/calcune.cpp
@@ -149,7 +149,7 @@ uint32_t calcune_state::screen_update_calcune(screen_device &screen, bitmap_rgb3
{
const unsigned palette_per_scanline = 64 * y;
- uint32_t *dst = &bitmap.pix32(y);
+ uint32_t *const dst = &bitmap.pix(y);
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
int pix;
diff --git a/src/mame/drivers/camplynx.cpp b/src/mame/drivers/camplynx.cpp
index fe43ec05f5c..81d46cc91ff 100644
--- a/src/mame/drivers/camplynx.cpp
+++ b/src/mame/drivers/camplynx.cpp
@@ -748,9 +748,8 @@ void camplynx_state::machine_reset()
MC6845_UPDATE_ROW( camplynx_state::lynx48k_update_row )
{
- u8 r,g,b,x;
- uint32_t green_bank, *p = &bitmap.pix32(y);
- uint16_t mem = ((ma << 2) + (ra << 5)) & 0x1fff;
+ uint32_t green_bank, *p = &bitmap.pix(y);
+ uint16_t const mem = ((ma << 2) + (ra << 5)) & 0x1fff;
// determine green bank
if (BIT(m_port80, 4))
@@ -758,11 +757,11 @@ MC6845_UPDATE_ROW( camplynx_state::lynx48k_update_row )
else
green_bank = 0x3c000 + mem; // normal green
- for (x = 0; x < x_count; x++)
+ for (u8 x = 0; x < x_count; x++)
{
- r = m_p_ram[0x2c000 + mem + x];
- b = m_p_ram[0x28000 + mem + x];
- g = m_p_ram[green_bank + x];
+ u8 const r = m_p_ram[0x2c000 + mem + x];
+ u8 const b = m_p_ram[0x28000 + mem + x];
+ u8 const g = m_p_ram[green_bank + x];
*p++ = m_palette->pen_color((BIT(b, 7) << 2) | (BIT(g, 7) << 1) | (BIT(r, 7)));
*p++ = m_palette->pen_color((BIT(b, 6) << 2) | (BIT(g, 6) << 1) | (BIT(r, 6)));
@@ -777,20 +776,20 @@ MC6845_UPDATE_ROW( camplynx_state::lynx48k_update_row )
MC6845_UPDATE_ROW( camplynx_state::lynx128k_update_row )
{
- u8 r,g,b,x;
- uint32_t green_bank, *p = &bitmap.pix32(y);
- uint16_t mem = ((ma << 2) + (ra << 6)) & 0x3fff;
+ uint32_t green_bank, *p = &bitmap.pix(y);
+ uint16_t const mem = ((ma << 2) + (ra << 6)) & 0x3fff;
+
// determine green bank
if (BIT(m_port80, 4))
- green_bank = 0x2c000+mem; // alt green
+ green_bank = 0x2c000 + mem; // alt green
else
- green_bank = 0x28000+mem; // normal green
+ green_bank = 0x28000 + mem; // normal green
- for (x = 0; x < x_count; x++)
+ for (u8 x = 0; x < x_count; x++)
{
- r = m_p_ram[0x20000+mem+x];
- b = m_p_ram[0x24000+mem+x];
- g = m_p_ram[green_bank+x];
+ u8 const r = m_p_ram[0x20000 + mem + x];
+ u8 const b = m_p_ram[0x24000 + mem + x];
+ u8 const g = m_p_ram[green_bank + x];
*p++ = m_palette->pen_color((BIT(b, 7) << 2) | (BIT(g, 7) << 1) | (BIT(r, 7)));
*p++ = m_palette->pen_color((BIT(b, 6) << 2) | (BIT(g, 6) << 1) | (BIT(r, 6)));
diff --git a/src/mame/drivers/candela.cpp b/src/mame/drivers/candela.cpp
index ca381740f0a..ec9997a80a8 100644
--- a/src/mame/drivers/candela.cpp
+++ b/src/mame/drivers/candela.cpp
@@ -570,7 +570,7 @@ uint32_t can09_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
for (x = 0; x < 8; x++)
{
// if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN(" %02x: ", *chardata);
- bitmap.pix16(row + y, col + x) = x & 1; //(*chardata & (1 << x)) ? 1 : 0;
+ bitmap.pix(row + y, col + x) = x & 1; //(*chardata & (1 << x)) ? 1 : 0;
}
// chardata++;
}
diff --git a/src/mame/drivers/canon_s80.cpp b/src/mame/drivers/canon_s80.cpp
index 7e2aa68a4dc..7799077fb53 100644
--- a/src/mame/drivers/canon_s80.cpp
+++ b/src/mame/drivers/canon_s80.cpp
@@ -41,7 +41,7 @@ private:
HD44780_PIXEL_UPDATE(canons80_state::pixel_update)
{
if (pos < 16)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
void canons80_state::canons80_map(address_map &map)
diff --git a/src/mame/drivers/cardline.cpp b/src/mame/drivers/cardline.cpp
index 0db1f9319dd..6dac232e77b 100644
--- a/src/mame/drivers/cardline.cpp
+++ b/src/mame/drivers/cardline.cpp
@@ -136,9 +136,9 @@ MC6845_UPDATE_ROW( cardline_state::crtc_update_row )
int fg_col = gfx[fg_tile * 64 + ra * 8 + i];
if (fg_col == 1)
- bitmap.pix32(y, x) = palette[bg_pal_ofs + bg_col];
+ bitmap.pix(y, x) = palette[bg_pal_ofs + bg_col];
else
- bitmap.pix32(y, x) = palette[fg_pal_ofs + fg_col];
+ bitmap.pix(y, x) = palette[fg_pal_ofs + fg_col];
x++;
}
diff --git a/src/mame/drivers/casloopy.cpp b/src/mame/drivers/casloopy.cpp
index 4ade93aa0eb..7beec8a8564 100644
--- a/src/mame/drivers/casloopy.cpp
+++ b/src/mame/drivers/casloopy.cpp
@@ -255,7 +255,6 @@ void casloopy_state::video_start()
uint32_t casloopy_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
gfx_element *gfx = m_gfxdecode->gfx(m_gfx_index);
- int x,y;
int count;
static int test;
@@ -279,9 +278,9 @@ uint32_t casloopy_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
#endif
count = test;
- for (y=0;y<32;y++)
+ for (int y=0;y<32;y++)
{
- for (x=0;x<32;x++)
+ for (int x=0;x<32;x++)
{
uint16_t tile = (m_vram[count+1])|(m_vram[count]<<8);
@@ -295,15 +294,13 @@ uint32_t casloopy_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
count = test;
- for (y=cliprect.top(); y<cliprect.bottom(); y++) // FIXME: off-by-one?
+ for (int y=cliprect.top(); y<cliprect.bottom(); y++) // FIXME: off-by-one?
{
- for(x=0;x<256;x++)
+ for(int x=0;x<256;x++)
{
- uint8_t pix;
-
- pix = m_bitmap_vram[count];
+ uint8_t pix = m_bitmap_vram[count];
if(pix)
- bitmap.pix16(y, x) = pix + 0x100;
+ bitmap.pix(y, x) = pix + 0x100;
count++;
}
diff --git a/src/mame/drivers/cat.cpp b/src/mame/drivers/cat.cpp
index 353e2caa6ea..628fa66569f 100644
--- a/src/mame/drivers/cat.cpp
+++ b/src/mame/drivers/cat.cpp
@@ -960,10 +960,10 @@ uint32_t cat_state::screen_update_cat(screen_device &screen, bitmap_rgb32 &bitma
int horpos = 0;
for (int x = 0; x < 42; x++)
{
- uint16_t code = m_p_cat_videoram[addr++];
+ const uint16_t code = m_p_cat_videoram[addr++];
for (int b = 15; b >= 0; b--)
{
- bitmap.pix32(y, horpos++) = BIT(code, b) ? on_color : off_color;
+ bitmap.pix(y, horpos++) = BIT(code, b) ? on_color : off_color;
}
}
}
diff --git a/src/mame/drivers/cave.cpp b/src/mame/drivers/cave.cpp
index fd30f06e933..07c3cd03156 100644
--- a/src/mame/drivers/cave.cpp
+++ b/src/mame/drivers/cave.cpp
@@ -222,7 +222,7 @@ void cave_state::videoregs_w(offs_t offset, u16 data, u16 mem_mask)
COMBINE_DATA(&m_videoregs[Chip][offset]);
offset <<= 1;
// offset 0x04 and 0x06 is offset related?
- // offset 0x0a is position mode toggle in bit 13-12 (seperated for X and Y?), other bits used but unknown
+ // offset 0x0a is position mode toggle in bit 13-12 (separated for X and Y?), other bits used but unknown
// offset 0x68 or 0x78 is commonly watchdog or DMA command?
// offset 0x6c or 0x7c is encryption key or CRTC or something else?
// offset 0x6e is commonly communication when sound CPU exists
@@ -236,7 +236,7 @@ void cave_state::videoregs_w(offs_t offset, u16 data, u16 mem_mask)
offset != 0x68 &&
offset != 0x6e &&
offset != 0x78)
- logerror("%s: Unknown videoregs #%02X writtten %04X = %04X & %04X\n",
+ logerror("%s: Unknown videoregs #%02X written %04X = %04X & %04X\n",
machine().describe_context(), Chip, offset, data, mem_mask);
}
@@ -1186,6 +1186,31 @@ void cave_state::paceight_map(address_map &map)
map(0xe00001, 0xe00001).w(FUNC(cave_state::tjumpman_eeprom_w)); // EEPROM
}
+
+/***************************************************************************
+ Pac-Carnival
+***************************************************************************/
+
+//TODO: leds need verifying
+
+void cave_state::paccarn_map(address_map &map)
+{
+ map(0x000000, 0x07ffff).rom(); // ROM
+ map(0x100000, 0x10ffff).ram().share("nvram"); // RAM (battery)
+ map(0x200000, 0x20ffff).ram().share("spriteram.0"); // Sprites
+ map(0x300000, 0x307fff).m(m_tilemap[0], FUNC(tilemap038_device::vram_map)); // Layer 0
+ map(0x400000, 0x40007f).w(FUNC(cave_state::videoregs_w<0>)).share("videoregs.0"); // Video Regs
+ map(0x400000, 0x400007).r(FUNC(cave_state::irq_cause_r)); // IRQ Cause
+ map(0x400068, 0x400069).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); // Watchdog
+ map(0x500000, 0x500001).portr("IN0"); // Inputs + EEPROM + Hopper
+ map(0x500002, 0x500003).portr("IN1"); // Inputs
+ map(0x600000, 0x600005).w(m_tilemap[0], FUNC(tilemap038_device::vregs_w)); // Layer 0 Control
+ map(0x700000, 0x70ffff).ram().w(m_palette[0], FUNC(palette_device::write16)).share("palette.0"); // Palette
+ map(0x800001, 0x800001).rw("oki1", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); // M6295
+ map(0xc00000, 0xc00001).w(FUNC(cave_state::pacslot_leds_w)); // Leds + Hopper
+ map(0xe00001, 0xe00001).w(FUNC(cave_state::tjumpman_eeprom_w)); // EEPROM
+}
+
/***************************************************************************
Uo Poko
***************************************************************************/
@@ -1692,6 +1717,28 @@ static INPUT_PORTS_START( paceight )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME( "Max Bet" )
INPUT_PORTS_END
+static INPUT_PORTS_START( paccarn ) // holding together Bet 4 and Bet 8 activates Bet 12 in IO Test Mode
+ PORT_START("IN0")
+ PORT_SERVICE( 0x01, IP_ACTIVE_LOW )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(10) // credits (impulse needed to coin up reliably)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("eeprom", eeprom_serial_93cxx_device, do_read)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME( "Bet 4" )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME( "Bet 2" )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(cave_state, tjumpman_hopper_r)
+
+ PORT_START("IN1")
+ PORT_BIT( 0x07, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_CONFNAME( 0x08, 0x08, "Self Test" )
+ PORT_CONFSETTING( 0x08, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x00, DEF_STR( On ) )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME( "Bet 8" )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME( "Bet 3" )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(10) // medal (impulse needed to coin up reliably)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT )
+INPUT_PORTS_END
+
static INPUT_PORTS_START( ppsatan )
PORT_START("SYSTEM") // $200000
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_COIN1 )
@@ -2406,6 +2453,12 @@ void cave_state::paceight(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &cave_state::paceight_map);
}
+void cave_state::paccarn(machine_config &config)
+{
+ pacslot(config);
+ m_maincpu->set_addrmap(AS_PROGRAM, &cave_state::paccarn_map);
+}
+
/***************************************************************************
Poka Poka Satan
***************************************************************************/
@@ -4099,6 +4152,51 @@ ROM_END
/***************************************************************************
+ Pac-Carnival by Namco, 1996
+ Namco N-44 EM VIDEO platform, PCB B0445
+
+ TMP 68HC000P-16
+
+ 013 9341E7005
+ 038 9429WX704
+
+ OKI M6295 x 2
+
+ Battery
+ 93C46 EEPROM (at U24)
+
+ 28MHz XTAL
+
+ TODO: doesn't boot. Can be tricked via debugger:
+ when stuck at PC 0x16628, do PC = 0x1662a
+***************************************************************************/
+
+ROM_START( paccarn )
+ ROM_REGION( 0x80000, "maincpu", 0 )
+ ROM_LOAD16_WORD_SWAP( "pl1-mpr0b.u41", 0x00000, 0x80000, CRC(ef6b08ea) SHA1(61fe4db433a154233c4e1efd248ad51ba1d265d0) )
+
+ ROM_REGION( 0x100000, "sprites0", 0 )
+ ROM_LOAD16_BYTE( "pl1-obj0.u52", 0x00000, 0x80000, CRC(1dd7c292) SHA1(e78d4be35c24616a1954910039e381869246a246) )
+ ROM_LOAD16_BYTE( "pl1-obj1.u53", 0x00001, 0x80000, CRC(7b9935d0) SHA1(ef05230689124d0999ba9e472968e04d6e75c405) )
+
+ ROM_REGION( 0x80000, "layer0", 0 )
+ ROM_LOAD16_BYTE( "pl1-cha0.u60", 0x00000, 0x40000, CRC(7977662e) SHA1(5aaa69ffaa62b20196a7b638232716b7c6391490) )
+ ROM_LOAD16_BYTE( "pl1-cha1.u61", 0x00001, 0x40000, CRC(2150eafa) SHA1(e744a0861ee8a76c2bb24f681df38966df5dc9f0) )
+
+ ROM_REGION( 0x40000, "oki1", 0 )
+ ROM_LOAD( "pl1-voi0.u27", 0x00000, 0x40000, CRC(e22b87e3) SHA1(83a6952fb0f695bb74cc5a3a1e24a916b6de9c8e) )
+
+ ROM_REGION( 0x40000, "oki2", ROMREGION_ERASE00 )
+ // empty ROM socket
+
+ ROM_REGION( 0x117 * 3, "plds", 0 ) // all protected
+ ROM_LOAD( "n44u1b.u1", 0x117*0, 0x117, NO_DUMP )
+ ROM_LOAD( "n44u3b.u3", 0x117*1, 0x117, NO_DUMP )
+ ROM_LOAD( "n44u51a.u51", 0x117*2, 0x117, NO_DUMP )
+ROM_END
+
+/***************************************************************************
+
Poka Poka Satan - wack-a-mole game with one frontal upright screen and two
table-top touch screens to bang on with plastic "hammers"
@@ -5255,8 +5353,9 @@ GAME( 1996, agalletah, agallet, sailormn, cave, cave_state, init_agallet,
GAME( 1996, hotdogst, 0, hotdogst, cave, cave_state, init_hotdogst, ROT90, "Marble (Ace International license)", "Hotdog Storm (Korea)", MACHINE_SUPPORTS_SAVE )
-GAME( 1996, pacslot, 0, pacslot, pacslot, cave_state, init_tjumpman, ROT0, "Namco", "Pac-Slot", MACHINE_SUPPORTS_SAVE )
-GAME( 1996, paceight, 0, paceight, paceight, cave_state, init_tjumpman, ROT0, "Namco", "Pac-Eight", MACHINE_SUPPORTS_SAVE )
+GAME( 1996, pacslot, 0, pacslot, pacslot, cave_state, init_tjumpman, ROT0, "Namco", "Pac-Slot", MACHINE_SUPPORTS_SAVE )
+GAME( 1996, paceight, 0, paceight, paceight, cave_state, init_tjumpman, ROT0, "Namco", "Pac-Eight", MACHINE_SUPPORTS_SAVE )
+GAME( 1996, paccarn, 0, paccarn, paccarn, cave_state, init_tjumpman, ROT0, "Namco", "Pac-Carnival", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // stuck at boot. See ROM_LOAD for infos on how to get it to start via debugger
GAME( 1996, ppsatan, 0, ppsatan, ppsatan, cave_state, init_ppsatan, ROT0, "Kato Seisakujo Co., Ltd.", "Poka Poka Satan (Japan)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_GRAPHICS )
diff --git a/src/mame/drivers/cbm2.cpp b/src/mame/drivers/cbm2.cpp
index 5cec01c471f..ae2bbae0d14 100644
--- a/src/mame/drivers/cbm2.cpp
+++ b/src/mame/drivers/cbm2.cpp
@@ -11,10 +11,7 @@
*/
#include "emu.h"
-#include "emupal.h"
-#include "screen.h"
-#include "softlist.h"
-#include "speaker.h"
+
#include "bus/cbm2/exp.h"
#include "bus/cbm2/user.h"
#include "bus/ieee488/ieee488.h"
@@ -37,6 +34,11 @@
#include "video/mc6845.h"
#include "video/mos6566.h"
+#include "emupal.h"
+#include "screen.h"
+#include "softlist.h"
+#include "speaker.h"
+
#define PLA1_TAG "u78"
#define PLA2_TAG "u88"
#define MOS6567_TAG "u23"
@@ -1413,7 +1415,7 @@ INPUT_PORTS_END
MC6845_UPDATE_ROW( cbm2_state::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
int x = 0;
@@ -1429,7 +1431,7 @@ MC6845_UPDATE_ROW( cbm2_state::crtc_update_row )
if (cursor_x == column) color ^= 1;
color &= de;
- bitmap.pix32(vbp + y, hbp + x++) = pen[color];
+ bitmap.pix(vbp + y, hbp + x++) = pen[color];
if (bit < 8 || !m_graphics) data <<= 1;
}
diff --git a/src/mame/drivers/cc40.cpp b/src/mame/drivers/cc40.cpp
index 31cb481ddc3..c0f60554e7e 100644
--- a/src/mame/drivers/cc40.cpp
+++ b/src/mame/drivers/cc40.cpp
@@ -226,7 +226,7 @@ HD44780_PIXEL_UPDATE(cc40_state::cc40_pixel_update)
{
// internal: 2*16, external: 1*31
if (y == 7) y++; // the cursor is slightly below the character
- bitmap.pix16(1 + y, 1 + line*16*6 + pos*6 + x) = state ? 1 : 2;
+ bitmap.pix(1 + y, 1 + line*16*6 + pos*6 + x) = state ? 1 : 2;
}
}
diff --git a/src/mame/drivers/cd2650.cpp b/src/mame/drivers/cd2650.cpp
index f5469448101..01760a14fbd 100644
--- a/src/mame/drivers/cd2650.cpp
+++ b/src/mame/drivers/cd2650.cpp
@@ -189,26 +189,25 @@ u32 cd2650_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con
Further, the letters have bit 6 set low, thus the range is 01 to 1A.
When the bottom of the screen is reached, it does not scroll, it just wraps around. */
- u8 y,ra,chr,gfx;
- u16 offset=0,sy=0,x,mem;
+ u16 offset=0,sy=0;
- for (y = 0; y < 16; y++)
+ for (u8 y = 0; y < 16; y++)
{
- for (ra = 0; ra < CHARACTER_LINES; ra++)
+ for (u8 ra = 0; ra < CHARACTER_LINES; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = 0; x < 80; x++)
+ for (u16 x = 0; x < 80; x++)
{
- gfx = 0;
+ u8 gfx = 0;
if (ra < CHARACTER_HEIGHT)
{
- mem = offset + y + (x<<4);
+ u16 mem = offset + y + (x<<4);
if (mem > 0x4ff)
mem -= 0x500;
- chr = m_p_videoram[mem] & 0x3f;
+ u8 chr = m_p_videoram[mem] & 0x3f;
gfx = m_p_chargen[(bitswap<8>(chr,7,6,2,1,0,3,4,5)<<3) | ra];
}
diff --git a/src/mame/drivers/cdc721.cpp b/src/mame/drivers/cdc721.cpp
index 028d9cae951..1643cf91350 100644
--- a/src/mame/drivers/cdc721.cpp
+++ b/src/mame/drivers/cdc721.cpp
@@ -259,24 +259,23 @@ void cdc721_state::cdc721_palette(palette_device &palette) const
uint32_t cdc721_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,chr,gfx,attr,pen;
- uint16_t sy=0,x;
+ uint16_t sy=0;
m_flashcnt++;
- for (y = 0; y < 30; y++)
+ for (uint8_t y = 0; y < 30; y++)
{
uint16_t ma = m_videoram[y * 2] | m_videoram[y * 2 + 1] << 8;
- for (ra = 0; ra < 15; ra++)
+ for (uint8_t ra = 0; ra < 15; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = 0; x < 160; x+=2)
+ for (uint16_t x = 0; x < 160; x+=2)
{
- pen = 1;
- chr = m_videoram[(x + ma) & 0x1fff];
- attr = m_videoram[(x + ma + 1) & 0x1fff];
- gfx = m_rom_chargen[chr | (ra << 8) ];
+ uint8_t pen = 1;
+ uint8_t chr = m_videoram[(x + ma) & 0x1fff];
+ uint8_t attr = m_videoram[(x + ma + 1) & 0x1fff];
+ uint8_t gfx = m_rom_chargen[chr | (ra << 8) ];
if (BIT(attr, 0)) // blank
pen = 0;
if (BIT(attr, 1) && (ra == 14)) // underline
diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp
index 94e939df12b..f5579cf659a 100644
--- a/src/mame/drivers/cdi.cpp
+++ b/src/mame/drivers/cdi.cpp
@@ -402,7 +402,7 @@ void cdi_state::draw_lcd(int y)
if (y >= 22 || !m_slave_hle.found())
return;
- uint32_t *scanline = &m_lcdbitmap.pix32(y);
+ uint32_t *scanline = &m_lcdbitmap.pix(y);
for (int lcd = 0; lcd < 8; lcd++)
{
diff --git a/src/mame/drivers/ceres.cpp b/src/mame/drivers/ceres.cpp
new file mode 100644
index 00000000000..ace6ea7b186
--- /dev/null
+++ b/src/mame/drivers/ceres.cpp
@@ -0,0 +1,283 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+/*
+ * Eidgenössische Technische Hochschule (ETH) Zürich Ceres-1
+ *
+ * Sources:
+ * - http://bitsavers.org/pdf/eth/ceres/Eberle_Hardware_Description_of_the_Workstation_Ceres_198701.pdf
+ *
+ * TODO:
+ * - startup/reset memory map
+ * - i/o device mapping
+ * - interrupt acknowledge
+ * - WD1002-05 Winchester/Floppy Disk Controller (WFC)
+ * - keyboard
+ * - mouse
+ */
+
+#include "emu.h"
+
+// cpus and memory
+#include "cpu/ns32000/ns32000.h"
+#include "machine/ram.h"
+
+// various hardware
+//#include "machine/ns32081.h"
+//#include "machine/ns32082.h"
+#include "machine/mc68681.h"
+#include "machine/z80scc.h"
+#include "machine/m3002.h"
+#include "machine/am9519.h"
+#include "machine/wd_fdc.h"
+
+// busses and connectors
+#include "bus/rs232/rs232.h"
+#include "imagedev/floppy.h"
+
+// video
+#include "screen.h"
+
+#define VERBOSE 0
+#include "logmacro.h"
+
+class ceres1_state : public driver_device
+{
+public:
+ ceres1_state(machine_config const &mconfig, device_type type, char const *tag)
+ : driver_device(mconfig, type, tag)
+ , m_cpu(*this, "cpu")
+ , m_ram(*this, "ram")
+ , m_uart(*this, "uart")
+ , m_serial(*this, "v24")
+ , m_scc(*this, "scc")
+ , m_rtc(*this, "rtc")
+ , m_icu(*this, "icu")
+ , m_fdc(*this, "fdc")
+ , m_fdd(*this, "fdc:0:35dd")
+ , m_screen(*this, "screen")
+ , m_vram(*this, "vram")
+ {
+ }
+
+protected:
+ // driver_device overrides
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ // address maps
+ template <unsigned ST> void cpu_map(address_map &map);
+
+public:
+ // machine config
+ void ceres1(machine_config &config);
+
+ u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect);
+
+ void wfc_w(offs_t offset, u8 data);
+ u8 wfc_r(offs_t offset);
+
+protected:
+ DECLARE_FLOPPY_FORMATS(floppy_formats);
+
+ required_device<ns32032_device> m_cpu;
+ required_device<ram_device> m_ram;
+
+ required_device<scn2681_device> m_uart;
+ required_device<rs232_port_device> m_serial;
+ required_device<z80scc_device> m_scc;
+ required_device<m3002_device> m_rtc;
+ required_device<am9519_device> m_icu;
+
+ required_device<wd2797_device> m_fdc;
+ required_device<floppy_image_device> m_fdd;
+
+ required_device<screen_device> m_screen;
+ required_shared_ptr<u32> m_vram;
+
+ u8 m_dcr;
+};
+
+void ceres1_state::machine_start()
+{
+ save_item(NAME(m_dcr));
+}
+
+void ceres1_state::machine_reset()
+{
+ m_dcr = 0;
+}
+
+void ceres1_state::wfc_w(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ case 0: LOG("wfc_w data 0x%02x\n", offset, data); break;
+ case 1: LOG("wfc_w write precomp 0x%02x\n", offset, data); break;
+ case 2: LOG("wfc_w sector count 0x%02x\n", offset, data); break;
+ case 3: LOG("wfc_w sector number 0x%02x\n", offset, data); break;
+ case 4: LOG("wfc_w cylinder low 0x%02x\n", offset, data); break;
+ case 5: LOG("wfc_w cylinder high 0x%02x\n", offset, data); break;
+ case 6: LOG("wfc_w size/drive/head 0x%02x\n", offset, data); break;
+ case 7: LOG("wfc_w command 0x%02x\n", offset, data); break;
+ }
+}
+
+u8 ceres1_state::wfc_r(offs_t offset)
+{
+ u8 data = 0;
+
+ switch (offset)
+ {
+ case 0: // data
+ case 1: // error
+ case 2: // sector count
+ case 3: // sector number
+ case 4: // cylinder low
+ case 5: // cylinder high
+ case 6: // size/drive/head
+ break;
+
+ case 7: // status
+ //data = 0x40; // drive ready
+ break;
+ }
+
+ LOG("wfc_r reg %d data 0x%02x\n", offset, data);
+
+ return data;
+}
+
+template <unsigned ST> void ceres1_state::cpu_map(address_map &map)
+{
+ // FIXME: address lines 19-23 driven high until boot flipflop reset
+ map(0x000000, 0x007fff).rom().region("eprom", 0);
+
+ map(0xe00000, 0xe3ffff).ram().share("vram");
+ map(0xf80000, 0xf87fff).rom().region("eprom", 0);
+ map(0xfffa00, 0xfffa00).lw8(
+ [this](u8 data)
+ {
+ m_dcr = data & 7;
+ }, "dcr_w");
+ map(0xfffdc0, 0xfffdc3).portr("SW1");
+ map(0xfffdc0, 0xfffdc0).lw8(
+ [this](u8 data)
+ {
+ m_cpu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
+ }, "bt_ff_w");
+
+ map(0xfffc00, 0xfffc1f).rw(FUNC(ceres1_state::wfc_r), FUNC(ceres1_state::wfc_w)).umask32(0xff);
+}
+
+static INPUT_PORTS_START(ceres1)
+ PORT_START("SW1")
+ PORT_DIPNAME(0x80, 0x00, "Diagnostic") PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING(0x00, DEF_STR(On))
+ PORT_DIPSETTING(0x80, DEF_STR(Off))
+
+ PORT_DIPNAME(0x40, 0x40, "FPU") PORT_DIPLOCATION("SW1:2")
+ PORT_DIPSETTING(0x00, DEF_STR(On))
+ PORT_DIPSETTING(0x40, DEF_STR(Off))
+
+ PORT_DIPNAME(0x20, 0x00, "MMU") PORT_DIPLOCATION("SW1:3")
+ PORT_DIPSETTING(0x00, DEF_STR(On))
+ PORT_DIPSETTING(0x20, DEF_STR(Off))
+
+ PORT_DIPUNUSED_DIPLOC(0x10, 0x00, "SW1:4")
+
+ // TODO: configuration is guesswork
+ PORT_DIPNAME(0x0f, 0x08, "Memory Size") PORT_DIPLOCATION("SW1:5,6,7,8")
+ PORT_DIPSETTING(0x01, "2M")
+ PORT_DIPSETTING(0x03, "4M")
+ PORT_DIPSETTING(0x07, "6M")
+ PORT_DIPSETTING(0x0f, "8M")
+INPUT_PORTS_END
+
+void ceres1_state::ceres1(machine_config &config)
+{
+ NS32032(config, m_cpu, 10_MHz_XTAL);
+ m_cpu->set_addrmap(0, &ceres1_state::cpu_map<0>);
+ m_cpu->set_addrmap(6, &ceres1_state::cpu_map<6>);
+
+ RAM(config, m_ram);
+ m_ram->set_default_size("2MiB");
+ m_ram->set_default_value(0);
+ m_ram->set_extra_options("4MiB,6MiB,8MiB");
+
+ // TODO: port A txd/rxd connect to keyboard
+ SCN2681(config, m_uart, 3.6864_MHz_XTAL);
+ m_uart->irq_cb().set(m_icu, FUNC(am9519_device::ireq2_w));
+ m_uart->outport_cb().set(
+ [this](u8 data)
+ {
+ m_serial->write_dtr(BIT(data, 0));
+ m_serial->write_rts(BIT(data, 1));
+ m_icu->ireq0_w(BIT(data, 3));
+ m_icu->ireq4_w(BIT(data, 4));
+ });
+ m_uart->b_tx_cb().set(m_serial, FUNC(rs232_port_device::write_txd));
+
+ RS232_PORT(config, m_serial, default_rs232_devices, nullptr);
+ m_serial->rxd_handler().set(m_uart, FUNC(scn2681_device::rx_b_w));
+ m_serial->cts_handler().set(m_uart, FUNC(scn2681_device::ip1_w));
+ m_serial->dcd_handler().set(m_uart, FUNC(scn2681_device::ip0_w));
+ m_serial->dsr_handler().set(m_uart, FUNC(scn2681_device::ip2_w));
+
+ // TODO: RS-485 ports "na" and "nb"
+ SCC8530N(config, m_scc, 6_MHz_XTAL);
+ m_scc->configure_channels(m_uart->clock(), 0, m_uart->clock(), 0);
+ m_scc->out_int_callback().set(m_icu, FUNC(am9519_device::ireq1_w));
+
+ M3002(config, m_rtc, 32.768_kHz_XTAL);
+ m_rtc->irq_out().set(m_icu, FUNC(am9519_device::ireq5_w));
+
+ AM9519(config, m_icu);
+ m_icu->out_int_callback().set_inputline(m_cpu, INPUT_LINE_IRQ0);
+
+ // TODO: WD1002-05 Winchester/Floppy Disk Controller (WFC)
+ WD2797(config, m_fdc, 0);
+ FLOPPY_CONNECTOR(config, "fdc:0", "35dd", FLOPPY_35_DD, true, floppy_formats).enable_sound(false);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_raw(70'000'000, 1344, 0, 1024, 838, 0, 800);
+ m_screen->set_screen_update(FUNC(ceres1_state::screen_update));
+}
+
+u32 ceres1_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rectangle const &cliprect)
+{
+ if (!BIT(m_dcr, 0))
+ {
+ offs_t offset = BIT(m_dcr, 1) ? 0x20000 : 0;
+ u32 const invert = BIT(m_dcr, 2) ? 0xffffffffU : 0;
+
+ for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++)
+ {
+ for (int x = screen.visible_area().min_x; x <= screen.visible_area().max_x; x += 32)
+ {
+ u32 const data = m_vram[offset++] ^ invert;
+
+ for (unsigned i = 0; i < 32; i++)
+ bitmap.pix(y, x + i) = BIT(data, 31 - i) ? rgb_t::white() : rgb_t::black();
+ }
+ }
+ }
+
+ return 0;
+}
+
+FLOPPY_FORMATS_MEMBER(ceres1_state::floppy_formats)
+ {}
+FLOPPY_FORMATS_END
+
+ROM_START(ceres1)
+ ROM_REGION32_LE(0x8000, "eprom", 0)
+ ROM_SYSTEM_BIOS(0, "ceres1", "30.6.89")
+ ROMX_LOAD("by0_u44__30_6_89.u44", 0x0000, 0x2000, CRC(8e1559fe) SHA1(2e11c144fd698b9576816f5cfb003c46ab9ce43b), ROM_BIOS(0) | ROM_SKIP(3))
+ ROMX_LOAD("by1_u43__30_6_89.u43", 0x0001, 0x2000, CRC(18625b0c) SHA1(3319043507b7eeb488ecd839708032f968e6e53e), ROM_BIOS(0) | ROM_SKIP(3))
+ ROMX_LOAD("by2_u42__30_6_89.u42", 0x0002, 0x2000, CRC(a56497c5) SHA1(85858bea9fd27031ee0191b1d508c7469a384f10), ROM_BIOS(0) | ROM_SKIP(3))
+ ROMX_LOAD("by3_u41__30_6_89.u41", 0x0003, 0x2000, CRC(6b628912) SHA1(f76ea089e8bf82f572f27def344b5174e577ebbb), ROM_BIOS(0) | ROM_SKIP(3))
+ROM_END
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
+COMP(1986, ceres1, 0, 0, ceres1, ceres1, ceres1_state, empty_init, "Eidgenössische Technische Hochschule Zürich", "Ceres-1", MACHINE_NOT_WORKING)
diff --git a/src/mame/drivers/cesclass.cpp b/src/mame/drivers/cesclass.cpp
index 73d88eaeccd..1ebb1c639f9 100644
--- a/src/mame/drivers/cesclass.cpp
+++ b/src/mame/drivers/cesclass.cpp
@@ -71,25 +71,21 @@ void cesclassic_state::video_start()
uint32_t cesclassic_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,xi;
-
bitmap.fill(m_palette->black_pen(), cliprect);
+ for(int y=0;y<64;y++)
{
- for(y=0;y<64;y++)
+ for(int x=0;x<16;x++)
{
- for(x=0;x<16;x++)
+ for(int xi=0;xi<16;xi++)
{
- for(xi=0;xi<16;xi++)
- {
- uint8_t color;
+ uint8_t color;
- color = (((m_vram[x+y*16+0x400])>>(15-xi)) & 1);
- color |= (((m_vram[x+y*16])>>(15-xi)) & 1)<<1;
+ color = (((m_vram[x+y*16+0x400])>>(15-xi)) & 1);
+ color |= (((m_vram[x+y*16])>>(15-xi)) & 1)<<1;
- if((x*16+xi)<256 && ((y)+0)<256)
- bitmap.pix32(y, x*16+xi) = m_palette->pen(color);
- }
+ if((x*16+xi)<256 && ((y)+0)<256)
+ bitmap.pix(y, x*16+xi) = m_palette->pen(color);
}
}
}
diff --git a/src/mame/drivers/cfx9850.cpp b/src/mame/drivers/cfx9850.cpp
index ffed4490e53..cfd718e9aa1 100644
--- a/src/mame/drivers/cfx9850.cpp
+++ b/src/mame/drivers/cfx9850.cpp
@@ -270,7 +270,7 @@ u32 cfx9850_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
for (int b = 0; b < 8; b++)
{
- bitmap.pix16(63-j, x+b) = ( data1 & 0x80 ) ? ( data2 & 0x80 ? 3 : 2 ) : ( data2 & 0x80 ? 1 : 0 );
+ bitmap.pix(63-j, x+b) = ( data1 & 0x80 ) ? ( data2 & 0x80 ? 3 : 2 ) : ( data2 & 0x80 ? 1 : 0 );
data1 <<= 1;
data2 <<= 1;
}
diff --git a/src/mame/drivers/cgang.cpp b/src/mame/drivers/cgang.cpp
index 094cef0f10c..851f021bf4e 100644
--- a/src/mame/drivers/cgang.cpp
+++ b/src/mame/drivers/cgang.cpp
@@ -9,14 +9,12 @@ It is an electromechanical arcade lightgun game. There is no screen, feedback
is with motorized elements, lamps and 7segs, and of course sounds and music.
To shoot the targets in MAME, either enable -mouse and click on one of the
-cosmogang lanes(left mouse button doubles as gun trigger by default).
+pink aliens(left mouse button doubles as gun trigger by default).
Or, configure the gun aim inputs and share them with the trigger. For example
use Z,X,C,V,B for the gun aims, and "Z or X or C or V or B" for the trigger.
TODO:
- dump/add Japanese version
-- game can't be played properly within MAME's constraints (mechanical stuff,
- and the lightguns linked to it)
- shot target is sometimes ignored, maybe a BTANB? since it's easy to dismiss
on the real thing as a missed aim. It turns on the lightgun lamp but then
doesn't read the lightsensor.
@@ -346,14 +344,14 @@ TIMER_DEVICE_CALLBACK_MEMBER(cgang_state::door_motor_tick)
void cgang_state::refresh_motor_output()
{
- // output motor positions in range 0-100
+ // output motor positions in range 0-255
for (int i = 0; i < 5; i++)
{
- m_cg_count[i] = int((m_cg_motor_pos[i] / float(CG_MOTOR_LIMIT)) * 100.0 + 0.5);
- m_en_count[i] = int((m_en_pos[i] / float(CG_MOTOR_LIMIT)) * 100.0 + 0.5);
+ m_cg_count[i] = int((m_cg_motor_pos[i] / float(CG_MOTOR_LIMIT)) * 255.0 + 0.5);
+ m_en_count[i] = int((m_en_pos[i] / float(CG_MOTOR_LIMIT)) * 255.0 + 0.5);
}
- m_door_count = (m_conf->read() & 1) ? int((m_door_motor_pos / float(DOOR_MOTOR_LIMIT)) * 100.0 + 0.5) : 0;
+ m_door_count = (m_conf->read() & 1) ? int((m_door_motor_pos / float(DOOR_MOTOR_LIMIT)) * 255.0 + 0.5) : 0;
}
diff --git a/src/mame/drivers/cgenie.cpp b/src/mame/drivers/cgenie.cpp
index ca1fe971ec6..b9c8edae374 100644
--- a/src/mame/drivers/cgenie.cpp
+++ b/src/mame/drivers/cgenie.cpp
@@ -344,10 +344,10 @@ MC6845_UPDATE_ROW( cgenie_state::crtc_update_row )
{
const rgb_t map[] = { m_background_color, m_palette[8], m_palette[6], m_palette[5] };
- bitmap.pix32(y + vbp, column * 4 + hbp + 0) = map[code >> 6 & 0x03];
- bitmap.pix32(y + vbp, column * 4 + hbp + 1) = map[code >> 4 & 0x03];
- bitmap.pix32(y + vbp, column * 4 + hbp + 2) = map[code >> 2 & 0x03];
- bitmap.pix32(y + vbp, column * 4 + hbp + 3) = map[code >> 0 & 0x03];
+ bitmap.pix(y + vbp, column * 4 + hbp + 0) = map[code >> 6 & 0x03];
+ bitmap.pix(y + vbp, column * 4 + hbp + 1) = map[code >> 4 & 0x03];
+ bitmap.pix(y + vbp, column * 4 + hbp + 2) = map[code >> 2 & 0x03];
+ bitmap.pix(y + vbp, column * 4 + hbp + 3) = map[code >> 0 & 0x03];
}
else
{
@@ -367,7 +367,7 @@ MC6845_UPDATE_ROW( cgenie_state::crtc_update_row )
// 8 pixel chars
for (int p = 0; p < 8; p++)
- bitmap.pix32(y + vbp, column * 8 + hbp + p) = BIT(gfx, 7 - p) ? m_palette[color] : m_background_color;
+ bitmap.pix(y + vbp, column * 8 + hbp + p) = BIT(gfx, 7 - p) ? m_palette[color] : m_background_color;
}
}
}
diff --git a/src/mame/drivers/champbas.cpp b/src/mame/drivers/champbas.cpp
index 472b2a4fc7f..d802707a1b4 100644
--- a/src/mame/drivers/champbas.cpp
+++ b/src/mame/drivers/champbas.cpp
@@ -281,6 +281,13 @@ void exctsccr_state::exctsccr_sound_io_map(address_map &map)
map(0x8e, 0x8f).w("ay4", FUNC(ay8910_device::data_address_w));
}
+void exctsccr_state::exctscc2_sound_io_map(address_map &map)
+{
+ map.global_mask(0x00ff);
+ map(0x8a, 0x8b).w("ay1", FUNC(ay8910_device::data_address_w));
+ map(0x8e, 0x8f).w("ay2", FUNC(ay8910_device::data_address_w));
+}
+
/*************************************
@@ -715,6 +722,19 @@ void exctsccr_state::exctsccr(machine_config &config)
vref.add_route(0, "dac2", 1.0, DAC_VREF_POS_INPUT); vref.add_route(0, "dac2", -1.0, DAC_VREF_NEG_INPUT);
}
+void exctsccr_state::exctscc2(machine_config &config)
+{
+ exctsccr(config);
+
+ m_audiocpu->set_addrmap(AS_IO, &exctsccr_state::exctscc2_sound_io_map);
+
+ subdevice<ay8910_device>("ay1")->set_clock(XTAL(14'318'181)/8); // measured on PCB
+
+ // Exciting Soccer II only has two AYs
+ config.device_remove("ay3");
+ config.device_remove("ay4");
+}
+
/* Bootleg running on a modified Champion Baseball board */
void exctsccr_state::exctsccrb(machine_config &config)
{
@@ -1184,9 +1204,9 @@ ROM_END
ROM_START( exctscc2 ) // 2-PCB stack: CPU & SOUND BOARD + DISPLAY BOARD N. 58AS51-1
ROM_REGION( 0x10000, "maincpu", 0 ) // on CPU & sound board
- ROM_LOAD( "eprom_1_vr_alpha_denshi.3j", 0x0000, 0x2000, CRC(c6115362) SHA1(6a258631abd72ef6b8d7968bb4b2bc88e89e597d) )
+ ROM_LOAD( "eprom_1_vr_b_alpha_denshi.3j", 0x0000, 0x2000, CRC(c6115362) SHA1(6a258631abd72ef6b8d7968bb4b2bc88e89e597d) ) // B handwritten
ROM_LOAD( "eprom_2_vr_alpha_denshi.3k", 0x2000, 0x2000, CRC(de36ba00) SHA1(0a0d92e710b8c749f145571bc8a204609456d19d) )
- ROM_LOAD( "eprom_3_vr_alpha_denshi.3l", 0x4000, 0x2000, CRC(1ddfdf65) SHA1(313d0a7f13fc2de15aa32492c38a59fbafad9f01) )
+ ROM_LOAD( "eprom_3_vr_v_alpha_denshi.3l", 0x4000, 0x2000, CRC(1ddfdf65) SHA1(313d0a7f13fc2de15aa32492c38a59fbafad9f01) ) // V handwritten
ROM_REGION( 0x10000, "audiocpu", 0 ) // on CPU & sound board
ROM_LOAD( "eprom_0_vr_alpha_denshi.7d", 0x0000, 0x2000, CRC(2c675a43) SHA1(aa0a8dbcae955e3da92c435202f2a1ed238c377e) ) // yes 0, not 10
@@ -1198,21 +1218,21 @@ ROM_START( exctscc2 ) // 2-PCB stack: CPU & SOUND BOARD + DISPLAY BOARD N. 58AS5
ROM_REGION( 0x2000, "alpha_8201:mcu", 0 ) // on CPU & sound board
ROM_LOAD( "alpha-8303_44801b42.1d", 0x0000, 0x2000, CRC(66adcb37) SHA1(e1c72ecb161129dcbddc0b16dd90e716d0c79311) )
- ROM_REGION( 0x04000, "gfx1", 0 ) // 3bpp chars + sprites: rearranged by DRIVER_INIT to leave only chars, on display board
+ ROM_REGION( 0x04000, "gfx1", 0 ) // 3bpp chars + sprites: rearranged by init_exctsccr() to leave only chars, on display board
ROM_LOAD( "eprom_4_vr_alpha_denshi.5a", 0x0000, 0x2000, CRC(4ff1783d) SHA1(c45074864c3a4bcbf3a87d164027ae16dca53d9c) ) // planes 0,1
ROM_LOAD( "eprom_6_vr_alpha_denshi.5c", 0x2000, 0x2000, CRC(1fb84ee6) SHA1(56ceb86c509be783f806403ac21e7c9684760d5f) ) // plane 3
- ROM_REGION( 0x04000, "gfx2", 0 ) // 3bpp chars + sprites: rearranged by DRIVER_INIT to leave only sprites, on display board
+ ROM_REGION( 0x04000, "gfx2", 0 ) // 3bpp chars + sprites: rearranged by init_exctsccr() to leave only sprites, on display board
ROM_LOAD( "eprom_5_vr_alpha_denshi.5b", 0x0000, 0x2000, CRC(5605b60b) SHA1(19d5909896ae4a3d7552225c369d30475c56793b) ) // planes 0,1
ROM_REGION( 0x02000, "gfx3", 0 ) // 4bpp sprites, on display board
ROM_LOAD( "eprom_7_vr_alpha_denshi.5k", 0x0000, 0x1000, CRC(1d37edfa) SHA1(184fa6dd7b1b3fff4c5fc19b42301ccb7979ac84) )
ROM_LOAD( "eprom_8_vr_alpha_denshi.5l", 0x1000, 0x1000, CRC(b97f396c) SHA1(4ffe512acf047230bd593911a615fc0ef66b481d) )
- ROM_REGION( 0x0220, "proms", 0 ) // it's suspected these weren't dumped for this set, but taken from an Exciting Soccer (see MT5026)
- ROM_LOAD( "prom1.5j", 0x0000, 0x0020, BAD_DUMP CRC(d9b10bf0) SHA1(bc1263331968f4bf37eb70ec4f56a8cb763c29d2) ) // palette, marked as 7051 on CPU & sound board
- ROM_LOAD( "prom3.60h", 0x0020, 0x0100, BAD_DUMP CRC(b5db1c2c) SHA1(900aaaac6b674a9c5c7b7804a4b0c3d5cce761aa) ) // lookup table, marked as 7052 on display board
- ROM_LOAD( "prom2.61d", 0x0120, 0x0100, BAD_DUMP CRC(8a9c0edf) SHA1(8aad387e9409cff0eeb42eeb57e9ea88770a8c9a) ) // lookup table, marked as 7052 on display board
+ ROM_REGION( 0x0220, "proms", 0 ) // colors match video from PCB (even the field one)
+ ROM_LOAD( "tbp18s030.5j", 0x0000, 0x0020, CRC(899d153d) SHA1(669f1a2de387ae7cdce16c2714a384c9586ed255) ) // palette, marked as 7051 on CPU & sound board
+ ROM_LOAD( "tbp24s10.61d", 0x0020, 0x0100, CRC(75613784) SHA1(38dc1c1d2d0f33d58f035942e71665c9810fdab1) ) // lookup table, marked as 7052 on display board
+ ROM_LOAD( "tbp24s10.60h", 0x0120, 0x0100, CRC(1a52d6eb) SHA1(cd0c8cbaf5d8df14df34103cde2ec595039a6d51) ) // lookup table, marked as 7052 on display board
ROM_END
@@ -1291,4 +1311,4 @@ GAME( 1983, exctsccra, exctsccr, exctsccr, exctsccr, exctsccr_state, init_exc
GAME( 1983, exctsccrj, exctsccr, exctsccr, exctsccr, exctsccr_state, init_exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1983, exctsccrjo, exctsccr, exctsccr, exctsccr, exctsccr_state, init_exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer (Japan, older)", MACHINE_SUPPORTS_SAVE )
GAME( 1983, exctsccrb, exctsccr, exctsccrb, exctsccr, exctsccr_state, init_exctsccr, ROT270, "bootleg (Kazutomi)", "Exciting Soccer (bootleg)", MACHINE_SUPPORTS_SAVE ) // on champbasj hardware
-GAME( 1984, exctscc2, 0, exctsccr, exctsccr, exctsccr_state, init_exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer II", MACHINE_SUPPORTS_SAVE )
+GAME( 1984, exctscc2, 0, exctscc2, exctsccr, exctsccr_state, init_exctsccr, ROT270, "Alpha Denshi Co.", "Exciting Soccer II", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/chihiro.cpp b/src/mame/drivers/chihiro.cpp
index 764e59c8606..678403f7abc 100644
--- a/src/mame/drivers/chihiro.cpp
+++ b/src/mame/drivers/chihiro.cpp
@@ -1953,8 +1953,10 @@ void chihiro_state::chihirogd(machine_config &config)
ROM_SYSTEM_BIOS( 0, "bios0", "Chihiro Bios" ) \
ROM_LOAD_BIOS( 0, "chihiro_xbox_bios.bin", 0x000000, 0x80000, CRC(66232714) SHA1(b700b0041af8f84835e45d1d1250247bf7077188) ) \
ROM_REGION( 0x200000, "mediaboard", 0) \
+ ROM_LOAD16_WORD_SWAP_BIOS( 0, "fpr-23887_29lv160te.ic4", 0x000000, 0x200000, CRC(13034372) SHA1(77197fba2781ed1d81402c48bd743adb26d3161a) ) \
ROM_LOAD16_WORD_SWAP_BIOS( 0, "fpr21042_m29w160et.bin", 0x000000, 0x200000, CRC(a4fcab0b) SHA1(a13cf9c5cdfe8605d82150b7573652f419b30197) ) \
ROM_REGION( 0x204080, "others", 0) \
+ ROM_LOAD16_WORD_SWAP_BIOS( 0, "315-6351a_epc1pc8.ic2", 0x0000, 0x1ff01, CRC(488624ea) SHA1(1a607337a186415ae90b48934ce2aae81639d4de) ) \
ROM_LOAD16_WORD_SWAP_BIOS( 0, "ic10_g24lc64.bin", 0x0000, 0x2000, CRC(cfc5e06f) SHA1(3ababd4334d8d57abb22dd98bd2d347df39648d9) ) \
ROM_LOAD16_WORD_SWAP_BIOS( 0, "ic11_24lc024.bin", 0x2000, 0x80, CRC(8dc8374e) SHA1(cc03a0650bfac4bf6cb66e414bbef121cba53efe) ) \
ROM_LOAD16_WORD_SWAP_BIOS( 0, "pc20_g24lc64.bin", 0x2080, 0x2000, CRC(7742ab62) SHA1(82dad6e2a75bab4a4840dc6939462f1fb9b95101) )
diff --git a/src/mame/drivers/cinemat.cpp b/src/mame/drivers/cinemat.cpp
index cdf9babd997..863ef360e7f 100644
--- a/src/mame/drivers/cinemat.cpp
+++ b/src/mame/drivers/cinemat.cpp
@@ -31,6 +31,7 @@
#include "emu.h"
#include "includes/cinemat.h"
+#include "speaker.h"
#include "armora.lh"
#include "barrier.lh"
@@ -1069,14 +1070,23 @@ void cinemat_state::cinemat_jmi_32k(machine_config &config)
void cinemat_state::spacewar(machine_config &config)
{
cinemat_nojmi_4k(config);
- SPACE_WARS_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ SPACE_WARS_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
+
m_screen->set_screen_update(FUNC(cinemat_state::screen_update_spacewar));
}
void cinemat_state::barrier(machine_config &config)
{
cinemat_jmi_4k(config);
- BARRIER_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ BARRIER_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
WRITE_LINE_MEMBER(cinemat_state::speedfrk_start_led_w)
@@ -1088,78 +1098,127 @@ WRITE_LINE_MEMBER(cinemat_state::speedfrk_start_led_w)
void cinemat_state::speedfrk(machine_config &config)
{
cinemat_nojmi_8k(config);
- SPEED_FREAK_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ SPEED_FREAK_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
// m_outlatch->q_out_cb<1>().set(FUNC(cinemat_state::speedfrk_start_led_w));
}
void cinemat_state::starhawk(machine_config &config)
{
cinemat_jmi_4k(config);
- STAR_HAWK_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ STAR_HAWK_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_16level_state::sundance(machine_config &config)
{
cinemat_jmi_8k(config);
- SUNDANCE_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ SUNDANCE_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_state::tailg(machine_config &config)
{
cinemat_nojmi_8k(config);
- TAIL_GUNNER_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ TAIL_GUNNER_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
m_outlatch->q_out_cb<7>().set(FUNC(cinemat_state::mux_select_w));
}
void cinemat_state::warrior(machine_config &config)
{
cinemat_jmi_8k(config);
- WARRIOR_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ WARRIOR_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_state::armora(machine_config &config)
{
cinemat_jmi_16k(config);
- ARMOR_ATTACK_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ ARMOR_ATTACK_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_state::ripoff(machine_config &config)
{
cinemat_jmi_8k(config);
- RIPOFF_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ RIPOFF_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_state::starcas(machine_config &config)
{
cinemat_jmi_8k(config);
- STAR_CASTLE_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ STAR_CASTLE_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_64level_state::solarq(machine_config &config)
{
cinemat_jmi_16k(config);
- SOLAR_QUEST_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ SOLAR_QUEST_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_color_state::boxingb(machine_config &config)
{
cinemat_jmi_32k(config);
- BOXING_BUGS_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
- m_screen->set_visarea(0, 1024, 0, 788);
+
+ SPEAKER(config, "mono").front_center();
+ BOXING_BUGS_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
m_outlatch->q_out_cb<7>().append(FUNC(cinemat_state::mux_select_w));
+
+ m_screen->set_visarea(0, 1024, 0, 788);
}
void cinemat_state::wotw(machine_config &config)
{
cinemat_jmi_16k(config);
m_screen->set_visarea(0, 1120, 0, 767);
- WAR_OF_THE_WORLDS_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ WAR_OF_THE_WORLDS_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void cinemat_color_state::wotwc(machine_config &config)
{
cinemat_jmi_16k(config);
- WAR_OF_THE_WORLDS_AUDIO(config, "soundboard", 0).configure_latch_inputs(*m_outlatch);
+
+ SPEAKER(config, "mono").front_center();
+ WAR_OF_THE_WORLDS_AUDIO(config, "soundboard", 0)
+ .configure_latch_inputs(*m_outlatch)
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
}
void demon_state::demon(machine_config &config)
diff --git a/src/mame/drivers/cit101.cpp b/src/mame/drivers/cit101.cpp
index a34c5d077ef..97ec2c97ffa 100644
--- a/src/mame/drivers/cit101.cpp
+++ b/src/mame/drivers/cit101.cpp
@@ -232,7 +232,7 @@ u32 cit101_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, con
{
const int line = ((z / (BIT(rowattr, 8) ? 2 : 1)) + (rowattr & 0x00f)) & 15;
const bool last_line = z++ == rowlines - 1;
- draw_line(&bitmap.pix32(y++), cliprect.left(), cliprect.right(), line, last_line, rowaddr, rowattr, scrattr);
+ draw_line(&bitmap.pix(y++), cliprect.left(), cliprect.right(), line, last_line, rowaddr, rowattr, scrattr);
if (last_line)
break;
}
diff --git a/src/mame/drivers/cit220.cpp b/src/mame/drivers/cit220.cpp
index 18651203502..bbde707b26c 100644
--- a/src/mame/drivers/cit220.cpp
+++ b/src/mame/drivers/cit220.cpp
@@ -135,7 +135,7 @@ SCN2674_DRAW_CHARACTER_MEMBER(cit220_state::draw_character)
for (int i = 0; i < width; i++)
{
- bitmap.pix32(y, x++) = BIT(dots, 9) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y, x++) = BIT(dots, 9) ? rgb_t::white() : rgb_t::black();
dots <<= 1;
}
}
diff --git a/src/mame/drivers/clayshoo.cpp b/src/mame/drivers/clayshoo.cpp
index 87b59a9ad6f..3af7ad14ed8 100644
--- a/src/mame/drivers/clayshoo.cpp
+++ b/src/mame/drivers/clayshoo.cpp
@@ -196,7 +196,7 @@ uint32_t clayshoo_state::screen_update_clayshoo(screen_device &screen, bitmap_rg
for (i = 0; i < 8; i++)
{
pen_t pen = (data & 0x80) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
data = data << 1;
x = x + 1;
diff --git a/src/mame/drivers/clcd.cpp b/src/mame/drivers/clcd.cpp
index 7f014bca587..aae6accb85e 100644
--- a/src/mame/drivers/clcd.cpp
+++ b/src/mame/drivers/clcd.cpp
@@ -105,43 +105,43 @@ public:
for (int x = 0; x < 60; x++)
{
- uint8_t bit = m_ram->pointer()[offset++];
-
- bitmap.pix16(y, (x * 8) + 0) = (bit >> 7) & 1;
- bitmap.pix16(y, (x * 8) + 1) = (bit >> 6) & 1;
- bitmap.pix16(y, (x * 8) + 2) = (bit >> 5) & 1;
- bitmap.pix16(y, (x * 8) + 3) = (bit >> 4) & 1;
- bitmap.pix16(y, (x * 8) + 4) = (bit >> 3) & 1;
- bitmap.pix16(y, (x * 8) + 5) = (bit >> 2) & 1;
- bitmap.pix16(y, (x * 8) + 6) = (bit >> 1) & 1;
- bitmap.pix16(y, (x * 8) + 7) = (bit >> 0) & 1;
+ uint8_t const bit = m_ram->pointer()[offset++];
+
+ bitmap.pix(y, (x * 8) + 0) = BIT(bit, 7);
+ bitmap.pix(y, (x * 8) + 1) = BIT(bit, 6);
+ bitmap.pix(y, (x * 8) + 2) = BIT(bit, 5);
+ bitmap.pix(y, (x * 8) + 3) = BIT(bit, 4);
+ bitmap.pix(y, (x * 8) + 4) = BIT(bit, 3);
+ bitmap.pix(y, (x * 8) + 5) = BIT(bit, 2);
+ bitmap.pix(y, (x * 8) + 6) = BIT(bit, 1);
+ bitmap.pix(y, (x * 8) + 7) = BIT(bit, 0);
}
}
}
else
{
- uint8_t *font = m_lcd_char_rom->base();
+ uint8_t const *font = m_lcd_char_rom->base();
if (m_lcd_mode & LCD_MODE_ALT)
{
font += 1024;
}
- int chrw = (m_lcd_size & LCD_SIZE_CHRW) ? 8 : 6;
+ int const chrw = (m_lcd_size & LCD_SIZE_CHRW) ? 8 : 6;
for (int y = 0; y < 128; y++)
{
- int offset = (m_lcd_scrolly * 128) + (m_lcd_scrollx & 0x7f) + ((y / 8) * 128);
+ int const offset = (m_lcd_scrolly * 128) + (m_lcd_scrollx & 0x7f) + ((y / 8) * 128);
for (int x = 0; x < 480; x++)
{
- uint8_t ch = m_ram->pointer()[offset + (x / chrw)];
+ uint8_t const ch = m_ram->pointer()[offset + (x / chrw)];
uint8_t bit = font[((ch & 0x7f) * 8) + (y % 8)];
if (ch & 0x80)
{
bit = ~bit;
}
- bitmap.pix16(y, x) = (bit >> (7 - (x % chrw))) & 1;
+ bitmap.pix(y, x) = (bit >> (7 - (x % chrw))) & 1;
}
}
}
@@ -565,52 +565,54 @@ void clcd_state::clcd_mem(address_map &map)
}
/* Input ports */
+// The keyboard has { } ~ _ marked, but there doesn't seem to be a way to type them in.
+// Natural keyboard is set up for the various apps, but since BASIC is the usual Commodore Basic, uppercase turns into graphics and is unusable.
static INPUT_PORTS_START( clcd )
PORT_START( "COL0" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
- PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') PORT_CHAR('_')
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('N')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('V')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("@") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('@')
PORT_START( "COL1" )
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("+") PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR('+')
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('O')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('U')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('T')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
PORT_START( "COL2" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("=") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=')
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(": [") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(':') PORT_CHAR('[')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('K')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('H')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(": [") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(':') PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
PORT_START( "COL3" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('M')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
PORT_START( "COL4" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('\"')
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0 ^") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0 ^") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('^') PORT_CHAR('~')
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
@@ -618,22 +620,22 @@ static INPUT_PORTS_START( clcd )
PORT_START( "COL5" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
- PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("; ]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(';') PORT_CHAR(']')
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('L')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('J')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('G')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("; ]") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(';') PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
PORT_START( "COL6" )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("HOME CLR") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME))
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("*") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*')
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('P')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('I')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('R')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r')
PORT_START( "COL7" )
@@ -649,7 +651,7 @@ static INPUT_PORTS_START( clcd )
PORT_START( "SPECIAL" )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("STOP") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END))
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CAPSLOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LEFT SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT))
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LEFT SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT),UCHAR_SHIFT_1)
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CBM") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT))
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // clears screen and goes into infinite loop
diff --git a/src/mame/drivers/clickstart.cpp b/src/mame/drivers/clickstart.cpp
index 9c67a8f78cc..e46cc3d3d7d 100644
--- a/src/mame/drivers/clickstart.cpp
+++ b/src/mame/drivers/clickstart.cpp
@@ -9,7 +9,7 @@
mouse optical sensor is a N2163, probably from Agilent.
ClickStart cartridges pinout:
-
+
1 N/C 2 GND
3 GND 4 VCC
5 GND 6 VCC
diff --git a/src/mame/drivers/cliffhgr.cpp b/src/mame/drivers/cliffhgr.cpp
index 3761c0548b7..339866ab13c 100644
--- a/src/mame/drivers/cliffhgr.cpp
+++ b/src/mame/drivers/cliffhgr.cpp
@@ -83,7 +83,6 @@ Side 2 = 0x8F7DDD (or 0x880000 | ( 0x77 << 12 ) | 0x0DDD)
#include "video/tms9928a.h"
#include "machine/nvram.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/cmi.cpp b/src/mame/drivers/cmi.cpp
index 333d352af29..2f83ed95871 100644
--- a/src/mame/drivers/cmi.cpp
+++ b/src/mame/drivers/cmi.cpp
@@ -490,7 +490,7 @@ uint32_t cmi_state::screen_update_cmi2x(screen_device &screen, bitmap_rgb32 &bit
for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
uint8_t *src = &m_video_ram[(512/8) * ((y + y_scroll) & 0xff)];
- uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
+ uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
for (int x = cliprect.min_x; x <= cliprect.max_x; x += 8)
{
@@ -507,7 +507,7 @@ uint32_t cmi_state::screen_update_cmi2x(screen_device &screen, bitmap_rgb32 &bit
if (m_lp_touch_port->read() && BIT(m_q219_pia->b_output(), 1))
{
/* Invert target pixel */
- bitmap.pix32(m_lp_y_port->read(), m_lp_x_port->read()) ^= 0x00ffffff;
+ bitmap.pix(m_lp_y_port->read(), m_lp_x_port->read()) ^= 0x00ffffff;
}
@@ -2048,6 +2048,14 @@ void cmi_state::machine_reset()
m_m6809_bs_hack_cnt[0] = 0;
m_m6809_bs_hack_cnt[1] = 0;
+ //m_midi_ptm[0]->set_g1(1); // /G1 has unknown source, "TIMER 1A /GATE" per schematic
+ m_midi_ptm[0]->set_g2(0); // /G2 and /G3 wired to ground per schematic
+ m_midi_ptm[0]->set_g3(0);
+
+ m_midi_ptm[1]->set_g1(0); // /G1, /G2, and /G3 wired to ground per schematic
+ m_midi_ptm[1]->set_g2(0);
+ m_midi_ptm[1]->set_g3(0);
+
memset(m_map_sel, 0, 16);
for (int i = 0; i < 4; i++)
@@ -2229,17 +2237,11 @@ void cmi_state::cmi2x(machine_config &config)
PTM6840(config, m_midi_ptm[0], 0);
m_midi_ptm[0]->set_external_clocks(0, 384000, 0); // C1 is 0, C2 is 384kHz per schematic block diagram, C3 is CLICK SYNC IN
- //m_midi_ptm[0]->set_g1(1); // /G1 has unknown source, "TIMER 1A /GATE" per schematic
- m_midi_ptm[0]->set_g2(0); // /G2 and /G3 wired to ground per schematic
- m_midi_ptm[0]->set_g3(0);
//m_midi_ptm[0]->o1_callback().set(FUNC(cmi_state::midi_ptm0_c1_w)); // TIMER 1A O/P per schematic
//m_midi_ptm[0]->o2_callback().set(FUNC(cmi_state::midi_ptm0_c2_w)); // CLK 2 per schematic
m_midi_ptm[0]->o3_callback().set(FUNC(cmi_state::midi_ptm0_c3_w));
PTM6840(config, m_midi_ptm[1], 0); // entirely clocked by PTM 0
- m_midi_ptm[1]->set_g1(0); // /G1, /G2, and /G3 wired to ground per schematic
- m_midi_ptm[1]->set_g2(0);
- m_midi_ptm[1]->set_g3(0);
//m_midi_ptm[1]->o1_callback().set(FUNC(cmi_state::midi_sync_out_1_w)); // SYNC OUT 1 per schematic
//m_midi_ptm[1]->o2_callback().set(FUNC(cmi_state::midi_sync_out_2_w)); // SYNC OUT 2 per schematic
//m_midi_ptm[1]->o3_callback().set(FUNC(cmi_state::midi_sync_out_3_w)); // SYNC OUT 3 per schematic
diff --git a/src/mame/drivers/cobra.cpp b/src/mame/drivers/cobra.cpp
index 162bf98d927..9fcd2d39ca6 100644
--- a/src/mame/drivers/cobra.cpp
+++ b/src/mame/drivers/cobra.cpp
@@ -860,8 +860,8 @@ public:
void cobra_renderer::render_color_scan(int32_t scanline, const extent_t &extent, const cobra_polydata &extradata, int threadid)
{
- uint32_t *fb = &m_backbuffer->pix32(scanline);
- float *zb = (float*)&m_zbuffer->pix32(scanline);
+ uint32_t *const fb = &m_backbuffer->pix(scanline);
+ float *const zb = (float*)&m_zbuffer->pix(scanline);
float z = extent.param[POLY_Z].start;
float dz = extent.param[POLY_Z].dpdx;
@@ -961,8 +961,8 @@ void cobra_renderer::render_texture_scan(int32_t scanline, const extent_t &exten
float ga = extent.param[POLY_A].start;
float dga = extent.param[POLY_A].dpdx;
- uint32_t *fb = &m_backbuffer->pix32(scanline);
- float *zb = (float*)&m_zbuffer->pix32(scanline);
+ uint32_t *const fb = &m_backbuffer->pix(scanline);
+ float *const zb = (float*)&m_zbuffer->pix(scanline);
uint32_t texture_width = 1 << ((extradata.tex_format >> 28) & 0xf);
uint32_t texture_height = 1 << ((extradata.tex_format >> 24) & 0xf);
@@ -1066,7 +1066,7 @@ void cobra_renderer::draw_point(const rectangle &visarea, vertex_t &v, uint32_t
if (x >= visarea.min_x && x <= visarea.max_x &&
y >= visarea.min_y && y <= visarea.max_y)
{
- uint32_t *fb = &m_backbuffer->pix32(y);
+ uint32_t *const fb = &m_backbuffer->pix(y);
fb[x] = color;
}
}
@@ -1094,7 +1094,7 @@ void cobra_renderer::draw_line(const rectangle &visarea, vertex_t &v1, vertex_t
{
int y = y1 + (dy * (float)(x - x1) / (float)(dx));
- uint32_t *fb = &m_backbuffer->pix32(y);
+ uint32_t *const fb = &m_backbuffer->pix(y);
fb[x] = color;
x++;
@@ -1107,7 +1107,7 @@ void cobra_renderer::draw_line(const rectangle &visarea, vertex_t &v1, vertex_t
{
int x = x1 + (dx * (float)(y - y1) / (float)(dy));
- uint32_t *fb = &m_backbuffer->pix32(y);
+ uint32_t *const fb = &m_backbuffer->pix(y);
fb[x] = color;
y++;
@@ -2610,11 +2610,11 @@ void cobra_renderer::gfx_fifo_exec()
uint32_t *buffer;
switch (m_gfx_gram[0x80104/4])
{
- case 0x800000: buffer = &m_framebuffer->pix32(y); break;
- case 0x200000: buffer = &m_backbuffer->pix32(y); break;
- case 0x0e0000: buffer = &m_overlay->pix32(y); break;
- case 0x000800: buffer = &m_zbuffer->pix32(y); break;
- case 0x000200: buffer = &m_stencil->pix32(y); break;
+ case 0x800000: buffer = &m_framebuffer->pix(y); break;
+ case 0x200000: buffer = &m_backbuffer->pix(y); break;
+ case 0x0e0000: buffer = &m_overlay->pix(y); break;
+ case 0x000800: buffer = &m_zbuffer->pix(y); break;
+ case 0x000200: buffer = &m_stencil->pix(y); break;
default:
{
@@ -2666,11 +2666,11 @@ void cobra_renderer::gfx_fifo_exec()
uint32_t *buffer;
switch (m_gfx_gram[0x80104/4])
{
- case 0x800000: buffer = &m_framebuffer->pix32(y+i); break;
- case 0x200000: buffer = &m_backbuffer->pix32(y+i); break;
- case 0x0e0000: buffer = &m_overlay->pix32(y+i); break;
- case 0x000800: buffer = &m_zbuffer->pix32(y+i); break;
- case 0x000200: buffer = &m_stencil->pix32(y+i); break;
+ case 0x800000: buffer = &m_framebuffer->pix(y+i); break;
+ case 0x200000: buffer = &m_backbuffer->pix(y+i); break;
+ case 0x0e0000: buffer = &m_overlay->pix(y+i); break;
+ case 0x000800: buffer = &m_zbuffer->pix(y+i); break;
+ case 0x000200: buffer = &m_stencil->pix(y+i); break;
default:
{
diff --git a/src/mame/drivers/cocoloco.cpp b/src/mame/drivers/cocoloco.cpp
index 37e9ac204ba..18e6e0060d4 100644
--- a/src/mame/drivers/cocoloco.cpp
+++ b/src/mame/drivers/cocoloco.cpp
@@ -288,7 +288,7 @@ uint32_t cocoloco_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
color |= ((m_videoram[count|0x6000] >> (xi)) & 1) << 3;
if (cliprect.contains(x + xi, 256 - y))
- bitmap.pix16(256 - y, x + xi) = m_palette->pen(color & 0x0f);
+ bitmap.pix(256 - y, x + xi) = m_palette->pen(color & 0x0f);
}
count++;
diff --git a/src/mame/drivers/compucolor.cpp b/src/mame/drivers/compucolor.cpp
index f5dc5662f4b..ca1b9824215 100644
--- a/src/mame/drivers/compucolor.cpp
+++ b/src/mame/drivers/compucolor.cpp
@@ -284,12 +284,12 @@ uint32_t compucolor2_state::screen_update(screen_device &screen, bitmap_rgb32 &b
uint8_t data = m_char_rom->base()[char_offs];
- rgb_t fg = m_palette->pen_color(attr & 0x07);
- rgb_t bg = m_palette->pen_color((attr >> 3) & 0x07);
+ rgb_t const fg = m_palette->pen_color(attr & 0x07);
+ rgb_t const bg = m_palette->pen_color((attr >> 3) & 0x07);
for (int x = 0; x < 6; x++)
{
- bitmap.pix32(y, (sx * 6) + x) = BIT(data, 7) ? fg : bg;
+ bitmap.pix(y, (sx * 6) + x) = BIT(data, 7) ? fg : bg;
data <<= 1;
}
diff --git a/src/mame/drivers/comx35.cpp b/src/mame/drivers/comx35.cpp
index ae63ceabe3e..12d4842427e 100644
--- a/src/mame/drivers/comx35.cpp
+++ b/src/mame/drivers/comx35.cpp
@@ -20,7 +20,6 @@
#include "includes/comx35.h"
#include "formats/imageutl.h"
#include "screen.h"
-#include "softlist.h"
/***************************************************************************
PARAMETERS
@@ -346,7 +345,7 @@ static INPUT_PORTS_START( comx35 )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('?')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR(39)
PORT_START("D2")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('[')
@@ -392,11 +391,11 @@ static INPUT_PORTS_START( comx35 )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR('+') PORT_CHAR('{')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('-') PORT_CHAR('|')
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*') PORT_CHAR('}')
- PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('~')
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CHAR(8)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR('+')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('-')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_START("D7")
PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
@@ -633,7 +632,6 @@ void comx35_state::base(machine_config &config, const XTAL clock)
QUICKLOAD(config, "quickload", "comx").set_load_callback(FUNC(comx35_state::quickload_cb));
CASSETTE(config, m_cassette).set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
- //m_cassette->add_route(ALL_OUTPUTS, "mono", 0.05);
// expansion bus
COMX_EXPANSION_SLOT(config, m_exp, 0, comx_expansion_cards, "eb").irq_callback().set(FUNC(comx35_state::irq_w));
diff --git a/src/mame/drivers/consola_emt.cpp b/src/mame/drivers/consola_emt.cpp
index 8e5abca8046..74bff79497f 100644
--- a/src/mame/drivers/consola_emt.cpp
+++ b/src/mame/drivers/consola_emt.cpp
@@ -233,7 +233,7 @@ HD44780_PIXEL_UPDATE( consoemt_state::lcd_pixel_update )
return;
if (line < 2 && pos < 20)
- bitmap.pix16(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
+ bitmap.pix(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
}
diff --git a/src/mame/drivers/coolpool.cpp b/src/mame/drivers/coolpool.cpp
index 8028dcc7a7e..f5fad8a2a87 100644
--- a/src/mame/drivers/coolpool.cpp
+++ b/src/mame/drivers/coolpool.cpp
@@ -63,21 +63,20 @@ static const uint16_t nvram_unlock_seq[] =
TMS340X0_SCANLINE_RGB32_CB_MEMBER(coolpool_state::amerdart_scanline)
{
- uint16_t *vram = &m_vram_base[(params->rowaddr << 8) & 0xff00];
- uint32_t *dest = &bitmap.pix32(scanline);
+ uint16_t const *const vram = &m_vram_base[(params->rowaddr << 8) & 0xff00];
+ uint32_t *const dest = &bitmap.pix(scanline);
rgb_t pens[16];
int coladdr = params->coladdr;
- int x;
/* update the palette */
if (scanline < 256)
- for (x = 0; x < 16; x++)
+ for (int x = 0; x < 16; x++)
{
uint16_t pal = m_vram_base[x];
pens[x] = rgb_t(pal4bit(pal >> 4), pal4bit(pal >> 8), pal4bit(pal >> 12));
}
- for (x = params->heblnk; x < params->hsblnk; x += 4)
+ for (int x = params->heblnk; x < params->hsblnk; x += 4)
{
uint16_t pixels = vram[coladdr++ & 0xff];
dest[x + 0] = pens[(pixels >> 0) & 15];
@@ -90,13 +89,12 @@ TMS340X0_SCANLINE_RGB32_CB_MEMBER(coolpool_state::amerdart_scanline)
TMS340X0_SCANLINE_RGB32_CB_MEMBER(coolpool_state::coolpool_scanline)
{
- uint16_t *vram = &m_vram_base[(params->rowaddr << 8) & 0x1ff00];
- uint32_t *dest = &bitmap.pix32(scanline);
- const pen_t *pens = m_tlc34076->pens();
+ uint16_t const *const vram = &m_vram_base[(params->rowaddr << 8) & 0x1ff00];
+ uint32_t *const dest = &bitmap.pix(scanline);
+ pen_t const *const pens = m_tlc34076->pens();
int coladdr = params->coladdr;
- int x;
- for (x = params->heblnk; x < params->hsblnk; x += 2)
+ for (int x = params->heblnk; x < params->hsblnk; x += 2)
{
uint16_t pixels = vram[coladdr++ & 0xff];
dest[x + 0] = pens[pixels & 0xff];
diff --git a/src/mame/drivers/coolridr.cpp b/src/mame/drivers/coolridr.cpp
index 8b454e86424..cbb54e200b3 100644
--- a/src/mame/drivers/coolridr.cpp
+++ b/src/mame/drivers/coolridr.cpp
@@ -663,17 +663,17 @@ do {
/* iterate over pixels in Y */ \
for (cury = desty; cury <= destendy; cury++) \
{ \
- PIXEL_TYPE *destptr = &dest.pixt<PIXEL_TYPE>(cury, destx); \
- const uint8_t *srcptr = srcdata; \
+ PIXEL_TYPE *destptr = &dest.pix(cury, destx); \
+ const uint8_t *srcptr = srcdata; \
srcdata += dy; \
\
/* iterate over unrolled blocks of 4 */ \
for (curx = 0; curx < numblocks; curx++) \
{ \
- COOL_PIXEL_OP(destptr[0], srcptr[0]); \
- COOL_PIXEL_OP(destptr[1], srcptr[1]); \
- COOL_PIXEL_OP(destptr[2], srcptr[2]); \
- COOL_PIXEL_OP(destptr[3], srcptr[3]); \
+ COOL_PIXEL_OP(destptr[0], srcptr[0]); \
+ COOL_PIXEL_OP(destptr[1], srcptr[1]); \
+ COOL_PIXEL_OP(destptr[2], srcptr[2]); \
+ COOL_PIXEL_OP(destptr[3], srcptr[3]); \
\
srcptr += 4; \
destptr += 4; \
@@ -682,7 +682,7 @@ do {
/* iterate over leftover pixels */ \
for (curx = 0; curx < leftovers; curx++) \
{ \
- COOL_PIXEL_OP(destptr[0], srcptr[0]); \
+ COOL_PIXEL_OP(destptr[0], srcptr[0]); \
srcptr++; \
destptr++; \
} \
@@ -695,8 +695,8 @@ do {
/* iterate over pixels in Y */ \
for (cury = desty; cury <= destendy; cury++) \
{ \
- PIXEL_TYPE *destptr = &dest.pixt<PIXEL_TYPE>(cury, destx); \
- const uint8_t *srcptr = srcdata; \
+ PIXEL_TYPE *destptr = &dest.pix(cury, destx); \
+ const uint8_t *srcptr = srcdata; \
srcdata += dy; \
\
/* iterate over unrolled blocks of 4 */ \
@@ -910,8 +910,8 @@ uint32_t coolridr_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint16_t* linesrc = &m_screen_bitmap[Screen].pix16(y);
- uint16_t* linedest = &bitmap.pix16(y);
+ uint16_t const *const linesrc = &m_screen_bitmap[Screen].pix(y);
+ uint16_t *const linedest = &bitmap.pix(y);
for (int x = cliprect.left(); x<= cliprect.right(); x++)
{
@@ -1129,8 +1129,8 @@ uint32_t coolridr_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
const int pixelOffsetnextX = ((hPositionTable) + ((h+1)* 16 * hZoomHere)) / 0x40; \
if (drawy>clipmaxY) { break; }; \
if (drawy<clipminY) { drawy++; continue; }; \
- line = &drawbitmap->pix16(drawy); \
- /* zline = &object->zbitmap->pix16(drawy); */ \
+ uint16_t *const line = &drawbitmap->pix(drawy); \
+ /* uint16_t *const zline = &object->zbitmap->pix(drawy); */ \
int blockwide = pixelOffsetnextX-pixelOffsetX; \
if (pixelOffsetX+blockwide <clipminX) { drawy++; continue; } \
if (pixelOffsetX>clipmaxX) { drawy++; continue; } \
@@ -1167,8 +1167,8 @@ uint32_t coolridr_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
int realy = ((y*incy)>>21); \
const int drawy = pixelOffsetY+y; \
if ((drawy>clipmaxY) || (drawy<clipminY)) continue; \
- line = &drawbitmap->pix16(drawy); \
- /* zline = &object->zbitmap->pix16(drawy); */ \
+ uint16_t *const line = &drawbitmap->pix(drawy); \
+ /* uint16_t *const zline = &object->zbitmap->pix(drawy); */ \
int drawx = pixelOffsetX; \
for (int x = 0; x < blockwide; x++) \
{ \
@@ -1185,8 +1185,8 @@ uint32_t coolridr_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
{ \
const int drawy = pixelOffsetY+realy; \
if ((drawy>clipmaxY) || (drawy<clipminY)) continue; \
- line = &drawbitmap->pix16(drawy); \
- /* zline = &object->zbitmap->pix16(drawy); */ \
+ uint16_t *const line = &drawbitmap->pix(drawy); \
+ /* uint16_t *const zline = &object->zbitmap->pix(drawy); */ \
int drawx = pixelOffsetX; \
for (int realx = 0; realx < 16; realx++) \
{ \
@@ -1937,9 +1937,6 @@ void *coolridr_state::draw_object_threaded(void *param, int threadid)
uint32_t incy = 0x8000000 / vZoom;
// DEBUG: Draw 16x16 block
- uint16_t* line;
- //uint16_t* zline;
-
if (indirect_zoom_enable)
{
diff --git a/src/mame/drivers/corona.cpp b/src/mame/drivers/corona.cpp
index d8bd5d0ae54..90c58278ed9 100644
--- a/src/mame/drivers/corona.cpp
+++ b/src/mame/drivers/corona.cpp
@@ -499,22 +499,18 @@ void corona_state::video_start()
uint32_t corona_state::screen_update_winner(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x, y;
-
- for (y = 0; y < 256; y++)
- for (x = 0; x < 256; x++)
- bitmap.pix16(y, x) = m_videobuf[y * 512 + x];
+ for (int y = 0; y < 256; y++)
+ for (int x = 0; x < 256; x++)
+ bitmap.pix(y, x) = m_videobuf[y * 512 + x];
return 0;
}
uint32_t corona_state::screen_update_luckyrlt(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x, y;
-
- for (y = 0; y < 256; y++)
- for (x = 0; x < 256; x++)
- bitmap.pix16(255 - y, x) = m_videobuf[y * 512 + x];
+ for (int y = 0; y < 256; y++)
+ for (int x = 0; x < 256; x++)
+ bitmap.pix(255 - y, x) = m_videobuf[y * 512 + x];
return 0;
}
diff --git a/src/mame/drivers/cowtipping.cpp b/src/mame/drivers/cowtipping.cpp
new file mode 100644
index 00000000000..211f6fc680b
--- /dev/null
+++ b/src/mame/drivers/cowtipping.cpp
@@ -0,0 +1,113 @@
+// license:BSD-3-Clause
+// copyright-holders:
+
+/*
+Cow Tipping
+Game Refuge / Team Play 2004
+
+PCB sputnik rev. 1.1
+
+- Motorola Super VZ DragonBall MC68SZ328AVH66
+- XTAL: 80 MHz (near Cyclone), 32.768k (near SoC and PIC)
+- Altera Cyclone EP1C6Q240C7
+- TDA8771AH DAC
+- PIC12C508 Microcontroller
+
+Two identical looking PCBs were dumped. The dumps are different (even taking into account a suspected bad dump), but it
+isn't currently known if it's because they're different sets or because of the saved scores and settings.
+
+The PIC is undumped, but on PCB the game seems to run without it, hanging when checking the ticket dispenser.
+*/
+
+
+
+#include "emu.h"
+#include "cpu/pic16c5x/pic16c5x.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/mc68328.h"
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+
+class cowtipping_state : public driver_device
+{
+public:
+ cowtipping_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu")
+ { }
+
+ void cowtipping(machine_config &config);
+
+protected:
+ virtual void machine_start() override;
+
+private:
+ required_device<cpu_device> m_maincpu;
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ void main_map(address_map &map);
+};
+
+
+void cowtipping_state::machine_start()
+{
+}
+
+uint32_t cowtipping_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ return 0;
+}
+
+void cowtipping_state::main_map(address_map &map)
+{
+ map(0x000000, 0x8000ff).rom().region("maincpu", 0);
+}
+
+
+static INPUT_PORTS_START( cowtipping )
+
+INPUT_PORTS_END
+
+void cowtipping_state::cowtipping(machine_config &config)
+{
+ MC68328(config, m_maincpu, 32.768_kHz_XTAL * 506); // 16.580608 MHz, multiplier unknown, to be adjusted
+ m_maincpu->set_addrmap(AS_PROGRAM, &cowtipping_state::main_map);
+
+ PIC16C56(config, "pic", 4000000); // Actually PIC12C508/P, clock not verified
+
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); // wrong
+ screen.set_refresh_hz(60);
+ screen.set_screen_update(FUNC(cowtipping_state::screen_update));
+ screen.set_size(1024, 256);
+ screen.set_visarea_full();
+
+ PALETTE(config, "palette").set_entries(65536); // wrong
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+}
+
+
+ROM_START( cowtipp )
+ ROM_REGION16_BE(0x800100, "maincpu", 0)
+ ROM_LOAD16_WORD_SWAP( "am29lv640mb-u5-3287.u5", 0x000000, 0x800100, CRC(5aa4ac7c) SHA1(4b882008e13e581c0131875a1845c7e78696087e) )
+ // empty space at u6
+
+ ROM_REGION( 0x1000, "pic", 0 )
+ ROM_LOAD( "56_pic12c508-04p.u3", 0x000, 0x09db, NO_DUMP )
+ROM_END
+
+ROM_START( cowtippa )
+ ROM_REGION16_BE(0x800100, "maincpu", 0)
+ ROM_LOAD16_WORD_SWAP( "am29lv640mb-u5-3276.u5", 0x000000, 0x800100, BAD_DUMP CRC(05ce9f7f) SHA1(c27772c9a6a1feaf4d83ae0902759fa25642ad65) ) // suspected bad, seems to have some problems with bit 5
+ // empty space at u6
+
+ ROM_REGION( 0x1000, "pic", 0 )
+ ROM_LOAD( "54_pic12c508-04p.u3", 0x000, 0x09db, NO_DUMP )
+ROM_END
+
+
+GAME( 2004, cowtipp, 0, cowtipping, cowtipping, cowtipping_state, empty_init, ROT270, "Game Refuge / Team Play", "Cow Tipping - Shake Cattle & Roll (set 1)", MACHINE_IS_SKELETON )
+GAME( 2004, cowtippa, cowtipp, cowtipping, cowtipping, cowtipping_state, empty_init, ROT270, "Game Refuge / Team Play", "Cow Tipping - Shake Cattle & Roll (set 2)", MACHINE_IS_SKELETON )
diff --git a/src/mame/drivers/cps1bl_5205.cpp b/src/mame/drivers/cps1bl_5205.cpp
index 30dbe9fc440..b305c46597f 100644
--- a/src/mame/drivers/cps1bl_5205.cpp
+++ b/src/mame/drivers/cps1bl_5205.cpp
@@ -1082,7 +1082,7 @@ ROM_START( knightsb3 )
== |
| 1 5 6 |
|________________________|
-
+
#1 palce20v8h secured, bruteforce ok
#2 palce16v8h secured, bruteforce ok
#3 palce16v8h secured, registered
@@ -1351,10 +1351,10 @@ GAME( 1991, knightsb3, knights, knightsb, knights, captcommb2_state,
GAME( 1992, sf2b, sf2, sf2b, sf2mdt, cps1bl_5205_state, init_sf2b, ROT0, "bootleg (Playmark)", "Street Fighter II: The World Warrior (bootleg, set 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 910204 ETC
GAME( 1992, sf2b2, sf2, sf2b, sf2mdt, cps1bl_5205_state, init_sf2mdtb, ROT0, "bootleg", "Street Fighter II: The World Warrior (bootleg, set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 910204 ETC
-GAME( 1992, sf2ceb, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdta, ROT0, "bootleg (Playmark)", "Street Fighter II': Champion Edition (Playmark bootleg)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
+GAME( 1992, sf2ceb, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdta, ROT0, "bootleg (Playmark)", "Street Fighter II': Champion Edition (Playmark bootleg, set 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
GAME( 1992, sf2ceb2, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdtb, ROT0, "bootleg", "Street Fighter II': Champion Edition (bootleg, set 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
GAME( 1992, sf2ceb3, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdtb, ROT0, "bootleg", "Street Fighter II': Champion Edition (bootleg, set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
-GAME( 1992, sf2ceb4, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdtb, ROT0, "bootleg", "Street Fighter II': Champion Edition (bootleg, set 3)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
+GAME( 1992, sf2ceb4, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdtb, ROT0, "bootleg", "Street Fighter II': Champion Edition (Playmark bootleg, set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
GAME( 1992, sf2mdt, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdt, ROT0, "bootleg", "Street Fighter II': Magic Delta Turbo (bootleg, set 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
GAME( 1992, sf2mdta, sf2ce, sf2mdt, sf2mdt, cps1bl_5205_state, init_sf2mdta, ROT0, "bootleg", "Street Fighter II': Magic Delta Turbo (bootleg, set 2)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE ) // 920313 ETC
diff --git a/src/mame/drivers/cps1bl_pic.cpp b/src/mame/drivers/cps1bl_pic.cpp
index b0b88216320..d8a1efd5d07 100644
--- a/src/mame/drivers/cps1bl_pic.cpp
+++ b/src/mame/drivers/cps1bl_pic.cpp
@@ -1319,7 +1319,7 @@ ROM_START( jurassic99 )
U98G ATF16V8B-15PC 8 secured, registered
U99G ATF16V8B-15PC 8 secured, registered
U134G ATF16V8B-15PC 8? secured, registered
-
+
3rd column numbers are what's hand-written on each chip
? = hard to read or rubbed off
the #8 pals appear to be just 74LS298 equivalents, can be replaced with real 74LS298 (additional 16-pin footprints underneath each chip) or hand-crafted jed
diff --git a/src/mame/drivers/cps3.cpp b/src/mame/drivers/cps3.cpp
index ce0a55bc62c..ab0408d1a1c 100644
--- a/src/mame/drivers/cps3.cpp
+++ b/src/mame/drivers/cps3.cpp
@@ -707,8 +707,8 @@ inline void cps3_state::cps3_drawgfxzoom(bitmap_rgb32 &dest_bmp,const rectangle
{
for (int y = sy; y < ey; y++)
{
- const u8 *source = source_base + (y_index>>16) * gfx->rowbytes();
- u32 *dest = &dest_bmp.pix32(y);
+ u8 const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ u32 *const dest = &dest_bmp.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
@@ -723,8 +723,8 @@ inline void cps3_state::cps3_drawgfxzoom(bitmap_rgb32 &dest_bmp,const rectangle
{
for (int y = sy; y < ey; y++)
{
- const u8 *source = source_base + (y_index>>16) * gfx->rowbytes();
- u32 *dest = &dest_bmp.pix32(y);
+ u8 const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ u32 *const dest = &dest_bmp.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
@@ -740,8 +740,8 @@ inline void cps3_state::cps3_drawgfxzoom(bitmap_rgb32 &dest_bmp,const rectangle
{
for (int y = sy; y < ey; y++)
{
- const u8 *source = source_base + (y_index>>16) * gfx->rowbytes();
- u32 *dest = &dest_bmp.pix32(y);
+ u8 const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ u32 *const dest = &dest_bmp.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
@@ -757,8 +757,8 @@ inline void cps3_state::cps3_drawgfxzoom(bitmap_rgb32 &dest_bmp,const rectangle
{
for (int y = sy; y < ey; y++)
{
- const u8 *source = source_base + (y_index>>16) * gfx->rowbytes();
- u32 *dest = &dest_bmp.pix32(y);
+ u8 const *const source = source_base + (y_index>>16) * gfx->rowbytes();
+ u32 *const dest = &dest_bmp.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
@@ -1288,8 +1288,8 @@ u32 cps3_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const
/* copy render bitmap without zoom */
for (u32 rendery = cliprect.top(); rendery <= cliprect.bottom(); rendery++)
{
- u32* dstbitmap = &bitmap.pix32(rendery);
- u32* srcbitmap = &m_renderbuffer_bitmap.pix32(rendery);
+ u32 *const dstbitmap = &bitmap.pix(rendery);
+ u32 const *const srcbitmap = &m_renderbuffer_bitmap.pix(rendery);
for (u32 renderx = cliprect.left(); renderx <= cliprect.right(); renderx++)
{
@@ -1303,8 +1303,8 @@ u32 cps3_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const
u32 srcy = cliprect.top() * fszy;
for (u32 rendery = cliprect.top(); rendery <= cliprect.bottom(); rendery++)
{
- u32* dstbitmap = &bitmap.pix32(rendery);
- u32* srcbitmap = &m_renderbuffer_bitmap.pix32(srcy >> 16);
+ u32 *const dstbitmap = &bitmap.pix(rendery);
+ u32 const *const srcbitmap = &m_renderbuffer_bitmap.pix(srcy >> 16);
u32 srcx = cliprect.left() * fszx;
for (u32 renderx = cliprect.left(); renderx <= cliprect.right(); renderx++)
diff --git a/src/mame/drivers/crvision.cpp b/src/mame/drivers/crvision.cpp
index f93bd04a6dc..ef0177bb6e7 100644
--- a/src/mame/drivers/crvision.cpp
+++ b/src/mame/drivers/crvision.cpp
@@ -922,6 +922,7 @@ void laser2001_state::lasr2001(machine_config &config)
// software list
SOFTWARE_LIST(config, "cart_list").set_original("crvision");
SOFTWARE_LIST(config, "cart_list2").set_original("laser2001_cart");
+ SOFTWARE_LIST(config, "flop_list").set_original("laser2001_flop");
}
/***************************************************************************
diff --git a/src/mame/drivers/cubeqst.cpp b/src/mame/drivers/cubeqst.cpp
index 6df6c4eec61..96a799ac89b 100644
--- a/src/mame/drivers/cubeqst.cpp
+++ b/src/mame/drivers/cubeqst.cpp
@@ -130,8 +130,6 @@ void cubeqst_state::palette_w(offs_t offset, uint16_t data, uint16_t mem_mask)
/* TODO: This is a simplified version of what actually happens */
uint32_t cubeqst_state::screen_update_cubeqst(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int y;
-
/*
* Clear the display with palette RAM entry 0xff
* This will be either transparent or an actual colour
@@ -141,13 +139,11 @@ uint32_t cubeqst_state::screen_update_cubeqst(screen_device &screen, bitmap_rgb3
bitmap.fill(m_colormap[255], cliprect);
/* TODO: Add 1 for linebuffering? */
- for (y = cliprect.min_y; y <= cliprect.max_y; ++y)
+ for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
- int i;
int num_entries = m_linecpu->cubeqcpu_get_ptr_ram_val(y);
- uint32_t *stk_ram = m_linecpu->cubeqcpu_get_stack_ram();
- uint32_t *dest = &bitmap.pix32(y);
- uint32_t pen;
+ uint32_t const *const stk_ram = m_linecpu->cubeqcpu_get_stack_ram();
+ uint32_t *const dest = &bitmap.pix(y);
/* Zap the depth buffer */
memset(m_depth_buffer.get(), 0xff, 512);
@@ -155,11 +151,10 @@ uint32_t cubeqst_state::screen_update_cubeqst(screen_device &screen, bitmap_rgb3
/* Process all the spans on this scanline */
if (y < 256)
{
- for (i = 0; i < num_entries; i += 2)
+ for (int i = 0; i < num_entries; i += 2)
{
int color = 0, depth = 0;
int h1 = 0, h2 = 0;
- int x;
int entry1 = stk_ram[(y << 7) | ((i + 0) & 0x7f)];
int entry2 = stk_ram[(y << 7) | ((i + 1) & 0x7f)];
@@ -187,8 +182,8 @@ uint32_t cubeqst_state::screen_update_cubeqst(screen_device &screen, bitmap_rgb3
}
/* Draw the span, testing for depth */
- pen = m_colormap[m_generic_paletteram_16[color]];
- for (x = h1; x <= h2; ++x)
+ uint32_t pen = m_colormap[m_generic_paletteram_16[color]];
+ for (int x = h1; x <= h2; ++x)
{
if (!(m_depth_buffer[x] < depth))
{
diff --git a/src/mame/drivers/cupidon.cpp b/src/mame/drivers/cupidon.cpp
index a4681e71eaf..4f0066ebf99 100644
--- a/src/mame/drivers/cupidon.cpp
+++ b/src/mame/drivers/cupidon.cpp
@@ -29,25 +29,23 @@ public:
m_gfxram(*this, "gfxram")
{ }
+ void init_cupidon();
+ void init_funnyfm();
+
+ void cupidon(machine_config &config);
+ void cupidon_map(address_map &map);
+
+protected:
// devices
required_device<m68340_cpu_device> m_maincpu;
required_shared_ptr<uint32_t> m_gfxram;
uint32_t screen_update_cupidon(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- void init_cupidon();
- void init_funnyfm();
-
uint32_t cupidon_return_ffffffff()
{
return -1; // or it hits an illegal opcode (sleep on the 68340?)
- };
-
- void cupidon(machine_config &config);
- void cupidon_map(address_map &map);
-protected:
-
-
+ }
};
uint32_t cupidon_state::screen_update_cupidon(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
@@ -60,7 +58,7 @@ uint32_t cupidon_state::screen_update_cupidon(screen_device &screen, bitmap_ind1
{
for (int y=0;y<16;y++)
{
- uint16_t* destline = &bitmap.pix16(ytile*16 + y);
+ uint16_t *const destline = &bitmap.pix(ytile*16 + y);
for (int x=0;x<8;x++)
{
diff --git a/src/mame/drivers/cxhumax.cpp b/src/mame/drivers/cxhumax.cpp
index 612e69281e3..a477f9626df 100644
--- a/src/mame/drivers/cxhumax.cpp
+++ b/src/mame/drivers/cxhumax.cpp
@@ -897,17 +897,14 @@ static inline uint32_t ycc_to_rgb(uint32_t ycc)
uint32_t cxhumax_state::screen_update_cxhumax(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int i, j;
-
-
uint32_t osd_pointer = m_drm1_regs[DRM_OSD_PTR_REG];
if(osd_pointer)
{
- uint32_t *ram = m_ram;
- uint32_t *osd_header = &ram[osd_pointer/4];
- uint8_t *vbuf = (uint8_t*)(&ram[osd_header[3]/4]);
- uint32_t *palette = &ram[osd_header[7]/4];
+ uint32_t const *ram = m_ram;
+ uint32_t const *osd_header = &ram[osd_pointer/4];
+ uint8_t const *vbuf = (uint8_t*)(&ram[osd_header[3]/4]);
+ uint32_t const *palette = &ram[osd_header[7]/4];
uint32_t x_disp_start_and_width = osd_header[1];
uint32_t xdisp_width = (x_disp_start_and_width >> 16) & 0x1fff;
@@ -927,14 +924,14 @@ uint32_t cxhumax_state::screen_update_cxhumax(screen_device &screen, bitmap_rgb3
uint32_t first_y = m_drm0_regs[DRM_ACTIVE_Y_REG] & 0xfff;
uint32_t last_y = (m_drm0_regs[DRM_ACTIVE_Y_REG] >> 16) & 0xfff;*/
- for (j=ydisp_start; j <= ydisp_last; j++)
+ for (int j=ydisp_start; j <= ydisp_last; j++)
{
- uint32_t *bmp = &bitmap.pix32(j);
+ uint32_t *const bmp = &bitmap.pix(j);
- for (i=xdisp_start; i <= (xdisp_start + xdisp_width); i++)
+ for (int i=xdisp_start; i <= (xdisp_start + xdisp_width); i++)
{
if ((i <= (xdisp_start + ximg_width)) && (j <= (ydisp_start + yimg_height))) {
- bmp[i] = palette[vbuf[i+((j-ydisp_start)*ximg_width)]];
+ bmp[i] = palette[vbuf[i+((j-ydisp_start)*ximg_width)]]; // FIXME: need BYTE4_XOR_?E for endianness
} else {
bmp[i] = ycc_to_rgb(m_drm1_regs[DRM_BCKGND_REG]);
}
diff --git a/src/mame/drivers/cybertnk.cpp b/src/mame/drivers/cybertnk.cpp
index 306769ebbb5..bc713eedbe1 100644
--- a/src/mame/drivers/cybertnk.cpp
+++ b/src/mame/drivers/cybertnk.cpp
@@ -379,7 +379,7 @@ void cybertnk_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, c
if ((yy>=miny) && (yy<=maxy))
{
- dest = &bitmap.pix16(yy, 0);
+ dest = &bitmap.pix(yy, 0);
int start,end,inc;
diff --git a/src/mame/drivers/cz101.cpp b/src/mame/drivers/cz101.cpp
index b41b08c17b0..1e475f33125 100644
--- a/src/mame/drivers/cz101.cpp
+++ b/src/mame/drivers/cz101.cpp
@@ -259,7 +259,7 @@ HD44780_PIXEL_UPDATE( cz101_state::lcd_pixel_update )
return;
if (line < 2 && pos < 16)
- bitmap.pix16(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
+ bitmap.pix(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
}
void cz101_state::led_4_w(uint8_t data)
diff --git a/src/mame/drivers/d6800.cpp b/src/mame/drivers/d6800.cpp
index 25dd3194179..010f6274193 100644
--- a/src/mame/drivers/d6800.cpp
+++ b/src/mame/drivers/d6800.cpp
@@ -41,6 +41,8 @@
Information and programs can be found at http://chip8.com/?page=78
+ Due to the way the keyboard is scanned, Natural Keyboard/Paste is not possible.
+
**********************************************************************************/
@@ -66,14 +68,7 @@ public:
, m_pia(*this, "pia")
, m_beeper(*this, "beeper")
, m_videoram(*this, "videoram")
- , m_io_x0(*this, "X0")
- , m_io_x1(*this, "X1")
- , m_io_x2(*this, "X2")
- , m_io_x3(*this, "X3")
- , m_io_y0(*this, "Y0")
- , m_io_y1(*this, "Y1")
- , m_io_y2(*this, "Y2")
- , m_io_y3(*this, "Y3")
+ , m_io_keyboard(*this, "X%u", 0U)
, m_io_shift(*this, "SHIFT")
{ }
@@ -107,14 +102,7 @@ private:
required_device<pia6821_device> m_pia;
required_device<beep_device> m_beeper;
required_shared_ptr<uint8_t> m_videoram;
- required_ioport m_io_x0;
- required_ioport m_io_x1;
- required_ioport m_io_x2;
- required_ioport m_io_x3;
- required_ioport m_io_y0;
- required_ioport m_io_y1;
- required_ioport m_io_y2;
- required_ioport m_io_y3;
+ required_ioport_array<4> m_io_keyboard;
required_ioport m_io_shift;
};
@@ -135,61 +123,33 @@ void d6800_state::d6800_map(address_map &map)
static INPUT_PORTS_START( d6800 )
PORT_START("X0")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1')
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_NAME("0") // ee
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_NAME("1") // ed
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_NAME("2") // eb
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_NAME("3") // e7
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("X1")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4')
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5')
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_NAME("4") // de
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_NAME("5") // dd
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_NAME("6") // db
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_NAME("7") // d7
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("X2")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8')
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9')
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_NAME("8") // be
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_NAME("9") // bd
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_NAME("A") // bb
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_NAME("B") // b7
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("X3")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_NAME("C") // 7e
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_NAME("D") // 7d
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_NAME("E") // 7b
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_NAME("F") // 77
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_START("Y0")
- PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4')
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8')
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
-
- PORT_START("Y1")
- PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5')
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9')
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
-
- PORT_START("Y2")
- PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6')
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
-
- PORT_START("Y3")
- PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3')
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7')
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
-
PORT_START("SHIFT")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("FN") PORT_CODE(KEYCODE_LSHIFT)
@@ -197,7 +157,6 @@ static INPUT_PORTS_START( d6800 )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RST") PORT_CODE(KEYCODE_LALT) PORT_CHANGED_MEMBER(DEVICE_SELF, d6800_state, reset_button, 0)
PORT_START("VS")
- /* vblank */
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_CUSTOM) PORT_VBLANK("screen")
INPUT_PORTS_END
@@ -212,16 +171,16 @@ INPUT_CHANGED_MEMBER(d6800_state::reset_button)
/* Video */
uint32_t d6800_state::screen_update_d6800(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t x,y,gfx=0;
+ uint8_t gfx=0;
- for (y = 0; y < 32; y++)
+ for (uint8_t y = 0; y < 32; y++)
{
- uint16_t *p = &bitmap.pix16(y);
+ uint16_t *p = &bitmap.pix(y);
- for (x = 0; x < 8; x++)
+ for (uint8_t x = 0; x < 8; x++)
{
if (m_cb2)
- gfx = m_videoram[ x | (y<<3)];
+ gfx = m_videoram[x | (y<<3)];
*p++ = BIT(gfx, 7);
*p++ = BIT(gfx, 6);
@@ -262,7 +221,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(d6800_state::kansas_r)
if (m_rtc > 159)
m_rtc = 0;
- uint8_t data = m_io_x0->read() & m_io_x1->read() & m_io_x2->read() & m_io_x3->read();
+ uint8_t data = m_io_keyboard[0]->read() & m_io_keyboard[1]->read() & m_io_keyboard[2]->read() & m_io_keyboard[3]->read();
int ca1 = (data == 255) ? 0 : 1;
int ca2 = m_io_shift->read();
int cb1 = (m_rtc) ? 1 : 0;
@@ -323,10 +282,18 @@ uint8_t d6800_state::d6800_keyboard_r()
lines around and reads it another way. This isolates the key that was pressed.
*/
- uint8_t data = m_io_x0->read() & m_io_x1->read() & m_io_x2->read() & m_io_x3->read()
- & m_io_y0->read() & m_io_y1->read() & m_io_y2->read() & m_io_y3->read();
+ u8 y = 8;
+ for (u8 i = 0; i < 4; i++)
+ {
+ u8 data = m_io_keyboard[i]->read() & 15;
+ y <<= 1;
+ if (data < 15)
+ for (u8 j = 0; j < 4; j++)
+ if (!BIT(data, j))
+ return data | (0xf0 - y);
+ }
- return data;
+ return 0xff;
}
void d6800_state::d6800_keyboard_w(uint8_t data)
diff --git a/src/mame/drivers/dai.cpp b/src/mame/drivers/dai.cpp
index 5cc6d97261f..efae8655fcb 100644
--- a/src/mame/drivers/dai.cpp
+++ b/src/mame/drivers/dai.cpp
@@ -212,7 +212,6 @@ void dai_state::dai(machine_config &config)
GFXDECODE(config, "gfxdecode", m_palette, gfx_dai);
PALETTE(config, m_palette, FUNC(dai_state::dai_palette), ARRAY_LENGTH(s_palette));
-
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER(config, "lspeaker").front_left();
@@ -230,6 +229,7 @@ void dai_state::dai(machine_config &config)
m_tms5501->int_callback().set_inputline("maincpu", I8085_INTR_LINE);
m_tms5501->xi_callback().set(FUNC(dai_state::keyboard_r));
m_tms5501->xo_callback().set(FUNC(dai_state::keyboard_w));
+ TIMER(config, m_tms_timer).configure_generic(FUNC(dai_state::tms_timer));
/* software lists */
SOFTWARE_LIST(config, "cass_list").set_original("dai_cass");
diff --git a/src/mame/drivers/dai3wksi.cpp b/src/mame/drivers/dai3wksi.cpp
index 91293f00cee..64a54bdad0e 100644
--- a/src/mame/drivers/dai3wksi.cpp
+++ b/src/mame/drivers/dai3wksi.cpp
@@ -179,9 +179,9 @@ uint32_t dai3wksi_state::screen_update_dai3wksi(screen_device &screen, bitmap_rg
rgb_t pen = (data & (1 << i)) ? m_palette->pen_color(color) : rgb_t::black();
if (m_dai3wksi_flipscreen)
- bitmap.pix32(255-y, 255-x) = pen;
+ bitmap.pix(255-y, 255-x) = pen;
else
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
x++;
}
diff --git a/src/mame/drivers/darius.cpp b/src/mame/drivers/darius.cpp
index 71ed723f5cf..6ef7140a0ec 100644
--- a/src/mame/drivers/darius.cpp
+++ b/src/mame/drivers/darius.cpp
@@ -324,8 +324,8 @@ void darius_state::update_psg1(int port)
void darius_state::update_da()
{
- const int left = m_def_vol[(m_pan[4] >> 4) & 0x0f];
- const int right = m_def_vol[(m_pan[4] >> 0) & 0x0f];
+ const int left = m_def_vol[(m_pan[4] >> 0) & 0x0f];
+ const int right = m_def_vol[(m_pan[4] >> 4) & 0x0f];
if (m_msm5205_l != nullptr)
m_msm5205_l->flt_volume_set_volume(left / 100.0);
diff --git a/src/mame/drivers/ddenlovr.cpp b/src/mame/drivers/ddenlovr.cpp
index 85e8f828216..8e59a701fa2 100644
--- a/src/mame/drivers/ddenlovr.cpp
+++ b/src/mame/drivers/ddenlovr.cpp
@@ -1703,7 +1703,6 @@ uint8_t ddenlovr_state::ddenlovr_gfxrom_r()
void ddenlovr_state::copylayer(bitmap_rgb32 &bitmap, const rectangle &cliprect, int layer)
{
- int x,y;
int scrollx = m_ddenlovr_scroll[layer / 4 * 8 + (layer % 4) + 0];
int scrolly = m_ddenlovr_scroll[layer / 4 * 8 + (layer % 4) + 4];
@@ -1720,15 +1719,15 @@ void ddenlovr_state::copylayer(bitmap_rgb32 &bitmap, const rectangle &cliprect,
if (((m_ddenlovr_layer_enable2 << 4) | m_ddenlovr_layer_enable) & (1 << layer))
{
- for (y = cliprect.top(); y <= cliprect.bottom(); y++)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- for (x = cliprect.left(); x <= cliprect.right(); x++)
+ for (int x = cliprect.left(); x <= cliprect.right(); x++)
{
int pen = m_ddenlovr_pixmap[layer][512 * ((y + scrolly) & 0x1ff) + ((x + scrollx) & 0x1ff)];
if ((pen & transmask) != transpen)
{
pen &= penmask;
- bitmap.pix32(y, x) = pens[pen];
+ bitmap.pix(y, x) = pens[pen];
}
}
}
@@ -4283,18 +4282,16 @@ VIDEO_START_MEMBER(htengoku_state,htengoku)
uint32_t htengoku_state::screen_update_htengoku(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int layer, x, y;
-
// render the layers, one by one, "dynax.c" style. Then convert the pixmaps to "ddenlovr.c"
// format and let screen_update_ddenlovr() do the final compositing (priorities + palettes)
- for (layer = 0; layer < 4; layer++)
+ for (int layer = 0; layer < 4; layer++)
{
m_htengoku_layer.fill(0, cliprect);
hanamai_copylayer(m_htengoku_layer, cliprect, layer);
- for (y = 0; y < 256; y++)
- for (x = 0; x < 512; x++)
- m_ddenlovr_pixmap[3 - layer][y * 512 + x] = (uint8_t)(m_htengoku_layer.pix16(y, x));
+ for (int y = 0; y < 256; y++)
+ for (int x = 0; x < 512; x++)
+ m_ddenlovr_pixmap[3 - layer][y * 512 + x] = uint8_t(m_htengoku_layer.pix(y, x));
}
return screen_update_ddenlovr(screen, bitmap, cliprect);
diff --git a/src/mame/drivers/dec0.cpp b/src/mame/drivers/dec0.cpp
index f4741f3cfa6..b320fac8a5e 100644
--- a/src/mame/drivers/dec0.cpp
+++ b/src/mame/drivers/dec0.cpp
@@ -1469,9 +1469,9 @@ static INPUT_PORTS_START( midres )
PORT_DIPUNUSED_DIPLOC( 0x0080, IP_ACTIVE_LOW, "SW1:8" ) // Always OFF
PORT_DIPNAME( 0x0300, 0x0300, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2")
+ PORT_DIPSETTING( 0x0100, "1" )
PORT_DIPSETTING( 0x0300, "3" )
- PORT_DIPSETTING( 0x0200, "4" )
- PORT_DIPSETTING( 0x0100, "5" )
+ PORT_DIPSETTING( 0x0200, "5" )
PORT_DIPSETTING( 0x0000, "Infinite (Cheat)")
PORT_DIPNAME( 0x0c00, 0x0c00, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW2:3,4")
PORT_DIPSETTING( 0x0800, DEF_STR( Easy ) )
@@ -1492,17 +1492,6 @@ static INPUT_PORTS_START( midres )
PORT_INCLUDE( rotary_ports )
INPUT_PORTS_END
-static INPUT_PORTS_START( midresu )
- PORT_INCLUDE( midres )
-
- PORT_MODIFY("DSW")
- PORT_DIPNAME( 0x0300, 0x0300, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2")
- PORT_DIPSETTING( 0x0100, "1" )
- PORT_DIPSETTING( 0x0300, "3" )
- PORT_DIPSETTING( 0x0200, "5" )
- PORT_DIPSETTING( 0x0000, "Infinite (Cheat)")
-INPUT_PORTS_END
-
static INPUT_PORTS_START( midresb )
PORT_INCLUDE( dec0 )
@@ -4167,8 +4156,8 @@ GAME( 1989, slyspy, secretag, slyspy, slyspy, dec0_state, init_slysp
GAME( 1989, slyspy3, secretag, slyspy, slyspy, dec0_state, init_slyspy, ROT0, "Data East USA", "Sly Spy (US revision 3)", MACHINE_SUPPORTS_SAVE )
GAME( 1989, slyspy2, secretag, slyspy, slyspy, dec0_state, init_slyspy, ROT0, "Data East USA", "Sly Spy (US revision 2)", MACHINE_SUPPORTS_SAVE )
GAME( 1989, midres, 0, midres, midres, dec0_state, empty_init, ROT0, "Data East Corporation", "Midnight Resistance (World)", MACHINE_SUPPORTS_SAVE )
-GAME( 1989, midresu, midres, midres, midresu, dec0_state, empty_init, ROT0, "Data East USA", "Midnight Resistance (US)", MACHINE_SUPPORTS_SAVE )
-GAME( 1989, midresj, midres, midres, midresu, dec0_state, empty_init, ROT0, "Data East Corporation", "Midnight Resistance (Japan)", MACHINE_SUPPORTS_SAVE )
+GAME( 1989, midresu, midres, midres, midres, dec0_state, empty_init, ROT0, "Data East USA", "Midnight Resistance (US)", MACHINE_SUPPORTS_SAVE )
+GAME( 1989, midresj, midres, midres, midres, dec0_state, empty_init, ROT0, "Data East Corporation", "Midnight Resistance (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1990, bouldash, 0, slyspy, bouldash, dec0_state, init_slyspy, ROT0, "Data East Corporation (licensed from First Star)", "Boulder Dash / Boulder Dash Part 2 (World)", MACHINE_SUPPORTS_SAVE )
GAME( 1990, bouldashj, bouldash, slyspy, bouldash, dec0_state, init_slyspy, ROT0, "Data East Corporation (licensed from First Star)", "Boulder Dash / Boulder Dash Part 2 (Japan)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/dec8.cpp b/src/mame/drivers/dec8.cpp
index 0fdd7a79c5e..e443f17e22a 100644
--- a/src/mame/drivers/dec8.cpp
+++ b/src/mame/drivers/dec8.cpp
@@ -2602,17 +2602,17 @@ ROM_START( gondo )
ROM_REGION( 0x40000, "maincpu", 0 )
ROM_LOAD( "dt00-e.f3", 0x08000, 0x08000, CRC(912a7eee) SHA1(15af89babf166dadaa77640e1973d7ebb4c078db) ) // Verified only DT00-E & DT03-E have the "-E" extention
ROM_LOAD( "dt01.f5", 0x10000, 0x10000, CRC(c39bb877) SHA1(9beb59ba19f38417c5d4d36e8f3c41f2b017d2d6) )
- ROM_LOAD( "dt02.f6", 0x20000, 0x10000, CRC(bb5e674b) SHA1(8057dc7464a8b6987536f248d607957923b223cf) )
+ ROM_LOAD( "dt02.f6", 0x20000, 0x10000, CRC(925307a4) SHA1(1e8b8eb21df1a11b14c981b343b34c6cc3676517) ) // same label as the US version, but content identical to Japanese version
ROM_LOAD( "dt03-e.f7", 0x30000, 0x10000, CRC(ee7475eb) SHA1(8c68198ea1c3e89c9c2c4ba0e5d3f47afb8eecd4) )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "dt05-e.h5", 0x8000, 0x8000, CRC(ec08aa29) SHA1(ce83974ae095d9518d1ebf9f7e712f0cbc2c1b42) )
ROM_REGION( 0x1000, "mcu", 0 ) /* i8751 microcontroller */
- ROM_LOAD( "dt-e.b1", 0x0000, 0x1000, NO_DUMP ) // No decapped dump or hand crafted code for this set
+ ROM_LOAD( "dt-e.b1", 0x0000, 0x1000, BAD_DUMP CRC(0d0532ec) SHA1(30894f69ff24c1be4b684e07729bbb3e0f353086) ) // hand-crafted from the US version
ROM_REGION( 0x08000, "gfx1", 0 ) /* characters */
- ROM_LOAD( "dt14.b18", 0x00000, 0x08000, CRC(4bef16e1) SHA1(b8157a7a1b8f36cea1fd353267a4e03d920cb4aa) )
+ ROM_LOAD( "dt14-e.b18", 0x00000, 0x08000, CRC(00cbe9c8) SHA1(de7b640de8fd54ee79194945c96d5768d09f483b) ) // identical to Japanese version
ROM_REGION( 0x80000, "gfx2", 0 ) /* sprites */
ROM_LOAD( "dt19.f13", 0x00000, 0x10000, CRC(da2abe4b) SHA1(d53e4769671f3fd437edcff7e7ea05156bbcb45d) ) // All sprite data matches the Japanese set
@@ -3729,7 +3729,7 @@ GAME( 1986, lastmisnu5, lastmisn, lastmisn, lastmisn, dec8_state, init_dec8,
GAME( 1986, lastmisnj, lastmisn, lastmisn, lastmisnj, dec8_state, init_dec8, ROT270, "Data East Corporation", "Last Mission (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1986, shackled, 0, shackled, shackled, dec8_state, init_dec8, ROT0, "Data East USA", "Shackled (US)", MACHINE_SUPPORTS_SAVE )
GAME( 1986, breywood, shackled, shackled, breywood, dec8_state, init_dec8, ROT0, "Data East Corporation", "Breywood (Japan revision 2)", MACHINE_SUPPORTS_SAVE )
-GAME( 1987, gondo, 0, gondo, gondo, dec8_state, init_dec8, ROT270, "Data East Corporation", "Gondomania (World)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // i8751 protection MCU not dumped
+GAME( 1987, gondo, 0, gondo, gondo, dec8_state, init_dec8, ROT270, "Data East Corporation", "Gondomania (World)", MACHINE_SUPPORTS_SAVE )
GAME( 1987, gondou, gondo, gondo, gondo, dec8_state, init_dec8, ROT270, "Data East USA", "Gondomania (US)", MACHINE_SUPPORTS_SAVE )
GAME( 1987, makyosen, gondo, gondo, gondo, dec8_state, init_dec8, ROT270, "Data East Corporation", "Makyou Senshi (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1987, garyoret, 0, garyoret, garyoret, dec8_state, init_dec8, ROT0, "Data East Corporation", "Garyo Retsuden (Japan)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/deco_mlc.cpp b/src/mame/drivers/deco_mlc.cpp
index c74c7a8aaf8..5154be2e8c6 100644
--- a/src/mame/drivers/deco_mlc.cpp
+++ b/src/mame/drivers/deco_mlc.cpp
@@ -92,13 +92,14 @@
Driver TODO:
stadhr96 - protection? issues (or 156 co-processor? or timing?)
avengrgs - doesn't generate enough line interrupts?
- ddream95 seems to have a dual screen mode(??)
- skullfng - slowdowns not verified from real PCB, Random hangs sometimes
+ ddream95 - seems to have a dual screen mode(??)
+ skullfng - slowdowns not verified from real PCB, random hangs sometimes
Graphic TODO:
- blending, raster effect features isn't fully emulated, verified currently
- Not verified : Can sprites effect 8bpp and shadowing simultaneously?
- Not verified what palette highest bits actually doing
+ blending, raster effect features aren't fully emulated, verified currently
+ Not verified : Can sprites affect 8bpp and shadowing simultaneously?
+ Not verified what palette highest bits actually do
+ Zoom algorithm is incorrect/unverified, reference: https://www.youtube.com/watch?v=eCwAVt0GbhQ
Driver by Bryan McPhail, bmcphail@tendril.co.uk, thank you to Avedis and The Guru.
@@ -186,7 +187,7 @@ void deco_mlc_state::eeprom_w(offs_t offset, u32 data, u32 mem_mask)
}
else if (ACCESSING_BITS_0_7)
{
- /* Master volume control (TODO: probably logaritmic) */
+ // Master volume control (TODO: probably logarithmic)
m_ymz->set_output_gain(0, (255.0 - data) / 255.0);
m_ymz->set_output_gain(1, (255.0 - data) / 255.0);
}
@@ -206,14 +207,14 @@ void deco_mlc_state::irq_ram_w(offs_t offset, u32 data, u32 mem_mask)
COMBINE_DATA(&m_irq_ram[offset]);
/*
- TODO : Accurate this from real PCB
- Word 0 : Used but Unknown
+ TODO : Verify this on real PCB
+ Word 0 : Used but unknown
skullfng : 0x00000cf3
hoops** : 0xffffdfff
avengrgs : 0x00000cd3
stadhr96 : 0x000028f3
- Word 1 : 0xc0 at shadow, 0x00 at alpha, Other bits unknown
+ Word 1 : 0xc0 at shadow, 0x00 at alpha, other bits unknown
skullfng : 0x000000c0 or 0x00000000
hoops** : 0xfffffffc
avengrgs : 0xffffffff
@@ -230,10 +231,10 @@ void deco_mlc_state::irq_ram_w(offs_t offset, u32 data, u32 mem_mask)
switch (offset * 4)
{
- case 0x10: /* IRQ ack. Value written doesn't matter */
+ case 0x10: // IRQ ack. Value written doesn't matter
m_maincpu->set_input_line(m_irqLevel, CLEAR_LINE);
return;
- case 0x14: /* Prepare scanline interrupt */
+ case 0x14: // Prepare scanline interrupt
if(m_irq_ram[0x14 / 4] == -1) // TODO: likely to be anything that doesn't fit into the screen v-pos range.
m_raster_irq_timer->adjust(attotime::never);
else
@@ -323,7 +324,7 @@ void deco_mlc_state::avengrgs_map(address_map &map)
map(0x0600000, 0x0600007).rw(m_ymz, FUNC(ymz280b_device::read), FUNC(ymz280b_device::write)).umask32(0xff000000).mirror(0xff000000);
}
-void deco_mlc_state::decomlc_map(address_map &map)
+void deco_mlc_state::decomlc_no146_map(address_map &map)
{
map(0x0000000, 0x00fffff).rom();
map(0x0100000, 0x011ffff).ram().share("mainram");
@@ -344,6 +345,12 @@ void deco_mlc_state::decomlc_map(address_map &map)
map(0x044001c, 0x044001f).rw(FUNC(deco_mlc_state::mlc_44001c_r), FUNC(deco_mlc_state::mlc_44001c_w));
map(0x0500000, 0x0500003).w(FUNC(deco_mlc_state::eeprom_w));
map(0x0600000, 0x0600007).rw(m_ymz, FUNC(ymz280b_device::read), FUNC(ymz280b_device::write)).umask32(0xff000000);
+}
+
+void deco_mlc_state::decomlc_146_map(address_map &map)
+{
+ decomlc_no146_map(map);
+
map(0x070f000, 0x070ffff).rw(FUNC(deco_mlc_state::sh96_protection_region_0_146_r), FUNC(deco_mlc_state::sh96_protection_region_0_146_w)).umask32(0xffff0000);
}
@@ -494,6 +501,18 @@ static const gfx_layout spritelayout_6bpp =
16*32
};
+static const gfx_layout spritelayout_acchi =
+{
+ 16,16,
+ RGN_FRAC(1,5),
+ 5,
+ { RGN_FRAC(0,5), RGN_FRAC(1,5), RGN_FRAC(2,5), RGN_FRAC(3,5), RGN_FRAC(4,5) },
+ { 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 },
+ { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16,
+ 8*16, 9*16, 10*16, 11*16, 12*16, 13*16, 14*16, 15*16 },
+ 16*16
+};
+
static GFXDECODE_START( gfx_deco_mlc )
GFXDECODE_ENTRY( "gfx1", 0, spritelayout_4bpp, 0, 256 )
GFXDECODE_END
@@ -506,6 +525,10 @@ static GFXDECODE_START( gfx_6bpp )
GFXDECODE_ENTRY( "gfx1", 0, spritelayout_6bpp, 0, 64 )
GFXDECODE_END
+static GFXDECODE_START( gfx_acchi )
+ GFXDECODE_ENTRY( "gfx1", 0, spritelayout_acchi, 0, 64 )
+GFXDECODE_END
+
/******************************************************************************/
void deco_mlc_state::machine_reset()
@@ -515,15 +538,15 @@ void deco_mlc_state::machine_reset()
void deco_mlc_state::avengrgs(machine_config &config)
{
- /* basic machine hardware */
- SH2(config, m_maincpu, 42000000/2); /* 21 MHz clock confirmed on real board */
+ // basic machine hardware
+ SH2(config, m_maincpu, 42000000/2); // 21 MHz clock confirmed on real board
m_maincpu->set_addrmap(AS_PROGRAM, &deco_mlc_state::avengrgs_map);
- EEPROM_93C46_16BIT(config, m_eeprom); /* Actually 93c45 */
+ EEPROM_93C46_16BIT(config, m_eeprom); // Actually 93c45
TIMER(config, m_raster_irq_timer).configure_generic(FUNC(deco_mlc_state::interrupt_gen));
- /* video hardware */
+ // video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(58);
m_screen->set_size(40*8, 32*8);
@@ -536,7 +559,7 @@ void deco_mlc_state::avengrgs(machine_config &config)
PALETTE(config, m_palette).set_format(palette_device::xBGR_555, 2048);
m_palette->set_membits(16);
- /* sound hardware */
+ // sound hardware
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
@@ -547,15 +570,15 @@ void deco_mlc_state::avengrgs(machine_config &config)
void deco_mlc_state::mlc(machine_config &config)
{
- /* basic machine hardware */
- ARM(config, m_maincpu, 42000000/6); /* 42 MHz -> 7MHz clock confirmed on real board */
- m_maincpu->set_addrmap(AS_PROGRAM, &deco_mlc_state::decomlc_map);
+ // basic machine hardware
+ ARM(config, m_maincpu, 42000000/6); // 42 MHz -> 7MHz clock confirmed on real board
+ m_maincpu->set_addrmap(AS_PROGRAM, &deco_mlc_state::decomlc_no146_map);
- EEPROM_93C46_16BIT(config, m_eeprom); /* Actually 93c45 */
+ EEPROM_93C46_16BIT(config, m_eeprom); // Actually 93c45
TIMER(config, m_raster_irq_timer).configure_generic(FUNC(deco_mlc_state::interrupt_gen));
- /* video hardware */
+ // video hardware
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(58);
m_screen->set_size(40*8, 32*8);
@@ -568,10 +591,7 @@ void deco_mlc_state::mlc(machine_config &config)
PALETTE(config, m_palette).set_format(palette_device::xBGR_555, 2048);
m_palette->set_membits(16);
- DECO146PROT(config, m_deco146, 0);
- m_deco146->set_use_magic_read_address_xor(true);
-
- /* sound hardware */
+ // sound hardware
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
@@ -598,6 +618,23 @@ void deco_mlc_state::mlc_5bpp(machine_config &config)
m_ymz->add_route(0, "rspeaker", 1.0);
}
+void deco_mlc_state::stadhr96(machine_config &config)
+{
+ mlc_6bpp(config);
+
+ m_maincpu->set_addrmap(AS_PROGRAM, &deco_mlc_state::decomlc_146_map);
+
+ DECO146PROT(config, m_deco146, 0);
+ m_deco146->set_use_magic_read_address_xor(true);
+}
+
+void deco_mlc_state::acchi(machine_config &config)
+{
+ mlc(config);
+
+ m_gfxdecode->set_info(gfx_acchi);
+}
+
/***************************************************************************/
/*
@@ -680,8 +717,8 @@ ROM_END
ROM_START( stadhr96 )
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD32_WORD( "sh-eaj.2a", 0x000000, 0x80000, CRC(10d1496a) SHA1(1dc151547463a38d717159b3dfce7ffd78a943ad) ) /* FRI SEP 20 14:32:35 JST 1996 */
- ROM_LOAD32_WORD( "sh-eaj.2b", 0x000002, 0x80000, CRC(608a9144) SHA1(15e2fa99dc96e8ebd9868713ae7708cb824fc6c5) ) /* EUROPE (DISTRIBUTED) */
+ ROM_LOAD32_WORD( "sh-eaj.2a", 0x000000, 0x80000, CRC(10d1496a) SHA1(1dc151547463a38d717159b3dfce7ffd78a943ad) ) // FRI SEP 20 14:32:35 JST 1996
+ ROM_LOAD32_WORD( "sh-eaj.2b", 0x000002, 0x80000, CRC(608a9144) SHA1(15e2fa99dc96e8ebd9868713ae7708cb824fc6c5) ) // EUROPE (DISTRIBUTED)
ROM_REGION( 0x1800000, "gfx1", 0 )
ROM_LOAD16_BYTE( "mcm-00.2e", 0x0000001, 0x400000, CRC(c1919c3c) SHA1(168000ff1512a147d7029ee8878dd70de680fb08) )
@@ -703,8 +740,8 @@ ROM_END
ROM_START( stadhr96u )
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD32_WORD( "eah00-0.2a", 0x000000, 0x80000, CRC(f45b2ca0) SHA1(442dbfea97abb98451b323986878504ac0370e85) ) /* FRI SEP 20 14:01:45 JST 1996 */
- ROM_LOAD32_WORD( "eah01-0.2b", 0x000002, 0x80000, CRC(328a2bca) SHA1(7e398b48719e5d71b2212d5b65be667e20663589) ) /* U.S.A. */
+ ROM_LOAD32_WORD( "eah00-0.2a", 0x000000, 0x80000, CRC(f45b2ca0) SHA1(442dbfea97abb98451b323986878504ac0370e85) ) // FRI SEP 20 14:01:45 JST 1996
+ ROM_LOAD32_WORD( "eah01-0.2b", 0x000002, 0x80000, CRC(328a2bca) SHA1(7e398b48719e5d71b2212d5b65be667e20663589) ) // U.S.A.
ROM_REGION( 0x1800000, "gfx1", 0 )
ROM_LOAD16_BYTE( "mcm-00.2e", 0x0000001, 0x400000, CRC(c1919c3c) SHA1(168000ff1512a147d7029ee8878dd70de680fb08) )
@@ -726,8 +763,8 @@ ROM_END
ROM_START( stadhr96j )
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD32_WORD( "ead00-4.2a", 0x000000, 0x80000, CRC(b0adfc39) SHA1(3094dfb7c7f8fa9d7e10d98dff8fb8aba285d710) ) /* WED SEP 5 00:00:00 JST 1996 (FINAL) */
- ROM_LOAD32_WORD( "ead01-4.2b", 0x000002, 0x80000, CRC(0b332820) SHA1(28b757fe529250711fcb82424ba63c222a9329b9) ) /* JAPAN */
+ ROM_LOAD32_WORD( "ead00-4.2a", 0x000000, 0x80000, CRC(b0adfc39) SHA1(3094dfb7c7f8fa9d7e10d98dff8fb8aba285d710) ) // WED SEP 5 00:00:00 JST 1996 (FINAL)
+ ROM_LOAD32_WORD( "ead01-4.2b", 0x000002, 0x80000, CRC(0b332820) SHA1(28b757fe529250711fcb82424ba63c222a9329b9) ) // JAPAN
ROM_REGION( 0x1800000, "gfx1", 0 )
ROM_LOAD16_BYTE( "mcm-00.2e", 0x0000001, 0x400000, CRC(c1919c3c) SHA1(168000ff1512a147d7029ee8878dd70de680fb08) )
@@ -913,11 +950,37 @@ ROM_START( skullfnga )
ROM_LOAD( "skullfng.eeprom", 0x00, 0x80, CRC(240d882e) SHA1(3c1a15ccac91d95b02a8c54b051aa64ff28ce2ab) )
ROM_END
+ROM_START( acchi ) // DE-0444-1 + DE-0457-0
+ ROM_REGION( 0x100000, "maincpu", 0 )
+ ROM_LOAD32_WORD( "eaa-00-3.l10", 0x000000, 0x80000, CRC(faff1710) SHA1(b28d210b16b7a0a818ecfeb59696b093be27dc2b) )
+ ROM_LOAD32_WORD( "eaa-01-3.l11", 0x000002, 0x80000, CRC(00510371) SHA1(1beef396065c10e5f16b80a92d960abcd4838363) )
+
+ ROM_REGION( 0x1400000, "gfx1", 0 )
+ ROM_LOAD16_BYTE( "faa-09-0.c2", 0x0000000, 0x200000, CRC(b616058f) SHA1(9dd8f259f08b76e177fc2a266159e4a716b5f4c6) )
+ ROM_LOAD16_BYTE( "faa-08-0.c1", 0x0000001, 0x200000, CRC(70ba2149) SHA1(fbcf7c65021e55ed74b0333852860bfb56f05cab) )
+ ROM_LOAD16_BYTE( "faa-07-0.h2", 0x0400000, 0x200000, CRC(60028a62) SHA1(883935cb5421b344c9a83665a6bbdcff4986f1e7) )
+ ROM_LOAD16_BYTE( "faa-05-0.h1", 0x0400001, 0x200000, CRC(1e7a7a0a) SHA1(09333289177aa102ca082f55d27c453037769b4c) )
+ ROM_LOAD16_BYTE( "faa-06-0.f2", 0x0800000, 0x200000, CRC(5538ff81) SHA1(f68369a0ee25fe5ac3ce5f36c56ca72e46a08279) )
+ ROM_LOAD16_BYTE( "faa-04-0.f1", 0x0800001, 0x200000, CRC(35280765) SHA1(9dcee2724f16fa5c371bf89a4257bbb7eb25f733) )
+ ROM_LOAD16_BYTE( "faa-03-0.e2", 0x0c00000, 0x200000, CRC(af457714) SHA1(dcb94ac0cc632a9d84bb896588f33b47bf87a695) )
+ ROM_LOAD16_BYTE( "faa-01-0.e1", 0x0c00001, 0x200000, CRC(a245270b) SHA1(a2279af96878fb099f8c1e67c2ecf3d0254b36a3) )
+ ROM_LOAD16_BYTE( "faa-02-0.b2", 0x1000000, 0x200000, CRC(bdf75bd6) SHA1(f271192a851e3750beeea6033dc43df614967de1) )
+ ROM_LOAD16_BYTE( "faa-00-0.b1", 0x1000001, 0x200000, CRC(2cf34cd6) SHA1(4d96ca597ad84bedabf53dc17a976f0d95ab99b4) )
+ // there are two unpopulated IC spaces at d1 and d2
+
+ ROM_REGION( 0x80000, "gfx2", 0 )
+ ROM_LOAD( "eaa-02-0.l12", 0x000000, 0x80000, CRC(09baf624) SHA1(548269cead3204c6d269955f5b91937a231bd6af) )
+
+ ROM_REGION( 0x400000, "ymz", ROMREGION_ERASE00 )
+ ROM_LOAD( "faa-10-0.a5", 0x000000, 0x200000, CRC(9f280e5f) SHA1(47c3532b4142ff677f4f0b763ba142883ba3d545) )
+ ROM_LOAD( "faa-11-0.a7", 0x200000, 0x200000, CRC(3775ae66) SHA1(28208d6fee4bf638545dc6b002c900dbb7ab85b0) )
+ROM_END
+
/***************************************************************************/
void deco_mlc_state::descramble_sound( )
{
- /* the same as simpl156 / heavy smash? */
+ // the same as simpl156 / heavy smash?
u8 *rom = memregion("ymz")->base();
int length = memregion("ymz")->bytes();
std::vector<u8> buf(length);
@@ -978,17 +1041,26 @@ void deco_mlc_state::init_mlc()
descramble_sound();
}
+void deco_mlc_state::init_acchi() // sound ROMs don't appear to be scrambled
+{
+ m_maincpu->set_clock_scale(2.0f); // avoids hangs in attract mode / end of round, see init_mlc()
+ m_irqLevel = ARM_IRQ_LINE;
+ deco156_decrypt(machine());
+}
+
+
/***************************************************************************/
-GAME( 1995, avengrgs, 0, avengrgs, mlc, deco_mlc_state, init_avengrgs, ROT0, "Data East Corporation", "Avengers In Galactic Storm (US/Europe 1.0)", MACHINE_IMPERFECT_GRAPHICS )
-GAME( 1995, avengrgsj, avengrgs, avengrgs, mlc, deco_mlc_state, init_avengrgs, ROT0, "Data East Corporation", "Avengers In Galactic Storm (Japan 1.2)", MACHINE_IMPERFECT_GRAPHICS )
-GAME( 1996, stadhr96, 0, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (Europe, EAJ)", MACHINE_IMPERFECT_GRAPHICS ) // Rom labels are EAJ ^^
-GAME( 1996, stadhr96u, stadhr96, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (USA, EAH)", MACHINE_IMPERFECT_GRAPHICS ) // Rom labels are EAH ^^
-GAME( 1996, stadhr96j, stadhr96, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (Japan, EAD)", MACHINE_IMPERFECT_GRAPHICS ) // Rom labels are EAD (this isn't a Konami region code!)
-GAME( 1996, stadhr96j2,stadhr96, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (Japan?, EAE)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) // Rom labels are EAE ^^
-GAME( 1996, skullfng, 0, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT270, "Data East Corporation", "Skull Fang (Europe 1.13)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) /* Version 1.13, Europe, Master 96.02.19 13:45 */
-GAME( 1996, skullfngj, skullfng, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT270, "Data East Corporation", "Skull Fang (Japan 1.09)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) /* Version 1.09, Japan, Master 96.02.08 14:39 */
-GAME( 1996, skullfnga, skullfng, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT270, "Data East Corporation", "Skull Fang (Asia 1.13)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) /* Version 1.13, Asia, Master 96.02.19 13:49 */
-GAME( 1996, hoops96, 0, mlc_5bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Hoops '96 (Europe/Asia 2.0)", MACHINE_IMPERFECT_GRAPHICS )
-GAME( 1995, ddream95, hoops96, mlc_5bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Dunk Dream '95 (Japan 1.4, EAM)", MACHINE_IMPERFECT_GRAPHICS )
-GAME( 1995, hoops95, hoops96, mlc_5bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Hoops (Europe/Asia 1.7)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, avengrgs, 0, avengrgs, mlc, deco_mlc_state, init_avengrgs, ROT0, "Data East Corporation", "Avengers In Galactic Storm (US/Europe 1.0)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, avengrgsj, avengrgs, avengrgs, mlc, deco_mlc_state, init_avengrgs, ROT0, "Data East Corporation", "Avengers In Galactic Storm (Japan 1.2)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1996, stadhr96, 0, stadhr96, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (Europe, EAJ)", MACHINE_IMPERFECT_GRAPHICS ) // Rom labels are EAJ ^^
+GAME( 1996, stadhr96u, stadhr96, stadhr96, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (USA, EAH)", MACHINE_IMPERFECT_GRAPHICS ) // Rom labels are EAH ^^
+GAME( 1996, stadhr96j, stadhr96, stadhr96, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (Japan, EAD)", MACHINE_IMPERFECT_GRAPHICS ) // Rom labels are EAD (this isn't a Konami region code!)
+GAME( 1996, stadhr96j2, stadhr96, stadhr96, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Stadium Hero '96 (Japan?, EAE)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) // Rom labels are EAE ^^
+GAME( 1996, skullfng, 0, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT270, "Data East Corporation", "Skull Fang (Europe 1.13)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) // Version 1.13, Europe, Master 96.02.19 13:45
+GAME( 1996, skullfngj, skullfng, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT270, "Data East Corporation", "Skull Fang (Japan 1.09)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) // Version 1.09, Japan, Master 96.02.08 14:39
+GAME( 1996, skullfnga, skullfng, mlc_6bpp, mlc, deco_mlc_state, init_mlc, ROT270, "Data East Corporation", "Skull Fang (Asia 1.13)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING ) // Version 1.13, Asia, Master 96.02.19 13:49
+GAME( 1996, hoops96, 0, mlc_5bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Hoops '96 (Europe/Asia 2.0)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, ddream95, hoops96, mlc_5bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Dunk Dream '95 (Japan 1.4, EAM)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, hoops95, hoops96, mlc_5bpp, mlc, deco_mlc_state, init_mlc, ROT0, "Data East Corporation", "Hoops (Europe/Asia 1.7)", MACHINE_IMPERFECT_GRAPHICS )
+GAME( 1995, acchi, 0, acchi, mlc, deco_mlc_state, init_acchi, ROT0, "Data East Corporation", "Janken Game Acchi Muite Hoi! (Japan 1.3)", MACHINE_IMPERFECT_GRAPHICS )
diff --git a/src/mame/drivers/decstation.cpp b/src/mame/drivers/decstation.cpp
index 36125d8c584..aa0ecc18f17 100644
--- a/src/mame/drivers/decstation.cpp
+++ b/src/mame/drivers/decstation.cpp
@@ -171,17 +171,14 @@ void decstation_state::video_start()
uint32_t decstation_state::kn01_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- uint32_t *scanline;
- int x, y;
- uint8_t pixels;
- uint8_t *vram = (uint8_t *)m_kn01vram.target();
+ uint8_t const *const vram = (uint8_t *)m_kn01vram.target();
- for (y = 0; y < 864; y++)
+ for (int y = 0; y < 864; y++)
{
- scanline = &bitmap.pix32(y);
- for (x = 0; x < 1024; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1024; x++)
{
- pixels = vram[(y * 1024) + x];
+ uint8_t const pixels = vram[(y * 1024) + x];
*scanline++ = m_palette[pixels];
}
}
diff --git a/src/mame/drivers/decwritr.cpp b/src/mame/drivers/decwritr.cpp
index b5b32b2ee71..84133c2e05c 100644
--- a/src/mame/drivers/decwritr.cpp
+++ b/src/mame/drivers/decwritr.cpp
@@ -19,7 +19,7 @@
#include "machine/i8251.h"
#include "machine/input_merger.h"
#include "sound/beep.h"
-#include "render.h"
+#include "screen.h"
#include "speaker.h"
diff --git a/src/mame/drivers/destroyr.cpp b/src/mame/drivers/destroyr.cpp
index 8d328ae2003..fd863440050 100644
--- a/src/mame/drivers/destroyr.cpp
+++ b/src/mame/drivers/destroyr.cpp
@@ -174,7 +174,7 @@ uint32_t destroyr_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
for (int i = 0; i < 256; i++)
{
if (i & 4)
- bitmap.pix16(m_cursor ^ 0xff, i) = 7;
+ bitmap.pix(m_cursor ^ 0xff, i) = 7;
}
return 0;
}
diff --git a/src/mame/drivers/dgpix.cpp b/src/mame/drivers/dgpix.cpp
index 29484abd2d0..e06bdcb99b2 100644
--- a/src/mame/drivers/dgpix.cpp
+++ b/src/mame/drivers/dgpix.cpp
@@ -419,8 +419,8 @@ u32 dgpix_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, cons
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
int x = cliprect.left();
- u16 *src = &m_vram[(m_vbuffer ? 0 : 0x20000) | (y << 9) | x];
- u16 *dest = &bitmap.pix16(y, x);
+ u16 const *src = &m_vram[(m_vbuffer ? 0 : 0x20000) | (y << 9) | x];
+ u16 *dest = &bitmap.pix(y, x);
for (; x <= cliprect.right(); x++)
{
diff --git a/src/mame/drivers/dim68k.cpp b/src/mame/drivers/dim68k.cpp
index ebb3ce6763d..b2937aaef95 100644
--- a/src/mame/drivers/dim68k.cpp
+++ b/src/mame/drivers/dim68k.cpp
@@ -234,20 +234,20 @@ void dim68k_state::machine_reset()
// Text-only; graphics isn't emulated yet. Need to find out if hardware cursor is used.
MC6845_UPDATE_ROW( dim68k_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx,x,xx,inv;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint16_t chr16=0x2020; // set to spaces if screen is off
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
u8 screen_on = ~m_video_control & 4;
u8 dot8 = ~m_video_control & 40;
// need to divide everything in half to cater for 16-bit reads
x_count /= 2;
ma /= 2;
- xx = 0;
+ u8 xx = 0;
- for (x = 0; x < x_count; x++)
+ for (u8 x = 0; x < x_count; x++)
{
+ u8 inv, chr, gfx;
if (screen_on)
chr16 = m_ram[ma+x]; // reads 2 characters
diff --git a/src/mame/drivers/dkmb.cpp b/src/mame/drivers/dkmb.cpp
index 5a83f16b125..715c0c03bbb 100644
--- a/src/mame/drivers/dkmb.cpp
+++ b/src/mame/drivers/dkmb.cpp
@@ -67,11 +67,11 @@ uint32_t dkmb_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
int count = 0;
for (int y = 0; y < 256; y++)
{
- uint32_t* dst = &bitmap.pix32(y);
+ uint32_t *const dst = &bitmap.pix(y);
for (int x = 0; x < 1024 / 2; x++)
{
- uint64_t val = m_framebuffer[count];
+ uint64_t const val = m_framebuffer[count];
dst[(x * 2) + 0] = (val >> 32) & 0x00ffffff;
dst[(x * 2) + 1] = (val >> 0) & 0x00ffffff;
diff --git a/src/mame/drivers/dlair.cpp b/src/mame/drivers/dlair.cpp
index b914c58b35c..496ad516322 100644
--- a/src/mame/drivers/dlair.cpp
+++ b/src/mame/drivers/dlair.cpp
@@ -46,7 +46,6 @@
#include "sound/ay8910.h"
#include "sound/spkrdev.h"
#include "emupal.h"
-#include "render.h"
#include "speaker.h"
#include "dlair.lh"
diff --git a/src/mame/drivers/dmv.cpp b/src/mame/drivers/dmv.cpp
index ced56a6fb8c..ba0a6881739 100644
--- a/src/mame/drivers/dmv.cpp
+++ b/src/mame/drivers/dmv.cpp
@@ -315,17 +315,17 @@ UPD7220_DISPLAY_PIXELS_MEMBER( dmv_state::hgdc_display_pixels )
for(int xi=0; xi<16; xi++)
{
- int r = ((red >> xi) & 1) ? 255 : 0;
- int g = ((green >> xi) & 1) ? 255 : 0;
- int b = ((blue >> xi) & 1) ? 255 : 0;
+ int r = BIT(red, xi) ? 255 : 0;
+ int g = BIT(green, xi) ? 255 : 0;
+ int b = BIT(blue, xi) ? 255 : 0;
if (bitmap.cliprect().contains(x + xi, y))
- bitmap.pix32(y, x + xi) = rgb_t(r, g, b);
+ bitmap.pix(y, x + xi) = rgb_t(r, g, b);
}
}
else
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
// 32KB videoram
uint16_t gfx = m_video_ram[(address & 0xffff) >> 1];
@@ -333,7 +333,7 @@ UPD7220_DISPLAY_PIXELS_MEMBER( dmv_state::hgdc_display_pixels )
for(int xi=0;xi<16;xi++)
{
if (bitmap.cliprect().contains(x + xi, y))
- bitmap.pix32(y, x + xi) = ((gfx >> xi) & 1) ? palette[2] : palette[0];
+ bitmap.pix(y, x + xi) = ((gfx >> xi) & 1) ? palette[2] : palette[0];
}
}
}
@@ -367,18 +367,17 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( dmv_state::hgdc_draw_text )
for( int xi = 0; xi < 8; xi++)
{
- int res_x,res_y;
int pen = (tile_data >> xi) & 1 ? 1 : 0;
- res_x = x * 8 + xi;
- res_y = y + yi;
+ int res_x = x * 8 + xi;
+ int res_y = y + yi;
if(!m_screen->visible_area().contains(res_x, res_y))
continue;
if(yi >= 16) { pen = 0; }
- bitmap.pix32(res_y, res_x) = pen ? fg : bg;
+ bitmap.pix(res_y, res_x) = pen ? fg : bg;
}
}
}
diff --git a/src/mame/drivers/dolphunk.cpp b/src/mame/drivers/dolphunk.cpp
index 94a05ae39ce..ae6cd62068b 100644
--- a/src/mame/drivers/dolphunk.cpp
+++ b/src/mame/drivers/dolphunk.cpp
@@ -2,51 +2,51 @@
// copyright-holders:Robbbert
/***************************************************************************
- Dolphin / Dauphin
-
- 2010-04-08 Skeleton driver.
- 2012-05-20 Fixed keyboard, added notes & speaker [Robbbert]
- 2013-11-03 Added cassette [Robbbert]
-
- Minimal Setup:
- 0000-00FF ROM "MO" (74S471)
- 0100-01FF ROM "MONI" (74S471)
- 0200-02FF RAM (2x 2112)
- 18 pushbuttons for programming (0-F, ADR, NXT).
- 4-digit LED display.
-
- Other options:
- 0400-07FF Expansion RAM (8x 2112)
- 0800-08FF Pulse for operation of an optional EPROM programmer
- 0C00-0FFF ROM "MONA" (2708)
- LEDs connected to all Address and Data Lines
- LEDs connected to WAIT and FLAG lines.
- Speaker with a LED wired across it.
- PAUSE switch.
- RUN/STOP switch.
- STEP switch.
- CLOCK switch.
-
- Cassette player connected to SENSE and FLAG lines.
-
- Keyboard encoder: AY-5-2376 (57 keys)
-
- CRT interface: (512 characters on a separate bus)
- 2114 video ram (one half holds the lower 4 data bits, other half the upper bits)
- 74LS175 holds the upper bits for the 74LS472
- 74LS472 Character Generator
-
- NOTE: a rom is missing, when the ADR button (- key) is pressed,
- it causes a freeze in nodebug mode, and a crash in debug mode.
- To see it, start in debug mode. g 6c. In the emulation, press the
- minus key. The debugger will stop and you can see an instruction
- referencing location 0100, which is in the missing rom.
-
- Keys:
- 0-9,A-F hexadecimal numbers
- UP - (NXT) to enter data and advance to the next address
- MINUS - (ADR) to change the address to what is shown in the data side
- Special keys:
+Dolphin / Dauphin
+
+2010-04-08 Skeleton driver.
+2012-05-20 Fixed keyboard, added notes & speaker [Robbbert]
+2013-11-03 Added cassette [Robbbert]
+
+Minimal Setup:
+ 0000-00FF ROM "MO" (74S471)
+ 0100-01FF ROM "MONI" (74S471)
+ 0200-02FF RAM (2x 2112)
+ 18 pushbuttons for programming (0-F, ADR, NXT).
+ 4-digit LED display.
+
+Other options:
+ 0400-07FF Expansion RAM (8x 2112)
+ 0800-08FF Pulse for operation of an optional EPROM programmer
+ 0C00-0FFF ROM "MONA" (2708)
+ LEDs connected to all Address and Data Lines
+ LEDs connected to WAIT and FLAG lines.
+ Speaker with a LED wired across it.
+ PAUSE switch.
+ RUN/STOP switch.
+ STEP switch.
+ CLOCK switch.
+
+Cassette player connected to SENSE and FLAG lines.
+
+Keyboard encoder: AY-5-2376 (57 keys)
+
+CRT interface: (512 characters on a separate bus)
+ 2114 video ram (one half holds the lower 4 data bits, other half the upper bits)
+ 74LS175 holds the upper bits for the 74LS472
+ 74LS472 Character Generator
+
+NOTE: a rom is missing, when the ADR button (- key) is pressed,
+ it causes a freeze in nodebug mode, and a crash in debug mode.
+ To see it, start in debug mode. g 6c. In the emulation, press the
+ minus key. The debugger will stop and you can see an instruction
+ referencing location 0100, which is in the missing rom.
+
+Keys:
+ 0-9,A-F hexadecimal numbers
+ UP - (NXT) to enter data and advance to the next address
+ MINUS - (ADR) to change the address to what is shown in the data side
+ Special keys:
Hold UP, hold 0, release UP, release 0 - execute program at the current address (i.e. 2xx)
Hold UP, hold 1, release UP, release 1 - execute program at address 0C00 (rom MONA)
Hold UP, hold 2, release UP, release 2 - play a tune with the keys
@@ -54,28 +54,32 @@
Hold MINUS, hold any hex key, release MINUS, release other key - execute program
at the current address-0x100 (i.e. 1xx).
- If you want to scan through other areas of memory (e.g. the roms), alter the
- data at address 2F9 (high byte) and 2FA (low byte).
+If you want to scan through other areas of memory (e.g. the roms), alter the
+data at address 2F9 (high byte) and 2FA (low byte).
- How to Use:
- The red digits are the address, and the orange digits are the data.
- The address range is 200-2FF (the 2 isn't displayed). To select an address,
- either press the UP key until you get there, or type the address and press
- minus. The orange digits show the current data at that address. To alter
- data, just type it in and press UP.
+How to Use:
+ The red digits are the address, and the orange digits are the data.
+ The address range is 200-2FF (the 2 isn't displayed). To select an address,
+ either press the UP key until you get there, or type the address and press
+ minus. The orange digits show the current data at that address. To alter
+ data, just type it in and press UP.
- To play the reflexes game, hold UP, press 1, release UP, release 1.
- The display will show A--0 (or some random number in the last position).
- Press any odd-numbered key (B is convenient), and read off the reaction time.
- After a short delay it will show '--' again, this is the signal to react.
- It doesn't seem to reset the counters each time around.
+To play the reflexes game, hold UP, press 1, release UP, release 1.
+ The display will show A--0 (or some random number in the last position).
+ Press any odd-numbered key (B is convenient), and read off the reaction time.
+ After a short delay it will show '--' again, this is the signal to react.
+ It doesn't seem to reset the counters each time around.
- TODO:
- - Find missing roms
- - Add optional hardware listed above
- - Cassette is added, but no idea how to operate it.
+Test Paste:
+ Paste this: 11^22^33^44^55^66^77^88^99^00-
+ Now press up-arrow to review the data that was entered.
- Thanks to Amigan site for various documents.
+TODO:
+ - Find missing roms
+ - Add optional hardware listed above
+ - Cassette is added, but no idea how to operate it.
+
+Thanks to Amigan site for various documents.
****************************************************************************/
diff --git a/src/mame/drivers/dooyong.cpp b/src/mame/drivers/dooyong.cpp
index c1498e8e5ce..c8fc3ac0278 100644
--- a/src/mame/drivers/dooyong.cpp
+++ b/src/mame/drivers/dooyong.cpp
@@ -770,9 +770,9 @@ u32 popbingo_state::screen_update_popbingo(screen_device &screen, bitmap_ind16 &
for (int y = cliprect.top(); cliprect.bottom() >= y; y++)
{
- const u16 *const bg_src(&m_bg_bitmap[0].pix16(y, 0));
- const u16 *const bg2_src(&m_bg_bitmap[1].pix16(y, 0));
- u16 *const dst(&bitmap.pix16(y, 0));
+ const u16 *const bg_src(&m_bg_bitmap[0].pix(y, 0));
+ const u16 *const bg2_src(&m_bg_bitmap[1].pix(y, 0));
+ u16 *const dst(&bitmap.pix(y, 0));
for (int x = cliprect.left(); cliprect.right() >= x; x++)
dst[x] = 0x100U | (bg_src[x] << 4) | bg2_src[x];
}
diff --git a/src/mame/drivers/dorachan.cpp b/src/mame/drivers/dorachan.cpp
index fc0e8a74f96..54820630f8c 100644
--- a/src/mame/drivers/dorachan.cpp
+++ b/src/mame/drivers/dorachan.cpp
@@ -74,8 +74,6 @@ uint32_t dorachan_state::screen_update_dorachan(screen_device &screen, bitmap_rg
{
for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- uint8_t fore_color;
-
uint8_t x = offs >> 8 << 3;
uint8_t y = offs & 0xff;
@@ -84,6 +82,7 @@ uint32_t dorachan_state::screen_update_dorachan(screen_device &screen, bitmap_rg
uint8_t data = m_videoram[offs];
+ uint8_t fore_color;
if (m_flip_screen)
fore_color = (m_colors[color_address] >> 3) & 0x07;
else
@@ -92,7 +91,7 @@ uint32_t dorachan_state::screen_update_dorachan(screen_device &screen, bitmap_rg
for (int i = 0; i < 8; i++)
{
uint8_t color = BIT(data, i) ? fore_color : 0;
- bitmap.pix32(y, x++) = m_palette->pen_color(color);
+ bitmap.pix(y, x++) = m_palette->pen_color(color);
}
}
diff --git a/src/mame/drivers/dotrikun.cpp b/src/mame/drivers/dotrikun.cpp
index 9fb00be2adf..3f56aeafaa1 100644
--- a/src/mame/drivers/dotrikun.cpp
+++ b/src/mame/drivers/dotrikun.cpp
@@ -130,7 +130,7 @@ uint32_t dotrikun_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
if ((x & 7) == 0)
m_vram_latch = m_vram[x >> 3 | y >> 1 << 4];
- bitmap.pix16(y, x) = (m_vram_latch >> (~x & 7) & 1) ? m_color & 7 : m_color >> 3;
+ bitmap.pix(y, x) = (m_vram_latch >> (~x & 7) & 1) ? m_color & 7 : m_color >> 3;
}
}
diff --git a/src/mame/drivers/dpb7000.cpp b/src/mame/drivers/dpb7000.cpp
index 1179cf9a0aa..87b278a2638 100644
--- a/src/mame/drivers/dpb7000.cpp
+++ b/src/mame/drivers/dpb7000.cpp
@@ -47,8 +47,8 @@
#define LOG_SIZE_CARD (1 << 14)
#define LOG_FILTER_CARD (1 << 15)
#define LOG_KEYBC (1 << 16)
-#define LOG_TDS (1 << 17)
-#define LOG_TABLET (1 << 18)
+#define LOG_TDS (1 << 17)
+#define LOG_TABLET (1 << 18)
#define LOG_ALL (LOG_UNKNOWN | LOG_CSR | LOG_CTRLBUS | LOG_SYS_CTRL | LOG_FDC_CTRL | LOG_FDC_PORT | LOG_FDC_CMD | LOG_FDC_MECH | LOG_BRUSH_ADDR | \
LOG_STORE_ADDR | LOG_COMBINER | LOG_SIZE_CARD | LOG_FILTER_CARD)
@@ -1068,8 +1068,8 @@ void dpb7000_state::device_timer(emu_timer &timer, device_timer_id id, int param
MC6845_UPDATE_ROW(dpb7000_state::crtc_update_row)
{
- const pen_t *pen = m_palette->pens();
- const uint8_t *char_rom = m_vdu_char_rom->base();
+ const pen_t *const pen = m_palette->pens();
+ const uint8_t *const char_rom = m_vdu_char_rom->base();
for (int column = 0; column < x_count; column++)
{
@@ -1087,7 +1087,7 @@ MC6845_UPDATE_ROW(dpb7000_state::crtc_update_row)
int x = (column * 8) + bit;
int color = BIT(data, 7) && de;
- bitmap.pix32(y, x) = pen[color];
+ bitmap.pix(y, x) = pen[color];
data <<= 1;
}
@@ -2396,9 +2396,9 @@ uint32_t dpb7000_state::store_screen_update(screen_device &screen, bitmap_rgb32
{
for (int py = 0; py < 768; py++)
{
- uint8_t *src_lum = &m_framestore_lum[StoreNum][py * 800];
- uint8_t *src_chr = &m_framestore_chr[StoreNum][py * 800];
- uint32_t *dst = &bitmap.pix32(py);
+ const uint8_t *src_lum = &m_framestore_lum[StoreNum][py * 800];
+ const uint8_t *src_chr = &m_framestore_chr[StoreNum][py * 800];
+ uint32_t *dst = &bitmap.pix(py);
for (int px = 0; px < 800; px++)
{
const uint32_t u = *src_chr++ << 16;
@@ -2412,9 +2412,9 @@ uint32_t dpb7000_state::store_screen_update(screen_device &screen, bitmap_rgb32
{
for (int py = 512; py < 768; py++)
{
- uint8_t *src_lum = &m_brushstore_lum[(py - 512) * 256];
- uint8_t *src_chr = &m_brushstore_chr[(py - 512) * 256];
- uint32_t *dst = &bitmap.pix32(py);
+ const uint8_t *src_lum = &m_brushstore_lum[(py - 512) * 256];
+ const uint8_t *src_chr = &m_brushstore_chr[(py - 512) * 256];
+ uint32_t *dst = &bitmap.pix(py);
for (int px = 0; px < 256; px += 2)
{
const uint32_t u = *src_chr++ << 16;
diff --git a/src/mame/drivers/dragon.cpp b/src/mame/drivers/dragon.cpp
index 2e5df2d838f..570716dd2da 100644
--- a/src/mame/drivers/dragon.cpp
+++ b/src/mame/drivers/dragon.cpp
@@ -2,10 +2,12 @@
// copyright-holders:Nathan Woods
/***************************************************************************
- dragon.c
+ dragon.cpp
Dragon
+ Bug? dragon200e hangs when single-quote is typed.
+
***************************************************************************/
#include "emu.h"
@@ -148,9 +150,9 @@ static INPUT_PORTS_START( dragon_keyboard )
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP), '^')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN), 10)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN), 10) PORT_CHAR('[')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(LEFT), 8)
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT), 9)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT), 9) PORT_CHAR(']')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_START("row6")
@@ -174,6 +176,7 @@ static INPUT_PORTS_START( dragon200e_keyboard )
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(';') PORT_CHAR('+')
PORT_MODIFY("row5")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP), '^') PORT_CHAR('_')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("DOWN \xC2\xA1") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(10) PORT_CHAR(0xA1)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("RIGHT \xC2\xBF") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(9) PORT_CHAR(0xBF)
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CHANGED_MEMBER(DEVICE_SELF, dragon_state, keyboard_changed, 0) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_CHAR(0xA7)
diff --git a/src/mame/drivers/drdmania.cpp b/src/mame/drivers/drdmania.cpp
index 7e8c9a9b890..95e66fd299e 100644
--- a/src/mame/drivers/drdmania.cpp
+++ b/src/mame/drivers/drdmania.cpp
@@ -57,6 +57,8 @@
#include "machine/nvram.h"
#include "sound/ay8910.h"
#include "screen.h"
+#include "tilemap.h"
+#include "emupal.h"
#include "speaker.h"
class drdmania_state : public driver_device
@@ -65,39 +67,123 @@ public:
drdmania_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
+ , m_screen(*this, "screen")
+ , m_gfxdecode(*this, "gfxdecode")
+ , m_fgram(*this, "fgram")
{
}
void drdmania(machine_config &config);
+ void init_drdmania();
+
+protected:
+ virtual void video_start() override;
+
private:
void mem_map(address_map &map);
void io_map(address_map &map);
required_device<cpu_device> m_maincpu;
+ required_device<screen_device> m_screen;
+ required_device<gfxdecode_device> m_gfxdecode;
+ required_shared_ptr<uint8_t> m_fgram;
+
+ tilemap_t *m_fg_tilemap;
+
+ uint8_t unk_port00_r();
+
+ void fgram_w(offs_t offset, uint8_t data);
+ TILE_GET_INFO_MEMBER(get_fg_tile_info);
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
};
void drdmania_state::mem_map(address_map &map)
{
- map(0x0000, 0x7fff).rom().region("maincpu", 0);
+ map(0x0000, 0xbfff).rom().region("maincpu", 0x0000);
+
+ map(0xc000, 0xc7ff).ram(); // stack is here, but also writes ASCII strings as if it were a tilemap, but tile ROMs don't decode as ASCII
+ map(0xd000, 0xd3ff).ram().w(FUNC(drdmania_state::fgram_w)).share("fgram"); // vram? fills with value of blank tile
}
+uint8_t drdmania_state::unk_port00_r()
+{
+ return machine().rand();
+}
+
+
void drdmania_state::io_map(address_map &map)
{
+ map(0x00, 0x00).r(FUNC(drdmania_state::unk_port00_r));
+
+ map.global_mask(0xff);
}
static INPUT_PORTS_START(drdmania)
INPUT_PORTS_END
+static const gfx_layout tiles8x8_layout =
+{
+ 8,8,
+ RGN_FRAC(1,3),
+ 3,
+ { RGN_FRAC(0,3), RGN_FRAC(1,3), RGN_FRAC(2,3) },
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8
+};
+
+static GFXDECODE_START( gfxa )
+ GFXDECODE_ENTRY( "gfx1", 0, tiles8x8_layout, 0, 1 )
+GFXDECODE_END
+
+void drdmania_state::fgram_w(offs_t offset, uint8_t data)
+{
+ m_fgram[offset] = data;
+ m_fg_tilemap->mark_tile_dirty(offset);
+}
+
+
+TILE_GET_INFO_MEMBER(drdmania_state::get_fg_tile_info)
+{
+ int code = m_fgram[tile_index];
+ tileinfo.set(0,code,0,0);
+}
+
+
+void drdmania_state::video_start()
+{
+ m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(drdmania_state::get_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
+}
+
+uint32_t drdmania_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+ return 0;
+}
+
+
+
void drdmania_state::drdmania(machine_config &config)
{
Z80(config, m_maincpu, 18.432_MHz_XTAL / 4); // divider not verified
m_maincpu->set_addrmap(AS_PROGRAM, &drdmania_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &drdmania_state::io_map);
+ m_maincpu->set_vblank_int("screen", FUNC(drdmania_state::irq0_line_hold));
//NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // MK48Z02B-20
- //SCREEN(config, "screen", SCREEN_TYPE_RASTER);
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_refresh_hz(60);
+ m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ m_screen->set_size(256, 256);
+ m_screen->set_visarea(0, 256-1, 0, 256-1);
+ m_screen->set_screen_update(FUNC(drdmania_state::screen_update));
+
+ GFXDECODE(config, m_gfxdecode, "palette", gfxa);
+
+ PALETTE(config, "palette").set_format(palette_device::xRGB_444, 0x100).set_endianness(ENDIANNESS_BIG);
SPEAKER(config, "mono").front_center();
@@ -105,17 +191,36 @@ void drdmania_state::drdmania(machine_config &config)
}
ROM_START(drdmania)
- ROM_REGION(0x08000, "maincpu", 0)
+ ROM_REGION(0x0c000, "maincpu", 0)
ROM_LOAD( "dardomania_dmp01_v2.1.ic38", 0x00000, 0x8000, CRC(9f24336f) SHA1(9a82b851d5c67a50118a3669d3bc5793e94219e4) )
-
- ROM_REGION(0x20000, "unsorted", 0)
- ROM_LOAD( "dardomania_dmp02_v2.1.ic33", 0x00000, 0x8000, CRC(e5dbf948) SHA1(241be0f2969b962bba602548dab3e2bdbf8f0696) ) // 1ST AND 2ND HALF IDENTICAL
- ROM_LOAD( "dardomania_dmp03_v2.1.ic21", 0x08000, 0x8000, CRC(b458975e) SHA1(862d62d147ac09b86aa8d2c54b2e03a6c5436f85) ) // 1ST AND 2ND HALF IDENTICAL
- ROM_LOAD( "dardomania_dmp04_v2.1.ic16", 0x10000, 0x8000, CRC(8564d0ba) SHA1(38c81173f1cf788d1a524abfae9ef7b6697383e4) ) // 1ST AND 2ND HALF IDENTICAL
- ROM_LOAD( "dardomania_dmp05_v2.1.ic10", 0x18000, 0x8000, CRC(e24f2a02) SHA1(16f3a9c80b3d60c66b070521a90c958b0fc690e7) ) // 1ST AND 2ND HALF IDENTICAL
+ // seems to have some bad bytes eg rst $08 instructions which should be calls but end up resetting it instead, see init
+ ROM_LOAD( "dardomania_dmp02_v2.1.ic33", 0x08000, 0x4000, BAD_DUMP CRC(e5dbf948) SHA1(241be0f2969b962bba602548dab3e2bdbf8f0696) ) // 1ST AND 2ND HALF IDENTICAL
+ ROM_IGNORE(0x4000)
+
+ ROM_REGION(0xc000, "gfx1", 0)
+ ROM_LOAD( "dardomania_dmp03_v2.1.ic21", 0x00000, 0x4000, CRC(b458975e) SHA1(862d62d147ac09b86aa8d2c54b2e03a6c5436f85) ) // 1ST AND 2ND HALF IDENTICAL
+ ROM_IGNORE(0x4000)
+ ROM_LOAD( "dardomania_dmp04_v2.1.ic16", 0x04000, 0x4000, CRC(8564d0ba) SHA1(38c81173f1cf788d1a524abfae9ef7b6697383e4) ) // 1ST AND 2ND HALF IDENTICAL
+ ROM_IGNORE(0x4000)
+ ROM_LOAD( "dardomania_dmp05_v2.1.ic10", 0x08000, 0x4000, CRC(e24f2a02) SHA1(16f3a9c80b3d60c66b070521a90c958b0fc690e7) ) // 1ST AND 2ND HALF IDENTICAL
+ ROM_IGNORE(0x4000)
ROM_REGION(0x20, "proms", 0)
ROM_LOAD( "n82s123n.ic49", 0x00, 0x20, CRC(dcbd2352) SHA1(ce72e84129ed1b455aaf648e1dfaa4333e7e7628) )
ROM_END
-GAME(1994, drdmania, 0, drdmania, drdmania, drdmania_state, empty_init, ROT0, "Sleic", "Dardomania (v2.1)", MACHINE_IS_SKELETON_MECHANICAL)
+void drdmania_state::init_drdmania()
+{
+ uint8_t *ROM = memregion("maincpu")->base();
+ ROM[0x8de0] ^= 0x02; // these are 0xcf in ROM so bit 0x02 got flipped? 3 calls in a row are incorrect in this way, so call addresses are suspect too
+ ROM[0x8de1] ^= 0x02; // call address
+
+ ROM[0x8de3] ^= 0x02; // call opcode
+
+ ROM[0x8de6] ^= 0x02; // call opcode
+ ROM[0x8de7] ^= 0x02; // call address
+
+ ROM[0x8e00] ^= 0x02; // wrong, different bit flipped?
+}
+
+GAME(1994, drdmania, 0, drdmania, drdmania, drdmania_state, init_drdmania, ROT0, "Sleic", "Dardomania (v2.1)", MACHINE_NOT_WORKING | MACHINE_MECHANICAL )
diff --git a/src/mame/drivers/duet16.cpp b/src/mame/drivers/duet16.cpp
index e2c0f49c303..e008bd8283a 100644
--- a/src/mame/drivers/duet16.cpp
+++ b/src/mame/drivers/duet16.cpp
@@ -111,8 +111,7 @@ void duet16_state::fdcctrl_w(u8 data)
m_fd[0]->get_device()->mon_w(!BIT(data, 0));
m_fd[1]->get_device()->mon_w(!BIT(data, 0));
- if(!BIT(data, 1))
- m_fdc->soft_reset();
+ m_fdc->reset_w(!BIT(data, 1));
// TODO: bit 3 = LSPD
}
@@ -194,7 +193,7 @@ MC6845_UPDATE_ROW(duet16_state::crtc_update_row)
{
if(!de)
return;
- u8 *gvram = (u8 *)&m_gvram[0];
+ u8 const *const gvram = (u8 *)&m_gvram[0];
for(int i = 0; i < x_count; i++)
{
u16 coffset = (ma + i) & 0x07ff;
@@ -235,7 +234,7 @@ MC6845_UPDATE_ROW(duet16_state::crtc_update_row)
color = m_pal->pen_color((BIT(g2, 7 - xi) << 2) | (BIT(g1, 7 - xi) << 1) | BIT(g0, 7 - xi));
else
color = 0;
- bitmap.pix32(y, (i * 8) + xi) = color;
+ bitmap.pix(y, (i * 8) + xi) = color;
}
}
}
diff --git a/src/mame/drivers/dvk_kcgd.cpp b/src/mame/drivers/dvk_kcgd.cpp
index 664a1d83db0..0844a6781e4 100644
--- a/src/mame/drivers/dvk_kcgd.cpp
+++ b/src/mame/drivers/dvk_kcgd.cpp
@@ -307,19 +307,19 @@ void kcgd_state::draw_scanline(uint16_t *p, uint16_t offset)
TIMER_DEVICE_CALLBACK_MEMBER(kcgd_state::scanline_callback)
{
- uint16_t y = m_screen->vpos(), offset;
+ uint16_t y = m_screen->vpos();
if (y < KCGD_VERT_START) return;
y -= KCGD_VERT_START;
if (y >= KCGD_DISP_VERT) return;
- offset = BIT(m_video.status, KCGD_STATUS_PAGE) ? (KCGD_PAGE_1 >> 1) : (KCGD_PAGE_0 >> 1);
+ uint16_t const offset = BIT(m_video.status, KCGD_STATUS_PAGE) ? (KCGD_PAGE_1 >> 1) : (KCGD_PAGE_0 >> 1);
DBG_LOG(2,"scanline_cb", ("frame %d y %.3d page %d offset %04X *offset %04X\n",
m_screen->frame_number(), BIT(m_video.status, KCGD_STATUS_PAGE),
y, offset + y, m_videoram[offset + y]));
- draw_scanline(&m_tmpbmp.pix16(y), m_videoram[offset + (KCGD_DISP_VERT-1) - y]);
+ draw_scanline(&m_tmpbmp.pix(y), m_videoram[offset + (KCGD_DISP_VERT-1) - y]);
}
uint32_t kcgd_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
diff --git a/src/mame/drivers/dvk_ksm.cpp b/src/mame/drivers/dvk_ksm.cpp
index 37dc73a84e8..4a6bc1afa65 100644
--- a/src/mame/drivers/dvk_ksm.cpp
+++ b/src/mame/drivers/dvk_ksm.cpp
@@ -365,7 +365,6 @@ uint32_t ksm_state::draw_scanline(uint16_t *p, uint16_t offset, uint8_t scanline
TIMER_DEVICE_CALLBACK_MEMBER(ksm_state::scanline_callback)
{
uint16_t y = m_screen->vpos();
- uint16_t offset;
LOGDBG("scanline_cb addr %02x frame %d x %.4d y %.3d row %.2d\n",
m_video.line, (int)m_screen->frame_number(), m_screen->hpos(), y, y%11);
@@ -374,6 +373,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(ksm_state::scanline_callback)
y -= KSM_VERT_START;
if (y >= KSM_DISP_VERT) return;
+ uint16_t offset;
if (y < KSM_STATUSLINE_TOTAL)
{
offset = KSM_STATUSLINE_VRAM - 0xC000;
@@ -383,7 +383,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(ksm_state::scanline_callback)
offset = 0x2000 + 0x30 + (((m_video.line + y / 11 - 1) % 48) << 7);
}
- draw_scanline(&m_tmpbmp.pix16(y), offset, y % 11);
+ draw_scanline(&m_tmpbmp.pix(y), offset, y % 11);
}
uint32_t ksm_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
diff --git a/src/mame/drivers/dwarfd.cpp b/src/mame/drivers/dwarfd.cpp
index 246e31d1bb1..4e040d7581b 100644
--- a/src/mame/drivers/dwarfd.cpp
+++ b/src/mame/drivers/dwarfd.cpp
@@ -619,10 +619,10 @@ I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::pesp_display_pixels)
{
uint8_t pixel = (pixels >> (i * 2)) & 0xf;
uint8_t value = (pixel >> 1) | (rvv << 4) | (vsp << 3);
- bitmap.pix32(y, x + i) = palette[value];
- bitmap.pix32(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
+ bitmap.pix(y, x + i) = palette[value];
+ bitmap.pix(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
if(m_back_color)
- bitmap.pix32(y, x + i - 1) = palette[value];
+ bitmap.pix(y, x + i - 1) = palette[value];
m_back_color = pixel & 1;
}
}
@@ -642,10 +642,10 @@ I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::display_pixels)
{
uint8_t pixel = (pixels >> (i * 2)) & 0xf;
uint8_t value = (pixel >> 1) | (rvv << 4) | (vsp << 3);
- bitmap.pix32(y, x + i) = palette[value];
- bitmap.pix32(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
+ bitmap.pix(y, x + i) = palette[value];
+ bitmap.pix(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
if(m_back_color)
- bitmap.pix32(y, x + i - 1) = palette[value];
+ bitmap.pix(y, x + i - 1) = palette[value];
m_back_color = pixel & 1;
}
}
@@ -665,10 +665,10 @@ I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::qc_display_pixels)
{
uint8_t pixel = (pixels >> (i * 2)) & 0xf;
uint8_t value = (pixel >> 1) | (rvv << 4) | (vsp << 3);
- bitmap.pix32(y, x + i) = palette[value];
- bitmap.pix32(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
+ bitmap.pix(y, x + i) = palette[value];
+ bitmap.pix(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
if(m_back_color)
- bitmap.pix32(y, x + i - 1) = palette[value];
+ bitmap.pix(y, x + i - 1) = palette[value];
m_back_color = pixel & 1;
}
}
diff --git a/src/mame/drivers/e100.cpp b/src/mame/drivers/e100.cpp
index 6afd7a2ec69..2ac709df04e 100644
--- a/src/mame/drivers/e100.cpp
+++ b/src/mame/drivers/e100.cpp
@@ -235,7 +235,7 @@ uint32_t e100_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
for (x = 0; x < 8; x++)
{
if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN(" %02x: ", *chardata);
- bitmap.pix16(row + y, col + x) = (*chardata & (1 << x)) ? 1 : 0;
+ bitmap.pix(row + y, col + x) = (*chardata & (1 << x)) ? 1 : 0;
}
chardata++;
}
diff --git a/src/mame/drivers/ec65.cpp b/src/mame/drivers/ec65.cpp
index c18395857b2..4ce325e34b5 100644
--- a/src/mame/drivers/ec65.cpp
+++ b/src/mame/drivers/ec65.cpp
@@ -164,19 +164,17 @@ void ec65_state::machine_reset()
MC6845_UPDATE_ROW( ec65_common::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx,inv;
- u16 mem,x;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u32 *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- inv = (x == cursor_x) ? 0xff : 0;
- mem = (ma + x) & 0x7ff;
- chr = m_vram[mem];
+ u8 const inv = (x == cursor_x) ? 0xff : 0;
+ u16 const mem = (ma + x) & 0x7ff;
+ u8 const chr = m_vram[mem];
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<4) | (ra & 0x0f)] ^ inv;
+ u8 const gfx = m_p_chargen[(chr<<4) | (ra & 0x0f)] ^ inv;
/* Display a scanline of a character */
*p++ = palette[BIT(gfx, 7)];
diff --git a/src/mame/drivers/elan_eu3a05.cpp b/src/mame/drivers/elan_eu3a05.cpp
index c1c7675cd21..29abd9ff08d 100644
--- a/src/mame/drivers/elan_eu3a05.cpp
+++ b/src/mame/drivers/elan_eu3a05.cpp
@@ -247,7 +247,7 @@ public:
void init_sudelan();
void init_sudelan3();
-
+
protected:
// driver_device overrides
virtual void machine_start() override;
@@ -869,7 +869,7 @@ void elan_eu3a05_pvwwcas_state::pvwwcas(machine_config& config)
m_screen->set_refresh_hz(50);
m_sys->set_pal(); // TODO: also set PAL clocks
- m_gpio->read_2_callback().set(FUNC(elan_eu3a05_pvwwcas_state::pvwwc_portc_r));
+ m_gpio->read_2_callback().set(FUNC(elan_eu3a05_pvwwcas_state::pvwwc_portc_r));
m_gpio->write_2_callback().set(FUNC(elan_eu3a05_pvwwcas_state::pvwwc_portc_w));
}
diff --git a/src/mame/drivers/electron.cpp b/src/mame/drivers/electron.cpp
index 83764b30a6d..f60a6936a19 100644
--- a/src/mame/drivers/electron.cpp
+++ b/src/mame/drivers/electron.cpp
@@ -333,6 +333,8 @@ void electronsp_state::electronsp(machine_config &config)
VIA6522(config, m_via, 16_MHz_XTAL / 16);
m_via->readpb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_r));
m_via->writepb_handler().set(m_userport, FUNC(bbc_userport_slot_device::pb_w));
+ m_via->cb1_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb1));
+ m_via->cb2_handler().set(m_userport, FUNC(bbc_userport_slot_device::write_cb2));
m_via->irq_handler().set(m_irqs, FUNC(input_merger_device::in_w<2>));
/* user port */
diff --git a/src/mame/drivers/elekscmp.cpp b/src/mame/drivers/elekscmp.cpp
index e0f7e012ee8..b3a43fc765b 100644
--- a/src/mame/drivers/elekscmp.cpp
+++ b/src/mame/drivers/elekscmp.cpp
@@ -12,8 +12,9 @@ To Use:
- Press MINUS to enter data input mode
- Press UP or DOWN to cycle through addresses
-At the moment Paste cannot be tested, but if it worked, you could
-paste this in: -0F0011^22^33^44^55^66^77^88^99^
+Paste test:
+paste this in: -0F0011^22^33^44^55^66^77^88^99^N-0F00
+Now press UP to verify the data that was entered.
It seems the only way to exit each mode is to press NRST.
@@ -190,7 +191,7 @@ static INPUT_PORTS_START( elekscmp )
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Run") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('X')
PORT_START("RESET")
- PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NRST") PORT_CODE(KEYCODE_LALT) PORT_CHANGED_MEMBER(DEVICE_SELF, elekscmp_state, reset_button, 0)
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NRST") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, elekscmp_state, reset_button, 0) PORT_CHAR('N')
INPUT_PORTS_END
INPUT_CHANGED_MEMBER(elekscmp_state::reset_button)
diff --git a/src/mame/drivers/elwro800.cpp b/src/mame/drivers/elwro800.cpp
index 29e116d660c..59b7d0c53c2 100644
--- a/src/mame/drivers/elwro800.cpp
+++ b/src/mame/drivers/elwro800.cpp
@@ -408,8 +408,8 @@ static INPUT_PORTS_START( elwro800 )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(": *") PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(':')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(": *") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
PORT_START("LINE1") /* 0xFDFE */
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
@@ -417,8 +417,8 @@ static INPUT_PORTS_START( elwro800 )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("- =") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("- =") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
PORT_START("LINE2") /* 0xFBFE */
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
@@ -426,26 +426,26 @@ static INPUT_PORTS_START( elwro800 )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_START("LINE3") /* 0xF7FE */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("@ \\") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('@')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR(0xff) PORT_CHAR('!')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR(0xff) PORT_CHAR('"')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(0xff) PORT_CHAR('#')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR(0xff) PORT_CHAR('$')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR(0xff) PORT_CHAR('%')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("@ \\") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('@') PORT_CHAR('\\')
PORT_START("LINE4") /* 0xEFFE */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 _") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('_')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 '") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 _") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(0xff) PORT_CHAR('_')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(0xff) PORT_CHAR(')')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR(0xff) PORT_CHAR('(')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 '") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR(0xff) PORT_CHAR('\'')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR(0xff) PORT_CHAR('&')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL),127)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
PORT_START("LINE5") /* 0xDFFE */
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
@@ -453,8 +453,8 @@ static INPUT_PORTS_START( elwro800 )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BS") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC),27)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BS") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE),8)
PORT_START("LINE6") /* 0xBFFE */
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
@@ -472,7 +472,7 @@ static INPUT_PORTS_START( elwro800 )
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("^ -") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^') PORT_CHAR('-')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("^ -") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('^')
PORT_START("LINE8")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\xC4\x98") PORT_CODE(KEYCODE_0_PAD) // LATIN CAPITAL LETTER E WITH OGONEK
@@ -643,4 +643,4 @@ ROM_END
/* Driver */
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
-COMP( 1986, elwro800, 0, 0, elwro800, elwro800, elwro800_state, empty_init, "Elwro", "800 Junior", 0 )
+COMP( 1986, elwro800, 0, 0, elwro800, elwro800, elwro800_state, empty_init, "Elwro", "800-3 Junior", 0 )
diff --git a/src/mame/drivers/embargo.cpp b/src/mame/drivers/embargo.cpp
index 9c528330d11..44d903197b8 100644
--- a/src/mame/drivers/embargo.cpp
+++ b/src/mame/drivers/embargo.cpp
@@ -52,23 +52,19 @@ private:
uint32_t embargo_state::screen_update_embargo(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- int i;
-
uint8_t x = offs << 3;
- uint8_t y = offs >> 5;
+ uint8_t const y = offs >> 5;
uint8_t data = m_videoram[offs];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
pen_t pen = (data & 0x01) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- data = data >> 1;
- x = x + 1;
+ data >>= 1;
+ x++;
}
}
diff --git a/src/mame/drivers/emu3.cpp b/src/mame/drivers/emu3.cpp
index 4bd40415e09..b2b0791654d 100644
--- a/src/mame/drivers/emu3.cpp
+++ b/src/mame/drivers/emu3.cpp
@@ -64,6 +64,7 @@ public:
protected:
virtual void machine_start() override;
+ virtual void machine_reset() override;
private:
void emu3_map(address_map &map);
@@ -133,6 +134,12 @@ void emu3_state::machine_start()
m_irq_state = false;
}
+void emu3_state::machine_reset()
+{
+ m_fdc->set_floppy(m_fdd);
+ m_fdc->dden_w(0);
+}
+
void emu3_state::emu3_map(address_map &map)
{
map(0x000000, 0x007fff).rom().region("bootprom", 0);
@@ -147,7 +154,7 @@ void emu3_state::emu3_map(address_map &map)
map(0xd70000, 0xd70000).lw8(
[this](u8 data)
{
- m_fdd->ss_w(BIT(data, MISC_SIDE));
+ m_fdd->ss_w(!BIT(data, MISC_SIDE));
m_fdd->mon_w(BIT(data, MISC_MTR));
m_led[16] = BIT(data, MISC_LED);
}, "misc_w");
@@ -209,10 +216,8 @@ void emu3_state::emu3(machine_config &config)
WD1772(config, m_fdc, 16_MHz_XTAL / 2);
m_fdc->intrq_wr_callback().set(*this, FUNC(emu3_state::irq_w<FDCINT>));
m_fdc->set_disable_motor_control(true);
- //m_fdc->sso_wr_callback().set([this](int state) {});
- m_fdc->dden_w(0);
- FLOPPY_CONNECTOR(config, "fdc:0", emu3_floppies, "35dd", floppy_image_device::default_floppy_formats);
+ FLOPPY_CONNECTOR(config, "fdc:0", emu3_floppies, "35dd", floppy_image_device::default_floppy_formats).enable_sound(true);
PIT8254(config, m_pit); // 8254-2
m_pit->set_clk<0>(20_MHz_XTAL / 2);
diff --git a/src/mame/drivers/emu68k.cpp b/src/mame/drivers/emu68k.cpp
index 2d2dba851cb..f4deb4ebf30 100644
--- a/src/mame/drivers/emu68k.cpp
+++ b/src/mame/drivers/emu68k.cpp
@@ -54,7 +54,7 @@ void emu68k_state::machine_start()
HD44780_PIXEL_UPDATE(emu68k_state::lcd_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 16)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
diff --git a/src/mame/drivers/enigma2.cpp b/src/mame/drivers/enigma2.cpp
index 7d9b2211cd0..6537fa57d92 100644
--- a/src/mame/drivers/enigma2.cpp
+++ b/src/mame/drivers/enigma2.cpp
@@ -282,7 +282,7 @@ uint32_t enigma2_state::screen_update_enigma2(screen_device &screen, bitmap_rgb3
/* stars only appear at certain positions */
color = ((x & y & 0x0f) == 0x0f) ? star_color : 0;
- bitmap.pix32(bitmap_y, x) = m_palette->pen_color(color);
+ bitmap.pix(bitmap_y, x) = m_palette->pen_color(color);
/* next pixel */
x = x + 1;
@@ -344,7 +344,7 @@ uint32_t enigma2_state::screen_update_enigma2a(screen_device &screen, bitmap_rgb
}
pen = bit ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(bitmap_y, x) = pen;
+ bitmap.pix(bitmap_y, x) = pen;
/* next pixel */
x = x + 1;
diff --git a/src/mame/drivers/eolith16.cpp b/src/mame/drivers/eolith16.cpp
index de0de146aaa..d3ad8c11532 100644
--- a/src/mame/drivers/eolith16.cpp
+++ b/src/mame/drivers/eolith16.cpp
@@ -129,7 +129,7 @@ uint32_t eolith16_state::screen_update_eolith16(screen_device &screen, bitmap_in
{
for (int x = 0; x < 320; x++)
{
- bitmap.pix16(y, x) = m_vram[(y * 320) + x] & 0xff;
+ bitmap.pix(y, x) = m_vram[(y * 320) + x] & 0xff;
}
}
return 0;
diff --git a/src/mame/drivers/epic14e.cpp b/src/mame/drivers/epic14e.cpp
index a32884f75ee..65647de0e8b 100644
--- a/src/mame/drivers/epic14e.cpp
+++ b/src/mame/drivers/epic14e.cpp
@@ -61,7 +61,7 @@ SCN2672_DRAW_CHARACTER_MEMBER(epic14e_state::draw_character)
for (int i = 0; i < 9; i++)
{
- bitmap.pix32(y, x++) = BIT(dots, 8) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y, x++) = BIT(dots, 8) ? rgb_t::white() : rgb_t::black();
dots <<= 1;
}
}
diff --git a/src/mame/drivers/esh.cpp b/src/mame/drivers/esh.cpp
index 98eeea10226..f47cbf90200 100644
--- a/src/mame/drivers/esh.cpp
+++ b/src/mame/drivers/esh.cpp
@@ -118,7 +118,7 @@ uint32_t esh_state::screen_update_esh(screen_device &screen, bitmap_rgb32 &bitma
for(int yi=0;yi<8;yi++)
for(int xi=0;xi<8;xi++)
- bitmap.pix32(yi+chary*8, xi+charx*8) = m_palette->pen(palIndex * 8 + pal_bank * 0x100);
+ bitmap.pix(yi+chary*8, xi+charx*8) = m_palette->pen(palIndex * 8 + pal_bank * 0x100);
continue;
}
diff --git a/src/mame/drivers/esprit.cpp b/src/mame/drivers/esprit.cpp
index 610c0fca646..6969eabe52e 100644
--- a/src/mame/drivers/esprit.cpp
+++ b/src/mame/drivers/esprit.cpp
@@ -82,8 +82,8 @@ INPUT_PORTS_END
MC6845_UPDATE_ROW(esprit_state::crtc_update_row)
{
- const rgb_t *pens = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ rgb_t const *const pens = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
for (uint16_t x = 0; x < x_count; x++)
{
diff --git a/src/mame/drivers/esq1.cpp b/src/mame/drivers/esq1.cpp
index b0a9e97a293..c7f4869c33d 100644
--- a/src/mame/drivers/esq1.cpp
+++ b/src/mame/drivers/esq1.cpp
@@ -210,7 +210,7 @@ protected:
virtual void device_start() override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
struct filter {
@@ -334,13 +334,13 @@ void esq1_filters::recalc_filter(filter &f)
void esq1_filters::device_start()
{
- stream = stream_alloc_legacy(8, 2, 44100);
+ stream = stream_alloc(8, 2, 44100);
memset(filters, 0, sizeof(filters));
for(auto & elem : filters)
recalc_filter(elem);
}
-void esq1_filters::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void esq1_filters::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
/* if(0) {
for(int i=0; i<8; i++)
@@ -352,11 +352,11 @@ void esq1_filters::sound_stream_update_legacy(sound_stream &stream, stream_sampl
fprintf(stderr, "\n");
}*/
- for(int i=0; i<samples; i++) {
+ for(int i=0; i<outputs[0].samples(); i++) {
double l=0, r=0;
for(int j=0; j<8; j++) {
filter &f = filters[j];
- double x = inputs[j][i];
+ double x = inputs[j].get(i);
double y = (x*f.a[0]
+ f.x[0]*f.a[1] + f.x[1]*f.a[2] + f.x[2]*f.a[3] + f.x[3]*f.a[4]
- f.y[0]*f.b[1] - f.y[1]*f.b[2] - f.y[2]*f.b[3] - f.y[3]*f.b[4]) / f.b[0];
@@ -378,8 +378,8 @@ void esq1_filters::sound_stream_update_legacy(sound_stream &stream, stream_sampl
// r *= 6553;
l *= 2;
r *= 2;
- outputs[0][i] = l < -32768 ? -32768 : l > 32767 ? 32767 : int(l);
- outputs[1][i] = r < -32768 ? -32768 : r > 32767 ? 32767 : int(r);
+ outputs[0].put_clamp(i, l, 1.0);
+ outputs[1].put_clamp(i, r, 1.0);
}
}
diff --git a/src/mame/drivers/eurit.cpp b/src/mame/drivers/eurit.cpp
index 24b9ad57b44..1bb12cfc320 100644
--- a/src/mame/drivers/eurit.cpp
+++ b/src/mame/drivers/eurit.cpp
@@ -53,7 +53,7 @@ void eurit_state::machine_start()
HD44780_PIXEL_UPDATE(eurit_state::lcd_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 20)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
diff --git a/src/mame/drivers/eurocom2.cpp b/src/mame/drivers/eurocom2.cpp
index 719bb57852c..a62c695a9e5 100644
--- a/src/mame/drivers/eurocom2.cpp
+++ b/src/mame/drivers/eurocom2.cpp
@@ -302,19 +302,16 @@ uint8_t waveterm_state::waveterm_adc()
uint32_t eurocom2_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x, y, offset, page;
- uint16_t gfx, *p;
+ int const page = (m_vico[0] & 3) << 14;
- page = (m_vico[0] & 3) << 14;
-
- for (y = 0; y < VC_DISP_VERT; y++)
+ for (int y = 0; y < VC_DISP_VERT; y++)
{
- offset = (VC_DISP_HORZ / 8) * ((m_vico[1] + y) % VC_DISP_VERT);
- p = &m_tmpbmp.pix16(y);
+ int const offset = (VC_DISP_HORZ / 8) * ((m_vico[1] + y) % VC_DISP_VERT);
+ uint16_t *p = &m_tmpbmp.pix(y);
- for (x = offset; x < offset + VC_DISP_HORZ / 8; x++)
+ for (int x = offset; x < offset + VC_DISP_HORZ / 8; x++)
{
- gfx = m_p_videoram[page + x];
+ uint16_t const gfx = m_p_videoram[page + x];
for (int i = 7; i >= 0; i--)
{
diff --git a/src/mame/drivers/excali64.cpp b/src/mame/drivers/excali64.cpp
index bf1368c495d..56d2afc5406 100644
--- a/src/mame/drivers/excali64.cpp
+++ b/src/mame/drivers/excali64.cpp
@@ -530,20 +530,19 @@ void excali64_state::excali64_palette(palette_device &palette)
MC6845_UPDATE_ROW( excali64_state::update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx,col,bg,fg;
- u16 mem,x;
- u8 col_base = BIT(m_sys_status, 3) ? 16 : 0;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u8 const col_base = BIT(m_sys_status, 3) ? 16 : 0;
+ u32 *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- mem = (ma + x) & 0x7ff;
- chr = m_vram[mem];
- col = m_vram[mem+0x800];
- fg = col_base + (col >> 4);
- bg = 32 + ((col >> 1) & 7);
+ u16 const mem = (ma + x) & 0x7ff;
+ u8 const chr = m_vram[mem];
+ u8 const col = m_vram[mem+0x800];
+ u8 const fg = col_base + (col >> 4);
+ u8 const bg = 32 + ((col >> 1) & 7);
+ u8 gfx;
if (BIT(col, 0))
{
u8 h = m_vram[mem+0x1000] - 4;
diff --git a/src/mame/drivers/expro02.cpp b/src/mame/drivers/expro02.cpp
index 6767f6454c7..5a2bc1ed6eb 100644
--- a/src/mame/drivers/expro02.cpp
+++ b/src/mame/drivers/expro02.cpp
@@ -338,7 +338,7 @@ uint32_t expro02_state::screen_update_backgrounds(screen_device &screen, bitmap_
count = 0;
for (int y = 0; y < 256; y++)
{
- uint16_t *const dest = &bitmap.pix16(y);
+ uint16_t *const dest = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
uint16_t dat = (m_bg_rgb555_pixram[count] & 0xfffe)>>1;
@@ -363,7 +363,7 @@ uint32_t expro02_state::screen_update_backgrounds(screen_device &screen, bitmap_
count = 0;
for (int y = 0; y < 256; y++)
{
- uint16_t *const dest = &bitmap.pix16(y);
+ uint16_t *const dest = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
uint16_t const dat = m_fg_ind8_pixram[count] & 0x7ff;
diff --git a/src/mame/drivers/f-32.cpp b/src/mame/drivers/f-32.cpp
index 7e58b37a5cc..0f07d04cd4a 100644
--- a/src/mame/drivers/f-32.cpp
+++ b/src/mame/drivers/f-32.cpp
@@ -67,17 +67,15 @@ private:
uint32_t mosaicf2_state::screen_update_mosaicf2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < 0x10000; offs++)
+ for (offs_t offs = 0; offs < 0x10000; offs++)
{
int y = offs >> 8;
int x = offs & 0xff;
if ((x < 0xa0) && (y < 0xe0))
{
- bitmap.pix16(y, (x * 2) + 0) = (m_videoram[offs] >> 16) & 0x7fff;
- bitmap.pix16(y, (x * 2) + 1) = (m_videoram[offs] >> 0) & 0x7fff;
+ bitmap.pix(y, (x * 2) + 0) = (m_videoram[offs] >> 16) & 0x7fff;
+ bitmap.pix(y, (x * 2) + 1) = (m_videoram[offs] >> 0) & 0x7fff;
}
}
diff --git a/src/mame/drivers/facit4440.cpp b/src/mame/drivers/facit4440.cpp
index 2c066aa243c..84c6d8cc8db 100644
--- a/src/mame/drivers/facit4440.cpp
+++ b/src/mame/drivers/facit4440.cpp
@@ -148,7 +148,7 @@ WRITE_LINE_MEMBER(facit4440_state::vsync_w)
MC6845_UPDATE_ROW(facit4440_state::update_row)
{
offs_t base = ma / 5 * 6;
- u32 *px = &bitmap.pix32(y);
+ u32 *px = &bitmap.pix(y);
for (int i = 0; i < x_count; i++)
{
diff --git a/src/mame/drivers/falco5220.cpp b/src/mame/drivers/falco5220.cpp
index b7950bde463..a4a2660e4db 100644
--- a/src/mame/drivers/falco5220.cpp
+++ b/src/mame/drivers/falco5220.cpp
@@ -96,7 +96,7 @@ u32 falco5220_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
gfx = 0xff;
for (int x = 0; x < 8; x++)
- bitmap.pix32(col*16 + y, row*8 + x) = BIT(gfx, x) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(col*16 + y, row*8 + x) = BIT(gfx, x) ? rgb_t::white() : rgb_t::black();
}
}
}
diff --git a/src/mame/drivers/fanucspmg.cpp b/src/mame/drivers/fanucspmg.cpp
index 4d8a2f70aca..c5608e0eb92 100644
--- a/src/mame/drivers/fanucspmg.cpp
+++ b/src/mame/drivers/fanucspmg.cpp
@@ -846,11 +846,10 @@ void fanucspmg_state::memory_write_byte(offs_t offset, uint8_t data)
MC6845_UPDATE_ROW( fanucspmg_state::crtc_update_row )
{
- uint32_t *p = &bitmap.pix32(y);
- int i;
- uint8_t *chargen = m_chargen->base();
+ uint32_t *p = &bitmap.pix(y);
+ uint8_t const *const chargen = m_chargen->base();
- for ( i = 0; i < x_count; i++ )
+ for ( int i = 0; i < x_count; i++ )
{
uint16_t offset = ( ma + i );
@@ -868,14 +867,14 @@ MC6845_UPDATE_ROW( fanucspmg_state::crtc_update_row )
if (attr & 0x40) fg |= 0x00ff00;
if (attr & 0x80) fg |= 0x0000ff;
- *p++ = ( data & 0x01 ) ? fg : bg;
- *p++ = ( data & 0x02 ) ? fg : bg;
- *p++ = ( data & 0x04 ) ? fg : bg;
- *p++ = ( data & 0x08 ) ? fg : bg;
- *p++ = ( data & 0x10 ) ? fg : bg;
- *p++ = ( data & 0x20 ) ? fg : bg;
- *p++ = ( data & 0x40 ) ? fg : bg;
- *p++ = ( data & 0x80 ) ? fg : bg;
+ *p++ = BIT(data, 0) ? fg : bg;
+ *p++ = BIT(data, 1) ? fg : bg;
+ *p++ = BIT(data, 2) ? fg : bg;
+ *p++ = BIT(data, 3) ? fg : bg;
+ *p++ = BIT(data, 4) ? fg : bg;
+ *p++ = BIT(data, 5) ? fg : bg;
+ *p++ = BIT(data, 6) ? fg : bg;
+ *p++ = BIT(data, 7) ? fg : bg;
}
}
else
@@ -894,11 +893,10 @@ MC6845_UPDATE_ROW( fanucspmg_state::crtc_update_row )
MC6845_UPDATE_ROW( fanucspmg_state::crtc_update_row_mono )
{
- uint32_t *p = &bitmap.pix32(y);
- int i;
- uint8_t *chargen = m_chargen->base();
+ uint32_t *p = &bitmap.pix(y);
+ uint8_t const *const chargen = m_chargen->base();
- for ( i = 0; i < x_count; i++ )
+ for ( int i = 0; i < x_count; i++ )
{
uint16_t offset = ( ma + i );
@@ -912,14 +910,14 @@ MC6845_UPDATE_ROW( fanucspmg_state::crtc_update_row_mono )
uint32_t fg = 0xff00;
uint32_t bg = 0;
- *p++ = ( data & 0x01 ) ? fg : bg;
- *p++ = ( data & 0x02 ) ? fg : bg;
- *p++ = ( data & 0x04 ) ? fg : bg;
- *p++ = ( data & 0x08 ) ? fg : bg;
- *p++ = ( data & 0x10 ) ? fg : bg;
- *p++ = ( data & 0x20 ) ? fg : bg;
- *p++ = ( data & 0x40 ) ? fg : bg;
- *p++ = ( data & 0x80 ) ? fg : bg;
+ *p++ = BIT(data, 0) ? fg : bg;
+ *p++ = BIT(data, 1) ? fg : bg;
+ *p++ = BIT(data, 2) ? fg : bg;
+ *p++ = BIT(data, 3) ? fg : bg;
+ *p++ = BIT(data, 4) ? fg : bg;
+ *p++ = BIT(data, 5) ? fg : bg;
+ *p++ = BIT(data, 6) ? fg : bg;
+ *p++ = BIT(data, 7) ? fg : bg;
}
}
else
diff --git a/src/mame/drivers/fb01.cpp b/src/mame/drivers/fb01.cpp
index 35cf5c36c46..e05ba8a9255 100644
--- a/src/mame/drivers/fb01.cpp
+++ b/src/mame/drivers/fb01.cpp
@@ -148,7 +148,7 @@ HD44780_PIXEL_UPDATE(fb01_state::fb01_pixel_update)
{
if ( pos < 8 && line < 2 )
{
- bitmap.pix16(y, line*6*8 + pos*6 + x) = state;
+ bitmap.pix(y, line*6*8 + pos*6 + x) = state;
}
}
diff --git a/src/mame/drivers/fc100.cpp b/src/mame/drivers/fc100.cpp
index 67a08b7f92a..05f48542c8b 100644
--- a/src/mame/drivers/fc100.cpp
+++ b/src/mame/drivers/fc100.cpp
@@ -159,8 +159,8 @@ static INPUT_PORTS_START( fc100 )
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_NAME("Caps")
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_NAME("[") PORT_CHAR('[') PORT_CHAR('{')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_NAME("]") PORT_CHAR(']') PORT_CHAR('}')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_NAME("P") PORT_CHAR('P') PORT_CHAR('p')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_NAME("O") PORT_CHAR('O') PORT_CHAR('o')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_NAME("P") PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_NAME("O") PORT_CHAR('o') PORT_CHAR('O')
PORT_START("KEY.1")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
@@ -171,10 +171,10 @@ static INPUT_PORTS_START( fc100 )
PORT_START("KEY.2")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Left")
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Down")
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Right")
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_NAME("Up")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Left") PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Down") PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Right") PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_NAME("Up") PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_START("KEY.3")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
@@ -199,17 +199,17 @@ static INPUT_PORTS_START( fc100 )
PORT_START("KEY.6")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_NAME("F5")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_NAME("F5") PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F10))
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Space") PORT_CHAR(32)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_NAME("Run")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_NAME("0") PORT_CHAR('0') PORT_CHAR(')')
PORT_START("KEY.7")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_NAME("F1")
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_NAME("F2")
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_NAME("F3")
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_NAME("F4")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_NAME("F1") PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_NAME("F2") PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_NAME("F3") PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_NAME("F4") PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CHAR(UCHAR_MAMEKEY(F9))
PORT_START("KEY.8")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
@@ -227,45 +227,45 @@ static INPUT_PORTS_START( fc100 )
PORT_START("KEY.10")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_NAME("B") PORT_CHAR('B') PORT_CHAR('b')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_NAME("N") PORT_CHAR('N') PORT_CHAR('n')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_NAME("M") PORT_CHAR('M') PORT_CHAR('m')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_NAME("L") PORT_CHAR('L') PORT_CHAR('l')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_NAME("B") PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_NAME("N") PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_NAME("M") PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_NAME("L") PORT_CHAR('l') PORT_CHAR('L')
PORT_START("KEY.11")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_NAME("Z") PORT_CHAR('Z') PORT_CHAR('z')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_NAME("X") PORT_CHAR('X') PORT_CHAR('x')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_NAME("C") PORT_CHAR('C') PORT_CHAR('c')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_NAME("V") PORT_CHAR('V') PORT_CHAR('v')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_NAME("Z") PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_NAME("X") PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_NAME("C") PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_NAME("V") PORT_CHAR('v') PORT_CHAR('V')
PORT_START("KEY.12")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_NAME("G") PORT_CHAR('G') PORT_CHAR('g')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_NAME("H") PORT_CHAR('H') PORT_CHAR('h')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_NAME("J") PORT_CHAR('J') PORT_CHAR('j')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_NAME("K") PORT_CHAR('K') PORT_CHAR('k')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_NAME("G") PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_NAME("H") PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_NAME("J") PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_NAME("K") PORT_CHAR('k') PORT_CHAR('K')
PORT_START("KEY.13")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_NAME("A") PORT_CHAR('A') PORT_CHAR('a')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_NAME("S") PORT_CHAR('S') PORT_CHAR('s')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_NAME("D") PORT_CHAR('D') PORT_CHAR('d')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_NAME("F") PORT_CHAR('F') PORT_CHAR('f')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_NAME("A") PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_NAME("S") PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_NAME("D") PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_NAME("F") PORT_CHAR('f') PORT_CHAR('F')
PORT_START("KEY.14")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_NAME("T") PORT_CHAR('T') PORT_CHAR('t')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_NAME("Y") PORT_CHAR('Y') PORT_CHAR('y')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_NAME("U") PORT_CHAR('U') PORT_CHAR('u')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_NAME("I") PORT_CHAR('I') PORT_CHAR('i')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_NAME("T") PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_NAME("Y") PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_NAME("U") PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_NAME("I") PORT_CHAR('i') PORT_CHAR('I')
PORT_START("KEY.15")
PORT_BIT(0xF0, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_NAME("Q") PORT_CHAR('Q') PORT_CHAR('q')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_NAME("W") PORT_CHAR('W') PORT_CHAR('w')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_NAME("E") PORT_CHAR('E') PORT_CHAR('e')
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_NAME("R") PORT_CHAR('R') PORT_CHAR('r')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_NAME("Q") PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_NAME("W") PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_NAME("E") PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_NAME("R") PORT_CHAR('r') PORT_CHAR('R')
PORT_START("JOY0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
diff --git a/src/mame/drivers/fk1.cpp b/src/mame/drivers/fk1.cpp
index 3e8f728ce02..e0d11652fee 100644
--- a/src/mame/drivers/fk1.cpp
+++ b/src/mame/drivers/fk1.cpp
@@ -404,17 +404,15 @@ void fk1_state::machine_reset()
uint32_t fk1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t code;
- int y, x, b;
- uint8_t *ram = m_ram->pointer();
+ uint8_t const *const ram = m_ram->pointer();
- for (x = 0; x < 64; x++)
+ for (int x = 0; x < 64; x++)
{
- for (y = 0; y < 256; y++)
+ for (int y = 0; y < 256; y++)
{
- code = ram[x * 0x100 + ((y + m_video_rol) & 0xff) + 0x8000];
- for (b = 0; b < 8; b++)
- bitmap.pix16(y, x*8+b) = ((code << b) & 0x80) ? 1 : 0;
+ uint8_t code = ram[x * 0x100 + ((y + m_video_rol) & 0xff) + 0x8000];
+ for (int b = 0; b < 8; b++)
+ bitmap.pix(y, x*8+b) = ((code << b) & 0x80) ? 1 : 0;
}
}
return 0;
diff --git a/src/mame/drivers/flipjack.cpp b/src/mame/drivers/flipjack.cpp
index 9f84bca2350..e0eb29c1691 100644
--- a/src/mame/drivers/flipjack.cpp
+++ b/src/mame/drivers/flipjack.cpp
@@ -173,8 +173,8 @@ MC6845_UPDATE_ROW(flipjack_state::update_row)
{
const bool flip = !BIT(m_layer, 0);
const uint16_t row_base = ((ma & 0x03e0) << 3 | (ra & 7) << 5) ^ (flip ? 0x1fff : 0);
- uint32_t *const pbegin = &bitmap.pix32(y);
- uint32_t *const pend = &bitmap.pix32(y, x_count * 8);
+ uint32_t *const pbegin = &bitmap.pix(y);
+ uint32_t *const pend = &bitmap.pix(y, x_count * 8);
std::fill(pbegin, pend, rgb_t::black());
diff --git a/src/mame/drivers/flyball.cpp b/src/mame/drivers/flyball.cpp
index a45064ae13f..ee657e4a41e 100644
--- a/src/mame/drivers/flyball.cpp
+++ b/src/mame/drivers/flyball.cpp
@@ -175,7 +175,7 @@ uint32_t flyball_state::screen_update(screen_device &screen, bitmap_ind16 &bitma
for (int y = bally; y < bally + 2; y++)
for (int x = ballx; x < ballx + 2; x++)
if (cliprect.contains(x, y))
- bitmap.pix16(y, x) = 1;
+ bitmap.pix(y, x) = 1;
return 0;
}
diff --git a/src/mame/drivers/fm7.cpp b/src/mame/drivers/fm7.cpp
index 642c68c9631..34db0decb19 100644
--- a/src/mame/drivers/fm7.cpp
+++ b/src/mame/drivers/fm7.cpp
@@ -1727,7 +1727,7 @@ INPUT_PORTS_START( fm7_keyboard )
PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("^") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^')
- PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xEF\xBF\xA5")
+ PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xEF\xBF\xA5") PORT_CHAR(165) PORT_CHAR('|')
PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
@@ -1767,7 +1767,7 @@ INPUT_PORTS_START( fm7_keyboard )
PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
- PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("_") PORT_CHAR('_')
+ PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("_") PORT_CHAR('"') PORT_CHAR('_')
PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tenkey *") PORT_CODE(KEYCODE_ASTERISK)
PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tenkey /") PORT_CODE(KEYCODE_SLASH_PAD)
diff --git a/src/mame/drivers/fmtowns.cpp b/src/mame/drivers/fmtowns.cpp
index 9a0f29f04d4..07044988df3 100644
--- a/src/mame/drivers/fmtowns.cpp
+++ b/src/mame/drivers/fmtowns.cpp
@@ -2012,16 +2012,6 @@ WRITE_LINE_MEMBER(towns_state::rtc_busy_w)
}
// SCSI controller - I/O ports 0xc30 and 0xc32
-uint16_t towns_state::towns_scsi_dma_r()
-{
- return m_scsi->fmscsi_data_r();
-}
-
-void towns_state::towns_scsi_dma_w(uint16_t data)
-{
- m_scsi->fmscsi_data_w(data & 0xff);
-}
-
WRITE_LINE_MEMBER(towns_state::towns_scsi_irq)
{
m_pic_slave->ir0_w(state);
@@ -2374,6 +2364,13 @@ void towns_state::towns_io(address_map &map)
map(0xff80, 0xffff).rw(FUNC(towns_state::towns_video_cff80_r), FUNC(towns_state::towns_video_cff80_w));
}
+void towns_state::towns_1g_io(address_map &map)
+{
+ // For the first generation FM Towns with a SCSI card slot
+ towns_io(map);
+ map(0x0c30, 0x0c37).rw(m_scsi_slot, FUNC(fmt_scsi_slot_device::read), FUNC(fmt_scsi_slot_device::write)).umask32(0x00ff00ff);
+}
+
void towns_state::towns2_io(address_map &map)
{
// For FM Towns II models with integrated SCSI controller
@@ -2469,59 +2466,59 @@ static INPUT_PORTS_START( towns )
PORT_START( "key1" ) // scancodes 0x00-0x1f
PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_UNUSED)
PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(27)
- PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1 ! \xE3\x81\xAC") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
- PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2 \x22 \xE3\x81\xB5") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
- PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3 # \xE3\x81\x82 \xE3\x81\x81") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
- PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4 $ \xE3\x81\x86 \xE3\x81\x85") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
- PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5 % \xE3\x81\x88 \xE3\x81\x87") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
- PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6 & \xE3\x81\x8A \xE3\x81\x89") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
- PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7 ´ \xE3\x82\x84 \xE3\x82\x83") PORT_CODE(KEYCODE_7) PORT_CHAR('7')
- PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8 ( \xE3\x82\x86 \xE3\x82\x85") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
- PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9 ) \xE3\x82\x88 \xE3\x82\x87") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
+ PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("1 ! \xE3\x81\xAC") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("2 \x22 \xE3\x81\xB5") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR(34)
+ PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("3 # \xE3\x81\x82 \xE3\x81\x81") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("4 $ \xE3\x81\x86 \xE3\x81\x85") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("5 % \xE3\x81\x88 \xE3\x81\x87") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("6 & \xE3\x81\x8A \xE3\x81\x89") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("7 ´ \xE3\x82\x84 \xE3\x82\x83") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR(39)
+ PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("8 ( \xE3\x82\x86 \xE3\x82\x85") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("9 ) \xE3\x82\x88 \xE3\x82\x87") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("0 \xE3\x82\x8F \xE3\x82\x92") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
- PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("- = \xE3\x81\xBB") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
+ PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("- = \xE3\x81\xBB") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("^ \xE2\x80\xBE \xE3\x81\xB8") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^')
- PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xEF\xBF\xA5 | -") PORT_CODE(KEYCODE_BACKSLASH)
+ PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xEF\xBF\xA5 | -") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(165) PORT_CHAR('|')
PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
- PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Q \xE3\x81\x9F") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
- PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("W \xE3\x81\xA6") PORT_CODE(KEYCODE_W) PORT_CHAR('W')
- PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E \xE3\x81\x84") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
- PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("R \xE3\x81\x99") PORT_CODE(KEYCODE_R) PORT_CHAR('R')
- PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("T \xE3\x81\x8B") PORT_CODE(KEYCODE_T) PORT_CHAR('T')
- PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Y \xE3\x82\x93") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
- PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("U \xE3\x81\xAA") PORT_CODE(KEYCODE_U) PORT_CHAR('U')
- PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("I \xE3\x81\xAB") PORT_CODE(KEYCODE_I) PORT_CHAR('I')
- PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("O \xE3\x82\x89") PORT_CODE(KEYCODE_O) PORT_CHAR('O')
- PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("P \xE3\x81\x9B") PORT_CODE(KEYCODE_P) PORT_CHAR('P')
- PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("@ ` \xE2\x80\x9D") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@')
- PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("[ { \xE3\x82\x9C \xE3\x80\x8C") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[')
- PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(27)
- PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A \xE3\x81\xA1") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
- PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("S \xE3\x81\xA8") PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Q \xE3\x81\x9F") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("W \xE3\x81\xA6") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("E \xE3\x81\x84") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("R \xE3\x81\x99") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("T \xE3\x81\x8B") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Y \xE3\x82\x93") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("U \xE3\x81\xAA") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("I \xE3\x81\xAB") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("O \xE3\x82\x89") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("P \xE3\x81\x9B") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("@ ` \xE2\x80\x9D") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') PORT_CHAR('`')
+ PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("[ { \xE3\x82\x9C \xE3\x80\x8C") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("A \xE3\x81\xA1") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("S \xE3\x81\xA8") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
PORT_START( "key2" ) // scancodes 0x20-0x3f
- PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D \xE3\x81\x97") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
- PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F \xE3\x81\xAF") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
- PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("G \xE3\x81\x8D") PORT_CODE(KEYCODE_G) PORT_CHAR('G')
- PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("H \xE3\x81\x8F") PORT_CODE(KEYCODE_H) PORT_CHAR('H')
- PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("J \xE3\x81\xBE") PORT_CODE(KEYCODE_J) PORT_CHAR('J')
- PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("K \xE3\x81\xAE") PORT_CODE(KEYCODE_K) PORT_CHAR('K')
- PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("L \xE3\x82\x8A") PORT_CODE(KEYCODE_L) PORT_CHAR('L')
- PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("; + \xE3\x82\x8C") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';')
- PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(": * \xE3\x81\x91") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':')
- PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("] } \xE3\x82\x80 \xE3\x80\x8D") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']')
- PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Z \xE3\x81\xA4 \xE3\x81\xA3") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
- PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("X \xE3\x81\x95") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
- PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C \xE3\x81\x9D") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
- PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("V \xE3\x81\xB2") PORT_CODE(KEYCODE_V) PORT_CHAR('V')
- PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B \xE3\x81\x93") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
- PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("N \xE3\x81\xBF") PORT_CODE(KEYCODE_N) PORT_CHAR('N')
- PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("M \xE3\x82\x82") PORT_CODE(KEYCODE_M) PORT_CHAR('M')
- PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(", < \xE3\x81\xAD \xE3\x80\x81") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',')
- PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(". > \xE3\x82\x8B \xE3\x80\x82") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.')
- PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/ ? \xE3\x82\x81 \xE3\x83\xBB") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/')
- PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\x22 _ \xE3\x82\x8D")
+ PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("D \xE3\x81\x97") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("F \xE3\x81\xAF") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("G \xE3\x81\x8D") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("H \xE3\x81\x8F") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("J \xE3\x81\xBE") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("K \xE3\x81\xAE") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("L \xE3\x82\x8A") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("; + \xE3\x82\x8C") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+ PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(": * \xE3\x81\x91") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("] } \xE3\x82\x80 \xE3\x80\x8D") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Z \xE3\x81\xA4 \xE3\x81\xA3") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("X \xE3\x81\x95") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("C \xE3\x81\x9D") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("V \xE3\x81\xB2") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("B \xE3\x81\x93") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("N \xE3\x81\xBF") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("M \xE3\x82\x82") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(", < \xE3\x81\xAD \xE3\x80\x81") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME(". > \xE3\x82\x8B \xE3\x80\x82") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("/ ? \xE3\x82\x81 \xE3\x83\xBB") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\x22 _ \xE3\x82\x8D") PORT_CHAR('"') PORT_CHAR('_')
PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tenkey *") PORT_CODE(KEYCODE_ASTERISK)
PORT_BIT(0x00800000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tenkey /") PORT_CODE(KEYCODE_SLASH_PAD)
@@ -2548,13 +2545,13 @@ static INPUT_PORTS_START( towns )
PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Tenkey 000") PORT_CODE(KEYCODE_000_PAD)
PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE5\x89\x8A\xE9\x99\xA4 (Delete) / EL") PORT_CODE(KEYCODE_DEL)
PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_UNUSED)
- PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP)
+ PORT_BIT(0x00002000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT(0x00004000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME)
- PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT)
- PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN)
- PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x00008000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x00010000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x00020000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0x00040000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL)
- PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT)
+ PORT_BIT(0x00080000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x00100000,IP_ACTIVE_HIGH,IPT_UNUSED)
PORT_BIT(0x00200000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("CAP") PORT_CODE(KEYCODE_CAPSLOCK)
PORT_BIT(0x00400000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE3\x81\xB2\xE3\x82\x89\xE3\x81\x8C\xE3\x81\xAA (Hiragana) / \xE3\x83\xAD\xE3\x83\xBC\xE3\x83\x9E\xE5\xAD\x97 (Romaji)") PORT_CODE(KEYCODE_RCONTROL)
@@ -2562,23 +2559,23 @@ static INPUT_PORTS_START( towns )
PORT_BIT(0x01000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE5\xA4\x89\xE6\x8F\x9B (Conversion)")
PORT_BIT(0x02000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE3\x81\x8B\xE3\x81\xAA\xE6\xBC\xA2\xE5\xAD\x97 (Kana Kanji)") PORT_CODE(KEYCODE_RALT)
PORT_BIT(0x04000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE3\x82\xAB\xE3\x82\xBF\xE3\x82\xAB\xE3\x83\x8A (Katakana)") PORT_CODE(KEYCODE_RWIN)
- PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF12") PORT_CODE(KEYCODE_F12)
+ PORT_BIT(0x08000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF12") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F12))
PORT_BIT(0x10000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("ALT") PORT_CODE(KEYCODE_LALT)
- PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1)
- PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2)
- PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3)
+ PORT_BIT(0x20000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT(0x40000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT(0x80000000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
PORT_START("key4")
- PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4)
- PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5)
- PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF6") PORT_CODE(KEYCODE_F6)
- PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF7") PORT_CODE(KEYCODE_F7)
- PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF8") PORT_CODE(KEYCODE_F8)
- PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF9") PORT_CODE(KEYCODE_F9)
- PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF10") PORT_CODE(KEYCODE_F10)
+ PORT_BIT(0x00000001,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x00000002,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0x00000004,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x00000008,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x00000010,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT(0x00000020,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT(0x00000040,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
PORT_BIT(0x00000080,IP_ACTIVE_HIGH,IPT_UNUSED)
PORT_BIT(0x00000100,IP_ACTIVE_HIGH,IPT_UNUSED)
- PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF11") PORT_CODE(KEYCODE_F11)
+ PORT_BIT(0x00000200,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("PF11") PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11))
PORT_BIT(0x00000400,IP_ACTIVE_HIGH,IPT_UNUSED)
PORT_BIT(0x00000800,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE6\xBC\xA2\xE5\xAD\x97\xE8\xBE\x9E\xE6\x9B\xB8 (Kanji Dictionary)")
PORT_BIT(0x00001000,IP_ACTIVE_HIGH,IPT_KEYBOARD) PORT_NAME("\xE5\x8D\x98\xE8\xAA\x9E\xE6\x8A\xB9\xE6\xB6\x88 (Word Deletion)")
@@ -2831,7 +2828,7 @@ void towns_state::towns_base(machine_config &config)
/* basic machine hardware */
I386(config, m_maincpu, 16000000);
m_maincpu->set_addrmap(AS_PROGRAM, &towns_state::towns_mem);
- m_maincpu->set_addrmap(AS_IO, &towns_state::towns_io);
+ m_maincpu->set_addrmap(AS_IO, &towns_state::towns_1g_io);
m_maincpu->set_vblank_int("screen", FUNC(towns_state::towns_vsync_irq));
m_maincpu->set_irq_acknowledge_callback("pic8259_master", FUNC(pic8259_device::inta_cb));
//MCFG_MACHINE_RESET_OVERRIDE(towns_state,towns)
@@ -2960,6 +2957,15 @@ void towns_state::towns(machine_config &config)
{
towns_base(config);
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
+
+ FMT_SCSI_SLOT(config, m_scsi_slot, fmt_scsi_default_devices, nullptr);
+ m_scsi_slot->irq_handler().set(FUNC(towns_state::towns_scsi_irq));
+ m_scsi_slot->drq_handler().set(FUNC(towns_state::towns_scsi_drq));
+
+ m_dma[0]->dma_read_callback<1>().set(m_scsi_slot, FUNC(fmt_scsi_slot_device::data_read));
+ m_dma[0]->dma_write_callback<1>().set(m_scsi_slot, FUNC(fmt_scsi_slot_device::data_write));
+ m_dma[1]->dma_read_callback<1>().set(m_scsi_slot, FUNC(fmt_scsi_slot_device::data_read));
+ m_dma[1]->dma_write_callback<1>().set(m_scsi_slot, FUNC(fmt_scsi_slot_device::data_write));
}
void towns16_state::townsux(machine_config &config)
@@ -2984,10 +2990,10 @@ void towns16_state::townsux(machine_config &config)
m_scsi->irq_handler().set(FUNC(towns16_state::towns_scsi_irq));
m_scsi->drq_handler().set(FUNC(towns16_state::towns_scsi_drq));
- m_dma[0]->dma_read_callback<1>().set(FUNC(towns16_state::towns_scsi_dma_r));
- m_dma[0]->dma_write_callback<1>().set(FUNC(towns16_state::towns_scsi_dma_w));
- m_dma[1]->dma_read_callback<1>().set(FUNC(towns16_state::towns_scsi_dma_r));
- m_dma[1]->dma_write_callback<1>().set(FUNC(towns16_state::towns_scsi_dma_w));
+ m_dma[0]->dma_read_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_r));
+ m_dma[0]->dma_write_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_w));
+ m_dma[1]->dma_read_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_r));
+ m_dma[1]->dma_write_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_w));
// 2 MB onboard, one SIMM slot with 2-8 MB
m_ram->set_default_size("2M").set_extra_options("4M,6M,10M");
@@ -2997,7 +3003,7 @@ void towns16_state::townsux(machine_config &config)
void towns_state::townssj(machine_config &config)
{
- towns(config);
+ towns_base(config);
I486(config.replace(), m_maincpu, 66000000);
m_maincpu->set_addrmap(AS_PROGRAM, &towns_state::towns_mem);
@@ -3017,13 +3023,15 @@ void towns_state::townssj(machine_config &config)
m_scsi->irq_handler().set(FUNC(towns_state::towns_scsi_irq));
m_scsi->drq_handler().set(FUNC(towns_state::towns_scsi_drq));
- m_dma[0]->dma_read_callback<1>().set(FUNC(towns_state::towns_scsi_dma_r));
- m_dma[0]->dma_write_callback<1>().set(FUNC(towns_state::towns_scsi_dma_w));
- m_dma[1]->dma_read_callback<1>().set(FUNC(towns_state::towns_scsi_dma_r));
- m_dma[1]->dma_write_callback<1>().set(FUNC(towns_state::towns_scsi_dma_w));
+ m_dma[0]->dma_read_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_r));
+ m_dma[0]->dma_write_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_w));
+ m_dma[1]->dma_read_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_r));
+ m_dma[1]->dma_write_callback<1>().set(m_scsi, FUNC(fmscsi_device::fmscsi_data_w));
// 4 MB (SJ2/SJ2A) or 8 MB (SJ26/SJ53) onboard, 2 SIMM slots with 4-32 MB each
m_ram->set_default_size("8M").set_extra_options("4M,12M,16M,20M,24M,28M,32M,36M,40M,44M,48M,52M,56M,68M,72M");
+
+ NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
}
void towns_state::townshr(machine_config &config)
diff --git a/src/mame/drivers/fp1100.cpp b/src/mame/drivers/fp1100.cpp
index dab8f080191..0c3208d75b1 100644
--- a/src/mame/drivers/fp1100.cpp
+++ b/src/mame/drivers/fp1100.cpp
@@ -137,7 +137,7 @@ private:
MC6845_UPDATE_ROW( fp1100_state::crtc_update_row )
{
const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u32 *p = &bitmap.pix32(y);
+ u32 *p = &bitmap.pix(y);
if (BIT(m_upd7801.porta, 4))
{ // green screen
diff --git a/src/mame/drivers/fp200.cpp b/src/mame/drivers/fp200.cpp
index bb8d027dc55..6794d2c5122 100644
--- a/src/mame/drivers/fp200.cpp
+++ b/src/mame/drivers/fp200.cpp
@@ -135,20 +135,16 @@ uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap
if(m_lcd.attr[x/8+yoffs*20] == 0x60 || m_lcd.attr[x/8+yoffs*20] == 0x50)
{
- uint8_t vram,pix;
-
- vram = m_lcd.vram[x/8+yoffs*20];
- pix = ((m_chargen[vram*8+(x & 7)]) >> (7-(yoffs & 7))) & 1;
- bitmap.pix16(y,x) = pix;
+ uint8_t const vram = m_lcd.vram[x/8+yoffs*20];
+ uint8_t const pix = ((m_chargen[vram*8+(x & 7)]) >> (7-(yoffs & 7))) & 1;
+ bitmap.pix(y,x) = pix;
}
/*
else if(m_lcd.attr[x/8+yoffs*20] == 0x40)
{
- uint8_t vram,pix;
-
- vram = m_lcd.vram[x/8+yoffs*20];
- pix = (vram) >> (7-(yoffs & 7)) & 1;
- bitmap.pix16(y,x) = pix;
+ uint8_t const vram = m_lcd.vram[x/8+yoffs*20];
+ uint8_t const pix = (vram) >> (7-(yoffs & 7)) & 1;
+ bitmap.pix(y,x) = pix;
}*/
}
}
@@ -166,19 +162,15 @@ uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap
if(m_lcd.attr[x/8+yoffs*20] == 0x60 || m_lcd.attr[x/8+yoffs*20] == 0x50)
{
- uint8_t vram,pix;
-
- vram = m_lcd.vram[x/8+yoffs*20];
- pix = ((m_chargen[vram*8+(x & 7)]) >> (7-(yoffs & 7))) & 1;
- bitmap.pix16(y,x) = pix;
+ uint8_t const vram = m_lcd.vram[x/8+yoffs*20];
+ uint8_t const pix = ((m_chargen[vram*8+(x & 7)]) >> (7-(yoffs & 7))) & 1;
+ bitmap.pix(y,x) = pix;
}
/*else if(m_lcd.attr[x/8+yoffs*20] == 0x40)
{
- uint8_t vram,pix;
-
- vram = m_lcd.vram[x/8+yoffs*20];
- pix = (vram) >> (7-(yoffs & 7)) & 1;
- bitmap.pix16(y,x) = pix;
+ uint8_t const vram = m_lcd.vram[x/8+yoffs*20];
+ uint8_t const pix = (vram) >> (7-(yoffs & 7)) & 1;
+ bitmap.pix(y,x) = pix;
}*/
}
}
diff --git a/src/mame/drivers/fp6000.cpp b/src/mame/drivers/fp6000.cpp
index b4f5ecff25a..51bec4e9682 100644
--- a/src/mame/drivers/fp6000.cpp
+++ b/src/mame/drivers/fp6000.cpp
@@ -243,15 +243,15 @@ uint16_t fp6000_state::unk_r()
MC6845_UPDATE_ROW( fp6000_state::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
- uint8_t *pcg = reinterpret_cast<uint8_t *>(m_pcg.target());
- uint32_t *vram = reinterpret_cast<uint32_t *>(m_gvram.target());
+ pen_t const *const pen = m_palette->pens();
+ uint8_t const *const pcg = reinterpret_cast<uint8_t *>(m_pcg.target());
+ uint32_t const *const vram = reinterpret_cast<uint32_t *>(m_gvram.target());
for (int x = 0; x < x_count; x++)
{
// text mode
- uint8_t code = (m_vram[ma + x] >> 0) & 0xff;
- uint8_t color = (m_vram[ma + x] >> 8) & 0x0f;
+ uint8_t const code = (m_vram[ma + x] >> 0) & 0xff;
+ uint8_t const color = (m_vram[ma + x] >> 8) & 0x0f;
uint8_t gfx = pcg[(code << 4) | ra];
// cursor?
@@ -260,20 +260,20 @@ MC6845_UPDATE_ROW( fp6000_state::crtc_update_row )
// draw 8 pixels of the character
for (int i = 0; i < 8; i++)
- bitmap.pix32(y, x * 8 + i) = BIT(gfx, 7 - i) ? pen[color] : 0;
+ bitmap.pix(y, x * 8 + i) = BIT(gfx, 7 - i) ? pen[color] : 0;
// graphics
- uint32_t data = vram[(ma << 3) + (ra * x_count) + x];
+ uint32_t const data = vram[(ma << 3) + (ra * x_count) + x];
// draw 8 gfx pixels
- if ((data >> 12) & 0x0f) bitmap.pix32(y, x * 8 + 0) = pen[(data >> 12) & 0x0f];
- if ((data >> 8) & 0x0f) bitmap.pix32(y, x * 8 + 1) = pen[(data >> 8) & 0x0f];
- if ((data >> 4) & 0x0f) bitmap.pix32(y, x * 8 + 2) = pen[(data >> 4) & 0x0f];
- if ((data >> 0) & 0x0f) bitmap.pix32(y, x * 8 + 3) = pen[(data >> 0) & 0x0f];
- if ((data >> 28) & 0x0f) bitmap.pix32(y, x * 8 + 4) = pen[(data >> 28) & 0x0f];
- if ((data >> 24) & 0x0f) bitmap.pix32(y, x * 8 + 5) = pen[(data >> 24) & 0x0f];
- if ((data >> 20) & 0x0f) bitmap.pix32(y, x * 8 + 6) = pen[(data >> 20) & 0x0f];
- if ((data >> 16) & 0x0f) bitmap.pix32(y, x * 8 + 7) = pen[(data >> 16) & 0x0f];
+ if ((data >> 12) & 0x0f) bitmap.pix(y, x * 8 + 0) = pen[(data >> 12) & 0x0f];
+ if ((data >> 8) & 0x0f) bitmap.pix(y, x * 8 + 1) = pen[(data >> 8) & 0x0f];
+ if ((data >> 4) & 0x0f) bitmap.pix(y, x * 8 + 2) = pen[(data >> 4) & 0x0f];
+ if ((data >> 0) & 0x0f) bitmap.pix(y, x * 8 + 3) = pen[(data >> 0) & 0x0f];
+ if ((data >> 28) & 0x0f) bitmap.pix(y, x * 8 + 4) = pen[(data >> 28) & 0x0f];
+ if ((data >> 24) & 0x0f) bitmap.pix(y, x * 8 + 5) = pen[(data >> 24) & 0x0f];
+ if ((data >> 20) & 0x0f) bitmap.pix(y, x * 8 + 6) = pen[(data >> 20) & 0x0f];
+ if ((data >> 16) & 0x0f) bitmap.pix(y, x * 8 + 7) = pen[(data >> 16) & 0x0f];
}
}
diff --git a/src/mame/drivers/fs3216.cpp b/src/mame/drivers/fs3216.cpp
index 5491a7a518b..a8ca0327d8e 100644
--- a/src/mame/drivers/fs3216.cpp
+++ b/src/mame/drivers/fs3216.cpp
@@ -141,7 +141,7 @@ void fs3216_state::machine_reset()
MC6845_UPDATE_ROW(fs3216_state::crt_update_row)
{
- u32 *px = &bitmap.pix32(y);
+ u32 *px = &bitmap.pix(y);
for (int i = 0; i < x_count; i++)
{
@@ -343,9 +343,9 @@ void fs3216_state::floppy_control_w(u8 data)
m_floppy_status &= 0xef;
}
+ m_fdc->reset_w(!BIT(data, 1));
if (!BIT(data, 1))
{
- m_fdc->soft_reset();
m_fdc_dma_count = 0;
m_fdc->tc_w(0);
}
diff --git a/src/mame/drivers/gaelco.cpp b/src/mame/drivers/gaelco.cpp
index c5f84c5dc1a..f68d28271c9 100644
--- a/src/mame/drivers/gaelco.cpp
+++ b/src/mame/drivers/gaelco.cpp
@@ -105,87 +105,87 @@ void gaelco_state::thoop_encrypted_w(address_space &space, offs_t offset, uint16
void gaelco_state::bigkarnk_map(address_map &map)
{
- map(0x000000, 0x07ffff).rom(); /* ROM */
- map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_w)).share("videoram"); /* Video RAM */
- map(0x102000, 0x103fff).ram(); /* Screen RAM */
- map(0x108000, 0x108007).writeonly().share("vregs"); /* Video Registers */
-// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); /* INT 6 ACK/Watchdog timer */
- map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); /* Palette */
- map(0x440000, 0x440fff).ram().share("spriteram"); /* Sprite RAM */
+ map(0x000000, 0x07ffff).rom(); // ROM
+ map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_w)).share("videoram"); // Video RAM
+ map(0x102000, 0x103fff).ram(); // Screen RAM
+ map(0x108000, 0x108007).writeonly().share("vregs"); // Video Registers
+// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); // INT 6 ACK/Watchdog timer
+ map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // Palette
+ map(0x440000, 0x440fff).ram().share("spriteram"); // Sprite RAM
map(0x700000, 0x700001).portr("DSW1");
map(0x700002, 0x700003).portr("DSW2");
map(0x700004, 0x700005).portr("P1");
map(0x700006, 0x700007).portr("P2");
map(0x700008, 0x700009).portr("SERVICE");
map(0x70000b, 0x70000b).select(0x000070).lw8(NAME([this] (offs_t offset, u8 data) { m_outlatch->write_d0(offset >> 4, data); }));
- map(0x70000f, 0x70000f).w(m_soundlatch, FUNC(generic_latch_8_device::write)); /* Triggers a FIRQ on the sound CPU */
- map(0xff8000, 0xffffff).ram(); /* Work RAM */
+ map(0x70000f, 0x70000f).w(m_soundlatch, FUNC(generic_latch_8_device::write)); // Triggers a FIRQ on the sound CPU
+ map(0xff8000, 0xffffff).ram(); // Work RAM
}
void gaelco_state::bigkarnk_snd_map(address_map &map)
{
- map(0x0000, 0x07ff).ram(); /* RAM */
- map(0x0800, 0x0801).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); /* OKI6295 */
-// map(0x0900, 0x0900).nopw(); /* enable sound output? */
- map(0x0a00, 0x0a01).rw("ymsnd", FUNC(ym3812_device::read), FUNC(ym3812_device::write)); /* YM3812 */
- map(0x0b00, 0x0b00).r(m_soundlatch, FUNC(generic_latch_8_device::read)); /* Sound latch */
- map(0x0c00, 0xffff).rom(); /* ROM */
+ map(0x0000, 0x07ff).ram(); // RAM
+ map(0x0800, 0x0801).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); // OKI6295
+// map(0x0900, 0x0900).nopw(); // Enable sound output?
+ map(0x0a00, 0x0a01).rw("ymsnd", FUNC(ym3812_device::read), FUNC(ym3812_device::write)); // YM3812
+ map(0x0b00, 0x0b00).r(m_soundlatch, FUNC(generic_latch_8_device::read)); // Sound latch
+ map(0x0c00, 0xffff).rom(); // ROM
}
void gaelco_state::maniacsq_map(address_map &map)
{
- map(0x000000, 0x0fffff).rom(); /* ROM */
- map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_w)).share("videoram"); /* Video RAM */
- map(0x102000, 0x103fff).ram(); /* Screen RAM */
- map(0x108000, 0x108007).writeonly().share("vregs"); /* Video Registers */
-// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); /* INT 6 ACK/Watchdog timer */
- map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); /* Palette */
- map(0x440000, 0x440fff).ram().share("spriteram"); /* Sprite RAM */
+ map(0x000000, 0x0fffff).rom(); // ROM
+ map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_w)).share("videoram"); // Video RAM
+ map(0x102000, 0x103fff).ram(); // Screen RAM
+ map(0x108000, 0x108007).writeonly().share("vregs"); // Video Registers
+// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); // INT 6 ACK/Watchdog timer
+ map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // Palette
+ map(0x440000, 0x440fff).ram().share("spriteram"); // Sprite RAM
map(0x700000, 0x700001).portr("DSW2");
map(0x700002, 0x700003).portr("DSW1");
map(0x700004, 0x700005).portr("P1");
map(0x700006, 0x700007).portr("P2");
map(0x70000d, 0x70000d).w(FUNC(gaelco_state::oki_bankswitch_w));
- map(0x70000f, 0x70000f).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); /* OKI6295 status register */
- map(0xff0000, 0xffffff).ram(); /* Work RAM */
+ map(0x70000f, 0x70000f).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); // OKI6295 status register
+ map(0xff0000, 0xffffff).ram(); // Work RAM
}
void gaelco_state::squash_map(address_map &map)
{
- map(0x000000, 0x0fffff).rom(); /* ROM */
- map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_encrypted_w)).share("videoram"); /* Video RAM */
- map(0x102000, 0x103fff).ram().w(FUNC(gaelco_state::encrypted_w)).share("screenram"); /* Screen RAM */
- map(0x108000, 0x108007).writeonly().share("vregs"); /* Video Registers */
-// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); /* INT 6 ACK/Watchdog timer */
- map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); /* Palette */
- map(0x440000, 0x440fff).ram().share("spriteram"); /* Sprite RAM */
+ map(0x000000, 0x0fffff).rom(); // ROM
+ map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::vram_encrypted_w)).share("videoram"); // Video RAM
+ map(0x102000, 0x103fff).ram().w(FUNC(gaelco_state::encrypted_w)).share("screenram"); // Screen RAM
+ map(0x108000, 0x108007).writeonly().share("vregs"); // Video Registers
+// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); // INT 6 ACK/Watchdog timer
+ map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // Palette
+ map(0x440000, 0x440fff).ram().share("spriteram"); // Sprite RAM
map(0x700000, 0x700001).portr("DSW2");
map(0x700002, 0x700003).portr("DSW1");
map(0x700004, 0x700005).portr("P1");
map(0x700006, 0x700007).portr("P2");
map(0x70000b, 0x70000b).select(0x000070).lw8(NAME([this] (offs_t offset, u8 data) { m_outlatch->write_d0(offset >> 4, data); }));
map(0x70000d, 0x70000d).w(FUNC(gaelco_state::oki_bankswitch_w));
- map(0x70000f, 0x70000f).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); /* OKI6295 status register */
- map(0xff0000, 0xffffff).ram(); /* Work RAM */
+ map(0x70000f, 0x70000f).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); // OKI6295 status register
+ map(0xff0000, 0xffffff).ram(); // Work RAM
}
void gaelco_state::thoop_map(address_map &map)
{
- map(0x000000, 0x0fffff).rom(); /* ROM */
- map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::thoop_vram_encrypted_w)).share("videoram"); /* Video RAM */
- map(0x102000, 0x103fff).ram().w(FUNC(gaelco_state::thoop_encrypted_w)).share("screenram"); /* Screen RAM */
- map(0x108000, 0x108007).writeonly().share("vregs"); /* Video Registers */
-// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); /* INT 6 ACK/Watchdog timer */
- map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); /* Palette */
- map(0x440000, 0x440fff).ram().share("spriteram"); /* Sprite RAM */
+ map(0x000000, 0x0fffff).rom(); // ROM
+ map(0x100000, 0x101fff).ram().w(FUNC(gaelco_state::thoop_vram_encrypted_w)).share("videoram"); // Video RAM
+ map(0x102000, 0x103fff).ram().w(FUNC(gaelco_state::thoop_encrypted_w)).share("screenram"); // Screen RAM
+ map(0x108000, 0x108007).writeonly().share("vregs"); // Video Registers
+// map(0x10800c, 0x10800d).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); // INT 6 ACK/Watchdog timer
+ map(0x200000, 0x2007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); // Palette
+ map(0x440000, 0x440fff).ram().share("spriteram"); // Sprite RAM
map(0x700000, 0x700001).portr("DSW2");
map(0x700002, 0x700003).portr("DSW1");
map(0x700004, 0x700005).portr("P1");
map(0x700006, 0x700007).portr("P2");
map(0x70000b, 0x70000b).select(0x000070).lw8(NAME([this] (offs_t offset, u8 data) { m_outlatch->write_d0(offset >> 4, data); }));
map(0x70000d, 0x70000d).w(FUNC(gaelco_state::oki_bankswitch_w));
- map(0x70000f, 0x70000f).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); /* OKI6295 status register */
- map(0xff0000, 0xffffff).ram(); /* Work RAM */
+ map(0x70000f, 0x70000f).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); // OKI6295 status register
+ map(0xff0000, 0xffffff).ram(); // Work RAM
}
@@ -202,7 +202,7 @@ void gaelco_state::oki_map(address_map &map)
*
*************************************/
-/* Common Inputs used by all the games */
+// Common Inputs used by all the games
static INPUT_PORTS_START( gaelco )
PORT_START("DSW1")
PORT_DIPNAME( 0x0f, 0x0f, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW1:8,7,6,5")
@@ -638,12 +638,12 @@ void gaelco_state::machine_start()
// TODO: verify all clocks (XTALs are 8.0MHz & 24.000 MHz) - One PCB reported to have 8867.23 kHz instead of 8MHz
void gaelco_state::bigkarnk(machine_config &config)
{
- /* basic machine hardware */
- M68000(config, m_maincpu, XTAL(24'000'000)/2); /* MC68000P10, 12 MHz? */
+ // Basic machine hardware
+ M68000(config, m_maincpu, XTAL(24'000'000)/2); // MC68000P10, 12 MHz?
m_maincpu->set_addrmap(AS_PROGRAM, &gaelco_state::bigkarnk_map);
m_maincpu->set_vblank_int("screen", FUNC(gaelco_state::irq6_line_hold));
- MC6809E(config, m_audiocpu, XTAL(8'000'000)/4); /* 68B09EP, 2 MHz? */
+ MC6809E(config, m_audiocpu, XTAL(8'000'000)/4); // 68B09EP, 2 MHz?
m_audiocpu->set_addrmap(AS_PROGRAM, &gaelco_state::bigkarnk_snd_map);
config.set_maximum_quantum(attotime::from_hz(600));
@@ -654,7 +654,7 @@ void gaelco_state::bigkarnk(machine_config &config)
m_outlatch->q_out_cb<2>().set(FUNC(gaelco_state::coin1_counter_w));
m_outlatch->q_out_cb<3>().set(FUNC(gaelco_state::coin2_counter_w));
- /* video hardware */
+ // Video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
@@ -668,7 +668,7 @@ void gaelco_state::bigkarnk(machine_config &config)
MCFG_VIDEO_START_OVERRIDE(gaelco_state,bigkarnk)
- /* sound hardware */
+ // Sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, m_soundlatch);
@@ -681,12 +681,12 @@ void gaelco_state::bigkarnk(machine_config &config)
void gaelco_state::maniacsq(machine_config &config)
{
- /* basic machine hardware */
+ // Basic machine hardware
M68000(config, m_maincpu, XTAL(24'000'000)/2); /* verified on pcb */
m_maincpu->set_addrmap(AS_PROGRAM, &gaelco_state::maniacsq_map);
m_maincpu->set_vblank_int("screen", FUNC(gaelco_state::irq6_line_hold));
- /* video hardware */
+ // Video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
@@ -700,7 +700,7 @@ void gaelco_state::maniacsq(machine_config &config)
MCFG_VIDEO_START_OVERRIDE(gaelco_state,maniacsq)
- /* sound hardware */
+ // Sound hardware
SPEAKER(config, "mono").front_center();
okim6295_device &oki(OKIM6295(config, "oki", XTAL(1'000'000), okim6295_device::PIN7_HIGH)); // pin 7 not verified
@@ -710,8 +710,8 @@ void gaelco_state::maniacsq(machine_config &config)
void gaelco_state::squash(machine_config &config)
{
- /* basic machine hardware */
- M68000(config, m_maincpu, XTAL(20'000'000)/2); /* verified on pcb */
+ // Basic machine hardware
+ M68000(config, m_maincpu, XTAL(20'000'000)/2); // Verified on PCB
m_maincpu->set_addrmap(AS_PROGRAM, &gaelco_state::squash_map);
m_maincpu->set_vblank_int("screen", FUNC(gaelco_state::irq6_line_hold));
@@ -724,7 +724,7 @@ void gaelco_state::squash(machine_config &config)
m_outlatch->q_out_cb<3>().set(FUNC(gaelco_state::coin2_counter_w));
m_outlatch->q_out_cb<4>().set_nop(); // used
- /* video hardware */
+ // Video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(58);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
@@ -738,7 +738,7 @@ void gaelco_state::squash(machine_config &config)
MCFG_VIDEO_START_OVERRIDE(gaelco_state,maniacsq)
- /* sound hardware */
+ // Sound hardware
SPEAKER(config, "mono").front_center();
okim6295_device &oki(OKIM6295(config, "oki", XTAL(1'000'000), okim6295_device::PIN7_HIGH)); /* verified on pcb */
@@ -748,8 +748,8 @@ void gaelco_state::squash(machine_config &config)
void gaelco_state::thoop(machine_config &config)
{
- /* basic machine hardware */
- M68000(config, m_maincpu, XTAL(24'000'000)/2); /* verified on pcb */
+ // Basic machine hardware
+ M68000(config, m_maincpu, XTAL(24'000'000)/2); // Verified on PCB
m_maincpu->set_addrmap(AS_PROGRAM, &gaelco_state::thoop_map);
m_maincpu->set_vblank_int("screen", FUNC(gaelco_state::irq6_line_hold));
@@ -762,7 +762,7 @@ void gaelco_state::thoop(machine_config &config)
m_outlatch->q_out_cb<3>().set(FUNC(gaelco_state::coin2_counter_w));
m_outlatch->q_out_cb<4>().set_nop(); // used
- /* video hardware */
+ // Video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500) /* not accurate */);
@@ -776,7 +776,7 @@ void gaelco_state::thoop(machine_config &config)
MCFG_VIDEO_START_OVERRIDE(gaelco_state,maniacsq)
- /* sound hardware */
+ // Sound hardware
SPEAKER(config, "mono").front_center();
okim6295_device &oki(OKIM6295(config, "oki", XTAL(1'000'000), okim6295_device::PIN7_HIGH)); // pin 7 not verified
@@ -791,12 +791,12 @@ void gaelco_state::thoop(machine_config &config)
*
*************************************/
-ROM_START( bigkarnk ) /* PCB silkscreened REF.901112 */
- ROM_REGION( 0x080000, "maincpu", 0 ) /* 68000 code */
+ROM_START( bigkarnk ) // PCB silkscreened REF.901112
+ ROM_REGION( 0x080000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "d16", 0x000000, 0x040000, CRC(44fb9c73) SHA1(c33852b37afea15482f4a43cb045434660e7a056) )
ROM_LOAD16_BYTE( "d19", 0x000001, 0x040000, CRC(ff79dfdd) SHA1(2bfa440299317967ba2018d3a148291ae0c144ae) )
- ROM_REGION( 0x01e000, "audiocpu", 0 ) /* 6809 code */
+ ROM_REGION( 0x01e000, "audiocpu", 0 ) // 6809 code
ROM_LOAD( "d5", 0x000000, 0x010000, CRC(3b73b9c5) SHA1(1b1c5545609a695dab87d611bd53e0c3dd91e6b7) )
ROM_REGION( 0x200000, "gfx1", 0 )
@@ -805,8 +805,12 @@ ROM_START( bigkarnk ) /* PCB silkscreened REF.901112 */
ROM_LOAD( "h8", 0x100000, 0x080000, CRC(83dce5a3) SHA1(b4f9473e93c96f4b86c446e89d13fd3ef2b03996) )
ROM_LOAD( "h6", 0x180000, 0x080000, CRC(24e84b24) SHA1(c0ad6ce1e4b8aa7b9c9a3db8bb0165e90f4b48ed) )
- ROM_REGION( 0x040000, "oki", 0 ) /* ADPCM samples - sound chip is OKIM6295 */
+ ROM_REGION( 0x040000, "oki", 0 ) // ADPCM samples - sound chip is OKIM6295
ROM_LOAD( "d1", 0x000000, 0x040000, CRC(26444ad1) SHA1(804101b9bbb6e1b6d43a1e9d91737f9c3b27802a) )
+
+ ROM_REGION( 0x26e, "plds", 0 )
+ ROM_LOAD( "bigkarnak_gal16v8.d6", 0x000, 0x117, BAD_DUMP CRC(587fe895) SHA1(bc244a50820ceff9bfbdc7f04bcac030198371ec) ) // Bruteforced but verified
+ ROM_LOAD( "bigkarnak_gal20v8.d21", 0x117, 0x157, BAD_DUMP CRC(0dcb286e) SHA1(4071af05ba0fd17446691e53bdbba736e416bf4a) ) // Bruteforced but verified
ROM_END
ROM_START( maniacsp ) /* PCB - REF 922804/2 */
@@ -816,17 +820,17 @@ ROM_START( maniacsp ) /* PCB - REF 922804/2 */
ROM_REGION( 0x200000, "gfx1", ROMREGION_ERASE00 )
ROM_LOAD( "f3", 0x000000, 0x040000, CRC(e7f6582b) SHA1(9e352edf2f71d0edecb54a11ab3fd0e3ec867d42) )
- /* 0x040000-0x07ffff empty */
+ // 0x040000-0x07ffff empty
ROM_LOAD( "f2", 0x080000, 0x040000, CRC(ca43a5ae) SHA1(8d2ed537be1dee60096a58b68b735fb50cab3285) )
- /* 0x0c0000-0x0fffff empty */
+ // 0x0c0000-0x0fffff empty
ROM_LOAD( "f1", 0x100000, 0x040000, CRC(fca112e8) SHA1(2a1412f8f1c856b18b6cc7794191d327a415266f) )
- /* 0x140000-0x17ffff empty */
+ // 0x140000-0x17ffff empty
ROM_LOAD( "f0", 0x180000, 0x040000, CRC(6e829ee8) SHA1(b602da8d987c1bafa41baf5d5e5d753e29ff5403) )
- /* 0x1c0000-0x1fffff empty */
+ // 0x1c0000-0x1fffff empty
- ROM_REGION( 0x080000, "oki", 0 ) /* ADPCM samples - sound chip is OKIM6295 */
+ ROM_REGION( 0x080000, "oki", 0 ) // ADPCM samples - sound chip is OKIM6295
ROM_LOAD( "c1", 0x000000, 0x080000, CRC(2557f2d6) SHA1(3a99388f2d845281f73a427d6dc797dce87b2f82) )
- /* 0x00000-0x2ffff is fixed, 0x30000-0x3ffff is bank switched from all the ROMs */
+ // 0x00000-0x2ffff is fixed, 0x30000-0x3ffff is bank switched from all the ROMs
ROM_END
@@ -1089,49 +1093,61 @@ Notes:
SQUASH_SOUND.1D 27C040 Sound
*/
-ROM_START( squash ) /* PCB - REF.922804/1 */
- ROM_REGION( 0x100000, "maincpu", 0 ) /* 68000 code */
+ROM_START( squash ) // PCB - REF.922804/1
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "squash.d18", 0x000000, 0x20000, CRC(ce7aae96) SHA1(4fe8666ae571bffc5a08fa68346c0623282989eb) )
ROM_LOAD16_BYTE( "squash.d16", 0x000001, 0x20000, CRC(8ffaedd7) SHA1(f4aada17ba67dd8b6c5a395e832bcbba2764c59d) )
ROM_REGION( 0x200000, "gfx1", 0 )
- ROM_LOAD( "squash.c09", 0x180000, 0x80000, CRC(0bb91c69) SHA1(8be945049ab411a4d49bd64bd3937542ec9ef9fb) ) /* encrypted video ram */
- ROM_LOAD( "squash.c10", 0x100000, 0x80000, CRC(892a035c) SHA1(d0156ceb9aa6639a1124c17fb12389be319bb51f) ) /* encrypted video ram */
- ROM_LOAD( "squash.c11", 0x080000, 0x80000, CRC(9e19694d) SHA1(1df4646f3147719fef516a37aa361ae26d9b23a2) ) /* encrypted video ram */
- ROM_LOAD( "squash.c12", 0x000000, 0x80000, CRC(5c440645) SHA1(4f2fc1647ffc549fa079f2dc0aaaceb447afdf44) ) /* encrypted video ram */
+ ROM_LOAD( "squash.c09", 0x180000, 0x80000, CRC(0bb91c69) SHA1(8be945049ab411a4d49bd64bd3937542ec9ef9fb) ) // Encrypted video RAM
+ ROM_LOAD( "squash.c10", 0x100000, 0x80000, CRC(892a035c) SHA1(d0156ceb9aa6639a1124c17fb12389be319bb51f) ) // Encrypted video RAM
+ ROM_LOAD( "squash.c11", 0x080000, 0x80000, CRC(9e19694d) SHA1(1df4646f3147719fef516a37aa361ae26d9b23a2) ) // Encrypted video RAM
+ ROM_LOAD( "squash.c12", 0x000000, 0x80000, CRC(5c440645) SHA1(4f2fc1647ffc549fa079f2dc0aaaceb447afdf44) ) // Encrypted video RAM
- ROM_REGION( 0x80000, "oki", 0 ) /* ADPCM samples - sound chip is OKIM6295 */
+ ROM_REGION( 0x80000, "oki", 0 ) // ADPCM samples - sound chip is OKIM6295
ROM_LOAD( "squash.d01", 0x000000, 0x80000, CRC(a1b9651b) SHA1(a396ba94889f70ea06d6330e3606b0f2497ff6ce) )
- /* 0x00000-0x2ffff is fixed, 0x30000-0x3ffff is bank switched from all the ROMs */
+ // 0x00000-0x2ffff is fixed, 0x30000-0x3ffff is bank switched from all the ROMs
+
+ ROM_REGION( 0x4dc, "plds", 0)
+ ROM_LOAD ( "squashv1_gal16v8.f2", 0x000, 0x117, CRC(d5ed5985) SHA1(a4e9c8e3a7774e2a02fbca3ddf8175cf251825ba) ) // Unprotected
+ ROM_LOAD ( "squashv1_gal16v8.j16", 0x117, 0x117, CRC(fe78b903) SHA1(c806e63ce56a77f631043c184a42bf77ebda8a09) ) // Unprotected
+ ROM_LOAD ( "squashv1_gal20v8.d21", 0x22e, 0x157, CRC(a715e392) SHA1(31ebc78b084d49cc2f6479cbd42738e6bfbfb46a) ) // Unprotected
+ ROM_LOAD ( "squashv1_gal20v8.h11", 0x385, 0x157, CRC(51e34bc2) SHA1(381a898b3afb709e7d8e0f87df106f23aec2ccbe) ) // Unprotected
ROM_END
-ROM_START( thoop ) /* PCB - REF.922804/1 */
- ROM_REGION( 0x100000, "maincpu", 0 ) /* 68000 code */
+ROM_START( thoop ) // PCB - REF.922804/1
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "th18dea1.040", 0x000000, 0x80000, CRC(59bad625) SHA1(28e058b2290bc5f7130b801014d026432f9e7fd5) )
ROM_LOAD16_BYTE( "th161eb4.020", 0x000001, 0x40000, CRC(6add61ed) SHA1(0e789d9a0ac19b6143044fbc04ab2227735b2a8f) )
ROM_REGION( 0x400000, "gfx1", 0 )
- ROM_LOAD( "c09", 0x300000, 0x040000, CRC(06f0edbf) SHA1(3cf2e5c29cd00b43d49a106084076f2ac0dbad98) ) /* encrypted video ram */
+ ROM_LOAD( "c09", 0x300000, 0x040000, CRC(06f0edbf) SHA1(3cf2e5c29cd00b43d49a106084076f2ac0dbad98) ) // Encrypted video RAM
ROM_CONTINUE( 0x380000, 0x040000 )
ROM_CONTINUE( 0x340000, 0x040000 )
ROM_CONTINUE( 0x3c0000, 0x040000 )
- ROM_LOAD( "c10", 0x200000, 0x040000, CRC(2d227085) SHA1(b224efd59ec83bb786fa92a23ef2d27ed36cab6c) ) /* encrypted video ram */
+ ROM_LOAD( "c10", 0x200000, 0x040000, CRC(2d227085) SHA1(b224efd59ec83bb786fa92a23ef2d27ed36cab6c) ) // Encrypted video RAM
ROM_CONTINUE( 0x280000, 0x040000 )
ROM_CONTINUE( 0x240000, 0x040000 )
ROM_CONTINUE( 0x2c0000, 0x040000 )
- ROM_LOAD( "c11", 0x100000, 0x040000, CRC(7403ef7e) SHA1(52a737816e25a07ada070ed3a5f40bbbd22ac8e0) ) /* encrypted video ram */
+ ROM_LOAD( "c11", 0x100000, 0x040000, CRC(7403ef7e) SHA1(52a737816e25a07ada070ed3a5f40bbbd22ac8e0) ) // Encrypted video RAM
ROM_CONTINUE( 0x180000, 0x040000 )
ROM_CONTINUE( 0x140000, 0x040000 )
ROM_CONTINUE( 0x1c0000, 0x040000 )
- ROM_LOAD( "c12", 0x000000, 0x040000, CRC(29a5ca36) SHA1(fdcfdefb3b02bfe34781fdd0295640caabe2a5fb) ) /* encrypted video ram */
+ ROM_LOAD( "c12", 0x000000, 0x040000, CRC(29a5ca36) SHA1(fdcfdefb3b02bfe34781fdd0295640caabe2a5fb) ) // Encrypted video RAM
ROM_CONTINUE( 0x080000, 0x040000 )
ROM_CONTINUE( 0x040000, 0x040000 )
ROM_CONTINUE( 0x0c0000, 0x040000 )
- ROM_REGION( 0x100000, "oki", 0 ) /* ADPCM samples - sound chip is OKIM6295 */
+ ROM_REGION( 0x100000, "oki", 0 ) // ADPCM samples - sound chip is OKIM6295
ROM_LOAD( "sound", 0x000000, 0x100000, CRC(99f80961) SHA1(de3a514a8f46dffd5f762e52aac1f4c3b08e2e18) )
- /* 0x00000-0x2ffff is fixed, 0x30000-0x3ffff is bank switched from all the ROMs */
+ // 0x00000-0x2ffff is fixed, 0x30000-0x3ffff is bank switched from all the ROMs
+
+ ROM_REGION( 0x4dc, "plds", 0)
+ ROM_LOAD ( "thunderhoop_gal16v8.f2", 0x000, 0x117, BAD_DUMP CRC(d5ed5985) SHA1(a4e9c8e3a7774e2a02fbca3ddf8175cf251825ba) ) // Bruteforced but verified
+ ROM_LOAD ( "thunderhoop_gal16v8.j16", 0x117, 0x117, BAD_DUMP CRC(fe78b903) SHA1(c806e63ce56a77f631043c184a42bf77ebda8a09) ) // Bruteforced but verified
+ ROM_LOAD ( "thunderhoop_gal20v8.d21", 0x22e, 0x157, BAD_DUMP CRC(a715e392) SHA1(31ebc78b084d49cc2f6479cbd42738e6bfbfb46a) ) // Bruteforced but verified
+ ROM_LOAD ( "thunderhoop_gal20v8.h11", 0x385, 0x157, BAD_DUMP CRC(51e34bc2) SHA1(381a898b3afb709e7d8e0f87df106f23aec2ccbe) ) // Bruteforced but verified
ROM_END
@@ -1142,13 +1158,13 @@ ROM_END
*
*************************************/
-GAME( 1991, bigkarnk, 0, bigkarnk, bigkarnk, gaelco_state, empty_init, ROT0, "Gaelco", "Big Karnak", MACHINE_SUPPORTS_SAVE )
-GAME( 1995, biomtoy, 0, maniacsq, biomtoy, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1885)", MACHINE_SUPPORTS_SAVE )
-GAME( 1995, biomtoya, biomtoy, maniacsq, biomtoy, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1884)", MACHINE_SUPPORTS_SAVE )
-GAME( 1995, biomtoyb, biomtoy, maniacsq, biomtoy, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1878)", MACHINE_SUPPORTS_SAVE )
-GAME( 1994, biomtoyc, biomtoy, maniacsq, biomtoyc, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1870)", MACHINE_SUPPORTS_SAVE )
+GAME( 1991, bigkarnk, 0, bigkarnk, bigkarnk, gaelco_state, empty_init, ROT0, "Gaelco", "Big Karnak", MACHINE_SUPPORTS_SAVE )
+GAME( 1995, biomtoy, 0, maniacsq, biomtoy, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1885)", MACHINE_SUPPORTS_SAVE )
+GAME( 1995, biomtoya, biomtoy, maniacsq, biomtoy, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1884)", MACHINE_SUPPORTS_SAVE )
+GAME( 1995, biomtoyb, biomtoy, maniacsq, biomtoy, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1878)", MACHINE_SUPPORTS_SAVE )
+GAME( 1994, biomtoyc, biomtoy, maniacsq, biomtoyc, gaelco_state, empty_init, ROT0, "Gaelco", "Biomechanical Toy (Ver. 1.0.1870)", MACHINE_SUPPORTS_SAVE )
GAME( 1994, bioplayc, biomtoy, maniacsq, bioplayc, gaelco_state, empty_init, ROT0, "Gaelco", "Bioplaything Cop (Ver. 1.0.1823, prototype)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) // copyright based on Ver. 1.0.1870
-GAME( 1996, maniacsp, maniacsq, maniacsq, maniacsq, gaelco_state, empty_init, ROT0, "Gaelco", "Maniac Square (prototype)", MACHINE_SUPPORTS_SAVE ) // sometimes listed as a 1992 proto?
-GAME( 1995, lastkm, 0, maniacsq, lastkm, gaelco_state, empty_init, ROT0, "Gaelco", "Last KM (Ver 1.0.0275)", MACHINE_SUPPORTS_SAVE ) // used on 'Salter' exercise bikes
-GAME( 1992, squash, 0, squash, squash, gaelco_state, empty_init, ROT0, "Gaelco", "Squash (Ver. 1.0)", MACHINE_SUPPORTS_SAVE )
-GAME( 1992, thoop, 0, thoop, thoop, gaelco_state, empty_init, ROT0, "Gaelco", "Thunder Hoop (Ver. 1, Checksum 02A09F7D)", MACHINE_SUPPORTS_SAVE ) // could be other versions, still Ver. 1 but different checksum listed on boot
+GAME( 1996, maniacsp, maniacsq, maniacsq, maniacsq, gaelco_state, empty_init, ROT0, "Gaelco", "Maniac Square (prototype)", MACHINE_SUPPORTS_SAVE ) // sometimes listed as a 1992 proto?
+GAME( 1995, lastkm, 0, maniacsq, lastkm, gaelco_state, empty_init, ROT0, "Gaelco", "Last KM (Ver 1.0.0275)", MACHINE_SUPPORTS_SAVE ) // used on 'Salter' exercise bikes
+GAME( 1992, squash, 0, squash, squash, gaelco_state, empty_init, ROT0, "Gaelco", "Squash (Ver. 1.0)", MACHINE_SUPPORTS_SAVE )
+GAME( 1992, thoop, 0, thoop, thoop, gaelco_state, empty_init, ROT0, "Gaelco", "Thunder Hoop (Ver. 1, Checksum 02A09F7D)", MACHINE_SUPPORTS_SAVE ) // could be other versions, still Ver. 1 but different checksum listed on boot
diff --git a/src/mame/drivers/gaelco2.cpp b/src/mame/drivers/gaelco2.cpp
index b24d2709298..8dd8abfa485 100644
--- a/src/mame/drivers/gaelco2.cpp
+++ b/src/mame/drivers/gaelco2.cpp
@@ -1102,8 +1102,8 @@ INPUT_PORTS_END
void bang_state::bang(machine_config &config)
{
- /* basic machine hardware */
- M68000(config, m_maincpu, XTAL(30'000'000) / 2); /* 15 MHz */
+ // Basic machine hardware
+ M68000(config, m_maincpu, XTAL(30'000'000) / 2); // 15 MHz
m_maincpu->set_addrmap(AS_PROGRAM, &bang_state::bang_map);
TIMER(config, "scantimer").configure_scanline(FUNC(bang_state::bang_irq), "screen", 0, 1);
@@ -1116,7 +1116,7 @@ void bang_state::bang(machine_config &config)
m_mainlatch->q_out_cb<5>().set("eeprom", FUNC(eeprom_serial_93cxx_device::clk_write)); /* EEPROM serial clock */
m_mainlatch->q_out_cb<6>().set("eeprom", FUNC(eeprom_serial_93cxx_device::cs_write)); /* EEPROM chip select */
- /* video hardware */
+ // Video hardware
BUFFERED_SPRITERAM16(config, m_spriteram);
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
@@ -1195,57 +1195,63 @@ JP3 - 4 pin light gun header (player 2)
*/
ROM_START( bang )
- ROM_REGION( 0x100000, "maincpu", 0 ) /* 68000 code */
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "bang53.ic53", 0x000000, 0x080000, CRC(014bb939) SHA1(bb245acf7a3bd4a56b3559518bcb8d0ae39dbaf4) )
ROM_LOAD16_BYTE( "bang55.ic55", 0x000001, 0x080000, CRC(582f8b1e) SHA1(c9b0d4c1dee71cdb2c01d49f20ffde32eddc9583) )
- ROM_REGION( 0x0a00000, "gfx1", 0 ) /* GFX + Sound */
- ROM_LOAD( "bang16.ic16", 0x0000000, 0x0080000, CRC(6ee4b878) SHA1(f646380d95650a60b5a17973bdfd3b80450a4d3b) ) /* GFX only */
- ROM_LOAD( "bang17.ic17", 0x0080000, 0x0080000, CRC(0c35aa6f) SHA1(df0474b1b9466d3c199e5aade39b7233f0cb45ee) ) /* GFX only */
- ROM_LOAD( "bang18.ic18", 0x0100000, 0x0080000, CRC(2056b1ad) SHA1(b796f92eef4bbb0efa12c53580e429b8a0aa394c) ) /* Sound only */
- ROM_FILL( 0x0180000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang9.ic9", 0x0200000, 0x0080000, CRC(078195dc) SHA1(362ff194e2579346dfc7af88559b0718bc36ec8a) ) /* GFX only */
- ROM_LOAD( "bang10.ic10", 0x0280000, 0x0080000, CRC(06711eeb) SHA1(3662ffe730fb54ee48925de9765f88be1abd5e4e) ) /* GFX only */
- ROM_LOAD( "bang11.ic11", 0x0300000, 0x0080000, CRC(2088d15c) SHA1(0c043ab9fd33836fa4b7ad60fd8e7cb96ffb6121) ) /* Sound only */
- ROM_FILL( 0x0380000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang1.ic1", 0x0400000, 0x0080000, CRC(e7b97b0f) SHA1(b5503687ae3ca0a0faa4b867a267d89dac788d6d) ) /* GFX only */
- ROM_LOAD( "bang2.ic2", 0x0480000, 0x0080000, CRC(ff297a8f) SHA1(28819a9d7b3cb177e7a7db3fe23a94f5cba33049) ) /* GFX only */
- ROM_LOAD( "bang3.ic3", 0x0500000, 0x0080000, CRC(d3da5d4f) SHA1(b9bea0b4d20ab0bfda3fac2bb1fab974c007aaf0) ) /* Sound only */
- ROM_FILL( 0x0580000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang20.ic20", 0x0600000, 0x0080000, CRC(a1145df8) SHA1(305cda041a6f201cb011982f1bf1fc6a4153a669) ) /* GFX only */
- ROM_LOAD( "bang13.ic13", 0x0680000, 0x0080000, CRC(fe3e8d07) SHA1(7a37561b1cf422b47cddb8751a6b6d57dec8baae) ) /* GFX only */
- ROM_LOAD( "bang5.ic5", 0x0700000, 0x0080000, CRC(9bee444c) SHA1(aebaa3306e7e5aada99ed469da9bf64507808cff) ) /* Sound only */
- ROM_FILL( 0x0780000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang21.ic21", 0x0800000, 0x0080000, CRC(fd93d7f2) SHA1(ff9d8eb5ac8d9757132aa6d79d2f7662c14cd650) ) /* GFX only */
- ROM_LOAD( "bang14.ic14", 0x0880000, 0x0080000, CRC(858fcbf9) SHA1(1e67431c8775666f4839bdc427fabf59ffc708c0) ) /* GFX only */
- ROM_FILL( 0x0900000, 0x0100000, 0x00 ) /* Empty */
+ ROM_REGION( 0x0a00000, "gfx1", 0 ) // GFX + Sound
+ ROM_LOAD( "bang16.ic16", 0x0000000, 0x0080000, CRC(6ee4b878) SHA1(f646380d95650a60b5a17973bdfd3b80450a4d3b) ) // GFX only
+ ROM_LOAD( "bang17.ic17", 0x0080000, 0x0080000, CRC(0c35aa6f) SHA1(df0474b1b9466d3c199e5aade39b7233f0cb45ee) ) // GFX only
+ ROM_LOAD( "bang18.ic18", 0x0100000, 0x0080000, CRC(2056b1ad) SHA1(b796f92eef4bbb0efa12c53580e429b8a0aa394c) ) // Sound only
+ ROM_FILL( 0x0180000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang9.ic9", 0x0200000, 0x0080000, CRC(078195dc) SHA1(362ff194e2579346dfc7af88559b0718bc36ec8a) ) // GFX only
+ ROM_LOAD( "bang10.ic10", 0x0280000, 0x0080000, CRC(06711eeb) SHA1(3662ffe730fb54ee48925de9765f88be1abd5e4e) ) // GFX only
+ ROM_LOAD( "bang11.ic11", 0x0300000, 0x0080000, CRC(2088d15c) SHA1(0c043ab9fd33836fa4b7ad60fd8e7cb96ffb6121) ) // Sound only
+ ROM_FILL( 0x0380000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang1.ic1", 0x0400000, 0x0080000, CRC(e7b97b0f) SHA1(b5503687ae3ca0a0faa4b867a267d89dac788d6d) ) // GFX only
+ ROM_LOAD( "bang2.ic2", 0x0480000, 0x0080000, CRC(ff297a8f) SHA1(28819a9d7b3cb177e7a7db3fe23a94f5cba33049) ) // GFX only
+ ROM_LOAD( "bang3.ic3", 0x0500000, 0x0080000, CRC(d3da5d4f) SHA1(b9bea0b4d20ab0bfda3fac2bb1fab974c007aaf0) ) // Sound only
+ ROM_FILL( 0x0580000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang20.ic20", 0x0600000, 0x0080000, CRC(a1145df8) SHA1(305cda041a6f201cb011982f1bf1fc6a4153a669) ) // GFX only
+ ROM_LOAD( "bang13.ic13", 0x0680000, 0x0080000, CRC(fe3e8d07) SHA1(7a37561b1cf422b47cddb8751a6b6d57dec8baae) ) // GFX only
+ ROM_LOAD( "bang5.ic5", 0x0700000, 0x0080000, CRC(9bee444c) SHA1(aebaa3306e7e5aada99ed469da9bf64507808cff) ) // Sound only
+ ROM_FILL( 0x0780000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang21.ic21", 0x0800000, 0x0080000, CRC(fd93d7f2) SHA1(ff9d8eb5ac8d9757132aa6d79d2f7662c14cd650) ) // GFX only
+ ROM_LOAD( "bang14.ic14", 0x0880000, 0x0080000, CRC(858fcbf9) SHA1(1e67431c8775666f4839bdc427fabf59ffc708c0) ) // GFX only
+ ROM_FILL( 0x0900000, 0x0100000, 0x00 ) // Empty
+
+ ROM_REGION( 0x400, "plds", 0)
+ ROM_LOAD ( "bang_gal16v8.ic56", 0x000, 0x117, BAD_DUMP CRC(226923ac) SHA1(b1cac5208673183f401702ba844e1016d5fa4ea0) ) // Bruteforced but verified
ROM_END
ROM_START( bangj )
- ROM_REGION( 0x100000, "maincpu", 0 ) /* 68000 code */
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "bang-a.ic53", 0x000000, 0x080000, CRC(5ee514e9) SHA1(b78b507d18de41be58049f5c597acd107ec1273f) )
ROM_LOAD16_BYTE( "bang-a.ic55", 0x000001, 0x080000, CRC(b90223ab) SHA1(7c097754a710169f41c574c3cc1a6346824853c4) )
- ROM_REGION( 0x0a00000, "gfx1", 0 ) /* GFX + Sound */
- ROM_LOAD( "bang-a.ic16", 0x0000000, 0x0080000, CRC(3b63acfc) SHA1(48f5598cdbc70f342d6b75909166571271920a8f) ) /* GFX only */
- ROM_LOAD( "bang-a.ic17", 0x0080000, 0x0080000, CRC(72865b80) SHA1(ec7753ea7961015149b9e6386fdeb9bd59aa962a) ) /* GFX only */
- ROM_LOAD( "bang18.ic18", 0x0100000, 0x0080000, CRC(2056b1ad) SHA1(b796f92eef4bbb0efa12c53580e429b8a0aa394c) ) /* Sound only */
- ROM_FILL( 0x0180000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang-a.ic9", 0x0200000, 0x0080000, CRC(3cb86360) SHA1(c803b3add253a552a1554714218740bdfca91764) ) /* GFX only */
- ROM_LOAD( "bang-a.ic10", 0x0280000, 0x0080000, CRC(03fdd777) SHA1(9eec194239f93d961ee9902a585c872dcdc7728f) ) /* GFX only */
- ROM_LOAD( "bang11.ic11", 0x0300000, 0x0080000, CRC(2088d15c) SHA1(0c043ab9fd33836fa4b7ad60fd8e7cb96ffb6121) ) /* Sound only */
- ROM_FILL( 0x0380000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang-a.ic1", 0x0400000, 0x0080000, CRC(965d0ad9) SHA1(eff521735129b7dd9366855c6312ed568950233c) ) /* GFX only */
- ROM_LOAD( "bang-a.ic2", 0x0480000, 0x0080000, CRC(8ea261a7) SHA1(50b59cf058ca03c0b8c888f6ddb40c720a210ece) ) /* GFX only */
- ROM_LOAD( "bang3.ic3", 0x0500000, 0x0080000, CRC(d3da5d4f) SHA1(b9bea0b4d20ab0bfda3fac2bb1fab974c007aaf0) ) /* Sound only */
- ROM_FILL( 0x0580000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang-a.ic20", 0x0600000, 0x0080000, CRC(4b828f3c) SHA1(5227a89c05c659a85d33f092c6778ce9d57a0236) ) /* GFX only */
- ROM_LOAD( "bang-a.ic13", 0x0680000, 0x0080000, CRC(d1146b92) SHA1(2b28d49fbffea6c038160fdab177bc0045195ca8) ) /* GFX only */
- ROM_LOAD( "bang5.ic5", 0x0700000, 0x0080000, CRC(9bee444c) SHA1(aebaa3306e7e5aada99ed469da9bf64507808cff) ) /* Sound only */
- ROM_FILL( 0x0780000, 0x0080000, 0x00 ) /* Empty */
- ROM_LOAD( "bang-a.ic21", 0x0800000, 0x0080000, CRC(531ce3b6) SHA1(196bb720591acc082f815b609a7cf1609510c8c1) ) /* GFX only */
- ROM_LOAD( "bang-a.ic14", 0x0880000, 0x0080000, CRC(f8e1cf84) SHA1(559c08584094e605635c5ef3a25534ea0bcfa199) ) /* GFX only */
- ROM_FILL( 0x0900000, 0x0100000, 0x00 ) /* Empty */
+ ROM_REGION( 0x0a00000, "gfx1", 0 ) // GFX + Sound
+ ROM_LOAD( "bang-a.ic16", 0x0000000, 0x0080000, CRC(3b63acfc) SHA1(48f5598cdbc70f342d6b75909166571271920a8f) ) // GFX only
+ ROM_LOAD( "bang-a.ic17", 0x0080000, 0x0080000, CRC(72865b80) SHA1(ec7753ea7961015149b9e6386fdeb9bd59aa962a) ) // GFX only
+ ROM_LOAD( "bang18.ic18", 0x0100000, 0x0080000, CRC(2056b1ad) SHA1(b796f92eef4bbb0efa12c53580e429b8a0aa394c) ) // Sound only
+ ROM_FILL( 0x0180000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang-a.ic9", 0x0200000, 0x0080000, CRC(3cb86360) SHA1(c803b3add253a552a1554714218740bdfca91764) ) // GFX only
+ ROM_LOAD( "bang-a.ic10", 0x0280000, 0x0080000, CRC(03fdd777) SHA1(9eec194239f93d961ee9902a585c872dcdc7728f) ) // GFX only
+ ROM_LOAD( "bang11.ic11", 0x0300000, 0x0080000, CRC(2088d15c) SHA1(0c043ab9fd33836fa4b7ad60fd8e7cb96ffb6121) ) // Sound only
+ ROM_FILL( 0x0380000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang-a.ic1", 0x0400000, 0x0080000, CRC(965d0ad9) SHA1(eff521735129b7dd9366855c6312ed568950233c) ) // GFX only
+ ROM_LOAD( "bang-a.ic2", 0x0480000, 0x0080000, CRC(8ea261a7) SHA1(50b59cf058ca03c0b8c888f6ddb40c720a210ece) ) // GFX only
+ ROM_LOAD( "bang3.ic3", 0x0500000, 0x0080000, CRC(d3da5d4f) SHA1(b9bea0b4d20ab0bfda3fac2bb1fab974c007aaf0) ) // Sound only
+ ROM_FILL( 0x0580000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang-a.ic20", 0x0600000, 0x0080000, CRC(4b828f3c) SHA1(5227a89c05c659a85d33f092c6778ce9d57a0236) ) // GFX only
+ ROM_LOAD( "bang-a.ic13", 0x0680000, 0x0080000, CRC(d1146b92) SHA1(2b28d49fbffea6c038160fdab177bc0045195ca8) ) // GFX only
+ ROM_LOAD( "bang5.ic5", 0x0700000, 0x0080000, CRC(9bee444c) SHA1(aebaa3306e7e5aada99ed469da9bf64507808cff) ) // Sound only
+ ROM_FILL( 0x0780000, 0x0080000, 0x00 ) // Empty
+ ROM_LOAD( "bang-a.ic21", 0x0800000, 0x0080000, CRC(531ce3b6) SHA1(196bb720591acc082f815b609a7cf1609510c8c1) ) // GFX only
+ ROM_LOAD( "bang-a.ic14", 0x0880000, 0x0080000, CRC(f8e1cf84) SHA1(559c08584094e605635c5ef3a25534ea0bcfa199) ) // GFX only
+ ROM_FILL( 0x0900000, 0x0100000, 0x00 ) // Empty
+
+ ROM_REGION( 0x117, "plds", 0)
+ ROM_LOAD ( "bang_gal16v8.ic56", 0x000, 0x117, BAD_DUMP CRC(226923ac) SHA1(b1cac5208673183f401702ba844e1016d5fa4ea0) ) // Bruteforced but verified
ROM_END
@@ -2165,7 +2171,7 @@ ROM_START( snowboar )
ROM_LOAD( "sb.a4", 0x0200000, 0x0080000, CRC(2ba3a5c8) SHA1(93de0382cbb41806ae3349ce7cfecdc1404bfb88) ) /* Sound only */
ROM_LOAD( "sb.a5", 0x0280000, 0x0080000, CRC(ae011eb3) SHA1(17223404640c55637364fa6e51cf07d8e64df085) ) /* Sound only */
ROM_FILL( 0x0300000, 0x0100000, 0x00 ) /* Empty */
- ROM_LOAD( "sb.b0", 0x0400000, 0x0080000, CRC(96c714cd) SHA1(c6225c43b88531a70436cc8a631b8ba401903e45) ) /* GFX only */
+ ROM_LOAD( "sb.b0", 0x0400000, 0x0080000, CRC(96c714cd) SHA1(c6225c43b88531a70436cc8a631b8ba401903e45) ) /* GFX only */
ROM_LOAD( "sb.b1", 0x0480000, 0x0080000, CRC(39a4c30c) SHA1(4598a68ef41483ba372aa3a40383de8eb70d706e) ) /* GFX only */
ROM_LOAD( "sb.b2", 0x0500000, 0x0080000, CRC(b58fcdd6) SHA1(21a8c00778be77165f89421fb2e3123244cf02c6) ) /* GFX only */
ROM_LOAD( "sb.b3", 0x0580000, 0x0080000, CRC(96afdebf) SHA1(880cfb365efa93bbee882aeb483ad6d75d8b7430) ) /* GFX only */
@@ -2575,11 +2581,11 @@ Also known to come with a GAE1 with various production codes including 449, 501
*/
ROM_START( wrally2 ) // REF: 950510-1
- ROM_REGION( 0x100000, "maincpu", 0 ) /* 68000 code */
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "wr2_64.ic64", 0x000000, 0x080000, CRC(4cdf4e1e) SHA1(a3b3ff4a70336b61c7bba5d518527bf4bd901867) )
ROM_LOAD16_BYTE( "wr2_63.ic63", 0x000001, 0x080000, CRC(94887c9f) SHA1(ad09f1fbeff4c3ba47f72346d261b22fa6a51457) )
- ROM_REGION( 0x8000, "gaelco_ds5002fp:sram", 0 ) /* DS5002FP code */
+ ROM_REGION( 0x8000, "gaelco_ds5002fp:sram", 0 ) // DS5002FP code
/* This SRAM has been dumped from 2 PCBs. The first had unused space filled as 0xff, the 2nd space was filled as 0x00.
In addition, the first had 2 bad bytes, one of which was identified at the time, the other not. For reference the
one that was not is "1938: 18 <-> 9B" (part of a data table)
@@ -2609,26 +2615,26 @@ ROM_START( wrally2 ) // REF: 950510-1
ROM_LOAD( "wrally2_ds5002fp_sram.bin", 0x00000, 0x8000, CRC(4c532e9e) SHA1(d0aad72b204d4abd3b8d7d5bbaf8d2d2f78edaa6) )
ROM_REGION( 0x100, "gaelco_ds5002fp:mcu:internal", ROMREGION_ERASE00 )
- /* these are the default states stored in NVRAM */
+ // These are the default states stored in NVRAM
DS5002FP_SET_MON( 0x69 )
DS5002FP_SET_RPCTL( 0x00 )
DS5002FP_SET_CRCR( 0x80 )
- ROM_REGION( 0x0a00000, "gfx1", 0 ) /* GFX + Sound */
- /* 0x0000000-0x06fffff filled in in the DRIVER_INIT */
- ROM_LOAD( "wr2_ic68.ic68", 0x0800000, 0x0100000, CRC(4a75ffaa) SHA1(ffae561ad4fa100398ab6b94d8dcb13e9fae4272) ) /* GFX only - read as 27C801 */
+ ROM_REGION( 0x0a00000, "gfx1", 0 ) // GFX + Sound
+ // 0x0000000-0x06fffff filled in in the DRIVER_INIT
+ ROM_LOAD( "wr2_ic68.ic68", 0x0800000, 0x0100000, CRC(4a75ffaa) SHA1(ffae561ad4fa100398ab6b94d8dcb13e9fae4272) ) // GFX only - read as 27C801
- ROM_REGION( 0x0600000, "gfx2", 0 ) /* Temporary storage */
- ROM_LOAD( "wr2_ic69.ic69", 0x0000000, 0x0400000, CRC(a174d196) SHA1(4a7da1cd288e73518143a027782f3140e6582cf4) ) /* GFX & Sound - read as 27C332 */
- ROM_LOAD( "wr2_ic70.ic70", 0x0400000, 0x0200000, CRC(8d1e43ba) SHA1(79eed51788c6c55a4347be70a3be4eb14a0d1747) ) /* GFX only - read as 27C160 */
+ ROM_REGION( 0x0600000, "gfx2", 0 ) // Temporary storage
+ ROM_LOAD( "wr2_ic69.ic69", 0x0000000, 0x0400000, CRC(a174d196) SHA1(4a7da1cd288e73518143a027782f3140e6582cf4) ) // GFX & Sound - read as 27C332
+ ROM_LOAD( "wr2_ic70.ic70", 0x0400000, 0x0200000, CRC(8d1e43ba) SHA1(79eed51788c6c55a4347be70a3be4eb14a0d1747) ) // GFX only - read as 27C160
ROM_END
ROM_START( wrally2a ) // REF: 950510
- ROM_REGION( 0x100000, "maincpu", 0 ) /* 68000 code */
+ ROM_REGION( 0x100000, "maincpu", 0 ) // 68000 code
ROM_LOAD16_BYTE( "wr2_64.ic64", 0x000000, 0x080000, CRC(4cdf4e1e) SHA1(a3b3ff4a70336b61c7bba5d518527bf4bd901867) )
ROM_LOAD16_BYTE( "wr2_63.ic63", 0x000001, 0x080000, CRC(94887c9f) SHA1(ad09f1fbeff4c3ba47f72346d261b22fa6a51457) )
- ROM_REGION( 0x8000, "gaelco_ds5002fp:sram", 0 ) /* DS5002FP code */
+ ROM_REGION( 0x8000, "gaelco_ds5002fp:sram", 0 ) // DS5002FP code
/* This SRAM has been dumped from 2 PCBs. The first had unused space filled as 0xff, the 2nd space was filled as 0x00.
In addition, the first had 2 bad bytes, one of which was identified at the time, the other not. For reference the
one that was not is "1938: 18 <-> 9B" (part of a data table)
@@ -2658,29 +2664,29 @@ ROM_START( wrally2a ) // REF: 950510
ROM_LOAD( "wrally2_ds5002fp_sram.bin", 0x00000, 0x8000, CRC(4c532e9e) SHA1(d0aad72b204d4abd3b8d7d5bbaf8d2d2f78edaa6) )
ROM_REGION( 0x100, "gaelco_ds5002fp:mcu:internal", ROMREGION_ERASE00 )
- /* these are the default states stored in NVRAM */
+ // These are the default states stored in NVRAM
DS5002FP_SET_MON( 0x69 )
DS5002FP_SET_RPCTL( 0x00 )
DS5002FP_SET_CRCR( 0x80 )
- ROM_REGION( 0x0a00000, "gfx1", 0 ) /* GFX + Sound */
- ROM_LOAD( "wr2.16d", 0x0000000, 0x0080000, CRC(ad26086b) SHA1(487ffaaca57c9d030fc486b8cae6735ee40a0ac3) ) /* GFX only */
- ROM_LOAD( "wr2.17d", 0x0080000, 0x0080000, CRC(c1ec0745) SHA1(a6c3ce9c889e6a53f4155f54d6655825af34a35b) ) /* GFX only */
- ROM_LOAD( "wr2.18d", 0x0100000, 0x0080000, CRC(e3617814) SHA1(9f9514052bb07d7e243f33b11bae409a444b7d9f) ) /* Sound only */
- ROM_LOAD( "wr2.19d", 0x0180000, 0x0080000, CRC(2dae988c) SHA1(a585e10b0e1519b828738b0b90698f8600082250) ) /* Sound only */
- ROM_LOAD( "wr2.09d", 0x0200000, 0x0080000, CRC(372d70c8) SHA1(a6d8419765eab1fa20c6d3ddff9d026adaab5cd9) ) /* GFX only */
- ROM_LOAD( "wr2.10d", 0x0280000, 0x0080000, CRC(5db67eb3) SHA1(faa58dafa26befb3291e5185ee04c39ce3b45b3f) ) /* GFX only */
- ROM_LOAD( "wr2.11d", 0x0300000, 0x0080000, CRC(ae66b97c) SHA1(bd0eba0b1c77864e06a9e136cfd834b35f200683) ) /* Sound only */
- ROM_LOAD( "wr2.12d", 0x0380000, 0x0080000, CRC(6dbdaa95) SHA1(f23df65e3df92d79f7b1e99d611c067a79fc849a) ) /* Sound only */
- ROM_LOAD( "wr2.01d", 0x0400000, 0x0080000, CRC(753a138d) SHA1(b05348af6d25e95208fc39007eb2082b759384e8) ) /* GFX only */
- ROM_LOAD( "wr2.02d", 0x0480000, 0x0080000, CRC(9c2a723c) SHA1(5259c8fa1ad73518e89a8df6e76a565b8f8799e3) ) /* GFX only */
- ROM_FILL( 0x0500000, 0x0100000, 0x00 ) /* Empty */
- ROM_LOAD( "wr2.20d", 0x0600000, 0x0080000, CRC(4f7ade84) SHA1(c8efcd4bcb1f2ad6ab8104ec0daea8324cefd3fd) ) /* GFX only */
- ROM_LOAD( "wr2.13d", 0x0680000, 0x0080000, CRC(a4cd32f8) SHA1(bc4cc73b7a58aecd735bf55bb5062baa6dd22f83) ) /* GFX only */
- ROM_FILL( 0x0700000, 0x0100000, 0x00 ) /* Empty */
- ROM_LOAD( "wr2.21d", 0x0800000, 0x0080000, CRC(899b0583) SHA1(a313e679980cc4da22bc70f2c7c9685af4f3d6df) ) /* GFX only */
- ROM_LOAD( "wr2.14d", 0x0880000, 0x0080000, CRC(6eb781d5) SHA1(d5c13db88e6de606b34805391cef9f3fbf09fac4) ) /* GFX only */
- ROM_FILL( 0x0900000, 0x0100000, 0x00 ) /* Empty */
+ ROM_REGION( 0x0a00000, "gfx1", 0 ) // GFX + Sound
+ ROM_LOAD( "wr2.16d", 0x0000000, 0x0080000, CRC(ad26086b) SHA1(487ffaaca57c9d030fc486b8cae6735ee40a0ac3) ) // GFX only
+ ROM_LOAD( "wr2.17d", 0x0080000, 0x0080000, CRC(c1ec0745) SHA1(a6c3ce9c889e6a53f4155f54d6655825af34a35b) ) // GFX only
+ ROM_LOAD( "wr2.18d", 0x0100000, 0x0080000, CRC(e3617814) SHA1(9f9514052bb07d7e243f33b11bae409a444b7d9f) ) // Sound only
+ ROM_LOAD( "wr2.19d", 0x0180000, 0x0080000, CRC(2dae988c) SHA1(a585e10b0e1519b828738b0b90698f8600082250) ) // Sound only
+ ROM_LOAD( "wr2.09d", 0x0200000, 0x0080000, CRC(372d70c8) SHA1(a6d8419765eab1fa20c6d3ddff9d026adaab5cd9) ) // GFX only
+ ROM_LOAD( "wr2.10d", 0x0280000, 0x0080000, CRC(5db67eb3) SHA1(faa58dafa26befb3291e5185ee04c39ce3b45b3f) ) // GFX only
+ ROM_LOAD( "wr2.11d", 0x0300000, 0x0080000, CRC(ae66b97c) SHA1(bd0eba0b1c77864e06a9e136cfd834b35f200683) ) // Sound only
+ ROM_LOAD( "wr2.12d", 0x0380000, 0x0080000, CRC(6dbdaa95) SHA1(f23df65e3df92d79f7b1e99d611c067a79fc849a) ) // Sound only
+ ROM_LOAD( "wr2.01d", 0x0400000, 0x0080000, CRC(753a138d) SHA1(b05348af6d25e95208fc39007eb2082b759384e8) ) // GFX only
+ ROM_LOAD( "wr2.02d", 0x0480000, 0x0080000, CRC(9c2a723c) SHA1(5259c8fa1ad73518e89a8df6e76a565b8f8799e3) ) // GFX only
+ ROM_FILL( 0x0500000, 0x0100000, 0x00 ) // Empty
+ ROM_LOAD( "wr2.20d", 0x0600000, 0x0080000, CRC(4f7ade84) SHA1(c8efcd4bcb1f2ad6ab8104ec0daea8324cefd3fd) ) // GFX only
+ ROM_LOAD( "wr2.13d", 0x0680000, 0x0080000, CRC(a4cd32f8) SHA1(bc4cc73b7a58aecd735bf55bb5062baa6dd22f83) ) // GFX only
+ ROM_FILL( 0x0700000, 0x0100000, 0x00 ) // Empty
+ ROM_LOAD( "wr2.21d", 0x0800000, 0x0080000, CRC(899b0583) SHA1(a313e679980cc4da22bc70f2c7c9685af4f3d6df) ) // GFX only
+ ROM_LOAD( "wr2.14d", 0x0880000, 0x0080000, CRC(6eb781d5) SHA1(d5c13db88e6de606b34805391cef9f3fbf09fac4) ) // GFX only
+ ROM_FILL( 0x0900000, 0x0100000, 0x00 ) // Empty
ROM_END
diff --git a/src/mame/drivers/galaga.cpp b/src/mame/drivers/galaga.cpp
index 75f79e07db7..5f90d0a126c 100644
--- a/src/mame/drivers/galaga.cpp
+++ b/src/mame/drivers/galaga.cpp
@@ -1639,6 +1639,8 @@ void bosco_state::bosco(machine_config &config)
WATCHDOG_TIMER(config, "watchdog").set_vblank_count(m_screen, 8);
+ config.set_maximum_quantum(attotime::from_hz(6000));
+
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(MASTER_CLOCK/3, 384, 0, 288, 264, 16, 224+16);
@@ -1716,6 +1718,8 @@ void galaga_state::galaga(machine_config &config)
WATCHDOG_TIMER(config, "watchdog").set_vblank_count(m_screen, 8);
+ config.set_maximum_quantum(attotime::from_hz(6000));
+
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(MASTER_CLOCK/3, 384, 0, 288, 264, 0, 224);
@@ -1834,6 +1838,8 @@ void xevious_state::xevious(machine_config &config)
WATCHDOG_TIMER(config, "watchdog").set_vblank_count(m_screen, 8);
+ config.set_maximum_quantum(attotime::from_hz(6000));
+
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(MASTER_CLOCK/3, 384, 0, 288, 264, 0, 224);
@@ -1952,6 +1958,8 @@ void digdug_state::digdug(machine_config &config)
WATCHDOG_TIMER(config, "watchdog");
+ config.set_maximum_quantum(attotime::from_hz(6000));
+
/* video hardware */
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(MASTER_CLOCK/3, 384, 0, 288, 264, 0, 224);
diff --git a/src/mame/drivers/galaxian.cpp b/src/mame/drivers/galaxian.cpp
index 9a3b5b9f375..cd93c2042d5 100644
--- a/src/mame/drivers/galaxian.cpp
+++ b/src/mame/drivers/galaxian.cpp
@@ -11683,6 +11683,26 @@ ROM_START( mandingarf )
ROM_LOAD( "6e.bin", 0x0000, 0x0020, BAD_DUMP CRC(4e3caeab) SHA1(a25083c3e36d28afdefe4af6e6d4f3155e303625) ) // not present, using mandinga PROM
ROM_END
+ROM_START( mandingac )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "2716-4.bin", 0x0000, 0x0800, CRC(a684a494) SHA1(76885bb3bdab09f46c7daa25164a2fdaa744742f) ) // 2716
+ ROM_LOAD( "2716-3.bin", 0x0800, 0x0800, CRC(f4038373) SHA1(8823b9816fc4ea03b92e08776c13610980f5ea7a) ) // 2716
+ ROM_LOAD( "2716-1.bin", 0x1000, 0x0800, CRC(96842877) SHA1(043ce4ed2628a209ca21cc42516c02366cd9f1fa) ) // 2716
+ ROM_LOAD( "2716-9.bin", 0x1800, 0x0800, CRC(b69f9f71) SHA1(cb781d61a481c493e89605bc0edc6a092d8b4d56) ) // 2716
+ ROM_LOAD( "2716-8.bin", 0x2000, 0x0800, CRC(400cf1bb) SHA1(06c891f7581b0c1036f6845ea847cd20b6f5dedc) ) // 2716
+ ROM_LOAD( "2716-7.bin", 0x2800, 0x0800, CRC(5382f7ed) SHA1(425ec2c2caf404fc8ab13ee38d6567413022e1a1) ) // 2716
+ ROM_LOAD( "2716-6.bin", 0x3000, 0x0800, CRC(c4e63305) SHA1(e03aed5ad89305ffc243cff8ff147ec82419c7bc) ) // 2716
+ ROM_LOAD( "2716-5.bin", 0x3800, 0x0800, CRC(8a4018ae) SHA1(9aba6f4527c59b0b016038236d5a6074e65966f6) ) // 2716
+ ROM_LOAD( "2716-2.bin", 0xc000, 0x0800, CRC(d8bf57e7) SHA1(421a0fa02fccbc52d460fafec6437bd2b7564056) ) // 2716
+
+ ROM_REGION( 0x1000, "gfx1", 0 )
+ ROM_LOAD( "2716-10.bin", 0x0000, 0x0800, CRC(2082ad0a) SHA1(c6014d9575e92adf09b0961c2158a779ebe940c4) ) // 2716
+ ROM_LOAD( "2716-11.bin", 0x0800, 0x0800, CRC(1891fc68) SHA1(6d03f5092fd73462c9d81c1a64e39120d9f10aea) ) // 2716
+
+ ROM_REGION( 0x0020, "proms", 0 )
+ ROM_LOAD( "82s123.bin", 0x0000, 0x0020, CRC(4e3caeab) SHA1(a25083c3e36d28afdefe4af6e6d4f3155e303625) ) // 82s123
+ROM_END
+
ROM_START( olmandingo )
ROM_REGION( 0x10000, "maincpu", 0 )
ROM_LOAD( "olmandingo_1.bin", 0x0000, 0x0800, CRC(b5b9fcd9) SHA1(7a134de30041ac18521274f330eb4afe349da2db) )
@@ -11703,24 +11723,24 @@ ROM_START( olmandingo )
ROM_LOAD( "olmandingo_pr.bin", 0x0000, 0x0020, CRC(c3ac9467) SHA1(f382ad5a34d282056c78a5ec00c30ec43772bae2) )
ROM_END
-ROM_START( mandingac )
+ROM_START( olmandingc )
ROM_REGION( 0x10000, "maincpu", 0 )
- ROM_LOAD( "2716-4.bin", 0x0000, 0x0800, CRC(a684a494) SHA1(76885bb3bdab09f46c7daa25164a2fdaa744742f) ) // 2716
- ROM_LOAD( "2716-3.bin", 0x0800, 0x0800, CRC(f4038373) SHA1(8823b9816fc4ea03b92e08776c13610980f5ea7a) ) // 2716
- ROM_LOAD( "2716-1.bin", 0x1000, 0x0800, CRC(96842877) SHA1(043ce4ed2628a209ca21cc42516c02366cd9f1fa) ) // 2716
- ROM_LOAD( "2716-9.bin", 0x1800, 0x0800, CRC(b69f9f71) SHA1(cb781d61a481c493e89605bc0edc6a092d8b4d56) ) // 2716
- ROM_LOAD( "2716-8.bin", 0x2000, 0x0800, CRC(400cf1bb) SHA1(06c891f7581b0c1036f6845ea847cd20b6f5dedc) ) // 2716
- ROM_LOAD( "2716-7.bin", 0x2800, 0x0800, CRC(5382f7ed) SHA1(425ec2c2caf404fc8ab13ee38d6567413022e1a1) ) // 2716
- ROM_LOAD( "2716-6.bin", 0x3000, 0x0800, CRC(c4e63305) SHA1(e03aed5ad89305ffc243cff8ff147ec82419c7bc) ) // 2716
- ROM_LOAD( "2716-5.bin", 0x3800, 0x0800, CRC(8a4018ae) SHA1(9aba6f4527c59b0b016038236d5a6074e65966f6) ) // 2716
- ROM_LOAD( "2716-2.bin", 0xc000, 0x0800, CRC(d8bf57e7) SHA1(421a0fa02fccbc52d460fafec6437bd2b7564056) ) // 2716
+ ROM_LOAD( "omc_1-2716.bin", 0x0000, 0x0800, CRC(b5b9fcd9) SHA1(7a134de30041ac18521274f330eb4afe349da2db) )
+ ROM_LOAD( "omc_2-2716.bin", 0x0800, 0x0800, CRC(f4038373) SHA1(8823b9816fc4ea03b92e08776c13610980f5ea7a) )
+ ROM_LOAD( "omc_4-2716.bin", 0x1000, 0x0800, CRC(96842877) SHA1(043ce4ed2628a209ca21cc42516c02366cd9f1fa) )
+ ROM_LOAD( "omc_5-2516.bin", 0x1800, 0x0800, CRC(29873461) SHA1(7d0ee9a82f02163b4cc6a7097e88ae34e96ebf58) )
+ ROM_LOAD( "omc_6-2516.bin", 0x2000, 0x0800, CRC(3f536791) SHA1(e1ba306c4f9063db8d7a9f3d702986d205e480dc) )
+ ROM_LOAD( "omc_7-2516.bin", 0x2800, 0x0800, CRC(5382f7ed) SHA1(425ec2c2caf404fc8ab13ee38d6567413022e1a1) )
+ ROM_LOAD( "omc_8-2716.bin", 0x3000, 0x0800, CRC(e78d0c6d) SHA1(947ac20463384ca0721875954d59ec4ae15b0670) )
+ ROM_LOAD( "omc_9-2516.bin", 0x3800, 0x0800, CRC(8a4018ae) SHA1(9aba6f4527c59b0b016038236d5a6074e65966f6) )
+ ROM_LOAD( "omc_3-2716.bin", 0xc000, 0x0800, CRC(e4cbb827) SHA1(4efa49bd7486b4fa77d7faa130e842f4030f822b) )
ROM_REGION( 0x1000, "gfx1", 0 )
- ROM_LOAD( "2716-10.bin", 0x0000, 0x0800, CRC(2082ad0a) SHA1(c6014d9575e92adf09b0961c2158a779ebe940c4) ) // 2716
- ROM_LOAD( "2716-11.bin", 0x0800, 0x0800, CRC(1891fc68) SHA1(6d03f5092fd73462c9d81c1a64e39120d9f10aea) ) // 2716
+ ROM_LOAD( "omc_10-2516.bin", 0x0000, 0x0800, CRC(2c51f2f1) SHA1(6a7a7dcedfa1f9f6f1964c7c67f5f766f551a258) )
+ ROM_LOAD( "omc_11-2716.bin", 0x0800, 0x0800, CRC(3029f94f) SHA1(3b432b42e79f8b0a7d65e197f373a04e3c92ff20) )
ROM_REGION( 0x0020, "proms", 0 )
- ROM_LOAD( "82s123.bin", 0x0000, 0x0020, CRC(4e3caeab) SHA1(a25083c3e36d28afdefe4af6e6d4f3155e303625) ) // 82s123
+ ROM_LOAD( "omc_27s19.bin", 0x0000, 0x0020, CRC(6a0c7d87) SHA1(140335d85c67c75b65689d4e76d29863c209cf32) )
ROM_END
ROM_START( theend )
@@ -13371,19 +13391,20 @@ GAME( 1981, turpin, turtles, turtles, turpin, galaxian_state, init_
GAME( 1981, 600, turtles, turtles, turtles, galaxian_state, init_turtles, ROT90, "Konami", "600", MACHINE_SUPPORTS_SAVE )
GAME( 1981, turpins, turtles, turpins, turtles, galaxian_state, init_turtles, ROT90, "bootleg", "Turpin (bootleg on Super Cobra hardware)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) // needs different sound timer
-GAME( 1982, amidar, 0, turtles, amidaru, galaxian_state, init_turtles, ROT90, "Konami", "Amidar", MACHINE_SUPPORTS_SAVE )
-GAME( 1981, amidar1, amidar, turtles, amidar, galaxian_state, init_turtles, ROT90, "Konami", "Amidar (older)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, amidaru, amidar, turtles, amidaru, galaxian_state, init_turtles, ROT90, "Konami (Stern Electronics license)", "Amidar (Stern Electronics)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, amidaro, amidar, turtles, amidaro, galaxian_state, init_turtles, ROT90, "Konami (Olympia license)", "Amidar (Olympia)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, amidarb, amidar, turtles, amidaru, galaxian_state, init_turtles, ROT90, "bootleg", "Amidar (bootleg)", MACHINE_SUPPORTS_SAVE ) // Similar to Amigo bootleg
-GAME( 1982, amigo, amidar, turtles, amidaru, galaxian_state, init_turtles, ROT90, "bootleg", "Amigo (bootleg of Amidar, set 1)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, amigo2, amidar, amigo2, amidaru, galaxian_state, init_amigo2, ROT90, "bootleg", "Amigo (bootleg of Amidar, set 2)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) // sound timer might be different?
-GAME( 1982, amidars, amidar, scramble, amidars, galaxian_state, init_scramble, ROT90, "Konami", "Amidar (Scramble hardware)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, mandinga, amidar, scramble, amidars, galaxian_state, init_mandinga, ROT90, "bootleg (Artemi)", "Mandinga (Artemi bootleg of Amidar)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // color PROM needs bitswap<8> on addressing, reference: http://www.youtube.com/watch?v=6uGK4AZxV2U
-GAME( 1982, mandingaeg, amidar, scramble, amidars, galaxian_state, init_mandingaeg, ROT90, "bootleg (Electrogame S.A.)", "Mandinga (Electrogame S.A. bootleg of Amidar)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE )
-GAME( 1982, mandingarf, amidar, mandingarf, mandingarf, galaxian_state, init_galaxian, ROT90, "bootleg (Recreativos Franco S.A.)", "Mandanga (bootleg of Mandinga on Galaxian hardware, set 1)", MACHINE_NO_COCKTAIL | MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // assume same issue as mandinga
-GAME( 1982, olmandingo, amidar, mandingarf, olmandingo, galaxian_state, init_galaxian, ROT90, "bootleg", "Olivmandingo (Spanish bootleg of Mandinga on Galaxian hardware)", MACHINE_SUPPORTS_SAVE )
-GAME( 1982, mandingac, amidar, mandingarf, mandingarf, galaxian_state, init_galaxian, ROT90, "bootleg (Centromatic)", "Mandanga (bootleg of Mandinga on Galaxian hardware, set 2)", MACHINE_NO_COCKTAIL | MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // assume same issue as mandinga
+GAME( 1982, amidar, 0, turtles, amidaru, galaxian_state, init_turtles, ROT90, "Konami", "Amidar", MACHINE_SUPPORTS_SAVE )
+GAME( 1981, amidar1, amidar, turtles, amidar, galaxian_state, init_turtles, ROT90, "Konami", "Amidar (older)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, amidaru, amidar, turtles, amidaru, galaxian_state, init_turtles, ROT90, "Konami (Stern Electronics license)", "Amidar (Stern Electronics)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, amidaro, amidar, turtles, amidaro, galaxian_state, init_turtles, ROT90, "Konami (Olympia license)", "Amidar (Olympia)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, amidarb, amidar, turtles, amidaru, galaxian_state, init_turtles, ROT90, "bootleg", "Amidar (bootleg)", MACHINE_SUPPORTS_SAVE ) // Similar to Amigo bootleg
+GAME( 1982, amigo, amidar, turtles, amidaru, galaxian_state, init_turtles, ROT90, "bootleg", "Amigo (bootleg of Amidar, set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, amigo2, amidar, amigo2, amidaru, galaxian_state, init_amigo2, ROT90, "bootleg", "Amigo (bootleg of Amidar, set 2)", MACHINE_SUPPORTS_SAVE | MACHINE_IMPERFECT_SOUND ) // sound timer might be different?
+GAME( 1982, amidars, amidar, scramble, amidars, galaxian_state, init_scramble, ROT90, "Konami", "Amidar (Scramble hardware)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, mandinga, amidar, scramble, amidars, galaxian_state, init_mandinga, ROT90, "bootleg (Artemi)", "Mandinga (Artemi bootleg of Amidar)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // color PROM needs bitswap<8> on addressing, reference: http://www.youtube.com/watch?v=6uGK4AZxV2U
+GAME( 1982, mandingaeg, amidar, scramble, amidars, galaxian_state, init_mandingaeg, ROT90, "bootleg (Electrogame S.A.)", "Mandinga (Electrogame S.A. bootleg of Amidar)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE )
+GAME( 1982, mandingarf, amidar, mandingarf, mandingarf, galaxian_state, init_galaxian, ROT90, "bootleg (Recreativos Franco S.A.)", "Mandanga (bootleg of Mandinga on Galaxian hardware, set 1)", MACHINE_NO_COCKTAIL | MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // assume same issue as mandinga
+GAME( 1982, mandingac, amidar, mandingarf, mandingarf, galaxian_state, init_galaxian, ROT90, "bootleg (Centromatic)", "Mandanga (bootleg of Mandinga on Galaxian hardware, set 2)", MACHINE_NO_COCKTAIL | MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // assume same issue as mandinga
+GAME( 1982, olmandingo, amidar, mandingarf, olmandingo, galaxian_state, init_galaxian, ROT90, "bootleg", "Olivmandingo (Spanish bootleg of Mandinga on Galaxian hardware, set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1982, olmandingc, amidar, mandingarf, olmandingo, galaxian_state, init_galaxian, ROT90, "bootleg (Calfesa)", "Olivmandingo (Spanish bootleg of Mandinga on Galaxian hardware, set 2)", MACHINE_SUPPORTS_SAVE )
// The End/Scramble based hardware
GAME( 1980, theend, 0, theend, theend, galaxian_state, init_theend, ROT90, "Konami", "The End", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/galgame.cpp b/src/mame/drivers/galgame.cpp
index cbfb4a7c6be..53fa633f66b 100644
--- a/src/mame/drivers/galgame.cpp
+++ b/src/mame/drivers/galgame.cpp
@@ -187,7 +187,7 @@ uint32_t galaxygame_state::screen_update_galaxygame(screen_device &screen, bitma
bitmap.fill(m_palette->black_pen(), cliprect);
for (int i = 0; i < m_point_display_list_index; i++ )
{
- bitmap.pix16(m_point_display_list[i].x >> 7, m_point_display_list[i].y >> 7) = 1;
+ bitmap.pix(m_point_display_list[i].x >> 7, m_point_display_list[i].y >> 7) = 1;
}
return 0;
}
diff --git a/src/mame/drivers/galpani3.cpp b/src/mame/drivers/galpani3.cpp
index 0ffb68cd319..6e56e73c5db 100644
--- a/src/mame/drivers/galpani3.cpp
+++ b/src/mame/drivers/galpani3.cpp
@@ -190,7 +190,7 @@ void galpani3_state::video_start()
uint32_t galpani3_state::screen_update_galpani3(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const pen_t *paldata = m_palette->pens();
+ pen_t const *const paldata = m_palette->pens();
bitmap.fill(0, cliprect);
@@ -198,137 +198,134 @@ uint32_t galpani3_state::screen_update_galpani3(screen_device &screen, bitmap_rg
// popmessage("%02x %02x", m_grap2[0]->m_framebuffer_bright2, m_grap2[1]->m_framebuffer_bright2);
+ for (int drawy=cliprect.min_y;drawy<=cliprect.max_y;drawy++)
{
- int drawy, drawx;
- for (drawy=cliprect.min_y;drawy<=cliprect.max_y;drawy++)
- {
- uint16_t* sprline = &m_sprite_bitmap.pix16(drawy);
- uint16_t* srcline1 = m_grap2[0]->m_framebuffer.get() + ((drawy+m_grap2[0]->m_framebuffer_scrolly+11)&0x1ff) * 0x200;
- uint16_t* srcline2 = m_grap2[1]->m_framebuffer.get() + ((drawy+m_grap2[1]->m_framebuffer_scrolly+11)&0x1ff) * 0x200;
- uint16_t* srcline3 = m_grap2[2]->m_framebuffer.get() + ((drawy+m_grap2[2]->m_framebuffer_scrolly+11)&0x1ff) * 0x200;
+ uint16_t const *const sprline = &m_sprite_bitmap.pix(drawy);
+ uint16_t const *const srcline1 = m_grap2[0]->m_framebuffer.get() + ((drawy+m_grap2[0]->m_framebuffer_scrolly+11)&0x1ff) * 0x200;
+ uint16_t const *const srcline2 = m_grap2[1]->m_framebuffer.get() + ((drawy+m_grap2[1]->m_framebuffer_scrolly+11)&0x1ff) * 0x200;
+ uint16_t const *const srcline3 = m_grap2[2]->m_framebuffer.get() + ((drawy+m_grap2[2]->m_framebuffer_scrolly+11)&0x1ff) * 0x200;
- uint16_t* priline = m_priority_buffer + ((drawy+m_priority_buffer_scrolly+11)&0x1ff) * 0x200;
+ uint16_t const *const priline = m_priority_buffer + ((drawy+m_priority_buffer_scrolly+11)&0x1ff) * 0x200;
- uint32_t* dst = &bitmap.pix32(drawy & 0x3ff);
+ uint32_t *const dst = &bitmap.pix(drawy & 0x3ff);
- for (drawx=cliprect.min_x;drawx<=cliprect.max_x;drawx++)
- {
- int sproffs = drawx & 0x3ff;
- int srcoffs1 = (drawx+m_grap2[0]->m_framebuffer_scrollx+67)&0x1ff;
- int srcoffs2 = (drawx+m_grap2[1]->m_framebuffer_scrollx+67)&0x1ff;
- int srcoffs3 = (drawx+m_grap2[2]->m_framebuffer_scrollx+67)&0x1ff;
+ for (int drawx=cliprect.min_x;drawx<=cliprect.max_x;drawx++)
+ {
+ int sproffs = drawx & 0x3ff;
+ int srcoffs1 = (drawx+m_grap2[0]->m_framebuffer_scrollx+67)&0x1ff;
+ int srcoffs2 = (drawx+m_grap2[1]->m_framebuffer_scrollx+67)&0x1ff;
+ int srcoffs3 = (drawx+m_grap2[2]->m_framebuffer_scrollx+67)&0x1ff;
- int prioffs = (drawx+m_priority_buffer_scrollx+66)&0x1ff;
+ int prioffs = (drawx+m_priority_buffer_scrollx+66)&0x1ff;
- uint16_t sprdat = sprline[sproffs];
- uint8_t dat1 = srcline1[srcoffs1];
- uint8_t dat2 = srcline2[srcoffs2];
- uint8_t dat3 = srcline3[srcoffs3];
+ uint16_t sprdat = sprline[sproffs];
+ uint8_t dat1 = srcline1[srcoffs1];
+ uint8_t dat2 = srcline2[srcoffs2];
+ uint8_t dat3 = srcline3[srcoffs3];
- uint8_t pridat = priline[prioffs];
+ uint8_t pridat = priline[prioffs];
- // TODO : Verify priorities, blendings from real PCB.
- if (pridat==0x0f) // relates to the area you've drawn over
+ // TODO : Verify priorities, blendings from real PCB.
+ if (pridat==0x0f) // relates to the area you've drawn over
+ {
+ SPRITE_DRAW_PIXEL(0x0000);
+ if (m_grap2[2]->m_framebuffer_enable)
{
- SPRITE_DRAW_PIXEL(0x0000);
- if (m_grap2[2]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(2, dat3);
- }
- SPRITE_DRAW_PIXEL(0x4000);
- if (dat1 && m_grap2[0]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(0, dat1);
- }
- SPRITE_DRAW_PIXEL(0x8000);
- if (dat2 && m_grap2[1]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(1, dat2);
- }
- SPRITE_DRAW_PIXEL(0xc000);
+ FB_DRAW_PIXEL(2, dat3);
}
- else if (pridat==0xcf) // the girl
+ SPRITE_DRAW_PIXEL(0x4000);
+ if (dat1 && m_grap2[0]->m_framebuffer_enable)
{
- SPRITE_DRAW_PIXEL(0x0000);
- if (m_grap2[0]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(0, 0x100);
- }
- SPRITE_DRAW_PIXEL(0x4000);
- if (m_grap2[1]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(1, 0x100);
- }
- SPRITE_DRAW_PIXEL(0x8000);
- if (dat3 && m_grap2[2]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(2, dat3);
- }
- SPRITE_DRAW_PIXEL(0xc000);
+ FB_DRAW_PIXEL(0, dat1);
}
- else if (pridat==0x30) // during the 'gals boxes' on the intro
+ SPRITE_DRAW_PIXEL(0x8000);
+ if (dat2 && m_grap2[1]->m_framebuffer_enable)
{
- SPRITE_DRAW_PIXEL(0x0000);
- if (m_grap2[1]->m_framebuffer_enable) // TODO : Opaqued and Swapped order?
- {
- FB_DRAW_PIXEL(1, dat2);
- }
- SPRITE_DRAW_PIXEL(0x4000);
- if (dat1 && m_grap2[0]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(0, dat1);
- }
- SPRITE_DRAW_PIXEL(0x8000);
- if (dat3 && m_grap2[2]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(2, dat3);
- }
- SPRITE_DRAW_PIXEL(0xc000);
+ FB_DRAW_PIXEL(1, dat2);
}
- else
+ SPRITE_DRAW_PIXEL(0xc000);
+ }
+ else if (pridat==0xcf) // the girl
+ {
+ SPRITE_DRAW_PIXEL(0x0000);
+ if (m_grap2[0]->m_framebuffer_enable)
{
- SPRITE_DRAW_PIXEL(0x0000);
- if (m_grap2[0]->m_framebuffer_enable) // TODO : Opaque drawing 1st framebuffer in real PCB?
- {
- FB_DRAW_PIXEL(0, dat1);
- }
- SPRITE_DRAW_PIXEL(0x4000);
- if (dat2 && m_grap2[1]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(1, dat2);
- }
- SPRITE_DRAW_PIXEL(0x8000);
- if (dat3 && m_grap2[2]->m_framebuffer_enable)
- {
- FB_DRAW_PIXEL(2, dat3);
- }
- SPRITE_DRAW_PIXEL(0xc000);
+ FB_DRAW_PIXEL(0, 0x100);
}
-
- /*
- else if (pridat==0x2f) // area outside of the girl
+ SPRITE_DRAW_PIXEL(0x4000);
+ if (m_grap2[1]->m_framebuffer_enable)
{
- //dst[drawx] = machine().rand()&0x3fff;
+ FB_DRAW_PIXEL(1, 0x100);
}
-
- else if (pridat==0x00) // the initial line / box that gets drawn
+ SPRITE_DRAW_PIXEL(0x8000);
+ if (dat3 && m_grap2[2]->m_framebuffer_enable)
+ {
+ FB_DRAW_PIXEL(2, dat3);
+ }
+ SPRITE_DRAW_PIXEL(0xc000);
+ }
+ else if (pridat==0x30) // during the 'gals boxes' on the intro
+ {
+ SPRITE_DRAW_PIXEL(0x0000);
+ if (m_grap2[1]->m_framebuffer_enable) // TODO : Opaqued and Swapped order?
+ {
+ FB_DRAW_PIXEL(1, dat2);
+ }
+ SPRITE_DRAW_PIXEL(0x4000);
+ if (dat1 && m_grap2[0]->m_framebuffer_enable)
+ {
+ FB_DRAW_PIXEL(0, dat1);
+ }
+ SPRITE_DRAW_PIXEL(0x8000);
+ if (dat3 && m_grap2[2]->m_framebuffer_enable)
{
- //dst[drawx] = machine().rand()&0x3fff;
+ FB_DRAW_PIXEL(2, dat3);
}
- else if (pridat==0x30) // during the 'gals boxes' on the intro
+ SPRITE_DRAW_PIXEL(0xc000);
+ }
+ else
+ {
+ SPRITE_DRAW_PIXEL(0x0000);
+ if (m_grap2[0]->m_framebuffer_enable) // TODO : Opaque drawing 1st framebuffer in real PCB?
{
- //dst[drawx] = machine().rand()&0x3fff;
+ FB_DRAW_PIXEL(0, dat1);
}
- else if (pridat==0x0c) // 'nice' at end of level
+ SPRITE_DRAW_PIXEL(0x4000);
+ if (dat2 && m_grap2[1]->m_framebuffer_enable)
{
- //dst[drawx] = machine().rand()&0x3fff;
+ FB_DRAW_PIXEL(1, dat2);
}
- else
+ SPRITE_DRAW_PIXEL(0x8000);
+ if (dat3 && m_grap2[2]->m_framebuffer_enable)
{
- //printf("%02x, ",pridat);
+ FB_DRAW_PIXEL(2, dat3);
}
- */
+ SPRITE_DRAW_PIXEL(0xc000);
+ }
+
+ /*
+ else if (pridat==0x2f) // area outside of the girl
+ {
+ //dst[drawx] = machine().rand()&0x3fff;
+ }
+
+ else if (pridat==0x00) // the initial line / box that gets drawn
+ {
+ //dst[drawx] = machine().rand()&0x3fff;
+ }
+ else if (pridat==0x30) // during the 'gals boxes' on the intro
+ {
+ //dst[drawx] = machine().rand()&0x3fff;
+ }
+ else if (pridat==0x0c) // 'nice' at end of level
+ {
+ //dst[drawx] = machine().rand()&0x3fff;
+ }
+ else
+ {
+ //printf("%02x, ",pridat);
}
+ */
}
}
return 0;
diff --git a/src/mame/drivers/galpanic_ms.cpp b/src/mame/drivers/galpanic_ms.cpp
index f94e85e1de7..7401d06caf5 100644
--- a/src/mame/drivers/galpanic_ms.cpp
+++ b/src/mame/drivers/galpanic_ms.cpp
@@ -272,7 +272,7 @@ uint32_t galspanic_ms_state::screen_update_backgrounds(screen_device &screen, bi
count = 0;
for (int y = 0; y < 256; y++)
{
- uint16_t *const dest = &bitmap.pix16(y);
+ uint16_t *const dest = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
uint16_t dat = (m_bg_rgb555_pixram[count] & 0xfffe)>>1;
@@ -285,7 +285,7 @@ uint32_t galspanic_ms_state::screen_update_backgrounds(screen_device &screen, bi
count = 0;
for (int y = 0; y < 256; y++)
{
- uint16_t *const dest = &bitmap.pix16(y);
+ uint16_t *const dest = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
uint16_t const dat = m_fg_ind8_pixram[count] & 0x7ff;
diff --git a/src/mame/drivers/gamecstl.cpp b/src/mame/drivers/gamecstl.cpp
index 0207bd9dd2b..699c0b9ed55 100644
--- a/src/mame/drivers/gamecstl.cpp
+++ b/src/mame/drivers/gamecstl.cpp
@@ -137,16 +137,14 @@ void gamecstl_state::video_start()
void gamecstl_state::draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect, gfx_element *gfx, int ch, int att, int x, int y)
{
- int i,j;
- const uint8_t *dp;
int index = 0;
- dp = gfx->get_data(ch);
+ uint8_t const *const dp = gfx->get_data(ch);
- for (j=y; j < y+8; j++)
+ for (int j=y; j < y+8; j++)
{
- uint16_t *p = &bitmap.pix16(j);
+ uint16_t *const p = &bitmap.pix(j);
- for (i=x; i < x+8; i++)
+ for (int i=x; i < x+8; i++)
{
uint8_t pen = dp[index++];
if (pen)
@@ -159,16 +157,15 @@ void gamecstl_state::draw_char(bitmap_ind16 &bitmap, const rectangle &cliprect,
uint32_t gamecstl_state::screen_update_gamecstl(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int i, j;
gfx_element *gfx = m_gfxdecode->gfx(0);
- uint32_t *cga = m_cga_ram;
+ uint32_t const *const cga = m_cga_ram;
int index = 0;
bitmap.fill(0, cliprect);
- for (j=0; j < 25; j++)
+ for (int j=0; j < 25; j++)
{
- for (i=0; i < 80; i+=2)
+ for (int i=0; i < 80; i+=2)
{
int att0 = (cga[index] >> 8) & 0xff;
int ch0 = (cga[index] >> 0) & 0xff;
diff --git a/src/mame/drivers/gameking.cpp b/src/mame/drivers/gameking.cpp
index b381b324244..0e02f8f42a5 100644
--- a/src/mame/drivers/gameking.cpp
+++ b/src/mame/drivers/gameking.cpp
@@ -153,10 +153,10 @@ uint32_t gameking_state::screen_update_gameking(screen_device &screen, bitmap_in
for (int x=0, j=0;j<48/4;x+=4, j++)
{
uint8_t data=maincpu_ram->read_byte(lssa+j+i*12);
- bitmap.pix16(y, x+3)=data&3;
- bitmap.pix16(y, x+2)=(data>>2)&3;
- bitmap.pix16(y, x+1)=(data>>4)&3;
- bitmap.pix16(y, x)=(data>>6)&3;
+ bitmap.pix(y, x+3)=data&3;
+ bitmap.pix(y, x+2)=(data>>2)&3;
+ bitmap.pix(y, x+1)=(data>>4)&3;
+ bitmap.pix(y, x)=(data>>6)&3;
}
}
return 0;
@@ -188,24 +188,24 @@ uint32_t gameking_state::screen_update_gameking3(screen_device& screen, bitmap_r
switch (i % 3)
{
case 0:
- bitmap.pix32(y, x + 3) = rgb_t(0, gameking3_intensities[data&3], 0);
- bitmap.pix32(y + 1, x + 2) = rgb_t(gameking3_intensities[(data>>2)&3], 0, 0);
- bitmap.pix32(y, x + 1) = rgb_t(0, gameking3_intensities[(data>>4)&3], 0);
- bitmap.pix32(y + 1, x) = rgb_t(gameking3_intensities[(data>>6)&3], 0, 0);
+ bitmap.pix(y, x + 3) = rgb_t(0, gameking3_intensities[data&3], 0);
+ bitmap.pix(y + 1, x + 2) = rgb_t(gameking3_intensities[(data>>2)&3], 0, 0);
+ bitmap.pix(y, x + 1) = rgb_t(0, gameking3_intensities[(data>>4)&3], 0);
+ bitmap.pix(y + 1, x) = rgb_t(gameking3_intensities[(data>>6)&3], 0, 0);
break;
case 1:
- bitmap.pix32(y, x + 3) = rgb_t(0, 0, gameking3_intensities[data&3]);
- bitmap.pix32(y + 1, x+2) = rgb_t(0, gameking3_intensities[(data>>2)&3], 0);
- bitmap.pix32(y, x + 1) = rgb_t(0, 0, gameking3_intensities[(data>>4)&3]);
- bitmap.pix32(y + 1, x) = rgb_t(0, gameking3_intensities[(data>>6)&3], 0);
+ bitmap.pix(y, x + 3) = rgb_t(0, 0, gameking3_intensities[data&3]);
+ bitmap.pix(y + 1, x+2) = rgb_t(0, gameking3_intensities[(data>>2)&3], 0);
+ bitmap.pix(y, x + 1) = rgb_t(0, 0, gameking3_intensities[(data>>4)&3]);
+ bitmap.pix(y + 1, x) = rgb_t(0, gameking3_intensities[(data>>6)&3], 0);
break;
case 2:
- bitmap.pix32(y, x + 3) = rgb_t(gameking3_intensities[data&3], 0, 0);
- bitmap.pix32(y + 1, x+2) = rgb_t(0, 0, gameking3_intensities[(data>>2)&3]);
- bitmap.pix32(y, x + 1) = rgb_t(gameking3_intensities[(data>>4)&3], 0, 0);
- bitmap.pix32(y + 1, x) = rgb_t(0, 0, gameking3_intensities[(data>>6)&3]);
+ bitmap.pix(y, x + 3) = rgb_t(gameking3_intensities[data&3], 0, 0);
+ bitmap.pix(y + 1, x+2) = rgb_t(0, 0, gameking3_intensities[(data>>2)&3]);
+ bitmap.pix(y, x + 1) = rgb_t(gameking3_intensities[(data>>4)&3], 0, 0);
+ bitmap.pix(y + 1, x) = rgb_t(0, 0, gameking3_intensities[(data>>6)&3]);
break;
}
}
@@ -216,12 +216,12 @@ uint32_t gameking_state::screen_update_gameking3(screen_device& screen, bitmap_r
{
for (int x = y & 1; x < 160; x += 2)
{
- rgb_t l = rgb_t(x == 0 ? 0 : bitmap.pix32(y, x - 1));
- rgb_t r = rgb_t(x == 159 ? 0 : bitmap.pix32(y, x + 1));
- rgb_t u = rgb_t(y == 0 ? 0 : bitmap.pix32(y - 1, x));
- rgb_t d = rgb_t(y == 159 ? 0 : bitmap.pix32(y + 1, x));
+ rgb_t l = rgb_t(x == 0 ? 0 : bitmap.pix(y, x - 1));
+ rgb_t r = rgb_t(x == 159 ? 0 : bitmap.pix(y, x + 1));
+ rgb_t u = rgb_t(y == 0 ? 0 : bitmap.pix(y - 1, x));
+ rgb_t d = rgb_t(y == 159 ? 0 : bitmap.pix(y + 1, x));
- bitmap.pix32(y, x) = rgb_t(
+ bitmap.pix(y, x) = rgb_t(
((u.r() + d.r()) * 2 + l.r() + r.r()) / 3,
((u.g() + d.g()) * 2 + l.g() + r.g()) / 3,
((u.b() + d.b()) * 2 + l.b() + r.b()) / 3
diff --git a/src/mame/drivers/gei.cpp b/src/mame/drivers/gei.cpp
index d7d3dadd732..fa12d4e20cf 100644
--- a/src/mame/drivers/gei.cpp
+++ b/src/mame/drivers/gei.cpp
@@ -235,7 +235,7 @@ void gei_state::gei_bitmap_w(offs_t offset, uint8_t data)
sy = (sy + m_yadd) & 0xff;
for (int i = 0; i < 8; i++)
- m_bitmap.pix16(sy, sx + i) = m_color[8 - i - 1];
+ m_bitmap.pix(sy, sx + i) = m_color[8 - i - 1];
}
void gei_state::video_start()
diff --git a/src/mame/drivers/generalplus_gpl16250_rom.cpp b/src/mame/drivers/generalplus_gpl16250_rom.cpp
index 0f6a192e7e9..9a118332720 100644
--- a/src/mame/drivers/generalplus_gpl16250_rom.cpp
+++ b/src/mame/drivers/generalplus_gpl16250_rom.cpp
@@ -416,6 +416,14 @@ ROM_START( myac220 )
ROM_LOAD16_WORD_SWAP( "myarcadegogamerportable.bin", 0x0000000, 0x8000000, BAD_DUMP CRC(c929a2fa) SHA1(e99007ccc45a268267b4ea0efaf22e3117f5a6bd) ) // several sections seemed to be erased, was repaired with data from tkmag220, likely good but should be verified
ROM_END
+ROM_START( beijuehh )
+ //ROM_REGION16_BE( 0x40000, "maincpu:internal", ROMREGION_ERASE00 ) // not on this model? (or at least not this size, as CS base is different)
+ //ROM_LOAD16_WORD_SWAP( "internal.rom", 0x00000, 0x40000, NO_DUMP )
+
+ ROM_REGION( 0x8000000, "maincpu", ROMREGION_ERASE00 )
+ ROM_LOAD16_WORD_SWAP( "beijeu.bin", 0x0000000, 0x8000000, CRC(e7b968af) SHA1(a39a3a70e6e0827e4395e09e55983eb9e9348e4a) ) // some address lines might be swapped
+ROM_END
+
void tkmag220_game_state::tkmag220(machine_config &config)
{
gcm394_game_state::base(config);
@@ -486,6 +494,9 @@ CONS(201?, myac220, 0, 0, tkmag220, tkmag220, tkmag220_game_state, empt
CONS(2012, imgame, 0, 0, tkmag220, tkmag220, tkmag220_game_state, empty_init, "I'm Game", "I'm Game! GP120 (Family Sport 120-in-1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
// a 180 game Family Sport I'm Game! also exists (and some Famiclones)
+// memory mapping needs figuring out
+CONS(201?, beijuehh, 0, 0, tkmag220, tkmag220, tkmag220_game_state, empty_init, "Beijue", "Beijue 16 Bit Handheld Games (Game Boy style case)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS )
+
// die on this one is 'GCM420'
CONS(2013, gormiti, 0, 0, base, gormiti, gormiti_game_state, empty_init, "Giochi Preziosi", "Gormiti Game Arena (Spain)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND)
diff --git a/src/mame/drivers/generalplus_gpl162xx_lcdtype.cpp b/src/mame/drivers/generalplus_gpl162xx_lcdtype.cpp
new file mode 100644
index 00000000000..c7b03fbacba
--- /dev/null
+++ b/src/mame/drivers/generalplus_gpl162xx_lcdtype.cpp
@@ -0,0 +1,886 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+/* These contain a similar game selection to the devices in unk6502_st2xxx.cpp but on updated hardware
+
+ The hardware appears to be an abuse of the GPL16250 SoC. The palette and sprite banks are used, but as work-ram
+ rather than for their intended purpose, and the rest of the GPL16250 video hardware is either entirely bypassed
+ or doesn't exist. All video is software rendered and output directly to the LCD Controller.
+
+ If this is confirmed via a decap then this should be merged with the GPL16250 implementation.
+
+ The coding of these is similar to the unk6502_st2xxx.cpp too, with all game specific function calls being loaded
+ on the fly from the SPI to a tiny portion of work RAM, with graphics likewise being loaded and decompressed for
+ every draw call.
+
+ pcp8718 / pcp8728 / bkid218
+ to access test mode hold up + left on startup.
+ (bkid218 cursor in test menu can't be moved in emulation, works on unit, why?)
+*/
+
+
+#include "emu.h"
+
+#include "cpu/unsp/unsp.h"
+#include "machine/bl_handhelds_menucontrol.h"
+
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+
+#define LOG_GPL162XX_LCDTYPE (1U << 1)
+#define LOG_GPL162XX_LCDTYPE_SELECT_SIM (1U << 2)
+#define LOG_GPL162XX_LCDTYPE_IO_PORT (1U << 3)
+
+#define LOG_ALL (LOG_GPL162XX_LCDTYPE | LOG_GPL162XX_LCDTYPE_SELECT_SIM | LOG_GPL162XX_LCDTYPE_IO_PORT)
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+
+class gpl162xx_lcdtype_state : public driver_device
+{
+public:
+ gpl162xx_lcdtype_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_mainrom(*this, "maincpu"),
+ m_mainram(*this, "mainram"),
+ m_palette(*this, "palette"),
+ m_screen(*this, "screen"),
+ m_spirom(*this, "spi"),
+ m_io_in0(*this, "IN0"),
+ m_io_in1(*this, "IN1"),
+ m_menucontrol(*this, "menucontrol")
+ { }
+
+ void gpl162xx_lcdtype(machine_config &config);
+
+private:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ required_device<unsp_20_device> m_maincpu;
+ required_region_ptr<uint16_t> m_mainrom;
+ required_shared_ptr<uint16_t> m_mainram;
+
+ required_device<palette_device> m_palette;
+ required_device<screen_device> m_screen;
+
+ void map(address_map &map);
+
+ required_region_ptr<uint8_t> m_spirom;
+
+ uint16_t unk_7abf_r();
+ uint16_t io_7860_r();
+ uint16_t unk_780f_r();
+
+ void io_7860_w(uint16_t data);
+ uint16_t m_7860;
+
+ void unk_7862_w(uint16_t data);
+ void unk_7863_w(uint16_t data);
+
+ void unk_7868_w(uint16_t data);
+ uint16_t unk_7868_r();
+ uint16_t m_7868;
+
+ void bankswitch_707e_w(uint16_t data);
+ uint16_t bankswitch_707e_r();
+ uint16_t m_707e_bank;
+
+ void bankswitch_703a_w(uint16_t data);
+ uint16_t bankswitch_703a_r();
+ uint16_t m_703a_bank;
+
+ void bankedram_7300_w(offs_t offset, uint16_t data);
+ uint16_t bankedram_7300_r(offs_t offset);
+ uint16_t m_bankedram_7300[0x400];
+
+ void bankedram_7400_w(offs_t offset, uint16_t data);
+ uint16_t bankedram_7400_r(offs_t offset);
+ uint16_t m_bankedram_7400[0x800];
+
+ void system_dma_params_channel0_w(offs_t offset, uint16_t data);
+ uint16_t system_dma_params_channel0_r(offs_t offset);
+
+ uint16_t m_dmaregs[8];
+
+ void lcd_w(uint16_t data);
+ void lcd_command_w(uint16_t data);
+
+ uint16_t spi_misc_control_r();
+ uint16_t spi_rx_fifo_r();
+ void spi_tx_fifo_w(uint16_t data);
+
+ void spi_control_w(uint16_t data);
+
+ void spi_process_tx_data(uint8_t data);
+ uint8_t spi_process_rx();
+ uint8_t spi_rx();
+ uint8_t spi_rx_fast();
+
+ uint8_t m_rx_fifo[5]; // actually 8 bytes? or 8 half-bytes?
+
+ uint32_t m_spiaddress;
+
+ uint16_t unk_78a1_r();
+ uint16_t m_78a1;
+ uint16_t unk_78d8_r();
+ void unk_78d8_w(uint16_t data);
+
+ enum spistate : const int
+ {
+ SPI_STATE_READY = 0,
+ SPI_STATE_WAITING_HIGH_ADDR = 1,
+ SPI_STATE_WAITING_MID_ADDR = 2,
+ SPI_STATE_WAITING_LOW_ADDR = 3,
+ // probably not
+ SPI_STATE_WAITING_DUMMY1_ADDR = 4,
+ SPI_STATE_WAITING_DUMMY2_ADDR = 5,
+ SPI_STATE_READING = 6,
+
+ SPI_STATE_WAITING_HIGH_ADDR_FAST = 8,
+ SPI_STATE_WAITING_MID_ADDR_FAST = 9,
+ SPI_STATE_WAITING_LOW_ADDR_FAST = 10,
+ SPI_STATE_WAITING_LOW_ADDR_FAST_DUMMY = 11,
+ SPI_STATE_READING_FAST = 12
+
+ };
+
+ spistate m_spistate;
+
+ enum lcdstate : const int
+ {
+ LCD_STATE_READY = 0,
+ LCD_STATE_WAITING_FOR_COMMAND = 1,
+ LCD_STATE_PROCESSING_COMMAND = 2
+ };
+
+ lcdstate m_lcdstate;
+ int m_lastlcdcommand;
+
+ uint8_t m_displaybuffer[0x40000];
+ int m_lcdaddr;
+
+ uint16_t io_7870_r();
+ required_ioport m_io_in0;
+ required_ioport m_io_in1;
+ required_device<bl_handhelds_menucontrol_device> m_menucontrol;
+
+ DECLARE_WRITE_LINE_MEMBER(screen_vblank);
+};
+
+uint32_t gpl162xx_lcdtype_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ int count = 0;
+ for (int y = 0; y < 256; y++)
+ {
+ uint32_t *const dst = &bitmap.pix(y);
+
+ for (int x = 0; x < 320; x++)
+ {
+ // 8-bit values get pumped through a 256 word table in internal ROM and converted to words
+ uint16_t dat = m_displaybuffer[(count * 2) + 1] | (m_displaybuffer[(count * 2) + 0] << 8);
+
+ int b = ((dat >> 0) & 0x1f) << 3;
+ int g = ((dat >> 5) & 0x3f) << 2;
+ int r = ((dat >> 11) & 0x1f) << 3;
+
+ dst[x] = (r << 16) | (g << 8) | (b << 0);
+ count++;
+ }
+ }
+
+ return 0;
+}
+
+
+static INPUT_PORTS_START( gpl162xx_lcdtype )
+ PORT_START("IN0")
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED ) // causes lag if state is inverted, investigate
+ PORT_DIPNAME( 0x0002, 0x0002, "P0:0002" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0002, "0002" )
+ PORT_DIPNAME( 0x0004, 0x0000, "Show Vs in Test Mode" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0004, "0004" )
+ PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("menucontrol", bl_handhelds_menucontrol_device, status_r)
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("menucontrol", bl_handhelds_menucontrol_device, data_r)
+ PORT_DIPNAME( 0x0020, 0x0020, "P0:0020" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0020, "0020" )
+ PORT_DIPNAME( 0x0040, 0x0040, "P0:0040" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0040, "0040" )
+ PORT_DIPNAME( 0x0080, 0x0080, "P0:0080" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0080, "0080" )
+ PORT_DIPNAME( 0x0100, 0x0100, "P0:0100" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0100, "0100" )
+ PORT_DIPNAME( 0x0200, 0x0000, "Battery Level" )
+ PORT_DIPSETTING( 0x0000, "Normal" )
+ PORT_DIPSETTING( 0x0200, "Low" )
+ PORT_DIPNAME( 0x0400, 0x0400, "P0:0400" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0400, "0400" )
+ PORT_DIPNAME( 0x0800, 0x0800, "P0:0800" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0800, "0800" )
+ PORT_DIPNAME( 0x1000, 0x1000, "P0:1000" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x1000, "1000" )
+ PORT_DIPNAME( 0x2000, 0x2000, "P0:2000" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x2000, "2000" )
+ PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
+
+ PORT_START("IN1")
+ PORT_DIPNAME( 0x0001, 0x0001, "P1:0001" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0001, "0001" )
+ PORT_DIPNAME( 0x0002, 0x0002, "P1:0002" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0002, "0002" )
+ PORT_DIPNAME( 0x0004, 0x0004, "P1:0004" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0004, "0004" )
+ PORT_DIPNAME( 0x0008, 0x0008, "P1:0008" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0008, "0008" )
+ PORT_DIPNAME( 0x0010, 0x0010, "P1:0010" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x0010, "0010" )
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("SOUND")
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A")
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B")
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("ON/OFF")
+ PORT_DIPNAME( 0x1000, 0x1000, "P1:1000" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x1000, "1000" )
+ PORT_DIPNAME( 0x2000, 0x2000, "P1:2000" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x2000, "2000" )
+ PORT_DIPNAME( 0x4000, 0x4000, "P1:4000" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x4000, "4000" )
+ PORT_DIPNAME( 0x8000, 0x8000, "P1:8000" )
+ PORT_DIPSETTING( 0x0000, "0000" )
+ PORT_DIPSETTING( 0x8000, "8000" )
+INPUT_PORTS_END
+
+uint16_t gpl162xx_lcdtype_state::unk_7abf_r()
+{
+ return 0x0001;
+}
+
+uint16_t gpl162xx_lcdtype_state::io_7860_r()
+{
+ uint16_t ret = m_io_in0->read();
+ LOGMASKED(LOG_GPL162XX_LCDTYPE_IO_PORT, "%s: io_7860_r %02x\n", machine().describe_context(), ret);
+ return ret;
+}
+
+void gpl162xx_lcdtype_state::io_7860_w(uint16_t data)
+{
+ m_menucontrol->data_w((data & 0x10)>>4);
+ m_menucontrol->clock_w((data & 0x20)>>5);
+
+ m_7860 = data;
+}
+
+void gpl162xx_lcdtype_state::unk_7862_w(uint16_t data)
+{
+}
+
+void gpl162xx_lcdtype_state::unk_7863_w(uint16_t data)
+{
+ // probably port direction (or 7862 is?)
+ if (data == 0x3cf7)
+ {
+ m_menucontrol->reset_w(1);
+ }
+}
+
+uint16_t gpl162xx_lcdtype_state::unk_780f_r()
+{
+ return 0x0002;
+}
+
+uint16_t gpl162xx_lcdtype_state::spi_misc_control_r()
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: spi_misc_control_r\n", machine().describe_context());
+ return 0x0000;
+}
+
+uint16_t gpl162xx_lcdtype_state::spi_rx_fifo_r()
+{
+ if (m_spistate == SPI_STATE_READING_FAST)
+ return spi_rx_fast();
+
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: spi_rx_fifo_r\n", machine().describe_context());
+ return spi_rx();
+}
+
+void gpl162xx_lcdtype_state::spi_process_tx_data(uint8_t data)
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"transmitting %02x\n", data);
+
+ switch (m_spistate)
+ {
+ case SPI_STATE_READY:
+ {
+ if (data == 0x03)
+ {
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to read mode (need address) %02x\n", data);
+ m_spistate = SPI_STATE_WAITING_HIGH_ADDR;
+ }
+ else if (data == 0x0b)
+ {
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to fast read mode (need address) %02x\n", data);
+ m_spistate = SPI_STATE_WAITING_HIGH_ADDR_FAST;
+ //machine().debug_break();
+ }
+ else
+ {
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"invalid state request %02x\n", data);
+ }
+ break;
+ }
+
+ case SPI_STATE_WAITING_HIGH_ADDR:
+ {
+ m_spiaddress = (m_spiaddress & 0xff00ffff) | data << 16;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to high address %02x address is now %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_WAITING_MID_ADDR;
+ break;
+ }
+
+ case SPI_STATE_WAITING_MID_ADDR:
+ {
+ m_spiaddress = (m_spiaddress & 0xffff00ff) | data << 8;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to mid address %02x address is now %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_WAITING_LOW_ADDR;
+ break;
+ }
+
+ case SPI_STATE_WAITING_LOW_ADDR:
+ {
+ m_spiaddress = (m_spiaddress & 0xffffff00) | data;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to low address %02x address is now %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_READING;
+ break;
+ }
+
+ case SPI_STATE_READING:
+ {
+ // writes when in read mode clock in data?
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"write while in read mode (clock data?)\n", data, m_spiaddress);
+ break;
+ }
+
+ case SPI_STATE_WAITING_DUMMY1_ADDR:
+ {
+ m_spistate = SPI_STATE_WAITING_DUMMY2_ADDR;
+ break;
+ }
+
+ case SPI_STATE_WAITING_DUMMY2_ADDR:
+ {
+ // m_spistate = SPI_STATE_READY;
+ break;
+ }
+
+
+ case SPI_STATE_WAITING_HIGH_ADDR_FAST:
+ {
+ m_spiaddress = (m_spiaddress & 0xff00ffff) | data << 16;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to high address %02x address is now %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_WAITING_MID_ADDR_FAST;
+ break;
+ }
+
+ case SPI_STATE_WAITING_MID_ADDR_FAST:
+ {
+ m_spiaddress = (m_spiaddress & 0xffff00ff) | data << 8;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to mid address %02x address is now %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_WAITING_LOW_ADDR_FAST;
+ break;
+ }
+
+ case SPI_STATE_WAITING_LOW_ADDR_FAST:
+ {
+ m_spiaddress = (m_spiaddress & 0xffffff00) | data;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"set to low address %02x address is now %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_WAITING_LOW_ADDR_FAST_DUMMY;
+
+ break;
+ }
+
+ case SPI_STATE_WAITING_LOW_ADDR_FAST_DUMMY:
+ {
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"dummy write %08x\n", data, m_spiaddress);
+ m_spistate = SPI_STATE_READING_FAST;
+ break;
+ }
+
+ case SPI_STATE_READING_FAST:
+ {
+ // writes when in read mode clock in data?
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"write while in read mode (clock data?)\n", data, m_spiaddress);
+ break;
+ }
+
+ }
+}
+
+uint8_t gpl162xx_lcdtype_state::spi_process_rx()
+{
+
+ switch (m_spistate)
+ {
+ case SPI_STATE_READING:
+ case SPI_STATE_READING_FAST:
+ {
+ uint8_t dat = m_spirom[m_spiaddress & 0x7fffff];
+
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"reading SPI %02x from SPI Address %08x (adjusted word offset %08x)\n", dat, m_spiaddress, (m_spiaddress/2)+0x20000);
+ m_spiaddress++;
+ return dat;
+ }
+
+ default:
+ {
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"reading FIFO in unknown state\n");
+ return 0x00;
+ }
+ }
+
+ return 0x00;
+}
+
+
+uint8_t gpl162xx_lcdtype_state::spi_rx()
+{
+ uint8_t ret = m_rx_fifo[0];
+
+ m_rx_fifo[0] = m_rx_fifo[1];
+ m_rx_fifo[1] = m_rx_fifo[2];
+ m_rx_fifo[2] = m_rx_fifo[3];
+ m_rx_fifo[3] = spi_process_rx();
+
+ return ret;
+}
+
+uint8_t gpl162xx_lcdtype_state::spi_rx_fast()
+{
+ uint8_t ret = m_rx_fifo[0];
+
+ m_rx_fifo[0] = m_rx_fifo[1];
+ m_rx_fifo[1] = m_rx_fifo[2];
+ m_rx_fifo[2] = m_rx_fifo[3];
+ m_rx_fifo[3] = m_rx_fifo[4];
+ m_rx_fifo[4] = spi_process_rx();
+
+ return ret;
+}
+
+void gpl162xx_lcdtype_state::spi_tx_fifo_w(uint16_t data)
+{
+ data &= 0x00ff;
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: spi_tx_fifo_w %04x\n", machine().describe_context(), data);
+
+ spi_process_tx_data(data);
+}
+
+// this is probably 'port b' but when SPI is enabled some points of this can become SPI control pins
+// it's accessed after each large data transfer, probably to reset the SPI into 'ready for command' state?
+void gpl162xx_lcdtype_state::unk_7868_w(uint16_t data)
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE_IO_PORT, "%s: unk_7868_w %04x (Port B + SPI reset?)\n", machine().describe_context(), data);
+
+ if ((m_7868 & 0x0100) != (data & 0x0100))
+ {
+ if (!(data & 0x0100))
+ {
+ for (int i = 0; i < 4; i++)
+ m_rx_fifo[i] = 0xff;
+
+ m_spistate = SPI_STATE_READY;
+ }
+ }
+
+ m_7868 = data;
+}
+
+uint16_t gpl162xx_lcdtype_state::unk_7868_r()
+{
+ return m_7868;
+}
+
+void gpl162xx_lcdtype_state::bankswitch_707e_w(uint16_t data)
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: bankswitch_707e_w %04x\n", machine().describe_context(), data);
+ m_707e_bank = data;
+}
+
+uint16_t gpl162xx_lcdtype_state::bankswitch_707e_r()
+{
+ return m_707e_bank;
+}
+
+
+void gpl162xx_lcdtype_state::bankswitch_703a_w(uint16_t data)
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: bankswitch_703a_w %04x\n", machine().describe_context(), data);
+ m_703a_bank = data;
+}
+
+uint16_t gpl162xx_lcdtype_state::bankswitch_703a_r()
+{
+ return m_703a_bank;
+}
+
+void gpl162xx_lcdtype_state::bankedram_7300_w(offs_t offset, uint16_t data)
+{
+ offset |= (m_703a_bank & 0x000c) << 6;
+ m_bankedram_7300[offset] = data;
+}
+
+uint16_t gpl162xx_lcdtype_state::bankedram_7300_r(offs_t offset)
+{
+ offset |= (m_703a_bank & 0x000c) << 6;
+ return m_bankedram_7300[offset];
+}
+
+void gpl162xx_lcdtype_state::bankedram_7400_w(offs_t offset, uint16_t data)
+{
+ if (m_707e_bank & 1)
+ {
+ m_bankedram_7400[offset + 0x400] = data;
+ }
+ else
+ {
+ m_bankedram_7400[offset] = data;
+ }
+}
+
+uint16_t gpl162xx_lcdtype_state::bankedram_7400_r(offs_t offset)
+{
+ if (m_707e_bank & 1)
+ {
+ return m_bankedram_7400[offset + 0x400];
+ }
+ else
+ {
+ return m_bankedram_7400[offset];
+ }
+}
+
+void gpl162xx_lcdtype_state::system_dma_params_channel0_w(offs_t offset, uint16_t data)
+{
+ m_dmaregs[offset] = data;
+
+ switch (offset)
+ {
+ case 0:
+ {
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Mode)\n", machine().describe_context(), offset, data);
+
+ uint16_t mode = m_dmaregs[0];
+ uint32_t source = m_dmaregs[1] | (m_dmaregs[4] << 16);
+ uint32_t dest = m_dmaregs[2] | (m_dmaregs[5] << 16) ;
+ uint32_t length = m_dmaregs[3] | (m_dmaregs[6] << 16);
+
+ if ((mode != 0x0200) && (mode != 0x4009) && (mode != 0x6009))
+ fatalerror("unknown dma mode write %04x\n", data);
+
+ if ((mode == 0x4009) || (mode == 0x6009))
+ {
+ address_space& mem = m_maincpu->space(AS_PROGRAM);
+
+ for (int i = 0; i < length; i++)
+ {
+ uint16_t dat = mem.read_word(source);
+
+ if (mode & 0x2000)
+ {
+ // Racing Car and Elevator Action need this logic
+ mem.write_word(dest, dat & 0xff);
+ dest++;
+ mem.write_word(dest, dat >> 8);
+ dest++;
+ }
+ else
+ {
+ mem.write_word(dest, dat);
+ dest++;
+ }
+
+ source++;
+ }
+ }
+
+ break;
+ }
+ case 1:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Source Low)\n", machine().describe_context(), offset, data);
+ break;
+
+ case 2:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Dest Low)\n", machine().describe_context(), offset, data);
+ break;
+
+ case 3:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Length Low)\n", machine().describe_context(), offset, data);
+ break;
+
+ case 4:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Source High)\n", machine().describe_context(), offset, data);
+ break;
+
+ case 5:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Dest High)\n", machine().describe_context(), offset, data);
+ break;
+
+ case 6:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA Length High)\n", machine().describe_context(), offset, data);
+ break;
+
+ case 7:
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_w %01x %04x (DMA unknown)\n", machine().describe_context(), offset, data);
+ break;
+ }
+}
+
+uint16_t gpl162xx_lcdtype_state::system_dma_params_channel0_r(offs_t offset)
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: system_dma_params_channel0_r %01x\n", machine().describe_context(), offset);
+ return m_dmaregs[offset];
+}
+
+uint16_t gpl162xx_lcdtype_state::io_7870_r()
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE_IO_PORT, "%s: io_7870_r (IO port)\n", machine().describe_context() );
+ return m_io_in1->read();
+}
+
+void gpl162xx_lcdtype_state::spi_control_w(uint16_t data)
+{
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: spi_control_w %04x\n", machine().describe_context(), data);
+}
+
+uint16_t gpl162xx_lcdtype_state::unk_78a1_r()
+{
+ // checked in interrupt, code skipped entirely if this isn't set
+ return m_78a1;
+}
+
+uint16_t gpl162xx_lcdtype_state::unk_78d8_r()
+{
+ return 0xffff;
+}
+
+void gpl162xx_lcdtype_state::unk_78d8_w(uint16_t data)
+{
+ // written in IRQ, possible ack
+ if (data & 0x8000)
+ m_78a1 &= ~0x8000;
+}
+
+
+void gpl162xx_lcdtype_state::map(address_map &map)
+{
+ // there are calls to 01xxx and 02xxx regions
+ // (RAM populated by internal ROM?, TODO: check to make sure code copied there isn't from SPI ROM like the GPL16250 bootstrap
+ // does from NAND, it doesn't seem to have a header in the same format at least)
+ map(0x000000, 0x006fff).ram().share("mainram");
+
+ // registers at 7xxx are similar to GPL16250, but not identical? (different video system? or just GPL16250 with the video part unused?)
+
+ map(0x00703a, 0x00703a).rw(FUNC(gpl162xx_lcdtype_state::bankswitch_703a_r), FUNC(gpl162xx_lcdtype_state::bankswitch_703a_w));
+ map(0x00707e, 0x00707e).rw(FUNC(gpl162xx_lcdtype_state::bankswitch_707e_r), FUNC(gpl162xx_lcdtype_state::bankswitch_707e_w));
+
+ map(0x007100, 0x0071ff).ram(); // rowscroll on gpl16250
+ map(0x007300, 0x0073ff).rw(FUNC(gpl162xx_lcdtype_state::bankedram_7300_r), FUNC(gpl162xx_lcdtype_state::bankedram_7300_w)); // palette on gpl16250
+ map(0x007400, 0x0077ff).rw(FUNC(gpl162xx_lcdtype_state::bankedram_7400_r), FUNC(gpl162xx_lcdtype_state::bankedram_7400_w)); // spriteram on gpl16250
+
+ map(0x00780f, 0x00780f).r(FUNC(gpl162xx_lcdtype_state::unk_780f_r));
+
+
+ map(0x007860, 0x007860).rw(FUNC(gpl162xx_lcdtype_state::io_7860_r),FUNC(gpl162xx_lcdtype_state::io_7860_w)); // Port A?
+ map(0x007862, 0x007862).w(FUNC(gpl162xx_lcdtype_state::unk_7862_w));
+ map(0x007863, 0x007863).w(FUNC(gpl162xx_lcdtype_state::unk_7863_w));
+
+ map(0x007868, 0x007868).rw(FUNC(gpl162xx_lcdtype_state::unk_7868_r), FUNC(gpl162xx_lcdtype_state::unk_7868_w)); // Port B?
+
+ map(0x007870, 0x007870).r(FUNC(gpl162xx_lcdtype_state::io_7870_r)); // Port C?
+
+ map(0x0078a1, 0x0078a1).r(FUNC(gpl162xx_lcdtype_state::unk_78a1_r));
+
+ map(0x0078d8, 0x0078d8).rw(FUNC(gpl162xx_lcdtype_state::unk_78d8_r), FUNC(gpl162xx_lcdtype_state::unk_78d8_w));
+
+
+ map(0x007940, 0x007940).w(FUNC(gpl162xx_lcdtype_state::spi_control_w));
+ // 7941 SPI Transmit Status
+ map(0x007942, 0x007942).w(FUNC(gpl162xx_lcdtype_state::spi_tx_fifo_w));
+ // 7943 SPI Receive Status
+ map(0x007944, 0x007944).r(FUNC(gpl162xx_lcdtype_state::spi_rx_fifo_r));
+ map(0x007945, 0x007945).r(FUNC(gpl162xx_lcdtype_state::spi_misc_control_r));
+
+ map(0x007a80, 0x007a87).rw(FUNC(gpl162xx_lcdtype_state::system_dma_params_channel0_r), FUNC(gpl162xx_lcdtype_state::system_dma_params_channel0_w));
+
+ map(0x007abf, 0x007abf).r(FUNC(gpl162xx_lcdtype_state::unk_7abf_r));
+
+ // there are calls to 0x0f000 (internal ROM?)
+ map(0x00f000, 0x00ffff).rom().region("maincpu", 0x00000);
+
+ // external LCD controller
+ map(0x200000, 0x200000).w(FUNC(gpl162xx_lcdtype_state::lcd_command_w));
+ map(0x20fc00, 0x20fc00).w(FUNC(gpl162xx_lcdtype_state::lcd_w));
+}
+
+void gpl162xx_lcdtype_state::lcd_command_w(uint16_t data)
+{
+ data &= 0xff;
+
+ switch (m_lcdstate)
+ {
+ case LCD_STATE_READY:
+ case LCD_STATE_PROCESSING_COMMAND:
+ {
+ if (data == 0x0000)
+ {
+ m_lcdstate = LCD_STATE_WAITING_FOR_COMMAND;
+ m_lastlcdcommand = 0;
+ }
+ break;
+ }
+
+ case LCD_STATE_WAITING_FOR_COMMAND:
+ {
+ m_lastlcdcommand = data;
+ m_lcdstate = LCD_STATE_PROCESSING_COMMAND;
+ break;
+ }
+
+ }
+}
+
+void gpl162xx_lcdtype_state::lcd_w(uint16_t data)
+{
+ data &= 0xff; // definitely looks like 8-bit port as 16-bit values are shifted and rewritten
+ LOGMASKED(LOG_GPL162XX_LCDTYPE,"%s: lcd_w %02x\n", machine().describe_context(), data);
+
+ if ((m_lcdstate == LCD_STATE_PROCESSING_COMMAND) && (m_lastlcdcommand == 0x22))
+ {
+ m_displaybuffer[m_lcdaddr] = data;
+ m_lcdaddr++;
+
+ if (m_lcdaddr >= ((320 * 240) * 2))
+ m_lcdaddr = 0;
+
+ //m_lcdaddr &= 0x3ffff;
+ }
+}
+
+
+void gpl162xx_lcdtype_state::machine_start()
+{
+}
+
+
+void gpl162xx_lcdtype_state::machine_reset()
+{
+ m_spistate = SPI_STATE_READY;
+ m_spiaddress = 0;
+
+ for (int i = 0; i < 320*240*2; i++)
+ m_displaybuffer[i] = 0x00;
+
+ m_lcdaddr = 0;
+
+ m_lcdstate = LCD_STATE_READY;
+ m_lastlcdcommand = 0;
+
+ m_78a1 = 0;
+
+// first menu index is stored here
+// m_spirom[0x16000] = gamenum & 0xff;
+// m_spirom[0x16001] = (gamenum>>8) & 0xff;
+}
+
+WRITE_LINE_MEMBER(gpl162xx_lcdtype_state::screen_vblank)
+{
+ if (state)
+ {
+ // probably a timer
+ m_maincpu->set_input_line(UNSP_IRQ4_LINE, ASSERT_LINE);
+ m_78a1 |= 0x8000;
+ }
+ else
+ {
+ m_maincpu->set_input_line(UNSP_IRQ4_LINE, CLEAR_LINE);
+ }
+}
+
+void gpl162xx_lcdtype_state::gpl162xx_lcdtype(machine_config &config)
+{
+
+ UNSP_20(config, m_maincpu, 96000000); // unknown CPU, unsp20 based, 96Mhz is listed as the maximum for most unSP2.0 chips, and appears correct here
+ m_maincpu->set_addrmap(AS_PROGRAM, &gpl162xx_lcdtype_state::map);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_refresh_hz(60);
+ m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(10));
+ m_screen->set_size(64*8, 32*8);
+ m_screen->set_visarea(0*8, 320-1, 0*8, 240-1);
+ m_screen->set_screen_update(FUNC(gpl162xx_lcdtype_state::screen_update));
+ m_screen->screen_vblank().set(FUNC(gpl162xx_lcdtype_state::screen_vblank));
+
+ PALETTE(config, m_palette).set_format(palette_device::xBGR_555, 0x8000);
+
+ BL_HANDHELDS_MENUCONTROL(config, m_menucontrol, 0);
+ m_menucontrol->set_is_unsp_type_hack();
+
+}
+
+// pcp8718 and pcp8728 both contain user data (player name?) and will need to be factory defaulted once they work
+// the ROM code is slightly different between them
+
+ROM_START( pcp8718 )
+ ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD( "internal.rom", 0x000000, 0x2000, CRC(ea119561) SHA1(a2680577e20fe1155efc40a5781cf1ec80ccec3a) )
+
+ ROM_REGION( 0x800000, "spi", ROMREGION_ERASEFF )
+ //ROM_LOAD16_WORD_SWAP( "8718_en25f32.bin", 0x000000, 0x400000, CRC(cc138db4) SHA1(379af3d94ae840f52c06416d6cf32e25923af5ae) ) // bad dump, some blocks are corrupt
+ ROM_LOAD( "eyecare_25q32av1g_ef4016.bin", 0x000000, 0x400000, CRC(58415e10) SHA1(b1adcc03f2ad8d741544204671677740e904ce1a) )
+ROM_END
+
+ROM_START( pcp8728 )
+ ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD( "internal.rom", 0x000000, 0x2000, CRC(ea119561) SHA1(a2680577e20fe1155efc40a5781cf1ec80ccec3a) )
+
+ ROM_REGION( 0x800000, "spi", ROMREGION_ERASEFF )
+ ROM_LOAD( "pcp 8728 788 in 1.bin", 0x000000, 0x400000, CRC(60115f21) SHA1(e15c39f11e442a76fae3823b6d510178f6166926) )
+ROM_END
+
+ROM_START( bkid218 )
+ ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD( "internal.rom", 0x000000, 0x2000, CRC(ea119561) SHA1(a2680577e20fe1155efc40a5781cf1ec80ccec3a) )
+
+ ROM_REGION( 0x800000, "spi", ROMREGION_ERASEFF )
+ ROM_LOAD( "218n1_25q64csig_c84017.bin", 0x000000, 0x800000, CRC(94f35dbd) SHA1(a1bd6defd2465ae14753cd83be5c31f99e9158ec) )
+ROM_END
+
+
+CONS( 200?, pcp8718, 0, 0, gpl162xx_lcdtype, gpl162xx_lcdtype, gpl162xx_lcdtype_state, empty_init, "PCP", "PCP 8718 - HD 360 Degrees Rocker Palm Eyecare Console - 788 in 1", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+CONS( 200?, pcp8728, 0, 0, gpl162xx_lcdtype, gpl162xx_lcdtype, gpl162xx_lcdtype_state, empty_init, "PCP", "PCP 8728 - 788 in 1", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // what name was this sold under?
+CONS( 200?, bkid218, 0, 0, gpl162xx_lcdtype, gpl162xx_lcdtype, gpl162xx_lcdtype_state, empty_init, "BornKid", "Handheld Game Console BC-19 - 218 in 1", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
diff --git a/src/mame/drivers/generalplus_gpl32612.cpp b/src/mame/drivers/generalplus_gpl32612.cpp
index d7d830a0424..1c9df04d370 100644
--- a/src/mame/drivers/generalplus_gpl32612.cpp
+++ b/src/mame/drivers/generalplus_gpl32612.cpp
@@ -45,6 +45,8 @@ private:
virtual void machine_start() override;
virtual void machine_reset() override;
+ void arm_map(address_map &map);
+
required_device<cpu_device> m_maincpu;
required_device<screen_device> m_screen;
@@ -52,10 +54,49 @@ private:
uint32_t screen_update_gpl32612(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void nand_init(int blocksize, int blocksize_stripped);
+ void copy_block(int i, int blocksize, int blocksize_stripped, uint8_t* nandrom, int dest);
+ void bootstrap();
std::vector<uint8_t> m_strippedrom;
+
+ uint32_t unk_d000003c_r(offs_t offset, uint32_t mem_mask);
+ uint32_t unk_d0800018_r(offs_t offset, uint32_t mem_mask);
+ uint32_t unk_d0900140_r(offs_t offset, uint32_t mem_mask);
+ uint32_t unk_d0900153_r(offs_t offset, uint32_t mem_mask);
};
+uint32_t generalplus_gpl32612_game_state::unk_d000003c_r(offs_t offset, uint32_t mem_mask)
+{
+ return machine().rand();
+}
+
+uint32_t generalplus_gpl32612_game_state::unk_d0800018_r(offs_t offset, uint32_t mem_mask)
+{
+ return machine().rand();
+}
+
+uint32_t generalplus_gpl32612_game_state::unk_d0900140_r(offs_t offset, uint32_t mem_mask)
+{
+ return machine().rand();
+}
+
+uint32_t generalplus_gpl32612_game_state::unk_d0900153_r(offs_t offset, uint32_t mem_mask)
+{
+ return machine().rand();
+}
+
+void generalplus_gpl32612_game_state::arm_map(address_map &map)
+{
+ map(0x00000000, 0x03ffffff).ram();
+
+ map(0xd000003c, 0xd000003f).r(FUNC(generalplus_gpl32612_game_state::unk_d000003c_r));
+
+ map(0xd0800018, 0xd080001b).r(FUNC(generalplus_gpl32612_game_state::unk_d0800018_r));
+
+ map(0xd0900140, 0xd0900143).r(FUNC(generalplus_gpl32612_game_state::unk_d0900140_r));
+ map(0xd0900150, 0xd0900153).r(FUNC(generalplus_gpl32612_game_state::unk_d0900153_r));
+}
+
uint32_t generalplus_gpl32612_game_state::screen_update_gpl32612(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
return 0;
@@ -72,10 +113,39 @@ void generalplus_gpl32612_game_state::machine_reset()
static INPUT_PORTS_START( gpl32612 )
INPUT_PORTS_END
+void generalplus_gpl32612_game_state::copy_block(int i, int blocksize, int blocksize_stripped, uint8_t* nandrom, int dest)
+{
+ const int base = i * blocksize;
+ address_space& mem = m_maincpu->space(AS_PROGRAM);
+
+ for (int j = 0; j < blocksize_stripped; j++)
+ {
+ uint8_t data = nandrom[base + j];
+ //printf("writing to %08x : %02x", dest + j, data);
+ mem.write_byte(dest+j, data);
+ }
+}
+
+void generalplus_gpl32612_game_state::bootstrap()
+{
+ uint8_t* rom = memregion("nand")->base();
+
+ //int startblock = 0xe0000 / 0x800;
+ int startblock = 0xa0000 / 0x800;
+ int endblock = 0x1f0000 / 0x800;
+
+ int j = 0;
+ for (int i = startblock; i < endblock; i++) // how much is copied, and where from? as with the unSP NAND ones there appear to be several stages of bootloader, this is not the 1st one
+ {
+ copy_block(i, 0x840, 0x800, rom, j * 0x800);
+ j++;
+ }
+}
void generalplus_gpl32612_game_state::gpl32612(machine_config &config)
{
ARM9(config, m_maincpu, 240000000); // unknown core / frequency, but ARM based
+ m_maincpu->set_addrmap(AS_PROGRAM, &generalplus_gpl32612_game_state::arm_map);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(60);
@@ -90,35 +160,40 @@ void generalplus_gpl32612_game_state::gpl32612(machine_config &config)
// NAND dumps, so there will be a bootloader / boot strap at least
ROM_START( jak_swbstrik )
- ROM_REGION( 0x8400000, "maincpu", ROMREGION_ERASEFF )
+ ROM_REGION( 0x8400000, "nand", ROMREGION_ERASEFF )
ROM_LOAD( "starwarsblaster.bin", 0x000000, 0x8400000, CRC(02c3c4d6) SHA1(a6ae05a7d7b2015023113f6baad25458f3c01102) )
ROM_END
ROM_START( jak_tmnthp )
- ROM_REGION( 0x8400000, "maincpu", ROMREGION_ERASEFF )
+ ROM_REGION( 0x8400000, "nand", ROMREGION_ERASEFF )
ROM_LOAD( "tmntheroportal.bin", 0x000000, 0x8400000, CRC(75ec7127) SHA1(cd05f55a1f5a7fd3d1b0658ad6805b8777857a7e) )
ROM_END
ROM_START( jak_ddhp )
- ROM_REGION( 0x8400000, "maincpu", ROMREGION_ERASEFF )
+ ROM_REGION( 0x8400000, "nand", ROMREGION_ERASEFF )
ROM_LOAD( "dragonsheroesportal_mx30lf1g08aa_c2f1.bin", 0x000000, 0x8400000, CRC(825cce7b) SHA1(2185137138f2a20e5cfe9c167eeb67a146953b65) )
ROM_END
ROM_START( jak_dchp )
- ROM_REGION( 0x8400000, "maincpu", ROMREGION_ERASEFF )
+ ROM_REGION( 0x8400000, "nand", ROMREGION_ERASEFF )
ROM_LOAD( "dcheroportal_mx30lf1g08aa_c2f1.bin", 0x000000, 0x8400000, CRC(576a3005) SHA1(6cd9edc4def707aede3f82a21c87269d2a6bc870) )
ROM_END
ROM_START( jak_prhp )
- ROM_REGION( 0x8400000, "maincpu", ROMREGION_ERASEFF )
+ ROM_REGION( 0x8400000, "nand", ROMREGION_ERASEFF )
ROM_LOAD( "mx30lf1g08aa.u2", 0x000000, 0x8400000, CRC(4ccd7e53) SHA1(decbd424f088d180776a817c80b147d6a887e5c1) )
ROM_END
+// uncertain hardware type, ARM based, has GPNAND strings
+ROM_START( zippity )
+ ROM_REGION( 0x10800000, "nandrom", ROMREGION_ERASE00 )
+ ROM_LOAD( "zippity_mt29f2g08aacwp_2cda8015.bin", 0x0000, 0x10800000, CRC(16248b63) SHA1(3607337588a68052ef5c495b496aa3e0449d3eb6) )
+ROM_END
void generalplus_gpl32612_game_state::nand_init(int blocksize, int blocksize_stripped)
{
- uint8_t* rom = memregion("maincpu")->base();
- int size = memregion("maincpu")->bytes();
+ uint8_t* rom = memregion("nand")->base();
+ int size = memregion("nand")->bytes();
int numblocks = size / blocksize;
@@ -153,6 +228,7 @@ void generalplus_gpl32612_game_state::nand_init(int blocksize, int blocksize_str
void generalplus_gpl32612_game_state::nand_init840()
{
nand_init(0x840, 0x800);
+ bootstrap();
}
@@ -162,3 +238,6 @@ CONS( 200?, jak_tmnthp, 0, 0, gpl32612, gpl32612, generalplus_gp
CONS( 200?, jak_ddhp, 0, 0, gpl32612, gpl32612, generalplus_gpl32612_game_state, nand_init840, "JAKKS Pacific Inc", "DreamWorks Dragons Hero Portal", MACHINE_IS_SKELETON )
CONS( 200?, jak_prhp, 0, 0, gpl32612, gpl32612, generalplus_gpl32612_game_state, nand_init840, "JAKKS Pacific Inc", "Power Rangers Super Megaforce Hero Portal", MACHINE_IS_SKELETON ) // from a PAL unit (probably not region specific)
CONS( 200?, jak_dchp, 0, 0, gpl32612, gpl32612, generalplus_gpl32612_game_state, nand_init840, "JAKKS Pacific Inc", "DC Super Heroes The Watchtower Hero Portal", MACHINE_IS_SKELETON )
+
+// Might not belong here, SoC is marked GPL32300A instead, but is still ARM based, and has GPNAND strings
+CONS( 201?, zippity, 0, 0, gpl32612, gpl32612, generalplus_gpl32612_game_state, empty_init, "LeapFrog", "Zippity (US)", MACHINE_NO_SOUND | MACHINE_NOT_WORKING)
diff --git a/src/mame/drivers/generalplus_gpl_unknown.cpp b/src/mame/drivers/generalplus_gpl_unknown.cpp
index 7560eddf55b..6aaef1a32d8 100644
--- a/src/mame/drivers/generalplus_gpl_unknown.cpp
+++ b/src/mame/drivers/generalplus_gpl_unknown.cpp
@@ -1,78 +1,6 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
-// these contain the similar game selections to the games in unk6502_st2xxx.cpp but on updated hardware
-
-/* These use SPI ROMs and unSP2.0 instructions, so will be GeneralPlus branded parts, not SunPlus
- this might just be a GPL16250 with the video features bypassed as the sprite/palette banking is still
- used, but the RAM treated as work buffers
-*/
-
-/*
-
-for pcp8728 long jumps are done indirect via a call to RAM
-
-990c 20ec r4 = 20ec
-d9dd [1d] = r4
-990c 0007 r4 = 0007
-d9de [1e] = r4
-fe80 28f7 goto 0028f7
-
-the code to handle this is copied in at startup.
-
-Almost all function calls in the game are handled via a call to RAM which copies data inline from SPI for execution
-these calls manage their own stack, and copying back the caller function on return etc.
-
-The largest function in RAM at any one time is ~0x600 bytes.
-
-This appears to be incredibly inefficient but the system can't execute directly from SPI ROM, and doesn't have any
-RAM outside of the small area internal to the Sunplus SoC
-
-Graphics likewise appear to be loaded pixel by pixel from the SPI to framebuffer every single time there is a draw
-call. Sound is almost certainly handled in the same way.
-
-There is a missing internal ROM that acts as bootstrap and provides some basic functions. It is at least 0x1000
-words in size, with the lowest call being to 0xf000. It is potentially larger than this.
-
-The internal ROM will also need to provide trampolining for the interrupts, there is a single pointer near the
-start of the SPI ROM '02000A: 0041 0002' which points to 20041 (assuming you map the SPI ROM base as word address
-0x20000, so that the calls to get code align with ROM addresses)
-
-The function pointed to for the interrupt has the same form of the other functions that get loaded into RAM via
-calls to functions in the RAM area.
-
---------------------------------------------------------
-
-BIOS (internal ROM) calls:
-
-0xf000 - copy dword from SPI using provided pointer
-
-0xf56f - unknown, after some time, done with PC = f56f, only in one place
-
-0xf58f - unknown, soon after startup (only 1 call)
-
-00f7a0 - unknown - 3 calls
-
-0xf931 - unknown, just one call
-
-00fa1d - unknown, just one call
-
-0xfb26 - unknown, after some time (done with pc = fb26 and calls)
-
-0xfb4f - unknown, just one call
-
-0xfbbf - unknown, 3 calls
-
-code currently goes off the rails after some of these unhandled calls (one to f56f?)
-
---
-
-use 'go 2938' to get to the inline code these load on the fly
-
-the first piece of code copied appears to attempt to checksum the internal BIOS!
-
-*/
-
#include "emu.h"
#include "cpu/unsp/unsp.h"
@@ -81,34 +9,23 @@ the first piece of code copied appears to attempt to checksum the internal BIOS!
#include "screen.h"
#include "speaker.h"
-
-#define LOG_GPL_UNKNOWN (1U << 1)
-#define LOG_GPL_UNKNOWN_SELECT_SIM (1U << 2)
-
-#define LOG_ALL (LOG_GPL_UNKNOWN | LOG_GPL_UNKNOWN_SELECT_SIM)
-#define VERBOSE (0)
-
#include "logmacro.h"
-class pcp8718_state : public driver_device
+class generalplus_gpl_unknown_state : public driver_device
{
public:
- pcp8718_state(const machine_config &mconfig, device_type type, const char *tag) :
+ generalplus_gpl_unknown_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
- m_mainrom(*this, "maincpu"),
- m_mainram(*this, "mainram"),
+ //m_mainrom(*this, "maincpu"),
+ //m_mainram(*this, "mainram"),
m_palette(*this, "palette"),
m_screen(*this, "screen"),
- m_spirom(*this, "spi"),
- m_io_p1(*this, "IN0"),
- m_io_p2(*this, "IN1")
+ m_spirom(*this, "spi")
{ }
-
- void pcp8718(machine_config &config);
-
- void spi_init();
+
+ void generalplus_gpl_unknown(machine_config &config);
private:
virtual void machine_start() override;
@@ -117,1041 +34,90 @@ private:
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
required_device<unsp_20_device> m_maincpu;
- required_region_ptr<uint16_t> m_mainrom;
- required_shared_ptr<uint16_t> m_mainram;
+ //required_region_ptr<uint16_t> m_mainrom;
+ //required_shared_ptr<uint16_t> m_mainram;
required_device<palette_device> m_palette;
required_device<screen_device> m_screen;
-
- void map(address_map &map);
-
- uint16_t simulate_f000_r(offs_t offset);
-
- uint16_t ramcall_2060_logger_r();
- uint16_t ramcall_2189_logger_r();
-
- uint16_t ramcall_2434_logger_r();
-
- uint16_t ramcall_2829_logger_r();
- uint16_t ramcall_287a_logger_r();
- uint16_t ramcall_28f7_logger_r();
- uint16_t ramcall_2079_logger_r();
-
-
required_region_ptr<uint8_t> m_spirom;
- uint16_t unk_7abf_r();
- uint16_t unk_7860_r();
- uint16_t unk_780f_r();
-
- void unk_7860_w(uint16_t data);
- uint16_t m_7860;
-
- void unk_7868_w(uint16_t data);
- uint16_t unk_7868_r();
- uint16_t m_7868;
-
- void bankswitch_707e_w(uint16_t data);
- uint16_t bankswitch_707e_r();
- uint16_t m_707e_bank;
-
- void bankswitch_703a_w(uint16_t data);
- uint16_t bankswitch_703a_r();
- uint16_t m_703a_bank;
-
- void bankedram_7300_w(offs_t offset, uint16_t data);
- uint16_t bankedram_7300_r(offs_t offset);
- uint16_t m_bankedram_7300[0x400];
-
- void bankedram_7400_w(offs_t offset, uint16_t data);
- uint16_t bankedram_7400_r(offs_t offset);
- uint16_t m_bankedram_7400[0x800];
-
- void system_dma_params_channel0_w(offs_t offset, uint16_t data);
- uint16_t system_dma_params_channel0_r(offs_t offset);
-
- uint16_t m_dmaregs[8];
-
- void lcd_w(uint16_t data);
- void lcd_command_w(uint16_t data);
-
- uint16_t spi_misc_control_r();
- uint16_t spi_rx_fifo_r();
- void spi_tx_fifo_w(uint16_t data);
-
- void spi_control_w(uint16_t data);
-
- void spi_process_tx_data(uint8_t data);
- uint8_t spi_process_rx();
- uint8_t spi_rx();
- uint8_t spi_rx_fast();
-
- uint8_t m_rx_fifo[5]; // actually 8 bytes? or 8 half-bytes?
-
- uint32_t m_spiaddress;
-
- uint16_t unk_78a1_r();
- uint16_t m_78a1;
- void unk_78d8_w(uint16_t data);
-
- enum spistate : const int
- {
- SPI_STATE_READY = 0,
- SPI_STATE_WAITING_HIGH_ADDR = 1,
- SPI_STATE_WAITING_MID_ADDR = 2,
- SPI_STATE_WAITING_LOW_ADDR = 3,
- // probably not
- SPI_STATE_WAITING_DUMMY1_ADDR = 4,
- SPI_STATE_WAITING_DUMMY2_ADDR = 5,
- SPI_STATE_READING = 6,
-
- SPI_STATE_WAITING_HIGH_ADDR_FAST = 8,
- SPI_STATE_WAITING_MID_ADDR_FAST = 9,
- SPI_STATE_WAITING_LOW_ADDR_FAST = 10,
- SPI_STATE_WAITING_LOW_ADDR_FAST_DUMMY = 11,
- SPI_STATE_READING_FAST = 12
-
- };
-
- spistate m_spistate;
-
- enum lcdstate : const int
- {
- LCD_STATE_READY = 0,
- LCD_STATE_WAITING_FOR_COMMAND = 1,
- LCD_STATE_PROCESSING_COMMAND = 2
- };
-
- lcdstate m_lcdstate;
- int m_lastlcdcommand;
-
- uint8_t m_displaybuffer[0x40000];
- int m_lcdaddr;
-
- uint16_t unk_7870_r();
- required_ioport m_io_p1;
- required_ioport m_io_p2;
-
- uint16_t m_stored_gamenum;
- int m_addval;
-
- DECLARE_WRITE_LINE_MEMBER(screen_vblank);
+ void map(address_map &map);
};
-uint32_t pcp8718_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+uint32_t generalplus_gpl_unknown_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int count = 0;
- for (int y = 0; y < 256; y++)
- {
- uint32_t* dst = &bitmap.pix32(y);
-
- for (int x = 0; x < 320; x++)
- {
- // 8-bit values get pumped through a 256 word table in intenral ROM and converted to words, so it's probably raw 16-bit RGB data?
- uint16_t dat = m_displaybuffer[(count * 2) + 1] | (m_displaybuffer[(count * 2) + 0] << 8);
-
- int b = ((dat >> 0) & 0x1f) << 3;
- int g = ((dat >> 5) & 0x3f) << 2;
- int r = ((dat >> 11) & 0x1f) << 3;
-
- dst[x] = (r << 16) | (g << 8) | (b << 0);
- count++;
- }
- }
-
return 0;
}
-
-
-
-
-static INPUT_PORTS_START( pcp8718 )
- PORT_START("IN0")
- PORT_DIPNAME( 0x0001, 0x0001, "P1:0001" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0001, "0001" )
- PORT_DIPNAME( 0x0002, 0x0002, "P1:0002" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0002, "0002" )
- PORT_DIPNAME( 0x0004, 0x0004, "P1:0004" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0004, "0004" )
- PORT_DIPNAME( 0x0008, 0x0008, "P1:0008" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0008, "0008" )
- PORT_DIPNAME( 0x0010, 0x0010, "P1:0010" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0010, "0010" )
- PORT_DIPNAME( 0x0020, 0x0020, "P1:0020" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0020, "0020" )
- PORT_DIPNAME( 0x0040, 0x0040, "P1:0040" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0040, "0040" )
- PORT_DIPNAME( 0x0080, 0x0080, "P1:0080" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0080, "0080" )
- PORT_DIPNAME( 0x0100, 0x0100, "P1:0100" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0100, "0100" )
- PORT_DIPNAME( 0x0200, 0x0200, "P1:0200" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0200, "0200" )
- PORT_DIPNAME( 0x0400, 0x0400, "P1:0400" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0400, "0400" )
- PORT_DIPNAME( 0x0800, 0x0800, "P1:0800" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0800, "0800" )
- PORT_DIPNAME( 0x1000, 0x1000, "P1:1000" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x1000, "1000" )
- PORT_DIPNAME( 0x2000, 0x2000, "P1:2000" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x2000, "2000" )
- PORT_DIPNAME( 0x4000, 0x4000, "P1:4000" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x4000, "4000" )
- PORT_DIPNAME( 0x8000, 0x8000, "P1:8000" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x8000, "8000" )
-
- PORT_START("IN1")
- PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED ) // causes lag if state is inverted, investigate
- PORT_DIPNAME( 0x0002, 0x0002, "P2:0002" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0002, "0002" )
- PORT_DIPNAME( 0x0004, 0x0004, "Show Vs in Test Mode" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0004, "0004" )
- PORT_DIPNAME( 0x0008, 0x0008, "P2:0008" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0008, "0008" )
- PORT_DIPNAME( 0x0010, 0x0010, "P2:0010" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x0010, "0010" )
- PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("SOUND")
- PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
- PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
- PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
- PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A")
- PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B")
- PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("ON/OFF")
- PORT_DIPNAME( 0x1000, 0x1000, "P2:1000" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x1000, "1000" )
- PORT_DIPNAME( 0x2000, 0x2000, "P2:2000" )
- PORT_DIPSETTING( 0x0000, "0000" )
- PORT_DIPSETTING( 0x2000, "2000" )
- PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_START1 )
- PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
+static INPUT_PORTS_START( generalplus_gpl_unknown )
INPUT_PORTS_END
-uint16_t pcp8718_state::unk_7abf_r()
-{
- return 0x0001;
-}
-
-uint16_t pcp8718_state::unk_7860_r()
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: unk_7860_r (IO port)\n", machine().describe_context());
-
- uint16_t ret = (m_io_p2->read() & 0xfff7);
-
- if ((m_7860 & 0x20))
- ret |= 0x08;
-
- return ret;
-}
-
-void pcp8718_state::unk_7860_w(uint16_t data)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: unk_7860_w %04x (IO port)\n", machine().describe_context(), data);
- m_7860 = data;
-}
-
-
-uint16_t pcp8718_state::unk_780f_r()
-{
- return 0x0002;
-}
-
-
-
-uint16_t pcp8718_state::spi_misc_control_r()
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: spi_misc_control_r\n", machine().describe_context());
- return 0x0000;
-}
-
-
-uint16_t pcp8718_state::spi_rx_fifo_r()
-{
- if (m_spistate == SPI_STATE_READING_FAST)
- return spi_rx_fast();
-
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: spi_rx_fifo_r\n", machine().describe_context());
- return spi_rx();
-}
-
-void pcp8718_state::spi_process_tx_data(uint8_t data)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"transmitting %02x\n", data);
-
- switch (m_spistate)
- {
- case SPI_STATE_READY:
- {
- if (data == 0x03)
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"set to read mode (need address) %02x\n", data);
- m_spistate = SPI_STATE_WAITING_HIGH_ADDR;
- }
- else if (data == 0x0b)
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"set to fast read mode (need address) %02x\n", data);
- m_spistate = SPI_STATE_WAITING_HIGH_ADDR_FAST;
- //machine().debug_break();
- }
- else
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"invalid state request %02x\n", data);
- }
- break;
- }
-
- case SPI_STATE_WAITING_HIGH_ADDR:
- {
- m_spiaddress = (m_spiaddress & 0xff00ffff) | data << 16;
- LOGMASKED(LOG_GPL_UNKNOWN,"set to high address %02x address is now %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_WAITING_MID_ADDR;
- break;
- }
-
- case SPI_STATE_WAITING_MID_ADDR:
- {
- m_spiaddress = (m_spiaddress & 0xffff00ff) | data << 8;
- LOGMASKED(LOG_GPL_UNKNOWN,"set to mid address %02x address is now %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_WAITING_LOW_ADDR;
- break;
- }
-
- case SPI_STATE_WAITING_LOW_ADDR:
- {
- m_spiaddress = (m_spiaddress & 0xffffff00) | data;
- LOGMASKED(LOG_GPL_UNKNOWN,"set to low address %02x address is now %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_READING;
- break;
- }
-
- case SPI_STATE_READING:
- {
- // writes when in read mode clock in data?
- LOGMASKED(LOG_GPL_UNKNOWN,"write while in read mode (clock data?)\n", data, m_spiaddress);
- break;
- }
-
- case SPI_STATE_WAITING_DUMMY1_ADDR:
- {
- m_spistate = SPI_STATE_WAITING_DUMMY2_ADDR;
- break;
- }
-
- case SPI_STATE_WAITING_DUMMY2_ADDR:
- {
- // m_spistate = SPI_STATE_READY;
- break;
- }
-
-
- case SPI_STATE_WAITING_HIGH_ADDR_FAST:
- {
- m_spiaddress = (m_spiaddress & 0xff00ffff) | data << 16;
- LOGMASKED(LOG_GPL_UNKNOWN,"set to high address %02x address is now %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_WAITING_MID_ADDR_FAST;
- break;
- }
-
- case SPI_STATE_WAITING_MID_ADDR_FAST:
- {
- m_spiaddress = (m_spiaddress & 0xffff00ff) | data << 8;
- LOGMASKED(LOG_GPL_UNKNOWN,"set to mid address %02x address is now %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_WAITING_LOW_ADDR_FAST;
- break;
- }
-
- case SPI_STATE_WAITING_LOW_ADDR_FAST:
- {
- m_spiaddress = (m_spiaddress & 0xffffff00) | data;
- LOGMASKED(LOG_GPL_UNKNOWN,"set to low address %02x address is now %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_WAITING_LOW_ADDR_FAST_DUMMY;
-
- break;
- }
-
- case SPI_STATE_WAITING_LOW_ADDR_FAST_DUMMY:
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"dummy write %08x\n", data, m_spiaddress);
- m_spistate = SPI_STATE_READING_FAST;
- break;
- }
-
- case SPI_STATE_READING_FAST:
- {
- // writes when in read mode clock in data?
- LOGMASKED(LOG_GPL_UNKNOWN,"write while in read mode (clock data?)\n", data, m_spiaddress);
- break;
- }
-
- }
-}
-
-uint8_t pcp8718_state::spi_process_rx()
-{
-
- switch (m_spistate)
- {
- case SPI_STATE_READING:
- case SPI_STATE_READING_FAST:
- {
- uint8_t dat = m_spirom[m_spiaddress & 0x3fffff];
-
- // hack internal BIOS checksum check
- //if (m_spiaddress == ((0x49d13 - 0x20000) * 2)+1)
- // if (dat == 0x4e)
- // dat = 0x5e;
-
- LOGMASKED(LOG_GPL_UNKNOWN,"reading SPI %02x from SPI Address %08x (adjusted word offset %08x)\n", dat, m_spiaddress, (m_spiaddress/2)+0x20000);
- m_spiaddress++;
- return dat;
- }
-
- default:
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"reading FIFO in unknown state\n");
- return 0x00;
- }
- }
-
- return 0x00;
-}
-
-
-uint8_t pcp8718_state::spi_rx()
-{
- uint8_t ret = m_rx_fifo[0];
-
- m_rx_fifo[0] = m_rx_fifo[1];
- m_rx_fifo[1] = m_rx_fifo[2];
- m_rx_fifo[2] = m_rx_fifo[3];
- m_rx_fifo[3] = spi_process_rx();
-
- return ret;
-}
-
-uint8_t pcp8718_state::spi_rx_fast()
-{
- uint8_t ret = m_rx_fifo[0];
-
- m_rx_fifo[0] = m_rx_fifo[1];
- m_rx_fifo[1] = m_rx_fifo[2];
- m_rx_fifo[2] = m_rx_fifo[3];
- m_rx_fifo[3] = m_rx_fifo[4];
- m_rx_fifo[4] = spi_process_rx();
-
- return ret;
-}
-
-void pcp8718_state::spi_tx_fifo_w(uint16_t data)
-{
- data &= 0x00ff;
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: spi_tx_fifo_w %04x\n", machine().describe_context(), data);
-
- spi_process_tx_data(data);
-}
-
-// this is probably 'port b' but when SPI is enabled some points of this can become SPI control pins
-// it's accessed after each large data transfer, probably to reset the SPI into 'ready for command' state?
-void pcp8718_state::unk_7868_w(uint16_t data)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: unk_7868_w %04x (Port B + SPI reset?)\n", machine().describe_context(), data);
-
- if ((m_7868 & 0x0100) != (data & 0x0100))
- {
- if (!(data & 0x0100))
- {
- for (int i = 0; i < 4; i++)
- m_rx_fifo[i] = 0xff;
-
- m_spistate = SPI_STATE_READY;
- }
- }
-
- m_7868 = data;
-}
-
-uint16_t pcp8718_state::unk_7868_r()
-{
- return m_7868;
-}
-
-void pcp8718_state::bankswitch_707e_w(uint16_t data)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: bankswitch_707e_w %04x\n", machine().describe_context(), data);
- m_707e_bank = data;
-}
-
-uint16_t pcp8718_state::bankswitch_707e_r()
-{
- return m_707e_bank;
-}
-
-
-void pcp8718_state::bankswitch_703a_w(uint16_t data)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: bankswitch_703a_w %04x\n", machine().describe_context(), data);
- m_703a_bank = data;
-}
-
-uint16_t pcp8718_state::bankswitch_703a_r()
-{
- return m_703a_bank;
-}
-
-void pcp8718_state::bankedram_7300_w(offs_t offset, uint16_t data)
-{
- offset |= (m_703a_bank & 0x000c) << 6;
- m_bankedram_7300[offset] = data;
-}
-
-uint16_t pcp8718_state::bankedram_7300_r(offs_t offset)
-{
- offset |= (m_703a_bank & 0x000c) << 6;
- return m_bankedram_7300[offset];
-}
-
-void pcp8718_state::bankedram_7400_w(offs_t offset, uint16_t data)
-{
- if (m_707e_bank & 1)
- {
- m_bankedram_7400[offset + 0x400] = data;
- }
- else
- {
- m_bankedram_7400[offset] = data;
- }
-}
-
-uint16_t pcp8718_state::bankedram_7400_r(offs_t offset)
-{
- if (m_707e_bank & 1)
- {
- return m_bankedram_7400[offset + 0x400];
- }
- else
- {
- return m_bankedram_7400[offset];
- }
-}
-
-void pcp8718_state::system_dma_params_channel0_w(offs_t offset, uint16_t data)
-{
- m_dmaregs[offset] = data;
-
- switch (offset)
- {
- case 0:
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Mode)\n", machine().describe_context(), offset, data);
-
-#if 1
-
- uint16_t mode = m_dmaregs[0];
- uint32_t source = m_dmaregs[1] | (m_dmaregs[4] << 16);
- uint32_t dest = m_dmaregs[2] | (m_dmaregs[5] << 16) ;
- uint32_t length = m_dmaregs[3] | (m_dmaregs[6] << 16);
-
- if ((mode != 0x0200) && (mode != 0x4009) && (mode != 0x6009))
- fatalerror("unknown dma mode write %04x\n", data);
- if ((mode == 0x4009) || (mode == 0x6009))
- {
- address_space& mem = m_maincpu->space(AS_PROGRAM);
-
- for (int i = 0; i < length; i++)
- {
- uint16_t dat = mem.read_word(source);
-
- if (mode & 0x2000)
- {
- // Racing Car and Elevator Action need this logic, the code in gpl16250 should probably be like this
- // but currently gets used in non-increment mode
- mem.write_word(dest, dat & 0xff);
- dest++;
- mem.write_word(dest, dat >> 8);
- dest++;
- }
- else
- {
- mem.write_word(dest, dat);
- dest++;
- }
-
- source++;
- }
- }
-#endif
- break;
- }
- case 1:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Source Low)\n", machine().describe_context(), offset, data);
- break;
-
- case 2:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Dest Low)\n", machine().describe_context(), offset, data);
- break;
-
- case 3:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Length Low)\n", machine().describe_context(), offset, data);
- break;
-
- case 4:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Source High)\n", machine().describe_context(), offset, data);
- break;
-
- case 5:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Dest High)\n", machine().describe_context(), offset, data);
- break;
-
- case 6:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA Length High)\n", machine().describe_context(), offset, data);
- break;
-
- case 7:
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_w %01x %04x (DMA unknown)\n", machine().describe_context(), offset, data);
- break;
- }
-}
-
-uint16_t pcp8718_state::system_dma_params_channel0_r(offs_t offset)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: system_dma_params_channel0_r %01x\n", machine().describe_context(), offset);
- return m_dmaregs[offset];
-}
-
-uint16_t pcp8718_state::unk_7870_r()
-{
- logerror("%06x: unk_7870_r (IO port)\n", machine().describe_context());
- return m_io_p2->read();
-}
-
-void pcp8718_state::spi_control_w(uint16_t data)
-{
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: spi_control_w %04x\n", machine().describe_context(), data);
-}
-
-uint16_t pcp8718_state::unk_78a1_r()
-{
- // checked in interrupt, code skipped entirely if this isn't set
- return m_78a1;
-}
-
-void pcp8718_state::unk_78d8_w(uint16_t data)
-{
- // written in IRQ, possible ack
- if (data & 0x8000)
- m_78a1 &= ~0x8000;
-}
-
-
-void pcp8718_state::map(address_map &map)
+void generalplus_gpl_unknown_state::map(address_map &map)
{
- // there are calls to 01xxx and 02xxx regions
- // (RAM populated by internal ROM?, TODO: check to make sure code copied there isn't from SPI ROM like the GPL16250 bootstrap
- // does from NAND, it doesn't seem to have a header in the same format at least)
- map(0x000000, 0x006fff).ram().share("mainram");
-
- // registers at 7xxx are similar to GPL16250, but not identical? (different video system? or just GPL16250 with the video part unused?)
-
- map(0x00703a, 0x00703a).rw(FUNC(pcp8718_state::bankswitch_703a_r), FUNC(pcp8718_state::bankswitch_703a_w));
- map(0x00707e, 0x00707e).rw(FUNC(pcp8718_state::bankswitch_707e_r), FUNC(pcp8718_state::bankswitch_707e_w));
-
- map(0x007100, 0x0071ff).ram(); // rowscroll on gpl16250
- map(0x007300, 0x0073ff).rw(FUNC(pcp8718_state::bankedram_7300_r), FUNC(pcp8718_state::bankedram_7300_w)); // palette on gpl16250
- map(0x007400, 0x0077ff).rw(FUNC(pcp8718_state::bankedram_7400_r), FUNC(pcp8718_state::bankedram_7400_w)); // spriteram on gpl16250
-
- map(0x00780f, 0x00780f).r(FUNC(pcp8718_state::unk_780f_r));
-
-
- map(0x007860, 0x007860).rw(FUNC(pcp8718_state::unk_7860_r),FUNC(pcp8718_state::unk_7860_w));
- map(0x007862, 0x007862).nopw();
- map(0x007863, 0x007863).nopw();
-
- map(0x007868, 0x007868).rw(FUNC(pcp8718_state::unk_7868_r), FUNC(pcp8718_state::unk_7868_w));
-
- map(0x007870, 0x007870).r(FUNC(pcp8718_state::unk_7870_r)); // I/O
-
- map(0x0078a1, 0x0078a1).r(FUNC(pcp8718_state::unk_78a1_r));
-
- map(0x0078d8, 0x0078d8).w(FUNC(pcp8718_state::unk_78d8_w));
-
-
- map(0x007940, 0x007940).w(FUNC(pcp8718_state::spi_control_w));
- // 7941 SPI Transmit Status
- map(0x007942, 0x007942).w(FUNC(pcp8718_state::spi_tx_fifo_w));
- // 7943 SPI Receive Status
- map(0x007944, 0x007944).r(FUNC(pcp8718_state::spi_rx_fifo_r));
- map(0x007945, 0x007945).r(FUNC(pcp8718_state::spi_misc_control_r));
-
- map(0x007a80, 0x007a87).rw(FUNC(pcp8718_state::system_dma_params_channel0_r), FUNC(pcp8718_state::system_dma_params_channel0_w));
-
- map(0x007abf, 0x007abf).r(FUNC(pcp8718_state::unk_7abf_r));
+ map(0x000000, 0x00ffff).ram(); // unknown, RAM/ROM? there are jumps to this region, doesn't seem the usual unSP 8000-ffff ROM mapping
// there are calls to 0x0f000 (internal ROM?)
- map(0x00f000, 0x00ffff).rom().region("maincpu", 0x00000);
-
- // external LCD controller
- map(0x200000, 0x200000).w(FUNC(pcp8718_state::lcd_command_w));
- map(0x20fc00, 0x20fc00).w(FUNC(pcp8718_state::lcd_w));
-}
-
-void pcp8718_state::lcd_command_w(uint16_t data)
-{
- data &= 0xff;
-
- switch (m_lcdstate)
- {
- case LCD_STATE_READY:
- case LCD_STATE_PROCESSING_COMMAND:
- {
- if (data == 0x0000)
- {
- m_lcdstate = LCD_STATE_WAITING_FOR_COMMAND;
- m_lastlcdcommand = 0;
- }
- break;
- }
-
- case LCD_STATE_WAITING_FOR_COMMAND:
- {
- m_lastlcdcommand = data;
- m_lcdstate = LCD_STATE_PROCESSING_COMMAND;
- break;
- }
-
- }
-}
-
-void pcp8718_state::lcd_w(uint16_t data)
-{
- data &= 0xff; // definitely looks like 8-bit port as 16-bit values are shifted and rewritten
- LOGMASKED(LOG_GPL_UNKNOWN,"%06x: lcd_w %02x\n", machine().describe_context(), data);
-
- if ((m_lcdstate == LCD_STATE_PROCESSING_COMMAND) && (m_lastlcdcommand == 0x22))
- {
- m_displaybuffer[m_lcdaddr] = data;
- m_lcdaddr++;
-
- if (m_lcdaddr >= ((320 * 240) * 2))
- m_lcdaddr = 0;
-
- //m_lcdaddr &= 0x3ffff;
- }
-}
-
-uint16_t pcp8718_state::simulate_f000_r(offs_t offset)
-{
- if (!machine().side_effects_disabled())
- {
- uint16_t pc = m_maincpu->state_int(UNSP_PC);
- uint16_t sr = m_maincpu->state_int(UNSP_SR);
- int realpc = (pc | (sr << 16)) & 0x003fffff;
-
- if ((offset + 0xf000) == (realpc))
- {
- //LOGMASKED(LOG_GPL_UNKNOWN,"simulate_f000_r reading BIOS area (for BIOS call?) %04x\n", offset);
- return m_mainrom[offset];
- }
- else
- {
- //LOGMASKED(LOG_GPL_UNKNOWN,"simulate_f000_r reading BIOS area (for checksum?) %04x\n", offset);
- return m_mainrom[offset];
- }
- }
- return m_mainrom[offset];
-}
-
-uint16_t pcp8718_state::ramcall_2060_logger_r()
-{
- if (!machine().side_effects_disabled())
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"call to 0x2060 in RAM (set SPI to read mode, set address, do dummy FIFO reads)\n");
- }
- return m_mainram[0x2060];
-}
-
-uint16_t pcp8718_state::ramcall_2189_logger_r()
-{
- if (!machine().side_effects_disabled())
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"call to 0x2189 in RAM (unknown)\n");
- }
- return m_mainram[0x2189];
-}
-
-
-uint16_t pcp8718_state::ramcall_2829_logger_r()
-{
- // this in turn calls 28f7 but has restore logic too
- if (!machine().side_effects_disabled())
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"call to 0x2829 in RAM (load+call function from SPI address %08x)\n", (m_mainram[0x1e] << 16) | m_mainram[0x1d]);
- }
- return m_mainram[0x2829];
-}
-
-
-uint16_t pcp8718_state::ramcall_287a_logger_r()
-{
- // this transmits to a device, then reads back the result, needed for menu navigation?!
- // TODO: data should transmit etc. over bits in the I/O ports, this is HLE, although
- // most of this code will end up in a simulation handler for whatever this device is
-
- if (!machine().side_effects_disabled())
- {
- if (m_maincpu->pc() == 0x287a)
- {
- // 1d = command, 1e = param?
- int command = m_mainram[0x1d] & 0xff;
- int param = m_mainram[0x1e] & 0xff;
-
- if ((command) == 0x00) // request result low
- {
- m_maincpu->set_state_int(UNSP_R1, m_stored_gamenum & 0xff);
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x (request result low)\n", command);
- }
- else if ((command) == 0x01) // request result high
- {
- m_maincpu->set_state_int(UNSP_R1, (m_stored_gamenum>>8) & 0xff);
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x (request result high)\n", command);
- }
- else if ((command) == 0x02)
- {
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x %02x (set data low)\n", command, param);
- m_stored_gamenum = (m_stored_gamenum & 0xff00) | (m_mainram[0x1e] & 0x00ff);
- }
- else if ((command) == 0x03)
- {
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x %02x (set data high)\n", command, param);
- m_stored_gamenum = (m_stored_gamenum & 0x00ff) | ((m_mainram[0x1e] & 0x00ff) << 8);
- }
- else if ((command) == 0x04)
- {
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x %02x (set add value)\n", command, param);
- // used with down
- if (param == 0x03)
- m_addval = 4;
- else if (param == 0x00)
- m_addval = 0;
-
- // used if you try to scroll up or left past 0 and the value becomes too large (a negative number)
- // actually writes 0x314 split into 2 commands, so the 2nd write to 0x04 with param then instead 0b/16 sequence of writes instead of 26/0c adds to the high byte?
- if (param == 0x14)
- m_addval = 0x314;
-
- }
- else if ((command) == 0x05)
- {
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x %02x (set subtract value)\n", command, param);
-
- // used if you try to scroll down past the and the value becomes too large
- // actually writes 0x313 split into 2 commands, so the 2nd write to 0x05 with param then instead 0b/16 sequence of writes instead of 26/0c subtracts from the high byte?
- if (param == 0x13)
- m_addval = -0x314; // why 314, it writes 313
-
- }
- else if ((command) == 0x10)
- {
- // this is followed by 0x1b, written if you try to move right off last entry
- m_stored_gamenum = 0x00;
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x (reset value)\n", command);
- }
- else if (command == 0x26)
- {
- // used in direction handlers after writing the first command
- m_stored_gamenum += m_addval;
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x\n", command);
- }
- else if (command == 0x30)
- {
- // used with right
- m_addval = 1;
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x\n", command);
- // 26/0c called after this, then another fixed command value, then 0b/16
- // unlike commands 04/05 there's no parameter byte written here, must be derived from the command?
- }
- else if (command == 0x37)
- {
- // used with left
- m_addval = -1;
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x\n", command);
- // 26/0c called after this, then another fixed command value, then 0b/16
- // unlike commands 04/05 there's no parameter byte written here, must be derived from the command?
- }
- else if (command == 0x39)
- {
- // used with up
- m_addval = -4;
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x\n", command);
- // 26/0c called after this, then another fixed command value, then 0b/16
- // unlike commands 04/05 there's no parameter byte written here, must be derived from the command?
- }
- else
- {
- LOGMASKED(LOG_GPL_UNKNOWN_SELECT_SIM,"call to 0x287a in RAM (transmit / receive) %02x\n", command);
- }
-
- // hack retf
- return 0x9a90;
- }
- }
- return m_mainram[0x287a];
+ map(0x200000, 0x3fffff).ram(); // almost certainly RAM where the SPI ROM gets copied
}
-uint16_t pcp8718_state::ramcall_28f7_logger_r()
-{
- if (!machine().side_effects_disabled())
- {
- // no restore logic?
- LOGMASKED(LOG_GPL_UNKNOWN,"call to 0x28f7 in RAM (load+GO TO function from SPI address %08x)\n", (m_mainram[0x1e] << 16) | m_mainram[0x1d]);
- }
- return m_mainram[0x28f7];
-}
-uint16_t pcp8718_state::ramcall_2079_logger_r()
+void generalplus_gpl_unknown_state::machine_start()
{
- if (!machine().side_effects_disabled())
- {
- LOGMASKED(LOG_GPL_UNKNOWN,"call to 0x2079 in RAM (maybe drawing related?)\n"); // called in the 'dummy' loop that doesn't actually draw? and other places? as well as after the actual draw command below in the real loop
- }
- return m_mainram[0x2079];
}
-uint16_t pcp8718_state::ramcall_2434_logger_r()
+void generalplus_gpl_unknown_state::machine_reset()
{
- if (!machine().side_effects_disabled())
+ address_space& mem = m_maincpu->space(AS_PROGRAM);
+ for (int j = 0; j < 0x200000/2; j++)
{
- LOGMASKED(LOG_GPL_UNKNOWN,"call to 0x2434 in RAM (drawing related?)\n"); // [1d] as the tile / sprite number, [1e] as xpos, [1f] as ypos, [20] as 0. [21] as ff in some title drawing calls
+ uint16_t data = (m_spirom[(j*2)+1] << 8) | (m_spirom[(j*2)+0]);
+ mem.write_word(0x200000+j, data);
}
- return m_mainram[0x2434];
-}
-
-void pcp8718_state::machine_start()
-{
-}
-
-void pcp8718_state::machine_reset()
-{
- m_maincpu->space(AS_PROGRAM).install_read_handler(0xf000, 0xffff, read16sm_delegate(*this, FUNC(pcp8718_state::simulate_f000_r)));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x2060, 0x2060, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_2060_logger_r)));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x2079, 0x2079, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_2079_logger_r)));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x2189, 0x2189, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_2189_logger_r)));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x2434, 0x2434, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_2434_logger_r)));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x2829, 0x2829, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_2829_logger_r)));
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x287a, 0x287a, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_287a_logger_r)));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x28f7, 0x28f7, read16smo_delegate(*this, FUNC(pcp8718_state::ramcall_28f7_logger_r)));
-
- m_spistate = SPI_STATE_READY;
- m_spiaddress = 0;
-
- for (int i = 0; i < 320*240*2; i++)
- m_displaybuffer[i] = 0x00;
-
- m_lcdaddr = 0;
-
- m_lcdstate = LCD_STATE_READY;
- m_lastlcdcommand = 0;
-
- m_78a1 = 0;
+ m_maincpu->set_state_int(UNSP_PC, 0x1000); // this is not the boot code, everything in the SPI ROM seems like relatively small functions (that never touch internal registers) only the very last one in SPI ROM has no callers from in the SPI ROM code
+ m_maincpu->set_state_int(UNSP_SR, 0x0020);
}
-WRITE_LINE_MEMBER(pcp8718_state::screen_vblank)
+void generalplus_gpl_unknown_state::generalplus_gpl_unknown(machine_config &config)
{
- if (state)
- {
- // probably a timer
- m_maincpu->set_input_line(UNSP_IRQ4_LINE, ASSERT_LINE);
- m_78a1 |= 0x8000;
- }
- else
- {
- m_maincpu->set_input_line(UNSP_IRQ4_LINE, CLEAR_LINE);
- }
-}
-void pcp8718_state::pcp8718(machine_config &config)
-{
-
- UNSP_20(config, m_maincpu, 96000000); // unknown CPU, unsp20 based, 96Mhz is listed as the maximum for most unSP2.0 chips, and appears correct here
- m_maincpu->set_addrmap(AS_PROGRAM, &pcp8718_state::map);
+ UNSP_20(config, m_maincpu, 96000000); // unknown CPU, no unSP2.0 opcodes?
+ m_maincpu->set_addrmap(AS_PROGRAM, &generalplus_gpl_unknown_state::map);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(60);
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(10));
m_screen->set_size(64*8, 32*8);
m_screen->set_visarea(0*8, 320-1, 0*8, 240-1);
- m_screen->set_screen_update(FUNC(pcp8718_state::screen_update));
- //m_screen->set_palette(m_palette);
- m_screen->screen_vblank().set(FUNC(pcp8718_state::screen_vblank));
+ m_screen->set_screen_update(FUNC(generalplus_gpl_unknown_state::screen_update));
+ //m_screen->screen_vblank().set(FUNC(generalplus_gpl_unknown_state::screen_vblank));
PALETTE(config, m_palette).set_format(palette_device::xBGR_555, 0x8000);
}
-// pcp8718 and pcp8728 both contain user data (player name?) and will need to be factory defaulted once they work
-// the ROM code is slightly different between them
-
-ROM_START( pcp8718 )
- ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD( "internal.rom", 0x000000, 0x2000, CRC(ea119561) SHA1(a2680577e20fe1155efc40a5781cf1ec80ccec3a) )
-
- ROM_REGION( 0x800000, "spi", ROMREGION_ERASEFF )
- //ROM_LOAD16_WORD_SWAP( "8718_en25f32.bin", 0x000000, 0x400000, CRC(cc138db4) SHA1(379af3d94ae840f52c06416d6cf32e25923af5ae) ) // bad dump, some blocks are corrupt
- ROM_LOAD( "eyecare_25q32av1g_ef4016.bin", 0x000000, 0x400000, CRC(58415e10) SHA1(b1adcc03f2ad8d741544204671677740e904ce1a) )
-ROM_END
-
-ROM_START( pcp8728 )
- ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD( "internal.rom", 0x000000, 0x2000, CRC(ea119561) SHA1(a2680577e20fe1155efc40a5781cf1ec80ccec3a) )
+ROM_START( mapacman )
+ //ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
+ //ROM_LOAD16_WORD_SWAP( "internal.rom", 0x000000, 0x2000, NO_DUMP ) // exact size unknown
ROM_REGION( 0x800000, "spi", ROMREGION_ERASEFF )
- ROM_LOAD( "pcp 8728 788 in 1.bin", 0x000000, 0x400000, CRC(60115f21) SHA1(e15c39f11e442a76fae3823b6d510178f6166926) )
+ ROM_LOAD( "fm25q16a.bin", 0x000000, 0x200000, CRC(aeb472ac) SHA1(500c24b725f6d3308ef8cbdf4259f5be556c7c92) )
ROM_END
-ROM_START( unkunsp )
- ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
- ROM_LOAD16_WORD_SWAP( "internal.rom", 0x000000, 0x2000, NO_DUMP ) // exact size unknown
+ROM_START( taspinv )
+ //ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
+ //ROM_LOAD16_WORD_SWAP( "internal.rom", 0x000000, 0x2000, NO_DUMP ) // exact size unknown
ROM_REGION( 0x800000, "spi", ROMREGION_ERASEFF )
- ROM_LOAD( "fm25q16a.bin", 0x000000, 0x200000, CRC(aeb472ac) SHA1(500c24b725f6d3308ef8cbdf4259f5be556c7c92) )
+ ROM_LOAD( "tinyarcade_spaceinvaders.bin", 0x000000, 0x200000, CRC(11ac4c77) SHA1(398d5eff83a4e94487ed810819085a0e44582908) )
ROM_END
-void pcp8718_state::spi_init()
-{
-}
-
+// first 0x2000 bytes in ROM are blank, ROM data maps fully in RAM at 200000, but there are calls to lower regions
+// is it possible the SunPlus here is only handling sound / graphics, not gameplay?
-CONS( 200?, pcp8718, 0, 0, pcp8718, pcp8718, pcp8718_state, spi_init, "PCP", "PCP 8718 - HD 360 Degrees Rocker Palm Eyecare Console - 788 in 1", MACHINE_IS_SKELETON )
-CONS( 200?, pcp8728, 0, 0, pcp8718, pcp8718, pcp8718_state, spi_init, "PCP", "PCP 8728 - 788 in 1", MACHINE_IS_SKELETON ) // what name was this sold under?
+CONS( 2017, mapacman, 0, 0, generalplus_gpl_unknown, generalplus_gpl_unknown, generalplus_gpl_unknown_state, empty_init, "Super Impulse", "Pac-Man (Micro Arcade)", MACHINE_IS_SKELETON )
-// maybe different hardware, first 0x2000 bytes in ROM is blank, so bootstrap pointers aren't there at least
-CONS( 200?, unkunsp, 0, 0, pcp8718, pcp8718, pcp8718_state, empty_init, "<unknown>", "unknown unSP-based handheld", MACHINE_IS_SKELETON )
+// multiple different units appear to share the same ROM with a jumper to select game, it should be verified in each case that the external ROM was not changed.
+CONS( 2017, taspinv, 0, 0, generalplus_gpl_unknown, generalplus_gpl_unknown, generalplus_gpl_unknown_state, empty_init, "Super Impulse", "Space Invaders (Tiny Arcade)", MACHINE_IS_SKELETON )
diff --git a/src/mame/drivers/geniusiq.cpp b/src/mame/drivers/geniusiq.cpp
index 9350d3c4989..b46c3df2457 100644
--- a/src/mame/drivers/geniusiq.cpp
+++ b/src/mame/drivers/geniusiq.cpp
@@ -275,7 +275,7 @@ uint32_t geniusiq_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
for(int b=0; b<4; b++)
{
- bitmap.pix16(y, x*2 + b) = (data>>12) & 0x0f;
+ bitmap.pix(y, x*2 + b) = (data>>12) & 0x0f;
data <<= 4;
}
}
@@ -292,7 +292,7 @@ uint32_t geniusiq_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
// I assume color 0 is transparent
if(pen != 0 && screen.visible_area().contains(m_mouse_gfx_posx + x*4 + b, m_mouse_gfx_posy + y))
- bitmap.pix16(m_mouse_gfx_posy + y, m_mouse_gfx_posx + x*4 + b) = pen;
+ bitmap.pix(m_mouse_gfx_posy + y, m_mouse_gfx_posx + x*4 + b) = pen;
data <<= 2;
}
}
diff --git a/src/mame/drivers/gigatron.cpp b/src/mame/drivers/gigatron.cpp
index 3261208786b..a6c86d2df37 100644
--- a/src/mame/drivers/gigatron.cpp
+++ b/src/mame/drivers/gigatron.cpp
@@ -103,7 +103,7 @@ void gigatron_state::video_start()
void gigatron_state::video_reset()
{
- uint32_t *dest = &m_bitmap_render->pix32(0, 0);
+ uint32_t *dest = &m_bitmap_render->pix(0, 0);
for(uint32_t i = 0; i < 640*480; i++)
*dest++ = 0;
}
@@ -138,7 +138,7 @@ void gigatron_state::port_out(uint8_t data)
uint8_t r = (out << 6) & 0xC0;
uint8_t g = (out << 4) & 0xC0;
uint8_t b = (out << 2) & 0xC0;
- uint32_t *dest = &m_bitmap_render->pix32(m_row, m_col);
+ uint32_t *dest = &m_bitmap_render->pix(m_row, m_col);
for(uint8_t i = 0; i < 4; i++)
*dest++ = b|(g<<8)|(r<<16);
}
@@ -255,7 +255,7 @@ void gigatron_state::gigatron(machine_config &config)
ROM_START( gigatron )
ROM_REGION( 0x20000, "maincpu", 0 )
ROM_SYSTEM_BIOS(0, "v5a", "Gigatron ROM v5a")
- ROMX_LOAD( "gigrom5a.rom", 0x0000, 0x20000, CRC(DCC071A6) SHA1(F82059BA0227FF48E4C687B90C8445DA30213EE2),ROM_BIOS(0))
+ ROMX_LOAD( "gigrom5a.rom", 0x0000, 0x20000, CRC(dcc071a6) SHA1(f82059ba0227ff48e4c687b90c8445da30213ee2),ROM_BIOS(0))
ROM_SYSTEM_BIOS(1, "v4", "Gigatron ROM v4")
ROMX_LOAD( "gigrom4.rom", 0x0000, 0x20000, CRC(78995109) SHA1(2395fc48e64099836111f5aeca39ddbf4650ea4e),ROM_BIOS(1))
ROM_SYSTEM_BIOS(2, "v3", "Gigatron ROM v3")
diff --git a/src/mame/drivers/ginganin.cpp b/src/mame/drivers/ginganin.cpp
index 5b6263f22de..caa0b4c5027 100644
--- a/src/mame/drivers/ginganin.cpp
+++ b/src/mame/drivers/ginganin.cpp
@@ -82,7 +82,7 @@ f5d6 print 7 digit BCD number: d0.l to (a1)+ color $3000
void ginganin_state::main_map(address_map &map)
{
- // PC=0x408 ROM area 10000-13fff is written at POST with: 0000 0000 0000 0001,
+ // PC=0x408 ROM area 10000-13fff is written at POST with: 0000 0000 0000 0001,
// looks a debugging left-over for GFX patching (causes state garbage if hooked as RAM write mirror)
map(0x000000, 0x01ffff).rom().nopw();
map(0x020000, 0x023fff).ram();
@@ -360,10 +360,10 @@ void ginganin_state::init_ginganin()
{
// pending full removal of this patch ...
/* main cpu patches */
-// u16 *rom = (u16 *)memregion("maincpu")->base();
+// u16 *rom = (u16 *)memregion("maincpu")->base();
/* avoid writes to rom getting to the log */
-// rom[0x408 / 2] = 0x6000;
-// rom[0x40a / 2] = 0x001c;
+// rom[0x408 / 2] = 0x6000;
+// rom[0x40a / 2] = 0x001c;
}
diff --git a/src/mame/drivers/gkigt.cpp b/src/mame/drivers/gkigt.cpp
index 4dfd39519ce..4b670245d25 100644
--- a/src/mame/drivers/gkigt.cpp
+++ b/src/mame/drivers/gkigt.cpp
@@ -162,22 +162,18 @@ void igt_gameking_state::video_start()
uint32_t igt_gameking_state::screen_update_igt_gameking(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x,y;
-
bitmap.fill(m_palette->black_pen(), cliprect);
- for(y = 0; y < 480; y++)
+ for(int y = 0; y < 480; y++)
{
- for(x = 0; x < 640; x+=4)
+ for(int x = 0; x < 640; x+=4)
{
for(int xi=0;xi<4;xi++)
{
- uint32_t color;
-
- color = (m_vram[(x+y*1024)/4] >> (xi*8)) & 0xff;
+ uint32_t const color = (m_vram[(x+y*1024)/4] >> (xi*8)) & 0xff;
if(cliprect.contains(x+xi, y))
- bitmap.pix16(y, x+xi) = m_palette->pen(color);
+ bitmap.pix(y, x+xi) = m_palette->pen(color);
}
}
diff --git a/src/mame/drivers/gmaster.cpp b/src/mame/drivers/gmaster.cpp
index 76e5f116817..cd798155887 100644
--- a/src/mame/drivers/gmaster.cpp
+++ b/src/mame/drivers/gmaster.cpp
@@ -280,30 +280,20 @@ void gmaster_state::gmaster_palette(palette_device &palette) const
uint32_t gmaster_state::screen_update_gmaster(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x,y;
- for (y = 0; y < ARRAY_LENGTH(m_video.pixels); y++)
+ for (int y = 0; y < ARRAY_LENGTH(m_video.pixels); y++)
{
- for (x = 0; x < ARRAY_LENGTH(m_video.pixels[0]); x++)
+ for (int x = 0; x < ARRAY_LENGTH(m_video.pixels[0]); x++)
{
- uint8_t d = m_video.pixels[y][x];
- uint16_t *line;
-
- line = &bitmap.pix16((y * 8), x);
- line[0] = BIT(d, 0);
- line = &bitmap.pix16((y * 8 + 1), x);
- line[0] = BIT(d, 1);
- line = &bitmap.pix16((y * 8 + 2), x);
- line[0] = BIT(d, 2);
- line = &bitmap.pix16((y * 8 + 3), x);
- line[0] = BIT(d, 3);
- line = &bitmap.pix16((y * 8 + 4), x);
- line[0] = BIT(d, 4);
- line = &bitmap.pix16((y * 8 + 5), x);
- line[0] = BIT(d, 5);
- line = &bitmap.pix16((y * 8 + 6), x);
- line[0] = BIT(d, 6);
- line = &bitmap.pix16((y * 8 + 7), x);
- line[0] = BIT(d, 7);
+ uint8_t const d = m_video.pixels[y][x];
+
+ bitmap.pix((y * 8 + 0), x) = BIT(d, 0);
+ bitmap.pix((y * 8 + 1), x) = BIT(d, 1);
+ bitmap.pix((y * 8 + 2), x) = BIT(d, 2);
+ bitmap.pix((y * 8 + 3), x) = BIT(d, 3);
+ bitmap.pix((y * 8 + 4), x) = BIT(d, 4);
+ bitmap.pix((y * 8 + 5), x) = BIT(d, 5);
+ bitmap.pix((y * 8 + 6), x) = BIT(d, 6);
+ bitmap.pix((y * 8 + 7), x) = BIT(d, 7);
}
}
return 0;
diff --git a/src/mame/drivers/goldart.cpp b/src/mame/drivers/goldart.cpp
index 975211b4e8c..d2b95d88a63 100644
--- a/src/mame/drivers/goldart.cpp
+++ b/src/mame/drivers/goldart.cpp
@@ -111,9 +111,9 @@ uint32_t goldart_state::screen_update_goldart(screen_device& screen, bitmap_ind1
{
for (int x = 0; x < 192; x++)
{
- uint16_t* dstptr_bitmap = &bitmap.pix16(y);
- uint8_t data = m_ram[count];
- uint8_t data2 = m_ram2[count];
+ uint16_t *const dstptr_bitmap = &bitmap.pix(y);
+ uint8_t const data = m_ram[count];
+ uint8_t const data2 = m_ram2[count];
count++;
diff --git a/src/mame/drivers/goldngam.cpp b/src/mame/drivers/goldngam.cpp
index c701d74f91e..27c0b483c20 100644
--- a/src/mame/drivers/goldngam.cpp
+++ b/src/mame/drivers/goldngam.cpp
@@ -300,8 +300,8 @@ uint32_t goldngam_state::screen_update_goldngam(screen_device &screen, bitmap_in
for(int x = 0; x < 384; x += 2)
{
uint16_t word = m_videoram[index];
- bitmap.pix16(y, x) = word >> 8;
- bitmap.pix16(y, x+1) = word & 0xff;
+ bitmap.pix(y, x) = word >> 8;
+ bitmap.pix(y, x+1) = word & 0xff;
++index;
}
}
diff --git a/src/mame/drivers/goupil.cpp b/src/mame/drivers/goupil.cpp
index 38fc94e5cb2..b4bcae82f41 100644
--- a/src/mame/drivers/goupil.cpp
+++ b/src/mame/drivers/goupil.cpp
@@ -489,7 +489,7 @@ WRITE_LINE_MEMBER( goupil_g1_state::via_video_ca2_w )
MC6845_UPDATE_ROW(goupil_g2_state::crtc_update_row)
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
for (uint8_t x = 0; x < x_count; ++x)
{
uint16_t const offset = ( 0x400 + ( ma + x ) ) & 0x7FF;
diff --git a/src/mame/drivers/gp2x.cpp b/src/mame/drivers/gp2x.cpp
index 2ff5addc312..7c2af984b7c 100644
--- a/src/mame/drivers/gp2x.cpp
+++ b/src/mame/drivers/gp2x.cpp
@@ -159,8 +159,7 @@ uint32_t gp2x_state::screen_update_gp2x(screen_device &screen, bitmap_rgb32 &bit
// only support RGB still image layer for now
if (m_vidregs[0x80/2] & 4)
{
- int x, y;
- uint16_t *vram = (uint16_t *)&m_ram[0x2100000/4];
+ uint16_t const *const vram = (uint16_t *)&m_ram[0x2100000/4];
/* printf("RGB still image 1 enabled, bpp %d, size is %d %d %d %d\n",
(m_vidregs[(0xda/2)]>>9)&3,
@@ -170,13 +169,13 @@ uint32_t gp2x_state::screen_update_gp2x(screen_device &screen, bitmap_rgb32 &bit
m_vidregs[(0xe8/2)]);*/
- for (y = 0; y < 240; y++)
+ for (int y = 0; y < 240; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
- for (x = 0; x < 320; x++)
+ for (int x = 0; x < 320; x++)
{
- uint16_t pixel = vram[(320*y)+x];
+ uint16_t const pixel = vram[(320*y)+x];
*scanline++ = rgb_t(0xff, (pixel>>11)<<3, ((pixel>>5)&0x3f)<<2, (pixel&0x1f)<<3);
}
diff --git a/src/mame/drivers/gp32.cpp b/src/mame/drivers/gp32.cpp
index 34a80fedcda..189babc7069 100644
--- a/src/mame/drivers/gp32.cpp
+++ b/src/mame/drivers/gp32.cpp
@@ -143,21 +143,20 @@ uint32_t gp32_state::s3c240x_lcd_dma_read( )
void gp32_state::s3c240x_lcd_render_01( )
{
bitmap_rgb32 &bitmap = m_bitmap;
- uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
- int i, j;
- for (i = 0; i < 4; i++)
+ uint32_t *scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ for (int i = 0; i < 4; i++)
{
uint32_t data = s3c240x_lcd_dma_read();
- for (j = 0; j < 32; j++)
+ for (int j = 0; j < 32; j++)
{
*scanline++ = m_palette->pen_color((data >> 31) & 0x01);
- data = data << 1;
+ data <<= 1;
m_s3c240x_lcd.hpos++;
if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 4))
{
m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
m_s3c240x_lcd.hpos = 0;
- scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
}
}
}
@@ -166,21 +165,20 @@ void gp32_state::s3c240x_lcd_render_01( )
void gp32_state::s3c240x_lcd_render_02( )
{
bitmap_rgb32 &bitmap = m_bitmap;
- uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
- int i, j;
- for (i = 0; i < 4; i++)
+ uint32_t *scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ for (int i = 0; i < 4; i++)
{
uint32_t data = s3c240x_lcd_dma_read();
- for (j = 0; j < 16; j++)
+ for (int j = 0; j < 16; j++)
{
*scanline++ = m_palette->pen_color((data >> 30) & 0x03);
- data = data << 2;
+ data <<= 2;
m_s3c240x_lcd.hpos++;
if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 3))
{
m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
m_s3c240x_lcd.hpos = 0;
- scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
}
}
}
@@ -189,21 +187,20 @@ void gp32_state::s3c240x_lcd_render_02( )
void gp32_state::s3c240x_lcd_render_04( )
{
bitmap_rgb32 &bitmap = m_bitmap;
- uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
- int i, j;
- for (i = 0; i < 4; i++)
+ uint32_t *scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ for (int i = 0; i < 4; i++)
{
uint32_t data = s3c240x_lcd_dma_read( );
- for (j = 0; j < 8; j++)
+ for (int j = 0; j < 8; j++)
{
*scanline++ = m_palette->pen_color((data >> 28) & 0x0F);
- data = data << 4;
+ data <<= 4;
m_s3c240x_lcd.hpos++;
if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 2))
{
m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
m_s3c240x_lcd.hpos = 0;
- scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
}
}
}
@@ -212,21 +209,20 @@ void gp32_state::s3c240x_lcd_render_04( )
void gp32_state::s3c240x_lcd_render_08( )
{
bitmap_rgb32 &bitmap = m_bitmap;
- uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
- int i, j;
- for (i = 0; i < 4; i++)
+ uint32_t *scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ for (int i = 0; i < 4; i++)
{
uint32_t data = s3c240x_lcd_dma_read();
- for (j = 0; j < 4; j++)
+ for (int j = 0; j < 4; j++)
{
*scanline++ = m_palette->pen_color((data >> 24) & 0xFF);
- data = data << 8;
+ data <<= 8;
m_s3c240x_lcd.hpos++;
if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 1))
{
m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
m_s3c240x_lcd.hpos = 0;
- scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
}
}
}
@@ -235,21 +231,20 @@ void gp32_state::s3c240x_lcd_render_08( )
void gp32_state::s3c240x_lcd_render_16( )
{
bitmap_rgb32 &bitmap = m_bitmap;
- uint32_t *scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
- int i, j;
- for (i = 0; i < 4; i++)
+ uint32_t *scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ for (int i = 0; i < 4; i++)
{
uint32_t data = s3c240x_lcd_dma_read();
- for (j = 0; j < 2; j++)
+ for (int j = 0; j < 2; j++)
{
*scanline++ = s3c240x_get_color_5551( (data >> 16) & 0xFFFF);
- data = data << 16;
+ data <<= 16;
m_s3c240x_lcd.hpos++;
if (m_s3c240x_lcd.hpos >= (m_s3c240x_lcd.pagewidth_max << 0))
{
m_s3c240x_lcd.vpos = (m_s3c240x_lcd.vpos + 1) % (m_s3c240x_lcd.lineval + 1);
m_s3c240x_lcd.hpos = 0;
- scanline = &bitmap.pix32(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
+ scanline = &bitmap.pix(m_s3c240x_lcd.vpos, m_s3c240x_lcd.hpos);
}
}
}
diff --git a/src/mame/drivers/gpworld.cpp b/src/mame/drivers/gpworld.cpp
index 0e717fe6fea..d9d008b31b7 100644
--- a/src/mame/drivers/gpworld.cpp
+++ b/src/mame/drivers/gpworld.cpp
@@ -138,7 +138,7 @@ void gpworld_state::draw_pixel(bitmap_rgb32 &bitmap,const rectangle &cliprect,in
}
if (cliprect.contains(x, y))
- bitmap.pix32(y, x) = m_palette->pen(color);
+ bitmap.pix(y, x) = m_palette->pen(color);
}
void gpworld_state::draw_sprites(bitmap_rgb32 &bitmap, const rectangle &cliprect)
diff --git a/src/mame/drivers/grfd2301.cpp b/src/mame/drivers/grfd2301.cpp
index 6767c3d543d..a17b1616455 100644
--- a/src/mame/drivers/grfd2301.cpp
+++ b/src/mame/drivers/grfd2301.cpp
@@ -82,21 +82,20 @@ void grfd2301_state::machine_reset()
uint32_t grfd2301_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,chr,gfx;
- uint16_t sy=0,ma=0,x;
+ uint16_t sy=0,ma=0;
- for (y = 0; y < 24; y++)
+ for (uint8_t y = 0; y < 24; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (uint8_t ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = 0; x < 80; x++)
+ for (uint16_t x = 0; x < 80; x++)
{
- gfx = 0;
+ uint8_t gfx = 0;
if (ra < 9)
{
- chr = m_p_videoram[x+ma];
+ uint8_t chr = m_p_videoram[x+ma];
gfx = m_p_chargen[(chr<<4) | ra ];
}
diff --git a/src/mame/drivers/gridcomp.cpp b/src/mame/drivers/gridcomp.cpp
index 63d41b12390..1deb3174053 100644
--- a/src/mame/drivers/gridcomp.cpp
+++ b/src/mame/drivers/gridcomp.cpp
@@ -246,18 +246,15 @@ uint8_t gridcomp_state::grid_dma_r(offs_t offset)
uint32_t gridcomp_state::screen_update_generic(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int px)
{
- int x, y, offset;
- uint16_t gfx, *p;
-
- for (y = 0; y < 240; y++)
+ for (int y = 0; y < 240; y++)
{
- p = &bitmap.pix16(y);
+ uint16_t *p = &bitmap.pix(y);
- offset = y * (px / 16);
+ int const offset = y * (px / 16);
- for (x = offset; x < offset + px / 16; x++)
+ for (int x = offset; x < offset + px / 16; x++)
{
- gfx = m_videoram[x];
+ uint16_t const gfx = m_videoram[x];
for (int i = 15; i >= 0; i--)
{
diff --git a/src/mame/drivers/gstream.cpp b/src/mame/drivers/gstream.cpp
index c5d88370663..95f27a7c4d4 100644
--- a/src/mame/drivers/gstream.cpp
+++ b/src/mame/drivers/gstream.cpp
@@ -587,10 +587,8 @@ void gstream_state::drawgfx_transpen_x2222(bitmap_rgb32 &dest, const rectangle &
do {
g_profiler.start(PROFILER_DRAWGFX);
do {
- const uint8_t *srcdata, *srcdata2;
int32_t destendx, destendy;
int32_t srcx, srcy;
- int32_t curx, cury;
int32_t dy;
assert(dest.valid());
@@ -649,8 +647,8 @@ void gstream_state::drawgfx_transpen_x2222(bitmap_rgb32 &dest, const rectangle &
}
/* fetch the source data */
- srcdata = gfx->get_data(code);
- srcdata2 = gfx2->get_data(code);
+ const uint8_t *srcdata = gfx->get_data(code);
+ const uint8_t *srcdata2 = gfx2->get_data(code);
/* compute how many blocks of 4 pixels we have */
uint32_t leftovers = (destendx + 1 - destx);
@@ -663,16 +661,16 @@ void gstream_state::drawgfx_transpen_x2222(bitmap_rgb32 &dest, const rectangle &
if (!flipx)
{
/* iterate over pixels in Y */
- for (cury = desty; cury <= destendy; cury++)
+ for (int32_t cury = desty; cury <= destendy; cury++)
{
- uint32_t *destptr = &dest.pix32(cury, destx);
+ uint32_t *destptr = &dest.pix(cury, destx);
const uint8_t *srcptr = srcdata;
const uint8_t *srcptr2 = srcdata2;
srcdata += dy;
srcdata2 += dy;
/* iterate over leftover pixels */
- for (curx = 0; curx < leftovers; curx++)
+ for (int32_t curx = 0; curx < leftovers; curx++)
{
uint32_t srcdata = (srcptr[0]);
uint32_t srcdata2 = (srcptr2[0]);
@@ -692,9 +690,9 @@ void gstream_state::drawgfx_transpen_x2222(bitmap_rgb32 &dest, const rectangle &
else
{
/* iterate over pixels in Y */
- for (cury = desty; cury <= destendy; cury++)
+ for (int32_t cury = desty; cury <= destendy; cury++)
{
- uint32_t *destptr = &dest.pix32(cury, destx);
+ uint32_t *destptr = &dest.pix(cury, destx);
const uint8_t *srcptr = srcdata;
const uint8_t *srcptr2 = srcdata2;
@@ -702,7 +700,7 @@ void gstream_state::drawgfx_transpen_x2222(bitmap_rgb32 &dest, const rectangle &
srcdata2 += dy;
/* iterate over leftover pixels */
- for (curx = 0; curx < leftovers; curx++)
+ for (int32_t curx = 0; curx < leftovers; curx++)
{
uint32_t srcdata = (srcptr[0]);
uint32_t srcdata2 = (srcptr2[0]);
diff --git a/src/mame/drivers/gsword.cpp b/src/mame/drivers/gsword.cpp
index 47398823e39..472c6a80550 100644
--- a/src/mame/drivers/gsword.cpp
+++ b/src/mame/drivers/gsword.cpp
@@ -153,14 +153,14 @@ So far, the AA-016 and AA-017 MCUs have been dumped successfully.
At least two Great Swordsman boards have been seen with a UVEPROM-based
D8741A-8 MCU for AA-013 at 9.5A. This suggests the developers made some
-last-minute change to the code that only the main CPU.
+last-minute change to the code that only affects the main CPU.
It appears that during development, the developers worked with three
copies of what became the AA-016 MCU. Protection code was added to the
I/O MCU program, and this became AA-017. At this point they intended to
use two copies of AA-016 for communications, and one AA-017 for I/O. It
-turned out that some last-minute change was required for the master CPU,
-but it was too late to order new mask ROM MUCs. This resulted in the
+turned out that some last-minute change was required for the main CPU,
+but it was too late to order new mask ROM MCUs. This resulted in the
use of UVEPROM parts for AA-013.
There are problems with sound. Many effects aren't playing or are cut
@@ -255,9 +255,9 @@ contained within a single page. The initialisation/self test and mode
selection, the subroutine for receiving configuration, and an unused
subroutine for sending a negated program byte to the host are in page 0.
The subroutines that implement coin handling are in page 1. There are
-three input handling and protection programs of increasing of increasing
-complexity in page 2 and page 3. The host selects the input handling
-program to use with the high nybble of the first command.
+three input handling and protection programs of increasing complexity in
+page 2 and page 3. The host selects the input handling program to use
+with the high nybble of the first command.
The subroutine for receiving configuration from the host is identical to
the one in the AA-016 MCU besides being shifted to a different address.
@@ -310,11 +310,11 @@ command:
The MCU keeps an internal credit counter ($2D). Each time the MCU
receives a polling command, if the credit counter is non-zero it will be
decremented and bit 7 of the response will be set; if the credit counter
-is zero, but 7 of the response will be clear.
+is zero, bit 7 of the response will be clear.
After terminating the setup phase, any byte written to the data port
will cause the MCU to check the coin inputs, update the credit counter
-if necessary, and return the desired data. A byte written to the
+if necessary, and return the requested data. A byte written to the
control port after the setup phase terminates causes the MCU to read a
byte of program memory from page 2 using the received byte as the
offset, twos-complement it, return it, and then immediately re-execute
diff --git a/src/mame/drivers/gticlub.cpp b/src/mame/drivers/gticlub.cpp
index 49bf5252eec..74d251c5d58 100644
--- a/src/mame/drivers/gticlub.cpp
+++ b/src/mame/drivers/gticlub.cpp
@@ -909,7 +909,7 @@ uint32_t gticlub_state::screen_update_gticlub(screen_device &screen, bitmap_rgb3
for (x=0; x < 512; x++)
{
uint8_t pixel = rom[index + (y*512) + x];
- bitmap.pix32(y, x) = K001006_palette[tp][(pal * 256) + pixel];
+ bitmap.pix(y, x) = K001006_palette[tp][(pal * 256) + pixel];
}
}
diff --git a/src/mame/drivers/gts1.cpp b/src/mame/drivers/gts1.cpp
index 652f4dfad08..53e5496d3c1 100644
--- a/src/mame/drivers/gts1.cpp
+++ b/src/mame/drivers/gts1.cpp
@@ -905,6 +905,15 @@ ROM_END
/*-------------------------------------------------------------------
/ Sahara Love (1984)
/-------------------------------------------------------------------*/
+ROM_START(sahalove)
+ ROM_REGION(0x10000, "maincpu", 0)
+ ROM_LOAD("u5_cf.bin", 0x0000, 0x0800, CRC(e0d4b405) SHA1(17aadd79c0dcbb336aadd5d203bc6ca866492345))
+ ROM_LOAD("u4_ce.bin", 0x0800, 0x0800, CRC(4cd312dd) SHA1(31245daa9972ef8652caee69986585bb8239e86e))
+ ROM_LOAD("412.cpu", 0x2000, 0x0400, CRC(84a86b83) SHA1(f331f2ffd7d1b279b4ffbb939aa8649e723f5fac))
+
+ ROM_REGION(0x2000, "audiocpu", 0) // extra Z80 for sound. TODO: emulate
+ ROM_LOAD("sahalove.bin", 0x0000, 0x2000, CRC(3512840a) SHA1(eb36bb78bbf2f8610bc1d71a6651b937db3a5c69))
+ROM_END
/*-------------------------------------------------------------------
/ Sinbad (05/1978) #412
@@ -1023,4 +1032,5 @@ GAME(1980, roldisco, gts1s, gts1, gts1, gts1_state, empty_init, ROT0, "Got
GAME(1980, astannie, gts1s, gts1, gts1, gts1_state, empty_init, ROT0, "Gottlieb", "Asteroid Annie and the Aliens", MACHINE_IS_SKELETON_MECHANICAL)
// homebrew
+GAME(1984, sahalove, sinbad, gts1, gts1, gts1_state, empty_init, ROT0, "Christian Tabart", "Sahara Love (France)", MACHINE_IS_SKELETON_MECHANICAL) // based on sinbad, 150 units produced, not sure it's 'homebrew'
GAME(1986, hexagone, gts1s, gts1, gts1, gts1_state, empty_init, ROT0, "Christian Tabart", "L'Hexagone (France)", MACHINE_IS_SKELETON_MECHANICAL)
diff --git a/src/mame/drivers/gts3a.cpp b/src/mame/drivers/gts3a.cpp
index 2e2aeb056bd..86a613df8b3 100644
--- a/src/mame/drivers/gts3a.cpp
+++ b/src/mame/drivers/gts3a.cpp
@@ -321,14 +321,13 @@ void gts3a_state::palette_init(palette_device &palette)
MC6845_UPDATE_ROW( gts3a_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t gfx=0;
- uint16_t mem,x;
- uint32_t *p = &bitmap.pix32(y);
+ uint32_t *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (uint16_t x = 0; x < x_count; x++)
{
- mem = (ma + x) & 0xfff;mem++;
+ uint16_t mem = (ma + x) & 0xfff;mem++;
gfx = 4;//m_p_chargen[(chr<<4) | ra] ^ inv;
/* Display a scanline of a character */
diff --git a/src/mame/drivers/gts80a.cpp b/src/mame/drivers/gts80a.cpp
index 6ed611719ac..84aa0c5ca58 100644
--- a/src/mame/drivers/gts80a.cpp
+++ b/src/mame/drivers/gts80a.cpp
@@ -430,10 +430,10 @@ uint32_t caveman_state::screen_update_caveman(screen_device &screen, bitmap_ind1
{
uint8_t pix = m_vram[count];
- bitmap.pix16(y, x+0) = (pix >> 6)&0x3;
- bitmap.pix16(y, x+1) = (pix >> 4)&0x3;
- bitmap.pix16(y, x+2) = (pix >> 2)&0x3;
- bitmap.pix16(y, x+3) = (pix >> 0)&0x3;
+ bitmap.pix(y, x+0) = (pix >> 6)&0x3;
+ bitmap.pix(y, x+1) = (pix >> 4)&0x3;
+ bitmap.pix(y, x+2) = (pix >> 2)&0x3;
+ bitmap.pix(y, x+3) = (pix >> 0)&0x3;
count++;
}
diff --git a/src/mame/drivers/guab.cpp b/src/mame/drivers/guab.cpp
index 193675652cc..d308bfb5e02 100644
--- a/src/mame/drivers/guab.cpp
+++ b/src/mame/drivers/guab.cpp
@@ -275,12 +275,12 @@ uint32_t guab_state::screen_update_guab(screen_device &screen, bitmap_ind16 &bit
for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
- uint8_t *src = &m_tms34061->m_display.vram[256 * y];
- uint16_t *dest = &bitmap.pix16(y);
+ uint8_t const *const src = &m_tms34061->m_display.vram[256 * y];
+ uint16_t *dest = &bitmap.pix(y);
for (int x = cliprect.min_x; x <= cliprect.max_x; x += 2)
{
- uint8_t pen = src[x >> 1];
+ uint8_t const pen = src[x >> 1];
/* Draw two 4-bit pixels */
*dest++ = m_palette->pen(pen >> 4);
diff --git a/src/mame/drivers/gunpey.cpp b/src/mame/drivers/gunpey.cpp
index 9b79660e2aa..db35f1242dc 100644
--- a/src/mame/drivers/gunpey.cpp
+++ b/src/mame/drivers/gunpey.cpp
@@ -295,9 +295,6 @@ void gunpey_state::video_start()
uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,int count,uint8_t scene_gradient)
{
- int x,y;
- int bpp_sel;
- int color;
const int ZOOM_SHIFT = 15;
// there doesn't seem to be a specific bit to mark compressed sprites (we currently have a hack to look at the first byte of the data)
// do they get decompressed at blit time instead? of are there other registers we need to look at
@@ -326,12 +323,12 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
if(!(m_wram[count+0] & 1))
{
- x = (m_wram[count+3] >> 8) | ((m_wram[count+4] & 0x03) << 8);
- y = (m_wram[count+4] >> 8) | ((m_wram[count+4] & 0x30) << 4);
+ int x = (m_wram[count+3] >> 8) | ((m_wram[count+4] & 0x03) << 8);
+ int y = (m_wram[count+4] >> 8) | ((m_wram[count+4] & 0x30) << 4);
uint32_t zoomheight = (m_wram[count+5] >> 8);
uint32_t zoomwidth = (m_wram[count+5] & 0xff);
- bpp_sel = (m_wram[count+0] & 0x18);
- color = (m_wram[count+0] >> 8);
+ int bpp_sel = (m_wram[count+0] & 0x18);
+ int color = (m_wram[count+0] >> 8);
x-=0x160;
y-=0x188;
@@ -379,8 +376,6 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
int xi2 = xsourceoff>>ZOOM_SHIFT;
uint8_t data = m_vram[((((ysource + yi2) & 0x7ff) * 0x800) + ((xsource + (xi2/2)) & 0x7ff))];
uint8_t pix;
- uint32_t col_offs;
- uint16_t color_data;
if (xi2 & 1)
{
@@ -391,19 +386,17 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
pix = (data & 0x0f);
}
- col_offs = ((pix + color*0x10) & 0xff) << 1;
+ uint32_t col_offs = ((pix + color*0x10) & 0xff) << 1;
col_offs+= ((pix + color*0x10) >> 8)*0x800;
- color_data = (m_vram[col_offs])|(m_vram[col_offs+1]<<8);
+ uint16_t color_data = (m_vram[col_offs])|(m_vram[col_offs+1]<<8);
if(!(color_data & 0x8000))
{
if(scene_gradient & 0x40)
{
- int r,g,b;
-
- r = (color_data & 0x7c00) >> 10;
- g = (color_data & 0x03e0) >> 5;
- b = (color_data & 0x001f) >> 0;
+ int r = (color_data & 0x7c00) >> 10;
+ int g = (color_data & 0x03e0) >> 5;
+ int b = (color_data & 0x001f) >> 0;
r-= (scene_gradient & 0x1f);
g-= (scene_gradient & 0x1f);
b-= (scene_gradient & 0x1f);
@@ -418,11 +411,11 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
{
if (alpha==0x00) // a value of 0x00 is solid
{
- bitmap.pix16(y+yi, x+xi) = color_data & 0x7fff;
+ bitmap.pix(y+yi, x+xi) = color_data & 0x7fff;
}
else
{
- uint16_t basecolor = bitmap.pix16(y+yi, x+xi);
+ uint16_t basecolor = bitmap.pix(y+yi, x+xi);
int base_r = ((basecolor >> 10)&0x1f)*alpha;
int base_g = ((basecolor >> 5)&0x1f)*alpha;
int base_b = ((basecolor >> 0)&0x1f)*alpha;
@@ -433,7 +426,7 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
g = (base_g+g)/0x1f;
b = (base_b+b)/0x1f;
color_data = (color_data & 0x8000) | (r << 10) | (g << 5) | (b << 0);
- bitmap.pix16(y+yi, x+xi) = color_data & 0x7fff;
+ bitmap.pix(y+yi, x+xi) = color_data & 0x7fff;
}
}
}
@@ -460,24 +453,19 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
int xi2 = xsourceoff>>ZOOM_SHIFT;
uint8_t data = m_vram[((((ysource+yi2)&0x7ff)*0x800) + ((xsource+xi2)&0x7ff))];
- uint8_t pix;
- uint32_t col_offs;
- uint16_t color_data;
- pix = (data & 0xff);
- col_offs = ((pix + color*0x100) & 0xff) << 1;
+ uint8_t pix = (data & 0xff);
+ uint32_t col_offs = ((pix + color*0x100) & 0xff) << 1;
col_offs+= ((pix + color*0x100) >> 8)*0x800;
- color_data = (m_vram[col_offs])|(m_vram[col_offs+1]<<8);
+ uint16_t color_data = (m_vram[col_offs])|(m_vram[col_offs+1]<<8);
if(!(color_data & 0x8000))
{
if(scene_gradient & 0x40)
{
- int r,g,b;
-
- r = (color_data & 0x7c00) >> 10;
- g = (color_data & 0x03e0) >> 5;
- b = (color_data & 0x001f) >> 0;
+ int r = (color_data & 0x7c00) >> 10;
+ int g = (color_data & 0x03e0) >> 5;
+ int b = (color_data & 0x001f) >> 0;
r-= (scene_gradient & 0x1f);
g-= (scene_gradient & 0x1f);
b-= (scene_gradient & 0x1f);
@@ -492,11 +480,11 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
{
if (alpha==0x00) // a value of 0x00 is solid
{
- bitmap.pix16(y+yi, x+xi) = color_data & 0x7fff;
+ bitmap.pix(y+yi, x+xi) = color_data & 0x7fff;
}
else
{
- uint16_t basecolor = bitmap.pix16(y+yi, x+xi);
+ uint16_t basecolor = bitmap.pix(y+yi, x+xi);
int base_r = ((basecolor >> 10)&0x1f)*alpha;
int base_g = ((basecolor >> 5)&0x1f)*alpha;
int base_b = ((basecolor >> 0)&0x1f)*alpha;
@@ -507,7 +495,7 @@ uint8_t gunpey_state::draw_gfx(bitmap_ind16 &bitmap,const rectangle &cliprect,in
g = (base_g+g)/0x1f;
b = (base_b+b)/0x1f;
color_data = (color_data & 0x8000) | (r << 10) | (g << 5) | (b << 0);
- bitmap.pix16(y+yi, x+xi) = color_data & 0x7fff;
+ bitmap.pix(y+yi, x+xi) = color_data & 0x7fff;
}
}
}
diff --git a/src/mame/drivers/h01x.cpp b/src/mame/drivers/h01x.cpp
index 15a676a477b..6680a803a77 100644
--- a/src/mame/drivers/h01x.cpp
+++ b/src/mame/drivers/h01x.cpp
@@ -11,7 +11,7 @@
#include "emu.h"
#include "includes/h01x.h"
-static const int16_t speaker_levels[] = {-32768, 0, 32767, 0};
+static const double speaker_levels[] = {-1.0, 0.0, 1.0, 0.0};
void h01x_state::h01x(machine_config &config)
{
diff --git a/src/mame/drivers/h19.cpp b/src/mame/drivers/h19.cpp
index e86e4948c1b..fc296c17392 100644
--- a/src/mame/drivers/h19.cpp
+++ b/src/mame/drivers/h19.cpp
@@ -192,7 +192,7 @@ static INPUT_PORTS_START( h19 )
PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LeftShift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Repeat") PORT_CODE(KEYCODE_LALT)
- PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RightShift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RightShift") PORT_CODE(KEYCODE_RSHIFT)
PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F10)
PORT_START("X1")
@@ -208,8 +208,8 @@ static INPUT_PORTS_START( h19 )
PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Unused")
PORT_START("X2")
- PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('.')
- PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\'") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"')
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\'") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("{") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('{') PORT_CHAR('}')
PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Unused")
@@ -475,8 +475,9 @@ MC6845_UPDATE_ROW( h19_state::crtc_update_row )
{
if (!de)
return;
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *p = &bitmap.pix32(y);
+
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
for (uint16_t x = 0; x < x_count; x++)
{
@@ -491,7 +492,7 @@ MC6845_UPDATE_ROW( h19_state::crtc_update_row )
}
/* get pattern of pixels for that character scanline */
- uint8_t gfx = m_p_chargen[(chr<<4) | ra] ^ inv;
+ uint8_t const gfx = m_p_chargen[(chr<<4) | ra] ^ inv;
/* Display a scanline of a character (8 pixels) */
*p++ = palette[BIT(gfx, 7)];
diff --git a/src/mame/drivers/halleys.cpp b/src/mame/drivers/halleys.cpp
index a4423bd304c..18b653d6908 100644
--- a/src/mame/drivers/halleys.cpp
+++ b/src/mame/drivers/halleys.cpp
@@ -1310,7 +1310,7 @@ void halleys_state::copy_scroll_op(bitmap_ind16 &bitmap, uint16_t *source, int s
// draw top split
for (int y=0; y != bch; y++) {
- uint16_t *dest = &bitmap.pix16(VIS_MINY + y, VIS_MINX);
+ uint16_t *dest = &bitmap.pix(VIS_MINY + y, VIS_MINX);
memcpy(dest, src+sx, 2*rcw);
memcpy(dest + rcw, src, 2*(CLIP_W - rcw));
src += SCREEN_WIDTH;
@@ -1320,7 +1320,7 @@ void halleys_state::copy_scroll_op(bitmap_ind16 &bitmap, uint16_t *source, int s
// draw bottom split
for (int y = bch; y != CLIP_H; y++) {
- uint16_t *dest = &bitmap.pix16(VIS_MINY + y, VIS_MINX);
+ uint16_t *dest = &bitmap.pix(VIS_MINY + y, VIS_MINX);
memcpy(dest, src+sx, 2*rcw);
memcpy(dest + rcw, src, 2*(CLIP_W - rcw));
src += SCREEN_WIDTH;
@@ -1345,7 +1345,7 @@ void halleys_state::copy_scroll_xp(bitmap_ind16 &bitmap, uint16_t *source, int s
// draw top split
for (int y=0; y != bch; y++) {
- uint16_t *dest = &bitmap.pix16(VIS_MINY + y, VIS_MINX);
+ uint16_t *dest = &bitmap.pix(VIS_MINY + y, VIS_MINX);
const uint16_t *src = src_base + sx;
for(int x=0; x != rcw; x++) {
uint16_t pixel = *src++;
@@ -1370,7 +1370,7 @@ void halleys_state::copy_scroll_xp(bitmap_ind16 &bitmap, uint16_t *source, int s
// draw bottom split
for (int y = bch; y != CLIP_H; y++) {
- uint16_t *dest = &bitmap.pix16(VIS_MINY + y, VIS_MINX);
+ uint16_t *dest = &bitmap.pix(VIS_MINY + y, VIS_MINX);
const uint16_t *src = src_base + sx;
for(int x=0; x != rcw; x++) {
uint16_t pixel = *src++;
@@ -1398,7 +1398,7 @@ void halleys_state::copy_fixed_xp(bitmap_ind16 &bitmap, uint16_t *source)
{
uint16_t *src = source + CLIP_SKIP;
for(int y=0; y != CLIP_H; y++) {
- uint16_t *dest = &bitmap.pix16(VIS_MINY + y, VIS_MINX);
+ uint16_t *dest = &bitmap.pix(VIS_MINY + y, VIS_MINX);
for(int x=0; x != CLIP_W; x++) {
uint16_t pixel = src[x];
@@ -1414,7 +1414,7 @@ void halleys_state::copy_fixed_2b(bitmap_ind16 &bitmap, uint16_t *source)
{
uint16_t *src = source + CLIP_SKIP;
for(int y=0; y != CLIP_H; y++) {
- uint16_t *dest = &bitmap.pix16(VIS_MINY + y, VIS_MINX);
+ uint16_t *dest = &bitmap.pix(VIS_MINY + y, VIS_MINX);
for(int x=0; x != CLIP_W; x++) {
uint16_t pixel = src[x];
@@ -1436,7 +1436,7 @@ void halleys_state::filter_bitmap(bitmap_ind16 &bitmap, int mask)
pal_ptr = m_internal_palette.get();
esi = mask | 0xffffff00;
- edi = (uint32_t*)&bitmap.pix16(VIS_MINY, VIS_MINX + CLIP_W);
+ edi = (uint32_t*)&bitmap.pix(VIS_MINY, VIS_MINX + CLIP_W);
dst_pitch = bitmap.rowpixels() >> 1;
ecx = -(CLIP_W>>1);
edx = CLIP_H;
diff --git a/src/mame/drivers/hazeltin.cpp b/src/mame/drivers/hazeltin.cpp
index 1055ae69d69..ba0ea2f53c3 100644
--- a/src/mame/drivers/hazeltin.cpp
+++ b/src/mame/drivers/hazeltin.cpp
@@ -269,11 +269,10 @@ uint32_t hazl1500_state::screen_update_hazl1500(screen_device &screen, bitmap_rg
m_last_hpos = 0;
m_last_vpos = 0;
- uint32_t pixindex = 0;
for (int y = 0; y < SCREEN_VTOTAL; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
- pixindex = y * SCREEN_HTOTAL;
+ uint32_t *scanline = &bitmap.pix(y);
+ uint32_t pixindex = y * SCREEN_HTOTAL;
for (int x = 0; x < SCREEN_HTOTAL; x++)
//*scanline++ = 0xff000000 | (uint8_t(m_screen_buf[pixindex++] * 0.5) * 0x010101);
*scanline++ = 0xff000000 | (uint8_t(m_screen_buf[pixindex++] * 63.0) * 0x010101);
diff --git a/src/mame/drivers/hec2hrp.cpp b/src/mame/drivers/hec2hrp.cpp
index a8a0fa64f45..8dfb44e1682 100644
--- a/src/mame/drivers/hec2hrp.cpp
+++ b/src/mame/drivers/hec2hrp.cpp
@@ -201,71 +201,71 @@ void hec2hrp_state::hecdisc2_io(address_map &map)
static INPUT_PORTS_START( hec2hrp )
/* keyboard input */
PORT_START("KEY.0") /* [0] - port 3000 @ 0 */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE)
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('*')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(32)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB)
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("<--") PORT_CODE(KEYCODE_BACKSPACE)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("<--") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK)
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_START("KEY.1") /* [1] - port 3000 @ 1 */ /* buttons => 2 1 0 / . - , + */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 >") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 <") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1 >") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('>')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0 <") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('<')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('/') PORT_CHAR('@')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR('.') PORT_CHAR('&')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M)
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR(',') PORT_CHAR('#')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('^')
PORT_START("KEY.2") /* [1] - port 3000 @ 2 */ /* buttons => .. 9 8 7 6 5 4 3 */
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 :") PORT_CODE(KEYCODE_7) PORT_CHAR('7')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 !") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 /") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("7 :") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR(':')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("6 !") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('!')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3 /") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(39)
PORT_START("KEY.3") /* [1] - port 3000 @ 3 */ /* buttons => B A .. ? .. = .. ; */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_Q) PORT_CHAR('a') PORT_CHAR('A')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('?')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('=')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED)
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR(';')
PORT_START("KEY.4") /* [1] - port 3000 @ 4 */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
PORT_START("KEY.5") /* [1] - port 3000 @ 5 */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('M')
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_A) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
PORT_START("KEY.6") /* [1] - port 3000 @ 6 */
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_W) PORT_CHAR('W')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_W) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_Z) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
PORT_START("KEY.7") /* [1] - port 3000 @ 7 JOYSTICK */
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Joy(0) LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
@@ -278,7 +278,7 @@ static INPUT_PORTS_START( hec2hrp )
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Joy(1) DOWN") PORT_CODE(KEYCODE_2_PAD)
PORT_START("KEY.8") /* [1] - port 3000 @ 8 not for the real machine, but to emulate the analog signal of the joystick */
- PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RESET") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RESET") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) // crashes the machine
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Joy(0) FIRE") PORT_CODE(KEYCODE_TILDE)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Joy(1) FIRE") PORT_CODE(KEYCODE_PLUS_PAD)
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Pot(0)+") PORT_CODE(KEYCODE_INSERT)
@@ -288,6 +288,14 @@ static INPUT_PORTS_START( hec2hrp )
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED)
INPUT_PORTS_END
+static INPUT_PORTS_START( interact )
+ PORT_INCLUDE( hec2hrp )
+ PORT_MODIFY("KEY.1")
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('/')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR('.')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR(',')
+INPUT_PORTS_END
+
MACHINE_RESET_MEMBER(hec2hrp_state,interact)
{
hector_reset(0, 0);
@@ -625,7 +633,7 @@ ROM_END
/* Driver */
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
-COMP(1979, interact, 0, 0, interact, hec2hrp, hec2hrp_state, init_interact, "Interact Electronics", "Interact Family Computer", MACHINE_IMPERFECT_SOUND)
+COMP(1979, interact, 0, 0, interact, interact,hec2hrp_state, init_interact, "Interact Electronics", "Interact Family Computer", MACHINE_IMPERFECT_SOUND)
COMP(1983, hector1, interact, 0, hector1, hec2hrp, hec2hrp_state, init_interact, "Micronique", "Hector 1", MACHINE_IMPERFECT_SOUND)
COMP(1983, hec2hrp, 0, interact, hec2hr, hec2hrp, hec2hrp_state, init_interact, "Micronique", "Hector 2HR+", MACHINE_IMPERFECT_SOUND)
COMP(1980, victor, hec2hrp, 0, hec2hr, hec2hrp, hec2hrp_state, init_victor, "Micronique", "Victor", MACHINE_IMPERFECT_SOUND)
diff --git a/src/mame/drivers/hektor.cpp b/src/mame/drivers/hektor.cpp
index 939896fcc0e..0342dc91160 100644
--- a/src/mame/drivers/hektor.cpp
+++ b/src/mame/drivers/hektor.cpp
@@ -215,14 +215,14 @@ MC6845_UPDATE_ROW(hektor3_state::crtc_update_row)
uint8_t data = m_ram->pointer()[~offset & 0xffff];
if (x == cursor_x) data ^= 0xff;
- bitmap.pix32(y, x * 8 + 0) = pen[BIT(data, 7)];
- bitmap.pix32(y, x * 8 + 1) = pen[BIT(data, 6)];
- bitmap.pix32(y, x * 8 + 2) = pen[BIT(data, 5)];
- bitmap.pix32(y, x * 8 + 3) = pen[BIT(data, 4)];
- bitmap.pix32(y, x * 8 + 4) = pen[BIT(data, 3)];
- bitmap.pix32(y, x * 8 + 5) = pen[BIT(data, 2)];
- bitmap.pix32(y, x * 8 + 6) = pen[BIT(data, 1)];
- bitmap.pix32(y, x * 8 + 7) = pen[BIT(data, 0)];
+ bitmap.pix(y, x * 8 + 0) = pen[BIT(data, 7)];
+ bitmap.pix(y, x * 8 + 1) = pen[BIT(data, 6)];
+ bitmap.pix(y, x * 8 + 2) = pen[BIT(data, 5)];
+ bitmap.pix(y, x * 8 + 3) = pen[BIT(data, 4)];
+ bitmap.pix(y, x * 8 + 4) = pen[BIT(data, 3)];
+ bitmap.pix(y, x * 8 + 5) = pen[BIT(data, 2)];
+ bitmap.pix(y, x * 8 + 6) = pen[BIT(data, 1)];
+ bitmap.pix(y, x * 8 + 7) = pen[BIT(data, 0)];
}
}
diff --git a/src/mame/drivers/hh_amis2k.cpp b/src/mame/drivers/hh_amis2k.cpp
index 67778048e8a..051503c30f6 100644
--- a/src/mame/drivers/hh_amis2k.cpp
+++ b/src/mame/drivers/hh_amis2k.cpp
@@ -157,6 +157,8 @@ public:
protected:
virtual void machine_start() override;
+
+ std::vector<double> m_speaker_levels;
};
void wildfire_state::machine_start()
@@ -255,10 +257,10 @@ void wildfire_state::wildfire(machine_config &config)
TIMER(config, "speaker_decay").configure_periodic(FUNC(wildfire_state::speaker_decay_sim), attotime::from_usec(100));
// set volume levels (set_output_gain is too slow for sub-frame intervals)
- static s16 speaker_levels[0x8000];
+ m_speaker_levels.resize(0x8000);
for (int i = 0; i < 0x8000; i++)
- speaker_levels[i] = i;
- m_speaker->set_levels(0x8000, speaker_levels);
+ m_speaker_levels[i] = double(i) / 32768.0;
+ m_speaker->set_levels(0x8000, &m_speaker_levels[0]);
}
// roms
diff --git a/src/mame/drivers/hh_cop400.cpp b/src/mame/drivers/hh_cop400.cpp
index 1a9d5ac7144..fd5e02571d6 100644
--- a/src/mame/drivers/hh_cop400.cpp
+++ b/src/mame/drivers/hh_cop400.cpp
@@ -555,7 +555,6 @@ public:
void write_l(u8 data);
u8 read_l();
- DECLARE_INPUT_CHANGED_MEMBER(position_changed) { update_display(); }
void unkeinv(machine_config &config);
};
@@ -563,17 +562,12 @@ public:
void unkeinv_state::update_display()
{
- m_display->matrix(m_l, m_g << 4 | m_d, false);
-
- // positional led row is on L6,L7
- u16 wand = m_display->read_row(7) << 8 | m_display->read_row(6);
- m_display->write_row(8 + m_inputs[1]->read(), wand);
- m_display->update();
+ m_display->matrix(m_g << 4 | m_d, m_l);
}
void unkeinv_state::write_g(u8 data)
{
- // G0-G3: led select part
+ // G0,G1: led select part
// G2,G3: input mux
m_g = ~data & 0xf;
update_display();
@@ -619,7 +613,7 @@ static INPUT_PORTS_START( unkeinv )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 )
PORT_START("IN.1")
- PORT_BIT( 0x0f, 0x00, IPT_POSITIONAL ) PORT_POSITIONS(12) PORT_SENSITIVITY(10) PORT_KEYDELTA(1) PORT_CENTERDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, unkeinv_state, position_changed, 0)
+ PORT_BIT( 0x0f, 0x00, IPT_POSITIONAL ) PORT_POSITIONS(12) PORT_SENSITIVITY(10) PORT_KEYDELTA(1) PORT_CENTERDELTA(0)
INPUT_PORTS_END
void unkeinv_state::unkeinv(machine_config &config)
@@ -635,7 +629,7 @@ void unkeinv_state::unkeinv(machine_config &config)
m_maincpu->write_so().set(m_speaker, FUNC(speaker_sound_device::level_w));
/* video hardware */
- PWM_DISPLAY(config, m_display).set_size(8+12, 8+8);
+ PWM_DISPLAY(config, m_display).set_size(6, 8);
config.set_default_layout(layout_unkeinv);
/* sound hardware */
diff --git a/src/mame/drivers/hh_hmcs40.cpp b/src/mame/drivers/hh_hmcs40.cpp
index d9f8bf63ce3..249a3c859c4 100644
--- a/src/mame/drivers/hh_hmcs40.cpp
+++ b/src/mame/drivers/hh_hmcs40.cpp
@@ -1926,6 +1926,8 @@ public:
protected:
virtual void machine_start() override;
+
+ std::vector<double> m_speaker_levels;
};
void cdkong_state::machine_start()
@@ -2027,10 +2029,10 @@ void cdkong_state::cdkong(machine_config &config)
TIMER(config, "speaker_decay").configure_periodic(FUNC(cdkong_state::speaker_decay_sim), attotime::from_msec(1));
// set volume levels (set_output_gain is too slow for sub-frame intervals)
- static s16 speaker_levels[0x8000];
+ m_speaker_levels.resize(0x8000);
for (int i = 0; i < 0x8000; i++)
- speaker_levels[i] = i;
- m_speaker->set_levels(0x8000, speaker_levels);
+ m_speaker_levels[i] = double(i) / 32768.0;
+ m_speaker->set_levels(0x8000, &m_speaker_levels[0]);
}
// roms
@@ -3668,7 +3670,7 @@ void mwcbaseb_state::mwcbaseb(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
- static const s16 speaker_levels[] = { 0, 0x3fff, -0x4000, 0, -0x4000, 0, -0x8000, -0x4000 };
+ static const double speaker_levels[] = { 0.0, 0.5, -0.5, 0.0, -0.5, 0.0, -1.0, -0.5 };
m_speaker->set_levels(8, speaker_levels);
}
diff --git a/src/mame/drivers/hh_pic16.cpp b/src/mame/drivers/hh_pic16.cpp
index 8fb36a746c4..102111824bc 100644
--- a/src/mame/drivers/hh_pic16.cpp
+++ b/src/mame/drivers/hh_pic16.cpp
@@ -295,7 +295,7 @@ void touchme_state::touchme(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -626,7 +626,7 @@ void maniac_state::maniac(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -1336,7 +1336,7 @@ void rockpin_state::rockpin(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
diff --git a/src/mame/drivers/hh_sm510.cpp b/src/mame/drivers/hh_sm510.cpp
index 7fc98eb6a76..01951558fa1 100644
--- a/src/mame/drivers/hh_sm510.cpp
+++ b/src/mame/drivers/hh_sm510.cpp
@@ -520,7 +520,7 @@ void hh_sm510_state::sm511_tiger2bit(machine_config &config, u16 width, u16 heig
m_maincpu->write_r().set(FUNC(hh_sm510_state::piezo2bit_r1_w));
// R via 120K resistor, S1 via 39K resistor (eg. tsonic, tsonic2, tbatmana)
- static const s16 speaker_levels[] = { 0, 0x7fff/3*1, 0x7fff/3*2, 0x7fff };
+ static const double speaker_levels[] = { 0.0, 1.0/3.0, 2.0/3.0, 1.0 };
m_speaker->set_levels(4, speaker_levels);
}
diff --git a/src/mame/drivers/hh_tms1k.cpp b/src/mame/drivers/hh_tms1k.cpp
index 872d4e19568..3219fa5234b 100644
--- a/src/mame/drivers/hh_tms1k.cpp
+++ b/src/mame/drivers/hh_tms1k.cpp
@@ -494,7 +494,7 @@ void matchnum_state::matchnum(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -606,7 +606,7 @@ void arrball_state::arrball(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -2852,7 +2852,7 @@ void cnfball_state::cnfball(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -5755,7 +5755,7 @@ void elecdet_state::elecdet(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x3fff, 0x3fff, 0x7fff };
+ static const double speaker_levels[4] = { 0.0, 0.5, 0.5, 1.0};
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -7469,7 +7469,7 @@ void bigtrak_state::bigtrak(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[8] = { 0, 0x7fff/3, 0x7fff/3, 0x7fff/3*2, 0x7fff/3, 0x7fff/3*2, 0x7fff/3*2, 0x7fff };
+ static const double speaker_levels[8] = { 0.0, 1.0/3.0, 1.0/3.0, 2.0/3.0, 1.0/3.0, 2.0/3.0, 2.0/3.0, 1.0 };
m_speaker->set_levels(8, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -7834,7 +7834,7 @@ void arcmania_state::arcmania(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[8] = { 0, 0x7fff/3, 0x7fff/3, 0x7fff/3*2, 0x7fff/3, 0x7fff/3*2, 0x7fff/3*2, 0x7fff };
+ static const double speaker_levels[8] = { 0.0, 1.0/3.0, 1.0/3.0, 2.0/3.0, 1.0/3.0, 2.0/3.0, 2.0/3.0, 1.0 };
m_speaker->set_levels(8, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -8096,7 +8096,7 @@ void merlin_state::merlin(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[8] = { 0, 0x7fff/3, 0x7fff/3, 0x7fff/3*2, 0x7fff/3, 0x7fff/3*2, 0x7fff/3*2, 0x7fff };
+ static const double speaker_levels[8] = { 0.0, 1.0/3.0, 1.0/3.0, 2.0/3.0, 1.0/3.0, 2.0/3.0, 2.0/3.0, 1.0 };
m_speaker->set_levels(8, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -8413,7 +8413,7 @@ void stopthief_state::stopthief(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[7] = { 0x7fff/7, 0x7fff/6, 0x7fff/5, 0x7fff/4, 0x7fff/3, 0x7fff/2, 0x7fff/1 };
+ static const double speaker_levels[7] = { 1.0/7.0, 1.0/6.0, 1.0/5.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 1.0 };
m_speaker->set_levels(7, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -8820,9 +8820,8 @@ void lostreas_state::lostreas(machine_config &config)
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
// set volume levels
- static s16 speaker_levels[0x10];
- for (int i = 0; i < 0x10; i++)
- speaker_levels[i] = 0x7fff / (0x10 - i);
+ static const double speaker_levels[0x10] =
+ { 1.0/16.0, 1.0/15.0, 1.0/14.0, 1.0/13.0, 1.0/12.0, 1.0/11.0, 1.0/10.0, 1.0/9.0, 1.0/8.0, 1.0/7.0, 1.0/6.0, 1.0/5.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 1.0 };
m_speaker->set_levels(16, speaker_levels);
}
@@ -11519,7 +11518,7 @@ void copycat_state::copycat(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -11609,7 +11608,7 @@ void copycatm2_state::copycatm2(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -11694,7 +11693,7 @@ void ditto_state::ditto(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[4] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[4] = { 0.0, 1.0, -1.0, 0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
diff --git a/src/mame/drivers/hh_ucom4.cpp b/src/mame/drivers/hh_ucom4.cpp
index 33c68e23a51..c6c778bb9b3 100644
--- a/src/mame/drivers/hh_ucom4.cpp
+++ b/src/mame/drivers/hh_ucom4.cpp
@@ -323,7 +323,7 @@ void ufombs_state::ufombs(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -479,7 +479,7 @@ void ssfball_state::ssfball(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
@@ -902,7 +902,7 @@ void splasfgt_state::splasfgt(machine_config &config)
/* sound hardware */
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker);
- static const s16 speaker_levels[] = { 0, 0x7fff, -0x8000, 0 };
+ static const double speaker_levels[] = { 0.0, 1.0, -1.0, 0.0 };
m_speaker->set_levels(4, speaker_levels);
m_speaker->add_route(ALL_OUTPUTS, "mono", 0.25);
}
diff --git a/src/mame/drivers/hhtiger.cpp b/src/mame/drivers/hhtiger.cpp
index e0d486317c3..24256624a91 100644
--- a/src/mame/drivers/hhtiger.cpp
+++ b/src/mame/drivers/hhtiger.cpp
@@ -184,18 +184,18 @@ GFXDECODE_END
UPD7220_DISPLAY_PIXELS_MEMBER(hhtiger_state::display_pixels)
{
/* 96KB video RAM (32KB green + 32KB red + 32KB blue) */
- uint16_t green = m_video_ram[(0x00000 + (address & 0x7fff)) >> 1];
- uint16_t red = m_video_ram[(0x08000 + (address & 0x7fff)) >> 1];
- uint16_t blue = m_video_ram[(0x10000 + (address & 0x7fff)) >> 1];
+ uint16_t const green = m_video_ram[(0x00000 + (address & 0x7fff)) >> 1];
+ uint16_t const red = m_video_ram[(0x08000 + (address & 0x7fff)) >> 1];
+ uint16_t const blue = m_video_ram[(0x10000 + (address & 0x7fff)) >> 1];
for (int xi = 0; xi<16; xi++)
{
- int r = ((red >> xi) & 1) ? 255 : 0;
- int g = ((green >> xi) & 1) ? 255 : 0;
- int b = ((blue >> xi) & 1) ? 255 : 0;
+ int const r = BIT(red, xi) ? 255 : 0;
+ int const g = BIT(green, xi) ? 255 : 0;
+ int const b = BIT(blue, xi) ? 255 : 0;
if (bitmap.cliprect().contains(x + xi, y))
- bitmap.pix32(y, x + xi) = rgb_t(r, g, b);
+ bitmap.pix(y, x + xi) = rgb_t(r, g, b);
}
}
@@ -226,7 +226,7 @@ UPD7220_DRAW_TEXT_LINE_MEMBER(hhtiger_state::draw_text)
pen = 0;
if (!m_screen->visible_area().contains(res_x, res_y))
- bitmap.pix32(res_y, res_x) = palette[pen];
+ bitmap.pix(res_y, res_x) = palette[pen];
}
}
}
diff --git a/src/mame/drivers/highvdeo.cpp b/src/mame/drivers/highvdeo.cpp
index 6fb110ad7d4..16c02ff3922 100644
--- a/src/mame/drivers/highvdeo.cpp
+++ b/src/mame/drivers/highvdeo.cpp
@@ -216,24 +216,22 @@ void highvdeo_state::machine_start()
uint32_t highvdeo_state::screen_update_tourvisn(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,count;
-
- for(y=cliprect.min_y;y<=cliprect.max_y;y++)
+ for(int y=cliprect.min_y;y<=cliprect.max_y;y++)
{
- count = ((y * (screen.visible_area().max_x+1)) + cliprect.min_x) >> 1;
- for(x=(cliprect.min_x>>1);x<=(cliprect.max_x>>1);x++)
+ int count = ((y * (screen.visible_area().max_x+1)) + cliprect.min_x) >> 1;
+ for(int x=(cliprect.min_x>>1);x<=(cliprect.max_x>>1);x++)
{
uint32_t color;
color = ((m_blit_ram[count]) & 0x00ff)>>0;
if(cliprect.contains((x*2)+0, y))
- bitmap.pix32(y, (x*2)+0) = m_palette->pen(color);
+ bitmap.pix(y, (x*2)+0) = m_palette->pen(color);
color = ((m_blit_ram[count]) & 0xff00)>>8;
if(cliprect.contains((x*2)+1, y))
- bitmap.pix32(y, (x*2)+1) = m_palette->pen(color);
+ bitmap.pix(y, (x*2)+1) = m_palette->pen(color);
count++;
}
@@ -245,16 +243,14 @@ uint32_t highvdeo_state::screen_update_tourvisn(screen_device &screen, bitmap_rg
/*Later HW, RGB565 instead of RAM-based pens (+ ramdac).*/
uint32_t highvdeo_state::screen_update_brasil(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,count;
-
- const pen_t *rgb = m_palette->pens(); // 16 bit RGB
+ pen_t const *const rgb = m_palette->pens(); // 16 bit RGB
- for(y=cliprect.min_y;y<=cliprect.max_y;y++)
+ for(int y=cliprect.min_y;y<=cliprect.max_y;y++)
{
- count = (y * 400) + cliprect.min_x;
- for(x=cliprect.min_x;x<=cliprect.max_x;x++)
+ int count = (y * 400) + cliprect.min_x;
+ for(int x=cliprect.min_x;x<=cliprect.max_x;x++)
{
- bitmap.pix32(y, x) = rgb[m_blit_ram[count++]];
+ bitmap.pix(y, x) = rgb[m_blit_ram[count++]];
}
}
diff --git a/src/mame/drivers/hitme.cpp b/src/mame/drivers/hitme.cpp
index 1c6e59f3742..33b65f0c945 100644
--- a/src/mame/drivers/hitme.cpp
+++ b/src/mame/drivers/hitme.cpp
@@ -80,26 +80,26 @@ uint32_t hitme_state::screen_update_hitme(screen_device &screen, bitmap_ind16 &b
double dot_freq = 15750 * 336;
/* the number of pixels is the duration times the frequency */
int width_pixels = width_duration * dot_freq;
- int x, y, xx, inv;
offs_t offs = 0;
/* start by drawing the tilemap */
m_tilemap->draw(screen, bitmap, cliprect, 0, 0);
/* now loop over and invert anything */
- for (y = 0; y < 19; y++)
+ for (int y = 0; y < 19; y++)
{
int dy = bitmap.rowpixels();
- for (inv = x = 0; x < 40; x++, offs++)
+ int inv = 0;
+ for (int x = 0; x < 40; x++, offs++)
{
/* if the high bit is set, reset the oneshot */
if (m_videoram[y * 40 + x] & 0x80)
inv = width_pixels;
/* invert pixels until we run out */
- for (xx = 0; xx < 8 && inv; xx++, inv--)
+ for (int xx = 0; xx < 8 && inv; xx++, inv--)
{
- uint16_t *dest = &bitmap.pix16(y * 10, x * 8 + xx);
+ uint16_t *const dest = &bitmap.pix(y * 10, x * 8 + xx);
dest[0 * dy] ^= 1;
dest[1 * dy] ^= 1;
dest[2 * dy] ^= 1;
diff --git a/src/mame/drivers/homelab.cpp b/src/mame/drivers/homelab.cpp
index d19379c2e8d..4861ab08b83 100644
--- a/src/mame/drivers/homelab.cpp
+++ b/src/mame/drivers/homelab.cpp
@@ -622,19 +622,18 @@ u32 homelab_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
if (!m_cols)
return 1;
- u8 y,ra,chr,gfx;
- u16 sy=0,ma=0,x;
+ u16 sy=0,ma=0;
- for(y = 0; y < m_rows; y++ )
+ for (u8 y = 0; y < m_rows; y++)
{
- for (ra = 0; ra < 8; ra++)
+ for (u8 ra = 0; ra < 8; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + m_cols; x++)
+ for (u16 x = ma; x < ma + m_cols; x++)
{
- chr = m_vram[x]; // get char in videoram
- gfx = m_p_chargen[chr | (ra<<8)]; // get dot pattern in chargen
+ u8 const chr = m_vram[x]; // get char in videoram
+ u8 const gfx = m_p_chargen[chr | (ra<<8)]; // get dot pattern in chargen
/* Display a scanline of a character */
*p++ = BIT(gfx, 7);
diff --git a/src/mame/drivers/homez80.cpp b/src/mame/drivers/homez80.cpp
index e84d42b71d6..c6e339af789 100644
--- a/src/mame/drivers/homez80.cpp
+++ b/src/mame/drivers/homez80.cpp
@@ -233,21 +233,20 @@ void homez80_state::machine_start()
u32 homez80_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx;
- u16 sy=0,ma=0,x;
+ u16 sy=0,ma=0;
- for (y = 0; y < 32; y++)
+ for (u8 y = 0; y < 32; y++)
{
- for (ra = 0; ra < 8; ra++)
+ for (u8 ra = 0; ra < 8; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++, 44);
+ uint16_t *p = &bitmap.pix(sy++, 44);
- for (x = ma; x < ma+32; x++)
+ for (u16 x = ma; x < ma+32; x++)
{
- chr = m_vram[x];
+ u8 const chr = m_vram[x];
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[ (chr<<3) | ra];
+ u8 const gfx = m_p_chargen[ (chr<<3) | ra];
/* Display a scanline of a character (8 pixels) */
*p++ = BIT(gfx, 7);
diff --git a/src/mame/drivers/hotblock.cpp b/src/mame/drivers/hotblock.cpp
index 40f73692962..9aa225c38ca 100644
--- a/src/mame/drivers/hotblock.cpp
+++ b/src/mame/drivers/hotblock.cpp
@@ -159,7 +159,7 @@ uint32_t hotblock_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
int count = (y * 320) + cliprect.left();
for(int x = cliprect.left(); x <= cliprect.right(); x++)
{
- bitmap.pix16(y, x) = m_vram[count++];
+ bitmap.pix(y, x) = m_vram[count++];
}
}
diff --git a/src/mame/drivers/hotstuff.cpp b/src/mame/drivers/hotstuff.cpp
index 446c4edbaab..05c1b1ffb77 100644
--- a/src/mame/drivers/hotstuff.cpp
+++ b/src/mame/drivers/hotstuff.cpp
@@ -40,11 +40,10 @@ void hotstuff_state::video_start()
uint32_t hotstuff_state::screen_update_hotstuff(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int yyy,xxx;
uint16_t row_palette_data[0x10];
rgb_t row_palette_data_as_rgb32_pen_data[0x10];
- yyy=512;xxx=512*2;
+ int yyy=512, xxx=512*2;
int count = 0;
for (int y = 0; y < yyy; y++)
@@ -61,13 +60,13 @@ uint32_t hotstuff_state::screen_update_hotstuff(screen_device &screen, bitmap_rg
for (int x = 0; x < xxx; )
{
- bitmap.pix32(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0xf000)>>12];
+ bitmap.pix(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0xf000)>>12];
x++;
- bitmap.pix32(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0x0f00)>>8];
+ bitmap.pix(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0x0f00)>>8];
x++;
- bitmap.pix32(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0x00f0)>>4];
+ bitmap.pix(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0x00f0)>>4];
x++;
- bitmap.pix32(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0x000f)>>0];
+ bitmap.pix(y, x) = row_palette_data_as_rgb32_pen_data[(m_bitmapram[count] &0x000f)>>0];
x++;
count++;
diff --git a/src/mame/drivers/hp16500.cpp b/src/mame/drivers/hp16500.cpp
index f26bfda1e2d..654228a96db 100644
--- a/src/mame/drivers/hp16500.cpp
+++ b/src/mame/drivers/hp16500.cpp
@@ -143,12 +143,11 @@ WRITE_LINE_MEMBER( hp16500_state::vsync_changed )
MC6845_UPDATE_ROW( hp16500_state::crtc_update_row )
{
- uint32_t *p = &bitmap.pix32(y);
- int i, pos;
+ uint32_t *p = &bitmap.pix(y);
- pos = y * 144;
+ int pos = y * 144;
- for (i = 0; i < x_count; i++)
+ for (int i = 0; i < x_count; i++)
{
*p++ = m_palette[m_vram[pos+0x00000]];
*p++ = m_palette[m_vram[pos+0x10000]];
@@ -165,12 +164,11 @@ MC6845_UPDATE_ROW( hp16500_state::crtc_update_row )
MC6845_UPDATE_ROW( hp16500_state::crtc_update_row_1650 )
{
- uint32_t *p = &bitmap.pix32(y);
- int i, pos;
+ uint32_t *p = &bitmap.pix(y);
- pos = y * 148;
+ int pos = y * 148;
- for (i = 0; i < x_count; i++)
+ for (int i = 0; i < x_count; i++)
{
*p++ = m_palette[m_vram[pos+0x00000]];
*p++ = m_palette[m_vram[pos+0x10000]];
@@ -400,7 +398,7 @@ uint32_t hp16500_state::screen_update_hp16500(screen_device &screen, bitmap_rgb3
int pos = 0;
for (int y = 0; y < 384; y++)
{
- uint32_t *scanline = &bitmap.pix32(y);
+ uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 576; x+=4)
{
diff --git a/src/mame/drivers/hp2640.cpp b/src/mame/drivers/hp2640.cpp
index 618377674aa..55c26b3edd3 100644
--- a/src/mame/drivers/hp2640.cpp
+++ b/src/mame/drivers/hp2640.cpp
@@ -667,8 +667,8 @@ void hp2645_state::video_render_buffer(unsigned video_scanline , unsigned line_i
}
unsigned on_pen = BIT(attrs , 3) ? 1 : 2;
for (unsigned x = 0; x < VIDEO_CHAR_WIDTH * 2; x += 2) {
- m_bitmap.pix32(video_scanline , x_left + x) = m_palette->pen(BIT(pixels_e , 0) ? on_pen : 0);
- m_bitmap.pix32(video_scanline , x_left + x + 1) = m_palette->pen(BIT(pixels_o , 0) ? on_pen : 0);
+ m_bitmap.pix(video_scanline , x_left + x) = m_palette->pen(BIT(pixels_e , 0) ? on_pen : 0);
+ m_bitmap.pix(video_scanline , x_left + x + 1) = m_palette->pen(BIT(pixels_o , 0) ? on_pen : 0);
pixels_e >>= 1;
pixels_o >>= 1;
}
diff --git a/src/mame/drivers/hp64k.cpp b/src/mame/drivers/hp64k.cpp
index ba1e068e2a0..3d2e2ca4298 100644
--- a/src/mame/drivers/hp64k.cpp
+++ b/src/mame/drivers/hp64k.cpp
@@ -481,11 +481,9 @@ WRITE_LINE_MEMBER(hp64k_state::hp64k_crtc_vrtc_w)
I8275_DRAW_CHARACTER_MEMBER(hp64k_state::crtc_display_pixels)
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t chargen_byte = m_chargen[ linecount | ((unsigned)charcode << 4) ];
- bool lvid , livid;
uint16_t pixels_lvid , pixels_livid;
- unsigned i;
if (vsp) {
pixels_lvid = pixels_livid = ~0;
@@ -504,19 +502,19 @@ I8275_DRAW_CHARACTER_MEMBER(hp64k_state::crtc_display_pixels)
pixels_livid = ~0;
}
- for (i = 0; i < 9; i++) {
- lvid = (pixels_lvid & (1U << (8 - i))) != 0;
- livid = (pixels_livid & (1U << (8 - i))) != 0;
+ for (unsigned i = 0; i < 9; i++) {
+ bool const lvid = (pixels_lvid & (1U << (8 - i))) != 0;
+ bool const livid = (pixels_livid & (1U << (8 - i))) != 0;
if (!lvid) {
// Normal brightness
- bitmap.pix32(y , x + i) = palette[ 2 ];
+ bitmap.pix(y , x + i) = palette[ 2 ];
} else if (livid) {
// Black
- bitmap.pix32(y , x + i) = palette[ 0 ];
+ bitmap.pix(y , x + i) = palette[ 0 ];
} else {
// Half brightness
- bitmap.pix32(y , x + i) = palette[ 1 ];
+ bitmap.pix(y , x + i) = palette[ 1 ];
}
}
diff --git a/src/mame/drivers/hp80.cpp b/src/mame/drivers/hp80.cpp
index 6fa046d2822..7daea00a448 100644
--- a/src/mame/drivers/hp80.cpp
+++ b/src/mame/drivers/hp80.cpp
@@ -1107,7 +1107,7 @@ WRITE_LINE_MEMBER(hp85_state::vblank_w)
uint8_t pixels = video_mem_r(video_start , GRAPH_MEM_SIZE / 2 - 1);
video_start += 2;
for (unsigned sub_x = 0; sub_x < 8; sub_x++) {
- m_bitmap.pix32(y , x + sub_x) = m_palette->pen(BIT(pixels , 7));
+ m_bitmap.pix(y , x + sub_x) = m_palette->pen(BIT(pixels , 7));
pixels <<= 1;
}
}
@@ -1130,7 +1130,7 @@ WRITE_LINE_MEMBER(hp85_state::vblank_w)
pixels = 0;
}
for (unsigned sub_x = 0; sub_x < 8; sub_x++) {
- m_bitmap.pix32(row + sub_row , col + sub_x) = m_palette->pen(BIT(pixels , 7));
+ m_bitmap.pix(row + sub_row , col + sub_x) = m_palette->pen(BIT(pixels , 7));
pixels <<= 1;
}
}
@@ -1840,14 +1840,14 @@ WRITE_LINE_MEMBER(hp86_state::vblank_w)
if (++video_ptr >= limit) {
video_ptr = 0;
}
- m_bitmap.pix32(y , x) = m_palette->pen(BIT(pixels , 7));
- m_bitmap.pix32(y , x + 1) = m_palette->pen(BIT(pixels , 6));
- m_bitmap.pix32(y , x + 2) = m_palette->pen(BIT(pixels , 5));
- m_bitmap.pix32(y , x + 3) = m_palette->pen(BIT(pixels , 4));
- m_bitmap.pix32(y , x + 4) = m_palette->pen(BIT(pixels , 3));
- m_bitmap.pix32(y , x + 5) = m_palette->pen(BIT(pixels , 2));
- m_bitmap.pix32(y , x + 6) = m_palette->pen(BIT(pixels , 1));
- m_bitmap.pix32(y , x + 7) = m_palette->pen(BIT(pixels , 0));
+ m_bitmap.pix(y , x) = m_palette->pen(BIT(pixels , 7));
+ m_bitmap.pix(y , x + 1) = m_palette->pen(BIT(pixels , 6));
+ m_bitmap.pix(y , x + 2) = m_palette->pen(BIT(pixels , 5));
+ m_bitmap.pix(y , x + 3) = m_palette->pen(BIT(pixels , 4));
+ m_bitmap.pix(y , x + 4) = m_palette->pen(BIT(pixels , 3));
+ m_bitmap.pix(y , x + 5) = m_palette->pen(BIT(pixels , 2));
+ m_bitmap.pix(y , x + 6) = m_palette->pen(BIT(pixels , 1));
+ m_bitmap.pix(y , x + 7) = m_palette->pen(BIT(pixels , 0));
}
}
} else {
@@ -1880,14 +1880,14 @@ WRITE_LINE_MEMBER(hp86_state::vblank_w)
pixels = ~pixels;
}
unsigned y = row * lines_per_row + sub_row;
- m_bitmap.pix32(y , col) = m_palette->pen(BIT(pixels , 7));
- m_bitmap.pix32(y , col + 1) = m_palette->pen(BIT(pixels , 6));
- m_bitmap.pix32(y , col + 2) = m_palette->pen(BIT(pixels , 5));
- m_bitmap.pix32(y , col + 3) = m_palette->pen(BIT(pixels , 4));
- m_bitmap.pix32(y , col + 4) = m_palette->pen(BIT(pixels , 3));
- m_bitmap.pix32(y , col + 5) = m_palette->pen(BIT(pixels , 2));
- m_bitmap.pix32(y , col + 6) = m_palette->pen(BIT(pixels , 1));
- m_bitmap.pix32(y , col + 7) = m_palette->pen(BIT(pixels , 0));
+ m_bitmap.pix(y , col) = m_palette->pen(BIT(pixels , 7));
+ m_bitmap.pix(y , col + 1) = m_palette->pen(BIT(pixels , 6));
+ m_bitmap.pix(y , col + 2) = m_palette->pen(BIT(pixels , 5));
+ m_bitmap.pix(y , col + 3) = m_palette->pen(BIT(pixels , 4));
+ m_bitmap.pix(y , col + 4) = m_palette->pen(BIT(pixels , 3));
+ m_bitmap.pix(y , col + 5) = m_palette->pen(BIT(pixels , 2));
+ m_bitmap.pix(y , col + 6) = m_palette->pen(BIT(pixels , 1));
+ m_bitmap.pix(y , col + 7) = m_palette->pen(BIT(pixels , 0));
}
}
}
diff --git a/src/mame/drivers/hp95lx.cpp b/src/mame/drivers/hp95lx.cpp
index dc8b0ec5998..2c8df7ad204 100644
--- a/src/mame/drivers/hp95lx.cpp
+++ b/src/mame/drivers/hp95lx.cpp
@@ -188,20 +188,16 @@ void hp95lx_state::hp95lx_palette(palette_device &palette) const
uint32_t hp95lx_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x, y, offset;
- uint16_t gfx, *p;
- uint8_t chr, attr;
-
if (m_graphics_mode)
{
- for (y = 0; y < 128; y++)
+ for (int y = 0; y < 128; y++)
{
- p = &bitmap.pix16(y);
- offset = y * (240 / 8);
+ uint16_t *p = &bitmap.pix(y);
+ int const offset = y * (240 / 8);
- for (x = offset; x < offset + (240 / 8); x++)
+ for (int x = offset; x < offset + (240 / 8); x++)
{
- gfx = m_p_videoram[x];
+ uint16_t const gfx = m_p_videoram[x];
for (int i = 7; i >= 0; i--)
{
@@ -215,17 +211,17 @@ uint32_t hp95lx_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap
bool blink((m_screen->frame_number() % 10) > 4);
// screen memory is normal MDA 80x25, but only a scrollable 40x16 window is displayed
- for (y = 0; y < 128; y++)
+ for (int y = 0; y < 128; y++)
{
- p = &bitmap.pix16(y);
- offset = (y / 8) * 160 + m_window_start_addr;
+ uint16_t *p = &bitmap.pix(y);
+ int const offset = (y / 8) * 160 + m_window_start_addr;
- for (x = offset; x < offset + 80; x += 2)
+ for (int x = offset; x < offset + 80; x += 2)
{
- chr = m_p_videoram[x];
- attr = m_p_videoram[x + 1];
+ uint8_t const chr = m_p_videoram[x];
+ uint8_t const attr = m_p_videoram[x + 1];
- gfx = m_p_chargen[(chr)*8 + (y % 8)];
+ uint16_t gfx = m_p_chargen[(chr)*8 + (y % 8)];
if ((x >> 1) == m_cursor_addr && blink && (y % 8) >= m_cursor_start_ras)
{
diff --git a/src/mame/drivers/hp9845.cpp b/src/mame/drivers/hp9845.cpp
index 1543d81dfe1..400aeb02133 100644
--- a/src/mame/drivers/hp9845.cpp
+++ b/src/mame/drivers/hp9845.cpp
@@ -1032,7 +1032,7 @@ void hp9845b_state::video_render_buff(unsigned video_scanline , unsigned line_in
if (m_video_blanked) {
// Blank scanline
for (unsigned i = 0; i < VIDEO_HBSTART; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ];
+ m_bitmap.pix(video_scanline , i) = pen[ PEN_BLACK ];
}
} else {
bool cursor_line = line_in_row == 12;
@@ -1065,7 +1065,7 @@ void hp9845b_state::video_render_buff(unsigned video_scanline , unsigned line_in
for (unsigned j = 0; j < 9; j++) {
bool pixel = (pixels & (1U << j)) != 0;
- m_bitmap.pix32(video_scanline , i * 9 + j) = pen[ pixel ? PEN_ALPHA : PEN_BLACK ];
+ m_bitmap.pix(video_scanline , i * 9 + j) = pen[ pixel ? PEN_ALPHA : PEN_BLACK ];
}
}
}
@@ -1105,7 +1105,7 @@ void hp9845b_state::graphic_video_render(unsigned video_scanline)
// Normal pixel
pixel = (word & mask) != 0 ? PEN_GRAPHIC : PEN_BLACK;
}
- m_bitmap.pix32(video_scanline - GVIDEO_VBEND , x++) = pen[ pixel ];
+ m_bitmap.pix(video_scanline - GVIDEO_VBEND , x++) = pen[ pixel ];
}
}
}
@@ -1693,15 +1693,15 @@ void hp9845ct_base_state::render_lp_cursor(unsigned video_scanline , unsigned pe
const pen_t &pen = m_palette->pen(pen_idx);
if (!yc) {
if (m_gv_lp_cursor_x < VIDEO_TOT_HPIXELS) {
- m_bitmap.pix32(video_scanline , m_gv_lp_cursor_x) = pen;
+ m_bitmap.pix(video_scanline , m_gv_lp_cursor_x) = pen;
}
} else if (m_gv_lp_cursor_fs) {
for (unsigned x = 0; x < VIDEO_TOT_HPIXELS; x++) {
- m_bitmap.pix32(video_scanline , x) = pen;
+ m_bitmap.pix(video_scanline , x) = pen;
}
} else {
for (unsigned x = std::max(0 , (int)m_gv_lp_cursor_x - 24); x <= (m_gv_lp_cursor_x + 25) && x < VIDEO_TOT_HPIXELS; x++) {
- m_bitmap.pix32(video_scanline , x) = pen;
+ m_bitmap.pix(video_scanline , x) = pen;
}
}
}
@@ -2216,15 +2216,15 @@ void hp9845c_state::video_render_buff(unsigned video_scanline , unsigned line_in
if (m_video_blanked || !m_alpha_sel) {
// Blank scanline
for (unsigned i = 0; i < VIDEO_770_ALPHA_L_LIM; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ pen_alpha(0) ];
+ m_bitmap.pix(video_scanline , i) = pen[ pen_alpha(0) ];
}
if (!m_graphic_sel) {
for (unsigned i = VIDEO_770_ALPHA_L_LIM; i < VIDEO_770_ALPHA_R_LIM; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ pen_alpha(0) ];
+ m_bitmap.pix(video_scanline , i) = pen[ pen_alpha(0) ];
}
}
for (unsigned i = VIDEO_770_ALPHA_R_LIM; i < VIDEO_TOT_HPIXELS; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ pen_alpha(0) ];
+ m_bitmap.pix(video_scanline , i) = pen[ pen_alpha(0) ];
}
} else {
bool cursor_line = line_in_row == 12;
@@ -2272,11 +2272,11 @@ void hp9845c_state::video_render_buff(unsigned video_scanline , unsigned line_in
if (m_graphic_sel && x >= VIDEO_770_ALPHA_L_LIM && x < VIDEO_770_ALPHA_R_LIM) {
// alpha overlays graphics (non-dominating)
if (pixel) {
- m_bitmap.pix32(video_scanline , x) = pen[ pen_alpha(color) ];
+ m_bitmap.pix(video_scanline , x) = pen[ pen_alpha(color) ];
}
} else {
// Graphics disabled or alpha-only zone
- m_bitmap.pix32(video_scanline , x) = pen[ pixel ? pen_alpha(color) : pen_alpha(0) ];
+ m_bitmap.pix(video_scanline , x) = pen[ pixel ? pen_alpha(color) : pen_alpha(0) ];
}
}
}
@@ -2347,7 +2347,7 @@ void hp9845c_state::graphic_video_render(unsigned video_scanline)
// Normal pixel
pixel = pen_graphic(((word0 & mask) ? pen0 : 0) | ((word1 & mask) ? pen1 : 0) | ((word2 & mask) ? pen2 : 0));
}
- m_bitmap.pix32(video_scanline , VIDEO_770_ALPHA_L_LIM + x++) = pen[ pixel ];
+ m_bitmap.pix(video_scanline , VIDEO_770_ALPHA_L_LIM + x++) = pen[ pixel ];
}
}
}
@@ -2914,15 +2914,15 @@ void hp9845t_state::video_render_buff(unsigned video_scanline , unsigned line_in
if (m_video_blanked || !m_alpha_sel) {
// Blank scanline
for (unsigned i = 0; i < VIDEO_780_ALPHA_L_LIM; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ];
+ m_bitmap.pix(video_scanline , i) = pen[ PEN_BLACK ];
}
if (!m_graphic_sel) {
for (unsigned i = VIDEO_780_ALPHA_L_LIM; i < VIDEO_780_ALPHA_R_LIM; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ];
+ m_bitmap.pix(video_scanline , i) = pen[ PEN_BLACK ];
}
}
for (unsigned i = VIDEO_780_ALPHA_R_LIM; i < VIDEO_TOT_HPIXELS; i++) {
- m_bitmap.pix32(video_scanline , i) = pen[ PEN_BLACK ];
+ m_bitmap.pix(video_scanline , i) = pen[ PEN_BLACK ];
}
} else {
bool cursor_line = line_in_row == 12;
@@ -2974,11 +2974,11 @@ void hp9845t_state::video_render_buff(unsigned video_scanline , unsigned line_in
if (m_graphic_sel && x >= VIDEO_780_ALPHA_L_LIM && x < VIDEO_780_ALPHA_R_LIM) {
// alpha overlays graphics (non-dominating)
if (pixel) {
- m_bitmap.pix32(video_scanline , x) = pen[ PEN_ALPHA ];
+ m_bitmap.pix(video_scanline , x) = pen[ PEN_ALPHA ];
}
} else {
// Graphics disabled or alpha-only zone
- m_bitmap.pix32(video_scanline , x) = pen[ pixel ? PEN_ALPHA : PEN_BLACK ];
+ m_bitmap.pix(video_scanline , x) = pen[ pixel ? PEN_ALPHA : PEN_BLACK ];
}
}
}
@@ -3042,7 +3042,7 @@ void hp9845t_state::graphic_video_render(unsigned video_scanline)
else
pixel = word & mask ? PEN_GRAPHIC : PEN_BLACK;
}
- m_bitmap.pix32(video_scanline , VIDEO_780_ALPHA_L_LIM + x++) = pen[ pixel ];
+ m_bitmap.pix(video_scanline , VIDEO_780_ALPHA_L_LIM + x++) = pen[ pixel ];
}
}
}
diff --git a/src/mame/drivers/hp9k.cpp b/src/mame/drivers/hp9k.cpp
index 1895babc4d1..ca89fd2a7bd 100644
--- a/src/mame/drivers/hp9k.cpp
+++ b/src/mame/drivers/hp9k.cpp
@@ -353,14 +353,13 @@ GFXDECODE_END
void hp9k_state::putChar(uint8_t thec,int x,int y,bitmap_ind16 &bitmap)
{
- const uint8_t* pchar=m_gfxdecode->gfx(0)->get_data(thec);
+ uint8_t const *const pchar=m_gfxdecode->gfx(0)->get_data(thec);
for (int py=0;py<HP9816_CHDIMY;py++)
{
for (int px=0;px<HP9816_CHDIMX;px++)
{
- uint16_t *dest=&bitmap.pix16((y*(HP9816_CHDIMY))+py,(x*(HP9816_CHDIMX))+px);
- *dest=pchar[px+(py*8)];
+ bitmap.pix((y*(HP9816_CHDIMY))+py,(x*(HP9816_CHDIMX))+px) = pchar[px+(py*8)];
}
}
}
diff --git a/src/mame/drivers/hprot1.cpp b/src/mame/drivers/hprot1.cpp
index 685bf8bc84f..feaff0856f5 100644
--- a/src/mame/drivers/hprot1.cpp
+++ b/src/mame/drivers/hprot1.cpp
@@ -236,12 +236,12 @@ HD44780_PIXEL_UPDATE(hprot1_state::hprot1_pixel_update)
{
if ( pos < 16 && line==0 )
{
- bitmap.pix16(y, pos*6 + x) = state;
+ bitmap.pix(y, pos*6 + x) = state;
}
if ( pos >= 64 && pos < 80 && line==0 )
{
- bitmap.pix16(y+9,(pos-64)*6 + x) = state;
+ bitmap.pix(y+9,(pos-64)*6 + x) = state;
}
}
diff --git a/src/mame/drivers/huebler.cpp b/src/mame/drivers/huebler.cpp
index 8b3a6974097..56b5748d3d3 100644
--- a/src/mame/drivers/huebler.cpp
+++ b/src/mame/drivers/huebler.cpp
@@ -231,26 +231,25 @@ INPUT_PORTS_END
uint32_t amu880_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int y, sx, x, line;
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
- for (y = 0; y < 240; y++)
+ for (int y = 0; y < 240; y++)
{
- line = y % 10;
+ int const line = y % 10;
- for (sx = 0; sx < 64; sx++)
+ for (int sx = 0; sx < 64; sx++)
{
- uint16_t videoram_addr = ((y / 10) * 64) + sx;
- uint8_t videoram_data = m_video_ram[videoram_addr & 0x7ff];
+ uint16_t const videoram_addr = ((y / 10) * 64) + sx;
+ uint8_t const videoram_data = m_video_ram[videoram_addr & 0x7ff];
- uint16_t charrom_addr = ((videoram_data & 0x7f) << 3) | line;
+ uint16_t const charrom_addr = ((videoram_data & 0x7f) << 3) | line;
uint8_t data = m_char_rom->base()[charrom_addr & 0x3ff];
- for (x = 0; x < 6; x++)
+ for (int x = 0; x < 6; x++)
{
- int color = ((line > 7) ? 0 : BIT(data, 7)) ^ BIT(videoram_data, 7);
+ int const color = ((line > 7) ? 0 : BIT(data, 7)) ^ BIT(videoram_data, 7);
- bitmap.pix32(y, (sx * 6) + x) = pen[color];
+ bitmap.pix(y, (sx * 6) + x) = pen[color];
data <<= 1;
}
diff --git a/src/mame/drivers/hunter16.cpp b/src/mame/drivers/hunter16.cpp
index aadb3dcea92..1824bbc508c 100644
--- a/src/mame/drivers/hunter16.cpp
+++ b/src/mame/drivers/hunter16.cpp
@@ -169,12 +169,12 @@ void hunter16_state::palette_init_hunter16(palette_device &palette)
MC6845_UPDATE_ROW(hunter16_state::crtc_update_row)
{
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
for (int i = 0; i < x_count; i++)
{
- uint16_t offset = (((ma + i) << 1) & 0x1fff) | ((ra & 1) << 13);
+ uint16_t const offset = (((ma + i) << 1) & 0x1fff) | ((ra & 1) << 13);
uint8_t data = m_videoram[offset];
for (int bit = 7; bit >= 0; bit--)
diff --git a/src/mame/drivers/husky.cpp b/src/mame/drivers/husky.cpp
index ba63742e0a2..84084b366cb 100644
--- a/src/mame/drivers/husky.cpp
+++ b/src/mame/drivers/husky.cpp
@@ -384,13 +384,13 @@ uint32_t husky_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
I'm drawing each character as 6x12 to form an overall screen of 192x48.
*/
- uint8_t data;
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
for (int y = 0; y < 48; y++)
{
for (int x = 0; x < 32; x++)
{
+ uint8_t data;
switch (y % 12)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6:
@@ -399,24 +399,24 @@ uint32_t husky_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
for (int b = 0; b < 5; b++)
{
- bitmap.pix32(y, (x * 6) + b) = BIT(data, 0) ? pen[1] : pen[2];
+ bitmap.pix(y, (x * 6) + b) = BIT(data, 0) ? pen[1] : pen[2];
data >>= 1;
}
- bitmap.pix32(y, (x * 6) + 5) = pen[0];
+ bitmap.pix(y, (x * 6) + 5) = pen[0];
break;
case 8:
/* cursor */
for (int b = 0; b < 5; b++)
{
- bitmap.pix32(y, (x * 6) + b) = (!m_curinh && m_cursor == (y / 12) * 32 + x) ? pen[1] : pen[2];
+ bitmap.pix(y, (x * 6) + b) = (!m_curinh && m_cursor == (y / 12) * 32 + x) ? pen[1] : pen[2];
}
- bitmap.pix32(y, (x * 6) + 5) = pen[0];
+ bitmap.pix(y, (x * 6) + 5) = pen[0];
break;
default:
/* blank */
for (int b = 0; b < 6; b++)
{
- bitmap.pix32(y, (x * 6) + b) = pen[0];
+ bitmap.pix(y, (x * 6) + b) = pen[0];
}
break;
}
diff --git a/src/mame/drivers/ibm6580.cpp b/src/mame/drivers/ibm6580.cpp
index 0f2ec3a18d1..26ae14be877 100644
--- a/src/mame/drivers/ibm6580.cpp
+++ b/src/mame/drivers/ibm6580.cpp
@@ -717,23 +717,24 @@ INPUT_PORTS_END
uint32_t ibm6580_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,gfx,fg,bg,chr,attr;
- uint16_t sy=0,ma=25,x,ca;
+ uint16_t sy=0,ma=25;
- fg = 1; bg = 0;
+ uint8_t fg = 1, bg = 0;
- for (y = 0; y < 25; y++)
+ for (uint8_t y = 0; y < 25; y++)
{
- for (ra = 0; ra < 16; ra++)
+ for (uint8_t ra = 0; ra < 16; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- // graphics mode
- if (m_p_videoram[ma] & 0x100) {
- for (x = ma; x < ma + 80; x++)
+ if (m_p_videoram[ma] & 0x100)
+ {
+ // graphics mode
+ for (uint16_t x = ma; x < ma + 80; x++)
{
- chr = m_p_videoram[x];
- attr = m_p_videoram[x] >> 8;
+ uint8_t const chr = m_p_videoram[x];
+ uint8_t const attr = m_p_videoram[x] >> 8;
+ uint8_t gfx;
switch (ra >> 1)
{
@@ -764,13 +765,16 @@ uint32_t ibm6580_state::screen_update(screen_device &screen, bitmap_ind16 &bitma
*p++ = BIT(gfx, i) ? fg : bg;
}
}
- } else {
- // text mode
- for (x = ma; x < ma + 80; x++)
+ }
+ else
+ {
+ // text mode
+ for (uint16_t x = ma; x < ma + 80; x++)
{
- chr = m_p_videoram[x];
- attr = m_p_videoram[x] >> 8;
- ca = (chr<<4);
+ uint8_t const chr = m_p_videoram[x];
+ uint8_t const attr = m_p_videoram[x] >> 8;
+ uint16_t ca = (chr<<4);
+ uint8_t gfx;
// font 2
if (attr & 0x02)
diff --git a/src/mame/drivers/ibmpcjr.cpp b/src/mame/drivers/ibmpcjr.cpp
index 86f3f34e528..26ef951ef54 100644
--- a/src/mame/drivers/ibmpcjr.cpp
+++ b/src/mame/drivers/ibmpcjr.cpp
@@ -404,8 +404,7 @@ void pcjr_state::pcjr_fdc_dor_w(uint8_t data)
else
m_fdc->set_floppy(nullptr);
- if((pdor^m_pcjr_dor) & 0x80)
- m_fdc->soft_reset();
+ m_fdc->reset_w(!BIT(m_pcjr_dor, 7));
if(m_pcjr_dor & 0x20) {
if((pdor & 0x40) && !(m_pcjr_dor & 0x40))
diff --git a/src/mame/drivers/icatel.cpp b/src/mame/drivers/icatel.cpp
index e20cde566cb..151fd97ed80 100644
--- a/src/mame/drivers/icatel.cpp
+++ b/src/mame/drivers/icatel.cpp
@@ -228,12 +228,12 @@ HD44780_PIXEL_UPDATE(icatel_state::icatel_pixel_update)
{
if ( pos < 16 && line==0 )
{
- bitmap.pix16(y, pos*6 + x) = state;
+ bitmap.pix(y, pos*6 + x) = state;
}
if ( pos >= 64 && pos < 80 && line==0 )
{
- bitmap.pix16(y+9,(pos-64)*6 + x) = state;
+ bitmap.pix(y+9,(pos-64)*6 + x) = state;
}
}
diff --git a/src/mame/drivers/if800.cpp b/src/mame/drivers/if800.cpp
index 0719bb7f354..26128d2aa91 100644
--- a/src/mame/drivers/if800.cpp
+++ b/src/mame/drivers/if800.cpp
@@ -43,18 +43,15 @@ private:
UPD7220_DISPLAY_PIXELS_MEMBER( if800_state::hgdc_display_pixels )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- int xi,gfx;
- uint8_t pen;
+ int gfx = m_video_ram[address >> 1];
- gfx = m_video_ram[address >> 1];
-
- for(xi=0;xi<16;xi++)
+ for(int xi=0;xi<16;xi++)
{
- pen = ((gfx >> xi) & 1) ? 1 : 0;
+ uint8_t pen = BIT(gfx, xi);
- bitmap.pix32(y, x + xi) = palette[pen];
+ bitmap.pix(y, x + xi) = palette[pen];
}
}
diff --git a/src/mame/drivers/igs011.cpp b/src/mame/drivers/igs011.cpp
index 284abb450fd..f6268c6800e 100644
--- a/src/mame/drivers/igs011.cpp
+++ b/src/mame/drivers/igs011.cpp
@@ -394,10 +394,10 @@ u32 igs011_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con
#ifdef MAME_DEBUG
if ((layer_enable != -1) && (pri_addr == 0xff))
- bitmap.pix16(y, x) = m_palette->black_pen();
+ bitmap.pix(y, x) = m_palette->black_pen();
else
#endif
- bitmap.pix16(y, x) = m_layer[l][scr_addr] | (l << 8);
+ bitmap.pix(y, x) = m_layer[l][scr_addr] | (l << 8);
}
}
return 0;
diff --git a/src/mame/drivers/igs017.cpp b/src/mame/drivers/igs017.cpp
index c0ea5203336..5e3fe848760 100644
--- a/src/mame/drivers/igs017.cpp
+++ b/src/mame/drivers/igs017.cpp
@@ -26,6 +26,7 @@ Year + Game PCB CPU Sound Custom
99 Tarzan (V109C) NO-0248-1 Z180 M6295 IGS031 IGS025 Battery
00? Super Tarzan (V100I) NO-0230-1 Z180 M6295 IGS031 IGS025 Battery
01? Happy Skill (V611) NO-0281 Z180 M6295 (K668) IGS031 IGS025 Battery
+01? unknown (V100A) unreadable Z180 M6295 IGS031 IGS025 Battery
?? Super Poker / Formosa NO-0187 Z180 M6295 YM2413 IGS017 IGS025 Battery
-------------------------------------------------------------------------------------------------------------
* not present in one set
@@ -94,6 +95,7 @@ public:
auto out_pa_callback() { return m_out_pa_cb.bind(); }
auto out_pb_callback() { return m_out_pb_cb.bind(); }
auto out_pc_callback() { return m_out_pc_cb.bind(); }
+ auto out_pd_callback() { return m_out_pd_cb.bind(); }
void address_w(u8 data);
void data_w(u8 data);
@@ -115,6 +117,7 @@ private:
devcb_write8 m_out_pa_cb;
devcb_write8 m_out_pb_cb;
devcb_write8 m_out_pc_cb;
+ devcb_write8 m_out_pd_cb;
u8 m_address, m_m3, m_mf;
u16 m_val, m_word;
@@ -172,7 +175,8 @@ igs_bitswap_device::igs_bitswap_device(const machine_config &mconfig, const char
m_in_pc_cb(*this),
m_out_pa_cb(*this),
m_out_pb_cb(*this),
- m_out_pc_cb(*this)
+ m_out_pc_cb(*this),
+ m_out_pd_cb(*this)
{
}
@@ -185,6 +189,7 @@ void igs_bitswap_device::device_start()
m_out_pa_cb.resolve();
m_out_pb_cb.resolve();
m_out_pc_cb.resolve();
+ m_out_pd_cb.resolve();
// register for save states
save_item(NAME(m_address));
@@ -230,6 +235,13 @@ void igs_bitswap_device::data_w(u8 data)
return;
}
break;
+ case 0x03:
+ if (!m_out_pd_cb.isnull())
+ {
+ m_out_pd_cb(data);
+ return;
+ }
+ break;
case 0x40: // word
{
@@ -488,6 +500,7 @@ public:
void starzan(machine_config &config);
void spkrform(machine_config &config);
void sdmg2(machine_config &config);
+ void tarzan(machine_config &config);
void init_iqblocka();
void init_mgdh();
@@ -503,6 +516,7 @@ public:
void init_lhzb2a();
void init_mgdha();
void init_happyskl();
+ void init_unkigs();
protected:
virtual void video_start() override;
@@ -528,7 +542,7 @@ private:
optional_ioport m_io_player2;
optional_ioport m_io_hopper;
optional_ioport_array<5> m_io_key;
- optional_ioport_array<2> m_io_dsw;
+ optional_ioport_array<3> m_io_dsw;
void igs025_to_igs022_callback(void);
@@ -538,6 +552,7 @@ private:
u8 m_scramble_data;
u8 m_dsw_select;
+ u8 m_i8255_portc_mux;
// IGS029 protection (communication)
u8 m_igs029_send_data, m_igs029_recv_data;
@@ -586,6 +601,8 @@ private:
u16 slqz2_magic_r();
u8 mgcs_keys_r();
+ u8 i8255_port_c_mux_r(); // starzan, happyskl, unkigs (maybe tarzanc and clones, too)
+
DECLARE_MACHINE_RESET(iqblocka);
DECLARE_MACHINE_RESET(mgcs);
DECLARE_MACHINE_RESET(lhzb2a);
@@ -1046,9 +1063,34 @@ void igs017_state::init_happyskl()
rom[i] = x;
}
- tarzan_decrypt_tiles(); // seems ok
+ tarzan_decrypt_tiles(); // enough for chars
}
+
+void igs017_state::init_unkigs()
+{
+ u8 *rom = memregion("maincpu")->base();
+
+ for (int i = 0; i < 0x40000; i++)
+ {
+ u8 x = rom[i];
+
+ if ((i & 0x00011) == 0x00011) x ^= 0x01;
+ if ((i & 0x02180) == 0x00000) x ^= 0x01;
+ if ((i & 0x001a0) != 0x00020) x ^= 0x20;
+ if ((i & 0x00260) != 0x00020) x ^= 0x40;
+ if ((i & 0x00020) == 0x00020) x ^= 0x80;
+ if ((i & 0x00260) == 0x00240) x ^= 0x80;
+
+ // this hasn't got split data / opcodes encryption like happyskl, but let's keep the same machine_config for easier testing
+ m_decrypted_opcodes[i] = x;
+ rom[i] = x;
+ }
+
+ tarzan_decrypt_tiles(); // enough for chars
+}
+
+
// sdmg2
void igs017_state::init_sdmg2()
@@ -2396,6 +2438,18 @@ void igs017_state::slqz2_map(address_map &map)
map(0x910001, 0x910001).rw(m_oki, FUNC(okim6295_device::read), FUNC(okim6295_device::write));
}
+u8 igs017_state::i8255_port_c_mux_r()
+{
+ switch(m_i8255_portc_mux)
+ {
+ case 0x01: return m_io_dsw[2]->read();
+ case 0x02: return m_io_dsw[1]->read();
+ case 0x03: return m_io_dsw[0]->read();
+ }
+
+ return 0xff;
+}
+
/***************************************************************************
Input Ports
@@ -3511,7 +3565,245 @@ static INPUT_PORTS_START( spkrform )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
INPUT_PORTS_END
+static INPUT_PORTS_START( starzan )
+ PORT_START("DSW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "System Limit" ) PORT_DIPLOCATION("SW1:2")
+ PORT_DIPSETTING( 0x02, "Unlimited" )
+ PORT_DIPSETTING( 0x00, "Limited" )
+ PORT_DIPNAME( 0x04, 0x04, "W-Up Game" ) PORT_DIPLOCATION("SW1:3")
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, "Back Color" ) PORT_DIPLOCATION("SW1:4")
+ PORT_DIPSETTING( 0x08, "Black" )
+ PORT_DIPSETTING( 0x00, "Color" )
+ PORT_DIPNAME( 0x10, 0x10, "Stop Status" ) PORT_DIPLOCATION("SW1:5")
+ PORT_DIPSETTING( 0x10, "Non Stop" )
+ PORT_DIPSETTING( 0x00, "Auto Stop" )
+ PORT_DIPNAME( 0x20, 0x20, "Key" ) PORT_DIPLOCATION("SW1:6")
+ PORT_DIPSETTING( 0x20, "Mode 1" )
+ PORT_DIPSETTING( 0x00, "Mode 2" )
+ PORT_DIPNAME( 0x40, 0x40, "Credit Level" ) PORT_DIPLOCATION("SW1:7")
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Odds Table" ) PORT_DIPLOCATION("SW1:8")
+ PORT_DIPSETTING( 0x80, "Show" )
+ PORT_DIPSETTING( 0x00, "No Show" )
+
+ PORT_START("DSW2")
+ PORT_DIPNAME( 0x01, 0x01, "Normal Level" ) PORT_DIPLOCATION("SW2:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Low ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( High ) )
+ PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW2:2") // not used from here on according to test mode, PCB does have 3 8-dip banks
+ PORT_DIPUNUSED_DIPLOC(0x04, 0x04, "SW2:3")
+ PORT_DIPUNUSED_DIPLOC(0x08, 0x08, "SW2:4")
+ PORT_DIPUNUSED_DIPLOC(0x10, 0x10, "SW2:5")
+ PORT_DIPUNUSED_DIPLOC(0x20, 0x20, "SW2:6")
+ PORT_DIPUNUSED_DIPLOC(0x40, 0x40, "SW2:7")
+ PORT_DIPUNUSED_DIPLOC(0x80, 0x80, "SW2:8")
+
+ PORT_START("DSW3")
+ PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW3:1")
+ PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW3:2")
+ PORT_DIPUNUSED_DIPLOC(0x04, 0x04, "SW3:3")
+ PORT_DIPUNUSED_DIPLOC(0x08, 0x08, "SW3:4")
+ PORT_DIPUNUSED_DIPLOC(0x10, 0x10, "SW3:5")
+ PORT_DIPUNUSED_DIPLOC(0x20, 0x20, "SW3:6")
+ PORT_DIPUNUSED_DIPLOC(0x40, 0x40, "SW3:7")
+ PORT_DIPUNUSED_DIPLOC(0x80, 0x80, "SW3:8")
+
+ PORT_START("PLAYER1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME( "HP SW" ) // called like this in key test, not clear what it does
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SLOT_STOP3 )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SLOT_STOP_ALL )
+
+ PORT_START("PLAYER2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SLOT_STOP2 )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_SLOT_STOP4 )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SLOT_STOP1 )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+
+ PORT_START("COINS")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_GAMBLE_KEYIN )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(5) // 'gettone C'
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(5) // 'gettone A'
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_GAMBLE_KEYOUT )
+ PORT_SERVICE_NO_TOGGLE( 0x20, IP_ACTIVE_LOW ) // keep pressed while booting
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_GAMBLE_BOOK ) // enters book-keeping menu
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+
+ PORT_START("BUTTONS")
+ PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+INPUT_PORTS_END
+
+// Test mode is in Italian (probably machine translated given how literal it is).
+static INPUT_PORTS_START( happyskl )
+ PORT_START("DSW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW1:1") // 'demo audio'
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "System Limit" ) PORT_DIPLOCATION("SW1:2") // 'lim. sistema'
+ PORT_DIPSETTING( 0x02, "Unlimited" )
+ PORT_DIPSETTING( 0x00, "Limited" )
+ PORT_DIPNAME( 0x04, 0x04, "W-Up Game" ) PORT_DIPLOCATION("SW1:3") // 'gioco radd.'
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, "Game Speed" ) PORT_DIPLOCATION("SW1:4") // 'velocitá gioco'
+ PORT_DIPSETTING( 0x08, DEF_STR( Normal ) )
+ PORT_DIPSETTING( 0x00, "Quick" )
+ PORT_DIPNAME( 0x10, 0x10, "Replay Game" ) PORT_DIPLOCATION("SW1:5") // not translated for some reason
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "Show Table" ) PORT_DIPLOCATION("SW1:6") // 'vedi tabella'
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Skill" ) PORT_DIPLOCATION("SW1:7") // 'abilitá'
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Payment Type" ) PORT_DIPLOCATION("SW1:8") // 'tipo pagam.'
+ PORT_DIPSETTING( 0x80, DEF_STR( Normal ) )
+ PORT_DIPSETTING( 0x00, "Automatic" )
+
+ PORT_START("DSW2")
+ PORT_DIPNAME( 0x01, 0x01, "Auto Payment" ) PORT_DIPLOCATION("SW2:1") // 'pagam. autom.'
+ PORT_DIPSETTING( 0x01, "1" )
+ PORT_DIPSETTING( 0x00, "10" )
+ PORT_DIPNAME( 0x06, 0x06, "Enable Payment" ) PORT_DIPLOCATION("SW2:2,3") // 'abilitá pagam.', they probably meant "abilita" instead of "abilitá"
+ PORT_DIPSETTING( 0x06, "Everything" ) // 'tutto'
+ PORT_DIPSETTING( 0x04, "1/Tickets" )
+ PORT_DIPSETTING( 0x02, "10/Tickets" )
+ PORT_DIPSETTING( 0x00, "1/Tickets" ) // same as 0x04, why?
+ PORT_DIPNAME( 0x08, 0x08, "Select Balls" ) PORT_DIPLOCATION("SW2:4") // 'sel. palloni'
+ PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x10, "Select Cubes" ) PORT_DIPLOCATION("SW2:5") // 'sel. cubi'
+ PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, "Select Cans" ) PORT_DIPLOCATION("SW2:6") // 'sel. lattine'
+ PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x40, 0x40, "Select Cards" ) PORT_DIPLOCATION("SW2:7") // 'sel. carte'
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Credit Limit" ) PORT_DIPLOCATION("SW2:8") // 'lim. crediti'
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_START("DSW3")
+ PORT_DIPNAME( 0x01, 0x01, "Level Limit" ) PORT_DIPLOCATION("SW3:1") // 'lim. livello'
+ PORT_DIPSETTING( 0x01, DEF_STR( Low ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( High ) )
+ PORT_DIPNAME( 0x02, 0x02, "Background" ) PORT_DIPLOCATION("SW3:2") // 'sfondo'
+ PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPUNUSED_DIPLOC(0x04, 0x04, "SW3:3") // not used from here on according to test mode
+ PORT_DIPUNUSED_DIPLOC(0x08, 0x08, "SW3:4")
+ PORT_DIPUNUSED_DIPLOC(0x10, 0x10, "SW3:5")
+ PORT_DIPUNUSED_DIPLOC(0x20, 0x20, "SW3:6")
+ PORT_DIPUNUSED_DIPLOC(0x40, 0x40, "SW3:7")
+ PORT_DIPUNUSED_DIPLOC(0x80, 0x80, "SW3:8")
+
+ PORT_START("PLAYER1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME( "HP SW" ) // called like this in key test, not clear what it does
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_POKER_HOLD1 )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_POKER_HOLD5 )
+
+ PORT_START("PLAYER2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD2 )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD3 )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD4 )
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+
+ PORT_START("COINS")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_GAMBLE_KEYIN )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(5) // 'gettone C'
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(5) // 'gettone A'
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT )
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_GAMBLE_KEYOUT )
+ PORT_SERVICE_NO_TOGGLE( 0x20, IP_ACTIVE_LOW ) // keep pressed while booting
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_GAMBLE_BOOK ) // enters book-keeping menu
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+
+ PORT_START("BUTTONS")
+ PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNKNOWN ) // no effects in key test
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( unkigs )
+ PORT_INCLUDE(happyskl)
+ PORT_MODIFY("PLAYER1")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_POKER_HOLD3 )
+
+ PORT_MODIFY("PLAYER2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1 )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2 )
+
+ // dips definitions taken from test mode, to be verified when the game will be playable
+ PORT_MODIFY("DSW1")
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW1:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "System Limit" ) PORT_DIPLOCATION("SW1:2")
+ PORT_DIPSETTING( 0x02, "Unlimited" )
+ PORT_DIPSETTING( 0x00, "Limited" )
+ PORT_DIPNAME( 0x04, 0x04, "W-Up Game" ) PORT_DIPLOCATION("SW1:3")
+ PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x08, "W-Up Type" ) PORT_DIPLOCATION("SW1:4")
+ PORT_DIPSETTING( 0x08, "Big-Small" )
+ PORT_DIPSETTING( 0x00, "Red-Black" )
+ PORT_DIPNAME( 0x10, 0x10, "Game Speed" ) PORT_DIPLOCATION("SW1:5")
+ PORT_DIPSETTING( 0x10, DEF_STR( Normal ) )
+ PORT_DIPSETTING( 0x00, "Quick" )
+ PORT_DIPNAME( 0x20, 0x20, "Card Type" ) PORT_DIPLOCATION("SW1:6")
+ PORT_DIPSETTING( 0x20, "Poker" )
+ PORT_DIPSETTING( 0x00, "Symbol" )
+ PORT_DIPNAME( 0x40, 0x40, "Sexy Girl" ) PORT_DIPLOCATION("SW1:7")
+ PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x80, "Title Name" ) PORT_DIPLOCATION("SW1:8")
+ PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+
+ PORT_MODIFY("DSW2")
+ PORT_DIPNAME( 0x01, 0x01, "Show Hold" ) PORT_DIPLOCATION("SW2:1")
+ PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x02, "Number Type" ) PORT_DIPLOCATION("SW2:2")
+ PORT_DIPSETTING( 0x02, "Number" )
+ PORT_DIPSETTING( 0x00, "AJQK" )
+ PORT_DIPUNUSED_DIPLOC(0x04, 0x04, "SW2:3") // not used from here on according to test mode, PCB does have 3 8-dip banks
+ PORT_DIPUNUSED_DIPLOC(0x08, 0x08, "SW2:4")
+ PORT_DIPUNUSED_DIPLOC(0x10, 0x10, "SW2:5")
+ PORT_DIPUNUSED_DIPLOC(0x20, 0x20, "SW2:6")
+ PORT_DIPUNUSED_DIPLOC(0x40, 0x40, "SW2:7")
+ PORT_DIPUNUSED_DIPLOC(0x80, 0x80, "SW2:8")
+
+ PORT_MODIFY("DSW3")
+ PORT_DIPUNUSED_DIPLOC(0x01, 0x01, "SW3:1")
+ PORT_DIPUNUSED_DIPLOC(0x02, 0x02, "SW3:2")
+INPUT_PORTS_END
/***************************************************************************
Machine Drivers
***************************************************************************/
@@ -3602,12 +3894,25 @@ void igs017_state::genius6(machine_config &config)
m_igs_bitswap->set_m3_bits<3>( 3, ~5, ~6, ~15);
}
-void igs017_state::starzan(machine_config &config)
+void igs017_state::tarzan(machine_config &config)
{
iqblocka(config);
+
m_maincpu->set_addrmap(AS_OPCODES, &igs017_state::decrypted_opcodes_map);
}
+void igs017_state::starzan(machine_config &config)
+{
+ tarzan(config);
+
+ subdevice<i8255_device>("ppi8255")->in_pa_callback().set_ioport("COINS");
+ subdevice<i8255_device>("ppi8255")->in_pb_callback().set_ioport("PLAYER1");
+ subdevice<i8255_device>("ppi8255")->in_pc_callback().set(FUNC(igs017_state::i8255_port_c_mux_r));
+
+ m_igs_bitswap->in_pa_callback().set_constant(0xff);
+ m_igs_bitswap->in_pc_callback().set_constant(0xff);
+ m_igs_bitswap->out_pd_callback().set([this](u8 data){ m_i8255_portc_mux = data >> 1; });
+}
// mgcs
@@ -4657,7 +4962,7 @@ ROM_START( happyskl )
ROM_REGION( 0x80000, "igs017_igs031:tilemaps", 0 )
ROM_LOAD( "happyskill_text.u11", 0x00000, 0x80000, CRC(c6f51041) SHA1(81a9a03e92c1c67f299113dec9e05ba77395ea31) )
- ROM_REGION( 0x80000, "oki", ROMREGION_ERASE )
+ ROM_REGION( 0x80000, "oki", 0 )
ROM_LOAD( "igs_s2702_sp_v100.u8", 0x00000, 0x80000, CRC(0ec9b1b5) SHA1(b8c7e068ddf6777a184339e6796be33e442a3df4) )
ROM_REGION( 0x2dd * 2, "plds", 0 )
@@ -4665,6 +4970,30 @@ ROM_START( happyskl )
ROM_LOAD( "peel22cv10a.u20", 0x2dd, 0x2dd, NO_DUMP )
ROM_END
+
+// PCB was heavily corroded and not working
+ROM_START( unkigs )
+ ROM_REGION( 0x40000, "maincpu", 0 )
+ ROM_LOAD( "u9.bin", 0x00000, 0x40000, CRC(8d79eb4d) SHA1(9cad09013f83335ec78c3ff78715bc5d9a989eb7) )
+
+ ROM_REGION( 0x480000, "igs017_igs031:sprites", ROMREGION_ERASE )
+ ROM_LOAD( "u2", 0x00000, 0x080000, NO_DUMP ) // not populated. Never there or removed (more probable)?
+ // the following ROM wasn't readable on this PCB, but it's the same as the one in happyskl. Assuming same contents for now
+ ROM_LOAD( "igs_a2701_cg_v100.u3", 0x80000, 0x400000, BAD_DUMP CRC(f3756a51) SHA1(8dd4677584f309cec4b068be9f9370a7a172a031) ) // FIXED BITS (xxxxxxx0xxxxxxxx) - 1xxxxxxxxxxxxxxxxxxxxx = 0x00
+
+ ROM_REGION( 0x40000, "igs017_igs031:tilemaps", ROMREGION_ERASEFF )
+ ROM_LOAD( "u11.bin", 0x00000, 0x40000, CRC(34475c83) SHA1(376ff68d89c25471483b074dcf7542f42f954e67) )
+ ROM_IGNORE(0x040000) // 1xxxxxxxxxxxxxxxxxx = 0x00
+
+ ROM_REGION( 0x80000, "oki", 0 ) // same as happyskl
+ ROM_LOAD( "igs_s2702_sp_v100.u8", 0x00000, 0x80000, CRC(0ec9b1b5) SHA1(b8c7e068ddf6777a184339e6796be33e442a3df4) )
+
+ ROM_REGION( 0x2dd * 2, "plds", 0 )
+ ROM_LOAD( "peel22cv10h.u10", 0x000, 0x2dd, NO_DUMP )
+ ROM_LOAD( "peel22cv10h.u20", 0x2dd, 0x2dd, NO_DUMP )
+ROM_END
+
+
/***************************************************************************
Super Poker (v100xD03) / Formosa
@@ -4709,11 +5038,12 @@ GAME( 1998, mgcs, 0, mgcs, mgcs, igs017_state, init_mgcs,
GAME( 1998, lhzb2, 0, lhzb2, lhzb2, igs017_state, init_lhzb2, ROT0, "IGS", "Mahjong Long Hu Zhengba 2 (set 1)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION )
GAME( 1998, lhzb2a, lhzb2, lhzb2a, lhzb2a, igs017_state, init_lhzb2a, ROT0, "IGS", "Mahjong Long Hu Zhengba 2 (VS221M)", 0 )
GAME( 1998, slqz2, 0, slqz2, slqz2, igs017_state, init_slqz2, ROT0, "IGS", "Mahjong Shuang Long Qiang Zhu 2 (VS203J)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION )
-GAME( 1999, tarzanc, 0, starzan, iqblocka, igs017_state, init_tarzan, ROT0, "IGS", "Tarzan Chuang Tian Guan (V109C, set 1)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing
-GAME( 1999, tarzan, tarzanc, starzan, iqblocka, igs017_state, init_tarzan, ROT0, "IGS", "Tarzan Chuang Tian Guan (V109C, set 2)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing
-GAME( 1999, tarzana, tarzanc, starzan, iqblocka, igs017_state, init_tarzana, ROT0, "IGS", "Tarzan (V107)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION ) // IGS029 needs to be emulated, sprites' decryption missing
-GAME( 2000?, starzan, 0, starzan, iqblocka, igs017_state, init_starzan, ROT0, "IGS (G.F. Gioca license)", "Super Tarzan (Italy, V100I)", MACHINE_NOT_WORKING )
-GAME( 2001?, happyskl, 0, starzan, iqblocka, igs017_state, init_happyskl, ROT0, "IGS", "Happy Skill (Italy, V611IT)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing
+GAME( 1999, tarzanc, 0, tarzan, iqblocka, igs017_state, init_tarzan, ROT0, "IGS", "Tarzan Chuang Tian Guan (V109C, set 1)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing, inputs to be done
+GAME( 1999, tarzan, tarzanc, tarzan, iqblocka, igs017_state, init_tarzan, ROT0, "IGS", "Tarzan Chuang Tian Guan (V109C, set 2)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing, inputs to be done
+GAME( 1999, tarzana, tarzanc, tarzan, iqblocka, igs017_state, init_tarzana, ROT0, "IGS", "Tarzan (V107)", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION ) // IGS029 needs to be emulated, sprites' decryption missing, inputs to be done
+GAME( 2000?, starzan, 0, starzan, starzan, igs017_state, init_starzan, ROT0, "IGS (G.F. Gioca license)", "Super Tarzan (Italy, V100I)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, incomplete dump, sprites' decryption missing
+GAME( 2001?, happyskl, 0, starzan, happyskl, igs017_state, init_happyskl, ROT0, "IGS", "Happy Skill (Italy, V611IT)", MACHINE_NOT_WORKING ) // IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing
+GAME( 2001?, unkigs, happyskl, starzan, unkigs, igs017_state, init_unkigs, ROT0, "IGS", "unknown IGS game (V100A)", MACHINE_NOT_WORKING ) // possibly titled 'Champion 2', definitely derived from Happy Skill or vice versa, missing ROM, IGS031 protection's game specific parameters not emulated yet, sprites' decryption missing
// Parent spk306us in driver spoker.cpp. Move this set to that driver?
GAME( ????, spkrform, spk306us, spkrform, spkrform, igs017_state, init_spkrform, ROT0, "IGS", "Super Poker (v100xD03) / Formosa", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION )
diff --git a/src/mame/drivers/imolagp.cpp b/src/mame/drivers/imolagp.cpp
index 67503390b3b..05b87fba010 100644
--- a/src/mame/drivers/imolagp.cpp
+++ b/src/mame/drivers/imolagp.cpp
@@ -182,7 +182,7 @@ uint32_t imolagp_state::screen_update_imolagp(screen_device &screen, bitmap_ind1
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
uint8_t const *const source = &m_videoram[layer][(y & 0xff) * 0x40];
- uint16_t *const dest = &bitmap.pix16(y & 0xff);
+ uint16_t *const dest = &bitmap.pix(y & 0xff);
for (int i = 0; i < 0x40; i++)
{
uint8_t const data = source[i];
diff --git a/src/mame/drivers/informer_207_100.cpp b/src/mame/drivers/informer_207_100.cpp
index 00bdf4d1b0d..932eeccd41a 100644
--- a/src/mame/drivers/informer_207_100.cpp
+++ b/src/mame/drivers/informer_207_100.cpp
@@ -8,15 +8,15 @@
Hardware:
- HD68B09EP
- - 3x HM6116LP-4 (+ 3 empty sockets), 2x TC5517BPL-20
+ - 3x HM6116LP-4 (+ 3 empty sockets), 2x TC5517BPL-20
- R6545-1AP CRTC
- - MC2681P DUART
+ - MC2681P DUART
- MC68B50P ACIA
- M58321 RTC
- - 19.7184 MHz XTAL, 3.6864 MHz XTAL
+ - 19.7184 MHz XTAL, 3.6864 MHz XTAL
TODO:
- - Redump ROM 207_100_2.bin
+ - Redump ROM 207_100_2.bin
***************************************************************************/
@@ -69,6 +69,7 @@ private:
void mem_map(address_map &map);
+ MC6845_ON_UPDATE_ADDR_CHANGED(crtc_addr);
MC6845_UPDATE_ROW(crtc_update_row);
};
@@ -81,6 +82,10 @@ void informer_207_100_state::mem_map(address_map &map)
{
map(0x0000, 0x27ff).ram().share("ram");
map(0xc000, 0xffff).rom().region("maincpu", 0);
+ map(0xff00, 0xff0f).rw(m_duart, FUNC(scn2681_device::read), FUNC(scn2681_device::write));
+ map(0xff20, 0xff20).rw(m_crtc, FUNC(mc6845_device::status_r), FUNC(mc6845_device::address_w));
+ map(0xff21, 0xff21).rw(m_crtc, FUNC(mc6845_device::register_r), FUNC(mc6845_device::register_w));
+ map(0xff40, 0xff41).rw(m_acia, FUNC(acia6850_device::read), FUNC(acia6850_device::write));
}
@@ -96,8 +101,34 @@ INPUT_PORTS_END
// VIDEO EMULATION
//**************************************************************************
+MC6845_ON_UPDATE_ADDR_CHANGED( informer_207_100_state::crtc_addr )
+{
+// m_video_update_address = address;
+}
+
MC6845_UPDATE_ROW( informer_207_100_state::crtc_update_row )
{
+ pen_t const *const pen = m_palette->pens();
+
+ for (int x = 0; x < x_count; x++)
+ {
+// uint8_t attr = m_ram[ma + x * 2 + 0];
+ uint8_t code = m_ram[ma + x * 2 + 1];
+ uint8_t data = m_chargen[(code << 4) + ra];
+
+ if (x == cursor_x)
+ data = 0xff;
+
+ // draw 8 pixels of the character
+ bitmap.pix(y, x * 8 + 7) = pen[BIT(data, 0)];
+ bitmap.pix(y, x * 8 + 6) = pen[BIT(data, 1)];
+ bitmap.pix(y, x * 8 + 5) = pen[BIT(data, 2)];
+ bitmap.pix(y, x * 8 + 4) = pen[BIT(data, 3)];
+ bitmap.pix(y, x * 8 + 3) = pen[BIT(data, 4)];
+ bitmap.pix(y, x * 8 + 2) = pen[BIT(data, 5)];
+ bitmap.pix(y, x * 8 + 1) = pen[BIT(data, 6)];
+ bitmap.pix(y, x * 8 + 0) = pen[BIT(data, 7)];
+ }
}
static const gfx_layout char_layout =
@@ -126,6 +157,8 @@ void informer_207_100_state::machine_start()
void informer_207_100_state::machine_reset()
{
+ // start executing somewhere sane
+ m_maincpu->set_pc(0xc000);
}
@@ -147,10 +180,7 @@ void informer_207_100_state::informer_207_100(machine_config &config)
// video
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_color(rgb_t::green());
- m_screen->set_size(640, 480);
- m_screen->set_visarea_full();
- m_screen->set_refresh_hz(60);
-// m_screen->set_raw(19.7184_MHz_XTAL, 0, 0, 0, 0, 0, 0);
+ m_screen->set_raw(19.7184_MHz_XTAL, 832, 0, 640, 316, 0, 300);
m_screen->set_screen_update("crtc", FUNC(mc6845_device::screen_update));
PALETTE(config, m_palette, palette_device::MONOCHROME);
@@ -161,6 +191,7 @@ void informer_207_100_state::informer_207_100(machine_config &config)
m_crtc->set_screen("screen");
m_crtc->set_show_border_area(false);
m_crtc->set_char_width(8);
+ m_crtc->set_on_update_addr_change_callback(FUNC(informer_207_100_state::crtc_addr));
m_crtc->set_update_row_callback(FUNC(informer_207_100_state::crtc_update_row));
}
@@ -178,7 +209,7 @@ ROM_START( in207100 )
ROM_REGION(0x1000, "chargen", 0)
// 79496 REV 1.01 12-29-83
- ROM_LOAD("79496.bin", 0x0000, 0x1000, CRC(930AC23A) SHA1(74e6bf81b60e3504cb2b9f14a33e7c3e367dc825))
+ ROM_LOAD("79496.bin", 0x0000, 0x1000, CRC(930ac23a) SHA1(74e6bf81b60e3504cb2b9f14a33e7c3e367dc825))
ROM_END
diff --git a/src/mame/drivers/informer_207_376.cpp b/src/mame/drivers/informer_207_376.cpp
index f4ed3c68f21..a10483728d3 100644
--- a/src/mame/drivers/informer_207_376.cpp
+++ b/src/mame/drivers/informer_207_376.cpp
@@ -8,17 +8,17 @@
Hardware:
- M6809
- - 8253 PIT
+ - 8253 PIT
- Z80SCC 8530
- 2x 6850 ACIA (up to 4)
- 2x X2212P NOVRAM
TODO:
- - Dump keyboard controller and emulate it (currently HLE'd)
- - Problably needs improvements to at least the Z80SCC to
- properly support synchrous modes
+ - Dump keyboard controller and emulate it (currently HLE'd)
+ - Problably needs improvements to at least the Z80SCC to
+ properly support synchrous modes
- Figure out the unknown bits at 0x8400
- - Verify clock speeds
+ - Verify clock speeds
Notes:
- Thanks to charcole and his zmachine3270 project at
@@ -139,11 +139,11 @@ void informer_207_376_state::crt_brightness_w(uint8_t data)
MC6845_UPDATE_ROW( informer_207_376_state::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
for (int x = 0; x < x_count; x++)
{
- uint8_t code = m_ram[ma + x];
+ uint8_t const code = m_ram[ma + x];
uint8_t data = m_chargen[(code << 4) + ra];
if (x == cursor_x)
@@ -154,14 +154,14 @@ MC6845_UPDATE_ROW( informer_207_376_state::crtc_update_row )
data = 0xff;
// draw 8 pixels of the character
- bitmap.pix32(y, x * 8 + 7) = pen[BIT(data, 0)];
- bitmap.pix32(y, x * 8 + 6) = pen[BIT(data, 1)];
- bitmap.pix32(y, x * 8 + 5) = pen[BIT(data, 2)];
- bitmap.pix32(y, x * 8 + 4) = pen[BIT(data, 3)];
- bitmap.pix32(y, x * 8 + 3) = pen[BIT(data, 4)];
- bitmap.pix32(y, x * 8 + 2) = pen[BIT(data, 5)];
- bitmap.pix32(y, x * 8 + 1) = pen[BIT(data, 6)];
- bitmap.pix32(y, x * 8 + 0) = pen[BIT(data, 7)];
+ bitmap.pix(y, x * 8 + 7) = pen[BIT(data, 0)];
+ bitmap.pix(y, x * 8 + 6) = pen[BIT(data, 1)];
+ bitmap.pix(y, x * 8 + 5) = pen[BIT(data, 2)];
+ bitmap.pix(y, x * 8 + 4) = pen[BIT(data, 3)];
+ bitmap.pix(y, x * 8 + 3) = pen[BIT(data, 4)];
+ bitmap.pix(y, x * 8 + 2) = pen[BIT(data, 5)];
+ bitmap.pix(y, x * 8 + 1) = pen[BIT(data, 6)];
+ bitmap.pix(y, x * 8 + 0) = pen[BIT(data, 7)];
}
}
diff --git a/src/mame/drivers/informer_213.cpp b/src/mame/drivers/informer_213.cpp
index 4c2551bfabf..f6d9268bbd8 100644
--- a/src/mame/drivers/informer_213.cpp
+++ b/src/mame/drivers/informer_213.cpp
@@ -3,30 +3,32 @@
/***************************************************************************
Informer 213 (IBM 374/SNA V.22)
- Informer 213 AE (VT-100)
+ Informer 213 AE (VT-100)
Hardware:
- EF68B09EP
- - 2x TC5564PL-15 [8k] (next to CG ROM)
- - 1x TC5565APL-15 [8k] + 2x TMS4464-15NL [32k] (next to CPU)
- - Z0853006PSC SCC
- - ASIC (INFORMER 44223)
- - 18.432 MHz XTAL
+ - 2x TC5564PL-15 [8k] (next to CG ROM)
+ - 1x TC5565APL-15 [8k] + 2x TMS4464-15NL [32k] (next to CPU)
+ - Z0853006PSC SCC
+ - ASIC (INFORMER 44223)
+ - 18.432 MHz XTAL
TODO:
- - Figure out the ASIC and how it's connected
-
- Notes:
- - Debug tricks (AE): "b@42=ff" after startup to show setup screen 1
- "bp 81a1" then "b@42=ff" and "a=02" after the break to show screen 2
+ - Figure out the ASIC and how it's connected
***************************************************************************/
#include "emu.h"
#include "cpu/m6809/m6809.h"
+#include "machine/nvram.h"
#include "machine/z80scc.h"
+#include "machine/informer_213_kbd.h"
+#include "bus/rs232/rs232.h"
+#include "bus/rs232/printer.h"
+#include "sound/beep.h"
#include "emupal.h"
#include "screen.h"
+#include "speaker.h"
//**************************************************************************
@@ -39,9 +41,12 @@ public:
informer_213_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
+ m_nvram(*this, "nvram%u", 0U),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_scc(*this, "scc"),
+ m_beep(*this, "beep"),
+ m_nvram_bank(*this, "banked"),
m_vram(*this, "vram"),
m_aram(*this, "aram"),
m_chargen(*this, "chargen")
@@ -55,9 +60,12 @@ protected:
private:
required_device<cpu_device> m_maincpu;
+ required_device_array<nvram_device, 2> m_nvram;
required_device<screen_device> m_screen;
required_device<palette_device> m_palette;
required_device<scc8530_device> m_scc;
+ required_device<beep_device> m_beep;
+ required_memory_bank m_nvram_bank;
required_shared_ptr<uint8_t> m_vram;
required_shared_ptr<uint8_t> m_aram;
required_region_ptr<uint8_t> m_chargen;
@@ -65,6 +73,30 @@ private:
void mem_map(address_map &map);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ void vblank_w(int state);
+ void vram_start_addr_w(offs_t offset, uint8_t data);
+ void vram_end_addr_w(offs_t offset, uint8_t data);
+ void vram_start_addr2_w(offs_t offset, uint8_t data);
+ void cursor_addr_w(offs_t offset, uint8_t data);
+ void cursor_start_w(uint8_t data);
+ void cursor_end_w(uint8_t data);
+ void screen_ctrl_w(uint8_t data);
+
+ void bell_w(uint8_t data);
+
+ void kbd_int_w(int state);
+ uint8_t firq_vector_r();
+
+ std::unique_ptr<uint8_t[]> m_banked_ram;
+
+ uint16_t m_vram_start_addr;
+ uint16_t m_vram_end_addr;
+ uint16_t m_vram_start_addr2;
+ uint8_t m_cursor_start;
+ uint8_t m_cursor_end;
+ uint16_t m_cursor_addr;
+ uint8_t m_screen_ctrl;
+ uint8_t m_firq_vector;
};
@@ -74,12 +106,24 @@ private:
void informer_213_state::mem_map(address_map &map)
{
- map(0x0000, 0x1fff).ram();
- map(0x2000, 0x3fff).ram();
- map(0x4000, 0x5fff).ram();
+ map(0x0000, 0x0000).rw("kbd", FUNC(informer_213_kbd_hle_device::read), FUNC(informer_213_kbd_hle_device::write));
+ map(0x0006, 0x0007).unmapr().w(FUNC(informer_213_state::vram_start_addr_w));
+ map(0x0008, 0x0009).unmapr().w(FUNC(informer_213_state::vram_end_addr_w));
+ map(0x000a, 0x000b).unmapr().w(FUNC(informer_213_state::vram_start_addr2_w));
+ map(0x000d, 0x000d).unmapr().w(FUNC(informer_213_state::cursor_start_w));
+ map(0x000e, 0x000e).unmapr().w(FUNC(informer_213_state::cursor_end_w));
+ map(0x000f, 0x0010).unmapr().w(FUNC(informer_213_state::cursor_addr_w));
+ map(0x0021, 0x0021).w(FUNC(informer_213_state::screen_ctrl_w));
+ map(0x0040, 0x0043).rw(m_scc, FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w));
+ map(0x0060, 0x0060).w(FUNC(informer_213_state::bell_w));
+ map(0x0100, 0x03ff).ram().share("nvram0"); // might not be all nvram
+ map(0x0400, 0x07ff).bankrw("banked"); // unknown size, data written 0x540 to 0x749
+ map(0x0800, 0x5fff).ram();
map(0x6000, 0x6fff).ram().share("vram");
map(0x7000, 0x7fff).ram().share("aram");
map(0x8000, 0xffff).rom().region("maincpu", 0);
+ map(0xfff7, 0xfff7).r(FUNC(informer_213_state::firq_vector_r));
+ map(0xfff9, 0xfff9).lr8(NAME([this] () { return m_scc->m1_r(); })); // irq vector
}
@@ -99,33 +143,71 @@ uint32_t informer_213_state::screen_update(screen_device &screen, bitmap_rgb32 &
{
offs_t chargen_base = (m_chargen.bytes() == 0x4000) ? 0x2000 : 0;
+ // line at which vram splits into two windows
+ int split = 24 - ((m_vram_start_addr2 - m_vram_start_addr) / 80);
+
for (int y = 0; y < 26; y++)
{
+ uint8_t line_attr = 0;
+
for (int x = 0; x < 80; x++)
{
- // screen memory starts at 0x6820
- uint8_t code = m_vram[26 * 80 + y * 80 + x];
-// uint8_t attr = m_aram[26 * 80 + y * 80 + x];
+ uint16_t addr;
- // but status line is at top of vram
- if (y > 23)
- {
- code = m_vram[(y - 24) * 80 + x];
-// attr = m_aram[(y - 24) * 80 + x];
- }
+ // vram is split into 3 areas: display window 1, display window 2, status bar
+ if (y >= 24)
+ addr = 0x6000 + (y - 24) * 80 + x;
+ else if (y >= split)
+ addr = m_vram_start_addr + (y - split) * 80 + x;
+ else
+ addr = m_vram_start_addr2 + y * 80 + x;
+
+ uint8_t code = m_vram[addr - 0x6000];
+ uint8_t attr = m_aram[addr - 0x6000];
+
+ if (code == 0xc0 || code == 0xe8)
+ line_attr = attr;
// draw 9 lines
for (int i = 0; i < 9; i++)
{
uint8_t data = m_chargen[chargen_base | ((code << 4) + i)];
+ // conceal
+ if (line_attr & 0x08 || attr & 0x08)
+ data = 0x00;
+
+ // reverse video
+ if (line_attr & 0x10 || attr & 0x10)
+ data ^= 0xff;
+
+ // underline (not supported by terminal?)
+ if (line_attr & 0x20 || attr & 0x20)
+ data = +data;
+
+ // blink (todo: timing)
+ if (line_attr & 0x40 || attr & 0x40)
+ data = m_screen->frame_number() & 0x20 ? 0x00 :data;
+
+ if (code == 0xc0 || code == 0xe8)
+ data = 0;
+
+ if (BIT(m_screen_ctrl, 5))
+ data ^= 0xff;
+
+ // cursor
+ if (BIT(m_cursor_start, 5) == 1 && addr == m_cursor_addr && y < 24)
+ if (i >= (m_cursor_start & 0x0f) && i < (m_cursor_end & 0x0f))
+ if (!(BIT(m_screen_ctrl, 4) == 0 && (m_screen->frame_number() & 0x20)))
+ data = 0xff;
+
// 6 pixels of the character
- bitmap.pix32(y * 9 + i, x * 6 + 0) = BIT(data, 7) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y * 9 + i, x * 6 + 1) = BIT(data, 6) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y * 9 + i, x * 6 + 2) = BIT(data, 5) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y * 9 + i, x * 6 + 3) = BIT(data, 4) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y * 9 + i, x * 6 + 4) = BIT(data, 3) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y * 9 + i, x * 6 + 5) = BIT(data, 2) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y * 9 + i, x * 6 + 0) = BIT(data, 7) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y * 9 + i, x * 6 + 1) = BIT(data, 6) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y * 9 + i, x * 6 + 2) = BIT(data, 5) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y * 9 + i, x * 6 + 3) = BIT(data, 4) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y * 9 + i, x * 6 + 4) = BIT(data, 3) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y * 9 + i, x * 6 + 5) = BIT(data, 2) ? rgb_t::white() : rgb_t::black();
}
}
}
@@ -133,6 +215,96 @@ uint32_t informer_213_state::screen_update(screen_device &screen, bitmap_rgb32 &
return 0;
}
+void informer_213_state::vram_start_addr_w(offs_t offset, uint8_t data)
+{
+ if (offset)
+ m_vram_start_addr = (m_vram_start_addr & 0xff00) | (data << 0);
+ else
+ m_vram_start_addr = (m_vram_start_addr & 0x00ff) | (data << 8);
+
+ if (offset)
+ logerror("vram_start_addr_w: %04x\n", m_vram_start_addr);
+}
+
+void informer_213_state::vram_end_addr_w(offs_t offset, uint8_t data)
+{
+ if (offset)
+ m_vram_end_addr = (m_vram_end_addr & 0xff00) | (data << 0);
+ else
+ m_vram_end_addr = (m_vram_end_addr & 0x00ff) | (data << 8);
+
+ if (offset)
+ logerror("vram_end_addr_w: %04x\n", m_vram_end_addr);
+}
+
+void informer_213_state::vram_start_addr2_w(offs_t offset, uint8_t data)
+{
+ if (offset)
+ m_vram_start_addr2 = (m_vram_start_addr2 & 0xff00) | (data << 0);
+ else
+ m_vram_start_addr2 = (m_vram_start_addr2 & 0x00ff) | (data << 8);
+
+ if (offset)
+ logerror("vram_start_addr2_w: %04x\n", m_vram_start_addr2);
+}
+
+void informer_213_state::cursor_start_w(uint8_t data)
+{
+ logerror("cursor_start_w: %02x\n", data);
+
+ // 76------ unknown
+ // --5----- cursor visible
+ // ---4---- unknown
+ // ----3210 cursor starting line, values seen: 0 (block/off), 6 (underline)
+
+ m_cursor_start = data;
+}
+
+void informer_213_state::cursor_end_w(uint8_t data)
+{
+ logerror("cursor_end_w: %02x\n", data);
+
+ // 7654---- unknown
+ // ----3210 cursor ending line, values seen: 9 (block), 8 (underline), 1 (off)
+
+ m_cursor_end = data;
+}
+
+void informer_213_state::cursor_addr_w(offs_t offset, uint8_t data)
+{
+ if (offset)
+ m_cursor_addr = (m_cursor_addr & 0xff00) | (data << 0);
+ else
+ m_cursor_addr = (m_cursor_addr & 0x00ff) | (data << 8);
+
+ if (offset)
+ logerror("cursor_addr_w: %04x\n", m_cursor_addr);
+}
+
+void informer_213_state::screen_ctrl_w(uint8_t data)
+{
+ logerror("screen_ctrl_w: %02x\n", data);
+
+ // 76------ unknown
+ // --5----- screen reverse
+ // ---4---- cursor blink/steady
+ // ----3210 unknown
+
+ m_screen_ctrl = data;
+}
+
+void informer_213_state::vblank_w(int state)
+{
+ if (state)
+ {
+ // real source if this interrupt is unknown, deactivated for now
+#if 0
+ m_firq_vector = 0x10;
+ m_maincpu->set_input_line(M6809_FIRQ_LINE, HOLD_LINE);
+#endif
+ }
+}
+
static const gfx_layout char_layout =
{
6,9,
@@ -153,12 +325,52 @@ GFXDECODE_END
// MACHINE EMULATION
//**************************************************************************
+void informer_213_state::bell_w(uint8_t data)
+{
+ logerror("bell_w: %02x\n", data);
+
+ // 7654---- unknown
+ // ----3--- ram bank
+ // -----2-- beeper
+ // ------10 unknown
+
+ m_beep->set_state(BIT(data, 2));
+ m_nvram_bank->set_entry(BIT(data, 3));
+}
+
+void informer_213_state::kbd_int_w(int state)
+{
+ m_firq_vector = 0x14;
+ m_maincpu->set_input_line(M6809_FIRQ_LINE, HOLD_LINE);
+}
+
+uint8_t informer_213_state::firq_vector_r()
+{
+ uint8_t tmp = m_firq_vector;
+ m_firq_vector = 0x00;
+
+ return tmp;
+}
+
void informer_213_state::machine_start()
{
+ m_banked_ram = make_unique_clear<uint8_t[]>(0x800);
+ membank("banked")->configure_entries(0, 2, m_banked_ram.get(), 0x400);
+
+ m_nvram[1]->set_base(m_banked_ram.get(), 0x800);
+
+ // register for save states
+ save_item(NAME(m_vram_start_addr));
+ save_item(NAME(m_vram_start_addr2));
+ save_item(NAME(m_vram_end_addr));
+ save_item(NAME(m_cursor_addr));
+ save_item(NAME(m_screen_ctrl));
+ save_item(NAME(m_firq_vector));
}
void informer_213_state::machine_reset()
{
+ m_firq_vector = 0x00;
}
@@ -166,12 +378,32 @@ void informer_213_state::machine_reset()
// MACHINE DEFINTIONS
//**************************************************************************
+void in213_printer_devices(device_slot_interface &device)
+{
+ device.option_add("printer", SERIAL_PRINTER);
+}
+
void informer_213_state::informer_213(machine_config &config)
{
MC6809(config, m_maincpu, 18.432_MHz_XTAL / 4); // unknown clock
m_maincpu->set_addrmap(AS_PROGRAM, &informer_213_state::mem_map);
- SCC8530N(config, m_scc, 0); // unknown clock
+ NVRAM(config, m_nvram[0], nvram_device::DEFAULT_ALL_0);
+ NVRAM(config, m_nvram[1], nvram_device::DEFAULT_ALL_0);
+
+ SCC8530N(config, m_scc, 18.432_MHz_XTAL / 5);
+ m_scc->out_txda_callback().set("host", FUNC(rs232_port_device::write_txd));
+ m_scc->out_dtra_callback().set("host", FUNC(rs232_port_device::write_dtr));
+ m_scc->out_rtsa_callback().set("host", FUNC(rs232_port_device::write_rts));
+ m_scc->out_txdb_callback().set("printer", FUNC(rs232_port_device::write_txd));
+ m_scc->out_int_callback().set_inputline(m_maincpu, M6809_IRQ_LINE);
+
+ rs232_port_device &rs232_host(RS232_PORT(config, "host", default_rs232_devices, nullptr));
+ rs232_host.rxd_handler().set(m_scc, FUNC(scc85c30_device::rxa_w));
+ rs232_host.dcd_handler().set(m_scc, FUNC(scc85c30_device::dcda_w));
+ rs232_host.cts_handler().set(m_scc, FUNC(scc85c30_device::ctsa_w));
+
+ RS232_PORT(config, "printer", in213_printer_devices, nullptr);
// video
SCREEN(config, m_screen, SCREEN_TYPE_LCD);
@@ -179,12 +411,21 @@ void informer_213_state::informer_213(machine_config &config)
m_screen->set_size(480, 234);
m_screen->set_visarea_full();
m_screen->set_refresh_hz(60);
-// m_screen->set_raw(18.432_MHz_XTAL, 0, 0, 0, 0, 0, 0);
+ m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
+// m_screen->set_raw(18.432_MHz_XTAL, 0, 0, 0, 0, 0, 0);
m_screen->set_screen_update(FUNC(informer_213_state::screen_update));
+ m_screen->screen_vblank().set(FUNC(informer_213_state::vblank_w));
PALETTE(config, m_palette, palette_device::MONOCHROME);
GFXDECODE(config, "gfxdecode", m_palette, chars);
+
+ // sound
+ SPEAKER(config, "mono").front_center();
+ BEEP(config, "beep", 500).add_route(ALL_OUTPUTS, "mono", 0.50); // frequency unknown
+
+ informer_213_kbd_hle_device &kbd(INFORMER_213_KBD_HLE(config, "kbd"));
+ kbd.int_handler().set(FUNC(informer_213_state::kbd_int_w));
}
@@ -218,5 +459,5 @@ ROM_END
//**************************************************************************
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
-COMP( 1990, in213 , 0, 0, informer_213, informer_213, informer_213_state, empty_init, "Informer", "Informer 213", MACHINE_IS_SKELETON | MACHINE_SUPPORTS_SAVE )
-COMP( 1992, in213ae, 0, 0, informer_213, informer_213, informer_213_state, empty_init, "Informer", "Informer 213 AE", MACHINE_IS_SKELETON | MACHINE_SUPPORTS_SAVE )
+COMP( 1990, in213 , 0, 0, informer_213, informer_213, informer_213_state, empty_init, "Informer", "Informer 213", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+COMP( 1992, in213ae, 0, 0, informer_213, informer_213, informer_213_state, empty_init, "Informer", "Informer 213 AE", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/instruct.cpp b/src/mame/drivers/instruct.cpp
index af29922cd67..9d57c095809 100644
--- a/src/mame/drivers/instruct.cpp
+++ b/src/mame/drivers/instruct.cpp
@@ -2,14 +2,14 @@
// copyright-holders:Robbbert
/***************************************************************************
- Signetics Intructor 50
+Signetics Intructor 50
- 2010-04-08 Skeleton driver.
- 2012-05-20 Connected digits, system boots. [Robbbert]
- 2012-05-20 Connected keyboard, system mostly usable. [Robbbert]
- 2013-10-15 Fixed various regressions. [Robbbert]
+2010-04-08 Skeleton driver.
+2012-05-20 Connected digits, system boots. [Robbbert]
+2012-05-20 Connected keyboard, system mostly usable. [Robbbert]
+2013-10-15 Fixed various regressions. [Robbbert]
- From looking at a blurry picture of it, this is what I can determine:
+From looking at a blurry picture of it, this is what I can determine:
- Left side: 8 toggle switches, with a round red led above each one.
- Below this is the Port Address Switch with choice of 'Non-Extended', 'Extended' or 'Memory'.
- To the right of this is another toggle switch labelled 'Interrupt', the
@@ -25,14 +25,18 @@
MIC and EAR cords to a cassette player.
- At the back is a S100 interface.
- Quick usage:
+Quick usage:
- Look at memory: Press minus key. Enter an address. Press UP key to see the next.
- Look at registers: Press R. Press 0. Press UP key to see the next.
- Set PC register: Press R. Press C. Type in new address, Press UP.
- Load a tape: Press L, enter file number (1 digit), press UP. On
completion of a successful load, HELLO will be displayed.
- ToDO:
+Pasting a test program: (page 2-4 of the user manual, modified)
+ - Paste this: QRF0^751120F005000620FA7EF97A84011F0003-0P
+ - You should see the LEDs flashing as they count upwards.
+
+ToDO:
- Connect round led for Run.
- Last Address Register
- Initial Jump Logic
diff --git a/src/mame/drivers/invqix.cpp b/src/mame/drivers/invqix.cpp
index d25b321c04c..6a51d9e74c6 100644
--- a/src/mame/drivers/invqix.cpp
+++ b/src/mame/drivers/invqix.cpp
@@ -174,8 +174,6 @@ void invqix_state::video_start()
uint32_t invqix_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y;
-
// this means freeze or blank or something
if (m_vctl == 0x100)
{
@@ -184,45 +182,39 @@ uint32_t invqix_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
if (m_vctl == 0x0000)
{
- for(y=0;y<256;y++)
+ for(int y=0;y<256;y++)
{
- for(x=0;x<256;x++)
+ for(int x=0;x<256;x++)
{
- uint8_t r,g,b;
- int pen_data;
-
- pen_data = (m_vram[(x+y*256)]);
- b = (pen_data & 0x001f);
- g = (pen_data & 0x03e0) >> 5;
- r = (pen_data & 0x7c00) >> 10;
+ int pen_data = (m_vram[(x+y*256)]);
+ uint8_t b = (pen_data & 0x001f);
+ uint8_t g = (pen_data & 0x03e0) >> 5;
+ uint8_t r = (pen_data & 0x7c00) >> 10;
r = (r << 3) | (r & 0x7);
g = (g << 3) | (g & 0x7);
b = (b << 3) | (b & 0x7);
if(cliprect.contains(x, y))
- bitmap.pix32(y, x) = r << 16 | g << 8 | b;
+ bitmap.pix(y, x) = r << 16 | g << 8 | b;
}
}
}
else if (m_vctl == 0x0001) // flip
{
- for(y=0;y<256;y++)
+ for(int y=0;y<256;y++)
{
- for(x=0;x<256;x++)
+ for(int x=0;x<256;x++)
{
- uint8_t r,g,b;
- int pen_data;
-
- pen_data = (m_vram[(256-x)+((256-y)*256)]);
- b = (pen_data & 0x001f);
- g = (pen_data & 0x03e0) >> 5;
- r = (pen_data & 0x7c00) >> 10;
+ int pen_data = (m_vram[(256-x)+((256-y)*256)]);
+ uint8_t b = (pen_data & 0x001f);
+ uint8_t g = (pen_data & 0x03e0) >> 5;
+ uint8_t r = (pen_data & 0x7c00) >> 10;
r = (r << 3) | (r & 0x7);
g = (g << 3) | (g & 0x7);
b = (b << 3) | (b & 0x7);
if(cliprect.contains(x, y))
- bitmap.pix32(y, x) = r << 16 | g << 8 | b;
+ bitmap.pix(y, x) = r << 16 | g << 8 | b;
}
}
}
diff --git a/src/mame/drivers/ipds.cpp b/src/mame/drivers/ipds.cpp
index 1e25739e3f9..cd6379ed07e 100644
--- a/src/mame/drivers/ipds.cpp
+++ b/src/mame/drivers/ipds.cpp
@@ -92,8 +92,7 @@ void ipds_state::machine_reset()
I8275_DRAW_CHARACTER_MEMBER( ipds_state::crtc_display_pixels )
{
- int i;
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t *charmap = memregion("chargen")->base();
uint8_t pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
@@ -106,8 +105,8 @@ I8275_DRAW_CHARACTER_MEMBER( ipds_state::crtc_display_pixels )
if (rvv)
pixels ^= 0xff;
- for(i=0;i<6;i++)
- bitmap.pix32(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
+ for(int i=0;i<6;i++)
+ bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}
/* F4 Character Displayer */
diff --git a/src/mame/drivers/irisha.cpp b/src/mame/drivers/irisha.cpp
index e986c5562c2..0a51a6b624e 100644
--- a/src/mame/drivers/irisha.cpp
+++ b/src/mame/drivers/irisha.cpp
@@ -207,17 +207,15 @@ INPUT_PORTS_END
uint32_t irisha_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t gfx;
- uint16_t y,ma=0,x;
- uint16_t *p;
+ uint16_t ma=0;
- for (y = 0; y < 200; y++)
+ for (uint16_t y = 0; y < 200; y++)
{
- p = &bitmap.pix16(y);
+ uint16_t *p = &bitmap.pix(y);
- for (x = ma; x < ma+40; x++)
+ for (uint16_t x = ma; x < ma+40; x++)
{
- gfx = m_p_videoram[x];
+ uint8_t const gfx = m_p_videoram[x];
/* Display a scanline of a character */
*p++ = BIT(gfx, 7);
diff --git a/src/mame/drivers/istellar.cpp b/src/mame/drivers/istellar.cpp
index 687be6f0e79..1f546d3be55 100644
--- a/src/mame/drivers/istellar.cpp
+++ b/src/mame/drivers/istellar.cpp
@@ -26,7 +26,6 @@ Todo:
#include "machine/gen_latch.h"
#include "machine/ldv1000.h"
#include "emupal.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/istrebiteli.cpp b/src/mame/drivers/istrebiteli.cpp
index a1ba11ca972..065c5329159 100644
--- a/src/mame/drivers/istrebiteli.cpp
+++ b/src/mame/drivers/istrebiteli.cpp
@@ -45,7 +45,7 @@ protected:
virtual void device_start() override;
// device_sound_interface overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// internal state
@@ -81,15 +81,15 @@ istrebiteli_sound_device::istrebiteli_sound_device(const machine_config &mconfig
void istrebiteli_sound_device::device_start()
{
- m_channel = stream_alloc_legacy(0, 1, clock() / 2);
+ m_channel = stream_alloc(0, 1, clock() / 2);
m_rom = machine().root_device().memregion("soundrom")->base();
}
-void istrebiteli_sound_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void istrebiteli_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- stream_sample_t *sample = outputs[0];
+ auto &buffer = outputs[0];
- while (samples-- > 0)
+ for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
{
int smpl = 0;
if (m_rom_out_en)
@@ -100,7 +100,7 @@ void istrebiteli_sound_device::sound_stream_update_legacy(sound_stream &stream,
smpl &= machine().rand() & 1;
smpl *= (m_prev_data & 0x80) ? 1000 : 4000; // b7 volume ?
- *sample++ = smpl;
+ buffer.put_int(sampindex, smpl, 32768);
m_rom_cnt = (m_rom_cnt + m_rom_incr) & 0x1ff;
}
}
diff --git a/src/mame/drivers/itgambl2.cpp b/src/mame/drivers/itgambl2.cpp
index 61b39d63c18..26d1107f089 100644
--- a/src/mame/drivers/itgambl2.cpp
+++ b/src/mame/drivers/itgambl2.cpp
@@ -145,7 +145,7 @@ uint32_t itgambl2_state::screen_update_itgambl2(screen_device &screen, bitmap_rg
uint32_t const color = (blit_ram[count] & 0xff) >> 0;
if(cliprect.contains(x, y))
- bitmap.pix32(y, x) = m_palette->pen(color);
+ bitmap.pix(y, x) = m_palette->pen(color);
count++;
}
diff --git a/src/mame/drivers/itgambl3.cpp b/src/mame/drivers/itgambl3.cpp
index 894145657f8..ea119054d62 100644
--- a/src/mame/drivers/itgambl3.cpp
+++ b/src/mame/drivers/itgambl3.cpp
@@ -92,8 +92,7 @@ void itgambl3_state::video_start()
/* (dirty) debug code for looking 8bpps blitter-based gfxs */
uint32_t itgambl3_state::screen_update_itgambl3(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x,y,count;
- const uint8_t *blit_ram = memregion("gfx1")->base();
+ uint8_t const *const blit_ram = memregion("gfx1")->base();
if(machine().input().code_pressed(KEYCODE_Z))
m_test_x++;
@@ -123,18 +122,16 @@ uint32_t itgambl3_state::screen_update_itgambl3(screen_device &screen, bitmap_rg
bitmap.fill(m_palette->black_pen(), cliprect);
- count = (m_start_offs);
+ int count = m_start_offs;
- for(y=0;y<m_test_y;y++)
+ for(int y=0;y<m_test_y;y++)
{
- for(x=0;x<m_test_x;x++)
+ for(int x=0;x<m_test_x;x++)
{
- uint32_t color;
-
- color = (blit_ram[count] & 0xff)>>0;
+ uint32_t color = (blit_ram[count] & 0xff)>>0;
if(cliprect.contains(x, y))
- bitmap.pix32(y, x) = m_palette->pen(color);
+ bitmap.pix(y, x) = m_palette->pen(color);
count++;
}
diff --git a/src/mame/drivers/itt1700.cpp b/src/mame/drivers/itt1700.cpp
index ec993830f2d..f9d9cb41f04 100644
--- a/src/mame/drivers/itt1700.cpp
+++ b/src/mame/drivers/itt1700.cpp
@@ -51,7 +51,7 @@ private:
MC6845_UPDATE_ROW(itt1700_state::update_row)
{
- u32 *px = &bitmap.pix32(y);
+ u32 *px = &bitmap.pix(y);
u16 page = 0x800;
for (int i = 0; i < x_count; i++)
diff --git a/src/mame/drivers/jangou.cpp b/src/mame/drivers/jangou.cpp
index 789343aa3dc..7888971b5a2 100644
--- a/src/mame/drivers/jangou.cpp
+++ b/src/mame/drivers/jangou.cpp
@@ -193,7 +193,7 @@ uint32_t jangou_state::screen_update_jangou(screen_device &screen, bitmap_ind16
for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
const uint8_t *src = &m_blitter->blit_buffer(y, cliprect.min_x);
- uint16_t *dst = &m_tmp_bitmap->pix16(y, cliprect.min_x);
+ uint16_t *dst = &m_tmp_bitmap->pix(y, cliprect.min_x);
for (int x = cliprect.min_x; x <= cliprect.max_x; x += 2)
{
diff --git a/src/mame/drivers/jantotsu.cpp b/src/mame/drivers/jantotsu.cpp
index 200b8339b36..41912c6a542 100644
--- a/src/mame/drivers/jantotsu.cpp
+++ b/src/mame/drivers/jantotsu.cpp
@@ -166,28 +166,23 @@ void jantotsu_state::video_start()
uint32_t jantotsu_state::screen_update_jantotsu(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x, y, i;
- int count = 0;
- uint8_t pen_i;
-
if(!m_display_on)
return 0;
- for (y = 0; y < 256; y++)
+ int count = 0;
+ for (int y = 0; y < 256; y++)
{
- for (x = 0; x < 256; x += 8)
+ for (int x = 0; x < 256; x += 8)
{
- uint8_t color;
-
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
- color = m_col_bank;
+ uint8_t color = m_col_bank;
- for(pen_i = 0;pen_i<4;pen_i++)
+ for (uint8_t pen_i = 0;pen_i<4;pen_i++)
color |= (((m_bitmap[count + pen_i*0x2000]) >> (7 - i)) & 1) << pen_i;
if (cliprect.contains(x + i, y))
- bitmap.pix32(y, x + i) = m_palette->pen(color);
+ bitmap.pix(y, x + i) = m_palette->pen(color);
}
count++;
diff --git a/src/mame/drivers/jchan.cpp b/src/mame/drivers/jchan.cpp
index 37a642da4cc..412ef71848c 100644
--- a/src/mame/drivers/jchan.cpp
+++ b/src/mame/drivers/jchan.cpp
@@ -323,10 +323,10 @@ u32 jchan_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, cons
// TODO : verify sprite-tile priorities from real hardware, Check what 15 bit of palette actually working
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
- const u16* src1 = &m_sprite_bitmap[0]->pix16(y);
- const u16* src2 = &m_sprite_bitmap[1]->pix16(y);
- u8 *tilepri = &tile_primap->pix8(y);
- u16* dst = &bitmap.pix16(y);
+ u16 const *const src1 = &m_sprite_bitmap[0]->pix(y);
+ u16 const *const src2 = &m_sprite_bitmap[1]->pix(y);
+ u8 *const tilepri = &tile_primap->pix(y);
+ u16 *const dst = &bitmap.pix(y);
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
diff --git a/src/mame/drivers/jollyjgr.cpp b/src/mame/drivers/jollyjgr.cpp
index 4c2bfccea69..d413146df0f 100644
--- a/src/mame/drivers/jollyjgr.cpp
+++ b/src/mame/drivers/jollyjgr.cpp
@@ -514,13 +514,13 @@ void jollyjgr_state::draw_bitmap(bitmap_rgb32 &bitmap)
if (color)
{
if (m_flip_x && m_flip_y)
- bitmap.pix32(y, x * 8 + i) = m_bm_palette->pen_color(color);
+ bitmap.pix(y, x * 8 + i) = m_bm_palette->pen_color(color);
else if (m_flip_x && !m_flip_y)
- bitmap.pix32(255 - y, x * 8 + i) = m_bm_palette->pen_color(color);
+ bitmap.pix(255 - y, x * 8 + i) = m_bm_palette->pen_color(color);
else if (!m_flip_x && m_flip_y)
- bitmap.pix32(y, 255 - x * 8 - i) = m_bm_palette->pen_color(color);
+ bitmap.pix(y, 255 - x * 8 - i) = m_bm_palette->pen_color(color);
else
- bitmap.pix32(255 - y, 255 - x * 8 - i) = m_bm_palette->pen_color(color);
+ bitmap.pix(255 - y, 255 - x * 8 - i) = m_bm_palette->pen_color(color);
}
}
@@ -602,7 +602,7 @@ uint32_t jollyjgr_state::screen_update_fspider(screen_device &screen, bitmap_rgb
if (sy>=cliprect.min_y && sy<=cliprect.max_y)
for (int x=sx-4;x<sx;x++)
if (x>=cliprect.min_x && x<=cliprect.max_x)
- bitmap.pix32(sy, x) = m_bm_palette->pen_color(bc);
+ bitmap.pix(sy, x) = m_bm_palette->pen_color(bc);
}
return 0;
diff --git a/src/mame/drivers/jongkyo.cpp b/src/mame/drivers/jongkyo.cpp
index 1193f11fa83..98f8ed1d3b0 100644
--- a/src/mame/drivers/jongkyo.cpp
+++ b/src/mame/drivers/jongkyo.cpp
@@ -98,18 +98,10 @@ void jongkyo_state::video_start()
uint32_t jongkyo_state::screen_update_jongkyo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int y;
-
- for (y = 0; y < 256; ++y)
+ for (int y = 0; y < 256; ++y)
{
- int x;
-
- for (x = 0; x < 256; x += 4)
+ for (int x = 0; x < 256; x += 4)
{
- int b;
- int res_x,res_y;
- uint8_t data1;
- uint8_t data2;
uint8_t data3;
// data3 = m_videoram2[x/4 + y*64]; // wrong
@@ -120,15 +112,14 @@ uint32_t jongkyo_state::screen_update_jongkyo(screen_device &screen, bitmap_ind1
// data3 = 0x00; // we're missing 2 bits.. there must be another piece of video ram somewhere or we can't use all the colours (6bpp).. banked somehow?
+ uint8_t data1 = m_videoram[0x4000 + x / 4 + y * 64];
+ uint8_t data2 = m_videoram[x / 4 + y * 64];
- data1 = m_videoram[0x4000 + x / 4 + y * 64];
- data2 = m_videoram[x / 4 + y * 64];
-
- for (b = 0; b < 4; ++b)
+ for (int b = 0; b < 4; ++b)
{
- res_x = m_flip_screen ? 255 - (x + b) : (x + b);
- res_y = m_flip_screen ? 255 - y : y;
- bitmap.pix16(res_y, res_x) = ((data2 & 0x01)) + ((data2 & 0x10) >> 3) +
+ int const res_x = m_flip_screen ? 255 - (x + b) : (x + b);
+ int const res_y = m_flip_screen ? 255 - y : y;
+ bitmap.pix(res_y, res_x) = ((data2 & 0x01)) + ((data2 & 0x10) >> 3) +
((data1 & 0x01) << 2) + ((data1 & 0x10) >> 1) +
((data3 & 0x01) << 4) + ((data3 & 0x10) << 1);
data1 >>= 1;
diff --git a/src/mame/drivers/jonos.cpp b/src/mame/drivers/jonos.cpp
index 2009928dd76..ea499a758d3 100644
--- a/src/mame/drivers/jonos.cpp
+++ b/src/mame/drivers/jonos.cpp
@@ -124,23 +124,23 @@ void jonos_state::machine_reset()
uint32_t jonos_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_framecnt++;
- u8 y,ra,chr,gfx,inv;
- u16 sy=0,x;
+ u16 sy=0;
u16 ma = (m_p_videoram[0x7da] + (m_p_videoram[0x7db] << 8)) & 0x7ff;
- for (y = 0; y < 24; y++)
+ for (u8 y = 0; y < 24; y++)
{
- for (ra = 0; ra < 12; ra++)
+ for (u8 ra = 0; ra < 12; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
u16 cpos = y << 8;
- for (x = ma; x < ma + 80; x++)
+ for (u16 x = ma; x < ma + 80; x++)
{
- chr = m_p_videoram[x];
- inv = (BIT(chr, 7) ^ ((cpos == m_curs_pos) && BIT(m_framecnt, 5))) ? 0xff : 0;
+ u8 chr = m_p_videoram[x];
+ u8 inv = (BIT(chr, 7) ^ ((cpos == m_curs_pos) && BIT(m_framecnt, 5))) ? 0xff : 0;
chr &= 0x7f;
+ u8 gfx;
if (ra < 8)
gfx = m_p_chargen[(chr<<3) | ra ] ^ inv;
else
diff --git a/src/mame/drivers/joystand.cpp b/src/mame/drivers/joystand.cpp
index 049ffbf1421..0fa58107e82 100644
--- a/src/mame/drivers/joystand.cpp
+++ b/src/mame/drivers/joystand.cpp
@@ -253,7 +253,7 @@ void joystand_state::bg2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
void joystand_state::bg15_0_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
uint16_t val = COMBINE_DATA(&m_bg15_0_ram[offset]);
- m_bg15_bitmap[0].pix32(offset >> 9, offset & 0x1ff) = (val & 0x8000) ? BG15_TRANSPARENT : m_bg15_palette->pen_color(val & 0x7fff);
+ m_bg15_bitmap[0].pix(offset >> 9, offset & 0x1ff) = (val & 0x8000) ? BG15_TRANSPARENT : m_bg15_palette->pen_color(val & 0x7fff);
}
// tile-based
@@ -268,7 +268,7 @@ void joystand_state::draw_bg15_tile(address_space &space, int x, int y, uint16_t
for (int tx = 0; tx < 16; ++tx)
{
uint16_t val = space.read_word(srcaddr + ty * 16 * 2 + tx * 2);
- m_bg15_bitmap[1].pix32(y + ty , x + tx) = (val & 0x8000) ? BG15_TRANSPARENT : m_bg15_palette->pen_color(val & 0x7fff);
+ m_bg15_bitmap[1].pix(y + ty , x + tx) = (val & 0x8000) ? BG15_TRANSPARENT : m_bg15_palette->pen_color(val & 0x7fff);
}
}
}
diff --git a/src/mame/drivers/jpmsys5.cpp b/src/mame/drivers/jpmsys5.cpp
index b203c7d6330..a0f4bad7093 100644
--- a/src/mame/drivers/jpmsys5.cpp
+++ b/src/mame/drivers/jpmsys5.cpp
@@ -153,8 +153,6 @@ void jpmsys5v_state::ramdac_w(offs_t offset, uint16_t data)
uint32_t jpmsys5v_state::screen_update_jpmsys5v(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x, y;
-
m_tms34061->get_display_state();
if (m_tms34061->m_display.blanked)
@@ -163,14 +161,14 @@ uint32_t jpmsys5v_state::screen_update_jpmsys5v(screen_device &screen, bitmap_rg
return 0;
}
- for (y = cliprect.min_y; y <= cliprect.max_y; ++y)
+ for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
- uint8_t *src = &m_tms34061->m_display.vram[(m_tms34061->m_display.dispstart & 0xffff)*2 + 256 * y];
- uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
+ uint8_t const *const src = &m_tms34061->m_display.vram[(m_tms34061->m_display.dispstart & 0xffff)*2 + 256 * y];
+ uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
- for (x = cliprect.min_x; x <= cliprect.max_x; x +=2)
+ for (int x = cliprect.min_x; x <= cliprect.max_x; x +=2)
{
- uint8_t pen = src[(x-cliprect.min_x)>>1];
+ uint8_t const pen = src[(x-cliprect.min_x)>>1];
/* Draw two 4-bit pixels */
*dest++ = m_palette->pen((pen >> 4) & 0xf);
diff --git a/src/mame/drivers/jr100.cpp b/src/mame/drivers/jr100.cpp
index 8514b1f5f8d..748771028d0 100644
--- a/src/mame/drivers/jr100.cpp
+++ b/src/mame/drivers/jr100.cpp
@@ -170,10 +170,10 @@ INPUT_PORTS_START( jr100 )
PORT_BIT(0xE0, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("LINE5")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y Locate") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U @ If") PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U @ If") PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHAR('@')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I \xc2\xa5 Input") PORT_CODE(KEYCODE_I) PORT_CHAR('I')
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O [ Option") PORT_CODE(KEYCODE_O) PORT_CHAR('O')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P ] Print") PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("O [ Option") PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('[')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P ] Print") PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR(']')
PORT_BIT(0xE0, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_START("LINE6")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H Poke") PORT_CODE(KEYCODE_H) PORT_CHAR('H')
@@ -216,20 +216,19 @@ void jr100_state::machine_reset()
uint32_t jr100_state::screen_update_jr100(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- bool attr;
- u8 y,ra,gfx,chr;
- u16 x,sy=0,ma=0;
+ u16 sy=0,ma=0;
- for (y = 0; y < 24; y++)
+ for (u8 y = 0; y < 24; y++)
{
- for (ra = 0; ra < 8; ra++)
+ for (u8 ra = 0; ra < 8; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
- for (x = ma; x < ma + 32; x++)
+ uint16_t *p = &bitmap.pix(sy++);
+ for (u16 x = ma; x < ma + 32; x++)
{
- chr = m_vram[x];
- attr = BIT(chr, 7);
+ u8 chr = m_vram[x];
+ bool const attr = BIT(chr, 7);
chr &= 0x7f;
+ u8 gfx;
// ATTR is inverted for normal char or use PCG in case of CMODE1
if (m_use_pcg && attr && (chr < 32))
gfx = m_pcg[(chr<<3) | ra];
@@ -401,7 +400,7 @@ void jr100_state::jr100(machine_config &config)
m_via->irq_handler().set_inputline(m_maincpu, M6800_IRQ_LINE);
SPEAKER(config, "mono").front_center();
- SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00);
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);
CASSETTE(config, m_cassette, 0);
m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
diff --git a/src/mame/drivers/jr200.cpp b/src/mame/drivers/jr200.cpp
index 80f08a50e21..eabbbd154b4 100644
--- a/src/mame/drivers/jr200.cpp
+++ b/src/mame/drivers/jr200.cpp
@@ -166,22 +166,21 @@ void jr200_state::video_start()
uint32_t jr200_state::screen_update_jr200(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x,y,xi,yi,pen;
-
bitmap.fill(m_border_col, cliprect);
- for (y = 0; y < 24; y++)
+ for (int y = 0; y < 24; y++)
{
- for (x = 0; x < 32; x++)
+ for (int x = 0; x < 32; x++)
{
uint8_t tile = m_vram[x + y*32];
uint8_t attr = m_cram[x + y*32];
- for(yi=0;yi<8;yi++)
+ for(int yi=0;yi<8;yi++)
{
- for(xi=0;xi<8;xi++)
+ for(int xi=0;xi<8;xi++)
{
- uint8_t *gfx_data;
+ const uint8_t *gfx_data;
+ int pen;
if(attr & 0x80) //bitmap mode
{
@@ -209,7 +208,7 @@ uint32_t jr200_state::screen_update_jr200(screen_device &screen, bitmap_ind16 &b
pen = (gfx_data[(tile*8)+yi]>>(7-xi) & 1) ? (attr & 0x7) : ((attr & 0x38) >> 3);
}
- bitmap.pix16(y*8+yi+16, x*8+xi+16) = m_palette->pen(pen);
+ bitmap.pix(y*8+yi+16, x*8+xi+16) = m_palette->pen(pen);
}
}
}
diff --git a/src/mame/drivers/jtc.cpp b/src/mame/drivers/jtc.cpp
index ffd343f3f2c..7c425e7eb46 100644
--- a/src/mame/drivers/jtc.cpp
+++ b/src/mame/drivers/jtc.cpp
@@ -669,16 +669,14 @@ QUICKLOAD_LOAD_MEMBER(jtc_state::quickload_cb)
u32 jtc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 i, y, sx;
-
- for (y = 0; y < 64; y++)
+ for (u8 y = 0; y < 64; y++)
{
- for (sx = 0; sx < 8; sx++)
+ for (u8 sx = 0; sx < 8; sx++)
{
- u8 data = m_video_ram[(y * 8) + sx];
+ u8 const data = m_video_ram[(y * 8) + sx];
- for (i = 0; i < 8; i++)
- bitmap.pix16(y, (sx * 8) + i) = BIT(data, 7-i);
+ for (u8 i = 0; i < 8; i++)
+ bitmap.pix(y, (sx * 8) + i) = BIT(data, 7-i);
}
}
@@ -687,16 +685,14 @@ u32 jtc_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const
u32 jtces23_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 i, y, sx;
-
- for (y = 0; y < 128; y++)
+ for (u8 y = 0; y < 128; y++)
{
- for (sx = 0; sx < 16; sx++)
+ for (u8 sx = 0; sx < 16; sx++)
{
- u8 data = m_video_ram[(y * 16) + sx];
+ u8 const data = m_video_ram[(y * 16) + sx];
- for (i = 0; i < 8; i++)
- bitmap.pix16(y, (sx * 8) + i) = BIT(data, 7-i);
+ for (u8 i = 0; i < 8; i++)
+ bitmap.pix(y, (sx * 8) + i) = BIT(data, 7-i);
}
}
@@ -742,7 +738,7 @@ u32 jtces40_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
u8 const b = ~m_color_ram_b[ma + x];
for (int i = 0; i < 8; i++)
- bitmap.pix16(y*3+z, (x * 8) + 7 - i) = (BIT(r, i) << 0) | (BIT(g, i) << 1) | (BIT(b, i) << 2) | (BIT(data, i) << 3);
+ bitmap.pix(y*3+z, (x * 8) + 7 - i) = (BIT(r, i) << 0) | (BIT(g, i) << 1) | (BIT(b, i) << 2) | (BIT(data, i) << 3);
}
ma+=40;
}
diff --git a/src/mame/drivers/juku.cpp b/src/mame/drivers/juku.cpp
index 0ab5ca60f12..98ac5951af0 100644
--- a/src/mame/drivers/juku.cpp
+++ b/src/mame/drivers/juku.cpp
@@ -303,7 +303,7 @@ uint32_t juku_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
{
for (int y = 0; y < 240; y++)
for (int x = 0; x < 320; x++)
- bitmap.pix32(y, x) = BIT(m_ram[0xd800 + (y * (320 / 8) + x / 8)], 7 - (x % 8)) ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y, x) = BIT(m_ram[0xd800 + (y * (320 / 8) + x / 8)], 7 - (x % 8)) ? rgb_t::white() : rgb_t::black();
return 0;
}
diff --git a/src/mame/drivers/jupace.cpp b/src/mame/drivers/jupace.cpp
index 9c1d55bf969..455eef6f8c2 100644
--- a/src/mame/drivers/jupace.cpp
+++ b/src/mame/drivers/jupace.cpp
@@ -584,21 +584,19 @@ TIMER_DEVICE_CALLBACK_MEMBER(ace_state::clear_irq)
uint32_t ace_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,chr,gfx;
- uint16_t sy=56,ma=0,x;
-
- for (y = 0; y < 24; y++)
+ uint16_t sy=56, ma=0;
+ for (uint8_t y = 0; y < 24; y++)
{
- for (ra = 0; ra < 8; ra++)
+ for (uint8_t ra = 0; ra < 8; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++, 40);
+ uint16_t *p = &bitmap.pix(sy++, 40);
- for (x = ma; x < ma+32; x++)
+ for (uint16_t x = ma; x < ma+32; x++)
{
- chr = m_video_ram[x];
+ uint8_t const chr = m_video_ram[x];
/* get pattern of pixels for that character scanline */
- gfx = m_char_ram[((chr&0x7f)<<3) | ra] ^ (BIT(chr, 7) ? 0xff : 0);
+ uint8_t const gfx = m_char_ram[((chr&0x7f)<<3) | ra] ^ (BIT(chr, 7) ? 0xff : 0);
/* Display a scanline of a character (8 pixels) */
*p++ = BIT(gfx, 7);
diff --git a/src/mame/drivers/jupiter.cpp b/src/mame/drivers/jupiter.cpp
index 9c2692e6ebc..79ca7743019 100644
--- a/src/mame/drivers/jupiter.cpp
+++ b/src/mame/drivers/jupiter.cpp
@@ -202,21 +202,20 @@ void jupiter3_state::kbd_put(u8 data)
uint32_t jupiter3_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,chr,gfx;
- uint16_t sy=0,ma=0,x;
+ uint16_t sy=0,ma=0;
- for (y = 0; y < 32; y++)
+ for (uint8_t y = 0; y < 32; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (uint8_t ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 64; x++)
+ for (uint16_t x = ma; x < ma + 64; x++)
{
- gfx = 0;
+ uint8_t gfx = 0;
if (ra < 9)
{
- chr = m_p_videoram[x];
+ uint8_t chr = m_p_videoram[x];
gfx = m_p_chargen[(chr<<4) | ra ];
}
diff --git a/src/mame/drivers/k8915.cpp b/src/mame/drivers/k8915.cpp
index 8e19debc68e..6f8f4bbd7d7 100644
--- a/src/mame/drivers/k8915.cpp
+++ b/src/mame/drivers/k8915.cpp
@@ -92,24 +92,23 @@ void k8915_state::machine_start()
u32 k8915_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx;
- u16 sy=0,ma=0,x;
+ u16 sy=0,ma=0;
m_framecnt++;
- for (y = 0; y < 25; y++)
+ for (u8 y = 0; y < 25; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (u8 ra = 0; ra < 10; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 80; x++)
+ for (u16 x = ma; x < ma + 80; x++)
{
- gfx = 0;
+ u8 gfx = 0;
if (ra < 9)
{
- chr = m_p_videoram[x];
+ u8 chr = m_p_videoram[x];
/* Take care of flashing characters */
if ((chr & 0x80) && (m_framecnt & 0x08))
diff --git a/src/mame/drivers/karnov.cpp b/src/mame/drivers/karnov.cpp
index 97b715a5fe0..776d40a70b3 100644
--- a/src/mame/drivers/karnov.cpp
+++ b/src/mame/drivers/karnov.cpp
@@ -202,45 +202,7 @@ void karnov_state::mcubl_p1_w(uint8_t data)
// mcu simulation below
-/* Emulation of the protected microcontroller - for coins & general protection */
-void karnov_state::karnov_i8751_w( int data )
-{
- /* Pending coin operations may cause protection commands to be queued */
- if (m_i8751_needs_ack)
- {
- m_i8751_command_queue = data;
- return;
- }
-
- m_i8751_return = 0;
-
- if (data == 0x100 && m_microcontroller_id == KARNOV) /* USA version */
- m_i8751_return = 0x56b;
-
- if (data == 0x100 && m_microcontroller_id == KARNOVJ) /* Japan version */
- m_i8751_return = 0x56a;
-
- if ((data & 0xf00) == 0x300)
- m_i8751_return = (data & 0xff) * 0x12; /* Player sprite mapping */
-
- /* I'm not sure the ones marked ^ appear in the right order */
- if (data == 0x400) m_i8751_return = 0x4000; /* Get The Map... */
- if (data == 0x402) m_i8751_return = 0x40a6; /* Ancient Ruins */
- if (data == 0x403) m_i8751_return = 0x4054; /* Forest... */
- if (data == 0x404) m_i8751_return = 0x40de; /* ^Rocky hills */
- if (data == 0x405) m_i8751_return = 0x4182; /* Sea */
- if (data == 0x406) m_i8751_return = 0x41ca; /* Town */
- if (data == 0x407) m_i8751_return = 0x421e; /* Desert */
- if (data == 0x401) m_i8751_return = 0x4138; /* ^Whistling wind */
- if (data == 0x408) m_i8751_return = 0x4276; /* ^Heavy Gates */
-
-// if (!m_i8751_return && data != 0x300) logerror("%s - Unknown Write %02x intel\n", machine().describe_context(), data);
-
- m_maincpu->set_input_line(6, HOLD_LINE); /* Signal main cpu task is complete */
- m_i8751_needs_ack = 1;
-}
-
-void karnov_state::wndrplnt_i8751_w( int data )
+void karnov_state::wndrplnt_mcu_w( uint16_t data )
{
/* The last command hasn't been ACK'd (probably a conflict with coin command) */
if (m_i8751_needs_ack)
@@ -305,7 +267,7 @@ void karnov_state::wndrplnt_i8751_w( int data )
*
*************************************/
-void karnov_state::mcusim_ack_w(u16 data)
+void karnov_state::wndrplnt_mcu_ack_w(u16 data)
{
m_maincpu->set_input_line(6, CLEAR_LINE);
@@ -322,7 +284,7 @@ void karnov_state::mcusim_ack_w(u16 data)
{
/* Pending control command - just write it back as SECREQ */
m_i8751_needs_ack = 0;
- mcusim_w(m_i8751_command_queue);
+ wndrplnt_mcu_w(m_i8751_command_queue);
m_i8751_command_queue = 0;
}
else
@@ -332,20 +294,12 @@ void karnov_state::mcusim_ack_w(u16 data)
}
}
-u16 karnov_state::mcusim_r()
+u16 karnov_state::wndrplnt_mcu_r()
{
return m_i8751_return;
}
-void karnov_state::mcusim_w(u16 data)
-{
- if (m_microcontroller_id == KARNOV || m_microcontroller_id == KARNOVJ)
- karnov_i8751_w(data);
- if (m_microcontroller_id == WNDRPLNT)
- wndrplnt_i8751_w(data);
-}
-
-void karnov_state::mcusim_reset_w(u16 data)
+void karnov_state::wndrplnt_mcu_reset_w(u16 data)
{
logerror("Reset i8751\n");
m_i8751_needs_ack = 0;
@@ -376,23 +330,28 @@ void karnov_state::karnov_map(address_map &map)
map(0x0a1000, 0x0a17ff).w(FUNC(karnov_state::playfield_w)).share("pf_data");
map(0x0a1800, 0x0a1fff).lw16([this](offs_t offset, u16 data, u16 mem_mask)
{ playfield_w(((offset & 0x1f) << 5) | ((offset & 0x3e0) >> 5), data, mem_mask); }, "pf_col_w");
- map(0x0c0000, 0x0c0001).portr("P1_P2").w(FUNC(karnov_state::mcusim_ack_w));
+ map(0x0c0000, 0x0c0001).portr("P1_P2").w(FUNC(karnov_state::mcu_ack_w));
map(0x0c0002, 0x0c0003).portr("SYSTEM");
map(0x0c0003, 0x0c0003).w(m_soundlatch, FUNC(generic_latch_8_device::write));
map(0x0c0004, 0x0c0005).portr("DSW").w(m_spriteram, FUNC(buffered_spriteram16_device::write));
- map(0x0c0006, 0x0c0007).rw(FUNC(karnov_state::mcusim_r), FUNC(karnov_state::mcusim_w));
+ map(0x0c0006, 0x0c0007).rw(FUNC(karnov_state::mcu_r), FUNC(karnov_state::mcu_w));
map(0x0c0008, 0x0c000b).writeonly().share("scroll");
- map(0x0c000c, 0x0c000d).w(FUNC(karnov_state::mcusim_reset_w));
- map(0x0c000e, 0x0c000f).w(FUNC(karnov_state::vint_ack_w));
+ map(0x0c000e, 0x0c000f).nopr().w(FUNC(karnov_state::vint_ack_w));
}
-void karnov_state::chelnov_map(address_map &map)
+void karnov_state::karnovjbl_map(address_map &map)
{
karnov_map(map);
- map(0x0c0000, 0x0c0001).portr("P1_P2").w(FUNC(karnov_state::mcu_ack_w));
- map(0x0c0006, 0x0c0007).rw(FUNC(karnov_state::mcu_r), FUNC(karnov_state::mcu_w));
- map(0x0c000c, 0x0c000d).unmaprw();
- map(0x0c000e, 0x0c000f).nopr();
+ map(0x0c0000, 0x0c0001).portr("P1_P2").nopw();
+ map(0x0c0006, 0x0c0007).lr16(NAME([]() { return 0x56a; })).lw16(NAME([this](u16 data) { m_maincpu->set_input_line(6, HOLD_LINE); }));
+}
+
+void karnov_state::wndrplnt_map(address_map &map)
+{
+ karnov_map(map);
+ map(0x0c0000, 0x0c0001).portr("P1_P2").w(FUNC(karnov_state::wndrplnt_mcu_ack_w));
+ map(0x0c0006, 0x0c0007).rw(FUNC(karnov_state::wndrplnt_mcu_r), FUNC(karnov_state::wndrplnt_mcu_w));
+ map(0x0c000c, 0x0c000d).w(FUNC(karnov_state::wndrplnt_mcu_reset_w));
}
void karnov_state::base_sound_map(address_map &map)
@@ -457,10 +416,11 @@ INPUT_PORTS_END
static INPUT_PORTS_START( karnov )
PORT_INCLUDE( common )
- PORT_START("COIN") /* Dummy input for i8751 */
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SERVICE1 )
+ PORT_START("COIN")
+ PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_WRITE_LINE_DEVICE_MEMBER("coin", input_merger_device, in_w<0>)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_WRITE_LINE_DEVICE_MEMBER("coin", input_merger_device, in_w<1>)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_WRITE_LINE_DEVICE_MEMBER("coin", input_merger_device, in_w<2>)
PORT_START("DSW")
PORT_DIPNAME( 0x0003, 0x0003, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW1:1,2")
@@ -505,6 +465,15 @@ static INPUT_PORTS_START( karnov )
PORT_DIPSETTING( 0x0000, "Fast" )
INPUT_PORTS_END
+static INPUT_PORTS_START( karnovjbl )
+ PORT_INCLUDE(karnov)
+
+ PORT_MODIFY("COIN")
+ PORT_BIT(0x1f, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_COIN1)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_COIN2)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_SERVICE1)
+INPUT_PORTS_END
/* verified from M68000 code */
static INPUT_PORTS_START( wndrplnt )
@@ -690,7 +659,7 @@ GFXDECODE_END
*
*************************************/
-WRITE_LINE_MEMBER(karnov_state::mcusim_vbint_w)
+WRITE_LINE_MEMBER(karnov_state::wndrplnt_mcusim_vbint_w)
{
if (!state)
return;
@@ -698,10 +667,10 @@ WRITE_LINE_MEMBER(karnov_state::mcusim_vbint_w)
uint8_t port = ioport("COIN")->read();
/* Coin input to the i8751 generates an interrupt to the main cpu */
- if (port == m_coin_mask)
+ if (port == 0)
m_latch = 1;
- if (port != m_coin_mask && m_latch)
+ if (port != 0 && m_latch)
{
if (m_i8751_needs_ack)
{
@@ -769,9 +738,22 @@ void karnov_state::karnov(machine_config &config)
M68000(config, m_maincpu, 20_MHz_XTAL/2); /* 10 MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::karnov_map);
+ // needs a tight sync with the mcu
+ config.set_perfect_quantum(m_maincpu);
+
M6502(config, m_audiocpu, 12_MHz_XTAL/8); /* Accurate */
m_audiocpu->set_addrmap(AS_PROGRAM, &karnov_state::karnov_sound_map);
+ I8751(config, m_mcu, 8_MHz_XTAL);
+ m_mcu->port_in_cb<0>().set([this](){ return m_mcu_p0; });
+ m_mcu->port_out_cb<0>().set([this](u8 data){ m_mcu_p0 = data; });
+ m_mcu->port_in_cb<1>().set([this](){ return m_mcu_p1; });
+ m_mcu->port_out_cb<1>().set([this](u8 data){ m_mcu_p1 = data; });
+ m_mcu->port_out_cb<2>().set(FUNC(karnov_state::mcu_p2_w));
+ m_mcu->port_in_cb<3>().set_ioport("COIN");
+
+ INPUT_MERGER_ANY_LOW(config, "coin").output_handler().set(FUNC(karnov_state::mcu_coin_irq));
+
/* video hardware */
BUFFERED_SPRITERAM16(config, m_spriteram);
@@ -782,7 +764,7 @@ void karnov_state::karnov(machine_config &config)
m_screen->set_visarea(0*8, 32*8-1, 1*8, 31*8-1);
m_screen->set_screen_update(FUNC(karnov_state::screen_update));
m_screen->set_palette(m_palette);
- m_screen->screen_vblank().set(FUNC(karnov_state::mcusim_vbint_w));
+ m_screen->screen_vblank().set(FUNC(karnov_state::vbint_w));
GFXDECODE(config, m_gfxdecode, m_palette, gfx_karnov);
DECO_RMC3(config, m_palette, 0, 1024); // xxxxBBBBGGGGRRRR with custom weighting
@@ -810,54 +792,44 @@ void karnov_state::karnov(machine_config &config)
void karnov_state::karnovjbl(machine_config &config)
{
karnov(config);
+
/* X-TALs:
Top board next to #9 is 20.000 MHz
Top board next to the microcontroller is 6.000 MHz
Bottom board next to the ribbon cable is 12.000 MHz*/
+
+ m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::karnovjbl_map);
m_audiocpu->set_addrmap(AS_PROGRAM, &karnov_state::karnovjbl_sound_map);
+ // different MCU
+ config.device_remove("mcu");
+ config.device_remove("coin");
+
ym3812_device &ym2(YM3812(config.replace(), "ym2", 3000000));
ym2.irq_handler().set_inputline(m_audiocpu, M6502_IRQ_LINE);
ym2.add_route(ALL_OUTPUTS, "mono", 1.0);
}
-void karnov_state::chelnov(machine_config &config)
-{
- karnov(config);
- m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::chelnov_map);
-
- I8751(config, m_mcu, 8_MHz_XTAL); // 8.000 MHz OSC next to MCU
- m_mcu->port_in_cb<0>().set([this](){ return m_mcu_p0; });
- m_mcu->port_out_cb<0>().set([this](u8 data){ m_mcu_p0 = data; });
- m_mcu->port_in_cb<1>().set([this](){ return m_mcu_p1; });
- m_mcu->port_out_cb<1>().set([this](u8 data){ m_mcu_p1 = data; });
- m_mcu->port_out_cb<2>().set(FUNC(karnov_state::mcu_p2_w));
- m_mcu->port_in_cb<3>().set_ioport("COIN");
-
- INPUT_MERGER_ANY_LOW(config, "coin").output_handler().set(FUNC(karnov_state::mcu_coin_irq));
-
- m_screen->screen_vblank().set(FUNC(karnov_state::vbint_w));
-}
-
void karnov_state::chelnovjbl(machine_config &config)
{
karnov(config);
- m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::chelnov_map);
+ m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::karnov_map);
+
+ config.device_remove("mcu");
+ config.device_remove("coin");
I8031(config, m_mcu, 8_MHz_XTAL); // info below states 8MHz for MCU
m_mcu->set_addrmap(AS_PROGRAM, &karnov_state::chelnovjbl_mcu_map);
m_mcu->set_addrmap(AS_IO, &karnov_state::chelnovjbl_mcu_io_map);
m_mcu->port_out_cb<1>().set(FUNC(karnov_state::mcubl_p1_w));
m_mcu->port_in_cb<3>().set_ioport("COIN");
-
- m_screen->screen_vblank().set(FUNC(karnov_state::vbint_w));
}
void karnov_state::wndrplnt(machine_config &config)
{
/* basic machine hardware */
M68000(config, m_maincpu, 20_MHz_XTAL/2); /* 10 MHz */
- m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::karnov_map);
+ m_maincpu->set_addrmap(AS_PROGRAM, &karnov_state::wndrplnt_map);
M6502(config, m_audiocpu, 12_MHz_XTAL/8); /* Accurate */
m_audiocpu->set_addrmap(AS_PROGRAM, &karnov_state::karnov_sound_map);
@@ -872,7 +844,7 @@ void karnov_state::wndrplnt(machine_config &config)
screen.set_visarea(0*8, 32*8-1, 1*8, 31*8-1);
screen.set_screen_update(FUNC(karnov_state::screen_update));
screen.set_palette(m_palette);
- screen.screen_vblank().set(FUNC(karnov_state::mcusim_vbint_w));
+ screen.screen_vblank().set(FUNC(karnov_state::wndrplnt_mcusim_vbint_w));
GFXDECODE(config, m_gfxdecode, m_palette, gfx_karnov);
DECO_RMC3(config, m_palette, 0, 1024); // xxxxBBBBGGGGRRRR with custom weighting
@@ -916,8 +888,8 @@ ROM_START( karnov ) /* DE-0248-3 main board, DE-259-0 sub/rom board */
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 6502 Sound CPU */
ROM_LOAD( "dn05-5.f3", 0x8000, 0x8000, CRC(fa1a31a8) SHA1(5007a625be03c546d2a78444d72c28761b10cdb0) )
- ROM_REGION( 0x1000, "mcu", 0 ) /* i8751 microcontroller */
- ROM_LOAD( "dn-e.k14", 0x0000, 0x1000, NO_DUMP ) /* DN-E or DN-6? */
+ ROM_REGION( 0x1000, "mcu", 0 ) // i8751 MCU (Note: Dump taken from a Rev 5 board)
+ ROM_LOAD( "dn-5.k14", 0x0000, 0x1000, CRC(d056de4e) SHA1(621587ed949ff46e5ccb0d0603612655a38b69a3) )
ROM_REGION( 0x08000, "gfx1", 0 )
ROM_LOAD( "dn00-.c5", 0x00000, 0x08000, CRC(0ed77c6d) SHA1(4ec86ac56c01c158a580dc13dea3e5cbdf90d0e9) ) /* Characters */
@@ -955,8 +927,8 @@ ROM_START( karnova ) /* DE-0248-3 main board, DE-259-0 sub/rom board */
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 6502 Sound CPU */
ROM_LOAD( "dn05-5.f3", 0x8000, 0x8000, CRC(fa1a31a8) SHA1(5007a625be03c546d2a78444d72c28761b10cdb0) )
- ROM_REGION( 0x1000, "mcu", 0 ) /* i8751 microcontroller */
- ROM_LOAD( "dn-5.k14", 0x0000, 0x1000, NO_DUMP )
+ ROM_REGION( 0x1000, "mcu", 0 ) // i8751 MCU
+ ROM_LOAD( "dn-5.k14", 0x0000, 0x1000, CRC(d056de4e) SHA1(621587ed949ff46e5ccb0d0603612655a38b69a3) )
ROM_REGION( 0x08000, "gfx1", 0 )
ROM_LOAD( "dn00-.c5", 0x00000, 0x08000, CRC(0ed77c6d) SHA1(4ec86ac56c01c158a580dc13dea3e5cbdf90d0e9) ) /* Characters */
@@ -994,8 +966,8 @@ ROM_START( karnovj ) /* DE-0248-3 main board, DE-259-0 sub/rom board */
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 6502 Sound CPU */
ROM_LOAD( "kar5.f3", 0x8000, 0x8000, CRC(7c9158f1) SHA1(dfba7b3abd6b8d6991f0207cd252ee652a6050c2) )
- ROM_REGION( 0x1000, "mcu", 0 ) /* i8751 microcontroller */
- ROM_LOAD( "karnovj_i8751.k14", 0x0000, 0x1000, NO_DUMP )
+ ROM_REGION( 0x1000, "mcu", 0 ) // i8751 MCU (BAD_DUMP because it was created from the US version)
+ ROM_LOAD( "karnovj_i8751.k14", 0x0000, 0x1000, BAD_DUMP CRC(5a8c4d28) SHA1(58cc912d91e569503d5a20fa3180fbdca595e39f) )
ROM_REGION( 0x08000, "gfx1", 0 )
ROM_LOAD( "dn00-.c5", 0x00000, 0x08000, CRC(0ed77c6d) SHA1(4ec86ac56c01c158a580dc13dea3e5cbdf90d0e9) ) /* Characters */
@@ -1306,42 +1278,17 @@ ROM_END
/*************************************
*
- * Driver initialization
- *
- *************************************/
-
-void karnov_state::init_karnov()
-{
- m_microcontroller_id = KARNOV;
- m_coin_mask = 0x07;
-}
-
-void karnov_state::init_karnovj()
-{
- m_microcontroller_id = KARNOVJ;
- m_coin_mask = 0x07;
-}
-
-void karnov_state::init_wndrplnt()
-{
- m_microcontroller_id = WNDRPLNT;
- m_coin_mask = 0x00;
-}
-
-
-/*************************************
- *
* Game driver(s)
*
*************************************/
-GAME( 1987, karnov, 0, karnov, karnov, karnov_state, init_karnov, ROT0, "Data East USA", "Karnov (US, rev 6)", MACHINE_SUPPORTS_SAVE )
-GAME( 1987, karnova, karnov, karnov, karnov, karnov_state, init_karnov, ROT0, "Data East USA", "Karnov (US, rev 5)", MACHINE_SUPPORTS_SAVE )
-GAME( 1987, karnovj, karnov, karnov, karnov, karnov_state, init_karnovj, ROT0, "Data East Corporation", "Karnov (Japan)", MACHINE_SUPPORTS_SAVE )
-GAME( 1987, karnovjbl, karnov, karnovjbl, karnov, karnov_state, init_karnovj, ROT0, "bootleg (K. J. Corporation)", "Karnov (Japan, bootleg with NEC D8748HD)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
-GAME( 1987, wndrplnt, 0, wndrplnt, wndrplnt, karnov_state, init_wndrplnt, ROT270, "Data East Corporation", "Wonder Planet (Japan)", MACHINE_SUPPORTS_SAVE )
-GAME( 1988, chelnov, 0, chelnov, chelnov, karnov_state, empty_init, ROT0, "Data East Corporation", "Chelnov - Atomic Runner (World)", MACHINE_SUPPORTS_SAVE )
-GAME( 1988, chelnovu, chelnov, chelnov, chelnovu, karnov_state, empty_init, ROT0, "Data East USA", "Chelnov - Atomic Runner (US)", MACHINE_SUPPORTS_SAVE )
-GAME( 1988, chelnovj, chelnov, chelnov, chelnovj, karnov_state, empty_init, ROT0, "Data East Corporation", "Chelnov - Atomic Runner (Japan)", MACHINE_SUPPORTS_SAVE )
-GAME( 1988, chelnovjbl, chelnov, chelnovjbl, chelnovjbl, karnov_state, empty_init, ROT0, "bootleg", "Chelnov - Atomic Runner (Japan, bootleg with I8031, set 1)", MACHINE_SUPPORTS_SAVE )
-GAME( 1988, chelnovjbla, chelnov, chelnovjbl, chelnovjbl, karnov_state, empty_init, ROT0, "bootleg", "Chelnov - Atomic Runner (Japan, bootleg with I8031, set 2)", MACHINE_SUPPORTS_SAVE )
+GAME( 1987, karnov, 0, karnov, karnov, karnov_state, empty_init, ROT0, "Data East USA", "Karnov (US, rev 6)", MACHINE_SUPPORTS_SAVE )
+GAME( 1987, karnova, karnov, karnov, karnov, karnov_state, empty_init, ROT0, "Data East USA", "Karnov (US, rev 5)", MACHINE_SUPPORTS_SAVE )
+GAME( 1987, karnovj, karnov, karnov, karnov, karnov_state, empty_init, ROT0, "Data East Corporation", "Karnov (Japan)", MACHINE_SUPPORTS_SAVE )
+GAME( 1987, karnovjbl, karnov, karnovjbl, karnovjbl, karnov_state, empty_init, ROT0, "bootleg (K. J. Corporation)", "Karnov (Japan, bootleg with NEC D8748HD)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+GAME( 1987, wndrplnt, 0, wndrplnt, wndrplnt, karnov_state, empty_init, ROT270, "Data East Corporation", "Wonder Planet (Japan)", MACHINE_SUPPORTS_SAVE )
+GAME( 1988, chelnov, 0, karnov, chelnov, karnov_state, empty_init, ROT0, "Data East Corporation", "Chelnov - Atomic Runner (World)", MACHINE_SUPPORTS_SAVE )
+GAME( 1988, chelnovu, chelnov, karnov, chelnovu, karnov_state, empty_init, ROT0, "Data East USA", "Chelnov - Atomic Runner (US)", MACHINE_SUPPORTS_SAVE )
+GAME( 1988, chelnovj, chelnov, karnov, chelnovj, karnov_state, empty_init, ROT0, "Data East Corporation", "Chelnov - Atomic Runner (Japan)", MACHINE_SUPPORTS_SAVE )
+GAME( 1988, chelnovjbl, chelnov, chelnovjbl, chelnovjbl, karnov_state, empty_init, ROT0, "bootleg", "Chelnov - Atomic Runner (Japan, bootleg with I8031, set 1)", MACHINE_SUPPORTS_SAVE )
+GAME( 1988, chelnovjbla, chelnov, chelnovjbl, chelnovjbl, karnov_state, empty_init, ROT0, "bootleg", "Chelnov - Atomic Runner (Japan, bootleg with I8031, set 2)", MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/kaypro.cpp b/src/mame/drivers/kaypro.cpp
index 84578280cdc..73c01b2ebb3 100644
--- a/src/mame/drivers/kaypro.cpp
+++ b/src/mame/drivers/kaypro.cpp
@@ -212,6 +212,8 @@ void kaypro_state::kayproii(machine_config &config)
m_screen->set_screen_update(FUNC(kaypro_state::screen_update_kayproii));
m_screen->set_palette(m_palette);
+ TIMER(config, m_floppy_timer).configure_generic(FUNC(kaypro_state::floppy_timer));
+
GFXDECODE(config, "gfxdecode", m_palette, gfx_kayproii);
PALETTE(config, m_palette, palette_device::MONOCHROME);
@@ -265,7 +267,7 @@ void kaypro_state::kayproii(machine_config &config)
m_fdc->set_force_ready(true);
FLOPPY_CONNECTOR(config, "fdc:0", kaypro_floppies, "525ssdd", floppy_image_device::default_floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "fdc:1", kaypro_floppies, "525ssdd", floppy_image_device::default_floppy_formats).enable_sound(true);
- SOFTWARE_LIST(config, "flop_list").set_original("kayproii");
+ SOFTWARE_LIST(config, "flop_list").set_original("kaypro").set_filter("A");
}
void kaypro_state::kayproiv(machine_config &config)
@@ -276,6 +278,7 @@ void kaypro_state::kayproiv(machine_config &config)
config.device_remove("fdc:1");
FLOPPY_CONNECTOR(config, "fdc:0", kaypro_floppies, "525dd", floppy_image_device::default_floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "fdc:1", kaypro_floppies, "525dd", floppy_image_device::default_floppy_formats).enable_sound(true);
+ SOFTWARE_LIST(config.replace(), "flop_list").set_original("kaypro").set_filter("D");
}
void kaypro_state::omni2(machine_config &config)
@@ -300,6 +303,8 @@ void kaypro_state::kaypro484(machine_config &config)
m_screen->set_visarea(0,80*8-1,0,25*16-1);
m_screen->set_screen_update(FUNC(kaypro_state::screen_update_kaypro484));
+ TIMER(config, m_floppy_timer).configure_generic(FUNC(kaypro_state::floppy_timer));
+
GFXDECODE(config, "gfxdecode", m_palette, gfx_kaypro484);
PALETTE(config, m_palette, FUNC(kaypro_state::kaypro_palette), 3);
@@ -362,7 +367,19 @@ void kaypro_state::kaypro484(machine_config &config)
m_fdc->set_force_ready(true);
FLOPPY_CONNECTOR(config, "fdc:0", kaypro_floppies, "525dd", floppy_image_device::default_floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "fdc:1", kaypro_floppies, "525dd", floppy_image_device::default_floppy_formats).enable_sound(true);
- SOFTWARE_LIST(config, "flop_list").set_original("kaypro484");
+ SOFTWARE_LIST(config, "flop_list").set_original("kaypro").set_filter("C");
+}
+
+void kaypro_state::kaypro4x(machine_config &config)
+{
+ kaypro484(config);
+ SOFTWARE_LIST(config.replace(), "flop_list").set_original("kaypro").set_filter("F");
+}
+
+void kaypro_state::kaypro1(machine_config &config)
+{
+ kaypro484(config);
+ SOFTWARE_LIST(config.replace(), "flop_list").set_original("kaypro").set_filter("G");
}
void kaypro_state::kaypro10(machine_config &config)
@@ -370,12 +387,14 @@ void kaypro_state::kaypro10(machine_config &config)
kaypro484(config);
config.device_remove("fdc:1"); // only has 1 floppy drive
// need to add hard drive & controller
+ SOFTWARE_LIST(config.replace(), "flop_list").set_original("kaypro").set_filter("E");
}
void kaypro_state::kaypronew2(machine_config &config)
{
kaypro484(config);
config.device_remove("fdc:1"); // only has 1 floppy drive
+ SOFTWARE_LIST(config.replace(), "flop_list").set_original("kaypro").set_filter("G");
}
void kaypro_state::kaypro284(machine_config &config)
@@ -385,6 +404,7 @@ void kaypro_state::kaypro284(machine_config &config)
config.device_remove("fdc:1");
FLOPPY_CONNECTOR(config, "fdc:0", kaypro_floppies, "525ssdd", floppy_image_device::default_floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, "fdc:1", kaypro_floppies, "525ssdd", floppy_image_device::default_floppy_formats).enable_sound(true);
+ SOFTWARE_LIST(config.replace(), "flop_list").set_original("kaypro").set_filter("B");
}
void kaypro_state::init_kaypro()
@@ -647,18 +667,18 @@ ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
-COMP( 1982, kayproii, 0, 0, kayproii, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro II - 2/83" , MACHINE_SUPPORTS_SAVE )
-COMP( 1983, kayproiv, kayproii, 0, kayproiv, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro IV - 4/83" , MACHINE_SUPPORTS_SAVE ) // model 81-004
+COMP( 1982, kayproii, 0, 0, kayproii, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro II - 2/83", MACHINE_SUPPORTS_SAVE )
+COMP( 1983, kayproiv, kayproii, 0, kayproiv, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro IV - 4/83", MACHINE_SUPPORTS_SAVE ) // model 81-004
COMP( 1983, kaypro10, 0, 0, kaypro10, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 10 - 1983", MACHINE_SUPPORTS_SAVE )
COMP( 1983, kayproiip88, kayproii, 0, kayproii, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 4 plus88 - 4/83" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-004 with an added 8088 daughterboard and rom
-COMP( 1984, kaypro484, 0, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 4/84" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-015
-COMP( 1984, kaypro284, kaypro484, 0, kaypro284, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 2/84" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-015
+COMP( 1984, kaypro484, 0, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 4/84", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-015
+COMP( 1984, kaypro284, kaypro484, 0, kaypro284, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 2/84", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-015
COMP( 1984, kaypro484p88, kaypro484, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 4/84 plus88", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-015 with an added 8088 daughterboard and rom
-COMP( 1984, kaypro1084, kaypro10, 0, kaypro10, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 10" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-005
-COMP( 1984, robie, 0, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro Robie" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
-COMP( 1985, kaypro2x, kaypro484, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 2x" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-025
+COMP( 1984, kaypro1084, kaypro10, 0, kaypro10, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 10", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // model 81-005
+COMP( 1984, robie, 0, 0, kaypro4x, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro Robie", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+COMP( 1985, kaypro2x, kaypro484, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 2x", MACHINE_SUPPORTS_SAVE ) // model 81-025
COMP( 1985, kaypronew2, 0, 0, kaypronew2, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro New 2", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
-COMP( 1985, kaypro4x, robie, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 4x" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
-COMP( 1986, kaypro1, kaypro484, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 1", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
-COMP( 198?, omni2, kayproii, 0, omni2, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Omni II Logic Analyzer" , MACHINE_SUPPORTS_SAVE )
-COMP( 198?, omni4, kaypro484, 0, kaypro484, kaypro, kaypro_state, init_kaypro, "Omni Logic Inc.", "Omni 4 Logic Analyzer" , MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+COMP( 1985, kaypro4x, robie, 0, kaypro4x, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 4x", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+COMP( 1986, kaypro1, kaypro484, 0, kaypro1, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Kaypro 1", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+COMP( 198?, omni2, kayproii, 0, omni2, kaypro, kaypro_state, init_kaypro, "Non Linear Systems", "Omni II Logic Analyzer", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+COMP( 198?, omni4, kaypro484, 0, kaypro1, kaypro, kaypro_state, init_kaypro, "Omni Logic Inc.", "Omni 4 Logic Analyzer", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
diff --git a/src/mame/drivers/kdt6.cpp b/src/mame/drivers/kdt6.cpp
index abd0ff77dfd..5cb6a5b28cb 100644
--- a/src/mame/drivers/kdt6.cpp
+++ b/src/mame/drivers/kdt6.cpp
@@ -297,7 +297,7 @@ uint32_t kdt6_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
MC6845_UPDATE_ROW( kdt6_state::crtc_update_row )
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
for (int i = 0; i < x_count; i++)
{
@@ -314,7 +314,7 @@ MC6845_UPDATE_ROW( kdt6_state::crtc_update_row )
for (int x = 0; x < 8; x++)
{
int color = BIT(data, 7 - x);
- bitmap.pix32(y, x + i*8) = pen[blink ? 0 : (color ^ inverse)];
+ bitmap.pix(y, x + i*8) = pen[blink ? 0 : (color ^ inverse)];
}
}
else
@@ -324,7 +324,7 @@ MC6845_UPDATE_ROW( kdt6_state::crtc_update_row )
// draw 8 pixels of the cell
for (int x = 0; x < 8; x++)
- bitmap.pix32(y, x + i*8) = pen[BIT(data, 7 - x)];
+ bitmap.pix(y, x + i*8) = pen[BIT(data, 7 - x)];
}
}
}
diff --git a/src/mame/drivers/kim1.cpp b/src/mame/drivers/kim1.cpp
index 06f481378b6..2eb52f01287 100644
--- a/src/mame/drivers/kim1.cpp
+++ b/src/mame/drivers/kim1.cpp
@@ -56,6 +56,11 @@ TODO:
- hook up Single Step dip switch
- slots for expansion & application ports
- add TTY support
+
+Paste test:
+ N-0100=11^22^33^44^55^66^77^88^99^-0100=
+ Press UP to verify data.
+
******************************************************************************/
#include "emu.h"
@@ -175,14 +180,14 @@ static INPUT_PORTS_START( kim1 )
PORT_BIT( 0x20, 0x20, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
PORT_BIT( 0x10, 0x10, IPT_KEYBOARD ) PORT_NAME("AD") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CODE(KEYCODE_MINUS_PAD)
PORT_BIT( 0x08, 0x08, IPT_KEYBOARD ) PORT_NAME("DA") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=')
- PORT_BIT( 0x04, 0x04, IPT_KEYBOARD ) PORT_NAME("+") PORT_CODE(KEYCODE_UP) PORT_CHAR(' ') PORT_CODE(KEYCODE_PLUS_PAD)
- PORT_BIT( 0x02, 0x02, IPT_KEYBOARD ) PORT_NAME("GO") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_CODE(KEYCODE_ENTER_PAD)
+ PORT_BIT( 0x04, 0x04, IPT_KEYBOARD ) PORT_NAME("+") PORT_CODE(KEYCODE_UP) PORT_CHAR('^') PORT_CODE(KEYCODE_PLUS_PAD)
+ PORT_BIT( 0x02, 0x02, IPT_KEYBOARD ) PORT_NAME("GO") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('X') PORT_CODE(KEYCODE_ENTER_PAD)
PORT_BIT( 0x01, 0x01, IPT_KEYBOARD ) PORT_NAME("PC") PORT_CODE(KEYCODE_F6)
PORT_START("SPECIAL")
PORT_BIT( 0x80, 0x00, IPT_UNUSED )
- PORT_BIT( 0x40, 0x40, IPT_KEYBOARD ) PORT_NAME("sw1: ST") PORT_CODE(KEYCODE_F7) PORT_CHANGED_MEMBER(DEVICE_SELF, kim1_state, trigger_nmi, 0)
- PORT_BIT( 0x20, 0x20, IPT_KEYBOARD ) PORT_NAME("sw2: RS") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, kim1_state, trigger_reset, 0)
+ PORT_BIT( 0x40, 0x40, IPT_KEYBOARD ) PORT_NAME("sw1: ST") PORT_CODE(KEYCODE_F7) PORT_CHANGED_MEMBER(DEVICE_SELF, kim1_state, trigger_nmi, 0) PORT_CHAR('S')
+ PORT_BIT( 0x20, 0x20, IPT_KEYBOARD ) PORT_NAME("sw2: RS") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, kim1_state, trigger_reset, 0) PORT_CHAR('N')
PORT_DIPNAME(0x10, 0x10, "sw3: SS") PORT_CODE(KEYCODE_NUMLOCK) PORT_TOGGLE
PORT_DIPSETTING( 0x00, "single step")
PORT_DIPSETTING( 0x10, "run")
diff --git a/src/mame/drivers/kinst.cpp b/src/mame/drivers/kinst.cpp
index bb9ed493ac3..a27fafc0d88 100644
--- a/src/mame/drivers/kinst.cpp
+++ b/src/mame/drivers/kinst.cpp
@@ -317,18 +317,18 @@ void kinst_state::machine_reset()
uint32_t kinst_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- const pen_t *pen = m_palette->pens();
+ pen_t const *const pen = m_palette->pens();
/* loop over rows and copy to the destination */
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
- uint32_t *src = &m_video_base[640/4 * y];
- uint32_t *dest = &bitmap.pix32(y, cliprect.min_x);
+ uint32_t const *src = &m_video_base[640/4 * y];
+ uint32_t *dest = &bitmap.pix(y, cliprect.min_x);
/* loop over columns */
for (int x = cliprect.min_x; x < cliprect.max_x; x += 2)
{
- uint32_t data = *src++;
+ uint32_t const data = *src++;
/* store two pixels */
*dest++ = pen[(data >> 0) & 0x7fff];
diff --git a/src/mame/drivers/konamigs.cpp b/src/mame/drivers/konamigs.cpp
index 23c307b78ac..a0afaef7075 100644
--- a/src/mame/drivers/konamigs.cpp
+++ b/src/mame/drivers/konamigs.cpp
@@ -746,7 +746,7 @@ u32 gsan_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const
if (!m_bg16bit)
col = get_color(col);
}
- bitmap.pix32(y, x) = pal565(col, 11, 5, 0);
+ bitmap.pix(y, x) = pal565(col, 11, 5, 0);
}
}
else
diff --git a/src/mame/drivers/konamigv.cpp b/src/mame/drivers/konamigv.cpp
index 650631c4fd8..36764c0063b 100644
--- a/src/mame/drivers/konamigv.cpp
+++ b/src/mame/drivers/konamigv.cpp
@@ -391,13 +391,13 @@ void konamigv_state::konamigv(machine_config &config)
static INPUT_PORTS_START( konamigv )
PORT_START("P1")
- PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
- PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY
- PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY
- PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY
- PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 )
- PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 )
- PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 )
+ PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(1)
+ PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_START1 )
@@ -677,19 +677,42 @@ INPUT_PORTS_END
static INPUT_PORTS_START( weddingr )
PORT_INCLUDE( konamigv )
+ // Control Type must match selection in service mode (no sense line to detect control panel type)
+ // Buttons 2 and 3 are shown in service mode, but not used by the game
+ // Button 1-3 inputs are read in service mode even when 4 Buttons is selected, but they could confuse users
+
+ PORT_START("CFG")
+ PORT_CONFNAME( 0x01, 0x01, "Control Type" )
+ PORT_CONFSETTING( 0x01, "4 Buttons" )
+ PORT_CONFSETTING( 0x00, "Joystick and Button" )
+
PORT_MODIFY("P1")
- PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("Answer 3/Zoom In")
- PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("Answer 4/Zoom Out")
- PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("Answer 1/Pan Left")
- PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("Answer 2/Pan Right")
- PORT_BIT( 0x00000070, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 Answer 3/Zoom In") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("P1 Answer 4/Zoom Out") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 Answer 1/Pan Left") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 Answer 2/Pan Right") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000070, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
PORT_MODIFY("P2")
- PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("Answer 3/Zoom In")
- PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("Answer 4/Zoom Out")
- PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("Answer 1/Pan Left")
- PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("Answer 2/Pan Right")
- PORT_BIT( 0x00000070, IP_ACTIVE_LOW, IPT_UNKNOWN )
+ PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 Answer 3/Zoom In") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("P2 Answer 4/Zoom Out") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 Answer 1/Pan Left") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("P2 Answer 2/Pan Right") PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000070, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_CONDITION("CFG", 0x01, EQUALS, 0x01)
+ PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_UP) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
+ PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_CONDITION("CFG", 0x01, EQUALS, 0x00)
PORT_MODIFY("P3_P4")
PORT_BIT( 0x0000ffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
diff --git a/src/mame/drivers/konmedal68k.cpp b/src/mame/drivers/konmedal68k.cpp
index 02ce8da8538..862d6693ad3 100644
--- a/src/mame/drivers/konmedal68k.cpp
+++ b/src/mame/drivers/konmedal68k.cpp
@@ -152,8 +152,8 @@ void konmedal68k_state::fill_backcolor(bitmap_ind16 &bitmap, const rectangle &cl
}
else
{
- uint16_t *dst_ptr = &bitmap.pix16(cliprect.min_y);
- int dst_pitch = bitmap.rowpixels();
+ uint16_t *dst_ptr = &bitmap.pix(cliprect.min_y);
+ int const dst_pitch = bitmap.rowpixels();
if ((mode & 0x01) == 0) // vertical gradient fill
{
@@ -173,7 +173,7 @@ void konmedal68k_state::fill_backcolor(bitmap_ind16 &bitmap, const rectangle &cl
{
pen_idx += cliprect.min_x;
dst_ptr += cliprect.min_x;
- for(int y = cliprect.min_y; y<= cliprect.max_y; y++)
+ for (int y = cliprect.min_y; y<= cliprect.max_y; y++)
{
for(int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
@@ -500,8 +500,8 @@ ROM_END
GAME( 1995, kzaurus, 0, kzaurus, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Pittanko Zaurus", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1996, dobouchn, 0, kzaurus, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Dobou-Chan (ver JAA)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
-GAME( 199?, konslot, 0, slot, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Unknown Konami slot medal game (set 1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
-GAME( 199?, konslot2, 0, slot, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Unknown Konami slot medal game (set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
+GAME( 199?, konslot, 0, slot, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "unknown Konami slot medal game (set 1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
+GAME( 199?, konslot2, 0, slot, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "unknown Konami slot medal game (set 2)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
GAME( 1997, koropens, 0, koropens, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Korokoro Pensuke", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1998, kattobas, 0, koropens, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Kattobase Power Pro Kun", MACHINE_IMPERFECT_GRAPHICS )
GAME( 1999, pwrchanc, 0, koropens, kzaurus, konmedal68k_state, empty_init, ROT0, "Konami", "Powerful Chance", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
diff --git a/src/mame/drivers/kontest.cpp b/src/mame/drivers/kontest.cpp
index 921ced6509f..c63d32404f4 100644
--- a/src/mame/drivers/kontest.cpp
+++ b/src/mame/drivers/kontest.cpp
@@ -106,29 +106,20 @@ void kontest_state::video_start()
uint32_t kontest_state::screen_update( screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect )
{
- int x,y;
- int xi,yi;
- uint16_t tile;
- uint8_t attr;
-
- for(y=0;y<32;y++)
+ for(int y=0;y<32;y++)
{
- for(x=0;x<64;x++)
+ for(int x=0;x<64;x++)
{
- tile = m_ram[(x+y*64)|0x800];
- attr = m_ram[(x+((y >> 1)*64))|0x000] & 7;
- tile *= 0x10;
- tile += 0x1000;
+ uint16_t const tile = (m_ram[(x+y*64)|0x800] * 0x10) + 0x1000;
+ uint8_t const attr = m_ram[(x+((y >> 1)*64))|0x000] & 7;
- for(yi=0;yi<8;yi++)
+ for(int yi=0;yi<8;yi++)
{
- for(xi=0;xi<8;xi++)
+ for(int xi=0;xi<8;xi++)
{
uint8_t color,pen[2];
- uint8_t x_step;
- int res_x,res_y;
- x_step = xi >> 2;
+ uint8_t const x_step = xi >> 2;
pen[0] = m_ram[(x_step+yi*2)|(tile)];
pen[0] >>= 3-((xi & 3));
@@ -140,11 +131,11 @@ uint32_t kontest_state::screen_update( screen_device &screen, bitmap_rgb32 &bitm
color = pen[0];
color|= pen[1]<<1;
- res_x = x*8+xi-256;
- res_y = y*8+yi;
+ int const res_x = x*8+xi-256;
+ int const res_y = y*8+yi;
if (cliprect.contains(res_x, res_y))
- bitmap.pix32(res_y, res_x) = m_palette->pen(color|attr*4);
+ bitmap.pix(res_y, res_x) = m_palette->pen(color|attr*4);
}
}
}
diff --git a/src/mame/drivers/korgds8.cpp b/src/mame/drivers/korgds8.cpp
index f6d80b7b8d2..18fedea0b89 100644
--- a/src/mame/drivers/korgds8.cpp
+++ b/src/mame/drivers/korgds8.cpp
@@ -72,13 +72,13 @@ void korg_ds8_state::machine_start()
HD44780_PIXEL_UPDATE(korg_ds8_state::lcd_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 40)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
HD44780_PIXEL_UPDATE(korg_ds8_state::korg707_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 20)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
u8 korg_ds8_state::kbd_sw_r()
diff --git a/src/mame/drivers/korgdss1.cpp b/src/mame/drivers/korgdss1.cpp
index eb6da9b2efe..317137c4a23 100644
--- a/src/mame/drivers/korgdss1.cpp
+++ b/src/mame/drivers/korgdss1.cpp
@@ -72,7 +72,6 @@ private:
void bank_switch_w(u8 data);
void panel_led_w(u8 data);
- DECLARE_WRITE_LINE_MEMBER(fdc_reset_w);
DECLARE_WRITE_LINE_MEMBER(fdc_tc_w);
DECLARE_WRITE_LINE_MEMBER(sed9420c_trgin_w);
u8 fdc_r(offs_t offset);
@@ -141,7 +140,7 @@ void korg_dss1_state::machine_reset()
HD44780_PIXEL_UPDATE(korg_dss1_state::lcd_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 20)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
@@ -156,12 +155,6 @@ void korg_dss1_state::panel_led_w(u8 data)
// TODO
}
-WRITE_LINE_MEMBER(korg_dss1_state::fdc_reset_w)
-{
- if (!state)
- m_fdc->soft_reset();
-}
-
WRITE_LINE_MEMBER(korg_dss1_state::fdc_tc_w)
{
if (m_cpu1.found())
@@ -444,7 +437,7 @@ void korg_dss1_state::klm780(machine_config &config)
m_io1->out_pc_callback().set(m_lcdc, FUNC(hd44780_device::e_w)).bit(0);
m_io1->out_pc_callback().append(m_lcdc, FUNC(hd44780_device::rw_w)).bit(1);
m_io1->out_pc_callback().append(m_lcdc, FUNC(hd44780_device::rs_w)).bit(2);
- m_io1->out_pc_callback().append(FUNC(korg_dss1_state::fdc_reset_w)).bit(3);
+ m_io1->out_pc_callback().append(m_fdc, FUNC(upd765a_device::reset_w)).bit(3).invert();
m_io1->out_pc_callback().append(FUNC(korg_dss1_state::fdc_tc_w)).bit(4);
m_io1->out_pc_callback().append(FUNC(korg_dss1_state::sed9420c_trgin_w)).bit(5);
diff --git a/src/mame/drivers/korgm1.cpp b/src/mame/drivers/korgm1.cpp
index c7fdc20825b..62e8d1dc1c0 100644
--- a/src/mame/drivers/korgm1.cpp
+++ b/src/mame/drivers/korgm1.cpp
@@ -66,7 +66,7 @@ void korgm1_state::video_start()
HD44780_PIXEL_UPDATE(korgm1_state::lcd_pixel_update)
{
if (x < 5 && y < 8 && line < 2 && pos < 40)
- bitmap.pix16(line * 8 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 8 + y, pos * 6 + x) = state;
}
void korgm1_state::pio_pa_w(u8 data)
diff --git a/src/mame/drivers/krokha.cpp b/src/mame/drivers/krokha.cpp
index 10140b2755c..399f29c69a3 100644
--- a/src/mame/drivers/krokha.cpp
+++ b/src/mame/drivers/krokha.cpp
@@ -116,22 +116,19 @@ void krokha_state::machine_reset()
uint32_t krokha_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y, ra, gfx;
- uint16_t chr, ma = 0, x = 0;
-
- for (y = 0; y < 32; y++)
+ for (uint8_t y = 0; y < 32; y++)
{
- ma = 0xe0 + y;
- for (ra = 0; ra < 8; ra++)
+ uint16_t ma = 0xe0 + y;
+ for (uint8_t ra = 0; ra < 8; ra++)
{
- for (x = ma; x < ma + 64*32; x += 32)
+ for (uint16_t x = ma; x < ma + 64*32; x += 32)
{
- chr = m_p_videoram[x] << 3;
- gfx = m_p_chargen[chr | ra];
+ uint16_t chr = m_p_videoram[x] << 3;
+ uint8_t gfx = m_p_chargen[chr | ra];
for (int i = 0; i < 8; i++)
{
- bitmap.pix16(y * 8 + ra, (x - ma) / 4 + i) = BIT(gfx, 7 - i);
+ bitmap.pix(y * 8 + ra, (x - ma) / 4 + i) = BIT(gfx, 7 - i);
}
}
}
diff --git a/src/mame/drivers/kron.cpp b/src/mame/drivers/kron.cpp
index 34f2804fdf7..bb9cd9dc0d3 100644
--- a/src/mame/drivers/kron.cpp
+++ b/src/mame/drivers/kron.cpp
@@ -224,30 +224,26 @@ INPUT_PORTS_END
/* Video TODO: find and understand the char table within main rom */
uint32_t kron180_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x, y;
- int vramad;
- uint8_t *chardata;
- uint8_t charcode;
-
LOGSCREEN("%s()\n", FUNCNAME);
- vramad = 0;
+ int vramad = 0;
for (int row = 0; row < 25 * 8; row += 8)
{
+ uint8_t charcode;
for (int col = 0; col < 80 * 8; col += 8)
{
/* look up the character data */
charcode = m_vram[vramad];
if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN("\n %c at X=%d Y=%d: ", charcode, col, row);
- chardata = &m_chargen[(charcode * 8) + 8];
+ uint8_t const *chardata = &m_chargen[(charcode * 8) + 8];
/* plot the character */
- for (y = 0; y < 8; y++)
+ for (int y = 0; y < 8; y++)
{
chardata--;
if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN("\n %02x: ", *chardata);
- for (x = 0; x < 8; x++)
+ for (int x = 0; x < 8; x++)
{
if (VERBOSE && charcode != 0x20 && charcode != 0) LOGSCREEN(" %02x: ", *chardata);
- bitmap.pix16(row + (8 - y), col + (8 - x)) = (*chardata & (1 << x)) ? 1 : 0;
+ bitmap.pix(row + (8 - y), col + (8 - x)) = (*chardata & (1 << x)) ? 1 : 0;
}
}
vramad += 2;
diff --git a/src/mame/drivers/laser3k.cpp b/src/mame/drivers/laser3k.cpp
index 9c3e20e49cf..f17caa47a11 100644
--- a/src/mame/drivers/laser3k.cpp
+++ b/src/mame/drivers/laser3k.cpp
@@ -496,32 +496,28 @@ uint8_t laser3k_state::io2_r(offs_t offset)
void laser3k_state::plot_text_character(bitmap_ind16 &bitmap, int xpos, int ypos, int xscale, uint32_t code,
const uint8_t *textgfx_data, uint32_t textgfx_datalen)
{
- int x, y, i;
int fg = m_fg_color;
int bg = m_bg_color;
- const uint8_t *chardata;
- uint16_t color;
/* look up the character data */
- chardata = &textgfx_data[(code * 8) % textgfx_datalen];
+ uint8_t const *const chardata = &textgfx_data[(code * 8) % textgfx_datalen];
if (m_flash && (code >= 0x40) && (code <= 0x7f))
{
/* we're flashing; swap */
- i = fg;
- fg = bg;
- bg = i;
+ using std::swap;
+ swap(fg, bg);
}
- for (y = 0; y < 8; y++)
+ for (int y = 0; y < 8; y++)
{
- for (x = 0; x < 7; x++)
+ for (int x = 0; x < 7; x++)
{
- color = (chardata[y] & (1 << (6-x))) ? fg : bg;
+ uint16_t color = (chardata[y] & (1 << (6-x))) ? fg : bg;
- for (i = 0; i < xscale; i++)
+ for (int i = 0; i < xscale; i++)
{
- bitmap.pix16(ypos + y, xpos + (x * xscale) + i) = color;
+ bitmap.pix(ypos + y, xpos + (x * xscale) + i) = color;
}
}
}
@@ -578,15 +574,6 @@ void laser3k_state::text_update(screen_device &screen, bitmap_ind16 &bitmap, con
void laser3k_state::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow)
{
- const uint8_t *vram;
- int row, col, b;
- int offset;
- uint8_t vram_row[42] ;
- uint16_t v;
- uint16_t *p;
- uint32_t w;
- uint16_t *artifact_map_ptr;
-
/* sanity checks */
if (beginrow < cliprect.min_y)
beginrow = cliprect.min_y;
@@ -595,31 +582,32 @@ void laser3k_state::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, cons
if (endrow < beginrow)
return;
- vram = m_ram->pointer() + (m_disp_page ? 0x4000 : 0x2000);
+ uint8_t const *const vram = m_ram->pointer() + (m_disp_page ? 0x4000 : 0x2000);
+ uint8_t vram_row[42];
vram_row[0] = 0;
vram_row[41] = 0;
- for (row = beginrow; row <= endrow; row++)
+ for (int row = beginrow; row <= endrow; row++)
{
- for (col = 0; col < 40; col++)
+ for (int col = 0; col < 40; col++)
{
- offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10);
+ int offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10);
vram_row[1+col] = vram[offset];
}
- p = &bitmap.pix16(row);
+ uint16_t *p = &bitmap.pix(row);
- for (col = 0; col < 40; col++)
+ for (int col = 0; col < 40; col++)
{
- w = (((uint32_t) vram_row[col+0] & 0x7f) << 0)
- | (((uint32_t) vram_row[col+1] & 0x7f) << 7)
- | (((uint32_t) vram_row[col+2] & 0x7f) << 14);
+ uint32_t w = (((uint32_t) vram_row[col+0] & 0x7f) << 0)
+ | (((uint32_t) vram_row[col+1] & 0x7f) << 7)
+ | (((uint32_t) vram_row[col+2] & 0x7f) << 14);
- artifact_map_ptr = &m_hires_artifact_map[((vram_row[col+1] & 0x80) >> 7) * 16];
- for (b = 0; b < 7; b++)
+ uint16_t const *const artifact_map_ptr = &m_hires_artifact_map[((vram_row[col+1] & 0x80) >> 7) * 16];
+ for (int b = 0; b < 7; b++)
{
- v = artifact_map_ptr[((w >> (b + 7-1)) & 0x07) | (((b ^ col) & 0x01) << 3)];
+ uint16_t v = artifact_map_ptr[((w >> (b + 7-1)) & 0x07) | (((b ^ col) & 0x01) << 3)];
*(p++) = v;
*(p++) = v;
}
@@ -629,14 +617,6 @@ void laser3k_state::hgr_update(screen_device &screen, bitmap_ind16 &bitmap, cons
void laser3k_state::dhgr_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int beginrow, int endrow)
{
- const uint8_t *vram;
- int row, col, b;
- int offset;
- uint8_t vram_row[82];
- uint16_t v;
- uint16_t *p;
- uint32_t w;
-
/* sanity checks */
if (beginrow < cliprect.min_y)
beginrow = cliprect.min_y;
@@ -645,16 +625,17 @@ void laser3k_state::dhgr_update(screen_device &screen, bitmap_ind16 &bitmap, con
if (endrow < beginrow)
return;
- vram = m_ram->pointer() + (m_disp_page ? 0x8000 : 0x4000);
+ uint8_t const *const vram = m_ram->pointer() + (m_disp_page ? 0x8000 : 0x4000);
+ uint8_t vram_row[82];
vram_row[0] = 0;
vram_row[81] = 0;
- for (row = beginrow; row <= endrow; row++)
+ for (int row = beginrow; row <= endrow; row++)
{
- for (col = 0; col < 40; col++)
+ for (int col = 0; col < 40; col++)
{
- offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10);
+ int offset = ((((row/8) & 0x07) << 7) | (((row/8) & 0x18) * 5 + col)) | ((row & 7) << 10);
if (col < 40)
{
vram_row[1+(col*2)+0] = vram[offset];
@@ -667,17 +648,17 @@ void laser3k_state::dhgr_update(screen_device &screen, bitmap_ind16 &bitmap, con
}
}
- p = &bitmap.pix16(row);
+ uint16_t *p = &bitmap.pix(row);
- for (col = 0; col < 80; col++)
+ for (int col = 0; col < 80; col++)
{
- w = (((uint32_t) vram_row[col+0] & 0x7f) << 0)
- | (((uint32_t) vram_row[col+1] & 0x7f) << 7)
- | (((uint32_t) vram_row[col+2] & 0x7f) << 14);
+ uint32_t w = (((uint32_t) vram_row[col+0] & 0x7f) << 0)
+ | (((uint32_t) vram_row[col+1] & 0x7f) << 7)
+ | (((uint32_t) vram_row[col+2] & 0x7f) << 14);
- for (b = 0; b < 7; b++)
+ for (int b = 0; b < 7; b++)
{
- v = m_dhires_artifact_map[((((w >> (b + 7-1)) & 0x0F) * 0x11) >> (((2-(col*7+b))) & 0x03)) & 0x0F];
+ uint16_t v = m_dhires_artifact_map[((((w >> (b + 7-1)) & 0x0F) * 0x11) >> (((2-(col*7+b))) & 0x03)) & 0x0F];
*(p++) = v;
}
}
@@ -830,10 +811,10 @@ static INPUT_PORTS_START( laser3k )
PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
- PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
- PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
- PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
- PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
@@ -859,8 +840,8 @@ static INPUT_PORTS_START( laser3k )
PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHAR('k')
PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('l')
PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
- PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT)
- PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_START("X3")
PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z')
@@ -876,7 +857,7 @@ static INPUT_PORTS_START( laser3k )
PORT_START("X4")
PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHAR('s')
- PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('\"')
+ PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a')
@@ -937,7 +918,7 @@ static INPUT_PORTS_START( laser3k )
PORT_START("keyb_special")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT)
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED)
diff --git a/src/mame/drivers/laserbas.cpp b/src/mame/drivers/laserbas.cpp
index 10a009326dd..8412283fcac 100644
--- a/src/mame/drivers/laserbas.cpp
+++ b/src/mame/drivers/laserbas.cpp
@@ -150,8 +150,8 @@ MC6845_UPDATE_ROW( laserbas_state::crtc_update_row )
}
int pixaddr = y << 8;
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint32_t *b = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ uint32_t *const b = &bitmap.pix(y);
while (x != x_max)
{
diff --git a/src/mame/drivers/lastfght.cpp b/src/mame/drivers/lastfght.cpp
index 81b4a5a40e3..fd7749a3502 100644
--- a/src/mame/drivers/lastfght.cpp
+++ b/src/mame/drivers/lastfght.cpp
@@ -165,9 +165,7 @@ uint32_t lastfght_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
#ifdef MAME_DEBUG
#if 1
// gfx roms viewer (toggle with enter, use pgup/down to browse)
- int x, y, count = 0;
- uint8_t *gfxdata = memregion("gfx1")->base();
- uint8_t data;
+ uint8_t const *const gfxdata = memregion("gfx1")->base();
if (machine().input().code_pressed_once(KEYCODE_ENTER)) m_view_roms ^= 1;
if (m_view_roms)
@@ -176,15 +174,15 @@ uint32_t lastfght_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
if (machine().input().code_pressed_once(KEYCODE_PGUP)) m_base -= 512 * 256;
m_base %= memregion("gfx1")->bytes();
- count = m_base;
+ int count = m_base;
bitmap.fill(m_palette->black_pen(), cliprect );
- for (y = 0 ; y < 256; y++)
+ for (int y = 0 ; y < 256; y++)
{
- for (x = 0; x < 512; x++)
+ for (int x = 0; x < 512; x++)
{
- data = (((count & 0xf) == 0) && ((count & 0x1e00) == 0)) ? m_palette->white_pen() : gfxdata[count]; // white grid or data
- bitmap.pix16(y, x) = data;
+ uint8_t data = (((count & 0xf) == 0) && ((count & 0x1e00) == 0)) ? m_palette->white_pen() : gfxdata[count]; // white grid or data
+ bitmap.pix(y, x) = data;
count++;
}
}
@@ -317,7 +315,6 @@ void lastfght_state::blit_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if (ACCESSING_BITS_8_15)
{
- int x, y, addr;
uint8_t *gfxdata = memregion( "gfx1" )->base();
bitmap_ind16 &dest = m_bitmap[m_dest];
@@ -330,18 +327,18 @@ void lastfght_state::blit_w(offs_t offset, uint16_t data, uint16_t mem_mask)
data >> 8);
#endif
- for (y = 0; y <= m_h; y++)
+ for (int y = 0; y <= m_h; y++)
{
- for (x = 0; x <= m_w; x++)
+ for (int x = 0; x <= m_w; x++)
{
- addr = (((m_sx + m_sx1 + m_dsx * x) >> 6) & 0x1ff) +
+ int addr = (((m_sx + m_sx1 + m_dsx * x) >> 6) & 0x1ff) +
(((m_sy + m_sy1 + m_dsy * y) >> 6) & 0xff) * 0x200 +
m_sp * 0x200 * 0x100 + m_sr * 0x200000;
data = gfxdata[addr];
if (data && (m_x + x >= 0) && (m_x + x < 512) && (m_y + y >= 0) && (m_y + y < 256))
- dest.pix16(m_y + y, m_x + x) = data;
+ dest.pix(m_y + y, m_x + x) = data;
}
}
}
diff --git a/src/mame/drivers/lbeach.cpp b/src/mame/drivers/lbeach.cpp
index a2f77a19d7b..94c44d0f39b 100644
--- a/src/mame/drivers/lbeach.cpp
+++ b/src/mame/drivers/lbeach.cpp
@@ -189,8 +189,8 @@ u32 lbeach_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, con
{
for (int x = sprite_x; x < (sprite_x + 16) && cliprect.contains(x, y); x++)
{
- m_collision_bg_car |= (bitmap.pix16(y, x) & m_colmap_car.pix16(y, x) & 1);
- m_collision_fg_car |= (fg_bitmap.pix16(y, x) & m_colmap_car.pix16(y, x) & 1);
+ m_collision_bg_car |= (bitmap.pix(y, x) & m_colmap_car.pix(y, x) & 1);
+ m_collision_fg_car |= (fg_bitmap.pix(y, x) & m_colmap_car.pix(y, x) & 1);
}
}
diff --git a/src/mame/drivers/lcmate2.cpp b/src/mame/drivers/lcmate2.cpp
index 4c687df074c..f4a64bf1c4b 100644
--- a/src/mame/drivers/lcmate2.cpp
+++ b/src/mame/drivers/lcmate2.cpp
@@ -118,12 +118,14 @@ void lcmate2_state::io_map(address_map &map)
}
/* Input ports */
+// Alternate keyboard layout exists. Different keys are 7& `~ ? +/ ,< .> ON/RESET, with removal of Numlock and [{ ]}
+// Machine starts up with capslock on - turn it off to access lowercase. Natural keyboard - use End key.
static INPUT_PORTS_START( lcmate2 )
PORT_START("LINE0")
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("UP") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
- PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC),27)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
@@ -132,7 +134,8 @@ static INPUT_PORTS_START( lcmate2 )
PORT_START("LINE1")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('/')
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CAPSLOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ // Natural keyboard: UCHAR_MAMEKEY(CAPSLOCK) does not disengage capslock on the emulated machine, so using END instead
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("CAPSLOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(END))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
@@ -161,7 +164,7 @@ static INPUT_PORTS_START( lcmate2 )
PORT_START("LINE4")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("'") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"')
- PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("BACKSPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(DEL))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(DEL),8)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
@@ -172,7 +175,7 @@ static INPUT_PORTS_START( lcmate2 )
PORT_START("LINE5")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("LEFT") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
@@ -182,7 +185,7 @@ static INPUT_PORTS_START( lcmate2 )
PORT_START("LINE6")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("RIGHT") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
@@ -192,7 +195,7 @@ static INPUT_PORTS_START( lcmate2 )
PORT_START("LINE7")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("NUMLOck") PORT_CODE(KEYCODE_NUMLOCK) PORT_CHAR(UCHAR_MAMEKEY(NUMLOCK))
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
- PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("DOWN") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
diff --git a/src/mame/drivers/lft_craft.cpp b/src/mame/drivers/lft_craft.cpp
index 3069c2172f2..6f6ce148570 100644
--- a/src/mame/drivers/lft_craft.cpp
+++ b/src/mame/drivers/lft_craft.cpp
@@ -174,7 +174,7 @@ uint32_t lft_craft_state::screen_update(screen_device &screen, bitmap_rgb32 &bit
const pen_t *pens = m_palette->pens();
for(int y = 0; y < LINES_PER_FRAME; y++)
{
- uint32_t *dst = &bitmap.pix32(y);
+ uint32_t *dst = &bitmap.pix(y);
uint8_t *src = &m_pixels[y * LINE_CYCLES];
for(int x = 0; x < LINE_CYCLES; x++)
{
diff --git a/src/mame/drivers/lft_phasor.cpp b/src/mame/drivers/lft_phasor.cpp
index 11335ca939b..2f18af496e3 100644
--- a/src/mame/drivers/lft_phasor.cpp
+++ b/src/mame/drivers/lft_phasor.cpp
@@ -186,7 +186,7 @@ uint32_t lft_phasor_state::screen_update(screen_device &screen, bitmap_rgb32 &bi
const pen_t *pens = m_palette->pens();
for(int y = 0; y < 313; y++)
{
- uint32_t *dst = &bitmap.pix32(y);
+ uint32_t *dst = &bitmap.pix(y);
uint8_t *src = &m_samples[y * 1135];
for(int x = 0; x < 1135; x++)
{
diff --git a/src/mame/drivers/lgp.cpp b/src/mame/drivers/lgp.cpp
index 67bc14514f8..9b76c5469de 100644
--- a/src/mame/drivers/lgp.cpp
+++ b/src/mame/drivers/lgp.cpp
@@ -69,7 +69,6 @@ Dumping Notes:
#include "cpu/z80/z80.h"
#include "machine/ldv1000.h"
#include "emupal.h"
-#include "render.h"
#include "speaker.h"
diff --git a/src/mame/drivers/limenko.cpp b/src/mame/drivers/limenko.cpp
index ced23bf5779..1455aaa25f3 100644
--- a/src/mame/drivers/limenko.cpp
+++ b/src/mame/drivers/limenko.cpp
@@ -375,9 +375,9 @@ void limenko_state::draw_single_sprite(bitmap_ind16 &dest_bmp,const rectangle &c
{ // skip if inner loop doesn't draw anything
for (int y = sy; y < ey; y++)
{
- const u8 *source = source_base + y_index * width;
- u16 *dest = &dest_bmp.pix16(y);
- u8 *pri = &m_sprites_bitmap_pri.pix8(y);
+ u8 const *const source = source_base + y_index * width;
+ u16 *const dest = &dest_bmp.pix(y);
+ u8 *const pri = &m_sprites_bitmap_pri.pix(y);
int x_index = x_index_base;
for (int x = sx; x < ex; x++)
{
@@ -452,10 +452,10 @@ void limenko_state::copy_sprites(bitmap_ind16 &bitmap, bitmap_ind16 &sprites_bit
{
for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
{
- u16 *source = &sprites_bitmap.pix16(y);
- u16 *dest = &bitmap.pix16(y);
- u8 *dest_pri = &priority_bitmap.pix8(y);
- u8 *source_pri = &m_sprites_bitmap_pri.pix8(y);
+ u16 const *const source = &sprites_bitmap.pix(y);
+ u16 *const dest = &bitmap.pix(y);
+ u8 const *const dest_pri = &priority_bitmap.pix(y);
+ u8 const *const source_pri = &m_sprites_bitmap_pri.pix(y);
for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
{
diff --git a/src/mame/drivers/llc1.cpp b/src/mame/drivers/llc1.cpp
index a0117d521d8..29e900f8b1e 100644
--- a/src/mame/drivers/llc1.cpp
+++ b/src/mame/drivers/llc1.cpp
@@ -237,22 +237,21 @@ void llc1_state::machine_start()
u32 llc1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx,inv;
- u16 sy=0,ma=0,x;
+ u16 sy=0,ma=0;
- for (y = 0; y < 16; y++)
+ for (u8 y = 0; y < 16; y++)
{
- for (ra = 0; ra < 8; ra++)
+ for (u8 ra = 0; ra < 8; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 64; x++)
+ for (u16 x = ma; x < ma + 64; x++)
{
- inv = (m_vram[x] & 0x80) ? 0xff : 0;
- chr = m_vram[x] & 0x7f;
+ u8 const inv = (m_vram[x] & 0x80) ? 0xff : 0;
+ u8 const chr = m_vram[x] & 0x7f;
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[ chr | (ra << 7) ] ^ inv;
+ u8 const gfx = m_p_chargen[ chr | (ra << 7) ] ^ inv;
/* Display a scanline of a character (8 pixels) */
*p++ = BIT(gfx, 7);
diff --git a/src/mame/drivers/llc2.cpp b/src/mame/drivers/llc2.cpp
index b22de1b0774..cc00f24d67c 100644
--- a/src/mame/drivers/llc2.cpp
+++ b/src/mame/drivers/llc2.cpp
@@ -166,30 +166,29 @@ void llc2_state::machine_start()
u32 llc2_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx,inv, inv1=m_rv ? 0xff : 0;
- u16 sy=0,ma=0,x;
+ u8 const inv1 = m_rv ? 0xff : 0;
+ u16 sy = 0, ma = 0;
- for (y = 0; y < 32; y++)
+ for (u8 y = 0; y < 32; y++)
{
- for (ra = 0; ra < 8; ra++)
+ for (u8 ra = 0; ra < 8; ra++)
{
- inv = 0;
- u16 *p = &bitmap.pix16(sy++);
+ u8 inv = 0;
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 64; x++)
+ for (u16 x = ma; x < ma + 64; x++)
{
- chr = m_vram[x];
+ u8 chr = m_vram[x];
if (chr==0x11) // inverse on
{
inv=0xff;
chr=0x0f; // must not show
}
- else
- if (chr==0x10) // inverse off
+ else if (chr==0x10) // inverse off
inv=0;
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[ (chr << 3) | ra ] ^ inv ^ inv1;
+ u8 const gfx = m_p_chargen[ (chr << 3) | ra ] ^ inv ^ inv1;
/* Display a scanline of a character (8 pixels) */
*p++ = BIT(gfx, 7);
diff --git a/src/mame/drivers/lola8a.cpp b/src/mame/drivers/lola8a.cpp
index f915bed8bfe..3ca470eb116 100644
--- a/src/mame/drivers/lola8a.cpp
+++ b/src/mame/drivers/lola8a.cpp
@@ -234,16 +234,14 @@ INPUT_PORTS_END
MC6845_UPDATE_ROW( lola8a_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 x,gfx;
- u16 mem;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u32 *p = &bitmap.pix(y);
ma &= 0x7ff;
- for (x = 0; x < x_count; x++)
+ for (u8 x = 0; x < x_count; x++)
{
- mem = (x+ma)*8 + ra;
- gfx = m_p_videoram[mem] ^ ((cursor_x == x) ? 0xff : 0);
+ u16 mem = (x+ma)*8 + ra;
+ u8 gfx = m_p_videoram[mem] ^ ((cursor_x == x) ? 0xff : 0);
*p++ = palette[BIT(gfx, 7) ? 7 : 0];
*p++ = palette[BIT(gfx, 6) ? 7 : 0];
diff --git a/src/mame/drivers/lviv.cpp b/src/mame/drivers/lviv.cpp
index 7aac9930b97..67f19c0392d 100644
--- a/src/mame/drivers/lviv.cpp
+++ b/src/mame/drivers/lviv.cpp
@@ -328,7 +328,7 @@ static INPUT_PORTS_START (lviv)
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR(']')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Run") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('*') PORT_CHAR(':')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(':') PORT_CHAR('*')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('H')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('Z')
PORT_START("KEY2") /* 2nd PPI port A bit 2 low */
@@ -354,7 +354,7 @@ static INPUT_PORTS_START (lviv)
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("(G)") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("(B)") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
- PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR(164)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
diff --git a/src/mame/drivers/m14.cpp b/src/mame/drivers/m14.cpp
index 5a40e118da5..99bedecc74c 100644
--- a/src/mame/drivers/m14.cpp
+++ b/src/mame/drivers/m14.cpp
@@ -161,33 +161,31 @@ void m14_state::video_start()
void m14_state::draw_ball_and_paddle(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int xi,yi;
//const rgb_t white_pen = rgb_t::white();
const uint8_t white_pen = 0x1f;
const int xoffs = -8; // matches left-right wall bounces
const int p_ybase = 184; // matches ball bounce to paddle
- int resx,resy;
// draw ball
- for(xi=0;xi<4;xi++)
- for(yi=0;yi<4;yi++)
+ for(int xi=0;xi<4;xi++)
+ for(int yi=0;yi<4;yi++)
{
- resx = flip_screen() ? 32*8-(m_ballx+xi+xoffs) : m_ballx+xi+xoffs;
- resy = flip_screen() ? 28*8-(m_bally+yi) : m_bally+yi;
+ const int resx = flip_screen() ? 32*8-(m_ballx+xi+xoffs) : m_ballx+xi+xoffs;
+ const int resy = flip_screen() ? 28*8-(m_bally+yi) : m_bally+yi;
if(cliprect.contains(resx,resy))
- bitmap.pix16(resy, resx) = m_palette->pen(white_pen);
+ bitmap.pix(resy, resx) = m_palette->pen(white_pen);
}
// draw paddle
- for(xi=0;xi<16;xi++)
- for(yi=0;yi<4;yi++)
+ for(int xi=0;xi<16;xi++)
+ for(int yi=0;yi<4;yi++)
{
- resx = flip_screen() ? 32*8-(m_paddlex+xi+xoffs) : (m_paddlex+xi+xoffs);
- resy = flip_screen() ? 28*8-(p_ybase+yi) : p_ybase+yi;
+ const int resx = flip_screen() ? 32*8-(m_paddlex+xi+xoffs) : (m_paddlex+xi+xoffs);
+ const int resy = flip_screen() ? 28*8-(p_ybase+yi) : p_ybase+yi;
if(cliprect.contains(resx,resy))
- bitmap.pix16(resy, resx) = m_palette->pen(white_pen);
+ bitmap.pix(resy, resx) = m_palette->pen(white_pen);
}
diff --git a/src/mame/drivers/m20.cpp b/src/mame/drivers/m20.cpp
index 00c61f10ee6..557c4e684a1 100644
--- a/src/mame/drivers/m20.cpp
+++ b/src/mame/drivers/m20.cpp
@@ -130,16 +130,15 @@ private:
MC6845_UPDATE_ROW( m20_state::update_row )
{
- uint32_t *p = &bitmap.pix32(y);
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int i, j;
+ uint32_t *p = &bitmap.pix(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
- for ( i = 0; i < x_count; i++ )
+ for ( int i = 0; i < x_count; i++ )
{
uint16_t offset = ((ma | (ra << 1)) << 4) + i;
uint16_t data = m_p_videoram[ offset ];
- for ( j = 15; j >= 0; j-- )
+ for ( int j = 15; j >= 0; j-- )
{
*p = palette[( data & 1 << j ) ? 1 : 0];
p++;
diff --git a/src/mame/drivers/m3.cpp b/src/mame/drivers/m3.cpp
index e97675a6e50..f40db77c10f 100644
--- a/src/mame/drivers/m3.cpp
+++ b/src/mame/drivers/m3.cpp
@@ -62,16 +62,14 @@ INPUT_PORTS_END
MC6845_UPDATE_ROW( m3_state::crtc_update_row )
{
- const rgb_t *pens = m_palette->palette()->entry_list_raw();
- uint8_t chr,gfx,inv;
- uint16_t mem,x;
- uint32_t *p = &bitmap.pix32(y);
+ rgb_t const *const pens = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (uint16_t x = 0; x < x_count; x++)
{
- inv = (x == cursor_x) ? 0xff : 0;
- mem = (ma + x) & 0x7ff;
- chr = m_p_videoram[mem];
+ uint8_t inv = (x == cursor_x) ? 0xff : 0;
+ uint16_t mem = (ma + x) & 0x7ff;
+ uint8_t chr = m_p_videoram[mem];
if (BIT(chr, 7))
{
inv ^= 0xff;
@@ -79,7 +77,7 @@ MC6845_UPDATE_ROW( m3_state::crtc_update_row )
}
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<4) | ra] ^ inv;
+ uint8_t gfx = m_p_chargen[(chr<<4) | ra] ^ inv;
/* Display a scanline of a character (8 pixels) */
*p++ = pens[BIT(gfx, 6)];
diff --git a/src/mame/drivers/m5.cpp b/src/mame/drivers/m5.cpp
index 79c405648a5..55f8679a087 100644
--- a/src/mame/drivers/m5.cpp
+++ b/src/mame/drivers/m5.cpp
@@ -832,7 +832,7 @@ static INPUT_PORTS_START( m5 )
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("_ Triangle") PORT_CODE(KEYCODE_TILDE) PORT_CHAR('_')
- PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH2) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('\\') PORT_CHAR('|') // backslash ok for m5p, shows as ¥ on m5.
PORT_START("Y6")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
diff --git a/src/mame/drivers/m72.cpp b/src/mame/drivers/m72.cpp
index 5e35cf81fc9..98505de4549 100644
--- a/src/mame/drivers/m72.cpp
+++ b/src/mame/drivers/m72.cpp
@@ -597,16 +597,16 @@ static const u8 airduelm72_crc[CRC_LEN] = { 0x54,0x81,0xe6,0x8a, 0xc9,0x12,0
// Actual MCU is dumped, information for Air Duel (Japan, M72 hardware) for reference:
static const u8 airduelm72_code[CODE_LEN] =
{
- 0x68,0x00,0xd0, // push 0d000h
- 0x1f, // pop ds
- // the game checks for
- // "This game can only be played in Japan..." message in the video text buffer
- // the message is nowhere to be found in the ROMs, so has to be displayed by the mcu
- 0xc6,0x06,0xc0,0x1c,0x57, // mov [1cc0h], byte 057h
- 0xea,0x69,0x0b,0x00,0x00 // jmp 0000:$0b69
+ 0x68,0x00,0xd0, // push 0d000h
+ 0x1f, // pop ds
+ // the game checks for
+ // "This game can only be played in Japan..." message in the video text buffer
+ // the message is nowhere to be found in the ROMs, so has to be displayed by the mcu
+ 0xc6,0x06,0xc0,0x1c,0x57, // mov [1cc0h], byte 057h
+ 0xea,0x69,0x0b,0x00,0x00 // jmp 0000:$0b69
};
static const u8 airduelm72j_crc[CRC_LEN] = { 0x72,0x9c,0xca,0x85, 0xc9,0x12,0xcc,0xea,
- 0x00,0x00 };
+ 0x00,0x00 };
*/
/* Daiku no Gensan */
diff --git a/src/mame/drivers/m79152pc.cpp b/src/mame/drivers/m79152pc.cpp
index cf041466982..2f05839a30c 100644
--- a/src/mame/drivers/m79152pc.cpp
+++ b/src/mame/drivers/m79152pc.cpp
@@ -185,10 +185,10 @@ TIMER_CALLBACK_MEMBER(m79152pc_state::hsync_off)
void m79152pc_state::screen_draw_line(bitmap_ind16 &bitmap, unsigned y)
{
- u16 ma = u16(m_line_base) << 4;
- u8 ra = m_line_count & 0xf;
+ const u16 ma = u16(m_line_base) << 4;
+ const u8 ra = m_line_count & 0xf;
- u16 *p = &bitmap.pix16(y++);
+ u16 *p = &bitmap.pix(y++);
for (u16 x = ma; x < ma + 80; x++)
{
diff --git a/src/mame/drivers/m79amb.cpp b/src/mame/drivers/m79amb.cpp
index 7baecaf457e..c855502faa1 100644
--- a/src/mame/drivers/m79amb.cpp
+++ b/src/mame/drivers/m79amb.cpp
@@ -75,20 +75,16 @@ void m79amb_state::ramtek_videoram_w(offs_t offset, uint8_t data)
uint32_t m79amb_state::screen_update_ramtek(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < 0x2000; offs++)
+ for (offs_t offs = 0; offs < 0x2000; offs++)
{
- int i;
-
uint8_t data = m_videoram[offs];
int y = offs >> 5;
int x = (offs & 0x1f) << 3;
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
pen_t pen = (data & 0x80) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
x++;
data <<= 1;
diff --git a/src/mame/drivers/m92.cpp b/src/mame/drivers/m92.cpp
index 63b4387b254..28883fe6c70 100644
--- a/src/mame/drivers/m92.cpp
+++ b/src/mame/drivers/m92.cpp
@@ -1465,83 +1465,83 @@ ROM_END
ROM_START( inthunt )
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD16_BYTE( "ith-h0-d.bin", 0x000001, 0x040000, CRC(52f8e7a6) SHA1(26d9e272b01e7b82019812059dcc9fbb043c6129) )
- ROM_LOAD16_BYTE( "ith-l0-d.bin", 0x000000, 0x040000, CRC(5db79eb7) SHA1(ffd4228d7b88a44a82e639a5583753da183fcb23) )
- ROM_LOAD16_BYTE( "ith-h1-b.bin", 0x080001, 0x020000, CRC(fc2899df) SHA1(f811ff5fd55655afdb25950d317db85c8091b6d6) )
- ROM_LOAD16_BYTE( "ith-l1-b.bin", 0x080000, 0x020000, CRC(955a605a) SHA1(2515accc2f4a06b07418e45eb62e746d09c81720) )
+ ROM_LOAD16_BYTE( "ith-h0-d.ic28", 0x000001, 0x040000, CRC(52f8e7a6) SHA1(26d9e272b01e7b82019812059dcc9fbb043c6129) )
+ ROM_LOAD16_BYTE( "ith-l0-d.ic39", 0x000000, 0x040000, CRC(5db79eb7) SHA1(ffd4228d7b88a44a82e639a5583753da183fcb23) )
+ ROM_LOAD16_BYTE( "ith-h1-b.ic38", 0x080001, 0x020000, CRC(fc2899df) SHA1(f811ff5fd55655afdb25950d317db85c8091b6d6) )
+ ROM_LOAD16_BYTE( "ith-l1-b.ic27", 0x080000, 0x020000, CRC(955a605a) SHA1(2515accc2f4a06b07418e45eb62e746d09c81720) )
ROM_REGION( 0x20000, "soundcpu", 0 ) /* Irem D8000011A1 */
- ROM_LOAD16_BYTE( "ith-sh0.rom", 0x00001, 0x10000, CRC(209c8b7f) SHA1(eaf4a6d9222fe181df65cea1f13c3f2ebff2ec5b) )
- ROM_LOAD16_BYTE( "ith-sl0.rom", 0x00000, 0x10000, CRC(18472d65) SHA1(2705e94ee350ffda272c50ea3bf605826aa19978) )
+ ROM_LOAD16_BYTE( "ith-sh0.ic30", 0x00001, 0x10000, CRC(209c8b7f) SHA1(eaf4a6d9222fe181df65cea1f13c3f2ebff2ec5b) )
+ ROM_LOAD16_BYTE( "ith-sl0.ic31", 0x00000, 0x10000, CRC(18472d65) SHA1(2705e94ee350ffda272c50ea3bf605826aa19978) )
ROM_REGION( 0x200000, "gfx1", 0 ) /* Tiles */
- ROM_LOAD( "ith_ic26.rom", 0x000000, 0x080000, CRC(4c1818cf) SHA1(fc8c2ae640bc3504a52736be46febb92c998fd7d) )
- ROM_LOAD( "ith_ic25.rom", 0x080000, 0x080000, CRC(91145bae) SHA1(71b2695575f189a2fc72635831ba408f824d4928) )
- ROM_LOAD( "ith_ic24.rom", 0x100000, 0x080000, CRC(fc03fe3b) SHA1(7e34220b9b21b82e012dcbf3052cccb118e3c382) )
- ROM_LOAD( "ith_ic23.rom", 0x180000, 0x080000, CRC(ee156a0a) SHA1(4a303ed292ce79e3f990139c35b921213eb2711d) )
+ ROM_LOAD( "ith_c0.ic26", 0x000000, 0x080000, CRC(4c1818cf) SHA1(fc8c2ae640bc3504a52736be46febb92c998fd7d) )
+ ROM_LOAD( "ith_c1.ic25", 0x080000, 0x080000, CRC(91145bae) SHA1(71b2695575f189a2fc72635831ba408f824d4928) )
+ ROM_LOAD( "ith_c2.ic24", 0x100000, 0x080000, CRC(fc03fe3b) SHA1(7e34220b9b21b82e012dcbf3052cccb118e3c382) )
+ ROM_LOAD( "ith_c3.ic23", 0x180000, 0x080000, CRC(ee156a0a) SHA1(4a303ed292ce79e3f990139c35b921213eb2711d) )
ROM_REGION( 0x400000, "gfx2", 0 ) /* Sprites */
- ROM_LOAD( "ith_ic34.rom", 0x000000, 0x100000, CRC(a019766e) SHA1(59012a41d152a471a95f1f86b6b1e0f9dd3f9711) )
- ROM_LOAD( "ith_ic35.rom", 0x100000, 0x100000, CRC(3fca3073) SHA1(bdae171cb7705647f28354ca83ecdea3a15f6e22) )
- ROM_LOAD( "ith_ic36.rom", 0x200000, 0x100000, CRC(20d1b28b) SHA1(290947d77242e837444766ff5d420bc9b53b5b01) )
- ROM_LOAD( "ith_ic37.rom", 0x300000, 0x100000, CRC(90b6fd4b) SHA1(99237ebab7cf4689e06965bd546cd80a825ab024) )
+ ROM_LOAD( "ith_000.ic34", 0x000000, 0x100000, CRC(a019766e) SHA1(59012a41d152a471a95f1f86b6b1e0f9dd3f9711) )
+ ROM_LOAD( "ith_010.ic35", 0x100000, 0x100000, CRC(3fca3073) SHA1(bdae171cb7705647f28354ca83ecdea3a15f6e22) )
+ ROM_LOAD( "ith_020.ic36", 0x200000, 0x100000, CRC(20d1b28b) SHA1(290947d77242e837444766ff5d420bc9b53b5b01) )
+ ROM_LOAD( "ith_030.ic37", 0x300000, 0x100000, CRC(90b6fd4b) SHA1(99237ebab7cf4689e06965bd546cd80a825ab024) )
ROM_REGION( 0x80000, "irem", 0 )
- ROM_LOAD( "ith_ic9.rom", 0x000000, 0x080000, CRC(318ee71a) SHA1(e6f49a7adf7155ba40c4f33a8fdc9553c00f5e3d) )
+ ROM_LOAD( "ith_da.ic9", 0x000000, 0x080000, CRC(318ee71a) SHA1(e6f49a7adf7155ba40c4f33a8fdc9553c00f5e3d) )
ROM_END
ROM_START( inthuntu )
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD16_BYTE( "ith-h0-c.bin", 0x000001, 0x040000, CRC(563dcec0) SHA1(0c7588ba603926fb0b490f2ba324ff73362a54d5) )
- ROM_LOAD16_BYTE( "ith-l0-c.bin", 0x000000, 0x040000, CRC(1638c705) SHA1(8ca7a12c2f75172d4c2c808ea666b2f2e969398c) )
- ROM_LOAD16_BYTE( "ith-h1-a.bin", 0x080001, 0x020000, CRC(0253065f) SHA1(a11e6bf014c19b2e317b75f01a7f0d7a9a85c7d3) )
- ROM_LOAD16_BYTE( "ith-l1-a.bin", 0x080000, 0x020000, CRC(a57d688d) SHA1(aa049de5c41097b6f1da31e9bf3bac132f67aa6c) )
+ ROM_LOAD16_BYTE( "ith-h0-c.ic28", 0x000001, 0x040000, CRC(563dcec0) SHA1(0c7588ba603926fb0b490f2ba324ff73362a54d5) )
+ ROM_LOAD16_BYTE( "ith-l0-c.ic39", 0x000000, 0x040000, CRC(1638c705) SHA1(8ca7a12c2f75172d4c2c808ea666b2f2e969398c) )
+ ROM_LOAD16_BYTE( "ith-h1-a.ic38", 0x080001, 0x020000, CRC(0253065f) SHA1(a11e6bf014c19b2e317b75f01a7f0d7a9a85c7d3) )
+ ROM_LOAD16_BYTE( "ith-l1-a.ic27", 0x080000, 0x020000, CRC(a57d688d) SHA1(aa049de5c41097b6f1da31e9bf3bac132f67aa6c) )
ROM_REGION( 0x20000, "soundcpu", 0 ) /* Irem D8000011A1 */
- ROM_LOAD16_BYTE( "ith-sh0.rom", 0x00001, 0x10000, CRC(209c8b7f) SHA1(eaf4a6d9222fe181df65cea1f13c3f2ebff2ec5b) )
- ROM_LOAD16_BYTE( "ith-sl0.rom", 0x00000, 0x10000, CRC(18472d65) SHA1(2705e94ee350ffda272c50ea3bf605826aa19978) )
+ ROM_LOAD16_BYTE( "ith-sh0.ic30", 0x00001, 0x10000, CRC(209c8b7f) SHA1(eaf4a6d9222fe181df65cea1f13c3f2ebff2ec5b) )
+ ROM_LOAD16_BYTE( "ith-sl0.ic31", 0x00000, 0x10000, CRC(18472d65) SHA1(2705e94ee350ffda272c50ea3bf605826aa19978) )
ROM_REGION( 0x200000, "gfx1", 0 ) /* Tiles */
- ROM_LOAD( "ith_ic26.rom", 0x000000, 0x080000, CRC(4c1818cf) SHA1(fc8c2ae640bc3504a52736be46febb92c998fd7d) )
- ROM_LOAD( "ith_ic25.rom", 0x080000, 0x080000, CRC(91145bae) SHA1(71b2695575f189a2fc72635831ba408f824d4928) )
- ROM_LOAD( "ith_ic24.rom", 0x100000, 0x080000, CRC(fc03fe3b) SHA1(7e34220b9b21b82e012dcbf3052cccb118e3c382) )
- ROM_LOAD( "ith_ic23.rom", 0x180000, 0x080000, CRC(ee156a0a) SHA1(4a303ed292ce79e3f990139c35b921213eb2711d) )
+ ROM_LOAD( "ith_c0.ic26", 0x000000, 0x080000, CRC(4c1818cf) SHA1(fc8c2ae640bc3504a52736be46febb92c998fd7d) )
+ ROM_LOAD( "ith_c1.ic25", 0x080000, 0x080000, CRC(91145bae) SHA1(71b2695575f189a2fc72635831ba408f824d4928) )
+ ROM_LOAD( "ith_c2.ic24", 0x100000, 0x080000, CRC(fc03fe3b) SHA1(7e34220b9b21b82e012dcbf3052cccb118e3c382) )
+ ROM_LOAD( "ith_c3.ic23", 0x180000, 0x080000, CRC(ee156a0a) SHA1(4a303ed292ce79e3f990139c35b921213eb2711d) )
ROM_REGION( 0x400000, "gfx2", 0 ) /* Sprites */
- ROM_LOAD( "ith_ic34.rom", 0x000000, 0x100000, CRC(a019766e) SHA1(59012a41d152a471a95f1f86b6b1e0f9dd3f9711) )
- ROM_LOAD( "ith_ic35.rom", 0x100000, 0x100000, CRC(3fca3073) SHA1(bdae171cb7705647f28354ca83ecdea3a15f6e22) )
- ROM_LOAD( "ith_ic36.rom", 0x200000, 0x100000, CRC(20d1b28b) SHA1(290947d77242e837444766ff5d420bc9b53b5b01) )
- ROM_LOAD( "ith_ic37.rom", 0x300000, 0x100000, CRC(90b6fd4b) SHA1(99237ebab7cf4689e06965bd546cd80a825ab024) )
+ ROM_LOAD( "ith_000.ic34", 0x000000, 0x100000, CRC(a019766e) SHA1(59012a41d152a471a95f1f86b6b1e0f9dd3f9711) )
+ ROM_LOAD( "ith_010.ic35", 0x100000, 0x100000, CRC(3fca3073) SHA1(bdae171cb7705647f28354ca83ecdea3a15f6e22) )
+ ROM_LOAD( "ith_020.ic36", 0x200000, 0x100000, CRC(20d1b28b) SHA1(290947d77242e837444766ff5d420bc9b53b5b01) )
+ ROM_LOAD( "ith_030.ic37", 0x300000, 0x100000, CRC(90b6fd4b) SHA1(99237ebab7cf4689e06965bd546cd80a825ab024) )
ROM_REGION( 0x80000, "irem", 0 )
- ROM_LOAD( "ith_ic9.rom", 0x000000, 0x080000, CRC(318ee71a) SHA1(e6f49a7adf7155ba40c4f33a8fdc9553c00f5e3d) )
+ ROM_LOAD( "ith_da.ic9", 0x000000, 0x080000, CRC(318ee71a) SHA1(e6f49a7adf7155ba40c4f33a8fdc9553c00f5e3d) )
ROM_END
ROM_START( kaiteids )
ROM_REGION( 0x100000, "maincpu", 0 )
- ROM_LOAD16_BYTE( "ith-h0j.bin", 0x000001, 0x040000, CRC(dc1dec36) SHA1(f0a6e3be19752bffd9fd5f435405c8f591eab258) )
- ROM_LOAD16_BYTE( "ith-l0j.bin", 0x000000, 0x040000, CRC(8835d704) SHA1(42be25ccdc31824797a17e6f76bd06edfe853833) )
- ROM_LOAD16_BYTE( "ith-h1j.bin", 0x080001, 0x020000, CRC(5a7b212d) SHA1(50562d804a43aed7c34c19c8345782ac2f85caa7) )
- ROM_LOAD16_BYTE( "ith-l1j.bin", 0x080000, 0x020000, CRC(4c084494) SHA1(4f32003db32f13e19dd07c66996b4328ac2a671e) )
+ ROM_LOAD16_BYTE( "ith-h0j.ic28", 0x000001, 0x040000, CRC(dc1dec36) SHA1(f0a6e3be19752bffd9fd5f435405c8f591eab258) )
+ ROM_LOAD16_BYTE( "ith-l0j.ic39", 0x000000, 0x040000, CRC(8835d704) SHA1(42be25ccdc31824797a17e6f76bd06edfe853833) )
+ ROM_LOAD16_BYTE( "ith-h1j.ic38", 0x080001, 0x020000, CRC(5a7b212d) SHA1(50562d804a43aed7c34c19c8345782ac2f85caa7) )
+ ROM_LOAD16_BYTE( "ith-l1j.ic27", 0x080000, 0x020000, CRC(4c084494) SHA1(4f32003db32f13e19dd07c66996b4328ac2a671e) )
ROM_REGION( 0x20000, "soundcpu", 0 ) /* Irem D8000011A1 */
- ROM_LOAD16_BYTE( "ith-sh0.rom", 0x00001, 0x10000, CRC(209c8b7f) SHA1(eaf4a6d9222fe181df65cea1f13c3f2ebff2ec5b) )
- ROM_LOAD16_BYTE( "ith-sl0.rom", 0x00000, 0x10000, CRC(18472d65) SHA1(2705e94ee350ffda272c50ea3bf605826aa19978) )
+ ROM_LOAD16_BYTE( "ith-sh0.ic30", 0x00001, 0x10000, CRC(209c8b7f) SHA1(eaf4a6d9222fe181df65cea1f13c3f2ebff2ec5b) )
+ ROM_LOAD16_BYTE( "ith-sl0.ic31", 0x00000, 0x10000, CRC(18472d65) SHA1(2705e94ee350ffda272c50ea3bf605826aa19978) )
ROM_REGION( 0x200000, "gfx1", 0 ) /* Tiles */
- ROM_LOAD( "ith_ic26.rom", 0x000000, 0x080000, CRC(4c1818cf) SHA1(fc8c2ae640bc3504a52736be46febb92c998fd7d) )
- ROM_LOAD( "ith_ic25.rom", 0x080000, 0x080000, CRC(91145bae) SHA1(71b2695575f189a2fc72635831ba408f824d4928) )
- ROM_LOAD( "ith_ic24.rom", 0x100000, 0x080000, CRC(fc03fe3b) SHA1(7e34220b9b21b82e012dcbf3052cccb118e3c382) )
- ROM_LOAD( "ith_ic23.rom", 0x180000, 0x080000, CRC(ee156a0a) SHA1(4a303ed292ce79e3f990139c35b921213eb2711d) )
+ ROM_LOAD( "ith_c0.ic26", 0x000000, 0x080000, CRC(4c1818cf) SHA1(fc8c2ae640bc3504a52736be46febb92c998fd7d) )
+ ROM_LOAD( "ith_c1.ic25", 0x080000, 0x080000, CRC(91145bae) SHA1(71b2695575f189a2fc72635831ba408f824d4928) )
+ ROM_LOAD( "ith_c2.ic24", 0x100000, 0x080000, CRC(fc03fe3b) SHA1(7e34220b9b21b82e012dcbf3052cccb118e3c382) )
+ ROM_LOAD( "ith_c3.ic23", 0x180000, 0x080000, CRC(ee156a0a) SHA1(4a303ed292ce79e3f990139c35b921213eb2711d) )
ROM_REGION( 0x400000, "gfx2", 0 ) /* Sprites */
- ROM_LOAD( "ith_ic34.rom", 0x000000, 0x100000, CRC(a019766e) SHA1(59012a41d152a471a95f1f86b6b1e0f9dd3f9711) )
- ROM_LOAD( "ith_ic35.rom", 0x100000, 0x100000, CRC(3fca3073) SHA1(bdae171cb7705647f28354ca83ecdea3a15f6e22) )
- ROM_LOAD( "ith_ic36.rom", 0x200000, 0x100000, CRC(20d1b28b) SHA1(290947d77242e837444766ff5d420bc9b53b5b01) )
- ROM_LOAD( "ith_ic37.rom", 0x300000, 0x100000, CRC(90b6fd4b) SHA1(99237ebab7cf4689e06965bd546cd80a825ab024) )
+ ROM_LOAD( "ith_000.ic34", 0x000000, 0x100000, CRC(a019766e) SHA1(59012a41d152a471a95f1f86b6b1e0f9dd3f9711) )
+ ROM_LOAD( "ith_010.ic35", 0x100000, 0x100000, CRC(3fca3073) SHA1(bdae171cb7705647f28354ca83ecdea3a15f6e22) )
+ ROM_LOAD( "ith_020.ic36", 0x200000, 0x100000, CRC(20d1b28b) SHA1(290947d77242e837444766ff5d420bc9b53b5b01) )
+ ROM_LOAD( "ith_030.ic37", 0x300000, 0x100000, CRC(90b6fd4b) SHA1(99237ebab7cf4689e06965bd546cd80a825ab024) )
ROM_REGION( 0x80000, "irem", 0 )
- ROM_LOAD( "ith_ic9.rom", 0x000000, 0x080000, CRC(318ee71a) SHA1(e6f49a7adf7155ba40c4f33a8fdc9553c00f5e3d) )
+ ROM_LOAD( "ith_da.ic9", 0x000000, 0x080000, CRC(318ee71a) SHA1(e6f49a7adf7155ba40c4f33a8fdc9553c00f5e3d) )
ROM_END
ROM_START( hook )
diff --git a/src/mame/drivers/mac.cpp b/src/mame/drivers/mac.cpp
index 2db4d331526..925d4cb9bce 100644
--- a/src/mame/drivers/mac.cpp
+++ b/src/mame/drivers/mac.cpp
@@ -41,13 +41,13 @@
when the PC hits GetCPUID, the move.l (a2), d0 at PC = 0x10000 will cause an MMU fault (jump to 0xFFF00300). why?
a2 = 0x5ffffffc (the CPU ID register). MMU is unable to resolve this; defect in the MMU emulation probable.
- TODO:
- - SE and Classic to own driver
- - Portable and PowerBook 100 to own driver
- - Remaining PowerBooks to own driver
- - Quadra 700 to own driver
- - V8 and friends to own driver
- - LC3 / LC520 / IIvx / IIvi to own driver
+ TODO:
+ - SE and Classic to own driver
+ - Portable and PowerBook 100 to own driver
+ - Remaining PowerBooks to own driver
+ - Quadra 700 to own driver
+ - V8 and friends to own driver
+ - LC3 / LC520 / IIvx / IIvi to own driver
****************************************************************************/
@@ -779,26 +779,6 @@ void mac_state::macpd210_map(address_map &map)
map(0x60000000, 0x6001ffff).ram().share("vram").mirror(0x0ffe0000);
}
-void mac_state::quadra700_map(address_map &map)
-{
- map(0x40000000, 0x400fffff).r(FUNC(mac_state::rom_switch_r)).mirror(0x0ff00000);
-
- map(0x50000000, 0x50001fff).rw(FUNC(mac_state::mac_via_r), FUNC(mac_state::mac_via_w)).mirror(0x00fc0000);
- map(0x50002000, 0x50003fff).rw(FUNC(mac_state::mac_via2_r), FUNC(mac_state::mac_via2_w)).mirror(0x00fc0000);
-// 50008000 = Ethernet MAC ID PROM
-// 5000a000 = Sonic (DP83932) ethernet
-// 5000f000 = SCSI cf96, 5000f402 = SCSI #2 cf96
- map(0x5000f000, 0x5000f3ff).rw(FUNC(mac_state::mac_5396_r), FUNC(mac_state::mac_5396_w)).mirror(0x00fc0000);
- map(0x5000c000, 0x5000dfff).rw(FUNC(mac_state::mac_scc_r), FUNC(mac_state::mac_scc_2_w)).mirror(0x00fc0000);
- map(0x50014000, 0x50015fff).rw(m_asc, FUNC(asc_device::read), FUNC(asc_device::write)).mirror(0x00fc0000);
- map(0x5001e000, 0x5001ffff).rw(FUNC(mac_state::mac_iwm_r), FUNC(mac_state::mac_iwm_w)).mirror(0x00fc0000);
-
- // f9800000 = VDAC / DAFB
- map(0xf9000000, 0xf91fffff).ram().share("vram");
- map(0xf9800000, 0xf98001ff).rw(FUNC(mac_state::dafb_r), FUNC(mac_state::dafb_w));
- map(0xf9800200, 0xf980023f).rw(FUNC(mac_state::dafb_dac_r), FUNC(mac_state::dafb_dac_w));
-}
-
void mac_state::pwrmac_map(address_map &map)
{
map(0x00000000, 0x007fffff).ram(); // 8 MB standard
@@ -1537,54 +1517,6 @@ void mac_state::pwrmac(machine_config &config)
add_cuda(config, CUDA_341S0060);
}
-void mac_state::macqd700(machine_config &config)
-{
- /* basic machine hardware */
- M68040(config, m_maincpu, 25000000);
- m_maincpu->set_addrmap(AS_PROGRAM, &mac_state::quadra700_map);
- m_maincpu->set_dasm_override(FUNC(mac_state::mac_dasm_override));
-
- SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
- m_screen->set_refresh_hz(75.08);
- m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(1260));
- m_screen->set_size(1152, 870);
- m_screen->set_visarea(0, 1152-1, 0, 870-1);
- m_screen->set_screen_update(FUNC(mac_state::screen_update_macdafb));
-
- MCFG_VIDEO_START_OVERRIDE(mac_state,macdafb)
- MCFG_VIDEO_RESET_OVERRIDE(mac_state,macdafb)
-
- PALETTE(config, m_palette).set_entries(256);
-
- add_asc(config, asc_device::asc_type::EASC);
- add_base_devices(config, true, false);
-
- add_nubus(config, false, false);
- NUBUS_SLOT(config, "nbd", "nubus", mac_nubus_cards, nullptr);
- NUBUS_SLOT(config, "nbe", "nubus", mac_nubus_cards, nullptr);
-
- add_via1_adb(config, false);
- m_via1->readpb_handler().set(FUNC(mac_state::mac_via_in_b));
-
- add_via2(config);
-
- scsi_port_device &scsibus(SCSI_PORT(config, "scsi"));
- scsibus.set_slot_device(1, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_6));
- scsibus.set_slot_device(2, "harddisk", SCSIHD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_5));
-
- NCR539X(config, m_539x_1, C7M);
- m_539x_1->set_scsi_port("scsi");
- m_539x_1->irq_callback().set(FUNC(mac_state::irq_539x_1_w));
- m_539x_1->drq_callback().set(FUNC(mac_state::drq_539x_1_w));
-
- /* internal ram */
- RAM(config, m_ram);
- m_ram->set_default_size("4M");
- m_ram->set_extra_options("8M,16M,32M,64M,68M,72M,80M,96M,128M");
-
- SOFTWARE_LIST(config, "flop35_list").set_original("mac_flop");
-}
-
static INPUT_PORTS_START( macadb )
INPUT_PORTS_END
@@ -1754,11 +1686,6 @@ ROM_START( macpb170 )
ROM_LOAD( "pmuv2.bin", 0x000000, 0x001800, CRC(1a32b5e5) SHA1(7c096324763cfc8d2024893b3e8493b7729b3a92) )
ROM_END
-ROM_START( macqd700 )
- ROM_REGION32_BE(0x100000, "bootrom", 0)
- ROM_LOAD( "420dbff3.rom", 0x000000, 0x100000, CRC(88ea2081) SHA1(7a8ee468d16e64f2ad10cb8d1a45e6f07cc9e212) )
-ROM_END
-
ROM_START( macpb160 )
ROM_REGION32_BE(0x100000, "bootrom", 0)
ROM_LOAD( "e33b2724.rom", 0x000000, 0x100000, CRC(536c60f4) SHA1(c0510682ae6d973652d7e17f3c3b27629c47afac) )
@@ -1816,7 +1743,6 @@ COMP( 1990, maciisi, 0, 0, maciisi, maciici, mac_state, init_maci
COMP( 1991, macpb100, 0, 0, macprtb, macadb, mac_state, init_macprtb, "Apple Computer", "Macintosh PowerBook 100", MACHINE_NOT_WORKING )
COMP( 1991, macpb140, 0, 0, macpb140, macadb, mac_state, init_macpb140, "Apple Computer", "Macintosh PowerBook 140", MACHINE_NOT_WORKING )
COMP( 1991, macpb170, macpb140, 0, macpb170, macadb, mac_state, init_macpb140, "Apple Computer", "Macintosh PowerBook 170", MACHINE_NOT_WORKING )
-COMP( 1991, macqd700, macpb140, 0, macqd700, macadb, mac_state, init_macquadra700, "Apple Computer", "Macintosh Quadra 700", MACHINE_NOT_WORKING )
COMP( 1991, macclas2, 0, 0, macclas2, macadb, mac_state, init_macclassic2, "Apple Computer", "Macintosh Classic II", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )
COMP( 1991, maclc2, 0, 0, maclc2, maciici, mac_state, init_maclc2, "Apple Computer", "Macintosh LC II", MACHINE_NOT_WORKING|MACHINE_IMPERFECT_SOUND )
COMP( 1992, macpb145, macpb140, 0, macpb145, macadb, mac_state, init_macpb140, "Apple Computer", "Macintosh PowerBook 145", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/mac128.cpp b/src/mame/drivers/mac128.cpp
index de3e93a68d8..95540d9a50a 100644
--- a/src/mame/drivers/mac128.cpp
+++ b/src/mame/drivers/mac128.cpp
@@ -6,8 +6,8 @@
Original-style Macintosh family emulation
The cutoff here is Macs with 128k-style video and audio.
- We also include the SE and Classic, which are basically cost-reduced Mac Pluses with ADB
- instead of the original keyboard/mouse hardware.
+ We also include the SE and Classic, which are basically cost-reduced Mac Pluses with ADB
+ instead of the original keyboard/mouse hardware.
Nate Woods, Raphael Nabet, R. Belmont
@@ -246,11 +246,8 @@ private:
uint32_t m_overlay;
int m_irq_count, m_ca1_data, m_ca2_data;
- int m_mouse_bit_x;
- int m_mouse_bit_y;
- int last_mx, last_my;
- int count_x, count_y;
- int m_last_was_x;
+ uint8_t m_mouse_bit[2], m_mouse_last[2];
+ int16_t m_mouse_last_m[2], m_mouse_count[2];
int m_screen_buffer;
emu_timer *m_scan_timer;
emu_timer *m_hblank_timer;
@@ -288,13 +285,10 @@ void mac128_state::machine_start()
save_item(NAME(m_irq_count));
save_item(NAME(m_ca1_data));
save_item(NAME(m_ca2_data));
- save_item(NAME(m_mouse_bit_x));
- save_item(NAME(m_mouse_bit_y));
- save_item(NAME(last_mx));
- save_item(NAME(last_my));
- save_item(NAME(count_x));
- save_item(NAME(count_y));
- save_item(NAME(m_last_was_x));
+ save_item(NAME(m_mouse_bit));
+ save_item(NAME(m_mouse_last));
+ save_item(NAME(m_mouse_last_m));
+ save_item(NAME(m_mouse_count));
save_item(NAME(m_screen_buffer));
save_item(NAME(m_scc_interrupt));
save_item(NAME(m_via_interrupt));
@@ -306,6 +300,9 @@ void mac128_state::machine_start()
save_item(NAME(m_adb_irq_pending));
save_item(NAME(m_drive_select));
save_item(NAME(m_scsiirq_enable));
+
+ m_mouse_bit[0] = m_mouse_bit[1] = 0;
+ m_mouse_last[0] = m_mouse_last[1] = 0;
}
void mac128_state::machine_reset()
@@ -314,7 +311,6 @@ void mac128_state::machine_reset()
m_last_taken_interrupt = -1;
m_overlay = 1;
m_screen_buffer = 1;
- m_mouse_bit_x = m_mouse_bit_y = 0;
m_last_taken_interrupt = 0;
m_snd_enable = false;
m_main_buffer = true;
@@ -336,7 +332,7 @@ uint16_t mac128_state::ram_r(offs_t offset)
{
if (m_overlay)
{
- return m_rom_ptr[offset];
+ return m_rom_ptr[offset & 0x7ffff];
}
return m_ram_ptr[offset & m_ram_mask];
@@ -379,7 +375,7 @@ void mac128_state::field_interrupts()
take_interrupt = 1;
}
-// printf("field_interrupts: take %d\n", take_interrupt);
+// printf("field_interrupts: take %d\n", take_interrupt);
if (m_last_taken_interrupt > -1)
{
@@ -518,137 +514,32 @@ void mac128_state::macplus_scsi_w(offs_t offset, uint16_t data, uint16_t mem_mas
void mac128_state::scc_mouse_irq(int x, int y)
{
- static int lasty = 0;
- static int lastx = 0;
-
// DCD lines are active low in hardware but active high to software
- if (x && y)
+ if (x)
{
- if (m_last_was_x)
+ m_scc->dcda_w(m_mouse_last[0] ? 1 : 0);
+ if (x < 0)
{
- if(x == 2)
- {
- if(lastx)
- {
- m_scc->dcda_w(1);
- m_mouse_bit_x = 0;
- }
- else
- {
- m_scc->dcda_w(0);
- m_mouse_bit_x = 1;
- }
- }
- else
- {
- if(lastx)
- {
- m_scc->dcda_w(1);
- m_mouse_bit_x = 1;
- }
- else
- {
- m_scc->dcda_w(0);
- m_mouse_bit_x = 0;
- }
- }
- lastx = !lastx;
+ m_mouse_bit[0] = m_mouse_last[0] ? 0 : 1;
}
else
{
- if(y == 2)
- {
- if(lasty)
- {
- m_scc->dcdb_w(1);
- m_mouse_bit_y = 0;
- }
- else
- {
- m_scc->dcdb_w(0);
- m_mouse_bit_y = 1;
- }
- }
- else
- {
- if(lasty)
- {
- m_scc->dcdb_w(1);
- m_mouse_bit_y = 1;
- }
- else
- {
- m_scc->dcdb_w(0);
- m_mouse_bit_y = 0;
- }
- }
- lasty = !lasty;
+ m_mouse_bit[0] = m_mouse_last[0] ? 1 : 0;
}
-
- m_last_was_x ^= 1;
+ m_mouse_last[0] = !m_mouse_last[0];
}
- else
+ if (y)
{
- if (x)
+ m_scc->dcdb_w(m_mouse_last[1] ? 1 : 0);
+ if (y < 0)
{
- if(x == 2)
- {
- if(lastx)
- {
- m_scc->dcda_w(1);
- m_mouse_bit_x = 0;
- }
- else
- {
- m_scc->dcda_w(0);
- m_mouse_bit_x = 1;
- }
- }
- else
- {
- if(lastx)
- {
- m_scc->dcda_w(1);
- m_mouse_bit_x = 1;
- }
- else
- {
- m_scc->dcda_w(0);
- m_mouse_bit_x = 0;
- }
- }
- lastx = !lastx;
+ m_mouse_bit[1] = m_mouse_last[1] ? 0 : 1;
}
else
{
- if(y == 2)
- {
- if(lasty)
- {
- m_scc->dcdb_w(1);
- m_mouse_bit_y = 0;
- }
- else
- {
- m_scc->dcdb_w(0);
- m_mouse_bit_y = 1;
- }
- }
- else
- {
- if(lasty)
- {
- m_scc->dcdb_w(1);
- m_mouse_bit_y = 1;
- }
- else
- {
- m_scc->dcdb_w(0);
- m_mouse_bit_y = 0;
- }
- }
- lasty = !lasty;
+ m_mouse_bit[1] = m_mouse_last[1] ? 1 : 0;
}
+ m_mouse_last[1] = !m_mouse_last[1];
}
}
@@ -748,16 +639,13 @@ uint8_t mac128_state::mac_via_in_b()
{
int val = 0x40;
- if (m_mouse_bit_y) /* Mouse Y2 */
- val |= 0x20;
- if (m_mouse_bit_x) /* Mouse X2 */
- val |= 0x10;
- if ((m_mouse0->read() & 0x01) == 0)
- val |= 0x08;
+ val |= m_mouse_bit[1] << 5; // Mouse Y2
+ val |= m_mouse_bit[0] << 4; // Mouse X2
+ val |= BIT(~m_mouse0->read(), 0) << 3;
val |= m_rtc->data_r();
-// printf("%s VIA1 IN_B = %02x\n", machine().describe_context().c_str(), val);
+// printf("%s VIA1 IN_B = %02x\n", machine().describe_context().c_str(), val);
return val;
}
@@ -849,79 +737,66 @@ void mac128_state::mac_via_out_b_se(uint8_t data)
void mac128_state::mouse_callback()
{
- int new_mx, new_my;
- int x_needs_update = 0, y_needs_update = 0;
-
- new_mx = m_mouse1->read();
- new_my = m_mouse2->read();
-
- /* see if it moved in the x coord */
- if (new_mx != last_mx)
+ // see if it moved in the x coord
+ const int new_mx = m_mouse1->read();
+ if (new_mx != m_mouse_last_m[0])
{
- int diff = new_mx - last_mx;
+ int diff = new_mx - m_mouse_last_m[0];
- /* check for wrap */
+ // check for wrap
if (diff > 0x80)
- diff = 0x100-diff;
- if (diff < -0x80)
- diff = -0x100-diff;
+ diff -= 0x100;
+ else if (diff < -0x80)
+ diff += 0x100;
- count_x += diff;
-
- last_mx = new_mx;
+ m_mouse_count[0] += diff;
+ m_mouse_last_m[0] = new_mx;
}
- /* see if it moved in the y coord */
- if (new_my != last_my)
+
+ // see if it moved in the y coord
+ const int new_my = m_mouse2->read();
+ if (new_my != m_mouse_last_m[1])
{
- int diff = new_my - last_my;
+ int diff = new_my - m_mouse_last_m[1];
- /* check for wrap */
+ // check for wrap
if (diff > 0x80)
- diff = 0x100-diff;
- if (diff < -0x80)
- diff = -0x100-diff;
-
- count_y += diff;
+ diff -= 0x100;
+ else if (diff < -0x80)
+ diff += 0x100;
- last_my = new_my;
+ m_mouse_count[1] += diff;
+ m_mouse_last_m[1] = new_my;
}
- /* update any remaining count and then return */
- if (count_x)
+ // update any remaining count and then return
+ int x_needs_update = 0;
+ if (m_mouse_count[0] < 0)
{
- if (count_x < 0)
- {
- count_x++;
- m_mouse_bit_x = 0;
- x_needs_update = 2;
- }
- else
- {
- count_x--;
- m_mouse_bit_x = 1;
- x_needs_update = 1;
- }
+ m_mouse_count[0]++;
+ x_needs_update = -1;
}
- else if (count_y)
+ else if (m_mouse_count[0])
{
- if (count_y < 0)
- {
- count_y++;
- m_mouse_bit_y = 1;
- y_needs_update = 1;
- }
- else
- {
- count_y--;
- m_mouse_bit_y = 0;
- y_needs_update = 2;
- }
+ m_mouse_count[0]--;
+ x_needs_update = 1;
+ }
+ int y_needs_update = 0;
+ if (m_mouse_count[1] < 0)
+ {
+ m_mouse_count[1]++;
+ y_needs_update = 1;
+ }
+ else if (m_mouse_count[1])
+ {
+ m_mouse_count[1]--;
+ y_needs_update = -1;
}
if (x_needs_update || y_needs_update)
{
- /* assert Port B External Interrupt on the SCC */
- scc_mouse_irq(x_needs_update, y_needs_update );
+ // assert Port B External Interrupt on the SCC
+ scc_mouse_irq(x_needs_update, y_needs_update);
}
}
@@ -938,23 +813,17 @@ void mac128_state::mac_driver_init(mac128model_t model)
uint32_t mac128_state::screen_update_mac(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint32_t video_base;
- const uint16_t *video_ram;
- uint16_t word;
- uint16_t *line;
- int y, x, b;
-
- video_base = m_ram_size - (m_screen_buffer ? MAC_MAIN_SCREEN_BUF_OFFSET : MAC_ALT_SCREEN_BUF_OFFSET);
- video_ram = (const uint16_t *) (m_ram_ptr + video_base);
+ uint32_t const video_base = m_ram_size - (m_screen_buffer ? MAC_MAIN_SCREEN_BUF_OFFSET : MAC_ALT_SCREEN_BUF_OFFSET);
+ uint16_t const *video_ram = (const uint16_t *) (m_ram_ptr + video_base);
- for (y = 0; y < MAC_V_VIS; y++)
+ for (int y = 0; y < MAC_V_VIS; y++)
{
- line = &bitmap.pix16(y);
+ uint16_t *const line = &bitmap.pix(y);
- for (x = 0; x < MAC_H_VIS; x += 16)
+ for (int x = 0; x < MAC_H_VIS; x += 16)
{
- word = *(video_ram++);
- for (b = 0; b < 16; b++)
+ uint16_t const word = *(video_ram++);
+ for (int b = 0; b < 16; b++)
{
line[x + b] = (word >> (15 - b)) & 0x0001;
}
@@ -1170,10 +1039,10 @@ static INPUT_PORTS_START( macplus )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Button") PORT_CODE(MOUSECODE_BUTTON1)
PORT_START("MOUSE1") /* Mouse - X AXIS */
- PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0)
PORT_START("MOUSE2") /* Mouse - Y AXIS */
- PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0)
INPUT_PORTS_END
static INPUT_PORTS_START( macadb )
diff --git a/src/mame/drivers/macquadra700.cpp b/src/mame/drivers/macquadra700.cpp
new file mode 100644
index 00000000000..72a96568aed
--- /dev/null
+++ b/src/mame/drivers/macquadra700.cpp
@@ -0,0 +1,936 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/****************************************************************************
+
+ drivers/macquadra700.cpp
+ Mac Quadra 700 emulation. (900/950 are IOP-based and closer to the IIfx)
+
+ By R. Belmont
+
+****************************************************************************/
+
+#include "emu.h"
+
+#include "machine/macrtc.h"
+#include "cpu/m68000/m68000.h"
+#include "machine/6522via.h"
+#include "machine/applefdc.h"
+#include "machine/ram.h"
+#include "machine/sonydriv.h"
+#include "machine/swim.h"
+#include "machine/timer.h"
+#include "machine/z80scc.h"
+#include "machine/macadb.h"
+#include "machine/dp83932c.h"
+#include "sound/asc.h"
+#include "formats/ap_dsk35.h"
+
+#include "bus/nubus/nubus.h"
+#include "bus/nubus/nubus_48gc.h"
+#include "bus/nubus/nubus_cb264.h"
+#include "bus/nubus/nubus_vikbw.h"
+#include "bus/nubus/nubus_specpdq.h"
+#include "bus/nubus/nubus_m2hires.h"
+#include "bus/nubus/nubus_spec8.h"
+#include "bus/nubus/nubus_radiustpd.h"
+#include "bus/nubus/nubus_wsportrait.h"
+#include "bus/nubus/nubus_asntmc3b.h"
+#include "bus/nubus/nubus_image.h"
+#include "bus/nubus/nubus_m2video.h"
+#include "bus/nubus/bootbug.h"
+#include "bus/nubus/quadralink.h"
+#include "bus/nubus/laserview.h"
+
+#include "emupal.h"
+#include "screen.h"
+#include "softlist.h"
+#include "speaker.h"
+
+#define C7M (7833600)
+#define C15M (C7M*2)
+#define C32M (C15M*2)
+
+class macquadra_state : public driver_device
+{
+public:
+ macquadra_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_via1(*this, "via1"),
+ m_via2(*this, "via2"),
+ m_macadb(*this, "macadb"),
+ m_ram(*this, RAM_TAG),
+ m_iwm(*this, "fdc"),
+ m_rtc(*this,"rtc"),
+ m_sonic(*this, "sonic"),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette"),
+ m_easc(*this, "easc"),
+ m_scc(*this, "scc"),
+ m_vram(*this, "vram")
+ {
+ }
+
+ void macqd700(machine_config &config);
+ void quadra700_map(address_map &map);
+
+ void init_macqd700();
+
+private:
+ required_device<m68040_device> m_maincpu;
+ required_device<via6522_device> m_via1, m_via2;
+ optional_device<macadb_device> m_macadb;
+ required_device<ram_device> m_ram;
+ required_device<applefdc_base_device> m_iwm;
+ required_device<rtc3430042_device> m_rtc;
+ required_device<dp83932c_device> m_sonic;
+ required_device<screen_device> m_screen;
+ required_device<palette_device> m_palette;
+ required_device<asc_device> m_easc;
+ required_device<z80scc_device> m_scc;
+ required_shared_ptr<uint32_t> m_vram;
+
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+ uint32_t screen_update_dafb(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ uint32_t dafb_r(offs_t offset, uint32_t mem_mask = ~0);
+ void dafb_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ uint32_t dafb_dac_r(offs_t offset, uint32_t mem_mask = ~0);
+ void dafb_dac_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
+ void dafb_recalc_ints();
+
+ TIMER_CALLBACK_MEMBER(dafb_vbl_tick);
+ TIMER_CALLBACK_MEMBER(dafb_cursor_tick);
+ DECLARE_VIDEO_START(macdafb);
+ DECLARE_VIDEO_RESET(macdafb);
+
+ u32 *m_ram_ptr, *m_rom_ptr;
+ u32 m_ram_mask, m_ram_size, m_rom_size;
+
+ emu_timer *m_vbl_timer, *m_cursor_timer, *m_6015_timer;
+
+ uint16_t m_cursor_line;
+ uint16_t m_dafb_int_status;
+ int m_dafb_scsi1_drq, m_dafb_scsi2_drq;
+ uint8_t m_dafb_mode;
+ uint32_t m_dafb_base, m_dafb_stride;
+ uint32_t m_dafb_colors[3], m_dafb_count, m_dafb_clutoffs, m_dafb_montype, m_dafb_vbltime;
+ uint32_t m_dafb_palette[256];
+
+ DECLARE_WRITE_LINE_MEMBER(nubus_irq_9_w);
+ DECLARE_WRITE_LINE_MEMBER(nubus_irq_a_w);
+ DECLARE_WRITE_LINE_MEMBER(nubus_irq_b_w);
+ DECLARE_WRITE_LINE_MEMBER(nubus_irq_c_w);
+ DECLARE_WRITE_LINE_MEMBER(nubus_irq_d_w);
+ DECLARE_WRITE_LINE_MEMBER(nubus_irq_e_w);
+ void nubus_slot_interrupt(uint8_t slot, uint32_t state);
+ int m_via2_ca1_hack, m_nubus_irq_state;
+
+ WRITE_LINE_MEMBER(adb_irq_w) { m_adb_irq_pending = state; }
+ int m_adb_irq_pending;
+
+ DECLARE_WRITE_LINE_MEMBER(irq_539x_1_w);
+ DECLARE_WRITE_LINE_MEMBER(irq_539x_2_w);
+ DECLARE_WRITE_LINE_MEMBER(drq_539x_1_w);
+ DECLARE_WRITE_LINE_MEMBER(drq_539x_2_w);
+
+ uint16_t mac_via_r(offs_t offset);
+ void mac_via_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ uint16_t mac_via2_r(offs_t offset);
+ void mac_via2_w(offs_t offset, uint16_t data, uint16_t mem_mask);
+ uint8_t mac_via_in_a();
+ uint8_t mac_via_in_b();
+ void mac_via_out_a(uint8_t data);
+ void mac_via_out_b(uint8_t data);
+ uint8_t mac_via2_in_a();
+ uint8_t mac_via2_in_b();
+ void mac_via2_out_a(uint8_t data);
+ void mac_via2_out_b(uint8_t data);
+ void field_interrupts();
+ DECLARE_WRITE_LINE_MEMBER(mac_via_irq);
+ DECLARE_WRITE_LINE_MEMBER(mac_via2_irq);
+ TIMER_CALLBACK_MEMBER(mac_6015_tick);
+ WRITE_LINE_MEMBER(via_cb2_w) { m_macadb->adb_data_w(state); }
+ int m_via_cycles, m_via_interrupt, m_via2_interrupt, m_scc_interrupt, m_last_taken_interrupt;
+ int m_irq_count, m_ca1_data, m_ca2_data;
+
+ uint32_t rom_switch_r(offs_t offset);
+ bool m_overlay;
+
+ uint16_t mac_scc_r(offs_t offset)
+ {
+ uint16_t result = m_scc->dc_ab_r(offset);
+ return (result << 8) | result;
+ }
+ void mac_scc_2_w(offs_t offset, uint16_t data) { m_scc->dc_ab_w(offset, data >> 8); }
+
+ uint16_t mac_iwm_r(offs_t offset, uint16_t mem_mask)
+ {
+ uint16_t result = m_iwm->read(offset >> 8);
+ return (result << 8) | result;
+ }
+ void mac_iwm_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+ {
+ if (ACCESSING_BITS_0_7)
+ m_iwm->write((offset >> 8), data & 0xff);
+ else
+ m_iwm->write((offset >> 8), data>>8);
+ }
+};
+
+void macquadra_state::field_interrupts()
+{
+ int take_interrupt = -1;
+
+ if (m_scc_interrupt)
+ {
+ take_interrupt = 4;
+ }
+ else if (m_via2_interrupt)
+ {
+ take_interrupt = 2;
+ }
+ else if (m_via_interrupt)
+ {
+ take_interrupt = 1;
+ }
+
+ if (m_last_taken_interrupt > -1)
+ {
+ m_maincpu->set_input_line(m_last_taken_interrupt, CLEAR_LINE);
+ m_last_taken_interrupt = -1;
+ }
+
+ if (take_interrupt > -1)
+ {
+ m_maincpu->set_input_line(take_interrupt, ASSERT_LINE);
+ m_last_taken_interrupt = take_interrupt;
+ }
+}
+
+void macquadra_state::machine_start()
+{
+ m_ram_ptr = (u32*)m_ram->pointer();
+ m_ram_size = m_ram->size()>>1;
+ m_ram_mask = m_ram_size - 1;
+ m_rom_ptr = (u32*)memregion("bootrom")->base();
+ m_rom_size = memregion("bootrom")->bytes();
+ m_via_cycles = -50;
+ m_via_interrupt = m_via2_interrupt = m_scc_interrupt = 0;
+ m_last_taken_interrupt = -1;
+ m_irq_count = m_ca1_data = m_ca2_data = 0;
+
+ m_6015_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(macquadra_state::mac_6015_tick),this));
+ m_6015_timer->adjust(attotime::never);
+}
+
+void macquadra_state::machine_reset()
+{
+ m_nubus_irq_state = 0xff;
+ m_via2_ca1_hack = 1;
+ m_via2->write_ca1(1);
+ m_via2->write_cb1(1);
+ m_overlay = true;
+ m_via_interrupt = m_via2_interrupt = m_scc_interrupt = 0;
+ m_last_taken_interrupt = -1;
+ m_irq_count = m_ca1_data = m_ca2_data = 0;
+
+ // put ROM mirror at 0
+ address_space& space = m_maincpu->space(AS_PROGRAM);
+ const u32 memory_size = std::min((u32)0x3fffff, m_rom_size);
+ const u32 memory_end = memory_size - 1;
+ offs_t memory_mirror = memory_end & ~(memory_size - 1);
+
+ space.unmap_write(0x00000000, memory_end);
+ space.install_read_bank(0x00000000, memory_end & ~memory_mirror, memory_mirror, "bank1");
+ membank("bank1")->set_base(m_rom_ptr);
+
+ // start 60.15 Hz timer
+ m_6015_timer->adjust(attotime::from_hz(60.15), 0, attotime::from_hz(60.15));
+}
+
+void macquadra_state::init_macqd700()
+{
+}
+
+void macquadra_state::nubus_slot_interrupt(uint8_t slot, uint32_t state)
+{
+ static const uint8_t masks[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
+ uint8_t mask = 0xff;
+
+ slot -= 9;
+
+ if (state)
+ {
+ m_nubus_irq_state &= ~masks[slot];
+ }
+ else
+ {
+ m_nubus_irq_state |= masks[slot];
+ }
+
+ if ((m_nubus_irq_state & mask) != mask)
+ {
+ // HACK: sometimes we miss an ack (possible misbehavior in the VIA?)
+ if (m_via2_ca1_hack == 0)
+ {
+ m_via2->write_ca1(1);
+ }
+ m_via2_ca1_hack = 0;
+ m_via2->write_ca1(0);
+ }
+ else
+ {
+ m_via2_ca1_hack = 1;
+ m_via2->write_ca1(1);
+ }
+}
+
+WRITE_LINE_MEMBER(macquadra_state::nubus_irq_9_w) { nubus_slot_interrupt(9, state); }
+WRITE_LINE_MEMBER(macquadra_state::nubus_irq_a_w) { nubus_slot_interrupt(0xa, state); }
+WRITE_LINE_MEMBER(macquadra_state::nubus_irq_b_w) { nubus_slot_interrupt(0xb, state); }
+WRITE_LINE_MEMBER(macquadra_state::nubus_irq_c_w) { nubus_slot_interrupt(0xc, state); }
+WRITE_LINE_MEMBER(macquadra_state::nubus_irq_d_w) { nubus_slot_interrupt(0xd, state); }
+WRITE_LINE_MEMBER(macquadra_state::nubus_irq_e_w) { nubus_slot_interrupt(0xe, state); }
+
+// DAFB: video for Quadra 700/900
+
+void macquadra_state::dafb_recalc_ints()
+{
+ if (m_dafb_int_status != 0)
+ {
+ nubus_slot_interrupt(0xf, ASSERT_LINE);
+ }
+ else
+ {
+ nubus_slot_interrupt(0xf, CLEAR_LINE);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(macquadra_state::dafb_vbl_tick)
+{
+ m_dafb_int_status |= 1;
+ dafb_recalc_ints();
+
+ m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
+}
+
+TIMER_CALLBACK_MEMBER(macquadra_state::dafb_cursor_tick)
+{
+ m_dafb_int_status |= 4;
+ dafb_recalc_ints();
+
+ m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
+}
+
+VIDEO_START_MEMBER(macquadra_state,macdafb)
+{
+ m_vbl_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(macquadra_state::dafb_vbl_tick),this));
+ m_cursor_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(macquadra_state::dafb_cursor_tick),this));
+
+ m_vbl_timer->adjust(attotime::never);
+ m_cursor_timer->adjust(attotime::never);
+}
+
+VIDEO_RESET_MEMBER(macquadra_state,macdafb)
+{
+ m_dafb_count = 0;
+ m_dafb_clutoffs = 0;
+ m_dafb_montype = 6;
+ m_dafb_vbltime = 0;
+ m_dafb_int_status = 0;
+ m_dafb_mode = 0;
+ m_dafb_base = 0x1000;
+ m_dafb_stride = 256*4;
+
+ memset(m_dafb_palette, 0, sizeof(m_dafb_palette));
+}
+
+uint32_t macquadra_state::dafb_r(offs_t offset, uint32_t mem_mask)
+{
+// if (offset != 0x108/4) printf("DAFB: Read @ %x (mask %x PC=%x)\n", offset*4, mem_mask, m_maincpu->pc());
+
+ switch (offset<<2)
+ {
+ case 0x1c: // inverse of monitor sense
+ return 7; // 21" color 2-page
+
+ case 0x24: // SCSI 539x #1 status
+ return m_dafb_scsi1_drq<<9;
+
+ case 0x28: // SCSI 539x #2 status
+ return m_dafb_scsi2_drq<<9;
+
+ case 0x108: // IRQ/VBL status
+ return m_dafb_int_status;
+
+ case 0x10c: // clear cursor scanline int
+ m_dafb_int_status &= ~4;
+ dafb_recalc_ints();
+ break;
+
+ case 0x114: // clear VBL int
+ m_dafb_int_status &= ~1;
+ dafb_recalc_ints();
+ break;
+ }
+ return 0;
+}
+
+void macquadra_state::dafb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+// if (offset != 0x10c/4) printf("DAFB: Write %08x @ %x (mask %x PC=%x)\n", data, offset*4, mem_mask, m_maincpu->pc());
+
+ switch (offset<<2)
+ {
+ case 0: // bits 20-9 of base
+ m_dafb_base &= 0x1ff;
+ m_dafb_base |= (data & 0xffff) << 9;
+// printf("DAFB baseH: %x\n", m_dafb_base);
+ break;
+
+ case 4: // bits 8-5 of base
+ m_dafb_base &= ~0x1ff;
+ m_dafb_base |= (data & 0xf) << 5;
+// printf("DAFB baseL: %x\n", m_dafb_base);
+ break;
+
+ case 8:
+ m_dafb_stride = data<<2; // stride in DWORDs
+// printf("DAFB stride: %x %x\n", m_dafb_stride, data);
+ break;
+
+ case 0x104:
+ if (data & 1) // VBL enable
+ {
+ m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
+ }
+ else
+ {
+ m_vbl_timer->adjust(attotime::never);
+ m_dafb_int_status &= ~1;
+ dafb_recalc_ints();
+ }
+
+ if (data & 2) // aux scanline interrupt enable
+ {
+ fatalerror("DAFB: Aux scanline interrupt enable not supported!\n");
+ }
+
+ if (data & 4) // cursor scanline interrupt enable
+ {
+ m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
+ }
+ else
+ {
+ m_cursor_timer->adjust(attotime::never);
+ m_dafb_int_status &= ~4;
+ dafb_recalc_ints();
+ }
+ break;
+
+ case 0x10c: // clear cursor scanline int
+ m_dafb_int_status &= ~4;
+ dafb_recalc_ints();
+ break;
+
+ case 0x114: // clear VBL int
+ m_dafb_int_status &= ~1;
+ dafb_recalc_ints();
+ break;
+ }
+}
+
+uint32_t macquadra_state::dafb_dac_r(offs_t offset, uint32_t mem_mask)
+{
+// printf("DAFB: Read DAC @ %x (mask %x PC=%x)\n", offset*4, mem_mask, m_maincpu->pc());
+ return 0;
+}
+
+void macquadra_state::dafb_dac_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+// if ((offset > 0) && (offset != 0x10/4)) printf("DAFB: Write %08x to DAC @ %x (mask %x PC=%x)\n", data, offset*4, mem_mask, m_maincpu->pc());
+
+ switch (offset<<2)
+ {
+ case 0:
+ m_dafb_clutoffs = data & 0xff;
+ m_dafb_count = 0;
+ break;
+
+ case 0x10:
+ m_dafb_colors[m_dafb_count++] = data&0xff;
+
+ if (m_dafb_count == 3)
+ {
+ m_palette->set_pen_color(m_dafb_clutoffs, rgb_t(m_dafb_colors[0], m_dafb_colors[1], m_dafb_colors[2]));
+ m_dafb_palette[m_dafb_clutoffs] = rgb_t(m_dafb_colors[0], m_dafb_colors[1], m_dafb_colors[2]);
+ m_dafb_clutoffs++;
+ m_dafb_count = 0;
+ }
+ break;
+
+ case 0x20:
+ printf("%x to DAFB mode\n", data);
+ switch (data & 0x9f)
+ {
+ case 0x80:
+ m_dafb_mode = 0; // 1bpp
+ break;
+
+ case 0x88:
+ m_dafb_mode = 1; // 2bpp
+ break;
+
+ case 0x90:
+ m_dafb_mode = 2; // 4bpp
+ break;
+
+ case 0x98:
+ m_dafb_mode = 3; // 8bpp
+ break;
+
+ case 0x9c:
+ m_dafb_mode = 4; // 24bpp
+ break;
+ }
+ break;
+ }
+}
+
+uint32_t macquadra_state::screen_update_dafb(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ switch (m_dafb_mode)
+ {
+ case 0: // 1bpp
+ {
+ uint8_t const *vram8 = (uint8_t *)m_vram.target();
+ vram8 += m_dafb_base;
+
+ for (int y = 0; y < 870; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152; x+=8)
+ {
+ uint8_t const pixels = vram8[(y * m_dafb_stride) + ((x/8)^3)];
+
+ *scanline++ = m_dafb_palette[(pixels>>7)&1];
+ *scanline++ = m_dafb_palette[(pixels>>6)&1];
+ *scanline++ = m_dafb_palette[(pixels>>5)&1];
+ *scanline++ = m_dafb_palette[(pixels>>4)&1];
+ *scanline++ = m_dafb_palette[(pixels>>3)&1];
+ *scanline++ = m_dafb_palette[(pixels>>2)&1];
+ *scanline++ = m_dafb_palette[(pixels>>1)&1];
+ *scanline++ = m_dafb_palette[(pixels&1)];
+ }
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ {
+ uint8_t const *vram8 = (uint8_t *)m_vram.target();
+ vram8 += m_dafb_base;
+
+ for (int y = 0; y < 870; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152/4; x++)
+ {
+ uint8_t const pixels = vram8[(y * m_dafb_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_dafb_palette[((pixels>>6)&3)];
+ *scanline++ = m_dafb_palette[((pixels>>4)&3)];
+ *scanline++ = m_dafb_palette[((pixels>>2)&3)];
+ *scanline++ = m_dafb_palette[(pixels&3)];
+ }
+ }
+ }
+ break;
+
+ case 2: // 4bpp
+ {
+ uint8_t const *vram8 = (uint8_t *)m_vram.target();
+ vram8 += m_dafb_base;
+
+ for (int y = 0; y < 870; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152/2; x++)
+ {
+ uint8_t const pixels = vram8[(y * m_dafb_stride) + (BYTE4_XOR_BE(x))];
+
+ *scanline++ = m_dafb_palette[(pixels>>4)];
+ *scanline++ = m_dafb_palette[(pixels&0xf)];
+ }
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ {
+ uint8_t const *vram8 = (uint8_t *)m_vram.target();
+ vram8 += m_dafb_base;
+
+ for (int y = 0; y < 870; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ for (int x = 0; x < 1152; x++)
+ {
+ uint8_t const pixels = vram8[(y * m_dafb_stride) + (BYTE4_XOR_BE(x))];
+ *scanline++ = m_dafb_palette[pixels];
+ }
+ }
+ }
+ break;
+
+ case 4: // 24 bpp
+ for (int y = 0; y < 480; y++)
+ {
+ uint32_t *scanline = &bitmap.pix(y);
+ uint32_t const *base = (uint32_t *)&m_vram[(y * (m_dafb_stride/4)) + (m_dafb_base/4)];
+ for (int x = 0; x < 640; x++)
+ {
+ *scanline++ = *base++;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+WRITE_LINE_MEMBER(macquadra_state::drq_539x_1_w)
+{
+}
+
+WRITE_LINE_MEMBER(macquadra_state::drq_539x_2_w)
+{
+}
+
+WRITE_LINE_MEMBER(macquadra_state::irq_539x_1_w)
+{
+ if (state) // make sure a CB1 transition occurs
+ {
+ m_via2->write_cb2(0);
+ m_via2->write_cb2(1);
+ }
+}
+
+WRITE_LINE_MEMBER(macquadra_state::irq_539x_2_w)
+{
+}
+
+uint16_t macquadra_state::mac_via_r(offs_t offset)
+{
+ uint16_t data;
+
+ offset >>= 8;
+ offset &= 0x0f;
+
+ data = m_via1->read(offset);
+
+ m_maincpu->adjust_icount(m_via_cycles);
+
+ return (data & 0xff) | (data << 8);
+}
+
+void macquadra_state::mac_via_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (ACCESSING_BITS_0_7)
+ m_via1->write(offset, data & 0xff);
+ if (ACCESSING_BITS_8_15)
+ m_via1->write(offset, (data >> 8) & 0xff);
+
+ m_maincpu->adjust_icount(m_via_cycles);
+}
+
+WRITE_LINE_MEMBER(macquadra_state::mac_via_irq)
+{
+ m_via_interrupt = state;
+ field_interrupts();
+}
+
+WRITE_LINE_MEMBER(macquadra_state::mac_via2_irq)
+{
+ m_via2_interrupt = state;
+ field_interrupts();
+}
+
+uint16_t macquadra_state::mac_via2_r(offs_t offset)
+{
+ int data;
+
+ offset >>= 8;
+ offset &= 0x0f;
+
+ data = m_via2->read(offset);
+ return (data & 0xff) | (data << 8);
+}
+
+void macquadra_state::mac_via2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (ACCESSING_BITS_0_7)
+ m_via2->write(offset, data & 0xff);
+ if (ACCESSING_BITS_8_15)
+ m_via2->write(offset, (data >> 8) & 0xff);
+}
+
+uint32_t macquadra_state::rom_switch_r(offs_t offset)
+{
+ // disable the overlay
+ if (m_overlay)
+ {
+ address_space& space = m_maincpu->space(AS_PROGRAM);
+ const u32 memory_end = m_ram->size() - 1;
+ void *memory_data = m_ram->pointer();
+ offs_t memory_mirror = memory_end & ~memory_end;
+
+ space.install_readwrite_bank(0x00000000, memory_end & ~memory_mirror, memory_mirror, "bank1");
+ membank("bank1")->set_base(memory_data);
+ m_overlay = false;
+ }
+
+ //printf("rom_switch_r: offset %08x ROM_size -1 = %08x, masked = %08x\n", offset, m_rom_size-1, offset & ((m_rom_size - 1)>>2));
+
+ return m_rom_ptr[offset & ((m_rom_size - 1)>>2)];
+}
+
+TIMER_CALLBACK_MEMBER(macquadra_state::mac_6015_tick)
+{
+ m_via1->write_ca1(0);
+ m_via1->write_ca1(1);
+
+ /* handle ADB keyboard/mouse */
+ m_macadb->adb_vblank();
+
+ /* signal VBlank on CA1 input on the VIA */
+ m_ca1_data ^= 1;
+ m_via1->write_ca1(m_ca1_data);
+
+ if (++m_irq_count == 60)
+ {
+ m_irq_count = 0;
+
+ m_ca2_data ^= 1;
+ /* signal 1 Hz irq on CA2 input on the VIA */
+ m_via1->write_ca2(m_ca2_data);
+ }
+}
+
+/***************************************************************************
+ ADDRESS MAPS
+***************************************************************************/
+void macquadra_state::quadra700_map(address_map &map)
+{
+ map(0x40000000, 0x400fffff).r(FUNC(macquadra_state::rom_switch_r)).mirror(0x0ff00000);
+
+ map(0x50000000, 0x50001fff).rw(FUNC(macquadra_state::mac_via_r), FUNC(macquadra_state::mac_via_w)).mirror(0x00fc0000);
+ map(0x50002000, 0x50003fff).rw(FUNC(macquadra_state::mac_via2_r), FUNC(macquadra_state::mac_via2_w)).mirror(0x00fc0000);
+// 50008000 = Ethernet MAC ID PROM
+// 5000a000 = Sonic (DP83932) ethernet
+// 5000f000 = SCSI cf96, 5000f402 = SCSI #2 cf96
+// map(0x5000f000, 0x5000f3ff).rw(FUNC(macquadra_state::mac_5396_r), FUNC(macquadra_state::mac_5396_w)).mirror(0x00fc0000);
+ map(0x5000c000, 0x5000dfff).rw(FUNC(macquadra_state::mac_scc_r), FUNC(macquadra_state::mac_scc_2_w)).mirror(0x00fc0000);
+ map(0x50014000, 0x50015fff).rw(m_easc, FUNC(asc_device::read), FUNC(asc_device::write)).mirror(0x00fc0000);
+ map(0x5001e000, 0x5001ffff).rw(FUNC(macquadra_state::mac_iwm_r), FUNC(macquadra_state::mac_iwm_w)).mirror(0x00fc0000);
+
+ // f9800000 = VDAC / DAFB
+ map(0xf9000000, 0xf91fffff).ram().share("vram");
+ map(0xf9800000, 0xf98001ff).rw(FUNC(macquadra_state::dafb_r), FUNC(macquadra_state::dafb_w));
+ map(0xf9800200, 0xf980023f).rw(FUNC(macquadra_state::dafb_dac_r), FUNC(macquadra_state::dafb_dac_w));
+}
+
+uint8_t macquadra_state::mac_via_in_a()
+{
+ return 0xc1;
+}
+
+uint8_t macquadra_state::mac_via_in_b()
+{
+ int val = m_macadb->get_adb_state()<<4;
+ val |= m_rtc->data_r();
+
+ if (!m_adb_irq_pending)
+ {
+ val |= 0x08;
+ }
+
+// printf("%s VIA1 IN_B = %02x\n", machine().describe_context().c_str(), val);
+
+ return val;
+}
+
+void macquadra_state::mac_via_out_a(uint8_t data)
+{
+// printf("%s VIA1 OUT A: %02x\n", machine().describe_context().c_str(), data);
+ sony_set_sel_line(m_iwm.target(), (data & 0x20) >> 5);
+}
+
+void macquadra_state::mac_via_out_b(uint8_t data)
+{
+// printf("%s VIA1 OUT B: %02x\n", machine().describe_context().c_str(), data);
+ m_macadb->mac_adb_newaction((data & 0x30) >> 4);
+
+ m_rtc->ce_w((data & 0x04)>>2);
+ m_rtc->data_w(data & 0x01);
+ m_rtc->clk_w((data >> 1) & 0x01);
+}
+
+uint8_t macquadra_state::mac_via2_in_a()
+{
+ return 0x80 | m_nubus_irq_state;
+}
+
+uint8_t macquadra_state::mac_via2_in_b()
+{
+ return 0xcf; // indicate no NuBus transaction error
+}
+
+void macquadra_state::mac_via2_out_a(uint8_t data)
+{
+}
+
+void macquadra_state::mac_via2_out_b(uint8_t data)
+{
+ // chain 60.15 Hz to VIA1
+ m_via1->write_ca1(data>>7);
+}
+
+/***************************************************************************
+ DEVICE CONFIG
+***************************************************************************/
+
+static const applefdc_interface mac_iwm_interface =
+{
+ sony_set_lines,
+ sony_set_enable_lines,
+
+ sony_read_data,
+ sony_write_data,
+ sony_read_status
+};
+
+static const floppy_interface mac_floppy_interface =
+{
+ FLOPPY_STANDARD_3_5_DSHD,
+ LEGACY_FLOPPY_OPTIONS_NAME(apple35_mac),
+ "floppy_3_5"
+};
+
+static INPUT_PORTS_START( macadb )
+INPUT_PORTS_END
+
+/***************************************************************************
+ MACHINE DRIVERS
+***************************************************************************/
+
+static void mac_nubus_cards(device_slot_interface &device)
+{
+ device.option_add("m2video", NUBUS_M2VIDEO); /* Apple Macintosh II Video Card */
+ device.option_add("48gc", NUBUS_48GC); /* Apple 4*8 Graphics Card */
+ device.option_add("824gc", NUBUS_824GC); /* Apple 8*24 Graphics Card */
+ device.option_add("cb264", NUBUS_CB264); /* RasterOps ColorBoard 264 */
+ device.option_add("vikbw", NUBUS_VIKBW); /* Moniterm Viking board */
+ device.option_add("image", NUBUS_IMAGE); /* Disk Image Pseudo-Card */
+ device.option_add("specpdq", NUBUS_SPECPDQ); /* SuperMac Spectrum PDQ */
+ device.option_add("m2hires", NUBUS_M2HIRES); /* Apple Macintosh II Hi-Resolution Card */
+ device.option_add("spec8s3", NUBUS_SPEC8S3); /* SuperMac Spectrum/8 Series III */
+// device.option_add("thundergx", NUBUS_THUNDERGX); /* Radius Thunder GX (not yet) */
+ device.option_add("radiustpd", NUBUS_RADIUSTPD); /* Radius Two Page Display */
+ device.option_add("asmc3nb", NUBUS_ASNTMC3NB); /* Asante MC3NB Ethernet card */
+ device.option_add("portrait", NUBUS_WSPORTRAIT); /* Apple Macintosh II Portrait video card */
+ device.option_add("enetnb", NUBUS_APPLEENET); /* Apple NuBus Ethernet */
+ device.option_add("bootbug", NUBUS_BOOTBUG); /* Brigent BootBug debugger card */
+ device.option_add("quadralink", NUBUS_QUADRALINK); /* AE Quadralink serial card */
+ device.option_add("laserview", NUBUS_LASERVIEW); /* Sigma Designs LaserView monochrome video card */
+}
+
+void macquadra_state::macqd700(machine_config &config)
+{
+ /* basic machine hardware */
+ M68040(config, m_maincpu, 25000000);
+ m_maincpu->set_addrmap(AS_PROGRAM, &macquadra_state::quadra700_map);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_refresh_hz(75.08);
+ m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(1260));
+ m_screen->set_size(1152, 870);
+ m_screen->set_visarea(0, 1152-1, 0, 870-1);
+ m_screen->set_screen_update(FUNC(macquadra_state::screen_update_dafb));
+
+ MCFG_VIDEO_START_OVERRIDE(macquadra_state,macdafb)
+ MCFG_VIDEO_RESET_OVERRIDE(macquadra_state,macdafb)
+
+ PALETTE(config, m_palette).set_entries(256);
+
+ RTC3430042(config, m_rtc, XTAL(32'768));
+
+ LEGACY_IWM(config, m_iwm, &mac_iwm_interface);
+ sonydriv_floppy_image_device::legacy_2_drives_add(config, &mac_floppy_interface);
+
+ SCC85C30(config, m_scc, C7M);
+// m_scc->intrq_callback().set(FUNC(macquadra_state::set_scc_interrupt));
+
+ DP83932C(config, m_sonic, 20_MHz_XTAL);
+ m_sonic->set_bus(m_maincpu, 0);
+
+ nubus_device &nubus(NUBUS(config, "nubus", 0));
+ nubus.set_space(m_maincpu, AS_PROGRAM);
+ nubus.out_irq9_callback().set(FUNC(macquadra_state::nubus_irq_9_w));
+ nubus.out_irqa_callback().set(FUNC(macquadra_state::nubus_irq_a_w));
+ nubus.out_irqb_callback().set(FUNC(macquadra_state::nubus_irq_b_w));
+ nubus.out_irqc_callback().set(FUNC(macquadra_state::nubus_irq_c_w));
+ nubus.out_irqd_callback().set(FUNC(macquadra_state::nubus_irq_d_w));
+ nubus.out_irqe_callback().set(FUNC(macquadra_state::nubus_irq_e_w));
+ NUBUS_SLOT(config, "nbd", "nubus", mac_nubus_cards, nullptr);
+ NUBUS_SLOT(config, "nbe", "nubus", mac_nubus_cards, nullptr);
+
+ VIA6522(config, m_via1, C7M/10);
+ m_via1->readpa_handler().set(FUNC(macquadra_state::mac_via_in_a));
+ m_via1->readpb_handler().set(FUNC(macquadra_state::mac_via_in_b));
+ m_via1->writepa_handler().set(FUNC(macquadra_state::mac_via_out_a));
+ m_via1->writepb_handler().set(FUNC(macquadra_state::mac_via_out_b));
+ m_via1->irq_handler().set(FUNC(macquadra_state::mac_via_irq));
+ m_via1->cb2_handler().set(FUNC(macquadra_state::via_cb2_w));
+
+ VIA6522(config, m_via2, C7M/10);
+ m_via2->readpa_handler().set(FUNC(macquadra_state::mac_via2_in_a));
+ m_via2->readpb_handler().set(FUNC(macquadra_state::mac_via2_in_b));
+ m_via2->writepa_handler().set(FUNC(macquadra_state::mac_via2_out_a));
+ m_via2->writepb_handler().set(FUNC(macquadra_state::mac_via2_out_b));
+ m_via2->irq_handler().set(FUNC(macquadra_state::mac_via2_irq));
+
+ MACADB(config, m_macadb, C15M);
+ m_macadb->via_clock_callback().set(m_via1, FUNC(via6522_device::write_cb1));
+ m_macadb->via_data_callback().set(m_via1, FUNC(via6522_device::write_cb2));
+ m_macadb->adb_irq_callback().set(FUNC(macquadra_state::adb_irq_w));
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+ ASC(config, m_easc, C15M, asc_device::asc_type::EASC);
+// m_easc->irqf_callback().set(FUNC(macquadra_state::mac_asc_irq));
+ m_easc->add_route(0, "lspeaker", 1.0);
+ m_easc->add_route(1, "rspeaker", 1.0);
+
+ /* internal ram */
+ RAM(config, m_ram);
+ m_ram->set_default_size("4M");
+ m_ram->set_extra_options("8M,16M,32M,64M,68M,72M,80M,96M,128M");
+
+ SOFTWARE_LIST(config, "flop35_list").set_original("mac_flop");
+}
+
+ROM_START( macqd700 )
+ ROM_REGION32_BE(0x100000, "bootrom", 0)
+ ROM_LOAD( "420dbff3.rom", 0x000000, 0x100000, CRC(88ea2081) SHA1(7a8ee468d16e64f2ad10cb8d1a45e6f07cc9e212) )
+ROM_END
+
+COMP( 1991, macqd700, 0, 0, macqd700, macadb, macquadra_state, init_macqd700, "Apple Computer", "Macintosh Quadra 700", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/macrossp.cpp b/src/mame/drivers/macrossp.cpp
index 1202cbfcb02..cc8733ce38d 100644
--- a/src/mame/drivers/macrossp.cpp
+++ b/src/mame/drivers/macrossp.cpp
@@ -10,6 +10,7 @@ Driver by David Haywood
TODO:
- what is the 'BIOS' ROM for? it appears to be data tables and is very different between games but we don't map it anywhere
- convert tilemaps to devices?
+ - quizmoon title gfx/sound in attract mode is incorrect? reference: https://youtu.be/925rRv2JG50
68020 interrupts
lev 1 : 0x64 : 0000 084c - unknown..
diff --git a/src/mame/drivers/magicard.cpp b/src/mame/drivers/magicard.cpp
index 20a74fe5b1e..eec8a48e058 100644
--- a/src/mame/drivers/magicard.cpp
+++ b/src/mame/drivers/magicard.cpp
@@ -646,43 +646,40 @@ void magicard_state::video_start()
uint32_t magicard_state::screen_update_magicard(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int x, y;
- uint32_t count;
-
bitmap.fill(m_palette->black_pen(), cliprect); //TODO
if(!(SCC_DE_VREG)) //display enable
return 0;
- count = ((SCC_VSR_VREG) / 2);
+ uint32_t count = ((SCC_VSR_VREG) / 2);
if(SCC_FG_VREG) //4bpp gfx
{
- for(y = 0; y < 300; y++)
+ for(int y = 0; y < 300; y++)
{
- for(x = 0; x < 84; x++)
+ for(int x = 0; x < 84; x++)
{
uint32_t color;
color = ((m_magicram[count]) & 0x000f) >> 0;
if(cliprect.contains((x * 4) + 3, y))
- bitmap.pix32(y, (x * 4) + 3) = m_palette->pen(color);
+ bitmap.pix(y, (x * 4) + 3) = m_palette->pen(color);
color = ((m_magicram[count]) & 0x00f0) >> 4;
if(cliprect.contains((x * 4) + 2, y))
- bitmap.pix32(y, (x * 4) + 2) = m_palette->pen(color);
+ bitmap.pix(y, (x * 4) + 2) = m_palette->pen(color);
color = ((m_magicram[count]) & 0x0f00) >> 8;
if(cliprect.contains((x * 4) + 1, y))
- bitmap.pix32(y, (x * 4) + 1) = m_palette->pen(color);
+ bitmap.pix(y, (x * 4) + 1) = m_palette->pen(color);
color = ((m_magicram[count]) & 0xf000) >> 12;
if(cliprect.contains((x * 4) + 0, y))
- bitmap.pix32(y, (x * 4) + 0) = m_palette->pen(color);
+ bitmap.pix(y, (x * 4) + 0) = m_palette->pen(color);
count++;
}
@@ -690,21 +687,21 @@ uint32_t magicard_state::screen_update_magicard(screen_device &screen, bitmap_rg
}
else //8bpp gfx
{
- for(y = 0; y < 300; y++)
+ for(int y = 0; y < 300; y++)
{
- for(x = 0; x < 168; x++)
+ for(int x = 0; x < 168; x++)
{
uint32_t color;
color = ((m_magicram[count]) & 0x00ff) >> 0;
if(cliprect.contains((x * 2) + 1, y))
- bitmap.pix32(y, (x * 2) + 1) = m_palette->pen(color);
+ bitmap.pix(y, (x * 2) + 1) = m_palette->pen(color);
color = ((m_magicram[count]) & 0xff00) >> 8;
if(cliprect.contains((x * 2) + 0, y))
- bitmap.pix32(y, (x * 2) + 0) = m_palette->pen(color);
+ bitmap.pix(y, (x * 2) + 0) = m_palette->pen(color);
count++;
}
diff --git a/src/mame/drivers/marinedt.cpp b/src/mame/drivers/marinedt.cpp
index 79ed6144257..b0a4bdfdb75 100644
--- a/src/mame/drivers/marinedt.cpp
+++ b/src/mame/drivers/marinedt.cpp
@@ -205,8 +205,8 @@ void marinedt_state::init_seabitmap()
if(blue_pen > 0x5f)
blue_pen = 0x5f;
- m_seabitmap[0]->pix16(y, x) = blue_pen;
- m_seabitmap[1]->pix16(y, x) = blue_pen+0x20;
+ m_seabitmap[0]->pix(y, x) = blue_pen;
+ m_seabitmap[1]->pix(y, x) = blue_pen+0x20;
}
}
}
@@ -360,11 +360,11 @@ inline uint32_t marinedt_state::obj_to_obj_collision()
resx = m_obj[0].x + x;
resy = m_obj[0].y + y;
- if((m_obj[0].bitmap.pix16(resy,resx) & 3) == 0)
+ if((m_obj[0].bitmap.pix(resy,resx) & 3) == 0)
continue;
// return value is never read most likely
- if(m_obj[1].bitmap.pix16(resy,resx) != 0)
+ if(m_obj[1].bitmap.pix(resy,resx) != 0)
return ((resy / 8) * 32) | (((resx / 8) - 1) & 0x1f);
}
}
@@ -387,14 +387,14 @@ inline uint32_t marinedt_state::obj_to_layer_collision()
resx = m_obj[0].x + x;
resy = m_obj[0].y + y;
- if((m_obj[0].bitmap.pix16(resy,resx) & 3) == 0)
+ if((m_obj[0].bitmap.pix(resy,resx) & 3) == 0)
continue;
if(!m_screen_flip)
resy -= 32;
// TODO: non screen flip path doesn't work properly
- if(m_tilemap->pixmap().pix16(resy,resx) != 0)
+ if(m_tilemap->pixmap().pix(resy,resx) != 0)
{
if(m_screen_flip)
return ((resy / 8) * 32) | (((resx / 8) - 1) & 0x1f);
diff --git a/src/mame/drivers/maygayv1.cpp b/src/mame/drivers/maygayv1.cpp
index 4459418d0cc..b0f686a348d 100644
--- a/src/mame/drivers/maygayv1.cpp
+++ b/src/mame/drivers/maygayv1.cpp
@@ -329,7 +329,6 @@ uint32_t maygayv1_state::screen_update_maygayv1(screen_device &screen, bitmap_in
uint16_t *atable = &i82716.dram[VREG(ATBA)];
uint16_t *otable = &i82716.dram[VREG(ODTBA) & 0xfc00]; // both must be bank 0
- int sl, sx;
int slmask = 0xffff; // TODO: Save if using scanline callbacks
int xbound = (VREG(DWBA) & 0x3f8) | 7;
@@ -344,13 +343,12 @@ uint32_t maygayv1_state::screen_update_maygayv1(screen_device &screen, bitmap_in
}
/* For every scanline... */
- for (sl = cliprect.min_x; sl <= cliprect.max_y; ++sl)
+ for (int sl = cliprect.min_x; sl <= cliprect.max_y; ++sl)
{
- int obj;
uint16_t aflags = atable[sl];
uint16_t slmask_old = slmask;
- uint16_t *bmp_ptr = &bitmap.pix16(sl);
+ uint16_t *bmp_ptr = &bitmap.pix(sl);
slmask = 0xffff ^ (slmask ^ aflags);
@@ -359,7 +357,7 @@ uint32_t maygayv1_state::screen_update_maygayv1(screen_device &screen, bitmap_in
memset(i82716.line_buf.get(), 0x22, 512);
/* Parse the list of 16 objects */
- for (obj = 0; obj < 16; ++obj)
+ for (int obj = 0; obj < 16; ++obj)
{
int offs = obj * 4;
@@ -367,7 +365,7 @@ uint32_t maygayv1_state::screen_update_maygayv1(screen_device &screen, bitmap_in
if ( !BIT(slmask, obj) )
{
uint32_t objbase, trans, width;
- int32_t x, xpos;
+ int32_t xpos;
uint16_t w0, w1, w2;
uint16_t *objptr;
uint8_t *bmpptr; // ?
@@ -419,7 +417,7 @@ uint32_t maygayv1_state::screen_update_maygayv1(screen_device &screen, bitmap_in
bmpptr = (uint8_t*)objptr;
// 4bpp
- for (x = xpos; x < std::min(xbound, int(xpos + width * 8)); ++x)
+ for (int x = xpos; x < std::min(xbound, int(xpos + width * 8)); ++x)
{
if (x >= 0)
{
@@ -441,7 +439,7 @@ uint32_t maygayv1_state::screen_update_maygayv1(screen_device &screen, bitmap_in
}
// Write it out
- for (sx = cliprect.min_x; sx < cliprect.max_x; sx += 2)
+ for (int sx = cliprect.min_x; sx < cliprect.max_x; sx += 2)
{
uint8_t pix = i82716.line_buf[sx / 2];
diff --git a/src/mame/drivers/mbc200.cpp b/src/mame/drivers/mbc200.cpp
index 369cb6ee117..64e89698e6b 100644
--- a/src/mame/drivers/mbc200.cpp
+++ b/src/mame/drivers/mbc200.cpp
@@ -268,15 +268,13 @@ static void mbc200_floppies(device_slot_interface &device)
MC6845_UPDATE_ROW( mbc200_state::update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 gfx;
- u16 mem,x;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u32 *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (u16 x = 0; x < x_count; x++)
{
- mem = (ma+x)*4+ra;
- gfx = m_vram[mem & 0x7fff];
+ u16 mem = (ma+x)*4+ra;
+ u8 gfx = m_vram[mem & 0x7fff];
*p++ = palette[BIT(gfx, 7)];
*p++ = palette[BIT(gfx, 6)];
*p++ = palette[BIT(gfx, 5)];
diff --git a/src/mame/drivers/mbee.cpp b/src/mame/drivers/mbee.cpp
index b99e0220a08..3df643bf789 100644
--- a/src/mame/drivers/mbee.cpp
+++ b/src/mame/drivers/mbee.cpp
@@ -685,7 +685,7 @@ void mbee_state::mbee(machine_config &config)
QUICKLOAD(config, "quickload", "mwb,com,bee", attotime::from_seconds(3)).set_load_callback(FUNC(mbee_state::quickload_bee));
QUICKLOAD(config, "quickload2", "bin", attotime::from_seconds(3)).set_load_callback(FUNC(mbee_state::quickload_bin));
- CENTRONICS(config, m_centronics, centronics_devices, "printer");
+ CENTRONICS(config, m_centronics, centronics_devices, nullptr);
m_centronics->ack_handler().set(m_pio, FUNC(z80pio_device::strobe_a));
OUTPUT_LATCH(config, m_cent_data_out);
@@ -820,6 +820,7 @@ void mbee_state::mbee256(machine_config &config)
config.device_remove("fdc:1");
FLOPPY_CONNECTOR(config, m_floppy0, mbee_floppies, "35dd", floppy_image_device::default_floppy_formats).enable_sound(true);
FLOPPY_CONNECTOR(config, m_floppy1, mbee_floppies, "35dd", floppy_image_device::default_floppy_formats).enable_sound(true);
+ TIMER(config, "newkb_timer").configure_periodic(FUNC(mbee_state::newkb_timer), attotime::from_hz(50));
}
void mbee_state::mbeett(machine_config &config)
@@ -829,6 +830,7 @@ void mbee_state::mbeett(machine_config &config)
m_maincpu->set_addrmap(AS_IO, &mbee_state::mbeett_io);
config.device_remove("quickload");
config.device_remove("quickload2");
+ TIMER(config, "newkb_timer").configure_periodic(FUNC(mbee_state::newkb_timer), attotime::from_hz(50));
SCC8530(config, "scc", 4000000); // clock unknown
}
@@ -866,7 +868,7 @@ ROM_START( mbee )
ROM_RELOAD( 0x0800, 0x0800 )
ROM_REGION( 0x0020, "proms", 0 )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0000, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0000, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbeeic )
@@ -888,7 +890,7 @@ ROM_START( mbeeic )
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbeepc )
@@ -910,7 +912,7 @@ ROM_START( mbeepc )
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbeepc85 )
@@ -936,7 +938,7 @@ ROM_START( mbeepc85 )
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbeepc85b )
@@ -963,7 +965,7 @@ ROM_START( mbeepc85b )
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbeepc85s )
@@ -988,7 +990,7 @@ ROM_START( mbeepc85s )
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbeett )
@@ -1045,7 +1047,7 @@ ROM_START( mbee56 )
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbee128 ) // Standard 128k (CIAB is the same thing with half the ram)
@@ -1060,7 +1062,7 @@ ROM_START( mbee128 ) // Standard 128k (CIAB is the same thing with half the ram)
ROM_REGION( 0x0040, "proms", 0 )
ROM_LOAD( "82s123.ic7", 0x0000, 0x0020, CRC(61b9c16c) SHA1(0ee72377831c21339360c376f7248861d476dc20) )
- ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(4e779985) SHA1(cd2579cf65032c30b3fe7d6d07b89d4633687481) ) /* video switching prom, not needed for emulation purposes */
+ ROM_LOAD_OPTIONAL( "82s123.ic16", 0x0020, 0x0020, CRC(79fa1e9d) SHA1(0454051697b23e4561744466fb31e7a133d02246) ) /* video switching prom, not needed for emulation purposes */
ROM_END
ROM_START( mbee128p ) // Premium 128K
diff --git a/src/mame/drivers/mc8020.cpp b/src/mame/drivers/mc8020.cpp
index 2a72b138d99..bcdd4f3c1fc 100644
--- a/src/mame/drivers/mc8020.cpp
+++ b/src/mame/drivers/mc8020.cpp
@@ -72,18 +72,18 @@ void mc8020_state::io_map(address_map &map)
/* Input ports */
static INPUT_PORTS_START( mc8020 )
PORT_START("X0")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('!')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('@')
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('#')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('$')
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('%')
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('&')
- PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('\'')
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('(')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(34)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
PORT_START("X1")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('9') PORT_CHAR(')')
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('0') PORT_CHAR('\"')
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('+') PORT_CHAR('*')
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('^')
@@ -133,13 +133,13 @@ static INPUT_PORTS_START( mc8020 )
PORT_START("X6")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN)
- PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT)
- PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL)
- PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
INPUT_PORTS_END
@@ -187,7 +187,7 @@ void mc8020_state::machine_start()
// This is not a content of U402 510
// but order is fine
static const uint8_t prom[] = {
- 0x0c,0x11,0x13,0x15,0x17,0x10,0x0e,0x00, // @
+ 0x0e,0x11,0x13,0x15,0x17,0x10,0x0e,0x00, // @
0x04,0x0a,0x11,0x11,0x1f,0x11,0x11,0x00, // A
0x1e,0x11,0x11,0x1e,0x11,0x11,0x1e,0x00, // B
0x0e,0x11,0x10,0x10,0x10,0x11,0x0e,0x00, // C
@@ -263,20 +263,20 @@ static const uint8_t prom[] = {
uint32_t mc8020_state::screen_update_mc8020(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,chr,gfx;
- uint16_t sy=0,ma=0,x;
+ u16 sy=0,ma=0;
- for(y = 0; y < 8; y++ )
+ for (u8 y = 0; y < 8; y++ )
{
- for (ra = 0; ra < 16; ra++)
+ for (u8 ra = 0; ra < 16; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 32; x++)
+ for (u16 x = ma; x < ma + 32; x++)
{
+ u8 gfx;
if (ra > 3 && ra < 12)
{
- chr = m_p_videoram[x];
+ u8 chr = m_p_videoram[x];
gfx = prom[(chr<<3) | (ra-4)];
}
else
diff --git a/src/mame/drivers/mc8030.cpp b/src/mame/drivers/mc8030.cpp
index a3b35bd5f2d..e8f0abcdfe1 100644
--- a/src/mame/drivers/mc8030.cpp
+++ b/src/mame/drivers/mc8030.cpp
@@ -145,27 +145,24 @@ uint8_t mc8030_state::asp_port_b_r()
uint32_t mc8030_state::screen_update_mc8030(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t gfx;
- uint16_t y=0,ma=0,x;
+ uint16_t ma=0;
- for(y = 0; y < 256; y++ )
+ for(uint16_t y = 0; y < 256; y++ )
{
- uint16_t *p = &bitmap.pix16(y);
+ uint16_t *p = &bitmap.pix(y);
+ for (uint16_t x = ma; x < ma + 64; x++)
{
- for (x = ma; x < ma + 64; x++)
- {
- gfx = m_vram[x^0x3fff];
-
- /* Display a scanline of a character */
- *p++ = BIT(gfx, 7);
- *p++ = BIT(gfx, 6);
- *p++ = BIT(gfx, 5);
- *p++ = BIT(gfx, 4);
- *p++ = BIT(gfx, 3);
- *p++ = BIT(gfx, 2);
- *p++ = BIT(gfx, 1);
- *p++ = BIT(gfx, 0);
- }
+ uint8_t const gfx = m_vram[x^0x3fff];
+
+ /* Display a scanline of a character */
+ *p++ = BIT(gfx, 7);
+ *p++ = BIT(gfx, 6);
+ *p++ = BIT(gfx, 5);
+ *p++ = BIT(gfx, 4);
+ *p++ = BIT(gfx, 3);
+ *p++ = BIT(gfx, 2);
+ *p++ = BIT(gfx, 1);
+ *p++ = BIT(gfx, 0);
}
ma+=64;
}
diff --git a/src/mame/drivers/mdt60.cpp b/src/mame/drivers/mdt60.cpp
index 63669bbf0f9..45623589d4f 100644
--- a/src/mame/drivers/mdt60.cpp
+++ b/src/mame/drivers/mdt60.cpp
@@ -108,7 +108,7 @@ TIMER_CALLBACK_MEMBER(mdt60_state::baud_timer)
MC6845_UPDATE_ROW(mdt60_state::update_row)
{
- u32 *pix = &bitmap.pix32(y);
+ u32 *pix = &bitmap.pix(y);
for (unsigned x = 0; x < x_count; x++)
{
diff --git a/src/mame/drivers/mediagx.cpp b/src/mame/drivers/mediagx.cpp
index 353f25ab02d..6e20ffb9e58 100644
--- a/src/mame/drivers/mediagx.cpp
+++ b/src/mame/drivers/mediagx.cpp
@@ -266,19 +266,17 @@ void mediagx_state::video_start()
void mediagx_state::draw_char(bitmap_rgb32 &bitmap, const rectangle &cliprect, gfx_element *gfx, int ch, int att, int x, int y)
{
- int i,j;
- const uint8_t *dp;
int index = 0;
- const pen_t *pens = &m_palette->pen(0);
+ pen_t const *const pens = &m_palette->pen(0);
- dp = gfx->get_data(ch);
+ uint8_t const *const dp = gfx->get_data(ch);
- for (j=y; j < y+8; j++)
+ for (int j=y; j < y+8; j++)
{
- uint32_t *p = &bitmap.pix32(j);
- for (i=x; i < x+8; i++)
+ uint32_t *const p = &bitmap.pix(j);
+ for (int i=x; i < x+8; i++)
{
- uint8_t pen = dp[index++];
+ uint8_t const pen = dp[index++];
if (pen)
p[i] = pens[gfx->colorbase() + (att & 0xf)];
else
@@ -292,18 +290,16 @@ void mediagx_state::draw_char(bitmap_rgb32 &bitmap, const rectangle &cliprect, g
void mediagx_state::draw_framebuffer(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int i, j;
- int width, height;
- int line_delta = (m_disp_ctrl_reg[DC_LINE_DELTA] & 0x3ff) * 4;
+ int const line_delta = (m_disp_ctrl_reg[DC_LINE_DELTA] & 0x3ff) * 4;
- width = (m_disp_ctrl_reg[DC_H_TIMING_1] & 0x7ff) + 1;
+ int width = (m_disp_ctrl_reg[DC_H_TIMING_1] & 0x7ff) + 1;
if (m_disp_ctrl_reg[DC_TIMING_CFG] & 0x8000) // pixel double
{
width >>= 1;
}
width += 4;
- height = (m_disp_ctrl_reg[DC_V_TIMING_1] & 0x7ff) + 1;
+ int height = (m_disp_ctrl_reg[DC_V_TIMING_1] & 0x7ff) + 1;
if ( (width != m_frame_width || height != m_frame_height) &&
(width > 1 && height > 1 && width <= 640 && height <= 480) )
@@ -319,19 +315,19 @@ void mediagx_state::draw_framebuffer(bitmap_rgb32 &bitmap, const rectangle &clip
if (m_disp_ctrl_reg[DC_OUTPUT_CFG] & 0x1) // 8-bit mode
{
- uint8_t *framebuf = (uint8_t*)&m_vram[m_disp_ctrl_reg[DC_FB_ST_OFFSET]/4];
- uint8_t *pal = m_pal;
+ uint8_t const *const framebuf = (uint8_t const *)&m_vram[m_disp_ctrl_reg[DC_FB_ST_OFFSET]/4];
+ uint8_t const *const pal = m_pal;
- for (j=0; j < m_frame_height; j++)
+ for (int j=0; j < m_frame_height; j++)
{
- uint32_t *p = &bitmap.pix32(j);
- uint8_t *si = &framebuf[j * line_delta];
- for (i=0; i < m_frame_width; i++)
+ uint32_t *const p = &bitmap.pix(j);
+ uint8_t const *si = &framebuf[j * line_delta];
+ for (int i=0; i < m_frame_width; i++)
{
- int c = *si++;
- int r = pal[(c*3)+0] << 2;
- int g = pal[(c*3)+1] << 2;
- int b = pal[(c*3)+2] << 2;
+ int const c = *si++;
+ int const r = pal[(c*3)+0] << 2;
+ int const g = pal[(c*3)+1] << 2;
+ int const b = pal[(c*3)+2] << 2;
p[i] = r << 16 | g << 8 | b;
}
@@ -339,21 +335,21 @@ void mediagx_state::draw_framebuffer(bitmap_rgb32 &bitmap, const rectangle &clip
}
else // 16-bit
{
- uint16_t *framebuf = (uint16_t*)&m_vram[m_disp_ctrl_reg[DC_FB_ST_OFFSET]/4];
+ uint16_t const *const framebuf = (uint16_t const *)&m_vram[m_disp_ctrl_reg[DC_FB_ST_OFFSET]/4];
// RGB 5-6-5 mode
if ((m_disp_ctrl_reg[DC_OUTPUT_CFG] & 0x2) == 0)
{
- for (j=0; j < m_frame_height; j++)
+ for (int j=0; j < m_frame_height; j++)
{
- uint32_t *p = &bitmap.pix32(j);
- uint16_t *si = &framebuf[j * (line_delta/2)];
- for (i=0; i < m_frame_width; i++)
+ uint32_t *const p = &bitmap.pix(j);
+ uint16_t const *si = &framebuf[j * (line_delta/2)];
+ for (int i=0; i < m_frame_width; i++)
{
- uint16_t c = *si++;
- int r = ((c >> 11) & 0x1f) << 3;
- int g = ((c >> 5) & 0x3f) << 2;
- int b = (c & 0x1f) << 3;
+ uint16_t const c = *si++;
+ int const r = ((c >> 11) & 0x1f) << 3;
+ int const g = ((c >> 5) & 0x3f) << 2;
+ int const b = (c & 0x1f) << 3;
p[i] = r << 16 | g << 8 | b;
}
@@ -362,16 +358,16 @@ void mediagx_state::draw_framebuffer(bitmap_rgb32 &bitmap, const rectangle &clip
// RGB 5-5-5 mode
else
{
- for (j=0; j < m_frame_height; j++)
+ for (int j=0; j < m_frame_height; j++)
{
- uint32_t *p = &bitmap.pix32(j);
- uint16_t *si = &framebuf[j * (line_delta/2)];
- for (i=0; i < m_frame_width; i++)
+ uint32_t *const p = &bitmap.pix(j);
+ uint16_t const *si = &framebuf[j * (line_delta/2)];
+ for (int i=0; i < m_frame_width; i++)
{
- uint16_t c = *si++;
- int r = ((c >> 10) & 0x1f) << 3;
- int g = ((c >> 5) & 0x1f) << 3;
- int b = (c & 0x1f) << 3;
+ uint16_t const c = *si++;
+ int const r = ((c >> 10) & 0x1f) << 3;
+ int const g = ((c >> 5) & 0x1f) << 3;
+ int const b = (c & 0x1f) << 3;
p[i] = r << 16 | g << 8 | b;
}
diff --git a/src/mame/drivers/megadriv_rad.cpp b/src/mame/drivers/megadriv_rad.cpp
index e0abb5b2f6c..fb4c4d52d2f 100644
--- a/src/mame/drivers/megadriv_rad.cpp
+++ b/src/mame/drivers/megadriv_rad.cpp
@@ -195,7 +195,12 @@ ROM_START( rad_sonic )
ROM_LOAD16_WORD_SWAP( "supersonicgold.bin", 0x000000, 0x400000, CRC(853c9140) SHA1(cf70a9cdd3be4d8d1b6195698db3a941f4908791) )
ROM_END
-
+// once byteswapped this matches "outrun 2019 (usa) (beta).bin megadriv:outr2019up Out Run 2019 (USA, Prototype)"
+// this was dumped from a PAL/UK unit, so maybe that 'beta' is really an alt Euro release, or was simply dumped from one of these Radica units and mislabeled?
+ROM_START( rad_orun )
+ ROM_REGION( 0x400000, "maincpu", ROMREGION_ERASEFF )
+ ROM_LOAD16_WORD_SWAP( "outrun.bin", 0x000000, 0x100000, CRC(4fd6d653) SHA1(57f0e4550ff883e4bb7857caef2c893c21f80b42) )
+ROM_END
void megadriv_radica_state::init_megadriv_radica_6button_pal()
@@ -224,3 +229,4 @@ CONS( 2004, rad_sf2p, rad_sf2,0, megadriv_radica_6button_pal, megadriv_radica_6
CONS( 2004, rad_ssoc, 0, 0, megadriv_radica_3button_pal, megadriv_radica_3button, megadriv_radica_state, init_megadrie, "Radica / Sensible Software / Sega", "Sensible Soccer plus [Cannon Fodder, Mega lo Mania] (Radica, Arcade Legends) (Europe)", 0) // still branded as Arcade Legends even if none of these were ever arcade games
+CONS( 2004, rad_orun, 0, 0, megadriv_radica_3button_pal, megadriv_radica_3button_1player, megadriv_radica_state, init_megadrie, "Radica / Sega", "Out Run 2019 (Radica Plug & Play, Europe)", 0)
diff --git a/src/mame/drivers/megaplay.cpp b/src/mame/drivers/megaplay.cpp
index 8b0f4011e38..be3943762bd 100644
--- a/src/mame/drivers/megaplay.cpp
+++ b/src/mame/drivers/megaplay.cpp
@@ -633,9 +633,9 @@ uint32_t mplay_state::screen_update_megplay(screen_device &screen, bitmap_rgb32
const u32 width = sega315_5124_device::WIDTH - (sega315_5124_device::LBORDER_START + sega315_5124_device::LBORDER_WIDTH);
for (int y = 0; y < 224; y++)
{
- uint32_t* lineptr = &bitmap.pix32(y);
- uint32_t* srcptr = &m_vdp1->get_bitmap().pix32(y + sega315_5124_device::TBORDER_START + sega315_5124_device::NTSC_224_TBORDER_HEIGHT, sega315_5124_device::LBORDER_START + sega315_5124_device::LBORDER_WIDTH);
- uint8_t* y1ptr = &m_vdp1->get_y1_bitmap().pix8(y + sega315_5124_device::TBORDER_START + sega315_5124_device::NTSC_224_TBORDER_HEIGHT, sega315_5124_device::LBORDER_START + sega315_5124_device::LBORDER_WIDTH);
+ uint32_t *const lineptr = &bitmap.pix(y);
+ uint32_t const *const srcptr = &m_vdp1->get_bitmap().pix(y + sega315_5124_device::TBORDER_START + sega315_5124_device::NTSC_224_TBORDER_HEIGHT, sega315_5124_device::LBORDER_START + sega315_5124_device::LBORDER_WIDTH);
+ uint8_t const *const y1ptr = &m_vdp1->get_y1_bitmap().pix(y + sega315_5124_device::TBORDER_START + sega315_5124_device::NTSC_224_TBORDER_HEIGHT, sega315_5124_device::LBORDER_START + sega315_5124_device::LBORDER_WIDTH);
for (int srcx = 0, xx = 0, dstx = 0; srcx < width; dstx++)
{
diff --git a/src/mame/drivers/megatech.cpp b/src/mame/drivers/megatech.cpp
index d13980ffad6..5b1f42d7a66 100644
--- a/src/mame/drivers/megatech.cpp
+++ b/src/mame/drivers/megatech.cpp
@@ -627,8 +627,8 @@ uint32_t mtech_state::screen_update_main(screen_device &screen, bitmap_rgb32 &bi
// when launching megatech + both sms and megadrive games, the following would be needed...
for (int y = 0; y < 224; y++)
{
- uint32_t* lineptr = &bitmap.pix32(y);
- uint32_t* srcptr = &m_vdp->get_bitmap().pix32(y + sega315_5124_device::TBORDER_START + sega315_5124_device::NTSC_224_TBORDER_HEIGHT);
+ uint32_t* lineptr = &bitmap.pix(y);
+ uint32_t* srcptr = &m_vdp->get_bitmap().pix(y + sega315_5124_device::TBORDER_START + sega315_5124_device::NTSC_224_TBORDER_HEIGHT);
for (int x = 0; x < sega315_5124_device::WIDTH; x++)
lineptr[x] = srcptr[x];
diff --git a/src/mame/drivers/meijinsn.cpp b/src/mame/drivers/meijinsn.cpp
index 0778c284c18..09fc80ded0a 100644
--- a/src/mame/drivers/meijinsn.cpp
+++ b/src/mame/drivers/meijinsn.cpp
@@ -324,7 +324,7 @@ uint32_t meijinsn_state::screen_update_meijinsn(screen_device &screen, bitmap_in
{
color= BIT(data1, x) | (BIT(data1, x + 4) << 1);
data = BIT(data2, x) | (BIT(data2, x + 4) << 1);
- bitmap.pix16(sy, (sx * 4 + (3 - x))) = color * 4 + data;
+ bitmap.pix(sy, (sx * 4 + (3 - x))) = color * 4 + data;
}
}
return 0;
diff --git a/src/mame/drivers/mekd2.cpp b/src/mame/drivers/mekd2.cpp
index b0f06299280..b46e73fbcde 100644
--- a/src/mame/drivers/mekd2.cpp
+++ b/src/mame/drivers/mekd2.cpp
@@ -89,11 +89,6 @@ TODO
class mekd2_state : public driver_device
{
public:
- enum
- {
- TIMER_TRACE
- };
-
mekd2_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
@@ -101,6 +96,7 @@ public:
, m_pia_u(*this, "pia_u")
, m_acia(*this, "acia")
, m_cass(*this, "cassette")
+ , m_trace_timer(*this, "trace_timer")
, m_digits(*this, "digit%u", 0U)
{ }
@@ -115,10 +111,10 @@ private:
DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb);
TIMER_DEVICE_CALLBACK_MEMBER(kansas_w);
TIMER_DEVICE_CALLBACK_MEMBER(kansas_r);
+ TIMER_DEVICE_CALLBACK_MEMBER(trace_timer);
void mem_map(address_map &map);
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
uint8_t m_cass_data[4];
uint8_t m_segment;
uint8_t m_digit;
@@ -131,6 +127,7 @@ private:
required_device<pia6821_device> m_pia_u;
required_device<acia6850_device> m_acia;
required_device<cassette_image_device> m_cass;
+ required_device<timer_device> m_trace_timer;
output_finder<6> m_digits;
};
@@ -203,16 +200,9 @@ INPUT_PORTS_END
************************************************************/
-void mekd2_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_DEVICE_CALLBACK_MEMBER(mekd2_state::trace_timer)
{
- switch (id)
- {
- case TIMER_TRACE:
- m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
- break;
- default:
- throw emu_fatalerror("Unknown id in mekd2_state::device_timer");
- }
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
}
@@ -221,7 +211,7 @@ WRITE_LINE_MEMBER( mekd2_state::nmi_w )
if (state)
m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
else
- timer_set(attotime::from_usec(18), TIMER_TRACE);
+ m_trace_timer->adjust(attotime::from_usec(18));
}
@@ -406,6 +396,7 @@ void mekd2_state::mekd2(machine_config &config)
TIMER(config, "kansas_w").configure_periodic(FUNC(mekd2_state::kansas_w), attotime::from_hz(4800));
TIMER(config, "kansas_r").configure_periodic(FUNC(mekd2_state::kansas_r), attotime::from_hz(40000));
+ TIMER(config, m_trace_timer).configure_generic(FUNC(mekd2_state::trace_timer));
QUICKLOAD(config, "quickload", "d2", attotime::from_seconds(1)).set_load_callback(FUNC(mekd2_state::quickload_cb));
}
diff --git a/src/mame/drivers/mekd3.cpp b/src/mame/drivers/mekd3.cpp
index aed68ab06ad..29105919019 100644
--- a/src/mame/drivers/mekd3.cpp
+++ b/src/mame/drivers/mekd3.cpp
@@ -837,31 +837,34 @@ MC6845_UPDATE_ROW(mekd3_state::update_row)
uint8_t code = m_video_ram[(ma + column) & 0xfff];
int dcursor = (column == cursor_x);
- if (BIT(code, 7)) {
- /* Lores 6 pixel character.
- -----------
- | D1 | D0 |
- | D3 | D2 |
- | D5 | D4 |
- -----------
- D6 - 1 Grey tone, 0 brightness.
- */
- int pixel = ((ra & 0x0c) >> 1) + 1;
- int dout = BIT(code, pixel);
- int grey = BIT(code, 6);
- int color = ((dcursor ^ dout) && de) << (grey ^ 1);
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- pixel--;
- dout = BIT(code, pixel);
- color = ((dcursor ^ dout) && de) << (grey ^ 1);
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- } else {
+ if (BIT(code, 7))
+ {
+ /* Lores 6 pixel character.
+ -----------
+ | D1 | D0 |
+ | D3 | D2 |
+ | D5 | D4 |
+ -----------
+ D6 - 1 Grey tone, 0 brightness.
+ */
+ int pixel = ((ra & 0x0c) >> 1) + 1;
+ int dout = BIT(code, pixel);
+ int grey = BIT(code, 6);
+ int color = ((dcursor ^ dout) && de) << (grey ^ 1);
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ pixel--;
+ dout = BIT(code, pixel);
+ color = ((dcursor ^ dout) && de) << (grey ^ 1);
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ }
+ else
+ {
offs_t address = ra < 8 ? ((code & 0x7f) << 3) | (ra & 0x07) : 0;
uint8_t data = m_p_chargen[address];
@@ -870,7 +873,7 @@ MC6845_UPDATE_ROW(mekd3_state::update_row)
int dout = BIT(data, 7);
int color = ((dcursor ^ dout) && de) << 1;
- bitmap.pix32(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
data <<= 1;
}
diff --git a/src/mame/drivers/mekd4.cpp b/src/mame/drivers/mekd4.cpp
index f03c8e3248f..d8856a11893 100644
--- a/src/mame/drivers/mekd4.cpp
+++ b/src/mame/drivers/mekd4.cpp
@@ -874,29 +874,29 @@ MC6845_UPDATE_ROW(mekd4_state::update_row)
int dcursor = (column == cursor_x);
if (BIT(code, 7)) {
- /* Lores 6 pixel character.
- -----------
- | D1 | D0 |
- | D3 | D2 |
- | D5 | D4 |
- -----------
- D6 - 1 Grey tone, 0 brightness.
- */
- int pixel = ((ra & 0x0c) >> 1) + 1;
- int dout = BIT(code, pixel);
- int grey = BIT(code, 6);
- int color = ((dcursor ^ dout) && de) << (grey ^ 1);
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- pixel--;
- dout = BIT(code, pixel);
- color = ((dcursor ^ dout) && de) << (grey ^ 1);
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
- bitmap.pix32(y, x++) = pen[color];
+ /* Lores 6 pixel character.
+ -----------
+ | D1 | D0 |
+ | D3 | D2 |
+ | D5 | D4 |
+ -----------
+ D6 - 1 Grey tone, 0 brightness.
+ */
+ int pixel = ((ra & 0x0c) >> 1) + 1;
+ int dout = BIT(code, pixel);
+ int grey = BIT(code, 6);
+ int color = ((dcursor ^ dout) && de) << (grey ^ 1);
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ pixel--;
+ dout = BIT(code, pixel);
+ color = ((dcursor ^ dout) && de) << (grey ^ 1);
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
} else {
offs_t address = ra < 8 ? ((code & 0x7f) << 3) | (ra & 0x07) : 0;
uint8_t data = m_p_chargen[address];
@@ -906,7 +906,7 @@ MC6845_UPDATE_ROW(mekd4_state::update_row)
int dout = BIT(data, 7);
int color = ((dcursor ^ dout) && de) << 1;
- bitmap.pix32(y, x++) = pen[color];
+ bitmap.pix(y, x++) = pen[color];
data <<= 1;
}
diff --git a/src/mame/drivers/merit.cpp b/src/mame/drivers/merit.cpp
index f54de1f3f07..ffa8650e791 100644
--- a/src/mame/drivers/merit.cpp
+++ b/src/mame/drivers/merit.cpp
@@ -296,28 +296,23 @@ MC6845_BEGIN_UPDATE( merit_state::crtc_begin_update )
MC6845_UPDATE_ROW( merit_state::crtc_update_row )
{
- uint8_t *gfx[2];
+ uint8_t const *const gfx[2] = { memregion("gfx1")->base(), memregion("gfx2")->base() };
uint16_t x = 0;
- int rlen;
- gfx[0] = memregion("gfx1")->base();
- gfx[1] = memregion("gfx2")->base();
- rlen = memregion("gfx2")->bytes();
+ int const rlen = memregion("gfx2")->bytes();
//ma = ma ^ 0x7ff;
for (uint8_t cx = 0; cx < x_count; cx++)
{
- int i;
int attr = m_ram_attr[ma & 0x7ff];
int region = (attr & 0x40) >> 6;
int addr = ((m_ram_video[ma & 0x7ff] | ((attr & 0x80) << 1) | (m_extra_video_bank_bit)) << 4) | (ra & 0x0f);
int colour = (attr & 0x7f) << 3;
- uint8_t *data;
addr &= (rlen-1);
- data = gfx[region];
+ uint8_t const *const data = gfx[region];
- for (i = 7; i>=0; i--)
+ for (int i = 7; i>=0; i--)
{
int col = colour;
@@ -331,7 +326,7 @@ MC6845_UPDATE_ROW( merit_state::crtc_update_row )
col |= 0x03;
col = m_ram_palette[col & 0x3ff];
- bitmap.pix32(y, x) = m_pens[col ? col & (NUM_PENS-1) : (m_lscnblk ? 8 : 0)];
+ bitmap.pix(y, x) = m_pens[col ? col & (NUM_PENS-1) : (m_lscnblk ? 8 : 0)];
x++;
}
diff --git a/src/mame/drivers/meritum.cpp b/src/mame/drivers/meritum.cpp
index a91fc301bf8..c16a2514999 100644
--- a/src/mame/drivers/meritum.cpp
+++ b/src/mame/drivers/meritum.cpp
@@ -227,12 +227,11 @@ static INPUT_PORTS_START( meritum )
INPUT_PORTS_END
u32 meritum_state::screen_update_meritum1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-/* lores characters are in the character generator. Each character is 6x12 (basic characters are 6x7 excluding descenders/ascenders). */
{
- u8 y,ra,chr,gfx;
- u16 sy=0,ma=0,x;
- u8 cols = m_mode ? 32 : 64;
- u8 skip = m_mode ? 2 : 1;
+ // lores characters are in the character generator. Each character is 6x12 (basic characters are 6x7 excluding descenders/ascenders).
+ u16 sy=0,ma=0;
+ const u8 cols = m_mode ? 32 : 64;
+ const u8 skip = m_mode ? 2 : 1;
if (m_mode != m_size_store)
{
@@ -240,28 +239,28 @@ u32 meritum_state::screen_update_meritum1(screen_device &screen, bitmap_ind16 &b
screen.set_visible_area(0, cols*6-1, 0, 16*12-1);
}
- for (y = 0; y < 16; y++)
+ for (u8 y = 0; y < 16; y++)
{
- for (ra = 0; ra < 12; ra++)
+ for (u8 ra = 0; ra < 12; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 64; x+=skip)
+ for (u16 x = ma; x < ma + 64; x+=skip)
{
- chr = m_p_videoram[x] & 0xbf;
+ const u8 chr = m_p_videoram[x] & 0xbf;
+ u8 gfx;
// shift down comma and semicolon
// not sure Meritum I got the circuit for this (like TRS80)
// but position of ';' suggests most likely yes
if ((chr == 0x2c) && (ra >= 2))
gfx = m_p_chargen[0x2be + ra];
- else
- if ((chr == 0x3b) && (ra >= 1))
+ else if ((chr == 0x3b) && (ra >= 1))
gfx = m_p_chargen[0x3af + ra];
else
gfx = m_p_chargen[(chr<<4) | ra];
- /* Display a scanline of a character (6 pixels) */
+ // Display a scanline of a character (6 pixels)
*p++ = BIT(gfx, 5);
*p++ = BIT(gfx, 4);
*p++ = BIT(gfx, 3);
@@ -277,10 +276,9 @@ u32 meritum_state::screen_update_meritum1(screen_device &screen, bitmap_ind16 &b
u32 meritum_state::screen_update_meritum2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx;
- u16 sy=0,ma=0,x;
- u8 cols = m_mode ? 32 : 64;
- u8 skip = m_mode ? 2 : 1;
+ u16 sy=0,ma=0;
+ const u8 cols = m_mode ? 32 : 64;
+ const u8 skip = m_mode ? 2 : 1;
if (m_mode != m_size_store)
{
@@ -288,20 +286,20 @@ u32 meritum_state::screen_update_meritum2(screen_device &screen, bitmap_ind16 &b
screen.set_visible_area(0, cols*6-1, 0, 16*12-1);
}
- for (y = 0; y < 16; y++)
+ for (u8 y = 0; y < 16; y++)
{
- for (ra = 0; ra < 12; ra++)
+ for (u8 ra = 0; ra < 12; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 64; x+=skip)
+ for (u16 x = ma; x < ma + 64; x+=skip)
{
- chr = m_p_videoram[x];
+ const u8 chr = m_p_videoram[x];
- /* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<4) | ra];
+ // get pattern of pixels for that character scanline
+ const u8 gfx = m_p_chargen[(chr<<4) | ra];
- /* Display a scanline of a character (6 pixels) */
+ // Display a scanline of a character (6 pixels)
*p++ = BIT(gfx, 5);
*p++ = BIT(gfx, 4);
*p++ = BIT(gfx, 3);
@@ -343,7 +341,7 @@ void meritum_state::port_ff_w(u8 data)
d1, d0 Cassette output */
static const double levels[4] = { 0.0, 1.0, -1.0, 0.0 };
- static bool init = 0;
+ static bool init = 0; // FIXME: static variable, breaks hard reset and multiple runs from system selection menu
m_cassette->change_state(BIT(data, 2) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR );
m_cassette->output(levels[data & 3]);
@@ -354,7 +352,7 @@ void meritum_state::port_ff_w(u8 data)
if (!init)
{
init = 1;
- static int16_t speaker_levels[4] = { 0, -32767, 0, 32767 };
+ static double const speaker_levels[4] = { 0.0, -1.0, 0.0, 1.0 };
m_speaker->set_levels(4, speaker_levels);
}
}
diff --git a/src/mame/drivers/mes.cpp b/src/mame/drivers/mes.cpp
index 24b69b6866a..de379ba2a96 100644
--- a/src/mame/drivers/mes.cpp
+++ b/src/mame/drivers/mes.cpp
@@ -99,21 +99,20 @@ void mes_state::machine_reset()
Also the screen dimensions are a guess. */
uint32_t mes_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx;
- u16 sy=0,ma=0,x;
+ u16 sy=0,ma=0;
- for (y = 0; y < 25; y++)
+ for (u8 y = 0; y < 25; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (u8 ra = 0; ra < 10; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 80; x++)
+ for (u16 x = ma; x < ma + 80; x++)
{
- gfx = 0;
+ u8 gfx = 0;
if (ra < 9)
{
- chr = m_p_videoram[x];
+ u8 chr = m_p_videoram[x];
gfx = m_p_chargen[(chr<<4) | ra ];
}
diff --git a/src/mame/drivers/metalmx.cpp b/src/mame/drivers/metalmx.cpp
index 4fc9ec4f3a6..e1c5acfb595 100644
--- a/src/mame/drivers/metalmx.cpp
+++ b/src/mame/drivers/metalmx.cpp
@@ -290,7 +290,7 @@ uint32_t metalmx_state::screen_update_metalmx(screen_device &screen, bitmap_ind1
for (int y = (std::max)(0, cliprect.min_y); y <= (std::min)(383, cliprect.max_y); ++y)
{
- uint16_t *pix = &bitmap.pix16(y);
+ uint16_t *pix = &bitmap.pix(y);
for (int x = 0; x < 256; x++)
{
*pix++ = src_base[256 * y + x] & 0xffff;
diff --git a/src/mame/drivers/meyc8080.cpp b/src/mame/drivers/meyc8080.cpp
index 7b63e7e117f..5ff1731fa36 100644
--- a/src/mame/drivers/meyc8080.cpp
+++ b/src/mame/drivers/meyc8080.cpp
@@ -113,12 +113,8 @@ private:
uint32_t meyc8080_state::screen_update_meyc8080(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram_0.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram_0.bytes(); offs++)
{
- int i;
-
uint8_t y = offs >> 5;
uint8_t x = offs << 3;
@@ -132,15 +128,15 @@ uint32_t meyc8080_state::screen_update_meyc8080(screen_device &screen, bitmap_rg
uint8_t data_g = (data2 & ~data0) | (data2 & data1) | (~data2 & ~data1 & data0);
uint8_t data_b = data0 ^ data1;
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
- bitmap.pix32(y, x) = rgb_t(pal1bit(data_r >> 7), pal1bit(data_g >> 7), pal1bit(data_b >> 7));
+ bitmap.pix(y, x) = rgb_t(pal1bit(data_r >> 7), pal1bit(data_g >> 7), pal1bit(data_b >> 7));
- data_r = data_r << 1;
- data_g = data_g << 1;
- data_b = data_b << 1;
+ data_r <<= 1;
+ data_g <<= 1;
+ data_b <<= 1;
- x = x + 1;
+ x++;
}
}
diff --git a/src/mame/drivers/meyc8088.cpp b/src/mame/drivers/meyc8088.cpp
index 363eaffe16d..653ff3b757b 100644
--- a/src/mame/drivers/meyc8088.cpp
+++ b/src/mame/drivers/meyc8088.cpp
@@ -163,7 +163,7 @@ uint32_t meyc8088_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
v[3] = m_vram[offs|0x4001]; // video4: color prom d3
for (int i = 0; i < 8; i++)
- bitmap.pix16(y, x | i) = ((v[0] << i) >> 7 & 1) | ((v[1] << i) >> 6 & 2) | ((v[2] << i) >> 5 & 4) | ((v[3] << i) >> 4 & 8) | v[4];
+ bitmap.pix(y, x | i) = ((v[0] << i) >> 7 & 1) | ((v[1] << i) >> 6 & 2) | ((v[2] << i) >> 5 & 4) | ((v[3] << i) >> 4 & 8) | v[4];
}
return 0;
diff --git a/src/mame/drivers/micral.cpp b/src/mame/drivers/micral.cpp
index 12c1c90f2af..692c61480b7 100644
--- a/src/mame/drivers/micral.cpp
+++ b/src/mame/drivers/micral.cpp
@@ -323,21 +323,20 @@ INPUT_PORTS_END
uint32_t micral_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t y,ra,chr,gfx;
- uint16_t sy=0,ma=0,x;
+ uint16_t sy=0,ma=0;
- for (y = 0; y < 24; y++)
+ for (uint8_t y = 0; y < 24; y++)
{
- for (ra = 0; ra < 10; ra++)
+ for (uint8_t ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = 0; x < 80; x++)
+ for (uint16_t x = 0; x < 80; x++)
{
- gfx = 0;
+ uint8_t gfx = 0;
if (ra < 9)
{
- chr = m_vram[x+ma];
+ uint8_t chr = m_vram[x+ma];
gfx = m_p_chargen[(chr<<4) | ra ];
if (((s_curpos & 0xff)==x) && ((s_curpos >> 8)==y))
gfx ^= 0xff;
diff --git a/src/mame/drivers/microb.cpp b/src/mame/drivers/microb.cpp
index 10544180c67..4feafb18f93 100644
--- a/src/mame/drivers/microb.cpp
+++ b/src/mame/drivers/microb.cpp
@@ -211,8 +211,8 @@ static INPUT_PORTS_START( microb )
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("3pad") PORT_CODE(KEYCODE_3_PAD)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC)
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Show/Hide Status")
- PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN)
- PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("0pad") PORT_CODE(KEYCODE_0_PAD)
PORT_START("X9")
@@ -223,10 +223,10 @@ static INPUT_PORTS_START( microb )
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED)
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Cursor Blink On/Off")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // carriage return
- PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_START("X10")
- PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("XMIT") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED)
@@ -285,9 +285,9 @@ I8275_DRAW_CHARACTER_MEMBER(microb_state::draw_character)
dots ^= 0xff;
// HLGT is active on status line
- rgb_t fg = hlgt ? rgb_t(0xc0, 0xc0, 0xc0) : rgb_t::white();
+ rgb_t const fg = hlgt ? rgb_t(0xc0, 0xc0, 0xc0) : rgb_t::white();
- u32 *pix = &bitmap.pix32(y, x);
+ u32 *pix = &bitmap.pix(y, x);
for (int i = 0; i < 8; i++)
{
*pix++ = BIT(dots, 7) ? fg : rgb_t::black();
diff --git a/src/mame/drivers/microtan.cpp b/src/mame/drivers/microtan.cpp
index 2e155561761..51018495c05 100644
--- a/src/mame/drivers/microtan.cpp
+++ b/src/mame/drivers/microtan.cpp
@@ -142,7 +142,7 @@ static INPUT_PORTS_START( microtan )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('o')
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p')
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("] }") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']') PORT_CHAR('}')
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_CODE(KEYCODE_DEL) PORT_CHAR(3)
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL)
@@ -162,7 +162,7 @@ static INPUT_PORTS_START( microtan )
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('l')
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("@") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('@') PORT_CHAR('`')
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\\ |") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('\\') PORT_CHAR('|')
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("SHIFT (L)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z')
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x')
diff --git a/src/mame/drivers/microterm_f8.cpp b/src/mame/drivers/microterm_f8.cpp
index 9d476def400..da4d83cd617 100644
--- a/src/mame/drivers/microterm_f8.cpp
+++ b/src/mame/drivers/microterm_f8.cpp
@@ -162,7 +162,7 @@ u32 microterm_f8_state::screen_update(screen_device &screen, bitmap_rgb32 &bitma
bool dot = (!BIT(ch, 8) && allow_underline) || ((BIT(ch, 10) || blink_on) && BIT(chdata, 8 - (x % 9)));
if ((BIT(ch, 7) && cursor_on) == BIT(ch, 9))
dot = !dot;
- bitmap.pix32(y, x) = dot ? rgb_t::white() : rgb_t::black();
+ bitmap.pix(y, x) = dot ? rgb_t::white() : rgb_t::black();
}
y++;
diff --git a/src/mame/drivers/microvsn.cpp b/src/mame/drivers/microvsn.cpp
index 7957d16279d..324443a5366 100644
--- a/src/mame/drivers/microvsn.cpp
+++ b/src/mame/drivers/microvsn.cpp
@@ -267,7 +267,7 @@ uint32_t microvision_state::screen_update(screen_device &screen, bitmap_rgb32 &b
p = (p > 255) ? 0 : p ^ 255;
if (cliprect.contains(x, y))
- bitmap.pix32(y, x) = p << 16 | p << 8 | p;
+ bitmap.pix(y, x) = p << 16 | p << 8 | p;
}
}
diff --git a/src/mame/drivers/mikro80.cpp b/src/mame/drivers/mikro80.cpp
index 5501b6d0536..b49f864e6f6 100644
--- a/src/mame/drivers/mikro80.cpp
+++ b/src/mame/drivers/mikro80.cpp
@@ -184,7 +184,7 @@ u32 mikro80_state::screen_update_mikro80(screen_device &screen, bitmap_ind16 &bi
{
for (u8 ra = 0; ra < 8; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
for (u16 x = ma; x < ma + 64; x++)
{
diff --git a/src/mame/drivers/mikromik.cpp b/src/mame/drivers/mikromik.cpp
index 75c4f6fa5dd..cddf5908c14 100644
--- a/src/mame/drivers/mikromik.cpp
+++ b/src/mame/drivers/mikromik.cpp
@@ -154,7 +154,7 @@ WRITE_LINE_MEMBER( mm1_state::recall_w )
{
LOG("RECALL %u\n", state);
m_recall = state;
- if (state) m_fdc->soft_reset();
+ m_fdc->reset_w(state);
}
diff --git a/src/mame/drivers/mikrosha.cpp b/src/mame/drivers/mikrosha.cpp
index 6660e81c278..8442c3238b3 100644
--- a/src/mame/drivers/mikrosha.cpp
+++ b/src/mame/drivers/mikrosha.cpp
@@ -190,7 +190,7 @@ I8275_DRAW_CHARACTER_MEMBER(mikrosha_state::display_pixels)
pixels ^= 0xff;
for(int i=0;i<6;i++)
- bitmap.pix32(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
+ bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}
/* F4 Character Displayer */
diff --git a/src/mame/drivers/milton6805.cpp b/src/mame/drivers/milton6805.cpp
index efda2a0886d..1377e8d85a2 100644
--- a/src/mame/drivers/milton6805.cpp
+++ b/src/mame/drivers/milton6805.cpp
@@ -90,7 +90,7 @@ public:
protected:
virtual void device_start() override;
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
sound_stream *m_stream;
@@ -108,25 +108,24 @@ milton_filter_device::milton_filter_device(const machine_config &mconfig, const
void milton_filter_device::device_start()
{
- m_stream = stream_alloc_legacy(1, 1, machine().sample_rate());
+ m_stream = stream_alloc(1, 1, machine().sample_rate());
m_led_out.resolve();
}
-void milton_filter_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void milton_filter_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- int level = 0;
+ stream_buffer::sample_t level = 0;
- for (int i = 0; i < samples; i++)
- {
- level += abs(inputs[0][i]);
- outputs[0][i] = inputs[0][i];
- }
+ for (int i = 0; i < outputs[0].samples(); i++)
+ level += fabsf(inputs[0].get(i));
+
+ outputs[0] = inputs[0];
- if (samples > 0)
- level /= samples;
+ if (outputs[0].samples() > 0)
+ level /= outputs[0].samples();
// 2 leds connected to the audio circuit
- const int threshold = 1500;
+ const stream_buffer::sample_t threshold = 1500.0 / 32768.0;
m_led_out = (level > threshold) ? 1 : 0;
}
diff --git a/src/mame/drivers/mindset.cpp b/src/mame/drivers/mindset.cpp
index 279ad92bbf8..d11e5291420 100644
--- a/src/mame/drivers/mindset.cpp
+++ b/src/mame/drivers/mindset.cpp
@@ -751,12 +751,12 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
if(ibm_mode) {
if(large_pixels) {
- static int palind[4] = { 0, 1, 4, 5 };
+ static int const palind[4] = { 0, 1, 4, 5 };
for(int field=0; field<2; field++) {
for(u32 yy=0; yy<2; yy++) {
const u16 *src = bank + 4096*yy;
for(u32 y=yy; y<200; y+=2) {
- u32 *dest = &bitmap.pix32(2*y+field+dy, dx);
+ u32 *dest = &bitmap.pix(2*y+field+dy, dx);
for(u32 x=0; x<320; x+=8) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<8; xx++) {
@@ -770,12 +770,12 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
}
return 0;
} else {
- static int palind[4] = { 0, 4 };
+ static int const palind[2] = { 0, 4 };
for(int field=0; field<2; field++) {
for(u32 yy=0; yy<2; yy++) {
const u16 *src = bank + 4096*yy;
for(u32 y=yy; y<200; y+=2) {
- u32 *dest = &bitmap.pix32(2*y+field+dy, dx);
+ u32 *dest = &bitmap.pix(2*y+field+dy, dx);
for(u32 x=0; x<640; x+=16) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<16; xx++) {
@@ -795,8 +795,8 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
case 0: {
const u16 *src = bank;
for(u32 y=0; y<200; y++) {
- u32 *dest0 = &bitmap.pix32(2*y+dy, dx);
- u32 *dest1 = &bitmap.pix32(2*y+1+dy, dx);
+ u32 *dest0 = &bitmap.pix(2*y+dy, dx);
+ u32 *dest1 = &bitmap.pix(2*y+1+dy, dx);
for(u32 x=0; x<320; x+=4) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<4; xx++) {
@@ -811,11 +811,11 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
return 0;
}
case 1: {
- static int palind[4] = { 0, 1, 4, 5 };
+ static int const palind[4] = { 0, 1, 4, 5 };
const u16 *src = bank;
for(u32 y=0; y<200; y++) {
- u32 *dest0 = &bitmap.pix32(2*y+dy, dx);
- u32 *dest1 = &bitmap.pix32(2*y+1+dy, dx);
+ u32 *dest0 = &bitmap.pix(2*y+dy, dx);
+ u32 *dest1 = &bitmap.pix(2*y+1+dy, dx);
for(u32 x=0; x<320; x+=8) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<8; xx++) {
@@ -832,8 +832,8 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
case 2: {
const u16 *src = bank;
for(u32 y=0; y<200; y++) {
- u32 *dest0 = &bitmap.pix32(2*y+dy, dx);
- u32 *dest1 = &bitmap.pix32(2*y+1+dy, dx);
+ u32 *dest0 = &bitmap.pix(2*y+dy, dx);
+ u32 *dest1 = &bitmap.pix(2*y+1+dy, dx);
for(u32 x=0; x<320; x+=16) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<16; xx++) {
@@ -853,7 +853,7 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
case 0: {
const u16 *src = bank;
for(u32 y=0; y<400; y++) {
- u32 *dest = &bitmap.pix32(y+dy, dx);
+ u32 *dest = &bitmap.pix(y+dy, dx);
for(u32 x=0; x<320; x+=4) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<4; xx++) {
@@ -866,10 +866,10 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
return 0;
}
case 1: {
- static int palind[4] = { 0, 1, 4, 5 };
+ static int const palind[4] = { 0, 1, 4, 5 };
const u16 *src = bank;
for(u32 y=0; y<400; y++) {
- u32 *dest = &bitmap.pix32(y+dy, dx);
+ u32 *dest = &bitmap.pix(y+dy, dx);
for(u32 x=0; x<320; x+=8) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<8; xx++) {
@@ -887,11 +887,11 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
if(!interleave) {
switch(pixels_per_byte_order) {
case 0: {
- static int palind[4] = { 0, 4, 8, 12 };
+ static int const palind[4] = { 0, 4, 8, 12 };
const u16 *src = bank;
for(u32 y=0; y<200; y++) {
- u32 *dest0 = &bitmap.pix32(2*y+dy, dx);
- u32 *dest1 = &bitmap.pix32(2*y+1+dy, dx);
+ u32 *dest0 = &bitmap.pix(2*y+dy, dx);
+ u32 *dest1 = &bitmap.pix(2*y+1+dy, dx);
for(u32 x=0; x<640; x+=8) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<8; xx++) {
@@ -904,11 +904,11 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
return 0;
}
case 1: {
- static int palind[4] = { 0, 4 };
+ static int const palind[2] = { 0, 4 };
const u16 *src = bank;
for(u32 y=0; y<200; y++) {
- u32 *dest0 = &bitmap.pix32(2*y+dy, dx);
- u32 *dest1 = &bitmap.pix32(2*y+1+dy, dx);
+ u32 *dest0 = &bitmap.pix(2*y+dy, dx);
+ u32 *dest1 = &bitmap.pix(2*y+1+dy, dx);
for(u32 x=0; x<640; x+=16) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<16; xx++) {
@@ -922,10 +922,10 @@ u32 mindset_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, co
}
}
} else {
- static int palind[4] = { 0, 4 };
+ static int const palind[2] = { 0, 4 };
const u16 *src = bank;
for(u32 y=0; y<400; y++) {
- u32 *dest = &bitmap.pix32(y+dy, dx);
+ u32 *dest = &bitmap.pix(y+dy, dx);
for(u32 x=0; x<640; x+=16) {
u16 sv = sw(*src++);
for(u32 xx=0; xx<16; xx++) {
diff --git a/src/mame/drivers/miniboy7.cpp b/src/mame/drivers/miniboy7.cpp
index 28f52c0aed3..9423a10432d 100644
--- a/src/mame/drivers/miniboy7.cpp
+++ b/src/mame/drivers/miniboy7.cpp
@@ -320,7 +320,7 @@ int miniboy7_state::get_color_offset(uint8_t tile, uint8_t attr, int ra, int px)
MC6845_UPDATE_ROW( miniboy7_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
for (uint8_t cx = 0; cx < x_count; cx+=1)
{
@@ -332,9 +332,9 @@ MC6845_UPDATE_ROW( miniboy7_state::crtc_update_row )
uint8_t color_b = m_proms[offset_b] & 0x0f;
if (color_a && (m_gpri || !color_b)) // videoram A has priority
- bitmap.pix32(y, (cx << 3) + px) = palette[offset_a];
+ bitmap.pix(y, (cx << 3) + px) = palette[offset_a];
else if (color_b && (!m_gpri || !color_a)) // videoram B has priority
- bitmap.pix32(y, (cx << 3) + px) = palette[offset_b];
+ bitmap.pix(y, (cx << 3) + px) = palette[offset_b];
}
}
}
diff --git a/src/mame/drivers/minivadr.cpp b/src/mame/drivers/minivadr.cpp
index 0b0b1bd4c88..329d3c5fa15 100644
--- a/src/mame/drivers/minivadr.cpp
+++ b/src/mame/drivers/minivadr.cpp
@@ -65,23 +65,19 @@ private:
uint32_t minivadr_state::screen_update_minivadr(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- offs_t offs;
-
- for (offs = 0; offs < m_videoram.bytes(); offs++)
+ for (offs_t offs = 0; offs < m_videoram.bytes(); offs++)
{
- int i;
-
uint8_t x = offs << 3;
- int y = offs >> 5;
+ const int y = offs >> 5;
uint8_t data = m_videoram[offs];
- for (i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++)
{
pen_t pen = (data & 0x80) ? rgb_t::white() : rgb_t::black();
- bitmap.pix32(y, x) = pen;
+ bitmap.pix(y, x) = pen;
- data = data << 1;
- x = x + 1;
+ data <<= 1;
+ x++;
}
}
diff --git a/src/mame/drivers/missile.cpp b/src/mame/drivers/missile.cpp
index ca2f756d1c4..b4c1d9c0823 100644
--- a/src/mame/drivers/missile.cpp
+++ b/src/mame/drivers/missile.cpp
@@ -683,24 +683,21 @@ uint8_t missile_state::read_vram(address_space &space, offs_t address)
uint32_t missile_state::screen_update_missile(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t *videoram = m_videoram;
- int x, y;
-
// draw the bitmap to the screen, looping over Y
- for (y = cliprect.top(); y <= cliprect.bottom(); y++)
+ for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint16_t *dst = &bitmap.pix16(y);
+ uint16_t *const dst = &bitmap.pix(y);
- int effy = m_flipscreen ? ((256+24 - y) & 0xff) : y;
- uint8_t *src = &videoram[effy * 64];
- uint8_t *src3 = nullptr;
+ int const effy = m_flipscreen ? ((256+24 - y) & 0xff) : y;
+ uint8_t const *const src = &m_videoram[effy * 64];
+ uint8_t const *src3 = nullptr;
// compute the base of the 3rd pixel row
if (effy >= 224)
- src3 = &videoram[get_bit3_addr(effy << 8)];
+ src3 = &m_videoram[get_bit3_addr(effy << 8)];
// loop over X
- for (x = cliprect.left(); x <= cliprect.right(); x++)
+ for (int x = cliprect.left(); x <= cliprect.right(); x++)
{
uint8_t pix = src[x / 4] >> (x & 3);
pix = ((pix >> 2) & 4) | ((pix << 1) & 2);
diff --git a/src/mame/drivers/mjsenpu.cpp b/src/mame/drivers/mjsenpu.cpp
index f38ca081012..5d3954855ca 100644
--- a/src/mame/drivers/mjsenpu.cpp
+++ b/src/mame/drivers/mjsenpu.cpp
@@ -407,32 +407,26 @@ void mjsenpu_state::video_start()
uint32_t mjsenpu_state::screen_update_mjsenpu(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x,y,count;
- int color;
+ uint32_t const *const vram = (m_control & 0x01) ? m_vram0 : m_vram1;
- uint32_t* vram;
-
- if (m_control & 0x01) vram = m_vram0;
- else vram = m_vram1;
-
-
-
- count = 0;
- for (y=0;y < 256;y++)
+ int count = 0;
+ for (int y=0;y < 256;y++)
{
- for (x=0;x < 512/4;x++)
+ for (int x=0;x < 512/4;x++)
{
+ int color;
+
color = vram[count] & 0x000000ff;
- bitmap.pix16(y, x*4 + 2) = color;
+ bitmap.pix(y, x*4 + 2) = color;
color = (vram[count] & 0x0000ff00) >> 8;
- bitmap.pix16(y, x*4 + 3) = color;
+ bitmap.pix(y, x*4 + 3) = color;
color = (vram[count] & 0x00ff0000) >> 16;
- bitmap.pix16(y, x*4 + 0) = color;
+ bitmap.pix(y, x*4 + 0) = color;
color = (vram[count] & 0xff000000) >> 24;
- bitmap.pix16(y, x*4 + 1) = color;
+ bitmap.pix(y, x*4 + 1) = color;
count++;
}
diff --git a/src/mame/drivers/mjsister.cpp b/src/mame/drivers/mjsister.cpp
index 79ea31be2ae..94f3f27cf69 100644
--- a/src/mame/drivers/mjsister.cpp
+++ b/src/mame/drivers/mjsister.cpp
@@ -139,8 +139,8 @@ MC6845_UPDATE_ROW( mjsister_state::crtc_update_row )
// background layer
uint8_t data_bg = m_vram[0x400 + ((ma << 3) | (ra << 7) | i)];
- bitmap.pix32(y, x1) = pen[m_colorbank << 5 | ((data_bg & 0x0f) >> 0)];
- bitmap.pix32(y, x2) = pen[m_colorbank << 5 | ((data_bg & 0xf0) >> 4)];
+ bitmap.pix(y, x1) = pen[m_colorbank << 5 | ((data_bg & 0x0f) >> 0)];
+ bitmap.pix(y, x2) = pen[m_colorbank << 5 | ((data_bg & 0xf0) >> 4)];
// foreground layer
uint8_t data_fg = m_vram[0x8000 | (0x400 + ((ma << 3) | (ra << 7) | i))];
@@ -149,8 +149,8 @@ MC6845_UPDATE_ROW( mjsister_state::crtc_update_row )
uint8_t c2 = ((data_fg & 0xf0) >> 4);
// 0 is transparent
- if (c1) bitmap.pix32(y, x1) = pen[m_colorbank << 5 | 0x10 | c1];
- if (c2) bitmap.pix32(y, x2) = pen[m_colorbank << 5 | 0x10 | c2];
+ if (c1) bitmap.pix(y, x1) = pen[m_colorbank << 5 | 0x10 | c1];
+ if (c2) bitmap.pix(y, x2) = pen[m_colorbank << 5 | 0x10 | c2];
}
}
diff --git a/src/mame/drivers/ml20.cpp b/src/mame/drivers/ml20.cpp
index 413efc7ca99..d31a697b5a0 100644
--- a/src/mame/drivers/ml20.cpp
+++ b/src/mame/drivers/ml20.cpp
@@ -170,7 +170,7 @@ HD44780_PIXEL_UPDATE( ml20_state::lcd_pixel_update )
return;
if (line < 2 && pos < 16)
- bitmap.pix16(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
+ bitmap.pix(1 + y + line*8 + line, 1 + pos*6 + x) = state ? 1 : 2;
}
// 7654---- unknown (set to input)
diff --git a/src/mame/drivers/mlanding.cpp b/src/mame/drivers/mlanding.cpp
index ef3b653a06a..1a7734e07c9 100644
--- a/src/mame/drivers/mlanding.cpp
+++ b/src/mame/drivers/mlanding.cpp
@@ -243,12 +243,12 @@ void mlanding_state::machine_reset()
u32 mlanding_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- const pen_t *pens = m_palette->pens();
+ pen_t const *const pens = m_palette->pens();
for (u32 y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
- u16 *src = &m_g_ram[(112 + y) * 512 + cliprect.min_x];
- u16 *dst = &bitmap.pix16(y, cliprect.min_x);
+ u16 const *src = &m_g_ram[(112 + y) * 512 + cliprect.min_x];
+ u16 *dst = &bitmap.pix(y, cliprect.min_x);
for (u32 x = cliprect.min_x; x <= cliprect.max_x; ++x)
{
diff --git a/src/mame/drivers/mmagic.cpp b/src/mame/drivers/mmagic.cpp
index cd17c92e098..ac9eb64d633 100644
--- a/src/mame/drivers/mmagic.cpp
+++ b/src/mame/drivers/mmagic.cpp
@@ -229,15 +229,15 @@ uint32_t mmagic_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
{
uint8_t gfx = m_tiles[(code << 4) + tx];
- bitmap.pix32(y * 12 + tx, x * 8 + 0) = BIT(gfx, 4) ? rgb_t::black() : m_palette->pen_color(color);
- bitmap.pix32(y * 12 + tx, x * 8 + 1) = BIT(gfx, 5) ? rgb_t::black() : m_palette->pen_color(color);
- bitmap.pix32(y * 12 + tx, x * 8 + 2) = BIT(gfx, 6) ? rgb_t::black() : m_palette->pen_color(color);
- bitmap.pix32(y * 12 + tx, x * 8 + 3) = BIT(gfx, 7) ? rgb_t::black() : m_palette->pen_color(color);
-
- bitmap.pix32(y * 12 + tx, x * 8 + 4) = BIT(gfx, 0) ? rgb_t::black() : m_palette->pen_color(color);
- bitmap.pix32(y * 12 + tx, x * 8 + 5) = BIT(gfx, 1) ? rgb_t::black() : m_palette->pen_color(color);
- bitmap.pix32(y * 12 + tx, x * 8 + 6) = BIT(gfx, 2) ? rgb_t::black() : m_palette->pen_color(color);
- bitmap.pix32(y * 12 + tx, x * 8 + 7) = BIT(gfx, 3) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 0) = BIT(gfx, 4) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 1) = BIT(gfx, 5) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 2) = BIT(gfx, 6) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 3) = BIT(gfx, 7) ? rgb_t::black() : m_palette->pen_color(color);
+
+ bitmap.pix(y * 12 + tx, x * 8 + 4) = BIT(gfx, 0) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 5) = BIT(gfx, 1) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 6) = BIT(gfx, 2) ? rgb_t::black() : m_palette->pen_color(color);
+ bitmap.pix(y * 12 + tx, x * 8 + 7) = BIT(gfx, 3) ? rgb_t::black() : m_palette->pen_color(color);
}
}
}
diff --git a/src/mame/drivers/modellot.cpp b/src/mame/drivers/modellot.cpp
index 8e8e710fe06..c33d1bc3460 100644
--- a/src/mame/drivers/modellot.cpp
+++ b/src/mame/drivers/modellot.cpp
@@ -166,25 +166,25 @@ GFXDECODE_END
u32 modellot_state::screen_update_modellot(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- u8 y,ra,chr,gfx,inv;
- u16 sy=0,ma=0,x;
+ u16 sy=0,ma=0;
- for (y = 0; y < 16; y++)
+ for (u8 y = 0; y < 16; y++)
{
- for (ra = 0; ra < 16; ra++)
+ for (u8 ra = 0; ra < 16; ra++)
{
- u16 *p = &bitmap.pix16(sy++);
+ u16 *p = &bitmap.pix(sy++);
- for (x = 0; x < 64; x++)
+ for (u16 x = 0; x < 64; x++)
{
- inv = 0;
+ u8 inv = 0;
- chr = m_p_videoram[x+ma];
+ u8 chr = m_p_videoram[x+ma];
if (BIT(chr, 7)) inv = 0xff;
chr &= 0x7f; // cursor
+ u8 gfx;
if (ra < 8)
gfx = m_p_chargen[(chr<<3) | ra ];
else
diff --git a/src/mame/drivers/monty.cpp b/src/mame/drivers/monty.cpp
index 835c6119390..b0d096fed3d 100644
--- a/src/mame/drivers/monty.cpp
+++ b/src/mame/drivers/monty.cpp
@@ -106,7 +106,7 @@ u32 monty_state::screen_update(screen_device& screen, bitmap_rgb32& bitmap, cons
// letters with width 5 with space in between them
for (int y = 0; y < 32; y++)
for (int x = 0; x < 40; x++)
- bitmap.pix32(y + 1, x + x/5 + 1) = BIT(m_lcd_data[y], x) ? 0 : 0xffffff;
+ bitmap.pix(y + 1, x + x/5 + 1) = BIT(m_lcd_data[y], x) ? 0 : 0xffffff;
return 0;
}
diff --git a/src/mame/drivers/monzagp.cpp b/src/mame/drivers/monzagp.cpp
index e0af88f679e..5ef342070a1 100644
--- a/src/mame/drivers/monzagp.cpp
+++ b/src/mame/drivers/monzagp.cpp
@@ -247,9 +247,9 @@ uint32_t monzagp_state::screen_update(screen_device &screen, bitmap_ind16 &bitma
}
if (cliprect.contains(x * 2, y))
- bitmap.pix16(y, x * 2) = color;
+ bitmap.pix(y, x * 2) = color;
if (cliprect.contains(x * 2 + 1, y))
- bitmap.pix16(y, x * 2 + 1) = color;
+ bitmap.pix(y, x * 2 + 1) = color;
// collisions
uint8_t coll_prom_addr = bitswap<8>(tile_idx, 7, 6, 5, 4, 2, 0, 1, 3);
diff --git a/src/mame/drivers/mpu4plasma.cpp b/src/mame/drivers/mpu4plasma.cpp
index d392a1232f0..5e9e182fb30 100644
--- a/src/mame/drivers/mpu4plasma.cpp
+++ b/src/mame/drivers/mpu4plasma.cpp
@@ -56,31 +56,23 @@ void mpu4plasma_state::mpu4plasma_map(address_map &map)
uint32_t mpu4plasma_state::screen_update_mpu4plasma(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// don't know if this really gets drawn straight from ram..
- int base = 0x1600 / 2;
+ int const base = 0x1600 / 2;
- uint16_t* rambase = m_plasmaram;
- uint16_t* dst_bitmap;
+ uint16_t const *const rambase = m_plasmaram;
- int i,y,x,p;
- i = 0;
+ int i = 0;
- for (y=0;y<40;y++)
+ for (int y=0; y<40; y++)
{
- dst_bitmap = &bitmap.pix16(y);
+ uint16_t *const dst_bitmap = &bitmap.pix(y);
- for (x=0;x<128/16;x++)
+ for (int x=0; x<128/16; x++)
{
- uint16_t pix = rambase[base+i];
-
- for (p=0;p<16;p++)
- {
- uint16_t bit = (pix << p)&0x8000;
- if (bit) dst_bitmap[x*16 + p] = 1;
- else dst_bitmap[x*16 + p] = 0;
- }
+ uint16_t const pix = rambase[base+i];
+ for (int p=0; p<16; p++)
+ dst_bitmap[x*16 + p] = ((pix << p) & 0x8000) ? 1 : 0;
i++;
-
}
}
diff --git a/src/mame/drivers/mpu4vid.cpp b/src/mame/drivers/mpu4vid.cpp
index 84cac95b732..cea0f4ea8ad 100644
--- a/src/mame/drivers/mpu4vid.cpp
+++ b/src/mame/drivers/mpu4vid.cpp
@@ -440,7 +440,7 @@ void mpu4vid_state::mpu4_vram(address_map &map)
SCN2674_DRAW_CHARACTER_MEMBER(mpu4vid_state::display_pixels)
{
- if(!lg)
+ if (!lg)
{
uint16_t tile = m_vid_mainram[address & 0x7fff];
const uint8_t *line = m_gfxdecode->gfx(m_gfx_index+0)->get_data(tile & 0xfff);
@@ -455,30 +455,29 @@ SCN2674_DRAW_CHARACTER_MEMBER(mpu4vid_state::display_pixels)
{
// TODO: calculate instead?
static const uint8_t lookup[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
- 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2,
- 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
- 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4,
- 0, 1, 0, 1, 4, 5, 4, 5, 0, 1, 0, 1, 4, 5, 4, 5,
- 0, 0, 2, 2, 4, 4, 6, 6, 0, 0, 2, 2, 4, 4, 6, 6,
- 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
- 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8,
- 0, 1, 0, 1, 0, 1, 0, 1, 8, 9, 8, 9, 8, 9, 8, 9,
- 0, 0, 2, 2, 0, 0, 2, 2, 8, 8,10,10, 8, 8,10,10,
- 0, 1, 2, 3, 0, 1, 2, 3, 8, 9,10,11, 8, 9,10,11,
- 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8,12,12,12,12,
- 0, 1, 0, 1, 4, 5, 4, 5, 8, 9, 8, 9,12,13,12,13,
- 0, 0, 2, 2, 4, 4, 6, 6, 8, 8,10,10,12,12,14,14,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15
- };
-
- bitmap.pix32(y, x + i) = m_palette->pen(lookup[(extra << 4) | (pen & 0xf)]);
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+ 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2,
+ 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
+ 0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 4, 4, 4, 4,
+ 0, 1, 0, 1, 4, 5, 4, 5, 0, 1, 0, 1, 4, 5, 4, 5,
+ 0, 0, 2, 2, 4, 4, 6, 6, 0, 0, 2, 2, 4, 4, 6, 6,
+ 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8,
+ 0, 1, 0, 1, 0, 1, 0, 1, 8, 9, 8, 9, 8, 9, 8, 9,
+ 0, 0, 2, 2, 0, 0, 2, 2, 8, 8,10,10, 8, 8,10,10,
+ 0, 1, 2, 3, 0, 1, 2, 3, 8, 9,10,11, 8, 9,10,11,
+ 0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8,12,12,12,12,
+ 0, 1, 0, 1, 4, 5, 4, 5, 8, 9, 8, 9,12,13,12,13,
+ 0, 0, 2, 2, 4, 4, 6, 6, 8, 8,10,10,12,12,14,14,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15
+ };
+
+ bitmap.pix(y, x + i) = m_palette->pen(lookup[(extra << 4) | (pen & 0xf)]);
}
else
{
- bitmap.pix32(y, x + i) = m_palette->pen((extra<<4) | (pen & 0xf));
-
+ bitmap.pix(y, x + i) = m_palette->pen((extra<<4) | (pen & 0xf));
}
}
}
diff --git a/src/mame/drivers/ms0515.cpp b/src/mame/drivers/ms0515.cpp
index 33f2e059fb2..5adf16996ad 100644
--- a/src/mame/drivers/ms0515.cpp
+++ b/src/mame/drivers/ms0515.cpp
@@ -384,34 +384,33 @@ static void ms0515_floppies(device_slot_interface &device)
uint32_t ms0515_state::screen_update_ms0515(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int y, x, b;
int addr = 0;
if (BIT(m_sysregc, 3))
{
uint8_t fg = m_sysregc & 7;
uint8_t bg = fg ^ 7;
- for (y = 0; y < 200; y++)
+ for (int y = 0; y < 200; y++)
{
int horpos = 0;
- for (x = 0; x < 40; x++)
+ for (int x = 0; x < 40; x++)
{
uint16_t code = (m_video_ram[addr++] << 8);
- code += m_video_ram[addr++];
- for (b = 0; b < 16; b++)
+ code |= m_video_ram[addr++];
+ for (int b = 0; b < 16; b++)
{
// In lower res mode we will just double pixels
- bitmap.pix16(y, horpos++) = ((code >> (15 - b)) & 0x01) ? bg : fg;
+ bitmap.pix(y, horpos++) = ((code >> (15 - b)) & 0x01) ? bg : fg;
}
}
}
}
else
{
- for (y = 0; y < 200; y++)
+ for (int y = 0; y < 200; y++)
{
int horpos = 0;
- for (x = 0; x < 40; x++)
+ for (int x = 0; x < 40; x++)
{
uint8_t code = m_video_ram[addr++];
uint8_t attr = m_video_ram[addr++];
@@ -424,11 +423,11 @@ uint32_t ms0515_state::screen_update_ms0515(screen_device &screen, bitmap_ind16
bg = tmp;
m_blink = -1;
}
- for (b = 0; b < 8; b++)
+ for (int b = 0; b < 8; b++)
{
// In lower res mode we will just double pixels
- bitmap.pix16(y, horpos++) = ((code >> (7 - b)) & 0x01) ? fg : bg;
- bitmap.pix16(y, horpos++) = ((code >> (7 - b)) & 0x01) ? fg : bg;
+ bitmap.pix(y, horpos++) = ((code >> (7 - b)) & 0x01) ? fg : bg;
+ bitmap.pix(y, horpos++) = ((code >> (7 - b)) & 0x01) ? fg : bg;
}
}
}
diff --git a/src/mame/drivers/ms6102.cpp b/src/mame/drivers/ms6102.cpp
index 6c52ac9c06d..5280a203381 100644
--- a/src/mame/drivers/ms6102.cpp
+++ b/src/mame/drivers/ms6102.cpp
@@ -183,7 +183,7 @@ u8 ms6102_state::memory_read_byte(offs_t offset)
I8275_DRAW_CHARACTER_MEMBER(ms6102_state::display_pixels)
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = (lten) ? 0xff : 0;
if (!vsp)
gfx = m_p_chargen[linecount | (charcode << 4)];
@@ -192,7 +192,7 @@ I8275_DRAW_CHARACTER_MEMBER(ms6102_state::display_pixels)
gfx ^= 0xff;
for(u8 i=0; i<8; i++)
- bitmap.pix32(y, x + i) = palette[BIT(gfx, 7-i) ? (hlgt ? 2 : 1) : 0];
+ bitmap.pix(y, x + i) = palette[BIT(gfx, 7-i) ? (hlgt ? 2 : 1) : 0];
}
I8275_DRAW_CHARACTER_MEMBER(ms6102_state::display_attr) // TODO: attributes
diff --git a/src/mame/drivers/msisaac.cpp b/src/mame/drivers/msisaac.cpp
index 353133ac175..e17c5c2c581 100644
--- a/src/mame/drivers/msisaac.cpp
+++ b/src/mame/drivers/msisaac.cpp
@@ -6,11 +6,11 @@
driver by Jarek Burczynski
- TODO:
- - complete MCU simulation, several gameplay elements not properly right;
- - sprites are probably banked differently (no way to be sure until MCU dump is available)
- - TA7630 emulation needs filter support (characteristics depend on the frequency)
- - TA7630 volume table is hand tuned to match the sample, but still slightly off.
+ TODO:
+ - complete MCU simulation, several gameplay elements not properly right;
+ - sprites are probably banked differently (no way to be sure until MCU dump is available)
+ - TA7630 emulation needs filter support (characteristics depend on the frequency)
+ - TA7630 volume table is hand tuned to match the sample, but still slightly off.
****************************************************************************/
diff --git a/src/mame/drivers/mstation.cpp b/src/mame/drivers/mstation.cpp
index 517300b2ee5..c96c359ca65 100644
--- a/src/mame/drivers/mstation.cpp
+++ b/src/mame/drivers/mstation.cpp
@@ -155,7 +155,7 @@ uint32_t mstation_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
// columns are inverted (right to left)
int col = ((x < 20) ? 19 : 59) - x;
- bitmap.pix16(y, col*8 + b)= BIT(data, 0);
+ bitmap.pix(y, col*8 + b)= BIT(data, 0);
data >>= 1;
}
}
@@ -164,7 +164,7 @@ uint32_t mstation_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
//***************************************************************************
// Bankswitch
-//***************************************************************************/
+//***************************************************************************
uint8_t mstation_state::bank1_r(offs_t offset)
{
diff --git a/src/mame/drivers/mtd1256.cpp b/src/mame/drivers/mtd1256.cpp
index fdc73e30185..0c05033a071 100644
--- a/src/mame/drivers/mtd1256.cpp
+++ b/src/mame/drivers/mtd1256.cpp
@@ -63,9 +63,9 @@ HD44780_PIXEL_UPDATE(mtd1256_state::pixel_update)
{
// Is this the right layout?
if (pos < 20)
- bitmap.pix16(line * 16 + y, pos * 6 + x) = state;
+ bitmap.pix(line * 16 + y, pos * 6 + x) = state;
else if (pos < 40)
- bitmap.pix16(line * 16 + 8 + y, (pos - 20) * 6 + x) = state;
+ bitmap.pix(line * 16 + 8 + y, (pos - 20) * 6 + x) = state;
}
diff --git a/src/mame/drivers/multi16.cpp b/src/mame/drivers/multi16.cpp
index 818a137d7cf..48ead99c97d 100644
--- a/src/mame/drivers/multi16.cpp
+++ b/src/mame/drivers/multi16.cpp
@@ -82,7 +82,7 @@ private:
MC6845_UPDATE_ROW(multi16_state::crtc_update_row)
{
- uint8_t *vram = reinterpret_cast<uint8_t *>(m_vram.target());
+ uint8_t const *const vram = reinterpret_cast<uint8_t *>(m_vram.target());
for (int i = 0; i < x_count; i++)
{
@@ -101,7 +101,7 @@ MC6845_UPDATE_ROW(multi16_state::crtc_update_row)
color |= BIT(data_g, 7 - x) << 1;
color |= BIT(data_b, 7 - x) << 2;
- bitmap.pix32(y, x + i * 8) = m_palette->pens()[color];
+ bitmap.pix(y, x + i * 8) = m_palette->pens()[color];
}
}
}
diff --git a/src/mame/drivers/multi8.cpp b/src/mame/drivers/multi8.cpp
index 05609efb6ec..819ddc3de4f 100644
--- a/src/mame/drivers/multi8.cpp
+++ b/src/mame/drivers/multi8.cpp
@@ -115,14 +115,13 @@ void multi8_state::video_start()
MC6845_UPDATE_ROW( multi8_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- uint8_t i,chr,gfx=0,color,pen,attr;
- uint16_t mem = y*80,x;
- uint32_t *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u16 mem = y*80;
+ u32 *p = &bitmap.pix(y);
- for(x = 0; x < x_count; x++)
+ for(u16 x = 0; x < x_count; x++)
{
- for(i = 0; i < 8; i++)
+ for(u8 i = 0; i < 8; i++)
{
u8 pen_b = BIT(m_p_vram[mem | 0x0000], 7-i);
u8 pen_r = BIT(m_p_vram[mem | 0x4000], 7-i);
@@ -143,18 +142,18 @@ MC6845_UPDATE_ROW( multi8_state::crtc_update_row )
mem++;
}
- u8 x_width = BIT(m_display_reg, 6) ? 80 : 40;
- u8 x_step = BIT(m_display_reg, 6) ? 1 : 2;
+ const u8 x_width = BIT(m_display_reg, 6) ? 80 : 40;
+ const u8 x_step = BIT(m_display_reg, 6) ? 1 : 2;
mem = 0xc000 + ma;
- p = &bitmap.pix32(y);
+ p = &bitmap.pix(y);
- for(x = 0; x < x_width; x++)
+ for(u16 x = 0; x < x_width; x++)
{
- chr = m_p_vram[mem];
- attr = m_p_vram[mem | 0x800];
- color = (BIT(m_display_reg, 7)) ? 7 : (attr & 0x07);
+ const u8 chr = m_p_vram[mem];
+ const u8 attr = m_p_vram[mem | 0x800];
+ const u8 color = (BIT(m_display_reg, 7)) ? 7 : (attr & 0x07);
- gfx = BIT(attr, 5);
+ u8 gfx = BIT(attr, 5);
if (cursor_x >= 0)
gfx ^= (x == (cursor_x / x_step));
@@ -165,9 +164,9 @@ MC6845_UPDATE_ROW( multi8_state::crtc_update_row )
if (ra < 8)
gfx ^= m_p_chargen[(chr << 3) | ra];
- for(i = 0; i < 8; i++)
+ for(u8 i = 0; i < 8; i++)
{
- pen = BIT(gfx, 7-i) ? color : 0;
+ u8 pen = BIT(gfx, 7-i) ? color : 0;
if (x_step == 1)
{
diff --git a/src/mame/drivers/mx2178.cpp b/src/mame/drivers/mx2178.cpp
index ef2d7160509..36950bf3ee5 100644
--- a/src/mame/drivers/mx2178.cpp
+++ b/src/mame/drivers/mx2178.cpp
@@ -84,18 +84,16 @@ INPUT_PORTS_END
MC6845_UPDATE_ROW( mx2178_state::crtc_update_row )
{
- const rgb_t *pens = m_palette->palette()->entry_list_raw();
- uint8_t chr,gfx;
- uint16_t mem,x;
- uint32_t *p = &bitmap.pix32(y);
+ rgb_t const *const pens = m_palette->palette()->entry_list_raw();
+ uint32_t *p = &bitmap.pix(y);
- for (x = 0; x < x_count; x++)
+ for (uint16_t x = 0; x < x_count; x++)
{
- mem = (ma + x) & 0x7ff;
- chr = m_p_videoram[mem];
+ uint16_t mem = (ma + x) & 0x7ff;
+ uint8_t chr = m_p_videoram[mem];
/* get pattern of pixels for that character scanline */
- gfx = m_p_chargen[(chr<<4) | ra] ^ ((x == cursor_x) ? 0xff : 0);
+ uint8_t gfx = m_p_chargen[(chr<<4) | ra] ^ ((x == cursor_x) ? 0xff : 0);
/* Display a scanline of a character (8 pixels) */
*p++ = pens[BIT(gfx, 7)];
diff --git a/src/mame/drivers/myb3k.cpp b/src/mame/drivers/myb3k.cpp
index 720357451c9..ebfe5b95628 100644
--- a/src/mame/drivers/myb3k.cpp
+++ b/src/mame/drivers/myb3k.cpp
@@ -305,7 +305,7 @@ MC6845_UPDATE_ROW( myb3k_state::crtc_update_row )
{
for (int pxl = 0; pxl < 8; pxl++)
{
- bitmap.pix32(y, ( x_pos * 8) + pxl) = rgb_t::black();
+ bitmap.pix(y, ( x_pos * 8) + pxl) = rgb_t::black();
}
}
else
@@ -332,7 +332,7 @@ MC6845_UPDATE_ROW( myb3k_state::crtc_update_row )
//pind ^= ((cursor_x != -1 && x_pos == cursor_x && ra == 7) ? 7 : 0);
/* Create the grey scale */
- bitmap.pix32(y, ( x_pos * 8) + pxl) = (*m_pal)[pind & 0x07];
+ bitmap.pix(y, ( x_pos * 8) + pxl) = (*m_pal)[pind & 0x07];
}
}
break;
@@ -372,7 +372,7 @@ MC6845_UPDATE_ROW( myb3k_state::crtc_update_row )
pind ^= ((cursor_x != -1 && x_pos == cursor_x && ra == 7) ? 7 : 0);
/* Pick up the color */
- bitmap.pix32(y, ( x_pos * 8) + pxl) = (*m_pal)[pind & 0x07];
+ bitmap.pix(y, ( x_pos * 8) + pxl) = (*m_pal)[pind & 0x07];
}
}
break;
@@ -394,11 +394,11 @@ MC6845_UPDATE_ROW( myb3k_state::crtc_update_row )
{
if ((pdat & (0x80 >> pxl)) != 0)
{
- bitmap.pix32(y, ( x_pos * 8) + pxl) = (*m_pal)[0x07];
+ bitmap.pix(y, ( x_pos * 8) + pxl) = (*m_pal)[0x07];
}
else
{
- bitmap.pix32(y, ( x_pos * 8) + pxl) = rgb_t::black();
+ bitmap.pix(y, ( x_pos * 8) + pxl) = rgb_t::black();
}
}
}
diff --git a/src/mame/drivers/mycom.cpp b/src/mame/drivers/mycom.cpp
index cd6f3f66ecb..a7fdd4f6403 100644
--- a/src/mame/drivers/mycom.cpp
+++ b/src/mame/drivers/mycom.cpp
@@ -148,20 +148,17 @@ private:
MC6845_UPDATE_ROW( mycom_state::crtc_update_row )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- u8 chr,gfx=0,z;
- u16 mem,x;
- u32 *p = &bitmap.pix32(y);
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ u32 *p = &bitmap.pix(y);
if (m_port0a & 0x40)
{
- for (x = 0; x < x_count; x++) // lores pixels
+ for (u16 x = 0; x < x_count; x++) // lores pixels
{
- u8 dbit=1;
- if (x == cursor_x) dbit=0;
- mem = (ma + x) & 0x7ff;
- chr = m_vram[mem];
- z = ra / 3;
+ u8 dbit = (x == cursor_x) ? 0 : 1;
+ u16 mem = (ma + x) & 0x7ff;
+ u8 chr = m_vram[mem];
+ u8 z = ra / 3;
*p++ = palette[BIT( chr, z ) ? dbit: dbit^1];
*p++ = palette[BIT( chr, z ) ? dbit: dbit^1];
*p++ = palette[BIT( chr, z ) ? dbit: dbit^1];
@@ -175,16 +172,16 @@ MC6845_UPDATE_ROW( mycom_state::crtc_update_row )
}
else
{
- for (x = 0; x < x_count; x++) // text
+ for (u16 x = 0; x < x_count; x++) // text
{
- u8 inv=0;
- if (x == cursor_x) inv=0xff;
- mem = (ma + x) & 0x7ff;
+ u8 inv = (x == cursor_x) ? 0xff : 0;
+ u16 mem = (ma + x) & 0x7ff;
+ u8 gfx;
if (ra > 7)
gfx = inv; // some blank spacing lines
else
{
- chr = m_vram[mem];
+ u8 chr = m_vram[mem];
gfx = m_p_chargen[(chr<<3) | ra] ^ inv;
}
diff --git a/src/mame/drivers/mz2000.cpp b/src/mame/drivers/mz2000.cpp
index 36331ccade5..f227ea79c00 100644
--- a/src/mame/drivers/mz2000.cpp
+++ b/src/mame/drivers/mz2000.cpp
@@ -183,8 +183,8 @@ uint32_t mz2000_state::screen_update_mz2000(screen_device &screen, bitmap_ind16
pen |= ((gvram[count+0xc000] >> (xi)) & 1) ? 4 : 0; //G
pen &= m_gvram_mask;
- bitmap.pix16(y*2+0, x+xi) = m_palette->pen(pen);
- bitmap.pix16(y*2+1, x+xi) = m_palette->pen(pen);
+ bitmap.pix(y*2+0, x+xi) = m_palette->pen(pen);
+ bitmap.pix(y*2+1, x+xi) = m_palette->pen(pen);
}
count++;
}
@@ -224,27 +224,27 @@ uint32_t mz2000_state::screen_update_mz2000(screen_device &screen, bitmap_ind16
{
if(m_width80 == 0)
{
- bitmap.pix16(res_y, res_x*2+0) = m_palette->pen(pen);
- bitmap.pix16(res_y, res_x*2+1) = m_palette->pen(pen);
+ bitmap.pix(res_y, res_x*2+0) = m_palette->pen(pen);
+ bitmap.pix(res_y, res_x*2+1) = m_palette->pen(pen);
}
else
{
- bitmap.pix16(res_y, res_x) = m_palette->pen(pen);
+ bitmap.pix(res_y, res_x) = m_palette->pen(pen);
}
}
else
{
if(m_width80 == 0)
{
- bitmap.pix16(res_y*2+0, res_x*2+0) = m_palette->pen(pen);
- bitmap.pix16(res_y*2+0, res_x*2+1) = m_palette->pen(pen);
- bitmap.pix16(res_y*2+1, res_x*2+0) = m_palette->pen(pen);
- bitmap.pix16(res_y*2+1, res_x*2+1) = m_palette->pen(pen);
+ bitmap.pix(res_y*2+0, res_x*2+0) = m_palette->pen(pen);
+ bitmap.pix(res_y*2+0, res_x*2+1) = m_palette->pen(pen);
+ bitmap.pix(res_y*2+1, res_x*2+0) = m_palette->pen(pen);
+ bitmap.pix(res_y*2+1, res_x*2+1) = m_palette->pen(pen);
}
else
{
- bitmap.pix16(res_y*2+0, res_x) = m_palette->pen(pen);
- bitmap.pix16(res_y*2+1, res_x) = m_palette->pen(pen);
+ bitmap.pix(res_y*2+0, res_x) = m_palette->pen(pen);
+ bitmap.pix(res_y*2+1, res_x) = m_palette->pen(pen);
}
}
}
diff --git a/src/mame/drivers/mz2500.cpp b/src/mame/drivers/mz2500.cpp
index c2a1c297686..055fc956233 100644
--- a/src/mame/drivers/mz2500.cpp
+++ b/src/mame/drivers/mz2500.cpp
@@ -6,6 +6,9 @@
driver by Angelo Salese
+ Computer box contains 2 floppy drives on the right, and a front-loading cassette player on the left.
+ Keyboard is separate, and the key layout is very similar to the fm7.
+
TODO:
- Kanji text is cutted in half when font_size is 1 / interlace is disabled, different ROM used? (check Back to the Future);
- Implement external ROM hook-up;
@@ -69,23 +72,23 @@ void mz2500_state::mz2500_draw_pixel(bitmap_ind16 &bitmap,int x,int y,uint16_t
{
if(width && height)
{
- bitmap.pix16(y*2+0, x*2+0) = m_palette->pen(pen);
- bitmap.pix16(y*2+0, x*2+1) = m_palette->pen(pen);
- bitmap.pix16(y*2+1, x*2+0) = m_palette->pen(pen);
- bitmap.pix16(y*2+1, x*2+1) = m_palette->pen(pen);
+ bitmap.pix(y*2+0, x*2+0) = m_palette->pen(pen);
+ bitmap.pix(y*2+0, x*2+1) = m_palette->pen(pen);
+ bitmap.pix(y*2+1, x*2+0) = m_palette->pen(pen);
+ bitmap.pix(y*2+1, x*2+1) = m_palette->pen(pen);
}
else if(width)
{
- bitmap.pix16(y, x*2+0) = m_palette->pen(pen);
- bitmap.pix16(y, x*2+1) = m_palette->pen(pen);
+ bitmap.pix(y, x*2+0) = m_palette->pen(pen);
+ bitmap.pix(y, x*2+1) = m_palette->pen(pen);
}
else if(height)
{
- bitmap.pix16(y*2+0, x) = m_palette->pen(pen);
- bitmap.pix16(y*2+1, x) = m_palette->pen(pen);
+ bitmap.pix(y*2+0, x) = m_palette->pen(pen);
+ bitmap.pix(y*2+1, x) = m_palette->pen(pen);
}
else
- bitmap.pix16(y, x) = m_palette->pen(pen);
+ bitmap.pix(y, x) = m_palette->pen(pen);
}
void mz2500_state::draw_80x25(bitmap_ind16 &bitmap,const rectangle &cliprect,uint16_t map_addr)
@@ -1274,18 +1277,18 @@ void mz2500_state::mz2500_io(address_map &map)
/* Input ports */
static INPUT_PORTS_START( mz2500 )
PORT_START("KEY0")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1)
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2)
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3)
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4)
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5)
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6)
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7)
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8)
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
PORT_START("KEY1")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9)
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10)
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("8 (PAD)") PORT_CODE(KEYCODE_8_PAD)
PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("9 (PAD)") PORT_CODE(KEYCODE_9_PAD)
PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(", (PAD)") PORT_CODE(KEYCODE_COMMA_PAD)
@@ -1304,91 +1307,91 @@ static INPUT_PORTS_START( mz2500 )
PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("7 (PAD)") PORT_CODE(KEYCODE_7_PAD)
PORT_START("KEY3")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB)
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(27)
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP)
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN)
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT)
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT)
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("BREAK") //PORT_CODE(KEYCODE_ESC)
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Up") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("BREAK") PORT_CHAR(3) //PORT_CODE(KEYCODE_ESC)
PORT_START("KEY4")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("/") //PORT_CODE(KEYCODE_SLASH)
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
PORT_START("KEY5")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('H')
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('I')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('J')
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('K')
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('L')
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('M')
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('N')
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('O')
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
PORT_START("KEY6")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('P')
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('R')
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('S')
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('T')
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('U')
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('V')
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
PORT_START("KEY7")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("^")
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) //Yen symbol
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("_")
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(".")
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(",")
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("^") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('^')
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("\xEF\xBF\xA5") PORT_CHAR(165) PORT_CHAR('|') //Yen symbol
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("_") PORT_CHAR('_')
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_START("KEY8")
PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
- PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7')
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
PORT_START("KEY9")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
- PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(":")
- PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(";")
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS)
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("@")
- PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("[")
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(":") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*')
+ PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("@") PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('@') PORT_CHAR('`')
+ PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("[") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[') PORT_CHAR('{')
PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_UNUSED)
PORT_START("KEYA")
- PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("]")
+ PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("]") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR(']') PORT_CHAR('}')
PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("COPY")
PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("CLR")
PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("INST")
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("BACKSPACE") PORT_CODE(KEYCODE_BACKSPACE)
- PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("ESC")
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("BACKSPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x20,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_TILDE) PORT_CHAR(27)
PORT_BIT(0x40,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("* (PAD)") PORT_CODE(KEYCODE_ASTERISK)
PORT_BIT(0x80,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("/ (PAD)") PORT_CODE(KEYCODE_SLASH_PAD)
PORT_START("KEYB")
PORT_BIT(0x01,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("GRPH")
PORT_BIT(0x02,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("SLOCK")
- PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT)
+ PORT_BIT(0x04,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
PORT_BIT(0x08,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("KANA")
- PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("CTRL")
+ PORT_BIT(0x10,IP_ACTIVE_LOW,IPT_KEYBOARD) PORT_NAME("CTRL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
PORT_BIT(0xe0,IP_ACTIVE_LOW,IPT_UNUSED)
PORT_START("KEYC")
diff --git a/src/mame/drivers/mz3500.cpp b/src/mame/drivers/mz3500.cpp
index 0b9b537c340..d9689c2afa1 100644
--- a/src/mame/drivers/mz3500.cpp
+++ b/src/mame/drivers/mz3500.cpp
@@ -167,39 +167,29 @@ UPD7220_DISPLAY_PIXELS_MEMBER( mz3500_state::hgdc_display_pixels )
UPD7220_DRAW_TEXT_LINE_MEMBER( mz3500_state::hgdc_draw_text )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int x;
- int xi,yi;
- int tile;
- int attr;
- uint8_t tile_data;
- uint8_t width80;
- uint8_t char_size;
- uint8_t hires;
- uint8_t color_mode;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
// popmessage("%02x",m_crtc[6]);
- color_mode = m_crtc[4] & 1;
- width80 = (m_crtc[5] & 2) >> 1;
- hires = (m_crtc[6] & 1);
- char_size = (hires) ? 16 : 8;
+ uint8_t color_mode = m_crtc[4] & 1;
+ uint8_t width80 = (m_crtc[5] & 2) >> 1;
+ uint8_t hires = (m_crtc[6] & 1);
+ uint8_t char_size = (hires) ? 16 : 8;
- for( x = 0; x < pitch; x++ )
+ for( int x = 0; x < pitch; x++ )
{
- tile = (m_video_ram[(((addr+x)*2) & 0x1fff) >> 1] & 0xff);
- attr = ((m_video_ram[(((addr+x)*2+1) & 0x3ffff) >> 1] >> 8) & 0x0f);
+ int tile = (m_video_ram[(((addr+x)*2) & 0x1fff) >> 1] & 0xff);
+ int attr = ((m_video_ram[(((addr+x)*2+1) & 0x3ffff) >> 1] >> 8) & 0x0f);
//if(hires)
// tile <<= 1;
- for( yi = 0; yi < lr; yi++)
+ for( int yi = 0; yi < lr; yi++)
{
- tile_data = m_char_rom[((tile*16+yi) & 0xfff) | (hires*0x1000)];
+ uint8_t tile_data = m_char_rom[((tile*16+yi) & 0xfff) | (hires*0x1000)];
- for( xi = 0; xi < 8; xi++)
+ for( int xi = 0; xi < 8; xi++)
{
- int res_x,res_y;
int pen;
if(yi >= char_size)
@@ -227,18 +217,18 @@ UPD7220_DRAW_TEXT_LINE_MEMBER( mz3500_state::hgdc_draw_text )
}
}
- res_x = x * 8 + xi;
- res_y = y + yi;
+ int res_x = x * 8 + xi;
+ int res_y = y + yi;
if(pen != -1)
{
if(!width80)
{
- bitmap.pix32(res_y, res_x*2+0) = palette[pen];
- bitmap.pix32(res_y, res_x*2+1) = palette[pen];
+ bitmap.pix(res_y, res_x*2+0) = palette[pen];
+ bitmap.pix(res_y, res_x*2+1) = palette[pen];
}
else
- bitmap.pix32(res_y, res_x) = palette[pen];
+ bitmap.pix(res_y, res_x) = palette[pen];
}
}
}
diff --git a/src/mame/drivers/mz6500.cpp b/src/mame/drivers/mz6500.cpp
index 76ba97cf42a..464cb888dd3 100644
--- a/src/mame/drivers/mz6500.cpp
+++ b/src/mame/drivers/mz6500.cpp
@@ -50,19 +50,14 @@ private:
UPD7220_DISPLAY_PIXELS_MEMBER( mz6500_state::hgdc_display_pixels )
{
- const rgb_t *palette = m_palette->palette()->entry_list_raw();
- int gfx[3];
- u8 i,pen;
+ rgb_t const *const palette = m_palette->palette()->entry_list_raw();
+ int const gfx[3] = { m_vram[(address + 0x00000) >> 1], m_vram[(address + 0x10000) >> 1], m_vram[(address + 0x20000) >> 1] };
- gfx[0] = m_vram[(address + 0x00000) >> 1];
- gfx[1] = m_vram[(address + 0x10000) >> 1];
- gfx[2] = m_vram[(address + 0x20000) >> 1];
-
- for(i=0; i<16; i++)
+ for(u8 i=0; i<16; i++)
{
- pen = (BIT(gfx[0], i)) | (BIT(gfx[1], i) << 1) | (BIT(gfx[2], i) << 2);
+ u8 pen = (BIT(gfx[0], i)) | (BIT(gfx[1], i) << 1) | (BIT(gfx[2], i) << 2);
- bitmap.pix32(y, x + i) = palette[pen];
+ bitmap.pix(y, x + i) = palette[pen];
}
}
diff --git a/src/mame/drivers/nakajies.cpp b/src/mame/drivers/nakajies.cpp
index a033f08bb83..8551fc700c6 100644
--- a/src/mame/drivers/nakajies.cpp
+++ b/src/mame/drivers/nakajies.cpp
@@ -685,7 +685,7 @@ uint32_t nakajies_state::screen_update(screen_device &screen, bitmap_ind16 &bitm
for (int px=0; px<8; px++)
{
- bitmap.pix16(y, (x * 8) + px) = BIT(data, 7);
+ bitmap.pix(y, (x * 8) + px) = BIT(data, 7);
data <<= 1;
}
}
diff --git a/src/mame/drivers/namcos10.cpp b/src/mame/drivers/namcos10.cpp
index 65012edf71e..5aabe9b3387 100644
--- a/src/mame/drivers/namcos10.cpp
+++ b/src/mame/drivers/namcos10.cpp
@@ -407,7 +407,9 @@ earlier TK games, so it appears to be optional or is only used by the later TK51
#include "machine/ns10crypt.h"
#include "cpu/psx/psx.h"
+#include "cpu/tlcs900/tmp95c061.h"
#include "machine/ram.h"
+//#include "sound/spu.h"
#include "video/psx.h"
#include "screen.h"
#include "speaker.h"
@@ -417,12 +419,17 @@ class namcos10_state : public driver_device
{
public:
namcos10_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu") { }
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_exio_mcu(*this, "exio_mcu")
+ , m_memp3_mcu(*this, "memp3_mcu")
+ { }
void namcos10_base(machine_config &config);
void namcos10_memm(machine_config &config);
void namcos10_memn(machine_config &config);
+ void namcos10_memn_exio(machine_config &config);
+ void namcos10_memp3(machine_config &config);
void ns10_konotako(machine_config &config);
void ns10_mrdrilr2(machine_config &config);
void ns10_knpuzzle(machine_config &config);
@@ -504,6 +511,8 @@ private:
DECLARE_MACHINE_RESET(namcos10);
void memn_driver_init( );
required_device<psxcpu_device> m_maincpu;
+ optional_device<tmp95c061_device> m_exio_mcu;
+ optional_device<tmp95c061_device> m_memp3_mcu;
};
@@ -938,7 +947,7 @@ void namcos10_state::namcos10_base(machine_config &config)
/* basic machine hardware */
CXD8606BQ(config, m_maincpu, XTAL(101'491'200));
m_maincpu->set_disable_rom_berr(true);
- m_maincpu->subdevice<ram_device>("ram")->set_default_size("16M");
+ m_maincpu->subdevice<ram_device>("ram")->set_default_size("16M"); // ->set_default_size("4M"); 2 IS41LV16100s
// The bios first configures the ROM window as 80000-big, then
// switches to 400000. If berr is active, the first configuration
// wipes all handlers after 1fc80000, which kills the system
@@ -947,13 +956,15 @@ void namcos10_state::namcos10_base(machine_config &config)
MCFG_MACHINE_RESET_OVERRIDE(namcos10_state, namcos10)
/* video hardware */
- CXD8561CQ(config, "gpu", XTAL(53'693'175), 0x200000, subdevice<psxcpu_device>("maincpu")).set_screen("screen");
+ CXD8561CQ(config, "gpu", XTAL(53'693'175), 0x200000, subdevice<psxcpu_device>("maincpu")).set_screen("screen"); // 2 54V25632s
SCREEN(config, "screen", SCREEN_TYPE_RASTER);
/* sound hardware */
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
+
+ // CXD2938Q; SPU with CD-ROM controller - also seen in PSone, 101.4912MHz / 3?
}
void namcos10_state::namcos10_memm(machine_config &config)
@@ -968,6 +979,19 @@ void namcos10_state::namcos10_memn(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &namcos10_state::namcos10_memn_map);
}
+void namcos10_state::namcos10_memn_exio(machine_config &config)
+{
+ namcos10_memn(config);
+ TMP95C061(config, m_exio_mcu, XTAL(22'118'400)).set_disable(); // not hooked up
+}
+
+void namcos10_state::namcos10_memp3(machine_config &config)
+{
+ namcos10_memn(config);
+ TMP95C061(config, m_memp3_mcu, XTAL(16'934'400)).set_disable(); // not hooked up
+ // LC82310 16.9344MHz
+}
+
void namcos10_state::ns10_mrdrilr2(machine_config &config)
{
namcos10_memm(config);
@@ -1315,26 +1339,26 @@ ROM_START( pacmball )
ROM_LOAD( "k9f2808u0c.8d", 0x1080000, 0x1080000, CRC(f79d7199) SHA1(4ef9b758ee778e12f7fef717e063597299fb8219) )
ROM_END
-GAME( 2000, mrdrilr2, 0, ns10_mrdrilr2, namcos10, namcos10_state, init_mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Japan, DR21 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
-GAME( 2000, mrdrlr2a, mrdrilr2, ns10_mrdrilr2, namcos10, namcos10_state, init_mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (World, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
-GAME( 2000, ptblank3, 0, namcos10_memn, namcos10, namcos10_state, init_gunbalna, ROT0, "Namco", "Point Blank 3 (World, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2000, gunbalina, ptblank3, namcos10_memn, namcos10, namcos10_state, init_gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2001, gjspace, 0, ns10_gjspace , namcos10, namcos10_state, init_gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2001, g13jnc, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Eighting / Raizing / Namco", "Golgo 13: Juusei no Chinkonka (Japan, GLT1 VER.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2001, mrdrilrg, 0, namcos10_memn, namcos10, namcos10_state, init_mrdrilrg, ROT0, "Namco", "Mr. Driller G (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
-GAME( 2001, mrdrilrga, mrdrilrg, namcos10_memn, namcos10, namcos10_state, init_mrdrilrg, ROT0, "Namco", "Mr. Driller G ALT (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
-GAME( 2001, knpuzzle, 0, ns10_knpuzzle, namcos10, namcos10_state, init_knpuzzle, ROT0, "Namco", "Kotoba no Puzzle Mojipittan (Japan, KPM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2001, kd2001, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Knock Down 2001 (Japan, KD11 Ver. B)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
-GAME( 2002, chocovdr, 0, ns10_chocovdr, namcos10, namcos10_state, init_chocovdr, ROT0, "Namco", "Uchuu Daisakusen: Chocovader Contactee (Japan, CVC1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2002, startrgn, 0, ns10_startrgn, namcos10, namcos10_state, init_startrgn, ROT0, "Namco", "Star Trigon (Japan, STT1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
-GAME( 2002, panikuru, 0, namcos10_memn, namcos10, namcos10_state, init_panikuru, ROT0, "Namco", "Panicuru Panekuru (Japan, PPA1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2002, gamshara, 0, ns10_gamshara, namcos10, namcos10_state, init_gamshara, ROT0, "Mitchell", "Gamshara (World, 10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // Ver. 20020912A ETC
-GAME( 2002, gamsharaj, gamshara, ns10_gamshara, namcos10, namcos10_state, init_gamshara, ROT0, "Mitchell", "Gamshara (Japan, 10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2003, nflclsfb, 0, ns10_nflclsfb, namcos10, namcos10_state, init_nflclsfb, ROT0, "Namco", "NFL Classic Football (US, NCF3 Ver.A.)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2003, pacmball, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Pacman BALL (PMB2 Ver.A.)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-GAME( 2003, konotako, 0, ns10_konotako, namcos10, namcos10_state, init_konotako, ROT0, "Mitchell", "Kono Tako (10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
-GAME( 2004, sekaikh, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Sekai Kaseki Hakken (Japan, SKH1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
-GAME( 2004, taiko6, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Taiko no Tatsujin 6 (Japan, TK61 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
-GAME( 2006, keroro, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Keroro Gunso Chikyu Shinryaku Shirei Dearimasu! (KRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // ã‚±ãƒ­ãƒ­è»æ›¹ã€€åœ°çƒä¾µç•¥æŒ‡ä»¤â€¦ã§ã‚りã¾ã™ï¼
-GAME( 2007, gegemdb, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Gegege no Kitaro Yokai Yokocho Matsuri De Batoru Ja (GYM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // ゲゲゲã®é¬¼å¤ªéƒŽã€€å¦–怪横ä¸ã¾ã¤ã‚Šã§ãƒãƒˆãƒ«ã˜ã‚ƒ
-GAME( 200?, unks10md, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "unknown Namco System 10 medal game (MTL1 SPR0B)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
+GAME( 2000, mrdrilr2, 0, ns10_mrdrilr2, namcos10, namcos10_state, init_mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Japan, DR21 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
+GAME( 2000, mrdrlr2a, mrdrilr2, ns10_mrdrilr2, namcos10, namcos10_state, init_mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (World, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
+GAME( 2000, ptblank3, 0, namcos10_memn_exio, namcos10, namcos10_state, init_gunbalna, ROT0, "Namco", "Point Blank 3 (World, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // needs to hookup gun IO
+GAME( 2000, gunbalina, ptblank3, namcos10_memn_exio, namcos10, namcos10_state, init_gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // ""
+GAME( 2001, gjspace, 0, ns10_gjspace, namcos10, namcos10_state, init_gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2001, g13jnc, 0, namcos10_memp3, namcos10, namcos10_state, empty_init, ROT0, "Eighting / Raizing / Namco", "Golgo 13: Juusei no Chinkonka (Japan, GLT1 VER.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2001, mrdrilrg, 0, namcos10_memn, namcos10, namcos10_state, init_mrdrilrg, ROT0, "Namco", "Mr. Driller G (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
+GAME( 2001, mrdrilrga, mrdrilrg, namcos10_memn, namcos10, namcos10_state, init_mrdrilrg, ROT0, "Namco", "Mr. Driller G ALT (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks
+GAME( 2001, knpuzzle, 0, ns10_knpuzzle, namcos10, namcos10_state, init_knpuzzle, ROT0, "Namco", "Kotoba no Puzzle Mojipittan (Japan, KPM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2001, kd2001, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Knock Down 2001 (Japan, KD11 Ver. B)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
+GAME( 2002, chocovdr, 0, ns10_chocovdr, namcos10, namcos10_state, init_chocovdr, ROT0, "Namco", "Uchuu Daisakusen: Chocovader Contactee (Japan, CVC1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2002, startrgn, 0, ns10_startrgn, namcos10, namcos10_state, init_startrgn, ROT0, "Namco", "Star Trigon (Japan, STT1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
+GAME( 2002, panikuru, 0, namcos10_memn, namcos10, namcos10_state, init_panikuru, ROT0, "Namco", "Panicuru Panekuru (Japan, PPA1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2002, gamshara, 0, ns10_gamshara, namcos10, namcos10_state, init_gamshara, ROT0, "Mitchell", "Gamshara (World, 10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // Ver. 20020912A ETC
+GAME( 2002, gamsharaj, gamshara, ns10_gamshara, namcos10, namcos10_state, init_gamshara, ROT0, "Mitchell", "Gamshara (Japan, 10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2003, nflclsfb, 0, ns10_nflclsfb, namcos10, namcos10_state, init_nflclsfb, ROT0, "Namco", "NFL Classic Football (US, NCF3 Ver.A.)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2003, pacmball, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Pacman BALL (PMB2 Ver.A.)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
+GAME( 2003, konotako, 0, ns10_konotako, namcos10, namcos10_state, init_konotako, ROT0, "Mitchell", "Kono Tako (10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
+GAME( 2004, sekaikh, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Sekai Kaseki Hakken (Japan, SKH1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
+GAME( 2004, taiko6, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Taiko no Tatsujin 6 (Japan, TK61 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
+GAME( 2006, keroro, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Keroro Gunso Chikyu Shinryaku Shirei Dearimasu! (KRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // ã‚±ãƒ­ãƒ­è»æ›¹ã€€åœ°çƒä¾µç•¥æŒ‡ä»¤â€¦ã§ã‚りã¾ã™ï¼
+GAME( 2007, gegemdb, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "Gegege no Kitaro Yokai Yokocho Matsuri De Batoru Ja (GYM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) // ゲゲゲã®é¬¼å¤ªéƒŽã€€å¦–怪横ä¸ã¾ã¤ã‚Šã§ãƒãƒˆãƒ«ã˜ã‚ƒ
+GAME( 200?, unks10md, 0, namcos10_memn, namcos10, namcos10_state, empty_init, ROT0, "Namco", "unknown Namco System 10 medal game (MTL1 SPR0B)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
diff --git a/src/mame/drivers/namcos12.cpp b/src/mame/drivers/namcos12.cpp
index 8a90913b3d5..29648ffb258 100644
--- a/src/mame/drivers/namcos12.cpp
+++ b/src/mame/drivers/namcos12.cpp
@@ -870,8 +870,8 @@ Type 2
SYSTEM12 COH716 PCB 8661962301 (8661972301)
(manufactured by Namco, probably in 2001, under license from Sony)
Component layout is identical to COH-700 PCB with some updated components. Generally
- it has 2X the amount of video RAM and 4X the amount of program RAM that the COH-700 PCB has.
- KM4132G271Q replaced with OKI 54V25632A 256k x 32-bit x 2 Banks SGRAM (x2, QFP100)
+ it has 4X the amount of program RAM that the COH-700 PCB has.
+ KM4132G271Q replaced with OKI 54V25632A 128k x 32-bit x 2 Banks SGRAM (x2, QFP100)
KM416V1204 replaced with Samsung Electronics K4E6416120D 4M x16 EDO DRAM (x2, TSOP44)
Updated Sony CXD8561CQ GPU (QFP208)
Updated Sony CXD8606BQ R3000A-based CPU (QFP208)
@@ -1761,11 +1761,11 @@ void namcos12_state::coh700(machine_config &config)
/* basic machine hardware */
CXD8661R(config, m_maincpu, XTAL(100'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &namcos12_state::namcos12_map);
- m_maincpu->subdevice<ram_device>("ram")->set_default_size("4M");
+ m_maincpu->subdevice<ram_device>("ram")->set_default_size("4M"); // 2 KM416V1204s
m_maincpu->subdevice<psxdma_device>("dma")->install_read_handler(5, psxdma_device::read_delegate(&namcos12_state::namcos12_rom_read, this));
/* video hardware */
- CXD8654Q(config, "gpu", XTAL(53'693'175), 0x200000, subdevice<psxcpu_device>("maincpu")).set_screen("screen");
+ CXD8654Q(config, "gpu", XTAL(53'693'175), 0x200000, subdevice<psxcpu_device>("maincpu")).set_screen("screen"); // 2 KM4132G271Qs
SCREEN(config, "screen", SCREEN_TYPE_RASTER).screen_vblank().set(FUNC(namcos12_state::namcos12_sub_irq));
}
@@ -1777,11 +1777,11 @@ void namcos12_state::coh716(machine_config &config)
/* basic machine hardware */
CXD8606BQ(config, m_maincpu, XTAL(100'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &namcos12_state::namcos12_map);
- m_maincpu->subdevice<ram_device>("ram")->set_default_size("16M");
+ m_maincpu->subdevice<ram_device>("ram")->set_default_size("16M"); // 2 K4E6416120Ds
m_maincpu->subdevice<psxdma_device>("dma")->install_read_handler(5, psxdma_device::read_delegate(&namcos12_state::namcos12_rom_read, this));
/* video hardware */
- CXD8561CQ(config, "gpu", XTAL(53'693'175), 0x400000, subdevice<psxcpu_device>("maincpu")).set_screen("screen");
+ CXD8561CQ(config, "gpu", XTAL(53'693'175), 0x200000, subdevice<psxcpu_device>("maincpu")).set_screen("screen"); // 2 54V25632As
SCREEN(config, "screen", SCREEN_TYPE_RASTER).screen_vblank().set(FUNC(namcos12_state::namcos12_sub_irq));
}
diff --git a/src/mame/drivers/namcos21.cpp b/src/mame/drivers/namcos21.cpp
index ee8177e023d..359c646a822 100644
--- a/src/mame/drivers/namcos21.cpp
+++ b/src/mame/drivers/namcos21.cpp
@@ -433,20 +433,19 @@ uint16_t namcos21_state::winrun_gpu_videoram_r(offs_t offset)
void namcos21_state::winrun_bitmap_draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint8_t *videoram = m_gpu_videoram.get();
+ uint8_t const *const videoram = m_gpu_videoram.get();
//printf("%d %d (%d %d) - %04x %04x %04x|%04x %04x\n",cliprect.top(),cliprect.bottom(),m_screen->vpos(),m_gpu_intc->get_posirq_line(),m_winrun_gpu_register[0],m_winrun_gpu_register[2/2],m_winrun_gpu_register[4/2],m_winrun_gpu_register[0xa/2],m_winrun_gpu_register[0xc/2]);
- int yscroll = -cliprect.top()+(int16_t)m_winrun_gpu_register[0x2/2];
- int xscroll = 0;//m_winrun_gpu_register[0xc/2] >> 7;
- int base = 0x1000+0x100*(m_winrun_color&0xf);
- int sx,sy;
- for( sy=cliprect.top(); sy<=cliprect.bottom(); sy++ )
+ int const yscroll = -cliprect.top()+(int16_t)m_winrun_gpu_register[0x2/2];
+ int const xscroll = 0;//m_winrun_gpu_register[0xc/2] >> 7;
+ int const base = 0x1000+0x100*(m_winrun_color&0xf);
+ for( int sy=cliprect.top(); sy<=cliprect.bottom(); sy++ )
{
- const uint8_t *pSource = &videoram[((yscroll+sy)&0x3ff)*0x200];
- uint16_t *pDest = &bitmap.pix16(sy);
- for( sx=cliprect.left(); sx<=cliprect.right(); sx++ )
+ uint8_t const *const pSource = &videoram[((yscroll+sy)&0x3ff)*0x200];
+ uint16_t *const pDest = &bitmap.pix(sy);
+ for( int sx=cliprect.left(); sx<=cliprect.right(); sx++ )
{
- int pen = pSource[(sx+xscroll) & 0x1ff];
+ int const pen = pSource[(sx+xscroll) & 0x1ff];
switch( pen )
{
case 0xff:
diff --git a/src/mame/drivers/namcos23.cpp b/src/mame/drivers/namcos23.cpp
index ca4b2eda839..12d30f9fe01 100644
--- a/src/mame/drivers/namcos23.cpp
+++ b/src/mame/drivers/namcos23.cpp
@@ -2060,16 +2060,16 @@ void namcos23_renderer::render_scanline(int32_t scanline, const extent_t& extent
float u = extent.param[1].start;
float v = extent.param[2].start;
float l = extent.param[3].start;
- float dw = extent.param[0].dpdx;
- float du = extent.param[1].dpdx;
- float dv = extent.param[2].dpdx;
- float dl = extent.param[3].dpdx;
+ const float dw = extent.param[0].dpdx;
+ const float du = extent.param[1].dpdx;
+ const float dv = extent.param[2].dpdx;
+ const float dl = extent.param[3].dpdx;
- uint32_t *img = &object.bitmap->pix32(scanline, extent.startx);
+ uint32_t *img = &object.bitmap->pix(scanline, extent.startx);
for(int x = extent.startx; x < extent.stopx; x++) {
- float z = w ? 1/w : 0;
- uint32_t pcol = rd.texture_lookup(*rd.machine, rd.pens, u*z, v*z);
+ const float z = w ? 1/w : 0;
+ const uint32_t pcol = rd.texture_lookup(*rd.machine, rd.pens, u*z, v*z);
float ll = l*z;
*img = (light(pcol >> 16, ll) << 16) | (light(pcol >> 8, ll) << 8) | light(pcol, ll);
diff --git a/src/mame/drivers/nanos.cpp b/src/mame/drivers/nanos.cpp
index 792a3cc7053..1adfc64ad2f 100644
--- a/src/mame/drivers/nanos.cpp
+++ b/src/mame/drivers/nanos.cpp
@@ -264,8 +264,7 @@ INPUT_PORTS_END
uint32_t nanos_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// static uint8_t framecnt=0;
- uint8_t gfx;
- uint16_t sy=0,ma=0,x;
+ uint16_t sy=0,ma=0;
// framecnt++;
@@ -273,13 +272,14 @@ uint32_t nanos_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap,
{
for (uint8_t ra = 0; ra < 10; ra++)
{
- uint16_t *p = &bitmap.pix16(sy++);
+ uint16_t *p = &bitmap.pix(sy++);
- for (x = ma; x < ma + 80; x++)
+ for (uint16_t x = ma; x < ma + 80; x++)
{
+ uint8_t gfx;
if (ra < 8)
{
- uint8_t chr = m_vram[x];
+ uint8_t const chr = m_vram[x];
/* get pattern of pixels for that character scanline */
gfx = m_p_chargen[(chr<<3) | ra ];
diff --git a/src/mame/drivers/naomi.cpp b/src/mame/drivers/naomi.cpp
index d434971fdf6..eb322704257 100644
--- a/src/mame/drivers/naomi.cpp
+++ b/src/mame/drivers/naomi.cpp
@@ -704,8 +704,9 @@ Melty Blood Actress Again Version A (Rev A) 841-0061C 24455 6
/Mushiking The King Of Beetles
\Mushiking II / III / III+ (Ver. 2.001) (World) 840-0164C 24357 2 (512Mb) present 317-0437-COM present IC4# is marked "18"
/Mushiking The King Of Beetles
-Mushiking The King Of Beetles 2006 First (Japan) 840-0167C not present 2 (512Mb) present 317-0444-JPN present requires 610-0669 barcode reader
\Mushiking IV / V / VI (World) 840-0180C not present 2 (512Mb) present 317-0437-COM present IC2# is labeled "VER.1", IC4# is marked "8A", requires 610-0669 barcode reader, 838-14245-92 "MAPLE/232C CONVERT BD" (MIE-based), 838-14243 "RFID CHIP R/W BD" and RFID chip
+Mushiking The King Of Beetles 2006 First (Japan) 840-0167C not present 2 (512Mb) present 317-0444-JPN present IC4# is marked "18", require 610-0669 barcode reader
+Mushiking The King Of Beetles 2006 Second (Japan) 840-0171C not present 2 (512Mb) present 317-0444-JPN present IC4# is marked "18", require 610-0669 barcode reader
Pokasuka Ghost! 840-0170C not present 5 (512Mb) present 317-0461-COM present requires 837-14672 sensor board (SH4 based)
Radirgy Noa 841-0062C not present 4 (512Mb) present 317-5138-JPN present IC2# is labeled "VER.2" - IC4# is marked "8A"
Rhythm Tengoku 841-0177C not present 4 (512Mb) present 317-0503-JPN present IC2# is labeled "VER.2" - IC4# is marked "8A"
@@ -5055,6 +5056,20 @@ ROM_START( mushi2k5 )
ROM_PARAMETER( ":rom_board:segam2crypt:key", "-1") // 315-5881 not populated
ROM_END
+ROM_START( mushi2k62 )
+ NAOMI_BIOS
+ NAOMI_DEFAULT_EEPROM
+
+ ROM_REGION( 0x8000000, "rom_board", ROMREGION_ERASEFF)
+ ROM_LOAD( "fpr-24360.ic8", 0x0000000, 0x4000000, CRC(6e6c6633) SHA1(e5fd1ff643899067db7ebda6641852bd45c36b86) )
+ ROM_LOAD( "fpr-24361.ic9", 0x4000000, 0x4000000, CRC(ce2a9720) SHA1(0a55d1c8a67288dbad374ab812d4720cdf78ded7) )
+
+ ROM_REGION( 0x800, "pic_readout", 0 )
+ ROM_LOAD( "317-0444-jpn.ic3", 0, 0x800, CRC(6ded35a2) SHA1(0bb12bf6b090b865abd04d26d65f28c661464514) )
+
+ ROM_PARAMETER( ":rom_board:id", "5502" )
+ROM_END
+
ROM_START( crackndj )
NAOMI_BIOS
NAOMI_DEFAULT_EEPROM
@@ -11181,9 +11196,10 @@ ROM_START( vfurlong )
ROM_REGION( 0x9000000, "rom_board", ROMREGION_ERASE)
ROM_LOAD( "ax2001p01.ic18", 0x0000000, 0x0800000, CRC(17ea9aa9) SHA1(c68500e9b3407a9d4b20f2678718ce475f179f7d) )
+ ROM_LOAD( "ax2001p01_alt.ic18", 0x0000000, 0x0800000, CRC(845399dd) SHA1(21565b13292cead2b532861d2998e381df2672d5) ) // same as above except for Customer ID, included for reference
ROM_LOAD( "ax2001m01.ic11", 0x1000000, 0x1000000, CRC(64460b24) SHA1(044857d6593897d303622e005a63ca7b3acd7453) )
ROM_LOAD( "ax2002m01.ic12", 0x2000000, 0x1000000, CRC(d4da357f) SHA1(c462cddec9a369a1a5595676de76499d56683ea9) )
- ROM_LOAD( "ax2003m01.ic13", 0x3000000, 0x1000000, CRC(ad046ad7) SHA1(ac7c46e458595714e327526354e1111fb25b44e0) )
+ ROM_LOAD( "ax2003m01.ic13", 0x3000000, 0x1000000, CRC(aa1e1246) SHA1(788cc9c070f82aeff1704361e3c72116fd5c4c9d) )
ROM_LOAD( "ax2004m01.ic14", 0x4000000, 0x1000000, CRC(4d555d7c) SHA1(a5eccc920bdb7ad9cf57c0e1ef6a905c6b9eee45) )
ROM_LOAD( "ax2005m01.ic15", 0x5000000, 0x1000000, CRC(785208e2) SHA1(6ba5bd3901c5b1d71abcc8d833a011bd4abae6b6) )
ROM_LOAD( "ax2006m01.ic16", 0x6000000, 0x1000000, CRC(8134ec55) SHA1(843e473d4f99237ded641cce9515b7802cfe3742) )
@@ -11565,7 +11581,7 @@ ROM_END
// 0167 Mushiking 2K6 1ST (Japan)
/* 0170-01 */ GAME( 2007, manicpnc, naomi, naomim4, naomi, naomi_state, init_naomi, ROT0, "Sega", "Manic Panic Ghosts! (USA, Export)", GAME_FLAGS )
/* 0170 */ GAME( 2007, pokasuka, manicpnc, naomim4, naomi, naomi_state, init_naomi, ROT0, "Sega", "Pokasuka Ghost! (Japan)", GAME_FLAGS )
-// 0171 Mushiking 2K6 2ND (Japan) note: starting from ver 2K6 was moved to SystemSP platform and later to PC-based hardware
+/* 0171 */ GAME( 2006, mushi2k62, naomi, naomim4, naomi, naomi_state, init_naomi, ROT0, "Sega", "Mushiking The King Of Beetles 2006 Second (Japan)", GAME_FLAGS )
/* 0175 */ GAME( 2007, asndynmt, naomi, naomim4, naomi, naomi_state, init_naomi, ROT0, "Sega", "Asian Dynamite / Dynamite Deka EX", GAME_FLAGS )
/* 0175 */ GAME( 2007, asndynmto, asndynmt, naomim4, naomi, naomi_state, init_naomi, ROT0, "Sega", "Asian Dynamite / Dynamite Deka EX (older)", GAME_FLAGS ) // no revision stickers, presumably older revision but might be release for Asian market
/* 0177 */ GAME( 2007, rhytngk, naomi, naomim4, naomi, naomi_state, init_naomi, ROT0, "Sega / Nintendo - J.P ROOM", "Rhythm Tengoku (Japan)", GAME_FLAGS )
@@ -11846,7 +11862,7 @@ GAME( 2004, ggisuka, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave,
GAME( 2004, rumblefp, rumblef, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / Dimps", "The Rumble Fish (prototype)", GAME_FLAGS) // Feb 20 2004 09:15:34
GAME( 2004, rangrmsn, awbios, aw2c, aw1w, atomiswave_state, init_atomiswave, ROT0, "RIZ Inc./ Sammy", "Ranger Mission", GAME_FLAGS ) // Mar 01 2004 19:08:15
GAME( 2004, rumblef, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / Dimps", "The Rumble Fish", GAME_FLAGS) // Mar 10 2004 19:07:43
-GAME( 2004, salmankt, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Yuki Enterprise / Sammy", "Net Select: Salaryman Kintaro", GAME_FLAGS ) // Jun 14 2004 22:50:03
+GAME( 2004, salmankt, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Yuki Enterprise / Sammy", "Net@Select: Salaryman Kintaro", GAME_FLAGS ) // Jun 14 2004 22:50:03
GAME( 2004, kofnw, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / SNK Playmore", "The King of Fighters Neowave", GAME_FLAGS ) // Jul 09 2004 15:05:53
GAME( 2004, kofnwj, kofnw, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / SNK Playmore", "The King of Fighters Neowave (Japan)", GAME_FLAGS ) // Jul 09 2004 15:05:53
GAME( 2004, ftspeed, awbios, aw1c, aw1w, atomiswave_state, init_atomiswave, ROT0, "Sammy", "Faster Than Speed", GAME_FLAGS ) // Aug 24 2004 18:40:24
@@ -11856,7 +11872,7 @@ GAME( 2005, rumblf2p, rumblef2, aw2c, aw2c, atomiswave_state, init_atomiswave,
GAME( 2005, anmlbskta, anmlbskt, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT270, "MOSS / Sammy", "Animal Basket (19 Jan 2005)", GAME_FLAGS ) // Jan 19 2005 13:09:07
GAME( 2005, anmlbskt, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT270, "MOSS / Sammy", "Animal Basket (24 Jan 2005)", GAME_FLAGS ) // Jan 24 2005 14:12:29
GAME( 2005, waidrive, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT270, "MOSS / Sammy", "WaiWai Drive", GAME_FLAGS ) // Jan 27 2005 16:21:21
-GAME( 2005, vfurlong, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Progress / Sammy", "Net Select Horse Racing: Victory Furlong", GAME_FLAGS ) // Mar 02 2005 22:10:33
+GAME( 2005, vfurlong, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Progress / Sammy", "Net@Select: Horse Racing - Victory Furlong", GAME_FLAGS ) // Mar 02 2005 22:10:33
GAME( 2005, rumblef2, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / Dimps", "The Rumble Fish 2", GAME_FLAGS ) // Mar 04 2005 19:26:32
GAME( 2005, ngbc, awbios, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / SNK Playmore", "NeoGeo Battle Coliseum", GAME_FLAGS ) // Jun 25 2005 17:00:38
GAME( 2005, ngbcj, ngbc, aw2c, aw2c, atomiswave_state, init_atomiswave, ROT0, "Sammy / SNK Playmore", "NeoGeo Battle Coliseum (Japan)", GAME_FLAGS ) // Jun 25 2005 17:00:38
diff --git a/src/mame/drivers/nc.cpp b/src/mame/drivers/nc.cpp
index 3ac537f8601..f1e0e822cb6 100644
--- a/src/mame/drivers/nc.cpp
+++ b/src/mame/drivers/nc.cpp
@@ -873,9 +873,10 @@ Small note about natural keyboard support (both for nc100 and nc200): currently,
- "Menu" is mapped to 'F4'
*/
+// 2020-09-21: not possible to select a menu item with natural keyboard. However, you can switch over to it after you enter an app.
static INPUT_PORTS_START(nc100)
PORT_START("LINE0")
- PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT))
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT),UCHAR_SHIFT_1)
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT))
PORT_BIT(0x04, 0x00, IPT_UNUSED)
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Cursor Left (Red)") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
@@ -886,7 +887,7 @@ static INPUT_PORTS_START(nc100)
PORT_START("LINE1")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Function (Yellow)") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // 5th row, 1st key on left (where 'fn' is on mac keyboards)
- PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL))
+ PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_MAMEKEY(RCONTROL),UCHAR_SHIFT_2)
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Stop") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(F2))
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT(0x10, 0x00, IPT_UNUSED)
@@ -931,8 +932,8 @@ static INPUT_PORTS_START(nc100)
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
- PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('c') PORT_CHAR('C')
- PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
PORT_START("LINE6")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
@@ -967,7 +968,7 @@ static INPUT_PORTS_START(nc100)
PORT_START("LINE9")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
- PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del<") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('8')
+ PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del<") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
diff --git a/src/mame/drivers/ncd68k.cpp b/src/mame/drivers/ncd68k.cpp
index ecfeca15ddf..566ebcea5d0 100644
--- a/src/mame/drivers/ncd68k.cpp
+++ b/src/mame/drivers/ncd68k.cpp
@@ -210,7 +210,7 @@ u32 ncd16_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rect
{
for (unsigned y = 0; y < 1024; y++)
{
- u32 *scanline = &bitmap.pix32(y);
+ u32 *scanline = &bitmap.pix(y);
for (unsigned x = 0; x < 1024 / 8; x++)
{
u8 const pixels = m_vram->read(BYTE_XOR_BE(y * (1024 / 8) + x));
@@ -227,7 +227,7 @@ u32 ncd17c_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rec
{
for (unsigned y = 0; y < 768; y++)
{
- u32 *scanline = &bitmap.pix32(y);
+ u32 *scanline = &bitmap.pix(y);
for (unsigned x = 0; x < 1024; x++)
{
u8 const pixels = m_vram->read((y * 1024) + BYTE4_XOR_BE(x));
@@ -242,7 +242,7 @@ u32 ncd19_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, rect
{
for (unsigned y = 0; y < 1024; y++)
{
- u32 *scanline = &bitmap.pix32(y);
+ u32 *scanline = &bitmap.pix(y);
for (unsigned x = 0; x < 1280/8; x++)
{
u8 const pixels = m_vram->read((y * (2048/8)) + BYTE4_XOR_BE(x));
diff --git a/src/mame/drivers/nes_sh6578.cpp b/src/mame/drivers/nes_sh6578.cpp
index caf03628290..53e3b06992f 100644
--- a/src/mame/drivers/nes_sh6578.cpp
+++ b/src/mame/drivers/nes_sh6578.cpp
@@ -714,16 +714,17 @@ ROM_START( max10in1 )
ROM_LOAD( "csmaxxcasino10.bin", 0x000000, 0x200000, CRC(2a05e9af) SHA1(fcf591c22ce8773f72e9d0fa0bae545f6a82a063) )
ROM_END
-CONS( 1997, bandgpad, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Multi Game Player Gamepad", MACHINE_NOT_WORKING )
-CONS( 1997, bandggcn, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Go! Go! Connie-chan! Asobou Mouse", MACHINE_NOT_WORKING )
+ROM_START( vsmaxx15 )
+ ROM_REGION( 0x100000, "maincpu", 0 )
+ ROM_LOAD( "vsmaxx15n1_e28f008sa_89a2.bin", 0x00000, 0x100000, CRC(713955ce) SHA1(f5ff02055fd4574cedc2f056d19388207a7244c0) )
+ROM_END
-// possibly newer than 2001
-CONS( 2001, ts_handy11, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Techno Source", "Handy Boy 11-in-1 (TV Play Power)", MACHINE_NOT_WORKING )
+ROM_START( vsmaxx25 )
+ ROM_REGION( 0x200000, "maincpu", 0 )
+ ROM_LOAD( "vsmaxx25_am29lv160dt_000122c4.bin", 0x00000, 0x200000, CRC(0efd1625) SHA1(34e83f748af3eee475c5b2b24ff03c00c1b5b8ed) )
+ROM_END
-CONS( 200?, cpatrolm, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "TimeTop", "City Patrolman", MACHINE_NOT_WORKING )
-// ROM is banked
-CONS( 200?, ablwikid, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_abl_wikid_state, init_nes_sh6578, "Advance Bright Ltd.", "Wikid Joystick", MACHINE_NOT_WORKING ) // or Wik!d Joystick
CONS( 200?, maxx5in1, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Senario", "Vs Maxx 5-in-1 Casino / Senario Card & Casino Games", 0 ) // advertised on box as 'With Solitaire" (was there an even older version without it?)
@@ -731,3 +732,25 @@ CONS( 200?, maxx6in1, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_ne
CONS( 200?, max10in1, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_max10in1_state, init_nes_sh6578, "Senario", "Vs Maxx 10-in-1 Casino / Senario Card & Casino Games", 0 )
+// titles below have various issues (DMA, split interrupt timing etc.)
+
+ // aka Wik!d Joystick, sometimes also called Air Blaster like the real Air Blaster game. Wik!d seems a rebranding (a 'gift' company) so did ABL reuse the Air Blaster name here instead?
+CONS( 200?, ablwikid, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_abl_wikid_state, init_nes_sh6578, "Advance Bright Ltd.", "Wikid Joystick 14-in-1", MACHINE_NOT_WORKING )
+
+CONS( 2001?, ts_handy11, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Techno Source", "Handy Boy 11-in-1 (TV Play Power)", MACHINE_NOT_WORKING ) // possibly newer than 2001
+
+// from a blue coloured unit, a yellow one exists, is it the same?
+CONS( 2004?, vsmaxx15, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Senario", "Vs Maxx 15-in-1", MACHINE_NOT_WORKING )
+
+// This is from the blue coloured unit with the 1p/2p slider (does it do anything / get read anywhere?)
+// A version of the 25-in-1 on VT hardware also exists, with the downgraded version of Big Racing & removed copyrights etc. (probably the purple tinted version without the 1p/2p slider)
+CONS( 2004?, vsmaxx25, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_max10in1_state, init_nes_sh6578, "Senario", "Vs Maxx 25-in-1", MACHINE_NOT_WORKING )
+
+// titles below need inputs mapping to go further
+
+CONS( 1997, bandgpad, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Multi Game Player Gamepad", MACHINE_NOT_WORKING )
+
+CONS( 1997, bandggcn, 0, 0, nes_sh6578, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "Bandai", "Go! Go! Connie-chan! Asobou Mouse", MACHINE_NOT_WORKING )
+
+CONS( 200?, cpatrolm, 0, 0, nes_sh6578_pal, nes_sh6578, nes_sh6578_state, init_nes_sh6578, "TimeTop", "City Patrolman", MACHINE_NOT_WORKING )
+
diff --git a/src/mame/drivers/nes_vt.cpp b/src/mame/drivers/nes_vt.cpp
index 5b529698010..d6fafae4898 100644
--- a/src/mame/drivers/nes_vt.cpp
+++ b/src/mame/drivers/nes_vt.cpp
@@ -47,17 +47,12 @@ protected:
void nes_vt_map(address_map& map);
-
optional_ioport m_io0;
optional_ioport m_io1;
+
uint8_t m_latch0;
uint8_t m_latch1;
-
- /* Misc */
- uint32_t m_ahigh; // external banking bits
- uint8_t m_4242;
- uint8_t m_411c;
- uint8_t m_411d;
+ uint8_t m_previous_port0;
optional_ioport m_cartsel;
optional_ioport m_exin0;
@@ -65,6 +60,12 @@ protected:
optional_ioport m_exin2;
optional_ioport m_exin3;
+ /* Misc */
+ uint32_t m_ahigh; // external banking bits
+ uint8_t m_4242;
+ uint8_t m_411c;
+ uint8_t m_411d;
+
required_region_ptr<uint8_t> m_prgrom;
uint8_t vt_rom_r(offs_t offset);
@@ -84,7 +85,6 @@ private:
uint8_t extrain_1_r();
uint8_t extrain_2_r();
uint8_t extrain_3_r();
-
};
class nes_vt_state : public nes_vt_base_state
@@ -105,6 +105,7 @@ public:
void nes_vt_1mb_baddma(machine_config& config);
void nes_vt_2mb_baddma(machine_config& config);
void nes_vt_4mb_baddma(machine_config& config);
+ void nes_vt_4mb_baddma_rasterhack(machine_config& config);
void nes_vt_4mb(machine_config& config);
void nes_vt_8mb(machine_config& config);
void nes_vt_16mb(machine_config& config);
@@ -123,12 +124,13 @@ public:
void vt_external_space_map_1mbyte(address_map& map);
void vt_external_space_map_512kbyte(address_map& map);
+ void nes_vt_1mb_majkon(machine_config& config);
+ void vt_external_space_map_1mbyte_majkon(address_map& map);
+
void init_protpp();
protected:
required_device<nes_vt_soc_device> m_soc;
-
- void vt03_8000_mapper_w(offs_t offset, uint8_t data) { m_soc->vt03_8000_mapper_w(offset, data); }
};
@@ -141,6 +143,7 @@ public:
void nes_vt_vh2009(machine_config& config);
void nes_vt_vh2009_1mb(machine_config& config);
+ void nes_vt_vh2009_2mb(machine_config& config);
void nes_vt_vh2009_4mb(machine_config& config);
void nes_vt_vh2009_8mb(machine_config& config);
@@ -168,6 +171,7 @@ public:
{ }
void nes_vt_waixing_512kb(machine_config& config);
+ void nes_vt_waixing_512kb_rasterhack(machine_config& config);
void nes_vt_waixing_2mb(machine_config& config);
};
@@ -182,14 +186,14 @@ public:
void nes_vt_waixing_alt_pal_8mb(machine_config& config);
};
-class nes_vt_waixing_alt_duetpp_state : public nes_vt_waixing_alt_state
+class nes_vt_waixing_alt_sporzpp_state : public nes_vt_waixing_alt_state
{
public:
- nes_vt_waixing_alt_duetpp_state(const machine_config& mconfig, device_type type, const char* tag) :
+ nes_vt_waixing_alt_sporzpp_state(const machine_config& mconfig, device_type type, const char* tag) :
nes_vt_waixing_alt_state(mconfig, type, tag)
{ }
- void nes_vt_waixing_alt_4mb_duetpp(machine_config& config);
+ void nes_vt_waixing_alt_4mb_sporzpp(machine_config& config);
private:
uint8_t in1_r() override
@@ -200,6 +204,21 @@ private:
}
};
+class nes_vt_wldsoctv_state : public nes_vt_state
+{
+public:
+ nes_vt_wldsoctv_state(const machine_config& mconfig, device_type type, const char* tag) :
+ nes_vt_state(mconfig, type, tag)
+ { }
+
+private:
+ uint8_t in1_r() override
+ {
+ uint8_t i = machine().rand() & 0x18;
+ uint8_t ret = m_io1->read() & ~0x18;
+ return i | ret;
+ }
+};
class nes_vt_timetp36_state : public nes_vt_state
{
@@ -275,7 +294,6 @@ class nes_vt_cy_lexibook_state : public nes_vt_cy_state
public:
nes_vt_cy_lexibook_state(const machine_config& mconfig, device_type type, const char* tag) :
nes_vt_cy_state(mconfig, type, tag),
- m_previous_port0(0),
m_latch0_bit(0),
m_latch1_bit(0)
{ }
@@ -288,7 +306,6 @@ protected:
virtual void in0_w(uint8_t data) override;
private:
- int m_previous_port0;
uint8_t m_latch0_bit;
uint8_t m_latch1_bit;
};
@@ -349,12 +366,12 @@ public:
void nes_vt_hh_8mb(machine_config& config);
void nes_vt_vg(machine_config& config);
+ void nes_vt_vg_2mb(machine_config& config);
void nes_vt_vg_4mb(machine_config& config);
+ void nes_vt_vg_4mb_rasterhack(machine_config& config);
void nes_vt_vg_8mb(machine_config& config);
void nes_vt_vg_16mb(machine_config& config);
-
- void nes_vt_vg_1mb_majkon(machine_config& config);
void nes_vt_fp(machine_config& config);
void nes_vt_fp_16mb(machine_config& config);
void nes_vt_fp_32mb(machine_config& config);
@@ -383,7 +400,7 @@ public:
m_plunger(*this, "PLUNGER")
{ }
- void nes_vt_waixing_alt_4mb_duetpp(machine_config& config);
+ void nes_vt_waixing_alt_4mb_sporzpp(machine_config& config);
protected:
virtual void machine_start() override;
@@ -425,45 +442,51 @@ void nes_vt_base_state::vtspace_w(offs_t offset, uint8_t data)
// VTxx can address 25-bit address space (32MB of ROM) so use maps with mirroring in depending on ROM size
void nes_vt_state::vt_external_space_map_32mbyte(address_map &map)
{
- map(0x0000000, 0x1ffffff).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x1ffffff).r(FUNC(nes_vt_state::vt_rom_r));
}
void nes_vt_state::vt_external_space_map_16mbyte(address_map &map)
{
- map(0x0000000, 0x0ffffff).mirror(0x1000000).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x0ffffff).mirror(0x1000000).r(FUNC(nes_vt_state::vt_rom_r));
}
void nes_vt_state::vt_external_space_map_8mbyte(address_map &map)
{
- map(0x0000000, 0x07fffff).mirror(0x1800000).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x07fffff).mirror(0x1800000).r(FUNC(nes_vt_state::vt_rom_r));
}
void nes_vt_state::vt_external_space_map_4mbyte(address_map &map)
{
- map(0x0000000, 0x03fffff).mirror(0x1c00000).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x03fffff).mirror(0x1c00000).r(FUNC(nes_vt_state::vt_rom_r));
}
void nes_vt_state::vt_external_space_map_2mbyte(address_map &map)
{
- map(0x0000000, 0x01fffff).mirror(0x1e00000).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x01fffff).mirror(0x1e00000).r(FUNC(nes_vt_state::vt_rom_r));
}
void nes_vt_state::vt_external_space_map_1mbyte(address_map &map)
{
- map(0x0000000, 0x00fffff).mirror(0x1f00000).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x00fffff).mirror(0x1f00000).r(FUNC(nes_vt_state::vt_rom_r));
}
void nes_vt_state::vt_external_space_map_512kbyte(address_map &map)
{
- map(0x0000000, 0x007ffff).mirror(0x1f80000).rw(FUNC(nes_vt_state::vt_rom_r), FUNC(nes_vt_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x007ffff).mirror(0x1f80000).r(FUNC(nes_vt_state::vt_rom_r));
}
// Win Lose Draw has RAM as well as ROM
void nes_vt_swap_op_d5_d6_state::vt_external_space_map_senwld_512kbyte(address_map &map)
{
- map(0x0000000, 0x007ffff).rw(FUNC(nes_vt_swap_op_d5_d6_state::vt_rom_r), FUNC(nes_vt_swap_op_d5_d6_state::vtspace_w));
+ map(0x0000000, 0x007ffff).r(FUNC(nes_vt_swap_op_d5_d6_state::vt_rom_r));
map(0x0100000, 0x010ffff).ram();
- map(0x0180000, 0x01fffff).rw(FUNC(nes_vt_swap_op_d5_d6_state::vt_rom_r), FUNC(nes_vt_swap_op_d5_d6_state::vtspace_w));
+ map(0x0180000, 0x01fffff).r(FUNC(nes_vt_swap_op_d5_d6_state::vt_rom_r));
+}
+
+void nes_vt_state::vt_external_space_map_1mbyte_majkon(address_map &map)
+{
+ map(0x0000000, 0x00fffff).mirror(0x1f00000).r(FUNC(nes_vt_state::vt_rom_r));
+ map(0x1400000, 0x1401fff).ram(); // rush'n attack writes to chr space, after setting the program and character outer bank to a mirror, is the correct way to handle it?
}
// bitboy is 2 16Mbyte banks
@@ -474,7 +497,7 @@ uint8_t nes_vt_cy_state::vt_rom_banked_r(offs_t offset)
void nes_vt_cy_state::vt_external_space_map_bitboy_2x16mbyte(address_map &map)
{
- map(0x0000000, 0x0ffffff).mirror(0x1000000).rw(FUNC(nes_vt_cy_state::vt_rom_banked_r), FUNC(nes_vt_cy_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x0ffffff).mirror(0x1000000).r(FUNC(nes_vt_cy_state::vt_rom_banked_r));
}
// fapocket is 4 16Mbyte banks
@@ -485,7 +508,7 @@ uint8_t nes_vt_dg_state::vt_rom_banked_r(offs_t offset)
void nes_vt_dg_state::vt_external_space_map_fapocket_4x16mbyte(address_map &map)
{
- map(0x0000000, 0x0ffffff).mirror(0x1000000).rw(FUNC(nes_vt_dg_state::vt_rom_banked_r), FUNC(nes_vt_dg_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x0ffffff).mirror(0x1000000).r(FUNC(nes_vt_dg_state::vt_rom_banked_r));
}
uint8_t nes_vt_hh_state::vt_rom_banked_r(offs_t offset)
@@ -495,7 +518,7 @@ uint8_t nes_vt_hh_state::vt_rom_banked_r(offs_t offset)
void nes_vt_hh_state::vt_external_space_map_fp_2x32mbyte(address_map &map)
{
- map(0x0000000, 0x1ffffff).rw(FUNC(nes_vt_hh_state::vt_rom_banked_r), FUNC(nes_vt_hh_state::vt03_8000_mapper_w));
+ map(0x0000000, 0x1ffffff).r(FUNC(nes_vt_hh_state::vt_rom_banked_r));
}
uint8_t nes_vt_base_state::extrain_0_r()
@@ -565,11 +588,18 @@ uint8_t nes_vt_base_state::in1_r()
void nes_vt_base_state::in0_w(uint8_t data)
{
//logerror("%s: in0_w %02x\n", machine().describe_context(), data);
- if (data & 0x01)
- return;
- m_latch0 = m_io0->read();
- m_latch1 = m_io1->read();
+ // need to check this or some games (eg cybar120 Aero Engine) won't have working inputs as they repeatedly write a pattern of 02 / 00 here between fetches which resets the latch
+ if ((data & 0x01) != (m_previous_port0 & 0x01))
+ {
+ if (data & 0x01)
+ {
+ m_latch0 = m_io0->read();
+ m_latch1 = m_io1->read();
+ }
+ }
+
+ m_previous_port0 = data;
}
/* Lexibook I/O handlers */
@@ -626,6 +656,23 @@ void nes_vt_ablping_state::ablping_extraio_w(uint8_t data)
void nes_vt_base_state::machine_start()
{
+ m_latch0 = 0;
+ m_latch1 = 0;
+ m_previous_port0 = 0;
+
+ m_ahigh = 0;
+ m_4242 = 0;
+ m_411c = 0;
+ m_411d = 0;
+
+ save_item(NAME(m_latch0));
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_previous_port0));
+
+ save_item(NAME(m_ahigh));
+ save_item(NAME(m_4242));
+ save_item(NAME(m_411c));
+ save_item(NAME(m_411d));
}
void nes_vt_base_state::machine_reset()
@@ -716,34 +763,6 @@ void nes_vt_ablpinb_state::in0_w(uint8_t data)
}
-/* not strictly needed, but helps us see where things are in ROM to aid with figuring out banking schemes*/
-static const gfx_layout helper_layout =
-{
- 8,8,
- RGN_FRAC(1,1),
- 4,
- { 0*64, 1*64, 2*64, 3*64 },
- { 0,1,2,3,4,5,6,7 },
- { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
- 4*64
-};
-
-static const gfx_layout helper2_layout =
-{
- 8,8,
- RGN_FRAC(1,1),
- 4,
- { 0*8, 1*8, 2*8, 3*8 },
- { 0,1,2,3,4,5,6,7 },
- { 0*16, 1*16, 2*16, 3*16,4*16,5*16,5*16,6*16,7*16 },
- 4*64
-};
-
-static GFXDECODE_START( vt03_gfx_helper )
- GFXDECODE_ENTRY( "mainrom", 0, helper_layout, 0x0, 2 )
- GFXDECODE_ENTRY( "mainrom", 0, helper2_layout, 0x0, 2 )
-GFXDECODE_END
-
void nes_vt_base_state::configure_soc(nes_vt_soc_device* soc)
{
soc->set_addrmap(AS_PROGRAM, &nes_vt_state::vt_external_space_map_32mbyte);
@@ -761,7 +780,6 @@ void nes_vt_vg_1mb_majgnc_state::nes_vt_vg_1mb_majgnc(machine_config &config)
{
NES_VT_SOC(config, m_soc, NTSC_APU_CLOCK);
configure_soc(m_soc);
- m_soc->set_default_palette_mode(PAL_MODE_NEW_VG);
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_vg_1mb_majgnc_state::vt_external_space_map_1mbyte);
}
@@ -802,6 +820,13 @@ void nes_vt_state::nes_vt_4mb_baddma(machine_config& config)
{
nes_vt_4mb(config);
m_soc->force_bad_dma();
+
+}
+
+void nes_vt_state::nes_vt_4mb_baddma_rasterhack(machine_config& config)
+{
+ nes_vt_2mb_baddma(config);
+ m_soc->force_raster_timing_hack();
}
@@ -862,6 +887,13 @@ void nes_vt_waixing_state::nes_vt_waixing_512kb(machine_config &config)
m_soc->set_201x_descramble(0x3, 0x2, 0x7, 0x6, 0x5, 0x4);
}
+void nes_vt_waixing_state::nes_vt_waixing_512kb_rasterhack(machine_config &config)
+{
+ nes_vt_waixing_512kb(config);
+ m_soc->force_raster_timing_hack();
+}
+
+
void nes_vt_waixing_state::nes_vt_waixing_2mb(machine_config &config)
{
NES_VT_SOC(config, m_soc, NTSC_APU_CLOCK);
@@ -888,7 +920,7 @@ void nes_vt_waixing_alt_state::nes_vt_waixing_alt_pal_8mb(machine_config &config
m_soc->set_8000_scramble(0x5, 0x4, 0x3, 0x2, 0x7, 0x6, 0x7, 0x8);
}
-void nes_vt_waixing_alt_duetpp_state::nes_vt_waixing_alt_4mb_duetpp(machine_config& config)
+void nes_vt_waixing_alt_sporzpp_state::nes_vt_waixing_alt_4mb_sporzpp(machine_config& config)
{
NES_VT_SOC(config, m_soc, NTSC_APU_CLOCK);
configure_soc(m_soc);
@@ -896,8 +928,6 @@ void nes_vt_waixing_alt_duetpp_state::nes_vt_waixing_alt_4mb_duetpp(machine_conf
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_ablping_state::vt_external_space_map_4mbyte);
m_soc->set_201x_descramble(0x3, 0x2, 0x7, 0x6, 0x5, 0x4);
m_soc->set_8000_scramble(0x5, 0x4, 0x3, 0x2, 0x7, 0x6, 0x7, 0x8);
-
- GFXDECODE(config, "gfxdecode", "soc:ppu", vt03_gfx_helper);
}
@@ -908,7 +938,6 @@ void nes_vt_hum_state::nes_vt_hummer_2mb(machine_config& config)
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_sp69_state::vt_external_space_map_2mbyte);
m_soc->set_201x_descramble(0x7, 0x6, 0x5, 0x4, 0x2, 0x3);
m_soc->set_8000_scramble(0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8);
- GFXDECODE(config, "gfxdecode", "soc:ppu", vt03_gfx_helper);
}
void nes_vt_hum_state::nes_vt_hummer_4mb(machine_config& config)
@@ -925,7 +954,6 @@ void nes_vt_pjoy_state::nes_vt_pjoy_4mb(machine_config &config)
m_soc->set_201x_descramble(0x2, 0x3, 0x4, 0x5, 0x6, 0x7);
m_soc->set_8000_scramble(0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x8, 0x7);
m_soc->set_410x_scramble(0x8, 0x7);
- GFXDECODE(config, "gfxdecode", "soc:ppu", vt03_gfx_helper);
}
@@ -936,7 +964,6 @@ void nes_vt_sp69_state::nes_vt_4mb_sp69(machine_config& config)
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_sp69_state::vt_external_space_map_4mbyte);
m_soc->set_201x_descramble(0x4, 0x7, 0x2, 0x6, 0x5, 0x3);
m_soc->set_8000_scramble(0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8);
- GFXDECODE(config, "gfxdecode", "soc:ppu", vt03_gfx_helper);
}
void nes_vt_ablping_state::nes_vt_2mb_ablping(machine_config &config)
@@ -952,8 +979,6 @@ void nes_vt_ablping_state::nes_vt_2mb_ablping(machine_config &config)
m_soc->extra_read_3_callback().set(FUNC(nes_vt_ablping_state::ablping_extraio_r));
m_soc->extra_write_2_callback().set(FUNC(nes_vt_ablping_state::ablping_extraio_w));
m_soc->extra_write_3_callback().set(FUNC(nes_vt_ablping_state::ablping_extraio_w));
-
- GFXDECODE(config, "gfxdecode", "soc:ppu", vt03_gfx_helper);
}
uint8_t nes_vt_base_state::upper_412c_r()
@@ -980,8 +1005,6 @@ void nes_vt_state::nes_vt_4k_ram(machine_config &config)
NES_VT_SOC_4KRAM(config, m_soc, NTSC_APU_CLOCK);
configure_soc(m_soc);
- GFXDECODE(config, "gfxdecode", "soc:ppu", vt03_gfx_helper);
-
dynamic_cast<nes_vt_soc_4kram_device&>(*m_soc).upper_read_412c_callback().set(FUNC(nes_vt_state::upper_412c_r));
dynamic_cast<nes_vt_soc_4kram_device&>(*m_soc).upper_read_412d_callback().set(FUNC(nes_vt_state::upper_412d_r));
dynamic_cast<nes_vt_soc_4kram_device&>(*m_soc).upper_write_412c_callback().set(FUNC(nes_vt_state::upper_412c_w));
@@ -1074,7 +1097,6 @@ void nes_vt_hh_state::nes_vt_vg(machine_config &config)
NES_VT_SOC_8KRAM_DG(config.replace(), m_soc, NTSC_APU_CLOCK);
configure_soc(m_soc);
- m_soc->set_default_palette_mode(PAL_MODE_NEW_VG);
m_soc->force_bad_dma();
}
@@ -1084,24 +1106,29 @@ void nes_vt_hh_state::nes_vt_vg_8mb(machine_config& config)
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_8mbyte);
}
-void nes_vt_hh_state::nes_vt_vg_4mb(machine_config& config)
+void nes_vt_hh_state::nes_vt_vg_2mb(machine_config& config)
{
nes_vt_vg(config);
- m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_4mbyte);
+ m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_2mbyte);
}
-void nes_vt_hh_state::nes_vt_vg_16mb(machine_config& config)
+void nes_vt_hh_state::nes_vt_vg_4mb(machine_config& config)
{
nes_vt_vg(config);
- m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_16mbyte);
+ m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_4mbyte);
}
-void nes_vt_hh_state::nes_vt_vg_1mb_majkon(machine_config &config)
+void nes_vt_hh_state::nes_vt_vg_4mb_rasterhack(machine_config& config)
{
- nes_vt_dg(config);
- m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_1mbyte);
+ nes_vt_vg_4mb(config);
+ m_soc->force_raster_timing_hack();
+}
- m_soc->set_default_palette_mode(PAL_MODE_NEW_VG);
+
+void nes_vt_hh_state::nes_vt_vg_16mb(machine_config& config)
+{
+ nes_vt_vg(config);
+ m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_16mbyte);
}
@@ -1139,6 +1166,16 @@ void nes_vt_hh_state::nes_vt_hh_4mb(machine_config& config)
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_hh_state::vt_external_space_map_4mbyte);
}
+
+void nes_vt_state::nes_vt_1mb_majkon(machine_config& config)
+{
+ NES_VT_SOC(config, m_soc, NTSC_APU_CLOCK);
+ configure_soc(m_soc);
+ m_soc->set_addrmap(AS_PROGRAM, &nes_vt_state::vt_external_space_map_1mbyte_majkon);
+ m_soc->force_raster_timing_hack();
+}
+
+
static INPUT_PORTS_START( nes_vt )
PORT_START("IO0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("A")
@@ -1349,8 +1386,6 @@ void nes_vt_swap_op_d5_d6_state::nes_vt_vh2009(machine_config &config)
NES_VT_SOC_SCRAMBLE(config.replace(), m_soc, NTSC_APU_CLOCK);
configure_soc(m_soc);
-
- //m_soc->set_default_palette_mode(PAL_MODE_NEW_VG); // gives better title screens, but worse ingame, must be able to switch
}
void nes_vt_swap_op_d5_d6_state::nes_vt_vh2009_1mb(machine_config& config)
@@ -1359,6 +1394,11 @@ void nes_vt_swap_op_d5_d6_state::nes_vt_vh2009_1mb(machine_config& config)
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_swap_op_d5_d6_state::vt_external_space_map_1mbyte);
}
+void nes_vt_swap_op_d5_d6_state::nes_vt_vh2009_2mb(machine_config& config)
+{
+ nes_vt_vh2009(config);
+ m_soc->set_addrmap(AS_PROGRAM, &nes_vt_swap_op_d5_d6_state::vt_external_space_map_2mbyte);
+}
void nes_vt_swap_op_d5_d6_state::nes_vt_vh2009_4mb(machine_config& config)
{
nes_vt_vh2009(config);
@@ -1376,7 +1416,6 @@ void nes_vt_swap_op_d5_d6_state::nes_vt_senwld_512kb(machine_config &config)
{
nes_vt_vh2009(config);
m_soc->set_addrmap(AS_PROGRAM, &nes_vt_swap_op_d5_d6_state::vt_external_space_map_senwld_512kbyte);
- m_soc->set_default_palette_mode(PAL_MODE_NEW_VG);
}
static INPUT_PORTS_START( nes_vt_fp )
@@ -1421,7 +1460,7 @@ static INPUT_PORTS_START( ablpinb )
INPUT_PORTS_END
-static INPUT_PORTS_START( duetpp )
+static INPUT_PORTS_START( sporzpp )
PORT_START("IO0")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1)
@@ -1720,6 +1759,11 @@ ROM_START( cybar120 )
ROM_LOAD( "m2500p-vt09-epson,20091222ver05,_30r-sx1067-01_pcb,_12r0cob128m_12001-3d05_fw.bin", 0x00000, 0x1000000, CRC(f7138980) SHA1(de31264ee3a5a5c77a86733b2e2d6845fee91ea5) )
ROM_END
+ROM_START( sen101 )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "101n1.bin", 0x00000, 0x400000, CRC(b03e1824) SHA1(c9ac4e16220414c1aa679133191140ced9986e9c) )
+ROM_END
+
ROM_START( mc_dg101 )
ROM_REGION( 0x400000, "mainrom", 0 )
@@ -1741,6 +1785,36 @@ ROM_START( mc_sp69 )
ROM_LOAD( "sports game 69-in-1.prg", 0x00000, 0x400000, CRC(1242da7f) SHA1(bb8f99b1f4a4783b3f7e54d74f1f2a6a628da154) )
ROM_END
+ROM_START( vsmaxtx2 )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "tx2.bin", 0x00000, 0x400000, CRC(eddf0ca8) SHA1(b87c5c3e945d1efdcb953325425d4ddb0fded00a) )
+ROM_END
+
+ROM_START( vsmaxx17 )
+ ROM_REGION( 0x200000, "mainrom", 0 )
+ ROM_LOAD( "vsmaxx17.bin", 0x00000, 0x200000, CRC(f3fccbb9) SHA1(8b70b10d28f03e72f6b35199001955033a65fd5d) ) // M6MG3D641RB
+ROM_END
+
+ROM_START( vsmaxx77 )
+ ROM_REGION( 0x800000, "mainrom", 0 )
+ ROM_LOAD( "vsmaxx77.bin", 0x00000, 0x800000, CRC(03f1f4b5) SHA1(13f7ecea3765cffcd3065de713abdabd24946b99) )
+ROM_END
+
+ROM_START( vsmaxxvd )
+ ROM_REGION( 0x800000, "mainrom", 0 )
+ ROM_LOAD( "vsmaxxvideo.bin", 0x00000, 0x800000, CRC(af365a77) SHA1(8119fcef3e1a2ade93d36740d5df451919f0e541) )
+ROM_END
+
+ROM_START( dturbogt )
+ ROM_REGION( 0x800000, "mainrom", 0 )
+ ROM_LOAD( "dgturbogt.bin", 0x00000, 0x800000, CRC(9532fb78) SHA1(cd188672f9b8e9c12069612ad0d0b70d3dd6c1b1) )
+ROM_END
+
+ROM_START( rcapnp )
+ ROM_REGION( 0x200000, "mainrom", 0 )
+ ROM_LOAD( "rcapnp_mx29lv160ab_00c22249.bin", 0x00000, 0x200000, CRC(8cc30a47) SHA1(815bfc26360b01ed3fa077016222939d2184408c) )
+ROM_END
+
ROM_START( polmega )
ROM_REGION( 0x400000, "mainrom", 0 )
ROM_LOAD( "megamax.bin", 0x00000, 0x400000, CRC(ef3aade3) SHA1(0c130080ace000cbe43e70a805d4301e05840294) )
@@ -1751,7 +1825,12 @@ ROM_START( silv35 )
ROM_LOAD( "silverlit35.bin", 0x00000, 0x400000, CRC(7540e350) SHA1(a0cb456136560fa4d8a365dd44d815ec0e9fc2e7) )
ROM_END
-ROM_START( duetpp )
+ROM_START( ventur25 )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "25games_m5m29gt320vp_001c0020.bin", 0x00000, 0x400000, CRC(3f78a45a) SHA1(3e97333c13e09c580e66518dd2e1e031371d399c) )
+ROM_END
+
+ROM_START( sporzpp )
ROM_REGION( 0x400000, "mainrom", 0 )
ROM_LOAD( "gamesporzduetpingpong.bin", 0x00000, 0x400000, CRC(96af199b) SHA1(c14ff15683545c1edf03376cebcee7ac408da733) )
ROM_END
@@ -1761,6 +1840,21 @@ ROM_START( sporzbx )
ROM_LOAD( "sporzboxing.bin", 0x00000, 0x400000, CRC(8b832c0b) SHA1(8193955a81e894a01308a80d5153f2ecfe134da6) )
ROM_END
+ROM_START( sporztn )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "wirelesstennis.bin", 0x00000, 0x400000, CRC(e60f5ee1) SHA1(838ba7f4e9dcd0101eaaef5be883206d8856f45c) )
+ROM_END
+
+ROM_START( wldsoctv )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "worldsoccer.bin", 0x00000, 0x400000, CRC(8c0b184b) SHA1(fe1e7e83b9a2ae50dca1e7ea3bf7d691b8407511) )
+ROM_END
+
+ROM_START( solargm )
+ ROM_REGION( 0x800000, "mainrom", 0 )
+ ROM_LOAD( "solargames.bin", 0x00000, 0x800000, CRC(b49f0985) SHA1(68231614b333911c25168c533f1ae9bc79c36c38) )
+ROM_END
+
ROM_START( lpgm240 )
ROM_REGION( 0x800000, "mainrom", 0 )
ROM_LOAD( "w25q64jv.u1", 0x00000, 0x800000, CRC(b973e65b) SHA1(36ff137068ea56b4679c2db386ac0067de0a9eaf) )
@@ -2136,7 +2230,7 @@ CONS( 2016, msisinv, 0, 0, nes_vt_1mb_baddma, nes_vt_msi, nes_vt_state, emp
// This is from the version with the same case type as the above MSI units.
// MSI also issued a version in the original Majesco shell but with the updated case logos and boot logos in the software, the software on that revision might match this one.
-CONS( 2016, msifrog, 0, 0, nes_vt_4mb_baddma, nes_vt_msi, nes_vt_state, empty_init, "MSI / Konami", "Frogger (MSI Plug & Play, white joystick)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // raster timing issues, mode change issues
+CONS( 2016, msifrog, 0, 0, nes_vt_4mb_baddma_rasterhack, nes_vt_msi, nes_vt_state, empty_init, "MSI / Konami", "Frogger (MSI Plug & Play, white joystick)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // raster timing for need a hack
// MSI Midway (Joust+Gauntlet 2 + Defender 2) has 2x Globs, rather than Glob + Flash ROM
@@ -2145,9 +2239,13 @@ CONS( 2016, msifrog, 0, 0, nes_vt_4mb_baddma, nes_vt_msi, nes_vt_state, emp
CONS( 2005, ablpinb, 0, 0, nes_vt_pal_2mb, ablpinb, nes_vt_ablpinb_state, empty_init, "Advance Bright Ltd", "Pinball (P8002, ABL TV Game)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
// need to map 2 player controls for Ping Pong, 'Eat-Bean' (the PacMan hack) gets stuck during intermission? (same happens on hardware?)
-CONS( 2004, duetpp, 0, 0, nes_vt_waixing_alt_4mb_duetpp, duetpp, nes_vt_waixing_alt_duetpp_state, empty_init, "Macro Winners", "Game Sporz Wireless Duet Play Ping-Pong", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
-
-CONS( 2004, sporzbx, 0, 0, nes_vt_waixing_alt_4mb_duetpp, duetpp, nes_vt_waixing_alt_duetpp_state, empty_init, "Macro Winners", "Game Sporz Wireless Boxing", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 2004, sporzpp, 0, 0, nes_vt_waixing_alt_4mb_sporzpp, sporzpp, nes_vt_waixing_alt_sporzpp_state, empty_init, "Macro Winners", "Game Sporz Wireless Duet Play Ping-Pong", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+// has some longer than expected delays when sounds should play on the Boxing part, but NES hacks are all functional
+CONS( 2004, sporzbx, 0, 0, nes_vt_waixing_alt_4mb_sporzpp, sporzpp, nes_vt_waixing_alt_sporzpp_state, empty_init, "Macro Winners", "Game Sporz Wireless Boxing", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+// has some longer than expected delays when sounds should play on the Tennis part, but NES hacks are all functional, US version is sold in DreamGear branded box.
+CONS( 2004, sporztn, 0, 0, nes_vt_pal_4mb, sporzpp, nes_vt_wldsoctv_state, empty_init, "Macro Winners (Play Vision license)", "Wireless Tennis (PAL, Play Vision)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+// missing PCM audio, but regular APU SFX work
+CONS( 200?, wldsoctv, 0, 0, nes_vt_pal_4mb, nes_vt, nes_vt_wldsoctv_state, empty_init, "Taikee", "World Soccer TV Game 10-in-1 (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
// should be VT03 based
// for testing 'Shark', 'Octopus', 'Harbor', and 'Earth Fighter' use the extended colour modes, other games just seem to use standard NES modes
@@ -2156,112 +2254,62 @@ CONS( 200?, mc_dgear, 0, 0, nes_vt_4mb, nes_vt, nes_vt_state, empty_init,
// all software in this runs in the VT03 enhanced mode, it also includes an actual licensed VT03 port of Frogger.
// all games work OK except Frogger which has serious graphical issues
-CONS( 2006, vgtablet, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "Performance Designed Products (licensed by Konami)", "VG Pocket Tablet (VG-4000)", MACHINE_NOT_WORKING ) // raster timing is broken for Frogger
+CONS( 2006, vgtablet, 0, 0, nes_vt_vg_4mb_rasterhack, nes_vt, nes_vt_hh_state, empty_init, "Performance Designed Products (licensed by Konami) / JungleTac", "VG Pocket Tablet (VG-4000)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // raster timing for Frogger needs a hack
// There is a 2004 Majesco Frogger "TV game" that appears to contain the same version of Frogger as above but with no other games, so probably fits here.
-CONS( 2004, majkon, 0, 0, nes_vt_vg_1mb_majkon, nes_vt, nes_vt_hh_state, empty_init, "Majesco (licensed from Konami)", "Konami Collector's Series Arcade Advanced", MACHINE_NOT_WORKING ) // raster timing is broken for Frogger, palette issues
+CONS( 2004, majkon, 0, 0, nes_vt_1mb_majkon, nes_vt, nes_vt_state, empty_init, "Majesco (licensed from Konami) / JungleTac", "Konami Collector's Series Arcade Advanced", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // raster timing for Frogger needs a hack, Rush'n Attack also has raster timing issues on the status bar split
-CONS( 200?, majgnc, 0, 0, nes_vt_vg_1mb_majgnc, majgnc, nes_vt_vg_1mb_majgnc_state, empty_init, "Majesco", "Golden Nugget Casino", MACHINE_NOT_WORKING )
+CONS( 200?, majgnc, 0, 0, nes_vt_vg_1mb_majgnc, majgnc, nes_vt_vg_1mb_majgnc_state, empty_init, "Majesco / JungleTac", "Golden Nugget Casino", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
// small black unit, dpad on left, 4 buttons (A,B,X,Y) on right, Start/Reset/Select in middle, unit text "Sudoku Plug & Play TV Game"
-CONS( 200?, sudopptv, 0, 0, nes_vt_waixing_512kb, nes_vt, nes_vt_waixing_state, empty_init, "Smart Planet", "Sudoku Plug & Play TV Game '6 Intelligent Games'", MACHINE_NOT_WORKING )
+CONS( 200?, sudopptv, 0, 0, nes_vt_waixing_512kb_rasterhack, nes_vt, nes_vt_waixing_state, empty_init, "Smart Planet", "Sudoku Plug & Play TV Game '6 Intelligent Games'", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
CONS( 200?, megapad, 0, 0, nes_vt_waixing_2mb, nes_vt, nes_vt_waixing_state, empty_init, "Waixing", "Megapad 31-in-1", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // Happy Biqi has broken sprites, investigate before promoting
// 060303 date code on PCB
CONS( 2006, ablmini, 0, 0, nes_vt_waixing_alt_pal_8mb, nes_vt, nes_vt_waixing_alt_state, empty_init, "Advance Bright Ltd", "Double Players Mini Joystick 80-in-1 (MJ8500, ABL TV Game)", MACHINE_IMPERFECT_GRAPHICS )
+CONS( 200?, solargm, 0, 0, nes_vt_waixing_alt_pal_8mb, nes_vt, nes_vt_waixing_alt_state, empty_init, "<unknown>", "Solar Games 80-in-1 (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // Solar Games logo is also found in the SunPlus based Millennium Arcade units
+
// silver 'N64' type controller design
-CONS( 200?, zudugo, 0, 0, nes_vt_waixing_alt_4mb, nes_vt, nes_vt_waixing_alt_state, empty_init, "Macro Winners / Waixing", "Zudu-go / 2udu-go", MACHINE_IMPERFECT_GRAPHICS ) // the styling on the box looks like a '2' in places, a 'Z' in others.
+CONS( 200?, zudugo, 0, 0, nes_vt_waixing_alt_4mb, nes_vt, nes_vt_waixing_alt_state, empty_init, "Macro Winners / Waixing", "Zudu-go / 2udu-go", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // the styling on the box looks like a '2' in places, a 'Z' in others.
// needs PCM samples, Y button is not mapped (not used by any of the games? some sources indicate it's just a hardware autofire button)
CONS( 200?, timetp36, 0, 0, nes_vt_pal_4mb, timetp36, nes_vt_timetp36_state, empty_init, "TimeTop", "Super Game 36-in-1 (TimeTop SuperGame) (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
CONS( 200?, timetp7, 0, 0, nes_vt_pal_2mb, timetp36, nes_vt_timetp36_state, empty_init, "TimeTop", "Super Game 7-in-1 (TimeTop SuperGame) (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
-// this is VT09 based
-// it boots, most games correct, but palette issues in some games still (usually they appear greyscale)
-// and colors overall a bit off
-CONS( 2009, cybar120, 0, 0, nes_vt_vg_16mb, nes_vt, nes_vt_hh_state, empty_init, "Defender", "Defender M2500P 120-in-1", MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_GRAPHICS )
-CONS( 2005, vgpocket, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "Performance Designed Products", "VG Pocket (VG-2000)", MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_GRAPHICS )
-CONS( 200?, vgpmini, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "Performance Designed Products", "VG Pocket Mini (VG-1500)", MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_GRAPHICS )
-// VG Pocket Max (VG-2500) (blue case, 75 games)
-// VG Pocket Max (VG-3000) (white case, 75 games) (does the game selection differ, or only the case?)
-// VG Pocket Caplet is SunPlus hardware instead, see spg2xx_lexibook.cpp
-
// Runs fine, non-sport 121 in 1 games perfect, but minor graphical issues in
// sport games, also no sound in menu or sport games due to missing PCM
// emulation
CONS( 200?, dgun2500, 0, 0, nes_vt_dg_baddma_16mb, nes_vt, nes_vt_dg_state, empty_init, "dreamGEAR", "dreamGEAR Wireless Motion Control with 130 games (DGUN-2500)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND)
-// don't even get to menu. very enhanced chipset, VT368/9?
-CONS( 2012, dgun2561, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "dreamGEAR", "My Arcade Portable Gaming System with 140 Games (DGUN-2561)", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 2016, dgun2593, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "dreamGEAR", "My Arcade Retro Arcade Machine - 300 Handheld Video Games (DGUN-2593)", MACHINE_NOT_WORKING ) // 128Mbyte ROM, must be externally banked or different addressing scheme
-
-CONS( 200?, lxcmcy, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxcmc250, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - 250-in-1 (JL2375)", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxcmcysw, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Star Wars Rebels", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxcmcyfz, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Frozen", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxcmcydp, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Disney Princess", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxcmcysp, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Marvel Ultimate Spider-Man", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxcmcycr, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Cars", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-// the data order is swapped for this one, maybe other internal differences?
-CONS( 200?, lxcmcypp, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, init_lxcmcypp, "Lexibook", "Lexibook Compact Cyber Arcade - Paw Patrol", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-
-
-CONS( 200?, lxccminn, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Console Colour - Minnie Mouse", MACHINE_NOT_WORKING ) // 64Mbyte (used) ROM, must be externally banked, or different addressing scheme
-CONS( 200?, lxccplan, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Console Colour - Disney's Planes", MACHINE_NOT_WORKING ) // 64Mbyte (used) ROM, must be externally banked, or different addressing scheme
-
-
-// GB-NO13-Main-VT389-2 on PCBs
-CONS( 2016, rtvgc300, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Retro TV Game Console - 300 Games", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-CONS( 2017, rtvgc300fz,0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Retro TV Game Console - Frozen - 300 Games", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
-
-
-/* The following are also confirmed to be NES/VT derived units, most having a standard set of games with a handful of lazy graphic mods thrown in to fit the unit theme
-
- (handhekd units, use standard AAA batteries)
- Lexibook Compact Cyber Arcade - Cars
- Lexibook Compact Cyber Arcade - Barbie
- Lexibook Compact Cyber Arcade - Finding Dory
- Lexibook Compact Cyber Arcade - PJ Masks
-
- (Handheld units, but different form factor to Compact Cyber Arcade, charged via USB)
- Lexibook Console Colour - Barbie
-
- (units for use with TV)
- Lexibook Retro TV Game Console (300 Games) - Cars
- Lexibook Retro TV Game Console (300 Games) - PJ Masks
-
- (more?)
-
- There are also updated 'Compact Cyber Arcade' branded units with a large + D-pad and internal battery / USB charger for
- Spiderman
- Frozen
- (generic)
- it isn't verified if these use the same ROMs as the original Compact Cyber Arcade releases, or if the software has been updated
-
-*/
-
-// intial code isn't valid? scrambled?
-CONS( 201?, red5mam, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Red5", "Mini Arcade Machine (Red5)", MACHINE_NOT_WORKING ) // 128Mbyte ROM, must be externally banked or different addressing scheme
-
-
-
-CONS( 201?, denv150, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Denver", "Denver Game Console GMP-240C 150-in-1", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
-
+// this is VT09 based
+CONS( 2009, cybar120, 0, 0, nes_vt_vg_16mb,nes_vt, nes_vt_hh_state, empty_init, "Defender / JungleTac", "Defender M2500P 120-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 200?, vsmaxtx2, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "Senario / JungleTac", "Vs Maxx TX-2 50-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 200?, rcapnp, 0, 0, nes_vt_vg_2mb, nes_vt, nes_vt_hh_state, empty_init, "RCA / JungleTac", "RCA NS-500 30-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // from a Green unit, '17 Classic & Racing Game'
+CONS( 200?, dturbogt, 0, 0, nes_vt_vg_8mb, nes_vt, nes_vt_hh_state, empty_init, "dreamGEAR / JungleTac", "Turbo GT 50-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 200?, ventur25, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "<unknown> / JungleTac", "Venturer '25 Games' 25-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 2005, vgpocket, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "Performance Designed Products / JungleTac", "VG Pocket (VG-2000)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 200?, vgpmini, 0, 0, nes_vt_vg_4mb, nes_vt, nes_vt_hh_state, empty_init, "Performance Designed Products / JungleTac", "VG Pocket Mini (VG-1500)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+// VG Pocket Max (VG-2500) (blue case, 75 games)
+// VG Pocket Max (VG-3000) (white case, 75 games) (does the game selection differ, or only the case?)
+// VG Pocket Caplet is SunPlus hardware instead, see spg2xx_lexibook.cpp
// CPU die is marked 'VH2009' There's also a 62256 RAM chip on the PCB, some scrambled opcodes
-CONS( 200?, polmega, 0, 0, nes_vt_vh2009_4mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "Polaroid", "Megamax GPD001SDG", MACHINE_NOT_WORKING )
-CONS( 200?, silv35, 0, 0, nes_vt_vh2009_4mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "SilverLit", "35 in 1 Super Twins", MACHINE_NOT_WORKING )
+CONS( 2004, polmega, 0, 0, nes_vt_vh2009_4mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "Polaroid / JungleTac", "TV MegaMax active power game system 30-in-1 (MegaMax GPD001SDG)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 2004, vsmaxx17, 0, 0, nes_vt_vh2009_2mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "Senario / JungleTac", "Vs Maxx 17-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // from a Green unit, '17 Classic & Racing Game'
+CONS( 200?, silv35, 0, 0, nes_vt_vh2009_4mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "SilverLit / JungleTac", "35 in 1 Super Twins", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
// die is marked as VH2009, as above, but no scrambled opcodes here
CONS( 201?, techni4, 0, 0, nes_vt_pal_2mb, nes_vt, nes_vt_state, empty_init, "Technigame", "Technigame Super 4-in-1 Sports (PAL)", MACHINE_IMPERFECT_GRAPHICS )
+
+CONS( 2004, vsmaxxvd, 0, 0, nes_vt_vh2009_8mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "Senario / JungleTac", "Vs Maxx Video Extreme 50-in-1 (with Speed Racer and Snood)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 2004, vsmaxx77, 0, 0, nes_vt_vh2009_8mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "Senario / JungleTac", "Vs Maxx Wireless 77-in-1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+
+
// seems to use PCM for all sound, some garbage at bottom of screen, needs correct inputs (seems to respond to start, and any direction input for 'hit' - check if they're power related)
CONS( 200?, protpp, 0, 0, nes_vt_vh2009_1mb, nes_vt, nes_vt_swap_op_d5_d6_state, init_protpp, "Protocol", "Virtual Ping Pong (Protocol)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND )
-// same encryption as above, but seems like newer hardware (or the above aren't using most of the features)
-CONS( 200?, lpgm240, 0, 0, nes_vt_vh2009_8mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "<unknown>", "Let's Play! Game Machine 240 in 1", MACHINE_NOT_WORKING ) // mini 'retro-arcade' style cabinet
-
// this has 'Shark' and 'Octopus' etc. like mc_dgear but uses scrambled bank registers
// This was also often found in cart form with SunPlus / Famiclone hybrid systems to boost the game count, eg. the WiWi (ROM verified to match)
CONS( 200?, mc_sp69, 0, 0, nes_vt_4mb_sp69, nes_vt, nes_vt_sp69_state, empty_init, "<unknown>", "Sports Game 69 in 1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND)
@@ -2303,6 +2351,9 @@ CONS( 2006, ddrstraw, 0, 0, nes_vt_2mb, nes_vt_ddr, nes_vt_state, empt
// there is also a 'Spectra Light Edition' which could be a different ROM as the title screen on this one does show the unit type.
CONS( 2006, dbdancem, 0, 0, nes_vt_2mb, dbdancem, nes_vt_state, empty_init, "Senario", "Double Dance Mania - Techno Light Edition", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+// unlike other Senario products this one is mostly just NES games, it also appears to be one of the final Senario products. Some games aren't what they claim to be, Warpman is Soccer for example.
+CONS( 2009, sen101, 0, 0, nes_vt_4mb, nes_vt, nes_vt_state, empty_init, "Senario", "101 Games in 1 (Senario)", MACHINE_IMPERFECT_GRAPHICS )
+
// unsorted, these were all in nes.xml listed as ONE BUS systems
CONS( 200?, mc_dg101, 0, 0, nes_vt_4mb, nes_vt, nes_vt_state, empty_init, "dreamGEAR", "dreamGEAR 101 in 1", MACHINE_IMPERFECT_GRAPHICS ) // dreamGear, but no enhanced games?
CONS( 200?, mc_aa2, 0, 0, nes_vt_4mb, nes_vt, nes_vt_state, empty_init, "<unknown>", "100 in 1 Arcade Action II (AT-103)", MACHINE_IMPERFECT_GRAPHICS )
@@ -2315,7 +2366,6 @@ CONS( 200?, mc_8x6ss, 0, 0, nes_vt_1mb, nes_vt, nes_vt_state, empty
CONS( 2004, mc_dcat8, 0, 0, nes_vt_8mb, nes_vt, nes_vt_state, empty_init, "<unknown>", "100 in 1 (D-CAT8 8bit Console, set 1) (v5.01.11-frd, BL 20041217)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 2004, mc_dcat8a, mc_dcat8, 0, nes_vt_8mb, nes_vt, nes_vt_state, empty_init, "<unknown>", "100 in 1 (D-CAT8 8bit Console, set 2)", MACHINE_IMPERFECT_GRAPHICS )
-
// Runs well, only issues in SMB3 which crashes
CONS( 2017, bittboy, 0, 0, nes_vt_bt_2x16mb, nes_vt, nes_vt_cy_state, empty_init, "BittBoy", "BittBoy Mini FC 300 in 1", MACHINE_IMPERFECT_GRAPHICS ) // has external banking (2x 16mbyte banks)
// Runs well, all games seem to work
@@ -2332,24 +2382,17 @@ CONS( 201?, mc_tv200, 0, 0, nes_vt_8mb, nes_vt, nes_vt_state, empty
// probably another Thumbs Up product? cursor doesn't work unless nes_vt_hh machine is used? possibly newer than VT02 as it runs from an SPI ROM, might just not use enhanced features. Some minor game name changes to above (eg Smackdown just becomes Wrestling)
CONS( 201?, unkra200, mc_tv200, 0, nes_vt_hh_8mb, nes_vt, nes_vt_hh_state, empty_init, "<unknown>", "200 in 1 Retro Arcade", MACHINE_IMPERFECT_GRAPHICS )
-
// available in a number of colours, with various brands, but likely all the same.
// This was a red coloured pad, contains various unlicensed bootleg reskinned NES game eg Blob Buster is a hack of Dig Dug 2 and there are also hacks of Xevious, Donkey Kong Jr, Donkey Kong 3 and many others.
CONS( 201?, ppgc200g, 0, 0, nes_vt_8mb, nes_vt, nes_vt_state, empty_init, "<unknown>", "Plug & Play Game Controller with 200 Games (Supreme 200)", MACHINE_IMPERFECT_GRAPHICS )
-
// Probably VT09 or similar
// Use DIP switch to select console or cartridge, as cartridge is fake and just toggles a ROM high address bit
// (which can also be overriden by GPIO)
CONS( 2017, fapocket, 0, 0, nes_vt_fa_4x16mb, nes_vt_fa, nes_vt_dg_fapocket_state, empty_init, "<unknown>", "Family Pocket 638 in 1", MACHINE_IMPERFECT_GRAPHICS ) // has external banking (4x 16mbyte banks)
-
-CONS( 2017, otrail, 0, 0, nes_vt_dg_1mb, nes_vt, nes_vt_dg_state, empty_init, "Basic Fun", "The Oregon Trail", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
-
CONS( 2005, senwld, 0, 0, nes_vt_senwld_512kb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "Senario", "Win, Lose or Draw (Senario)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS ) // needs RAM in banked space, Alpha display emulating, Touchpad emulating etc.
-
-
// Runs well, minor GFX issues in intro
CONS( 2017, sy889, 0, 0, nes_vt_hh_8mb, nes_vt, nes_vt_hh_state, empty_init, "SY Corp", "SY-889 300 in 1 Handheld", MACHINE_IMPERFECT_GRAPHICS )
CONS( 2016, sy888b, 0, 0, nes_vt_hh_4mb, nes_vt, nes_vt_hh_state, empty_init, "SY Corp", "SY-888B 288 in 1 Handheld", MACHINE_IMPERFECT_GRAPHICS )
@@ -2370,4 +2413,76 @@ CONS( 2015, rminitv, 0, 0, nes_vt_fp_pal_32mb, nes_vt, nes_vt_hh_state, empt
// Use DIP switch to select console or cartridge, as cartridge is fake and just toggles a GPIO
CONS( 2016, fcpocket, 0, 0, nes_vt_fp_4x16mb, nes_vt_fp, nes_vt_hh_state, empty_init, "<unknown>", "FC Pocket 600 in 1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // has external banking (2x 32mbyte banks)
+
+/****************************************************************************************************************
+
+ Things below seem on heavily enhanced hardware of unknown VT type
+
+ It's possible some of these are the same as some of the ones above (sy889, rminitv, dgun2573 etc.) but with
+ more features used.
+
+ In some cases these might be almost entirely different, and it is likely a number don't belong in this
+ driver at all.
+
+****************************************************************************************************************/
+
+// don't even get to menu. very enhanced chipset, VT368/9?
+CONS( 2012, dgun2561, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "dreamGEAR", "My Arcade Portable Gaming System with 140 Games (DGUN-2561)", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 2016, dgun2593, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "dreamGEAR", "My Arcade Retro Arcade Machine - 300 Handheld Video Games (DGUN-2593)", MACHINE_NOT_WORKING ) // 128Mbyte ROM, must be externally banked or different addressing scheme
+
+CONS( 200?, lxcmcy, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxcmc250, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - 250-in-1 (JL2375)", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxcmcysw, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Star Wars Rebels", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxcmcyfz, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Frozen", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxcmcydp, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Disney Princess", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxcmcysp, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Marvel Ultimate Spider-Man", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxcmcycr, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Compact Cyber Arcade - Cars", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+// the data order is swapped for this one, maybe other internal differences?
+CONS( 200?, lxcmcypp, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, init_lxcmcypp, "Lexibook", "Lexibook Compact Cyber Arcade - Paw Patrol", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+
+
+CONS( 200?, lxccminn, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Console Colour - Minnie Mouse", MACHINE_NOT_WORKING ) // 64Mbyte (used) ROM, must be externally banked, or different addressing scheme
+CONS( 200?, lxccplan, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Console Colour - Disney's Planes", MACHINE_NOT_WORKING ) // 64Mbyte (used) ROM, must be externally banked, or different addressing scheme
+
+
+// GB-NO13-Main-VT389-2 on PCBs
+CONS( 2016, rtvgc300, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Retro TV Game Console - 300 Games", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+CONS( 2017, rtvgc300fz,0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Lexibook", "Lexibook Retro TV Game Console - Frozen - 300 Games", MACHINE_NOT_WORKING ) // 64Mbyte ROM, must be externally banked, or different addressing scheme
+
+
+/* The following are also confirmed to be NES/VT derived units, most having a standard set of games with a handful of lazy graphic mods thrown in to fit the unit theme
+
+ (handhekd units, use standard AAA batteries)
+ Lexibook Compact Cyber Arcade - Cars
+ Lexibook Compact Cyber Arcade - Barbie
+ Lexibook Compact Cyber Arcade - Finding Dory
+ Lexibook Compact Cyber Arcade - PJ Masks
+
+ (Handheld units, but different form factor to Compact Cyber Arcade, charged via USB)
+ Lexibook Console Colour - Barbie
+
+ (units for use with TV)
+ Lexibook Retro TV Game Console (300 Games) - Cars
+ Lexibook Retro TV Game Console (300 Games) - PJ Masks
+
+ (more?)
+
+ There are also updated 'Compact Cyber Arcade' branded units with a large + D-pad and internal battery / USB charger for
+ Spiderman
+ Frozen
+ (generic)
+ it isn't verified if these use the same ROMs as the original Compact Cyber Arcade releases, or if the software has been updated
+
+*/
+
+// intial code isn't valid? scrambled?
+CONS( 201?, red5mam, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Red5", "Mini Arcade Machine (Red5)", MACHINE_NOT_WORKING ) // 128Mbyte ROM, must be externally banked or different addressing scheme
+
+CONS( 201?, denv150, 0, 0, nes_vt_cy_bigger, nes_vt, nes_vt_cy_lexibook_state, empty_init, "Denver", "Denver Game Console GMP-240C 150-in-1", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
+
+// same encryption as above, but seems like newer hardware (or the above aren't using most of the features)
+CONS( 200?, lpgm240, 0, 0, nes_vt_vh2009_8mb, nes_vt, nes_vt_swap_op_d5_d6_state, empty_init, "<unknown>", "Let's Play! Game Machine 240 in 1", MACHINE_NOT_WORKING ) // mini 'retro-arcade' style cabinet
+
+CONS( 2017, otrail, 0, 0, nes_vt_dg_1mb, nes_vt, nes_vt_dg_state, empty_init, "Basic Fun", "The Oregon Trail", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS )
+
CONS( 200?, zonefusn, 0, 0, nes_vt_fp_16mb, nes_vt, nes_vt_hh_state, empty_init, "Ultimate Products / Jungle's Soft", "Zone Fusion", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/newton.cpp b/src/mame/drivers/newton.cpp
index d072a9788d8..bdad52420a7 100644
--- a/src/mame/drivers/newton.cpp
+++ b/src/mame/drivers/newton.cpp
@@ -47,13 +47,26 @@ public:
protected:
void mem_map(address_map &map);
+ uint32_t tick_count_r();
+
required_device<arm7_cpu_device> m_maincpu;
required_device<ram_device> m_ram;
+
+ uint32_t m_ram_size;
};
+uint32_t newton_state::tick_count_r()
+{
+ return (uint32_t)m_maincpu->total_cycles();
+}
+
void newton_state::mem_map(address_map &map)
{
- map(0x00000000, 0x007fffff).rom().region("maincpu", 0);
+ map(0x00000000, 0x007fffff).mirror(0x00800000).rom().region("maincpu", 0);
+ map(0x02000000, 0x023fffff).ram(); // Actually Flash
+ map(0x04000000, 0x04ffffff).rw(m_ram, FUNC(ram_device::read), FUNC(ram_device::write));
+ map(0x0f181800, 0x0f181803).r(FUNC(newton_state::tick_count_r));
+ map(0x0f001800, 0x0f001803).lrw32(NAME([this](){ return m_ram_size; }), NAME([this](uint32_t data) { m_ram_size = data; }));
}
static INPUT_PORTS_START( newton )
diff --git a/src/mame/drivers/nexus3d.cpp b/src/mame/drivers/nexus3d.cpp
index a0bfc095328..81c218bb886 100644
--- a/src/mame/drivers/nexus3d.cpp
+++ b/src/mame/drivers/nexus3d.cpp
@@ -97,14 +97,14 @@ void nexus3d_state::video_start()
uint32_t nexus3d_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- uint16_t *fbram = reinterpret_cast<uint16_t *>(m_fbram.target());
- const int width = 640;
+ uint16_t const *const fbram = reinterpret_cast<uint16_t *>(m_fbram.target());
+ int const width = 640;
- uint16_t *visible = fbram + (m_screen->frame_number() & 1) * (0x96000/2);
+ uint16_t const *const visible = fbram + (m_screen->frame_number() & 1) * (0x96000/2);
uint32_t const dx = cliprect.left();
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
- std::copy_n(&visible[(y * width) + dx], width, &bitmap.pix16(y, dx));
+ std::copy_n(&visible[(y * width) + dx], width, &bitmap.pix(y, dx));
return 0;
}
diff --git a/src/mame/drivers/nforcepc.cpp b/src/mame/drivers/nforcepc.cpp
index 06d2db89863..c6a73538d71 100644
--- a/src/mame/drivers/nforcepc.cpp
+++ b/src/mame/drivers/nforcepc.cpp
@@ -103,6 +103,9 @@ void crush11_host_device::device_start()
io_window_end = 0xffff;
io_offset = 0;
status = 0x00b0;
+ command = 0x0000;
+
+ add_map(64 * 1024 * 1024, M_MEM | M_PREF, FUNC(crush11_host_device::aperture_map));
}
void crush11_host_device::reset_all_mappings()
@@ -169,16 +172,16 @@ void crush11_memory_device::config_map(address_map &map)
map(0xc8, 0xcb).nopr();
}
-crush11_memory_device::crush11_memory_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, int ram_size)
+crush11_memory_device::crush11_memory_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint32_t subsystem_id, int ram_size)
: crush11_memory_device(mconfig, tag, owner, clock)
{
+ set_ids(0x10de01ac, 0xb2, 0x050000, subsystem_id);
set_ram_size(ram_size);
}
crush11_memory_device::crush11_memory_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: pci_device(mconfig, CRUSH11_MEMORY, tag, owner, clock)
{
- set_ids(0x10de01ac, 0, 0, 0);
}
void crush11_memory_device::device_start()
@@ -191,6 +194,7 @@ void crush11_memory_device::device_start()
host = dynamic_cast<crush11_host_device *>(r);
ram_space = host->get_cpu_space(AS_PROGRAM);
status = 0x0020;
+ command = 0x0000;
}
void crush11_memory_device::device_reset()
@@ -1159,7 +1163,7 @@ void nforcepc_state::nforcepc(machine_config &config)
PCI_ROOT(config, ":pci", 0);
CRUSH11(config, ":pci:00.0", 0, "maincpu", "bios"); // 10de:01a4 NVIDIA Corporation nForce CPU bridge
- CRUSH11_MEMORY(config, ":pci:00.1", 0, 2); // 10de:01ac NVIDIA Corporation nForce 220/420 Memory Controller
+ CRUSH11_MEMORY(config, ":pci:00.1", 0, 0x10430c11, 2); // 10de:01ac NVIDIA Corporation nForce 220/420 Memory Controller
// 10de:01ad NVIDIA Corporation nForce 220/420 Memory Controller
// 10de:01ab NVIDIA Corporation nForce 420 Memory Controller (DDR)
mcpx_isalpc_device &isa(MCPX_ISALPC(config, ":pci:01.0", 0, 0x10430c11)); // 10de:01b2 NVIDIA Corporation nForce ISA Bridge (LPC bus)
@@ -1175,7 +1179,7 @@ void nforcepc_state::nforcepc(machine_config &config)
ite.txd2().set("serport1", FUNC(rs232_port_device::write_txd));
ite.ndtr2().set("serport1", FUNC(rs232_port_device::write_dtr));
ite.nrts2().set("serport1", FUNC(rs232_port_device::write_rts));
- MCPX_SMBUS(config, ":pci:01.1", 0); // 10de:01b4 NVIDIA Corporation nForce PCI System Management (SMBus)
+ MCPX_SMBUS(config, ":pci:01.1", 0, 0x10430c11); // 10de:01b4 NVIDIA Corporation nForce PCI System Management (SMBus)
SMBUS_ROM(config, ":pci:01.1:050", 0, test_spd_data, sizeof(test_spd_data)); // these 3 are on smbus number 0
SMBUS_LOGGER(config, ":pci:01.1:051", 0);
SMBUS_LOGGER(config, ":pci:01.1:052", 0);
@@ -1183,20 +1187,20 @@ void nforcepc_state::nforcepc(machine_config &config)
AS99127F(config, ":pci:01.1:12d", 0);
AS99127F_SENSOR2(config, ":pci:01.1:148", 0);
AS99127F_SENSOR3(config, ":pci:01.1:149", 0);
- mcpx_ohci_device &ohci(MCPX_OHCI(config, ":pci:02.0", 0)); // 10de:01c2 NVIDIA Corporation nForce USB Controller
+ mcpx_ohci_device &ohci(MCPX_OHCI(config, ":pci:02.0", 0, 0x10430c11)); // 10de:01c2 NVIDIA Corporation nForce USB Controller
ohci.interrupt_handler().set(":pci:01.0", FUNC(mcpx_isalpc_device::irq1));
- MCPX_OHCI(config, ":pci:03.0", 0); // 10de:01c2 NVIDIA Corporation nForce USB Controller
+ MCPX_OHCI(config, ":pci:03.0", 0, 0x10430c11); // 10de:01c2 NVIDIA Corporation nForce USB Controller
MCPX_ETH(config, ":pci:04.0", 0); // 10de:01c3 NVIDIA Corporation nForce Ethernet Controller
- MCPX_APU(config, ":pci:05.0", 0, m_maincpu); // 10de:01b0 NVIDIA Corporation nForce Audio Processing Unit
- MCPX_AC97_AUDIO(config, ":pci:06.0", 0); // 10de:01b1 NVIDIA Corporation nForce AC'97 Audio Controller
- PCI_BRIDGE(config, ":pci:08.0", 0, 0x10de01b8, 0); // 10de:01b8 NVIDIA Corporation nForce PCI-to-PCI bridge
+ MCPX_APU(config, ":pci:05.0", 0, 0x10430c11, m_maincpu); // 10de:01b0 NVIDIA Corporation nForce Audio Processing Unit
+ MCPX_AC97_AUDIO(config, ":pci:06.0", 0, 0x10438384); // 10de:01b1 NVIDIA Corporation nForce AC'97 Audio Controller
+ PCI_BRIDGE(config, ":pci:08.0", 0, 0x10de01b8, 0xc2); // 10de:01b8 NVIDIA Corporation nForce PCI-to-PCI bridge
// 10ec:8139 Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+ (behind bridge)
- mcpx_ide_device &ide(MCPX_IDE(config, ":pci:09.0", 0)); // 10de:01bc NVIDIA Corporation nForce IDE
+ mcpx_ide_device &ide(MCPX_IDE(config, ":pci:09.0", 0, 0x10430c11)); // 10de:01bc NVIDIA Corporation nForce IDE
ide.pri_interrupt_handler().set(":pci:01.0", FUNC(mcpx_isalpc_device::irq14));
ide.sec_interrupt_handler().set(":pci:01.0", FUNC(mcpx_isalpc_device::irq15));
ide.subdevice<ide_controller_32_device>("ide1")->options(ata_devices, "hdd", nullptr, true);
ide.subdevice<ide_controller_32_device>("ide2")->options(ata_devices, "cdrom", nullptr, true);
- NV2A_AGP(config, ":pci:1e.0", 0, 0x10de01b7, 0); // 10de:01b7 NVIDIA Corporation nForce AGP to PCI Bridge
+ NV2A_AGP(config, ":pci:1e.0", 0, 0x10de01b7, 0xb2); // 10de:01b7 NVIDIA Corporation nForce AGP to PCI Bridge
VIRGEDX_PCI(config, ":pci:0a.0", 0);
SST_49LF020(config, "bios", 0);
diff --git a/src/mame/drivers/ngen.cpp b/src/mame/drivers/ngen.cpp
index de4ee86a914..e0a18155ead 100644
--- a/src/mame/drivers/ngen.cpp
+++ b/src/mame/drivers/ngen.cpp
@@ -768,9 +768,9 @@ MC6845_UPDATE_ROW( ngen_state::crtc_update_row )
for(int z=0;z<9;z++)
{
if(BIT(m_fontram.read16(ch*16+ra),8-z))
- bitmap.pix32(y,x+z) = rgb_t(0,0xff,0);
+ bitmap.pix(y,x+z) = rgb_t(0,0xff,0);
else
- bitmap.pix32(y,x+z) = rgb_t(0,0,0);
+ bitmap.pix(y,x+z) = rgb_t(0,0,0);
}
}
}
diff --git a/src/mame/drivers/nightgal.cpp b/src/mame/drivers/nightgal.cpp
index 99b2428e3f1..8acac8fd461 100644
--- a/src/mame/drivers/nightgal.cpp
+++ b/src/mame/drivers/nightgal.cpp
@@ -175,14 +175,12 @@ void nightgal_state::video_start()
uint32_t nightgal_state::screen_update_nightgal(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
- int x, y;
-
- for (y = cliprect.min_y; y <= cliprect.max_y; ++y)
+ for (int y = cliprect.min_y; y <= cliprect.max_y; ++y)
{
const uint8_t *src = &m_blitter->blit_buffer(y, cliprect.min_x);
- uint16_t *dst = &m_tmp_bitmap->pix16(y, cliprect.min_x);
+ uint16_t *dst = &m_tmp_bitmap->pix(y, cliprect.min_x);
- for (x = cliprect.min_x; x <= cliprect.max_x; x += 2)
+ for (int x = cliprect.min_x; x <= cliprect.max_x; x += 2)
{
uint32_t srcpix = *src++;
*dst++ = m_palette->pen((srcpix & 0xf) | m_pal_bank);
diff --git a/src/mame/drivers/nightmare.cpp b/src/mame/drivers/nightmare.cpp
index 5ea1c4ac209..5dda8921429 100644
--- a/src/mame/drivers/nightmare.cpp
+++ b/src/mame/drivers/nightmare.cpp
@@ -369,9 +369,9 @@ uint32_t nightmare_state::screen_update_nightmare(screen_device &screen, bitmap_
// combine two buffers (additive?)
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
- uint32_t *const bitmap1 = &m_vdc2->get_bitmap().pix32(y);
- uint32_t *const bitmap2 = &m_vdc->get_bitmap().pix32(y);
- uint32_t *dst = &bitmap.pix32(y);
+ uint32_t const *const bitmap1 = &m_vdc2->get_bitmap().pix(y);
+ uint32_t const *const bitmap2 = &m_vdc->get_bitmap().pix(y);
+ uint32_t *const dst = &bitmap.pix(y);
for (int x = cliprect.left(); x <= cliprect.right(); x++)
{
@@ -379,9 +379,9 @@ uint32_t nightmare_state::screen_update_nightmare(screen_device &screen, bitmap_
uint32_t p2 = bitmap2[x];
uint32_t result = 0;
- for(int shift=0; shift<32;shift+=8)
+ for (int shift=0; shift<32;shift+=8)
{
- uint32_t data = ((p2>>shift)&0xff)+((p1>>shift)&0xff);
+ uint32_t const data = ((p2>>shift)&0xff)+((p1>>shift)&0xff);
result|=((data>0xff)?0xff:data)<<shift;
}
dst[x]=result;
diff --git a/src/mame/drivers/ninjaw.cpp b/src/mame/drivers/ninjaw.cpp
index 3cff502baf7..d3eecd5df84 100644
--- a/src/mame/drivers/ninjaw.cpp
+++ b/src/mame/drivers/ninjaw.cpp
@@ -373,6 +373,7 @@ void ninjaw_state::pancontrol_w(offs_t offset, u8 data)
{
filter_volume_device *flt = nullptr;
offset &= 3;
+ offset ^= 1;
switch (offset)
{
@@ -618,7 +619,7 @@ protected:
virtual void device_start();
// sound stream update overrides
- virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples);
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
private:
// internal state
@@ -654,11 +655,12 @@ void subwoofer_device::device_start()
}
//-------------------------------------------------
-// sound_stream_update_legacy - handle a stream update
+// sound_stream_update - handle a stream update
//-------------------------------------------------
-void subwoofer_device::sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples)
+void subwoofer_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
+ outputs[0].fill(0);
}
diff --git a/src/mame/drivers/nmg5.cpp b/src/mame/drivers/nmg5.cpp
index a657a5641b8..c887aaa54f1 100644
--- a/src/mame/drivers/nmg5.cpp
+++ b/src/mame/drivers/nmg5.cpp
@@ -315,7 +315,7 @@ uint8_t nmg5_state::pixmap_r(offs_t offset)
int const sy = offset >> 8;
int const sx = (offset & 0xff) << 1;
- return ((m_pixmap->pix16(sy & 0xff, sx & ~1) & 0xf) << 4) | (m_pixmap->pix16(sy & 0xff, sx | 1) & 0xf);
+ return ((m_pixmap->pix(sy & 0xff, sx & ~1) & 0xf) << 4) | (m_pixmap->pix(sy & 0xff, sx | 1) & 0xf);
}
void nmg5_state::pixmap_w(offs_t offset, uint8_t data)
@@ -323,8 +323,8 @@ void nmg5_state::pixmap_w(offs_t offset, uint8_t data)
int const sy = offset >> 8;
int const sx = (offset & 0xff) << 1;
- m_pixmap->pix16(sy & 0xff, sx & ~1) = 0x300 + ((data & 0xf0) >> 4);
- m_pixmap->pix16(sy & 0xff, sx | 1) = 0x300 + (data & 0x0f);
+ m_pixmap->pix(sy & 0xff, sx & ~1) = 0x300 + ((data & 0xf0) >> 4);
+ m_pixmap->pix(sy & 0xff, sx | 1) = 0x300 + (data & 0x0f);
}
template<int Layer>
diff --git a/src/mame/drivers/nmk16.cpp b/src/mame/drivers/nmk16.cpp
index 3cc0dc80a5d..e7034e36d79 100644
--- a/src/mame/drivers/nmk16.cpp
+++ b/src/mame/drivers/nmk16.cpp